summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acpi/Makefile4
-rw-r--r--drivers/acpi/acpi_pad.c37
-rw-r--r--drivers/acpi/acpica/accommon.h2
-rw-r--r--drivers/acpi/acpica/acconfig.h2
-rw-r--r--drivers/acpi/acpica/acdebug.h2
-rw-r--r--drivers/acpi/acpica/acdispat.h2
-rw-r--r--drivers/acpi/acpica/acevents.h15
-rw-r--r--drivers/acpi/acpica/acglobal.h2
-rw-r--r--drivers/acpi/acpica/achware.h2
-rw-r--r--drivers/acpi/acpica/acinterp.h44
-rw-r--r--drivers/acpi/acpica/aclocal.h8
-rw-r--r--drivers/acpi/acpica/acmacros.h14
-rw-r--r--drivers/acpi/acpica/acnamesp.h18
-rw-r--r--drivers/acpi/acpica/acobject.h6
-rw-r--r--drivers/acpi/acpica/acopcode.h2
-rw-r--r--drivers/acpi/acpica/acparser.h2
-rw-r--r--drivers/acpi/acpica/acpredef.h2
-rw-r--r--drivers/acpi/acpica/acresrc.h2
-rw-r--r--drivers/acpi/acpica/acstruct.h2
-rw-r--r--drivers/acpi/acpica/actables.h2
-rw-r--r--drivers/acpi/acpica/acutils.h22
-rw-r--r--drivers/acpi/acpica/amlcode.h2
-rw-r--r--drivers/acpi/acpica/amlresrc.h2
-rw-r--r--drivers/acpi/acpica/dsfield.c12
-rw-r--r--drivers/acpi/acpica/dsinit.c2
-rw-r--r--drivers/acpi/acpica/dsmethod.c2
-rw-r--r--drivers/acpi/acpica/dsmthdat.c2
-rw-r--r--drivers/acpi/acpica/dsobject.c4
-rw-r--r--drivers/acpi/acpica/dsopcode.c2
-rw-r--r--drivers/acpi/acpica/dsutils.c2
-rw-r--r--drivers/acpi/acpica/dswexec.c2
-rw-r--r--drivers/acpi/acpica/dswload.c2
-rw-r--r--drivers/acpi/acpica/dswscope.c2
-rw-r--r--drivers/acpi/acpica/dswstate.c2
-rw-r--r--drivers/acpi/acpica/evevent.c2
-rw-r--r--drivers/acpi/acpica/evgpe.c163
-rw-r--r--drivers/acpi/acpica/evgpeblk.c89
-rw-r--r--drivers/acpi/acpica/evmisc.c14
-rw-r--r--drivers/acpi/acpica/evregion.c7
-rw-r--r--drivers/acpi/acpica/evrgnini.c4
-rw-r--r--drivers/acpi/acpica/evsci.c2
-rw-r--r--drivers/acpi/acpica/evxface.c191
-rw-r--r--drivers/acpi/acpica/evxfevnt.c98
-rw-r--r--drivers/acpi/acpica/evxfregn.c2
-rw-r--r--drivers/acpi/acpica/exconfig.c17
-rw-r--r--drivers/acpi/acpica/exconvrt.c21
-rw-r--r--drivers/acpi/acpica/excreate.c2
-rw-r--r--drivers/acpi/acpica/exdump.c2
-rw-r--r--drivers/acpi/acpica/exfield.c9
-rw-r--r--drivers/acpi/acpica/exfldio.c59
-rw-r--r--drivers/acpi/acpica/exmisc.c12
-rw-r--r--drivers/acpi/acpica/exmutex.c5
-rw-r--r--drivers/acpi/acpica/exnames.c2
-rw-r--r--drivers/acpi/acpica/exoparg1.c16
-rw-r--r--drivers/acpi/acpica/exoparg2.c6
-rw-r--r--drivers/acpi/acpica/exoparg3.c4
-rw-r--r--drivers/acpi/acpica/exoparg6.c10
-rw-r--r--drivers/acpi/acpica/exprep.c2
-rw-r--r--drivers/acpi/acpica/exregion.c35
-rw-r--r--drivers/acpi/acpica/exresnte.c2
-rw-r--r--drivers/acpi/acpica/exresolv.c2
-rw-r--r--drivers/acpi/acpica/exresop.c2
-rw-r--r--drivers/acpi/acpica/exstore.c2
-rw-r--r--drivers/acpi/acpica/exstoren.c2
-rw-r--r--drivers/acpi/acpica/exstorob.c2
-rw-r--r--drivers/acpi/acpica/exsystem.c4
-rw-r--r--drivers/acpi/acpica/exutils.c24
-rw-r--r--drivers/acpi/acpica/hwacpi.c2
-rw-r--r--drivers/acpi/acpica/hwgpe.c8
-rw-r--r--drivers/acpi/acpica/hwregs.c2
-rw-r--r--drivers/acpi/acpica/hwsleep.c2
-rw-r--r--drivers/acpi/acpica/hwtimer.c4
-rw-r--r--drivers/acpi/acpica/hwvalid.c2
-rw-r--r--drivers/acpi/acpica/hwxface.c2
-rw-r--r--drivers/acpi/acpica/nsaccess.c2
-rw-r--r--drivers/acpi/acpica/nsalloc.c2
-rw-r--r--drivers/acpi/acpica/nsdump.c2
-rw-r--r--drivers/acpi/acpica/nsdumpdv.c2
-rw-r--r--drivers/acpi/acpica/nseval.c2
-rw-r--r--drivers/acpi/acpica/nsinit.c2
-rw-r--r--drivers/acpi/acpica/nsload.c2
-rw-r--r--drivers/acpi/acpica/nsnames.c2
-rw-r--r--drivers/acpi/acpica/nsobject.c2
-rw-r--r--drivers/acpi/acpica/nsparse.c2
-rw-r--r--drivers/acpi/acpica/nspredef.c53
-rw-r--r--drivers/acpi/acpica/nsrepair.c175
-rw-r--r--drivers/acpi/acpica/nsrepair2.c110
-rw-r--r--drivers/acpi/acpica/nssearch.c2
-rw-r--r--drivers/acpi/acpica/nsutils.c2
-rw-r--r--drivers/acpi/acpica/nswalk.c2
-rw-r--r--drivers/acpi/acpica/nsxfeval.c54
-rw-r--r--drivers/acpi/acpica/nsxfname.c2
-rw-r--r--drivers/acpi/acpica/nsxfobj.c2
-rw-r--r--drivers/acpi/acpica/psargs.c4
-rw-r--r--drivers/acpi/acpica/psloop.c2
-rw-r--r--drivers/acpi/acpica/psopcode.c2
-rw-r--r--drivers/acpi/acpica/psparse.c2
-rw-r--r--drivers/acpi/acpica/psscope.c2
-rw-r--r--drivers/acpi/acpica/pstree.c2
-rw-r--r--drivers/acpi/acpica/psutils.c2
-rw-r--r--drivers/acpi/acpica/pswalk.c2
-rw-r--r--drivers/acpi/acpica/psxface.c2
-rw-r--r--drivers/acpi/acpica/rsaddr.c2
-rw-r--r--drivers/acpi/acpica/rscalc.c2
-rw-r--r--drivers/acpi/acpica/rscreate.c4
-rw-r--r--drivers/acpi/acpica/rsdump.c2
-rw-r--r--drivers/acpi/acpica/rsinfo.c2
-rw-r--r--drivers/acpi/acpica/rsio.c2
-rw-r--r--drivers/acpi/acpica/rsirq.c2
-rw-r--r--drivers/acpi/acpica/rslist.c2
-rw-r--r--drivers/acpi/acpica/rsmemory.c2
-rw-r--r--drivers/acpi/acpica/rsmisc.c2
-rw-r--r--drivers/acpi/acpica/rsutils.c2
-rw-r--r--drivers/acpi/acpica/rsxface.c2
-rw-r--r--drivers/acpi/acpica/tbfadt.c2
-rw-r--r--drivers/acpi/acpica/tbfind.c2
-rw-r--r--drivers/acpi/acpica/tbinstal.c2
-rw-r--r--drivers/acpi/acpica/tbutils.c2
-rw-r--r--drivers/acpi/acpica/tbxface.c2
-rw-r--r--drivers/acpi/acpica/tbxfroot.c2
-rw-r--r--drivers/acpi/acpica/utalloc.c2
-rw-r--r--drivers/acpi/acpica/utcopy.c2
-rw-r--r--drivers/acpi/acpica/utdebug.c5
-rw-r--r--drivers/acpi/acpica/utdelete.c2
-rw-r--r--drivers/acpi/acpica/uteval.c4
-rw-r--r--drivers/acpi/acpica/utglobal.c4
-rw-r--r--drivers/acpi/acpica/utids.c2
-rw-r--r--drivers/acpi/acpica/utinit.c2
-rw-r--r--drivers/acpi/acpica/utlock.c2
-rw-r--r--drivers/acpi/acpica/utmath.c27
-rw-r--r--drivers/acpi/acpica/utmisc.c16
-rw-r--r--drivers/acpi/acpica/utmutex.c18
-rw-r--r--drivers/acpi/acpica/utobject.c2
-rw-r--r--drivers/acpi/acpica/utresrc.c2
-rw-r--r--drivers/acpi/acpica/utstate.c2
-rw-r--r--drivers/acpi/acpica/utxface.c2
-rw-r--r--drivers/acpi/battery.c4
-rw-r--r--drivers/acpi/bus.c17
-rw-r--r--drivers/acpi/button.c15
-rw-r--r--drivers/acpi/dock.c3
-rw-r--r--drivers/acpi/ec.c185
-rw-r--r--drivers/acpi/glue.c4
-rw-r--r--drivers/acpi/internal.h4
-rw-r--r--drivers/acpi/numa.c4
-rw-r--r--drivers/acpi/osl.c4
-rw-r--r--drivers/acpi/pci_bind.c14
-rw-r--r--drivers/acpi/pci_link.c2
-rw-r--r--drivers/acpi/pci_root.c11
-rw-r--r--drivers/acpi/power.c2
-rw-r--r--drivers/acpi/power_meter.c34
-rw-r--r--drivers/acpi/proc.c2
-rw-r--r--drivers/acpi/processor_core.c1116
-rw-r--r--drivers/acpi/processor_driver.c978
-rw-r--r--drivers/acpi/processor_idle.c102
-rw-r--r--drivers/acpi/processor_pdc.c165
-rw-r--r--drivers/acpi/processor_perflib.c8
-rw-r--r--drivers/acpi/processor_thermal.c3
-rw-r--r--drivers/acpi/processor_throttling.c27
-rw-r--r--drivers/acpi/sbs.c3
-rw-r--r--drivers/acpi/sbshc.c2
-rw-r--r--drivers/acpi/scan.c65
-rw-r--r--drivers/acpi/sleep.c34
-rw-r--r--drivers/acpi/system.c6
-rw-r--r--drivers/acpi/tables.c4
-rw-r--r--drivers/acpi/thermal.c36
-rw-r--r--drivers/acpi/utils.c61
-rw-r--r--drivers/acpi/video.c73
-rw-r--r--drivers/acpi/wakeup.c84
-rw-r--r--drivers/ata/Kconfig4
-rw-r--r--drivers/ata/ahci.c262
-rw-r--r--drivers/ata/ata_generic.c2
-rw-r--r--drivers/ata/ata_piix.c28
-rw-r--r--drivers/ata/libata-acpi.c4
-rw-r--r--drivers/ata/libata-core.c19
-rw-r--r--drivers/ata/libata-eh.c5
-rw-r--r--drivers/ata/libata-scsi.c4
-rw-r--r--drivers/ata/libata-sff.c55
-rw-r--r--drivers/ata/pata_acpi.c4
-rw-r--r--drivers/ata/pata_ali.c10
-rw-r--r--drivers/ata/pata_amd.c2
-rw-r--r--drivers/ata/pata_artop.c2
-rw-r--r--drivers/ata/pata_at91.c4
-rw-r--r--drivers/ata/pata_atiixp.c14
-rw-r--r--drivers/ata/pata_cmd640.c2
-rw-r--r--drivers/ata/pata_cmd64x.c27
-rw-r--r--drivers/ata/pata_cs5530.c2
-rw-r--r--drivers/ata/pata_cs5535.c4
-rw-r--r--drivers/ata/pata_cs5536.c2
-rw-r--r--drivers/ata/pata_cypress.c12
-rw-r--r--drivers/ata/pata_efar.c22
-rw-r--r--drivers/ata/pata_hpt366.c23
-rw-r--r--drivers/ata/pata_hpt37x.c189
-rw-r--r--drivers/ata/pata_hpt3x2n.c120
-rw-r--r--drivers/ata/pata_hpt3x3.c2
-rw-r--r--drivers/ata/pata_it8213.c2
-rw-r--r--drivers/ata/pata_it821x.c2
-rw-r--r--drivers/ata/pata_jmicron.c2
-rw-r--r--drivers/ata/pata_marvell.c4
-rw-r--r--drivers/ata/pata_netcell.c2
-rw-r--r--drivers/ata/pata_ns87410.c2
-rw-r--r--drivers/ata/pata_ns87415.c2
-rw-r--r--drivers/ata/pata_oldpiix.c2
-rw-r--r--drivers/ata/pata_opti.c2
-rw-r--r--drivers/ata/pata_optidma.c2
-rw-r--r--drivers/ata/pata_pcmcia.c4
-rw-r--r--drivers/ata/pata_pdc202xx_old.c17
-rw-r--r--drivers/ata/pata_piccolo.c2
-rw-r--r--drivers/ata/pata_radisys.c2
-rw-r--r--drivers/ata/pata_rz1000.c2
-rw-r--r--drivers/ata/pata_sc1200.c2
-rw-r--r--drivers/ata/pata_serverworks.c7
-rw-r--r--drivers/ata/pata_sil680.c2
-rw-r--r--drivers/ata/pata_sis.c2
-rw-r--r--drivers/ata/pata_sl82c105.c2
-rw-r--r--drivers/ata/pata_triflex.c2
-rw-r--r--drivers/ata/pata_via.c210
-rw-r--r--drivers/ata/sata_nv.c2
-rw-r--r--drivers/ata/sata_via.c23
-rw-r--r--drivers/atm/fore200e.c11
-rw-r--r--drivers/atm/idt77252.c5
-rw-r--r--drivers/atm/lanai.c14
-rw-r--r--drivers/atm/nicstar.c4
-rw-r--r--drivers/auxdisplay/cfag12864bfb.c2
-rw-r--r--drivers/base/Kconfig51
-rw-r--r--drivers/base/bus.c26
-rw-r--r--drivers/base/class.c18
-rw-r--r--drivers/base/core.c46
-rw-r--r--drivers/base/cpu.c105
-rw-r--r--drivers/base/dd.c38
-rw-r--r--drivers/base/devtmpfs.c16
-rw-r--r--drivers/base/firmware_class.c11
-rw-r--r--drivers/base/memory.c22
-rw-r--r--drivers/base/node.c81
-rw-r--r--drivers/base/platform.c76
-rw-r--r--drivers/base/power/Makefile1
-rw-r--r--drivers/base/power/generic_ops.c233
-rw-r--r--drivers/base/power/main.c163
-rw-r--r--drivers/base/power/power.h6
-rw-r--r--drivers/base/power/runtime.c45
-rw-r--r--drivers/base/power/sysfs.c100
-rw-r--r--drivers/base/sys.c17
-rw-r--r--drivers/block/DAC960.c6
-rw-r--r--drivers/block/ataflop.c2
-rw-r--r--drivers/block/brd.c2
-rw-r--r--drivers/block/cciss.c221
-rw-r--r--drivers/block/cciss.h21
-rw-r--r--drivers/block/cciss_cmd.h164
-rw-r--r--drivers/block/cciss_scsi.c145
-rw-r--r--drivers/block/cciss_scsi.h18
-rw-r--r--drivers/block/cpqarray.c5
-rw-r--r--drivers/block/drbd/Kconfig2
-rw-r--r--drivers/block/drbd/drbd_int.h11
-rw-r--r--drivers/block/drbd/drbd_main.c3
-rw-r--r--drivers/block/drbd/drbd_nl.c24
-rw-r--r--drivers/block/drbd/drbd_receiver.c48
-rw-r--r--drivers/block/drbd/drbd_req.h2
-rw-r--r--drivers/block/floppy.c1495
-rw-r--r--drivers/block/hd.c2
-rw-r--r--drivers/block/mg_disk.c2
-rw-r--r--drivers/block/osdblk.c12
-rw-r--r--drivers/block/paride/pd.c2
-rw-r--r--drivers/block/paride/pf.c3
-rw-r--r--drivers/block/pktcdvd.c113
-rw-r--r--drivers/block/ps3disk.c5
-rw-r--r--drivers/block/ps3vram.c7
-rw-r--r--drivers/block/sunvdc.c5
-rw-r--r--drivers/block/swim.c4
-rw-r--r--drivers/block/sx8.c5
-rw-r--r--drivers/block/ub.c7
-rw-r--r--drivers/block/viodasd.c91
-rw-r--r--drivers/block/virtio_blk.c63
-rw-r--r--drivers/block/xd.c2
-rw-r--r--drivers/block/xen-blkfront.c7
-rw-r--r--drivers/block/xsysace.c2
-rw-r--r--drivers/bluetooth/Kconfig13
-rw-r--r--drivers/bluetooth/Makefile1
-rw-r--r--drivers/bluetooth/ath3k.c189
-rw-r--r--drivers/bluetooth/bcm203x.c2
-rw-r--r--drivers/bluetooth/bfusb.c2
-rw-r--r--drivers/bluetooth/bluecard_cs.c6
-rw-r--r--drivers/bluetooth/bpa10x.c2
-rw-r--r--drivers/bluetooth/bt3c_cs.c6
-rw-r--r--drivers/bluetooth/btmrvl_debugfs.c14
-rw-r--r--drivers/bluetooth/btmrvl_main.c2
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c5
-rw-r--r--drivers/bluetooth/btsdio.c2
-rw-r--r--drivers/bluetooth/btuart_cs.c6
-rw-r--r--drivers/bluetooth/btusb.c2
-rw-r--r--drivers/bluetooth/dtl1_cs.c6
-rw-r--r--drivers/bluetooth/hci_ldisc.c2
-rw-r--r--drivers/bluetooth/hci_vhci.c2
-rw-r--r--drivers/cdrom/gdrom.c2
-rw-r--r--drivers/cdrom/viocd.c5
-rw-r--r--drivers/char/ChangeLog775
-rw-r--r--drivers/char/Kconfig10
-rw-r--r--drivers/char/agp/Kconfig2
-rw-r--r--drivers/char/agp/amd64-agp.c19
-rw-r--r--drivers/char/agp/intel-agp.c146
-rw-r--r--drivers/char/applicom.c2
-rw-r--r--drivers/char/cyclades.c16
-rw-r--r--drivers/char/hvc_beat.c4
-rw-r--r--drivers/char/hvc_console.c11
-rw-r--r--drivers/char/hvc_console.h9
-rw-r--r--drivers/char/hvc_iseries.c4
-rw-r--r--drivers/char/hvc_iucv.c8
-rw-r--r--drivers/char/hvc_rtas.c2
-rw-r--r--drivers/char/hvc_udbg.c2
-rw-r--r--drivers/char/hvc_vio.c2
-rw-r--r--drivers/char/hvc_xen.c2
-rw-r--r--drivers/char/hw_random/Kconfig14
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/n2-drv.c2
-rw-r--r--drivers/char/hw_random/nomadik-rng.c103
-rw-r--r--drivers/char/hw_random/virtio-rng.c6
-rw-r--r--drivers/char/ip2/i2hw.h2
-rw-r--r--drivers/char/ip2/ip2main.c26
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c71
-rw-r--r--drivers/char/isicom.c54
-rw-r--r--drivers/char/keyboard.c29
-rw-r--r--drivers/char/mem.c225
-rw-r--r--drivers/char/mmtimer.c2
-rw-r--r--drivers/char/moxa.c20
-rw-r--r--drivers/char/mxser.c3
-rw-r--r--drivers/char/n_tty.c17
-rw-r--r--drivers/char/nozomi.c157
-rw-r--r--drivers/char/nvram.c3
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c2
-rw-r--r--drivers/char/pty.c2
-rw-r--r--drivers/char/random.c11
-rw-r--r--drivers/char/serial167.c5
-rw-r--r--drivers/char/specialix.c2
-rw-r--r--drivers/char/synclink.c4
-rw-r--r--drivers/char/synclink_gt.c186
-rw-r--r--drivers/char/tpm/tpm_infineon.c79
-rw-r--r--drivers/char/tty_audit.c1
-rw-r--r--drivers/char/tty_buffer.c17
-rw-r--r--drivers/char/tty_io.c4
-rw-r--r--drivers/char/tty_ldisc.c50
-rw-r--r--drivers/char/uv_mmtimer.c18
-rw-r--r--drivers/char/virtio_console.c1581
-rw-r--r--drivers/char/vme_scc.c12
-rw-r--r--drivers/char/vt.c6
-rw-r--r--drivers/char/vt_ioctl.c39
-rw-r--r--drivers/clocksource/Kconfig9
-rw-r--r--drivers/clocksource/cs5535-clockevt.c2
-rw-r--r--drivers/clocksource/sh_cmt.c67
-rw-r--r--drivers/clocksource/sh_mtu2.c6
-rw-r--r--drivers/clocksource/sh_tmu.c6
-rw-r--r--drivers/connector/connector.c175
-rw-r--r--drivers/cpufreq/cpufreq.c2
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c3
-rw-r--r--drivers/cpuidle/governors/menu.c2
-rw-r--r--drivers/cpuidle/sysfs.c8
-rw-r--r--drivers/crypto/amcc/crypto4xx_core.c2
-rw-r--r--drivers/crypto/geode-aes.c8
-rw-r--r--drivers/crypto/hifn_795x.c2
-rw-r--r--drivers/crypto/padlock-sha.c23
-rw-r--r--drivers/crypto/talitos.c2
-rw-r--r--drivers/dma/Kconfig23
-rw-r--r--drivers/dma/Makefile8
-rw-r--r--drivers/dma/coh901318.c184
-rw-r--r--drivers/dma/coh901318_lli.c23
-rw-r--r--drivers/dma/coh901318_lli.h2
-rw-r--r--drivers/dma/dmaengine.c3
-rw-r--r--drivers/dma/dmatest.c10
-rw-r--r--drivers/dma/fsldma.c1177
-rw-r--r--drivers/dma/fsldma.h35
-rw-r--r--drivers/dma/ioat/dma.c50
-rw-r--r--drivers/dma/ioat/dma.h13
-rw-r--r--drivers/dma/ioat/dma_v2.c72
-rw-r--r--drivers/dma/ioat/dma_v2.h6
-rw-r--r--drivers/dma/ioat/dma_v3.c64
-rw-r--r--drivers/dma/ioat/registers.h2
-rw-r--r--drivers/dma/ipu/ipu_idmac.c40
-rw-r--r--drivers/dma/mpc512x_dma.c800
-rw-r--r--drivers/dma/ppc4xx/adma.c2
-rw-r--r--drivers/dma/shdma.c841
-rw-r--r--drivers/dma/shdma.h31
-rw-r--r--drivers/edac/amd64_edac.c56
-rw-r--r--drivers/edac/amd64_edac.h3
-rw-r--r--drivers/edac/e752x_edac.c117
-rw-r--r--drivers/edac/edac_device_sysfs.c6
-rw-r--r--drivers/edac/edac_mc_sysfs.c4
-rw-r--r--drivers/edac/edac_pci_sysfs.c4
-rw-r--r--drivers/edac/i5000_edac.c8
-rw-r--r--drivers/edac/mpc85xx_edac.c171
-rw-r--r--drivers/edac/mpc85xx_edac.h3
-rw-r--r--drivers/eisa/eisa-bus.c240
-rw-r--r--drivers/firewire/core-card.c41
-rw-r--r--drivers/firewire/core-cdev.c410
-rw-r--r--drivers/firewire/core-device.c203
-rw-r--r--drivers/firewire/core-transaction.c17
-rw-r--r--drivers/firewire/core.h2
-rw-r--r--drivers/firewire/net.c53
-rw-r--r--drivers/firewire/ohci.c375
-rw-r--r--drivers/firewire/sbp2.c7
-rw-r--r--drivers/firmware/edd.c2
-rw-r--r--drivers/firmware/efivars.c2
-rw-r--r--drivers/firmware/iscsi_ibft.c16
-rw-r--r--drivers/firmware/memmap.c59
-rw-r--r--drivers/gpio/Kconfig57
-rw-r--r--drivers/gpio/Makefile6
-rw-r--r--drivers/gpio/cs5535-gpio.c4
-rw-r--r--drivers/gpio/gpiolib.c66
-rw-r--r--drivers/gpio/it8761e_gpio.c231
-rw-r--r--drivers/gpio/max7300.c94
-rw-r--r--drivers/gpio/max7301.c293
-rw-r--r--drivers/gpio/max730x.c244
-rw-r--r--drivers/gpio/pca953x.c249
-rw-r--r--drivers/gpio/pl061.c2
-rw-r--r--drivers/gpio/sch_gpio.c295
-rw-r--r--drivers/gpio/timbgpio.c35
-rw-r--r--drivers/gpio/wm831x-gpio.c45
-rw-r--r--drivers/gpio/wm8350-gpiolib.c181
-rw-r--r--drivers/gpio/wm8994-gpio.c204
-rw-r--r--drivers/gpu/drm/Kconfig2
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/ati_pcigart.c2
-rw-r--r--drivers/gpu/drm/drm_buffer.c184
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c6
-rw-r--r--drivers/gpu/drm/drm_drv.c44
-rw-r--r--drivers/gpu/drm/drm_edid.c80
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c28
-rw-r--r--drivers/gpu/drm/drm_gem.c83
-rw-r--r--drivers/gpu/drm/drm_mm.c3
-rw-r--r--drivers/gpu/drm/drm_sysfs.c18
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c255
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c334
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c175
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h85
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c567
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c169
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c413
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h173
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c10
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c38
-rw-r--r--drivers/gpu/drm/i915/intel_bios.h40
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c17
-rw-r--r--drivers/gpu/drm/i915/intel_display.c568
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c81
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c4
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c54
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c2
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c74
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c29
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c114
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c2
-rw-r--r--drivers/gpu/drm/nouveau/Makefile2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c160
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c544
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h126
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c12
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_calc.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_channel.c46
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c201
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_debugfs.c24
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.c168
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.h21
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c23
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h61
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c46
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.h6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c502
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_grctx.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_hw.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.c10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_irq.c167
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c128
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_notifier.c22
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_object.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_reg.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sgdma.c7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c90
-rw-r--r--drivers/gpu/drm/nouveau/nv04_crtc.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dac.c14
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dfp.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv04_display.c49
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fbcon.c11
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fifo.c5
-rw-r--r--drivers/gpu/drm/nouveau/nv04_instmem.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv04_tv.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv17_tv.c8
-rw-r--r--drivers/gpu/drm/nouveau/nv40_fifo.c5
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c37
-rw-r--r--drivers/gpu/drm/nouveau/nv50_dac.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c54
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fbcon.c11
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fifo.c24
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c87
-rw-r--r--drivers/gpu/drm/nouveau/nv50_grctx.c2367
-rw-r--r--drivers/gpu/drm/nouveau/nv50_instmem.c60
-rw-r--r--drivers/gpu/drm/nouveau/nv50_sor.c14
-rw-r--r--drivers/gpu/drm/radeon/Kconfig12
-rw-r--r--drivers/gpu/drm/radeon/Makefile9
-rw-r--r--drivers/gpu/drm/radeon/atom.c109
-rw-r--r--drivers/gpu/drm/radeon/atom.h1
-rw-r--r--drivers/gpu/drm/radeon/atombios.h7300
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c677
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c95
-rw-r--r--drivers/gpu/drm/radeon/avivod.h2
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c767
-rw-r--r--drivers/gpu/drm/radeon/evergreen_reg.h176
-rw-r--r--drivers/gpu/drm/radeon/r100.c193
-rw-r--r--drivers/gpu/drm/radeon/r200.c53
-rw-r--r--drivers/gpu/drm/radeon/r300.c171
-rw-r--r--drivers/gpu/drm/radeon/r300_cmdbuf.c280
-rw-r--r--drivers/gpu/drm/radeon/r300_reg.h2
-rw-r--r--drivers/gpu/drm/radeon/r420.c54
-rw-r--r--drivers/gpu/drm/radeon/r500_reg.h100
-rw-r--r--drivers/gpu/drm/radeon/r520.c24
-rw-r--r--drivers/gpu/drm/radeon/r600.c370
-rw-r--r--drivers/gpu/drm/radeon/r600_audio.c20
-rw-r--r--drivers/gpu/drm/radeon/r600_blit.c2
-rw-r--r--drivers/gpu/drm/radeon/r600_blit_kms.c41
-rw-r--r--drivers/gpu/drm/radeon/r600_blit_shaders.c10
-rw-r--r--drivers/gpu/drm/radeon/r600_cp.c259
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c806
-rw-r--r--drivers/gpu/drm/radeon/r600d.h490
-rw-r--r--drivers/gpu/drm/radeon/radeon.h196
-rw-r--r--drivers/gpu/drm/radeon/radeon_agp.c15
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h183
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c453
-rw-r--r--drivers/gpu/drm/radeon/radeon_atpx_handler.c257
-rw-r--r--drivers/gpu/drm/radeon/radeon_benchmark.c55
-rw-r--r--drivers/gpu/drm/radeon/radeon_bios.c50
-rw-r--r--drivers/gpu/drm/radeon/radeon_clocks.c22
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c337
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c31
-rw-r--r--drivers/gpu/drm/radeon/radeon_cp.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c18
-rw-r--r--drivers/gpu/drm/radeon/radeon_cursor.c50
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c236
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c384
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c14
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.h49
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c493
-rw-r--r--drivers/gpu/drm/radeon/radeon_family.h5
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c14
-rw-r--r--drivers/gpu/drm/radeon/radeon_gart.c32
-rw-r--r--drivers/gpu/drm/radeon/radeon_gem.c39
-rw-r--r--drivers/gpu/drm/radeon/radeon_i2c.c768
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c27
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c106
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_encoders.c20
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h83
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c42
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.h4
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c399
-rw-r--r--drivers/gpu/drm/radeon/radeon_reg.h50
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c174
-rw-r--r--drivers/gpu/drm/radeon/radeon_state.c205
-rw-r--r--drivers/gpu/drm/radeon/radeon_test.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c12
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/r2002
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/r600837
-rw-r--r--drivers/gpu/drm/radeon/rs400.c67
-rw-r--r--drivers/gpu/drm/radeon/rs600.c58
-rw-r--r--drivers/gpu/drm/radeon/rs690.c43
-rw-r--r--drivers/gpu/drm/radeon/rv515.c25
-rw-r--r--drivers/gpu/drm/radeon/rv770.c332
-rw-r--r--drivers/gpu/drm/radeon/rv770d.h2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c77
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c9
-rw-r--r--drivers/gpu/drm/ttm/ttm_lock.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_memory.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_object.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_tt.c53
-rw-r--r--drivers/gpu/drm/via/via_irq.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c25
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c125
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h18
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c127
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fb.c11
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c37
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c8
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_irq.c13
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c30
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c9
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c64
-rw-r--r--drivers/gpu/vga/Kconfig19
-rw-r--r--drivers/gpu/vga/Makefile1
-rw-r--r--drivers/gpu/vga/vga_switcheroo.c450
-rw-r--r--drivers/gpu/vga/vgaarb.c29
-rw-r--r--drivers/hid/Kconfig54
-rw-r--r--drivers/hid/Makefile9
-rw-r--r--drivers/hid/hid-3m-pct.c290
-rw-r--r--drivers/hid/hid-apple.c17
-rw-r--r--drivers/hid/hid-core.c23
-rw-r--r--drivers/hid/hid-debug.c6
-rw-r--r--drivers/hid/hid-ids.h37
-rw-r--r--drivers/hid/hid-input.c36
-rw-r--r--drivers/hid/hid-lg.c7
-rw-r--r--drivers/hid/hid-lg.h6
-rw-r--r--drivers/hid/hid-lg3ff.c176
-rw-r--r--drivers/hid/hid-lgff.c1
-rw-r--r--drivers/hid/hid-magicmouse.c449
-rw-r--r--drivers/hid/hid-mosart.c273
-rw-r--r--drivers/hid/hid-ntrig.c212
-rw-r--r--drivers/hid/hid-ortek.c56
-rw-r--r--drivers/hid/hid-quanta.c260
-rw-r--r--drivers/hid/hid-sony.c23
-rw-r--r--drivers/hid/hid-stantum.c283
-rw-r--r--drivers/hid/hid-wacom.c28
-rw-r--r--drivers/hid/hidraw.c2
-rw-r--r--drivers/hid/usbhid/hid-core.c42
-rw-r--r--drivers/hid/usbhid/hid-quirks.c3
-rw-r--r--drivers/hid/usbhid/hiddev.c7
-rw-r--r--drivers/hid/usbhid/usbhid.h2
-rw-r--r--drivers/hwmon/Kconfig45
-rw-r--r--drivers/hwmon/Makefile3
-rw-r--r--drivers/hwmon/adcxx.c15
-rw-r--r--drivers/hwmon/adt7411.c366
-rw-r--r--drivers/hwmon/adt7462.c2
-rw-r--r--drivers/hwmon/adt7473.c1180
-rw-r--r--drivers/hwmon/amc6821.c1
-rw-r--r--drivers/hwmon/ams/ams-core.c11
-rw-r--r--drivers/hwmon/ams/ams-i2c.c2
-rw-r--r--drivers/hwmon/ams/ams-pmu.c2
-rw-r--r--drivers/hwmon/ams/ams.h1
-rw-r--r--drivers/hwmon/asc7621.c1255
-rw-r--r--drivers/hwmon/asus_atk0110.c19
-rw-r--r--drivers/hwmon/fschmd.c22
-rw-r--r--drivers/hwmon/g760a.c2
-rw-r--r--drivers/hwmon/it87.c939
-rw-r--r--drivers/hwmon/lm78.c25
-rw-r--r--drivers/hwmon/lm90.c89
-rw-r--r--drivers/hwmon/smsc47m1.c2
-rw-r--r--drivers/hwmon/tmp401.c7
-rw-r--r--drivers/hwmon/tmp421.c24
-rw-r--r--drivers/hwmon/vt8231.c3
-rw-r--r--drivers/hwmon/w83781d.c26
-rw-r--r--drivers/hwmon/w83793.c482
-rw-r--r--drivers/i2c/Kconfig19
-rw-r--r--drivers/i2c/Makefile3
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c9
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c2
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c2
-rw-r--r--drivers/i2c/busses/Kconfig43
-rw-r--r--drivers/i2c/busses/Makefile3
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c2
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c10
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c2
-rw-r--r--drivers/i2c/busses/i2c-amd756.c2
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c2
-rw-r--r--drivers/i2c/busses/i2c-designware.c4
-rw-r--r--drivers/i2c/busses/i2c-hydra.c2
-rw-r--r--drivers/i2c/busses/i2c-i801.c13
-rw-r--r--drivers/i2c/busses/i2c-imx.c27
-rw-r--r--drivers/i2c/busses/i2c-isch.c68
-rw-r--r--drivers/i2c/busses/i2c-mpc.c194
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c2
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c959
-rw-r--r--drivers/i2c/busses/i2c-octeon.c651
-rw-r--r--drivers/i2c/busses/i2c-omap.c46
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c48
-rw-r--r--drivers/i2c/busses/i2c-parport.c43
-rw-r--r--drivers/i2c/busses/i2c-parport.h4
-rw-r--r--drivers/i2c/busses/i2c-pasemi.c2
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c4
-rw-r--r--drivers/i2c/busses/i2c-pca-platform.c4
-rw-r--r--drivers/i2c/busses/i2c-piix4.c6
-rw-r--r--drivers/i2c/busses/i2c-pnx.c296
-rw-r--r--drivers/i2c/busses/i2c-powermac.c25
-rw-r--r--drivers/i2c/busses/i2c-pxa.c2
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c2
-rw-r--r--drivers/i2c/busses/i2c-sis630.c2
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c2
-rw-r--r--drivers/i2c/busses/i2c-tiny-usb.c22
-rw-r--r--drivers/i2c/busses/i2c-via.c2
-rw-r--r--drivers/i2c/busses/i2c-viapro.c6
-rw-r--r--drivers/i2c/busses/i2c-xiic.c825
-rw-r--r--drivers/i2c/chips/Kconfig19
-rw-r--r--drivers/i2c/chips/Makefile18
-rw-r--r--drivers/i2c/i2c-core.c61
-rw-r--r--drivers/i2c/i2c-smbus.c262
-rw-r--r--drivers/ide/aec62xx.c13
-rw-r--r--drivers/ide/ali14xx.c3
-rw-r--r--drivers/ide/alim15x3.c171
-rw-r--r--drivers/ide/amd74xx.c18
-rw-r--r--drivers/ide/at91_ide.c5
-rw-r--r--drivers/ide/atiixp.c14
-rw-r--r--drivers/ide/au1xxx-ide.c34
-rw-r--r--drivers/ide/cmd640.c5
-rw-r--r--drivers/ide/cmd64x.c114
-rw-r--r--drivers/ide/cs5520.c9
-rw-r--r--drivers/ide/cs5530.c13
-rw-r--r--drivers/ide/cs5535.c14
-rw-r--r--drivers/ide/cs5536.c16
-rw-r--r--drivers/ide/cy82c693.c146
-rw-r--r--drivers/ide/dtc2278.c4
-rw-r--r--drivers/ide/hpt366.c9
-rw-r--r--drivers/ide/ht6560b.c3
-rw-r--r--drivers/ide/icside.c67
-rw-r--r--drivers/ide/ide-acpi.c8
-rw-r--r--drivers/ide/ide-cs.c23
-rw-r--r--drivers/ide/ide-devsets.c6
-rw-r--r--drivers/ide/ide-disk.c2
-rw-r--r--drivers/ide/ide-floppy.c4
-rw-r--r--drivers/ide/ide-iops.c2
-rw-r--r--drivers/ide/ide-probe.c7
-rw-r--r--drivers/ide/ide-tape.c14
-rw-r--r--drivers/ide/ide-timings.c18
-rw-r--r--drivers/ide/ide-xfer-mode.c18
-rw-r--r--drivers/ide/it8172.c14
-rw-r--r--drivers/ide/it8213.c20
-rw-r--r--drivers/ide/it821x.c14
-rw-r--r--drivers/ide/jmicron.c6
-rw-r--r--drivers/ide/opti621.c77
-rw-r--r--drivers/ide/palm_bk3710.c12
-rw-r--r--drivers/ide/pdc202xx_new.c8
-rw-r--r--drivers/ide/pdc202xx_old.c31
-rw-r--r--drivers/ide/piix.c20
-rw-r--r--drivers/ide/pmac.c13
-rw-r--r--drivers/ide/qd65xx.c10
-rw-r--r--drivers/ide/sc1200.c8
-rw-r--r--drivers/ide/scc_pata.c24
-rw-r--r--drivers/ide/serverworks.c50
-rw-r--r--drivers/ide/sgiioc4.c2
-rw-r--r--drivers/ide/siimage.c14
-rw-r--r--drivers/ide/sis5513.c8
-rw-r--r--drivers/ide/sl82c105.c8
-rw-r--r--drivers/ide/slc90e66.c17
-rw-r--r--drivers/ide/tc86c001.c9
-rw-r--r--drivers/ide/triflex.c10
-rw-r--r--drivers/ide/tx4938ide.c7
-rw-r--r--drivers/ide/tx4939ide.c10
-rw-r--r--drivers/ide/umc8672.c5
-rw-r--r--drivers/ide/via82cxxx.c132
-rw-r--r--drivers/ieee1394/nodemgr.c5
-rw-r--r--drivers/ieee1394/pcilynx.c2
-rw-r--r--drivers/ieee1394/sbp2.c2
-rw-r--r--drivers/infiniband/Kconfig1
-rw-r--r--drivers/infiniband/core/cm.c2
-rw-r--r--drivers/infiniband/core/cma.c4
-rw-r--r--drivers/infiniband/core/mad.c24
-rw-r--r--drivers/infiniband/core/sysfs.c2
-rw-r--r--drivers/infiniband/core/ucm.c76
-rw-r--r--drivers/infiniband/core/ud_header.c14
-rw-r--r--drivers/infiniband/core/umem.c2
-rw-r--r--drivers/infiniband/core/user_mad.c178
-rw-r--r--drivers/infiniband/core/uverbs.h13
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c25
-rw-r--r--drivers/infiniband/core/uverbs_main.c261
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c15
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.h4
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_wr.h17
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch.c82
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch.h2
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c11
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c2
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c9
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c5
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qes.h4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_sqp.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_user_pages.c3
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c4
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c2
-rw-r--r--drivers/infiniband/hw/nes/nes.c1
-rw-r--r--drivers/infiniband/hw/nes/nes.h9
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c11
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c492
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.h3
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c170
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c7
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c12
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ethtool.c10
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c9
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c2
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c47
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h97
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c506
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c64
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c281
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c91
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h6
-rw-r--r--drivers/input/evdev.c7
-rw-r--r--drivers/input/gameport/emu10k1-gp.c2
-rw-r--r--drivers/input/gameport/fm801-gp.c2
-rw-r--r--drivers/input/gameport/gameport.c98
-rw-r--r--drivers/input/gameport/ns558.c2
-rw-r--r--drivers/input/input-compat.h2
-rw-r--r--drivers/input/input-polldev.c6
-rw-r--r--drivers/input/input.c215
-rw-r--r--drivers/input/joydev.c34
-rw-r--r--drivers/input/joystick/Kconfig1
-rw-r--r--drivers/input/joystick/gamecon.c666
-rw-r--r--drivers/input/joystick/gf2k.c2
-rw-r--r--drivers/input/joystick/xpad.c255
-rw-r--r--drivers/input/keyboard/Kconfig33
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/adp5588-keys.c6
-rw-r--r--drivers/input/keyboard/atkbd.c378
-rw-r--r--drivers/input/keyboard/bf54x-keys.c2
-rw-r--r--drivers/input/keyboard/davinci_keyscan.c8
-rw-r--r--drivers/input/keyboard/ep93xx_keypad.c40
-rw-r--r--drivers/input/keyboard/gpio_keys.c318
-rw-r--r--drivers/input/keyboard/imx_keypad.c594
-rw-r--r--drivers/input/keyboard/locomokbd.c32
-rw-r--r--drivers/input/keyboard/qt2160.c2
-rw-r--r--drivers/input/keyboard/sh_keysc.c145
-rw-r--r--drivers/input/misc/88pm860x_onkey.c155
-rw-r--r--drivers/input/misc/Kconfig21
-rw-r--r--drivers/input/misc/Makefile2
-rw-r--r--drivers/input/misc/apanel.c2
-rw-r--r--drivers/input/misc/ati_remote2.c14
-rw-r--r--drivers/input/misc/atlas_btns.c2
-rw-r--r--drivers/input/misc/rotary_encoder.c14
-rw-r--r--drivers/input/misc/twl4030-vibra.c297
-rw-r--r--drivers/input/misc/uinput.c4
-rw-r--r--drivers/input/misc/winbond-cir.c227
-rw-r--r--drivers/input/misc/wm831x-on.c9
-rw-r--r--drivers/input/misc/yealink.h2
-rw-r--r--drivers/input/mouse/alps.c49
-rw-r--r--drivers/input/mouse/appletouch.c6
-rw-r--r--drivers/input/mouse/bcm5974.c44
-rw-r--r--drivers/input/mouse/hgpk.c4
-rw-r--r--drivers/input/mouse/lifebook.c6
-rw-r--r--drivers/input/mouse/psmouse-base.c78
-rw-r--r--drivers/input/mouse/sentelic.c6
-rw-r--r--drivers/input/mouse/synaptics.c10
-rw-r--r--drivers/input/mouse/synaptics.h1
-rw-r--r--drivers/input/mousedev.c6
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h17
-rw-r--r--drivers/input/serio/i8042.c34
-rw-r--r--drivers/input/serio/pcips2.c2
-rw-r--r--drivers/input/serio/serio.c131
-rw-r--r--drivers/input/serio/serio_raw.c11
-rw-r--r--drivers/input/serio/xilinx_ps2.c6
-rw-r--r--drivers/input/sparse-keymap.c6
-rw-r--r--drivers/input/tablet/aiptek.c2
-rw-r--r--drivers/input/tablet/gtco.c2
-rw-r--r--drivers/input/tablet/wacom.h5
-rw-r--r--drivers/input/tablet/wacom_sys.c74
-rw-r--r--drivers/input/tablet/wacom_wac.c565
-rw-r--r--drivers/input/tablet/wacom_wac.h18
-rw-r--r--drivers/input/touchscreen/88pm860x-ts.c236
-rw-r--r--drivers/input/touchscreen/Kconfig27
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/ad7877.c2
-rw-r--r--drivers/input/touchscreen/ad7879.c197
-rw-r--r--drivers/input/touchscreen/ads7846.c48
-rw-r--r--drivers/input/touchscreen/elo.c225
-rw-r--r--drivers/input/touchscreen/mainstone-wm97xx.c3
-rw-r--r--drivers/input/touchscreen/mc13783_ts.c4
-rw-r--r--drivers/input/touchscreen/s3c2410_ts.c31
-rw-r--r--drivers/input/touchscreen/tsc2007.c2
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c325
-rw-r--r--drivers/input/touchscreen/zylonite-wm97xx.c3
-rw-r--r--drivers/input/xen-kbdfront.c2
-rw-r--r--drivers/isdn/Kconfig43
-rw-r--r--drivers/isdn/capi/Kconfig16
-rw-r--r--drivers/isdn/capi/capi.c1203
-rw-r--r--drivers/isdn/capi/capidrv.c103
-rw-r--r--drivers/isdn/capi/capifs.c126
-rw-r--r--drivers/isdn/capi/capifs.h21
-rw-r--r--drivers/isdn/capi/kcapi.c817
-rw-r--r--drivers/isdn/capi/kcapi.h13
-rw-r--r--drivers/isdn/capi/kcapi_proc.c41
-rw-r--r--drivers/isdn/gigaset/asyncdata.c6
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c18
-rw-r--r--drivers/isdn/gigaset/capi.c106
-rw-r--r--drivers/isdn/gigaset/common.c49
-rw-r--r--drivers/isdn/gigaset/ev-layer.c63
-rw-r--r--drivers/isdn/gigaset/gigaset.h11
-rw-r--r--drivers/isdn/gigaset/i4l.c52
-rw-r--r--drivers/isdn/gigaset/interface.c12
-rw-r--r--drivers/isdn/gigaset/isocdata.c44
-rw-r--r--drivers/isdn/gigaset/proc.c2
-rw-r--r--drivers/isdn/gigaset/usb-gigaset.c2
-rw-r--r--drivers/isdn/hardware/avm/avmcard.h6
-rw-r--r--drivers/isdn/hardware/avm/b1.c54
-rw-r--r--drivers/isdn/hardware/avm/b1dma.c71
-rw-r--r--drivers/isdn/hardware/avm/b1isa.c2
-rw-r--r--drivers/isdn/hardware/avm/b1pci.c4
-rw-r--r--drivers/isdn/hardware/avm/b1pcmcia.c2
-rw-r--r--drivers/isdn/hardware/avm/c4.c53
-rw-r--r--drivers/isdn/hardware/avm/t1isa.c2
-rw-r--r--drivers/isdn/hardware/avm/t1pci.c2
-rw-r--r--drivers/isdn/hardware/eicon/capimain.c40
-rw-r--r--drivers/isdn/hardware/eicon/diva_didd.c45
-rw-r--r--drivers/isdn/hardware/eicon/divasi.c48
-rw-r--r--drivers/isdn/hardware/eicon/divasproc.c198
-rw-r--r--drivers/isdn/hardware/mISDN/hfcmulti.c2
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNinfineon.c1
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNisar.c4
-rw-r--r--drivers/isdn/hardware/mISDN/w6692.c2
-rw-r--r--drivers/isdn/hisax/Kconfig18
-rw-r--r--drivers/isdn/hisax/avm_pci.c6
-rw-r--r--drivers/isdn/hisax/bkm_a4t.c2
-rw-r--r--drivers/isdn/hisax/bkm_a8.c2
-rw-r--r--drivers/isdn/hisax/diva.c14
-rw-r--r--drivers/isdn/hisax/elsa.c8
-rw-r--r--drivers/isdn/hisax/enternow_pci.c2
-rw-r--r--drivers/isdn/hisax/gazel.c8
-rw-r--r--drivers/isdn/hisax/hfc_pci.c2
-rw-r--r--drivers/isdn/hisax/hisax.h23
-rw-r--r--drivers/isdn/hisax/isar.c2
-rw-r--r--drivers/isdn/hisax/niccy.c6
-rw-r--r--drivers/isdn/hisax/nj_s.c2
-rw-r--r--drivers/isdn/hisax/nj_u.c2
-rw-r--r--drivers/isdn/hisax/sedlbauer.c6
-rw-r--r--drivers/isdn/hisax/telespci.c2
-rw-r--r--drivers/isdn/hisax/w6692.c2
-rw-r--r--drivers/isdn/hysdn/hycapi.c56
-rw-r--r--drivers/isdn/i4l/Kconfig7
-rw-r--r--drivers/isdn/i4l/isdn_common.c2
-rw-r--r--drivers/isdn/mISDN/dsp_core.c4
-rw-r--r--drivers/isdn/mISDN/l1oip_core.c4
-rw-r--r--drivers/isdn/sc/hardware.h2
-rw-r--r--drivers/leds/Kconfig7
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-88pm860x.c325
-rw-r--r--drivers/macintosh/Kconfig7
-rw-r--r--drivers/macintosh/adb.c10
-rw-r--r--drivers/macintosh/mac_hid.c266
-rw-r--r--drivers/macintosh/smu.c2
-rw-r--r--drivers/macintosh/therm_adt746x.c36
-rw-r--r--drivers/macintosh/therm_pm72.c40
-rw-r--r--drivers/macintosh/therm_pm72.h2
-rw-r--r--drivers/macintosh/therm_windtunnel.c4
-rw-r--r--drivers/macintosh/via-cuda.c74
-rw-r--r--drivers/macintosh/via-pmu-backlight.c8
-rw-r--r--drivers/macintosh/via-pmu.c8
-rw-r--r--drivers/macintosh/windfarm_core.c7
-rw-r--r--drivers/macintosh/windfarm_cpufreq_clamp.c6
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c6
-rw-r--r--drivers/macintosh/windfarm_max6690_sensor.c6
-rw-r--r--drivers/macintosh/windfarm_pm112.c2
-rw-r--r--drivers/macintosh/windfarm_pm121.c2
-rw-r--r--drivers/macintosh/windfarm_pm81.c4
-rw-r--r--drivers/macintosh/windfarm_pm91.c2
-rw-r--r--drivers/macintosh/windfarm_smu_controls.c1
-rw-r--r--drivers/macintosh/windfarm_smu_sensors.c6
-rw-r--r--drivers/md/dm-crypt.c3
-rw-r--r--drivers/md/dm-delay.c8
-rw-r--r--drivers/md/dm-ioctl.c24
-rw-r--r--drivers/md/dm-linear.c3
-rw-r--r--drivers/md/dm-log-userspace-transfer.c10
-rw-r--r--drivers/md/dm-log.c3
-rw-r--r--drivers/md/dm-mpath.c111
-rw-r--r--drivers/md/dm-raid1.c55
-rw-r--r--drivers/md/dm-region-hash.c5
-rw-r--r--drivers/md/dm-snap-persistent.c2
-rw-r--r--drivers/md/dm-snap.c34
-rw-r--r--drivers/md/dm-stripe.c5
-rw-r--r--drivers/md/dm-sysfs.c10
-rw-r--r--drivers/md/dm-table.c32
-rw-r--r--drivers/md/dm-uevent.c7
-rw-r--r--drivers/md/dm.c46
-rw-r--r--drivers/md/dm.h4
-rw-r--r--drivers/md/linear.c2
-rw-r--r--drivers/md/md.c18
-rw-r--r--drivers/md/multipath.c4
-rw-r--r--drivers/md/raid0.c4
-rw-r--r--drivers/md/raid1.c4
-rw-r--r--drivers/md/raid10.c4
-rw-r--r--drivers/md/raid5.c18
-rw-r--r--drivers/md/raid5.h2
-rw-r--r--drivers/media/IR/Makefile2
-rw-r--r--drivers/media/IR/ir-functions.c2
-rw-r--r--drivers/media/IR/ir-keymaps.c99
-rw-r--r--drivers/media/IR/ir-keytable.c67
-rw-r--r--drivers/media/IR/ir-sysfs.c211
-rw-r--r--drivers/media/common/saa7146_fops.c11
-rw-r--r--drivers/media/common/saa7146_video.c4
-rw-r--r--drivers/media/common/tuners/tda8290.c12
-rw-r--r--drivers/media/common/tuners/tuner-types.c21
-rw-r--r--drivers/media/common/tuners/tuner-xc2028.c79
-rw-r--r--drivers/media/dvb/Kconfig8
-rw-r--r--drivers/media/dvb/Makefile15
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c21
-rw-r--r--drivers/media/dvb/bt8xx/dst.c12
-rw-r--r--drivers/media/dvb/dm1105/Kconfig1
-rw-r--r--drivers/media/dvb/dm1105/dm1105.c505
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c20
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c12
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h8
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c15
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ringbuffer.c1
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig12
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile3
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.c351
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.h1
-rw-r--r--drivers/media/dvb/dvb-usb/az6027.c1151
-rw-r--r--drivers/media/dvb/dvb-usb/az6027.h14
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c3
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700.h1
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c197
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c160
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h9
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-init.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c5
-rw-r--r--drivers/media/dvb/dvb-usb/dw2102.c95
-rw-r--r--drivers/media/dvb/dvb-usb/friio-fe.c2
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.c141
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.h2
-rw-r--r--drivers/media/dvb/dvb-usb/opera1.c2
-rw-r--r--drivers/media/dvb/firewire/firedtv-1394.c19
-rw-r--r--drivers/media/dvb/firewire/firedtv-avc.c514
-rw-r--r--drivers/media/dvb/firewire/firedtv-dvb.c1
-rw-r--r--drivers/media/dvb/firewire/firedtv-fw.c41
-rw-r--r--drivers/media/dvb/firewire/firedtv.h6
-rw-r--r--drivers/media/dvb/frontends/Kconfig19
-rw-r--r--drivers/media/dvb/frontends/Makefile2
-rw-r--r--drivers/media/dvb/frontends/af9013.h1
-rw-r--r--drivers/media/dvb/frontends/atbm8830.c16
-rw-r--r--drivers/media/dvb/frontends/dib0090.c2
-rw-r--r--drivers/media/dvb/frontends/dib8000.c2
-rw-r--r--drivers/media/dvb/frontends/dib8000.h2
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.c2
-rw-r--r--drivers/media/dvb/frontends/l64781.c4
-rw-r--r--drivers/media/dvb/frontends/lgdt3305.h6
-rw-r--r--drivers/media/dvb/frontends/lnbp21.c3
-rw-r--r--drivers/media/dvb/frontends/mb86a16.c1878
-rw-r--r--drivers/media/dvb/frontends/mb86a16.h52
-rw-r--r--drivers/media/dvb/frontends/mb86a16_priv.h151
-rw-r--r--drivers/media/dvb/frontends/si21xx.c38
-rw-r--r--drivers/media/dvb/frontends/stv0900.h2
-rw-r--r--drivers/media/dvb/frontends/stv0900_core.c109
-rw-r--r--drivers/media/dvb/frontends/stv0900_priv.h11
-rw-r--r--drivers/media/dvb/frontends/stv0900_reg.h6
-rw-r--r--drivers/media/dvb/frontends/stv0900_sw.c54
-rw-r--r--drivers/media/dvb/frontends/stv090x.c486
-rw-r--r--drivers/media/dvb/frontends/stv090x.h13
-rw-r--r--drivers/media/dvb/frontends/stv090x_priv.h17
-rw-r--r--drivers/media/dvb/frontends/stv6110x.c188
-rw-r--r--drivers/media/dvb/frontends/stv6110x.h1
-rw-r--r--drivers/media/dvb/frontends/stv6110x_priv.h1
-rw-r--r--drivers/media/dvb/frontends/tda10021.c4
-rw-r--r--drivers/media/dvb/frontends/tda665x.c257
-rw-r--r--drivers/media/dvb/frontends/tda665x.h52
-rw-r--r--drivers/media/dvb/frontends/tda8261.c2
-rw-r--r--drivers/media/dvb/frontends/zl10036.c2
-rw-r--r--drivers/media/dvb/frontends/zl10039.c1
-rw-r--r--drivers/media/dvb/mantis/Kconfig32
-rw-r--r--drivers/media/dvb/mantis/Makefile28
-rw-r--r--drivers/media/dvb/mantis/hopper_cards.c275
-rw-r--r--drivers/media/dvb/mantis/hopper_vp3028.c88
-rw-r--r--drivers/media/dvb/mantis/hopper_vp3028.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_ca.c207
-rw-r--r--drivers/media/dvb/mantis/mantis_ca.h27
-rw-r--r--drivers/media/dvb/mantis/mantis_cards.c305
-rw-r--r--drivers/media/dvb/mantis/mantis_common.h179
-rw-r--r--drivers/media/dvb/mantis/mantis_core.c238
-rw-r--r--drivers/media/dvb/mantis/mantis_core.h57
-rw-r--r--drivers/media/dvb/mantis/mantis_dma.c256
-rw-r--r--drivers/media/dvb/mantis/mantis_dma.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_dvb.c296
-rw-r--r--drivers/media/dvb/mantis/mantis_dvb.h35
-rw-r--r--drivers/media/dvb/mantis/mantis_evm.c117
-rw-r--r--drivers/media/dvb/mantis/mantis_hif.c238
-rw-r--r--drivers/media/dvb/mantis/mantis_hif.h29
-rw-r--r--drivers/media/dvb/mantis/mantis_i2c.c267
-rw-r--r--drivers/media/dvb/mantis/mantis_i2c.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_input.c148
-rw-r--r--drivers/media/dvb/mantis/mantis_ioc.c130
-rw-r--r--drivers/media/dvb/mantis/mantis_ioc.h51
-rw-r--r--drivers/media/dvb/mantis/mantis_link.h83
-rw-r--r--drivers/media/dvb/mantis/mantis_pci.c172
-rw-r--r--drivers/media/dvb/mantis/mantis_pci.h27
-rw-r--r--drivers/media/dvb/mantis/mantis_pcmcia.c120
-rw-r--r--drivers/media/dvb/mantis/mantis_reg.h197
-rw-r--r--drivers/media/dvb/mantis/mantis_uart.c186
-rw-r--r--drivers/media/dvb/mantis/mantis_uart.h58
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1033.c212
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1033.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1034.c119
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1034.h33
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1041.c358
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1041.h33
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2033.c187
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2033.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2040.c186
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2040.h32
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3028.c38
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3028.h33
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3030.c105
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3030.h30
-rw-r--r--drivers/media/dvb/ngene/Kconfig9
-rw-r--r--drivers/media/dvb/ngene/Makefile11
-rw-r--r--drivers/media/dvb/ngene/ngene-core.c2024
-rw-r--r--drivers/media/dvb/ngene/ngene.h859
-rw-r--r--drivers/media/dvb/siano/sms-cards.c1
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c7
-rw-r--r--drivers/media/dvb/siano/smscoreapi.h77
-rw-r--r--drivers/media/dvb/siano/smsdvb.c318
-rw-r--r--drivers/media/dvb/siano/smsir.c6
-rw-r--r--drivers/media/dvb/ttpci/av7110_ir.c14
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c2
-rw-r--r--drivers/media/dvb/ttpci/budget.c4
-rw-r--r--drivers/media/radio/Kconfig23
-rw-r--r--drivers/media/radio/Makefile2
-rw-r--r--drivers/media/radio/radio-timb.c244
-rw-r--r--drivers/media/radio/saa7706h.c451
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c2
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c8
-rw-r--r--drivers/media/video/Kconfig36
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/bt819.c10
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c4
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c8
-rw-r--r--drivers/media/video/bt8xx/bttv-i2c.c8
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c4
-rw-r--r--drivers/media/video/bt8xx/bttvp.h1
-rw-r--r--drivers/media/video/cafe_ccic.c6
-rw-r--r--drivers/media/video/cpia.c3
-rw-r--r--drivers/media/video/cx18/Kconfig11
-rw-r--r--drivers/media/video/cx18/Makefile2
-rw-r--r--drivers/media/video/cx18/cx18-alsa-main.c293
-rw-r--r--drivers/media/video/cx18/cx18-alsa-mixer.c175
-rw-r--r--drivers/media/video/cx18/cx18-alsa-mixer.h23
-rw-r--r--drivers/media/video/cx18/cx18-alsa-pcm.c354
-rw-r--r--drivers/media/video/cx18/cx18-alsa-pcm.h27
-rw-r--r--drivers/media/video/cx18/cx18-alsa.h75
-rw-r--r--drivers/media/video/cx18/cx18-cards.c2
-rw-r--r--drivers/media/video/cx18/cx18-driver.c70
-rw-r--r--drivers/media/video/cx18/cx18-driver.h50
-rw-r--r--drivers/media/video/cx18/cx18-dvb.c22
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c205
-rw-r--r--drivers/media/video/cx18/cx18-fileops.h3
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c135
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c45
-rw-r--r--drivers/media/video/cx18/cx18-queue.c3
-rw-r--r--drivers/media/video/cx18/cx18-streams.c72
-rw-r--r--drivers/media/video/cx18/cx18-streams.h10
-rw-r--r--drivers/media/video/cx18/cx18-version.h2
-rw-r--r--drivers/media/video/cx18/cx23418.h3
-rw-r--r--drivers/media/video/cx231xx/cx231xx-dvb.c8
-rw-r--r--drivers/media/video/cx231xx/cx231xx-input.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-417.c4
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c32
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c17
-rw-r--r--drivers/media/video/cx23885/cx23885-input.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-video.c13
-rw-r--r--drivers/media/video/cx23885/cx23885.h1
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c54
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c10
-rw-r--r--drivers/media/video/cx88/cx88-cards.c23
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c214
-rw-r--r--drivers/media/video/cx88/cx88-input.c4
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c3
-rw-r--r--drivers/media/video/cx88/cx88.h1
-rw-r--r--drivers/media/video/dabusb.c10
-rw-r--r--drivers/media/video/davinci/Makefile1
-rw-r--r--drivers/media/video/davinci/dm355_ccdc.c410
-rw-r--r--drivers/media/video/davinci/dm644x_ccdc.c361
-rw-r--r--drivers/media/video/davinci/isif.c1172
-rw-r--r--drivers/media/video/davinci/isif_regs.h269
-rw-r--r--drivers/media/video/davinci/vpfe_capture.c131
-rw-r--r--drivers/media/video/davinci/vpss.c289
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c80
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c19
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c3
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c113
-rw-r--r--drivers/media/video/em28xx/em28xx-reg.h4
-rw-r--r--drivers/media/video/em28xx/em28xx-vbi.c17
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c58
-rw-r--r--drivers/media/video/em28xx/em28xx.h6
-rw-r--r--drivers/media/video/et61x251/Kconfig6
-rw-r--r--drivers/media/video/gspca/Kconfig46
-rw-r--r--drivers/media/video/gspca/Makefile8
-rw-r--r--drivers/media/video/gspca/benq.c322
-rw-r--r--drivers/media/video/gspca/coarse_expo_autogain.h116
-rw-r--r--drivers/media/video/gspca/conex.c4
-rw-r--r--drivers/media/video/gspca/cpia1.c2022
-rw-r--r--drivers/media/video/gspca/etoms.c4
-rw-r--r--drivers/media/video/gspca/gl860/gl860.c10
-rw-r--r--drivers/media/video/gspca/gspca.c261
-rw-r--r--drivers/media/video/gspca/gspca.h30
-rw-r--r--drivers/media/video/gspca/m5602/m5602_mt9m111.c4
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov7660.c2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov7660.h2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov9650.c2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_po1030.c2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.c8
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.c2
-rw-r--r--drivers/media/video/gspca/mars.c2
-rw-r--r--drivers/media/video/gspca/mr97310a.c226
-rw-r--r--drivers/media/video/gspca/ov519.c153
-rw-r--r--drivers/media/video/gspca/ov534.c1253
-rw-r--r--drivers/media/video/gspca/ov534_9.c1477
-rw-r--r--drivers/media/video/gspca/pac207.c25
-rw-r--r--drivers/media/video/gspca/pac7302.c411
-rw-r--r--drivers/media/video/gspca/pac7311.c251
-rw-r--r--drivers/media/video/gspca/pac_common.h9
-rw-r--r--drivers/media/video/gspca/sn9c2028.c757
-rw-r--r--drivers/media/video/gspca/sn9c2028.h51
-rw-r--r--drivers/media/video/gspca/sn9c20x.c33
-rw-r--r--drivers/media/video/gspca/sonixb.c451
-rw-r--r--drivers/media/video/gspca/sonixj.c341
-rw-r--r--drivers/media/video/gspca/spca500.c4
-rw-r--r--drivers/media/video/gspca/spca501.c2
-rw-r--r--drivers/media/video/gspca/spca505.c2
-rw-r--r--drivers/media/video/gspca/spca506.c4
-rw-r--r--drivers/media/video/gspca/spca508.c2
-rw-r--r--drivers/media/video/gspca/spca561.c4
-rw-r--r--drivers/media/video/gspca/sq905c.c45
-rw-r--r--drivers/media/video/gspca/stk014.c2
-rw-r--r--drivers/media/video/gspca/stv0680.c16
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c32
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h1
-rw-r--r--drivers/media/video/gspca/sunplus.c212
-rw-r--r--drivers/media/video/gspca/t613.c51
-rw-r--r--drivers/media/video/gspca/tv8532.c2
-rw-r--r--drivers/media/video/gspca/vc032x.c698
-rw-r--r--drivers/media/video/gspca/zc3xx.c679
-rw-r--r--drivers/media/video/hdpvr/hdpvr-core.c5
-rw-r--r--drivers/media/video/hdpvr/hdpvr-video.c5
-rw-r--r--drivers/media/video/hdpvr/hdpvr.h1
-rw-r--r--drivers/media/video/hexium_gemini.c9
-rw-r--r--drivers/media/video/hexium_orion.c4
-rw-r--r--drivers/media/video/ir-kbd-i2c.c5
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c48
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.h4
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c1
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c14
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.c9
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.h3
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c6
-rw-r--r--drivers/media/video/ivtv/ivtv-udma.c1
-rw-r--r--drivers/media/video/mt9t112.c2
-rw-r--r--drivers/media/video/mt9v022.c17
-rw-r--r--drivers/media/video/mx1_camera.c2
-rw-r--r--drivers/media/video/mxb.c10
-rw-r--r--drivers/media/video/omap24xxcam.c2
-rw-r--r--drivers/media/video/ov772x.c22
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h12
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c53
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h1
-rw-r--r--drivers/media/video/pwc/philips.txt2
-rw-r--r--drivers/media/video/pwc/pwc-ctrl.c2
-rw-r--r--drivers/media/video/pxa_camera.c10
-rw-r--r--drivers/media/video/rj54n1cb0c.c14
-rw-r--r--drivers/media/video/saa7115.c27
-rw-r--r--drivers/media/video/saa7127.c47
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c52
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c13
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c8
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c7
-rw-r--r--drivers/media/video/saa7134/saa7134-ts.c13
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c2
-rw-r--r--drivers/media/video/saa7134/saa7134.h3
-rw-r--r--drivers/media/video/saa7164/saa7164-api.c2
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c20
-rw-r--r--drivers/media/video/sn9c102/Kconfig5
-rw-r--r--drivers/media/video/sn9c102/sn9c102_devtable.h6
-rw-r--r--drivers/media/video/sn9c102/sn9c102_sensor.h2
-rw-r--r--drivers/media/video/soc_camera.c36
-rw-r--r--drivers/media/video/soc_mediabus.c48
-rw-r--r--drivers/media/video/tea6420.c2
-rw-r--r--drivers/media/video/tlg2300/Kconfig16
-rw-r--r--drivers/media/video/tlg2300/Makefile9
-rw-r--r--drivers/media/video/tlg2300/pd-alsa.c332
-rw-r--r--drivers/media/video/tlg2300/pd-common.h282
-rw-r--r--drivers/media/video/tlg2300/pd-dvb.c593
-rw-r--r--drivers/media/video/tlg2300/pd-main.c539
-rw-r--r--drivers/media/video/tlg2300/pd-radio.c420
-rw-r--r--drivers/media/video/tlg2300/pd-video.c1667
-rw-r--r--drivers/media/video/tlg2300/vendorcmds.h243
-rw-r--r--drivers/media/video/tuner-core.c1
-rw-r--r--drivers/media/video/tveeprom.c5
-rw-r--r--drivers/media/video/tvp7002.c1187
-rw-r--r--drivers/media/video/tvp7002_reg.h150
-rw-r--r--drivers/media/video/tw9910.c8
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c2
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c244
-rw-r--r--drivers/media/video/uvc/uvc_driver.c74
-rw-r--r--drivers/media/video/uvc/uvc_queue.c14
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c4
-rw-r--r--drivers/media/video/uvc/uvc_video.c55
-rw-r--r--drivers/media/video/uvc/uvcvideo.h24
-rw-r--r--drivers/media/video/v4l2-compat-ioctl32.c5
-rw-r--r--drivers/media/video/videobuf-dma-sg.c2
-rw-r--r--drivers/media/video/videobuf-vmalloc.c2
-rw-r--r--drivers/media/video/vivi.c2
-rw-r--r--drivers/media/video/zc0301/Kconfig6
-rw-r--r--drivers/media/video/zoran/zoran_device.c6
-rw-r--r--drivers/media/video/zoran/zoran_driver.c4
-rw-r--r--drivers/media/video/zr364xx.c37
-rw-r--r--drivers/memstick/core/mspro_block.c5
-rw-r--r--drivers/message/fusion/mptbase.c7
-rw-r--r--drivers/message/fusion/mptbase.h4
-rw-r--r--drivers/message/fusion/mptctl.c4
-rw-r--r--drivers/message/fusion/mptfc.c17
-rw-r--r--drivers/message/fusion/mptsas.c211
-rw-r--r--drivers/message/fusion/mptscsih.c11
-rw-r--r--drivers/message/i2o/i2o_block.c5
-rw-r--r--drivers/message/i2o/i2o_proc.c11
-rw-r--r--drivers/message/i2o/iop.c2
-rw-r--r--drivers/mfd/88pm8607.c302
-rw-r--r--drivers/mfd/88pm860x-core.c740
-rw-r--r--drivers/mfd/88pm860x-i2c.c236
-rw-r--r--drivers/mfd/Kconfig87
-rw-r--r--drivers/mfd/Makefile19
-rw-r--r--drivers/mfd/ab3100-core.c54
-rw-r--r--drivers/mfd/ab3100-otp.c13
-rw-r--r--drivers/mfd/asic3.c40
-rw-r--r--drivers/mfd/htc-egpio.c2
-rw-r--r--drivers/mfd/htc-i2cpld.c710
-rw-r--r--drivers/mfd/lpc_sch.c133
-rw-r--r--drivers/mfd/max8925-core.c656
-rw-r--r--drivers/mfd/max8925-i2c.c211
-rw-r--r--drivers/mfd/mc13783-core.c77
-rw-r--r--drivers/mfd/mfd-core.c5
-rw-r--r--drivers/mfd/sh_mobile_sdhi.c6
-rw-r--r--drivers/mfd/sm501.c11
-rw-r--r--drivers/mfd/t7l66xb.c59
-rw-r--r--drivers/mfd/tc6387xb.c119
-rw-r--r--drivers/mfd/tc6393xb.c58
-rw-r--r--drivers/mfd/timberdale.c727
-rw-r--r--drivers/mfd/timberdale.h130
-rw-r--r--drivers/mfd/tmio_core.c52
-rw-r--r--drivers/mfd/twl-core.c59
-rw-r--r--drivers/mfd/twl4030-power.c52
-rw-r--r--drivers/mfd/ucb1x00-core.c1
-rw-r--r--drivers/mfd/wm831x-core.c51
-rw-r--r--drivers/mfd/wm8350-core.c38
-rw-r--r--drivers/mfd/wm8350-irq.c155
-rw-r--r--drivers/mfd/wm8994-core.c537
-rw-r--r--drivers/misc/Kconfig19
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/eeprom/at24.c1
-rw-r--r--drivers/misc/iwmc3200top/fw-download.c50
-rw-r--r--drivers/misc/iwmc3200top/iwmc3200top.h4
-rw-r--r--drivers/misc/iwmc3200top/log.h31
-rw-r--r--drivers/misc/iwmc3200top/main.c61
-rw-r--r--drivers/misc/lkdtm.c472
-rw-r--r--drivers/misc/phantom.c13
-rw-r--r--drivers/misc/sgi-gru/grutables.h15
-rw-r--r--drivers/misc/sgi-xp/xpnet.c2
-rw-r--r--drivers/misc/tsl2550.c (renamed from drivers/i2c/chips/tsl2550.c)4
-rw-r--r--drivers/mmc/card/mmc_test.c9
-rw-r--r--drivers/mmc/card/queue.c10
-rw-r--r--drivers/mmc/card/sdio_uart.c95
-rw-r--r--drivers/mmc/core/core.c13
-rw-r--r--drivers/mmc/core/sdio.c64
-rw-r--r--drivers/mmc/core/sdio_io.c56
-rw-r--r--drivers/mmc/core/sdio_ops.c36
-rw-r--r--drivers/mmc/core/sdio_ops.h1
-rw-r--r--drivers/mmc/host/Kconfig15
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/at91_mci.c224
-rw-r--r--drivers/mmc/host/au1xmmc.c12
-rw-r--r--drivers/mmc/host/bfin_sdh.c10
-rw-r--r--drivers/mmc/host/davinci_mmc.c45
-rw-r--r--drivers/mmc/host/mmci.c41
-rw-r--r--drivers/mmc/host/msm_sdcc.c4
-rw-r--r--drivers/mmc/host/mxcmmc.c4
-rw-r--r--drivers/mmc/host/omap_hsmmc.c400
-rw-r--r--drivers/mmc/host/ricoh_mmc.c262
-rw-r--r--drivers/mmc/host/s3cmci.c4
-rw-r--r--drivers/mmc/host/sdhci-pci.c24
-rw-r--r--drivers/mmc/host/sdhci.c76
-rw-r--r--drivers/mmc/host/tmio_mmc.c68
-rw-r--r--drivers/mmc/host/tmio_mmc.h52
-rw-r--r--[-rwxr-xr-x]drivers/mtd/chips/cfi_util.c0
-rw-r--r--drivers/mtd/chips/jedec_probe.c2
-rw-r--r--[-rwxr-xr-x]drivers/mtd/inftlcore.c0
-rw-r--r--drivers/mtd/maps/Kconfig32
-rw-r--r--drivers/mtd/maps/Makefile2
-rw-r--r--drivers/mtd/maps/alchemy-flash.c166
-rw-r--r--drivers/mtd/maps/omap_nor.c188
-rw-r--r--drivers/mtd/maps/pismo.c320
-rw-r--r--drivers/mtd/maps/plat-ram.c2
-rw-r--r--drivers/mtd/mtdoops.c2
-rw-r--r--drivers/mtd/nand/Kconfig6
-rw-r--r--drivers/mtd/nand/au1550nd.c4
-rw-r--r--drivers/mtd/nand/bcm_umi_nand.c4
-rw-r--r--drivers/mtd/nand/mxc_nand.c2
-rw-r--r--drivers/mtd/nand/omap2.c35
-rw-r--r--drivers/mtd/nand/sh_flctl.c69
-rw-r--r--drivers/mtd/tests/mtd_readtest.c6
-rw-r--r--drivers/mtd/tests/mtd_speedtest.c7
-rw-r--r--drivers/mtd/tests/mtd_stresstest.c6
-rw-r--r--drivers/mtd/ubi/build.c136
-rw-r--r--drivers/mtd/ubi/cdev.c1
-rw-r--r--drivers/mtd/ubi/debug.h4
-rw-r--r--drivers/mtd/ubi/io.c120
-rw-r--r--drivers/mtd/ubi/kapi.c15
-rw-r--r--drivers/mtd/ubi/scan.c11
-rw-r--r--drivers/mtd/ubi/upd.c1
-rw-r--r--drivers/mtd/ubi/vtbl.c1
-rw-r--r--drivers/mtd/ubi/wl.c17
-rw-r--r--drivers/net/3c501.c2
-rw-r--r--drivers/net/3c505.c13
-rw-r--r--drivers/net/3c509.c10
-rw-r--r--drivers/net/3c515.c2
-rw-r--r--drivers/net/3c523.c13
-rw-r--r--drivers/net/3c527.c17
-rw-r--r--drivers/net/3c59x.c4
-rw-r--r--drivers/net/7990.c6
-rw-r--r--drivers/net/8139cp.c81
-rw-r--r--drivers/net/8139too.c196
-rw-r--r--drivers/net/82596.c15
-rw-r--r--drivers/net/Kconfig86
-rw-r--r--drivers/net/Makefile5
-rw-r--r--drivers/net/a2065.c6
-rw-r--r--drivers/net/acenic.c4
-rw-r--r--drivers/net/amd8111e.c21
-rw-r--r--drivers/net/amd8111e.h1
-rw-r--r--drivers/net/appletalk/ltpc.c1
-rw-r--r--drivers/net/arcnet/com20020-pci.c2
-rw-r--r--drivers/net/ariadne.c4
-rw-r--r--drivers/net/arm/am79c961a.c12
-rw-r--r--drivers/net/arm/at91_ether.c9
-rw-r--r--drivers/net/arm/ep93xx_eth.c140
-rw-r--r--drivers/net/arm/ether3.c2
-rw-r--r--drivers/net/arm/ixp4xx_eth.c13
-rw-r--r--drivers/net/arm/ks8695net.c25
-rw-r--r--drivers/net/arm/w90p910_ether.c8
-rw-r--r--drivers/net/at1700.c8
-rw-r--r--drivers/net/atarilance.c2
-rw-r--r--drivers/net/atl1c/atl1c.h11
-rw-r--r--drivers/net/atl1c/atl1c_ethtool.c2
-rw-r--r--drivers/net/atl1c/atl1c_hw.c83
-rw-r--r--drivers/net/atl1c/atl1c_hw.h5
-rw-r--r--drivers/net/atl1c/atl1c_main.c126
-rw-r--r--drivers/net/atl1e/atl1e_hw.c23
-rw-r--r--drivers/net/atl1e/atl1e_main.c160
-rw-r--r--drivers/net/atl1e/atl1e_param.c35
-rw-r--r--drivers/net/atlx/atl1.c2
-rw-r--r--drivers/net/atlx/atl2.c4
-rw-r--r--drivers/net/atlx/atl2.h2
-rw-r--r--drivers/net/atlx/atlx.c2
-rw-r--r--drivers/net/atp.c9
-rw-r--r--drivers/net/au1000_eth.c448
-rw-r--r--drivers/net/au1000_eth.h9
-rw-r--r--drivers/net/ax88796.c2
-rw-r--r--drivers/net/b44.c94
-rw-r--r--drivers/net/bcm63xx_enet.c15
-rw-r--r--drivers/net/benet/Kconfig4
-rw-r--r--drivers/net/benet/be.h29
-rw-r--r--drivers/net/benet/be_cmds.c127
-rw-r--r--drivers/net/benet/be_cmds.h32
-rw-r--r--drivers/net/benet/be_ethtool.c65
-rw-r--r--drivers/net/benet/be_hw.h122
-rw-r--r--drivers/net/benet/be_main.c594
-rw-r--r--drivers/net/bfin_mac.c13
-rw-r--r--drivers/net/bmac.c13
-rw-r--r--drivers/net/bnx2.c410
-rw-r--r--drivers/net/bnx2.h3
-rw-r--r--drivers/net/bnx2x.h53
-rw-r--r--drivers/net/bnx2x_fw_defs.h7
-rw-r--r--drivers/net/bnx2x_hsi.h10
-rw-r--r--drivers/net/bnx2x_init_ops.h13
-rw-r--r--drivers/net/bnx2x_link.c21
-rw-r--r--drivers/net/bnx2x_main.c284
-rw-r--r--drivers/net/bonding/bond_main.c29
-rw-r--r--drivers/net/bonding/bond_sysfs.c5
-rw-r--r--drivers/net/bonding/bonding.h1
-rw-r--r--drivers/net/can/at91_can.c4
-rw-r--r--drivers/net/can/bfin_can.c7
-rw-r--r--drivers/net/can/dev.c8
-rw-r--r--drivers/net/can/mcp251x.c426
-rw-r--r--drivers/net/can/mscan/Kconfig7
-rw-r--r--drivers/net/can/mscan/mpc5xxx_can.c248
-rw-r--r--drivers/net/can/mscan/mscan.c58
-rw-r--r--drivers/net/can/mscan/mscan.h86
-rw-r--r--drivers/net/can/sja1000/Kconfig12
-rw-r--r--drivers/net/can/sja1000/Makefile1
-rw-r--r--drivers/net/can/sja1000/ems_pci.c2
-rw-r--r--drivers/net/can/sja1000/kvaser_pci.c2
-rw-r--r--drivers/net/can/sja1000/plx_pci.c472
-rw-r--r--drivers/net/can/sja1000/sja1000.c27
-rw-r--r--drivers/net/can/ti_hecc.c73
-rw-r--r--drivers/net/can/usb/Kconfig2
-rw-r--r--drivers/net/can/usb/ems_usb.c10
-rw-r--r--drivers/net/can/vcan.c12
-rw-r--r--drivers/net/cassini.c439
-rw-r--r--drivers/net/chelsio/common.h44
-rw-r--r--drivers/net/chelsio/cxgb2.c20
-rw-r--r--drivers/net/chelsio/espi.c4
-rw-r--r--drivers/net/chelsio/pm3393.c22
-rw-r--r--drivers/net/chelsio/sge.c14
-rw-r--r--drivers/net/chelsio/subr.c34
-rw-r--r--drivers/net/chelsio/vsc7326.c24
-rw-r--r--drivers/net/cnic.c206
-rw-r--r--drivers/net/cnic.h13
-rw-r--r--drivers/net/cnic_defs.h2
-rw-r--r--drivers/net/cnic_if.h6
-rw-r--r--drivers/net/cpmac.c28
-rw-r--r--drivers/net/cris/eth_v10.c8
-rw-r--r--drivers/net/cs89x0.c4
-rw-r--r--drivers/net/cxgb3/adapter.h5
-rw-r--r--drivers/net/cxgb3/common.h28
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c68
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.c2
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.h5
-rw-r--r--drivers/net/cxgb3/regs.h16
-rw-r--r--drivers/net/cxgb3/sge.c50
-rw-r--r--drivers/net/cxgb3/t3_hw.c8
-rw-r--r--drivers/net/cxgb3/xgmac.c18
-rw-r--r--drivers/net/davinci_emac.c71
-rw-r--r--drivers/net/de620.c2
-rw-r--r--drivers/net/declance.c6
-rw-r--r--drivers/net/defxx.c24
-rw-r--r--drivers/net/depca.c5
-rw-r--r--drivers/net/dl2k.c9
-rw-r--r--drivers/net/dl2k.h2
-rw-r--r--drivers/net/dm9000.c5
-rw-r--r--drivers/net/e100.c18
-rw-r--r--drivers/net/e1000/e1000.h3
-rw-r--r--drivers/net/e1000/e1000_ethtool.c19
-rw-r--r--drivers/net/e1000/e1000_main.c108
-rw-r--r--drivers/net/e1000e/82571.c70
-rw-r--r--drivers/net/e1000e/defines.h4
-rw-r--r--drivers/net/e1000e/e1000.h20
-rw-r--r--drivers/net/e1000e/es2lan.c32
-rw-r--r--drivers/net/e1000e/ethtool.c2
-rw-r--r--drivers/net/e1000e/hw.h12
-rw-r--r--drivers/net/e1000e/ich8lan.c11
-rw-r--r--drivers/net/e1000e/lib.c232
-rw-r--r--drivers/net/e1000e/netdev.c102
-rw-r--r--drivers/net/eepro.c21
-rw-r--r--drivers/net/eexpress.c22
-rw-r--r--drivers/net/ehea/ehea_main.c9
-rw-r--r--drivers/net/enc28j60.c2
-rw-r--r--drivers/net/enic/enic.h5
-rw-r--r--drivers/net/enic/enic_main.c208
-rw-r--r--drivers/net/enic/enic_res.c16
-rw-r--r--drivers/net/enic/vnic_dev.c1
-rw-r--r--drivers/net/enic/vnic_enet.h5
-rw-r--r--drivers/net/enic/vnic_intr.c8
-rw-r--r--drivers/net/enic/vnic_intr.h3
-rw-r--r--drivers/net/enic/vnic_nic.h12
-rw-r--r--drivers/net/epic100.c9
-rw-r--r--drivers/net/eth16i.c2
-rw-r--r--drivers/net/ethoc.c14
-rw-r--r--drivers/net/ewrk3.c5
-rw-r--r--drivers/net/fealnx.c8
-rw-r--r--drivers/net/fec.c84
-rw-r--r--drivers/net/fec_mpc52xx.c5
-rw-r--r--drivers/net/forcedeth.c8
-rw-r--r--drivers/net/fs_enet/Kconfig10
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c93
-rw-r--r--drivers/net/fs_enet/fs_enet.h49
-rw-r--r--drivers/net/fs_enet/mac-fcc.c9
-rw-r--r--drivers/net/fs_enet/mac-fec.c62
-rw-r--r--drivers/net/fs_enet/mac-scc.c13
-rw-r--r--drivers/net/fs_enet/mii-fec.c4
-rw-r--r--drivers/net/gianfar.c21
-rw-r--r--drivers/net/greth.c1634
-rw-r--r--drivers/net/greth.h143
-rw-r--r--drivers/net/hamachi.c13
-rw-r--r--drivers/net/hp100.c13
-rw-r--r--drivers/net/ibm_newemac/core.c8
-rw-r--r--drivers/net/ibmlana.c2
-rw-r--r--drivers/net/ibmveth.c10
-rw-r--r--drivers/net/igb/e1000_82575.c65
-rw-r--r--drivers/net/igb/e1000_82575.h5
-rw-r--r--drivers/net/igb/e1000_defines.h7
-rw-r--r--drivers/net/igb/e1000_hw.h7
-rw-r--r--drivers/net/igb/e1000_mac.c70
-rw-r--r--drivers/net/igb/e1000_mac.h2
-rw-r--r--drivers/net/igb/e1000_phy.c35
-rw-r--r--drivers/net/igb/e1000_phy.h2
-rw-r--r--drivers/net/igb/e1000_regs.h1
-rw-r--r--drivers/net/igb/igb.h16
-rw-r--r--drivers/net/igb/igb_ethtool.c93
-rw-r--r--drivers/net/igb/igb_main.c440
-rw-r--r--drivers/net/igbvf/netdev.c46
-rw-r--r--drivers/net/ioc3-eth.c11
-rw-r--r--drivers/net/ipg.c13
-rw-r--r--drivers/net/irda/Kconfig10
-rw-r--r--drivers/net/irda/Makefile1
-rw-r--r--drivers/net/irda/au1k_ir.c14
-rw-r--r--drivers/net/irda/donauboe.c2
-rw-r--r--drivers/net/irda/irda-usb.c4
-rw-r--r--drivers/net/irda/sa1100_ir.c2
-rw-r--r--drivers/net/irda/sh_sir.c823
-rw-r--r--drivers/net/irda/via-ircc.c2
-rw-r--r--drivers/net/irda/vlsi_ir.c2
-rw-r--r--drivers/net/isa-skeleton.c718
-rw-r--r--drivers/net/iseries_veth.c12
-rw-r--r--drivers/net/ixgb/ixgb.h11
-rw-r--r--drivers/net/ixgb/ixgb_main.c114
-rw-r--r--drivers/net/ixgbe/Makefile3
-rw-r--r--drivers/net/ixgbe/ixgbe.h54
-rw-r--r--drivers/net/ixgbe/ixgbe_82598.c22
-rw-r--r--drivers/net/ixgbe/ixgbe_82599.c233
-rw-r--r--drivers/net/ixgbe/ixgbe_common.c19
-rw-r--r--drivers/net/ixgbe/ixgbe_common.h2
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_nl.c16
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c195
-rw-r--r--drivers/net/ixgbe/ixgbe_fcoe.c4
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c701
-rw-r--r--drivers/net/ixgbe/ixgbe_mbx.c479
-rw-r--r--drivers/net/ixgbe/ixgbe_mbx.h96
-rw-r--r--drivers/net/ixgbe/ixgbe_sriov.c362
-rw-r--r--drivers/net/ixgbe/ixgbe_sriov.h47
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h66
-rw-r--r--drivers/net/ixgbevf/Makefile38
-rw-r--r--drivers/net/ixgbevf/defines.h292
-rw-r--r--drivers/net/ixgbevf/ethtool.c716
-rw-r--r--drivers/net/ixgbevf/ixgbevf.h318
-rw-r--r--drivers/net/ixgbevf/ixgbevf_main.c3578
-rw-r--r--drivers/net/ixgbevf/mbx.c341
-rw-r--r--drivers/net/ixgbevf/mbx.h100
-rw-r--r--drivers/net/ixgbevf/regs.h85
-rw-r--r--drivers/net/ixgbevf/vf.c387
-rw-r--r--drivers/net/ixgbevf/vf.h168
-rw-r--r--drivers/net/jme.c62
-rw-r--r--drivers/net/jme.h41
-rw-r--r--drivers/net/korina.c10
-rw-r--r--drivers/net/ks8851.c9
-rw-r--r--drivers/net/ks8851_mll.c11
-rw-r--r--drivers/net/ksz884x.c7335
-rw-r--r--drivers/net/lance.c2
-rw-r--r--drivers/net/lib82596.c21
-rw-r--r--drivers/net/lib8390.c15
-rw-r--r--drivers/net/ll_temac_main.c25
-rw-r--r--drivers/net/loopback.c16
-rw-r--r--drivers/net/lp486e.c16
-rw-r--r--drivers/net/mac8390.c632
-rw-r--r--drivers/net/mac89x0.c4
-rw-r--r--drivers/net/macb.c38
-rw-r--r--drivers/net/mace.c13
-rw-r--r--drivers/net/macmace.c45
-rw-r--r--drivers/net/macsonic.c33
-rw-r--r--drivers/net/macvlan.c117
-rw-r--r--drivers/net/macvtap.c803
-rw-r--r--drivers/net/meth.c3
-rw-r--r--drivers/net/mlx4/en_rx.c8
-rw-r--r--drivers/net/mlx4/main.c2
-rw-r--r--drivers/net/mv643xx_eth.c6
-rw-r--r--drivers/net/myri10ge/myri10ge.c198
-rw-r--r--drivers/net/myri_sbus.c6
-rw-r--r--drivers/net/natsemi.c8
-rw-r--r--drivers/net/ne2k-pci.c2
-rw-r--r--drivers/net/netxen/Makefile2
-rw-r--r--drivers/net/netxen/netxen_nic.h8
-rw-r--r--drivers/net/netxen/netxen_nic_ctx.c2
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c2
-rw-r--r--drivers/net/netxen/netxen_nic_hdr.h5
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c46
-rw-r--r--drivers/net/netxen/netxen_nic_hw.h2
-rw-r--r--drivers/net/netxen/netxen_nic_init.c5
-rw-r--r--drivers/net/netxen/netxen_nic_main.c217
-rw-r--r--drivers/net/ni5010.c3
-rw-r--r--drivers/net/ni52.c10
-rw-r--r--drivers/net/ni65.c2
-rw-r--r--drivers/net/niu.c699
-rw-r--r--drivers/net/ns83820.c4
-rw-r--r--drivers/net/octeon/octeon_mgmt.c18
-rw-r--r--drivers/net/pasemi_mac.c2
-rw-r--r--drivers/net/pci-skeleton.c1029
-rw-r--r--drivers/net/pcmcia/3c574_cs.c2
-rw-r--r--drivers/net/pcmcia/3c589_cs.c2
-rw-r--r--drivers/net/pcmcia/axnet_cs.c11
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c11
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c18
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c41
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c88
-rw-r--r--drivers/net/pcnet32.c507
-rw-r--r--drivers/net/phy/broadcom.c5
-rw-r--r--drivers/net/phy/marvell.c38
-rw-r--r--drivers/net/phy/phy.c4
-rw-r--r--drivers/net/phy/phy_device.c17
-rw-r--r--drivers/net/phy/smsc.c21
-rw-r--r--drivers/net/ppp_generic.c122
-rw-r--r--drivers/net/ps3_gelic_net.c4
-rw-r--r--drivers/net/ps3_gelic_wireless.c149
-rw-r--r--drivers/net/qla3xxx.c3
-rw-r--r--drivers/net/qlcnic/Makefile8
-rw-r--r--drivers/net/qlcnic/qlcnic.h1131
-rw-r--r--drivers/net/qlcnic/qlcnic_ctx.c534
-rw-r--r--drivers/net/qlcnic/qlcnic_ethtool.c1032
-rw-r--r--drivers/net/qlcnic/qlcnic_hdr.h937
-rw-r--r--drivers/net/qlcnic/qlcnic_hw.c1256
-rw-r--r--drivers/net/qlcnic/qlcnic_init.c1677
-rw-r--r--drivers/net/qlcnic/qlcnic_main.c2725
-rw-r--r--drivers/net/qlge/qlge.h446
-rw-r--r--drivers/net/qlge/qlge_dbg.c1183
-rw-r--r--drivers/net/qlge/qlge_ethtool.c56
-rw-r--r--drivers/net/qlge/qlge_main.c1204
-rw-r--r--drivers/net/qlge/qlge_mpi.c340
-rw-r--r--drivers/net/r6040.c37
-rw-r--r--drivers/net/r8169.c170
-rw-r--r--drivers/net/rrunner.c2
-rw-r--r--drivers/net/s2io.c21
-rw-r--r--drivers/net/sb1250-mac.c6
-rw-r--r--drivers/net/sc92031.c6
-rw-r--r--drivers/net/sfc/efx.c9
-rw-r--r--drivers/net/sfc/efx.h2
-rw-r--r--drivers/net/sfc/ethtool.c10
-rw-r--r--drivers/net/sfc/falcon.c6
-rw-r--r--drivers/net/sfc/falcon_boards.c45
-rw-r--r--drivers/net/sfc/mcdi.c118
-rw-r--r--drivers/net/sfc/mcdi.h2
-rw-r--r--drivers/net/sfc/mcdi_pcol.h206
-rw-r--r--drivers/net/sfc/mcdi_phy.c36
-rw-r--r--drivers/net/sfc/mdio_10g.c24
-rw-r--r--drivers/net/sfc/mdio_10g.h3
-rw-r--r--drivers/net/sfc/mtd.c5
-rw-r--r--drivers/net/sfc/net_driver.h17
-rw-r--r--drivers/net/sfc/nic.c13
-rw-r--r--drivers/net/sfc/qt202x_phy.c9
-rw-r--r--drivers/net/sfc/regs.h2
-rw-r--r--drivers/net/sfc/selftest.c42
-rw-r--r--drivers/net/sfc/selftest.h4
-rw-r--r--drivers/net/sfc/siena.c16
-rw-r--r--drivers/net/sfc/tenxpress.c2
-rw-r--r--drivers/net/sgiseeq.c2
-rw-r--r--drivers/net/sh_eth.c10
-rw-r--r--drivers/net/sis190.c221
-rw-r--r--drivers/net/sis900.c9
-rw-r--r--drivers/net/skfp/ess.c2
-rw-r--r--drivers/net/skfp/skfddi.c35
-rw-r--r--drivers/net/skge.c218
-rw-r--r--drivers/net/sky2.c740
-rw-r--r--drivers/net/sky2.h10
-rw-r--r--drivers/net/smc911x.c14
-rw-r--r--drivers/net/smc911x.h4
-rw-r--r--drivers/net/smc9194.c12
-rw-r--r--drivers/net/smc91x.c11
-rw-r--r--drivers/net/smc91x.h42
-rw-r--r--drivers/net/smsc911x.c53
-rw-r--r--drivers/net/smsc9420.c11
-rw-r--r--drivers/net/sonic.c13
-rw-r--r--drivers/net/spider_net.c8
-rw-r--r--drivers/net/starfire.c18
-rw-r--r--drivers/net/stmmac/Kconfig8
-rw-r--r--drivers/net/stmmac/Makefile5
-rw-r--r--drivers/net/stmmac/common.h279
-rw-r--r--drivers/net/stmmac/descs.h4
-rw-r--r--drivers/net/stmmac/dwmac100.c (renamed from drivers/net/stmmac/mac100.c)212
-rw-r--r--drivers/net/stmmac/dwmac100.h (renamed from drivers/net/stmmac/mac100.h)0
-rw-r--r--drivers/net/stmmac/dwmac1000.h (renamed from drivers/net/stmmac/gmac.h)18
-rw-r--r--drivers/net/stmmac/dwmac1000_core.c243
-rw-r--r--drivers/net/stmmac/dwmac1000_dma.c (renamed from drivers/net/stmmac/gmac.c)351
-rw-r--r--drivers/net/stmmac/dwmac_dma.h107
-rw-r--r--drivers/net/stmmac/dwmac_lib.c263
-rw-r--r--drivers/net/stmmac/stmmac.h28
-rw-r--r--drivers/net/stmmac/stmmac_ethtool.c11
-rw-r--r--drivers/net/stmmac/stmmac_main.c436
-rw-r--r--drivers/net/stmmac/stmmac_mdio.c11
-rw-r--r--drivers/net/sun3_82586.c10
-rw-r--r--drivers/net/sun3lance.c2
-rw-r--r--drivers/net/sunbmac.c7
-rw-r--r--drivers/net/sundance.c9
-rw-r--r--drivers/net/sungem.c16
-rw-r--r--drivers/net/sunhme.c26
-rw-r--r--drivers/net/sunlance.c6
-rw-r--r--drivers/net/sunqe.c11
-rw-r--r--drivers/net/sunvnet.c7
-rw-r--r--drivers/net/tc35815.c28
-rw-r--r--drivers/net/tehuti.c161
-rw-r--r--drivers/net/tehuti.h30
-rw-r--r--drivers/net/tg3.c969
-rw-r--r--drivers/net/tg3.h162
-rw-r--r--drivers/net/tlan.c37
-rw-r--r--drivers/net/tlan.h3
-rw-r--r--drivers/net/tokenring/3c359.c7
-rw-r--r--drivers/net/tokenring/abyss.c2
-rw-r--r--drivers/net/tokenring/ibmtr.c4
-rw-r--r--drivers/net/tokenring/lanstreamer.c6
-rw-r--r--drivers/net/tokenring/olympic.c7
-rw-r--r--drivers/net/tokenring/tms380tr.c12
-rw-r--r--drivers/net/tokenring/tmspci.c2
-rw-r--r--drivers/net/tsi108_eth.c22
-rw-r--r--drivers/net/tulip/21142.c76
-rw-r--r--drivers/net/tulip/de2104x.c163
-rw-r--r--drivers/net/tulip/de4x5.c16
-rw-r--r--drivers/net/tulip/dmfe.c103
-rw-r--r--drivers/net/tulip/eeprom.c53
-rw-r--r--drivers/net/tulip/interrupt.c100
-rw-r--r--drivers/net/tulip/media.c74
-rw-r--r--drivers/net/tulip/pnic.c33
-rw-r--r--drivers/net/tulip/pnic2.c59
-rw-r--r--drivers/net/tulip/timer.c52
-rw-r--r--drivers/net/tulip/tulip_core.c188
-rw-r--r--drivers/net/tulip/uli526x.c64
-rw-r--r--drivers/net/tulip/winbond-840.c186
-rw-r--r--drivers/net/tulip/xircom_cb.c46
-rw-r--r--drivers/net/tun.c129
-rw-r--r--drivers/net/typhoon.c265
-rw-r--r--drivers/net/ucc_geth.c36
-rw-r--r--drivers/net/usb/asix.c147
-rw-r--r--drivers/net/usb/catc.c9
-rw-r--r--drivers/net/usb/cdc_eem.c10
-rw-r--r--drivers/net/usb/cdc_ether.c29
-rw-r--r--drivers/net/usb/dm9601.c59
-rw-r--r--drivers/net/usb/int51x1.c17
-rw-r--r--drivers/net/usb/kaweth.c2
-rw-r--r--drivers/net/usb/mcs7830.c256
-rw-r--r--drivers/net/usb/net1080.c109
-rw-r--r--drivers/net/usb/pegasus.c172
-rw-r--r--drivers/net/usb/pegasus.h6
-rw-r--r--drivers/net/usb/rndis_host.c24
-rw-r--r--drivers/net/usb/rtl8150.c9
-rw-r--r--drivers/net/usb/smsc95xx.c245
-rw-r--r--drivers/net/usb/usbnet.c238
-rw-r--r--drivers/net/veth.c19
-rw-r--r--drivers/net/via-rhine.c9
-rw-r--r--drivers/net/via-velocity.c57
-rw-r--r--drivers/net/virtio_net.c477
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c19
-rw-r--r--drivers/net/vxge/vxge-main.c16
-rw-r--r--drivers/net/wan/cosa.c10
-rw-r--r--drivers/net/wan/dscc4.c2
-rw-r--r--drivers/net/wan/farsync.c2
-rw-r--r--drivers/net/wan/hdlc_cisco.c8
-rw-r--r--drivers/net/wan/hdlc_x25.c4
-rw-r--r--drivers/net/wan/lmc/lmc_main.c2
-rw-r--r--drivers/net/wan/pc300_drv.c2
-rw-r--r--drivers/net/wan/pc300too.c2
-rw-r--r--drivers/net/wan/pci200syn.c2
-rw-r--r--drivers/net/wan/wanxl.c2
-rw-r--r--drivers/net/wimax/i2400m/driver.c17
-rw-r--r--drivers/net/wimax/i2400m/fw.c13
-rw-r--r--drivers/net/wimax/i2400m/i2400m-usb.h2
-rw-r--r--drivers/net/wimax/i2400m/i2400m.h2
-rw-r--r--drivers/net/wimax/i2400m/sdio.c4
-rw-r--r--drivers/net/wimax/i2400m/usb.c16
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/adm8211.c27
-rw-r--r--drivers/net/wireless/airo.c38
-rw-r--r--drivers/net/wireless/at76c50x-usb.c6
-rw-r--r--drivers/net/wireless/ath/ar9170/ar9170.h18
-rw-r--r--drivers/net/wireless/ath/ar9170/hw.h1
-rw-r--r--drivers/net/wireless/ath/ar9170/mac.c2
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c207
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c172
-rw-r--r--drivers/net/wireless/ath/ath.h1
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h27
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c108
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h1
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c4
-rw-r--r--drivers/net/wireless/ath/ath5k/led.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c121
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c41
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c25
-rw-r--r--drivers/net/wireless/ath/ath5k/reg.h1
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c36
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile2
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c31
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h80
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c30
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c199
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h32
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c442
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c185
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h10
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c863
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h34
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c1453
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c75
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c33
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c40
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c70
-rw-r--r--drivers/net/wireless/ath/debug.h8
-rw-r--r--drivers/net/wireless/ath/regd.c5
-rw-r--r--drivers/net/wireless/atmel_pci.c2
-rw-r--r--drivers/net/wireless/b43/Kconfig6
-rw-r--r--drivers/net/wireless/b43/Makefile2
-rw-r--r--drivers/net/wireless/b43/b43.h21
-rw-r--r--drivers/net/wireless/b43/dma.c19
-rw-r--r--drivers/net/wireless/b43/dma.h5
-rw-r--r--drivers/net/wireless/b43/main.c111
-rw-r--r--drivers/net/wireless/b43/phy_common.c45
-rw-r--r--drivers/net/wireless/b43/phy_common.h10
-rw-r--r--drivers/net/wireless/b43/phy_lp.c76
-rw-r--r--drivers/net/wireless/b43/phy_n.c3035
-rw-r--r--drivers/net/wireless/b43/phy_n.h98
-rw-r--r--drivers/net/wireless/b43/pio.c17
-rw-r--r--drivers/net/wireless/b43/pio.h45
-rw-r--r--drivers/net/wireless/b43/tables_nphy.c744
-rw-r--r--drivers/net/wireless/b43/tables_nphy.h100
-rw-r--r--drivers/net/wireless/b43legacy/dma.c20
-rw-r--r--drivers/net/wireless/b43legacy/dma.h10
-rw-r--r--drivers/net/wireless/b43legacy/leds.h2
-rw-r--r--drivers/net/wireless/b43legacy/main.c61
-rw-r--r--drivers/net/wireless/b43legacy/pio.c13
-rw-r--r--drivers/net/wireless/b43legacy/pio.h11
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c17
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c9
-rw-r--r--drivers/net/wireless/hostap/hostap_pci.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_plx.c2
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c2
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c21
-rw-r--r--drivers/net/wireless/ipw2x00/libipw.h2
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_module.c37
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig14
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c84
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-fh.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c31
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h25
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000-hw.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c138
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000-hw.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c116
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-led.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-led.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c493
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h68
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c389
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h57
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h60
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c1461
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h99
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.c28
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.h70
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c141
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c209
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-spectrum.c198
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-spectrum.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c154
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c99
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c197
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h1
-rw-r--r--drivers/net/wireless/iwmc3200wifi/debugfs.c2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/lmac.h2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c75
-rw-r--r--drivers/net/wireless/libertas/Kconfig6
-rw-r--r--drivers/net/wireless/libertas/Makefile2
-rw-r--r--drivers/net/wireless/libertas/assoc.c95
-rw-r--r--drivers/net/wireless/libertas/cmd.c22
-rw-r--r--drivers/net/wireless/libertas/cmd.h12
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c21
-rw-r--r--drivers/net/wireless/libertas/defs.h7
-rw-r--r--drivers/net/wireless/libertas/dev.h8
-rw-r--r--drivers/net/wireless/libertas/ethtool.c2
-rw-r--r--drivers/net/wireless/libertas/if_spi.c1
-rw-r--r--drivers/net/wireless/libertas/main.c81
-rw-r--r--drivers/net/wireless/libertas/mesh.c29
-rw-r--r--drivers/net/wireless/libertas/mesh.h32
-rw-r--r--drivers/net/wireless/libertas/scan.c2
-rw-r--r--drivers/net/wireless/libertas/tx.c2
-rw-r--r--drivers/net/wireless/libertas/wext.c26
-rw-r--r--drivers/net/wireless/libertas_tf/main.c13
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c198
-rw-r--r--drivers/net/wireless/mwl8k.c2084
-rw-r--r--drivers/net/wireless/orinoco/hw.c22
-rw-r--r--drivers/net/wireless/orinoco/hw.h2
-rw-r--r--drivers/net/wireless/orinoco/main.c7
-rw-r--r--drivers/net/wireless/orinoco/orinoco_cs.c9
-rw-r--r--drivers/net/wireless/orinoco/orinoco_nortel.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_plx.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_tmd.c2
-rw-r--r--drivers/net/wireless/p54/main.c51
-rw-r--r--drivers/net/wireless/p54/p54.h8
-rw-r--r--drivers/net/wireless/p54/p54pci.c84
-rw-r--r--drivers/net/wireless/p54/p54pci.h6
-rw-r--r--drivers/net/wireless/p54/p54usb.c2
-rw-r--r--drivers/net/wireless/p54/txrx.c4
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c2
-rw-r--r--drivers/net/wireless/ray_cs.c10
-rw-r--r--drivers/net/wireless/rndis_wlan.c428
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig71
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.h1
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c48
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.h1
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c43
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h14
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c203
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h3
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c104
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c377
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.h90
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h96
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c42
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c10
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c81
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h5
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00soc.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00soc.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c48
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h9
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c49
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180.h1
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_dev.c37
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187.h2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c27
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_leds.c6
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_leds.h2
-rw-r--r--drivers/net/wireless/wl12xx/Makefile4
-rw-r--r--drivers/net/wireless/wl12xx/wl1251.h4
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.c69
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.h87
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.c83
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.h22
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_debugfs.c23
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.c5
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.h47
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c375
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.c9
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.c2
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.c9
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.h17
-rw-r--r--drivers/net/wireless/wl12xx/wl1271.h67
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.c196
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.h50
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_boot.c102
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.c137
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.h67
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_conf.h174
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_debugfs.c62
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.c68
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.h2
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_init.c50
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_init.h4
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_io.c213
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_io.h68
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c823
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.c37
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.h3
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_reg.h99
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_rx.c11
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_spi.c158
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_spi.h30
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_testmode.c283
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_testmode.h31
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.c71
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.h36
-rw-r--r--drivers/net/wireless/zd1201.c14
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c22
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c15
-rw-r--r--drivers/net/xilinx_emaclite.c384
-rw-r--r--drivers/net/yellowfin.c173
-rw-r--r--drivers/net/znet.c3
-rw-r--r--drivers/of/Kconfig8
-rw-r--r--drivers/of/Makefile1
-rw-r--r--drivers/of/base.c318
-rw-r--r--drivers/of/fdt.c590
-rw-r--r--drivers/of/gpio.c13
-rw-r--r--drivers/of/of_i2c.c4
-rw-r--r--drivers/of/of_mdio.c8
-rw-r--r--drivers/of/of_spi.c6
-rw-r--r--drivers/parisc/eisa_enumerator.c2
-rw-r--r--drivers/parisc/pdc_stable.c2
-rw-r--r--drivers/parisc/superio.c2
-rw-r--r--drivers/parport/ChangeLog583
-rw-r--r--drivers/parport/parport_pc.c6
-rw-r--r--drivers/pci/Kconfig11
-rw-r--r--drivers/pci/Makefile7
-rw-r--r--drivers/pci/bus.c60
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c2
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c25
-rw-r--r--drivers/pci/hotplug/cpcihp_generic.c1
-rw-r--r--drivers/pci/hotplug/cpqphp.h2
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c57
-rw-r--r--drivers/pci/hotplug/cpqphp_ctrl.c27
-rw-r--r--drivers/pci/hotplug/fakephp.c2
-rw-r--r--drivers/pci/hotplug/ibmphp_core.c106
-rw-r--r--drivers/pci/hotplug/ibmphp_ebda.c13
-rw-r--r--drivers/pci/hotplug/ibmphp_hpc.c1
-rw-r--r--drivers/pci/hotplug/ibmphp_res.c14
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c132
-rw-r--r--drivers/pci/hotplug/pciehp_core.c25
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c1
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c72
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c23
-rw-r--r--drivers/pci/hotplug/rpaphp_core.c24
-rw-r--r--drivers/pci/hotplug/shpchp.h2
-rw-r--r--drivers/pci/hotplug/shpchp_core.c35
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c14
-rw-r--r--drivers/pci/hotplug/shpchp_hpc.c149
-rw-r--r--drivers/pci/hotplug/shpchp_sysfs.c9
-rw-r--r--drivers/pci/iov.c15
-rw-r--r--drivers/pci/legacy.c34
-rw-r--r--drivers/pci/pci-acpi.c213
-rw-r--r--drivers/pci/pci-driver.c160
-rw-r--r--drivers/pci/pci-sysfs.c5
-rw-r--r--drivers/pci/pci.c263
-rw-r--r--drivers/pci/pci.h16
-rw-r--r--drivers/pci/pcie/Kconfig4
-rw-r--r--drivers/pci/pcie/Makefile2
-rw-r--r--drivers/pci/pcie/aer/aer_inject.c12
-rw-r--r--drivers/pci/pcie/pme/Makefile8
-rw-r--r--drivers/pci/pcie/pme/pcie_pme.c505
-rw-r--r--drivers/pci/pcie/pme/pcie_pme.h28
-rw-r--r--drivers/pci/pcie/pme/pcie_pme_acpi.c54
-rw-r--r--drivers/pci/pcie/portdrv.h17
-rw-r--r--drivers/pci/pcie/portdrv_core.c13
-rw-r--r--drivers/pci/pcie/portdrv_pci.c27
-rw-r--r--drivers/pci/probe.c297
-rw-r--r--drivers/pci/quirks.c117
-rw-r--r--drivers/pci/setup-bus.c514
-rw-r--r--drivers/pci/slot.c57
-rw-r--r--drivers/pci/vpd.c61
-rw-r--r--drivers/pcmcia/Kconfig44
-rw-r--r--drivers/pcmcia/Makefile16
-rw-r--r--drivers/pcmcia/at91_cf.c2
-rw-r--r--drivers/pcmcia/au1000_db1x00.c305
-rw-r--r--drivers/pcmcia/au1000_generic.c10
-rw-r--r--drivers/pcmcia/au1000_generic.h18
-rw-r--r--drivers/pcmcia/au1000_pb1x00.c119
-rw-r--r--drivers/pcmcia/au1000_xxs1500.c188
-rw-r--r--drivers/pcmcia/bfin_cf_pcmcia.c2
-rw-r--r--drivers/pcmcia/cardbus.c177
-rw-r--r--drivers/pcmcia/cistpl.c2388
-rw-r--r--drivers/pcmcia/cs.c312
-rw-r--r--drivers/pcmcia/cs_internal.h89
-rw-r--r--drivers/pcmcia/db1xxx_ss.c612
-rw-r--r--drivers/pcmcia/ds.c341
-rw-r--r--drivers/pcmcia/electra_cf.c2
-rw-r--r--drivers/pcmcia/i82365.h4
-rw-r--r--drivers/pcmcia/m32r_cfc.c2
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c4
-rw-r--r--drivers/pcmcia/o2micro.h45
-rw-r--r--drivers/pcmcia/omap_cf.c2
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c42
-rw-r--r--drivers/pcmcia/pcmcia_resource.c169
-rw-r--r--drivers/pcmcia/pd6729.c18
-rw-r--r--drivers/pcmcia/rsrc_mgr.c64
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c310
-rw-r--r--drivers/pcmcia/sa1111_generic.c25
-rw-r--r--drivers/pcmcia/socket_sysfs.c196
-rw-r--r--drivers/pcmcia/xxs1500_ss.c340
-rw-r--r--drivers/pcmcia/yenta_socket.c18
-rw-r--r--drivers/platform/x86/Kconfig16
-rw-r--r--drivers/platform/x86/acer-wmi.c2
-rw-r--r--drivers/platform/x86/asus-laptop.c1741
-rw-r--r--drivers/platform/x86/asus_acpi.c3
-rw-r--r--drivers/platform/x86/classmate-laptop.c35
-rw-r--r--drivers/platform/x86/compal-laptop.c247
-rw-r--r--drivers/platform/x86/dell-laptop.c257
-rw-r--r--drivers/platform/x86/dell-wmi.c16
-rw-r--r--drivers/platform/x86/eeepc-laptop.c317
-rw-r--r--drivers/platform/x86/hp-wmi.c20
-rw-r--r--drivers/platform/x86/msi-laptop.c360
-rw-r--r--drivers/platform/x86/panasonic-laptop.c15
-rw-r--r--drivers/platform/x86/sony-laptop.c100
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c122
-rw-r--r--drivers/platform/x86/topstar-laptop.c13
-rw-r--r--drivers/platform/x86/toshiba_acpi.c205
-rw-r--r--drivers/platform/x86/toshiba_bluetooth.c4
-rw-r--r--drivers/platform/x86/wmi.c4
-rw-r--r--drivers/pnp/base.h3
-rw-r--r--drivers/pnp/interface.c7
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c49
-rw-r--r--drivers/pnp/resource.c27
-rw-r--r--drivers/pnp/support.c4
-rw-r--r--drivers/power/Kconfig11
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/bq27x00_battery.c177
-rw-r--r--drivers/power/da9030_battery.c2
-rw-r--r--drivers/power/max8925_power.c534
-rw-r--r--drivers/power/wm8350_power.c26
-rw-r--r--drivers/power/wm97xx_battery.c14
-rw-r--r--drivers/pps/Kconfig2
-rw-r--r--drivers/pps/Makefile1
-rw-r--r--drivers/pps/clients/Kconfig25
-rw-r--r--drivers/pps/clients/Makefile10
-rw-r--r--drivers/pps/clients/pps-ktimer.c123
-rw-r--r--drivers/pps/clients/pps-ldisc.c154
-rw-r--r--drivers/ps3/ps3av.c2
-rw-r--r--drivers/regulator/88pm8607.c318
-rw-r--r--drivers/regulator/Kconfig37
-rw-r--r--drivers/regulator/Makefile4
-rw-r--r--drivers/regulator/ab3100.c6
-rw-r--r--drivers/regulator/core.c81
-rw-r--r--drivers/regulator/dummy.c66
-rw-r--r--drivers/regulator/dummy.h31
-rw-r--r--drivers/regulator/fixed.c30
-rw-r--r--drivers/regulator/lp3971.c72
-rw-r--r--drivers/regulator/max1586.c9
-rw-r--r--drivers/regulator/max8649.c408
-rw-r--r--drivers/regulator/max8660.c11
-rw-r--r--drivers/regulator/max8925-regulator.c306
-rw-r--r--drivers/regulator/mc13783-regulator.c465
-rw-r--r--drivers/regulator/pcap-regulator.c8
-rw-r--r--drivers/regulator/tps65023-regulator.c35
-rw-r--r--drivers/regulator/tps6507x-regulator.c34
-rw-r--r--drivers/regulator/twl-regulator.c22
-rw-r--r--drivers/regulator/virtual.c64
-rw-r--r--drivers/regulator/wm831x-dcdc.c12
-rw-r--r--drivers/regulator/wm831x-isink.c3
-rw-r--r--drivers/regulator/wm831x-ldo.c5
-rw-r--r--drivers/regulator/wm8350-regulator.c52
-rw-r--r--drivers/regulator/wm8400-regulator.c7
-rw-r--r--drivers/regulator/wm8994-regulator.c307
-rw-r--r--drivers/rtc/Kconfig20
-rw-r--r--drivers/rtc/Makefile2
-rw-r--r--drivers/rtc/class.c1
-rw-r--r--drivers/rtc/hctosys.c59
-rw-r--r--drivers/rtc/rtc-at91sam9.c2
-rw-r--r--drivers/rtc/rtc-coh901331.c5
-rw-r--r--drivers/rtc/rtc-ep93xx.c71
-rw-r--r--drivers/rtc/rtc-fm3130.c6
-rw-r--r--drivers/rtc/rtc-max8925.c314
-rw-r--r--drivers/rtc/rtc-mc13783.c214
-rw-r--r--drivers/rtc/rtc-mpc5121.c387
-rw-r--r--drivers/rtc/rtc-mxc.c7
-rw-r--r--drivers/rtc/rtc-pcf2123.c2
-rw-r--r--drivers/rtc/rtc-pl031.c365
-rw-r--r--drivers/rtc/rtc-sysfs.c5
-rw-r--r--drivers/rtc/rtc-twl.c4
-rw-r--r--drivers/rtc/rtc-wm8350.c11
-rw-r--r--drivers/s390/block/dasd.c97
-rw-r--r--drivers/s390/block/dasd_3990_erp.c4
-rw-r--r--drivers/s390/block/dasd_devmap.c26
-rw-r--r--drivers/s390/block/dasd_diag.c6
-rw-r--r--drivers/s390/block/dasd_eckd.c29
-rw-r--r--drivers/s390/block/dasd_fba.c10
-rw-r--r--drivers/s390/block/dasd_genhd.c4
-rw-r--r--drivers/s390/block/dasd_int.h8
-rw-r--r--drivers/s390/block/dasd_ioctl.c13
-rw-r--r--drivers/s390/block/dasd_proc.c116
-rw-r--r--drivers/s390/char/raw3270.c2
-rw-r--r--drivers/s390/char/sclp.c2
-rw-r--r--drivers/s390/char/sclp_vt220.c4
-rw-r--r--drivers/s390/char/tape_block.c5
-rw-r--r--drivers/s390/char/zcore.c163
-rw-r--r--drivers/s390/cio/ccwreq.c2
-rw-r--r--drivers/s390/cio/chsc.c2
-rw-r--r--drivers/s390/cio/chsc_sch.c4
-rw-r--r--drivers/s390/cio/cio.c14
-rw-r--r--drivers/s390/cio/crw.c29
-rw-r--r--drivers/s390/cio/css.c79
-rw-r--r--drivers/s390/cio/css.h5
-rw-r--r--drivers/s390/cio/device.c165
-rw-r--r--drivers/s390/cio/device.h3
-rw-r--r--drivers/s390/cio/device_fsm.c43
-rw-r--r--drivers/s390/cio/qdio.h92
-rw-r--r--drivers/s390/cio/qdio_debug.c24
-rw-r--r--drivers/s390/cio/qdio_main.c35
-rw-r--r--drivers/s390/cio/qdio_setup.c20
-rw-r--r--drivers/s390/cio/qdio_thinint.c4
-rw-r--r--drivers/s390/crypto/zcrypt_api.c158
-rw-r--r--drivers/s390/crypto/zcrypt_pcicc.c2
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c2
-rw-r--r--drivers/s390/kvm/kvm_virtio.c4
-rw-r--r--drivers/s390/net/Kconfig10
-rw-r--r--drivers/s390/net/Makefile1
-rw-r--r--drivers/s390/net/qeth_core.h8
-rw-r--r--drivers/s390/net/qeth_core_main.c177
-rw-r--r--drivers/s390/net/qeth_core_mpc.h44
-rw-r--r--drivers/s390/net/qeth_core_sys.c17
-rw-r--r--drivers/s390/net/qeth_l2_main.c46
-rw-r--r--drivers/s390/net/qeth_l3.h2
-rw-r--r--drivers/s390/net/qeth_l3_main.c200
-rw-r--r--drivers/s390/net/qeth_l3_sys.c56
-rw-r--r--drivers/s390/net/smsgiucv.c15
-rw-r--r--drivers/s390/net/smsgiucv.h8
-rw-r--r--drivers/s390/net/smsgiucv_app.c211
-rw-r--r--drivers/s390/scsi/zfcp_aux.c90
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c11
-rw-r--r--drivers/s390/scsi/zfcp_cfdc.c9
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c22
-rw-r--r--drivers/s390/scsi/zfcp_dbf.h34
-rw-r--r--drivers/s390/scsi/zfcp_def.h114
-rw-r--r--drivers/s390/scsi/zfcp_erp.c36
-rw-r--r--drivers/s390/scsi/zfcp_ext.h14
-rw-r--r--drivers/s390/scsi/zfcp_fc.c116
-rw-r--r--drivers/s390/scsi/zfcp_fc.h2
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c182
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c52
-rw-r--r--drivers/s390/scsi/zfcp_qdio.h109
-rw-r--r--drivers/s390/scsi/zfcp_reqlist.h183
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c39
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c37
-rw-r--r--drivers/sbus/char/openprom.c10
-rw-r--r--drivers/scsi/FlashPoint.c2
-rw-r--r--drivers/scsi/a100u2w.c2
-rw-r--r--drivers/scsi/aacraid/aachba.c52
-rw-r--r--drivers/scsi/aacraid/aacraid.h5
-rw-r--r--drivers/scsi/aacraid/commctrl.c28
-rw-r--r--drivers/scsi/aacraid/comminit.c6
-rw-r--r--drivers/scsi/aacraid/commsup.c72
-rw-r--r--drivers/scsi/aacraid/dpcsup.c36
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c53
-rw-r--r--drivers/scsi/arm/fas216.c2
-rw-r--r--drivers/scsi/be2iscsi/be.h21
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c88
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h14
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c136
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.h2
-rw-r--r--drivers/scsi/be2iscsi/be_main.c488
-rw-r--r--drivers/scsi/be2iscsi/be_main.h27
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c139
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h6
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c5
-rw-r--r--drivers/scsi/constants.c20
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_iscsi.c17
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_offload.c7
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_pdu.c6
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c2
-rw-r--r--drivers/scsi/eata.c2
-rw-r--r--drivers/scsi/esp_scsi.c14
-rw-r--r--drivers/scsi/fcoe/fcoe.c18
-rw-r--r--drivers/scsi/fcoe/libfcoe.c2
-rw-r--r--drivers/scsi/fnic/fnic.h2
-rw-r--r--drivers/scsi/fnic/fnic_main.c4
-rw-r--r--drivers/scsi/fnic/vnic_devcmd.h2
-rw-r--r--drivers/scsi/gdth.c430
-rw-r--r--drivers/scsi/gdth.h952
-rw-r--r--drivers/scsi/gdth_ioctl.h366
-rw-r--r--drivers/scsi/gdth_proc.c42
-rw-r--r--drivers/scsi/gdth_proc.h4
-rw-r--r--drivers/scsi/hosts.c4
-rw-r--r--drivers/scsi/hpsa.c793
-rw-r--r--drivers/scsi/hpsa.h136
-rw-r--r--drivers/scsi/hpsa_cmd.h204
-rw-r--r--drivers/scsi/ibmmca.c2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c4
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c2
-rw-r--r--drivers/scsi/initio.c2
-rw-r--r--drivers/scsi/ipr.c2
-rw-r--r--drivers/scsi/iscsi_tcp.c8
-rw-r--r--drivers/scsi/libfc/fc_exch.c2
-rw-r--r--drivers/scsi/libfc/fc_fcp.c7
-rw-r--r--drivers/scsi/libfc/fc_lport.c3
-rw-r--r--drivers/scsi/libfc/fc_rport.c2
-rw-r--r--drivers/scsi/libiscsi.c53
-rw-r--r--drivers/scsi/libiscsi_tcp.c8
-rw-r--r--drivers/scsi/libsrp.c8
-rw-r--r--drivers/scsi/lpfc/lpfc.h14
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c118
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c2473
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.h98
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h22
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c15
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c149
-rw-r--r--[-rwxr-xr-x]drivers/scsi/lpfc/lpfc_hbadisc.c735
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h23
-rw-r--r--[-rwxr-xr-x]drivers/scsi/lpfc/lpfc_hw4.h265
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c547
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c111
-rw-r--r--drivers/scsi/lpfc/lpfc_nl.h22
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c85
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c50
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c329
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h10
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h82
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c7
-rw-r--r--drivers/scsi/mac_esp.c152
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c264
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h36
-rw-r--r--drivers/scsi/mpt2sas/Kconfig1
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h16
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h25
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_history.txt93
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_init.h24
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h77
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_sas.h6
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c18
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h14
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_config.c51
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c13
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c266
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c196
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.h2
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c2
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c2
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c2
-rw-r--r--drivers/scsi/pmcraid.c2
-rw-r--r--drivers/scsi/pmcraid.h2
-rw-r--r--drivers/scsi/qla1280.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c732
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h158
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h33
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h8
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c44
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c120
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c154
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c151
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c8
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c147
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h6
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c14
-rw-r--r--drivers/scsi/qlogicpti.c2
-rw-r--r--drivers/scsi/raid_class.c1
-rw-r--r--drivers/scsi/scsi.c42
-rw-r--r--drivers/scsi/scsi_lib.c18
-rw-r--r--drivers/scsi/scsi_sas_internal.h2
-rw-r--r--drivers/scsi/scsi_scan.c11
-rw-r--r--drivers/scsi/scsi_sysfs.c22
-rw-r--r--drivers/scsi/scsi_transport_fc.c31
-rw-r--r--drivers/scsi/scsi_transport_sas.c103
-rw-r--r--drivers/scsi/sd.c56
-rw-r--r--drivers/scsi/ses.c14
-rw-r--r--drivers/scsi/sg.c6
-rw-r--r--drivers/scsi/sgiwd93.c2
-rw-r--r--drivers/scsi/sni_53c710.c2
-rw-r--r--drivers/scsi/st.c3
-rw-r--r--drivers/scsi/u14-34f.c2
-rw-r--r--drivers/scsi/vmw_pvscsi.c3
-rw-r--r--drivers/serial/68328serial.c8
-rw-r--r--drivers/serial/8250.c59
-rw-r--r--drivers/serial/8250_pci.c31
-rw-r--r--drivers/serial/8250_pnp.c12
-rw-r--r--drivers/serial/Kconfig100
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/amba-pl010.c15
-rw-r--r--drivers/serial/amba-pl011.c19
-rw-r--r--drivers/serial/atmel_serial.c22
-rw-r--r--drivers/serial/bcm63xx_uart.c7
-rw-r--r--drivers/serial/bfin_5xx.c22
-rw-r--r--drivers/serial/bfin_sport_uart.c701
-rw-r--r--drivers/serial/bfin_sport_uart.h38
-rw-r--r--drivers/serial/icom.c5
-rw-r--r--drivers/serial/imx.c10
-rw-r--r--drivers/serial/ioc3_serial.c3
-rw-r--r--drivers/serial/jsm/jsm_driver.c1
-rw-r--r--drivers/serial/jsm/jsm_tty.c9
-rw-r--r--drivers/serial/mpc52xx_uart.c251
-rw-r--r--drivers/serial/msm_serial.c6
-rw-r--r--drivers/serial/pmac_zilog.c257
-rw-r--r--drivers/serial/pmac_zilog.h34
-rw-r--r--drivers/serial/s3c2412.c1
-rw-r--r--drivers/serial/s5pv210.c154
-rw-r--r--drivers/serial/samsung.c8
-rw-r--r--drivers/serial/samsung.h19
-rw-r--r--drivers/serial/serial_core.c105
-rw-r--r--drivers/serial/serial_cs.c11
-rw-r--r--drivers/serial/sh-sci.c623
-rw-r--r--drivers/serial/sh-sci.h242
-rw-r--r--drivers/serial/timbuart.c7
-rw-r--r--drivers/serial/uartlite.c2
-rw-r--r--drivers/sh/intc.c276
-rw-r--r--drivers/sh/pfc.c37
-rw-r--r--drivers/spi/Kconfig25
-rw-r--r--drivers/spi/Makefile3
-rw-r--r--drivers/spi/amba-pl022.c18
-rw-r--r--drivers/spi/au1550_spi.c6
-rw-r--r--drivers/spi/coldfire_qspi.c640
-rw-r--r--drivers/spi/davinci_spi.c1255
-rw-r--r--drivers/spi/dw_spi.c111
-rw-r--r--drivers/spi/dw_spi_mmio.c147
-rw-r--r--drivers/spi/dw_spi_pci.c2
-rw-r--r--drivers/spi/mpc52xx_psc_spi.c2
-rw-r--r--drivers/spi/mpc52xx_spi.c2
-rw-r--r--drivers/spi/omap2_mcspi.c2
-rw-r--r--drivers/spi/spi_imx.c2
-rw-r--r--drivers/spi/spi_mpc8xxx.c8
-rw-r--r--drivers/spi/spi_ppc4xx.c2
-rw-r--r--drivers/spi/spi_s3c24xx.c2
-rw-r--r--drivers/spi/spi_s3c64xx.c89
-rw-r--r--drivers/spi/spi_sh_msiof.c17
-rw-r--r--drivers/spi/spi_stmp.c2
-rw-r--r--drivers/spi/xilinx_spi.c28
-rw-r--r--drivers/spi/xilinx_spi_of.c2
-rw-r--r--drivers/ssb/driver_chipcommon_pmu.c7
-rw-r--r--drivers/ssb/driver_mipscore.c5
-rw-r--r--drivers/ssb/main.c3
-rw-r--r--drivers/ssb/ssb_private.h4
-rw-r--r--drivers/staging/Kconfig16
-rw-r--r--drivers/staging/Makefile8
-rw-r--r--drivers/staging/altpciechdma/Kconfig10
-rw-r--r--drivers/staging/altpciechdma/Makefile2
-rw-r--r--drivers/staging/altpciechdma/TODO15
-rw-r--r--drivers/staging/altpciechdma/altpciechdma.c1182
-rw-r--r--drivers/staging/arlan/Makefile2
-rw-r--r--drivers/staging/arlan/arlan-main.c25
-rw-r--r--drivers/staging/arlan/arlan.h136
-rw-r--r--drivers/staging/asus_oled/asus_oled.c46
-rw-r--r--drivers/staging/b3dfg/Kconfig10
-rw-r--r--drivers/staging/b3dfg/Makefile1
-rw-r--r--drivers/staging/b3dfg/TODO4
-rw-r--r--drivers/staging/b3dfg/b3dfg.c1100
-rw-r--r--drivers/staging/batman-adv/Kconfig6
-rw-r--r--drivers/staging/batman-adv/Makefile2
-rw-r--r--drivers/staging/batman-adv/README84
-rw-r--r--drivers/staging/batman-adv/TODO24
-rw-r--r--drivers/staging/batman-adv/aggregation.c13
-rw-r--r--drivers/staging/batman-adv/bitarray.c15
-rw-r--r--drivers/staging/batman-adv/compat.h75
-rw-r--r--drivers/staging/batman-adv/device.c53
-rw-r--r--drivers/staging/batman-adv/hard-interface.c209
-rw-r--r--drivers/staging/batman-adv/hard-interface.h4
-rw-r--r--drivers/staging/batman-adv/hash.c23
-rw-r--r--drivers/staging/batman-adv/hash.h5
-rw-r--r--drivers/staging/batman-adv/log.c179
-rw-r--r--drivers/staging/batman-adv/main.c55
-rw-r--r--drivers/staging/batman-adv/main.h46
-rw-r--r--drivers/staging/batman-adv/originator.c252
-rw-r--r--drivers/staging/batman-adv/originator.h (renamed from drivers/staging/batman-adv/log.h)19
-rw-r--r--drivers/staging/batman-adv/packet.h2
-rw-r--r--drivers/staging/batman-adv/proc.c508
-rw-r--r--drivers/staging/batman-adv/proc.h13
-rw-r--r--drivers/staging/batman-adv/routing.c1304
-rw-r--r--drivers/staging/batman-adv/routing.h21
-rw-r--r--drivers/staging/batman-adv/send.c172
-rw-r--r--drivers/staging/batman-adv/send.h5
-rw-r--r--drivers/staging/batman-adv/soft-interface.c96
-rw-r--r--drivers/staging/batman-adv/soft-interface.h3
-rw-r--r--drivers/staging/batman-adv/translation-table.c94
-rw-r--r--drivers/staging/batman-adv/translation-table.h1
-rw-r--r--drivers/staging/batman-adv/types.h14
-rw-r--r--drivers/staging/batman-adv/vis.c201
-rw-r--r--drivers/staging/batman-adv/vis.h13
-rw-r--r--drivers/staging/comedi/comedi_compat32.c1
-rw-r--r--drivers/staging/comedi/comedi_fops.c12
-rw-r--r--drivers/staging/comedi/drivers.c30
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c7
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.h4
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_eeprom.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c12
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c121
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c6
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c6
-rw-r--r--drivers/staging/comedi/drivers/adq12b.c66
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c21
-rw-r--r--drivers/staging/comedi/drivers/aio_iiro_16.c4
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.c122
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236.c46
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c16
-rw-r--r--drivers/staging/comedi/drivers/c6xdigio.c57
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c28
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c12
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidio.c6
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c8
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c8
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c2
-rw-r--r--drivers/staging/comedi/drivers/contec_pci_dio.c3
-rw-r--r--drivers/staging/comedi/drivers/das08_cs.c4
-rw-r--r--drivers/staging/comedi/drivers/das6402.c2
-rw-r--r--drivers/staging/comedi/drivers/das800.c6
-rw-r--r--drivers/staging/comedi/drivers/dmm32at.c5
-rw-r--r--drivers/staging/comedi/drivers/dt2801.c33
-rw-r--r--drivers/staging/comedi/drivers/dt2815.c89
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c2
-rw-r--r--drivers/staging/comedi/drivers/fl512.c72
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c2
-rw-r--r--drivers/staging/comedi/drivers/mpc624.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c49
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c73
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c32
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio.c34
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c24
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c276
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c83
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c29
-rw-r--r--drivers/staging/comedi/drivers/pcl724.c26
-rw-r--r--drivers/staging/comedi/drivers/pcl725.c6
-rw-r--r--drivers/staging/comedi/drivers/pcl730.c6
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c16
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c66
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c39
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c85
-rw-r--r--drivers/staging/comedi/drivers/pcm3730.c6
-rw-r--r--drivers/staging/comedi/drivers/pcmad.c22
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c2
-rw-r--r--drivers/staging/comedi/drivers/poc.c14
-rw-r--r--drivers/staging/comedi/drivers/rti800.c61
-rw-r--r--drivers/staging/comedi/drivers/rti802.c8
-rw-r--r--drivers/staging/comedi/drivers/s626.c2
-rw-r--r--drivers/staging/comedi/drivers/serial2002.c2
-rw-r--r--drivers/staging/comedi/drivers/ssv_dnp.c6
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c5
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c5
-rw-r--r--drivers/staging/comedi/drivers/vmk80xx.c2
-rw-r--r--drivers/staging/crystalhd/Kconfig6
-rw-r--r--drivers/staging/crystalhd/Makefile6
-rw-r--r--drivers/staging/crystalhd/TODO16
-rw-r--r--drivers/staging/crystalhd/bc_dts_defs.h498
-rw-r--r--drivers/staging/crystalhd/bc_dts_glob_lnx.h299
-rw-r--r--drivers/staging/crystalhd/bc_dts_types.h121
-rw-r--r--drivers/staging/crystalhd/bcm_70012_regs.h757
-rw-r--r--drivers/staging/crystalhd/crystalhd_cmds.c1058
-rw-r--r--drivers/staging/crystalhd/crystalhd_cmds.h88
-rw-r--r--drivers/staging/crystalhd/crystalhd_fw_if.h369
-rw-r--r--drivers/staging/crystalhd/crystalhd_hw.c2395
-rw-r--r--drivers/staging/crystalhd/crystalhd_hw.h398
-rw-r--r--drivers/staging/crystalhd/crystalhd_lnx.c765
-rw-r--r--drivers/staging/crystalhd/crystalhd_lnx.h96
-rw-r--r--drivers/staging/crystalhd/crystalhd_misc.c1030
-rw-r--r--drivers/staging/crystalhd/crystalhd_misc.h229
-rw-r--r--drivers/staging/cx25821/cx25821-audups11.c3
-rw-r--r--drivers/staging/cx25821/cx25821-medusa-video.c8
-rw-r--r--drivers/staging/cx25821/cx25821-video.c5
-rw-r--r--drivers/staging/dream/camera/Kconfig2
-rw-r--r--drivers/staging/dream/camera/Makefile1
-rw-r--r--drivers/staging/dream/camera/msm_camera.c69
-rw-r--r--drivers/staging/dream/camera/msm_vfe7x.c3
-rw-r--r--drivers/staging/dream/camera/s5k3e2fx.c30
-rw-r--r--drivers/staging/dream/include/linux/android_pmem.h80
-rw-r--r--drivers/staging/dream/include/linux/gpio_event.h154
-rw-r--r--drivers/staging/dream/include/linux/msm_adsp.h84
-rw-r--r--drivers/staging/dream/include/linux/msm_audio.h115
-rw-r--r--drivers/staging/dream/include/linux/msm_rpcrouter.h47
-rw-r--r--drivers/staging/dream/include/linux/wakelock.h91
-rw-r--r--drivers/staging/dream/include/mach/camera.h279
-rw-r--r--drivers/staging/dream/include/mach/msm_adsp.h112
-rw-r--r--drivers/staging/dream/include/mach/msm_rpcrouter.h179
-rw-r--r--drivers/staging/dream/include/mach/msm_smd.h107
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5audplaycmdi.h94
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5audplaymsg.h70
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5audppcmdi.h914
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5audppmsg.h318
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5audpreproccmdi.h256
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5audpreprocmsg.h85
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5audreccmdi.h176
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5audrecmsg.h127
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5jpegcmdi.h376
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5jpegmsg.h177
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5lpmcmdi.h82
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5lpmmsg.h80
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5vdeccmdi.h235
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5vdecmsg.h107
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5venccmdi.h212
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5vfecmdi.h910
-rw-r--r--drivers/staging/dream/include/mach/qdsp5/qdsp5vfemsg.h290
-rw-r--r--drivers/staging/dream/include/media/msm_camera.h388
-rw-r--r--drivers/staging/dream/pmem.c26
-rw-r--r--drivers/staging/dream/qdsp5/Makefile1
-rw-r--r--drivers/staging/dream/qdsp5/audio_mp3.c3
-rw-r--r--drivers/staging/dream/smd/Makefile1
-rw-r--r--drivers/staging/dream/smd/smd_rpcrouter.c2
-rw-r--r--drivers/staging/dt3155/Kconfig4
-rw-r--r--drivers/staging/dt3155/Makefile6
-rw-r--r--drivers/staging/dt3155/TODO10
-rw-r--r--drivers/staging/dt3155/allocator.README98
-rw-r--r--drivers/staging/dt3155/allocator.c295
-rw-r--r--drivers/staging/dt3155/allocator.h28
-rw-r--r--drivers/staging/dt3155/dt3155.h171
-rw-r--r--drivers/staging/dt3155/dt3155.sysvinit60
-rw-r--r--drivers/staging/dt3155/dt3155_drv.c1095
-rw-r--r--drivers/staging/dt3155/dt3155_drv.h45
-rw-r--r--drivers/staging/dt3155/dt3155_io.c175
-rw-r--r--drivers/staging/dt3155/dt3155_io.h358
-rw-r--r--drivers/staging/dt3155/dt3155_isr.c516
-rw-r--r--drivers/staging/dt3155/dt3155_isr.h77
-rw-r--r--drivers/staging/et131x/et1310_address_map.h633
-rw-r--r--drivers/staging/et131x/et1310_eeprom.c41
-rw-r--r--drivers/staging/et131x/et1310_eeprom.h103
-rw-r--r--drivers/staging/et131x/et1310_jagcore.h94
-rw-r--r--drivers/staging/et131x/et1310_mac.c104
-rw-r--r--drivers/staging/et131x/et1310_mac.h93
-rw-r--r--drivers/staging/et131x/et1310_phy.c7
-rw-r--r--drivers/staging/et131x/et1310_phy.h34
-rw-r--r--drivers/staging/et131x/et1310_pm.c6
-rw-r--r--drivers/staging/et131x/et1310_pm.h85
-rw-r--r--drivers/staging/et131x/et1310_rx.c307
-rw-r--r--drivers/staging/et131x/et1310_rx.h253
-rw-r--r--drivers/staging/et131x/et1310_tx.c10
-rw-r--r--drivers/staging/et131x/et1310_tx.h14
-rw-r--r--drivers/staging/et131x/et131x.h153
-rw-r--r--drivers/staging/et131x/et131x_adapter.h43
-rw-r--r--drivers/staging/et131x/et131x_config.h67
-rw-r--r--drivers/staging/et131x/et131x_initpci.c12
-rw-r--r--drivers/staging/et131x/et131x_initpci.h73
-rw-r--r--drivers/staging/et131x/et131x_isr.c34
-rw-r--r--drivers/staging/et131x/et131x_isr.h65
-rw-r--r--drivers/staging/et131x/et131x_netdev.c82
-rw-r--r--drivers/staging/et131x/et131x_netdev.h64
-rw-r--r--drivers/staging/et131x/et131x_version.h9
-rw-r--r--drivers/staging/frontier/alphatrack.c2
-rw-r--r--drivers/staging/frontier/tranzport.c2
-rw-r--r--drivers/staging/go7007/go7007-driver.c2
-rw-r--r--drivers/staging/go7007/go7007-usb.c4
-rw-r--r--drivers/staging/go7007/s2250-board.c4
-rw-r--r--drivers/staging/go7007/s2250-loader.c4
-rw-r--r--drivers/staging/go7007/saa7134-go7007.c1
-rw-r--r--drivers/staging/go7007/wis-ov7640.c2
-rw-r--r--drivers/staging/go7007/wis-saa7113.c2
-rw-r--r--drivers/staging/go7007/wis-saa7115.c2
-rw-r--r--drivers/staging/go7007/wis-sony-tuner.c2
-rw-r--r--drivers/staging/go7007/wis-tw2804.c2
-rw-r--r--drivers/staging/go7007/wis-tw9903.c2
-rw-r--r--drivers/staging/go7007/wis-uda1342.c2
-rw-r--r--drivers/staging/hv/Channel.c3
-rw-r--r--drivers/staging/hv/Hv.c223
-rw-r--r--drivers/staging/hv/Hv.h16
-rw-r--r--drivers/staging/hv/NetVscApi.h4
-rw-r--r--drivers/staging/hv/RingBuffer.c153
-rw-r--r--drivers/staging/hv/RndisFilter.c10
-rw-r--r--drivers/staging/hv/StorVsc.c3
-rw-r--r--drivers/staging/hv/StorVscApi.h5
-rw-r--r--drivers/staging/hv/VersionInfo.h22
-rw-r--r--drivers/staging/hv/Vmbus.c18
-rw-r--r--drivers/staging/hv/blkvsc_drv.c15
-rw-r--r--drivers/staging/hv/netvsc_drv.c29
-rw-r--r--drivers/staging/hv/storvsc_drv.c227
-rw-r--r--drivers/staging/hv/vmbus.h12
-rw-r--r--drivers/staging/hv/vmbus_drv.c68
-rw-r--r--drivers/staging/iio/industrialio-core.c35
-rw-r--r--drivers/staging/iio/ring_generic.h3
-rw-r--r--drivers/staging/iio/ring_sw.c3
-rw-r--r--drivers/staging/iio/trigger_consumer.h4
-rw-r--r--drivers/staging/line6/driver.c2
-rw-r--r--drivers/staging/line6/variax.c2
-rw-r--r--drivers/staging/mimio/Kconfig10
-rw-r--r--drivers/staging/mimio/Makefile1
-rw-r--r--drivers/staging/mimio/mimio.c914
-rw-r--r--drivers/staging/netwave/netwave_cs.c8
-rw-r--r--drivers/staging/octeon/Makefile1
-rw-r--r--drivers/staging/octeon/ethernet-defines.h34
-rw-r--r--drivers/staging/octeon/ethernet-mdio.c6
-rw-r--r--drivers/staging/octeon/ethernet-mdio.h1
-rw-r--r--drivers/staging/octeon/ethernet-mem.c124
-rw-r--r--drivers/staging/octeon/ethernet-proc.c144
-rw-r--r--drivers/staging/octeon/ethernet-proc.h29
-rw-r--r--drivers/staging/octeon/ethernet-rgmii.c56
-rw-r--r--drivers/staging/octeon/ethernet-rx.c384
-rw-r--r--drivers/staging/octeon/ethernet-rx.h25
-rw-r--r--drivers/staging/octeon/ethernet-sgmii.c1
-rw-r--r--drivers/staging/octeon/ethernet-spi.c1
-rw-r--r--drivers/staging/octeon/ethernet-tx.c441
-rw-r--r--drivers/staging/octeon/ethernet-tx.h29
-rw-r--r--drivers/staging/octeon/ethernet-util.h13
-rw-r--r--drivers/staging/octeon/ethernet-xaui.c1
-rw-r--r--drivers/staging/octeon/ethernet.c256
-rw-r--r--drivers/staging/octeon/octeon-ethernet.h58
-rw-r--r--drivers/staging/otus/80211core/cagg.c18
-rw-r--r--drivers/staging/otus/80211core/ccmd.c2
-rw-r--r--drivers/staging/otus/80211core/cfunc.c2
-rw-r--r--drivers/staging/otus/80211core/cmm.c4
-rw-r--r--drivers/staging/otus/80211core/cmmsta.c7
-rw-r--r--drivers/staging/otus/80211core/cpsmgr.c2
-rw-r--r--drivers/staging/otus/80211core/cscanmgr.c2
-rw-r--r--drivers/staging/otus/80211core/ctkip.c5
-rw-r--r--drivers/staging/otus/80211core/ctxrx.c8
-rw-r--r--drivers/staging/otus/80211core/ledmgr.c1
-rw-r--r--drivers/staging/otus/80211core/pub_zfi.h1
-rw-r--r--drivers/staging/otus/Kconfig2
-rw-r--r--drivers/staging/otus/apdbg.c53
-rw-r--r--drivers/staging/otus/hal/hpmain.c4
-rw-r--r--drivers/staging/otus/hal/hpreg.c133
-rw-r--r--drivers/staging/otus/hal/hprw.c1
-rw-r--r--drivers/staging/otus/ioctl.c16
-rw-r--r--drivers/staging/otus/usbdrv.c4
-rw-r--r--drivers/staging/otus/wrap_pkt.c10
-rw-r--r--drivers/staging/otus/zdusb.c2
-rw-r--r--drivers/staging/p9auth/Kconfig9
-rw-r--r--drivers/staging/p9auth/Makefile1
-rw-r--r--drivers/staging/p9auth/p9auth.c408
-rw-r--r--drivers/staging/panel/panel.c1
-rw-r--r--drivers/staging/phison/phison.c4
-rw-r--r--drivers/staging/pohmelfs/inode.c30
-rw-r--r--drivers/staging/pohmelfs/netfs.h3
-rw-r--r--drivers/staging/quatech_usb2/quatech_usb2.c2
-rw-r--r--drivers/staging/ramzswap/Kconfig2
-rw-r--r--drivers/staging/ramzswap/ramzswap.txt6
-rw-r--r--drivers/staging/ramzswap/ramzswap_drv.c144
-rw-r--r--drivers/staging/ramzswap/ramzswap_drv.h67
-rw-r--r--drivers/staging/ramzswap/ramzswap_ioctl.h7
-rw-r--r--drivers/staging/ramzswap/xvmalloc.c4
-rw-r--r--drivers/staging/ramzswap/xvmalloc.h2
-rw-r--r--drivers/staging/ramzswap/xvmalloc_int.h4
-rw-r--r--drivers/staging/rar/Kconfig17
-rw-r--r--drivers/staging/rar/Makefile2
-rw-r--r--drivers/staging/rar/rar_driver.c444
-rw-r--r--drivers/staging/rar/rar_driver.h99
-rw-r--r--drivers/staging/rar_register/Kconfig30
-rw-r--r--drivers/staging/rar_register/Makefile2
-rw-r--r--drivers/staging/rar_register/rar_register.c615
-rw-r--r--drivers/staging/rar_register/rar_register.h84
-rw-r--r--drivers/staging/rt2860/Kconfig2
-rw-r--r--drivers/staging/rt2860/common/firmware.h558
-rw-r--r--drivers/staging/rt2860/common/firmware_3070.h517
-rw-r--r--drivers/staging/rt2860/common/rtmp_mcu.c167
-rw-r--r--drivers/staging/rt2860/rt_linux.c13
-rw-r--r--drivers/staging/rt2860/rt_linux.h4
-rw-r--r--drivers/staging/rt2860/rt_main_dev.c2
-rw-r--r--drivers/staging/rt2860/rtmp.h7
-rw-r--r--drivers/staging/rt2860/sta/connect.c4
-rw-r--r--drivers/staging/rt2860/sta_ioctl.c5
-rw-r--r--drivers/staging/rt2860/usb_main_dev.c6
-rw-r--r--drivers/staging/rt2870/Kconfig2
-rw-r--r--drivers/staging/rt2870/common/rtusb_io.c10
-rw-r--r--drivers/staging/rt3070/firmware.h558
-rw-r--r--drivers/staging/rt3070/md4.h8
-rw-r--r--drivers/staging/rt3090/firmware.h517
-rw-r--r--drivers/staging/rtl8187se/Kconfig1
-rw-r--r--drivers/staging/rtl8187se/Makefile1
-rw-r--r--drivers/staging/rtl8187se/TODO1
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211.h14
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c21
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c20
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c48
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c26
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c3
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c6
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c6
-rw-r--r--drivers/staging/rtl8187se/r8180.h4
-rw-r--r--drivers/staging/rtl8187se/r8180_93cx6.c146
-rw-r--r--drivers/staging/rtl8187se/r8180_93cx6.h17
-rw-r--r--drivers/staging/rtl8187se/r8180_core.c506
-rw-r--r--drivers/staging/rtl8187se/r8180_dm.c67
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8225z2.c232
-rw-r--r--drivers/staging/rtl8187se/r8185b_init.c986
-rw-r--r--drivers/staging/rtl8192e/Makefile9
-rw-r--r--drivers/staging/rtl8192e/dot11d.h138
-rw-r--r--drivers/staging/rtl8192e/ieee80211.h3
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211.h160
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.c2
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_ccmp.c37
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_tkip.c29
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c148
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c246
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c26
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c80
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c6
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c6
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl819x_HT.h4
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c65
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl819x_TSProc.c6
-rw-r--r--drivers/staging/rtl8192e/r8180_93cx6.c63
-rw-r--r--drivers/staging/rtl8192e/r8180_93cx6.h33
-rw-r--r--drivers/staging/rtl8192e/r8190_rtl8256.c360
-rw-r--r--drivers/staging/rtl8192e/r8190_rtl8256.h49
-rw-r--r--drivers/staging/rtl8192e/r8192E.h23
-rw-r--r--drivers/staging/rtl8192e/r8192E_core.c773
-rw-r--r--drivers/staging/rtl8192e/r8192E_dm.c40
-rw-r--r--drivers/staging/rtl8192e/r8192E_hw.h8
-rw-r--r--drivers/staging/rtl8192e/r8192E_wx.c212
-rw-r--r--drivers/staging/rtl8192e/r8192E_wx.h1
-rw-r--r--drivers/staging/rtl8192e/r819xE_cmdpkt.c2
-rw-r--r--drivers/staging/rtl8192e/r819xE_firmware.c85
-rw-r--r--drivers/staging/rtl8192e/r819xE_phy.c2
-rw-r--r--drivers/staging/rtl8192e/r819xE_phy.h194
-rw-r--r--drivers/staging/rtl8192e/r819xE_phyreg.h1117
-rw-r--r--drivers/staging/rtl8192su/Kconfig3
-rw-r--r--drivers/staging/rtl8192su/TODO1
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211.h17
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c19
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c21
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c20
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_module.c2
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h2
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c66
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c44
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c4
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c6
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c25
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c2
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c6
-rw-r--r--drivers/staging/rtl8192su/r8192SU_HWImg.c4276
-rw-r--r--drivers/staging/rtl8192su/r8192SU_HWImg.h2
-rw-r--r--drivers/staging/rtl8192su/r8192S_firmware.c126
-rw-r--r--drivers/staging/rtl8192su/r8192S_firmware.h7
-rw-r--r--drivers/staging/rtl8192su/r8192S_phy.c16
-rw-r--r--drivers/staging/rtl8192su/r8192U.h1
-rw-r--r--drivers/staging/rtl8192su/r8192U_core.c187
-rw-r--r--drivers/staging/rtl8192su/r8192U_dm.c2
-rw-r--r--drivers/staging/rtl8192u/Kconfig3
-rw-r--r--drivers/staging/rtl8192u/Makefile2
-rw-r--r--drivers/staging/rtl8192u/ieee80211.h3
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211.h4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c21
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c20
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_module.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c48
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c6
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c6
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c6
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c8
-rw-r--r--drivers/staging/samsung-laptop/samsung-laptop.c9
-rw-r--r--drivers/staging/sep/sep_driver.c28
-rw-r--r--drivers/staging/serqt_usb2/serqt_usb2.c4
-rw-r--r--drivers/staging/slicoss/slic.h9
-rw-r--r--drivers/staging/slicoss/slicoss.c132
-rw-r--r--drivers/staging/sm7xx/Kconfig7
-rw-r--r--drivers/staging/sm7xx/TODO1
-rw-r--r--drivers/staging/sm7xx/smtc2d.c979
-rw-r--r--drivers/staging/sm7xx/smtc2d.h530
-rw-r--r--drivers/staging/sm7xx/smtcfb.c133
-rw-r--r--drivers/staging/sm7xx/smtcfb.h2
-rw-r--r--drivers/staging/udlfb/Kconfig14
-rw-r--r--drivers/staging/udlfb/udlfb.c1993
-rw-r--r--drivers/staging/udlfb/udlfb.h281
-rw-r--r--drivers/staging/usbip/Kconfig7
-rw-r--r--drivers/staging/usbip/Makefile2
-rw-r--r--drivers/staging/usbip/usbip_common.c90
-rw-r--r--drivers/staging/usbip/usbip_common.h8
-rw-r--r--drivers/staging/usbip/vhci_sysfs.c2
-rw-r--r--drivers/staging/vme/Kconfig2
-rw-r--r--drivers/staging/vme/Makefile1
-rw-r--r--drivers/staging/vme/TODO28
-rw-r--r--drivers/staging/vme/boards/Kconfig9
-rw-r--r--drivers/staging/vme/boards/Makefile5
-rw-r--r--drivers/staging/vme/boards/vme_vmivme7805.c124
-rw-r--r--drivers/staging/vme/boards/vme_vmivme7805.h37
-rw-r--r--drivers/staging/vme/bridges/Kconfig2
-rw-r--r--drivers/staging/vme/bridges/vme_ca91cx42.c1592
-rw-r--r--drivers/staging/vme/bridges/vme_ca91cx42.h136
-rw-r--r--drivers/staging/vme/bridges/vme_tsi148.c1010
-rw-r--r--drivers/staging/vme/bridges/vme_tsi148.h16
-rw-r--r--drivers/staging/vme/devices/vme_user.c65
-rw-r--r--drivers/staging/vme/vme.c248
-rw-r--r--drivers/staging/vme/vme.h33
-rw-r--r--drivers/staging/vme/vme_api.txt27
-rw-r--r--drivers/staging/vme/vme_bridge.h107
-rw-r--r--drivers/staging/vt6655/card.c6
-rw-r--r--drivers/staging/vt6655/device_main.c13
-rw-r--r--drivers/staging/vt6655/iwctl.c2
-rw-r--r--drivers/staging/vt6656/main_usb.c8
-rw-r--r--drivers/staging/wavelan/wavelan.c14
-rw-r--r--drivers/staging/wavelan/wavelan_cs.c20
-rw-r--r--drivers/staging/winbond/core.h2
-rw-r--r--drivers/staging/winbond/localpara.h34
-rw-r--r--drivers/staging/winbond/mds_f.h3
-rw-r--r--drivers/staging/winbond/mds_s.h28
-rw-r--r--drivers/staging/winbond/mlme_s.h8
-rw-r--r--drivers/staging/winbond/mto.h5
-rw-r--r--drivers/staging/winbond/reg.c10
-rw-r--r--drivers/staging/winbond/scan_s.h1
-rw-r--r--drivers/staging/winbond/sme_api.h4
-rw-r--r--drivers/staging/winbond/wb35reg_f.h2
-rw-r--r--drivers/staging/winbond/wbusb.c24
-rw-r--r--drivers/staging/wlags49_h2/wl_main.c2
-rw-r--r--drivers/staging/wlags49_h2/wl_netdev.c32
-rw-r--r--drivers/staging/wlags49_h2/wl_pci.c1
-rw-r--r--drivers/staging/wlags49_h2/wl_profile.c76
-rw-r--r--drivers/staging/wlags49_h2/wl_util.c49
-rw-r--r--drivers/staging/wlags49_h2/wl_util.h2
-rw-r--r--drivers/staging/wlan-ng/Kconfig4
-rw-r--r--drivers/staging/wlan-ng/hfa384x.h180
-rw-r--r--drivers/staging/wlan-ng/hfa384x_usb.c42
-rw-r--r--drivers/staging/wlan-ng/p80211conv.c16
-rw-r--r--drivers/staging/wlan-ng/p80211conv.h4
-rw-r--r--drivers/staging/wlan-ng/p80211metadef.h18
-rw-r--r--drivers/staging/wlan-ng/p80211mgmt.h42
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c7
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.h44
-rw-r--r--drivers/staging/wlan-ng/p80211req.c2
-rw-r--r--drivers/staging/wlan-ng/p80211req.h2
-rw-r--r--drivers/staging/wlan-ng/p80211types.h18
-rw-r--r--drivers/staging/wlan-ng/p80211wext.c83
-rw-r--r--drivers/staging/wlan-ng/prism2fw.c69
-rw-r--r--drivers/staging/wlan-ng/prism2mgmt.c30
-rw-r--r--drivers/staging/wlan-ng/prism2mgmt.h48
-rw-r--r--drivers/staging/wlan-ng/prism2mib.c10
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c20
-rw-r--r--drivers/staging/wlan-ng/prism2usb.c6
-rw-r--r--drivers/uio/Kconfig24
-rw-r--r--drivers/uio/Makefile2
-rw-r--r--drivers/uio/uio.c4
-rw-r--r--drivers/uio/uio_netx.c172
-rw-r--r--drivers/uio/uio_smx.c140
-rw-r--r--drivers/usb/Kconfig4
-rw-r--r--drivers/usb/Makefile1
-rw-r--r--drivers/usb/atm/cxacru.c192
-rw-r--r--drivers/usb/atm/usbatm.c3
-rw-r--r--drivers/usb/atm/usbatm.h15
-rw-r--r--drivers/usb/c67x00/c67x00-drv.c8
-rw-r--r--drivers/usb/class/cdc-acm.c82
-rw-r--r--drivers/usb/class/cdc-acm.h2
-rw-r--r--drivers/usb/class/cdc-wdm.c2
-rw-r--r--drivers/usb/class/usblp.c22
-rw-r--r--drivers/usb/class/usbtmc.c2
-rw-r--r--drivers/usb/core/Kconfig4
-rw-r--r--drivers/usb/core/devices.c85
-rw-r--r--drivers/usb/core/devio.c175
-rw-r--r--drivers/usb/core/driver.c930
-rw-r--r--drivers/usb/core/endpoint.c1
-rw-r--r--drivers/usb/core/file.c2
-rw-r--r--drivers/usb/core/hcd-pci.c127
-rw-r--r--drivers/usb/core/hcd.c45
-rw-r--r--drivers/usb/core/hcd.h13
-rw-r--r--drivers/usb/core/hub.c139
-rw-r--r--drivers/usb/core/message.c14
-rw-r--r--drivers/usb/core/quirks.c18
-rw-r--r--drivers/usb/core/sysfs.c89
-rw-r--r--drivers/usb/core/urb.c13
-rw-r--r--drivers/usb/core/usb.c38
-rw-r--r--drivers/usb/core/usb.h43
-rw-r--r--drivers/usb/early/ehci-dbgp.c68
-rw-r--r--drivers/usb/gadget/Kconfig10
-rw-r--r--drivers/usb/gadget/Makefile2
-rw-r--r--drivers/usb/gadget/at91_udc.c10
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c9
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.h1
-rw-r--r--drivers/usb/gadget/epautoconf.c24
-rw-r--r--drivers/usb/gadget/ether.c2
-rw-r--r--drivers/usb/gadget/f_acm.c8
-rw-r--r--drivers/usb/gadget/f_audio.c6
-rw-r--r--drivers/usb/gadget/f_ecm.c7
-rw-r--r--drivers/usb/gadget/f_eem.c3
-rw-r--r--drivers/usb/gadget/f_mass_storage.c52
-rw-r--r--drivers/usb/gadget/f_rndis.c4
-rw-r--r--drivers/usb/gadget/file_storage.c10
-rw-r--r--drivers/usb/gadget/fsl_mx3_udc.c31
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c2
-rw-r--r--drivers/usb/gadget/gadget_chips.h59
-rw-r--r--drivers/usb/gadget/gmidi.c7
-rw-r--r--drivers/usb/gadget/goku_udc.c2
-rw-r--r--drivers/usb/gadget/inode.c39
-rw-r--r--drivers/usb/gadget/mass_storage.c8
-rw-r--r--drivers/usb/gadget/multi.c2
-rw-r--r--drivers/usb/gadget/nokia.c259
-rw-r--r--drivers/usb/gadget/printer.c18
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c4
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c135
-rw-r--r--drivers/usb/gadget/pxa27x_udc.h6
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c1
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c14
-rw-r--r--drivers/usb/gadget/u_ether.c5
-rw-r--r--drivers/usb/gadget/u_ether.h7
-rw-r--r--drivers/usb/gadget/zero.c6
-rw-r--r--drivers/usb/host/Kconfig11
-rw-r--r--drivers/usb/host/Makefile2
-rw-r--r--drivers/usb/host/ehci-atmel.c2
-rw-r--r--drivers/usb/host/ehci-au1xxx.c6
-rw-r--r--drivers/usb/host/ehci-fsl.c97
-rw-r--r--drivers/usb/host/ehci-hcd.c7
-rw-r--r--drivers/usb/host/ehci-hub.c33
-rw-r--r--drivers/usb/host/ehci-mxc.c23
-rw-r--r--drivers/usb/host/ehci-omap.c47
-rw-r--r--drivers/usb/host/ehci-orion.c8
-rw-r--r--drivers/usb/host/ehci-ppc-of.c14
-rw-r--r--drivers/usb/host/ehci-q.c11
-rw-r--r--drivers/usb/host/ehci-sched.c12
-rw-r--r--drivers/usb/host/ehci-xilinx-of.c8
-rw-r--r--drivers/usb/host/fhci-hcd.c7
-rw-r--r--drivers/usb/host/fhci-tds.c6
-rw-r--r--drivers/usb/host/imx21-dbg.c527
-rw-r--r--drivers/usb/host/imx21-hcd.c1789
-rw-r--r--drivers/usb/host/imx21-hcd.h436
-rw-r--r--drivers/usb/host/isp1362-hcd.c40
-rw-r--r--drivers/usb/host/isp1760-hcd.c16
-rw-r--r--drivers/usb/host/isp1760-if.c2
-rw-r--r--drivers/usb/host/ohci-da8xx.c456
-rw-r--r--drivers/usb/host/ohci-dbg.c4
-rw-r--r--drivers/usb/host/ohci-hcd.c5
-rw-r--r--drivers/usb/host/ohci-lh7a404.c11
-rw-r--r--drivers/usb/host/ohci-pnx4008.c6
-rw-r--r--drivers/usb/host/ohci-ppc-of.c10
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c8
-rw-r--r--drivers/usb/host/ohci-sa1111.c8
-rw-r--r--drivers/usb/host/r8a66597-hcd.c58
-rw-r--r--drivers/usb/host/sl811-hcd.c5
-rw-r--r--drivers/usb/host/uhci-hcd.c16
-rw-r--r--drivers/usb/host/uhci-hub.c2
-rw-r--r--drivers/usb/host/xhci-dbg.c19
-rw-r--r--drivers/usb/host/xhci-ext-caps.h7
-rw-r--r--drivers/usb/host/xhci-hcd.c150
-rw-r--r--drivers/usb/host/xhci-hub.c65
-rw-r--r--drivers/usb/host/xhci-mem.c47
-rw-r--r--drivers/usb/host/xhci-pci.c1
-rw-r--r--drivers/usb/host/xhci-ring.c41
-rw-r--r--drivers/usb/host/xhci.h11
-rw-r--r--drivers/usb/image/mdc800.c2
-rw-r--r--drivers/usb/image/microtek.c4
-rw-r--r--drivers/usb/misc/Kconfig25
-rw-r--r--drivers/usb/misc/Makefile2
-rw-r--r--drivers/usb/misc/adutux.c8
-rw-r--r--drivers/usb/misc/appledisplay.c5
-rw-r--r--drivers/usb/misc/berry_charge.c183
-rw-r--r--drivers/usb/misc/cypress_cy7c63.c2
-rw-r--r--drivers/usb/misc/cytherm.c2
-rw-r--r--drivers/usb/misc/emi26.c2
-rw-r--r--drivers/usb/misc/emi62.c2
-rw-r--r--drivers/usb/misc/ftdi-elan.c11
-rw-r--r--drivers/usb/misc/idmouse.c2
-rw-r--r--drivers/usb/misc/iowarrior.c6
-rw-r--r--drivers/usb/misc/isight_firmware.c4
-rw-r--r--drivers/usb/misc/ldusb.c4
-rw-r--r--drivers/usb/misc/legousbtower.c13
-rw-r--r--drivers/usb/misc/rio500.c11
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c21
-rw-r--r--drivers/usb/misc/trancevibrator.c2
-rw-r--r--drivers/usb/misc/usblcd.c7
-rw-r--r--drivers/usb/misc/usbled.c2
-rw-r--r--drivers/usb/misc/usbsevseg.c2
-rw-r--r--drivers/usb/misc/usbtest.c6
-rw-r--r--drivers/usb/misc/uss720.c2
-rw-r--r--drivers/usb/misc/vstusb.c783
-rw-r--r--drivers/usb/mon/mon_bin.c7
-rw-r--r--drivers/usb/mon/mon_text.c6
-rw-r--r--drivers/usb/musb/Kconfig6
-rw-r--r--drivers/usb/musb/blackfin.c28
-rw-r--r--drivers/usb/musb/cppi_dma.c33
-rw-r--r--drivers/usb/musb/davinci.c2
-rw-r--r--drivers/usb/musb/musb_core.c564
-rw-r--r--drivers/usb/musb/musb_core.h74
-rw-r--r--drivers/usb/musb/musb_gadget.c20
-rw-r--r--drivers/usb/musb/musb_host.c34
-rw-r--r--drivers/usb/musb/musb_regs.h103
-rw-r--r--drivers/usb/musb/musbhsdma.c25
-rw-r--r--drivers/usb/musb/musbhsdma.h17
-rw-r--r--drivers/usb/musb/omap2430.c48
-rw-r--r--drivers/usb/musb/omap2430.h32
-rw-r--r--drivers/usb/musb/tusb6010.c2
-rw-r--r--drivers/usb/musb/tusb6010_omap.c2
-rw-r--r--drivers/usb/otg/Kconfig1
-rw-r--r--drivers/usb/otg/twl4030-usb.c45
-rw-r--r--drivers/usb/serial/Kconfig19
-rw-r--r--drivers/usb/serial/Makefile2
-rw-r--r--drivers/usb/serial/aircable.c36
-rw-r--r--drivers/usb/serial/ark3116.c3
-rw-r--r--drivers/usb/serial/belkin_sa.c2
-rw-r--r--drivers/usb/serial/ch341.c27
-rw-r--r--drivers/usb/serial/cp210x.c7
-rw-r--r--drivers/usb/serial/cyberjack.c5
-rw-r--r--drivers/usb/serial/cypress_m8.c84
-rw-r--r--drivers/usb/serial/digi_acceleport.c38
-rw-r--r--drivers/usb/serial/empeg.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.c220
-rw-r--r--drivers/usb/serial/ftdi_sio.h6
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h57
-rw-r--r--drivers/usb/serial/funsoft.c2
-rw-r--r--drivers/usb/serial/garmin_gps.c3
-rw-r--r--drivers/usb/serial/generic.c17
-rw-r--r--drivers/usb/serial/hp4x.c2
-rw-r--r--drivers/usb/serial/io_edgeport.c69
-rw-r--r--drivers/usb/serial/io_tables.h10
-rw-r--r--drivers/usb/serial/io_ti.c75
-rw-r--r--drivers/usb/serial/ipaq.c1
-rw-r--r--drivers/usb/serial/ipw.c3
-rw-r--r--drivers/usb/serial/ir-usb.c13
-rw-r--r--drivers/usb/serial/iuu_phoenix.c2
-rw-r--r--drivers/usb/serial/keyspan.c57
-rw-r--r--drivers/usb/serial/keyspan.h10
-rw-r--r--drivers/usb/serial/keyspan_pda.c60
-rw-r--r--drivers/usb/serial/kl5kusb105.c66
-rw-r--r--drivers/usb/serial/kobil_sct.c25
-rw-r--r--drivers/usb/serial/mct_u232.c57
-rw-r--r--drivers/usb/serial/mct_u232.h2
-rw-r--r--drivers/usb/serial/mos7720.c185
-rw-r--r--drivers/usb/serial/mos7840.c27
-rw-r--r--drivers/usb/serial/moto_modem.c2
-rw-r--r--drivers/usb/serial/navman.c3
-rw-r--r--drivers/usb/serial/omninet.c8
-rw-r--r--drivers/usb/serial/opticon.c19
-rw-r--r--drivers/usb/serial/option.c71
-rw-r--r--drivers/usb/serial/oti6858.c36
-rw-r--r--drivers/usb/serial/pl2303.c38
-rw-r--r--drivers/usb/serial/qcaux.c96
-rw-r--r--drivers/usb/serial/qcserial.c2
-rw-r--r--drivers/usb/serial/siemens_mpi.c2
-rw-r--r--drivers/usb/serial/sierra.c60
-rw-r--r--drivers/usb/serial/spcp8x5.c27
-rw-r--r--drivers/usb/serial/symbolserial.c14
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c3
-rw-r--r--drivers/usb/serial/usb-serial.c15
-rw-r--r--drivers/usb/serial/usb_debug.c2
-rw-r--r--drivers/usb/serial/visor.c40
-rw-r--r--drivers/usb/serial/vivopay-serial.c76
-rw-r--r--drivers/usb/serial/whiteheat.c24
-rw-r--r--drivers/usb/storage/onetouch.c2
-rw-r--r--drivers/usb/storage/scsiglue.c16
-rw-r--r--drivers/usb/storage/shuttle_usbat.c15
-rw-r--r--drivers/usb/storage/transport.c6
-rw-r--r--drivers/usb/storage/unusual_devs.h97
-rw-r--r--drivers/usb/storage/usb.c5
-rw-r--r--drivers/usb/usb-skeleton.c2
-rw-r--r--drivers/usb/wusbcore/cbaf.c2
-rw-r--r--drivers/usb/wusbcore/devconnect.c2
-rw-r--r--drivers/usb/wusbcore/mmc.c2
-rw-r--r--drivers/usb/wusbcore/wusbhc.h2
-rw-r--r--drivers/uwb/driver.c5
-rw-r--r--drivers/uwb/i1480/i1480-est.c4
-rw-r--r--drivers/uwb/umc-bus.c4
-rw-r--r--drivers/uwb/uwb-internal.h4
-rw-r--r--drivers/uwb/uwbd.c2
-rw-r--r--drivers/uwb/wlp/sysfs.c3
-rw-r--r--drivers/vhost/Kconfig11
-rw-r--r--drivers/vhost/Makefile2
-rw-r--r--drivers/vhost/net.c669
-rw-r--r--drivers/vhost/vhost.c1104
-rw-r--r--drivers/vhost/vhost.h161
-rw-r--r--drivers/video/68328fb.c2
-rw-r--r--drivers/video/Kconfig39
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/acornfb.c2
-rw-r--r--drivers/video/arcfb.c2
-rw-r--r--drivers/video/asiliantfb.c4
-rw-r--r--drivers/video/aty/aty128fb.c14
-rw-r--r--drivers/video/aty/atyfb_base.c10
-rw-r--r--drivers/video/aty/radeon_backlight.c6
-rw-r--r--drivers/video/backlight/88pm860x_bl.c304
-rw-r--r--drivers/video/backlight/Kconfig13
-rw-r--r--drivers/video/backlight/Makefile2
-rw-r--r--drivers/video/backlight/max8925_bl.c200
-rw-r--r--drivers/video/bf54x-lq043fb.c30
-rw-r--r--drivers/video/bfin-lq035q1-fb.c1
-rw-r--r--drivers/video/bfin-t350mcqb-fb.c29
-rw-r--r--drivers/video/broadsheetfb.c738
-rw-r--r--drivers/video/cobalt_lcdfb.c2
-rw-r--r--drivers/video/console/Kconfig1
-rw-r--r--drivers/video/console/fbcon.c18
-rw-r--r--drivers/video/console/vgacon.c2
-rw-r--r--drivers/video/efifb.c13
-rw-r--r--drivers/video/epson1355fb.c2
-rw-r--r--drivers/video/fbmem.c1
-rw-r--r--drivers/video/fsl-diu-fb.c5
-rw-r--r--drivers/video/gbefb.c2
-rw-r--r--drivers/video/hgafb.c2
-rw-r--r--drivers/video/hitfb.c2
-rw-r--r--drivers/video/imxfb.c6
-rw-r--r--drivers/video/macfb.c736
-rw-r--r--drivers/video/macmodes.c80
-rw-r--r--drivers/video/mb862xx/mb862xxfb.c13
-rw-r--r--drivers/video/mbx/mbxfb.c2
-rw-r--r--drivers/video/modedb.c8
-rw-r--r--drivers/video/mx3fb.c12
-rw-r--r--drivers/video/nuc900fb.c779
-rw-r--r--drivers/video/nuc900fb.h55
-rw-r--r--drivers/video/omap/lcd_ams_delta.c93
-rw-r--r--drivers/video/omap/lcdc.c2
-rw-r--r--drivers/video/omap/omapfb_main.c7
-rw-r--r--drivers/video/omap2/displays/Kconfig18
-rw-r--r--drivers/video/omap2/displays/Makefile3
-rw-r--r--drivers/video/omap2/displays/panel-generic.c56
-rw-r--r--drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c159
-rw-r--r--drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c77
-rw-r--r--drivers/video/omap2/displays/panel-taal.c253
-rw-r--r--drivers/video/omap2/displays/panel-toppoly-tdo35s.c154
-rw-r--r--drivers/video/omap2/displays/panel-tpo-td043mtea1.c528
-rw-r--r--drivers/video/omap2/dss/Kconfig26
-rw-r--r--drivers/video/omap2/dss/core.c117
-rw-r--r--drivers/video/omap2/dss/dispc.c42
-rw-r--r--drivers/video/omap2/dss/display.c119
-rw-r--r--drivers/video/omap2/dss/dpi.c144
-rw-r--r--drivers/video/omap2/dss/dsi.c1031
-rw-r--r--drivers/video/omap2/dss/dss.c42
-rw-r--r--drivers/video/omap2/dss/dss.h23
-rw-r--r--drivers/video/omap2/dss/manager.c50
-rw-r--r--drivers/video/omap2/dss/overlay.c4
-rw-r--r--drivers/video/omap2/dss/rfbi.c321
-rw-r--r--drivers/video/omap2/dss/sdi.c115
-rw-r--r--drivers/video/omap2/dss/venc.c296
-rw-r--r--drivers/video/omap2/omapfb/Kconfig11
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c68
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c133
-rw-r--r--drivers/video/omap2/omapfb/omapfb.h9
-rw-r--r--drivers/video/pm2fb.c2
-rw-r--r--drivers/video/pvr2fb.c2
-rw-r--r--drivers/video/q40fb.c2
-rw-r--r--drivers/video/s1d13xxxfb.c4
-rw-r--r--drivers/video/s3c-fb.c14
-rw-r--r--drivers/video/s3c2410fb.c4
-rw-r--r--drivers/video/sa1100fb.c2
-rw-r--r--drivers/video/sgivwfb.c2
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c90
-rw-r--r--drivers/video/sis/sis_main.c3
-rw-r--r--drivers/video/sm501fb.c2
-rw-r--r--drivers/video/sstfb.c2
-rw-r--r--drivers/video/sunxvr1000.c228
-rw-r--r--drivers/video/sunxvr500.c1
-rw-r--r--drivers/video/valkyriefb.c6
-rw-r--r--drivers/video/valkyriefb.h31
-rw-r--r--drivers/video/vesafb.c2
-rw-r--r--drivers/video/vfb.c2
-rw-r--r--drivers/video/vga16fb.c2
-rw-r--r--drivers/video/via/Makefile2
-rw-r--r--drivers/video/via/accel.c5
-rw-r--r--drivers/video/via/chip.h11
-rw-r--r--drivers/video/via/dvi.c233
-rw-r--r--drivers/video/via/dvi.h7
-rw-r--r--drivers/video/via/global.c5
-rw-r--r--drivers/video/via/global.h3
-rw-r--r--drivers/video/via/hw.c330
-rw-r--r--drivers/video/via/hw.h17
-rw-r--r--drivers/video/via/iface.c78
-rw-r--r--drivers/video/via/iface.h38
-rw-r--r--drivers/video/via/lcd.c640
-rw-r--r--drivers/video/via/share.h56
-rw-r--r--drivers/video/via/via_utility.c12
-rw-r--r--drivers/video/via/via_utility.h1
-rw-r--r--drivers/video/via/viafbdev.c523
-rw-r--r--drivers/video/via/viafbdev.h6
-rw-r--r--drivers/video/via/viamode.c180
-rw-r--r--drivers/video/via/viamode.h8
-rw-r--r--drivers/video/w100fb.c2
-rw-r--r--drivers/virtio/virtio_balloon.c115
-rw-r--r--drivers/virtio/virtio_pci.c6
-rw-r--r--drivers/virtio/virtio_ring.c59
-rw-r--r--drivers/w1/masters/Kconfig2
-rw-r--r--drivers/w1/masters/ds2482.c2
-rw-r--r--drivers/w1/masters/mxc_w1.c4
-rw-r--r--drivers/w1/masters/omap_hdq.c4
-rw-r--r--drivers/w1/w1.c4
-rw-r--r--drivers/watchdog/Kconfig26
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/acquirewdt.c2
-rw-r--r--drivers/watchdog/advantechwdt.c2
-rw-r--r--drivers/watchdog/adx_wdt.c2
-rw-r--r--drivers/watchdog/alim1535_wdt.c2
-rw-r--r--drivers/watchdog/alim7101_wdt.c2
-rw-r--r--drivers/watchdog/ar7_wdt.c20
-rw-r--r--drivers/watchdog/at32ap700x_wdt.c2
-rw-r--r--drivers/watchdog/at91rm9200_wdt.c2
-rw-r--r--drivers/watchdog/bcm47xx_wdt.c2
-rw-r--r--drivers/watchdog/bfin_wdt.c69
-rw-r--r--drivers/watchdog/booke_wdt.c2
-rw-r--r--drivers/watchdog/coh901327_wdt.c2
-rw-r--r--drivers/watchdog/cpu5wdt.c2
-rw-r--r--drivers/watchdog/cpwd.c2
-rw-r--r--drivers/watchdog/davinci_wdt.c2
-rw-r--r--drivers/watchdog/ep93xx_wdt.c2
-rw-r--r--drivers/watchdog/eurotechwdt.c2
-rw-r--r--drivers/watchdog/gef_wdt.c16
-rw-r--r--drivers/watchdog/geodewdt.c2
-rw-r--r--drivers/watchdog/hpwdt.c2
-rw-r--r--drivers/watchdog/i6300esb.c101
-rw-r--r--drivers/watchdog/iTCO_wdt.c66
-rw-r--r--drivers/watchdog/ib700wdt.c2
-rw-r--r--drivers/watchdog/indydog.c2
-rw-r--r--drivers/watchdog/it8712f_wdt.c2
-rw-r--r--drivers/watchdog/it87_wdt.c2
-rw-r--r--drivers/watchdog/ixp2000_wdt.c3
-rw-r--r--drivers/watchdog/ixp4xx_wdt.c2
-rw-r--r--drivers/watchdog/ks8695_wdt.c2
-rw-r--r--drivers/watchdog/machzwd.c2
-rw-r--r--drivers/watchdog/max63xx_wdt.c397
-rw-r--r--drivers/watchdog/mixcomwd.c2
-rw-r--r--drivers/watchdog/mpc8xxx_wdt.c2
-rw-r--r--drivers/watchdog/mpcore_wdt.c2
-rw-r--r--drivers/watchdog/mv64x60_wdt.c2
-rw-r--r--drivers/watchdog/pc87413_wdt.c2
-rw-r--r--drivers/watchdog/pcwd.c2
-rw-r--r--drivers/watchdog/pcwd_pci.c2
-rw-r--r--drivers/watchdog/pcwd_usb.c2
-rw-r--r--drivers/watchdog/pika_wdt.c2
-rw-r--r--drivers/watchdog/pnx4008_wdt.c39
-rw-r--r--drivers/watchdog/pnx833x_wdt.c2
-rw-r--r--drivers/watchdog/rc32434_wdt.c2
-rw-r--r--drivers/watchdog/rdc321x_wdt.c2
-rw-r--r--drivers/watchdog/riowd.c2
-rw-r--r--drivers/watchdog/sbc_fitpc2_wdt.c13
-rw-r--r--drivers/watchdog/sch311x_wdt.c2
-rw-r--r--drivers/watchdog/stmp3xxx_wdt.c2
-rw-r--r--drivers/watchdog/ts72xx_wdt.c520
-rw-r--r--drivers/watchdog/txx9wdt.c25
-rw-r--r--drivers/watchdog/w83627hf_wdt.c2
-rw-r--r--drivers/watchdog/w83977f_wdt.c2
-rw-r--r--drivers/watchdog/wdrtas.c2
-rw-r--r--drivers/watchdog/wdt.c2
-rw-r--r--drivers/watchdog/wdt_pci.c2
-rw-r--r--drivers/watchdog/wm831x_wdt.c2
-rw-r--r--drivers/watchdog/wm8350_wdt.c2
-rw-r--r--drivers/xen/Kconfig12
-rw-r--r--drivers/xen/events.c8
-rw-r--r--drivers/xen/sys-hypervisor.c2
-rw-r--r--drivers/zorro/zorro.ids2
3394 files changed, 224175 insertions, 94375 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 368ae6d3a096..a2b902f4d437 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -96,8 +96,6 @@ source "drivers/edac/Kconfig"
source "drivers/rtc/Kconfig"
-source "drivers/clocksource/Kconfig"
-
source "drivers/dma/Kconfig"
source "drivers/dca/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 6ee53c7a57a1..34f1e1064dbc 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -99,6 +99,7 @@ obj-$(CONFIG_SGI_SN) += sn/
obj-y += firmware/
obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
+obj-$(CONFIG_ARCH_SHMOBILE) += sh/
obj-$(CONFIG_GENERIC_TIME) += clocksource/
obj-$(CONFIG_DMA_ENGINE) += dma/
obj-$(CONFIG_DCA) += dca/
@@ -106,6 +107,7 @@ obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_OF) += of/
obj-$(CONFIG_SSB) += ssb/
+obj-$(CONFIG_VHOST_NET) += vhost/
obj-$(CONFIG_VIRTIO) += virtio/
obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_STAGING) += staging/
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 66cc3f36a954..a8d8998dd5c5 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -32,7 +32,7 @@ acpi-$(CONFIG_ACPI_SLEEP) += proc.o
#
acpi-y += bus.o glue.o
acpi-y += scan.o
-acpi-y += processor_pdc.o
+acpi-y += processor_core.o
acpi-y += ec.o
acpi-$(CONFIG_ACPI_DOCK) += dock.o
acpi-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
@@ -61,7 +61,7 @@ obj-$(CONFIG_ACPI_SBS) += sbs.o
obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o
# processor has its own "processor." module_param namespace
-processor-y := processor_core.o processor_throttling.o
+processor-y := processor_driver.o processor_throttling.o
processor-y += processor_idle.o processor_thermal.o
processor-$(CONFIG_CPU_FREQ) += processor_perflib.o
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 97991ac6f5fc..7e52295f1ecc 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -208,7 +208,7 @@ static int power_saving_thread(void *data)
* the mechanism only works when all CPUs have RT task running,
* as if one CPU hasn't RT task, RT task from other CPUs will
* borrow CPU time from this CPU and cause RT task use > 95%
- * CPU time. To make 'avoid staration' work, takes a nap here.
+ * CPU time. To make 'avoid starvation' work, takes a nap here.
*/
if (do_sleep)
schedule_timeout_killable(HZ * idle_pct / 100);
@@ -222,14 +222,18 @@ static struct task_struct *ps_tsks[NR_CPUS];
static unsigned int ps_tsk_num;
static int create_power_saving_task(void)
{
+ int rc = -ENOMEM;
+
ps_tsks[ps_tsk_num] = kthread_run(power_saving_thread,
(void *)(unsigned long)ps_tsk_num,
"power_saving/%d", ps_tsk_num);
- if (ps_tsks[ps_tsk_num]) {
+ rc = IS_ERR(ps_tsks[ps_tsk_num]) ? PTR_ERR(ps_tsks[ps_tsk_num]) : 0;
+ if (!rc)
ps_tsk_num++;
- return 0;
- }
- return -EINVAL;
+ else
+ ps_tsks[ps_tsk_num] = NULL;
+
+ return rc;
}
static void destroy_power_saving_task(void)
@@ -237,6 +241,7 @@ static void destroy_power_saving_task(void)
if (ps_tsk_num > 0) {
ps_tsk_num--;
kthread_stop(ps_tsks[ps_tsk_num]);
+ ps_tsks[ps_tsk_num] = NULL;
}
}
@@ -253,7 +258,7 @@ static void set_power_saving_task_num(unsigned int num)
}
}
-static int acpi_pad_idle_cpus(unsigned int num_cpus)
+static void acpi_pad_idle_cpus(unsigned int num_cpus)
{
get_online_cpus();
@@ -261,7 +266,6 @@ static int acpi_pad_idle_cpus(unsigned int num_cpus)
set_power_saving_task_num(num_cpus);
put_online_cpus();
- return 0;
}
static uint32_t acpi_pad_idle_cpus_num(void)
@@ -369,19 +373,21 @@ static void acpi_pad_remove_sysfs(struct acpi_device *device)
static int acpi_pad_pur(acpi_handle handle, int *num_cpus)
{
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
- acpi_status status;
union acpi_object *package;
int rev, num, ret = -EINVAL;
- status = acpi_evaluate_object(handle, "_PUR", NULL, &buffer);
- if (ACPI_FAILURE(status))
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PUR", NULL, &buffer)))
+ return -EINVAL;
+
+ if (!buffer.length || !buffer.pointer)
return -EINVAL;
+
package = buffer.pointer;
if (package->type != ACPI_TYPE_PACKAGE || package->package.count != 2)
goto out;
rev = package->package.elements[0].integer.value;
num = package->package.elements[1].integer.value;
- if (rev != 1)
+ if (rev != 1 || num < 0)
goto out;
*num_cpus = num;
ret = 0;
@@ -410,7 +416,7 @@ static void acpi_pad_ost(acpi_handle handle, int stat,
static void acpi_pad_handle_notify(acpi_handle handle)
{
- int num_cpus, ret;
+ int num_cpus;
uint32_t idle_cpus;
mutex_lock(&isolated_cpus_lock);
@@ -418,12 +424,9 @@ static void acpi_pad_handle_notify(acpi_handle handle)
mutex_unlock(&isolated_cpus_lock);
return;
}
- ret = acpi_pad_idle_cpus(num_cpus);
+ acpi_pad_idle_cpus(num_cpus);
idle_cpus = acpi_pad_idle_cpus_num();
- if (!ret)
- acpi_pad_ost(handle, 0, idle_cpus);
- else
- acpi_pad_ost(handle, 1, 0);
+ acpi_pad_ost(handle, 0, idle_cpus);
mutex_unlock(&isolated_cpus_lock);
}
diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h
index 3b20786cbb0d..3e50c74ed4a1 100644
--- a/drivers/acpi/acpica/accommon.h
+++ b/drivers/acpi/acpica/accommon.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h
index a4471e3d3853..33181ad350d5 100644
--- a/drivers/acpi/acpica/acconfig.h
+++ b/drivers/acpi/acpica/acconfig.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index a4fb001d96f1..48faf3eba9fb 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h
index 6291904be01e..894a0ff2a946 100644
--- a/drivers/acpi/acpica/acdispat.h
+++ b/drivers/acpi/acpica/acdispat.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index 0bba148a2c61..3e6ba99e4053 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -76,12 +76,9 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node *node,
* evgpe - GPE handling and dispatch
*/
acpi_status
-acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
- u8 type);
+acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info);
-acpi_status
-acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info,
- u8 write_to_hardware);
+acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info);
acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info);
@@ -122,9 +119,6 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info,
u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list);
acpi_status
-acpi_ev_set_gpe_type(struct acpi_gpe_event_info *gpe_event_info, u8 type);
-
-acpi_status
acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info);
acpi_status acpi_ev_gpe_initialize(void);
@@ -139,8 +133,7 @@ acpi_status acpi_ev_initialize_op_regions(void);
acpi_status
acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
u32 function,
- u32 region_offset,
- u32 bit_width, acpi_integer * value);
+ u32 region_offset, u32 bit_width, u64 *value);
acpi_status
acpi_ev_attach_region(union acpi_operand_object *handler_obj,
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 29ba66d5a790..f8dd8f250ac4 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index 36192f142fbb..5900f135dc6d 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
index 5db9f2916f7c..6df3f8428168 100644
--- a/drivers/acpi/acpica/acinterp.h
+++ b/drivers/acpi/acpica/acinterp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -129,18 +129,17 @@ acpi_ex_common_buffer_setup(union acpi_operand_object *obj_desc,
acpi_status
acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
- acpi_integer mask,
- acpi_integer field_value,
- u32 field_datum_byte_offset);
+ u64 mask,
+ u64 field_value, u32 field_datum_byte_offset);
void
-acpi_ex_get_buffer_datum(acpi_integer * datum,
+acpi_ex_get_buffer_datum(u64 *datum,
void *buffer,
u32 buffer_length,
u32 byte_granularity, u32 buffer_offset);
void
-acpi_ex_set_buffer_datum(acpi_integer merged_datum,
+acpi_ex_set_buffer_datum(u64 merged_datum,
void *buffer,
u32 buffer_length,
u32 byte_granularity, u32 buffer_offset);
@@ -168,8 +167,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
acpi_status
acpi_ex_access_region(union acpi_operand_object *obj_desc,
- u32 field_datum_byte_offset,
- acpi_integer * value, u32 read_write);
+ u32 field_datum_byte_offset, u64 *value, u32 read_write);
/*
* exmisc - misc support routines
@@ -193,16 +191,14 @@ acpi_ex_do_concatenate(union acpi_operand_object *obj_desc,
acpi_status
acpi_ex_do_logical_numeric_op(u16 opcode,
- acpi_integer integer0,
- acpi_integer integer1, u8 * logical_result);
+ u64 integer0, u64 integer1, u8 *logical_result);
acpi_status
acpi_ex_do_logical_op(u16 opcode,
union acpi_operand_object *operand0,
- union acpi_operand_object *operand1, u8 * logical_result);
+ union acpi_operand_object *operand1, u8 *logical_result);
-acpi_integer
-acpi_ex_do_math_op(u16 opcode, acpi_integer operand0, acpi_integer operand1);
+u64 acpi_ex_do_math_op(u16 opcode, u64 operand0, u64 operand1);
acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state);
@@ -278,7 +274,7 @@ acpi_status
acpi_ex_system_do_notify_op(union acpi_operand_object *value,
union acpi_operand_object *obj_desc);
-acpi_status acpi_ex_system_do_suspend(acpi_integer time);
+acpi_status acpi_ex_system_do_suspend(u64 time);
acpi_status acpi_ex_system_do_stall(u32 time);
@@ -461,9 +457,9 @@ void acpi_ex_acquire_global_lock(u32 rule);
void acpi_ex_release_global_lock(u32 rule);
-void acpi_ex_eisa_id_to_string(char *dest, acpi_integer compressed_id);
+void acpi_ex_eisa_id_to_string(char *dest, u64 compressed_id);
-void acpi_ex_integer_to_string(char *dest, acpi_integer value);
+void acpi_ex_integer_to_string(char *dest, u64 value);
/*
* exregion - default op_region handlers
@@ -472,7 +468,7 @@ acpi_status
acpi_ex_system_memory_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context,
void *region_context);
@@ -480,35 +476,35 @@ acpi_status
acpi_ex_system_io_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context, void *region_context);
acpi_status
acpi_ex_pci_config_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context, void *region_context);
acpi_status
acpi_ex_cmos_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context, void *region_context);
acpi_status
acpi_ex_pci_bar_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context, void *region_context);
acpi_status
acpi_ex_embedded_controller_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context,
void *region_context);
@@ -516,14 +512,14 @@ acpi_status
acpi_ex_sm_bus_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context, void *region_context);
acpi_status
acpi_ex_data_table_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context, void *region_context);
#endif /* __INTERP_H__ */
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 81e64f478679..24b8faa5c395 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -374,6 +374,7 @@ union acpi_predefined_info {
struct acpi_predefined_data {
char *pathname;
const union acpi_predefined_info *predefined;
+ union acpi_operand_object *parent_package;
u32 flags;
u8 node_flags;
};
@@ -426,6 +427,8 @@ struct acpi_gpe_event_info {
struct acpi_gpe_register_info *register_info; /* Backpointer to register info */
u8 flags; /* Misc info about this GPE */
u8 gpe_number; /* This GPE */
+ u8 runtime_count;
+ u8 wakeup_count;
};
/* Information about a GPE register pair, one per each status/enable pair in an array */
@@ -649,8 +652,7 @@ struct acpi_opcode_info {
};
union acpi_parse_value {
- acpi_integer integer; /* Integer constant (Up to 64 bits) */
- struct uint64_struct integer64; /* Structure overlay for 2 32-bit Dwords */
+ u64 integer; /* Integer constant (Up to 64 bits) */
u32 size; /* bytelist or field size */
char *string; /* NULL terminated string */
u8 *buffer; /* buffer or string */
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index 7d9ba6e57554..9894929a2abb 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -272,8 +272,8 @@
* MASK_BITS_ABOVE creates a mask starting AT the position and above
* MASK_BITS_BELOW creates a mask starting one bit BELOW the position
*/
-#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_INTEGER_MAX) << ((u32) (position))))
-#define ACPI_MASK_BITS_BELOW(position) ((ACPI_INTEGER_MAX) << ((u32) (position)))
+#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_UINT64_MAX) << ((u32) (position))))
+#define ACPI_MASK_BITS_BELOW(position) ((ACPI_UINT64_MAX) << ((u32) (position)))
/* Bitfields within ACPI registers */
@@ -414,16 +414,16 @@
acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) _s); \
return (_s); })
#define return_VALUE(s) ACPI_DO_WHILE0 ({ \
- register acpi_integer _s = (s); \
+ register u64 _s = (s); \
acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, _s); \
return (_s); })
#define return_UINT8(s) ACPI_DO_WHILE0 ({ \
register u8 _s = (u8) (s); \
- acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) _s); \
+ acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) _s); \
return (_s); })
#define return_UINT32(s) ACPI_DO_WHILE0 ({ \
register u32 _s = (u32) (s); \
- acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) _s); \
+ acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) _s); \
return (_s); })
#else /* Use original less-safe macros */
@@ -434,7 +434,7 @@
acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) (s)); \
return((s)); })
#define return_VALUE(s) ACPI_DO_WHILE0 ({ \
- acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) (s)); \
+ acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) (s)); \
return((s)); })
#define return_UINT8(s) return_VALUE(s)
#define return_UINT32(s) return_VALUE(s)
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index 61edb156e8d0..258159cfcdfa 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -286,6 +286,17 @@ acpi_status
acpi_ns_repair_package_list(struct acpi_predefined_data *data,
union acpi_operand_object **obj_desc_ptr);
+acpi_status
+acpi_ns_repair_null_element(struct acpi_predefined_data *data,
+ u32 expected_btypes,
+ u32 package_index,
+ union acpi_operand_object **return_object_ptr);
+
+void
+acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
+ u8 package_type,
+ union acpi_operand_object *obj_desc);
+
/*
* nsrepair2 - Return object repair for specific
* predefined methods/objects
@@ -296,11 +307,6 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data,
acpi_status validate_status,
union acpi_operand_object **return_object_ptr);
-void
-acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
- u8 package_type,
- union acpi_operand_object *obj_desc);
-
/*
* nssearch - Namespace searching and entry
*/
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index 64062b1be3ee..cde18ea82656 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -111,7 +111,7 @@ ACPI_OBJECT_COMMON_HEADER};
struct acpi_object_integer {
ACPI_OBJECT_COMMON_HEADER u8 fill[3]; /* Prevent warning on some compilers */
- acpi_integer value;
+ u64 value;
};
/*
@@ -287,8 +287,10 @@ struct acpi_object_buffer_field {
struct acpi_object_notify_handler {
ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Parent device */
+ u32 handler_type;
acpi_notify_handler handler;
void *context;
+ struct acpi_object_notify_handler *next;
};
struct acpi_object_addr_handler {
diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h
index dfdf63327885..8c15ff43f42b 100644
--- a/drivers/acpi/acpica/acopcode.h
+++ b/drivers/acpi/acpica/acopcode.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h
index 22881e8ce229..d0bb0fd3e57a 100644
--- a/drivers/acpi/acpica/acparser.h
+++ b/drivers/acpi/acpica/acparser.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 57bdaf6ffab1..97116082cb6c 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h
index eef5bd7a59fa..528bcbaf4ce7 100644
--- a/drivers/acpi/acpica/acresrc.h
+++ b/drivers/acpi/acpica/acresrc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h
index 7980a26bad35..161bc0e3d70a 100644
--- a/drivers/acpi/acpica/acstruct.h
+++ b/drivers/acpi/acpica/acstruct.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index 01c76b8ea7ba..8ff3b741df28 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index 3a451a21a3f9..35df755251ce 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -134,7 +134,7 @@ char *acpi_ut_get_region_name(u8 space_id);
char *acpi_ut_get_event_name(u32 event_id);
-char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position);
+char acpi_ut_hex_to_ascii_char(u64 integer, u32 position);
u8 acpi_ut_valid_object_type(acpi_object_type type);
@@ -279,8 +279,7 @@ acpi_ut_status_exit(u32 line_number,
void
acpi_ut_value_exit(u32 line_number,
const char *function_name,
- const char *module_name,
- u32 component_id, acpi_integer value);
+ const char *module_name, u32 component_id, u64 value);
void
acpi_ut_ptr_exit(u32 line_number,
@@ -324,7 +323,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
acpi_status
acpi_ut_evaluate_numeric_object(char *object_name,
struct acpi_namespace_node *device_node,
- acpi_integer *value);
+ u64 *value);
acpi_status
acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 *status_flags);
@@ -437,14 +436,12 @@ void acpi_ut_delete_generic_state(union acpi_generic_state *state);
* utmath
*/
acpi_status
-acpi_ut_divide(acpi_integer in_dividend,
- acpi_integer in_divisor,
- acpi_integer * out_quotient, acpi_integer * out_remainder);
+acpi_ut_divide(u64 in_dividend,
+ u64 in_divisor, u64 *out_quotient, u64 *out_remainder);
acpi_status
-acpi_ut_short_divide(acpi_integer in_dividend,
- u32 divisor,
- acpi_integer * out_quotient, u32 * out_remainder);
+acpi_ut_short_divide(u64 in_dividend,
+ u32 divisor, u64 *out_quotient, u32 *out_remainder);
/*
* utmisc
@@ -474,8 +471,7 @@ acpi_name acpi_ut_repair_name(char *name);
u8 acpi_ut_valid_acpi_char(char character, u32 position);
-acpi_status
-acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer);
+acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer);
void ACPI_INTERNAL_VAR_XFACE
acpi_ut_predefined_warning(const char *module_name,
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h
index 4940249f2524..1f484ba228fc 100644
--- a/drivers/acpi/acpica/amlcode.h
+++ b/drivers/acpi/acpica/amlcode.h
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h
index 7b070e42b7c5..0e5798fcbb19 100644
--- a/drivers/acpi/acpica/amlresrc.h
+++ b/drivers/acpi/acpica/amlresrc.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c
index 54a225e56a64..bb13817e0c31 100644
--- a/drivers/acpi/acpica/dsfield.c
+++ b/drivers/acpi/acpica/dsfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -220,7 +220,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
union acpi_parse_object *arg)
{
acpi_status status;
- acpi_integer position;
+ u64 position;
ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info);
@@ -240,8 +240,8 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
switch (arg->common.aml_opcode) {
case AML_INT_RESERVEDFIELD_OP:
- position = (acpi_integer) info->field_bit_position
- + (acpi_integer) arg->common.value.size;
+ position = (u64) info->field_bit_position
+ + (u64) arg->common.value.size;
if (position > ACPI_UINT32_MAX) {
ACPI_ERROR((AE_INFO,
@@ -305,8 +305,8 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
/* Keep track of bit position for the next field */
- position = (acpi_integer) info->field_bit_position
- + (acpi_integer) arg->common.value.size;
+ position = (u64) info->field_bit_position
+ + (u64) arg->common.value.size;
if (position > ACPI_UINT32_MAX) {
ACPI_ERROR((AE_INFO,
diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c
index f23fa0be6fc2..abe140318a74 100644
--- a/drivers/acpi/acpica/dsinit.c
+++ b/drivers/acpi/acpica/dsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index e786f9fd767f..721039233aa7 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c
index 0ba19f84ad82..cc343b959540 100644
--- a/drivers/acpi/acpica/dsmthdat.c
+++ b/drivers/acpi/acpica/dsmthdat.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c
index 9bc1ba076347..891e08bf560b 100644
--- a/drivers/acpi/acpica/dsobject.c
+++ b/drivers/acpi/acpica/dsobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -684,7 +684,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
case AML_ONES_OP:
- obj_desc->integer.value = ACPI_INTEGER_MAX;
+ obj_desc->integer.value = ACPI_UINT64_MAX;
/* Truncate value if we are executing from a 32-bit ACPI table */
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index b79978f7bc71..bf980cadb1e8 100644
--- a/drivers/acpi/acpica/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index dfa104102926..306c62ab2e88 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index f0280856dc0e..6b76c486d784 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c
index b40513dd6a6a..140a9d002959 100644
--- a/drivers/acpi/acpica/dswload.c
+++ b/drivers/acpi/acpica/dswload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c
index 908645e72f03..d1e701709dac 100644
--- a/drivers/acpi/acpica/dswscope.c
+++ b/drivers/acpi/acpica/dswscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c
index e46c821cf572..050df8164165 100644
--- a/drivers/acpi/acpica/dswstate.c
+++ b/drivers/acpi/acpica/dswstate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index cd55c774e882..c1e6f472d435 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index afacf4416c73..837de669743a 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,54 +54,9 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context);
/*******************************************************************************
*
- * FUNCTION: acpi_ev_set_gpe_type
- *
- * PARAMETERS: gpe_event_info - GPE to set
- * Type - New type
- *
- * RETURN: Status
- *
- * DESCRIPTION: Sets the new type for the GPE (wake, run, or wake/run)
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ev_set_gpe_type(struct acpi_gpe_event_info *gpe_event_info, u8 type)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(ev_set_gpe_type);
-
- /* Validate type and update register enable masks */
-
- switch (type) {
- case ACPI_GPE_TYPE_WAKE:
- case ACPI_GPE_TYPE_RUNTIME:
- case ACPI_GPE_TYPE_WAKE_RUN:
- break;
-
- default:
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Disable the GPE if currently enabled */
-
- status = acpi_ev_disable_gpe(gpe_event_info);
-
- /* Clear the type bits and insert the new Type */
-
- gpe_event_info->flags &= ~ACPI_GPE_TYPE_MASK;
- gpe_event_info->flags |= type;
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ev_update_gpe_enable_masks
*
* PARAMETERS: gpe_event_info - GPE to update
- * Type - What to do: ACPI_GPE_DISABLE or
- * ACPI_GPE_ENABLE
*
* RETURN: Status
*
@@ -110,8 +65,7 @@ acpi_ev_set_gpe_type(struct acpi_gpe_event_info *gpe_event_info, u8 type)
******************************************************************************/
acpi_status
-acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
- u8 type)
+acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info)
{
struct acpi_gpe_register_info *gpe_register_info;
u8 register_bit;
@@ -127,37 +81,14 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
(1 <<
(gpe_event_info->gpe_number - gpe_register_info->base_gpe_number));
- /* 1) Disable case. Simply clear all enable bits */
-
- if (type == ACPI_GPE_DISABLE) {
- ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
- register_bit);
- ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit);
- return_ACPI_STATUS(AE_OK);
- }
-
- /* 2) Enable case. Set/Clear the appropriate enable bits */
+ ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, register_bit);
+ ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit);
- switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
- case ACPI_GPE_TYPE_WAKE:
- ACPI_SET_BIT(gpe_register_info->enable_for_wake, register_bit);
- ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit);
- break;
-
- case ACPI_GPE_TYPE_RUNTIME:
- ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
- register_bit);
+ if (gpe_event_info->runtime_count)
ACPI_SET_BIT(gpe_register_info->enable_for_run, register_bit);
- break;
- case ACPI_GPE_TYPE_WAKE_RUN:
+ if (gpe_event_info->wakeup_count)
ACPI_SET_BIT(gpe_register_info->enable_for_wake, register_bit);
- ACPI_SET_BIT(gpe_register_info->enable_for_run, register_bit);
- break;
-
- default:
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
return_ACPI_STATUS(AE_OK);
}
@@ -167,8 +98,6 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
* FUNCTION: acpi_ev_enable_gpe
*
* PARAMETERS: gpe_event_info - GPE to enable
- * write_to_hardware - Enable now, or just mark data structs
- * (WAKE GPEs should be deferred)
*
* RETURN: Status
*
@@ -176,9 +105,7 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
*
******************************************************************************/
-acpi_status
-acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info,
- u8 write_to_hardware)
+acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
{
acpi_status status;
@@ -186,47 +113,20 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info,
/* Make sure HW enable masks are updated */
- status =
- acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_ENABLE);
- if (ACPI_FAILURE(status)) {
+ status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
+ if (ACPI_FAILURE(status))
return_ACPI_STATUS(status);
- }
/* Mark wake-enabled or HW enable, or both */
- switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
- case ACPI_GPE_TYPE_WAKE:
-
- ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
- break;
-
- case ACPI_GPE_TYPE_WAKE_RUN:
-
- ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
-
- /*lint -fallthrough */
-
- case ACPI_GPE_TYPE_RUNTIME:
-
- ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
-
- if (write_to_hardware) {
-
- /* Clear the GPE (of stale events), then enable it */
-
- status = acpi_hw_clear_gpe(gpe_event_info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Enable the requested runtime GPE */
-
- status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
- }
- break;
+ if (gpe_event_info->runtime_count) {
+ /* Clear the GPE (of stale events), then enable it */
+ status = acpi_hw_clear_gpe(gpe_event_info);
+ if (ACPI_FAILURE(status))
+ return_ACPI_STATUS(status);
- default:
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ /* Enable the requested runtime GPE */
+ status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
}
return_ACPI_STATUS(AE_OK);
@@ -252,34 +152,9 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/* Make sure HW enable masks are updated */
- status =
- acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_DISABLE);
- if (ACPI_FAILURE(status)) {
+ status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
+ if (ACPI_FAILURE(status))
return_ACPI_STATUS(status);
- }
-
- /* Clear the appropriate enabled flags for this GPE */
-
- switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
- case ACPI_GPE_TYPE_WAKE:
- ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
- break;
-
- case ACPI_GPE_TYPE_WAKE_RUN:
- ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
-
- /* fallthrough */
-
- case ACPI_GPE_TYPE_RUNTIME:
-
- /* Disable the requested runtime GPE */
-
- ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
- break;
-
- default:
- break;
- }
/*
* Even if we don't know the GPE type, make sure that we always
@@ -521,7 +396,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
/* Set the GPE flags for return to enabled state */
- (void)acpi_ev_enable_gpe(gpe_event_info, FALSE);
+ (void)acpi_ev_update_gpe_enable_masks(gpe_event_info);
/*
* Take a snapshot of the GPE info for this level - we copy the info to
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index 247920900187..fef721917eaf 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -258,7 +258,6 @@ acpi_ev_save_method_info(acpi_handle obj_handle,
u32 gpe_number;
char name[ACPI_NAME_SIZE + 1];
u8 type;
- acpi_status status;
ACPI_FUNCTION_TRACE(ev_save_method_info);
@@ -325,26 +324,20 @@ acpi_ev_save_method_info(acpi_handle obj_handle,
/*
* Now we can add this information to the gpe_event_info block for use
- * during dispatch of this GPE. Default type is RUNTIME, although this may
- * change when the _PRW methods are executed later.
+ * during dispatch of this GPE.
*/
gpe_event_info =
&gpe_block->event_info[gpe_number - gpe_block->block_base_number];
- gpe_event_info->flags = (u8)
- (type | ACPI_GPE_DISPATCH_METHOD | ACPI_GPE_TYPE_RUNTIME);
+ gpe_event_info->flags = (u8) (type | ACPI_GPE_DISPATCH_METHOD);
gpe_event_info->dispatch.method_node =
(struct acpi_namespace_node *)obj_handle;
- /* Update enable mask, but don't enable the HW GPE as of yet */
-
- status = acpi_ev_enable_gpe(gpe_event_info, FALSE);
-
ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
"Registered GPE method %s as GPE number 0x%.2X\n",
name, gpe_number));
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
@@ -454,20 +447,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
gpe_block->
block_base_number];
- /* Mark GPE for WAKE-ONLY but WAKE_DISABLED */
-
- gpe_event_info->flags &=
- ~(ACPI_GPE_WAKE_ENABLED | ACPI_GPE_RUN_ENABLED);
-
- status =
- acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- status =
- acpi_ev_update_gpe_enable_masks(gpe_event_info,
- ACPI_GPE_DISABLE);
+ gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
}
cleanup:
@@ -989,7 +969,6 @@ acpi_status
acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
struct acpi_gpe_block_info *gpe_block)
{
- acpi_status status;
struct acpi_gpe_event_info *gpe_event_info;
struct acpi_gpe_walk_info gpe_info;
u32 wake_gpe_count;
@@ -1019,42 +998,50 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
gpe_info.gpe_block = gpe_block;
gpe_info.gpe_device = gpe_device;
- status =
- acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
acpi_ev_match_prw_and_gpe, NULL,
&gpe_info, NULL);
}
/*
- * Enable all GPEs in this block that have these attributes:
- * 1) are "runtime" or "run/wake" GPEs, and
- * 2) have a corresponding _Lxx or _Exx method
- *
- * Any other GPEs within this block must be enabled via the
- * acpi_enable_gpe() external interface.
+ * Enable all GPEs that have a corresponding method and aren't
+ * capable of generating wakeups. Any other GPEs within this block
+ * must be enabled via the acpi_enable_gpe() interface.
*/
wake_gpe_count = 0;
gpe_enabled_count = 0;
+ if (gpe_device == acpi_gbl_fadt_gpe_device)
+ gpe_device = NULL;
for (i = 0; i < gpe_block->register_count; i++) {
- for (j = 0; j < 8; j++) {
+ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
+ acpi_status status;
+ acpi_size gpe_index;
+ int gpe_number;
/* Get the info block for this particular GPE */
+ gpe_index = (acpi_size)i * ACPI_GPE_REGISTER_WIDTH + j;
+ gpe_event_info = &gpe_block->event_info[gpe_index];
- gpe_event_info = &gpe_block->event_info[((acpi_size) i *
- ACPI_GPE_REGISTER_WIDTH)
- + j];
-
- if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
- ACPI_GPE_DISPATCH_METHOD) &&
- (gpe_event_info->flags & ACPI_GPE_TYPE_RUNTIME)) {
- gpe_enabled_count++;
- }
-
- if (gpe_event_info->flags & ACPI_GPE_TYPE_WAKE) {
+ if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) {
wake_gpe_count++;
+ if (acpi_gbl_leave_wake_gpes_disabled)
+ continue;
}
+
+ if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD))
+ continue;
+
+ gpe_number = gpe_index + gpe_block->block_base_number;
+ status = acpi_enable_gpe(gpe_device, gpe_number,
+ ACPI_GPE_TYPE_RUNTIME);
+ if (ACPI_FAILURE(status))
+ ACPI_ERROR((AE_INFO,
+ "Failed to enable GPE %02X\n",
+ gpe_number));
+ else
+ gpe_enabled_count++;
}
}
@@ -1062,15 +1049,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
"Found %u Wake, Enabled %u Runtime GPEs in this block\n",
wake_gpe_count, gpe_enabled_count));
- /* Enable all valid runtime GPEs found above */
-
- status = acpi_hw_enable_runtime_gpe_block(NULL, gpe_block, NULL);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO, "Could not enable GPEs in GpeBlock %p",
- gpe_block));
- }
-
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index ce224e1eaa89..9a3cb7045a32 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -259,9 +259,15 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
handler_obj = notify_info->notify.handler_obj;
if (handler_obj) {
- handler_obj->notify.handler(notify_info->notify.node,
- notify_info->notify.value,
- handler_obj->notify.context);
+ struct acpi_object_notify_handler *notifier;
+
+ notifier = &handler_obj->notify;
+ while (notifier) {
+ notifier->handler(notify_info->notify.node,
+ notify_info->notify.value,
+ notifier->context);
+ notifier = notifier->next;
+ }
}
/* All done with the info object */
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index 5336d911fbf0..98fd210e87b2 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -329,7 +329,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
* region_offset - Where in the region to read or write
* bit_width - Field width in bits (8, 16, 32, or 64)
* Value - Pointer to in or out value, must be
- * full 64-bit acpi_integer
+ * a full 64-bit integer
*
* RETURN: Status
*
@@ -341,8 +341,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
acpi_status
acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
u32 function,
- u32 region_offset,
- u32 bit_width, acpi_integer * value)
+ u32 region_offset, u32 bit_width, u64 *value)
{
acpi_status status;
acpi_adr_space_handler handler;
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index ff168052a332..2e3b0334072f 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -168,7 +168,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
void *handler_context, void **region_context)
{
acpi_status status = AE_OK;
- acpi_integer pci_value;
+ u64 pci_value;
struct acpi_pci_id *pci_id = *region_context;
union acpi_operand_object *handler_obj;
struct acpi_namespace_node *parent_node;
diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c
index 567b356c85af..8dfbaa96e422 100644
--- a/drivers/acpi/acpica/evsci.c
+++ b/drivers/acpi/acpica/evsci.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 2fe0809d4eb2..b40757955f9b 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -218,6 +218,72 @@ ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)
/*******************************************************************************
*
+ * FUNCTION: acpi_populate_handler_object
+ *
+ * PARAMETERS: handler_obj - Handler object to populate
+ * handler_type - The type of handler:
+ * ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
+ * ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
+ * ACPI_ALL_NOTIFY: both system and device
+ * handler - Address of the handler
+ * context - Value passed to the handler on each GPE
+ * next - Address of a handler object to link to
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Populate a handler object.
+ *
+ ******************************************************************************/
+static void
+acpi_populate_handler_object(struct acpi_object_notify_handler *handler_obj,
+ u32 handler_type,
+ acpi_notify_handler handler, void *context,
+ struct acpi_object_notify_handler *next)
+{
+ handler_obj->handler_type = handler_type;
+ handler_obj->handler = handler;
+ handler_obj->context = context;
+ handler_obj->next = next;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_add_handler_object
+ *
+ * PARAMETERS: parent_obj - Parent of the new object
+ * handler - Address of the handler
+ * context - Value passed to the handler on each GPE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new handler object and populate it.
+ *
+ ******************************************************************************/
+static acpi_status
+acpi_add_handler_object(struct acpi_object_notify_handler *parent_obj,
+ acpi_notify_handler handler, void *context)
+{
+ struct acpi_object_notify_handler *handler_obj;
+
+ /* The parent must not be a defice notify handler object. */
+ if (parent_obj->handler_type & ACPI_DEVICE_NOTIFY)
+ return AE_BAD_PARAMETER;
+
+ handler_obj = ACPI_ALLOCATE_ZEROED(sizeof(*handler_obj));
+ if (!handler_obj)
+ return AE_NO_MEMORY;
+
+ acpi_populate_handler_object(handler_obj,
+ ACPI_SYSTEM_NOTIFY,
+ handler, context,
+ parent_obj->next);
+ parent_obj->next = handler_obj;
+
+ return AE_OK;
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_install_notify_handler
*
* PARAMETERS: Device - The device for which notifies will be handled
@@ -316,15 +382,32 @@ acpi_install_notify_handler(acpi_handle device,
obj_desc = acpi_ns_get_attached_object(node);
if (obj_desc) {
- /* Object exists - make sure there's no handler */
+ /* Object exists. */
- if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
- obj_desc->common_notify.system_notify) ||
- ((handler_type & ACPI_DEVICE_NOTIFY) &&
- obj_desc->common_notify.device_notify)) {
+ /* For a device notify, make sure there's no handler. */
+ if ((handler_type & ACPI_DEVICE_NOTIFY) &&
+ obj_desc->common_notify.device_notify) {
status = AE_ALREADY_EXISTS;
goto unlock_and_exit;
}
+
+ /* System notifies may have more handlers installed. */
+ notify_obj = obj_desc->common_notify.system_notify;
+
+ if ((handler_type & ACPI_SYSTEM_NOTIFY) && notify_obj) {
+ struct acpi_object_notify_handler *parent_obj;
+
+ if (handler_type & ACPI_DEVICE_NOTIFY) {
+ status = AE_ALREADY_EXISTS;
+ goto unlock_and_exit;
+ }
+
+ parent_obj = &notify_obj->notify;
+ status = acpi_add_handler_object(parent_obj,
+ handler,
+ context);
+ goto unlock_and_exit;
+ }
} else {
/* Create a new object */
@@ -356,9 +439,10 @@ acpi_install_notify_handler(acpi_handle device,
goto unlock_and_exit;
}
- notify_obj->notify.node = node;
- notify_obj->notify.handler = handler;
- notify_obj->notify.context = context;
+ acpi_populate_handler_object(&notify_obj->notify,
+ handler_type,
+ handler, context,
+ NULL);
if (handler_type & ACPI_SYSTEM_NOTIFY) {
obj_desc->common_notify.system_notify = notify_obj;
@@ -418,6 +502,10 @@ acpi_remove_notify_handler(acpi_handle device,
goto exit;
}
+
+ /* Make sure all deferred tasks are completed */
+ acpi_os_wait_events_complete(NULL);
+
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
goto exit;
@@ -445,15 +533,6 @@ acpi_remove_notify_handler(acpi_handle device,
goto unlock_and_exit;
}
- /* Make sure all deferred tasks are completed */
-
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- acpi_os_wait_events_complete(NULL);
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
-
if (handler_type & ACPI_SYSTEM_NOTIFY) {
acpi_gbl_system_notify.node = NULL;
acpi_gbl_system_notify.handler = NULL;
@@ -488,28 +567,60 @@ acpi_remove_notify_handler(acpi_handle device,
/* Object exists - make sure there's an existing handler */
if (handler_type & ACPI_SYSTEM_NOTIFY) {
+ struct acpi_object_notify_handler *handler_obj;
+ struct acpi_object_notify_handler *parent_obj;
+
notify_obj = obj_desc->common_notify.system_notify;
if (!notify_obj) {
status = AE_NOT_EXIST;
goto unlock_and_exit;
}
- if (notify_obj->notify.handler != handler) {
+ handler_obj = &notify_obj->notify;
+ parent_obj = NULL;
+ while (handler_obj->handler != handler) {
+ if (handler_obj->next) {
+ parent_obj = handler_obj;
+ handler_obj = handler_obj->next;
+ } else {
+ break;
+ }
+ }
+
+ if (handler_obj->handler != handler) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
- /* Make sure all deferred tasks are completed */
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- acpi_os_wait_events_complete(NULL);
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- goto exit;
+ /*
+ * Remove the handler. There are three possible cases.
+ * First, we may need to remove a non-embedded object.
+ * Second, we may need to remove the embedded object's
+ * handler data, while non-embedded objects exist.
+ * Finally, we may need to remove the embedded object
+ * entirely along with its container.
+ */
+ if (parent_obj) {
+ /* Non-embedded object is being removed. */
+ parent_obj->next = handler_obj->next;
+ ACPI_FREE(handler_obj);
+ } else if (notify_obj->notify.next) {
+ /*
+ * The handler matches the embedded object, but
+ * there are more handler objects in the list.
+ * Replace the embedded object's data with the
+ * first next object's data and remove that
+ * object.
+ */
+ parent_obj = &notify_obj->notify;
+ handler_obj = notify_obj->notify.next;
+ *parent_obj = *handler_obj;
+ ACPI_FREE(handler_obj);
+ } else {
+ /* No more handler objects in the list. */
+ obj_desc->common_notify.system_notify = NULL;
+ acpi_ut_remove_reference(notify_obj);
}
-
- /* Remove the handler */
- obj_desc->common_notify.system_notify = NULL;
- acpi_ut_remove_reference(notify_obj);
}
if (handler_type & ACPI_DEVICE_NOTIFY) {
@@ -523,14 +634,6 @@ acpi_remove_notify_handler(acpi_handle device,
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
- /* Make sure all deferred tasks are completed */
-
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- acpi_os_wait_events_complete(NULL);
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
/* Remove the handler */
obj_desc->common_notify.device_notify = NULL;
@@ -617,13 +720,6 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
handler->context = context;
handler->method_node = gpe_event_info->dispatch.method_node;
- /* Disable the GPE before installing the handler */
-
- status = acpi_ev_disable_gpe(gpe_event_info);
- if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
- }
-
/* Install the handler */
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
@@ -707,13 +803,6 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
goto unlock_and_exit;
}
- /* Disable the GPE before removing the handler */
-
- status = acpi_ev_disable_gpe(gpe_event_info);
- if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
- }
-
/* Make sure all deferred tasks are completed */
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index eed7a38d25f2..5ff32c78ea2d 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -201,23 +201,27 @@ ACPI_EXPORT_SYMBOL(acpi_enable_event)
/*******************************************************************************
*
- * FUNCTION: acpi_set_gpe_type
+ * FUNCTION: acpi_set_gpe
*
* PARAMETERS: gpe_device - Parent GPE Device
* gpe_number - GPE level within the GPE block
- * Type - New GPE type
+ * action - Enable or disable
+ * Called from ISR or not
*
* RETURN: Status
*
- * DESCRIPTION: Set the type of an individual GPE
+ * DESCRIPTION: Enable or disable an ACPI event (general purpose)
*
******************************************************************************/
-acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type)
+acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
{
acpi_status status = AE_OK;
+ acpi_cpu_flags flags;
struct acpi_gpe_event_info *gpe_event_info;
- ACPI_FUNCTION_TRACE(acpi_set_gpe_type);
+ ACPI_FUNCTION_TRACE(acpi_set_gpe);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
/* Ensure that we have a valid GPE number */
@@ -227,19 +231,29 @@ acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type)
goto unlock_and_exit;
}
- if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == type) {
- return_ACPI_STATUS(AE_OK);
- }
+ /* Perform the action */
+
+ switch (action) {
+ case ACPI_GPE_ENABLE:
+ status = acpi_ev_enable_gpe(gpe_event_info);
+ break;
- /* Set the new type (will disable GPE if currently enabled) */
+ case ACPI_GPE_DISABLE:
+ status = acpi_ev_disable_gpe(gpe_event_info);
+ break;
- status = acpi_ev_set_gpe_type(gpe_event_info, type);
+ default:
+ ACPI_ERROR((AE_INFO, "Invalid action\n"));
+ status = AE_BAD_PARAMETER;
+ break;
+ }
unlock_and_exit:
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
return_ACPI_STATUS(status);
}
-ACPI_EXPORT_SYMBOL(acpi_set_gpe_type)
+ACPI_EXPORT_SYMBOL(acpi_set_gpe)
/*******************************************************************************
*
@@ -247,15 +261,14 @@ ACPI_EXPORT_SYMBOL(acpi_set_gpe_type)
*
* PARAMETERS: gpe_device - Parent GPE Device
* gpe_number - GPE level within the GPE block
- * Flags - Just enable, or also wake enable?
- * Called from ISR or not
+ * type - Purpose the GPE will be used for
*
* RETURN: Status
*
- * DESCRIPTION: Enable an ACPI event (general purpose)
+ * DESCRIPTION: Take a reference to a GPE and enable it if necessary
*
******************************************************************************/
-acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
+acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 type)
{
acpi_status status = AE_OK;
acpi_cpu_flags flags;
@@ -263,6 +276,9 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
ACPI_FUNCTION_TRACE(acpi_enable_gpe);
+ if (type & ~ACPI_GPE_TYPE_WAKE_RUN)
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
/* Ensure that we have a valid GPE number */
@@ -273,15 +289,32 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
goto unlock_and_exit;
}
- /* Perform the enable */
+ if (type & ACPI_GPE_TYPE_RUNTIME) {
+ if (++gpe_event_info->runtime_count == 1) {
+ status = acpi_ev_enable_gpe(gpe_event_info);
+ if (ACPI_FAILURE(status))
+ gpe_event_info->runtime_count--;
+ }
+ }
+
+ if (type & ACPI_GPE_TYPE_WAKE) {
+ if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
- status = acpi_ev_enable_gpe(gpe_event_info, TRUE);
+ /*
+ * Wake-up GPEs are only enabled right prior to putting the
+ * system into a sleep state.
+ */
+ if (++gpe_event_info->wakeup_count == 1)
+ acpi_ev_update_gpe_enable_masks(gpe_event_info);
+ }
- unlock_and_exit:
+unlock_and_exit:
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
return_ACPI_STATUS(status);
}
-
ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
/*******************************************************************************
@@ -290,15 +323,14 @@ ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
*
* PARAMETERS: gpe_device - Parent GPE Device
* gpe_number - GPE level within the GPE block
- * Flags - Just disable, or also wake disable?
- * Called from ISR or not
+ * type - Purpose the GPE won't be used for any more
*
* RETURN: Status
*
- * DESCRIPTION: Disable an ACPI event (general purpose)
+ * DESCRIPTION: Release a reference to a GPE and disable it if necessary
*
******************************************************************************/
-acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
+acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 type)
{
acpi_status status = AE_OK;
acpi_cpu_flags flags;
@@ -306,6 +338,9 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
ACPI_FUNCTION_TRACE(acpi_disable_gpe);
+ if (type & ~ACPI_GPE_TYPE_WAKE_RUN)
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
/* Ensure that we have a valid GPE number */
@@ -315,13 +350,24 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
goto unlock_and_exit;
}
- status = acpi_ev_disable_gpe(gpe_event_info);
+ if ((type & ACPI_GPE_TYPE_RUNTIME) && gpe_event_info->runtime_count) {
+ if (--gpe_event_info->runtime_count == 0)
+ status = acpi_ev_disable_gpe(gpe_event_info);
+ }
+
+ if ((type & ACPI_GPE_TYPE_WAKE) && gpe_event_info->wakeup_count) {
+ /*
+ * Wake-up GPEs are not enabled after leaving system sleep
+ * states, so we don't need to disable them here.
+ */
+ if (--gpe_event_info->wakeup_count == 0)
+ acpi_ev_update_gpe_enable_masks(gpe_event_info);
+ }
unlock_and_exit:
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
return_ACPI_STATUS(status);
}
-
ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
/*******************************************************************************
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c
index c98aa7c2d67c..541cbc1544d5 100644
--- a/drivers/acpi/acpica/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 46adfa541cbc..7e8b3bedc376 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -284,7 +284,7 @@ static acpi_status
acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer)
{
acpi_status status;
- acpi_integer value;
+ u64 value;
u32 region_offset = 0;
u32 i;
@@ -490,7 +490,11 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
status = acpi_tb_add_table(&table_desc, &table_index);
if (ACPI_FAILURE(status)) {
- goto cleanup;
+
+ /* Delete allocated table buffer */
+
+ acpi_tb_delete_table(&table_desc);
+ return_ACPI_STATUS(status);
}
/*
@@ -533,13 +537,6 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
acpi_gbl_table_handler_context);
}
- cleanup:
- if (ACPI_FAILURE(status)) {
-
- /* Delete allocated table buffer */
-
- acpi_tb_delete_table(&table_desc);
- }
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c
index 51d5f224f9fa..bda7aed0404b 100644
--- a/drivers/acpi/acpica/exconvrt.c
+++ b/drivers/acpi/acpica/exconvrt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,8 +51,7 @@ ACPI_MODULE_NAME("exconvrt")
/* Local prototypes */
static u32
-acpi_ex_convert_to_ascii(acpi_integer integer,
- u16 base, u8 * string, u8 max_length);
+acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 max_length);
/*******************************************************************************
*
@@ -75,7 +74,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
{
union acpi_operand_object *return_desc;
u8 *pointer;
- acpi_integer result;
+ u64 result;
u32 i;
u32 count;
acpi_status status;
@@ -155,7 +154,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
* Little endian is used, meaning that the first byte of the buffer
* is the LSB of the integer
*/
- result |= (((acpi_integer) pointer[i]) << (i * 8));
+ result |= (((u64) pointer[i]) << (i * 8));
}
break;
@@ -285,10 +284,9 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
******************************************************************************/
static u32
-acpi_ex_convert_to_ascii(acpi_integer integer,
- u16 base, u8 * string, u8 data_width)
+acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
{
- acpi_integer digit;
+ u64 digit;
u32 i;
u32 j;
u32 k = 0;
@@ -531,10 +529,9 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
* (separated by commas or spaces)
*/
for (i = 0; i < obj_desc->buffer.length; i++) {
- new_buf += acpi_ex_convert_to_ascii((acpi_integer)
- obj_desc->buffer.
- pointer[i], base,
- new_buf, 1);
+ new_buf += acpi_ex_convert_to_ascii((u64) obj_desc->
+ buffer.pointer[i],
+ base, new_buf, 1);
*new_buf++ = separator; /* each separated by a comma or space */
}
diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c
index 02b25d233d99..0aa57d938698 100644
--- a/drivers/acpi/acpica/excreate.c
+++ b/drivers/acpi/acpica/excreate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index de3446372ddc..d39d438ba1e3 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index 1588a2d660e7..6c79fecbee42 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -130,7 +130,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
/* Call the region handler for the read */
status = acpi_ex_access_region(obj_desc, 0,
- ACPI_CAST_PTR(acpi_integer,
+ ACPI_CAST_PTR(u64,
buffer_desc->
buffer.pointer),
function);
@@ -141,7 +141,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
/*
* Allocate a buffer for the contents of the field.
*
- * If the field is larger than the size of an acpi_integer, create
+ * If the field is larger than the current integer width, create
* a BUFFER to hold it. Otherwise, use an INTEGER. This allows
* the use of arithmetic operators on the returned value if the
* field size is equal or smaller than an Integer.
@@ -306,8 +306,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
* same buffer)
*/
status = acpi_ex_access_region(obj_desc, 0,
- (acpi_integer *) buffer,
- function);
+ (u64 *) buffer, function);
acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
*result_desc = buffer_desc;
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index d7b3b418fb45..f68a216168be 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,11 +55,10 @@ ACPI_MODULE_NAME("exfldio")
static acpi_status
acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
u32 field_datum_byte_offset,
- acpi_integer * value, u32 read_write);
+ u64 *value, u32 read_write);
static u8
-acpi_ex_register_overflow(union acpi_operand_object *obj_desc,
- acpi_integer value);
+acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value);
static acpi_status
acpi_ex_setup_region(union acpi_operand_object *obj_desc,
@@ -212,7 +211,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
* field_datum_byte_offset - Byte offset of this datum within the
* parent field
* Value - Where to store value (must at least
- * the size of acpi_integer)
+ * 64 bits)
* Function - Read or Write flag plus other region-
* dependent flags
*
@@ -224,8 +223,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
acpi_status
acpi_ex_access_region(union acpi_operand_object *obj_desc,
- u32 field_datum_byte_offset,
- acpi_integer * value, u32 function)
+ u32 field_datum_byte_offset, u64 *value, u32 function)
{
acpi_status status;
union acpi_operand_object *rgn_desc;
@@ -317,8 +315,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
******************************************************************************/
static u8
-acpi_ex_register_overflow(union acpi_operand_object *obj_desc,
- acpi_integer value)
+acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value)
{
if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) {
@@ -329,7 +326,7 @@ acpi_ex_register_overflow(union acpi_operand_object *obj_desc,
return (FALSE);
}
- if (value >= ((acpi_integer) 1 << obj_desc->common_field.bit_length)) {
+ if (value >= ((u64) 1 << obj_desc->common_field.bit_length)) {
/*
* The Value is larger than the maximum value that can fit into
* the register.
@@ -362,11 +359,10 @@ acpi_ex_register_overflow(union acpi_operand_object *obj_desc,
static acpi_status
acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
- u32 field_datum_byte_offset,
- acpi_integer * value, u32 read_write)
+ u32 field_datum_byte_offset, u64 *value, u32 read_write)
{
acpi_status status;
- acpi_integer local_value;
+ u64 local_value;
ACPI_FUNCTION_TRACE_U32(ex_field_datum_io, field_datum_byte_offset);
@@ -439,8 +435,8 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
* the register
*/
if (acpi_ex_register_overflow(obj_desc->bank_field.bank_obj,
- (acpi_integer) obj_desc->
- bank_field.value)) {
+ (u64) obj_desc->bank_field.
+ value)) {
return_ACPI_STATUS(AE_AML_REGISTER_LIMIT);
}
@@ -481,8 +477,8 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
* the register
*/
if (acpi_ex_register_overflow(obj_desc->index_field.index_obj,
- (acpi_integer) obj_desc->
- index_field.value)) {
+ (u64) obj_desc->index_field.
+ value)) {
return_ACPI_STATUS(AE_AML_REGISTER_LIMIT);
}
@@ -512,7 +508,7 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
status =
acpi_ex_extract_from_field(obj_desc->index_field.
data_obj, value,
- sizeof(acpi_integer));
+ sizeof(u64));
} else {
/* Write the datum to the data_register */
@@ -523,7 +519,7 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
status =
acpi_ex_insert_into_field(obj_desc->index_field.
data_obj, value,
- sizeof(acpi_integer));
+ sizeof(u64));
}
break;
@@ -571,13 +567,12 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
acpi_status
acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
- acpi_integer mask,
- acpi_integer field_value,
- u32 field_datum_byte_offset)
+ u64 mask,
+ u64 field_value, u32 field_datum_byte_offset)
{
acpi_status status = AE_OK;
- acpi_integer merged_value;
- acpi_integer current_value;
+ u64 merged_value;
+ u64 current_value;
ACPI_FUNCTION_TRACE_U32(ex_write_with_update_rule, mask);
@@ -587,7 +582,7 @@ acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
/* If the mask is all ones, we don't need to worry about the update rule */
- if (mask != ACPI_INTEGER_MAX) {
+ if (mask != ACPI_UINT64_MAX) {
/* Decode the update rule */
@@ -678,8 +673,8 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
void *buffer, u32 buffer_length)
{
acpi_status status;
- acpi_integer raw_datum;
- acpi_integer merged_datum;
+ u64 raw_datum;
+ u64 merged_datum;
u32 field_offset = 0;
u32 buffer_offset = 0;
u32 buffer_tail_bits;
@@ -804,10 +799,10 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
void *buffer, u32 buffer_length)
{
acpi_status status;
- acpi_integer mask;
- acpi_integer width_mask;
- acpi_integer merged_datum;
- acpi_integer raw_datum = 0;
+ u64 mask;
+ u64 width_mask;
+ u64 merged_datum;
+ u64 raw_datum = 0;
u32 field_offset = 0;
u32 buffer_offset = 0;
u32 buffer_tail_bits;
@@ -855,7 +850,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
* shift operator
*/
if (obj_desc->common_field.access_bit_width == ACPI_INTEGER_BIT_SIZE) {
- width_mask = ACPI_INTEGER_MAX;
+ width_mask = ACPI_UINT64_MAX;
} else {
width_mask =
ACPI_MASK_BITS_ABOVE(obj_desc->common_field.
diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c
index 998eac329937..c5bb1eeed2df 100644
--- a/drivers/acpi/acpica/exmisc.c
+++ b/drivers/acpi/acpica/exmisc.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -409,8 +409,7 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0,
*
******************************************************************************/
-acpi_integer
-acpi_ex_do_math_op(u16 opcode, acpi_integer integer0, acpi_integer integer1)
+u64 acpi_ex_do_math_op(u16 opcode, u64 integer0, u64 integer1)
{
ACPI_FUNCTION_ENTRY();
@@ -498,8 +497,7 @@ acpi_ex_do_math_op(u16 opcode, acpi_integer integer0, acpi_integer integer1)
acpi_status
acpi_ex_do_logical_numeric_op(u16 opcode,
- acpi_integer integer0,
- acpi_integer integer1, u8 * logical_result)
+ u64 integer0, u64 integer1, u8 *logical_result)
{
acpi_status status = AE_OK;
u8 local_result = FALSE;
@@ -564,8 +562,8 @@ acpi_ex_do_logical_op(u16 opcode,
union acpi_operand_object *operand1, u8 * logical_result)
{
union acpi_operand_object *local_operand1 = operand1;
- acpi_integer integer0;
- acpi_integer integer1;
+ u64 integer0;
+ u64 integer1;
u32 length0;
u32 length1;
acpi_status status = AE_OK;
diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c
index 3c456bd575d0..7116bc86494d 100644
--- a/drivers/acpi/acpica/exmutex.c
+++ b/drivers/acpi/acpica/exmutex.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -375,8 +375,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
}
- /* Must have a valid thread ID */
-
+ /* Must have a valid thread. */
if (!walk_state->thread) {
ACPI_ERROR((AE_INFO,
"Cannot release Mutex [%4.4s], null thread info",
diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c
index ffdae122d94a..679f308c5a89 100644
--- a/drivers/acpi/acpica/exnames.c
+++ b/drivers/acpi/acpica/exnames.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c
index 752fe48b2d20..99adbab5acbf 100644
--- a/drivers/acpi/acpica/exoparg1.c
+++ b/drivers/acpi/acpica/exoparg1.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -261,8 +261,8 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
union acpi_operand_object *return_desc2 = NULL;
u32 temp32;
u32 i;
- acpi_integer power_of_ten;
- acpi_integer digit;
+ u64 power_of_ten;
+ u64 digit;
ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_1R,
acpi_ps_get_opcode_name(walk_state->opcode));
@@ -362,7 +362,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
/* Sum the digit into the result with the current power of 10 */
return_desc->integer.value +=
- (((acpi_integer) temp32) * power_of_ten);
+ (((u64) temp32) * power_of_ten);
/* Shift to next BCD digit */
@@ -392,7 +392,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
* remainder from above
*/
return_desc->integer.value |=
- (((acpi_integer) temp32) << ACPI_MUL_4(i));
+ (((u64) temp32) << ACPI_MUL_4(i));
}
/* Overflow if there is any data left in Digit */
@@ -439,7 +439,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
/* The object exists in the namespace, return TRUE */
- return_desc->integer.value = ACPI_INTEGER_MAX;
+ return_desc->integer.value = ACPI_UINT64_MAX;
goto cleanup;
default:
@@ -589,7 +589,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
union acpi_operand_object *return_desc = NULL;
acpi_status status = AE_OK;
u32 type;
- acpi_integer value;
+ u64 value;
ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_0T_1R,
acpi_ps_get_opcode_name(walk_state->opcode));
@@ -610,7 +610,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
* return_desc->Integer.Value is initially == 0 (FALSE) from above.
*/
if (!operand[0]->integer.value) {
- return_desc->integer.value = ACPI_INTEGER_MAX;
+ return_desc->integer.value = ACPI_UINT64_MAX;
}
break;
diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c
index 85d95c92dfd3..22841bbbe63c 100644
--- a/drivers/acpi/acpica/exoparg2.c
+++ b/drivers/acpi/acpica/exoparg2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -282,7 +282,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
{
union acpi_operand_object **operand = &walk_state->operands[0];
union acpi_operand_object *return_desc = NULL;
- acpi_integer index;
+ u64 index;
acpi_status status = AE_OK;
acpi_size length;
@@ -584,7 +584,7 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state)
* Default is FALSE (zero)
*/
if (logical_result) {
- return_desc->integer.value = ACPI_INTEGER_MAX;
+ return_desc->integer.value = ACPI_UINT64_MAX;
}
cleanup:
diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c
index 253f9e122584..8bb1012ef44e 100644
--- a/drivers/acpi/acpica/exoparg3.c
+++ b/drivers/acpi/acpica/exoparg3.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -148,7 +148,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state)
union acpi_operand_object *return_desc = NULL;
char *buffer = NULL;
acpi_status status = AE_OK;
- acpi_integer index;
+ u64 index;
acpi_size length;
ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_1T_1R,
diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c
index 295542e6bd51..f256b6a25f2e 100644
--- a/drivers/acpi/acpica/exoparg6.c
+++ b/drivers/acpi/acpica/exoparg6.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -218,7 +218,7 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state)
union acpi_operand_object **operand = &walk_state->operands[0];
union acpi_operand_object *return_desc = NULL;
acpi_status status = AE_OK;
- acpi_integer index;
+ u64 index;
union acpi_operand_object *this_element;
ACPI_FUNCTION_TRACE_STR(ex_opcode_6A_0T_1R,
@@ -253,9 +253,9 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state)
}
/* Create an integer for the return value */
- /* Default return value is ACPI_INTEGER_MAX if no match found */
+ /* Default return value is ACPI_UINT64_MAX if no match found */
- return_desc = acpi_ut_create_integer_object(ACPI_INTEGER_MAX);
+ return_desc = acpi_ut_create_integer_object(ACPI_UINT64_MAX);
if (!return_desc) {
status = AE_NO_MEMORY;
goto cleanup;
@@ -270,7 +270,7 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state)
*
* Upon finding a match, the loop will terminate via "break" at
* the bottom. If it terminates "normally", match_value will be
- * ACPI_INTEGER_MAX (Ones) (its initial value) indicating that no
+ * ACPI_UINT64_MAX (Ones) (its initial value) indicating that no
* match was found.
*/
for (; index < operand[0]->package.count; index++) {
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index 52fec07064f0..edf62bf5b266 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index 2bd83ac57c3a..486b2e5661b6 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,7 +70,7 @@ acpi_status
acpi_ex_system_memory_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context, void *region_context)
{
acpi_status status = AE_OK;
@@ -115,8 +115,7 @@ acpi_ex_system_memory_space_handler(u32 function,
* Hardware does not support non-aligned data transfers, we must verify
* the request.
*/
- (void)acpi_ut_short_divide((acpi_integer) address, length, NULL,
- &remainder);
+ (void)acpi_ut_short_divide((u64) address, length, NULL, &remainder);
if (remainder != 0) {
return_ACPI_STATUS(AE_AML_ALIGNMENT);
}
@@ -128,10 +127,9 @@ acpi_ex_system_memory_space_handler(u32 function,
* 2) Address beyond the current mapping?
*/
if ((address < mem_info->mapped_physical_address) ||
- (((acpi_integer) address + length) > ((acpi_integer)
- mem_info->
- mapped_physical_address +
- mem_info->mapped_length))) {
+ (((u64) address + length) > ((u64)
+ mem_info->mapped_physical_address +
+ mem_info->mapped_length))) {
/*
* The request cannot be resolved by the current memory mapping;
* Delete the existing mapping and create a new one.
@@ -193,8 +191,7 @@ acpi_ex_system_memory_space_handler(u32 function,
* access
*/
logical_addr_ptr = mem_info->mapped_logical_address +
- ((acpi_integer) address -
- (acpi_integer) mem_info->mapped_physical_address);
+ ((u64) address - (u64) mem_info->mapped_physical_address);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"System-Memory (width %d) R/W %d Address=%8.8X%8.8X\n",
@@ -215,19 +212,19 @@ acpi_ex_system_memory_space_handler(u32 function,
*value = 0;
switch (bit_width) {
case 8:
- *value = (acpi_integer) ACPI_GET8(logical_addr_ptr);
+ *value = (u64) ACPI_GET8(logical_addr_ptr);
break;
case 16:
- *value = (acpi_integer) ACPI_GET16(logical_addr_ptr);
+ *value = (u64) ACPI_GET16(logical_addr_ptr);
break;
case 32:
- *value = (acpi_integer) ACPI_GET32(logical_addr_ptr);
+ *value = (u64) ACPI_GET32(logical_addr_ptr);
break;
case 64:
- *value = (acpi_integer) ACPI_GET64(logical_addr_ptr);
+ *value = (u64) ACPI_GET64(logical_addr_ptr);
break;
default:
@@ -291,7 +288,7 @@ acpi_status
acpi_ex_system_io_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context, void *region_context)
{
acpi_status status = AE_OK;
@@ -350,7 +347,7 @@ acpi_status
acpi_ex_pci_config_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context, void *region_context)
{
acpi_status status = AE_OK;
@@ -425,7 +422,7 @@ acpi_status
acpi_ex_cmos_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context, void *region_context)
{
acpi_status status = AE_OK;
@@ -457,7 +454,7 @@ acpi_status
acpi_ex_pci_bar_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context, void *region_context)
{
acpi_status status = AE_OK;
@@ -489,7 +486,7 @@ acpi_status
acpi_ex_data_table_space_handler(u32 function,
acpi_physical_address address,
u32 bit_width,
- acpi_integer * value,
+ u64 *value,
void *handler_context, void *region_context)
{
ACPI_FUNCTION_TRACE(ex_data_table_space_handler);
diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c
index 607958ff467c..fdc1b27999ef 100644
--- a/drivers/acpi/acpica/exresnte.c
+++ b/drivers/acpi/acpica/exresnte.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c
index c93b54ce7f78..fdd6a7079b97 100644
--- a/drivers/acpi/acpica/exresolv.c
+++ b/drivers/acpi/acpica/exresolv.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c
index 5c729a9e9131..c5ecd615f145 100644
--- a/drivers/acpi/acpica/exresop.c
+++ b/drivers/acpi/acpica/exresop.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c
index 6efd07a4f779..702b9ecfd44b 100644
--- a/drivers/acpi/acpica/exstore.c
+++ b/drivers/acpi/acpica/exstore.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c
index 608e838d537e..d4af684620ca 100644
--- a/drivers/acpi/acpica/exstoren.c
+++ b/drivers/acpi/acpica/exstoren.c
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c
index 257706e7734f..e972b667b09b 100644
--- a/drivers/acpi/acpica/exstorob.c
+++ b/drivers/acpi/acpica/exstorob.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c
index 3d00b9357233..e11b6cb42a57 100644
--- a/drivers/acpi/acpica/exsystem.c
+++ b/drivers/acpi/acpica/exsystem.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -193,7 +193,7 @@ acpi_status acpi_ex_system_do_stall(u32 how_long)
*
******************************************************************************/
-acpi_status acpi_ex_system_do_suspend(acpi_integer how_long)
+acpi_status acpi_ex_system_do_suspend(u64 how_long)
{
ACPI_FUNCTION_ENTRY();
diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c
index 7d41f99f7052..74c24d517f81 100644
--- a/drivers/acpi/acpica/exutils.c
+++ b/drivers/acpi/acpica/exutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -67,7 +67,7 @@
ACPI_MODULE_NAME("exutils")
/* Local prototypes */
-static u32 acpi_ex_digits_needed(acpi_integer value, u32 base);
+static u32 acpi_ex_digits_needed(u64 value, u32 base);
#ifndef ACPI_NO_METHOD_EXECUTION
/*******************************************************************************
@@ -230,7 +230,7 @@ void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc)
* We are running a method that exists in a 32-bit ACPI table.
* Truncate the value to 32 bits by zeroing out the upper 32-bit field
*/
- obj_desc->integer.value &= (acpi_integer) ACPI_UINT32_MAX;
+ obj_desc->integer.value &= (u64) ACPI_UINT32_MAX;
}
}
@@ -327,14 +327,14 @@ void acpi_ex_release_global_lock(u32 field_flags)
*
******************************************************************************/
-static u32 acpi_ex_digits_needed(acpi_integer value, u32 base)
+static u32 acpi_ex_digits_needed(u64 value, u32 base)
{
u32 num_digits;
- acpi_integer current_value;
+ u64 current_value;
ACPI_FUNCTION_TRACE(ex_digits_needed);
- /* acpi_integer is unsigned, so we don't worry about a '-' prefix */
+ /* u64 is unsigned, so we don't worry about a '-' prefix */
if (value == 0) {
return_UINT32(1);
@@ -370,7 +370,7 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base)
*
******************************************************************************/
-void acpi_ex_eisa_id_to_string(char *out_string, acpi_integer compressed_id)
+void acpi_ex_eisa_id_to_string(char *out_string, u64 compressed_id)
{
u32 swapped_id;
@@ -394,10 +394,10 @@ void acpi_ex_eisa_id_to_string(char *out_string, acpi_integer compressed_id)
(char)(0x40 + (((unsigned long)swapped_id >> 26) & 0x1F));
out_string[1] = (char)(0x40 + ((swapped_id >> 21) & 0x1F));
out_string[2] = (char)(0x40 + ((swapped_id >> 16) & 0x1F));
- out_string[3] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 12);
- out_string[4] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 8);
- out_string[5] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 4);
- out_string[6] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 0);
+ out_string[3] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 12);
+ out_string[4] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 8);
+ out_string[5] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 4);
+ out_string[6] = acpi_ut_hex_to_ascii_char((u64) swapped_id, 0);
out_string[7] = 0;
}
@@ -418,7 +418,7 @@ void acpi_ex_eisa_id_to_string(char *out_string, acpi_integer compressed_id)
*
******************************************************************************/
-void acpi_ex_integer_to_string(char *out_string, acpi_integer value)
+void acpi_ex_integer_to_string(char *out_string, u64 value)
{
u32 count;
u32 digits_needed;
diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c
index 9af361a191e7..679a112a7d26 100644
--- a/drivers/acpi/acpica/hwacpi.c
+++ b/drivers/acpi/acpica/hwacpi.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index c28c41b3180b..bd72319a38f0 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -224,7 +224,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
status = acpi_hw_read(&in_byte, &gpe_register_info->status_address);
if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ return (status);
}
if (register_bit & in_byte) {
@@ -234,9 +234,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
/* Set return value */
(*event_status) = local_event_status;
-
- unlock_and_exit:
- return (status);
+ return (AE_OK);
}
/******************************************************************************
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index 15c9ed2be853..ec7fc227b33f 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -7,7 +7,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index cc22f9a585b0..5e6d4dbb8024 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c
index 6b282e85d039..1ef8e0bb250b 100644
--- a/drivers/acpi/acpica/hwtimer.c
+++ b/drivers/acpi/acpica/hwtimer.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -140,7 +140,7 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed)
{
acpi_status status;
u32 delta_ticks;
- acpi_integer quotient;
+ u64 quotient;
ACPI_FUNCTION_TRACE(acpi_get_timer_duration);
diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c
index ec33f270c5b7..e26c17d4b716 100644
--- a/drivers/acpi/acpica/hwvalid.c
+++ b/drivers/acpi/acpica/hwvalid.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2009, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c
index 647c7b6e6756..50cc3be77724 100644
--- a/drivers/acpi/acpica/hwxface.c
+++ b/drivers/acpi/acpica/hwxface.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c
index d622ba770000..aa2b80132d0a 100644
--- a/drivers/acpi/acpica/nsaccess.c
+++ b/drivers/acpi/acpica/nsaccess.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c
index 8a58a1b85aa0..982269c1fa48 100644
--- a/drivers/acpi/acpica/nsalloc.c
+++ b/drivers/acpi/acpica/nsalloc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c
index e37836e27e29..0689d36638d9 100644
--- a/drivers/acpi/acpica/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c
index 36be7f0e97ec..d2a97921e249 100644
--- a/drivers/acpi/acpica/nsdumpdv.c
+++ b/drivers/acpi/acpica/nsdumpdv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c
index af9fe9103734..f52829cc294b 100644
--- a/drivers/acpi/acpica/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index 4f8abac231d2..9bd6f050f299 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c
index a7234e60e985..df18be94fefe 100644
--- a/drivers/acpi/acpica/nsload.c
+++ b/drivers/acpi/acpica/nsload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c
index 8f9a4875ce26..959372451635 100644
--- a/drivers/acpi/acpica/nsnames.c
+++ b/drivers/acpi/acpica/nsnames.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c
index 60f3af08d28c..41a9213dd5af 100644
--- a/drivers/acpi/acpica/nsobject.c
+++ b/drivers/acpi/acpica/nsobject.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c
index 662a4bd5b621..27cda52c76bc 100644
--- a/drivers/acpi/acpica/nsparse.c
+++ b/drivers/acpi/acpica/nsparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index d34fa59548f7..7096bcda0c72 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -231,6 +231,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
* Note: Package may have been newly created by call above.
*/
if ((*return_object_ptr)->common.type == ACPI_TYPE_PACKAGE) {
+ data->parent_package = *return_object_ptr;
status = acpi_ns_check_package(data, return_object_ptr);
if (ACPI_FAILURE(status)) {
goto exit;
@@ -710,6 +711,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
for (i = 0; i < count; i++) {
sub_package = *elements;
sub_elements = sub_package->package.elements;
+ data->parent_package = sub_package;
/* Each sub-object must be of type Package */
@@ -721,6 +723,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
/* Examine the different types of expected sub-packages */
+ data->parent_package = sub_package;
switch (package->ret_info.type) {
case ACPI_PTYPE2:
case ACPI_PTYPE2_PKG_COUNT:
@@ -800,7 +803,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
/*
* First element is the (Integer) count of elements, including
- * the count field.
+ * the count field (the ACPI name is num_elements)
*/
status = acpi_ns_check_object_type(data, sub_elements,
ACPI_RTYPE_INTEGER,
@@ -822,6 +825,16 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
expected_count = package->ret_info.count1;
goto package_too_small;
}
+ if (expected_count == 0) {
+ /*
+ * Either the num_entries element was originally zero or it was
+ * a NULL element and repaired to an Integer of value zero.
+ * In either case, repair it by setting num_entries to be the
+ * actual size of the subpackage.
+ */
+ expected_count = sub_package->package.count;
+ (*sub_elements)->integer.value = expected_count;
+ }
/* Check the type of each sub-package element */
@@ -945,10 +958,18 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
char type_buffer[48]; /* Room for 5 types */
/*
- * If we get a NULL return_object here, it is a NULL package element,
- * and this is always an error.
+ * If we get a NULL return_object here, it is a NULL package element.
+ * Since all extraneous NULL package elements were removed earlier by a
+ * call to acpi_ns_remove_null_elements, this is an unexpected NULL element.
+ * We will attempt to repair it.
*/
if (!return_object) {
+ status = acpi_ns_repair_null_element(data, expected_btypes,
+ package_index,
+ return_object_ptr);
+ if (ACPI_SUCCESS(status)) {
+ return (AE_OK); /* Repair was successful */
+ }
goto type_error_exit;
}
@@ -1000,27 +1021,25 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
/* Is the object one of the expected types? */
- if (!(return_btype & expected_btypes)) {
+ if (return_btype & expected_btypes) {
- /* Type mismatch -- attempt repair of the returned object */
+ /* For reference objects, check that the reference type is correct */
- status = acpi_ns_repair_object(data, expected_btypes,
- package_index,
- return_object_ptr);
- if (ACPI_SUCCESS(status)) {
- return (AE_OK); /* Repair was successful */
+ if (return_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) {
+ status = acpi_ns_check_reference(data, return_object);
}
- goto type_error_exit;
+
+ return (status);
}
- /* For reference objects, check that the reference type is correct */
+ /* Type mismatch -- attempt repair of the returned object */
- if (return_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) {
- status = acpi_ns_check_reference(data, return_object);
+ status = acpi_ns_repair_object(data, expected_btypes,
+ package_index, return_object_ptr);
+ if (ACPI_SUCCESS(status)) {
+ return (AE_OK); /* Repair was successful */
}
- return (status);
-
type_error_exit:
/* Create a string with all expected types for this predefined object */
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
index 4fd1bdb056b2..d4be37751be4 100644
--- a/drivers/acpi/acpica/nsrepair.c
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2009, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,7 @@
#include "accommon.h"
#include "acnamesp.h"
#include "acinterp.h"
+#include "acpredef.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsrepair")
@@ -71,6 +72,12 @@ ACPI_MODULE_NAME("nsrepair")
* Buffer -> Package of Integers
* Package -> Package of one Package
*
+ * Additional possible repairs:
+ *
+ * Optional/unnecessary NULL package elements removed
+ * Required package elements that are NULL replaced by Integer/String/Buffer
+ * Incorrect standalone package wrapped with required outer package
+ *
******************************************************************************/
/* Local prototypes */
static acpi_status
@@ -506,6 +513,172 @@ acpi_ns_convert_to_package(union acpi_operand_object *original_object,
/*******************************************************************************
*
+ * FUNCTION: acpi_ns_repair_null_element
+ *
+ * PARAMETERS: Data - Pointer to validation data structure
+ * expected_btypes - Object types expected
+ * package_index - Index of object within parent package (if
+ * applicable - ACPI_NOT_PACKAGE_ELEMENT
+ * otherwise)
+ * return_object_ptr - Pointer to the object returned from the
+ * evaluation of a method or object
+ *
+ * RETURN: Status. AE_OK if repair was successful.
+ *
+ * DESCRIPTION: Attempt to repair a NULL element of a returned Package object.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_repair_null_element(struct acpi_predefined_data *data,
+ u32 expected_btypes,
+ u32 package_index,
+ union acpi_operand_object **return_object_ptr)
+{
+ union acpi_operand_object *return_object = *return_object_ptr;
+ union acpi_operand_object *new_object;
+
+ ACPI_FUNCTION_NAME(ns_repair_null_element);
+
+ /* No repair needed if return object is non-NULL */
+
+ if (return_object) {
+ return (AE_OK);
+ }
+
+ /*
+ * Attempt to repair a NULL element of a Package object. This applies to
+ * predefined names that return a fixed-length package and each element
+ * is required. It does not apply to variable-length packages where NULL
+ * elements are allowed, especially at the end of the package.
+ */
+ if (expected_btypes & ACPI_RTYPE_INTEGER) {
+
+ /* Need an Integer - create a zero-value integer */
+
+ new_object = acpi_ut_create_integer_object(0);
+ } else if (expected_btypes & ACPI_RTYPE_STRING) {
+
+ /* Need a String - create a NULL string */
+
+ new_object = acpi_ut_create_string_object(0);
+ } else if (expected_btypes & ACPI_RTYPE_BUFFER) {
+
+ /* Need a Buffer - create a zero-length buffer */
+
+ new_object = acpi_ut_create_buffer_object(0);
+ } else {
+ /* Error for all other expected types */
+
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Set the reference count according to the parent Package object */
+
+ new_object->common.reference_count =
+ data->parent_package->common.reference_count;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
+ "%s: Converted NULL package element to expected %s at index %u\n",
+ data->pathname,
+ acpi_ut_get_object_type_name(new_object),
+ package_index));
+
+ *return_object_ptr = new_object;
+ data->flags |= ACPI_OBJECT_REPAIRED;
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ns_remove_null_elements
+ *
+ * PARAMETERS: Data - Pointer to validation data structure
+ * package_type - An acpi_return_package_types value
+ * obj_desc - A Package object
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Remove all NULL package elements from packages that contain
+ * a variable number of sub-packages. For these types of
+ * packages, NULL elements can be safely removed.
+ *
+ *****************************************************************************/
+
+void
+acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
+ u8 package_type,
+ union acpi_operand_object *obj_desc)
+{
+ union acpi_operand_object **source;
+ union acpi_operand_object **dest;
+ u32 count;
+ u32 new_count;
+ u32 i;
+
+ ACPI_FUNCTION_NAME(ns_remove_null_elements);
+
+ /*
+ * PTYPE1 packages contain no subpackages.
+ * PTYPE2 packages contain a variable number of sub-packages. We can
+ * safely remove all NULL elements from the PTYPE2 packages.
+ */
+ switch (package_type) {
+ case ACPI_PTYPE1_FIXED:
+ case ACPI_PTYPE1_VAR:
+ case ACPI_PTYPE1_OPTION:
+ return;
+
+ case ACPI_PTYPE2:
+ case ACPI_PTYPE2_COUNT:
+ case ACPI_PTYPE2_PKG_COUNT:
+ case ACPI_PTYPE2_FIXED:
+ case ACPI_PTYPE2_MIN:
+ case ACPI_PTYPE2_REV_FIXED:
+ break;
+
+ default:
+ return;
+ }
+
+ count = obj_desc->package.count;
+ new_count = count;
+
+ source = obj_desc->package.elements;
+ dest = source;
+
+ /* Examine all elements of the package object, remove nulls */
+
+ for (i = 0; i < count; i++) {
+ if (!*source) {
+ new_count--;
+ } else {
+ *dest = *source;
+ dest++;
+ }
+ source++;
+ }
+
+ /* Update parent package if any null elements were removed */
+
+ if (new_count < count) {
+ ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
+ "%s: Found and removed %u NULL elements\n",
+ data->pathname, (count - new_count)));
+
+ /* NULL terminate list and update the package count */
+
+ *dest = NULL;
+ obj_desc->package.count = new_count;
+ }
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ns_repair_package_list
*
* PARAMETERS: Data - Pointer to validation data structure
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index f13691c1cca5..61bd0f6755d2 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2009, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,6 @@
#include <acpi/acpi.h>
#include "accommon.h"
#include "acnamesp.h"
-#include "acpredef.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsrepair2")
@@ -93,7 +92,7 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
u32 sort_index,
u8 sort_direction, char *sort_key_name);
-static acpi_status
+static void
acpi_ns_sort_list(union acpi_operand_object **elements,
u32 count, u32 index, u8 sort_direction);
@@ -443,7 +442,6 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
union acpi_operand_object *obj_desc;
u32 i;
u32 previous_value;
- acpi_status status;
ACPI_FUNCTION_NAME(ns_check_sorted_list);
@@ -494,19 +492,15 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
/*
* The list must be sorted in the specified order. If we detect a
- * discrepancy, issue a warning and sort the entire list
+ * discrepancy, sort the entire list.
*/
if (((sort_direction == ACPI_SORT_ASCENDING) &&
(obj_desc->integer.value < previous_value)) ||
((sort_direction == ACPI_SORT_DESCENDING) &&
(obj_desc->integer.value > previous_value))) {
- status =
- acpi_ns_sort_list(return_object->package.elements,
- outer_element_count, sort_index,
- sort_direction);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
+ acpi_ns_sort_list(return_object->package.elements,
+ outer_element_count, sort_index,
+ sort_direction);
data->flags |= ACPI_OBJECT_REPAIRED;
@@ -525,89 +519,6 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
/******************************************************************************
*
- * FUNCTION: acpi_ns_remove_null_elements
- *
- * PARAMETERS: Data - Pointer to validation data structure
- * package_type - An acpi_return_package_types value
- * obj_desc - A Package object
- *
- * RETURN: None.
- *
- * DESCRIPTION: Remove all NULL package elements from packages that contain
- * a variable number of sub-packages.
- *
- *****************************************************************************/
-
-void
-acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
- u8 package_type,
- union acpi_operand_object *obj_desc)
-{
- union acpi_operand_object **source;
- union acpi_operand_object **dest;
- u32 count;
- u32 new_count;
- u32 i;
-
- ACPI_FUNCTION_NAME(ns_remove_null_elements);
-
- /*
- * PTYPE1 packages contain no subpackages.
- * PTYPE2 packages contain a variable number of sub-packages. We can
- * safely remove all NULL elements from the PTYPE2 packages.
- */
- switch (package_type) {
- case ACPI_PTYPE1_FIXED:
- case ACPI_PTYPE1_VAR:
- case ACPI_PTYPE1_OPTION:
- return;
-
- case ACPI_PTYPE2:
- case ACPI_PTYPE2_COUNT:
- case ACPI_PTYPE2_PKG_COUNT:
- case ACPI_PTYPE2_FIXED:
- case ACPI_PTYPE2_MIN:
- case ACPI_PTYPE2_REV_FIXED:
- break;
-
- default:
- return;
- }
-
- count = obj_desc->package.count;
- new_count = count;
-
- source = obj_desc->package.elements;
- dest = source;
-
- /* Examine all elements of the package object, remove nulls */
-
- for (i = 0; i < count; i++) {
- if (!*source) {
- new_count--;
- } else {
- *dest = *source;
- dest++;
- }
- source++;
- }
-
- /* Update parent package if any null elements were removed */
-
- if (new_count < count) {
- ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
- "%s: Found and removed %u NULL elements\n",
- data->pathname, (count - new_count)));
-
- /* NULL terminate list and update the package count */
-
- *dest = NULL;
- obj_desc->package.count = new_count;
- }
-}
-
-/******************************************************************************
- *
* FUNCTION: acpi_ns_sort_list
*
* PARAMETERS: Elements - Package object element list
@@ -615,15 +526,16 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
* Index - Sort by which package element
* sort_direction - Ascending or Descending sort
*
- * RETURN: Status
+ * RETURN: None
*
* DESCRIPTION: Sort the objects that are in a package element list.
*
- * NOTE: Assumes that all NULL elements have been removed from the package.
+ * NOTE: Assumes that all NULL elements have been removed from the package,
+ * and that all elements have been verified to be of type Integer.
*
*****************************************************************************/
-static acpi_status
+static void
acpi_ns_sort_list(union acpi_operand_object **elements,
u32 count, u32 index, u8 sort_direction)
{
@@ -652,6 +564,4 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
}
}
}
-
- return (AE_OK);
}
diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c
index 7e865639a928..08f8b3f5ccaa 100644
--- a/drivers/acpi/acpica/nssearch.c
+++ b/drivers/acpi/acpica/nssearch.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index 47d91e668a1b..24d05a87a2a3 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c
index d7e6b52b4482..00e79fb26029 100644
--- a/drivers/acpi/acpica/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index f0c0892bc7e5..ebef8a7fd707 100644
--- a/drivers/acpi/acpica/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -562,25 +562,20 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
return (AE_BAD_PARAMETER);
}
- /* Run _STA to determine if device is present */
-
- status = acpi_ut_execute_STA(node, &flags);
- if (ACPI_FAILURE(status)) {
- return (AE_CTRL_DEPTH);
- }
-
- if (!(flags & ACPI_STA_DEVICE_PRESENT) &&
- !(flags & ACPI_STA_DEVICE_FUNCTIONING)) {
- /*
- * Don't examine the children of the device only when the
- * device is neither present nor functional. See ACPI spec,
- * description of _STA for more information.
- */
- return (AE_CTRL_DEPTH);
- }
-
- /* Filter based on device HID & CID */
-
+ /*
+ * First, filter based on the device HID and CID.
+ *
+ * 01/2010: For this case where a specific HID is requested, we don't
+ * want to run _STA until we have an actual HID match. Thus, we will
+ * not unnecessarily execute _STA on devices for which the caller
+ * doesn't care about. Previously, _STA was executed unconditionally
+ * on all devices found here.
+ *
+ * A side-effect of this change is that now we will continue to search
+ * for a matching HID even under device trees where the parent device
+ * would have returned a _STA that indicates it is not present or
+ * not functioning (thus aborting the search on that branch).
+ */
if (info->hid != NULL) {
status = acpi_ut_execute_HID(node, &hid);
if (status == AE_NOT_FOUND) {
@@ -620,6 +615,25 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
}
}
+ /* Run _STA to determine if device is present */
+
+ status = acpi_ut_execute_STA(node, &flags);
+ if (ACPI_FAILURE(status)) {
+ return (AE_CTRL_DEPTH);
+ }
+
+ if (!(flags & ACPI_STA_DEVICE_PRESENT) &&
+ !(flags & ACPI_STA_DEVICE_FUNCTIONING)) {
+ /*
+ * Don't examine the children of the device only when the
+ * device is neither present nor functional. See ACPI spec,
+ * description of _STA for more information.
+ */
+ return (AE_CTRL_DEPTH);
+ }
+
+ /* We have a valid device, invoke the user function */
+
status = info->user_function(obj_handle, nesting_level, info->context,
return_value);
return (status);
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c
index e611dd961b20..b01e45a415e3 100644
--- a/drivers/acpi/acpica/nsxfname.c
+++ b/drivers/acpi/acpica/nsxfname.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c
index 0cc6ba01a495..eafef24ea448 100644
--- a/drivers/acpi/acpica/nsxfobj.c
+++ b/drivers/acpi/acpica/nsxfobj.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index b161f3544b51..00493e108a01 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -403,7 +403,7 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state,
/* Get 1 byte from the AML stream */
opcode = AML_BYTE_OP;
- arg->common.value.integer = (acpi_integer) * aml;
+ arg->common.value.integer = (u64) *aml;
length = 1;
break;
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c
index 0988e4a8901d..59aabaeab1d3 100644
--- a/drivers/acpi/acpica/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c
index 3bc3a60194d6..2b0c3be2b1b8 100644
--- a/drivers/acpi/acpica/psopcode.c
+++ b/drivers/acpi/acpica/psopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c
index 4df8f139026c..8d81542194d4 100644
--- a/drivers/acpi/acpica/psparse.c
+++ b/drivers/acpi/acpica/psparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c
index 2feca5ca9581..40e2b279ea12 100644
--- a/drivers/acpi/acpica/psscope.c
+++ b/drivers/acpi/acpica/psscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c
index 4d3389118ec3..d4b970c3630b 100644
--- a/drivers/acpi/acpica/pstree.c
+++ b/drivers/acpi/acpica/pstree.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c
index e636e078ad3d..fe29eee5adb1 100644
--- a/drivers/acpi/acpica/psutils.c
+++ b/drivers/acpi/acpica/psutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c
index 78b8b791f2ae..8abb9629443d 100644
--- a/drivers/acpi/acpica/pswalk.c
+++ b/drivers/acpi/acpica/pswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c
index d0c1b91eb8ca..6064dd4e94c2 100644
--- a/drivers/acpi/acpica/psxface.c
+++ b/drivers/acpi/acpica/psxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c
index 1e437bfd8db5..226c806ae986 100644
--- a/drivers/acpi/acpica/rsaddr.c
+++ b/drivers/acpi/acpica/rsaddr.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c
index 3c4dcc3d1069..d6ebf7ec622d 100644
--- a/drivers/acpi/acpica/rscalc.c
+++ b/drivers/acpi/acpica/rscalc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c
index a3c23d686d5f..f2ee3b548609 100644
--- a/drivers/acpi/acpica/rscreate.c
+++ b/drivers/acpi/acpica/rscreate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -182,7 +182,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
/*
* Loop through the ACPI_INTERNAL_OBJECTS - Each object should be a
- * package that in turn contains an acpi_integer Address, a u8 Pin,
+ * package that in turn contains an u64 Address, a u8 Pin,
* a Name, and a u8 source_index.
*/
top_object_list = package_object->package.elements;
diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c
index 3f0ca5a12d34..f859b0386fe4 100644
--- a/drivers/acpi/acpica/rsdump.c
+++ b/drivers/acpi/acpica/rsdump.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c
index 77b25fdb459c..1fd868b964fd 100644
--- a/drivers/acpi/acpica/rsinfo.c
+++ b/drivers/acpi/acpica/rsinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c
index 35a49aa95609..33bff17c0bbc 100644
--- a/drivers/acpi/acpica/rsio.c
+++ b/drivers/acpi/acpica/rsio.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c
index 2e0256983aa6..545da40d7fa7 100644
--- a/drivers/acpi/acpica/rsirq.c
+++ b/drivers/acpi/acpica/rsirq.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c
index 1b1dbc69f087..fd057c72d252 100644
--- a/drivers/acpi/acpica/rslist.c
+++ b/drivers/acpi/acpica/rslist.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c
index ddc76cebdc92..887b8ba8c432 100644
--- a/drivers/acpi/acpica/rsmemory.c
+++ b/drivers/acpi/acpica/rsmemory.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c
index 5bc49a553284..07de352fa443 100644
--- a/drivers/acpi/acpica/rsmisc.c
+++ b/drivers/acpi/acpica/rsmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c
index bc03d5966829..22cfcfbd9fff 100644
--- a/drivers/acpi/acpica/rsutils.c
+++ b/drivers/acpi/acpica/rsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c
index f27feb4772f6..9f6a6e7e1c8e 100644
--- a/drivers/acpi/acpica/rsxface.c
+++ b/drivers/acpi/acpica/rsxface.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index c016335fb759..f43fbe0fc3fc 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c
index 1054dfd49207..e252180ce61c 100644
--- a/drivers/acpi/acpica/tbfind.c
+++ b/drivers/acpi/acpica/tbfind.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c
index 63e82329a9e8..7ec02b0f69e0 100644
--- a/drivers/acpi/acpica/tbinstal.c
+++ b/drivers/acpi/acpica/tbinstal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 1f15497f00d1..02723a9fb10c 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c
index a88f02bd6c94..5217a6159a31 100644
--- a/drivers/acpi/acpica/tbxface.c
+++ b/drivers/acpi/acpica/tbxface.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c
index 85ea834199e2..dda6e8c497d3 100644
--- a/drivers/acpi/acpica/tbxfroot.c
+++ b/drivers/acpi/acpica/tbxfroot.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c
index 7580f6b3069e..3d706b8fd449 100644
--- a/drivers/acpi/acpica/utalloc.c
+++ b/drivers/acpi/acpica/utalloc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c
index f857c5efb79f..97ec3621e71d 100644
--- a/drivers/acpi/acpica/utcopy.c
+++ b/drivers/acpi/acpica/utcopy.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c
index 527d729f6815..983510640059 100644
--- a/drivers/acpi/acpica/utdebug.c
+++ b/drivers/acpi/acpica/utdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -460,8 +460,7 @@ ACPI_EXPORT_SYMBOL(acpi_ut_status_exit)
void
acpi_ut_value_exit(u32 line_number,
const char *function_name,
- const char *module_name,
- u32 component_id, acpi_integer value)
+ const char *module_name, u32 component_id, u64 value)
{
acpi_debug_print(ACPI_LV_FUNCTIONS,
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index 96e26e70c63d..16b51c69606a 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c
index 5d54e36ab453..7f5e734ce7f7 100644
--- a/drivers/acpi/acpica/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -348,7 +348,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
acpi_status
acpi_ut_evaluate_numeric_object(char *object_name,
struct acpi_namespace_node *device_node,
- acpi_integer *value)
+ u64 *value)
{
union acpi_operand_object *obj_desc;
acpi_status status;
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index 3f2c68f4e959..eda3e656c4af 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -234,7 +234,7 @@ static const char acpi_gbl_hex_to_ascii[] = {
*
******************************************************************************/
-char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position)
+char acpi_ut_hex_to_ascii_char(u64 integer, u32 position)
{
return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]);
diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c
index 52eaae404554..1397fadd0d4b 100644
--- a/drivers/acpi/acpica/utids.c
+++ b/drivers/acpi/acpica/utids.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2009, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index 9d0919ebf7b0..a39c93dac719 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c
index 25e03120686d..b081cd46a15f 100644
--- a/drivers/acpi/acpica/utlock.c
+++ b/drivers/acpi/acpica/utlock.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2009, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c
index c9f682d640ef..35059a14eb72 100644
--- a/drivers/acpi/acpica/utmath.c
+++ b/drivers/acpi/acpica/utmath.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,9 +70,8 @@ ACPI_MODULE_NAME("utmath")
*
******************************************************************************/
acpi_status
-acpi_ut_short_divide(acpi_integer dividend,
- u32 divisor,
- acpi_integer * out_quotient, u32 * out_remainder)
+acpi_ut_short_divide(u64 dividend,
+ u32 divisor, u64 *out_quotient, u32 *out_remainder)
{
union uint64_overlay dividend_ovl;
union uint64_overlay quotient;
@@ -126,9 +125,8 @@ acpi_ut_short_divide(acpi_integer dividend,
******************************************************************************/
acpi_status
-acpi_ut_divide(acpi_integer in_dividend,
- acpi_integer in_divisor,
- acpi_integer * out_quotient, acpi_integer * out_remainder)
+acpi_ut_divide(u64 in_dividend,
+ u64 in_divisor, u64 *out_quotient, u64 *out_remainder)
{
union uint64_overlay dividend;
union uint64_overlay divisor;
@@ -199,9 +197,8 @@ acpi_ut_divide(acpi_integer in_dividend,
* The 64-bit remainder must be generated.
*/
partial1 = quotient.part.lo * divisor.part.hi;
- partial2.full =
- (acpi_integer) quotient.part.lo * divisor.part.lo;
- partial3.full = (acpi_integer) partial2.part.hi + partial1;
+ partial2.full = (u64) quotient.part.lo * divisor.part.lo;
+ partial3.full = (u64) partial2.part.hi + partial1;
remainder.part.hi = partial3.part.lo;
remainder.part.lo = partial2.part.lo;
@@ -257,9 +254,8 @@ acpi_ut_divide(acpi_integer in_dividend,
*
******************************************************************************/
acpi_status
-acpi_ut_short_divide(acpi_integer in_dividend,
- u32 divisor,
- acpi_integer * out_quotient, u32 * out_remainder)
+acpi_ut_short_divide(u64 in_dividend,
+ u32 divisor, u64 *out_quotient, u32 *out_remainder)
{
ACPI_FUNCTION_TRACE(ut_short_divide);
@@ -284,9 +280,8 @@ acpi_ut_short_divide(acpi_integer in_dividend,
}
acpi_status
-acpi_ut_divide(acpi_integer in_dividend,
- acpi_integer in_divisor,
- acpi_integer * out_quotient, acpi_integer * out_remainder)
+acpi_ut_divide(u64 in_dividend,
+ u64 in_divisor, u64 *out_quotient, u64 *out_remainder)
{
ACPI_FUNCTION_TRACE(ut_divide);
diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c
index 6c6a5137b728..32982e2ac384 100644
--- a/drivers/acpi/acpica/utmisc.c
+++ b/drivers/acpi/acpica/utmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -724,13 +724,12 @@ acpi_name acpi_ut_repair_name(char *name)
*
******************************************************************************/
-acpi_status
-acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
+acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer)
{
u32 this_digit = 0;
- acpi_integer return_value = 0;
- acpi_integer quotient;
- acpi_integer dividend;
+ u64 return_value = 0;
+ u64 quotient;
+ u64 dividend;
u32 to_integer_op = (base == ACPI_ANY_BASE);
u32 mode32 = (acpi_gbl_integer_byte_width == 4);
u8 valid_digits = 0;
@@ -844,9 +843,8 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
/* Divide the digit into the correct position */
- (void)
- acpi_ut_short_divide((dividend - (acpi_integer) this_digit),
- base, &quotient, NULL);
+ (void)acpi_ut_short_divide((dividend - (u64) this_digit),
+ base, &quotient, NULL);
if (return_value > quotient) {
if (to_integer_op) {
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index 80bb65154117..55d014ed6d55 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -50,7 +50,7 @@ ACPI_MODULE_NAME("utmutex")
/* Local prototypes */
static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id);
-static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id);
+static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id);
/*******************************************************************************
*
@@ -114,7 +114,7 @@ void acpi_ut_mutex_terminate(void)
/* Delete each predefined mutex object */
for (i = 0; i < ACPI_NUM_MUTEX; i++) {
- (void)acpi_ut_delete_mutex(i);
+ acpi_ut_delete_mutex(i);
}
/* Delete the spinlocks */
@@ -146,10 +146,6 @@ static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id)
ACPI_FUNCTION_TRACE_U32(ut_create_mutex, mutex_id);
- if (mutex_id > ACPI_MAX_MUTEX) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
if (!acpi_gbl_mutex_info[mutex_id].mutex) {
status =
acpi_os_create_mutex(&acpi_gbl_mutex_info[mutex_id].mutex);
@@ -173,21 +169,15 @@ static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id)
*
******************************************************************************/
-static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id)
+static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id)
{
ACPI_FUNCTION_TRACE_U32(ut_delete_mutex, mutex_id);
- if (mutex_id > ACPI_MAX_MUTEX) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
acpi_os_delete_mutex(acpi_gbl_mutex_info[mutex_id].mutex);
acpi_gbl_mutex_info[mutex_id].mutex = NULL;
acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED;
-
- return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c
index 42e658b543f1..3356f0cb0745 100644
--- a/drivers/acpi/acpica/utobject.c
+++ b/drivers/acpi/acpica/utobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c
index 91b7c00236f4..7965919000b1 100644
--- a/drivers/acpi/acpica/utresrc.c
+++ b/drivers/acpi/acpica/utresrc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c
index 0440c958f5a4..d35d109b8da2 100644
--- a/drivers/acpi/acpica/utstate.c
+++ b/drivers/acpi/acpica/utstate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index b1f5f680bc78..db9d8ca57987 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2010, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 1ca0ea77115b..75f39f2c166d 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -362,8 +362,8 @@ static int extract_package(struct acpi_battery *battery,
strncpy(ptr, element->string.pointer, 32);
else if (element->type == ACPI_TYPE_INTEGER) {
strncpy(ptr, (u8 *)&element->integer.value,
- sizeof(acpi_integer));
- ptr[sizeof(acpi_integer)] = 0;
+ sizeof(u64));
+ ptr[sizeof(u64)] = 0;
} else
*ptr = 0; /* don't have value */
} else {
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index cf761b904e4a..b70cd3756142 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -190,16 +190,16 @@ int acpi_bus_get_power(acpi_handle handle, int *state)
* Get the device's power state either directly (via _PSC) or
* indirectly (via power resources).
*/
- if (device->power.flags.explicit_get) {
+ if (device->power.flags.power_resources) {
+ result = acpi_power_get_inferred_state(device);
+ if (result)
+ return result;
+ } else if (device->power.flags.explicit_get) {
status = acpi_evaluate_integer(device->handle, "_PSC",
NULL, &psc);
if (ACPI_FAILURE(status))
return -ENODEV;
device->power.state = (int)psc;
- } else if (device->power.flags.power_resources) {
- result = acpi_power_get_inferred_state(device);
- if (result)
- return result;
}
*state = device->power.state;
@@ -490,9 +490,14 @@ static void acpi_bus_osc_support(void)
capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
capbuf[OSC_SUPPORT_TYPE] = OSC_SB_PR3_SUPPORT; /* _PR3 is in use */
-#ifdef CONFIG_ACPI_PROCESSOR_AGGREGATOR
+#if defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR) ||\
+ defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR_MODULE)
capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PAD_SUPPORT;
#endif
+
+#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+ capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PPC_OST_SUPPORT;
+#endif
if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))
return;
if (ACPI_SUCCESS(acpi_run_osc(handle, &context)))
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 8a95e8329df7..f53fbe307c9d 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -422,11 +422,10 @@ static int acpi_button_add(struct acpi_device *device)
if (device->wakeup.flags.valid) {
/* Button's GPE is run-wake GPE */
- acpi_set_gpe_type(device->wakeup.gpe_device,
- device->wakeup.gpe_number,
- ACPI_GPE_TYPE_WAKE_RUN);
acpi_enable_gpe(device->wakeup.gpe_device,
- device->wakeup.gpe_number);
+ device->wakeup.gpe_number,
+ ACPI_GPE_TYPE_WAKE_RUN);
+ device->wakeup.run_wake_count++;
device->wakeup.state.enabled = 1;
}
@@ -446,6 +445,14 @@ static int acpi_button_remove(struct acpi_device *device, int type)
{
struct acpi_button *button = acpi_driver_data(device);
+ if (device->wakeup.flags.valid) {
+ acpi_disable_gpe(device->wakeup.gpe_device,
+ device->wakeup.gpe_number,
+ ACPI_GPE_TYPE_WAKE_RUN);
+ device->wakeup.run_wake_count--;
+ device->wakeup.state.enabled = 0;
+ }
+
acpi_button_remove_fs(device);
input_unregister_device(button->input);
kfree(button);
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index bbc2c1315c47..d9a85f1ddde6 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -605,7 +605,7 @@ register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops,
list_for_each_entry(dock_station, &dock_stations, sibling) {
/*
* An ATA bay can be in a dock and itself can be ejected
- * seperately, so there are two 'dock stations' which need the
+ * separately, so there are two 'dock stations' which need the
* ops
*/
dd = find_dock_dependent_device(dock_station, handle);
@@ -935,6 +935,7 @@ static int dock_add(acpi_handle handle)
struct platform_device *dd;
id = dock_station_count;
+ memset(&ds, 0, sizeof(ds));
dd = platform_device_register_data(NULL, "dock", id, &ds, sizeof(ds));
if (IS_ERR(dd))
return PTR_ERR(dd);
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index fd1801bdee66..1ac28c6a672e 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -76,8 +76,9 @@ enum ec_command {
enum {
EC_FLAGS_QUERY_PENDING, /* Query is pending */
EC_FLAGS_GPE_STORM, /* GPE storm detected */
- EC_FLAGS_HANDLERS_INSTALLED /* Handlers for GPE and
+ EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and
* OpReg are installed */
+ EC_FLAGS_FROZEN, /* Transactions are suspended */
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
@@ -201,14 +202,13 @@ unlock:
spin_unlock_irqrestore(&ec->curr_lock, flags);
}
-static void acpi_ec_gpe_query(void *ec_cxt);
+static int acpi_ec_sync_query(struct acpi_ec *ec);
-static int ec_check_sci(struct acpi_ec *ec, u8 state)
+static int ec_check_sci_sync(struct acpi_ec *ec, u8 state)
{
if (state & ACPI_EC_FLAG_SCI) {
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
- return acpi_os_execute(OSL_EC_BURST_HANDLER,
- acpi_ec_gpe_query, ec);
+ return acpi_ec_sync_query(ec);
}
return 0;
}
@@ -249,11 +249,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
{
unsigned long tmp;
int ret = 0;
- pr_debug(PREFIX "transaction start\n");
- /* disable GPE during transaction if storm is detected */
- if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
- acpi_disable_gpe(NULL, ec->gpe);
- }
if (EC_FLAGS_MSI)
udelay(ACPI_EC_MSI_UDELAY);
/* start transaction */
@@ -265,20 +260,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
spin_unlock_irqrestore(&ec->curr_lock, tmp);
ret = ec_poll(ec);
- pr_debug(PREFIX "transaction end\n");
spin_lock_irqsave(&ec->curr_lock, tmp);
ec->curr = NULL;
spin_unlock_irqrestore(&ec->curr_lock, tmp);
- if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
- /* check if we received SCI during transaction */
- ec_check_sci(ec, acpi_ec_read_status(ec));
- /* it is safe to enable GPE outside of transaction */
- acpi_enable_gpe(NULL, ec->gpe);
- } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
- pr_info(PREFIX "GPE storm detected, "
- "transactions will use polling mode\n");
- set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
- }
return ret;
}
@@ -308,6 +292,10 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
if (t->rdata)
memset(t->rdata, 0, t->rlen);
mutex_lock(&ec->lock);
+ if (test_bit(EC_FLAGS_FROZEN, &ec->flags)) {
+ status = -EINVAL;
+ goto unlock;
+ }
if (ec->global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status)) {
@@ -321,7 +309,34 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
status = -ETIME;
goto end;
}
+ pr_debug(PREFIX "transaction start\n");
+ /* disable GPE during transaction if storm is detected */
+ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+ /*
+ * It has to be disabled at the hardware level regardless of the
+ * GPE reference counting, so that it doesn't trigger.
+ */
+ acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
+ }
+
status = acpi_ec_transaction_unlocked(ec, t);
+
+ /* check if we received SCI during transaction */
+ ec_check_sci_sync(ec, acpi_ec_read_status(ec));
+ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+ msleep(1);
+ /*
+ * It is safe to enable the GPE outside of the transaction. Use
+ * acpi_set_gpe() for that, since we used it to disable the GPE
+ * above.
+ */
+ acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
+ } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
+ pr_info(PREFIX "GPE storm detected, "
+ "transactions will use polling mode\n");
+ set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
+ }
+ pr_debug(PREFIX "transaction end\n");
end:
if (ec->global_lock)
acpi_release_global_lock(glk);
@@ -443,7 +458,33 @@ int ec_transaction(u8 command,
EXPORT_SYMBOL(ec_transaction);
-static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
+void acpi_ec_suspend_transactions(void)
+{
+ struct acpi_ec *ec = first_ec;
+
+ if (!ec)
+ return;
+
+ mutex_lock(&ec->lock);
+ /* Prevent transactions from being carried out */
+ set_bit(EC_FLAGS_FROZEN, &ec->flags);
+ mutex_unlock(&ec->lock);
+}
+
+void acpi_ec_resume_transactions(void)
+{
+ struct acpi_ec *ec = first_ec;
+
+ if (!ec)
+ return;
+
+ mutex_lock(&ec->lock);
+ /* Allow transactions to be carried out again */
+ clear_bit(EC_FLAGS_FROZEN, &ec->flags);
+ mutex_unlock(&ec->lock);
+}
+
+static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
{
int result;
u8 d;
@@ -452,20 +493,16 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
.wlen = 0, .rlen = 1};
if (!ec || !data)
return -EINVAL;
-
/*
* Query the EC to find out which _Qxx method we need to evaluate.
* Note that successful completion of the query causes the ACPI_EC_SCI
* bit to be cleared (and thus clearing the interrupt source).
*/
-
- result = acpi_ec_transaction(ec, &t);
+ result = acpi_ec_transaction_unlocked(ec, &t);
if (result)
return result;
-
if (!d)
return -ENODATA;
-
*data = d;
return 0;
}
@@ -509,43 +546,79 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
-static void acpi_ec_gpe_query(void *ec_cxt)
+static void acpi_ec_run(void *cxt)
{
- struct acpi_ec *ec = ec_cxt;
- u8 value = 0;
- struct acpi_ec_query_handler *handler, copy;
-
- if (!ec || acpi_ec_query(ec, &value))
+ struct acpi_ec_query_handler *handler = cxt;
+ if (!handler)
return;
- mutex_lock(&ec->lock);
+ pr_debug(PREFIX "start query execution\n");
+ if (handler->func)
+ handler->func(handler->data);
+ else if (handler->handle)
+ acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
+ pr_debug(PREFIX "stop query execution\n");
+ kfree(handler);
+}
+
+static int acpi_ec_sync_query(struct acpi_ec *ec)
+{
+ u8 value = 0;
+ int status;
+ struct acpi_ec_query_handler *handler, *copy;
+ if ((status = acpi_ec_query_unlocked(ec, &value)))
+ return status;
list_for_each_entry(handler, &ec->list, node) {
if (value == handler->query_bit) {
/* have custom handler for this bit */
- memcpy(&copy, handler, sizeof(copy));
- mutex_unlock(&ec->lock);
- if (copy.func) {
- copy.func(copy.data);
- } else if (copy.handle) {
- acpi_evaluate_object(copy.handle, NULL, NULL, NULL);
- }
- return;
+ copy = kmalloc(sizeof(*handler), GFP_KERNEL);
+ if (!copy)
+ return -ENOMEM;
+ memcpy(copy, handler, sizeof(*copy));
+ pr_debug(PREFIX "push query execution (0x%2x) on queue\n", value);
+ return acpi_os_execute((copy->func) ?
+ OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
+ acpi_ec_run, copy);
}
}
+ return 0;
+}
+
+static void acpi_ec_gpe_query(void *ec_cxt)
+{
+ struct acpi_ec *ec = ec_cxt;
+ if (!ec)
+ return;
+ mutex_lock(&ec->lock);
+ acpi_ec_sync_query(ec);
mutex_unlock(&ec->lock);
}
+static void acpi_ec_gpe_query(void *ec_cxt);
+
+static int ec_check_sci(struct acpi_ec *ec, u8 state)
+{
+ if (state & ACPI_EC_FLAG_SCI) {
+ if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
+ pr_debug(PREFIX "push gpe query to the queue\n");
+ return acpi_os_execute(OSL_NOTIFY_HANDLER,
+ acpi_ec_gpe_query, ec);
+ }
+ }
+ return 0;
+}
+
static u32 acpi_ec_gpe_handler(void *data)
{
struct acpi_ec *ec = data;
- u8 status;
pr_debug(PREFIX "~~~> interrupt\n");
- status = acpi_ec_read_status(ec);
- advance_transaction(ec, status);
- if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0)
+ advance_transaction(ec, acpi_ec_read_status(ec));
+ if (ec_transaction_done(ec) &&
+ (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) {
wake_up(&ec->wait);
- ec_check_sci(ec, status);
+ ec_check_sci(ec, acpi_ec_read_status(ec));
+ }
return ACPI_INTERRUPT_HANDLED;
}
@@ -555,7 +628,7 @@ static u32 acpi_ec_gpe_handler(void *data)
static acpi_status
acpi_ec_space_handler(u32 function, acpi_physical_address address,
- u32 bits, acpi_integer *value,
+ u32 bits, u64 *value,
void *handler_context, void *region_context)
{
struct acpi_ec *ec = handler_context;
@@ -586,7 +659,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
++address;
if (function == ACPI_READ) {
result = acpi_ec_read(ec, address, &temp);
- (*value) |= ((acpi_integer)temp) << i;
+ (*value) |= ((u64)temp) << i;
} else {
temp = 0xff & ((*value) >> i);
result = acpi_ec_write(ec, address, temp);
@@ -754,8 +827,8 @@ static int ec_install_handlers(struct acpi_ec *ec)
&acpi_ec_gpe_handler, ec);
if (ACPI_FAILURE(status))
return -ENODEV;
- acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
- acpi_enable_gpe(NULL, ec->gpe);
+
+ acpi_enable_gpe(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
status = acpi_install_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler,
@@ -772,6 +845,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
} else {
acpi_remove_gpe_handler(NULL, ec->gpe,
&acpi_ec_gpe_handler);
+ acpi_disable_gpe(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
return -ENODEV;
}
}
@@ -782,6 +856,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
static void ec_remove_handlers(struct acpi_ec *ec)
{
+ acpi_disable_gpe(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
pr_err(PREFIX "failed to remove space handler\n");
@@ -1023,16 +1098,16 @@ error:
static int acpi_ec_suspend(struct acpi_device *device, pm_message_t state)
{
struct acpi_ec *ec = acpi_driver_data(device);
- /* Stop using GPE */
- acpi_disable_gpe(NULL, ec->gpe);
+ /* Stop using the GPE, but keep it reference counted. */
+ acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
return 0;
}
static int acpi_ec_resume(struct acpi_device *device)
{
struct acpi_ec *ec = acpi_driver_data(device);
- /* Enable use of GPE back */
- acpi_enable_gpe(NULL, ec->gpe);
+ /* Enable the GPE again, but don't reference count it once more. */
+ acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
return 0;
}
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 4c8fcff662cf..6d5b64b7d526 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -87,7 +87,7 @@ static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
/* Get device's handler per its address under its parent */
struct acpi_find_child {
acpi_handle handle;
- acpi_integer address;
+ u64 address;
};
static acpi_status
@@ -106,7 +106,7 @@ do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
-acpi_handle acpi_get_child(acpi_handle parent, acpi_integer address)
+acpi_handle acpi_get_child(acpi_handle parent, u64 address)
{
struct acpi_find_child find = { NULL, address };
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index cb28e0502acc..e28411367239 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -36,8 +36,6 @@ static inline int acpi_debug_init(void) { return 0; }
int acpi_power_init(void);
int acpi_device_sleep_wake(struct acpi_device *dev,
int enable, int sleep_state, int dev_state);
-int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state);
-int acpi_disable_wakeup_device_power(struct acpi_device *dev);
int acpi_power_get_inferred_state(struct acpi_device *device);
int acpi_power_transition(struct acpi_device *device, int state);
extern int acpi_power_nocheck;
@@ -51,6 +49,8 @@ void acpi_early_processor_set_pdc(void);
int acpi_ec_init(void);
int acpi_ec_ecdt_probe(void);
int acpi_boot_ec_enable(void);
+void acpi_ec_suspend_transactions(void);
+void acpi_ec_resume_transactions(void);
/*--------------------------------------------------------------------------
Suspend/Resume
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 7ad48dfc12db..b8725461d887 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -279,9 +279,9 @@ int __init acpi_numa_init(void)
/* SRAT: Static Resource Affinity Table */
if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY,
- acpi_parse_x2apic_affinity, NR_CPUS);
+ acpi_parse_x2apic_affinity, nr_cpu_ids);
acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
- acpi_parse_processor_affinity, NR_CPUS);
+ acpi_parse_processor_affinity, nr_cpu_ids);
ret = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
acpi_parse_memory_affinity,
NR_NODE_MEMBLKS);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 02e8464e480f..8e6d8665f0ae 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -436,7 +436,7 @@ acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)
* Running in interpreter thread context, safe to sleep
*/
-void acpi_os_sleep(acpi_integer ms)
+void acpi_os_sleep(u64 ms)
{
schedule_timeout_interruptible(msecs_to_jiffies(ms));
}
@@ -603,7 +603,7 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
acpi_status
acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
- acpi_integer value, u32 width)
+ u64 value, u32 width)
{
int result, size;
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
index a5a77b78a723..2ef04098cc1d 100644
--- a/drivers/acpi/pci_bind.c
+++ b/drivers/acpi/pci_bind.c
@@ -26,7 +26,9 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/pci-acpi.h>
#include <linux/acpi.h>
+#include <linux/pm_runtime.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -38,7 +40,13 @@ static int acpi_pci_unbind(struct acpi_device *device)
struct pci_dev *dev;
dev = acpi_get_pci_dev(device->handle);
- if (!dev || !dev->subordinate)
+ if (!dev)
+ goto out;
+
+ device_set_run_wake(&dev->dev, false);
+ pci_acpi_remove_pm_notifier(device);
+
+ if (!dev->subordinate)
goto out;
acpi_pci_irq_del_prt(dev->subordinate);
@@ -62,6 +70,10 @@ static int acpi_pci_bind(struct acpi_device *device)
if (!dev)
return 0;
+ pci_acpi_add_pm_notifier(device, dev);
+ if (device->wakeup.flags.run_wake)
+ device_set_run_wake(&dev->dev, true);
+
/*
* Install the 'bind' function to facilitate callbacks for
* children of the P2P bridge.
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 394ae89409c2..04b0f007c9b7 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -56,7 +56,7 @@ ACPI_MODULE_NAME("pci_link");
static int acpi_pci_link_add(struct acpi_device *device);
static int acpi_pci_link_remove(struct acpi_device *device, int type);
-static struct acpi_device_id link_device_ids[] = {
+static const struct acpi_device_id link_device_ids[] = {
{"PNP0C0F", 0},
{"", 0},
};
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 101cce3681d1..d724736d56c8 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -30,6 +30,7 @@
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include <linux/pci.h>
#include <linux/pci-acpi.h>
#include <linux/acpi.h>
@@ -46,7 +47,7 @@ static int acpi_pci_root_add(struct acpi_device *device);
static int acpi_pci_root_remove(struct acpi_device *device, int type);
static int acpi_pci_root_start(struct acpi_device *device);
-static struct acpi_device_id root_device_ids[] = {
+static const struct acpi_device_id root_device_ids[] = {
{"PNP0A03", 0},
{"", 0},
};
@@ -528,6 +529,10 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
if (flags != base_flags)
acpi_pci_osc_support(root, flags);
+ pci_acpi_add_bus_pm_notifier(device, root->bus);
+ if (device->wakeup.flags.run_wake)
+ device_set_run_wake(root->bus->bridge, true);
+
return 0;
end:
@@ -549,6 +554,9 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type)
{
struct acpi_pci_root *root = acpi_driver_data(device);
+ device_set_run_wake(root->bus->bridge, false);
+ pci_acpi_remove_bus_pm_notifier(device);
+
kfree(root);
return 0;
}
@@ -558,6 +566,7 @@ static int __init acpi_pci_root_init(void)
if (acpi_pci_disabled)
return 0;
+ pci_acpi_crs_quirks();
if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0)
return -ENODEV;
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 22b297916519..0f30c3c1eea4 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -65,7 +65,7 @@ static int acpi_power_remove(struct acpi_device *device, int type);
static int acpi_power_resume(struct acpi_device *device);
static int acpi_power_open_fs(struct inode *inode, struct file *file);
-static struct acpi_device_id power_device_ids[] = {
+static const struct acpi_device_id power_device_ids[] = {
{ACPI_POWER_HID, 0},
{"", 0},
};
diff --git a/drivers/acpi/power_meter.c b/drivers/acpi/power_meter.c
index 2ef7030a0c28..834c5af0de4b 100644
--- a/drivers/acpi/power_meter.c
+++ b/drivers/acpi/power_meter.c
@@ -64,24 +64,24 @@ static int can_cap_in_hardware(void)
return force_cap_on || cap_in_hardware;
}
-static struct acpi_device_id power_meter_ids[] = {
+static const struct acpi_device_id power_meter_ids[] = {
{"ACPI000D", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, power_meter_ids);
struct acpi_power_meter_capabilities {
- acpi_integer flags;
- acpi_integer units;
- acpi_integer type;
- acpi_integer accuracy;
- acpi_integer sampling_time;
- acpi_integer min_avg_interval;
- acpi_integer max_avg_interval;
- acpi_integer hysteresis;
- acpi_integer configurable_cap;
- acpi_integer min_cap;
- acpi_integer max_cap;
+ u64 flags;
+ u64 units;
+ u64 type;
+ u64 accuracy;
+ u64 sampling_time;
+ u64 min_avg_interval;
+ u64 max_avg_interval;
+ u64 hysteresis;
+ u64 configurable_cap;
+ u64 min_cap;
+ u64 max_cap;
};
struct acpi_power_meter_resource {
@@ -93,9 +93,9 @@ struct acpi_power_meter_resource {
acpi_string model_number;
acpi_string serial_number;
acpi_string oem_info;
- acpi_integer power;
- acpi_integer cap;
- acpi_integer avg_interval;
+ u64 power;
+ u64 cap;
+ u64 avg_interval;
int sensors_valid;
unsigned long sensors_last_updated;
struct sensor_device_attribute sensors[NUM_SENSORS];
@@ -402,7 +402,7 @@ static ssize_t show_val(struct device *dev,
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct acpi_device *acpi_dev = to_acpi_device(dev);
struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
- acpi_integer val = 0;
+ u64 val = 0;
switch (attr->index) {
case 0:
@@ -534,6 +534,7 @@ static void remove_domain_devices(struct acpi_power_meter_resource *resource)
kfree(resource->domain_devices);
kobject_put(resource->holders_dir);
+ resource->num_domain_devices = 0;
}
static int read_domain_devices(struct acpi_power_meter_resource *resource)
@@ -740,7 +741,6 @@ skip_unsafe_cap:
return res;
error:
- remove_domain_devices(resource);
remove_attrs(resource);
return res;
}
diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c
index d0d25e2e1ced..1ac678d2c51c 100644
--- a/drivers/acpi/proc.c
+++ b/drivers/acpi/proc.c
@@ -435,7 +435,7 @@ acpi_system_write_wakeup_device(struct file *file,
found_dev->wakeup.gpe_device)) {
printk(KERN_WARNING
"ACPI: '%s' and '%s' have the same GPE, "
- "can't disable/enable one seperately\n",
+ "can't disable/enable one separately\n",
dev->pnp.bus_id, found_dev->pnp.bus_id);
dev->wakeup.state.enabled =
found_dev->wakeup.state.enabled;
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 9863c98c81ba..791ac7b0f8df 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -1,381 +1,62 @@
/*
- * acpi_processor.c - ACPI Processor Driver ($Revision: 71 $)
+ * Copyright (C) 2005 Intel Corporation
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
*
- * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
- * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
- * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
- * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
- * - Added processor hotplug support
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * 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.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * TBD:
- * 1. Make # power states dynamic.
- * 2. Support duty_cycle values that span bit 4.
- * 3. Optimize by having scheduler determine business instead of
- * having us try to calculate it here.
- * 4. Need C1 timing -- must modify kernel (IRQ handler) to get this.
+ * Alex Chiang <achiang@hp.com>
+ * - Unified x86/ia64 implementations
+ * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ * - Added _PDC for platforms with Intel CPUs
*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/pm.h>
-#include <linux/cpufreq.h>
-#include <linux/cpu.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
#include <linux/dmi.h>
-#include <linux/moduleparam.h>
-#include <linux/cpuidle.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/cpu.h>
-#include <asm/delay.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-#include <asm/smp.h>
-#include <asm/acpi.h>
-
-#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/processor.h>
-#define PREFIX "ACPI: "
-
-#define ACPI_PROCESSOR_CLASS "processor"
-#define ACPI_PROCESSOR_DEVICE_NAME "Processor"
-#define ACPI_PROCESSOR_FILE_INFO "info"
-#define ACPI_PROCESSOR_FILE_THROTTLING "throttling"
-#define ACPI_PROCESSOR_FILE_LIMIT "limit"
-#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
-#define ACPI_PROCESSOR_NOTIFY_POWER 0x81
-#define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82
-
-#define ACPI_PROCESSOR_LIMIT_USER 0
-#define ACPI_PROCESSOR_LIMIT_THERMAL 1
+#include "internal.h"
+#define PREFIX "ACPI: "
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_core");
-MODULE_AUTHOR("Paul Diefenbaugh");
-MODULE_DESCRIPTION("ACPI Processor Driver");
-MODULE_LICENSE("GPL");
-
-static int acpi_processor_add(struct acpi_device *device);
-static int acpi_processor_remove(struct acpi_device *device, int type);
-#ifdef CONFIG_ACPI_PROCFS
-static int acpi_processor_info_open_fs(struct inode *inode, struct file *file);
-#endif
-static void acpi_processor_notify(struct acpi_device *device, u32 event);
-static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
-static int acpi_processor_handle_eject(struct acpi_processor *pr);
-
-
-static const struct acpi_device_id processor_device_ids[] = {
- {ACPI_PROCESSOR_OBJECT_HID, 0},
- {"ACPI0007", 0},
- {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, processor_device_ids);
-
-static struct acpi_driver acpi_processor_driver = {
- .name = "processor",
- .class = ACPI_PROCESSOR_CLASS,
- .ids = processor_device_ids,
- .ops = {
- .add = acpi_processor_add,
- .remove = acpi_processor_remove,
- .suspend = acpi_processor_suspend,
- .resume = acpi_processor_resume,
- .notify = acpi_processor_notify,
- },
-};
-
-#define INSTALL_NOTIFY_HANDLER 1
-#define UNINSTALL_NOTIFY_HANDLER 2
-#ifdef CONFIG_ACPI_PROCFS
-static const struct file_operations acpi_processor_info_fops = {
- .owner = THIS_MODULE,
- .open = acpi_processor_info_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif
-
-DEFINE_PER_CPU(struct acpi_processor *, processors);
-struct acpi_processor_errata errata __read_mostly;
-
-/* --------------------------------------------------------------------------
- Errata Handling
- -------------------------------------------------------------------------- */
-
-static int acpi_processor_errata_piix4(struct pci_dev *dev)
+static int set_no_mwait(const struct dmi_system_id *id)
{
- u8 value1 = 0;
- u8 value2 = 0;
-
-
- if (!dev)
- return -EINVAL;
-
- /*
- * Note that 'dev' references the PIIX4 ACPI Controller.
- */
-
- switch (dev->revision) {
- case 0:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n"));
- break;
- case 1:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n"));
- break;
- case 2:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n"));
- break;
- case 3:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n"));
- break;
- default:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n"));
- break;
- }
-
- switch (dev->revision) {
-
- case 0: /* PIIX4 A-step */
- case 1: /* PIIX4 B-step */
- /*
- * See specification changes #13 ("Manual Throttle Duty Cycle")
- * and #14 ("Enabling and Disabling Manual Throttle"), plus
- * erratum #5 ("STPCLK# Deassertion Time") from the January
- * 2002 PIIX4 specification update. Applies to only older
- * PIIX4 models.
- */
- errata.piix4.throttle = 1;
-
- case 2: /* PIIX4E */
- case 3: /* PIIX4M */
- /*
- * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA
- * Livelock") from the January 2002 PIIX4 specification update.
- * Applies to all PIIX4 models.
- */
-
- /*
- * BM-IDE
- * ------
- * Find the PIIX4 IDE Controller and get the Bus Master IDE
- * Status register address. We'll use this later to read
- * each IDE controller's DMA status to make sure we catch all
- * DMA activity.
- */
- dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB,
- PCI_ANY_ID, PCI_ANY_ID, NULL);
- if (dev) {
- errata.piix4.bmisx = pci_resource_start(dev, 4);
- pci_dev_put(dev);
- }
-
- /*
- * Type-F DMA
- * ----------
- * Find the PIIX4 ISA Controller and read the Motherboard
- * DMA controller's status to see if Type-F (Fast) DMA mode
- * is enabled (bit 7) on either channel. Note that we'll
- * disable C3 support if this is enabled, as some legacy
- * devices won't operate well if fast DMA is disabled.
- */
- dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_0,
- PCI_ANY_ID, PCI_ANY_ID, NULL);
- if (dev) {
- pci_read_config_byte(dev, 0x76, &value1);
- pci_read_config_byte(dev, 0x77, &value2);
- if ((value1 & 0x80) || (value2 & 0x80))
- errata.piix4.fdma = 1;
- pci_dev_put(dev);
- }
-
- break;
- }
-
- if (errata.piix4.bmisx)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Bus master activity detection (BM-IDE) erratum enabled\n"));
- if (errata.piix4.fdma)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Type-F DMA livelock erratum (C3 disabled)\n"));
-
+ printk(KERN_NOTICE PREFIX "%s detected - "
+ "disabling mwait for CPU C-states\n", id->ident);
+ idle_nomwait = 1;
return 0;
}
-static int acpi_processor_errata(struct acpi_processor *pr)
-{
- int result = 0;
- struct pci_dev *dev = NULL;
-
-
- if (!pr)
- return -EINVAL;
-
- /*
- * PIIX4
- */
- dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID,
- PCI_ANY_ID, NULL);
- if (dev) {
- result = acpi_processor_errata_piix4(dev);
- pci_dev_put(dev);
- }
-
- return result;
-}
-
-/* --------------------------------------------------------------------------
- FS Interface (/proc)
- -------------------------------------------------------------------------- */
-
-#ifdef CONFIG_ACPI_PROCFS
-static struct proc_dir_entry *acpi_processor_dir = NULL;
-
-static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_processor *pr = seq->private;
-
-
- if (!pr)
- goto end;
-
- seq_printf(seq, "processor id: %d\n"
- "acpi id: %d\n"
- "bus mastering control: %s\n"
- "power management: %s\n"
- "throttling control: %s\n"
- "limit interface: %s\n",
- pr->id,
- pr->acpi_id,
- pr->flags.bm_control ? "yes" : "no",
- pr->flags.power ? "yes" : "no",
- pr->flags.throttling ? "yes" : "no",
- pr->flags.limit ? "yes" : "no");
-
- end:
- return 0;
-}
-
-static int acpi_processor_info_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_processor_info_seq_show,
- PDE(inode)->data);
-}
-
-static int __cpuinit acpi_processor_add_fs(struct acpi_device *device)
-{
- struct proc_dir_entry *entry = NULL;
-
-
- if (!acpi_device_dir(device)) {
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
- acpi_processor_dir);
- if (!acpi_device_dir(device))
- return -ENODEV;
- }
-
- /* 'info' [R] */
- entry = proc_create_data(ACPI_PROCESSOR_FILE_INFO,
- S_IRUGO, acpi_device_dir(device),
- &acpi_processor_info_fops,
- acpi_driver_data(device));
- if (!entry)
- return -EIO;
-
- /* 'throttling' [R/W] */
- entry = proc_create_data(ACPI_PROCESSOR_FILE_THROTTLING,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device),
- &acpi_processor_throttling_fops,
- acpi_driver_data(device));
- if (!entry)
- return -EIO;
-
- /* 'limit' [R/W] */
- entry = proc_create_data(ACPI_PROCESSOR_FILE_LIMIT,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device),
- &acpi_processor_limit_fops,
- acpi_driver_data(device));
- if (!entry)
- return -EIO;
- return 0;
-}
-static int acpi_processor_remove_fs(struct acpi_device *device)
-{
-
- if (acpi_device_dir(device)) {
- remove_proc_entry(ACPI_PROCESSOR_FILE_INFO,
- acpi_device_dir(device));
- remove_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING,
- acpi_device_dir(device));
- remove_proc_entry(ACPI_PROCESSOR_FILE_LIMIT,
- acpi_device_dir(device));
- remove_proc_entry(acpi_device_bid(device), acpi_processor_dir);
- acpi_device_dir(device) = NULL;
- }
-
- return 0;
-}
-#else
-static inline int acpi_processor_add_fs(struct acpi_device *device)
-{
- return 0;
-}
-static inline int acpi_processor_remove_fs(struct acpi_device *device)
-{
- return 0;
-}
-#endif
-
-/* Use the acpiid in MADT to map cpus in case of SMP */
-
-#ifndef CONFIG_SMP
-static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id) { return -1; }
-#else
-
-static struct acpi_table_madt *madt;
+static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = {
+ {
+ set_no_mwait, "IFL91 board", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
+ DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"),
+ DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL},
+ {
+ set_no_mwait, "Extensa 5220", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
+ DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
+ {},
+};
+#ifdef CONFIG_SMP
static int map_lapic_id(struct acpi_subtable_header *entry,
u32 acpi_id, int *apic_id)
{
struct acpi_madt_local_apic *lapic =
(struct acpi_madt_local_apic *)entry;
- if ((lapic->lapic_flags & ACPI_MADT_ENABLED) &&
- lapic->processor_id == acpi_id) {
- *apic_id = lapic->id;
- return 1;
- }
- return 0;
+
+ if (!(lapic->lapic_flags & ACPI_MADT_ENABLED))
+ return 0;
+
+ if (lapic->processor_id != acpi_id)
+ return 0;
+
+ *apic_id = lapic->id;
+ return 1;
}
static int map_x2apic_id(struct acpi_subtable_header *entry,
@@ -383,22 +64,16 @@ static int map_x2apic_id(struct acpi_subtable_header *entry,
{
struct acpi_madt_local_x2apic *apic =
(struct acpi_madt_local_x2apic *)entry;
- u32 tmp = apic->local_apic_id;
- /* Only check enabled APICs*/
if (!(apic->lapic_flags & ACPI_MADT_ENABLED))
return 0;
- /* Device statement declaration type */
- if (device_declaration) {
- if (apic->uid == acpi_id)
- goto found;
+ if (device_declaration && (apic->uid == acpi_id)) {
+ *apic_id = apic->local_apic_id;
+ return 1;
}
return 0;
-found:
- *apic_id = tmp;
- return 1;
}
static int map_lsapic_id(struct acpi_subtable_header *entry,
@@ -406,35 +81,34 @@ static int map_lsapic_id(struct acpi_subtable_header *entry,
{
struct acpi_madt_local_sapic *lsapic =
(struct acpi_madt_local_sapic *)entry;
- u32 tmp = (lsapic->id << 8) | lsapic->eid;
- /* Only check enabled APICs*/
if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED))
return 0;
- /* Device statement declaration type */
if (device_declaration) {
- if (entry->length < 16)
- printk(KERN_ERR PREFIX
- "Invalid LSAPIC with Device type processor (SAPIC ID %#x)\n",
- tmp);
- else if (lsapic->uid == acpi_id)
- goto found;
- /* Processor statement declaration type */
- } else if (lsapic->processor_id == acpi_id)
- goto found;
+ if ((entry->length < 16) || (lsapic->uid != acpi_id))
+ return 0;
+ } else if (lsapic->processor_id != acpi_id)
+ return 0;
- return 0;
-found:
- *apic_id = tmp;
+ *apic_id = (lsapic->id << 8) | lsapic->eid;
return 1;
}
static int map_madt_entry(int type, u32 acpi_id)
{
unsigned long madt_end, entry;
+ static struct acpi_table_madt *madt;
+ static int read_madt;
int apic_id = -1;
+ if (!read_madt) {
+ if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
+ (struct acpi_table_header **)&madt)))
+ madt = NULL;
+ read_madt++;
+ }
+
if (!madt)
return apic_id;
@@ -494,7 +168,7 @@ exit:
return apic_id;
}
-static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id)
+int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
{
int i;
int apic_id = -1;
@@ -511,630 +185,170 @@ static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id)
}
return -1;
}
+EXPORT_SYMBOL_GPL(acpi_get_cpuid);
#endif
-/* --------------------------------------------------------------------------
- Driver Interface
- -------------------------------------------------------------------------- */
-
-static int acpi_processor_get_info(struct acpi_device *device)
+static bool processor_physically_present(acpi_handle handle)
{
- acpi_status status = 0;
+ int cpuid, type;
+ u32 acpi_id;
+ acpi_status status;
+ acpi_object_type acpi_type;
+ unsigned long long tmp;
union acpi_object object = { 0 };
struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
- struct acpi_processor *pr;
- int cpu_index, device_declaration = 0;
- static int cpu0_initialized;
-
- pr = acpi_driver_data(device);
- if (!pr)
- return -EINVAL;
-
- if (num_online_cpus() > 1)
- errata.smp = TRUE;
-
- acpi_processor_errata(pr);
-
- /*
- * Check to see if we have bus mastering arbitration control. This
- * is required for proper C3 usage (to maintain cache coherency).
- */
- if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) {
- pr->flags.bm_control = 1;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Bus mastering arbitration control present\n"));
- } else
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "No bus mastering arbitration control\n"));
-
- if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) {
- /* Declared with "Processor" statement; match ProcessorID */
- status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Evaluating processor object\n");
- return -ENODEV;
- }
-
- /*
- * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
- * >>> 'acpi_get_processor_id(acpi_id, &id)' in
- * arch/xxx/acpi.c
- */
- pr->acpi_id = object.processor.proc_id;
- } else {
- /*
- * Declared with "Device" statement; match _UID.
- * Note that we don't handle string _UIDs yet.
- */
- unsigned long long value;
- status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
- NULL, &value);
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX
- "Evaluating processor _UID [%#x]\n", status);
- return -ENODEV;
- }
- device_declaration = 1;
- pr->acpi_id = value;
- }
- cpu_index = get_cpu_id(pr->handle, device_declaration, pr->acpi_id);
-
- /* Handle UP system running SMP kernel, with no LAPIC in MADT */
- if (!cpu0_initialized && (cpu_index == -1) &&
- (num_online_cpus() == 1)) {
- cpu_index = 0;
- }
-
- cpu0_initialized = 1;
-
- pr->id = cpu_index;
-
- /*
- * Extra Processor objects may be enumerated on MP systems with
- * less than the max # of CPUs. They should be ignored _iff
- * they are physically not present.
- */
- if (pr->id == -1) {
- if (ACPI_FAILURE
- (acpi_processor_hotadd_init(pr->handle, &pr->id))) {
- return -ENODEV;
- }
- }
- /*
- * On some boxes several processors use the same processor bus id.
- * But they are located in different scope. For example:
- * \_SB.SCK0.CPU0
- * \_SB.SCK1.CPU0
- * Rename the processor device bus id. And the new bus id will be
- * generated as the following format:
- * CPU+CPU ID.
- */
- sprintf(acpi_device_bid(device), "CPU%X", pr->id);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id,
- pr->acpi_id));
-
- if (!object.processor.pblk_address)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n"));
- else if (object.processor.pblk_length != 6)
- printk(KERN_ERR PREFIX "Invalid PBLK length [%d]\n",
- object.processor.pblk_length);
- else {
- pr->throttling.address = object.processor.pblk_address;
- pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;
- pr->throttling.duty_width = acpi_gbl_FADT.duty_width;
-
- pr->pblk = object.processor.pblk_address;
-
- /*
- * We don't care about error returns - we just try to mark
- * these reserved so that nobody else is confused into thinking
- * that this region might be unused..
- *
- * (In particular, allocating the IO range for Cardbus)
- */
- request_region(pr->throttling.address, 6, "ACPI CPU throttle");
- }
-
- /*
- * If ACPI describes a slot number for this CPU, we can use it
- * ensure we get the right value in the "physical id" field
- * of /proc/cpuinfo
- */
- status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer);
- if (ACPI_SUCCESS(status))
- arch_fix_phys_package_id(pr->id, object.integer.value);
-
- return 0;
-}
-static DEFINE_PER_CPU(void *, processor_device_array);
-
-static void acpi_processor_notify(struct acpi_device *device, u32 event)
-{
- struct acpi_processor *pr = acpi_driver_data(device);
- int saved;
-
- if (!pr)
- return;
-
- switch (event) {
- case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
- saved = pr->performance_platform_limit;
- acpi_processor_ppc_has_changed(pr, 1);
- if (saved == pr->performance_platform_limit)
- break;
- acpi_bus_generate_proc_event(device, event,
- pr->performance_platform_limit);
- acpi_bus_generate_netlink_event(device->pnp.device_class,
- dev_name(&device->dev), event,
- pr->performance_platform_limit);
+ status = acpi_get_type(handle, &acpi_type);
+ if (ACPI_FAILURE(status))
+ return false;
+
+ switch (acpi_type) {
+ case ACPI_TYPE_PROCESSOR:
+ status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return false;
+ acpi_id = object.processor.proc_id;
break;
- case ACPI_PROCESSOR_NOTIFY_POWER:
- acpi_processor_cst_has_changed(pr);
- acpi_bus_generate_proc_event(device, event, 0);
- acpi_bus_generate_netlink_event(device->pnp.device_class,
- dev_name(&device->dev), event, 0);
+ case ACPI_TYPE_DEVICE:
+ status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp);
+ if (ACPI_FAILURE(status))
+ return false;
+ acpi_id = tmp;
break;
- case ACPI_PROCESSOR_NOTIFY_THROTTLING:
- acpi_processor_tstate_has_changed(pr);
- acpi_bus_generate_proc_event(device, event, 0);
- acpi_bus_generate_netlink_event(device->pnp.device_class,
- dev_name(&device->dev), event, 0);
default:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Unsupported event [0x%x]\n", event));
- break;
+ return false;
}
- return;
-}
+ type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0;
+ cpuid = acpi_get_cpuid(handle, type, acpi_id);
-static int acpi_cpu_soft_notify(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
-{
- unsigned int cpu = (unsigned long)hcpu;
- struct acpi_processor *pr = per_cpu(processors, cpu);
+ if (cpuid == -1)
+ return false;
- if (action == CPU_ONLINE && pr) {
- acpi_processor_ppc_has_changed(pr, 0);
- acpi_processor_cst_has_changed(pr);
- acpi_processor_tstate_has_changed(pr);
- }
- return NOTIFY_OK;
+ return true;
}
-static struct notifier_block acpi_cpu_notifier =
+static void acpi_set_pdc_bits(u32 *buf)
{
- .notifier_call = acpi_cpu_soft_notify,
-};
-
-static int __cpuinit acpi_processor_add(struct acpi_device *device)
-{
- struct acpi_processor *pr = NULL;
- int result = 0;
- struct sys_device *sysdev;
-
- pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
- if (!pr)
- return -ENOMEM;
-
- if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) {
- kfree(pr);
- return -ENOMEM;
- }
-
- pr->handle = device->handle;
- strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
- device->driver_data = pr;
-
- result = acpi_processor_get_info(device);
- if (result) {
- /* Processor is physically not present */
- return 0;
- }
-
- BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0));
-
- /*
- * Buggy BIOS check
- * ACPI id of processors can be reported wrongly by the BIOS.
- * Don't trust it blindly
- */
- if (per_cpu(processor_device_array, pr->id) != NULL &&
- per_cpu(processor_device_array, pr->id) != device) {
- printk(KERN_WARNING "BIOS reported wrong ACPI id "
- "for the processor\n");
- result = -ENODEV;
- goto err_free_cpumask;
- }
- per_cpu(processor_device_array, pr->id) = device;
-
- per_cpu(processors, pr->id) = pr;
-
- result = acpi_processor_add_fs(device);
- if (result)
- goto err_free_cpumask;
-
- sysdev = get_cpu_sysdev(pr->id);
- if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) {
- result = -EFAULT;
- goto err_remove_fs;
- }
-
- /* _PDC call should be done before doing anything else (if reqd.). */
- acpi_processor_set_pdc(pr->handle);
-
-#ifdef CONFIG_CPU_FREQ
- acpi_processor_ppc_has_changed(pr, 0);
-#endif
- acpi_processor_get_throttling_info(pr);
- acpi_processor_get_limit_info(pr);
-
-
- acpi_processor_power_init(pr, device);
-
- pr->cdev = thermal_cooling_device_register("Processor", device,
- &processor_cooling_ops);
- if (IS_ERR(pr->cdev)) {
- result = PTR_ERR(pr->cdev);
- goto err_power_exit;
- }
-
- dev_dbg(&device->dev, "registered as cooling_device%d\n",
- pr->cdev->id);
-
- result = sysfs_create_link(&device->dev.kobj,
- &pr->cdev->device.kobj,
- "thermal_cooling");
- if (result) {
- printk(KERN_ERR PREFIX "Create sysfs link\n");
- goto err_thermal_unregister;
- }
- result = sysfs_create_link(&pr->cdev->device.kobj,
- &device->dev.kobj,
- "device");
- if (result) {
- printk(KERN_ERR PREFIX "Create sysfs link\n");
- goto err_remove_sysfs;
- }
+ buf[0] = ACPI_PDC_REVISION_ID;
+ buf[1] = 1;
- return 0;
-
-err_remove_sysfs:
- sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
-err_thermal_unregister:
- thermal_cooling_device_unregister(pr->cdev);
-err_power_exit:
- acpi_processor_power_exit(pr, device);
-err_remove_fs:
- acpi_processor_remove_fs(device);
-err_free_cpumask:
- free_cpumask_var(pr->throttling.shared_cpu_map);
+ /* Enable coordination with firmware's _TSD info */
+ buf[2] = ACPI_PDC_SMP_T_SWCOORD;
- return result;
+ /* Twiddle arch-specific bits needed for _PDC */
+ arch_acpi_set_pdc_bits(buf);
}
-static int acpi_processor_remove(struct acpi_device *device, int type)
+static struct acpi_object_list *acpi_processor_alloc_pdc(void)
{
- struct acpi_processor *pr = NULL;
-
-
- if (!device || !acpi_driver_data(device))
- return -EINVAL;
-
- pr = acpi_driver_data(device);
-
- if (pr->id >= nr_cpu_ids)
- goto free;
+ struct acpi_object_list *obj_list;
+ union acpi_object *obj;
+ u32 *buf;
- if (type == ACPI_BUS_REMOVAL_EJECT) {
- if (acpi_processor_handle_eject(pr))
- return -EINVAL;
+ /* allocate and initialize pdc. It will be used later. */
+ obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL);
+ if (!obj_list) {
+ printk(KERN_ERR "Memory allocation error\n");
+ return NULL;
}
- acpi_processor_power_exit(pr, device);
-
- sysfs_remove_link(&device->dev.kobj, "sysdev");
-
- acpi_processor_remove_fs(device);
-
- if (pr->cdev) {
- sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
- sysfs_remove_link(&pr->cdev->device.kobj, "device");
- thermal_cooling_device_unregister(pr->cdev);
- pr->cdev = NULL;
+ obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL);
+ if (!obj) {
+ printk(KERN_ERR "Memory allocation error\n");
+ kfree(obj_list);
+ return NULL;
}
- per_cpu(processors, pr->id) = NULL;
- per_cpu(processor_device_array, pr->id) = NULL;
-
-free:
- free_cpumask_var(pr->throttling.shared_cpu_map);
- kfree(pr);
-
- return 0;
-}
-
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
-/****************************************************************************
- * Acpi processor hotplug support *
- ****************************************************************************/
-
-static int is_processor_present(acpi_handle handle)
-{
- acpi_status status;
- unsigned long long sta = 0;
-
-
- status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-
- if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT))
- return 1;
-
- /*
- * _STA is mandatory for a processor that supports hot plug
- */
- if (status == AE_NOT_FOUND)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Processor does not support hot plug\n"));
- else
- ACPI_EXCEPTION((AE_INFO, status,
- "Processor Device is not present"));
- return 0;
-}
-
-static
-int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
-{
- acpi_handle phandle;
- struct acpi_device *pdev;
-
-
- if (acpi_get_parent(handle, &phandle)) {
- return -ENODEV;
+ buf = kmalloc(12, GFP_KERNEL);
+ if (!buf) {
+ printk(KERN_ERR "Memory allocation error\n");
+ kfree(obj);
+ kfree(obj_list);
+ return NULL;
}
- if (acpi_bus_get_device(phandle, &pdev)) {
- return -ENODEV;
- }
+ acpi_set_pdc_bits(buf);
- if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
- return -ENODEV;
- }
+ obj->type = ACPI_TYPE_BUFFER;
+ obj->buffer.length = 12;
+ obj->buffer.pointer = (u8 *) buf;
+ obj_list->count = 1;
+ obj_list->pointer = obj;
- return 0;
+ return obj_list;
}
-static void __ref acpi_processor_hotplug_notify(acpi_handle handle,
- u32 event, void *data)
+/*
+ * _PDC is required for a BIOS-OS handshake for most of the newer
+ * ACPI processor features.
+ */
+static int
+acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
{
- struct acpi_processor *pr;
- struct acpi_device *device = NULL;
- int result;
-
+ acpi_status status = AE_OK;
- switch (event) {
- case ACPI_NOTIFY_BUS_CHECK:
- case ACPI_NOTIFY_DEVICE_CHECK:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Processor driver received %s event\n",
- (event == ACPI_NOTIFY_BUS_CHECK) ?
- "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"));
-
- if (!is_processor_present(handle))
- break;
+ if (idle_nomwait) {
+ /*
+ * If mwait is disabled for CPU C-states, the C2C3_FFH access
+ * mode will be disabled in the parameter of _PDC object.
+ * Of course C1_FFH access mode will also be disabled.
+ */
+ union acpi_object *obj;
+ u32 *buffer = NULL;
- if (acpi_bus_get_device(handle, &device)) {
- result = acpi_processor_device_add(handle, &device);
- if (result)
- printk(KERN_ERR PREFIX
- "Unable to add the device\n");
- break;
- }
- break;
- case ACPI_NOTIFY_EJECT_REQUEST:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "received ACPI_NOTIFY_EJECT_REQUEST\n"));
+ obj = pdc_in->pointer;
+ buffer = (u32 *)(obj->buffer.pointer);
+ buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH);
- if (acpi_bus_get_device(handle, &device)) {
- printk(KERN_ERR PREFIX
- "Device don't exist, dropping EJECT\n");
- break;
- }
- pr = acpi_driver_data(device);
- if (!pr) {
- printk(KERN_ERR PREFIX
- "Driver data is NULL, dropping EJECT\n");
- return;
- }
- break;
- default:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Unsupported event [0x%x]\n", event));
- break;
}
+ status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL);
- return;
-}
-
-static acpi_status
-processor_walk_namespace_cb(acpi_handle handle,
- u32 lvl, void *context, void **rv)
-{
- acpi_status status;
- int *action = context;
- acpi_object_type type = 0;
-
- status = acpi_get_type(handle, &type);
if (ACPI_FAILURE(status))
- return (AE_OK);
-
- if (type != ACPI_TYPE_PROCESSOR)
- return (AE_OK);
-
- switch (*action) {
- case INSTALL_NOTIFY_HANDLER:
- acpi_install_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- acpi_processor_hotplug_notify,
- NULL);
- break;
- case UNINSTALL_NOTIFY_HANDLER:
- acpi_remove_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- acpi_processor_hotplug_notify);
- break;
- default:
- break;
- }
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Could not evaluate _PDC, using legacy perf. control.\n"));
- return (AE_OK);
+ return status;
}
-static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu)
+void acpi_processor_set_pdc(acpi_handle handle)
{
+ struct acpi_object_list *obj_list;
- if (!is_processor_present(handle)) {
- return AE_ERROR;
- }
+ if (arch_has_acpi_pdc() == false)
+ return;
- if (acpi_map_lsapic(handle, p_cpu))
- return AE_ERROR;
+ obj_list = acpi_processor_alloc_pdc();
+ if (!obj_list)
+ return;
- if (arch_register_cpu(*p_cpu)) {
- acpi_unmap_lsapic(*p_cpu);
- return AE_ERROR;
- }
+ acpi_processor_eval_pdc(handle, obj_list);
- return AE_OK;
+ kfree(obj_list->pointer->buffer.pointer);
+ kfree(obj_list->pointer);
+ kfree(obj_list);
}
+EXPORT_SYMBOL_GPL(acpi_processor_set_pdc);
-static int acpi_processor_handle_eject(struct acpi_processor *pr)
+static acpi_status
+early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)
{
- if (cpu_online(pr->id))
- cpu_down(pr->id);
+ if (processor_physically_present(handle) == false)
+ return AE_OK;
- arch_unregister_cpu(pr->id);
- acpi_unmap_lsapic(pr->id);
- return (0);
-}
-#else
-static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu)
-{
- return AE_ERROR;
-}
-static int acpi_processor_handle_eject(struct acpi_processor *pr)
-{
- return (-EINVAL);
+ acpi_processor_set_pdc(handle);
+ return AE_OK;
}
-#endif
-static
-void acpi_processor_install_hotplug_notify(void)
+void __init acpi_early_processor_set_pdc(void)
{
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
- int action = INSTALL_NOTIFY_HANDLER;
- acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
- ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- processor_walk_namespace_cb, NULL, &action, NULL);
-#endif
- register_hotcpu_notifier(&acpi_cpu_notifier);
-}
+ /*
+ * Check whether the system is DMI table. If yes, OSPM
+ * should not use mwait for CPU-states.
+ */
+ dmi_check_system(processor_idle_dmi_table);
-static
-void acpi_processor_uninstall_hotplug_notify(void)
-{
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
- int action = UNINSTALL_NOTIFY_HANDLER;
- acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
- ACPI_ROOT_OBJECT,
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
- processor_walk_namespace_cb, NULL, &action, NULL);
-#endif
- unregister_hotcpu_notifier(&acpi_cpu_notifier);
+ early_init_pdc, NULL, NULL, NULL);
}
-
-/*
- * We keep the driver loaded even when ACPI is not running.
- * This is needed for the powernow-k8 driver, that works even without
- * ACPI, but needs symbols from this driver
- */
-
-static int __init acpi_processor_init(void)
-{
- int result = 0;
-
- if (acpi_disabled)
- return 0;
-
- memset(&errata, 0, sizeof(errata));
-
-#ifdef CONFIG_SMP
- if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
- (struct acpi_table_header **)&madt)))
- madt = NULL;
-#endif
-#ifdef CONFIG_ACPI_PROCFS
- acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
- if (!acpi_processor_dir)
- return -ENOMEM;
-#endif
- result = cpuidle_register_driver(&acpi_idle_driver);
- if (result < 0)
- goto out_proc;
-
- result = acpi_bus_register_driver(&acpi_processor_driver);
- if (result < 0)
- goto out_cpuidle;
-
- acpi_processor_install_hotplug_notify();
-
- acpi_thermal_cpufreq_init();
-
- acpi_processor_ppc_init();
-
- acpi_processor_throttling_init();
-
- return 0;
-
-out_cpuidle:
- cpuidle_unregister_driver(&acpi_idle_driver);
-
-out_proc:
-#ifdef CONFIG_ACPI_PROCFS
- remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
-#endif
-
- return result;
-}
-
-static void __exit acpi_processor_exit(void)
-{
- if (acpi_disabled)
- return;
-
- acpi_processor_ppc_exit();
-
- acpi_thermal_cpufreq_exit();
-
- acpi_processor_uninstall_hotplug_notify();
-
- acpi_bus_unregister_driver(&acpi_processor_driver);
-
- cpuidle_unregister_driver(&acpi_idle_driver);
-
-#ifdef CONFIG_ACPI_PROCFS
- remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
-#endif
-
- return;
-}
-
-module_init(acpi_processor_init);
-module_exit(acpi_processor_exit);
-
-EXPORT_SYMBOL(acpi_processor_set_thermal_limit);
-
-MODULE_ALIAS("processor");
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
new file mode 100644
index 000000000000..b5658cdce27f
--- /dev/null
+++ b/drivers/acpi/processor_driver.c
@@ -0,0 +1,978 @@
+/*
+ * acpi_processor.c - ACPI Processor Driver ($Revision: 71 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
+ * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * - Added processor hotplug support
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * TBD:
+ * 1. Make # power states dynamic.
+ * 2. Support duty_cycle values that span bit 4.
+ * 3. Optimize by having scheduler determine business instead of
+ * having us try to calculate it here.
+ * 4. Need C1 timing -- must modify kernel (IRQ handler) to get this.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/dmi.h>
+#include <linux/moduleparam.h>
+#include <linux/cpuidle.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/cpu.h>
+#include <asm/delay.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/smp.h>
+#include <asm/acpi.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/processor.h>
+
+#define PREFIX "ACPI: "
+
+#define ACPI_PROCESSOR_CLASS "processor"
+#define ACPI_PROCESSOR_DEVICE_NAME "Processor"
+#define ACPI_PROCESSOR_FILE_INFO "info"
+#define ACPI_PROCESSOR_FILE_THROTTLING "throttling"
+#define ACPI_PROCESSOR_FILE_LIMIT "limit"
+#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
+#define ACPI_PROCESSOR_NOTIFY_POWER 0x81
+#define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82
+
+#define ACPI_PROCESSOR_LIMIT_USER 0
+#define ACPI_PROCESSOR_LIMIT_THERMAL 1
+
+#define _COMPONENT ACPI_PROCESSOR_COMPONENT
+ACPI_MODULE_NAME("processor_driver");
+
+MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_DESCRIPTION("ACPI Processor Driver");
+MODULE_LICENSE("GPL");
+
+static int acpi_processor_add(struct acpi_device *device);
+static int acpi_processor_remove(struct acpi_device *device, int type);
+#ifdef CONFIG_ACPI_PROCFS
+static int acpi_processor_info_open_fs(struct inode *inode, struct file *file);
+#endif
+static void acpi_processor_notify(struct acpi_device *device, u32 event);
+static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
+static int acpi_processor_handle_eject(struct acpi_processor *pr);
+
+
+static const struct acpi_device_id processor_device_ids[] = {
+ {ACPI_PROCESSOR_OBJECT_HID, 0},
+ {"ACPI0007", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, processor_device_ids);
+
+static struct acpi_driver acpi_processor_driver = {
+ .name = "processor",
+ .class = ACPI_PROCESSOR_CLASS,
+ .ids = processor_device_ids,
+ .ops = {
+ .add = acpi_processor_add,
+ .remove = acpi_processor_remove,
+ .suspend = acpi_processor_suspend,
+ .resume = acpi_processor_resume,
+ .notify = acpi_processor_notify,
+ },
+};
+
+#define INSTALL_NOTIFY_HANDLER 1
+#define UNINSTALL_NOTIFY_HANDLER 2
+#ifdef CONFIG_ACPI_PROCFS
+static const struct file_operations acpi_processor_info_fops = {
+ .owner = THIS_MODULE,
+ .open = acpi_processor_info_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif
+
+DEFINE_PER_CPU(struct acpi_processor *, processors);
+EXPORT_PER_CPU_SYMBOL(processors);
+
+struct acpi_processor_errata errata __read_mostly;
+
+/* --------------------------------------------------------------------------
+ Errata Handling
+ -------------------------------------------------------------------------- */
+
+static int acpi_processor_errata_piix4(struct pci_dev *dev)
+{
+ u8 value1 = 0;
+ u8 value2 = 0;
+
+
+ if (!dev)
+ return -EINVAL;
+
+ /*
+ * Note that 'dev' references the PIIX4 ACPI Controller.
+ */
+
+ switch (dev->revision) {
+ case 0:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n"));
+ break;
+ case 1:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n"));
+ break;
+ case 2:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n"));
+ break;
+ case 3:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n"));
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n"));
+ break;
+ }
+
+ switch (dev->revision) {
+
+ case 0: /* PIIX4 A-step */
+ case 1: /* PIIX4 B-step */
+ /*
+ * See specification changes #13 ("Manual Throttle Duty Cycle")
+ * and #14 ("Enabling and Disabling Manual Throttle"), plus
+ * erratum #5 ("STPCLK# Deassertion Time") from the January
+ * 2002 PIIX4 specification update. Applies to only older
+ * PIIX4 models.
+ */
+ errata.piix4.throttle = 1;
+
+ case 2: /* PIIX4E */
+ case 3: /* PIIX4M */
+ /*
+ * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA
+ * Livelock") from the January 2002 PIIX4 specification update.
+ * Applies to all PIIX4 models.
+ */
+
+ /*
+ * BM-IDE
+ * ------
+ * Find the PIIX4 IDE Controller and get the Bus Master IDE
+ * Status register address. We'll use this later to read
+ * each IDE controller's DMA status to make sure we catch all
+ * DMA activity.
+ */
+ dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB,
+ PCI_ANY_ID, PCI_ANY_ID, NULL);
+ if (dev) {
+ errata.piix4.bmisx = pci_resource_start(dev, 4);
+ pci_dev_put(dev);
+ }
+
+ /*
+ * Type-F DMA
+ * ----------
+ * Find the PIIX4 ISA Controller and read the Motherboard
+ * DMA controller's status to see if Type-F (Fast) DMA mode
+ * is enabled (bit 7) on either channel. Note that we'll
+ * disable C3 support if this is enabled, as some legacy
+ * devices won't operate well if fast DMA is disabled.
+ */
+ dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_0,
+ PCI_ANY_ID, PCI_ANY_ID, NULL);
+ if (dev) {
+ pci_read_config_byte(dev, 0x76, &value1);
+ pci_read_config_byte(dev, 0x77, &value2);
+ if ((value1 & 0x80) || (value2 & 0x80))
+ errata.piix4.fdma = 1;
+ pci_dev_put(dev);
+ }
+
+ break;
+ }
+
+ if (errata.piix4.bmisx)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Bus master activity detection (BM-IDE) erratum enabled\n"));
+ if (errata.piix4.fdma)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Type-F DMA livelock erratum (C3 disabled)\n"));
+
+ return 0;
+}
+
+static int acpi_processor_errata(struct acpi_processor *pr)
+{
+ int result = 0;
+ struct pci_dev *dev = NULL;
+
+
+ if (!pr)
+ return -EINVAL;
+
+ /*
+ * PIIX4
+ */
+ dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID,
+ PCI_ANY_ID, NULL);
+ if (dev) {
+ result = acpi_processor_errata_piix4(dev);
+ pci_dev_put(dev);
+ }
+
+ return result;
+}
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+
+#ifdef CONFIG_ACPI_PROCFS
+static struct proc_dir_entry *acpi_processor_dir = NULL;
+
+static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_processor *pr = seq->private;
+
+
+ if (!pr)
+ goto end;
+
+ seq_printf(seq, "processor id: %d\n"
+ "acpi id: %d\n"
+ "bus mastering control: %s\n"
+ "power management: %s\n"
+ "throttling control: %s\n"
+ "limit interface: %s\n",
+ pr->id,
+ pr->acpi_id,
+ pr->flags.bm_control ? "yes" : "no",
+ pr->flags.power ? "yes" : "no",
+ pr->flags.throttling ? "yes" : "no",
+ pr->flags.limit ? "yes" : "no");
+
+ end:
+ return 0;
+}
+
+static int acpi_processor_info_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_processor_info_seq_show,
+ PDE(inode)->data);
+}
+
+static int __cpuinit acpi_processor_add_fs(struct acpi_device *device)
+{
+ struct proc_dir_entry *entry = NULL;
+
+
+ if (!acpi_device_dir(device)) {
+ acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
+ acpi_processor_dir);
+ if (!acpi_device_dir(device))
+ return -ENODEV;
+ }
+
+ /* 'info' [R] */
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_INFO,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_processor_info_fops,
+ acpi_driver_data(device));
+ if (!entry)
+ return -EIO;
+
+ /* 'throttling' [R/W] */
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_THROTTLING,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_processor_throttling_fops,
+ acpi_driver_data(device));
+ if (!entry)
+ return -EIO;
+
+ /* 'limit' [R/W] */
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_LIMIT,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_processor_limit_fops,
+ acpi_driver_data(device));
+ if (!entry)
+ return -EIO;
+ return 0;
+}
+static int acpi_processor_remove_fs(struct acpi_device *device)
+{
+
+ if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_PROCESSOR_FILE_INFO,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_PROCESSOR_FILE_LIMIT,
+ acpi_device_dir(device));
+ remove_proc_entry(acpi_device_bid(device), acpi_processor_dir);
+ acpi_device_dir(device) = NULL;
+ }
+
+ return 0;
+}
+#else
+static inline int acpi_processor_add_fs(struct acpi_device *device)
+{
+ return 0;
+}
+static inline int acpi_processor_remove_fs(struct acpi_device *device)
+{
+ return 0;
+}
+#endif
+
+/* --------------------------------------------------------------------------
+ Driver Interface
+ -------------------------------------------------------------------------- */
+
+static int acpi_processor_get_info(struct acpi_device *device)
+{
+ acpi_status status = 0;
+ union acpi_object object = { 0 };
+ struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
+ struct acpi_processor *pr;
+ int cpu_index, device_declaration = 0;
+ static int cpu0_initialized;
+
+ pr = acpi_driver_data(device);
+ if (!pr)
+ return -EINVAL;
+
+ if (num_online_cpus() > 1)
+ errata.smp = TRUE;
+
+ acpi_processor_errata(pr);
+
+ /*
+ * Check to see if we have bus mastering arbitration control. This
+ * is required for proper C3 usage (to maintain cache coherency).
+ */
+ if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) {
+ pr->flags.bm_control = 1;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Bus mastering arbitration control present\n"));
+ } else
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "No bus mastering arbitration control\n"));
+
+ if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) {
+ /* Declared with "Processor" statement; match ProcessorID */
+ status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Evaluating processor object\n");
+ return -ENODEV;
+ }
+
+ /*
+ * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
+ * >>> 'acpi_get_processor_id(acpi_id, &id)' in
+ * arch/xxx/acpi.c
+ */
+ pr->acpi_id = object.processor.proc_id;
+ } else {
+ /*
+ * Declared with "Device" statement; match _UID.
+ * Note that we don't handle string _UIDs yet.
+ */
+ unsigned long long value;
+ status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
+ NULL, &value);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX
+ "Evaluating processor _UID [%#x]\n", status);
+ return -ENODEV;
+ }
+ device_declaration = 1;
+ pr->acpi_id = value;
+ }
+ cpu_index = acpi_get_cpuid(pr->handle, device_declaration, pr->acpi_id);
+
+ /* Handle UP system running SMP kernel, with no LAPIC in MADT */
+ if (!cpu0_initialized && (cpu_index == -1) &&
+ (num_online_cpus() == 1)) {
+ cpu_index = 0;
+ }
+
+ cpu0_initialized = 1;
+
+ pr->id = cpu_index;
+
+ /*
+ * Extra Processor objects may be enumerated on MP systems with
+ * less than the max # of CPUs. They should be ignored _iff
+ * they are physically not present.
+ */
+ if (pr->id == -1) {
+ if (ACPI_FAILURE
+ (acpi_processor_hotadd_init(pr->handle, &pr->id))) {
+ return -ENODEV;
+ }
+ }
+ /*
+ * On some boxes several processors use the same processor bus id.
+ * But they are located in different scope. For example:
+ * \_SB.SCK0.CPU0
+ * \_SB.SCK1.CPU0
+ * Rename the processor device bus id. And the new bus id will be
+ * generated as the following format:
+ * CPU+CPU ID.
+ */
+ sprintf(acpi_device_bid(device), "CPU%X", pr->id);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id,
+ pr->acpi_id));
+
+ if (!object.processor.pblk_address)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n"));
+ else if (object.processor.pblk_length != 6)
+ printk(KERN_ERR PREFIX "Invalid PBLK length [%d]\n",
+ object.processor.pblk_length);
+ else {
+ pr->throttling.address = object.processor.pblk_address;
+ pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;
+ pr->throttling.duty_width = acpi_gbl_FADT.duty_width;
+
+ pr->pblk = object.processor.pblk_address;
+
+ /*
+ * We don't care about error returns - we just try to mark
+ * these reserved so that nobody else is confused into thinking
+ * that this region might be unused..
+ *
+ * (In particular, allocating the IO range for Cardbus)
+ */
+ request_region(pr->throttling.address, 6, "ACPI CPU throttle");
+ }
+
+ /*
+ * If ACPI describes a slot number for this CPU, we can use it
+ * ensure we get the right value in the "physical id" field
+ * of /proc/cpuinfo
+ */
+ status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer);
+ if (ACPI_SUCCESS(status))
+ arch_fix_phys_package_id(pr->id, object.integer.value);
+
+ return 0;
+}
+
+static DEFINE_PER_CPU(void *, processor_device_array);
+
+static void acpi_processor_notify(struct acpi_device *device, u32 event)
+{
+ struct acpi_processor *pr = acpi_driver_data(device);
+ int saved;
+
+ if (!pr)
+ return;
+
+ switch (event) {
+ case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
+ saved = pr->performance_platform_limit;
+ acpi_processor_ppc_has_changed(pr, 1);
+ if (saved == pr->performance_platform_limit)
+ break;
+ acpi_bus_generate_proc_event(device, event,
+ pr->performance_platform_limit);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ dev_name(&device->dev), event,
+ pr->performance_platform_limit);
+ break;
+ case ACPI_PROCESSOR_NOTIFY_POWER:
+ acpi_processor_cst_has_changed(pr);
+ acpi_bus_generate_proc_event(device, event, 0);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ dev_name(&device->dev), event, 0);
+ break;
+ case ACPI_PROCESSOR_NOTIFY_THROTTLING:
+ acpi_processor_tstate_has_changed(pr);
+ acpi_bus_generate_proc_event(device, event, 0);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ dev_name(&device->dev), event, 0);
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+
+ return;
+}
+
+static int acpi_cpu_soft_notify(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ struct acpi_processor *pr = per_cpu(processors, cpu);
+
+ if (action == CPU_ONLINE && pr) {
+ acpi_processor_ppc_has_changed(pr, 0);
+ acpi_processor_cst_has_changed(pr);
+ acpi_processor_tstate_has_changed(pr);
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block acpi_cpu_notifier =
+{
+ .notifier_call = acpi_cpu_soft_notify,
+};
+
+static int __cpuinit acpi_processor_add(struct acpi_device *device)
+{
+ struct acpi_processor *pr = NULL;
+ int result = 0;
+ struct sys_device *sysdev;
+
+ pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
+ if (!pr)
+ return -ENOMEM;
+
+ if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) {
+ kfree(pr);
+ return -ENOMEM;
+ }
+
+ pr->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
+ device->driver_data = pr;
+
+ result = acpi_processor_get_info(device);
+ if (result) {
+ /* Processor is physically not present */
+ return 0;
+ }
+
+ BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0));
+
+ /*
+ * Buggy BIOS check
+ * ACPI id of processors can be reported wrongly by the BIOS.
+ * Don't trust it blindly
+ */
+ if (per_cpu(processor_device_array, pr->id) != NULL &&
+ per_cpu(processor_device_array, pr->id) != device) {
+ printk(KERN_WARNING "BIOS reported wrong ACPI id "
+ "for the processor\n");
+ result = -ENODEV;
+ goto err_free_cpumask;
+ }
+ per_cpu(processor_device_array, pr->id) = device;
+
+ per_cpu(processors, pr->id) = pr;
+
+ result = acpi_processor_add_fs(device);
+ if (result)
+ goto err_free_cpumask;
+
+ sysdev = get_cpu_sysdev(pr->id);
+ if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) {
+ result = -EFAULT;
+ goto err_remove_fs;
+ }
+
+#ifdef CONFIG_CPU_FREQ
+ acpi_processor_ppc_has_changed(pr, 0);
+#endif
+ acpi_processor_get_throttling_info(pr);
+ acpi_processor_get_limit_info(pr);
+
+
+ acpi_processor_power_init(pr, device);
+
+ pr->cdev = thermal_cooling_device_register("Processor", device,
+ &processor_cooling_ops);
+ if (IS_ERR(pr->cdev)) {
+ result = PTR_ERR(pr->cdev);
+ goto err_power_exit;
+ }
+
+ dev_dbg(&device->dev, "registered as cooling_device%d\n",
+ pr->cdev->id);
+
+ result = sysfs_create_link(&device->dev.kobj,
+ &pr->cdev->device.kobj,
+ "thermal_cooling");
+ if (result) {
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ goto err_thermal_unregister;
+ }
+ result = sysfs_create_link(&pr->cdev->device.kobj,
+ &device->dev.kobj,
+ "device");
+ if (result) {
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ goto err_remove_sysfs;
+ }
+
+ return 0;
+
+err_remove_sysfs:
+ sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+err_thermal_unregister:
+ thermal_cooling_device_unregister(pr->cdev);
+err_power_exit:
+ acpi_processor_power_exit(pr, device);
+err_remove_fs:
+ acpi_processor_remove_fs(device);
+err_free_cpumask:
+ free_cpumask_var(pr->throttling.shared_cpu_map);
+
+ return result;
+}
+
+static int acpi_processor_remove(struct acpi_device *device, int type)
+{
+ struct acpi_processor *pr = NULL;
+
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
+ pr = acpi_driver_data(device);
+
+ if (pr->id >= nr_cpu_ids)
+ goto free;
+
+ if (type == ACPI_BUS_REMOVAL_EJECT) {
+ if (acpi_processor_handle_eject(pr))
+ return -EINVAL;
+ }
+
+ acpi_processor_power_exit(pr, device);
+
+ sysfs_remove_link(&device->dev.kobj, "sysdev");
+
+ acpi_processor_remove_fs(device);
+
+ if (pr->cdev) {
+ sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+ sysfs_remove_link(&pr->cdev->device.kobj, "device");
+ thermal_cooling_device_unregister(pr->cdev);
+ pr->cdev = NULL;
+ }
+
+ per_cpu(processors, pr->id) = NULL;
+ per_cpu(processor_device_array, pr->id) = NULL;
+
+free:
+ free_cpumask_var(pr->throttling.shared_cpu_map);
+ kfree(pr);
+
+ return 0;
+}
+
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+/****************************************************************************
+ * Acpi processor hotplug support *
+ ****************************************************************************/
+
+static int is_processor_present(acpi_handle handle)
+{
+ acpi_status status;
+ unsigned long long sta = 0;
+
+
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+
+ if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT))
+ return 1;
+
+ /*
+ * _STA is mandatory for a processor that supports hot plug
+ */
+ if (status == AE_NOT_FOUND)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Processor does not support hot plug\n"));
+ else
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Processor Device is not present"));
+ return 0;
+}
+
+static
+int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
+{
+ acpi_handle phandle;
+ struct acpi_device *pdev;
+
+
+ if (acpi_get_parent(handle, &phandle)) {
+ return -ENODEV;
+ }
+
+ if (acpi_bus_get_device(phandle, &pdev)) {
+ return -ENODEV;
+ }
+
+ if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __ref acpi_processor_hotplug_notify(acpi_handle handle,
+ u32 event, void *data)
+{
+ struct acpi_processor *pr;
+ struct acpi_device *device = NULL;
+ int result;
+
+
+ switch (event) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Processor driver received %s event\n",
+ (event == ACPI_NOTIFY_BUS_CHECK) ?
+ "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"));
+
+ if (!is_processor_present(handle))
+ break;
+
+ if (acpi_bus_get_device(handle, &device)) {
+ result = acpi_processor_device_add(handle, &device);
+ if (result)
+ printk(KERN_ERR PREFIX
+ "Unable to add the device\n");
+ break;
+ }
+ break;
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "received ACPI_NOTIFY_EJECT_REQUEST\n"));
+
+ if (acpi_bus_get_device(handle, &device)) {
+ printk(KERN_ERR PREFIX
+ "Device don't exist, dropping EJECT\n");
+ break;
+ }
+ pr = acpi_driver_data(device);
+ if (!pr) {
+ printk(KERN_ERR PREFIX
+ "Driver data is NULL, dropping EJECT\n");
+ return;
+ }
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+
+ return;
+}
+
+static acpi_status
+processor_walk_namespace_cb(acpi_handle handle,
+ u32 lvl, void *context, void **rv)
+{
+ acpi_status status;
+ int *action = context;
+ acpi_object_type type = 0;
+
+ status = acpi_get_type(handle, &type);
+ if (ACPI_FAILURE(status))
+ return (AE_OK);
+
+ if (type != ACPI_TYPE_PROCESSOR)
+ return (AE_OK);
+
+ switch (*action) {
+ case INSTALL_NOTIFY_HANDLER:
+ acpi_install_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ acpi_processor_hotplug_notify,
+ NULL);
+ break;
+ case UNINSTALL_NOTIFY_HANDLER:
+ acpi_remove_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ acpi_processor_hotplug_notify);
+ break;
+ default:
+ break;
+ }
+
+ return (AE_OK);
+}
+
+static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu)
+{
+
+ if (!is_processor_present(handle)) {
+ return AE_ERROR;
+ }
+
+ if (acpi_map_lsapic(handle, p_cpu))
+ return AE_ERROR;
+
+ if (arch_register_cpu(*p_cpu)) {
+ acpi_unmap_lsapic(*p_cpu);
+ return AE_ERROR;
+ }
+
+ return AE_OK;
+}
+
+static int acpi_processor_handle_eject(struct acpi_processor *pr)
+{
+ if (cpu_online(pr->id))
+ cpu_down(pr->id);
+
+ arch_unregister_cpu(pr->id);
+ acpi_unmap_lsapic(pr->id);
+ return (0);
+}
+#else
+static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu)
+{
+ return AE_ERROR;
+}
+static int acpi_processor_handle_eject(struct acpi_processor *pr)
+{
+ return (-EINVAL);
+}
+#endif
+
+static
+void acpi_processor_install_hotplug_notify(void)
+{
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+ int action = INSTALL_NOTIFY_HANDLER;
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ processor_walk_namespace_cb, NULL, &action, NULL);
+#endif
+ register_hotcpu_notifier(&acpi_cpu_notifier);
+}
+
+static
+void acpi_processor_uninstall_hotplug_notify(void)
+{
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+ int action = UNINSTALL_NOTIFY_HANDLER;
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ processor_walk_namespace_cb, NULL, &action, NULL);
+#endif
+ unregister_hotcpu_notifier(&acpi_cpu_notifier);
+}
+
+/*
+ * We keep the driver loaded even when ACPI is not running.
+ * This is needed for the powernow-k8 driver, that works even without
+ * ACPI, but needs symbols from this driver
+ */
+
+static int __init acpi_processor_init(void)
+{
+ int result = 0;
+
+ if (acpi_disabled)
+ return 0;
+
+ memset(&errata, 0, sizeof(errata));
+
+#ifdef CONFIG_ACPI_PROCFS
+ acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+ if (!acpi_processor_dir)
+ return -ENOMEM;
+#endif
+ result = cpuidle_register_driver(&acpi_idle_driver);
+ if (result < 0)
+ goto out_proc;
+
+ result = acpi_bus_register_driver(&acpi_processor_driver);
+ if (result < 0)
+ goto out_cpuidle;
+
+ acpi_processor_install_hotplug_notify();
+
+ acpi_thermal_cpufreq_init();
+
+ acpi_processor_ppc_init();
+
+ acpi_processor_throttling_init();
+
+ return 0;
+
+out_cpuidle:
+ cpuidle_unregister_driver(&acpi_idle_driver);
+
+out_proc:
+#ifdef CONFIG_ACPI_PROCFS
+ remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+#endif
+
+ return result;
+}
+
+static void __exit acpi_processor_exit(void)
+{
+ if (acpi_disabled)
+ return;
+
+ acpi_processor_ppc_exit();
+
+ acpi_thermal_cpufreq_exit();
+
+ acpi_processor_uninstall_hotplug_notify();
+
+ acpi_bus_unregister_driver(&acpi_processor_driver);
+
+ cpuidle_unregister_driver(&acpi_idle_driver);
+
+#ifdef CONFIG_ACPI_PROCFS
+ remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+#endif
+
+ return;
+}
+
+module_init(acpi_processor_init);
+module_exit(acpi_processor_exit);
+
+EXPORT_SYMBOL(acpi_processor_set_thermal_limit);
+
+MODULE_ALIAS("processor");
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index d1676b1754d9..37dfce749398 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -110,6 +110,14 @@ static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = {
DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307")},
(void *)2},
+ { set_max_cstate, "Pavilion zv5000", {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME,"Pavilion zv5000 (DS502A#ABA)")},
+ (void *)1},
+ { set_max_cstate, "Asus L8400B", {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME,"L8400B series Notebook PC")},
+ (void *)1},
{},
};
@@ -305,6 +313,28 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
pr->power.states[ACPI_STATE_C2].latency = acpi_gbl_FADT.C2latency;
pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.C3latency;
+ /*
+ * FADT specified C2 latency must be less than or equal to
+ * 100 microseconds.
+ */
+ if (acpi_gbl_FADT.C2latency > ACPI_PROCESSOR_MAX_C2_LATENCY) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C2 latency too large [%d]\n", acpi_gbl_FADT.C2latency));
+ /* invalidate C2 */
+ pr->power.states[ACPI_STATE_C2].address = 0;
+ }
+
+ /*
+ * FADT supplied C3 latency must be less than or equal to
+ * 1000 microseconds.
+ */
+ if (acpi_gbl_FADT.C3latency > ACPI_PROCESSOR_MAX_C3_LATENCY) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C3 latency too large [%d]\n", acpi_gbl_FADT.C3latency));
+ /* invalidate C3 */
+ pr->power.states[ACPI_STATE_C3].address = 0;
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"lvl2[0x%08x] lvl3[0x%08x]\n",
pr->power.states[ACPI_STATE_C2].address,
@@ -330,7 +360,7 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
{
acpi_status status = 0;
- acpi_integer count;
+ u64 count;
int current_count;
int i;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -494,33 +524,6 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
return status;
}
-static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx)
-{
-
- if (!cx->address)
- return;
-
- /*
- * C2 latency must be less than or equal to 100
- * microseconds.
- */
- else if (cx->latency > ACPI_PROCESSOR_MAX_C2_LATENCY) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "latency too large [%d]\n", cx->latency));
- return;
- }
-
- /*
- * Otherwise we've met all of our C2 requirements.
- * Normalize the C2 latency to expidite policy
- */
- cx->valid = 1;
-
- cx->latency_ticks = cx->latency;
-
- return;
-}
-
static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
struct acpi_processor_cx *cx)
{
@@ -532,16 +535,6 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
return;
/*
- * C3 latency must be less than or equal to 1000
- * microseconds.
- */
- else if (cx->latency > ACPI_PROCESSOR_MAX_C3_LATENCY) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "latency too large [%d]\n", cx->latency));
- return;
- }
-
- /*
* PIIX4 Erratum #18: We don't support C3 when Type-F (fast)
* DMA transfers are used by any ISA device to avoid livelock.
* Note that we could disable Type-F DMA (as recommended by
@@ -629,7 +622,10 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
break;
case ACPI_STATE_C2:
- acpi_processor_power_verify_c2(cx);
+ if (!cx->address)
+ break;
+ cx->valid = 1;
+ cx->latency_ticks = cx->latency; /* Normalize latency */
break;
case ACPI_STATE_C3:
@@ -884,12 +880,14 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
return(acpi_idle_enter_c1(dev, state));
local_irq_disable();
- current_thread_info()->status &= ~TS_POLLING;
- /*
- * TS_POLLING-cleared state must be visible before we test
- * NEED_RESCHED:
- */
- smp_mb();
+ if (cx->entry_method != ACPI_CSTATE_FFH) {
+ current_thread_info()->status &= ~TS_POLLING;
+ /*
+ * TS_POLLING-cleared state must be visible before we test
+ * NEED_RESCHED:
+ */
+ smp_mb();
+ }
if (unlikely(need_resched())) {
current_thread_info()->status |= TS_POLLING;
@@ -969,12 +967,14 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
}
local_irq_disable();
- current_thread_info()->status &= ~TS_POLLING;
- /*
- * TS_POLLING-cleared state must be visible before we test
- * NEED_RESCHED:
- */
- smp_mb();
+ if (cx->entry_method != ACPI_CSTATE_FFH) {
+ current_thread_info()->status &= ~TS_POLLING;
+ /*
+ * TS_POLLING-cleared state must be visible before we test
+ * NEED_RESCHED:
+ */
+ smp_mb();
+ }
if (unlikely(need_resched())) {
current_thread_info()->status |= TS_POLLING;
diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c
deleted file mode 100644
index 30e4dc0cdf30..000000000000
--- a/drivers/acpi/processor_pdc.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2005 Intel Corporation
- * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
- *
- * Alex Chiang <achiang@hp.com>
- * - Unified x86/ia64 implementations
- * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
- * - Added _PDC for platforms with Intel CPUs
- */
-#include <linux/dmi.h>
-
-#include <acpi/acpi_drivers.h>
-#include <acpi/processor.h>
-
-#include "internal.h"
-
-#define PREFIX "ACPI: "
-#define _COMPONENT ACPI_PROCESSOR_COMPONENT
-ACPI_MODULE_NAME("processor_pdc");
-
-static int set_no_mwait(const struct dmi_system_id *id)
-{
- printk(KERN_NOTICE PREFIX "%s detected - "
- "disabling mwait for CPU C-states\n", id->ident);
- idle_nomwait = 1;
- return 0;
-}
-
-static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = {
- {
- set_no_mwait, "IFL91 board", {
- DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
- DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"),
- DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL},
- {
- set_no_mwait, "Extensa 5220", {
- DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
- DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
- DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
- {},
-};
-
-static void acpi_set_pdc_bits(u32 *buf)
-{
- buf[0] = ACPI_PDC_REVISION_ID;
- buf[1] = 1;
-
- /* Enable coordination with firmware's _TSD info */
- buf[2] = ACPI_PDC_SMP_T_SWCOORD;
-
- /* Twiddle arch-specific bits needed for _PDC */
- arch_acpi_set_pdc_bits(buf);
-}
-
-static struct acpi_object_list *acpi_processor_alloc_pdc(void)
-{
- struct acpi_object_list *obj_list;
- union acpi_object *obj;
- u32 *buf;
-
- /* allocate and initialize pdc. It will be used later. */
- obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL);
- if (!obj_list) {
- printk(KERN_ERR "Memory allocation error\n");
- return NULL;
- }
-
- obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL);
- if (!obj) {
- printk(KERN_ERR "Memory allocation error\n");
- kfree(obj_list);
- return NULL;
- }
-
- buf = kmalloc(12, GFP_KERNEL);
- if (!buf) {
- printk(KERN_ERR "Memory allocation error\n");
- kfree(obj);
- kfree(obj_list);
- return NULL;
- }
-
- acpi_set_pdc_bits(buf);
-
- obj->type = ACPI_TYPE_BUFFER;
- obj->buffer.length = 12;
- obj->buffer.pointer = (u8 *) buf;
- obj_list->count = 1;
- obj_list->pointer = obj;
-
- return obj_list;
-}
-
-/*
- * _PDC is required for a BIOS-OS handshake for most of the newer
- * ACPI processor features.
- */
-static int
-acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
-{
- acpi_status status = AE_OK;
-
- if (idle_nomwait) {
- /*
- * If mwait is disabled for CPU C-states, the C2C3_FFH access
- * mode will be disabled in the parameter of _PDC object.
- * Of course C1_FFH access mode will also be disabled.
- */
- union acpi_object *obj;
- u32 *buffer = NULL;
-
- obj = pdc_in->pointer;
- buffer = (u32 *)(obj->buffer.pointer);
- buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH);
-
- }
- status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL);
-
- if (ACPI_FAILURE(status))
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Could not evaluate _PDC, using legacy perf. control.\n"));
-
- return status;
-}
-
-void acpi_processor_set_pdc(acpi_handle handle)
-{
- struct acpi_object_list *obj_list;
-
- if (arch_has_acpi_pdc() == false)
- return;
-
- obj_list = acpi_processor_alloc_pdc();
- if (!obj_list)
- return;
-
- acpi_processor_eval_pdc(handle, obj_list);
-
- kfree(obj_list->pointer->buffer.pointer);
- kfree(obj_list->pointer);
- kfree(obj_list);
-}
-EXPORT_SYMBOL_GPL(acpi_processor_set_pdc);
-
-static acpi_status
-early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- acpi_processor_set_pdc(handle);
- return AE_OK;
-}
-
-void acpi_early_processor_set_pdc(void)
-{
- /*
- * Check whether the system is DMI table. If yes, OSPM
- * should not use mwait for CPU-states.
- */
- dmi_check_system(processor_idle_dmi_table);
-
- acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- early_init_pdc, NULL, NULL, NULL);
-}
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 2cabadcc4d8c..d648a9860b88 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -413,7 +413,11 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
if (result)
goto update_bios;
- return 0;
+ /* We need to call _PPC once when cpufreq starts */
+ if (ignore_ppc != 1)
+ result = acpi_processor_get_platform_limit(pr);
+
+ return result;
/*
* Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that
@@ -557,7 +561,7 @@ end:
}
int acpi_processor_preregister_performance(
- struct acpi_processor_performance *performance)
+ struct acpi_processor_performance __percpu *performance)
{
int count, count_target;
int retval = 0;
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 140c5c5b423c..6deafb4aa0da 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -443,8 +443,7 @@ struct thermal_cooling_device_ops processor_cooling_ops = {
#ifdef CONFIG_ACPI_PROCFS
static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_processor *pr = (struct acpi_processor *)seq->private;
-
+ struct acpi_processor *pr = seq->private;
if (!pr)
goto end;
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 1c5d7a8b2fdf..29c6f5766dcf 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -660,7 +660,7 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
#ifdef CONFIG_X86
static int acpi_throttling_rdmsr(struct acpi_processor *pr,
- acpi_integer * value)
+ u64 *value)
{
struct cpuinfo_x86 *c;
u64 msr_high, msr_low;
@@ -681,13 +681,13 @@ static int acpi_throttling_rdmsr(struct acpi_processor *pr,
rdmsr_safe(MSR_IA32_THERM_CONTROL,
(u32 *)&msr_low , (u32 *) &msr_high);
msr = (msr_high << 32) | msr_low;
- *value = (acpi_integer) msr;
+ *value = (u64) msr;
ret = 0;
}
return ret;
}
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
+static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
{
struct cpuinfo_x86 *c;
unsigned int cpu;
@@ -711,14 +711,14 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
}
#else
static int acpi_throttling_rdmsr(struct acpi_processor *pr,
- acpi_integer * value)
+ u64 *value)
{
printk(KERN_ERR PREFIX
"HARDWARE addr space,NOT supported yet\n");
return -1;
}
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
+static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
{
printk(KERN_ERR PREFIX
"HARDWARE addr space,NOT supported yet\n");
@@ -727,7 +727,7 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
#endif
static int acpi_read_throttling_status(struct acpi_processor *pr,
- acpi_integer *value)
+ u64 *value)
{
u32 bit_width, bit_offset;
u64 ptc_value;
@@ -746,7 +746,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr,
address, (u32 *) &ptc_value,
(u32) (bit_width + bit_offset));
ptc_mask = (1 << bit_width) - 1;
- *value = (acpi_integer) ((ptc_value >> bit_offset) & ptc_mask);
+ *value = (u64) ((ptc_value >> bit_offset) & ptc_mask);
ret = 0;
break;
case ACPI_ADR_SPACE_FIXED_HARDWARE:
@@ -760,7 +760,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr,
}
static int acpi_write_throttling_state(struct acpi_processor *pr,
- acpi_integer value)
+ u64 value)
{
u32 bit_width, bit_offset;
u64 ptc_value;
@@ -793,7 +793,7 @@ static int acpi_write_throttling_state(struct acpi_processor *pr,
}
static int acpi_get_throttling_state(struct acpi_processor *pr,
- acpi_integer value)
+ u64 value)
{
int i;
@@ -808,7 +808,7 @@ static int acpi_get_throttling_state(struct acpi_processor *pr,
}
static int acpi_get_throttling_value(struct acpi_processor *pr,
- int state, acpi_integer *value)
+ int state, u64 *value)
{
int ret = -1;
@@ -826,7 +826,7 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
{
int state = 0;
int ret;
- acpi_integer value;
+ u64 value;
if (!pr)
return -EINVAL;
@@ -993,7 +993,7 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
int state, bool force)
{
int ret;
- acpi_integer value;
+ u64 value;
if (!pr)
return -EINVAL;
@@ -1133,9 +1133,6 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
int result = 0;
struct acpi_processor_throttling *pthrottling;
- if (!pr)
- return -EINVAL;
-
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
pr->throttling.address,
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 38412ec2332d..89ad11138e48 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -827,7 +827,10 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
static void acpi_battery_remove(struct acpi_sbs *sbs, int id)
{
+#if defined(CONFIG_ACPI_SYSFS_POWER) || defined(CONFIG_ACPI_PROCFS_POWER)
struct acpi_battery *battery = &sbs->battery[id];
+#endif
+
#ifdef CONFIG_ACPI_SYSFS_POWER
if (battery->bat.dev) {
if (battery->have_sysfs_alarm)
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index d9339806df45..fd09229282ea 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -242,7 +242,7 @@ static int smbus_alarm(void *context)
case ACPI_SBS_CHARGER:
case ACPI_SBS_MANAGER:
case ACPI_SBS_BATTERY:
- acpi_os_execute(OSL_GPE_HANDLER,
+ acpi_os_execute(OSL_NOTIFY_HANDLER,
acpi_smbus_callback, hc);
default:;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index ff9f6226085d..fb7fc24fe727 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -741,19 +741,40 @@ acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
return AE_OK;
}
-static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
+static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
{
- acpi_status status = 0;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *package = NULL;
- int psw_error;
-
struct acpi_device_id button_device_ids[] = {
{"PNP0C0D", 0},
{"PNP0C0C", 0},
{"PNP0C0E", 0},
{"", 0},
};
+ acpi_status status;
+ acpi_event_status event_status;
+
+ device->wakeup.run_wake_count = 0;
+ device->wakeup.flags.notifier_present = 0;
+
+ /* Power button, Lid switch always enable wakeup */
+ if (!acpi_match_device_ids(device, button_device_ids)) {
+ device->wakeup.flags.run_wake = 1;
+ device->wakeup.flags.always_enabled = 1;
+ return;
+ }
+
+ status = acpi_get_gpe_status(NULL, device->wakeup.gpe_number,
+ ACPI_NOT_ISR, &event_status);
+ if (status == AE_OK)
+ device->wakeup.flags.run_wake =
+ !!(event_status & ACPI_EVENT_FLAG_HANDLE);
+}
+
+static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
+{
+ acpi_status status = 0;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *package = NULL;
+ int psw_error;
/* _PRW */
status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
@@ -773,6 +794,7 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
device->wakeup.flags.valid = 1;
device->wakeup.prepare_count = 0;
+ acpi_bus_set_run_wake_flags(device);
/* Call _PSW/_DSW object to disable its ability to wake the sleeping
* system for the ACPI device with the _PRW object.
* The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
@@ -784,10 +806,6 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"error in _DSW or _PSW evaluation\n"));
- /* Power button, Lid switch always enable wakeup */
- if (!acpi_match_device_ids(device, button_device_ids))
- device->wakeup.flags.run_wake = 1;
-
end:
if (ACPI_FAILURE(status))
device->flags.wake_capable = 0;
@@ -1336,9 +1354,25 @@ static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
if (child)
*child = device;
- return 0;
+
+ if (device)
+ return 0;
+ else
+ return -ENODEV;
}
+/*
+ * acpi_bus_add and acpi_bus_start
+ *
+ * scan a given ACPI tree and (probably recently hot-plugged)
+ * create and add or starts found devices.
+ *
+ * If no devices were found -ENODEV is returned which does not
+ * mean that this is a real error, there just have been no suitable
+ * ACPI objects in the table trunk from which the kernel could create
+ * a device and add/start an appropriate driver.
+ */
+
int
acpi_bus_add(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type)
@@ -1348,8 +1382,7 @@ acpi_bus_add(struct acpi_device **child,
memset(&ops, 0, sizeof(ops));
ops.acpi_op_add = 1;
- acpi_bus_scan(handle, &ops, child);
- return 0;
+ return acpi_bus_scan(handle, &ops, child);
}
EXPORT_SYMBOL(acpi_bus_add);
@@ -1357,11 +1390,13 @@ int acpi_bus_start(struct acpi_device *device)
{
struct acpi_bus_ops ops;
+ if (!device)
+ return -EINVAL;
+
memset(&ops, 0, sizeof(ops));
ops.acpi_op_start = 1;
- acpi_bus_scan(device->handle, &ops, NULL);
- return 0;
+ return acpi_bus_scan(device->handle, &ops, NULL);
}
EXPORT_SYMBOL(acpi_bus_start);
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 79d33d908b5a..f74834a544fd 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -552,8 +552,17 @@ static void acpi_hibernation_leave(void)
hibernate_nvs_restore();
}
-static void acpi_pm_enable_gpes(void)
+static int acpi_pm_pre_restore(void)
{
+ acpi_disable_all_gpes();
+ acpi_os_wait_events_complete(NULL);
+ acpi_ec_suspend_transactions();
+ return 0;
+}
+
+static void acpi_pm_restore_cleanup(void)
+{
+ acpi_ec_resume_transactions();
acpi_enable_all_runtime_gpes();
}
@@ -565,8 +574,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops = {
.prepare = acpi_pm_prepare,
.enter = acpi_hibernation_enter,
.leave = acpi_hibernation_leave,
- .pre_restore = acpi_pm_disable_gpes,
- .restore_cleanup = acpi_pm_enable_gpes,
+ .pre_restore = acpi_pm_pre_restore,
+ .restore_cleanup = acpi_pm_restore_cleanup,
};
/**
@@ -618,8 +627,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops_old = {
.prepare = acpi_pm_disable_gpes,
.enter = acpi_hibernation_enter,
.leave = acpi_hibernation_leave,
- .pre_restore = acpi_pm_disable_gpes,
- .restore_cleanup = acpi_pm_enable_gpes,
+ .pre_restore = acpi_pm_pre_restore,
+ .restore_cleanup = acpi_pm_restore_cleanup,
.recover = acpi_pm_finish,
};
#endif /* CONFIG_HIBERNATION */
@@ -745,9 +754,18 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
return -ENODEV;
}
- error = enable ?
- acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) :
- acpi_disable_wakeup_device_power(adev);
+ if (enable) {
+ error = acpi_enable_wakeup_device_power(adev,
+ acpi_target_sleep_state);
+ if (!error)
+ acpi_enable_gpe(adev->wakeup.gpe_device,
+ adev->wakeup.gpe_number,
+ ACPI_GPE_TYPE_WAKE);
+ } else {
+ acpi_disable_gpe(adev->wakeup.gpe_device, adev->wakeup.gpe_number,
+ ACPI_GPE_TYPE_WAKE);
+ error = acpi_disable_wakeup_device_power(adev);
+ }
if (!error)
dev_info(dev, "wake-up capability %s by ACPI\n",
enable ? "enabled" : "disabled");
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index d11282975f35..743f2445e2a1 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -101,6 +101,7 @@ static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
struct acpi_table_header *header = NULL;
struct acpi_table_attr *attr = NULL;
+ sysfs_attr_init(&table_attr->attr.attr);
if (table_header->signature[0] != '\0')
memcpy(table_attr->name, table_header->signature,
ACPI_NAME_SIZE);
@@ -387,10 +388,10 @@ static ssize_t counter_set(struct kobject *kobj,
if (index < num_gpes) {
if (!strcmp(buf, "disable\n") &&
(status & ACPI_EVENT_FLAG_ENABLED))
- result = acpi_disable_gpe(handle, index);
+ result = acpi_set_gpe(handle, index, ACPI_GPE_DISABLE);
else if (!strcmp(buf, "enable\n") &&
!(status & ACPI_EVENT_FLAG_ENABLED))
- result = acpi_enable_gpe(handle, index);
+ result = acpi_set_gpe(handle, index, ACPI_GPE_ENABLE);
else if (!strcmp(buf, "clear\n") &&
(status & ACPI_EVENT_FLAG_SET))
result = acpi_clear_gpe(handle, index, ACPI_NOT_ISR);
@@ -475,6 +476,7 @@ void acpi_irq_stats_init(void)
goto fail;
strncpy(name, buffer, strlen(buffer) + 1);
+ sysfs_attr_init(&counter_attrs[i].attr);
counter_attrs[i].attr.name = name;
counter_attrs[i].attr.mode = 0644;
counter_attrs[i].show = counter_show;
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index f336bca7c450..8a0ed2800e63 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -213,7 +213,7 @@ acpi_table_parse_entries(char *id,
unsigned long table_end;
acpi_size tbl_size;
- if (acpi_disabled)
+ if (acpi_disabled && !acpi_ht)
return -ENODEV;
if (!handler)
@@ -280,7 +280,7 @@ int __init acpi_table_parse(char *id, acpi_table_handler handler)
struct acpi_table_header *table = NULL;
acpi_size tbl_size;
- if (acpi_disabled)
+ if (acpi_disabled && !acpi_ht)
return -ENODEV;
if (!handler)
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 9073ada88835..5d3893558cf7 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -368,7 +368,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
int valid = 0;
int i;
- /* Critical Shutdown (required) */
+ /* Critical Shutdown */
if (flag & ACPI_TRIPS_CRITICAL) {
status = acpi_evaluate_integer(tz->device->handle,
"_CRT", NULL, &tmp);
@@ -379,17 +379,19 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
* Below zero (Celsius) values clearly aren't right for sure..
* ... so lets discard those as invalid.
*/
- if (ACPI_FAILURE(status) ||
- tz->trips.critical.temperature <= 2732) {
+ if (ACPI_FAILURE(status)) {
+ tz->trips.critical.flags.valid = 0;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "No critical threshold\n"));
+ } else if (tmp <= 2732) {
+ printk(KERN_WARNING FW_BUG "Invalid critical threshold "
+ "(%llu)\n", tmp);
tz->trips.critical.flags.valid = 0;
- ACPI_EXCEPTION((AE_INFO, status,
- "No or invalid critical threshold"));
- return -ENODEV;
} else {
tz->trips.critical.flags.valid = 1;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Found critical threshold [%lu]\n",
- tz->trips.critical.temperature));
+ "Found critical threshold [%lu]\n",
+ tz->trips.critical.temperature));
}
if (tz->trips.critical.flags.valid == 1) {
if (crt == -1) {
@@ -575,7 +577,23 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
{
- return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
+ int i, valid, ret = acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
+
+ if (ret)
+ return ret;
+
+ valid = tz->trips.critical.flags.valid |
+ tz->trips.hot.flags.valid |
+ tz->trips.passive.flags.valid;
+
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
+ valid |= tz->trips.active[i].flags.valid;
+
+ if (!valid) {
+ printk(KERN_WARNING FW_BUG "No valid trip found\n");
+ return -ENODEV;
+ }
+ return 0;
}
static void acpi_thermal_check(void *data)
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 811fec10462b..c9a49f4747e6 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -107,12 +107,12 @@ acpi_extract_package(union acpi_object *package,
case ACPI_TYPE_INTEGER:
switch (format_string[i]) {
case 'N':
- size_required += sizeof(acpi_integer);
- tail_offset += sizeof(acpi_integer);
+ size_required += sizeof(u64);
+ tail_offset += sizeof(u64);
break;
case 'S':
size_required +=
- sizeof(char *) + sizeof(acpi_integer) +
+ sizeof(char *) + sizeof(u64) +
sizeof(char);
tail_offset += sizeof(char *);
break;
@@ -193,17 +193,17 @@ acpi_extract_package(union acpi_object *package,
case ACPI_TYPE_INTEGER:
switch (format_string[i]) {
case 'N':
- *((acpi_integer *) head) =
+ *((u64 *) head) =
element->integer.value;
- head += sizeof(acpi_integer);
+ head += sizeof(u64);
break;
case 'S':
pointer = (u8 **) head;
*pointer = tail;
- *((acpi_integer *) tail) =
+ *((u64 *) tail) =
element->integer.value;
- head += sizeof(acpi_integer *);
- tail += sizeof(acpi_integer);
+ head += sizeof(u64 *);
+ tail += sizeof(u64);
/* NULL terminate string */
*tail = (char)0;
tail += sizeof(char);
@@ -289,51 +289,6 @@ acpi_evaluate_integer(acpi_handle handle,
EXPORT_SYMBOL(acpi_evaluate_integer);
-#if 0
-acpi_status
-acpi_evaluate_string(acpi_handle handle,
- acpi_string pathname,
- acpi_object_list * arguments, acpi_string * data)
-{
- acpi_status status = AE_OK;
- acpi_object *element = NULL;
- acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
-
- if (!data)
- return AE_BAD_PARAMETER;
-
- status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
- if (ACPI_FAILURE(status)) {
- acpi_util_eval_error(handle, pathname, status);
- return status;
- }
-
- element = (acpi_object *) buffer.pointer;
-
- if ((element->type != ACPI_TYPE_STRING)
- || (element->type != ACPI_TYPE_BUFFER)
- || !element->string.length) {
- acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
- return AE_BAD_DATA;
- }
-
- *data = kzalloc(element->string.length + 1, GFP_KERNEL);
- if (!data) {
- printk(KERN_ERR PREFIX "Memory allocation\n");
- return -ENOMEM;
- }
-
- memcpy(*data, element->string.pointer, element->string.length);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%s]\n", *data));
-
- kfree(buffer.pointer);
-
- return AE_OK;
-}
-#endif
-
acpi_status
acpi_evaluate_reference(acpi_handle handle,
acpi_string pathname,
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 72e76b4b6538..2ff2b6ab5b6c 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -78,6 +78,13 @@ MODULE_LICENSE("GPL");
static int brightness_switch_enabled = 1;
module_param(brightness_switch_enabled, bool, 0644);
+/*
+ * By default, we don't allow duplicate ACPI video bus devices
+ * under the same VGA controller
+ */
+static int allow_duplicates;
+module_param(allow_duplicates, bool, 0644);
+
static int register_count = 0;
static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device, int type);
@@ -320,7 +327,7 @@ static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
int level);
static int acpi_video_device_lcd_get_level_current(
struct acpi_video_device *device,
- unsigned long long *level);
+ unsigned long long *level, int init);
static int acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event);
static int acpi_video_switch_brightness(struct acpi_video_device *device,
@@ -338,7 +345,7 @@ static int acpi_video_get_brightness(struct backlight_device *bd)
struct acpi_video_device *vd =
(struct acpi_video_device *)bl_get_data(bd);
- if (acpi_video_device_lcd_get_level_current(vd, &cur_level))
+ if (acpi_video_device_lcd_get_level_current(vd, &cur_level, 0))
return -EINVAL;
for (i = 2; i < vd->brightness->count; i++) {
if (vd->brightness->levels[i] == cur_level)
@@ -407,7 +414,7 @@ static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsig
unsigned long long level;
int offset;
- if (acpi_video_device_lcd_get_level_current(video, &level))
+ if (acpi_video_device_lcd_get_level_current(video, &level, 0))
return -EINVAL;
for (offset = 2; offset < video->brightness->count; offset++)
if (level == video->brightness->levels[offset]) {
@@ -602,7 +609,7 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
static int
acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
- unsigned long long *level)
+ unsigned long long *level, int init)
{
acpi_status status = AE_OK;
int i;
@@ -626,10 +633,16 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
device->brightness->curr = *level;
return 0;
}
- /* BQC returned an invalid level. Stop using it. */
- ACPI_WARNING((AE_INFO, "%s returned an invalid level",
- buf));
- device->cap._BQC = device->cap._BCQ = 0;
+ if (!init) {
+ /*
+ * BQC returned an invalid level.
+ * Stop using it.
+ */
+ ACPI_WARNING((AE_INFO,
+ "%s returned an invalid level",
+ buf));
+ device->cap._BQC = device->cap._BCQ = 0;
+ }
} else {
/* Fixme:
* should we return an error or ignore this failure?
@@ -752,7 +765,7 @@ acpi_video_bus_POST_options(struct acpi_video_bus *video,
static int
acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
{
- acpi_integer status = 0;
+ u64 status = 0;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
@@ -885,7 +898,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
if (!device->cap._BQC)
goto set_level;
- result = acpi_video_device_lcd_get_level_current(device, &level_old);
+ result = acpi_video_device_lcd_get_level_current(device, &level_old, 1);
if (result)
goto out_free_levels;
@@ -896,7 +909,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
if (result)
goto out_free_levels;
- result = acpi_video_device_lcd_get_level_current(device, &level);
+ result = acpi_video_device_lcd_get_level_current(device, &level, 0);
if (result)
goto out_free_levels;
@@ -1989,7 +2002,7 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
goto out;
result = acpi_video_device_lcd_get_level_current(device,
- &level_current);
+ &level_current, 0);
if (result)
goto out;
@@ -2239,11 +2252,47 @@ static int acpi_video_resume(struct acpi_device *device)
return AE_OK;
}
+static acpi_status
+acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
+ void **return_value)
+{
+ struct acpi_device *device = context;
+ struct acpi_device *sibling;
+ int result;
+
+ if (handle == device->handle)
+ return AE_CTRL_TERMINATE;
+
+ result = acpi_bus_get_device(handle, &sibling);
+ if (result)
+ return AE_OK;
+
+ if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME))
+ return AE_ALREADY_EXISTS;
+
+ return AE_OK;
+}
+
static int acpi_video_bus_add(struct acpi_device *device)
{
struct acpi_video_bus *video;
struct input_dev *input;
int error;
+ acpi_status status;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
+ device->parent->handle, 1,
+ acpi_video_bus_match, NULL,
+ device, NULL);
+ if (status == AE_ALREADY_EXISTS) {
+ printk(KERN_WARNING FW_BUG
+ "Duplicate ACPI video bus devices for the"
+ " same VGA controller, please try module "
+ "parameter \"video.allow_duplicates=1\""
+ "if the current driver doesn't work.\n");
+ if (!allow_duplicates)
+ return -ENODEV;
+ }
video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
if (!video)
diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c
index e0ee0c036f5a..4b9d339a6e28 100644
--- a/drivers/acpi/wakeup.c
+++ b/drivers/acpi/wakeup.c
@@ -21,12 +21,12 @@
ACPI_MODULE_NAME("wakeup_devices")
/**
- * acpi_enable_wakeup_device_prep - prepare wakeup devices
- * @sleep_state: ACPI state
- * Enable all wakup devices power if the devices' wakeup level
- * is higher than requested sleep level
+ * acpi_enable_wakeup_device_prep - Prepare wake-up devices.
+ * @sleep_state: ACPI system sleep state.
+ *
+ * Enable all wake-up devices' power, unless the requested system sleep state is
+ * too deep.
*/
-
void acpi_enable_wakeup_device_prep(u8 sleep_state)
{
struct list_head *node, *next;
@@ -36,9 +36,8 @@ void acpi_enable_wakeup_device_prep(u8 sleep_state)
struct acpi_device,
wakeup_list);
- if (!dev->wakeup.flags.valid ||
- !dev->wakeup.state.enabled ||
- (sleep_state > (u32) dev->wakeup.sleep_state))
+ if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled
+ || (sleep_state > (u32) dev->wakeup.sleep_state))
continue;
acpi_enable_wakeup_device_power(dev, sleep_state);
@@ -46,9 +45,12 @@ void acpi_enable_wakeup_device_prep(u8 sleep_state)
}
/**
- * acpi_enable_wakeup_device - enable wakeup devices
- * @sleep_state: ACPI state
- * Enable all wakup devices's GPE
+ * acpi_enable_wakeup_device - Enable wake-up device GPEs.
+ * @sleep_state: ACPI system sleep state.
+ *
+ * Enable all wake-up devices' GPEs, with the assumption that
+ * acpi_disable_all_gpes() was executed before, so we don't need to disable any
+ * GPEs here.
*/
void acpi_enable_wakeup_device(u8 sleep_state)
{
@@ -65,29 +67,22 @@ void acpi_enable_wakeup_device(u8 sleep_state)
if (!dev->wakeup.flags.valid)
continue;
- /* If users want to disable run-wake GPE,
- * we only disable it for wake and leave it for runtime
- */
if ((!dev->wakeup.state.enabled && !dev->wakeup.prepare_count)
- || sleep_state > (u32) dev->wakeup.sleep_state) {
- if (dev->wakeup.flags.run_wake) {
- /* set_gpe_type will disable GPE, leave it like that */
- acpi_set_gpe_type(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number,
- ACPI_GPE_TYPE_RUNTIME);
- }
+ || sleep_state > (u32) dev->wakeup.sleep_state)
continue;
- }
- if (!dev->wakeup.flags.run_wake)
- acpi_enable_gpe(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number);
+
+ /* The wake-up power should have been enabled already. */
+ acpi_set_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
+ ACPI_GPE_ENABLE);
}
}
/**
- * acpi_disable_wakeup_device - disable devices' wakeup capability
- * @sleep_state: ACPI state
- * Disable all wakup devices's GPE and wakeup capability
+ * acpi_disable_wakeup_device - Disable devices' wakeup capability.
+ * @sleep_state: ACPI system sleep state.
+ *
+ * This function only affects devices with wakeup.state.enabled set, which means
+ * that it reverses the changes made by acpi_enable_wakeup_device_prep().
*/
void acpi_disable_wakeup_device(u8 sleep_state)
{
@@ -97,30 +92,11 @@ void acpi_disable_wakeup_device(u8 sleep_state)
struct acpi_device *dev =
container_of(node, struct acpi_device, wakeup_list);
- if (!dev->wakeup.flags.valid)
- continue;
-
- if ((!dev->wakeup.state.enabled && !dev->wakeup.prepare_count)
- || sleep_state > (u32) dev->wakeup.sleep_state) {
- if (dev->wakeup.flags.run_wake) {
- acpi_set_gpe_type(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number,
- ACPI_GPE_TYPE_WAKE_RUN);
- /* Re-enable it, since set_gpe_type will disable it */
- acpi_enable_gpe(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number);
- }
+ if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled
+ || (sleep_state > (u32) dev->wakeup.sleep_state))
continue;
- }
acpi_disable_wakeup_device_power(dev);
- /* Never disable run-wake GPE */
- if (!dev->wakeup.flags.run_wake) {
- acpi_disable_gpe(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number);
- acpi_clear_gpe(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number, ACPI_NOT_ISR);
- }
}
}
@@ -134,13 +110,11 @@ int __init acpi_wakeup_device_init(void)
struct acpi_device,
wakeup_list);
/* In case user doesn't load button driver */
- if (!dev->wakeup.flags.run_wake || dev->wakeup.state.enabled)
+ if (!dev->wakeup.flags.always_enabled ||
+ dev->wakeup.state.enabled)
continue;
- acpi_set_gpe_type(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number,
- ACPI_GPE_TYPE_WAKE_RUN);
- acpi_enable_gpe(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number);
+ acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
+ ACPI_GPE_TYPE_WAKE);
dev->wakeup.state.enabled = 1;
}
mutex_unlock(&acpi_device_lock);
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 56c6374a3989..01c52c415bdc 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -446,9 +446,9 @@ config PATA_JMICRON
config PATA_LEGACY
tristate "Legacy ISA PATA support (Experimental)"
- depends on ISA && EXPERIMENTAL
+ depends on (ISA || PCI) && EXPERIMENTAL
help
- This option enables support for ISA/VLB bus legacy PATA
+ This option enables support for ISA/VLB/PCI bus legacy PATA
ports and allows them to be accessed via the new ATA layer.
If unsure, say N.
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index b8bea100a160..6bd930b93bcc 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -93,6 +93,9 @@ enum {
AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
AHCI_RX_FIS_SZ,
+ AHCI_PORT_PRIV_FBS_DMA_SZ = AHCI_CMD_SLOT_SZ +
+ AHCI_CMD_TBL_AR_SZ +
+ (AHCI_RX_FIS_SZ * 16),
AHCI_IRQ_ON_SG = (1 << 31),
AHCI_CMD_ATAPI = (1 << 5),
AHCI_CMD_WRITE = (1 << 6),
@@ -170,6 +173,7 @@ enum {
PORT_SCR_ERR = 0x30, /* SATA phy register: SError */
PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */
+ PORT_FBS = 0x40, /* FIS-based Switching */
/* PORT_IRQ_{STAT,MASK} bits */
PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
@@ -208,6 +212,7 @@ enum {
PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */
PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */
PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
+ PORT_CMD_FBSCP = (1 << 22), /* FBS Capable Port */
PORT_CMD_PMP = (1 << 17), /* PMP attached */
PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
@@ -222,6 +227,14 @@ enum {
PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
+ PORT_FBS_DWE_OFFSET = 16, /* FBS device with error offset */
+ PORT_FBS_ADO_OFFSET = 12, /* FBS active dev optimization offset */
+ PORT_FBS_DEV_OFFSET = 8, /* FBS device to issue offset */
+ PORT_FBS_DEV_MASK = (0xf << PORT_FBS_DEV_OFFSET), /* FBS.DEV */
+ PORT_FBS_SDE = (1 << 2), /* FBS single device error */
+ PORT_FBS_DEC = (1 << 1), /* FBS device error clear */
+ PORT_FBS_EN = (1 << 0), /* Enable FBS */
+
/* hpriv->flags bits */
AHCI_HFLAG_NO_NCQ = (1 << 0),
AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */
@@ -304,6 +317,9 @@ struct ahci_port_priv {
unsigned int ncq_saw_dmas:1;
unsigned int ncq_saw_sdb:1;
u32 intr_mask; /* interrupts to enable */
+ bool fbs_supported; /* set iff FBS is supported */
+ bool fbs_enabled; /* set iff FBS is enabled */
+ int fbs_last_dev; /* save FBS.DEV of last FIS */
/* enclosure management info per PM slot */
struct ahci_em_priv em_priv[EM_MAX_SLOTS];
};
@@ -315,9 +331,12 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
static int ahci_port_start(struct ata_port *ap);
static void ahci_port_stop(struct ata_port *ap);
+static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc);
static void ahci_qc_prep(struct ata_queued_cmd *qc);
static void ahci_freeze(struct ata_port *ap);
static void ahci_thaw(struct ata_port *ap);
+static void ahci_enable_fbs(struct ata_port *ap);
+static void ahci_disable_fbs(struct ata_port *ap);
static void ahci_pmp_attach(struct ata_port *ap);
static void ahci_pmp_detach(struct ata_port *ap);
static int ahci_softreset(struct ata_link *link, unsigned int *class,
@@ -356,10 +375,10 @@ static ssize_t ahci_show_host_version(struct device *dev,
static ssize_t ahci_show_port_cmd(struct device *dev,
struct device_attribute *attr, char *buf);
-DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
-DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
-DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
-DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
+static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
+static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
+static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
+static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
static struct device_attribute *ahci_shost_attrs[] = {
&dev_attr_link_power_management_policy,
@@ -390,7 +409,7 @@ static struct scsi_host_template ahci_sht = {
static struct ata_port_operations ahci_ops = {
.inherits = &sata_pmp_port_ops,
- .qc_defer = sata_pmp_qc_defer_cmd_switch,
+ .qc_defer = ahci_pmp_qc_defer,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
.qc_fill_rtf = ahci_qc_fill_rtf,
@@ -570,6 +589,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
+ { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
+ { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
+ { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
+ { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */
+ { PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
+ { PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -2045,6 +2070,17 @@ static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
return si;
}
+static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+
+ if (!sata_pmp_attached(ap) || pp->fbs_enabled)
+ return ata_std_qc_defer(qc);
+ else
+ return sata_pmp_qc_defer_cmd_switch(qc);
+}
+
static void ahci_qc_prep(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
@@ -2083,6 +2119,31 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
ahci_fill_cmd_slot(pp, qc->tag, opts);
}
+static void ahci_fbs_dec_intr(struct ata_port *ap)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs = readl(port_mmio + PORT_FBS);
+ int retries = 3;
+
+ DPRINTK("ENTER\n");
+ BUG_ON(!pp->fbs_enabled);
+
+ /* time to wait for DEC is not specified by AHCI spec,
+ * add a retry loop for safety.
+ */
+ writel(fbs | PORT_FBS_DEC, port_mmio + PORT_FBS);
+ fbs = readl(port_mmio + PORT_FBS);
+ while ((fbs & PORT_FBS_DEC) && retries--) {
+ udelay(1);
+ fbs = readl(port_mmio + PORT_FBS);
+ }
+
+ if (fbs & PORT_FBS_DEC)
+ dev_printk(KERN_ERR, ap->host->dev,
+ "failed to clear device error\n");
+}
+
static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
@@ -2091,12 +2152,26 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
struct ata_link *link = NULL;
struct ata_queued_cmd *active_qc;
struct ata_eh_info *active_ehi;
+ bool fbs_need_dec = false;
u32 serror;
- /* determine active link */
- ata_for_each_link(link, ap, EDGE)
- if (ata_link_active(link))
- break;
+ /* determine active link with error */
+ if (pp->fbs_enabled) {
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs = readl(port_mmio + PORT_FBS);
+ int pmp = fbs >> PORT_FBS_DWE_OFFSET;
+
+ if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links) &&
+ ata_link_online(&ap->pmp_link[pmp])) {
+ link = &ap->pmp_link[pmp];
+ fbs_need_dec = true;
+ }
+
+ } else
+ ata_for_each_link(link, ap, EDGE)
+ if (ata_link_active(link))
+ break;
+
if (!link)
link = &ap->link;
@@ -2153,8 +2228,13 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
}
if (irq_stat & PORT_IRQ_IF_ERR) {
- host_ehi->err_mask |= AC_ERR_ATA_BUS;
- host_ehi->action |= ATA_EH_RESET;
+ if (fbs_need_dec)
+ active_ehi->err_mask |= AC_ERR_DEV;
+ else {
+ host_ehi->err_mask |= AC_ERR_ATA_BUS;
+ host_ehi->action |= ATA_EH_RESET;
+ }
+
ata_ehi_push_desc(host_ehi, "interface fatal error");
}
@@ -2169,7 +2249,10 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
if (irq_stat & PORT_IRQ_FREEZE)
ata_port_freeze(ap);
- else
+ else if (fbs_need_dec) {
+ ata_link_abort(link);
+ ahci_fbs_dec_intr(ap);
+ } else
ata_port_abort(ap);
}
@@ -2222,12 +2305,19 @@ static void ahci_port_intr(struct ata_port *ap)
/* If the 'N' bit in word 0 of the FIS is set,
* we just received asynchronous notification.
* Tell libata about it.
+ *
+ * Lack of SNotification should not appear in
+ * ahci 1.2, so the workaround is unnecessary
+ * when FBS is enabled.
*/
- const __le32 *f = pp->rx_fis + RX_FIS_SDB;
- u32 f0 = le32_to_cpu(f[0]);
-
- if (f0 & (1 << 15))
- sata_async_notification(ap);
+ if (pp->fbs_enabled)
+ WARN_ON_ONCE(1);
+ else {
+ const __le32 *f = pp->rx_fis + RX_FIS_SDB;
+ u32 f0 = le32_to_cpu(f[0]);
+ if (f0 & (1 << 15))
+ sata_async_notification(ap);
+ }
}
}
@@ -2321,6 +2411,15 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
if (qc->tf.protocol == ATA_PROT_NCQ)
writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
+
+ if (pp->fbs_enabled && pp->fbs_last_dev != qc->dev->link->pmp) {
+ u32 fbs = readl(port_mmio + PORT_FBS);
+ fbs &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC);
+ fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET;
+ writel(fbs, port_mmio + PORT_FBS);
+ pp->fbs_last_dev = qc->dev->link->pmp;
+ }
+
writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
ahci_sw_activity(qc->dev->link);
@@ -2333,6 +2432,9 @@ static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
struct ahci_port_priv *pp = qc->ap->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ if (pp->fbs_enabled)
+ d2h_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
+
ata_tf_from_fis(d2h_fis, &qc->result_tf);
return true;
}
@@ -2381,6 +2483,71 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
ahci_kick_engine(ap);
}
+static void ahci_enable_fbs(struct ata_port *ap)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs;
+ int rc;
+
+ if (!pp->fbs_supported)
+ return;
+
+ fbs = readl(port_mmio + PORT_FBS);
+ if (fbs & PORT_FBS_EN) {
+ pp->fbs_enabled = true;
+ pp->fbs_last_dev = -1; /* initialization */
+ return;
+ }
+
+ rc = ahci_stop_engine(ap);
+ if (rc)
+ return;
+
+ writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS);
+ fbs = readl(port_mmio + PORT_FBS);
+ if (fbs & PORT_FBS_EN) {
+ dev_printk(KERN_INFO, ap->host->dev, "FBS is enabled.\n");
+ pp->fbs_enabled = true;
+ pp->fbs_last_dev = -1; /* initialization */
+ } else
+ dev_printk(KERN_ERR, ap->host->dev, "Failed to enable FBS\n");
+
+ ahci_start_engine(ap);
+}
+
+static void ahci_disable_fbs(struct ata_port *ap)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs;
+ int rc;
+
+ if (!pp->fbs_supported)
+ return;
+
+ fbs = readl(port_mmio + PORT_FBS);
+ if ((fbs & PORT_FBS_EN) == 0) {
+ pp->fbs_enabled = false;
+ return;
+ }
+
+ rc = ahci_stop_engine(ap);
+ if (rc)
+ return;
+
+ writel(fbs & ~PORT_FBS_EN, port_mmio + PORT_FBS);
+ fbs = readl(port_mmio + PORT_FBS);
+ if (fbs & PORT_FBS_EN)
+ dev_printk(KERN_ERR, ap->host->dev, "Failed to disable FBS\n");
+ else {
+ dev_printk(KERN_INFO, ap->host->dev, "FBS is disabled.\n");
+ pp->fbs_enabled = false;
+ }
+
+ ahci_start_engine(ap);
+}
+
static void ahci_pmp_attach(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
@@ -2391,6 +2558,8 @@ static void ahci_pmp_attach(struct ata_port *ap)
cmd |= PORT_CMD_PMP;
writel(cmd, port_mmio + PORT_CMD);
+ ahci_enable_fbs(ap);
+
pp->intr_mask |= PORT_IRQ_BAD_PMP;
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
@@ -2401,6 +2570,8 @@ static void ahci_pmp_detach(struct ata_port *ap)
struct ahci_port_priv *pp = ap->private_data;
u32 cmd;
+ ahci_disable_fbs(ap);
+
cmd = readl(port_mmio + PORT_CMD);
cmd &= ~PORT_CMD_PMP;
writel(cmd, port_mmio + PORT_CMD);
@@ -2492,20 +2663,40 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
static int ahci_port_start(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
struct device *dev = ap->host->dev;
struct ahci_port_priv *pp;
void *mem;
dma_addr_t mem_dma;
+ size_t dma_sz, rx_fis_sz;
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
- mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
- GFP_KERNEL);
+ /* check FBS capability */
+ if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) {
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 cmd = readl(port_mmio + PORT_CMD);
+ if (cmd & PORT_CMD_FBSCP)
+ pp->fbs_supported = true;
+ else
+ dev_printk(KERN_WARNING, dev,
+ "The port is not capable of FBS\n");
+ }
+
+ if (pp->fbs_supported) {
+ dma_sz = AHCI_PORT_PRIV_FBS_DMA_SZ;
+ rx_fis_sz = AHCI_RX_FIS_SZ * 16;
+ } else {
+ dma_sz = AHCI_PORT_PRIV_DMA_SZ;
+ rx_fis_sz = AHCI_RX_FIS_SZ;
+ }
+
+ mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL);
if (!mem)
return -ENOMEM;
- memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
+ memset(mem, 0, dma_sz);
/*
* First item in chunk of DMA memory: 32-slot command table,
@@ -2523,8 +2714,8 @@ static int ahci_port_start(struct ata_port *ap)
pp->rx_fis = mem;
pp->rx_fis_dma = mem_dma;
- mem += AHCI_RX_FIS_SZ;
- mem_dma += AHCI_RX_FIS_SZ;
+ mem += rx_fis_sz;
+ mem_dma += rx_fis_sz;
/*
* Third item: data area for storing a single command
@@ -2868,6 +3059,21 @@ static bool ahci_broken_suspend(struct pci_dev *pdev)
},
.driver_data = "F.23", /* cutoff BIOS version */
},
+ /*
+ * Acer eMachines G725 has the same problem. BIOS
+ * V1.03 is known to be broken. V3.04 is known to
+ * work. Inbetween, there are V1.06, V2.06 and V3.03
+ * that we don't have much idea about. For now,
+ * blacklist anything older than V3.04.
+ */
+ {
+ .ident = "G725",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "eMachines"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "eMachines G725"),
+ },
+ .driver_data = "V3.04", /* cutoff BIOS version */
+ },
{ } /* terminate list */
};
const struct dmi_system_id *dmi = dmi_first_match(sysids);
@@ -3067,8 +3273,16 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
ahci_save_initial_config(pdev, hpriv);
/* prepare host */
- if (hpriv->cap & HOST_CAP_NCQ)
- pi.flags |= ATA_FLAG_NCQ | ATA_FLAG_FPDMA_AA;
+ if (hpriv->cap & HOST_CAP_NCQ) {
+ pi.flags |= ATA_FLAG_NCQ;
+ /* Auto-activate optimization is supposed to be supported on
+ all AHCI controllers indicating NCQ support, but it seems
+ to be broken at least on some NVIDIA MCP79 chipsets.
+ Until we get info on which NVIDIA chipsets don't have this
+ issue, if any, disable AA on all NVIDIA AHCIs. */
+ if (pdev->vendor != PCI_VENDOR_ID_NVIDIA)
+ pi.flags |= ATA_FLAG_FPDMA_AA;
+ }
if (hpriv->cap & HOST_CAP_PMP)
pi.flags |= ATA_FLAG_PMP;
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 12e26c3c68e3..33fb614f9784 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -155,7 +155,7 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
return rc;
pcim_pin_device(dev);
}
- return ata_pci_sff_init_one(dev, ppi, &generic_sht, NULL);
+ return ata_pci_sff_init_one(dev, ppi, &generic_sht, NULL, 0);
}
static struct pci_device_id ata_generic[] = {
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 6f3f2257d0f0..c33806654e46 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -173,6 +173,7 @@ static int piix_sidpr_scr_read(struct ata_link *link,
unsigned int reg, u32 *val);
static int piix_sidpr_scr_write(struct ata_link *link,
unsigned int reg, u32 val);
+static bool piix_irq_check(struct ata_port *ap);
#ifdef CONFIG_PM
static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
static int piix_pci_device_resume(struct pci_dev *pdev);
@@ -291,6 +292,14 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x3b2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
/* SATA Controller IDE (PCH) */
{ 0x8086, 0x3b2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+ /* SATA Controller IDE (CPT) */
+ { 0x8086, 0x1c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+ /* SATA Controller IDE (CPT) */
+ { 0x8086, 0x1c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+ /* SATA Controller IDE (CPT) */
+ { 0x8086, 0x1c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (CPT) */
+ { 0x8086, 0x1c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
{ } /* terminate list */
};
@@ -309,8 +318,13 @@ static struct scsi_host_template piix_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
-static struct ata_port_operations piix_pata_ops = {
+static struct ata_port_operations piix_sata_ops = {
.inherits = &ata_bmdma32_port_ops,
+ .sff_irq_check = piix_irq_check,
+};
+
+static struct ata_port_operations piix_pata_ops = {
+ .inherits = &piix_sata_ops,
.cable_detect = ata_cable_40wire,
.set_piomode = piix_set_piomode,
.set_dmamode = piix_set_dmamode,
@@ -328,10 +342,6 @@ static struct ata_port_operations ich_pata_ops = {
.set_dmamode = ich_set_dmamode,
};
-static struct ata_port_operations piix_sata_ops = {
- .inherits = &ata_bmdma32_port_ops,
-};
-
static struct ata_port_operations piix_sidpr_sata_ops = {
.inherits = &piix_sata_ops,
.hardreset = sata_std_hardreset,
@@ -962,6 +972,14 @@ static int piix_sidpr_scr_write(struct ata_link *link,
return 0;
}
+static bool piix_irq_check(struct ata_port *ap)
+{
+ if (unlikely(!ap->ioaddr.bmdma_addr))
+ return false;
+
+ return ap->ops->bmdma_status(ap) & ATA_DMA_INTR;
+}
+
#ifdef CONFIG_PM
static int piix_broken_suspend(void)
{
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 1245838ac13d..292fdbc0431a 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -64,7 +64,7 @@ void ata_acpi_associate_sata_port(struct ata_port *ap)
WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA));
if (!sata_pmp_attached(ap)) {
- acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+ u64 adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
ap->link.device->acpi_handle =
acpi_get_child(ap->host->acpi_handle, adr);
@@ -74,7 +74,7 @@ void ata_acpi_associate_sata_port(struct ata_port *ap)
ap->link.device->acpi_handle = NULL;
ata_for_each_link(link, ap, EDGE) {
- acpi_integer adr = SATA_ADR(ap->port_no, link->pmp);
+ u64 adr = SATA_ADR(ap->port_no, link->pmp);
link->device->acpi_handle =
acpi_get_child(ap->host->acpi_handle, adr);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 6728328f3bea..4a28420efff2 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2232,7 +2232,7 @@ retry:
* Some drives were very specific about that exact sequence.
*
* Note that ATA4 says lba is mandatory so the second check
- * shoud never trigger.
+ * should never trigger.
*/
if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
err_mask = ata_dev_init_params(dev, id[3], id[6]);
@@ -3211,6 +3211,7 @@ const struct ata_timing *ata_timing_find_mode(u8 xfer_mode)
int ata_timing_compute(struct ata_device *adev, unsigned short speed,
struct ata_timing *t, int T, int UT)
{
+ const u16 *id = adev->id;
const struct ata_timing *s;
struct ata_timing p;
@@ -3228,14 +3229,18 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
* PIO/MW_DMA cycle timing.
*/
- if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
+ if (id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
memset(&p, 0, sizeof(p));
+
if (speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) {
- if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO];
- else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY];
- } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) {
- p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN];
- }
+ if (speed <= XFER_PIO_2)
+ p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
+ else if ((speed <= XFER_PIO_4) ||
+ (speed == XFER_PIO_5 && !ata_id_is_cfa(id)))
+ p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
+ } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+ p.cycle = id[ATA_ID_EIDE_DMA_MIN];
+
ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B);
}
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 0ea97c942ced..9f6cfac0f2cc 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2028,8 +2028,9 @@ static void ata_eh_link_autopsy(struct ata_link *link)
qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
/* determine whether the command is worth retrying */
- if (!(qc->err_mask & AC_ERR_INVALID) &&
- ((qc->flags & ATA_QCFLAG_IO) || qc->err_mask != AC_ERR_DEV))
+ if (qc->flags & ATA_QCFLAG_IO ||
+ (!(qc->err_mask & AC_ERR_INVALID) &&
+ qc->err_mask != AC_ERR_DEV))
qc->flags |= ATA_QCFLAG_RETRY;
/* accumulate error info */
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index f4ea5a8c325b..bea003a24d27 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1097,7 +1097,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
dev->flags |= ATA_DFLAG_NO_UNLOAD;
/* configure max sectors */
- blk_queue_max_sectors(sdev->request_queue, dev->max_sectors);
+ blk_queue_max_hw_sectors(sdev->request_queue, dev->max_sectors);
if (dev->class == ATA_DEV_ATAPI) {
struct request_queue *q = sdev->request_queue;
@@ -2875,7 +2875,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
* write indication (used for PIO/DMA setup), result TF is
* copied back and we don't whine too much about its failure.
*/
- tf->flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
if (scmd->sc_data_direction == DMA_TO_DEVICE)
tf->flags |= ATA_TFLAG_WRITE;
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 741065c9da67..561dec2481cb 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -893,6 +893,9 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
do_write);
}
+ if (!do_write)
+ flush_dcache_page(page);
+
qc->curbytes += qc->sect_size;
qc->cursg_ofs += qc->sect_size;
@@ -1760,24 +1763,50 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
unsigned int i;
- unsigned int handled = 0;
+ unsigned int handled = 0, polling = 0;
unsigned long flags;
/* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
spin_lock_irqsave(&host->lock, flags);
for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap;
+ struct ata_port *ap = host->ports[i];
+ struct ata_queued_cmd *qc;
- ap = host->ports[i];
- if (ap &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
+ if (unlikely(ap->flags & ATA_FLAG_DISABLED))
+ continue;
- qc = ata_qc_from_tag(ap, ap->link.active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
- (qc->flags & ATA_QCFLAG_ACTIVE))
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc) {
+ if (!(qc->tf.flags & ATA_TFLAG_POLLING))
handled |= ata_sff_host_intr(ap, qc);
+ else
+ polling |= 1 << i;
+ }
+ }
+
+ /*
+ * If no port was expecting IRQ but the controller is actually
+ * asserting IRQ line, nobody cared will ensue. Check IRQ
+ * pending status if available and clear spurious IRQ.
+ */
+ if (!handled) {
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (polling & (1 << i))
+ continue;
+
+ if (!ap->ops->sff_irq_check ||
+ !ap->ops->sff_irq_check(ap))
+ continue;
+
+ if (printk_ratelimit())
+ ata_port_printk(ap, KERN_INFO,
+ "clearing spurious IRQ\n");
+
+ ap->ops->sff_check_status(ap);
+ ap->ops->sff_irq_clear(ap);
}
}
@@ -2258,7 +2287,7 @@ EXPORT_SYMBOL_GPL(ata_sff_postreset);
* @qc: command
*
* Drain the FIFO and device of any stuck data following a command
- * failing to complete. In some cases this is neccessary before a
+ * failing to complete. In some cases this is necessary before a
* reset will recover the device.
*
*/
@@ -3008,6 +3037,7 @@ EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host);
* @ppi: array of port_info, must be enough for two ports
* @sht: scsi_host_template to use when registering the host
* @host_priv: host private_data
+ * @hflag: host flags
*
* This is a helper function which can be called from a driver's
* xxx_init_one() probe function if the hardware uses traditional
@@ -3028,8 +3058,8 @@ EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host);
* Zero on success, negative on errno-based value on error.
*/
int ata_pci_sff_init_one(struct pci_dev *pdev,
- const struct ata_port_info * const *ppi,
- struct scsi_host_template *sht, void *host_priv)
+ const struct ata_port_info * const *ppi,
+ struct scsi_host_template *sht, void *host_priv, int hflag)
{
struct device *dev = &pdev->dev;
const struct ata_port_info *pi = NULL;
@@ -3064,6 +3094,7 @@ int ata_pci_sff_init_one(struct pci_dev *pdev,
if (rc)
goto out;
host->private_data = host_priv;
+ host->flags |= hflag;
pci_set_master(pdev);
rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht);
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
index d8f35fe44421..8e5e13210426 100644
--- a/drivers/ata/pata_acpi.c
+++ b/drivers/ata/pata_acpi.c
@@ -161,7 +161,7 @@ static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev)
*
* Called when the libata layer is about to issue a command. We wrap
* this interface so that we can load the correct ATA timings if
- * neccessary.
+ * necessary.
*/
static unsigned int pacpi_qc_issue(struct ata_queued_cmd *qc)
@@ -259,7 +259,7 @@ static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
return rc;
pcim_pin_device(pdev);
}
- return ata_pci_sff_init_one(pdev, ppi, &pacpi_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &pacpi_sht, NULL, 0);
}
static const struct pci_device_id pacpi_pci_tbl[] = {
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 9434114b2ca8..dc61b72f751c 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -159,8 +159,7 @@ static void ali_fifo_control(struct ata_port *ap, struct ata_device *adev, int o
* ali_program_modes - load mode registers
* @ap: ALi channel to load
* @adev: Device the timing is for
- * @cmd: Command timing
- * @data: Data timing
+ * @t: timing data
* @ultra: UDMA timing or zero for off
*
* Loads the timing registers for cmd/data and disable UDMA if
@@ -202,8 +201,7 @@ static void ali_program_modes(struct ata_port *ap, struct ata_device *adev, stru
* @ap: ATA interface
* @adev: ATA device
*
- * Program the ALi registers for PIO mode. FIXME: add timings for
- * PIO5.
+ * Program the ALi registers for PIO mode.
*/
static void ali_set_piomode(struct ata_port *ap, struct ata_device *adev)
@@ -237,7 +235,7 @@ static void ali_set_piomode(struct ata_port *ap, struct ata_device *adev)
* @ap: ATA interface
* @adev: ATA device
*
- * FIXME: MWDMA timings
+ * Program the ALi registers for DMA mode.
*/
static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev)
@@ -585,7 +583,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
ppi[0] = &info_20_udma;
}
- return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL, 0);
}
#ifdef CONFIG_PM
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 567f3f72774e..d95eca9c547e 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -574,7 +574,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* And fire it up */
- return ata_pci_sff_init_one(pdev, ppi, &amd_sht, hpriv);
+ return ata_pci_sff_init_one(pdev, ppi, &amd_sht, hpriv, 0);
}
#ifdef CONFIG_PM
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index d332cfdb0f30..4d066d6c30fa 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -421,7 +421,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
BUG_ON(ppi[0] == NULL);
- return ata_pci_sff_init_one(pdev, ppi, &artop_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &artop_sht, NULL, 0);
}
static const struct pci_device_id artop_pci_tbl[] = {
diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c
index 41c94b1ae493..376dd380b43c 100644
--- a/drivers/ata/pata_at91.c
+++ b/drivers/ata/pata_at91.c
@@ -153,8 +153,8 @@ static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev)
/* Compute ATA timing and set it to SMC */
ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0);
if (ret) {
- dev_warn(ap->dev, "Failed to compute ATA timing %d, \
- set PIO_0 timing\n", ret);
+ dev_warn(ap->dev, "Failed to compute ATA timing %d, "
+ "set PIO_0 timing\n", ret);
set_smc_timing(ap->dev, info, &initial_timing);
} else {
set_smc_timing(ap->dev, info, &timing);
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index ae4454d4e955..cbaf2eddac6b 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -1,7 +1,7 @@
/*
* pata_atiixp.c - ATI PATA for new ATA layer
* (C) 2005 Red Hat Inc
- * (C) 2009 Bartlomiej Zolnierkiewicz
+ * (C) 2009-2010 Bartlomiej Zolnierkiewicz
*
* Based on
*
@@ -46,6 +46,8 @@ static int atiixp_cable_detect(struct ata_port *ap)
return ATA_CBL_PATA40;
}
+static DEFINE_SPINLOCK(atiixp_lock);
+
/**
* atiixp_set_pio_timing - set initial PIO mode data
* @ap: ATA interface
@@ -88,7 +90,10 @@ static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev,
static void atiixp_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
+ unsigned long flags;
+ spin_lock_irqsave(&atiixp_lock, flags);
atiixp_set_pio_timing(ap, adev, adev->pio_mode - XFER_PIO_0);
+ spin_unlock_irqrestore(&atiixp_lock, flags);
}
/**
@@ -108,6 +113,9 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
int dma = adev->dma_mode;
int dn = 2 * ap->port_no + adev->devno;
int wanted_pio;
+ unsigned long flags;
+
+ spin_lock_irqsave(&atiixp_lock, flags);
if (adev->dma_mode >= XFER_UDMA_0) {
u16 udma_mode_data;
@@ -145,6 +153,7 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
if (adev->pio_mode != wanted_pio)
atiixp_set_pio_timing(ap, adev, wanted_pio);
+ spin_unlock_irqrestore(&atiixp_lock, flags);
}
/**
@@ -237,7 +246,8 @@ static int atiixp_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (!pci_test_config_bits(pdev, &atiixp_enable_bits[i]))
ppi[i] = &ata_dummy_port_info;
- return ata_pci_sff_init_one(pdev, ppi, &atiixp_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &atiixp_sht, NULL,
+ ATA_HOST_PARALLEL_SCAN);
}
static const struct pci_device_id atiixp[] = {
diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c
index 5acf9fa9b39f..6cd5d5dd9e3b 100644
--- a/drivers/ata/pata_cmd640.c
+++ b/drivers/ata/pata_cmd640.c
@@ -223,7 +223,7 @@ static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
cmd640_hardware_init(pdev);
- return ata_pci_sff_init_one(pdev, ppi, &cmd640_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &cmd640_sht, NULL, 0);
}
#ifdef CONFIG_PM
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index 0efb1f58f255..4c81a71b8877 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -2,6 +2,7 @@
* pata_cmd64x.c - CMD64x PATA for new ATA layer
* (C) 2005 Red Hat Inc
* Alan Cox <alan@lxorguk.ukuu.org.uk>
+ * (C) 2009-2010 Bartlomiej Zolnierkiewicz
*
* Based upon
* linux/drivers/ide/pci/cmd64x.c Version 1.30 Sept 10, 2002
@@ -39,11 +40,7 @@
enum {
CFR = 0x50,
- CFR_INTR_CH0 = 0x02,
- CNTRL = 0x51,
- CNTRL_DIS_RA0 = 0x40,
- CNTRL_DIS_RA1 = 0x80,
- CNTRL_ENA_2ND = 0x08,
+ CFR_INTR_CH0 = 0x04,
CMDTIM = 0x52,
ARTTIM0 = 0x53,
DRWTIM0 = 0x54,
@@ -53,9 +50,6 @@ enum {
ARTTIM23_DIS_RA2 = 0x04,
ARTTIM23_DIS_RA3 = 0x08,
ARTTIM23_INTR_CH1 = 0x10,
- ARTTIM2 = 0x57,
- ARTTIM3 = 0x57,
- DRWTIM23 = 0x58,
DRWTIM2 = 0x58,
BRST = 0x59,
DRWTIM3 = 0x5b,
@@ -63,14 +57,11 @@ enum {
MRDMODE = 0x71,
MRDMODE_INTR_CH0 = 0x04,
MRDMODE_INTR_CH1 = 0x08,
- MRDMODE_BLK_CH0 = 0x10,
- MRDMODE_BLK_CH1 = 0x20,
BMIDESR0 = 0x72,
UDIDETCR0 = 0x73,
DTPR0 = 0x74,
BMIDECR1 = 0x78,
BMIDECSR = 0x79,
- BMIDESR1 = 0x7A,
UDIDETCR1 = 0x7B,
DTPR1 = 0x7C
};
@@ -130,8 +121,14 @@ static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 m
if (pair) {
struct ata_timing tp;
+
ata_timing_compute(pair, pair->pio_mode, &tp, T, 0);
ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
+ if (pair->dma_mode) {
+ ata_timing_compute(pair, pair->dma_mode,
+ &tp, T, 0);
+ ata_timing_merge(&tp, &t, &t, ATA_TIMING_SETUP);
+ }
}
}
@@ -147,7 +144,9 @@ static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 m
/* Now convert the clocks into values we can actually stuff into
the chip */
- if (t.recover > 1)
+ if (t.recover == 16)
+ t.recover = 0;
+ else if (t.recover > 1)
t.recover--;
else
t.recover = 15;
@@ -245,7 +244,7 @@ static void cmd648_bmdma_stop(struct ata_queued_cmd *qc)
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 dma_intr;
int dma_mask = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
- int dma_reg = ap->port_no ? ARTTIM2 : CFR;
+ int dma_reg = ap->port_no ? ARTTIM23 : CFR;
ata_bmdma_stop(qc);
@@ -368,7 +367,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
#endif
- return ata_pci_sff_init_one(pdev, ppi, &cmd64x_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &cmd64x_sht, NULL, 0);
}
#ifdef CONFIG_PM
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index c974b05e4129..738ad2e14a97 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -324,7 +324,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
ppi[1] = &info_palmax_secondary;
/* Now kick off ATA set up */
- return ata_pci_sff_init_one(pdev, ppi, &cs5530_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &cs5530_sht, NULL, 0);
}
#ifdef CONFIG_PM
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 71cef9a962d4..a02e6459fdcc 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -100,7 +100,7 @@ static int cs5535_cable_detect(struct ata_port *ap)
static void cs5535_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
static const u16 pio_timings[5] = {
- 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131
+ 0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131
};
static const u16 pio_cmd_timings[5] = {
0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131
@@ -198,7 +198,7 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
rdmsr(ATAC_CH0D1_PIO, timings, dummy);
if (CS5535_BAD_PIO(timings))
wrmsr(ATAC_CH0D1_PIO, 0xF7F4F7F4UL, 0);
- return ata_pci_sff_init_one(dev, ppi, &cs5535_sht, NULL);
+ return ata_pci_sff_init_one(dev, ppi, &cs5535_sht, NULL, 0);
}
static const struct pci_device_id cs5535[] = {
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c
index ffee3978ec83..914ae3506ff5 100644
--- a/drivers/ata/pata_cs5536.c
+++ b/drivers/ata/pata_cs5536.c
@@ -260,7 +260,7 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return -ENODEV;
}
- return ata_pci_sff_init_one(dev, ppi, &cs5536_sht, NULL);
+ return ata_pci_sff_init_one(dev, ppi, &cs5536_sht, NULL, 0);
}
static const struct pci_device_id cs5536[] = {
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index 8fb040bf7361..0fcc096b8dac 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -62,14 +62,16 @@ static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev)
return;
}
- time_16 = clamp_val(t.recover, 0, 15) | (clamp_val(t.active, 0, 15) << 4);
- time_8 = clamp_val(t.act8b, 0, 15) | (clamp_val(t.rec8b, 0, 15) << 4);
+ time_16 = clamp_val(t.recover - 1, 0, 15) |
+ (clamp_val(t.active - 1, 0, 15) << 4);
+ time_8 = clamp_val(t.act8b - 1, 0, 15) |
+ (clamp_val(t.rec8b - 1, 0, 15) << 4);
if (adev->devno == 0) {
pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
addr &= ~0x0F; /* Mask bits */
- addr |= clamp_val(t.setup, 0, 15);
+ addr |= clamp_val(t.setup - 1, 0, 15);
pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
pci_write_config_byte(pdev, CY82_IDE_MASTER_IOR, time_16);
@@ -79,7 +81,7 @@ static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev)
pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
addr &= ~0xF0; /* Mask bits */
- addr |= (clamp_val(t.setup, 0, 15) << 4);
+ addr |= (clamp_val(t.setup - 1, 0, 15) << 4);
pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOR, time_16);
@@ -136,7 +138,7 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i
if (PCI_FUNC(pdev->devfn) != 1)
return -ENODEV;
- return ata_pci_sff_init_one(pdev, ppi, &cy82c693_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &cy82c693_sht, NULL, 0);
}
static const struct pci_device_id cy82c693[] = {
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index b2e71e6473ed..3bac0e079691 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -2,7 +2,7 @@
* pata_efar.c - EFAR PIIX clone controller driver
*
* (C) 2005 Red Hat
- * (C) 2009 Bartlomiej Zolnierkiewicz
+ * (C) 2009-2010 Bartlomiej Zolnierkiewicz
*
* Some parts based on ata_piix.c by Jeff Garzik and others.
*
@@ -68,6 +68,8 @@ static int efar_cable_detect(struct ata_port *ap)
return ATA_CBL_PATA80;
}
+static DEFINE_SPINLOCK(efar_lock);
+
/**
* efar_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
@@ -84,7 +86,9 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
unsigned int pio = adev->pio_mode - XFER_PIO_0;
struct pci_dev *dev = to_pci_dev(ap->host->dev);
unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
+ unsigned long flags;
u16 idetm_data;
+ u8 udma_enable;
int control = 0;
/*
@@ -107,6 +111,8 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
if (adev->class == ATA_DEV_ATA)
control |= 4; /* PPE */
+ spin_lock_irqsave(&efar_lock, flags);
+
pci_read_config_word(dev, idetm_port, &idetm_data);
/* Set PPE, IE, and TIME as appropriate */
@@ -131,6 +137,11 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
idetm_data |= 0x4000; /* Ensure SITRE is set */
pci_write_config_word(dev, idetm_port, idetm_data);
+
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+ udma_enable &= ~(1 << (2 * ap->port_no + adev->devno));
+ pci_write_config_byte(dev, 0x48, udma_enable);
+ spin_unlock_irqrestore(&efar_lock, flags);
}
/**
@@ -151,6 +162,7 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
u16 master_data;
u8 speed = adev->dma_mode;
int devid = adev->devno + 2 * ap->port_no;
+ unsigned long flags;
u8 udma_enable;
static const /* ISP RTC */
@@ -160,6 +172,8 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
{ 2, 1 },
{ 2, 3 }, };
+ spin_lock_irqsave(&efar_lock, flags);
+
pci_read_config_word(dev, master_port, &master_data);
pci_read_config_byte(dev, 0x48, &udma_enable);
@@ -217,6 +231,7 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
pci_write_config_word(dev, master_port, master_data);
}
pci_write_config_byte(dev, 0x48, udma_enable);
+ spin_unlock_irqrestore(&efar_lock, flags);
}
static struct scsi_host_template efar_sht = {
@@ -256,13 +271,14 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
.udma_mask = ATA_UDMA4,
.port_ops = &efar_ops,
};
- const struct ata_port_info *ppi[] = { &info, NULL };
+ const struct ata_port_info *ppi[] = { &info, &info };
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev,
"version " DRV_VERSION "\n");
- return ata_pci_sff_init_one(pdev, ppi, &efar_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &efar_sht, NULL,
+ ATA_HOST_PARALLEL_SCAN);
}
static const struct pci_device_id efar_pci_tbl[] = {
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 0bd48e8f21bd..af49bfb57247 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -11,9 +11,7 @@
*
*
* TODO
- * Maybe PLL mode
- * Look into engine reset on timeout errors. Should not be
- * required.
+ * Look into engine reset on timeout errors. Should not be required.
*/
@@ -27,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt366"
-#define DRV_VERSION "0.6.7"
+#define DRV_VERSION "0.6.8"
struct hpt_clock {
u8 xfer_mode;
@@ -207,17 +205,8 @@ static void hpt366_set_mode(struct ata_port *ap, struct ata_device *adev,
{
struct hpt_clock *clocks = ap->host->private_data;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
- u32 addr2 = 0x51 + 4 * ap->port_no;
+ u32 addr = 0x40 + 4 * adev->devno;
u32 mask, reg;
- u8 fast;
-
- /* Fast interrupt prediction disable, hold off interrupt disable */
- pci_read_config_byte(pdev, addr2, &fast);
- if (fast & 0x80) {
- fast &= ~0x80;
- pci_write_config_byte(pdev, addr2, fast);
- }
/* determine timing mask and find matching clock entry */
if (mode < XFER_MW_DMA_0)
@@ -240,9 +229,9 @@ static void hpt366_set_mode(struct ata_port *ap, struct ata_device *adev,
* on-chip PIO FIFO/buffer (and PIO MST mode as well) to avoid
* problems handling I/O errors later.
*/
- pci_read_config_dword(pdev, addr1, &reg);
+ pci_read_config_dword(pdev, addr, &reg);
reg = ((reg & ~mask) | (clocks->timing & mask)) & ~0xc0000000;
- pci_write_config_dword(pdev, addr1, reg);
+ pci_write_config_dword(pdev, addr, reg);
}
/**
@@ -372,7 +361,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
break;
}
/* Now kick off ATA set up */
- return ata_pci_sff_init_one(dev, ppi, &hpt36x_sht, hpriv);
+ return ata_pci_sff_init_one(dev, ppi, &hpt36x_sht, hpriv, 0);
}
#ifdef CONFIG_PM
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index 4224cfccedef..8839307a64cf 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -24,7 +24,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt37x"
-#define DRV_VERSION "0.6.14"
+#define DRV_VERSION "0.6.15"
struct hpt_clock {
u8 xfer_speed;
@@ -39,25 +39,24 @@ struct hpt_chip {
/* key for bus clock timings
* bit
- * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
- * DMA. cycles = value + 1
- * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
- * DMA. cycles = value + 1
- * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 4:8 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 9:12 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
* register access.
- * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file
* register access.
- * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
- * during task file register access.
- * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
- * xfer.
- * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * 18:20 udma_cycle_time. Clock cycles for UDMA xfer.
+ * 21 CLK frequency for UDMA: 0=ATA clock, 1=dual ATA clock.
+ * 22:24 pre_high_time. Time to initialize 1st cycle for PIO and MW DMA xfer.
+ * 25:27 cmd_pre_high_time. Time to initialize 1st PIO cycle for task file
* register access.
- * 28 UDMA enable
- * 29 DMA enable
- * 30 PIO_MST enable. if set, the chip is in bus master mode during
- * PIO.
- * 31 FIFO enable.
+ * 28 UDMA enable.
+ * 29 DMA enable.
+ * 30 PIO_MST enable. If set, the chip is in bus master mode during
+ * PIO xfer.
+ * 31 FIFO enable. Only for PIO.
*/
static struct hpt_clock hpt37x_timings_33[] = {
@@ -384,20 +383,12 @@ static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline)
return ata_sff_prereset(link, deadline);
}
-/**
- * hpt370_set_piomode - PIO setup
- * @ap: ATA interface
- * @adev: device on the interface
- *
- * Perform PIO mode setup.
- */
-
-static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void hpt370_set_mode(struct ata_port *ap, struct ata_device *adev,
+ u8 mode)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 addr1, addr2;
- u32 reg;
- u32 mode;
+ u32 reg, timing, mask;
u8 fast;
addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
@@ -409,11 +400,31 @@ static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
fast |= 0x01;
pci_write_config_byte(pdev, addr2, fast);
+ /* Determine timing mask and find matching mode entry */
+ if (mode < XFER_MW_DMA_0)
+ mask = 0xcfc3ffff;
+ else if (mode < XFER_UDMA_0)
+ mask = 0x31c001ff;
+ else
+ mask = 0x303c0000;
+
+ timing = hpt37x_find_mode(ap, mode);
+
pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt37x_find_mode(ap, adev->pio_mode);
- mode &= 0xCFC3FFFF; /* Leave DMA bits alone */
- reg &= ~0xCFC3FFFF; /* Strip timing bits */
- pci_write_config_dword(pdev, addr1, reg | mode);
+ reg = (reg & ~mask) | (timing & mask);
+ pci_write_config_dword(pdev, addr1, reg);
+}
+/**
+ * hpt370_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
+
+static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ hpt370_set_mode(ap, adev, adev->pio_mode);
}
/**
@@ -421,33 +432,12 @@ static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
* @ap: ATA interface
* @adev: Device being configured
*
- * Set up the channel for MWDMA or UDMA modes. Much the same as with
- * PIO, load the mode number and then set MWDMA or UDMA flag.
+ * Set up the channel for MWDMA or UDMA modes.
*/
static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 addr1, addr2;
- u32 reg, mode, mask;
- u8 fast;
-
- addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
- addr2 = 0x51 + 4 * ap->port_no;
-
- /* Fast interrupt prediction disable, hold off interrupt disable */
- pci_read_config_byte(pdev, addr2, &fast);
- fast &= ~0x02;
- fast |= 0x01;
- pci_write_config_byte(pdev, addr2, fast);
-
- mask = adev->dma_mode < XFER_UDMA_0 ? 0x31C001FF : 0x303C0000;
-
- pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt37x_find_mode(ap, adev->dma_mode);
- mode &= mask;
- reg &= ~mask;
- pci_write_config_dword(pdev, addr1, reg | mode);
+ hpt370_set_mode(ap, adev, adev->dma_mode);
}
/**
@@ -461,24 +451,25 @@ static void hpt370_bmdma_stop(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u8 dma_stat = ioread8(ap->ioaddr.bmdma_addr + 2);
- u8 dma_cmd;
void __iomem *bmdma = ap->ioaddr.bmdma_addr;
+ u8 dma_stat = ioread8(bmdma + ATA_DMA_STATUS);
+ u8 dma_cmd;
- if (dma_stat & 0x01) {
+ if (dma_stat & ATA_DMA_ACTIVE) {
udelay(20);
- dma_stat = ioread8(bmdma + 2);
+ dma_stat = ioread8(bmdma + ATA_DMA_STATUS);
}
- if (dma_stat & 0x01) {
+ if (dma_stat & ATA_DMA_ACTIVE) {
/* Clear the engine */
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(10);
/* Stop DMA */
- dma_cmd = ioread8(bmdma );
- iowrite8(dma_cmd & 0xFE, bmdma);
+ dma_cmd = ioread8(bmdma + ATA_DMA_CMD);
+ iowrite8(dma_cmd & ~ATA_DMA_START, bmdma + ATA_DMA_CMD);
/* Clear Error */
- dma_stat = ioread8(bmdma + 2);
- iowrite8(dma_stat | 0x06 , bmdma + 2);
+ dma_stat = ioread8(bmdma + ATA_DMA_STATUS);
+ iowrite8(dma_stat | ATA_DMA_INTR | ATA_DMA_ERR,
+ bmdma + ATA_DMA_STATUS);
/* Clear the engine */
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(10);
@@ -486,20 +477,12 @@ static void hpt370_bmdma_stop(struct ata_queued_cmd *qc)
ata_bmdma_stop(qc);
}
-/**
- * hpt372_set_piomode - PIO setup
- * @ap: ATA interface
- * @adev: device on the interface
- *
- * Perform PIO mode setup.
- */
-
-static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void hpt372_set_mode(struct ata_port *ap, struct ata_device *adev,
+ u8 mode)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 addr1, addr2;
- u32 reg;
- u32 mode;
+ u32 reg, timing, mask;
u8 fast;
addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
@@ -510,13 +493,32 @@ static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
fast &= ~0x07;
pci_write_config_byte(pdev, addr2, fast);
+ /* Determine timing mask and find matching mode entry */
+ if (mode < XFER_MW_DMA_0)
+ mask = 0xcfc3ffff;
+ else if (mode < XFER_UDMA_0)
+ mask = 0x31c001ff;
+ else
+ mask = 0x303c0000;
+
+ timing = hpt37x_find_mode(ap, mode);
+
pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt37x_find_mode(ap, adev->pio_mode);
+ reg = (reg & ~mask) | (timing & mask);
+ pci_write_config_dword(pdev, addr1, reg);
+}
+
+/**
+ * hpt372_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
- printk("Find mode for %d reports %X\n", adev->pio_mode, mode);
- mode &= 0xCFC3FFFF; /* Leave DMA bits alone */
- reg &= ~0xCFC3FFFF; /* Strip timing bits */
- pci_write_config_dword(pdev, addr1, reg | mode);
+static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ hpt372_set_mode(ap, adev, adev->pio_mode);
}
/**
@@ -524,33 +526,12 @@ static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
* @ap: ATA interface
* @adev: Device being configured
*
- * Set up the channel for MWDMA or UDMA modes. Much the same as with
- * PIO, load the mode number and then set MWDMA or UDMA flag.
+ * Set up the channel for MWDMA or UDMA modes.
*/
static void hpt372_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 addr1, addr2;
- u32 reg, mode, mask;
- u8 fast;
-
- addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
- addr2 = 0x51 + 4 * ap->port_no;
-
- /* Fast interrupt prediction disable, hold off interrupt disable */
- pci_read_config_byte(pdev, addr2, &fast);
- fast &= ~0x07;
- pci_write_config_byte(pdev, addr2, fast);
-
- mask = adev->dma_mode < XFER_UDMA_0 ? 0x31C001FF : 0x303C0000;
-
- pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt37x_find_mode(ap, adev->dma_mode);
- printk("Find mode for DMA %d reports %X\n", adev->dma_mode, mode);
- mode &= mask;
- reg &= ~mask;
- pci_write_config_dword(pdev, addr1, reg | mode);
+ hpt372_set_mode(ap, adev, adev->dma_mode);
}
/**
@@ -1006,7 +987,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
}
/* Now kick off ATA set up */
- return ata_pci_sff_init_one(dev, ppi, &hpt37x_sht, private_data);
+ return ata_pci_sff_init_one(dev, ppi, &hpt37x_sht, private_data, 0);
}
static const struct pci_device_id hpt37x[] = {
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index dd26bc73bd9a..01457b266f3d 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt3x2n"
-#define DRV_VERSION "0.3.8"
+#define DRV_VERSION "0.3.10"
enum {
HPT_PCI_FAST = (1 << 31),
@@ -45,25 +45,24 @@ struct hpt_chip {
/* key for bus clock timings
* bit
- * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
- * DMA. cycles = value + 1
- * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
- * DMA. cycles = value + 1
- * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 4:8 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 9:12 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
* register access.
- * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file
* register access.
- * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
- * during task file register access.
- * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
- * xfer.
- * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * 18:20 udma_cycle_time. Clock cycles for UDMA xfer.
+ * 21 CLK frequency for UDMA: 0=ATA clock, 1=dual ATA clock.
+ * 22:24 pre_high_time. Time to initialize 1st cycle for PIO and MW DMA xfer.
+ * 25:27 cmd_pre_high_time. Time to initialize 1st PIO cycle for task file
* register access.
- * 28 UDMA enable
- * 29 DMA enable
- * 30 PIO_MST enable. if set, the chip is in bus master mode during
- * PIO.
- * 31 FIFO enable.
+ * 28 UDMA enable.
+ * 29 DMA enable.
+ * 30 PIO_MST enable. If set, the chip is in bus master mode during
+ * PIO xfer.
+ * 31 FIFO enable. Only for PIO.
*/
/* 66MHz DPLL clocks */
@@ -161,20 +160,12 @@ static int hpt3x2n_pre_reset(struct ata_link *link, unsigned long deadline)
return ata_sff_prereset(link, deadline);
}
-/**
- * hpt3x2n_set_piomode - PIO setup
- * @ap: ATA interface
- * @adev: device on the interface
- *
- * Perform PIO mode setup.
- */
-
-static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void hpt3x2n_set_mode(struct ata_port *ap, struct ata_device *adev,
+ u8 mode)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 addr1, addr2;
- u32 reg;
- u32 mode;
+ u32 reg, timing, mask;
u8 fast;
addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
@@ -185,11 +176,32 @@ static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
fast &= ~0x07;
pci_write_config_byte(pdev, addr2, fast);
+ /* Determine timing mask and find matching mode entry */
+ if (mode < XFER_MW_DMA_0)
+ mask = 0xcfc3ffff;
+ else if (mode < XFER_UDMA_0)
+ mask = 0x31c001ff;
+ else
+ mask = 0x303c0000;
+
+ timing = hpt3x2n_find_mode(ap, mode);
+
pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt3x2n_find_mode(ap, adev->pio_mode);
- mode &= 0xCFC3FFFF; /* Leave DMA bits alone */
- reg &= ~0xCFC3FFFF; /* Strip timing bits */
- pci_write_config_dword(pdev, addr1, reg | mode);
+ reg = (reg & ~mask) | (timing & mask);
+ pci_write_config_dword(pdev, addr1, reg);
+}
+
+/**
+ * hpt3x2n_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
+
+static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ hpt3x2n_set_mode(ap, adev, adev->pio_mode);
}
/**
@@ -197,32 +209,12 @@ static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
* @ap: ATA interface
* @adev: Device being configured
*
- * Set up the channel for MWDMA or UDMA modes. Much the same as with
- * PIO, load the mode number and then set MWDMA or UDMA flag.
+ * Set up the channel for MWDMA or UDMA modes.
*/
static void hpt3x2n_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 addr1, addr2;
- u32 reg, mode, mask;
- u8 fast;
-
- addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
- addr2 = 0x51 + 4 * ap->port_no;
-
- /* Fast interrupt prediction disable, hold off interrupt disable */
- pci_read_config_byte(pdev, addr2, &fast);
- fast &= ~0x07;
- pci_write_config_byte(pdev, addr2, fast);
-
- mask = adev->dma_mode < XFER_UDMA_0 ? 0x31C001FF : 0x303C0000;
-
- pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt3x2n_find_mode(ap, adev->dma_mode);
- mode &= mask;
- reg &= ~mask;
- pci_write_config_dword(pdev, addr1, reg | mode);
+ hpt3x2n_set_mode(ap, adev, adev->dma_mode);
}
/**
@@ -544,19 +536,19 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
pci_mhz);
/* Set our private data up. We only need a few flags so we use
it directly */
- if (pci_mhz > 60) {
+ if (pci_mhz > 60)
hpriv = (void *)(PCI66 | USE_DPLL);
- /*
- * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
- * the MISC. register to stretch the UltraDMA Tss timing.
- * NOTE: This register is only writeable via I/O space.
- */
- if (dev->device == PCI_DEVICE_ID_TTI_HPT371)
- outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c);
- }
+
+ /*
+ * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
+ * the MISC. register to stretch the UltraDMA Tss timing.
+ * NOTE: This register is only writeable via I/O space.
+ */
+ if (dev->device == PCI_DEVICE_ID_TTI_HPT371)
+ outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c);
/* Now kick off ATA set up */
- return ata_pci_sff_init_one(dev, ppi, &hpt3x2n_sht, hpriv);
+ return ata_pci_sff_init_one(dev, ppi, &hpt3x2n_sht, hpriv, 0);
}
static const struct pci_device_id hpt3x2n[] = {
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index c86c71639a95..727a81ce4c9f 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -180,7 +180,7 @@ static void hpt3x3_init_chipset(struct pci_dev *dev)
* @id: Entry in match table
*
* Perform basic initialisation. We set the device up so we access all
- * ports via BAR4. This is neccessary to work around errata.
+ * ports via BAR4. This is necessary to work around errata.
*/
static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
index 8f3325adceb3..f971f0de88e6 100644
--- a/drivers/ata/pata_it8213.c
+++ b/drivers/ata/pata_it8213.c
@@ -273,7 +273,7 @@ static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *en
dev_printk(KERN_DEBUG, &pdev->dev,
"version " DRV_VERSION "\n");
- return ata_pci_sff_init_one(pdev, ppi, &it8213_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &it8213_sht, NULL, 0);
}
static const struct pci_device_id it8213_pci_tbl[] = {
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index edc5c1fed150..9bde1cb5f981 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -932,7 +932,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
else
ppi[0] = &info_smart;
}
- return ata_pci_sff_init_one(pdev, ppi, &it821x_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &it821x_sht, NULL, 0);
}
#ifdef CONFIG_PM
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 3a1474ac8838..565e01e6ac7c 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -144,7 +144,7 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
};
const struct ata_port_info *ppi[] = { &info, NULL };
- return ata_pci_sff_init_one(pdev, ppi, &jmicron_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &jmicron_sht, NULL, 0);
}
static const struct pci_device_id jmicron_pci_tbl[] = {
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index 950da39cae3d..e8ca02e5a71d 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -147,13 +147,13 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i
if (pdev->device == 0x6101)
ppi[1] = &ata_dummy_port_info;
-#if defined(CONFIG_AHCI) || defined(CONFIG_AHCI_MODULE)
+#if defined(CONFIG_SATA_AHCI) || defined(CONFIG_SATA_AHCI_MODULE)
if (!marvell_pata_active(pdev)) {
printk(KERN_INFO DRV_NAME ": PATA port not active, deferring to AHCI driver.\n");
return -ENODEV;
}
#endif
- return ata_pci_sff_init_one(pdev, ppi, &marvell_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &marvell_sht, NULL, 0);
}
static const struct pci_device_id marvell_pci_tbl[] = {
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index f0d52f72f5bb..94f979a7f4f7 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -82,7 +82,7 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e
ata_pci_bmdma_clear_simplex(pdev);
/* And let the library code do the work */
- return ata_pci_sff_init_one(pdev, port_info, &netcell_sht, NULL);
+ return ata_pci_sff_init_one(pdev, port_info, &netcell_sht, NULL, 0);
}
static const struct pci_device_id netcell_pci_tbl[] = {
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index ca53fac06717..2110863bb3db 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -148,7 +148,7 @@ static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
.port_ops = &ns87410_port_ops
};
const struct ata_port_info *ppi[] = { &info, NULL };
- return ata_pci_sff_init_one(dev, ppi, &ns87410_sht, NULL);
+ return ata_pci_sff_init_one(dev, ppi, &ns87410_sht, NULL, 0);
}
static const struct pci_device_id ns87410[] = {
diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c
index 061aa1c41a48..830431f036a1 100644
--- a/drivers/ata/pata_ns87415.c
+++ b/drivers/ata/pata_ns87415.c
@@ -380,7 +380,7 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e
ns87415_fixup(pdev);
- return ata_pci_sff_init_one(pdev, ppi, &ns87415_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &ns87415_sht, NULL, 0);
}
static const struct pci_device_id ns87415_pci_tbl[] = {
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index 9a8687db6b2d..5f6aba7eb0dd 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -248,7 +248,7 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e
dev_printk(KERN_DEBUG, &pdev->dev,
"version " DRV_VERSION "\n");
- return ata_pci_sff_init_one(pdev, ppi, &oldpiix_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &oldpiix_sht, NULL, 0);
}
static const struct pci_device_id oldpiix_pci_tbl[] = {
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index 99eddda2d2e5..00c5a02a94fc 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -172,7 +172,7 @@ static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (!printed_version++)
dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
- return ata_pci_sff_init_one(dev, ppi, &opti_sht, NULL);
+ return ata_pci_sff_init_one(dev, ppi, &opti_sht, NULL, 0);
}
static const struct pci_device_id opti[] = {
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index 86885a445f97..76b7d12b1e8d 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -429,7 +429,7 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (optiplus_with_udma(dev))
ppi[0] = &info_82c700_udma;
- return ata_pci_sff_init_one(dev, ppi, &optidma_sht, NULL);
+ return ata_pci_sff_init_one(dev, ppi, &optidma_sht, NULL, 0);
}
static const struct pci_device_id optidma[] = {
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 1b392c9e8531..147de2fd66d2 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -131,12 +131,12 @@ static unsigned int ata_data_xfer_8bit(struct ata_device *dev,
* @qc: command
*
* Drain the FIFO and device of any stuck data following a command
- * failing to complete. In some cases this is neccessary before a
+ * failing to complete. In some cases this is necessary before a
* reset will recover the device.
*
*/
-void pcmcia_8bit_drain_fifo(struct ata_queued_cmd *qc)
+static void pcmcia_8bit_drain_fifo(struct ata_queued_cmd *qc)
{
int count;
struct ata_port *ap;
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 2f3c9bed63d9..9ac0897cf8b0 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -2,7 +2,7 @@
* pata_pdc202xx_old.c - Promise PDC202xx PATA for new ATA layer
* (C) 2005 Red Hat Inc
* Alan Cox <alan@lxorguk.ukuu.org.uk>
- * (C) 2007,2009 Bartlomiej Zolnierkiewicz
+ * (C) 2007,2009,2010 Bartlomiej Zolnierkiewicz
*
* Based in part on linux/drivers/ide/pci/pdc202xx_old.c
*
@@ -35,6 +35,15 @@ static int pdc2026x_cable_detect(struct ata_port *ap)
return ATA_CBL_PATA80;
}
+static void pdc202xx_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+
+ iowrite8(tf->command, ap->ioaddr.command_addr);
+ ndelay(400);
+}
+
/**
* pdc202xx_configure_piomode - set chip PIO timing
* @ap: ATA interface
@@ -271,6 +280,8 @@ static struct ata_port_operations pdc2024x_port_ops = {
.cable_detect = ata_cable_40wire,
.set_piomode = pdc202xx_set_piomode,
.set_dmamode = pdc202xx_set_dmamode,
+
+ .sff_exec_command = pdc202xx_exec_command,
};
static struct ata_port_operations pdc2026x_port_ops = {
@@ -284,6 +295,8 @@ static struct ata_port_operations pdc2026x_port_ops = {
.dev_config = pdc2026x_dev_config,
.port_start = pdc2026x_port_start,
+
+ .sff_exec_command = pdc202xx_exec_command,
};
static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -324,7 +337,7 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id
return -ENODEV;
}
}
- return ata_pci_sff_init_one(dev, ppi, &pdc202xx_sht, NULL);
+ return ata_pci_sff_init_one(dev, ppi, &pdc202xx_sht, NULL, 0);
}
static const struct pci_device_id pdc202xx[] = {
diff --git a/drivers/ata/pata_piccolo.c b/drivers/ata/pata_piccolo.c
index bfe0180f3efa..981615414849 100644
--- a/drivers/ata/pata_piccolo.c
+++ b/drivers/ata/pata_piccolo.c
@@ -95,7 +95,7 @@ static int ata_tosh_init_one(struct pci_dev *dev, const struct pci_device_id *id
};
const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
/* Just one port for the moment */
- return ata_pci_sff_init_one(dev, ppi, &tosh_sht, NULL);
+ return ata_pci_sff_init_one(dev, ppi, &tosh_sht, NULL, 0);
}
static struct pci_device_id ata_tosh[] = {
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index 4fd25e737d9a..fc9602229acb 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -227,7 +227,7 @@ static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *e
dev_printk(KERN_DEBUG, &pdev->dev,
"version " DRV_VERSION "\n");
- return ata_pci_sff_init_one(pdev, ppi, &radisys_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &radisys_sht, NULL, 0);
}
static const struct pci_device_id radisys_pci_tbl[] = {
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index 2932998fc4c6..4a454a88aa9d 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -95,7 +95,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en
printk_once(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
if (rz1000_fifo_disable(pdev) == 0)
- return ata_pci_sff_init_one(pdev, ppi, &rz1000_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &rz1000_sht, NULL, 0);
printk(KERN_ERR DRV_NAME ": failed to disable read-ahead on chipset..\n");
/* Not safe to use so skip */
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index 3bbed8322ecf..dfecc6f964b0 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -237,7 +237,7 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
};
const struct ata_port_info *ppi[] = { &info, NULL };
- return ata_pci_sff_init_one(dev, ppi, &sc1200_sht, NULL);
+ return ata_pci_sff_init_one(dev, ppi, &sc1200_sht, NULL, 0);
}
static const struct pci_device_id sc1200[] = {
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index beaed12d50e4..9524d54035f7 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -1,6 +1,7 @@
/*
* pata_serverworks.c - Serverworks PATA for new ATA layer
* (C) 2005 Red Hat Inc
+ * (C) 2010 Bartlomiej Zolnierkiewicz
*
* based upon
*
@@ -253,7 +254,7 @@ static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev
if (serverworks_is_csb(pdev)) {
pci_read_config_word(pdev, 0x4A, &csb5_pio);
csb5_pio &= ~(0x0F << devbits);
- pci_write_config_byte(pdev, 0x4A, csb5_pio | (pio << devbits));
+ pci_write_config_word(pdev, 0x4A, csb5_pio | (pio << devbits));
}
}
@@ -327,7 +328,7 @@ static int serverworks_fixup_osb4(struct pci_dev *pdev)
pci_dev_put(isa_dev);
return 0;
}
- printk(KERN_WARNING "ata_serverworks: Unable to find bridge.\n");
+ printk(KERN_WARNING DRV_NAME ": Unable to find bridge.\n");
return -ENODEV;
}
@@ -459,7 +460,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id
if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
ata_pci_bmdma_clear_simplex(pdev);
- return ata_pci_sff_init_one(pdev, ppi, &serverworks_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &serverworks_sht, NULL, 0);
}
#ifdef CONFIG_PM
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index a2ace48a4610..c6c589c23ffc 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -356,7 +356,7 @@ static int __devinit sil680_init_one(struct pci_dev *pdev,
IRQF_SHARED, &sil680_sht);
use_ioports:
- return ata_pci_sff_init_one(pdev, ppi, &sil680_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &sil680_sht, NULL, 0);
}
#ifdef CONFIG_PM
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 5c30d56dec84..b6708032f321 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -826,7 +826,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
sis_fixup(pdev, chipset);
- return ata_pci_sff_init_one(pdev, ppi, &sis_sht, chipset);
+ return ata_pci_sff_init_one(pdev, ppi, &sis_sht, chipset, 0);
}
#ifdef CONFIG_PM
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index 29f733c32066..733b042a7469 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -316,7 +316,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id
val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
pci_write_config_dword(dev, 0x40, val);
- return ata_pci_sff_init_one(dev, ppi, &sl82c105_sht, NULL);
+ return ata_pci_sff_init_one(dev, ppi, &sl82c105_sht, NULL, 0);
}
static const struct pci_device_id sl82c105[] = {
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index f1f13ff222fd..48f50600ed2a 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -201,7 +201,7 @@ static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (!printed_version++)
dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
- return ata_pci_sff_init_one(dev, ppi, &triflex_sht, NULL);
+ return ata_pci_sff_init_one(dev, ppi, &triflex_sht, NULL, 0);
}
static const struct pci_device_id triflex[] = {
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 0d97890af681..3059ec017de3 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -22,6 +22,7 @@
* VIA VT8233c - UDMA100
* VIA VT8235 - UDMA133
* VIA VT8237 - UDMA133
+ * VIA VT8237A - UDMA133
* VIA VT8237S - UDMA133
* VIA VT8251 - UDMA133
*
@@ -64,26 +65,15 @@
#define DRV_NAME "pata_via"
#define DRV_VERSION "0.3.4"
-/*
- * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
- * driver.
- */
-
enum {
- VIA_UDMA = 0x007,
- VIA_UDMA_NONE = 0x000,
- VIA_UDMA_33 = 0x001,
- VIA_UDMA_66 = 0x002,
- VIA_UDMA_100 = 0x003,
- VIA_UDMA_133 = 0x004,
- VIA_BAD_PREQ = 0x010, /* Crashes if PREQ# till DDACK# set */
- VIA_BAD_CLK66 = 0x020, /* 66 MHz clock doesn't work correctly */
- VIA_SET_FIFO = 0x040, /* Needs to have FIFO split set */
- VIA_NO_UNMASK = 0x080, /* Doesn't work with IRQ unmasking on */
- VIA_BAD_ID = 0x100, /* Has wrong vendor ID (0x1107) */
- VIA_BAD_AST = 0x200, /* Don't touch Address Setup Timing */
- VIA_NO_ENABLES = 0x400, /* Has no enablebits */
- VIA_SATA_PATA = 0x800, /* SATA/PATA combined configuration */
+ VIA_BAD_PREQ = 0x01, /* Crashes if PREQ# till DDACK# set */
+ VIA_BAD_CLK66 = 0x02, /* 66 MHz clock doesn't work correctly */
+ VIA_SET_FIFO = 0x04, /* Needs to have FIFO split set */
+ VIA_NO_UNMASK = 0x08, /* Doesn't work with IRQ unmasking on */
+ VIA_BAD_ID = 0x10, /* Has wrong vendor ID (0x1107) */
+ VIA_BAD_AST = 0x20, /* Don't touch Address Setup Timing */
+ VIA_NO_ENABLES = 0x40, /* Has no enablebits */
+ VIA_SATA_PATA = 0x80, /* SATA/PATA combined configuration */
};
enum {
@@ -99,40 +89,37 @@ static const struct via_isa_bridge {
u16 id;
u8 rev_min;
u8 rev_max;
- u16 flags;
+ u8 udma_mask;
+ u8 flags;
} via_isa_bridges[] = {
- { "vx855", PCI_DEVICE_ID_VIA_VX855, 0x00, 0x2f,
- VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA },
- { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, VIA_UDMA_133 |
- VIA_BAD_AST | VIA_SATA_PATA },
- { "vt8261", PCI_DEVICE_ID_VIA_8261, 0x00, 0x2f,
- VIA_UDMA_133 | VIA_BAD_AST },
- { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
- { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
- { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA },
- { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
- { "vt6415", PCI_DEVICE_ID_VIA_6415, 0x00, 0xff, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
- { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
- { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
- { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
- { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
- { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, VIA_UDMA_100 },
- { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, VIA_UDMA_100 },
- { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, VIA_UDMA_100 },
- { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 },
- { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, VIA_UDMA_66 },
- { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
- { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, VIA_UDMA_66 },
- { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
- { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
- { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
- { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
- { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
- { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
- { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
- { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
- { "vtxxxx", PCI_DEVICE_ID_VIA_ANON, 0x00, 0x2f,
- VIA_UDMA_133 | VIA_BAD_AST },
+ { "vx855", PCI_DEVICE_ID_VIA_VX855, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
+ { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
+ { "vt8261", PCI_DEVICE_ID_VIA_8261, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
+ { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_NO_ENABLES },
+ { "vt6415", PCI_DEVICE_ID_VIA_6415, 0x00, 0xff, ATA_UDMA6, VIA_BAD_AST | VIA_NO_ENABLES },
+ { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, ATA_UDMA5, },
+ { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, ATA_UDMA5, },
+ { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, ATA_UDMA5, },
+ { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, ATA_UDMA5, },
+ { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, ATA_UDMA4, },
+ { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
+ { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, ATA_UDMA4, },
+ { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, ATA_UDMA2, VIA_SET_FIFO },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, ATA_UDMA2, VIA_SET_FIFO | VIA_BAD_PREQ },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, ATA_UDMA2, VIA_SET_FIFO },
+ { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, ATA_UDMA2, VIA_SET_FIFO },
+ { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, 0x00, VIA_SET_FIFO },
+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK },
+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+ { "vtxxxx", PCI_DEVICE_ID_VIA_ANON, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
{ NULL }
};
@@ -191,10 +178,10 @@ static int via_cable_detect(struct ata_port *ap) {
return ATA_CBL_SATA;
/* Early chips are 40 wire */
- if ((config->flags & VIA_UDMA) < VIA_UDMA_66)
+ if (config->udma_mask < ATA_UDMA4)
return ATA_CBL_PATA40;
/* UDMA 66 chips have only drive side logic */
- else if ((config->flags & VIA_UDMA) < VIA_UDMA_100)
+ else if (config->udma_mask < ATA_UDMA5)
return ATA_CBL_PATA_UNK;
/* UDMA 100 or later */
pci_read_config_dword(pdev, 0x50, &ata66);
@@ -229,11 +216,10 @@ static int via_pre_reset(struct ata_link *link, unsigned long deadline)
/**
- * via_do_set_mode - set initial PIO mode data
+ * via_do_set_mode - set transfer mode data
* @ap: ATA interface
* @adev: ATA device
* @mode: ATA mode being programmed
- * @tdiv: Clocks per PCI clock
* @set_ast: Set to program address setup
* @udma_type: UDMA mode/format of registers
*
@@ -244,17 +230,27 @@ static int via_pre_reset(struct ata_link *link, unsigned long deadline)
* on the two channels.
*/
-static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mode, int tdiv, int set_ast, int udma_type)
+static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev,
+ int mode, int set_ast, int udma_type)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct ata_device *peer = ata_dev_pair(adev);
struct ata_timing t, p;
- static int via_clock = 33333; /* Bus clock in kHZ - ought to be tunable one day */
+ static int via_clock = 33333; /* Bus clock in kHZ */
unsigned long T = 1000000000 / via_clock;
- unsigned long UT = T/tdiv;
+ unsigned long UT = T;
int ut;
int offset = 3 - (2*ap->port_no) - adev->devno;
+ switch (udma_type) {
+ case ATA_UDMA4:
+ UT = T / 2; break;
+ case ATA_UDMA5:
+ UT = T / 3; break;
+ case ATA_UDMA6:
+ UT = T / 4; break;
+ }
+
/* Calculate the timing values we require */
ata_timing_compute(adev, mode, &t, T, UT);
@@ -273,7 +269,7 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo
pci_read_config_byte(pdev, 0x4C, &setup);
setup &= ~(3 << shift);
- setup |= clamp_val(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */
+ setup |= (clamp_val(t.setup, 1, 4) - 1) << shift;
pci_write_config_byte(pdev, 0x4C, setup);
}
@@ -284,22 +280,20 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo
((clamp_val(t.active, 1, 16) - 1) << 4) | (clamp_val(t.recover, 1, 16) - 1));
/* Load the UDMA bits according to type */
- switch(udma_type) {
- default:
- /* BUG() ? */
- /* fall through */
- case 33:
- ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 5) - 2)) : 0x03;
- break;
- case 66:
- ut = t.udma ? (0xe8 | (clamp_val(t.udma, 2, 9) - 2)) : 0x0f;
- break;
- case 100:
- ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
- break;
- case 133:
- ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
- break;
+ switch (udma_type) {
+ case ATA_UDMA2:
+ default:
+ ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 5) - 2)) : 0x03;
+ break;
+ case ATA_UDMA4:
+ ut = t.udma ? (0xe8 | (clamp_val(t.udma, 2, 9) - 2)) : 0x0f;
+ break;
+ case ATA_UDMA5:
+ ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
+ break;
+ case ATA_UDMA6:
+ ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
+ break;
}
/* Set UDMA unless device is not UDMA capable */
@@ -325,22 +319,16 @@ static void via_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
const struct via_isa_bridge *config = ap->host->private_data;
int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1;
- int mode = config->flags & VIA_UDMA;
- static u8 tclock[5] = { 1, 1, 2, 3, 4 };
- static u8 udma[5] = { 0, 33, 66, 100, 133 };
- via_do_set_mode(ap, adev, adev->pio_mode, tclock[mode], set_ast, udma[mode]);
+ via_do_set_mode(ap, adev, adev->pio_mode, set_ast, config->udma_mask);
}
static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
const struct via_isa_bridge *config = ap->host->private_data;
int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1;
- int mode = config->flags & VIA_UDMA;
- static u8 tclock[5] = { 1, 1, 2, 3, 4 };
- static u8 udma[5] = { 0, 33, 66, 100, 133 };
- via_do_set_mode(ap, adev, adev->dma_mode, tclock[mode], set_ast, udma[mode]);
+ via_do_set_mode(ap, adev, adev->dma_mode, set_ast, config->udma_mask);
}
/**
@@ -604,33 +592,29 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
via_config_fifo(pdev, config->flags);
/* Clock set up */
- switch(config->flags & VIA_UDMA) {
- case VIA_UDMA_NONE:
- if (config->flags & VIA_NO_UNMASK)
- ppi[0] = &via_mwdma_info_borked;
- else
- ppi[0] = &via_mwdma_info;
- break;
- case VIA_UDMA_33:
- ppi[0] = &via_udma33_info;
- break;
- case VIA_UDMA_66:
- ppi[0] = &via_udma66_info;
- /* The 66 MHz devices require we enable the clock */
- pci_read_config_dword(pdev, 0x50, &timing);
- timing |= 0x80008;
- pci_write_config_dword(pdev, 0x50, timing);
- break;
- case VIA_UDMA_100:
- ppi[0] = &via_udma100_info;
- break;
- case VIA_UDMA_133:
- ppi[0] = &via_udma133_info;
- break;
- default:
- WARN_ON(1);
- return -ENODEV;
- }
+ switch (config->udma_mask) {
+ case 0x00:
+ if (config->flags & VIA_NO_UNMASK)
+ ppi[0] = &via_mwdma_info_borked;
+ else
+ ppi[0] = &via_mwdma_info;
+ break;
+ case ATA_UDMA2:
+ ppi[0] = &via_udma33_info;
+ break;
+ case ATA_UDMA4:
+ ppi[0] = &via_udma66_info;
+ break;
+ case ATA_UDMA5:
+ ppi[0] = &via_udma100_info;
+ break;
+ case ATA_UDMA6:
+ ppi[0] = &via_udma133_info;
+ break;
+ default:
+ WARN_ON(1);
+ return -ENODEV;
+ }
if (config->flags & VIA_BAD_CLK66) {
/* Disable the 66MHz clock on problem devices */
@@ -640,7 +624,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* We have established the device type, now fire it up */
- return ata_pci_sff_init_one(pdev, ppi, &via_sht, (void *)config);
+ return ata_pci_sff_init_one(pdev, ppi, &via_sht, (void *)config, 0);
}
#ifdef CONFIG_PM
@@ -667,7 +651,7 @@ static int via_reinit_one(struct pci_dev *pdev)
via_config_fifo(pdev, config->flags);
- if ((config->flags & VIA_UDMA) == VIA_UDMA_66) {
+ if (config->udma_mask == ATA_UDMA4) {
/* The 66 MHz devices require we enable the clock */
pci_read_config_dword(pdev, 0x50, &timing);
timing |= 0x80008;
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 0c82d335c55d..684fe04dbbb7 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -772,7 +772,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
}
blk_queue_segment_boundary(sdev->request_queue, segment_boundary);
- blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize);
+ blk_queue_max_segments(sdev->request_queue, sg_tablesize);
ata_port_printk(ap, KERN_INFO,
"DMA mask 0x%llX, segment boundary 0x%lX, hw segs %hu\n",
(unsigned long long)*ap->host->dev->dma_mask,
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 02efd9a83d26..08f65492cc81 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -40,11 +40,13 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "sata_via"
-#define DRV_VERSION "2.4"
+#define DRV_VERSION "2.6"
/*
* vt8251 is different from other sata controllers of VIA. It has two
@@ -80,6 +82,7 @@ static int vt8251_scr_write(struct ata_link *link, unsigned int scr, u32 val);
static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
static void svia_noop_freeze(struct ata_port *ap);
static int vt6420_prereset(struct ata_link *link, unsigned long deadline);
+static void vt6420_bmdma_start(struct ata_queued_cmd *qc);
static int vt6421_pata_cable_detect(struct ata_port *ap);
static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev);
static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev);
@@ -121,6 +124,7 @@ static struct ata_port_operations vt6420_sata_ops = {
.inherits = &svia_base_ops,
.freeze = svia_noop_freeze,
.prereset = vt6420_prereset,
+ .bmdma_start = vt6420_bmdma_start,
};
static struct ata_port_operations vt6421_pata_ops = {
@@ -377,6 +381,17 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
return 0;
}
+static void vt6420_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ if ((qc->tf.command == ATA_CMD_PACKET) &&
+ (qc->scsicmd->sc_data_direction == DMA_TO_DEVICE)) {
+ /* Prevents corruption on some ATAPI burners */
+ ata_sff_pause(ap);
+ }
+ ata_bmdma_start(qc);
+}
+
static int vt6421_pata_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -392,14 +407,16 @@ static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const u8 pio_bits[] = { 0xA8, 0x65, 0x65, 0x31, 0x20 };
- pci_write_config_byte(pdev, PATA_PIO_TIMING, pio_bits[adev->pio_mode - XFER_PIO_0]);
+ pci_write_config_byte(pdev, PATA_PIO_TIMING - adev->devno,
+ pio_bits[adev->pio_mode - XFER_PIO_0]);
}
static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const u8 udma_bits[] = { 0xEE, 0xE8, 0xE6, 0xE4, 0xE2, 0xE1, 0xE0, 0xE0 };
- pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->dma_mode - XFER_UDMA_0]);
+ pci_write_config_byte(pdev, PATA_UDMA_TIMING - adev->devno,
+ udma_bits[adev->dma_mode - XFER_UDMA_0]);
}
static const unsigned int svia_bar_sizes[] = {
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index bc53fed89b1e..f7d6ebaa0418 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -2064,12 +2064,10 @@ fore200e_get_esi(struct fore200e* fore200e)
return -EBUSY;
}
- printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %pM\n",
fore200e->name,
(prom->hw_revision & 0xFF) + '@', /* probably meaningless with SBA boards */
- prom->serial_number & 0xFFFF,
- prom->mac_addr[ 2 ], prom->mac_addr[ 3 ], prom->mac_addr[ 4 ],
- prom->mac_addr[ 5 ], prom->mac_addr[ 6 ], prom->mac_addr[ 7 ]);
+ prom->serial_number & 0xFFFF, &prom->mac_addr[2]);
for (i = 0; i < ESI_LEN; i++) {
fore200e->esi[ i ] = fore200e->atm_dev->esi[ i ] = prom->mac_addr[ i + 2 ];
@@ -2845,13 +2843,12 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
" interrupt line:\t\t%s\n"
" physical base address:\t0x%p\n"
" virtual base address:\t0x%p\n"
- " factory address (ESI):\t%02x:%02x:%02x:%02x:%02x:%02x\n"
+ " factory address (ESI):\t%pM\n"
" board serial number:\t\t%d\n\n",
fore200e_irq_itoa(fore200e->irq),
(void*)fore200e->phys_base,
fore200e->virt_base,
- fore200e->esi[0], fore200e->esi[1], fore200e->esi[2],
- fore200e->esi[3], fore200e->esi[4], fore200e->esi[5],
+ fore200e->esi,
fore200e->esi[4] * 256 + fore200e->esi[5]);
return len;
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index e33ae0025b12..01f36c08cb52 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -3557,10 +3557,7 @@ init_card(struct atm_dev *dev)
if (tmp) {
memcpy(card->atmdev->esi, tmp->dev_addr, 6);
- printk("%s: ESI %02x:%02x:%02x:%02x:%02x:%02x\n",
- card->name, card->atmdev->esi[0], card->atmdev->esi[1],
- card->atmdev->esi[2], card->atmdev->esi[3],
- card->atmdev->esi[4], card->atmdev->esi[5]);
+ printk("%s: ESI %pM\n", card->name, card->atmdev->esi);
}
/*
* XXX: </hack>
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
index cf97c34cbaf1..7fe7c324e7ef 100644
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -998,9 +998,7 @@ static int __devinit eeprom_validate(struct lanai_dev *lanai)
(unsigned int) e[EEPROM_MAC_REV + i]);
return -EIO;
}
- DPRINTK("eeprom: MAC address = %02X:%02X:%02X:%02X:%02X:%02X\n",
- e[EEPROM_MAC + 0], e[EEPROM_MAC + 1], e[EEPROM_MAC + 2],
- e[EEPROM_MAC + 3], e[EEPROM_MAC + 4], e[EEPROM_MAC + 5]);
+ DPRINTK("eeprom: MAC address = %pM\n", &e[EEPROM_MAC]);
/* Verify serial number */
lanai->serialno = eeprom_be4(lanai, EEPROM_SERIAL);
v = eeprom_be4(lanai, EEPROM_SERIAL_REV);
@@ -2483,14 +2481,8 @@ static int lanai_proc_read(struct atm_dev *atmdev, loff_t *pos, char *page)
return sprintf(page, "revision: board=%d, pci_if=%d\n",
lanai->board_rev, (int) lanai->pci->revision);
if (left-- == 0)
- return sprintf(page, "EEPROM ESI: "
- "%02X:%02X:%02X:%02X:%02X:%02X\n",
- lanai->eeprom[EEPROM_MAC + 0],
- lanai->eeprom[EEPROM_MAC + 1],
- lanai->eeprom[EEPROM_MAC + 2],
- lanai->eeprom[EEPROM_MAC + 3],
- lanai->eeprom[EEPROM_MAC + 4],
- lanai->eeprom[EEPROM_MAC + 5]);
+ return sprintf(page, "EEPROM ESI: %pM\n",
+ &lanai->eeprom[EEPROM_MAC]);
if (left-- == 0)
return sprintf(page, "status: SOOL=%d, LOCD=%d, LED=%d, "
"GPIN=%d\n", (lanai->status & STATUS_SOOL) ? 1 : 0,
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index 3da804b1627d..50838407b117 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -807,9 +807,7 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
}
}
- printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i,
- card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2],
- card->atmdev->esi[3], card->atmdev->esi[4], card->atmdev->esi[5]);
+ printk("nicstar%d: MAC address %pM\n", i, card->atmdev->esi);
card->atmdev->dev_data = card;
card->atmdev->ci_range.vpi_bits = card->vpibits;
diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c
index fe3a865be4e5..b0ca5a47f47d 100644
--- a/drivers/auxdisplay/cfag12864bfb.c
+++ b/drivers/auxdisplay/cfag12864bfb.c
@@ -81,7 +81,7 @@ static struct fb_ops cfag12864bfb_ops = {
.fb_mmap = cfag12864bfb_mmap,
};
-static int __init cfag12864bfb_probe(struct platform_device *device)
+static int __devinit cfag12864bfb_probe(struct platform_device *device)
{
int ret = -EINVAL;
struct fb_info *info = framebuffer_alloc(0, &device->dev);
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index ee377270beb9..fd52c48ee762 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -3,35 +3,50 @@ menu "Generic Driver Options"
config UEVENT_HELPER_PATH
string "path to uevent helper"
depends on HOTPLUG
- default "/sbin/hotplug"
+ default ""
help
Path to uevent helper program forked by the kernel for
every uevent.
+ Before the switch to the netlink-based uevent source, this was
+ used to hook hotplug scripts into kernel device events. It
+ usually pointed to a shell script at /sbin/hotplug.
+ This should not be used today, because usual systems create
+ many events at bootup or device discovery in a very short time
+ frame. One forked process per event can create so many processes
+ that it creates a high system load, or on smaller systems
+ it is known to create out-of-memory situations during bootup.
config DEVTMPFS
- bool "Create a kernel maintained /dev tmpfs (EXPERIMENTAL)"
+ bool "Maintain a devtmpfs filesystem to mount at /dev"
depends on HOTPLUG && SHMEM && TMPFS
help
- This creates a tmpfs filesystem, and mounts it at bootup
- and mounts it at /dev. The kernel driver core creates device
- nodes for all registered devices in that filesystem. All device
- nodes are owned by root and have the default mode of 0600.
- Userspace can add and delete the nodes as needed. This is
- intended to simplify bootup, and make it possible to delay
- the initial coldplug at bootup done by udev in userspace.
- It should also provide a simpler way for rescue systems
- to bring up a kernel with dynamic major/minor numbers.
- Meaningful symlinks, permissions and device ownership must
- still be handled by userspace.
- If unsure, say N here.
+ This creates a tmpfs filesystem instance early at bootup.
+ In this filesystem, the kernel driver core maintains device
+ nodes with their default names and permissions for all
+ registered devices with an assigned major/minor number.
+ Userspace can modify the filesystem content as needed, add
+ symlinks, and apply needed permissions.
+ It provides a fully functional /dev directory, where usually
+ udev runs on top, managing permissions and adding meaningful
+ symlinks.
+ In very limited environments, it may provide a sufficient
+ functional /dev without any further help. It also allows simple
+ rescue systems, and reliably handles dynamic major/minor numbers.
config DEVTMPFS_MOUNT
- bool "Automount devtmpfs at /dev"
+ bool "Automount devtmpfs at /dev, after the kernel mounted the rootfs"
depends on DEVTMPFS
help
- This will mount devtmpfs at /dev if the kernel mounts the root
- filesystem. It will not affect initramfs based mounting.
- If unsure, say N here.
+ This will instruct the kernel to automatically mount the
+ devtmpfs filesystem at /dev, directly after the kernel has
+ mounted the root filesystem. The behavior can be overridden
+ with the commandline parameter: devtmpfs.mount=0|1.
+ This option does not affect initramfs based booting, here
+ the devtmpfs filesystem always needs to be mounted manually
+ after the roots is mounted.
+ With this option enabled, it allows to bring up a system in
+ rescue mode with init=/bin/sh, even when the /dev directory
+ on the rootfs is completely empty.
config STANDALONE
bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index c0c5a43d9fb3..71f6af5c8b0b 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -70,7 +70,7 @@ static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr,
return ret;
}
-static struct sysfs_ops driver_sysfs_ops = {
+static const struct sysfs_ops driver_sysfs_ops = {
.show = drv_attr_show,
.store = drv_attr_store,
};
@@ -115,7 +115,7 @@ static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,
return ret;
}
-static struct sysfs_ops bus_sysfs_ops = {
+static const struct sysfs_ops bus_sysfs_ops = {
.show = bus_attr_show,
.store = bus_attr_store,
};
@@ -154,7 +154,7 @@ static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
return 0;
}
-static struct kset_uevent_ops bus_uevent_ops = {
+static const struct kset_uevent_ops bus_uevent_ops = {
.filter = bus_uevent_filter,
};
@@ -173,10 +173,10 @@ static ssize_t driver_unbind(struct device_driver *drv,
dev = bus_find_device_by_name(bus, NULL, buf);
if (dev && dev->driver == drv) {
if (dev->parent) /* Needed for USB */
- down(&dev->parent->sem);
+ device_lock(dev->parent);
device_release_driver(dev);
if (dev->parent)
- up(&dev->parent->sem);
+ device_unlock(dev->parent);
err = count;
}
put_device(dev);
@@ -200,12 +200,12 @@ static ssize_t driver_bind(struct device_driver *drv,
dev = bus_find_device_by_name(bus, NULL, buf);
if (dev && dev->driver == NULL && driver_match_device(drv, dev)) {
if (dev->parent) /* Needed for USB */
- down(&dev->parent->sem);
- down(&dev->sem);
+ device_lock(dev->parent);
+ device_lock(dev);
err = driver_probe_device(drv, dev);
- up(&dev->sem);
+ device_unlock(dev);
if (dev->parent)
- up(&dev->parent->sem);
+ device_unlock(dev->parent);
if (err > 0) {
/* success */
@@ -744,10 +744,10 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
if (!dev->driver) {
if (dev->parent) /* Needed for USB */
- down(&dev->parent->sem);
+ device_lock(dev->parent);
ret = device_attach(dev);
if (dev->parent)
- up(&dev->parent->sem);
+ device_unlock(dev->parent);
}
return ret < 0 ? ret : 0;
}
@@ -779,10 +779,10 @@ int device_reprobe(struct device *dev)
{
if (dev->driver) {
if (dev->parent) /* Needed for USB */
- down(&dev->parent->sem);
+ device_lock(dev->parent);
device_release_driver(dev);
if (dev->parent)
- up(&dev->parent->sem);
+ device_unlock(dev->parent);
}
return bus_rescan_devices_helper(dev, NULL);
}
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 161746deab4b..0147f476b8a9 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -31,7 +31,7 @@ static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr,
ssize_t ret = -EIO;
if (class_attr->show)
- ret = class_attr->show(cp->class, buf);
+ ret = class_attr->show(cp->class, class_attr, buf);
return ret;
}
@@ -43,7 +43,7 @@ static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr,
ssize_t ret = -EIO;
if (class_attr->store)
- ret = class_attr->store(cp->class, buf, count);
+ ret = class_attr->store(cp->class, class_attr, buf, count);
return ret;
}
@@ -59,9 +59,11 @@ static void class_release(struct kobject *kobj)
else
pr_debug("class '%s' does not have a release() function, "
"be careful\n", class->name);
+
+ kfree(cp);
}
-static struct sysfs_ops class_sysfs_ops = {
+static const struct sysfs_ops class_sysfs_ops = {
.show = class_attr_show,
.store = class_attr_store,
};
@@ -488,6 +490,16 @@ void class_interface_unregister(struct class_interface *class_intf)
class_put(parent);
}
+ssize_t show_class_attr_string(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ struct class_attribute_string *cs;
+ cs = container_of(attr, struct class_attribute_string, attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n", cs->str);
+}
+
+EXPORT_SYMBOL_GPL(show_class_attr_string);
+
struct class_compat {
struct kobject *kobj;
};
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 282025770429..ef55df34ddd0 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -100,7 +100,7 @@ static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr,
return ret;
}
-static struct sysfs_ops dev_sysfs_ops = {
+static const struct sysfs_ops dev_sysfs_ops = {
.show = dev_attr_show,
.store = dev_attr_store,
};
@@ -252,7 +252,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
return retval;
}
-static struct kset_uevent_ops device_uevent_ops = {
+static const struct kset_uevent_ops device_uevent_ops = {
.filter = dev_uevent_filter,
.name = dev_uevent_name,
.uevent = dev_uevent,
@@ -306,15 +306,10 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
{
enum kobject_action action;
- if (kobject_action_type(buf, count, &action) == 0) {
+ if (kobject_action_type(buf, count, &action) == 0)
kobject_uevent(&dev->kobj, action);
- goto out;
- }
-
- dev_err(dev, "uevent: unsupported action-string; this will "
- "be ignored in a future kernel version\n");
- kobject_uevent(&dev->kobj, KOBJ_ADD);
-out:
+ else
+ dev_err(dev, "uevent: unknown action-string\n");
return count;
}
@@ -607,6 +602,7 @@ static struct kobject *get_device_parent(struct device *dev,
int retval;
if (dev->class) {
+ static DEFINE_MUTEX(gdp_mutex);
struct kobject *kobj = NULL;
struct kobject *parent_kobj;
struct kobject *k;
@@ -623,6 +619,8 @@ static struct kobject *get_device_parent(struct device *dev,
else
parent_kobj = &parent->kobj;
+ mutex_lock(&gdp_mutex);
+
/* find our class-directory at the parent and reference it */
spin_lock(&dev->class->p->class_dirs.list_lock);
list_for_each_entry(k, &dev->class->p->class_dirs.list, entry)
@@ -631,20 +629,26 @@ static struct kobject *get_device_parent(struct device *dev,
break;
}
spin_unlock(&dev->class->p->class_dirs.list_lock);
- if (kobj)
+ if (kobj) {
+ mutex_unlock(&gdp_mutex);
return kobj;
+ }
/* or create a new class-directory at the parent device */
k = kobject_create();
- if (!k)
+ if (!k) {
+ mutex_unlock(&gdp_mutex);
return NULL;
+ }
k->kset = &dev->class->p->class_dirs;
retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
if (retval < 0) {
+ mutex_unlock(&gdp_mutex);
kobject_put(k);
return NULL;
}
/* do not emit an uevent for this simple "glue" directory */
+ mutex_unlock(&gdp_mutex);
return k;
}
@@ -1574,22 +1578,16 @@ int device_rename(struct device *dev, char *new_name)
if (old_class_name) {
new_class_name = make_class_name(dev->class->name, &dev->kobj);
if (new_class_name) {
- error = sysfs_create_link_nowarn(&dev->parent->kobj,
- &dev->kobj,
- new_class_name);
- if (error)
- goto out;
- sysfs_remove_link(&dev->parent->kobj, old_class_name);
+ error = sysfs_rename_link(&dev->parent->kobj,
+ &dev->kobj,
+ old_class_name,
+ new_class_name);
}
}
#else
if (dev->class) {
- error = sysfs_create_link_nowarn(&dev->class->p->class_subsys.kobj,
- &dev->kobj, dev_name(dev));
- if (error)
- goto out;
- sysfs_remove_link(&dev->class->p->class_subsys.kobj,
- old_device_name);
+ error = sysfs_rename_link(&dev->class->p->class_subsys.kobj,
+ &dev->kobj, old_device_name, new_name);
}
#endif
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 958bd1540c30..7036e8e96ab8 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -13,8 +13,11 @@
#include "base.h"
+static struct sysdev_class_attribute *cpu_sysdev_class_attrs[];
+
struct sysdev_class cpu_sysdev_class = {
.name = "cpu",
+ .attrs = cpu_sysdev_class_attrs,
};
EXPORT_SYMBOL(cpu_sysdev_class);
@@ -76,34 +79,24 @@ void unregister_cpu(struct cpu *cpu)
}
#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
-static ssize_t cpu_probe_store(struct class *class, const char *buf,
+static ssize_t cpu_probe_store(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ const char *buf,
size_t count)
{
return arch_cpu_probe(buf, count);
}
-static ssize_t cpu_release_store(struct class *class, const char *buf,
+static ssize_t cpu_release_store(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ const char *buf,
size_t count)
{
return arch_cpu_release(buf, count);
}
-static CLASS_ATTR(probe, S_IWUSR, NULL, cpu_probe_store);
-static CLASS_ATTR(release, S_IWUSR, NULL, cpu_release_store);
-
-int __init cpu_probe_release_init(void)
-{
- int rc;
-
- rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj,
- &class_attr_probe.attr);
- if (!rc)
- rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj,
- &class_attr_release.attr);
-
- return rc;
-}
-device_initcall(cpu_probe_release_init);
+static SYSDEV_ATTR(probe, S_IWUSR, NULL, cpu_probe_store);
+static SYSDEV_ATTR(release, S_IWUSR, NULL, cpu_release_store);
#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
#else /* ... !CONFIG_HOTPLUG_CPU */
@@ -141,31 +134,39 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL);
/*
* Print cpu online, possible, present, and system maps
*/
-static ssize_t print_cpus_map(char *buf, const struct cpumask *map)
+
+struct cpu_attr {
+ struct sysdev_class_attribute attr;
+ const struct cpumask *const * const map;
+};
+
+static ssize_t show_cpus_attr(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr,
+ char *buf)
{
- int n = cpulist_scnprintf(buf, PAGE_SIZE-2, map);
+ struct cpu_attr *ca = container_of(attr, struct cpu_attr, attr);
+ int n = cpulist_scnprintf(buf, PAGE_SIZE-2, *(ca->map));
buf[n++] = '\n';
buf[n] = '\0';
return n;
}
-#define print_cpus_func(type) \
-static ssize_t print_cpus_##type(struct sysdev_class *class, char *buf) \
-{ \
- return print_cpus_map(buf, cpu_##type##_mask); \
-} \
-static struct sysdev_class_attribute attr_##type##_map = \
- _SYSDEV_CLASS_ATTR(type, 0444, print_cpus_##type, NULL)
+#define _CPU_ATTR(name, map) \
+ { _SYSDEV_CLASS_ATTR(name, 0444, show_cpus_attr, NULL), map }
-print_cpus_func(online);
-print_cpus_func(possible);
-print_cpus_func(present);
+/* Keep in sync with cpu_sysdev_class_attrs */
+static struct cpu_attr cpu_attrs[] = {
+ _CPU_ATTR(online, &cpu_online_mask),
+ _CPU_ATTR(possible, &cpu_possible_mask),
+ _CPU_ATTR(present, &cpu_present_mask),
+};
/*
* Print values for NR_CPUS and offlined cpus
*/
-static ssize_t print_cpus_kernel_max(struct sysdev_class *class, char *buf)
+static ssize_t print_cpus_kernel_max(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr, char *buf)
{
int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1);
return n;
@@ -175,7 +176,8 @@ static SYSDEV_CLASS_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL);
/* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */
unsigned int total_cpus;
-static ssize_t print_cpus_offline(struct sysdev_class *class, char *buf)
+static ssize_t print_cpus_offline(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr, char *buf)
{
int n = 0, len = PAGE_SIZE-2;
cpumask_var_t offline;
@@ -204,29 +206,6 @@ static ssize_t print_cpus_offline(struct sysdev_class *class, char *buf)
}
static SYSDEV_CLASS_ATTR(offline, 0444, print_cpus_offline, NULL);
-static struct sysdev_class_attribute *cpu_state_attr[] = {
- &attr_online_map,
- &attr_possible_map,
- &attr_present_map,
- &attr_kernel_max,
- &attr_offline,
-};
-
-static int cpu_states_init(void)
-{
- int i;
- int err = 0;
-
- for (i = 0; i < ARRAY_SIZE(cpu_state_attr); i++) {
- int ret;
- ret = sysdev_class_create_file(&cpu_sysdev_class,
- cpu_state_attr[i]);
- if (!err)
- err = ret;
- }
- return err;
-}
-
/*
* register_cpu - Setup a sysfs device for a CPU.
* @cpu - cpu->hotpluggable field set to 1 will generate a control file in
@@ -272,9 +251,6 @@ int __init cpu_dev_init(void)
int err;
err = sysdev_class_register(&cpu_sysdev_class);
- if (!err)
- err = cpu_states_init();
-
#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
if (!err)
err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class);
@@ -282,3 +258,16 @@ int __init cpu_dev_init(void)
return err;
}
+
+static struct sysdev_class_attribute *cpu_sysdev_class_attrs[] = {
+#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
+ &attr_probe,
+ &attr_release,
+#endif
+ &cpu_attrs[0].attr,
+ &cpu_attrs[1].attr,
+ &cpu_attrs[2].attr,
+ &attr_kernel_max,
+ &attr_offline,
+ NULL
+};
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index ee95c76bfd3d..c89291f8a16b 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -85,7 +85,7 @@ static void driver_sysfs_remove(struct device *dev)
* for before calling this. (It is ok to call with no other effort
* from a driver's probe() method.)
*
- * This function must be called with @dev->sem held.
+ * This function must be called with the device lock held.
*/
int device_bind_driver(struct device *dev)
{
@@ -190,8 +190,8 @@ EXPORT_SYMBOL_GPL(wait_for_device_probe);
* This function returns -ENODEV if the device is not registered,
* 1 if the device is bound successfully and 0 otherwise.
*
- * This function must be called with @dev->sem held. When called for a
- * USB interface, @dev->parent->sem must be held as well.
+ * This function must be called with @dev lock held. When called for a
+ * USB interface, @dev->parent lock must be held as well.
*/
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
@@ -233,13 +233,13 @@ static int __device_attach(struct device_driver *drv, void *data)
* 0 if no matching driver was found;
* -ENODEV if the device is not registered.
*
- * When called for a USB interface, @dev->parent->sem must be held.
+ * When called for a USB interface, @dev->parent lock must be held.
*/
int device_attach(struct device *dev)
{
int ret = 0;
- down(&dev->sem);
+ device_lock(dev);
if (dev->driver) {
ret = device_bind_driver(dev);
if (ret == 0)
@@ -253,7 +253,7 @@ int device_attach(struct device *dev)
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
pm_runtime_put_sync(dev);
}
- up(&dev->sem);
+ device_unlock(dev);
return ret;
}
EXPORT_SYMBOL_GPL(device_attach);
@@ -276,13 +276,13 @@ static int __driver_attach(struct device *dev, void *data)
return 0;
if (dev->parent) /* Needed for USB */
- down(&dev->parent->sem);
- down(&dev->sem);
+ device_lock(dev->parent);
+ device_lock(dev);
if (!dev->driver)
driver_probe_device(drv, dev);
- up(&dev->sem);
+ device_unlock(dev);
if (dev->parent)
- up(&dev->parent->sem);
+ device_unlock(dev->parent);
return 0;
}
@@ -303,8 +303,8 @@ int driver_attach(struct device_driver *drv)
EXPORT_SYMBOL_GPL(driver_attach);
/*
- * __device_release_driver() must be called with @dev->sem held.
- * When called for a USB interface, @dev->parent->sem must be held as well.
+ * __device_release_driver() must be called with @dev lock held.
+ * When called for a USB interface, @dev->parent lock must be held as well.
*/
static void __device_release_driver(struct device *dev)
{
@@ -343,7 +343,7 @@ static void __device_release_driver(struct device *dev)
* @dev: device.
*
* Manually detach device from driver.
- * When called for a USB interface, @dev->parent->sem must be held.
+ * When called for a USB interface, @dev->parent lock must be held.
*/
void device_release_driver(struct device *dev)
{
@@ -352,9 +352,9 @@ void device_release_driver(struct device *dev)
* within their ->remove callback for the same device, they
* will deadlock right here.
*/
- down(&dev->sem);
+ device_lock(dev);
__device_release_driver(dev);
- up(&dev->sem);
+ device_unlock(dev);
}
EXPORT_SYMBOL_GPL(device_release_driver);
@@ -381,13 +381,13 @@ void driver_detach(struct device_driver *drv)
spin_unlock(&drv->p->klist_devices.k_lock);
if (dev->parent) /* Needed for USB */
- down(&dev->parent->sem);
- down(&dev->sem);
+ device_lock(dev->parent);
+ device_lock(dev);
if (dev->driver == drv)
__device_release_driver(dev);
- up(&dev->sem);
+ device_unlock(dev);
if (dev->parent)
- up(&dev->parent->sem);
+ device_unlock(dev->parent);
put_device(dev);
}
}
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index 090dd4851301..dac478c6e460 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -301,6 +301,19 @@ int devtmpfs_delete_node(struct device *dev)
if (dentry->d_inode) {
err = vfs_getattr(nd.path.mnt, dentry, &stat);
if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
+ struct iattr newattrs;
+ /*
+ * before unlinking this node, reset permissions
+ * of possible references like hardlinks
+ */
+ newattrs.ia_uid = 0;
+ newattrs.ia_gid = 0;
+ newattrs.ia_mode = stat.mode & ~0777;
+ newattrs.ia_valid =
+ ATTR_UID|ATTR_GID|ATTR_MODE;
+ mutex_lock(&dentry->d_inode->i_mutex);
+ notify_change(dentry, &newattrs);
+ mutex_unlock(&dentry->d_inode->i_mutex);
err = vfs_unlink(nd.path.dentry->d_inode,
dentry);
if (!err || err == -ENOENT)
@@ -354,6 +367,7 @@ int __init devtmpfs_init(void)
{
int err;
struct vfsmount *mnt;
+ char options[] = "mode=0755";
err = register_filesystem(&dev_fs_type);
if (err) {
@@ -362,7 +376,7 @@ int __init devtmpfs_init(void)
return err;
}
- mnt = kern_mount_data(&dev_fs_type, "mode=0755");
+ mnt = kern_mount_data(&dev_fs_type, options);
if (IS_ERR(mnt)) {
err = PTR_ERR(mnt);
printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index a95024166b66..d0dc26ad5387 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -19,7 +19,6 @@
#include <linux/kthread.h>
#include <linux/highmem.h>
#include <linux/firmware.h>
-#include "base.h"
#define to_dev(obj) container_of(obj, struct device, kobj)
@@ -69,7 +68,9 @@ fw_load_abort(struct firmware_priv *fw_priv)
}
static ssize_t
-firmware_timeout_show(struct class *class, char *buf)
+firmware_timeout_show(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
{
return sprintf(buf, "%d\n", loading_timeout);
}
@@ -87,7 +88,9 @@ firmware_timeout_show(struct class *class, char *buf)
* Note: zero means 'wait forever'.
**/
static ssize_t
-firmware_timeout_store(struct class *class, const char *buf, size_t count)
+firmware_timeout_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t count)
{
loading_timeout = simple_strtol(buf, NULL, 10);
if (loading_timeout < 0)
@@ -610,7 +613,7 @@ request_firmware_work_func(void *arg)
}
/**
- * request_firmware_nowait: asynchronous version of request_firmware
+ * request_firmware_nowait - asynchronous version of request_firmware
* @module: module requesting the firmware
* @uevent: sends uevent to copy the firmware image if this flag
* is non-zero else the firmware copy must be done manually.
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index d7d77d4a402c..2f8691511190 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -44,7 +44,7 @@ static int memory_uevent(struct kset *kset, struct kobject *obj, struct kobj_uev
return retval;
}
-static struct kset_uevent_ops memory_uevent_ops = {
+static const struct kset_uevent_ops memory_uevent_ops = {
.name = memory_uevent_name,
.uevent = memory_uevent,
};
@@ -309,17 +309,18 @@ static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL);
* Block size attribute stuff
*/
static ssize_t
-print_block_size(struct class *class, char *buf)
+print_block_size(struct sysdev_class *class, struct sysdev_class_attribute *attr,
+ char *buf)
{
- return sprintf(buf, "%lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE);
+ return sprintf(buf, "%#lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE);
}
-static CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL);
+static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL);
static int block_size_init(void)
{
return sysfs_create_file(&memory_sysdev_class.kset.kobj,
- &class_attr_block_size_bytes.attr);
+ &attr_block_size_bytes.attr);
}
/*
@@ -330,7 +331,8 @@ static int block_size_init(void)
*/
#ifdef CONFIG_ARCH_MEMORY_PROBE
static ssize_t
-memory_probe_store(struct class *class, const char *buf, size_t count)
+memory_probe_store(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t count)
{
u64 phys_addr;
int nid;
@@ -367,7 +369,9 @@ static inline int memory_probe_init(void)
/* Soft offline a page */
static ssize_t
-store_soft_offline_page(struct class *class, const char *buf, size_t count)
+store_soft_offline_page(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t count)
{
int ret;
u64 pfn;
@@ -384,7 +388,9 @@ store_soft_offline_page(struct class *class, const char *buf, size_t count)
/* Forcibly offline a page, including killing processes. */
static ssize_t
-store_hard_offline_page(struct class *class, const char *buf, size_t count)
+store_hard_offline_page(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t count)
{
int ret;
u64 pfn;
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 70122791683d..ad43185ec15a 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -16,8 +16,11 @@
#include <linux/device.h>
#include <linux/swap.h>
+static struct sysdev_class_attribute *node_state_attrs[];
+
static struct sysdev_class node_class = {
.name = "node",
+ .attrs = node_state_attrs,
};
@@ -544,76 +547,52 @@ static ssize_t print_nodes_state(enum node_states state, char *buf)
return n;
}
-static ssize_t print_nodes_possible(struct sysdev_class *class, char *buf)
-{
- return print_nodes_state(N_POSSIBLE, buf);
-}
-
-static ssize_t print_nodes_online(struct sysdev_class *class, char *buf)
-{
- return print_nodes_state(N_ONLINE, buf);
-}
-
-static ssize_t print_nodes_has_normal_memory(struct sysdev_class *class,
- char *buf)
-{
- return print_nodes_state(N_NORMAL_MEMORY, buf);
-}
+struct node_attr {
+ struct sysdev_class_attribute attr;
+ enum node_states state;
+};
-static ssize_t print_nodes_has_cpu(struct sysdev_class *class, char *buf)
+static ssize_t show_node_state(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr, char *buf)
{
- return print_nodes_state(N_CPU, buf);
+ struct node_attr *na = container_of(attr, struct node_attr, attr);
+ return print_nodes_state(na->state, buf);
}
-static SYSDEV_CLASS_ATTR(possible, 0444, print_nodes_possible, NULL);
-static SYSDEV_CLASS_ATTR(online, 0444, print_nodes_online, NULL);
-static SYSDEV_CLASS_ATTR(has_normal_memory, 0444, print_nodes_has_normal_memory,
- NULL);
-static SYSDEV_CLASS_ATTR(has_cpu, 0444, print_nodes_has_cpu, NULL);
+#define _NODE_ATTR(name, state) \
+ { _SYSDEV_CLASS_ATTR(name, 0444, show_node_state, NULL), state }
+static struct node_attr node_state_attr[] = {
+ _NODE_ATTR(possible, N_POSSIBLE),
+ _NODE_ATTR(online, N_ONLINE),
+ _NODE_ATTR(has_normal_memory, N_NORMAL_MEMORY),
+ _NODE_ATTR(has_cpu, N_CPU),
#ifdef CONFIG_HIGHMEM
-static ssize_t print_nodes_has_high_memory(struct sysdev_class *class,
- char *buf)
-{
- return print_nodes_state(N_HIGH_MEMORY, buf);
-}
-
-static SYSDEV_CLASS_ATTR(has_high_memory, 0444, print_nodes_has_high_memory,
- NULL);
+ _NODE_ATTR(has_high_memory, N_HIGH_MEMORY),
#endif
+};
-struct sysdev_class_attribute *node_state_attr[] = {
- &attr_possible,
- &attr_online,
- &attr_has_normal_memory,
+static struct sysdev_class_attribute *node_state_attrs[] = {
+ &node_state_attr[0].attr,
+ &node_state_attr[1].attr,
+ &node_state_attr[2].attr,
+ &node_state_attr[3].attr,
#ifdef CONFIG_HIGHMEM
- &attr_has_high_memory,
+ &node_state_attr[4].attr,
#endif
- &attr_has_cpu,
+ NULL
};
-static int node_states_init(void)
-{
- int i;
- int err = 0;
-
- for (i = 0; i < NR_NODE_STATES; i++) {
- int ret;
- ret = sysdev_class_create_file(&node_class, node_state_attr[i]);
- if (!err)
- err = ret;
- }
- return err;
-}
-
#define NODE_CALLBACK_PRI 2 /* lower than SLAB */
static int __init register_node_type(void)
{
int ret;
+ BUILD_BUG_ON(ARRAY_SIZE(node_state_attr) != NR_NODE_STATES);
+ BUILD_BUG_ON(ARRAY_SIZE(node_state_attrs)-1 != NR_NODE_STATES);
+
ret = sysdev_class_register(&node_class);
if (!ret) {
- ret = node_states_init();
hotplug_memory_notifier(node_memory_callback,
NODE_CALLBACK_PRI);
}
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 58efaf2f1259..1ba9d617d241 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -128,7 +128,7 @@ struct platform_object {
};
/**
- * platform_device_put
+ * platform_device_put - destroy a platform device
* @pdev: platform device to free
*
* Free all memory associated with a platform device. This function must
@@ -152,7 +152,7 @@ static void platform_device_release(struct device *dev)
}
/**
- * platform_device_alloc
+ * platform_device_alloc - create a platform device
* @name: base name of the device we're adding
* @id: instance id
*
@@ -177,7 +177,7 @@ struct platform_device *platform_device_alloc(const char *name, int id)
EXPORT_SYMBOL_GPL(platform_device_alloc);
/**
- * platform_device_add_resources
+ * platform_device_add_resources - add resources to a platform device
* @pdev: platform device allocated by platform_device_alloc to add resources to
* @res: set of resources that needs to be allocated for the device
* @num: number of resources
@@ -202,7 +202,7 @@ int platform_device_add_resources(struct platform_device *pdev,
EXPORT_SYMBOL_GPL(platform_device_add_resources);
/**
- * platform_device_add_data
+ * platform_device_add_data - add platform-specific data to a platform device
* @pdev: platform device allocated by platform_device_alloc to add resources to
* @data: platform specific data for this platform device
* @size: size of platform specific data
@@ -344,7 +344,7 @@ void platform_device_unregister(struct platform_device *pdev)
EXPORT_SYMBOL_GPL(platform_device_unregister);
/**
- * platform_device_register_simple
+ * platform_device_register_simple - add a platform-level device and its resources
* @name: base name of the device we're adding
* @id: instance id
* @res: set of resources that needs to be allocated for the device
@@ -396,7 +396,7 @@ error:
EXPORT_SYMBOL_GPL(platform_device_register_simple);
/**
- * platform_device_register_data
+ * platform_device_register_data - add a platform-level device with platform-specific data
* @parent: parent device for the device we're adding
* @name: base name of the device we're adding
* @id: instance id
@@ -473,7 +473,7 @@ static void platform_drv_shutdown(struct device *_dev)
}
/**
- * platform_driver_register
+ * platform_driver_register - register a driver for platform-level devices
* @drv: platform driver structure
*/
int platform_driver_register(struct platform_driver *drv)
@@ -491,7 +491,7 @@ int platform_driver_register(struct platform_driver *drv)
EXPORT_SYMBOL_GPL(platform_driver_register);
/**
- * platform_driver_unregister
+ * platform_driver_unregister - unregister a driver for platform-level devices
* @drv: platform driver structure
*/
void platform_driver_unregister(struct platform_driver *drv)
@@ -548,6 +548,64 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv,
}
EXPORT_SYMBOL_GPL(platform_driver_probe);
+/**
+ * platform_create_bundle - register driver and create corresponding device
+ * @driver: platform driver structure
+ * @probe: the driver probe routine, probably from an __init section
+ * @res: set of resources that needs to be allocated for the device
+ * @n_res: number of resources
+ * @data: platform specific data for this platform device
+ * @size: size of platform specific data
+ *
+ * Use this in legacy-style modules that probe hardware directly and
+ * register a single platform device and corresponding platform driver.
+ */
+struct platform_device * __init_or_module platform_create_bundle(
+ struct platform_driver *driver,
+ int (*probe)(struct platform_device *),
+ struct resource *res, unsigned int n_res,
+ const void *data, size_t size)
+{
+ struct platform_device *pdev;
+ int error;
+
+ pdev = platform_device_alloc(driver->driver.name, -1);
+ if (!pdev) {
+ error = -ENOMEM;
+ goto err_out;
+ }
+
+ if (res) {
+ error = platform_device_add_resources(pdev, res, n_res);
+ if (error)
+ goto err_pdev_put;
+ }
+
+ if (data) {
+ error = platform_device_add_data(pdev, data, size);
+ if (error)
+ goto err_pdev_put;
+ }
+
+ error = platform_device_add(pdev);
+ if (error)
+ goto err_pdev_put;
+
+ error = platform_driver_probe(driver, probe);
+ if (error)
+ goto err_pdev_del;
+
+ return pdev;
+
+err_pdev_del:
+ platform_device_del(pdev);
+err_pdev_put:
+ platform_device_put(pdev);
+err_out:
+ return ERR_PTR(error);
+}
+EXPORT_SYMBOL_GPL(platform_create_bundle);
+
/* modalias support enables more hands-off userspace setup:
* (a) environment variable lets new-style hotplug events work once system is
* fully running: "modprobe $MODALIAS"
@@ -578,7 +636,7 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
}
static const struct platform_device_id *platform_match_id(
- struct platform_device_id *id,
+ const struct platform_device_id *id,
struct platform_device *pdev)
{
while (id->name[0]) {
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 3ce3519e8f30..89de75325cea 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_PM) += sysfs.o
obj-$(CONFIG_PM_SLEEP) += main.o
obj-$(CONFIG_PM_RUNTIME) += runtime.o
+obj-$(CONFIG_PM_OPS) += generic_ops.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c
new file mode 100644
index 000000000000..4b29d4981253
--- /dev/null
+++ b/drivers/base/power/generic_ops.c
@@ -0,0 +1,233 @@
+/*
+ * drivers/base/power/generic_ops.c - Generic PM callbacks for subsystems
+ *
+ * Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+
+#ifdef CONFIG_PM_RUNTIME
+/**
+ * pm_generic_runtime_idle - Generic runtime idle callback for subsystems.
+ * @dev: Device to handle.
+ *
+ * If PM operations are defined for the @dev's driver and they include
+ * ->runtime_idle(), execute it and return its error code, if nonzero.
+ * Otherwise, execute pm_runtime_suspend() for the device and return 0.
+ */
+int pm_generic_runtime_idle(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (pm && pm->runtime_idle) {
+ int ret = pm->runtime_idle(dev);
+ if (ret)
+ return ret;
+ }
+
+ pm_runtime_suspend(dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pm_generic_runtime_idle);
+
+/**
+ * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems.
+ * @dev: Device to suspend.
+ *
+ * If PM operations are defined for the @dev's driver and they include
+ * ->runtime_suspend(), execute it and return its error code. Otherwise,
+ * return -EINVAL.
+ */
+int pm_generic_runtime_suspend(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ int ret;
+
+ ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : -EINVAL;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend);
+
+/**
+ * pm_generic_runtime_resume - Generic runtime resume callback for subsystems.
+ * @dev: Device to resume.
+ *
+ * If PM operations are defined for the @dev's driver and they include
+ * ->runtime_resume(), execute it and return its error code. Otherwise,
+ * return -EINVAL.
+ */
+int pm_generic_runtime_resume(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ int ret;
+
+ ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : -EINVAL;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pm_generic_runtime_resume);
+#endif /* CONFIG_PM_RUNTIME */
+
+#ifdef CONFIG_PM_SLEEP
+/**
+ * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback.
+ * @dev: Device to handle.
+ * @event: PM transition of the system under way.
+ *
+ * If the device has not been suspended at run time, execute the
+ * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and
+ * return its error code. Otherwise, return zero.
+ */
+static int __pm_generic_call(struct device *dev, int event)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ int (*callback)(struct device *);
+
+ if (!pm || pm_runtime_suspended(dev))
+ return 0;
+
+ switch (event) {
+ case PM_EVENT_SUSPEND:
+ callback = pm->suspend;
+ break;
+ case PM_EVENT_FREEZE:
+ callback = pm->freeze;
+ break;
+ case PM_EVENT_HIBERNATE:
+ callback = pm->poweroff;
+ break;
+ case PM_EVENT_THAW:
+ callback = pm->thaw;
+ break;
+ default:
+ callback = NULL;
+ break;
+ }
+
+ return callback ? callback(dev) : 0;
+}
+
+/**
+ * pm_generic_suspend - Generic suspend callback for subsystems.
+ * @dev: Device to suspend.
+ */
+int pm_generic_suspend(struct device *dev)
+{
+ return __pm_generic_call(dev, PM_EVENT_SUSPEND);
+}
+EXPORT_SYMBOL_GPL(pm_generic_suspend);
+
+/**
+ * pm_generic_freeze - Generic freeze callback for subsystems.
+ * @dev: Device to freeze.
+ */
+int pm_generic_freeze(struct device *dev)
+{
+ return __pm_generic_call(dev, PM_EVENT_FREEZE);
+}
+EXPORT_SYMBOL_GPL(pm_generic_freeze);
+
+/**
+ * pm_generic_poweroff - Generic poweroff callback for subsystems.
+ * @dev: Device to handle.
+ */
+int pm_generic_poweroff(struct device *dev)
+{
+ return __pm_generic_call(dev, PM_EVENT_HIBERNATE);
+}
+EXPORT_SYMBOL_GPL(pm_generic_poweroff);
+
+/**
+ * pm_generic_thaw - Generic thaw callback for subsystems.
+ * @dev: Device to thaw.
+ */
+int pm_generic_thaw(struct device *dev)
+{
+ return __pm_generic_call(dev, PM_EVENT_THAW);
+}
+EXPORT_SYMBOL_GPL(pm_generic_thaw);
+
+/**
+ * __pm_generic_resume - Generic resume/restore callback for subsystems.
+ * @dev: Device to handle.
+ * @event: PM transition of the system under way.
+ *
+ * Execute the resume/resotre callback provided by the @dev's driver, if
+ * defined. If it returns 0, change the device's runtime PM status to 'active'.
+ * Return the callback's error code.
+ */
+static int __pm_generic_resume(struct device *dev, int event)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ int (*callback)(struct device *);
+ int ret;
+
+ if (!pm)
+ return 0;
+
+ switch (event) {
+ case PM_EVENT_RESUME:
+ callback = pm->resume;
+ break;
+ case PM_EVENT_RESTORE:
+ callback = pm->restore;
+ break;
+ default:
+ callback = NULL;
+ break;
+ }
+
+ if (!callback)
+ return 0;
+
+ ret = callback(dev);
+ if (!ret) {
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ }
+
+ return ret;
+}
+
+/**
+ * pm_generic_resume - Generic resume callback for subsystems.
+ * @dev: Device to resume.
+ */
+int pm_generic_resume(struct device *dev)
+{
+ return __pm_generic_resume(dev, PM_EVENT_RESUME);
+}
+EXPORT_SYMBOL_GPL(pm_generic_resume);
+
+/**
+ * pm_generic_restore - Generic restore callback for subsystems.
+ * @dev: Device to restore.
+ */
+int pm_generic_restore(struct device *dev)
+{
+ return __pm_generic_resume(dev, PM_EVENT_RESTORE);
+}
+EXPORT_SYMBOL_GPL(pm_generic_restore);
+#endif /* CONFIG_PM_SLEEP */
+
+struct dev_pm_ops generic_subsys_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+ .suspend = pm_generic_suspend,
+ .resume = pm_generic_resume,
+ .freeze = pm_generic_freeze,
+ .thaw = pm_generic_thaw,
+ .poweroff = pm_generic_poweroff,
+ .restore = pm_generic_restore,
+#endif
+#ifdef CONFIG_PM_RUNTIME
+ .runtime_suspend = pm_generic_runtime_suspend,
+ .runtime_resume = pm_generic_runtime_resume,
+ .runtime_idle = pm_generic_runtime_idle,
+#endif
+};
+EXPORT_SYMBOL_GPL(generic_subsys_pm_ops);
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index a5142bddef41..d477f4dc5e51 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -25,6 +25,7 @@
#include <linux/resume-trace.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
+#include <linux/async.h>
#include "../base.h"
#include "power.h"
@@ -34,14 +35,15 @@
* because children are guaranteed to be discovered after parents, and
* are inserted at the back of the list on discovery.
*
- * Since device_pm_add() may be called with a device semaphore held,
- * we must never try to acquire a device semaphore while holding
+ * Since device_pm_add() may be called with a device lock held,
+ * we must never try to acquire a device lock while holding
* dpm_list_mutex.
*/
LIST_HEAD(dpm_list);
static DEFINE_MUTEX(dpm_list_mtx);
+static pm_message_t pm_transition;
/*
* Set once the preparation of devices for a PM transition has started, reset
@@ -56,6 +58,7 @@ static bool transition_started;
void device_pm_init(struct device *dev)
{
dev->power.status = DPM_ON;
+ init_completion(&dev->power.completion);
pm_runtime_init(dev);
}
@@ -111,6 +114,7 @@ void device_pm_remove(struct device *dev)
pr_debug("PM: Removing info for %s:%s\n",
dev->bus ? dev->bus->name : "No Bus",
kobject_name(&dev->kobj));
+ complete_all(&dev->power.completion);
mutex_lock(&dpm_list_mtx);
list_del_init(&dev->power.entry);
mutex_unlock(&dpm_list_mtx);
@@ -188,6 +192,31 @@ static void initcall_debug_report(struct device *dev, ktime_t calltime,
}
/**
+ * dpm_wait - Wait for a PM operation to complete.
+ * @dev: Device to wait for.
+ * @async: If unset, wait only if the device's power.async_suspend flag is set.
+ */
+static void dpm_wait(struct device *dev, bool async)
+{
+ if (!dev)
+ return;
+
+ if (async || (pm_async_enabled && dev->power.async_suspend))
+ wait_for_completion(&dev->power.completion);
+}
+
+static int dpm_wait_fn(struct device *dev, void *async_ptr)
+{
+ dpm_wait(dev, *((bool *)async_ptr));
+ return 0;
+}
+
+static void dpm_wait_for_children(struct device *dev, bool async)
+{
+ device_for_each_child(dev, &async, dpm_wait_fn);
+}
+
+/**
* pm_op - Execute the PM operation appropriate for given PM event.
* @dev: Device to handle.
* @ops: PM operations to choose from.
@@ -271,8 +300,9 @@ static int pm_noirq_op(struct device *dev,
ktime_t calltime, delta, rettime;
if (initcall_debug) {
- pr_info("calling %s_i+ @ %i\n",
- dev_name(dev), task_pid_nr(current));
+ pr_info("calling %s+ @ %i, parent: %s\n",
+ dev_name(dev), task_pid_nr(current),
+ dev->parent ? dev_name(dev->parent) : "none");
calltime = ktime_get();
}
@@ -468,15 +498,19 @@ static int legacy_resume(struct device *dev, int (*cb)(struct device *dev))
* device_resume - Execute "resume" callbacks for given device.
* @dev: Device to handle.
* @state: PM transition of the system being carried out.
+ * @async: If true, the device is being resumed asynchronously.
*/
-static int device_resume(struct device *dev, pm_message_t state)
+static int device_resume(struct device *dev, pm_message_t state, bool async)
{
int error = 0;
TRACE_DEVICE(dev);
TRACE_RESUME(0);
- down(&dev->sem);
+ dpm_wait(dev->parent, async);
+ device_lock(dev);
+
+ dev->power.status = DPM_RESUMING;
if (dev->bus) {
if (dev->bus->pm) {
@@ -509,12 +543,30 @@ static int device_resume(struct device *dev, pm_message_t state)
}
}
End:
- up(&dev->sem);
+ device_unlock(dev);
+ complete_all(&dev->power.completion);
TRACE_RESUME(error);
return error;
}
+static void async_resume(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+ int error;
+
+ error = device_resume(dev, pm_transition, true);
+ if (error)
+ pm_dev_err(dev, pm_transition, " async", error);
+ put_device(dev);
+}
+
+static bool is_async(struct device *dev)
+{
+ return dev->power.async_suspend && pm_async_enabled
+ && !pm_trace_is_enabled();
+}
+
/**
* dpm_resume - Execute "resume" callbacks for non-sysdev devices.
* @state: PM transition of the system being carried out.
@@ -525,21 +577,33 @@ static int device_resume(struct device *dev, pm_message_t state)
static void dpm_resume(pm_message_t state)
{
struct list_head list;
+ struct device *dev;
ktime_t starttime = ktime_get();
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
- while (!list_empty(&dpm_list)) {
- struct device *dev = to_device(dpm_list.next);
+ pm_transition = state;
+
+ list_for_each_entry(dev, &dpm_list, power.entry) {
+ if (dev->power.status < DPM_OFF)
+ continue;
+
+ INIT_COMPLETION(dev->power.completion);
+ if (is_async(dev)) {
+ get_device(dev);
+ async_schedule(async_resume, dev);
+ }
+ }
+ while (!list_empty(&dpm_list)) {
+ dev = to_device(dpm_list.next);
get_device(dev);
- if (dev->power.status >= DPM_OFF) {
+ if (dev->power.status >= DPM_OFF && !is_async(dev)) {
int error;
- dev->power.status = DPM_RESUMING;
mutex_unlock(&dpm_list_mtx);
- error = device_resume(dev, state);
+ error = device_resume(dev, state, false);
mutex_lock(&dpm_list_mtx);
if (error)
@@ -554,6 +618,7 @@ static void dpm_resume(pm_message_t state)
}
list_splice(&list, &dpm_list);
mutex_unlock(&dpm_list_mtx);
+ async_synchronize_full();
dpm_show_time(starttime, state, NULL);
}
@@ -564,7 +629,7 @@ static void dpm_resume(pm_message_t state)
*/
static void device_complete(struct device *dev, pm_message_t state)
{
- down(&dev->sem);
+ device_lock(dev);
if (dev->class && dev->class->pm && dev->class->pm->complete) {
pm_dev_dbg(dev, state, "completing class ");
@@ -581,7 +646,7 @@ static void device_complete(struct device *dev, pm_message_t state)
dev->bus->pm->complete(dev);
}
- up(&dev->sem);
+ device_unlock(dev);
}
/**
@@ -731,16 +796,23 @@ static int legacy_suspend(struct device *dev, pm_message_t state,
return error;
}
+static int async_error;
+
/**
* device_suspend - Execute "suspend" callbacks for given device.
* @dev: Device to handle.
* @state: PM transition of the system being carried out.
+ * @async: If true, the device is being suspended asynchronously.
*/
-static int device_suspend(struct device *dev, pm_message_t state)
+static int __device_suspend(struct device *dev, pm_message_t state, bool async)
{
int error = 0;
- down(&dev->sem);
+ dpm_wait_for_children(dev, async);
+ device_lock(dev);
+
+ if (async_error)
+ goto End;
if (dev->class) {
if (dev->class->pm) {
@@ -772,12 +844,44 @@ static int device_suspend(struct device *dev, pm_message_t state)
error = legacy_suspend(dev, state, dev->bus->suspend);
}
}
+
+ if (!error)
+ dev->power.status = DPM_OFF;
+
End:
- up(&dev->sem);
+ device_unlock(dev);
+ complete_all(&dev->power.completion);
return error;
}
+static void async_suspend(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+ int error;
+
+ error = __device_suspend(dev, pm_transition, true);
+ if (error) {
+ pm_dev_err(dev, pm_transition, " async", error);
+ async_error = error;
+ }
+
+ put_device(dev);
+}
+
+static int device_suspend(struct device *dev)
+{
+ INIT_COMPLETION(dev->power.completion);
+
+ if (pm_async_enabled && dev->power.async_suspend) {
+ get_device(dev);
+ async_schedule(async_suspend, dev);
+ return 0;
+ }
+
+ return __device_suspend(dev, pm_transition, false);
+}
+
/**
* dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
* @state: PM transition of the system being carried out.
@@ -790,13 +894,15 @@ static int dpm_suspend(pm_message_t state)
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
+ pm_transition = state;
+ async_error = 0;
while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.prev);
get_device(dev);
mutex_unlock(&dpm_list_mtx);
- error = device_suspend(dev, state);
+ error = device_suspend(dev);
mutex_lock(&dpm_list_mtx);
if (error) {
@@ -804,13 +910,17 @@ static int dpm_suspend(pm_message_t state)
put_device(dev);
break;
}
- dev->power.status = DPM_OFF;
if (!list_empty(&dev->power.entry))
list_move(&dev->power.entry, &list);
put_device(dev);
+ if (async_error)
+ break;
}
list_splice(&list, dpm_list.prev);
mutex_unlock(&dpm_list_mtx);
+ async_synchronize_full();
+ if (!error)
+ error = async_error;
if (!error)
dpm_show_time(starttime, state, NULL);
return error;
@@ -828,7 +938,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
{
int error = 0;
- down(&dev->sem);
+ device_lock(dev);
if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) {
pm_dev_dbg(dev, state, "preparing ");
@@ -852,7 +962,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
suspend_report_result(dev->class->pm->prepare, error);
}
End:
- up(&dev->sem);
+ device_unlock(dev);
return error;
}
@@ -936,3 +1046,14 @@ void __suspend_report_result(const char *function, void *fn, int ret)
printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret);
}
EXPORT_SYMBOL_GPL(__suspend_report_result);
+
+/**
+ * device_pm_wait_for_dev - Wait for suspend/resume of a device to complete.
+ * @dev: Device to wait for.
+ * @subordinate: Device that needs to wait for @dev.
+ */
+void device_pm_wait_for_dev(struct device *subordinate, struct device *dev)
+{
+ dpm_wait(dev, subordinate->power.async_suspend);
+}
+EXPORT_SYMBOL_GPL(device_pm_wait_for_dev);
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index b8fa1aa5225a..c0bd03c83b9c 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -12,10 +12,10 @@ static inline void pm_runtime_remove(struct device *dev) {}
#ifdef CONFIG_PM_SLEEP
-/*
- * main.c
- */
+/* kernel/power/main.c */
+extern int pm_async_enabled;
+/* drivers/base/power/main.c */
extern struct list_head dpm_list; /* The active device list */
static inline struct device *to_device(struct list_head *entry)
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index f8b044e8aef7..626dd147b75f 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1011,6 +1011,50 @@ void pm_runtime_enable(struct device *dev)
EXPORT_SYMBOL_GPL(pm_runtime_enable);
/**
+ * pm_runtime_forbid - Block run-time PM of a device.
+ * @dev: Device to handle.
+ *
+ * Increase the device's usage count and clear its power.runtime_auto flag,
+ * so that it cannot be suspended at run time until pm_runtime_allow() is called
+ * for it.
+ */
+void pm_runtime_forbid(struct device *dev)
+{
+ spin_lock_irq(&dev->power.lock);
+ if (!dev->power.runtime_auto)
+ goto out;
+
+ dev->power.runtime_auto = false;
+ atomic_inc(&dev->power.usage_count);
+ __pm_runtime_resume(dev, false);
+
+ out:
+ spin_unlock_irq(&dev->power.lock);
+}
+EXPORT_SYMBOL_GPL(pm_runtime_forbid);
+
+/**
+ * pm_runtime_allow - Unblock run-time PM of a device.
+ * @dev: Device to handle.
+ *
+ * Decrease the device's usage count and set its power.runtime_auto flag.
+ */
+void pm_runtime_allow(struct device *dev)
+{
+ spin_lock_irq(&dev->power.lock);
+ if (dev->power.runtime_auto)
+ goto out;
+
+ dev->power.runtime_auto = true;
+ if (atomic_dec_and_test(&dev->power.usage_count))
+ __pm_runtime_idle(dev);
+
+ out:
+ spin_unlock_irq(&dev->power.lock);
+}
+EXPORT_SYMBOL_GPL(pm_runtime_allow);
+
+/**
* pm_runtime_init - Initialize run-time PM fields in given device object.
* @dev: Device object to initialize.
*/
@@ -1028,6 +1072,7 @@ void pm_runtime_init(struct device *dev)
atomic_set(&dev->power.child_count, 0);
pm_suspend_ignore_children(dev, false);
+ dev->power.runtime_auto = true;
dev->power.request_pending = false;
dev->power.request = RPM_REQ_NONE;
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 596aeecfdffe..86fd9373447e 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -4,9 +4,25 @@
#include <linux/device.h>
#include <linux/string.h>
+#include <linux/pm_runtime.h>
#include "power.h"
/*
+ * control - Report/change current runtime PM setting of the device
+ *
+ * Runtime power management of a device can be blocked with the help of
+ * this attribute. All devices have one of the following two values for
+ * the power/control file:
+ *
+ * + "auto\n" to allow the device to be power managed at run time;
+ * + "on\n" to prevent the device from being power managed at run time;
+ *
+ * The default for all devices is "auto", which means that devices may be
+ * subject to automatic power management, depending on their drivers.
+ * Changing this attribute to "on" prevents the driver from power managing
+ * the device at run time. Doing that while the device is suspended causes
+ * it to be woken up.
+ *
* wakeup - Report/change current wakeup option for device
*
* Some devices support "wakeup" events, which are hardware signals
@@ -38,11 +54,61 @@
* wakeup events internally (unless they are disabled), keeping
* their hardware in low power modes whenever they're unused. This
* saves runtime power, without requiring system-wide sleep states.
+ *
+ * async - Report/change current async suspend setting for the device
+ *
+ * Asynchronous suspend and resume of the device during system-wide power
+ * state transitions can be enabled by writing "enabled" to this file.
+ * Analogously, if "disabled" is written to this file, the device will be
+ * suspended and resumed synchronously.
+ *
+ * All devices have one of the following two values for power/async:
+ *
+ * + "enabled\n" to permit the asynchronous suspend/resume of the device;
+ * + "disabled\n" to forbid it;
+ *
+ * NOTE: It generally is unsafe to permit the asynchronous suspend/resume
+ * of a device unless it is certain that all of the PM dependencies of the
+ * device are known to the PM core. However, for some devices this
+ * attribute is set to "enabled" by bus type code or device drivers and in
+ * that cases it should be safe to leave the default value.
*/
static const char enabled[] = "enabled";
static const char disabled[] = "disabled";
+#ifdef CONFIG_PM_RUNTIME
+static const char ctrl_auto[] = "auto";
+static const char ctrl_on[] = "on";
+
+static ssize_t control_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n",
+ dev->power.runtime_auto ? ctrl_auto : ctrl_on);
+}
+
+static ssize_t control_store(struct device * dev, struct device_attribute *attr,
+ const char * buf, size_t n)
+{
+ char *cp;
+ int len = n;
+
+ cp = memchr(buf, '\n', n);
+ if (cp)
+ len = cp - buf;
+ if (len == sizeof ctrl_auto - 1 && strncmp(buf, ctrl_auto, len) == 0)
+ pm_runtime_allow(dev);
+ else if (len == sizeof ctrl_on - 1 && strncmp(buf, ctrl_on, len) == 0)
+ pm_runtime_forbid(dev);
+ else
+ return -EINVAL;
+ return n;
+}
+
+static DEVICE_ATTR(control, 0644, control_show, control_store);
+#endif
+
static ssize_t
wake_show(struct device * dev, struct device_attribute *attr, char * buf)
{
@@ -77,9 +143,43 @@ wake_store(struct device * dev, struct device_attribute *attr,
static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
+#ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG
+static ssize_t async_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n",
+ device_async_suspend_enabled(dev) ? enabled : disabled);
+}
+
+static ssize_t async_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ char *cp;
+ int len = n;
+
+ cp = memchr(buf, '\n', n);
+ if (cp)
+ len = cp - buf;
+ if (len == sizeof enabled - 1 && strncmp(buf, enabled, len) == 0)
+ device_enable_async_suspend(dev);
+ else if (len == sizeof disabled - 1 && strncmp(buf, disabled, len) == 0)
+ device_disable_async_suspend(dev);
+ else
+ return -EINVAL;
+ return n;
+}
+
+static DEVICE_ATTR(async, 0644, async_show, async_store);
+#endif /* CONFIG_PM_SLEEP_ADVANCED_DEBUG */
static struct attribute * power_attrs[] = {
+#ifdef CONFIG_PM_RUNTIME
+ &dev_attr_control.attr,
+#endif
&dev_attr_wakeup.attr,
+#ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG
+ &dev_attr_async.attr,
+#endif
NULL,
};
static struct attribute_group pm_attr_group = {
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 0d903909af7e..8980feec5d14 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -54,7 +54,7 @@ sysdev_store(struct kobject *kobj, struct attribute *attr,
return -EIO;
}
-static struct sysfs_ops sysfs_ops = {
+static const struct sysfs_ops sysfs_ops = {
.show = sysdev_show,
.store = sysdev_store,
};
@@ -89,7 +89,7 @@ static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr,
struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr);
if (class_attr->show)
- return class_attr->show(class, buffer);
+ return class_attr->show(class, class_attr, buffer);
return -EIO;
}
@@ -100,11 +100,11 @@ static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr,
struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr);
if (class_attr->store)
- return class_attr->store(class, buffer, count);
+ return class_attr->store(class, class_attr, buffer, count);
return -EIO;
}
-static struct sysfs_ops sysfs_class_ops = {
+static const struct sysfs_ops sysfs_class_ops = {
.show = sysdev_class_show,
.store = sysdev_class_store,
};
@@ -145,13 +145,20 @@ int sysdev_class_register(struct sysdev_class *cls)
if (retval)
return retval;
- return kset_register(&cls->kset);
+ retval = kset_register(&cls->kset);
+ if (!retval && cls->attrs)
+ retval = sysfs_create_files(&cls->kset.kobj,
+ (const struct attribute **)cls->attrs);
+ return retval;
}
void sysdev_class_unregister(struct sysdev_class *cls)
{
pr_debug("Unregistering sysdev class '%s'\n",
kobject_name(&cls->kset.kobj));
+ if (cls->attrs)
+ sysfs_remove_files(&cls->kset.kobj,
+ (const struct attribute **)cls->attrs);
kset_unregister(&cls->kset);
}
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index ce1fa923c414..459f1bc25a7b 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -2534,8 +2534,8 @@ static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
blk_queue_bounce_limit(RequestQueue, Controller->BounceBufferLimit);
RequestQueue->queuedata = Controller;
blk_queue_max_hw_segments(RequestQueue, Controller->DriverScatterGatherLimit);
- blk_queue_max_phys_segments(RequestQueue, Controller->DriverScatterGatherLimit);
- blk_queue_max_sectors(RequestQueue, Controller->MaxBlocksPerCommand);
+ blk_queue_max_segments(RequestQueue, Controller->DriverScatterGatherLimit);
+ blk_queue_max_hw_sectors(RequestQueue, Controller->MaxBlocksPerCommand);
disk->queue = RequestQueue;
sprintf(disk->disk_name, "rd/c%dd%d", Controller->ControllerNumber, n);
disk->major = MajorNumber;
@@ -7134,7 +7134,7 @@ static struct DAC960_privdata DAC960_P_privdata = {
.MemoryWindowSize = DAC960_PD_RegisterWindowSize,
};
-static struct pci_device_id DAC960_id_table[] = {
+static const struct pci_device_id DAC960_id_table[] = {
{
.vendor = PCI_VENDOR_ID_MYLEX,
.device = PCI_DEVICE_ID_MYLEX_DAC960_GEM,
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index a5af1d6dda8b..e35cf59cbfde 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1470,8 +1470,6 @@ repeat:
void do_fd_request(struct request_queue * q)
{
- unsigned long flags;
-
DPRINT(("do_fd_request for pid %d\n",current->pid));
while( fdc_busy ) sleep_on( &fdc_wait );
fdc_busy = 1;
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index 4f688434daf1..c6ddeacb77fd 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -434,7 +434,7 @@ static struct brd_device *brd_alloc(int i)
goto out_free_dev;
blk_queue_make_request(brd->brd_queue, brd_make_request);
blk_queue_ordered(brd->brd_queue, QUEUE_ORDERED_TAG, NULL);
- blk_queue_max_sectors(brd->brd_queue, 1024);
+ blk_queue_max_hw_sectors(brd->brd_queue, 1024);
blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY);
disk = brd->brd_disk = alloc_disk(1 << part_shift);
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 873e594860d3..9e3af307aae1 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -257,6 +257,79 @@ static inline void removeQ(CommandList_struct *c)
hlist_del_init(&c->list);
}
+static void cciss_free_sg_chain_blocks(SGDescriptor_struct **cmd_sg_list,
+ int nr_cmds)
+{
+ int i;
+
+ if (!cmd_sg_list)
+ return;
+ for (i = 0; i < nr_cmds; i++) {
+ kfree(cmd_sg_list[i]);
+ cmd_sg_list[i] = NULL;
+ }
+ kfree(cmd_sg_list);
+}
+
+static SGDescriptor_struct **cciss_allocate_sg_chain_blocks(
+ ctlr_info_t *h, int chainsize, int nr_cmds)
+{
+ int j;
+ SGDescriptor_struct **cmd_sg_list;
+
+ if (chainsize <= 0)
+ return NULL;
+
+ cmd_sg_list = kmalloc(sizeof(*cmd_sg_list) * nr_cmds, GFP_KERNEL);
+ if (!cmd_sg_list)
+ return NULL;
+
+ /* Build up chain blocks for each command */
+ for (j = 0; j < nr_cmds; j++) {
+ /* Need a block of chainsized s/g elements. */
+ cmd_sg_list[j] = kmalloc((chainsize *
+ sizeof(*cmd_sg_list[j])), GFP_KERNEL);
+ if (!cmd_sg_list[j]) {
+ dev_err(&h->pdev->dev, "Cannot get memory "
+ "for s/g chains.\n");
+ goto clean;
+ }
+ }
+ return cmd_sg_list;
+clean:
+ cciss_free_sg_chain_blocks(cmd_sg_list, nr_cmds);
+ return NULL;
+}
+
+static void cciss_unmap_sg_chain_block(ctlr_info_t *h, CommandList_struct *c)
+{
+ SGDescriptor_struct *chain_sg;
+ u64bit temp64;
+
+ if (c->Header.SGTotal <= h->max_cmd_sgentries)
+ return;
+
+ chain_sg = &c->SG[h->max_cmd_sgentries - 1];
+ temp64.val32.lower = chain_sg->Addr.lower;
+ temp64.val32.upper = chain_sg->Addr.upper;
+ pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE);
+}
+
+static void cciss_map_sg_chain_block(ctlr_info_t *h, CommandList_struct *c,
+ SGDescriptor_struct *chain_block, int len)
+{
+ SGDescriptor_struct *chain_sg;
+ u64bit temp64;
+
+ chain_sg = &c->SG[h->max_cmd_sgentries - 1];
+ chain_sg->Ext = CCISS_SG_CHAIN;
+ chain_sg->Len = len;
+ temp64.val = pci_map_single(h->pdev, chain_block, len,
+ PCI_DMA_TODEVICE);
+ chain_sg->Addr.lower = temp64.val32.lower;
+ chain_sg->Addr.upper = temp64.val32.upper;
+}
+
#include "cciss_scsi.c" /* For SCSI tape support */
static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
@@ -337,6 +410,9 @@ static int cciss_seq_show(struct seq_file *seq, void *v)
if (*pos > h->highest_lun)
return 0;
+ if (drv == NULL) /* it's possible for h->drv[] to have holes. */
+ return 0;
+
if (drv->heads == 0)
return 0;
@@ -1341,26 +1417,27 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
kfree(buff);
return -ENOMEM;
}
- // Fill in the command type
+ /* Fill in the command type */
c->cmd_type = CMD_IOCTL_PEND;
- // Fill in Command Header
- c->Header.ReplyQueue = 0; // unused in simple mode
- if (iocommand.buf_size > 0) // buffer to fill
+ /* Fill in Command Header */
+ c->Header.ReplyQueue = 0; /* unused in simple mode */
+ if (iocommand.buf_size > 0) /* buffer to fill */
{
c->Header.SGList = 1;
c->Header.SGTotal = 1;
- } else // no buffers to fill
+ } else /* no buffers to fill */
{
c->Header.SGList = 0;
c->Header.SGTotal = 0;
}
c->Header.LUN = iocommand.LUN_info;
- c->Header.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag
+ /* use the kernel address the cmd block for tag */
+ c->Header.Tag.lower = c->busaddr;
- // Fill in Request block
+ /* Fill in Request block */
c->Request = iocommand.Request;
- // Fill in the scatter gather information
+ /* Fill in the scatter gather information */
if (iocommand.buf_size > 0) {
temp64.val = pci_map_single(host->pdev, buff,
iocommand.buf_size,
@@ -1368,7 +1445,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
c->SG[0].Addr.lower = temp64.val32.lower;
c->SG[0].Addr.upper = temp64.val32.upper;
c->SG[0].Len = iocommand.buf_size;
- c->SG[0].Ext = 0; // we are not chaining
+ c->SG[0].Ext = 0; /* we are not chaining */
}
c->waiting = &wait;
@@ -1667,14 +1744,9 @@ static void cciss_softirq_done(struct request *rq)
/* unmap the DMA mapping for all the scatter gather elements */
for (i = 0; i < cmd->Header.SGList; i++) {
if (curr_sg[sg_index].Ext == CCISS_SG_CHAIN) {
- temp64.val32.lower = cmd->SG[i].Addr.lower;
- temp64.val32.upper = cmd->SG[i].Addr.upper;
- pci_dma_sync_single_for_cpu(h->pdev, temp64.val,
- cmd->SG[i].Len, ddir);
- pci_unmap_single(h->pdev, temp64.val,
- cmd->SG[i].Len, ddir);
+ cciss_unmap_sg_chain_block(h, cmd);
/* Point to the next block */
- curr_sg = h->cmd_sg_list[cmd->cmdindex]->sgchain;
+ curr_sg = h->cmd_sg_list[cmd->cmdindex];
sg_index = 0;
}
temp64.val32.lower = curr_sg[sg_index].Addr.lower;
@@ -1793,12 +1865,9 @@ static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask);
/* This is a hardware imposed limit. */
- blk_queue_max_hw_segments(disk->queue, h->maxsgentries);
+ blk_queue_max_segments(disk->queue, h->maxsgentries);
- /* This is a limit in the driver and could be eliminated. */
- blk_queue_max_phys_segments(disk->queue, h->maxsgentries);
-
- blk_queue_max_sectors(disk->queue, h->cciss_max_sectors);
+ blk_queue_max_hw_sectors(disk->queue, h->cciss_max_sectors);
blk_queue_softirq_done(disk->queue, cciss_softirq_done);
@@ -2422,7 +2491,7 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
c->Request.Type.Direction = XFER_READ;
c->Request.Timeout = 0;
c->Request.CDB[0] = cmd;
- c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB
+ c->Request.CDB[6] = (size >> 24) & 0xFF; /* MSB */
c->Request.CDB[7] = (size >> 16) & 0xFF;
c->Request.CDB[8] = (size >> 8) & 0xFF;
c->Request.CDB[9] = size & 0xFF;
@@ -2691,7 +2760,7 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
"cciss: reading geometry failed, volume "
"does not support reading geometry\n");
drv->heads = 255;
- drv->sectors = 32; // Sectors per track
+ drv->sectors = 32; /* Sectors per track */
drv->cylinders = total_size + 1;
drv->raid_level = RAID_UNKNOWN;
} else {
@@ -3079,7 +3148,6 @@ static void do_cciss_request(struct request_queue *q)
SGDescriptor_struct *curr_sg;
drive_info_struct *drv;
int i, dir;
- int nseg = 0;
int sg_index = 0;
int chained = 0;
@@ -3109,19 +3177,19 @@ static void do_cciss_request(struct request_queue *q)
/* fill in the request */
drv = creq->rq_disk->private_data;
- c->Header.ReplyQueue = 0; // unused in simple mode
+ c->Header.ReplyQueue = 0; /* unused in simple mode */
/* got command from pool, so use the command block index instead */
/* for direct lookups. */
/* The first 2 bits are reserved for controller error reporting. */
c->Header.Tag.lower = (c->cmdindex << 3);
c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */
memcpy(&c->Header.LUN, drv->LunID, sizeof(drv->LunID));
- c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
- c->Request.Type.Type = TYPE_CMD; // It is a command.
+ c->Request.CDBLen = 10; /* 12 byte commands not in FW yet; */
+ c->Request.Type.Type = TYPE_CMD; /* It is a command. */
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction =
(rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE;
- c->Request.Timeout = 0; // Don't time out
+ c->Request.Timeout = 0; /* Don't time out */
c->Request.CDB[0] =
(rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write;
start_blk = blk_rq_pos(creq);
@@ -3146,13 +3214,8 @@ static void do_cciss_request(struct request_queue *q)
for (i = 0; i < seg; i++) {
if (((sg_index+1) == (h->max_cmd_sgentries)) &&
!chained && ((seg - i) > 1)) {
- nseg = seg - i;
- curr_sg[sg_index].Len = (nseg) *
- sizeof(SGDescriptor_struct);
- curr_sg[sg_index].Ext = CCISS_SG_CHAIN;
-
/* Point to next chain block. */
- curr_sg = h->cmd_sg_list[c->cmdindex]->sgchain;
+ curr_sg = h->cmd_sg_list[c->cmdindex];
sg_index = 0;
chained = 1;
}
@@ -3163,31 +3226,12 @@ static void do_cciss_request(struct request_queue *q)
curr_sg[sg_index].Addr.lower = temp64.val32.lower;
curr_sg[sg_index].Addr.upper = temp64.val32.upper;
curr_sg[sg_index].Ext = 0; /* we are not chaining */
-
++sg_index;
}
-
- if (chained) {
- int len;
- curr_sg = c->SG;
- sg_index = h->max_cmd_sgentries - 1;
- len = curr_sg[sg_index].Len;
- /* Setup pointer to next chain block.
- * Fill out last element in current chain
- * block with address of next chain block.
- */
- temp64.val = pci_map_single(h->pdev,
- h->cmd_sg_list[c->cmdindex]->sgchain,
- len, dir);
-
- h->cmd_sg_list[c->cmdindex]->sg_chain_dma = temp64.val;
- curr_sg[sg_index].Addr.lower = temp64.val32.lower;
- curr_sg[sg_index].Addr.upper = temp64.val32.upper;
-
- pci_dma_sync_single_for_device(h->pdev,
- h->cmd_sg_list[c->cmdindex]->sg_chain_dma,
- len, dir);
- }
+ if (chained)
+ cciss_map_sg_chain_block(h, c, h->cmd_sg_list[c->cmdindex],
+ (seg - (h->max_cmd_sgentries - 1)) *
+ sizeof(SGDescriptor_struct));
/* track how many SG entries we are using */
if (seg > h->maxSG)
@@ -3206,11 +3250,11 @@ static void do_cciss_request(struct request_queue *q)
if (likely(blk_fs_request(creq))) {
if(h->cciss_read == CCISS_READ_10) {
c->Request.CDB[1] = 0;
- c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB
+ c->Request.CDB[2] = (start_blk >> 24) & 0xff; /* MSB */
c->Request.CDB[3] = (start_blk >> 16) & 0xff;
c->Request.CDB[4] = (start_blk >> 8) & 0xff;
c->Request.CDB[5] = start_blk & 0xff;
- c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB
+ c->Request.CDB[6] = 0; /* (sect >> 24) & 0xff; MSB */
c->Request.CDB[7] = (blk_rq_sectors(creq) >> 8) & 0xff;
c->Request.CDB[8] = blk_rq_sectors(creq) & 0xff;
c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
@@ -3219,7 +3263,7 @@ static void do_cciss_request(struct request_queue *q)
c->Request.CDBLen = 16;
c->Request.CDB[1]= 0;
- c->Request.CDB[2]= (upper32 >> 24) & 0xff; //MSB
+ c->Request.CDB[2]= (upper32 >> 24) & 0xff; /* MSB */
c->Request.CDB[3]= (upper32 >> 16) & 0xff;
c->Request.CDB[4]= (upper32 >> 8) & 0xff;
c->Request.CDB[5]= upper32 & 0xff;
@@ -4237,37 +4281,10 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
goto clean4;
}
}
- hba[i]->cmd_sg_list = kmalloc(sizeof(struct Cmd_sg_list *) *
- hba[i]->nr_cmds,
- GFP_KERNEL);
- if (!hba[i]->cmd_sg_list) {
- printk(KERN_ERR "cciss%d: Cannot get memory for "
- "s/g chaining.\n", i);
+ hba[i]->cmd_sg_list = cciss_allocate_sg_chain_blocks(hba[i],
+ hba[i]->chainsize, hba[i]->nr_cmds);
+ if (!hba[i]->cmd_sg_list && hba[i]->chainsize > 0)
goto clean4;
- }
- /* Build up chain blocks for each command */
- if (hba[i]->chainsize > 0) {
- for (j = 0; j < hba[i]->nr_cmds; j++) {
- hba[i]->cmd_sg_list[j] =
- kmalloc(sizeof(struct Cmd_sg_list),
- GFP_KERNEL);
- if (!hba[i]->cmd_sg_list[j]) {
- printk(KERN_ERR "cciss%d: Cannot get memory "
- "for chain block.\n", i);
- goto clean4;
- }
- /* Need a block of chainsized s/g elements. */
- hba[i]->cmd_sg_list[j]->sgchain =
- kmalloc((hba[i]->chainsize *
- sizeof(SGDescriptor_struct)),
- GFP_KERNEL);
- if (!hba[i]->cmd_sg_list[j]->sgchain) {
- printk(KERN_ERR "cciss%d: Cannot get memory "
- "for s/g chains\n", i);
- goto clean4;
- }
- }
- }
spin_lock_init(&hba[i]->lock);
@@ -4326,16 +4343,7 @@ clean4:
for (k = 0; k < hba[i]->nr_cmds; k++)
kfree(hba[i]->scatter_list[k]);
kfree(hba[i]->scatter_list);
- /* Only free up extra s/g lists if controller supports them */
- if (hba[i]->chainsize > 0) {
- for (j = 0; j < hba[i]->nr_cmds; j++) {
- if (hba[i]->cmd_sg_list[j]) {
- kfree(hba[i]->cmd_sg_list[j]->sgchain);
- kfree(hba[i]->cmd_sg_list[j]);
- }
- }
- kfree(hba[i]->cmd_sg_list);
- }
+ cciss_free_sg_chain_blocks(hba[i]->cmd_sg_list, hba[i]->nr_cmds);
if (hba[i]->cmd_pool)
pci_free_consistent(hba[i]->pdev,
hba[i]->nr_cmds * sizeof(CommandList_struct),
@@ -4453,16 +4461,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
for (j = 0; j < hba[i]->nr_cmds; j++)
kfree(hba[i]->scatter_list[j]);
kfree(hba[i]->scatter_list);
- /* Only free up extra s/g lists if controller supports them */
- if (hba[i]->chainsize > 0) {
- for (j = 0; j < hba[i]->nr_cmds; j++) {
- if (hba[i]->cmd_sg_list[j]) {
- kfree(hba[i]->cmd_sg_list[j]->sgchain);
- kfree(hba[i]->cmd_sg_list[j]);
- }
- }
- kfree(hba[i]->cmd_sg_list);
- }
+ cciss_free_sg_chain_blocks(hba[i]->cmd_sg_list, hba[i]->nr_cmds);
/*
* Deliberately omit pci_disable_device(): it does something nasty to
* Smart Array controllers that pci_enable_device does not undo
@@ -4495,7 +4494,7 @@ static int __init cciss_init(void)
* boundary. Given that we use pci_alloc_consistent() to allocate an
* array of them, the size must be a multiple of 8 bytes.
*/
- BUILD_BUG_ON(sizeof(CommandList_struct) % 8);
+ BUILD_BUG_ON(sizeof(CommandList_struct) % COMMANDLIST_ALIGNMENT);
printk(KERN_INFO DRIVER_NAME "\n");
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index 1d95db254069..c5d411174db0 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -55,18 +55,12 @@ typedef struct _drive_info_struct
char device_initialized; /* indicates whether dev is initialized */
} drive_info_struct;
-struct Cmd_sg_list {
- SGDescriptor_struct *sgchain;
- dma_addr_t sg_chain_dma;
- int chain_block_size;
-};
-
struct ctlr_info
{
int ctlr;
char devname[8];
char *product_name;
- char firm_ver[4]; // Firmware version
+ char firm_ver[4]; /* Firmware version */
struct pci_dev *pdev;
__u32 board_id;
void __iomem *vaddr;
@@ -89,7 +83,7 @@ struct ctlr_info
int maxsgentries;
int chainsize;
int max_cmd_sgentries;
- struct Cmd_sg_list **cmd_sg_list;
+ SGDescriptor_struct **cmd_sg_list;
# define DOORBELL_INT 0
# define PERF_MODE_INT 1
@@ -103,7 +97,7 @@ struct ctlr_info
BYTE cciss_write;
BYTE cciss_read_capacity;
- // information about each logical volume
+ /* information about each logical volume */
drive_info_struct *drv[CISS_MAX_LUN];
struct access_method access;
@@ -116,7 +110,7 @@ struct ctlr_info
unsigned int maxSG;
spinlock_t lock;
- //* pointers to command and error info pool */
+ /* pointers to command and error info pool */
CommandList_struct *cmd_pool;
dma_addr_t cmd_pool_dhandle;
ErrorInfo_struct *errinfo_pool;
@@ -134,12 +128,10 @@ struct ctlr_info
*/
int next_to_run;
- // Disk structures we need to pass back
+ /* Disk structures we need to pass back */
struct gendisk *gendisk[CISS_MAX_LUN];
#ifdef CONFIG_CISS_SCSI_TAPE
- void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
- /* list of block side commands the scsi error handling sucked up */
- /* and saved for later processing */
+ struct cciss_scsi_adapter_data_t *scsi_ctlr;
#endif
unsigned char alive;
struct list_head scan_list;
@@ -315,4 +307,3 @@ struct board_type {
#define CCISS_LOCK(i) (&hba[i]->lock)
#endif /* CCISS_H */
-
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h
index 6afa700890ff..e624ff959cb6 100644
--- a/drivers/block/cciss_cmd.h
+++ b/drivers/block/cciss_cmd.h
@@ -1,31 +1,16 @@
#ifndef CCISS_CMD_H
#define CCISS_CMD_H
-//###########################################################################
-//DEFINES
-//###########################################################################
+
+#include <linux/cciss_defs.h>
+
+/* DEFINES */
#define CISS_VERSION "1.00"
-//general boundary definitions
-#define SENSEINFOBYTES 32//note that this value may vary between host implementations
+/* general boundary definitions */
#define MAXSGENTRIES 32
#define CCISS_SG_CHAIN 0x80000000
#define MAXREPLYQS 256
-//Command Status value
-#define CMD_SUCCESS 0x0000
-#define CMD_TARGET_STATUS 0x0001
-#define CMD_DATA_UNDERRUN 0x0002
-#define CMD_DATA_OVERRUN 0x0003
-#define CMD_INVALID 0x0004
-#define CMD_PROTOCOL_ERR 0x0005
-#define CMD_HARDWARE_ERR 0x0006
-#define CMD_CONNECTION_LOST 0x0007
-#define CMD_ABORTED 0x0008
-#define CMD_ABORT_FAILED 0x0009
-#define CMD_UNSOLICITED_ABORT 0x000A
-#define CMD_TIMEOUT 0x000B
-#define CMD_UNABORTABLE 0x000C
-
/* Unit Attentions ASC's as defined for the MSA2012sa */
#define POWER_OR_RESET 0x29
#define STATE_CHANGED 0x2a
@@ -49,30 +34,13 @@
#define ASYM_ACCESS_CHANGED 0x06
#define LUN_CAPACITY_CHANGED 0x09
-//transfer direction
-#define XFER_NONE 0x00
-#define XFER_WRITE 0x01
-#define XFER_READ 0x02
-#define XFER_RSVD 0x03
-
-//task attribute
-#define ATTR_UNTAGGED 0x00
-#define ATTR_SIMPLE 0x04
-#define ATTR_HEADOFQUEUE 0x05
-#define ATTR_ORDERED 0x06
-#define ATTR_ACA 0x07
-
-//cdb type
-#define TYPE_CMD 0x00
-#define TYPE_MSG 0x01
-
-//config space register offsets
+/* config space register offsets */
#define CFG_VENDORID 0x00
#define CFG_DEVICEID 0x02
#define CFG_I2OBAR 0x10
#define CFG_MEM1BAR 0x14
-//i2o space register offsets
+/* i2o space register offsets */
#define I2O_IBDB_SET 0x20
#define I2O_IBDB_CLEAR 0x70
#define I2O_INT_STATUS 0x30
@@ -81,7 +49,7 @@
#define I2O_OBPOST_Q 0x44
#define I2O_DMA1_CFG 0x214
-//Configuration Table
+/* Configuration Table */
#define CFGTBL_ChangeReq 0x00000001l
#define CFGTBL_AccCmds 0x00000001l
@@ -103,24 +71,17 @@ typedef union _u64bit
__u64 val;
} u64bit;
-// Type defs used in the following structs
-#define BYTE __u8
-#define WORD __u16
-#define HWORD __u16
-#define DWORD __u32
+/* Type defs used in the following structs */
#define QWORD vals32
-//###########################################################################
-//STRUCTURES
-//###########################################################################
-#define CISS_MAX_LUN 1024
+/* STRUCTURES */
#define CISS_MAX_PHYS_LUN 1024
-// SCSI-3 Cmmands
+/* SCSI-3 Cmmands */
#pragma pack(1)
#define CISS_INQUIRY 0x12
-//Date returned
+/* Date returned */
typedef struct _InquiryData_struct
{
BYTE data_byte[36];
@@ -128,7 +89,7 @@ typedef struct _InquiryData_struct
#define CISS_REPORT_LOG 0xc2 /* Report Logical LUNs */
#define CISS_REPORT_PHYS 0xc3 /* Report Physical LUNs */
-// Data returned
+/* Data returned */
typedef struct _ReportLUNdata_struct
{
BYTE LUNListLength[4];
@@ -139,8 +100,8 @@ typedef struct _ReportLUNdata_struct
#define CCISS_READ_CAPACITY 0x25 /* Read Capacity */
typedef struct _ReadCapdata_struct
{
- BYTE total_size[4]; // Total size in blocks
- BYTE block_size[4]; // Size of blocks in bytes
+ BYTE total_size[4]; /* Total size in blocks */
+ BYTE block_size[4]; /* Size of blocks in bytes */
} ReadCapdata_struct;
#define CCISS_READ_CAPACITY_16 0x9e /* Read Capacity 16 */
@@ -172,52 +133,13 @@ typedef struct _ReadCapdata_struct_16
#define CDB_LEN10 10
#define CDB_LEN16 16
-// BMIC commands
+/* BMIC commands */
#define BMIC_READ 0x26
#define BMIC_WRITE 0x27
#define BMIC_CACHE_FLUSH 0xc2
-#define CCISS_CACHE_FLUSH 0x01 //C2 was already being used by CCISS
-
-//Command List Structure
-typedef union _SCSI3Addr_struct {
- struct {
- BYTE Dev;
- BYTE Bus:6;
- BYTE Mode:2; // b00
- } PeripDev;
- struct {
- BYTE DevLSB;
- BYTE DevMSB:6;
- BYTE Mode:2; // b01
- } LogDev;
- struct {
- BYTE Dev:5;
- BYTE Bus:3;
- BYTE Targ:6;
- BYTE Mode:2; // b10
- } LogUnit;
-} SCSI3Addr_struct;
-
-typedef struct _PhysDevAddr_struct {
- DWORD TargetId:24;
- DWORD Bus:6;
- DWORD Mode:2;
- SCSI3Addr_struct Target[2]; //2 level target device addr
-} PhysDevAddr_struct;
-
-typedef struct _LogDevAddr_struct {
- DWORD VolId:30;
- DWORD Mode:2;
- BYTE reserved[4];
-} LogDevAddr_struct;
-
-typedef union _LUNAddr_struct {
- BYTE LunAddrBytes[8];
- SCSI3Addr_struct SCSI3Lun[4];
- PhysDevAddr_struct PhysDev;
- LogDevAddr_struct LogDev;
-} LUNAddr_struct;
+#define CCISS_CACHE_FLUSH 0x01 /* C2 was already being used by CCISS */
+/* Command List Structure */
#define CTLR_LUNID "\0\0\0\0\0\0\0\0"
typedef struct _CommandListHeader_struct {
@@ -227,16 +149,6 @@ typedef struct _CommandListHeader_struct {
QWORD Tag;
LUNAddr_struct LUN;
} CommandListHeader_struct;
-typedef struct _RequestBlock_struct {
- BYTE CDBLen;
- struct {
- BYTE Type:3;
- BYTE Attribute:3;
- BYTE Direction:2;
- } Type;
- HWORD Timeout;
- BYTE CDB[16];
-} RequestBlock_struct;
typedef struct _ErrDescriptor_struct {
QWORD Addr;
DWORD Len;
@@ -247,28 +159,6 @@ typedef struct _SGDescriptor_struct {
DWORD Ext;
} SGDescriptor_struct;
-typedef union _MoreErrInfo_struct{
- struct {
- BYTE Reserved[3];
- BYTE Type;
- DWORD ErrorInfo;
- }Common_Info;
- struct{
- BYTE Reserved[2];
- BYTE offense_size;//size of offending entry
- BYTE offense_num; //byte # of offense 0-base
- DWORD offense_value;
- }Invalid_Cmd;
-}MoreErrInfo_struct;
-typedef struct _ErrorInfo_struct {
- BYTE ScsiStatus;
- BYTE SenseLen;
- HWORD CommandStatus;
- DWORD ResidualCnt;
- MoreErrInfo_struct MoreErrInfo;
- BYTE SenseInfo[SENSEINFOBYTES];
-} ErrorInfo_struct;
-
/* Command types */
#define CMD_RWREQ 0x00
#define CMD_IOCTL_PEND 0x01
@@ -277,10 +167,18 @@ typedef struct _ErrorInfo_struct {
#define CMD_MSG_TIMEOUT 0x05
#define CMD_MSG_STALE 0xff
-/* This structure needs to be divisible by 8 for new
- * indexing method.
+/* This structure needs to be divisible by COMMANDLIST_ALIGNMENT
+ * because low bits of the address are used to to indicate that
+ * whether the tag contains an index or an address. PAD_32 and
+ * PAD_64 can be adjusted independently as needed for 32-bit
+ * and 64-bits systems.
*/
-#define PADSIZE (sizeof(long) - 4)
+#define COMMANDLIST_ALIGNMENT (8)
+#define IS_64_BIT ((sizeof(long) - 4)/4)
+#define IS_32_BIT (!IS_64_BIT)
+#define PAD_32 (0)
+#define PAD_64 (4)
+#define PADSIZE (IS_32_BIT * PAD_32 + IS_64_BIT * PAD_64)
typedef struct _CommandList_struct {
CommandListHeader_struct Header;
RequestBlock_struct Request;
@@ -300,7 +198,7 @@ typedef struct _CommandList_struct {
char pad[PADSIZE];
} CommandList_struct;
-//Configuration Table Structure
+/* Configuration Table Structure */
typedef struct _HostWrite_struct {
DWORD TransportRequest;
DWORD Reserved;
@@ -326,4 +224,4 @@ typedef struct _CfgTable_struct {
DWORD MaxPhysicalDrivesPerLogicalUnit;
} CfgTable_struct;
#pragma pack()
-#endif // CCISS_CMD_H
+#endif /* CCISS_CMD_H */
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index 5d0e46dc3632..e1d0e2cfec72 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -84,7 +84,6 @@ static struct scsi_host_template cciss_driver_template = {
.queuecommand = cciss_scsi_queue_command,
.can_queue = SCSI_CCISS_CAN_QUEUE,
.this_id = 7,
- .sg_tablesize = MAXSGENTRIES,
.cmd_per_lun = 1,
.use_clustering = DISABLE_CLUSTERING,
/* Can't have eh_bus_reset_handler or eh_host_reset_handler for cciss */
@@ -93,11 +92,16 @@ static struct scsi_host_template cciss_driver_template = {
};
#pragma pack(1)
+
+#define SCSI_PAD_32 0
+#define SCSI_PAD_64 0
+
struct cciss_scsi_cmd_stack_elem_t {
CommandList_struct cmd;
ErrorInfo_struct Err;
__u32 busaddr;
- __u32 pad;
+ int cmdindex;
+ u8 pad[IS_32_BIT * SCSI_PAD_32 + IS_64_BIT * SCSI_PAD_64];
};
#pragma pack()
@@ -118,16 +122,15 @@ struct cciss_scsi_cmd_stack_t {
struct cciss_scsi_adapter_data_t {
struct Scsi_Host *scsi_host;
struct cciss_scsi_cmd_stack_t cmd_stack;
+ SGDescriptor_struct **cmd_sg_list;
int registered;
spinlock_t lock; // to protect ccissscsi[ctlr];
};
#define CPQ_TAPE_LOCK(ctlr, flags) spin_lock_irqsave( \
- &(((struct cciss_scsi_adapter_data_t *) \
- hba[ctlr]->scsi_ctlr)->lock), flags);
+ &hba[ctlr]->scsi_ctlr->lock, flags);
#define CPQ_TAPE_UNLOCK(ctlr, flags) spin_unlock_irqrestore( \
- &(((struct cciss_scsi_adapter_data_t *) \
- hba[ctlr]->scsi_ctlr)->lock), flags);
+ &hba[ctlr]->scsi_ctlr->lock, flags);
static CommandList_struct *
scsi_cmd_alloc(ctlr_info_t *h)
@@ -143,7 +146,7 @@ scsi_cmd_alloc(ctlr_info_t *h)
struct cciss_scsi_cmd_stack_t *stk;
u64bit temp64;
- sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr;
+ sa = h->scsi_ctlr;
stk = &sa->cmd_stack;
if (stk->top < 0)
@@ -154,6 +157,7 @@ scsi_cmd_alloc(ctlr_info_t *h)
memset(&c->Err, 0, sizeof(c->Err));
/* set physical addr of cmd and addr of scsi parameters */
c->cmd.busaddr = c->busaddr;
+ c->cmd.cmdindex = c->cmdindex;
/* (__u32) (stk->cmd_pool_handle +
(sizeof(struct cciss_scsi_cmd_stack_elem_t)*stk->top)); */
@@ -182,7 +186,7 @@ scsi_cmd_free(ctlr_info_t *h, CommandList_struct *cmd)
struct cciss_scsi_adapter_data_t *sa;
struct cciss_scsi_cmd_stack_t *stk;
- sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr;
+ sa = h->scsi_ctlr;
stk = &sa->cmd_stack;
if (stk->top >= CMD_STACK_SIZE) {
printk("cciss: scsi_cmd_free called too many times.\n");
@@ -199,24 +203,31 @@ scsi_cmd_stack_setup(int ctlr, struct cciss_scsi_adapter_data_t *sa)
struct cciss_scsi_cmd_stack_t *stk;
size_t size;
+ sa->cmd_sg_list = cciss_allocate_sg_chain_blocks(hba[ctlr],
+ hba[ctlr]->chainsize, CMD_STACK_SIZE);
+ if (!sa->cmd_sg_list && hba[ctlr]->chainsize > 0)
+ return -ENOMEM;
+
stk = &sa->cmd_stack;
size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
- // pci_alloc_consistent guarantees 32-bit DMA address will
- // be used
-
+ /* Check alignment, see cciss_cmd.h near CommandList_struct def. */
+ BUILD_BUG_ON((sizeof(*stk->pool) % COMMANDLIST_ALIGNMENT) != 0);
+ /* pci_alloc_consistent guarantees 32-bit DMA address will be used */
stk->pool = (struct cciss_scsi_cmd_stack_elem_t *)
pci_alloc_consistent(hba[ctlr]->pdev, size, &stk->cmd_pool_handle);
if (stk->pool == NULL) {
- printk("stk->pool is null\n");
- return -1;
+ cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE);
+ sa->cmd_sg_list = NULL;
+ return -ENOMEM;
}
for (i=0; i<CMD_STACK_SIZE; i++) {
stk->elem[i] = &stk->pool[i];
stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle +
(sizeof(struct cciss_scsi_cmd_stack_elem_t) * i));
+ stk->elem[i]->cmdindex = i;
}
stk->top = CMD_STACK_SIZE-1;
return 0;
@@ -229,7 +240,7 @@ scsi_cmd_stack_free(int ctlr)
struct cciss_scsi_cmd_stack_t *stk;
size_t size;
- sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+ sa = hba[ctlr]->scsi_ctlr;
stk = &sa->cmd_stack;
if (stk->top != CMD_STACK_SIZE-1) {
printk( "cciss: %d scsi commands are still outstanding.\n",
@@ -241,6 +252,7 @@ scsi_cmd_stack_free(int ctlr)
pci_free_consistent(hba[ctlr]->pdev, size, stk->pool, stk->cmd_pool_handle);
stk->pool = NULL;
+ cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE);
}
#if 0
@@ -530,8 +542,7 @@ adjust_cciss_scsi_table(int ctlr, int hostno,
CPQ_TAPE_LOCK(ctlr, flags);
if (hostno != -1) /* if it's not the first time... */
- sh = ((struct cciss_scsi_adapter_data_t *)
- hba[ctlr]->scsi_ctlr)->scsi_host;
+ sh = hba[ctlr]->scsi_ctlr->scsi_host;
/* find any devices in ccissscsi[] that are not in
sd[] and remove them from ccissscsi[] */
@@ -702,7 +713,7 @@ cciss_scsi_setup(int cntl_num)
kfree(shba);
shba = NULL;
}
- hba[cntl_num]->scsi_ctlr = (void *) shba;
+ hba[cntl_num]->scsi_ctlr = shba;
return;
}
@@ -725,6 +736,8 @@ complete_scsi_command( CommandList_struct *cp, int timeout, __u32 tag)
ctlr = hba[cp->ctlr];
scsi_dma_unmap(cmd);
+ if (cp->Header.SGTotal > ctlr->max_cmd_sgentries)
+ cciss_unmap_sg_chain_block(ctlr, cp);
cmd->result = (DID_OK << 16); /* host byte */
cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
@@ -847,9 +860,10 @@ cciss_scsi_detect(int ctlr)
sh->io_port = 0; // good enough? FIXME,
sh->n_io_port = 0; // I don't think we use these two...
sh->this_id = SELF_SCSI_ID;
+ sh->sg_tablesize = hba[ctlr]->maxsgentries;
((struct cciss_scsi_adapter_data_t *)
- hba[ctlr]->scsi_ctlr)->scsi_host = (void *) sh;
+ hba[ctlr]->scsi_ctlr)->scsi_host = sh;
sh->hostdata[0] = (unsigned long) hba[ctlr];
sh->irq = hba[ctlr]->intr[SIMPLE_MODE_INT];
sh->unique_id = sh->irq;
@@ -1364,34 +1378,54 @@ cciss_scsi_proc_info(struct Scsi_Host *sh,
dma mapping and fills in the scatter gather entries of the
cciss command, cp. */
-static void
-cciss_scatter_gather(struct pci_dev *pdev,
- CommandList_struct *cp,
- struct scsi_cmnd *cmd)
+static void cciss_scatter_gather(ctlr_info_t *h, CommandList_struct *cp,
+ struct scsi_cmnd *cmd)
{
unsigned int len;
struct scatterlist *sg;
__u64 addr64;
- int use_sg, i;
-
- BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES);
-
- use_sg = scsi_dma_map(cmd);
- if (use_sg) { /* not too many addrs? */
- scsi_for_each_sg(cmd, sg, use_sg, i) {
+ int request_nsgs, i, chained, sg_index;
+ struct cciss_scsi_adapter_data_t *sa = h->scsi_ctlr;
+ SGDescriptor_struct *curr_sg;
+
+ BUG_ON(scsi_sg_count(cmd) > h->maxsgentries);
+
+ chained = 0;
+ sg_index = 0;
+ curr_sg = cp->SG;
+ request_nsgs = scsi_dma_map(cmd);
+ if (request_nsgs) {
+ scsi_for_each_sg(cmd, sg, request_nsgs, i) {
+ if (sg_index + 1 == h->max_cmd_sgentries &&
+ !chained && request_nsgs - i > 1) {
+ chained = 1;
+ sg_index = 0;
+ curr_sg = sa->cmd_sg_list[cp->cmdindex];
+ }
addr64 = (__u64) sg_dma_address(sg);
len = sg_dma_len(sg);
- cp->SG[i].Addr.lower =
- (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
- cp->SG[i].Addr.upper =
- (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
- cp->SG[i].Len = len;
- cp->SG[i].Ext = 0; // we are not chaining
+ curr_sg[sg_index].Addr.lower =
+ (__u32) (addr64 & 0x0FFFFFFFFULL);
+ curr_sg[sg_index].Addr.upper =
+ (__u32) ((addr64 >> 32) & 0x0FFFFFFFFULL);
+ curr_sg[sg_index].Len = len;
+ curr_sg[sg_index].Ext = 0;
+ ++sg_index;
}
+ if (chained)
+ cciss_map_sg_chain_block(h, cp,
+ sa->cmd_sg_list[cp->cmdindex],
+ (request_nsgs - (h->max_cmd_sgentries - 1)) *
+ sizeof(SGDescriptor_struct));
}
-
- cp->Header.SGList = (__u8) use_sg; /* no. SGs contig in this cmd */
- cp->Header.SGTotal = (__u16) use_sg; /* total sgs in this cmd list */
+ /* track how many SG entries we are using */
+ if (request_nsgs > h->maxSG)
+ h->maxSG = request_nsgs;
+ cp->Header.SGTotal = (__u8) request_nsgs + chained;
+ if (request_nsgs > h->max_cmd_sgentries)
+ cp->Header.SGList = h->max_cmd_sgentries;
+ else
+ cp->Header.SGList = cp->Header.SGTotal;
return;
}
@@ -1399,7 +1433,7 @@ cciss_scatter_gather(struct pci_dev *pdev,
static int
cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
{
- ctlr_info_t **c;
+ ctlr_info_t *c;
int ctlr, rc;
unsigned char scsi3addr[8];
CommandList_struct *cp;
@@ -1407,8 +1441,8 @@ cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd
// Get the ptr to our adapter structure (hba[i]) out of cmd->host.
// We violate cmd->host privacy here. (Is there another way?)
- c = (ctlr_info_t **) &cmd->device->host->hostdata[0];
- ctlr = (*c)->ctlr;
+ c = (ctlr_info_t *) cmd->device->host->hostdata[0];
+ ctlr = c->ctlr;
rc = lookup_scsi3addr(ctlr, cmd->device->channel, cmd->device->id,
cmd->device->lun, scsi3addr);
@@ -1431,7 +1465,7 @@ cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd
see what the device thinks of it. */
spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- cp = scsi_cmd_alloc(*c);
+ cp = scsi_cmd_alloc(c);
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
if (cp == NULL) { /* trouble... */
printk("scsi_cmd_alloc returned NULL!\n");
@@ -1489,15 +1523,14 @@ cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd
BUG();
break;
}
-
- cciss_scatter_gather((*c)->pdev, cp, cmd); // Fill the SG list
+ cciss_scatter_gather(c, cp, cmd);
/* Put the request on the tail of the request queue */
spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- addQ(&(*c)->reqQ, cp);
- (*c)->Qdepth++;
- start_io(*c);
+ addQ(&c->reqQ, cp);
+ c->Qdepth++;
+ start_io(c);
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
/* the cmd'll come back via intr handler in complete_scsi_command() */
@@ -1514,7 +1547,7 @@ cciss_unregister_scsi(int ctlr)
/* we are being forcibly unloaded, and may not refuse. */
spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+ sa = hba[ctlr]->scsi_ctlr;
stk = &sa->cmd_stack;
/* if we weren't ever actually registered, don't unregister */
@@ -1541,7 +1574,7 @@ cciss_engage_scsi(int ctlr)
unsigned long flags;
spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+ sa = hba[ctlr]->scsi_ctlr;
stk = &sa->cmd_stack;
if (sa->registered) {
@@ -1654,14 +1687,14 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
int rc;
CommandList_struct *cmd_in_trouble;
unsigned char lunaddr[8];
- ctlr_info_t **c;
+ ctlr_info_t *c;
int ctlr;
/* find the controller to which the command to be aborted was sent */
- c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0];
+ c = (ctlr_info_t *) scsicmd->device->host->hostdata[0];
if (c == NULL) /* paranoia */
return FAILED;
- ctlr = (*c)->ctlr;
+ ctlr = c->ctlr;
printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr);
/* find the command that's giving us trouble */
cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble;
@@ -1671,7 +1704,7 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
/* send a reset to the SCSI LUN which the command was sent to */
rc = sendcmd_withirq(CCISS_RESET_MSG, ctlr, NULL, 0, 0, lunaddr,
TYPE_MSG);
- if (rc == 0 && wait_for_device_to_become_ready(*c, lunaddr) == 0)
+ if (rc == 0 && wait_for_device_to_become_ready(c, lunaddr) == 0)
return SUCCESS;
printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr);
return FAILED;
@@ -1682,14 +1715,14 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd)
int rc;
CommandList_struct *cmd_to_abort;
unsigned char lunaddr[8];
- ctlr_info_t **c;
+ ctlr_info_t *c;
int ctlr;
/* find the controller to which the command to be aborted was sent */
- c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0];
+ c = (ctlr_info_t *) scsicmd->device->host->hostdata[0];
if (c == NULL) /* paranoia */
return FAILED;
- ctlr = (*c)->ctlr;
+ ctlr = c->ctlr;
printk(KERN_WARNING "cciss%d: aborting tardy SCSI cmd\n", ctlr);
/* find the command to be aborted */
diff --git a/drivers/block/cciss_scsi.h b/drivers/block/cciss_scsi.h
index 7b750245ae76..6d5822fe851a 100644
--- a/drivers/block/cciss_scsi.h
+++ b/drivers/block/cciss_scsi.h
@@ -25,16 +25,16 @@
#include <scsi/scsicam.h> /* possibly irrelevant, since we don't show disks */
- // the scsi id of the adapter...
+ /* the scsi id of the adapter... */
#define SELF_SCSI_ID 15
- // 15 is somewhat arbitrary, since the scsi-2 bus
- // that's presented by the driver to the OS is
- // fabricated. The "real" scsi-3 bus the
- // hardware presents is fabricated too.
- // The actual, honest-to-goodness physical
- // bus that the devices are attached to is not
- // addressible natively, and may in fact turn
- // out to be not scsi at all.
+ /* 15 is somewhat arbitrary, since the scsi-2 bus
+ that's presented by the driver to the OS is
+ fabricated. The "real" scsi-3 bus the
+ hardware presents is fabricated too.
+ The actual, honest-to-goodness physical
+ bus that the devices are attached to is not
+ addressible natively, and may in fact turn
+ out to be not scsi at all. */
#define SCSI_CCISS_CAN_QUEUE 2
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 6422651ec364..91d11631cec9 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -448,11 +448,8 @@ static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev)
blk_queue_bounce_limit(q, hba[i]->pci_dev->dma_mask);
/* This is a hardware imposed limit. */
- blk_queue_max_hw_segments(q, SG_MAX);
+ blk_queue_max_segments(q, SG_MAX);
- /* This is a driver limit and could be eliminated. */
- blk_queue_max_phys_segments(q, SG_MAX);
-
init_timer(&hba[i]->timer);
hba[i]->timer.expires = jiffies + IDA_TIMER;
hba[i]->timer.data = (unsigned long)hba[i];
diff --git a/drivers/block/drbd/Kconfig b/drivers/block/drbd/Kconfig
index f4acd04ebeef..df0983787390 100644
--- a/drivers/block/drbd/Kconfig
+++ b/drivers/block/drbd/Kconfig
@@ -3,7 +3,7 @@
#
comment "DRBD disabled because PROC_FS, INET or CONNECTOR not selected"
- depends on !PROC_FS || !INET || !CONNECTOR
+ depends on PROC_FS='n' || INET='n' || CONNECTOR='n'
config BLK_DEV_DRBD
tristate "DRBD Distributed Replicated Block Device support"
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index c97558763430..d9301e861d9f 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -95,7 +95,7 @@ extern char usermode_helper[];
/* All EEs on the free list should have ID_VACANT (== 0)
* freshly allocated EEs get !ID_VACANT (== 1)
- * so if it says "cannot dereference null pointer at adress 0x00000001",
+ * so if it says "cannot dereference null pointer at address 0x00000001",
* it is most likely one of these :( */
#define ID_IN_SYNC (4711ULL)
@@ -1171,7 +1171,7 @@ extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf
/* Meta data layout
We reserve a 128MB Block (4k aligned)
* either at the end of the backing device
- * or on a seperate meta data device. */
+ * or on a separate meta data device. */
#define MD_RESERVED_SECT (128LU << 11) /* 128 MB, unit sectors */
/* The following numbers are sectors */
@@ -1275,7 +1275,7 @@ struct bm_extent {
#if DRBD_MAX_SECTORS_BM < DRBD_MAX_SECTORS_32
#define DRBD_MAX_SECTORS DRBD_MAX_SECTORS_BM
#define DRBD_MAX_SECTORS_FLEX DRBD_MAX_SECTORS_BM
-#elif !defined(CONFIG_LBD) && BITS_PER_LONG == 32
+#elif !defined(CONFIG_LBDAF) && BITS_PER_LONG == 32
#define DRBD_MAX_SECTORS DRBD_MAX_SECTORS_32
#define DRBD_MAX_SECTORS_FLEX DRBD_MAX_SECTORS_32
#else
@@ -1371,10 +1371,9 @@ extern int is_valid_ar_handle(struct drbd_request *, sector_t);
extern void drbd_suspend_io(struct drbd_conf *mdev);
extern void drbd_resume_io(struct drbd_conf *mdev);
extern char *ppsize(char *buf, unsigned long long size);
-extern sector_t drbd_new_dev_size(struct drbd_conf *,
- struct drbd_backing_dev *);
+extern sector_t drbd_new_dev_size(struct drbd_conf *, struct drbd_backing_dev *, int);
enum determine_dev_size { dev_size_error = -1, unchanged = 0, shrunk = 1, grew = 2 };
-extern enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *) __must_hold(local);
+extern enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *, int force) __must_hold(local);
extern void resync_after_online_grow(struct drbd_conf *);
extern void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int) __must_hold(local);
extern int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role,
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 9348f33f6242..ab871e00ffc5 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -1298,6 +1298,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
dev_err(DEV, "Sending state in drbd_io_error() failed\n");
}
+ wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
lc_destroy(mdev->resync);
mdev->resync = NULL;
lc_destroy(mdev->act_log);
@@ -2972,7 +2973,6 @@ struct drbd_conf *drbd_new_device(unsigned int minor)
goto out_no_q;
mdev->rq_queue = q;
q->queuedata = mdev;
- blk_queue_max_segment_size(q, DRBD_MAX_SEGMENT_SIZE);
disk = alloc_disk(1);
if (!disk)
@@ -2996,6 +2996,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor)
q->backing_dev_info.congested_data = mdev;
blk_queue_make_request(q, drbd_make_request_26);
+ blk_queue_max_segment_size(q, DRBD_MAX_SEGMENT_SIZE);
blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
blk_queue_merge_bvec(q, drbd_merge_bvec);
q->queue_lock = &mdev->req_lock; /* needed since we use */
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 4e0726aa53b0..4df3b40b1057 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -510,7 +510,7 @@ void drbd_resume_io(struct drbd_conf *mdev)
* Returns 0 on success, negative return values indicate errors.
* You should call drbd_md_sync() after calling this function.
*/
-enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev) __must_hold(local)
+enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev, int force) __must_hold(local)
{
sector_t prev_first_sect, prev_size; /* previous meta location */
sector_t la_size;
@@ -541,7 +541,7 @@ enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev) __must_ho
/* TODO: should only be some assert here, not (re)init... */
drbd_md_set_sector_offsets(mdev, mdev->ldev);
- size = drbd_new_dev_size(mdev, mdev->ldev);
+ size = drbd_new_dev_size(mdev, mdev->ldev, force);
if (drbd_get_capacity(mdev->this_bdev) != size ||
drbd_bm_capacity(mdev) != size) {
@@ -596,7 +596,7 @@ out:
}
sector_t
-drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
+drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, int assume_peer_has_space)
{
sector_t p_size = mdev->p_size; /* partner's disk size. */
sector_t la_size = bdev->md.la_size_sect; /* last agreed size. */
@@ -606,6 +606,11 @@ drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
m_size = drbd_get_max_capacity(bdev);
+ if (mdev->state.conn < C_CONNECTED && assume_peer_has_space) {
+ dev_warn(DEV, "Resize while not connected was forced by the user!\n");
+ p_size = m_size;
+ }
+
if (p_size && m_size) {
size = min_t(sector_t, p_size, m_size);
} else {
@@ -704,9 +709,8 @@ void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_seg_s) __mu
max_seg_s = min(queue_max_sectors(b) * queue_logical_block_size(b), max_seg_s);
- blk_queue_max_sectors(q, max_seg_s >> 9);
- blk_queue_max_phys_segments(q, max_segments ? max_segments : MAX_PHYS_SEGMENTS);
- blk_queue_max_hw_segments(q, max_segments ? max_segments : MAX_HW_SEGMENTS);
+ blk_queue_max_hw_sectors(q, max_seg_s >> 9);
+ blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS);
blk_queue_max_segment_size(q, max_seg_s);
blk_queue_logical_block_size(q, 512);
blk_queue_segment_boundary(q, PAGE_SIZE-1);
@@ -965,7 +969,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
/* Prevent shrinking of consistent devices ! */
if (drbd_md_test_flag(nbc, MDF_CONSISTENT) &&
- drbd_new_dev_size(mdev, nbc) < nbc->md.la_size_sect) {
+ drbd_new_dev_size(mdev, nbc, 0) < nbc->md.la_size_sect) {
dev_warn(DEV, "refusing to truncate a consistent device\n");
retcode = ERR_DISK_TO_SMALL;
goto force_diskless_dec;
@@ -1052,7 +1056,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
!drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND))
set_bit(USE_DEGR_WFC_T, &mdev->flags);
- dd = drbd_determin_dev_size(mdev);
+ dd = drbd_determin_dev_size(mdev, 0);
if (dd == dev_size_error) {
retcode = ERR_NOMEM_BITMAP;
goto force_diskless_dec;
@@ -1271,7 +1275,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
goto fail;
}
- if (crypto_tfm_alg_type(crypto_hash_tfm(tfm)) != CRYPTO_ALG_TYPE_SHASH) {
+ if (!drbd_crypto_is_hash(crypto_hash_tfm(tfm))) {
retcode = ERR_AUTH_ALG_ND;
goto fail;
}
@@ -1504,7 +1508,7 @@ static int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
}
mdev->ldev->dc.disk_size = (sector_t)rs.resize_size;
- dd = drbd_determin_dev_size(mdev);
+ dd = drbd_determin_dev_size(mdev, rs.resize_force);
drbd_md_sync(mdev);
put_ldev(mdev);
if (dd == dev_size_error) {
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 259c1351b152..d065c646b35a 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -878,9 +878,13 @@ retry:
if (mdev->cram_hmac_tfm) {
/* drbd_request_state(mdev, NS(conn, WFAuth)); */
- if (!drbd_do_auth(mdev)) {
+ switch (drbd_do_auth(mdev)) {
+ case -1:
dev_err(DEV, "Authentication of peer failed\n");
return -1;
+ case 0:
+ dev_err(DEV, "Authentication of peer failed, trying again.\n");
+ return 0;
}
}
@@ -1201,10 +1205,11 @@ static int receive_Barrier(struct drbd_conf *mdev, struct p_header *h)
case WO_bdev_flush:
case WO_drain_io:
- D_ASSERT(rv == FE_STILL_LIVE);
- set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags);
- drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
- rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
+ if (rv == FE_STILL_LIVE) {
+ set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags);
+ drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
+ rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
+ }
if (rv == FE_RECYCLED)
return TRUE;
@@ -1219,7 +1224,7 @@ static int receive_Barrier(struct drbd_conf *mdev, struct p_header *h)
epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
if (!epoch) {
dev_warn(DEV, "Allocation of an epoch failed, slowing down\n");
- issue_flush = !test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
+ issue_flush = !test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags);
drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
if (issue_flush) {
rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
@@ -2865,7 +2870,7 @@ static int receive_sizes(struct drbd_conf *mdev, struct p_header *h)
/* Never shrink a device with usable data during connect.
But allow online shrinking if we are connected. */
- if (drbd_new_dev_size(mdev, mdev->ldev) <
+ if (drbd_new_dev_size(mdev, mdev->ldev, 0) <
drbd_get_capacity(mdev->this_bdev) &&
mdev->state.disk >= D_OUTDATED &&
mdev->state.conn < C_CONNECTED) {
@@ -2880,7 +2885,7 @@ static int receive_sizes(struct drbd_conf *mdev, struct p_header *h)
#undef min_not_zero
if (get_ldev(mdev)) {
- dd = drbd_determin_dev_size(mdev);
+ dd = drbd_determin_dev_size(mdev, 0);
put_ldev(mdev);
if (dd == dev_size_error)
return FALSE;
@@ -3830,10 +3835,17 @@ static int drbd_do_auth(struct drbd_conf *mdev)
{
dev_err(DEV, "This kernel was build without CONFIG_CRYPTO_HMAC.\n");
dev_err(DEV, "You need to disable 'cram-hmac-alg' in drbd.conf.\n");
- return 0;
+ return -1;
}
#else
#define CHALLENGE_LEN 64
+
+/* Return value:
+ 1 - auth succeeded,
+ 0 - failed, try again (network error),
+ -1 - auth failed, don't try again.
+*/
+
static int drbd_do_auth(struct drbd_conf *mdev)
{
char my_challenge[CHALLENGE_LEN]; /* 64 Bytes... */
@@ -3854,7 +3866,7 @@ static int drbd_do_auth(struct drbd_conf *mdev)
(u8 *)mdev->net_conf->shared_secret, key_len);
if (rv) {
dev_err(DEV, "crypto_hash_setkey() failed with %d\n", rv);
- rv = 0;
+ rv = -1;
goto fail;
}
@@ -3877,14 +3889,14 @@ static int drbd_do_auth(struct drbd_conf *mdev)
if (p.length > CHALLENGE_LEN*2) {
dev_err(DEV, "expected AuthChallenge payload too big.\n");
- rv = 0;
+ rv = -1;
goto fail;
}
peers_ch = kmalloc(p.length, GFP_NOIO);
if (peers_ch == NULL) {
dev_err(DEV, "kmalloc of peers_ch failed\n");
- rv = 0;
+ rv = -1;
goto fail;
}
@@ -3900,7 +3912,7 @@ static int drbd_do_auth(struct drbd_conf *mdev)
response = kmalloc(resp_size, GFP_NOIO);
if (response == NULL) {
dev_err(DEV, "kmalloc of response failed\n");
- rv = 0;
+ rv = -1;
goto fail;
}
@@ -3910,7 +3922,7 @@ static int drbd_do_auth(struct drbd_conf *mdev)
rv = crypto_hash_digest(&desc, &sg, sg.length, response);
if (rv) {
dev_err(DEV, "crypto_hash_digest() failed with %d\n", rv);
- rv = 0;
+ rv = -1;
goto fail;
}
@@ -3944,9 +3956,9 @@ static int drbd_do_auth(struct drbd_conf *mdev)
}
right_response = kmalloc(resp_size, GFP_NOIO);
- if (response == NULL) {
+ if (right_response == NULL) {
dev_err(DEV, "kmalloc of right_response failed\n");
- rv = 0;
+ rv = -1;
goto fail;
}
@@ -3955,7 +3967,7 @@ static int drbd_do_auth(struct drbd_conf *mdev)
rv = crypto_hash_digest(&desc, &sg, sg.length, right_response);
if (rv) {
dev_err(DEV, "crypto_hash_digest() failed with %d\n", rv);
- rv = 0;
+ rv = -1;
goto fail;
}
@@ -3964,6 +3976,8 @@ static int drbd_do_auth(struct drbd_conf *mdev)
if (rv)
dev_info(DEV, "Peer authenticated using %d bytes of '%s' HMAC\n",
resp_size, mdev->net_conf->cram_hmac_alg);
+ else
+ rv = -1;
fail:
kfree(peers_ch);
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h
index f22c1bc8ec7e..16119d7056cc 100644
--- a/drivers/block/drbd/drbd_req.h
+++ b/drivers/block/drbd/drbd_req.h
@@ -57,7 +57,7 @@
*
* It may me handed over to the local disk subsystem.
* It may be completed by the local disk subsystem,
- * either sucessfully or with io-error.
+ * either successfully or with io-error.
* In case it is a READ request, and it failed locally,
* it may be retried remotely.
*
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 3266b4f65daa..90c4038702da 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -144,13 +144,23 @@
* Better audit of register_blkdev.
*/
-#define FLOPPY_SANITY_CHECK
#undef FLOPPY_SILENT_DCL_CLEAR
#define REALLY_SLOW_IO
#define DEBUGT 2
-#define DCL_DEBUG /* debug disk change line */
+
+#define DPRINT(format, args...) \
+ pr_info("floppy%d: " format, current_drive, ##args)
+
+#define DCL_DEBUG /* debug disk change line */
+#ifdef DCL_DEBUG
+#define debug_dcl(test, fmt, args...) \
+ do { if ((test) & FD_DEBUG) DPRINT(fmt, ##args); } while (0)
+#else
+#define debug_dcl(test, fmt, args...) \
+ do { if (0) DPRINT(fmt, ##args); } while (0)
+#endif
/* do print messages for unexpected interrupts */
static int print_unex = 1;
@@ -180,6 +190,8 @@ static int print_unex = 1;
#include <linux/mod_devicetable.h>
#include <linux/buffer_head.h> /* for invalidate_buffers() */
#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
/*
* PS/2 floppies have much slower step rates than regular floppies.
@@ -191,8 +203,6 @@ static int slow_floppy;
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
static int FLOPPY_IRQ = 6;
static int FLOPPY_DMA = 2;
@@ -241,8 +251,6 @@ static int allowed_drive_mask = 0x33;
static int irqdma_allocated;
-#define DEVICE_NAME "floppy"
-
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/cdrom.h> /* for the compatibility eject ioctl */
@@ -250,7 +258,7 @@ static int irqdma_allocated;
static struct request *current_req;
static struct request_queue *floppy_queue;
-static void do_fd_request(struct request_queue * q);
+static void do_fd_request(struct request_queue *q);
#ifndef fd_get_dma_residue
#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
@@ -263,7 +271,7 @@ static void do_fd_request(struct request_queue * q);
#endif
#ifndef fd_dma_mem_alloc
-#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,get_order(size))
+#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
#endif
static inline void fallback_on_nodma_alloc(char **addr, size_t l)
@@ -273,7 +281,7 @@ static inline void fallback_on_nodma_alloc(char **addr, size_t l)
return; /* we have the memory */
if (can_use_virtual_dma != 2)
return; /* no fallback allowed */
- printk("DMA memory shortage. Temporarily falling back on virtual DMA\n");
+ pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
*addr = (char *)nodma_mem_alloc(l);
#else
return;
@@ -283,59 +291,50 @@ static inline void fallback_on_nodma_alloc(char **addr, size_t l)
/* End dma memory related stuff */
static unsigned long fake_change;
-static int initialising = 1;
+static bool initialized;
-#define ITYPE(x) (((x)>>2) & 0x1f)
-#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
-#define UNIT(x) ((x) & 0x03) /* drive on fdc */
-#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
+#define ITYPE(x) (((x) >> 2) & 0x1f)
+#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
+#define UNIT(x) ((x) & 0x03) /* drive on fdc */
+#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
/* reverse mapping from unit and fdc to drive */
#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
-#define DP (&drive_params[current_drive])
-#define DRS (&drive_state[current_drive])
-#define DRWE (&write_errors[current_drive])
-#define FDCS (&fdc_state[fdc])
-#define CLEARF(x) clear_bit(x##_BIT, &DRS->flags)
-#define SETF(x) set_bit(x##_BIT, &DRS->flags)
-#define TESTF(x) test_bit(x##_BIT, &DRS->flags)
-#define UDP (&drive_params[drive])
-#define UDRS (&drive_state[drive])
-#define UDRWE (&write_errors[drive])
-#define UFDCS (&fdc_state[FDC(drive)])
-#define UCLEARF(x) clear_bit(x##_BIT, &UDRS->flags)
-#define USETF(x) set_bit(x##_BIT, &UDRS->flags)
-#define UTESTF(x) test_bit(x##_BIT, &UDRS->flags)
+#define DP (&drive_params[current_drive])
+#define DRS (&drive_state[current_drive])
+#define DRWE (&write_errors[current_drive])
+#define FDCS (&fdc_state[fdc])
-#define DPRINT(format, args...) printk(DEVICE_NAME "%d: " format, current_drive , ## args)
+#define UDP (&drive_params[drive])
+#define UDRS (&drive_state[drive])
+#define UDRWE (&write_errors[drive])
+#define UFDCS (&fdc_state[FDC(drive)])
-#define PH_HEAD(floppy,head) (((((floppy)->stretch & 2) >>1) ^ head) << 2)
-#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
-
-#define CLEARSTRUCT(x) memset((x), 0, sizeof(*(x)))
+#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
+#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
/* read/write */
-#define COMMAND raw_cmd->cmd[0]
-#define DR_SELECT raw_cmd->cmd[1]
-#define TRACK raw_cmd->cmd[2]
-#define HEAD raw_cmd->cmd[3]
-#define SECTOR raw_cmd->cmd[4]
-#define SIZECODE raw_cmd->cmd[5]
-#define SECT_PER_TRACK raw_cmd->cmd[6]
-#define GAP raw_cmd->cmd[7]
-#define SIZECODE2 raw_cmd->cmd[8]
+#define COMMAND (raw_cmd->cmd[0])
+#define DR_SELECT (raw_cmd->cmd[1])
+#define TRACK (raw_cmd->cmd[2])
+#define HEAD (raw_cmd->cmd[3])
+#define SECTOR (raw_cmd->cmd[4])
+#define SIZECODE (raw_cmd->cmd[5])
+#define SECT_PER_TRACK (raw_cmd->cmd[6])
+#define GAP (raw_cmd->cmd[7])
+#define SIZECODE2 (raw_cmd->cmd[8])
#define NR_RW 9
/* format */
-#define F_SIZECODE raw_cmd->cmd[2]
-#define F_SECT_PER_TRACK raw_cmd->cmd[3]
-#define F_GAP raw_cmd->cmd[4]
-#define F_FILL raw_cmd->cmd[5]
+#define F_SIZECODE (raw_cmd->cmd[2])
+#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
+#define F_GAP (raw_cmd->cmd[4])
+#define F_FILL (raw_cmd->cmd[5])
#define NR_F 6
/*
- * Maximum disk size (in kilobytes). This default is used whenever the
- * current disk size is unknown.
+ * Maximum disk size (in kilobytes).
+ * This default is used whenever the current disk size is unknown.
* [Now it is rather a minimum]
*/
#define MAX_DISK_SIZE 4 /* 3984 */
@@ -345,16 +344,17 @@ static int initialising = 1;
*/
#define MAX_REPLIES 16
static unsigned char reply_buffer[MAX_REPLIES];
-static int inr; /* size of reply buffer, when called from interrupt */
-#define ST0 (reply_buffer[0])
-#define ST1 (reply_buffer[1])
-#define ST2 (reply_buffer[2])
-#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
-#define R_TRACK (reply_buffer[3])
-#define R_HEAD (reply_buffer[4])
-#define R_SECTOR (reply_buffer[5])
-#define R_SIZECODE (reply_buffer[6])
-#define SEL_DLY (2*HZ/100)
+static int inr; /* size of reply buffer, when called from interrupt */
+#define ST0 (reply_buffer[0])
+#define ST1 (reply_buffer[1])
+#define ST2 (reply_buffer[2])
+#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
+#define R_TRACK (reply_buffer[3])
+#define R_HEAD (reply_buffer[4])
+#define R_SECTOR (reply_buffer[5])
+#define R_SIZECODE (reply_buffer[6])
+
+#define SEL_DLY (2 * HZ / 100)
/*
* this struct defines the different floppy drive types.
@@ -505,9 +505,9 @@ static char floppy_device_name[] = "floppy";
static int probing;
/* Synchronization of FDC access. */
-#define FD_COMMAND_NONE -1
-#define FD_COMMAND_ERROR 2
-#define FD_COMMAND_OKAY 3
+#define FD_COMMAND_NONE -1
+#define FD_COMMAND_ERROR 2
+#define FD_COMMAND_OKAY 3
static volatile int command_status = FD_COMMAND_NONE;
static unsigned long fdc_busy;
@@ -515,11 +515,6 @@ static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
static DECLARE_WAIT_QUEUE_HEAD(command_done);
#define NO_SIGNAL (!interruptible || !signal_pending(current))
-#define CALL(x) if ((x) == -EINTR) return -EINTR
-#define ECALL(x) if ((ret = (x))) return ret;
-#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))
-#define WAIT(x) _WAIT((x),interruptible)
-#define IWAIT(x) _WAIT((x),1)
/* Errors during formatting are counted here. */
static int format_errors;
@@ -545,8 +540,9 @@ static int max_buffer_sectors;
static int *errors;
typedef void (*done_f)(int);
static struct cont_t {
- void (*interrupt)(void); /* this is called after the interrupt of the
- * main command */
+ void (*interrupt)(void);
+ /* this is called after the interrupt of the
+ * main command */
void (*redo)(void); /* this is called to retry the operation */
void (*error)(void); /* this is called to tally an error */
done_f done; /* this is called to say if the operation has
@@ -571,7 +567,6 @@ static void floppy_release_irq_and_dma(void);
* reset doesn't need to be tested before sending commands, because
* output_byte is automatically disabled when reset is set.
*/
-#define CHECK_RESET { if (FDCS->reset){ reset_fdc(); return; } }
static void reset_fdc(void);
/*
@@ -579,9 +574,9 @@ static void reset_fdc(void);
* information to interrupts. They are the data used for the current
* request.
*/
-#define NO_TRACK -1
-#define NEED_1_RECAL -2
-#define NEED_2_RECAL -3
+#define NO_TRACK -1
+#define NEED_1_RECAL -2
+#define NEED_2_RECAL -3
static int usage_count;
@@ -621,39 +616,35 @@ static inline void set_debugt(void)
debugtimer = jiffies;
}
-static inline void debugt(const char *message)
+static inline void debugt(const char *func, const char *msg)
{
if (DP->flags & DEBUGT)
- printk("%s dtime=%lu\n", message, jiffies - debugtimer);
+ pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
}
#else
static inline void set_debugt(void) { }
-static inline void debugt(const char *message) { }
+static inline void debugt(const char *func, const char *msg) { }
#endif /* DEBUGT */
-typedef void (*timeout_fn) (unsigned long);
+typedef void (*timeout_fn)(unsigned long);
static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
static const char *timeout_message;
-#ifdef FLOPPY_SANITY_CHECK
-static void is_alive(const char *message)
+static void is_alive(const char *func, const char *message)
{
/* this routine checks whether the floppy driver is "alive" */
- if (test_bit(0, &fdc_busy) && command_status < 2
- && !timer_pending(&fd_timeout)) {
- DPRINT("timeout handler died: %s\n", message);
+ if (test_bit(0, &fdc_busy) && command_status < 2 &&
+ !timer_pending(&fd_timeout)) {
+ DPRINT("%s: timeout handler died. %s\n", func, message);
}
}
-#endif
-static void (*do_floppy) (void) = NULL;
-
-#ifdef FLOPPY_SANITY_CHECK
+static void (*do_floppy)(void) = NULL;
#define OLOGSIZE 20
-static void (*lasthandler) (void);
+static void (*lasthandler)(void);
static unsigned long interruptjiffies;
static unsigned long resultjiffies;
static int resultsize;
@@ -666,12 +657,11 @@ static struct output_log {
} output_log[OLOGSIZE];
static int output_log_pos;
-#endif
#define current_reqD -1
#define MAXTIMEOUT -2
-static void __reschedule_timeout(int drive, const char *message, int marg)
+static void __reschedule_timeout(int drive, const char *message)
{
if (drive == current_reqD)
drive = current_drive;
@@ -682,25 +672,22 @@ static void __reschedule_timeout(int drive, const char *message, int marg)
} else
fd_timeout.expires = jiffies + UDP->timeout;
add_timer(&fd_timeout);
- if (UDP->flags & FD_DEBUG) {
- DPRINT("reschedule timeout ");
- printk(message, marg);
- printk("\n");
- }
+ if (UDP->flags & FD_DEBUG)
+ DPRINT("reschedule timeout %s\n", message);
timeout_message = message;
}
-static void reschedule_timeout(int drive, const char *message, int marg)
+static void reschedule_timeout(int drive, const char *message)
{
unsigned long flags;
spin_lock_irqsave(&floppy_lock, flags);
- __reschedule_timeout(drive, message, marg);
+ __reschedule_timeout(drive, message);
spin_unlock_irqrestore(&floppy_lock, flags);
}
-#define INFBOUND(a,b) (a)=max_t(int, a, b)
-#define SUPBOUND(a,b) (a)=min_t(int, a, b)
+#define INFBOUND(a, b) (a) = max_t(int, a, b)
+#define SUPBOUND(a, b) (a) = min_t(int, a, b)
/*
* Bottom half floppy driver.
@@ -739,7 +726,6 @@ static int disk_change(int drive)
{
int fdc = FDC(drive);
-#ifdef FLOPPY_SANITY_CHECK
if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
DPRINT("WARNING disk change called early\n");
if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
@@ -748,31 +734,27 @@ static int disk_change(int drive)
DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
(unsigned int)FDCS->dor);
}
-#endif
-#ifdef DCL_DEBUG
- if (UDP->flags & FD_DEBUG) {
- DPRINT("checking disk change line for drive %d\n", drive);
- DPRINT("jiffies=%lu\n", jiffies);
- DPRINT("disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
- DPRINT("flags=%lx\n", UDRS->flags);
- }
-#endif
+ debug_dcl(UDP->flags,
+ "checking disk change line for drive %d\n", drive);
+ debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
+ debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
+ debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
+
if (UDP->flags & FD_BROKEN_DCL)
- return UTESTF(FD_DISK_CHANGED);
+ return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
- USETF(FD_VERIFY); /* verify write protection */
- if (UDRS->maxblock) {
- /* mark it changed */
- USETF(FD_DISK_CHANGED);
- }
+ set_bit(FD_VERIFY_BIT, &UDRS->flags);
+ /* verify write protection */
+
+ if (UDRS->maxblock) /* mark it changed */
+ set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
/* invalidate its geometry */
if (UDRS->keep_data >= 0) {
if ((UDP->flags & FTD_MSG) &&
current_type[drive] != NULL)
- DPRINT("Disk type is undefined after "
- "disk change\n");
+ DPRINT("Disk type is undefined after disk change\n");
current_type[drive] = NULL;
floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
}
@@ -780,7 +762,7 @@ static int disk_change(int drive)
return 1;
} else {
UDRS->last_checked = jiffies;
- UCLEARF(FD_DISK_NEWCHANGE);
+ clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
}
return 0;
}
@@ -790,6 +772,12 @@ static inline int is_selected(int dor, int unit)
return ((dor & (0x10 << unit)) && (dor & 3) == unit);
}
+static bool is_ready_state(int status)
+{
+ int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
+ return state == STATUS_READY;
+}
+
static int set_dor(int fdc, char mask, char data)
{
unsigned char unit;
@@ -806,11 +794,8 @@ static int set_dor(int fdc, char mask, char data)
unit = olddor & 0x3;
if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
drive = REVDRIVE(fdc, unit);
-#ifdef DCL_DEBUG
- if (UDP->flags & FD_DEBUG) {
- DPRINT("calling disk change from set_dor\n");
- }
-#endif
+ debug_dcl(UDP->flags,
+ "calling disk change from set_dor\n");
disk_change(drive);
}
FDCS->dor = newdor;
@@ -834,8 +819,10 @@ static void twaddle(void)
DRS->select_date = jiffies;
}
-/* reset all driver information about the current fdc. This is needed after
- * a reset, and after a raw command. */
+/*
+ * Reset all driver information about the current fdc.
+ * This is needed after a reset, and after a raw command.
+ */
static void reset_fdc_info(int mode)
{
int drive;
@@ -857,7 +844,7 @@ static void set_fdc(int drive)
current_drive = drive;
}
if (fdc != 1 && fdc != 0) {
- printk("bad fdc value\n");
+ pr_info("bad fdc value\n");
return;
}
set_dor(fdc, ~0, 8);
@@ -871,11 +858,10 @@ static void set_fdc(int drive)
}
/* locks the driver */
-static int _lock_fdc(int drive, int interruptible, int line)
+static int _lock_fdc(int drive, bool interruptible, int line)
{
if (!usage_count) {
- printk(KERN_ERR
- "Trying to lock fdc while usage count=0 at line %d\n",
+ pr_err("Trying to lock fdc while usage count=0 at line %d\n",
line);
return -1;
}
@@ -904,15 +890,13 @@ static int _lock_fdc(int drive, int interruptible, int line)
}
command_status = FD_COMMAND_NONE;
- __reschedule_timeout(drive, "lock fdc", 0);
+ __reschedule_timeout(drive, "lock fdc");
set_fdc(drive);
return 0;
}
-#define lock_fdc(drive,interruptible) _lock_fdc(drive,interruptible, __LINE__)
-
-#define LOCK_FDC(drive,interruptible) \
-if (lock_fdc(drive,interruptible)) return -EINTR;
+#define lock_fdc(drive, interruptible) \
+ _lock_fdc(drive, interruptible, __LINE__)
/* unlocks the driver */
static inline void unlock_fdc(void)
@@ -924,7 +908,7 @@ static inline void unlock_fdc(void)
DPRINT("FDC access conflict!\n");
if (do_floppy)
- DPRINT("device interrupt still active at FDC release: %p!\n",
+ DPRINT("device interrupt still active at FDC release: %pf!\n",
do_floppy);
command_status = FD_COMMAND_NONE;
spin_lock_irqsave(&floppy_lock, flags);
@@ -1003,7 +987,7 @@ static void empty(void)
static DECLARE_WORK(floppy_work, NULL);
-static void schedule_bh(void (*handler) (void))
+static void schedule_bh(void (*handler)(void))
{
PREPARE_WORK(&floppy_work, (work_func_t)handler);
schedule_work(&floppy_work);
@@ -1026,11 +1010,7 @@ static void cancel_activity(void)
* transfer */
static void fd_watchdog(void)
{
-#ifdef DCL_DEBUG
- if (DP->flags & FD_DEBUG) {
- DPRINT("calling disk change from watchdog\n");
- }
-#endif
+ debug_dcl(DP->flags, "calling disk change from watchdog\n");
if (disk_change(current_drive)) {
DPRINT("disk removed during i/o\n");
@@ -1039,7 +1019,7 @@ static void fd_watchdog(void)
reset_fdc();
} else {
del_timer(&fd_timer);
- fd_timer.function = (timeout_fn) fd_watchdog;
+ fd_timer.function = (timeout_fn)fd_watchdog;
fd_timer.expires = jiffies + HZ / 10;
add_timer(&fd_timer);
}
@@ -1105,25 +1085,23 @@ static void setup_DMA(void)
{
unsigned long f;
-#ifdef FLOPPY_SANITY_CHECK
if (raw_cmd->length == 0) {
int i;
- printk("zero dma transfer size:");
+ pr_info("zero dma transfer size:");
for (i = 0; i < raw_cmd->cmd_count; i++)
- printk("%x,", raw_cmd->cmd[i]);
- printk("\n");
+ pr_cont("%x,", raw_cmd->cmd[i]);
+ pr_cont("\n");
cont->done(0);
FDCS->reset = 1;
return;
}
if (((unsigned long)raw_cmd->kernel_data) % 512) {
- printk("non aligned address: %p\n", raw_cmd->kernel_data);
+ pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
cont->done(0);
FDCS->reset = 1;
return;
}
-#endif
f = claim_dma_lock();
fd_disable_dma();
#ifdef fd_dma_setup
@@ -1165,7 +1143,7 @@ static int wait_til_ready(void)
if (status & STATUS_READY)
return status;
}
- if (!initialising) {
+ if (initialized) {
DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
show_floppy();
}
@@ -1176,22 +1154,21 @@ static int wait_til_ready(void)
/* sends a command byte to the fdc */
static int output_byte(char byte)
{
- int status;
+ int status = wait_til_ready();
- if ((status = wait_til_ready()) < 0)
+ if (status < 0)
return -1;
- if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY) {
+
+ if (is_ready_state(status)) {
fd_outb(byte, FD_DATA);
-#ifdef FLOPPY_SANITY_CHECK
output_log[output_log_pos].data = byte;
output_log[output_log_pos].status = status;
output_log[output_log_pos].jiffies = jiffies;
output_log_pos = (output_log_pos + 1) % OLOGSIZE;
-#endif
return 0;
}
FDCS->reset = 1;
- if (!initialising) {
+ if (initialized) {
DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
byte, fdc, status);
show_floppy();
@@ -1199,8 +1176,6 @@ static int output_byte(char byte)
return -1;
}
-#define LAST_OUT(x) if (output_byte(x)<0){ reset_fdc();return;}
-
/* gets the response from the fdc */
static int result(void)
{
@@ -1208,14 +1183,13 @@ static int result(void)
int status = 0;
for (i = 0; i < MAX_REPLIES; i++) {
- if ((status = wait_til_ready()) < 0)
+ status = wait_til_ready();
+ if (status < 0)
break;
status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
if ((status & ~STATUS_BUSY) == STATUS_READY) {
-#ifdef FLOPPY_SANITY_CHECK
resultjiffies = jiffies;
resultsize = i;
-#endif
return i;
}
if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
@@ -1223,10 +1197,9 @@ static int result(void)
else
break;
}
- if (!initialising) {
- DPRINT
- ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
- fdc, status, i);
+ if (initialized) {
+ DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
+ fdc, status, i);
show_floppy();
}
FDCS->reset = 1;
@@ -1237,12 +1210,14 @@ static int result(void)
/* does the fdc need more output? */
static int need_more_output(void)
{
- int status;
+ int status = wait_til_ready();
- if ((status = wait_til_ready()) < 0)
+ if (status < 0)
return -1;
- if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
+
+ if (is_ready_state(status))
return MORE_OUTPUT;
+
return result();
}
@@ -1264,9 +1239,12 @@ static inline void perpendicular_mode(void)
default:
DPRINT("Invalid data rate for perpendicular mode!\n");
cont->done(0);
- FDCS->reset = 1; /* convenient way to return to
- * redo without to much hassle (deep
- * stack et al. */
+ FDCS->reset = 1;
+ /*
+ * convenient way to return to
+ * redo without too much hassle
+ * (deep stack et al.)
+ */
return;
}
} else
@@ -1366,9 +1344,9 @@ static void fdc_specify(void)
/* Convert step rate from microseconds to milliseconds and 4 bits */
srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
- if (slow_floppy) {
+ if (slow_floppy)
srt = srt / 4;
- }
+
SUPBOUND(srt, 0xf);
INFBOUND(srt, 0);
@@ -1415,16 +1393,46 @@ static int fdc_dtr(void)
* Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
*/
FDCS->dtr = raw_cmd->rate & 3;
- return (fd_wait_for_completion(jiffies + 2UL * HZ / 100,
- (timeout_fn) floppy_ready));
+ return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
+ (timeout_fn)floppy_ready);
} /* fdc_dtr */
static void tell_sector(void)
{
- printk(": track %d, head %d, sector %d, size %d",
- R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
+ pr_cont(": track %d, head %d, sector %d, size %d",
+ R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
} /* tell_sector */
+static void print_errors(void)
+{
+ DPRINT("");
+ if (ST0 & ST0_ECE) {
+ pr_cont("Recalibrate failed!");
+ } else if (ST2 & ST2_CRC) {
+ pr_cont("data CRC error");
+ tell_sector();
+ } else if (ST1 & ST1_CRC) {
+ pr_cont("CRC error");
+ tell_sector();
+ } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
+ (ST2 & ST2_MAM)) {
+ if (!probing) {
+ pr_cont("sector not found");
+ tell_sector();
+ } else
+ pr_cont("probe failed...");
+ } else if (ST2 & ST2_WC) { /* seek error */
+ pr_cont("wrong cylinder");
+ } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
+ pr_cont("bad cylinder");
+ } else {
+ pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
+ ST0, ST1, ST2);
+ tell_sector();
+ }
+ pr_cont("\n");
+}
+
/*
* OK, this error interpreting routine is called after a
* DMA read/write has succeeded
@@ -1437,7 +1445,7 @@ static int interpret_errors(void)
char bad;
if (inr != 7) {
- DPRINT("-- FDC reply error");
+ DPRINT("-- FDC reply error\n");
FDCS->reset = 1;
return 1;
}
@@ -1450,43 +1458,17 @@ static int interpret_errors(void)
bad = 1;
if (ST1 & ST1_WP) {
DPRINT("Drive is write protected\n");
- CLEARF(FD_DISK_WRITABLE);
+ clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
cont->done(0);
bad = 2;
} else if (ST1 & ST1_ND) {
- SETF(FD_NEED_TWADDLE);
+ set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
} else if (ST1 & ST1_OR) {
if (DP->flags & FTD_MSG)
DPRINT("Over/Underrun - retrying\n");
bad = 0;
} else if (*errors >= DP->max_errors.reporting) {
- DPRINT("");
- if (ST0 & ST0_ECE) {
- printk("Recalibrate failed!");
- } else if (ST2 & ST2_CRC) {
- printk("data CRC error");
- tell_sector();
- } else if (ST1 & ST1_CRC) {
- printk("CRC error");
- tell_sector();
- } else if ((ST1 & (ST1_MAM | ST1_ND))
- || (ST2 & ST2_MAM)) {
- if (!probing) {
- printk("sector not found");
- tell_sector();
- } else
- printk("probe failed...");
- } else if (ST2 & ST2_WC) { /* seek error */
- printk("wrong cylinder");
- } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
- printk("bad cylinder");
- } else {
- printk
- ("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
- ST0, ST1, ST2);
- tell_sector();
- }
- printk("\n");
+ print_errors();
}
if (ST2 & ST2_WC || ST2 & ST2_BC)
/* wrong cylinder => recal */
@@ -1531,9 +1513,9 @@ static void setup_rw_floppy(void)
*/
if (time_after(ready_date, jiffies + DP->select_delay)) {
ready_date -= DP->select_delay;
- function = (timeout_fn) floppy_start;
+ function = (timeout_fn)floppy_start;
} else
- function = (timeout_fn) setup_rw_floppy;
+ function = (timeout_fn)setup_rw_floppy;
/* wait until the floppy is spinning fast enough */
if (fd_wait_for_completion(ready_date, function))
@@ -1551,7 +1533,7 @@ static void setup_rw_floppy(void)
for (i = 0; i < raw_cmd->cmd_count; i++)
r |= output_byte(raw_cmd->cmd[i]);
- debugt("rw_command: ");
+ debugt(__func__, "rw_command");
if (r) {
cont->error();
@@ -1574,7 +1556,7 @@ static int blind_seek;
*/
static void seek_interrupt(void)
{
- debugt("seek interrupt:");
+ debugt(__func__, "");
if (inr != 2 || (ST0 & 0xF8) != 0x20) {
DPRINT("seek failed\n");
DRS->track = NEED_2_RECAL;
@@ -1583,14 +1565,11 @@ static void seek_interrupt(void)
return;
}
if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
-#ifdef DCL_DEBUG
- if (DP->flags & FD_DEBUG) {
- DPRINT
- ("clearing NEWCHANGE flag because of effective seek\n");
- DPRINT("jiffies=%lu\n", jiffies);
- }
-#endif
- CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
+ debug_dcl(DP->flags,
+ "clearing NEWCHANGE flag because of effective seek\n");
+ debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
+ clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
+ /* effective seek */
DRS->select_date = jiffies;
}
DRS->track = ST1;
@@ -1599,26 +1578,23 @@ static void seek_interrupt(void)
static void check_wp(void)
{
- if (TESTF(FD_VERIFY)) {
- /* check write protection */
+ if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
+ /* check write protection */
output_byte(FD_GETSTATUS);
output_byte(UNIT(current_drive));
if (result() != 1) {
FDCS->reset = 1;
return;
}
- CLEARF(FD_VERIFY);
- CLEARF(FD_NEED_TWADDLE);
-#ifdef DCL_DEBUG
- if (DP->flags & FD_DEBUG) {
- DPRINT("checking whether disk is write protected\n");
- DPRINT("wp=%x\n", ST3 & 0x40);
- }
-#endif
+ clear_bit(FD_VERIFY_BIT, &DRS->flags);
+ clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
+ debug_dcl(DP->flags,
+ "checking whether disk is write protected\n");
+ debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
if (!(ST3 & 0x40))
- SETF(FD_DISK_WRITABLE);
+ set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
else
- CLEARF(FD_DISK_WRITABLE);
+ clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
}
}
@@ -1628,19 +1604,15 @@ static void seek_floppy(void)
blind_seek = 0;
-#ifdef DCL_DEBUG
- if (DP->flags & FD_DEBUG) {
- DPRINT("calling disk change from seek\n");
- }
-#endif
+ debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
- if (!TESTF(FD_DISK_NEWCHANGE) &&
+ if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
/* the media changed flag should be cleared after the seek.
* If it isn't, this means that there is really no disk in
* the drive.
*/
- SETF(FD_DISK_CHANGED);
+ set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
cont->done(0);
cont->redo();
return;
@@ -1648,7 +1620,7 @@ static void seek_floppy(void)
if (DRS->track <= NEED_1_RECAL) {
recalibrate_floppy();
return;
- } else if (TESTF(FD_DISK_NEWCHANGE) &&
+ } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
(raw_cmd->flags & FD_RAW_NEED_DISK) &&
(DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
/* we seek to clear the media-changed condition. Does anybody
@@ -1677,19 +1649,22 @@ static void seek_floppy(void)
do_floppy = seek_interrupt;
output_byte(FD_SEEK);
output_byte(UNIT(current_drive));
- LAST_OUT(track);
- debugt("seek command:");
+ if (output_byte(track) < 0) {
+ reset_fdc();
+ return;
+ }
+ debugt(__func__, "");
}
static void recal_interrupt(void)
{
- debugt("recal interrupt:");
+ debugt(__func__, "");
if (inr != 2)
FDCS->reset = 1;
else if (ST0 & ST0_ECE) {
switch (DRS->track) {
case NEED_1_RECAL:
- debugt("recal interrupt need 1 recal:");
+ debugt(__func__, "need 1 recal");
/* after a second recalibrate, we still haven't
* reached track 0. Probably no drive. Raise an
* error, as failing immediately might upset
@@ -1698,25 +1673,21 @@ static void recal_interrupt(void)
cont->redo();
return;
case NEED_2_RECAL:
- debugt("recal interrupt need 2 recal:");
+ debugt(__func__, "need 2 recal");
/* If we already did a recalibrate,
* and we are not at track 0, this
* means we have moved. (The only way
* not to move at recalibration is to
* be already at track 0.) Clear the
* new change flag */
-#ifdef DCL_DEBUG
- if (DP->flags & FD_DEBUG) {
- DPRINT
- ("clearing NEWCHANGE flag because of second recalibrate\n");
- }
-#endif
+ debug_dcl(DP->flags,
+ "clearing NEWCHANGE flag because of second recalibrate\n");
- CLEARF(FD_DISK_NEWCHANGE);
+ clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
DRS->select_date = jiffies;
/* fall through */
default:
- debugt("recal interrupt default:");
+ debugt(__func__, "default");
/* Recalibrate moves the head by at
* most 80 steps. If after one
* recalibrate we don't have reached
@@ -1738,8 +1709,8 @@ static void print_result(char *message, int inr)
DPRINT("%s ", message);
if (inr >= 0)
for (i = 0; i < inr; i++)
- printk("repl[%d]=%x ", i, reply_buffer[i]);
- printk("\n");
+ pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
+ pr_cont("\n");
}
/* interrupt handler. Note that this can be called externally on the Sparc */
@@ -1760,10 +1731,10 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id)
do_floppy = NULL;
if (fdc >= N_FDC || FDCS->address == -1) {
/* we don't even know which FDC is the culprit */
- printk("DOR0=%x\n", fdc_state[0].dor);
- printk("floppy interrupt on bizarre fdc %d\n", fdc);
- printk("handler=%p\n", handler);
- is_alive("bizarre fdc");
+ pr_info("DOR0=%x\n", fdc_state[0].dor);
+ pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
+ pr_info("handler=%pf\n", handler);
+ is_alive(__func__, "bizarre fdc");
return IRQ_NONE;
}
@@ -1777,7 +1748,7 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id)
* activity.
*/
- do_print = !handler && print_unex && !initialising;
+ do_print = !handler && print_unex && initialized;
inr = result();
if (do_print)
@@ -1790,15 +1761,15 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id)
if (do_print)
print_result("sensei", inr);
max_sensei--;
- } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
- && max_sensei);
+ } while ((ST0 & 0x83) != UNIT(current_drive) &&
+ inr == 2 && max_sensei);
}
if (!handler) {
FDCS->reset = 1;
return IRQ_NONE;
}
schedule_bh(handler);
- is_alive("normal interrupt end");
+ is_alive(__func__, "normal interrupt end");
/* FIXME! Was it really for us? */
return IRQ_HANDLED;
@@ -1806,10 +1777,11 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id)
static void recalibrate_floppy(void)
{
- debugt("recalibrate floppy:");
+ debugt(__func__, "");
do_floppy = recal_interrupt;
output_byte(FD_RECALIBRATE);
- LAST_OUT(UNIT(current_drive));
+ if (output_byte(UNIT(current_drive)) < 0)
+ reset_fdc();
}
/*
@@ -1817,10 +1789,10 @@ static void recalibrate_floppy(void)
*/
static void reset_interrupt(void)
{
- debugt("reset interrupt:");
+ debugt(__func__, "");
result(); /* get the status ready for set_fdc */
if (FDCS->reset) {
- printk("reset set in interrupt, calling %p\n", cont->error);
+ pr_info("reset set in interrupt, calling %pf\n", cont->error);
cont->error(); /* a reset just after a reset. BAD! */
}
cont->redo();
@@ -1858,53 +1830,49 @@ static void show_floppy(void)
{
int i;
- printk("\n");
- printk("floppy driver state\n");
- printk("-------------------\n");
- printk("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
- jiffies, interruptjiffies, jiffies - interruptjiffies,
- lasthandler);
+ pr_info("\n");
+ pr_info("floppy driver state\n");
+ pr_info("-------------------\n");
+ pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%pf\n",
+ jiffies, interruptjiffies, jiffies - interruptjiffies,
+ lasthandler);
-#ifdef FLOPPY_SANITY_CHECK
- printk("timeout_message=%s\n", timeout_message);
- printk("last output bytes:\n");
+ pr_info("timeout_message=%s\n", timeout_message);
+ pr_info("last output bytes:\n");
for (i = 0; i < OLOGSIZE; i++)
- printk("%2x %2x %lu\n",
- output_log[(i + output_log_pos) % OLOGSIZE].data,
- output_log[(i + output_log_pos) % OLOGSIZE].status,
- output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
- printk("last result at %lu\n", resultjiffies);
- printk("last redo_fd_request at %lu\n", lastredo);
- for (i = 0; i < resultsize; i++) {
- printk("%2x ", reply_buffer[i]);
- }
- printk("\n");
-#endif
-
- printk("status=%x\n", fd_inb(FD_STATUS));
- printk("fdc_busy=%lu\n", fdc_busy);
+ pr_info("%2x %2x %lu\n",
+ output_log[(i + output_log_pos) % OLOGSIZE].data,
+ output_log[(i + output_log_pos) % OLOGSIZE].status,
+ output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
+ pr_info("last result at %lu\n", resultjiffies);
+ pr_info("last redo_fd_request at %lu\n", lastredo);
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
+ reply_buffer, resultsize, true);
+
+ pr_info("status=%x\n", fd_inb(FD_STATUS));
+ pr_info("fdc_busy=%lu\n", fdc_busy);
if (do_floppy)
- printk("do_floppy=%p\n", do_floppy);
+ pr_info("do_floppy=%pf\n", do_floppy);
if (work_pending(&floppy_work))
- printk("floppy_work.func=%p\n", floppy_work.func);
+ pr_info("floppy_work.func=%pf\n", floppy_work.func);
if (timer_pending(&fd_timer))
- printk("fd_timer.function=%p\n", fd_timer.function);
+ pr_info("fd_timer.function=%pf\n", fd_timer.function);
if (timer_pending(&fd_timeout)) {
- printk("timer_function=%p\n", fd_timeout.function);
- printk("expires=%lu\n", fd_timeout.expires - jiffies);
- printk("now=%lu\n", jiffies);
- }
- printk("cont=%p\n", cont);
- printk("current_req=%p\n", current_req);
- printk("command_status=%d\n", command_status);
- printk("\n");
+ pr_info("timer_function=%pf\n", fd_timeout.function);
+ pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
+ pr_info("now=%lu\n", jiffies);
+ }
+ pr_info("cont=%p\n", cont);
+ pr_info("current_req=%p\n", current_req);
+ pr_info("command_status=%d\n", command_status);
+ pr_info("\n");
}
static void floppy_shutdown(unsigned long data)
{
unsigned long flags;
- if (!initialising)
+ if (initialized)
show_floppy();
cancel_activity();
@@ -1916,17 +1884,17 @@ static void floppy_shutdown(unsigned long data)
/* avoid dma going to a random drive after shutdown */
- if (!initialising)
+ if (initialized)
DPRINT("floppy timeout called\n");
FDCS->reset = 1;
if (cont) {
cont->done(0);
cont->redo(); /* this will recall reset when needed */
} else {
- printk("no cont in shutdown!\n");
+ pr_info("no cont in shutdown!\n");
process_fd_request();
}
- is_alive("floppy shutdown");
+ is_alive(__func__, "");
}
/* start motor, check media-changed condition and write protection */
@@ -1954,27 +1922,26 @@ static int start_motor(void (*function)(void))
set_dor(fdc, mask, data);
/* wait_for_completion also schedules reset if needed. */
- return (fd_wait_for_completion(DRS->select_date + DP->select_delay,
- (timeout_fn) function));
+ return fd_wait_for_completion(DRS->select_date + DP->select_delay,
+ (timeout_fn)function);
}
static void floppy_ready(void)
{
- CHECK_RESET;
+ if (FDCS->reset) {
+ reset_fdc();
+ return;
+ }
if (start_motor(floppy_ready))
return;
if (fdc_dtr())
return;
-#ifdef DCL_DEBUG
- if (DP->flags & FD_DEBUG) {
- DPRINT("calling disk change from floppy_ready\n");
- }
-#endif
+ debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
disk_change(current_drive) && !DP->select_delay)
- twaddle(); /* this clears the dcl on certain drive/controller
- * combinations */
+ twaddle(); /* this clears the dcl on certain
+ * drive/controller combinations */
#ifdef fd_chose_dma_mode
if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
@@ -1998,15 +1965,11 @@ static void floppy_ready(void)
static void floppy_start(void)
{
- reschedule_timeout(current_reqD, "floppy start", 0);
+ reschedule_timeout(current_reqD, "floppy start");
scandrives();
-#ifdef DCL_DEBUG
- if (DP->flags & FD_DEBUG) {
- DPRINT("setting NEWCHANGE in floppy_start\n");
- }
-#endif
- SETF(FD_DISK_NEWCHANGE);
+ debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
+ set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
floppy_ready();
}
@@ -2026,7 +1989,7 @@ static void floppy_start(void)
static void do_wakeup(void)
{
- reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
+ reschedule_timeout(MAXTIMEOUT, "do wakeup");
cont = NULL;
command_status += 2;
wake_up(&command_done);
@@ -2046,7 +2009,7 @@ static struct cont_t intr_cont = {
.done = (done_f)empty
};
-static int wait_til_done(void (*handler)(void), int interruptible)
+static int wait_til_done(void (*handler)(void), bool interruptible)
{
int ret;
@@ -2064,7 +2027,7 @@ static int wait_til_done(void (*handler)(void), int interruptible)
if (command_status >= 2 || !NO_SIGNAL)
break;
- is_alive("wait_til_done");
+ is_alive(__func__, "");
schedule();
}
@@ -2180,9 +2143,9 @@ static void format_interrupt(void)
cont->redo();
}
-#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
-#define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80) >>1))
+#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
#define CT(x) ((x) | 0xc0)
+
static void setup_format_params(int track)
{
int n;
@@ -2197,8 +2160,8 @@ static void setup_format_params(int track)
raw_cmd = &default_raw_cmd;
raw_cmd->track = track;
- raw_cmd->flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
- FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
+ raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
+ FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
raw_cmd->rate = _floppy->rate & 0x43;
raw_cmd->cmd_count = NR_F;
COMMAND = FM_MODE(_floppy, FD_FORMAT);
@@ -2257,7 +2220,7 @@ static void redo_format(void)
buffer_track = -1;
setup_format_params(format_req.track << STRETCH(_floppy));
floppy_start();
- debugt("queue format request");
+ debugt(__func__, "queue format request");
}
static struct cont_t format_cont = {
@@ -2271,7 +2234,9 @@ static int do_format(int drive, struct format_descr *tmp_format_req)
{
int ret;
- LOCK_FDC(drive, 1);
+ if (lock_fdc(drive, true))
+ return -EINTR;
+
set_floppy(drive);
if (!_floppy ||
_floppy->track > DP->tracks ||
@@ -2286,7 +2251,9 @@ static int do_format(int drive, struct format_descr *tmp_format_req)
format_errors = 0;
cont = &format_cont;
errors = &format_errors;
- IWAIT(redo_format);
+ ret = wait_til_done(redo_format, true);
+ if (ret == -EINTR)
+ return -EINTR;
process_fd_request();
return ret;
}
@@ -2320,12 +2287,14 @@ static void request_done(int uptodate)
struct request *req = current_req;
unsigned long flags;
int block;
+ char msg[sizeof("request done ") + sizeof(int) * 3];
probing = 0;
- reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate);
+ snprintf(msg, sizeof(msg), "request done %d", uptodate);
+ reschedule_timeout(MAXTIMEOUT, msg);
if (!req) {
- printk("floppy.c: no request in request_done\n");
+ pr_info("floppy.c: no request in request_done\n");
return;
}
@@ -2377,7 +2346,7 @@ static void rw_interrupt(void)
DRS->first_read_date = jiffies;
nr_sectors = 0;
- CODE2SIZE;
+ ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
if (ST1 & ST1_EOC)
eoc = 1;
@@ -2393,20 +2362,18 @@ static void rw_interrupt(void)
R_HEAD - HEAD) * SECT_PER_TRACK +
R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
-#ifdef FLOPPY_SANITY_CHECK
if (nr_sectors / ssize >
DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
DPRINT("long rw: %x instead of %lx\n",
nr_sectors, current_count_sectors);
- printk("rs=%d s=%d\n", R_SECTOR, SECTOR);
- printk("rh=%d h=%d\n", R_HEAD, HEAD);
- printk("rt=%d t=%d\n", R_TRACK, TRACK);
- printk("heads=%d eoc=%d\n", heads, eoc);
- printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK,
- fsector_t, ssize);
- printk("in_sector_offset=%d\n", in_sector_offset);
+ pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
+ pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
+ pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
+ pr_info("heads=%d eoc=%d\n", heads, eoc);
+ pr_info("spt=%d st=%d ss=%d\n",
+ SECT_PER_TRACK, fsector_t, ssize);
+ pr_info("in_sector_offset=%d\n", in_sector_offset);
}
-#endif
nr_sectors -= in_sector_offset;
INFBOUND(nr_sectors, 0);
@@ -2511,19 +2478,17 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
blk_rq_sectors(current_req));
remaining = current_count_sectors << 9;
-#ifdef FLOPPY_SANITY_CHECK
if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
DPRINT("in copy buffer\n");
- printk("current_count_sectors=%ld\n", current_count_sectors);
- printk("remaining=%d\n", remaining >> 9);
- printk("current_req->nr_sectors=%u\n",
- blk_rq_sectors(current_req));
- printk("current_req->current_nr_sectors=%u\n",
- blk_rq_cur_sectors(current_req));
- printk("max_sector=%d\n", max_sector);
- printk("ssize=%d\n", ssize);
+ pr_info("current_count_sectors=%ld\n", current_count_sectors);
+ pr_info("remaining=%d\n", remaining >> 9);
+ pr_info("current_req->nr_sectors=%u\n",
+ blk_rq_sectors(current_req));
+ pr_info("current_req->current_nr_sectors=%u\n",
+ blk_rq_cur_sectors(current_req));
+ pr_info("max_sector=%d\n", max_sector);
+ pr_info("ssize=%d\n", ssize);
}
-#endif
buffer_max = max(max_sector, buffer_max);
@@ -2539,26 +2504,24 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
SUPBOUND(size, remaining);
buffer = page_address(bv->bv_page) + bv->bv_offset;
-#ifdef FLOPPY_SANITY_CHECK
if (dma_buffer + size >
floppy_track_buffer + (max_buffer_sectors << 10) ||
dma_buffer < floppy_track_buffer) {
DPRINT("buffer overrun in copy buffer %d\n",
- (int)((floppy_track_buffer -
- dma_buffer) >> 9));
- printk("fsector_t=%d buffer_min=%d\n",
- fsector_t, buffer_min);
- printk("current_count_sectors=%ld\n",
- current_count_sectors);
+ (int)((floppy_track_buffer - dma_buffer) >> 9));
+ pr_info("fsector_t=%d buffer_min=%d\n",
+ fsector_t, buffer_min);
+ pr_info("current_count_sectors=%ld\n",
+ current_count_sectors);
if (CT(COMMAND) == FD_READ)
- printk("read\n");
+ pr_info("read\n");
if (CT(COMMAND) == FD_WRITE)
- printk("write\n");
+ pr_info("write\n");
break;
}
if (((unsigned long)buffer) % 512)
DPRINT("%p buffer not aligned\n", buffer);
-#endif
+
if (CT(COMMAND) == FD_READ)
memcpy(buffer, dma_buffer, size);
else
@@ -2567,13 +2530,11 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
remaining -= size;
dma_buffer += size;
}
-#ifdef FLOPPY_SANITY_CHECK
if (remaining) {
if (remaining > 0)
max_sector -= remaining >> 9;
DPRINT("weirdness: remaining %d\n", remaining >> 9);
}
-#endif
}
/* work around a bug in pseudo DMA
@@ -2593,15 +2554,14 @@ static void virtualdmabug_workaround(void)
hard_sectors = raw_cmd->length >> (7 + SIZECODE);
end_sector = SECTOR + hard_sectors - 1;
-#ifdef FLOPPY_SANITY_CHECK
if (end_sector > SECT_PER_TRACK) {
- printk("too many sectors %d > %d\n",
- end_sector, SECT_PER_TRACK);
+ pr_info("too many sectors %d > %d\n",
+ end_sector, SECT_PER_TRACK);
return;
}
-#endif
- SECT_PER_TRACK = end_sector; /* make sure SECT_PER_TRACK points
- * to end of transfer */
+ SECT_PER_TRACK = end_sector;
+ /* make sure SECT_PER_TRACK
+ * points to end of transfer */
}
}
@@ -2624,7 +2584,7 @@ static int make_raw_rw_request(void)
int ssize;
if (max_buffer_sectors == 0) {
- printk("VFS: Block I/O scheduled on unopened device\n");
+ pr_info("VFS: Block I/O scheduled on unopened device\n");
return 0;
}
@@ -2641,7 +2601,7 @@ static int make_raw_rw_request(void)
raw_cmd->flags |= FD_RAW_WRITE;
COMMAND = FM_MODE(_floppy, FD_WRITE);
} else {
- DPRINT("make_raw_rw_request: unknown command\n");
+ DPRINT("%s: unknown command\n", __func__);
return 0;
}
@@ -2659,7 +2619,8 @@ static int make_raw_rw_request(void)
HEAD = fsector_t / _floppy->sect;
if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
- TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
+ test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
+ fsector_t < _floppy->sect)
max_sector = _floppy->sect;
/* 2M disks have phantom sectors on the first track */
@@ -2685,7 +2646,7 @@ static int make_raw_rw_request(void)
raw_cmd->track = TRACK << STRETCH(_floppy);
DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
GAP = _floppy->gap;
- CODE2SIZE;
+ ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
FD_SECTBASE(_floppy);
@@ -2730,8 +2691,10 @@ static int make_raw_rw_request(void)
}
} else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
if (CT(COMMAND) == FD_WRITE) {
- if (fsector_t + blk_rq_sectors(current_req) > ssize &&
- fsector_t + blk_rq_sectors(current_req) < ssize + ssize)
+ unsigned int sectors;
+
+ sectors = fsector_t + blk_rq_sectors(current_req);
+ if (sectors > ssize && sectors < ssize + ssize)
max_size = ssize + ssize;
else
max_size = ssize;
@@ -2752,12 +2715,10 @@ static int make_raw_rw_request(void)
* on a 64 bit machine!
*/
max_size = buffer_chain_size();
- dma_limit =
- (MAX_DMA_ADDRESS -
- ((unsigned long)current_req->buffer)) >> 9;
- if ((unsigned long)max_size > dma_limit) {
+ dma_limit = (MAX_DMA_ADDRESS -
+ ((unsigned long)current_req->buffer)) >> 9;
+ if ((unsigned long)max_size > dma_limit)
max_size = dma_limit;
- }
/* 64 kb boundaries */
if (CROSS_64KB(current_req->buffer, max_size << 9))
max_size = (K_64 -
@@ -2773,16 +2734,16 @@ static int make_raw_rw_request(void)
*/
if (!direct ||
(indirect * 2 > direct * 3 &&
- *errors < DP->max_errors.read_track && ((!probing
- || (DP->read_track & (1 << DRS->probed_format)))))) {
+ *errors < DP->max_errors.read_track &&
+ ((!probing ||
+ (DP->read_track & (1 << DRS->probed_format)))))) {
max_size = blk_rq_sectors(current_req);
} else {
raw_cmd->kernel_data = current_req->buffer;
raw_cmd->length = current_count_sectors << 9;
if (raw_cmd->length == 0) {
- DPRINT
- ("zero dma transfer attempted from make_raw_request\n");
- DPRINT("indirect=%d direct=%d fsector_t=%d",
+ DPRINT("%s: zero dma transfer attempted\n", __func__);
+ DPRINT("indirect=%d direct=%d fsector_t=%d\n",
indirect, direct, fsector_t);
return 0;
}
@@ -2802,25 +2763,22 @@ static int make_raw_rw_request(void)
((CT(COMMAND) == FD_READ ||
(!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
max_sector > 2 * max_buffer_sectors + buffer_min &&
- max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)
- /* not enough space */
- ) {
+ max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
+ /* not enough space */
buffer_track = -1;
buffer_drive = current_drive;
buffer_max = buffer_min = aligned_sector_t;
}
raw_cmd->kernel_data = floppy_track_buffer +
- ((aligned_sector_t - buffer_min) << 9);
+ ((aligned_sector_t - buffer_min) << 9);
if (CT(COMMAND) == FD_WRITE) {
/* copy write buffer to track buffer.
* if we get here, we know that the write
* is either aligned or the data already in the buffer
* (buffer will be overwritten) */
-#ifdef FLOPPY_SANITY_CHECK
if (in_sector_offset && buffer_track == -1)
DPRINT("internal error offset !=0 on write\n");
-#endif
buffer_track = raw_cmd->track;
buffer_drive = current_drive;
copy_buffer(ssize, max_sector,
@@ -2834,7 +2792,6 @@ static int make_raw_rw_request(void)
raw_cmd->length = in_sector_offset + current_count_sectors;
raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
raw_cmd->length <<= 9;
-#ifdef FLOPPY_SANITY_CHECK
if ((raw_cmd->length < current_count_sectors << 9) ||
(raw_cmd->kernel_data != current_req->buffer &&
CT(COMMAND) == FD_WRITE &&
@@ -2845,19 +2802,19 @@ static int make_raw_rw_request(void)
DPRINT("fractionary current count b=%lx s=%lx\n",
raw_cmd->length, current_count_sectors);
if (raw_cmd->kernel_data != current_req->buffer)
- printk("addr=%d, length=%ld\n",
- (int)((raw_cmd->kernel_data -
- floppy_track_buffer) >> 9),
- current_count_sectors);
- printk("st=%d ast=%d mse=%d msi=%d\n",
- fsector_t, aligned_sector_t, max_sector, max_size);
- printk("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
- printk("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
- COMMAND, SECTOR, HEAD, TRACK);
- printk("buffer drive=%d\n", buffer_drive);
- printk("buffer track=%d\n", buffer_track);
- printk("buffer_min=%d\n", buffer_min);
- printk("buffer_max=%d\n", buffer_max);
+ pr_info("addr=%d, length=%ld\n",
+ (int)((raw_cmd->kernel_data -
+ floppy_track_buffer) >> 9),
+ current_count_sectors);
+ pr_info("st=%d ast=%d mse=%d msi=%d\n",
+ fsector_t, aligned_sector_t, max_sector, max_size);
+ pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
+ pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
+ COMMAND, SECTOR, HEAD, TRACK);
+ pr_info("buffer drive=%d\n", buffer_drive);
+ pr_info("buffer track=%d\n", buffer_track);
+ pr_info("buffer_min=%d\n", buffer_min);
+ pr_info("buffer_max=%d\n", buffer_max);
return 0;
}
@@ -2868,14 +2825,14 @@ static int make_raw_rw_request(void)
raw_cmd->kernel_data + raw_cmd->length >
floppy_track_buffer + (max_buffer_sectors << 10)) {
DPRINT("buffer overrun in schedule dma\n");
- printk("fsector_t=%d buffer_min=%d current_count=%ld\n",
- fsector_t, buffer_min, raw_cmd->length >> 9);
- printk("current_count_sectors=%ld\n",
- current_count_sectors);
+ pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
+ fsector_t, buffer_min, raw_cmd->length >> 9);
+ pr_info("current_count_sectors=%ld\n",
+ current_count_sectors);
if (CT(COMMAND) == FD_READ)
- printk("read\n");
+ pr_info("read\n");
if (CT(COMMAND) == FD_WRITE)
- printk("write\n");
+ pr_info("write\n");
return 0;
}
} else if (raw_cmd->length > blk_rq_bytes(current_req) ||
@@ -2884,14 +2841,13 @@ static int make_raw_rw_request(void)
return 0;
} else if (raw_cmd->length < current_count_sectors << 9) {
DPRINT("more sectors than bytes\n");
- printk("bytes=%ld\n", raw_cmd->length >> 9);
- printk("sectors=%ld\n", current_count_sectors);
+ pr_info("bytes=%ld\n", raw_cmd->length >> 9);
+ pr_info("sectors=%ld\n", current_count_sectors);
}
if (raw_cmd->length == 0) {
DPRINT("zero dma transfer attempted from make_raw_request\n");
return 0;
}
-#endif
virtualdmabug_workaround();
return 2;
@@ -2899,7 +2855,6 @@ static int make_raw_rw_request(void)
static void redo_fd_request(void)
{
-#define REPEAT {request_done(0); continue; }
int drive;
int tmp;
@@ -2907,63 +2862,63 @@ static void redo_fd_request(void)
if (current_drive < N_DRIVE)
floppy_off(current_drive);
- for (;;) {
- if (!current_req) {
- struct request *req;
-
- spin_lock_irq(floppy_queue->queue_lock);
- req = blk_fetch_request(floppy_queue);
- spin_unlock_irq(floppy_queue->queue_lock);
- if (!req) {
- do_floppy = NULL;
- unlock_fdc();
- return;
- }
- current_req = req;
- }
- drive = (long)current_req->rq_disk->private_data;
- set_fdc(drive);
- reschedule_timeout(current_reqD, "redo fd request", 0);
+do_request:
+ if (!current_req) {
+ struct request *req;
- set_floppy(drive);
- raw_cmd = &default_raw_cmd;
- raw_cmd->flags = 0;
- if (start_motor(redo_fd_request))
+ spin_lock_irq(floppy_queue->queue_lock);
+ req = blk_fetch_request(floppy_queue);
+ spin_unlock_irq(floppy_queue->queue_lock);
+ if (!req) {
+ do_floppy = NULL;
+ unlock_fdc();
return;
- disk_change(current_drive);
- if (test_bit(current_drive, &fake_change) ||
- TESTF(FD_DISK_CHANGED)) {
- DPRINT("disk absent or changed during operation\n");
- REPEAT;
- }
- if (!_floppy) { /* Autodetection */
- if (!probing) {
- DRS->probed_format = 0;
- if (next_valid_format()) {
- DPRINT("no autodetectable formats\n");
- _floppy = NULL;
- REPEAT;
- }
- }
- probing = 1;
- _floppy =
- floppy_type + DP->autodetect[DRS->probed_format];
- } else
- probing = 0;
- errors = &(current_req->errors);
- tmp = make_raw_rw_request();
- if (tmp < 2) {
- request_done(tmp);
- continue;
}
+ current_req = req;
+ }
+ drive = (long)current_req->rq_disk->private_data;
+ set_fdc(drive);
+ reschedule_timeout(current_reqD, "redo fd request");
- if (TESTF(FD_NEED_TWADDLE))
- twaddle();
- schedule_bh(floppy_start);
- debugt("queue fd request");
+ set_floppy(drive);
+ raw_cmd = &default_raw_cmd;
+ raw_cmd->flags = 0;
+ if (start_motor(redo_fd_request))
return;
+
+ disk_change(current_drive);
+ if (test_bit(current_drive, &fake_change) ||
+ test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
+ DPRINT("disk absent or changed during operation\n");
+ request_done(0);
+ goto do_request;
+ }
+ if (!_floppy) { /* Autodetection */
+ if (!probing) {
+ DRS->probed_format = 0;
+ if (next_valid_format()) {
+ DPRINT("no autodetectable formats\n");
+ _floppy = NULL;
+ request_done(0);
+ goto do_request;
+ }
+ }
+ probing = 1;
+ _floppy = floppy_type + DP->autodetect[DRS->probed_format];
+ } else
+ probing = 0;
+ errors = &(current_req->errors);
+ tmp = make_raw_rw_request();
+ if (tmp < 2) {
+ request_done(tmp);
+ goto do_request;
}
-#undef REPEAT
+
+ if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
+ twaddle();
+ schedule_bh(floppy_start);
+ debugt(__func__, "queue fd request");
+ return;
}
static struct cont_t rw_cont = {
@@ -2979,30 +2934,30 @@ static void process_fd_request(void)
schedule_bh(redo_fd_request);
}
-static void do_fd_request(struct request_queue * q)
+static void do_fd_request(struct request_queue *q)
{
if (max_buffer_sectors == 0) {
- printk("VFS: do_fd_request called on non-open device\n");
+ pr_info("VFS: %s called on non-open device\n", __func__);
return;
}
if (usage_count == 0) {
- printk("warning: usage count=0, current_req=%p exiting\n",
- current_req);
- printk("sect=%ld type=%x flags=%x\n",
- (long)blk_rq_pos(current_req), current_req->cmd_type,
- current_req->cmd_flags);
+ pr_info("warning: usage count=0, current_req=%p exiting\n",
+ current_req);
+ pr_info("sect=%ld type=%x flags=%x\n",
+ (long)blk_rq_pos(current_req), current_req->cmd_type,
+ current_req->cmd_flags);
return;
}
if (test_bit(0, &fdc_busy)) {
/* fdc busy, this new request will be treated when the
current one is done */
- is_alive("do fd request, old request running");
+ is_alive(__func__, "old request running");
return;
}
- lock_fdc(MAXTIMEOUT, 0);
+ lock_fdc(MAXTIMEOUT, false);
process_fd_request();
- is_alive("do fd request");
+ is_alive(__func__, "");
}
static struct cont_t poll_cont = {
@@ -3012,24 +2967,18 @@ static struct cont_t poll_cont = {
.done = generic_done
};
-static int poll_drive(int interruptible, int flag)
+static int poll_drive(bool interruptible, int flag)
{
- int ret;
-
/* no auto-sense, just clear dcl */
raw_cmd = &default_raw_cmd;
raw_cmd->flags = flag;
raw_cmd->track = 0;
raw_cmd->cmd_count = 0;
cont = &poll_cont;
-#ifdef DCL_DEBUG
- if (DP->flags & FD_DEBUG) {
- DPRINT("setting NEWCHANGE in poll_drive\n");
- }
-#endif
- SETF(FD_DISK_NEWCHANGE);
- WAIT(floppy_ready);
- return ret;
+ debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
+ set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
+
+ return wait_til_done(floppy_ready, interruptible);
}
/*
@@ -3039,7 +2988,7 @@ static int poll_drive(int interruptible, int flag)
static void reset_intr(void)
{
- printk("weird, reset interrupt called\n");
+ pr_info("weird, reset interrupt called\n");
}
static struct cont_t reset_cont = {
@@ -3049,20 +2998,23 @@ static struct cont_t reset_cont = {
.done = generic_done
};
-static int user_reset_fdc(int drive, int arg, int interruptible)
+static int user_reset_fdc(int drive, int arg, bool interruptible)
{
int ret;
- ret = 0;
- LOCK_FDC(drive, interruptible);
+ if (lock_fdc(drive, interruptible))
+ return -EINTR;
+
if (arg == FD_RESET_ALWAYS)
FDCS->reset = 1;
if (FDCS->reset) {
cont = &reset_cont;
- WAIT(reset_fdc);
+ ret = wait_til_done(reset_fdc, interruptible);
+ if (ret == -EINTR)
+ return -EINTR;
}
process_fd_request();
- return ret;
+ return 0;
}
/*
@@ -3075,17 +3027,12 @@ static inline int fd_copyout(void __user *param, const void *address,
return copy_to_user(param, address, size) ? -EFAULT : 0;
}
-static inline int fd_copyin(void __user *param, void *address, unsigned long size)
+static inline int fd_copyin(void __user *param, void *address,
+ unsigned long size)
{
return copy_from_user(address, param, size) ? -EFAULT : 0;
}
-#define _COPYOUT(x) (copy_to_user((void __user *)param, &(x), sizeof(x)) ? -EFAULT : 0)
-#define _COPYIN(x) (copy_from_user(&(x), (void __user *)param, sizeof(x)) ? -EFAULT : 0)
-
-#define COPYOUT(x) ECALL(_COPYOUT(x))
-#define COPYIN(x) ECALL(_COPYIN(x))
-
static inline const char *drive_name(int type, int drive)
{
struct floppy_struct *floppy;
@@ -3156,23 +3103,29 @@ static struct cont_t raw_cmd_cont = {
.done = raw_cmd_done
};
-static inline int raw_cmd_copyout(int cmd, char __user *param,
+static inline int raw_cmd_copyout(int cmd, void __user *param,
struct floppy_raw_cmd *ptr)
{
int ret;
while (ptr) {
- COPYOUT(*ptr);
+ ret = copy_to_user(param, ptr, sizeof(*ptr));
+ if (ret)
+ return -EFAULT;
param += sizeof(struct floppy_raw_cmd);
if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
- if (ptr->length >= 0
- && ptr->length <= ptr->buffer_length)
- ECALL(fd_copyout
- (ptr->data, ptr->kernel_data,
- ptr->buffer_length - ptr->length));
+ if (ptr->length >= 0 &&
+ ptr->length <= ptr->buffer_length) {
+ long length = ptr->buffer_length - ptr->length;
+ ret = fd_copyout(ptr->data, ptr->kernel_data,
+ length);
+ if (ret)
+ return ret;
+ }
}
ptr = ptr->next;
}
+
return 0;
}
@@ -3195,7 +3148,7 @@ static void raw_cmd_free(struct floppy_raw_cmd **ptr)
}
}
-static inline int raw_cmd_copyin(int cmd, char __user *param,
+static inline int raw_cmd_copyin(int cmd, void __user *param,
struct floppy_raw_cmd **rcmd)
{
struct floppy_raw_cmd *ptr;
@@ -3203,17 +3156,19 @@ static inline int raw_cmd_copyin(int cmd, char __user *param,
int i;
*rcmd = NULL;
- while (1) {
- ptr = (struct floppy_raw_cmd *)
- kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
- if (!ptr)
- return -ENOMEM;
- *rcmd = ptr;
- COPYIN(*ptr);
- ptr->next = NULL;
- ptr->buffer_length = 0;
- param += sizeof(struct floppy_raw_cmd);
- if (ptr->cmd_count > 33)
+
+loop:
+ ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
+ if (!ptr)
+ return -ENOMEM;
+ *rcmd = ptr;
+ ret = copy_from_user(ptr, param, sizeof(*ptr));
+ if (ret)
+ return -EFAULT;
+ ptr->next = NULL;
+ ptr->buffer_length = 0;
+ param += sizeof(struct floppy_raw_cmd);
+ if (ptr->cmd_count > 33)
/* the command may now also take up the space
* initially intended for the reply & the
* reply count. Needed for long 82078 commands
@@ -3222,31 +3177,35 @@ static inline int raw_cmd_copyin(int cmd, char __user *param,
* 16 bytes for a structure, you'll one day
* discover that you really need 17...
*/
+ return -EINVAL;
+
+ for (i = 0; i < 16; i++)
+ ptr->reply[i] = 0;
+ ptr->resultcode = 0;
+ ptr->kernel_data = NULL;
+
+ if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
+ if (ptr->length <= 0)
return -EINVAL;
+ ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
+ fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
+ if (!ptr->kernel_data)
+ return -ENOMEM;
+ ptr->buffer_length = ptr->length;
+ }
+ if (ptr->flags & FD_RAW_WRITE) {
+ ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
+ if (ret)
+ return ret;
+ }
- for (i = 0; i < 16; i++)
- ptr->reply[i] = 0;
- ptr->resultcode = 0;
- ptr->kernel_data = NULL;
-
- if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
- if (ptr->length <= 0)
- return -EINVAL;
- ptr->kernel_data =
- (char *)fd_dma_mem_alloc(ptr->length);
- fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
- if (!ptr->kernel_data)
- return -ENOMEM;
- ptr->buffer_length = ptr->length;
- }
- if (ptr->flags & FD_RAW_WRITE)
- ECALL(fd_copyin(ptr->data, ptr->kernel_data,
- ptr->length));
+ if (ptr->flags & FD_RAW_MORE) {
rcmd = &(ptr->next);
- if (!(ptr->flags & FD_RAW_MORE))
- return 0;
ptr->rate &= 0x43;
+ goto loop;
}
+
+ return 0;
}
static int raw_cmd_ioctl(int cmd, void __user *param)
@@ -3283,12 +3242,8 @@ static int raw_cmd_ioctl(int cmd, void __user *param)
raw_cmd = my_raw_cmd;
cont = &raw_cmd_cont;
- ret = wait_til_done(floppy_start, 1);
-#ifdef DCL_DEBUG
- if (DP->flags & FD_DEBUG) {
- DPRINT("calling disk change from raw_cmd ioctl\n");
- }
-#endif
+ ret = wait_til_done(floppy_start, true);
+ debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
if (ret != -EINTR && FDCS->reset)
ret = -EIO;
@@ -3327,7 +3282,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
mutex_lock(&open_lock);
- if (lock_fdc(drive, 1)) {
+ if (lock_fdc(drive, true)) {
mutex_unlock(&open_lock);
return -EINTR;
}
@@ -3346,11 +3301,15 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
mutex_unlock(&open_lock);
} else {
int oldStretch;
- LOCK_FDC(drive, 1);
- if (cmd != FDDEFPRM)
+
+ if (lock_fdc(drive, true))
+ return -EINTR;
+ if (cmd != FDDEFPRM) {
/* notice a disk change immediately, else
* we lose our settings immediately*/
- CALL(poll_drive(1, FD_RAW_NEED_DISK));
+ if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
+ return -EINTR;
+ }
oldStretch = g->stretch;
user_params[drive] = *g;
if (buffer_drive == drive)
@@ -3415,7 +3374,7 @@ static inline int normalize_ioctl(int *cmd, int *size)
*size = _IOC_SIZE(*cmd);
*cmd = ioctl_table[i];
if (*size > _IOC_SIZE(*cmd)) {
- printk("ioctl not yet supported\n");
+ pr_info("ioctl not yet supported\n");
return -EFAULT;
}
return 0;
@@ -3429,8 +3388,10 @@ static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
if (type)
*g = &floppy_type[type];
else {
- LOCK_FDC(drive, 0);
- CALL(poll_drive(0, 0));
+ if (lock_fdc(drive, false))
+ return -EINTR;
+ if (poll_drive(false, 0) == -EINTR)
+ return -EINTR;
process_fd_request();
*g = current_type[drive];
}
@@ -3459,10 +3420,6 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
unsigned long param)
{
-#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
-#define OUT(c,x) case c: outparam = (const char *) (x); break
-#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
-
int drive = (long)bdev->bd_disk->private_data;
int type = ITYPE(UDRS->fd_device);
int i;
@@ -3474,26 +3431,28 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
struct floppy_max_errors max_errors;
struct floppy_drive_params dp;
} inparam; /* parameters coming from user space */
- const char *outparam; /* parameters passed back to user space */
+ const void *outparam; /* parameters passed back to user space */
/* convert compatibility eject ioctls into floppy eject ioctl.
* We do this in order to provide a means to eject floppy disks before
* installing the new fdutils package */
if (cmd == CDROMEJECT || /* CD-ROM eject */
- cmd == 0x6470 /* SunOS floppy eject */ ) {
+ cmd == 0x6470) { /* SunOS floppy eject */
DPRINT("obsolete eject ioctl\n");
DPRINT("please use floppycontrol --eject\n");
cmd = FDEJECT;
}
- /* convert the old style command into a new style command */
- if ((cmd & 0xff00) == 0x0200) {
- ECALL(normalize_ioctl(&cmd, &size));
- } else
+ if (!((cmd & 0xff00) == 0x0200))
return -EINVAL;
+ /* convert the old style command into a new style command */
+ ret = normalize_ioctl(&cmd, &size);
+ if (ret)
+ return ret;
+
/* permission checks */
- if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
+ if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
return -EPERM;
@@ -3501,129 +3460,142 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
return -EINVAL;
/* copyin */
- CLEARSTRUCT(&inparam);
- if (_IOC_DIR(cmd) & _IOC_WRITE)
- ECALL(fd_copyin((void __user *)param, &inparam, size))
-
- switch (cmd) {
- case FDEJECT:
- if (UDRS->fd_ref != 1)
- /* somebody else has this drive open */
- return -EBUSY;
- LOCK_FDC(drive, 1);
-
- /* do the actual eject. Fails on
- * non-Sparc architectures */
- ret = fd_eject(UNIT(drive));
-
- USETF(FD_DISK_CHANGED);
- USETF(FD_VERIFY);
- process_fd_request();
+ memset(&inparam, 0, sizeof(inparam));
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ ret = fd_copyin((void __user *)param, &inparam, size);
+ if (ret)
return ret;
- case FDCLRPRM:
- LOCK_FDC(drive, 1);
- current_type[drive] = NULL;
- floppy_sizes[drive] = MAX_DISK_SIZE << 1;
- UDRS->keep_data = 0;
- return invalidate_drive(bdev);
- case FDSETPRM:
- case FDDEFPRM:
- return set_geometry(cmd, &inparam.g,
- drive, type, bdev);
- case FDGETPRM:
- ECALL(get_floppy_geometry(drive, type,
- (struct floppy_struct **)
- &outparam));
- break;
-
- case FDMSGON:
- UDP->flags |= FTD_MSG;
- return 0;
- case FDMSGOFF:
- UDP->flags &= ~FTD_MSG;
- return 0;
-
- case FDFMTBEG:
- LOCK_FDC(drive, 1);
- CALL(poll_drive(1, FD_RAW_NEED_DISK));
- ret = UDRS->flags;
- process_fd_request();
- if (ret & FD_VERIFY)
- return -ENODEV;
- if (!(ret & FD_DISK_WRITABLE))
- return -EROFS;
- return 0;
- case FDFMTTRK:
- if (UDRS->fd_ref != 1)
- return -EBUSY;
- return do_format(drive, &inparam.f);
- case FDFMTEND:
- case FDFLUSH:
- LOCK_FDC(drive, 1);
- return invalidate_drive(bdev);
-
- case FDSETEMSGTRESH:
- UDP->max_errors.reporting =
- (unsigned short)(param & 0x0f);
- return 0;
- OUT(FDGETMAXERRS, &UDP->max_errors);
- IN(FDSETMAXERRS, &UDP->max_errors, max_errors);
-
- case FDGETDRVTYP:
- outparam = drive_name(type, drive);
- SUPBOUND(size, strlen(outparam) + 1);
- break;
-
- IN(FDSETDRVPRM, UDP, dp);
- OUT(FDGETDRVPRM, UDP);
-
- case FDPOLLDRVSTAT:
- LOCK_FDC(drive, 1);
- CALL(poll_drive(1, FD_RAW_NEED_DISK));
- process_fd_request();
- /* fall through */
- OUT(FDGETDRVSTAT, UDRS);
-
- case FDRESET:
- return user_reset_fdc(drive, (int)param, 1);
-
- OUT(FDGETFDCSTAT, UFDCS);
+ }
- case FDWERRORCLR:
- CLEARSTRUCT(UDRWE);
- return 0;
- OUT(FDWERRORGET, UDRWE);
-
- case FDRAWCMD:
- if (type)
- return -EINVAL;
- LOCK_FDC(drive, 1);
- set_floppy(drive);
- CALL(i = raw_cmd_ioctl(cmd, (void __user *)param));
- process_fd_request();
- return i;
+ switch (cmd) {
+ case FDEJECT:
+ if (UDRS->fd_ref != 1)
+ /* somebody else has this drive open */
+ return -EBUSY;
+ if (lock_fdc(drive, true))
+ return -EINTR;
- case FDTWADDLE:
- LOCK_FDC(drive, 1);
- twaddle();
- process_fd_request();
- return 0;
+ /* do the actual eject. Fails on
+ * non-Sparc architectures */
+ ret = fd_eject(UNIT(drive));
- default:
+ set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
+ set_bit(FD_VERIFY_BIT, &UDRS->flags);
+ process_fd_request();
+ return ret;
+ case FDCLRPRM:
+ if (lock_fdc(drive, true))
+ return -EINTR;
+ current_type[drive] = NULL;
+ floppy_sizes[drive] = MAX_DISK_SIZE << 1;
+ UDRS->keep_data = 0;
+ return invalidate_drive(bdev);
+ case FDSETPRM:
+ case FDDEFPRM:
+ return set_geometry(cmd, &inparam.g, drive, type, bdev);
+ case FDGETPRM:
+ ret = get_floppy_geometry(drive, type,
+ (struct floppy_struct **)&outparam);
+ if (ret)
+ return ret;
+ break;
+ case FDMSGON:
+ UDP->flags |= FTD_MSG;
+ return 0;
+ case FDMSGOFF:
+ UDP->flags &= ~FTD_MSG;
+ return 0;
+ case FDFMTBEG:
+ if (lock_fdc(drive, true))
+ return -EINTR;
+ if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
+ return -EINTR;
+ ret = UDRS->flags;
+ process_fd_request();
+ if (ret & FD_VERIFY)
+ return -ENODEV;
+ if (!(ret & FD_DISK_WRITABLE))
+ return -EROFS;
+ return 0;
+ case FDFMTTRK:
+ if (UDRS->fd_ref != 1)
+ return -EBUSY;
+ return do_format(drive, &inparam.f);
+ case FDFMTEND:
+ case FDFLUSH:
+ if (lock_fdc(drive, true))
+ return -EINTR;
+ return invalidate_drive(bdev);
+ case FDSETEMSGTRESH:
+ UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
+ return 0;
+ case FDGETMAXERRS:
+ outparam = &UDP->max_errors;
+ break;
+ case FDSETMAXERRS:
+ UDP->max_errors = inparam.max_errors;
+ break;
+ case FDGETDRVTYP:
+ outparam = drive_name(type, drive);
+ SUPBOUND(size, strlen((const char *)outparam) + 1);
+ break;
+ case FDSETDRVPRM:
+ *UDP = inparam.dp;
+ break;
+ case FDGETDRVPRM:
+ outparam = UDP;
+ break;
+ case FDPOLLDRVSTAT:
+ if (lock_fdc(drive, true))
+ return -EINTR;
+ if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
+ return -EINTR;
+ process_fd_request();
+ /* fall through */
+ case FDGETDRVSTAT:
+ outparam = UDRS;
+ break;
+ case FDRESET:
+ return user_reset_fdc(drive, (int)param, true);
+ case FDGETFDCSTAT:
+ outparam = UFDCS;
+ break;
+ case FDWERRORCLR:
+ memset(UDRWE, 0, sizeof(*UDRWE));
+ return 0;
+ case FDWERRORGET:
+ outparam = UDRWE;
+ break;
+ case FDRAWCMD:
+ if (type)
return -EINVAL;
- }
+ if (lock_fdc(drive, true))
+ return -EINTR;
+ set_floppy(drive);
+ i = raw_cmd_ioctl(cmd, (void __user *)param);
+ if (i == -EINTR)
+ return -EINTR;
+ process_fd_request();
+ return i;
+ case FDTWADDLE:
+ if (lock_fdc(drive, true))
+ return -EINTR;
+ twaddle();
+ process_fd_request();
+ return 0;
+ default:
+ return -EINVAL;
+ }
if (_IOC_DIR(cmd) & _IOC_READ)
return fd_copyout((void __user *)param, outparam, size);
- else
- return 0;
-#undef OUT
-#undef IN
+
+ return 0;
}
static void __init config_types(void)
{
- int first = 1;
+ bool has_drive = false;
int drive;
/* read drive info out of physical CMOS */
@@ -3655,17 +3627,22 @@ static void __init config_types(void)
name = temparea;
}
if (name) {
- const char *prepend = ",";
- if (first) {
- prepend = KERN_INFO "Floppy drive(s):";
- first = 0;
+ const char *prepend;
+ if (!has_drive) {
+ prepend = "";
+ has_drive = true;
+ pr_info("Floppy drive(s):");
+ } else {
+ prepend = ",";
}
- printk("%s fd%d is %s", prepend, drive, name);
+
+ pr_cont("%s fd%d is %s", prepend, drive, name);
}
*UDP = *params;
}
- if (!first)
- printk("\n");
+
+ if (has_drive)
+ pr_cont("\n");
}
static int floppy_release(struct gendisk *disk, fmode_t mode)
@@ -3705,8 +3682,8 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
goto out2;
if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
- USETF(FD_DISK_CHANGED);
- USETF(FD_VERIFY);
+ set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
+ set_bit(FD_VERIFY_BIT, &UDRS->flags);
}
if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
@@ -3735,9 +3712,8 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
INFBOUND(try, 16);
tmp = (char *)fd_dma_mem_alloc(1024 * try);
}
- if (!tmp && !floppy_track_buffer) {
+ if (!tmp && !floppy_track_buffer)
fallback_on_nodma_alloc(&tmp, 2048 * try);
- }
if (!tmp && !floppy_track_buffer) {
DPRINT("Unable to allocate DMA memory\n");
goto out;
@@ -3767,11 +3743,12 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
if (mode & (FMODE_READ|FMODE_WRITE)) {
UDRS->last_checked = 0;
check_disk_change(bdev);
- if (UTESTF(FD_DISK_CHANGED))
+ if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
goto out;
}
res = -EROFS;
- if ((mode & FMODE_WRITE) && !(UTESTF(FD_DISK_WRITABLE)))
+ if ((mode & FMODE_WRITE) &&
+ !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
goto out;
}
mutex_unlock(&open_lock);
@@ -3795,17 +3772,18 @@ static int check_floppy_change(struct gendisk *disk)
{
int drive = (long)disk->private_data;
- if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
+ if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
+ test_bit(FD_VERIFY_BIT, &UDRS->flags))
return 1;
if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
- lock_fdc(drive, 0);
- poll_drive(0, 0);
+ lock_fdc(drive, false);
+ poll_drive(false, 0);
process_fd_request();
}
- if (UTESTF(FD_DISK_CHANGED) ||
- UTESTF(FD_VERIFY) ||
+ if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
+ test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
test_bit(drive, &fake_change) ||
(!ITYPE(UDRS->fd_device) && !current_type[drive]))
return 1;
@@ -3818,8 +3796,7 @@ static int check_floppy_change(struct gendisk *disk)
* a disk in the drive, and whether that disk is writable.
*/
-static void floppy_rb0_complete(struct bio *bio,
- int err)
+static void floppy_rb0_complete(struct bio *bio, int err)
{
complete((struct completion *)bio->bi_private);
}
@@ -3877,14 +3854,16 @@ static int floppy_revalidate(struct gendisk *disk)
int cf;
int res = 0;
- if (UTESTF(FD_DISK_CHANGED) ||
- UTESTF(FD_VERIFY) || test_bit(drive, &fake_change) || NO_GEOM) {
+ if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
+ test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
+ test_bit(drive, &fake_change) || NO_GEOM) {
if (usage_count == 0) {
- printk("VFS: revalidate called on non-open device.\n");
+ pr_info("VFS: revalidate called on non-open device.\n");
return -EFAULT;
}
- lock_fdc(drive, 0);
- cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
+ lock_fdc(drive, false);
+ cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
+ test_bit(FD_VERIFY_BIT, &UDRS->flags));
if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
process_fd_request(); /*already done by another thread */
return 0;
@@ -3894,7 +3873,7 @@ static int floppy_revalidate(struct gendisk *disk)
if (buffer_drive == drive)
buffer_track = -1;
clear_bit(drive, &fake_change);
- UCLEARF(FD_DISK_CHANGED);
+ clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
if (cf)
UDRS->generation++;
if (NO_GEOM) {
@@ -3902,7 +3881,7 @@ static int floppy_revalidate(struct gendisk *disk)
res = __floppy_read_block_0(opened_bdev[drive]);
} else {
if (cf)
- poll_drive(0, FD_RAW_NEED_DISK);
+ poll_drive(false, FD_RAW_NEED_DISK);
process_fd_request();
}
}
@@ -3934,21 +3913,21 @@ static char __init get_fdc_version(void)
output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
if (FDCS->reset)
return FDC_NONE;
- if ((r = result()) <= 0x00)
+ r = result();
+ if (r <= 0x00)
return FDC_NONE; /* No FDC present ??? */
if ((r == 1) && (reply_buffer[0] == 0x80)) {
- printk(KERN_INFO "FDC %d is an 8272A\n", fdc);
+ pr_info("FDC %d is an 8272A\n", fdc);
return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
}
if (r != 10) {
- printk
- ("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
- fdc, r);
+ pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
+ fdc, r);
return FDC_UNKNOWN;
}
if (!fdc_configure()) {
- printk(KERN_INFO "FDC %d is an 82072\n", fdc);
+ pr_info("FDC %d is an 82072\n", fdc);
return FDC_82072; /* 82072 doesn't know CONFIGURE */
}
@@ -3956,52 +3935,50 @@ static char __init get_fdc_version(void)
if (need_more_output() == MORE_OUTPUT) {
output_byte(0);
} else {
- printk(KERN_INFO "FDC %d is an 82072A\n", fdc);
+ pr_info("FDC %d is an 82072A\n", fdc);
return FDC_82072A; /* 82072A as found on Sparcs. */
}
output_byte(FD_UNLOCK);
r = result();
if ((r == 1) && (reply_buffer[0] == 0x80)) {
- printk(KERN_INFO "FDC %d is a pre-1991 82077\n", fdc);
- return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
+ pr_info("FDC %d is a pre-1991 82077\n", fdc);
+ return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
* LOCK/UNLOCK */
}
if ((r != 1) || (reply_buffer[0] != 0x00)) {
- printk("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
- fdc, r);
+ pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
+ fdc, r);
return FDC_UNKNOWN;
}
output_byte(FD_PARTID);
r = result();
if (r != 1) {
- printk("FDC %d init: PARTID: unexpected return of %d bytes.\n",
- fdc, r);
+ pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
+ fdc, r);
return FDC_UNKNOWN;
}
if (reply_buffer[0] == 0x80) {
- printk(KERN_INFO "FDC %d is a post-1991 82077\n", fdc);
+ pr_info("FDC %d is a post-1991 82077\n", fdc);
return FDC_82077; /* Revised 82077AA passes all the tests */
}
switch (reply_buffer[0] >> 5) {
case 0x0:
/* Either a 82078-1 or a 82078SL running at 5Volt */
- printk(KERN_INFO "FDC %d is an 82078.\n", fdc);
+ pr_info("FDC %d is an 82078.\n", fdc);
return FDC_82078;
case 0x1:
- printk(KERN_INFO "FDC %d is a 44pin 82078\n", fdc);
+ pr_info("FDC %d is a 44pin 82078\n", fdc);
return FDC_82078;
case 0x2:
- printk(KERN_INFO "FDC %d is a S82078B\n", fdc);
+ pr_info("FDC %d is a S82078B\n", fdc);
return FDC_S82078B;
case 0x3:
- printk(KERN_INFO "FDC %d is a National Semiconductor PC87306\n",
- fdc);
+ pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
return FDC_87306;
default:
- printk(KERN_INFO
- "FDC %d init: 82078 variant with unknown PARTID=%d.\n",
- fdc, reply_buffer[0] >> 5);
+ pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
+ fdc, reply_buffer[0] >> 5);
return FDC_82078_UNKN;
}
} /* get_fdc_version */
@@ -4113,9 +4090,9 @@ static int __init floppy_setup(char *str)
else
param = config_params[i].def_param;
if (config_params[i].fn)
- config_params[i].
- fn(ints, param,
- config_params[i].param2);
+ config_params[i].fn(ints, param,
+ config_params[i].
+ param2);
if (config_params[i].var) {
DPRINT("%s=%d\n", str, param);
*config_params[i].var = param;
@@ -4129,8 +4106,8 @@ static int __init floppy_setup(char *str)
DPRINT("allowed options are:");
for (i = 0; i < ARRAY_SIZE(config_params); i++)
- printk(" %s", config_params[i].name);
- printk("\n");
+ pr_cont(" %s", config_params[i].name);
+ pr_cont("\n");
} else
DPRINT("botched floppy option\n");
DPRINT("Read Documentation/blockdev/floppy.txt\n");
@@ -4148,7 +4125,8 @@ static ssize_t floppy_cmos_show(struct device *dev,
drive = p->id;
return sprintf(buf, "%X\n", UDP->cmos);
}
-DEVICE_ATTR(cmos,S_IRUGO,floppy_cmos_show,NULL);
+
+DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
static void floppy_device_release(struct device *dev)
{
@@ -4160,7 +4138,7 @@ static int floppy_resume(struct device *dev)
for (fdc = 0; fdc < N_FDC; fdc++)
if (FDCS->address != -1)
- user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
+ user_reset_fdc(-1, FD_RESET_ALWAYS, false);
return 0;
}
@@ -4172,8 +4150,8 @@ static const struct dev_pm_ops floppy_pm_ops = {
static struct platform_driver floppy_driver = {
.driver = {
- .name = "floppy",
- .pm = &floppy_pm_ops,
+ .name = "floppy",
+ .pm = &floppy_pm_ops,
},
};
@@ -4234,7 +4212,7 @@ static int __init floppy_init(void)
err = -ENOMEM;
goto out_unreg_driver;
}
- blk_queue_max_sectors(floppy_queue, 64);
+ blk_queue_max_hw_sectors(floppy_queue, 64);
blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
floppy_find, NULL, NULL);
@@ -4245,16 +4223,16 @@ static int __init floppy_init(void)
else
floppy_sizes[i] = MAX_DISK_SIZE << 1;
- reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
+ reschedule_timeout(MAXTIMEOUT, "floppy init");
config_types();
for (i = 0; i < N_FDC; i++) {
fdc = i;
- CLEARSTRUCT(FDCS);
+ memset(FDCS, 0, sizeof(*FDCS));
FDCS->dtr = -1;
FDCS->dor = 0x4;
#if defined(__sparc__) || defined(__mc68000__)
- /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
+ /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
#ifdef __mc68000__
if (MACH_IS_SUN3X)
#endif
@@ -4283,11 +4261,11 @@ static int __init floppy_init(void)
/* initialise drive state */
for (drive = 0; drive < N_DRIVE; drive++) {
- CLEARSTRUCT(UDRS);
- CLEARSTRUCT(UDRWE);
- USETF(FD_DISK_NEWCHANGE);
- USETF(FD_DISK_CHANGED);
- USETF(FD_VERIFY);
+ memset(UDRS, 0, sizeof(*UDRS));
+ memset(UDRWE, 0, sizeof(*UDRWE));
+ set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
+ set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
+ set_bit(FD_VERIFY_BIT, &UDRS->flags);
UDRS->fd_device = -1;
floppy_track_buffer = NULL;
max_buffer_sectors = 0;
@@ -4307,7 +4285,7 @@ static int __init floppy_init(void)
if (FDCS->address == -1)
continue;
FDCS->rawcmd = 2;
- if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
+ if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
/* free ioports reserved by floppy_grab_irq_and_dma() */
floppy_release_regions(fdc);
FDCS->address = -1;
@@ -4330,12 +4308,12 @@ static int __init floppy_init(void)
* properly, so force a reset for the standard FDC clones,
* to avoid interrupt garbage.
*/
- user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
+ user_reset_fdc(-1, FD_RESET_ALWAYS, false);
}
fdc = 0;
del_timer(&fd_timeout);
current_drive = 0;
- initialising = 0;
+ initialized = true;
if (have_no_fdc) {
DPRINT("no floppy controllers found\n");
err = have_no_fdc;
@@ -4356,7 +4334,8 @@ static int __init floppy_init(void)
if (err)
goto out_flush_work;
- err = device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
+ err = device_create_file(&floppy_device[drive].dev,
+ &dev_attr_cmos);
if (err)
goto out_unreg_platform_dev;
@@ -4420,8 +4399,10 @@ static int floppy_request_regions(int fdc)
const struct io_region *p;
for (p = io_regions; p < ARRAY_END(io_regions); p++) {
- if (!request_region(FDCS->address + p->offset, p->size, "floppy")) {
- DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + p->offset);
+ if (!request_region(FDCS->address + p->offset,
+ p->size, "floppy")) {
+ DPRINT("Floppy io-port 0x%04lx in use\n",
+ FDCS->address + p->offset);
floppy_release_allocated_regions(fdc, p);
return -EBUSY;
}
@@ -4512,11 +4493,9 @@ cleanup:
static void floppy_release_irq_and_dma(void)
{
int old_fdc;
-#ifdef FLOPPY_SANITY_CHECK
#ifndef __sparc__
int drive;
#endif
-#endif
long tmpsize;
unsigned long tmpaddr;
unsigned long flags;
@@ -4547,20 +4526,18 @@ static void floppy_release_irq_and_dma(void)
buffer_min = buffer_max = -1;
fd_dma_mem_free(tmpaddr, tmpsize);
}
-#ifdef FLOPPY_SANITY_CHECK
#ifndef __sparc__
for (drive = 0; drive < N_FDC * 4; drive++)
if (timer_pending(motor_off_timer + drive))
- printk("motor off timer %d still active\n", drive);
+ pr_info("motor off timer %d still active\n", drive);
#endif
if (timer_pending(&fd_timeout))
- printk("floppy timer still active:%s\n", timeout_message);
+ pr_info("floppy timer still active:%s\n", timeout_message);
if (timer_pending(&fd_timer))
- printk("auxiliary floppy timer still active\n");
+ pr_info("auxiliary floppy timer still active\n");
if (work_pending(&floppy_work))
- printk("work still pending\n");
-#endif
+ pr_info("work still pending\n");
old_fdc = fdc;
for (fdc = 0; fdc < N_FDC; fdc++)
if (FDCS->address != -1)
@@ -4577,7 +4554,9 @@ static void __init parse_floppy_cfg_string(char *cfg)
char *ptr;
while (*cfg) {
- for (ptr = cfg; *cfg && *cfg != ' ' && *cfg != '\t'; cfg++) ;
+ ptr = cfg;
+ while (*cfg && *cfg != ' ' && *cfg != '\t')
+ cfg++;
if (*cfg) {
*cfg = '\0';
cfg++;
@@ -4625,6 +4604,7 @@ static void __exit floppy_module_exit(void)
/* eject disk, if any */
fd_eject(0);
}
+
module_exit(floppy_module_exit);
module_param(floppy, charp, 0);
@@ -4636,9 +4616,10 @@ MODULE_LICENSE("GPL");
/* This doesn't actually get used other than for module information */
static const struct pnp_device_id floppy_pnpids[] = {
- { "PNP0700", 0 },
- { }
+ {"PNP0700", 0},
+ {}
};
+
MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
#else
diff --git a/drivers/block/hd.c b/drivers/block/hd.c
index d5cdce08ffd2..5116c65c07cb 100644
--- a/drivers/block/hd.c
+++ b/drivers/block/hd.c
@@ -719,7 +719,7 @@ static int __init hd_init(void)
return -ENOMEM;
}
- blk_queue_max_sectors(hd_queue, 255);
+ blk_queue_max_hw_sectors(hd_queue, 255);
init_timer(&device_timer);
device_timer.function = hd_times_out;
blk_queue_logical_block_size(hd_queue, 512);
diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c
index 02b2583df7fc..5416c9a606e4 100644
--- a/drivers/block/mg_disk.c
+++ b/drivers/block/mg_disk.c
@@ -980,7 +980,7 @@ static int mg_probe(struct platform_device *plat_dev)
__func__, __LINE__);
goto probe_err_6;
}
- blk_queue_max_sectors(host->breq, MG_MAX_SECTS);
+ blk_queue_max_hw_sectors(host->breq, MG_MAX_SECTS);
blk_queue_logical_block_size(host->breq, MG_SECTOR_SIZE);
init_timer(&host->timer);
diff --git a/drivers/block/osdblk.c b/drivers/block/osdblk.c
index a808b1530b3b..eb2091aa1c19 100644
--- a/drivers/block/osdblk.c
+++ b/drivers/block/osdblk.c
@@ -476,7 +476,9 @@ static void class_osdblk_release(struct class *cls)
kfree(cls);
}
-static ssize_t class_osdblk_list(struct class *c, char *data)
+static ssize_t class_osdblk_list(struct class *c,
+ struct class_attribute *attr,
+ char *data)
{
int n = 0;
struct list_head *tmp;
@@ -500,7 +502,9 @@ static ssize_t class_osdblk_list(struct class *c, char *data)
return n;
}
-static ssize_t class_osdblk_add(struct class *c, const char *buf, size_t count)
+static ssize_t class_osdblk_add(struct class *c,
+ struct class_attribute *attr,
+ const char *buf, size_t count)
{
struct osdblk_device *osdev;
ssize_t rc;
@@ -592,7 +596,9 @@ err_out_mod:
return rc;
}
-static ssize_t class_osdblk_remove(struct class *c, const char *buf,
+static ssize_t class_osdblk_remove(struct class *c,
+ struct class_attribute *attr,
+ const char *buf,
size_t count)
{
struct osdblk_device *osdev = NULL;
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 569e39e8f114..e712cd51af15 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -906,7 +906,7 @@ static int __init pd_init(void)
if (!pd_queue)
goto out1;
- blk_queue_max_sectors(pd_queue, cluster);
+ blk_queue_max_hw_sectors(pd_queue, cluster);
if (register_blkdev(major, name))
goto out2;
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index ea54ea393553..ddb4f9abd480 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -956,8 +956,7 @@ static int __init pf_init(void)
return -ENOMEM;
}
- blk_queue_max_phys_segments(pf_queue, cluster);
- blk_queue_max_hw_segments(pf_queue, cluster);
+ blk_queue_max_segments(pf_queue, cluster);
for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) {
struct gendisk *disk = pf->disk;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 2ddf03ae034e..39c8514442eb 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -284,7 +284,7 @@ static ssize_t kobj_pkt_store(struct kobject *kobj,
return len;
}
-static struct sysfs_ops kobj_pkt_ops = {
+static const struct sysfs_ops kobj_pkt_ops = {
.show = kobj_pkt_show,
.store = kobj_pkt_store
};
@@ -322,7 +322,7 @@ static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd)
pkt_kobj_remove(pd->kobj_stat);
pkt_kobj_remove(pd->kobj_wqueue);
if (class_pktcdvd)
- device_destroy(class_pktcdvd, pd->pkt_dev);
+ device_unregister(pd->dev);
}
@@ -337,7 +337,9 @@ static void class_pktcdvd_release(struct class *cls)
{
kfree(cls);
}
-static ssize_t class_pktcdvd_show_map(struct class *c, char *data)
+static ssize_t class_pktcdvd_show_map(struct class *c,
+ struct class_attribute *attr,
+ char *data)
{
int n = 0;
int idx;
@@ -356,7 +358,9 @@ static ssize_t class_pktcdvd_show_map(struct class *c, char *data)
return n;
}
-static ssize_t class_pktcdvd_store_add(struct class *c, const char *buf,
+static ssize_t class_pktcdvd_store_add(struct class *c,
+ struct class_attribute *attr,
+ const char *buf,
size_t count)
{
unsigned int major, minor;
@@ -376,7 +380,9 @@ static ssize_t class_pktcdvd_store_add(struct class *c, const char *buf,
return -EINVAL;
}
-static ssize_t class_pktcdvd_store_remove(struct class *c, const char *buf,
+static ssize_t class_pktcdvd_store_remove(struct class *c,
+ struct class_attribute *attr,
+ const char *buf,
size_t count)
{
unsigned int major, minor;
@@ -569,6 +575,7 @@ static struct packet_data *pkt_alloc_packet_data(int frames)
}
spin_lock_init(&pkt->lock);
+ bio_list_init(&pkt->orig_bios);
for (i = 0; i < frames; i++) {
struct bio *bio = pkt_bio_alloc(1);
@@ -721,43 +728,6 @@ static void pkt_rbtree_insert(struct pktcdvd_device *pd, struct pkt_rb_node *nod
}
/*
- * Add a bio to a single linked list defined by its head and tail pointers.
- */
-static void pkt_add_list_last(struct bio *bio, struct bio **list_head, struct bio **list_tail)
-{
- bio->bi_next = NULL;
- if (*list_tail) {
- BUG_ON((*list_head) == NULL);
- (*list_tail)->bi_next = bio;
- (*list_tail) = bio;
- } else {
- BUG_ON((*list_head) != NULL);
- (*list_head) = bio;
- (*list_tail) = bio;
- }
-}
-
-/*
- * Remove and return the first bio from a single linked list defined by its
- * head and tail pointers.
- */
-static inline struct bio *pkt_get_list_first(struct bio **list_head, struct bio **list_tail)
-{
- struct bio *bio;
-
- if (*list_head == NULL)
- return NULL;
-
- bio = *list_head;
- *list_head = bio->bi_next;
- if (*list_head == NULL)
- *list_tail = NULL;
-
- bio->bi_next = NULL;
- return bio;
-}
-
-/*
* Send a packet_command to the underlying block device and
* wait for completion.
*/
@@ -876,13 +846,10 @@ static noinline_for_stack int pkt_set_speed(struct pktcdvd_device *pd,
static void pkt_queue_bio(struct pktcdvd_device *pd, struct bio *bio)
{
spin_lock(&pd->iosched.lock);
- if (bio_data_dir(bio) == READ) {
- pkt_add_list_last(bio, &pd->iosched.read_queue,
- &pd->iosched.read_queue_tail);
- } else {
- pkt_add_list_last(bio, &pd->iosched.write_queue,
- &pd->iosched.write_queue_tail);
- }
+ if (bio_data_dir(bio) == READ)
+ bio_list_add(&pd->iosched.read_queue, bio);
+ else
+ bio_list_add(&pd->iosched.write_queue, bio);
spin_unlock(&pd->iosched.lock);
atomic_set(&pd->iosched.attention, 1);
@@ -917,8 +884,8 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
int reads_queued, writes_queued;
spin_lock(&pd->iosched.lock);
- reads_queued = (pd->iosched.read_queue != NULL);
- writes_queued = (pd->iosched.write_queue != NULL);
+ reads_queued = !bio_list_empty(&pd->iosched.read_queue);
+ writes_queued = !bio_list_empty(&pd->iosched.write_queue);
spin_unlock(&pd->iosched.lock);
if (!reads_queued && !writes_queued)
@@ -927,7 +894,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
if (pd->iosched.writing) {
int need_write_seek = 1;
spin_lock(&pd->iosched.lock);
- bio = pd->iosched.write_queue;
+ bio = bio_list_peek(&pd->iosched.write_queue);
spin_unlock(&pd->iosched.lock);
if (bio && (bio->bi_sector == pd->iosched.last_write))
need_write_seek = 0;
@@ -950,13 +917,10 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
}
spin_lock(&pd->iosched.lock);
- if (pd->iosched.writing) {
- bio = pkt_get_list_first(&pd->iosched.write_queue,
- &pd->iosched.write_queue_tail);
- } else {
- bio = pkt_get_list_first(&pd->iosched.read_queue,
- &pd->iosched.read_queue_tail);
- }
+ if (pd->iosched.writing)
+ bio = bio_list_pop(&pd->iosched.write_queue);
+ else
+ bio = bio_list_pop(&pd->iosched.read_queue);
spin_unlock(&pd->iosched.lock);
if (!bio)
@@ -992,14 +956,14 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_queue *q)
{
if ((pd->settings.size << 9) / CD_FRAMESIZE
- <= queue_max_phys_segments(q)) {
+ <= queue_max_segments(q)) {
/*
* The cdrom device can handle one segment/frame
*/
clear_bit(PACKET_MERGE_SEGS, &pd->flags);
return 0;
} else if ((pd->settings.size << 9) / PAGE_SIZE
- <= queue_max_phys_segments(q)) {
+ <= queue_max_segments(q)) {
/*
* We can handle this case at the expense of some extra memory
* copies during write operations
@@ -1114,7 +1078,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
int f;
char written[PACKET_MAX_SIZE];
- BUG_ON(!pkt->orig_bios);
+ BUG_ON(bio_list_empty(&pkt->orig_bios));
atomic_set(&pkt->io_wait, 0);
atomic_set(&pkt->io_errors, 0);
@@ -1124,7 +1088,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
*/
memset(written, 0, sizeof(written));
spin_lock(&pkt->lock);
- for (bio = pkt->orig_bios; bio; bio = bio->bi_next) {
+ bio_list_for_each(bio, &pkt->orig_bios) {
int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9);
int num_frames = bio->bi_size / CD_FRAMESIZE;
pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9);
@@ -1363,7 +1327,7 @@ try_next_bio:
break;
pkt_rbtree_erase(pd, node);
spin_lock(&pkt->lock);
- pkt_add_list_last(bio, &pkt->orig_bios, &pkt->orig_bios_tail);
+ bio_list_add(&pkt->orig_bios, bio);
pkt->write_size += bio->bi_size / CD_FRAMESIZE;
spin_unlock(&pkt->lock);
}
@@ -1409,7 +1373,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
*/
frames_write = 0;
spin_lock(&pkt->lock);
- for (bio = pkt->orig_bios; bio; bio = bio->bi_next) {
+ bio_list_for_each(bio, &pkt->orig_bios) {
int segment = bio->bi_idx;
int src_offs = 0;
int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9);
@@ -1472,20 +1436,14 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
static void pkt_finish_packet(struct packet_data *pkt, int uptodate)
{
- struct bio *bio, *next;
+ struct bio *bio;
if (!uptodate)
pkt->cache_valid = 0;
/* Finish all bios corresponding to this packet */
- bio = pkt->orig_bios;
- while (bio) {
- next = bio->bi_next;
- bio->bi_next = NULL;
+ while ((bio = bio_list_pop(&pkt->orig_bios)))
bio_endio(bio, uptodate ? 0 : -EIO);
- bio = next;
- }
- pkt->orig_bios = pkt->orig_bios_tail = NULL;
}
static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data *pkt)
@@ -2360,7 +2318,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
* even if the size is a multiple of the packet size.
*/
spin_lock_irq(q->queue_lock);
- blk_queue_max_sectors(q, pd->settings.size);
+ blk_queue_max_hw_sectors(q, pd->settings.size);
spin_unlock_irq(q->queue_lock);
set_bit(PACKET_WRITABLE, &pd->flags);
} else {
@@ -2567,8 +2525,7 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio)
spin_lock(&pkt->lock);
if ((pkt->state == PACKET_WAITING_STATE) ||
(pkt->state == PACKET_READ_WAIT_STATE)) {
- pkt_add_list_last(bio, &pkt->orig_bios,
- &pkt->orig_bios_tail);
+ bio_list_add(&pkt->orig_bios, bio);
pkt->write_size += bio->bi_size / CD_FRAMESIZE;
if ((pkt->write_size >= pkt->frames) &&
(pkt->state == PACKET_WAITING_STATE)) {
@@ -2662,7 +2619,7 @@ static void pkt_init_queue(struct pktcdvd_device *pd)
blk_queue_make_request(q, pkt_make_request);
blk_queue_logical_block_size(q, CD_FRAMESIZE);
- blk_queue_max_sectors(q, PACKET_MAX_SECTORS);
+ blk_queue_max_hw_sectors(q, PACKET_MAX_SECTORS);
blk_queue_merge_bvec(q, pkt_merge_bvec);
q->queuedata = pd;
}
@@ -2898,6 +2855,8 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
spin_lock_init(&pd->lock);
spin_lock_init(&pd->iosched.lock);
+ bio_list_init(&pd->iosched.read_queue);
+ bio_list_init(&pd->iosched.write_queue);
sprintf(pd->name, DRIVER_NAME"%d", idx);
init_waitqueue_head(&pd->wqueue);
pd->bio_queue = RB_ROOT;
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
index 03a130dca8ab..bc95469d33c1 100644
--- a/drivers/block/ps3disk.c
+++ b/drivers/block/ps3disk.c
@@ -474,7 +474,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
blk_queue_bounce_limit(queue, BLK_BOUNCE_HIGH);
- blk_queue_max_sectors(queue, dev->bounce_size >> 9);
+ blk_queue_max_hw_sectors(queue, dev->bounce_size >> 9);
blk_queue_segment_boundary(queue, -1UL);
blk_queue_dma_alignment(queue, dev->blk_size-1);
blk_queue_logical_block_size(queue, dev->blk_size);
@@ -482,8 +482,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH,
ps3disk_prepare_flush);
- blk_queue_max_phys_segments(queue, -1);
- blk_queue_max_hw_segments(queue, -1);
+ blk_queue_max_segments(queue, -1);
blk_queue_max_segment_size(queue, dev->bounce_size);
gendisk = alloc_disk(PS3DISK_MINORS);
diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c
index 1fb6c3135fc8..e44608229972 100644
--- a/drivers/block/ps3vram.c
+++ b/drivers/block/ps3vram.c
@@ -751,10 +751,9 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
priv->queue = queue;
queue->queuedata = dev;
blk_queue_make_request(queue, ps3vram_make_request);
- blk_queue_max_phys_segments(queue, MAX_PHYS_SEGMENTS);
- blk_queue_max_hw_segments(queue, MAX_HW_SEGMENTS);
- blk_queue_max_segment_size(queue, MAX_SEGMENT_SIZE);
- blk_queue_max_sectors(queue, SAFE_MAX_SECTORS);
+ blk_queue_max_segments(queue, BLK_MAX_SEGMENTS);
+ blk_queue_max_segment_size(queue, BLK_MAX_SEGMENT_SIZE);
+ blk_queue_max_hw_sectors(queue, BLK_SAFE_MAX_SECTORS);
gendisk = alloc_disk(1);
if (!gendisk) {
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 411f064760b4..48e8fee9f2d4 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -691,9 +691,8 @@ static int probe_disk(struct vdc_port *port)
port->disk = g;
- blk_queue_max_hw_segments(q, port->ring_cookies);
- blk_queue_max_phys_segments(q, port->ring_cookies);
- blk_queue_max_sectors(q, port->max_xfer_size);
+ blk_queue_max_segments(q, port->ring_cookies);
+ blk_queue_max_hw_sectors(q, port->max_xfer_size);
g->major = vdc_major;
g->first_minor = port->vio.vdev->dev_no << PARTITION_SHIFT;
strcpy(g->disk_name, port->disk_name);
diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 8f569e3df890..821c2833f9cf 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -864,7 +864,7 @@ static int __devinit swim_probe(struct platform_device *dev)
struct swim_priv *swd;
int ret;
- res = platform_get_resource_byname(dev, IORESOURCE_MEM, "swim-regs");
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
goto out;
@@ -942,7 +942,7 @@ static int __devexit swim_remove(struct platform_device *dev)
iounmap(swd->base);
- res = platform_get_resource_byname(dev, IORESOURCE_MEM, "swim-regs");
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (res)
release_mem_region(res->start, resource_size(res));
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index a7c4184f4a63..b70f0fca9a42 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -409,7 +409,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
static void carm_remove_one (struct pci_dev *pdev);
static int carm_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo);
-static struct pci_device_id carm_pci_tbl[] = {
+static const struct pci_device_id carm_pci_tbl[] = {
{ PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
{ PCI_VENDOR_ID_PROMISE, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
{ } /* terminate list */
@@ -1518,8 +1518,7 @@ static int carm_init_disks(struct carm_host *host)
break;
}
disk->queue = q;
- blk_queue_max_hw_segments(q, CARM_MAX_REQ_SG);
- blk_queue_max_phys_segments(q, CARM_MAX_REQ_SG);
+ blk_queue_max_segments(q, CARM_MAX_REQ_SG);
blk_queue_segment_boundary(q, CARM_SG_BOUNDARY);
q->queuedata = port;
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index c739b203fe91..2e889838e819 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -393,7 +393,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum);
#define ub_usb_ids usb_storage_usb_ids
#else
-static struct usb_device_id ub_usb_ids[] = {
+static const struct usb_device_id ub_usb_ids[] = {
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
{ }
};
@@ -2320,10 +2320,9 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
disk->queue = q;
blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
- blk_queue_max_hw_segments(q, UB_MAX_REQ_SG);
- blk_queue_max_phys_segments(q, UB_MAX_REQ_SG);
+ blk_queue_max_segments(q, UB_MAX_REQ_SG);
blk_queue_segment_boundary(q, 0xffffffff); /* Dubious. */
- blk_queue_max_sectors(q, UB_MAX_SECTORS);
+ blk_queue_max_hw_sectors(q, UB_MAX_SECTORS);
blk_queue_logical_block_size(q, lun->capacity.bsize);
lun->disk = disk;
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
index a8c8b56b275e..788d93882ab9 100644
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -28,6 +28,9 @@
* All disk operations are performed by sending messages back and forth to
* the OS/400 partition.
*/
+
+#define pr_fmt(fmt) "viod: " fmt
+
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/module.h>
@@ -63,9 +66,6 @@ MODULE_LICENSE("GPL");
#define VIOD_VERS "1.64"
-#define VIOD_KERN_WARNING KERN_WARNING "viod: "
-#define VIOD_KERN_INFO KERN_INFO "viod: "
-
enum {
PARTITION_SHIFT = 3,
MAX_DISKNO = HVMAXARCHITECTEDVIRTUALDISKS,
@@ -156,7 +156,7 @@ static int viodasd_open(struct block_device *bdev, fmode_t mode)
((u64)DEVICE_NO(d) << 48) | ((u64)flags << 32),
0, 0, 0);
if (hvrc != 0) {
- printk(VIOD_KERN_WARNING "HV open failed %d\n", (int)hvrc);
+ pr_warning("HV open failed %d\n", (int)hvrc);
return -EIO;
}
@@ -167,9 +167,8 @@ static int viodasd_open(struct block_device *bdev, fmode_t mode)
const struct vio_error_entry *err =
vio_lookup_rc(viodasd_err_table, we.sub_result);
- printk(VIOD_KERN_WARNING
- "bad rc opening disk: %d:0x%04x (%s)\n",
- (int)we.rc, we.sub_result, err->msg);
+ pr_warning("bad rc opening disk: %d:0x%04x (%s)\n",
+ (int)we.rc, we.sub_result, err->msg);
return -EIO;
}
@@ -195,8 +194,7 @@ static int viodasd_release(struct gendisk *disk, fmode_t mode)
((u64)DEVICE_NO(d) << 48) /* | ((u64)flags << 32) */,
0, 0, 0);
if (hvrc != 0)
- printk(VIOD_KERN_WARNING "HV close call failed %d\n",
- (int)hvrc);
+ pr_warning("HV close call failed %d\n", (int)hvrc);
return 0;
}
@@ -288,8 +286,7 @@ static int send_request(struct request *req)
bevent = (struct vioblocklpevent *)
vio_get_event_buffer(viomajorsubtype_blockio);
if (bevent == NULL) {
- printk(VIOD_KERN_WARNING
- "error allocating disk event buffer\n");
+ pr_warning("error allocating disk event buffer\n");
goto error_ret;
}
@@ -333,9 +330,8 @@ static int send_request(struct request *req)
}
if (hvrc != HvLpEvent_Rc_Good) {
- printk(VIOD_KERN_WARNING
- "error sending disk event to OS/400 (rc %d)\n",
- (int)hvrc);
+ pr_warning("error sending disk event to OS/400 (rc %d)\n",
+ (int)hvrc);
goto error_ret;
}
spin_unlock_irqrestore(&viodasd_spinlock, flags);
@@ -402,7 +398,7 @@ retry:
((u64)dev_no << 48) | ((u64)flags<< 32),
0, 0, 0);
if (hvrc != 0) {
- printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc);
+ pr_warning("bad rc on HV open %d\n", (int)hvrc);
return 0;
}
@@ -416,9 +412,8 @@ retry:
goto retry;
}
if (we.max_disk > (MAX_DISKNO - 1)) {
- printk_once(VIOD_KERN_INFO
- "Only examining the first %d of %d disks connected\n",
- MAX_DISKNO, we.max_disk + 1);
+ printk_once(KERN_INFO pr_fmt("Only examining the first %d of %d disks connected\n"),
+ MAX_DISKNO, we.max_disk + 1);
}
/* Send the close event to OS/400. We DON'T expect a response */
@@ -432,17 +427,15 @@ retry:
((u64)dev_no << 48) | ((u64)flags << 32),
0, 0, 0);
if (hvrc != 0) {
- printk(VIOD_KERN_WARNING
- "bad rc sending event to OS/400 %d\n", (int)hvrc);
+ pr_warning("bad rc sending event to OS/400 %d\n", (int)hvrc);
return 0;
}
if (d->dev == NULL) {
/* this is when we reprobe for new disks */
if (vio_create_viodasd(dev_no) == NULL) {
- printk(VIOD_KERN_WARNING
- "cannot allocate virtual device for disk %d\n",
- dev_no);
+ pr_warning("cannot allocate virtual device for disk %d\n",
+ dev_no);
return 0;
}
/*
@@ -457,23 +450,20 @@ retry:
spin_lock_init(&d->q_lock);
q = blk_init_queue(do_viodasd_request, &d->q_lock);
if (q == NULL) {
- printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n",
- dev_no);
+ pr_warning("cannot allocate queue for disk %d\n", dev_no);
return 0;
}
g = alloc_disk(1 << PARTITION_SHIFT);
if (g == NULL) {
- printk(VIOD_KERN_WARNING
- "cannot allocate disk structure for disk %d\n",
- dev_no);
+ pr_warning("cannot allocate disk structure for disk %d\n",
+ dev_no);
blk_cleanup_queue(q);
return 0;
}
d->disk = g;
- blk_queue_max_hw_segments(q, VIOMAXBLOCKDMA);
- blk_queue_max_phys_segments(q, VIOMAXBLOCKDMA);
- blk_queue_max_sectors(q, VIODASD_MAXSECTORS);
+ blk_queue_max_segments(q, VIOMAXBLOCKDMA);
+ blk_queue_max_hw_sectors(q, VIODASD_MAXSECTORS);
g->major = VIODASD_MAJOR;
g->first_minor = dev_no << PARTITION_SHIFT;
if (dev_no >= 26)
@@ -489,13 +479,12 @@ retry:
g->driverfs_dev = d->dev;
set_capacity(g, d->size >> 9);
- printk(VIOD_KERN_INFO "disk %d: %lu sectors (%lu MB) "
- "CHS=%d/%d/%d sector size %d%s\n",
- dev_no, (unsigned long)(d->size >> 9),
- (unsigned long)(d->size >> 20),
- (int)d->cylinders, (int)d->tracks,
- (int)d->sectors, (int)d->bytes_per_sector,
- d->read_only ? " (RO)" : "");
+ pr_info("disk %d: %lu sectors (%lu MB) CHS=%d/%d/%d sector size %d%s\n",
+ dev_no, (unsigned long)(d->size >> 9),
+ (unsigned long)(d->size >> 20),
+ (int)d->cylinders, (int)d->tracks,
+ (int)d->sectors, (int)d->bytes_per_sector,
+ d->read_only ? " (RO)" : "");
/* register us in the global list */
add_disk(g);
@@ -580,8 +569,8 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
if (error) {
const struct vio_error_entry *err;
err = vio_lookup_rc(viodasd_err_table, bevent->sub_result);
- printk(VIOD_KERN_WARNING "read/write error %d:0x%04x (%s)\n",
- event->xRc, bevent->sub_result, err->msg);
+ pr_warning("read/write error %d:0x%04x (%s)\n",
+ event->xRc, bevent->sub_result, err->msg);
num_sect = blk_rq_sectors(req);
}
qlock = req->q->queue_lock;
@@ -606,8 +595,7 @@ static void handle_block_event(struct HvLpEvent *event)
return;
/* First, we should NEVER get an int here...only acks */
if (hvlpevent_is_int(event)) {
- printk(VIOD_KERN_WARNING
- "Yikes! got an int in viodasd event handler!\n");
+ pr_warning("Yikes! got an int in viodasd event handler!\n");
if (hvlpevent_need_ack(event)) {
event->xRc = HvLpEvent_Rc_InvalidSubtype;
HvCallEvent_ackLpEvent(event);
@@ -650,7 +638,7 @@ static void handle_block_event(struct HvLpEvent *event)
break;
default:
- printk(VIOD_KERN_WARNING "invalid subtype!");
+ pr_warning("invalid subtype!");
if (hvlpevent_need_ack(event)) {
event->xRc = HvLpEvent_Rc_InvalidSubtype;
HvCallEvent_ackLpEvent(event);
@@ -739,29 +727,26 @@ static int __init viodasd_init(void)
vio_set_hostlp();
if (viopath_hostLp == HvLpIndexInvalid) {
- printk(VIOD_KERN_WARNING "invalid hosting partition\n");
+ pr_warning("invalid hosting partition\n");
rc = -EIO;
goto early_fail;
}
- printk(VIOD_KERN_INFO "vers " VIOD_VERS ", hosting partition %d\n",
- viopath_hostLp);
+ pr_info("vers " VIOD_VERS ", hosting partition %d\n", viopath_hostLp);
/* register the block device */
rc = register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
if (rc) {
- printk(VIOD_KERN_WARNING
- "Unable to get major number %d for %s\n",
- VIODASD_MAJOR, VIOD_GENHD_NAME);
+ pr_warning("Unable to get major number %d for %s\n",
+ VIODASD_MAJOR, VIOD_GENHD_NAME);
goto early_fail;
}
/* Actually open the path to the hosting partition */
rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio,
VIOMAXREQ + 2);
if (rc) {
- printk(VIOD_KERN_WARNING
- "error opening path to host partition %d\n",
- viopath_hostLp);
+ pr_warning("error opening path to host partition %d\n",
+ viopath_hostLp);
goto unregister_blk;
}
@@ -770,7 +755,7 @@ static int __init viodasd_init(void)
rc = vio_register_driver(&viodasd_driver);
if (rc) {
- printk(VIOD_KERN_WARNING "vio_register_driver failed\n");
+ pr_warning("vio_register_driver failed\n");
goto unset_handler;
}
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 51042f0ba7e1..3c64af05fa82 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -243,10 +243,12 @@ static int index_to_minor(int index)
static int __devinit virtblk_probe(struct virtio_device *vdev)
{
struct virtio_blk *vblk;
+ struct request_queue *q;
int err;
u64 cap;
- u32 v;
- u32 blk_size, sg_elems;
+ u32 v, blk_size, sg_elems, opt_io_size;
+ u16 min_io_size;
+ u8 physical_block_exp, alignment_offset;
if (index_to_minor(index) >= 1 << MINORBITS)
return -ENOSPC;
@@ -293,13 +295,13 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
goto out_mempool;
}
- vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
- if (!vblk->disk->queue) {
+ q = vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
+ if (!q) {
err = -ENOMEM;
goto out_put_disk;
}
- vblk->disk->queue->queuedata = vblk;
+ q->queuedata = vblk;
if (index < 26) {
sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26);
@@ -323,10 +325,10 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
/* If barriers are supported, tell block layer that queue is ordered */
if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH))
- blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_DRAIN_FLUSH,
+ blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH,
virtblk_prepare_flush);
else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
- blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
+ blk_queue_ordered(q, QUEUE_ORDERED_TAG, NULL);
/* If disk is read-only in the host, the guest should obey */
if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
@@ -345,14 +347,14 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
set_capacity(vblk->disk, cap);
/* We can handle whatever the host told us to handle. */
- blk_queue_max_phys_segments(vblk->disk->queue, vblk->sg_elems-2);
- blk_queue_max_hw_segments(vblk->disk->queue, vblk->sg_elems-2);
+ blk_queue_max_phys_segments(q, vblk->sg_elems-2);
+ blk_queue_max_hw_segments(q, vblk->sg_elems-2);
/* No need to bounce any requests */
- blk_queue_bounce_limit(vblk->disk->queue, BLK_BOUNCE_ANY);
+ blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
/* No real sector limit. */
- blk_queue_max_sectors(vblk->disk->queue, -1U);
+ blk_queue_max_sectors(q, -1U);
/* Host can optionally specify maximum segment size and number of
* segments. */
@@ -360,16 +362,45 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
offsetof(struct virtio_blk_config, size_max),
&v);
if (!err)
- blk_queue_max_segment_size(vblk->disk->queue, v);
+ blk_queue_max_segment_size(q, v);
else
- blk_queue_max_segment_size(vblk->disk->queue, -1U);
+ blk_queue_max_segment_size(q, -1U);
/* Host can optionally specify the block size of the device */
err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE,
offsetof(struct virtio_blk_config, blk_size),
&blk_size);
if (!err)
- blk_queue_logical_block_size(vblk->disk->queue, blk_size);
+ blk_queue_logical_block_size(q, blk_size);
+ else
+ blk_size = queue_logical_block_size(q);
+
+ /* Use topology information if available */
+ err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
+ offsetof(struct virtio_blk_config, physical_block_exp),
+ &physical_block_exp);
+ if (!err && physical_block_exp)
+ blk_queue_physical_block_size(q,
+ blk_size * (1 << physical_block_exp));
+
+ err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
+ offsetof(struct virtio_blk_config, alignment_offset),
+ &alignment_offset);
+ if (!err && alignment_offset)
+ blk_queue_alignment_offset(q, blk_size * alignment_offset);
+
+ err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
+ offsetof(struct virtio_blk_config, min_io_size),
+ &min_io_size);
+ if (!err && min_io_size)
+ blk_queue_io_min(q, blk_size * min_io_size);
+
+ err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
+ offsetof(struct virtio_blk_config, opt_io_size),
+ &opt_io_size);
+ if (!err && opt_io_size)
+ blk_queue_io_opt(q, blk_size * opt_io_size);
+
add_disk(vblk->disk);
return 0;
@@ -404,7 +435,7 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
kfree(vblk);
}
-static struct virtio_device_id id_table[] = {
+static const struct virtio_device_id id_table[] = {
{ VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
{ 0 },
};
@@ -412,7 +443,7 @@ static struct virtio_device_id id_table[] = {
static unsigned int features[] = {
VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
- VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH
+ VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY
};
/*
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index d1fd032e7514..1a325fb05c92 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -242,7 +242,7 @@ static int __init xd_init(void)
}
/* xd_maxsectors depends on controller - so set after detection */
- blk_queue_max_sectors(xd_queue, xd_maxsectors);
+ blk_queue_max_hw_sectors(xd_queue, xd_maxsectors);
for (i = 0; i < xd_drives; i++)
add_disk(xd_gendisk[i]);
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 05a31e55d278..9c09694b2520 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -346,15 +346,14 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
/* Hard sector size and max sectors impersonate the equiv. hardware. */
blk_queue_logical_block_size(rq, sector_size);
- blk_queue_max_sectors(rq, 512);
+ blk_queue_max_hw_sectors(rq, 512);
/* Each segment in a request is up to an aligned page in size. */
blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
blk_queue_max_segment_size(rq, PAGE_SIZE);
/* Ensure a merged request will fit in a single I/O ring slot. */
- blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
- blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ blk_queue_max_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
/* Make sure buffer addresses are sector-aligned. */
blk_queue_dma_alignment(rq, 511);
@@ -1050,7 +1049,7 @@ static const struct block_device_operations xlvbd_block_fops =
};
-static struct xenbus_device_id blkfront_ids[] = {
+static const struct xenbus_device_id blkfront_ids[] = {
{ "vbd" },
{ "" }
};
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index e5c5415eb45e..e1c95e208a66 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -1227,7 +1227,7 @@ static int __devexit ace_of_remove(struct of_device *op)
}
/* Match table for of_platform binding */
-static struct of_device_id ace_of_match[] __devinitdata = {
+static const struct of_device_id ace_of_match[] __devinitconst = {
{ .compatible = "xlnx,opb-sysace-1.00.b", },
{ .compatible = "xlnx,opb-sysace-1.00.c", },
{ .compatible = "xlnx,xps-sysace-1.00.a", },
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 652367aa6546..058fbccf2f52 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -195,5 +195,16 @@ config BT_MRVL_SDIO
Say Y here to compile support for Marvell BT-over-SDIO driver
into the kernel or say M to compile it as module.
-endmenu
+config BT_ATH3K
+ tristate "Atheros firmware download driver"
+ depends on BT_HCIBTUSB
+ select FW_LOADER
+ help
+ Bluetooth firmware download driver.
+ This driver loads the firmware into the Atheros Bluetooth
+ chipset.
+ Say Y here to compile support for "Atheros firmware download driver"
+ into the kernel or say M to compile it as module (ath3k).
+
+endmenu
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index b3f57d2d4eb0..7e5aed598121 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
obj-$(CONFIG_BT_HCIBTUSB) += btusb.o
obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
+obj-$(CONFIG_BT_ATH3K) += ath3k.o
obj-$(CONFIG_BT_MRVL) += btmrvl.o
obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
new file mode 100644
index 000000000000..128cae4e8629
--- /dev/null
+++ b/drivers/bluetooth/ath3k.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/usb.h>
+#include <net/bluetooth/bluetooth.h>
+
+#define VERSION "1.0"
+
+
+static struct usb_device_id ath3k_table[] = {
+ /* Atheros AR3011 */
+ { USB_DEVICE(0x0CF3, 0x3000) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, ath3k_table);
+
+#define USB_REQ_DFU_DNLOAD 1
+#define BULK_SIZE 4096
+
+struct ath3k_data {
+ struct usb_device *udev;
+ u8 *fw_data;
+ u32 fw_size;
+ u32 fw_sent;
+};
+
+static int ath3k_load_firmware(struct ath3k_data *data,
+ unsigned char *firmware,
+ int count)
+{
+ u8 *send_buf;
+ int err, pipe, len, size, sent = 0;
+
+ BT_DBG("ath3k %p udev %p", data, data->udev);
+
+ pipe = usb_sndctrlpipe(data->udev, 0);
+
+ if ((usb_control_msg(data->udev, pipe,
+ USB_REQ_DFU_DNLOAD,
+ USB_TYPE_VENDOR, 0, 0,
+ firmware, 20, USB_CTRL_SET_TIMEOUT)) < 0) {
+ BT_ERR("Can't change to loading configuration err");
+ return -EBUSY;
+ }
+ sent += 20;
+ count -= 20;
+
+ send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
+ if (!send_buf) {
+ BT_ERR("Can't allocate memory chunk for firmware");
+ return -ENOMEM;
+ }
+
+ while (count) {
+ size = min_t(uint, count, BULK_SIZE);
+ pipe = usb_sndbulkpipe(data->udev, 0x02);
+ memcpy(send_buf, firmware + sent, size);
+
+ err = usb_bulk_msg(data->udev, pipe, send_buf, size,
+ &len, 3000);
+
+ if (err || (len != size)) {
+ BT_ERR("Error in firmware loading err = %d,"
+ "len = %d, size = %d", err, len, size);
+ goto error;
+ }
+
+ sent += size;
+ count -= size;
+ }
+
+ kfree(send_buf);
+ return 0;
+
+error:
+ kfree(send_buf);
+ return err;
+}
+
+static int ath3k_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ const struct firmware *firmware;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct ath3k_data *data;
+ int size;
+
+ BT_DBG("intf %p id %p", intf, id);
+
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+ return -ENODEV;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->udev = udev;
+
+ if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
+ kfree(data);
+ return -EIO;
+ }
+
+ size = max_t(uint, firmware->size, 4096);
+ data->fw_data = kmalloc(size, GFP_KERNEL);
+ if (!data->fw_data) {
+ release_firmware(firmware);
+ kfree(data);
+ return -ENOMEM;
+ }
+
+ memcpy(data->fw_data, firmware->data, firmware->size);
+ data->fw_size = firmware->size;
+ data->fw_sent = 0;
+ release_firmware(firmware);
+
+ usb_set_intfdata(intf, data);
+ if (ath3k_load_firmware(data, data->fw_data, data->fw_size)) {
+ usb_set_intfdata(intf, NULL);
+ kfree(data->fw_data);
+ kfree(data);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void ath3k_disconnect(struct usb_interface *intf)
+{
+ struct ath3k_data *data = usb_get_intfdata(intf);
+
+ BT_DBG("ath3k_disconnect intf %p", intf);
+
+ kfree(data->fw_data);
+ kfree(data);
+}
+
+static struct usb_driver ath3k_driver = {
+ .name = "ath3k",
+ .probe = ath3k_probe,
+ .disconnect = ath3k_disconnect,
+ .id_table = ath3k_table,
+};
+
+static int __init ath3k_init(void)
+{
+ BT_INFO("Atheros AR30xx firmware driver ver %s", VERSION);
+ return usb_register(&ath3k_driver);
+}
+
+static void __exit ath3k_exit(void)
+{
+ usb_deregister(&ath3k_driver);
+}
+
+module_init(ath3k_init);
+module_exit(ath3k_exit);
+
+MODULE_AUTHOR("Atheros Communications");
+MODULE_DESCRIPTION("Atheros AR30xx firmware driver");
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("ath3k-1.fw");
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
index eafd4af0746e..b0c84c19f442 100644
--- a/drivers/bluetooth/bcm203x.c
+++ b/drivers/bluetooth/bcm203x.c
@@ -39,7 +39,7 @@
#define VERSION "1.2"
-static struct usb_device_id bcm203x_table[] = {
+static const struct usb_device_id bcm203x_table[] = {
/* Broadcom Blutonium (BCM2033) */
{ USB_DEVICE(0x0a5c, 0x2033) },
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index 2a00707aba3b..005919ab043c 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -703,7 +703,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
data->hdev = hdev;
- hdev->type = HCI_USB;
+ hdev->bus = HCI_USB;
hdev->driver_data = data;
SET_HCIDEV_DEV(hdev, &intf->dev);
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 2acdc605cb4b..d9bf87ca9e83 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -503,7 +503,9 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
unsigned int iobase;
unsigned char reg;
- BUG_ON(!info->hdev);
+ if (!info || !info->hdev)
+ /* our irq handler is shared */
+ return IRQ_NONE;
if (!test_bit(CARD_READY, &(info->hw_state)))
return IRQ_HANDLED;
@@ -734,7 +736,7 @@ static int bluecard_open(bluecard_info_t *info)
info->hdev = hdev;
- hdev->type = HCI_PCCARD;
+ hdev->bus = HCI_PCCARD;
hdev->driver_data = info;
SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index c115285867c3..d945cd12433a 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -469,7 +469,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
return -ENOMEM;
}
- hdev->type = HCI_USB;
+ hdev->bus = HCI_USB;
hdev->driver_data = data;
data->hdev = hdev;
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index d814a2755ccb..027cb8bf650f 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -345,7 +345,9 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
int iir;
irqreturn_t r = IRQ_NONE;
- BUG_ON(!info->hdev);
+ if (!info || !info->hdev)
+ /* our irq handler is shared */
+ return IRQ_NONE;
iobase = info->p_dev->io.BasePort1;
@@ -580,7 +582,7 @@ static int bt3c_open(bt3c_info_t *info)
info->hdev = hdev;
- hdev->type = HCI_PCCARD;
+ hdev->bus = HCI_PCCARD;
hdev->driver_data = info;
SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c
index d43b5cb864ef..3126a3d0c45c 100644
--- a/drivers/bluetooth/btmrvl_debugfs.c
+++ b/drivers/bluetooth/btmrvl_debugfs.c
@@ -26,7 +26,8 @@
#include "btmrvl_drv.h"
struct btmrvl_debugfs_data {
- struct dentry *root_dir, *config_dir, *status_dir;
+ struct dentry *config_dir;
+ struct dentry *status_dir;
/* config */
struct dentry *psmode;
@@ -363,6 +364,9 @@ void btmrvl_debugfs_init(struct hci_dev *hdev)
struct btmrvl_private *priv = hdev->driver_data;
struct btmrvl_debugfs_data *dbg;
+ if (!hdev->debugfs)
+ return;
+
dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
priv->debugfs_data = dbg;
@@ -371,9 +375,7 @@ void btmrvl_debugfs_init(struct hci_dev *hdev)
return;
}
- dbg->root_dir = debugfs_create_dir("btmrvl", NULL);
-
- dbg->config_dir = debugfs_create_dir("config", dbg->root_dir);
+ dbg->config_dir = debugfs_create_dir("config", hdev->debugfs);
dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir,
hdev->driver_data, &btmrvl_psmode_fops);
@@ -388,7 +390,7 @@ void btmrvl_debugfs_init(struct hci_dev *hdev)
dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
hdev->driver_data, &btmrvl_hscfgcmd_fops);
- dbg->status_dir = debugfs_create_dir("status", dbg->root_dir);
+ dbg->status_dir = debugfs_create_dir("status", hdev->debugfs);
dbg->curpsmode = debugfs_create_file("curpsmode", 0444,
dbg->status_dir,
hdev->driver_data,
@@ -425,7 +427,5 @@ void btmrvl_debugfs_remove(struct hci_dev *hdev)
debugfs_remove(dbg->txdnldready);
debugfs_remove(dbg->status_dir);
- debugfs_remove(dbg->root_dir);
-
kfree(dbg);
}
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index f97771ce432c..53a43adf2e21 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -563,7 +563,7 @@ struct btmrvl_private *btmrvl_add_card(void *card)
priv->btmrvl_dev.tx_dnld_rdy = true;
- hdev->type = HCI_SDIO;
+ hdev->bus = HCI_SDIO;
hdev->open = btmrvl_open;
hdev->close = btmrvl_close;
hdev->flush = btmrvl_flush;
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index f36defa37764..94f1f55f81f0 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -808,6 +808,7 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv,
exit:
sdio_release_host(card->func);
+ kfree(tmpbuf);
return ret;
}
@@ -975,7 +976,7 @@ static struct sdio_driver bt_mrvl_sdio = {
.remove = btmrvl_sdio_remove,
};
-static int btmrvl_sdio_init_module(void)
+static int __init btmrvl_sdio_init_module(void)
{
if (sdio_register_driver(&bt_mrvl_sdio) != 0) {
BT_ERR("SDIO Driver Registration Failed");
@@ -988,7 +989,7 @@ static int btmrvl_sdio_init_module(void)
return 0;
}
-static void btmrvl_sdio_exit_module(void)
+static void __exit btmrvl_sdio_exit_module(void)
{
/* Set the flag as user is removing this module. */
user_rmmod = 1;
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
index 7e298275c8f6..76e5127884f0 100644
--- a/drivers/bluetooth/btsdio.c
+++ b/drivers/bluetooth/btsdio.c
@@ -326,7 +326,7 @@ static int btsdio_probe(struct sdio_func *func,
return -ENOMEM;
}
- hdev->type = HCI_SDIO;
+ hdev->bus = HCI_SDIO;
hdev->driver_data = data;
data->hdev = hdev;
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index d339464dc15e..60c0953d7d00 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -295,7 +295,9 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
int iir, lsr;
irqreturn_t r = IRQ_NONE;
- BUG_ON(!info->hdev);
+ if (!info || !info->hdev)
+ /* our irq handler is shared */
+ return IRQ_NONE;
iobase = info->p_dev->io.BasePort1;
@@ -498,7 +500,7 @@ static int btuart_open(btuart_info_t *info)
info->hdev = hdev;
- hdev->type = HCI_PCCARD;
+ hdev->bus = HCI_PCCARD;
hdev->driver_data = info;
SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index a699f09ddf7c..5d9cc53bd643 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -939,7 +939,7 @@ static int btusb_probe(struct usb_interface *intf,
return -ENOMEM;
}
- hdev->type = HCI_USB;
+ hdev->bus = HCI_USB;
hdev->driver_data = data;
data->hdev = hdev;
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 4f02a6f3c980..17788317c51a 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -299,7 +299,9 @@ static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
int iir, lsr;
irqreturn_t r = IRQ_NONE;
- BUG_ON(!info->hdev);
+ if (!info || !info->hdev)
+ /* our irq handler is shared */
+ return IRQ_NONE;
iobase = info->p_dev->io.BasePort1;
@@ -483,7 +485,7 @@ static int dtl1_open(dtl1_info_t *info)
info->hdev = hdev;
- hdev->type = HCI_PCCARD;
+ hdev->bus = HCI_PCCARD;
hdev->driver_data = info;
SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index aa0919386b8c..76a1abb8f214 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -383,7 +383,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
hu->hdev = hdev;
- hdev->type = HCI_UART;
+ hdev->bus = HCI_UART;
hdev->driver_data = hu;
hdev->open = hci_uart_open;
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 7595274103fd..bb0aefdb4267 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -236,7 +236,7 @@ static int vhci_open(struct inode *inode, struct file *file)
data->hdev = hdev;
- hdev->type = HCI_VIRTUAL;
+ hdev->bus = HCI_VIRTUAL;
hdev->driver_data = data;
hdev->open = vhci_open_dev;
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index e789e6c9a422..03c71f7698cb 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -741,7 +741,7 @@ static int __devinit probe_gdrom_setupqueue(void)
{
blk_queue_logical_block_size(gd.gdrom_rq, GDROM_HARD_SECTOR);
/* using DMA so memory will need to be contiguous */
- blk_queue_max_hw_segments(gd.gdrom_rq, 1);
+ blk_queue_max_segments(gd.gdrom_rq, 1);
/* set a large max size to get most from DMA */
blk_queue_max_segment_size(gd.gdrom_rq, 0x40000);
gd.disk->queue = gd.gdrom_rq;
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index 57ca69e0ac55..cc435be0bc13 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -616,9 +616,8 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
gendisk->first_minor = deviceno;
strncpy(gendisk->disk_name, c->name,
sizeof(gendisk->disk_name));
- blk_queue_max_hw_segments(q, 1);
- blk_queue_max_phys_segments(q, 1);
- blk_queue_max_sectors(q, 4096 / 512);
+ blk_queue_max_segments(q, 1);
+ blk_queue_max_hw_sectors(q, 4096 / 512);
gendisk->queue = q;
gendisk->fops = &viocd_fops;
gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE;
diff --git a/drivers/char/ChangeLog b/drivers/char/ChangeLog
deleted file mode 100644
index 56b8a2e76ab1..000000000000
--- a/drivers/char/ChangeLog
+++ /dev/null
@@ -1,775 +0,0 @@
-2001-08-11 Tim Waugh <twaugh@redhat.com>
-
- * serial.c (get_pci_port): Deal with awkward Titan cards.
-
-1998-08-26 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * serial.c (rs_open): Correctly decrement the module in-use count
- on errors.
-
-Thu Feb 19 14:24:08 1998 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * tty_io.c (tty_name): Remove the non-reentrant (and non-SMP safe)
- version of tty_name, and rename the reentrant _tty_name
- function to be tty_name.
- (tty_open): Add a warning message stating callout devices
- are deprecated.
-
-Mon Dec 1 08:24:15 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * tty_io.c (tty_get_baud_rate): Print a warning syslog if the
- tty->alt_speed kludge is used; this means the system is
- using the deprecated SPD_HI ioctls.
-
-Mon Nov 24 10:37:49 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * serial.c, esp.c, rocket.c: Change drivers to take advantage of
- tty_get_baud_rate().
-
- * tty_io.c (tty_get_baud_rate): New function which computes the
- correct baud rate for the tty. More factoring out of
- common code out of the serial driver to the high-level tty
- functions....
-
-Sat Nov 22 07:53:36 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * serial.c, esp.c, rocket.c: Add tty->driver.break() routine, and
- allow high-level tty code to handle the break and soft
- carrier ioctls.
-
- * tty_ioctl.c (n_tty_ioctl): Support TIOCGSOFTCAR and
- TIOCSSOFTCAR, so that device drivers don't have to support
- it.
-
- * serial.c (autoconfig): Change 16750 test to hopefully eliminate
- false results by people with strange 16550As being
- detected as 16750s. Hopefully 16750s will still be
- detected as 16750, and other weird UARTs won't get poorly
- autodetected. If this doesn't work, I'll have to disable
- the auto identification for the 16750.
-
- * tty_io.c (tty_hangup): Now actually do the tty hangup
- processing during the timer processing, and disable
- interrupts while doing the hangup processing. This avoids
- several nasty race conditions which happened when the
- hangup processing was done asynchronously.
- (tty_ioctl): Do break handling in the tty driver if
- driver's break function is supported.
- (tty_flip_buffer_push): New exported function which should
- be used by drivers to push characters in the flip buffer
- to the tty handler. This may either be done using a task
- queue function for better CPU efficiency, or directly for
- low latency operation.
-
- * serial.c (rs_set_termios): Fix bug rs_set_termios when
- transitioning away from B0, submitted by Stanislav
- Voronyi.
-
-Thu Jun 19 20:05:58 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * serial.c (begin_break, end_break, rs_ioctl): Applied patch
- to support BSD ioctls to set and clear the break
- condition explicitly.
-
- * console.c (scrup, scrdown, insert_line, delete_line): Applied
- fix suggested by Aaron Tiensivu to speed up block scrolls
- up and down.
-
- * n_tty.c (opost_block, write_chan): Added a modified "fast
- console" patch which processes a block of text via
- "cooking" efficiently.
-
-Wed Jun 18 15:25:50 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * tty_io.c (init_dev, release_dev): Applied fix suggested by Bill
- Hawes to prevent race conditions in the tty code.
-
- * n_tty.c (n_tty_chars_in_buffer): Applied fix suggested by Bill
- Hawes so that n_tty_chars_in_buffer returns the correct
- value in the case when the tty is in cannonical mode. (To
- avoid a pty deadlock with telnetd.)
-
-Thu Feb 27 01:53:08 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * serial.c (change_speed): Add support for the termios flag
- CMSPAR, which allows the user to select stick parity.
- (i.e, if PARODD is set, the parity bit is always 1; if
- PARRODD is not set, then the parity bit is always 0).
-
-Wed Feb 26 19:03:10 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * serial.c (cleanup_module): Fix memory leak when using the serial
- driver as a module; make sure tmp_buf gets freed!
-
-Tue Feb 25 11:01:59 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * serial.c (set_modem_info): Add support for setting and clearing
- the OUT1 and OUT2 bits. (For special case UART's, usually
- for half-duplex.)
- (autoconfig, change_speed): Fix TI 16750 support.
-
-Sun Feb 16 00:14:43 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * tty_io.c (release_dev): Add sanity check to make sure there are
- no waiters on tty->read_wait or tty->write_wait.
-
- * serial.c (rs_init): Don't autoconfig a device if the I/O region
- is already reserved.
-
- * serial.c (serial_proc_info): Add support for /proc/serial.
-
-Thu Feb 13 00:49:10 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * serial.c (receive_chars): When the UART repotrs an overrun
- condition, it does so with a valid character. Changed to
- not throw away the valid character, but instead report the
- overrun after the valid character.
-
- * serial.c: Added new #ifdef's for some of the advanced serial
- driver features. A minimal driver that only supports COM
- 1/2/3/4 without sharing serial interrupts only takes 17k;
- the full driver takes 32k.
-
-Wed Feb 12 14:50:44 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * vt.c:
- * pty.c:
- * tty_ioctl.c:
- * serial.c: Update routines to use the new 2.1 memory access
- routines.
-
-Wed Dec 4 07:51:52 1996 Theodore Ts'o <tytso@localhost.mit.edu>
-
- * serial.c (change_speed): Use save_flags(); cli() and
- restore_flags() in order to ensure we don't accidentally
- turn on interrupts when starting up the port.
- (startup): Move the insertion of serial structure into the
- IRQ chain earlier into the startup processing. Interrupts
- should be off this whole time, but we eventually will want
- to reduce this window.
-
-Thu Nov 21 10:05:22 1996 Theodore Ts'o <tytso@localhost.mit.edu>
-
- * tty_ioctl.c (tty_wait_until_sent): Always check the driver
- wait_until_ready routine, even if there are no characters
- in the xmit buffer. (There may be charactes in the device
- FIFO.)
- (n_tty_ioctl): Add new flag tty->flow_stopped which
- indicates whether the tty is stopped due to a request by
- the TCXONC ioctl (used by tcflow). If so, don't let an
- incoming XOFF character restart the tty. The tty can only
- be restarted by another TCXONC request.
-
- * tty_io.c (start_tty): Don't allow the tty to be restarted if
- tty->flow_stopped is true.
-
- * n_tty.c (n_tty_receive_char): If tty->flow_stopped is true, and
- IXANY is set, don't eat a character trying to restart the
- tty.
-
- * serial.c (startup): Remove need for MCR_noint from the
- async_struct structure. Only turn on DTR and RTS if the
- baud rate is not zero.
- (change_speed): More accurately calculate the timeout
- value based on the word size. Move responsibility of
- hangup when speed becomes B0 to rs_set_termios()
- (set_serial_info): When changing the UART type set the
- current xmit_fifo_size as well as the permanent
- xmit_fifo_size.
- (rs_ioctl): Fix TCSBRK (used by tcdrain) and TCSBRKP
- ioctls to return EINTR if interrupted by a signal.
- (rs_set_termios): If the baud rate changes to or from B0,
- this function is now responsible for setting or clearing
- DTR and RTS. DTR and RTS are only be changed on the
- transition to or from the B0 state.
- (rs_close): Wait for the characters to drain based on
- info->timeout. At low baud rates (50 bps), it may take a
- long time for the FIFO to completely drain out!
- (rs_wait_until_sent): Fixed timeout handling. Now
- releases control to the scheduler, but checks frequently
- enough so that the function is sensitive enough to pass
- the timing requirements of the NIST-PCTS.
- (block_til_ready): When opening the device, don't turn on
- DTR and RTS if the baud rate is B0.
-
-Thu Nov 14 00:06:09 1996 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * serial.c (autoconfig): Fix autoconfiguration problems;
- info->flags wasn't getting initialized from the state
- structure. Put in more paranoid test for the 16750.
-
-Fri Nov 8 20:19:50 1996 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * n_tty.c (n_tty_flush_buffer): Only call driver->unthrottle() if
- the tty was previous throttled.
- (n_tty_set_termios, write_chan): Add changes suggested by
- Simon P. Allen to allow hardware cooking.
-
- * tty_ioctl.c (set_termios): If we get a signal while waiting for
- the tty to drain, return -EINTR.
-
- * serial.c (change_speed): Add support for CREAD, as required by
- POSIX.
-
-Sat Nov 2 20:43:10 1996 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * serial.c: Wholesale changes. Added support for the Startech
- 16650 and 16650V2 chips. (WARNING: the new startech
- 16650A may or may not work!) Added support for the
- TI16750 (not yet tested). Split async_struct into a
- transient part (async_struct) and a permanent part
- (serial_state) which contains the configuration
- information for the ports. Added new driver routines
- wait_until_sent() and send_xchar() to help with POSIX
- compliance. Added support for radio clocks which waggle
- the carrier detect line (CONFIG_HARD_PPS).
-
- * tty_ioctl.c (tty_wait_until_sent): Added call to new driver
- function tty->driver.wait_until_sent(), which returns when
- the tty's device xmit buffers are drained. Needed for
- full POSIX compliance.
-
- (send_prio_char): New function, called by the ioctl's
- TCIOFF and TCION; uses the new driver call send_xchar(),
- which will send the XON or XOFF character at high priority
- (and even if tty output is stopped).
-
-Wed Jun 5 18:52:04 1996 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * pty.c (pty_close): When closing a pty, make sure packet mode is
- cleared.
-
-Sun May 26 09:33:52 1996 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * vesa_blank.c (set_vesa_blanking): Add missing verify_area() call.
-
- * selection.c (set_selection): Add missing verify_area() call.
-
- * tty_io.c (tty_ioctl): Add missing verify_area() calls.
-
- * serial.c (rs_ioctl): Add missing verify_area() calls.
- (rs_init): Allow initialization of serial driver
- configuration from a module.
-
- * random.c (extract_entropy): Add missing verify_area call.
- Don't limit number of characters returned to
- 32,768. Extract entropy is now no longer a inlined
- function.
-
- (random_read): Check return value in case extract_entropy
- returns an error.
-
- (secure_tcp_sequence_number): New function which returns a
- secure TCP sequence number. This is needed to prevent some
- nasty TCP hijacking attacks.
-
- (init_std_data): Initialize using gettimeofday() instead of
- struct timeval xtime.
-
- (fast_add_entropy_word, add_entropy_word): Rename the
- inline function add_entropy_word() to
- fast_add_entropy_word(). Make add_entropy_word() be the
- non-inlined function which is used in non-timing critical
- places, in order to save space.
-
- (initialize_benchmark, begin_benchmark, end_benchmark): New
- functions defined when RANDOM_BENCHMARK is defined. They
- allow us to benchmark the speed of the
- add_timer_randomness() call.
-
- (int_ln, rotate_left): Add two new inline functions with
- i386 optimized asm instructions. This speeds up the
- critical add_entropy_word() and add_timer_randomness()
- functions, which are called from interrupt handlers.
-
-Tue May 7 22:51:11 1996 <tytso@rsts-11.mit.edu>
-
- * random.c (add_timer_randomness): Limit the amount randomness
- that we estimate to 12 bits. (An arbitrary amount).
-
- (extract_entropy): To make it harder to analyze the hash
- function, fold the hash function in half using XOR, and
- use the folded result as the value to emit to the user.
- Also, add timer randomness each pass through the
- exact_entropy call, to increase the amount of unknown
- values during the extraction process.
-
- (random_ioctl): Use IOR/IOW definitions to define the
- ioctl values used by the /dev/random driver. Allow the
- old ioctl values to be used for backwards compatibility
- (for a limited amount of time).
-
-Wed Apr 24 14:02:04 1996 Theodore Ts'o <tytso@rsts-11.mit.edu>
-
- * random.c (add_timer_randomness): Use 2nd derivative as well to
- better estimate entropy.
-
- (rand_initialize): Explicitly initialize all the pointers
- to NULL. (Clearing pointers using memset isn't portable.)
- Initialize the random pool with OS-dependent data.
-
- (random_write): Add sanity checking to the arguments to
- random_write(), so that bad arguments won't cause a kernel
- SEGV.
-
- (random_read): Update the access time of the device inode
- when you return data to the user.
-
- (random_ioctl): Wake up the random_wait channel when there
- are only WAIT_INPUT_BITS available. Add more paranoia
- checks to make sure entropy_count doesn't go beyond the
- bounds of (0, POOLSIZE). Add a few missing verify_area
- checks. Add support for the RNDCLEARPOOL ioctl, which
- zaps the random pool.
-
- (add_timer_randomness): Wake up the random_wait
- channel only when there are WAIT_INPUT_BITS available.
-
- (random_select): Allow a random refresh daemon process to
- select on /dev/random for writing; wake up the daemon when
- there are less than WAIT_OUTPUT_BITS bits of randomness
- available.
-
-Tue Apr 23 22:56:07 1996 <tytso@rsts-11.mit.edu>
-
- * tty_io.c (init_dev): Change return code when user attempts to
- open master pty which is already open from EAGAIN to EIO,
- to match with BSD expectations. EIO is more correct
- anyway, since EAGAIN implies that retrying will be
- successful --- which it might be.... Eventually!!
-
- * pty.c (pty_open, pty_close): Fix wait loop so that we don't
- busy loop while waiting for the master side to open.
- Fix tty opening/closing logic. TTY_SLAVE_CLOSED was
- renamed to TTY_OTHER_CLOSED, so that the name is more
- descriptive. Also fixed code so that the tty flag
- actually works correctly now....
-
-Mon Apr 1 10:22:01 1996 <tytso@rsts-11.mit.edu>
-
- * serial.c (rs_close): Cleaned up modularization changes.
- Remove code which forced line discipline back to N_TTY
- this is done in the tty upper layers, and there's no
- reason to do it here. (Making this change also
- removed the requirement that the serial module access
- the internal kernel symbol "ldiscs".)
-
- * tty_io.c (tty_init): Formally register a tty_driver entry for
- /dev/tty (device 4, 0) and /dev/console (device 5, 0).
- This guarantees that major device numbers 4 and 5 will be
- reserved for the tty subsystem (as they have to be because
- of /dev/tty and /dev/console). Removed tty_regdev, as
- this interface is no longer necessary.
-
-Sun Mar 17 20:42:47 GMT 1996 <ah@doc.ic.ac.uk>
-
- * serial.c : modularisation (changes in linux/fs/device.c allow
- kerneld to automatically load the serial module).
-
- * Makefile, Config.in : serial modularisation adds.
-
- * tty_io.c : tty_init_ctty used by to register "cua" driver just
- for the /dev/tty device (5,0). Added tty_regdev.
-
- * serial.c (shutdown, rs_ioctl) : when port shuts down wakeup processes
- waiting on delta_msr_wait. The TIOCMIWAIT ioctl returns EIO
- if no change was done since the time of call.
-
-Sat Mar 16 14:33:13 1996 <aeb@cwi.nl>
-
- * tty_io.c (disassociate_ctty): If disassociate_ctty is called by
- exit, do not perform an implicit vhangup on a pty.
-
-Fri Feb 9 14:15:47 1996 <tytso@rsts-11.mit.edu>
-
- * serial.c (block_til_ready): Fixed another race condition which
- happens if a hangup happens during the open.
-
-Wed Jan 10 10:08:00 1996 <tytso@rsts-11.mit.edu>
-
- * serial.c (block_til_ready): Remove race condition which happened
- if a hangup condition happened during the setup of the
- UART, before rs_open() called block_til_ready(). This
- caused the info->count counter to be erroneously
- decremented.
-
- * serial.c (startup, rs_open): Remove race condition that could
- cause a memory leak of one page. (Fortunately, both race
- conditions were relatively rare in practice.)
-
-Tue Dec 5 13:21:27 1995 <tytso@rsts-11.mit.edu>
-
- * serial.c (check_modem_status, rs_ioctl): Support the new
- ioctl()'s TIOCGICOUNT, TIOCMIWAIT. These allow an
- application program to wait on a modem serial register
- status bit change, and to find out how many changes have
- taken place for the MSR bits.
-
- (rs_write): Eliminate a race condition which is introduced
- if it is necessary to wait for the semaphore.
-
-Sat Nov 4 17:14:45 1995 <tytso@rsts-11.mit.edu>
-
- * tty_io.c (tty_init): Move registration of TTY_MAJOR and
- TTY_AUX_MAJOR to the end, so that /proc/devices looks
- prettier.
-
- * pty.c (pty_init): Use new major numbers for PTY master and slave
- devices. This allow us to have more than 64 pty's. We
- register the old pty devices for backwards compatibility.
- Note that a system should either be using the old pty
- devices or the new pty devices --- in general, it should
- try to use both, since they map into the same pty table.
- The old pty devices are strictly for backwards compatibility.
-
-Wed Oct 11 12:45:24 1995 <tytso@rsts-11.mit.edu>
-
- * tty_io.c (disassociate_ctty): If disassociate_ctty is called by
- exit, perform an implicit vhangup on the tty.
-
- * pty.c (pty_close): When the master pty is closed, send a hangup
- to the slave pty.
- (pty_open): Use the flag TTY_SLAVE_CLOSED to test to see
- if there are any open slave ptys, instead of using
- tty->link->count. The old method got confused if there
- were processes that had hung-up file descriptors on the
- slave tty.
-
-Tue May 2 00:53:25 1995 <tytso@rsx-11.mit.edu>
-
- * tty_io.c (tty_set_ldisc): Wait until the output buffer is
- drained before closing the old line discipline --- needed
- in only one case: XON/XOFF processing.
-
- * n_tty.c (n_tty_close): Don't bother waiting until the output
- driver is closed; in general, the line discipline
- shouldn't care if the hardware is finished
- transmitting before the line discipline terminates.
-
- * tty_io.c (release_dev): Shutdown the line discipline after
- decrementing the tty count variable; but set the
- TTY_CLOSING flag so that we know that this tty structure
- isn't long for this world.
-
- * tty_io.c (init_dev): Add sanity code to check to see if
- TTY_CLOSING is set on a tty structure; if so, something
- bad has happened (probably a line discipline close blocked
- when it shouldn't have; so do a kernel printk and then
- return an error).
-
-Wed Apr 26 10:23:44 1995 Theodore Y. Ts'o <tytso@localhost>
-
- * tty_io.c (release_dev): Try to shutdown the line discipline
- *before* decrementing the tty count variable; this removes
- a potential race condition which occurs when the line
- discipline close blocks, and another process then tries
- open the same serial port.
-
- * serial.c (rs_hangup): When hanging up, flush the output buffer
- before shutting down the UART. Otherwise the line
- discipline close blocks waiting for the characters to get
- flushed, which never happens until the serial port gets reused.
-
-Wed Apr 12 08:06:16 1995 Theodore Y. Ts'o <tytso@localhost>
-
- * serial.c (do_serial_hangup, do_softint, check_modem_status,
- rs_init): Hangups are now scheduled via a separate tqueue
- structure in the async_struct structure, tqueue_hangup.
- This task is pushed on to the tq_schedule queue, so that
- it is processed synchronously by the scheduler.
-
-Sat Feb 18 12:13:51 1995 Theodore Y. Ts'o (tytso@rt-11)
-
- * tty_io.c (disassociate_ctty, tty_open, tty_ioctl): Clear
- current->tty_old_pgrp field when a session leader
- acquires a controlling tty, and after a session leader
- has disassociated from a controlling tty.
-
-Fri Feb 17 09:34:09 1995 Theodore Y. Ts'o (tytso@rt-11)
-
- * serial.c (rs_interrupt_single, rs_interrupt, rs_interrupt_multi):
- Change the number of passes made from 64 to be 256,
- configurable with the #define RS_ISR_PASS_LIMIT.
-
- * serial.c (rs_init, set_serial_info, get_serial_info, rs_close):
- Remove support for closing_wait2. Instead, set
- tty->closing and rely on the line discipline to prevent
- echo wars.
-
- * n_tty.c (n_tty_receive_char): IEXTEN does not need to be
- enabled in order for IXANY to be active.
-
- If tty->closing is set, then only process XON and XOFF
- characters.
-
-Sun Feb 12 23:57:48 1995 Theodore Y. Ts'o (tytso@rt-11)
-
- * serial.c (rs_timer): Change the interrupt poll time from 60
- seconds to 10 seconds, configurable with the #define
- RS_STROBE_TIME.
-
- * serial.c (rs_interrupt_multi, startup, shutdown, rs_ioctl,
- set_multiport_struct, get_multiport_struct): Add
- provisions for a new type of interrupt service routine,
- which better supports multiple serial ports on a single
- IRQ.
-
-Sun Feb 5 19:35:11 1995 Theodore Y. Ts'o (tytso@rt-11)
-
- * tty_ioctl.c (n_tty_ioctl, set_termios, tty_wait_until_sent):
- * serial.c (rs_ioctl, rs_close):
- * cyclades.c (cy_ioctl, cy_close):
- * n_tty.c (n_tty_close): Rename wait_until_sent to
- tty_wait_until_sent, so that it's a better name to export
- in ksyms.c.
-
-Sat Feb 4 23:36:20 1995 Theodore Y. Ts'o (tytso@rt-11)
-
- * serial.c (rs_close): Added missing check for closing_wait2 being
- ASYNC_CLOSING_WAIT_NONE.
-
-Thu Jan 26 09:02:49 1995 Theodore Y. Ts'o (tytso@rt-11)
-
- * serial.c (rs_init, set_serial_info, get_serial_info,
- rs_close): Support close_wait in the serial driver.
- This is helpful for slow devices (like serial
- plotters) so that their outputs don't get flushed upon
- device close. This has to be configurable because
- normally we don't want ports to be hung up for long
- periods of time during a close when they are not
- connected to a device, or the device is powered off.
-
- The default is to wait 30 seconds; in the case of a
- very slow device, the close_wait timeout should be
- lengthened. If it is set to 0, the kernel will wait
- forever for all of the data to be transmitted.
-
-Thu Jan 17 01:17:20 1995 Theodore Y. Ts'o (tytso@rt-11)
-
- * serial.c (startup, change_speed, rs_init): Add support to detect
- the StarTech 16650 chip. Treat it as a 16450 for now,
- because of its FIFO bugs.
-
-Thu Jan 5 21:21:57 1995 <dahinds@users.sourceforge.net>
-
- * serial.c: (receive_char): Added counter to prevent infinite loop
- when a PCMCIA serial device is ejected.
-
-Thu Dec 29 17:53:48 1994 <tytso@rsx-11.mit.edu>
-
- * tty_io.c (check_tty_count): New procedure which checks
- tty->count to make sure that it matches with the number of
- open file descriptors which point at the structure. If
- the number doesn't match, it prints a warning message.
-
-Wed Dec 28 15:41:51 1994 <tytso@rsx-11.mit.edu>
-
- * tty_io.c (do_tty_hangup, disassociate_ctty): At hangup time,
- save the tty's current foreground process group in the
- session leader's task structure. When the session leader
- terminates, send a SIGHUP, SIGCONT to that process group.
- This is not required by POSIX, but it's not prohibited
- either, and it appears to be the least intrusive way
- to fix a problem that dialup servers have with
- orphaned process groups caused by modem hangups.
-
-Thu Dec 8 14:52:11 1994 <tytso@rsx-11.mit.edu>
-
- * serial.c (rs_ioctl): Don't allow most ioctl's if the serial port
- isn't initialized.
-
- * serial.c (rs_close): Don't clear the IER if the serial port
- isn't initialized.
-
- * serial.c (block_til_ready): Don't try to block on the dialin
- port if the serial port isn't initialized.
-
-Wed Dec 7 10:48:30 1994 Si Park (si@wimpol.demon.co.uk)
- * tty_io.c (tty_register_driver): Fix bug when linking onto
- the tty_drivers list. We now test that there are elements
- already on the list before setting the back link from the
- first element to the new driver.
-
- * tty_io.c (tty_unregister_driver): Fix bug in unlinking the
- specified driver from the tty_drivers list. We were not
- setting the back link correctly. This used to result in
- a dangling back link pointer and cause panics on the next
- call to get_tty_driver().
-
-Tue Nov 29 10:21:09 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * tty_io.c (tty_unregister_driver): Fix bug in
- tty_unregister_driver where the pointer to the refcount is
- tested, instead of the refcount itself. This caused
- tty_unregister_driver to always return EBUSY.
-
-Sat Nov 26 11:59:24 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * tty_io.c (tty_ioctl): Add support for the new ioctl
- TIOCTTYGSTRUCT, which allow a kernel debugging program
- direct read access to the tty and tty_driver structures.
-
-Fri Nov 25 17:26:22 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * serial.c (rs_set_termios): Don't wake up processes blocked in
- open when the CLOCAL flag changes, since a blocking
- open only samples the CLOCAL flag once when it blocks,
- and doesn't check it again. (n.b. FreeBSD has a
- different behavior for blocking opens; it's not clear
- whether Linux or FreeBSD's interpretation is correct.
- POSIX doesn't give clear guidance on this issue, so
- this may change in the future....)
-
- * serial.c (block_til_ready): Use the correct termios structure to
- check the CLOCAL flag. If the cuaXX device is active,
- then check the saved termios for the ttySXX device.
- Otherwise, use the currently active termios structure.
-
-Sun Nov 6 21:05:44 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * serial.c (change_speed): Add support for direct access of
- 57,600 and 115,200 bps.
-
-Wed Nov 2 10:32:36 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * n_tty.c (n_tty_receive_room): Only allow excess characters
- through if we are in ICANON mode *and* there are other no
- pending lines in the buffer. Otherwise cut and paste over
- 4k breaks.
-
-Sat Oct 29 18:17:34 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * serial.c (rs_ioctl, get_lsr_info): Added patch suggested by Arne
- Riiber so that user mode programs can tell when the
- transmitter shift register is empty.
-
-Thu Oct 27 23:14:29 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * tty_ioctl.c (wait_until_sent): Added debugging printk statements
- (under the #ifdef TTY_DEBUG_WAIT_UNTIL_SENT)
-
- * serial.c (rs_interrupt, rs_interrupt_single, receive_chars,
- change_speed, rs_close): rs_close now disables receiver
- interrupts when closing the serial port. This allows the
- serial port to close quickly when Linux and a modem (or a
- mouse) are engaged in an echo war; when closing the serial
- port, we now first stop listening to incoming characters,
- and *then* wait for the transmit buffer to drain.
-
- In order to make this change, the info->read_status_mask
- is now used to control what bits of the line status
- register are looked at in the interrupt routine in all
- cases; previously it was only used in receive_chars to
- select a few of the status bits.
-
-Mon Oct 24 23:36:21 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * serial.c (rs_close): Add a timeout to the transmitter flush
- loop; this is just a sanity check in case we have flaky
- (or non-existent-but-configured-by-the-user) hardware.
-
-Fri Oct 21 09:37:23 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * tty_io.c (tty_fasync): When asynchronous I/O is enabled, if the
- process or process group has not be specified yet, set it
- to be the tty's process group, or if that is not yet set,
- to the current process's pid.
-
-Thu Oct 20 23:17:28 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * n_tty.c (n_tty_receive_room): If we are doing input
- canonicalization, let as many characters through as
- possible, so that the excess characters can be "beeped".
-
-Tue Oct 18 10:02:43 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * serial.c (rs_start): Removed an incorrect '!' that was
- preventing transmit interrupts from being re-enabled in
- rs_start(). Fortunately in most cases it would be
- re-enabled elsewhere, but this still should be fixed
- correctly.
-
-Sun Oct 9 23:46:03 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * tty_io.c (do_tty_hangup): If the tty driver flags
- TTY_DRIVER_RESET_TERMIOS is set, then reset the termios
- settings back to the driver's initial configuration. This
- allows the termios settings to be reset even if a process
- has hung up file descriptors keeping a pty's termios from
- being freed and reset.
-
- * tty_io.c (release_dev): Fix memory leak. The pty's other
- termios structure should also be freed.
-
- * serial.c (rs_close, shutdown): Change how we wait for the
- transmitter to completely drain before shutting down the
- serial port. We now do it by scheduling in another
- process instead of busy looping with the interrupts turned
- on. This may eliminate some race condition problems that
- some people seem to be reporting.
-
-Sun Sep 25 14:18:14 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * tty_io.c (release_dev): When freeing a tty make sure that both
- the tty and the o_tty (if present) aren't a process's
- controlling tty. (Previously, we only checked the tty.)
-
- * serial.c (change_speed): Only enable the Modem Status
- Interrupt for a port if CLOCAL is not set or CRTSCTS
- is set. If we're not checking the carrier detect and
- CTS line, there's no point in enabling the modem
- status interrupt. This will save spurious interrupts
- from slowing down systems who have terminals that
- don't support either line. (Of course, if you want
- only one of CD and CTS support, you will need a
- properly wired serial cable.)
-
-Thu Sep 22 08:32:48 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * tty_io.c (do_SAK): Return if tty is null.
-
- * tty_io.c (_tty_name): Return "NULL tty" if the passed in tty is
- NULL.
-
-Sat Sep 17 13:19:25 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * tty_ioctl.c (n_tty_ioctl): Fix TIOCGLCKTRMIOS and
- TIOCSLCKTRMIOS, which were totally broken. Remove
- extra indirection from argument; it should be a struct
- termios *, not a struct termios **.
- &real_tty->termios_locked should have been
- real_tty->termios_locked. This caused us to be
- reading and writing the termios_locked structure to
- random places in kernel memory.
-
- * tty_io.c (release_dev): Oops! Forgot to delete a critical kfree
- of the locked_termios. This leaves the locked_termios
- structure pointed at a freed object.
-
-Fri Sep 16 08:13:25 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * tty_io.c (tty_open): Don't check for an exclusive open until
- after the device specific open routine has been called.
- Otherwise, the serial device ref counting will be screwed
- up.
-
- * serial.c (rs_open, block_til_ready): Don't set termios structure
- until after block_til_ready has returned successfully.
- Modify block_til_ready to check the normal_termios
- structure directly, so it doesn't rely on termios being
- set before it's called.
-
-Thu Sep 15 23:34:01 1994 Theodore Y. Ts'o (tytso@rt-11)
-
- * serial.c (rs_close): Turn off interrupts during rs_close() to
- prevent a race condition with the hangup code (which
- runs during a software interrupt).
-
- * tty_io.c (release_dev): Don't free the locked_termios structure;
- its state must be retained across device opens.
-
-
- * tty_io.c (tty_unregister_driver): Added function to unregister a
- tty driver. (For loadable device drivers.)
-
-
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 31be3ac2e21b..3141dd3b6e53 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -666,10 +666,18 @@ config VIRTIO_CONSOLE
help
Virtio console for use with lguest and other hypervisors.
+ Also serves as a general-purpose serial device for data
+ transfer between the guest and host. Character devices at
+ /dev/vportNpn will be created when corresponding ports are
+ found, where N is the device number and n is the port number
+ within that device. If specified by the host, a sysfs
+ attribute called 'name' will be populated with a name for
+ the port which can be used by udev scripts to create a
+ symlink to the device.
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"
- depends on PPC_PSERIES
+ depends on PPC_PSERIES && HVC_CONSOLE
help
Partitionable IBM Power5 ppc64 machines allow hosting of
firmware virtual consoles from one Linux partition by
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index 2fb3a480f6b0..4b66c69eaf57 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -57,7 +57,7 @@ config AGP_AMD
config AGP_AMD64
tristate "AMD Opteron/Athlon64 on-CPU GART support"
- depends on AGP && X86
+ depends on AGP && X86 && K8_NB
help
This option gives you AGP support for the GLX component of
X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs.
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 5aa7a586a7ff..fd50ead59c79 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -725,14 +725,10 @@ static struct pci_driver agp_amd64_pci_driver = {
int __init agp_amd64_init(void)
{
int err = 0;
- static int done = 0;
if (agp_off)
return -EINVAL;
- if (done++)
- return agp_bridges_found ? 0 : -ENODEV;
-
err = pci_register_driver(&agp_amd64_pci_driver);
if (err < 0)
return err;
@@ -769,14 +765,27 @@ int __init agp_amd64_init(void)
return err;
}
+static int __init agp_amd64_mod_init(void)
+{
+#ifndef MODULE
+ if (gart_iommu_aperture)
+ return agp_bridges_found ? 0 : -ENODEV;
+#endif
+ return agp_amd64_init();
+}
+
static void __exit agp_amd64_cleanup(void)
{
+#ifndef MODULE
+ if (gart_iommu_aperture)
+ return;
+#endif
if (aperture_resource)
release_resource(aperture_resource);
pci_unregister_driver(&agp_amd64_pci_driver);
}
-module_init(agp_amd64_init);
+module_init(agp_amd64_mod_init);
module_exit(agp_amd64_cleanup);
MODULE_AUTHOR("Dave Jones <davej@redhat.com>, Andi Kleen");
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 30c36ac2cd00..a3e10dc7cc25 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -8,8 +8,12 @@
#include <linux/kernel.h>
#include <linux/pagemap.h>
#include <linux/agp_backend.h>
+#include <asm/smp.h>
#include "agp.h"
+int intel_agp_enabled;
+EXPORT_SYMBOL(intel_agp_enabled);
+
/*
* If we have Intel graphics, we're not going to have anything other than
* an Intel IOMMU. So make the correct use of the PCI DMA API contingent
@@ -64,6 +68,10 @@
#define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB 0x0062
#define PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB 0x006a
#define PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG 0x0046
+#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB 0x0100
+#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG 0x0102
+#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB 0x0104
+#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG 0x0106
/* cover 915 and 945 variants */
#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
@@ -98,7 +106,9 @@
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB)
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
extern int agp_memory_reserved;
@@ -147,6 +157,25 @@ extern int agp_memory_reserved;
#define INTEL_I7505_AGPCTRL 0x70
#define INTEL_I7505_MCHCFG 0x50
+#define SNB_GMCH_CTRL 0x50
+#define SNB_GMCH_GMS_STOLEN_MASK 0xF8
+#define SNB_GMCH_GMS_STOLEN_32M (1 << 3)
+#define SNB_GMCH_GMS_STOLEN_64M (2 << 3)
+#define SNB_GMCH_GMS_STOLEN_96M (3 << 3)
+#define SNB_GMCH_GMS_STOLEN_128M (4 << 3)
+#define SNB_GMCH_GMS_STOLEN_160M (5 << 3)
+#define SNB_GMCH_GMS_STOLEN_192M (6 << 3)
+#define SNB_GMCH_GMS_STOLEN_224M (7 << 3)
+#define SNB_GMCH_GMS_STOLEN_256M (8 << 3)
+#define SNB_GMCH_GMS_STOLEN_288M (9 << 3)
+#define SNB_GMCH_GMS_STOLEN_320M (0xa << 3)
+#define SNB_GMCH_GMS_STOLEN_352M (0xb << 3)
+#define SNB_GMCH_GMS_STOLEN_384M (0xc << 3)
+#define SNB_GMCH_GMS_STOLEN_416M (0xd << 3)
+#define SNB_GMCH_GMS_STOLEN_448M (0xe << 3)
+#define SNB_GMCH_GMS_STOLEN_480M (0xf << 3)
+#define SNB_GMCH_GMS_STOLEN_512M (0x10 << 3)
+
static const struct aper_size_info_fixed intel_i810_sizes[] =
{
{64, 16384, 4},
@@ -269,7 +298,7 @@ static void intel_agp_insert_sg_entries(struct agp_memory *mem,
j++;
}
} else {
- /* sg may merge pages, but we have to seperate
+ /* sg may merge pages, but we have to separate
* per-page addr for GTT */
unsigned int len, m;
@@ -293,6 +322,13 @@ static void intel_agp_insert_sg_entries(struct agp_memory *mem,
off_t pg_start, int mask_type)
{
int i, j;
+ u32 cache_bits = 0;
+
+ if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
+ {
+ cache_bits = I830_PTE_SYSTEM_CACHED;
+ }
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
@@ -613,7 +649,7 @@ static struct aper_size_info_fixed intel_i830_sizes[] =
static void intel_i830_init_gtt_entries(void)
{
u16 gmch_ctrl;
- int gtt_entries;
+ int gtt_entries = 0;
u8 rdct;
int local = 0;
static const int ddt[4] = { 0, 16, 32, 64 };
@@ -705,6 +741,63 @@ static void intel_i830_init_gtt_entries(void)
gtt_entries = 0;
break;
}
+ } else if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) {
+ /*
+ * SandyBridge has new memory control reg at 0x50.w
+ */
+ u16 snb_gmch_ctl;
+ pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+ switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
+ case SNB_GMCH_GMS_STOLEN_32M:
+ gtt_entries = MB(32) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_64M:
+ gtt_entries = MB(64) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_96M:
+ gtt_entries = MB(96) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_128M:
+ gtt_entries = MB(128) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_160M:
+ gtt_entries = MB(160) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_192M:
+ gtt_entries = MB(192) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_224M:
+ gtt_entries = MB(224) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_256M:
+ gtt_entries = MB(256) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_288M:
+ gtt_entries = MB(288) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_320M:
+ gtt_entries = MB(320) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_352M:
+ gtt_entries = MB(352) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_384M:
+ gtt_entries = MB(384) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_416M:
+ gtt_entries = MB(416) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_448M:
+ gtt_entries = MB(448) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_480M:
+ gtt_entries = MB(480) - KB(size);
+ break;
+ case SNB_GMCH_GMS_STOLEN_512M:
+ gtt_entries = MB(512) - KB(size);
+ break;
+ }
} else {
switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
case I855_GMCH_GMS_STOLEN_1M:
@@ -815,12 +908,6 @@ static void intel_i830_setup_flush(void)
intel_i830_fini_flush();
}
-static void
-do_wbinvd(void *null)
-{
- wbinvd();
-}
-
/* The chipset_flush interface needs to get data that has already been
* flushed out of the CPU all the way out to main memory, because the GPU
* doesn't snoop those buffers.
@@ -837,12 +924,10 @@ static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
memset(pg, 0, 1024);
- if (cpu_has_clflush) {
+ if (cpu_has_clflush)
clflush_cache_range(pg, 1024);
- } else {
- if (on_each_cpu(do_wbinvd, NULL, 1) != 0)
- printk(KERN_ERR "Timed out waiting for cache flush.\n");
- }
+ else if (wbinvd_on_all_cpus() != 0)
+ printk(KERN_ERR "Timed out waiting for cache flush.\n");
}
/* The intel i830 automatically initializes the agp aperture during POST.
@@ -1364,6 +1449,8 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB:
case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB:
case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB:
+ case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB:
+ case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB:
*gtt_offset = *gtt_size = MB(2);
break;
default:
@@ -2345,9 +2432,9 @@ static const struct intel_driver_description {
NULL, &intel_g33_driver },
{ PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33",
NULL, &intel_g33_driver },
- { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, 0, "Pineview",
+ { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, 0, "GMA3150",
NULL, &intel_g33_driver },
- { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, 0, "Pineview",
+ { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, 0, "GMA3150",
NULL, &intel_g33_driver },
{ PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, 0,
"GM45", NULL, &intel_i965_driver },
@@ -2362,13 +2449,17 @@ static const struct intel_driver_description {
{ PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0,
"G41", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 0,
- "Ironlake/D", NULL, &intel_i965_driver },
+ "HD Graphics", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
- "Ironlake/M", NULL, &intel_i965_driver },
+ "HD Graphics", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
- "Ironlake/MA", NULL, &intel_i965_driver },
+ "HD Graphics", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
- "Ironlake/MC2", NULL, &intel_i965_driver },
+ "HD Graphics", NULL, &intel_i965_driver },
+ { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG, 0,
+ "Sandybridge", NULL, &intel_i965_driver },
+ { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG, 0,
+ "Sandybridge", NULL, &intel_i965_driver },
{ 0, 0, 0, NULL, NULL, NULL }
};
@@ -2378,7 +2469,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
struct agp_bridge_data *bridge;
u8 cap_ptr = 0;
struct resource *r;
- int i;
+ int i, err;
cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
@@ -2460,13 +2551,20 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
&bridge->mode);
}
- if (bridge->driver->mask_memory == intel_i965_mask_memory)
+ if (bridge->driver->mask_memory == intel_i965_mask_memory) {
if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36)))
dev_err(&intel_private.pcidev->dev,
"set gfx device dma mask 36bit failed!\n");
+ else
+ pci_set_consistent_dma_mask(intel_private.pcidev,
+ DMA_BIT_MASK(36));
+ }
pci_set_drvdata(pdev, bridge);
- return agp_add_bridge(bridge);
+ err = agp_add_bridge(bridge);
+ if (!err)
+ intel_agp_enabled = 1;
+ return err;
}
static void __devexit agp_intel_remove(struct pci_dev *pdev)
@@ -2571,6 +2669,8 @@ static struct pci_device_id agp_intel_pci_table[] = {
ID(PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB),
ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB),
ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB),
+ ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB),
+ ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB),
{ }
};
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index fe2cb2f5db17..a7424bf7eacf 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -14,7 +14,7 @@
/* et passe en argument a acinit, mais est scrute sur le bus pour s'adapter */
/* au nombre de cartes presentes sur le bus. IOCL code 6 affichait V2.4.3 */
/* F.LAFORSE 28/11/95 creation de fichiers acXX.o avec les differentes */
-/* adresses de base des cartes, IOCTL 6 plus complet */
+/* addresses de base des cartes, IOCTL 6 plus complet */
/* J.PAGET le 19/08/96 copie de la version V2.6 en V2.8.0 sans modification */
/* de code autre que le texte V2.6.1 en V2.8.0 */
/*****************************************************************************/
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 4254457d3911..b861c08263a4 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -158,13 +158,11 @@ static unsigned int cy_isa_addresses[] = {
#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
-#ifdef MODULE
static long maddr[NR_CARDS];
static int irq[NR_CARDS];
module_param_array(maddr, long, NULL, 0);
module_param_array(irq, int, NULL, 0);
-#endif
#endif /* CONFIG_ISA */
@@ -598,12 +596,6 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
save_car = readb(base_addr + (CyCAR << index));
cy_writeb(base_addr + (CyCAR << index), save_xir);
- /* validate the port# (as configured and open) */
- if (channel + chip * 4 >= cinfo->nports) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) & ~CyTxRdy);
- goto end;
- }
info = &cinfo->ports[channel + chip * 4];
tty = tty_port_tty_get(&info->port);
if (tty == NULL) {
@@ -3316,13 +3308,10 @@ static int __init cy_detect_isa(void)
unsigned short cy_isa_irq, nboard;
void __iomem *cy_isa_address;
unsigned short i, j, cy_isa_nchan;
-#ifdef MODULE
int isparam = 0;
-#endif
nboard = 0;
-#ifdef MODULE
/* Check for module parameters */
for (i = 0; i < NR_CARDS; i++) {
if (maddr[i] || i) {
@@ -3332,7 +3321,6 @@ static int __init cy_detect_isa(void)
if (!maddr[i])
break;
}
-#endif
/* scan the address table probing for Cyclom-Y/ISA boards */
for (i = 0; i < NR_ISA_ADDRS; i++) {
@@ -3353,11 +3341,10 @@ static int __init cy_detect_isa(void)
iounmap(cy_isa_address);
continue;
}
-#ifdef MODULE
+
if (isparam && i < NR_CARDS && irq[i])
cy_isa_irq = irq[i];
else
-#endif
/* find out the board's irq by probing */
cy_isa_irq = detect_isa_irq(cy_isa_address);
if (cy_isa_irq == 0) {
@@ -4208,3 +4195,4 @@ module_exit(cy_cleanup_module);
MODULE_LICENSE("GPL");
MODULE_VERSION(CY_VERSION);
MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
+MODULE_FIRMWARE("cyzfirm.bin");
diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c
index 0afc8b82212e..5fe4631e2a61 100644
--- a/drivers/char/hvc_beat.c
+++ b/drivers/char/hvc_beat.c
@@ -84,7 +84,7 @@ static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt)
return cnt;
}
-static struct hv_ops hvc_beat_get_put_ops = {
+static const struct hv_ops hvc_beat_get_put_ops = {
.get_chars = hvc_beat_get_chars,
.put_chars = hvc_beat_put_chars,
};
@@ -99,7 +99,7 @@ static int hvc_beat_config(char *p)
static int __init hvc_beat_console_init(void)
{
- if (hvc_beat_useit && machine_is_compatible("Beat")) {
+ if (hvc_beat_useit && of_machine_is_compatible("Beat")) {
hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
}
return 0;
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 416d3423150d..465185fc0f52 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -125,7 +125,7 @@ static struct hvc_struct *hvc_get_by_index(int index)
* console interfaces but can still be used as a tty device. This has to be
* static because kmalloc will not work during early console init.
*/
-static struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES];
+static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES];
static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] =
{[0 ... MAX_NR_HVC_CONSOLES - 1] = -1};
@@ -146,7 +146,7 @@ static void hvc_console_print(struct console *co, const char *b,
return;
/* This console adapter was removed so it is not usable. */
- if (vtermnos[index] < 0)
+ if (vtermnos[index] == -1)
return;
while (count > 0 || i > 0) {
@@ -247,7 +247,7 @@ static void destroy_hvc_struct(struct kref *kref)
* vty adapters do NOT get an hvc_instantiate() callback since they
* appear after early console init.
*/
-int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
+int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
{
struct hvc_struct *hp;
@@ -748,8 +748,9 @@ static const struct tty_operations hvc_ops = {
.chars_in_buffer = hvc_chars_in_buffer,
};
-struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
- struct hv_ops *ops, int outbuf_size)
+struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
+ const struct hv_ops *ops,
+ int outbuf_size)
{
struct hvc_struct *hp;
int i;
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h
index 10950ca706d8..54381eba4e4a 100644
--- a/drivers/char/hvc_console.h
+++ b/drivers/char/hvc_console.h
@@ -55,7 +55,7 @@ struct hvc_struct {
int outbuf_size;
int n_outbuf;
uint32_t vtermno;
- struct hv_ops *ops;
+ const struct hv_ops *ops;
int irq_requested;
int data;
struct winsize ws;
@@ -76,11 +76,12 @@ struct hv_ops {
};
/* Register a vterm and a slot index for use as a console (console_init) */
-extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops);
+extern int hvc_instantiate(uint32_t vtermno, int index,
+ const struct hv_ops *ops);
/* register a vterm for hvc tty operation (module_init or hotplug add) */
-extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data,
- struct hv_ops *ops, int outbuf_size);
+extern struct hvc_struct * hvc_alloc(uint32_t vtermno, int data,
+ const struct hv_ops *ops, int outbuf_size);
/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */
extern int hvc_remove(struct hvc_struct *hp);
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index 936d05bf37fa..21c54955084e 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -197,7 +197,7 @@ done:
return sent;
}
-static struct hv_ops hvc_get_put_ops = {
+static const struct hv_ops hvc_get_put_ops = {
.get_chars = get_chars,
.put_chars = put_chars,
.notifier_add = notifier_add_irq,
@@ -353,7 +353,7 @@ static void hvc_close_event(struct HvLpEvent *event)
if (!hvlpevent_is_int(event)) {
printk(KERN_WARNING
- "hvc: got unexpected close acknowlegement\n");
+ "hvc: got unexpected close acknowledgement\n");
return;
}
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c
index fe62bd0e17b7..37b0542a4eeb 100644
--- a/drivers/char/hvc_iucv.c
+++ b/drivers/char/hvc_iucv.c
@@ -139,6 +139,8 @@ struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num)
*
* This function allocates a new struct iucv_tty_buffer element and, optionally,
* allocates an internal data buffer with the specified size @size.
+ * The internal data buffer is always allocated with GFP_DMA which is
+ * required for receiving and sending data with IUCV.
* Note: The total message size arises from the internal buffer size and the
* members of the iucv_tty_msg structure.
* The function returns NULL if memory allocation has failed.
@@ -154,7 +156,7 @@ static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags)
if (size > 0) {
bufp->msg.length = MSG_SIZE(size);
- bufp->mbuf = kmalloc(bufp->msg.length, flags);
+ bufp->mbuf = kmalloc(bufp->msg.length, flags | GFP_DMA);
if (!bufp->mbuf) {
mempool_free(bufp, hvc_iucv_mempool);
return NULL;
@@ -237,7 +239,7 @@ static int hvc_iucv_write(struct hvc_iucv_private *priv,
if (!rb->mbuf) { /* message not yet received ... */
/* allocate mem to store msg data; if no memory is available
* then leave the buffer on the list and re-try later */
- rb->mbuf = kmalloc(rb->msg.length, GFP_ATOMIC);
+ rb->mbuf = kmalloc(rb->msg.length, GFP_ATOMIC | GFP_DMA);
if (!rb->mbuf)
return -ENOMEM;
@@ -922,7 +924,7 @@ static int hvc_iucv_pm_restore_thaw(struct device *dev)
/* HVC operations */
-static struct hv_ops hvc_iucv_ops = {
+static const struct hv_ops hvc_iucv_ops = {
.get_chars = hvc_iucv_get_chars,
.put_chars = hvc_iucv_put_chars,
.notifier_add = hvc_iucv_notifier_add,
diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c
index 88590d040046..61c4a61558d9 100644
--- a/drivers/char/hvc_rtas.c
+++ b/drivers/char/hvc_rtas.c
@@ -71,7 +71,7 @@ static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count)
return i;
}
-static struct hv_ops hvc_rtas_get_put_ops = {
+static const struct hv_ops hvc_rtas_get_put_ops = {
.get_chars = hvc_rtas_read_console,
.put_chars = hvc_rtas_write_console,
};
diff --git a/drivers/char/hvc_udbg.c b/drivers/char/hvc_udbg.c
index bd63ba878a56..b0957e61a7be 100644
--- a/drivers/char/hvc_udbg.c
+++ b/drivers/char/hvc_udbg.c
@@ -58,7 +58,7 @@ static int hvc_udbg_get(uint32_t vtermno, char *buf, int count)
return i;
}
-static struct hv_ops hvc_udbg_ops = {
+static const struct hv_ops hvc_udbg_ops = {
.get_chars = hvc_udbg_get,
.put_chars = hvc_udbg_put,
};
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index 10be343d6ae7..27370e99c66f 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -77,7 +77,7 @@ static int filtered_get_chars(uint32_t vtermno, char *buf, int count)
return got;
}
-static struct hv_ops hvc_get_put_ops = {
+static const struct hv_ops hvc_get_put_ops = {
.get_chars = filtered_get_chars,
.put_chars = hvc_put_chars,
.notifier_add = notifier_add_irq,
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
index b1a71638c772..60446f82a3fc 100644
--- a/drivers/char/hvc_xen.c
+++ b/drivers/char/hvc_xen.c
@@ -122,7 +122,7 @@ static int read_console(uint32_t vtermno, char *buf, int len)
return recv;
}
-static struct hv_ops hvc_ops = {
+static const struct hv_ops hvc_ops = {
.get_chars = read_console,
.put_chars = write_console,
.notifier_add = notifier_add_irq,
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 87060266ef91..d31483c54883 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -114,7 +114,7 @@ config HW_RANDOM_IXP4XX
config HW_RANDOM_OMAP
tristate "OMAP Random Number Generator support"
- depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+ depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP2)
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -186,3 +186,15 @@ config HW_RANDOM_MXC_RNGA
module will be called mxc-rnga.
If unsure, say Y.
+
+config HW_RANDOM_NOMADIK
+ tristate "ST-Ericsson Nomadik Random Number Generator support"
+ depends on HW_RANDOM && PLAT_NOMADIK
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on ST-Ericsson SoCs (8815 and 8500).
+
+ To compile this driver as a module, choose M here: the
+ module will be called nomadik-rng.
+
+ If unsure, say Y.
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 5eeb1303f0d0..4273308aa1e3 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
+obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
index 9b3e09cd41f9..10f868eefaa6 100644
--- a/drivers/char/hw_random/n2-drv.c
+++ b/drivers/char/hw_random/n2-drv.c
@@ -71,7 +71,7 @@ MODULE_VERSION(DRV_MODULE_VERSION);
* x22 + x21 + x17 + x15 + x13 + x12 + x11 + x7 + x5 + x + 1
*
* The RNG_CTL_VCO value of each noise cell must be programmed
- * seperately. This is why 4 control register values must be provided
+ * separately. This is why 4 control register values must be provided
* to the hypervisor. During a write, the hypervisor writes them all,
* one at a time, to the actual RNG_CTL register. The first three
* values are used to setup the desired RNG_CTL_VCO for each entropy
diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c
new file mode 100644
index 000000000000..a8b4c4010144
--- /dev/null
+++ b/drivers/char/hw_random/nomadik-rng.c
@@ -0,0 +1,103 @@
+/*
+ * Nomadik RNG support
+ * Copyright 2009 Alessandro Rubini
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+
+static int nmk_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+ void __iomem *base = (void __iomem *)rng->priv;
+
+ /*
+ * The register is 32 bits and gives 16 random bits (low half).
+ * A subsequent read will delay the core for 400ns, so we just read
+ * once and accept the very unlikely very small delay, even if wait==0.
+ */
+ *(u16 *)data = __raw_readl(base + 8) & 0xffff;
+ return 2;
+}
+
+/* we have at most one RNG per machine, granted */
+static struct hwrng nmk_rng = {
+ .name = "nomadik",
+ .read = nmk_rng_read,
+};
+
+static int nmk_rng_probe(struct amba_device *dev, struct amba_id *id)
+{
+ void __iomem *base;
+ int ret;
+
+ ret = amba_request_regions(dev, dev->dev.init_name);
+ if (ret)
+ return ret;
+ ret = -ENOMEM;
+ base = ioremap(dev->res.start, resource_size(&dev->res));
+ if (!base)
+ goto out_release;
+ nmk_rng.priv = (unsigned long)base;
+ ret = hwrng_register(&nmk_rng);
+ if (ret)
+ goto out_unmap;
+ return 0;
+
+out_unmap:
+ iounmap(base);
+out_release:
+ amba_release_regions(dev);
+ return ret;
+}
+
+static int nmk_rng_remove(struct amba_device *dev)
+{
+ void __iomem *base = (void __iomem *)nmk_rng.priv;
+ hwrng_unregister(&nmk_rng);
+ iounmap(base);
+ amba_release_regions(dev);
+ return 0;
+}
+
+static struct amba_id nmk_rng_ids[] = {
+ {
+ .id = 0x000805e1,
+ .mask = 0x000fffff, /* top bits are rev and cfg: accept all */
+ },
+ {0, 0},
+};
+
+static struct amba_driver nmk_rng_driver = {
+ .drv = {
+ .owner = THIS_MODULE,
+ .name = "rng",
+ },
+ .probe = nmk_rng_probe,
+ .remove = nmk_rng_remove,
+ .id_table = nmk_rng_ids,
+};
+
+static int __init nmk_rng_init(void)
+{
+ return amba_driver_register(&nmk_rng_driver);
+}
+
+static void __devexit nmk_rng_exit(void)
+{
+ amba_driver_unregister(&nmk_rng_driver);
+}
+
+module_init(nmk_rng_init);
+module_exit(nmk_rng_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index bdaef8e94021..64fe0a793efd 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -114,7 +114,7 @@ static struct virtio_device_id id_table[] = {
{ 0 },
};
-static struct virtio_driver virtio_rng = {
+static struct virtio_driver virtio_rng_driver = {
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
@@ -124,12 +124,12 @@ static struct virtio_driver virtio_rng = {
static int __init init(void)
{
- return register_virtio_driver(&virtio_rng);
+ return register_virtio_driver(&virtio_rng_driver);
}
static void __exit fini(void)
{
- unregister_virtio_driver(&virtio_rng);
+ unregister_virtio_driver(&virtio_rng_driver);
}
module_init(init);
module_exit(fini);
diff --git a/drivers/char/ip2/i2hw.h b/drivers/char/ip2/i2hw.h
index 8aa6e7ab8d5b..c0ba6c05f0cd 100644
--- a/drivers/char/ip2/i2hw.h
+++ b/drivers/char/ip2/i2hw.h
@@ -559,7 +559,7 @@ Loadware may be sent to the board in two ways:
2) It may be hard-coded into your source by including a .h file (typically
supplied by Computone), which declares a data array and initializes every
- element. This acheives the same result as if an entire loadware file had
+ element. This achieves the same result as if an entire loadware file had
been read into the array.
This requires more data space in your program, but access to the file system
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 517271c762e6..911e1da6def2 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -208,6 +208,7 @@ static int DumpFifoBuffer( char __user *, int);
static void ip2_init_board(int, const struct firmware *);
static unsigned short find_eisa_board(int);
+static int ip2_setup(char *str);
/***************/
/* Static Data */
@@ -263,7 +264,7 @@ static int tracewrap;
/* Macros */
/**********/
-#if defined(MODULE) && defined(IP2DEBUG_OPEN)
+#ifdef IP2DEBUG_OPEN
#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \
tty->name,(pCh->flags), \
tty->count,/*GET_USE_COUNT(module)*/0,s)
@@ -285,7 +286,10 @@ MODULE_AUTHOR("Doug McNash");
MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
MODULE_LICENSE("GPL");
+#define MAX_CMD_STR 50
+
static int poll_only;
+static char cmd[MAX_CMD_STR];
static int Eisa_irq;
static int Eisa_slot;
@@ -309,6 +313,8 @@ module_param_array(io, int, NULL, 0);
MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards");
module_param(poll_only, bool, 0);
MODULE_PARM_DESC(poll_only, "Do not use card interrupts");
+module_param_string(ip2, cmd, MAX_CMD_STR, 0);
+MODULE_PARM_DESC(ip2, "Contains module parameter passed with 'ip2='");
/* for sysfs class support */
static struct class *ip2_class;
@@ -487,7 +493,6 @@ static const struct firmware *ip2_request_firmware(void)
return fw;
}
-#ifndef MODULE
/******************************************************************************
* ip2_setup:
* str: kernel command line string
@@ -531,7 +536,6 @@ static int __init ip2_setup(char *str)
return 1;
}
__setup("ip2=", ip2_setup);
-#endif /* !MODULE */
static int __init ip2_loadmain(void)
{
@@ -539,14 +543,20 @@ static int __init ip2_loadmain(void)
int err = 0;
i2eBordStrPtr pB = NULL;
int rc = -1;
- struct pci_dev *pdev = NULL;
const struct firmware *fw = NULL;
+ char *str;
+
+ str = cmd;
if (poll_only) {
/* Hard lock the interrupts to zero */
irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0;
}
+ /* Check module parameter with 'ip2=' has been passed or not */
+ if (!poll_only && (!strncmp(str, "ip2=", 4)))
+ ip2_setup(str);
+
ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0);
/* process command line arguments to modprobe or
@@ -612,6 +622,7 @@ static int __init ip2_loadmain(void)
case PCI:
#ifdef CONFIG_PCI
{
+ struct pci_dev *pdev = NULL;
u32 addr;
int status;
@@ -626,7 +637,7 @@ static int __init ip2_loadmain(void)
if (pci_enable_device(pdev)) {
dev_err(&pdev->dev, "can't enable device\n");
- break;
+ goto out;
}
ip2config.type[i] = PCI;
ip2config.pci_dev[i] = pci_dev_get(pdev);
@@ -638,6 +649,8 @@ static int __init ip2_loadmain(void)
dev_err(&pdev->dev, "I/O address error\n");
ip2config.irq[i] = pdev->irq;
+out:
+ pci_dev_put(pdev);
}
#else
printk(KERN_ERR "IP2: PCI card specified but PCI "
@@ -656,7 +669,6 @@ static int __init ip2_loadmain(void)
break;
} /* switch */
} /* for */
- pci_dev_put(pdev);
for (i = 0; i < IP2_MAX_BOARDS; ++i) {
if (ip2config.addr[i]) {
@@ -3197,3 +3209,5 @@ static struct pci_device_id ip2main_pci_tbl[] __devinitdata = {
};
MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl);
+
+MODULE_FIRMWARE("intelliport2.bin");
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 176f1751237f..4462b113ba3f 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -295,6 +295,9 @@ struct smi_info {
static int force_kipmid[SI_MAX_PARMS];
static int num_force_kipmid;
+static unsigned int kipmid_max_busy_us[SI_MAX_PARMS];
+static int num_max_busy_us;
+
static int unload_when_empty = 1;
static int try_smi_init(struct smi_info *smi);
@@ -925,23 +928,77 @@ static void set_run_to_completion(void *send_info, int i_run_to_completion)
}
}
+/*
+ * Use -1 in the nsec value of the busy waiting timespec to tell that
+ * we are spinning in kipmid looking for something and not delaying
+ * between checks
+ */
+static inline void ipmi_si_set_not_busy(struct timespec *ts)
+{
+ ts->tv_nsec = -1;
+}
+static inline int ipmi_si_is_busy(struct timespec *ts)
+{
+ return ts->tv_nsec != -1;
+}
+
+static int ipmi_thread_busy_wait(enum si_sm_result smi_result,
+ const struct smi_info *smi_info,
+ struct timespec *busy_until)
+{
+ unsigned int max_busy_us = 0;
+
+ if (smi_info->intf_num < num_max_busy_us)
+ max_busy_us = kipmid_max_busy_us[smi_info->intf_num];
+ if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY)
+ ipmi_si_set_not_busy(busy_until);
+ else if (!ipmi_si_is_busy(busy_until)) {
+ getnstimeofday(busy_until);
+ timespec_add_ns(busy_until, max_busy_us*NSEC_PER_USEC);
+ } else {
+ struct timespec now;
+ getnstimeofday(&now);
+ if (unlikely(timespec_compare(&now, busy_until) > 0)) {
+ ipmi_si_set_not_busy(busy_until);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+/*
+ * A busy-waiting loop for speeding up IPMI operation.
+ *
+ * Lousy hardware makes this hard. This is only enabled for systems
+ * that are not BT and do not have interrupts. It starts spinning
+ * when an operation is complete or until max_busy tells it to stop
+ * (if that is enabled). See the paragraph on kimid_max_busy_us in
+ * Documentation/IPMI.txt for details.
+ */
static int ipmi_thread(void *data)
{
struct smi_info *smi_info = data;
unsigned long flags;
enum si_sm_result smi_result;
+ struct timespec busy_until;
+ ipmi_si_set_not_busy(&busy_until);
set_user_nice(current, 19);
while (!kthread_should_stop()) {
+ int busy_wait;
+
spin_lock_irqsave(&(smi_info->si_lock), flags);
smi_result = smi_event_handler(smi_info, 0);
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+ busy_wait = ipmi_thread_busy_wait(smi_result, smi_info,
+ &busy_until);
if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
; /* do nothing */
- else if (smi_result == SI_SM_CALL_WITH_DELAY)
+ else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait)
schedule();
else
- schedule_timeout_interruptible(1);
+ schedule_timeout_interruptible(0);
}
return 0;
}
@@ -1144,7 +1201,7 @@ static int regsizes[SI_MAX_PARMS];
static unsigned int num_regsizes;
static int regshifts[SI_MAX_PARMS];
static unsigned int num_regshifts;
-static int slave_addrs[SI_MAX_PARMS];
+static int slave_addrs[SI_MAX_PARMS]; /* Leaving 0 chooses the default value */
static unsigned int num_slave_addrs;
#define IPMI_IO_ADDR_SPACE 0
@@ -1212,6 +1269,11 @@ module_param(unload_when_empty, int, 0);
MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are"
" specified or found, default is 1. Setting to 0"
" is useful for hot add of devices using hotmod.");
+module_param_array(kipmid_max_busy_us, uint, &num_max_busy_us, 0644);
+MODULE_PARM_DESC(kipmid_max_busy_us,
+ "Max time (in microseconds) to busy-wait for IPMI data before"
+ " sleeping. 0 (default) means to wait forever. Set to 100-500"
+ " if kipmid is using up a lot of CPU time.");
static void std_irq_cleanup(struct smi_info *info)
@@ -1607,7 +1669,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
regsize = 1;
regshift = 0;
irq = 0;
- ipmb = 0x20;
+ ipmb = 0; /* Choose the default if not specified */
next = strchr(curr, ':');
if (next) {
@@ -1799,6 +1861,7 @@ static __devinit void hardcode_find_bmc(void)
info->irq = irqs[i];
if (info->irq)
info->irq_setup = std_irq_setup;
+ info->slave_addr = slave_addrs[i];
try_smi_init(info);
}
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 300d5bd6cd06..be2e8f9a27c3 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -113,6 +113,8 @@
* 64-bit verification
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/kernel.h>
@@ -140,7 +142,6 @@
#define InterruptTheCard(base) outw(0, (base) + 0xc)
#define ClearInterrupt(base) inw((base) + 0x0a)
-#define pr_dbg(str...) pr_debug("ISICOM: " str)
#ifdef DEBUG
#define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c))
#else
@@ -249,8 +250,7 @@ static int lock_card(struct isi_board *card)
spin_unlock_irqrestore(&card->card_lock, card->flags);
msleep(10);
}
- printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%lx)\n",
- card->base);
+ pr_warning("Failed to lock Card (0x%lx)\n", card->base);
return 0; /* Failed to acquire the card! */
}
@@ -379,13 +379,13 @@ static inline int __isicom_paranoia_check(struct isi_port const *port,
char *name, const char *routine)
{
if (!port) {
- printk(KERN_WARNING "ISICOM: Warning: bad isicom magic for "
- "dev %s in %s.\n", name, routine);
+ pr_warning("Warning: bad isicom magic for dev %s in %s.\n",
+ name, routine);
return 1;
}
if (port->magic != ISICOM_MAGIC) {
- printk(KERN_WARNING "ISICOM: Warning: NULL isicom port for "
- "dev %s in %s.\n", name, routine);
+ pr_warning("Warning: NULL isicom port for dev %s in %s.\n",
+ name, routine);
return 1;
}
@@ -450,8 +450,8 @@ static void isicom_tx(unsigned long _data)
if (!(inw(base + 0x02) & (1 << port->channel)))
continue;
- pr_dbg("txing %d bytes, port%d.\n", txcount,
- port->channel + 1);
+ pr_debug("txing %d bytes, port%d.\n",
+ txcount, port->channel + 1);
outw((port->channel << isi_card[card].shift_count) | txcount,
base);
residue = NO;
@@ -547,8 +547,8 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
byte_count = header & 0xff;
if (channel + 1 > card->port_count) {
- printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): "
- "%d(channel) > port_count.\n", base, channel+1);
+ pr_warning("%s(0x%lx): %d(channel) > port_count.\n",
+ __func__, base, channel+1);
outw(0x0000, base+0x04); /* enable interrupts */
spin_unlock(&card->card_lock);
return IRQ_HANDLED;
@@ -582,14 +582,15 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
if (port->status & ISI_DCD) {
if (!(header & ISI_DCD)) {
/* Carrier has been lost */
- pr_dbg("interrupt: DCD->low.\n"
- );
+ pr_debug("%s: DCD->low.\n",
+ __func__);
port->status &= ~ISI_DCD;
tty_hangup(tty);
}
} else if (header & ISI_DCD) {
/* Carrier has been detected */
- pr_dbg("interrupt: DCD->high.\n");
+ pr_debug("%s: DCD->high.\n",
+ __func__);
port->status |= ISI_DCD;
wake_up_interruptible(&port->port.open_wait);
}
@@ -641,17 +642,19 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
break;
case 2: /* Statistics */
- pr_dbg("isicom_interrupt: stats!!!.\n");
+ pr_debug("%s: stats!!!\n", __func__);
break;
default:
- pr_dbg("Intr: Unknown code in status packet.\n");
+ pr_debug("%s: Unknown code in status packet.\n",
+ __func__);
break;
}
} else { /* Data Packet */
count = tty_prepare_flip_string(tty, &rp, byte_count & ~1);
- pr_dbg("Intr: Can rx %d of %d bytes.\n", count, byte_count);
+ pr_debug("%s: Can rx %d of %d bytes.\n",
+ __func__, count, byte_count);
word_count = count >> 1;
insw(base, rp, word_count);
byte_count -= (word_count << 1);
@@ -661,8 +664,8 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
byte_count -= 2;
}
if (byte_count > 0) {
- pr_dbg("Intr(0x%lx:%d): Flip buffer overflow! dropping "
- "bytes...\n", base, channel + 1);
+ pr_debug("%s(0x%lx:%d): Flip buffer overflow! dropping bytes...\n",
+ __func__, base, channel + 1);
/* drain out unread xtra data */
while (byte_count > 0) {
inw(base);
@@ -888,8 +891,8 @@ static void isicom_shutdown_port(struct isi_port *port)
struct isi_board *card = port->card;
if (--card->count < 0) {
- pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n",
- card->base, card->count);
+ pr_debug("%s: bad board(0x%lx) count %d.\n",
+ __func__, card->base, card->count);
card->count = 0;
}
/* last port was closed, shutdown that board too */
@@ -1681,13 +1684,13 @@ static int __init isicom_init(void)
retval = tty_register_driver(isicom_normal);
if (retval) {
- pr_dbg("Couldn't register the dialin driver\n");
+ pr_debug("Couldn't register the dialin driver\n");
goto err_puttty;
}
retval = pci_register_driver(&isicom_driver);
if (retval < 0) {
- printk(KERN_ERR "ISICOM: Unable to register pci driver.\n");
+ pr_err("Unable to register pci driver.\n");
goto err_unrtty;
}
@@ -1717,3 +1720,8 @@ module_exit(isicom_exit);
MODULE_AUTHOR("MultiTech");
MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("isi608.bin");
+MODULE_FIRMWARE("isi608em.bin");
+MODULE_FIRMWARE("isi616em.bin");
+MODULE_FIRMWARE("isi4608.bin");
+MODULE_FIRMWARE("isi4616.bin");
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index f706b1dffdb3..ada25bb8941e 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -1185,11 +1185,6 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
rep = (down == 2);
-#ifdef CONFIG_MAC_EMUMOUSEBTN
- if (mac_hid_mouse_emulate_buttons(1, keycode, down))
- return;
-#endif /* CONFIG_MAC_EMUMOUSEBTN */
-
if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
if (emulate_raw(vc, keycode, !down << 7))
if (keycode < BTN_MISC && printk_ratelimit())
@@ -1328,6 +1323,21 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
schedule_console_callback();
}
+static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
+{
+ int i;
+
+ if (test_bit(EV_SND, dev->evbit))
+ return true;
+
+ if (test_bit(EV_KEY, dev->evbit))
+ for (i = KEY_RESERVED; i < BTN_MISC; i++)
+ if (test_bit(i, dev->keybit))
+ return true;
+
+ return false;
+}
+
/*
* When a keyboard (or other input device) is found, the kbd_connect
* function is called. The function then looks at the device, and if it
@@ -1339,14 +1349,6 @@ static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
{
struct input_handle *handle;
int error;
- int i;
-
- for (i = KEY_RESERVED; i < BTN_MISC; i++)
- if (test_bit(i, dev->keybit))
- break;
-
- if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
- return -ENODEV;
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle)
@@ -1412,6 +1414,7 @@ MODULE_DEVICE_TABLE(input, kbd_ids);
static struct input_handler kbd_handler = {
.event = kbd_event,
+ .match = kbd_match,
.connect = kbd_connect,
.disconnect = kbd_disconnect,
.start = kbd_start,
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index be832b6f8279..1f3215ac085b 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
- * Added devfs support.
+ * Added devfs support.
* Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>
* Shared /dev/zero mmapping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
*/
@@ -44,36 +44,6 @@ static inline unsigned long size_inside_page(unsigned long start,
return min(sz, size);
}
-/*
- * Architectures vary in how they handle caching for addresses
- * outside of main memory.
- *
- */
-static inline int uncached_access(struct file *file, unsigned long addr)
-{
-#if defined(CONFIG_IA64)
- /*
- * On ia64, we ignore O_DSYNC because we cannot tolerate memory attribute aliases.
- */
- return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
-#elif defined(CONFIG_MIPS)
- {
- extern int __uncached_access(struct file *file,
- unsigned long addr);
-
- return __uncached_access(file, addr);
- }
-#else
- /*
- * Accessing memory above the top the kernel knows about or through a file pointer
- * that was marked O_DSYNC will be done non-cached.
- */
- if (file->f_flags & O_DSYNC)
- return 1;
- return addr >= __pa(high_memory);
-#endif
-}
-
#ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE
static inline int valid_phys_addr_range(unsigned long addr, size_t count)
{
@@ -115,15 +85,15 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
}
#endif
-void __attribute__((weak)) unxlate_dev_mem_ptr(unsigned long phys, void *addr)
+void __weak unxlate_dev_mem_ptr(unsigned long phys, void *addr)
{
}
/*
- * This funcion reads the *physical* memory. The f_pos points directly to the
- * memory location.
+ * This funcion reads the *physical* memory. The f_pos points directly to the
+ * memory location.
*/
-static ssize_t read_mem(struct file * file, char __user * buf,
+static ssize_t read_mem(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
@@ -140,10 +110,10 @@ static ssize_t read_mem(struct file * file, char __user * buf,
if (sz > 0) {
if (clear_user(buf, sz))
return -EFAULT;
- buf += sz;
- p += sz;
- count -= sz;
- read += sz;
+ buf += sz;
+ p += sz;
+ count -= sz;
+ read += sz;
}
}
#endif
@@ -157,9 +127,9 @@ static ssize_t read_mem(struct file * file, char __user * buf,
return -EPERM;
/*
- * On ia64 if a page has been mapped somewhere as
- * uncached, then it must also be accessed uncached
- * by the kernel or data corruption may occur
+ * On ia64 if a page has been mapped somewhere as uncached, then
+ * it must also be accessed uncached by the kernel or data
+ * corruption may occur.
*/
ptr = xlate_dev_mem_ptr(p);
if (!ptr)
@@ -180,7 +150,7 @@ static ssize_t read_mem(struct file * file, char __user * buf,
return read;
}
-static ssize_t write_mem(struct file * file, const char __user * buf,
+static ssize_t write_mem(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
@@ -212,9 +182,9 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
return -EPERM;
/*
- * On ia64 if a page has been mapped somewhere as
- * uncached, then it must also be accessed uncached
- * by the kernel or data corruption may occur
+ * On ia64 if a page has been mapped somewhere as uncached, then
+ * it must also be accessed uncached by the kernel or data
+ * corruption may occur.
*/
ptr = xlate_dev_mem_ptr(p);
if (!ptr) {
@@ -242,13 +212,46 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
return written;
}
-int __attribute__((weak)) phys_mem_access_prot_allowed(struct file *file,
+int __weak phys_mem_access_prot_allowed(struct file *file,
unsigned long pfn, unsigned long size, pgprot_t *vma_prot)
{
return 1;
}
#ifndef __HAVE_PHYS_MEM_ACCESS_PROT
+
+/*
+ * Architectures vary in how they handle caching for addresses
+ * outside of main memory.
+ *
+ */
+static int uncached_access(struct file *file, unsigned long addr)
+{
+#if defined(CONFIG_IA64)
+ /*
+ * On ia64, we ignore O_DSYNC because we cannot tolerate memory
+ * attribute aliases.
+ */
+ return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
+#elif defined(CONFIG_MIPS)
+ {
+ extern int __uncached_access(struct file *file,
+ unsigned long addr);
+
+ return __uncached_access(file, addr);
+ }
+#else
+ /*
+ * Accessing memory above the top the kernel knows about or through a
+ * file pointer
+ * that was marked O_DSYNC will be done non-cached.
+ */
+ if (file->f_flags & O_DSYNC)
+ return 1;
+ return addr >= __pa(high_memory);
+#endif
+}
+
static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
unsigned long size, pgprot_t vma_prot)
{
@@ -294,7 +297,7 @@ static const struct vm_operations_struct mmap_mem_ops = {
#endif
};
-static int mmap_mem(struct file * file, struct vm_area_struct * vma)
+static int mmap_mem(struct file *file, struct vm_area_struct *vma)
{
size_t size = vma->vm_end - vma->vm_start;
@@ -329,7 +332,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
}
#ifdef CONFIG_DEVKMEM
-static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
+static int mmap_kmem(struct file *file, struct vm_area_struct *vma)
{
unsigned long pfn;
@@ -337,9 +340,9 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT;
/*
- * RED-PEN: on some architectures there is more mapped memory
- * than available in mem_map which pfn_valid checks
- * for. Perhaps should add a new macro here.
+ * RED-PEN: on some architectures there is more mapped memory than
+ * available in mem_map which pfn_valid checks for. Perhaps should add a
+ * new macro here.
*
* RED-PEN: vmalloc is not supported right now.
*/
@@ -389,18 +392,19 @@ static ssize_t read_oldmem(struct file *file, char __user *buf,
/*
* This function reads the *virtual* memory as seen by the kernel.
*/
-static ssize_t read_kmem(struct file *file, char __user *buf,
+static ssize_t read_kmem(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
ssize_t low_count, read, sz;
char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
+ int err = 0;
read = 0;
if (p < (unsigned long) high_memory) {
low_count = count;
- if (count > (unsigned long) high_memory - p)
- low_count = (unsigned long) high_memory - p;
+ if (count > (unsigned long)high_memory - p)
+ low_count = (unsigned long)high_memory - p;
#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
/* we don't have page 0 mapped on sparc and m68k.. */
@@ -441,12 +445,16 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
return -ENOMEM;
while (count > 0) {
sz = size_inside_page(p, count);
+ if (!is_vmalloc_or_module_addr((void *)p)) {
+ err = -ENXIO;
+ break;
+ }
sz = vread(kbuf, (char *)p, sz);
if (!sz)
break;
if (copy_to_user(buf, kbuf, sz)) {
- free_page((unsigned long)kbuf);
- return -EFAULT;
+ err = -EFAULT;
+ break;
}
count -= sz;
buf += sz;
@@ -455,14 +463,13 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
}
free_page((unsigned long)kbuf);
}
- *ppos = p;
- return read;
+ *ppos = p;
+ return read ? read : err;
}
-static inline ssize_t
-do_write_kmem(unsigned long p, const char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t do_write_kmem(unsigned long p, const char __user *buf,
+ size_t count, loff_t *ppos)
{
ssize_t written, sz;
unsigned long copied;
@@ -486,9 +493,9 @@ do_write_kmem(unsigned long p, const char __user *buf,
sz = size_inside_page(p, count);
/*
- * On ia64 if a page has been mapped somewhere as
- * uncached, then it must also be accessed uncached
- * by the kernel or data corruption may occur
+ * On ia64 if a page has been mapped somewhere as uncached, then
+ * it must also be accessed uncached by the kernel or data
+ * corruption may occur.
*/
ptr = xlate_dev_kmem_ptr((char *)p);
@@ -509,17 +516,17 @@ do_write_kmem(unsigned long p, const char __user *buf,
return written;
}
-
/*
* This function writes to the *virtual* memory as seen by the kernel.
*/
-static ssize_t write_kmem(struct file * file, const char __user * buf,
+static ssize_t write_kmem(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
ssize_t wrote = 0;
ssize_t virtr = 0;
char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
+ int err = 0;
if (p < (unsigned long) high_memory) {
unsigned long to_write = min_t(unsigned long, count,
@@ -540,14 +547,16 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
unsigned long sz = size_inside_page(p, count);
unsigned long n;
+ if (!is_vmalloc_or_module_addr((void *)p)) {
+ err = -ENXIO;
+ break;
+ }
n = copy_from_user(kbuf, buf, sz);
if (n) {
- if (wrote + virtr)
- break;
- free_page((unsigned long)kbuf);
- return -EFAULT;
+ err = -EFAULT;
+ break;
}
- sz = vwrite(kbuf, (char *)p, sz);
+ vwrite(kbuf, (char *)p, sz);
count -= sz;
buf += sz;
virtr += sz;
@@ -556,23 +565,23 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
free_page((unsigned long)kbuf);
}
- *ppos = p;
- return virtr + wrote;
+ *ppos = p;
+ return virtr + wrote ? : err;
}
#endif
#ifdef CONFIG_DEVPORT
-static ssize_t read_port(struct file * file, char __user * buf,
+static ssize_t read_port(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long i = *ppos;
char __user *tmp = buf;
if (!access_ok(VERIFY_WRITE, buf, count))
- return -EFAULT;
+ return -EFAULT;
while (count-- > 0 && i < 65536) {
- if (__put_user(inb(i),tmp) < 0)
- return -EFAULT;
+ if (__put_user(inb(i), tmp) < 0)
+ return -EFAULT;
i++;
tmp++;
}
@@ -580,22 +589,22 @@ static ssize_t read_port(struct file * file, char __user * buf,
return tmp-buf;
}
-static ssize_t write_port(struct file * file, const char __user * buf,
+static ssize_t write_port(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long i = *ppos;
const char __user * tmp = buf;
- if (!access_ok(VERIFY_READ,buf,count))
+ if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;
while (count-- > 0 && i < 65536) {
char c;
if (__get_user(c, tmp)) {
if (tmp > buf)
break;
- return -EFAULT;
+ return -EFAULT;
}
- outb(c,i);
+ outb(c, i);
i++;
tmp++;
}
@@ -604,13 +613,13 @@ static ssize_t write_port(struct file * file, const char __user * buf,
}
#endif
-static ssize_t read_null(struct file * file, char __user * buf,
+static ssize_t read_null(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
return 0;
}
-static ssize_t write_null(struct file * file, const char __user * buf,
+static ssize_t write_null(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
return count;
@@ -622,13 +631,13 @@ static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf,
return sd->len;
}
-static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out,
+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);
}
-static ssize_t read_zero(struct file * file, char __user * buf,
+static ssize_t read_zero(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
size_t written;
@@ -659,7 +668,7 @@ static ssize_t read_zero(struct file * file, char __user * buf,
return written ? written : -EFAULT;
}
-static int mmap_zero(struct file * file, struct vm_area_struct * vma)
+static int mmap_zero(struct file *file, struct vm_area_struct *vma)
{
#ifndef CONFIG_MMU
return -ENOSYS;
@@ -669,7 +678,7 @@ static int mmap_zero(struct file * file, struct vm_area_struct * vma)
return 0;
}
-static ssize_t write_full(struct file * file, const char __user * buf,
+static ssize_t write_full(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
return -ENOSPC;
@@ -680,8 +689,7 @@ static ssize_t write_full(struct file * file, const char __user * buf,
* can fopen() both devices with "a" now. This was previously impossible.
* -- SRB.
*/
-
-static loff_t null_lseek(struct file * file, loff_t offset, int orig)
+static loff_t null_lseek(struct file *file, loff_t offset, int orig)
{
return file->f_pos = 0;
}
@@ -694,24 +702,31 @@ static loff_t null_lseek(struct file * file, loff_t offset, int orig)
* also note that seeking relative to the "end of file" isn't supported:
* it has no meaning, so it returns -EINVAL.
*/
-static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
+static loff_t memory_lseek(struct file *file, loff_t offset, int orig)
{
loff_t ret;
mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
switch (orig) {
- case 0:
- file->f_pos = offset;
- ret = file->f_pos;
- force_successful_syscall_return();
+ case SEEK_CUR:
+ offset += file->f_pos;
+ if ((unsigned long long)offset <
+ (unsigned long long)file->f_pos) {
+ ret = -EOVERFLOW;
break;
- case 1:
- file->f_pos += offset;
- ret = file->f_pos;
- force_successful_syscall_return();
+ }
+ case SEEK_SET:
+ /* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */
+ if ((unsigned long long)offset >= ~0xFFFULL) {
+ ret = -EOVERFLOW;
break;
- default:
- ret = -EINVAL;
+ }
+ file->f_pos = offset;
+ ret = file->f_pos;
+ force_successful_syscall_return();
+ break;
+ default:
+ ret = -EINVAL;
}
mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return ret;
@@ -795,7 +810,7 @@ static const struct file_operations oldmem_fops = {
};
#endif
-static ssize_t kmsg_write(struct file * file, const char __user * buf,
+static ssize_t kmsg_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char *tmp;
@@ -817,7 +832,7 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf,
}
static const struct file_operations kmsg_fops = {
- .write = kmsg_write,
+ .write = kmsg_write,
};
static const struct memdev {
@@ -868,7 +883,7 @@ static int memory_open(struct inode *inode, struct file *filp)
}
static const struct file_operations memory_fops = {
- .open = memory_open,
+ .open = memory_open,
};
static char *mem_devnode(struct device *dev, mode_t *mode)
@@ -889,7 +904,7 @@ static int __init chr_dev_init(void)
if (err)
return err;
- if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
+ if (register_chrdev(MEM_MAJOR, "mem", &memory_fops))
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
mem_class = class_create(THIS_MODULE, "mem");
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index 918711aa56f3..04fd0d843b3b 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -546,7 +546,7 @@ static void mmtimer_tasklet(unsigned long data)
{
int nodeid = data;
struct mmtimer_node *mn = &timers[nodeid];
- struct mmtimer *x = rb_entry(mn->next, struct mmtimer, list);
+ struct mmtimer *x;
struct k_itimer *t;
unsigned long flags;
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 63ee3bbc1ce4..166495d6a1d7 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -164,24 +164,25 @@ static unsigned int moxaFuncTout = HZ / 2;
static unsigned int moxaLowWaterChk;
static DEFINE_MUTEX(moxa_openlock);
static DEFINE_SPINLOCK(moxa_lock);
-/* Variables for insmod */
-#ifdef MODULE
+
static unsigned long baseaddr[MAX_BOARDS];
static unsigned int type[MAX_BOARDS];
static unsigned int numports[MAX_BOARDS];
-#endif
MODULE_AUTHOR("William Chen");
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
MODULE_LICENSE("GPL");
-#ifdef MODULE
+MODULE_FIRMWARE("c218tunx.cod");
+MODULE_FIRMWARE("cp204unx.cod");
+MODULE_FIRMWARE("c320tunx.cod");
+
module_param_array(type, uint, NULL, 0);
MODULE_PARM_DESC(type, "card type: C218=2, C320=4");
module_param_array(baseaddr, ulong, NULL, 0);
MODULE_PARM_DESC(baseaddr, "base address");
module_param_array(numports, uint, NULL, 0);
MODULE_PARM_DESC(numports, "numports (ignored for C218)");
-#endif
+
module_param(ttymajor, int, 0);
/*
@@ -1024,6 +1025,8 @@ static int __init moxa_init(void)
{
unsigned int isabrds = 0;
int retval = 0;
+ struct moxa_board_conf *brd = moxa_boards;
+ unsigned int i;
printk(KERN_INFO "MOXA Intellio family driver version %s\n",
MOXA_VERSION);
@@ -1051,10 +1054,7 @@ static int __init moxa_init(void)
}
/* Find the boards defined from module args. */
-#ifdef MODULE
- {
- struct moxa_board_conf *brd = moxa_boards;
- unsigned int i;
+
for (i = 0; i < MAX_BOARDS; i++) {
if (!baseaddr[i])
break;
@@ -1087,8 +1087,6 @@ static int __init moxa_init(void)
isabrds++;
}
}
- }
-#endif
#ifdef CONFIG_PCI
retval = pci_register_driver(&moxa_pci_driver);
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 3d923065d9a2..e0c5d2a69046 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -895,8 +895,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
if (inb(info->ioaddr + UART_LSR) == 0xff) {
spin_unlock_irqrestore(&info->slock, flags);
if (capable(CAP_SYS_ADMIN)) {
- if (tty)
- set_bit(TTY_IO_ERROR, &tty->flags);
+ set_bit(TTY_IO_ERROR, &tty->flags);
return 0;
} else
return -ENODEV;
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 2e50f4dfc79c..bdae8327143c 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -48,6 +48,7 @@
#include <linux/audit.h>
#include <linux/file.h>
#include <linux/uaccess.h>
+#include <linux/module.h>
#include <asm/system.h>
@@ -2091,3 +2092,19 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
.receive_buf = n_tty_receive_buf,
.write_wakeup = n_tty_write_wakeup
};
+
+/**
+ * n_tty_inherit_ops - inherit N_TTY methods
+ * @ops: struct tty_ldisc_ops where to save N_TTY methods
+ *
+ * Used by a generic struct tty_ldisc_ops to easily inherit N_TTY
+ * methods.
+ */
+
+void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
+{
+ *ops = tty_ldisc_N_TTY;
+ ops->owner = NULL;
+ ops->refcount = ops->flags = 0;
+}
+EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
index 7d73cd430340..a3f32a15fde4 100644
--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -136,10 +136,6 @@ static int debug;
#define RECEIVE_BUF_MAX 4
-/* Define all types of vendors and devices to support */
-#define VENDOR1 0x1931 /* Vendor Option */
-#define DEVICE1 0x000c /* HSDPA card */
-
#define R_IIR 0x0000 /* Interrupt Identity Register */
#define R_FCR 0x0000 /* Flow Control Register */
#define R_IER 0x0004 /* Interrupt Enable Register */
@@ -371,6 +367,8 @@ struct port {
struct mutex tty_sem;
wait_queue_head_t tty_wait;
struct async_icount tty_icount;
+
+ struct nozomi *dc;
};
/* Private data one for each card in the system */
@@ -405,7 +403,7 @@ struct buffer {
/* Global variables */
static const struct pci_device_id nozomi_pci_tbl[] __devinitconst = {
- {PCI_DEVICE(VENDOR1, DEVICE1)},
+ {PCI_DEVICE(0x1931, 0x000c)}, /* Nozomi HSDPA */
{},
};
@@ -414,6 +412,8 @@ MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl);
static struct nozomi *ndevs[NOZOMI_MAX_CARDS];
static struct tty_driver *ntty_driver;
+static const struct tty_port_operations noz_tty_port_ops;
+
/*
* find card by tty_index
*/
@@ -853,8 +853,6 @@ static int receive_data(enum port_type index, struct nozomi *dc)
goto put;
}
- tty_buffer_request_room(tty, size);
-
while (size > 0) {
read_mem32((u32 *) buf, addr + offset, RECEIVE_BUF_MAX);
@@ -1473,9 +1471,11 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
for (i = 0; i < MAX_PORT; i++) {
struct device *tty_dev;
-
- mutex_init(&dc->port[i].tty_sem);
- tty_port_init(&dc->port[i].port);
+ struct port *port = &dc->port[i];
+ port->dc = dc;
+ mutex_init(&port->tty_sem);
+ tty_port_init(&port->port);
+ port->port.ops = &noz_tty_port_ops;
tty_dev = tty_register_device(ntty_driver, dc->index_start + i,
&pdev->dev);
@@ -1600,67 +1600,74 @@ static void set_dtr(const struct tty_struct *tty, int dtr)
* ----------------------------------------------------------------------------
*/
-/* Called when the userspace process opens the tty, /dev/noz*. */
-static int ntty_open(struct tty_struct *tty, struct file *file)
+static int ntty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct port *port = get_port_by_tty(tty);
struct nozomi *dc = get_dc_by_tty(tty);
- unsigned long flags;
-
+ int ret;
if (!port || !dc || dc->state != NOZOMI_STATE_READY)
return -ENODEV;
-
- if (mutex_lock_interruptible(&port->tty_sem))
- return -ERESTARTSYS;
-
- port->port.count++;
- dc->open_ttys++;
-
- /* Enable interrupt downlink for channel */
- if (port->port.count == 1) {
- tty->driver_data = port;
- tty_port_tty_set(&port->port, tty);
- DBG1("open: %d", port->token_dl);
- spin_lock_irqsave(&dc->spin_mutex, flags);
- dc->last_ier = dc->last_ier | port->token_dl;
- writew(dc->last_ier, dc->reg_ier);
- spin_unlock_irqrestore(&dc->spin_mutex, flags);
+ ret = tty_init_termios(tty);
+ if (ret == 0) {
+ tty_driver_kref_get(driver);
+ driver->ttys[tty->index] = tty;
}
- mutex_unlock(&port->tty_sem);
- return 0;
+ return ret;
}
-/* Called when the userspace process close the tty, /dev/noz*. Also
- called immediately if ntty_open fails in which case tty->driver_data
- will be NULL an we exit by the first return */
+static void ntty_cleanup(struct tty_struct *tty)
+{
+ tty->driver_data = NULL;
+}
-static void ntty_close(struct tty_struct *tty, struct file *file)
+static int ntty_activate(struct tty_port *tport, struct tty_struct *tty)
{
- struct nozomi *dc = get_dc_by_tty(tty);
- struct port *nport = tty->driver_data;
- struct tty_port *port = &nport->port;
+ struct port *port = container_of(tport, struct port, port);
+ struct nozomi *dc = port->dc;
unsigned long flags;
- if (!dc || !nport)
- return;
+ DBG1("open: %d", port->token_dl);
+ spin_lock_irqsave(&dc->spin_mutex, flags);
+ dc->last_ier = dc->last_ier | port->token_dl;
+ writew(dc->last_ier, dc->reg_ier);
+ dc->open_ttys++;
+ spin_unlock_irqrestore(&dc->spin_mutex, flags);
+ printk("noz: activated %d: %p\n", tty->index, tport);
+ return 0;
+}
- /* Users cannot interrupt a close */
- mutex_lock(&nport->tty_sem);
+static int ntty_open(struct tty_struct *tty, struct file *filp)
+{
+ struct port *port = get_port_by_tty(tty);
+ return tty_port_open(&port->port, tty, filp);
+}
- WARN_ON(!port->count);
+static void ntty_shutdown(struct tty_port *tport)
+{
+ struct port *port = container_of(tport, struct port, port);
+ struct nozomi *dc = port->dc;
+ unsigned long flags;
+ DBG1("close: %d", port->token_dl);
+ spin_lock_irqsave(&dc->spin_mutex, flags);
+ dc->last_ier &= ~(port->token_dl);
+ writew(dc->last_ier, dc->reg_ier);
dc->open_ttys--;
- port->count--;
- tty_port_tty_set(port, NULL);
+ spin_unlock_irqrestore(&dc->spin_mutex, flags);
+ printk("noz: shutdown %p\n", tport);
+}
- if (port->count == 0) {
- DBG1("close: %d", nport->token_dl);
- spin_lock_irqsave(&dc->spin_mutex, flags);
- dc->last_ier &= ~(nport->token_dl);
- writew(dc->last_ier, dc->reg_ier);
- spin_unlock_irqrestore(&dc->spin_mutex, flags);
- }
- mutex_unlock(&nport->tty_sem);
+static void ntty_close(struct tty_struct *tty, struct file *filp)
+{
+ struct port *port = tty->driver_data;
+ if (port)
+ tty_port_close(&port->port, tty, filp);
+}
+
+static void ntty_hangup(struct tty_struct *tty)
+{
+ struct port *port = tty->driver_data;
+ tty_port_hangup(&port->port);
}
/*
@@ -1680,15 +1687,7 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer,
if (!dc || !port)
return -ENODEV;
- if (unlikely(!mutex_trylock(&port->tty_sem))) {
- /*
- * must test lock as tty layer wraps calls
- * to this function with BKL
- */
- dev_err(&dc->pdev->dev, "Would have deadlocked - "
- "return EAGAIN\n");
- return -EAGAIN;
- }
+ mutex_lock(&port->tty_sem);
if (unlikely(!port->port.count)) {
DBG1(" ");
@@ -1728,25 +1727,23 @@ exit:
* This method is called by the upper tty layer.
* #according to sources N_TTY.c it expects a value >= 0 and
* does not check for negative values.
+ *
+ * If the port is unplugged report lots of room and let the bits
+ * dribble away so we don't block anything.
*/
static int ntty_write_room(struct tty_struct *tty)
{
struct port *port = tty->driver_data;
- int room = 0;
+ int room = 4096;
const struct nozomi *dc = get_dc_by_tty(tty);
- if (!dc || !port)
- return 0;
- if (!mutex_trylock(&port->tty_sem))
- return 0;
-
- if (!port->port.count)
- goto exit;
-
- room = port->fifo_ul.size - kfifo_len(&port->fifo_ul);
-
-exit:
- mutex_unlock(&port->tty_sem);
+ if (dc) {
+ mutex_lock(&port->tty_sem);
+ if (port->port.count)
+ room = port->fifo_ul.size -
+ kfifo_len(&port->fifo_ul);
+ mutex_unlock(&port->tty_sem);
+ }
return room;
}
@@ -1906,10 +1903,16 @@ exit_in_buffer:
return rval;
}
+static const struct tty_port_operations noz_tty_port_ops = {
+ .activate = ntty_activate,
+ .shutdown = ntty_shutdown,
+};
+
static const struct tty_operations tty_ops = {
.ioctl = ntty_ioctl,
.open = ntty_open,
.close = ntty_close,
+ .hangup = ntty_hangup,
.write = ntty_write,
.write_room = ntty_write_room,
.unthrottle = ntty_unthrottle,
@@ -1917,6 +1920,8 @@ static const struct tty_operations tty_ops = {
.chars_in_buffer = ntty_chars_in_buffer,
.tiocmget = ntty_tiocmget,
.tiocmset = ntty_tiocmset,
+ .install = ntty_install,
+ .cleanup = ntty_cleanup,
};
/* Module initialization */
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index fdbcc9fd6d31..5eb83c3ca20d 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -336,14 +336,12 @@ static int nvram_ioctl(struct inode *inode, struct file *file,
static int nvram_open(struct inode *inode, struct file *file)
{
- lock_kernel();
spin_lock(&nvram_state_lock);
if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
(nvram_open_mode & NVRAM_EXCL) ||
((file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE))) {
spin_unlock(&nvram_state_lock);
- unlock_kernel();
return -EBUSY;
}
@@ -354,7 +352,6 @@ static int nvram_open(struct inode *inode, struct file *file)
nvram_open_cnt++;
spin_unlock(&nvram_state_lock);
- unlock_kernel();
return 0;
}
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 2db4c0a29b05..c9bc896d68af 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -1047,7 +1047,7 @@ release_io:
static ssize_t cmm_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct cm4000_dev *dev = (struct cm4000_dev *) filp->private_data;
+ struct cm4000_dev *dev = filp->private_data;
unsigned int iobase = dev->p_dev->io.BasePort1;
unsigned short s;
unsigned char tmp;
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 385c44b3034f..5ee424817263 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -220,7 +220,7 @@ static void pty_set_termios(struct tty_struct *tty,
* @tty: tty being resized
* @ws: window size being set.
*
- * Update the termios variables and send the neccessary signals to
+ * Update the termios variables and send the necessary signals to
* peform a terminal resize correctly
*/
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 8258982b49ec..2fd3d39995d5 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1051,12 +1051,6 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
/* like a named pipe */
}
- /*
- * If we gave the user some bytes, update the access time.
- */
- if (count)
- file_accessed(file);
-
return (count ? count : retval);
}
@@ -1107,7 +1101,6 @@ static ssize_t random_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
size_t ret;
- struct inode *inode = file->f_path.dentry->d_inode;
ret = write_pool(&blocking_pool, buffer, count);
if (ret)
@@ -1116,8 +1109,6 @@ static ssize_t random_write(struct file *file, const char __user *buffer,
if (ret)
return ret;
- inode->i_mtime = current_fs_time(inode->i_sb);
- mark_inode_dirty(inode);
return (ssize_t)count;
}
@@ -1200,7 +1191,7 @@ const struct file_operations urandom_fops = {
void generate_random_uuid(unsigned char uuid_out[16])
{
get_random_bytes(uuid_out, 16);
- /* Set UUID version to 4 --- truely random generation */
+ /* Set UUID version to 4 --- truly random generation */
uuid_out[6] = (uuid_out[6] & 0x0F) | 0x40;
/* Set the UUID variant to DCE */
uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80;
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index 452370af95de..1ec3d5cd748f 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -658,8 +658,7 @@ static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
info->mon.char_max = char_count;
info->mon.char_last = char_count;
#endif
- len = tty_buffer_request_room(tty, char_count);
- while (len--) {
+ while (char_count--) {
data = base_addr[CyRDR];
tty_insert_flip_char(tty, data, TTY_NORMAL);
#ifdef CYCLOM_16Y_HACK
@@ -1990,7 +1989,7 @@ void mvme167_serial_console_setup(int cflag)
/*
* Attempt to set up all channels to something reasonable, and
* bang out a INIT_CHAN command. We should then be able to limit
- * the ammount of fiddling we have to do in normal running.
+ * the amount of fiddling we have to do in normal running.
*/
for (ch = 3; ch >= 0; ch--) {
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 268e17f9ec3f..07ac14d949ce 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -646,8 +646,6 @@ static void sx_receive(struct specialix_board *bp)
dprintk(SX_DEBUG_RX, "port: %p: count: %d\n", port, count);
port->hits[count > 8 ? 9 : count]++;
- tty_buffer_request_room(tty, count);
-
while (count--)
tty_insert_flip_char(tty, sx_in(bp, CD186x_RDR), TTY_NORMAL);
tty_flip_buffer_push(tty);
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 4846b73ef28d..0658fc548222 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -2031,7 +2031,7 @@ static int mgsl_put_char(struct tty_struct *tty, unsigned char ch)
if (mgsl_paranoia_check(info, tty->name, "mgsl_put_char"))
return 0;
- if (!tty || !info->xmit_buf)
+ if (!info->xmit_buf)
return 0;
spin_lock_irqsave(&info->irq_spinlock, flags);
@@ -2121,7 +2121,7 @@ static int mgsl_write(struct tty_struct * tty,
if (mgsl_paranoia_check(info, tty->name, "mgsl_write"))
goto cleanup;
- if (!tty || !info->xmit_buf)
+ if (!info->xmit_buf)
goto cleanup;
if ( info->params.mode == MGSL_MODE_HDLC ||
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 8678f0c8699d..4561ce2fba6d 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -468,7 +468,7 @@ static unsigned int free_tbuf_count(struct slgt_info *info);
static unsigned int tbuf_bytes(struct slgt_info *info);
static void reset_tbufs(struct slgt_info *info);
static void tdma_reset(struct slgt_info *info);
-static void tx_load(struct slgt_info *info, const char *buf, unsigned int count);
+static bool tx_load(struct slgt_info *info, const char *buf, unsigned int count);
static void get_signals(struct slgt_info *info);
static void set_signals(struct slgt_info *info);
@@ -813,59 +813,32 @@ static int write(struct tty_struct *tty,
int ret = 0;
struct slgt_info *info = tty->driver_data;
unsigned long flags;
- unsigned int bufs_needed;
if (sanity_check(info, tty->name, "write"))
- goto cleanup;
+ return -EIO;
+
DBGINFO(("%s write count=%d\n", info->device_name, count));
- if (!info->tx_buf)
- goto cleanup;
+ if (!info->tx_buf || (count > info->max_frame_size))
+ return -EIO;
- if (count > info->max_frame_size) {
- ret = -EIO;
- goto cleanup;
- }
+ if (!count || tty->stopped || tty->hw_stopped)
+ return 0;
- if (!count)
- goto cleanup;
+ spin_lock_irqsave(&info->lock, flags);
- if (!info->tx_active && info->tx_count) {
+ if (info->tx_count) {
/* send accumulated data from send_char() */
- tx_load(info, info->tx_buf, info->tx_count);
- goto start;
+ if (!tx_load(info, info->tx_buf, info->tx_count))
+ goto cleanup;
+ info->tx_count = 0;
}
- bufs_needed = (count/DMABUFSIZE);
- if (count % DMABUFSIZE)
- ++bufs_needed;
- if (bufs_needed > free_tbuf_count(info))
- goto cleanup;
- ret = info->tx_count = count;
- tx_load(info, buf, count);
- goto start;
-
-start:
- if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
- spin_lock_irqsave(&info->lock,flags);
- if (!info->tx_active)
- tx_start(info);
- else if (!(rd_reg32(info, TDCSR) & BIT0)) {
- /* transmit still active but transmit DMA stopped */
- unsigned int i = info->tbuf_current;
- if (!i)
- i = info->tbuf_count;
- i--;
- /* if DMA buf unsent must try later after tx idle */
- if (desc_count(info->tbufs[i]))
- ret = 0;
- }
- if (ret > 0)
- update_tx_timer(info);
- spin_unlock_irqrestore(&info->lock,flags);
- }
+ if (tx_load(info, buf, count))
+ ret = count;
cleanup:
+ spin_unlock_irqrestore(&info->lock, flags);
DBGINFO(("%s write rc=%d\n", info->device_name, ret));
return ret;
}
@@ -882,7 +855,7 @@ static int put_char(struct tty_struct *tty, unsigned char ch)
if (!info->tx_buf)
return 0;
spin_lock_irqsave(&info->lock,flags);
- if (!info->tx_active && (info->tx_count < info->max_frame_size)) {
+ if (info->tx_count < info->max_frame_size) {
info->tx_buf[info->tx_count++] = ch;
ret = 1;
}
@@ -981,10 +954,8 @@ static void flush_chars(struct tty_struct *tty)
DBGINFO(("%s flush_chars start transmit\n", info->device_name));
spin_lock_irqsave(&info->lock,flags);
- if (!info->tx_active && info->tx_count) {
- tx_load(info, info->tx_buf,info->tx_count);
- tx_start(info);
- }
+ if (info->tx_count && tx_load(info, info->tx_buf, info->tx_count))
+ info->tx_count = 0;
spin_unlock_irqrestore(&info->lock,flags);
}
@@ -997,10 +968,9 @@ static void flush_buffer(struct tty_struct *tty)
return;
DBGINFO(("%s flush_buffer\n", info->device_name));
- spin_lock_irqsave(&info->lock,flags);
- if (!info->tx_active)
- info->tx_count = 0;
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
+ info->tx_count = 0;
+ spin_unlock_irqrestore(&info->lock, flags);
tty_wakeup(tty);
}
@@ -1033,12 +1003,10 @@ static void tx_release(struct tty_struct *tty)
if (sanity_check(info, tty->name, "tx_release"))
return;
DBGINFO(("%s tx_release\n", info->device_name));
- spin_lock_irqsave(&info->lock,flags);
- if (!info->tx_active && info->tx_count) {
- tx_load(info, info->tx_buf, info->tx_count);
- tx_start(info);
- }
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
+ if (info->tx_count && tx_load(info, info->tx_buf, info->tx_count))
+ info->tx_count = 0;
+ spin_unlock_irqrestore(&info->lock, flags);
}
/*
@@ -1506,27 +1474,25 @@ static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb,
DBGINFO(("%s hdlc_xmit\n", dev->name));
+ if (!skb->len)
+ return NETDEV_TX_OK;
+
/* stop sending until this frame completes */
netif_stop_queue(dev);
- /* copy data to device buffers */
- info->tx_count = skb->len;
- tx_load(info, skb->data, skb->len);
-
/* update network statistics */
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
- /* done with socket buffer, so free it */
- dev_kfree_skb(skb);
-
/* save start time for transmit timeout detection */
dev->trans_start = jiffies;
- spin_lock_irqsave(&info->lock,flags);
- tx_start(info);
- update_tx_timer(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
+ tx_load(info, skb->data, skb->len);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ /* done with socket buffer, so free it */
+ dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -2180,7 +2146,7 @@ static void isr_serial(struct slgt_info *info)
if (info->params.mode == MGSL_MODE_ASYNC) {
if (status & IRQ_TXIDLE) {
- if (info->tx_count)
+ if (info->tx_active)
isr_txeom(info, status);
}
if (info->rx_pio && (status & IRQ_RXDATA))
@@ -2276,13 +2242,42 @@ static void isr_tdma(struct slgt_info *info)
}
}
+/*
+ * return true if there are unsent tx DMA buffers, otherwise false
+ *
+ * if there are unsent buffers then info->tbuf_start
+ * is set to index of first unsent buffer
+ */
+static bool unsent_tbufs(struct slgt_info *info)
+{
+ unsigned int i = info->tbuf_current;
+ bool rc = false;
+
+ /*
+ * search backwards from last loaded buffer (precedes tbuf_current)
+ * for first unsent buffer (desc_count > 0)
+ */
+
+ do {
+ if (i)
+ i--;
+ else
+ i = info->tbuf_count - 1;
+ if (!desc_count(info->tbufs[i]))
+ break;
+ info->tbuf_start = i;
+ rc = true;
+ } while (i != info->tbuf_current);
+
+ return rc;
+}
+
static void isr_txeom(struct slgt_info *info, unsigned short status)
{
DBGISR(("%s txeom status=%04x\n", info->device_name, status));
slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER);
tdma_reset(info);
- reset_tbufs(info);
if (status & IRQ_TXUNDER) {
unsigned short val = rd_reg16(info, TCR);
wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */
@@ -2297,8 +2292,12 @@ static void isr_txeom(struct slgt_info *info, unsigned short status)
info->icount.txok++;
}
+ if (unsent_tbufs(info)) {
+ tx_start(info);
+ update_tx_timer(info);
+ return;
+ }
info->tx_active = false;
- info->tx_count = 0;
del_timer(&info->tx_timer);
@@ -3949,7 +3948,7 @@ static void tx_start(struct slgt_info *info)
info->tx_enabled = true;
}
- if (info->tx_count) {
+ if (desc_count(info->tbufs[info->tbuf_start])) {
info->drop_rts_on_tx_done = false;
if (info->params.mode != MGSL_MODE_ASYNC) {
@@ -4772,25 +4771,36 @@ static unsigned int tbuf_bytes(struct slgt_info *info)
}
/*
- * load transmit DMA buffer(s) with data
+ * load data into transmit DMA buffer ring and start transmitter if needed
+ * return true if data accepted, otherwise false (buffers full)
*/
-static void tx_load(struct slgt_info *info, const char *buf, unsigned int size)
+static bool tx_load(struct slgt_info *info, const char *buf, unsigned int size)
{
unsigned short count;
unsigned int i;
struct slgt_desc *d;
- if (size == 0)
- return;
+ /* check required buffer space */
+ if (DIV_ROUND_UP(size, DMABUFSIZE) > free_tbuf_count(info))
+ return false;
DBGDATA(info, buf, size, "tx");
+ /*
+ * copy data to one or more DMA buffers in circular ring
+ * tbuf_start = first buffer for this data
+ * tbuf_current = next free buffer
+ *
+ * Copy all data before making data visible to DMA controller by
+ * setting descriptor count of the first buffer.
+ * This prevents an active DMA controller from reading the first DMA
+ * buffers of a frame and stopping before the final buffers are filled.
+ */
+
info->tbuf_start = i = info->tbuf_current;
while (size) {
d = &info->tbufs[i];
- if (++i == info->tbuf_count)
- i = 0;
count = (unsigned short)((size > DMABUFSIZE) ? DMABUFSIZE : size);
memcpy(d->buf, buf, count);
@@ -4808,11 +4818,27 @@ static void tx_load(struct slgt_info *info, const char *buf, unsigned int size)
else
set_desc_eof(*d, 0);
- set_desc_count(*d, count);
+ /* set descriptor count for all but first buffer */
+ if (i != info->tbuf_start)
+ set_desc_count(*d, count);
d->buf_count = count;
+
+ if (++i == info->tbuf_count)
+ i = 0;
}
info->tbuf_current = i;
+
+ /* set first buffer count to make new data visible to DMA controller */
+ d = &info->tbufs[info->tbuf_start];
+ set_desc_count(*d, d->buf_count);
+
+ /* start transmitter if needed and update transmit timeout */
+ if (!info->tx_active)
+ tx_start(info);
+ update_tx_timer(info);
+
+ return true;
}
static int register_test(struct slgt_info *info)
@@ -4934,9 +4960,7 @@ static int loopback_test(struct slgt_info *info)
spin_lock_irqsave(&info->lock,flags);
async_mode(info);
rx_start(info);
- info->tx_count = count;
tx_load(info, buf, count);
- tx_start(info);
spin_unlock_irqrestore(&info->lock, flags);
/* wait for receive complete */
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index ecba4942fc8e..f58440791e65 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -39,12 +39,12 @@
struct tpm_inf_dev {
int iotype;
- void __iomem *mem_base; /* MMIO ioremap'd addr */
- unsigned long map_base; /* phys MMIO base */
- unsigned long map_size; /* MMIO region size */
- unsigned int index_off; /* index register offset */
+ void __iomem *mem_base; /* MMIO ioremap'd addr */
+ unsigned long map_base; /* phys MMIO base */
+ unsigned long map_size; /* MMIO region size */
+ unsigned int index_off; /* index register offset */
- unsigned int data_regs; /* Data registers */
+ unsigned int data_regs; /* Data registers */
unsigned int data_size;
unsigned int config_port; /* IO Port config index reg */
@@ -406,14 +406,14 @@ static const struct tpm_vendor_specific tpm_inf = {
.miscdev = {.fops = &inf_ops,},
};
-static const struct pnp_device_id tpm_pnp_tbl[] = {
+static const struct pnp_device_id tpm_inf_pnp_tbl[] = {
/* Infineon TPMs */
{"IFX0101", 0},
{"IFX0102", 0},
{"", 0}
};
-MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
+MODULE_DEVICE_TABLE(pnp, tpm_inf_pnp_tbl);
static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
const struct pnp_device_id *dev_id)
@@ -430,7 +430,7 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
!(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) {
- tpm_dev.iotype = TPM_INF_IO_PORT;
+ tpm_dev.iotype = TPM_INF_IO_PORT;
tpm_dev.config_port = pnp_port_start(dev, 0);
tpm_dev.config_size = pnp_port_len(dev, 0);
@@ -459,9 +459,9 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
goto err_last;
}
} else if (pnp_mem_valid(dev, 0) &&
- !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) {
+ !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) {
- tpm_dev.iotype = TPM_INF_IO_MEM;
+ tpm_dev.iotype = TPM_INF_IO_MEM;
tpm_dev.map_base = pnp_mem_start(dev, 0);
tpm_dev.map_size = pnp_mem_len(dev, 0);
@@ -563,11 +563,11 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
"product id 0x%02x%02x"
"%s\n",
tpm_dev.iotype == TPM_INF_IO_PORT ?
- tpm_dev.config_port :
- tpm_dev.map_base + tpm_dev.index_off,
+ tpm_dev.config_port :
+ tpm_dev.map_base + tpm_dev.index_off,
tpm_dev.iotype == TPM_INF_IO_PORT ?
- tpm_dev.data_regs :
- tpm_dev.map_base + tpm_dev.data_regs,
+ tpm_dev.data_regs :
+ tpm_dev.map_base + tpm_dev.data_regs,
version[0], version[1],
vendorid[0], vendorid[1],
productid[0], productid[1], chipname);
@@ -607,20 +607,55 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev)
iounmap(tpm_dev.mem_base);
release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
}
+ tpm_dev_vendor_release(chip);
tpm_remove_hardware(chip->dev);
}
}
+static int tpm_inf_pnp_suspend(struct pnp_dev *dev, pm_message_t pm_state)
+{
+ struct tpm_chip *chip = pnp_get_drvdata(dev);
+ int rc;
+ if (chip) {
+ u8 savestate[] = {
+ 0, 193, /* TPM_TAG_RQU_COMMAND */
+ 0, 0, 0, 10, /* blob length (in bytes) */
+ 0, 0, 0, 152 /* TPM_ORD_SaveState */
+ };
+ dev_info(&dev->dev, "saving TPM state\n");
+ rc = tpm_inf_send(chip, savestate, sizeof(savestate));
+ if (rc < 0) {
+ dev_err(&dev->dev, "error while saving TPM state\n");
+ return rc;
+ }
+ }
+ return 0;
+}
+
+static int tpm_inf_pnp_resume(struct pnp_dev *dev)
+{
+ /* Re-configure TPM after suspending */
+ tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
+ tpm_config_out(IOLIMH, TPM_INF_ADDR);
+ tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA);
+ tpm_config_out(IOLIML, TPM_INF_ADDR);
+ tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA);
+ /* activate register */
+ tpm_config_out(TPM_DAR, TPM_INF_ADDR);
+ tpm_config_out(0x01, TPM_INF_DATA);
+ tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
+ /* disable RESET, LP and IRQC */
+ tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
+ return tpm_pm_resume(&dev->dev);
+}
+
static struct pnp_driver tpm_inf_pnp_driver = {
.name = "tpm_inf_pnp",
- .driver = {
- .owner = THIS_MODULE,
- .suspend = tpm_pm_suspend,
- .resume = tpm_pm_resume,
- },
- .id_table = tpm_pnp_tbl,
+ .id_table = tpm_inf_pnp_tbl,
.probe = tpm_inf_pnp_probe,
- .remove = __devexit_p(tpm_inf_pnp_remove),
+ .suspend = tpm_inf_pnp_suspend,
+ .resume = tpm_inf_pnp_resume,
+ .remove = __devexit_p(tpm_inf_pnp_remove)
};
static int __init init_inf(void)
@@ -638,5 +673,5 @@ module_exit(cleanup_inf);
MODULE_AUTHOR("Marcel Selhorst <m.selhorst@sirrix.com>");
MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
-MODULE_VERSION("1.9");
+MODULE_VERSION("1.9.2");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
index ac16fbec72d0..283a15bc84e3 100644
--- a/drivers/char/tty_audit.c
+++ b/drivers/char/tty_audit.c
@@ -148,7 +148,6 @@ void tty_audit_fork(struct signal_struct *sig)
spin_lock_irq(&current->sighand->siglock);
sig->audit_tty = current->signal->audit_tty;
spin_unlock_irq(&current->sighand->siglock);
- sig->tty_audit_buf = NULL;
}
/**
diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c
index 66fa4e10d76b..af8d97715728 100644
--- a/drivers/char/tty_buffer.c
+++ b/drivers/char/tty_buffer.c
@@ -231,9 +231,10 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
/**
- * tty_insert_flip_string - Add characters to the tty buffer
+ * tty_insert_flip_string_fixed_flag - Add characters to the tty buffer
* @tty: tty structure
* @chars: characters
+ * @flag: flag value for each character
* @size: size
*
* Queue a series of bytes to the tty buffering. All the characters
@@ -242,18 +243,19 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room);
* Locking: Called functions may take tty->buf.lock
*/
-int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
- size_t size)
+int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
+ const unsigned char *chars, char flag, size_t size)
{
int copied = 0;
do {
- int space = tty_buffer_request_room(tty, size - copied);
+ int goal = min(size - copied, TTY_BUFFER_PAGE);
+ int space = tty_buffer_request_room(tty, goal);
struct tty_buffer *tb = tty->buf.tail;
/* If there is no space then tb may be NULL */
if (unlikely(space == 0))
break;
memcpy(tb->char_buf_ptr + tb->used, chars, space);
- memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+ memset(tb->flag_buf_ptr + tb->used, flag, space);
tb->used += space;
copied += space;
chars += space;
@@ -262,7 +264,7 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
} while (unlikely(size > copied));
return copied;
}
-EXPORT_SYMBOL(tty_insert_flip_string);
+EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
/**
* tty_insert_flip_string_flags - Add characters to the tty buffer
@@ -283,7 +285,8 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
{
int copied = 0;
do {
- int space = tty_buffer_request_room(tty, size - copied);
+ int goal = min(size - copied, TTY_BUFFER_PAGE);
+ int space = tty_buffer_request_room(tty, goal);
struct tty_buffer *tb = tty->buf.tail;
/* If there is no space then tb may be NULL */
if (unlikely(space == 0))
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index f15df40bc318..a42c466f7092 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1951,8 +1951,10 @@ static int tty_fasync(int fd, struct file *filp, int on)
pid = task_pid(current);
type = PIDTYPE_PID;
}
+ get_pid(pid);
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
retval = __f_setown(filp, pid, type, 0);
+ put_pid(pid);
if (retval)
goto out;
} else {
@@ -2026,7 +2028,7 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
* @rows: rows (character)
* @cols: cols (character)
*
- * Update the termios variables and send the neccessary signals to
+ * Update the termios variables and send the necessary signals to
* peform a terminal resize correctly
*/
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index 3f653f7d849f..500e740ec5e4 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -706,12 +706,13 @@ static void tty_reset_termios(struct tty_struct *tty)
/**
* tty_ldisc_reinit - reinitialise the tty ldisc
* @tty: tty to reinit
+ * @ldisc: line discipline to reinitialize
*
- * Switch the tty back to N_TTY line discipline and leave the
- * ldisc state closed
+ * Switch the tty to a line discipline and leave the ldisc
+ * state closed
*/
-static void tty_ldisc_reinit(struct tty_struct *tty)
+static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
{
struct tty_ldisc *ld;
@@ -721,10 +722,10 @@ static void tty_ldisc_reinit(struct tty_struct *tty)
/*
* Switch the line discipline back
*/
- ld = tty_ldisc_get(N_TTY);
+ ld = tty_ldisc_get(ldisc);
BUG_ON(IS_ERR(ld));
tty_ldisc_assign(tty, ld);
- tty_set_termios_ldisc(tty, N_TTY);
+ tty_set_termios_ldisc(tty, ldisc);
}
/**
@@ -745,6 +746,8 @@ static void tty_ldisc_reinit(struct tty_struct *tty)
void tty_ldisc_hangup(struct tty_struct *tty)
{
struct tty_ldisc *ld;
+ int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
+ int err = 0;
/*
* FIXME! What are the locking issues here? This may me overdoing
@@ -772,25 +775,32 @@ void tty_ldisc_hangup(struct tty_struct *tty)
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
/*
* Shutdown the current line discipline, and reset it to
- * N_TTY.
+ * N_TTY if need be.
+ *
+ * Avoid racing set_ldisc or tty_ldisc_release
*/
- if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
- /* Avoid racing set_ldisc or tty_ldisc_release */
- mutex_lock(&tty->ldisc_mutex);
- tty_ldisc_halt(tty);
- if (tty->ldisc) { /* Not yet closed */
- /* Switch back to N_TTY */
- tty_ldisc_reinit(tty);
- /* At this point we have a closed ldisc and we want to
- reopen it. We could defer this to the next open but
- it means auditing a lot of other paths so this is
- a FIXME */
+ mutex_lock(&tty->ldisc_mutex);
+ tty_ldisc_halt(tty);
+ /* At this point we have a closed ldisc and we want to
+ reopen it. We could defer this to the next open but
+ it means auditing a lot of other paths so this is
+ a FIXME */
+ if (tty->ldisc) { /* Not yet closed */
+ if (reset == 0) {
+ tty_ldisc_reinit(tty, tty->termios->c_line);
+ err = tty_ldisc_open(tty, tty->ldisc);
+ }
+ /* If the re-open fails or we reset then go to N_TTY. The
+ N_TTY open cannot fail */
+ if (reset || err) {
+ tty_ldisc_reinit(tty, N_TTY);
WARN_ON(tty_ldisc_open(tty, tty->ldisc));
- tty_ldisc_enable(tty);
}
- mutex_unlock(&tty->ldisc_mutex);
- tty_reset_termios(tty);
+ tty_ldisc_enable(tty);
}
+ mutex_unlock(&tty->ldisc_mutex);
+ if (reset)
+ tty_reset_termios(tty);
}
/**
diff --git a/drivers/char/uv_mmtimer.c b/drivers/char/uv_mmtimer.c
index 867b67be9f0a..c7072ba14f48 100644
--- a/drivers/char/uv_mmtimer.c
+++ b/drivers/char/uv_mmtimer.c
@@ -89,13 +89,17 @@ static long uv_mmtimer_ioctl(struct file *file, unsigned int cmd,
switch (cmd) {
case MMTIMER_GETOFFSET: /* offset of the counter */
/*
- * UV RTC register is on its own page
+ * Starting with HUB rev 2.0, the UV RTC register is
+ * replicated across all cachelines of it's own page.
+ * This allows faster simultaneous reads from a given socket.
+ *
+ * The offset returned is in 64 bit units.
*/
- if (PAGE_SIZE <= (1 << 16))
- ret = ((UV_LOCAL_MMR_BASE | UVH_RTC) & (PAGE_SIZE-1))
- / 8;
+ if (uv_get_min_hub_revision_id() == 1)
+ ret = 0;
else
- ret = -ENOSYS;
+ ret = ((uv_blade_processor_id() * L1_CACHE_BYTES) %
+ PAGE_SIZE) / 8;
break;
case MMTIMER_GETRES: /* resolution of the clock in 10^-15 s */
@@ -115,8 +119,8 @@ static long uv_mmtimer_ioctl(struct file *file, unsigned int cmd,
ret = hweight64(UVH_RTC_REAL_TIME_CLOCK_MASK);
break;
- case MMTIMER_MMAPAVAIL: /* can we mmap the clock into userspace? */
- ret = (PAGE_SIZE <= (1 << 16)) ? 1 : 0;
+ case MMTIMER_MMAPAVAIL:
+ ret = 1;
break;
case MMTIMER_GETCOUNTER:
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index a035ae39a359..f404ccfc9c20 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1,18 +1,6 @@
-/*D:300
- * The Guest console driver
- *
- * Writing console drivers is one of the few remaining Dark Arts in Linux.
- * Fortunately for us, the path of virtual consoles has been well-trodden by
- * the PowerPC folks, who wrote "hvc_console.c" to generically support any
- * virtual console. We use that infrastructure which only requires us to write
- * the basic put_chars and get_chars functions and call the right register
- * functions.
- :*/
-
-/*M:002 The console can be flooded: while the Guest is processing input the
- * Host can send more. Buffering in the Host could alleviate this, but it is a
- * difficult problem in general. :*/
-/* Copyright (C) 2006, 2007 Rusty Russell, IBM Corporation
+/*
+ * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation
+ * Copyright (C) 2009, 2010 Red Hat, 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
@@ -28,142 +16,694 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/cdev.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
#include <linux/err.h>
+#include <linux/fs.h>
#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
#include <linux/virtio.h>
#include <linux/virtio_console.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
#include "hvc_console.h"
-/*D:340 These represent our input and output console queues, and the virtio
- * operations for them. */
-static struct virtqueue *in_vq, *out_vq;
-static struct virtio_device *vdev;
+/*
+ * This is a global struct for storing common data for all the devices
+ * this driver handles.
+ *
+ * Mainly, it has a linked list for all the consoles in one place so
+ * that callbacks from hvc for get_chars(), put_chars() work properly
+ * across multiple devices and multiple ports per device.
+ */
+struct ports_driver_data {
+ /* Used for registering chardevs */
+ struct class *class;
+
+ /* Used for exporting per-port information to debugfs */
+ struct dentry *debugfs_dir;
+
+ /* Number of devices this driver is handling */
+ unsigned int index;
+
+ /*
+ * This is used to keep track of the number of hvc consoles
+ * spawned by this driver. This number is given as the first
+ * argument to hvc_alloc(). To correctly map an initial
+ * console spawned via hvc_instantiate to the console being
+ * hooked up via hvc_alloc, we need to pass the same vtermno.
+ *
+ * We also just assume the first console being initialised was
+ * the first one that got used as the initial console.
+ */
+ unsigned int next_vtermno;
+
+ /* All the console devices handled by this driver */
+ struct list_head consoles;
+};
+static struct ports_driver_data pdrvdata;
+
+DEFINE_SPINLOCK(pdrvdata_lock);
+
+/* This struct holds information that's relevant only for console ports */
+struct console {
+ /* We'll place all consoles in a list in the pdrvdata struct */
+ struct list_head list;
+
+ /* The hvc device associated with this console port */
+ struct hvc_struct *hvc;
+
+ /*
+ * This number identifies the number that we used to register
+ * with hvc in hvc_instantiate() and hvc_alloc(); this is the
+ * number passed on by the hvc callbacks to us to
+ * differentiate between the other console ports handled by
+ * this driver
+ */
+ u32 vtermno;
+};
+
+struct port_buffer {
+ char *buf;
+
+ /* size of the buffer in *buf above */
+ size_t size;
+
+ /* used length of the buffer */
+ size_t len;
+ /* offset in the buf from which to consume data */
+ size_t offset;
+};
+
+/*
+ * This is a per-device struct that stores data common to all the
+ * ports for that device (vdev->priv).
+ */
+struct ports_device {
+ /*
+ * Workqueue handlers where we process deferred work after
+ * notification
+ */
+ struct work_struct control_work;
+ struct work_struct config_work;
+
+ struct list_head ports;
+
+ /* To protect the list of ports */
+ spinlock_t ports_lock;
+
+ /* To protect the vq operations for the control channel */
+ spinlock_t cvq_lock;
+
+ /* The current config space is stored here */
+ struct virtio_console_config config;
+
+ /* The virtio device we're associated with */
+ struct virtio_device *vdev;
+
+ /*
+ * A couple of virtqueues for the control channel: one for
+ * guest->host transfers, one for host->guest transfers
+ */
+ struct virtqueue *c_ivq, *c_ovq;
+
+ /* Array of per-port IO virtqueues */
+ struct virtqueue **in_vqs, **out_vqs;
+
+ /* Used for numbering devices for sysfs and debugfs */
+ unsigned int drv_index;
+
+ /* Major number for this device. Ports will be created as minors. */
+ int chr_major;
+};
+
+/* This struct holds the per-port data */
+struct port {
+ /* Next port in the list, head is in the ports_device */
+ struct list_head list;
+
+ /* Pointer to the parent virtio_console device */
+ struct ports_device *portdev;
+
+ /* The current buffer from which data has to be fed to readers */
+ struct port_buffer *inbuf;
+
+ /*
+ * To protect the operations on the in_vq associated with this
+ * port. Has to be a spinlock because it can be called from
+ * interrupt context (get_char()).
+ */
+ spinlock_t inbuf_lock;
+
+ /* The IO vqs for this port */
+ struct virtqueue *in_vq, *out_vq;
+
+ /* File in the debugfs directory that exposes this port's information */
+ struct dentry *debugfs_file;
+
+ /*
+ * The entries in this struct will be valid if this port is
+ * hooked up to an hvc console
+ */
+ struct console cons;
+
+ /* Each port associates with a separate char device */
+ struct cdev cdev;
+ struct device *dev;
+
+ /* A waitqueue for poll() or blocking read operations */
+ wait_queue_head_t waitqueue;
+
+ /* The 'name' of the port that we expose via sysfs properties */
+ char *name;
+
+ /* The 'id' to identify the port with the Host */
+ u32 id;
+
+ /* Is the host device open */
+ bool host_connected;
+
+ /* We should allow only one process to open a port */
+ bool guest_connected;
+};
+
+/* This is the very early arch-specified put chars function. */
+static int (*early_put_chars)(u32, const char *, int);
+
+static struct port *find_port_by_vtermno(u32 vtermno)
+{
+ struct port *port;
+ struct console *cons;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdrvdata_lock, flags);
+ list_for_each_entry(cons, &pdrvdata.consoles, list) {
+ if (cons->vtermno == vtermno) {
+ port = container_of(cons, struct port, cons);
+ goto out;
+ }
+ }
+ port = NULL;
+out:
+ spin_unlock_irqrestore(&pdrvdata_lock, flags);
+ return port;
+}
+
+static struct port *find_port_by_id(struct ports_device *portdev, u32 id)
+{
+ struct port *port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&portdev->ports_lock, flags);
+ list_for_each_entry(port, &portdev->ports, list)
+ if (port->id == id)
+ goto out;
+ port = NULL;
+out:
+ spin_unlock_irqrestore(&portdev->ports_lock, flags);
+
+ return port;
+}
+
+static struct port *find_port_by_vq(struct ports_device *portdev,
+ struct virtqueue *vq)
+{
+ struct port *port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&portdev->ports_lock, flags);
+ list_for_each_entry(port, &portdev->ports, list)
+ if (port->in_vq == vq || port->out_vq == vq)
+ goto out;
+ port = NULL;
+out:
+ spin_unlock_irqrestore(&portdev->ports_lock, flags);
+ return port;
+}
+
+static bool is_console_port(struct port *port)
+{
+ if (port->cons.hvc)
+ return true;
+ return false;
+}
+
+static inline bool use_multiport(struct ports_device *portdev)
+{
+ /*
+ * This condition can be true when put_chars is called from
+ * early_init
+ */
+ if (!portdev->vdev)
+ return 0;
+ return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
+}
-/* This is our input buffer, and how much data is left in it. */
-static unsigned int in_len;
-static char *in, *inbuf;
+static void free_buf(struct port_buffer *buf)
+{
+ kfree(buf->buf);
+ kfree(buf);
+}
+
+static struct port_buffer *alloc_buf(size_t buf_size)
+{
+ struct port_buffer *buf;
-/* The operations for our console. */
-static struct hv_ops virtio_cons;
+ buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+ if (!buf)
+ goto fail;
+ buf->buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!buf->buf)
+ goto free_buf;
+ buf->len = 0;
+ buf->offset = 0;
+ buf->size = buf_size;
+ return buf;
+
+free_buf:
+ kfree(buf);
+fail:
+ return NULL;
+}
+
+/* Callers should take appropriate locks */
+static void *get_inbuf(struct port *port)
+{
+ struct port_buffer *buf;
+ struct virtqueue *vq;
+ unsigned int len;
-/* The hvc device */
-static struct hvc_struct *hvc;
+ vq = port->in_vq;
+ buf = vq->vq_ops->get_buf(vq, &len);
+ if (buf) {
+ buf->len = len;
+ buf->offset = 0;
+ }
+ return buf;
+}
-/*D:310 The put_chars() callback is pretty straightforward.
+/*
+ * Create a scatter-gather list representing our input buffer and put
+ * it in the queue.
*
- * We turn the characters into a scatter-gather list, add it to the output
- * queue and then kick the Host. Then we sit here waiting for it to finish:
- * inefficient in theory, but in practice implementations will do it
- * immediately (lguest's Launcher does). */
-static int put_chars(u32 vtermno, const char *buf, int count)
+ * Callers should take appropriate locks.
+ */
+static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
{
struct scatterlist sg[1];
+ int ret;
+
+ sg_init_one(sg, buf->buf, buf->size);
+
+ ret = vq->vq_ops->add_buf(vq, sg, 0, 1, buf);
+ vq->vq_ops->kick(vq);
+ return ret;
+}
+
+/* Discard any unread data this port has. Callers lockers. */
+static void discard_port_data(struct port *port)
+{
+ struct port_buffer *buf;
+ struct virtqueue *vq;
unsigned int len;
+ int ret;
- /* This is a convenient routine to initialize a single-elem sg list */
- sg_init_one(sg, buf, count);
+ vq = port->in_vq;
+ if (port->inbuf)
+ buf = port->inbuf;
+ else
+ buf = vq->vq_ops->get_buf(vq, &len);
- /* add_buf wants a token to identify this buffer: we hand it any
- * non-NULL pointer, since there's only ever one buffer. */
- if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, (void *)1) >= 0) {
- /* Tell Host to go! */
- out_vq->vq_ops->kick(out_vq);
- /* Chill out until it's done with the buffer. */
- while (!out_vq->vq_ops->get_buf(out_vq, &len))
- cpu_relax();
+ ret = 0;
+ while (buf) {
+ if (add_inbuf(vq, buf) < 0) {
+ ret++;
+ free_buf(buf);
+ }
+ buf = vq->vq_ops->get_buf(vq, &len);
}
+ port->inbuf = NULL;
+ if (ret)
+ dev_warn(port->dev, "Errors adding %d buffers back to vq\n",
+ ret);
+}
- /* We're expected to return the amount of data we wrote: all of it. */
- return count;
+static bool port_has_data(struct port *port)
+{
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&port->inbuf_lock, flags);
+ if (port->inbuf) {
+ ret = true;
+ goto out;
+ }
+ port->inbuf = get_inbuf(port);
+ if (port->inbuf) {
+ ret = true;
+ goto out;
+ }
+ ret = false;
+out:
+ spin_unlock_irqrestore(&port->inbuf_lock, flags);
+ return ret;
}
-/* Create a scatter-gather list representing our input buffer and put it in the
- * queue. */
-static void add_inbuf(void)
+static ssize_t send_control_msg(struct port *port, unsigned int event,
+ unsigned int value)
{
struct scatterlist sg[1];
- sg_init_one(sg, inbuf, PAGE_SIZE);
+ struct virtio_console_control cpkt;
+ struct virtqueue *vq;
+ unsigned int len;
+
+ if (!use_multiport(port->portdev))
+ return 0;
+
+ cpkt.id = port->id;
+ cpkt.event = event;
+ cpkt.value = value;
- /* We should always be able to add one buffer to an empty queue. */
- if (in_vq->vq_ops->add_buf(in_vq, sg, 0, 1, inbuf) < 0)
- BUG();
- in_vq->vq_ops->kick(in_vq);
+ vq = port->portdev->c_ovq;
+
+ sg_init_one(sg, &cpkt, sizeof(cpkt));
+ if (vq->vq_ops->add_buf(vq, sg, 1, 0, &cpkt) >= 0) {
+ vq->vq_ops->kick(vq);
+ while (!vq->vq_ops->get_buf(vq, &len))
+ cpu_relax();
+ }
+ return 0;
}
-/*D:350 get_chars() is the callback from the hvc_console infrastructure when
- * an interrupt is received.
- *
- * Most of the code deals with the fact that the hvc_console() infrastructure
- * only asks us for 16 bytes at a time. We keep in_offset and in_used fields
- * for partially-filled buffers. */
-static int get_chars(u32 vtermno, char *buf, int count)
+static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count)
{
- /* If we don't have an input queue yet, we can't get input. */
- BUG_ON(!in_vq);
+ struct scatterlist sg[1];
+ struct virtqueue *out_vq;
+ ssize_t ret;
+ unsigned int len;
+
+ out_vq = port->out_vq;
+
+ sg_init_one(sg, in_buf, in_count);
+ ret = out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, in_buf);
+
+ /* Tell Host to go! */
+ out_vq->vq_ops->kick(out_vq);
+
+ if (ret < 0) {
+ len = 0;
+ goto fail;
+ }
+
+ /*
+ * Wait till the host acknowledges it pushed out the data we
+ * sent. Also ensure we return to userspace the number of
+ * bytes that were successfully consumed by the host.
+ */
+ while (!out_vq->vq_ops->get_buf(out_vq, &len))
+ cpu_relax();
+fail:
+ /* We're expected to return the amount of data we wrote */
+ return len;
+}
+
+/*
+ * Give out the data that's requested from the buffer that we have
+ * queued up.
+ */
+static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
+ bool to_user)
+{
+ struct port_buffer *buf;
+ unsigned long flags;
+
+ if (!out_count || !port_has_data(port))
+ return 0;
+
+ buf = port->inbuf;
+ out_count = min(out_count, buf->len - buf->offset);
+
+ if (to_user) {
+ ssize_t ret;
+
+ ret = copy_to_user(out_buf, buf->buf + buf->offset, out_count);
+ if (ret)
+ return -EFAULT;
+ } else {
+ memcpy(out_buf, buf->buf + buf->offset, out_count);
+ }
+
+ buf->offset += out_count;
+
+ if (buf->offset == buf->len) {
+ /*
+ * We're done using all the data in this buffer.
+ * Re-queue so that the Host can send us more data.
+ */
+ spin_lock_irqsave(&port->inbuf_lock, flags);
+ port->inbuf = NULL;
+
+ if (add_inbuf(port->in_vq, buf) < 0)
+ dev_warn(port->dev, "failed add_buf\n");
+
+ spin_unlock_irqrestore(&port->inbuf_lock, flags);
+ }
+ /* Return the number of bytes actually copied */
+ return out_count;
+}
+
+/* The condition that must be true for polling to end */
+static bool wait_is_over(struct port *port)
+{
+ return port_has_data(port) || !port->host_connected;
+}
+
+static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
+ size_t count, loff_t *offp)
+{
+ struct port *port;
+ ssize_t ret;
+
+ port = filp->private_data;
- /* No buffer? Try to get one. */
- if (!in_len) {
- in = in_vq->vq_ops->get_buf(in_vq, &in_len);
- if (!in)
+ if (!port_has_data(port)) {
+ /*
+ * If nothing's connected on the host just return 0 in
+ * case of list_empty; this tells the userspace app
+ * that there's no connection
+ */
+ if (!port->host_connected)
return 0;
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ ret = wait_event_interruptible(port->waitqueue,
+ wait_is_over(port));
+ if (ret < 0)
+ return ret;
+ }
+ /*
+ * We could've received a disconnection message while we were
+ * waiting for more data.
+ *
+ * This check is not clubbed in the if() statement above as we
+ * might receive some data as well as the host could get
+ * disconnected after we got woken up from our wait. So we
+ * really want to give off whatever data we have and only then
+ * check for host_connected.
+ */
+ if (!port_has_data(port) && !port->host_connected)
+ return 0;
+
+ return fill_readbuf(port, ubuf, count, true);
+}
+
+static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
+ size_t count, loff_t *offp)
+{
+ struct port *port;
+ char *buf;
+ ssize_t ret;
+
+ port = filp->private_data;
+
+ count = min((size_t)(32 * 1024), count);
+
+ buf = kmalloc(count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = copy_from_user(buf, ubuf, count);
+ if (ret) {
+ ret = -EFAULT;
+ goto free_buf;
}
- /* You want more than we have to give? Well, try wanting less! */
- if (in_len < count)
- count = in_len;
+ ret = send_buf(port, buf, count);
+free_buf:
+ kfree(buf);
+ return ret;
+}
+
+static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
+{
+ struct port *port;
+ unsigned int ret;
+
+ port = filp->private_data;
+ poll_wait(filp, &port->waitqueue, wait);
+
+ ret = 0;
+ if (port->inbuf)
+ ret |= POLLIN | POLLRDNORM;
+ if (port->host_connected)
+ ret |= POLLOUT;
+ if (!port->host_connected)
+ ret |= POLLHUP;
+
+ return ret;
+}
+
+static int port_fops_release(struct inode *inode, struct file *filp)
+{
+ struct port *port;
+
+ port = filp->private_data;
+
+ /* Notify host of port being closed */
+ send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
+
+ spin_lock_irq(&port->inbuf_lock);
+ port->guest_connected = false;
+
+ discard_port_data(port);
+
+ spin_unlock_irq(&port->inbuf_lock);
+
+ return 0;
+}
+
+static int port_fops_open(struct inode *inode, struct file *filp)
+{
+ struct cdev *cdev = inode->i_cdev;
+ struct port *port;
+
+ port = container_of(cdev, struct port, cdev);
+ filp->private_data = port;
+
+ /*
+ * Don't allow opening of console port devices -- that's done
+ * via /dev/hvc
+ */
+ if (is_console_port(port))
+ return -ENXIO;
- /* Copy across to their buffer and increment offset. */
- memcpy(buf, in, count);
- in += count;
- in_len -= count;
+ /* Allow only one process to open a particular port at a time */
+ spin_lock_irq(&port->inbuf_lock);
+ if (port->guest_connected) {
+ spin_unlock_irq(&port->inbuf_lock);
+ return -EMFILE;
+ }
+
+ port->guest_connected = true;
+ spin_unlock_irq(&port->inbuf_lock);
- /* Finished? Re-register buffer so Host will use it again. */
- if (in_len == 0)
- add_inbuf();
+ /* Notify host of port being opened */
+ send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
- return count;
+ return 0;
}
-/*:*/
-/*D:320 Console drivers are initialized very early so boot messages can go out,
- * so we do things slightly differently from the generic virtio initialization
- * of the net and block drivers.
+/*
+ * The file operations that we support: programs in the guest can open
+ * a console device, read from it, write to it, poll for data and
+ * close it. The devices are at
+ * /dev/vport<device number>p<port number>
+ */
+static const struct file_operations port_fops = {
+ .owner = THIS_MODULE,
+ .open = port_fops_open,
+ .read = port_fops_read,
+ .write = port_fops_write,
+ .poll = port_fops_poll,
+ .release = port_fops_release,
+};
+
+/*
+ * The put_chars() callback is pretty straightforward.
*
- * At this stage, the console is output-only. It's too early to set up a
- * virtqueue, so we let the drivers do some boutique early-output thing. */
-int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
+ * We turn the characters into a scatter-gather list, add it to the
+ * output queue and then kick the Host. Then we sit here waiting for
+ * it to finish: inefficient in theory, but in practice
+ * implementations will do it immediately (lguest's Launcher does).
+ */
+static int put_chars(u32 vtermno, const char *buf, int count)
{
- virtio_cons.put_chars = put_chars;
- return hvc_instantiate(0, 0, &virtio_cons);
+ struct port *port;
+
+ port = find_port_by_vtermno(vtermno);
+ if (!port)
+ return 0;
+
+ if (unlikely(early_put_chars))
+ return early_put_chars(vtermno, buf, count);
+
+ return send_buf(port, (void *)buf, count);
}
/*
- * virtio console configuration. This supports:
- * - console resize
+ * get_chars() is the callback from the hvc_console infrastructure
+ * when an interrupt is received.
+ *
+ * We call out to fill_readbuf that gets us the required data from the
+ * buffers that are queued up.
*/
-static void virtcons_apply_config(struct virtio_device *dev)
+static int get_chars(u32 vtermno, char *buf, int count)
{
+ struct port *port;
+
+ port = find_port_by_vtermno(vtermno);
+ if (!port)
+ return 0;
+
+ /* If we don't have an input queue yet, we can't get input. */
+ BUG_ON(!port->in_vq);
+
+ return fill_readbuf(port, buf, count, false);
+}
+
+static void resize_console(struct port *port)
+{
+ struct virtio_device *vdev;
struct winsize ws;
- if (virtio_has_feature(dev, VIRTIO_CONSOLE_F_SIZE)) {
- dev->config->get(dev,
- offsetof(struct virtio_console_config, cols),
- &ws.ws_col, sizeof(u16));
- dev->config->get(dev,
- offsetof(struct virtio_console_config, rows),
- &ws.ws_row, sizeof(u16));
- hvc_resize(hvc, ws);
+ vdev = port->portdev->vdev;
+ if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) {
+ vdev->config->get(vdev,
+ offsetof(struct virtio_console_config, cols),
+ &ws.ws_col, sizeof(u16));
+ vdev->config->get(vdev,
+ offsetof(struct virtio_console_config, rows),
+ &ws.ws_row, sizeof(u16));
+ hvc_resize(port->cons.hvc, ws);
}
}
-/*
- * we support only one console, the hvc struct is a global var
- * We set the configuration at this point, since we now have a tty
- */
+/* We set the configuration at this point, since we now have a tty */
static int notifier_add_vio(struct hvc_struct *hp, int data)
{
+ struct port *port;
+
+ port = find_port_by_vtermno(hp->vtermno);
+ if (!port)
+ return -EINVAL;
+
hp->irq_requested = 1;
- virtcons_apply_config(vdev);
+ resize_console(port);
return 0;
}
@@ -173,79 +713,800 @@ static void notifier_del_vio(struct hvc_struct *hp, int data)
hp->irq_requested = 0;
}
-static void hvc_handle_input(struct virtqueue *vq)
+/* The operations for console ports. */
+static const struct hv_ops hv_ops = {
+ .get_chars = get_chars,
+ .put_chars = put_chars,
+ .notifier_add = notifier_add_vio,
+ .notifier_del = notifier_del_vio,
+ .notifier_hangup = notifier_del_vio,
+};
+
+/*
+ * Console drivers are initialized very early so boot messages can go
+ * out, so we do things slightly differently from the generic virtio
+ * initialization of the net and block drivers.
+ *
+ * At this stage, the console is output-only. It's too early to set
+ * up a virtqueue, so we let the drivers do some boutique early-output
+ * thing.
+ */
+int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
+{
+ early_put_chars = put_chars;
+ return hvc_instantiate(0, 0, &hv_ops);
+}
+
+int init_port_console(struct port *port)
+{
+ int ret;
+
+ /*
+ * The Host's telling us this port is a console port. Hook it
+ * up with an hvc console.
+ *
+ * To set up and manage our virtual console, we call
+ * hvc_alloc().
+ *
+ * The first argument of hvc_alloc() is the virtual console
+ * number. The second argument is the parameter for the
+ * notification mechanism (like irq number). We currently
+ * leave this as zero, virtqueues have implicit notifications.
+ *
+ * The third argument is a "struct hv_ops" containing the
+ * put_chars() get_chars(), notifier_add() and notifier_del()
+ * pointers. The final argument is the output buffer size: we
+ * can do any size, so we put PAGE_SIZE here.
+ */
+ port->cons.vtermno = pdrvdata.next_vtermno;
+
+ port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE);
+ if (IS_ERR(port->cons.hvc)) {
+ ret = PTR_ERR(port->cons.hvc);
+ dev_err(port->dev,
+ "error %d allocating hvc for port\n", ret);
+ port->cons.hvc = NULL;
+ return ret;
+ }
+ spin_lock_irq(&pdrvdata_lock);
+ pdrvdata.next_vtermno++;
+ list_add_tail(&port->cons.list, &pdrvdata.consoles);
+ spin_unlock_irq(&pdrvdata_lock);
+ port->guest_connected = true;
+
+ /* Notify host of port being opened */
+ send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
+
+ return 0;
+}
+
+static ssize_t show_port_name(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ struct port *port;
+
+ port = dev_get_drvdata(dev);
+
+ return sprintf(buffer, "%s\n", port->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL);
+
+static struct attribute *port_sysfs_entries[] = {
+ &dev_attr_name.attr,
+ NULL
+};
+
+static struct attribute_group port_attribute_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = port_sysfs_entries,
+};
+
+static int debugfs_open(struct inode *inode, struct file *filp)
+{
+ filp->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
+ size_t count, loff_t *offp)
+{
+ struct port *port;
+ char *buf;
+ ssize_t ret, out_offset, out_count;
+
+ out_count = 1024;
+ buf = kmalloc(out_count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ port = filp->private_data;
+ out_offset = 0;
+ out_offset += snprintf(buf + out_offset, out_count,
+ "name: %s\n", port->name ? port->name : "");
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "guest_connected: %d\n", port->guest_connected);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "host_connected: %d\n", port->host_connected);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "is_console: %s\n",
+ is_console_port(port) ? "yes" : "no");
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "console_vtermno: %u\n", port->cons.vtermno);
+
+ ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations port_debugfs_ops = {
+ .owner = THIS_MODULE,
+ .open = debugfs_open,
+ .read = debugfs_read,
+};
+
+/* Remove all port-specific data. */
+static int remove_port(struct port *port)
+{
+ struct port_buffer *buf;
+
+ spin_lock_irq(&port->portdev->ports_lock);
+ list_del(&port->list);
+ spin_unlock_irq(&port->portdev->ports_lock);
+
+ if (is_console_port(port)) {
+ spin_lock_irq(&pdrvdata_lock);
+ list_del(&port->cons.list);
+ spin_unlock_irq(&pdrvdata_lock);
+ hvc_remove(port->cons.hvc);
+ }
+ if (port->guest_connected)
+ send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
+
+ sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
+ device_destroy(pdrvdata.class, port->dev->devt);
+ cdev_del(&port->cdev);
+
+ /* Remove unused data this port might have received. */
+ discard_port_data(port);
+
+ /* Remove buffers we queued up for the Host to send us data in. */
+ while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq)))
+ free_buf(buf);
+
+ kfree(port->name);
+
+ debugfs_remove(port->debugfs_file);
+
+ kfree(port);
+ return 0;
+}
+
+/* Any private messages that the Host and Guest want to share */
+static void handle_control_message(struct ports_device *portdev,
+ struct port_buffer *buf)
+{
+ struct virtio_console_control *cpkt;
+ struct port *port;
+ size_t name_size;
+ int err;
+
+ cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);
+
+ port = find_port_by_id(portdev, cpkt->id);
+ if (!port) {
+ /* No valid header at start of buffer. Drop it. */
+ dev_dbg(&portdev->vdev->dev,
+ "Invalid index %u in control packet\n", cpkt->id);
+ return;
+ }
+
+ switch (cpkt->event) {
+ case VIRTIO_CONSOLE_CONSOLE_PORT:
+ if (!cpkt->value)
+ break;
+ if (is_console_port(port))
+ break;
+
+ init_port_console(port);
+ /*
+ * Could remove the port here in case init fails - but
+ * have to notify the host first.
+ */
+ break;
+ case VIRTIO_CONSOLE_RESIZE:
+ if (!is_console_port(port))
+ break;
+ port->cons.hvc->irq_requested = 1;
+ resize_console(port);
+ break;
+ case VIRTIO_CONSOLE_PORT_OPEN:
+ port->host_connected = cpkt->value;
+ wake_up_interruptible(&port->waitqueue);
+ break;
+ case VIRTIO_CONSOLE_PORT_NAME:
+ /*
+ * Skip the size of the header and the cpkt to get the size
+ * of the name that was sent
+ */
+ name_size = buf->len - buf->offset - sizeof(*cpkt) + 1;
+
+ port->name = kmalloc(name_size, GFP_KERNEL);
+ if (!port->name) {
+ dev_err(port->dev,
+ "Not enough space to store port name\n");
+ break;
+ }
+ strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt),
+ name_size - 1);
+ port->name[name_size - 1] = 0;
+
+ /*
+ * Since we only have one sysfs attribute, 'name',
+ * create it only if we have a name for the port.
+ */
+ err = sysfs_create_group(&port->dev->kobj,
+ &port_attribute_group);
+ if (err)
+ dev_err(port->dev,
+ "Error %d creating sysfs device attributes\n",
+ err);
+
+ break;
+ case VIRTIO_CONSOLE_PORT_REMOVE:
+ /*
+ * Hot unplug the port. We don't decrement nr_ports
+ * since we don't want to deal with extra complexities
+ * of using the lowest-available port id: We can just
+ * pick up the nr_ports number as the id and not have
+ * userspace send it to us. This helps us in two
+ * ways:
+ *
+ * - We don't need to have a 'port_id' field in the
+ * config space when a port is hot-added. This is a
+ * good thing as we might queue up multiple hotplug
+ * requests issued in our workqueue.
+ *
+ * - Another way to deal with this would have been to
+ * use a bitmap of the active ports and select the
+ * lowest non-active port from that map. That
+ * bloats the already tight config space and we
+ * would end up artificially limiting the
+ * max. number of ports to sizeof(bitmap). Right
+ * now we can support 2^32 ports (as the port id is
+ * stored in a u32 type).
+ *
+ */
+ remove_port(port);
+ break;
+ }
+}
+
+static void control_work_handler(struct work_struct *work)
+{
+ struct ports_device *portdev;
+ struct virtqueue *vq;
+ struct port_buffer *buf;
+ unsigned int len;
+
+ portdev = container_of(work, struct ports_device, control_work);
+ vq = portdev->c_ivq;
+
+ spin_lock(&portdev->cvq_lock);
+ while ((buf = vq->vq_ops->get_buf(vq, &len))) {
+ spin_unlock(&portdev->cvq_lock);
+
+ buf->len = len;
+ buf->offset = 0;
+
+ handle_control_message(portdev, buf);
+
+ spin_lock(&portdev->cvq_lock);
+ if (add_inbuf(portdev->c_ivq, buf) < 0) {
+ dev_warn(&portdev->vdev->dev,
+ "Error adding buffer to queue\n");
+ free_buf(buf);
+ }
+ }
+ spin_unlock(&portdev->cvq_lock);
+}
+
+static void in_intr(struct virtqueue *vq)
{
- if (hvc_poll(hvc))
+ struct port *port;
+ unsigned long flags;
+
+ port = find_port_by_vq(vq->vdev->priv, vq);
+ if (!port)
+ return;
+
+ spin_lock_irqsave(&port->inbuf_lock, flags);
+ if (!port->inbuf)
+ port->inbuf = get_inbuf(port);
+
+ /*
+ * Don't queue up data when port is closed. This condition
+ * can be reached when a console port is not yet connected (no
+ * tty is spawned) and the host sends out data to console
+ * ports. For generic serial ports, the host won't
+ * (shouldn't) send data till the guest is connected.
+ */
+ if (!port->guest_connected)
+ discard_port_data(port);
+
+ spin_unlock_irqrestore(&port->inbuf_lock, flags);
+
+ wake_up_interruptible(&port->waitqueue);
+
+ if (is_console_port(port) && hvc_poll(port->cons.hvc))
hvc_kick();
}
-/*D:370 Once we're further in boot, we get probed like any other virtio device.
- * At this stage we set up the output virtqueue.
- *
- * To set up and manage our virtual console, we call hvc_alloc(). Since we
- * never remove the console device we never need this pointer again.
+static void control_intr(struct virtqueue *vq)
+{
+ struct ports_device *portdev;
+
+ portdev = vq->vdev->priv;
+ schedule_work(&portdev->control_work);
+}
+
+static void config_intr(struct virtio_device *vdev)
+{
+ struct ports_device *portdev;
+
+ portdev = vdev->priv;
+ if (use_multiport(portdev)) {
+ /* Handle port hot-add */
+ schedule_work(&portdev->config_work);
+ }
+ /*
+ * We'll use this way of resizing only for legacy support.
+ * For newer userspace (VIRTIO_CONSOLE_F_MULTPORT+), use
+ * control messages to indicate console size changes so that
+ * it can be done per-port
+ */
+ resize_console(find_port_by_id(portdev, 0));
+}
+
+static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
+{
+ struct port_buffer *buf;
+ unsigned int nr_added_bufs;
+ int ret;
+
+ nr_added_bufs = 0;
+ do {
+ buf = alloc_buf(PAGE_SIZE);
+ if (!buf)
+ break;
+
+ spin_lock_irq(lock);
+ ret = add_inbuf(vq, buf);
+ if (ret < 0) {
+ spin_unlock_irq(lock);
+ free_buf(buf);
+ break;
+ }
+ nr_added_bufs++;
+ spin_unlock_irq(lock);
+ } while (ret > 0);
+
+ return nr_added_bufs;
+}
+
+static int add_port(struct ports_device *portdev, u32 id)
+{
+ char debugfs_name[16];
+ struct port *port;
+ struct port_buffer *buf;
+ dev_t devt;
+ unsigned int nr_added_bufs;
+ int err;
+
+ port = kmalloc(sizeof(*port), GFP_KERNEL);
+ if (!port) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ port->portdev = portdev;
+ port->id = id;
+
+ port->name = NULL;
+ port->inbuf = NULL;
+ port->cons.hvc = NULL;
+
+ port->host_connected = port->guest_connected = false;
+
+ port->in_vq = portdev->in_vqs[port->id];
+ port->out_vq = portdev->out_vqs[port->id];
+
+ cdev_init(&port->cdev, &port_fops);
+
+ devt = MKDEV(portdev->chr_major, id);
+ err = cdev_add(&port->cdev, devt, 1);
+ if (err < 0) {
+ dev_err(&port->portdev->vdev->dev,
+ "Error %d adding cdev for port %u\n", err, id);
+ goto free_port;
+ }
+ port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
+ devt, port, "vport%up%u",
+ port->portdev->drv_index, id);
+ if (IS_ERR(port->dev)) {
+ err = PTR_ERR(port->dev);
+ dev_err(&port->portdev->vdev->dev,
+ "Error %d creating device for port %u\n",
+ err, id);
+ goto free_cdev;
+ }
+
+ spin_lock_init(&port->inbuf_lock);
+ init_waitqueue_head(&port->waitqueue);
+
+ /* Fill the in_vq with buffers so the host can send us data. */
+ nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock);
+ if (!nr_added_bufs) {
+ dev_err(port->dev, "Error allocating inbufs\n");
+ err = -ENOMEM;
+ goto free_device;
+ }
+
+ /*
+ * If we're not using multiport support, this has to be a console port
+ */
+ if (!use_multiport(port->portdev)) {
+ err = init_port_console(port);
+ if (err)
+ goto free_inbufs;
+ }
+
+ spin_lock_irq(&portdev->ports_lock);
+ list_add_tail(&port->list, &port->portdev->ports);
+ spin_unlock_irq(&portdev->ports_lock);
+
+ /*
+ * Tell the Host we're set so that it can send us various
+ * configuration parameters for this port (eg, port name,
+ * caching, whether this is a console port, etc.)
+ */
+ send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+
+ if (pdrvdata.debugfs_dir) {
+ /*
+ * Finally, create the debugfs file that we can use to
+ * inspect a port's state at any time
+ */
+ sprintf(debugfs_name, "vport%up%u",
+ port->portdev->drv_index, id);
+ port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
+ pdrvdata.debugfs_dir,
+ port,
+ &port_debugfs_ops);
+ }
+ return 0;
+
+free_inbufs:
+ while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq)))
+ free_buf(buf);
+free_device:
+ device_destroy(pdrvdata.class, port->dev->devt);
+free_cdev:
+ cdev_del(&port->cdev);
+free_port:
+ kfree(port);
+fail:
+ return err;
+}
+
+/*
+ * The workhandler for config-space updates.
*
- * Finally we put our input buffer in the input queue, ready to receive. */
-static int __devinit virtcons_probe(struct virtio_device *dev)
+ * This is called when ports are hot-added.
+ */
+static void config_work_handler(struct work_struct *work)
+{
+ struct virtio_console_config virtconconf;
+ struct ports_device *portdev;
+ struct virtio_device *vdev;
+ int err;
+
+ portdev = container_of(work, struct ports_device, config_work);
+
+ vdev = portdev->vdev;
+ vdev->config->get(vdev,
+ offsetof(struct virtio_console_config, nr_ports),
+ &virtconconf.nr_ports,
+ sizeof(virtconconf.nr_ports));
+
+ if (portdev->config.nr_ports == virtconconf.nr_ports) {
+ /*
+ * Port 0 got hot-added. Since we already did all the
+ * other initialisation for it, just tell the Host
+ * that the port is ready if we find the port. In
+ * case the port was hot-removed earlier, we call
+ * add_port to add the port.
+ */
+ struct port *port;
+
+ port = find_port_by_id(portdev, 0);
+ if (!port)
+ add_port(portdev, 0);
+ else
+ send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+ return;
+ }
+ if (virtconconf.nr_ports > portdev->config.max_nr_ports) {
+ dev_warn(&vdev->dev,
+ "More ports specified (%u) than allowed (%u)",
+ portdev->config.nr_ports + 1,
+ portdev->config.max_nr_ports);
+ return;
+ }
+ if (virtconconf.nr_ports < portdev->config.nr_ports)
+ return;
+
+ /* Hot-add ports */
+ while (virtconconf.nr_ports - portdev->config.nr_ports) {
+ err = add_port(portdev, portdev->config.nr_ports);
+ if (err)
+ break;
+ portdev->config.nr_ports++;
+ }
+}
+
+static int init_vqs(struct ports_device *portdev)
{
- vq_callback_t *callbacks[] = { hvc_handle_input, NULL};
- const char *names[] = { "input", "output" };
- struct virtqueue *vqs[2];
+ vq_callback_t **io_callbacks;
+ char **io_names;
+ struct virtqueue **vqs;
+ u32 i, j, nr_ports, nr_queues;
int err;
- vdev = dev;
+ nr_ports = portdev->config.max_nr_ports;
+ nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
- /* This is the scratch page we use to receive console input */
- inbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!inbuf) {
+ vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
+ if (!vqs) {
err = -ENOMEM;
goto fail;
}
+ io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL);
+ if (!io_callbacks) {
+ err = -ENOMEM;
+ goto free_vqs;
+ }
+ io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL);
+ if (!io_names) {
+ err = -ENOMEM;
+ goto free_callbacks;
+ }
+ portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
+ GFP_KERNEL);
+ if (!portdev->in_vqs) {
+ err = -ENOMEM;
+ goto free_names;
+ }
+ portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
+ GFP_KERNEL);
+ if (!portdev->out_vqs) {
+ err = -ENOMEM;
+ goto free_invqs;
+ }
+
+ /*
+ * For backward compat (newer host but older guest), the host
+ * spawns a console port first and also inits the vqs for port
+ * 0 before others.
+ */
+ j = 0;
+ io_callbacks[j] = in_intr;
+ io_callbacks[j + 1] = NULL;
+ io_names[j] = "input";
+ io_names[j + 1] = "output";
+ j += 2;
+ if (use_multiport(portdev)) {
+ io_callbacks[j] = control_intr;
+ io_callbacks[j + 1] = NULL;
+ io_names[j] = "control-i";
+ io_names[j + 1] = "control-o";
+
+ for (i = 1; i < nr_ports; i++) {
+ j += 2;
+ io_callbacks[j] = in_intr;
+ io_callbacks[j + 1] = NULL;
+ io_names[j] = "input";
+ io_names[j + 1] = "output";
+ }
+ }
/* Find the queues. */
- /* FIXME: This is why we want to wean off hvc: we do nothing
- * when input comes in. */
- err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names);
+ err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs,
+ io_callbacks,
+ (const char **)io_names);
if (err)
+ goto free_outvqs;
+
+ j = 0;
+ portdev->in_vqs[0] = vqs[0];
+ portdev->out_vqs[0] = vqs[1];
+ j += 2;
+ if (use_multiport(portdev)) {
+ portdev->c_ivq = vqs[j];
+ portdev->c_ovq = vqs[j + 1];
+
+ for (i = 1; i < nr_ports; i++) {
+ j += 2;
+ portdev->in_vqs[i] = vqs[j];
+ portdev->out_vqs[i] = vqs[j + 1];
+ }
+ }
+ kfree(io_callbacks);
+ kfree(io_names);
+ kfree(vqs);
+
+ return 0;
+
+free_names:
+ kfree(io_names);
+free_callbacks:
+ kfree(io_callbacks);
+free_outvqs:
+ kfree(portdev->out_vqs);
+free_invqs:
+ kfree(portdev->in_vqs);
+free_vqs:
+ kfree(vqs);
+fail:
+ return err;
+}
+
+static const struct file_operations portdev_fops = {
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Once we're further in boot, we get probed like any other virtio
+ * device.
+ *
+ * If the host also supports multiple console ports, we check the
+ * config space to see how many ports the host has spawned. We
+ * initialize each port found.
+ */
+static int __devinit virtcons_probe(struct virtio_device *vdev)
+{
+ struct ports_device *portdev;
+ u32 i;
+ int err;
+ bool multiport;
+
+ portdev = kmalloc(sizeof(*portdev), GFP_KERNEL);
+ if (!portdev) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ /* Attach this portdev to this virtio_device, and vice-versa. */
+ portdev->vdev = vdev;
+ vdev->priv = portdev;
+
+ spin_lock_irq(&pdrvdata_lock);
+ portdev->drv_index = pdrvdata.index++;
+ spin_unlock_irq(&pdrvdata_lock);
+
+ portdev->chr_major = register_chrdev(0, "virtio-portsdev",
+ &portdev_fops);
+ if (portdev->chr_major < 0) {
+ dev_err(&vdev->dev,
+ "Error %d registering chrdev for device %u\n",
+ portdev->chr_major, portdev->drv_index);
+ err = portdev->chr_major;
goto free;
+ }
- in_vq = vqs[0];
- out_vq = vqs[1];
+ multiport = false;
+ portdev->config.nr_ports = 1;
+ portdev->config.max_nr_ports = 1;
+ if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
+ multiport = true;
+ vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
- /* Start using the new console output. */
- virtio_cons.get_chars = get_chars;
- virtio_cons.put_chars = put_chars;
- virtio_cons.notifier_add = notifier_add_vio;
- virtio_cons.notifier_del = notifier_del_vio;
- virtio_cons.notifier_hangup = notifier_del_vio;
-
- /* The first argument of hvc_alloc() is the virtual console number, so
- * we use zero. The second argument is the parameter for the
- * notification mechanism (like irq number). We currently leave this
- * as zero, virtqueues have implicit notifications.
- *
- * The third argument is a "struct hv_ops" containing the put_chars()
- * get_chars(), notifier_add() and notifier_del() pointers.
- * The final argument is the output buffer size: we can do any size,
- * so we put PAGE_SIZE here. */
- hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE);
- if (IS_ERR(hvc)) {
- err = PTR_ERR(hvc);
- goto free_vqs;
+ vdev->config->get(vdev, offsetof(struct virtio_console_config,
+ nr_ports),
+ &portdev->config.nr_ports,
+ sizeof(portdev->config.nr_ports));
+ vdev->config->get(vdev, offsetof(struct virtio_console_config,
+ max_nr_ports),
+ &portdev->config.max_nr_ports,
+ sizeof(portdev->config.max_nr_ports));
+ if (portdev->config.nr_ports > portdev->config.max_nr_ports) {
+ dev_warn(&vdev->dev,
+ "More ports (%u) specified than allowed (%u). Will init %u ports.",
+ portdev->config.nr_ports,
+ portdev->config.max_nr_ports,
+ portdev->config.max_nr_ports);
+
+ portdev->config.nr_ports = portdev->config.max_nr_ports;
+ }
+ }
+
+ /* Let the Host know we support multiple ports.*/
+ vdev->config->finalize_features(vdev);
+
+ err = init_vqs(portdev);
+ if (err < 0) {
+ dev_err(&vdev->dev, "Error %d initializing vqs\n", err);
+ goto free_chrdev;
+ }
+
+ spin_lock_init(&portdev->ports_lock);
+ INIT_LIST_HEAD(&portdev->ports);
+
+ if (multiport) {
+ unsigned int nr_added_bufs;
+
+ spin_lock_init(&portdev->cvq_lock);
+ INIT_WORK(&portdev->control_work, &control_work_handler);
+ INIT_WORK(&portdev->config_work, &config_work_handler);
+
+ nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+ if (!nr_added_bufs) {
+ dev_err(&vdev->dev,
+ "Error allocating buffers for control queue\n");
+ err = -ENOMEM;
+ goto free_vqs;
+ }
}
- /* Register the input buffer the first time. */
- add_inbuf();
+ for (i = 0; i < portdev->config.nr_ports; i++)
+ add_port(portdev, i);
+
+ /* Start using the new console output. */
+ early_put_chars = NULL;
return 0;
free_vqs:
vdev->config->del_vqs(vdev);
+ kfree(portdev->in_vqs);
+ kfree(portdev->out_vqs);
+free_chrdev:
+ unregister_chrdev(portdev->chr_major, "virtio-portsdev");
free:
- kfree(inbuf);
+ kfree(portdev);
fail:
return err;
}
+static void virtcons_remove(struct virtio_device *vdev)
+{
+ struct ports_device *portdev;
+ struct port *port, *port2;
+ struct port_buffer *buf;
+ unsigned int len;
+
+ portdev = vdev->priv;
+
+ cancel_work_sync(&portdev->control_work);
+ cancel_work_sync(&portdev->config_work);
+
+ list_for_each_entry_safe(port, port2, &portdev->ports, list)
+ remove_port(port);
+
+ unregister_chrdev(portdev->chr_major, "virtio-portsdev");
+
+ while ((buf = portdev->c_ivq->vq_ops->get_buf(portdev->c_ivq, &len)))
+ free_buf(buf);
+
+ while ((buf = portdev->c_ivq->vq_ops->detach_unused_buf(portdev->c_ivq)))
+ free_buf(buf);
+
+ vdev->config->del_vqs(vdev);
+ kfree(portdev->in_vqs);
+ kfree(portdev->out_vqs);
+
+ kfree(portdev);
+}
+
static struct virtio_device_id id_table[] = {
{ VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
{ 0 },
@@ -253,6 +1514,7 @@ static struct virtio_device_id id_table[] = {
static unsigned int features[] = {
VIRTIO_CONSOLE_F_SIZE,
+ VIRTIO_CONSOLE_F_MULTIPORT,
};
static struct virtio_driver virtio_console = {
@@ -262,14 +1524,41 @@ static struct virtio_driver virtio_console = {
.driver.owner = THIS_MODULE,
.id_table = id_table,
.probe = virtcons_probe,
- .config_changed = virtcons_apply_config,
+ .remove = virtcons_remove,
+ .config_changed = config_intr,
};
static int __init init(void)
{
+ int err;
+
+ pdrvdata.class = class_create(THIS_MODULE, "virtio-ports");
+ if (IS_ERR(pdrvdata.class)) {
+ err = PTR_ERR(pdrvdata.class);
+ pr_err("Error %d creating virtio-ports class\n", err);
+ return err;
+ }
+
+ pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
+ if (!pdrvdata.debugfs_dir) {
+ pr_warning("Error %ld creating debugfs dir for virtio-ports\n",
+ PTR_ERR(pdrvdata.debugfs_dir));
+ }
+ INIT_LIST_HEAD(&pdrvdata.consoles);
+
return register_virtio_driver(&virtio_console);
}
+
+static void __exit fini(void)
+{
+ unregister_virtio_driver(&virtio_console);
+
+ class_destroy(pdrvdata.class);
+ if (pdrvdata.debugfs_dir)
+ debugfs_remove_recursive(pdrvdata.debugfs_dir);
+}
module_init(init);
+module_exit(fini);
MODULE_DEVICE_TABLE(virtio, id_table);
MODULE_DESCRIPTION("Virtio console driver");
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index 994e1a58b987..8b24729fec89 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -136,7 +136,7 @@ static const struct tty_port_operations scc_port_ops = {
* vme_scc_init() and support functions
*---------------------------------------------------------------------------*/
-static int scc_init_drivers(void)
+static int __init scc_init_drivers(void)
{
int error;
@@ -172,7 +172,7 @@ static int scc_init_drivers(void)
/* ports[] array is indexed by line no (i.e. [0] for ttyS0, [1] for ttyS1).
*/
-static void scc_init_portstructs(void)
+static void __init scc_init_portstructs(void)
{
struct scc_port *port;
int i;
@@ -195,7 +195,7 @@ static void scc_init_portstructs(void)
#ifdef CONFIG_MVME147_SCC
-static int mvme147_scc_init(void)
+static int __init mvme147_scc_init(void)
{
struct scc_port *port;
int error;
@@ -298,7 +298,7 @@ fail:
#ifdef CONFIG_MVME162_SCC
-static int mvme162_scc_init(void)
+static int __init mvme162_scc_init(void)
{
struct scc_port *port;
int error;
@@ -404,7 +404,7 @@ fail:
#ifdef CONFIG_BVME6000_SCC
-static int bvme6000_scc_init(void)
+static int __init bvme6000_scc_init(void)
{
struct scc_port *port;
int error;
@@ -503,7 +503,7 @@ fail_free_b_rx:
#endif
-static int vme_scc_init(void)
+static int __init vme_scc_init(void)
{
int res = -ENODEV;
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 50faa1fb0f06..bd1d1164fec5 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -821,7 +821,7 @@ static inline int resize_screen(struct vc_data *vc, int width, int height,
*
* Resize a virtual console, clipping according to the actual constraints.
* If the caller passes a tty structure then update the termios winsize
- * information and perform any neccessary signal handling.
+ * information and perform any necessary signal handling.
*
* Caller must hold the console semaphore. Takes the termios mutex and
* ctrl_lock of the tty IFF a tty is passed.
@@ -2119,8 +2119,6 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
uint8_t inverse;
uint8_t width;
u16 himask, charmask;
- const unsigned char *orig_buf = NULL;
- int orig_count;
if (in_interrupt())
return count;
@@ -2142,8 +2140,6 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
release_console_sem();
return 0;
}
- orig_buf = buf;
- orig_count = count;
himask = vc->vc_hi_font_mask;
charmask = himask ? 0x1ff : 0xff;
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index 6aa10284104a..87778dcf8727 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -888,7 +888,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
ret = -EFAULT;
goto out;
}
- if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
+ if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS && tmp.mode != VT_PROCESS_AUTO) {
ret = -EINVAL;
goto out;
}
@@ -1622,7 +1622,7 @@ static void complete_change_console(struct vc_data *vc)
* telling it that it has acquired. Also check if it has died and
* clean up (similar to logic employed in change_console())
*/
- if (vc->vt_mode.mode == VT_PROCESS) {
+ if (vc->vt_mode.mode == VT_PROCESS || vc->vt_mode.mode == VT_PROCESS_AUTO) {
/*
* Send the signal as privileged - kill_pid() will
* tell us if the process has gone or something else
@@ -1682,7 +1682,7 @@ void change_console(struct vc_data *new_vc)
* vt to auto control.
*/
vc = vc_cons[fg_console].d;
- if (vc->vt_mode.mode == VT_PROCESS) {
+ if (vc->vt_mode.mode == VT_PROCESS || vc->vt_mode.mode == VT_PROCESS_AUTO) {
/*
* Send the signal as privileged - kill_pid() will
* tell us if the process has gone or something else
@@ -1693,27 +1693,28 @@ void change_console(struct vc_data *new_vc)
*/
vc->vt_newvt = new_vc->vc_num;
if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
+ if(vc->vt_mode.mode == VT_PROCESS)
+ /*
+ * It worked. Mark the vt to switch to and
+ * return. The process needs to send us a
+ * VT_RELDISP ioctl to complete the switch.
+ */
+ return;
+ } else {
/*
- * It worked. Mark the vt to switch to and
- * return. The process needs to send us a
- * VT_RELDISP ioctl to complete the switch.
+ * The controlling process has died, so we revert back to
+ * normal operation. In this case, we'll also change back
+ * to KD_TEXT mode. I'm not sure if this is strictly correct
+ * but it saves the agony when the X server dies and the screen
+ * remains blanked due to KD_GRAPHICS! It would be nice to do
+ * this outside of VT_PROCESS but there is no single process
+ * to account for and tracking tty count may be undesirable.
*/
- return;
+ reset_vc(vc);
}
/*
- * The controlling process has died, so we revert back to
- * normal operation. In this case, we'll also change back
- * to KD_TEXT mode. I'm not sure if this is strictly correct
- * but it saves the agony when the X server dies and the screen
- * remains blanked due to KD_GRAPHICS! It would be nice to do
- * this outside of VT_PROCESS but there is no single process
- * to account for and tracking tty count may be undesirable.
- */
- reset_vc(vc);
-
- /*
- * Fall through to normal (VT_AUTO) handling of the switch...
+ * Fall through to normal (VT_AUTO and VT_PROCESS_AUTO) handling of the switch...
*/
}
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
deleted file mode 100644
index 08f726c5fee5..000000000000
--- a/drivers/clocksource/Kconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-config CS5535_CLOCK_EVENT_SRC
- tristate "CS5535/CS5536 high-res timer (MFGPT) events"
- depends on GENERIC_TIME && GENERIC_CLOCKEVENTS && CS5535_MFGPT
- help
- This driver provides a clock event source based on the MFGPT
- timer(s) in the CS5535 and CS5536 companion chips.
- MFGPTs have a better resolution and max interval than the
- generic PIT, and are suitable for use as high-res timers.
-
diff --git a/drivers/clocksource/cs5535-clockevt.c b/drivers/clocksource/cs5535-clockevt.c
index 27d20fac19d1..b314a999aabe 100644
--- a/drivers/clocksource/cs5535-clockevt.c
+++ b/drivers/clocksource/cs5535-clockevt.c
@@ -21,7 +21,7 @@
#define DRV_NAME "cs5535-clockevt"
-static int timer_irq = CONFIG_CS5535_MFGPT_DEFAULT_IRQ;
+static int timer_irq;
module_param_named(irq, timer_irq, int, 0644);
MODULE_PARM_DESC(irq, "Which IRQ to use for the clock source MFGPT ticks.");
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index 6b3e0c2f33e2..578595c4425d 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -40,7 +40,6 @@ struct sh_cmt_priv {
struct platform_device *pdev;
unsigned long flags;
- unsigned long flags_suspend;
unsigned long match_value;
unsigned long next_match_value;
unsigned long max_match_value;
@@ -432,6 +431,11 @@ static void sh_cmt_clocksource_disable(struct clocksource *cs)
sh_cmt_stop(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
}
+static void sh_cmt_clocksource_resume(struct clocksource *cs)
+{
+ sh_cmt_start(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
+}
+
static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
char *name, unsigned long rating)
{
@@ -442,6 +446,8 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
cs->read = sh_cmt_clocksource_read;
cs->enable = sh_cmt_clocksource_enable;
cs->disable = sh_cmt_clocksource_disable;
+ cs->suspend = sh_cmt_clocksource_disable;
+ cs->resume = sh_cmt_clocksource_resume;
cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
pr_info("sh_cmt: %s used as clock source\n", cs->name);
@@ -603,18 +609,13 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
p->irqaction.handler = sh_cmt_interrupt;
p->irqaction.dev_id = p;
p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
- ret = setup_irq(irq, &p->irqaction);
- if (ret) {
- pr_err("sh_cmt: failed to request irq %d\n", irq);
- goto err1;
- }
/* get hold of clock */
p->clk = clk_get(&p->pdev->dev, cfg->clk);
if (IS_ERR(p->clk)) {
pr_err("sh_cmt: cannot get clock \"%s\"\n", cfg->clk);
ret = PTR_ERR(p->clk);
- goto err2;
+ goto err1;
}
if (resource_size(res) == 6) {
@@ -627,14 +628,25 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
p->clear_bits = ~0xc000;
}
- return sh_cmt_register(p, cfg->name,
- cfg->clockevent_rating,
- cfg->clocksource_rating);
- err2:
- remove_irq(irq, &p->irqaction);
- err1:
+ ret = sh_cmt_register(p, cfg->name,
+ cfg->clockevent_rating,
+ cfg->clocksource_rating);
+ if (ret) {
+ pr_err("sh_cmt: registration failed\n");
+ goto err1;
+ }
+
+ ret = setup_irq(irq, &p->irqaction);
+ if (ret) {
+ pr_err("sh_cmt: failed to request irq %d\n", irq);
+ goto err1;
+ }
+
+ return 0;
+
+err1:
iounmap(p->mapbase);
- err0:
+err0:
return ret;
}
@@ -668,38 +680,11 @@ static int __devexit sh_cmt_remove(struct platform_device *pdev)
return -EBUSY; /* cannot unregister clockevent and clocksource */
}
-static int sh_cmt_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct sh_cmt_priv *p = platform_get_drvdata(pdev);
-
- /* save flag state and stop CMT channel */
- p->flags_suspend = p->flags;
- sh_cmt_stop(p, p->flags);
- return 0;
-}
-
-static int sh_cmt_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct sh_cmt_priv *p = platform_get_drvdata(pdev);
-
- /* start CMT channel from saved state */
- sh_cmt_start(p, p->flags_suspend);
- return 0;
-}
-
-static struct dev_pm_ops sh_cmt_dev_pm_ops = {
- .suspend = sh_cmt_suspend,
- .resume = sh_cmt_resume,
-};
-
static struct platform_driver sh_cmt_device_driver = {
.probe = sh_cmt_probe,
.remove = __devexit_p(sh_cmt_remove),
.driver = {
.name = "sh_cmt",
- .pm = &sh_cmt_dev_pm_ops,
}
};
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c
index 973e714d6051..4c8a759e60cd 100644
--- a/drivers/clocksource/sh_mtu2.c
+++ b/drivers/clocksource/sh_mtu2.c
@@ -221,15 +221,15 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p,
ced->cpumask = cpumask_of(0);
ced->set_mode = sh_mtu2_clock_event_mode;
+ pr_info("sh_mtu2: %s used for clock events\n", ced->name);
+ clockevents_register_device(ced);
+
ret = setup_irq(p->irqaction.irq, &p->irqaction);
if (ret) {
pr_err("sh_mtu2: failed to request irq %d\n",
p->irqaction.irq);
return;
}
-
- pr_info("sh_mtu2: %s used for clock events\n", ced->name);
- clockevents_register_device(ced);
}
static int sh_mtu2_register(struct sh_mtu2_priv *p, char *name,
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index 93c2322feab7..961f5b5ef6a3 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -323,15 +323,15 @@ static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,
ced->set_next_event = sh_tmu_clock_event_next;
ced->set_mode = sh_tmu_clock_event_mode;
+ pr_info("sh_tmu: %s used for clock events\n", ced->name);
+ clockevents_register_device(ced);
+
ret = setup_irq(p->irqaction.irq, &p->irqaction);
if (ret) {
pr_err("sh_tmu: failed to request irq %d\n",
p->irqaction.irq);
return;
}
-
- pr_info("sh_tmu: %s used for clock events\n", ced->name);
- clockevents_register_device(ced);
}
static int sh_tmu_register(struct sh_tmu_priv *p, char *name,
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index f06024668f99..537c29ac4487 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -36,17 +36,6 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector.");
-static u32 cn_idx = CN_IDX_CONNECTOR;
-static u32 cn_val = CN_VAL_CONNECTOR;
-
-module_param(cn_idx, uint, 0);
-module_param(cn_val, uint, 0);
-MODULE_PARM_DESC(cn_idx, "Connector's main device idx.");
-MODULE_PARM_DESC(cn_val, "Connector's main device val.");
-
-static DEFINE_MUTEX(notify_lock);
-static LIST_HEAD(notify_list);
-
static struct cn_dev cdev;
static int cn_already_initialized;
@@ -210,54 +199,6 @@ static void cn_rx_skb(struct sk_buff *__skb)
}
/*
- * Notification routing.
- *
- * Gets id and checks if there are notification request for it's idx
- * and val. If there are such requests notify the listeners with the
- * given notify event.
- *
- */
-static void cn_notify(struct cb_id *id, u32 notify_event)
-{
- struct cn_ctl_entry *ent;
-
- mutex_lock(&notify_lock);
- list_for_each_entry(ent, &notify_list, notify_entry) {
- int i;
- struct cn_notify_req *req;
- struct cn_ctl_msg *ctl = ent->msg;
- int idx_found, val_found;
-
- idx_found = val_found = 0;
-
- req = (struct cn_notify_req *)ctl->data;
- for (i = 0; i < ctl->idx_notify_num; ++i, ++req) {
- if (id->idx >= req->first &&
- id->idx < req->first + req->range) {
- idx_found = 1;
- break;
- }
- }
-
- for (i = 0; i < ctl->val_notify_num; ++i, ++req) {
- if (id->val >= req->first &&
- id->val < req->first + req->range) {
- val_found = 1;
- break;
- }
- }
-
- if (idx_found && val_found) {
- struct cn_msg m = { .ack = notify_event, };
-
- memcpy(&m.id, id, sizeof(m.id));
- cn_netlink_send(&m, ctl->group, GFP_KERNEL);
- }
- }
- mutex_unlock(&notify_lock);
-}
-
-/*
* Callback add routing - adds callback with given ID and name.
* If there is registered callback with the same ID it will not be added.
*
@@ -276,8 +217,6 @@ int cn_add_callback(struct cb_id *id, char *name,
if (err)
return err;
- cn_notify(id, 0);
-
return 0;
}
EXPORT_SYMBOL_GPL(cn_add_callback);
@@ -295,111 +234,9 @@ void cn_del_callback(struct cb_id *id)
struct cn_dev *dev = &cdev;
cn_queue_del_callback(dev->cbdev, id);
- cn_notify(id, 1);
}
EXPORT_SYMBOL_GPL(cn_del_callback);
-/*
- * Checks two connector's control messages to be the same.
- * Returns 1 if they are the same or if the first one is corrupted.
- */
-static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2)
-{
- int i;
- struct cn_notify_req *req1, *req2;
-
- if (m1->idx_notify_num != m2->idx_notify_num)
- return 0;
-
- if (m1->val_notify_num != m2->val_notify_num)
- return 0;
-
- if (m1->len != m2->len)
- return 0;
-
- if ((m1->idx_notify_num + m1->val_notify_num) * sizeof(*req1) !=
- m1->len)
- return 1;
-
- req1 = (struct cn_notify_req *)m1->data;
- req2 = (struct cn_notify_req *)m2->data;
-
- for (i = 0; i < m1->idx_notify_num; ++i) {
- if (req1->first != req2->first || req1->range != req2->range)
- return 0;
- req1++;
- req2++;
- }
-
- for (i = 0; i < m1->val_notify_num; ++i) {
- if (req1->first != req2->first || req1->range != req2->range)
- return 0;
- req1++;
- req2++;
- }
-
- return 1;
-}
-
-/*
- * Main connector device's callback.
- *
- * Used for notification of a request's processing.
- */
-static void cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
-{
- struct cn_ctl_msg *ctl;
- struct cn_ctl_entry *ent;
- u32 size;
-
- if (msg->len < sizeof(*ctl))
- return;
-
- ctl = (struct cn_ctl_msg *)msg->data;
-
- size = (sizeof(*ctl) + ((ctl->idx_notify_num +
- ctl->val_notify_num) *
- sizeof(struct cn_notify_req)));
-
- if (msg->len != size)
- return;
-
- if (ctl->len + sizeof(*ctl) != msg->len)
- return;
-
- /*
- * Remove notification.
- */
- if (ctl->group == 0) {
- struct cn_ctl_entry *n;
-
- mutex_lock(&notify_lock);
- list_for_each_entry_safe(ent, n, &notify_list, notify_entry) {
- if (cn_ctl_msg_equals(ent->msg, ctl)) {
- list_del(&ent->notify_entry);
- kfree(ent);
- }
- }
- mutex_unlock(&notify_lock);
-
- return;
- }
-
- size += sizeof(*ent);
-
- ent = kzalloc(size, GFP_KERNEL);
- if (!ent)
- return;
-
- ent->msg = (struct cn_ctl_msg *)(ent + 1);
-
- memcpy(ent->msg, ctl, size - sizeof(*ent));
-
- mutex_lock(&notify_lock);
- list_add(&ent->notify_entry, &notify_list);
- mutex_unlock(&notify_lock);
-}
-
static int cn_proc_show(struct seq_file *m, void *v)
{
struct cn_queue_dev *dev = cdev.cbdev;
@@ -437,11 +274,8 @@ static const struct file_operations cn_file_ops = {
static int __devinit cn_init(void)
{
struct cn_dev *dev = &cdev;
- int err;
dev->input = cn_rx_skb;
- dev->id.idx = cn_idx;
- dev->id.val = cn_val;
dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR,
CN_NETLINK_USERS + 0xf,
@@ -457,14 +291,6 @@ static int __devinit cn_init(void)
cn_already_initialized = 1;
- err = cn_add_callback(&dev->id, "connector", &cn_callback);
- if (err) {
- cn_already_initialized = 0;
- cn_queue_free_dev(dev->cbdev);
- netlink_kernel_release(dev->nls);
- return -EINVAL;
- }
-
proc_net_fops_create(&init_net, "connector", S_IRUGO, &cn_file_ops);
return 0;
@@ -478,7 +304,6 @@ static void __devexit cn_fini(void)
proc_net_remove(&init_net, "connector");
- cn_del_callback(&dev->id);
cn_queue_free_dev(dev->cbdev);
netlink_kernel_release(dev->nls);
}
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 67bc2ece7b4b..2d5d575e889d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -766,7 +766,7 @@ static void cpufreq_sysfs_release(struct kobject *kobj)
complete(&policy->kobj_unregister);
}
-static struct sysfs_ops sysfs_ops = {
+static const struct sysfs_ops sysfs_ops = {
.show = show,
.store = store,
};
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 4b34ade2332b..bd444dc93cf2 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -554,6 +554,9 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
(dbs_tuners_ins.up_threshold -
dbs_tuners_ins.down_differential);
+ if (freq_next < policy->min)
+ freq_next = policy->min;
+
if (!dbs_tuners_ins.powersave_bias) {
__cpufreq_driver_target(policy, freq_next,
CPUFREQ_RELATION_L);
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 73655aeb3a60..1aea7157d8ff 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -100,8 +100,8 @@ struct menu_device {
int needs_update;
unsigned int expected_us;
- u64 predicted_us;
unsigned int measured_us;
+ u64 predicted_us;
unsigned int exit_us;
unsigned int bucket;
u64 correction_factor[BUCKETS];
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 97b003839fb6..8719b36e1a4d 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -22,6 +22,7 @@ static int __init cpuidle_sysfs_setup(char *unused)
__setup("cpuidle_sysfs_switch", cpuidle_sysfs_setup);
static ssize_t show_available_governors(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr,
char *buf)
{
ssize_t i = 0;
@@ -41,6 +42,7 @@ out:
}
static ssize_t show_current_driver(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr,
char *buf)
{
ssize_t ret;
@@ -56,6 +58,7 @@ static ssize_t show_current_driver(struct sysdev_class *class,
}
static ssize_t show_current_governor(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr,
char *buf)
{
ssize_t ret;
@@ -71,6 +74,7 @@ static ssize_t show_current_governor(struct sysdev_class *class,
}
static ssize_t store_current_governor(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr,
const char *buf, size_t count)
{
char gov_name[CPUIDLE_NAME_LEN];
@@ -191,7 +195,7 @@ static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr,
return ret;
}
-static struct sysfs_ops cpuidle_sysfs_ops = {
+static const struct sysfs_ops cpuidle_sysfs_ops = {
.show = cpuidle_show,
.store = cpuidle_store,
};
@@ -277,7 +281,7 @@ static ssize_t cpuidle_state_show(struct kobject * kobj,
return ret;
}
-static struct sysfs_ops cpuidle_state_sysfs_ops = {
+static const struct sysfs_ops cpuidle_state_sysfs_ops = {
.show = cpuidle_state_show,
};
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index 46e899ac924e..1c3849f6b7a2 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -1274,7 +1274,7 @@ static int __exit crypto4xx_remove(struct of_device *ofdev)
return 0;
}
-static struct of_device_id crypto4xx_match[] = {
+static const struct of_device_id crypto4xx_match[] = {
{ .compatible = "amcc,ppc4xx-crypto",},
{ },
};
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c
index 4801162919d9..c7a5a43ba691 100644
--- a/drivers/crypto/geode-aes.c
+++ b/drivers/crypto/geode-aes.c
@@ -135,13 +135,13 @@ static int geode_setkey_cip(struct crypto_tfm *tfm, const u8 *key,
/*
* The requested key size is not supported by HW, do a fallback
*/
- op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
- op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
+ op->fallback.cip->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+ op->fallback.cip->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
ret = crypto_cipher_setkey(op->fallback.cip, key, len);
if (ret) {
tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
- tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK);
+ tfm->crt_flags |= (op->fallback.cip->base.crt_flags & CRYPTO_TFM_RES_MASK);
}
return ret;
}
@@ -263,7 +263,7 @@ static int fallback_init_cip(struct crypto_tfm *tfm)
if (IS_ERR(op->fallback.cip)) {
printk(KERN_ERR "Error allocating fallback algo %s\n", name);
- return PTR_ERR(op->fallback.blk);
+ return PTR_ERR(op->fallback.cip);
}
return 0;
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index 09ad9154d86c..73e8b1713b54 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -321,7 +321,7 @@ static atomic_t hifn_dev_number;
#define HIFN_PUBOPLEN_MOD_M 0x0000007f /* modulus length mask */
#define HIFN_PUBOPLEN_MOD_S 0 /* modulus length shift */
#define HIFN_PUBOPLEN_EXP_M 0x0003ff80 /* exponent length mask */
-#define HIFN_PUBOPLEN_EXP_S 7 /* exponent lenght shift */
+#define HIFN_PUBOPLEN_EXP_S 7 /* exponent length shift */
#define HIFN_PUBOPLEN_RED_M 0x003c0000 /* reducend length mask */
#define HIFN_PUBOPLEN_RED_S 18 /* reducend length shift */
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index 0af80577dc7b..d3a27e0119bc 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -57,6 +57,23 @@ static int padlock_sha_update(struct shash_desc *desc,
return crypto_shash_update(&dctx->fallback, data, length);
}
+static int padlock_sha_export(struct shash_desc *desc, void *out)
+{
+ struct padlock_sha_desc *dctx = shash_desc_ctx(desc);
+
+ return crypto_shash_export(&dctx->fallback, out);
+}
+
+static int padlock_sha_import(struct shash_desc *desc, const void *in)
+{
+ struct padlock_sha_desc *dctx = shash_desc_ctx(desc);
+ struct padlock_sha_ctx *ctx = crypto_shash_ctx(desc->tfm);
+
+ dctx->fallback.tfm = ctx->fallback;
+ dctx->fallback.flags = desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+ return crypto_shash_import(&dctx->fallback, in);
+}
+
static inline void padlock_output_block(uint32_t *src,
uint32_t *dst, size_t count)
{
@@ -235,7 +252,10 @@ static struct shash_alg sha1_alg = {
.update = padlock_sha_update,
.finup = padlock_sha1_finup,
.final = padlock_sha1_final,
+ .export = padlock_sha_export,
+ .import = padlock_sha_import,
.descsize = sizeof(struct padlock_sha_desc),
+ .statesize = sizeof(struct sha1_state),
.base = {
.cra_name = "sha1",
.cra_driver_name = "sha1-padlock",
@@ -256,7 +276,10 @@ static struct shash_alg sha256_alg = {
.update = padlock_sha_update,
.finup = padlock_sha256_finup,
.final = padlock_sha256_final,
+ .export = padlock_sha_export,
+ .import = padlock_sha_import,
.descsize = sizeof(struct padlock_sha_desc),
+ .statesize = sizeof(struct sha256_state),
.base = {
.cra_name = "sha256",
.cra_driver_name = "sha256-padlock",
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index c47ffe8a73ef..fd529d68c5ba 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -1958,7 +1958,7 @@ err_out:
return err;
}
-static struct of_device_id talitos_match[] = {
+static const struct of_device_id talitos_match[] = {
{
.compatible = "fsl,sec2.0",
},
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index e02d74b1e892..c27f80e5d531 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -13,6 +13,22 @@ menuconfig DMADEVICES
DMA Device drivers supported by the configured arch, it may
be empty in some cases.
+config DMADEVICES_DEBUG
+ bool "DMA Engine debugging"
+ depends on DMADEVICES != n
+ help
+ This is an option for use by developers; most people should
+ say N here. This enables DMA engine core and driver debugging.
+
+config DMADEVICES_VDEBUG
+ bool "DMA Engine verbose debugging"
+ depends on DMADEVICES_DEBUG != n
+ help
+ This is an option for use by developers; most people should
+ say N here. This enables deeper (more verbose) debugging of
+ the DMA engine core and drivers.
+
+
if DMADEVICES
comment "DMA Devices"
@@ -69,6 +85,13 @@ config FSL_DMA
The Elo is the DMA controller on some 82xx and 83xx parts, and the
Elo Plus is the DMA controller on 85xx and 86xx parts.
+config MPC512X_DMA
+ tristate "Freescale MPC512x built-in DMA engine support"
+ depends on PPC_MPC512x
+ select DMA_ENGINE
+ ---help---
+ Enable support for the Freescale MPC512x built-in DMA engine.
+
config MV_XOR
bool "Marvell XOR engine support"
depends on PLAT_ORION
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 807053d48232..22bba3d5e2b6 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -1,9 +1,17 @@
+ifeq ($(CONFIG_DMADEVICES_DEBUG),y)
+ EXTRA_CFLAGS += -DDEBUG
+endif
+ifeq ($(CONFIG_DMADEVICES_VDEBUG),y)
+ EXTRA_CFLAGS += -DVERBOSE_DEBUG
+endif
+
obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
obj-$(CONFIG_NET_DMA) += iovlock.o
obj-$(CONFIG_DMATEST) += dmatest.o
obj-$(CONFIG_INTEL_IOATDMA) += ioat/
obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
obj-$(CONFIG_FSL_DMA) += fsldma.o
+obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o
obj-$(CONFIG_MV_XOR) += mv_xor.o
obj-$(CONFIG_DW_DMAC) += dw_dmac.o
obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index b5f2ee0f8e2c..1656fdcdb6c2 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -39,7 +39,6 @@ struct coh901318_desc {
unsigned int sg_len;
struct coh901318_lli *data;
enum dma_data_direction dir;
- int pending_irqs;
unsigned long flags;
};
@@ -72,7 +71,6 @@ struct coh901318_chan {
unsigned long nbr_active_done;
unsigned long busy;
- int pending_irqs;
struct coh901318_base *base;
};
@@ -80,18 +78,16 @@ struct coh901318_chan {
static void coh901318_list_print(struct coh901318_chan *cohc,
struct coh901318_lli *lli)
{
- struct coh901318_lli *l;
- dma_addr_t addr = virt_to_phys(lli);
+ struct coh901318_lli *l = lli;
int i = 0;
- while (addr) {
- l = phys_to_virt(addr);
+ while (l) {
dev_vdbg(COHC_2_DEV(cohc), "i %d, lli %p, ctrl 0x%x, src 0x%x"
- ", dst 0x%x, link 0x%x link_virt 0x%p\n",
+ ", dst 0x%x, link 0x%x virt_link_addr 0x%p\n",
i, l, l->control, l->src_addr, l->dst_addr,
- l->link_addr, phys_to_virt(l->link_addr));
+ l->link_addr, l->virt_link_addr);
i++;
- addr = l->link_addr;
+ l = l->virt_link_addr;
}
}
@@ -125,7 +121,7 @@ static int coh901318_debugfs_read(struct file *file, char __user *buf,
goto err_kmalloc;
tmp = dev_buf;
- tmp += sprintf(tmp, "DMA -- enable dma channels\n");
+ tmp += sprintf(tmp, "DMA -- enabled dma channels\n");
for (i = 0; i < debugfs_dma_base->platform->max_channels; i++)
if (started_channels & (1 << i))
@@ -337,16 +333,22 @@ coh901318_desc_get(struct coh901318_chan *cohc)
* TODO: alloc a pile of descs instead of just one,
* avoid many small allocations.
*/
- desc = kmalloc(sizeof(struct coh901318_desc), GFP_NOWAIT);
+ desc = kzalloc(sizeof(struct coh901318_desc), GFP_NOWAIT);
if (desc == NULL)
goto out;
INIT_LIST_HEAD(&desc->node);
+ dma_async_tx_descriptor_init(&desc->desc, &cohc->chan);
} else {
/* Reuse an old desc. */
desc = list_first_entry(&cohc->free,
struct coh901318_desc,
node);
list_del(&desc->node);
+ /* Initialize it a bit so it's not insane */
+ desc->sg = NULL;
+ desc->sg_len = 0;
+ desc->desc.callback = NULL;
+ desc->desc.callback_param = NULL;
}
out:
@@ -364,10 +366,6 @@ static void
coh901318_desc_submit(struct coh901318_chan *cohc, struct coh901318_desc *desc)
{
list_add_tail(&desc->node, &cohc->active);
-
- BUG_ON(cohc->pending_irqs != 0);
-
- cohc->pending_irqs = desc->pending_irqs;
}
static struct coh901318_desc *
@@ -592,6 +590,10 @@ static struct coh901318_desc *coh901318_queue_start(struct coh901318_chan *cohc)
return cohd_que;
}
+/*
+ * This tasklet is called from the interrupt handler to
+ * handle each descriptor (DMA job) that is sent to a channel.
+ */
static void dma_tasklet(unsigned long data)
{
struct coh901318_chan *cohc = (struct coh901318_chan *) data;
@@ -600,57 +602,58 @@ static void dma_tasklet(unsigned long data)
dma_async_tx_callback callback;
void *callback_param;
+ dev_vdbg(COHC_2_DEV(cohc), "[%s] chan_id %d"
+ " nbr_active_done %ld\n", __func__,
+ cohc->id, cohc->nbr_active_done);
+
spin_lock_irqsave(&cohc->lock, flags);
- /* get first active entry from list */
+ /* get first active descriptor entry from list */
cohd_fin = coh901318_first_active_get(cohc);
- BUG_ON(cohd_fin->pending_irqs == 0);
-
if (cohd_fin == NULL)
goto err;
- cohd_fin->pending_irqs--;
- cohc->completed = cohd_fin->desc.cookie;
-
- BUG_ON(cohc->nbr_active_done && cohd_fin == NULL);
-
- if (cohc->nbr_active_done == 0)
- return;
+ /* locate callback to client */
+ callback = cohd_fin->desc.callback;
+ callback_param = cohd_fin->desc.callback_param;
- if (!cohd_fin->pending_irqs) {
- /* release the lli allocation*/
- coh901318_lli_free(&cohc->base->pool, &cohd_fin->data);
- }
+ /* sign this job as completed on the channel */
+ cohc->completed = cohd_fin->desc.cookie;
- dev_vdbg(COHC_2_DEV(cohc), "[%s] chan_id %d pending_irqs %d"
- " nbr_active_done %ld\n", __func__,
- cohc->id, cohc->pending_irqs, cohc->nbr_active_done);
+ /* release the lli allocation and remove the descriptor */
+ coh901318_lli_free(&cohc->base->pool, &cohd_fin->data);
- /* callback to client */
- callback = cohd_fin->desc.callback;
- callback_param = cohd_fin->desc.callback_param;
+ /* return desc to free-list */
+ coh901318_desc_remove(cohd_fin);
+ coh901318_desc_free(cohc, cohd_fin);
- if (!cohd_fin->pending_irqs) {
- coh901318_desc_remove(cohd_fin);
+ spin_unlock_irqrestore(&cohc->lock, flags);
- /* return desc to free-list */
- coh901318_desc_free(cohc, cohd_fin);
- }
+ /* Call the callback when we're done */
+ if (callback)
+ callback(callback_param);
- if (cohc->nbr_active_done)
- cohc->nbr_active_done--;
+ spin_lock_irqsave(&cohc->lock, flags);
+ /*
+ * If another interrupt fired while the tasklet was scheduling,
+ * we don't get called twice, so we have this number of active
+ * counter that keep track of the number of IRQs expected to
+ * be handled for this channel. If there happen to be more than
+ * one IRQ to be ack:ed, we simply schedule this tasklet again.
+ */
+ cohc->nbr_active_done--;
if (cohc->nbr_active_done) {
+ dev_dbg(COHC_2_DEV(cohc), "scheduling tasklet again, new IRQs "
+ "came in while we were scheduling this tasklet\n");
if (cohc_chan_conf(cohc)->priority_high)
tasklet_hi_schedule(&cohc->tasklet);
else
tasklet_schedule(&cohc->tasklet);
}
- spin_unlock_irqrestore(&cohc->lock, flags);
- if (callback)
- callback(callback_param);
+ spin_unlock_irqrestore(&cohc->lock, flags);
return;
@@ -669,16 +672,17 @@ static void dma_tc_handle(struct coh901318_chan *cohc)
if (!cohc->allocated)
return;
- BUG_ON(cohc->pending_irqs == 0);
+ spin_lock(&cohc->lock);
- cohc->pending_irqs--;
cohc->nbr_active_done++;
- if (cohc->pending_irqs == 0 && coh901318_queue_start(cohc) == NULL)
+ if (coh901318_queue_start(cohc) == NULL)
cohc->busy = 0;
BUG_ON(list_empty(&cohc->active));
+ spin_unlock(&cohc->lock);
+
if (cohc_chan_conf(cohc)->priority_high)
tasklet_hi_schedule(&cohc->tasklet);
else
@@ -872,6 +876,7 @@ coh901318_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
struct coh901318_chan *cohc = to_coh901318_chan(chan);
int lli_len;
u32 ctrl_last = cohc_chan_param(cohc)->ctrl_lli_last;
+ int ret;
spin_lock_irqsave(&cohc->lock, flg);
@@ -892,22 +897,19 @@ coh901318_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
if (data == NULL)
goto err;
- cohd = coh901318_desc_get(cohc);
- cohd->sg = NULL;
- cohd->sg_len = 0;
- cohd->data = data;
-
- cohd->pending_irqs =
- coh901318_lli_fill_memcpy(
- &cohc->base->pool, data, src, size, dest,
- cohc_chan_param(cohc)->ctrl_lli_chained,
- ctrl_last);
- cohd->flags = flags;
+ ret = coh901318_lli_fill_memcpy(
+ &cohc->base->pool, data, src, size, dest,
+ cohc_chan_param(cohc)->ctrl_lli_chained,
+ ctrl_last);
+ if (ret)
+ goto err;
COH_DBG(coh901318_list_print(cohc, data));
- dma_async_tx_descriptor_init(&cohd->desc, chan);
-
+ /* Pick a descriptor to handle this transfer */
+ cohd = coh901318_desc_get(cohc);
+ cohd->data = data;
+ cohd->flags = flags;
cohd->desc.tx_submit = coh901318_tx_submit;
spin_unlock_irqrestore(&cohc->lock, flg);
@@ -926,6 +928,7 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
struct coh901318_chan *cohc = to_coh901318_chan(chan);
struct coh901318_lli *data;
struct coh901318_desc *cohd;
+ const struct coh901318_params *params;
struct scatterlist *sg;
int len = 0;
int size;
@@ -933,7 +936,9 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
u32 ctrl_chained = cohc_chan_param(cohc)->ctrl_lli_chained;
u32 ctrl = cohc_chan_param(cohc)->ctrl_lli;
u32 ctrl_last = cohc_chan_param(cohc)->ctrl_lli_last;
+ u32 config;
unsigned long flg;
+ int ret;
if (!sgl)
goto out;
@@ -949,15 +954,14 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
/* Trigger interrupt after last lli */
ctrl_last |= COH901318_CX_CTRL_TC_IRQ_ENABLE;
- cohd = coh901318_desc_get(cohc);
- cohd->sg = NULL;
- cohd->sg_len = 0;
- cohd->dir = direction;
+ params = cohc_chan_param(cohc);
+ config = params->config;
if (direction == DMA_TO_DEVICE) {
u32 tx_flags = COH901318_CX_CTRL_PRDD_SOURCE |
COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE;
+ config |= COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY;
ctrl_chained |= tx_flags;
ctrl_last |= tx_flags;
ctrl |= tx_flags;
@@ -965,16 +969,14 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
u32 rx_flags = COH901318_CX_CTRL_PRDD_DEST |
COH901318_CX_CTRL_DST_ADDR_INC_ENABLE;
+ config |= COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY;
ctrl_chained |= rx_flags;
ctrl_last |= rx_flags;
ctrl |= rx_flags;
} else
goto err_direction;
- dma_async_tx_descriptor_init(&cohd->desc, chan);
-
- cohd->desc.tx_submit = coh901318_tx_submit;
-
+ coh901318_set_conf(cohc, config);
/* The dma only supports transmitting packages up to
* MAX_DMA_PACKET_SIZE. Calculate to total number of
@@ -996,32 +998,37 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
len += factor;
}
+ pr_debug("Allocate %d lli:s for this transfer\n", len);
data = coh901318_lli_alloc(&cohc->base->pool, len);
if (data == NULL)
goto err_dma_alloc;
/* initiate allocated data list */
- cohd->pending_irqs =
- coh901318_lli_fill_sg(&cohc->base->pool, data, sgl, sg_len,
- cohc_dev_addr(cohc),
- ctrl_chained,
- ctrl,
- ctrl_last,
- direction, COH901318_CX_CTRL_TC_IRQ_ENABLE);
- cohd->data = data;
-
- cohd->flags = flags;
+ ret = coh901318_lli_fill_sg(&cohc->base->pool, data, sgl, sg_len,
+ cohc_dev_addr(cohc),
+ ctrl_chained,
+ ctrl,
+ ctrl_last,
+ direction, COH901318_CX_CTRL_TC_IRQ_ENABLE);
+ if (ret)
+ goto err_lli_fill;
COH_DBG(coh901318_list_print(cohc, data));
+ /* Pick a descriptor to handle this transfer */
+ cohd = coh901318_desc_get(cohc);
+ cohd->dir = direction;
+ cohd->flags = flags;
+ cohd->desc.tx_submit = coh901318_tx_submit;
+ cohd->data = data;
+
spin_unlock_irqrestore(&cohc->lock, flg);
return &cohd->desc;
+ err_lli_fill:
err_dma_alloc:
err_direction:
- coh901318_desc_remove(cohd);
- coh901318_desc_free(cohc, cohd);
spin_unlock_irqrestore(&cohc->lock, flg);
out:
return NULL;
@@ -1094,9 +1101,8 @@ coh901318_terminate_all(struct dma_chan *chan)
/* release the lli allocation*/
coh901318_lli_free(&cohc->base->pool, &cohd->data);
- coh901318_desc_remove(cohd);
-
/* return desc to free-list */
+ coh901318_desc_remove(cohd);
coh901318_desc_free(cohc, cohd);
}
@@ -1104,16 +1110,14 @@ coh901318_terminate_all(struct dma_chan *chan)
/* release the lli allocation*/
coh901318_lli_free(&cohc->base->pool, &cohd->data);
- coh901318_desc_remove(cohd);
-
/* return desc to free-list */
+ coh901318_desc_remove(cohd);
coh901318_desc_free(cohc, cohd);
}
cohc->nbr_active_done = 0;
cohc->busy = 0;
- cohc->pending_irqs = 0;
spin_unlock_irqrestore(&cohc->lock, flags);
}
@@ -1140,7 +1144,6 @@ void coh901318_base_init(struct dma_device *dma, const int *pick_chans,
spin_lock_init(&cohc->lock);
- cohc->pending_irqs = 0;
cohc->nbr_active_done = 0;
cohc->busy = 0;
INIT_LIST_HEAD(&cohc->free);
@@ -1256,12 +1259,17 @@ static int __init coh901318_probe(struct platform_device *pdev)
base->dma_memcpy.device_issue_pending = coh901318_issue_pending;
base->dma_memcpy.device_terminate_all = coh901318_terminate_all;
base->dma_memcpy.dev = &pdev->dev;
+ /*
+ * This controller can only access address at even 32bit boundaries,
+ * i.e. 2^2
+ */
+ base->dma_memcpy.copy_align = 2;
err = dma_async_device_register(&base->dma_memcpy);
if (err)
goto err_register_memcpy;
- dev_dbg(&pdev->dev, "Initialized COH901318 DMA on virtual base 0x%08x\n",
+ dev_info(&pdev->dev, "Initialized COH901318 DMA on virtual base 0x%08x\n",
(u32) base->virtbase);
return err;
diff --git a/drivers/dma/coh901318_lli.c b/drivers/dma/coh901318_lli.c
index f5120f238a4d..71d58c1a1e86 100644
--- a/drivers/dma/coh901318_lli.c
+++ b/drivers/dma/coh901318_lli.c
@@ -74,6 +74,8 @@ coh901318_lli_alloc(struct coh901318_pool *pool, unsigned int len)
lli = head;
lli->phy_this = phy;
+ lli->link_addr = 0x00000000;
+ lli->virt_link_addr = 0x00000000U;
for (i = 1; i < len; i++) {
lli_prev = lli;
@@ -85,13 +87,13 @@ coh901318_lli_alloc(struct coh901318_pool *pool, unsigned int len)
DEBUGFS_POOL_COUNTER_ADD(pool, 1);
lli->phy_this = phy;
+ lli->link_addr = 0x00000000;
+ lli->virt_link_addr = 0x00000000U;
lli_prev->link_addr = phy;
lli_prev->virt_link_addr = lli;
}
- lli->link_addr = 0x00000000U;
-
spin_unlock(&pool->lock);
return head;
@@ -166,8 +168,7 @@ coh901318_lli_fill_memcpy(struct coh901318_pool *pool,
lli->src_addr = src;
lli->dst_addr = dst;
- /* One irq per single transfer */
- return 1;
+ return 0;
}
int
@@ -223,8 +224,7 @@ coh901318_lli_fill_single(struct coh901318_pool *pool,
lli->src_addr = src;
lli->dst_addr = dst;
- /* One irq per single transfer */
- return 1;
+ return 0;
}
int
@@ -240,7 +240,6 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool,
u32 ctrl_sg;
dma_addr_t src = 0;
dma_addr_t dst = 0;
- int nbr_of_irq = 0;
u32 bytes_to_transfer;
u32 elem_size;
@@ -269,15 +268,12 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool,
ctrl_sg = ctrl ? ctrl : ctrl_last;
- if ((ctrl_sg & ctrl_irq_mask))
- nbr_of_irq++;
-
if (dir == DMA_TO_DEVICE)
/* increment source address */
- src = sg_dma_address(sg);
+ src = sg_phys(sg);
else
/* increment destination address */
- dst = sg_dma_address(sg);
+ dst = sg_phys(sg);
bytes_to_transfer = sg_dma_len(sg);
@@ -310,8 +306,7 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool,
}
spin_unlock(&pool->lock);
- /* There can be many IRQs per sg transfer */
- return nbr_of_irq;
+ return 0;
err:
spin_unlock(&pool->lock);
return -EINVAL;
diff --git a/drivers/dma/coh901318_lli.h b/drivers/dma/coh901318_lli.h
index 7bf713b79c6b..7a5c80990e9e 100644
--- a/drivers/dma/coh901318_lli.h
+++ b/drivers/dma/coh901318_lli.h
@@ -30,7 +30,7 @@ struct device;
* @pool: pool handle
* @dev: dma device
* @lli_nbr: number of lli:s in the pool
- * @algin: adress alignemtn of lli:s
+ * @algin: address alignemtn of lli:s
* returns 0 on success otherwise none zero
*/
int coh901318_pool_create(struct coh901318_pool *pool,
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 6f51a0a7a8bb..87399cafce37 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -284,7 +284,7 @@ struct dma_chan_tbl_ent {
/**
* channel_table - percpu lookup table for memory-to-memory offload providers
*/
-static struct dma_chan_tbl_ent *channel_table[DMA_TX_TYPE_END];
+static struct dma_chan_tbl_ent __percpu *channel_table[DMA_TX_TYPE_END];
static int __init dma_channel_table_init(void)
{
@@ -826,6 +826,7 @@ void dma_async_device_unregister(struct dma_device *device)
chan->dev->chan = NULL;
mutex_unlock(&dma_list_mutex);
device_unregister(&chan->dev->device);
+ free_percpu(chan->local);
}
}
EXPORT_SYMBOL(dma_async_device_unregister);
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index 8b905161fbf4..6fa55fe3dd24 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -237,7 +237,7 @@ static int dmatest_func(void *data)
dma_cookie_t cookie;
enum dma_status status;
enum dma_ctrl_flags flags;
- u8 pq_coefs[pq_sources];
+ u8 pq_coefs[pq_sources + 1];
int ret;
int src_cnt;
int dst_cnt;
@@ -257,7 +257,7 @@ static int dmatest_func(void *data)
} else if (thread->type == DMA_PQ) {
src_cnt = pq_sources | 1; /* force odd to ensure dst = src */
dst_cnt = 2;
- for (i = 0; i < pq_sources; i++)
+ for (i = 0; i < src_cnt; i++)
pq_coefs[i] = 1;
} else
goto err_srcs;
@@ -347,7 +347,7 @@ static int dmatest_func(void *data)
else if (thread->type == DMA_XOR)
tx = dev->device_prep_dma_xor(chan,
dma_dsts[0] + dst_off,
- dma_srcs, xor_sources,
+ dma_srcs, src_cnt,
len, flags);
else if (thread->type == DMA_PQ) {
dma_addr_t dma_pq[dst_cnt];
@@ -355,7 +355,7 @@ static int dmatest_func(void *data)
for (i = 0; i < dst_cnt; i++)
dma_pq[i] = dma_dsts[i] + dst_off;
tx = dev->device_prep_dma_pq(chan, dma_pq, dma_srcs,
- pq_sources, pq_coefs,
+ src_cnt, pq_coefs,
len, flags);
}
@@ -467,7 +467,7 @@ err_srcs:
if (iterations > 0)
while (!kthread_should_stop()) {
- DECLARE_WAIT_QUEUE_HEAD(wait_dmatest_exit);
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_dmatest_exit);
interruptible_sleep_on(&wait_dmatest_exit);
}
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 296f9e747fac..bbb4be5a3ff4 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -37,19 +37,19 @@
#include <asm/fsldma.h>
#include "fsldma.h"
-static void dma_init(struct fsl_dma_chan *fsl_chan)
+static void dma_init(struct fsldma_chan *chan)
{
/* Reset the channel */
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, 0, 32);
+ DMA_OUT(chan, &chan->regs->mr, 0, 32);
- switch (fsl_chan->feature & FSL_DMA_IP_MASK) {
+ switch (chan->feature & FSL_DMA_IP_MASK) {
case FSL_DMA_IP_85XX:
/* Set the channel to below modes:
* EIE - Error interrupt enable
* EOSIE - End of segments interrupt enable (basic mode)
* EOLNIE - End of links interrupt enable
*/
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EIE
+ DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EIE
| FSL_DMA_MR_EOLNIE | FSL_DMA_MR_EOSIE, 32);
break;
case FSL_DMA_IP_83XX:
@@ -57,170 +57,146 @@ static void dma_init(struct fsl_dma_chan *fsl_chan)
* EOTIE - End-of-transfer interrupt enable
* PRC_RM - PCI read multiple
*/
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EOTIE
+ DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EOTIE
| FSL_DMA_MR_PRC_RM, 32);
break;
}
-
}
-static void set_sr(struct fsl_dma_chan *fsl_chan, u32 val)
+static void set_sr(struct fsldma_chan *chan, u32 val)
{
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->sr, val, 32);
+ DMA_OUT(chan, &chan->regs->sr, val, 32);
}
-static u32 get_sr(struct fsl_dma_chan *fsl_chan)
+static u32 get_sr(struct fsldma_chan *chan)
{
- return DMA_IN(fsl_chan, &fsl_chan->reg_base->sr, 32);
+ return DMA_IN(chan, &chan->regs->sr, 32);
}
-static void set_desc_cnt(struct fsl_dma_chan *fsl_chan,
+static void set_desc_cnt(struct fsldma_chan *chan,
struct fsl_dma_ld_hw *hw, u32 count)
{
- hw->count = CPU_TO_DMA(fsl_chan, count, 32);
+ hw->count = CPU_TO_DMA(chan, count, 32);
}
-static void set_desc_src(struct fsl_dma_chan *fsl_chan,
+static void set_desc_src(struct fsldma_chan *chan,
struct fsl_dma_ld_hw *hw, dma_addr_t src)
{
u64 snoop_bits;
- snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
+ snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
? ((u64)FSL_DMA_SATR_SREADTYPE_SNOOP_READ << 32) : 0;
- hw->src_addr = CPU_TO_DMA(fsl_chan, snoop_bits | src, 64);
+ hw->src_addr = CPU_TO_DMA(chan, snoop_bits | src, 64);
}
-static void set_desc_dest(struct fsl_dma_chan *fsl_chan,
- struct fsl_dma_ld_hw *hw, dma_addr_t dest)
+static void set_desc_dst(struct fsldma_chan *chan,
+ struct fsl_dma_ld_hw *hw, dma_addr_t dst)
{
u64 snoop_bits;
- snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
+ snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
? ((u64)FSL_DMA_DATR_DWRITETYPE_SNOOP_WRITE << 32) : 0;
- hw->dst_addr = CPU_TO_DMA(fsl_chan, snoop_bits | dest, 64);
+ hw->dst_addr = CPU_TO_DMA(chan, snoop_bits | dst, 64);
}
-static void set_desc_next(struct fsl_dma_chan *fsl_chan,
+static void set_desc_next(struct fsldma_chan *chan,
struct fsl_dma_ld_hw *hw, dma_addr_t next)
{
u64 snoop_bits;
- snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX)
+ snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX)
? FSL_DMA_SNEN : 0;
- hw->next_ln_addr = CPU_TO_DMA(fsl_chan, snoop_bits | next, 64);
-}
-
-static void set_cdar(struct fsl_dma_chan *fsl_chan, dma_addr_t addr)
-{
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->cdar, addr | FSL_DMA_SNEN, 64);
+ hw->next_ln_addr = CPU_TO_DMA(chan, snoop_bits | next, 64);
}
-static dma_addr_t get_cdar(struct fsl_dma_chan *fsl_chan)
+static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr)
{
- return DMA_IN(fsl_chan, &fsl_chan->reg_base->cdar, 64) & ~FSL_DMA_SNEN;
+ DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64);
}
-static void set_ndar(struct fsl_dma_chan *fsl_chan, dma_addr_t addr)
+static dma_addr_t get_cdar(struct fsldma_chan *chan)
{
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->ndar, addr, 64);
+ return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN;
}
-static dma_addr_t get_ndar(struct fsl_dma_chan *fsl_chan)
+static dma_addr_t get_ndar(struct fsldma_chan *chan)
{
- return DMA_IN(fsl_chan, &fsl_chan->reg_base->ndar, 64);
+ return DMA_IN(chan, &chan->regs->ndar, 64);
}
-static u32 get_bcr(struct fsl_dma_chan *fsl_chan)
+static u32 get_bcr(struct fsldma_chan *chan)
{
- return DMA_IN(fsl_chan, &fsl_chan->reg_base->bcr, 32);
+ return DMA_IN(chan, &chan->regs->bcr, 32);
}
-static int dma_is_idle(struct fsl_dma_chan *fsl_chan)
+static int dma_is_idle(struct fsldma_chan *chan)
{
- u32 sr = get_sr(fsl_chan);
+ u32 sr = get_sr(chan);
return (!(sr & FSL_DMA_SR_CB)) || (sr & FSL_DMA_SR_CH);
}
-static void dma_start(struct fsl_dma_chan *fsl_chan)
+static void dma_start(struct fsldma_chan *chan)
{
- u32 mr_set = 0;
-
- if (fsl_chan->feature & FSL_DMA_CHAN_PAUSE_EXT) {
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->bcr, 0, 32);
- mr_set |= FSL_DMA_MR_EMP_EN;
- } else if ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32)
- & ~FSL_DMA_MR_EMP_EN, 32);
+ u32 mode;
+
+ mode = DMA_IN(chan, &chan->regs->mr, 32);
+
+ if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
+ if (chan->feature & FSL_DMA_CHAN_PAUSE_EXT) {
+ DMA_OUT(chan, &chan->regs->bcr, 0, 32);
+ mode |= FSL_DMA_MR_EMP_EN;
+ } else {
+ mode &= ~FSL_DMA_MR_EMP_EN;
+ }
}
- if (fsl_chan->feature & FSL_DMA_CHAN_START_EXT)
- mr_set |= FSL_DMA_MR_EMS_EN;
+ if (chan->feature & FSL_DMA_CHAN_START_EXT)
+ mode |= FSL_DMA_MR_EMS_EN;
else
- mr_set |= FSL_DMA_MR_CS;
+ mode |= FSL_DMA_MR_CS;
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32)
- | mr_set, 32);
+ DMA_OUT(chan, &chan->regs->mr, mode, 32);
}
-static void dma_halt(struct fsl_dma_chan *fsl_chan)
+static void dma_halt(struct fsldma_chan *chan)
{
+ u32 mode;
int i;
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) | FSL_DMA_MR_CA,
- 32);
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) & ~(FSL_DMA_MR_CS
- | FSL_DMA_MR_EMS_EN | FSL_DMA_MR_CA), 32);
+ mode = DMA_IN(chan, &chan->regs->mr, 32);
+ mode |= FSL_DMA_MR_CA;
+ DMA_OUT(chan, &chan->regs->mr, mode, 32);
+
+ mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN | FSL_DMA_MR_CA);
+ DMA_OUT(chan, &chan->regs->mr, mode, 32);
for (i = 0; i < 100; i++) {
- if (dma_is_idle(fsl_chan))
- break;
+ if (dma_is_idle(chan))
+ return;
+
udelay(10);
}
- if (i >= 100 && !dma_is_idle(fsl_chan))
- dev_err(fsl_chan->dev, "DMA halt timeout!\n");
+
+ if (!dma_is_idle(chan))
+ dev_err(chan->dev, "DMA halt timeout!\n");
}
-static void set_ld_eol(struct fsl_dma_chan *fsl_chan,
+static void set_ld_eol(struct fsldma_chan *chan,
struct fsl_desc_sw *desc)
{
u64 snoop_bits;
- snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX)
+ snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX)
? FSL_DMA_SNEN : 0;
- desc->hw.next_ln_addr = CPU_TO_DMA(fsl_chan,
- DMA_TO_CPU(fsl_chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL
+ desc->hw.next_ln_addr = CPU_TO_DMA(chan,
+ DMA_TO_CPU(chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL
| snoop_bits, 64);
}
-static void append_ld_queue(struct fsl_dma_chan *fsl_chan,
- struct fsl_desc_sw *new_desc)
-{
- struct fsl_desc_sw *queue_tail = to_fsl_desc(fsl_chan->ld_queue.prev);
-
- if (list_empty(&fsl_chan->ld_queue))
- return;
-
- /* Link to the new descriptor physical address and
- * Enable End-of-segment interrupt for
- * the last link descriptor.
- * (the previous node's next link descriptor)
- *
- * For FSL_DMA_IP_83xx, the snoop enable bit need be set.
- */
- queue_tail->hw.next_ln_addr = CPU_TO_DMA(fsl_chan,
- new_desc->async_tx.phys | FSL_DMA_EOSIE |
- (((fsl_chan->feature & FSL_DMA_IP_MASK)
- == FSL_DMA_IP_83XX) ? FSL_DMA_SNEN : 0), 64);
-}
-
/**
* fsl_chan_set_src_loop_size - Set source address hold transfer size
- * @fsl_chan : Freescale DMA channel
+ * @chan : Freescale DMA channel
* @size : Address loop size, 0 for disable loop
*
* The set source address hold transfer size. The source
@@ -229,29 +205,30 @@ static void append_ld_queue(struct fsl_dma_chan *fsl_chan,
* read data from SA, SA + 1, SA + 2, SA + 3, then loop back to SA,
* SA + 1 ... and so on.
*/
-static void fsl_chan_set_src_loop_size(struct fsl_dma_chan *fsl_chan, int size)
+static void fsl_chan_set_src_loop_size(struct fsldma_chan *chan, int size)
{
+ u32 mode;
+
+ mode = DMA_IN(chan, &chan->regs->mr, 32);
+
switch (size) {
case 0:
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) &
- (~FSL_DMA_MR_SAHE), 32);
+ mode &= ~FSL_DMA_MR_SAHE;
break;
case 1:
case 2:
case 4:
case 8:
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) |
- FSL_DMA_MR_SAHE | (__ilog2(size) << 14),
- 32);
+ mode |= FSL_DMA_MR_SAHE | (__ilog2(size) << 14);
break;
}
+
+ DMA_OUT(chan, &chan->regs->mr, mode, 32);
}
/**
- * fsl_chan_set_dest_loop_size - Set destination address hold transfer size
- * @fsl_chan : Freescale DMA channel
+ * fsl_chan_set_dst_loop_size - Set destination address hold transfer size
+ * @chan : Freescale DMA channel
* @size : Address loop size, 0 for disable loop
*
* The set destination address hold transfer size. The destination
@@ -260,29 +237,30 @@ static void fsl_chan_set_src_loop_size(struct fsl_dma_chan *fsl_chan, int size)
* write data to TA, TA + 1, TA + 2, TA + 3, then loop back to TA,
* TA + 1 ... and so on.
*/
-static void fsl_chan_set_dest_loop_size(struct fsl_dma_chan *fsl_chan, int size)
+static void fsl_chan_set_dst_loop_size(struct fsldma_chan *chan, int size)
{
+ u32 mode;
+
+ mode = DMA_IN(chan, &chan->regs->mr, 32);
+
switch (size) {
case 0:
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) &
- (~FSL_DMA_MR_DAHE), 32);
+ mode &= ~FSL_DMA_MR_DAHE;
break;
case 1:
case 2:
case 4:
case 8:
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) |
- FSL_DMA_MR_DAHE | (__ilog2(size) << 16),
- 32);
+ mode |= FSL_DMA_MR_DAHE | (__ilog2(size) << 16);
break;
}
+
+ DMA_OUT(chan, &chan->regs->mr, mode, 32);
}
/**
* fsl_chan_set_request_count - Set DMA Request Count for external control
- * @fsl_chan : Freescale DMA channel
+ * @chan : Freescale DMA channel
* @size : Number of bytes to transfer in a single request
*
* The Freescale DMA channel can be controlled by the external signal DREQ#.
@@ -292,35 +270,38 @@ static void fsl_chan_set_dest_loop_size(struct fsl_dma_chan *fsl_chan, int size)
*
* A size of 0 disables external pause control. The maximum size is 1024.
*/
-static void fsl_chan_set_request_count(struct fsl_dma_chan *fsl_chan, int size)
+static void fsl_chan_set_request_count(struct fsldma_chan *chan, int size)
{
+ u32 mode;
+
BUG_ON(size > 1024);
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32)
- | ((__ilog2(size) << 24) & 0x0f000000),
- 32);
+
+ mode = DMA_IN(chan, &chan->regs->mr, 32);
+ mode |= (__ilog2(size) << 24) & 0x0f000000;
+
+ DMA_OUT(chan, &chan->regs->mr, mode, 32);
}
/**
* fsl_chan_toggle_ext_pause - Toggle channel external pause status
- * @fsl_chan : Freescale DMA channel
+ * @chan : Freescale DMA channel
* @enable : 0 is disabled, 1 is enabled.
*
* The Freescale DMA channel can be controlled by the external signal DREQ#.
* The DMA Request Count feature should be used in addition to this feature
* to set the number of bytes to transfer before pausing the channel.
*/
-static void fsl_chan_toggle_ext_pause(struct fsl_dma_chan *fsl_chan, int enable)
+static void fsl_chan_toggle_ext_pause(struct fsldma_chan *chan, int enable)
{
if (enable)
- fsl_chan->feature |= FSL_DMA_CHAN_PAUSE_EXT;
+ chan->feature |= FSL_DMA_CHAN_PAUSE_EXT;
else
- fsl_chan->feature &= ~FSL_DMA_CHAN_PAUSE_EXT;
+ chan->feature &= ~FSL_DMA_CHAN_PAUSE_EXT;
}
/**
* fsl_chan_toggle_ext_start - Toggle channel external start status
- * @fsl_chan : Freescale DMA channel
+ * @chan : Freescale DMA channel
* @enable : 0 is disabled, 1 is enabled.
*
* If enable the external start, the channel can be started by an
@@ -328,141 +309,196 @@ static void fsl_chan_toggle_ext_pause(struct fsl_dma_chan *fsl_chan, int enable)
* transfer immediately. The DMA channel will wait for the
* control pin asserted.
*/
-static void fsl_chan_toggle_ext_start(struct fsl_dma_chan *fsl_chan, int enable)
+static void fsl_chan_toggle_ext_start(struct fsldma_chan *chan, int enable)
{
if (enable)
- fsl_chan->feature |= FSL_DMA_CHAN_START_EXT;
+ chan->feature |= FSL_DMA_CHAN_START_EXT;
else
- fsl_chan->feature &= ~FSL_DMA_CHAN_START_EXT;
+ chan->feature &= ~FSL_DMA_CHAN_START_EXT;
+}
+
+static void append_ld_queue(struct fsldma_chan *chan,
+ struct fsl_desc_sw *desc)
+{
+ struct fsl_desc_sw *tail = to_fsl_desc(chan->ld_pending.prev);
+
+ if (list_empty(&chan->ld_pending))
+ goto out_splice;
+
+ /*
+ * Add the hardware descriptor to the chain of hardware descriptors
+ * that already exists in memory.
+ *
+ * This will un-set the EOL bit of the existing transaction, and the
+ * last link in this transaction will become the EOL descriptor.
+ */
+ set_desc_next(chan, &tail->hw, desc->async_tx.phys);
+
+ /*
+ * Add the software descriptor and all children to the list
+ * of pending transactions
+ */
+out_splice:
+ list_splice_tail_init(&desc->tx_list, &chan->ld_pending);
}
static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
{
- struct fsl_dma_chan *fsl_chan = to_fsl_chan(tx->chan);
+ struct fsldma_chan *chan = to_fsl_chan(tx->chan);
struct fsl_desc_sw *desc = tx_to_fsl_desc(tx);
struct fsl_desc_sw *child;
unsigned long flags;
dma_cookie_t cookie;
- /* cookie increment and adding to ld_queue must be atomic */
- spin_lock_irqsave(&fsl_chan->desc_lock, flags);
+ spin_lock_irqsave(&chan->desc_lock, flags);
- cookie = fsl_chan->common.cookie;
+ /*
+ * assign cookies to all of the software descriptors
+ * that make up this transaction
+ */
+ cookie = chan->common.cookie;
list_for_each_entry(child, &desc->tx_list, node) {
cookie++;
if (cookie < 0)
cookie = 1;
- desc->async_tx.cookie = cookie;
+ child->async_tx.cookie = cookie;
}
- fsl_chan->common.cookie = cookie;
- append_ld_queue(fsl_chan, desc);
- list_splice_init(&desc->tx_list, fsl_chan->ld_queue.prev);
+ chan->common.cookie = cookie;
+
+ /* put this transaction onto the tail of the pending queue */
+ append_ld_queue(chan, desc);
- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
return cookie;
}
/**
* fsl_dma_alloc_descriptor - Allocate descriptor from channel's DMA pool.
- * @fsl_chan : Freescale DMA channel
+ * @chan : Freescale DMA channel
*
* Return - The descriptor allocated. NULL for failed.
*/
static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
- struct fsl_dma_chan *fsl_chan)
+ struct fsldma_chan *chan)
{
+ struct fsl_desc_sw *desc;
dma_addr_t pdesc;
- struct fsl_desc_sw *desc_sw;
-
- desc_sw = dma_pool_alloc(fsl_chan->desc_pool, GFP_ATOMIC, &pdesc);
- if (desc_sw) {
- memset(desc_sw, 0, sizeof(struct fsl_desc_sw));
- INIT_LIST_HEAD(&desc_sw->tx_list);
- dma_async_tx_descriptor_init(&desc_sw->async_tx,
- &fsl_chan->common);
- desc_sw->async_tx.tx_submit = fsl_dma_tx_submit;
- desc_sw->async_tx.phys = pdesc;
+
+ desc = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &pdesc);
+ if (!desc) {
+ dev_dbg(chan->dev, "out of memory for link desc\n");
+ return NULL;
}
- return desc_sw;
+ memset(desc, 0, sizeof(*desc));
+ INIT_LIST_HEAD(&desc->tx_list);
+ dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+ desc->async_tx.tx_submit = fsl_dma_tx_submit;
+ desc->async_tx.phys = pdesc;
+
+ return desc;
}
/**
* fsl_dma_alloc_chan_resources - Allocate resources for DMA channel.
- * @fsl_chan : Freescale DMA channel
+ * @chan : Freescale DMA channel
*
* This function will create a dma pool for descriptor allocation.
*
* Return - The number of descriptors allocated.
*/
-static int fsl_dma_alloc_chan_resources(struct dma_chan *chan)
+static int fsl_dma_alloc_chan_resources(struct dma_chan *dchan)
{
- struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan);
+ struct fsldma_chan *chan = to_fsl_chan(dchan);
/* Has this channel already been allocated? */
- if (fsl_chan->desc_pool)
+ if (chan->desc_pool)
return 1;
- /* We need the descriptor to be aligned to 32bytes
+ /*
+ * We need the descriptor to be aligned to 32bytes
* for meeting FSL DMA specification requirement.
*/
- fsl_chan->desc_pool = dma_pool_create("fsl_dma_engine_desc_pool",
- fsl_chan->dev, sizeof(struct fsl_desc_sw),
- 32, 0);
- if (!fsl_chan->desc_pool) {
- dev_err(fsl_chan->dev, "No memory for channel %d "
- "descriptor dma pool.\n", fsl_chan->id);
- return 0;
+ chan->desc_pool = dma_pool_create("fsl_dma_engine_desc_pool",
+ chan->dev,
+ sizeof(struct fsl_desc_sw),
+ __alignof__(struct fsl_desc_sw), 0);
+ if (!chan->desc_pool) {
+ dev_err(chan->dev, "unable to allocate channel %d "
+ "descriptor pool\n", chan->id);
+ return -ENOMEM;
}
+ /* there is at least one descriptor free to be allocated */
return 1;
}
/**
- * fsl_dma_free_chan_resources - Free all resources of the channel.
- * @fsl_chan : Freescale DMA channel
+ * fsldma_free_desc_list - Free all descriptors in a queue
+ * @chan: Freescae DMA channel
+ * @list: the list to free
+ *
+ * LOCKING: must hold chan->desc_lock
*/
-static void fsl_dma_free_chan_resources(struct dma_chan *chan)
+static void fsldma_free_desc_list(struct fsldma_chan *chan,
+ struct list_head *list)
{
- struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan);
struct fsl_desc_sw *desc, *_desc;
- unsigned long flags;
- dev_dbg(fsl_chan->dev, "Free all channel resources.\n");
- spin_lock_irqsave(&fsl_chan->desc_lock, flags);
- list_for_each_entry_safe(desc, _desc, &fsl_chan->ld_queue, node) {
-#ifdef FSL_DMA_LD_DEBUG
- dev_dbg(fsl_chan->dev,
- "LD %p will be released.\n", desc);
-#endif
+ list_for_each_entry_safe(desc, _desc, list, node) {
+ list_del(&desc->node);
+ dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
+ }
+}
+
+static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan,
+ struct list_head *list)
+{
+ struct fsl_desc_sw *desc, *_desc;
+
+ list_for_each_entry_safe_reverse(desc, _desc, list, node) {
list_del(&desc->node);
- /* free link descriptor */
- dma_pool_free(fsl_chan->desc_pool, desc, desc->async_tx.phys);
+ dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
}
- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
- dma_pool_destroy(fsl_chan->desc_pool);
+}
+
+/**
+ * fsl_dma_free_chan_resources - Free all resources of the channel.
+ * @chan : Freescale DMA channel
+ */
+static void fsl_dma_free_chan_resources(struct dma_chan *dchan)
+{
+ struct fsldma_chan *chan = to_fsl_chan(dchan);
+ unsigned long flags;
+
+ dev_dbg(chan->dev, "Free all channel resources.\n");
+ spin_lock_irqsave(&chan->desc_lock, flags);
+ fsldma_free_desc_list(chan, &chan->ld_pending);
+ fsldma_free_desc_list(chan, &chan->ld_running);
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
- fsl_chan->desc_pool = NULL;
+ dma_pool_destroy(chan->desc_pool);
+ chan->desc_pool = NULL;
}
static struct dma_async_tx_descriptor *
-fsl_dma_prep_interrupt(struct dma_chan *chan, unsigned long flags)
+fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags)
{
- struct fsl_dma_chan *fsl_chan;
+ struct fsldma_chan *chan;
struct fsl_desc_sw *new;
- if (!chan)
+ if (!dchan)
return NULL;
- fsl_chan = to_fsl_chan(chan);
+ chan = to_fsl_chan(dchan);
- new = fsl_dma_alloc_descriptor(fsl_chan);
+ new = fsl_dma_alloc_descriptor(chan);
if (!new) {
- dev_err(fsl_chan->dev, "No free memory for link descriptor\n");
+ dev_err(chan->dev, "No free memory for link descriptor\n");
return NULL;
}
@@ -473,51 +509,50 @@ fsl_dma_prep_interrupt(struct dma_chan *chan, unsigned long flags)
list_add_tail(&new->node, &new->tx_list);
/* Set End-of-link to the last link descriptor of new list*/
- set_ld_eol(fsl_chan, new);
+ set_ld_eol(chan, new);
return &new->async_tx;
}
static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
- struct dma_chan *chan, dma_addr_t dma_dest, dma_addr_t dma_src,
+ struct dma_chan *dchan, dma_addr_t dma_dst, dma_addr_t dma_src,
size_t len, unsigned long flags)
{
- struct fsl_dma_chan *fsl_chan;
+ struct fsldma_chan *chan;
struct fsl_desc_sw *first = NULL, *prev = NULL, *new;
- struct list_head *list;
size_t copy;
- if (!chan)
+ if (!dchan)
return NULL;
if (!len)
return NULL;
- fsl_chan = to_fsl_chan(chan);
+ chan = to_fsl_chan(dchan);
do {
/* Allocate the link descriptor from DMA pool */
- new = fsl_dma_alloc_descriptor(fsl_chan);
+ new = fsl_dma_alloc_descriptor(chan);
if (!new) {
- dev_err(fsl_chan->dev,
+ dev_err(chan->dev,
"No free memory for link descriptor\n");
goto fail;
}
#ifdef FSL_DMA_LD_DEBUG
- dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new);
+ dev_dbg(chan->dev, "new link desc alloc %p\n", new);
#endif
copy = min(len, (size_t)FSL_DMA_BCR_MAX_CNT);
- set_desc_cnt(fsl_chan, &new->hw, copy);
- set_desc_src(fsl_chan, &new->hw, dma_src);
- set_desc_dest(fsl_chan, &new->hw, dma_dest);
+ set_desc_cnt(chan, &new->hw, copy);
+ set_desc_src(chan, &new->hw, dma_src);
+ set_desc_dst(chan, &new->hw, dma_dst);
if (!first)
first = new;
else
- set_desc_next(fsl_chan, &prev->hw, new->async_tx.phys);
+ set_desc_next(chan, &prev->hw, new->async_tx.phys);
new->async_tx.cookie = 0;
async_tx_ack(&new->async_tx);
@@ -525,7 +560,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
prev = new;
len -= copy;
dma_src += copy;
- dma_dest += copy;
+ dma_dst += copy;
/* Insert the link descriptor to the LD ring */
list_add_tail(&new->node, &first->tx_list);
@@ -535,7 +570,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
new->async_tx.cookie = -EBUSY;
/* Set End-of-link to the last link descriptor of new list*/
- set_ld_eol(fsl_chan, new);
+ set_ld_eol(chan, new);
return &first->async_tx;
@@ -543,12 +578,7 @@ fail:
if (!first)
return NULL;
- list = &first->tx_list;
- list_for_each_entry_safe_reverse(new, prev, list, node) {
- list_del(&new->node);
- dma_pool_free(fsl_chan->desc_pool, new, new->async_tx.phys);
- }
-
+ fsldma_free_desc_list_reverse(chan, &first->tx_list);
return NULL;
}
@@ -565,13 +595,12 @@ fail:
* chan->private variable.
*/
static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
- struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len,
+ struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
enum dma_data_direction direction, unsigned long flags)
{
- struct fsl_dma_chan *fsl_chan;
+ struct fsldma_chan *chan;
struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL;
struct fsl_dma_slave *slave;
- struct list_head *tx_list;
size_t copy;
int i;
@@ -581,14 +610,14 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
struct fsl_dma_hw_addr *hw;
dma_addr_t dma_dst, dma_src;
- if (!chan)
+ if (!dchan)
return NULL;
- if (!chan->private)
+ if (!dchan->private)
return NULL;
- fsl_chan = to_fsl_chan(chan);
- slave = chan->private;
+ chan = to_fsl_chan(dchan);
+ slave = dchan->private;
if (list_empty(&slave->addresses))
return NULL;
@@ -637,14 +666,14 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
}
/* Allocate the link descriptor from DMA pool */
- new = fsl_dma_alloc_descriptor(fsl_chan);
+ new = fsl_dma_alloc_descriptor(chan);
if (!new) {
- dev_err(fsl_chan->dev, "No free memory for "
+ dev_err(chan->dev, "No free memory for "
"link descriptor\n");
goto fail;
}
#ifdef FSL_DMA_LD_DEBUG
- dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new);
+ dev_dbg(chan->dev, "new link desc alloc %p\n", new);
#endif
/*
@@ -671,9 +700,9 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
}
/* Fill in the descriptor */
- set_desc_cnt(fsl_chan, &new->hw, copy);
- set_desc_src(fsl_chan, &new->hw, dma_src);
- set_desc_dest(fsl_chan, &new->hw, dma_dst);
+ set_desc_cnt(chan, &new->hw, copy);
+ set_desc_src(chan, &new->hw, dma_src);
+ set_desc_dst(chan, &new->hw, dma_dst);
/*
* If this is not the first descriptor, chain the
@@ -682,7 +711,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
if (!first) {
first = new;
} else {
- set_desc_next(fsl_chan, &prev->hw,
+ set_desc_next(chan, &prev->hw,
new->async_tx.phys);
}
@@ -708,23 +737,23 @@ finished:
new->async_tx.cookie = -EBUSY;
/* Set End-of-link to the last link descriptor of new list */
- set_ld_eol(fsl_chan, new);
+ set_ld_eol(chan, new);
/* Enable extra controller features */
- if (fsl_chan->set_src_loop_size)
- fsl_chan->set_src_loop_size(fsl_chan, slave->src_loop_size);
+ if (chan->set_src_loop_size)
+ chan->set_src_loop_size(chan, slave->src_loop_size);
- if (fsl_chan->set_dest_loop_size)
- fsl_chan->set_dest_loop_size(fsl_chan, slave->dst_loop_size);
+ if (chan->set_dst_loop_size)
+ chan->set_dst_loop_size(chan, slave->dst_loop_size);
- if (fsl_chan->toggle_ext_start)
- fsl_chan->toggle_ext_start(fsl_chan, slave->external_start);
+ if (chan->toggle_ext_start)
+ chan->toggle_ext_start(chan, slave->external_start);
- if (fsl_chan->toggle_ext_pause)
- fsl_chan->toggle_ext_pause(fsl_chan, slave->external_pause);
+ if (chan->toggle_ext_pause)
+ chan->toggle_ext_pause(chan, slave->external_pause);
- if (fsl_chan->set_request_count)
- fsl_chan->set_request_count(fsl_chan, slave->request_count);
+ if (chan->set_request_count)
+ chan->set_request_count(chan, slave->request_count);
return &first->async_tx;
@@ -741,215 +770,216 @@ fail:
*
* We're re-using variables for the loop, oh well
*/
- tx_list = &first->tx_list;
- list_for_each_entry_safe_reverse(new, prev, tx_list, node) {
- list_del_init(&new->node);
- dma_pool_free(fsl_chan->desc_pool, new, new->async_tx.phys);
- }
-
+ fsldma_free_desc_list_reverse(chan, &first->tx_list);
return NULL;
}
-static void fsl_dma_device_terminate_all(struct dma_chan *chan)
+static void fsl_dma_device_terminate_all(struct dma_chan *dchan)
{
- struct fsl_dma_chan *fsl_chan;
- struct fsl_desc_sw *desc, *tmp;
+ struct fsldma_chan *chan;
unsigned long flags;
- if (!chan)
+ if (!dchan)
return;
- fsl_chan = to_fsl_chan(chan);
+ chan = to_fsl_chan(dchan);
/* Halt the DMA engine */
- dma_halt(fsl_chan);
+ dma_halt(chan);
- spin_lock_irqsave(&fsl_chan->desc_lock, flags);
+ spin_lock_irqsave(&chan->desc_lock, flags);
/* Remove and free all of the descriptors in the LD queue */
- list_for_each_entry_safe(desc, tmp, &fsl_chan->ld_queue, node) {
- list_del(&desc->node);
- dma_pool_free(fsl_chan->desc_pool, desc, desc->async_tx.phys);
- }
+ fsldma_free_desc_list(chan, &chan->ld_pending);
+ fsldma_free_desc_list(chan, &chan->ld_running);
- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
}
/**
* fsl_dma_update_completed_cookie - Update the completed cookie.
- * @fsl_chan : Freescale DMA channel
+ * @chan : Freescale DMA channel
+ *
+ * CONTEXT: hardirq
*/
-static void fsl_dma_update_completed_cookie(struct fsl_dma_chan *fsl_chan)
+static void fsl_dma_update_completed_cookie(struct fsldma_chan *chan)
{
- struct fsl_desc_sw *cur_desc, *desc;
- dma_addr_t ld_phy;
+ struct fsl_desc_sw *desc;
+ unsigned long flags;
+ dma_cookie_t cookie;
- ld_phy = get_cdar(fsl_chan) & FSL_DMA_NLDA_MASK;
+ spin_lock_irqsave(&chan->desc_lock, flags);
- if (ld_phy) {
- cur_desc = NULL;
- list_for_each_entry(desc, &fsl_chan->ld_queue, node)
- if (desc->async_tx.phys == ld_phy) {
- cur_desc = desc;
- break;
- }
+ if (list_empty(&chan->ld_running)) {
+ dev_dbg(chan->dev, "no running descriptors\n");
+ goto out_unlock;
+ }
- if (cur_desc && cur_desc->async_tx.cookie) {
- if (dma_is_idle(fsl_chan))
- fsl_chan->completed_cookie =
- cur_desc->async_tx.cookie;
- else
- fsl_chan->completed_cookie =
- cur_desc->async_tx.cookie - 1;
- }
+ /* Get the last descriptor, update the cookie to that */
+ desc = to_fsl_desc(chan->ld_running.prev);
+ if (dma_is_idle(chan))
+ cookie = desc->async_tx.cookie;
+ else {
+ cookie = desc->async_tx.cookie - 1;
+ if (unlikely(cookie < DMA_MIN_COOKIE))
+ cookie = DMA_MAX_COOKIE;
}
+
+ chan->completed_cookie = cookie;
+
+out_unlock:
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
+}
+
+/**
+ * fsldma_desc_status - Check the status of a descriptor
+ * @chan: Freescale DMA channel
+ * @desc: DMA SW descriptor
+ *
+ * This function will return the status of the given descriptor
+ */
+static enum dma_status fsldma_desc_status(struct fsldma_chan *chan,
+ struct fsl_desc_sw *desc)
+{
+ return dma_async_is_complete(desc->async_tx.cookie,
+ chan->completed_cookie,
+ chan->common.cookie);
}
/**
* fsl_chan_ld_cleanup - Clean up link descriptors
- * @fsl_chan : Freescale DMA channel
+ * @chan : Freescale DMA channel
*
* This function clean up the ld_queue of DMA channel.
- * If 'in_intr' is set, the function will move the link descriptor to
- * the recycle list. Otherwise, free it directly.
*/
-static void fsl_chan_ld_cleanup(struct fsl_dma_chan *fsl_chan)
+static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
{
struct fsl_desc_sw *desc, *_desc;
unsigned long flags;
- spin_lock_irqsave(&fsl_chan->desc_lock, flags);
+ spin_lock_irqsave(&chan->desc_lock, flags);
- dev_dbg(fsl_chan->dev, "chan completed_cookie = %d\n",
- fsl_chan->completed_cookie);
- list_for_each_entry_safe(desc, _desc, &fsl_chan->ld_queue, node) {
+ dev_dbg(chan->dev, "chan completed_cookie = %d\n", chan->completed_cookie);
+ list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) {
dma_async_tx_callback callback;
void *callback_param;
- if (dma_async_is_complete(desc->async_tx.cookie,
- fsl_chan->completed_cookie, fsl_chan->common.cookie)
- == DMA_IN_PROGRESS)
+ if (fsldma_desc_status(chan, desc) == DMA_IN_PROGRESS)
break;
- callback = desc->async_tx.callback;
- callback_param = desc->async_tx.callback_param;
-
- /* Remove from ld_queue list */
+ /* Remove from the list of running transactions */
list_del(&desc->node);
- dev_dbg(fsl_chan->dev, "link descriptor %p will be recycle.\n",
- desc);
- dma_pool_free(fsl_chan->desc_pool, desc, desc->async_tx.phys);
-
/* Run the link descriptor callback function */
+ callback = desc->async_tx.callback;
+ callback_param = desc->async_tx.callback_param;
if (callback) {
- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
- dev_dbg(fsl_chan->dev, "link descriptor %p callback\n",
- desc);
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
+ dev_dbg(chan->dev, "LD %p callback\n", desc);
callback(callback_param);
- spin_lock_irqsave(&fsl_chan->desc_lock, flags);
+ spin_lock_irqsave(&chan->desc_lock, flags);
}
+
+ /* Run any dependencies, then free the descriptor */
+ dma_run_dependencies(&desc->async_tx);
+ dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
}
- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
+
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
}
/**
- * fsl_chan_xfer_ld_queue - Transfer link descriptors in channel ld_queue.
- * @fsl_chan : Freescale DMA channel
+ * fsl_chan_xfer_ld_queue - transfer any pending transactions
+ * @chan : Freescale DMA channel
+ *
+ * This will make sure that any pending transactions will be run.
+ * If the DMA controller is idle, it will be started. Otherwise,
+ * the DMA controller's interrupt handler will start any pending
+ * transactions when it becomes idle.
*/
-static void fsl_chan_xfer_ld_queue(struct fsl_dma_chan *fsl_chan)
+static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
{
- struct list_head *ld_node;
- dma_addr_t next_dest_addr;
+ struct fsl_desc_sw *desc;
unsigned long flags;
- spin_lock_irqsave(&fsl_chan->desc_lock, flags);
+ spin_lock_irqsave(&chan->desc_lock, flags);
- if (!dma_is_idle(fsl_chan))
+ /*
+ * If the list of pending descriptors is empty, then we
+ * don't need to do any work at all
+ */
+ if (list_empty(&chan->ld_pending)) {
+ dev_dbg(chan->dev, "no pending LDs\n");
goto out_unlock;
+ }
- dma_halt(fsl_chan);
+ /*
+ * The DMA controller is not idle, which means the interrupt
+ * handler will start any queued transactions when it runs
+ * at the end of the current transaction
+ */
+ if (!dma_is_idle(chan)) {
+ dev_dbg(chan->dev, "DMA controller still busy\n");
+ goto out_unlock;
+ }
- /* If there are some link descriptors
- * not transfered in queue. We need to start it.
+ /*
+ * TODO:
+ * make sure the dma_halt() function really un-wedges the
+ * controller as much as possible
*/
+ dma_halt(chan);
- /* Find the first un-transfer desciptor */
- for (ld_node = fsl_chan->ld_queue.next;
- (ld_node != &fsl_chan->ld_queue)
- && (dma_async_is_complete(
- to_fsl_desc(ld_node)->async_tx.cookie,
- fsl_chan->completed_cookie,
- fsl_chan->common.cookie) == DMA_SUCCESS);
- ld_node = ld_node->next);
-
- if (ld_node != &fsl_chan->ld_queue) {
- /* Get the ld start address from ld_queue */
- next_dest_addr = to_fsl_desc(ld_node)->async_tx.phys;
- dev_dbg(fsl_chan->dev, "xfer LDs staring from 0x%llx\n",
- (unsigned long long)next_dest_addr);
- set_cdar(fsl_chan, next_dest_addr);
- dma_start(fsl_chan);
- } else {
- set_cdar(fsl_chan, 0);
- set_ndar(fsl_chan, 0);
- }
+ /*
+ * If there are some link descriptors which have not been
+ * transferred, we need to start the controller
+ */
+
+ /*
+ * Move all elements from the queue of pending transactions
+ * onto the list of running transactions
+ */
+ desc = list_first_entry(&chan->ld_pending, struct fsl_desc_sw, node);
+ list_splice_tail_init(&chan->ld_pending, &chan->ld_running);
+
+ /*
+ * Program the descriptor's address into the DMA controller,
+ * then start the DMA transaction
+ */
+ set_cdar(chan, desc->async_tx.phys);
+ dma_start(chan);
out_unlock:
- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
}
/**
* fsl_dma_memcpy_issue_pending - Issue the DMA start command
- * @fsl_chan : Freescale DMA channel
+ * @chan : Freescale DMA channel
*/
-static void fsl_dma_memcpy_issue_pending(struct dma_chan *chan)
+static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan)
{
- struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan);
-
-#ifdef FSL_DMA_LD_DEBUG
- struct fsl_desc_sw *ld;
- unsigned long flags;
-
- spin_lock_irqsave(&fsl_chan->desc_lock, flags);
- if (list_empty(&fsl_chan->ld_queue)) {
- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
- return;
- }
-
- dev_dbg(fsl_chan->dev, "--memcpy issue--\n");
- list_for_each_entry(ld, &fsl_chan->ld_queue, node) {
- int i;
- dev_dbg(fsl_chan->dev, "Ch %d, LD %08x\n",
- fsl_chan->id, ld->async_tx.phys);
- for (i = 0; i < 8; i++)
- dev_dbg(fsl_chan->dev, "LD offset %d: %08x\n",
- i, *(((u32 *)&ld->hw) + i));
- }
- dev_dbg(fsl_chan->dev, "----------------\n");
- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
-#endif
-
- fsl_chan_xfer_ld_queue(fsl_chan);
+ struct fsldma_chan *chan = to_fsl_chan(dchan);
+ fsl_chan_xfer_ld_queue(chan);
}
/**
* fsl_dma_is_complete - Determine the DMA status
- * @fsl_chan : Freescale DMA channel
+ * @chan : Freescale DMA channel
*/
-static enum dma_status fsl_dma_is_complete(struct dma_chan *chan,
+static enum dma_status fsl_dma_is_complete(struct dma_chan *dchan,
dma_cookie_t cookie,
dma_cookie_t *done,
dma_cookie_t *used)
{
- struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan);
+ struct fsldma_chan *chan = to_fsl_chan(dchan);
dma_cookie_t last_used;
dma_cookie_t last_complete;
- fsl_chan_ld_cleanup(fsl_chan);
+ fsl_chan_ld_cleanup(chan);
- last_used = chan->cookie;
- last_complete = fsl_chan->completed_cookie;
+ last_used = dchan->cookie;
+ last_complete = chan->completed_cookie;
if (done)
*done = last_complete;
@@ -960,32 +990,37 @@ static enum dma_status fsl_dma_is_complete(struct dma_chan *chan,
return dma_async_is_complete(cookie, last_complete, last_used);
}
-static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data)
+/*----------------------------------------------------------------------------*/
+/* Interrupt Handling */
+/*----------------------------------------------------------------------------*/
+
+static irqreturn_t fsldma_chan_irq(int irq, void *data)
{
- struct fsl_dma_chan *fsl_chan = (struct fsl_dma_chan *)data;
- u32 stat;
+ struct fsldma_chan *chan = data;
int update_cookie = 0;
int xfer_ld_q = 0;
+ u32 stat;
- stat = get_sr(fsl_chan);
- dev_dbg(fsl_chan->dev, "event: channel %d, stat = 0x%x\n",
- fsl_chan->id, stat);
- set_sr(fsl_chan, stat); /* Clear the event register */
+ /* save and clear the status register */
+ stat = get_sr(chan);
+ set_sr(chan, stat);
+ dev_dbg(chan->dev, "irq: channel %d, stat = 0x%x\n", chan->id, stat);
stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH);
if (!stat)
return IRQ_NONE;
if (stat & FSL_DMA_SR_TE)
- dev_err(fsl_chan->dev, "Transfer Error!\n");
+ dev_err(chan->dev, "Transfer Error!\n");
- /* Programming Error
+ /*
+ * Programming Error
* The DMA_INTERRUPT async_tx is a NULL transfer, which will
* triger a PE interrupt.
*/
if (stat & FSL_DMA_SR_PE) {
- dev_dbg(fsl_chan->dev, "event: Programming Error INT\n");
- if (get_bcr(fsl_chan) == 0) {
+ dev_dbg(chan->dev, "irq: Programming Error INT\n");
+ if (get_bcr(chan) == 0) {
/* BCR register is 0, this is a DMA_INTERRUPT async_tx.
* Now, update the completed cookie, and continue the
* next uncompleted transfer.
@@ -996,208 +1031,296 @@ static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data)
stat &= ~FSL_DMA_SR_PE;
}
- /* If the link descriptor segment transfer finishes,
+ /*
+ * If the link descriptor segment transfer finishes,
* we will recycle the used descriptor.
*/
if (stat & FSL_DMA_SR_EOSI) {
- dev_dbg(fsl_chan->dev, "event: End-of-segments INT\n");
- dev_dbg(fsl_chan->dev, "event: clndar 0x%llx, nlndar 0x%llx\n",
- (unsigned long long)get_cdar(fsl_chan),
- (unsigned long long)get_ndar(fsl_chan));
+ dev_dbg(chan->dev, "irq: End-of-segments INT\n");
+ dev_dbg(chan->dev, "irq: clndar 0x%llx, nlndar 0x%llx\n",
+ (unsigned long long)get_cdar(chan),
+ (unsigned long long)get_ndar(chan));
stat &= ~FSL_DMA_SR_EOSI;
update_cookie = 1;
}
- /* For MPC8349, EOCDI event need to update cookie
+ /*
+ * For MPC8349, EOCDI event need to update cookie
* and start the next transfer if it exist.
*/
if (stat & FSL_DMA_SR_EOCDI) {
- dev_dbg(fsl_chan->dev, "event: End-of-Chain link INT\n");
+ dev_dbg(chan->dev, "irq: End-of-Chain link INT\n");
stat &= ~FSL_DMA_SR_EOCDI;
update_cookie = 1;
xfer_ld_q = 1;
}
- /* If it current transfer is the end-of-transfer,
+ /*
+ * If it current transfer is the end-of-transfer,
* we should clear the Channel Start bit for
* prepare next transfer.
*/
if (stat & FSL_DMA_SR_EOLNI) {
- dev_dbg(fsl_chan->dev, "event: End-of-link INT\n");
+ dev_dbg(chan->dev, "irq: End-of-link INT\n");
stat &= ~FSL_DMA_SR_EOLNI;
xfer_ld_q = 1;
}
if (update_cookie)
- fsl_dma_update_completed_cookie(fsl_chan);
+ fsl_dma_update_completed_cookie(chan);
if (xfer_ld_q)
- fsl_chan_xfer_ld_queue(fsl_chan);
+ fsl_chan_xfer_ld_queue(chan);
if (stat)
- dev_dbg(fsl_chan->dev, "event: unhandled sr 0x%02x\n",
- stat);
+ dev_dbg(chan->dev, "irq: unhandled sr 0x%02x\n", stat);
- dev_dbg(fsl_chan->dev, "event: Exit\n");
- tasklet_schedule(&fsl_chan->tasklet);
+ dev_dbg(chan->dev, "irq: Exit\n");
+ tasklet_schedule(&chan->tasklet);
return IRQ_HANDLED;
}
-static irqreturn_t fsl_dma_do_interrupt(int irq, void *data)
+static void dma_do_tasklet(unsigned long data)
{
- struct fsl_dma_device *fdev = (struct fsl_dma_device *)data;
- u32 gsr;
- int ch_nr;
+ struct fsldma_chan *chan = (struct fsldma_chan *)data;
+ fsl_chan_ld_cleanup(chan);
+}
+
+static irqreturn_t fsldma_ctrl_irq(int irq, void *data)
+{
+ struct fsldma_device *fdev = data;
+ struct fsldma_chan *chan;
+ unsigned int handled = 0;
+ u32 gsr, mask;
+ int i;
- gsr = (fdev->feature & FSL_DMA_BIG_ENDIAN) ? in_be32(fdev->reg_base)
- : in_le32(fdev->reg_base);
- ch_nr = (32 - ffs(gsr)) / 8;
+ gsr = (fdev->feature & FSL_DMA_BIG_ENDIAN) ? in_be32(fdev->regs)
+ : in_le32(fdev->regs);
+ mask = 0xff000000;
+ dev_dbg(fdev->dev, "IRQ: gsr 0x%.8x\n", gsr);
+
+ for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
+ chan = fdev->chan[i];
+ if (!chan)
+ continue;
+
+ if (gsr & mask) {
+ dev_dbg(fdev->dev, "IRQ: chan %d\n", chan->id);
+ fsldma_chan_irq(irq, chan);
+ handled++;
+ }
- return fdev->chan[ch_nr] ? fsl_dma_chan_do_interrupt(irq,
- fdev->chan[ch_nr]) : IRQ_NONE;
+ gsr &= ~mask;
+ mask >>= 8;
+ }
+
+ return IRQ_RETVAL(handled);
}
-static void dma_do_tasklet(unsigned long data)
+static void fsldma_free_irqs(struct fsldma_device *fdev)
{
- struct fsl_dma_chan *fsl_chan = (struct fsl_dma_chan *)data;
- fsl_chan_ld_cleanup(fsl_chan);
+ struct fsldma_chan *chan;
+ int i;
+
+ if (fdev->irq != NO_IRQ) {
+ dev_dbg(fdev->dev, "free per-controller IRQ\n");
+ free_irq(fdev->irq, fdev);
+ return;
+ }
+
+ for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
+ chan = fdev->chan[i];
+ if (chan && chan->irq != NO_IRQ) {
+ dev_dbg(fdev->dev, "free channel %d IRQ\n", chan->id);
+ free_irq(chan->irq, chan);
+ }
+ }
}
-static int __devinit fsl_dma_chan_probe(struct fsl_dma_device *fdev,
+static int fsldma_request_irqs(struct fsldma_device *fdev)
+{
+ struct fsldma_chan *chan;
+ int ret;
+ int i;
+
+ /* if we have a per-controller IRQ, use that */
+ if (fdev->irq != NO_IRQ) {
+ dev_dbg(fdev->dev, "request per-controller IRQ\n");
+ ret = request_irq(fdev->irq, fsldma_ctrl_irq, IRQF_SHARED,
+ "fsldma-controller", fdev);
+ return ret;
+ }
+
+ /* no per-controller IRQ, use the per-channel IRQs */
+ for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
+ chan = fdev->chan[i];
+ if (!chan)
+ continue;
+
+ if (chan->irq == NO_IRQ) {
+ dev_err(fdev->dev, "no interrupts property defined for "
+ "DMA channel %d. Please fix your "
+ "device tree\n", chan->id);
+ ret = -ENODEV;
+ goto out_unwind;
+ }
+
+ dev_dbg(fdev->dev, "request channel %d IRQ\n", chan->id);
+ ret = request_irq(chan->irq, fsldma_chan_irq, IRQF_SHARED,
+ "fsldma-chan", chan);
+ if (ret) {
+ dev_err(fdev->dev, "unable to request IRQ for DMA "
+ "channel %d\n", chan->id);
+ goto out_unwind;
+ }
+ }
+
+ return 0;
+
+out_unwind:
+ for (/* none */; i >= 0; i--) {
+ chan = fdev->chan[i];
+ if (!chan)
+ continue;
+
+ if (chan->irq == NO_IRQ)
+ continue;
+
+ free_irq(chan->irq, chan);
+ }
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/* OpenFirmware Subsystem */
+/*----------------------------------------------------------------------------*/
+
+static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev,
struct device_node *node, u32 feature, const char *compatible)
{
- struct fsl_dma_chan *new_fsl_chan;
+ struct fsldma_chan *chan;
+ struct resource res;
int err;
/* alloc channel */
- new_fsl_chan = kzalloc(sizeof(struct fsl_dma_chan), GFP_KERNEL);
- if (!new_fsl_chan) {
- dev_err(fdev->dev, "No free memory for allocating "
- "dma channels!\n");
- return -ENOMEM;
+ chan = kzalloc(sizeof(*chan), GFP_KERNEL);
+ if (!chan) {
+ dev_err(fdev->dev, "no free memory for DMA channels!\n");
+ err = -ENOMEM;
+ goto out_return;
}
- /* get dma channel register base */
- err = of_address_to_resource(node, 0, &new_fsl_chan->reg);
- if (err) {
- dev_err(fdev->dev, "Can't get %s property 'reg'\n",
- node->full_name);
- goto err_no_reg;
+ /* ioremap registers for use */
+ chan->regs = of_iomap(node, 0);
+ if (!chan->regs) {
+ dev_err(fdev->dev, "unable to ioremap registers\n");
+ err = -ENOMEM;
+ goto out_free_chan;
}
- new_fsl_chan->feature = feature;
+ err = of_address_to_resource(node, 0, &res);
+ if (err) {
+ dev_err(fdev->dev, "unable to find 'reg' property\n");
+ goto out_iounmap_regs;
+ }
+ chan->feature = feature;
if (!fdev->feature)
- fdev->feature = new_fsl_chan->feature;
+ fdev->feature = chan->feature;
- /* If the DMA device's feature is different than its channels',
- * report the bug.
+ /*
+ * If the DMA device's feature is different than the feature
+ * of its channels, report the bug
*/
- WARN_ON(fdev->feature != new_fsl_chan->feature);
+ WARN_ON(fdev->feature != chan->feature);
- new_fsl_chan->dev = fdev->dev;
- new_fsl_chan->reg_base = ioremap(new_fsl_chan->reg.start,
- new_fsl_chan->reg.end - new_fsl_chan->reg.start + 1);
-
- new_fsl_chan->id = ((new_fsl_chan->reg.start - 0x100) & 0xfff) >> 7;
- if (new_fsl_chan->id >= FSL_DMA_MAX_CHANS_PER_DEVICE) {
- dev_err(fdev->dev, "There is no %d channel!\n",
- new_fsl_chan->id);
+ chan->dev = fdev->dev;
+ chan->id = ((res.start - 0x100) & 0xfff) >> 7;
+ if (chan->id >= FSL_DMA_MAX_CHANS_PER_DEVICE) {
+ dev_err(fdev->dev, "too many channels for device\n");
err = -EINVAL;
- goto err_no_chan;
+ goto out_iounmap_regs;
}
- fdev->chan[new_fsl_chan->id] = new_fsl_chan;
- tasklet_init(&new_fsl_chan->tasklet, dma_do_tasklet,
- (unsigned long)new_fsl_chan);
- /* Init the channel */
- dma_init(new_fsl_chan);
+ fdev->chan[chan->id] = chan;
+ tasklet_init(&chan->tasklet, dma_do_tasklet, (unsigned long)chan);
+
+ /* Initialize the channel */
+ dma_init(chan);
/* Clear cdar registers */
- set_cdar(new_fsl_chan, 0);
+ set_cdar(chan, 0);
- switch (new_fsl_chan->feature & FSL_DMA_IP_MASK) {
+ switch (chan->feature & FSL_DMA_IP_MASK) {
case FSL_DMA_IP_85XX:
- new_fsl_chan->toggle_ext_pause = fsl_chan_toggle_ext_pause;
+ chan->toggle_ext_pause = fsl_chan_toggle_ext_pause;
case FSL_DMA_IP_83XX:
- new_fsl_chan->toggle_ext_start = fsl_chan_toggle_ext_start;
- new_fsl_chan->set_src_loop_size = fsl_chan_set_src_loop_size;
- new_fsl_chan->set_dest_loop_size = fsl_chan_set_dest_loop_size;
- new_fsl_chan->set_request_count = fsl_chan_set_request_count;
+ chan->toggle_ext_start = fsl_chan_toggle_ext_start;
+ chan->set_src_loop_size = fsl_chan_set_src_loop_size;
+ chan->set_dst_loop_size = fsl_chan_set_dst_loop_size;
+ chan->set_request_count = fsl_chan_set_request_count;
}
- spin_lock_init(&new_fsl_chan->desc_lock);
- INIT_LIST_HEAD(&new_fsl_chan->ld_queue);
+ spin_lock_init(&chan->desc_lock);
+ INIT_LIST_HEAD(&chan->ld_pending);
+ INIT_LIST_HEAD(&chan->ld_running);
+
+ chan->common.device = &fdev->common;
- new_fsl_chan->common.device = &fdev->common;
+ /* find the IRQ line, if it exists in the device tree */
+ chan->irq = irq_of_parse_and_map(node, 0);
/* Add the channel to DMA device channel list */
- list_add_tail(&new_fsl_chan->common.device_node,
- &fdev->common.channels);
+ list_add_tail(&chan->common.device_node, &fdev->common.channels);
fdev->common.chancnt++;
- new_fsl_chan->irq = irq_of_parse_and_map(node, 0);
- if (new_fsl_chan->irq != NO_IRQ) {
- err = request_irq(new_fsl_chan->irq,
- &fsl_dma_chan_do_interrupt, IRQF_SHARED,
- "fsldma-channel", new_fsl_chan);
- if (err) {
- dev_err(fdev->dev, "DMA channel %s request_irq error "
- "with return %d\n", node->full_name, err);
- goto err_no_irq;
- }
- }
-
- dev_info(fdev->dev, "#%d (%s), irq %d\n", new_fsl_chan->id,
- compatible,
- new_fsl_chan->irq != NO_IRQ ? new_fsl_chan->irq : fdev->irq);
+ dev_info(fdev->dev, "#%d (%s), irq %d\n", chan->id, compatible,
+ chan->irq != NO_IRQ ? chan->irq : fdev->irq);
return 0;
-err_no_irq:
- list_del(&new_fsl_chan->common.device_node);
-err_no_chan:
- iounmap(new_fsl_chan->reg_base);
-err_no_reg:
- kfree(new_fsl_chan);
+out_iounmap_regs:
+ iounmap(chan->regs);
+out_free_chan:
+ kfree(chan);
+out_return:
return err;
}
-static void fsl_dma_chan_remove(struct fsl_dma_chan *fchan)
+static void fsl_dma_chan_remove(struct fsldma_chan *chan)
{
- if (fchan->irq != NO_IRQ)
- free_irq(fchan->irq, fchan);
- list_del(&fchan->common.device_node);
- iounmap(fchan->reg_base);
- kfree(fchan);
+ irq_dispose_mapping(chan->irq);
+ list_del(&chan->common.device_node);
+ iounmap(chan->regs);
+ kfree(chan);
}
-static int __devinit of_fsl_dma_probe(struct of_device *dev,
+static int __devinit fsldma_of_probe(struct of_device *op,
const struct of_device_id *match)
{
- int err;
- struct fsl_dma_device *fdev;
+ struct fsldma_device *fdev;
struct device_node *child;
+ int err;
- fdev = kzalloc(sizeof(struct fsl_dma_device), GFP_KERNEL);
+ fdev = kzalloc(sizeof(*fdev), GFP_KERNEL);
if (!fdev) {
- dev_err(&dev->dev, "No enough memory for 'priv'\n");
- return -ENOMEM;
+ dev_err(&op->dev, "No enough memory for 'priv'\n");
+ err = -ENOMEM;
+ goto out_return;
}
- fdev->dev = &dev->dev;
+
+ fdev->dev = &op->dev;
INIT_LIST_HEAD(&fdev->common.channels);
- /* get DMA controller register base */
- err = of_address_to_resource(dev->node, 0, &fdev->reg);
- if (err) {
- dev_err(&dev->dev, "Can't get %s property 'reg'\n",
- dev->node->full_name);
- goto err_no_reg;
+ /* ioremap the registers for use */
+ fdev->regs = of_iomap(op->node, 0);
+ if (!fdev->regs) {
+ dev_err(&op->dev, "unable to ioremap registers\n");
+ err = -ENOMEM;
+ goto out_free_fdev;
}
- dev_info(&dev->dev, "Probe the Freescale DMA driver for %s "
- "controller at 0x%llx...\n",
- match->compatible, (unsigned long long)fdev->reg.start);
- fdev->reg_base = ioremap(fdev->reg.start, fdev->reg.end
- - fdev->reg.start + 1);
+ /* map the channel IRQ if it exists, but don't hookup the handler yet */
+ fdev->irq = irq_of_parse_and_map(op->node, 0);
dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
@@ -1210,103 +1333,111 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev,
fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg;
fdev->common.device_terminate_all = fsl_dma_device_terminate_all;
- fdev->common.dev = &dev->dev;
+ fdev->common.dev = &op->dev;
- fdev->irq = irq_of_parse_and_map(dev->node, 0);
- if (fdev->irq != NO_IRQ) {
- err = request_irq(fdev->irq, &fsl_dma_do_interrupt, IRQF_SHARED,
- "fsldma-device", fdev);
- if (err) {
- dev_err(&dev->dev, "DMA device request_irq error "
- "with return %d\n", err);
- goto err;
- }
- }
-
- dev_set_drvdata(&(dev->dev), fdev);
+ dev_set_drvdata(&op->dev, fdev);
- /* We cannot use of_platform_bus_probe() because there is no
- * of_platform_bus_remove. Instead, we manually instantiate every DMA
+ /*
+ * We cannot use of_platform_bus_probe() because there is no
+ * of_platform_bus_remove(). Instead, we manually instantiate every DMA
* channel object.
*/
- for_each_child_of_node(dev->node, child) {
- if (of_device_is_compatible(child, "fsl,eloplus-dma-channel"))
+ for_each_child_of_node(op->node, child) {
+ if (of_device_is_compatible(child, "fsl,eloplus-dma-channel")) {
fsl_dma_chan_probe(fdev, child,
FSL_DMA_IP_85XX | FSL_DMA_BIG_ENDIAN,
"fsl,eloplus-dma-channel");
- if (of_device_is_compatible(child, "fsl,elo-dma-channel"))
+ }
+
+ if (of_device_is_compatible(child, "fsl,elo-dma-channel")) {
fsl_dma_chan_probe(fdev, child,
FSL_DMA_IP_83XX | FSL_DMA_LITTLE_ENDIAN,
"fsl,elo-dma-channel");
+ }
+ }
+
+ /*
+ * Hookup the IRQ handler(s)
+ *
+ * If we have a per-controller interrupt, we prefer that to the
+ * per-channel interrupts to reduce the number of shared interrupt
+ * handlers on the same IRQ line
+ */
+ err = fsldma_request_irqs(fdev);
+ if (err) {
+ dev_err(fdev->dev, "unable to request IRQs\n");
+ goto out_free_fdev;
}
dma_async_device_register(&fdev->common);
return 0;
-err:
- iounmap(fdev->reg_base);
-err_no_reg:
+out_free_fdev:
+ irq_dispose_mapping(fdev->irq);
kfree(fdev);
+out_return:
return err;
}
-static int of_fsl_dma_remove(struct of_device *of_dev)
+static int fsldma_of_remove(struct of_device *op)
{
- struct fsl_dma_device *fdev;
+ struct fsldma_device *fdev;
unsigned int i;
- fdev = dev_get_drvdata(&of_dev->dev);
-
+ fdev = dev_get_drvdata(&op->dev);
dma_async_device_unregister(&fdev->common);
- for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++)
+ fsldma_free_irqs(fdev);
+
+ for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
if (fdev->chan[i])
fsl_dma_chan_remove(fdev->chan[i]);
+ }
- if (fdev->irq != NO_IRQ)
- free_irq(fdev->irq, fdev);
-
- iounmap(fdev->reg_base);
-
+ iounmap(fdev->regs);
+ dev_set_drvdata(&op->dev, NULL);
kfree(fdev);
- dev_set_drvdata(&of_dev->dev, NULL);
return 0;
}
-static struct of_device_id of_fsl_dma_ids[] = {
+static const struct of_device_id fsldma_of_ids[] = {
{ .compatible = "fsl,eloplus-dma", },
{ .compatible = "fsl,elo-dma", },
{}
};
-static struct of_platform_driver of_fsl_dma_driver = {
- .name = "fsl-elo-dma",
- .match_table = of_fsl_dma_ids,
- .probe = of_fsl_dma_probe,
- .remove = of_fsl_dma_remove,
+static struct of_platform_driver fsldma_of_driver = {
+ .name = "fsl-elo-dma",
+ .match_table = fsldma_of_ids,
+ .probe = fsldma_of_probe,
+ .remove = fsldma_of_remove,
};
-static __init int of_fsl_dma_init(void)
+/*----------------------------------------------------------------------------*/
+/* Module Init / Exit */
+/*----------------------------------------------------------------------------*/
+
+static __init int fsldma_init(void)
{
int ret;
pr_info("Freescale Elo / Elo Plus DMA driver\n");
- ret = of_register_platform_driver(&of_fsl_dma_driver);
+ ret = of_register_platform_driver(&fsldma_of_driver);
if (ret)
pr_err("fsldma: failed to register platform driver\n");
return ret;
}
-static void __exit of_fsl_dma_exit(void)
+static void __exit fsldma_exit(void)
{
- of_unregister_platform_driver(&of_fsl_dma_driver);
+ of_unregister_platform_driver(&fsldma_of_driver);
}
-subsys_initcall(of_fsl_dma_init);
-module_exit(of_fsl_dma_exit);
+subsys_initcall(fsldma_init);
+module_exit(fsldma_exit);
MODULE_DESCRIPTION("Freescale Elo / Elo Plus DMA driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index 0df14cbb8ca3..cb4d6ff51597 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -92,11 +92,9 @@ struct fsl_desc_sw {
struct list_head node;
struct list_head tx_list;
struct dma_async_tx_descriptor async_tx;
- struct list_head *ld;
- void *priv;
} __attribute__((aligned(32)));
-struct fsl_dma_chan_regs {
+struct fsldma_chan_regs {
u32 mr; /* 0x00 - Mode Register */
u32 sr; /* 0x04 - Status Register */
u64 cdar; /* 0x08 - Current descriptor address register */
@@ -106,20 +104,19 @@ struct fsl_dma_chan_regs {
u64 ndar; /* 0x24 - Next Descriptor Address Register */
};
-struct fsl_dma_chan;
+struct fsldma_chan;
#define FSL_DMA_MAX_CHANS_PER_DEVICE 4
-struct fsl_dma_device {
- void __iomem *reg_base; /* DGSR register base */
- struct resource reg; /* Resource for register */
+struct fsldma_device {
+ void __iomem *regs; /* DGSR register base */
struct device *dev;
struct dma_device common;
- struct fsl_dma_chan *chan[FSL_DMA_MAX_CHANS_PER_DEVICE];
+ struct fsldma_chan *chan[FSL_DMA_MAX_CHANS_PER_DEVICE];
u32 feature; /* The same as DMA channels */
int irq; /* Channel IRQ */
};
-/* Define macros for fsl_dma_chan->feature property */
+/* Define macros for fsldma_chan->feature property */
#define FSL_DMA_LITTLE_ENDIAN 0x00000000
#define FSL_DMA_BIG_ENDIAN 0x00000001
@@ -130,28 +127,28 @@ struct fsl_dma_device {
#define FSL_DMA_CHAN_PAUSE_EXT 0x00001000
#define FSL_DMA_CHAN_START_EXT 0x00002000
-struct fsl_dma_chan {
- struct fsl_dma_chan_regs __iomem *reg_base;
+struct fsldma_chan {
+ struct fsldma_chan_regs __iomem *regs;
dma_cookie_t completed_cookie; /* The maximum cookie completed */
spinlock_t desc_lock; /* Descriptor operation lock */
- struct list_head ld_queue; /* Link descriptors queue */
+ struct list_head ld_pending; /* Link descriptors queue */
+ struct list_head ld_running; /* Link descriptors queue */
struct dma_chan common; /* DMA common channel */
struct dma_pool *desc_pool; /* Descriptors pool */
struct device *dev; /* Channel device */
- struct resource reg; /* Resource for register */
int irq; /* Channel IRQ */
int id; /* Raw id of this channel */
struct tasklet_struct tasklet;
u32 feature;
- void (*toggle_ext_pause)(struct fsl_dma_chan *fsl_chan, int enable);
- void (*toggle_ext_start)(struct fsl_dma_chan *fsl_chan, int enable);
- void (*set_src_loop_size)(struct fsl_dma_chan *fsl_chan, int size);
- void (*set_dest_loop_size)(struct fsl_dma_chan *fsl_chan, int size);
- void (*set_request_count)(struct fsl_dma_chan *fsl_chan, int size);
+ void (*toggle_ext_pause)(struct fsldma_chan *fsl_chan, int enable);
+ void (*toggle_ext_start)(struct fsldma_chan *fsl_chan, int enable);
+ void (*set_src_loop_size)(struct fsldma_chan *fsl_chan, int size);
+ void (*set_dst_loop_size)(struct fsldma_chan *fsl_chan, int size);
+ void (*set_request_count)(struct fsldma_chan *fsl_chan, int size);
};
-#define to_fsl_chan(chan) container_of(chan, struct fsl_dma_chan, common)
+#define to_fsl_chan(chan) container_of(chan, struct fsldma_chan, common)
#define to_fsl_desc(lh) container_of(lh, struct fsl_desc_sw, node)
#define tx_to_fsl_desc(tx) container_of(tx, struct fsl_desc_sw, async_tx)
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
index dcc4ab78b32b..0099340b9616 100644
--- a/drivers/dma/ioat/dma.c
+++ b/drivers/dma/ioat/dma.c
@@ -71,7 +71,7 @@ static irqreturn_t ioat_dma_do_interrupt(int irq, void *data)
}
attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET);
- for_each_bit(bit, &attnstatus, BITS_PER_LONG) {
+ for_each_set_bit(bit, &attnstatus, BITS_PER_LONG) {
chan = ioat_chan_by_index(instance, bit);
tasklet_schedule(&chan->cleanup_task);
}
@@ -94,16 +94,12 @@ static irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data)
return IRQ_HANDLED;
}
-static void ioat1_cleanup_tasklet(unsigned long data);
-
/* common channel initialization */
-void ioat_init_channel(struct ioatdma_device *device,
- struct ioat_chan_common *chan, int idx,
- void (*timer_fn)(unsigned long),
- void (*tasklet)(unsigned long),
- unsigned long ioat)
+void ioat_init_channel(struct ioatdma_device *device, struct ioat_chan_common *chan, int idx)
{
struct dma_device *dma = &device->common;
+ struct dma_chan *c = &chan->common;
+ unsigned long data = (unsigned long) c;
chan->device = device;
chan->reg_base = device->reg_base + (0x80 * (idx + 1));
@@ -112,14 +108,12 @@ void ioat_init_channel(struct ioatdma_device *device,
list_add_tail(&chan->common.device_node, &dma->channels);
device->idx[idx] = chan;
init_timer(&chan->timer);
- chan->timer.function = timer_fn;
- chan->timer.data = ioat;
- tasklet_init(&chan->cleanup_task, tasklet, ioat);
+ chan->timer.function = device->timer_fn;
+ chan->timer.data = data;
+ tasklet_init(&chan->cleanup_task, device->cleanup_fn, data);
tasklet_disable(&chan->cleanup_task);
}
-static void ioat1_timer_event(unsigned long data);
-
/**
* ioat1_dma_enumerate_channels - find and initialize the device's channels
* @device: the device to be enumerated
@@ -155,10 +149,7 @@ static int ioat1_enumerate_channels(struct ioatdma_device *device)
if (!ioat)
break;
- ioat_init_channel(device, &ioat->base, i,
- ioat1_timer_event,
- ioat1_cleanup_tasklet,
- (unsigned long) ioat);
+ ioat_init_channel(device, &ioat->base, i);
ioat->xfercap = xfercap;
spin_lock_init(&ioat->desc_lock);
INIT_LIST_HEAD(&ioat->free_desc);
@@ -532,12 +523,12 @@ ioat1_dma_prep_memcpy(struct dma_chan *c, dma_addr_t dma_dest,
return &desc->txd;
}
-static void ioat1_cleanup_tasklet(unsigned long data)
+static void ioat1_cleanup_event(unsigned long data)
{
- struct ioat_dma_chan *chan = (void *)data;
+ struct ioat_dma_chan *ioat = to_ioat_chan((void *) data);
- ioat1_cleanup(chan);
- writew(IOAT_CHANCTRL_RUN, chan->base.reg_base + IOAT_CHANCTRL_OFFSET);
+ ioat1_cleanup(ioat);
+ writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
}
void ioat_dma_unmap(struct ioat_chan_common *chan, enum dma_ctrl_flags flags,
@@ -687,7 +678,7 @@ static void ioat1_cleanup(struct ioat_dma_chan *ioat)
static void ioat1_timer_event(unsigned long data)
{
- struct ioat_dma_chan *ioat = (void *) data;
+ struct ioat_dma_chan *ioat = to_ioat_chan((void *) data);
struct ioat_chan_common *chan = &ioat->base;
dev_dbg(to_dev(chan), "%s: state: %lx\n", __func__, chan->state);
@@ -734,16 +725,17 @@ static void ioat1_timer_event(unsigned long data)
spin_unlock_bh(&chan->cleanup_lock);
}
-static enum dma_status
-ioat1_dma_is_complete(struct dma_chan *c, dma_cookie_t cookie,
+enum dma_status
+ioat_is_dma_complete(struct dma_chan *c, dma_cookie_t cookie,
dma_cookie_t *done, dma_cookie_t *used)
{
- struct ioat_dma_chan *ioat = to_ioat_chan(c);
+ struct ioat_chan_common *chan = to_chan_common(c);
+ struct ioatdma_device *device = chan->device;
if (ioat_is_complete(c, cookie, done, used) == DMA_SUCCESS)
return DMA_SUCCESS;
- ioat1_cleanup(ioat);
+ device->cleanup_fn((unsigned long) c);
return ioat_is_complete(c, cookie, done, used);
}
@@ -1146,7 +1138,7 @@ ioat_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
return entry->show(&chan->common, page);
}
-struct sysfs_ops ioat_sysfs_ops = {
+const struct sysfs_ops ioat_sysfs_ops = {
.show = ioat_attr_show,
};
@@ -1199,12 +1191,14 @@ int __devinit ioat1_dma_probe(struct ioatdma_device *device, int dca)
device->intr_quirk = ioat1_intr_quirk;
device->enumerate_channels = ioat1_enumerate_channels;
device->self_test = ioat_dma_self_test;
+ device->timer_fn = ioat1_timer_event;
+ device->cleanup_fn = ioat1_cleanup_event;
dma = &device->common;
dma->device_prep_dma_memcpy = ioat1_dma_prep_memcpy;
dma->device_issue_pending = ioat1_dma_memcpy_issue_pending;
dma->device_alloc_chan_resources = ioat1_dma_alloc_chan_resources;
dma->device_free_chan_resources = ioat1_dma_free_chan_resources;
- dma->device_is_tx_complete = ioat1_dma_is_complete;
+ dma->device_is_tx_complete = ioat_is_dma_complete;
err = ioat_probe(device);
if (err)
diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h
index bbc3e78ef333..86b97ac8774e 100644
--- a/drivers/dma/ioat/dma.h
+++ b/drivers/dma/ioat/dma.h
@@ -61,7 +61,7 @@
* @intr_quirk: interrupt setup quirk (for ioat_v1 devices)
* @enumerate_channels: hw version specific channel enumeration
* @reset_hw: hw version specific channel (re)initialization
- * @cleanup_tasklet: select between the v2 and v3 cleanup routines
+ * @cleanup_fn: select between the v2 and v3 cleanup routines
* @timer_fn: select between the v2 and v3 timer watchdog routines
* @self_test: hardware version specific self test for each supported op type
*
@@ -80,7 +80,7 @@ struct ioatdma_device {
void (*intr_quirk)(struct ioatdma_device *device);
int (*enumerate_channels)(struct ioatdma_device *device);
int (*reset_hw)(struct ioat_chan_common *chan);
- void (*cleanup_tasklet)(unsigned long data);
+ void (*cleanup_fn)(unsigned long data);
void (*timer_fn)(unsigned long data);
int (*self_test)(struct ioatdma_device *device);
};
@@ -337,17 +337,16 @@ struct dca_provider * __devinit ioat_dca_init(struct pci_dev *pdev,
void __iomem *iobase);
unsigned long ioat_get_current_completion(struct ioat_chan_common *chan);
void ioat_init_channel(struct ioatdma_device *device,
- struct ioat_chan_common *chan, int idx,
- void (*timer_fn)(unsigned long),
- void (*tasklet)(unsigned long),
- unsigned long ioat);
+ struct ioat_chan_common *chan, int idx);
+enum dma_status ioat_is_dma_complete(struct dma_chan *c, dma_cookie_t cookie,
+ dma_cookie_t *done, dma_cookie_t *used);
void ioat_dma_unmap(struct ioat_chan_common *chan, enum dma_ctrl_flags flags,
size_t len, struct ioat_dma_descriptor *hw);
bool ioat_cleanup_preamble(struct ioat_chan_common *chan,
unsigned long *phys_complete);
void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type);
void ioat_kobject_del(struct ioatdma_device *device);
-extern struct sysfs_ops ioat_sysfs_ops;
+extern const struct sysfs_ops ioat_sysfs_ops;
extern struct ioat_sysfs_entry ioat_version_attr;
extern struct ioat_sysfs_entry ioat_cap_attr;
#endif /* IOATDMA_H */
diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c
index 5f7a500e18d0..1ed5d66d7dca 100644
--- a/drivers/dma/ioat/dma_v2.c
+++ b/drivers/dma/ioat/dma_v2.c
@@ -51,48 +51,40 @@ MODULE_PARM_DESC(ioat_ring_max_alloc_order,
void __ioat2_issue_pending(struct ioat2_dma_chan *ioat)
{
- void * __iomem reg_base = ioat->base.reg_base;
+ struct ioat_chan_common *chan = &ioat->base;
- ioat->pending = 0;
ioat->dmacount += ioat2_ring_pending(ioat);
ioat->issued = ioat->head;
/* make descriptor updates globally visible before notifying channel */
wmb();
- writew(ioat->dmacount, reg_base + IOAT_CHAN_DMACOUNT_OFFSET);
- dev_dbg(to_dev(&ioat->base),
+ writew(ioat->dmacount, chan->reg_base + IOAT_CHAN_DMACOUNT_OFFSET);
+ dev_dbg(to_dev(chan),
"%s: head: %#x tail: %#x issued: %#x count: %#x\n",
__func__, ioat->head, ioat->tail, ioat->issued, ioat->dmacount);
}
-void ioat2_issue_pending(struct dma_chan *chan)
+void ioat2_issue_pending(struct dma_chan *c)
{
- struct ioat2_dma_chan *ioat = to_ioat2_chan(chan);
+ struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
- spin_lock_bh(&ioat->ring_lock);
- if (ioat->pending == 1)
+ if (ioat2_ring_pending(ioat)) {
+ spin_lock_bh(&ioat->ring_lock);
__ioat2_issue_pending(ioat);
- spin_unlock_bh(&ioat->ring_lock);
+ spin_unlock_bh(&ioat->ring_lock);
+ }
}
/**
* ioat2_update_pending - log pending descriptors
* @ioat: ioat2+ channel
*
- * set pending to '1' unless pending is already set to '2', pending == 2
- * indicates that submission is temporarily blocked due to an in-flight
- * reset. If we are already above the ioat_pending_level threshold then
- * just issue pending.
- *
- * called with ring_lock held
+ * Check if the number of unsubmitted descriptors has exceeded the
+ * watermark. Called with ring_lock held
*/
static void ioat2_update_pending(struct ioat2_dma_chan *ioat)
{
- if (unlikely(ioat->pending == 2))
- return;
- else if (ioat2_ring_pending(ioat) > ioat_pending_level)
+ if (ioat2_ring_pending(ioat) > ioat_pending_level)
__ioat2_issue_pending(ioat);
- else
- ioat->pending = 1;
}
static void __ioat2_start_null_desc(struct ioat2_dma_chan *ioat)
@@ -166,7 +158,7 @@ static void __cleanup(struct ioat2_dma_chan *ioat, unsigned long phys_complete)
seen_current = true;
}
ioat->tail += i;
- BUG_ON(!seen_current); /* no active descs have written a completion? */
+ BUG_ON(active && !seen_current); /* no active descs have written a completion? */
chan->last_completion = phys_complete;
if (ioat->head == ioat->tail) {
@@ -207,9 +199,9 @@ static void ioat2_cleanup(struct ioat2_dma_chan *ioat)
spin_unlock_bh(&chan->cleanup_lock);
}
-void ioat2_cleanup_tasklet(unsigned long data)
+void ioat2_cleanup_event(unsigned long data)
{
- struct ioat2_dma_chan *ioat = (void *) data;
+ struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data);
ioat2_cleanup(ioat);
writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
@@ -249,7 +241,7 @@ int ioat2_quiesce(struct ioat_chan_common *chan, unsigned long tmo)
if (is_ioat_active(status) || is_ioat_idle(status))
ioat_suspend(chan);
while (is_ioat_active(status) || is_ioat_idle(status)) {
- if (end && time_after(jiffies, end)) {
+ if (tmo && time_after(jiffies, end)) {
err = -ETIMEDOUT;
break;
}
@@ -291,7 +283,7 @@ static void ioat2_restart_channel(struct ioat2_dma_chan *ioat)
void ioat2_timer_event(unsigned long data)
{
- struct ioat2_dma_chan *ioat = (void *) data;
+ struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data);
struct ioat_chan_common *chan = &ioat->base;
spin_lock_bh(&chan->cleanup_lock);
@@ -397,10 +389,7 @@ int ioat2_enumerate_channels(struct ioatdma_device *device)
if (!ioat)
break;
- ioat_init_channel(device, &ioat->base, i,
- device->timer_fn,
- device->cleanup_tasklet,
- (unsigned long) ioat);
+ ioat_init_channel(device, &ioat->base, i);
ioat->xfercap_log = xfercap_log;
spin_lock_init(&ioat->ring_lock);
if (device->reset_hw(&ioat->base)) {
@@ -546,7 +535,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
ioat->head = 0;
ioat->issued = 0;
ioat->tail = 0;
- ioat->pending = 0;
ioat->alloc_order = order;
spin_unlock_bh(&ioat->ring_lock);
@@ -701,7 +689,7 @@ int ioat2_alloc_and_lock(u16 *idx, struct ioat2_dma_chan *ioat, int num_descs)
mod_timer(&chan->timer, jiffies + COMPLETION_TIMEOUT);
spin_unlock_bh(&chan->cleanup_lock);
- device->timer_fn((unsigned long) ioat);
+ device->timer_fn((unsigned long) &chan->common);
} else
spin_unlock_bh(&chan->cleanup_lock);
return -ENOMEM;
@@ -785,7 +773,7 @@ void ioat2_free_chan_resources(struct dma_chan *c)
tasklet_disable(&chan->cleanup_task);
del_timer_sync(&chan->timer);
- device->cleanup_tasklet((unsigned long) ioat);
+ device->cleanup_fn((unsigned long) c);
device->reset_hw(chan);
spin_lock_bh(&ioat->ring_lock);
@@ -815,25 +803,9 @@ void ioat2_free_chan_resources(struct dma_chan *c)
chan->last_completion = 0;
chan->completion_dma = 0;
- ioat->pending = 0;
ioat->dmacount = 0;
}
-enum dma_status
-ioat2_is_complete(struct dma_chan *c, dma_cookie_t cookie,
- dma_cookie_t *done, dma_cookie_t *used)
-{
- struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
- struct ioatdma_device *device = ioat->base.device;
-
- if (ioat_is_complete(c, cookie, done, used) == DMA_SUCCESS)
- return DMA_SUCCESS;
-
- device->cleanup_tasklet((unsigned long) ioat);
-
- return ioat_is_complete(c, cookie, done, used);
-}
-
static ssize_t ring_size_show(struct dma_chan *c, char *page)
{
struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
@@ -874,7 +846,7 @@ int __devinit ioat2_dma_probe(struct ioatdma_device *device, int dca)
device->enumerate_channels = ioat2_enumerate_channels;
device->reset_hw = ioat2_reset_hw;
- device->cleanup_tasklet = ioat2_cleanup_tasklet;
+ device->cleanup_fn = ioat2_cleanup_event;
device->timer_fn = ioat2_timer_event;
device->self_test = ioat_dma_self_test;
dma = &device->common;
@@ -882,7 +854,7 @@ int __devinit ioat2_dma_probe(struct ioatdma_device *device, int dca)
dma->device_issue_pending = ioat2_issue_pending;
dma->device_alloc_chan_resources = ioat2_alloc_chan_resources;
dma->device_free_chan_resources = ioat2_free_chan_resources;
- dma->device_is_tx_complete = ioat2_is_complete;
+ dma->device_is_tx_complete = ioat_is_dma_complete;
err = ioat_probe(device);
if (err)
diff --git a/drivers/dma/ioat/dma_v2.h b/drivers/dma/ioat/dma_v2.h
index 3afad8da43cc..ef2871fd7868 100644
--- a/drivers/dma/ioat/dma_v2.h
+++ b/drivers/dma/ioat/dma_v2.h
@@ -47,7 +47,6 @@ extern int ioat_ring_alloc_order;
* @head: allocated index
* @issued: hardware notification point
* @tail: cleanup index
- * @pending: lock free indicator for issued != head
* @dmacount: identical to 'head' except for occasionally resetting to zero
* @alloc_order: log2 of the number of allocated descriptors
* @ring: software ring buffer implementation of hardware ring
@@ -61,7 +60,6 @@ struct ioat2_dma_chan {
u16 tail;
u16 dmacount;
u16 alloc_order;
- int pending;
struct ioat_ring_ent **ring;
spinlock_t ring_lock;
};
@@ -178,12 +176,10 @@ ioat2_dma_prep_memcpy_lock(struct dma_chan *c, dma_addr_t dma_dest,
void ioat2_issue_pending(struct dma_chan *chan);
int ioat2_alloc_chan_resources(struct dma_chan *c);
void ioat2_free_chan_resources(struct dma_chan *c);
-enum dma_status ioat2_is_complete(struct dma_chan *c, dma_cookie_t cookie,
- dma_cookie_t *done, dma_cookie_t *used);
void __ioat2_restart_chan(struct ioat2_dma_chan *ioat);
bool reshape_ring(struct ioat2_dma_chan *ioat, int order);
void __ioat2_issue_pending(struct ioat2_dma_chan *ioat);
-void ioat2_cleanup_tasklet(unsigned long data);
+void ioat2_cleanup_event(unsigned long data);
void ioat2_timer_event(unsigned long data);
int ioat2_quiesce(struct ioat_chan_common *chan, unsigned long tmo);
int ioat2_reset_sync(struct ioat_chan_common *chan, unsigned long tmo);
diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c
index 9908c9e94b2d..26febc56dab1 100644
--- a/drivers/dma/ioat/dma_v3.c
+++ b/drivers/dma/ioat/dma_v3.c
@@ -293,17 +293,25 @@ static void __cleanup(struct ioat2_dma_chan *ioat, unsigned long phys_complete)
}
}
ioat->tail += i;
- BUG_ON(!seen_current); /* no active descs have written a completion? */
+ BUG_ON(active && !seen_current); /* no active descs have written a completion? */
chan->last_completion = phys_complete;
- if (ioat->head == ioat->tail) {
+
+ active = ioat2_ring_active(ioat);
+ if (active == 0) {
dev_dbg(to_dev(chan), "%s: cancel completion timeout\n",
__func__);
clear_bit(IOAT_COMPLETION_PENDING, &chan->state);
mod_timer(&chan->timer, jiffies + IDLE_TIMEOUT);
}
+ /* 5 microsecond delay per pending descriptor */
+ writew(min((5 * active), IOAT_INTRDELAY_MASK),
+ chan->device->reg_base + IOAT_INTRDELAY_OFFSET);
}
-static void ioat3_cleanup(struct ioat2_dma_chan *ioat)
+/* try to cleanup, but yield (via spin_trylock) to incoming submissions
+ * with the expectation that we will immediately poll again shortly
+ */
+static void ioat3_cleanup_poll(struct ioat2_dma_chan *ioat)
{
struct ioat_chan_common *chan = &ioat->base;
unsigned long phys_complete;
@@ -329,29 +337,41 @@ static void ioat3_cleanup(struct ioat2_dma_chan *ioat)
spin_unlock_bh(&chan->cleanup_lock);
}
-static void ioat3_cleanup_tasklet(unsigned long data)
+/* run cleanup now because we already delayed the interrupt via INTRDELAY */
+static void ioat3_cleanup_sync(struct ioat2_dma_chan *ioat)
+{
+ struct ioat_chan_common *chan = &ioat->base;
+ unsigned long phys_complete;
+
+ prefetch(chan->completion);
+
+ spin_lock_bh(&chan->cleanup_lock);
+ if (!ioat_cleanup_preamble(chan, &phys_complete)) {
+ spin_unlock_bh(&chan->cleanup_lock);
+ return;
+ }
+ spin_lock_bh(&ioat->ring_lock);
+
+ __cleanup(ioat, phys_complete);
+
+ spin_unlock_bh(&ioat->ring_lock);
+ spin_unlock_bh(&chan->cleanup_lock);
+}
+
+static void ioat3_cleanup_event(unsigned long data)
{
- struct ioat2_dma_chan *ioat = (void *) data;
+ struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data);
- ioat3_cleanup(ioat);
- writew(IOAT_CHANCTRL_RUN | IOAT3_CHANCTRL_COMPL_DCA_EN,
- ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
+ ioat3_cleanup_sync(ioat);
+ writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
}
static void ioat3_restart_channel(struct ioat2_dma_chan *ioat)
{
struct ioat_chan_common *chan = &ioat->base;
unsigned long phys_complete;
- u32 status;
-
- status = ioat_chansts(chan);
- if (is_ioat_active(status) || is_ioat_idle(status))
- ioat_suspend(chan);
- while (is_ioat_active(status) || is_ioat_idle(status)) {
- status = ioat_chansts(chan);
- cpu_relax();
- }
+ ioat2_quiesce(chan, 0);
if (ioat_cleanup_preamble(chan, &phys_complete))
__cleanup(ioat, phys_complete);
@@ -360,7 +380,7 @@ static void ioat3_restart_channel(struct ioat2_dma_chan *ioat)
static void ioat3_timer_event(unsigned long data)
{
- struct ioat2_dma_chan *ioat = (void *) data;
+ struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data);
struct ioat_chan_common *chan = &ioat->base;
spin_lock_bh(&chan->cleanup_lock);
@@ -426,7 +446,7 @@ ioat3_is_complete(struct dma_chan *c, dma_cookie_t cookie,
if (ioat_is_complete(c, cookie, done, used) == DMA_SUCCESS)
return DMA_SUCCESS;
- ioat3_cleanup(ioat);
+ ioat3_cleanup_poll(ioat);
return ioat_is_complete(c, cookie, done, used);
}
@@ -1239,11 +1259,11 @@ int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca)
if (is_raid_device) {
dma->device_is_tx_complete = ioat3_is_complete;
- device->cleanup_tasklet = ioat3_cleanup_tasklet;
+ device->cleanup_fn = ioat3_cleanup_event;
device->timer_fn = ioat3_timer_event;
} else {
- dma->device_is_tx_complete = ioat2_is_complete;
- device->cleanup_tasklet = ioat2_cleanup_tasklet;
+ dma->device_is_tx_complete = ioat_is_dma_complete;
+ device->cleanup_fn = ioat2_cleanup_event;
device->timer_fn = ioat2_timer_event;
}
diff --git a/drivers/dma/ioat/registers.h b/drivers/dma/ioat/registers.h
index e8ae63baf588..1391798542b6 100644
--- a/drivers/dma/ioat/registers.h
+++ b/drivers/dma/ioat/registers.h
@@ -60,7 +60,7 @@
#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_MASK 0x3FFF /* Interrupt Delay Time */
#define IOAT_INTRDELAY_COALESE_SUPPORT 0x8000 /* Interrupt Coalescing Supported */
#define IOAT_DEVICE_STATUS_OFFSET 0x0E /* 16-bit */
diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c
index 9a5bc1a7389e..2a446397c884 100644
--- a/drivers/dma/ipu/ipu_idmac.c
+++ b/drivers/dma/ipu/ipu_idmac.c
@@ -348,6 +348,7 @@ static void ipu_ch_param_set_size(union chan_param_mem *params,
break;
case IPU_PIX_FMT_BGRA32:
case IPU_PIX_FMT_BGR32:
+ case IPU_PIX_FMT_ABGR32:
params->ip.bpp = 0;
params->ip.pfs = 4;
params->ip.npb = 7;
@@ -376,20 +377,6 @@ static void ipu_ch_param_set_size(union chan_param_mem *params,
params->ip.wid2 = 7; /* Blue bit width - 1 */
params->ip.wid3 = 7; /* Alpha bit width - 1 */
break;
- case IPU_PIX_FMT_ABGR32:
- params->ip.bpp = 0;
- params->ip.pfs = 4;
- params->ip.npb = 7;
- params->ip.sat = 2; /* SAT = 32-bit access */
- params->ip.ofs0 = 8; /* Red bit offset */
- params->ip.ofs1 = 16; /* Green bit offset */
- params->ip.ofs2 = 24; /* Blue bit offset */
- params->ip.ofs3 = 0; /* Alpha bit offset */
- params->ip.wid0 = 7; /* Red bit width - 1 */
- params->ip.wid1 = 7; /* Green bit width - 1 */
- params->ip.wid2 = 7; /* Blue bit width - 1 */
- params->ip.wid3 = 7; /* Alpha bit width - 1 */
- break;
case IPU_PIX_FMT_UYVY:
params->ip.bpp = 2;
params->ip.pfs = 6;
@@ -761,12 +748,10 @@ static void ipu_select_buffer(enum ipu_channel channel, int buffer_n)
* @buffer_n: buffer number to update.
* 0 or 1 are the only valid values.
* @phyaddr: buffer physical address.
- * @return: Returns 0 on success or negative error code on failure. This
- * function will fail if the buffer is set to ready.
*/
/* Called under spin_lock(_irqsave)(&ichan->lock) */
-static int ipu_update_channel_buffer(struct idmac_channel *ichan,
- int buffer_n, dma_addr_t phyaddr)
+static void ipu_update_channel_buffer(struct idmac_channel *ichan,
+ int buffer_n, dma_addr_t phyaddr)
{
enum ipu_channel channel = ichan->dma_chan.chan_id;
uint32_t reg;
@@ -806,8 +791,6 @@ static int ipu_update_channel_buffer(struct idmac_channel *ichan,
}
spin_unlock_irqrestore(&ipu_data.lock, flags);
-
- return 0;
}
/* Called under spin_lock_irqsave(&ichan->lock) */
@@ -816,7 +799,6 @@ static int ipu_submit_buffer(struct idmac_channel *ichan,
{
unsigned int chan_id = ichan->dma_chan.chan_id;
struct device *dev = &ichan->dma_chan.dev->device;
- int ret;
if (async_tx_test_ack(&desc->txd))
return -EINTR;
@@ -827,14 +809,7 @@ static int ipu_submit_buffer(struct idmac_channel *ichan,
* could make it conditional on status >= IPU_CHANNEL_ENABLED, but
* doing it again shouldn't hurt either.
*/
- ret = ipu_update_channel_buffer(ichan, buf_idx,
- sg_dma_address(sg));
-
- if (ret < 0) {
- dev_err(dev, "Updating sg %p on channel 0x%x buffer %d failed!\n",
- sg, chan_id, buf_idx);
- return ret;
- }
+ ipu_update_channel_buffer(ichan, buf_idx, sg_dma_address(sg));
ipu_select_buffer(chan_id, buf_idx);
dev_dbg(dev, "Updated sg %p on channel 0x%x buffer %d\n",
@@ -1379,10 +1354,11 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
if (likely(sgnew) &&
ipu_submit_buffer(ichan, descnew, sgnew, ichan->active_buffer) < 0) {
- callback = desc->txd.callback;
- callback_param = desc->txd.callback_param;
+ callback = descnew->txd.callback;
+ callback_param = descnew->txd.callback_param;
spin_unlock(&ichan->lock);
- callback(callback_param);
+ if (callback)
+ callback(callback_param);
spin_lock(&ichan->lock);
}
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
new file mode 100644
index 000000000000..3fdf1f46bd63
--- /dev/null
+++ b/drivers/dma/mpc512x_dma.c
@@ -0,0 +1,800 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2007, 2008.
+ * Copyright (C) Semihalf 2009
+ *
+ * Written by Piotr Ziecik <kosmo@semihalf.com>. Hardware description
+ * (defines, structures and comments) was taken from MPC5121 DMA driver
+ * written by Hongjun Chen <hong-jun.chen@freescale.com>.
+ *
+ * Approved as OSADL project by a majority of OSADL members and funded
+ * by OSADL membership fees in 2009; for details see www.osadl.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.
+ *
+ * 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 is initial version of MPC5121 DMA driver. Only memory to memory
+ * transfers are supported (tested using dmatest module).
+ */
+
+#include <linux/module.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include <linux/random.h>
+
+/* Number of DMA Transfer descriptors allocated per channel */
+#define MPC_DMA_DESCRIPTORS 64
+
+/* Macro definitions */
+#define MPC_DMA_CHANNELS 64
+#define MPC_DMA_TCD_OFFSET 0x1000
+
+/* Arbitration mode of group and channel */
+#define MPC_DMA_DMACR_EDCG (1 << 31)
+#define MPC_DMA_DMACR_ERGA (1 << 3)
+#define MPC_DMA_DMACR_ERCA (1 << 2)
+
+/* Error codes */
+#define MPC_DMA_DMAES_VLD (1 << 31)
+#define MPC_DMA_DMAES_GPE (1 << 15)
+#define MPC_DMA_DMAES_CPE (1 << 14)
+#define MPC_DMA_DMAES_ERRCHN(err) \
+ (((err) >> 8) & 0x3f)
+#define MPC_DMA_DMAES_SAE (1 << 7)
+#define MPC_DMA_DMAES_SOE (1 << 6)
+#define MPC_DMA_DMAES_DAE (1 << 5)
+#define MPC_DMA_DMAES_DOE (1 << 4)
+#define MPC_DMA_DMAES_NCE (1 << 3)
+#define MPC_DMA_DMAES_SGE (1 << 2)
+#define MPC_DMA_DMAES_SBE (1 << 1)
+#define MPC_DMA_DMAES_DBE (1 << 0)
+
+#define MPC_DMA_TSIZE_1 0x00
+#define MPC_DMA_TSIZE_2 0x01
+#define MPC_DMA_TSIZE_4 0x02
+#define MPC_DMA_TSIZE_16 0x04
+#define MPC_DMA_TSIZE_32 0x05
+
+/* MPC5121 DMA engine registers */
+struct __attribute__ ((__packed__)) mpc_dma_regs {
+ /* 0x00 */
+ u32 dmacr; /* DMA control register */
+ u32 dmaes; /* DMA error status */
+ /* 0x08 */
+ u32 dmaerqh; /* DMA enable request high(channels 63~32) */
+ u32 dmaerql; /* DMA enable request low(channels 31~0) */
+ u32 dmaeeih; /* DMA enable error interrupt high(ch63~32) */
+ u32 dmaeeil; /* DMA enable error interrupt low(ch31~0) */
+ /* 0x18 */
+ u8 dmaserq; /* DMA set enable request */
+ u8 dmacerq; /* DMA clear enable request */
+ u8 dmaseei; /* DMA set enable error interrupt */
+ u8 dmaceei; /* DMA clear enable error interrupt */
+ /* 0x1c */
+ u8 dmacint; /* DMA clear interrupt request */
+ u8 dmacerr; /* DMA clear error */
+ u8 dmassrt; /* DMA set start bit */
+ u8 dmacdne; /* DMA clear DONE status bit */
+ /* 0x20 */
+ u32 dmainth; /* DMA interrupt request high(ch63~32) */
+ u32 dmaintl; /* DMA interrupt request low(ch31~0) */
+ u32 dmaerrh; /* DMA error high(ch63~32) */
+ u32 dmaerrl; /* DMA error low(ch31~0) */
+ /* 0x30 */
+ u32 dmahrsh; /* DMA hw request status high(ch63~32) */
+ u32 dmahrsl; /* DMA hardware request status low(ch31~0) */
+ u32 dmaihsa; /* DMA interrupt high select AXE(ch63~32) */
+ u32 dmailsa; /* DMA interrupt low select AXE(ch31~0) */
+ /* 0x40 ~ 0xff */
+ u32 reserve0[48]; /* Reserved */
+ /* 0x100 */
+ u8 dchpri[MPC_DMA_CHANNELS];
+ /* DMA channels(0~63) priority */
+};
+
+struct __attribute__ ((__packed__)) mpc_dma_tcd {
+ /* 0x00 */
+ u32 saddr; /* Source address */
+
+ u32 smod:5; /* Source address modulo */
+ u32 ssize:3; /* Source data transfer size */
+ u32 dmod:5; /* Destination address modulo */
+ u32 dsize:3; /* Destination data transfer size */
+ u32 soff:16; /* Signed source address offset */
+
+ /* 0x08 */
+ u32 nbytes; /* Inner "minor" byte count */
+ u32 slast; /* Last source address adjustment */
+ u32 daddr; /* Destination address */
+
+ /* 0x14 */
+ u32 citer_elink:1; /* Enable channel-to-channel linking on
+ * minor loop complete
+ */
+ u32 citer_linkch:6; /* Link channel for minor loop complete */
+ u32 citer:9; /* Current "major" iteration count */
+ u32 doff:16; /* Signed destination address offset */
+
+ /* 0x18 */
+ u32 dlast_sga; /* Last Destination address adjustment/scatter
+ * gather address
+ */
+
+ /* 0x1c */
+ u32 biter_elink:1; /* Enable channel-to-channel linking on major
+ * loop complete
+ */
+ u32 biter_linkch:6;
+ u32 biter:9; /* Beginning "major" iteration count */
+ u32 bwc:2; /* Bandwidth control */
+ u32 major_linkch:6; /* Link channel number */
+ u32 done:1; /* Channel done */
+ u32 active:1; /* Channel active */
+ u32 major_elink:1; /* Enable channel-to-channel linking on major
+ * loop complete
+ */
+ u32 e_sg:1; /* Enable scatter/gather processing */
+ u32 d_req:1; /* Disable request */
+ u32 int_half:1; /* Enable an interrupt when major counter is
+ * half complete
+ */
+ u32 int_maj:1; /* Enable an interrupt when major iteration
+ * count completes
+ */
+ u32 start:1; /* Channel start */
+};
+
+struct mpc_dma_desc {
+ struct dma_async_tx_descriptor desc;
+ struct mpc_dma_tcd *tcd;
+ dma_addr_t tcd_paddr;
+ int error;
+ struct list_head node;
+};
+
+struct mpc_dma_chan {
+ struct dma_chan chan;
+ struct list_head free;
+ struct list_head prepared;
+ struct list_head queued;
+ struct list_head active;
+ struct list_head completed;
+ struct mpc_dma_tcd *tcd;
+ dma_addr_t tcd_paddr;
+ dma_cookie_t completed_cookie;
+
+ /* Lock for this structure */
+ spinlock_t lock;
+};
+
+struct mpc_dma {
+ struct dma_device dma;
+ struct tasklet_struct tasklet;
+ struct mpc_dma_chan channels[MPC_DMA_CHANNELS];
+ struct mpc_dma_regs __iomem *regs;
+ struct mpc_dma_tcd __iomem *tcd;
+ int irq;
+ uint error_status;
+
+ /* Lock for error_status field in this structure */
+ spinlock_t error_status_lock;
+};
+
+#define DRV_NAME "mpc512x_dma"
+
+/* Convert struct dma_chan to struct mpc_dma_chan */
+static inline struct mpc_dma_chan *dma_chan_to_mpc_dma_chan(struct dma_chan *c)
+{
+ return container_of(c, struct mpc_dma_chan, chan);
+}
+
+/* Convert struct dma_chan to struct mpc_dma */
+static inline struct mpc_dma *dma_chan_to_mpc_dma(struct dma_chan *c)
+{
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(c);
+ return container_of(mchan, struct mpc_dma, channels[c->chan_id]);
+}
+
+/*
+ * Execute all queued DMA descriptors.
+ *
+ * Following requirements must be met while calling mpc_dma_execute():
+ * a) mchan->lock is acquired,
+ * b) mchan->active list is empty,
+ * c) mchan->queued list contains at least one entry.
+ */
+static void mpc_dma_execute(struct mpc_dma_chan *mchan)
+{
+ struct mpc_dma *mdma = dma_chan_to_mpc_dma(&mchan->chan);
+ struct mpc_dma_desc *first = NULL;
+ struct mpc_dma_desc *prev = NULL;
+ struct mpc_dma_desc *mdesc;
+ int cid = mchan->chan.chan_id;
+
+ /* Move all queued descriptors to active list */
+ list_splice_tail_init(&mchan->queued, &mchan->active);
+
+ /* Chain descriptors into one transaction */
+ list_for_each_entry(mdesc, &mchan->active, node) {
+ if (!first)
+ first = mdesc;
+
+ if (!prev) {
+ prev = mdesc;
+ continue;
+ }
+
+ prev->tcd->dlast_sga = mdesc->tcd_paddr;
+ prev->tcd->e_sg = 1;
+ mdesc->tcd->start = 1;
+
+ prev = mdesc;
+ }
+
+ prev->tcd->start = 0;
+ prev->tcd->int_maj = 1;
+
+ /* Send first descriptor in chain into hardware */
+ memcpy_toio(&mdma->tcd[cid], first->tcd, sizeof(struct mpc_dma_tcd));
+ out_8(&mdma->regs->dmassrt, cid);
+}
+
+/* Handle interrupt on one half of DMA controller (32 channels) */
+static void mpc_dma_irq_process(struct mpc_dma *mdma, u32 is, u32 es, int off)
+{
+ struct mpc_dma_chan *mchan;
+ struct mpc_dma_desc *mdesc;
+ u32 status = is | es;
+ int ch;
+
+ while ((ch = fls(status) - 1) >= 0) {
+ status &= ~(1 << ch);
+ mchan = &mdma->channels[ch + off];
+
+ spin_lock(&mchan->lock);
+
+ /* Check error status */
+ if (es & (1 << ch))
+ list_for_each_entry(mdesc, &mchan->active, node)
+ mdesc->error = -EIO;
+
+ /* Execute queued descriptors */
+ list_splice_tail_init(&mchan->active, &mchan->completed);
+ if (!list_empty(&mchan->queued))
+ mpc_dma_execute(mchan);
+
+ spin_unlock(&mchan->lock);
+ }
+}
+
+/* Interrupt handler */
+static irqreturn_t mpc_dma_irq(int irq, void *data)
+{
+ struct mpc_dma *mdma = data;
+ uint es;
+
+ /* Save error status register */
+ es = in_be32(&mdma->regs->dmaes);
+ spin_lock(&mdma->error_status_lock);
+ if ((es & MPC_DMA_DMAES_VLD) && mdma->error_status == 0)
+ mdma->error_status = es;
+ spin_unlock(&mdma->error_status_lock);
+
+ /* Handle interrupt on each channel */
+ mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmainth),
+ in_be32(&mdma->regs->dmaerrh), 32);
+ mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmaintl),
+ in_be32(&mdma->regs->dmaerrl), 0);
+
+ /* Ack interrupt on all channels */
+ out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
+
+ /* Schedule tasklet */
+ tasklet_schedule(&mdma->tasklet);
+
+ return IRQ_HANDLED;
+}
+
+/* DMA Tasklet */
+static void mpc_dma_tasklet(unsigned long data)
+{
+ struct mpc_dma *mdma = (void *)data;
+ dma_cookie_t last_cookie = 0;
+ struct mpc_dma_chan *mchan;
+ struct mpc_dma_desc *mdesc;
+ struct dma_async_tx_descriptor *desc;
+ unsigned long flags;
+ LIST_HEAD(list);
+ uint es;
+ int i;
+
+ spin_lock_irqsave(&mdma->error_status_lock, flags);
+ es = mdma->error_status;
+ mdma->error_status = 0;
+ spin_unlock_irqrestore(&mdma->error_status_lock, flags);
+
+ /* Print nice error report */
+ if (es) {
+ dev_err(mdma->dma.dev,
+ "Hardware reported following error(s) on channel %u:\n",
+ MPC_DMA_DMAES_ERRCHN(es));
+
+ if (es & MPC_DMA_DMAES_GPE)
+ dev_err(mdma->dma.dev, "- Group Priority Error\n");
+ if (es & MPC_DMA_DMAES_CPE)
+ dev_err(mdma->dma.dev, "- Channel Priority Error\n");
+ if (es & MPC_DMA_DMAES_SAE)
+ dev_err(mdma->dma.dev, "- Source Address Error\n");
+ if (es & MPC_DMA_DMAES_SOE)
+ dev_err(mdma->dma.dev, "- Source Offset"
+ " Configuration Error\n");
+ if (es & MPC_DMA_DMAES_DAE)
+ dev_err(mdma->dma.dev, "- Destination Address"
+ " Error\n");
+ if (es & MPC_DMA_DMAES_DOE)
+ dev_err(mdma->dma.dev, "- Destination Offset"
+ " Configuration Error\n");
+ if (es & MPC_DMA_DMAES_NCE)
+ dev_err(mdma->dma.dev, "- NBytes/Citter"
+ " Configuration Error\n");
+ if (es & MPC_DMA_DMAES_SGE)
+ dev_err(mdma->dma.dev, "- Scatter/Gather"
+ " Configuration Error\n");
+ if (es & MPC_DMA_DMAES_SBE)
+ dev_err(mdma->dma.dev, "- Source Bus Error\n");
+ if (es & MPC_DMA_DMAES_DBE)
+ dev_err(mdma->dma.dev, "- Destination Bus Error\n");
+ }
+
+ for (i = 0; i < mdma->dma.chancnt; i++) {
+ mchan = &mdma->channels[i];
+
+ /* Get all completed descriptors */
+ spin_lock_irqsave(&mchan->lock, flags);
+ if (!list_empty(&mchan->completed))
+ list_splice_tail_init(&mchan->completed, &list);
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ if (list_empty(&list))
+ continue;
+
+ /* Execute callbacks and run dependencies */
+ list_for_each_entry(mdesc, &list, node) {
+ desc = &mdesc->desc;
+
+ if (desc->callback)
+ desc->callback(desc->callback_param);
+
+ last_cookie = desc->cookie;
+ dma_run_dependencies(desc);
+ }
+
+ /* Free descriptors */
+ spin_lock_irqsave(&mchan->lock, flags);
+ list_splice_tail_init(&list, &mchan->free);
+ mchan->completed_cookie = last_cookie;
+ spin_unlock_irqrestore(&mchan->lock, flags);
+ }
+}
+
+/* Submit descriptor to hardware */
+static dma_cookie_t mpc_dma_tx_submit(struct dma_async_tx_descriptor *txd)
+{
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(txd->chan);
+ struct mpc_dma_desc *mdesc;
+ unsigned long flags;
+ dma_cookie_t cookie;
+
+ mdesc = container_of(txd, struct mpc_dma_desc, desc);
+
+ spin_lock_irqsave(&mchan->lock, flags);
+
+ /* Move descriptor to queue */
+ list_move_tail(&mdesc->node, &mchan->queued);
+
+ /* If channel is idle, execute all queued descriptors */
+ if (list_empty(&mchan->active))
+ mpc_dma_execute(mchan);
+
+ /* Update cookie */
+ cookie = mchan->chan.cookie + 1;
+ if (cookie <= 0)
+ cookie = 1;
+
+ mchan->chan.cookie = cookie;
+ mdesc->desc.cookie = cookie;
+
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ return cookie;
+}
+
+/* Alloc channel resources */
+static int mpc_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+ struct mpc_dma_desc *mdesc;
+ struct mpc_dma_tcd *tcd;
+ dma_addr_t tcd_paddr;
+ unsigned long flags;
+ LIST_HEAD(descs);
+ int i;
+
+ /* Alloc DMA memory for Transfer Control Descriptors */
+ tcd = dma_alloc_coherent(mdma->dma.dev,
+ MPC_DMA_DESCRIPTORS * sizeof(struct mpc_dma_tcd),
+ &tcd_paddr, GFP_KERNEL);
+ if (!tcd)
+ return -ENOMEM;
+
+ /* Alloc descriptors for this channel */
+ for (i = 0; i < MPC_DMA_DESCRIPTORS; i++) {
+ mdesc = kzalloc(sizeof(struct mpc_dma_desc), GFP_KERNEL);
+ if (!mdesc) {
+ dev_notice(mdma->dma.dev, "Memory allocation error. "
+ "Allocated only %u descriptors\n", i);
+ break;
+ }
+
+ dma_async_tx_descriptor_init(&mdesc->desc, chan);
+ mdesc->desc.flags = DMA_CTRL_ACK;
+ mdesc->desc.tx_submit = mpc_dma_tx_submit;
+
+ mdesc->tcd = &tcd[i];
+ mdesc->tcd_paddr = tcd_paddr + (i * sizeof(struct mpc_dma_tcd));
+
+ list_add_tail(&mdesc->node, &descs);
+ }
+
+ /* Return error only if no descriptors were allocated */
+ if (i == 0) {
+ dma_free_coherent(mdma->dma.dev,
+ MPC_DMA_DESCRIPTORS * sizeof(struct mpc_dma_tcd),
+ tcd, tcd_paddr);
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&mchan->lock, flags);
+ mchan->tcd = tcd;
+ mchan->tcd_paddr = tcd_paddr;
+ list_splice_tail_init(&descs, &mchan->free);
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ /* Enable Error Interrupt */
+ out_8(&mdma->regs->dmaseei, chan->chan_id);
+
+ return 0;
+}
+
+/* Free channel resources */
+static void mpc_dma_free_chan_resources(struct dma_chan *chan)
+{
+ struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+ struct mpc_dma_desc *mdesc, *tmp;
+ struct mpc_dma_tcd *tcd;
+ dma_addr_t tcd_paddr;
+ unsigned long flags;
+ LIST_HEAD(descs);
+
+ spin_lock_irqsave(&mchan->lock, flags);
+
+ /* Channel must be idle */
+ BUG_ON(!list_empty(&mchan->prepared));
+ BUG_ON(!list_empty(&mchan->queued));
+ BUG_ON(!list_empty(&mchan->active));
+ BUG_ON(!list_empty(&mchan->completed));
+
+ /* Move data */
+ list_splice_tail_init(&mchan->free, &descs);
+ tcd = mchan->tcd;
+ tcd_paddr = mchan->tcd_paddr;
+
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ /* Free DMA memory used by descriptors */
+ dma_free_coherent(mdma->dma.dev,
+ MPC_DMA_DESCRIPTORS * sizeof(struct mpc_dma_tcd),
+ tcd, tcd_paddr);
+
+ /* Free descriptors */
+ list_for_each_entry_safe(mdesc, tmp, &descs, node)
+ kfree(mdesc);
+
+ /* Disable Error Interrupt */
+ out_8(&mdma->regs->dmaceei, chan->chan_id);
+}
+
+/* Send all pending descriptor to hardware */
+static void mpc_dma_issue_pending(struct dma_chan *chan)
+{
+ /*
+ * We are posting descriptors to the hardware as soon as
+ * they are ready, so this function does nothing.
+ */
+}
+
+/* Check request completion status */
+static enum dma_status
+mpc_dma_is_tx_complete(struct dma_chan *chan, dma_cookie_t cookie,
+ dma_cookie_t *done, dma_cookie_t *used)
+{
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+ unsigned long flags;
+ dma_cookie_t last_used;
+ dma_cookie_t last_complete;
+
+ spin_lock_irqsave(&mchan->lock, flags);
+ last_used = mchan->chan.cookie;
+ last_complete = mchan->completed_cookie;
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ if (done)
+ *done = last_complete;
+
+ if (used)
+ *used = last_used;
+
+ return dma_async_is_complete(cookie, last_complete, last_used);
+}
+
+/* Prepare descriptor for memory to memory copy */
+static struct dma_async_tx_descriptor *
+mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
+ size_t len, unsigned long flags)
+{
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+ struct mpc_dma_desc *mdesc = NULL;
+ struct mpc_dma_tcd *tcd;
+ unsigned long iflags;
+
+ /* Get free descriptor */
+ spin_lock_irqsave(&mchan->lock, iflags);
+ if (!list_empty(&mchan->free)) {
+ mdesc = list_first_entry(&mchan->free, struct mpc_dma_desc,
+ node);
+ list_del(&mdesc->node);
+ }
+ spin_unlock_irqrestore(&mchan->lock, iflags);
+
+ if (!mdesc)
+ return NULL;
+
+ mdesc->error = 0;
+ tcd = mdesc->tcd;
+
+ /* Prepare Transfer Control Descriptor for this transaction */
+ memset(tcd, 0, sizeof(struct mpc_dma_tcd));
+
+ if (IS_ALIGNED(src | dst | len, 32)) {
+ tcd->ssize = MPC_DMA_TSIZE_32;
+ tcd->dsize = MPC_DMA_TSIZE_32;
+ tcd->soff = 32;
+ tcd->doff = 32;
+ } else if (IS_ALIGNED(src | dst | len, 16)) {
+ tcd->ssize = MPC_DMA_TSIZE_16;
+ tcd->dsize = MPC_DMA_TSIZE_16;
+ tcd->soff = 16;
+ tcd->doff = 16;
+ } else if (IS_ALIGNED(src | dst | len, 4)) {
+ tcd->ssize = MPC_DMA_TSIZE_4;
+ tcd->dsize = MPC_DMA_TSIZE_4;
+ tcd->soff = 4;
+ tcd->doff = 4;
+ } else if (IS_ALIGNED(src | dst | len, 2)) {
+ tcd->ssize = MPC_DMA_TSIZE_2;
+ tcd->dsize = MPC_DMA_TSIZE_2;
+ tcd->soff = 2;
+ tcd->doff = 2;
+ } else {
+ tcd->ssize = MPC_DMA_TSIZE_1;
+ tcd->dsize = MPC_DMA_TSIZE_1;
+ tcd->soff = 1;
+ tcd->doff = 1;
+ }
+
+ tcd->saddr = src;
+ tcd->daddr = dst;
+ tcd->nbytes = len;
+ tcd->biter = 1;
+ tcd->citer = 1;
+
+ /* Place descriptor in prepared list */
+ spin_lock_irqsave(&mchan->lock, iflags);
+ list_add_tail(&mdesc->node, &mchan->prepared);
+ spin_unlock_irqrestore(&mchan->lock, iflags);
+
+ return &mdesc->desc;
+}
+
+static int __devinit mpc_dma_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct device_node *dn = op->node;
+ struct device *dev = &op->dev;
+ struct dma_device *dma;
+ struct mpc_dma *mdma;
+ struct mpc_dma_chan *mchan;
+ struct resource res;
+ ulong regs_start, regs_size;
+ int retval, i;
+
+ mdma = devm_kzalloc(dev, sizeof(struct mpc_dma), GFP_KERNEL);
+ if (!mdma) {
+ dev_err(dev, "Memory exhausted!\n");
+ return -ENOMEM;
+ }
+
+ mdma->irq = irq_of_parse_and_map(dn, 0);
+ if (mdma->irq == NO_IRQ) {
+ dev_err(dev, "Error mapping IRQ!\n");
+ return -EINVAL;
+ }
+
+ retval = of_address_to_resource(dn, 0, &res);
+ if (retval) {
+ dev_err(dev, "Error parsing memory region!\n");
+ return retval;
+ }
+
+ regs_start = res.start;
+ regs_size = res.end - res.start + 1;
+
+ if (!devm_request_mem_region(dev, regs_start, regs_size, DRV_NAME)) {
+ dev_err(dev, "Error requesting memory region!\n");
+ return -EBUSY;
+ }
+
+ mdma->regs = devm_ioremap(dev, regs_start, regs_size);
+ if (!mdma->regs) {
+ dev_err(dev, "Error mapping memory region!\n");
+ return -ENOMEM;
+ }
+
+ mdma->tcd = (struct mpc_dma_tcd *)((u8 *)(mdma->regs)
+ + MPC_DMA_TCD_OFFSET);
+
+ retval = devm_request_irq(dev, mdma->irq, &mpc_dma_irq, 0, DRV_NAME,
+ mdma);
+ if (retval) {
+ dev_err(dev, "Error requesting IRQ!\n");
+ return -EINVAL;
+ }
+
+ spin_lock_init(&mdma->error_status_lock);
+
+ dma = &mdma->dma;
+ dma->dev = dev;
+ dma->chancnt = MPC_DMA_CHANNELS;
+ dma->device_alloc_chan_resources = mpc_dma_alloc_chan_resources;
+ dma->device_free_chan_resources = mpc_dma_free_chan_resources;
+ dma->device_issue_pending = mpc_dma_issue_pending;
+ dma->device_is_tx_complete = mpc_dma_is_tx_complete;
+ dma->device_prep_dma_memcpy = mpc_dma_prep_memcpy;
+
+ INIT_LIST_HEAD(&dma->channels);
+ dma_cap_set(DMA_MEMCPY, dma->cap_mask);
+
+ for (i = 0; i < dma->chancnt; i++) {
+ mchan = &mdma->channels[i];
+
+ mchan->chan.device = dma;
+ mchan->chan.chan_id = i;
+ mchan->chan.cookie = 1;
+ mchan->completed_cookie = mchan->chan.cookie;
+
+ INIT_LIST_HEAD(&mchan->free);
+ INIT_LIST_HEAD(&mchan->prepared);
+ INIT_LIST_HEAD(&mchan->queued);
+ INIT_LIST_HEAD(&mchan->active);
+ INIT_LIST_HEAD(&mchan->completed);
+
+ spin_lock_init(&mchan->lock);
+ list_add_tail(&mchan->chan.device_node, &dma->channels);
+ }
+
+ tasklet_init(&mdma->tasklet, mpc_dma_tasklet, (unsigned long)mdma);
+
+ /*
+ * Configure DMA Engine:
+ * - Dynamic clock,
+ * - Round-robin group arbitration,
+ * - Round-robin channel arbitration.
+ */
+ out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG |
+ MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA);
+
+ /* Disable hardware DMA requests */
+ out_be32(&mdma->regs->dmaerqh, 0);
+ out_be32(&mdma->regs->dmaerql, 0);
+
+ /* Disable error interrupts */
+ out_be32(&mdma->regs->dmaeeih, 0);
+ out_be32(&mdma->regs->dmaeeil, 0);
+
+ /* Clear interrupts status */
+ out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
+
+ /* Route interrupts to IPIC */
+ out_be32(&mdma->regs->dmaihsa, 0);
+ out_be32(&mdma->regs->dmailsa, 0);
+
+ /* Register DMA engine */
+ dev_set_drvdata(dev, mdma);
+ retval = dma_async_device_register(dma);
+ if (retval) {
+ devm_free_irq(dev, mdma->irq, mdma);
+ irq_dispose_mapping(mdma->irq);
+ }
+
+ return retval;
+}
+
+static int __devexit mpc_dma_remove(struct of_device *op)
+{
+ struct device *dev = &op->dev;
+ struct mpc_dma *mdma = dev_get_drvdata(dev);
+
+ dma_async_device_unregister(&mdma->dma);
+ devm_free_irq(dev, mdma->irq, mdma);
+ irq_dispose_mapping(mdma->irq);
+
+ return 0;
+}
+
+static struct of_device_id mpc_dma_match[] = {
+ { .compatible = "fsl,mpc5121-dma", },
+ {},
+};
+
+static struct of_platform_driver mpc_dma_driver = {
+ .match_table = mpc_dma_match,
+ .probe = mpc_dma_probe,
+ .remove = __devexit_p(mpc_dma_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mpc_dma_init(void)
+{
+ return of_register_platform_driver(&mpc_dma_driver);
+}
+module_init(mpc_dma_init);
+
+static void __exit mpc_dma_exit(void)
+{
+ of_unregister_platform_driver(&mpc_dma_driver);
+}
+module_exit(mpc_dma_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Piotr Ziecik <kosmo@semihalf.com>");
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index 0a3478e910f0..e69d87f24a25 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -4940,7 +4940,7 @@ out_free:
return ret;
}
-static struct of_device_id __devinitdata ppc440spe_adma_of_match[] = {
+static const struct of_device_id ppc440spe_adma_of_match[] __devinitconst = {
{ .compatible = "ibm,dma-440spe", },
{ .compatible = "amcc,xor-accelerator", },
{},
diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
index d10cc899c460..5d17e09cb625 100644
--- a/drivers/dma/shdma.c
+++ b/drivers/dma/shdma.c
@@ -24,8 +24,10 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
-#include <cpu/dma.h>
-#include <asm/dma-sh.h>
+#include <linux/pm_runtime.h>
+
+#include <asm/dmaengine.h>
+
#include "shdma.h"
/* DMA descriptor control */
@@ -38,33 +40,32 @@ enum sh_dmae_desc_status {
};
#define NR_DESCS_PER_CHANNEL 32
-/*
- * Define the default configuration for dual address memory-memory transfer.
- * The 0x400 value represents auto-request, external->external.
- *
- * And this driver set 4byte burst mode.
- * If you want to change mode, you need to change RS_DEFAULT of value.
- * (ex 1byte burst mode -> (RS_DUAL & ~TS_32)
- */
-#define RS_DEFAULT (RS_DUAL)
+/* Default MEMCPY transfer size = 2^2 = 4 bytes */
+#define LOG2_DEFAULT_XFER_SIZE 2
+
+/* A bitmask with bits enough for enum sh_dmae_slave_chan_id */
+static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SHDMA_SLAVE_NUMBER)];
static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all);
-#define SH_DMAC_CHAN_BASE(id) (dma_base_addr[id])
static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg)
{
- ctrl_outl(data, (SH_DMAC_CHAN_BASE(sh_dc->id) + reg));
+ __raw_writel(data, sh_dc->base + reg / sizeof(u32));
}
static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg)
{
- return ctrl_inl((SH_DMAC_CHAN_BASE(sh_dc->id) + reg));
+ return __raw_readl(sh_dc->base + reg / sizeof(u32));
}
-static void dmae_init(struct sh_dmae_chan *sh_chan)
+static u16 dmaor_read(struct sh_dmae_device *shdev)
{
- u32 chcr = RS_DEFAULT; /* default is DUAL mode */
- sh_dmae_writel(sh_chan, chcr, CHCR);
+ return __raw_readw(shdev->chan_reg + DMAOR / sizeof(u32));
+}
+
+static void dmaor_write(struct sh_dmae_device *shdev, u16 data)
+{
+ __raw_writew(data, shdev->chan_reg + DMAOR / sizeof(u32));
}
/*
@@ -72,50 +73,75 @@ static void dmae_init(struct sh_dmae_chan *sh_chan)
*
* SH7780 has two DMAOR register
*/
-static void sh_dmae_ctl_stop(int id)
+static void sh_dmae_ctl_stop(struct sh_dmae_device *shdev)
{
- unsigned short dmaor = dmaor_read_reg(id);
+ unsigned short dmaor = dmaor_read(shdev);
- dmaor &= ~(DMAOR_NMIF | DMAOR_AE);
- dmaor_write_reg(id, dmaor);
+ dmaor_write(shdev, dmaor & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME));
}
-static int sh_dmae_rst(int id)
+static int sh_dmae_rst(struct sh_dmae_device *shdev)
{
unsigned short dmaor;
- sh_dmae_ctl_stop(id);
- dmaor = dmaor_read_reg(id) | DMAOR_INIT;
+ sh_dmae_ctl_stop(shdev);
+ dmaor = dmaor_read(shdev) | shdev->pdata->dmaor_init;
- dmaor_write_reg(id, dmaor);
- if (dmaor_read_reg(id) & (DMAOR_AE | DMAOR_NMIF)) {
- pr_warning(KERN_ERR "dma-sh: Can't initialize DMAOR.\n");
+ dmaor_write(shdev, dmaor);
+ if (dmaor_read(shdev) & (DMAOR_AE | DMAOR_NMIF)) {
+ pr_warning("dma-sh: Can't initialize DMAOR.\n");
return -EINVAL;
}
return 0;
}
-static int dmae_is_busy(struct sh_dmae_chan *sh_chan)
+static bool dmae_is_busy(struct sh_dmae_chan *sh_chan)
{
u32 chcr = sh_dmae_readl(sh_chan, CHCR);
- if (chcr & CHCR_DE) {
- if (!(chcr & CHCR_TE))
- return -EBUSY; /* working */
- }
- return 0; /* waiting */
+
+ if ((chcr & (CHCR_DE | CHCR_TE)) == CHCR_DE)
+ return true; /* working */
+
+ return false; /* waiting */
}
-static inline unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan)
+static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
{
- u32 chcr = sh_dmae_readl(sh_chan, CHCR);
- return ts_shift[(chcr & CHCR_TS_MASK) >> CHCR_TS_SHIFT];
+ struct sh_dmae_device *shdev = container_of(sh_chan->common.device,
+ struct sh_dmae_device, common);
+ struct sh_dmae_pdata *pdata = shdev->pdata;
+ int cnt = ((chcr & pdata->ts_low_mask) >> pdata->ts_low_shift) |
+ ((chcr & pdata->ts_high_mask) >> pdata->ts_high_shift);
+
+ if (cnt >= pdata->ts_shift_num)
+ cnt = 0;
+
+ return pdata->ts_shift[cnt];
+}
+
+static u32 log2size_to_chcr(struct sh_dmae_chan *sh_chan, int l2size)
+{
+ struct sh_dmae_device *shdev = container_of(sh_chan->common.device,
+ struct sh_dmae_device, common);
+ struct sh_dmae_pdata *pdata = shdev->pdata;
+ int i;
+
+ for (i = 0; i < pdata->ts_shift_num; i++)
+ if (pdata->ts_shift[i] == l2size)
+ break;
+
+ if (i == pdata->ts_shift_num)
+ i = 0;
+
+ return ((i << pdata->ts_low_shift) & pdata->ts_low_mask) |
+ ((i << pdata->ts_high_shift) & pdata->ts_high_mask);
}
static void dmae_set_reg(struct sh_dmae_chan *sh_chan, struct sh_dmae_regs *hw)
{
sh_dmae_writel(sh_chan, hw->sar, SAR);
sh_dmae_writel(sh_chan, hw->dar, DAR);
- sh_dmae_writel(sh_chan, hw->tcr >> calc_xmit_shift(sh_chan), TCR);
+ sh_dmae_writel(sh_chan, hw->tcr >> sh_chan->xmit_shift, TCR);
}
static void dmae_start(struct sh_dmae_chan *sh_chan)
@@ -123,7 +149,7 @@ static void dmae_start(struct sh_dmae_chan *sh_chan)
u32 chcr = sh_dmae_readl(sh_chan, CHCR);
chcr |= CHCR_DE | CHCR_IE;
- sh_dmae_writel(sh_chan, chcr, CHCR);
+ sh_dmae_writel(sh_chan, chcr & ~CHCR_TE, CHCR);
}
static void dmae_halt(struct sh_dmae_chan *sh_chan)
@@ -134,55 +160,44 @@ static void dmae_halt(struct sh_dmae_chan *sh_chan)
sh_dmae_writel(sh_chan, chcr, CHCR);
}
+static void dmae_init(struct sh_dmae_chan *sh_chan)
+{
+ /*
+ * Default configuration for dual address memory-memory transfer.
+ * 0x400 represents auto-request.
+ */
+ u32 chcr = DM_INC | SM_INC | 0x400 | log2size_to_chcr(sh_chan,
+ LOG2_DEFAULT_XFER_SIZE);
+ sh_chan->xmit_shift = calc_xmit_shift(sh_chan, chcr);
+ sh_dmae_writel(sh_chan, chcr, CHCR);
+}
+
static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val)
{
- int ret = dmae_is_busy(sh_chan);
/* When DMA was working, can not set data to CHCR */
- if (ret)
- return ret;
+ if (dmae_is_busy(sh_chan))
+ return -EBUSY;
+ sh_chan->xmit_shift = calc_xmit_shift(sh_chan, val);
sh_dmae_writel(sh_chan, val, CHCR);
+
return 0;
}
-#define DMARS1_ADDR 0x04
-#define DMARS2_ADDR 0x08
-#define DMARS_SHIFT 8
-#define DMARS_CHAN_MSK 0x01
static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
{
- u32 addr;
- int shift = 0;
- int ret = dmae_is_busy(sh_chan);
- if (ret)
- return ret;
-
- if (sh_chan->id & DMARS_CHAN_MSK)
- shift = DMARS_SHIFT;
-
- switch (sh_chan->id) {
- /* DMARS0 */
- case 0:
- case 1:
- addr = SH_DMARS_BASE;
- break;
- /* DMARS1 */
- case 2:
- case 3:
- addr = (SH_DMARS_BASE + DMARS1_ADDR);
- break;
- /* DMARS2 */
- case 4:
- case 5:
- addr = (SH_DMARS_BASE + DMARS2_ADDR);
- break;
- default:
- return -EINVAL;
- }
+ struct sh_dmae_device *shdev = container_of(sh_chan->common.device,
+ struct sh_dmae_device, common);
+ struct sh_dmae_pdata *pdata = shdev->pdata;
+ struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->id];
+ u16 __iomem *addr = shdev->dmars + chan_pdata->dmars / sizeof(u16);
+ int shift = chan_pdata->dmars_bit;
+
+ if (dmae_is_busy(sh_chan))
+ return -EBUSY;
- ctrl_outw((val << shift) |
- (ctrl_inw(addr) & (shift ? 0xFF00 : 0x00FF)),
- addr);
+ __raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift),
+ addr);
return 0;
}
@@ -250,10 +265,54 @@ static struct sh_desc *sh_dmae_get_desc(struct sh_dmae_chan *sh_chan)
return NULL;
}
+static struct sh_dmae_slave_config *sh_dmae_find_slave(
+ struct sh_dmae_chan *sh_chan, enum sh_dmae_slave_chan_id slave_id)
+{
+ struct dma_device *dma_dev = sh_chan->common.device;
+ struct sh_dmae_device *shdev = container_of(dma_dev,
+ struct sh_dmae_device, common);
+ struct sh_dmae_pdata *pdata = shdev->pdata;
+ int i;
+
+ if ((unsigned)slave_id >= SHDMA_SLAVE_NUMBER)
+ return NULL;
+
+ for (i = 0; i < pdata->slave_num; i++)
+ if (pdata->slave[i].slave_id == slave_id)
+ return pdata->slave + i;
+
+ return NULL;
+}
+
static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
{
struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
struct sh_desc *desc;
+ struct sh_dmae_slave *param = chan->private;
+
+ pm_runtime_get_sync(sh_chan->dev);
+
+ /*
+ * This relies on the guarantee from dmaengine that alloc_chan_resources
+ * never runs concurrently with itself or free_chan_resources.
+ */
+ if (param) {
+ struct sh_dmae_slave_config *cfg;
+
+ cfg = sh_dmae_find_slave(sh_chan, param->slave_id);
+ if (!cfg)
+ return -EINVAL;
+
+ if (test_and_set_bit(param->slave_id, sh_dmae_slave_used))
+ return -EBUSY;
+
+ param->config = cfg;
+
+ dmae_set_dmars(sh_chan, cfg->mid_rid);
+ dmae_set_chcr(sh_chan, cfg->chcr);
+ } else if ((sh_dmae_readl(sh_chan, CHCR) & 0xf00) != 0x400) {
+ dmae_init(sh_chan);
+ }
spin_lock_bh(&sh_chan->desc_lock);
while (sh_chan->descs_allocated < NR_DESCS_PER_CHANNEL) {
@@ -274,6 +333,9 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
}
spin_unlock_bh(&sh_chan->desc_lock);
+ if (!sh_chan->descs_allocated)
+ pm_runtime_put(sh_chan->dev);
+
return sh_chan->descs_allocated;
}
@@ -285,11 +347,20 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
struct sh_desc *desc, *_desc;
LIST_HEAD(list);
+ int descs = sh_chan->descs_allocated;
+
+ dmae_halt(sh_chan);
/* Prepared and not submitted descriptors can still be on the queue */
if (!list_empty(&sh_chan->ld_queue))
sh_dmae_chan_ld_cleanup(sh_chan, true);
+ if (chan->private) {
+ /* The caller is holding dma_list_mutex */
+ struct sh_dmae_slave *param = chan->private;
+ clear_bit(param->slave_id, sh_dmae_slave_used);
+ }
+
spin_lock_bh(&sh_chan->desc_lock);
list_splice_init(&sh_chan->ld_free, &list);
@@ -297,27 +368,104 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
spin_unlock_bh(&sh_chan->desc_lock);
+ if (descs > 0)
+ pm_runtime_put(sh_chan->dev);
+
list_for_each_entry_safe(desc, _desc, &list, node)
kfree(desc);
}
-static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy(
- struct dma_chan *chan, dma_addr_t dma_dest, dma_addr_t dma_src,
- size_t len, unsigned long flags)
+/**
+ * sh_dmae_add_desc - get, set up and return one transfer descriptor
+ * @sh_chan: DMA channel
+ * @flags: DMA transfer flags
+ * @dest: destination DMA address, incremented when direction equals
+ * DMA_FROM_DEVICE or DMA_BIDIRECTIONAL
+ * @src: source DMA address, incremented when direction equals
+ * DMA_TO_DEVICE or DMA_BIDIRECTIONAL
+ * @len: DMA transfer length
+ * @first: if NULL, set to the current descriptor and cookie set to -EBUSY
+ * @direction: needed for slave DMA to decide which address to keep constant,
+ * equals DMA_BIDIRECTIONAL for MEMCPY
+ * Returns 0 or an error
+ * Locks: called with desc_lock held
+ */
+static struct sh_desc *sh_dmae_add_desc(struct sh_dmae_chan *sh_chan,
+ unsigned long flags, dma_addr_t *dest, dma_addr_t *src, size_t *len,
+ struct sh_desc **first, enum dma_data_direction direction)
{
- struct sh_dmae_chan *sh_chan;
- struct sh_desc *first = NULL, *prev = NULL, *new;
+ struct sh_desc *new;
size_t copy_size;
- LIST_HEAD(tx_list);
- int chunks = (len + SH_DMA_TCR_MAX) / (SH_DMA_TCR_MAX + 1);
- if (!chan)
+ if (!*len)
return NULL;
- if (!len)
+ /* Allocate the link descriptor from the free list */
+ new = sh_dmae_get_desc(sh_chan);
+ if (!new) {
+ dev_err(sh_chan->dev, "No free link descriptor available\n");
return NULL;
+ }
- sh_chan = to_sh_chan(chan);
+ copy_size = min(*len, (size_t)SH_DMA_TCR_MAX + 1);
+
+ new->hw.sar = *src;
+ new->hw.dar = *dest;
+ new->hw.tcr = copy_size;
+
+ if (!*first) {
+ /* First desc */
+ new->async_tx.cookie = -EBUSY;
+ *first = new;
+ } else {
+ /* Other desc - invisible to the user */
+ new->async_tx.cookie = -EINVAL;
+ }
+
+ dev_dbg(sh_chan->dev,
+ "chaining (%u/%u)@%x -> %x with %p, cookie %d, shift %d\n",
+ copy_size, *len, *src, *dest, &new->async_tx,
+ new->async_tx.cookie, sh_chan->xmit_shift);
+
+ new->mark = DESC_PREPARED;
+ new->async_tx.flags = flags;
+ new->direction = direction;
+
+ *len -= copy_size;
+ if (direction == DMA_BIDIRECTIONAL || direction == DMA_TO_DEVICE)
+ *src += copy_size;
+ if (direction == DMA_BIDIRECTIONAL || direction == DMA_FROM_DEVICE)
+ *dest += copy_size;
+
+ return new;
+}
+
+/*
+ * sh_dmae_prep_sg - prepare transfer descriptors from an SG list
+ *
+ * Common routine for public (MEMCPY) and slave DMA. The MEMCPY case is also
+ * converted to scatter-gather to guarantee consistent locking and a correct
+ * list manipulation. For slave DMA direction carries the usual meaning, and,
+ * logically, the SG list is RAM and the addr variable contains slave address,
+ * e.g., the FIFO I/O register. For MEMCPY direction equals DMA_BIDIRECTIONAL
+ * and the SG list contains only one element and points at the source buffer.
+ */
+static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_chan,
+ struct scatterlist *sgl, unsigned int sg_len, dma_addr_t *addr,
+ enum dma_data_direction direction, unsigned long flags)
+{
+ struct scatterlist *sg;
+ struct sh_desc *first = NULL, *new = NULL /* compiler... */;
+ LIST_HEAD(tx_list);
+ int chunks = 0;
+ int i;
+
+ if (!sg_len)
+ return NULL;
+
+ for_each_sg(sgl, sg, sg_len, i)
+ chunks += (sg_dma_len(sg) + SH_DMA_TCR_MAX) /
+ (SH_DMA_TCR_MAX + 1);
/* Have to lock the whole loop to protect against concurrent release */
spin_lock_bh(&sh_chan->desc_lock);
@@ -333,49 +481,32 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy(
* only during this function, then they are immediately spliced
* back onto the free list in form of a chain
*/
- do {
- /* Allocate the link descriptor from the free list */
- new = sh_dmae_get_desc(sh_chan);
- if (!new) {
- dev_err(sh_chan->dev,
- "No free memory for link descriptor\n");
- list_for_each_entry(new, &tx_list, node)
- new->mark = DESC_IDLE;
- list_splice(&tx_list, &sh_chan->ld_free);
- spin_unlock_bh(&sh_chan->desc_lock);
- return NULL;
- }
-
- copy_size = min(len, (size_t)SH_DMA_TCR_MAX + 1);
-
- new->hw.sar = dma_src;
- new->hw.dar = dma_dest;
- new->hw.tcr = copy_size;
- if (!first) {
- /* First desc */
- new->async_tx.cookie = -EBUSY;
- first = new;
- } else {
- /* Other desc - invisible to the user */
- new->async_tx.cookie = -EINVAL;
- }
-
- dev_dbg(sh_chan->dev,
- "chaining %u of %u with %p, dst %x, cookie %d\n",
- copy_size, len, &new->async_tx, dma_dest,
- new->async_tx.cookie);
-
- new->mark = DESC_PREPARED;
- new->async_tx.flags = flags;
- new->chunks = chunks--;
-
- prev = new;
- len -= copy_size;
- dma_src += copy_size;
- dma_dest += copy_size;
- /* Insert the link descriptor to the LD ring */
- list_add_tail(&new->node, &tx_list);
- } while (len);
+ for_each_sg(sgl, sg, sg_len, i) {
+ dma_addr_t sg_addr = sg_dma_address(sg);
+ size_t len = sg_dma_len(sg);
+
+ if (!len)
+ goto err_get_desc;
+
+ do {
+ dev_dbg(sh_chan->dev, "Add SG #%d@%p[%d], dma %llx\n",
+ i, sg, len, (unsigned long long)sg_addr);
+
+ if (direction == DMA_FROM_DEVICE)
+ new = sh_dmae_add_desc(sh_chan, flags,
+ &sg_addr, addr, &len, &first,
+ direction);
+ else
+ new = sh_dmae_add_desc(sh_chan, flags,
+ addr, &sg_addr, &len, &first,
+ direction);
+ if (!new)
+ goto err_get_desc;
+
+ new->chunks = chunks--;
+ list_add_tail(&new->node, &tx_list);
+ } while (len);
+ }
if (new != first)
new->async_tx.cookie = -ENOSPC;
@@ -386,6 +517,90 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy(
spin_unlock_bh(&sh_chan->desc_lock);
return &first->async_tx;
+
+err_get_desc:
+ list_for_each_entry(new, &tx_list, node)
+ new->mark = DESC_IDLE;
+ list_splice(&tx_list, &sh_chan->ld_free);
+
+ spin_unlock_bh(&sh_chan->desc_lock);
+
+ return NULL;
+}
+
+static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy(
+ struct dma_chan *chan, dma_addr_t dma_dest, dma_addr_t dma_src,
+ size_t len, unsigned long flags)
+{
+ struct sh_dmae_chan *sh_chan;
+ struct scatterlist sg;
+
+ if (!chan || !len)
+ return NULL;
+
+ chan->private = NULL;
+
+ sh_chan = to_sh_chan(chan);
+
+ sg_init_table(&sg, 1);
+ sg_set_page(&sg, pfn_to_page(PFN_DOWN(dma_src)), len,
+ offset_in_page(dma_src));
+ sg_dma_address(&sg) = dma_src;
+ sg_dma_len(&sg) = len;
+
+ return sh_dmae_prep_sg(sh_chan, &sg, 1, &dma_dest, DMA_BIDIRECTIONAL,
+ flags);
+}
+
+static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len,
+ enum dma_data_direction direction, unsigned long flags)
+{
+ struct sh_dmae_slave *param;
+ struct sh_dmae_chan *sh_chan;
+
+ if (!chan)
+ return NULL;
+
+ sh_chan = to_sh_chan(chan);
+ param = chan->private;
+
+ /* Someone calling slave DMA on a public channel? */
+ if (!param || !sg_len) {
+ dev_warn(sh_chan->dev, "%s: bad parameter: %p, %d, %d\n",
+ __func__, param, sg_len, param ? param->slave_id : -1);
+ return NULL;
+ }
+
+ /*
+ * if (param != NULL), this is a successfully requested slave channel,
+ * therefore param->config != NULL too.
+ */
+ return sh_dmae_prep_sg(sh_chan, sgl, sg_len, &param->config->addr,
+ direction, flags);
+}
+
+static void sh_dmae_terminate_all(struct dma_chan *chan)
+{
+ struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
+
+ if (!chan)
+ return;
+
+ dmae_halt(sh_chan);
+
+ spin_lock_bh(&sh_chan->desc_lock);
+ if (!list_empty(&sh_chan->ld_queue)) {
+ /* Record partial transfer */
+ struct sh_desc *desc = list_entry(sh_chan->ld_queue.next,
+ struct sh_desc, node);
+ desc->partial = (desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) <<
+ sh_chan->xmit_shift;
+
+ }
+ spin_unlock_bh(&sh_chan->desc_lock);
+
+ sh_dmae_chan_ld_cleanup(sh_chan, true);
}
static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all)
@@ -419,7 +634,11 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all
cookie = tx->cookie;
if (desc->mark == DESC_COMPLETED && desc->chunks == 1) {
- BUG_ON(sh_chan->completed_cookie != desc->cookie - 1);
+ if (sh_chan->completed_cookie != desc->cookie - 1)
+ dev_dbg(sh_chan->dev,
+ "Completing cookie %d, expected %d\n",
+ desc->cookie,
+ sh_chan->completed_cookie + 1);
sh_chan->completed_cookie = desc->cookie;
}
@@ -483,7 +702,7 @@ static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all)
static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
{
- struct sh_desc *sd;
+ struct sh_desc *desc;
spin_lock_bh(&sh_chan->desc_lock);
/* DMA work check */
@@ -492,11 +711,14 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
return;
}
- /* Find the first un-transfer desciptor */
- list_for_each_entry(sd, &sh_chan->ld_queue, node)
- if (sd->mark == DESC_SUBMITTED) {
+ /* Find the first not transferred desciptor */
+ list_for_each_entry(desc, &sh_chan->ld_queue, node)
+ if (desc->mark == DESC_SUBMITTED) {
+ dev_dbg(sh_chan->dev, "Queue #%d to %d: %u@%x -> %x\n",
+ desc->async_tx.cookie, sh_chan->id,
+ desc->hw.tcr, desc->hw.sar, desc->hw.dar);
/* Get the ld start address from ld_queue */
- dmae_set_reg(sh_chan, &sd->hw);
+ dmae_set_reg(sh_chan, &desc->hw);
dmae_start(sh_chan);
break;
}
@@ -518,6 +740,7 @@ static enum dma_status sh_dmae_is_complete(struct dma_chan *chan,
struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
dma_cookie_t last_used;
dma_cookie_t last_complete;
+ enum dma_status status;
sh_dmae_chan_ld_cleanup(sh_chan, false);
@@ -531,7 +754,27 @@ static enum dma_status sh_dmae_is_complete(struct dma_chan *chan,
if (used)
*used = last_used;
- return dma_async_is_complete(cookie, last_complete, last_used);
+ spin_lock_bh(&sh_chan->desc_lock);
+
+ status = dma_async_is_complete(cookie, last_complete, last_used);
+
+ /*
+ * If we don't find cookie on the queue, it has been aborted and we have
+ * to report error
+ */
+ if (status != DMA_SUCCESS) {
+ struct sh_desc *desc;
+ status = DMA_ERROR;
+ list_for_each_entry(desc, &sh_chan->ld_queue, node)
+ if (desc->cookie == cookie) {
+ status = DMA_IN_PROGRESS;
+ break;
+ }
+ }
+
+ spin_unlock_bh(&sh_chan->desc_lock);
+
+ return status;
}
static irqreturn_t sh_dmae_interrupt(int irq, void *data)
@@ -554,40 +797,32 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data)
#if defined(CONFIG_CPU_SH4)
static irqreturn_t sh_dmae_err(int irq, void *data)
{
- int err = 0;
struct sh_dmae_device *shdev = (struct sh_dmae_device *)data;
+ int i;
- /* IRQ Multi */
- if (shdev->pdata.mode & SHDMA_MIX_IRQ) {
- int cnt = 0;
- switch (irq) {
-#if defined(DMTE6_IRQ) && defined(DMAE1_IRQ)
- case DMTE6_IRQ:
- cnt++;
-#endif
- case DMTE0_IRQ:
- if (dmaor_read_reg(cnt) & (DMAOR_NMIF | DMAOR_AE)) {
- disable_irq(irq);
- return IRQ_HANDLED;
+ /* halt the dma controller */
+ sh_dmae_ctl_stop(shdev);
+
+ /* We cannot detect, which channel caused the error, have to reset all */
+ for (i = 0; i < SH_DMAC_MAX_CHANNELS; i++) {
+ struct sh_dmae_chan *sh_chan = shdev->chan[i];
+ if (sh_chan) {
+ struct sh_desc *desc;
+ /* Stop the channel */
+ dmae_halt(sh_chan);
+ /* Complete all */
+ list_for_each_entry(desc, &sh_chan->ld_queue, node) {
+ struct dma_async_tx_descriptor *tx = &desc->async_tx;
+ desc->mark = DESC_IDLE;
+ if (tx->callback)
+ tx->callback(tx->callback_param);
}
- default:
- return IRQ_NONE;
- }
- } else {
- /* reset dma controller */
- err = sh_dmae_rst(0);
- if (err)
- return err;
-#ifdef SH_DMAC_BASE1
- if (shdev->pdata.mode & SHDMA_DMAOR1) {
- err = sh_dmae_rst(1);
- if (err)
- return err;
+ list_splice_init(&sh_chan->ld_queue, &sh_chan->ld_free);
}
-#endif
- disable_irq(irq);
- return IRQ_HANDLED;
}
+ sh_dmae_rst(shdev);
+
+ return IRQ_HANDLED;
}
#endif
@@ -596,11 +831,14 @@ static void dmae_do_tasklet(unsigned long data)
struct sh_dmae_chan *sh_chan = (struct sh_dmae_chan *)data;
struct sh_desc *desc;
u32 sar_buf = sh_dmae_readl(sh_chan, SAR);
+ u32 dar_buf = sh_dmae_readl(sh_chan, DAR);
spin_lock(&sh_chan->desc_lock);
list_for_each_entry(desc, &sh_chan->ld_queue, node) {
- if ((desc->hw.sar + desc->hw.tcr) == sar_buf &&
- desc->mark == DESC_SUBMITTED) {
+ if (desc->mark == DESC_SUBMITTED &&
+ ((desc->direction == DMA_FROM_DEVICE &&
+ (desc->hw.dar + desc->hw.tcr) == dar_buf) ||
+ (desc->hw.sar + desc->hw.tcr) == sar_buf)) {
dev_dbg(sh_chan->dev, "done #%d@%p dst %u\n",
desc->async_tx.cookie, &desc->async_tx,
desc->hw.dar);
@@ -615,19 +853,12 @@ static void dmae_do_tasklet(unsigned long data)
sh_dmae_chan_ld_cleanup(sh_chan, false);
}
-static unsigned int get_dmae_irq(unsigned int id)
-{
- unsigned int irq = 0;
- if (id < ARRAY_SIZE(dmte_irq_map))
- irq = dmte_irq_map[id];
- return irq;
-}
-
-static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id)
+static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
+ int irq, unsigned long flags)
{
int err;
- unsigned int irq = get_dmae_irq(id);
- unsigned long irqflags = IRQF_DISABLED;
+ struct sh_dmae_channel *chan_pdata = &shdev->pdata->channel[id];
+ struct platform_device *pdev = to_platform_device(shdev->common.dev);
struct sh_dmae_chan *new_sh_chan;
/* alloc channel */
@@ -638,8 +869,13 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id)
return -ENOMEM;
}
+ /* copy struct dma_device */
+ new_sh_chan->common.device = &shdev->common;
+
new_sh_chan->dev = shdev->common.dev;
new_sh_chan->id = id;
+ new_sh_chan->irq = irq;
+ new_sh_chan->base = shdev->chan_reg + chan_pdata->offset / sizeof(u32);
/* Init DMA tasklet */
tasklet_init(&new_sh_chan->tasklet, dmae_do_tasklet,
@@ -654,29 +890,20 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id)
INIT_LIST_HEAD(&new_sh_chan->ld_queue);
INIT_LIST_HEAD(&new_sh_chan->ld_free);
- /* copy struct dma_device */
- new_sh_chan->common.device = &shdev->common;
-
/* Add the channel to DMA device channel list */
list_add_tail(&new_sh_chan->common.device_node,
&shdev->common.channels);
shdev->common.chancnt++;
- if (shdev->pdata.mode & SHDMA_MIX_IRQ) {
- irqflags = IRQF_SHARED;
-#if defined(DMTE6_IRQ)
- if (irq >= DMTE6_IRQ)
- irq = DMTE6_IRQ;
- else
-#endif
- irq = DMTE0_IRQ;
- }
-
- snprintf(new_sh_chan->dev_id, sizeof(new_sh_chan->dev_id),
- "sh-dmae%d", new_sh_chan->id);
+ if (pdev->id >= 0)
+ snprintf(new_sh_chan->dev_id, sizeof(new_sh_chan->dev_id),
+ "sh-dmae%d.%d", pdev->id, new_sh_chan->id);
+ else
+ snprintf(new_sh_chan->dev_id, sizeof(new_sh_chan->dev_id),
+ "sh-dma%d", new_sh_chan->id);
/* set up channel irq */
- err = request_irq(irq, &sh_dmae_interrupt, irqflags,
+ err = request_irq(irq, &sh_dmae_interrupt, flags,
new_sh_chan->dev_id, new_sh_chan);
if (err) {
dev_err(shdev->common.dev, "DMA channel %d request_irq error "
@@ -684,11 +911,6 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id)
goto err_no_irq;
}
- /* CHCR register control function */
- new_sh_chan->set_chcr = dmae_set_chcr;
- /* DMARS register control function */
- new_sh_chan->set_dmars = dmae_set_dmars;
-
shdev->chan[id] = new_sh_chan;
return 0;
@@ -705,12 +927,12 @@ static void sh_dmae_chan_remove(struct sh_dmae_device *shdev)
for (i = shdev->common.chancnt - 1 ; i >= 0 ; i--) {
if (shdev->chan[i]) {
- struct sh_dmae_chan *shchan = shdev->chan[i];
- if (!(shdev->pdata.mode & SHDMA_MIX_IRQ))
- free_irq(dmte_irq_map[i], shchan);
+ struct sh_dmae_chan *sh_chan = shdev->chan[i];
- list_del(&shchan->common.device_node);
- kfree(shchan);
+ free_irq(sh_chan->irq, sh_chan);
+
+ list_del(&sh_chan->common.device_node);
+ kfree(sh_chan);
shdev->chan[i] = NULL;
}
}
@@ -719,85 +941,164 @@ static void sh_dmae_chan_remove(struct sh_dmae_device *shdev)
static int __init sh_dmae_probe(struct platform_device *pdev)
{
- int err = 0, cnt, ecnt;
- unsigned long irqflags = IRQF_DISABLED;
-#if defined(CONFIG_CPU_SH4)
- int eirq[] = { DMAE0_IRQ,
-#if defined(DMAE1_IRQ)
- DMAE1_IRQ
-#endif
- };
-#endif
+ struct sh_dmae_pdata *pdata = pdev->dev.platform_data;
+ unsigned long irqflags = IRQF_DISABLED,
+ chan_flag[SH_DMAC_MAX_CHANNELS] = {};
+ int errirq, chan_irq[SH_DMAC_MAX_CHANNELS];
+ int err, i, irq_cnt = 0, irqres = 0;
struct sh_dmae_device *shdev;
+ struct resource *chan, *dmars, *errirq_res, *chanirq_res;
/* get platform data */
- if (!pdev->dev.platform_data)
+ if (!pdata || !pdata->channel_num)
+ return -ENODEV;
+
+ chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ /* DMARS area is optional, if absent, this controller cannot do slave DMA */
+ dmars = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ /*
+ * IRQ resources:
+ * 1. there always must be at least one IRQ IO-resource. On SH4 it is
+ * the error IRQ, in which case it is the only IRQ in this resource:
+ * start == end. If it is the only IRQ resource, all channels also
+ * use the same IRQ.
+ * 2. DMA channel IRQ resources can be specified one per resource or in
+ * ranges (start != end)
+ * 3. iff all events (channels and, optionally, error) on this
+ * controller use the same IRQ, only one IRQ resource can be
+ * specified, otherwise there must be one IRQ per channel, even if
+ * some of them are equal
+ * 4. if all IRQs on this controller are equal or if some specific IRQs
+ * specify IORESOURCE_IRQ_SHAREABLE in their resources, they will be
+ * requested with the IRQF_SHARED flag
+ */
+ errirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!chan || !errirq_res)
return -ENODEV;
+ if (!request_mem_region(chan->start, resource_size(chan), pdev->name)) {
+ dev_err(&pdev->dev, "DMAC register region already claimed\n");
+ return -EBUSY;
+ }
+
+ if (dmars && !request_mem_region(dmars->start, resource_size(dmars), pdev->name)) {
+ dev_err(&pdev->dev, "DMAC DMARS region already claimed\n");
+ err = -EBUSY;
+ goto ermrdmars;
+ }
+
+ err = -ENOMEM;
shdev = kzalloc(sizeof(struct sh_dmae_device), GFP_KERNEL);
if (!shdev) {
- dev_err(&pdev->dev, "No enough memory\n");
- return -ENOMEM;
+ dev_err(&pdev->dev, "Not enough memory\n");
+ goto ealloc;
+ }
+
+ shdev->chan_reg = ioremap(chan->start, resource_size(chan));
+ if (!shdev->chan_reg)
+ goto emapchan;
+ if (dmars) {
+ shdev->dmars = ioremap(dmars->start, resource_size(dmars));
+ if (!shdev->dmars)
+ goto emapdmars;
}
/* platform data */
- memcpy(&shdev->pdata, pdev->dev.platform_data,
- sizeof(struct sh_dmae_pdata));
+ shdev->pdata = pdata;
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
/* reset dma controller */
- err = sh_dmae_rst(0);
+ err = sh_dmae_rst(shdev);
if (err)
goto rst_err;
- /* SH7780/85/23 has DMAOR1 */
- if (shdev->pdata.mode & SHDMA_DMAOR1) {
- err = sh_dmae_rst(1);
- if (err)
- goto rst_err;
- }
-
INIT_LIST_HEAD(&shdev->common.channels);
dma_cap_set(DMA_MEMCPY, shdev->common.cap_mask);
+ if (dmars)
+ dma_cap_set(DMA_SLAVE, shdev->common.cap_mask);
+
shdev->common.device_alloc_chan_resources
= sh_dmae_alloc_chan_resources;
shdev->common.device_free_chan_resources = sh_dmae_free_chan_resources;
shdev->common.device_prep_dma_memcpy = sh_dmae_prep_memcpy;
shdev->common.device_is_tx_complete = sh_dmae_is_complete;
shdev->common.device_issue_pending = sh_dmae_memcpy_issue_pending;
+
+ /* Compulsory for DMA_SLAVE fields */
+ shdev->common.device_prep_slave_sg = sh_dmae_prep_slave_sg;
+ shdev->common.device_terminate_all = sh_dmae_terminate_all;
+
shdev->common.dev = &pdev->dev;
/* Default transfer size of 32 bytes requires 32-byte alignment */
- shdev->common.copy_align = 5;
+ shdev->common.copy_align = LOG2_DEFAULT_XFER_SIZE;
#if defined(CONFIG_CPU_SH4)
- /* Non Mix IRQ mode SH7722/SH7730 etc... */
- if (shdev->pdata.mode & SHDMA_MIX_IRQ) {
+ chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+
+ if (!chanirq_res)
+ chanirq_res = errirq_res;
+ else
+ irqres++;
+
+ if (chanirq_res == errirq_res ||
+ (errirq_res->flags & IORESOURCE_BITS) == IORESOURCE_IRQ_SHAREABLE)
irqflags = IRQF_SHARED;
- eirq[0] = DMTE0_IRQ;
-#if defined(DMTE6_IRQ) && defined(DMAE1_IRQ)
- eirq[1] = DMTE6_IRQ;
-#endif
+
+ errirq = errirq_res->start;
+
+ err = request_irq(errirq, sh_dmae_err, irqflags,
+ "DMAC Address Error", shdev);
+ if (err) {
+ dev_err(&pdev->dev,
+ "DMA failed requesting irq #%d, error %d\n",
+ errirq, err);
+ goto eirq_err;
}
- for (ecnt = 0 ; ecnt < ARRAY_SIZE(eirq); ecnt++) {
- err = request_irq(eirq[ecnt], sh_dmae_err, irqflags,
- "DMAC Address Error", shdev);
- if (err) {
- dev_err(&pdev->dev, "DMA device request_irq"
- "error (irq %d) with return %d\n",
- eirq[ecnt], err);
- goto eirq_err;
+#else
+ chanirq_res = errirq_res;
+#endif /* CONFIG_CPU_SH4 */
+
+ if (chanirq_res->start == chanirq_res->end &&
+ !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) {
+ /* Special case - all multiplexed */
+ for (; irq_cnt < pdata->channel_num; irq_cnt++) {
+ chan_irq[irq_cnt] = chanirq_res->start;
+ chan_flag[irq_cnt] = IRQF_SHARED;
}
+ } else {
+ do {
+ for (i = chanirq_res->start; i <= chanirq_res->end; i++) {
+ if ((errirq_res->flags & IORESOURCE_BITS) ==
+ IORESOURCE_IRQ_SHAREABLE)
+ chan_flag[irq_cnt] = IRQF_SHARED;
+ else
+ chan_flag[irq_cnt] = IRQF_DISABLED;
+ dev_dbg(&pdev->dev,
+ "Found IRQ %d for channel %d\n",
+ i, irq_cnt);
+ chan_irq[irq_cnt++] = i;
+ }
+ chanirq_res = platform_get_resource(pdev,
+ IORESOURCE_IRQ, ++irqres);
+ } while (irq_cnt < pdata->channel_num && chanirq_res);
}
-#endif /* CONFIG_CPU_SH4 */
+
+ if (irq_cnt < pdata->channel_num)
+ goto eirqres;
/* Create DMA Channel */
- for (cnt = 0 ; cnt < MAX_DMA_CHANNELS ; cnt++) {
- err = sh_dmae_chan_probe(shdev, cnt);
+ for (i = 0; i < pdata->channel_num; i++) {
+ err = sh_dmae_chan_probe(shdev, i, chan_irq[i], chan_flag[i]);
if (err)
goto chan_probe_err;
}
+ pm_runtime_put(&pdev->dev);
+
platform_set_drvdata(pdev, shdev);
dma_async_device_register(&shdev->common);
@@ -805,13 +1106,24 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
chan_probe_err:
sh_dmae_chan_remove(shdev);
-
+eirqres:
+#if defined(CONFIG_CPU_SH4)
+ free_irq(errirq, shdev);
eirq_err:
- for (ecnt-- ; ecnt >= 0; ecnt--)
- free_irq(eirq[ecnt], shdev);
-
+#endif
rst_err:
+ pm_runtime_put(&pdev->dev);
+ if (dmars)
+ iounmap(shdev->dmars);
+emapdmars:
+ iounmap(shdev->chan_reg);
+emapchan:
kfree(shdev);
+ealloc:
+ if (dmars)
+ release_mem_region(dmars->start, resource_size(dmars));
+ermrdmars:
+ release_mem_region(chan->start, resource_size(chan));
return err;
}
@@ -819,36 +1131,39 @@ rst_err:
static int __exit sh_dmae_remove(struct platform_device *pdev)
{
struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
+ struct resource *res;
+ int errirq = platform_get_irq(pdev, 0);
dma_async_device_unregister(&shdev->common);
- if (shdev->pdata.mode & SHDMA_MIX_IRQ) {
- free_irq(DMTE0_IRQ, shdev);
-#if defined(DMTE6_IRQ)
- free_irq(DMTE6_IRQ, shdev);
-#endif
- }
+ if (errirq > 0)
+ free_irq(errirq, shdev);
/* channel data remove */
sh_dmae_chan_remove(shdev);
- if (!(shdev->pdata.mode & SHDMA_MIX_IRQ)) {
- free_irq(DMAE0_IRQ, shdev);
-#if defined(DMAE1_IRQ)
- free_irq(DMAE1_IRQ, shdev);
-#endif
- }
+ pm_runtime_disable(&pdev->dev);
+
+ if (shdev->dmars)
+ iounmap(shdev->dmars);
+ iounmap(shdev->chan_reg);
+
kfree(shdev);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+
return 0;
}
static void sh_dmae_shutdown(struct platform_device *pdev)
{
struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
- sh_dmae_ctl_stop(0);
- if (shdev->pdata.mode & SHDMA_DMAOR1)
- sh_dmae_ctl_stop(1);
+ sh_dmae_ctl_stop(shdev);
}
static struct platform_driver sh_dmae_driver = {
diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
index 108f1cffb6f5..153609a1e96c 100644
--- a/drivers/dma/shdma.h
+++ b/drivers/dma/shdma.h
@@ -17,22 +17,9 @@
#include <linux/interrupt.h>
#include <linux/list.h>
-#define SH_DMA_TCR_MAX 0x00FFFFFF /* 16MB */
-
-struct sh_dmae_regs {
- u32 sar; /* SAR / source address */
- u32 dar; /* DAR / destination address */
- u32 tcr; /* TCR / transfer count */
-};
+#include <asm/dmaengine.h>
-struct sh_desc {
- struct sh_dmae_regs hw;
- struct list_head node;
- struct dma_async_tx_descriptor async_tx;
- dma_cookie_t cookie;
- int chunks;
- int mark;
-};
+#define SH_DMA_TCR_MAX 0x00FFFFFF /* 16MB */
struct device;
@@ -45,19 +32,19 @@ struct sh_dmae_chan {
struct device *dev; /* Channel device */
struct tasklet_struct tasklet; /* Tasklet */
int descs_allocated; /* desc count */
+ int xmit_shift; /* log_2(bytes_per_xfer) */
+ int irq;
int id; /* Raw id of this channel */
+ u32 __iomem *base;
char dev_id[16]; /* unique name per DMAC of channel */
-
- /* Set chcr */
- int (*set_chcr)(struct sh_dmae_chan *sh_chan, u32 regs);
- /* Set DMA resource */
- int (*set_dmars)(struct sh_dmae_chan *sh_chan, u16 res);
};
struct sh_dmae_device {
struct dma_device common;
- struct sh_dmae_chan *chan[MAX_DMA_CHANNELS];
- struct sh_dmae_pdata pdata;
+ struct sh_dmae_chan *chan[SH_DMAC_MAX_CHANNELS];
+ struct sh_dmae_pdata *pdata;
+ u32 __iomem *chan_reg;
+ u16 __iomem *dmars;
};
#define to_sh_chan(chan) container_of(chan, struct sh_dmae_chan, common)
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index c5facd951dda..cf17dbb8014f 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -13,7 +13,7 @@ module_param(report_gart_errors, int, 0644);
static int ecc_enable_override;
module_param(ecc_enable_override, int, 0644);
-static struct msr *msrs;
+static struct msr __percpu *msrs;
/* Lookup table for all possible MC control instances */
struct amd64_pvt;
@@ -197,7 +197,7 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
edac_printk(KERN_DEBUG, EDAC_MC,
"pci-read, sdram scrub control value: %d \n", scrubval);
- for (i = 0; ARRAY_SIZE(scrubrates); i++) {
+ for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
if (scrubrates[i].scrubval == scrubval) {
*bw = scrubrates[i].bandwidth;
status = 0;
@@ -2553,14 +2553,14 @@ static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on)
if (on) {
if (reg->l & K8_MSR_MCGCTL_NBE)
- pvt->flags.ecc_report = 1;
+ pvt->flags.nb_mce_enable = 1;
reg->l |= K8_MSR_MCGCTL_NBE;
} else {
/*
- * Turn off ECC reporting only when it was off before
+ * Turn off NB MCE reporting only when it was off before
*/
- if (!pvt->flags.ecc_report)
+ if (!pvt->flags.nb_mce_enable)
reg->l &= ~K8_MSR_MCGCTL_NBE;
}
}
@@ -2571,22 +2571,11 @@ static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on)
return 0;
}
-/*
- * Only if 'ecc_enable_override' is set AND BIOS had ECC disabled, do "we"
- * enable it.
- */
static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci)
{
struct amd64_pvt *pvt = mci->pvt_info;
u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn;
- if (!ecc_enable_override)
- return;
-
- amd64_printk(KERN_WARNING,
- "'ecc_enable_override' parameter is active, "
- "Enabling AMD ECC hardware now: CAUTION\n");
-
amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCTL, &value);
/* turn on UECCn and CECCEn bits */
@@ -2611,6 +2600,8 @@ static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci)
"This node reports that DRAM ECC is "
"currently Disabled; ENABLING now\n");
+ pvt->flags.nb_ecc_prev = 0;
+
/* Attempt to turn on DRAM ECC Enable */
value |= K8_NBCFG_ECC_ENABLE;
pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCFG, value);
@@ -2625,7 +2616,10 @@ static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci)
amd64_printk(KERN_DEBUG,
"Hardware accepted DRAM ECC Enable\n");
}
+ } else {
+ pvt->flags.nb_ecc_prev = 1;
}
+
debugf0("NBCFG(2)= 0x%x CHIPKILL= %s ECC_ENABLE= %s\n", value,
(value & K8_NBCFG_CHIPKILL) ? "Enabled" : "Disabled",
(value & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled");
@@ -2644,12 +2638,18 @@ static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt)
value &= ~mask;
value |= pvt->old_nbctl;
- /* restore the NB Enable MCGCTL bit */
pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value);
+ /* restore previous BIOS DRAM ECC "off" setting which we force-enabled */
+ if (!pvt->flags.nb_ecc_prev) {
+ amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCFG, &value);
+ value &= ~K8_NBCFG_ECC_ENABLE;
+ pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCFG, value);
+ }
+
+ /* restore the NB Enable MCGCTL bit */
if (amd64_toggle_ecc_err_reporting(pvt, OFF))
- amd64_printk(KERN_WARNING, "Error restoring ECC reporting over "
- "MCGCTL!\n");
+ amd64_printk(KERN_WARNING, "Error restoring NB MCGCTL settings!\n");
}
/*
@@ -2658,10 +2658,11 @@ static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt)
* the memory system completely. A command line option allows to force-enable
* hardware ECC later in amd64_enable_ecc_error_reporting().
*/
-static const char *ecc_warning =
- "WARNING: ECC is disabled by BIOS. Module will NOT be loaded.\n"
- " Either Enable ECC in the BIOS, or set 'ecc_enable_override'.\n"
- " Also, use of the override can cause unknown side effects.\n";
+static const char *ecc_msg =
+ "ECC disabled in the BIOS or no ECC capability, module will not load.\n"
+ " Either enable ECC checking or force module loading by setting "
+ "'ecc_enable_override'.\n"
+ " (Note that use of the override may cause unknown side effects.)\n";
static int amd64_check_ecc_enabled(struct amd64_pvt *pvt)
{
@@ -2673,7 +2674,7 @@ static int amd64_check_ecc_enabled(struct amd64_pvt *pvt)
ecc_enabled = !!(value & K8_NBCFG_ECC_ENABLE);
if (!ecc_enabled)
- amd64_printk(KERN_WARNING, "This node reports that Memory ECC "
+ amd64_printk(KERN_NOTICE, "This node reports that Memory ECC "
"is currently disabled, set F3x%x[22] (%s).\n",
K8_NBCFG, pci_name(pvt->misc_f3_ctl));
else
@@ -2681,16 +2682,17 @@ static int amd64_check_ecc_enabled(struct amd64_pvt *pvt)
nb_mce_en = amd64_nb_mce_bank_enabled_on_node(pvt->mc_node_id);
if (!nb_mce_en)
- amd64_printk(KERN_WARNING, "NB MCE bank disabled, set MSR "
+ amd64_printk(KERN_NOTICE, "NB MCE bank disabled, set MSR "
"0x%08x[4] on node %d to enable.\n",
MSR_IA32_MCG_CTL, pvt->mc_node_id);
if (!ecc_enabled || !nb_mce_en) {
if (!ecc_enable_override) {
- amd64_printk(KERN_WARNING, "%s", ecc_warning);
+ amd64_printk(KERN_NOTICE, "%s", ecc_msg);
return -ENODEV;
+ } else {
+ amd64_printk(KERN_WARNING, "Forcing ECC checking on!\n");
}
- ecc_enable_override = 0;
}
return 0;
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 41bc561e5981..0d4bf5638243 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -487,7 +487,8 @@ struct amd64_pvt {
/* misc settings */
struct flags {
unsigned long cf8_extcfg:1;
- unsigned long ecc_report:1;
+ unsigned long nb_mce_enable:1;
+ unsigned long nb_ecc_prev:1;
} flags;
};
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index d205d493a68a..243e9aacad69 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -75,6 +75,14 @@ static struct edac_pci_ctl_info *e752x_pci;
#define E752X_NR_CSROWS 8 /* number of csrows */
/* E752X register addresses - device 0 function 0 */
+#define E752X_MCHSCRB 0x52 /* Memory Scrub register (16b) */
+ /*
+ * 6:5 Scrub Completion Count
+ * 3:2 Scrub Rate (i3100 only)
+ * 01=fast 10=normal
+ * 1:0 Scrub Mode enable
+ * 00=off 10=on
+ */
#define E752X_DRB 0x60 /* DRAM row boundary register (8b) */
#define E752X_DRA 0x70 /* DRAM row attribute register (8b) */
/*
@@ -240,6 +248,41 @@ static const struct e752x_dev_info e752x_devs[] = {
.ctl_name = "3100"},
};
+/* Valid scrub rates for the e752x/3100 hardware memory scrubber. We
+ * map the scrubbing bandwidth to a hardware register value. The 'set'
+ * operation finds the 'matching or higher value'. Note that scrubbing
+ * on the e752x can only be enabled/disabled. The 3100 supports
+ * a normal and fast mode.
+ */
+
+#define SDRATE_EOT 0xFFFFFFFF
+
+struct scrubrate {
+ u32 bandwidth; /* bandwidth consumed by scrubbing in bytes/sec */
+ u16 scrubval; /* register value for scrub rate */
+};
+
+/* Rate below assumes same performance as i3100 using PC3200 DDR2 in
+ * normal mode. e752x bridges don't support choosing normal or fast mode,
+ * so the scrubbing bandwidth value isn't all that important - scrubbing is
+ * either on or off.
+ */
+static const struct scrubrate scrubrates_e752x[] = {
+ {0, 0x00}, /* Scrubbing Off */
+ {500000, 0x02}, /* Scrubbing On */
+ {SDRATE_EOT, 0x00} /* End of Table */
+};
+
+/* Fast mode: 2 GByte PC3200 DDR2 scrubbed in 33s = 63161283 bytes/s
+ * Normal mode: 125 (32000 / 256) times slower than fast mode.
+ */
+static const struct scrubrate scrubrates_i3100[] = {
+ {0, 0x00}, /* Scrubbing Off */
+ {500000, 0x0a}, /* Normal mode - 32k clocks */
+ {62500000, 0x06}, /* Fast mode - 256 clocks */
+ {SDRATE_EOT, 0x00} /* End of Table */
+};
+
static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
unsigned long page)
{
@@ -915,6 +958,68 @@ static void e752x_check(struct mem_ctl_info *mci)
e752x_process_error_info(mci, &info, 1);
}
+/* Program byte/sec bandwidth scrub rate to hardware */
+static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *new_bw)
+{
+ const struct scrubrate *scrubrates;
+ struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+ struct pci_dev *pdev = pvt->dev_d0f0;
+ int i;
+
+ if (pvt->dev_info->ctl_dev == PCI_DEVICE_ID_INTEL_3100_0)
+ scrubrates = scrubrates_i3100;
+ else
+ scrubrates = scrubrates_e752x;
+
+ /* Translate the desired scrub rate to a e752x/3100 register value.
+ * Search for the bandwidth that is equal or greater than the
+ * desired rate and program the cooresponding register value.
+ */
+ for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++)
+ if (scrubrates[i].bandwidth >= *new_bw)
+ break;
+
+ if (scrubrates[i].bandwidth == SDRATE_EOT)
+ return -1;
+
+ pci_write_config_word(pdev, E752X_MCHSCRB, scrubrates[i].scrubval);
+
+ return 0;
+}
+
+/* Convert current scrub rate value into byte/sec bandwidth */
+static int get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
+{
+ const struct scrubrate *scrubrates;
+ struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+ struct pci_dev *pdev = pvt->dev_d0f0;
+ u16 scrubval;
+ int i;
+
+ if (pvt->dev_info->ctl_dev == PCI_DEVICE_ID_INTEL_3100_0)
+ scrubrates = scrubrates_i3100;
+ else
+ scrubrates = scrubrates_e752x;
+
+ /* Find the bandwidth matching the memory scrubber configuration */
+ pci_read_config_word(pdev, E752X_MCHSCRB, &scrubval);
+ scrubval = scrubval & 0x0f;
+
+ for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++)
+ if (scrubrates[i].scrubval == scrubval)
+ break;
+
+ if (scrubrates[i].bandwidth == SDRATE_EOT) {
+ e752x_printk(KERN_WARNING,
+ "Invalid sdram scrub control value: 0x%x\n", scrubval);
+ return -1;
+ }
+
+ *bw = scrubrates[i].bandwidth;
+
+ return 0;
+}
+
/* Return 1 if dual channel mode is active. Else return 0. */
static inline int dual_channel_active(u16 ddrcsr)
{
@@ -1073,10 +1178,7 @@ fail:
/* Setup system bus parity mask register.
* Sysbus parity supported on:
- * e7320/e7520/e7525 + Xeon
- * i3100 + Xeon/Celeron
- * Sysbus parity not supported on:
- * i3100 + Pentium M/Celeron M/Core Duo/Core2 Duo
+ * e7320/e7520/e7525 + Xeon
*/
static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt)
{
@@ -1087,10 +1189,7 @@ static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt)
/* Allow module parameter override, else see if CPU supports parity */
if (sysbus_parity != -1) {
enable = sysbus_parity;
- } else if (cpu_id[0] &&
- ((strstr(cpu_id, "Pentium") && strstr(cpu_id, " M ")) ||
- (strstr(cpu_id, "Celeron") && strstr(cpu_id, " M ")) ||
- (strstr(cpu_id, "Core") && strstr(cpu_id, "Duo")))) {
+ } else if (cpu_id[0] && !strstr(cpu_id, "Xeon")) {
e752x_printk(KERN_INFO, "System Bus Parity not "
"supported by CPU, disabling\n");
enable = 0;
@@ -1187,6 +1286,8 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
mci->dev_name = pci_name(pdev);
mci->edac_check = e752x_check;
mci->ctl_page_to_phys = ctl_page_to_phys;
+ mci->set_sdram_scrub_rate = set_sdram_scrub_rate;
+ mci->get_sdram_scrub_rate = get_sdram_scrub_rate;
/* set the map type. 1 = normal, 0 = reversed
* Must be set before e752x_init_csrows in case csrow mapping
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
index 53764577035f..5fdedbc0f545 100644
--- a/drivers/edac/edac_device_sysfs.c
+++ b/drivers/edac/edac_device_sysfs.c
@@ -137,7 +137,7 @@ static ssize_t edac_dev_ctl_info_store(struct kobject *kobj,
}
/* edac_dev file operations for an 'ctl_info' */
-static struct sysfs_ops device_ctl_info_ops = {
+static const struct sysfs_ops device_ctl_info_ops = {
.show = edac_dev_ctl_info_show,
.store = edac_dev_ctl_info_store
};
@@ -373,7 +373,7 @@ static ssize_t edac_dev_instance_store(struct kobject *kobj,
}
/* edac_dev file operations for an 'instance' */
-static struct sysfs_ops device_instance_ops = {
+static const struct sysfs_ops device_instance_ops = {
.show = edac_dev_instance_show,
.store = edac_dev_instance_store
};
@@ -476,7 +476,7 @@ static ssize_t edac_dev_block_store(struct kobject *kobj,
}
/* edac_dev file operations for a 'block' */
-static struct sysfs_ops device_block_ops = {
+static const struct sysfs_ops device_block_ops = {
.show = edac_dev_block_show,
.store = edac_dev_block_store
};
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index e1d4ce083481..88840e9fa3e0 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -245,7 +245,7 @@ static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
return -EIO;
}
-static struct sysfs_ops csrowfs_ops = {
+static const struct sysfs_ops csrowfs_ops = {
.show = csrowdev_show,
.store = csrowdev_store
};
@@ -575,7 +575,7 @@ static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
}
/* Intermediate show/store table */
-static struct sysfs_ops mci_ops = {
+static const struct sysfs_ops mci_ops = {
.show = mcidev_show,
.store = mcidev_store
};
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
index fb60a877d768..bef94e3d9944 100644
--- a/drivers/edac/edac_pci_sysfs.c
+++ b/drivers/edac/edac_pci_sysfs.c
@@ -121,7 +121,7 @@ static ssize_t edac_pci_instance_store(struct kobject *kobj,
}
/* fs_ops table */
-static struct sysfs_ops pci_instance_ops = {
+static const struct sysfs_ops pci_instance_ops = {
.show = edac_pci_instance_show,
.store = edac_pci_instance_store
};
@@ -261,7 +261,7 @@ static ssize_t edac_pci_dev_store(struct kobject *kobj,
return -EIO;
}
-static struct sysfs_ops edac_pci_sysfs_ops = {
+static const struct sysfs_ops edac_pci_sysfs_ops = {
.show = edac_pci_dev_show,
.store = edac_pci_dev_store
};
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 77a9579d7167..adc10a2ac5f6 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -577,7 +577,13 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
debugf0("\tUncorrected bits= 0x%x\n", ue_errors);
branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
- channel = branch;
+
+ /*
+ * According with i5000 datasheet, bit 28 has no significance
+ * for errors M4Err-M12Err and M17Err-M21Err, on FERR_NF_FBD
+ */
+ channel = branch & 2;
+
bank = NREC_BANK(info->nrecmema);
rank = NREC_RANK(info->nrecmema);
rdwr = NREC_RDWR(info->nrecmema);
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index cf27402af97b..94cac0aacea3 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -239,16 +239,15 @@ static int __devinit mpc85xx_pci_err_probe(struct of_device *op,
/* we only need the error registers */
r.start += 0xe00;
- if (!devm_request_mem_region(&op->dev, r.start,
- r.end - r.start + 1, pdata->name)) {
+ if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
+ pdata->name)) {
printk(KERN_ERR "%s: Error while requesting mem region\n",
__func__);
res = -EBUSY;
goto err;
}
- pdata->pci_vbase = devm_ioremap(&op->dev, r.start,
- r.end - r.start + 1);
+ pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));
if (!pdata->pci_vbase) {
printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
res = -ENOMEM;
@@ -668,15 +667,125 @@ static struct of_platform_driver mpc85xx_l2_err_driver = {
/**************************** MC Err device ***************************/
+/*
+ * Taken from table 8-55 in the MPC8641 User's Manual and/or 9-61 in the
+ * MPC8572 User's Manual. Each line represents a syndrome bit column as a
+ * 64-bit value, but split into an upper and lower 32-bit chunk. The labels
+ * below correspond to Freescale's manuals.
+ */
+static unsigned int ecc_table[16] = {
+ /* MSB LSB */
+ /* [0:31] [32:63] */
+ 0xf00fe11e, 0xc33c0ff7, /* Syndrome bit 7 */
+ 0x00ff00ff, 0x00fff0ff,
+ 0x0f0f0f0f, 0x0f0fff00,
+ 0x11113333, 0x7777000f,
+ 0x22224444, 0x8888222f,
+ 0x44448888, 0xffff4441,
+ 0x8888ffff, 0x11118882,
+ 0xffff1111, 0x22221114, /* Syndrome bit 0 */
+};
+
+/*
+ * Calculate the correct ECC value for a 64-bit value specified by high:low
+ */
+static u8 calculate_ecc(u32 high, u32 low)
+{
+ u32 mask_low;
+ u32 mask_high;
+ int bit_cnt;
+ u8 ecc = 0;
+ int i;
+ int j;
+
+ for (i = 0; i < 8; i++) {
+ mask_high = ecc_table[i * 2];
+ mask_low = ecc_table[i * 2 + 1];
+ bit_cnt = 0;
+
+ for (j = 0; j < 32; j++) {
+ if ((mask_high >> j) & 1)
+ bit_cnt ^= (high >> j) & 1;
+ if ((mask_low >> j) & 1)
+ bit_cnt ^= (low >> j) & 1;
+ }
+
+ ecc |= bit_cnt << i;
+ }
+
+ return ecc;
+}
+
+/*
+ * Create the syndrome code which is generated if the data line specified by
+ * 'bit' failed. Eg generate an 8-bit codes seen in Table 8-55 in the MPC8641
+ * User's Manual and 9-61 in the MPC8572 User's Manual.
+ */
+static u8 syndrome_from_bit(unsigned int bit) {
+ int i;
+ u8 syndrome = 0;
+
+ /*
+ * Cycle through the upper or lower 32-bit portion of each value in
+ * ecc_table depending on if 'bit' is in the upper or lower half of
+ * 64-bit data.
+ */
+ for (i = bit < 32; i < 16; i += 2)
+ syndrome |= ((ecc_table[i] >> (bit % 32)) & 1) << (i / 2);
+
+ return syndrome;
+}
+
+/*
+ * Decode data and ecc syndrome to determine what went wrong
+ * Note: This can only decode single-bit errors
+ */
+static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc,
+ int *bad_data_bit, int *bad_ecc_bit)
+{
+ int i;
+ u8 syndrome;
+
+ *bad_data_bit = -1;
+ *bad_ecc_bit = -1;
+
+ /*
+ * Calculate the ECC of the captured data and XOR it with the captured
+ * ECC to find an ECC syndrome value we can search for
+ */
+ syndrome = calculate_ecc(cap_high, cap_low) ^ cap_ecc;
+
+ /* Check if a data line is stuck... */
+ for (i = 0; i < 64; i++) {
+ if (syndrome == syndrome_from_bit(i)) {
+ *bad_data_bit = i;
+ return;
+ }
+ }
+
+ /* If data is correct, check ECC bits for errors... */
+ for (i = 0; i < 8; i++) {
+ if ((syndrome >> i) & 0x1) {
+ *bad_ecc_bit = i;
+ return;
+ }
+ }
+}
+
static void mpc85xx_mc_check(struct mem_ctl_info *mci)
{
struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
struct csrow_info *csrow;
+ u32 bus_width;
u32 err_detect;
u32 syndrome;
u32 err_addr;
u32 pfn;
int row_index;
+ u32 cap_high;
+ u32 cap_low;
+ int bad_data_bit;
+ int bad_ecc_bit;
err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT);
if (!err_detect)
@@ -692,6 +801,15 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
}
syndrome = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ECC);
+
+ /* Mask off appropriate bits of syndrome based on bus width */
+ bus_width = (in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG) &
+ DSC_DBW_MASK) ? 32 : 64;
+ if (bus_width == 64)
+ syndrome &= 0xff;
+ else
+ syndrome &= 0xffff;
+
err_addr = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS);
pfn = err_addr >> PAGE_SHIFT;
@@ -701,14 +819,35 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
break;
}
- mpc85xx_mc_printk(mci, KERN_ERR, "Capture Data High: %#8.8x\n",
- in_be32(pdata->mc_vbase +
- MPC85XX_MC_CAPTURE_DATA_HI));
- mpc85xx_mc_printk(mci, KERN_ERR, "Capture Data Low: %#8.8x\n",
- in_be32(pdata->mc_vbase +
- MPC85XX_MC_CAPTURE_DATA_LO));
- mpc85xx_mc_printk(mci, KERN_ERR, "syndrome: %#8.8x\n", syndrome);
- mpc85xx_mc_printk(mci, KERN_ERR, "err addr: %#8.8x\n", err_addr);
+ cap_high = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_HI);
+ cap_low = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_LO);
+
+ /*
+ * Analyze single-bit errors on 64-bit wide buses
+ * TODO: Add support for 32-bit wide buses
+ */
+ if ((err_detect & DDR_EDE_SBE) && (bus_width == 64)) {
+ sbe_ecc_decode(cap_high, cap_low, syndrome,
+ &bad_data_bit, &bad_ecc_bit);
+
+ if (bad_data_bit != -1)
+ mpc85xx_mc_printk(mci, KERN_ERR,
+ "Faulty Data bit: %d\n", bad_data_bit);
+ if (bad_ecc_bit != -1)
+ mpc85xx_mc_printk(mci, KERN_ERR,
+ "Faulty ECC bit: %d\n", bad_ecc_bit);
+
+ mpc85xx_mc_printk(mci, KERN_ERR,
+ "Expected Data / ECC:\t%#8.8x_%08x / %#2.2x\n",
+ cap_high ^ (1 << (bad_data_bit - 32)),
+ cap_low ^ (1 << bad_data_bit),
+ syndrome ^ (1 << bad_ecc_bit));
+ }
+
+ mpc85xx_mc_printk(mci, KERN_ERR,
+ "Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n",
+ cap_high, cap_low, syndrome);
+ mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8x\n", err_addr);
mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn);
/* we are out of range */
@@ -804,8 +943,8 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
end <<= (24 - PAGE_SHIFT);
end |= (1 << (24 - PAGE_SHIFT)) - 1;
- csrow->first_page = start >> PAGE_SHIFT;
- csrow->last_page = end >> PAGE_SHIFT;
+ csrow->first_page = start;
+ csrow->last_page = end;
csrow->nr_pages = end + 1 - start;
csrow->grain = 8;
csrow->mtype = mtype;
@@ -892,10 +1031,6 @@ static int __devinit mpc85xx_mc_err_probe(struct of_device *op,
mpc85xx_init_csrows(mci);
-#ifdef CONFIG_EDAC_DEBUG
- edac_mc_register_mcidev_debug((struct attribute **)debug_attr);
-#endif
-
/* store the original error disable bits */
orig_ddr_err_disable =
in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE);
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h
index 52432ee7c4b9..cb24df839460 100644
--- a/drivers/edac/mpc85xx_edac.h
+++ b/drivers/edac/mpc85xx_edac.h
@@ -48,6 +48,9 @@
#define DSC_MEM_EN 0x80000000
#define DSC_ECC_EN 0x20000000
#define DSC_RD_EN 0x10000000
+#define DSC_DBW_MASK 0x00180000
+#define DSC_DBW_32 0x00080000
+#define DSC_DBW_64 0x00000000
#define DSC_SDTYPE_MASK 0x07000000
diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
index 66958b3f10b4..806c77bfd434 100644
--- a/drivers/eisa/eisa-bus.c
+++ b/drivers/eisa/eisa-bus.c
@@ -39,10 +39,10 @@ static unsigned int enable_dev_count;
static int disable_dev[EISA_MAX_FORCED_DEV];
static unsigned int disable_dev_count;
-static int is_forced_dev (int *forced_tab,
- int forced_count,
- struct eisa_root_device *root,
- struct eisa_device *edev)
+static int is_forced_dev(int *forced_tab,
+ int forced_count,
+ struct eisa_root_device *root,
+ struct eisa_device *edev)
{
int i, x;
@@ -55,21 +55,21 @@ static int is_forced_dev (int *forced_tab,
return 0;
}
-static void __init eisa_name_device (struct eisa_device *edev)
+static void __init eisa_name_device(struct eisa_device *edev)
{
#ifdef CONFIG_EISA_NAMES
int i;
for (i = 0; i < EISA_INFOS; i++) {
- if (!strcmp (edev->id.sig, eisa_table[i].id.sig)) {
- strlcpy (edev->pretty_name,
- eisa_table[i].name,
- sizeof(edev->pretty_name));
+ if (!strcmp(edev->id.sig, eisa_table[i].id.sig)) {
+ strlcpy(edev->pretty_name,
+ eisa_table[i].name,
+ sizeof(edev->pretty_name));
return;
}
}
/* No name was found */
- sprintf (edev->pretty_name, "EISA device %.7s", edev->id.sig);
+ sprintf(edev->pretty_name, "EISA device %.7s", edev->id.sig);
#endif
}
@@ -91,7 +91,7 @@ static char __init *decode_eisa_sig(unsigned long addr)
*/
outb(0x80 + i, addr);
#endif
- sig[i] = inb (addr + i);
+ sig[i] = inb(addr + i);
if (!i && (sig[0] & 0x80))
return NULL;
@@ -106,17 +106,17 @@ static char __init *decode_eisa_sig(unsigned long addr)
return sig_str;
}
-static int eisa_bus_match (struct device *dev, struct device_driver *drv)
+static int eisa_bus_match(struct device *dev, struct device_driver *drv)
{
- struct eisa_device *edev = to_eisa_device (dev);
- struct eisa_driver *edrv = to_eisa_driver (drv);
+ struct eisa_device *edev = to_eisa_device(dev);
+ struct eisa_driver *edrv = to_eisa_driver(drv);
const struct eisa_device_id *eids = edrv->id_table;
if (!eids)
return 0;
- while (strlen (eids->sig)) {
- if (!strcmp (eids->sig, edev->id.sig) &&
+ while (strlen(eids->sig)) {
+ if (!strcmp(eids->sig, edev->id.sig) &&
edev->state & EISA_CONFIG_ENABLED) {
edev->id.driver_data = eids->driver_data;
return 1;
@@ -141,61 +141,71 @@ struct bus_type eisa_bus_type = {
.match = eisa_bus_match,
.uevent = eisa_bus_uevent,
};
+EXPORT_SYMBOL(eisa_bus_type);
-int eisa_driver_register (struct eisa_driver *edrv)
+int eisa_driver_register(struct eisa_driver *edrv)
{
edrv->driver.bus = &eisa_bus_type;
- return driver_register (&edrv->driver);
+ return driver_register(&edrv->driver);
}
+EXPORT_SYMBOL(eisa_driver_register);
-void eisa_driver_unregister (struct eisa_driver *edrv)
+void eisa_driver_unregister(struct eisa_driver *edrv)
{
- driver_unregister (&edrv->driver);
+ driver_unregister(&edrv->driver);
}
+EXPORT_SYMBOL(eisa_driver_unregister);
-static ssize_t eisa_show_sig (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t eisa_show_sig(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- struct eisa_device *edev = to_eisa_device (dev);
- return sprintf (buf,"%s\n", edev->id.sig);
+ struct eisa_device *edev = to_eisa_device(dev);
+ return sprintf(buf, "%s\n", edev->id.sig);
}
static DEVICE_ATTR(signature, S_IRUGO, eisa_show_sig, NULL);
-static ssize_t eisa_show_state (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t eisa_show_state(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct eisa_device *edev = to_eisa_device (dev);
- return sprintf (buf,"%d\n", edev->state & EISA_CONFIG_ENABLED);
+ struct eisa_device *edev = to_eisa_device(dev);
+ return sprintf(buf, "%d\n", edev->state & EISA_CONFIG_ENABLED);
}
static DEVICE_ATTR(enabled, S_IRUGO, eisa_show_state, NULL);
-static ssize_t eisa_show_modalias (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t eisa_show_modalias(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct eisa_device *edev = to_eisa_device (dev);
- return sprintf (buf, EISA_DEVICE_MODALIAS_FMT "\n", edev->id.sig);
+ struct eisa_device *edev = to_eisa_device(dev);
+ return sprintf(buf, EISA_DEVICE_MODALIAS_FMT "\n", edev->id.sig);
}
static DEVICE_ATTR(modalias, S_IRUGO, eisa_show_modalias, NULL);
-static int __init eisa_init_device (struct eisa_root_device *root,
- struct eisa_device *edev,
- int slot)
+static int __init eisa_init_device(struct eisa_root_device *root,
+ struct eisa_device *edev,
+ int slot)
{
char *sig;
- unsigned long sig_addr;
+ unsigned long sig_addr;
int i;
- sig_addr = SLOT_ADDRESS (root, slot) + EISA_VENDOR_ID_OFFSET;
+ sig_addr = SLOT_ADDRESS(root, slot) + EISA_VENDOR_ID_OFFSET;
- if (!(sig = decode_eisa_sig (sig_addr)))
+ sig = decode_eisa_sig(sig_addr);
+ if (!sig)
return -1; /* No EISA device here */
- memcpy (edev->id.sig, sig, EISA_SIG_LEN);
+ memcpy(edev->id.sig, sig, EISA_SIG_LEN);
edev->slot = slot;
- edev->state = inb (SLOT_ADDRESS (root, slot) + EISA_CONFIG_OFFSET) & EISA_CONFIG_ENABLED;
- edev->base_addr = SLOT_ADDRESS (root, slot);
+ edev->state = inb(SLOT_ADDRESS(root, slot) + EISA_CONFIG_OFFSET)
+ & EISA_CONFIG_ENABLED;
+ edev->base_addr = SLOT_ADDRESS(root, slot);
edev->dma_mask = root->dma_mask; /* Default DMA mask */
- eisa_name_device (edev);
+ eisa_name_device(edev);
edev->dev.parent = root->dev;
edev->dev.bus = &eisa_bus_type;
edev->dev.dma_mask = &edev->dma_mask;
@@ -210,42 +220,45 @@ static int __init eisa_init_device (struct eisa_root_device *root,
#endif
}
- if (is_forced_dev (enable_dev, enable_dev_count, root, edev))
+ if (is_forced_dev(enable_dev, enable_dev_count, root, edev))
edev->state = EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED;
- if (is_forced_dev (disable_dev, disable_dev_count, root, edev))
+ if (is_forced_dev(disable_dev, disable_dev_count, root, edev))
edev->state = EISA_CONFIG_FORCED;
return 0;
}
-static int __init eisa_register_device (struct eisa_device *edev)
+static int __init eisa_register_device(struct eisa_device *edev)
{
- int rc = device_register (&edev->dev);
+ int rc = device_register(&edev->dev);
if (rc)
return rc;
- rc = device_create_file (&edev->dev, &dev_attr_signature);
- if (rc) goto err_devreg;
- rc = device_create_file (&edev->dev, &dev_attr_enabled);
- if (rc) goto err_sig;
- rc = device_create_file (&edev->dev, &dev_attr_modalias);
- if (rc) goto err_enab;
+ rc = device_create_file(&edev->dev, &dev_attr_signature);
+ if (rc)
+ goto err_devreg;
+ rc = device_create_file(&edev->dev, &dev_attr_enabled);
+ if (rc)
+ goto err_sig;
+ rc = device_create_file(&edev->dev, &dev_attr_modalias);
+ if (rc)
+ goto err_enab;
return 0;
err_enab:
- device_remove_file (&edev->dev, &dev_attr_enabled);
+ device_remove_file(&edev->dev, &dev_attr_enabled);
err_sig:
- device_remove_file (&edev->dev, &dev_attr_signature);
+ device_remove_file(&edev->dev, &dev_attr_signature);
err_devreg:
device_unregister(&edev->dev);
return rc;
}
-static int __init eisa_request_resources (struct eisa_root_device *root,
- struct eisa_device *edev,
- int slot)
+static int __init eisa_request_resources(struct eisa_root_device *root,
+ struct eisa_device *edev,
+ int slot)
{
int i;
@@ -263,17 +276,19 @@ static int __init eisa_request_resources (struct eisa_root_device *root,
if (slot) {
edev->res[i].name = NULL;
- edev->res[i].start = SLOT_ADDRESS (root, slot) + (i * 0x400);
+ edev->res[i].start = SLOT_ADDRESS(root, slot)
+ + (i * 0x400);
edev->res[i].end = edev->res[i].start + 0xff;
edev->res[i].flags = IORESOURCE_IO;
} else {
edev->res[i].name = NULL;
- edev->res[i].start = SLOT_ADDRESS (root, slot) + EISA_VENDOR_ID_OFFSET;
+ edev->res[i].start = SLOT_ADDRESS(root, slot)
+ + EISA_VENDOR_ID_OFFSET;
edev->res[i].end = edev->res[i].start + 3;
edev->res[i].flags = IORESOURCE_BUSY;
}
- if (request_resource (root->res, &edev->res[i]))
+ if (request_resource(root->res, &edev->res[i]))
goto failed;
}
@@ -281,99 +296,100 @@ static int __init eisa_request_resources (struct eisa_root_device *root,
failed:
while (--i >= 0)
- release_resource (&edev->res[i]);
+ release_resource(&edev->res[i]);
return -1;
}
-static void __init eisa_release_resources (struct eisa_device *edev)
+static void __init eisa_release_resources(struct eisa_device *edev)
{
int i;
for (i = 0; i < EISA_MAX_RESOURCES; i++)
if (edev->res[i].start || edev->res[i].end)
- release_resource (&edev->res[i]);
+ release_resource(&edev->res[i]);
}
-static int __init eisa_probe (struct eisa_root_device *root)
+static int __init eisa_probe(struct eisa_root_device *root)
{
int i, c;
struct eisa_device *edev;
- printk (KERN_INFO "EISA: Probing bus %d at %s\n",
- root->bus_nr, dev_name(root->dev));
+ printk(KERN_INFO "EISA: Probing bus %d at %s\n",
+ root->bus_nr, dev_name(root->dev));
/* First try to get hold of slot 0. If there is no device
* here, simply fail, unless root->force_probe is set. */
- if (!(edev = kzalloc (sizeof (*edev), GFP_KERNEL))) {
- printk (KERN_ERR "EISA: Couldn't allocate mainboard slot\n");
+ edev = kzalloc(sizeof(*edev), GFP_KERNEL);
+ if (!edev) {
+ printk(KERN_ERR "EISA: Couldn't allocate mainboard slot\n");
return -ENOMEM;
}
- if (eisa_request_resources (root, edev, 0)) {
- printk (KERN_WARNING \
- "EISA: Cannot allocate resource for mainboard\n");
- kfree (edev);
+ if (eisa_request_resources(root, edev, 0)) {
+ printk(KERN_WARNING \
+ "EISA: Cannot allocate resource for mainboard\n");
+ kfree(edev);
if (!root->force_probe)
return -EBUSY;
goto force_probe;
}
- if (eisa_init_device (root, edev, 0)) {
- eisa_release_resources (edev);
- kfree (edev);
+ if (eisa_init_device(root, edev, 0)) {
+ eisa_release_resources(edev);
+ kfree(edev);
if (!root->force_probe)
return -ENODEV;
goto force_probe;
}
- printk (KERN_INFO "EISA: Mainboard %s detected.\n", edev->id.sig);
+ printk(KERN_INFO "EISA: Mainboard %s detected.\n", edev->id.sig);
- if (eisa_register_device (edev)) {
- printk (KERN_ERR "EISA: Failed to register %s\n",
- edev->id.sig);
- eisa_release_resources (edev);
- kfree (edev);
+ if (eisa_register_device(edev)) {
+ printk(KERN_ERR "EISA: Failed to register %s\n",
+ edev->id.sig);
+ eisa_release_resources(edev);
+ kfree(edev);
}
force_probe:
for (c = 0, i = 1; i <= root->slots; i++) {
- if (!(edev = kzalloc (sizeof (*edev), GFP_KERNEL))) {
- printk (KERN_ERR "EISA: Out of memory for slot %d\n",
- i);
+ edev = kzalloc(sizeof(*edev), GFP_KERNEL);
+ if (!edev) {
+ printk(KERN_ERR "EISA: Out of memory for slot %d\n", i);
continue;
}
- if (eisa_request_resources (root, edev, i)) {
- printk (KERN_WARNING \
- "Cannot allocate resource for EISA slot %d\n",
- i);
- kfree (edev);
+ if (eisa_request_resources(root, edev, i)) {
+ printk(KERN_WARNING \
+ "Cannot allocate resource for EISA slot %d\n",
+ i);
+ kfree(edev);
continue;
}
- if (eisa_init_device (root, edev, i)) {
- eisa_release_resources (edev);
- kfree (edev);
+ if (eisa_init_device(root, edev, i)) {
+ eisa_release_resources(edev);
+ kfree(edev);
continue;
}
- printk (KERN_INFO "EISA: slot %d : %s detected",
- i, edev->id.sig);
+ printk(KERN_INFO "EISA: slot %d : %s detected",
+ i, edev->id.sig);
switch (edev->state) {
case EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED:
- printk (" (forced enabled)");
+ printk(" (forced enabled)");
break;
case EISA_CONFIG_FORCED:
- printk (" (forced disabled)");
+ printk(" (forced disabled)");
break;
case 0:
- printk (" (disabled)");
+ printk(" (disabled)");
break;
}
@@ -381,15 +397,15 @@ static int __init eisa_probe (struct eisa_root_device *root)
c++;
- if (eisa_register_device (edev)) {
- printk (KERN_ERR "EISA: Failed to register %s\n",
- edev->id.sig);
- eisa_release_resources (edev);
- kfree (edev);
+ if (eisa_register_device(edev)) {
+ printk(KERN_ERR "EISA: Failed to register %s\n",
+ edev->id.sig);
+ eisa_release_resources(edev);
+ kfree(edev);
}
}
- printk (KERN_INFO "EISA: Detected %d card%s.\n", c, c == 1 ? "" : "s");
+ printk(KERN_INFO "EISA: Detected %d card%s.\n", c, c == 1 ? "" : "s");
return 0;
}
@@ -403,7 +419,7 @@ static struct resource eisa_root_res = {
static int eisa_bus_count;
-int __init eisa_root_register (struct eisa_root_device *root)
+int __init eisa_root_register(struct eisa_root_device *root)
{
int err;
@@ -417,35 +433,35 @@ int __init eisa_root_register (struct eisa_root_device *root)
root->eisa_root_res.end = root->res->end;
root->eisa_root_res.flags = IORESOURCE_BUSY;
- if ((err = request_resource (&eisa_root_res, &root->eisa_root_res)))
+ err = request_resource(&eisa_root_res, &root->eisa_root_res);
+ if (err)
return err;
root->bus_nr = eisa_bus_count++;
- if ((err = eisa_probe (root)))
- release_resource (&root->eisa_root_res);
+ err = eisa_probe(root);
+ if (err)
+ release_resource(&root->eisa_root_res);
return err;
}
-static int __init eisa_init (void)
+static int __init eisa_init(void)
{
int r;
- if ((r = bus_register (&eisa_bus_type)))
+ r = bus_register(&eisa_bus_type);
+ if (r)
return r;
- printk (KERN_INFO "EISA bus registered\n");
+ printk(KERN_INFO "EISA bus registered\n");
return 0;
}
module_param_array(enable_dev, int, &enable_dev_count, 0444);
module_param_array(disable_dev, int, &disable_dev_count, 0444);
-postcore_initcall (eisa_init);
+postcore_initcall(eisa_init);
int EISA_bus; /* for legacy drivers */
-EXPORT_SYMBOL (EISA_bus);
-EXPORT_SYMBOL (eisa_bus_type);
-EXPORT_SYMBOL (eisa_driver_register);
-EXPORT_SYMBOL (eisa_driver_unregister);
+EXPORT_SYMBOL(EISA_bus);
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 7083bcc1b9c7..5045156c5313 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -57,6 +57,8 @@ static LIST_HEAD(descriptor_list);
static int descriptor_count;
static __be32 tmp_config_rom[256];
+/* ROM header, bus info block, root dir header, capabilities = 7 quadlets */
+static size_t config_rom_length = 1 + 4 + 1 + 1;
#define BIB_CRC(v) ((v) << 0)
#define BIB_CRC_LENGTH(v) ((v) << 16)
@@ -73,7 +75,7 @@ static __be32 tmp_config_rom[256];
#define BIB_CMC ((1) << 30)
#define BIB_IMC ((1) << 31)
-static size_t generate_config_rom(struct fw_card *card, __be32 *config_rom)
+static void generate_config_rom(struct fw_card *card, __be32 *config_rom)
{
struct fw_descriptor *desc;
int i, j, k, length;
@@ -130,23 +132,30 @@ static size_t generate_config_rom(struct fw_card *card, __be32 *config_rom)
for (i = 0; i < j; i += length + 1)
length = fw_compute_block_crc(config_rom + i);
- return j;
+ WARN_ON(j != config_rom_length);
}
static void update_config_roms(void)
{
struct fw_card *card;
- size_t length;
list_for_each_entry (card, &card_list, link) {
- length = generate_config_rom(card, tmp_config_rom);
- card->driver->set_config_rom(card, tmp_config_rom, length);
+ generate_config_rom(card, tmp_config_rom);
+ card->driver->set_config_rom(card, tmp_config_rom,
+ config_rom_length);
}
}
+static size_t required_space(struct fw_descriptor *desc)
+{
+ /* descriptor + entry into root dir + optional immediate entry */
+ return desc->length + 1 + (desc->immediate > 0 ? 1 : 0);
+}
+
int fw_core_add_descriptor(struct fw_descriptor *desc)
{
size_t i;
+ int ret;
/*
* Check descriptor is valid; the length of all blocks in the
@@ -162,15 +171,21 @@ int fw_core_add_descriptor(struct fw_descriptor *desc)
mutex_lock(&card_mutex);
- list_add_tail(&desc->link, &descriptor_list);
- descriptor_count++;
- if (desc->immediate > 0)
+ if (config_rom_length + required_space(desc) > 256) {
+ ret = -EBUSY;
+ } else {
+ list_add_tail(&desc->link, &descriptor_list);
+ config_rom_length += required_space(desc);
descriptor_count++;
- update_config_roms();
+ if (desc->immediate > 0)
+ descriptor_count++;
+ update_config_roms();
+ ret = 0;
+ }
mutex_unlock(&card_mutex);
- return 0;
+ return ret;
}
EXPORT_SYMBOL(fw_core_add_descriptor);
@@ -179,6 +194,7 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc)
mutex_lock(&card_mutex);
list_del(&desc->link);
+ config_rom_length -= required_space(desc);
descriptor_count--;
if (desc->immediate > 0)
descriptor_count--;
@@ -428,7 +444,6 @@ EXPORT_SYMBOL(fw_card_initialize);
int fw_card_add(struct fw_card *card,
u32 max_receive, u32 link_speed, u64 guid)
{
- size_t length;
int ret;
card->max_receive = max_receive;
@@ -437,8 +452,8 @@ int fw_card_add(struct fw_card *card,
mutex_lock(&card_mutex);
- length = generate_config_rom(card, tmp_config_rom);
- ret = card->driver->enable(card, tmp_config_rom, length);
+ generate_config_rom(card, tmp_config_rom);
+ ret = card->driver->enable(card, tmp_config_rom, config_rom_length);
if (ret == 0)
list_add_tail(&card->link, &card_list);
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index e6d63849e78e..8be720b278b7 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -25,6 +25,7 @@
#include <linux/firewire.h>
#include <linux/firewire-cdev.h>
#include <linux/idr.h>
+#include <linux/irqflags.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/kref.h>
@@ -32,9 +33,9 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/poll.h>
-#include <linux/preempt.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
+#include <linux/string.h>
#include <linux/time.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
@@ -367,39 +368,56 @@ void fw_device_cdev_remove(struct fw_device *device)
for_each_client(device, wake_up_client);
}
-static int ioctl_get_info(struct client *client, void *buffer)
+union ioctl_arg {
+ struct fw_cdev_get_info get_info;
+ struct fw_cdev_send_request send_request;
+ struct fw_cdev_allocate allocate;
+ struct fw_cdev_deallocate deallocate;
+ struct fw_cdev_send_response send_response;
+ struct fw_cdev_initiate_bus_reset initiate_bus_reset;
+ struct fw_cdev_add_descriptor add_descriptor;
+ struct fw_cdev_remove_descriptor remove_descriptor;
+ struct fw_cdev_create_iso_context create_iso_context;
+ struct fw_cdev_queue_iso queue_iso;
+ struct fw_cdev_start_iso start_iso;
+ struct fw_cdev_stop_iso stop_iso;
+ struct fw_cdev_get_cycle_timer get_cycle_timer;
+ struct fw_cdev_allocate_iso_resource allocate_iso_resource;
+ struct fw_cdev_send_stream_packet send_stream_packet;
+ struct fw_cdev_get_cycle_timer2 get_cycle_timer2;
+};
+
+static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_get_info *get_info = buffer;
+ struct fw_cdev_get_info *a = &arg->get_info;
struct fw_cdev_event_bus_reset bus_reset;
unsigned long ret = 0;
- client->version = get_info->version;
- get_info->version = FW_CDEV_VERSION;
- get_info->card = client->device->card->index;
+ client->version = a->version;
+ a->version = FW_CDEV_VERSION;
+ a->card = client->device->card->index;
down_read(&fw_device_rwsem);
- if (get_info->rom != 0) {
- void __user *uptr = u64_to_uptr(get_info->rom);
- size_t want = get_info->rom_length;
+ if (a->rom != 0) {
+ size_t want = a->rom_length;
size_t have = client->device->config_rom_length * 4;
- ret = copy_to_user(uptr, client->device->config_rom,
- min(want, have));
+ ret = copy_to_user(u64_to_uptr(a->rom),
+ client->device->config_rom, min(want, have));
}
- get_info->rom_length = client->device->config_rom_length * 4;
+ a->rom_length = client->device->config_rom_length * 4;
up_read(&fw_device_rwsem);
if (ret != 0)
return -EFAULT;
- client->bus_reset_closure = get_info->bus_reset_closure;
- if (get_info->bus_reset != 0) {
- void __user *uptr = u64_to_uptr(get_info->bus_reset);
-
+ client->bus_reset_closure = a->bus_reset_closure;
+ if (a->bus_reset != 0) {
fill_bus_reset_event(&bus_reset, client);
- if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset)))
+ if (copy_to_user(u64_to_uptr(a->bus_reset),
+ &bus_reset, sizeof(bus_reset)))
return -EFAULT;
}
@@ -570,11 +588,9 @@ static int init_request(struct client *client,
return ret;
}
-static int ioctl_send_request(struct client *client, void *buffer)
+static int ioctl_send_request(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_send_request *request = buffer;
-
- switch (request->tcode) {
+ switch (arg->send_request.tcode) {
case TCODE_WRITE_QUADLET_REQUEST:
case TCODE_WRITE_BLOCK_REQUEST:
case TCODE_READ_QUADLET_REQUEST:
@@ -591,17 +607,24 @@ static int ioctl_send_request(struct client *client, void *buffer)
return -EINVAL;
}
- return init_request(client, request, client->device->node_id,
+ return init_request(client, &arg->send_request, client->device->node_id,
client->device->max_speed);
}
+static inline bool is_fcp_request(struct fw_request *request)
+{
+ return request == NULL;
+}
+
static void release_request(struct client *client,
struct client_resource *resource)
{
struct inbound_transaction_resource *r = container_of(resource,
struct inbound_transaction_resource, resource);
- if (r->request)
+ if (is_fcp_request(r->request))
+ kfree(r->data);
+ else
fw_send_response(client->device->card, r->request,
RCODE_CONFLICT_ERROR);
kfree(r);
@@ -616,6 +639,7 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
struct address_handler_resource *handler = callback_data;
struct inbound_transaction_resource *r;
struct inbound_transaction_event *e;
+ void *fcp_frame = NULL;
int ret;
r = kmalloc(sizeof(*r), GFP_ATOMIC);
@@ -627,6 +651,18 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
r->data = payload;
r->length = length;
+ if (is_fcp_request(request)) {
+ /*
+ * FIXME: Let core-transaction.c manage a
+ * single reference-counted copy?
+ */
+ fcp_frame = kmemdup(payload, length, GFP_ATOMIC);
+ if (fcp_frame == NULL)
+ goto failed;
+
+ r->data = fcp_frame;
+ }
+
r->resource.release = release_request;
ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC);
if (ret < 0)
@@ -640,13 +676,15 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
e->request.closure = handler->closure;
queue_event(handler->client, &e->event,
- &e->request, sizeof(e->request), payload, length);
+ &e->request, sizeof(e->request), r->data, length);
return;
failed:
kfree(r);
kfree(e);
- if (request)
+ kfree(fcp_frame);
+
+ if (!is_fcp_request(request))
fw_send_response(card, request, RCODE_CONFLICT_ERROR);
}
@@ -660,9 +698,9 @@ static void release_address_handler(struct client *client,
kfree(r);
}
-static int ioctl_allocate(struct client *client, void *buffer)
+static int ioctl_allocate(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_allocate *request = buffer;
+ struct fw_cdev_allocate *a = &arg->allocate;
struct address_handler_resource *r;
struct fw_address_region region;
int ret;
@@ -671,13 +709,13 @@ static int ioctl_allocate(struct client *client, void *buffer)
if (r == NULL)
return -ENOMEM;
- region.start = request->offset;
- region.end = request->offset + request->length;
- r->handler.length = request->length;
+ region.start = a->offset;
+ region.end = a->offset + a->length;
+ r->handler.length = a->length;
r->handler.address_callback = handle_request;
- r->handler.callback_data = r;
- r->closure = request->closure;
- r->client = client;
+ r->handler.callback_data = r;
+ r->closure = a->closure;
+ r->client = client;
ret = fw_core_add_address_handler(&r->handler, &region);
if (ret < 0) {
@@ -691,58 +729,51 @@ static int ioctl_allocate(struct client *client, void *buffer)
release_address_handler(client, &r->resource);
return ret;
}
- request->handle = r->resource.handle;
+ a->handle = r->resource.handle;
return 0;
}
-static int ioctl_deallocate(struct client *client, void *buffer)
+static int ioctl_deallocate(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_deallocate *request = buffer;
-
- return release_client_resource(client, request->handle,
+ return release_client_resource(client, arg->deallocate.handle,
release_address_handler, NULL);
}
-static int ioctl_send_response(struct client *client, void *buffer)
+static int ioctl_send_response(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_send_response *request = buffer;
+ struct fw_cdev_send_response *a = &arg->send_response;
struct client_resource *resource;
struct inbound_transaction_resource *r;
int ret = 0;
- if (release_client_resource(client, request->handle,
+ if (release_client_resource(client, a->handle,
release_request, &resource) < 0)
return -EINVAL;
r = container_of(resource, struct inbound_transaction_resource,
resource);
- if (r->request) {
- if (request->length < r->length)
- r->length = request->length;
- if (copy_from_user(r->data, u64_to_uptr(request->data),
- r->length)) {
- ret = -EFAULT;
- kfree(r->request);
- goto out;
- }
- fw_send_response(client->device->card, r->request,
- request->rcode);
+ if (is_fcp_request(r->request))
+ goto out;
+
+ if (a->length < r->length)
+ r->length = a->length;
+ if (copy_from_user(r->data, u64_to_uptr(a->data), r->length)) {
+ ret = -EFAULT;
+ kfree(r->request);
+ goto out;
}
+ fw_send_response(client->device->card, r->request, a->rcode);
out:
kfree(r);
return ret;
}
-static int ioctl_initiate_bus_reset(struct client *client, void *buffer)
+static int ioctl_initiate_bus_reset(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_initiate_bus_reset *request = buffer;
- int short_reset;
-
- short_reset = (request->type == FW_CDEV_SHORT_RESET);
-
- return fw_core_initiate_bus_reset(client->device->card, short_reset);
+ return fw_core_initiate_bus_reset(client->device->card,
+ arg->initiate_bus_reset.type == FW_CDEV_SHORT_RESET);
}
static void release_descriptor(struct client *client,
@@ -755,9 +786,9 @@ static void release_descriptor(struct client *client,
kfree(r);
}
-static int ioctl_add_descriptor(struct client *client, void *buffer)
+static int ioctl_add_descriptor(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_add_descriptor *request = buffer;
+ struct fw_cdev_add_descriptor *a = &arg->add_descriptor;
struct descriptor_resource *r;
int ret;
@@ -765,22 +796,21 @@ static int ioctl_add_descriptor(struct client *client, void *buffer)
if (!client->device->is_local)
return -ENOSYS;
- if (request->length > 256)
+ if (a->length > 256)
return -EINVAL;
- r = kmalloc(sizeof(*r) + request->length * 4, GFP_KERNEL);
+ r = kmalloc(sizeof(*r) + a->length * 4, GFP_KERNEL);
if (r == NULL)
return -ENOMEM;
- if (copy_from_user(r->data,
- u64_to_uptr(request->data), request->length * 4)) {
+ if (copy_from_user(r->data, u64_to_uptr(a->data), a->length * 4)) {
ret = -EFAULT;
goto failed;
}
- r->descriptor.length = request->length;
- r->descriptor.immediate = request->immediate;
- r->descriptor.key = request->key;
+ r->descriptor.length = a->length;
+ r->descriptor.immediate = a->immediate;
+ r->descriptor.key = a->key;
r->descriptor.data = r->data;
ret = fw_core_add_descriptor(&r->descriptor);
@@ -793,7 +823,7 @@ static int ioctl_add_descriptor(struct client *client, void *buffer)
fw_core_remove_descriptor(&r->descriptor);
goto failed;
}
- request->handle = r->resource.handle;
+ a->handle = r->resource.handle;
return 0;
failed:
@@ -802,11 +832,9 @@ static int ioctl_add_descriptor(struct client *client, void *buffer)
return ret;
}
-static int ioctl_remove_descriptor(struct client *client, void *buffer)
+static int ioctl_remove_descriptor(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_remove_descriptor *request = buffer;
-
- return release_client_resource(client, request->handle,
+ return release_client_resource(client, arg->remove_descriptor.handle,
release_descriptor, NULL);
}
@@ -829,49 +857,44 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle,
sizeof(e->interrupt) + header_length, NULL, 0);
}
-static int ioctl_create_iso_context(struct client *client, void *buffer)
+static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_create_iso_context *request = buffer;
+ struct fw_cdev_create_iso_context *a = &arg->create_iso_context;
struct fw_iso_context *context;
/* We only support one context at this time. */
if (client->iso_context != NULL)
return -EBUSY;
- if (request->channel > 63)
+ if (a->channel > 63)
return -EINVAL;
- switch (request->type) {
+ switch (a->type) {
case FW_ISO_CONTEXT_RECEIVE:
- if (request->header_size < 4 || (request->header_size & 3))
+ if (a->header_size < 4 || (a->header_size & 3))
return -EINVAL;
-
break;
case FW_ISO_CONTEXT_TRANSMIT:
- if (request->speed > SCODE_3200)
+ if (a->speed > SCODE_3200)
return -EINVAL;
-
break;
default:
return -EINVAL;
}
- context = fw_iso_context_create(client->device->card,
- request->type,
- request->channel,
- request->speed,
- request->header_size,
- iso_callback, client);
+ context = fw_iso_context_create(client->device->card, a->type,
+ a->channel, a->speed, a->header_size,
+ iso_callback, client);
if (IS_ERR(context))
return PTR_ERR(context);
- client->iso_closure = request->closure;
+ client->iso_closure = a->closure;
client->iso_context = context;
/* We only support one context at this time. */
- request->handle = 0;
+ a->handle = 0;
return 0;
}
@@ -884,9 +907,9 @@ static int ioctl_create_iso_context(struct client *client, void *buffer)
#define GET_SY(v) (((v) >> 20) & 0x0f)
#define GET_HEADER_LENGTH(v) (((v) >> 24) & 0xff)
-static int ioctl_queue_iso(struct client *client, void *buffer)
+static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_queue_iso *request = buffer;
+ struct fw_cdev_queue_iso *a = &arg->queue_iso;
struct fw_cdev_iso_packet __user *p, *end, *next;
struct fw_iso_context *ctx = client->iso_context;
unsigned long payload, buffer_end, header_length;
@@ -897,7 +920,7 @@ static int ioctl_queue_iso(struct client *client, void *buffer)
u8 header[256];
} u;
- if (ctx == NULL || request->handle != 0)
+ if (ctx == NULL || a->handle != 0)
return -EINVAL;
/*
@@ -907,23 +930,23 @@ static int ioctl_queue_iso(struct client *client, void *buffer)
* set them both to 0, which will still let packets with
* payload_length == 0 through. In other words, if no packets
* use the indirect payload, the iso buffer need not be mapped
- * and the request->data pointer is ignored.
+ * and the a->data pointer is ignored.
*/
- payload = (unsigned long)request->data - client->vm_start;
+ payload = (unsigned long)a->data - client->vm_start;
buffer_end = client->buffer.page_count << PAGE_SHIFT;
- if (request->data == 0 || client->buffer.pages == NULL ||
+ if (a->data == 0 || client->buffer.pages == NULL ||
payload >= buffer_end) {
payload = 0;
buffer_end = 0;
}
- p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets);
+ p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(a->packets);
- if (!access_ok(VERIFY_READ, p, request->size))
+ if (!access_ok(VERIFY_READ, p, a->size))
return -EFAULT;
- end = (void __user *)p + request->size;
+ end = (void __user *)p + a->size;
count = 0;
while (p < end) {
if (get_user(control, &p->control))
@@ -973,61 +996,78 @@ static int ioctl_queue_iso(struct client *client, void *buffer)
count++;
}
- request->size -= uptr_to_u64(p) - request->packets;
- request->packets = uptr_to_u64(p);
- request->data = client->vm_start + payload;
+ a->size -= uptr_to_u64(p) - a->packets;
+ a->packets = uptr_to_u64(p);
+ a->data = client->vm_start + payload;
return count;
}
-static int ioctl_start_iso(struct client *client, void *buffer)
+static int ioctl_start_iso(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_start_iso *request = buffer;
+ struct fw_cdev_start_iso *a = &arg->start_iso;
- if (client->iso_context == NULL || request->handle != 0)
+ if (client->iso_context == NULL || a->handle != 0)
return -EINVAL;
- if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) {
- if (request->tags == 0 || request->tags > 15)
- return -EINVAL;
-
- if (request->sync > 15)
- return -EINVAL;
- }
+ if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE &&
+ (a->tags == 0 || a->tags > 15 || a->sync > 15))
+ return -EINVAL;
- return fw_iso_context_start(client->iso_context, request->cycle,
- request->sync, request->tags);
+ return fw_iso_context_start(client->iso_context,
+ a->cycle, a->sync, a->tags);
}
-static int ioctl_stop_iso(struct client *client, void *buffer)
+static int ioctl_stop_iso(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_stop_iso *request = buffer;
+ struct fw_cdev_stop_iso *a = &arg->stop_iso;
- if (client->iso_context == NULL || request->handle != 0)
+ if (client->iso_context == NULL || a->handle != 0)
return -EINVAL;
return fw_iso_context_stop(client->iso_context);
}
-static int ioctl_get_cycle_timer(struct client *client, void *buffer)
+static int ioctl_get_cycle_timer2(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_get_cycle_timer *request = buffer;
+ struct fw_cdev_get_cycle_timer2 *a = &arg->get_cycle_timer2;
struct fw_card *card = client->device->card;
- unsigned long long bus_time;
- struct timeval tv;
- unsigned long flags;
+ struct timespec ts = {0, 0};
+ u32 cycle_time;
+ int ret = 0;
+
+ local_irq_disable();
+
+ cycle_time = card->driver->get_cycle_time(card);
+
+ switch (a->clk_id) {
+ case CLOCK_REALTIME: getnstimeofday(&ts); break;
+ case CLOCK_MONOTONIC: do_posix_clock_monotonic_gettime(&ts); break;
+ case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts); break;
+ default:
+ ret = -EINVAL;
+ }
- preempt_disable();
- local_irq_save(flags);
+ local_irq_enable();
- bus_time = card->driver->get_bus_time(card);
- do_gettimeofday(&tv);
+ a->tv_sec = ts.tv_sec;
+ a->tv_nsec = ts.tv_nsec;
+ a->cycle_timer = cycle_time;
- local_irq_restore(flags);
- preempt_enable();
+ return ret;
+}
+
+static int ioctl_get_cycle_timer(struct client *client, union ioctl_arg *arg)
+{
+ struct fw_cdev_get_cycle_timer *a = &arg->get_cycle_timer;
+ struct fw_cdev_get_cycle_timer2 ct2;
+
+ ct2.clk_id = CLOCK_REALTIME;
+ ioctl_get_cycle_timer2(client, (union ioctl_arg *)&ct2);
+
+ a->local_time = ct2.tv_sec * USEC_PER_SEC + ct2.tv_nsec / NSEC_PER_USEC;
+ a->cycle_timer = ct2.cycle_timer;
- request->local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;
- request->cycle_timer = bus_time & 0xffffffff;
return 0;
}
@@ -1198,33 +1238,32 @@ static int init_iso_resource(struct client *client,
return ret;
}
-static int ioctl_allocate_iso_resource(struct client *client, void *buffer)
+static int ioctl_allocate_iso_resource(struct client *client,
+ union ioctl_arg *arg)
{
- struct fw_cdev_allocate_iso_resource *request = buffer;
-
- return init_iso_resource(client, request, ISO_RES_ALLOC);
+ return init_iso_resource(client,
+ &arg->allocate_iso_resource, ISO_RES_ALLOC);
}
-static int ioctl_deallocate_iso_resource(struct client *client, void *buffer)
+static int ioctl_deallocate_iso_resource(struct client *client,
+ union ioctl_arg *arg)
{
- struct fw_cdev_deallocate *request = buffer;
-
- return release_client_resource(client, request->handle,
- release_iso_resource, NULL);
+ return release_client_resource(client,
+ arg->deallocate.handle, release_iso_resource, NULL);
}
-static int ioctl_allocate_iso_resource_once(struct client *client, void *buffer)
+static int ioctl_allocate_iso_resource_once(struct client *client,
+ union ioctl_arg *arg)
{
- struct fw_cdev_allocate_iso_resource *request = buffer;
-
- return init_iso_resource(client, request, ISO_RES_ALLOC_ONCE);
+ return init_iso_resource(client,
+ &arg->allocate_iso_resource, ISO_RES_ALLOC_ONCE);
}
-static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffer)
+static int ioctl_deallocate_iso_resource_once(struct client *client,
+ union ioctl_arg *arg)
{
- struct fw_cdev_allocate_iso_resource *request = buffer;
-
- return init_iso_resource(client, request, ISO_RES_DEALLOC_ONCE);
+ return init_iso_resource(client,
+ &arg->allocate_iso_resource, ISO_RES_DEALLOC_ONCE);
}
/*
@@ -1232,16 +1271,17 @@ static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffe
* limited by the device's link speed, the local node's link speed,
* and all PHY port speeds between the two links.
*/
-static int ioctl_get_speed(struct client *client, void *buffer)
+static int ioctl_get_speed(struct client *client, union ioctl_arg *arg)
{
return client->device->max_speed;
}
-static int ioctl_send_broadcast_request(struct client *client, void *buffer)
+static int ioctl_send_broadcast_request(struct client *client,
+ union ioctl_arg *arg)
{
- struct fw_cdev_send_request *request = buffer;
+ struct fw_cdev_send_request *a = &arg->send_request;
- switch (request->tcode) {
+ switch (a->tcode) {
case TCODE_WRITE_QUADLET_REQUEST:
case TCODE_WRITE_BLOCK_REQUEST:
break;
@@ -1250,36 +1290,36 @@ static int ioctl_send_broadcast_request(struct client *client, void *buffer)
}
/* Security policy: Only allow accesses to Units Space. */
- if (request->offset < CSR_REGISTER_BASE + CSR_CONFIG_ROM_END)
+ if (a->offset < CSR_REGISTER_BASE + CSR_CONFIG_ROM_END)
return -EACCES;
- return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100);
+ return init_request(client, a, LOCAL_BUS | 0x3f, SCODE_100);
}
-static int ioctl_send_stream_packet(struct client *client, void *buffer)
+static int ioctl_send_stream_packet(struct client *client, union ioctl_arg *arg)
{
- struct fw_cdev_send_stream_packet *p = buffer;
+ struct fw_cdev_send_stream_packet *a = &arg->send_stream_packet;
struct fw_cdev_send_request request;
int dest;
- if (p->speed > client->device->card->link_speed ||
- p->length > 1024 << p->speed)
+ if (a->speed > client->device->card->link_speed ||
+ a->length > 1024 << a->speed)
return -EIO;
- if (p->tag > 3 || p->channel > 63 || p->sy > 15)
+ if (a->tag > 3 || a->channel > 63 || a->sy > 15)
return -EINVAL;
- dest = fw_stream_packet_destination_id(p->tag, p->channel, p->sy);
+ dest = fw_stream_packet_destination_id(a->tag, a->channel, a->sy);
request.tcode = TCODE_STREAM_DATA;
- request.length = p->length;
- request.closure = p->closure;
- request.data = p->data;
- request.generation = p->generation;
+ request.length = a->length;
+ request.closure = a->closure;
+ request.data = a->data;
+ request.generation = a->generation;
- return init_request(client, &request, dest, p->speed);
+ return init_request(client, &request, dest, a->speed);
}
-static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
+static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = {
ioctl_get_info,
ioctl_send_request,
ioctl_allocate,
@@ -1300,47 +1340,35 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
ioctl_get_speed,
ioctl_send_broadcast_request,
ioctl_send_stream_packet,
+ ioctl_get_cycle_timer2,
};
static int dispatch_ioctl(struct client *client,
unsigned int cmd, void __user *arg)
{
- char buffer[sizeof(union {
- struct fw_cdev_get_info _00;
- struct fw_cdev_send_request _01;
- struct fw_cdev_allocate _02;
- struct fw_cdev_deallocate _03;
- struct fw_cdev_send_response _04;
- struct fw_cdev_initiate_bus_reset _05;
- struct fw_cdev_add_descriptor _06;
- struct fw_cdev_remove_descriptor _07;
- struct fw_cdev_create_iso_context _08;
- struct fw_cdev_queue_iso _09;
- struct fw_cdev_start_iso _0a;
- struct fw_cdev_stop_iso _0b;
- struct fw_cdev_get_cycle_timer _0c;
- struct fw_cdev_allocate_iso_resource _0d;
- struct fw_cdev_send_stream_packet _13;
- })];
+ union ioctl_arg buffer;
int ret;
+ if (fw_device_is_shutdown(client->device))
+ return -ENODEV;
+
if (_IOC_TYPE(cmd) != '#' ||
_IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers))
return -EINVAL;
if (_IOC_DIR(cmd) & _IOC_WRITE) {
if (_IOC_SIZE(cmd) > sizeof(buffer) ||
- copy_from_user(buffer, arg, _IOC_SIZE(cmd)))
+ copy_from_user(&buffer, arg, _IOC_SIZE(cmd)))
return -EFAULT;
}
- ret = ioctl_handlers[_IOC_NR(cmd)](client, buffer);
+ ret = ioctl_handlers[_IOC_NR(cmd)](client, &buffer);
if (ret < 0)
return ret;
if (_IOC_DIR(cmd) & _IOC_READ) {
if (_IOC_SIZE(cmd) > sizeof(buffer) ||
- copy_to_user(arg, buffer, _IOC_SIZE(cmd)))
+ copy_to_user(arg, &buffer, _IOC_SIZE(cmd)))
return -EFAULT;
}
@@ -1350,24 +1378,14 @@ static int dispatch_ioctl(struct client *client,
static long fw_device_op_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct client *client = file->private_data;
-
- if (fw_device_is_shutdown(client->device))
- return -ENODEV;
-
- return dispatch_ioctl(client, cmd, (void __user *) arg);
+ return dispatch_ioctl(file->private_data, cmd, (void __user *)arg);
}
#ifdef CONFIG_COMPAT
static long fw_device_op_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct client *client = file->private_data;
-
- if (fw_device_is_shutdown(client->device))
- return -ENODEV;
-
- return dispatch_ioctl(client, cmd, compat_ptr(arg));
+ return dispatch_ioctl(file->private_data, cmd, compat_ptr(arg));
}
#endif
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 9d0dfcbe2c1c..5db0518c66da 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -18,6 +18,7 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/bug.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -32,7 +33,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/rwsem.h>
-#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/workqueue.h>
@@ -43,7 +43,7 @@
#include "core.h"
-void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 * p)
+void fw_csr_iterator_init(struct fw_csr_iterator *ci, const u32 *p)
{
ci->p = p + 1;
ci->end = ci->p + (p[0] >> 16);
@@ -59,9 +59,76 @@ int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value)
}
EXPORT_SYMBOL(fw_csr_iterator_next);
+static const u32 *search_leaf(const u32 *directory, int search_key)
+{
+ struct fw_csr_iterator ci;
+ int last_key = 0, key, value;
+
+ fw_csr_iterator_init(&ci, directory);
+ while (fw_csr_iterator_next(&ci, &key, &value)) {
+ if (last_key == search_key &&
+ key == (CSR_DESCRIPTOR | CSR_LEAF))
+ return ci.p - 1 + value;
+
+ last_key = key;
+ }
+
+ return NULL;
+}
+
+static int textual_leaf_to_string(const u32 *block, char *buf, size_t size)
+{
+ unsigned int quadlets, i;
+ char c;
+
+ if (!size || !buf)
+ return -EINVAL;
+
+ quadlets = min(block[0] >> 16, 256U);
+ if (quadlets < 2)
+ return -ENODATA;
+
+ if (block[1] != 0 || block[2] != 0)
+ /* unknown language/character set */
+ return -ENODATA;
+
+ block += 3;
+ quadlets -= 2;
+ for (i = 0; i < quadlets * 4 && i < size - 1; i++) {
+ c = block[i / 4] >> (24 - 8 * (i % 4));
+ if (c == '\0')
+ break;
+ buf[i] = c;
+ }
+ buf[i] = '\0';
+
+ return i;
+}
+
+/**
+ * fw_csr_string - reads a string from the configuration ROM
+ * @directory: e.g. root directory or unit directory
+ * @key: the key of the preceding directory entry
+ * @buf: where to put the string
+ * @size: size of @buf, in bytes
+ *
+ * The string is taken from a minimal ASCII text descriptor leaf after
+ * the immediate entry with @key. The string is zero-terminated.
+ * Returns strlen(buf) or a negative error code.
+ */
+int fw_csr_string(const u32 *directory, int key, char *buf, size_t size)
+{
+ const u32 *leaf = search_leaf(directory, key);
+ if (!leaf)
+ return -ENOENT;
+
+ return textual_leaf_to_string(leaf, buf, size);
+}
+EXPORT_SYMBOL(fw_csr_string);
+
static bool is_fw_unit(struct device *dev);
-static int match_unit_directory(u32 *directory, u32 match_flags,
+static int match_unit_directory(const u32 *directory, u32 match_flags,
const struct ieee1394_device_id *id)
{
struct fw_csr_iterator ci;
@@ -195,7 +262,7 @@ static ssize_t show_immediate(struct device *dev,
struct config_rom_attribute *attr =
container_of(dattr, struct config_rom_attribute, attr);
struct fw_csr_iterator ci;
- u32 *dir;
+ const u32 *dir;
int key, value, ret = -ENOENT;
down_read(&fw_device_rwsem);
@@ -226,10 +293,10 @@ static ssize_t show_text_leaf(struct device *dev,
{
struct config_rom_attribute *attr =
container_of(dattr, struct config_rom_attribute, attr);
- struct fw_csr_iterator ci;
- u32 *dir, *block = NULL, *p, *end;
- int length, key, value, last_key = 0, ret = -ENOENT;
- char *b;
+ const u32 *dir;
+ size_t bufsize;
+ char dummy_buf[2];
+ int ret;
down_read(&fw_device_rwsem);
@@ -238,40 +305,23 @@ static ssize_t show_text_leaf(struct device *dev,
else
dir = fw_device(dev)->config_rom + 5;
- fw_csr_iterator_init(&ci, dir);
- while (fw_csr_iterator_next(&ci, &key, &value)) {
- if (attr->key == last_key &&
- key == (CSR_DESCRIPTOR | CSR_LEAF))
- block = ci.p - 1 + value;
- last_key = key;
+ if (buf) {
+ bufsize = PAGE_SIZE - 1;
+ } else {
+ buf = dummy_buf;
+ bufsize = 1;
}
- if (block == NULL)
- goto out;
-
- length = min(block[0] >> 16, 256U);
- if (length < 3)
- goto out;
-
- if (block[1] != 0 || block[2] != 0)
- /* Unknown encoding. */
- goto out;
+ ret = fw_csr_string(dir, attr->key, buf, bufsize);
- if (buf == NULL) {
- ret = length * 4;
- goto out;
+ if (ret >= 0) {
+ /* Strip trailing whitespace and add newline. */
+ while (ret > 0 && isspace(buf[ret - 1]))
+ ret--;
+ strcpy(buf + ret, "\n");
+ ret++;
}
- b = buf;
- end = &block[length + 1];
- for (p = &block[3]; p < end; p++, b += 4)
- * (u32 *) b = (__force u32) __cpu_to_be32(*p);
-
- /* Strip trailing whitespace and add newline. */
- while (b--, (isspace(*b) || *b == '\0') && b > buf);
- strcpy(b + 1, "\n");
- ret = b + 2 - buf;
- out:
up_read(&fw_device_rwsem);
return ret;
@@ -371,7 +421,7 @@ static ssize_t guid_show(struct device *dev,
return ret;
}
-static int units_sprintf(char *buf, u32 *directory)
+static int units_sprintf(char *buf, const u32 *directory)
{
struct fw_csr_iterator ci;
int key, value;
@@ -441,28 +491,29 @@ static int read_rom(struct fw_device *device,
return rcode;
}
-#define READ_BIB_ROM_SIZE 256
-#define READ_BIB_STACK_SIZE 16
+#define MAX_CONFIG_ROM_SIZE 256
/*
* Read the bus info block, perform a speed probe, and read all of the rest of
* the config ROM. We do all this with a cached bus generation. If the bus
- * generation changes under us, read_bus_info_block will fail and get retried.
+ * generation changes under us, read_config_rom will fail and get retried.
* It's better to start all over in this case because the node from which we
* are reading the ROM may have changed the ROM during the reset.
*/
-static int read_bus_info_block(struct fw_device *device, int generation)
+static int read_config_rom(struct fw_device *device, int generation)
{
- u32 *rom, *stack, *old_rom, *new_rom;
+ const u32 *old_rom, *new_rom;
+ u32 *rom, *stack;
u32 sp, key;
int i, end, length, ret = -1;
- rom = kmalloc(sizeof(*rom) * READ_BIB_ROM_SIZE +
- sizeof(*stack) * READ_BIB_STACK_SIZE, GFP_KERNEL);
+ rom = kmalloc(sizeof(*rom) * MAX_CONFIG_ROM_SIZE +
+ sizeof(*stack) * MAX_CONFIG_ROM_SIZE, GFP_KERNEL);
if (rom == NULL)
return -ENOMEM;
- stack = &rom[READ_BIB_ROM_SIZE];
+ stack = &rom[MAX_CONFIG_ROM_SIZE];
+ memset(rom, 0, sizeof(*rom) * MAX_CONFIG_ROM_SIZE);
device->max_speed = SCODE_100;
@@ -529,40 +580,54 @@ static int read_bus_info_block(struct fw_device *device, int generation)
*/
key = stack[--sp];
i = key & 0xffffff;
- if (i >= READ_BIB_ROM_SIZE)
- /*
- * The reference points outside the standard
- * config rom area, something's fishy.
- */
+ if (WARN_ON(i >= MAX_CONFIG_ROM_SIZE))
goto out;
/* Read header quadlet for the block to get the length. */
if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
goto out;
end = i + (rom[i] >> 16) + 1;
- i++;
- if (end > READ_BIB_ROM_SIZE)
+ if (end > MAX_CONFIG_ROM_SIZE) {
/*
- * This block extends outside standard config
- * area (and the array we're reading it
- * into). That's broken, so ignore this
- * device.
+ * This block extends outside the config ROM which is
+ * a firmware bug. Ignore this whole block, i.e.
+ * simply set a fake block length of 0.
*/
- goto out;
+ fw_error("skipped invalid ROM block %x at %llx\n",
+ rom[i],
+ i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM);
+ rom[i] = 0;
+ end = i;
+ }
+ i++;
/*
* Now read in the block. If this is a directory
* block, check the entries as we read them to see if
* it references another block, and push it in that case.
*/
- while (i < end) {
+ for (; i < end; i++) {
if (read_rom(device, generation, i, &rom[i]) !=
RCODE_COMPLETE)
goto out;
- if ((key >> 30) == 3 && (rom[i] >> 30) > 1 &&
- sp < READ_BIB_STACK_SIZE)
- stack[sp++] = i + rom[i];
- i++;
+
+ if ((key >> 30) != 3 || (rom[i] >> 30) < 2)
+ continue;
+ /*
+ * Offset points outside the ROM. May be a firmware
+ * bug or an Extended ROM entry (IEEE 1212-2001 clause
+ * 7.7.18). Simply overwrite this pointer here by a
+ * fake immediate entry so that later iterators over
+ * the ROM don't have to check offsets all the time.
+ */
+ if (i + (rom[i] & 0xffffff) >= MAX_CONFIG_ROM_SIZE) {
+ fw_error("skipped unsupported ROM entry %x at %llx\n",
+ rom[i],
+ i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM);
+ rom[i] = 0;
+ continue;
+ }
+ stack[sp++] = i + rom[i];
}
if (length < i)
length = i;
@@ -762,9 +827,9 @@ static int update_unit(struct device *dev, void *data)
struct fw_driver *driver = (struct fw_driver *)dev->driver;
if (is_fw_unit(dev) && driver != NULL && driver->update != NULL) {
- down(&dev->sem);
+ device_lock(dev);
driver->update(unit);
- up(&dev->sem);
+ device_unlock(dev);
}
return 0;
@@ -905,7 +970,7 @@ static void fw_device_init(struct work_struct *work)
* device.
*/
- if (read_bus_info_block(device, device->generation) < 0) {
+ if (read_config_rom(device, device->generation) < 0) {
if (device->config_rom_retries < MAX_RETRIES &&
atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
device->config_rom_retries++;
@@ -1022,7 +1087,7 @@ enum {
};
/* Reread and compare bus info block and header of root directory */
-static int reread_bus_info_block(struct fw_device *device, int generation)
+static int reread_config_rom(struct fw_device *device, int generation)
{
u32 q;
int i;
@@ -1048,7 +1113,7 @@ static void fw_device_refresh(struct work_struct *work)
struct fw_card *card = device->card;
int node_id = device->node_id;
- switch (reread_bus_info_block(device, device->generation)) {
+ switch (reread_config_rom(device, device->generation)) {
case REREAD_BIB_ERROR:
if (device->config_rom_retries < MAX_RETRIES / 2 &&
atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
@@ -1082,7 +1147,7 @@ static void fw_device_refresh(struct work_struct *work)
*/
device_for_each_child(&device->device, NULL, shutdown_unit);
- if (read_bus_info_block(device, device->generation) < 0) {
+ if (read_config_rom(device, device->generation) < 0) {
if (device->config_rom_retries < MAX_RETRIES &&
atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
device->config_rom_retries++;
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 495849eb13cc..673b03f8b4ec 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -921,23 +921,15 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
void *payload, size_t length, void *callback_data)
{
int reg = offset & ~CSR_REGISTER_BASE;
- unsigned long long bus_time;
__be32 *data = payload;
int rcode = RCODE_COMPLETE;
switch (reg) {
case CSR_CYCLE_TIME:
- case CSR_BUS_TIME:
- if (!TCODE_IS_READ_REQUEST(tcode) || length != 4) {
- rcode = RCODE_TYPE_ERROR;
- break;
- }
-
- bus_time = card->driver->get_bus_time(card);
- if (reg == CSR_CYCLE_TIME)
- *data = cpu_to_be32(bus_time);
+ if (TCODE_IS_READ_REQUEST(tcode) && length == 4)
+ *data = cpu_to_be32(card->driver->get_cycle_time(card));
else
- *data = cpu_to_be32(bus_time >> 25);
+ rcode = RCODE_TYPE_ERROR;
break;
case CSR_BROADCAST_CHANNEL:
@@ -968,6 +960,9 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
case CSR_BUSY_TIMEOUT:
/* FIXME: Implement this. */
+ case CSR_BUS_TIME:
+ /* Useless without initialization by the bus manager. */
+
default:
rcode = RCODE_ADDRESS_ERROR;
break;
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index ed3b1a765c00..fb0321300cce 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -70,7 +70,7 @@ struct fw_card_driver {
int (*enable_phys_dma)(struct fw_card *card,
int node_id, int generation);
- u64 (*get_bus_time)(struct fw_card *card);
+ u32 (*get_cycle_time)(struct fw_card *card);
struct fw_iso_context *
(*allocate_iso_context)(struct fw_card *card,
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index cbaf420c36c5..2d3dc7ded0a9 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -893,20 +893,31 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,
static struct kmem_cache *fwnet_packet_task_cache;
+static void fwnet_free_ptask(struct fwnet_packet_task *ptask)
+{
+ dev_kfree_skb_any(ptask->skb);
+ kmem_cache_free(fwnet_packet_task_cache, ptask);
+}
+
static int fwnet_send_packet(struct fwnet_packet_task *ptask);
static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
{
- struct fwnet_device *dev;
+ struct fwnet_device *dev = ptask->dev;
unsigned long flags;
-
- dev = ptask->dev;
+ bool free;
spin_lock_irqsave(&dev->lock, flags);
- list_del(&ptask->pt_link);
- spin_unlock_irqrestore(&dev->lock, flags);
- ptask->outstanding_pkts--; /* FIXME access inside lock */
+ ptask->outstanding_pkts--;
+
+ /* Check whether we or the networking TX soft-IRQ is last user. */
+ free = (ptask->outstanding_pkts == 0 && !list_empty(&ptask->pt_link));
+
+ if (ptask->outstanding_pkts == 0)
+ list_del(&ptask->pt_link);
+
+ spin_unlock_irqrestore(&dev->lock, flags);
if (ptask->outstanding_pkts > 0) {
u16 dg_size;
@@ -951,10 +962,10 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
ptask->max_payload = skb->len + RFC2374_FRAG_HDR_SIZE;
}
fwnet_send_packet(ptask);
- } else {
- dev_kfree_skb_any(ptask->skb);
- kmem_cache_free(fwnet_packet_task_cache, ptask);
}
+
+ if (free)
+ fwnet_free_ptask(ptask);
}
static void fwnet_write_complete(struct fw_card *card, int rcode,
@@ -977,6 +988,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
unsigned tx_len;
struct rfc2734_header *bufhdr;
unsigned long flags;
+ bool free;
dev = ptask->dev;
tx_len = ptask->max_payload;
@@ -1022,12 +1034,16 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
generation, SCODE_100, 0ULL, ptask->skb->data,
tx_len + 8, fwnet_write_complete, ptask);
- /* FIXME race? */
spin_lock_irqsave(&dev->lock, flags);
- list_add_tail(&ptask->pt_link, &dev->broadcasted_list);
+
+ /* If the AT tasklet already ran, we may be last user. */
+ free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link));
+ if (!free)
+ list_add_tail(&ptask->pt_link, &dev->broadcasted_list);
+
spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
+ goto out;
}
fw_send_request(dev->card, &ptask->transaction,
@@ -1035,12 +1051,19 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
ptask->generation, ptask->speed, ptask->fifo_addr,
ptask->skb->data, tx_len, fwnet_write_complete, ptask);
- /* FIXME race? */
spin_lock_irqsave(&dev->lock, flags);
- list_add_tail(&ptask->pt_link, &dev->sent_list);
+
+ /* If the AT tasklet already ran, we may be last user. */
+ free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link));
+ if (!free)
+ list_add_tail(&ptask->pt_link, &dev->sent_list);
+
spin_unlock_irqrestore(&dev->lock, flags);
dev->netdev->trans_start = jiffies;
+ out:
+ if (free)
+ fwnet_free_ptask(ptask);
return 0;
}
@@ -1298,6 +1321,8 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
spin_unlock_irqrestore(&dev->lock, flags);
ptask->max_payload = max_payload;
+ INIT_LIST_HEAD(&ptask->pt_link);
+
fwnet_send_packet(ptask);
return NETDEV_TX_OK;
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index a61571c63c59..75dc6988cffd 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -38,7 +38,6 @@
#include <linux/spinlock.h>
#include <linux/string.h>
-#include <asm/atomic.h>
#include <asm/byteorder.h>
#include <asm/page.h>
#include <asm/system.h>
@@ -73,20 +72,6 @@ struct descriptor {
__le16 transfer_status;
} __attribute__((aligned(16)));
-struct db_descriptor {
- __le16 first_size;
- __le16 control;
- __le16 second_req_count;
- __le16 first_req_count;
- __le32 branch_address;
- __le16 second_res_count;
- __le16 first_res_count;
- __le32 reserved0;
- __le32 first_buffer;
- __le32 second_buffer;
- __le32 reserved1;
-} __attribute__((aligned(16)));
-
#define CONTROL_SET(regs) (regs)
#define CONTROL_CLEAR(regs) ((regs) + 4)
#define COMMAND_PTR(regs) ((regs) + 12)
@@ -181,31 +166,16 @@ struct fw_ohci {
struct fw_card card;
__iomem char *registers;
- dma_addr_t self_id_bus;
- __le32 *self_id_cpu;
- struct tasklet_struct bus_reset_tasklet;
int node_id;
int generation;
int request_generation; /* for timestamping incoming requests */
- atomic_t bus_seconds;
-
- bool use_dualbuffer;
- bool old_uninorth;
- bool bus_reset_packet_quirk;
+ unsigned quirks;
/*
* Spinlock for accessing fw_ohci data. Never call out of
* this driver with this lock held.
*/
spinlock_t lock;
- u32 self_id_buffer[512];
-
- /* Config rom buffers */
- __be32 *config_rom;
- dma_addr_t config_rom_bus;
- __be32 *next_config_rom;
- dma_addr_t next_config_rom_bus;
- __be32 next_header;
struct ar_context ar_request_ctx;
struct ar_context ar_response_ctx;
@@ -217,6 +187,18 @@ struct fw_ohci {
u64 ir_context_channels;
u32 ir_context_mask;
struct iso_context *ir_context_list;
+
+ __be32 *config_rom;
+ dma_addr_t config_rom_bus;
+ __be32 *next_config_rom;
+ dma_addr_t next_config_rom_bus;
+ __be32 next_header;
+
+ __le32 *self_id_cpu;
+ dma_addr_t self_id_bus;
+ struct tasklet_struct bus_reset_tasklet;
+
+ u32 self_id_buffer[512];
};
static inline struct fw_ohci *fw_ohci(struct fw_card *card)
@@ -249,6 +231,30 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card)
static char ohci_driver_name[] = KBUILD_MODNAME;
+#define QUIRK_CYCLE_TIMER 1
+#define QUIRK_RESET_PACKET 2
+#define QUIRK_BE_HEADERS 4
+
+/* In case of multiple matches in ohci_quirks[], only the first one is used. */
+static const struct {
+ unsigned short vendor, device, flags;
+} ohci_quirks[] = {
+ {PCI_VENDOR_ID_TI, PCI_ANY_ID, QUIRK_RESET_PACKET},
+ {PCI_VENDOR_ID_AL, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
+ {PCI_VENDOR_ID_NEC, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
+ {PCI_VENDOR_ID_VIA, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
+ {PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, QUIRK_BE_HEADERS},
+};
+
+/* This overrides anything that was found in ohci_quirks[]. */
+static int param_quirks;
+module_param_named(quirks, param_quirks, int, 0644);
+MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
+ ", nonatomic cycle timer = " __stringify(QUIRK_CYCLE_TIMER)
+ ", reset packet generation = " __stringify(QUIRK_RESET_PACKET)
+ ", AR/selfID endianess = " __stringify(QUIRK_BE_HEADERS)
+ ")");
+
#ifdef CONFIG_FIREWIRE_OHCI_DEBUG
#define OHCI_PARAM_DEBUG_AT_AR 1
@@ -275,7 +281,7 @@ static void log_irqs(u32 evt)
!(evt & OHCI1394_busReset))
return;
- fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
+ fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
evt & OHCI1394_selfIDComplete ? " selfID" : "",
evt & OHCI1394_RQPkt ? " AR_req" : "",
evt & OHCI1394_RSPkt ? " AR_resp" : "",
@@ -285,7 +291,6 @@ static void log_irqs(u32 evt)
evt & OHCI1394_isochTx ? " IT" : "",
evt & OHCI1394_postedWriteErr ? " postedWriteErr" : "",
evt & OHCI1394_cycleTooLong ? " cycleTooLong" : "",
- evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "",
evt & OHCI1394_cycleInconsistent ? " cycleInconsistent" : "",
evt & OHCI1394_regAccessFail ? " regAccessFail" : "",
evt & OHCI1394_busReset ? " busReset" : "",
@@ -293,8 +298,7 @@ static void log_irqs(u32 evt)
OHCI1394_RSPkt | OHCI1394_reqTxComplete |
OHCI1394_respTxComplete | OHCI1394_isochRx |
OHCI1394_isochTx | OHCI1394_postedWriteErr |
- OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
- OHCI1394_cycleInconsistent |
+ OHCI1394_cycleTooLong | OHCI1394_cycleInconsistent |
OHCI1394_regAccessFail | OHCI1394_busReset)
? " ?" : "");
}
@@ -524,7 +528,7 @@ static void ar_context_release(struct ar_context *ctx)
#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
#define cond_le32_to_cpu(v) \
- (ohci->old_uninorth ? (__force __u32)(v) : le32_to_cpu(v))
+ (ohci->quirks & QUIRK_BE_HEADERS ? (__force __u32)(v) : le32_to_cpu(v))
#else
#define cond_le32_to_cpu(v) le32_to_cpu(v)
#endif
@@ -605,7 +609,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
* at a slightly incorrect time (in bus_reset_tasklet).
*/
if (evt == OHCI1394_evt_bus_reset) {
- if (!ohci->bus_reset_packet_quirk)
+ if (!(ohci->quirks & QUIRK_RESET_PACKET))
ohci->request_generation = (p.header[2] >> 16) & 0xff;
} else if (ctx == &ohci->ar_request_ctx) {
fw_core_handle_request(&ohci->card, &p);
@@ -1329,7 +1333,7 @@ static void bus_reset_tasklet(unsigned long data)
context_stop(&ohci->at_response_ctx);
reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
- if (ohci->bus_reset_packet_quirk)
+ if (ohci->quirks & QUIRK_RESET_PACKET)
ohci->request_generation = generation;
/*
@@ -1384,7 +1388,7 @@ static void bus_reset_tasklet(unsigned long data)
static irqreturn_t irq_handler(int irq, void *data)
{
struct fw_ohci *ohci = data;
- u32 event, iso_event, cycle_time;
+ u32 event, iso_event;
int i;
event = reg_read(ohci, OHCI1394_IntEventClear);
@@ -1454,12 +1458,6 @@ static irqreturn_t irq_handler(int irq, void *data)
fw_notify("isochronous cycle inconsistent\n");
}
- if (event & OHCI1394_cycle64Seconds) {
- cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
- if ((cycle_time & 0x80000000) == 0)
- atomic_inc(&ohci->bus_seconds);
- }
-
return IRQ_HANDLED;
}
@@ -1553,8 +1551,7 @@ static int ohci_enable(struct fw_card *card,
OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
OHCI1394_isochRx | OHCI1394_isochTx |
OHCI1394_postedWriteErr | OHCI1394_cycleTooLong |
- OHCI1394_cycleInconsistent |
- OHCI1394_cycle64Seconds | OHCI1394_regAccessFail |
+ OHCI1394_cycleInconsistent | OHCI1394_regAccessFail |
OHCI1394_masterIntEnable);
if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
@@ -1794,16 +1791,61 @@ static int ohci_enable_phys_dma(struct fw_card *card,
#endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */
}
-static u64 ohci_get_bus_time(struct fw_card *card)
+static u32 cycle_timer_ticks(u32 cycle_timer)
{
- struct fw_ohci *ohci = fw_ohci(card);
- u32 cycle_time;
- u64 bus_time;
+ u32 ticks;
+
+ ticks = cycle_timer & 0xfff;
+ ticks += 3072 * ((cycle_timer >> 12) & 0x1fff);
+ ticks += (3072 * 8000) * (cycle_timer >> 25);
+
+ return ticks;
+}
- cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
- bus_time = ((u64)atomic_read(&ohci->bus_seconds) << 32) | cycle_time;
+/*
+ * Some controllers exhibit one or more of the following bugs when updating the
+ * iso cycle timer register:
+ * - When the lowest six bits are wrapping around to zero, a read that happens
+ * at the same time will return garbage in the lowest ten bits.
+ * - When the cycleOffset field wraps around to zero, the cycleCount field is
+ * not incremented for about 60 ns.
+ * - Occasionally, the entire register reads zero.
+ *
+ * To catch these, we read the register three times and ensure that the
+ * difference between each two consecutive reads is approximately the same, i.e.
+ * less than twice the other. Furthermore, any negative difference indicates an
+ * error. (A PCI read should take at least 20 ticks of the 24.576 MHz timer to
+ * execute, so we have enough precision to compute the ratio of the differences.)
+ */
+static u32 ohci_get_cycle_time(struct fw_card *card)
+{
+ struct fw_ohci *ohci = fw_ohci(card);
+ u32 c0, c1, c2;
+ u32 t0, t1, t2;
+ s32 diff01, diff12;
+ int i;
- return bus_time;
+ c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+
+ if (ohci->quirks & QUIRK_CYCLE_TIMER) {
+ i = 0;
+ c1 = c2;
+ c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+ do {
+ c0 = c1;
+ c1 = c2;
+ c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+ t0 = cycle_timer_ticks(c0);
+ t1 = cycle_timer_ticks(c1);
+ t2 = cycle_timer_ticks(c2);
+ diff01 = t1 - t0;
+ diff12 = t2 - t1;
+ } while ((diff01 <= 0 || diff12 <= 0 ||
+ diff01 / diff12 >= 2 || diff12 / diff01 >= 2)
+ && i++ < 20);
+ }
+
+ return c2;
}
static void copy_iso_headers(struct iso_context *ctx, void *p)
@@ -1828,52 +1870,6 @@ static void copy_iso_headers(struct iso_context *ctx, void *p)
ctx->header_length += ctx->base.header_size;
}
-static int handle_ir_dualbuffer_packet(struct context *context,
- struct descriptor *d,
- struct descriptor *last)
-{
- struct iso_context *ctx =
- container_of(context, struct iso_context, context);
- struct db_descriptor *db = (struct db_descriptor *) d;
- __le32 *ir_header;
- size_t header_length;
- void *p, *end;
-
- if (db->first_res_count != 0 && db->second_res_count != 0) {
- if (ctx->excess_bytes <= le16_to_cpu(db->second_req_count)) {
- /* This descriptor isn't done yet, stop iteration. */
- return 0;
- }
- ctx->excess_bytes -= le16_to_cpu(db->second_req_count);
- }
-
- header_length = le16_to_cpu(db->first_req_count) -
- le16_to_cpu(db->first_res_count);
-
- p = db + 1;
- end = p + header_length;
- while (p < end) {
- copy_iso_headers(ctx, p);
- ctx->excess_bytes +=
- (le32_to_cpu(*(__le32 *)(p + 4)) >> 16) & 0xffff;
- p += max(ctx->base.header_size, (size_t)8);
- }
-
- ctx->excess_bytes -= le16_to_cpu(db->second_req_count) -
- le16_to_cpu(db->second_res_count);
-
- if (le16_to_cpu(db->control) & DESCRIPTOR_IRQ_ALWAYS) {
- ir_header = (__le32 *) (db + 1);
- ctx->base.callback(&ctx->base,
- le32_to_cpu(ir_header[0]) & 0xffff,
- ctx->header_length, ctx->header,
- ctx->base.callback_data);
- ctx->header_length = 0;
- }
-
- return 1;
-}
-
static int handle_ir_packet_per_buffer(struct context *context,
struct descriptor *d,
struct descriptor *last)
@@ -1960,10 +1956,7 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
channels = &ohci->ir_context_channels;
mask = &ohci->ir_context_mask;
list = ohci->ir_context_list;
- if (ohci->use_dualbuffer)
- callback = handle_ir_dualbuffer_packet;
- else
- callback = handle_ir_packet_per_buffer;
+ callback = handle_ir_packet_per_buffer;
}
spin_lock_irqsave(&ohci->lock, flags);
@@ -2026,8 +2019,6 @@ static int ohci_start_iso(struct fw_iso_context *base,
} else {
index = ctx - ohci->ir_context_list;
control = IR_CONTEXT_ISOCH_HEADER;
- if (ohci->use_dualbuffer)
- control |= IR_CONTEXT_DUAL_BUFFER_MODE;
match = (tags << 28) | (sync << 8) | ctx->base.channel;
if (cycle >= 0) {
match |= (cycle & 0x07fff) << 12;
@@ -2101,11 +2092,6 @@ static int ohci_queue_iso_transmit(struct fw_iso_context *base,
u32 payload_index, payload_end_index, next_page_index;
int page, end_page, i, length, offset;
- /*
- * FIXME: Cycle lost behavior should be configurable: lose
- * packet, retransmit or terminate..
- */
-
p = packet;
payload_index = payload;
@@ -2135,6 +2121,14 @@ static int ohci_queue_iso_transmit(struct fw_iso_context *base,
if (!p->skip) {
d[0].control = cpu_to_le16(DESCRIPTOR_KEY_IMMEDIATE);
d[0].req_count = cpu_to_le16(8);
+ /*
+ * Link the skip address to this descriptor itself. This causes
+ * a context to skip a cycle whenever lost cycles or FIFO
+ * overruns occur, without dropping the data. The application
+ * should then decide whether this is an error condition or not.
+ * FIXME: Make the context's cycle-lost behaviour configurable?
+ */
+ d[0].branch_address = cpu_to_le32(d_bus | z);
header = (__le32 *) &d[1];
header[0] = cpu_to_le32(IT_HEADER_SY(p->sy) |
@@ -2185,92 +2179,6 @@ static int ohci_queue_iso_transmit(struct fw_iso_context *base,
return 0;
}
-static int ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
- struct fw_iso_packet *packet,
- struct fw_iso_buffer *buffer,
- unsigned long payload)
-{
- struct iso_context *ctx = container_of(base, struct iso_context, base);
- struct db_descriptor *db = NULL;
- struct descriptor *d;
- struct fw_iso_packet *p;
- dma_addr_t d_bus, page_bus;
- u32 z, header_z, length, rest;
- int page, offset, packet_count, header_size;
-
- /*
- * FIXME: Cycle lost behavior should be configurable: lose
- * packet, retransmit or terminate..
- */
-
- p = packet;
- z = 2;
-
- /*
- * The OHCI controller puts the isochronous header and trailer in the
- * buffer, so we need at least 8 bytes.
- */
- packet_count = p->header_length / ctx->base.header_size;
- header_size = packet_count * max(ctx->base.header_size, (size_t)8);
-
- /* Get header size in number of descriptors. */
- header_z = DIV_ROUND_UP(header_size, sizeof(*d));
- page = payload >> PAGE_SHIFT;
- offset = payload & ~PAGE_MASK;
- rest = p->payload_length;
- /*
- * The controllers I've tested have not worked correctly when
- * second_req_count is zero. Rather than do something we know won't
- * work, return an error
- */
- if (rest == 0)
- return -EINVAL;
-
- while (rest > 0) {
- d = context_get_descriptors(&ctx->context,
- z + header_z, &d_bus);
- if (d == NULL)
- return -ENOMEM;
-
- db = (struct db_descriptor *) d;
- db->control = cpu_to_le16(DESCRIPTOR_STATUS |
- DESCRIPTOR_BRANCH_ALWAYS);
- db->first_size =
- cpu_to_le16(max(ctx->base.header_size, (size_t)8));
- if (p->skip && rest == p->payload_length) {
- db->control |= cpu_to_le16(DESCRIPTOR_WAIT);
- db->first_req_count = db->first_size;
- } else {
- db->first_req_count = cpu_to_le16(header_size);
- }
- db->first_res_count = db->first_req_count;
- db->first_buffer = cpu_to_le32(d_bus + sizeof(*db));
-
- if (p->skip && rest == p->payload_length)
- length = 4;
- else if (offset + rest < PAGE_SIZE)
- length = rest;
- else
- length = PAGE_SIZE - offset;
-
- db->second_req_count = cpu_to_le16(length);
- db->second_res_count = db->second_req_count;
- page_bus = page_private(buffer->pages[page]);
- db->second_buffer = cpu_to_le32(page_bus + offset);
-
- if (p->interrupt && length == rest)
- db->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS);
-
- context_append(&ctx->context, d, z, header_z);
- offset = (offset + length) & ~PAGE_MASK;
- rest -= length;
- if (offset == 0)
- page++;
- }
-
- return 0;
-}
-
static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base,
struct fw_iso_packet *packet,
struct fw_iso_buffer *buffer,
@@ -2361,9 +2269,6 @@ static int ohci_queue_iso(struct fw_iso_context *base,
spin_lock_irqsave(&ctx->context.ohci->lock, flags);
if (base->type == FW_ISO_CONTEXT_TRANSMIT)
ret = ohci_queue_iso_transmit(base, packet, buffer, payload);
- else if (ctx->context.ohci->use_dualbuffer)
- ret = ohci_queue_iso_receive_dualbuffer(base, packet,
- buffer, payload);
else
ret = ohci_queue_iso_receive_packet_per_buffer(base, packet,
buffer, payload);
@@ -2380,7 +2285,7 @@ static const struct fw_card_driver ohci_driver = {
.send_response = ohci_send_response,
.cancel_packet = ohci_cancel_packet,
.enable_phys_dma = ohci_enable_phys_dma,
- .get_bus_time = ohci_get_bus_time,
+ .get_cycle_time = ohci_get_cycle_time,
.allocate_iso_context = ohci_allocate_iso_context,
.free_iso_context = ohci_free_iso_context,
@@ -2418,16 +2323,13 @@ static void ohci_pmac_off(struct pci_dev *dev)
#define ohci_pmac_off(dev)
#endif /* CONFIG_PPC_PMAC */
-#define PCI_VENDOR_ID_AGERE PCI_VENDOR_ID_ATT
-#define PCI_DEVICE_ID_AGERE_FW643 0x5901
-
static int __devinit pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
struct fw_ohci *ohci;
u32 bus_options, max_receive, link_speed, version;
u64 guid;
- int err;
+ int i, err, n_ir, n_it;
size_t size;
ohci = kzalloc(sizeof(*ohci), GFP_KERNEL);
@@ -2468,35 +2370,15 @@ static int __devinit pci_probe(struct pci_dev *dev,
goto fail_iomem;
}
- version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
-#if 0
- /* FIXME: make it a context option or remove dual-buffer mode */
- ohci->use_dualbuffer = version >= OHCI_VERSION_1_1;
-#endif
-
- /* dual-buffer mode is broken if more than one IR context is active */
- if (dev->vendor == PCI_VENDOR_ID_AGERE &&
- dev->device == PCI_DEVICE_ID_AGERE_FW643)
- ohci->use_dualbuffer = false;
-
- /* dual-buffer mode is broken */
- if (dev->vendor == PCI_VENDOR_ID_RICOH &&
- dev->device == PCI_DEVICE_ID_RICOH_R5C832)
- ohci->use_dualbuffer = false;
-
-/* x86-32 currently doesn't use highmem for dma_alloc_coherent */
-#if !defined(CONFIG_X86_32)
- /* dual-buffer mode is broken with descriptor addresses above 2G */
- if (dev->vendor == PCI_VENDOR_ID_TI &&
- dev->device == PCI_DEVICE_ID_TI_TSB43AB22)
- ohci->use_dualbuffer = false;
-#endif
-
-#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
- ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
- dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
-#endif
- ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
+ for (i = 0; i < ARRAY_SIZE(ohci_quirks); i++)
+ if (ohci_quirks[i].vendor == dev->vendor &&
+ (ohci_quirks[i].device == dev->device ||
+ ohci_quirks[i].device == (unsigned short)PCI_ANY_ID)) {
+ ohci->quirks = ohci_quirks[i].flags;
+ break;
+ }
+ if (param_quirks)
+ ohci->quirks = param_quirks;
ar_context_init(&ohci->ar_request_ctx, ohci,
OHCI1394_AsReqRcvContextControlSet);
@@ -2511,17 +2393,19 @@ static int __devinit pci_probe(struct pci_dev *dev,
OHCI1394_AsRspTrContextControlSet, handle_at_packet);
reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
- ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
+ ohci->ir_context_channels = ~0ULL;
+ ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0);
- size = sizeof(struct iso_context) * hweight32(ohci->it_context_mask);
- ohci->it_context_list = kzalloc(size, GFP_KERNEL);
+ n_ir = hweight32(ohci->ir_context_mask);
+ size = sizeof(struct iso_context) * n_ir;
+ ohci->ir_context_list = kzalloc(size, GFP_KERNEL);
reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0);
- ohci->ir_context_channels = ~0ULL;
- ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
+ ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0);
- size = sizeof(struct iso_context) * hweight32(ohci->ir_context_mask);
- ohci->ir_context_list = kzalloc(size, GFP_KERNEL);
+ n_it = hweight32(ohci->it_context_mask);
+ size = sizeof(struct iso_context) * n_it;
+ ohci->it_context_list = kzalloc(size, GFP_KERNEL);
if (ohci->it_context_list == NULL || ohci->ir_context_list == NULL) {
err = -ENOMEM;
@@ -2548,8 +2432,11 @@ static int __devinit pci_probe(struct pci_dev *dev,
if (err)
goto fail_self_id;
- fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
- dev_name(&dev->dev), version >> 16, version & 0xff);
+ version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
+ fw_notify("Added fw-ohci device %s, OHCI v%x.%x, "
+ "%d IR + %d IT contexts, quirks 0x%x\n",
+ dev_name(&dev->dev), version >> 16, version & 0xff,
+ n_ir, n_it, ohci->quirks);
return 0;
@@ -2657,7 +2544,7 @@ static int pci_resume(struct pci_dev *dev)
}
#endif
-static struct pci_device_id pci_table[] = {
+static const struct pci_device_id pci_table[] = {
{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_FIREWIRE_OHCI, ~0) },
{ }
};
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index d485cdd8cbac..ca264f2fdf0c 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -1014,7 +1014,8 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
return 0;
}
-static int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt, u32 *directory)
+static int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt,
+ const u32 *directory)
{
struct fw_csr_iterator ci;
int key, value;
@@ -1027,7 +1028,7 @@ static int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt, u32 *directory)
return 0;
}
-static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
+static int sbp2_scan_unit_dir(struct sbp2_target *tgt, const u32 *directory,
u32 *model, u32 *firmware_revision)
{
struct fw_csr_iterator ci;
@@ -1571,7 +1572,7 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
sdev->start_stop_pwr_cond = 1;
if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
- blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
+ blk_queue_max_hw_sectors(sdev->request_queue, 128 * 1024 / 512);
blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index 9e4f59dc7f1e..110e24e50883 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -122,7 +122,7 @@ edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
return ret;
}
-static struct sysfs_ops edd_attr_ops = {
+static const struct sysfs_ops edd_attr_ops = {
.show = edd_attr_show,
};
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index f4f709d1370b..082f06ecd327 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -362,7 +362,7 @@ static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr,
return ret;
}
-static struct sysfs_ops efivar_attr_ops = {
+static const struct sysfs_ops efivar_attr_ops = {
.show = efivar_attr_show,
.store = efivar_attr_store,
};
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c
index 051d1ebbd287..ed2801c378de 100644
--- a/drivers/firmware/iscsi_ibft.c
+++ b/drivers/firmware/iscsi_ibft.c
@@ -380,8 +380,7 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
struct ibft_nic *nic = entry->nic;
void *ibft_loc = entry->header;
char *str = buf;
- char *mac;
- int val;
+ __be32 val;
if (!nic)
return 0;
@@ -397,10 +396,8 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
str += sprintf_ipaddr(str, nic->ip_addr);
break;
case ibft_eth_subnet_mask:
- val = ~((1 << (32-nic->subnet_mask_prefix))-1);
- str += sprintf(str, NIPQUAD_FMT,
- (u8)(val >> 24), (u8)(val >> 16),
- (u8)(val >> 8), (u8)(val));
+ val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1));
+ str += sprintf(str, "%pI4", &val);
break;
case ibft_eth_origin:
str += sprintf(str, "%d\n", nic->origin);
@@ -421,10 +418,7 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
str += sprintf(str, "%d\n", nic->vlan);
break;
case ibft_eth_mac:
- mac = nic->mac;
- str += sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x\n",
- (u8)mac[0], (u8)mac[1], (u8)mac[2],
- (u8)mac[3], (u8)mac[4], (u8)mac[5]);
+ str += sprintf(str, "%pM\n", nic->mac);
break;
case ibft_eth_hostname:
str += sprintf_string(str, nic->hostname_len,
@@ -525,7 +519,7 @@ static ssize_t ibft_show_attribute(struct kobject *kobj,
return ret;
}
-static struct sysfs_ops ibft_attr_ops = {
+static const struct sysfs_ops ibft_attr_ops = {
.show = ibft_show_attribute,
};
diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c
index 56f9234781fa..d59f7cad2269 100644
--- a/drivers/firmware/memmap.c
+++ b/drivers/firmware/memmap.c
@@ -74,7 +74,7 @@ static struct attribute *def_attrs[] = {
NULL
};
-static struct sysfs_ops memmap_attr_ops = {
+static const struct sysfs_ops memmap_attr_ops = {
.show = memmap_attr_show,
};
@@ -122,29 +122,53 @@ static int firmware_map_add_entry(u64 start, u64 end,
return 0;
}
+/*
+ * Add memmap entry on sysfs
+ */
+static int add_sysfs_fw_map_entry(struct firmware_map_entry *entry)
+{
+ static int map_entries_nr;
+ static struct kset *mmap_kset;
+
+ if (!mmap_kset) {
+ mmap_kset = kset_create_and_add("memmap", NULL, firmware_kobj);
+ if (!mmap_kset)
+ return -ENOMEM;
+ }
+
+ entry->kobj.kset = mmap_kset;
+ if (kobject_add(&entry->kobj, NULL, "%d", map_entries_nr++))
+ kobject_put(&entry->kobj);
+
+ return 0;
+}
+
/**
- * firmware_map_add() - Adds a firmware mapping entry.
+ * firmware_map_add_hotplug() - Adds a firmware mapping entry when we do
+ * memory hotplug.
* @start: Start of the memory range.
* @end: End of the memory range (inclusive).
* @type: Type of the memory range.
*
- * This function uses kmalloc() for memory
- * allocation. Use firmware_map_add_early() if you want to use the bootmem
- * allocator.
- *
- * That function must be called before late_initcall.
+ * Adds a firmware mapping entry. This function is for memory hotplug, it is
+ * similar to function firmware_map_add_early(). The only difference is that
+ * it will create the syfs entry dynamically.
*
* Returns 0 on success, or -ENOMEM if no memory could be allocated.
**/
-int firmware_map_add(u64 start, u64 end, const char *type)
+int __meminit firmware_map_add_hotplug(u64 start, u64 end, const char *type)
{
struct firmware_map_entry *entry;
- entry = kmalloc(sizeof(struct firmware_map_entry), GFP_ATOMIC);
+ entry = kzalloc(sizeof(struct firmware_map_entry), GFP_ATOMIC);
if (!entry)
return -ENOMEM;
- return firmware_map_add_entry(start, end, type, entry);
+ firmware_map_add_entry(start, end, type, entry);
+ /* create the memmap entry */
+ add_sysfs_fw_map_entry(entry);
+
+ return 0;
}
/**
@@ -154,7 +178,7 @@ int firmware_map_add(u64 start, u64 end, const char *type)
* @type: Type of the memory range.
*
* Adds a firmware mapping entry. This function uses the bootmem allocator
- * for memory allocation. Use firmware_map_add() if you want to use kmalloc().
+ * for memory allocation.
*
* That function must be called before late_initcall.
*
@@ -214,19 +238,10 @@ static ssize_t memmap_attr_show(struct kobject *kobj,
*/
static int __init memmap_init(void)
{
- int i = 0;
struct firmware_map_entry *entry;
- struct kset *memmap_kset;
-
- memmap_kset = kset_create_and_add("memmap", NULL, firmware_kobj);
- if (WARN_ON(!memmap_kset))
- return -ENOMEM;
- list_for_each_entry(entry, &map_entries, list) {
- entry->kobj.kset = memmap_kset;
- if (kobject_add(&entry->kobj, NULL, "%d", i++))
- kobject_put(&entry->kobj);
- }
+ list_for_each_entry(entry, &map_entries, list)
+ add_sysfs_fw_map_entry(entry);
return 0;
}
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 1f1d88ae68d6..fee678f74a19 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -65,8 +65,17 @@ config GPIO_SYSFS
# put expanders in the right section, in alphabetical order
+config GPIO_MAX730X
+ tristate
+
comment "Memory mapped GPIO expanders:"
+config GPIO_IT8761E
+ tristate "IT8761E GPIO support"
+ depends on GPIOLIB
+ help
+ Say yes here to support GPIO functionality of IT8761E super I/O chip.
+
config GPIO_PL061
bool "PrimeCell PL061 GPIO support"
depends on ARM_AMBA
@@ -85,8 +94,32 @@ config GPIO_VR41XX
help
Say yes here to support the NEC VR4100 series General-purpose I/O Uint
+config GPIO_SCH
+ tristate "Intel SCH GPIO"
+ depends on GPIOLIB && PCI
+ select MFD_CORE
+ select LPC_SCH
+ help
+ Say yes here to support GPIO interface on Intel Poulsbo SCH.
+ The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
+ powered by the core power rail and are turned off during sleep
+ modes (S3 and higher). The remaining four GPIOs are powered by
+ the Intel SCH suspend power supply. These GPIOs remain
+ active during S3. The suspend powered GPIOs can be used to wake the
+ system from the Suspend-to-RAM state.
+
+ This driver can also be built as a module. If so, the module
+ will be called sch-gpio.
+
comment "I2C GPIO expanders:"
+config GPIO_MAX7300
+ tristate "Maxim MAX7300 GPIO expander"
+ depends on I2C
+ select GPIO_MAX730X
+ help
+ GPIO driver for Maxim MAX7301 I2C-based GPIO expander.
+
config GPIO_MAX732X
tristate "MAX7319, MAX7320-7327 I2C Port Expanders"
depends on I2C
@@ -124,6 +157,13 @@ config GPIO_PCA953X
This driver can also be built as a module. If so, the module
will be called pca953x.
+config GPIO_PCA953X_IRQ
+ bool "Interrupt controller support for PCA953x"
+ depends on GPIO_PCA953X=y
+ help
+ Say yes here to enable the pca953x to be used as an interrupt
+ controller. It requires the driver to be built in the kernel.
+
config GPIO_PCF857X
tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders"
depends on I2C
@@ -162,6 +202,20 @@ config GPIO_WM831X
Say yes here to access the GPIO signals of WM831x power management
chips from Wolfson Microelectronics.
+config GPIO_WM8350
+ tristate "WM8350 GPIOs"
+ depends on MFD_WM8350
+ help
+ Say yes here to access the GPIO signals of WM8350 power management
+ chips from Wolfson Microelectronics.
+
+config GPIO_WM8994
+ tristate "WM8994 GPIOs"
+ depends on MFD_WM8994
+ help
+ Say yes here to access the GPIO signals of WM8994 audio hub
+ CODECs from Wolfson Microelectronics.
+
config GPIO_ADP5520
tristate "GPIO Support for ADP5520 PMIC"
depends on PMIC_ADP5520
@@ -226,8 +280,9 @@ comment "SPI GPIO expanders:"
config GPIO_MAX7301
tristate "Maxim MAX7301 GPIO expander"
depends on SPI_MASTER
+ select GPIO_MAX730X
help
- gpio driver for Maxim MAX7301 SPI GPIO expander.
+ GPIO driver for Maxim MAX7301 SPI-based GPIO expander.
config GPIO_MCP23S08
tristate "Microchip MCP23S08 I/O expander"
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 48687238edb1..10f3f8d958b1 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -7,6 +7,8 @@ obj-$(CONFIG_GPIOLIB) += gpiolib.o
obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o
obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o
obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o
+obj-$(CONFIG_GPIO_MAX730X) += max730x.o
+obj-$(CONFIG_GPIO_MAX7300) += max7300.o
obj-$(CONFIG_GPIO_MAX7301) += max7301.o
obj-$(CONFIG_GPIO_MAX732X) += max732x.o
obj-$(CONFIG_GPIO_MC33880) += mc33880.o
@@ -20,5 +22,9 @@ obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o
obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o
obj-$(CONFIG_GPIO_CS5535) += cs5535-gpio.o
obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o
+obj-$(CONFIG_GPIO_IT8761E) += it8761e_gpio.o
obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o
+obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o
+obj-$(CONFIG_GPIO_WM8994) += wm8994-gpio.o
+obj-$(CONFIG_GPIO_SCH) += sch_gpio.o \ No newline at end of file
diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c
index 0fdbe94f24a3..0c3c498f2260 100644
--- a/drivers/gpio/cs5535-gpio.c
+++ b/drivers/gpio/cs5535-gpio.c
@@ -154,7 +154,7 @@ static int chip_gpio_request(struct gpio_chip *c, unsigned offset)
static int chip_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- return cs5535_gpio_isset(offset, GPIO_OUTPUT_VAL);
+ return cs5535_gpio_isset(offset, GPIO_READ_BACK);
}
static void chip_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
@@ -172,6 +172,7 @@ static int chip_direction_input(struct gpio_chip *c, unsigned offset)
spin_lock_irqsave(&chip->lock, flags);
__cs5535_gpio_set(chip, offset, GPIO_INPUT_ENABLE);
+ __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_ENABLE);
spin_unlock_irqrestore(&chip->lock, flags);
return 0;
@@ -184,6 +185,7 @@ static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val)
spin_lock_irqsave(&chip->lock, flags);
+ __cs5535_gpio_set(chip, offset, GPIO_INPUT_ENABLE);
__cs5535_gpio_set(chip, offset, GPIO_OUTPUT_ENABLE);
if (val)
__cs5535_gpio_set(chip, offset, GPIO_OUTPUT_VAL);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 350842ad3632..6d1b86661e63 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -623,7 +623,9 @@ static const struct attribute_group gpiochip_attr_group = {
* /sys/class/gpio/unexport ... write-only
* integer N ... number of GPIO to unexport
*/
-static ssize_t export_store(struct class *class, const char *buf, size_t len)
+static ssize_t export_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t len)
{
long gpio;
int status;
@@ -653,7 +655,9 @@ done:
return status ? : len;
}
-static ssize_t unexport_store(struct class *class, const char *buf, size_t len)
+static ssize_t unexport_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t len)
{
long gpio;
int status;
@@ -1237,6 +1241,64 @@ void gpio_free(unsigned gpio)
}
EXPORT_SYMBOL_GPL(gpio_free);
+/**
+ * gpio_request_one - request a single GPIO with initial configuration
+ * @gpio: the GPIO number
+ * @flags: GPIO configuration as specified by GPIOF_*
+ * @label: a literal description string of this GPIO
+ */
+int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
+{
+ int err;
+
+ err = gpio_request(gpio, label);
+ if (err)
+ return err;
+
+ if (flags & GPIOF_DIR_IN)
+ err = gpio_direction_input(gpio);
+ else
+ err = gpio_direction_output(gpio,
+ (flags & GPIOF_INIT_HIGH) ? 1 : 0);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(gpio_request_one);
+
+/**
+ * gpio_request_array - request multiple GPIOs in a single call
+ * @array: array of the 'struct gpio'
+ * @num: how many GPIOs in the array
+ */
+int gpio_request_array(struct gpio *array, size_t num)
+{
+ int i, err;
+
+ for (i = 0; i < num; i++, array++) {
+ err = gpio_request_one(array->gpio, array->flags, array->label);
+ if (err)
+ goto err_free;
+ }
+ return 0;
+
+err_free:
+ while (i--)
+ gpio_free((--array)->gpio);
+ return err;
+}
+EXPORT_SYMBOL_GPL(gpio_request_array);
+
+/**
+ * gpio_free_array - release multiple GPIOs in a single call
+ * @array: array of the 'struct gpio'
+ * @num: how many GPIOs in the array
+ */
+void gpio_free_array(struct gpio *array, size_t num)
+{
+ while (num--)
+ gpio_free((array++)->gpio);
+}
+EXPORT_SYMBOL_GPL(gpio_free_array);
/**
* gpiochip_is_requested - return string iff signal was requested
diff --git a/drivers/gpio/it8761e_gpio.c b/drivers/gpio/it8761e_gpio.c
new file mode 100644
index 000000000000..753219cf993a
--- /dev/null
+++ b/drivers/gpio/it8761e_gpio.c
@@ -0,0 +1,231 @@
+/*
+ * it8761_gpio.c - GPIO interface for IT8761E Super I/O chip
+ *
+ * Author: Denis Turischev <denis@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+
+#include <linux/gpio.h>
+
+#define SIO_CHIP_ID 0x8761
+#define CHIP_ID_HIGH_BYTE 0x20
+#define CHIP_ID_LOW_BYTE 0x21
+
+static u8 ports[2] = { 0x2e, 0x4e };
+static u8 port;
+
+static DEFINE_SPINLOCK(sio_lock);
+
+#define GPIO_NAME "it8761-gpio"
+#define GPIO_BA_HIGH_BYTE 0x60
+#define GPIO_BA_LOW_BYTE 0x61
+#define GPIO_IOSIZE 4
+#define GPIO1X_IO 0xf0
+#define GPIO2X_IO 0xf1
+
+static u16 gpio_ba;
+
+static u8 read_reg(u8 addr, u8 port)
+{
+ outb(addr, port);
+ return inb(port + 1);
+}
+
+static void write_reg(u8 data, u8 addr, u8 port)
+{
+ outb(addr, port);
+ outb(data, port + 1);
+}
+
+static void enter_conf_mode(u8 port)
+{
+ outb(0x87, port);
+ outb(0x61, port);
+ outb(0x55, port);
+ outb((port == 0x2e) ? 0x55 : 0xaa, port);
+}
+
+static void exit_conf_mode(u8 port)
+{
+ outb(0x2, port);
+ outb(0x2, port + 1);
+}
+
+static void enter_gpio_mode(u8 port)
+{
+ write_reg(0x2, 0x7, port);
+}
+
+static int it8761e_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
+{
+ u16 reg;
+ u8 bit;
+
+ bit = gpio_num % 7;
+ reg = (gpio_num >= 7) ? gpio_ba + 1 : gpio_ba;
+
+ return !!(inb(reg) & (1 << bit));
+}
+
+static int it8761e_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
+{
+ u8 curr_dirs;
+ u8 io_reg, bit;
+
+ bit = gpio_num % 7;
+ io_reg = (gpio_num >= 7) ? GPIO2X_IO : GPIO1X_IO;
+
+ spin_lock(&sio_lock);
+
+ enter_conf_mode(port);
+ enter_gpio_mode(port);
+
+ curr_dirs = read_reg(io_reg, port);
+
+ if (curr_dirs & (1 << bit))
+ write_reg(curr_dirs & ~(1 << bit), io_reg, port);
+
+ exit_conf_mode(port);
+
+ spin_unlock(&sio_lock);
+ return 0;
+}
+
+static void it8761e_gpio_set(struct gpio_chip *gc,
+ unsigned gpio_num, int val)
+{
+ u8 curr_vals, bit;
+ u16 reg;
+
+ bit = gpio_num % 7;
+ reg = (gpio_num >= 7) ? gpio_ba + 1 : gpio_ba;
+
+ spin_lock(&sio_lock);
+
+ curr_vals = inb(reg);
+ if (val)
+ outb(curr_vals | (1 << bit) , reg);
+ else
+ outb(curr_vals & ~(1 << bit), reg);
+
+ spin_unlock(&sio_lock);
+}
+
+static int it8761e_gpio_direction_out(struct gpio_chip *gc,
+ unsigned gpio_num, int val)
+{
+ u8 curr_dirs, io_reg, bit;
+
+ bit = gpio_num % 7;
+ io_reg = (gpio_num >= 7) ? GPIO2X_IO : GPIO1X_IO;
+
+ it8761e_gpio_set(gc, gpio_num, val);
+
+ spin_lock(&sio_lock);
+
+ enter_conf_mode(port);
+ enter_gpio_mode(port);
+
+ curr_dirs = read_reg(io_reg, port);
+
+ if (!(curr_dirs & (1 << bit)))
+ write_reg(curr_dirs | (1 << bit), io_reg, port);
+
+ exit_conf_mode(port);
+
+ spin_unlock(&sio_lock);
+ return 0;
+}
+
+static struct gpio_chip it8761e_gpio_chip = {
+ .label = GPIO_NAME,
+ .owner = THIS_MODULE,
+ .get = it8761e_gpio_get,
+ .direction_input = it8761e_gpio_direction_in,
+ .set = it8761e_gpio_set,
+ .direction_output = it8761e_gpio_direction_out,
+};
+
+static int __init it8761e_gpio_init(void)
+{
+ int i, id, err;
+
+ /* chip and port detection */
+ for (i = 0; i < ARRAY_SIZE(ports); i++) {
+ spin_lock(&sio_lock);
+ enter_conf_mode(ports[i]);
+
+ id = (read_reg(CHIP_ID_HIGH_BYTE, ports[i]) << 8) +
+ read_reg(CHIP_ID_LOW_BYTE, ports[i]);
+
+ exit_conf_mode(ports[i]);
+ spin_unlock(&sio_lock);
+
+ if (id == SIO_CHIP_ID) {
+ port = ports[i];
+ break;
+ }
+ }
+
+ if (!port)
+ return -ENODEV;
+
+ /* fetch GPIO base address */
+ enter_conf_mode(port);
+ enter_gpio_mode(port);
+ gpio_ba = (read_reg(GPIO_BA_HIGH_BYTE, port) << 8) +
+ read_reg(GPIO_BA_LOW_BYTE, port);
+ exit_conf_mode(port);
+
+ if (!request_region(gpio_ba, GPIO_IOSIZE, GPIO_NAME))
+ return -EBUSY;
+
+ it8761e_gpio_chip.base = -1;
+ it8761e_gpio_chip.ngpio = 14;
+
+ err = gpiochip_add(&it8761e_gpio_chip);
+ if (err < 0)
+ goto gpiochip_add_err;
+
+ return 0;
+
+gpiochip_add_err:
+ release_region(gpio_ba, GPIO_IOSIZE);
+ gpio_ba = 0;
+ return err;
+}
+
+static void __exit it8761e_gpio_exit(void)
+{
+ if (gpio_ba) {
+ gpiochip_remove(&it8761e_gpio_chip);
+
+ release_region(gpio_ba, GPIO_IOSIZE);
+ gpio_ba = 0;
+ }
+}
+module_init(it8761e_gpio_init);
+module_exit(it8761e_gpio_exit);
+
+MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
+MODULE_DESCRIPTION("GPIO interface for IT8761E Super I/O chip");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/max7300.c b/drivers/gpio/max7300.c
new file mode 100644
index 000000000000..9d74eef1157a
--- /dev/null
+++ b/drivers/gpio/max7300.c
@@ -0,0 +1,94 @@
+/*
+ * drivers/gpio/max7300.c
+ *
+ * Copyright (C) 2009 Wolfram Sang, Pengutronix
+ *
+ * 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.
+ *
+ * Check max730x.c for further details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/spi/max7301.h>
+
+static int max7300_i2c_write(struct device *dev, unsigned int reg,
+ unsigned int val)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int max7300_i2c_read(struct device *dev, unsigned int reg)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int __devinit max7300_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max7301 *ts;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ ts = kzalloc(sizeof(struct max7301), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ ts->read = max7300_i2c_read;
+ ts->write = max7300_i2c_write;
+ ts->dev = &client->dev;
+
+ ret = __max730x_probe(ts);
+ if (ret)
+ kfree(ts);
+ return ret;
+}
+
+static int __devexit max7300_remove(struct i2c_client *client)
+{
+ return __max730x_remove(&client->dev);
+}
+
+static const struct i2c_device_id max7300_id[] = {
+ { "max7300", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max7300_id);
+
+static struct i2c_driver max7300_driver = {
+ .driver = {
+ .name = "max7300",
+ .owner = THIS_MODULE,
+ },
+ .probe = max7300_probe,
+ .remove = __devexit_p(max7300_remove),
+ .id_table = max7300_id,
+};
+
+static int __init max7300_init(void)
+{
+ return i2c_add_driver(&max7300_driver);
+}
+subsys_initcall(max7300_init);
+
+static void __exit max7300_exit(void)
+{
+ i2c_del_driver(&max7300_driver);
+}
+module_exit(max7300_exit);
+
+MODULE_AUTHOR("Wolfram Sang");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MAX7300 GPIO-Expander");
diff --git a/drivers/gpio/max7301.c b/drivers/gpio/max7301.c
index 480956f1ca50..965d9b1ea13e 100644
--- a/drivers/gpio/max7301.c
+++ b/drivers/gpio/max7301.c
@@ -1,98 +1,41 @@
-/**
+/*
* drivers/gpio/max7301.c
*
* Copyright (C) 2006 Juergen Beisert, Pengutronix
* Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix
+ * Copyright (C) 2009 Wolfram Sang, Pengutronix
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * The Maxim's MAX7301 device is an SPI driven GPIO expander. There are
- * 28 GPIOs. 8 of them can trigger an interrupt. See datasheet for more
- * details
- * Note:
- * - DIN must be stable at the rising edge of clock.
- * - when writing:
- * - always clock in 16 clocks at once
- * - at DIN: D15 first, D0 last
- * - D0..D7 = databyte, D8..D14 = commandbyte
- * - D15 = low -> write command
- * - when reading
- * - always clock in 16 clocks at once
- * - at DIN: D15 first, D0 last
- * - D0..D7 = dummy, D8..D14 = register address
- * - D15 = high -> read command
- * - raise CS and assert it again
- * - always clock in 16 clocks at once
- * - at DOUT: D15 first, D0 last
- * - D0..D7 contains the data from the first cycle
- *
- * The driver exports a standard gpiochip interface
+ * Check max730x.c for further details.
*/
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/spi/spi.h>
#include <linux/spi/max7301.h>
-#include <linux/gpio.h>
-
-#define DRIVER_NAME "max7301"
-
-/*
- * Pin configurations, see MAX7301 datasheet page 6
- */
-#define PIN_CONFIG_MASK 0x03
-#define PIN_CONFIG_IN_PULLUP 0x03
-#define PIN_CONFIG_IN_WO_PULLUP 0x02
-#define PIN_CONFIG_OUT 0x01
-
-#define PIN_NUMBER 28
-
-
-/*
- * Some registers must be read back to modify.
- * To save time we cache them here in memory
- */
-struct max7301 {
- struct mutex lock;
- u8 port_config[8]; /* field 0 is unused */
- u32 out_level; /* cached output levels */
- struct gpio_chip chip;
- struct spi_device *spi;
-};
-/**
- * max7301_write - Write a new register content
- * @spi: The SPI device
- * @reg: Register offset
- * @val: Value to write
- *
- * A write to the MAX7301 means one message with one transfer
- *
- * Returns 0 if successful or a negative value on error
- */
-static int max7301_write(struct spi_device *spi, unsigned int reg, unsigned int val)
+/* A write to the MAX7301 means one message with one transfer */
+static int max7301_spi_write(struct device *dev, unsigned int reg,
+ unsigned int val)
{
+ struct spi_device *spi = to_spi_device(dev);
u16 word = ((reg & 0x7F) << 8) | (val & 0xFF);
+
return spi_write(spi, (const u8 *)&word, sizeof(word));
}
-/**
- * max7301_read - Read back register content
- * @spi: The SPI device
- * @reg: Register offset
- *
- * A read from the MAX7301 means two transfers; here, one message each
- *
- * Returns positive 8 bit value from device if successful or a
- * negative value on error
- */
-static int max7301_read(struct spi_device *spi, unsigned int reg)
+/* A read from the MAX7301 means two transfers; here, one message each */
+
+static int max7301_spi_read(struct device *dev, unsigned int reg)
{
int ret;
u16 word;
+ struct spi_device *spi = to_spi_device(dev);
word = 0x8000 | (reg << 8);
ret = spi_write(spi, (const u8 *)&word, sizeof(word));
@@ -108,125 +51,13 @@ static int max7301_read(struct spi_device *spi, unsigned int reg)
return word & 0xff;
}
-static int max7301_direction_input(struct gpio_chip *chip, unsigned offset)
-{
- struct max7301 *ts = container_of(chip, struct max7301, chip);
- u8 *config;
- int ret;
-
- /* First 4 pins are unused in the controller */
- offset += 4;
-
- config = &ts->port_config[offset >> 2];
-
- mutex_lock(&ts->lock);
-
- /* Standard GPIO API doesn't support pull-ups, has to be extended.
- * Hard-coding no pollup for now. */
- *config = (*config & ~(3 << (offset & 3))) | (1 << (offset & 3));
-
- ret = max7301_write(ts->spi, 0x08 + (offset >> 2), *config);
-
- mutex_unlock(&ts->lock);
-
- return ret;
-}
-
-static int __max7301_set(struct max7301 *ts, unsigned offset, int value)
-{
- if (value) {
- ts->out_level |= 1 << offset;
- return max7301_write(ts->spi, 0x20 + offset, 0x01);
- } else {
- ts->out_level &= ~(1 << offset);
- return max7301_write(ts->spi, 0x20 + offset, 0x00);
- }
-}
-
-static int max7301_direction_output(struct gpio_chip *chip, unsigned offset,
- int value)
-{
- struct max7301 *ts = container_of(chip, struct max7301, chip);
- u8 *config;
- int ret;
-
- /* First 4 pins are unused in the controller */
- offset += 4;
-
- config = &ts->port_config[offset >> 2];
-
- mutex_lock(&ts->lock);
-
- *config = (*config & ~(3 << (offset & 3))) | (1 << (offset & 3));
-
- ret = __max7301_set(ts, offset, value);
-
- if (!ret)
- ret = max7301_write(ts->spi, 0x08 + (offset >> 2), *config);
-
- mutex_unlock(&ts->lock);
-
- return ret;
-}
-
-static int max7301_get(struct gpio_chip *chip, unsigned offset)
-{
- struct max7301 *ts = container_of(chip, struct max7301, chip);
- int config, level = -EINVAL;
-
- /* First 4 pins are unused in the controller */
- offset += 4;
-
- mutex_lock(&ts->lock);
-
- config = (ts->port_config[offset >> 2] >> ((offset & 3) * 2)) & 3;
-
- switch (config) {
- case 1:
- /* Output: return cached level */
- level = !!(ts->out_level & (1 << offset));
- break;
- case 2:
- case 3:
- /* Input: read out */
- level = max7301_read(ts->spi, 0x20 + offset) & 0x01;
- }
- mutex_unlock(&ts->lock);
-
- return level;
-}
-
-static void max7301_set(struct gpio_chip *chip, unsigned offset, int value)
-{
- struct max7301 *ts = container_of(chip, struct max7301, chip);
-
- /* First 4 pins are unused in the controller */
- offset += 4;
-
- mutex_lock(&ts->lock);
-
- __max7301_set(ts, offset, value);
-
- mutex_unlock(&ts->lock);
-}
-
static int __devinit max7301_probe(struct spi_device *spi)
{
struct max7301 *ts;
- struct max7301_platform_data *pdata;
- int i, ret;
-
- pdata = spi->dev.platform_data;
- if (!pdata || !pdata->base) {
- dev_dbg(&spi->dev, "incorrect or missing platform data\n");
- return -EINVAL;
- }
+ int ret;
- /*
- * bits_per_word cannot be configured in platform data
- */
+ /* bits_per_word cannot be configured in platform data */
spi->bits_per_word = 16;
-
ret = spi_setup(spi);
if (ret < 0)
return ret;
@@ -235,90 +66,35 @@ static int __devinit max7301_probe(struct spi_device *spi)
if (!ts)
return -ENOMEM;
- mutex_init(&ts->lock);
-
- dev_set_drvdata(&spi->dev, ts);
+ ts->read = max7301_spi_read;
+ ts->write = max7301_spi_write;
+ ts->dev = &spi->dev;
- /* Power up the chip and disable IRQ output */
- max7301_write(spi, 0x04, 0x01);
-
- ts->spi = spi;
-
- ts->chip.label = DRIVER_NAME,
-
- ts->chip.direction_input = max7301_direction_input;
- ts->chip.get = max7301_get;
- ts->chip.direction_output = max7301_direction_output;
- ts->chip.set = max7301_set;
-
- ts->chip.base = pdata->base;
- ts->chip.ngpio = PIN_NUMBER;
- ts->chip.can_sleep = 1;
- ts->chip.dev = &spi->dev;
- ts->chip.owner = THIS_MODULE;
-
- /*
- * tristate all pins in hardware and cache the
- * register values for later use.
- */
- for (i = 1; i < 8; i++) {
- int j;
- /* 0xAA means input with internal pullup disabled */
- max7301_write(spi, 0x08 + i, 0xAA);
- ts->port_config[i] = 0xAA;
- for (j = 0; j < 4; j++) {
- int offset = (i - 1) * 4 + j;
- ret = max7301_direction_input(&ts->chip, offset);
- if (ret)
- goto exit_destroy;
- }
- }
-
- ret = gpiochip_add(&ts->chip);
+ ret = __max730x_probe(ts);
if (ret)
- goto exit_destroy;
-
- return ret;
-
-exit_destroy:
- dev_set_drvdata(&spi->dev, NULL);
- mutex_destroy(&ts->lock);
- kfree(ts);
+ kfree(ts);
return ret;
}
static int __devexit max7301_remove(struct spi_device *spi)
{
- struct max7301 *ts;
- int ret;
-
- ts = dev_get_drvdata(&spi->dev);
- if (ts == NULL)
- return -ENODEV;
-
- dev_set_drvdata(&spi->dev, NULL);
-
- /* Power down the chip and disable IRQ output */
- max7301_write(spi, 0x04, 0x00);
-
- ret = gpiochip_remove(&ts->chip);
- if (!ret) {
- mutex_destroy(&ts->lock);
- kfree(ts);
- } else
- dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n",
- ret);
-
- return ret;
+ return __max730x_remove(&spi->dev);
}
+static const struct spi_device_id max7301_id[] = {
+ { "max7301", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, max7301_id);
+
static struct spi_driver max7301_driver = {
.driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
+ .name = "max7301",
+ .owner = THIS_MODULE,
},
- .probe = max7301_probe,
- .remove = __devexit_p(max7301_remove),
+ .probe = max7301_probe,
+ .remove = __devexit_p(max7301_remove),
+ .id_table = max7301_id,
};
static int __init max7301_init(void)
@@ -336,7 +112,6 @@ static void __exit max7301_exit(void)
}
module_exit(max7301_exit);
-MODULE_AUTHOR("Juergen Beisert");
+MODULE_AUTHOR("Juergen Beisert, Wolfram Sang");
MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("MAX7301 SPI based GPIO-Expander");
-MODULE_ALIAS("spi:" DRIVER_NAME);
+MODULE_DESCRIPTION("MAX7301 GPIO-Expander");
diff --git a/drivers/gpio/max730x.c b/drivers/gpio/max730x.c
new file mode 100644
index 000000000000..c9bced55f82b
--- /dev/null
+++ b/drivers/gpio/max730x.c
@@ -0,0 +1,244 @@
+/**
+ * drivers/gpio/max7301.c
+ *
+ * Copyright (C) 2006 Juergen Beisert, Pengutronix
+ * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix
+ * Copyright (C) 2009 Wolfram Sang, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The Maxim MAX7300/1 device is an I2C/SPI driven GPIO expander. There are
+ * 28 GPIOs. 8 of them can trigger an interrupt. See datasheet for more
+ * details
+ * Note:
+ * - DIN must be stable at the rising edge of clock.
+ * - when writing:
+ * - always clock in 16 clocks at once
+ * - at DIN: D15 first, D0 last
+ * - D0..D7 = databyte, D8..D14 = commandbyte
+ * - D15 = low -> write command
+ * - when reading
+ * - always clock in 16 clocks at once
+ * - at DIN: D15 first, D0 last
+ * - D0..D7 = dummy, D8..D14 = register address
+ * - D15 = high -> read command
+ * - raise CS and assert it again
+ * - always clock in 16 clocks at once
+ * - at DOUT: D15 first, D0 last
+ * - D0..D7 contains the data from the first cycle
+ *
+ * The driver exports a standard gpiochip interface
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/spi/max7301.h>
+#include <linux/gpio.h>
+
+/*
+ * Pin configurations, see MAX7301 datasheet page 6
+ */
+#define PIN_CONFIG_MASK 0x03
+#define PIN_CONFIG_IN_PULLUP 0x03
+#define PIN_CONFIG_IN_WO_PULLUP 0x02
+#define PIN_CONFIG_OUT 0x01
+
+#define PIN_NUMBER 28
+
+static int max7301_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct max7301 *ts = container_of(chip, struct max7301, chip);
+ u8 *config;
+ u8 offset_bits;
+ int ret;
+
+ /* First 4 pins are unused in the controller */
+ offset += 4;
+ offset_bits = (offset & 3) << 1;
+
+ config = &ts->port_config[offset >> 2];
+
+ mutex_lock(&ts->lock);
+
+ /* Standard GPIO API doesn't support pull-ups, has to be extended.
+ * Hard-coding no pollup for now. */
+ *config = (*config & ~(PIN_CONFIG_MASK << offset_bits))
+ | (PIN_CONFIG_IN_WO_PULLUP << offset_bits);
+
+ ret = ts->write(ts->dev, 0x08 + (offset >> 2), *config);
+
+ mutex_unlock(&ts->lock);
+
+ return ret;
+}
+
+static int __max7301_set(struct max7301 *ts, unsigned offset, int value)
+{
+ if (value) {
+ ts->out_level |= 1 << offset;
+ return ts->write(ts->dev, 0x20 + offset, 0x01);
+ } else {
+ ts->out_level &= ~(1 << offset);
+ return ts->write(ts->dev, 0x20 + offset, 0x00);
+ }
+}
+
+static int max7301_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct max7301 *ts = container_of(chip, struct max7301, chip);
+ u8 *config;
+ u8 offset_bits;
+ int ret;
+
+ /* First 4 pins are unused in the controller */
+ offset += 4;
+ offset_bits = (offset & 3) << 1;
+
+ config = &ts->port_config[offset >> 2];
+
+ mutex_lock(&ts->lock);
+
+ *config = (*config & ~(PIN_CONFIG_MASK << offset_bits))
+ | (PIN_CONFIG_OUT << offset_bits);
+
+ ret = __max7301_set(ts, offset, value);
+
+ if (!ret)
+ ret = ts->write(ts->dev, 0x08 + (offset >> 2), *config);
+
+ mutex_unlock(&ts->lock);
+
+ return ret;
+}
+
+static int max7301_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct max7301 *ts = container_of(chip, struct max7301, chip);
+ int config, level = -EINVAL;
+
+ /* First 4 pins are unused in the controller */
+ offset += 4;
+
+ mutex_lock(&ts->lock);
+
+ config = (ts->port_config[offset >> 2] >> ((offset & 3) << 1))
+ & PIN_CONFIG_MASK;
+
+ switch (config) {
+ case PIN_CONFIG_OUT:
+ /* Output: return cached level */
+ level = !!(ts->out_level & (1 << offset));
+ break;
+ case PIN_CONFIG_IN_WO_PULLUP:
+ case PIN_CONFIG_IN_PULLUP:
+ /* Input: read out */
+ level = ts->read(ts->dev, 0x20 + offset) & 0x01;
+ }
+ mutex_unlock(&ts->lock);
+
+ return level;
+}
+
+static void max7301_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct max7301 *ts = container_of(chip, struct max7301, chip);
+
+ /* First 4 pins are unused in the controller */
+ offset += 4;
+
+ mutex_lock(&ts->lock);
+
+ __max7301_set(ts, offset, value);
+
+ mutex_unlock(&ts->lock);
+}
+
+int __devinit __max730x_probe(struct max7301 *ts)
+{
+ struct device *dev = ts->dev;
+ struct max7301_platform_data *pdata;
+ int i, ret;
+
+ pdata = dev->platform_data;
+ if (!pdata || !pdata->base) {
+ dev_err(dev, "incorrect or missing platform data\n");
+ return -EINVAL;
+ }
+
+ mutex_init(&ts->lock);
+ dev_set_drvdata(dev, ts);
+
+ /* Power up the chip and disable IRQ output */
+ ts->write(dev, 0x04, 0x01);
+
+ ts->chip.label = dev->driver->name;
+
+ ts->chip.direction_input = max7301_direction_input;
+ ts->chip.get = max7301_get;
+ ts->chip.direction_output = max7301_direction_output;
+ ts->chip.set = max7301_set;
+
+ ts->chip.base = pdata->base;
+ ts->chip.ngpio = PIN_NUMBER;
+ ts->chip.can_sleep = 1;
+ ts->chip.dev = dev;
+ ts->chip.owner = THIS_MODULE;
+
+ /*
+ * tristate all pins in hardware and cache the
+ * register values for later use.
+ */
+ for (i = 1; i < 8; i++) {
+ int j;
+ /* 0xAA means input with internal pullup disabled */
+ ts->write(dev, 0x08 + i, 0xAA);
+ ts->port_config[i] = 0xAA;
+ for (j = 0; j < 4; j++) {
+ int offset = (i - 1) * 4 + j;
+ ret = max7301_direction_input(&ts->chip, offset);
+ if (ret)
+ goto exit_destroy;
+ }
+ }
+
+ ret = gpiochip_add(&ts->chip);
+ if (ret)
+ goto exit_destroy;
+
+ return ret;
+
+exit_destroy:
+ dev_set_drvdata(dev, NULL);
+ mutex_destroy(&ts->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__max730x_probe);
+
+int __devexit __max730x_remove(struct device *dev)
+{
+ struct max7301 *ts = dev_get_drvdata(dev);
+ int ret;
+
+ if (ts == NULL)
+ return -ENODEV;
+
+ dev_set_drvdata(dev, NULL);
+
+ /* Power down the chip and disable IRQ output */
+ ts->write(dev, 0x04, 0x00);
+
+ ret = gpiochip_remove(&ts->chip);
+ if (!ret) {
+ mutex_destroy(&ts->lock);
+ kfree(ts);
+ } else
+ dev_err(dev, "Failed to remove GPIO controller: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__max730x_remove);
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 6a2fb3fbb3d9..ab5daab14bc2 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -14,6 +14,8 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/i2c/pca953x.h>
#ifdef CONFIG_OF_GPIO
@@ -26,23 +28,28 @@
#define PCA953X_INVERT 2
#define PCA953X_DIRECTION 3
+#define PCA953X_GPIOS 0x00FF
+#define PCA953X_INT 0x0100
+
static const struct i2c_device_id pca953x_id[] = {
- { "pca9534", 8, },
- { "pca9535", 16, },
+ { "pca9534", 8 | PCA953X_INT, },
+ { "pca9535", 16 | PCA953X_INT, },
{ "pca9536", 4, },
- { "pca9537", 4, },
- { "pca9538", 8, },
- { "pca9539", 16, },
- { "pca9554", 8, },
- { "pca9555", 16, },
+ { "pca9537", 4 | PCA953X_INT, },
+ { "pca9538", 8 | PCA953X_INT, },
+ { "pca9539", 16 | PCA953X_INT, },
+ { "pca9554", 8 | PCA953X_INT, },
+ { "pca9555", 16 | PCA953X_INT, },
{ "pca9556", 8, },
{ "pca9557", 8, },
{ "max7310", 8, },
- { "max7315", 8, },
- { "pca6107", 8, },
- { "tca6408", 8, },
- { "tca6416", 16, },
+ { "max7312", 16 | PCA953X_INT, },
+ { "max7313", 16 | PCA953X_INT, },
+ { "max7315", 8 | PCA953X_INT, },
+ { "pca6107", 8 | PCA953X_INT, },
+ { "tca6408", 8 | PCA953X_INT, },
+ { "tca6416", 16 | PCA953X_INT, },
/* NYET: { "tca6424", 24, }, */
{ }
};
@@ -53,6 +60,15 @@ struct pca953x_chip {
uint16_t reg_output;
uint16_t reg_direction;
+#ifdef CONFIG_GPIO_PCA953X_IRQ
+ struct mutex irq_lock;
+ uint16_t irq_mask;
+ uint16_t irq_stat;
+ uint16_t irq_trig_raise;
+ uint16_t irq_trig_fall;
+ int irq_base;
+#endif
+
struct i2c_client *client;
struct pca953x_platform_data *dyn_pdata;
struct gpio_chip gpio_chip;
@@ -202,6 +218,210 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
gc->names = chip->names;
}
+#ifdef CONFIG_GPIO_PCA953X_IRQ
+static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
+{
+ struct pca953x_chip *chip;
+
+ chip = container_of(gc, struct pca953x_chip, gpio_chip);
+ return chip->irq_base + off;
+}
+
+static void pca953x_irq_mask(unsigned int irq)
+{
+ struct pca953x_chip *chip = get_irq_chip_data(irq);
+
+ chip->irq_mask &= ~(1 << (irq - chip->irq_base));
+}
+
+static void pca953x_irq_unmask(unsigned int irq)
+{
+ struct pca953x_chip *chip = get_irq_chip_data(irq);
+
+ chip->irq_mask |= 1 << (irq - chip->irq_base);
+}
+
+static void pca953x_irq_bus_lock(unsigned int irq)
+{
+ struct pca953x_chip *chip = get_irq_chip_data(irq);
+
+ mutex_lock(&chip->irq_lock);
+}
+
+static void pca953x_irq_bus_sync_unlock(unsigned int irq)
+{
+ struct pca953x_chip *chip = get_irq_chip_data(irq);
+
+ mutex_unlock(&chip->irq_lock);
+}
+
+static int pca953x_irq_set_type(unsigned int irq, unsigned int type)
+{
+ struct pca953x_chip *chip = get_irq_chip_data(irq);
+ uint16_t level = irq - chip->irq_base;
+ uint16_t mask = 1 << level;
+
+ if (!(type & IRQ_TYPE_EDGE_BOTH)) {
+ dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
+ irq, type);
+ return -EINVAL;
+ }
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ chip->irq_trig_fall |= mask;
+ else
+ chip->irq_trig_fall &= ~mask;
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ chip->irq_trig_raise |= mask;
+ else
+ chip->irq_trig_raise &= ~mask;
+
+ return pca953x_gpio_direction_input(&chip->gpio_chip, level);
+}
+
+static struct irq_chip pca953x_irq_chip = {
+ .name = "pca953x",
+ .mask = pca953x_irq_mask,
+ .unmask = pca953x_irq_unmask,
+ .bus_lock = pca953x_irq_bus_lock,
+ .bus_sync_unlock = pca953x_irq_bus_sync_unlock,
+ .set_type = pca953x_irq_set_type,
+};
+
+static uint16_t pca953x_irq_pending(struct pca953x_chip *chip)
+{
+ uint16_t cur_stat;
+ uint16_t old_stat;
+ uint16_t pending;
+ uint16_t trigger;
+ int ret;
+
+ ret = pca953x_read_reg(chip, PCA953X_INPUT, &cur_stat);
+ if (ret)
+ return 0;
+
+ /* Remove output pins from the equation */
+ cur_stat &= chip->reg_direction;
+
+ old_stat = chip->irq_stat;
+ trigger = (cur_stat ^ old_stat) & chip->irq_mask;
+
+ if (!trigger)
+ return 0;
+
+ chip->irq_stat = cur_stat;
+
+ pending = (old_stat & chip->irq_trig_fall) |
+ (cur_stat & chip->irq_trig_raise);
+ pending &= trigger;
+
+ return pending;
+}
+
+static irqreturn_t pca953x_irq_handler(int irq, void *devid)
+{
+ struct pca953x_chip *chip = devid;
+ uint16_t pending;
+ uint16_t level;
+
+ pending = pca953x_irq_pending(chip);
+
+ if (!pending)
+ return IRQ_HANDLED;
+
+ do {
+ level = __ffs(pending);
+ handle_nested_irq(level + chip->irq_base);
+
+ pending &= ~(1 << level);
+ } while (pending);
+
+ return IRQ_HANDLED;
+}
+
+static int pca953x_irq_setup(struct pca953x_chip *chip,
+ const struct i2c_device_id *id)
+{
+ struct i2c_client *client = chip->client;
+ struct pca953x_platform_data *pdata = client->dev.platform_data;
+ int ret;
+
+ if (pdata->irq_base && (id->driver_data & PCA953X_INT)) {
+ int lvl;
+
+ ret = pca953x_read_reg(chip, PCA953X_INPUT,
+ &chip->irq_stat);
+ if (ret)
+ goto out_failed;
+
+ /*
+ * There is no way to know which GPIO line generated the
+ * interrupt. We have to rely on the previous read for
+ * this purpose.
+ */
+ chip->irq_stat &= chip->reg_direction;
+ chip->irq_base = pdata->irq_base;
+ mutex_init(&chip->irq_lock);
+
+ for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) {
+ int irq = lvl + chip->irq_base;
+
+ set_irq_chip_data(irq, chip);
+ set_irq_chip_and_handler(irq, &pca953x_irq_chip,
+ handle_edge_irq);
+ set_irq_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ set_irq_noprobe(irq);
+#endif
+ }
+
+ ret = request_threaded_irq(client->irq,
+ NULL,
+ pca953x_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(&client->dev), chip);
+ if (ret) {
+ dev_err(&client->dev, "failed to request irq %d\n",
+ client->irq);
+ goto out_failed;
+ }
+
+ chip->gpio_chip.to_irq = pca953x_gpio_to_irq;
+ }
+
+ return 0;
+
+out_failed:
+ chip->irq_base = 0;
+ return ret;
+}
+
+static void pca953x_irq_teardown(struct pca953x_chip *chip)
+{
+ if (chip->irq_base)
+ free_irq(chip->client->irq, chip);
+}
+#else /* CONFIG_GPIO_PCA953X_IRQ */
+static int pca953x_irq_setup(struct pca953x_chip *chip,
+ const struct i2c_device_id *id)
+{
+ struct i2c_client *client = chip->client;
+ struct pca953x_platform_data *pdata = client->dev.platform_data;
+
+ if (pdata->irq_base && (id->driver_data & PCA953X_INT))
+ dev_warn(&client->dev, "interrupt support not compiled in\n");
+
+ return 0;
+}
+
+static void pca953x_irq_teardown(struct pca953x_chip *chip)
+{
+}
+#endif
+
/*
* Handlers for alternative sources of platform_data
*/
@@ -286,7 +506,7 @@ static int __devinit pca953x_probe(struct i2c_client *client,
/* initialize cached registers from their original values.
* we can't share this chip with another i2c master.
*/
- pca953x_setup_gpio(chip, id->driver_data);
+ pca953x_setup_gpio(chip, id->driver_data & PCA953X_GPIOS);
ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
if (ret)
@@ -301,6 +521,9 @@ static int __devinit pca953x_probe(struct i2c_client *client,
if (ret)
goto out_failed;
+ ret = pca953x_irq_setup(chip, id);
+ if (ret)
+ goto out_failed;
ret = gpiochip_add(&chip->gpio_chip);
if (ret)
@@ -317,6 +540,7 @@ static int __devinit pca953x_probe(struct i2c_client *client,
return 0;
out_failed:
+ pca953x_irq_teardown(chip);
kfree(chip->dyn_pdata);
kfree(chip);
return ret;
@@ -345,6 +569,7 @@ static int pca953x_remove(struct i2c_client *client)
return ret;
}
+ pca953x_irq_teardown(chip);
kfree(chip->dyn_pdata);
kfree(chip);
return 0;
diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c
index 4ee4c8367a3f..3ad1eeb49609 100644
--- a/drivers/gpio/pl061.c
+++ b/drivers/gpio/pl061.c
@@ -219,7 +219,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
if (pending == 0)
continue;
- for_each_bit(offset, &pending, PL061_GPIO_NR)
+ for_each_set_bit(offset, &pending, PL061_GPIO_NR)
generic_handle_irq(pl061_to_irq(&chip->gc, offset));
}
desc->chip->unmask(irq);
diff --git a/drivers/gpio/sch_gpio.c b/drivers/gpio/sch_gpio.c
new file mode 100644
index 000000000000..583521352c16
--- /dev/null
+++ b/drivers/gpio/sch_gpio.c
@@ -0,0 +1,295 @@
+/*
+ * sch_gpio.c - GPIO interface for Intel Poulsbo SCH
+ *
+ * Copyright (c) 2010 CompuLab Ltd
+ * Author: Denis Turischev <denis@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+
+#include <linux/gpio.h>
+
+static DEFINE_SPINLOCK(gpio_lock);
+
+#define CGEN (0x00)
+#define CGIO (0x04)
+#define CGLV (0x08)
+
+#define RGEN (0x20)
+#define RGIO (0x24)
+#define RGLV (0x28)
+
+static unsigned short gpio_ba;
+
+static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num)
+{
+ u8 curr_dirs;
+ unsigned short offset, bit;
+
+ spin_lock(&gpio_lock);
+
+ offset = CGIO + gpio_num / 8;
+ bit = gpio_num % 8;
+
+ curr_dirs = inb(gpio_ba + offset);
+
+ if (!(curr_dirs & (1 << bit)))
+ outb(curr_dirs | (1 << bit), gpio_ba + offset);
+
+ spin_unlock(&gpio_lock);
+ return 0;
+}
+
+static int sch_gpio_core_get(struct gpio_chip *gc, unsigned gpio_num)
+{
+ int res;
+ unsigned short offset, bit;
+
+ offset = CGLV + gpio_num / 8;
+ bit = gpio_num % 8;
+
+ res = !!(inb(gpio_ba + offset) & (1 << bit));
+ return res;
+}
+
+static void sch_gpio_core_set(struct gpio_chip *gc, unsigned gpio_num, int val)
+{
+ u8 curr_vals;
+ unsigned short offset, bit;
+
+ spin_lock(&gpio_lock);
+
+ offset = CGLV + gpio_num / 8;
+ bit = gpio_num % 8;
+
+ curr_vals = inb(gpio_ba + offset);
+
+ if (val)
+ outb(curr_vals | (1 << bit), gpio_ba + offset);
+ else
+ outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
+ spin_unlock(&gpio_lock);
+}
+
+static int sch_gpio_core_direction_out(struct gpio_chip *gc,
+ unsigned gpio_num, int val)
+{
+ u8 curr_dirs;
+ unsigned short offset, bit;
+
+ sch_gpio_core_set(gc, gpio_num, val);
+
+ spin_lock(&gpio_lock);
+
+ offset = CGIO + gpio_num / 8;
+ bit = gpio_num % 8;
+
+ curr_dirs = inb(gpio_ba + offset);
+ if (curr_dirs & (1 << bit))
+ outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
+
+ spin_unlock(&gpio_lock);
+ return 0;
+}
+
+static struct gpio_chip sch_gpio_core = {
+ .label = "sch_gpio_core",
+ .owner = THIS_MODULE,
+ .direction_input = sch_gpio_core_direction_in,
+ .get = sch_gpio_core_get,
+ .direction_output = sch_gpio_core_direction_out,
+ .set = sch_gpio_core_set,
+};
+
+static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
+ unsigned gpio_num)
+{
+ u8 curr_dirs;
+
+ spin_lock(&gpio_lock);
+
+ curr_dirs = inb(gpio_ba + RGIO);
+
+ if (!(curr_dirs & (1 << gpio_num)))
+ outb(curr_dirs | (1 << gpio_num) , gpio_ba + RGIO);
+
+ spin_unlock(&gpio_lock);
+ return 0;
+}
+
+static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num)
+{
+ return !!(inb(gpio_ba + RGLV) & (1 << gpio_num));
+}
+
+static void sch_gpio_resume_set(struct gpio_chip *gc,
+ unsigned gpio_num, int val)
+{
+ u8 curr_vals;
+
+ spin_lock(&gpio_lock);
+
+ curr_vals = inb(gpio_ba + RGLV);
+
+ if (val)
+ outb(curr_vals | (1 << gpio_num), gpio_ba + RGLV);
+ else
+ outb((curr_vals & ~(1 << gpio_num)), gpio_ba + RGLV);
+
+ spin_unlock(&gpio_lock);
+}
+
+static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
+ unsigned gpio_num, int val)
+{
+ u8 curr_dirs;
+
+ sch_gpio_resume_set(gc, gpio_num, val);
+
+ spin_lock(&gpio_lock);
+
+ curr_dirs = inb(gpio_ba + RGIO);
+ if (curr_dirs & (1 << gpio_num))
+ outb(curr_dirs & ~(1 << gpio_num), gpio_ba + RGIO);
+
+ spin_unlock(&gpio_lock);
+ return 0;
+}
+
+static struct gpio_chip sch_gpio_resume = {
+ .label = "sch_gpio_resume",
+ .owner = THIS_MODULE,
+ .direction_input = sch_gpio_resume_direction_in,
+ .get = sch_gpio_resume_get,
+ .direction_output = sch_gpio_resume_direction_out,
+ .set = sch_gpio_resume_set,
+};
+
+static int __devinit sch_gpio_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int err;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res)
+ return -EBUSY;
+
+ if (!request_region(res->start, resource_size(res), pdev->name))
+ return -EBUSY;
+
+ gpio_ba = res->start;
+
+ sch_gpio_core.base = 0;
+ sch_gpio_core.ngpio = 10;
+ sch_gpio_core.dev = &pdev->dev;
+
+ sch_gpio_resume.base = 10;
+ sch_gpio_resume.ngpio = 4;
+ sch_gpio_resume.dev = &pdev->dev;
+
+ err = gpiochip_add(&sch_gpio_core);
+ if (err < 0)
+ goto err_sch_gpio_core;
+
+ err = gpiochip_add(&sch_gpio_resume);
+ if (err < 0)
+ goto err_sch_gpio_resume;
+
+ /*
+ * GPIO[6:0] enabled by default
+ * GPIO7 is configured by the CMC as SLPIOVR
+ * Enable GPIO[9:8] core powered gpios explicitly
+ */
+ outb(0x3, gpio_ba + CGEN + 1);
+ /*
+ * SUS_GPIO[2:0] enabled by default
+ * Enable SUS_GPIO3 resume powered gpio explicitly
+ */
+ outb(0x8, gpio_ba + RGEN);
+
+ return 0;
+
+err_sch_gpio_resume:
+ err = gpiochip_remove(&sch_gpio_core);
+ if (err)
+ dev_err(&pdev->dev, "%s failed, %d\n",
+ "gpiochip_remove()", err);
+
+err_sch_gpio_core:
+ release_region(res->start, resource_size(res));
+ gpio_ba = 0;
+
+ return err;
+}
+
+static int __devexit sch_gpio_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+ if (gpio_ba) {
+ int err;
+
+ err = gpiochip_remove(&sch_gpio_core);
+ if (err)
+ dev_err(&pdev->dev, "%s failed, %d\n",
+ "gpiochip_remove()", err);
+ err = gpiochip_remove(&sch_gpio_resume);
+ if (err)
+ dev_err(&pdev->dev, "%s failed, %d\n",
+ "gpiochip_remove()", err);
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+
+ release_region(res->start, resource_size(res));
+ gpio_ba = 0;
+
+ return err;
+ }
+
+ return 0;
+}
+
+static struct platform_driver sch_gpio_driver = {
+ .driver = {
+ .name = "sch_gpio",
+ .owner = THIS_MODULE,
+ },
+ .probe = sch_gpio_probe,
+ .remove = __devexit_p(sch_gpio_remove),
+};
+
+static int __init sch_gpio_init(void)
+{
+ return platform_driver_register(&sch_gpio_driver);
+}
+
+static void __exit sch_gpio_exit(void)
+{
+ platform_driver_unregister(&sch_gpio_driver);
+}
+
+module_init(sch_gpio_init);
+module_exit(sch_gpio_exit);
+
+MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
+MODULE_DESCRIPTION("GPIO interface for Intel Poulsbo SCH");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sch_gpio");
diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c
index a4d344ba8e5c..d4295fa5369e 100644
--- a/drivers/gpio/timbgpio.c
+++ b/drivers/gpio/timbgpio.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
+#include <linux/irq.h>
#include <linux/io.h>
#include <linux/timb_gpio.h>
#include <linux/interrupt.h>
@@ -37,6 +38,8 @@
#define TGPIO_ICR 0x14
#define TGPIO_FLR 0x18
#define TGPIO_LVR 0x1c
+#define TGPIO_VER 0x20
+#define TGPIO_BFLR 0x24
struct timbgpio {
void __iomem *membase;
@@ -125,17 +128,23 @@ static int timbgpio_irq_type(unsigned irq, unsigned trigger)
struct timbgpio *tgpio = get_irq_chip_data(irq);
int offset = irq - tgpio->irq_base;
unsigned long flags;
- u32 lvr, flr;
+ u32 lvr, flr, bflr = 0;
+ u32 ver;
if (offset < 0 || offset > tgpio->gpio.ngpio)
return -EINVAL;
+ ver = ioread32(tgpio->membase + TGPIO_VER);
+
spin_lock_irqsave(&tgpio->lock, flags);
lvr = ioread32(tgpio->membase + TGPIO_LVR);
flr = ioread32(tgpio->membase + TGPIO_FLR);
+ if (ver > 2)
+ bflr = ioread32(tgpio->membase + TGPIO_BFLR);
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
+ bflr &= ~(1 << offset);
flr &= ~(1 << offset);
if (trigger & IRQ_TYPE_LEVEL_HIGH)
lvr |= 1 << offset;
@@ -143,21 +152,27 @@ static int timbgpio_irq_type(unsigned irq, unsigned trigger)
lvr &= ~(1 << offset);
}
- if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- return -EINVAL;
- else {
+ if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
+ if (ver < 3)
+ return -EINVAL;
+ else {
+ flr |= 1 << offset;
+ bflr |= 1 << offset;
+ }
+ } else {
+ bflr &= ~(1 << offset);
flr |= 1 << offset;
- /* opposite compared to the datasheet, but it mirrors the
- * reality
- */
if (trigger & IRQ_TYPE_EDGE_FALLING)
- lvr |= 1 << offset;
- else
lvr &= ~(1 << offset);
+ else
+ lvr |= 1 << offset;
}
iowrite32(lvr, tgpio->membase + TGPIO_LVR);
iowrite32(flr, tgpio->membase + TGPIO_FLR);
+ if (ver > 2)
+ iowrite32(bflr, tgpio->membase + TGPIO_BFLR);
+
iowrite32(1 << offset, tgpio->membase + TGPIO_ICR);
spin_unlock_irqrestore(&tgpio->lock, flags);
@@ -174,7 +189,7 @@ static void timbgpio_irq(unsigned int irq, struct irq_desc *desc)
ipr = ioread32(tgpio->membase + TGPIO_IPR);
iowrite32(ipr, tgpio->membase + TGPIO_ICR);
- for_each_bit(offset, &ipr, tgpio->gpio.ngpio)
+ for_each_set_bit(offset, &ipr, tgpio->gpio.ngpio)
generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset));
}
diff --git a/drivers/gpio/wm831x-gpio.c b/drivers/gpio/wm831x-gpio.c
index b4468b616890..d09021f4a7d3 100644
--- a/drivers/gpio/wm831x-gpio.c
+++ b/drivers/gpio/wm831x-gpio.c
@@ -38,10 +38,14 @@ static int wm831x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
+ int val = WM831X_GPN_DIR;
+
+ if (wm831x->has_gpio_ena)
+ val |= WM831X_GPN_TRI;
return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset,
- WM831X_GPN_DIR | WM831X_GPN_TRI,
- WM831X_GPN_DIR);
+ WM831X_GPN_DIR | WM831X_GPN_TRI |
+ WM831X_GPN_FN_MASK, val);
}
static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -60,23 +64,36 @@ static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset)
return 0;
}
-static int wm831x_gpio_direction_out(struct gpio_chip *chip,
- unsigned offset, int value)
+static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
- return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset,
- WM831X_GPN_DIR | WM831X_GPN_TRI, 0);
+ wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << offset,
+ value << offset);
}
-static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static int wm831x_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
{
struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
+ int val = 0;
+ int ret;
- wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << offset,
- value << offset);
+ if (wm831x->has_gpio_ena)
+ val |= WM831X_GPN_TRI;
+
+ ret = wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset,
+ WM831X_GPN_DIR | WM831X_GPN_TRI |
+ WM831X_GPN_FN_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ /* Can only set GPIO state once it's in output mode */
+ wm831x_gpio_set(chip, offset, value);
+
+ return 0;
}
static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
@@ -95,7 +112,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
- int i;
+ int i, tristated;
for (i = 0; i < chip->ngpio; i++) {
int gpio = i + chip->base;
@@ -162,15 +179,19 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
break;
}
+ tristated = reg & WM831X_GPN_TRI;
+ if (wm831x->has_gpio_ena)
+ tristated = !tristated;
+
seq_printf(s, " %s %s %s %s%s\n"
" %s%s (0x%4x)\n",
reg & WM831X_GPN_DIR ? "in" : "out",
wm831x_gpio_get(chip, i) ? "high" : "low",
pull,
powerdomain,
- reg & WM831X_GPN_POL ? " inverted" : "",
+ reg & WM831X_GPN_POL ? "" : " inverted",
reg & WM831X_GPN_OD ? "open-drain" : "CMOS",
- reg & WM831X_GPN_TRI ? " tristated" : "",
+ tristated ? " tristated" : "",
reg);
}
}
diff --git a/drivers/gpio/wm8350-gpiolib.c b/drivers/gpio/wm8350-gpiolib.c
new file mode 100644
index 000000000000..511840d1c7ba
--- /dev/null
+++ b/drivers/gpio/wm8350-gpiolib.c
@@ -0,0 +1,181 @@
+/*
+ * wm835x-gpiolib.c -- gpiolib support for Wolfson WM835x PMICs
+ *
+ * Copyright 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/gpio.h>
+
+struct wm8350_gpio_data {
+ struct wm8350 *wm8350;
+ struct gpio_chip gpio_chip;
+};
+
+static inline struct wm8350_gpio_data *to_wm8350_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct wm8350_gpio_data, gpio_chip);
+}
+
+static int wm8350_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+ struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+ struct wm8350 *wm8350 = wm8350_gpio->wm8350;
+
+ return wm8350_set_bits(wm8350, WM8350_GPIO_CONFIGURATION_I_O,
+ 1 << offset);
+}
+
+static int wm8350_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+ struct wm8350 *wm8350 = wm8350_gpio->wm8350;
+ int ret;
+
+ ret = wm8350_reg_read(wm8350, WM8350_GPIO_LEVEL);
+ if (ret < 0)
+ return ret;
+
+ if (ret & (1 << offset))
+ return 1;
+ else
+ return 0;
+}
+
+static void wm8350_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+ struct wm8350 *wm8350 = wm8350_gpio->wm8350;
+
+ if (value)
+ wm8350_set_bits(wm8350, WM8350_GPIO_LEVEL, 1 << offset);
+ else
+ wm8350_clear_bits(wm8350, WM8350_GPIO_LEVEL, 1 << offset);
+}
+
+static int wm8350_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+ struct wm8350 *wm8350 = wm8350_gpio->wm8350;
+ int ret;
+
+ ret = wm8350_clear_bits(wm8350, WM8350_GPIO_CONFIGURATION_I_O,
+ 1 << offset);
+ if (ret < 0)
+ return ret;
+
+ /* Don't have an atomic direction/value setup */
+ wm8350_gpio_set(chip, offset, value);
+
+ return 0;
+}
+
+static int wm8350_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+ struct wm8350 *wm8350 = wm8350_gpio->wm8350;
+
+ if (!wm8350->irq_base)
+ return -EINVAL;
+
+ return wm8350->irq_base + WM8350_IRQ_GPIO(offset);
+}
+
+static struct gpio_chip template_chip = {
+ .label = "wm8350",
+ .owner = THIS_MODULE,
+ .direction_input = wm8350_gpio_direction_in,
+ .get = wm8350_gpio_get,
+ .direction_output = wm8350_gpio_direction_out,
+ .set = wm8350_gpio_set,
+ .to_irq = wm8350_gpio_to_irq,
+ .can_sleep = 1,
+};
+
+static int __devinit wm8350_gpio_probe(struct platform_device *pdev)
+{
+ struct wm8350 *wm8350 = dev_get_drvdata(pdev->dev.parent);
+ struct wm8350_platform_data *pdata = wm8350->dev->platform_data;
+ struct wm8350_gpio_data *wm8350_gpio;
+ int ret;
+
+ wm8350_gpio = kzalloc(sizeof(*wm8350_gpio), GFP_KERNEL);
+ if (wm8350_gpio == NULL)
+ return -ENOMEM;
+
+ wm8350_gpio->wm8350 = wm8350;
+ wm8350_gpio->gpio_chip = template_chip;
+ wm8350_gpio->gpio_chip.ngpio = 13;
+ wm8350_gpio->gpio_chip.dev = &pdev->dev;
+ if (pdata && pdata->gpio_base)
+ wm8350_gpio->gpio_chip.base = pdata->gpio_base;
+ else
+ wm8350_gpio->gpio_chip.base = -1;
+
+ ret = gpiochip_add(&wm8350_gpio->gpio_chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
+ ret);
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, wm8350_gpio);
+
+ return ret;
+
+err:
+ kfree(wm8350_gpio);
+ return ret;
+}
+
+static int __devexit wm8350_gpio_remove(struct platform_device *pdev)
+{
+ struct wm8350_gpio_data *wm8350_gpio = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = gpiochip_remove(&wm8350_gpio->gpio_chip);
+ if (ret == 0)
+ kfree(wm8350_gpio);
+
+ return ret;
+}
+
+static struct platform_driver wm8350_gpio_driver = {
+ .driver.name = "wm8350-gpio",
+ .driver.owner = THIS_MODULE,
+ .probe = wm8350_gpio_probe,
+ .remove = __devexit_p(wm8350_gpio_remove),
+};
+
+static int __init wm8350_gpio_init(void)
+{
+ return platform_driver_register(&wm8350_gpio_driver);
+}
+subsys_initcall(wm8350_gpio_init);
+
+static void __exit wm8350_gpio_exit(void)
+{
+ platform_driver_unregister(&wm8350_gpio_driver);
+}
+module_exit(wm8350_gpio_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("GPIO interface for WM8350 PMICs");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8350-gpio");
diff --git a/drivers/gpio/wm8994-gpio.c b/drivers/gpio/wm8994-gpio.c
new file mode 100644
index 000000000000..de28b4a470ea
--- /dev/null
+++ b/drivers/gpio/wm8994-gpio.c
@@ -0,0 +1,204 @@
+/*
+ * wm8994-gpio.c -- gpiolib support for Wolfson WM8994
+ *
+ * Copyright 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/mfd/wm8994/gpio.h>
+#include <linux/mfd/wm8994/registers.h>
+
+struct wm8994_gpio {
+ struct wm8994 *wm8994;
+ struct gpio_chip gpio_chip;
+};
+
+static inline struct wm8994_gpio *to_wm8994_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct wm8994_gpio, gpio_chip);
+}
+
+static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+ struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+ struct wm8994 *wm8994 = wm8994_gpio->wm8994;
+
+ return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
+ WM8994_GPN_DIR, WM8994_GPN_DIR);
+}
+
+static int wm8994_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+ struct wm8994 *wm8994 = wm8994_gpio->wm8994;
+ int ret;
+
+ ret = wm8994_reg_read(wm8994, WM8994_GPIO_1 + offset);
+ if (ret < 0)
+ return ret;
+
+ if (ret & WM8994_GPN_LVL)
+ return 1;
+ else
+ return 0;
+}
+
+static int wm8994_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+ struct wm8994 *wm8994 = wm8994_gpio->wm8994;
+
+ return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
+ WM8994_GPN_DIR, 0);
+}
+
+static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+ struct wm8994 *wm8994 = wm8994_gpio->wm8994;
+
+ if (value)
+ value = WM8994_GPN_LVL;
+
+ wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, WM8994_GPN_LVL, value);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+ struct wm8994 *wm8994 = wm8994_gpio->wm8994;
+ int i;
+
+ for (i = 0; i < chip->ngpio; i++) {
+ int gpio = i + chip->base;
+ int reg;
+ const char *label;
+
+ /* We report the GPIO even if it's not requested since
+ * we're also reporting things like alternate
+ * functions which apply even when the GPIO is not in
+ * use as a GPIO.
+ */
+ label = gpiochip_is_requested(chip, i);
+ if (!label)
+ label = "Unrequested";
+
+ seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label);
+
+ reg = wm8994_reg_read(wm8994, WM8994_GPIO_1 + i);
+ if (reg < 0) {
+ dev_err(wm8994->dev,
+ "GPIO control %d read failed: %d\n",
+ gpio, reg);
+ seq_printf(s, "\n");
+ continue;
+ }
+
+ /* No decode yet; note that GPIO2 is special */
+ seq_printf(s, "(%x)\n", reg);
+ }
+}
+#else
+#define wm8994_gpio_dbg_show NULL
+#endif
+
+static struct gpio_chip template_chip = {
+ .label = "wm8994",
+ .owner = THIS_MODULE,
+ .direction_input = wm8994_gpio_direction_in,
+ .get = wm8994_gpio_get,
+ .direction_output = wm8994_gpio_direction_out,
+ .set = wm8994_gpio_set,
+ .dbg_show = wm8994_gpio_dbg_show,
+ .can_sleep = 1,
+};
+
+static int __devinit wm8994_gpio_probe(struct platform_device *pdev)
+{
+ struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
+ struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+ struct wm8994_gpio *wm8994_gpio;
+ int ret;
+
+ wm8994_gpio = kzalloc(sizeof(*wm8994_gpio), GFP_KERNEL);
+ if (wm8994_gpio == NULL)
+ return -ENOMEM;
+
+ wm8994_gpio->wm8994 = wm8994;
+ wm8994_gpio->gpio_chip = template_chip;
+ wm8994_gpio->gpio_chip.ngpio = WM8994_GPIO_MAX;
+ wm8994_gpio->gpio_chip.dev = &pdev->dev;
+ if (pdata && pdata->gpio_base)
+ wm8994_gpio->gpio_chip.base = pdata->gpio_base;
+ else
+ wm8994_gpio->gpio_chip.base = -1;
+
+ ret = gpiochip_add(&wm8994_gpio->gpio_chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
+ ret);
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, wm8994_gpio);
+
+ return ret;
+
+err:
+ kfree(wm8994_gpio);
+ return ret;
+}
+
+static int __devexit wm8994_gpio_remove(struct platform_device *pdev)
+{
+ struct wm8994_gpio *wm8994_gpio = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = gpiochip_remove(&wm8994_gpio->gpio_chip);
+ if (ret == 0)
+ kfree(wm8994_gpio);
+
+ return ret;
+}
+
+static struct platform_driver wm8994_gpio_driver = {
+ .driver.name = "wm8994-gpio",
+ .driver.owner = THIS_MODULE,
+ .probe = wm8994_gpio_probe,
+ .remove = __devexit_p(wm8994_gpio_remove),
+};
+
+static int __init wm8994_gpio_init(void)
+{
+ return platform_driver_register(&wm8994_gpio_driver);
+}
+subsys_initcall(wm8994_gpio_init);
+
+static void __exit wm8994_gpio_exit(void)
+{
+ platform_driver_unregister(&wm8994_gpio_driver);
+}
+module_exit(wm8994_gpio_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("GPIO interface for WM8994");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8994-gpio");
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 96eddd17e050..305c59003963 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -66,6 +66,8 @@ config DRM_RADEON
If M is selected, the module will be called radeon.
+source "drivers/gpu/drm/radeon/Kconfig"
+
config DRM_I810
tristate "Intel I810"
depends on DRM && AGP && AGP_INTEL
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 39c5aa75b8f1..abe3f446ca48 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -4,7 +4,7 @@
ccflags-y := -Iinclude/drm
-drm-y := drm_auth.o drm_bufs.o drm_cache.o \
+drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
drm_context.o drm_dma.o drm_drawable.o \
drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
diff --git a/drivers/gpu/drm/ati_pcigart.c b/drivers/gpu/drm/ati_pcigart.c
index a1fce68e3bbe..17be051b7aa3 100644
--- a/drivers/gpu/drm/ati_pcigart.c
+++ b/drivers/gpu/drm/ati_pcigart.c
@@ -113,7 +113,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
if (pci_set_dma_mask(dev->pdev, gart_info->table_mask)) {
DRM_ERROR("fail to set dma mask to 0x%Lx\n",
- gart_info->table_mask);
+ (unsigned long long)gart_info->table_mask);
ret = 1;
goto done;
}
diff --git a/drivers/gpu/drm/drm_buffer.c b/drivers/gpu/drm/drm_buffer.c
new file mode 100644
index 000000000000..55d03ed05000
--- /dev/null
+++ b/drivers/gpu/drm/drm_buffer.c
@@ -0,0 +1,184 @@
+/**************************************************************************
+ *
+ * Copyright 2010 Pauli Nieminen.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ *
+ **************************************************************************/
+/*
+ * Multipart buffer for coping data which is larger than the page size.
+ *
+ * Authors:
+ * Pauli Nieminen <suokkos-at-gmail-dot-com>
+ */
+
+#include "drm_buffer.h"
+
+/**
+ * Allocate the drm buffer object.
+ *
+ * buf: Pointer to a pointer where the object is stored.
+ * size: The number of bytes to allocate.
+ */
+int drm_buffer_alloc(struct drm_buffer **buf, int size)
+{
+ int nr_pages = size / PAGE_SIZE + 1;
+ int idx;
+
+ /* Allocating pointer table to end of structure makes drm_buffer
+ * variable sized */
+ *buf = kzalloc(sizeof(struct drm_buffer) + nr_pages*sizeof(char *),
+ GFP_KERNEL);
+
+ if (*buf == NULL) {
+ DRM_ERROR("Failed to allocate drm buffer object to hold"
+ " %d bytes in %d pages.\n",
+ size, nr_pages);
+ return -ENOMEM;
+ }
+
+ (*buf)->size = size;
+
+ for (idx = 0; idx < nr_pages; ++idx) {
+
+ (*buf)->data[idx] =
+ kmalloc(min(PAGE_SIZE, size - idx * PAGE_SIZE),
+ GFP_KERNEL);
+
+
+ if ((*buf)->data[idx] == NULL) {
+ DRM_ERROR("Failed to allocate %dth page for drm"
+ " buffer with %d bytes and %d pages.\n",
+ idx + 1, size, nr_pages);
+ goto error_out;
+ }
+
+ }
+
+ return 0;
+
+error_out:
+
+ /* Only last element can be null pointer so check for it first. */
+ if ((*buf)->data[idx])
+ kfree((*buf)->data[idx]);
+
+ for (--idx; idx >= 0; --idx)
+ kfree((*buf)->data[idx]);
+
+ kfree(*buf);
+ return -ENOMEM;
+}
+EXPORT_SYMBOL(drm_buffer_alloc);
+
+/**
+ * Copy the user data to the begin of the buffer and reset the processing
+ * iterator.
+ *
+ * user_data: A pointer the data that is copied to the buffer.
+ * size: The Number of bytes to copy.
+ */
+extern int drm_buffer_copy_from_user(struct drm_buffer *buf,
+ void __user *user_data, int size)
+{
+ int nr_pages = size / PAGE_SIZE + 1;
+ int idx;
+
+ if (size > buf->size) {
+ DRM_ERROR("Requesting to copy %d bytes to a drm buffer with"
+ " %d bytes space\n",
+ size, buf->size);
+ return -EFAULT;
+ }
+
+ for (idx = 0; idx < nr_pages; ++idx) {
+
+ if (DRM_COPY_FROM_USER(buf->data[idx],
+ user_data + idx * PAGE_SIZE,
+ min(PAGE_SIZE, size - idx * PAGE_SIZE))) {
+ DRM_ERROR("Failed to copy user data (%p) to drm buffer"
+ " (%p) %dth page.\n",
+ user_data, buf, idx);
+ return -EFAULT;
+
+ }
+ }
+ buf->iterator = 0;
+ return 0;
+}
+EXPORT_SYMBOL(drm_buffer_copy_from_user);
+
+/**
+ * Free the drm buffer object
+ */
+void drm_buffer_free(struct drm_buffer *buf)
+{
+
+ if (buf != NULL) {
+
+ int nr_pages = buf->size / PAGE_SIZE + 1;
+ int idx;
+ for (idx = 0; idx < nr_pages; ++idx)
+ kfree(buf->data[idx]);
+
+ kfree(buf);
+ }
+}
+EXPORT_SYMBOL(drm_buffer_free);
+
+/**
+ * Read an object from buffer that may be split to multiple parts. If object
+ * is not split function just returns the pointer to object in buffer. But in
+ * case of split object data is copied to given stack object that is suplied
+ * by caller.
+ *
+ * The processing location of the buffer is also advanced to the next byte
+ * after the object.
+ *
+ * objsize: The size of the objet in bytes.
+ * stack_obj: A pointer to a memory location where object can be copied.
+ */
+void *drm_buffer_read_object(struct drm_buffer *buf,
+ int objsize, void *stack_obj)
+{
+ int idx = drm_buffer_index(buf);
+ int page = drm_buffer_page(buf);
+ void *obj = 0;
+
+ if (idx + objsize <= PAGE_SIZE) {
+ obj = &buf->data[page][idx];
+ } else {
+ /* The object is split which forces copy to temporary object.*/
+ int beginsz = PAGE_SIZE - idx;
+ memcpy(stack_obj, &buf->data[page][idx], beginsz);
+
+ memcpy(stack_obj + beginsz, &buf->data[page + 1][0],
+ objsize - beginsz);
+
+ obj = stack_obj;
+ }
+
+ drm_buffer_advance(buf, objsize);
+ return obj;
+}
+EXPORT_SYMBOL(drm_buffer_read_object);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 7d0f00a935fa..f2aaf39be398 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -836,11 +836,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
mode_changed = true;
} else if (set->fb == NULL) {
mode_changed = true;
- } else if ((set->fb->bits_per_pixel !=
- set->crtc->fb->bits_per_pixel) ||
- set->fb->depth != set->crtc->fb->depth)
- fb_changed = true;
- else
+ } else
fb_changed = true;
}
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 766c46875a20..f3c58e2bd75c 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -125,28 +125,28 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, 0),
- DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH),
-
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW)
+ DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED)
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index defcaf108460..f97e7c42ac8e 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -60,8 +60,7 @@
#define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5)
/* use +hsync +vsync for detailed mode */
#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6)
-/* define the number of Extension EDID block */
-#define MAX_EDID_EXT_NUM 4
+
#define LEVEL_DMT 0
#define LEVEL_GTF 1
@@ -114,14 +113,14 @@ static const u8 edid_header[] = {
};
/**
- * edid_is_valid - sanity check EDID data
+ * drm_edid_is_valid - sanity check EDID data
* @edid: EDID data
*
* Sanity check the EDID block by looking at the header, the version number
* and the checksum. Return 0 if the EDID doesn't check out, or 1 if it's
* valid.
*/
-static bool edid_is_valid(struct edid *edid)
+bool drm_edid_is_valid(struct edid *edid)
{
int i, score = 0;
u8 csum = 0;
@@ -163,6 +162,7 @@ bad:
}
return 0;
}
+EXPORT_SYMBOL(drm_edid_is_valid);
/**
* edid_vendor - match a string against EDID's obfuscated vendor field
@@ -598,6 +598,50 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
return mode;
}
+/*
+ * EDID is delightfully ambiguous about how interlaced modes are to be
+ * encoded. Our internal representation is of frame height, but some
+ * HDTV detailed timings are encoded as field height.
+ *
+ * The format list here is from CEA, in frame size. Technically we
+ * should be checking refresh rate too. Whatever.
+ */
+static void
+drm_mode_do_interlace_quirk(struct drm_display_mode *mode,
+ struct detailed_pixel_timing *pt)
+{
+ int i;
+ static const struct {
+ int w, h;
+ } cea_interlaced[] = {
+ { 1920, 1080 },
+ { 720, 480 },
+ { 1440, 480 },
+ { 2880, 480 },
+ { 720, 576 },
+ { 1440, 576 },
+ { 2880, 576 },
+ };
+ static const int n_sizes =
+ sizeof(cea_interlaced)/sizeof(cea_interlaced[0]);
+
+ if (!(pt->misc & DRM_EDID_PT_INTERLACED))
+ return;
+
+ for (i = 0; i < n_sizes; i++) {
+ if ((mode->hdisplay == cea_interlaced[i].w) &&
+ (mode->vdisplay == cea_interlaced[i].h / 2)) {
+ mode->vdisplay *= 2;
+ mode->vsync_start *= 2;
+ mode->vsync_end *= 2;
+ mode->vtotal *= 2;
+ mode->vtotal |= 1;
+ }
+ }
+
+ mode->flags |= DRM_MODE_FLAG_INTERLACE;
+}
+
/**
* drm_mode_detailed - create a new mode from an EDID detailed timing section
* @dev: DRM device (needed to create new mode)
@@ -633,8 +677,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
return NULL;
}
if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) {
- printk(KERN_WARNING "integrated sync not supported\n");
- return NULL;
+ printk(KERN_WARNING "composite sync not supported\n");
}
/* it is incorrect if hsync/vsync width is zero */
@@ -681,8 +724,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
drm_mode_set_name(mode);
- if (pt->misc & DRM_EDID_PT_INTERLACED)
- mode->flags |= DRM_MODE_FLAG_INTERLACE;
+ drm_mode_do_interlace_quirk(mode, pt);
if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE;
@@ -1070,8 +1112,8 @@ static int add_detailed_info_eedid(struct drm_connector *connector,
}
/* Chose real EDID extension number */
- edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ?
- MAX_EDID_EXT_NUM : edid->extensions;
+ edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ?
+ DRM_MAX_EDID_EXT_NUM : edid->extensions;
/* Find CEA extension */
for (i = 0; i < edid_ext_num; i++) {
@@ -1153,7 +1195,7 @@ static int drm_ddc_read_edid(struct drm_connector *connector,
for (i = 0; i < 4; i++) {
if (drm_do_probe_ddc_edid(adapter, buf, len))
return -1;
- if (edid_is_valid((struct edid *)buf))
+ if (drm_edid_is_valid((struct edid *)buf))
return 0;
}
@@ -1178,7 +1220,7 @@ struct edid *drm_get_edid(struct drm_connector *connector,
int ret;
struct edid *edid;
- edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1),
+ edid = kmalloc(EDID_LENGTH * (DRM_MAX_EDID_EXT_NUM + 1),
GFP_KERNEL);
if (edid == NULL) {
dev_warn(&connector->dev->pdev->dev,
@@ -1196,14 +1238,14 @@ struct edid *drm_get_edid(struct drm_connector *connector,
if (edid->extensions != 0) {
int edid_ext_num = edid->extensions;
- if (edid_ext_num > MAX_EDID_EXT_NUM) {
+ if (edid_ext_num > DRM_MAX_EDID_EXT_NUM) {
dev_warn(&connector->dev->pdev->dev,
"The number of extension(%d) is "
"over max (%d), actually read number (%d)\n",
- edid_ext_num, MAX_EDID_EXT_NUM,
- MAX_EDID_EXT_NUM);
+ edid_ext_num, DRM_MAX_EDID_EXT_NUM,
+ DRM_MAX_EDID_EXT_NUM);
/* Reset EDID extension number to be read */
- edid_ext_num = MAX_EDID_EXT_NUM;
+ edid_ext_num = DRM_MAX_EDID_EXT_NUM;
}
/* Read EDID including extensions too */
ret = drm_ddc_read_edid(connector, adapter, (char *)edid,
@@ -1246,8 +1288,8 @@ bool drm_detect_hdmi_monitor(struct edid *edid)
goto end;
/* Chose real EDID extension number */
- edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ?
- MAX_EDID_EXT_NUM : edid->extensions;
+ edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ?
+ DRM_MAX_EDID_EXT_NUM : edid->extensions;
/* Find CEA extension */
for (i = 0; i < edid_ext_num; i++) {
@@ -1304,7 +1346,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
if (edid == NULL) {
return 0;
}
- if (!edid_is_valid(edid)) {
+ if (!drm_edid_is_valid(edid)) {
dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
drm_get_connector_name(connector));
return 0;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 1c2b7d44ec05..50549703584f 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -27,6 +27,7 @@
* Dave Airlie <airlied@linux.ie>
* Jesse Barnes <jesse.barnes@intel.com>
*/
+#include <linux/kernel.h>
#include <linux/sysrq.h>
#include <linux/fb.h>
#include "drmP.h"
@@ -50,21 +51,6 @@ int drm_fb_helper_add_connector(struct drm_connector *connector)
}
EXPORT_SYMBOL(drm_fb_helper_add_connector);
-static int my_atoi(const char *name)
-{
- int val = 0;
-
- for (;; name++) {
- switch (*name) {
- case '0' ... '9':
- val = 10*val+(*name-'0');
- break;
- default:
- return val;
- }
- }
-}
-
/**
* drm_fb_helper_connector_parse_command_line - parse command line for connector
* @connector - connector to parse line for
@@ -111,7 +97,7 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *con
namelen = i;
if (!refresh_specified && !bpp_specified &&
!yres_specified) {
- refresh = my_atoi(&name[i+1]);
+ refresh = simple_strtol(&name[i+1], NULL, 10);
refresh_specified = 1;
if (cvt || rb)
cvt = 0;
@@ -121,7 +107,7 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *con
case '-':
namelen = i;
if (!bpp_specified && !yres_specified) {
- bpp = my_atoi(&name[i+1]);
+ bpp = simple_strtol(&name[i+1], NULL, 10);
bpp_specified = 1;
if (cvt || rb)
cvt = 0;
@@ -130,7 +116,7 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *con
break;
case 'x':
if (!yres_specified) {
- yres = my_atoi(&name[i+1]);
+ yres = simple_strtol(&name[i+1], NULL, 10);
yres_specified = 1;
} else
goto done;
@@ -170,7 +156,7 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *con
}
}
if (i < 0 && yres_specified) {
- xres = my_atoi(name);
+ xres = simple_strtol(name, NULL, 10);
res_specified = 1;
}
done:
@@ -389,7 +375,7 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
break;
/* Display: Off; HSync: On, VSync: On */
case FB_BLANK_NORMAL:
- drm_fb_helper_off(info, DRM_MODE_DPMS_ON);
+ drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
break;
/* Display: Off; HSync: Off, VSync: On */
case FB_BLANK_HSYNC_SUSPEND:
@@ -694,7 +680,7 @@ int drm_fb_helper_set_par(struct fb_info *info)
int i;
if (var->pixclock != 0) {
- DRM_ERROR("PIXEL CLCOK SET\n");
+ DRM_ERROR("PIXEL CLOCK SET\n");
return -EINVAL;
}
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index e9dbb481c469..aa89d4b0b4c4 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -142,19 +142,6 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size)
if (IS_ERR(obj->filp))
goto free;
- /* Basically we want to disable the OOM killer and handle ENOMEM
- * ourselves by sacrificing pages from cached buffers.
- * XXX shmem_file_[gs]et_gfp_mask()
- */
- mapping_set_gfp_mask(obj->filp->f_path.dentry->d_inode->i_mapping,
- GFP_HIGHUSER |
- __GFP_COLD |
- __GFP_FS |
- __GFP_RECLAIMABLE |
- __GFP_NORETRY |
- __GFP_NOWARN |
- __GFP_NOMEMALLOC);
-
kref_init(&obj->refcount);
kref_init(&obj->handlecount);
obj->size = size;
@@ -205,9 +192,7 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)
idr_remove(&filp->object_idr, handle);
spin_unlock(&filp->table_lock);
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_handle_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_handle_unreference_unlocked(obj);
return 0;
}
@@ -338,9 +323,7 @@ again:
}
err:
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(obj);
return ret;
}
@@ -371,9 +354,7 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
return -ENOENT;
ret = drm_gem_handle_create(file_priv, obj, &handle);
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(obj);
if (ret)
return ret;
@@ -403,7 +384,7 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
{
struct drm_gem_object *obj = ptr;
- drm_gem_object_handle_unreference(obj);
+ drm_gem_object_handle_unreference_unlocked(obj);
return 0;
}
@@ -416,16 +397,25 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
void
drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
{
- mutex_lock(&dev->struct_mutex);
idr_for_each(&file_private->object_idr,
&drm_gem_object_release_handle, NULL);
idr_destroy(&file_private->object_idr);
- mutex_unlock(&dev->struct_mutex);
+}
+
+static void
+drm_gem_object_free_common(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ fput(obj->filp);
+ atomic_dec(&dev->object_count);
+ atomic_sub(obj->size, &dev->object_memory);
+ kfree(obj);
}
/**
* Called after the last reference to the object has been lost.
+ * Must be called holding struct_ mutex
*
* Frees the object
*/
@@ -440,14 +430,40 @@ drm_gem_object_free(struct kref *kref)
if (dev->driver->gem_free_object != NULL)
dev->driver->gem_free_object(obj);
- fput(obj->filp);
- atomic_dec(&dev->object_count);
- atomic_sub(obj->size, &dev->object_memory);
- kfree(obj);
+ drm_gem_object_free_common(obj);
}
EXPORT_SYMBOL(drm_gem_object_free);
/**
+ * Called after the last reference to the object has been lost.
+ * Must be called without holding struct_mutex
+ *
+ * Frees the object
+ */
+void
+drm_gem_object_free_unlocked(struct kref *kref)
+{
+ struct drm_gem_object *obj = (struct drm_gem_object *) kref;
+ struct drm_device *dev = obj->dev;
+
+ if (dev->driver->gem_free_object_unlocked != NULL)
+ dev->driver->gem_free_object_unlocked(obj);
+ else if (dev->driver->gem_free_object != NULL) {
+ mutex_lock(&dev->struct_mutex);
+ dev->driver->gem_free_object(obj);
+ mutex_unlock(&dev->struct_mutex);
+ }
+
+ drm_gem_object_free_common(obj);
+}
+EXPORT_SYMBOL(drm_gem_object_free_unlocked);
+
+static void drm_gem_object_ref_bug(struct kref *list_kref)
+{
+ BUG();
+}
+
+/**
* Called after the last handle to the object has been closed
*
* Removes any name for the object. Note that this must be
@@ -471,8 +487,10 @@ drm_gem_object_handle_free(struct kref *kref)
/*
* The object name held a reference to this object, drop
* that now.
+ *
+ * This cannot be the last reference, since the handle holds one too.
*/
- drm_gem_object_unreference(obj);
+ kref_put(&obj->refcount, drm_gem_object_ref_bug);
} else
spin_unlock(&dev->object_name_lock);
@@ -490,11 +508,8 @@ EXPORT_SYMBOL(drm_gem_vm_open);
void drm_gem_vm_close(struct vm_area_struct *vma)
{
struct drm_gem_object *obj = vma->vm_private_data;
- struct drm_device *dev = obj->dev;
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(obj);
}
EXPORT_SYMBOL(drm_gem_vm_close);
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index cdec32977129..2ac074c8f5d2 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -405,7 +405,8 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm,
wasted += alignment - tmp;
}
- if (entry->size >= size + wasted) {
+ if (entry->size >= size + wasted &&
+ (entry->start + wasted + size) <= end) {
if (!best_match)
return entry;
if (entry->size < best_size) {
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 7e42b7e9d43a..014ce24761b9 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -70,19 +70,17 @@ static int drm_class_resume(struct device *dev)
return 0;
}
-/* Display the version of drm_core. This doesn't work right in current design */
-static ssize_t version_show(struct class *dev, char *buf)
-{
- return sprintf(buf, "%s %d.%d.%d %s\n", CORE_NAME, CORE_MAJOR,
- CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
-}
-
static char *drm_devnode(struct device *dev, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
}
-static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
+static CLASS_ATTR_STRING(version, S_IRUGO,
+ CORE_NAME " "
+ __stringify(CORE_MAJOR) "."
+ __stringify(CORE_MINOR) "."
+ __stringify(CORE_PATCHLEVEL) " "
+ CORE_DATE);
/**
* drm_sysfs_create - create a struct drm_sysfs_class structure
@@ -109,7 +107,7 @@ struct class *drm_sysfs_create(struct module *owner, char *name)
class->suspend = drm_class_suspend;
class->resume = drm_class_resume;
- err = class_create_file(class, &class_attr_version);
+ err = class_create_file(class, &class_attr_version.attr);
if (err)
goto err_out_class;
@@ -132,7 +130,7 @@ void drm_sysfs_destroy(void)
{
if ((drm_class == NULL) || (IS_ERR(drm_class)))
return;
- class_remove_file(drm_class, &class_attr_version);
+ class_remove_file(drm_class, &class_attr_version.attr);
class_destroy(drm_class);
}
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 9c9998c4dceb..1376dfe44c95 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -162,7 +162,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- if (!IS_IRONLAKE(dev)) {
+ if (!HAS_PCH_SPLIT(dev)) {
seq_printf(m, "Interrupt enable: %08x\n",
I915_READ(IER));
seq_printf(m, "Interrupt identity: %08x\n",
@@ -290,7 +290,7 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data)
list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) {
obj = obj_priv->obj;
if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) {
- ret = i915_gem_object_get_pages(obj);
+ ret = i915_gem_object_get_pages(obj, 0);
if (ret) {
DRM_ERROR("Failed to get pages: %d\n", ret);
spin_unlock(&dev_priv->mm.active_list_lock);
@@ -350,6 +350,36 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
return 0;
}
+static const char *pin_flag(int pinned)
+{
+ if (pinned > 0)
+ return " P";
+ else if (pinned < 0)
+ return " p";
+ else
+ return "";
+}
+
+static const char *tiling_flag(int tiling)
+{
+ switch (tiling) {
+ default:
+ case I915_TILING_NONE: return "";
+ case I915_TILING_X: return " X";
+ case I915_TILING_Y: return " Y";
+ }
+}
+
+static const char *dirty_flag(int dirty)
+{
+ return dirty ? " dirty" : "";
+}
+
+static const char *purgeable_flag(int purgeable)
+{
+ return purgeable ? " purgeable" : "";
+}
+
static int i915_error_state(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -357,6 +387,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_error_state *error;
unsigned long flags;
+ int i, page, offset, elt;
spin_lock_irqsave(&dev_priv->error_lock, flags);
if (!dev_priv->first_error) {
@@ -368,6 +399,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
error->time.tv_usec);
+ seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
seq_printf(m, "EIR: 0x%08x\n", error->eir);
seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er);
seq_printf(m, " INSTPM: 0x%08x\n", error->instpm);
@@ -379,6 +411,59 @@ static int i915_error_state(struct seq_file *m, void *unused)
seq_printf(m, " INSTPS: 0x%08x\n", error->instps);
seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1);
}
+ seq_printf(m, "seqno: 0x%08x\n", error->seqno);
+
+ if (error->active_bo_count) {
+ seq_printf(m, "Buffers [%d]:\n", error->active_bo_count);
+
+ for (i = 0; i < error->active_bo_count; i++) {
+ seq_printf(m, " %08x %8zd %08x %08x %08x%s%s%s%s",
+ error->active_bo[i].gtt_offset,
+ error->active_bo[i].size,
+ error->active_bo[i].read_domains,
+ error->active_bo[i].write_domain,
+ error->active_bo[i].seqno,
+ pin_flag(error->active_bo[i].pinned),
+ tiling_flag(error->active_bo[i].tiling),
+ dirty_flag(error->active_bo[i].dirty),
+ purgeable_flag(error->active_bo[i].purgeable));
+
+ if (error->active_bo[i].name)
+ seq_printf(m, " (name: %d)", error->active_bo[i].name);
+ if (error->active_bo[i].fence_reg != I915_FENCE_REG_NONE)
+ seq_printf(m, " (fence: %d)", error->active_bo[i].fence_reg);
+
+ seq_printf(m, "\n");
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(error->batchbuffer); i++) {
+ if (error->batchbuffer[i]) {
+ struct drm_i915_error_object *obj = error->batchbuffer[i];
+
+ seq_printf(m, "--- gtt_offset = 0x%08x\n", obj->gtt_offset);
+ offset = 0;
+ for (page = 0; page < obj->page_count; page++) {
+ for (elt = 0; elt < PAGE_SIZE/4; elt++) {
+ seq_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]);
+ offset += 4;
+ }
+ }
+ }
+ }
+
+ if (error->ringbuffer) {
+ struct drm_i915_error_object *obj = error->ringbuffer;
+
+ seq_printf(m, "--- ringbuffer = 0x%08x\n", obj->gtt_offset);
+ offset = 0;
+ for (page = 0; page < obj->page_count; page++) {
+ for (elt = 0; elt < PAGE_SIZE/4; elt++) {
+ seq_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]);
+ offset += 4;
+ }
+ }
+ }
out:
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
@@ -386,6 +471,165 @@ out:
return 0;
}
+static int i915_rstdby_delays(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u16 crstanddelay = I915_READ16(CRSTANDVID);
+
+ seq_printf(m, "w/ctx: %d, w/o ctx: %d\n", (crstanddelay >> 8) & 0x3f, (crstanddelay & 0x3f));
+
+ return 0;
+}
+
+static int i915_cur_delayinfo(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u16 rgvswctl = I915_READ16(MEMSWCTL);
+
+ seq_printf(m, "Last command: 0x%01x\n", (rgvswctl >> 13) & 0x3);
+ seq_printf(m, "Command status: %d\n", (rgvswctl >> 12) & 1);
+ seq_printf(m, "P%d DELAY 0x%02x\n", (rgvswctl >> 8) & 0xf,
+ rgvswctl & 0x3f);
+
+ return 0;
+}
+
+static int i915_delayfreq_table(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 delayfreq;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ delayfreq = I915_READ(PXVFREQ_BASE + i * 4);
+ seq_printf(m, "P%02dVIDFREQ: 0x%08x\n", i, delayfreq);
+ }
+
+ return 0;
+}
+
+static inline int MAP_TO_MV(int map)
+{
+ return 1250 - (map * 25);
+}
+
+static int i915_inttoext_table(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 inttoext;
+ int i;
+
+ for (i = 1; i <= 32; i++) {
+ inttoext = I915_READ(INTTOEXT_BASE_ILK + i * 4);
+ seq_printf(m, "INTTOEXT%02d: 0x%08x\n", i, inttoext);
+ }
+
+ return 0;
+}
+
+static int i915_drpc_info(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 rgvmodectl = I915_READ(MEMMODECTL);
+
+ seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ?
+ "yes" : "no");
+ seq_printf(m, "Boost freq: %d\n",
+ (rgvmodectl & MEMMODE_BOOST_FREQ_MASK) >>
+ MEMMODE_BOOST_FREQ_SHIFT);
+ seq_printf(m, "HW control enabled: %s\n",
+ rgvmodectl & MEMMODE_HWIDLE_EN ? "yes" : "no");
+ seq_printf(m, "SW control enabled: %s\n",
+ rgvmodectl & MEMMODE_SWMODE_EN ? "yes" : "no");
+ seq_printf(m, "Gated voltage change: %s\n",
+ rgvmodectl & MEMMODE_RCLK_GATE ? "yes" : "no");
+ seq_printf(m, "Starting frequency: P%d\n",
+ (rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT);
+ seq_printf(m, "Max frequency: P%d\n",
+ (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT);
+ seq_printf(m, "Min frequency: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK));
+
+ return 0;
+}
+
+static int i915_fbc_status(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_crtc *crtc;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ bool fbc_enabled = false;
+
+ if (!dev_priv->display.fbc_enabled) {
+ seq_printf(m, "FBC unsupported on this chipset\n");
+ return 0;
+ }
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ if (!crtc->enabled)
+ continue;
+ if (dev_priv->display.fbc_enabled(crtc))
+ fbc_enabled = true;
+ }
+
+ if (fbc_enabled) {
+ seq_printf(m, "FBC enabled\n");
+ } else {
+ seq_printf(m, "FBC disabled: ");
+ switch (dev_priv->no_fbc_reason) {
+ case FBC_STOLEN_TOO_SMALL:
+ seq_printf(m, "not enough stolen memory");
+ break;
+ case FBC_UNSUPPORTED_MODE:
+ seq_printf(m, "mode not supported");
+ break;
+ case FBC_MODE_TOO_LARGE:
+ seq_printf(m, "mode too large");
+ break;
+ case FBC_BAD_PLANE:
+ seq_printf(m, "FBC unsupported on plane");
+ break;
+ case FBC_NOT_TILED:
+ seq_printf(m, "scanout buffer not tiled");
+ break;
+ default:
+ seq_printf(m, "unknown reason");
+ }
+ seq_printf(m, "\n");
+ }
+ return 0;
+}
+
+static int i915_sr_status(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ bool sr_enabled = false;
+
+ if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev))
+ sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
+ else if (IS_I915GM(dev))
+ sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN;
+ else if (IS_PINEVIEW(dev))
+ sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN;
+
+ seq_printf(m, "self-refresh: %s\n", sr_enabled ? "enabled" :
+ "disabled");
+
+ return 0;
+}
+
static int
i915_wedged_open(struct inode *inode,
struct file *filp)
@@ -503,6 +747,13 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_ringbuffer_info", i915_ringbuffer_info, 0},
{"i915_batchbuffers", i915_batchbuffer_info, 0},
{"i915_error_state", i915_error_state, 0},
+ {"i915_rstdby_delays", i915_rstdby_delays, 0},
+ {"i915_cur_delayinfo", i915_cur_delayinfo, 0},
+ {"i915_delayfreq_table", i915_delayfreq_table, 0},
+ {"i915_inttoext_table", i915_inttoext_table, 0},
+ {"i915_drpc_info", i915_drpc_info, 0},
+ {"i915_fbc_status", i915_fbc_status, 0},
+ {"i915_sr_status", i915_sr_status, 0},
};
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index bbe47812e4b6..8bfc0bbf13e6 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -35,6 +35,9 @@
#include "i915_drv.h"
#include "i915_trace.h"
#include <linux/vgaarb.h>
+#include <linux/acpi.h>
+#include <linux/pnp.h>
+#include <linux/vga_switcheroo.h>
/* Really want an OS-independent resettable timer. Would like to have
* this loop run for (eg) 3 sec, but have the timer reset every time
@@ -134,6 +137,10 @@ static int i915_init_phys_hws(struct drm_device *dev)
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+ if (IS_I965G(dev))
+ dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) &
+ 0xf0;
+
I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
DRM_DEBUG_DRIVER("Enabled hardware status page\n");
return 0;
@@ -731,8 +738,10 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
if (cmdbuf->num_cliprects) {
cliprects = kcalloc(cmdbuf->num_cliprects,
sizeof(struct drm_clip_rect), GFP_KERNEL);
- if (cliprects == NULL)
+ if (cliprects == NULL) {
+ ret = -ENOMEM;
goto fail_batch_free;
+ }
ret = copy_from_user(cliprects, cmdbuf->cliprects,
cmdbuf->num_cliprects *
@@ -927,6 +936,120 @@ static int i915_get_bridge_dev(struct drm_device *dev)
return 0;
}
+#define MCHBAR_I915 0x44
+#define MCHBAR_I965 0x48
+#define MCHBAR_SIZE (4*4096)
+
+#define DEVEN_REG 0x54
+#define DEVEN_MCHBAR_EN (1 << 28)
+
+/* Allocate space for the MCH regs if needed, return nonzero on error */
+static int
+intel_alloc_mchbar_resource(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+ u32 temp_lo, temp_hi = 0;
+ u64 mchbar_addr;
+ int ret = 0;
+
+ if (IS_I965G(dev))
+ pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
+ pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
+ mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
+
+ /* If ACPI doesn't have it, assume we need to allocate it ourselves */
+#ifdef CONFIG_PNP
+ if (mchbar_addr &&
+ pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
+ ret = 0;
+ goto out;
+ }
+#endif
+
+ /* Get some space for it */
+ ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus, &dev_priv->mch_res,
+ MCHBAR_SIZE, MCHBAR_SIZE,
+ PCIBIOS_MIN_MEM,
+ 0, pcibios_align_resource,
+ dev_priv->bridge_dev);
+ if (ret) {
+ DRM_DEBUG_DRIVER("failed bus alloc: %d\n", ret);
+ dev_priv->mch_res.start = 0;
+ goto out;
+ }
+
+ if (IS_I965G(dev))
+ pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
+ upper_32_bits(dev_priv->mch_res.start));
+
+ pci_write_config_dword(dev_priv->bridge_dev, reg,
+ lower_32_bits(dev_priv->mch_res.start));
+out:
+ return ret;
+}
+
+/* Setup MCHBAR if possible, return true if we should disable it again */
+static void
+intel_setup_mchbar(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+ u32 temp;
+ bool enabled;
+
+ dev_priv->mchbar_need_disable = false;
+
+ if (IS_I915G(dev) || IS_I915GM(dev)) {
+ pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
+ enabled = !!(temp & DEVEN_MCHBAR_EN);
+ } else {
+ pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
+ enabled = temp & 1;
+ }
+
+ /* If it's already enabled, don't have to do anything */
+ if (enabled)
+ return;
+
+ if (intel_alloc_mchbar_resource(dev))
+ return;
+
+ dev_priv->mchbar_need_disable = true;
+
+ /* Space is allocated or reserved, so enable it. */
+ if (IS_I915G(dev) || IS_I915GM(dev)) {
+ pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG,
+ temp | DEVEN_MCHBAR_EN);
+ } else {
+ pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
+ pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp | 1);
+ }
+}
+
+static void
+intel_teardown_mchbar(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+ u32 temp;
+
+ if (dev_priv->mchbar_need_disable) {
+ if (IS_I915G(dev) || IS_I915GM(dev)) {
+ pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
+ temp &= ~DEVEN_MCHBAR_EN;
+ pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG, temp);
+ } else {
+ pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
+ temp &= ~1;
+ pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp);
+ }
+ }
+
+ if (dev_priv->mch_res.start)
+ release_resource(&dev_priv->mch_res);
+}
+
/**
* i915_probe_agp - get AGP bootup configuration
* @pdev: PCI device
@@ -972,59 +1095,123 @@ static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
* Some of the preallocated space is taken by the GTT
* and popup. GTT is 1K per MB of aperture size, and popup is 4K.
*/
- if (IS_G4X(dev) || IS_PINEVIEW(dev) || IS_IRONLAKE(dev))
+ if (IS_G4X(dev) || IS_PINEVIEW(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev))
overhead = 4096;
else
overhead = (*aperture_size / 1024) + 4096;
- switch (tmp & INTEL_GMCH_GMS_MASK) {
- case INTEL_855_GMCH_GMS_DISABLED:
- DRM_ERROR("video memory is disabled\n");
- return -1;
- case INTEL_855_GMCH_GMS_STOLEN_1M:
- stolen = 1 * 1024 * 1024;
- break;
- case INTEL_855_GMCH_GMS_STOLEN_4M:
- stolen = 4 * 1024 * 1024;
- break;
- case INTEL_855_GMCH_GMS_STOLEN_8M:
- stolen = 8 * 1024 * 1024;
- break;
- case INTEL_855_GMCH_GMS_STOLEN_16M:
- stolen = 16 * 1024 * 1024;
- break;
- case INTEL_855_GMCH_GMS_STOLEN_32M:
- stolen = 32 * 1024 * 1024;
- break;
- case INTEL_915G_GMCH_GMS_STOLEN_48M:
- stolen = 48 * 1024 * 1024;
- break;
- case INTEL_915G_GMCH_GMS_STOLEN_64M:
- stolen = 64 * 1024 * 1024;
- break;
- case INTEL_GMCH_GMS_STOLEN_128M:
- stolen = 128 * 1024 * 1024;
- break;
- case INTEL_GMCH_GMS_STOLEN_256M:
- stolen = 256 * 1024 * 1024;
- break;
- case INTEL_GMCH_GMS_STOLEN_96M:
- stolen = 96 * 1024 * 1024;
- break;
- case INTEL_GMCH_GMS_STOLEN_160M:
- stolen = 160 * 1024 * 1024;
- break;
- case INTEL_GMCH_GMS_STOLEN_224M:
- stolen = 224 * 1024 * 1024;
- break;
- case INTEL_GMCH_GMS_STOLEN_352M:
- stolen = 352 * 1024 * 1024;
- break;
- default:
- DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
- tmp & INTEL_GMCH_GMS_MASK);
- return -1;
+ if (IS_GEN6(dev)) {
+ /* SNB has memory control reg at 0x50.w */
+ pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &tmp);
+
+ switch (tmp & SNB_GMCH_GMS_STOLEN_MASK) {
+ case INTEL_855_GMCH_GMS_DISABLED:
+ DRM_ERROR("video memory is disabled\n");
+ return -1;
+ case SNB_GMCH_GMS_STOLEN_32M:
+ stolen = 32 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_64M:
+ stolen = 64 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_96M:
+ stolen = 96 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_128M:
+ stolen = 128 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_160M:
+ stolen = 160 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_192M:
+ stolen = 192 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_224M:
+ stolen = 224 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_256M:
+ stolen = 256 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_288M:
+ stolen = 288 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_320M:
+ stolen = 320 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_352M:
+ stolen = 352 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_384M:
+ stolen = 384 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_416M:
+ stolen = 416 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_448M:
+ stolen = 448 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_480M:
+ stolen = 480 * 1024 * 1024;
+ break;
+ case SNB_GMCH_GMS_STOLEN_512M:
+ stolen = 512 * 1024 * 1024;
+ break;
+ default:
+ DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
+ tmp & SNB_GMCH_GMS_STOLEN_MASK);
+ return -1;
+ }
+ } else {
+ switch (tmp & INTEL_GMCH_GMS_MASK) {
+ case INTEL_855_GMCH_GMS_DISABLED:
+ DRM_ERROR("video memory is disabled\n");
+ return -1;
+ case INTEL_855_GMCH_GMS_STOLEN_1M:
+ stolen = 1 * 1024 * 1024;
+ break;
+ case INTEL_855_GMCH_GMS_STOLEN_4M:
+ stolen = 4 * 1024 * 1024;
+ break;
+ case INTEL_855_GMCH_GMS_STOLEN_8M:
+ stolen = 8 * 1024 * 1024;
+ break;
+ case INTEL_855_GMCH_GMS_STOLEN_16M:
+ stolen = 16 * 1024 * 1024;
+ break;
+ case INTEL_855_GMCH_GMS_STOLEN_32M:
+ stolen = 32 * 1024 * 1024;
+ break;
+ case INTEL_915G_GMCH_GMS_STOLEN_48M:
+ stolen = 48 * 1024 * 1024;
+ break;
+ case INTEL_915G_GMCH_GMS_STOLEN_64M:
+ stolen = 64 * 1024 * 1024;
+ break;
+ case INTEL_GMCH_GMS_STOLEN_128M:
+ stolen = 128 * 1024 * 1024;
+ break;
+ case INTEL_GMCH_GMS_STOLEN_256M:
+ stolen = 256 * 1024 * 1024;
+ break;
+ case INTEL_GMCH_GMS_STOLEN_96M:
+ stolen = 96 * 1024 * 1024;
+ break;
+ case INTEL_GMCH_GMS_STOLEN_160M:
+ stolen = 160 * 1024 * 1024;
+ break;
+ case INTEL_GMCH_GMS_STOLEN_224M:
+ stolen = 224 * 1024 * 1024;
+ break;
+ case INTEL_GMCH_GMS_STOLEN_352M:
+ stolen = 352 * 1024 * 1024;
+ break;
+ default:
+ DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
+ tmp & INTEL_GMCH_GMS_MASK);
+ return -1;
+ }
}
+
*preallocated_size = stolen - overhead;
*start = overhead;
@@ -1058,7 +1245,7 @@ static unsigned long i915_gtt_to_phys(struct drm_device *dev,
int gtt_offset, gtt_size;
if (IS_I965G(dev)) {
- if (IS_G4X(dev) || IS_IRONLAKE(dev)) {
+ if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) {
gtt_offset = 2*1024*1024;
gtt_size = 2*1024*1024;
} else {
@@ -1127,6 +1314,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
/* Leave 1M for line length buffer & misc. */
compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0);
if (!compressed_fb) {
+ dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
i915_warn_stolen(dev);
return;
}
@@ -1134,6 +1322,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
compressed_fb = drm_mm_get_block(compressed_fb, size, 4096);
if (!compressed_fb) {
i915_warn_stolen(dev);
+ dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
return;
}
@@ -1193,6 +1382,32 @@ static unsigned int i915_vga_set_decode(void *cookie, bool state)
return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
}
+static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+ pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
+ if (state == VGA_SWITCHEROO_ON) {
+ printk(KERN_INFO "i915: switched off\n");
+ /* i915 resume handler doesn't set to D0 */
+ pci_set_power_state(dev->pdev, PCI_D0);
+ i915_resume(dev);
+ } else {
+ printk(KERN_ERR "i915: switched off\n");
+ i915_suspend(dev, pmm);
+ }
+}
+
+static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+ bool can_switch;
+
+ spin_lock(&dev->count_lock);
+ can_switch = (dev->open_count == 0);
+ spin_unlock(&dev->count_lock);
+ return can_switch;
+}
+
static int i915_load_modeset_init(struct drm_device *dev,
unsigned long prealloc_start,
unsigned long prealloc_size,
@@ -1254,6 +1469,12 @@ static int i915_load_modeset_init(struct drm_device *dev,
if (ret)
goto destroy_ringbuffer;
+ ret = vga_switcheroo_register_client(dev->pdev,
+ i915_switcheroo_set_state,
+ i915_switcheroo_can_switch);
+ if (ret)
+ goto destroy_ringbuffer;
+
intel_modeset_init(dev);
ret = drm_irq_install(dev);
@@ -1275,7 +1496,9 @@ static int i915_load_modeset_init(struct drm_device *dev,
return 0;
destroy_ringbuffer:
+ mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev);
+ mutex_unlock(&dev->struct_mutex);
out:
return ret;
}
@@ -1439,11 +1662,14 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev->driver->get_vblank_counter = i915_get_vblank_counter;
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
- if (IS_G4X(dev) || IS_IRONLAKE(dev)) {
+ if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) {
dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
dev->driver->get_vblank_counter = gm45_get_vblank_counter;
}
+ /* Try to make sure MCHBAR is enabled before poking at it */
+ intel_setup_mchbar(dev);
+
i915_gem_load(dev);
/* Init HWS */
@@ -1517,6 +1743,8 @@ int i915_driver_unload(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ i915_destroy_error_state(dev);
+
destroy_workqueue(dev_priv->wq);
del_timer_sync(&dev_priv->hangcheck_timer);
@@ -1538,6 +1766,7 @@ int i915_driver_unload(struct drm_device *dev)
dev_priv->child_dev_num = 0;
}
drm_irq_uninstall(dev);
+ vga_switcheroo_unregister_client(dev->pdev);
vga_client_register(dev->pdev, NULL, NULL, NULL);
}
@@ -1563,6 +1792,8 @@ int i915_driver_unload(struct drm_device *dev)
intel_cleanup_overlay(dev);
}
+ intel_teardown_mchbar(dev);
+
pci_dev_put(dev_priv->bridge_dev);
kfree(dev->dev_private);
@@ -1605,6 +1836,7 @@ void i915_driver_lastclose(struct drm_device * dev)
if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) {
drm_fb_helper_restore();
+ vga_switcheroo_process_delayed_switch();
return;
}
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index be631cc3e4dc..1b2e95455c05 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -45,7 +45,11 @@ module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
unsigned int i915_powersave = 1;
module_param_named(powersave, i915_powersave, int, 0400);
+unsigned int i915_lvds_downclock = 0;
+module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
+
static struct drm_driver driver;
+extern int intel_agp_enabled;
#define INTEL_VGA_DEVICE(id, info) { \
.class = PCI_CLASS_DISPLAY_VGA << 8, \
@@ -117,7 +121,7 @@ const static struct intel_device_info intel_gm45_info = {
const static struct intel_device_info intel_pineview_info = {
.is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1,
- .has_pipe_cxsr = 1,
+ .need_gfx_hws = 1,
.has_hotplug = 1,
};
@@ -133,6 +137,16 @@ const static struct intel_device_info intel_ironlake_m_info = {
.has_hotplug = 1,
};
+const static struct intel_device_info intel_sandybridge_d_info = {
+ .is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1,
+ .has_hotplug = 1,
+};
+
+const static struct intel_device_info intel_sandybridge_m_info = {
+ .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1, .need_gfx_hws = 1,
+ .has_hotplug = 1,
+};
+
const static struct pci_device_id pciidlist[] = {
INTEL_VGA_DEVICE(0x3577, &intel_i830_info),
INTEL_VGA_DEVICE(0x2562, &intel_845g_info),
@@ -164,6 +178,8 @@ const static struct pci_device_id pciidlist[] = {
INTEL_VGA_DEVICE(0xa011, &intel_pineview_info),
INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info),
INTEL_VGA_DEVICE(0x0046, &intel_ironlake_m_info),
+ INTEL_VGA_DEVICE(0x0102, &intel_sandybridge_d_info),
+ INTEL_VGA_DEVICE(0x0106, &intel_sandybridge_m_info),
{0, 0, 0}
};
@@ -171,26 +187,20 @@ const static struct pci_device_id pciidlist[] = {
MODULE_DEVICE_TABLE(pci, pciidlist);
#endif
-static int i915_suspend(struct drm_device *dev, pm_message_t state)
+static int i915_drm_freeze(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (!dev || !dev_priv) {
- DRM_ERROR("dev: %p, dev_priv: %p\n", dev, dev_priv);
- DRM_ERROR("DRM not initialized, aborting suspend.\n");
- return -ENODEV;
- }
-
- if (state.event == PM_EVENT_PRETHAW)
- return 0;
-
pci_save_state(dev->pdev);
/* If KMS is active, we do the leavevt stuff here */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- if (i915_gem_idle(dev))
+ int error = i915_gem_idle(dev);
+ if (error) {
dev_err(&dev->pdev->dev,
- "GEM idle failed, resume may fail\n");
+ "GEM idle failed, resume might fail\n");
+ return error;
+ }
drm_irq_uninstall(dev);
}
@@ -198,26 +208,42 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
intel_opregion_free(dev, 1);
+ /* Modeset on resume, not lid events */
+ dev_priv->modeset_on_lid = 0;
+
+ return 0;
+}
+
+int i915_suspend(struct drm_device *dev, pm_message_t state)
+{
+ int error;
+
+ if (!dev || !dev->dev_private) {
+ DRM_ERROR("dev: %p\n", dev);
+ DRM_ERROR("DRM not initialized, aborting suspend.\n");
+ return -ENODEV;
+ }
+
+ if (state.event == PM_EVENT_PRETHAW)
+ return 0;
+
+ error = i915_drm_freeze(dev);
+ if (error)
+ return error;
+
if (state.event == PM_EVENT_SUSPEND) {
/* Shut down the device */
pci_disable_device(dev->pdev);
pci_set_power_state(dev->pdev, PCI_D3hot);
}
- /* Modeset on resume, not lid events */
- dev_priv->modeset_on_lid = 0;
-
return 0;
}
-static int i915_resume(struct drm_device *dev)
+static int i915_drm_thaw(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int ret = 0;
-
- if (pci_enable_device(dev->pdev))
- return -1;
- pci_set_master(dev->pdev);
+ int error = 0;
i915_restore_state(dev);
@@ -228,21 +254,28 @@ static int i915_resume(struct drm_device *dev)
mutex_lock(&dev->struct_mutex);
dev_priv->mm.suspended = 0;
- ret = i915_gem_init_ringbuffer(dev);
- if (ret != 0)
- ret = -1;
+ error = i915_gem_init_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex);
drm_irq_install(dev);
- }
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+
/* Resume the modeset for every activated CRTC */
drm_helper_resume_force_mode(dev);
}
dev_priv->modeset_on_lid = 0;
- return ret;
+ return error;
+}
+
+int i915_resume(struct drm_device *dev)
+{
+ if (pci_enable_device(dev->pdev))
+ return -EIO;
+
+ pci_set_master(dev->pdev);
+
+ return i915_drm_thaw(dev);
}
/**
@@ -383,57 +416,62 @@ i915_pci_remove(struct pci_dev *pdev)
drm_put_dev(dev);
}
-static int
-i915_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int i915_pm_suspend(struct device *dev)
{
- struct drm_device *dev = pci_get_drvdata(pdev);
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ int error;
- return i915_suspend(dev, state);
-}
+ if (!drm_dev || !drm_dev->dev_private) {
+ dev_err(dev, "DRM not initialized, aborting suspend.\n");
+ return -ENODEV;
+ }
-static int
-i915_pci_resume(struct pci_dev *pdev)
-{
- struct drm_device *dev = pci_get_drvdata(pdev);
+ error = i915_drm_freeze(drm_dev);
+ if (error)
+ return error;
- return i915_resume(dev);
-}
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
-static int
-i915_pm_suspend(struct device *dev)
-{
- return i915_pci_suspend(to_pci_dev(dev), PMSG_SUSPEND);
+ return 0;
}
-static int
-i915_pm_resume(struct device *dev)
+static int i915_pm_resume(struct device *dev)
{
- return i915_pci_resume(to_pci_dev(dev));
-}
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
-static int
-i915_pm_freeze(struct device *dev)
-{
- return i915_pci_suspend(to_pci_dev(dev), PMSG_FREEZE);
+ return i915_resume(drm_dev);
}
-static int
-i915_pm_thaw(struct device *dev)
+static int i915_pm_freeze(struct device *dev)
{
- /* thaw during hibernate, do nothing! */
- return 0;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+
+ if (!drm_dev || !drm_dev->dev_private) {
+ dev_err(dev, "DRM not initialized, aborting suspend.\n");
+ return -ENODEV;
+ }
+
+ return i915_drm_freeze(drm_dev);
}
-static int
-i915_pm_poweroff(struct device *dev)
+static int i915_pm_thaw(struct device *dev)
{
- return i915_pci_suspend(to_pci_dev(dev), PMSG_HIBERNATE);
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+
+ return i915_drm_thaw(drm_dev);
}
-static int
-i915_pm_restore(struct device *dev)
+static int i915_pm_poweroff(struct device *dev)
{
- return i915_pci_resume(to_pci_dev(dev));
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+
+ return i915_drm_freeze(drm_dev);
}
const struct dev_pm_ops i915_pm_ops = {
@@ -442,7 +480,7 @@ const struct dev_pm_ops i915_pm_ops = {
.freeze = i915_pm_freeze,
.thaw = i915_pm_thaw,
.poweroff = i915_pm_poweroff,
- .restore = i915_pm_restore,
+ .restore = i915_pm_resume,
};
static struct vm_operations_struct i915_gem_vm_ops = {
@@ -464,8 +502,11 @@ static struct drm_driver driver = {
.lastclose = i915_driver_lastclose,
.preclose = i915_driver_preclose,
.postclose = i915_driver_postclose,
+
+ /* Used in place of i915_pm_ops for non-DRIVER_MODESET */
.suspend = i915_suspend,
.resume = i915_resume,
+
.device_is_agp = i915_driver_device_is_agp,
.enable_vblank = i915_enable_vblank,
.disable_vblank = i915_disable_vblank,
@@ -518,6 +559,11 @@ static struct drm_driver driver = {
static int __init i915_init(void)
{
+ if (!intel_agp_enabled) {
+ DRM_ERROR("drm/i915 can't work without intel_agp module!\n");
+ return -ENODEV;
+ }
+
driver.num_ioctls = i915_max_ioctl;
i915_gem_shrinker_init();
@@ -543,6 +589,11 @@ static int __init i915_init(void)
driver.driver_features &= ~DRIVER_MODESET;
#endif
+ if (!(driver.driver_features & DRIVER_MODESET)) {
+ driver.suspend = i915_suspend;
+ driver.resume = i915_resume;
+ }
+
return drm_init(&driver);
}
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 29dd67626967..979439cfb827 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -150,7 +150,27 @@ struct drm_i915_error_state {
u32 instps;
u32 instdone1;
u32 seqno;
+ u64 bbaddr;
struct timeval time;
+ struct drm_i915_error_object {
+ int page_count;
+ u32 gtt_offset;
+ u32 *pages[0];
+ } *ringbuffer, *batchbuffer[2];
+ struct drm_i915_error_buffer {
+ size_t size;
+ u32 name;
+ u32 seqno;
+ u32 gtt_offset;
+ u32 read_domains;
+ u32 write_domain;
+ u32 fence_reg;
+ s32 pinned:2;
+ u32 tiling:2;
+ u32 dirty:1;
+ u32 purgeable:1;
+ } *active_bo;
+ u32 active_bo_count;
};
struct drm_i915_display_funcs {
@@ -192,6 +212,14 @@ struct intel_device_info {
u8 cursor_needs_physical : 1;
};
+enum no_fbc_reason {
+ FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */
+ FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */
+ FBC_MODE_TOO_LARGE, /* mode too large for compression */
+ FBC_BAD_PLANE, /* fbc not supported on plane */
+ FBC_NOT_TILED, /* buffer not tiled */
+};
+
typedef struct drm_i915_private {
struct drm_device *dev;
@@ -283,6 +311,7 @@ typedef struct drm_i915_private {
unsigned int lvds_use_ssc:1;
unsigned int edp_support:1;
int lvds_ssc_freq;
+ int edp_bpp;
struct notifier_block lid_notifier;
@@ -451,6 +480,7 @@ typedef struct drm_i915_private {
u32 savePIPEB_DATA_N1;
u32 savePIPEB_LINK_M1;
u32 savePIPEB_LINK_N1;
+ u32 saveMCHBAR_RENDER_STANDBY;
struct {
struct drm_mm gtt_space;
@@ -492,6 +522,15 @@ typedef struct drm_i915_private {
struct list_head flushing_list;
/**
+ * List of objects currently pending a GPU write flush.
+ *
+ * All elements on this list will belong to either the
+ * active_list or flushing_list, last_rendering_seqno can
+ * be used to differentiate between the two elements.
+ */
+ struct list_head gpu_write_list;
+
+ /**
* LRU list of objects which are not in the ringbuffer and
* are ready to unbind, but are still in the GTT.
*
@@ -580,6 +619,14 @@ typedef struct drm_i915_private {
int child_dev_num;
struct child_device_config *child_dev;
struct drm_connector *int_lvds_connector;
+
+ bool mchbar_need_disable;
+
+ u8 cur_delay;
+ u8 min_delay;
+ u8 max_delay;
+
+ enum no_fbc_reason no_fbc_reason;
} drm_i915_private_t;
/** driver private structure attached to each drm_gem_object */
@@ -591,6 +638,8 @@ struct drm_i915_gem_object {
/** This object's place on the active/flushing/inactive lists */
struct list_head list;
+ /** This object's place on GPU write list */
+ struct list_head gpu_write_list;
/** This object's place on the fenced object LRU */
struct list_head fence_list;
@@ -722,7 +771,10 @@ extern struct drm_ioctl_desc i915_ioctls[];
extern int i915_max_ioctl;
extern unsigned int i915_fbpercrtc;
extern unsigned int i915_powersave;
+extern unsigned int i915_lvds_downclock;
+extern int i915_suspend(struct drm_device *dev, pm_message_t state);
+extern int i915_resume(struct drm_device *dev);
extern void i915_save_display(struct drm_device *dev);
extern void i915_restore_display(struct drm_device *dev);
extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
@@ -748,6 +800,7 @@ extern int i965_reset(struct drm_device *dev, u8 flags);
/* i915_irq.c */
void i915_hangcheck_elapsed(unsigned long data);
+void i915_destroy_error_state(struct drm_device *dev);
extern int i915_irq_emit(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int i915_irq_wait(struct drm_device *dev, void *data,
@@ -864,12 +917,13 @@ int i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptib
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
int write);
+int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj);
int i915_gem_attach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj, int id);
void i915_gem_detach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj);
void i915_gem_free_all_phys_object(struct drm_device *dev);
-int i915_gem_object_get_pages(struct drm_gem_object *obj);
+int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
void i915_gem_object_put_pages(struct drm_gem_object *obj);
void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv);
void i915_gem_object_flush_write_domain(struct drm_gem_object *obj);
@@ -883,7 +937,8 @@ void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj);
void i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj);
bool i915_tiling_ok(struct drm_device *dev, int stride, int size,
int tiling_mode);
-bool i915_obj_fenceable(struct drm_device *dev, struct drm_gem_object *obj);
+bool i915_gem_object_fence_offset_ok(struct drm_gem_object *obj,
+ int tiling_mode);
/* i915_gem_debug.c */
void i915_gem_dump_object(struct drm_gem_object *obj, int len,
@@ -1012,7 +1067,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define IS_845G(dev) ((dev)->pci_device == 0x2562)
#define IS_I85X(dev) ((dev)->pci_device == 0x3582)
#define IS_I865G(dev) ((dev)->pci_device == 0x2572)
-#define IS_I8XX(dev) (INTEL_INFO(dev)->is_i8xx)
+#define IS_GEN2(dev) (INTEL_INFO(dev)->is_i8xx)
#define IS_I915G(dev) (INTEL_INFO(dev)->is_i915g)
#define IS_I915GM(dev) ((dev)->pci_device == 0x2592)
#define IS_I945G(dev) ((dev)->pci_device == 0x2772)
@@ -1031,8 +1086,29 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define IS_I9XX(dev) (INTEL_INFO(dev)->is_i9xx)
#define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile)
+#define IS_GEN3(dev) (IS_I915G(dev) || \
+ IS_I915GM(dev) || \
+ IS_I945G(dev) || \
+ IS_I945GM(dev) || \
+ IS_G33(dev) || \
+ IS_PINEVIEW(dev))
+#define IS_GEN4(dev) ((dev)->pci_device == 0x2972 || \
+ (dev)->pci_device == 0x2982 || \
+ (dev)->pci_device == 0x2992 || \
+ (dev)->pci_device == 0x29A2 || \
+ (dev)->pci_device == 0x2A02 || \
+ (dev)->pci_device == 0x2A12 || \
+ (dev)->pci_device == 0x2E02 || \
+ (dev)->pci_device == 0x2E12 || \
+ (dev)->pci_device == 0x2E22 || \
+ (dev)->pci_device == 0x2E32 || \
+ (dev)->pci_device == 0x2A42 || \
+ (dev)->pci_device == 0x2E42)
+
#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
+#define IS_GEN6(dev) ((dev)->pci_device == 0x0102)
+
/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
* rows, which changed the alignment requirements and fence programming.
*/
@@ -1053,6 +1129,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
#define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6)
+#define HAS_PCH_SPLIT(dev) (IS_IRONLAKE(dev) || \
+ IS_GEN6(dev))
+
#define PRIMARY_RINGBUFFER_SIZE (128*1024)
#endif
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 2748609f05b3..fba37e9f775d 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -128,9 +128,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
return -ENOMEM;
ret = drm_gem_handle_create(file_priv, obj, &handle);
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_handle_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_handle_unreference_unlocked(obj);
if (ret)
return ret;
@@ -277,7 +275,7 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj,
mutex_lock(&dev->struct_mutex);
- ret = i915_gem_object_get_pages(obj);
+ ret = i915_gem_object_get_pages(obj, 0);
if (ret != 0)
goto fail_unlock;
@@ -321,40 +319,24 @@ fail_unlock:
return ret;
}
-static inline gfp_t
-i915_gem_object_get_page_gfp_mask (struct drm_gem_object *obj)
-{
- return mapping_gfp_mask(obj->filp->f_path.dentry->d_inode->i_mapping);
-}
-
-static inline void
-i915_gem_object_set_page_gfp_mask (struct drm_gem_object *obj, gfp_t gfp)
-{
- mapping_set_gfp_mask(obj->filp->f_path.dentry->d_inode->i_mapping, gfp);
-}
-
static int
i915_gem_object_get_pages_or_evict(struct drm_gem_object *obj)
{
int ret;
- ret = i915_gem_object_get_pages(obj);
+ ret = i915_gem_object_get_pages(obj, __GFP_NORETRY | __GFP_NOWARN);
/* If we've insufficient memory to map in the pages, attempt
* to make some space by throwing out some old buffers.
*/
if (ret == -ENOMEM) {
struct drm_device *dev = obj->dev;
- gfp_t gfp;
ret = i915_gem_evict_something(dev, obj->size);
if (ret)
return ret;
- gfp = i915_gem_object_get_page_gfp_mask(obj);
- i915_gem_object_set_page_gfp_mask(obj, gfp & ~__GFP_NORETRY);
- ret = i915_gem_object_get_pages(obj);
- i915_gem_object_set_page_gfp_mask (obj, gfp);
+ ret = i915_gem_object_get_pages(obj, 0);
}
return ret;
@@ -504,7 +486,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
*/
if (args->offset > obj->size || args->size > obj->size ||
args->offset + args->size > obj->size) {
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference_unlocked(obj);
return -EINVAL;
}
@@ -517,7 +499,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
file_priv);
}
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference_unlocked(obj);
return ret;
}
@@ -790,7 +772,7 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
mutex_lock(&dev->struct_mutex);
- ret = i915_gem_object_get_pages(obj);
+ ret = i915_gem_object_get_pages(obj, 0);
if (ret != 0)
goto fail_unlock;
@@ -977,7 +959,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
*/
if (args->offset > obj->size || args->size > obj->size ||
args->offset + args->size > obj->size) {
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference_unlocked(obj);
return -EINVAL;
}
@@ -1011,7 +993,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
DRM_INFO("pwrite failed %d\n", ret);
#endif
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference_unlocked(obj);
return ret;
}
@@ -1154,9 +1136,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
PROT_READ | PROT_WRITE, MAP_SHARED,
args->offset);
up_write(&current->mm->mmap_sem);
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(obj);
if (IS_ERR((void *)addr))
return addr;
@@ -1568,6 +1548,8 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
else
list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+ BUG_ON(!list_empty(&obj_priv->gpu_write_list));
+
obj_priv->last_rendering_seqno = 0;
if (obj_priv->active) {
obj_priv->active = 0;
@@ -1576,6 +1558,38 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
i915_verify_inactive(dev, __FILE__, __LINE__);
}
+static void
+i915_gem_process_flushing_list(struct drm_device *dev,
+ uint32_t flush_domains, uint32_t seqno)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv, *next;
+
+ list_for_each_entry_safe(obj_priv, next,
+ &dev_priv->mm.gpu_write_list,
+ gpu_write_list) {
+ struct drm_gem_object *obj = obj_priv->obj;
+
+ if ((obj->write_domain & flush_domains) ==
+ obj->write_domain) {
+ uint32_t old_write_domain = obj->write_domain;
+
+ obj->write_domain = 0;
+ list_del_init(&obj_priv->gpu_write_list);
+ i915_gem_object_move_to_active(obj, seqno);
+
+ /* update the fence lru list */
+ if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
+ list_move_tail(&obj_priv->fence_list,
+ &dev_priv->mm.fence_list);
+
+ trace_i915_gem_object_change_domain(obj,
+ obj->read_domains,
+ old_write_domain);
+ }
+ }
+}
+
/**
* Creates a new sequence number, emitting a write of it to the status page
* plus an interrupt, which will trigger i915_user_interrupt_handler.
@@ -1634,27 +1648,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
/* Associate any objects on the flushing list matching the write
* domain we're flushing with our flush.
*/
- if (flush_domains != 0) {
- struct drm_i915_gem_object *obj_priv, *next;
-
- list_for_each_entry_safe(obj_priv, next,
- &dev_priv->mm.flushing_list, list) {
- struct drm_gem_object *obj = obj_priv->obj;
-
- if ((obj->write_domain & flush_domains) ==
- obj->write_domain) {
- uint32_t old_write_domain = obj->write_domain;
-
- obj->write_domain = 0;
- i915_gem_object_move_to_active(obj, seqno);
-
- trace_i915_gem_object_change_domain(obj,
- obj->read_domains,
- old_write_domain);
- }
- }
-
- }
+ if (flush_domains != 0)
+ i915_gem_process_flushing_list(dev, flush_domains, seqno);
if (!dev_priv->mm.suspended) {
mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
@@ -1834,7 +1829,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible)
return -EIO;
if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) {
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
ier = I915_READ(DEIER) | I915_READ(GTIER);
else
ier = I915_READ(IER);
@@ -2003,6 +1998,7 @@ int
i915_gem_object_unbind(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
int ret = 0;
@@ -2058,8 +2054,10 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
}
/* Remove ourselves from the LRU list if present. */
+ spin_lock(&dev_priv->mm.active_list_lock);
if (!list_empty(&obj_priv->list))
list_del_init(&obj_priv->list);
+ spin_unlock(&dev_priv->mm.active_list_lock);
if (i915_gem_object_is_purgeable(obj_priv))
i915_gem_object_truncate(obj);
@@ -2097,10 +2095,33 @@ i915_gem_find_inactive_object(struct drm_device *dev, int min_size)
}
static int
-i915_gem_evict_everything(struct drm_device *dev)
+i915_gpu_idle(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ bool lists_empty;
uint32_t seqno;
+
+ spin_lock(&dev_priv->mm.active_list_lock);
+ lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
+ list_empty(&dev_priv->mm.active_list);
+ spin_unlock(&dev_priv->mm.active_list_lock);
+
+ if (lists_empty)
+ return 0;
+
+ /* Flush everything onto the inactive list. */
+ i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+ seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS);
+ if (seqno == 0)
+ return -ENOMEM;
+
+ return i915_wait_request(dev, seqno);
+}
+
+static int
+i915_gem_evict_everything(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
bool lists_empty;
@@ -2114,15 +2135,12 @@ i915_gem_evict_everything(struct drm_device *dev)
return -ENOSPC;
/* Flush everything (on to the inactive lists) and evict */
- i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
- seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS);
- if (seqno == 0)
- return -ENOMEM;
-
- ret = i915_wait_request(dev, seqno);
+ ret = i915_gpu_idle(dev);
if (ret)
return ret;
+ BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
+
ret = i915_gem_evict_from_inactive_list(dev);
if (ret)
return ret;
@@ -2230,7 +2248,8 @@ i915_gem_evict_something(struct drm_device *dev, int min_size)
}
int
-i915_gem_object_get_pages(struct drm_gem_object *obj)
+i915_gem_object_get_pages(struct drm_gem_object *obj,
+ gfp_t gfpmask)
{
struct drm_i915_gem_object *obj_priv = obj->driver_private;
int page_count, i;
@@ -2256,7 +2275,10 @@ i915_gem_object_get_pages(struct drm_gem_object *obj)
inode = obj->filp->f_path.dentry->d_inode;
mapping = inode->i_mapping;
for (i = 0; i < page_count; i++) {
- page = read_mapping_page(mapping, i, NULL);
+ page = read_cache_page_gfp(mapping, i,
+ mapping_gfp_mask (mapping) |
+ __GFP_COLD |
+ gfpmask);
if (IS_ERR(page)) {
ret = PTR_ERR(page);
i915_gem_object_put_pages(obj);
@@ -2271,6 +2293,28 @@ i915_gem_object_get_pages(struct drm_gem_object *obj)
return 0;
}
+static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg)
+{
+ struct drm_gem_object *obj = reg->obj;
+ struct drm_device *dev = obj->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ int regnum = obj_priv->fence_reg;
+ uint64_t val;
+
+ val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) &
+ 0xfffff000) << 32;
+ val |= obj_priv->gtt_offset & 0xfffff000;
+ val |= (uint64_t)((obj_priv->stride / 128) - 1) <<
+ SANDYBRIDGE_FENCE_PITCH_SHIFT;
+
+ if (obj_priv->tiling_mode == I915_TILING_Y)
+ val |= 1 << I965_FENCE_TILING_Y_SHIFT;
+ val |= I965_FENCE_REG_VALID;
+
+ I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (regnum * 8), val);
+}
+
static void i965_write_fence_reg(struct drm_i915_fence_reg *reg)
{
struct drm_gem_object *obj = reg->obj;
@@ -2367,6 +2411,58 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val);
}
+static int i915_find_fence_reg(struct drm_device *dev)
+{
+ struct drm_i915_fence_reg *reg = NULL;
+ struct drm_i915_gem_object *obj_priv = NULL;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_gem_object *obj = NULL;
+ int i, avail, ret;
+
+ /* First try to find a free reg */
+ avail = 0;
+ for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
+ reg = &dev_priv->fence_regs[i];
+ if (!reg->obj)
+ return i;
+
+ obj_priv = reg->obj->driver_private;
+ if (!obj_priv->pin_count)
+ avail++;
+ }
+
+ if (avail == 0)
+ return -ENOSPC;
+
+ /* None available, try to steal one or wait for a user to finish */
+ i = I915_FENCE_REG_NONE;
+ list_for_each_entry(obj_priv, &dev_priv->mm.fence_list,
+ fence_list) {
+ obj = obj_priv->obj;
+
+ if (obj_priv->pin_count)
+ continue;
+
+ /* found one! */
+ i = obj_priv->fence_reg;
+ break;
+ }
+
+ BUG_ON(i == I915_FENCE_REG_NONE);
+
+ /* We only have a reference on obj from the active list. put_fence_reg
+ * might drop that one, causing a use-after-free in it. So hold a
+ * private reference to obj like the other callers of put_fence_reg
+ * (set_tiling ioctl) do. */
+ drm_gem_object_reference(obj);
+ ret = i915_gem_object_put_fence_reg(obj);
+ drm_gem_object_unreference(obj);
+ if (ret != 0)
+ return ret;
+
+ return i;
+}
+
/**
* i915_gem_object_get_fence_reg - set up a fence reg for an object
* @obj: object to map through a fence reg
@@ -2387,8 +2483,7 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
struct drm_i915_fence_reg *reg = NULL;
- struct drm_i915_gem_object *old_obj_priv = NULL;
- int i, ret, avail;
+ int ret;
/* Just update our place in the LRU if our fence is getting used. */
if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
@@ -2416,86 +2511,27 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
break;
}
- /* First try to find a free reg */
- avail = 0;
- for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
- reg = &dev_priv->fence_regs[i];
- if (!reg->obj)
- break;
-
- old_obj_priv = reg->obj->driver_private;
- if (!old_obj_priv->pin_count)
- avail++;
- }
-
- /* None available, try to steal one or wait for a user to finish */
- if (i == dev_priv->num_fence_regs) {
- struct drm_gem_object *old_obj = NULL;
-
- if (avail == 0)
- return -ENOSPC;
-
- list_for_each_entry(old_obj_priv, &dev_priv->mm.fence_list,
- fence_list) {
- old_obj = old_obj_priv->obj;
-
- if (old_obj_priv->pin_count)
- continue;
-
- /* Take a reference, as otherwise the wait_rendering
- * below may cause the object to get freed out from
- * under us.
- */
- drm_gem_object_reference(old_obj);
-
- /* i915 uses fences for GPU access to tiled buffers */
- if (IS_I965G(dev) || !old_obj_priv->active)
- break;
-
- /* This brings the object to the head of the LRU if it
- * had been written to. The only way this should
- * result in us waiting longer than the expected
- * optimal amount of time is if there was a
- * fence-using buffer later that was read-only.
- */
- i915_gem_object_flush_gpu_write_domain(old_obj);
- ret = i915_gem_object_wait_rendering(old_obj);
- if (ret != 0) {
- drm_gem_object_unreference(old_obj);
- return ret;
- }
-
- break;
- }
-
- /*
- * Zap this virtual mapping so we can set up a fence again
- * for this object next time we need it.
- */
- i915_gem_release_mmap(old_obj);
-
- i = old_obj_priv->fence_reg;
- reg = &dev_priv->fence_regs[i];
-
- old_obj_priv->fence_reg = I915_FENCE_REG_NONE;
- list_del_init(&old_obj_priv->fence_list);
-
- drm_gem_object_unreference(old_obj);
- }
+ ret = i915_find_fence_reg(dev);
+ if (ret < 0)
+ return ret;
- obj_priv->fence_reg = i;
+ obj_priv->fence_reg = ret;
+ reg = &dev_priv->fence_regs[obj_priv->fence_reg];
list_add_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list);
reg->obj = obj;
- if (IS_I965G(dev))
+ if (IS_GEN6(dev))
+ sandybridge_write_fence_reg(reg);
+ else if (IS_I965G(dev))
i965_write_fence_reg(reg);
else if (IS_I9XX(dev))
i915_write_fence_reg(reg);
else
i830_write_fence_reg(reg);
- trace_i915_gem_object_get_fence(obj, i, obj_priv->tiling_mode);
+ trace_i915_gem_object_get_fence(obj, obj_priv->fence_reg,
+ obj_priv->tiling_mode);
return 0;
}
@@ -2514,9 +2550,12 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
- if (IS_I965G(dev))
+ if (IS_GEN6(dev)) {
+ I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 +
+ (obj_priv->fence_reg * 8), 0);
+ } else if (IS_I965G(dev)) {
I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0);
- else {
+ } else {
uint32_t fence_reg;
if (obj_priv->fence_reg < 8)
@@ -2550,6 +2589,12 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
if (obj_priv->fence_reg == I915_FENCE_REG_NONE)
return 0;
+ /* If we've changed tiling, GTT-mappings of the object
+ * need to re-fault to ensure that the correct fence register
+ * setup is in place.
+ */
+ i915_gem_release_mmap(obj);
+
/* On the i915, GPU access to tiled buffers is via a fence,
* therefore we must wait for any outstanding access to complete
* before clearing the fence.
@@ -2558,12 +2603,12 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
int ret;
i915_gem_object_flush_gpu_write_domain(obj);
- i915_gem_object_flush_gtt_write_domain(obj);
ret = i915_gem_object_wait_rendering(obj);
if (ret != 0)
return ret;
}
+ i915_gem_object_flush_gtt_write_domain(obj);
i915_gem_clear_fence_reg (obj);
return 0;
@@ -2579,7 +2624,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
struct drm_mm_node *free_space;
- bool retry_alloc = false;
+ gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN;
int ret;
if (obj_priv->madv != I915_MADV_WILLNEED) {
@@ -2623,15 +2668,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
DRM_INFO("Binding object of size %zd at 0x%08x\n",
obj->size, obj_priv->gtt_offset);
#endif
- if (retry_alloc) {
- i915_gem_object_set_page_gfp_mask (obj,
- i915_gem_object_get_page_gfp_mask (obj) & ~__GFP_NORETRY);
- }
- ret = i915_gem_object_get_pages(obj);
- if (retry_alloc) {
- i915_gem_object_set_page_gfp_mask (obj,
- i915_gem_object_get_page_gfp_mask (obj) | __GFP_NORETRY);
- }
+ ret = i915_gem_object_get_pages(obj, gfpmask);
if (ret) {
drm_mm_put_block(obj_priv->gtt_space);
obj_priv->gtt_space = NULL;
@@ -2641,9 +2678,9 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
ret = i915_gem_evict_something(dev, obj->size);
if (ret) {
/* now try to shrink everyone else */
- if (! retry_alloc) {
- retry_alloc = true;
- goto search_free;
+ if (gfpmask) {
+ gfpmask = 0;
+ goto search_free;
}
return ret;
@@ -2711,7 +2748,6 @@ static void
i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
- uint32_t seqno;
uint32_t old_write_domain;
if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
@@ -2720,9 +2756,8 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
/* Queue the GPU write cache flushing we need. */
old_write_domain = obj->write_domain;
i915_gem_flush(dev, 0, obj->write_domain);
- seqno = i915_add_request(dev, NULL, obj->write_domain);
- obj->write_domain = 0;
- i915_gem_object_move_to_active(obj, seqno);
+ (void) i915_add_request(dev, NULL, obj->write_domain);
+ BUG_ON(obj->write_domain);
trace_i915_gem_object_change_domain(obj,
obj->read_domains,
@@ -2837,6 +2872,57 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
return 0;
}
+/*
+ * Prepare buffer for display plane. Use uninterruptible for possible flush
+ * wait, as in modesetting process we're not supposed to be interrupted.
+ */
+int
+i915_gem_object_set_to_display_plane(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ uint32_t old_write_domain, old_read_domains;
+ int ret;
+
+ /* Not valid to be called on unbound objects. */
+ if (obj_priv->gtt_space == NULL)
+ return -EINVAL;
+
+ i915_gem_object_flush_gpu_write_domain(obj);
+
+ /* Wait on any GPU rendering and flushing to occur. */
+ if (obj_priv->active) {
+#if WATCH_BUF
+ DRM_INFO("%s: object %p wait for seqno %08x\n",
+ __func__, obj, obj_priv->last_rendering_seqno);
+#endif
+ ret = i915_do_wait_request(dev, obj_priv->last_rendering_seqno, 0);
+ if (ret != 0)
+ return ret;
+ }
+
+ old_write_domain = obj->write_domain;
+ old_read_domains = obj->read_domains;
+
+ obj->read_domains &= I915_GEM_DOMAIN_GTT;
+
+ i915_gem_object_flush_cpu_write_domain(obj);
+
+ /* It should now be out of any other write domains, and we can update
+ * the domain values for our changes.
+ */
+ BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
+ obj->read_domains |= I915_GEM_DOMAIN_GTT;
+ obj->write_domain = I915_GEM_DOMAIN_GTT;
+ obj_priv->dirty = 1;
+
+ trace_i915_gem_object_change_domain(obj,
+ old_read_domains,
+ old_write_domain);
+
+ return 0;
+}
+
/**
* Moves a single object to the CPU read, and possibly write domain.
*
@@ -3210,7 +3296,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
obj_priv->tiling_mode != I915_TILING_NONE;
/* Check fence reg constraints and rebind if necessary */
- if (need_fence && !i915_obj_fenceable(dev, obj))
+ if (need_fence && !i915_gem_object_fence_offset_ok(obj,
+ obj_priv->tiling_mode))
i915_gem_object_unbind(obj);
/* Choose the GTT offset for our buffer and put it there. */
@@ -3280,6 +3367,16 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
}
/* Validate that the target is in a valid r/w GPU domain */
+ if (reloc->write_domain & (reloc->write_domain - 1)) {
+ DRM_ERROR("reloc with multiple write domains: "
+ "obj %p target %d offset %d "
+ "read %08x write %08x",
+ obj, reloc->target_handle,
+ (int) reloc->offset,
+ reloc->read_domains,
+ reloc->write_domain);
+ return -EINVAL;
+ }
if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
reloc->read_domains & I915_GEM_DOMAIN_CPU) {
DRM_ERROR("reloc with read/write CPU domains: "
@@ -3533,6 +3630,9 @@ i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object2 *exec_list,
uint32_t reloc_count = 0, i;
int ret = 0;
+ if (relocs == NULL)
+ return 0;
+
for (i = 0; i < buffer_count; i++) {
struct drm_i915_gem_relocation_entry __user *user_relocs;
int unwritten;
@@ -3622,7 +3722,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
struct drm_gem_object *batch_obj;
struct drm_i915_gem_object *obj_priv;
struct drm_clip_rect *cliprects = NULL;
- struct drm_i915_gem_relocation_entry *relocs;
+ struct drm_i915_gem_relocation_entry *relocs = NULL;
int ret = 0, ret2, i, pinned = 0;
uint64_t exec_offset;
uint32_t seqno, flush_domains, reloc_index;
@@ -3648,8 +3748,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
if (args->num_cliprects != 0) {
cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects),
GFP_KERNEL);
- if (cliprects == NULL)
+ if (cliprects == NULL) {
+ ret = -ENOMEM;
goto pre_mutex_err;
+ }
ret = copy_from_user(cliprects,
(struct drm_clip_rect __user *)
@@ -3691,6 +3793,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
if (object_list[i] == NULL) {
DRM_ERROR("Invalid object handle %d at index %d\n",
exec_list[i].handle, i);
+ /* prevent error path from reading uninitialized data */
+ args->buffer_count = i + 1;
ret = -EBADF;
goto err;
}
@@ -3699,6 +3803,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
if (obj_priv->in_execbuffer) {
DRM_ERROR("Object %p appears more than once in object list\n",
object_list[i]);
+ /* prevent error path from reading uninitialized data */
+ args->buffer_count = i + 1;
ret = -EBADF;
goto err;
}
@@ -3812,16 +3918,23 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
i915_gem_flush(dev,
dev->invalidate_domains,
dev->flush_domains);
- if (dev->flush_domains)
+ if (dev->flush_domains & I915_GEM_GPU_DOMAINS)
(void)i915_add_request(dev, file_priv,
dev->flush_domains);
}
for (i = 0; i < args->buffer_count; i++) {
struct drm_gem_object *obj = object_list[i];
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
uint32_t old_write_domain = obj->write_domain;
obj->write_domain = obj->pending_write_domain;
+ if (obj->write_domain)
+ list_move_tail(&obj_priv->gpu_write_list,
+ &dev_priv->mm.gpu_write_list);
+ else
+ list_del_init(&obj_priv->gpu_write_list);
+
trace_i915_gem_object_change_domain(obj,
obj->read_domains,
old_write_domain);
@@ -3895,6 +4008,7 @@ err:
mutex_unlock(&dev->struct_mutex);
+pre_mutex_err:
/* Copy the updated relocations out regardless of current error
* state. Failure to update the relocs would mean that the next
* time userland calls execbuf, it would do so with presumed offset
@@ -3909,7 +4023,6 @@ err:
ret = ret2;
}
-pre_mutex_err:
drm_free_large(object_list);
kfree(cliprects);
@@ -4000,8 +4113,6 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
"back to user (%d)\n",
args->buffer_count, ret);
}
- } else {
- DRM_ERROR("i915_gem_do_execbuffer returns %d\n", ret);
}
drm_free_large(exec_list);
@@ -4334,6 +4445,7 @@ int i915_gem_init_object(struct drm_gem_object *obj)
obj_priv->obj = obj;
obj_priv->fence_reg = I915_FENCE_REG_NONE;
INIT_LIST_HEAD(&obj_priv->list);
+ INIT_LIST_HEAD(&obj_priv->gpu_write_list);
INIT_LIST_HEAD(&obj_priv->fence_list);
obj_priv->madv = I915_MADV_WILLNEED;
@@ -4393,8 +4505,7 @@ int
i915_gem_idle(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t seqno, cur_seqno, last_seqno;
- int stuck, ret;
+ int ret;
mutex_lock(&dev->struct_mutex);
@@ -4403,115 +4514,36 @@ i915_gem_idle(struct drm_device *dev)
return 0;
}
- /* Hack! Don't let anybody do execbuf while we don't control the chip.
- * We need to replace this with a semaphore, or something.
- */
- dev_priv->mm.suspended = 1;
- del_timer(&dev_priv->hangcheck_timer);
-
- /* Cancel the retire work handler, wait for it to finish if running
- */
- mutex_unlock(&dev->struct_mutex);
- cancel_delayed_work_sync(&dev_priv->mm.retire_work);
- mutex_lock(&dev->struct_mutex);
-
- i915_kernel_lost_context(dev);
-
- /* Flush the GPU along with all non-CPU write domains
- */
- i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
- seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS);
-
- if (seqno == 0) {
+ ret = i915_gpu_idle(dev);
+ if (ret) {
mutex_unlock(&dev->struct_mutex);
- return -ENOMEM;
+ return ret;
}
- dev_priv->mm.waiting_gem_seqno = seqno;
- last_seqno = 0;
- stuck = 0;
- for (;;) {
- cur_seqno = i915_get_gem_seqno(dev);
- if (i915_seqno_passed(cur_seqno, seqno))
- break;
- if (last_seqno == cur_seqno) {
- if (stuck++ > 100) {
- DRM_ERROR("hardware wedged\n");
- atomic_set(&dev_priv->mm.wedged, 1);
- DRM_WAKEUP(&dev_priv->irq_queue);
- break;
- }
+ /* Under UMS, be paranoid and evict. */
+ if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
+ ret = i915_gem_evict_from_inactive_list(dev);
+ if (ret) {
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
}
- msleep(10);
- last_seqno = cur_seqno;
}
- dev_priv->mm.waiting_gem_seqno = 0;
- i915_gem_retire_requests(dev);
-
- spin_lock(&dev_priv->mm.active_list_lock);
- if (!atomic_read(&dev_priv->mm.wedged)) {
- /* Active and flushing should now be empty as we've
- * waited for a sequence higher than any pending execbuffer
- */
- WARN_ON(!list_empty(&dev_priv->mm.active_list));
- WARN_ON(!list_empty(&dev_priv->mm.flushing_list));
- /* Request should now be empty as we've also waited
- * for the last request in the list
- */
- WARN_ON(!list_empty(&dev_priv->mm.request_list));
- }
-
- /* Empty the active and flushing lists to inactive. If there's
- * anything left at this point, it means that we're wedged and
- * nothing good's going to happen by leaving them there. So strip
- * the GPU domains and just stuff them onto inactive.
+ /* Hack! Don't let anybody do execbuf while we don't control the chip.
+ * We need to replace this with a semaphore, or something.
+ * And not confound mm.suspended!
*/
- while (!list_empty(&dev_priv->mm.active_list)) {
- struct drm_gem_object *obj;
- uint32_t old_write_domain;
-
- obj = list_first_entry(&dev_priv->mm.active_list,
- struct drm_i915_gem_object,
- list)->obj;
- old_write_domain = obj->write_domain;
- obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
- i915_gem_object_move_to_inactive(obj);
-
- trace_i915_gem_object_change_domain(obj,
- obj->read_domains,
- old_write_domain);
- }
- spin_unlock(&dev_priv->mm.active_list_lock);
-
- while (!list_empty(&dev_priv->mm.flushing_list)) {
- struct drm_gem_object *obj;
- uint32_t old_write_domain;
-
- obj = list_first_entry(&dev_priv->mm.flushing_list,
- struct drm_i915_gem_object,
- list)->obj;
- old_write_domain = obj->write_domain;
- obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
- i915_gem_object_move_to_inactive(obj);
-
- trace_i915_gem_object_change_domain(obj,
- obj->read_domains,
- old_write_domain);
- }
-
-
- /* Move all inactive buffers out of the GTT. */
- ret = i915_gem_evict_from_inactive_list(dev);
- WARN_ON(!list_empty(&dev_priv->mm.inactive_list));
- if (ret) {
- mutex_unlock(&dev->struct_mutex);
- return ret;
- }
+ dev_priv->mm.suspended = 1;
+ del_timer(&dev_priv->hangcheck_timer);
+ i915_kernel_lost_context(dev);
i915_gem_cleanup_ringbuffer(dev);
+
mutex_unlock(&dev->struct_mutex);
+ /* Cancel the retire work handler, which should be idle now. */
+ cancel_delayed_work_sync(&dev_priv->mm.retire_work);
+
return 0;
}
@@ -4555,8 +4587,13 @@ i915_gem_init_hws(struct drm_device *dev)
}
dev_priv->hws_obj = obj;
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
- I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
- I915_READ(HWS_PGA); /* posting read */
+ if (IS_GEN6(dev)) {
+ I915_WRITE(HWS_PGA_GEN6, dev_priv->status_gfx_addr);
+ I915_READ(HWS_PGA_GEN6); /* posting read */
+ } else {
+ I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
+ I915_READ(HWS_PGA); /* posting read */
+ }
DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr);
return 0;
@@ -4785,6 +4822,7 @@ i915_gem_load(struct drm_device *dev)
spin_lock_init(&dev_priv->mm.active_list_lock);
INIT_LIST_HEAD(&dev_priv->mm.active_list);
INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
+ INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
INIT_LIST_HEAD(&dev_priv->mm.request_list);
INIT_LIST_HEAD(&dev_priv->mm.fence_list);
@@ -4797,7 +4835,8 @@ i915_gem_load(struct drm_device *dev)
spin_unlock(&shrink_list_lock);
/* Old X drivers will take 0-2 for front, back, depth buffers */
- dev_priv->fence_reg_start = 3;
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ dev_priv->fence_reg_start = 3;
if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
dev_priv->num_fence_regs = 16;
@@ -4897,7 +4936,7 @@ void i915_gem_detach_phys_object(struct drm_device *dev,
if (!obj_priv->phys_obj)
return;
- ret = i915_gem_object_get_pages(obj);
+ ret = i915_gem_object_get_pages(obj, 0);
if (ret)
goto out;
@@ -4955,7 +4994,7 @@ i915_gem_attach_phys_object(struct drm_device *dev,
obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1];
obj_priv->phys_obj->cur_obj = obj;
- ret = i915_gem_object_get_pages(obj);
+ ret = i915_gem_object_get_pages(obj, 0);
if (ret) {
DRM_ERROR("failed to get page list\n");
goto out;
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index df278b2685bf..b5c55d88ff76 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -25,8 +25,6 @@
*
*/
-#include <linux/acpi.h>
-#include <linux/pnp.h>
#include "linux/string.h"
#include "linux/bitops.h"
#include "drmP.h"
@@ -83,120 +81,6 @@
* to match what the GPU expects.
*/
-#define MCHBAR_I915 0x44
-#define MCHBAR_I965 0x48
-#define MCHBAR_SIZE (4*4096)
-
-#define DEVEN_REG 0x54
-#define DEVEN_MCHBAR_EN (1 << 28)
-
-/* Allocate space for the MCH regs if needed, return nonzero on error */
-static int
-intel_alloc_mchbar_resource(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
- u32 temp_lo, temp_hi = 0;
- u64 mchbar_addr;
- int ret = 0;
-
- if (IS_I965G(dev))
- pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
- pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
- mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
-
- /* If ACPI doesn't have it, assume we need to allocate it ourselves */
-#ifdef CONFIG_PNP
- if (mchbar_addr &&
- pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
- ret = 0;
- goto out;
- }
-#endif
-
- /* Get some space for it */
- ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus, &dev_priv->mch_res,
- MCHBAR_SIZE, MCHBAR_SIZE,
- PCIBIOS_MIN_MEM,
- 0, pcibios_align_resource,
- dev_priv->bridge_dev);
- if (ret) {
- DRM_DEBUG_DRIVER("failed bus alloc: %d\n", ret);
- dev_priv->mch_res.start = 0;
- goto out;
- }
-
- if (IS_I965G(dev))
- pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
- upper_32_bits(dev_priv->mch_res.start));
-
- pci_write_config_dword(dev_priv->bridge_dev, reg,
- lower_32_bits(dev_priv->mch_res.start));
-out:
- return ret;
-}
-
-/* Setup MCHBAR if possible, return true if we should disable it again */
-static bool
-intel_setup_mchbar(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
- u32 temp;
- bool need_disable = false, enabled;
-
- if (IS_I915G(dev) || IS_I915GM(dev)) {
- pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
- enabled = !!(temp & DEVEN_MCHBAR_EN);
- } else {
- pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
- enabled = temp & 1;
- }
-
- /* If it's already enabled, don't have to do anything */
- if (enabled)
- goto out;
-
- if (intel_alloc_mchbar_resource(dev))
- goto out;
-
- need_disable = true;
-
- /* Space is allocated or reserved, so enable it. */
- if (IS_I915G(dev) || IS_I915GM(dev)) {
- pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG,
- temp | DEVEN_MCHBAR_EN);
- } else {
- pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
- pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp | 1);
- }
-out:
- return need_disable;
-}
-
-static void
-intel_teardown_mchbar(struct drm_device *dev, bool disable)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
- u32 temp;
-
- if (disable) {
- if (IS_I915G(dev) || IS_I915GM(dev)) {
- pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
- temp &= ~DEVEN_MCHBAR_EN;
- pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG, temp);
- } else {
- pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
- temp &= ~1;
- pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp);
- }
- }
-
- if (dev_priv->mch_res.start)
- release_resource(&dev_priv->mch_res);
-}
-
/**
* Detects bit 6 swizzling of address lookup between IGD access and CPU
* access through main memory.
@@ -207,9 +91,8 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
- bool need_disable;
- if (IS_IRONLAKE(dev)) {
+ if (IS_IRONLAKE(dev) || IS_GEN6(dev)) {
/* On Ironlake whatever DRAM config, GPU always do
* same swizzling setup.
*/
@@ -224,9 +107,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
} else if (IS_MOBILE(dev)) {
uint32_t dcc;
- /* Try to make sure MCHBAR is enabled before poking at it */
- need_disable = intel_setup_mchbar(dev);
-
/* On mobile 9xx chipsets, channel interleave by the CPU is
* determined by DCC. For single-channel, neither the CPU
* nor the GPU do swizzling. For dual channel interleaved,
@@ -266,8 +146,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
}
-
- intel_teardown_mchbar(dev, need_disable);
} else {
/* The 965, G33, and newer, have a very flexible memory
* configuration. It will enable dual-channel mode
@@ -302,39 +180,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
dev_priv->mm.bit_6_swizzle_y = swizzle_y;
}
-
-/**
- * Returns whether an object is currently fenceable. If not, it may need
- * to be unbound and have its pitch adjusted.
- */
-bool
-i915_obj_fenceable(struct drm_device *dev, struct drm_gem_object *obj)
-{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
-
- if (IS_I965G(dev)) {
- /* The 965 can have fences at any page boundary. */
- if (obj->size & 4095)
- return false;
- return true;
- } else if (IS_I9XX(dev)) {
- if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
- return false;
- } else {
- if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
- return false;
- }
-
- /* Power of two sized... */
- if (obj->size & (obj->size - 1))
- return false;
-
- /* Objects must be size aligned as well */
- if (obj_priv->gtt_offset & (obj->size - 1))
- return false;
- return true;
-}
-
/* Check pitch constriants for all chips & tiling formats */
bool
i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
@@ -391,7 +236,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
return true;
}
-static bool
+bool
i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode)
{
struct drm_device *dev = obj->dev;
@@ -438,9 +283,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
obj_priv = obj->driver_private;
if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) {
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(obj);
return -EINVAL;
}
@@ -493,12 +336,6 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
goto err;
}
- /* If we've changed tiling, GTT-mappings of the object
- * need to re-fault to ensure that the correct fence register
- * setup is in place.
- */
- i915_gem_release_mmap(obj);
-
obj_priv->tiling_mode = args->tiling_mode;
obj_priv->stride = args->stride;
}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 7cd8110051b6..5388354da0d1 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -166,7 +166,7 @@ void intel_enable_asle (struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
ironlake_enable_display_irq(dev_priv, DE_GSE);
else
i915_enable_pipestat(dev_priv, 1,
@@ -269,12 +269,62 @@ static void i915_hotplug_work_func(struct work_struct *work)
drm_sysfs_hotplug_event(dev);
}
+static void i915_handle_rps_change(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 busy_up, busy_down, max_avg, min_avg;
+ u16 rgvswctl;
+ u8 new_delay = dev_priv->cur_delay;
+
+ I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS) & ~MEMINT_EVAL_CHG);
+ busy_up = I915_READ(RCPREVBSYTUPAVG);
+ busy_down = I915_READ(RCPREVBSYTDNAVG);
+ max_avg = I915_READ(RCBMAXAVG);
+ min_avg = I915_READ(RCBMINAVG);
+
+ /* Handle RCS change request from hw */
+ if (busy_up > max_avg) {
+ if (dev_priv->cur_delay != dev_priv->max_delay)
+ new_delay = dev_priv->cur_delay - 1;
+ if (new_delay < dev_priv->max_delay)
+ new_delay = dev_priv->max_delay;
+ } else if (busy_down < min_avg) {
+ if (dev_priv->cur_delay != dev_priv->min_delay)
+ new_delay = dev_priv->cur_delay + 1;
+ if (new_delay > dev_priv->min_delay)
+ new_delay = dev_priv->min_delay;
+ }
+
+ DRM_DEBUG("rps change requested: %d -> %d\n",
+ dev_priv->cur_delay, new_delay);
+
+ rgvswctl = I915_READ(MEMSWCTL);
+ if (rgvswctl & MEMCTL_CMD_STS) {
+ DRM_ERROR("gpu busy, RCS change rejected\n");
+ return; /* still busy with another command */
+ }
+
+ /* Program the new state */
+ rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
+ (new_delay << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
+ I915_WRITE(MEMSWCTL, rgvswctl);
+ POSTING_READ(MEMSWCTL);
+
+ rgvswctl |= MEMCTL_CMD_STS;
+ I915_WRITE(MEMSWCTL, rgvswctl);
+
+ dev_priv->cur_delay = new_delay;
+
+ DRM_DEBUG("rps changed\n");
+
+ return;
+}
+
irqreturn_t ironlake_irq_handler(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = IRQ_NONE;
u32 de_iir, gt_iir, de_ier, pch_iir;
- u32 new_de_iir, new_gt_iir, new_pch_iir;
struct drm_i915_master_private *master_priv;
/* disable master interrupt before clearing iir */
@@ -286,51 +336,63 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
gt_iir = I915_READ(GTIIR);
pch_iir = I915_READ(SDEIIR);
- for (;;) {
- if (de_iir == 0 && gt_iir == 0 && pch_iir == 0)
- break;
+ if (de_iir == 0 && gt_iir == 0 && pch_iir == 0)
+ goto done;
- ret = IRQ_HANDLED;
+ ret = IRQ_HANDLED;
- /* should clear PCH hotplug event before clear CPU irq */
- I915_WRITE(SDEIIR, pch_iir);
- new_pch_iir = I915_READ(SDEIIR);
+ if (dev->primary->master) {
+ master_priv = dev->primary->master->driver_priv;
+ if (master_priv->sarea_priv)
+ master_priv->sarea_priv->last_dispatch =
+ READ_BREADCRUMB(dev_priv);
+ }
- I915_WRITE(DEIIR, de_iir);
- new_de_iir = I915_READ(DEIIR);
- I915_WRITE(GTIIR, gt_iir);
- new_gt_iir = I915_READ(GTIIR);
+ if (gt_iir & GT_USER_INTERRUPT) {
+ u32 seqno = i915_get_gem_seqno(dev);
+ dev_priv->mm.irq_gem_seqno = seqno;
+ trace_i915_gem_request_complete(dev, seqno);
+ DRM_WAKEUP(&dev_priv->irq_queue);
+ dev_priv->hangcheck_count = 0;
+ mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+ }
- if (dev->primary->master) {
- master_priv = dev->primary->master->driver_priv;
- if (master_priv->sarea_priv)
- master_priv->sarea_priv->last_dispatch =
- READ_BREADCRUMB(dev_priv);
- }
+ if (de_iir & DE_GSE)
+ ironlake_opregion_gse_intr(dev);
- if (gt_iir & GT_USER_INTERRUPT) {
- u32 seqno = i915_get_gem_seqno(dev);
- dev_priv->mm.irq_gem_seqno = seqno;
- trace_i915_gem_request_complete(dev, seqno);
- DRM_WAKEUP(&dev_priv->irq_queue);
- dev_priv->hangcheck_count = 0;
- mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
- }
+ if (de_iir & DE_PLANEA_FLIP_DONE) {
+ intel_prepare_page_flip(dev, 0);
+ intel_finish_page_flip(dev, 0);
+ }
- if (de_iir & DE_GSE)
- ironlake_opregion_gse_intr(dev);
+ if (de_iir & DE_PLANEB_FLIP_DONE) {
+ intel_prepare_page_flip(dev, 1);
+ intel_finish_page_flip(dev, 1);
+ }
- /* check event from PCH */
- if ((de_iir & DE_PCH_EVENT) &&
- (pch_iir & SDE_HOTPLUG_MASK)) {
- queue_work(dev_priv->wq, &dev_priv->hotplug_work);
- }
+ if (de_iir & DE_PIPEA_VBLANK)
+ drm_handle_vblank(dev, 0);
- de_iir = new_de_iir;
- gt_iir = new_gt_iir;
- pch_iir = new_pch_iir;
+ if (de_iir & DE_PIPEB_VBLANK)
+ drm_handle_vblank(dev, 1);
+
+ /* check event from PCH */
+ if ((de_iir & DE_PCH_EVENT) &&
+ (pch_iir & SDE_HOTPLUG_MASK)) {
+ queue_work(dev_priv->wq, &dev_priv->hotplug_work);
}
+ if (de_iir & DE_PCU_EVENT) {
+ I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS));
+ i915_handle_rps_change(dev);
+ }
+
+ /* should clear PCH hotplug event before clear CPU irq */
+ I915_WRITE(SDEIIR, pch_iir);
+ I915_WRITE(GTIIR, gt_iir);
+ I915_WRITE(DEIIR, de_iir);
+
+done:
I915_WRITE(DEIER, de_ier);
(void)I915_READ(DEIER);
@@ -370,6 +432,121 @@ static void i915_error_work_func(struct work_struct *work)
}
}
+static struct drm_i915_error_object *
+i915_error_object_create(struct drm_device *dev,
+ struct drm_gem_object *src)
+{
+ struct drm_i915_error_object *dst;
+ struct drm_i915_gem_object *src_priv;
+ int page, page_count;
+
+ if (src == NULL)
+ return NULL;
+
+ src_priv = src->driver_private;
+ if (src_priv->pages == NULL)
+ return NULL;
+
+ page_count = src->size / PAGE_SIZE;
+
+ dst = kmalloc(sizeof(*dst) + page_count * sizeof (u32 *), GFP_ATOMIC);
+ if (dst == NULL)
+ return NULL;
+
+ for (page = 0; page < page_count; page++) {
+ void *s, *d = kmalloc(PAGE_SIZE, GFP_ATOMIC);
+ if (d == NULL)
+ goto unwind;
+ s = kmap_atomic(src_priv->pages[page], KM_USER0);
+ memcpy(d, s, PAGE_SIZE);
+ kunmap_atomic(s, KM_USER0);
+ dst->pages[page] = d;
+ }
+ dst->page_count = page_count;
+ dst->gtt_offset = src_priv->gtt_offset;
+
+ return dst;
+
+unwind:
+ while (page--)
+ kfree(dst->pages[page]);
+ kfree(dst);
+ return NULL;
+}
+
+static void
+i915_error_object_free(struct drm_i915_error_object *obj)
+{
+ int page;
+
+ if (obj == NULL)
+ return;
+
+ for (page = 0; page < obj->page_count; page++)
+ kfree(obj->pages[page]);
+
+ kfree(obj);
+}
+
+static void
+i915_error_state_free(struct drm_device *dev,
+ struct drm_i915_error_state *error)
+{
+ i915_error_object_free(error->batchbuffer[0]);
+ i915_error_object_free(error->batchbuffer[1]);
+ i915_error_object_free(error->ringbuffer);
+ kfree(error->active_bo);
+ kfree(error);
+}
+
+static u32
+i915_get_bbaddr(struct drm_device *dev, u32 *ring)
+{
+ u32 cmd;
+
+ if (IS_I830(dev) || IS_845G(dev))
+ cmd = MI_BATCH_BUFFER;
+ else if (IS_I965G(dev))
+ cmd = (MI_BATCH_BUFFER_START | (2 << 6) |
+ MI_BATCH_NON_SECURE_I965);
+ else
+ cmd = (MI_BATCH_BUFFER_START | (2 << 6));
+
+ return ring[0] == cmd ? ring[1] : 0;
+}
+
+static u32
+i915_ringbuffer_last_batch(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 head, bbaddr;
+ u32 *ring;
+
+ /* Locate the current position in the ringbuffer and walk back
+ * to find the most recently dispatched batch buffer.
+ */
+ bbaddr = 0;
+ head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+ ring = (u32 *)(dev_priv->ring.virtual_start + head);
+
+ while (--ring >= (u32 *)dev_priv->ring.virtual_start) {
+ bbaddr = i915_get_bbaddr(dev, ring);
+ if (bbaddr)
+ break;
+ }
+
+ if (bbaddr == 0) {
+ ring = (u32 *)(dev_priv->ring.virtual_start + dev_priv->ring.Size);
+ while (--ring >= (u32 *)dev_priv->ring.virtual_start) {
+ bbaddr = i915_get_bbaddr(dev, ring);
+ if (bbaddr)
+ break;
+ }
+ }
+
+ return bbaddr;
+}
+
/**
* i915_capture_error_state - capture an error record for later analysis
* @dev: drm device
@@ -382,19 +559,26 @@ static void i915_error_work_func(struct work_struct *work)
static void i915_capture_error_state(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv;
struct drm_i915_error_state *error;
+ struct drm_gem_object *batchbuffer[2];
unsigned long flags;
+ u32 bbaddr;
+ int count;
spin_lock_irqsave(&dev_priv->error_lock, flags);
- if (dev_priv->first_error)
- goto out;
+ error = dev_priv->first_error;
+ spin_unlock_irqrestore(&dev_priv->error_lock, flags);
+ if (error)
+ return;
error = kmalloc(sizeof(*error), GFP_ATOMIC);
if (!error) {
- DRM_DEBUG_DRIVER("out ot memory, not capturing error state\n");
- goto out;
+ DRM_DEBUG_DRIVER("out of memory, not capturing error state\n");
+ return;
}
+ error->seqno = i915_get_gem_seqno(dev);
error->eir = I915_READ(EIR);
error->pgtbl_er = I915_READ(PGTBL_ER);
error->pipeastat = I915_READ(PIPEASTAT);
@@ -405,6 +589,7 @@ static void i915_capture_error_state(struct drm_device *dev)
error->ipehr = I915_READ(IPEHR);
error->instdone = I915_READ(INSTDONE);
error->acthd = I915_READ(ACTHD);
+ error->bbaddr = 0;
} else {
error->ipeir = I915_READ(IPEIR_I965);
error->ipehr = I915_READ(IPEHR_I965);
@@ -412,14 +597,101 @@ static void i915_capture_error_state(struct drm_device *dev)
error->instps = I915_READ(INSTPS);
error->instdone1 = I915_READ(INSTDONE1);
error->acthd = I915_READ(ACTHD_I965);
+ error->bbaddr = I915_READ64(BB_ADDR);
}
- do_gettimeofday(&error->time);
+ bbaddr = i915_ringbuffer_last_batch(dev);
- dev_priv->first_error = error;
+ /* Grab the current batchbuffer, most likely to have crashed. */
+ batchbuffer[0] = NULL;
+ batchbuffer[1] = NULL;
+ count = 0;
+ list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) {
+ struct drm_gem_object *obj = obj_priv->obj;
-out:
+ if (batchbuffer[0] == NULL &&
+ bbaddr >= obj_priv->gtt_offset &&
+ bbaddr < obj_priv->gtt_offset + obj->size)
+ batchbuffer[0] = obj;
+
+ if (batchbuffer[1] == NULL &&
+ error->acthd >= obj_priv->gtt_offset &&
+ error->acthd < obj_priv->gtt_offset + obj->size &&
+ batchbuffer[0] != obj)
+ batchbuffer[1] = obj;
+
+ count++;
+ }
+
+ /* We need to copy these to an anonymous buffer as the simplest
+ * method to avoid being overwritten by userpace.
+ */
+ error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]);
+ error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]);
+
+ /* Record the ringbuffer */
+ error->ringbuffer = i915_error_object_create(dev, dev_priv->ring.ring_obj);
+
+ /* Record buffers on the active list. */
+ error->active_bo = NULL;
+ error->active_bo_count = 0;
+
+ if (count)
+ error->active_bo = kmalloc(sizeof(*error->active_bo)*count,
+ GFP_ATOMIC);
+
+ if (error->active_bo) {
+ int i = 0;
+ list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) {
+ struct drm_gem_object *obj = obj_priv->obj;
+
+ error->active_bo[i].size = obj->size;
+ error->active_bo[i].name = obj->name;
+ error->active_bo[i].seqno = obj_priv->last_rendering_seqno;
+ error->active_bo[i].gtt_offset = obj_priv->gtt_offset;
+ error->active_bo[i].read_domains = obj->read_domains;
+ error->active_bo[i].write_domain = obj->write_domain;
+ error->active_bo[i].fence_reg = obj_priv->fence_reg;
+ error->active_bo[i].pinned = 0;
+ if (obj_priv->pin_count > 0)
+ error->active_bo[i].pinned = 1;
+ if (obj_priv->user_pin_count > 0)
+ error->active_bo[i].pinned = -1;
+ error->active_bo[i].tiling = obj_priv->tiling_mode;
+ error->active_bo[i].dirty = obj_priv->dirty;
+ error->active_bo[i].purgeable = obj_priv->madv != I915_MADV_WILLNEED;
+
+ if (++i == count)
+ break;
+ }
+ error->active_bo_count = i;
+ }
+
+ do_gettimeofday(&error->time);
+
+ spin_lock_irqsave(&dev_priv->error_lock, flags);
+ if (dev_priv->first_error == NULL) {
+ dev_priv->first_error = error;
+ error = NULL;
+ }
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
+
+ if (error)
+ i915_error_state_free(dev, error);
+}
+
+void i915_destroy_error_state(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_error_state *error;
+
+ spin_lock(&dev_priv->error_lock);
+ error = dev_priv->first_error;
+ dev_priv->first_error = NULL;
+ spin_unlock(&dev_priv->error_lock);
+
+ if (error)
+ i915_error_state_free(dev, error);
}
/**
@@ -570,7 +842,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
atomic_inc(&dev_priv->irq_received);
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
return ironlake_irq_handler(dev);
iir = I915_READ(IIR);
@@ -731,7 +1003,7 @@ void i915_user_irq_get(struct drm_device *dev)
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) {
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
ironlake_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
else
i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
@@ -747,7 +1019,7 @@ void i915_user_irq_put(struct drm_device *dev)
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
ironlake_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
else
i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
@@ -854,11 +1126,11 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
if (!(pipeconf & PIPEACONF_ENABLE))
return -EINVAL;
- if (IS_IRONLAKE(dev))
- return 0;
-
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
- if (IS_I965G(dev))
+ if (HAS_PCH_SPLIT(dev))
+ ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
+ DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
+ else if (IS_I965G(dev))
i915_enable_pipestat(dev_priv, pipe,
PIPE_START_VBLANK_INTERRUPT_ENABLE);
else
@@ -876,13 +1148,14 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
- if (IS_IRONLAKE(dev))
- return;
-
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
- i915_disable_pipestat(dev_priv, pipe,
- PIPE_VBLANK_INTERRUPT_ENABLE |
- PIPE_START_VBLANK_INTERRUPT_ENABLE);
+ if (HAS_PCH_SPLIT(dev))
+ ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
+ DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
+ else
+ i915_disable_pipestat(dev_priv, pipe,
+ PIPE_VBLANK_INTERRUPT_ENABLE |
+ PIPE_START_VBLANK_INTERRUPT_ENABLE);
spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
}
@@ -890,7 +1163,7 @@ void i915_enable_interrupt (struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (!IS_IRONLAKE(dev))
+ if (!HAS_PCH_SPLIT(dev))
opregion_enable_asle(dev);
dev_priv->irq_enabled = 1;
}
@@ -966,7 +1239,11 @@ void i915_hangcheck_elapsed(unsigned long data)
struct drm_device *dev = (struct drm_device *)data;
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t acthd;
-
+
+ /* No reset support on this chip yet. */
+ if (IS_GEN6(dev))
+ return;
+
if (!IS_I965G(dev))
acthd = I915_READ(ACTHD);
else
@@ -1025,13 +1302,14 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
/* enable kind of interrupts always enabled */
- u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT;
+ u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
+ DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
u32 render_mask = GT_USER_INTERRUPT;
u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
dev_priv->irq_mask_reg = ~display_mask;
- dev_priv->de_irq_enable_reg = display_mask;
+ dev_priv->de_irq_enable_reg = display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK;
/* should always can generate irq */
I915_WRITE(DEIIR, I915_READ(DEIIR));
@@ -1056,6 +1334,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
I915_WRITE(SDEIER, dev_priv->pch_irq_enable_reg);
(void) I915_READ(SDEIER);
+ if (IS_IRONLAKE_M(dev)) {
+ /* Clear & enable PCU event interrupts */
+ I915_WRITE(DEIIR, DE_PCU_EVENT);
+ I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
+ ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
+ }
+
return 0;
}
@@ -1068,7 +1353,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
INIT_WORK(&dev_priv->error_work, i915_error_work_func);
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
ironlake_irq_preinstall(dev);
return;
}
@@ -1100,7 +1385,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
return ironlake_irq_postinstall(dev);
/* Unmask the interrupts that we always want on. */
@@ -1188,7 +1473,7 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
dev_priv->vblank_pipe = 0;
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
ironlake_irq_uninstall(dev);
return;
}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 149d360d64a3..3d59862c7ccd 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -53,6 +53,25 @@
#define INTEL_GMCH_GMS_STOLEN_224M (0xc << 4)
#define INTEL_GMCH_GMS_STOLEN_352M (0xd << 4)
+#define SNB_GMCH_CTRL 0x50
+#define SNB_GMCH_GMS_STOLEN_MASK 0xF8
+#define SNB_GMCH_GMS_STOLEN_32M (1 << 3)
+#define SNB_GMCH_GMS_STOLEN_64M (2 << 3)
+#define SNB_GMCH_GMS_STOLEN_96M (3 << 3)
+#define SNB_GMCH_GMS_STOLEN_128M (4 << 3)
+#define SNB_GMCH_GMS_STOLEN_160M (5 << 3)
+#define SNB_GMCH_GMS_STOLEN_192M (6 << 3)
+#define SNB_GMCH_GMS_STOLEN_224M (7 << 3)
+#define SNB_GMCH_GMS_STOLEN_256M (8 << 3)
+#define SNB_GMCH_GMS_STOLEN_288M (9 << 3)
+#define SNB_GMCH_GMS_STOLEN_320M (0xa << 3)
+#define SNB_GMCH_GMS_STOLEN_352M (0xb << 3)
+#define SNB_GMCH_GMS_STOLEN_384M (0xc << 3)
+#define SNB_GMCH_GMS_STOLEN_416M (0xd << 3)
+#define SNB_GMCH_GMS_STOLEN_448M (0xe << 3)
+#define SNB_GMCH_GMS_STOLEN_480M (0xf << 3)
+#define SNB_GMCH_GMS_STOLEN_512M (0x10 << 3)
+
/* PCI config space */
#define HPLLCC 0xc0 /* 855 only */
@@ -61,6 +80,7 @@
#define GC_CLOCK_100_200 (1 << 0)
#define GC_CLOCK_100_133 (2 << 0)
#define GC_CLOCK_166_250 (3 << 0)
+#define GCFGC2 0xda
#define GCFGC 0xf0 /* 915+ only */
#define GC_LOW_FREQUENCY_ENABLE (1 << 7)
#define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4)
@@ -234,6 +254,9 @@
#define I965_FENCE_REG_VALID (1<<0)
#define I965_FENCE_MAX_PITCH_VAL 0x0400
+#define FENCE_REG_SANDYBRIDGE_0 0x100000
+#define SANDYBRIDGE_FENCE_PITCH_SHIFT 32
+
/*
* Instruction and interrupt control regs
*/
@@ -265,6 +288,7 @@
#define INSTDONE1 0x0207c /* 965+ only */
#define ACTHD_I965 0x02074
#define HWS_PGA 0x02080
+#define HWS_PGA_GEN6 0x04080
#define HWS_ADDRESS_MASK 0xfffff000
#define HWS_START_ADDRESS_SHIFT 4
#define PWRCTXA 0x2088 /* 965GM+ only */
@@ -282,7 +306,7 @@
#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
#define I915_DISPLAY_PORT_INTERRUPT (1<<17)
#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15)
-#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14)
+#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) /* p-state */
#define I915_HWB_OOM_INTERRUPT (1<<13)
#define I915_SYNC_STATUS_INTERRUPT (1<<12)
#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11)
@@ -306,11 +330,14 @@
#define I915_ERROR_MEMORY_REFRESH (1<<1)
#define I915_ERROR_INSTRUCTION (1<<0)
#define INSTPM 0x020c0
+#define INSTPM_SELF_EN (1<<12) /* 915GM only */
#define ACTHD 0x020c8
#define FW_BLC 0x020d8
#define FW_BLC2 0x020dc
#define FW_BLC_SELF 0x020e0 /* 915+ only */
-#define FW_BLC_SELF_EN (1<<15)
+#define FW_BLC_SELF_EN_MASK (1<<31)
+#define FW_BLC_SELF_FIFO_MASK (1<<16) /* 945 only */
+#define FW_BLC_SELF_EN (1<<15) /* 945 only */
#define MM_BURST_LENGTH 0x00700000
#define MM_FIFO_WATERMARK 0x0001F000
#define LM_BURST_LENGTH 0x00000700
@@ -324,6 +351,7 @@
#define CM0_COLOR_EVICT_DISABLE (1<<3)
#define CM0_DEPTH_WRITE_DISABLE (1<<1)
#define CM0_RC_OP_FLUSH_DISABLE (1<<0)
+#define BB_ADDR 0x02140 /* 8 bytes */
#define GFX_FLSH_CNTL 0x02170 /* 915+ only */
@@ -338,6 +366,7 @@
#define FBC_CTL_PERIODIC (1<<30)
#define FBC_CTL_INTERVAL_SHIFT (16)
#define FBC_CTL_UNCOMPRESSIBLE (1<<14)
+#define FBC_C3_IDLE (1<<13)
#define FBC_CTL_STRIDE_SHIFT (5)
#define FBC_CTL_FENCENO (1<<0)
#define FBC_COMMAND 0x0320c
@@ -783,10 +812,144 @@
#define CLKCFG_MEM_800 (3 << 4)
#define CLKCFG_MEM_MASK (7 << 4)
-/** GM965 GM45 render standby register */
-#define MCHBAR_RENDER_STANDBY 0x111B8
+#define CRSTANDVID 0x11100
+#define PXVFREQ_BASE 0x11110 /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */
+#define PXVFREQ_PX_MASK 0x7f000000
+#define PXVFREQ_PX_SHIFT 24
+#define VIDFREQ_BASE 0x11110
+#define VIDFREQ1 0x11110 /* VIDFREQ1-4 (0x1111c) (Cantiga) */
+#define VIDFREQ2 0x11114
+#define VIDFREQ3 0x11118
+#define VIDFREQ4 0x1111c
+#define VIDFREQ_P0_MASK 0x1f000000
+#define VIDFREQ_P0_SHIFT 24
+#define VIDFREQ_P0_CSCLK_MASK 0x00f00000
+#define VIDFREQ_P0_CSCLK_SHIFT 20
+#define VIDFREQ_P0_CRCLK_MASK 0x000f0000
+#define VIDFREQ_P0_CRCLK_SHIFT 16
+#define VIDFREQ_P1_MASK 0x00001f00
+#define VIDFREQ_P1_SHIFT 8
+#define VIDFREQ_P1_CSCLK_MASK 0x000000f0
+#define VIDFREQ_P1_CSCLK_SHIFT 4
+#define VIDFREQ_P1_CRCLK_MASK 0x0000000f
+#define INTTOEXT_BASE_ILK 0x11300
+#define INTTOEXT_BASE 0x11120 /* INTTOEXT1-8 (0x1113c) */
+#define INTTOEXT_MAP3_SHIFT 24
+#define INTTOEXT_MAP3_MASK (0x1f << INTTOEXT_MAP3_SHIFT)
+#define INTTOEXT_MAP2_SHIFT 16
+#define INTTOEXT_MAP2_MASK (0x1f << INTTOEXT_MAP2_SHIFT)
+#define INTTOEXT_MAP1_SHIFT 8
+#define INTTOEXT_MAP1_MASK (0x1f << INTTOEXT_MAP1_SHIFT)
+#define INTTOEXT_MAP0_SHIFT 0
+#define INTTOEXT_MAP0_MASK (0x1f << INTTOEXT_MAP0_SHIFT)
+#define MEMSWCTL 0x11170 /* Ironlake only */
+#define MEMCTL_CMD_MASK 0xe000
+#define MEMCTL_CMD_SHIFT 13
+#define MEMCTL_CMD_RCLK_OFF 0
+#define MEMCTL_CMD_RCLK_ON 1
+#define MEMCTL_CMD_CHFREQ 2
+#define MEMCTL_CMD_CHVID 3
+#define MEMCTL_CMD_VMMOFF 4
+#define MEMCTL_CMD_VMMON 5
+#define MEMCTL_CMD_STS (1<<12) /* write 1 triggers command, clears
+ when command complete */
+#define MEMCTL_FREQ_MASK 0x0f00 /* jitter, from 0-15 */
+#define MEMCTL_FREQ_SHIFT 8
+#define MEMCTL_SFCAVM (1<<7)
+#define MEMCTL_TGT_VID_MASK 0x007f
+#define MEMIHYST 0x1117c
+#define MEMINTREN 0x11180 /* 16 bits */
+#define MEMINT_RSEXIT_EN (1<<8)
+#define MEMINT_CX_SUPR_EN (1<<7)
+#define MEMINT_CONT_BUSY_EN (1<<6)
+#define MEMINT_AVG_BUSY_EN (1<<5)
+#define MEMINT_EVAL_CHG_EN (1<<4)
+#define MEMINT_MON_IDLE_EN (1<<3)
+#define MEMINT_UP_EVAL_EN (1<<2)
+#define MEMINT_DOWN_EVAL_EN (1<<1)
+#define MEMINT_SW_CMD_EN (1<<0)
+#define MEMINTRSTR 0x11182 /* 16 bits */
+#define MEM_RSEXIT_MASK 0xc000
+#define MEM_RSEXIT_SHIFT 14
+#define MEM_CONT_BUSY_MASK 0x3000
+#define MEM_CONT_BUSY_SHIFT 12
+#define MEM_AVG_BUSY_MASK 0x0c00
+#define MEM_AVG_BUSY_SHIFT 10
+#define MEM_EVAL_CHG_MASK 0x0300
+#define MEM_EVAL_BUSY_SHIFT 8
+#define MEM_MON_IDLE_MASK 0x00c0
+#define MEM_MON_IDLE_SHIFT 6
+#define MEM_UP_EVAL_MASK 0x0030
+#define MEM_UP_EVAL_SHIFT 4
+#define MEM_DOWN_EVAL_MASK 0x000c
+#define MEM_DOWN_EVAL_SHIFT 2
+#define MEM_SW_CMD_MASK 0x0003
+#define MEM_INT_STEER_GFX 0
+#define MEM_INT_STEER_CMR 1
+#define MEM_INT_STEER_SMI 2
+#define MEM_INT_STEER_SCI 3
+#define MEMINTRSTS 0x11184
+#define MEMINT_RSEXIT (1<<7)
+#define MEMINT_CONT_BUSY (1<<6)
+#define MEMINT_AVG_BUSY (1<<5)
+#define MEMINT_EVAL_CHG (1<<4)
+#define MEMINT_MON_IDLE (1<<3)
+#define MEMINT_UP_EVAL (1<<2)
+#define MEMINT_DOWN_EVAL (1<<1)
+#define MEMINT_SW_CMD (1<<0)
+#define MEMMODECTL 0x11190
+#define MEMMODE_BOOST_EN (1<<31)
+#define MEMMODE_BOOST_FREQ_MASK 0x0f000000 /* jitter for boost, 0-15 */
+#define MEMMODE_BOOST_FREQ_SHIFT 24
+#define MEMMODE_IDLE_MODE_MASK 0x00030000
+#define MEMMODE_IDLE_MODE_SHIFT 16
+#define MEMMODE_IDLE_MODE_EVAL 0
+#define MEMMODE_IDLE_MODE_CONT 1
+#define MEMMODE_HWIDLE_EN (1<<15)
+#define MEMMODE_SWMODE_EN (1<<14)
+#define MEMMODE_RCLK_GATE (1<<13)
+#define MEMMODE_HW_UPDATE (1<<12)
+#define MEMMODE_FSTART_MASK 0x00000f00 /* starting jitter, 0-15 */
+#define MEMMODE_FSTART_SHIFT 8
+#define MEMMODE_FMAX_MASK 0x000000f0 /* max jitter, 0-15 */
+#define MEMMODE_FMAX_SHIFT 4
+#define MEMMODE_FMIN_MASK 0x0000000f /* min jitter, 0-15 */
+#define RCBMAXAVG 0x1119c
+#define MEMSWCTL2 0x1119e /* Cantiga only */
+#define SWMEMCMD_RENDER_OFF (0 << 13)
+#define SWMEMCMD_RENDER_ON (1 << 13)
+#define SWMEMCMD_SWFREQ (2 << 13)
+#define SWMEMCMD_TARVID (3 << 13)
+#define SWMEMCMD_VRM_OFF (4 << 13)
+#define SWMEMCMD_VRM_ON (5 << 13)
+#define CMDSTS (1<<12)
+#define SFCAVM (1<<11)
+#define SWFREQ_MASK 0x0380 /* P0-7 */
+#define SWFREQ_SHIFT 7
+#define TARVID_MASK 0x001f
+#define MEMSTAT_CTG 0x111a0
+#define RCBMINAVG 0x111a0
+#define RCUPEI 0x111b0
+#define RCDNEI 0x111b4
+#define MCHBAR_RENDER_STANDBY 0x111b8
#define RCX_SW_EXIT (1<<23)
#define RSX_STATUS_MASK 0x00700000
+#define VIDCTL 0x111c0
+#define VIDSTS 0x111c8
+#define VIDSTART 0x111cc /* 8 bits */
+#define MEMSTAT_ILK 0x111f8
+#define MEMSTAT_VID_MASK 0x7f00
+#define MEMSTAT_VID_SHIFT 8
+#define MEMSTAT_PSTATE_MASK 0x00f8
+#define MEMSTAT_PSTATE_SHIFT 3
+#define MEMSTAT_MON_ACTV (1<<2)
+#define MEMSTAT_SRC_CTL_MASK 0x0003
+#define MEMSTAT_SRC_CTL_CORE 0
+#define MEMSTAT_SRC_CTL_TRB 1
+#define MEMSTAT_SRC_CTL_THM 2
+#define MEMSTAT_SRC_CTL_STDBY 3
+#define RCPREVBSYTUPAVG 0x113b8
+#define RCPREVBSYTDNAVG 0x113bc
#define PEG_BAND_GAP_DATA 0x14d68
/*
@@ -1815,7 +1978,7 @@
#define DSPFW_PLANEB_SHIFT 8
#define DSPFW2 0x70038
#define DSPFW_CURSORA_MASK 0x00003f00
-#define DSPFW_CURSORA_SHIFT 16
+#define DSPFW_CURSORA_SHIFT 8
#define DSPFW3 0x7003c
#define DSPFW_HPLL_SR_EN (1<<31)
#define DSPFW_CURSOR_SR_SHIFT 24
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index a3b90c9561dc..ac0d1a73ac22 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -682,6 +682,8 @@ void i915_restore_display(struct drm_device *dev)
I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR);
I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL);
+ I915_WRITE(MCHBAR_RENDER_STANDBY,
+ dev_priv->saveMCHBAR_RENDER_STANDBY);
} else {
I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
@@ -745,11 +747,16 @@ int i915_save_state(struct drm_device *dev)
dev_priv->saveGTIMR = I915_READ(GTIMR);
dev_priv->saveFDI_RXA_IMR = I915_READ(FDI_RXA_IMR);
dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR);
+ dev_priv->saveMCHBAR_RENDER_STANDBY =
+ I915_READ(MCHBAR_RENDER_STANDBY);
} else {
dev_priv->saveIER = I915_READ(IER);
dev_priv->saveIMR = I915_READ(IMR);
}
+ if (IS_IRONLAKE_M(dev))
+ ironlake_disable_drps(dev);
+
/* Cache mode state */
dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
@@ -820,6 +827,9 @@ int i915_restore_state(struct drm_device *dev)
/* Clock gating state */
intel_init_clock_gating(dev);
+ if (IS_IRONLAKE_M(dev))
+ ironlake_enable_drps(dev);
+
/* Cache mode state */
I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index f27567747580..70c9d4ba7042 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -33,6 +33,8 @@
#define SLAVE_ADDR1 0x70
#define SLAVE_ADDR2 0x72
+static int panel_type;
+
static void *
find_section(struct bdb_header *bdb, int section_id)
{
@@ -128,6 +130,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
dev_priv->lvds_dither = lvds_options->pixel_dither;
if (lvds_options->panel_type == 0xff)
return;
+ panel_type = lvds_options->panel_type;
lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
if (!lvds_lfp_data)
@@ -197,7 +200,8 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
memset(temp_mode, 0, sizeof(*temp_mode));
}
kfree(temp_mode);
- if (temp_downclock < panel_fixed_mode->clock) {
+ if (temp_downclock < panel_fixed_mode->clock &&
+ i915_lvds_downclock) {
dev_priv->lvds_downclock_avail = 1;
dev_priv->lvds_downclock = temp_downclock;
DRM_DEBUG_KMS("LVDS downclock is found in VBT. ",
@@ -243,6 +247,7 @@ static void
parse_general_features(struct drm_i915_private *dev_priv,
struct bdb_header *bdb)
{
+ struct drm_device *dev = dev_priv->dev;
struct bdb_general_features *general;
/* Set sensible defaults in case we can't find the general block */
@@ -259,7 +264,7 @@ parse_general_features(struct drm_i915_private *dev_priv,
if (IS_I85X(dev_priv->dev))
dev_priv->lvds_ssc_freq =
general->ssc_freq ? 66 : 48;
- else if (IS_IRONLAKE(dev_priv->dev))
+ else if (IS_IRONLAKE(dev_priv->dev) || IS_GEN6(dev))
dev_priv->lvds_ssc_freq =
general->ssc_freq ? 100 : 120;
else
@@ -405,6 +410,34 @@ parse_driver_features(struct drm_i915_private *dev_priv,
}
static void
+parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
+{
+ struct bdb_edp *edp;
+
+ edp = find_section(bdb, BDB_EDP);
+ if (!edp) {
+ if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp_support) {
+ DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported,\
+ assume 18bpp panel color depth.\n");
+ dev_priv->edp_bpp = 18;
+ }
+ return;
+ }
+
+ switch ((edp->color_depth >> (panel_type * 2)) & 3) {
+ case EDP_18BPP:
+ dev_priv->edp_bpp = 18;
+ break;
+ case EDP_24BPP:
+ dev_priv->edp_bpp = 24;
+ break;
+ case EDP_30BPP:
+ dev_priv->edp_bpp = 30;
+ break;
+ }
+}
+
+static void
parse_device_mapping(struct drm_i915_private *dev_priv,
struct bdb_header *bdb)
{
@@ -521,6 +554,7 @@ intel_init_bios(struct drm_device *dev)
parse_sdvo_device_mapping(dev_priv, bdb);
parse_device_mapping(dev_priv, bdb);
parse_driver_features(dev_priv, bdb);
+ parse_edp(dev_priv, bdb);
pci_unmap_rom(pdev, bios);
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index 425ac9d7f724..4c18514f6f80 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -98,6 +98,7 @@ struct vbios_data {
#define BDB_SDVO_LVDS_PNP_IDS 24
#define BDB_SDVO_LVDS_POWER_SEQ 25
#define BDB_TV_OPTIONS 26
+#define BDB_EDP 27
#define BDB_LVDS_OPTIONS 40
#define BDB_LVDS_LFP_DATA_PTRS 41
#define BDB_LVDS_LFP_DATA 42
@@ -426,6 +427,45 @@ struct bdb_driver_features {
u8 custom_vbt_version;
} __attribute__((packed));
+#define EDP_18BPP 0
+#define EDP_24BPP 1
+#define EDP_30BPP 2
+#define EDP_RATE_1_62 0
+#define EDP_RATE_2_7 1
+#define EDP_LANE_1 0
+#define EDP_LANE_2 1
+#define EDP_LANE_4 3
+#define EDP_PREEMPHASIS_NONE 0
+#define EDP_PREEMPHASIS_3_5dB 1
+#define EDP_PREEMPHASIS_6dB 2
+#define EDP_PREEMPHASIS_9_5dB 3
+#define EDP_VSWING_0_4V 0
+#define EDP_VSWING_0_6V 1
+#define EDP_VSWING_0_8V 2
+#define EDP_VSWING_1_2V 3
+
+struct edp_power_seq {
+ u16 t3;
+ u16 t7;
+ u16 t9;
+ u16 t10;
+ u16 t12;
+} __attribute__ ((packed));
+
+struct edp_link_params {
+ u8 rate:4;
+ u8 lanes:4;
+ u8 preemphasis:4;
+ u8 vswing:4;
+} __attribute__ ((packed));
+
+struct bdb_edp {
+ struct edp_power_seq power_seqs[16];
+ u32 color_depth;
+ u32 sdrrs_msa_timing_delay;
+ struct edp_link_params link_params[16];
+} __attribute__ ((packed));
+
bool intel_init_bios(struct drm_device *dev);
/*
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index ddefc871edfe..fccf07470c8f 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -39,7 +39,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
struct drm_i915_private *dev_priv = dev->dev_private;
u32 temp, reg;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
reg = PCH_ADPA;
else
reg = ADPA;
@@ -113,7 +113,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
else
dpll_md_reg = DPLL_B_MD;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
adpa_reg = PCH_ADPA;
else
adpa_reg = ADPA;
@@ -122,7 +122,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
* Disable separate mode multiplier used when cloning SDVO to CRT
* XXX this needs to be adjusted when we really are cloning
*/
- if (IS_I965G(dev) && !IS_IRONLAKE(dev)) {
+ if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
dpll_md = I915_READ(dpll_md_reg);
I915_WRITE(dpll_md_reg,
dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
@@ -136,11 +136,11 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
if (intel_crtc->pipe == 0) {
adpa |= ADPA_PIPE_A_SELECT;
- if (!IS_IRONLAKE(dev))
+ if (!HAS_PCH_SPLIT(dev))
I915_WRITE(BCLRPAT_A, 0);
} else {
adpa |= ADPA_PIPE_B_SELECT;
- if (!IS_IRONLAKE(dev))
+ if (!HAS_PCH_SPLIT(dev))
I915_WRITE(BCLRPAT_B, 0);
}
@@ -157,6 +157,9 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
adpa = I915_READ(PCH_ADPA);
adpa &= ~ADPA_CRT_HOTPLUG_MASK;
+ /* disable HPD first */
+ I915_WRITE(PCH_ADPA, adpa);
+ (void)I915_READ(PCH_ADPA);
adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
ADPA_CRT_HOTPLUG_WARMUP_10MS |
@@ -199,7 +202,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
u32 hotplug_en;
int i, tries = 0;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
return intel_ironlake_crt_detect_hotplug(connector);
/*
@@ -521,7 +524,7 @@ void intel_crt_init(struct drm_device *dev)
&intel_output->enc);
/* Set up the DDC bus. */
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
i2c_reg = PCH_GPIOA;
else {
i2c_reg = GPIOA;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 002612fae717..9cd6de5f9906 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -70,8 +70,6 @@ struct intel_limit {
intel_p2_t p2;
bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
int, int, intel_clock_t *);
- bool (* find_reduced_pll)(const intel_limit_t *, struct drm_crtc *,
- int, int, intel_clock_t *);
};
#define I8XX_DOT_MIN 25000
@@ -234,7 +232,7 @@ struct intel_limit {
#define G4X_P2_DISPLAY_PORT_FAST 10
#define G4X_P2_DISPLAY_PORT_LIMIT 0
-/* Ironlake */
+/* Ironlake / Sandybridge */
/* as we calculate clock using (register_value + 2) for
N/M1/M2, so here the range value for them is (actual_value-2).
*/
@@ -242,41 +240,91 @@ struct intel_limit {
#define IRONLAKE_DOT_MAX 350000
#define IRONLAKE_VCO_MIN 1760000
#define IRONLAKE_VCO_MAX 3510000
-#define IRONLAKE_N_MIN 1
-#define IRONLAKE_N_MAX 5
-#define IRONLAKE_M_MIN 79
-#define IRONLAKE_M_MAX 118
#define IRONLAKE_M1_MIN 12
-#define IRONLAKE_M1_MAX 23
+#define IRONLAKE_M1_MAX 22
#define IRONLAKE_M2_MIN 5
#define IRONLAKE_M2_MAX 9
-#define IRONLAKE_P_SDVO_DAC_MIN 5
-#define IRONLAKE_P_SDVO_DAC_MAX 80
-#define IRONLAKE_P_LVDS_MIN 28
-#define IRONLAKE_P_LVDS_MAX 112
-#define IRONLAKE_P1_MIN 1
-#define IRONLAKE_P1_MAX 8
-#define IRONLAKE_P2_SDVO_DAC_SLOW 10
-#define IRONLAKE_P2_SDVO_DAC_FAST 5
-#define IRONLAKE_P2_LVDS_SLOW 14 /* single channel */
-#define IRONLAKE_P2_LVDS_FAST 7 /* double channel */
#define IRONLAKE_P2_DOT_LIMIT 225000 /* 225Mhz */
-#define IRONLAKE_P_DISPLAY_PORT_MIN 10
-#define IRONLAKE_P_DISPLAY_PORT_MAX 20
-#define IRONLAKE_P2_DISPLAY_PORT_FAST 10
-#define IRONLAKE_P2_DISPLAY_PORT_SLOW 10
-#define IRONLAKE_P2_DISPLAY_PORT_LIMIT 0
-#define IRONLAKE_P1_DISPLAY_PORT_MIN 1
-#define IRONLAKE_P1_DISPLAY_PORT_MAX 2
+/* We have parameter ranges for different type of outputs. */
+
+/* DAC & HDMI Refclk 120Mhz */
+#define IRONLAKE_DAC_N_MIN 1
+#define IRONLAKE_DAC_N_MAX 5
+#define IRONLAKE_DAC_M_MIN 79
+#define IRONLAKE_DAC_M_MAX 127
+#define IRONLAKE_DAC_P_MIN 5
+#define IRONLAKE_DAC_P_MAX 80
+#define IRONLAKE_DAC_P1_MIN 1
+#define IRONLAKE_DAC_P1_MAX 8
+#define IRONLAKE_DAC_P2_SLOW 10
+#define IRONLAKE_DAC_P2_FAST 5
+
+/* LVDS single-channel 120Mhz refclk */
+#define IRONLAKE_LVDS_S_N_MIN 1
+#define IRONLAKE_LVDS_S_N_MAX 3
+#define IRONLAKE_LVDS_S_M_MIN 79
+#define IRONLAKE_LVDS_S_M_MAX 118
+#define IRONLAKE_LVDS_S_P_MIN 28
+#define IRONLAKE_LVDS_S_P_MAX 112
+#define IRONLAKE_LVDS_S_P1_MIN 2
+#define IRONLAKE_LVDS_S_P1_MAX 8
+#define IRONLAKE_LVDS_S_P2_SLOW 14
+#define IRONLAKE_LVDS_S_P2_FAST 14
+
+/* LVDS dual-channel 120Mhz refclk */
+#define IRONLAKE_LVDS_D_N_MIN 1
+#define IRONLAKE_LVDS_D_N_MAX 3
+#define IRONLAKE_LVDS_D_M_MIN 79
+#define IRONLAKE_LVDS_D_M_MAX 127
+#define IRONLAKE_LVDS_D_P_MIN 14
+#define IRONLAKE_LVDS_D_P_MAX 56
+#define IRONLAKE_LVDS_D_P1_MIN 2
+#define IRONLAKE_LVDS_D_P1_MAX 8
+#define IRONLAKE_LVDS_D_P2_SLOW 7
+#define IRONLAKE_LVDS_D_P2_FAST 7
+
+/* LVDS single-channel 100Mhz refclk */
+#define IRONLAKE_LVDS_S_SSC_N_MIN 1
+#define IRONLAKE_LVDS_S_SSC_N_MAX 2
+#define IRONLAKE_LVDS_S_SSC_M_MIN 79
+#define IRONLAKE_LVDS_S_SSC_M_MAX 126
+#define IRONLAKE_LVDS_S_SSC_P_MIN 28
+#define IRONLAKE_LVDS_S_SSC_P_MAX 112
+#define IRONLAKE_LVDS_S_SSC_P1_MIN 2
+#define IRONLAKE_LVDS_S_SSC_P1_MAX 8
+#define IRONLAKE_LVDS_S_SSC_P2_SLOW 14
+#define IRONLAKE_LVDS_S_SSC_P2_FAST 14
+
+/* LVDS dual-channel 100Mhz refclk */
+#define IRONLAKE_LVDS_D_SSC_N_MIN 1
+#define IRONLAKE_LVDS_D_SSC_N_MAX 3
+#define IRONLAKE_LVDS_D_SSC_M_MIN 79
+#define IRONLAKE_LVDS_D_SSC_M_MAX 126
+#define IRONLAKE_LVDS_D_SSC_P_MIN 14
+#define IRONLAKE_LVDS_D_SSC_P_MAX 42
+#define IRONLAKE_LVDS_D_SSC_P1_MIN 2
+#define IRONLAKE_LVDS_D_SSC_P1_MAX 6
+#define IRONLAKE_LVDS_D_SSC_P2_SLOW 7
+#define IRONLAKE_LVDS_D_SSC_P2_FAST 7
+
+/* DisplayPort */
+#define IRONLAKE_DP_N_MIN 1
+#define IRONLAKE_DP_N_MAX 2
+#define IRONLAKE_DP_M_MIN 81
+#define IRONLAKE_DP_M_MAX 90
+#define IRONLAKE_DP_P_MIN 10
+#define IRONLAKE_DP_P_MAX 20
+#define IRONLAKE_DP_P2_FAST 10
+#define IRONLAKE_DP_P2_SLOW 10
+#define IRONLAKE_DP_P2_LIMIT 0
+#define IRONLAKE_DP_P1_MIN 1
+#define IRONLAKE_DP_P1_MAX 2
static bool
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
static bool
-intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock);
-static bool
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
@@ -299,7 +347,6 @@ static const intel_limit_t intel_limits_i8xx_dvo = {
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
.p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST },
.find_pll = intel_find_best_PLL,
- .find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_i8xx_lvds = {
@@ -314,7 +361,6 @@ static const intel_limit_t intel_limits_i8xx_lvds = {
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
.p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST },
.find_pll = intel_find_best_PLL,
- .find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_i9xx_sdvo = {
@@ -329,7 +375,6 @@ static const intel_limit_t intel_limits_i9xx_sdvo = {
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
.find_pll = intel_find_best_PLL,
- .find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_i9xx_lvds = {
@@ -347,7 +392,6 @@ static const intel_limit_t intel_limits_i9xx_lvds = {
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST },
.find_pll = intel_find_best_PLL,
- .find_reduced_pll = intel_find_best_reduced_PLL,
};
/* below parameter and function is for G4X Chipset Family*/
@@ -365,7 +409,6 @@ static const intel_limit_t intel_limits_g4x_sdvo = {
.p2_fast = G4X_P2_SDVO_FAST
},
.find_pll = intel_g4x_find_best_PLL,
- .find_reduced_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_hdmi = {
@@ -382,7 +425,6 @@ static const intel_limit_t intel_limits_g4x_hdmi = {
.p2_fast = G4X_P2_HDMI_DAC_FAST
},
.find_pll = intel_g4x_find_best_PLL,
- .find_reduced_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
@@ -407,7 +449,6 @@ static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
.p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
},
.find_pll = intel_g4x_find_best_PLL,
- .find_reduced_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
@@ -432,7 +473,6 @@ static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
.p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
},
.find_pll = intel_g4x_find_best_PLL,
- .find_reduced_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_display_port = {
@@ -470,7 +510,6 @@ static const intel_limit_t intel_limits_pineview_sdvo = {
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
.find_pll = intel_find_best_PLL,
- .find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_pineview_lvds = {
@@ -486,36 +525,80 @@ static const intel_limit_t intel_limits_pineview_lvds = {
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW },
.find_pll = intel_find_best_PLL,
- .find_reduced_pll = intel_find_best_reduced_PLL,
};
-static const intel_limit_t intel_limits_ironlake_sdvo = {
+static const intel_limit_t intel_limits_ironlake_dac = {
+ .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
+ .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
+ .n = { .min = IRONLAKE_DAC_N_MIN, .max = IRONLAKE_DAC_N_MAX },
+ .m = { .min = IRONLAKE_DAC_M_MIN, .max = IRONLAKE_DAC_M_MAX },
+ .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
+ .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
+ .p = { .min = IRONLAKE_DAC_P_MIN, .max = IRONLAKE_DAC_P_MAX },
+ .p1 = { .min = IRONLAKE_DAC_P1_MIN, .max = IRONLAKE_DAC_P1_MAX },
+ .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
+ .p2_slow = IRONLAKE_DAC_P2_SLOW,
+ .p2_fast = IRONLAKE_DAC_P2_FAST },
+ .find_pll = intel_g4x_find_best_PLL,
+};
+
+static const intel_limit_t intel_limits_ironlake_single_lvds = {
+ .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
+ .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
+ .n = { .min = IRONLAKE_LVDS_S_N_MIN, .max = IRONLAKE_LVDS_S_N_MAX },
+ .m = { .min = IRONLAKE_LVDS_S_M_MIN, .max = IRONLAKE_LVDS_S_M_MAX },
+ .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
+ .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
+ .p = { .min = IRONLAKE_LVDS_S_P_MIN, .max = IRONLAKE_LVDS_S_P_MAX },
+ .p1 = { .min = IRONLAKE_LVDS_S_P1_MIN, .max = IRONLAKE_LVDS_S_P1_MAX },
+ .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
+ .p2_slow = IRONLAKE_LVDS_S_P2_SLOW,
+ .p2_fast = IRONLAKE_LVDS_S_P2_FAST },
+ .find_pll = intel_g4x_find_best_PLL,
+};
+
+static const intel_limit_t intel_limits_ironlake_dual_lvds = {
+ .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
+ .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
+ .n = { .min = IRONLAKE_LVDS_D_N_MIN, .max = IRONLAKE_LVDS_D_N_MAX },
+ .m = { .min = IRONLAKE_LVDS_D_M_MIN, .max = IRONLAKE_LVDS_D_M_MAX },
+ .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
+ .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
+ .p = { .min = IRONLAKE_LVDS_D_P_MIN, .max = IRONLAKE_LVDS_D_P_MAX },
+ .p1 = { .min = IRONLAKE_LVDS_D_P1_MIN, .max = IRONLAKE_LVDS_D_P1_MAX },
+ .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
+ .p2_slow = IRONLAKE_LVDS_D_P2_SLOW,
+ .p2_fast = IRONLAKE_LVDS_D_P2_FAST },
+ .find_pll = intel_g4x_find_best_PLL,
+};
+
+static const intel_limit_t intel_limits_ironlake_single_lvds_100m = {
.dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
.vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
- .n = { .min = IRONLAKE_N_MIN, .max = IRONLAKE_N_MAX },
- .m = { .min = IRONLAKE_M_MIN, .max = IRONLAKE_M_MAX },
+ .n = { .min = IRONLAKE_LVDS_S_SSC_N_MIN, .max = IRONLAKE_LVDS_S_SSC_N_MAX },
+ .m = { .min = IRONLAKE_LVDS_S_SSC_M_MIN, .max = IRONLAKE_LVDS_S_SSC_M_MAX },
.m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
.m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
- .p = { .min = IRONLAKE_P_SDVO_DAC_MIN, .max = IRONLAKE_P_SDVO_DAC_MAX },
- .p1 = { .min = IRONLAKE_P1_MIN, .max = IRONLAKE_P1_MAX },
+ .p = { .min = IRONLAKE_LVDS_S_SSC_P_MIN, .max = IRONLAKE_LVDS_S_SSC_P_MAX },
+ .p1 = { .min = IRONLAKE_LVDS_S_SSC_P1_MIN,.max = IRONLAKE_LVDS_S_SSC_P1_MAX },
.p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
- .p2_slow = IRONLAKE_P2_SDVO_DAC_SLOW,
- .p2_fast = IRONLAKE_P2_SDVO_DAC_FAST },
+ .p2_slow = IRONLAKE_LVDS_S_SSC_P2_SLOW,
+ .p2_fast = IRONLAKE_LVDS_S_SSC_P2_FAST },
.find_pll = intel_g4x_find_best_PLL,
};
-static const intel_limit_t intel_limits_ironlake_lvds = {
+static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = {
.dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
.vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
- .n = { .min = IRONLAKE_N_MIN, .max = IRONLAKE_N_MAX },
- .m = { .min = IRONLAKE_M_MIN, .max = IRONLAKE_M_MAX },
+ .n = { .min = IRONLAKE_LVDS_D_SSC_N_MIN, .max = IRONLAKE_LVDS_D_SSC_N_MAX },
+ .m = { .min = IRONLAKE_LVDS_D_SSC_M_MIN, .max = IRONLAKE_LVDS_D_SSC_M_MAX },
.m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
.m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
- .p = { .min = IRONLAKE_P_LVDS_MIN, .max = IRONLAKE_P_LVDS_MAX },
- .p1 = { .min = IRONLAKE_P1_MIN, .max = IRONLAKE_P1_MAX },
+ .p = { .min = IRONLAKE_LVDS_D_SSC_P_MIN, .max = IRONLAKE_LVDS_D_SSC_P_MAX },
+ .p1 = { .min = IRONLAKE_LVDS_D_SSC_P1_MIN,.max = IRONLAKE_LVDS_D_SSC_P1_MAX },
.p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
- .p2_slow = IRONLAKE_P2_LVDS_SLOW,
- .p2_fast = IRONLAKE_P2_LVDS_FAST },
+ .p2_slow = IRONLAKE_LVDS_D_SSC_P2_SLOW,
+ .p2_fast = IRONLAKE_LVDS_D_SSC_P2_FAST },
.find_pll = intel_g4x_find_best_PLL,
};
@@ -524,34 +607,53 @@ static const intel_limit_t intel_limits_ironlake_display_port = {
.max = IRONLAKE_DOT_MAX },
.vco = { .min = IRONLAKE_VCO_MIN,
.max = IRONLAKE_VCO_MAX},
- .n = { .min = IRONLAKE_N_MIN,
- .max = IRONLAKE_N_MAX },
- .m = { .min = IRONLAKE_M_MIN,
- .max = IRONLAKE_M_MAX },
+ .n = { .min = IRONLAKE_DP_N_MIN,
+ .max = IRONLAKE_DP_N_MAX },
+ .m = { .min = IRONLAKE_DP_M_MIN,
+ .max = IRONLAKE_DP_M_MAX },
.m1 = { .min = IRONLAKE_M1_MIN,
.max = IRONLAKE_M1_MAX },
.m2 = { .min = IRONLAKE_M2_MIN,
.max = IRONLAKE_M2_MAX },
- .p = { .min = IRONLAKE_P_DISPLAY_PORT_MIN,
- .max = IRONLAKE_P_DISPLAY_PORT_MAX },
- .p1 = { .min = IRONLAKE_P1_DISPLAY_PORT_MIN,
- .max = IRONLAKE_P1_DISPLAY_PORT_MAX},
- .p2 = { .dot_limit = IRONLAKE_P2_DISPLAY_PORT_LIMIT,
- .p2_slow = IRONLAKE_P2_DISPLAY_PORT_SLOW,
- .p2_fast = IRONLAKE_P2_DISPLAY_PORT_FAST },
+ .p = { .min = IRONLAKE_DP_P_MIN,
+ .max = IRONLAKE_DP_P_MAX },
+ .p1 = { .min = IRONLAKE_DP_P1_MIN,
+ .max = IRONLAKE_DP_P1_MAX},
+ .p2 = { .dot_limit = IRONLAKE_DP_P2_LIMIT,
+ .p2_slow = IRONLAKE_DP_P2_SLOW,
+ .p2_fast = IRONLAKE_DP_P2_FAST },
.find_pll = intel_find_pll_ironlake_dp,
};
static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc)
{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
const intel_limit_t *limit;
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
- limit = &intel_limits_ironlake_lvds;
- else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) ||
+ int refclk = 120;
+
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+ if (dev_priv->lvds_use_ssc && dev_priv->lvds_ssc_freq == 100)
+ refclk = 100;
+
+ if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
+ LVDS_CLKB_POWER_UP) {
+ /* LVDS dual channel */
+ if (refclk == 100)
+ limit = &intel_limits_ironlake_dual_lvds_100m;
+ else
+ limit = &intel_limits_ironlake_dual_lvds;
+ } else {
+ if (refclk == 100)
+ limit = &intel_limits_ironlake_single_lvds_100m;
+ else
+ limit = &intel_limits_ironlake_single_lvds;
+ }
+ } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) ||
HAS_eDP)
limit = &intel_limits_ironlake_display_port;
else
- limit = &intel_limits_ironlake_sdvo;
+ limit = &intel_limits_ironlake_dac;
return limit;
}
@@ -588,7 +690,7 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
const intel_limit_t *limit;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
limit = intel_ironlake_limit(crtc);
else if (IS_G4X(dev)) {
limit = intel_g4x_limit(crtc);
@@ -768,46 +870,6 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
return (err != target);
}
-
-static bool
-intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock)
-
-{
- struct drm_device *dev = crtc->dev;
- intel_clock_t clock;
- int err = target;
- bool found = false;
-
- memcpy(&clock, best_clock, sizeof(intel_clock_t));
-
- for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
- for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++) {
- /* m1 is always 0 in Pineview */
- if (clock.m2 >= clock.m1 && !IS_PINEVIEW(dev))
- break;
- for (clock.n = limit->n.min; clock.n <= limit->n.max;
- clock.n++) {
- int this_err;
-
- intel_clock(dev, refclk, &clock);
-
- if (!intel_PLL_is_valid(crtc, &clock))
- continue;
-
- this_err = abs(clock.dot - target);
- if (this_err < err) {
- *best_clock = clock;
- err = this_err;
- found = true;
- }
- }
- }
- }
-
- return found;
-}
-
static bool
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock)
@@ -824,7 +886,7 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
int lvds_reg;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
lvds_reg = PCH_LVDS;
else
lvds_reg = LVDS;
@@ -969,6 +1031,8 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
/* enable it... */
fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC;
+ if (IS_I945GM(dev))
+ fbc_ctl |= FBC_C3_IDLE; /* 945 needs special SR handling */
fbc_ctl |= (dev_priv->cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
if (obj_priv->tiling_mode != I915_TILING_NONE)
@@ -1124,25 +1188,30 @@ static void intel_update_fbc(struct drm_crtc *crtc,
if (intel_fb->obj->size > dev_priv->cfb_size) {
DRM_DEBUG_KMS("framebuffer too large, disabling "
"compression\n");
+ dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
goto out_disable;
}
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
(mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
DRM_DEBUG_KMS("mode incompatible with compression, "
"disabling\n");
+ dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
goto out_disable;
}
if ((mode->hdisplay > 2048) ||
(mode->vdisplay > 1536)) {
DRM_DEBUG_KMS("mode too large for compression, disabling\n");
+ dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
goto out_disable;
}
if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) {
DRM_DEBUG_KMS("plane not 0, disabling compression\n");
+ dev_priv->no_fbc_reason = FBC_BAD_PLANE;
goto out_disable;
}
if (obj_priv->tiling_mode != I915_TILING_X) {
DRM_DEBUG_KMS("framebuffer not tiled, disabling compression\n");
+ dev_priv->no_fbc_reason = FBC_NOT_TILED;
goto out_disable;
}
@@ -1262,7 +1331,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
return ret;
}
- ret = i915_gem_object_set_to_gtt_domain(obj, 1);
+ ret = i915_gem_object_set_to_display_plane(obj);
if (ret != 0) {
i915_gem_object_unpin(obj);
mutex_unlock(&dev->struct_mutex);
@@ -1302,7 +1371,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
dspcntr &= ~DISPPLANE_TILED;
}
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
/* must disable */
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
@@ -1363,7 +1432,7 @@ static void i915_disable_vga (struct drm_device *dev)
u8 sr1;
u32 vga_reg;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
vga_reg = CPU_VGACNTRL;
else
vga_reg = VGACNTRL;
@@ -1693,6 +1762,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
case DRM_MODE_DPMS_OFF:
DRM_DEBUG_KMS("crtc %d dpms off\n", pipe);
+ drm_vblank_off(dev, pipe);
/* Disable display plane */
temp = I915_READ(dspcntr_reg);
if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
@@ -2046,7 +2116,7 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
struct drm_display_mode *adjusted_mode)
{
struct drm_device *dev = crtc->dev;
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
/* FDI link clock is fixed at 2.7G */
if (mode->clock * 3 > 27000 * 4)
return MODE_CLOCK_HIGH;
@@ -2574,6 +2644,10 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock,
sr_entries = roundup(sr_entries / cacheline_size, 1);
DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
+ } else {
+ /* Turn off self refresh if both pipes are enabled */
+ I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
+ & ~FW_BLC_SELF_EN);
}
DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n",
@@ -2617,6 +2691,10 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
srwm = 1;
srwm &= 0x3f;
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
+ } else {
+ /* Turn off self refresh if both pipes are enabled */
+ I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
+ & ~FW_BLC_SELF_EN);
}
DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n",
@@ -2684,7 +2762,22 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
srwm = total_size - sr_entries;
if (srwm < 0)
srwm = 1;
- I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f));
+
+ if (IS_I945G(dev) || IS_I945GM(dev))
+ I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_FIFO_MASK | (srwm & 0xff));
+ else if (IS_I915GM(dev)) {
+ /* 915M has a smaller SRWM field */
+ I915_WRITE(FW_BLC_SELF, srwm & 0x3f);
+ I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN);
+ }
+ } else {
+ /* Turn off self refresh if both pipes are enabled */
+ if (IS_I945G(dev) || IS_I945GM(dev)) {
+ I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
+ & ~FW_BLC_SELF_EN);
+ } else if (IS_I915GM(dev)) {
+ I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN);
+ }
}
DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
@@ -2890,7 +2983,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
refclk / 1000);
} else if (IS_I9XX(dev)) {
refclk = 96000;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
refclk = 120000; /* 120Mhz refclk */
} else {
refclk = 48000;
@@ -2910,10 +3003,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
return -EINVAL;
}
- if (is_lvds && limit->find_reduced_pll &&
- dev_priv->lvds_downclock_avail) {
- memcpy(&reduced_clock, &clock, sizeof(intel_clock_t));
- has_reduced_clock = limit->find_reduced_pll(limit, crtc,
+ if (is_lvds && dev_priv->lvds_downclock_avail) {
+ has_reduced_clock = limit->find_pll(limit, crtc,
dev_priv->lvds_downclock,
refclk,
&reduced_clock);
@@ -2950,7 +3041,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}
/* FDI link */
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
int lane, link_bw, bpp;
/* eDP doesn't require FDI link, so just set DP M/N
according to current link config */
@@ -2981,6 +3072,21 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
temp |= PIPE_8BPC;
else
temp |= PIPE_6BPC;
+ } else if (is_edp) {
+ switch (dev_priv->edp_bpp/3) {
+ case 8:
+ temp |= PIPE_8BPC;
+ break;
+ case 10:
+ temp |= PIPE_10BPC;
+ break;
+ case 6:
+ temp |= PIPE_6BPC;
+ break;
+ case 12:
+ temp |= PIPE_12BPC;
+ break;
+ }
} else
temp |= PIPE_8BPC;
I915_WRITE(pipeconf_reg, temp);
@@ -3012,7 +3118,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
* PCH B stepping, previous chipset stepping should be
* ignoring this setting.
*/
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
temp = I915_READ(PCH_DREF_CONTROL);
/* Always enable nonspread source */
temp &= ~DREF_NONSPREAD_SOURCE_MASK;
@@ -3059,7 +3165,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
reduced_clock.m2;
}
- if (!IS_IRONLAKE(dev))
+ if (!HAS_PCH_SPLIT(dev))
dpll = DPLL_VGA_MODE_DIS;
if (IS_I9XX(dev)) {
@@ -3072,7 +3178,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
- else if (IS_IRONLAKE(dev))
+ else if (HAS_PCH_SPLIT(dev))
dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
}
if (is_dp)
@@ -3084,7 +3190,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
else {
dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
/* also FPA1 */
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
if (IS_G4X(dev) && has_reduced_clock)
dpll |= (1 << (reduced_clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
@@ -3103,7 +3209,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
break;
}
- if (IS_I965G(dev) && !IS_IRONLAKE(dev))
+ if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
} else {
if (is_lvds) {
@@ -3137,7 +3243,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Ironlake's plane is forced to pipe, bit 24 is to
enable color space conversion */
- if (!IS_IRONLAKE(dev)) {
+ if (!HAS_PCH_SPLIT(dev)) {
if (pipe == 0)
dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
else
@@ -3164,14 +3270,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Disable the panel fitter if it was on our pipe */
- if (!IS_IRONLAKE(dev) && intel_panel_fitter_pipe(dev) == pipe)
+ if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe)
I915_WRITE(PFIT_CONTROL, 0);
DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
drm_mode_debug_printmodeline(mode);
/* assign to Ironlake registers */
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
fp_reg = pch_fp_reg;
dpll_reg = pch_dpll_reg;
}
@@ -3192,7 +3298,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
if (is_lvds) {
u32 lvds;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
lvds_reg = PCH_LVDS;
lvds = I915_READ(lvds_reg);
@@ -3214,12 +3320,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* set the dithering flag */
if (IS_I965G(dev)) {
if (dev_priv->lvds_dither) {
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
pipeconf |= PIPE_ENABLE_DITHER;
else
lvds |= LVDS_ENABLE_DITHER;
} else {
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
pipeconf &= ~PIPE_ENABLE_DITHER;
else
lvds &= ~LVDS_ENABLE_DITHER;
@@ -3238,7 +3344,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Wait for the clocks to stabilize. */
udelay(150);
- if (IS_I965G(dev) && !IS_IRONLAKE(dev)) {
+ if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
if (is_sdvo) {
sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
@@ -3285,14 +3391,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* pipesrc and dspsize control the size that is scaled from, which should
* always be the user's requested size.
*/
- if (!IS_IRONLAKE(dev)) {
+ if (!HAS_PCH_SPLIT(dev)) {
I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) |
(mode->hdisplay - 1));
I915_WRITE(dsppos_reg, 0);
}
I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m);
I915_WRITE(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n);
I915_WRITE(link_m1_reg, m_n.link_m);
@@ -3348,7 +3454,7 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
return;
/* use legacy palette for Ironlake */
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
palreg = (intel_crtc->pipe == 0) ? LGC_PALETTE_A :
LGC_PALETTE_B;
@@ -3463,11 +3569,10 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
intel_crtc->cursor_bo = bo;
return 0;
-fail:
- mutex_lock(&dev->struct_mutex);
fail_locked:
- drm_gem_object_unreference(bo);
mutex_unlock(&dev->struct_mutex);
+fail:
+ drm_gem_object_unreference_unlocked(bo);
return ret;
}
@@ -3832,7 +3937,7 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
int dpll = I915_READ(dpll_reg);
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
return;
if (!dev_priv->lvds_downclock_avail)
@@ -3871,7 +3976,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
int dpll = I915_READ(dpll_reg);
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
return;
if (!dev_priv->lvds_downclock_avail)
@@ -3921,6 +4026,11 @@ static void intel_idle_update(struct work_struct *work)
mutex_lock(&dev->struct_mutex);
+ if (IS_I945G(dev) || IS_I945GM(dev)) {
+ DRM_DEBUG_DRIVER("enable memory self refresh on 945\n");
+ I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
+ }
+
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
/* Skip inactive CRTCs */
if (!crtc->fb)
@@ -3954,9 +4064,17 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return;
- if (!dev_priv->busy)
+ if (!dev_priv->busy) {
+ if (IS_I945G(dev) || IS_I945GM(dev)) {
+ u32 fw_blc_self;
+
+ DRM_DEBUG_DRIVER("disable memory self refresh on 945\n");
+ fw_blc_self = I915_READ(FW_BLC_SELF);
+ fw_blc_self &= ~FW_BLC_SELF_EN;
+ I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
+ }
dev_priv->busy = true;
- else
+ } else
mod_timer(&dev_priv->idle_timer, jiffies +
msecs_to_jiffies(GPU_IDLE_TIMEOUT));
@@ -3968,6 +4086,14 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
intel_fb = to_intel_framebuffer(crtc->fb);
if (intel_fb->obj == obj) {
if (!intel_crtc->busy) {
+ if (IS_I945G(dev) || IS_I945GM(dev)) {
+ u32 fw_blc_self;
+
+ DRM_DEBUG_DRIVER("disable memory self refresh on 945\n");
+ fw_blc_self = I915_READ(FW_BLC_SELF);
+ fw_blc_self &= ~FW_BLC_SELF_EN;
+ I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
+ }
/* Non-busy -> busy, upclock */
intel_increase_pllclock(crtc, true);
intel_crtc->busy = true;
@@ -3991,7 +4117,8 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
struct intel_unpin_work {
struct work_struct work;
struct drm_device *dev;
- struct drm_gem_object *obj;
+ struct drm_gem_object *old_fb_obj;
+ struct drm_gem_object *pending_flip_obj;
struct drm_pending_vblank_event *event;
int pending;
};
@@ -4002,8 +4129,9 @@ static void intel_unpin_work_fn(struct work_struct *__work)
container_of(__work, struct intel_unpin_work, work);
mutex_lock(&work->dev->struct_mutex);
- i915_gem_object_unpin(work->obj);
- drm_gem_object_unreference(work->obj);
+ i915_gem_object_unpin(work->old_fb_obj);
+ drm_gem_object_unreference(work->pending_flip_obj);
+ drm_gem_object_unreference(work->old_fb_obj);
mutex_unlock(&work->dev->struct_mutex);
kfree(work);
}
@@ -4026,6 +4154,12 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe)
spin_lock_irqsave(&dev->event_lock, flags);
work = intel_crtc->unpin_work;
if (work == NULL || !work->pending) {
+ if (work && !work->pending) {
+ obj_priv = work->pending_flip_obj->driver_private;
+ DRM_DEBUG_DRIVER("flip finish: %p (%d) not pending?\n",
+ obj_priv,
+ atomic_read(&obj_priv->pending_flip));
+ }
spin_unlock_irqrestore(&dev->event_lock, flags);
return;
}
@@ -4046,8 +4180,11 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe)
spin_unlock_irqrestore(&dev->event_lock, flags);
- obj_priv = work->obj->driver_private;
- if (atomic_dec_and_test(&obj_priv->pending_flip))
+ obj_priv = work->pending_flip_obj->driver_private;
+
+ /* Initial scanout buffer will have a 0 pending flip count */
+ if ((atomic_read(&obj_priv->pending_flip) == 0) ||
+ atomic_dec_and_test(&obj_priv->pending_flip))
DRM_WAKEUP(&dev_priv->pending_flip_queue);
schedule_work(&work->work);
}
@@ -4060,8 +4197,11 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane)
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
- if (intel_crtc->unpin_work)
+ if (intel_crtc->unpin_work) {
intel_crtc->unpin_work->pending = 1;
+ } else {
+ DRM_DEBUG_DRIVER("preparing flip with no unpin work?\n");
+ }
spin_unlock_irqrestore(&dev->event_lock, flags);
}
@@ -4077,7 +4217,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_unpin_work *work;
unsigned long flags;
- int ret;
+ int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC;
+ int ret, pipesrc;
RING_LOCALS;
work = kzalloc(sizeof *work, GFP_KERNEL);
@@ -4089,12 +4230,13 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
work->event = event;
work->dev = crtc->dev;
intel_fb = to_intel_framebuffer(crtc->fb);
- work->obj = intel_fb->obj;
+ work->old_fb_obj = intel_fb->obj;
INIT_WORK(&work->work, intel_unpin_work_fn);
/* We borrow the event spin lock for protecting unpin_work */
spin_lock_irqsave(&dev->event_lock, flags);
if (intel_crtc->unpin_work) {
+ DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
spin_unlock_irqrestore(&dev->event_lock, flags);
kfree(work);
mutex_unlock(&dev->struct_mutex);
@@ -4108,19 +4250,24 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
ret = intel_pin_and_fence_fb_obj(dev, obj);
if (ret != 0) {
+ DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n",
+ obj->driver_private);
kfree(work);
+ intel_crtc->unpin_work = NULL;
mutex_unlock(&dev->struct_mutex);
return ret;
}
- /* Reference the old fb object for the scheduled work. */
- drm_gem_object_reference(work->obj);
+ /* Reference the objects for the scheduled work. */
+ drm_gem_object_reference(work->old_fb_obj);
+ drm_gem_object_reference(obj);
crtc->fb = fb;
i915_gem_object_flush_write_domain(obj);
drm_vblank_get(dev, intel_crtc->pipe);
obj_priv = obj->driver_private;
atomic_inc(&obj_priv->pending_flip);
+ work->pending_flip_obj = obj;
BEGIN_LP_RING(4);
OUT_RING(MI_DISPLAY_FLIP |
@@ -4128,7 +4275,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
OUT_RING(fb->pitch);
if (IS_I965G(dev)) {
OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode);
- OUT_RING((fb->width << 16) | fb->height);
+ pipesrc = I915_READ(pipesrc_reg);
+ OUT_RING(pipesrc & 0x0fff0fff);
} else {
OUT_RING(obj_priv->gtt_offset);
OUT_RING(MI_NOOP);
@@ -4270,7 +4418,7 @@ static void intel_setup_outputs(struct drm_device *dev)
if (IS_MOBILE(dev) && !IS_I830(dev))
intel_lvds_init(dev);
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
int found;
if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED))
@@ -4339,7 +4487,7 @@ static void intel_setup_outputs(struct drm_device *dev)
DRM_DEBUG_KMS("probing DP_D\n");
intel_dp_init(dev, DP_D);
}
- } else if (IS_I8XX(dev))
+ } else if (IS_GEN2(dev))
intel_dvo_init(dev);
if (SUPPORTS_TV(dev))
@@ -4364,9 +4512,7 @@ static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
intelfb_remove(dev, fb);
drm_framebuffer_cleanup(fb);
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(intel_fb->obj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(intel_fb->obj);
kfree(intel_fb);
}
@@ -4429,9 +4575,7 @@ intel_user_framebuffer_create(struct drm_device *dev,
ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj);
if (ret) {
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(obj);
return NULL;
}
@@ -4479,6 +4623,91 @@ err_unref:
return NULL;
}
+void ironlake_enable_drps(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 rgvmodectl = I915_READ(MEMMODECTL), rgvswctl;
+ u8 fmax, fmin, fstart, vstart;
+ int i = 0;
+
+ /* 100ms RC evaluation intervals */
+ I915_WRITE(RCUPEI, 100000);
+ I915_WRITE(RCDNEI, 100000);
+
+ /* Set max/min thresholds to 90ms and 80ms respectively */
+ I915_WRITE(RCBMAXAVG, 90000);
+ I915_WRITE(RCBMINAVG, 80000);
+
+ I915_WRITE(MEMIHYST, 1);
+
+ /* Set up min, max, and cur for interrupt handling */
+ fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT;
+ fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
+ fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
+ MEMMODE_FSTART_SHIFT;
+ vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
+ PXVFREQ_PX_SHIFT;
+
+ dev_priv->max_delay = fstart; /* can't go to fmax w/o IPS */
+ dev_priv->min_delay = fmin;
+ dev_priv->cur_delay = fstart;
+
+ I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
+
+ /*
+ * Interrupts will be enabled in ironlake_irq_postinstall
+ */
+
+ I915_WRITE(VIDSTART, vstart);
+ POSTING_READ(VIDSTART);
+
+ rgvmodectl |= MEMMODE_SWMODE_EN;
+ I915_WRITE(MEMMODECTL, rgvmodectl);
+
+ while (I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) {
+ if (i++ > 100) {
+ DRM_ERROR("stuck trying to change perf mode\n");
+ break;
+ }
+ msleep(1);
+ }
+ msleep(1);
+
+ rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
+ (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
+ I915_WRITE(MEMSWCTL, rgvswctl);
+ POSTING_READ(MEMSWCTL);
+
+ rgvswctl |= MEMCTL_CMD_STS;
+ I915_WRITE(MEMSWCTL, rgvswctl);
+}
+
+void ironlake_disable_drps(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 rgvswctl;
+ u8 fstart;
+
+ /* Ack interrupts, disable EFC interrupt */
+ I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
+ I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG);
+ I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT);
+ I915_WRITE(DEIIR, DE_PCU_EVENT);
+ I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
+
+ /* Go back to the starting frequency */
+ fstart = (I915_READ(MEMMODECTL) & MEMMODE_FSTART_MASK) >>
+ MEMMODE_FSTART_SHIFT;
+ rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
+ (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
+ I915_WRITE(MEMSWCTL, rgvswctl);
+ msleep(1);
+ rgvswctl |= MEMCTL_CMD_STS;
+ I915_WRITE(MEMSWCTL, rgvswctl);
+ msleep(1);
+
+}
+
void intel_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4487,7 +4716,7 @@ void intel_init_clock_gating(struct drm_device *dev)
* Disable clock gating reported to work incorrectly according to the
* specs, but enable as much else as we can.
*/
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
return;
} else if (IS_G4X(dev)) {
uint32_t dspclk_gate;
@@ -4560,7 +4789,7 @@ static void intel_init_display(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
/* We always want a DPMS function */
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
dev_priv->display.dpms = ironlake_crtc_dpms;
else
dev_priv->display.dpms = i9xx_crtc_dpms;
@@ -4603,7 +4832,7 @@ static void intel_init_display(struct drm_device *dev)
i830_get_display_clock_speed;
/* For FIFO watermark updates */
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
dev_priv->display.update_wm = NULL;
else if (IS_G4X(dev))
dev_priv->display.update_wm = g4x_update_wm;
@@ -4662,11 +4891,6 @@ void intel_modeset_init(struct drm_device *dev)
DRM_DEBUG_KMS("%d display pipe%s available.\n",
num_pipe, num_pipe > 1 ? "s" : "");
- if (IS_I85X(dev))
- pci_read_config_word(dev->pdev, HPLLCC, &dev_priv->orig_clock);
- else if (IS_I9XX(dev) || IS_G4X(dev))
- pci_read_config_word(dev->pdev, GCFGC, &dev_priv->orig_clock);
-
for (i = 0; i < num_pipe; i++) {
intel_crtc_init(dev, i);
}
@@ -4675,6 +4899,9 @@ void intel_modeset_init(struct drm_device *dev)
intel_init_clock_gating(dev);
+ if (IS_IRONLAKE_M(dev))
+ ironlake_enable_drps(dev);
+
INIT_WORK(&dev_priv->idle_work, intel_idle_update);
setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
(unsigned long)dev);
@@ -4722,6 +4949,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
drm_gem_object_unreference(dev_priv->pwrctx);
}
+ if (IS_IRONLAKE_M(dev))
+ ironlake_disable_drps(dev);
+
mutex_unlock(&dev->struct_mutex);
drm_mode_config_cleanup(dev);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 1349d9fd01c4..3ef3a0d0edd0 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -125,9 +125,15 @@ intel_dp_link_clock(uint8_t link_bw)
/* I think this is a fiction */
static int
-intel_dp_link_required(int pixel_clock)
+intel_dp_link_required(struct drm_device *dev,
+ struct intel_output *intel_output, int pixel_clock)
{
- return pixel_clock * 3;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (IS_eDP(intel_output))
+ return (pixel_clock * dev_priv->edp_bpp) / 8;
+ else
+ return pixel_clock * 3;
}
static int
@@ -138,7 +144,8 @@ intel_dp_mode_valid(struct drm_connector *connector,
int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_output));
int max_lanes = intel_dp_max_lane_count(intel_output);
- if (intel_dp_link_required(mode->clock) > max_link_clock * max_lanes)
+ if (intel_dp_link_required(connector->dev, intel_output, mode->clock)
+ > max_link_clock * max_lanes)
return MODE_CLOCK_HIGH;
if (mode->clock < 10000)
@@ -224,7 +231,7 @@ intel_dp_aux_ch(struct intel_output *intel_output,
*/
if (IS_eDP(intel_output))
aux_clock_divider = 225; /* eDP input clock at 450Mhz */
- else if (IS_IRONLAKE(dev))
+ else if (HAS_PCH_SPLIT(dev))
aux_clock_divider = 62; /* IRL input clock fixed at 125Mhz */
else
aux_clock_divider = intel_hrawclk(dev) / 2;
@@ -492,7 +499,8 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
for (clock = 0; clock <= max_clock; clock++) {
int link_avail = intel_dp_link_clock(bws[clock]) * lane_count;
- if (intel_dp_link_required(mode->clock) <= link_avail) {
+ if (intel_dp_link_required(encoder->dev, intel_output, mode->clock)
+ <= link_avail) {
dp_priv->link_bw = bws[clock];
dp_priv->lane_count = lane_count;
adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw);
@@ -576,7 +584,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
intel_dp_compute_m_n(3, lane_count,
mode->clock, adjusted_mode->clock, &m_n);
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
if (intel_crtc->pipe == 0) {
I915_WRITE(TRANSA_DATA_M1,
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
@@ -1168,7 +1176,7 @@ intel_dp_detect(struct drm_connector *connector)
dp_priv->has_audio = false;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
return ironlake_dp_detect(connector);
temp = I915_READ(PORT_HOTPLUG_EN);
@@ -1289,53 +1297,7 @@ intel_dp_hot_plug(struct intel_output *intel_output)
if (dp_priv->dpms_mode == DRM_MODE_DPMS_ON)
intel_dp_check_link_status(intel_output);
}
-/*
- * Enumerate the child dev array parsed from VBT to check whether
- * the given DP is present.
- * If it is present, return 1.
- * If it is not present, return false.
- * If no child dev is parsed from VBT, it is assumed that the given
- * DP is present.
- */
-static int dp_is_present_in_vbt(struct drm_device *dev, int dp_reg)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct child_device_config *p_child;
- int i, dp_port, ret;
-
- if (!dev_priv->child_dev_num)
- return 1;
-
- dp_port = 0;
- if (dp_reg == DP_B || dp_reg == PCH_DP_B)
- dp_port = PORT_IDPB;
- else if (dp_reg == DP_C || dp_reg == PCH_DP_C)
- dp_port = PORT_IDPC;
- else if (dp_reg == DP_D || dp_reg == PCH_DP_D)
- dp_port = PORT_IDPD;
-
- ret = 0;
- for (i = 0; i < dev_priv->child_dev_num; i++) {
- p_child = dev_priv->child_dev + i;
- /*
- * If the device type is not DP, continue.
- */
- if (p_child->device_type != DEVICE_TYPE_DP &&
- p_child->device_type != DEVICE_TYPE_eDP)
- continue;
- /* Find the eDP port */
- if (dp_reg == DP_A && p_child->device_type == DEVICE_TYPE_eDP) {
- ret = 1;
- break;
- }
- /* Find the DP port */
- if (p_child->dvo_port == dp_port) {
- ret = 1;
- break;
- }
- }
- return ret;
-}
+
void
intel_dp_init(struct drm_device *dev, int output_reg)
{
@@ -1345,10 +1307,6 @@ intel_dp_init(struct drm_device *dev, int output_reg)
struct intel_dp_priv *dp_priv;
const char *name = NULL;
- if (!dp_is_present_in_vbt(dev, output_reg)) {
- DRM_DEBUG_KMS("DP is not present. Ignore it\n");
- return;
- }
intel_output = kcalloc(sizeof(struct intel_output) +
sizeof(struct intel_dp_priv), 1, GFP_KERNEL);
if (!intel_output)
@@ -1373,11 +1331,10 @@ intel_dp_init(struct drm_device *dev, int output_reg)
else if (output_reg == DP_D || output_reg == PCH_DP_D)
intel_output->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
- if (IS_eDP(intel_output)) {
- intel_output->crtc_mask = (1 << 1);
+ if (IS_eDP(intel_output))
intel_output->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
- } else
- intel_output->crtc_mask = (1 << 0) | (1 << 1);
+
+ intel_output->crtc_mask = (1 << 0) | (1 << 1);
connector->interlace_allowed = true;
connector->doublescan_allowed = 0;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index a51573da1ff6..3a467ca57857 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -209,6 +209,8 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, int regno);
extern void intel_init_clock_gating(struct drm_device *dev);
+extern void ironlake_enable_drps(struct drm_device *dev);
+extern void ironlake_disable_drps(struct drm_device *dev);
extern int intel_framebuffer_create(struct drm_device *dev,
struct drm_mode_fb_cmd *mode_cmd,
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 371d753e362b..8cd791dc5b29 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -35,6 +35,7 @@
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
+#include <linux/vga_switcheroo.h>
#include "drmP.h"
#include "drm.h"
@@ -148,7 +149,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
mutex_lock(&dev->struct_mutex);
- ret = i915_gem_object_pin(fbo, PAGE_SIZE);
+ ret = i915_gem_object_pin(fbo, 64*1024);
if (ret) {
DRM_ERROR("failed to pin fb: %d\n", ret);
goto out_unref;
@@ -235,6 +236,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
obj_priv->gtt_offset, fbo);
mutex_unlock(&dev->struct_mutex);
+ vga_switcheroo_client_fb_set(dev->pdev, info);
return 0;
out_unpin:
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 06431941b233..a30f8bfc1985 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -82,7 +82,7 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
/* HW workaround, need to toggle enable bit off and on for 12bpc, but
* we do this anyway which shows more stable in testing.
*/
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(hdmi_priv->sdvox_reg, temp & ~SDVO_ENABLE);
POSTING_READ(hdmi_priv->sdvox_reg);
}
@@ -99,7 +99,7 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
/* HW workaround, need to write this twice for issue that may result
* in first write getting masked.
*/
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(hdmi_priv->sdvox_reg, temp);
POSTING_READ(hdmi_priv->sdvox_reg);
}
@@ -225,52 +225,6 @@ static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
.destroy = intel_hdmi_enc_destroy,
};
-/*
- * Enumerate the child dev array parsed from VBT to check whether
- * the given HDMI is present.
- * If it is present, return 1.
- * If it is not present, return false.
- * If no child dev is parsed from VBT, it assumes that the given
- * HDMI is present.
- */
-static int hdmi_is_present_in_vbt(struct drm_device *dev, int hdmi_reg)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct child_device_config *p_child;
- int i, hdmi_port, ret;
-
- if (!dev_priv->child_dev_num)
- return 1;
-
- if (hdmi_reg == SDVOB)
- hdmi_port = DVO_B;
- else if (hdmi_reg == SDVOC)
- hdmi_port = DVO_C;
- else if (hdmi_reg == HDMIB)
- hdmi_port = DVO_B;
- else if (hdmi_reg == HDMIC)
- hdmi_port = DVO_C;
- else if (hdmi_reg == HDMID)
- hdmi_port = DVO_D;
- else
- return 0;
-
- ret = 0;
- for (i = 0; i < dev_priv->child_dev_num; i++) {
- p_child = dev_priv->child_dev + i;
- /*
- * If the device type is not HDMI, continue.
- */
- if (p_child->device_type != DEVICE_TYPE_HDMI)
- continue;
- /* Find the HDMI port */
- if (p_child->dvo_port == hdmi_port) {
- ret = 1;
- break;
- }
- }
- return ret;
-}
void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -278,10 +232,6 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
struct intel_output *intel_output;
struct intel_hdmi_priv *hdmi_priv;
- if (!hdmi_is_present_in_vbt(dev, sdvox_reg)) {
- DRM_DEBUG_KMS("HDMI is not present. Ignored it \n");
- return;
- }
intel_output = kcalloc(sizeof(struct intel_output) +
sizeof(struct intel_hdmi_priv), 1, GFP_KERNEL);
if (!intel_output)
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 8673c735b8ab..fcc753ca5d94 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -128,7 +128,7 @@ intel_i2c_reset_gmbus(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(PCH_GMBUS0, 0);
} else {
I915_WRITE(GMBUS0, 0);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index f4b4aa242df1..14e516fdc2dd 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -56,7 +56,7 @@ static void intel_lvds_set_backlight(struct drm_device *dev, int level)
struct drm_i915_private *dev_priv = dev->dev_private;
u32 blc_pwm_ctl, reg;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
reg = BLC_PWM_CPU_CTL;
else
reg = BLC_PWM_CTL;
@@ -74,7 +74,7 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
reg = BLC_PWM_PCH_CTL2;
else
reg = BLC_PWM_CTL;
@@ -89,17 +89,22 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
static void intel_lvds_set_power(struct drm_device *dev, bool on)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 pp_status, ctl_reg, status_reg;
+ u32 pp_status, ctl_reg, status_reg, lvds_reg;
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
ctl_reg = PCH_PP_CONTROL;
status_reg = PCH_PP_STATUS;
+ lvds_reg = PCH_LVDS;
} else {
ctl_reg = PP_CONTROL;
status_reg = PP_STATUS;
+ lvds_reg = LVDS;
}
if (on) {
+ I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
+ POSTING_READ(lvds_reg);
+
I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
POWER_TARGET_ON);
do {
@@ -115,6 +120,9 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
do {
pp_status = I915_READ(status_reg);
} while (pp_status & PP_ON);
+
+ I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
+ POSTING_READ(lvds_reg);
}
}
@@ -137,7 +145,7 @@ static void intel_lvds_save(struct drm_connector *connector)
u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
u32 pwm_ctl_reg;
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
pp_on_reg = PCH_PP_ON_DELAYS;
pp_off_reg = PCH_PP_OFF_DELAYS;
pp_ctl_reg = PCH_PP_CONTROL;
@@ -174,7 +182,7 @@ static void intel_lvds_restore(struct drm_connector *connector)
u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
u32 pwm_ctl_reg;
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
pp_on_reg = PCH_PP_ON_DELAYS;
pp_off_reg = PCH_PP_OFF_DELAYS;
pp_ctl_reg = PCH_PP_CONTROL;
@@ -297,7 +305,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
}
/* full screen scale for now */
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
goto out;
/* 965+ wants fuzzy fitting */
@@ -327,7 +335,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
* to register description and PRM.
* Change the value here to see the borders for debugging
*/
- if (!IS_IRONLAKE(dev)) {
+ if (!HAS_PCH_SPLIT(dev)) {
I915_WRITE(BCLRPAT_A, 0);
I915_WRITE(BCLRPAT_B, 0);
}
@@ -548,7 +556,7 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg;
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
reg = BLC_PWM_CPU_CTL;
else
reg = BLC_PWM_CTL;
@@ -587,7 +595,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
* settings.
*/
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
return;
/*
@@ -602,6 +610,20 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
/* Some lid devices report incorrect lid status, assume they're connected */
static const struct dmi_system_id bad_lid_status[] = {
{
+ .ident = "Compaq nx9020",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_BOARD_NAME, "3084"),
+ },
+ },
+ {
+ .ident = "Samsung SX20S",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"),
+ DMI_MATCH(DMI_BOARD_NAME, "SX20S"),
+ },
+ },
+ {
.ident = "Aspire One",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -609,12 +631,26 @@ static const struct dmi_system_id bad_lid_status[] = {
},
},
{
+ .ident = "Aspire 1810T",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1810T"),
+ },
+ },
+ {
.ident = "PC-81005",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MALATA"),
DMI_MATCH(DMI_PRODUCT_NAME, "PC-81005"),
},
},
+ {
+ .ident = "Clevo M5x0N",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."),
+ DMI_MATCH(DMI_BOARD_NAME, "M5x0N"),
+ },
+ },
{ }
};
@@ -627,9 +663,16 @@ static const struct dmi_system_id bad_lid_status[] = {
*/
static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector)
{
+ struct drm_device *dev = connector->dev;
enum drm_connector_status status = connector_status_connected;
- if (!acpi_lid_open() && !dmi_check_system(bad_lid_status))
+ /* ACPI lid methods were generally unreliable in this generation, so
+ * don't even bother.
+ */
+ if (IS_GEN2(dev))
+ return connector_status_connected;
+
+ if (!dmi_check_system(bad_lid_status) && !acpi_lid_open())
status = connector_status_disconnected;
return status;
@@ -912,7 +955,8 @@ static void intel_find_lvds_downclock(struct drm_device *dev,
}
}
mutex_unlock(&dev->mode_config.mutex);
- if (temp_downclock < panel_fixed_mode->clock) {
+ if (temp_downclock < panel_fixed_mode->clock &&
+ i915_lvds_downclock) {
/* We found the downclock for LVDS. */
dev_priv->lvds_downclock_avail = 1;
dev_priv->lvds_downclock = temp_downclock;
@@ -991,7 +1035,7 @@ void intel_lvds_init(struct drm_device *dev)
return;
}
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
return;
if (dev_priv->edp_support) {
@@ -1094,7 +1138,7 @@ void intel_lvds_init(struct drm_device *dev)
*/
/* Ironlake: FIXME if still fail, not try pipe mode now */
- if (IS_IRONLAKE(dev))
+ if (HAS_PCH_SPLIT(dev))
goto failed;
lvds = I915_READ(LVDS);
@@ -1115,7 +1159,7 @@ void intel_lvds_init(struct drm_device *dev)
goto failed;
out:
- if (IS_IRONLAKE(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
u32 pwm;
/* make sure PWM is enabled */
pwm = I915_READ(BLC_PWM_CPU_CTL2);
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 2639591c72e9..d355d1d527e7 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -172,7 +172,7 @@ struct overlay_registers {
#define OFC_UPDATE 0x1
#define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev))
-#define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev))
+#define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev) && !IS_GEN6(dev))
static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
@@ -199,16 +199,11 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over
static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
{
- struct drm_device *dev = overlay->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
-
if (OVERLAY_NONPHYSICAL(overlay->dev))
io_mapping_unmap_atomic(overlay->virt_addr);
overlay->virt_addr = NULL;
- I915_READ(OVADD); /* flush wc cashes */
-
return;
}
@@ -225,9 +220,7 @@ static int intel_overlay_on(struct intel_overlay *overlay)
overlay->active = 1;
overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP;
- BEGIN_LP_RING(6);
- OUT_RING(MI_FLUSH);
- OUT_RING(MI_NOOP);
+ BEGIN_LP_RING(4);
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
OUT_RING(overlay->flip_addr | OFC_UPDATE);
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
@@ -267,9 +260,7 @@ static void intel_overlay_continue(struct intel_overlay *overlay,
if (tmp & (1 << 17))
DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
- BEGIN_LP_RING(4);
- OUT_RING(MI_FLUSH);
- OUT_RING(MI_NOOP);
+ BEGIN_LP_RING(2);
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
OUT_RING(flip_addr);
ADVANCE_LP_RING();
@@ -338,9 +329,7 @@ static int intel_overlay_off(struct intel_overlay *overlay)
/* wait for overlay to go idle */
overlay->hw_wedged = SWITCH_OFF_STAGE_1;
- BEGIN_LP_RING(6);
- OUT_RING(MI_FLUSH);
- OUT_RING(MI_NOOP);
+ BEGIN_LP_RING(4);
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
OUT_RING(flip_addr);
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
@@ -358,9 +347,7 @@ static int intel_overlay_off(struct intel_overlay *overlay)
/* turn overlay off */
overlay->hw_wedged = SWITCH_OFF_STAGE_2;
- BEGIN_LP_RING(6);
- OUT_RING(MI_FLUSH);
- OUT_RING(MI_NOOP);
+ BEGIN_LP_RING(4);
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
OUT_RING(flip_addr);
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
@@ -435,9 +422,7 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
overlay->hw_wedged = SWITCH_OFF_STAGE_2;
- BEGIN_LP_RING(6);
- OUT_RING(MI_FLUSH);
- OUT_RING(MI_NOOP);
+ BEGIN_LP_RING(4);
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
OUT_RING(flip_addr);
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
@@ -1179,7 +1164,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
out_unlock:
mutex_unlock(&dev->struct_mutex);
mutex_unlock(&dev->mode_config.mutex);
- drm_gem_object_unreference(new_bo);
+ drm_gem_object_unreference_unlocked(new_bo);
kfree(params);
return ret;
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index de5144c8c153..48daee5c9c63 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -35,6 +35,7 @@
#include "i915_drm.h"
#include "i915_drv.h"
#include "intel_sdvo_regs.h"
+#include <linux/dmi.h>
static char *tv_format_names[] = {
"NTSC_M" , "NTSC_J" , "NTSC_443",
@@ -462,14 +463,63 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
}
/**
- * Don't check status code from this as it switches the bus back to the
- * SDVO chips which defeats the purpose of doing a bus switch in the first
- * place.
+ * Try to read the response after issuie the DDC switch command. But it
+ * is noted that we must do the action of reading response and issuing DDC
+ * switch command in one I2C transaction. Otherwise when we try to start
+ * another I2C transaction after issuing the DDC bus switch, it will be
+ * switched to the internal SDVO register.
*/
static void intel_sdvo_set_control_bus_switch(struct intel_output *intel_output,
u8 target)
{
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1);
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ u8 out_buf[2], cmd_buf[2], ret_value[2], ret;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = sdvo_priv->slave_addr >> 1,
+ .flags = 0,
+ .len = 2,
+ .buf = out_buf,
+ },
+ /* the following two are to read the response */
+ {
+ .addr = sdvo_priv->slave_addr >> 1,
+ .flags = 0,
+ .len = 1,
+ .buf = cmd_buf,
+ },
+ {
+ .addr = sdvo_priv->slave_addr >> 1,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = ret_value,
+ },
+ };
+
+ intel_sdvo_debug_write(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH,
+ &target, 1);
+ /* write the DDC switch command argument */
+ intel_sdvo_write_byte(intel_output, SDVO_I2C_ARG_0, target);
+
+ out_buf[0] = SDVO_I2C_OPCODE;
+ out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH;
+ cmd_buf[0] = SDVO_I2C_CMD_STATUS;
+ cmd_buf[1] = 0;
+ ret_value[0] = 0;
+ ret_value[1] = 0;
+
+ ret = i2c_transfer(intel_output->i2c_bus, msgs, 3);
+ if (ret != 3) {
+ /* failure in I2C transfer */
+ DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
+ return;
+ }
+ if (ret_value[0] != SDVO_CMD_STATUS_SUCCESS) {
+ DRM_DEBUG_KMS("DDC switch command returns response %d\n",
+ ret_value[0]);
+ return;
+ }
+ return;
}
static bool intel_sdvo_set_target_input(struct intel_output *intel_output, bool target_0, bool target_1)
@@ -1579,6 +1629,32 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
edid = drm_get_edid(&intel_output->base,
intel_output->ddc_bus);
+ /* This is only applied to SDVO cards with multiple outputs */
+ if (edid == NULL && intel_sdvo_multifunc_encoder(intel_output)) {
+ uint8_t saved_ddc, temp_ddc;
+ saved_ddc = sdvo_priv->ddc_bus;
+ temp_ddc = sdvo_priv->ddc_bus >> 1;
+ /*
+ * Don't use the 1 as the argument of DDC bus switch to get
+ * the EDID. It is used for SDVO SPD ROM.
+ */
+ while(temp_ddc > 1) {
+ sdvo_priv->ddc_bus = temp_ddc;
+ edid = drm_get_edid(&intel_output->base,
+ intel_output->ddc_bus);
+ if (edid) {
+ /*
+ * When we can get the EDID, maybe it is the
+ * correct DDC bus. Update it.
+ */
+ sdvo_priv->ddc_bus = temp_ddc;
+ break;
+ }
+ temp_ddc >>= 1;
+ }
+ if (edid == NULL)
+ sdvo_priv->ddc_bus = saved_ddc;
+ }
/* when there is no edid and no monitor is connected with VGA
* port, try to use the CRT ddc to read the EDID for DVI-connector
*/
@@ -2208,6 +2284,25 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)
return 0x72;
}
+static int intel_sdvo_bad_tv_callback(const struct dmi_system_id *id)
+{
+ DRM_DEBUG_KMS("Ignoring bad SDVO TV connector for %s\n", id->ident);
+ return 1;
+}
+
+static struct dmi_system_id intel_sdvo_bad_tv[] = {
+ {
+ .callback = intel_sdvo_bad_tv_callback,
+ .ident = "IntelG45/ICH10R/DME1737",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM CORPORATION"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "4800784"),
+ },
+ },
+
+ { } /* terminating entry */
+};
+
static bool
intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
{
@@ -2248,7 +2343,8 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
(1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
(1 << INTEL_ANALOG_CLONE_BIT);
}
- } else if (flags & SDVO_OUTPUT_SVID0) {
+ } else if ((flags & SDVO_OUTPUT_SVID0) &&
+ !dmi_check_system(intel_sdvo_bad_tv)) {
sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
@@ -2270,6 +2366,14 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
connector->connector_type = DRM_MODE_CONNECTOR_VGA;
intel_output->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
(1 << INTEL_ANALOG_CLONE_BIT);
+ } else if (flags & SDVO_OUTPUT_CVBS0) {
+
+ sdvo_priv->controlled_output = SDVO_OUTPUT_CVBS0;
+ encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
+ connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
+ sdvo_priv->is_tv = true;
+ intel_output->needs_tv_clock = true;
+ intel_output->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
} else if (flags & SDVO_OUTPUT_LVDS0) {
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 1d5b9b7b033f..552ec110b741 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1840,8 +1840,6 @@ intel_tv_init(struct drm_device *dev)
drm_connector_attach_property(connector,
dev->mode_config.tv_bottom_margin_property,
tv_priv->margin[TV_MARGIN_BOTTOM]);
-
- dev_priv->hotplug_supported_mask |= TV_HOTPLUG_INT_STATUS;
out:
drm_sysfs_connector_add(connector);
}
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 48c290b5da8c..32db806f3b5a 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -16,7 +16,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
nv04_graph.o nv10_graph.o nv20_graph.o \
nv40_graph.o nv50_graph.o \
- nv40_grctx.o \
+ nv40_grctx.o nv50_grctx.o \
nv04_instmem.o nv50_instmem.o \
nv50_crtc.o nv50_dac.o nv50_sor.o \
nv50_cursor.o nv50_display.o nv50_fbcon.o \
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 1cf488247a16..0e0730a53137 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -11,6 +11,8 @@
#include "nouveau_drm.h"
#include "nv50_display.h"
+#include <linux/vga_switcheroo.h>
+
#define NOUVEAU_DSM_SUPPORTED 0x00
#define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00
@@ -28,31 +30,30 @@
#define NOUVEAU_DSM_POWER_SPEED 0x01
#define NOUVEAU_DSM_POWER_STAMINA 0x02
-static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
-{
- static char muid[] = {
- 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
- 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
- };
+static struct nouveau_dsm_priv {
+ bool dsm_detected;
+ acpi_handle dhandle;
+ acpi_handle dsm_handle;
+} nouveau_dsm_priv;
+
+static const char nouveau_dsm_muid[] = {
+ 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
+ 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
+};
- struct pci_dev *pdev = dev->pdev;
- struct acpi_handle *handle;
+static int nouveau_dsm(acpi_handle handle, int func, int arg, int *result)
+{
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_object_list input;
union acpi_object params[4];
union acpi_object *obj;
int err;
- handle = DEVICE_ACPI_HANDLE(&pdev->dev);
-
- if (!handle)
- return -ENODEV;
-
input.count = 4;
input.pointer = params;
params[0].type = ACPI_TYPE_BUFFER;
- params[0].buffer.length = sizeof(muid);
- params[0].buffer.pointer = (char *)muid;
+ params[0].buffer.length = sizeof(nouveau_dsm_muid);
+ params[0].buffer.pointer = (char *)nouveau_dsm_muid;
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = 0x00000102;
params[2].type = ACPI_TYPE_INTEGER;
@@ -62,7 +63,7 @@ static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
err = acpi_evaluate_object(handle, "_DSM", &input, &output);
if (err) {
- NV_INFO(dev, "failed to evaluate _DSM: %d\n", err);
+ printk(KERN_INFO "failed to evaluate _DSM: %d\n", err);
return err;
}
@@ -86,40 +87,119 @@ static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
return 0;
}
-int nouveau_hybrid_setup(struct drm_device *dev)
+static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
{
- int result;
-
- if (nouveau_dsm(dev, NOUVEAU_DSM_ACTIVE, NOUVEAU_DSM_ACTIVE_QUERY,
- &result))
- return -ENODEV;
-
- NV_INFO(dev, "_DSM hardware status gave 0x%x\n", result);
-
- if (result & 0x1) { /* Stamina mode - disable the external GPU */
- nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_STAMINA,
- NULL);
- nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STAMINA,
- NULL);
- } else { /* Ensure that the external GPU is enabled */
- nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_SPEED, NULL);
- nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_SPEED,
- NULL);
- }
+ return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL);
+}
+
+static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state)
+{
+ int arg;
+ if (state == VGA_SWITCHEROO_ON)
+ arg = NOUVEAU_DSM_POWER_SPEED;
+ else
+ arg = NOUVEAU_DSM_POWER_STAMINA;
+ nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg, NULL);
+ return 0;
+}
+
+static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
+{
+ if (id == VGA_SWITCHEROO_IGD)
+ return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_STAMINA);
+ else
+ return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_SPEED);
+}
+static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
+ enum vga_switcheroo_state state)
+{
+ if (id == VGA_SWITCHEROO_IGD)
+ return 0;
+
+ return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dsm_handle, state);
+}
+
+static int nouveau_dsm_init(void)
+{
return 0;
}
-bool nouveau_dsm_probe(struct drm_device *dev)
+static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
{
- int support = 0;
+ if (nouveau_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
+ return VGA_SWITCHEROO_IGD;
+ else
+ return VGA_SWITCHEROO_DIS;
+}
+
+static struct vga_switcheroo_handler nouveau_dsm_handler = {
+ .switchto = nouveau_dsm_switchto,
+ .power_state = nouveau_dsm_power_state,
+ .init = nouveau_dsm_init,
+ .get_client_id = nouveau_dsm_get_client_id,
+};
- if (nouveau_dsm(dev, NOUVEAU_DSM_SUPPORTED,
- NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &support))
+static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
+{
+ acpi_handle dhandle, nvidia_handle;
+ acpi_status status;
+ int ret;
+ uint32_t result;
+
+ dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
+ if (!dhandle)
+ return false;
+ status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle);
+ if (ACPI_FAILURE(status)) {
return false;
+ }
- if (!support)
+ ret= nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED,
+ NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
+ if (ret < 0)
return false;
+ nouveau_dsm_priv.dhandle = dhandle;
+ nouveau_dsm_priv.dsm_handle = nvidia_handle;
return true;
}
+
+static bool nouveau_dsm_detect(void)
+{
+ char acpi_method_name[255] = { 0 };
+ struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
+ struct pci_dev *pdev = NULL;
+ int has_dsm = 0;
+ int vga_count = 0;
+ while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
+ vga_count++;
+
+ has_dsm |= (nouveau_dsm_pci_probe(pdev) == true);
+ }
+
+ if (vga_count == 2 && has_dsm) {
+ acpi_get_name(nouveau_dsm_priv.dsm_handle, ACPI_FULL_PATHNAME, &buffer);
+ printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
+ acpi_method_name);
+ nouveau_dsm_priv.dsm_detected = true;
+ return true;
+ }
+ return false;
+}
+
+void nouveau_register_dsm_handler(void)
+{
+ bool r;
+
+ r = nouveau_dsm_detect();
+ if (!r)
+ return;
+
+ vga_switcheroo_register_handler(&nouveau_dsm_handler);
+}
+
+void nouveau_unregister_dsm_handler(void)
+{
+ vga_switcheroo_unregister_handler();
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index ba143972769f..75bceee76044 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -310,63 +310,22 @@ valid_reg(struct nvbios *bios, uint32_t reg)
struct drm_device *dev = bios->dev;
/* C51 has misaligned regs on purpose. Marvellous */
- if (reg & 0x2 || (reg & 0x1 && dev_priv->VBIOS.pub.chip_version != 0x51)) {
- NV_ERROR(dev, "========== misaligned reg 0x%08X ==========\n",
- reg);
- return 0;
- }
- /*
- * Warn on C51 regs that have not been verified accessible in
- * mmiotracing
- */
- if (reg & 0x1 && dev_priv->VBIOS.pub.chip_version == 0x51 &&
+ if (reg & 0x2 ||
+ (reg & 0x1 && dev_priv->vbios.chip_version != 0x51))
+ NV_ERROR(dev, "======= misaligned reg 0x%08X =======\n", reg);
+
+ /* warn on C51 regs that haven't been verified accessible in tracing */
+ if (reg & 0x1 && dev_priv->vbios.chip_version == 0x51 &&
reg != 0x130d && reg != 0x1311 && reg != 0x60081d)
NV_WARN(dev, "=== C51 misaligned reg 0x%08X not verified ===\n",
reg);
- /* Trust the init scripts on G80 */
- if (dev_priv->card_type >= NV_50)
- return 1;
-
- #define WITHIN(x, y, z) ((x >= y) && (x < y + z))
- if (WITHIN(reg, NV_PMC_OFFSET, NV_PMC_SIZE))
- return 1;
- if (WITHIN(reg, NV_PBUS_OFFSET, NV_PBUS_SIZE))
- return 1;
- if (WITHIN(reg, NV_PFIFO_OFFSET, NV_PFIFO_SIZE))
- return 1;
- if (dev_priv->VBIOS.pub.chip_version >= 0x30 &&
- (WITHIN(reg, 0x4000, 0x600) || reg == 0x00004600))
- return 1;
- if (dev_priv->VBIOS.pub.chip_version >= 0x40 &&
- WITHIN(reg, 0xc000, 0x48))
- return 1;
- if (dev_priv->VBIOS.pub.chip_version >= 0x17 && reg == 0x0000d204)
- return 1;
- if (dev_priv->VBIOS.pub.chip_version >= 0x40) {
- if (reg == 0x00011014 || reg == 0x00020328)
- return 1;
- if (WITHIN(reg, 0x88000, NV_PBUS_SIZE)) /* new PBUS */
- return 1;
+ if (reg >= (8*1024*1024)) {
+ NV_ERROR(dev, "=== reg 0x%08x out of mapped bounds ===\n", reg);
+ return 0;
}
- if (WITHIN(reg, NV_PFB_OFFSET, NV_PFB_SIZE))
- return 1;
- if (WITHIN(reg, NV_PEXTDEV_OFFSET, NV_PEXTDEV_SIZE))
- return 1;
- if (WITHIN(reg, NV_PCRTC0_OFFSET, NV_PCRTC0_SIZE * 2))
- return 1;
- if (WITHIN(reg, NV_PRAMDAC0_OFFSET, NV_PRAMDAC0_SIZE * 2))
- return 1;
- if (dev_priv->VBIOS.pub.chip_version >= 0x17 && reg == 0x0070fff0)
- return 1;
- if (dev_priv->VBIOS.pub.chip_version == 0x51 &&
- WITHIN(reg, NV_PRAMIN_OFFSET, NV_PRAMIN_SIZE))
- return 1;
- #undef WITHIN
-
- NV_ERROR(dev, "========== unknown reg 0x%08X ==========\n", reg);
- return 0;
+ return 1;
}
static bool
@@ -461,7 +420,7 @@ bios_wr32(struct nvbios *bios, uint32_t reg, uint32_t data)
LOG_OLD_VALUE(bios_rd32(bios, reg));
BIOSLOG(bios, " Write: Reg: 0x%08X, Data: 0x%08X\n", reg, data);
- if (dev_priv->VBIOS.execute) {
+ if (dev_priv->vbios.execute) {
still_alive();
nv_wr32(bios->dev, reg, data);
}
@@ -688,7 +647,7 @@ nv50_pll_set(struct drm_device *dev, uint32_t reg, uint32_t clk)
reg0 = (reg0 & 0xfff8ffff) | (pll.log2P << 16);
reg1 = (reg1 & 0xffff0000) | (pll.N1 << 8) | pll.M1;
- if (dev_priv->VBIOS.execute) {
+ if (dev_priv->vbios.execute) {
still_alive();
nv_wr32(dev, reg + 4, reg1);
nv_wr32(dev, reg + 0, reg0);
@@ -730,7 +689,7 @@ setPLL(struct nvbios *bios, uint32_t reg, uint32_t clk)
static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
/*
* For the results of this function to be correct, CR44 must have been
@@ -741,7 +700,7 @@ static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
uint8_t dcb_entry = NVReadVgaCrtc5758(dev, bios->state.crtchead, 0);
- if (dcb_entry > bios->bdcb.dcb.entries) {
+ if (dcb_entry > bios->dcb.entries) {
NV_ERROR(dev, "CR58 doesn't have a valid DCB entry currently "
"(%02X)\n", dcb_entry);
dcb_entry = 0x7f; /* unused / invalid marker */
@@ -754,25 +713,26 @@ static struct nouveau_i2c_chan *
init_i2c_device_find(struct drm_device *dev, int i2c_index)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct bios_parsed_dcb *bdcb = &dev_priv->VBIOS.bdcb;
+ struct dcb_table *dcb = &dev_priv->vbios.dcb;
if (i2c_index == 0xff) {
/* note: dcb_entry_idx_from_crtchead needs pre-script set-up */
int idx = dcb_entry_idx_from_crtchead(dev), shift = 0;
- int default_indices = bdcb->i2c_default_indices;
+ int default_indices = dcb->i2c_default_indices;
- if (idx != 0x7f && bdcb->dcb.entry[idx].i2c_upper_default)
+ if (idx != 0x7f && dcb->entry[idx].i2c_upper_default)
shift = 4;
i2c_index = (default_indices >> shift) & 0xf;
}
if (i2c_index == 0x80) /* g80+ */
- i2c_index = bdcb->i2c_default_indices & 0xf;
+ i2c_index = dcb->i2c_default_indices & 0xf;
return nouveau_i2c_find(dev, i2c_index);
}
-static uint32_t get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
+static uint32_t
+get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
{
/*
* For mlv < 0x80, it is an index into a table of TMDS base addresses.
@@ -785,6 +745,7 @@ static uint32_t get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
*/
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvbios *bios = &dev_priv->vbios;
const int pramdac_offset[13] = {
0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000 };
const uint32_t pramdac_table[4] = {
@@ -797,13 +758,12 @@ static uint32_t get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
dcb_entry = dcb_entry_idx_from_crtchead(dev);
if (dcb_entry == 0x7f)
return 0;
- dacoffset = pramdac_offset[
- dev_priv->VBIOS.bdcb.dcb.entry[dcb_entry].or];
+ dacoffset = pramdac_offset[bios->dcb.entry[dcb_entry].or];
if (mlv == 0x81)
dacoffset ^= 8;
return 0x6808b0 + dacoffset;
} else {
- if (mlv > ARRAY_SIZE(pramdac_table)) {
+ if (mlv >= ARRAY_SIZE(pramdac_table)) {
NV_ERROR(dev, "Magic Lookup Value too big (%02X)\n",
mlv);
return 0;
@@ -1906,7 +1866,7 @@ init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
- if (dev_priv->card_type >= NV_50)
+ if (dev_priv->card_type >= NV_40)
return 1;
/*
@@ -2615,19 +2575,19 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
const uint32_t nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
- const uint8_t *gpio_table = &bios->data[bios->bdcb.gpio_table_ptr];
+ const uint8_t *gpio_table = &bios->data[bios->dcb.gpio_table_ptr];
const uint8_t *gpio_entry;
int i;
if (!iexec->execute)
return 1;
- if (bios->bdcb.version != 0x40) {
+ if (bios->dcb.version != 0x40) {
NV_ERROR(bios->dev, "DCB table not version 4.0\n");
return 0;
}
- if (!bios->bdcb.gpio_table_ptr) {
+ if (!bios->dcb.gpio_table_ptr) {
NV_WARN(bios->dev, "Invalid pointer to INIT_8E table\n");
return 0;
}
@@ -3164,7 +3124,7 @@ run_digital_op_script(struct drm_device *dev, uint16_t scriptptr,
struct dcb_entry *dcbent, int head, bool dl)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
struct init_exec iexec = {true, false};
NV_TRACE(dev, "0x%04X: Parsing digital output script table\n",
@@ -3181,7 +3141,7 @@ run_digital_op_script(struct drm_device *dev, uint16_t scriptptr,
static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entry *dcbent, int head, enum LVDS_script script)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
uint8_t sub = bios->data[bios->fp.xlated_entry + script] + (bios->fp.link_c_increment && dcbent->or & OUTPUT_C ? 1 : 0);
uint16_t scriptofs = ROM16(bios->data[bios->init_script_tbls_ptr + sub * 2]);
@@ -3196,16 +3156,25 @@ static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entr
}
#ifdef __powerpc__
/* Powerbook specific quirks */
- if (script == LVDS_RESET && ((dev->pci_device & 0xffff) == 0x0179 || (dev->pci_device & 0xffff) == 0x0329))
- nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72);
- if ((dev->pci_device & 0xffff) == 0x0179 || (dev->pci_device & 0xffff) == 0x0189 || (dev->pci_device & 0xffff) == 0x0329) {
- if (script == LVDS_PANEL_ON) {
- bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) | (1 << 31));
- bios_wr32(bios, NV_PCRTC_GPIO_EXT, bios_rd32(bios, NV_PCRTC_GPIO_EXT) | 1);
- }
- if (script == LVDS_PANEL_OFF) {
- bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) & ~(1 << 31));
- bios_wr32(bios, NV_PCRTC_GPIO_EXT, bios_rd32(bios, NV_PCRTC_GPIO_EXT) & ~3);
+ if ((dev->pci_device & 0xffff) == 0x0179 ||
+ (dev->pci_device & 0xffff) == 0x0189 ||
+ (dev->pci_device & 0xffff) == 0x0329) {
+ if (script == LVDS_RESET) {
+ nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72);
+
+ } else if (script == LVDS_PANEL_ON) {
+ bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL,
+ bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL)
+ | (1 << 31));
+ bios_wr32(bios, NV_PCRTC_GPIO_EXT,
+ bios_rd32(bios, NV_PCRTC_GPIO_EXT) | 1);
+
+ } else if (script == LVDS_PANEL_OFF) {
+ bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL,
+ bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL)
+ & ~(1 << 31));
+ bios_wr32(bios, NV_PCRTC_GPIO_EXT,
+ bios_rd32(bios, NV_PCRTC_GPIO_EXT) & ~3);
}
}
#endif
@@ -3226,7 +3195,7 @@ static int run_lvds_table(struct drm_device *dev, struct dcb_entry *dcbent, int
* of a list of pxclks and script pointers.
*/
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
unsigned int outputset = (dcbent->or == 4) ? 1 : 0;
uint16_t scriptptr = 0, clktable;
uint8_t clktableptr = 0;
@@ -3293,7 +3262,7 @@ int call_lvds_script(struct drm_device *dev, struct dcb_entry *dcbent, int head,
*/
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
uint8_t lvds_ver = bios->data[bios->fp.lvdsmanufacturerpointer];
uint32_t sel_clk_binding, sel_clk;
int ret;
@@ -3427,7 +3396,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
#ifndef __powerpc__
NV_ERROR(dev, "Pointer to flat panel table invalid\n");
#endif
- bios->pub.digital_min_front_porch = 0x4b;
+ bios->digital_min_front_porch = 0x4b;
return 0;
}
@@ -3460,7 +3429,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
* fptable[4] is the minimum
* RAMDAC_FP_HCRTC -> RAMDAC_FP_HSYNC_START gap
*/
- bios->pub.digital_min_front_porch = fptable[4];
+ bios->digital_min_front_porch = fptable[4];
ofs = -7;
break;
default:
@@ -3499,7 +3468,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
/* nv4x cards need both a strap value and fpindex of 0xf to use DDC */
if (lth.lvds_ver > 0x10)
- bios->pub.fp_no_ddc = fpstrapping != 0xf || fpindex != 0xf;
+ bios->fp_no_ddc = fpstrapping != 0xf || fpindex != 0xf;
/*
* If either the strap or xlated fpindex value are 0xf there is no
@@ -3523,7 +3492,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
bool nouveau_bios_fp_mode(struct drm_device *dev, struct drm_display_mode *mode)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
uint8_t *mode_entry = &bios->data[bios->fp.mode_ptr];
if (!mode) /* just checking whether we can produce a mode */
@@ -3576,7 +3545,7 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b
* at which modes should be set up in the dual link style.
*
* Following the header, the BMP (ver 0xa) table has several records,
- * indexed by a seperate xlat table, indexed in turn by the fp strap in
+ * indexed by a separate xlat table, indexed in turn by the fp strap in
* EXTDEV_BOOT. Each record had a config byte, followed by 6 script
* numbers for use by INIT_SUB which controlled panel init and power,
* and finally a dword of ms to sleep between power off and on
@@ -3594,11 +3563,11 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b
* until later, when this function should be called with non-zero pxclk
*/
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
int fpstrapping = get_fp_strap(dev, bios), lvdsmanufacturerindex = 0;
struct lvdstableheader lth;
uint16_t lvdsofs;
- int ret, chip_version = bios->pub.chip_version;
+ int ret, chip_version = bios->chip_version;
ret = parse_lvds_manufacturer_table_header(dev, bios, &lth);
if (ret)
@@ -3714,7 +3683,7 @@ bios_output_config_match(struct drm_device *dev, struct dcb_entry *dcbent,
uint16_t record, int record_len, int record_nr)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
uint32_t entry;
uint16_t table;
int i, v;
@@ -3748,7 +3717,7 @@ nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent,
int *length)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
uint8_t *table;
if (!bios->display.dp_table_ptr) {
@@ -3757,7 +3726,7 @@ nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent,
}
table = &bios->data[bios->display.dp_table_ptr];
- if (table[0] != 0x21) {
+ if (table[0] != 0x20 && table[0] != 0x21) {
NV_ERROR(dev, "DisplayPort table version 0x%02x unknown\n",
table[0]);
return NULL;
@@ -3797,8 +3766,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
*/
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct init_exec iexec = {true, false};
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
uint8_t *table = &bios->data[bios->display.script_table_ptr];
uint8_t *otable = NULL;
uint16_t script;
@@ -3877,8 +3845,6 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
}
}
- bios->display.output = dcbent;
-
if (pxclk == 0) {
script = ROM16(otable[6]);
if (!script) {
@@ -3887,7 +3853,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
}
NV_TRACE(dev, "0x%04X: parsing output script 0\n", script);
- parse_init_table(bios, script, &iexec);
+ nouveau_bios_run_init_table(dev, script, dcbent);
} else
if (pxclk == -1) {
script = ROM16(otable[8]);
@@ -3897,7 +3863,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
}
NV_TRACE(dev, "0x%04X: parsing output script 1\n", script);
- parse_init_table(bios, script, &iexec);
+ nouveau_bios_run_init_table(dev, script, dcbent);
} else
if (pxclk == -2) {
if (table[4] >= 12)
@@ -3910,7 +3876,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
}
NV_TRACE(dev, "0x%04X: parsing output script 2\n", script);
- parse_init_table(bios, script, &iexec);
+ nouveau_bios_run_init_table(dev, script, dcbent);
} else
if (pxclk > 0) {
script = ROM16(otable[table[4] + i*6 + 2]);
@@ -3922,7 +3888,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
}
NV_TRACE(dev, "0x%04X: parsing clock script 0\n", script);
- parse_init_table(bios, script, &iexec);
+ nouveau_bios_run_init_table(dev, script, dcbent);
} else
if (pxclk < 0) {
script = ROM16(otable[table[4] + i*6 + 4]);
@@ -3934,7 +3900,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
}
NV_TRACE(dev, "0x%04X: parsing clock script 1\n", script);
- parse_init_table(bios, script, &iexec);
+ nouveau_bios_run_init_table(dev, script, dcbent);
}
return 0;
@@ -3953,8 +3919,8 @@ int run_tmds_table(struct drm_device *dev, struct dcb_entry *dcbent, int head, i
*/
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
- int cv = bios->pub.chip_version;
+ struct nvbios *bios = &dev_priv->vbios;
+ int cv = bios->chip_version;
uint16_t clktable = 0, scriptptr;
uint32_t sel_clk_binding, sel_clk;
@@ -4013,8 +3979,8 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
*/
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
- int cv = bios->pub.chip_version, pllindex = 0;
+ struct nvbios *bios = &dev_priv->vbios;
+ int cv = bios->chip_version, pllindex = 0;
uint8_t pll_lim_ver = 0, headerlen = 0, recordlen = 0, entries = 0;
uint32_t crystal_strap_mask, crystal_straps;
@@ -4367,7 +4333,7 @@ static void parse_bios_version(struct drm_device *dev, struct nvbios *bios, uint
*/
bios->major_version = bios->data[offset + 3];
- bios->pub.chip_version = bios->data[offset + 2];
+ bios->chip_version = bios->data[offset + 2];
NV_TRACE(dev, "Bios version %02x.%02x.%02x.%02x\n",
bios->data[offset + 3], bios->data[offset + 2],
bios->data[offset + 1], bios->data[offset]);
@@ -4437,7 +4403,7 @@ static int parse_bit_A_tbl_entry(struct drm_device *dev, struct nvbios *bios, st
}
/* First entry is normal dac, 2nd tv-out perhaps? */
- bios->pub.dactestval = ROM32(bios->data[load_table_ptr + headerlen]) & 0x3ff;
+ bios->dactestval = ROM32(bios->data[load_table_ptr + headerlen]) & 0x3ff;
return 0;
}
@@ -4561,8 +4527,8 @@ static int parse_bit_i_tbl_entry(struct drm_device *dev, struct nvbios *bios, st
return -ENOSYS;
}
- bios->pub.dactestval = ROM32(bios->data[daccmpoffset + dacheaderlen]);
- bios->pub.tvdactestval = ROM32(bios->data[daccmpoffset + dacheaderlen + 4]);
+ bios->dactestval = ROM32(bios->data[daccmpoffset + dacheaderlen]);
+ bios->tvdactestval = ROM32(bios->data[daccmpoffset + dacheaderlen + 4]);
return 0;
}
@@ -4831,11 +4797,11 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
uint16_t legacy_scripts_offset, legacy_i2c_offset;
/* load needed defaults in case we can't parse this info */
- bios->bdcb.dcb.i2c[0].write = NV_CIO_CRE_DDC_WR__INDEX;
- bios->bdcb.dcb.i2c[0].read = NV_CIO_CRE_DDC_STATUS__INDEX;
- bios->bdcb.dcb.i2c[1].write = NV_CIO_CRE_DDC0_WR__INDEX;
- bios->bdcb.dcb.i2c[1].read = NV_CIO_CRE_DDC0_STATUS__INDEX;
- bios->pub.digital_min_front_porch = 0x4b;
+ bios->dcb.i2c[0].write = NV_CIO_CRE_DDC_WR__INDEX;
+ bios->dcb.i2c[0].read = NV_CIO_CRE_DDC_STATUS__INDEX;
+ bios->dcb.i2c[1].write = NV_CIO_CRE_DDC0_WR__INDEX;
+ bios->dcb.i2c[1].read = NV_CIO_CRE_DDC0_STATUS__INDEX;
+ bios->digital_min_front_porch = 0x4b;
bios->fmaxvco = 256000;
bios->fminvco = 128000;
bios->fp.duallink_transition_clk = 90000;
@@ -4942,10 +4908,10 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
bios->legacy.i2c_indices.crt = bios->data[legacy_i2c_offset];
bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1];
bios->legacy.i2c_indices.panel = bios->data[legacy_i2c_offset + 2];
- bios->bdcb.dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4];
- bios->bdcb.dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5];
- bios->bdcb.dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6];
- bios->bdcb.dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7];
+ bios->dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4];
+ bios->dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5];
+ bios->dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6];
+ bios->dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7];
if (bmplength > 74) {
bios->fmaxvco = ROM32(bmp[67]);
@@ -5019,7 +4985,8 @@ read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, i
else
NV_WARN(dev,
"DCB I2C table has more entries than indexable "
- "(%d entries, max index 15)\n", i2ctable[2]);
+ "(%d entries, max %d)\n", i2ctable[2],
+ DCB_MAX_NUM_I2C_ENTRIES);
entry_len = i2ctable[3];
/* [4] is i2c_default_indices, read in parse_dcb_table() */
}
@@ -5035,8 +5002,8 @@ read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, i
if (index == 0xf)
return 0;
- if (index > i2c_entries) {
- NV_ERROR(dev, "DCB I2C index too big (%d > %d)\n",
+ if (index >= i2c_entries) {
+ NV_ERROR(dev, "DCB I2C index too big (%d >= %d)\n",
index, i2ctable[2]);
return -ENOENT;
}
@@ -5071,7 +5038,7 @@ read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, i
static struct dcb_gpio_entry *
new_gpio_entry(struct nvbios *bios)
{
- struct parsed_dcb_gpio *gpio = &bios->bdcb.gpio;
+ struct dcb_gpio_table *gpio = &bios->dcb.gpio;
return &gpio->entry[gpio->entries++];
}
@@ -5080,14 +5047,14 @@ struct dcb_gpio_entry *
nouveau_bios_gpio_entry(struct drm_device *dev, enum dcb_gpio_tag tag)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
int i;
- for (i = 0; i < bios->bdcb.gpio.entries; i++) {
- if (bios->bdcb.gpio.entry[i].tag != tag)
+ for (i = 0; i < bios->dcb.gpio.entries; i++) {
+ if (bios->dcb.gpio.entry[i].tag != tag)
continue;
- return &bios->bdcb.gpio.entry[i];
+ return &bios->dcb.gpio.entry[i];
}
return NULL;
@@ -5135,7 +5102,7 @@ static void
parse_dcb_gpio_table(struct nvbios *bios)
{
struct drm_device *dev = bios->dev;
- uint16_t gpio_table_ptr = bios->bdcb.gpio_table_ptr;
+ uint16_t gpio_table_ptr = bios->dcb.gpio_table_ptr;
uint8_t *gpio_table = &bios->data[gpio_table_ptr];
int header_len = gpio_table[1],
entries = gpio_table[2],
@@ -5143,7 +5110,7 @@ parse_dcb_gpio_table(struct nvbios *bios)
void (*parse_entry)(struct nvbios *, uint16_t) = NULL;
int i;
- if (bios->bdcb.version >= 0x40) {
+ if (bios->dcb.version >= 0x40) {
if (gpio_table_ptr && entry_len != 4) {
NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
return;
@@ -5151,7 +5118,7 @@ parse_dcb_gpio_table(struct nvbios *bios)
parse_entry = parse_dcb40_gpio_entry;
- } else if (bios->bdcb.version >= 0x30) {
+ } else if (bios->dcb.version >= 0x30) {
if (gpio_table_ptr && entry_len != 2) {
NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
return;
@@ -5159,7 +5126,7 @@ parse_dcb_gpio_table(struct nvbios *bios)
parse_entry = parse_dcb30_gpio_entry;
- } else if (bios->bdcb.version >= 0x22) {
+ } else if (bios->dcb.version >= 0x22) {
/*
* DCBs older than v3.0 don't really have a GPIO
* table, instead they keep some GPIO info at fixed
@@ -5193,30 +5160,67 @@ struct dcb_connector_table_entry *
nouveau_bios_connector_entry(struct drm_device *dev, int index)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
struct dcb_connector_table_entry *cte;
- if (index >= bios->bdcb.connector.entries)
+ if (index >= bios->dcb.connector.entries)
return NULL;
- cte = &bios->bdcb.connector.entry[index];
+ cte = &bios->dcb.connector.entry[index];
if (cte->type == 0xff)
return NULL;
return cte;
}
+static enum dcb_connector_type
+divine_connector_type(struct nvbios *bios, int index)
+{
+ struct dcb_table *dcb = &bios->dcb;
+ unsigned encoders = 0, type = DCB_CONNECTOR_NONE;
+ int i;
+
+ for (i = 0; i < dcb->entries; i++) {
+ if (dcb->entry[i].connector == index)
+ encoders |= (1 << dcb->entry[i].type);
+ }
+
+ if (encoders & (1 << OUTPUT_DP)) {
+ if (encoders & (1 << OUTPUT_TMDS))
+ type = DCB_CONNECTOR_DP;
+ else
+ type = DCB_CONNECTOR_eDP;
+ } else
+ if (encoders & (1 << OUTPUT_TMDS)) {
+ if (encoders & (1 << OUTPUT_ANALOG))
+ type = DCB_CONNECTOR_DVI_I;
+ else
+ type = DCB_CONNECTOR_DVI_D;
+ } else
+ if (encoders & (1 << OUTPUT_ANALOG)) {
+ type = DCB_CONNECTOR_VGA;
+ } else
+ if (encoders & (1 << OUTPUT_LVDS)) {
+ type = DCB_CONNECTOR_LVDS;
+ } else
+ if (encoders & (1 << OUTPUT_TV)) {
+ type = DCB_CONNECTOR_TV_0;
+ }
+
+ return type;
+}
+
static void
parse_dcb_connector_table(struct nvbios *bios)
{
struct drm_device *dev = bios->dev;
- struct dcb_connector_table *ct = &bios->bdcb.connector;
+ struct dcb_connector_table *ct = &bios->dcb.connector;
struct dcb_connector_table_entry *cte;
- uint8_t *conntab = &bios->data[bios->bdcb.connector_table_ptr];
+ uint8_t *conntab = &bios->data[bios->dcb.connector_table_ptr];
uint8_t *entry;
int i;
- if (!bios->bdcb.connector_table_ptr) {
+ if (!bios->dcb.connector_table_ptr) {
NV_DEBUG_KMS(dev, "No DCB connector table present\n");
return;
}
@@ -5238,6 +5242,7 @@ parse_dcb_connector_table(struct nvbios *bios)
cte->entry = ROM16(entry[0]);
else
cte->entry = ROM32(entry[0]);
+
cte->type = (cte->entry & 0x000000ff) >> 0;
cte->index = (cte->entry & 0x00000f00) >> 8;
switch (cte->entry & 0x00033000) {
@@ -5263,10 +5268,33 @@ parse_dcb_connector_table(struct nvbios *bios)
NV_INFO(dev, " %d: 0x%08x: type 0x%02x idx %d tag 0x%02x\n",
i, cte->entry, cte->type, cte->index, cte->gpio_tag);
+
+ /* check for known types, fallback to guessing the type
+ * from attached encoders if we hit an unknown.
+ */
+ switch (cte->type) {
+ case DCB_CONNECTOR_VGA:
+ case DCB_CONNECTOR_TV_0:
+ case DCB_CONNECTOR_TV_1:
+ case DCB_CONNECTOR_TV_3:
+ case DCB_CONNECTOR_DVI_I:
+ case DCB_CONNECTOR_DVI_D:
+ case DCB_CONNECTOR_LVDS:
+ case DCB_CONNECTOR_DP:
+ case DCB_CONNECTOR_eDP:
+ case DCB_CONNECTOR_HDMI_0:
+ case DCB_CONNECTOR_HDMI_1:
+ break;
+ default:
+ cte->type = divine_connector_type(bios, cte->index);
+ NV_WARN(dev, "unknown type, using 0x%02x", cte->type);
+ break;
+ }
+
}
}
-static struct dcb_entry *new_dcb_entry(struct parsed_dcb *dcb)
+static struct dcb_entry *new_dcb_entry(struct dcb_table *dcb)
{
struct dcb_entry *entry = &dcb->entry[dcb->entries];
@@ -5276,7 +5304,7 @@ static struct dcb_entry *new_dcb_entry(struct parsed_dcb *dcb)
return entry;
}
-static void fabricate_vga_output(struct parsed_dcb *dcb, int i2c, int heads)
+static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads)
{
struct dcb_entry *entry = new_dcb_entry(dcb);
@@ -5287,7 +5315,7 @@ static void fabricate_vga_output(struct parsed_dcb *dcb, int i2c, int heads)
/* "or" mostly unused in early gen crt modesetting, 0 is fine */
}
-static void fabricate_dvi_i_output(struct parsed_dcb *dcb, bool twoHeads)
+static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads)
{
struct dcb_entry *entry = new_dcb_entry(dcb);
@@ -5314,7 +5342,7 @@ static void fabricate_dvi_i_output(struct parsed_dcb *dcb, bool twoHeads)
#endif
}
-static void fabricate_tv_output(struct parsed_dcb *dcb, bool twoHeads)
+static void fabricate_tv_output(struct dcb_table *dcb, bool twoHeads)
{
struct dcb_entry *entry = new_dcb_entry(dcb);
@@ -5325,13 +5353,13 @@ static void fabricate_tv_output(struct parsed_dcb *dcb, bool twoHeads)
}
static bool
-parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
uint32_t conn, uint32_t conf, struct dcb_entry *entry)
{
entry->type = conn & 0xf;
entry->i2c_index = (conn >> 4) & 0xf;
entry->heads = (conn >> 8) & 0xf;
- if (bdcb->version >= 0x40)
+ if (dcb->version >= 0x40)
entry->connector = (conn >> 12) & 0xf;
entry->bus = (conn >> 16) & 0xf;
entry->location = (conn >> 20) & 0x3;
@@ -5349,7 +5377,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
* Although the rest of a CRT conf dword is usually
* zeros, mac biosen have stuff there so we must mask
*/
- entry->crtconf.maxfreq = (bdcb->version < 0x30) ?
+ entry->crtconf.maxfreq = (dcb->version < 0x30) ?
(conf & 0xffff) * 10 :
(conf & 0xff) * 10000;
break;
@@ -5358,7 +5386,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
uint32_t mask;
if (conf & 0x1)
entry->lvdsconf.use_straps_for_mode = true;
- if (bdcb->version < 0x22) {
+ if (dcb->version < 0x22) {
mask = ~0xd;
/*
* The laptop in bug 14567 lies and claims to not use
@@ -5382,7 +5410,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
* Until we even try to use these on G8x, it's
* useless reporting unknown bits. They all are.
*/
- if (bdcb->version >= 0x40)
+ if (dcb->version >= 0x40)
break;
NV_ERROR(dev, "Unknown LVDS configuration bits, "
@@ -5392,7 +5420,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
}
case OUTPUT_TV:
{
- if (bdcb->version >= 0x30)
+ if (dcb->version >= 0x30)
entry->tvconf.has_component_output = conf & (0x8 << 4);
else
entry->tvconf.has_component_output = false;
@@ -5419,8 +5447,10 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
break;
case 0xe:
/* weird g80 mobile type that "nv" treats as a terminator */
- bdcb->dcb.entries--;
+ dcb->entries--;
return false;
+ default:
+ break;
}
/* unsure what DCB version introduces this, 3.0? */
@@ -5431,55 +5461,52 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
}
static bool
-parse_dcb15_entry(struct drm_device *dev, struct parsed_dcb *dcb,
+parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb,
uint32_t conn, uint32_t conf, struct dcb_entry *entry)
{
- if (conn != 0xf0003f00 && conn != 0xf2247f10 && conn != 0xf2204001 &&
- conn != 0xf2204301 && conn != 0xf2204311 && conn != 0xf2208001 &&
- conn != 0xf2244001 && conn != 0xf2244301 && conn != 0xf2244311 &&
- conn != 0xf4204011 && conn != 0xf4208011 && conn != 0xf4248011 &&
- conn != 0xf2045ff2 && conn != 0xf2045f14 && conn != 0xf207df14 &&
- conn != 0xf2205004 && conn != 0xf2209004) {
- NV_ERROR(dev, "Unknown DCB 1.5 entry, please report\n");
-
- /* cause output setting to fail for !TV, so message is seen */
- if ((conn & 0xf) != 0x1)
- dcb->entries = 0;
-
- return false;
- }
- /* most of the below is a "best guess" atm */
- entry->type = conn & 0xf;
- if (entry->type == 2)
- /* another way of specifying straps based lvds... */
+ switch (conn & 0x0000000f) {
+ case 0:
+ entry->type = OUTPUT_ANALOG;
+ break;
+ case 1:
+ entry->type = OUTPUT_TV;
+ break;
+ case 2:
+ case 3:
entry->type = OUTPUT_LVDS;
- if (entry->type == 4) { /* digital */
- if (conn & 0x10)
- entry->type = OUTPUT_LVDS;
- else
+ break;
+ case 4:
+ switch ((conn & 0x000000f0) >> 4) {
+ case 0:
entry->type = OUTPUT_TMDS;
+ break;
+ case 1:
+ entry->type = OUTPUT_LVDS;
+ break;
+ default:
+ NV_ERROR(dev, "Unknown DCB subtype 4/%d\n",
+ (conn & 0x000000f0) >> 4);
+ return false;
+ }
+ break;
+ default:
+ NV_ERROR(dev, "Unknown DCB type %d\n", conn & 0x0000000f);
+ return false;
}
- /* what's in bits 5-13? could be some encoder maker thing, in tv case */
- entry->i2c_index = (conn >> 14) & 0xf;
- /* raw heads field is in range 0-1, so move to 1-2 */
- entry->heads = ((conn >> 18) & 0x7) + 1;
- entry->location = (conn >> 21) & 0xf;
- /* unused: entry->bus = (conn >> 25) & 0x7; */
- /* set or to be same as heads -- hopefully safe enough */
- entry->or = entry->heads;
+
+ entry->i2c_index = (conn & 0x0003c000) >> 14;
+ entry->heads = ((conn & 0x001c0000) >> 18) + 1;
+ entry->or = entry->heads; /* same as heads, hopefully safe enough */
+ entry->location = (conn & 0x01e00000) >> 21;
+ entry->bus = (conn & 0x0e000000) >> 25;
entry->duallink_possible = false;
switch (entry->type) {
case OUTPUT_ANALOG:
entry->crtconf.maxfreq = (conf & 0xffff) * 10;
break;
- case OUTPUT_LVDS:
- /*
- * This is probably buried in conn's unknown bits.
- * This will upset EDID-ful models, if they exist
- */
- entry->lvdsconf.use_straps_for_mode = true;
- entry->lvdsconf.use_power_scripts = true;
+ case OUTPUT_TV:
+ entry->tvconf.has_component_output = false;
break;
case OUTPUT_TMDS:
/*
@@ -5488,35 +5515,39 @@ parse_dcb15_entry(struct drm_device *dev, struct parsed_dcb *dcb,
*/
fabricate_vga_output(dcb, entry->i2c_index, entry->heads);
break;
- case OUTPUT_TV:
- entry->tvconf.has_component_output = false;
+ case OUTPUT_LVDS:
+ if ((conn & 0x00003f00) != 0x10)
+ entry->lvdsconf.use_straps_for_mode = true;
+ entry->lvdsconf.use_power_scripts = true;
+ break;
+ default:
break;
}
return true;
}
-static bool parse_dcb_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+static bool parse_dcb_entry(struct drm_device *dev, struct dcb_table *dcb,
uint32_t conn, uint32_t conf)
{
- struct dcb_entry *entry = new_dcb_entry(&bdcb->dcb);
+ struct dcb_entry *entry = new_dcb_entry(dcb);
bool ret;
- if (bdcb->version >= 0x20)
- ret = parse_dcb20_entry(dev, bdcb, conn, conf, entry);
+ if (dcb->version >= 0x20)
+ ret = parse_dcb20_entry(dev, dcb, conn, conf, entry);
else
- ret = parse_dcb15_entry(dev, &bdcb->dcb, conn, conf, entry);
+ ret = parse_dcb15_entry(dev, dcb, conn, conf, entry);
if (!ret)
return ret;
- read_dcb_i2c_entry(dev, bdcb->version, bdcb->i2c_table,
- entry->i2c_index, &bdcb->dcb.i2c[entry->i2c_index]);
+ read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
+ entry->i2c_index, &dcb->i2c[entry->i2c_index]);
return true;
}
static
-void merge_like_dcb_entries(struct drm_device *dev, struct parsed_dcb *dcb)
+void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb)
{
/*
* DCB v2.0 lists each output combination separately.
@@ -5564,31 +5595,31 @@ void merge_like_dcb_entries(struct drm_device *dev, struct parsed_dcb *dcb)
dcb->entries = newentries;
}
-static int parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+static int
+parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
{
- struct bios_parsed_dcb *bdcb = &bios->bdcb;
- struct parsed_dcb *dcb;
- uint16_t dcbptr, i2ctabptr = 0;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct dcb_table *dcb = &bios->dcb;
+ uint16_t dcbptr = 0, i2ctabptr = 0;
uint8_t *dcbtable;
uint8_t headerlen = 0x4, entries = DCB_MAX_NUM_ENTRIES;
bool configblock = true;
int recordlength = 8, confofs = 4;
int i;
- dcb = bios->pub.dcb = &bdcb->dcb;
- dcb->entries = 0;
-
/* get the offset from 0x36 */
- dcbptr = ROM16(bios->data[0x36]);
+ if (dev_priv->card_type > NV_04) {
+ dcbptr = ROM16(bios->data[0x36]);
+ if (dcbptr == 0x0000)
+ NV_WARN(dev, "No output data (DCB) found in BIOS\n");
+ }
+ /* this situation likely means a really old card, pre DCB */
if (dcbptr == 0x0) {
- NV_WARN(dev, "No output data (DCB) found in BIOS, "
- "assuming a CRT output exists\n");
- /* this situation likely means a really old card, pre DCB */
+ NV_INFO(dev, "Assuming a CRT output exists\n");
fabricate_vga_output(dcb, LEGACY_I2C_CRT, 1);
- if (nv04_tv_identify(dev,
- bios->legacy.i2c_indices.tv) >= 0)
+ if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0)
fabricate_tv_output(dcb, twoHeads);
return 0;
@@ -5597,21 +5628,21 @@ static int parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool two
dcbtable = &bios->data[dcbptr];
/* get DCB version */
- bdcb->version = dcbtable[0];
+ dcb->version = dcbtable[0];
NV_TRACE(dev, "Found Display Configuration Block version %d.%d\n",
- bdcb->version >> 4, bdcb->version & 0xf);
+ dcb->version >> 4, dcb->version & 0xf);
- if (bdcb->version >= 0x20) { /* NV17+ */
+ if (dcb->version >= 0x20) { /* NV17+ */
uint32_t sig;
- if (bdcb->version >= 0x30) { /* NV40+ */
+ if (dcb->version >= 0x30) { /* NV40+ */
headerlen = dcbtable[1];
entries = dcbtable[2];
recordlength = dcbtable[3];
i2ctabptr = ROM16(dcbtable[4]);
sig = ROM32(dcbtable[6]);
- bdcb->gpio_table_ptr = ROM16(dcbtable[10]);
- bdcb->connector_table_ptr = ROM16(dcbtable[20]);
+ dcb->gpio_table_ptr = ROM16(dcbtable[10]);
+ dcb->connector_table_ptr = ROM16(dcbtable[20]);
} else {
i2ctabptr = ROM16(dcbtable[2]);
sig = ROM32(dcbtable[4]);
@@ -5623,7 +5654,7 @@ static int parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool two
"signature (%08X)\n", sig);
return -EINVAL;
}
- } else if (bdcb->version >= 0x15) { /* some NV11 and NV20 */
+ } else if (dcb->version >= 0x15) { /* some NV11 and NV20 */
char sig[8] = { 0 };
strncpy(sig, (char *)&dcbtable[-7], 7);
@@ -5671,14 +5702,11 @@ static int parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool two
if (!i2ctabptr)
NV_WARN(dev, "No pointer to DCB I2C port table\n");
else {
- bdcb->i2c_table = &bios->data[i2ctabptr];
- if (bdcb->version >= 0x30)
- bdcb->i2c_default_indices = bdcb->i2c_table[4];
+ dcb->i2c_table = &bios->data[i2ctabptr];
+ if (dcb->version >= 0x30)
+ dcb->i2c_default_indices = dcb->i2c_table[4];
}
- parse_dcb_gpio_table(bios);
- parse_dcb_connector_table(bios);
-
if (entries > DCB_MAX_NUM_ENTRIES)
entries = DCB_MAX_NUM_ENTRIES;
@@ -5703,7 +5731,7 @@ static int parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool two
NV_TRACEWARN(dev, "Raw DCB entry %d: %08x %08x\n",
dcb->entries, connection, config);
- if (!parse_dcb_entry(dev, bdcb, connection, config))
+ if (!parse_dcb_entry(dev, dcb, connection, config))
break;
}
@@ -5711,18 +5739,22 @@ static int parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool two
* apart for v2.1+ not being known for requiring merging, this
* guarantees dcbent->index is the index of the entry in the rom image
*/
- if (bdcb->version < 0x21)
+ if (dcb->version < 0x21)
merge_like_dcb_entries(dev, dcb);
- return dcb->entries ? 0 : -ENXIO;
+ if (!dcb->entries)
+ return -ENXIO;
+
+ parse_dcb_gpio_table(bios);
+ parse_dcb_connector_table(bios);
+ return 0;
}
static void
fixup_legacy_connector(struct nvbios *bios)
{
- struct bios_parsed_dcb *bdcb = &bios->bdcb;
- struct parsed_dcb *dcb = &bdcb->dcb;
- int high = 0, i;
+ struct dcb_table *dcb = &bios->dcb;
+ int i, i2c, i2c_conn[DCB_MAX_NUM_I2C_ENTRIES] = { };
/*
* DCB 3.0 also has the table in most cases, but there are some cards
@@ -5730,9 +5762,11 @@ fixup_legacy_connector(struct nvbios *bios)
* indices are all 0. We don't need the connector indices on pre-G80
* chips (yet?) so limit the use to DCB 4.0 and above.
*/
- if (bdcb->version >= 0x40)
+ if (dcb->version >= 0x40)
return;
+ dcb->connector.entries = 0;
+
/*
* No known connector info before v3.0, so make it up. the rule here
* is: anything on the same i2c bus is considered to be on the same
@@ -5740,37 +5774,38 @@ fixup_legacy_connector(struct nvbios *bios)
* its own unique connector index.
*/
for (i = 0; i < dcb->entries; i++) {
- if (dcb->entry[i].i2c_index == 0xf)
- continue;
-
/*
* Ignore the I2C index for on-chip TV-out, as there
* are cards with bogus values (nv31m in bug 23212),
* and it's otherwise useless.
*/
if (dcb->entry[i].type == OUTPUT_TV &&
- dcb->entry[i].location == DCB_LOC_ON_CHIP) {
+ dcb->entry[i].location == DCB_LOC_ON_CHIP)
dcb->entry[i].i2c_index = 0xf;
+ i2c = dcb->entry[i].i2c_index;
+
+ if (i2c_conn[i2c]) {
+ dcb->entry[i].connector = i2c_conn[i2c] - 1;
continue;
}
- dcb->entry[i].connector = dcb->entry[i].i2c_index;
- if (dcb->entry[i].connector > high)
- high = dcb->entry[i].connector;
+ dcb->entry[i].connector = dcb->connector.entries++;
+ if (i2c != 0xf)
+ i2c_conn[i2c] = dcb->connector.entries;
}
- for (i = 0; i < dcb->entries; i++) {
- if (dcb->entry[i].i2c_index != 0xf)
- continue;
-
- dcb->entry[i].connector = ++high;
+ /* Fake the connector table as well as just connector indices */
+ for (i = 0; i < dcb->connector.entries; i++) {
+ dcb->connector.entry[i].index = i;
+ dcb->connector.entry[i].type = divine_connector_type(bios, i);
+ dcb->connector.entry[i].gpio_tag = 0xff;
}
}
static void
fixup_legacy_i2c(struct nvbios *bios)
{
- struct parsed_dcb *dcb = &bios->bdcb.dcb;
+ struct dcb_table *dcb = &bios->dcb;
int i;
for (i = 0; i < dcb->entries; i++) {
@@ -5856,7 +5891,7 @@ static int load_nv17_hw_sequencer_ucode(struct drm_device *dev,
uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
const uint8_t edid_sig[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
uint16_t offset = 0;
@@ -5889,20 +5924,23 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
struct dcb_entry *dcbent)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
struct init_exec iexec = { true, false };
+ mutex_lock(&bios->lock);
bios->display.output = dcbent;
parse_init_table(bios, table, &iexec);
bios->display.output = NULL;
+ mutex_unlock(&bios->lock);
}
static bool NVInitVBIOS(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
memset(bios, 0, sizeof(struct nvbios));
+ mutex_init(&bios->lock);
bios->dev = dev;
if (!NVShadowVBIOS(dev, bios->data))
@@ -5915,7 +5953,7 @@ static bool NVInitVBIOS(struct drm_device *dev)
static int nouveau_parse_vbios_struct(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
const uint8_t bit_signature[] = { 0xff, 0xb8, 'B', 'I', 'T' };
const uint8_t bmp_signature[] = { 0xff, 0x7f, 'N', 'V', 0x0 };
int offset;
@@ -5942,7 +5980,7 @@ int
nouveau_run_vbios_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
int i, ret = 0;
NVLockVgaCrtcs(dev, false);
@@ -5973,9 +6011,9 @@ nouveau_run_vbios_init(struct drm_device *dev)
}
if (dev_priv->card_type >= NV_50) {
- for (i = 0; i < bios->bdcb.dcb.entries; i++) {
+ for (i = 0; i < bios->dcb.entries; i++) {
nouveau_bios_run_display_table(dev,
- &bios->bdcb.dcb.entry[i],
+ &bios->dcb.entry[i],
0, 0);
}
}
@@ -5989,11 +6027,11 @@ static void
nouveau_bios_i2c_devices_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
struct dcb_i2c_entry *entry;
int i;
- entry = &bios->bdcb.dcb.i2c[0];
+ entry = &bios->dcb.i2c[0];
for (i = 0; i < DCB_MAX_NUM_I2C_ENTRIES; i++, entry++)
nouveau_i2c_fini(dev, entry);
}
@@ -6002,13 +6040,11 @@ int
nouveau_bios_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
uint32_t saved_nv_pextdev_boot_0;
bool was_locked;
int ret;
- dev_priv->vbios = &bios->pub;
-
if (!NVInitVBIOS(dev))
return -ENODEV;
@@ -6050,10 +6086,8 @@ nouveau_bios_init(struct drm_device *dev)
bios_wr32(bios, NV_PEXTDEV_BOOT_0, saved_nv_pextdev_boot_0);
ret = nouveau_run_vbios_init(dev);
- if (ret) {
- dev_priv->vbios = NULL;
+ if (ret)
return ret;
- }
/* feature_byte on BMP is poor, but init always sets CR4B */
was_locked = NVLockVgaCrtcs(dev, false);
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index 058e98c76d89..9f688aa9a655 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -34,9 +34,67 @@
#define DCB_LOC_ON_CHIP 0
+struct dcb_i2c_entry {
+ uint8_t port_type;
+ uint8_t read, write;
+ struct nouveau_i2c_chan *chan;
+};
+
+enum dcb_gpio_tag {
+ DCB_GPIO_TVDAC0 = 0xc,
+ DCB_GPIO_TVDAC1 = 0x2d,
+};
+
+struct dcb_gpio_entry {
+ enum dcb_gpio_tag tag;
+ int line;
+ bool invert;
+};
+
+struct dcb_gpio_table {
+ int entries;
+ struct dcb_gpio_entry entry[DCB_MAX_NUM_GPIO_ENTRIES];
+};
+
+enum dcb_connector_type {
+ DCB_CONNECTOR_VGA = 0x00,
+ DCB_CONNECTOR_TV_0 = 0x10,
+ DCB_CONNECTOR_TV_1 = 0x11,
+ DCB_CONNECTOR_TV_3 = 0x13,
+ DCB_CONNECTOR_DVI_I = 0x30,
+ DCB_CONNECTOR_DVI_D = 0x31,
+ DCB_CONNECTOR_LVDS = 0x40,
+ DCB_CONNECTOR_DP = 0x46,
+ DCB_CONNECTOR_eDP = 0x47,
+ DCB_CONNECTOR_HDMI_0 = 0x60,
+ DCB_CONNECTOR_HDMI_1 = 0x61,
+ DCB_CONNECTOR_NONE = 0xff
+};
+
+struct dcb_connector_table_entry {
+ uint32_t entry;
+ enum dcb_connector_type type;
+ uint8_t index;
+ uint8_t gpio_tag;
+};
+
+struct dcb_connector_table {
+ int entries;
+ struct dcb_connector_table_entry entry[DCB_MAX_NUM_CONNECTOR_ENTRIES];
+};
+
+enum dcb_type {
+ OUTPUT_ANALOG = 0,
+ OUTPUT_TV = 1,
+ OUTPUT_TMDS = 2,
+ OUTPUT_LVDS = 3,
+ OUTPUT_DP = 6,
+ OUTPUT_ANY = -1
+};
+
struct dcb_entry {
int index; /* may not be raw dcb index if merging has happened */
- uint8_t type;
+ enum dcb_type type;
uint8_t i2c_index;
uint8_t heads;
uint8_t connector;
@@ -71,69 +129,22 @@ struct dcb_entry {
bool i2c_upper_default;
};
-struct dcb_i2c_entry {
- uint8_t port_type;
- uint8_t read, write;
- struct nouveau_i2c_chan *chan;
-};
+struct dcb_table {
+ uint8_t version;
-struct parsed_dcb {
int entries;
struct dcb_entry entry[DCB_MAX_NUM_ENTRIES];
- struct dcb_i2c_entry i2c[DCB_MAX_NUM_I2C_ENTRIES];
-};
-
-enum dcb_gpio_tag {
- DCB_GPIO_TVDAC0 = 0xc,
- DCB_GPIO_TVDAC1 = 0x2d,
-};
-
-struct dcb_gpio_entry {
- enum dcb_gpio_tag tag;
- int line;
- bool invert;
-};
-
-struct parsed_dcb_gpio {
- int entries;
- struct dcb_gpio_entry entry[DCB_MAX_NUM_GPIO_ENTRIES];
-};
-
-struct dcb_connector_table_entry {
- uint32_t entry;
- uint8_t type;
- uint8_t index;
- uint8_t gpio_tag;
-};
-
-struct dcb_connector_table {
- int entries;
- struct dcb_connector_table_entry entry[DCB_MAX_NUM_CONNECTOR_ENTRIES];
-};
-
-struct bios_parsed_dcb {
- uint8_t version;
-
- struct parsed_dcb dcb;
uint8_t *i2c_table;
uint8_t i2c_default_indices;
+ struct dcb_i2c_entry i2c[DCB_MAX_NUM_I2C_ENTRIES];
uint16_t gpio_table_ptr;
- struct parsed_dcb_gpio gpio;
+ struct dcb_gpio_table gpio;
uint16_t connector_table_ptr;
struct dcb_connector_table connector;
};
-enum nouveau_encoder_type {
- OUTPUT_ANALOG = 0,
- OUTPUT_TV = 1,
- OUTPUT_TMDS = 2,
- OUTPUT_LVDS = 3,
- OUTPUT_DP = 6,
- OUTPUT_ANY = -1
-};
-
enum nouveau_or {
OUTPUT_A = (1 << 0),
OUTPUT_B = (1 << 1),
@@ -190,8 +201,8 @@ struct pll_lims {
int refclk;
};
-struct nouveau_bios_info {
- struct parsed_dcb *dcb;
+struct nvbios {
+ struct drm_device *dev;
uint8_t chip_version;
@@ -199,11 +210,8 @@ struct nouveau_bios_info {
uint32_t tvdactestval;
uint8_t digital_min_front_porch;
bool fp_no_ddc;
-};
-struct nvbios {
- struct drm_device *dev;
- struct nouveau_bios_info pub;
+ struct mutex lock;
uint8_t data[NV_PROM_SIZE];
unsigned int length;
@@ -232,7 +240,7 @@ struct nvbios {
uint16_t some_script_ptr; /* BIT I + 14 */
uint16_t init96_tbl_ptr; /* BIT I + 16 */
- struct bios_parsed_dcb bdcb;
+ struct dcb_table dcb;
struct {
int crtchead;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index e342a418d434..028719fddf76 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -65,8 +65,10 @@ nouveau_bo_fixup_align(struct drm_device *dev,
/*
* Some of the tile_flags have a periodic structure of N*4096 bytes,
- * align to to that as well as the page size. Overallocate memory to
- * avoid corruption of other buffer objects.
+ * align to to that as well as the page size. Align the size to the
+ * appropriate boundaries. This does imply that sizes are rounded up
+ * 3-7 pages, so be aware of this and do not waste memory by allocating
+ * many small buffers.
*/
if (dev_priv->card_type == NV_50) {
uint32_t block_size = nouveau_mem_fb_amount(dev) >> 15;
@@ -77,22 +79,20 @@ nouveau_bo_fixup_align(struct drm_device *dev,
case 0x2800:
case 0x4800:
case 0x7a00:
- *size = roundup(*size, block_size);
if (is_power_of_2(block_size)) {
- *size += 3 * block_size;
for (i = 1; i < 10; i++) {
*align = 12 * i * block_size;
if (!(*align % 65536))
break;
}
} else {
- *size += 6 * block_size;
for (i = 1; i < 10; i++) {
*align = 8 * i * block_size;
if (!(*align % 65536))
break;
}
}
+ *size = roundup(*size, *align);
break;
default:
break;
@@ -469,6 +469,8 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan,
ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL,
evict, no_wait, new_mem);
+ if (nvbo->channel && nvbo->channel != chan)
+ ret = nouveau_fence_wait(fence, NULL, false, false);
nouveau_fence_unref((void *)&fence);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_calc.c b/drivers/gpu/drm/nouveau/nouveau_calc.c
index ee2b84504d05..88f9bc0941eb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_calc.c
+++ b/drivers/gpu/drm/nouveau/nouveau_calc.c
@@ -274,7 +274,7 @@ getMNP_single(struct drm_device *dev, struct pll_lims *pll_lim, int clk,
* returns calculated clock
*/
struct drm_nouveau_private *dev_priv = dev->dev_private;
- int cv = dev_priv->vbios->chip_version;
+ int cv = dev_priv->vbios.chip_version;
int minvco = pll_lim->vco1.minfreq, maxvco = pll_lim->vco1.maxfreq;
int minM = pll_lim->vco1.min_m, maxM = pll_lim->vco1.max_m;
int minN = pll_lim->vco1.min_n, maxN = pll_lim->vco1.max_n;
@@ -373,7 +373,7 @@ getMNP_double(struct drm_device *dev, struct pll_lims *pll_lim, int clk,
* returns calculated clock
*/
struct drm_nouveau_private *dev_priv = dev->dev_private;
- int chip_version = dev_priv->vbios->chip_version;
+ int chip_version = dev_priv->vbios.chip_version;
int minvco1 = pll_lim->vco1.minfreq, maxvco1 = pll_lim->vco1.maxfreq;
int minvco2 = pll_lim->vco2.minfreq, maxvco2 = pll_lim->vco2.maxfreq;
int minU1 = pll_lim->vco1.min_inputfreq, minU2 = pll_lim->vco2.min_inputfreq;
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index 343d718a9667..6dfb425cbae9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -35,22 +35,27 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_bo *pb = chan->pushbuf_bo;
struct nouveau_gpuobj *pushbuf = NULL;
- uint32_t start = pb->bo.mem.mm_node->start << PAGE_SHIFT;
int ret;
+ if (dev_priv->card_type >= NV_50) {
+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
+ dev_priv->vm_end, NV_DMA_ACCESS_RO,
+ NV_DMA_TARGET_AGP, &pushbuf);
+ chan->pushbuf_base = pb->bo.offset;
+ } else
if (pb->bo.mem.mem_type == TTM_PL_TT) {
ret = nouveau_gpuobj_gart_dma_new(chan, 0,
dev_priv->gart_info.aper_size,
NV_DMA_ACCESS_RO, &pushbuf,
NULL);
- chan->pushbuf_base = start;
+ chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
} else
if (dev_priv->card_type != NV_04) {
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
dev_priv->fb_available_size,
NV_DMA_ACCESS_RO,
NV_DMA_TARGET_VIDMEM, &pushbuf);
- chan->pushbuf_base = start;
+ chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
} else {
/* NV04 cmdbuf hack, from original ddx.. not sure of it's
* exact reason for existing :) PCI access to cmdbuf in
@@ -61,7 +66,7 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
dev_priv->fb_available_size,
NV_DMA_ACCESS_RO,
NV_DMA_TARGET_PCI, &pushbuf);
- chan->pushbuf_base = start;
+ chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
}
ret = nouveau_gpuobj_ref_add(dev, chan, 0, pushbuf, &chan->pushbuf);
@@ -275,15 +280,23 @@ nouveau_channel_free(struct nouveau_channel *chan)
*/
nouveau_fence_fini(chan);
- /* Ensure the channel is no longer active on the GPU */
+ /* This will prevent pfifo from switching channels. */
pfifo->reassign(dev, false);
- if (pgraph->channel(dev) == chan) {
- pgraph->fifo_access(dev, false);
+ /* We want to give pgraph a chance to idle and get rid of all potential
+ * errors. We need to do this before the lock, otherwise the irq handler
+ * is unable to process them.
+ */
+ if (pgraph->channel(dev) == chan)
+ nouveau_wait_for_idle(dev);
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+
+ pgraph->fifo_access(dev, false);
+ if (pgraph->channel(dev) == chan)
pgraph->unload_context(dev);
- pgraph->fifo_access(dev, true);
- }
pgraph->destroy_context(chan);
+ pgraph->fifo_access(dev, true);
if (pfifo->channel_id(dev) == chan->id) {
pfifo->disable(dev);
@@ -294,6 +307,8 @@ nouveau_channel_free(struct nouveau_channel *chan)
pfifo->reassign(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
/* Release the channel's resources */
nouveau_gpuobj_ref_del(dev, &chan->pushbuf);
if (chan->pushbuf_bo) {
@@ -370,6 +385,14 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
return ret;
init->channel = chan->id;
+ if (chan->dma.ib_max)
+ init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
+ NOUVEAU_GEM_DOMAIN_GART;
+ else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM)
+ init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
+ else
+ init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
+
init->subchan[0].handle = NvM2MF;
if (dev_priv->card_type < NV_50)
init->subchan[0].grclass = 0x0039;
@@ -409,7 +432,6 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data,
***********************************/
struct drm_ioctl_desc nouveau_ioctls[] = {
- DRM_IOCTL_DEF(DRM_NOUVEAU_CARD_INIT, nouveau_ioctl_card_init, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH),
@@ -419,13 +441,9 @@ struct drm_ioctl_desc nouveau_ioctls[] = {
DRM_IOCTL_DEF(DRM_NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_PUSHBUF_CALL, nouveau_gem_ioctl_pushbuf_call, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_PIN, nouveau_gem_ioctl_pin, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_UNPIN, nouveau_gem_ioctl_unpin, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_PUSHBUF_CALL2, nouveau_gem_ioctl_pushbuf_call2, DRM_AUTH),
};
int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls);
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 5a10deb8bdbd..24327f468c4b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -24,9 +24,12 @@
*
*/
+#include <acpi/button.h>
+
#include "drmP.h"
#include "drm_edid.h"
#include "drm_crtc_helper.h"
+
#include "nouveau_reg.h"
#include "nouveau_drv.h"
#include "nouveau_encoder.h"
@@ -83,14 +86,17 @@ nouveau_encoder_connector_get(struct nouveau_encoder *encoder)
static void
nouveau_connector_destroy(struct drm_connector *drm_connector)
{
- struct nouveau_connector *connector = nouveau_connector(drm_connector);
- struct drm_device *dev = connector->base.dev;
-
- NV_DEBUG_KMS(dev, "\n");
+ struct nouveau_connector *nv_connector =
+ nouveau_connector(drm_connector);
+ struct drm_device *dev;
- if (!connector)
+ if (!nv_connector)
return;
+ dev = nv_connector->base.dev;
+ NV_DEBUG_KMS(dev, "\n");
+
+ kfree(nv_connector->edid);
drm_sysfs_connector_remove(drm_connector);
drm_connector_cleanup(drm_connector);
kfree(drm_connector);
@@ -212,7 +218,7 @@ nouveau_connector_set_encoder(struct drm_connector *connector,
connector->interlace_allowed = true;
}
- if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) {
+ if (nv_connector->dcb->type == DCB_CONNECTOR_DVI_I) {
drm_connector_property_set_value(connector,
dev->mode_config.dvi_i_subconnector_property,
nv_encoder->dcb->type == OUTPUT_TMDS ?
@@ -230,11 +236,24 @@ nouveau_connector_detect(struct drm_connector *connector)
struct nouveau_i2c_chan *i2c;
int type, flags;
- if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
+ if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS)
nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS);
if (nv_encoder && nv_connector->native_mode) {
+ unsigned status = connector_status_connected;
+
+#ifdef CONFIG_ACPI
+ if (!nouveau_ignorelid && !acpi_lid_open())
+ status = connector_status_unknown;
+#endif
nouveau_connector_set_encoder(connector, nv_encoder);
- return connector_status_connected;
+ return status;
+ }
+
+ /* Cleanup the previous EDID block. */
+ if (nv_connector->edid) {
+ drm_mode_connector_update_edid_property(connector, NULL);
+ kfree(nv_connector->edid);
+ nv_connector->edid = NULL;
}
i2c = nouveau_connector_ddc_detect(connector, &nv_encoder);
@@ -247,7 +266,7 @@ nouveau_connector_detect(struct drm_connector *connector)
if (!nv_connector->edid) {
NV_ERROR(dev, "DDC responded, but no EDID for %s\n",
drm_get_connector_name(connector));
- return connector_status_disconnected;
+ goto detect_analog;
}
if (nv_encoder->dcb->type == OUTPUT_DP &&
@@ -262,7 +281,7 @@ nouveau_connector_detect(struct drm_connector *connector)
* same i2c channel so the value returned from ddc_detect
* isn't necessarily correct.
*/
- if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) {
+ if (nv_connector->dcb->type == DCB_CONNECTOR_DVI_I) {
if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL)
type = OUTPUT_TMDS;
else
@@ -281,6 +300,7 @@ nouveau_connector_detect(struct drm_connector *connector)
return connector_status_connected;
}
+detect_analog:
nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG);
if (!nv_encoder)
nv_encoder = find_encoder_by_type(connector, OUTPUT_TV);
@@ -303,11 +323,11 @@ nouveau_connector_detect(struct drm_connector *connector)
static void
nouveau_connector_force(struct drm_connector *connector)
{
- struct drm_device *dev = connector->dev;
+ struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder;
int type;
- if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) {
+ if (nv_connector->dcb->type == DCB_CONNECTOR_DVI_I) {
if (connector->force == DRM_FORCE_ON_DIGITAL)
type = OUTPUT_TMDS;
else
@@ -317,7 +337,7 @@ nouveau_connector_force(struct drm_connector *connector)
nv_encoder = find_encoder_by_type(connector, type);
if (!nv_encoder) {
- NV_ERROR(dev, "can't find encoder to force %s on!\n",
+ NV_ERROR(connector->dev, "can't find encoder to force %s on!\n",
drm_get_connector_name(connector));
connector->status = connector_status_disconnected;
return;
@@ -351,7 +371,7 @@ nouveau_connector_set_property(struct drm_connector *connector,
}
/* LVDS always needs gpu scaling */
- if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
+ if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS &&
value == DRM_MODE_SCALE_NONE)
return -EINVAL;
@@ -517,7 +537,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
/* If we're not LVDS, destroy the previous native mode, the attached
* monitor could have changed.
*/
- if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
+ if (nv_connector->dcb->type != DCB_CONNECTOR_LVDS &&
nv_connector->native_mode) {
drm_mode_destroy(dev, nv_connector->native_mode);
nv_connector->native_mode = NULL;
@@ -545,7 +565,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
ret = get_slave_funcs(nv_encoder)->
get_modes(to_drm_encoder(nv_encoder), connector);
- if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
+ if (nv_encoder->dcb->type == OUTPUT_LVDS)
ret += nouveau_connector_scaler_modes_add(connector);
return ret;
@@ -595,6 +615,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
clock *= 3;
break;
+ default:
+ BUG_ON(1);
+ return MODE_BAD;
}
if (clock < min_clock)
@@ -662,7 +685,7 @@ nouveau_connector_create_lvds(struct drm_device *dev,
/* Firstly try getting EDID over DDC, if allowed and I2C channel
* is available.
*/
- if (!dev_priv->VBIOS.pub.fp_no_ddc && nv_encoder->dcb->i2c_index < 0xf)
+ if (!dev_priv->vbios.fp_no_ddc && nv_encoder->dcb->i2c_index < 0xf)
i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
if (i2c) {
@@ -677,7 +700,7 @@ nouveau_connector_create_lvds(struct drm_device *dev,
*/
if (!nv_connector->edid && nouveau_bios_fp_mode(dev, &native) &&
(nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
- dev_priv->VBIOS.pub.fp_no_ddc)) {
+ dev_priv->vbios.fp_no_ddc)) {
nv_connector->native_mode = drm_mode_duplicate(dev, &native);
goto out;
}
@@ -686,9 +709,13 @@ nouveau_connector_create_lvds(struct drm_device *dev,
* stored for the panel stored in them.
*/
if (!nv_connector->edid && !nv_connector->native_mode &&
- !dev_priv->VBIOS.pub.fp_no_ddc) {
- nv_connector->edid =
+ !dev_priv->vbios.fp_no_ddc) {
+ struct edid *edid =
(struct edid *)nouveau_bios_embedded_edid(dev);
+ if (edid) {
+ nv_connector->edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
+ *(nv_connector->edid) = *edid;
+ }
}
if (!nv_connector->edid)
@@ -717,46 +744,66 @@ out:
}
int
-nouveau_connector_create(struct drm_device *dev, int index, int type)
+nouveau_connector_create(struct drm_device *dev,
+ struct dcb_connector_table_entry *dcb)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = NULL;
struct drm_connector *connector;
struct drm_encoder *encoder;
- int ret;
+ int ret, type;
NV_DEBUG_KMS(dev, "\n");
- nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
- if (!nv_connector)
- return -ENOMEM;
- nv_connector->dcb = nouveau_bios_connector_entry(dev, index);
- connector = &nv_connector->base;
-
- switch (type) {
- case DRM_MODE_CONNECTOR_VGA:
+ switch (dcb->type) {
+ case DCB_CONNECTOR_NONE:
+ return 0;
+ case DCB_CONNECTOR_VGA:
NV_INFO(dev, "Detected a VGA connector\n");
+ type = DRM_MODE_CONNECTOR_VGA;
break;
- case DRM_MODE_CONNECTOR_DVID:
- NV_INFO(dev, "Detected a DVI-D connector\n");
+ case DCB_CONNECTOR_TV_0:
+ case DCB_CONNECTOR_TV_1:
+ case DCB_CONNECTOR_TV_3:
+ NV_INFO(dev, "Detected a TV connector\n");
+ type = DRM_MODE_CONNECTOR_TV;
break;
- case DRM_MODE_CONNECTOR_DVII:
+ case DCB_CONNECTOR_DVI_I:
NV_INFO(dev, "Detected a DVI-I connector\n");
+ type = DRM_MODE_CONNECTOR_DVII;
break;
- case DRM_MODE_CONNECTOR_LVDS:
- NV_INFO(dev, "Detected a LVDS connector\n");
+ case DCB_CONNECTOR_DVI_D:
+ NV_INFO(dev, "Detected a DVI-D connector\n");
+ type = DRM_MODE_CONNECTOR_DVID;
break;
- case DRM_MODE_CONNECTOR_TV:
- NV_INFO(dev, "Detected a TV connector\n");
+ case DCB_CONNECTOR_HDMI_0:
+ case DCB_CONNECTOR_HDMI_1:
+ NV_INFO(dev, "Detected a HDMI connector\n");
+ type = DRM_MODE_CONNECTOR_HDMIA;
break;
- case DRM_MODE_CONNECTOR_DisplayPort:
+ case DCB_CONNECTOR_LVDS:
+ NV_INFO(dev, "Detected a LVDS connector\n");
+ type = DRM_MODE_CONNECTOR_LVDS;
+ break;
+ case DCB_CONNECTOR_DP:
NV_INFO(dev, "Detected a DisplayPort connector\n");
+ type = DRM_MODE_CONNECTOR_DisplayPort;
break;
- default:
- NV_ERROR(dev, "Unknown connector, this is not good.\n");
+ case DCB_CONNECTOR_eDP:
+ NV_INFO(dev, "Detected an eDP connector\n");
+ type = DRM_MODE_CONNECTOR_eDP;
break;
+ default:
+ NV_ERROR(dev, "unknown connector type: 0x%02x!!\n", dcb->type);
+ return -EINVAL;
}
+ nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
+ if (!nv_connector)
+ return -ENOMEM;
+ nv_connector->dcb = dcb;
+ connector = &nv_connector->base;
+
/* defaults, will get overridden in detect() */
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
@@ -764,55 +811,65 @@ nouveau_connector_create(struct drm_device *dev, int index, int type)
drm_connector_init(dev, connector, &nouveau_connector_funcs, type);
drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
+ /* attach encoders */
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+
+ if (nv_encoder->dcb->connector != dcb->index)
+ continue;
+
+ if (get_slave_funcs(nv_encoder))
+ get_slave_funcs(nv_encoder)->create_resources(encoder, connector);
+
+ drm_mode_connector_attach_encoder(connector, encoder);
+ }
+
+ if (!connector->encoder_ids[0]) {
+ NV_WARN(dev, " no encoders, ignoring\n");
+ drm_connector_cleanup(connector);
+ kfree(connector);
+ return 0;
+ }
+
/* Init DVI-I specific properties */
- if (type == DRM_MODE_CONNECTOR_DVII) {
+ if (dcb->type == DCB_CONNECTOR_DVI_I) {
drm_mode_create_dvi_i_properties(dev);
drm_connector_attach_property(connector, dev->mode_config.dvi_i_subconnector_property, 0);
drm_connector_attach_property(connector, dev->mode_config.dvi_i_select_subconnector_property, 0);
}
- if (type != DRM_MODE_CONNECTOR_LVDS)
+ if (dcb->type != DCB_CONNECTOR_LVDS)
nv_connector->use_dithering = false;
- if (type == DRM_MODE_CONNECTOR_DVID ||
- type == DRM_MODE_CONNECTOR_DVII ||
- type == DRM_MODE_CONNECTOR_LVDS ||
- type == DRM_MODE_CONNECTOR_DisplayPort) {
- nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
-
- drm_connector_attach_property(connector, dev->mode_config.scaling_mode_property,
- nv_connector->scaling_mode);
- drm_connector_attach_property(connector, dev->mode_config.dithering_mode_property,
- nv_connector->use_dithering ? DRM_MODE_DITHERING_ON
- : DRM_MODE_DITHERING_OFF);
-
- } else {
- nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
-
- if (type == DRM_MODE_CONNECTOR_VGA &&
- dev_priv->card_type >= NV_50) {
+ switch (dcb->type) {
+ case DCB_CONNECTOR_VGA:
+ if (dev_priv->card_type >= NV_50) {
drm_connector_attach_property(connector,
dev->mode_config.scaling_mode_property,
nv_connector->scaling_mode);
}
- }
-
- /* attach encoders */
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-
- if (nv_encoder->dcb->connector != index)
- continue;
-
- if (get_slave_funcs(nv_encoder))
- get_slave_funcs(nv_encoder)->create_resources(encoder, connector);
+ /* fall-through */
+ case DCB_CONNECTOR_TV_0:
+ case DCB_CONNECTOR_TV_1:
+ case DCB_CONNECTOR_TV_3:
+ nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
+ break;
+ default:
+ nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
- drm_mode_connector_attach_encoder(connector, encoder);
+ drm_connector_attach_property(connector,
+ dev->mode_config.scaling_mode_property,
+ nv_connector->scaling_mode);
+ drm_connector_attach_property(connector,
+ dev->mode_config.dithering_mode_property,
+ nv_connector->use_dithering ?
+ DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
+ break;
}
drm_sysfs_connector_add(connector);
- if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+ if (dcb->type == DCB_CONNECTOR_LVDS) {
ret = nouveau_connector_create_lvds(dev, connector);
if (ret) {
connector->funcs->destroy(connector);
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index 728b8090e5ff..4ef38abc2d9c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -49,6 +49,7 @@ static inline struct nouveau_connector *nouveau_connector(
return container_of(con, struct nouveau_connector, base);
}
-int nouveau_connector_create(struct drm_device *dev, int i2c_index, int type);
+int nouveau_connector_create(struct drm_device *,
+ struct dcb_connector_table_entry *);
#endif /* __NOUVEAU_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
index d79db3698f16..8ff9ef5d4b47 100644
--- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c
+++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
@@ -47,12 +47,23 @@ nouveau_debugfs_channel_info(struct seq_file *m, void *data)
seq_printf(m, " cur: 0x%08x\n", chan->dma.cur << 2);
seq_printf(m, " put: 0x%08x\n", chan->dma.put << 2);
seq_printf(m, " free: 0x%08x\n", chan->dma.free << 2);
+ if (chan->dma.ib_max) {
+ seq_printf(m, " ib max: 0x%08x\n", chan->dma.ib_max);
+ seq_printf(m, " ib put: 0x%08x\n", chan->dma.ib_put);
+ seq_printf(m, " ib free: 0x%08x\n", chan->dma.ib_free);
+ }
seq_printf(m, "gpu fifo state:\n");
seq_printf(m, " get: 0x%08x\n",
nvchan_rd32(chan, chan->user_get));
seq_printf(m, " put: 0x%08x\n",
nvchan_rd32(chan, chan->user_put));
+ if (chan->dma.ib_max) {
+ seq_printf(m, " ib get: 0x%08x\n",
+ nvchan_rd32(chan, 0x88));
+ seq_printf(m, " ib put: 0x%08x\n",
+ nvchan_rd32(chan, 0x8c));
+ }
seq_printf(m, "last fence : %d\n", chan->fence.sequence);
seq_printf(m, "last signalled: %d\n", chan->fence.sequence_ack);
@@ -133,9 +144,22 @@ nouveau_debugfs_memory_info(struct seq_file *m, void *data)
return 0;
}
+static int
+nouveau_debugfs_vbios_image(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_nouveau_private *dev_priv = node->minor->dev->dev_private;
+ int i;
+
+ for (i = 0; i < dev_priv->vbios.length; i++)
+ seq_printf(m, "%c", dev_priv->vbios.data[i]);
+ return 0;
+}
+
static struct drm_info_list nouveau_debugfs_list[] = {
{ "chipset", nouveau_debugfs_chipset_info, 0, NULL },
{ "memory", nouveau_debugfs_memory_info, 0, NULL },
+ { "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL },
};
#define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index dfc94391d71e..cf1c5c0a0abe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -39,11 +39,8 @@ nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
if (drm_fb->fbdev)
nouveau_fbcon_remove(dev, drm_fb);
- if (fb->nvbo) {
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(fb->nvbo->gem);
- mutex_unlock(&dev->struct_mutex);
- }
+ if (fb->nvbo)
+ drm_gem_object_unreference_unlocked(fb->nvbo->gem);
drm_framebuffer_cleanup(drm_fb);
kfree(fb);
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
index 7afbe8b40d51..c8482a108a78 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
@@ -32,7 +32,22 @@
void
nouveau_dma_pre_init(struct nouveau_channel *chan)
{
- chan->dma.max = (chan->pushbuf_bo->bo.mem.size >> 2) - 2;
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct nouveau_bo *pushbuf = chan->pushbuf_bo;
+
+ if (dev_priv->card_type == NV_50) {
+ const int ib_size = pushbuf->bo.mem.size / 2;
+
+ chan->dma.ib_base = (pushbuf->bo.mem.size - ib_size) >> 2;
+ chan->dma.ib_max = (ib_size / 8) - 1;
+ chan->dma.ib_put = 0;
+ chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
+
+ chan->dma.max = (pushbuf->bo.mem.size - ib_size) >> 2;
+ } else {
+ chan->dma.max = (pushbuf->bo.mem.size >> 2) - 2;
+ }
+
chan->dma.put = 0;
chan->dma.cur = chan->dma.put;
chan->dma.free = chan->dma.max - chan->dma.cur;
@@ -126,37 +141,66 @@ OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords)
chan->dma.cur += nr_dwords;
}
-static inline bool
-READ_GET(struct nouveau_channel *chan, uint32_t *get)
+/* Fetch and adjust GPU GET pointer
+ *
+ * Returns:
+ * value >= 0, the adjusted GET pointer
+ * -EINVAL if GET pointer currently outside main push buffer
+ * -EBUSY if timeout exceeded
+ */
+static inline int
+READ_GET(struct nouveau_channel *chan, uint32_t *prev_get, uint32_t *timeout)
{
uint32_t val;
val = nvchan_rd32(chan, chan->user_get);
- if (val < chan->pushbuf_base ||
- val > chan->pushbuf_base + (chan->dma.max << 2)) {
- /* meaningless to dma_wait() except to know whether the
- * GPU has stalled or not
- */
- *get = val;
- return false;
+
+ /* reset counter as long as GET is still advancing, this is
+ * to avoid misdetecting a GPU lockup if the GPU happens to
+ * just be processing an operation that takes a long time
+ */
+ if (val != *prev_get) {
+ *prev_get = val;
+ *timeout = 0;
}
- *get = (val - chan->pushbuf_base) >> 2;
- return true;
+ if ((++*timeout & 0xff) == 0) {
+ DRM_UDELAY(1);
+ if (*timeout > 100000)
+ return -EBUSY;
+ }
+
+ if (val < chan->pushbuf_base ||
+ val > chan->pushbuf_base + (chan->dma.max << 2))
+ return -EINVAL;
+
+ return (val - chan->pushbuf_base) >> 2;
}
-int
-nouveau_dma_wait(struct nouveau_channel *chan, int size)
+void
+nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo,
+ int delta, int length)
{
- uint32_t get, prev_get = 0, cnt = 0;
- bool get_valid;
+ struct nouveau_bo *pb = chan->pushbuf_bo;
+ uint64_t offset = bo->bo.offset + delta;
+ int ip = (chan->dma.ib_put * 2) + chan->dma.ib_base;
- while (chan->dma.free < size) {
- /* reset counter as long as GET is still advancing, this is
- * to avoid misdetecting a GPU lockup if the GPU happens to
- * just be processing an operation that takes a long time
- */
- get_valid = READ_GET(chan, &get);
+ BUG_ON(chan->dma.ib_free < 1);
+ nouveau_bo_wr32(pb, ip++, lower_32_bits(offset));
+ nouveau_bo_wr32(pb, ip++, upper_32_bits(offset) | length << 8);
+
+ chan->dma.ib_put = (chan->dma.ib_put + 1) & chan->dma.ib_max;
+ nvchan_wr32(chan, 0x8c, chan->dma.ib_put);
+ chan->dma.ib_free--;
+}
+
+static int
+nv50_dma_push_wait(struct nouveau_channel *chan, int count)
+{
+ uint32_t cnt = 0, prev_get = 0;
+
+ while (chan->dma.ib_free < count) {
+ uint32_t get = nvchan_rd32(chan, 0x88);
if (get != prev_get) {
prev_get = get;
cnt = 0;
@@ -168,6 +212,71 @@ nouveau_dma_wait(struct nouveau_channel *chan, int size)
return -EBUSY;
}
+ chan->dma.ib_free = get - chan->dma.ib_put;
+ if (chan->dma.ib_free <= 0)
+ chan->dma.ib_free += chan->dma.ib_max + 1;
+ }
+
+ return 0;
+}
+
+static int
+nv50_dma_wait(struct nouveau_channel *chan, int slots, int count)
+{
+ uint32_t cnt = 0, prev_get = 0;
+ int ret;
+
+ ret = nv50_dma_push_wait(chan, slots + 1);
+ if (unlikely(ret))
+ return ret;
+
+ while (chan->dma.free < count) {
+ int get = READ_GET(chan, &prev_get, &cnt);
+ if (unlikely(get < 0)) {
+ if (get == -EINVAL)
+ continue;
+
+ return get;
+ }
+
+ if (get <= chan->dma.cur) {
+ chan->dma.free = chan->dma.max - chan->dma.cur;
+ if (chan->dma.free >= count)
+ break;
+
+ FIRE_RING(chan);
+ do {
+ get = READ_GET(chan, &prev_get, &cnt);
+ if (unlikely(get < 0)) {
+ if (get == -EINVAL)
+ continue;
+ return get;
+ }
+ } while (get == 0);
+ chan->dma.cur = 0;
+ chan->dma.put = 0;
+ }
+
+ chan->dma.free = get - chan->dma.cur - 1;
+ }
+
+ return 0;
+}
+
+int
+nouveau_dma_wait(struct nouveau_channel *chan, int slots, int size)
+{
+ uint32_t prev_get = 0, cnt = 0;
+ int get;
+
+ if (chan->dma.ib_max)
+ return nv50_dma_wait(chan, slots, size);
+
+ while (chan->dma.free < size) {
+ get = READ_GET(chan, &prev_get, &cnt);
+ if (unlikely(get == -EBUSY))
+ return -EBUSY;
+
/* loop until we have a usable GET pointer. the value
* we read from the GPU may be outside the main ring if
* PFIFO is processing a buffer called from the main ring,
@@ -177,7 +286,7 @@ nouveau_dma_wait(struct nouveau_channel *chan, int size)
* from the SKIPS area, so the code below doesn't have to deal
* with some fun corner cases.
*/
- if (!get_valid || get < NOUVEAU_DMA_SKIPS)
+ if (unlikely(get == -EINVAL) || get < NOUVEAU_DMA_SKIPS)
continue;
if (get <= chan->dma.cur) {
@@ -203,6 +312,19 @@ nouveau_dma_wait(struct nouveau_channel *chan, int size)
* after processing the currently pending commands.
*/
OUT_RING(chan, chan->pushbuf_base | 0x20000000);
+
+ /* wait for GET to depart from the skips area.
+ * prevents writing GET==PUT and causing a race
+ * condition that causes us to think the GPU is
+ * idle when it's not.
+ */
+ do {
+ get = READ_GET(chan, &prev_get, &cnt);
+ if (unlikely(get == -EBUSY))
+ return -EBUSY;
+ if (unlikely(get == -EINVAL))
+ continue;
+ } while (get <= NOUVEAU_DMA_SKIPS);
WRITE_PUT(NOUVEAU_DMA_SKIPS);
/* we're now submitting commands at the start of
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h
index dabfd655f93e..8b05c15866d5 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.h
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.h
@@ -31,6 +31,9 @@
#define NOUVEAU_DMA_DEBUG 0
#endif
+void nv50_dma_push(struct nouveau_channel *, struct nouveau_bo *,
+ int delta, int length);
+
/*
* There's a hw race condition where you can't jump to your PUT offset,
* to avoid this we jump to offset + SKIPS and fill the difference with
@@ -96,13 +99,11 @@ enum {
static __must_check inline int
RING_SPACE(struct nouveau_channel *chan, int size)
{
- if (chan->dma.free < size) {
- int ret;
+ int ret;
- ret = nouveau_dma_wait(chan, size);
- if (ret)
- return ret;
- }
+ ret = nouveau_dma_wait(chan, 1, size);
+ if (ret)
+ return ret;
chan->dma.free -= size;
return 0;
@@ -146,7 +147,13 @@ FIRE_RING(struct nouveau_channel *chan)
return;
chan->accel_done = true;
- WRITE_PUT(chan->dma.cur);
+ if (chan->dma.ib_max) {
+ nv50_dma_push(chan, chan->pushbuf_bo, chan->dma.put << 2,
+ (chan->dma.cur - chan->dma.put) << 2);
+ } else {
+ WRITE_PUT(chan->dma.cur);
+ }
+
chan->dma.put = chan->dma.cur;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 9e2926c48579..f954ad93e81f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -490,7 +490,8 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
if (!nv_wait(NV50_AUXCH_CTRL(index), 0x00010000, 0x00000000)) {
NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n",
nv_rd32(dev, NV50_AUXCH_CTRL(index)));
- return -EBUSY;
+ ret = -EBUSY;
+ goto out;
}
udelay(400);
@@ -502,6 +503,11 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
}
if (cmd & 1) {
+ if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) {
+ ret = -EREMOTEIO;
+ goto out;
+ }
+
for (i = 0; i < 4; i++) {
data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i));
NV_DEBUG_KMS(dev, "rd %d: 0x%08x\n", i, data32[i]);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 06eb993e0883..30cc09e8a709 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -56,7 +56,7 @@ int nouveau_vram_pushbuf;
module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
MODULE_PARM_DESC(vram_notify, "Force DMA notifiers to be in VRAM");
-int nouveau_vram_notify;
+int nouveau_vram_notify = 1;
module_param_named(vram_notify, nouveau_vram_notify, int, 0400);
MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (>=GeForce 8)");
@@ -71,6 +71,18 @@ MODULE_PARM_DESC(uscript_tmds, "TMDS output script table ID (>=GeForce 8)");
int nouveau_uscript_tmds = -1;
module_param_named(uscript_tmds, nouveau_uscript_tmds, int, 0400);
+MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status");
+int nouveau_ignorelid = 0;
+module_param_named(ignorelid, nouveau_ignorelid, int, 0400);
+
+MODULE_PARM_DESC(noaccel, "Disable all acceleration");
+int nouveau_noaccel = 0;
+module_param_named(noaccel, nouveau_noaccel, int, 0400);
+
+MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration");
+int nouveau_nofbaccel = 0;
+module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
+
MODULE_PARM_DESC(tv_norm, "Default TV norm.\n"
"\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n"
"\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n"
@@ -123,7 +135,7 @@ nouveau_pci_remove(struct pci_dev *pdev)
drm_put_dev(dev);
}
-static int
+int
nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
{
struct drm_device *dev = pci_get_drvdata(pdev);
@@ -221,7 +233,7 @@ out_abort:
return ret;
}
-static int
+int
nouveau_pci_resume(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
@@ -390,8 +402,10 @@ static int __init nouveau_init(void)
nouveau_modeset = 1;
}
- if (nouveau_modeset == 1)
+ if (nouveau_modeset == 1) {
driver.driver_features |= DRIVER_MODESET;
+ nouveau_register_dsm_handler();
+ }
return drm_init(&driver);
}
@@ -399,6 +413,7 @@ static int __init nouveau_init(void)
static void __exit nouveau_exit(void)
{
drm_exit(&driver);
+ nouveau_unregister_dsm_handler();
}
module_init(nouveau_init);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 026419fe8791..4b9aaf2a8d0f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -34,7 +34,7 @@
#define DRIVER_MAJOR 0
#define DRIVER_MINOR 0
-#define DRIVER_PATCHLEVEL 15
+#define DRIVER_PATCHLEVEL 16
#define NOUVEAU_FAMILY 0x0000FFFF
#define NOUVEAU_FLAGS 0xFFFF0000
@@ -83,6 +83,7 @@ struct nouveau_bo {
struct drm_file *reserved_by;
struct list_head entry;
int pbbo_index;
+ bool validate_mapped;
struct nouveau_channel *channel;
@@ -239,6 +240,11 @@ struct nouveau_channel {
int cur;
int put;
/* access via pushbuf_bo */
+
+ int ib_base;
+ int ib_max;
+ int ib_free;
+ int ib_put;
} dma;
uint32_t sw_subchannel[8];
@@ -509,6 +515,8 @@ struct drm_nouveau_private {
void __iomem *ramin;
uint32_t ramin_size;
+ struct nouveau_bo *vga_ram;
+
struct workqueue_struct *wq;
struct work_struct irq_work;
@@ -531,6 +539,9 @@ struct drm_nouveau_private {
struct nouveau_engine engine;
struct nouveau_channel *channel;
+ /* For PFIFO and PGRAPH. */
+ spinlock_t context_switch_lock;
+
/* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
struct nouveau_gpuobj *ramht;
uint32_t ramin_rsvd_vram;
@@ -542,7 +553,7 @@ struct drm_nouveau_private {
uint32_t ramro_offset;
uint32_t ramro_size;
- /* base physical adresses */
+ /* base physical addresses */
uint64_t fb_phys;
uint64_t fb_available_size;
uint64_t fb_mappable_pages;
@@ -581,6 +592,7 @@ struct drm_nouveau_private {
uint64_t vm_end;
struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
int vm_vram_pt_nr;
+ uint64_t vram_sys_base;
/* the mtrr covering the FB */
int fb_mtrr;
@@ -593,8 +605,7 @@ struct drm_nouveau_private {
struct list_head gpuobj_list;
- struct nvbios VBIOS;
- struct nouveau_bios_info *vbios;
+ struct nvbios vbios;
struct nv04_mode_state mode_reg;
struct nv04_mode_state saved_reg;
@@ -611,7 +622,6 @@ struct drm_nouveau_private {
} susres;
struct backlight_device *backlight;
- bool acpi_dsm;
struct nouveau_channel *evo;
@@ -675,6 +685,12 @@ extern char *nouveau_tv_norm;
extern int nouveau_reg_debug;
extern char *nouveau_vbios;
extern int nouveau_ctxfw;
+extern int nouveau_ignorelid;
+extern int nouveau_nofbaccel;
+extern int nouveau_noaccel;
+
+extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state);
+extern int nouveau_pci_resume(struct pci_dev *pdev);
/* nouveau_state.c */
extern void nouveau_preclose(struct drm_device *dev, struct drm_file *);
@@ -690,12 +706,6 @@ extern bool nouveau_wait_until(struct drm_device *, uint64_t timeout,
uint32_t reg, uint32_t mask, uint32_t val);
extern bool nouveau_wait_for_idle(struct drm_device *);
extern int nouveau_card_init(struct drm_device *);
-extern int nouveau_ioctl_card_init(struct drm_device *, void *data,
- struct drm_file *);
-extern int nouveau_ioctl_suspend(struct drm_device *, void *data,
- struct drm_file *);
-extern int nouveau_ioctl_resume(struct drm_device *, void *data,
- struct drm_file *);
/* nouveau_mem.c */
extern int nouveau_mem_init_heap(struct mem_block **, uint64_t start,
@@ -839,21 +849,15 @@ nouveau_debugfs_channel_fini(struct nouveau_channel *chan)
/* nouveau_dma.c */
extern void nouveau_dma_pre_init(struct nouveau_channel *);
extern int nouveau_dma_init(struct nouveau_channel *);
-extern int nouveau_dma_wait(struct nouveau_channel *, int size);
+extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
/* nouveau_acpi.c */
-#ifdef CONFIG_ACPI
-extern int nouveau_hybrid_setup(struct drm_device *dev);
-extern bool nouveau_dsm_probe(struct drm_device *dev);
+#if defined(CONFIG_ACPI)
+void nouveau_register_dsm_handler(void);
+void nouveau_unregister_dsm_handler(void);
#else
-static inline int nouveau_hybrid_setup(struct drm_device *dev)
-{
- return 0;
-}
-static inline bool nouveau_dsm_probe(struct drm_device *dev)
-{
- return false;
-}
+static inline void nouveau_register_dsm_handler(void) {}
+static inline void nouveau_unregister_dsm_handler(void) {}
#endif
/* nouveau_backlight.c */
@@ -1021,6 +1025,7 @@ extern void nv50_graph_destroy_context(struct nouveau_channel *);
extern int nv50_graph_load_context(struct nouveau_channel *);
extern int nv50_graph_unload_context(struct drm_device *);
extern void nv50_graph_context_switch(struct drm_device *);
+extern int nv50_grctx_init(struct nouveau_grctx *);
/* nouveau_grctx.c */
extern int nouveau_grctx_prog_load(struct drm_device *);
@@ -1146,16 +1151,6 @@ extern int nouveau_gem_ioctl_new(struct drm_device *, void *,
struct drm_file *);
extern int nouveau_gem_ioctl_pushbuf(struct drm_device *, void *,
struct drm_file *);
-extern int nouveau_gem_ioctl_pushbuf_call(struct drm_device *, void *,
- struct drm_file *);
-extern int nouveau_gem_ioctl_pushbuf_call2(struct drm_device *, void *,
- struct drm_file *);
-extern int nouveau_gem_ioctl_pin(struct drm_device *, void *,
- struct drm_file *);
-extern int nouveau_gem_ioctl_unpin(struct drm_device *, void *,
- struct drm_file *);
-extern int nouveau_gem_ioctl_tile(struct drm_device *, void *,
- struct drm_file *);
extern int nouveau_gem_ioctl_cpu_prep(struct drm_device *, void *,
struct drm_file *);
extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 0b05c869e0e7..68cedd9194fe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -36,6 +36,7 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/screen_info.h>
+#include <linux/vga_switcheroo.h>
#include "drmP.h"
#include "drm.h"
@@ -107,6 +108,34 @@ static struct fb_ops nouveau_fbcon_ops = {
.fb_setcmap = drm_fb_helper_setcmap,
};
+static struct fb_ops nv04_fbcon_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = drm_fb_helper_check_var,
+ .fb_set_par = drm_fb_helper_set_par,
+ .fb_setcolreg = drm_fb_helper_setcolreg,
+ .fb_fillrect = nv04_fbcon_fillrect,
+ .fb_copyarea = nv04_fbcon_copyarea,
+ .fb_imageblit = nv04_fbcon_imageblit,
+ .fb_sync = nouveau_fbcon_sync,
+ .fb_pan_display = drm_fb_helper_pan_display,
+ .fb_blank = drm_fb_helper_blank,
+ .fb_setcmap = drm_fb_helper_setcmap,
+};
+
+static struct fb_ops nv50_fbcon_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = drm_fb_helper_check_var,
+ .fb_set_par = drm_fb_helper_set_par,
+ .fb_setcolreg = drm_fb_helper_setcolreg,
+ .fb_fillrect = nv50_fbcon_fillrect,
+ .fb_copyarea = nv50_fbcon_copyarea,
+ .fb_imageblit = nv50_fbcon_imageblit,
+ .fb_sync = nouveau_fbcon_sync,
+ .fb_pan_display = drm_fb_helper_pan_display,
+ .fb_blank = drm_fb_helper_blank,
+ .fb_setcmap = drm_fb_helper_setcmap,
+};
+
static void nouveau_fbcon_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno)
{
@@ -267,8 +296,12 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
dev_priv->fbdev_info = info;
strcpy(info->fix.id, "nouveaufb");
- info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
- FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_IMAGEBLIT;
+ if (nouveau_nofbaccel)
+ info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_DISABLED;
+ else
+ info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
+ FBINFO_HWACCEL_FILLRECT |
+ FBINFO_HWACCEL_IMAGEBLIT;
info->fbops = &nouveau_fbcon_ops;
info->fix.smem_start = dev->mode_config.fb_base + nvbo->bo.offset -
dev_priv->vm_vram_base;
@@ -316,13 +349,15 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
par->nouveau_fb = nouveau_fb;
par->dev = dev;
- if (dev_priv->channel) {
+ if (dev_priv->channel && !nouveau_nofbaccel) {
switch (dev_priv->card_type) {
case NV_50:
nv50_fbcon_accel_init(info);
+ info->fbops = &nv50_fbcon_ops;
break;
default:
nv04_fbcon_accel_init(info);
+ info->fbops = &nv04_fbcon_ops;
break;
};
}
@@ -336,6 +371,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
nvbo->bo.offset, nvbo);
mutex_unlock(&dev->struct_mutex);
+ vga_switcheroo_client_fb_set(dev->pdev, info);
return 0;
out_unref:
@@ -367,10 +403,8 @@ nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb)
unregister_framebuffer(info);
nouveau_bo_unmap(nouveau_fb->nvbo);
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(nouveau_fb->nvbo->gem);
+ drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
nouveau_fb->nvbo = NULL;
- mutex_unlock(&dev->struct_mutex);
if (par)
drm_fb_helper_free(&par->helper);
framebuffer_release(info);
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index 462e0b87b4bd..f9c34e1a8c11 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -40,7 +40,13 @@ int nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb);
void nouveau_fbcon_restore(void);
void nouveau_fbcon_zfill(struct drm_device *dev);
+void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
+void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+void nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv04_fbcon_accel_init(struct fb_info *info);
+void nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+void nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
+void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv50_fbcon_accel_init(struct fb_info *info);
void nouveau_fbcon_gpu_lockup(struct fb_info *info);
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 2009db2426c3..0d22f66f1c79 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -167,12 +167,10 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
ret = drm_gem_handle_create(file_priv, nvbo->gem, &req->info.handle);
out:
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_handle_unreference(nvbo->gem);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_handle_unreference_unlocked(nvbo->gem);
if (ret)
- drm_gem_object_unreference(nvbo->gem);
+ drm_gem_object_unreference_unlocked(nvbo->gem);
return ret;
}
@@ -243,6 +241,11 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence)
nouveau_fence_unref((void *)&prev_fence);
}
+ if (unlikely(nvbo->validate_mapped)) {
+ ttm_bo_kunmap(&nvbo->kmap);
+ nvbo->validate_mapped = false;
+ }
+
list_del(&nvbo->entry);
nvbo->reserved_by = NULL;
ttm_bo_unreserve(&nvbo->bo);
@@ -302,11 +305,14 @@ retry:
if (ret == -EAGAIN)
ret = ttm_bo_wait_unreserved(&nvbo->bo, false);
drm_gem_object_unreference(gem);
- if (ret)
+ if (ret) {
+ NV_ERROR(dev, "fail reserve\n");
return ret;
+ }
goto retry;
}
+ b->user_priv = (uint64_t)(unsigned long)nvbo;
nvbo->reserved_by = file_priv;
nvbo->pbbo_index = i;
if ((b->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) &&
@@ -321,6 +327,7 @@ retry:
else {
NV_ERROR(dev, "invalid valid domains: 0x%08x\n",
b->valid_domains);
+ list_add_tail(&nvbo->entry, &op->both_list);
validate_fini(op, NULL);
return -EINVAL;
}
@@ -335,8 +342,10 @@ retry:
}
ret = ttm_bo_wait_cpu(&nvbo->bo, false);
- if (ret)
+ if (ret) {
+ NV_ERROR(dev, "fail wait_cpu\n");
return ret;
+ }
goto retry;
}
}
@@ -350,6 +359,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
{
struct drm_nouveau_gem_pushbuf_bo __user *upbbo =
(void __force __user *)(uintptr_t)user_pbbo_ptr;
+ struct drm_device *dev = chan->dev;
struct nouveau_bo *nvbo;
int ret, relocs = 0;
@@ -361,39 +371,46 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
spin_lock(&nvbo->bo.lock);
ret = ttm_bo_wait(&nvbo->bo, false, false, false);
spin_unlock(&nvbo->bo.lock);
- if (unlikely(ret))
+ if (unlikely(ret)) {
+ NV_ERROR(dev, "fail wait other chan\n");
return ret;
+ }
}
ret = nouveau_gem_set_domain(nvbo->gem, b->read_domains,
b->write_domains,
b->valid_domains);
- if (unlikely(ret))
+ if (unlikely(ret)) {
+ NV_ERROR(dev, "fail set_domain\n");
return ret;
+ }
nvbo->channel = chan;
ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement,
false, false);
nvbo->channel = NULL;
- if (unlikely(ret))
+ if (unlikely(ret)) {
+ NV_ERROR(dev, "fail ttm_validate\n");
return ret;
+ }
- if (nvbo->bo.offset == b->presumed_offset &&
+ if (nvbo->bo.offset == b->presumed.offset &&
((nvbo->bo.mem.mem_type == TTM_PL_VRAM &&
- b->presumed_domain & NOUVEAU_GEM_DOMAIN_VRAM) ||
+ b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) ||
(nvbo->bo.mem.mem_type == TTM_PL_TT &&
- b->presumed_domain & NOUVEAU_GEM_DOMAIN_GART)))
+ b->presumed.domain & NOUVEAU_GEM_DOMAIN_GART)))
continue;
if (nvbo->bo.mem.mem_type == TTM_PL_TT)
- b->presumed_domain = NOUVEAU_GEM_DOMAIN_GART;
+ b->presumed.domain = NOUVEAU_GEM_DOMAIN_GART;
else
- b->presumed_domain = NOUVEAU_GEM_DOMAIN_VRAM;
- b->presumed_offset = nvbo->bo.offset;
- b->presumed_ok = 0;
+ b->presumed.domain = NOUVEAU_GEM_DOMAIN_VRAM;
+ b->presumed.offset = nvbo->bo.offset;
+ b->presumed.valid = 0;
relocs++;
- if (DRM_COPY_TO_USER(&upbbo[nvbo->pbbo_index], b, sizeof(*b)))
+ if (DRM_COPY_TO_USER(&upbbo[nvbo->pbbo_index].presumed,
+ &b->presumed, sizeof(b->presumed)))
return -EFAULT;
}
@@ -407,6 +424,7 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
uint64_t user_buffers, int nr_buffers,
struct validate_op *op, int *apply_relocs)
{
+ struct drm_device *dev = chan->dev;
int ret, relocs = 0;
INIT_LIST_HEAD(&op->vram_list);
@@ -417,11 +435,14 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
return 0;
ret = validate_init(chan, file_priv, pbbo, nr_buffers, op);
- if (unlikely(ret))
+ if (unlikely(ret)) {
+ NV_ERROR(dev, "validate_init\n");
return ret;
+ }
ret = validate_list(chan, &op->vram_list, pbbo, user_buffers);
if (unlikely(ret < 0)) {
+ NV_ERROR(dev, "validate vram_list\n");
validate_fini(op, NULL);
return ret;
}
@@ -429,6 +450,7 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
ret = validate_list(chan, &op->gart_list, pbbo, user_buffers);
if (unlikely(ret < 0)) {
+ NV_ERROR(dev, "validate gart_list\n");
validate_fini(op, NULL);
return ret;
}
@@ -436,6 +458,7 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
ret = validate_list(chan, &op->both_list, pbbo, user_buffers);
if (unlikely(ret < 0)) {
+ NV_ERROR(dev, "validate both_list\n");
validate_fini(op, NULL);
return ret;
}
@@ -464,58 +487,82 @@ u_memcpya(uint64_t user, unsigned nmemb, unsigned size)
}
static int
-nouveau_gem_pushbuf_reloc_apply(struct nouveau_channel *chan, int nr_bo,
- struct drm_nouveau_gem_pushbuf_bo *bo,
- int nr_relocs, uint64_t ptr_relocs,
- int nr_dwords, int first_dword,
- uint32_t *pushbuf, bool is_iomem)
+nouveau_gem_pushbuf_reloc_apply(struct drm_device *dev,
+ struct drm_nouveau_gem_pushbuf *req,
+ struct drm_nouveau_gem_pushbuf_bo *bo)
{
struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL;
- struct drm_device *dev = chan->dev;
- int ret = 0, i;
+ int ret = 0;
+ unsigned i;
- reloc = u_memcpya(ptr_relocs, nr_relocs, sizeof(*reloc));
+ reloc = u_memcpya(req->relocs, req->nr_relocs, sizeof(*reloc));
if (IS_ERR(reloc))
return PTR_ERR(reloc);
- for (i = 0; i < nr_relocs; i++) {
+ for (i = 0; i < req->nr_relocs; i++) {
struct drm_nouveau_gem_pushbuf_reloc *r = &reloc[i];
struct drm_nouveau_gem_pushbuf_bo *b;
+ struct nouveau_bo *nvbo;
uint32_t data;
- if (r->bo_index >= nr_bo || r->reloc_index < first_dword ||
- r->reloc_index >= first_dword + nr_dwords) {
- NV_ERROR(dev, "Bad relocation %d\n", i);
- NV_ERROR(dev, " bo: %d max %d\n", r->bo_index, nr_bo);
- NV_ERROR(dev, " id: %d max %d\n", r->reloc_index, nr_dwords);
+ if (unlikely(r->bo_index > req->nr_buffers)) {
+ NV_ERROR(dev, "reloc bo index invalid\n");
ret = -EINVAL;
break;
}
b = &bo[r->bo_index];
- if (b->presumed_ok)
+ if (b->presumed.valid)
continue;
+ if (unlikely(r->reloc_bo_index > req->nr_buffers)) {
+ NV_ERROR(dev, "reloc container bo index invalid\n");
+ ret = -EINVAL;
+ break;
+ }
+ nvbo = (void *)(unsigned long)bo[r->reloc_bo_index].user_priv;
+
+ if (unlikely(r->reloc_bo_offset + 4 >
+ nvbo->bo.mem.num_pages << PAGE_SHIFT)) {
+ NV_ERROR(dev, "reloc outside of bo\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ if (!nvbo->kmap.virtual) {
+ ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages,
+ &nvbo->kmap);
+ if (ret) {
+ NV_ERROR(dev, "failed kmap for reloc\n");
+ break;
+ }
+ nvbo->validate_mapped = true;
+ }
+
if (r->flags & NOUVEAU_GEM_RELOC_LOW)
- data = b->presumed_offset + r->data;
+ data = b->presumed.offset + r->data;
else
if (r->flags & NOUVEAU_GEM_RELOC_HIGH)
- data = (b->presumed_offset + r->data) >> 32;
+ data = (b->presumed.offset + r->data) >> 32;
else
data = r->data;
if (r->flags & NOUVEAU_GEM_RELOC_OR) {
- if (b->presumed_domain == NOUVEAU_GEM_DOMAIN_GART)
+ if (b->presumed.domain == NOUVEAU_GEM_DOMAIN_GART)
data |= r->tor;
else
data |= r->vor;
}
- if (is_iomem)
- iowrite32_native(data, (void __force __iomem *)
- &pushbuf[r->reloc_index]);
- else
- pushbuf[r->reloc_index] = data;
+ spin_lock(&nvbo->bo.lock);
+ ret = ttm_bo_wait(&nvbo->bo, false, false, false);
+ spin_unlock(&nvbo->bo.lock);
+ if (ret) {
+ NV_ERROR(dev, "reloc wait_idle failed: %d\n", ret);
+ break;
+ }
+
+ nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data);
}
kfree(reloc);
@@ -526,127 +573,50 @@ int
nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_nouveau_gem_pushbuf *req = data;
- struct drm_nouveau_gem_pushbuf_bo *bo = NULL;
+ struct drm_nouveau_gem_pushbuf_push *push;
+ struct drm_nouveau_gem_pushbuf_bo *bo;
struct nouveau_channel *chan;
struct validate_op op;
- struct nouveau_fence* fence = 0;
- uint32_t *pushbuf = NULL;
- int ret = 0, do_reloc = 0, i;
+ struct nouveau_fence *fence = 0;
+ int i, j, ret = 0, do_reloc = 0;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan);
- if (req->nr_dwords >= chan->dma.max ||
- req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS ||
- req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS) {
- NV_ERROR(dev, "Pushbuf config exceeds limits:\n");
- NV_ERROR(dev, " dwords : %d max %d\n", req->nr_dwords,
- chan->dma.max - 1);
- NV_ERROR(dev, " buffers: %d max %d\n", req->nr_buffers,
- NOUVEAU_GEM_MAX_BUFFERS);
- NV_ERROR(dev, " relocs : %d max %d\n", req->nr_relocs,
- NOUVEAU_GEM_MAX_RELOCS);
- return -EINVAL;
- }
-
- pushbuf = u_memcpya(req->dwords, req->nr_dwords, sizeof(uint32_t));
- if (IS_ERR(pushbuf))
- return PTR_ERR(pushbuf);
-
- bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo));
- if (IS_ERR(bo)) {
- kfree(pushbuf);
- return PTR_ERR(bo);
- }
-
- mutex_lock(&dev->struct_mutex);
-
- /* Validate buffer list */
- ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers,
- req->nr_buffers, &op, &do_reloc);
- if (ret)
- goto out;
-
- /* Apply any relocations that are required */
- if (do_reloc) {
- ret = nouveau_gem_pushbuf_reloc_apply(chan, req->nr_buffers,
- bo, req->nr_relocs,
- req->relocs,
- req->nr_dwords, 0,
- pushbuf, false);
- if (ret)
- goto out;
- }
-
- /* Emit push buffer to the hw
- */
- ret = RING_SPACE(chan, req->nr_dwords);
- if (ret)
- goto out;
-
- OUT_RINGp(chan, pushbuf, req->nr_dwords);
+ req->vram_available = dev_priv->fb_aper_free;
+ req->gart_available = dev_priv->gart_info.aper_free;
+ if (unlikely(req->nr_push == 0))
+ goto out_next;
- ret = nouveau_fence_new(chan, &fence, true);
- if (ret) {
- NV_ERROR(dev, "error fencing pushbuf: %d\n", ret);
- WIND_RING(chan);
- goto out;
+ if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) {
+ NV_ERROR(dev, "pushbuf push count exceeds limit: %d max %d\n",
+ req->nr_push, NOUVEAU_GEM_MAX_PUSH);
+ return -EINVAL;
}
- if (nouveau_gem_pushbuf_sync(chan)) {
- ret = nouveau_fence_wait(fence, NULL, false, false);
- if (ret) {
- for (i = 0; i < req->nr_dwords; i++)
- NV_ERROR(dev, "0x%08x\n", pushbuf[i]);
- NV_ERROR(dev, "^^ above push buffer is fail :(\n");
- }
+ if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) {
+ NV_ERROR(dev, "pushbuf bo count exceeds limit: %d max %d\n",
+ req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS);
+ return -EINVAL;
}
-out:
- validate_fini(&op, fence);
- nouveau_fence_unref((void**)&fence);
- mutex_unlock(&dev->struct_mutex);
- kfree(pushbuf);
- kfree(bo);
- return ret;
-}
-
-#define PUSHBUF_CAL (dev_priv->card_type >= NV_20)
-
-int
-nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct drm_nouveau_gem_pushbuf_call *req = data;
- struct drm_nouveau_gem_pushbuf_bo *bo = NULL;
- struct nouveau_channel *chan;
- struct drm_gem_object *gem;
- struct nouveau_bo *pbbo;
- struct validate_op op;
- struct nouveau_fence* fence = 0;
- int i, ret = 0, do_reloc = 0;
-
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
- NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan);
-
- if (unlikely(req->handle == 0))
- goto out_next;
-
- if (req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS ||
- req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS) {
- NV_ERROR(dev, "Pushbuf config exceeds limits:\n");
- NV_ERROR(dev, " buffers: %d max %d\n", req->nr_buffers,
- NOUVEAU_GEM_MAX_BUFFERS);
- NV_ERROR(dev, " relocs : %d max %d\n", req->nr_relocs,
- NOUVEAU_GEM_MAX_RELOCS);
+ if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) {
+ NV_ERROR(dev, "pushbuf reloc count exceeds limit: %d max %d\n",
+ req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS);
return -EINVAL;
}
+ push = u_memcpya(req->push, req->nr_push, sizeof(*push));
+ if (IS_ERR(push))
+ return PTR_ERR(push);
+
bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo));
- if (IS_ERR(bo))
+ if (IS_ERR(bo)) {
+ kfree(push);
return PTR_ERR(bo);
+ }
mutex_lock(&dev->struct_mutex);
@@ -658,110 +628,84 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data,
goto out;
}
- /* Validate DMA push buffer */
- gem = drm_gem_object_lookup(dev, file_priv, req->handle);
- if (!gem) {
- NV_ERROR(dev, "Unknown pb handle 0x%08x\n", req->handle);
- ret = -EINVAL;
- goto out;
- }
- pbbo = nouveau_gem_object(gem);
-
- ret = ttm_bo_reserve(&pbbo->bo, false, false, true,
- chan->fence.sequence);
- if (ret) {
- NV_ERROR(dev, "resv pb: %d\n", ret);
- drm_gem_object_unreference(gem);
- goto out;
- }
-
- nouveau_bo_placement_set(pbbo, 1 << chan->pushbuf_bo->bo.mem.mem_type);
- ret = ttm_bo_validate(&pbbo->bo, &pbbo->placement, false, false);
- if (ret) {
- NV_ERROR(dev, "validate pb: %d\n", ret);
- ttm_bo_unreserve(&pbbo->bo);
- drm_gem_object_unreference(gem);
- goto out;
- }
-
- list_add_tail(&pbbo->entry, &op.both_list);
-
- /* If presumed return address doesn't match, we need to map the
- * push buffer and fix it..
- */
- if (!PUSHBUF_CAL) {
- uint32_t retaddy;
-
- if (chan->dma.free < 4 + NOUVEAU_DMA_SKIPS) {
- ret = nouveau_dma_wait(chan, 4 + NOUVEAU_DMA_SKIPS);
- if (ret) {
- NV_ERROR(dev, "jmp_space: %d\n", ret);
- goto out;
- }
- }
-
- retaddy = chan->pushbuf_base + ((chan->dma.cur + 2) << 2);
- retaddy |= 0x20000000;
- if (retaddy != req->suffix0) {
- req->suffix0 = retaddy;
- do_reloc = 1;
- }
- }
-
/* Apply any relocations that are required */
if (do_reloc) {
- void *pbvirt;
- bool is_iomem;
- ret = ttm_bo_kmap(&pbbo->bo, 0, pbbo->bo.mem.num_pages,
- &pbbo->kmap);
+ ret = nouveau_gem_pushbuf_reloc_apply(dev, req, bo);
if (ret) {
- NV_ERROR(dev, "kmap pb: %d\n", ret);
+ NV_ERROR(dev, "reloc apply: %d\n", ret);
goto out;
}
+ }
- pbvirt = ttm_kmap_obj_virtual(&pbbo->kmap, &is_iomem);
- ret = nouveau_gem_pushbuf_reloc_apply(chan, req->nr_buffers, bo,
- req->nr_relocs,
- req->relocs,
- req->nr_dwords,
- req->offset / 4,
- pbvirt, is_iomem);
-
- if (!PUSHBUF_CAL) {
- nouveau_bo_wr32(pbbo,
- req->offset / 4 + req->nr_dwords - 2,
- req->suffix0);
- }
-
- ttm_bo_kunmap(&pbbo->kmap);
+ if (chan->dma.ib_max) {
+ ret = nouveau_dma_wait(chan, req->nr_push + 1, 6);
if (ret) {
- NV_ERROR(dev, "reloc apply: %d\n", ret);
+ NV_INFO(dev, "nv50cal_space: %d\n", ret);
goto out;
}
- }
- if (PUSHBUF_CAL) {
- ret = RING_SPACE(chan, 2);
+ for (i = 0; i < req->nr_push; i++) {
+ struct nouveau_bo *nvbo = (void *)(unsigned long)
+ bo[push[i].bo_index].user_priv;
+
+ nv50_dma_push(chan, nvbo, push[i].offset,
+ push[i].length);
+ }
+ } else
+ if (dev_priv->card_type >= NV_20) {
+ ret = RING_SPACE(chan, req->nr_push * 2);
if (ret) {
NV_ERROR(dev, "cal_space: %d\n", ret);
goto out;
}
- OUT_RING(chan, ((pbbo->bo.mem.mm_node->start << PAGE_SHIFT) +
- req->offset) | 2);
- OUT_RING(chan, 0);
+
+ for (i = 0; i < req->nr_push; i++) {
+ struct nouveau_bo *nvbo = (void *)(unsigned long)
+ bo[push[i].bo_index].user_priv;
+ struct drm_mm_node *mem = nvbo->bo.mem.mm_node;
+
+ OUT_RING(chan, ((mem->start << PAGE_SHIFT) +
+ push[i].offset) | 2);
+ OUT_RING(chan, 0);
+ }
} else {
- ret = RING_SPACE(chan, 2 + NOUVEAU_DMA_SKIPS);
+ ret = RING_SPACE(chan, req->nr_push * (2 + NOUVEAU_DMA_SKIPS));
if (ret) {
NV_ERROR(dev, "jmp_space: %d\n", ret);
goto out;
}
- OUT_RING(chan, ((pbbo->bo.mem.mm_node->start << PAGE_SHIFT) +
- req->offset) | 0x20000000);
- OUT_RING(chan, 0);
- /* Space the jumps apart with NOPs. */
- for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
+ for (i = 0; i < req->nr_push; i++) {
+ struct nouveau_bo *nvbo = (void *)(unsigned long)
+ bo[push[i].bo_index].user_priv;
+ struct drm_mm_node *mem = nvbo->bo.mem.mm_node;
+ uint32_t cmd;
+
+ cmd = chan->pushbuf_base + ((chan->dma.cur + 2) << 2);
+ cmd |= 0x20000000;
+ if (unlikely(cmd != req->suffix0)) {
+ if (!nvbo->kmap.virtual) {
+ ret = ttm_bo_kmap(&nvbo->bo, 0,
+ nvbo->bo.mem.
+ num_pages,
+ &nvbo->kmap);
+ if (ret) {
+ WIND_RING(chan);
+ goto out;
+ }
+ nvbo->validate_mapped = true;
+ }
+
+ nouveau_bo_wr32(nvbo, (push[i].offset +
+ push[i].length - 8) / 4, cmd);
+ }
+
+ OUT_RING(chan, ((mem->start << PAGE_SHIFT) +
+ push[i].offset) | 0x20000000);
OUT_RING(chan, 0);
+ for (j = 0; j < NOUVEAU_DMA_SKIPS; j++)
+ OUT_RING(chan, 0);
+ }
}
ret = nouveau_fence_new(chan, &fence, true);
@@ -776,9 +720,14 @@ out:
nouveau_fence_unref((void**)&fence);
mutex_unlock(&dev->struct_mutex);
kfree(bo);
+ kfree(push);
out_next:
- if (PUSHBUF_CAL) {
+ if (chan->dma.ib_max) {
+ req->suffix0 = 0x00000000;
+ req->suffix1 = 0x00000000;
+ } else
+ if (dev_priv->card_type >= NV_20) {
req->suffix0 = 0x00020000;
req->suffix1 = 0x00000000;
} else {
@@ -790,19 +739,6 @@ out_next:
return ret;
}
-int
-nouveau_gem_ioctl_pushbuf_call2(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct drm_nouveau_gem_pushbuf_call *req = data;
-
- req->vram_available = dev_priv->fb_aper_free;
- req->gart_available = dev_priv->gart_info.aper_free;
-
- return nouveau_gem_ioctl_pushbuf_call(dev, data, file_priv);
-}
-
static inline uint32_t
domain_to_ttm(struct nouveau_bo *nvbo, uint32_t domain)
{
@@ -817,74 +753,6 @@ domain_to_ttm(struct nouveau_bo *nvbo, uint32_t domain)
}
int
-nouveau_gem_ioctl_pin(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_nouveau_gem_pin *req = data;
- struct drm_gem_object *gem;
- struct nouveau_bo *nvbo;
- int ret = 0;
-
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- NV_ERROR(dev, "pin only allowed without kernel modesetting\n");
- return -EINVAL;
- }
-
- if (!DRM_SUSER(DRM_CURPROC))
- return -EPERM;
-
- gem = drm_gem_object_lookup(dev, file_priv, req->handle);
- if (!gem)
- return -EINVAL;
- nvbo = nouveau_gem_object(gem);
-
- ret = nouveau_bo_pin(nvbo, domain_to_ttm(nvbo, req->domain));
- if (ret)
- goto out;
-
- req->offset = nvbo->bo.offset;
- if (nvbo->bo.mem.mem_type == TTM_PL_TT)
- req->domain = NOUVEAU_GEM_DOMAIN_GART;
- else
- req->domain = NOUVEAU_GEM_DOMAIN_VRAM;
-
-out:
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gem);
- mutex_unlock(&dev->struct_mutex);
-
- return ret;
-}
-
-int
-nouveau_gem_ioctl_unpin(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_nouveau_gem_pin *req = data;
- struct drm_gem_object *gem;
- int ret;
-
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
- if (drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
- gem = drm_gem_object_lookup(dev, file_priv, req->handle);
- if (!gem)
- return -EINVAL;
-
- ret = nouveau_bo_unpin(nouveau_gem_object(gem));
-
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gem);
- mutex_unlock(&dev->struct_mutex);
-
- return ret;
-}
-
-int
nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -911,7 +779,9 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
}
if (req->flags & NOUVEAU_GEM_CPU_PREP_NOBLOCK) {
+ spin_lock(&nvbo->bo.lock);
ret = ttm_bo_wait(&nvbo->bo, false, false, no_wait);
+ spin_unlock(&nvbo->bo.lock);
} else {
ret = ttm_bo_synccpu_write_grab(&nvbo->bo, no_wait);
if (ret == 0)
@@ -919,9 +789,7 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
}
out:
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gem);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(gem);
return ret;
}
@@ -949,9 +817,7 @@ nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data,
ret = 0;
out:
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gem);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(gem);
return ret;
}
@@ -970,9 +836,7 @@ nouveau_gem_ioctl_info(struct drm_device *dev, void *data,
return -EINVAL;
ret = nouveau_gem_info(gem, req);
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gem);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(gem);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.c b/drivers/gpu/drm/nouveau/nouveau_grctx.c
index 419f4c2b3b89..c7ebec696747 100644
--- a/drivers/gpu/drm/nouveau/nouveau_grctx.c
+++ b/drivers/gpu/drm/nouveau/nouveau_grctx.c
@@ -97,8 +97,8 @@ nouveau_grctx_prog_load(struct drm_device *dev)
}
pgraph->ctxvals = kmalloc(fw->size, GFP_KERNEL);
- if (!pgraph->ctxprog) {
- NV_ERROR(dev, "OOM copying ctxprog\n");
+ if (!pgraph->ctxvals) {
+ NV_ERROR(dev, "OOM copying ctxvals\n");
release_firmware(fw);
nouveau_grctx_fini(dev);
return -ENOMEM;
diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c
index dc46792a5c96..7855b35effc3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_hw.c
+++ b/drivers/gpu/drm/nouveau/nouveau_hw.c
@@ -160,7 +160,7 @@ static void
setPLL_single(struct drm_device *dev, uint32_t reg, struct nouveau_pll_vals *pv)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- int chip_version = dev_priv->vbios->chip_version;
+ int chip_version = dev_priv->vbios.chip_version;
uint32_t oldpll = NVReadRAMDAC(dev, 0, reg);
int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff;
uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1;
@@ -216,7 +216,7 @@ setPLL_double_highregs(struct drm_device *dev, uint32_t reg1,
struct nouveau_pll_vals *pv)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- int chip_version = dev_priv->vbios->chip_version;
+ int chip_version = dev_priv->vbios.chip_version;
bool nv3035 = chip_version == 0x30 || chip_version == 0x35;
uint32_t reg2 = reg1 + ((reg1 == NV_RAMDAC_VPLL2) ? 0x5c : 0x70);
uint32_t oldpll1 = NVReadRAMDAC(dev, 0, reg1);
@@ -374,7 +374,7 @@ nouveau_hw_setpll(struct drm_device *dev, uint32_t reg1,
struct nouveau_pll_vals *pv)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- int cv = dev_priv->vbios->chip_version;
+ int cv = dev_priv->vbios.chip_version;
if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
cv >= 0x40) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c
index 70e994d28122..88583e7bf651 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c
@@ -254,16 +254,16 @@ struct nouveau_i2c_chan *
nouveau_i2c_find(struct drm_device *dev, int index)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
- if (index > DCB_MAX_NUM_I2C_ENTRIES)
+ if (index >= DCB_MAX_NUM_I2C_ENTRIES)
return NULL;
- if (!bios->bdcb.dcb.i2c[index].chan) {
- if (nouveau_i2c_init(dev, &bios->bdcb.dcb.i2c[index], index))
+ if (!bios->dcb.i2c[index].chan) {
+ if (nouveau_i2c_init(dev, &bios->dcb.i2c[index], index))
return NULL;
}
- return bios->bdcb.dcb.i2c[index].chan;
+ return bios->dcb.i2c[index].chan;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
index 919a619ca7fa..95220ddebb45 100644
--- a/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -211,6 +211,20 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
get + 4);
}
+ if (status & NV_PFIFO_INTR_SEMAPHORE) {
+ uint32_t sem;
+
+ status &= ~NV_PFIFO_INTR_SEMAPHORE;
+ nv_wr32(dev, NV03_PFIFO_INTR_0,
+ NV_PFIFO_INTR_SEMAPHORE);
+
+ sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE);
+ nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
+
+ nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
+ nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
+ }
+
if (status) {
NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
status, chid);
@@ -483,6 +497,13 @@ nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource)
if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
if (nouveau_pgraph_intr_swmthd(dev, &trap))
unhandled = 1;
+ } else if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
+ uint32_t v = nv_rd32(dev, 0x402000);
+ nv_wr32(dev, 0x402000, v);
+
+ /* dump the error anyway for now: it's useful for
+ Gallium development */
+ unhandled = 1;
} else {
unhandled = 1;
}
@@ -559,86 +580,99 @@ nouveau_pgraph_irq_handler(struct drm_device *dev)
static void
nv50_pgraph_irq_handler(struct drm_device *dev)
{
- uint32_t status, nsource;
+ uint32_t status;
- status = nv_rd32(dev, NV03_PGRAPH_INTR);
- nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
+ while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) {
+ uint32_t nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
- if (status & 0x00000001) {
- nouveau_pgraph_intr_notify(dev, nsource);
- status &= ~0x00000001;
- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001);
- }
+ if (status & 0x00000001) {
+ nouveau_pgraph_intr_notify(dev, nsource);
+ status &= ~0x00000001;
+ nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001);
+ }
- if (status & 0x00000010) {
- nouveau_pgraph_intr_error(dev, nsource |
- NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD);
+ if (status & 0x00000010) {
+ nouveau_pgraph_intr_error(dev, nsource |
+ NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD);
- status &= ~0x00000010;
- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010);
- }
+ status &= ~0x00000010;
+ nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010);
+ }
- if (status & 0x00001000) {
- nv_wr32(dev, 0x400500, 0x00000000);
- nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
- nv_wr32(dev, NV40_PGRAPH_INTR_EN, nv_rd32(dev,
- NV40_PGRAPH_INTR_EN) & ~NV_PGRAPH_INTR_CONTEXT_SWITCH);
- nv_wr32(dev, 0x400500, 0x00010001);
+ if (status & 0x00001000) {
+ nv_wr32(dev, 0x400500, 0x00000000);
+ nv_wr32(dev, NV03_PGRAPH_INTR,
+ NV_PGRAPH_INTR_CONTEXT_SWITCH);
+ nv_wr32(dev, NV40_PGRAPH_INTR_EN, nv_rd32(dev,
+ NV40_PGRAPH_INTR_EN) &
+ ~NV_PGRAPH_INTR_CONTEXT_SWITCH);
+ nv_wr32(dev, 0x400500, 0x00010001);
- nv50_graph_context_switch(dev);
+ nv50_graph_context_switch(dev);
- status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
- }
+ status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ }
- if (status & 0x00100000) {
- nouveau_pgraph_intr_error(dev, nsource |
- NV03_PGRAPH_NSOURCE_DATA_ERROR);
+ if (status & 0x00100000) {
+ nouveau_pgraph_intr_error(dev, nsource |
+ NV03_PGRAPH_NSOURCE_DATA_ERROR);
- status &= ~0x00100000;
- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000);
- }
+ status &= ~0x00100000;
+ nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000);
+ }
- if (status & 0x00200000) {
- int r;
-
- nouveau_pgraph_intr_error(dev, nsource |
- NV03_PGRAPH_NSOURCE_PROTECTION_ERROR);
-
- NV_ERROR(dev, "magic set 1:\n");
- for (r = 0x408900; r <= 0x408910; r += 4)
- NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r));
- nv_wr32(dev, 0x408900, nv_rd32(dev, 0x408904) | 0xc0000000);
- for (r = 0x408e08; r <= 0x408e24; r += 4)
- NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r));
- nv_wr32(dev, 0x408e08, nv_rd32(dev, 0x408e08) | 0xc0000000);
-
- NV_ERROR(dev, "magic set 2:\n");
- for (r = 0x409900; r <= 0x409910; r += 4)
- NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r));
- nv_wr32(dev, 0x409900, nv_rd32(dev, 0x409904) | 0xc0000000);
- for (r = 0x409e08; r <= 0x409e24; r += 4)
- NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r));
- nv_wr32(dev, 0x409e08, nv_rd32(dev, 0x409e08) | 0xc0000000);
-
- status &= ~0x00200000;
- nv_wr32(dev, NV03_PGRAPH_NSOURCE, nsource);
- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000);
- }
+ if (status & 0x00200000) {
+ int r;
+
+ nouveau_pgraph_intr_error(dev, nsource |
+ NV03_PGRAPH_NSOURCE_PROTECTION_ERROR);
+
+ NV_ERROR(dev, "magic set 1:\n");
+ for (r = 0x408900; r <= 0x408910; r += 4)
+ NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
+ nv_rd32(dev, r));
+ nv_wr32(dev, 0x408900,
+ nv_rd32(dev, 0x408904) | 0xc0000000);
+ for (r = 0x408e08; r <= 0x408e24; r += 4)
+ NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
+ nv_rd32(dev, r));
+ nv_wr32(dev, 0x408e08,
+ nv_rd32(dev, 0x408e08) | 0xc0000000);
+
+ NV_ERROR(dev, "magic set 2:\n");
+ for (r = 0x409900; r <= 0x409910; r += 4)
+ NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
+ nv_rd32(dev, r));
+ nv_wr32(dev, 0x409900,
+ nv_rd32(dev, 0x409904) | 0xc0000000);
+ for (r = 0x409e08; r <= 0x409e24; r += 4)
+ NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
+ nv_rd32(dev, r));
+ nv_wr32(dev, 0x409e08,
+ nv_rd32(dev, 0x409e08) | 0xc0000000);
+
+ status &= ~0x00200000;
+ nv_wr32(dev, NV03_PGRAPH_NSOURCE, nsource);
+ nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000);
+ }
- if (status) {
- NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", status);
- nv_wr32(dev, NV03_PGRAPH_INTR, status);
- }
+ if (status) {
+ NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n",
+ status);
+ nv_wr32(dev, NV03_PGRAPH_INTR, status);
+ }
- {
- const int isb = (1 << 16) | (1 << 0);
+ {
+ const int isb = (1 << 16) | (1 << 0);
- if ((nv_rd32(dev, 0x400500) & isb) != isb)
- nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | isb);
- nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
+ if ((nv_rd32(dev, 0x400500) & isb) != isb)
+ nv_wr32(dev, 0x400500,
+ nv_rd32(dev, 0x400500) | isb);
+ }
}
nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
+ nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
}
static void
@@ -657,11 +691,14 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
struct drm_device *dev = (struct drm_device *)arg;
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t status, fbdev_flags = 0;
+ unsigned long flags;
status = nv_rd32(dev, NV03_PMC_INTR_0);
if (!status)
return IRQ_NONE;
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+
if (dev_priv->fbdev_info) {
fbdev_flags = dev_priv->fbdev_info->flags;
dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
@@ -699,5 +736,7 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
if (dev_priv->fbdev_info)
dev_priv->fbdev_info->flags = fbdev_flags;
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
return IRQ_HANDLED;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index fb9bdd6edf1f..2dc09dbd817d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -285,53 +285,50 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
uint32_t flags, uint64_t phys)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj **pgt;
- unsigned psz, pfl, pages;
-
- if (virt >= dev_priv->vm_gart_base &&
- (virt + size) < (dev_priv->vm_gart_base + dev_priv->vm_gart_size)) {
- psz = 12;
- pgt = &dev_priv->gart_info.sg_ctxdma;
- pfl = 0x21;
- virt -= dev_priv->vm_gart_base;
- } else
- if (virt >= dev_priv->vm_vram_base &&
- (virt + size) < (dev_priv->vm_vram_base + dev_priv->vm_vram_size)) {
- psz = 16;
- pgt = dev_priv->vm_vram_pt;
- pfl = 0x01;
- virt -= dev_priv->vm_vram_base;
- } else {
- NV_ERROR(dev, "Invalid address: 0x%16llx-0x%16llx\n",
- virt, virt + size - 1);
- return -EINVAL;
- }
+ struct nouveau_gpuobj *pgt;
+ unsigned block;
+ int i;
- pages = size >> psz;
+ virt = ((virt - dev_priv->vm_vram_base) >> 16) << 1;
+ size = (size >> 16) << 1;
+
+ phys |= ((uint64_t)flags << 32);
+ phys |= 1;
+ if (dev_priv->vram_sys_base) {
+ phys += dev_priv->vram_sys_base;
+ phys |= 0x30;
+ }
dev_priv->engine.instmem.prepare_access(dev, true);
- if (flags & 0x80000000) {
- while (pages--) {
- struct nouveau_gpuobj *pt = pgt[virt >> 29];
- unsigned pte = ((virt & 0x1fffffffULL) >> psz) << 1;
+ while (size) {
+ unsigned offset_h = upper_32_bits(phys);
+ unsigned offset_l = lower_32_bits(phys);
+ unsigned pte, end;
+
+ for (i = 7; i >= 0; i--) {
+ block = 1 << (i + 1);
+ if (size >= block && !(virt & (block - 1)))
+ break;
+ }
+ offset_l |= (i << 7);
- nv_wo32(dev, pt, pte++, 0x00000000);
- nv_wo32(dev, pt, pte++, 0x00000000);
+ phys += block << 15;
+ size -= block;
- virt += (1 << psz);
- }
- } else {
- while (pages--) {
- struct nouveau_gpuobj *pt = pgt[virt >> 29];
- unsigned pte = ((virt & 0x1fffffffULL) >> psz) << 1;
- unsigned offset_h = upper_32_bits(phys) & 0xff;
- unsigned offset_l = lower_32_bits(phys);
+ while (block) {
+ pgt = dev_priv->vm_vram_pt[virt >> 14];
+ pte = virt & 0x3ffe;
- nv_wo32(dev, pt, pte++, offset_l | pfl);
- nv_wo32(dev, pt, pte++, offset_h | flags);
+ end = pte + block;
+ if (end > 16384)
+ end = 16384;
+ block -= (end - pte);
+ virt += (end - pte);
- phys += (1 << psz);
- virt += (1 << psz);
+ while (pte < end) {
+ nv_wo32(dev, pgt, pte++, offset_l);
+ nv_wo32(dev, pgt, pte++, offset_h);
+ }
}
}
dev_priv->engine.instmem.finish_access(dev);
@@ -356,7 +353,41 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
void
nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
{
- nv50_mem_vm_bind_linear(dev, virt, size, 0x80000000, 0);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *pgt;
+ unsigned pages, pte, end;
+
+ virt -= dev_priv->vm_vram_base;
+ pages = (size >> 16) << 1;
+
+ dev_priv->engine.instmem.prepare_access(dev, true);
+ while (pages) {
+ pgt = dev_priv->vm_vram_pt[virt >> 29];
+ pte = (virt & 0x1ffe0000ULL) >> 15;
+
+ end = pte + pages;
+ if (end > 16384)
+ end = 16384;
+ pages -= (end - pte);
+ virt += (end - pte) << 15;
+
+ while (pte < end)
+ nv_wo32(dev, pgt, pte++, 0);
+ }
+ dev_priv->engine.instmem.finish_access(dev);
+
+ nv_wr32(dev, 0x100c80, 0x00050001);
+ if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
+ NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
+ NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
+ return;
+ }
+
+ nv_wr32(dev, 0x100c80, 0x00000001);
+ if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
+ NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
+ NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
+ }
}
/*
@@ -383,9 +414,8 @@ void nouveau_mem_close(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- if (dev_priv->ttm.bdev.man[TTM_PL_PRIV0].has_type)
- ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_PRIV0);
- ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
+ nouveau_bo_unpin(dev_priv->vga_ram);
+ nouveau_bo_ref(NULL, &dev_priv->vga_ram);
ttm_bo_device_release(&dev_priv->ttm.bdev);
@@ -622,6 +652,15 @@ nouveau_mem_init(struct drm_device *dev)
return ret;
}
+ ret = nouveau_bo_new(dev, NULL, 256*1024, 0, TTM_PL_FLAG_VRAM,
+ 0, 0, true, true, &dev_priv->vga_ram);
+ if (ret == 0)
+ ret = nouveau_bo_pin(dev_priv->vga_ram, TTM_PL_FLAG_VRAM);
+ if (ret) {
+ NV_WARN(dev, "failed to reserve VGA memory\n");
+ nouveau_bo_ref(NULL, &dev_priv->vga_ram);
+ }
+
/* GART */
#if !defined(__powerpc__) && !defined(__ia64__)
if (drm_device_is_agp(dev) && dev->agp) {
@@ -653,6 +692,7 @@ nouveau_mem_init(struct drm_device *dev)
dev_priv->fb_mtrr = drm_mtrr_add(drm_get_resource_start(dev, 1),
drm_get_resource_len(dev, 1),
DRM_MTRR_WC);
+
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c
index 6c66a34b6345..9537f3e30115 100644
--- a/drivers/gpu/drm/nouveau/nouveau_notifier.c
+++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c
@@ -34,15 +34,20 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct nouveau_bo *ntfy = NULL;
+ uint32_t flags;
int ret;
- ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, nouveau_vram_notify ?
- TTM_PL_FLAG_VRAM : TTM_PL_FLAG_TT,
+ if (nouveau_vram_notify)
+ flags = TTM_PL_FLAG_VRAM;
+ else
+ flags = TTM_PL_FLAG_TT;
+
+ ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, flags,
0, 0x0000, false, true, &ntfy);
if (ret)
return ret;
- ret = nouveau_bo_pin(ntfy, TTM_PL_FLAG_VRAM);
+ ret = nouveau_bo_pin(ntfy, flags);
if (ret)
goto out_err;
@@ -56,11 +61,8 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan)
chan->notifier_bo = ntfy;
out_err:
- if (ret) {
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(ntfy->gem);
- mutex_unlock(&dev->struct_mutex);
- }
+ if (ret)
+ drm_gem_object_unreference_unlocked(ntfy->gem);
return ret;
}
@@ -76,8 +78,8 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan)
nouveau_bo_unmap(chan->notifier_bo);
mutex_lock(&dev->struct_mutex);
nouveau_bo_unpin(chan->notifier_bo);
- drm_gem_object_unreference(chan->notifier_bo->gem);
mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(chan->notifier_bo->gem);
nouveau_mem_takedown(&chan->notifier_heap);
}
@@ -128,6 +130,8 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
target = NV_DMA_TARGET_PCI;
} else {
target = NV_DMA_TARGET_AGP;
+ if (dev_priv->card_type >= NV_50)
+ offset += dev_priv->vm_gart_base;
}
} else {
NV_ERROR(dev, "Bad DMA target, mem_type %d!\n",
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
index 6c2cf81716df..e7c100ba63a1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_object.c
+++ b/drivers/gpu/drm/nouveau/nouveau_object.c
@@ -885,11 +885,12 @@ int
nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
struct nouveau_gpuobj **gpuobj_ret)
{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct drm_nouveau_private *dev_priv;
struct nouveau_gpuobj *gpuobj;
if (!chan || !gpuobj_ret || *gpuobj_ret != NULL)
return -EINVAL;
+ dev_priv = chan->dev->dev_private;
gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
if (!gpuobj)
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 251f1b3b38b9..aa9b310e41be 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -99,6 +99,7 @@
* the card will hang early on in the X init process.
*/
# define NV_PMC_ENABLE_UNK13 (1<<13)
+#define NV40_PMC_GRAPH_UNITS 0x00001540
#define NV40_PMC_BACKLIGHT 0x000015f0
# define NV40_PMC_BACKLIGHT_MASK 0x001f0000
#define NV40_PMC_1700 0x00001700
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index 4c7f1e403e80..ed1590577b6c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -54,11 +54,12 @@ static void
nouveau_sgdma_clear(struct ttm_backend *be)
{
struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
- struct drm_device *dev = nvbe->dev;
-
- NV_DEBUG(nvbe->dev, "\n");
+ struct drm_device *dev;
if (nvbe && nvbe->pages) {
+ dev = nvbe->dev;
+ NV_DEBUG(dev, "\n");
+
if (nvbe->bound)
be->func->unbind(be);
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 09b9a46dfc0e..eb8f084d5f53 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -29,6 +29,7 @@
#include "drm_sarea.h"
#include "drm_crtc_helper.h"
#include <linux/vgaarb.h>
+#include <linux/vga_switcheroo.h>
#include "nouveau_drv.h"
#include "nouveau_drm.h"
@@ -310,6 +311,14 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
static unsigned int
nouveau_vga_set_decode(void *priv, bool state)
{
+ struct drm_device *dev = priv;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->chipset >= 0x40)
+ nv_wr32(dev, 0x88054, state);
+ else
+ nv_wr32(dev, 0x1854, state);
+
if (state)
return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
@@ -363,6 +372,30 @@ out_err:
return ret;
}
+static void nouveau_switcheroo_set_state(struct pci_dev *pdev,
+ enum vga_switcheroo_state state)
+{
+ pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
+ if (state == VGA_SWITCHEROO_ON) {
+ printk(KERN_ERR "VGA switcheroo: switched nouveau on\n");
+ nouveau_pci_resume(pdev);
+ } else {
+ printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");
+ nouveau_pci_suspend(pdev, pmm);
+ }
+}
+
+static bool nouveau_switcheroo_can_switch(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+ bool can_switch;
+
+ spin_lock(&dev->count_lock);
+ can_switch = (dev->open_count == 0);
+ spin_unlock(&dev->count_lock);
+ return can_switch;
+}
+
int
nouveau_card_init(struct drm_device *dev)
{
@@ -376,6 +409,8 @@ nouveau_card_init(struct drm_device *dev)
return 0;
vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
+ vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
+ nouveau_switcheroo_can_switch);
/* Initialise internal driver API hooks */
ret = nouveau_init_engine_ptrs(dev);
@@ -383,6 +418,7 @@ nouveau_card_init(struct drm_device *dev)
goto out;
engine = &dev_priv->engine;
dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED;
+ spin_lock_init(&dev_priv->context_switch_lock);
/* Parse BIOS tables / Run init tables if card not POSTed */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
@@ -427,15 +463,19 @@ nouveau_card_init(struct drm_device *dev)
if (ret)
goto out_timer;
- /* PGRAPH */
- ret = engine->graph.init(dev);
- if (ret)
- goto out_fb;
+ if (nouveau_noaccel)
+ engine->graph.accel_blocked = true;
+ else {
+ /* PGRAPH */
+ ret = engine->graph.init(dev);
+ if (ret)
+ goto out_fb;
- /* PFIFO */
- ret = engine->fifo.init(dev);
- if (ret)
- goto out_graph;
+ /* PFIFO */
+ ret = engine->fifo.init(dev);
+ if (ret)
+ goto out_graph;
+ }
/* this call irq_preinstall, register irq handler and
* call irq_postinstall
@@ -479,9 +519,11 @@ nouveau_card_init(struct drm_device *dev)
out_irq:
drm_irq_uninstall(dev);
out_fifo:
- engine->fifo.takedown(dev);
+ if (!nouveau_noaccel)
+ engine->fifo.takedown(dev);
out_graph:
- engine->graph.takedown(dev);
+ if (!nouveau_noaccel)
+ engine->graph.takedown(dev);
out_fb:
engine->fb.takedown(dev);
out_timer:
@@ -518,13 +560,16 @@ static void nouveau_card_takedown(struct drm_device *dev)
dev_priv->channel = NULL;
}
- engine->fifo.takedown(dev);
- engine->graph.takedown(dev);
+ if (!nouveau_noaccel) {
+ engine->fifo.takedown(dev);
+ engine->graph.takedown(dev);
+ }
engine->fb.takedown(dev);
engine->timer.takedown(dev);
engine->mc.takedown(dev);
mutex_lock(&dev->struct_mutex);
+ ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
mutex_unlock(&dev->struct_mutex);
nouveau_sgdma_takedown(dev);
@@ -600,11 +645,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n",
dev->pci_vendor, dev->pci_device, dev->pdev->class);
- dev_priv->acpi_dsm = nouveau_dsm_probe(dev);
-
- if (dev_priv->acpi_dsm)
- nouveau_hybrid_setup(dev);
-
dev_priv->wq = create_workqueue("nouveau");
if (!dev_priv->wq)
return -EINVAL;
@@ -759,13 +799,6 @@ int nouveau_unload(struct drm_device *dev)
return 0;
}
-int
-nouveau_ioctl_card_init(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- return nouveau_card_init(dev);
-}
-
int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -816,6 +849,15 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
case NOUVEAU_GETPARAM_VM_VRAM_BASE:
getparam->value = dev_priv->vm_vram_base;
break;
+ case NOUVEAU_GETPARAM_GRAPH_UNITS:
+ /* NV40 and NV50 versions are quite different, but register
+ * address is the same. User is supposed to know the card
+ * family anyway... */
+ if (dev_priv->chipset >= 0x40) {
+ getparam->value = nv_rd32(dev, NV40_PMC_GRAPH_UNITS);
+ break;
+ }
+ /* FALLTHRU */
default:
NV_ERROR(dev, "unknown parameter %lld\n", getparam->param);
return -EINVAL;
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index d2f143ed97c1..a1d1ebb073d9 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -926,9 +926,7 @@ nv04_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.offset);
nv_crtc->cursor.show(nv_crtc, true);
out:
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gem);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(gem);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c
index d0e038d28948..1cb19e3acb55 100644
--- a/drivers/gpu/drm/nouveau/nv04_dac.c
+++ b/drivers/gpu/drm/nouveau/nv04_dac.c
@@ -119,7 +119,7 @@ static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder,
struct drm_connector *connector)
{
struct drm_device *dev = encoder->dev;
- uint8_t saved_seq1, saved_pi, saved_rpc1;
+ uint8_t saved_seq1, saved_pi, saved_rpc1, saved_cr_mode;
uint8_t saved_palette0[3], saved_palette_mask;
uint32_t saved_rtest_ctrl, saved_rgen_ctrl;
int i;
@@ -135,6 +135,9 @@ static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder,
/* only implemented for head A for now */
NVSetOwner(dev, 0);
+ saved_cr_mode = NVReadVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX);
+ NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode | 0x80);
+
saved_seq1 = NVReadVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX);
NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1 & ~0x20);
@@ -203,6 +206,7 @@ out:
NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX, saved_pi);
NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1);
NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1);
+ NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode);
if (blue == 0x18) {
NV_INFO(dev, "Load detected on head A\n");
@@ -226,13 +230,13 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
if (dcb->type == OUTPUT_TV) {
testval = RGB_TEST_DATA(0xa0, 0xa0, 0xa0);
- if (dev_priv->vbios->tvdactestval)
- testval = dev_priv->vbios->tvdactestval;
+ if (dev_priv->vbios.tvdactestval)
+ testval = dev_priv->vbios.tvdactestval;
} else {
testval = RGB_TEST_DATA(0x140, 0x140, 0x140); /* 0x94050140 */
- if (dev_priv->vbios->dactestval)
- testval = dev_priv->vbios->dactestval;
+ if (dev_priv->vbios.dactestval)
+ testval = dev_priv->vbios.dactestval;
}
saved_rtest_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c
index 483f875bdb6a..41634d4752fe 100644
--- a/drivers/gpu/drm/nouveau/nv04_dfp.c
+++ b/drivers/gpu/drm/nouveau/nv04_dfp.c
@@ -269,10 +269,10 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
regp->fp_horiz_regs[FP_TOTAL] = output_mode->htotal - 1;
if (!nv_gf4_disp_arch(dev) ||
(output_mode->hsync_start - output_mode->hdisplay) >=
- dev_priv->vbios->digital_min_front_porch)
+ dev_priv->vbios.digital_min_front_porch)
regp->fp_horiz_regs[FP_CRTC] = output_mode->hdisplay;
else
- regp->fp_horiz_regs[FP_CRTC] = output_mode->hsync_start - dev_priv->vbios->digital_min_front_porch - 1;
+ regp->fp_horiz_regs[FP_CRTC] = output_mode->hsync_start - dev_priv->vbios.digital_min_front_porch - 1;
regp->fp_horiz_regs[FP_SYNC_START] = output_mode->hsync_start - 1;
regp->fp_horiz_regs[FP_SYNC_END] = output_mode->hsync_end - 1;
regp->fp_horiz_regs[FP_VALID_START] = output_mode->hskew;
diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c
index ef77215fa5b9..c7898b4f6dfb 100644
--- a/drivers/gpu/drm/nouveau/nv04_display.c
+++ b/drivers/gpu/drm/nouveau/nv04_display.c
@@ -93,10 +93,9 @@ int
nv04_display_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct parsed_dcb *dcb = dev_priv->vbios->dcb;
+ struct dcb_table *dcb = &dev_priv->vbios.dcb;
struct drm_encoder *encoder;
struct drm_crtc *crtc;
- uint16_t connector[16] = { 0 };
int i, ret;
NV_DEBUG_KMS(dev, "\n");
@@ -154,52 +153,10 @@ nv04_display_create(struct drm_device *dev)
if (ret)
continue;
-
- connector[dcbent->connector] |= (1 << dcbent->type);
}
- for (i = 0; i < dcb->entries; i++) {
- struct dcb_entry *dcbent = &dcb->entry[i];
- uint16_t encoders;
- int type;
-
- encoders = connector[dcbent->connector];
- if (!(encoders & (1 << dcbent->type)))
- continue;
- connector[dcbent->connector] = 0;
-
- switch (dcbent->type) {
- case OUTPUT_ANALOG:
- if (!MULTIPLE_ENCODERS(encoders))
- type = DRM_MODE_CONNECTOR_VGA;
- else
- type = DRM_MODE_CONNECTOR_DVII;
- break;
- case OUTPUT_TMDS:
- if (!MULTIPLE_ENCODERS(encoders))
- type = DRM_MODE_CONNECTOR_DVID;
- else
- type = DRM_MODE_CONNECTOR_DVII;
- break;
- case OUTPUT_LVDS:
- type = DRM_MODE_CONNECTOR_LVDS;
-#if 0
- /* don't create i2c adapter when lvds ddc not allowed */
- if (dcbent->lvdsconf.use_straps_for_mode ||
- dev_priv->vbios->fp_no_ddc)
- i2c_index = 0xf;
-#endif
- break;
- case OUTPUT_TV:
- type = DRM_MODE_CONNECTOR_TV;
- break;
- default:
- type = DRM_MODE_CONNECTOR_Unknown;
- continue;
- }
-
- nouveau_connector_create(dev, dcbent->connector, type);
- }
+ for (i = 0; i < dcb->connector.entries; i++)
+ nouveau_connector_create(dev, &dcb->connector.entry[i]);
/* Save previous state */
NVLockVgaCrtcs(dev, false);
diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c
index d910873c1368..3da90c2c4e63 100644
--- a/drivers/gpu/drm/nouveau/nv04_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c
@@ -27,7 +27,7 @@
#include "nouveau_dma.h"
#include "nouveau_fbcon.h"
-static void
+void
nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
struct nouveau_fbcon_par *par = info->par;
@@ -54,7 +54,7 @@ nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
FIRE_RING(chan);
}
-static void
+void
nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct nouveau_fbcon_par *par = info->par;
@@ -88,7 +88,7 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
FIRE_RING(chan);
}
-static void
+void
nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct nouveau_fbcon_par *par = info->par;
@@ -118,7 +118,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
return;
}
- width = (image->width + 31) & ~31;
+ width = ALIGN(image->width, 32);
dsize = (width * image->height) >> 5;
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
@@ -307,9 +307,6 @@ nv04_fbcon_accel_init(struct fb_info *info)
FIRE_RING(chan);
- info->fbops->fb_fillrect = nv04_fbcon_fillrect;
- info->fbops->fb_copyarea = nv04_fbcon_copyarea;
- info->fbops->fb_imageblit = nv04_fbcon_imageblit;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c
index f31347b8c9b0..66fe55983b6e 100644
--- a/drivers/gpu/drm/nouveau/nv04_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv04_fifo.c
@@ -117,6 +117,7 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ unsigned long flags;
int ret;
ret = nouveau_gpuobj_new_fake(dev, NV04_RAMFC(chan->id), ~0,
@@ -127,6 +128,8 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
if (ret)
return ret;
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+
/* Setup initial state */
dev_priv->engine.instmem.prepare_access(dev, true);
RAMFC_WR(DMA_PUT, chan->pushbuf_base);
@@ -144,6 +147,8 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
/* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE,
nv_rd32(dev, NV04_PFIFO_MODE) | (1 << chan->id));
+
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c
index a20c206625a2..a3b9563a6f60 100644
--- a/drivers/gpu/drm/nouveau/nv04_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv04_instmem.c
@@ -30,7 +30,7 @@ nv04_instmem_determine_amount(struct drm_device *dev)
* of vram. For now, only reserve a small piece until we know
* more about what each chipset requires.
*/
- switch (dev_priv->chipset & 0xf0) {
+ switch (dev_priv->chipset) {
case 0x40:
case 0x47:
case 0x49:
diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c
index 9c63099e9c42..c4e3404337d4 100644
--- a/drivers/gpu/drm/nouveau/nv04_tv.c
+++ b/drivers/gpu/drm/nouveau/nv04_tv.c
@@ -262,7 +262,7 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
nv_encoder->or = ffs(entry->or) - 1;
/* Run the slave-specific initialization */
- adap = &dev_priv->vbios->dcb->i2c[i2c_index].chan->adapter;
+ adap = &dev_priv->vbios.dcb.i2c[i2c_index].chan->adapter;
was_locked = NVLockVgaCrtcs(dev, false);
diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c
index 58b917c3341b..74c880374fb9 100644
--- a/drivers/gpu/drm/nouveau/nv17_tv.c
+++ b/drivers/gpu/drm/nouveau/nv17_tv.c
@@ -45,8 +45,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
#define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20)
testval = RGB_TEST_DATA(0x82, 0xeb, 0x82);
- if (dev_priv->vbios->tvdactestval)
- testval = dev_priv->vbios->tvdactestval;
+ if (dev_priv->vbios.tvdactestval)
+ testval = dev_priv->vbios.tvdactestval;
dacclk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset);
head = (dacclk & 0x100) >> 8;
@@ -367,7 +367,7 @@ static void nv17_tv_prepare(struct drm_encoder *encoder)
!enc->crtc &&
nv04_dfp_get_bound_head(dev, dcb) == head) {
nv04_dfp_bind_head(dev, dcb, head ^ 1,
- dev_priv->VBIOS.fp.dual_link);
+ dev_priv->vbios.fp.dual_link);
}
}
@@ -579,6 +579,8 @@ static void nv17_tv_restore(struct drm_encoder *encoder)
nouveau_encoder(encoder)->restore.output);
nv17_tv_state_load(dev, &to_tv_enc(encoder)->saved_state);
+
+ nouveau_encoder(encoder)->last_dpms = NV_DPMS_CLEARED;
}
static int nv17_tv_create_resources(struct drm_encoder *encoder,
diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c
index b4f19ccb8b41..6b2ef4a9fce1 100644
--- a/drivers/gpu/drm/nouveau/nv40_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv40_fifo.c
@@ -37,6 +37,7 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t fc = NV40_RAMFC(chan->id);
+ unsigned long flags;
int ret;
ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(chan->id), ~0,
@@ -45,6 +46,8 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
if (ret)
return ret;
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+
dev_priv->engine.instmem.prepare_access(dev, true);
nv_wi32(dev, fc + 0, chan->pushbuf_base);
nv_wi32(dev, fc + 4, chan->pushbuf_base);
@@ -63,6 +66,8 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
/* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE,
nv_rd32(dev, NV04_PFIFO_MODE) | (1 << chan->id));
+
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index 118d3285fd8c..cfabeb974a56 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -298,14 +298,17 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
static void
nv50_crtc_destroy(struct drm_crtc *crtc)
{
- struct drm_device *dev = crtc->dev;
- struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-
- NV_DEBUG_KMS(dev, "\n");
+ struct drm_device *dev;
+ struct nouveau_crtc *nv_crtc;
if (!crtc)
return;
+ dev = crtc->dev;
+ nv_crtc = nouveau_crtc(crtc);
+
+ NV_DEBUG_KMS(dev, "\n");
+
drm_crtc_cleanup(&nv_crtc->base);
nv50_cursor_fini(nv_crtc);
@@ -355,9 +358,7 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
nv_crtc->cursor.show(nv_crtc, true);
out:
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gem);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(gem);
return ret;
}
@@ -432,6 +433,7 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct drm_encoder *encoder;
+ uint32_t dac = 0, sor = 0;
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
@@ -439,9 +441,28 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- if (drm_helper_encoder_in_use(encoder))
+ if (!drm_helper_encoder_in_use(encoder))
continue;
+ if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
+ nv_encoder->dcb->type == OUTPUT_TV)
+ dac |= (1 << nv_encoder->or);
+ else
+ sor |= (1 << nv_encoder->or);
+ }
+
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+
+ if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
+ nv_encoder->dcb->type == OUTPUT_TV) {
+ if (dac & (1 << nv_encoder->or))
+ continue;
+ } else {
+ if (sor & (1 << nv_encoder->or))
+ continue;
+ }
+
nv_encoder->disconnect(nv_encoder);
}
diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c
index f08f042a8e10..1fd9537beff6 100644
--- a/drivers/gpu/drm/nouveau/nv50_dac.c
+++ b/drivers/gpu/drm/nouveau/nv50_dac.c
@@ -79,8 +79,8 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
}
/* Use bios provided value if possible. */
- if (dev_priv->vbios->dactestval) {
- load_pattern = dev_priv->vbios->dactestval;
+ if (dev_priv->vbios.dactestval) {
+ load_pattern = dev_priv->vbios.dactestval;
NV_DEBUG_KMS(dev, "Using bios provided load_pattern of %d\n",
load_pattern);
} else {
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 90f0bf59fbcd..61a89f2dc553 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -370,9 +370,7 @@ nv50_display_init(struct drm_device *dev)
struct nouveau_connector *conn = nouveau_connector(connector);
struct dcb_gpio_entry *gpio;
- if (connector->connector_type != DRM_MODE_CONNECTOR_DVII &&
- connector->connector_type != DRM_MODE_CONNECTOR_DVID &&
- connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
+ if (conn->dcb->gpio_tag == 0xff)
continue;
gpio = nouveau_bios_gpio_entry(dev, conn->dcb->gpio_tag);
@@ -465,8 +463,7 @@ static int nv50_display_disable(struct drm_device *dev)
int nv50_display_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct parsed_dcb *dcb = dev_priv->vbios->dcb;
- uint32_t connector[16] = {};
+ struct dcb_table *dcb = &dev_priv->vbios.dcb;
int ret, i;
NV_DEBUG_KMS(dev, "\n");
@@ -522,44 +519,13 @@ int nv50_display_create(struct drm_device *dev)
NV_WARN(dev, "DCB encoder %d unknown\n", entry->type);
continue;
}
-
- connector[entry->connector] |= (1 << entry->type);
}
- /* It appears that DCB 3.0+ VBIOS has a connector table, however,
- * I'm not 100% certain how to decode it correctly yet so just
- * look at what encoders are present on each connector index and
- * attempt to derive the connector type from that.
- */
- for (i = 0 ; i < dcb->entries; i++) {
- struct dcb_entry *entry = &dcb->entry[i];
- uint16_t encoders;
- int type;
-
- encoders = connector[entry->connector];
- if (!(encoders & (1 << entry->type)))
+ for (i = 0 ; i < dcb->connector.entries; i++) {
+ if (i != 0 && dcb->connector.entry[i].index ==
+ dcb->connector.entry[i - 1].index)
continue;
- connector[entry->connector] = 0;
-
- if (encoders & (1 << OUTPUT_DP)) {
- type = DRM_MODE_CONNECTOR_DisplayPort;
- } else if (encoders & (1 << OUTPUT_TMDS)) {
- if (encoders & (1 << OUTPUT_ANALOG))
- type = DRM_MODE_CONNECTOR_DVII;
- else
- type = DRM_MODE_CONNECTOR_DVID;
- } else if (encoders & (1 << OUTPUT_ANALOG)) {
- type = DRM_MODE_CONNECTOR_VGA;
- } else if (encoders & (1 << OUTPUT_LVDS)) {
- type = DRM_MODE_CONNECTOR_LVDS;
- } else {
- type = DRM_MODE_CONNECTOR_Unknown;
- }
-
- if (type == DRM_MODE_CONNECTOR_Unknown)
- continue;
-
- nouveau_connector_create(dev, entry->connector, type);
+ nouveau_connector_create(dev, &dcb->connector.entry[i]);
}
ret = nv50_display_init(dev);
@@ -667,8 +633,8 @@ nv50_display_irq_head(struct drm_device *dev, int *phead,
return -1;
}
- for (i = 0; i < dev_priv->vbios->dcb->entries; i++) {
- struct dcb_entry *dcbent = &dev_priv->vbios->dcb->entry[i];
+ for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
+ struct dcb_entry *dcbent = &dev_priv->vbios.dcb.entry[i];
if (dcbent->type != type)
continue;
@@ -692,7 +658,7 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent,
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = NULL;
struct drm_encoder *encoder;
- struct nvbios *bios = &dev_priv->VBIOS;
+ struct nvbios *bios = &dev_priv->vbios;
uint32_t mc, script = 0, or;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
@@ -710,7 +676,7 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent,
switch (dcbent->type) {
case OUTPUT_LVDS:
script = (mc >> 8) & 0xf;
- if (bios->pub.fp_no_ddc) {
+ if (bios->fp_no_ddc) {
if (bios->fp.dual_link)
script |= 0x0100;
if (bios->fp.if_is_24bit)
diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c
index e4f279ee61cf..993c7126fbde 100644
--- a/drivers/gpu/drm/nouveau/nv50_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c
@@ -3,7 +3,7 @@
#include "nouveau_dma.h"
#include "nouveau_fbcon.h"
-static void
+void
nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct nouveau_fbcon_par *par = info->par;
@@ -46,7 +46,7 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
FIRE_RING(chan);
}
-static void
+void
nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
struct nouveau_fbcon_par *par = info->par;
@@ -81,7 +81,7 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
FIRE_RING(chan);
}
-static void
+void
nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct nouveau_fbcon_par *par = info->par;
@@ -109,7 +109,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
return;
}
- width = (image->width + 31) & ~31;
+ width = ALIGN(image->width, 32);
dwords = (width * image->height) >> 5;
BEGIN_RING(chan, NvSub2D, 0x0814, 2);
@@ -262,9 +262,6 @@ nv50_fbcon_accel_init(struct fb_info *info)
OUT_RING(chan, info->fix.smem_start - dev_priv->fb_phys +
dev_priv->vm_vram_base);
- info->fbops->fb_fillrect = nv50_fbcon_fillrect;
- info->fbops->fb_copyarea = nv50_fbcon_copyarea;
- info->fbops->fb_imageblit = nv50_fbcon_imageblit;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c
index 39caf167587d..e20c0e2474f3 100644
--- a/drivers/gpu/drm/nouveau/nv50_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv50_fifo.c
@@ -243,6 +243,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ramfc = NULL;
+ unsigned long flags;
int ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
@@ -272,25 +273,27 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
return ret;
ramfc = chan->ramfc->gpuobj;
- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 4096, 256,
+ ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 4096, 1024,
0, &chan->cache);
if (ret)
return ret;
}
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+
dev_priv->engine.instmem.prepare_access(dev, true);
- nv_wo32(dev, ramfc, 0x08/4, chan->pushbuf_base);
- nv_wo32(dev, ramfc, 0x10/4, chan->pushbuf_base);
nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4);
nv_wo32(dev, ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4));
- nv_wo32(dev, ramfc, 0x3c/4, 0x00086078);
nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff);
nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff);
nv_wo32(dev, ramfc, 0x40/4, 0x00000000);
nv_wo32(dev, ramfc, 0x7c/4, 0x30000001);
nv_wo32(dev, ramfc, 0x78/4, 0x00000000);
- nv_wo32(dev, ramfc, 0x4c/4, 0xffffffff);
+ nv_wo32(dev, ramfc, 0x3c/4, 0x403f6078);
+ nv_wo32(dev, ramfc, 0x50/4, chan->pushbuf_base +
+ chan->dma.ib_base * 4);
+ nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16);
if (!IS_G80) {
nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id);
@@ -306,10 +309,12 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
ret = nv50_fifo_channel_enable(dev, chan->id, false);
if (ret) {
NV_ERROR(dev, "error enabling ch%d: %d\n", chan->id, ret);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
nouveau_gpuobj_ref_del(dev, &chan->ramfc);
return ret;
}
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return 0;
}
@@ -317,17 +322,20 @@ void
nv50_fifo_destroy_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
+ struct nouveau_gpuobj_ref *ramfc = chan->ramfc;
NV_DEBUG(dev, "ch%d\n", chan->id);
- nouveau_gpuobj_ref_del(dev, &chan->ramfc);
- nouveau_gpuobj_ref_del(dev, &chan->cache);
-
+ /* This will ensure the channel is seen as disabled. */
+ chan->ramfc = NULL;
nv50_fifo_channel_disable(dev, chan->id, false);
/* Dummy channel, also used on ch 127 */
if (chan->id == 0)
nv50_fifo_channel_disable(dev, 127, false);
+
+ nouveau_gpuobj_ref_del(dev, &ramfc);
+ nouveau_gpuobj_ref_del(dev, &chan->cache);
}
int
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index ca79f32be44c..857a09671a39 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -28,30 +28,7 @@
#include "drm.h"
#include "nouveau_drv.h"
-MODULE_FIRMWARE("nouveau/nv50.ctxprog");
-MODULE_FIRMWARE("nouveau/nv50.ctxvals");
-MODULE_FIRMWARE("nouveau/nv84.ctxprog");
-MODULE_FIRMWARE("nouveau/nv84.ctxvals");
-MODULE_FIRMWARE("nouveau/nv86.ctxprog");
-MODULE_FIRMWARE("nouveau/nv86.ctxvals");
-MODULE_FIRMWARE("nouveau/nv92.ctxprog");
-MODULE_FIRMWARE("nouveau/nv92.ctxvals");
-MODULE_FIRMWARE("nouveau/nv94.ctxprog");
-MODULE_FIRMWARE("nouveau/nv94.ctxvals");
-MODULE_FIRMWARE("nouveau/nv96.ctxprog");
-MODULE_FIRMWARE("nouveau/nv96.ctxvals");
-MODULE_FIRMWARE("nouveau/nv98.ctxprog");
-MODULE_FIRMWARE("nouveau/nv98.ctxvals");
-MODULE_FIRMWARE("nouveau/nva0.ctxprog");
-MODULE_FIRMWARE("nouveau/nva0.ctxvals");
-MODULE_FIRMWARE("nouveau/nva5.ctxprog");
-MODULE_FIRMWARE("nouveau/nva5.ctxvals");
-MODULE_FIRMWARE("nouveau/nva8.ctxprog");
-MODULE_FIRMWARE("nouveau/nva8.ctxvals");
-MODULE_FIRMWARE("nouveau/nvaa.ctxprog");
-MODULE_FIRMWARE("nouveau/nvaa.ctxvals");
-MODULE_FIRMWARE("nouveau/nvac.ctxprog");
-MODULE_FIRMWARE("nouveau/nvac.ctxvals");
+#include "nouveau_grctx.h"
#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
@@ -84,7 +61,7 @@ nv50_graph_init_regs__nv(struct drm_device *dev)
nv_wr32(dev, 0x400804, 0xc0000000);
nv_wr32(dev, 0x406800, 0xc0000000);
nv_wr32(dev, 0x400c04, 0xc0000000);
- nv_wr32(dev, 0x401804, 0xc0000000);
+ nv_wr32(dev, 0x401800, 0xc0000000);
nv_wr32(dev, 0x405018, 0xc0000000);
nv_wr32(dev, 0x402000, 0xc0000000);
@@ -111,9 +88,34 @@ nv50_graph_init_ctxctl(struct drm_device *dev)
NV_DEBUG(dev, "\n");
- nouveau_grctx_prog_load(dev);
- if (!dev_priv->engine.graph.ctxprog)
- dev_priv->engine.graph.accel_blocked = true;
+ if (nouveau_ctxfw) {
+ nouveau_grctx_prog_load(dev);
+ dev_priv->engine.graph.grctx_size = 0x70000;
+ }
+ if (!dev_priv->engine.graph.ctxprog) {
+ struct nouveau_grctx ctx = {};
+ uint32_t *cp = kmalloc(512 * 4, GFP_KERNEL);
+ int i;
+ if (!cp) {
+ NV_ERROR(dev, "Couldn't alloc ctxprog! Disabling acceleration.\n");
+ dev_priv->engine.graph.accel_blocked = true;
+ return 0;
+ }
+ ctx.dev = dev;
+ ctx.mode = NOUVEAU_GRCTX_PROG;
+ ctx.data = cp;
+ ctx.ctxprog_max = 512;
+ if (!nv50_grctx_init(&ctx)) {
+ dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
+
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+ for (i = 0; i < ctx.ctxprog_len; i++)
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
+ } else {
+ dev_priv->engine.graph.accel_blocked = true;
+ }
+ kfree(cp);
+ }
nv_wr32(dev, 0x400320, 4);
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0);
@@ -165,6 +167,12 @@ nv50_graph_channel(struct drm_device *dev)
uint32_t inst;
int i;
+ /* Be sure we're not in the middle of a context switch or bad things
+ * will happen, such as unloading the wrong pgraph context.
+ */
+ if (!nv_wait(0x400300, 0x00000001, 0x00000000))
+ NV_ERROR(dev, "Ctxprog is still running\n");
+
inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
return NULL;
@@ -187,13 +195,13 @@ nv50_graph_create_context(struct nouveau_channel *chan)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
struct nouveau_gpuobj *ctx;
- uint32_t grctx_size = 0x70000;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
int hdr, ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, grctx_size, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC |
+ ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
+ 0x1000, NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
if (ret)
return ret;
@@ -203,7 +211,7 @@ nv50_graph_create_context(struct nouveau_channel *chan)
dev_priv->engine.instmem.prepare_access(dev, true);
nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002);
nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance +
- grctx_size - 1);
+ pgraph->grctx_size - 1);
nv_wo32(dev, ramin, (hdr + 0x08)/4, chan->ramin_grctx->instance);
nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0);
nv_wo32(dev, ramin, (hdr + 0x10)/4, 0);
@@ -211,7 +219,15 @@ nv50_graph_create_context(struct nouveau_channel *chan)
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.prepare_access(dev, true);
- nouveau_grctx_vals_load(dev, ctx);
+ if (!pgraph->ctxprog) {
+ struct nouveau_grctx ctx = {};
+ ctx.dev = chan->dev;
+ ctx.mode = NOUVEAU_GRCTX_VALS;
+ ctx.data = chan->ramin_grctx->gpuobj;
+ nv50_grctx_init(&ctx);
+ } else {
+ nouveau_grctx_vals_load(dev, ctx);
+ }
nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12);
if ((dev_priv->chipset & 0xf0) == 0xa0)
nv_wo32(dev, ctx, 0x00004/4, 0x00000000);
@@ -275,19 +291,18 @@ nv50_graph_load_context(struct nouveau_channel *chan)
int
nv50_graph_unload_context(struct drm_device *dev)
{
- uint32_t inst, fifo = nv_rd32(dev, 0x400500);
+ uint32_t inst;
inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
return 0;
inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE;
- nv_wr32(dev, 0x400500, fifo & ~1);
+ nouveau_wait_for_idle(dev);
nv_wr32(dev, 0x400784, inst);
nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20);
nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01);
nouveau_wait_for_idle(dev);
- nv_wr32(dev, 0x400500, fifo);
nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst);
return 0;
diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c
new file mode 100644
index 000000000000..d105fcd42ca0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv50_grctx.c
@@ -0,0 +1,2367 @@
+/*
+ * Copyright 2009 Marcin Kościelnicki
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ */
+
+#define CP_FLAG_CLEAR 0
+#define CP_FLAG_SET 1
+#define CP_FLAG_SWAP_DIRECTION ((0 * 32) + 0)
+#define CP_FLAG_SWAP_DIRECTION_LOAD 0
+#define CP_FLAG_SWAP_DIRECTION_SAVE 1
+#define CP_FLAG_UNK01 ((0 * 32) + 1)
+#define CP_FLAG_UNK01_CLEAR 0
+#define CP_FLAG_UNK01_SET 1
+#define CP_FLAG_UNK03 ((0 * 32) + 3)
+#define CP_FLAG_UNK03_CLEAR 0
+#define CP_FLAG_UNK03_SET 1
+#define CP_FLAG_USER_SAVE ((0 * 32) + 5)
+#define CP_FLAG_USER_SAVE_NOT_PENDING 0
+#define CP_FLAG_USER_SAVE_PENDING 1
+#define CP_FLAG_USER_LOAD ((0 * 32) + 6)
+#define CP_FLAG_USER_LOAD_NOT_PENDING 0
+#define CP_FLAG_USER_LOAD_PENDING 1
+#define CP_FLAG_UNK0B ((0 * 32) + 0xb)
+#define CP_FLAG_UNK0B_CLEAR 0
+#define CP_FLAG_UNK0B_SET 1
+#define CP_FLAG_UNK1D ((0 * 32) + 0x1d)
+#define CP_FLAG_UNK1D_CLEAR 0
+#define CP_FLAG_UNK1D_SET 1
+#define CP_FLAG_UNK20 ((1 * 32) + 0)
+#define CP_FLAG_UNK20_CLEAR 0
+#define CP_FLAG_UNK20_SET 1
+#define CP_FLAG_STATUS ((2 * 32) + 0)
+#define CP_FLAG_STATUS_BUSY 0
+#define CP_FLAG_STATUS_IDLE 1
+#define CP_FLAG_AUTO_SAVE ((2 * 32) + 4)
+#define CP_FLAG_AUTO_SAVE_NOT_PENDING 0
+#define CP_FLAG_AUTO_SAVE_PENDING 1
+#define CP_FLAG_AUTO_LOAD ((2 * 32) + 5)
+#define CP_FLAG_AUTO_LOAD_NOT_PENDING 0
+#define CP_FLAG_AUTO_LOAD_PENDING 1
+#define CP_FLAG_XFER ((2 * 32) + 11)
+#define CP_FLAG_XFER_IDLE 0
+#define CP_FLAG_XFER_BUSY 1
+#define CP_FLAG_NEWCTX ((2 * 32) + 12)
+#define CP_FLAG_NEWCTX_BUSY 0
+#define CP_FLAG_NEWCTX_DONE 1
+#define CP_FLAG_ALWAYS ((2 * 32) + 13)
+#define CP_FLAG_ALWAYS_FALSE 0
+#define CP_FLAG_ALWAYS_TRUE 1
+
+#define CP_CTX 0x00100000
+#define CP_CTX_COUNT 0x000f0000
+#define CP_CTX_COUNT_SHIFT 16
+#define CP_CTX_REG 0x00003fff
+#define CP_LOAD_SR 0x00200000
+#define CP_LOAD_SR_VALUE 0x000fffff
+#define CP_BRA 0x00400000
+#define CP_BRA_IP 0x0001ff00
+#define CP_BRA_IP_SHIFT 8
+#define CP_BRA_IF_CLEAR 0x00000080
+#define CP_BRA_FLAG 0x0000007f
+#define CP_WAIT 0x00500000
+#define CP_WAIT_SET 0x00000080
+#define CP_WAIT_FLAG 0x0000007f
+#define CP_SET 0x00700000
+#define CP_SET_1 0x00000080
+#define CP_SET_FLAG 0x0000007f
+#define CP_NEWCTX 0x00600004
+#define CP_NEXT_TO_SWAP 0x00600005
+#define CP_SET_CONTEXT_POINTER 0x00600006
+#define CP_SET_XFER_POINTER 0x00600007
+#define CP_ENABLE 0x00600009
+#define CP_END 0x0060000c
+#define CP_NEXT_TO_CURRENT 0x0060000d
+#define CP_DISABLE1 0x0090ffff
+#define CP_DISABLE2 0x0091ffff
+#define CP_XFER_1 0x008000ff
+#define CP_XFER_2 0x008800ff
+#define CP_SEEK_1 0x00c000ff
+#define CP_SEEK_2 0x00c800ff
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_grctx.h"
+
+/*
+ * This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's
+ * the GPU itself that does context-switching, but it needs a special
+ * microcode to do it. And it's the driver's task to supply this microcode,
+ * further known as ctxprog, as well as the initial context values, known
+ * as ctxvals.
+ *
+ * Without ctxprog, you cannot switch contexts. Not even in software, since
+ * the majority of context [xfer strands] isn't accessible directly. You're
+ * stuck with a single channel, and you also suffer all the problems resulting
+ * from missing ctxvals, since you cannot load them.
+ *
+ * Without ctxvals, you're stuck with PGRAPH's default context. It's enough to
+ * run 2d operations, but trying to utilise 3d or CUDA will just lock you up,
+ * since you don't have... some sort of needed setup.
+ *
+ * Nouveau will just disable acceleration if not given ctxprog + ctxvals, since
+ * it's too much hassle to handle no-ctxprog as a special case.
+ */
+
+/*
+ * How ctxprogs work.
+ *
+ * The ctxprog is written in its own kind of microcode, with very small and
+ * crappy set of available commands. You upload it to a small [512 insns]
+ * area of memory on PGRAPH, and it'll be run when PFIFO wants PGRAPH to
+ * switch channel. or when the driver explicitely requests it. Stuff visible
+ * to ctxprog consists of: PGRAPH MMIO registers, PGRAPH context strands,
+ * the per-channel context save area in VRAM [known as ctxvals or grctx],
+ * 4 flags registers, a scratch register, two grctx pointers, plus many
+ * random poorly-understood details.
+ *
+ * When ctxprog runs, it's supposed to check what operations are asked of it,
+ * save old context if requested, optionally reset PGRAPH and switch to the
+ * new channel, and load the new context. Context consists of three major
+ * parts: subset of MMIO registers and two "xfer areas".
+ */
+
+/* TODO:
+ * - document unimplemented bits compared to nvidia
+ * - NVAx: make a TP subroutine, use it.
+ * - use 0x4008fc instead of 0x1540?
+ */
+
+enum cp_label {
+ cp_check_load = 1,
+ cp_setup_auto_load,
+ cp_setup_load,
+ cp_setup_save,
+ cp_swap_state,
+ cp_prepare_exit,
+ cp_exit,
+};
+
+static void nv50_graph_construct_mmio(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_xfer1(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_xfer2(struct nouveau_grctx *ctx);
+
+/* Main function: construct the ctxprog skeleton, call the other functions. */
+
+int
+nv50_grctx_init(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+
+ switch (dev_priv->chipset) {
+ case 0x50:
+ case 0x84:
+ case 0x86:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0x98:
+ case 0xa0:
+ case 0xa5:
+ case 0xa8:
+ case 0xaa:
+ case 0xac:
+ break;
+ default:
+ NV_ERROR(ctx->dev, "I don't know how to make a ctxprog for "
+ "your NV%x card.\n", dev_priv->chipset);
+ NV_ERROR(ctx->dev, "Disabling acceleration. Please contact "
+ "the devs.\n");
+ return -ENOSYS;
+ }
+ /* decide whether we're loading/unloading the context */
+ cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
+ cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);
+
+ cp_name(ctx, cp_check_load);
+ cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
+ cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
+ cp_bra (ctx, ALWAYS, TRUE, cp_exit);
+
+ /* setup for context load */
+ cp_name(ctx, cp_setup_auto_load);
+ cp_out (ctx, CP_DISABLE1);
+ cp_out (ctx, CP_DISABLE2);
+ cp_out (ctx, CP_ENABLE);
+ cp_out (ctx, CP_NEXT_TO_SWAP);
+ cp_set (ctx, UNK01, SET);
+ cp_name(ctx, cp_setup_load);
+ cp_out (ctx, CP_NEWCTX);
+ cp_wait(ctx, NEWCTX, BUSY);
+ cp_set (ctx, UNK1D, CLEAR);
+ cp_set (ctx, SWAP_DIRECTION, LOAD);
+ cp_bra (ctx, UNK0B, SET, cp_prepare_exit);
+ cp_bra (ctx, ALWAYS, TRUE, cp_swap_state);
+
+ /* setup for context save */
+ cp_name(ctx, cp_setup_save);
+ cp_set (ctx, UNK1D, SET);
+ cp_wait(ctx, STATUS, BUSY);
+ cp_set (ctx, UNK01, SET);
+ cp_set (ctx, SWAP_DIRECTION, SAVE);
+
+ /* general PGRAPH state */
+ cp_name(ctx, cp_swap_state);
+ cp_set (ctx, UNK03, SET);
+ cp_pos (ctx, 0x00004/4);
+ cp_ctx (ctx, 0x400828, 1); /* needed. otherwise, flickering happens. */
+ cp_pos (ctx, 0x00100/4);
+ nv50_graph_construct_mmio(ctx);
+ nv50_graph_construct_xfer1(ctx);
+ nv50_graph_construct_xfer2(ctx);
+
+ cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load);
+
+ cp_set (ctx, UNK20, SET);
+ cp_set (ctx, SWAP_DIRECTION, SAVE); /* no idea why this is needed, but fixes at least one lockup. */
+ cp_lsr (ctx, ctx->ctxvals_base);
+ cp_out (ctx, CP_SET_XFER_POINTER);
+ cp_lsr (ctx, 4);
+ cp_out (ctx, CP_SEEK_1);
+ cp_out (ctx, CP_XFER_1);
+ cp_wait(ctx, XFER, BUSY);
+
+ /* pre-exit state updates */
+ cp_name(ctx, cp_prepare_exit);
+ cp_set (ctx, UNK01, CLEAR);
+ cp_set (ctx, UNK03, CLEAR);
+ cp_set (ctx, UNK1D, CLEAR);
+
+ cp_bra (ctx, USER_SAVE, PENDING, cp_exit);
+ cp_out (ctx, CP_NEXT_TO_CURRENT);
+
+ cp_name(ctx, cp_exit);
+ cp_set (ctx, USER_SAVE, NOT_PENDING);
+ cp_set (ctx, USER_LOAD, NOT_PENDING);
+ cp_out (ctx, CP_END);
+ ctx->ctxvals_pos += 0x400; /* padding... no idea why you need it */
+
+ return 0;
+}
+
+/*
+ * Constructs MMIO part of ctxprog and ctxvals. Just a matter of knowing which
+ * registers to save/restore and the default values for them.
+ */
+
+static void
+nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ int i, j;
+ int offset, base;
+ uint32_t units = nv_rd32 (ctx->dev, 0x1540);
+
+ /* 0800 */
+ cp_ctx(ctx, 0x400808, 7);
+ gr_def(ctx, 0x400814, 0x00000030);
+ cp_ctx(ctx, 0x400834, 0x32);
+ if (dev_priv->chipset == 0x50) {
+ gr_def(ctx, 0x400834, 0xff400040);
+ gr_def(ctx, 0x400838, 0xfff00080);
+ gr_def(ctx, 0x40083c, 0xfff70090);
+ gr_def(ctx, 0x400840, 0xffe806a8);
+ }
+ gr_def(ctx, 0x400844, 0x00000002);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ gr_def(ctx, 0x400894, 0x00001000);
+ gr_def(ctx, 0x4008e8, 0x00000003);
+ gr_def(ctx, 0x4008ec, 0x00001000);
+ if (dev_priv->chipset == 0x50)
+ cp_ctx(ctx, 0x400908, 0xb);
+ else if (dev_priv->chipset < 0xa0)
+ cp_ctx(ctx, 0x400908, 0xc);
+ else
+ cp_ctx(ctx, 0x400908, 0xe);
+
+ if (dev_priv->chipset >= 0xa0)
+ cp_ctx(ctx, 0x400b00, 0x1);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+ cp_ctx(ctx, 0x400b10, 0x1);
+ gr_def(ctx, 0x400b10, 0x0001629d);
+ cp_ctx(ctx, 0x400b20, 0x1);
+ gr_def(ctx, 0x400b20, 0x0001629d);
+ }
+
+ /* 0C00 */
+ cp_ctx(ctx, 0x400c08, 0x2);
+ gr_def(ctx, 0x400c08, 0x0000fe0c);
+
+ /* 1000 */
+ if (dev_priv->chipset < 0xa0) {
+ cp_ctx(ctx, 0x401008, 0x4);
+ gr_def(ctx, 0x401014, 0x00001000);
+ } else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa) {
+ cp_ctx(ctx, 0x401008, 0x5);
+ gr_def(ctx, 0x401018, 0x00001000);
+ } else {
+ cp_ctx(ctx, 0x401008, 0x5);
+ gr_def(ctx, 0x401018, 0x00004000);
+ }
+
+ /* 1400 */
+ cp_ctx(ctx, 0x401400, 0x8);
+ cp_ctx(ctx, 0x401424, 0x3);
+ if (dev_priv->chipset == 0x50)
+ gr_def(ctx, 0x40142c, 0x0001fd87);
+ else
+ gr_def(ctx, 0x40142c, 0x00000187);
+ cp_ctx(ctx, 0x401540, 0x5);
+ gr_def(ctx, 0x401550, 0x00001018);
+
+ /* 1800 */
+ cp_ctx(ctx, 0x401814, 0x1);
+ gr_def(ctx, 0x401814, 0x000000ff);
+ if (dev_priv->chipset == 0x50) {
+ cp_ctx(ctx, 0x40181c, 0xe);
+ gr_def(ctx, 0x401850, 0x00000004);
+ } else if (dev_priv->chipset < 0xa0) {
+ cp_ctx(ctx, 0x40181c, 0xf);
+ gr_def(ctx, 0x401854, 0x00000004);
+ } else {
+ cp_ctx(ctx, 0x40181c, 0x13);
+ gr_def(ctx, 0x401864, 0x00000004);
+ }
+
+ /* 1C00 */
+ cp_ctx(ctx, 0x401c00, 0x1);
+ switch (dev_priv->chipset) {
+ case 0x50:
+ gr_def(ctx, 0x401c00, 0x0001005f);
+ break;
+ case 0x84:
+ case 0x86:
+ case 0x94:
+ gr_def(ctx, 0x401c00, 0x044d00df);
+ break;
+ case 0x92:
+ case 0x96:
+ case 0x98:
+ case 0xa0:
+ case 0xaa:
+ case 0xac:
+ gr_def(ctx, 0x401c00, 0x042500df);
+ break;
+ case 0xa5:
+ case 0xa8:
+ gr_def(ctx, 0x401c00, 0x142500df);
+ break;
+ }
+
+ /* 2400 */
+ cp_ctx(ctx, 0x402400, 0x1);
+ if (dev_priv->chipset == 0x50)
+ cp_ctx(ctx, 0x402408, 0x1);
+ else
+ cp_ctx(ctx, 0x402408, 0x2);
+ gr_def(ctx, 0x402408, 0x00000600);
+
+ /* 2800 */
+ cp_ctx(ctx, 0x402800, 0x1);
+ if (dev_priv->chipset == 0x50)
+ gr_def(ctx, 0x402800, 0x00000006);
+
+ /* 2C00 */
+ cp_ctx(ctx, 0x402c08, 0x6);
+ if (dev_priv->chipset != 0x50)
+ gr_def(ctx, 0x402c14, 0x01000000);
+ gr_def(ctx, 0x402c18, 0x000000ff);
+ if (dev_priv->chipset == 0x50)
+ cp_ctx(ctx, 0x402ca0, 0x1);
+ else
+ cp_ctx(ctx, 0x402ca0, 0x2);
+ if (dev_priv->chipset < 0xa0)
+ gr_def(ctx, 0x402ca0, 0x00000400);
+ else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa)
+ gr_def(ctx, 0x402ca0, 0x00000800);
+ else
+ gr_def(ctx, 0x402ca0, 0x00000400);
+ cp_ctx(ctx, 0x402cac, 0x4);
+
+ /* 3000 */
+ cp_ctx(ctx, 0x403004, 0x1);
+ gr_def(ctx, 0x403004, 0x00000001);
+
+ /* 3404 */
+ if (dev_priv->chipset >= 0xa0) {
+ cp_ctx(ctx, 0x403404, 0x1);
+ gr_def(ctx, 0x403404, 0x00000001);
+ }
+
+ /* 5000 */
+ cp_ctx(ctx, 0x405000, 0x1);
+ switch (dev_priv->chipset) {
+ case 0x50:
+ gr_def(ctx, 0x405000, 0x00300080);
+ break;
+ case 0x84:
+ case 0xa0:
+ case 0xa5:
+ case 0xa8:
+ case 0xaa:
+ case 0xac:
+ gr_def(ctx, 0x405000, 0x000e0080);
+ break;
+ case 0x86:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0x98:
+ gr_def(ctx, 0x405000, 0x00000080);
+ break;
+ }
+ cp_ctx(ctx, 0x405014, 0x1);
+ gr_def(ctx, 0x405014, 0x00000004);
+ cp_ctx(ctx, 0x40501c, 0x1);
+ cp_ctx(ctx, 0x405024, 0x1);
+ cp_ctx(ctx, 0x40502c, 0x1);
+
+ /* 5400 or maybe 4800 */
+ if (dev_priv->chipset == 0x50) {
+ offset = 0x405400;
+ cp_ctx(ctx, 0x405400, 0xea);
+ } else if (dev_priv->chipset < 0x94) {
+ offset = 0x405400;
+ cp_ctx(ctx, 0x405400, 0xcb);
+ } else if (dev_priv->chipset < 0xa0) {
+ offset = 0x405400;
+ cp_ctx(ctx, 0x405400, 0xcc);
+ } else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+ offset = 0x404800;
+ cp_ctx(ctx, 0x404800, 0xda);
+ } else {
+ offset = 0x405400;
+ cp_ctx(ctx, 0x405400, 0xd4);
+ }
+ gr_def(ctx, offset + 0x0c, 0x00000002);
+ gr_def(ctx, offset + 0x10, 0x00000001);
+ if (dev_priv->chipset >= 0x94)
+ offset += 4;
+ gr_def(ctx, offset + 0x1c, 0x00000001);
+ gr_def(ctx, offset + 0x20, 0x00000100);
+ gr_def(ctx, offset + 0x38, 0x00000002);
+ gr_def(ctx, offset + 0x3c, 0x00000001);
+ gr_def(ctx, offset + 0x40, 0x00000001);
+ gr_def(ctx, offset + 0x50, 0x00000001);
+ gr_def(ctx, offset + 0x54, 0x003fffff);
+ gr_def(ctx, offset + 0x58, 0x00001fff);
+ gr_def(ctx, offset + 0x60, 0x00000001);
+ gr_def(ctx, offset + 0x64, 0x00000001);
+ gr_def(ctx, offset + 0x6c, 0x00000001);
+ gr_def(ctx, offset + 0x70, 0x00000001);
+ gr_def(ctx, offset + 0x74, 0x00000001);
+ gr_def(ctx, offset + 0x78, 0x00000004);
+ gr_def(ctx, offset + 0x7c, 0x00000001);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ offset += 4;
+ gr_def(ctx, offset + 0x80, 0x00000001);
+ gr_def(ctx, offset + 0x84, 0x00000001);
+ gr_def(ctx, offset + 0x88, 0x00000007);
+ gr_def(ctx, offset + 0x8c, 0x00000001);
+ gr_def(ctx, offset + 0x90, 0x00000007);
+ gr_def(ctx, offset + 0x94, 0x00000001);
+ gr_def(ctx, offset + 0x98, 0x00000001);
+ gr_def(ctx, offset + 0x9c, 0x00000001);
+ if (dev_priv->chipset == 0x50) {
+ gr_def(ctx, offset + 0xb0, 0x00000001);
+ gr_def(ctx, offset + 0xb4, 0x00000001);
+ gr_def(ctx, offset + 0xbc, 0x00000001);
+ gr_def(ctx, offset + 0xc0, 0x0000000a);
+ gr_def(ctx, offset + 0xd0, 0x00000040);
+ gr_def(ctx, offset + 0xd8, 0x00000002);
+ gr_def(ctx, offset + 0xdc, 0x00000100);
+ gr_def(ctx, offset + 0xe0, 0x00000001);
+ gr_def(ctx, offset + 0xe4, 0x00000100);
+ gr_def(ctx, offset + 0x100, 0x00000001);
+ gr_def(ctx, offset + 0x124, 0x00000004);
+ gr_def(ctx, offset + 0x13c, 0x00000001);
+ gr_def(ctx, offset + 0x140, 0x00000100);
+ gr_def(ctx, offset + 0x148, 0x00000001);
+ gr_def(ctx, offset + 0x154, 0x00000100);
+ gr_def(ctx, offset + 0x158, 0x00000001);
+ gr_def(ctx, offset + 0x15c, 0x00000100);
+ gr_def(ctx, offset + 0x164, 0x00000001);
+ gr_def(ctx, offset + 0x170, 0x00000100);
+ gr_def(ctx, offset + 0x174, 0x00000001);
+ gr_def(ctx, offset + 0x17c, 0x00000001);
+ gr_def(ctx, offset + 0x188, 0x00000002);
+ gr_def(ctx, offset + 0x190, 0x00000001);
+ gr_def(ctx, offset + 0x198, 0x00000001);
+ gr_def(ctx, offset + 0x1ac, 0x00000003);
+ offset += 0xd0;
+ } else {
+ gr_def(ctx, offset + 0xb0, 0x00000001);
+ gr_def(ctx, offset + 0xb4, 0x00000100);
+ gr_def(ctx, offset + 0xbc, 0x00000001);
+ gr_def(ctx, offset + 0xc8, 0x00000100);
+ gr_def(ctx, offset + 0xcc, 0x00000001);
+ gr_def(ctx, offset + 0xd0, 0x00000100);
+ gr_def(ctx, offset + 0xd8, 0x00000001);
+ gr_def(ctx, offset + 0xe4, 0x00000100);
+ }
+ gr_def(ctx, offset + 0xf8, 0x00000004);
+ gr_def(ctx, offset + 0xfc, 0x00000070);
+ gr_def(ctx, offset + 0x100, 0x00000080);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ offset += 4;
+ gr_def(ctx, offset + 0x114, 0x0000000c);
+ if (dev_priv->chipset == 0x50)
+ offset -= 4;
+ gr_def(ctx, offset + 0x11c, 0x00000008);
+ gr_def(ctx, offset + 0x120, 0x00000014);
+ if (dev_priv->chipset == 0x50) {
+ gr_def(ctx, offset + 0x124, 0x00000026);
+ offset -= 0x18;
+ } else {
+ gr_def(ctx, offset + 0x128, 0x00000029);
+ gr_def(ctx, offset + 0x12c, 0x00000027);
+ gr_def(ctx, offset + 0x130, 0x00000026);
+ gr_def(ctx, offset + 0x134, 0x00000008);
+ gr_def(ctx, offset + 0x138, 0x00000004);
+ gr_def(ctx, offset + 0x13c, 0x00000027);
+ }
+ gr_def(ctx, offset + 0x148, 0x00000001);
+ gr_def(ctx, offset + 0x14c, 0x00000002);
+ gr_def(ctx, offset + 0x150, 0x00000003);
+ gr_def(ctx, offset + 0x154, 0x00000004);
+ gr_def(ctx, offset + 0x158, 0x00000005);
+ gr_def(ctx, offset + 0x15c, 0x00000006);
+ gr_def(ctx, offset + 0x160, 0x00000007);
+ gr_def(ctx, offset + 0x164, 0x00000001);
+ gr_def(ctx, offset + 0x1a8, 0x000000cf);
+ if (dev_priv->chipset == 0x50)
+ offset -= 4;
+ gr_def(ctx, offset + 0x1d8, 0x00000080);
+ gr_def(ctx, offset + 0x1dc, 0x00000004);
+ gr_def(ctx, offset + 0x1e0, 0x00000004);
+ if (dev_priv->chipset == 0x50)
+ offset -= 4;
+ else
+ gr_def(ctx, offset + 0x1e4, 0x00000003);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+ gr_def(ctx, offset + 0x1ec, 0x00000003);
+ offset += 8;
+ }
+ gr_def(ctx, offset + 0x1e8, 0x00000001);
+ if (dev_priv->chipset == 0x50)
+ offset -= 4;
+ gr_def(ctx, offset + 0x1f4, 0x00000012);
+ gr_def(ctx, offset + 0x1f8, 0x00000010);
+ gr_def(ctx, offset + 0x1fc, 0x0000000c);
+ gr_def(ctx, offset + 0x200, 0x00000001);
+ gr_def(ctx, offset + 0x210, 0x00000004);
+ gr_def(ctx, offset + 0x214, 0x00000002);
+ gr_def(ctx, offset + 0x218, 0x00000004);
+ if (dev_priv->chipset >= 0xa0)
+ offset += 4;
+ gr_def(ctx, offset + 0x224, 0x003fffff);
+ gr_def(ctx, offset + 0x228, 0x00001fff);
+ if (dev_priv->chipset == 0x50)
+ offset -= 0x20;
+ else if (dev_priv->chipset >= 0xa0) {
+ gr_def(ctx, offset + 0x250, 0x00000001);
+ gr_def(ctx, offset + 0x254, 0x00000001);
+ gr_def(ctx, offset + 0x258, 0x00000002);
+ offset += 0x10;
+ }
+ gr_def(ctx, offset + 0x250, 0x00000004);
+ gr_def(ctx, offset + 0x254, 0x00000014);
+ gr_def(ctx, offset + 0x258, 0x00000001);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ offset += 4;
+ gr_def(ctx, offset + 0x264, 0x00000002);
+ if (dev_priv->chipset >= 0xa0)
+ offset += 8;
+ gr_def(ctx, offset + 0x270, 0x00000001);
+ gr_def(ctx, offset + 0x278, 0x00000002);
+ gr_def(ctx, offset + 0x27c, 0x00001000);
+ if (dev_priv->chipset == 0x50)
+ offset -= 0xc;
+ else {
+ gr_def(ctx, offset + 0x280, 0x00000e00);
+ gr_def(ctx, offset + 0x284, 0x00001000);
+ gr_def(ctx, offset + 0x288, 0x00001e00);
+ }
+ gr_def(ctx, offset + 0x290, 0x00000001);
+ gr_def(ctx, offset + 0x294, 0x00000001);
+ gr_def(ctx, offset + 0x298, 0x00000001);
+ gr_def(ctx, offset + 0x29c, 0x00000001);
+ gr_def(ctx, offset + 0x2a0, 0x00000001);
+ gr_def(ctx, offset + 0x2b0, 0x00000200);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+ gr_def(ctx, offset + 0x2b4, 0x00000200);
+ offset += 4;
+ }
+ if (dev_priv->chipset < 0xa0) {
+ gr_def(ctx, offset + 0x2b8, 0x00000001);
+ gr_def(ctx, offset + 0x2bc, 0x00000070);
+ gr_def(ctx, offset + 0x2c0, 0x00000080);
+ gr_def(ctx, offset + 0x2cc, 0x00000001);
+ gr_def(ctx, offset + 0x2d0, 0x00000070);
+ gr_def(ctx, offset + 0x2d4, 0x00000080);
+ } else {
+ gr_def(ctx, offset + 0x2b8, 0x00000001);
+ gr_def(ctx, offset + 0x2bc, 0x000000f0);
+ gr_def(ctx, offset + 0x2c0, 0x000000ff);
+ gr_def(ctx, offset + 0x2cc, 0x00000001);
+ gr_def(ctx, offset + 0x2d0, 0x000000f0);
+ gr_def(ctx, offset + 0x2d4, 0x000000ff);
+ gr_def(ctx, offset + 0x2dc, 0x00000009);
+ offset += 4;
+ }
+ gr_def(ctx, offset + 0x2e4, 0x00000001);
+ gr_def(ctx, offset + 0x2e8, 0x000000cf);
+ gr_def(ctx, offset + 0x2f0, 0x00000001);
+ gr_def(ctx, offset + 0x300, 0x000000cf);
+ gr_def(ctx, offset + 0x308, 0x00000002);
+ gr_def(ctx, offset + 0x310, 0x00000001);
+ gr_def(ctx, offset + 0x318, 0x00000001);
+ gr_def(ctx, offset + 0x320, 0x000000cf);
+ gr_def(ctx, offset + 0x324, 0x000000cf);
+ gr_def(ctx, offset + 0x328, 0x00000001);
+
+ /* 6000? */
+ if (dev_priv->chipset == 0x50)
+ cp_ctx(ctx, 0x4063e0, 0x1);
+
+ /* 6800 */
+ if (dev_priv->chipset < 0x90) {
+ cp_ctx(ctx, 0x406814, 0x2b);
+ gr_def(ctx, 0x406818, 0x00000f80);
+ gr_def(ctx, 0x406860, 0x007f0080);
+ gr_def(ctx, 0x40689c, 0x007f0080);
+ } else {
+ cp_ctx(ctx, 0x406814, 0x4);
+ if (dev_priv->chipset == 0x98)
+ gr_def(ctx, 0x406818, 0x00000f80);
+ else
+ gr_def(ctx, 0x406818, 0x00001f80);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ gr_def(ctx, 0x40681c, 0x00000030);
+ cp_ctx(ctx, 0x406830, 0x3);
+ }
+
+ /* 7000: per-ROP group state */
+ for (i = 0; i < 8; i++) {
+ if (units & (1<<(i+16))) {
+ cp_ctx(ctx, 0x407000 + (i<<8), 3);
+ if (dev_priv->chipset == 0x50)
+ gr_def(ctx, 0x407000 + (i<<8), 0x1b74f820);
+ else if (dev_priv->chipset != 0xa5)
+ gr_def(ctx, 0x407000 + (i<<8), 0x3b74f821);
+ else
+ gr_def(ctx, 0x407000 + (i<<8), 0x7b74f821);
+ gr_def(ctx, 0x407004 + (i<<8), 0x89058001);
+
+ if (dev_priv->chipset == 0x50) {
+ cp_ctx(ctx, 0x407010 + (i<<8), 1);
+ } else if (dev_priv->chipset < 0xa0) {
+ cp_ctx(ctx, 0x407010 + (i<<8), 2);
+ gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
+ gr_def(ctx, 0x407014 + (i<<8), 0x0000001f);
+ } else {
+ cp_ctx(ctx, 0x407010 + (i<<8), 3);
+ gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
+ if (dev_priv->chipset != 0xa5)
+ gr_def(ctx, 0x407014 + (i<<8), 0x000000ff);
+ else
+ gr_def(ctx, 0x407014 + (i<<8), 0x000001ff);
+ }
+
+ cp_ctx(ctx, 0x407080 + (i<<8), 4);
+ if (dev_priv->chipset != 0xa5)
+ gr_def(ctx, 0x407080 + (i<<8), 0x027c10fa);
+ else
+ gr_def(ctx, 0x407080 + (i<<8), 0x827c10fa);
+ if (dev_priv->chipset == 0x50)
+ gr_def(ctx, 0x407084 + (i<<8), 0x000000c0);
+ else
+ gr_def(ctx, 0x407084 + (i<<8), 0x400000c0);
+ gr_def(ctx, 0x407088 + (i<<8), 0xb7892080);
+
+ if (dev_priv->chipset < 0xa0)
+ cp_ctx(ctx, 0x407094 + (i<<8), 1);
+ else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa)
+ cp_ctx(ctx, 0x407094 + (i<<8), 3);
+ else {
+ cp_ctx(ctx, 0x407094 + (i<<8), 4);
+ gr_def(ctx, 0x4070a0 + (i<<8), 1);
+ }
+ }
+ }
+
+ cp_ctx(ctx, 0x407c00, 0x3);
+ if (dev_priv->chipset < 0x90)
+ gr_def(ctx, 0x407c00, 0x00010040);
+ else if (dev_priv->chipset < 0xa0)
+ gr_def(ctx, 0x407c00, 0x00390040);
+ else
+ gr_def(ctx, 0x407c00, 0x003d0040);
+ gr_def(ctx, 0x407c08, 0x00000022);
+ if (dev_priv->chipset >= 0xa0) {
+ cp_ctx(ctx, 0x407c10, 0x3);
+ cp_ctx(ctx, 0x407c20, 0x1);
+ cp_ctx(ctx, 0x407c2c, 0x1);
+ }
+
+ if (dev_priv->chipset < 0xa0) {
+ cp_ctx(ctx, 0x407d00, 0x9);
+ } else {
+ cp_ctx(ctx, 0x407d00, 0x15);
+ }
+ if (dev_priv->chipset == 0x98)
+ gr_def(ctx, 0x407d08, 0x00380040);
+ else {
+ if (dev_priv->chipset < 0x90)
+ gr_def(ctx, 0x407d08, 0x00010040);
+ else if (dev_priv->chipset < 0xa0)
+ gr_def(ctx, 0x407d08, 0x00390040);
+ else
+ gr_def(ctx, 0x407d08, 0x003d0040);
+ gr_def(ctx, 0x407d0c, 0x00000022);
+ }
+
+ /* 8000+: per-TP state */
+ for (i = 0; i < 10; i++) {
+ if (units & (1<<i)) {
+ if (dev_priv->chipset < 0xa0)
+ base = 0x408000 + (i<<12);
+ else
+ base = 0x408000 + (i<<11);
+ if (dev_priv->chipset < 0xa0)
+ offset = base + 0xc00;
+ else
+ offset = base + 0x80;
+ cp_ctx(ctx, offset + 0x00, 1);
+ gr_def(ctx, offset + 0x00, 0x0000ff0a);
+ cp_ctx(ctx, offset + 0x08, 1);
+
+ /* per-MP state */
+ for (j = 0; j < (dev_priv->chipset < 0xa0 ? 2 : 4); j++) {
+ if (!(units & (1 << (j+24)))) continue;
+ if (dev_priv->chipset < 0xa0)
+ offset = base + 0x200 + (j<<7);
+ else
+ offset = base + 0x100 + (j<<7);
+ cp_ctx(ctx, offset, 0x20);
+ gr_def(ctx, offset + 0x00, 0x01800000);
+ gr_def(ctx, offset + 0x04, 0x00160000);
+ gr_def(ctx, offset + 0x08, 0x01800000);
+ gr_def(ctx, offset + 0x18, 0x0003ffff);
+ switch (dev_priv->chipset) {
+ case 0x50:
+ gr_def(ctx, offset + 0x1c, 0x00080000);
+ break;
+ case 0x84:
+ gr_def(ctx, offset + 0x1c, 0x00880000);
+ break;
+ case 0x86:
+ gr_def(ctx, offset + 0x1c, 0x008c0000);
+ break;
+ case 0x92:
+ case 0x96:
+ case 0x98:
+ gr_def(ctx, offset + 0x1c, 0x118c0000);
+ break;
+ case 0x94:
+ gr_def(ctx, offset + 0x1c, 0x10880000);
+ break;
+ case 0xa0:
+ case 0xa5:
+ gr_def(ctx, offset + 0x1c, 0x310c0000);
+ break;
+ case 0xa8:
+ case 0xaa:
+ case 0xac:
+ gr_def(ctx, offset + 0x1c, 0x300c0000);
+ break;
+ }
+ gr_def(ctx, offset + 0x40, 0x00010401);
+ if (dev_priv->chipset == 0x50)
+ gr_def(ctx, offset + 0x48, 0x00000040);
+ else
+ gr_def(ctx, offset + 0x48, 0x00000078);
+ gr_def(ctx, offset + 0x50, 0x000000bf);
+ gr_def(ctx, offset + 0x58, 0x00001210);
+ if (dev_priv->chipset == 0x50)
+ gr_def(ctx, offset + 0x5c, 0x00000080);
+ else
+ gr_def(ctx, offset + 0x5c, 0x08000080);
+ if (dev_priv->chipset >= 0xa0)
+ gr_def(ctx, offset + 0x68, 0x0000003e);
+ }
+
+ if (dev_priv->chipset < 0xa0)
+ cp_ctx(ctx, base + 0x300, 0x4);
+ else
+ cp_ctx(ctx, base + 0x300, 0x5);
+ if (dev_priv->chipset == 0x50)
+ gr_def(ctx, base + 0x304, 0x00007070);
+ else if (dev_priv->chipset < 0xa0)
+ gr_def(ctx, base + 0x304, 0x00027070);
+ else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa)
+ gr_def(ctx, base + 0x304, 0x01127070);
+ else
+ gr_def(ctx, base + 0x304, 0x05127070);
+
+ if (dev_priv->chipset < 0xa0)
+ cp_ctx(ctx, base + 0x318, 1);
+ else
+ cp_ctx(ctx, base + 0x320, 1);
+ if (dev_priv->chipset == 0x50)
+ gr_def(ctx, base + 0x318, 0x0003ffff);
+ else if (dev_priv->chipset < 0xa0)
+ gr_def(ctx, base + 0x318, 0x03ffffff);
+ else
+ gr_def(ctx, base + 0x320, 0x07ffffff);
+
+ if (dev_priv->chipset < 0xa0)
+ cp_ctx(ctx, base + 0x324, 5);
+ else
+ cp_ctx(ctx, base + 0x328, 4);
+
+ if (dev_priv->chipset < 0xa0) {
+ cp_ctx(ctx, base + 0x340, 9);
+ offset = base + 0x340;
+ } else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) {
+ cp_ctx(ctx, base + 0x33c, 0xb);
+ offset = base + 0x344;
+ } else {
+ cp_ctx(ctx, base + 0x33c, 0xd);
+ offset = base + 0x344;
+ }
+ gr_def(ctx, offset + 0x0, 0x00120407);
+ gr_def(ctx, offset + 0x4, 0x05091507);
+ if (dev_priv->chipset == 0x84)
+ gr_def(ctx, offset + 0x8, 0x05100202);
+ else
+ gr_def(ctx, offset + 0x8, 0x05010202);
+ gr_def(ctx, offset + 0xc, 0x00030201);
+
+ cp_ctx(ctx, base + 0x400, 2);
+ gr_def(ctx, base + 0x404, 0x00000040);
+ cp_ctx(ctx, base + 0x40c, 2);
+ gr_def(ctx, base + 0x40c, 0x0d0c0b0a);
+ gr_def(ctx, base + 0x410, 0x00141210);
+
+ if (dev_priv->chipset < 0xa0)
+ offset = base + 0x800;
+ else
+ offset = base + 0x500;
+ cp_ctx(ctx, offset, 6);
+ gr_def(ctx, offset + 0x0, 0x000001f0);
+ gr_def(ctx, offset + 0x4, 0x00000001);
+ gr_def(ctx, offset + 0x8, 0x00000003);
+ if (dev_priv->chipset == 0x50 || dev_priv->chipset >= 0xaa)
+ gr_def(ctx, offset + 0xc, 0x00008000);
+ gr_def(ctx, offset + 0x14, 0x00039e00);
+ cp_ctx(ctx, offset + 0x1c, 2);
+ if (dev_priv->chipset == 0x50)
+ gr_def(ctx, offset + 0x1c, 0x00000040);
+ else
+ gr_def(ctx, offset + 0x1c, 0x00000100);
+ gr_def(ctx, offset + 0x20, 0x00003800);
+
+ if (dev_priv->chipset >= 0xa0) {
+ cp_ctx(ctx, base + 0x54c, 2);
+ if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa)
+ gr_def(ctx, base + 0x54c, 0x003fe006);
+ else
+ gr_def(ctx, base + 0x54c, 0x003fe007);
+ gr_def(ctx, base + 0x550, 0x003fe000);
+ }
+
+ if (dev_priv->chipset < 0xa0)
+ offset = base + 0xa00;
+ else
+ offset = base + 0x680;
+ cp_ctx(ctx, offset, 1);
+ gr_def(ctx, offset, 0x00404040);
+
+ if (dev_priv->chipset < 0xa0)
+ offset = base + 0xe00;
+ else
+ offset = base + 0x700;
+ cp_ctx(ctx, offset, 2);
+ if (dev_priv->chipset < 0xa0)
+ gr_def(ctx, offset, 0x0077f005);
+ else if (dev_priv->chipset == 0xa5)
+ gr_def(ctx, offset, 0x6cf7f007);
+ else if (dev_priv->chipset == 0xa8)
+ gr_def(ctx, offset, 0x6cfff007);
+ else if (dev_priv->chipset == 0xac)
+ gr_def(ctx, offset, 0x0cfff007);
+ else
+ gr_def(ctx, offset, 0x0cf7f007);
+ if (dev_priv->chipset == 0x50)
+ gr_def(ctx, offset + 0x4, 0x00007fff);
+ else if (dev_priv->chipset < 0xa0)
+ gr_def(ctx, offset + 0x4, 0x003f7fff);
+ else
+ gr_def(ctx, offset + 0x4, 0x02bf7fff);
+ cp_ctx(ctx, offset + 0x2c, 1);
+ if (dev_priv->chipset == 0x50) {
+ cp_ctx(ctx, offset + 0x50, 9);
+ gr_def(ctx, offset + 0x54, 0x000003ff);
+ gr_def(ctx, offset + 0x58, 0x00000003);
+ gr_def(ctx, offset + 0x5c, 0x00000003);
+ gr_def(ctx, offset + 0x60, 0x000001ff);
+ gr_def(ctx, offset + 0x64, 0x0000001f);
+ gr_def(ctx, offset + 0x68, 0x0000000f);
+ gr_def(ctx, offset + 0x6c, 0x0000000f);
+ } else if(dev_priv->chipset < 0xa0) {
+ cp_ctx(ctx, offset + 0x50, 1);
+ cp_ctx(ctx, offset + 0x70, 1);
+ } else {
+ cp_ctx(ctx, offset + 0x50, 1);
+ cp_ctx(ctx, offset + 0x60, 5);
+ }
+ }
+ }
+}
+
+/*
+ * xfer areas. These are a pain.
+ *
+ * There are 2 xfer areas: the first one is big and contains all sorts of
+ * stuff, the second is small and contains some per-TP context.
+ *
+ * Each area is split into 8 "strands". The areas, when saved to grctx,
+ * are made of 8-word blocks. Each block contains a single word from
+ * each strand. The strands are independent of each other, their
+ * addresses are unrelated to each other, and data in them is closely
+ * packed together. The strand layout varies a bit between cards: here
+ * and there, a single word is thrown out in the middle and the whole
+ * strand is offset by a bit from corresponding one on another chipset.
+ * For this reason, addresses of stuff in strands are almost useless.
+ * Knowing sequence of stuff and size of gaps between them is much more
+ * useful, and that's how we build the strands in our generator.
+ *
+ * NVA0 takes this mess to a whole new level by cutting the old strands
+ * into a few dozen pieces [known as genes], rearranging them randomly,
+ * and putting them back together to make new strands. Hopefully these
+ * genes correspond more or less directly to the same PGRAPH subunits
+ * as in 400040 register.
+ *
+ * The most common value in default context is 0, and when the genes
+ * are separated by 0's, gene bounduaries are quite speculative...
+ * some of them can be clearly deduced, others can be guessed, and yet
+ * others won't be resolved without figuring out the real meaning of
+ * given ctxval. For the same reason, ending point of each strand
+ * is unknown. Except for strand 0, which is the longest strand and
+ * its end corresponds to end of the whole xfer.
+ *
+ * An unsolved mystery is the seek instruction: it takes an argument
+ * in bits 8-18, and that argument is clearly the place in strands to
+ * seek to... but the offsets don't seem to correspond to offsets as
+ * seen in grctx. Perhaps there's another, real, not randomly-changing
+ * addressing in strands, and the xfer insn just happens to skip over
+ * the unused bits? NV10-NV30 PIPE comes to mind...
+ *
+ * As far as I know, there's no way to access the xfer areas directly
+ * without the help of ctxprog.
+ */
+
+static inline void
+xf_emit(struct nouveau_grctx *ctx, int num, uint32_t val) {
+ int i;
+ if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
+ for (i = 0; i < num; i++)
+ nv_wo32(ctx->dev, ctx->data, ctx->ctxvals_pos + (i << 3), val);
+ ctx->ctxvals_pos += num << 3;
+}
+
+/* Gene declarations... */
+
+static void nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk1(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk2(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk3(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk4(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk5(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk6(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk7(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk8(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk9(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk10(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx);
+
+static void
+nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ int i;
+ int offset;
+ int size = 0;
+ uint32_t units = nv_rd32 (ctx->dev, 0x1540);
+
+ offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
+ ctx->ctxvals_base = offset;
+
+ if (dev_priv->chipset < 0xa0) {
+ /* Strand 0 */
+ ctx->ctxvals_pos = offset;
+ switch (dev_priv->chipset) {
+ case 0x50:
+ xf_emit(ctx, 0x99, 0);
+ break;
+ case 0x84:
+ case 0x86:
+ xf_emit(ctx, 0x384, 0);
+ break;
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0x98:
+ xf_emit(ctx, 0x380, 0);
+ break;
+ }
+ nv50_graph_construct_gene_m2mf (ctx);
+ switch (dev_priv->chipset) {
+ case 0x50:
+ case 0x84:
+ case 0x86:
+ case 0x98:
+ xf_emit(ctx, 0x4c4, 0);
+ break;
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ xf_emit(ctx, 0x984, 0);
+ break;
+ }
+ nv50_graph_construct_gene_unk5(ctx);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 0xa, 0);
+ else
+ xf_emit(ctx, 0xb, 0);
+ nv50_graph_construct_gene_unk4(ctx);
+ nv50_graph_construct_gene_unk3(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 1 */
+ ctx->ctxvals_pos = offset + 0x1;
+ nv50_graph_construct_gene_unk6(ctx);
+ nv50_graph_construct_gene_unk7(ctx);
+ nv50_graph_construct_gene_unk8(ctx);
+ switch (dev_priv->chipset) {
+ case 0x50:
+ case 0x92:
+ xf_emit(ctx, 0xfb, 0);
+ break;
+ case 0x84:
+ xf_emit(ctx, 0xd3, 0);
+ break;
+ case 0x94:
+ case 0x96:
+ xf_emit(ctx, 0xab, 0);
+ break;
+ case 0x86:
+ case 0x98:
+ xf_emit(ctx, 0x6b, 0);
+ break;
+ }
+ xf_emit(ctx, 2, 0x4e3bfdf);
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 0x0fac6881);
+ xf_emit(ctx, 0xb, 0);
+ xf_emit(ctx, 2, 0x4e3bfdf);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 2 */
+ ctx->ctxvals_pos = offset + 0x2;
+ switch (dev_priv->chipset) {
+ case 0x50:
+ case 0x92:
+ xf_emit(ctx, 0xa80, 0);
+ break;
+ case 0x84:
+ xf_emit(ctx, 0xa7e, 0);
+ break;
+ case 0x94:
+ case 0x96:
+ xf_emit(ctx, 0xa7c, 0);
+ break;
+ case 0x86:
+ case 0x98:
+ xf_emit(ctx, 0xa7a, 0);
+ break;
+ }
+ xf_emit(ctx, 1, 0x3fffff);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x1fff);
+ xf_emit(ctx, 0xe, 0);
+ nv50_graph_construct_gene_unk9(ctx);
+ nv50_graph_construct_gene_unk2(ctx);
+ nv50_graph_construct_gene_unk1(ctx);
+ nv50_graph_construct_gene_unk10(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 3: per-ROP group state */
+ ctx->ctxvals_pos = offset + 3;
+ for (i = 0; i < 6; i++)
+ if (units & (1 << (i + 16)))
+ nv50_graph_construct_gene_ropc(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strands 4-7: per-TP state */
+ for (i = 0; i < 4; i++) {
+ ctx->ctxvals_pos = offset + 4 + i;
+ if (units & (1 << (2 * i)))
+ nv50_graph_construct_xfer_tp(ctx);
+ if (units & (1 << (2 * i + 1)))
+ nv50_graph_construct_xfer_tp(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+ }
+ } else {
+ /* Strand 0 */
+ ctx->ctxvals_pos = offset;
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 0x385, 0);
+ else
+ xf_emit(ctx, 0x384, 0);
+ nv50_graph_construct_gene_m2mf(ctx);
+ xf_emit(ctx, 0x950, 0);
+ nv50_graph_construct_gene_unk10(ctx);
+ xf_emit(ctx, 1, 0x0fac6881);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 3, 0);
+ }
+ nv50_graph_construct_gene_unk8(ctx);
+ if (dev_priv->chipset == 0xa0)
+ xf_emit(ctx, 0x189, 0);
+ else if (dev_priv->chipset < 0xa8)
+ xf_emit(ctx, 0x99, 0);
+ else if (dev_priv->chipset == 0xaa)
+ xf_emit(ctx, 0x65, 0);
+ else
+ xf_emit(ctx, 0x6d, 0);
+ nv50_graph_construct_gene_unk9(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 1 */
+ ctx->ctxvals_pos = offset + 1;
+ nv50_graph_construct_gene_unk1(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 2 */
+ ctx->ctxvals_pos = offset + 2;
+ if (dev_priv->chipset == 0xa0) {
+ nv50_graph_construct_gene_unk2(ctx);
+ }
+ xf_emit(ctx, 0x36, 0);
+ nv50_graph_construct_gene_unk5(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 3 */
+ ctx->ctxvals_pos = offset + 3;
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ nv50_graph_construct_gene_unk6(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 4 */
+ ctx->ctxvals_pos = offset + 4;
+ if (dev_priv->chipset == 0xa0)
+ xf_emit(ctx, 0xa80, 0);
+ else
+ xf_emit(ctx, 0xa7a, 0);
+ xf_emit(ctx, 1, 0x3fffff);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x1fff);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 5 */
+ ctx->ctxvals_pos = offset + 5;
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x0fac6881);
+ xf_emit(ctx, 0xb, 0);
+ xf_emit(ctx, 2, 0x4e3bfdf);
+ xf_emit(ctx, 3, 0);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 2, 0x4e3bfdf);
+ xf_emit(ctx, 2, 0);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 1, 0);
+ for (i = 0; i < 8; i++)
+ if (units & (1<<(i+16)))
+ nv50_graph_construct_gene_ropc(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 6 */
+ ctx->ctxvals_pos = offset + 6;
+ nv50_graph_construct_gene_unk3(ctx);
+ xf_emit(ctx, 0xb, 0);
+ nv50_graph_construct_gene_unk4(ctx);
+ nv50_graph_construct_gene_unk7(ctx);
+ if (units & (1 << 0))
+ nv50_graph_construct_xfer_tp(ctx);
+ if (units & (1 << 1))
+ nv50_graph_construct_xfer_tp(ctx);
+ if (units & (1 << 2))
+ nv50_graph_construct_xfer_tp(ctx);
+ if (units & (1 << 3))
+ nv50_graph_construct_xfer_tp(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 7 */
+ ctx->ctxvals_pos = offset + 7;
+ if (dev_priv->chipset == 0xa0) {
+ if (units & (1 << 4))
+ nv50_graph_construct_xfer_tp(ctx);
+ if (units & (1 << 5))
+ nv50_graph_construct_xfer_tp(ctx);
+ if (units & (1 << 6))
+ nv50_graph_construct_xfer_tp(ctx);
+ if (units & (1 << 7))
+ nv50_graph_construct_xfer_tp(ctx);
+ if (units & (1 << 8))
+ nv50_graph_construct_xfer_tp(ctx);
+ if (units & (1 << 9))
+ nv50_graph_construct_xfer_tp(ctx);
+ } else {
+ nv50_graph_construct_gene_unk2(ctx);
+ }
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+ }
+
+ ctx->ctxvals_pos = offset + size * 8;
+ ctx->ctxvals_pos = (ctx->ctxvals_pos+0x3f)&~0x3f;
+ cp_lsr (ctx, offset);
+ cp_out (ctx, CP_SET_XFER_POINTER);
+ cp_lsr (ctx, size);
+ cp_out (ctx, CP_SEEK_1);
+ cp_out (ctx, CP_XFER_1);
+ cp_wait(ctx, XFER, BUSY);
+}
+
+/*
+ * non-trivial demagiced parts of ctx init go here
+ */
+
+static void
+nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx)
+{
+ /* m2mf state */
+ xf_emit (ctx, 1, 0); /* DMA_NOTIFY instance >> 4 */
+ xf_emit (ctx, 1, 0); /* DMA_BUFFER_IN instance >> 4 */
+ xf_emit (ctx, 1, 0); /* DMA_BUFFER_OUT instance >> 4 */
+ xf_emit (ctx, 1, 0); /* OFFSET_IN */
+ xf_emit (ctx, 1, 0); /* OFFSET_OUT */
+ xf_emit (ctx, 1, 0); /* PITCH_IN */
+ xf_emit (ctx, 1, 0); /* PITCH_OUT */
+ xf_emit (ctx, 1, 0); /* LINE_LENGTH */
+ xf_emit (ctx, 1, 0); /* LINE_COUNT */
+ xf_emit (ctx, 1, 0x21); /* FORMAT: bits 0-4 INPUT_INC, bits 5-9 OUTPUT_INC */
+ xf_emit (ctx, 1, 1); /* LINEAR_IN */
+ xf_emit (ctx, 1, 0x2); /* TILING_MODE_IN: bits 0-2 y tiling, bits 3-5 z tiling */
+ xf_emit (ctx, 1, 0x100); /* TILING_PITCH_IN */
+ xf_emit (ctx, 1, 0x100); /* TILING_HEIGHT_IN */
+ xf_emit (ctx, 1, 1); /* TILING_DEPTH_IN */
+ xf_emit (ctx, 1, 0); /* TILING_POSITION_IN_Z */
+ xf_emit (ctx, 1, 0); /* TILING_POSITION_IN */
+ xf_emit (ctx, 1, 1); /* LINEAR_OUT */
+ xf_emit (ctx, 1, 0x2); /* TILING_MODE_OUT: bits 0-2 y tiling, bits 3-5 z tiling */
+ xf_emit (ctx, 1, 0x100); /* TILING_PITCH_OUT */
+ xf_emit (ctx, 1, 0x100); /* TILING_HEIGHT_OUT */
+ xf_emit (ctx, 1, 1); /* TILING_DEPTH_OUT */
+ xf_emit (ctx, 1, 0); /* TILING_POSITION_OUT_Z */
+ xf_emit (ctx, 1, 0); /* TILING_POSITION_OUT */
+ xf_emit (ctx, 1, 0); /* OFFSET_IN_HIGH */
+ xf_emit (ctx, 1, 0); /* OFFSET_OUT_HIGH */
+}
+
+static void
+nv50_graph_construct_gene_unk1(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ /* end of area 2 on pre-NVA0, area 1 on NVAx */
+ xf_emit(ctx, 2, 4);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x80);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 0x80c14);
+ xf_emit(ctx, 1, 0);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 1, 0x3ff);
+ else
+ xf_emit(ctx, 1, 0x7ff);
+ switch (dev_priv->chipset) {
+ case 0x50:
+ case 0x86:
+ case 0x98:
+ case 0xaa:
+ case 0xac:
+ xf_emit(ctx, 0x542, 0);
+ break;
+ case 0x84:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ xf_emit(ctx, 0x942, 0);
+ break;
+ case 0xa0:
+ xf_emit(ctx, 0x2042, 0);
+ break;
+ case 0xa5:
+ case 0xa8:
+ xf_emit(ctx, 0x842, 0);
+ break;
+ }
+ xf_emit(ctx, 2, 4);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x80);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x27);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x26);
+ xf_emit(ctx, 3, 0);
+}
+
+static void
+nv50_graph_construct_gene_unk10(struct nouveau_grctx *ctx)
+{
+ /* end of area 2 on pre-NVA0, area 1 on NVAx */
+ xf_emit(ctx, 0x10, 0x04000000);
+ xf_emit(ctx, 0x24, 0);
+ xf_emit(ctx, 2, 0x04e3bfdf);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x1fe21);
+}
+
+static void
+nv50_graph_construct_gene_unk2(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ /* middle of area 2 on pre-NVA0, beginning of area 2 on NVA0, area 7 on >NVA0 */
+ if (dev_priv->chipset != 0x50) {
+ xf_emit(ctx, 5, 0);
+ xf_emit(ctx, 1, 0x80c14);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x804);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 2, 4);
+ xf_emit(ctx, 1, 0x8100c12);
+ }
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 2, 4);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x10);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 3, 0);
+ else
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 0x804);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0x1a);
+ if (dev_priv->chipset != 0x50)
+ xf_emit(ctx, 1, 0x7f);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0x80c14);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x8100c12);
+ xf_emit(ctx, 2, 4);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x10);
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0x8100c12);
+ xf_emit(ctx, 6, 0);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 1, 0x3ff);
+ else
+ xf_emit(ctx, 1, 0x7ff);
+ xf_emit(ctx, 1, 0x80c14);
+ xf_emit(ctx, 0x38, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x10);
+ xf_emit(ctx, 0x38, 0);
+ xf_emit(ctx, 2, 0x88);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 0x16, 0);
+ xf_emit(ctx, 1, 0x26);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x3f800000);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 4, 0);
+ else
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 0x1a);
+ xf_emit(ctx, 1, 0x10);
+ if (dev_priv->chipset != 0x50)
+ xf_emit(ctx, 0x28, 0);
+ else
+ xf_emit(ctx, 0x25, 0);
+ xf_emit(ctx, 1, 0x52);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x26);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 2, 4);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x1a);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x00ffff00);
+ xf_emit(ctx, 1, 0);
+}
+
+static void
+nv50_graph_construct_gene_unk3(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ /* end of area 0 on pre-NVA0, beginning of area 6 on NVAx */
+ xf_emit(ctx, 1, 0x3f);
+ xf_emit(ctx, 0xa, 0);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 2, 0x04000000);
+ xf_emit(ctx, 8, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 4);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 0x10, 0);
+ else
+ xf_emit(ctx, 0x11, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0x1001);
+ xf_emit(ctx, 4, 0xffff);
+ xf_emit(ctx, 0x20, 0);
+ xf_emit(ctx, 0x10, 0x3f800000);
+ xf_emit(ctx, 1, 0x10);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 1, 0);
+ else
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 3);
+ xf_emit(ctx, 2, 0);
+}
+
+static void
+nv50_graph_construct_gene_unk4(struct nouveau_grctx *ctx)
+{
+ /* middle of area 0 on pre-NVA0, middle of area 6 on NVAx */
+ xf_emit(ctx, 2, 0x04000000);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x80);
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 0x80);
+ xf_emit(ctx, 1, 0);
+}
+
+static void
+nv50_graph_construct_gene_unk5(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ /* middle of area 0 on pre-NVA0 [after m2mf], end of area 2 on NVAx */
+ xf_emit(ctx, 2, 4);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 0x1c4d, 0);
+ else
+ xf_emit(ctx, 0x1c4b, 0);
+ xf_emit(ctx, 2, 4);
+ xf_emit(ctx, 1, 0x8100c12);
+ if (dev_priv->chipset != 0x50)
+ xf_emit(ctx, 1, 3);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x8100c12);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x80c14);
+ xf_emit(ctx, 1, 1);
+ if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 2, 4);
+ xf_emit(ctx, 1, 0x80c14);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x8100c12);
+ xf_emit(ctx, 1, 0x27);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 0x3c1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 0x16, 0);
+ xf_emit(ctx, 1, 0x8100c12);
+ xf_emit(ctx, 1, 0);
+}
+
+static void
+nv50_graph_construct_gene_unk6(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ /* beginning of area 1 on pre-NVA0 [after m2mf], area 3 on NVAx */
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 0xf);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 8, 0);
+ else
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 0x20);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 0x11, 0);
+ else if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 0xf, 0);
+ else
+ xf_emit(ctx, 0xe, 0);
+ xf_emit(ctx, 1, 0x1a);
+ xf_emit(ctx, 0xd, 0);
+ xf_emit(ctx, 2, 4);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 8);
+ xf_emit(ctx, 1, 0);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 1, 0x3ff);
+ else
+ xf_emit(ctx, 1, 0x7ff);
+ if (dev_priv->chipset == 0xa8)
+ xf_emit(ctx, 1, 0x1e00);
+ xf_emit(ctx, 0xc, 0);
+ xf_emit(ctx, 1, 0xf);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 0x125, 0);
+ else if (dev_priv->chipset < 0xa0)
+ xf_emit(ctx, 0x126, 0);
+ else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa)
+ xf_emit(ctx, 0x124, 0);
+ else
+ xf_emit(ctx, 0x1f7, 0);
+ xf_emit(ctx, 1, 0xf);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 3, 0);
+ else
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 0xa1, 0);
+ else
+ xf_emit(ctx, 0x5a, 0);
+ xf_emit(ctx, 1, 0xf);
+ if (dev_priv->chipset < 0xa0)
+ xf_emit(ctx, 0x834, 0);
+ else if (dev_priv->chipset == 0xa0)
+ xf_emit(ctx, 0x1873, 0);
+ else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 0x8ba, 0);
+ else
+ xf_emit(ctx, 0x833, 0);
+ xf_emit(ctx, 1, 0xf);
+ xf_emit(ctx, 0xf, 0);
+}
+
+static void
+nv50_graph_construct_gene_unk7(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ /* middle of area 1 on pre-NVA0 [after m2mf], middle of area 6 on NVAx */
+ xf_emit(ctx, 2, 0);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 2, 1);
+ else
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 2, 0x100);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 8);
+ xf_emit(ctx, 5, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 3, 1);
+ xf_emit(ctx, 1, 0xcf);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 6, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 3, 1);
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0x15);
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 0x4444480);
+ xf_emit(ctx, 0x37, 0);
+}
+
+static void
+nv50_graph_construct_gene_unk8(struct nouveau_grctx *ctx)
+{
+ /* middle of area 1 on pre-NVA0 [after m2mf], middle of area 0 on NVAx */
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 0x8100c12);
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 0x100);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x10001);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x10001);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0x10001);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 2);
+}
+
+static void
+nv50_graph_construct_gene_unk9(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ /* middle of area 2 on pre-NVA0 [after m2mf], end of area 0 on NVAx */
+ xf_emit(ctx, 1, 0x3f800000);
+ xf_emit(ctx, 6, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 0x1a);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 0x12, 0);
+ xf_emit(ctx, 1, 0x00ffff00);
+ xf_emit(ctx, 6, 0);
+ xf_emit(ctx, 1, 0xf);
+ xf_emit(ctx, 7, 0);
+ xf_emit(ctx, 1, 0x0fac6881);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 0xf, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 2, 0);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 1, 3);
+ else if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 2, 0x04000000);
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 5);
+ xf_emit(ctx, 1, 0x52);
+ if (dev_priv->chipset == 0x50) {
+ xf_emit(ctx, 0x13, 0);
+ } else {
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 1);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 0x11, 0);
+ else
+ xf_emit(ctx, 0x10, 0);
+ }
+ xf_emit(ctx, 0x10, 0x3f800000);
+ xf_emit(ctx, 1, 0x10);
+ xf_emit(ctx, 0x26, 0);
+ xf_emit(ctx, 1, 0x8100c12);
+ xf_emit(ctx, 1, 5);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 4, 0xffff);
+ if (dev_priv->chipset != 0x50)
+ xf_emit(ctx, 1, 3);
+ if (dev_priv->chipset < 0xa0)
+ xf_emit(ctx, 0x1f, 0);
+ else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 0xc, 0);
+ else
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 0x00ffff00);
+ xf_emit(ctx, 1, 0x1a);
+ if (dev_priv->chipset != 0x50) {
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 3);
+ }
+ if (dev_priv->chipset < 0xa0)
+ xf_emit(ctx, 0x26, 0);
+ else
+ xf_emit(ctx, 0x3c, 0);
+ xf_emit(ctx, 1, 0x102);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 4, 4);
+ if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 8, 0);
+ xf_emit(ctx, 2, 4);
+ xf_emit(ctx, 1, 0);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 1, 0x3ff);
+ else
+ xf_emit(ctx, 1, 0x7ff);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x102);
+ xf_emit(ctx, 9, 0);
+ xf_emit(ctx, 4, 4);
+ xf_emit(ctx, 0x2c, 0);
+}
+
+static void
+nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ int magic2;
+ if (dev_priv->chipset == 0x50) {
+ magic2 = 0x00003e60;
+ } else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) {
+ magic2 = 0x001ffe67;
+ } else {
+ magic2 = 0x00087e67;
+ }
+ xf_emit(ctx, 8, 0);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, magic2);
+ xf_emit(ctx, 4, 0);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 7, 0);
+ if (dev_priv->chipset >= 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 1, 0x15);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0x10);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 4, 0);
+ if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x92 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa0) {
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 0x400);
+ xf_emit(ctx, 1, 0x300);
+ xf_emit(ctx, 1, 0x1001);
+ if (dev_priv->chipset != 0xa0) {
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 1, 0);
+ else
+ xf_emit(ctx, 1, 0x15);
+ }
+ xf_emit(ctx, 3, 0);
+ }
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 8, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0x10);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 0x13, 0);
+ xf_emit(ctx, 1, 0x10);
+ xf_emit(ctx, 0x10, 0);
+ xf_emit(ctx, 0x10, 0x3f800000);
+ xf_emit(ctx, 0x19, 0);
+ xf_emit(ctx, 1, 0x10);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x3f);
+ xf_emit(ctx, 6, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ if (dev_priv->chipset >= 0xa0) {
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x1001);
+ xf_emit(ctx, 0xb, 0);
+ } else {
+ xf_emit(ctx, 0xc, 0);
+ }
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 7, 0);
+ xf_emit(ctx, 1, 0xf);
+ xf_emit(ctx, 7, 0);
+ xf_emit(ctx, 1, 0x11);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 4, 0);
+ else
+ xf_emit(ctx, 6, 0);
+ xf_emit(ctx, 3, 1);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, magic2);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x0fac6881);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 0x18, 1);
+ xf_emit(ctx, 8, 2);
+ xf_emit(ctx, 8, 1);
+ xf_emit(ctx, 8, 2);
+ xf_emit(ctx, 8, 1);
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 5, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 0x16, 0);
+ } else {
+ if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 0x1b, 0);
+ else
+ xf_emit(ctx, 0x15, 0);
+ }
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 2, 1);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 2, 1);
+ if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 4, 0);
+ else
+ xf_emit(ctx, 3, 0);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+ xf_emit(ctx, 0x10, 1);
+ xf_emit(ctx, 8, 2);
+ xf_emit(ctx, 0x10, 1);
+ xf_emit(ctx, 8, 2);
+ xf_emit(ctx, 8, 1);
+ xf_emit(ctx, 3, 0);
+ }
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 0x5b, 0);
+}
+
+static void
+nv50_graph_construct_xfer_tp_x1(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ int magic3;
+ if (dev_priv->chipset == 0x50)
+ magic3 = 0x1000;
+ else if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa8)
+ magic3 = 0x1e00;
+ else
+ magic3 = 0;
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 4);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 0x24, 0);
+ else if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 0x14, 0);
+ else
+ xf_emit(ctx, 0x15, 0);
+ xf_emit(ctx, 2, 4);
+ if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 1, 0x03020100);
+ else
+ xf_emit(ctx, 1, 0x00608080);
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 2, 4);
+ xf_emit(ctx, 1, 0x80);
+ if (magic3)
+ xf_emit(ctx, 1, magic3);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 0x24, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 0x80);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 0x03020100);
+ xf_emit(ctx, 1, 3);
+ if (magic3)
+ xf_emit(ctx, 1, magic3);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 3);
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 4);
+ if (dev_priv->chipset == 0x94 || dev_priv->chipset == 0x96)
+ xf_emit(ctx, 0x1024, 0);
+ else if (dev_priv->chipset < 0xa0)
+ xf_emit(ctx, 0xa24, 0);
+ else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa)
+ xf_emit(ctx, 0x214, 0);
+ else
+ xf_emit(ctx, 0x414, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 3);
+ xf_emit(ctx, 2, 0);
+}
+
+static void
+nv50_graph_construct_xfer_tp_x2(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ int magic1, magic2;
+ if (dev_priv->chipset == 0x50) {
+ magic1 = 0x3ff;
+ magic2 = 0x00003e60;
+ } else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) {
+ magic1 = 0x7ff;
+ magic2 = 0x001ffe67;
+ } else {
+ magic1 = 0x7ff;
+ magic2 = 0x00087e67;
+ }
+ xf_emit(ctx, 3, 0);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 0xc, 0);
+ xf_emit(ctx, 1, 0xf);
+ xf_emit(ctx, 0xb, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 4, 0xffff);
+ xf_emit(ctx, 8, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 5, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 2, 0);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+ xf_emit(ctx, 1, 3);
+ xf_emit(ctx, 1, 0);
+ } else if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 0xa, 0);
+ xf_emit(ctx, 2, 1);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 2, 1);
+ xf_emit(ctx, 1, 2);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 0x18, 1);
+ xf_emit(ctx, 8, 2);
+ xf_emit(ctx, 8, 1);
+ xf_emit(ctx, 8, 2);
+ xf_emit(ctx, 8, 1);
+ xf_emit(ctx, 1, 0);
+ }
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 7, 0);
+ xf_emit(ctx, 1, 0x0fac6881);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 3, 0xcf);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 0xa, 0);
+ xf_emit(ctx, 2, 1);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 2, 1);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 8, 1);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 7, 0);
+ xf_emit(ctx, 1, 0x0fac6881);
+ xf_emit(ctx, 1, 0xf);
+ xf_emit(ctx, 7, 0);
+ xf_emit(ctx, 1, magic2);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x11);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 2, 1);
+ else
+ xf_emit(ctx, 1, 1);
+ if(dev_priv->chipset == 0x50)
+ xf_emit(ctx, 1, 0);
+ else
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 5, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 7, 0);
+ xf_emit(ctx, 1, 0x0fac6881);
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, magic1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 2, 0);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 0x28, 0);
+ xf_emit(ctx, 8, 8);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 7, 0);
+ xf_emit(ctx, 1, 0x0fac6881);
+ xf_emit(ctx, 8, 0x400);
+ xf_emit(ctx, 8, 0x300);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0xf);
+ xf_emit(ctx, 7, 0);
+ xf_emit(ctx, 1, 0x20);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 1, 0x100);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x40);
+ xf_emit(ctx, 1, 0x100);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 3);
+ xf_emit(ctx, 4, 0);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, magic2);
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 1, 0x0fac6881);
+ xf_emit(ctx, 9, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0x400);
+ xf_emit(ctx, 1, 0x300);
+ xf_emit(ctx, 1, 0x1001);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 4, 0);
+ else
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 7, 0);
+ xf_emit(ctx, 1, 0x0fac6881);
+ xf_emit(ctx, 1, 0xf);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+ xf_emit(ctx, 0x15, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 3, 0);
+ } else
+ xf_emit(ctx, 0x17, 0);
+ if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 1, 0x0fac6881);
+ xf_emit(ctx, 1, magic2);
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 2, 1);
+ xf_emit(ctx, 3, 0);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 2, 1);
+ else
+ xf_emit(ctx, 1, 1);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 2, 0);
+ else if (dev_priv->chipset != 0x50)
+ xf_emit(ctx, 1, 0);
+}
+
+static void
+nv50_graph_construct_xfer_tp_x3(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 2, 0);
+ else
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 0x2a712488);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x4085c000);
+ xf_emit(ctx, 1, 0x40);
+ xf_emit(ctx, 1, 0x100);
+ xf_emit(ctx, 1, 0x10100);
+ xf_emit(ctx, 1, 0x02800000);
+}
+
+static void
+nv50_graph_construct_xfer_tp_x4(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ xf_emit(ctx, 2, 0x04e3bfdf);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x00ffff00);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 2, 1);
+ else
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x00ffff00);
+ xf_emit(ctx, 8, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0x30201000);
+ xf_emit(ctx, 1, 0x70605040);
+ xf_emit(ctx, 1, 0xb8a89888);
+ xf_emit(ctx, 1, 0xf8e8d8c8);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x1a);
+}
+
+static void
+nv50_graph_construct_xfer_tp_x5(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 0xfac6881);
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 2, 1);
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 1);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 0xb, 0);
+ else
+ xf_emit(ctx, 0xa, 0);
+ xf_emit(ctx, 8, 1);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 7, 0);
+ xf_emit(ctx, 1, 0xfac6881);
+ xf_emit(ctx, 1, 0xf);
+ xf_emit(ctx, 7, 0);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 1, 1);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+ xf_emit(ctx, 6, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 6, 0);
+ } else {
+ xf_emit(ctx, 0xb, 0);
+ }
+}
+
+static void
+nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ if (dev_priv->chipset < 0xa0) {
+ nv50_graph_construct_xfer_tp_x1(ctx);
+ nv50_graph_construct_xfer_tp_x2(ctx);
+ nv50_graph_construct_xfer_tp_x3(ctx);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 0xf, 0);
+ else
+ xf_emit(ctx, 0x12, 0);
+ nv50_graph_construct_xfer_tp_x4(ctx);
+ } else {
+ nv50_graph_construct_xfer_tp_x3(ctx);
+ if (dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 0xc, 0);
+ else
+ xf_emit(ctx, 0xa, 0);
+ nv50_graph_construct_xfer_tp_x2(ctx);
+ nv50_graph_construct_xfer_tp_x5(ctx);
+ nv50_graph_construct_xfer_tp_x4(ctx);
+ nv50_graph_construct_xfer_tp_x1(ctx);
+ }
+}
+
+static void
+nv50_graph_construct_xfer_tp2(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ int i, mpcnt;
+ if (dev_priv->chipset == 0x98 || dev_priv->chipset == 0xaa)
+ mpcnt = 1;
+ else if (dev_priv->chipset < 0xa0 || dev_priv->chipset >= 0xa8)
+ mpcnt = 2;
+ else
+ mpcnt = 3;
+ for (i = 0; i < mpcnt; i++) {
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x80);
+ xf_emit(ctx, 1, 0x80007004);
+ xf_emit(ctx, 1, 0x04000400);
+ if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 1, 0xc0);
+ xf_emit(ctx, 1, 0x1000);
+ xf_emit(ctx, 2, 0);
+ if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa8) {
+ xf_emit(ctx, 1, 0xe00);
+ xf_emit(ctx, 1, 0x1e00);
+ }
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 2, 0);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 2, 0x1000);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 2);
+ if (dev_priv->chipset >= 0xaa)
+ xf_emit(ctx, 0xb, 0);
+ else if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 0xc, 0);
+ else
+ xf_emit(ctx, 0xa, 0);
+ }
+ xf_emit(ctx, 1, 0x08100c12);
+ xf_emit(ctx, 1, 0);
+ if (dev_priv->chipset >= 0xa0) {
+ xf_emit(ctx, 1, 0x1fe21);
+ }
+ xf_emit(ctx, 5, 0);
+ xf_emit(ctx, 4, 0xffff);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 2, 0x10001);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x1fe21);
+ xf_emit(ctx, 1, 0);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 0x08100c12);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 8, 0);
+ xf_emit(ctx, 1, 0xfac6881);
+ xf_emit(ctx, 1, 0);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ xf_emit(ctx, 1, 3);
+ xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 9, 0);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 2, 1);
+ xf_emit(ctx, 1, 2);
+ xf_emit(ctx, 3, 1);
+ xf_emit(ctx, 1, 0);
+ if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+ xf_emit(ctx, 8, 2);
+ xf_emit(ctx, 0x10, 1);
+ xf_emit(ctx, 8, 2);
+ xf_emit(ctx, 0x18, 1);
+ xf_emit(ctx, 3, 0);
+ }
+ xf_emit(ctx, 1, 4);
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 0x3a0, 0);
+ else if (dev_priv->chipset < 0x94)
+ xf_emit(ctx, 0x3a2, 0);
+ else if (dev_priv->chipset == 0x98 || dev_priv->chipset == 0xaa)
+ xf_emit(ctx, 0x39f, 0);
+ else
+ xf_emit(ctx, 0x3a3, 0);
+ xf_emit(ctx, 1, 0x11);
+ xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 0x2d, 0);
+}
+
+static void
+nv50_graph_construct_xfer2(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ int i;
+ uint32_t offset;
+ uint32_t units = nv_rd32 (ctx->dev, 0x1540);
+ int size = 0;
+
+ offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
+
+ if (dev_priv->chipset < 0xa0) {
+ for (i = 0; i < 8; i++) {
+ ctx->ctxvals_pos = offset + i;
+ if (i == 0)
+ xf_emit(ctx, 1, 0x08100c12);
+ if (units & (1 << i))
+ nv50_graph_construct_xfer_tp2(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+ }
+ } else {
+ /* Strand 0: TPs 0, 1 */
+ ctx->ctxvals_pos = offset;
+ xf_emit(ctx, 1, 0x08100c12);
+ if (units & (1 << 0))
+ nv50_graph_construct_xfer_tp2(ctx);
+ if (units & (1 << 1))
+ nv50_graph_construct_xfer_tp2(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 0: TPs 2, 3 */
+ ctx->ctxvals_pos = offset + 1;
+ if (units & (1 << 2))
+ nv50_graph_construct_xfer_tp2(ctx);
+ if (units & (1 << 3))
+ nv50_graph_construct_xfer_tp2(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 0: TPs 4, 5, 6 */
+ ctx->ctxvals_pos = offset + 2;
+ if (units & (1 << 4))
+ nv50_graph_construct_xfer_tp2(ctx);
+ if (units & (1 << 5))
+ nv50_graph_construct_xfer_tp2(ctx);
+ if (units & (1 << 6))
+ nv50_graph_construct_xfer_tp2(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 0: TPs 7, 8, 9 */
+ ctx->ctxvals_pos = offset + 3;
+ if (units & (1 << 7))
+ nv50_graph_construct_xfer_tp2(ctx);
+ if (units & (1 << 8))
+ nv50_graph_construct_xfer_tp2(ctx);
+ if (units & (1 << 9))
+ nv50_graph_construct_xfer_tp2(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+ }
+ ctx->ctxvals_pos = offset + size * 8;
+ ctx->ctxvals_pos = (ctx->ctxvals_pos+0x3f)&~0x3f;
+ cp_lsr (ctx, offset);
+ cp_out (ctx, CP_SET_XFER_POINTER);
+ cp_lsr (ctx, size);
+ cp_out (ctx, CP_SEEK_2);
+ cp_out (ctx, CP_XFER_2);
+ cp_wait(ctx, XFER, BUSY);
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c
index 94400f777e7f..de1f5b0062c5 100644
--- a/drivers/gpu/drm/nouveau/nv50_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv50_instmem.c
@@ -76,6 +76,11 @@ nv50_instmem_init(struct drm_device *dev)
for (i = 0x1700; i <= 0x1710; i += 4)
priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i);
+ if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac)
+ dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10) << 12;
+ else
+ dev_priv->vram_sys_base = 0;
+
/* Reserve the last MiB of VRAM, we should probably try to avoid
* setting up the below tables over the top of the VBIOS image at
* some point.
@@ -172,16 +177,28 @@ nv50_instmem_init(struct drm_device *dev)
* We map the entire fake channel into the start of the PRAMIN BAR
*/
ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pt_size, 0x1000,
- 0, &priv->pramin_pt);
+ 0, &priv->pramin_pt);
if (ret)
return ret;
- for (i = 0, v = c_offset; i < pt_size; i += 8, v += 0x1000) {
- if (v < (c_offset + c_size))
- BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, v | 1);
- else
- BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, 0x00000009);
+ v = c_offset | 1;
+ if (dev_priv->vram_sys_base) {
+ v += dev_priv->vram_sys_base;
+ v |= 0x30;
+ }
+
+ i = 0;
+ while (v < dev_priv->vram_sys_base + c_offset + c_size) {
+ BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, v);
+ BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, 0x00000000);
+ v += 0x1000;
+ i += 8;
+ }
+
+ while (i < pt_size) {
+ BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, 0x00000000);
BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, 0x00000000);
+ i += 8;
}
BAR0_WI32(chan->vm_pd, 0x00, priv->pramin_pt->instance | 0x63);
@@ -373,7 +390,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
if (gpuobj->im_backing)
return -EINVAL;
- *sz = (*sz + (NV50_INSTMEM_PAGE_SIZE-1)) & ~(NV50_INSTMEM_PAGE_SIZE-1);
+ *sz = ALIGN(*sz, NV50_INSTMEM_PAGE_SIZE);
if (*sz == 0)
return -EINVAL;
@@ -416,7 +433,9 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
- uint32_t pte, pte_end, vram;
+ struct nouveau_gpuobj *pramin_pt = priv->pramin_pt->gpuobj;
+ uint32_t pte, pte_end;
+ uint64_t vram;
if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
return -EINVAL;
@@ -424,20 +443,24 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
NV_DEBUG(dev, "st=0x%0llx sz=0x%0llx\n",
gpuobj->im_pramin->start, gpuobj->im_pramin->size);
- pte = (gpuobj->im_pramin->start >> 12) << 3;
- pte_end = ((gpuobj->im_pramin->size >> 12) << 3) + pte;
+ pte = (gpuobj->im_pramin->start >> 12) << 1;
+ pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
vram = gpuobj->im_backing_start;
NV_DEBUG(dev, "pramin=0x%llx, pte=%d, pte_end=%d\n",
gpuobj->im_pramin->start, pte, pte_end);
NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
+ vram |= 1;
+ if (dev_priv->vram_sys_base) {
+ vram += dev_priv->vram_sys_base;
+ vram |= 0x30;
+ }
+
dev_priv->engine.instmem.prepare_access(dev, true);
while (pte < pte_end) {
- nv_wo32(dev, priv->pramin_pt->gpuobj, (pte + 0)/4, vram | 1);
- nv_wo32(dev, priv->pramin_pt->gpuobj, (pte + 4)/4, 0x00000000);
-
- pte += 8;
+ nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram));
+ nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram));
vram += NV50_INSTMEM_PAGE_SIZE;
}
dev_priv->engine.instmem.finish_access(dev);
@@ -470,14 +493,13 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
if (gpuobj->im_bound == 0)
return -EINVAL;
- pte = (gpuobj->im_pramin->start >> 12) << 3;
- pte_end = ((gpuobj->im_pramin->size >> 12) << 3) + pte;
+ pte = (gpuobj->im_pramin->start >> 12) << 1;
+ pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
dev_priv->engine.instmem.prepare_access(dev, true);
while (pte < pte_end) {
- nv_wo32(dev, priv->pramin_pt->gpuobj, (pte + 0)/4, 0x00000009);
- nv_wo32(dev, priv->pramin_pt->gpuobj, (pte + 4)/4, 0x00000000);
- pte += 8;
+ nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
+ nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
}
dev_priv->engine.instmem.finish_access(dev);
diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
index e395c16d30f5..c2fff543b06f 100644
--- a/drivers/gpu/drm/nouveau/nv50_sor.c
+++ b/drivers/gpu/drm/nouveau/nv50_sor.c
@@ -90,11 +90,25 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct drm_encoder *enc;
uint32_t val;
int or = nv_encoder->or;
NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
+ nv_encoder->last_dpms = mode;
+ list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
+ struct nouveau_encoder *nvenc = nouveau_encoder(enc);
+
+ if (nvenc == nv_encoder ||
+ nvenc->disconnect != nv50_sor_disconnect ||
+ nvenc->dcb->or != nv_encoder->dcb->or)
+ continue;
+
+ if (nvenc->last_dpms == DRM_MODE_DPMS_ON)
+ return;
+ }
+
/* wait for it to be done */
if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_CTRL(or),
NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING, 0)) {
diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
index 5982321be4d5..1c02d23f6fcc 100644
--- a/drivers/gpu/drm/radeon/Kconfig
+++ b/drivers/gpu/drm/radeon/Kconfig
@@ -1,10 +1,14 @@
config DRM_RADEON_KMS
- bool "Enable modesetting on radeon by default"
+ bool "Enable modesetting on radeon by default - NEW DRIVER"
depends on DRM_RADEON
help
- Choose this option if you want kernel modesetting enabled by default,
- and you have a new enough userspace to support this. Running old
- userspaces with this enabled will cause pain.
+ Choose this option if you want kernel modesetting enabled by default.
+
+ This is a completely new driver. It's only part of the existing drm
+ for compatibility reasons. It requires an entirely different graphics
+ stack above it and works very differently from the old drm stack.
+ i.e. don't enable this unless you know what you are doing it may
+ cause issues or bugs compared to the previous userspace driver stack.
When kernel modesetting is enabled the IOCTL of radeon/drm
driver are considered as invalid and an error message is printed
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 1cc7b937b1ea..ed38262d9985 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -30,6 +30,9 @@ $(obj)/r420_reg_safe.h: $(src)/reg_srcs/r420 $(obj)/mkregtable
$(obj)/rs600_reg_safe.h: $(src)/reg_srcs/rs600 $(obj)/mkregtable
$(call if_changed,mkregtable)
+$(obj)/r600_reg_safe.h: $(src)/reg_srcs/r600 $(obj)/mkregtable
+ $(call if_changed,mkregtable)
+
$(obj)/r100.o: $(obj)/r100_reg_safe.h $(obj)/rn50_reg_safe.h
$(obj)/r200.o: $(obj)/r200_reg_safe.h
@@ -42,6 +45,8 @@ $(obj)/r420.o: $(obj)/r420_reg_safe.h
$(obj)/rs600.o: $(obj)/rs600_reg_safe.h
+$(obj)/r600_cs.o: $(obj)/r600_reg_safe.h
+
radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o \
radeon_irq.o r300_cmdbuf.o r600_cp.o
# add KMS driver
@@ -54,8 +59,10 @@ radeon-y += radeon_device.o radeon_kms.o \
radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \
rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \
r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \
- r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o
+ r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \
+ evergreen.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
+radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
obj-$(CONFIG_DRM_RADEON)+= radeon.o
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
index 388140a7e651..d75788feac6c 100644
--- a/drivers/gpu/drm/radeon/atom.c
+++ b/drivers/gpu/drm/radeon/atom.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/sched.h>
+#include <asm/unaligned.h>
#define ATOM_DEBUG
@@ -212,7 +213,9 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
case ATOM_ARG_PS:
idx = U8(*ptr);
(*ptr)++;
- val = le32_to_cpu(ctx->ps[idx]);
+ /* get_unaligned_le32 avoids unaligned accesses from atombios
+ * tables, noticed on a DEC Alpha. */
+ val = get_unaligned_le32((u32 *)&ctx->ps[idx]);
if (print)
DEBUG("PS[0x%02X,0x%04X]", idx, val);
break;
@@ -246,6 +249,9 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
case ATOM_WS_ATTRIBUTES:
val = gctx->io_attr;
break;
+ case ATOM_WS_REGPTR:
+ val = gctx->reg_block;
+ break;
default:
val = ctx->ws[idx];
}
@@ -385,6 +391,32 @@ static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
return atom_get_src_int(ctx, attr, ptr, NULL, 1);
}
+static uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr)
+{
+ uint32_t val = 0xCDCDCDCD;
+
+ switch (align) {
+ case ATOM_SRC_DWORD:
+ val = U32(*ptr);
+ (*ptr) += 4;
+ break;
+ case ATOM_SRC_WORD0:
+ case ATOM_SRC_WORD8:
+ case ATOM_SRC_WORD16:
+ val = U16(*ptr);
+ (*ptr) += 2;
+ break;
+ case ATOM_SRC_BYTE0:
+ case ATOM_SRC_BYTE8:
+ case ATOM_SRC_BYTE16:
+ case ATOM_SRC_BYTE24:
+ val = U8(*ptr);
+ (*ptr)++;
+ break;
+ }
+ return val;
+}
+
static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
int *ptr, uint32_t *saved, int print)
{
@@ -482,6 +514,9 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
case ATOM_WS_ATTRIBUTES:
gctx->io_attr = val;
break;
+ case ATOM_WS_REGPTR:
+ gctx->reg_block = val;
+ break;
default:
ctx->ws[idx] = val;
}
@@ -608,7 +643,7 @@ static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
uint8_t count = U8((*ptr)++);
SDEBUG(" count: %d\n", count);
if (arg == ATOM_UNIT_MICROSEC)
- schedule_timeout_uninterruptible(usecs_to_jiffies(count));
+ udelay(count);
else
schedule_timeout_uninterruptible(msecs_to_jiffies(count));
}
@@ -677,7 +712,7 @@ static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
SDEBUG(" dst: ");
dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
SDEBUG(" src1: ");
- src1 = atom_get_src(ctx, attr, ptr);
+ src1 = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr);
SDEBUG(" src2: ");
src2 = atom_get_src(ctx, attr, ptr);
dst &= src1;
@@ -809,7 +844,7 @@ static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block);
}
-static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
+static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg)
{
uint8_t attr = U8((*ptr)++), shift;
uint32_t saved, dst;
@@ -818,14 +853,14 @@ static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
attr |= atom_def_dst[attr >> 3] << 6;
SDEBUG(" dst: ");
dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
- shift = U8((*ptr)++);
+ shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
SDEBUG(" shift: %d\n", shift);
dst <<= shift;
SDEBUG(" dst: ");
atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
}
-static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
+static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg)
{
uint8_t attr = U8((*ptr)++), shift;
uint32_t saved, dst;
@@ -834,7 +869,35 @@ static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
attr |= atom_def_dst[attr >> 3] << 6;
SDEBUG(" dst: ");
dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
- shift = U8((*ptr)++);
+ shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
+ SDEBUG(" shift: %d\n", shift);
+ dst >>= shift;
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++), shift;
+ uint32_t saved, dst;
+ int dptr = *ptr;
+ SDEBUG(" dst: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ shift = atom_get_src(ctx, attr, ptr);
+ SDEBUG(" shift: %d\n", shift);
+ dst <<= shift;
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++), shift;
+ uint32_t saved, dst;
+ int dptr = *ptr;
+ SDEBUG(" dst: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ shift = atom_get_src(ctx, attr, ptr);
SDEBUG(" shift: %d\n", shift);
dst >>= shift;
SDEBUG(" dst: ");
@@ -937,18 +1000,18 @@ static struct {
atom_op_or, ATOM_ARG_FB}, {
atom_op_or, ATOM_ARG_PLL}, {
atom_op_or, ATOM_ARG_MC}, {
- atom_op_shl, ATOM_ARG_REG}, {
- atom_op_shl, ATOM_ARG_PS}, {
- atom_op_shl, ATOM_ARG_WS}, {
- atom_op_shl, ATOM_ARG_FB}, {
- atom_op_shl, ATOM_ARG_PLL}, {
- atom_op_shl, ATOM_ARG_MC}, {
- atom_op_shr, ATOM_ARG_REG}, {
- atom_op_shr, ATOM_ARG_PS}, {
- atom_op_shr, ATOM_ARG_WS}, {
- atom_op_shr, ATOM_ARG_FB}, {
- atom_op_shr, ATOM_ARG_PLL}, {
- atom_op_shr, ATOM_ARG_MC}, {
+ atom_op_shift_left, ATOM_ARG_REG}, {
+ atom_op_shift_left, ATOM_ARG_PS}, {
+ atom_op_shift_left, ATOM_ARG_WS}, {
+ atom_op_shift_left, ATOM_ARG_FB}, {
+ atom_op_shift_left, ATOM_ARG_PLL}, {
+ atom_op_shift_left, ATOM_ARG_MC}, {
+ atom_op_shift_right, ATOM_ARG_REG}, {
+ atom_op_shift_right, ATOM_ARG_PS}, {
+ atom_op_shift_right, ATOM_ARG_WS}, {
+ atom_op_shift_right, ATOM_ARG_FB}, {
+ atom_op_shift_right, ATOM_ARG_PLL}, {
+ atom_op_shift_right, ATOM_ARG_MC}, {
atom_op_mul, ATOM_ARG_REG}, {
atom_op_mul, ATOM_ARG_PS}, {
atom_op_mul, ATOM_ARG_WS}, {
@@ -1058,8 +1121,6 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
- /* reset reg block */
- ctx->reg_block = 0;
ectx.ctx = ctx;
ectx.ps_shift = ps / 4;
ectx.start = base;
@@ -1096,6 +1157,12 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3
void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
{
mutex_lock(&ctx->mutex);
+ /* reset reg block */
+ ctx->reg_block = 0;
+ /* reset fb window */
+ ctx->fb_base = 0;
+ /* reset io mode */
+ ctx->io_mode = ATOM_IO_MM;
atom_execute_table_locked(ctx, index, params);
mutex_unlock(&ctx->mutex);
}
diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h
index 47fd943f6d14..bc73781423a1 100644
--- a/drivers/gpu/drm/radeon/atom.h
+++ b/drivers/gpu/drm/radeon/atom.h
@@ -91,6 +91,7 @@
#define ATOM_WS_AND_MASK 0x45
#define ATOM_WS_FB_WINDOW 0x46
#define ATOM_WS_ATTRIBUTES 0x47
+#define ATOM_WS_REGPTR 0x48
#define ATOM_IIO_NOP 0
#define ATOM_IIO_START 1
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index 91ad0d1c1b17..6732b5dd8ff4 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2006-2007 Advanced Micro Devices, Inc.
+ * Copyright 2006-2007 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -20,10 +20,12 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-/****************************************************************************/
+
+/****************************************************************************/
/*Portion I: Definitions shared between VBIOS and Driver */
/****************************************************************************/
+
#ifndef _ATOMBIOS_H
#define _ATOMBIOS_H
@@ -40,39 +42,46 @@
#endif
#ifdef _H2INC
-#ifndef ULONG
-typedef unsigned long ULONG;
-#endif
+ #ifndef ULONG
+ typedef unsigned long ULONG;
+ #endif
-#ifndef UCHAR
-typedef unsigned char UCHAR;
-#endif
+ #ifndef UCHAR
+ typedef unsigned char UCHAR;
+ #endif
-#ifndef USHORT
-typedef unsigned short USHORT;
-#endif
+ #ifndef USHORT
+ typedef unsigned short USHORT;
+ #endif
#endif
-
-#define ATOM_DAC_A 0
+
+#define ATOM_DAC_A 0
#define ATOM_DAC_B 1
#define ATOM_EXT_DAC 2
#define ATOM_CRTC1 0
#define ATOM_CRTC2 1
+#define ATOM_CRTC3 2
+#define ATOM_CRTC4 3
+#define ATOM_CRTC5 4
+#define ATOM_CRTC6 5
+#define ATOM_CRTC_INVALID 0xFF
#define ATOM_DIGA 0
#define ATOM_DIGB 1
#define ATOM_PPLL1 0
#define ATOM_PPLL2 1
+#define ATOM_DCPLL 2
+#define ATOM_PPLL_INVALID 0xFF
#define ATOM_SCALER1 0
#define ATOM_SCALER2 1
-#define ATOM_SCALER_DISABLE 0
-#define ATOM_SCALER_CENTER 1
-#define ATOM_SCALER_EXPANSION 2
-#define ATOM_SCALER_MULTI_EX 3
+#define ATOM_SCALER_DISABLE 0
+#define ATOM_SCALER_CENTER 1
+#define ATOM_SCALER_EXPANSION 2
+#define ATOM_SCALER_MULTI_EX 3
#define ATOM_DISABLE 0
#define ATOM_ENABLE 1
@@ -82,6 +91,7 @@ typedef unsigned short USHORT;
#define ATOM_LCD_SELFTEST_START (ATOM_DISABLE+5)
#define ATOM_LCD_SELFTEST_STOP (ATOM_ENABLE+5)
#define ATOM_ENCODER_INIT (ATOM_DISABLE+7)
+#define ATOM_GET_STATUS (ATOM_DISABLE+8)
#define ATOM_BLANKING 1
#define ATOM_BLANKING_OFF 0
@@ -114,7 +124,7 @@ typedef unsigned short USHORT;
#define ATOM_DAC2_CV ATOM_DAC1_CV
#define ATOM_DAC2_NTSC ATOM_DAC1_NTSC
#define ATOM_DAC2_PAL ATOM_DAC1_PAL
-
+
#define ATOM_PM_ON 0
#define ATOM_PM_STANDBY 1
#define ATOM_PM_SUSPEND 2
@@ -134,6 +144,7 @@ typedef unsigned short USHORT;
#define ATOM_PANEL_MISC_TEMPORAL 0x00000040
#define ATOM_PANEL_MISC_API_ENABLED 0x00000080
+
#define MEMTYPE_DDR1 "DDR1"
#define MEMTYPE_DDR2 "DDR2"
#define MEMTYPE_DDR3 "DDR3"
@@ -145,19 +156,19 @@ typedef unsigned short USHORT;
/* Maximum size of that FireGL flag string */
-#define ATOM_FIREGL_FLAG_STRING "FGL" /* Flag used to enable FireGL Support */
-#define ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING 3 /* sizeof( ATOM_FIREGL_FLAG_STRING ) */
+#define ATOM_FIREGL_FLAG_STRING "FGL" //Flag used to enable FireGL Support
+#define ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING 3 //sizeof( ATOM_FIREGL_FLAG_STRING )
-#define ATOM_FAKE_DESKTOP_STRING "DSK" /* Flag used to enable mobile ASIC on Desktop */
-#define ATOM_MAX_SIZE_OF_FAKE_DESKTOP_STRING ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING
+#define ATOM_FAKE_DESKTOP_STRING "DSK" //Flag used to enable mobile ASIC on Desktop
+#define ATOM_MAX_SIZE_OF_FAKE_DESKTOP_STRING ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING
-#define ATOM_M54T_FLAG_STRING "M54T" /* Flag used to enable M54T Support */
-#define ATOM_MAX_SIZE_OF_M54T_FLAG_STRING 4 /* sizeof( ATOM_M54T_FLAG_STRING ) */
+#define ATOM_M54T_FLAG_STRING "M54T" //Flag used to enable M54T Support
+#define ATOM_MAX_SIZE_OF_M54T_FLAG_STRING 4 //sizeof( ATOM_M54T_FLAG_STRING )
#define HW_ASSISTED_I2C_STATUS_FAILURE 2
#define HW_ASSISTED_I2C_STATUS_SUCCESS 1
-#pragma pack(1) /* BIOS data must use byte aligment */
+#pragma pack(1) /* BIOS data must use byte aligment */
/* Define offset to location of ROM header. */
@@ -165,367 +176,410 @@ typedef unsigned short USHORT;
#define OFFSET_TO_ATOM_ROM_IMAGE_SIZE 0x00000002L
#define OFFSET_TO_ATOMBIOS_ASIC_BUS_MEM_TYPE 0x94
-#define MAXSIZE_OF_ATOMBIOS_ASIC_BUS_MEM_TYPE 20 /* including the terminator 0x0! */
+#define MAXSIZE_OF_ATOMBIOS_ASIC_BUS_MEM_TYPE 20 /* including the terminator 0x0! */
#define OFFSET_TO_GET_ATOMBIOS_STRINGS_NUMBER 0x002f
#define OFFSET_TO_GET_ATOMBIOS_STRINGS_START 0x006e
/* Common header for all ROM Data tables.
- Every table pointed _ATOM_MASTER_DATA_TABLE has this common header.
+ Every table pointed _ATOM_MASTER_DATA_TABLE has this common header.
And the pointer actually points to this header. */
-typedef struct _ATOM_COMMON_TABLE_HEADER {
- USHORT usStructureSize;
- UCHAR ucTableFormatRevision; /*Change it when the Parser is not backward compatible */
- UCHAR ucTableContentRevision; /*Change it only when the table needs to change but the firmware */
- /*Image can't be updated, while Driver needs to carry the new table! */
-} ATOM_COMMON_TABLE_HEADER;
-
-typedef struct _ATOM_ROM_HEADER {
- ATOM_COMMON_TABLE_HEADER sHeader;
- UCHAR uaFirmWareSignature[4]; /*Signature to distinguish between Atombios and non-atombios,
- atombios should init it as "ATOM", don't change the position */
- USHORT usBiosRuntimeSegmentAddress;
- USHORT usProtectedModeInfoOffset;
- USHORT usConfigFilenameOffset;
- USHORT usCRC_BlockOffset;
- USHORT usBIOS_BootupMessageOffset;
- USHORT usInt10Offset;
- USHORT usPciBusDevInitCode;
- USHORT usIoBaseAddress;
- USHORT usSubsystemVendorID;
- USHORT usSubsystemID;
- USHORT usPCI_InfoOffset;
- USHORT usMasterCommandTableOffset; /*Offset for SW to get all command table offsets, Don't change the position */
- USHORT usMasterDataTableOffset; /*Offset for SW to get all data table offsets, Don't change the position */
- UCHAR ucExtendedFunctionCode;
- UCHAR ucReserved;
-} ATOM_ROM_HEADER;
+typedef struct _ATOM_COMMON_TABLE_HEADER
+{
+ USHORT usStructureSize;
+ UCHAR ucTableFormatRevision; /*Change it when the Parser is not backward compatible */
+ UCHAR ucTableContentRevision; /*Change it only when the table needs to change but the firmware */
+ /*Image can't be updated, while Driver needs to carry the new table! */
+}ATOM_COMMON_TABLE_HEADER;
+
+typedef struct _ATOM_ROM_HEADER
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR uaFirmWareSignature[4]; /*Signature to distinguish between Atombios and non-atombios,
+ atombios should init it as "ATOM", don't change the position */
+ USHORT usBiosRuntimeSegmentAddress;
+ USHORT usProtectedModeInfoOffset;
+ USHORT usConfigFilenameOffset;
+ USHORT usCRC_BlockOffset;
+ USHORT usBIOS_BootupMessageOffset;
+ USHORT usInt10Offset;
+ USHORT usPciBusDevInitCode;
+ USHORT usIoBaseAddress;
+ USHORT usSubsystemVendorID;
+ USHORT usSubsystemID;
+ USHORT usPCI_InfoOffset;
+ USHORT usMasterCommandTableOffset; /*Offset for SW to get all command table offsets, Don't change the position */
+ USHORT usMasterDataTableOffset; /*Offset for SW to get all data table offsets, Don't change the position */
+ UCHAR ucExtendedFunctionCode;
+ UCHAR ucReserved;
+}ATOM_ROM_HEADER;
/*==============================Command Table Portion==================================== */
#ifdef UEFI_BUILD
-#define UTEMP USHORT
-#define USHORT void*
+ #define UTEMP USHORT
+ #define USHORT void*
#endif
-typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES {
- USHORT ASIC_Init; /* Function Table, used by various SW components,latest version 1.1 */
- USHORT GetDisplaySurfaceSize; /* Atomic Table, Used by Bios when enabling HW ICON */
- USHORT ASIC_RegistersInit; /* Atomic Table, indirectly used by various SW components,called from ASIC_Init */
- USHORT VRAM_BlockVenderDetection; /* Atomic Table, used only by Bios */
- USHORT DIGxEncoderControl; /* Only used by Bios */
- USHORT MemoryControllerInit; /* Atomic Table, indirectly used by various SW components,called from ASIC_Init */
- USHORT EnableCRTCMemReq; /* Function Table,directly used by various SW components,latest version 2.1 */
- USHORT MemoryParamAdjust; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock if needed */
- USHORT DVOEncoderControl; /* Function Table,directly used by various SW components,latest version 1.2 */
- USHORT GPIOPinControl; /* Atomic Table, only used by Bios */
- USHORT SetEngineClock; /*Function Table,directly used by various SW components,latest version 1.1 */
- USHORT SetMemoryClock; /* Function Table,directly used by various SW components,latest version 1.1 */
- USHORT SetPixelClock; /*Function Table,directly used by various SW components,latest version 1.2 */
- USHORT DynamicClockGating; /* Atomic Table, indirectly used by various SW components,called from ASIC_Init */
- USHORT ResetMemoryDLL; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock */
- USHORT ResetMemoryDevice; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock */
- USHORT MemoryPLLInit;
- USHORT AdjustDisplayPll; /* only used by Bios */
- USHORT AdjustMemoryController; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock */
- USHORT EnableASIC_StaticPwrMgt; /* Atomic Table, only used by Bios */
- USHORT ASIC_StaticPwrMgtStatusChange; /* Obsolete, only used by Bios */
- USHORT DAC_LoadDetection; /* Atomic Table, directly used by various SW components,latest version 1.2 */
- USHORT LVTMAEncoderControl; /* Atomic Table,directly used by various SW components,latest version 1.3 */
- USHORT LCD1OutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT DAC1EncoderControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT DAC2EncoderControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT DVOOutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT CV1OutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT GetConditionalGoldenSetting; /* only used by Bios */
- USHORT TVEncoderControl; /* Function Table,directly used by various SW components,latest version 1.1 */
- USHORT TMDSAEncoderControl; /* Atomic Table, directly used by various SW components,latest version 1.3 */
- USHORT LVDSEncoderControl; /* Atomic Table, directly used by various SW components,latest version 1.3 */
- USHORT TV1OutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT EnableScaler; /* Atomic Table, used only by Bios */
- USHORT BlankCRTC; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT EnableCRTC; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT GetPixelClock; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT EnableVGA_Render; /* Function Table,directly used by various SW components,latest version 1.1 */
- USHORT EnableVGA_Access; /* Obsolete , only used by Bios */
- USHORT SetCRTC_Timing; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT SetCRTC_OverScan; /* Atomic Table, used by various SW components,latest version 1.1 */
- USHORT SetCRTC_Replication; /* Atomic Table, used only by Bios */
- USHORT SelectCRTC_Source; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT EnableGraphSurfaces; /* Atomic Table, used only by Bios */
- USHORT UpdateCRTC_DoubleBufferRegisters;
- USHORT LUT_AutoFill; /* Atomic Table, only used by Bios */
- USHORT EnableHW_IconCursor; /* Atomic Table, only used by Bios */
- USHORT GetMemoryClock; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT GetEngineClock; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT SetCRTC_UsingDTDTiming; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT ExternalEncoderControl; /* Atomic Table, directly used by various SW components,latest version 2.1 */
- USHORT LVTMAOutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT VRAM_BlockDetectionByStrap; /* Atomic Table, used only by Bios */
- USHORT MemoryCleanUp; /* Atomic Table, only used by Bios */
- USHORT ProcessI2cChannelTransaction; /* Function Table,only used by Bios */
- USHORT WriteOneByteToHWAssistedI2C; /* Function Table,indirectly used by various SW components */
- USHORT ReadHWAssistedI2CStatus; /* Atomic Table, indirectly used by various SW components */
- USHORT SpeedFanControl; /* Function Table,indirectly used by various SW components,called from ASIC_Init */
- USHORT PowerConnectorDetection; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT MC_Synchronization; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock */
- USHORT ComputeMemoryEnginePLL; /* Atomic Table, indirectly used by various SW components,called from SetMemory/EngineClock */
- USHORT MemoryRefreshConversion; /* Atomic Table, indirectly used by various SW components,called from SetMemory or SetEngineClock */
- USHORT VRAM_GetCurrentInfoBlock; /* Atomic Table, used only by Bios */
- USHORT DynamicMemorySettings; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock */
- USHORT MemoryTraining; /* Atomic Table, used only by Bios */
- USHORT EnableSpreadSpectrumOnPPLL; /* Atomic Table, directly used by various SW components,latest version 1.2 */
- USHORT TMDSAOutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT SetVoltage; /* Function Table,directly and/or indirectly used by various SW components,latest version 1.1 */
- USHORT DAC1OutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT DAC2OutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */
- USHORT SetupHWAssistedI2CStatus; /* Function Table,only used by Bios, obsolete soon.Switch to use "ReadEDIDFromHWAssistedI2C" */
- USHORT ClockSource; /* Atomic Table, indirectly used by various SW components,called from ASIC_Init */
- USHORT MemoryDeviceInit; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock */
- USHORT EnableYUV; /* Atomic Table, indirectly used by various SW components,called from EnableVGARender */
- USHORT DIG1EncoderControl; /* Atomic Table,directly used by various SW components,latest version 1.1 */
- USHORT DIG2EncoderControl; /* Atomic Table,directly used by various SW components,latest version 1.1 */
- USHORT DIG1TransmitterControl; /* Atomic Table,directly used by various SW components,latest version 1.1 */
- USHORT DIG2TransmitterControl; /* Atomic Table,directly used by various SW components,latest version 1.1 */
- USHORT ProcessAuxChannelTransaction; /* Function Table,only used by Bios */
- USHORT DPEncoderService; /* Function Table,only used by Bios */
-} ATOM_MASTER_LIST_OF_COMMAND_TABLES;
-
-/* For backward compatible */
+typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
+ USHORT ASIC_Init; //Function Table, used by various SW components,latest version 1.1
+ USHORT GetDisplaySurfaceSize; //Atomic Table, Used by Bios when enabling HW ICON
+ USHORT ASIC_RegistersInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init
+ USHORT VRAM_BlockVenderDetection; //Atomic Table, used only by Bios
+ USHORT DIGxEncoderControl; //Only used by Bios
+ USHORT MemoryControllerInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init
+ USHORT EnableCRTCMemReq; //Function Table,directly used by various SW components,latest version 2.1
+ USHORT MemoryParamAdjust; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock if needed
+ USHORT DVOEncoderControl; //Function Table,directly used by various SW components,latest version 1.2
+ USHORT GPIOPinControl; //Atomic Table, only used by Bios
+ USHORT SetEngineClock; //Function Table,directly used by various SW components,latest version 1.1
+ USHORT SetMemoryClock; //Function Table,directly used by various SW components,latest version 1.1
+ USHORT SetPixelClock; //Function Table,directly used by various SW components,latest version 1.2
+ USHORT DynamicClockGating; //Atomic Table, indirectly used by various SW components,called from ASIC_Init
+ USHORT ResetMemoryDLL; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock
+ USHORT ResetMemoryDevice; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock
+ USHORT MemoryPLLInit;
+ USHORT AdjustDisplayPll; //only used by Bios
+ USHORT AdjustMemoryController; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock
+ USHORT EnableASIC_StaticPwrMgt; //Atomic Table, only used by Bios
+ USHORT ASIC_StaticPwrMgtStatusChange; //Obsolete , only used by Bios
+ USHORT DAC_LoadDetection; //Atomic Table, directly used by various SW components,latest version 1.2
+ USHORT LVTMAEncoderControl; //Atomic Table,directly used by various SW components,latest version 1.3
+ USHORT LCD1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT DAC1EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT DAC2EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT DVOOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT CV1OutputControl; //Atomic Table, Atomic Table, Obsolete from Ry6xx, use DAC2 Output instead
+ USHORT GetConditionalGoldenSetting; //only used by Bios
+ USHORT TVEncoderControl; //Function Table,directly used by various SW components,latest version 1.1
+ USHORT TMDSAEncoderControl; //Atomic Table, directly used by various SW components,latest version 1.3
+ USHORT LVDSEncoderControl; //Atomic Table, directly used by various SW components,latest version 1.3
+ USHORT TV1OutputControl; //Atomic Table, Obsolete from Ry6xx, use DAC2 Output instead
+ USHORT EnableScaler; //Atomic Table, used only by Bios
+ USHORT BlankCRTC; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT EnableCRTC; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT GetPixelClock; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT EnableVGA_Render; //Function Table,directly used by various SW components,latest version 1.1
+ USHORT GetSCLKOverMCLKRatio; //Atomic Table, only used by Bios
+ USHORT SetCRTC_Timing; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT SetCRTC_OverScan; //Atomic Table, used by various SW components,latest version 1.1
+ USHORT SetCRTC_Replication; //Atomic Table, used only by Bios
+ USHORT SelectCRTC_Source; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT EnableGraphSurfaces; //Atomic Table, used only by Bios
+ USHORT UpdateCRTC_DoubleBufferRegisters;
+ USHORT LUT_AutoFill; //Atomic Table, only used by Bios
+ USHORT EnableHW_IconCursor; //Atomic Table, only used by Bios
+ USHORT GetMemoryClock; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT GetEngineClock; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT SetCRTC_UsingDTDTiming; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT ExternalEncoderControl; //Atomic Table, directly used by various SW components,latest version 2.1
+ USHORT LVTMAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT VRAM_BlockDetectionByStrap; //Atomic Table, used only by Bios
+ USHORT MemoryCleanUp; //Atomic Table, only used by Bios
+ USHORT ProcessI2cChannelTransaction; //Function Table,only used by Bios
+ USHORT WriteOneByteToHWAssistedI2C; //Function Table,indirectly used by various SW components
+ USHORT ReadHWAssistedI2CStatus; //Atomic Table, indirectly used by various SW components
+ USHORT SpeedFanControl; //Function Table,indirectly used by various SW components,called from ASIC_Init
+ USHORT PowerConnectorDetection; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT MC_Synchronization; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock
+ USHORT ComputeMemoryEnginePLL; //Atomic Table, indirectly used by various SW components,called from SetMemory/EngineClock
+ USHORT MemoryRefreshConversion; //Atomic Table, indirectly used by various SW components,called from SetMemory or SetEngineClock
+ USHORT VRAM_GetCurrentInfoBlock; //Atomic Table, used only by Bios
+ USHORT DynamicMemorySettings; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock
+ USHORT MemoryTraining; //Atomic Table, used only by Bios
+ USHORT EnableSpreadSpectrumOnPPLL; //Atomic Table, directly used by various SW components,latest version 1.2
+ USHORT TMDSAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT SetVoltage; //Function Table,directly and/or indirectly used by various SW components,latest version 1.1
+ USHORT DAC1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT DAC2OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT SetupHWAssistedI2CStatus; //Function Table,only used by Bios, obsolete soon.Switch to use "ReadEDIDFromHWAssistedI2C"
+ USHORT ClockSource; //Atomic Table, indirectly used by various SW components,called from ASIC_Init
+ USHORT MemoryDeviceInit; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock
+ USHORT EnableYUV; //Atomic Table, indirectly used by various SW components,called from EnableVGARender
+ USHORT DIG1EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1
+ USHORT DIG2EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1
+ USHORT DIG1TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1
+ USHORT DIG2TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1
+ USHORT ProcessAuxChannelTransaction; //Function Table,only used by Bios
+ USHORT DPEncoderService; //Function Table,only used by Bios
+}ATOM_MASTER_LIST_OF_COMMAND_TABLES;
+
+// For backward compatible
#define ReadEDIDFromHWAssistedI2C ProcessI2cChannelTransaction
#define UNIPHYTransmitterControl DIG1TransmitterControl
#define LVTMATransmitterControl DIG2TransmitterControl
#define SetCRTC_DPM_State GetConditionalGoldenSetting
#define SetUniphyInstance ASIC_StaticPwrMgtStatusChange
+#define HPDInterruptService ReadHWAssistedI2CStatus
+#define EnableVGA_Access GetSCLKOverMCLKRatio
-typedef struct _ATOM_MASTER_COMMAND_TABLE {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_MASTER_LIST_OF_COMMAND_TABLES ListOfCommandTables;
-} ATOM_MASTER_COMMAND_TABLE;
-
-/****************************************************************************/
-/* Structures used in every command table */
-/****************************************************************************/
-typedef struct _ATOM_TABLE_ATTRIBUTE {
+typedef struct _ATOM_MASTER_COMMAND_TABLE
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_MASTER_LIST_OF_COMMAND_TABLES ListOfCommandTables;
+}ATOM_MASTER_COMMAND_TABLE;
+
+/****************************************************************************/
+// Structures used in every command table
+/****************************************************************************/
+typedef struct _ATOM_TABLE_ATTRIBUTE
+{
#if ATOM_BIG_ENDIAN
- USHORT UpdatedByUtility:1; /* [15]=Table updated by utility flag */
- USHORT PS_SizeInBytes:7; /* [14:8]=Size of parameter space in Bytes (multiple of a dword), */
- USHORT WS_SizeInBytes:8; /* [7:0]=Size of workspace in Bytes (in multiple of a dword), */
+ USHORT UpdatedByUtility:1; //[15]=Table updated by utility flag
+ USHORT PS_SizeInBytes:7; //[14:8]=Size of parameter space in Bytes (multiple of a dword),
+ USHORT WS_SizeInBytes:8; //[7:0]=Size of workspace in Bytes (in multiple of a dword),
#else
- USHORT WS_SizeInBytes:8; /* [7:0]=Size of workspace in Bytes (in multiple of a dword), */
- USHORT PS_SizeInBytes:7; /* [14:8]=Size of parameter space in Bytes (multiple of a dword), */
- USHORT UpdatedByUtility:1; /* [15]=Table updated by utility flag */
+ USHORT WS_SizeInBytes:8; //[7:0]=Size of workspace in Bytes (in multiple of a dword),
+ USHORT PS_SizeInBytes:7; //[14:8]=Size of parameter space in Bytes (multiple of a dword),
+ USHORT UpdatedByUtility:1; //[15]=Table updated by utility flag
#endif
-} ATOM_TABLE_ATTRIBUTE;
-
-typedef union _ATOM_TABLE_ATTRIBUTE_ACCESS {
- ATOM_TABLE_ATTRIBUTE sbfAccess;
- USHORT susAccess;
-} ATOM_TABLE_ATTRIBUTE_ACCESS;
+}ATOM_TABLE_ATTRIBUTE;
-/****************************************************************************/
-/* Common header for all command tables. */
-/* Every table pointed by _ATOM_MASTER_COMMAND_TABLE has this common header. */
-/* And the pointer actually points to this header. */
-/****************************************************************************/
-typedef struct _ATOM_COMMON_ROM_COMMAND_TABLE_HEADER {
- ATOM_COMMON_TABLE_HEADER CommonHeader;
- ATOM_TABLE_ATTRIBUTE TableAttribute;
-} ATOM_COMMON_ROM_COMMAND_TABLE_HEADER;
+typedef union _ATOM_TABLE_ATTRIBUTE_ACCESS
+{
+ ATOM_TABLE_ATTRIBUTE sbfAccess;
+ USHORT susAccess;
+}ATOM_TABLE_ATTRIBUTE_ACCESS;
+
+/****************************************************************************/
+// Common header for all command tables.
+// Every table pointed by _ATOM_MASTER_COMMAND_TABLE has this common header.
+// And the pointer actually points to this header.
+/****************************************************************************/
+typedef struct _ATOM_COMMON_ROM_COMMAND_TABLE_HEADER
+{
+ ATOM_COMMON_TABLE_HEADER CommonHeader;
+ ATOM_TABLE_ATTRIBUTE TableAttribute;
+}ATOM_COMMON_ROM_COMMAND_TABLE_HEADER;
-/****************************************************************************/
-/* Structures used by ComputeMemoryEnginePLLTable */
-/****************************************************************************/
+/****************************************************************************/
+// Structures used by ComputeMemoryEnginePLLTable
+/****************************************************************************/
#define COMPUTE_MEMORY_PLL_PARAM 1
#define COMPUTE_ENGINE_PLL_PARAM 2
-typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS {
- ULONG ulClock; /* When returen, it's the re-calculated clock based on given Fb_div Post_Div and ref_div */
- UCHAR ucAction; /* 0:reserved //1:Memory //2:Engine */
- UCHAR ucReserved; /* may expand to return larger Fbdiv later */
- UCHAR ucFbDiv; /* return value */
- UCHAR ucPostDiv; /* return value */
-} COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS;
-
-typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 {
- ULONG ulClock; /* When return, [23:0] return real clock */
- UCHAR ucAction; /* 0:reserved;COMPUTE_MEMORY_PLL_PARAM:Memory;COMPUTE_ENGINE_PLL_PARAM:Engine. it return ref_div to be written to register */
- USHORT usFbDiv; /* return Feedback value to be written to register */
- UCHAR ucPostDiv; /* return post div to be written to register */
-} COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2;
+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS
+{
+ ULONG ulClock; //When returen, it's the re-calculated clock based on given Fb_div Post_Div and ref_div
+ UCHAR ucAction; //0:reserved //1:Memory //2:Engine
+ UCHAR ucReserved; //may expand to return larger Fbdiv later
+ UCHAR ucFbDiv; //return value
+ UCHAR ucPostDiv; //return value
+}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS;
+
+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2
+{
+ ULONG ulClock; //When return, [23:0] return real clock
+ UCHAR ucAction; //0:reserved;COMPUTE_MEMORY_PLL_PARAM:Memory;COMPUTE_ENGINE_PLL_PARAM:Engine. it return ref_div to be written to register
+ USHORT usFbDiv; //return Feedback value to be written to register
+ UCHAR ucPostDiv; //return post div to be written to register
+}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2;
#define COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS
-#define SET_CLOCK_FREQ_MASK 0x00FFFFFF /* Clock change tables only take bit [23:0] as the requested clock value */
-#define USE_NON_BUS_CLOCK_MASK 0x01000000 /* Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa) */
-#define USE_MEMORY_SELF_REFRESH_MASK 0x02000000 /* Only applicable to memory clock change, when set, using memory self refresh during clock transition */
-#define SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04000000 /* Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change */
-#define FIRST_TIME_CHANGE_CLOCK 0x08000000 /* Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup */
-#define SKIP_SW_PROGRAM_PLL 0x10000000 /* Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL */
+
+#define SET_CLOCK_FREQ_MASK 0x00FFFFFF //Clock change tables only take bit [23:0] as the requested clock value
+#define USE_NON_BUS_CLOCK_MASK 0x01000000 //Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa)
+#define USE_MEMORY_SELF_REFRESH_MASK 0x02000000 //Only applicable to memory clock change, when set, using memory self refresh during clock transition
+#define SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04000000 //Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change
+#define FIRST_TIME_CHANGE_CLOCK 0x08000000 //Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup
+#define SKIP_SW_PROGRAM_PLL 0x10000000 //Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL
#define USE_SS_ENABLED_PIXEL_CLOCK USE_NON_BUS_CLOCK_MASK
-#define b3USE_NON_BUS_CLOCK_MASK 0x01 /* Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa) */
-#define b3USE_MEMORY_SELF_REFRESH 0x02 /* Only applicable to memory clock change, when set, using memory self refresh during clock transition */
-#define b3SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04 /* Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change */
-#define b3FIRST_TIME_CHANGE_CLOCK 0x08 /* Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup */
-#define b3SKIP_SW_PROGRAM_PLL 0x10 /* Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL */
+#define b3USE_NON_BUS_CLOCK_MASK 0x01 //Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa)
+#define b3USE_MEMORY_SELF_REFRESH 0x02 //Only applicable to memory clock change, when set, using memory self refresh during clock transition
+#define b3SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04 //Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change
+#define b3FIRST_TIME_CHANGE_CLOCK 0x08 //Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup
+#define b3SKIP_SW_PROGRAM_PLL 0x10 //Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL
-typedef struct _ATOM_COMPUTE_CLOCK_FREQ {
+typedef struct _ATOM_COMPUTE_CLOCK_FREQ
+{
#if ATOM_BIG_ENDIAN
- ULONG ulComputeClockFlag:8; /* =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM */
- ULONG ulClockFreq:24; /* in unit of 10kHz */
+ ULONG ulComputeClockFlag:8; // =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM
+ ULONG ulClockFreq:24; // in unit of 10kHz
#else
- ULONG ulClockFreq:24; /* in unit of 10kHz */
- ULONG ulComputeClockFlag:8; /* =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM */
+ ULONG ulClockFreq:24; // in unit of 10kHz
+ ULONG ulComputeClockFlag:8; // =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM
#endif
-} ATOM_COMPUTE_CLOCK_FREQ;
-
-typedef struct _ATOM_S_MPLL_FB_DIVIDER {
- USHORT usFbDivFrac;
- USHORT usFbDiv;
-} ATOM_S_MPLL_FB_DIVIDER;
+}ATOM_COMPUTE_CLOCK_FREQ;
-typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 {
- union {
- ATOM_COMPUTE_CLOCK_FREQ ulClock; /* Input Parameter */
- ATOM_S_MPLL_FB_DIVIDER ulFbDiv; /* Output Parameter */
- };
- UCHAR ucRefDiv; /* Output Parameter */
- UCHAR ucPostDiv; /* Output Parameter */
- UCHAR ucCntlFlag; /* Output Parameter */
- UCHAR ucReserved;
-} COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3;
+typedef struct _ATOM_S_MPLL_FB_DIVIDER
+{
+ USHORT usFbDivFrac;
+ USHORT usFbDiv;
+}ATOM_S_MPLL_FB_DIVIDER;
-/* ucCntlFlag */
+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3
+{
+ union
+ {
+ ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter
+ ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter
+ };
+ UCHAR ucRefDiv; //Output Parameter
+ UCHAR ucPostDiv; //Output Parameter
+ UCHAR ucCntlFlag; //Output Parameter
+ UCHAR ucReserved;
+}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3;
+
+// ucCntlFlag
#define ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN 1
#define ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE 2
#define ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE 4
+#define ATOM_PLL_CNTL_FLAG_SPLL_ISPARE_9 8
-typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER {
- ATOM_COMPUTE_CLOCK_FREQ ulClock;
- ULONG ulReserved[2];
-} DYNAMICE_MEMORY_SETTINGS_PARAMETER;
-
-typedef struct _DYNAMICE_ENGINE_SETTINGS_PARAMETER {
- ATOM_COMPUTE_CLOCK_FREQ ulClock;
- ULONG ulMemoryClock;
- ULONG ulReserved;
-} DYNAMICE_ENGINE_SETTINGS_PARAMETER;
-
-/****************************************************************************/
-/* Structures used by SetEngineClockTable */
-/****************************************************************************/
-typedef struct _SET_ENGINE_CLOCK_PARAMETERS {
- ULONG ulTargetEngineClock; /* In 10Khz unit */
-} SET_ENGINE_CLOCK_PARAMETERS;
-typedef struct _SET_ENGINE_CLOCK_PS_ALLOCATION {
- ULONG ulTargetEngineClock; /* In 10Khz unit */
- COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved;
-} SET_ENGINE_CLOCK_PS_ALLOCATION;
+// V4 are only used for APU which PLL outside GPU
+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4
+{
+#if ATOM_BIG_ENDIAN
+ ULONG ucPostDiv; //return parameter: post divider which is used to program to register directly
+ ULONG ulClock:24; //Input= target clock, output = actual clock
+#else
+ ULONG ulClock:24; //Input= target clock, output = actual clock
+ ULONG ucPostDiv; //return parameter: post divider which is used to program to register directly
+#endif
+}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4;
-/****************************************************************************/
-/* Structures used by SetMemoryClockTable */
-/****************************************************************************/
-typedef struct _SET_MEMORY_CLOCK_PARAMETERS {
- ULONG ulTargetMemoryClock; /* In 10Khz unit */
-} SET_MEMORY_CLOCK_PARAMETERS;
+typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER
+{
+ ATOM_COMPUTE_CLOCK_FREQ ulClock;
+ ULONG ulReserved[2];
+}DYNAMICE_MEMORY_SETTINGS_PARAMETER;
-typedef struct _SET_MEMORY_CLOCK_PS_ALLOCATION {
- ULONG ulTargetMemoryClock; /* In 10Khz unit */
- COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved;
-} SET_MEMORY_CLOCK_PS_ALLOCATION;
+typedef struct _DYNAMICE_ENGINE_SETTINGS_PARAMETER
+{
+ ATOM_COMPUTE_CLOCK_FREQ ulClock;
+ ULONG ulMemoryClock;
+ ULONG ulReserved;
+}DYNAMICE_ENGINE_SETTINGS_PARAMETER;
+
+/****************************************************************************/
+// Structures used by SetEngineClockTable
+/****************************************************************************/
+typedef struct _SET_ENGINE_CLOCK_PARAMETERS
+{
+ ULONG ulTargetEngineClock; //In 10Khz unit
+}SET_ENGINE_CLOCK_PARAMETERS;
-/****************************************************************************/
-/* Structures used by ASIC_Init.ctb */
-/****************************************************************************/
-typedef struct _ASIC_INIT_PARAMETERS {
- ULONG ulDefaultEngineClock; /* In 10Khz unit */
- ULONG ulDefaultMemoryClock; /* In 10Khz unit */
-} ASIC_INIT_PARAMETERS;
+typedef struct _SET_ENGINE_CLOCK_PS_ALLOCATION
+{
+ ULONG ulTargetEngineClock; //In 10Khz unit
+ COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved;
+}SET_ENGINE_CLOCK_PS_ALLOCATION;
+
+/****************************************************************************/
+// Structures used by SetMemoryClockTable
+/****************************************************************************/
+typedef struct _SET_MEMORY_CLOCK_PARAMETERS
+{
+ ULONG ulTargetMemoryClock; //In 10Khz unit
+}SET_MEMORY_CLOCK_PARAMETERS;
-typedef struct _ASIC_INIT_PS_ALLOCATION {
- ASIC_INIT_PARAMETERS sASICInitClocks;
- SET_ENGINE_CLOCK_PS_ALLOCATION sReserved; /* Caller doesn't need to init this structure */
-} ASIC_INIT_PS_ALLOCATION;
+typedef struct _SET_MEMORY_CLOCK_PS_ALLOCATION
+{
+ ULONG ulTargetMemoryClock; //In 10Khz unit
+ COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved;
+}SET_MEMORY_CLOCK_PS_ALLOCATION;
+
+/****************************************************************************/
+// Structures used by ASIC_Init.ctb
+/****************************************************************************/
+typedef struct _ASIC_INIT_PARAMETERS
+{
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+}ASIC_INIT_PARAMETERS;
-/****************************************************************************/
-/* Structure used by DynamicClockGatingTable.ctb */
-/****************************************************************************/
-typedef struct _DYNAMIC_CLOCK_GATING_PARAMETERS {
- UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */
- UCHAR ucPadding[3];
-} DYNAMIC_CLOCK_GATING_PARAMETERS;
+typedef struct _ASIC_INIT_PS_ALLOCATION
+{
+ ASIC_INIT_PARAMETERS sASICInitClocks;
+ SET_ENGINE_CLOCK_PS_ALLOCATION sReserved; //Caller doesn't need to init this structure
+}ASIC_INIT_PS_ALLOCATION;
+
+/****************************************************************************/
+// Structure used by DynamicClockGatingTable.ctb
+/****************************************************************************/
+typedef struct _DYNAMIC_CLOCK_GATING_PARAMETERS
+{
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucPadding[3];
+}DYNAMIC_CLOCK_GATING_PARAMETERS;
#define DYNAMIC_CLOCK_GATING_PS_ALLOCATION DYNAMIC_CLOCK_GATING_PARAMETERS
-/****************************************************************************/
-/* Structure used by EnableASIC_StaticPwrMgtTable.ctb */
-/****************************************************************************/
-typedef struct _ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS {
- UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */
- UCHAR ucPadding[3];
-} ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS;
+/****************************************************************************/
+// Structure used by EnableASIC_StaticPwrMgtTable.ctb
+/****************************************************************************/
+typedef struct _ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS
+{
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucPadding[3];
+}ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS;
#define ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS
-/****************************************************************************/
-/* Structures used by DAC_LoadDetectionTable.ctb */
-/****************************************************************************/
-typedef struct _DAC_LOAD_DETECTION_PARAMETERS {
- USHORT usDeviceID; /* {ATOM_DEVICE_CRTx_SUPPORT,ATOM_DEVICE_TVx_SUPPORT,ATOM_DEVICE_CVx_SUPPORT} */
- UCHAR ucDacType; /* {ATOM_DAC_A,ATOM_DAC_B, ATOM_EXT_DAC} */
- UCHAR ucMisc; /* Valid only when table revision =1.3 and above */
-} DAC_LOAD_DETECTION_PARAMETERS;
+/****************************************************************************/
+// Structures used by DAC_LoadDetectionTable.ctb
+/****************************************************************************/
+typedef struct _DAC_LOAD_DETECTION_PARAMETERS
+{
+ USHORT usDeviceID; //{ATOM_DEVICE_CRTx_SUPPORT,ATOM_DEVICE_TVx_SUPPORT,ATOM_DEVICE_CVx_SUPPORT}
+ UCHAR ucDacType; //{ATOM_DAC_A,ATOM_DAC_B, ATOM_EXT_DAC}
+ UCHAR ucMisc; //Valid only when table revision =1.3 and above
+}DAC_LOAD_DETECTION_PARAMETERS;
-/* DAC_LOAD_DETECTION_PARAMETERS.ucMisc */
+// DAC_LOAD_DETECTION_PARAMETERS.ucMisc
#define DAC_LOAD_MISC_YPrPb 0x01
-typedef struct _DAC_LOAD_DETECTION_PS_ALLOCATION {
- DAC_LOAD_DETECTION_PARAMETERS sDacload;
- ULONG Reserved[2]; /* Don't set this one, allocation for EXT DAC */
-} DAC_LOAD_DETECTION_PS_ALLOCATION;
-
-/****************************************************************************/
-/* Structures used by DAC1EncoderControlTable.ctb and DAC2EncoderControlTable.ctb */
-/****************************************************************************/
-typedef struct _DAC_ENCODER_CONTROL_PARAMETERS {
- USHORT usPixelClock; /* in 10KHz; for bios convenient */
- UCHAR ucDacStandard; /* See definition of ATOM_DACx_xxx, For DEC3.0, bit 7 used as internal flag to indicate DAC2 (==1) or DAC1 (==0) */
- UCHAR ucAction; /* 0: turn off encoder */
- /* 1: setup and turn on encoder */
- /* 7: ATOM_ENCODER_INIT Initialize DAC */
-} DAC_ENCODER_CONTROL_PARAMETERS;
+typedef struct _DAC_LOAD_DETECTION_PS_ALLOCATION
+{
+ DAC_LOAD_DETECTION_PARAMETERS sDacload;
+ ULONG Reserved[2];// Don't set this one, allocation for EXT DAC
+}DAC_LOAD_DETECTION_PS_ALLOCATION;
+
+/****************************************************************************/
+// Structures used by DAC1EncoderControlTable.ctb and DAC2EncoderControlTable.ctb
+/****************************************************************************/
+typedef struct _DAC_ENCODER_CONTROL_PARAMETERS
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ UCHAR ucDacStandard; // See definition of ATOM_DACx_xxx, For DEC3.0, bit 7 used as internal flag to indicate DAC2 (==1) or DAC1 (==0)
+ UCHAR ucAction; // 0: turn off encoder
+ // 1: setup and turn on encoder
+ // 7: ATOM_ENCODER_INIT Initialize DAC
+}DAC_ENCODER_CONTROL_PARAMETERS;
#define DAC_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PARAMETERS
-/****************************************************************************/
-/* Structures used by DIG1EncoderControlTable */
-/* DIG2EncoderControlTable */
-/* ExternalEncoderControlTable */
-/****************************************************************************/
-typedef struct _DIG_ENCODER_CONTROL_PARAMETERS {
- USHORT usPixelClock; /* in 10KHz; for bios convenient */
- UCHAR ucConfig;
- /* [2] Link Select: */
- /* =0: PHY linkA if bfLane<3 */
- /* =1: PHY linkB if bfLanes<3 */
- /* =0: PHY linkA+B if bfLanes=3 */
- /* [3] Transmitter Sel */
- /* =0: UNIPHY or PCIEPHY */
- /* =1: LVTMA */
- UCHAR ucAction; /* =0: turn off encoder */
- /* =1: turn on encoder */
- UCHAR ucEncoderMode;
- /* =0: DP encoder */
- /* =1: LVDS encoder */
- /* =2: DVI encoder */
- /* =3: HDMI encoder */
- /* =4: SDVO encoder */
- UCHAR ucLaneNum; /* how many lanes to enable */
- UCHAR ucReserved[2];
-} DIG_ENCODER_CONTROL_PARAMETERS;
+/****************************************************************************/
+// Structures used by DIG1EncoderControlTable
+// DIG2EncoderControlTable
+// ExternalEncoderControlTable
+/****************************************************************************/
+typedef struct _DIG_ENCODER_CONTROL_PARAMETERS
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ UCHAR ucConfig;
+ // [2] Link Select:
+ // =0: PHY linkA if bfLane<3
+ // =1: PHY linkB if bfLanes<3
+ // =0: PHY linkA+B if bfLanes=3
+ // [3] Transmitter Sel
+ // =0: UNIPHY or PCIEPHY
+ // =1: LVTMA
+ UCHAR ucAction; // =0: turn off encoder
+ // =1: turn on encoder
+ UCHAR ucEncoderMode;
+ // =0: DP encoder
+ // =1: LVDS encoder
+ // =2: DVI encoder
+ // =3: HDMI encoder
+ // =4: SDVO encoder
+ UCHAR ucLaneNum; // how many lanes to enable
+ UCHAR ucReserved[2];
+}DIG_ENCODER_CONTROL_PARAMETERS;
#define DIG_ENCODER_CONTROL_PS_ALLOCATION DIG_ENCODER_CONTROL_PARAMETERS
#define EXTERNAL_ENCODER_CONTROL_PARAMETER DIG_ENCODER_CONTROL_PARAMETERS
-/* ucConfig */
+//ucConfig
#define ATOM_ENCODER_CONFIG_DPLINKRATE_MASK 0x01
#define ATOM_ENCODER_CONFIG_DPLINKRATE_1_62GHZ 0x00
#define ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ 0x01
@@ -539,52 +593,57 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS {
#define ATOM_ENCODER_CONFIG_LVTMA 0x08
#define ATOM_ENCODER_CONFIG_TRANSMITTER1 0x00
#define ATOM_ENCODER_CONFIG_TRANSMITTER2 0x08
-#define ATOM_ENCODER_CONFIG_DIGB 0x80 /* VBIOS Internal use, outside SW should set this bit=0 */
-/* ucAction */
-/* ATOM_ENABLE: Enable Encoder */
-/* ATOM_DISABLE: Disable Encoder */
+#define ATOM_ENCODER_CONFIG_DIGB 0x80 // VBIOS Internal use, outside SW should set this bit=0
+// ucAction
+// ATOM_ENABLE: Enable Encoder
+// ATOM_DISABLE: Disable Encoder
-/* ucEncoderMode */
+//ucEncoderMode
#define ATOM_ENCODER_MODE_DP 0
#define ATOM_ENCODER_MODE_LVDS 1
#define ATOM_ENCODER_MODE_DVI 2
#define ATOM_ENCODER_MODE_HDMI 3
#define ATOM_ENCODER_MODE_SDVO 4
+#define ATOM_ENCODER_MODE_DP_AUDIO 5
#define ATOM_ENCODER_MODE_TV 13
#define ATOM_ENCODER_MODE_CV 14
#define ATOM_ENCODER_MODE_CRT 15
-typedef struct _ATOM_DIG_ENCODER_CONFIG_V2 {
+typedef struct _ATOM_DIG_ENCODER_CONFIG_V2
+{
#if ATOM_BIG_ENDIAN
- UCHAR ucReserved1:2;
- UCHAR ucTransmitterSel:2; /* =0: UniphyAB, =1: UniphyCD =2: UniphyEF */
- UCHAR ucLinkSel:1; /* =0: linkA/C/E =1: linkB/D/F */
- UCHAR ucReserved:1;
- UCHAR ucDPLinkRate:1; /* =0: 1.62Ghz, =1: 2.7Ghz */
+ UCHAR ucReserved1:2;
+ UCHAR ucTransmitterSel:2; // =0: UniphyAB, =1: UniphyCD =2: UniphyEF
+ UCHAR ucLinkSel:1; // =0: linkA/C/E =1: linkB/D/F
+ UCHAR ucReserved:1;
+ UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz
#else
- UCHAR ucDPLinkRate:1; /* =0: 1.62Ghz, =1: 2.7Ghz */
- UCHAR ucReserved:1;
- UCHAR ucLinkSel:1; /* =0: linkA/C/E =1: linkB/D/F */
- UCHAR ucTransmitterSel:2; /* =0: UniphyAB, =1: UniphyCD =2: UniphyEF */
- UCHAR ucReserved1:2;
+ UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz
+ UCHAR ucReserved:1;
+ UCHAR ucLinkSel:1; // =0: linkA/C/E =1: linkB/D/F
+ UCHAR ucTransmitterSel:2; // =0: UniphyAB, =1: UniphyCD =2: UniphyEF
+ UCHAR ucReserved1:2;
#endif
-} ATOM_DIG_ENCODER_CONFIG_V2;
+}ATOM_DIG_ENCODER_CONFIG_V2;
-typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2 {
- USHORT usPixelClock; /* in 10KHz; for bios convenient */
- ATOM_DIG_ENCODER_CONFIG_V2 acConfig;
- UCHAR ucAction;
- UCHAR ucEncoderMode;
- /* =0: DP encoder */
- /* =1: LVDS encoder */
- /* =2: DVI encoder */
- /* =3: HDMI encoder */
- /* =4: SDVO encoder */
- UCHAR ucLaneNum; /* how many lanes to enable */
- UCHAR ucReserved[2];
-} DIG_ENCODER_CONTROL_PARAMETERS_V2;
-/* ucConfig */
+typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ ATOM_DIG_ENCODER_CONFIG_V2 acConfig;
+ UCHAR ucAction;
+ UCHAR ucEncoderMode;
+ // =0: DP encoder
+ // =1: LVDS encoder
+ // =2: DVI encoder
+ // =3: HDMI encoder
+ // =4: SDVO encoder
+ UCHAR ucLaneNum; // how many lanes to enable
+ UCHAR ucStatus; // = DP_LINK_TRAINING_COMPLETE or DP_LINK_TRAINING_INCOMPLETE, only used by VBIOS with command ATOM_ENCODER_CMD_QUERY_DP_LINK_TRAINING_STATUS
+ UCHAR ucReserved;
+}DIG_ENCODER_CONTROL_PARAMETERS_V2;
+
+//ucConfig
#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_MASK 0x01
#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_1_62GHZ 0x00
#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_2_70GHZ 0x01
@@ -596,58 +655,122 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2 {
#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER2 0x08
#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER3 0x10
-/****************************************************************************/
-/* Structures used by UNIPHYTransmitterControlTable */
-/* LVTMATransmitterControlTable */
-/* DVOOutputControlTable */
-/****************************************************************************/
-typedef struct _ATOM_DP_VS_MODE {
- UCHAR ucLaneSel;
- UCHAR ucLaneSet;
-} ATOM_DP_VS_MODE;
-
-typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS {
- union {
- USHORT usPixelClock; /* in 10KHz; for bios convenient */
- USHORT usInitInfo; /* when init uniphy,lower 8bit is used for connector type defined in objectid.h */
- ATOM_DP_VS_MODE asMode; /* DP Voltage swing mode */
+// ucAction:
+// ATOM_DISABLE
+// ATOM_ENABLE
+#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_START 0x08
+#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1 0x09
+#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2 0x0a
+#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE 0x0b
+#define ATOM_ENCODER_CMD_DP_VIDEO_OFF 0x0c
+#define ATOM_ENCODER_CMD_DP_VIDEO_ON 0x0d
+#define ATOM_ENCODER_CMD_QUERY_DP_LINK_TRAINING_STATUS 0x0e
+#define ATOM_ENCODER_CMD_SETUP 0x0f
+
+// ucStatus
+#define ATOM_ENCODER_STATUS_LINK_TRAINING_COMPLETE 0x10
+#define ATOM_ENCODER_STATUS_LINK_TRAINING_INCOMPLETE 0x00
+
+// Following function ENABLE sub-function will be used by driver when TMDS/HDMI/LVDS is used, disable function will be used by driver
+typedef struct _ATOM_DIG_ENCODER_CONFIG_V3
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucReserved1:1;
+ UCHAR ucDigSel:3; // =0: DIGA/B/C/D/E/F
+ UCHAR ucReserved:3;
+ UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz
+#else
+ UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz
+ UCHAR ucReserved:3;
+ UCHAR ucDigSel:3; // =0: DIGA/B/C/D/E/F
+ UCHAR ucReserved1:1;
+#endif
+}ATOM_DIG_ENCODER_CONFIG_V3;
+
+#define ATOM_ENCODER_CONFIG_V3_ENCODER_SEL 0x70
+
+
+typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V3
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ ATOM_DIG_ENCODER_CONFIG_V3 acConfig;
+ UCHAR ucAction;
+ UCHAR ucEncoderMode;
+ // =0: DP encoder
+ // =1: LVDS encoder
+ // =2: DVI encoder
+ // =3: HDMI encoder
+ // =4: SDVO encoder
+ // =5: DP audio
+ UCHAR ucLaneNum; // how many lanes to enable
+ UCHAR ucBitPerColor; // only valid for DP mode when ucAction = ATOM_ENCODER_CMD_SETUP
+ UCHAR ucReserved;
+}DIG_ENCODER_CONTROL_PARAMETERS_V3;
+
+
+// define ucBitPerColor:
+#define PANEL_BPC_UNDEFINE 0x00
+#define PANEL_6BIT_PER_COLOR 0x01
+#define PANEL_8BIT_PER_COLOR 0x02
+#define PANEL_10BIT_PER_COLOR 0x03
+#define PANEL_12BIT_PER_COLOR 0x04
+#define PANEL_16BIT_PER_COLOR 0x05
+
+/****************************************************************************/
+// Structures used by UNIPHYTransmitterControlTable
+// LVTMATransmitterControlTable
+// DVOOutputControlTable
+/****************************************************************************/
+typedef struct _ATOM_DP_VS_MODE
+{
+ UCHAR ucLaneSel;
+ UCHAR ucLaneSet;
+}ATOM_DP_VS_MODE;
+
+typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS
+{
+ union
+ {
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h
+ ATOM_DP_VS_MODE asMode; // DP Voltage swing mode
};
- UCHAR ucConfig;
- /* [0]=0: 4 lane Link, */
- /* =1: 8 lane Link ( Dual Links TMDS ) */
- /* [1]=0: InCoherent mode */
- /* =1: Coherent Mode */
- /* [2] Link Select: */
- /* =0: PHY linkA if bfLane<3 */
- /* =1: PHY linkB if bfLanes<3 */
- /* =0: PHY linkA+B if bfLanes=3 */
- /* [5:4]PCIE lane Sel */
- /* =0: lane 0~3 or 0~7 */
- /* =1: lane 4~7 */
- /* =2: lane 8~11 or 8~15 */
- /* =3: lane 12~15 */
- UCHAR ucAction; /* =0: turn off encoder */
- /* =1: turn on encoder */
- UCHAR ucReserved[4];
-} DIG_TRANSMITTER_CONTROL_PARAMETERS;
-
-#define DIG_TRANSMITTER_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PARAMETERS
-
-/* ucInitInfo */
-#define ATOM_TRAMITTER_INITINFO_CONNECTOR_MASK 0x00ff
-
-/* ucConfig */
+ UCHAR ucConfig;
+ // [0]=0: 4 lane Link,
+ // =1: 8 lane Link ( Dual Links TMDS )
+ // [1]=0: InCoherent mode
+ // =1: Coherent Mode
+ // [2] Link Select:
+ // =0: PHY linkA if bfLane<3
+ // =1: PHY linkB if bfLanes<3
+ // =0: PHY linkA+B if bfLanes=3
+ // [5:4]PCIE lane Sel
+ // =0: lane 0~3 or 0~7
+ // =1: lane 4~7
+ // =2: lane 8~11 or 8~15
+ // =3: lane 12~15
+ UCHAR ucAction; // =0: turn off encoder
+ // =1: turn on encoder
+ UCHAR ucReserved[4];
+}DIG_TRANSMITTER_CONTROL_PARAMETERS;
+
+#define DIG_TRANSMITTER_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PARAMETERS
+
+//ucInitInfo
+#define ATOM_TRAMITTER_INITINFO_CONNECTOR_MASK 0x00ff
+
+//ucConfig
#define ATOM_TRANSMITTER_CONFIG_8LANE_LINK 0x01
#define ATOM_TRANSMITTER_CONFIG_COHERENT 0x02
#define ATOM_TRANSMITTER_CONFIG_LINK_SEL_MASK 0x04
#define ATOM_TRANSMITTER_CONFIG_LINKA 0x00
#define ATOM_TRANSMITTER_CONFIG_LINKB 0x04
-#define ATOM_TRANSMITTER_CONFIG_LINKA_B 0x00
+#define ATOM_TRANSMITTER_CONFIG_LINKA_B 0x00
#define ATOM_TRANSMITTER_CONFIG_LINKB_A 0x04
-#define ATOM_TRANSMITTER_CONFIG_ENCODER_SEL_MASK 0x08 /* only used when ATOM_TRANSMITTER_ACTION_ENABLE */
-#define ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER 0x00 /* only used when ATOM_TRANSMITTER_ACTION_ENABLE */
-#define ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER 0x08 /* only used when ATOM_TRANSMITTER_ACTION_ENABLE */
+#define ATOM_TRANSMITTER_CONFIG_ENCODER_SEL_MASK 0x08 // only used when ATOM_TRANSMITTER_ACTION_ENABLE
+#define ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER 0x00 // only used when ATOM_TRANSMITTER_ACTION_ENABLE
+#define ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER 0x08 // only used when ATOM_TRANSMITTER_ACTION_ENABLE
#define ATOM_TRANSMITTER_CONFIG_CLKSRC_MASK 0x30
#define ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL 0x00
@@ -661,7 +784,7 @@ typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS {
#define ATOM_TRANSMITTER_CONFIG_LANE_8_15 0x80
#define ATOM_TRANSMITTER_CONFIG_LANE_12_15 0xc0
-/* ucAction */
+//ucAction
#define ATOM_TRANSMITTER_ACTION_DISABLE 0
#define ATOM_TRANSMITTER_ACTION_ENABLE 1
#define ATOM_TRANSMITTER_ACTION_LCD_BLOFF 2
@@ -674,93 +797,168 @@ typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS {
#define ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT 9
#define ATOM_TRANSMITTER_ACTION_SETUP 10
#define ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH 11
+#define ATOM_TRANSMITTER_ACTION_POWER_ON 12
+#define ATOM_TRANSMITTER_ACTION_POWER_OFF 13
-/* Following are used for DigTransmitterControlTable ver1.2 */
-typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V2 {
+// Following are used for DigTransmitterControlTable ver1.2
+typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V2
+{
#if ATOM_BIG_ENDIAN
- UCHAR ucTransmitterSel:2; /* bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) */
- /* =1 Dig Transmitter 2 ( Uniphy CD ) */
- /* =2 Dig Transmitter 3 ( Uniphy EF ) */
- UCHAR ucReserved:1;
- UCHAR fDPConnector:1; /* bit4=0: DP connector =1: None DP connector */
- UCHAR ucEncoderSel:1; /* bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 ) */
- UCHAR ucLinkSel:1; /* bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E */
- /* =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F */
-
- UCHAR fCoherentMode:1; /* bit1=1: Coherent Mode ( for DVI/HDMI mode ) */
- UCHAR fDualLinkConnector:1; /* bit0=1: Dual Link DVI connector */
+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB )
+ // =1 Dig Transmitter 2 ( Uniphy CD )
+ // =2 Dig Transmitter 3 ( Uniphy EF )
+ UCHAR ucReserved:1;
+ UCHAR fDPConnector:1; //bit4=0: DP connector =1: None DP connector
+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 )
+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E
+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F
+
+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode )
+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector
#else
- UCHAR fDualLinkConnector:1; /* bit0=1: Dual Link DVI connector */
- UCHAR fCoherentMode:1; /* bit1=1: Coherent Mode ( for DVI/HDMI mode ) */
- UCHAR ucLinkSel:1; /* bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E */
- /* =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F */
- UCHAR ucEncoderSel:1; /* bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 ) */
- UCHAR fDPConnector:1; /* bit4=0: DP connector =1: None DP connector */
- UCHAR ucReserved:1;
- UCHAR ucTransmitterSel:2; /* bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) */
- /* =1 Dig Transmitter 2 ( Uniphy CD ) */
- /* =2 Dig Transmitter 3 ( Uniphy EF ) */
+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector
+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode )
+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E
+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F
+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 )
+ UCHAR fDPConnector:1; //bit4=0: DP connector =1: None DP connector
+ UCHAR ucReserved:1;
+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB )
+ // =1 Dig Transmitter 2 ( Uniphy CD )
+ // =2 Dig Transmitter 3 ( Uniphy EF )
#endif
-} ATOM_DIG_TRANSMITTER_CONFIG_V2;
+}ATOM_DIG_TRANSMITTER_CONFIG_V2;
-/* ucConfig */
-/* Bit0 */
+//ucConfig
+//Bit0
#define ATOM_TRANSMITTER_CONFIG_V2_DUAL_LINK_CONNECTOR 0x01
-/* Bit1 */
+//Bit1
#define ATOM_TRANSMITTER_CONFIG_V2_COHERENT 0x02
-/* Bit2 */
+//Bit2
#define ATOM_TRANSMITTER_CONFIG_V2_LINK_SEL_MASK 0x04
-#define ATOM_TRANSMITTER_CONFIG_V2_LINKA 0x00
+#define ATOM_TRANSMITTER_CONFIG_V2_LINKA 0x00
#define ATOM_TRANSMITTER_CONFIG_V2_LINKB 0x04
-/* Bit3 */
+// Bit3
#define ATOM_TRANSMITTER_CONFIG_V2_ENCODER_SEL_MASK 0x08
-#define ATOM_TRANSMITTER_CONFIG_V2_DIG1_ENCODER 0x00 /* only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP */
-#define ATOM_TRANSMITTER_CONFIG_V2_DIG2_ENCODER 0x08 /* only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP */
+#define ATOM_TRANSMITTER_CONFIG_V2_DIG1_ENCODER 0x00 // only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP
+#define ATOM_TRANSMITTER_CONFIG_V2_DIG2_ENCODER 0x08 // only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP
-/* Bit4 */
+// Bit4
#define ATOM_TRASMITTER_CONFIG_V2_DP_CONNECTOR 0x10
-/* Bit7:6 */
+// Bit7:6
#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER_SEL_MASK 0xC0
-#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER1 0x00 /* AB */
-#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER2 0x40 /* CD */
-#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER3 0x80 /* EF */
-
-typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 {
- union {
- USHORT usPixelClock; /* in 10KHz; for bios convenient */
- USHORT usInitInfo; /* when init uniphy,lower 8bit is used for connector type defined in objectid.h */
- ATOM_DP_VS_MODE asMode; /* DP Voltage swing mode */
+#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER1 0x00 //AB
+#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER2 0x40 //CD
+#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER3 0x80 //EF
+
+typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V2
+{
+ union
+ {
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h
+ ATOM_DP_VS_MODE asMode; // DP Voltage swing mode
};
- ATOM_DIG_TRANSMITTER_CONFIG_V2 acConfig;
- UCHAR ucAction; /* define as ATOM_TRANSMITER_ACTION_XXX */
- UCHAR ucReserved[4];
-} DIG_TRANSMITTER_CONTROL_PARAMETERS_V2;
+ ATOM_DIG_TRANSMITTER_CONFIG_V2 acConfig;
+ UCHAR ucAction; // define as ATOM_TRANSMITER_ACTION_XXX
+ UCHAR ucReserved[4];
+}DIG_TRANSMITTER_CONTROL_PARAMETERS_V2;
-/****************************************************************************/
-/* Structures used by DAC1OuputControlTable */
-/* DAC2OuputControlTable */
-/* LVTMAOutputControlTable (Before DEC30) */
-/* TMDSAOutputControlTable (Before DEC30) */
-/****************************************************************************/
-typedef struct _DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS {
- UCHAR ucAction; /* Possible input:ATOM_ENABLE||ATOMDISABLE */
- /* When the display is LCD, in addition to above: */
- /* ATOM_LCD_BLOFF|| ATOM_LCD_BLON ||ATOM_LCD_BL_BRIGHTNESS_CONTROL||ATOM_LCD_SELFTEST_START|| */
- /* ATOM_LCD_SELFTEST_STOP */
+typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V3
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB )
+ // =1 Dig Transmitter 2 ( Uniphy CD )
+ // =2 Dig Transmitter 3 ( Uniphy EF )
+ UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, EXT_CLK=2
+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F
+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E
+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F
+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode )
+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector
+#else
+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector
+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode )
+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E
+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F
+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F
+ UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, EXT_CLK=2
+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB )
+ // =1 Dig Transmitter 2 ( Uniphy CD )
+ // =2 Dig Transmitter 3 ( Uniphy EF )
+#endif
+}ATOM_DIG_TRANSMITTER_CONFIG_V3;
- UCHAR aucPadding[3]; /* padding to DWORD aligned */
-} DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS;
+typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V3
+{
+ union
+ {
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h
+ ATOM_DP_VS_MODE asMode; // DP Voltage swing mode
+ };
+ ATOM_DIG_TRANSMITTER_CONFIG_V3 acConfig;
+ UCHAR ucAction; // define as ATOM_TRANSMITER_ACTION_XXX
+ UCHAR ucLaneNum;
+ UCHAR ucReserved[3];
+}DIG_TRANSMITTER_CONTROL_PARAMETERS_V3;
+
+//ucConfig
+//Bit0
+#define ATOM_TRANSMITTER_CONFIG_V3_DUAL_LINK_CONNECTOR 0x01
+
+//Bit1
+#define ATOM_TRANSMITTER_CONFIG_V3_COHERENT 0x02
+
+//Bit2
+#define ATOM_TRANSMITTER_CONFIG_V3_LINK_SEL_MASK 0x04
+#define ATOM_TRANSMITTER_CONFIG_V3_LINKA 0x00
+#define ATOM_TRANSMITTER_CONFIG_V3_LINKB 0x04
+
+// Bit3
+#define ATOM_TRANSMITTER_CONFIG_V3_ENCODER_SEL_MASK 0x08
+#define ATOM_TRANSMITTER_CONFIG_V3_DIG1_ENCODER 0x00
+#define ATOM_TRANSMITTER_CONFIG_V3_DIG2_ENCODER 0x08
+
+// Bit5:4
+#define ATOM_TRASMITTER_CONFIG_V3_REFCLK_SEL_MASK 0x30
+#define ATOM_TRASMITTER_CONFIG_V3_P1PLL 0x00
+#define ATOM_TRASMITTER_CONFIG_V3_P2PLL 0x10
+#define ATOM_TRASMITTER_CONFIG_V3_REFCLK_SRC_EXT 0x20
+
+// Bit7:6
+#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER_SEL_MASK 0xC0
+#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER1 0x00 //AB
+#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER2 0x40 //CD
+#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER3 0x80 //EF
+
+/****************************************************************************/
+// Structures used by DAC1OuputControlTable
+// DAC2OuputControlTable
+// LVTMAOutputControlTable (Before DEC30)
+// TMDSAOutputControlTable (Before DEC30)
+/****************************************************************************/
+typedef struct _DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+{
+ UCHAR ucAction; // Possible input:ATOM_ENABLE||ATOMDISABLE
+ // When the display is LCD, in addition to above:
+ // ATOM_LCD_BLOFF|| ATOM_LCD_BLON ||ATOM_LCD_BL_BRIGHTNESS_CONTROL||ATOM_LCD_SELFTEST_START||
+ // ATOM_LCD_SELFTEST_STOP
+
+ UCHAR aucPadding[3]; // padding to DWORD aligned
+}DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS;
#define DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
-#define CRT1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+
+#define CRT1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
#define CRT1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
-#define CRT2_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define CRT2_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
#define CRT2_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
#define CV1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
@@ -782,397 +980,550 @@ typedef struct _DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS {
#define DVO_OUTPUT_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PS_ALLOCATION
#define DVO_OUTPUT_CONTROL_PARAMETERS_V3 DIG_TRANSMITTER_CONTROL_PARAMETERS
-/****************************************************************************/
-/* Structures used by BlankCRTCTable */
-/****************************************************************************/
-typedef struct _BLANK_CRTC_PARAMETERS {
- UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */
- UCHAR ucBlanking; /* ATOM_BLANKING or ATOM_BLANKINGOFF */
- USHORT usBlackColorRCr;
- USHORT usBlackColorGY;
- USHORT usBlackColorBCb;
-} BLANK_CRTC_PARAMETERS;
+/****************************************************************************/
+// Structures used by BlankCRTCTable
+/****************************************************************************/
+typedef struct _BLANK_CRTC_PARAMETERS
+{
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucBlanking; // ATOM_BLANKING or ATOM_BLANKINGOFF
+ USHORT usBlackColorRCr;
+ USHORT usBlackColorGY;
+ USHORT usBlackColorBCb;
+}BLANK_CRTC_PARAMETERS;
#define BLANK_CRTC_PS_ALLOCATION BLANK_CRTC_PARAMETERS
-/****************************************************************************/
-/* Structures used by EnableCRTCTable */
-/* EnableCRTCMemReqTable */
-/* UpdateCRTC_DoubleBufferRegistersTable */
-/****************************************************************************/
-typedef struct _ENABLE_CRTC_PARAMETERS {
- UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */
- UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */
- UCHAR ucPadding[2];
-} ENABLE_CRTC_PARAMETERS;
+/****************************************************************************/
+// Structures used by EnableCRTCTable
+// EnableCRTCMemReqTable
+// UpdateCRTC_DoubleBufferRegistersTable
+/****************************************************************************/
+typedef struct _ENABLE_CRTC_PARAMETERS
+{
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucPadding[2];
+}ENABLE_CRTC_PARAMETERS;
#define ENABLE_CRTC_PS_ALLOCATION ENABLE_CRTC_PARAMETERS
-/****************************************************************************/
-/* Structures used by SetCRTC_OverScanTable */
-/****************************************************************************/
-typedef struct _SET_CRTC_OVERSCAN_PARAMETERS {
- USHORT usOverscanRight; /* right */
- USHORT usOverscanLeft; /* left */
- USHORT usOverscanBottom; /* bottom */
- USHORT usOverscanTop; /* top */
- UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */
- UCHAR ucPadding[3];
-} SET_CRTC_OVERSCAN_PARAMETERS;
+/****************************************************************************/
+// Structures used by SetCRTC_OverScanTable
+/****************************************************************************/
+typedef struct _SET_CRTC_OVERSCAN_PARAMETERS
+{
+ USHORT usOverscanRight; // right
+ USHORT usOverscanLeft; // left
+ USHORT usOverscanBottom; // bottom
+ USHORT usOverscanTop; // top
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucPadding[3];
+}SET_CRTC_OVERSCAN_PARAMETERS;
#define SET_CRTC_OVERSCAN_PS_ALLOCATION SET_CRTC_OVERSCAN_PARAMETERS
-/****************************************************************************/
-/* Structures used by SetCRTC_ReplicationTable */
-/****************************************************************************/
-typedef struct _SET_CRTC_REPLICATION_PARAMETERS {
- UCHAR ucH_Replication; /* horizontal replication */
- UCHAR ucV_Replication; /* vertical replication */
- UCHAR usCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */
- UCHAR ucPadding;
-} SET_CRTC_REPLICATION_PARAMETERS;
+/****************************************************************************/
+// Structures used by SetCRTC_ReplicationTable
+/****************************************************************************/
+typedef struct _SET_CRTC_REPLICATION_PARAMETERS
+{
+ UCHAR ucH_Replication; // horizontal replication
+ UCHAR ucV_Replication; // vertical replication
+ UCHAR usCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucPadding;
+}SET_CRTC_REPLICATION_PARAMETERS;
#define SET_CRTC_REPLICATION_PS_ALLOCATION SET_CRTC_REPLICATION_PARAMETERS
-/****************************************************************************/
-/* Structures used by SelectCRTC_SourceTable */
-/****************************************************************************/
-typedef struct _SELECT_CRTC_SOURCE_PARAMETERS {
- UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */
- UCHAR ucDevice; /* ATOM_DEVICE_CRT1|ATOM_DEVICE_CRT2|.... */
- UCHAR ucPadding[2];
-} SELECT_CRTC_SOURCE_PARAMETERS;
+/****************************************************************************/
+// Structures used by SelectCRTC_SourceTable
+/****************************************************************************/
+typedef struct _SELECT_CRTC_SOURCE_PARAMETERS
+{
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucDevice; // ATOM_DEVICE_CRT1|ATOM_DEVICE_CRT2|....
+ UCHAR ucPadding[2];
+}SELECT_CRTC_SOURCE_PARAMETERS;
#define SELECT_CRTC_SOURCE_PS_ALLOCATION SELECT_CRTC_SOURCE_PARAMETERS
-typedef struct _SELECT_CRTC_SOURCE_PARAMETERS_V2 {
- UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */
- UCHAR ucEncoderID; /* DAC1/DAC2/TVOUT/DIG1/DIG2/DVO */
- UCHAR ucEncodeMode; /* Encoding mode, only valid when using DIG1/DIG2/DVO */
- UCHAR ucPadding;
-} SELECT_CRTC_SOURCE_PARAMETERS_V2;
-
-/* ucEncoderID */
-/* #define ASIC_INT_DAC1_ENCODER_ID 0x00 */
-/* #define ASIC_INT_TV_ENCODER_ID 0x02 */
-/* #define ASIC_INT_DIG1_ENCODER_ID 0x03 */
-/* #define ASIC_INT_DAC2_ENCODER_ID 0x04 */
-/* #define ASIC_EXT_TV_ENCODER_ID 0x06 */
-/* #define ASIC_INT_DVO_ENCODER_ID 0x07 */
-/* #define ASIC_INT_DIG2_ENCODER_ID 0x09 */
-/* #define ASIC_EXT_DIG_ENCODER_ID 0x05 */
-
-/* ucEncodeMode */
-/* #define ATOM_ENCODER_MODE_DP 0 */
-/* #define ATOM_ENCODER_MODE_LVDS 1 */
-/* #define ATOM_ENCODER_MODE_DVI 2 */
-/* #define ATOM_ENCODER_MODE_HDMI 3 */
-/* #define ATOM_ENCODER_MODE_SDVO 4 */
-/* #define ATOM_ENCODER_MODE_TV 13 */
-/* #define ATOM_ENCODER_MODE_CV 14 */
-/* #define ATOM_ENCODER_MODE_CRT 15 */
-
-/****************************************************************************/
-/* Structures used by SetPixelClockTable */
-/* GetPixelClockTable */
-/****************************************************************************/
-/* Major revision=1., Minor revision=1 */
-typedef struct _PIXEL_CLOCK_PARAMETERS {
- USHORT usPixelClock; /* in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) */
- /* 0 means disable PPLL */
- USHORT usRefDiv; /* Reference divider */
- USHORT usFbDiv; /* feedback divider */
- UCHAR ucPostDiv; /* post divider */
- UCHAR ucFracFbDiv; /* fractional feedback divider */
- UCHAR ucPpll; /* ATOM_PPLL1 or ATOM_PPL2 */
- UCHAR ucRefDivSrc; /* ATOM_PJITTER or ATO_NONPJITTER */
- UCHAR ucCRTC; /* Which CRTC uses this Ppll */
- UCHAR ucPadding;
-} PIXEL_CLOCK_PARAMETERS;
-
-/* Major revision=1., Minor revision=2, add ucMiscIfno */
-/* ucMiscInfo: */
+typedef struct _SELECT_CRTC_SOURCE_PARAMETERS_V2
+{
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucEncoderID; // DAC1/DAC2/TVOUT/DIG1/DIG2/DVO
+ UCHAR ucEncodeMode; // Encoding mode, only valid when using DIG1/DIG2/DVO
+ UCHAR ucPadding;
+}SELECT_CRTC_SOURCE_PARAMETERS_V2;
+
+//ucEncoderID
+//#define ASIC_INT_DAC1_ENCODER_ID 0x00
+//#define ASIC_INT_TV_ENCODER_ID 0x02
+//#define ASIC_INT_DIG1_ENCODER_ID 0x03
+//#define ASIC_INT_DAC2_ENCODER_ID 0x04
+//#define ASIC_EXT_TV_ENCODER_ID 0x06
+//#define ASIC_INT_DVO_ENCODER_ID 0x07
+//#define ASIC_INT_DIG2_ENCODER_ID 0x09
+//#define ASIC_EXT_DIG_ENCODER_ID 0x05
+
+//ucEncodeMode
+//#define ATOM_ENCODER_MODE_DP 0
+//#define ATOM_ENCODER_MODE_LVDS 1
+//#define ATOM_ENCODER_MODE_DVI 2
+//#define ATOM_ENCODER_MODE_HDMI 3
+//#define ATOM_ENCODER_MODE_SDVO 4
+//#define ATOM_ENCODER_MODE_TV 13
+//#define ATOM_ENCODER_MODE_CV 14
+//#define ATOM_ENCODER_MODE_CRT 15
+
+/****************************************************************************/
+// Structures used by SetPixelClockTable
+// GetPixelClockTable
+/****************************************************************************/
+//Major revision=1., Minor revision=1
+typedef struct _PIXEL_CLOCK_PARAMETERS
+{
+ USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div)
+ // 0 means disable PPLL
+ USHORT usRefDiv; // Reference divider
+ USHORT usFbDiv; // feedback divider
+ UCHAR ucPostDiv; // post divider
+ UCHAR ucFracFbDiv; // fractional feedback divider
+ UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2
+ UCHAR ucRefDivSrc; // ATOM_PJITTER or ATO_NONPJITTER
+ UCHAR ucCRTC; // Which CRTC uses this Ppll
+ UCHAR ucPadding;
+}PIXEL_CLOCK_PARAMETERS;
+
+//Major revision=1., Minor revision=2, add ucMiscIfno
+//ucMiscInfo:
#define MISC_FORCE_REPROG_PIXEL_CLOCK 0x1
#define MISC_DEVICE_INDEX_MASK 0xF0
#define MISC_DEVICE_INDEX_SHIFT 4
-typedef struct _PIXEL_CLOCK_PARAMETERS_V2 {
- USHORT usPixelClock; /* in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) */
- /* 0 means disable PPLL */
- USHORT usRefDiv; /* Reference divider */
- USHORT usFbDiv; /* feedback divider */
- UCHAR ucPostDiv; /* post divider */
- UCHAR ucFracFbDiv; /* fractional feedback divider */
- UCHAR ucPpll; /* ATOM_PPLL1 or ATOM_PPL2 */
- UCHAR ucRefDivSrc; /* ATOM_PJITTER or ATO_NONPJITTER */
- UCHAR ucCRTC; /* Which CRTC uses this Ppll */
- UCHAR ucMiscInfo; /* Different bits for different purpose, bit [7:4] as device index, bit[0]=Force prog */
-} PIXEL_CLOCK_PARAMETERS_V2;
-
-/* Major revision=1., Minor revision=3, structure/definition change */
-/* ucEncoderMode: */
-/* ATOM_ENCODER_MODE_DP */
-/* ATOM_ENOCDER_MODE_LVDS */
-/* ATOM_ENOCDER_MODE_DVI */
-/* ATOM_ENOCDER_MODE_HDMI */
-/* ATOM_ENOCDER_MODE_SDVO */
-/* ATOM_ENCODER_MODE_TV 13 */
-/* ATOM_ENCODER_MODE_CV 14 */
-/* ATOM_ENCODER_MODE_CRT 15 */
-
-/* ucDVOConfig */
-/* #define DVO_ENCODER_CONFIG_RATE_SEL 0x01 */
-/* #define DVO_ENCODER_CONFIG_DDR_SPEED 0x00 */
-/* #define DVO_ENCODER_CONFIG_SDR_SPEED 0x01 */
-/* #define DVO_ENCODER_CONFIG_OUTPUT_SEL 0x0c */
-/* #define DVO_ENCODER_CONFIG_LOW12BIT 0x00 */
-/* #define DVO_ENCODER_CONFIG_UPPER12BIT 0x04 */
-/* #define DVO_ENCODER_CONFIG_24BIT 0x08 */
-
-/* ucMiscInfo: also changed, see below */
+typedef struct _PIXEL_CLOCK_PARAMETERS_V2
+{
+ USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div)
+ // 0 means disable PPLL
+ USHORT usRefDiv; // Reference divider
+ USHORT usFbDiv; // feedback divider
+ UCHAR ucPostDiv; // post divider
+ UCHAR ucFracFbDiv; // fractional feedback divider
+ UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2
+ UCHAR ucRefDivSrc; // ATOM_PJITTER or ATO_NONPJITTER
+ UCHAR ucCRTC; // Which CRTC uses this Ppll
+ UCHAR ucMiscInfo; // Different bits for different purpose, bit [7:4] as device index, bit[0]=Force prog
+}PIXEL_CLOCK_PARAMETERS_V2;
+
+//Major revision=1., Minor revision=3, structure/definition change
+//ucEncoderMode:
+//ATOM_ENCODER_MODE_DP
+//ATOM_ENOCDER_MODE_LVDS
+//ATOM_ENOCDER_MODE_DVI
+//ATOM_ENOCDER_MODE_HDMI
+//ATOM_ENOCDER_MODE_SDVO
+//ATOM_ENCODER_MODE_TV 13
+//ATOM_ENCODER_MODE_CV 14
+//ATOM_ENCODER_MODE_CRT 15
+
+//ucDVOConfig
+//#define DVO_ENCODER_CONFIG_RATE_SEL 0x01
+//#define DVO_ENCODER_CONFIG_DDR_SPEED 0x00
+//#define DVO_ENCODER_CONFIG_SDR_SPEED 0x01
+//#define DVO_ENCODER_CONFIG_OUTPUT_SEL 0x0c
+//#define DVO_ENCODER_CONFIG_LOW12BIT 0x00
+//#define DVO_ENCODER_CONFIG_UPPER12BIT 0x04
+//#define DVO_ENCODER_CONFIG_24BIT 0x08
+
+//ucMiscInfo: also changed, see below
#define PIXEL_CLOCK_MISC_FORCE_PROG_PPLL 0x01
#define PIXEL_CLOCK_MISC_VGA_MODE 0x02
#define PIXEL_CLOCK_MISC_CRTC_SEL_MASK 0x04
#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1 0x00
#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2 0x04
#define PIXEL_CLOCK_MISC_USE_ENGINE_FOR_DISPCLK 0x08
+#define PIXEL_CLOCK_MISC_REF_DIV_SRC 0x10
+// V1.4 for RoadRunner
+#define PIXEL_CLOCK_V4_MISC_SS_ENABLE 0x10
+#define PIXEL_CLOCK_V4_MISC_COHERENT_MODE 0x20
-typedef struct _PIXEL_CLOCK_PARAMETERS_V3 {
- USHORT usPixelClock; /* in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) */
- /* 0 means disable PPLL. For VGA PPLL,make sure this value is not 0. */
- USHORT usRefDiv; /* Reference divider */
- USHORT usFbDiv; /* feedback divider */
- UCHAR ucPostDiv; /* post divider */
- UCHAR ucFracFbDiv; /* fractional feedback divider */
- UCHAR ucPpll; /* ATOM_PPLL1 or ATOM_PPL2 */
- UCHAR ucTransmitterId; /* graphic encoder id defined in objectId.h */
- union {
- UCHAR ucEncoderMode; /* encoder type defined as ATOM_ENCODER_MODE_DP/DVI/HDMI/ */
- UCHAR ucDVOConfig; /* when use DVO, need to know SDR/DDR, 12bit or 24bit */
+typedef struct _PIXEL_CLOCK_PARAMETERS_V3
+{
+ USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div)
+ // 0 means disable PPLL. For VGA PPLL,make sure this value is not 0.
+ USHORT usRefDiv; // Reference divider
+ USHORT usFbDiv; // feedback divider
+ UCHAR ucPostDiv; // post divider
+ UCHAR ucFracFbDiv; // fractional feedback divider
+ UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2
+ UCHAR ucTransmitterId; // graphic encoder id defined in objectId.h
+ union
+ {
+ UCHAR ucEncoderMode; // encoder type defined as ATOM_ENCODER_MODE_DP/DVI/HDMI/
+ UCHAR ucDVOConfig; // when use DVO, need to know SDR/DDR, 12bit or 24bit
};
- UCHAR ucMiscInfo; /* bit[0]=Force program, bit[1]= set pclk for VGA, b[2]= CRTC sel */
- /* bit[3]=0:use PPLL for dispclk source, =1: use engine clock for dispclock source */
-} PIXEL_CLOCK_PARAMETERS_V3;
+ UCHAR ucMiscInfo; // bit[0]=Force program, bit[1]= set pclk for VGA, b[2]= CRTC sel
+ // bit[3]=0:use PPLL for dispclk source, =1: use engine clock for dispclock source
+ // bit[4]=0:use XTALIN as the source of reference divider,=1 use the pre-defined clock as the source of reference divider
+}PIXEL_CLOCK_PARAMETERS_V3;
#define PIXEL_CLOCK_PARAMETERS_LAST PIXEL_CLOCK_PARAMETERS_V2
#define GET_PIXEL_CLOCK_PS_ALLOCATION PIXEL_CLOCK_PARAMETERS_LAST
-/****************************************************************************/
-/* Structures used by AdjustDisplayPllTable */
-/****************************************************************************/
-typedef struct _ADJUST_DISPLAY_PLL_PARAMETERS {
+typedef struct _PIXEL_CLOCK_PARAMETERS_V5
+{
+ UCHAR ucCRTC; // ATOM_CRTC1~6, indicate the CRTC controller to
+ // drive the pixel clock. not used for DCPLL case.
+ union{
+ UCHAR ucReserved;
+ UCHAR ucFracFbDiv; // [gphan] temporary to prevent build problem. remove it after driver code is changed.
+ };
+ USHORT usPixelClock; // target the pixel clock to drive the CRTC timing
+ // 0 means disable PPLL/DCPLL.
+ USHORT usFbDiv; // feedback divider integer part.
+ UCHAR ucPostDiv; // post divider.
+ UCHAR ucRefDiv; // Reference divider
+ UCHAR ucPpll; // ATOM_PPLL1/ATOM_PPLL2/ATOM_DCPLL
+ UCHAR ucTransmitterID; // ASIC encoder id defined in objectId.h,
+ // indicate which graphic encoder will be used.
+ UCHAR ucEncoderMode; // Encoder mode:
+ UCHAR ucMiscInfo; // bit[0]= Force program PPLL
+ // bit[1]= when VGA timing is used.
+ // bit[3:2]= HDMI panel bit depth: =0: 24bpp =1:30bpp, =2:32bpp
+ // bit[4]= RefClock source for PPLL.
+ // =0: XTLAIN( default mode )
+ // =1: other external clock source, which is pre-defined
+ // by VBIOS depend on the feature required.
+ // bit[7:5]: reserved.
+ ULONG ulFbDivDecFrac; // 20 bit feedback divider decimal fraction part, range from 1~999999 ( 0.000001 to 0.999999 )
+
+}PIXEL_CLOCK_PARAMETERS_V5;
+
+#define PIXEL_CLOCK_V5_MISC_FORCE_PROG_PPLL 0x01
+#define PIXEL_CLOCK_V5_MISC_VGA_MODE 0x02
+#define PIXEL_CLOCK_V5_MISC_HDMI_BPP_MASK 0x0c
+#define PIXEL_CLOCK_V5_MISC_HDMI_24BPP 0x00
+#define PIXEL_CLOCK_V5_MISC_HDMI_30BPP 0x04
+#define PIXEL_CLOCK_V5_MISC_HDMI_32BPP 0x08
+#define PIXEL_CLOCK_V5_MISC_REF_DIV_SRC 0x10
+
+typedef struct _GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V2
+{
+ PIXEL_CLOCK_PARAMETERS_V3 sDispClkInput;
+}GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V2;
+
+typedef struct _GET_DISP_PLL_STATUS_OUTPUT_PARAMETERS_V2
+{
+ UCHAR ucStatus;
+ UCHAR ucRefDivSrc; // =1: reference clock source from XTALIN, =0: source from PCIE ref clock
+ UCHAR ucReserved[2];
+}GET_DISP_PLL_STATUS_OUTPUT_PARAMETERS_V2;
+
+typedef struct _GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V3
+{
+ PIXEL_CLOCK_PARAMETERS_V5 sDispClkInput;
+}GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V3;
+
+/****************************************************************************/
+// Structures used by AdjustDisplayPllTable
+/****************************************************************************/
+typedef struct _ADJUST_DISPLAY_PLL_PARAMETERS
+{
USHORT usPixelClock;
UCHAR ucTransmitterID;
UCHAR ucEncodeMode;
- union {
- UCHAR ucDVOConfig; /* if DVO, need passing link rate and output 12bitlow or 24bit */
- UCHAR ucConfig; /* if none DVO, not defined yet */
+ union
+ {
+ UCHAR ucDVOConfig; //if DVO, need passing link rate and output 12bitlow or 24bit
+ UCHAR ucConfig; //if none DVO, not defined yet
};
UCHAR ucReserved[3];
-} ADJUST_DISPLAY_PLL_PARAMETERS;
+}ADJUST_DISPLAY_PLL_PARAMETERS;
#define ADJUST_DISPLAY_CONFIG_SS_ENABLE 0x10
-
#define ADJUST_DISPLAY_PLL_PS_ALLOCATION ADJUST_DISPLAY_PLL_PARAMETERS
-/****************************************************************************/
-/* Structures used by EnableYUVTable */
-/****************************************************************************/
-typedef struct _ENABLE_YUV_PARAMETERS {
- UCHAR ucEnable; /* ATOM_ENABLE:Enable YUV or ATOM_DISABLE:Disable YUV (RGB) */
- UCHAR ucCRTC; /* Which CRTC needs this YUV or RGB format */
- UCHAR ucPadding[2];
-} ENABLE_YUV_PARAMETERS;
+typedef struct _ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3
+{
+ USHORT usPixelClock; // target pixel clock
+ UCHAR ucTransmitterID; // transmitter id defined in objectid.h
+ UCHAR ucEncodeMode; // encoder mode: CRT, LVDS, DP, TMDS or HDMI
+ UCHAR ucDispPllConfig; // display pll configure parameter defined as following DISPPLL_CONFIG_XXXX
+ UCHAR ucReserved[3];
+}ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3;
+
+// usDispPllConfig v1.2 for RoadRunner
+#define DISPPLL_CONFIG_DVO_RATE_SEL 0x0001 // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_DVO_DDR_SPEED 0x0000 // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_DVO_SDR_SPEED 0x0001 // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_DVO_OUTPUT_SEL 0x000c // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_DVO_LOW12BIT 0x0000 // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_DVO_UPPER12BIT 0x0004 // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_DVO_24BIT 0x0008 // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_SS_ENABLE 0x0010 // Only used when ucEncoderMode = DP or LVDS
+#define DISPPLL_CONFIG_COHERENT_MODE 0x0020 // Only used when ucEncoderMode = TMDS or HDMI
+#define DISPPLL_CONFIG_DUAL_LINK 0x0040 // Only used when ucEncoderMode = TMDS or LVDS
+
+
+typedef struct _ADJUST_DISPLAY_PLL_OUTPUT_PARAMETERS_V3
+{
+ ULONG ulDispPllFreq; // return display PPLL freq which is used to generate the pixclock, and related idclk, symclk etc
+ UCHAR ucRefDiv; // if it is none-zero, it is used to be calculated the other ppll parameter fb_divider and post_div ( if it is not given )
+ UCHAR ucPostDiv; // if it is none-zero, it is used to be calculated the other ppll parameter fb_divider
+ UCHAR ucReserved[2];
+}ADJUST_DISPLAY_PLL_OUTPUT_PARAMETERS_V3;
+
+typedef struct _ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3
+{
+ union
+ {
+ ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3 sInput;
+ ADJUST_DISPLAY_PLL_OUTPUT_PARAMETERS_V3 sOutput;
+ };
+} ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3;
+
+/****************************************************************************/
+// Structures used by EnableYUVTable
+/****************************************************************************/
+typedef struct _ENABLE_YUV_PARAMETERS
+{
+ UCHAR ucEnable; // ATOM_ENABLE:Enable YUV or ATOM_DISABLE:Disable YUV (RGB)
+ UCHAR ucCRTC; // Which CRTC needs this YUV or RGB format
+ UCHAR ucPadding[2];
+}ENABLE_YUV_PARAMETERS;
#define ENABLE_YUV_PS_ALLOCATION ENABLE_YUV_PARAMETERS
-/****************************************************************************/
-/* Structures used by GetMemoryClockTable */
-/****************************************************************************/
-typedef struct _GET_MEMORY_CLOCK_PARAMETERS {
- ULONG ulReturnMemoryClock; /* current memory speed in 10KHz unit */
+/****************************************************************************/
+// Structures used by GetMemoryClockTable
+/****************************************************************************/
+typedef struct _GET_MEMORY_CLOCK_PARAMETERS
+{
+ ULONG ulReturnMemoryClock; // current memory speed in 10KHz unit
} GET_MEMORY_CLOCK_PARAMETERS;
#define GET_MEMORY_CLOCK_PS_ALLOCATION GET_MEMORY_CLOCK_PARAMETERS
-/****************************************************************************/
-/* Structures used by GetEngineClockTable */
-/****************************************************************************/
-typedef struct _GET_ENGINE_CLOCK_PARAMETERS {
- ULONG ulReturnEngineClock; /* current engine speed in 10KHz unit */
+/****************************************************************************/
+// Structures used by GetEngineClockTable
+/****************************************************************************/
+typedef struct _GET_ENGINE_CLOCK_PARAMETERS
+{
+ ULONG ulReturnEngineClock; // current engine speed in 10KHz unit
} GET_ENGINE_CLOCK_PARAMETERS;
#define GET_ENGINE_CLOCK_PS_ALLOCATION GET_ENGINE_CLOCK_PARAMETERS
-/****************************************************************************/
-/* Following Structures and constant may be obsolete */
-/****************************************************************************/
-/* Maxium 8 bytes,the data read in will be placed in the parameter space. */
-/* Read operaion successeful when the paramter space is non-zero, otherwise read operation failed */
-typedef struct _READ_EDID_FROM_HW_I2C_DATA_PARAMETERS {
- USHORT usPrescale; /* Ratio between Engine clock and I2C clock */
- USHORT usVRAMAddress; /* Adress in Frame Buffer where to pace raw EDID */
- USHORT usStatus; /* When use output: lower byte EDID checksum, high byte hardware status */
- /* WHen use input: lower byte as 'byte to read':currently limited to 128byte or 1byte */
- UCHAR ucSlaveAddr; /* Read from which slave */
- UCHAR ucLineNumber; /* Read from which HW assisted line */
-} READ_EDID_FROM_HW_I2C_DATA_PARAMETERS;
+/****************************************************************************/
+// Following Structures and constant may be obsolete
+/****************************************************************************/
+//Maxium 8 bytes,the data read in will be placed in the parameter space.
+//Read operaion successeful when the paramter space is non-zero, otherwise read operation failed
+typedef struct _READ_EDID_FROM_HW_I2C_DATA_PARAMETERS
+{
+ USHORT usPrescale; //Ratio between Engine clock and I2C clock
+ USHORT usVRAMAddress; //Adress in Frame Buffer where to pace raw EDID
+ USHORT usStatus; //When use output: lower byte EDID checksum, high byte hardware status
+ //WHen use input: lower byte as 'byte to read':currently limited to 128byte or 1byte
+ UCHAR ucSlaveAddr; //Read from which slave
+ UCHAR ucLineNumber; //Read from which HW assisted line
+}READ_EDID_FROM_HW_I2C_DATA_PARAMETERS;
#define READ_EDID_FROM_HW_I2C_DATA_PS_ALLOCATION READ_EDID_FROM_HW_I2C_DATA_PARAMETERS
+
#define ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSDATABYTE 0
#define ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSTWODATABYTES 1
#define ATOM_WRITE_I2C_FORMAT_PSCOUNTER_PSOFFSET_IDDATABLOCK 2
#define ATOM_WRITE_I2C_FORMAT_PSCOUNTER_IDOFFSET_PLUS_IDDATABLOCK 3
#define ATOM_WRITE_I2C_FORMAT_IDCOUNTER_IDOFFSET_IDDATABLOCK 4
-typedef struct _WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS {
- USHORT usPrescale; /* Ratio between Engine clock and I2C clock */
- USHORT usByteOffset; /* Write to which byte */
- /* Upper portion of usByteOffset is Format of data */
- /* 1bytePS+offsetPS */
- /* 2bytesPS+offsetPS */
- /* blockID+offsetPS */
- /* blockID+offsetID */
- /* blockID+counterID+offsetID */
- UCHAR ucData; /* PS data1 */
- UCHAR ucStatus; /* Status byte 1=success, 2=failure, Also is used as PS data2 */
- UCHAR ucSlaveAddr; /* Write to which slave */
- UCHAR ucLineNumber; /* Write from which HW assisted line */
-} WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS;
+typedef struct _WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS
+{
+ USHORT usPrescale; //Ratio between Engine clock and I2C clock
+ USHORT usByteOffset; //Write to which byte
+ //Upper portion of usByteOffset is Format of data
+ //1bytePS+offsetPS
+ //2bytesPS+offsetPS
+ //blockID+offsetPS
+ //blockID+offsetID
+ //blockID+counterID+offsetID
+ UCHAR ucData; //PS data1
+ UCHAR ucStatus; //Status byte 1=success, 2=failure, Also is used as PS data2
+ UCHAR ucSlaveAddr; //Write to which slave
+ UCHAR ucLineNumber; //Write from which HW assisted line
+}WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS;
#define WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS
-typedef struct _SET_UP_HW_I2C_DATA_PARAMETERS {
- USHORT usPrescale; /* Ratio between Engine clock and I2C clock */
- UCHAR ucSlaveAddr; /* Write to which slave */
- UCHAR ucLineNumber; /* Write from which HW assisted line */
-} SET_UP_HW_I2C_DATA_PARAMETERS;
+typedef struct _SET_UP_HW_I2C_DATA_PARAMETERS
+{
+ USHORT usPrescale; //Ratio between Engine clock and I2C clock
+ UCHAR ucSlaveAddr; //Write to which slave
+ UCHAR ucLineNumber; //Write from which HW assisted line
+}SET_UP_HW_I2C_DATA_PARAMETERS;
+
/**************************************************************************/
#define SPEED_FAN_CONTROL_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS
-/****************************************************************************/
-/* Structures used by PowerConnectorDetectionTable */
-/****************************************************************************/
-typedef struct _POWER_CONNECTOR_DETECTION_PARAMETERS {
- UCHAR ucPowerConnectorStatus; /* Used for return value 0: detected, 1:not detected */
- UCHAR ucPwrBehaviorId;
- USHORT usPwrBudget; /* how much power currently boot to in unit of watt */
-} POWER_CONNECTOR_DETECTION_PARAMETERS;
-
-typedef struct POWER_CONNECTOR_DETECTION_PS_ALLOCATION {
- UCHAR ucPowerConnectorStatus; /* Used for return value 0: detected, 1:not detected */
- UCHAR ucReserved;
- USHORT usPwrBudget; /* how much power currently boot to in unit of watt */
- WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;
-} POWER_CONNECTOR_DETECTION_PS_ALLOCATION;
+/****************************************************************************/
+// Structures used by PowerConnectorDetectionTable
+/****************************************************************************/
+typedef struct _POWER_CONNECTOR_DETECTION_PARAMETERS
+{
+ UCHAR ucPowerConnectorStatus; //Used for return value 0: detected, 1:not detected
+ UCHAR ucPwrBehaviorId;
+ USHORT usPwrBudget; //how much power currently boot to in unit of watt
+}POWER_CONNECTOR_DETECTION_PARAMETERS;
+
+typedef struct POWER_CONNECTOR_DETECTION_PS_ALLOCATION
+{
+ UCHAR ucPowerConnectorStatus; //Used for return value 0: detected, 1:not detected
+ UCHAR ucReserved;
+ USHORT usPwrBudget; //how much power currently boot to in unit of watt
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;
+}POWER_CONNECTOR_DETECTION_PS_ALLOCATION;
/****************************LVDS SS Command Table Definitions**********************/
-/****************************************************************************/
-/* Structures used by EnableSpreadSpectrumOnPPLLTable */
-/****************************************************************************/
-typedef struct _ENABLE_LVDS_SS_PARAMETERS {
- USHORT usSpreadSpectrumPercentage;
- UCHAR ucSpreadSpectrumType; /* Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD */
- UCHAR ucSpreadSpectrumStepSize_Delay; /* bits3:2 SS_STEP_SIZE; bit 6:4 SS_DELAY */
- UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */
- UCHAR ucPadding[3];
-} ENABLE_LVDS_SS_PARAMETERS;
-
-/* ucTableFormatRevision=1,ucTableContentRevision=2 */
-typedef struct _ENABLE_LVDS_SS_PARAMETERS_V2 {
- USHORT usSpreadSpectrumPercentage;
- UCHAR ucSpreadSpectrumType; /* Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD */
- UCHAR ucSpreadSpectrumStep; /* */
- UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */
- UCHAR ucSpreadSpectrumDelay;
- UCHAR ucSpreadSpectrumRange;
- UCHAR ucPadding;
-} ENABLE_LVDS_SS_PARAMETERS_V2;
-
-/* This new structure is based on ENABLE_LVDS_SS_PARAMETERS but expands to SS on PPLL, so other devices can use SS. */
-typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL {
- USHORT usSpreadSpectrumPercentage;
- UCHAR ucSpreadSpectrumType; /* Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD */
- UCHAR ucSpreadSpectrumStep; /* */
- UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */
- UCHAR ucSpreadSpectrumDelay;
- UCHAR ucSpreadSpectrumRange;
- UCHAR ucPpll; /* ATOM_PPLL1/ATOM_PPLL2 */
-} ENABLE_SPREAD_SPECTRUM_ON_PPLL;
+/****************************************************************************/
+// Structures used by EnableSpreadSpectrumOnPPLLTable
+/****************************************************************************/
+typedef struct _ENABLE_LVDS_SS_PARAMETERS
+{
+ USHORT usSpreadSpectrumPercentage;
+ UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD
+ UCHAR ucSpreadSpectrumStepSize_Delay; //bits3:2 SS_STEP_SIZE; bit 6:4 SS_DELAY
+ UCHAR ucEnable; //ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucPadding[3];
+}ENABLE_LVDS_SS_PARAMETERS;
+
+//ucTableFormatRevision=1,ucTableContentRevision=2
+typedef struct _ENABLE_LVDS_SS_PARAMETERS_V2
+{
+ USHORT usSpreadSpectrumPercentage;
+ UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD
+ UCHAR ucSpreadSpectrumStep; //
+ UCHAR ucEnable; //ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucSpreadSpectrumDelay;
+ UCHAR ucSpreadSpectrumRange;
+ UCHAR ucPadding;
+}ENABLE_LVDS_SS_PARAMETERS_V2;
+
+//This new structure is based on ENABLE_LVDS_SS_PARAMETERS but expands to SS on PPLL, so other devices can use SS.
+typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL
+{
+ USHORT usSpreadSpectrumPercentage;
+ UCHAR ucSpreadSpectrumType; // Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD
+ UCHAR ucSpreadSpectrumStep; //
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucSpreadSpectrumDelay;
+ UCHAR ucSpreadSpectrumRange;
+ UCHAR ucPpll; // ATOM_PPLL1/ATOM_PPLL2
+}ENABLE_SPREAD_SPECTRUM_ON_PPLL;
+
+typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2
+{
+ USHORT usSpreadSpectrumPercentage;
+ UCHAR ucSpreadSpectrumType; // Bit[0]: 0-Down Spread,1-Center Spread.
+ // Bit[1]: 1-Ext. 0-Int.
+ // Bit[3:2]: =0 P1PLL =1 P2PLL =2 DCPLL
+ // Bits[7:4] reserved
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ USHORT usSpreadSpectrumAmount; // Includes SS_AMOUNT_FBDIV[7:0] and SS_AMOUNT_NFRAC_SLIP[11:8]
+ USHORT usSpreadSpectrumStep; // SS_STEP_SIZE_DSFRAC
+}ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2;
+
+#define ATOM_PPLL_SS_TYPE_V2_DOWN_SPREAD 0x00
+#define ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD 0x01
+#define ATOM_PPLL_SS_TYPE_V2_EXT_SPREAD 0x02
+#define ATOM_PPLL_SS_TYPE_V2_PPLL_SEL_MASK 0x0c
+#define ATOM_PPLL_SS_TYPE_V2_P1PLL 0x00
+#define ATOM_PPLL_SS_TYPE_V2_P2PLL 0x04
+#define ATOM_PPLL_SS_TYPE_V2_DCPLL 0x08
+#define ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK 0x00FF
+#define ATOM_PPLL_SS_AMOUNT_V2_FBDIV_SHIFT 0
+#define ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK 0x0F00
+#define ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT 8
#define ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION ENABLE_SPREAD_SPECTRUM_ON_PPLL
/**************************************************************************/
-typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION {
- PIXEL_CLOCK_PARAMETERS sPCLKInput;
- ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved; /* Caller doesn't need to init this portion */
-} SET_PIXEL_CLOCK_PS_ALLOCATION;
+typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION
+{
+ PIXEL_CLOCK_PARAMETERS sPCLKInput;
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved;//Caller doesn't need to init this portion
+}SET_PIXEL_CLOCK_PS_ALLOCATION;
#define ENABLE_VGA_RENDER_PS_ALLOCATION SET_PIXEL_CLOCK_PS_ALLOCATION
-/****************************************************************************/
-/* Structures used by ### */
-/****************************************************************************/
-typedef struct _MEMORY_TRAINING_PARAMETERS {
- ULONG ulTargetMemoryClock; /* In 10Khz unit */
-} MEMORY_TRAINING_PARAMETERS;
+/****************************************************************************/
+// Structures used by ###
+/****************************************************************************/
+typedef struct _MEMORY_TRAINING_PARAMETERS
+{
+ ULONG ulTargetMemoryClock; //In 10Khz unit
+}MEMORY_TRAINING_PARAMETERS;
#define MEMORY_TRAINING_PS_ALLOCATION MEMORY_TRAINING_PARAMETERS
+
/****************************LVDS and other encoder command table definitions **********************/
-/****************************************************************************/
-/* Structures used by LVDSEncoderControlTable (Before DCE30) */
-/* LVTMAEncoderControlTable (Before DCE30) */
-/* TMDSAEncoderControlTable (Before DCE30) */
-/****************************************************************************/
-typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS {
- USHORT usPixelClock; /* in 10KHz; for bios convenient */
- UCHAR ucMisc; /* bit0=0: Enable single link */
- /* =1: Enable dual link */
- /* Bit1=0: 666RGB */
- /* =1: 888RGB */
- UCHAR ucAction; /* 0: turn off encoder */
- /* 1: setup and turn on encoder */
-} LVDS_ENCODER_CONTROL_PARAMETERS;
-#define LVDS_ENCODER_CONTROL_PS_ALLOCATION LVDS_ENCODER_CONTROL_PARAMETERS
+/****************************************************************************/
+// Structures used by LVDSEncoderControlTable (Before DCE30)
+// LVTMAEncoderControlTable (Before DCE30)
+// TMDSAEncoderControlTable (Before DCE30)
+/****************************************************************************/
+typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ UCHAR ucMisc; // bit0=0: Enable single link
+ // =1: Enable dual link
+ // Bit1=0: 666RGB
+ // =1: 888RGB
+ UCHAR ucAction; // 0: turn off encoder
+ // 1: setup and turn on encoder
+}LVDS_ENCODER_CONTROL_PARAMETERS;
+#define LVDS_ENCODER_CONTROL_PS_ALLOCATION LVDS_ENCODER_CONTROL_PARAMETERS
+
#define TMDS1_ENCODER_CONTROL_PARAMETERS LVDS_ENCODER_CONTROL_PARAMETERS
#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION TMDS1_ENCODER_CONTROL_PARAMETERS
#define TMDS2_ENCODER_CONTROL_PARAMETERS TMDS1_ENCODER_CONTROL_PARAMETERS
#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION TMDS2_ENCODER_CONTROL_PARAMETERS
-/* ucTableFormatRevision=1,ucTableContentRevision=2 */
-typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS_V2 {
- USHORT usPixelClock; /* in 10KHz; for bios convenient */
- UCHAR ucMisc; /* see PANEL_ENCODER_MISC_xx definitions below */
- UCHAR ucAction; /* 0: turn off encoder */
- /* 1: setup and turn on encoder */
- UCHAR ucTruncate; /* bit0=0: Disable truncate */
- /* =1: Enable truncate */
- /* bit4=0: 666RGB */
- /* =1: 888RGB */
- UCHAR ucSpatial; /* bit0=0: Disable spatial dithering */
- /* =1: Enable spatial dithering */
- /* bit4=0: 666RGB */
- /* =1: 888RGB */
- UCHAR ucTemporal; /* bit0=0: Disable temporal dithering */
- /* =1: Enable temporal dithering */
- /* bit4=0: 666RGB */
- /* =1: 888RGB */
- /* bit5=0: Gray level 2 */
- /* =1: Gray level 4 */
- UCHAR ucFRC; /* bit4=0: 25FRC_SEL pattern E */
- /* =1: 25FRC_SEL pattern F */
- /* bit6:5=0: 50FRC_SEL pattern A */
- /* =1: 50FRC_SEL pattern B */
- /* =2: 50FRC_SEL pattern C */
- /* =3: 50FRC_SEL pattern D */
- /* bit7=0: 75FRC_SEL pattern E */
- /* =1: 75FRC_SEL pattern F */
-} LVDS_ENCODER_CONTROL_PARAMETERS_V2;
-#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2
+//ucTableFormatRevision=1,ucTableContentRevision=2
+typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS_V2
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ UCHAR ucMisc; // see PANEL_ENCODER_MISC_xx defintions below
+ UCHAR ucAction; // 0: turn off encoder
+ // 1: setup and turn on encoder
+ UCHAR ucTruncate; // bit0=0: Disable truncate
+ // =1: Enable truncate
+ // bit4=0: 666RGB
+ // =1: 888RGB
+ UCHAR ucSpatial; // bit0=0: Disable spatial dithering
+ // =1: Enable spatial dithering
+ // bit4=0: 666RGB
+ // =1: 888RGB
+ UCHAR ucTemporal; // bit0=0: Disable temporal dithering
+ // =1: Enable temporal dithering
+ // bit4=0: 666RGB
+ // =1: 888RGB
+ // bit5=0: Gray level 2
+ // =1: Gray level 4
+ UCHAR ucFRC; // bit4=0: 25FRC_SEL pattern E
+ // =1: 25FRC_SEL pattern F
+ // bit6:5=0: 50FRC_SEL pattern A
+ // =1: 50FRC_SEL pattern B
+ // =2: 50FRC_SEL pattern C
+ // =3: 50FRC_SEL pattern D
+ // bit7=0: 75FRC_SEL pattern E
+ // =1: 75FRC_SEL pattern F
+}LVDS_ENCODER_CONTROL_PARAMETERS_V2;
+#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2
+
#define TMDS1_ENCODER_CONTROL_PARAMETERS_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2
#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2
-
+
#define TMDS2_ENCODER_CONTROL_PARAMETERS_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2
#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS2_ENCODER_CONTROL_PARAMETERS_V2
@@ -1185,38 +1536,42 @@ typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS_V2 {
#define TMDS2_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3
#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS2_ENCODER_CONTROL_PARAMETERS_V3
-/****************************************************************************/
-/* Structures used by ### */
-/****************************************************************************/
-typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS {
- UCHAR ucEnable; /* Enable or Disable External TMDS encoder */
- UCHAR ucMisc; /* Bit0=0:Enable Single link;=1:Enable Dual link;Bit1 {=0:666RGB, =1:888RGB} */
- UCHAR ucPadding[2];
-} ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS;
-
-typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION {
- ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS sXTmdsEncoder;
- WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; /* Caller doesn't need to init this portion */
-} ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION;
+/****************************************************************************/
+// Structures used by ###
+/****************************************************************************/
+typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS
+{
+ UCHAR ucEnable; // Enable or Disable External TMDS encoder
+ UCHAR ucMisc; // Bit0=0:Enable Single link;=1:Enable Dual link;Bit1 {=0:666RGB, =1:888RGB}
+ UCHAR ucPadding[2];
+}ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS;
+
+typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION
+{
+ ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS sXTmdsEncoder;
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion
+}ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION;
#define ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2
-typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2 {
- ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 sXTmdsEncoder;
- WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; /* Caller doesn't need to init this portion */
-} ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2;
+typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2
+{
+ ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 sXTmdsEncoder;
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion
+}ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2;
-typedef struct _EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION {
- DIG_ENCODER_CONTROL_PARAMETERS sDigEncoder;
- WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;
-} EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION;
+typedef struct _EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION
+{
+ DIG_ENCODER_CONTROL_PARAMETERS sDigEncoder;
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;
+}EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION;
-/****************************************************************************/
-/* Structures used by DVOEncoderControlTable */
-/****************************************************************************/
-/* ucTableFormatRevision=1,ucTableContentRevision=3 */
+/****************************************************************************/
+// Structures used by DVOEncoderControlTable
+/****************************************************************************/
+//ucTableFormatRevision=1,ucTableContentRevision=3
-/* ucDVOConfig: */
+//ucDVOConfig:
#define DVO_ENCODER_CONFIG_RATE_SEL 0x01
#define DVO_ENCODER_CONFIG_DDR_SPEED 0x00
#define DVO_ENCODER_CONFIG_SDR_SPEED 0x01
@@ -1225,21 +1580,22 @@ typedef struct _EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION {
#define DVO_ENCODER_CONFIG_UPPER12BIT 0x04
#define DVO_ENCODER_CONFIG_24BIT 0x08
-typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3 {
- USHORT usPixelClock;
- UCHAR ucDVOConfig;
- UCHAR ucAction; /* ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT */
- UCHAR ucReseved[4];
-} DVO_ENCODER_CONTROL_PARAMETERS_V3;
+typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3
+{
+ USHORT usPixelClock;
+ UCHAR ucDVOConfig;
+ UCHAR ucAction; //ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT
+ UCHAR ucReseved[4];
+}DVO_ENCODER_CONTROL_PARAMETERS_V3;
#define DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 DVO_ENCODER_CONTROL_PARAMETERS_V3
-/* ucTableFormatRevision=1 */
-/* ucTableContentRevision=3 structure is not changed but usMisc add bit 1 as another input for */
-/* bit1=0: non-coherent mode */
-/* =1: coherent mode */
+//ucTableFormatRevision=1
+//ucTableContentRevision=3 structure is not changed but usMisc add bit 1 as another input for
+// bit1=0: non-coherent mode
+// =1: coherent mode
-/* ========================================================================================== */
-/* Only change is here next time when changing encoder parameter definitions again! */
+//==========================================================================================
+//Only change is here next time when changing encoder parameter definitions again!
#define LVDS_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3
#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_LAST LVDS_ENCODER_CONTROL_PARAMETERS_LAST
@@ -1252,7 +1608,7 @@ typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3 {
#define DVO_ENCODER_CONTROL_PARAMETERS_LAST DVO_ENCODER_CONTROL_PARAMETERS
#define DVO_ENCODER_CONTROL_PS_ALLOCATION_LAST DVO_ENCODER_CONTROL_PS_ALLOCATION
-/* ========================================================================================== */
+//==========================================================================================
#define PANEL_ENCODER_MISC_DUAL 0x01
#define PANEL_ENCODER_MISC_COHERENT 0x02
#define PANEL_ENCODER_MISC_TMDS_LINKB 0x04
@@ -1281,159 +1637,159 @@ typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3 {
#define PANEL_ENCODER_75FRC_E 0x00
#define PANEL_ENCODER_75FRC_F 0x80
-/****************************************************************************/
-/* Structures used by SetVoltageTable */
-/****************************************************************************/
+/****************************************************************************/
+// Structures used by SetVoltageTable
+/****************************************************************************/
#define SET_VOLTAGE_TYPE_ASIC_VDDC 1
#define SET_VOLTAGE_TYPE_ASIC_MVDDC 2
#define SET_VOLTAGE_TYPE_ASIC_MVDDQ 3
#define SET_VOLTAGE_TYPE_ASIC_VDDCI 4
#define SET_VOLTAGE_INIT_MODE 5
-#define SET_VOLTAGE_GET_MAX_VOLTAGE 6 /* Gets the Max. voltage for the soldered Asic */
+#define SET_VOLTAGE_GET_MAX_VOLTAGE 6 //Gets the Max. voltage for the soldered Asic
#define SET_ASIC_VOLTAGE_MODE_ALL_SOURCE 0x1
#define SET_ASIC_VOLTAGE_MODE_SOURCE_A 0x2
#define SET_ASIC_VOLTAGE_MODE_SOURCE_B 0x4
#define SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE 0x0
-#define SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL 0x1
+#define SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL 0x1
#define SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK 0x2
-typedef struct _SET_VOLTAGE_PARAMETERS {
- UCHAR ucVoltageType; /* To tell which voltage to set up, VDDC/MVDDC/MVDDQ */
- UCHAR ucVoltageMode; /* To set all, to set source A or source B or ... */
- UCHAR ucVoltageIndex; /* An index to tell which voltage level */
- UCHAR ucReserved;
-} SET_VOLTAGE_PARAMETERS;
-
-typedef struct _SET_VOLTAGE_PARAMETERS_V2 {
- UCHAR ucVoltageType; /* To tell which voltage to set up, VDDC/MVDDC/MVDDQ */
- UCHAR ucVoltageMode; /* Not used, maybe use for state machine for differen power mode */
- USHORT usVoltageLevel; /* real voltage level */
-} SET_VOLTAGE_PARAMETERS_V2;
-
-typedef struct _SET_VOLTAGE_PS_ALLOCATION {
- SET_VOLTAGE_PARAMETERS sASICSetVoltage;
- WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;
-} SET_VOLTAGE_PS_ALLOCATION;
-
-/****************************************************************************/
-/* Structures used by TVEncoderControlTable */
-/****************************************************************************/
-typedef struct _TV_ENCODER_CONTROL_PARAMETERS {
- USHORT usPixelClock; /* in 10KHz; for bios convenient */
- UCHAR ucTvStandard; /* See definition "ATOM_TV_NTSC ..." */
- UCHAR ucAction; /* 0: turn off encoder */
- /* 1: setup and turn on encoder */
-} TV_ENCODER_CONTROL_PARAMETERS;
-
-typedef struct _TV_ENCODER_CONTROL_PS_ALLOCATION {
- TV_ENCODER_CONTROL_PARAMETERS sTVEncoder;
- WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; /* Don't set this one */
-} TV_ENCODER_CONTROL_PS_ALLOCATION;
-
-/* ==============================Data Table Portion==================================== */
-
-#ifdef UEFI_BUILD
-#define UTEMP USHORT
-#define USHORT void*
-#endif
-
-/****************************************************************************/
-/* Structure used in Data.mtb */
-/****************************************************************************/
-typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES {
- USHORT UtilityPipeLine; /* Offest for the utility to get parser info,Don't change this position! */
- USHORT MultimediaCapabilityInfo; /* Only used by MM Lib,latest version 1.1, not configuable from Bios, need to include the table to build Bios */
- USHORT MultimediaConfigInfo; /* Only used by MM Lib,latest version 2.1, not configuable from Bios, need to include the table to build Bios */
- USHORT StandardVESA_Timing; /* Only used by Bios */
- USHORT FirmwareInfo; /* Shared by various SW components,latest version 1.4 */
- USHORT DAC_Info; /* Will be obsolete from R600 */
- USHORT LVDS_Info; /* Shared by various SW components,latest version 1.1 */
- USHORT TMDS_Info; /* Will be obsolete from R600 */
- USHORT AnalogTV_Info; /* Shared by various SW components,latest version 1.1 */
- USHORT SupportedDevicesInfo; /* Will be obsolete from R600 */
- USHORT GPIO_I2C_Info; /* Shared by various SW components,latest version 1.2 will be used from R600 */
- USHORT VRAM_UsageByFirmware; /* Shared by various SW components,latest version 1.3 will be used from R600 */
- USHORT GPIO_Pin_LUT; /* Shared by various SW components,latest version 1.1 */
- USHORT VESA_ToInternalModeLUT; /* Only used by Bios */
- USHORT ComponentVideoInfo; /* Shared by various SW components,latest version 2.1 will be used from R600 */
- USHORT PowerPlayInfo; /* Shared by various SW components,latest version 2.1,new design from R600 */
- USHORT CompassionateData; /* Will be obsolete from R600 */
- USHORT SaveRestoreInfo; /* Only used by Bios */
- USHORT PPLL_SS_Info; /* Shared by various SW components,latest version 1.2, used to call SS_Info, change to new name because of int ASIC SS info */
- USHORT OemInfo; /* Defined and used by external SW, should be obsolete soon */
- USHORT XTMDS_Info; /* Will be obsolete from R600 */
- USHORT MclkSS_Info; /* Shared by various SW components,latest version 1.1, only enabled when ext SS chip is used */
- USHORT Object_Header; /* Shared by various SW components,latest version 1.1 */
- USHORT IndirectIOAccess; /* Only used by Bios,this table position can't change at all!! */
- USHORT MC_InitParameter; /* Only used by command table */
- USHORT ASIC_VDDC_Info; /* Will be obsolete from R600 */
- USHORT ASIC_InternalSS_Info; /* New tabel name from R600, used to be called "ASIC_MVDDC_Info" */
- USHORT TV_VideoMode; /* Only used by command table */
- USHORT VRAM_Info; /* Only used by command table, latest version 1.3 */
- USHORT MemoryTrainingInfo; /* Used for VBIOS and Diag utility for memory training purpose since R600. the new table rev start from 2.1 */
- USHORT IntegratedSystemInfo; /* Shared by various SW components */
- USHORT ASIC_ProfilingInfo; /* New table name from R600, used to be called "ASIC_VDDCI_Info" for pre-R600 */
- USHORT VoltageObjectInfo; /* Shared by various SW components, latest version 1.1 */
- USHORT PowerSourceInfo; /* Shared by various SW components, latest versoin 1.1 */
-} ATOM_MASTER_LIST_OF_DATA_TABLES;
-
-#ifdef UEFI_BUILD
-#define USHORT UTEMP
-#endif
+typedef struct _SET_VOLTAGE_PARAMETERS
+{
+ UCHAR ucVoltageType; // To tell which voltage to set up, VDDC/MVDDC/MVDDQ
+ UCHAR ucVoltageMode; // To set all, to set source A or source B or ...
+ UCHAR ucVoltageIndex; // An index to tell which voltage level
+ UCHAR ucReserved;
+}SET_VOLTAGE_PARAMETERS;
-typedef struct _ATOM_MASTER_DATA_TABLE {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_MASTER_LIST_OF_DATA_TABLES ListOfDataTables;
-} ATOM_MASTER_DATA_TABLE;
+typedef struct _SET_VOLTAGE_PARAMETERS_V2
+{
+ UCHAR ucVoltageType; // To tell which voltage to set up, VDDC/MVDDC/MVDDQ
+ UCHAR ucVoltageMode; // Not used, maybe use for state machine for differen power mode
+ USHORT usVoltageLevel; // real voltage level
+}SET_VOLTAGE_PARAMETERS_V2;
-/****************************************************************************/
-/* Structure used in MultimediaCapabilityInfoTable */
-/****************************************************************************/
-typedef struct _ATOM_MULTIMEDIA_CAPABILITY_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ULONG ulSignature; /* HW info table signature string "$ATI" */
- UCHAR ucI2C_Type; /* I2C type (normal GP_IO, ImpactTV GP_IO, Dedicated I2C pin, etc) */
- UCHAR ucTV_OutInfo; /* Type of TV out supported (3:0) and video out crystal frequency (6:4) and TV data port (7) */
- UCHAR ucVideoPortInfo; /* Provides the video port capabilities */
- UCHAR ucHostPortInfo; /* Provides host port configuration information */
-} ATOM_MULTIMEDIA_CAPABILITY_INFO;
+typedef struct _SET_VOLTAGE_PS_ALLOCATION
+{
+ SET_VOLTAGE_PARAMETERS sASICSetVoltage;
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;
+}SET_VOLTAGE_PS_ALLOCATION;
+
+/****************************************************************************/
+// Structures used by TVEncoderControlTable
+/****************************************************************************/
+typedef struct _TV_ENCODER_CONTROL_PARAMETERS
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ UCHAR ucTvStandard; // See definition "ATOM_TV_NTSC ..."
+ UCHAR ucAction; // 0: turn off encoder
+ // 1: setup and turn on encoder
+}TV_ENCODER_CONTROL_PARAMETERS;
-/****************************************************************************/
-/* Structure used in MultimediaConfigInfoTable */
-/****************************************************************************/
-typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ULONG ulSignature; /* MM info table signature sting "$MMT" */
- UCHAR ucTunerInfo; /* Type of tuner installed on the adapter (4:0) and video input for tuner (7:5) */
- UCHAR ucAudioChipInfo; /* List the audio chip type (3:0) product type (4) and OEM revision (7:5) */
- UCHAR ucProductID; /* Defines as OEM ID or ATI board ID dependent on product type setting */
- UCHAR ucMiscInfo1; /* Tuner voltage (1:0) HW teletext support (3:2) FM audio decoder (5:4) reserved (6) audio scrambling (7) */
- UCHAR ucMiscInfo2; /* I2S input config (0) I2S output config (1) I2S Audio Chip (4:2) SPDIF Output Config (5) reserved (7:6) */
- UCHAR ucMiscInfo3; /* Video Decoder Type (3:0) Video In Standard/Crystal (7:4) */
- UCHAR ucMiscInfo4; /* Video Decoder Host Config (2:0) reserved (7:3) */
- UCHAR ucVideoInput0Info; /* Video Input 0 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */
- UCHAR ucVideoInput1Info; /* Video Input 1 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */
- UCHAR ucVideoInput2Info; /* Video Input 2 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */
- UCHAR ucVideoInput3Info; /* Video Input 3 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */
- UCHAR ucVideoInput4Info; /* Video Input 4 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */
-} ATOM_MULTIMEDIA_CONFIG_INFO;
+typedef struct _TV_ENCODER_CONTROL_PS_ALLOCATION
+{
+ TV_ENCODER_CONTROL_PARAMETERS sTVEncoder;
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; // Don't set this one
+}TV_ENCODER_CONTROL_PS_ALLOCATION;
-/****************************************************************************/
-/* Structures used in FirmwareInfoTable */
-/****************************************************************************/
+//==============================Data Table Portion====================================
-/* usBIOSCapability Definition: */
-/* Bit 0 = 0: Bios image is not Posted, =1:Bios image is Posted; */
-/* Bit 1 = 0: Dual CRTC is not supported, =1: Dual CRTC is supported; */
-/* Bit 2 = 0: Extended Desktop is not supported, =1: Extended Desktop is supported; */
-/* Others: Reserved */
+/****************************************************************************/
+// Structure used in Data.mtb
+/****************************************************************************/
+typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES
+{
+ USHORT UtilityPipeLine; // Offest for the utility to get parser info,Don't change this position!
+ USHORT MultimediaCapabilityInfo; // Only used by MM Lib,latest version 1.1, not configuable from Bios, need to include the table to build Bios
+ USHORT MultimediaConfigInfo; // Only used by MM Lib,latest version 2.1, not configuable from Bios, need to include the table to build Bios
+ USHORT StandardVESA_Timing; // Only used by Bios
+ USHORT FirmwareInfo; // Shared by various SW components,latest version 1.4
+ USHORT DAC_Info; // Will be obsolete from R600
+ USHORT LVDS_Info; // Shared by various SW components,latest version 1.1
+ USHORT TMDS_Info; // Will be obsolete from R600
+ USHORT AnalogTV_Info; // Shared by various SW components,latest version 1.1
+ USHORT SupportedDevicesInfo; // Will be obsolete from R600
+ USHORT GPIO_I2C_Info; // Shared by various SW components,latest version 1.2 will be used from R600
+ USHORT VRAM_UsageByFirmware; // Shared by various SW components,latest version 1.3 will be used from R600
+ USHORT GPIO_Pin_LUT; // Shared by various SW components,latest version 1.1
+ USHORT VESA_ToInternalModeLUT; // Only used by Bios
+ USHORT ComponentVideoInfo; // Shared by various SW components,latest version 2.1 will be used from R600
+ USHORT PowerPlayInfo; // Shared by various SW components,latest version 2.1,new design from R600
+ USHORT CompassionateData; // Will be obsolete from R600
+ USHORT SaveRestoreInfo; // Only used by Bios
+ USHORT PPLL_SS_Info; // Shared by various SW components,latest version 1.2, used to call SS_Info, change to new name because of int ASIC SS info
+ USHORT OemInfo; // Defined and used by external SW, should be obsolete soon
+ USHORT XTMDS_Info; // Will be obsolete from R600
+ USHORT MclkSS_Info; // Shared by various SW components,latest version 1.1, only enabled when ext SS chip is used
+ USHORT Object_Header; // Shared by various SW components,latest version 1.1
+ USHORT IndirectIOAccess; // Only used by Bios,this table position can't change at all!!
+ USHORT MC_InitParameter; // Only used by command table
+ USHORT ASIC_VDDC_Info; // Will be obsolete from R600
+ USHORT ASIC_InternalSS_Info; // New tabel name from R600, used to be called "ASIC_MVDDC_Info"
+ USHORT TV_VideoMode; // Only used by command table
+ USHORT VRAM_Info; // Only used by command table, latest version 1.3
+ USHORT MemoryTrainingInfo; // Used for VBIOS and Diag utility for memory training purpose since R600. the new table rev start from 2.1
+ USHORT IntegratedSystemInfo; // Shared by various SW components
+ USHORT ASIC_ProfilingInfo; // New table name from R600, used to be called "ASIC_VDDCI_Info" for pre-R600
+ USHORT VoltageObjectInfo; // Shared by various SW components, latest version 1.1
+ USHORT PowerSourceInfo; // Shared by various SW components, latest versoin 1.1
+}ATOM_MASTER_LIST_OF_DATA_TABLES;
+
+typedef struct _ATOM_MASTER_DATA_TABLE
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_MASTER_LIST_OF_DATA_TABLES ListOfDataTables;
+}ATOM_MASTER_DATA_TABLE;
+
+/****************************************************************************/
+// Structure used in MultimediaCapabilityInfoTable
+/****************************************************************************/
+typedef struct _ATOM_MULTIMEDIA_CAPABILITY_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulSignature; // HW info table signature string "$ATI"
+ UCHAR ucI2C_Type; // I2C type (normal GP_IO, ImpactTV GP_IO, Dedicated I2C pin, etc)
+ UCHAR ucTV_OutInfo; // Type of TV out supported (3:0) and video out crystal frequency (6:4) and TV data port (7)
+ UCHAR ucVideoPortInfo; // Provides the video port capabilities
+ UCHAR ucHostPortInfo; // Provides host port configuration information
+}ATOM_MULTIMEDIA_CAPABILITY_INFO;
+
+/****************************************************************************/
+// Structure used in MultimediaConfigInfoTable
+/****************************************************************************/
+typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulSignature; // MM info table signature sting "$MMT"
+ UCHAR ucTunerInfo; // Type of tuner installed on the adapter (4:0) and video input for tuner (7:5)
+ UCHAR ucAudioChipInfo; // List the audio chip type (3:0) product type (4) and OEM revision (7:5)
+ UCHAR ucProductID; // Defines as OEM ID or ATI board ID dependent on product type setting
+ UCHAR ucMiscInfo1; // Tuner voltage (1:0) HW teletext support (3:2) FM audio decoder (5:4) reserved (6) audio scrambling (7)
+ UCHAR ucMiscInfo2; // I2S input config (0) I2S output config (1) I2S Audio Chip (4:2) SPDIF Output Config (5) reserved (7:6)
+ UCHAR ucMiscInfo3; // Video Decoder Type (3:0) Video In Standard/Crystal (7:4)
+ UCHAR ucMiscInfo4; // Video Decoder Host Config (2:0) reserved (7:3)
+ UCHAR ucVideoInput0Info;// Video Input 0 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6)
+ UCHAR ucVideoInput1Info;// Video Input 1 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6)
+ UCHAR ucVideoInput2Info;// Video Input 2 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6)
+ UCHAR ucVideoInput3Info;// Video Input 3 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6)
+ UCHAR ucVideoInput4Info;// Video Input 4 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6)
+}ATOM_MULTIMEDIA_CONFIG_INFO;
+
+/****************************************************************************/
+// Structures used in FirmwareInfoTable
+/****************************************************************************/
+
+// usBIOSCapability Defintion:
+// Bit 0 = 0: Bios image is not Posted, =1:Bios image is Posted;
+// Bit 1 = 0: Dual CRTC is not supported, =1: Dual CRTC is supported;
+// Bit 2 = 0: Extended Desktop is not supported, =1: Extended Desktop is supported;
+// Others: Reserved
#define ATOM_BIOS_INFO_ATOM_FIRMWARE_POSTED 0x0001
#define ATOM_BIOS_INFO_DUAL_CRTC_SUPPORT 0x0002
#define ATOM_BIOS_INFO_EXTENDED_DESKTOP_SUPPORT 0x0004
-#define ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT 0x0008
-#define ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT 0x0010
+#define ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT 0x0008 // (valid from v1.1 ~v1.4):=1: memclk SS enable, =0 memclk SS disable.
+#define ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT 0x0010 // (valid from v1.1 ~v1.4):=1: engclk SS enable, =0 engclk SS disable.
#define ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU 0x0020
#define ATOM_BIOS_INFO_WMI_SUPPORT 0x0040
#define ATOM_BIOS_INFO_PPMODE_ASSIGNGED_BY_SYSTEM 0x0080
@@ -1441,242 +1797,292 @@ typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO {
#define ATOM_BIOS_INFO_HYPERMEMORY_SIZE_MASK 0x1E00
#define ATOM_BIOS_INFO_VPOST_WITHOUT_FIRST_MODE_SET 0x2000
#define ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE 0x4000
+#define ATOM_BIOS_INFO_MEMORY_CLOCK_EXT_SS_SUPPORT 0x0008 // (valid from v2.1 ): =1: memclk ss enable with external ss chip
+#define ATOM_BIOS_INFO_ENGINE_CLOCK_EXT_SS_SUPPORT 0x0010 // (valid from v2.1 ): =1: engclk ss enable with external ss chip
#ifndef _H2INC
-/* Please don't add or expand this bitfield structure below, this one will retire soon.! */
-typedef struct _ATOM_FIRMWARE_CAPABILITY {
+//Please don't add or expand this bitfield structure below, this one will retire soon.!
+typedef struct _ATOM_FIRMWARE_CAPABILITY
+{
#if ATOM_BIG_ENDIAN
- USHORT Reserved:3;
- USHORT HyperMemory_Size:4;
- USHORT HyperMemory_Support:1;
- USHORT PPMode_Assigned:1;
- USHORT WMI_SUPPORT:1;
- USHORT GPUControlsBL:1;
- USHORT EngineClockSS_Support:1;
- USHORT MemoryClockSS_Support:1;
- USHORT ExtendedDesktopSupport:1;
- USHORT DualCRTC_Support:1;
- USHORT FirmwarePosted:1;
+ USHORT Reserved:3;
+ USHORT HyperMemory_Size:4;
+ USHORT HyperMemory_Support:1;
+ USHORT PPMode_Assigned:1;
+ USHORT WMI_SUPPORT:1;
+ USHORT GPUControlsBL:1;
+ USHORT EngineClockSS_Support:1;
+ USHORT MemoryClockSS_Support:1;
+ USHORT ExtendedDesktopSupport:1;
+ USHORT DualCRTC_Support:1;
+ USHORT FirmwarePosted:1;
#else
- USHORT FirmwarePosted:1;
- USHORT DualCRTC_Support:1;
- USHORT ExtendedDesktopSupport:1;
- USHORT MemoryClockSS_Support:1;
- USHORT EngineClockSS_Support:1;
- USHORT GPUControlsBL:1;
- USHORT WMI_SUPPORT:1;
- USHORT PPMode_Assigned:1;
- USHORT HyperMemory_Support:1;
- USHORT HyperMemory_Size:4;
- USHORT Reserved:3;
+ USHORT FirmwarePosted:1;
+ USHORT DualCRTC_Support:1;
+ USHORT ExtendedDesktopSupport:1;
+ USHORT MemoryClockSS_Support:1;
+ USHORT EngineClockSS_Support:1;
+ USHORT GPUControlsBL:1;
+ USHORT WMI_SUPPORT:1;
+ USHORT PPMode_Assigned:1;
+ USHORT HyperMemory_Support:1;
+ USHORT HyperMemory_Size:4;
+ USHORT Reserved:3;
#endif
-} ATOM_FIRMWARE_CAPABILITY;
+}ATOM_FIRMWARE_CAPABILITY;
-typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS {
- ATOM_FIRMWARE_CAPABILITY sbfAccess;
- USHORT susAccess;
-} ATOM_FIRMWARE_CAPABILITY_ACCESS;
+typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS
+{
+ ATOM_FIRMWARE_CAPABILITY sbfAccess;
+ USHORT susAccess;
+}ATOM_FIRMWARE_CAPABILITY_ACCESS;
#else
-typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS {
- USHORT susAccess;
-} ATOM_FIRMWARE_CAPABILITY_ACCESS;
+typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS
+{
+ USHORT susAccess;
+}ATOM_FIRMWARE_CAPABILITY_ACCESS;
#endif
-typedef struct _ATOM_FIRMWARE_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ULONG ulFirmwareRevision;
- ULONG ulDefaultEngineClock; /* In 10Khz unit */
- ULONG ulDefaultMemoryClock; /* In 10Khz unit */
- ULONG ulDriverTargetEngineClock; /* In 10Khz unit */
- ULONG ulDriverTargetMemoryClock; /* In 10Khz unit */
- ULONG ulMaxEngineClockPLL_Output; /* In 10Khz unit */
- ULONG ulMaxMemoryClockPLL_Output; /* In 10Khz unit */
- ULONG ulMaxPixelClockPLL_Output; /* In 10Khz unit */
- ULONG ulASICMaxEngineClock; /* In 10Khz unit */
- ULONG ulASICMaxMemoryClock; /* In 10Khz unit */
- UCHAR ucASICMaxTemperature;
- UCHAR ucPadding[3]; /* Don't use them */
- ULONG aulReservedForBIOS[3]; /* Don't use them */
- USHORT usMinEngineClockPLL_Input; /* In 10Khz unit */
- USHORT usMaxEngineClockPLL_Input; /* In 10Khz unit */
- USHORT usMinEngineClockPLL_Output; /* In 10Khz unit */
- USHORT usMinMemoryClockPLL_Input; /* In 10Khz unit */
- USHORT usMaxMemoryClockPLL_Input; /* In 10Khz unit */
- USHORT usMinMemoryClockPLL_Output; /* In 10Khz unit */
- USHORT usMaxPixelClock; /* In 10Khz unit, Max. Pclk */
- USHORT usMinPixelClockPLL_Input; /* In 10Khz unit */
- USHORT usMaxPixelClockPLL_Input; /* In 10Khz unit */
- USHORT usMinPixelClockPLL_Output; /* In 10Khz unit, the definitions above can't change!!! */
- ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
- USHORT usReferenceClock; /* In 10Khz unit */
- USHORT usPM_RTS_Location; /* RTS PM4 starting location in ROM in 1Kb unit */
- UCHAR ucPM_RTS_StreamSize; /* RTS PM4 packets in Kb unit */
- UCHAR ucDesign_ID; /* Indicate what is the board design */
- UCHAR ucMemoryModule_ID; /* Indicate what is the board design */
-} ATOM_FIRMWARE_INFO;
-
-typedef struct _ATOM_FIRMWARE_INFO_V1_2 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ULONG ulFirmwareRevision;
- ULONG ulDefaultEngineClock; /* In 10Khz unit */
- ULONG ulDefaultMemoryClock; /* In 10Khz unit */
- ULONG ulDriverTargetEngineClock; /* In 10Khz unit */
- ULONG ulDriverTargetMemoryClock; /* In 10Khz unit */
- ULONG ulMaxEngineClockPLL_Output; /* In 10Khz unit */
- ULONG ulMaxMemoryClockPLL_Output; /* In 10Khz unit */
- ULONG ulMaxPixelClockPLL_Output; /* In 10Khz unit */
- ULONG ulASICMaxEngineClock; /* In 10Khz unit */
- ULONG ulASICMaxMemoryClock; /* In 10Khz unit */
- UCHAR ucASICMaxTemperature;
- UCHAR ucMinAllowedBL_Level;
- UCHAR ucPadding[2]; /* Don't use them */
- ULONG aulReservedForBIOS[2]; /* Don't use them */
- ULONG ulMinPixelClockPLL_Output; /* In 10Khz unit */
- USHORT usMinEngineClockPLL_Input; /* In 10Khz unit */
- USHORT usMaxEngineClockPLL_Input; /* In 10Khz unit */
- USHORT usMinEngineClockPLL_Output; /* In 10Khz unit */
- USHORT usMinMemoryClockPLL_Input; /* In 10Khz unit */
- USHORT usMaxMemoryClockPLL_Input; /* In 10Khz unit */
- USHORT usMinMemoryClockPLL_Output; /* In 10Khz unit */
- USHORT usMaxPixelClock; /* In 10Khz unit, Max. Pclk */
- USHORT usMinPixelClockPLL_Input; /* In 10Khz unit */
- USHORT usMaxPixelClockPLL_Input; /* In 10Khz unit */
- USHORT usMinPixelClockPLL_Output; /* In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output */
- ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
- USHORT usReferenceClock; /* In 10Khz unit */
- USHORT usPM_RTS_Location; /* RTS PM4 starting location in ROM in 1Kb unit */
- UCHAR ucPM_RTS_StreamSize; /* RTS PM4 packets in Kb unit */
- UCHAR ucDesign_ID; /* Indicate what is the board design */
- UCHAR ucMemoryModule_ID; /* Indicate what is the board design */
-} ATOM_FIRMWARE_INFO_V1_2;
-
-typedef struct _ATOM_FIRMWARE_INFO_V1_3 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ULONG ulFirmwareRevision;
- ULONG ulDefaultEngineClock; /* In 10Khz unit */
- ULONG ulDefaultMemoryClock; /* In 10Khz unit */
- ULONG ulDriverTargetEngineClock; /* In 10Khz unit */
- ULONG ulDriverTargetMemoryClock; /* In 10Khz unit */
- ULONG ulMaxEngineClockPLL_Output; /* In 10Khz unit */
- ULONG ulMaxMemoryClockPLL_Output; /* In 10Khz unit */
- ULONG ulMaxPixelClockPLL_Output; /* In 10Khz unit */
- ULONG ulASICMaxEngineClock; /* In 10Khz unit */
- ULONG ulASICMaxMemoryClock; /* In 10Khz unit */
- UCHAR ucASICMaxTemperature;
- UCHAR ucMinAllowedBL_Level;
- UCHAR ucPadding[2]; /* Don't use them */
- ULONG aulReservedForBIOS; /* Don't use them */
- ULONG ul3DAccelerationEngineClock; /* In 10Khz unit */
- ULONG ulMinPixelClockPLL_Output; /* In 10Khz unit */
- USHORT usMinEngineClockPLL_Input; /* In 10Khz unit */
- USHORT usMaxEngineClockPLL_Input; /* In 10Khz unit */
- USHORT usMinEngineClockPLL_Output; /* In 10Khz unit */
- USHORT usMinMemoryClockPLL_Input; /* In 10Khz unit */
- USHORT usMaxMemoryClockPLL_Input; /* In 10Khz unit */
- USHORT usMinMemoryClockPLL_Output; /* In 10Khz unit */
- USHORT usMaxPixelClock; /* In 10Khz unit, Max. Pclk */
- USHORT usMinPixelClockPLL_Input; /* In 10Khz unit */
- USHORT usMaxPixelClockPLL_Input; /* In 10Khz unit */
- USHORT usMinPixelClockPLL_Output; /* In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output */
- ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
- USHORT usReferenceClock; /* In 10Khz unit */
- USHORT usPM_RTS_Location; /* RTS PM4 starting location in ROM in 1Kb unit */
- UCHAR ucPM_RTS_StreamSize; /* RTS PM4 packets in Kb unit */
- UCHAR ucDesign_ID; /* Indicate what is the board design */
- UCHAR ucMemoryModule_ID; /* Indicate what is the board design */
-} ATOM_FIRMWARE_INFO_V1_3;
-
-typedef struct _ATOM_FIRMWARE_INFO_V1_4 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ULONG ulFirmwareRevision;
- ULONG ulDefaultEngineClock; /* In 10Khz unit */
- ULONG ulDefaultMemoryClock; /* In 10Khz unit */
- ULONG ulDriverTargetEngineClock; /* In 10Khz unit */
- ULONG ulDriverTargetMemoryClock; /* In 10Khz unit */
- ULONG ulMaxEngineClockPLL_Output; /* In 10Khz unit */
- ULONG ulMaxMemoryClockPLL_Output; /* In 10Khz unit */
- ULONG ulMaxPixelClockPLL_Output; /* In 10Khz unit */
- ULONG ulASICMaxEngineClock; /* In 10Khz unit */
- ULONG ulASICMaxMemoryClock; /* In 10Khz unit */
- UCHAR ucASICMaxTemperature;
- UCHAR ucMinAllowedBL_Level;
- USHORT usBootUpVDDCVoltage; /* In MV unit */
- USHORT usLcdMinPixelClockPLL_Output; /* In MHz unit */
- USHORT usLcdMaxPixelClockPLL_Output; /* In MHz unit */
- ULONG ul3DAccelerationEngineClock; /* In 10Khz unit */
- ULONG ulMinPixelClockPLL_Output; /* In 10Khz unit */
- USHORT usMinEngineClockPLL_Input; /* In 10Khz unit */
- USHORT usMaxEngineClockPLL_Input; /* In 10Khz unit */
- USHORT usMinEngineClockPLL_Output; /* In 10Khz unit */
- USHORT usMinMemoryClockPLL_Input; /* In 10Khz unit */
- USHORT usMaxMemoryClockPLL_Input; /* In 10Khz unit */
- USHORT usMinMemoryClockPLL_Output; /* In 10Khz unit */
- USHORT usMaxPixelClock; /* In 10Khz unit, Max. Pclk */
- USHORT usMinPixelClockPLL_Input; /* In 10Khz unit */
- USHORT usMaxPixelClockPLL_Input; /* In 10Khz unit */
- USHORT usMinPixelClockPLL_Output; /* In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output */
- ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
- USHORT usReferenceClock; /* In 10Khz unit */
- USHORT usPM_RTS_Location; /* RTS PM4 starting location in ROM in 1Kb unit */
- UCHAR ucPM_RTS_StreamSize; /* RTS PM4 packets in Kb unit */
- UCHAR ucDesign_ID; /* Indicate what is the board design */
- UCHAR ucMemoryModule_ID; /* Indicate what is the board design */
-} ATOM_FIRMWARE_INFO_V1_4;
-
-#define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V1_4
-
-/****************************************************************************/
-/* Structures used in IntegratedSystemInfoTable */
-/****************************************************************************/
+typedef struct _ATOM_FIRMWARE_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulFirmwareRevision;
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+ ULONG ulDriverTargetEngineClock; //In 10Khz unit
+ ULONG ulDriverTargetMemoryClock; //In 10Khz unit
+ ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit
+ ULONG ulASICMaxEngineClock; //In 10Khz unit
+ ULONG ulASICMaxMemoryClock; //In 10Khz unit
+ UCHAR ucASICMaxTemperature;
+ UCHAR ucPadding[3]; //Don't use them
+ ULONG aulReservedForBIOS[3]; //Don't use them
+ USHORT usMinEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMaxEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Output; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Output; //In 10Khz unit
+ USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk
+ USHORT usMinPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMaxPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMinPixelClockPLL_Output; //In 10Khz unit, the definitions above can't change!!!
+ ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+ USHORT usReferenceClock; //In 10Khz unit
+ USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit
+ UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit
+ UCHAR ucDesign_ID; //Indicate what is the board design
+ UCHAR ucMemoryModule_ID; //Indicate what is the board design
+}ATOM_FIRMWARE_INFO;
+
+typedef struct _ATOM_FIRMWARE_INFO_V1_2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulFirmwareRevision;
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+ ULONG ulDriverTargetEngineClock; //In 10Khz unit
+ ULONG ulDriverTargetMemoryClock; //In 10Khz unit
+ ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit
+ ULONG ulASICMaxEngineClock; //In 10Khz unit
+ ULONG ulASICMaxMemoryClock; //In 10Khz unit
+ UCHAR ucASICMaxTemperature;
+ UCHAR ucMinAllowedBL_Level;
+ UCHAR ucPadding[2]; //Don't use them
+ ULONG aulReservedForBIOS[2]; //Don't use them
+ ULONG ulMinPixelClockPLL_Output; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMaxEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Output; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Output; //In 10Khz unit
+ USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk
+ USHORT usMinPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMaxPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output
+ ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+ USHORT usReferenceClock; //In 10Khz unit
+ USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit
+ UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit
+ UCHAR ucDesign_ID; //Indicate what is the board design
+ UCHAR ucMemoryModule_ID; //Indicate what is the board design
+}ATOM_FIRMWARE_INFO_V1_2;
+
+typedef struct _ATOM_FIRMWARE_INFO_V1_3
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulFirmwareRevision;
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+ ULONG ulDriverTargetEngineClock; //In 10Khz unit
+ ULONG ulDriverTargetMemoryClock; //In 10Khz unit
+ ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit
+ ULONG ulASICMaxEngineClock; //In 10Khz unit
+ ULONG ulASICMaxMemoryClock; //In 10Khz unit
+ UCHAR ucASICMaxTemperature;
+ UCHAR ucMinAllowedBL_Level;
+ UCHAR ucPadding[2]; //Don't use them
+ ULONG aulReservedForBIOS; //Don't use them
+ ULONG ul3DAccelerationEngineClock;//In 10Khz unit
+ ULONG ulMinPixelClockPLL_Output; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMaxEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Output; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Output; //In 10Khz unit
+ USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk
+ USHORT usMinPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMaxPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output
+ ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+ USHORT usReferenceClock; //In 10Khz unit
+ USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit
+ UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit
+ UCHAR ucDesign_ID; //Indicate what is the board design
+ UCHAR ucMemoryModule_ID; //Indicate what is the board design
+}ATOM_FIRMWARE_INFO_V1_3;
+
+typedef struct _ATOM_FIRMWARE_INFO_V1_4
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulFirmwareRevision;
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+ ULONG ulDriverTargetEngineClock; //In 10Khz unit
+ ULONG ulDriverTargetMemoryClock; //In 10Khz unit
+ ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit
+ ULONG ulASICMaxEngineClock; //In 10Khz unit
+ ULONG ulASICMaxMemoryClock; //In 10Khz unit
+ UCHAR ucASICMaxTemperature;
+ UCHAR ucMinAllowedBL_Level;
+ USHORT usBootUpVDDCVoltage; //In MV unit
+ USHORT usLcdMinPixelClockPLL_Output; // In MHz unit
+ USHORT usLcdMaxPixelClockPLL_Output; // In MHz unit
+ ULONG ul3DAccelerationEngineClock;//In 10Khz unit
+ ULONG ulMinPixelClockPLL_Output; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMaxEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Output; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Output; //In 10Khz unit
+ USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk
+ USHORT usMinPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMaxPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output
+ ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+ USHORT usReferenceClock; //In 10Khz unit
+ USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit
+ UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit
+ UCHAR ucDesign_ID; //Indicate what is the board design
+ UCHAR ucMemoryModule_ID; //Indicate what is the board design
+}ATOM_FIRMWARE_INFO_V1_4;
+
+//the structure below to be used from Cypress
+typedef struct _ATOM_FIRMWARE_INFO_V2_1
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulFirmwareRevision;
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+ ULONG ulReserved1;
+ ULONG ulReserved2;
+ ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit
+ ULONG ulBinaryAlteredInfo; //Was ulASICMaxEngineClock
+ ULONG ulDefaultDispEngineClkFreq; //In 10Khz unit
+ UCHAR ucReserved1; //Was ucASICMaxTemperature;
+ UCHAR ucMinAllowedBL_Level;
+ USHORT usBootUpVDDCVoltage; //In MV unit
+ USHORT usLcdMinPixelClockPLL_Output; // In MHz unit
+ USHORT usLcdMaxPixelClockPLL_Output; // In MHz unit
+ ULONG ulReserved4; //Was ulAsicMaximumVoltage
+ ULONG ulMinPixelClockPLL_Output; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMaxEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Output; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Output; //In 10Khz unit
+ USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk
+ USHORT usMinPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMaxPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output
+ ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+ USHORT usCoreReferenceClock; //In 10Khz unit
+ USHORT usMemoryReferenceClock; //In 10Khz unit
+ USHORT usUniphyDPModeExtClkFreq; //In 10Khz unit, if it is 0, In DP Mode Uniphy Input clock from internal PPLL, otherwise Input clock from external Spread clock
+ UCHAR ucMemoryModule_ID; //Indicate what is the board design
+ UCHAR ucReserved4[3];
+}ATOM_FIRMWARE_INFO_V2_1;
+
+
+#define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V2_1
+
+/****************************************************************************/
+// Structures used in IntegratedSystemInfoTable
+/****************************************************************************/
#define IGP_CAP_FLAG_DYNAMIC_CLOCK_EN 0x2
#define IGP_CAP_FLAG_AC_CARD 0x4
#define IGP_CAP_FLAG_SDVO_CARD 0x8
#define IGP_CAP_FLAG_POSTDIV_BY_2_MODE 0x10
-typedef struct _ATOM_INTEGRATED_SYSTEM_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ULONG ulBootUpEngineClock; /* in 10kHz unit */
- ULONG ulBootUpMemoryClock; /* in 10kHz unit */
- ULONG ulMaxSystemMemoryClock; /* in 10kHz unit */
- ULONG ulMinSystemMemoryClock; /* in 10kHz unit */
- UCHAR ucNumberOfCyclesInPeriodHi;
- UCHAR ucLCDTimingSel; /* =0:not valid.!=0 sel this timing descriptor from LCD EDID. */
- USHORT usReserved1;
- USHORT usInterNBVoltageLow; /* An intermidiate PMW value to set the voltage */
- USHORT usInterNBVoltageHigh; /* Another intermidiate PMW value to set the voltage */
- ULONG ulReserved[2];
-
- USHORT usFSBClock; /* In MHz unit */
- USHORT usCapabilityFlag; /* Bit0=1 indicates the fake HDMI support,Bit1=0/1 for Dynamic clocking dis/enable */
- /* Bit[3:2]== 0:No PCIE card, 1:AC card, 2:SDVO card */
- /* Bit[4]==1: P/2 mode, ==0: P/1 mode */
- USHORT usPCIENBCfgReg7; /* bit[7:0]=MUX_Sel, bit[9:8]=MUX_SEL_LEVEL2, bit[10]=Lane_Reversal */
- USHORT usK8MemoryClock; /* in MHz unit */
- USHORT usK8SyncStartDelay; /* in 0.01 us unit */
- USHORT usK8DataReturnTime; /* in 0.01 us unit */
- UCHAR ucMaxNBVoltage;
- UCHAR ucMinNBVoltage;
- UCHAR ucMemoryType; /* [7:4]=1:DDR1;=2:DDR2;=3:DDR3.[3:0] is reserved */
- UCHAR ucNumberOfCyclesInPeriod; /* CG.FVTHROT_PWM_CTRL_REG0.NumberOfCyclesInPeriod */
- UCHAR ucStartingPWM_HighTime; /* CG.FVTHROT_PWM_CTRL_REG0.StartingPWM_HighTime */
- UCHAR ucHTLinkWidth; /* 16 bit vs. 8 bit */
- UCHAR ucMaxNBVoltageHigh;
- UCHAR ucMinNBVoltageHigh;
-} ATOM_INTEGRATED_SYSTEM_INFO;
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulBootUpEngineClock; //in 10kHz unit
+ ULONG ulBootUpMemoryClock; //in 10kHz unit
+ ULONG ulMaxSystemMemoryClock; //in 10kHz unit
+ ULONG ulMinSystemMemoryClock; //in 10kHz unit
+ UCHAR ucNumberOfCyclesInPeriodHi;
+ UCHAR ucLCDTimingSel; //=0:not valid.!=0 sel this timing descriptor from LCD EDID.
+ USHORT usReserved1;
+ USHORT usInterNBVoltageLow; //An intermidiate PMW value to set the voltage
+ USHORT usInterNBVoltageHigh; //Another intermidiate PMW value to set the voltage
+ ULONG ulReserved[2];
+
+ USHORT usFSBClock; //In MHz unit
+ USHORT usCapabilityFlag; //Bit0=1 indicates the fake HDMI support,Bit1=0/1 for Dynamic clocking dis/enable
+ //Bit[3:2]== 0:No PCIE card, 1:AC card, 2:SDVO card
+ //Bit[4]==1: P/2 mode, ==0: P/1 mode
+ USHORT usPCIENBCfgReg7; //bit[7:0]=MUX_Sel, bit[9:8]=MUX_SEL_LEVEL2, bit[10]=Lane_Reversal
+ USHORT usK8MemoryClock; //in MHz unit
+ USHORT usK8SyncStartDelay; //in 0.01 us unit
+ USHORT usK8DataReturnTime; //in 0.01 us unit
+ UCHAR ucMaxNBVoltage;
+ UCHAR ucMinNBVoltage;
+ UCHAR ucMemoryType; //[7:4]=1:DDR1;=2:DDR2;=3:DDR3.[3:0] is reserved
+ UCHAR ucNumberOfCyclesInPeriod; //CG.FVTHROT_PWM_CTRL_REG0.NumberOfCyclesInPeriod
+ UCHAR ucStartingPWM_HighTime; //CG.FVTHROT_PWM_CTRL_REG0.StartingPWM_HighTime
+ UCHAR ucHTLinkWidth; //16 bit vs. 8 bit
+ UCHAR ucMaxNBVoltageHigh;
+ UCHAR ucMinNBVoltageHigh;
+}ATOM_INTEGRATED_SYSTEM_INFO;
/* Explanation on entries in ATOM_INTEGRATED_SYSTEM_INFO
-ulBootUpMemoryClock: For Intel IGP,it's the UMA system memory clock
+ulBootUpMemoryClock: For Intel IGP,it's the UMA system memory clock
For AMD IGP,it's 0 if no SidePort memory installed or it's the boot-up SidePort memory clock
ulMaxSystemMemoryClock: For Intel IGP,it's the Max freq from memory SPD if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0
For AMD IGP,for now this can be 0
-ulMinSystemMemoryClock: For Intel IGP,it's 133MHz if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0
+ulMinSystemMemoryClock: For Intel IGP,it's 133MHz if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0
For AMD IGP,for now this can be 0
-usFSBClock: For Intel IGP,it's FSB Freq
+usFSBClock: For Intel IGP,it's FSB Freq
For AMD IGP,it's HT Link Speed
usK8MemoryClock: For AMD IGP only. For RevF CPU, set it to 200
@@ -1687,98 +2093,113 @@ VC:Voltage Control
ucMaxNBVoltage: Voltage regulator dependent PWM value. Low 8 bits of the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all.
ucMinNBVoltage: Voltage regulator dependent PWM value. Low 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all.
-ucNumberOfCyclesInPeriod: Indicate how many cycles when PWM duty is 100%. low 8 bits of the value.
-ucNumberOfCyclesInPeriodHi: Indicate how many cycles when PWM duty is 100%. high 8 bits of the value.If the PWM has an inverter,set bit [7]==1,otherwise set it 0
+ucNumberOfCyclesInPeriod: Indicate how many cycles when PWM duty is 100%. low 8 bits of the value.
+ucNumberOfCyclesInPeriodHi: Indicate how many cycles when PWM duty is 100%. high 8 bits of the value.If the PWM has an inverter,set bit [7]==1,otherwise set it 0
ucMaxNBVoltageHigh: Voltage regulator dependent PWM value. High 8 bits of the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all.
ucMinNBVoltageHigh: Voltage regulator dependent PWM value. High 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all.
+
usInterNBVoltageLow: Voltage regulator dependent PWM value. The value makes the the voltage >=Min NB voltage but <=InterNBVoltageHigh. Set this to 0x0000 if VC without PWM or no VC at all.
usInterNBVoltageHigh: Voltage regulator dependent PWM value. The value makes the the voltage >=InterNBVoltageLow but <=Max NB voltage.Set this to 0x0000 if VC without PWM or no VC at all.
*/
+
/*
The following IGP table is introduced from RS780, which is supposed to be put by SBIOS in FB before IGP VBIOS starts VPOST;
-Then VBIOS will copy the whole structure to its image so all GPU SW components can access this data structure to get whatever they need.
+Then VBIOS will copy the whole structure to its image so all GPU SW components can access this data structure to get whatever they need.
The enough reservation should allow us to never change table revisions. Whenever needed, a GPU SW component can use reserved portion for new data entries.
SW components can access the IGP system infor structure in the same way as before
*/
-typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ULONG ulBootUpEngineClock; /* in 10kHz unit */
- ULONG ulReserved1[2]; /* must be 0x0 for the reserved */
- ULONG ulBootUpUMAClock; /* in 10kHz unit */
- ULONG ulBootUpSidePortClock; /* in 10kHz unit */
- ULONG ulMinSidePortClock; /* in 10kHz unit */
- ULONG ulReserved2[6]; /* must be 0x0 for the reserved */
- ULONG ulSystemConfig; /* see explanation below */
- ULONG ulBootUpReqDisplayVector;
- ULONG ulOtherDisplayMisc;
- ULONG ulDDISlot1Config;
- ULONG ulDDISlot2Config;
- UCHAR ucMemoryType; /* [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved */
- UCHAR ucUMAChannelNumber;
- UCHAR ucDockingPinBit;
- UCHAR ucDockingPinPolarity;
- ULONG ulDockingPinCFGInfo;
- ULONG ulCPUCapInfo;
- USHORT usNumberOfCyclesInPeriod;
- USHORT usMaxNBVoltage;
- USHORT usMinNBVoltage;
- USHORT usBootUpNBVoltage;
- ULONG ulHTLinkFreq; /* in 10Khz */
- USHORT usMinHTLinkWidth;
- USHORT usMaxHTLinkWidth;
- USHORT usUMASyncStartDelay;
- USHORT usUMADataReturnTime;
- USHORT usLinkStatusZeroTime;
- USHORT usReserved;
- ULONG ulHighVoltageHTLinkFreq; /* in 10Khz */
- ULONG ulLowVoltageHTLinkFreq; /* in 10Khz */
- USHORT usMaxUpStreamHTLinkWidth;
- USHORT usMaxDownStreamHTLinkWidth;
- USHORT usMinUpStreamHTLinkWidth;
- USHORT usMinDownStreamHTLinkWidth;
- ULONG ulReserved3[97]; /* must be 0x0 */
-} ATOM_INTEGRATED_SYSTEM_INFO_V2;
+
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulBootUpEngineClock; //in 10kHz unit
+ ULONG ulReserved1[2]; //must be 0x0 for the reserved
+ ULONG ulBootUpUMAClock; //in 10kHz unit
+ ULONG ulBootUpSidePortClock; //in 10kHz unit
+ ULONG ulMinSidePortClock; //in 10kHz unit
+ ULONG ulReserved2[6]; //must be 0x0 for the reserved
+ ULONG ulSystemConfig; //see explanation below
+ ULONG ulBootUpReqDisplayVector;
+ ULONG ulOtherDisplayMisc;
+ ULONG ulDDISlot1Config;
+ ULONG ulDDISlot2Config;
+ UCHAR ucMemoryType; //[3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved
+ UCHAR ucUMAChannelNumber;
+ UCHAR ucDockingPinBit;
+ UCHAR ucDockingPinPolarity;
+ ULONG ulDockingPinCFGInfo;
+ ULONG ulCPUCapInfo;
+ USHORT usNumberOfCyclesInPeriod;
+ USHORT usMaxNBVoltage;
+ USHORT usMinNBVoltage;
+ USHORT usBootUpNBVoltage;
+ ULONG ulHTLinkFreq; //in 10Khz
+ USHORT usMinHTLinkWidth;
+ USHORT usMaxHTLinkWidth;
+ USHORT usUMASyncStartDelay;
+ USHORT usUMADataReturnTime;
+ USHORT usLinkStatusZeroTime;
+ USHORT usDACEfuse; //for storing badgap value (for RS880 only)
+ ULONG ulHighVoltageHTLinkFreq; // in 10Khz
+ ULONG ulLowVoltageHTLinkFreq; // in 10Khz
+ USHORT usMaxUpStreamHTLinkWidth;
+ USHORT usMaxDownStreamHTLinkWidth;
+ USHORT usMinUpStreamHTLinkWidth;
+ USHORT usMinDownStreamHTLinkWidth;
+ USHORT usFirmwareVersion; //0 means FW is not supported. Otherwise it's the FW version loaded by SBIOS and driver should enable FW.
+ USHORT usFullT0Time; // Input to calculate minimum HT link change time required by NB P-State. Unit is 0.01us.
+ ULONG ulReserved3[96]; //must be 0x0
+}ATOM_INTEGRATED_SYSTEM_INFO_V2;
/*
ulBootUpEngineClock: Boot-up Engine Clock in 10Khz;
ulBootUpUMAClock: Boot-up UMA Clock in 10Khz; it must be 0x0 when UMA is not present
ulBootUpSidePortClock: Boot-up SidePort Clock in 10Khz; it must be 0x0 when SidePort Memory is not present,this could be equal to or less than maximum supported Sideport memory clock
-ulSystemConfig:
-Bit[0]=1: PowerExpress mode =0 Non-PowerExpress mode;
+ulSystemConfig:
+Bit[0]=1: PowerExpress mode =0 Non-PowerExpress mode;
Bit[1]=1: system boots up at AMD overdrived state or user customized mode. In this case, driver will just stick to this boot-up mode. No other PowerPlay state
=0: system boots up at driver control state. Power state depends on PowerPlay table.
Bit[2]=1: PWM method is used on NB voltage control. =0: GPIO method is used.
Bit[3]=1: Only one power state(Performance) will be supported.
=0: Multiple power states supported from PowerPlay table.
-Bit[4]=1: CLMC is supported and enabled on current system.
- =0: CLMC is not supported or enabled on current system. SBIOS need to support HT link/freq change through ATIF interface.
-Bit[5]=1: Enable CDLW for all driver control power states. Max HT width is from SBIOS, while Min HT width is determined by display requirement.
+Bit[4]=1: CLMC is supported and enabled on current system.
+ =0: CLMC is not supported or enabled on current system. SBIOS need to support HT link/freq change through ATIF interface.
+Bit[5]=1: Enable CDLW for all driver control power states. Max HT width is from SBIOS, while Min HT width is determined by display requirement.
=0: CDLW is disabled. If CLMC is enabled case, Min HT width will be set equal to Max HT width. If CLMC disabled case, Max HT width will be applied.
Bit[6]=1: High Voltage requested for all power states. In this case, voltage will be forced at 1.1v and powerplay table voltage drop/throttling request will be ignored.
=0: Voltage settings is determined by powerplay table.
Bit[7]=1: Enable CLMC as hybrid Mode. CDLD and CILR will be disabled in this case and we're using legacy C1E. This is workaround for CPU(Griffin) performance issue.
=0: Enable CLMC as regular mode, CDLD and CILR will be enabled.
+Bit[8]=1: CDLF is supported and enabled on current system.
+ =0: CDLF is not supported or enabled on current system.
+Bit[9]=1: DLL Shut Down feature is enabled on current system.
+ =0: DLL Shut Down feature is not enabled or supported on current system.
ulBootUpReqDisplayVector: This dword is a bit vector indicates what display devices are requested during boot-up. Refer to ATOM_DEVICE_xxx_SUPPORT for the bit vector definitions.
ulOtherDisplayMisc: [15:8]- Bootup LCD Expansion selection; 0-center, 1-full panel size expansion;
- [7:0] - BootupTV standard selection; This is a bit vector to indicate what TV standards are supported by the system. Refer to ucTVSuppportedStd definition;
+ [7:0] - BootupTV standard selection; This is a bit vector to indicate what TV standards are supported by the system. Refer to ucTVSupportedStd definition;
ulDDISlot1Config: Describes the PCIE lane configuration on this DDI PCIE slot (ADD2 card) or connector (Mobile design).
[3:0] - Bit vector to indicate PCIE lane config of the DDI slot/connector on chassis (bit 0=1 lane 3:0; bit 1=1 lane 7:4; bit 2=1 lane 11:8; bit 3=1 lane 15:12)
- [7:4] - Bit vector to indicate PCIE lane config of the same DDI slot/connector on docking station (bit 0=1 lane 3:0; bit 1=1 lane 7:4; bit 2=1 lane 11:8; bit 3=1 lane 15:12)
- [15:8] - Lane configuration attribute;
+ [7:4] - Bit vector to indicate PCIE lane config of the same DDI slot/connector on docking station (bit 4=1 lane 3:0; bit 5=1 lane 7:4; bit 6=1 lane 11:8; bit 7=1 lane 15:12)
+ When a DDI connector is not "paired" (meaming two connections mutualexclusive on chassis or docking, only one of them can be connected at one time.
+ in both chassis and docking, SBIOS has to duplicate the same PCIE lane info from chassis to docking or vice versa. For example:
+ one DDI connector is only populated in docking with PCIE lane 8-11, but there is no paired connection on chassis, SBIOS has to copy bit 6 to bit 2.
+
+ [15:8] - Lane configuration attribute;
[23:16]- Connector type, possible value:
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D
CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D
CONNECTOR_OBJECT_ID_HDMI_TYPE_A
CONNECTOR_OBJECT_ID_DISPLAYPORT
+ CONNECTOR_OBJECT_ID_eDP
[31:24]- Reserved
ulDDISlot2Config: Same as Slot1.
@@ -1787,29 +2208,31 @@ For IGP, Hypermemory is the only memory type showed in CCC.
ucUMAChannelNumber: how many channels for the UMA;
-ulDockingPinCFGInfo: [15:0]-Bus/Device/Function # to CFG to read this Docking Pin; [31:16]-reg offset in CFG to read this pin
+ulDockingPinCFGInfo: [15:0]-Bus/Device/Function # to CFG to read this Docking Pin; [31:16]-reg offset in CFG to read this pin
ucDockingPinBit: which bit in this register to read the pin status;
ucDockingPinPolarity:Polarity of the pin when docked;
ulCPUCapInfo: [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, other bits reserved for now and must be 0x0
usNumberOfCyclesInPeriod:Indicate how many cycles when PWM duty is 100%.
-usMaxNBVoltage:Max. voltage control value in either PWM or GPIO mode.
+
+usMaxNBVoltage:Max. voltage control value in either PWM or GPIO mode.
usMinNBVoltage:Min. voltage control value in either PWM or GPIO mode.
GPIO mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=0
PWM mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=1
GPU SW don't control mode: usMaxNBVoltage & usMinNBVoltage=0 and no care about ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE
+
usBootUpNBVoltage:Boot-up voltage regulator dependent PWM value.
ulHTLinkFreq: Bootup HT link Frequency in 10Khz.
-usMinHTLinkWidth: Bootup minimum HT link width. If CDLW disabled, this is equal to usMaxHTLinkWidth.
- If CDLW enabled, both upstream and downstream width should be the same during bootup.
-usMaxHTLinkWidth: Bootup maximum HT link width. If CDLW disabled, this is equal to usMinHTLinkWidth.
+usMinHTLinkWidth: Bootup minimum HT link width. If CDLW disabled, this is equal to usMaxHTLinkWidth.
If CDLW enabled, both upstream and downstream width should be the same during bootup.
+usMaxHTLinkWidth: Bootup maximum HT link width. If CDLW disabled, this is equal to usMinHTLinkWidth.
+ If CDLW enabled, both upstream and downstream width should be the same during bootup.
-usUMASyncStartDelay: Memory access latency, required for watermark calculation
+usUMASyncStartDelay: Memory access latency, required for watermark calculation
usUMADataReturnTime: Memory access latency, required for watermark calculation
-usLinkStatusZeroTime:Memory access latency required for watermark calculation, set this to 0x0 for K8 CPU, set a proper value in 0.01 the unit of us
+usLinkStatusZeroTime:Memory access latency required for watermark calculation, set this to 0x0 for K8 CPU, set a proper value in 0.01 the unit of us
for Griffin or Greyhound. SBIOS needs to convert to actual time by:
if T0Ttime [5:4]=00b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.1us (0.0 to 1.5us)
if T0Ttime [5:4]=01b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.5us (0.0 to 7.5us)
@@ -1817,7 +2240,7 @@ for Griffin or Greyhound. SBIOS needs to convert to actual time by:
if T0Ttime [5:4]=11b, and T0Ttime [3:0]=0x0 to 0xa, then usLinkStatusZeroTime=T0Ttime [3:0]*20us (0.0 to 200us)
ulHighVoltageHTLinkFreq: HT link frequency for power state with low voltage. If boot up runs in HT1, this must be 0.
- This must be less than or equal to ulHTLinkFreq(bootup frequency).
+ This must be less than or equal to ulHTLinkFreq(bootup frequency).
ulLowVoltageHTLinkFreq: HT link frequency for power state with low voltage or voltage scaling 1.0v~1.1v. If boot up runs in HT1, this must be 0.
This must be less than or equal to ulHighVoltageHTLinkFreq.
@@ -1827,14 +2250,17 @@ usMinUpStreamHTLinkWidth: Asymmetric link width support in the future, to rep
usMinDownStreamHTLinkWidth: same as above.
*/
+
#define SYSTEM_CONFIG_POWEREXPRESS_ENABLE 0x00000001
#define SYSTEM_CONFIG_RUN_AT_OVERDRIVE_ENGINE 0x00000002
-#define SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE 0x00000004
+#define SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE 0x00000004
#define SYSTEM_CONFIG_PERFORMANCE_POWERSTATE_ONLY 0x00000008
#define SYSTEM_CONFIG_CLMC_ENABLED 0x00000010
#define SYSTEM_CONFIG_CDLW_ENABLED 0x00000020
#define SYSTEM_CONFIG_HIGH_VOLTAGE_REQUESTED 0x00000040
#define SYSTEM_CONFIG_CLMC_HYBRID_MODE_ENABLED 0x00000080
+#define SYSTEM_CONFIG_CDLF_ENABLED 0x00000100
+#define SYSTEM_CONFIG_DLL_SHUTDOWN_ENABLED 0x00000200
#define IGP_DDI_SLOT_LANE_CONFIG_MASK 0x000000FF
@@ -1851,6 +2277,41 @@ usMinDownStreamHTLinkWidth: same as above.
#define IGP_DDI_SLOT_CONNECTOR_TYPE_MASK 0x00FF0000
+// IntegratedSystemInfoTable new Rev is V5 after V2, because of the real rev of V2 is v1.4. This rev is used for RR
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V5
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulBootUpEngineClock; //in 10kHz unit
+ ULONG ulDentistVCOFreq; //Dentist VCO clock in 10kHz unit, the source of GPU SCLK, LCLK, UCLK and VCLK.
+ ULONG ulLClockFreq; //GPU Lclk freq in 10kHz unit, have relationship with NCLK in NorthBridge
+ ULONG ulBootUpUMAClock; //in 10kHz unit
+ ULONG ulReserved1[8]; //must be 0x0 for the reserved
+ ULONG ulBootUpReqDisplayVector;
+ ULONG ulOtherDisplayMisc;
+ ULONG ulReserved2[4]; //must be 0x0 for the reserved
+ ULONG ulSystemConfig; //TBD
+ ULONG ulCPUCapInfo; //TBD
+ USHORT usMaxNBVoltage; //high NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse;
+ USHORT usMinNBVoltage; //low NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse;
+ USHORT usBootUpNBVoltage; //boot up NB voltage
+ UCHAR ucHtcTmpLmt; //bit [22:16] of D24F3x64 Hardware Thermal Control (HTC) Register, may not be needed, TBD
+ UCHAR ucTjOffset; //bit [28:22] of D24F3xE4 Thermtrip Status Register,may not be needed, TBD
+ ULONG ulReserved3[4]; //must be 0x0 for the reserved
+ ULONG ulDDISlot1Config; //see above ulDDISlot1Config definition
+ ULONG ulDDISlot2Config;
+ ULONG ulDDISlot3Config;
+ ULONG ulDDISlot4Config;
+ ULONG ulReserved4[4]; //must be 0x0 for the reserved
+ UCHAR ucMemoryType; //[3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved
+ UCHAR ucUMAChannelNumber;
+ USHORT usReserved;
+ ULONG ulReserved5[4]; //must be 0x0 for the reserved
+ ULONG ulCSR_M3_ARB_CNTL_DEFAULT[10];//arrays with values for CSR M3 arbiter for default
+ ULONG ulCSR_M3_ARB_CNTL_UVD[10]; //arrays with values for CSR M3 arbiter for UVD playback
+ ULONG ulCSR_M3_ARB_CNTL_FS3D[10];//arrays with values for CSR M3 arbiter for Full Screen 3D applications
+ ULONG ulReserved6[61]; //must be 0x0
+}ATOM_INTEGRATED_SYSTEM_INFO_V5;
+
#define ATOM_CRT_INT_ENCODER1_INDEX 0x00000000
#define ATOM_LCD_INT_ENCODER1_INDEX 0x00000001
#define ATOM_TV_INT_ENCODER1_INDEX 0x00000002
@@ -1866,8 +2327,8 @@ usMinDownStreamHTLinkWidth: same as above.
#define ATOM_DFP_INT_ENCODER3_INDEX 0x0000000C
#define ATOM_DFP_INT_ENCODER4_INDEX 0x0000000D
-/* define ASIC internal encoder id ( bit vector ) */
-#define ASIC_INT_DAC1_ENCODER_ID 0x00
+// define ASIC internal encoder id ( bit vector ), used for CRTC_SourceSelTable
+#define ASIC_INT_DAC1_ENCODER_ID 0x00
#define ASIC_INT_TV_ENCODER_ID 0x02
#define ASIC_INT_DIG1_ENCODER_ID 0x03
#define ASIC_INT_DAC2_ENCODER_ID 0x04
@@ -1875,10 +2336,24 @@ usMinDownStreamHTLinkWidth: same as above.
#define ASIC_INT_DVO_ENCODER_ID 0x07
#define ASIC_INT_DIG2_ENCODER_ID 0x09
#define ASIC_EXT_DIG_ENCODER_ID 0x05
+#define ASIC_EXT_DIG2_ENCODER_ID 0x08
+#define ASIC_INT_DIG3_ENCODER_ID 0x0a
+#define ASIC_INT_DIG4_ENCODER_ID 0x0b
+#define ASIC_INT_DIG5_ENCODER_ID 0x0c
+#define ASIC_INT_DIG6_ENCODER_ID 0x0d
-/* define Encoder attribute */
+//define Encoder attribute
#define ATOM_ANALOG_ENCODER 0
-#define ATOM_DIGITAL_ENCODER 1
+#define ATOM_DIGITAL_ENCODER 1
+#define ATOM_DP_ENCODER 2
+
+#define ATOM_ENCODER_ENUM_MASK 0x70
+#define ATOM_ENCODER_ENUM_ID1 0x00
+#define ATOM_ENCODER_ENUM_ID2 0x10
+#define ATOM_ENCODER_ENUM_ID3 0x20
+#define ATOM_ENCODER_ENUM_ID4 0x30
+#define ATOM_ENCODER_ENUM_ID5 0x40
+#define ATOM_ENCODER_ENUM_ID6 0x50
#define ATOM_DEVICE_CRT1_INDEX 0x00000000
#define ATOM_DEVICE_LCD1_INDEX 0x00000001
@@ -1886,45 +2361,40 @@ usMinDownStreamHTLinkWidth: same as above.
#define ATOM_DEVICE_DFP1_INDEX 0x00000003
#define ATOM_DEVICE_CRT2_INDEX 0x00000004
#define ATOM_DEVICE_LCD2_INDEX 0x00000005
-#define ATOM_DEVICE_TV2_INDEX 0x00000006
+#define ATOM_DEVICE_DFP6_INDEX 0x00000006
#define ATOM_DEVICE_DFP2_INDEX 0x00000007
#define ATOM_DEVICE_CV_INDEX 0x00000008
-#define ATOM_DEVICE_DFP3_INDEX 0x00000009
-#define ATOM_DEVICE_DFP4_INDEX 0x0000000A
-#define ATOM_DEVICE_DFP5_INDEX 0x0000000B
+#define ATOM_DEVICE_DFP3_INDEX 0x00000009
+#define ATOM_DEVICE_DFP4_INDEX 0x0000000A
+#define ATOM_DEVICE_DFP5_INDEX 0x0000000B
+
#define ATOM_DEVICE_RESERVEDC_INDEX 0x0000000C
#define ATOM_DEVICE_RESERVEDD_INDEX 0x0000000D
#define ATOM_DEVICE_RESERVEDE_INDEX 0x0000000E
#define ATOM_DEVICE_RESERVEDF_INDEX 0x0000000F
#define ATOM_MAX_SUPPORTED_DEVICE_INFO (ATOM_DEVICE_DFP3_INDEX+1)
#define ATOM_MAX_SUPPORTED_DEVICE_INFO_2 ATOM_MAX_SUPPORTED_DEVICE_INFO
-#define ATOM_MAX_SUPPORTED_DEVICE_INFO_3 (ATOM_DEVICE_DFP5_INDEX + 1)
+#define ATOM_MAX_SUPPORTED_DEVICE_INFO_3 (ATOM_DEVICE_DFP5_INDEX + 1 )
#define ATOM_MAX_SUPPORTED_DEVICE (ATOM_DEVICE_RESERVEDF_INDEX+1)
-#define ATOM_DEVICE_CRT1_SUPPORT (0x1L << ATOM_DEVICE_CRT1_INDEX)
-#define ATOM_DEVICE_LCD1_SUPPORT (0x1L << ATOM_DEVICE_LCD1_INDEX)
-#define ATOM_DEVICE_TV1_SUPPORT (0x1L << ATOM_DEVICE_TV1_INDEX)
-#define ATOM_DEVICE_DFP1_SUPPORT (0x1L << ATOM_DEVICE_DFP1_INDEX)
-#define ATOM_DEVICE_CRT2_SUPPORT (0x1L << ATOM_DEVICE_CRT2_INDEX)
-#define ATOM_DEVICE_LCD2_SUPPORT (0x1L << ATOM_DEVICE_LCD2_INDEX)
-#define ATOM_DEVICE_TV2_SUPPORT (0x1L << ATOM_DEVICE_TV2_INDEX)
-#define ATOM_DEVICE_DFP2_SUPPORT (0x1L << ATOM_DEVICE_DFP2_INDEX)
-#define ATOM_DEVICE_CV_SUPPORT (0x1L << ATOM_DEVICE_CV_INDEX)
-#define ATOM_DEVICE_DFP3_SUPPORT (0x1L << ATOM_DEVICE_DFP3_INDEX)
-#define ATOM_DEVICE_DFP4_SUPPORT (0x1L << ATOM_DEVICE_DFP4_INDEX )
-#define ATOM_DEVICE_DFP5_SUPPORT (0x1L << ATOM_DEVICE_DFP5_INDEX)
-
-#define ATOM_DEVICE_CRT_SUPPORT \
- (ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_CRT2_SUPPORT)
-#define ATOM_DEVICE_DFP_SUPPORT \
- (ATOM_DEVICE_DFP1_SUPPORT | ATOM_DEVICE_DFP2_SUPPORT | \
- ATOM_DEVICE_DFP3_SUPPORT | ATOM_DEVICE_DFP4_SUPPORT | \
- ATOM_DEVICE_DFP5_SUPPORT)
-#define ATOM_DEVICE_TV_SUPPORT \
- (ATOM_DEVICE_TV1_SUPPORT | ATOM_DEVICE_TV2_SUPPORT)
-#define ATOM_DEVICE_LCD_SUPPORT \
- (ATOM_DEVICE_LCD1_SUPPORT | ATOM_DEVICE_LCD2_SUPPORT)
+#define ATOM_DEVICE_CRT1_SUPPORT (0x1L << ATOM_DEVICE_CRT1_INDEX )
+#define ATOM_DEVICE_LCD1_SUPPORT (0x1L << ATOM_DEVICE_LCD1_INDEX )
+#define ATOM_DEVICE_TV1_SUPPORT (0x1L << ATOM_DEVICE_TV1_INDEX )
+#define ATOM_DEVICE_DFP1_SUPPORT (0x1L << ATOM_DEVICE_DFP1_INDEX )
+#define ATOM_DEVICE_CRT2_SUPPORT (0x1L << ATOM_DEVICE_CRT2_INDEX )
+#define ATOM_DEVICE_LCD2_SUPPORT (0x1L << ATOM_DEVICE_LCD2_INDEX )
+#define ATOM_DEVICE_DFP6_SUPPORT (0x1L << ATOM_DEVICE_DFP6_INDEX )
+#define ATOM_DEVICE_DFP2_SUPPORT (0x1L << ATOM_DEVICE_DFP2_INDEX )
+#define ATOM_DEVICE_CV_SUPPORT (0x1L << ATOM_DEVICE_CV_INDEX )
+#define ATOM_DEVICE_DFP3_SUPPORT (0x1L << ATOM_DEVICE_DFP3_INDEX )
+#define ATOM_DEVICE_DFP4_SUPPORT (0x1L << ATOM_DEVICE_DFP4_INDEX )
+#define ATOM_DEVICE_DFP5_SUPPORT (0x1L << ATOM_DEVICE_DFP5_INDEX )
+
+#define ATOM_DEVICE_CRT_SUPPORT (ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_CRT2_SUPPORT)
+#define ATOM_DEVICE_DFP_SUPPORT (ATOM_DEVICE_DFP1_SUPPORT | ATOM_DEVICE_DFP2_SUPPORT | ATOM_DEVICE_DFP3_SUPPORT | ATOM_DEVICE_DFP4_SUPPORT | ATOM_DEVICE_DFP5_SUPPORT | ATOM_DEVICE_DFP6_SUPPORT)
+#define ATOM_DEVICE_TV_SUPPORT (ATOM_DEVICE_TV1_SUPPORT)
+#define ATOM_DEVICE_LCD_SUPPORT (ATOM_DEVICE_LCD1_SUPPORT | ATOM_DEVICE_LCD2_SUPPORT)
#define ATOM_DEVICE_CONNECTOR_TYPE_MASK 0x000000F0
#define ATOM_DEVICE_CONNECTOR_TYPE_SHIFT 0x00000004
@@ -1942,6 +2412,7 @@ usMinDownStreamHTLinkWidth: same as above.
#define ATOM_DEVICE_CONNECTOR_CASE_1 0x0000000E
#define ATOM_DEVICE_CONNECTOR_DISPLAYPORT 0x0000000F
+
#define ATOM_DEVICE_DAC_INFO_MASK 0x0000000F
#define ATOM_DEVICE_DAC_INFO_SHIFT 0x00000000
#define ATOM_DEVICE_DAC_INFO_NODAC 0x00000000
@@ -1958,139 +2429,150 @@ usMinDownStreamHTLinkWidth: same as above.
#define ATOM_DEVICE_I2C_ID_SHIFT 0x00000004
#define ATOM_DEVICE_I2C_ID_IS_FOR_NON_MM_USE 0x00000001
#define ATOM_DEVICE_I2C_ID_IS_FOR_MM_USE 0x00000002
-#define ATOM_DEVICE_I2C_ID_IS_FOR_SDVO_USE 0x00000003 /* For IGP RS600 */
-#define ATOM_DEVICE_I2C_ID_IS_FOR_DAC_SCL 0x00000004 /* For IGP RS690 */
+#define ATOM_DEVICE_I2C_ID_IS_FOR_SDVO_USE 0x00000003 //For IGP RS600
+#define ATOM_DEVICE_I2C_ID_IS_FOR_DAC_SCL 0x00000004 //For IGP RS690
#define ATOM_DEVICE_I2C_HARDWARE_CAP_MASK 0x00000080
#define ATOM_DEVICE_I2C_HARDWARE_CAP_SHIFT 0x00000007
#define ATOM_DEVICE_USES_SOFTWARE_ASSISTED_I2C 0x00000000
#define ATOM_DEVICE_USES_HARDWARE_ASSISTED_I2C 0x00000001
-/* usDeviceSupport: */
-/* Bits0 = 0 - no CRT1 support= 1- CRT1 is supported */
-/* Bit 1 = 0 - no LCD1 support= 1- LCD1 is supported */
-/* Bit 2 = 0 - no TV1 support= 1- TV1 is supported */
-/* Bit 3 = 0 - no DFP1 support= 1- DFP1 is supported */
-/* Bit 4 = 0 - no CRT2 support= 1- CRT2 is supported */
-/* Bit 5 = 0 - no LCD2 support= 1- LCD2 is supported */
-/* Bit 6 = 0 - no TV2 support= 1- TV2 is supported */
-/* Bit 7 = 0 - no DFP2 support= 1- DFP2 is supported */
-/* Bit 8 = 0 - no CV support= 1- CV is supported */
-/* Bit 9 = 0 - no DFP3 support= 1- DFP3 is supported */
-/* Byte1 (Supported Device Info) */
-/* Bit 0 = = 0 - no CV support= 1- CV is supported */
-/* */
-/* */
-
-/* ucI2C_ConfigID */
-/* [7:0] - I2C LINE Associate ID */
-/* = 0 - no I2C */
-/* [7] - HW_Cap = 1, [6:0]=HW assisted I2C ID(HW line selection) */
-/* = 0, [6:0]=SW assisted I2C ID */
-/* [6-4] - HW_ENGINE_ID = 1, HW engine for NON multimedia use */
-/* = 2, HW engine for Multimedia use */
-/* = 3-7 Reserved for future I2C engines */
-/* [3-0] - I2C_LINE_MUX = A Mux number when it's HW assisted I2C or GPIO ID when it's SW I2C */
-
-typedef struct _ATOM_I2C_ID_CONFIG {
-#if ATOM_BIG_ENDIAN
- UCHAR bfHW_Capable:1;
- UCHAR bfHW_EngineID:3;
- UCHAR bfI2C_LineMux:4;
-#else
- UCHAR bfI2C_LineMux:4;
- UCHAR bfHW_EngineID:3;
- UCHAR bfHW_Capable:1;
-#endif
-} ATOM_I2C_ID_CONFIG;
-
-typedef union _ATOM_I2C_ID_CONFIG_ACCESS {
- ATOM_I2C_ID_CONFIG sbfAccess;
- UCHAR ucAccess;
-} ATOM_I2C_ID_CONFIG_ACCESS;
+// usDeviceSupport:
+// Bits0 = 0 - no CRT1 support= 1- CRT1 is supported
+// Bit 1 = 0 - no LCD1 support= 1- LCD1 is supported
+// Bit 2 = 0 - no TV1 support= 1- TV1 is supported
+// Bit 3 = 0 - no DFP1 support= 1- DFP1 is supported
+// Bit 4 = 0 - no CRT2 support= 1- CRT2 is supported
+// Bit 5 = 0 - no LCD2 support= 1- LCD2 is supported
+// Bit 6 = 0 - no DFP6 support= 1- DFP6 is supported
+// Bit 7 = 0 - no DFP2 support= 1- DFP2 is supported
+// Bit 8 = 0 - no CV support= 1- CV is supported
+// Bit 9 = 0 - no DFP3 support= 1- DFP3 is supported
+// Bit 10 = 0 - no DFP4 support= 1- DFP4 is supported
+// Bit 11 = 0 - no DFP5 support= 1- DFP5 is supported
+//
+//
/****************************************************************************/
-/* Structure used in GPIO_I2C_InfoTable */
+/* Structure used in MclkSS_InfoTable */
/****************************************************************************/
-typedef struct _ATOM_GPIO_I2C_ASSIGMENT {
- USHORT usClkMaskRegisterIndex;
- USHORT usClkEnRegisterIndex;
- USHORT usClkY_RegisterIndex;
- USHORT usClkA_RegisterIndex;
- USHORT usDataMaskRegisterIndex;
- USHORT usDataEnRegisterIndex;
- USHORT usDataY_RegisterIndex;
- USHORT usDataA_RegisterIndex;
- ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;
- UCHAR ucClkMaskShift;
- UCHAR ucClkEnShift;
- UCHAR ucClkY_Shift;
- UCHAR ucClkA_Shift;
- UCHAR ucDataMaskShift;
- UCHAR ucDataEnShift;
- UCHAR ucDataY_Shift;
- UCHAR ucDataA_Shift;
- UCHAR ucReserved1;
- UCHAR ucReserved2;
-} ATOM_GPIO_I2C_ASSIGMENT;
-
-typedef struct _ATOM_GPIO_I2C_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_GPIO_I2C_ASSIGMENT asGPIO_Info[ATOM_MAX_SUPPORTED_DEVICE];
-} ATOM_GPIO_I2C_INFO;
+// ucI2C_ConfigID
+// [7:0] - I2C LINE Associate ID
+// = 0 - no I2C
+// [7] - HW_Cap = 1, [6:0]=HW assisted I2C ID(HW line selection)
+// = 0, [6:0]=SW assisted I2C ID
+// [6-4] - HW_ENGINE_ID = 1, HW engine for NON multimedia use
+// = 2, HW engine for Multimedia use
+// = 3-7 Reserved for future I2C engines
+// [3-0] - I2C_LINE_MUX = A Mux number when it's HW assisted I2C or GPIO ID when it's SW I2C
+
+typedef struct _ATOM_I2C_ID_CONFIG
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR bfHW_Capable:1;
+ UCHAR bfHW_EngineID:3;
+ UCHAR bfI2C_LineMux:4;
+#else
+ UCHAR bfI2C_LineMux:4;
+ UCHAR bfHW_EngineID:3;
+ UCHAR bfHW_Capable:1;
+#endif
+}ATOM_I2C_ID_CONFIG;
-/****************************************************************************/
-/* Common Structure used in other structures */
-/****************************************************************************/
+typedef union _ATOM_I2C_ID_CONFIG_ACCESS
+{
+ ATOM_I2C_ID_CONFIG sbfAccess;
+ UCHAR ucAccess;
+}ATOM_I2C_ID_CONFIG_ACCESS;
+
+
+/****************************************************************************/
+// Structure used in GPIO_I2C_InfoTable
+/****************************************************************************/
+typedef struct _ATOM_GPIO_I2C_ASSIGMENT
+{
+ USHORT usClkMaskRegisterIndex;
+ USHORT usClkEnRegisterIndex;
+ USHORT usClkY_RegisterIndex;
+ USHORT usClkA_RegisterIndex;
+ USHORT usDataMaskRegisterIndex;
+ USHORT usDataEnRegisterIndex;
+ USHORT usDataY_RegisterIndex;
+ USHORT usDataA_RegisterIndex;
+ ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;
+ UCHAR ucClkMaskShift;
+ UCHAR ucClkEnShift;
+ UCHAR ucClkY_Shift;
+ UCHAR ucClkA_Shift;
+ UCHAR ucDataMaskShift;
+ UCHAR ucDataEnShift;
+ UCHAR ucDataY_Shift;
+ UCHAR ucDataA_Shift;
+ UCHAR ucReserved1;
+ UCHAR ucReserved2;
+}ATOM_GPIO_I2C_ASSIGMENT;
+
+typedef struct _ATOM_GPIO_I2C_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_GPIO_I2C_ASSIGMENT asGPIO_Info[ATOM_MAX_SUPPORTED_DEVICE];
+}ATOM_GPIO_I2C_INFO;
+
+/****************************************************************************/
+// Common Structure used in other structures
+/****************************************************************************/
#ifndef _H2INC
-
-/* Please don't add or expand this bitfield structure below, this one will retire soon.! */
-typedef struct _ATOM_MODE_MISC_INFO {
+
+//Please don't add or expand this bitfield structure below, this one will retire soon.!
+typedef struct _ATOM_MODE_MISC_INFO
+{
#if ATOM_BIG_ENDIAN
- USHORT Reserved:6;
- USHORT RGB888:1;
- USHORT DoubleClock:1;
- USHORT Interlace:1;
- USHORT CompositeSync:1;
- USHORT V_ReplicationBy2:1;
- USHORT H_ReplicationBy2:1;
- USHORT VerticalCutOff:1;
- USHORT VSyncPolarity:1; /* 0=Active High, 1=Active Low */
- USHORT HSyncPolarity:1; /* 0=Active High, 1=Active Low */
- USHORT HorizontalCutOff:1;
+ USHORT Reserved:6;
+ USHORT RGB888:1;
+ USHORT DoubleClock:1;
+ USHORT Interlace:1;
+ USHORT CompositeSync:1;
+ USHORT V_ReplicationBy2:1;
+ USHORT H_ReplicationBy2:1;
+ USHORT VerticalCutOff:1;
+ USHORT VSyncPolarity:1; //0=Active High, 1=Active Low
+ USHORT HSyncPolarity:1; //0=Active High, 1=Active Low
+ USHORT HorizontalCutOff:1;
#else
- USHORT HorizontalCutOff:1;
- USHORT HSyncPolarity:1; /* 0=Active High, 1=Active Low */
- USHORT VSyncPolarity:1; /* 0=Active High, 1=Active Low */
- USHORT VerticalCutOff:1;
- USHORT H_ReplicationBy2:1;
- USHORT V_ReplicationBy2:1;
- USHORT CompositeSync:1;
- USHORT Interlace:1;
- USHORT DoubleClock:1;
- USHORT RGB888:1;
- USHORT Reserved:6;
+ USHORT HorizontalCutOff:1;
+ USHORT HSyncPolarity:1; //0=Active High, 1=Active Low
+ USHORT VSyncPolarity:1; //0=Active High, 1=Active Low
+ USHORT VerticalCutOff:1;
+ USHORT H_ReplicationBy2:1;
+ USHORT V_ReplicationBy2:1;
+ USHORT CompositeSync:1;
+ USHORT Interlace:1;
+ USHORT DoubleClock:1;
+ USHORT RGB888:1;
+ USHORT Reserved:6;
#endif
-} ATOM_MODE_MISC_INFO;
-
-typedef union _ATOM_MODE_MISC_INFO_ACCESS {
- ATOM_MODE_MISC_INFO sbfAccess;
- USHORT usAccess;
-} ATOM_MODE_MISC_INFO_ACCESS;
-
+}ATOM_MODE_MISC_INFO;
+
+typedef union _ATOM_MODE_MISC_INFO_ACCESS
+{
+ ATOM_MODE_MISC_INFO sbfAccess;
+ USHORT usAccess;
+}ATOM_MODE_MISC_INFO_ACCESS;
+
#else
-
-typedef union _ATOM_MODE_MISC_INFO_ACCESS {
- USHORT usAccess;
-} ATOM_MODE_MISC_INFO_ACCESS;
-
+
+typedef union _ATOM_MODE_MISC_INFO_ACCESS
+{
+ USHORT usAccess;
+}ATOM_MODE_MISC_INFO_ACCESS;
+
#endif
-/* usModeMiscInfo- */
+// usModeMiscInfo-
#define ATOM_H_CUTOFF 0x01
-#define ATOM_HSYNC_POLARITY 0x02 /* 0=Active High, 1=Active Low */
-#define ATOM_VSYNC_POLARITY 0x04 /* 0=Active High, 1=Active Low */
+#define ATOM_HSYNC_POLARITY 0x02 //0=Active High, 1=Active Low
+#define ATOM_VSYNC_POLARITY 0x04 //0=Active High, 1=Active Low
#define ATOM_V_CUTOFF 0x08
#define ATOM_H_REPLICATIONBY2 0x10
#define ATOM_V_REPLICATIONBY2 0x20
@@ -2099,10 +2581,10 @@ typedef union _ATOM_MODE_MISC_INFO_ACCESS {
#define ATOM_DOUBLE_CLOCK_MODE 0x100
#define ATOM_RGB888_MODE 0x200
-/* usRefreshRate- */
+//usRefreshRate-
#define ATOM_REFRESH_43 43
#define ATOM_REFRESH_47 47
-#define ATOM_REFRESH_56 56
+#define ATOM_REFRESH_56 56
#define ATOM_REFRESH_60 60
#define ATOM_REFRESH_65 65
#define ATOM_REFRESH_70 70
@@ -2110,192 +2592,233 @@ typedef union _ATOM_MODE_MISC_INFO_ACCESS {
#define ATOM_REFRESH_75 75
#define ATOM_REFRESH_85 85
-/* ATOM_MODE_TIMING data are exactly the same as VESA timing data. */
-/* Translation from EDID to ATOM_MODE_TIMING, use the following formula. */
-/* */
-/* VESA_HTOTAL = VESA_ACTIVE + 2* VESA_BORDER + VESA_BLANK */
-/* = EDID_HA + EDID_HBL */
-/* VESA_HDISP = VESA_ACTIVE = EDID_HA */
-/* VESA_HSYNC_START = VESA_ACTIVE + VESA_BORDER + VESA_FRONT_PORCH */
-/* = EDID_HA + EDID_HSO */
-/* VESA_HSYNC_WIDTH = VESA_HSYNC_TIME = EDID_HSPW */
-/* VESA_BORDER = EDID_BORDER */
-
-/****************************************************************************/
-/* Structure used in SetCRTC_UsingDTDTimingTable */
-/****************************************************************************/
-typedef struct _SET_CRTC_USING_DTD_TIMING_PARAMETERS {
- USHORT usH_Size;
- USHORT usH_Blanking_Time;
- USHORT usV_Size;
- USHORT usV_Blanking_Time;
- USHORT usH_SyncOffset;
- USHORT usH_SyncWidth;
- USHORT usV_SyncOffset;
- USHORT usV_SyncWidth;
- ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
- UCHAR ucH_Border; /* From DFP EDID */
- UCHAR ucV_Border;
- UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */
- UCHAR ucPadding[3];
-} SET_CRTC_USING_DTD_TIMING_PARAMETERS;
-
-/****************************************************************************/
-/* Structure used in SetCRTC_TimingTable */
-/****************************************************************************/
-typedef struct _SET_CRTC_TIMING_PARAMETERS {
- USHORT usH_Total; /* horizontal total */
- USHORT usH_Disp; /* horizontal display */
- USHORT usH_SyncStart; /* horozontal Sync start */
- USHORT usH_SyncWidth; /* horizontal Sync width */
- USHORT usV_Total; /* vertical total */
- USHORT usV_Disp; /* vertical display */
- USHORT usV_SyncStart; /* vertical Sync start */
- USHORT usV_SyncWidth; /* vertical Sync width */
- ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
- UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */
- UCHAR ucOverscanRight; /* right */
- UCHAR ucOverscanLeft; /* left */
- UCHAR ucOverscanBottom; /* bottom */
- UCHAR ucOverscanTop; /* top */
- UCHAR ucReserved;
-} SET_CRTC_TIMING_PARAMETERS;
+// ATOM_MODE_TIMING data are exactly the same as VESA timing data.
+// Translation from EDID to ATOM_MODE_TIMING, use the following formula.
+//
+// VESA_HTOTAL = VESA_ACTIVE + 2* VESA_BORDER + VESA_BLANK
+// = EDID_HA + EDID_HBL
+// VESA_HDISP = VESA_ACTIVE = EDID_HA
+// VESA_HSYNC_START = VESA_ACTIVE + VESA_BORDER + VESA_FRONT_PORCH
+// = EDID_HA + EDID_HSO
+// VESA_HSYNC_WIDTH = VESA_HSYNC_TIME = EDID_HSPW
+// VESA_BORDER = EDID_BORDER
+
+/****************************************************************************/
+// Structure used in SetCRTC_UsingDTDTimingTable
+/****************************************************************************/
+typedef struct _SET_CRTC_USING_DTD_TIMING_PARAMETERS
+{
+ USHORT usH_Size;
+ USHORT usH_Blanking_Time;
+ USHORT usV_Size;
+ USHORT usV_Blanking_Time;
+ USHORT usH_SyncOffset;
+ USHORT usH_SyncWidth;
+ USHORT usV_SyncOffset;
+ USHORT usV_SyncWidth;
+ ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
+ UCHAR ucH_Border; // From DFP EDID
+ UCHAR ucV_Border;
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucPadding[3];
+}SET_CRTC_USING_DTD_TIMING_PARAMETERS;
+
+/****************************************************************************/
+// Structure used in SetCRTC_TimingTable
+/****************************************************************************/
+typedef struct _SET_CRTC_TIMING_PARAMETERS
+{
+ USHORT usH_Total; // horizontal total
+ USHORT usH_Disp; // horizontal display
+ USHORT usH_SyncStart; // horozontal Sync start
+ USHORT usH_SyncWidth; // horizontal Sync width
+ USHORT usV_Total; // vertical total
+ USHORT usV_Disp; // vertical display
+ USHORT usV_SyncStart; // vertical Sync start
+ USHORT usV_SyncWidth; // vertical Sync width
+ ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucOverscanRight; // right
+ UCHAR ucOverscanLeft; // left
+ UCHAR ucOverscanBottom; // bottom
+ UCHAR ucOverscanTop; // top
+ UCHAR ucReserved;
+}SET_CRTC_TIMING_PARAMETERS;
#define SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION SET_CRTC_TIMING_PARAMETERS
-/****************************************************************************/
-/* Structure used in StandardVESA_TimingTable */
-/* AnalogTV_InfoTable */
-/* ComponentVideoInfoTable */
-/****************************************************************************/
-typedef struct _ATOM_MODE_TIMING {
- USHORT usCRTC_H_Total;
- USHORT usCRTC_H_Disp;
- USHORT usCRTC_H_SyncStart;
- USHORT usCRTC_H_SyncWidth;
- USHORT usCRTC_V_Total;
- USHORT usCRTC_V_Disp;
- USHORT usCRTC_V_SyncStart;
- USHORT usCRTC_V_SyncWidth;
- USHORT usPixelClock; /* in 10Khz unit */
- ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
- USHORT usCRTC_OverscanRight;
- USHORT usCRTC_OverscanLeft;
- USHORT usCRTC_OverscanBottom;
- USHORT usCRTC_OverscanTop;
- USHORT usReserve;
- UCHAR ucInternalModeNumber;
- UCHAR ucRefreshRate;
-} ATOM_MODE_TIMING;
-
-typedef struct _ATOM_DTD_FORMAT {
- USHORT usPixClk;
- USHORT usHActive;
- USHORT usHBlanking_Time;
- USHORT usVActive;
- USHORT usVBlanking_Time;
- USHORT usHSyncOffset;
- USHORT usHSyncWidth;
- USHORT usVSyncOffset;
- USHORT usVSyncWidth;
- USHORT usImageHSize;
- USHORT usImageVSize;
- UCHAR ucHBorder;
- UCHAR ucVBorder;
- ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
- UCHAR ucInternalModeNumber;
- UCHAR ucRefreshRate;
-} ATOM_DTD_FORMAT;
-
-/****************************************************************************/
-/* Structure used in LVDS_InfoTable */
-/* * Need a document to describe this table */
-/****************************************************************************/
+/****************************************************************************/
+// Structure used in StandardVESA_TimingTable
+// AnalogTV_InfoTable
+// ComponentVideoInfoTable
+/****************************************************************************/
+typedef struct _ATOM_MODE_TIMING
+{
+ USHORT usCRTC_H_Total;
+ USHORT usCRTC_H_Disp;
+ USHORT usCRTC_H_SyncStart;
+ USHORT usCRTC_H_SyncWidth;
+ USHORT usCRTC_V_Total;
+ USHORT usCRTC_V_Disp;
+ USHORT usCRTC_V_SyncStart;
+ USHORT usCRTC_V_SyncWidth;
+ USHORT usPixelClock; //in 10Khz unit
+ ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
+ USHORT usCRTC_OverscanRight;
+ USHORT usCRTC_OverscanLeft;
+ USHORT usCRTC_OverscanBottom;
+ USHORT usCRTC_OverscanTop;
+ USHORT usReserve;
+ UCHAR ucInternalModeNumber;
+ UCHAR ucRefreshRate;
+}ATOM_MODE_TIMING;
+
+typedef struct _ATOM_DTD_FORMAT
+{
+ USHORT usPixClk;
+ USHORT usHActive;
+ USHORT usHBlanking_Time;
+ USHORT usVActive;
+ USHORT usVBlanking_Time;
+ USHORT usHSyncOffset;
+ USHORT usHSyncWidth;
+ USHORT usVSyncOffset;
+ USHORT usVSyncWidth;
+ USHORT usImageHSize;
+ USHORT usImageVSize;
+ UCHAR ucHBorder;
+ UCHAR ucVBorder;
+ ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
+ UCHAR ucInternalModeNumber;
+ UCHAR ucRefreshRate;
+}ATOM_DTD_FORMAT;
+
+/****************************************************************************/
+// Structure used in LVDS_InfoTable
+// * Need a document to describe this table
+/****************************************************************************/
#define SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004
#define SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008
#define SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010
#define SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020
-/* Once DAL sees this CAP is set, it will read EDID from LCD on its own instead of using sLCDTiming in ATOM_LVDS_INFO_V12. */
-/* Other entries in ATOM_LVDS_INFO_V12 are still valid/useful to DAL */
-#define LCDPANEL_CAP_READ_EDID 0x1
-
-/* ucTableFormatRevision=1 */
-/* ucTableContentRevision=1 */
-typedef struct _ATOM_LVDS_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_DTD_FORMAT sLCDTiming;
- USHORT usModePatchTableOffset;
- USHORT usSupportedRefreshRate; /* Refer to panel info table in ATOMBIOS extension Spec. */
- USHORT usOffDelayInMs;
- UCHAR ucPowerSequenceDigOntoDEin10Ms;
- UCHAR ucPowerSequenceDEtoBLOnin10Ms;
- UCHAR ucLVDS_Misc; /* Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level} */
- /* Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888} */
- /* Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled} */
- /* Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled} */
- UCHAR ucPanelDefaultRefreshRate;
- UCHAR ucPanelIdentification;
- UCHAR ucSS_Id;
-} ATOM_LVDS_INFO;
-
-/* ucTableFormatRevision=1 */
-/* ucTableContentRevision=2 */
-typedef struct _ATOM_LVDS_INFO_V12 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_DTD_FORMAT sLCDTiming;
- USHORT usExtInfoTableOffset;
- USHORT usSupportedRefreshRate; /* Refer to panel info table in ATOMBIOS extension Spec. */
- USHORT usOffDelayInMs;
- UCHAR ucPowerSequenceDigOntoDEin10Ms;
- UCHAR ucPowerSequenceDEtoBLOnin10Ms;
- UCHAR ucLVDS_Misc; /* Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level} */
- /* Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888} */
- /* Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled} */
- /* Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled} */
- UCHAR ucPanelDefaultRefreshRate;
- UCHAR ucPanelIdentification;
- UCHAR ucSS_Id;
- USHORT usLCDVenderID;
- USHORT usLCDProductID;
- UCHAR ucLCDPanel_SpecialHandlingCap;
- UCHAR ucPanelInfoSize; /* start from ATOM_DTD_FORMAT to end of panel info, include ExtInfoTable */
- UCHAR ucReserved[2];
-} ATOM_LVDS_INFO_V12;
+//ucTableFormatRevision=1
+//ucTableContentRevision=1
+typedef struct _ATOM_LVDS_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_DTD_FORMAT sLCDTiming;
+ USHORT usModePatchTableOffset;
+ USHORT usSupportedRefreshRate; //Refer to panel info table in ATOMBIOS extension Spec.
+ USHORT usOffDelayInMs;
+ UCHAR ucPowerSequenceDigOntoDEin10Ms;
+ UCHAR ucPowerSequenceDEtoBLOnin10Ms;
+ UCHAR ucLVDS_Misc; // Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level}
+ // Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888}
+ // Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled}
+ // Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled}
+ UCHAR ucPanelDefaultRefreshRate;
+ UCHAR ucPanelIdentification;
+ UCHAR ucSS_Id;
+}ATOM_LVDS_INFO;
+
+//ucTableFormatRevision=1
+//ucTableContentRevision=2
+typedef struct _ATOM_LVDS_INFO_V12
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_DTD_FORMAT sLCDTiming;
+ USHORT usExtInfoTableOffset;
+ USHORT usSupportedRefreshRate; //Refer to panel info table in ATOMBIOS extension Spec.
+ USHORT usOffDelayInMs;
+ UCHAR ucPowerSequenceDigOntoDEin10Ms;
+ UCHAR ucPowerSequenceDEtoBLOnin10Ms;
+ UCHAR ucLVDS_Misc; // Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level}
+ // Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888}
+ // Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled}
+ // Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled}
+ UCHAR ucPanelDefaultRefreshRate;
+ UCHAR ucPanelIdentification;
+ UCHAR ucSS_Id;
+ USHORT usLCDVenderID;
+ USHORT usLCDProductID;
+ UCHAR ucLCDPanel_SpecialHandlingCap;
+ UCHAR ucPanelInfoSize; // start from ATOM_DTD_FORMAT to end of panel info, include ExtInfoTable
+ UCHAR ucReserved[2];
+}ATOM_LVDS_INFO_V12;
+
+//Definitions for ucLCDPanel_SpecialHandlingCap:
+
+//Once DAL sees this CAP is set, it will read EDID from LCD on its own instead of using sLCDTiming in ATOM_LVDS_INFO_V12.
+//Other entries in ATOM_LVDS_INFO_V12 are still valid/useful to DAL
+#define LCDPANEL_CAP_READ_EDID 0x1
+
+//If a design supports DRR (dynamic refresh rate) on internal panels (LVDS or EDP), this cap is set in ucLCDPanel_SpecialHandlingCap together
+//with multiple supported refresh rates@usSupportedRefreshRate. This cap should not be set when only slow refresh rate is supported (static
+//refresh rate switch by SW. This is only valid from ATOM_LVDS_INFO_V12
+#define LCDPANEL_CAP_DRR_SUPPORTED 0x2
+
+//Use this cap bit for a quick reference whether an embadded panel (LCD1 ) is LVDS or eDP.
+#define LCDPANEL_CAP_eDP 0x4
+
+
+//Color Bit Depth definition in EDID V1.4 @BYTE 14h
+//Bit 6 5 4
+ // 0 0 0 - Color bit depth is undefined
+ // 0 0 1 - 6 Bits per Primary Color
+ // 0 1 0 - 8 Bits per Primary Color
+ // 0 1 1 - 10 Bits per Primary Color
+ // 1 0 0 - 12 Bits per Primary Color
+ // 1 0 1 - 14 Bits per Primary Color
+ // 1 1 0 - 16 Bits per Primary Color
+ // 1 1 1 - Reserved
+
+#define PANEL_COLOR_BIT_DEPTH_MASK 0x70
+
+// Bit7:{=0:Random Dithering disabled;1 Random Dithering enabled}
+#define PANEL_RANDOM_DITHER 0x80
+#define PANEL_RANDOM_DITHER_MASK 0x80
+
#define ATOM_LVDS_INFO_LAST ATOM_LVDS_INFO_V12
-typedef struct _ATOM_PATCH_RECORD_MODE {
- UCHAR ucRecordType;
- USHORT usHDisp;
- USHORT usVDisp;
-} ATOM_PATCH_RECORD_MODE;
+typedef struct _ATOM_PATCH_RECORD_MODE
+{
+ UCHAR ucRecordType;
+ USHORT usHDisp;
+ USHORT usVDisp;
+}ATOM_PATCH_RECORD_MODE;
-typedef struct _ATOM_LCD_RTS_RECORD {
- UCHAR ucRecordType;
- UCHAR ucRTSValue;
-} ATOM_LCD_RTS_RECORD;
+typedef struct _ATOM_LCD_RTS_RECORD
+{
+ UCHAR ucRecordType;
+ UCHAR ucRTSValue;
+}ATOM_LCD_RTS_RECORD;
-/* !! If the record below exits, it shoud always be the first record for easy use in command table!!! */
-typedef struct _ATOM_LCD_MODE_CONTROL_CAP {
- UCHAR ucRecordType;
- USHORT usLCDCap;
-} ATOM_LCD_MODE_CONTROL_CAP;
+//!! If the record below exits, it shoud always be the first record for easy use in command table!!!
+// The record below is only used when LVDS_Info is present. From ATOM_LVDS_INFO_V12, use ucLCDPanel_SpecialHandlingCap instead.
+typedef struct _ATOM_LCD_MODE_CONTROL_CAP
+{
+ UCHAR ucRecordType;
+ USHORT usLCDCap;
+}ATOM_LCD_MODE_CONTROL_CAP;
#define LCD_MODE_CAP_BL_OFF 1
#define LCD_MODE_CAP_CRTC_OFF 2
#define LCD_MODE_CAP_PANEL_OFF 4
-typedef struct _ATOM_FAKE_EDID_PATCH_RECORD {
- UCHAR ucRecordType;
- UCHAR ucFakeEDIDLength;
- UCHAR ucFakeEDIDString[1]; /* This actually has ucFakeEdidLength elements. */
+typedef struct _ATOM_FAKE_EDID_PATCH_RECORD
+{
+ UCHAR ucRecordType;
+ UCHAR ucFakeEDIDLength;
+ UCHAR ucFakeEDIDString[1]; // This actually has ucFakeEdidLength elements.
} ATOM_FAKE_EDID_PATCH_RECORD;
-typedef struct _ATOM_PANEL_RESOLUTION_PATCH_RECORD {
- UCHAR ucRecordType;
- USHORT usHSize;
- USHORT usVSize;
-} ATOM_PANEL_RESOLUTION_PATCH_RECORD;
+typedef struct _ATOM_PANEL_RESOLUTION_PATCH_RECORD
+{
+ UCHAR ucRecordType;
+ USHORT usHSize;
+ USHORT usVSize;
+}ATOM_PANEL_RESOLUTION_PATCH_RECORD;
#define LCD_MODE_PATCH_RECORD_MODE_TYPE 1
#define LCD_RTS_RECORD_TYPE 2
@@ -2306,21 +2829,25 @@ typedef struct _ATOM_PANEL_RESOLUTION_PATCH_RECORD {
/****************************Spread Spectrum Info Table Definitions **********************/
-/* ucTableFormatRevision=1 */
-/* ucTableContentRevision=2 */
-typedef struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT {
- USHORT usSpreadSpectrumPercentage;
- UCHAR ucSpreadSpectrumType; /* Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD */
- UCHAR ucSS_Step;
- UCHAR ucSS_Delay;
- UCHAR ucSS_Id;
- UCHAR ucRecommendedRef_Div;
- UCHAR ucSS_Range; /* it was reserved for V11 */
-} ATOM_SPREAD_SPECTRUM_ASSIGNMENT;
+//ucTableFormatRevision=1
+//ucTableContentRevision=2
+typedef struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT
+{
+ USHORT usSpreadSpectrumPercentage;
+ UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Bit2=1: PCIE REFCLK SS =0 iternal PPLL SS Others:TBD
+ UCHAR ucSS_Step;
+ UCHAR ucSS_Delay;
+ UCHAR ucSS_Id;
+ UCHAR ucRecommendedRef_Div;
+ UCHAR ucSS_Range; //it was reserved for V11
+}ATOM_SPREAD_SPECTRUM_ASSIGNMENT;
#define ATOM_MAX_SS_ENTRY 16
-#define ATOM_DP_SS_ID1 0x0f1 /* SS modulation freq=30k */
-#define ATOM_DP_SS_ID2 0x0f2 /* SS modulation freq=33k */
+#define ATOM_DP_SS_ID1 0x0f1 // SS ID for internal DP stream at 2.7Ghz. if ATOM_DP_SS_ID2 does not exist in SS_InfoTable, it is used for internal DP stream at 1.62Ghz as well.
+#define ATOM_DP_SS_ID2 0x0f2 // SS ID for internal DP stream at 1.62Ghz, if it exists in SS_InfoTable.
+#define ATOM_LVLINK_2700MHz_SS_ID 0x0f3 // SS ID for LV link translator chip at 2.7Ghz
+#define ATOM_LVLINK_1620MHz_SS_ID 0x0f4 // SS ID for LV link translator chip at 1.62Ghz
+
#define ATOM_SS_DOWN_SPREAD_MODE_MASK 0x00000000
#define ATOM_SS_DOWN_SPREAD_MODE 0x00000000
@@ -2329,29 +2856,30 @@ typedef struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT {
#define ATOM_INTERNAL_SS_MASK 0x00000000
#define ATOM_EXTERNAL_SS_MASK 0x00000002
#define EXEC_SS_STEP_SIZE_SHIFT 2
-#define EXEC_SS_DELAY_SHIFT 4
+#define EXEC_SS_DELAY_SHIFT 4
#define ACTIVEDATA_TO_BLON_DELAY_SHIFT 4
-typedef struct _ATOM_SPREAD_SPECTRUM_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_SPREAD_SPECTRUM_ASSIGNMENT asSS_Info[ATOM_MAX_SS_ENTRY];
-} ATOM_SPREAD_SPECTRUM_INFO;
-
-/****************************************************************************/
-/* Structure used in AnalogTV_InfoTable (Top level) */
-/****************************************************************************/
-/* ucTVBootUpDefaultStd definiton: */
-
-/* ATOM_TV_NTSC 1 */
-/* ATOM_TV_NTSCJ 2 */
-/* ATOM_TV_PAL 3 */
-/* ATOM_TV_PALM 4 */
-/* ATOM_TV_PALCN 5 */
-/* ATOM_TV_PALN 6 */
-/* ATOM_TV_PAL60 7 */
-/* ATOM_TV_SECAM 8 */
-
-/* ucTVSuppportedStd definition: */
+typedef struct _ATOM_SPREAD_SPECTRUM_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_SPREAD_SPECTRUM_ASSIGNMENT asSS_Info[ATOM_MAX_SS_ENTRY];
+}ATOM_SPREAD_SPECTRUM_INFO;
+
+/****************************************************************************/
+// Structure used in AnalogTV_InfoTable (Top level)
+/****************************************************************************/
+//ucTVBootUpDefaultStd definiton:
+
+//ATOM_TV_NTSC 1
+//ATOM_TV_NTSCJ 2
+//ATOM_TV_PAL 3
+//ATOM_TV_PALM 4
+//ATOM_TV_PALCN 5
+//ATOM_TV_PALN 6
+//ATOM_TV_PAL60 7
+//ATOM_TV_SECAM 8
+
+//ucTVSupportedStd definition:
#define NTSC_SUPPORT 0x1
#define NTSCJ_SUPPORT 0x2
@@ -2364,46 +2892,58 @@ typedef struct _ATOM_SPREAD_SPECTRUM_INFO {
#define MAX_SUPPORTED_TV_TIMING 2
-typedef struct _ATOM_ANALOG_TV_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- UCHAR ucTV_SupportedStandard;
- UCHAR ucTV_BootUpDefaultStandard;
- UCHAR ucExt_TV_ASIC_ID;
- UCHAR ucExt_TV_ASIC_SlaveAddr;
- /*ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_TV_TIMING]; */
- ATOM_MODE_TIMING aModeTimings[MAX_SUPPORTED_TV_TIMING];
-} ATOM_ANALOG_TV_INFO;
+typedef struct _ATOM_ANALOG_TV_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucTV_SupportedStandard;
+ UCHAR ucTV_BootUpDefaultStandard;
+ UCHAR ucExt_TV_ASIC_ID;
+ UCHAR ucExt_TV_ASIC_SlaveAddr;
+ /*ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_TV_TIMING];*/
+ ATOM_MODE_TIMING aModeTimings[MAX_SUPPORTED_TV_TIMING];
+}ATOM_ANALOG_TV_INFO;
#define MAX_SUPPORTED_TV_TIMING_V1_2 3
-typedef struct _ATOM_ANALOG_TV_INFO_V1_2 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- UCHAR ucTV_SupportedStandard;
- UCHAR ucTV_BootUpDefaultStandard;
- UCHAR ucExt_TV_ASIC_ID;
- UCHAR ucExt_TV_ASIC_SlaveAddr;
- ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_TV_TIMING];
-} ATOM_ANALOG_TV_INFO_V1_2;
+typedef struct _ATOM_ANALOG_TV_INFO_V1_2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucTV_SupportedStandard;
+ UCHAR ucTV_BootUpDefaultStandard;
+ UCHAR ucExt_TV_ASIC_ID;
+ UCHAR ucExt_TV_ASIC_SlaveAddr;
+ ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_TV_TIMING];
+}ATOM_ANALOG_TV_INFO_V1_2;
+
+typedef struct _ATOM_DPCD_INFO
+{
+ UCHAR ucRevisionNumber; //10h : Revision 1.0; 11h : Revision 1.1
+ UCHAR ucMaxLinkRate; //06h : 1.62Gbps per lane; 0Ah = 2.7Gbps per lane
+ UCHAR ucMaxLane; //Bits 4:0 = MAX_LANE_COUNT (1/2/4). Bit 7 = ENHANCED_FRAME_CAP
+ UCHAR ucMaxDownSpread; //Bit0 = 0: No Down spread; Bit0 = 1: 0.5% (Subject to change according to DP spec)
+}ATOM_DPCD_INFO;
+
+#define ATOM_DPCD_MAX_LANE_MASK 0x1F
/**************************************************************************/
-/* VRAM usage and their definitions */
+// VRAM usage and their defintions
-/* One chunk of VRAM used by Bios are for HWICON surfaces,EDID data. */
-/* Current Mode timing and Dail Timing and/or STD timing data EACH device. They can be broken down as below. */
-/* All the addresses below are the offsets from the frame buffer start.They all MUST be Dword aligned! */
-/* To driver: The physical address of this memory portion=mmFB_START(4K aligned)+ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR */
-/* To Bios: ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR->MM_INDEX */
+// One chunk of VRAM used by Bios are for HWICON surfaces,EDID data.
+// Current Mode timing and Dail Timing and/or STD timing data EACH device. They can be broken down as below.
+// All the addresses below are the offsets from the frame buffer start.They all MUST be Dword aligned!
+// To driver: The physical address of this memory portion=mmFB_START(4K aligned)+ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR
+// To Bios: ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR->MM_INDEX
#ifndef VESA_MEMORY_IN_64K_BLOCK
-#define VESA_MEMORY_IN_64K_BLOCK 0x100 /* 256*64K=16Mb (Max. VESA memory is 16Mb!) */
+#define VESA_MEMORY_IN_64K_BLOCK 0x100 //256*64K=16Mb (Max. VESA memory is 16Mb!)
#endif
-#define ATOM_EDID_RAW_DATASIZE 256 /* In Bytes */
-#define ATOM_HWICON_SURFACE_SIZE 4096 /* In Bytes */
+#define ATOM_EDID_RAW_DATASIZE 256 //In Bytes
+#define ATOM_HWICON_SURFACE_SIZE 4096 //In Bytes
#define ATOM_HWICON_INFOTABLE_SIZE 32
#define MAX_DTD_MODE_IN_VRAM 6
-#define ATOM_DTD_MODE_SUPPORT_TBL_SIZE (MAX_DTD_MODE_IN_VRAM*28) /* 28= (SIZEOF ATOM_DTD_FORMAT) */
-#define ATOM_STD_MODE_SUPPORT_TBL_SIZE (32*8) /* 32 is a predefined number,8= (SIZEOF ATOM_STD_FORMAT) */
+#define ATOM_DTD_MODE_SUPPORT_TBL_SIZE (MAX_DTD_MODE_IN_VRAM*28) //28= (SIZEOF ATOM_DTD_FORMAT)
+#define ATOM_STD_MODE_SUPPORT_TBL_SIZE 32*8 //32 is a predefined number,8= (SIZEOF ATOM_STD_FORMAT)
#define DFP_ENCODER_TYPE_OFFSET 0x80
#define DP_ENCODER_LANE_NUM_OFFSET 0x84
#define DP_ENCODER_LINK_RATE_OFFSET 0x88
@@ -2417,7 +2957,7 @@ typedef struct _ATOM_ANALOG_TV_INFO_V1_2 {
#define ATOM_LCD1_EDID_ADDR (ATOM_CRT1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
#define ATOM_LCD1_DTD_MODE_TBL_ADDR (ATOM_LCD1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
-#define ATOM_LCD1_STD_MODE_TBL_ADDR (ATOM_LCD1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_LCD1_STD_MODE_TBL_ADDR (ATOM_LCD1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
#define ATOM_TV1_DTD_MODE_TBL_ADDR (ATOM_LCD1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
@@ -2431,13 +2971,13 @@ typedef struct _ATOM_ANALOG_TV_INFO_V1_2 {
#define ATOM_LCD2_EDID_ADDR (ATOM_CRT2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
#define ATOM_LCD2_DTD_MODE_TBL_ADDR (ATOM_LCD2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
-#define ATOM_LCD2_STD_MODE_TBL_ADDR (ATOM_LCD2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_LCD2_STD_MODE_TBL_ADDR (ATOM_LCD2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
-#define ATOM_TV2_EDID_ADDR (ATOM_LCD2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
-#define ATOM_TV2_DTD_MODE_TBL_ADDR (ATOM_TV2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
-#define ATOM_TV2_STD_MODE_TBL_ADDR (ATOM_TV2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP6_EDID_ADDR (ATOM_LCD2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP6_DTD_MODE_TBL_ADDR (ATOM_DFP6_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_DFP6_STD_MODE_TBL_ADDR (ATOM_DFP6_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
-#define ATOM_DFP2_EDID_ADDR (ATOM_TV2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP2_EDID_ADDR (ATOM_DFP6_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
#define ATOM_DFP2_DTD_MODE_TBL_ADDR (ATOM_DFP2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
#define ATOM_DFP2_STD_MODE_TBL_ADDR (ATOM_DFP2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
@@ -2457,533 +2997,850 @@ typedef struct _ATOM_ANALOG_TV_INFO_V1_2 {
#define ATOM_DFP5_DTD_MODE_TBL_ADDR (ATOM_DFP5_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
#define ATOM_DFP5_STD_MODE_TBL_ADDR (ATOM_DFP5_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
-#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP5_STD_MODE_TBL_ADDR+ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP5_STD_MODE_TBL_ADDR+ATOM_STD_MODE_SUPPORT_TBL_SIZE)
-#define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR + 256)
-#define ATOM_STACK_STORAGE_END (ATOM_STACK_STORAGE_START + 512)
+#define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR+256)
+#define ATOM_STACK_STORAGE_END ATOM_STACK_STORAGE_START+512
-/* The size below is in Kb! */
+//The size below is in Kb!
#define ATOM_VRAM_RESERVE_SIZE ((((ATOM_STACK_STORAGE_END - ATOM_HWICON1_SURFACE_ADDR)>>10)+4)&0xFFFC)
-
+
#define ATOM_VRAM_OPERATION_FLAGS_MASK 0xC0000000L
#define ATOM_VRAM_OPERATION_FLAGS_SHIFT 30
#define ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION 0x1
#define ATOM_VRAM_BLOCK_NEEDS_RESERVATION 0x0
-/***********************************************************************************/
-/* Structure used in VRAM_UsageByFirmwareTable */
-/* Note1: This table is filled by SetBiosReservationStartInFB in CoreCommSubs.asm */
-/* at running time. */
-/* note2: From RV770, the memory is more than 32bit addressable, so we will change */
-/* ucTableFormatRevision=1,ucTableContentRevision=4, the strcuture remains */
-/* exactly same as 1.1 and 1.2 (1.3 is never in use), but ulStartAddrUsedByFirmware */
-/* (in offset to start of memory address) is KB aligned instead of byte aligend. */
-/***********************************************************************************/
+/***********************************************************************************/
+// Structure used in VRAM_UsageByFirmwareTable
+// Note1: This table is filled by SetBiosReservationStartInFB in CoreCommSubs.asm
+// at running time.
+// note2: From RV770, the memory is more than 32bit addressable, so we will change
+// ucTableFormatRevision=1,ucTableContentRevision=4, the strcuture remains
+// exactly same as 1.1 and 1.2 (1.3 is never in use), but ulStartAddrUsedByFirmware
+// (in offset to start of memory address) is KB aligned instead of byte aligend.
+/***********************************************************************************/
+// Note3:
+/* If we change usReserved to "usFBUsedbyDrvInKB", then to VBIOS this usFBUsedbyDrvInKB is a predefined, unchanged constant across VGA or non VGA adapter,
+for CAIL, The size of FB access area is known, only thing missing is the Offset of FB Access area, so we can have:
+
+If (ulStartAddrUsedByFirmware!=0)
+FBAccessAreaOffset= ulStartAddrUsedByFirmware - usFBUsedbyDrvInKB;
+Reserved area has been claimed by VBIOS including this FB access area; CAIL doesn't need to reserve any extra area for this purpose
+else //Non VGA case
+ if (FB_Size<=2Gb)
+ FBAccessAreaOffset= FB_Size - usFBUsedbyDrvInKB;
+ else
+ FBAccessAreaOffset= Aper_Size - usFBUsedbyDrvInKB
+
+CAIL needs to claim an reserved area defined by FBAccessAreaOffset and usFBUsedbyDrvInKB in non VGA case.*/
+
#define ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO 1
-typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO {
- ULONG ulStartAddrUsedByFirmware;
- USHORT usFirmwareUseInKb;
- USHORT usReserved;
-} ATOM_FIRMWARE_VRAM_RESERVE_INFO;
+typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO
+{
+ ULONG ulStartAddrUsedByFirmware;
+ USHORT usFirmwareUseInKb;
+ USHORT usReserved;
+}ATOM_FIRMWARE_VRAM_RESERVE_INFO;
-typedef struct _ATOM_VRAM_USAGE_BY_FIRMWARE {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_FIRMWARE_VRAM_RESERVE_INFO
- asFirmwareVramReserveInfo[ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO];
-} ATOM_VRAM_USAGE_BY_FIRMWARE;
+typedef struct _ATOM_VRAM_USAGE_BY_FIRMWARE
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_FIRMWARE_VRAM_RESERVE_INFO asFirmwareVramReserveInfo[ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO];
+}ATOM_VRAM_USAGE_BY_FIRMWARE;
-/****************************************************************************/
-/* Structure used in GPIO_Pin_LUTTable */
-/****************************************************************************/
-typedef struct _ATOM_GPIO_PIN_ASSIGNMENT {
- USHORT usGpioPin_AIndex;
- UCHAR ucGpioPinBitShift;
- UCHAR ucGPIO_ID;
-} ATOM_GPIO_PIN_ASSIGNMENT;
+// change verion to 1.5, when allow driver to allocate the vram area for command table access.
+typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO_V1_5
+{
+ ULONG ulStartAddrUsedByFirmware;
+ USHORT usFirmwareUseInKb;
+ USHORT usFBUsedByDrvInKb;
+}ATOM_FIRMWARE_VRAM_RESERVE_INFO_V1_5;
-typedef struct _ATOM_GPIO_PIN_LUT {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_GPIO_PIN_ASSIGNMENT asGPIO_Pin[1];
-} ATOM_GPIO_PIN_LUT;
+typedef struct _ATOM_VRAM_USAGE_BY_FIRMWARE_V1_5
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_FIRMWARE_VRAM_RESERVE_INFO_V1_5 asFirmwareVramReserveInfo[ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO];
+}ATOM_VRAM_USAGE_BY_FIRMWARE_V1_5;
+
+/****************************************************************************/
+// Structure used in GPIO_Pin_LUTTable
+/****************************************************************************/
+typedef struct _ATOM_GPIO_PIN_ASSIGNMENT
+{
+ USHORT usGpioPin_AIndex;
+ UCHAR ucGpioPinBitShift;
+ UCHAR ucGPIO_ID;
+}ATOM_GPIO_PIN_ASSIGNMENT;
-/****************************************************************************/
-/* Structure used in ComponentVideoInfoTable */
-/****************************************************************************/
+typedef struct _ATOM_GPIO_PIN_LUT
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_GPIO_PIN_ASSIGNMENT asGPIO_Pin[1];
+}ATOM_GPIO_PIN_LUT;
+
+/****************************************************************************/
+// Structure used in ComponentVideoInfoTable
+/****************************************************************************/
#define GPIO_PIN_ACTIVE_HIGH 0x1
#define MAX_SUPPORTED_CV_STANDARDS 5
-/* definitions for ATOM_D_INFO.ucSettings */
-#define ATOM_GPIO_SETTINGS_BITSHIFT_MASK 0x1F /* [4:0] */
-#define ATOM_GPIO_SETTINGS_RESERVED_MASK 0x60 /* [6:5] = must be zeroed out */
-#define ATOM_GPIO_SETTINGS_ACTIVE_MASK 0x80 /* [7] */
+// definitions for ATOM_D_INFO.ucSettings
+#define ATOM_GPIO_SETTINGS_BITSHIFT_MASK 0x1F // [4:0]
+#define ATOM_GPIO_SETTINGS_RESERVED_MASK 0x60 // [6:5] = must be zeroed out
+#define ATOM_GPIO_SETTINGS_ACTIVE_MASK 0x80 // [7]
-typedef struct _ATOM_GPIO_INFO {
- USHORT usAOffset;
- UCHAR ucSettings;
- UCHAR ucReserved;
-} ATOM_GPIO_INFO;
+typedef struct _ATOM_GPIO_INFO
+{
+ USHORT usAOffset;
+ UCHAR ucSettings;
+ UCHAR ucReserved;
+}ATOM_GPIO_INFO;
-/* definitions for ATOM_COMPONENT_VIDEO_INFO.ucMiscInfo (bit vector) */
+// definitions for ATOM_COMPONENT_VIDEO_INFO.ucMiscInfo (bit vector)
#define ATOM_CV_RESTRICT_FORMAT_SELECTION 0x2
-/* definitions for ATOM_COMPONENT_VIDEO_INFO.uc480i/uc480p/uc720p/uc1080i */
-#define ATOM_GPIO_DEFAULT_MODE_EN 0x80 /* [7]; */
-#define ATOM_GPIO_SETTING_PERMODE_MASK 0x7F /* [6:0] */
-
-/* definitions for ATOM_COMPONENT_VIDEO_INFO.ucLetterBoxMode */
-/* Line 3 out put 5V. */
-#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_A 0x01 /* represent gpio 3 state for 16:9 */
-#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_B 0x02 /* represent gpio 4 state for 16:9 */
-#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_SHIFT 0x0
-
-/* Line 3 out put 2.2V */
-#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_A 0x04 /* represent gpio 3 state for 4:3 Letter box */
-#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_B 0x08 /* represent gpio 4 state for 4:3 Letter box */
-#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_SHIFT 0x2
-
-/* Line 3 out put 0V */
-#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_A 0x10 /* represent gpio 3 state for 4:3 */
-#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_B 0x20 /* represent gpio 4 state for 4:3 */
-#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_SHIFT 0x4
-
-#define ATOM_CV_LINE3_ASPECTRATIO_MASK 0x3F /* bit [5:0] */
-
-#define ATOM_CV_LINE3_ASPECTRATIO_EXIST 0x80 /* bit 7 */
-
-/* GPIO bit index in gpio setting per mode value, also represend the block no. in gpio blocks. */
-#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_A 3 /* bit 3 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode. */
-#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_B 4 /* bit 4 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode. */
-
-typedef struct _ATOM_COMPONENT_VIDEO_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- USHORT usMask_PinRegisterIndex;
- USHORT usEN_PinRegisterIndex;
- USHORT usY_PinRegisterIndex;
- USHORT usA_PinRegisterIndex;
- UCHAR ucBitShift;
- UCHAR ucPinActiveState; /* ucPinActiveState: Bit0=1 active high, =0 active low */
- ATOM_DTD_FORMAT sReserved; /* must be zeroed out */
- UCHAR ucMiscInfo;
- UCHAR uc480i;
- UCHAR uc480p;
- UCHAR uc720p;
- UCHAR uc1080i;
- UCHAR ucLetterBoxMode;
- UCHAR ucReserved[3];
- UCHAR ucNumOfWbGpioBlocks; /* For Component video D-Connector support. If zere, NTSC type connector */
- ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS];
- ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS];
-} ATOM_COMPONENT_VIDEO_INFO;
-
-/* ucTableFormatRevision=2 */
-/* ucTableContentRevision=1 */
-typedef struct _ATOM_COMPONENT_VIDEO_INFO_V21 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- UCHAR ucMiscInfo;
- UCHAR uc480i;
- UCHAR uc480p;
- UCHAR uc720p;
- UCHAR uc1080i;
- UCHAR ucReserved;
- UCHAR ucLetterBoxMode;
- UCHAR ucNumOfWbGpioBlocks; /* For Component video D-Connector support. If zere, NTSC type connector */
- ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS];
- ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS];
-} ATOM_COMPONENT_VIDEO_INFO_V21;
+// definitions for ATOM_COMPONENT_VIDEO_INFO.uc480i/uc480p/uc720p/uc1080i
+#define ATOM_GPIO_DEFAULT_MODE_EN 0x80 //[7];
+#define ATOM_GPIO_SETTING_PERMODE_MASK 0x7F //[6:0]
+
+// definitions for ATOM_COMPONENT_VIDEO_INFO.ucLetterBoxMode
+//Line 3 out put 5V.
+#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_A 0x01 //represent gpio 3 state for 16:9
+#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_B 0x02 //represent gpio 4 state for 16:9
+#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_SHIFT 0x0
+
+//Line 3 out put 2.2V
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_A 0x04 //represent gpio 3 state for 4:3 Letter box
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_B 0x08 //represent gpio 4 state for 4:3 Letter box
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_SHIFT 0x2
+
+//Line 3 out put 0V
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_A 0x10 //represent gpio 3 state for 4:3
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_B 0x20 //represent gpio 4 state for 4:3
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_SHIFT 0x4
+
+#define ATOM_CV_LINE3_ASPECTRATIO_MASK 0x3F // bit [5:0]
+
+#define ATOM_CV_LINE3_ASPECTRATIO_EXIST 0x80 //bit 7
+
+//GPIO bit index in gpio setting per mode value, also represend the block no. in gpio blocks.
+#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_A 3 //bit 3 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode.
+#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_B 4 //bit 4 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode.
+
+
+typedef struct _ATOM_COMPONENT_VIDEO_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usMask_PinRegisterIndex;
+ USHORT usEN_PinRegisterIndex;
+ USHORT usY_PinRegisterIndex;
+ USHORT usA_PinRegisterIndex;
+ UCHAR ucBitShift;
+ UCHAR ucPinActiveState; //ucPinActiveState: Bit0=1 active high, =0 active low
+ ATOM_DTD_FORMAT sReserved; // must be zeroed out
+ UCHAR ucMiscInfo;
+ UCHAR uc480i;
+ UCHAR uc480p;
+ UCHAR uc720p;
+ UCHAR uc1080i;
+ UCHAR ucLetterBoxMode;
+ UCHAR ucReserved[3];
+ UCHAR ucNumOfWbGpioBlocks; //For Component video D-Connector support. If zere, NTSC type connector
+ ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS];
+ ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS];
+}ATOM_COMPONENT_VIDEO_INFO;
+
+//ucTableFormatRevision=2
+//ucTableContentRevision=1
+typedef struct _ATOM_COMPONENT_VIDEO_INFO_V21
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucMiscInfo;
+ UCHAR uc480i;
+ UCHAR uc480p;
+ UCHAR uc720p;
+ UCHAR uc1080i;
+ UCHAR ucReserved;
+ UCHAR ucLetterBoxMode;
+ UCHAR ucNumOfWbGpioBlocks; //For Component video D-Connector support. If zere, NTSC type connector
+ ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS];
+ ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS];
+}ATOM_COMPONENT_VIDEO_INFO_V21;
#define ATOM_COMPONENT_VIDEO_INFO_LAST ATOM_COMPONENT_VIDEO_INFO_V21
-/****************************************************************************/
-/* Structure used in object_InfoTable */
-/****************************************************************************/
-typedef struct _ATOM_OBJECT_HEADER {
- ATOM_COMMON_TABLE_HEADER sHeader;
- USHORT usDeviceSupport;
- USHORT usConnectorObjectTableOffset;
- USHORT usRouterObjectTableOffset;
- USHORT usEncoderObjectTableOffset;
- USHORT usProtectionObjectTableOffset; /* only available when Protection block is independent. */
- USHORT usDisplayPathTableOffset;
-} ATOM_OBJECT_HEADER;
-
-typedef struct _ATOM_DISPLAY_OBJECT_PATH {
- USHORT usDeviceTag; /* supported device */
- USHORT usSize; /* the size of ATOM_DISPLAY_OBJECT_PATH */
- USHORT usConnObjectId; /* Connector Object ID */
- USHORT usGPUObjectId; /* GPU ID */
- USHORT usGraphicObjIds[1]; /* 1st Encoder Obj source from GPU to last Graphic Obj destinate to connector. */
-} ATOM_DISPLAY_OBJECT_PATH;
-
-typedef struct _ATOM_DISPLAY_OBJECT_PATH_TABLE {
- UCHAR ucNumOfDispPath;
- UCHAR ucVersion;
- UCHAR ucPadding[2];
- ATOM_DISPLAY_OBJECT_PATH asDispPath[1];
-} ATOM_DISPLAY_OBJECT_PATH_TABLE;
-
-typedef struct _ATOM_OBJECT /* each object has this structure */
-{
- USHORT usObjectID;
- USHORT usSrcDstTableOffset;
- USHORT usRecordOffset; /* this pointing to a bunch of records defined below */
- USHORT usReserved;
-} ATOM_OBJECT;
-
-typedef struct _ATOM_OBJECT_TABLE /* Above 4 object table offset pointing to a bunch of objects all have this structure */
-{
- UCHAR ucNumberOfObjects;
- UCHAR ucPadding[3];
- ATOM_OBJECT asObjects[1];
-} ATOM_OBJECT_TABLE;
-
-typedef struct _ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT /* usSrcDstTableOffset pointing to this structure */
-{
- UCHAR ucNumberOfSrc;
- USHORT usSrcObjectID[1];
- UCHAR ucNumberOfDst;
- USHORT usDstObjectID[1];
-} ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT;
-
-/* Related definitions, all records are differnt but they have a commond header */
-typedef struct _ATOM_COMMON_RECORD_HEADER {
- UCHAR ucRecordType; /* An emun to indicate the record type */
- UCHAR ucRecordSize; /* The size of the whole record in byte */
-} ATOM_COMMON_RECORD_HEADER;
-
-#define ATOM_I2C_RECORD_TYPE 1
+/****************************************************************************/
+// Structure used in object_InfoTable
+/****************************************************************************/
+typedef struct _ATOM_OBJECT_HEADER
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usDeviceSupport;
+ USHORT usConnectorObjectTableOffset;
+ USHORT usRouterObjectTableOffset;
+ USHORT usEncoderObjectTableOffset;
+ USHORT usProtectionObjectTableOffset; //only available when Protection block is independent.
+ USHORT usDisplayPathTableOffset;
+}ATOM_OBJECT_HEADER;
+
+typedef struct _ATOM_OBJECT_HEADER_V3
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usDeviceSupport;
+ USHORT usConnectorObjectTableOffset;
+ USHORT usRouterObjectTableOffset;
+ USHORT usEncoderObjectTableOffset;
+ USHORT usProtectionObjectTableOffset; //only available when Protection block is independent.
+ USHORT usDisplayPathTableOffset;
+ USHORT usMiscObjectTableOffset;
+}ATOM_OBJECT_HEADER_V3;
+
+typedef struct _ATOM_DISPLAY_OBJECT_PATH
+{
+ USHORT usDeviceTag; //supported device
+ USHORT usSize; //the size of ATOM_DISPLAY_OBJECT_PATH
+ USHORT usConnObjectId; //Connector Object ID
+ USHORT usGPUObjectId; //GPU ID
+ USHORT usGraphicObjIds[1]; //1st Encoder Obj source from GPU to last Graphic Obj destinate to connector.
+}ATOM_DISPLAY_OBJECT_PATH;
+
+typedef struct _ATOM_DISPLAY_OBJECT_PATH_TABLE
+{
+ UCHAR ucNumOfDispPath;
+ UCHAR ucVersion;
+ UCHAR ucPadding[2];
+ ATOM_DISPLAY_OBJECT_PATH asDispPath[1];
+}ATOM_DISPLAY_OBJECT_PATH_TABLE;
+
+
+typedef struct _ATOM_OBJECT //each object has this structure
+{
+ USHORT usObjectID;
+ USHORT usSrcDstTableOffset;
+ USHORT usRecordOffset; //this pointing to a bunch of records defined below
+ USHORT usReserved;
+}ATOM_OBJECT;
+
+typedef struct _ATOM_OBJECT_TABLE //Above 4 object table offset pointing to a bunch of objects all have this structure
+{
+ UCHAR ucNumberOfObjects;
+ UCHAR ucPadding[3];
+ ATOM_OBJECT asObjects[1];
+}ATOM_OBJECT_TABLE;
+
+typedef struct _ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT //usSrcDstTableOffset pointing to this structure
+{
+ UCHAR ucNumberOfSrc;
+ USHORT usSrcObjectID[1];
+ UCHAR ucNumberOfDst;
+ USHORT usDstObjectID[1];
+}ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT;
+
+
+//Two definitions below are for OPM on MXM module designs
+
+#define EXT_HPDPIN_LUTINDEX_0 0
+#define EXT_HPDPIN_LUTINDEX_1 1
+#define EXT_HPDPIN_LUTINDEX_2 2
+#define EXT_HPDPIN_LUTINDEX_3 3
+#define EXT_HPDPIN_LUTINDEX_4 4
+#define EXT_HPDPIN_LUTINDEX_5 5
+#define EXT_HPDPIN_LUTINDEX_6 6
+#define EXT_HPDPIN_LUTINDEX_7 7
+#define MAX_NUMBER_OF_EXT_HPDPIN_LUT_ENTRIES (EXT_HPDPIN_LUTINDEX_7+1)
+
+#define EXT_AUXDDC_LUTINDEX_0 0
+#define EXT_AUXDDC_LUTINDEX_1 1
+#define EXT_AUXDDC_LUTINDEX_2 2
+#define EXT_AUXDDC_LUTINDEX_3 3
+#define EXT_AUXDDC_LUTINDEX_4 4
+#define EXT_AUXDDC_LUTINDEX_5 5
+#define EXT_AUXDDC_LUTINDEX_6 6
+#define EXT_AUXDDC_LUTINDEX_7 7
+#define MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES (EXT_AUXDDC_LUTINDEX_7+1)
+
+typedef struct _EXT_DISPLAY_PATH
+{
+ USHORT usDeviceTag; //A bit vector to show what devices are supported
+ USHORT usDeviceACPIEnum; //16bit device ACPI id.
+ USHORT usDeviceConnector; //A physical connector for displays to plug in, using object connector definitions
+ UCHAR ucExtAUXDDCLutIndex; //An index into external AUX/DDC channel LUT
+ UCHAR ucExtHPDPINLutIndex; //An index into external HPD pin LUT
+ USHORT usExtEncoderObjId; //external encoder object id
+ USHORT usReserved[3];
+}EXT_DISPLAY_PATH;
+
+#define NUMBER_OF_UCHAR_FOR_GUID 16
+#define MAX_NUMBER_OF_EXT_DISPLAY_PATH 7
+
+typedef struct _ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucGuid [NUMBER_OF_UCHAR_FOR_GUID]; // a GUID is a 16 byte long string
+ EXT_DISPLAY_PATH sPath[MAX_NUMBER_OF_EXT_DISPLAY_PATH]; // total of fixed 7 entries.
+ UCHAR ucChecksum; // a simple Checksum of the sum of whole structure equal to 0x0.
+ UCHAR Reserved [7]; // for potential expansion
+}ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO;
+
+//Related definitions, all records are differnt but they have a commond header
+typedef struct _ATOM_COMMON_RECORD_HEADER
+{
+ UCHAR ucRecordType; //An emun to indicate the record type
+ UCHAR ucRecordSize; //The size of the whole record in byte
+}ATOM_COMMON_RECORD_HEADER;
+
+
+#define ATOM_I2C_RECORD_TYPE 1
#define ATOM_HPD_INT_RECORD_TYPE 2
#define ATOM_OUTPUT_PROTECTION_RECORD_TYPE 3
#define ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE 4
-#define ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD_TYPE 5 /* Obsolete, switch to use GPIO_CNTL_RECORD_TYPE */
-#define ATOM_ENCODER_FPGA_CONTROL_RECORD_TYPE 6 /* Obsolete, switch to use GPIO_CNTL_RECORD_TYPE */
+#define ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD_TYPE 5 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE
+#define ATOM_ENCODER_FPGA_CONTROL_RECORD_TYPE 6 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE
#define ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD_TYPE 7
-#define ATOM_JTAG_RECORD_TYPE 8 /* Obsolete, switch to use GPIO_CNTL_RECORD_TYPE */
+#define ATOM_JTAG_RECORD_TYPE 8 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE
#define ATOM_OBJECT_GPIO_CNTL_RECORD_TYPE 9
#define ATOM_ENCODER_DVO_CF_RECORD_TYPE 10
#define ATOM_CONNECTOR_CF_RECORD_TYPE 11
#define ATOM_CONNECTOR_HARDCODE_DTD_RECORD_TYPE 12
#define ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE 13
-#define ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE 14
-#define ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE 15
-
-/* Must be updated when new record type is added,equal to that record definition! */
-#define ATOM_MAX_OBJECT_RECORD_NUMBER ATOM_CONNECTOR_CF_RECORD_TYPE
-
-typedef struct _ATOM_I2C_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- ATOM_I2C_ID_CONFIG sucI2cId;
- UCHAR ucI2CAddr; /* The slave address, it's 0 when the record is attached to connector for DDC */
-} ATOM_I2C_RECORD;
-
-typedef struct _ATOM_HPD_INT_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- UCHAR ucHPDIntGPIOID; /* Corresponding block in GPIO_PIN_INFO table gives the pin info */
- UCHAR ucPlugged_PinState;
-} ATOM_HPD_INT_RECORD;
-
-typedef struct _ATOM_OUTPUT_PROTECTION_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- UCHAR ucProtectionFlag;
- UCHAR ucReserved;
-} ATOM_OUTPUT_PROTECTION_RECORD;
-
-typedef struct _ATOM_CONNECTOR_DEVICE_TAG {
- ULONG ulACPIDeviceEnum; /* Reserved for now */
- USHORT usDeviceID; /* This Id is same as "ATOM_DEVICE_XXX_SUPPORT" */
- USHORT usPadding;
-} ATOM_CONNECTOR_DEVICE_TAG;
-
-typedef struct _ATOM_CONNECTOR_DEVICE_TAG_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- UCHAR ucNumberOfDevice;
- UCHAR ucReserved;
- ATOM_CONNECTOR_DEVICE_TAG asDeviceTag[1]; /* This Id is same as "ATOM_DEVICE_XXX_SUPPORT", 1 is only for allocation */
-} ATOM_CONNECTOR_DEVICE_TAG_RECORD;
-
-typedef struct _ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- UCHAR ucConfigGPIOID;
- UCHAR ucConfigGPIOState; /* Set to 1 when it's active high to enable external flow in */
- UCHAR ucFlowinGPIPID;
- UCHAR ucExtInGPIPID;
-} ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD;
-
-typedef struct _ATOM_ENCODER_FPGA_CONTROL_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- UCHAR ucCTL1GPIO_ID;
- UCHAR ucCTL1GPIOState; /* Set to 1 when it's active high */
- UCHAR ucCTL2GPIO_ID;
- UCHAR ucCTL2GPIOState; /* Set to 1 when it's active high */
- UCHAR ucCTL3GPIO_ID;
- UCHAR ucCTL3GPIOState; /* Set to 1 when it's active high */
- UCHAR ucCTLFPGA_IN_ID;
- UCHAR ucPadding[3];
-} ATOM_ENCODER_FPGA_CONTROL_RECORD;
-
-typedef struct _ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- UCHAR ucGPIOID; /* Corresponding block in GPIO_PIN_INFO table gives the pin info */
- UCHAR ucTVActiveState; /* Indicating when the pin==0 or 1 when TV is connected */
-} ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD;
-
-typedef struct _ATOM_JTAG_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- UCHAR ucTMSGPIO_ID;
- UCHAR ucTMSGPIOState; /* Set to 1 when it's active high */
- UCHAR ucTCKGPIO_ID;
- UCHAR ucTCKGPIOState; /* Set to 1 when it's active high */
- UCHAR ucTDOGPIO_ID;
- UCHAR ucTDOGPIOState; /* Set to 1 when it's active high */
- UCHAR ucTDIGPIO_ID;
- UCHAR ucTDIGPIOState; /* Set to 1 when it's active high */
- UCHAR ucPadding[2];
-} ATOM_JTAG_RECORD;
-
-/* The following generic object gpio pin control record type will replace JTAG_RECORD/FPGA_CONTROL_RECORD/DVI_EXT_INPUT_RECORD above gradually */
-typedef struct _ATOM_GPIO_PIN_CONTROL_PAIR {
- UCHAR ucGPIOID; /* GPIO_ID, find the corresponding ID in GPIO_LUT table */
- UCHAR ucGPIO_PinState; /* Pin state showing how to set-up the pin */
-} ATOM_GPIO_PIN_CONTROL_PAIR;
-
-typedef struct _ATOM_OBJECT_GPIO_CNTL_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- UCHAR ucFlags; /* Future expnadibility */
- UCHAR ucNumberOfPins; /* Number of GPIO pins used to control the object */
- ATOM_GPIO_PIN_CONTROL_PAIR asGpio[1]; /* the real gpio pin pair determined by number of pins ucNumberOfPins */
-} ATOM_OBJECT_GPIO_CNTL_RECORD;
-
-/* Definitions for GPIO pin state */
+#define ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE 14
+#define ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE 15
+#define ATOM_CONNECTOR_HPDPIN_LUT_RECORD_TYPE 16 //This is for the case when connectors are not known to object table
+#define ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE 17 //This is for the case when connectors are not known to object table
+#define ATOM_OBJECT_LINK_RECORD_TYPE 18 //Once this record is present under one object, it indicats the oobject is linked to another obj described by the record
+#define ATOM_CONNECTOR_REMOTE_CAP_RECORD_TYPE 19
+
+
+//Must be updated when new record type is added,equal to that record definition!
+#define ATOM_MAX_OBJECT_RECORD_NUMBER ATOM_CONNECTOR_REMOTE_CAP_RECORD_TYPE
+
+typedef struct _ATOM_I2C_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ ATOM_I2C_ID_CONFIG sucI2cId;
+ UCHAR ucI2CAddr; //The slave address, it's 0 when the record is attached to connector for DDC
+}ATOM_I2C_RECORD;
+
+typedef struct _ATOM_HPD_INT_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucHPDIntGPIOID; //Corresponding block in GPIO_PIN_INFO table gives the pin info
+ UCHAR ucPlugged_PinState;
+}ATOM_HPD_INT_RECORD;
+
+
+typedef struct _ATOM_OUTPUT_PROTECTION_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucProtectionFlag;
+ UCHAR ucReserved;
+}ATOM_OUTPUT_PROTECTION_RECORD;
+
+typedef struct _ATOM_CONNECTOR_DEVICE_TAG
+{
+ ULONG ulACPIDeviceEnum; //Reserved for now
+ USHORT usDeviceID; //This Id is same as "ATOM_DEVICE_XXX_SUPPORT"
+ USHORT usPadding;
+}ATOM_CONNECTOR_DEVICE_TAG;
+
+typedef struct _ATOM_CONNECTOR_DEVICE_TAG_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucNumberOfDevice;
+ UCHAR ucReserved;
+ ATOM_CONNECTOR_DEVICE_TAG asDeviceTag[1]; //This Id is same as "ATOM_DEVICE_XXX_SUPPORT", 1 is only for allocation
+}ATOM_CONNECTOR_DEVICE_TAG_RECORD;
+
+
+typedef struct _ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucConfigGPIOID;
+ UCHAR ucConfigGPIOState; //Set to 1 when it's active high to enable external flow in
+ UCHAR ucFlowinGPIPID;
+ UCHAR ucExtInGPIPID;
+}ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD;
+
+typedef struct _ATOM_ENCODER_FPGA_CONTROL_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucCTL1GPIO_ID;
+ UCHAR ucCTL1GPIOState; //Set to 1 when it's active high
+ UCHAR ucCTL2GPIO_ID;
+ UCHAR ucCTL2GPIOState; //Set to 1 when it's active high
+ UCHAR ucCTL3GPIO_ID;
+ UCHAR ucCTL3GPIOState; //Set to 1 when it's active high
+ UCHAR ucCTLFPGA_IN_ID;
+ UCHAR ucPadding[3];
+}ATOM_ENCODER_FPGA_CONTROL_RECORD;
+
+typedef struct _ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucGPIOID; //Corresponding block in GPIO_PIN_INFO table gives the pin info
+ UCHAR ucTVActiveState; //Indicating when the pin==0 or 1 when TV is connected
+}ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD;
+
+typedef struct _ATOM_JTAG_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucTMSGPIO_ID;
+ UCHAR ucTMSGPIOState; //Set to 1 when it's active high
+ UCHAR ucTCKGPIO_ID;
+ UCHAR ucTCKGPIOState; //Set to 1 when it's active high
+ UCHAR ucTDOGPIO_ID;
+ UCHAR ucTDOGPIOState; //Set to 1 when it's active high
+ UCHAR ucTDIGPIO_ID;
+ UCHAR ucTDIGPIOState; //Set to 1 when it's active high
+ UCHAR ucPadding[2];
+}ATOM_JTAG_RECORD;
+
+
+//The following generic object gpio pin control record type will replace JTAG_RECORD/FPGA_CONTROL_RECORD/DVI_EXT_INPUT_RECORD above gradually
+typedef struct _ATOM_GPIO_PIN_CONTROL_PAIR
+{
+ UCHAR ucGPIOID; // GPIO_ID, find the corresponding ID in GPIO_LUT table
+ UCHAR ucGPIO_PinState; // Pin state showing how to set-up the pin
+}ATOM_GPIO_PIN_CONTROL_PAIR;
+
+typedef struct _ATOM_OBJECT_GPIO_CNTL_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucFlags; // Future expnadibility
+ UCHAR ucNumberOfPins; // Number of GPIO pins used to control the object
+ ATOM_GPIO_PIN_CONTROL_PAIR asGpio[1]; // the real gpio pin pair determined by number of pins ucNumberOfPins
+}ATOM_OBJECT_GPIO_CNTL_RECORD;
+
+//Definitions for GPIO pin state
#define GPIO_PIN_TYPE_INPUT 0x00
#define GPIO_PIN_TYPE_OUTPUT 0x10
#define GPIO_PIN_TYPE_HW_CONTROL 0x20
-/* For GPIO_PIN_TYPE_OUTPUT the following is defined */
+//For GPIO_PIN_TYPE_OUTPUT the following is defined
#define GPIO_PIN_OUTPUT_STATE_MASK 0x01
#define GPIO_PIN_OUTPUT_STATE_SHIFT 0
#define GPIO_PIN_STATE_ACTIVE_LOW 0x0
#define GPIO_PIN_STATE_ACTIVE_HIGH 0x1
-typedef struct _ATOM_ENCODER_DVO_CF_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- ULONG ulStrengthControl; /* DVOA strength control for CF */
- UCHAR ucPadding[2];
-} ATOM_ENCODER_DVO_CF_RECORD;
+// Indexes to GPIO array in GLSync record
+#define ATOM_GPIO_INDEX_GLSYNC_REFCLK 0
+#define ATOM_GPIO_INDEX_GLSYNC_HSYNC 1
+#define ATOM_GPIO_INDEX_GLSYNC_VSYNC 2
+#define ATOM_GPIO_INDEX_GLSYNC_SWAP_REQ 3
+#define ATOM_GPIO_INDEX_GLSYNC_SWAP_GNT 4
+#define ATOM_GPIO_INDEX_GLSYNC_INTERRUPT 5
+#define ATOM_GPIO_INDEX_GLSYNC_V_RESET 6
+#define ATOM_GPIO_INDEX_GLSYNC_MAX 7
+
+typedef struct _ATOM_ENCODER_DVO_CF_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ ULONG ulStrengthControl; // DVOA strength control for CF
+ UCHAR ucPadding[2];
+}ATOM_ENCODER_DVO_CF_RECORD;
-/* value for ATOM_CONNECTOR_CF_RECORD.ucConnectedDvoBundle */
+// value for ATOM_CONNECTOR_CF_RECORD.ucConnectedDvoBundle
#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_UPPER12BITBUNDLEA 1
#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_LOWER12BITBUNDLEB 2
-typedef struct _ATOM_CONNECTOR_CF_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- USHORT usMaxPixClk;
- UCHAR ucFlowCntlGpioId;
- UCHAR ucSwapCntlGpioId;
- UCHAR ucConnectedDvoBundle;
- UCHAR ucPadding;
-} ATOM_CONNECTOR_CF_RECORD;
-
-typedef struct _ATOM_CONNECTOR_HARDCODE_DTD_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- ATOM_DTD_FORMAT asTiming;
-} ATOM_CONNECTOR_HARDCODE_DTD_RECORD;
-
-typedef struct _ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader; /* ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE */
- UCHAR ucSubConnectorType; /* CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D|X_ID_DUAL_LINK_DVI_D|HDMI_TYPE_A */
- UCHAR ucReserved;
-} ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD;
-
-typedef struct _ATOM_ROUTER_DDC_PATH_SELECT_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- UCHAR ucMuxType; /* decide the number of ucMuxState, =0, no pin state, =1: single state with complement, >1: multiple state */
- UCHAR ucMuxControlPin;
- UCHAR ucMuxState[2]; /* for alligment purpose */
-} ATOM_ROUTER_DDC_PATH_SELECT_RECORD;
-
-typedef struct _ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD {
- ATOM_COMMON_RECORD_HEADER sheader;
- UCHAR ucMuxType;
- UCHAR ucMuxControlPin;
- UCHAR ucMuxState[2]; /* for alligment purpose */
-} ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD;
-
-/* define ucMuxType */
+typedef struct _ATOM_CONNECTOR_CF_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ USHORT usMaxPixClk;
+ UCHAR ucFlowCntlGpioId;
+ UCHAR ucSwapCntlGpioId;
+ UCHAR ucConnectedDvoBundle;
+ UCHAR ucPadding;
+}ATOM_CONNECTOR_CF_RECORD;
+
+typedef struct _ATOM_CONNECTOR_HARDCODE_DTD_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ ATOM_DTD_FORMAT asTiming;
+}ATOM_CONNECTOR_HARDCODE_DTD_RECORD;
+
+typedef struct _ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader; //ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE
+ UCHAR ucSubConnectorType; //CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D|X_ID_DUAL_LINK_DVI_D|HDMI_TYPE_A
+ UCHAR ucReserved;
+}ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD;
+
+
+typedef struct _ATOM_ROUTER_DDC_PATH_SELECT_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucMuxType; //decide the number of ucMuxState, =0, no pin state, =1: single state with complement, >1: multiple state
+ UCHAR ucMuxControlPin;
+ UCHAR ucMuxState[2]; //for alligment purpose
+}ATOM_ROUTER_DDC_PATH_SELECT_RECORD;
+
+typedef struct _ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucMuxType;
+ UCHAR ucMuxControlPin;
+ UCHAR ucMuxState[2]; //for alligment purpose
+}ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD;
+
+// define ucMuxType
#define ATOM_ROUTER_MUX_PIN_STATE_MASK 0x0f
#define ATOM_ROUTER_MUX_PIN_SINGLE_STATE_COMPLEMENT 0x01
-/****************************************************************************/
-/* ASIC voltage data table */
-/****************************************************************************/
-typedef struct _ATOM_VOLTAGE_INFO_HEADER {
- USHORT usVDDCBaseLevel; /* In number of 50mv unit */
- USHORT usReserved; /* For possible extension table offset */
- UCHAR ucNumOfVoltageEntries;
- UCHAR ucBytesPerVoltageEntry;
- UCHAR ucVoltageStep; /* Indicating in how many mv increament is one step, 0.5mv unit */
- UCHAR ucDefaultVoltageEntry;
- UCHAR ucVoltageControlI2cLine;
- UCHAR ucVoltageControlAddress;
- UCHAR ucVoltageControlOffset;
-} ATOM_VOLTAGE_INFO_HEADER;
-
-typedef struct _ATOM_VOLTAGE_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_VOLTAGE_INFO_HEADER viHeader;
- UCHAR ucVoltageEntries[64]; /* 64 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries*ucBytesPerVoltageEntry */
-} ATOM_VOLTAGE_INFO;
-
-typedef struct _ATOM_VOLTAGE_FORMULA {
- USHORT usVoltageBaseLevel; /* In number of 1mv unit */
- USHORT usVoltageStep; /* Indicating in how many mv increament is one step, 1mv unit */
- UCHAR ucNumOfVoltageEntries; /* Number of Voltage Entry, which indicate max Voltage */
- UCHAR ucFlag; /* bit0=0 :step is 1mv =1 0.5mv */
- UCHAR ucBaseVID; /* if there is no lookup table, VID= BaseVID + ( Vol - BaseLevle ) /VoltageStep */
- UCHAR ucReserved;
- UCHAR ucVIDAdjustEntries[32]; /* 32 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries */
-} ATOM_VOLTAGE_FORMULA;
-
-typedef struct _ATOM_VOLTAGE_CONTROL {
- UCHAR ucVoltageControlId; /* Indicate it is controlled by I2C or GPIO or HW state machine */
- UCHAR ucVoltageControlI2cLine;
- UCHAR ucVoltageControlAddress;
- UCHAR ucVoltageControlOffset;
- USHORT usGpioPin_AIndex; /* GPIO_PAD register index */
- UCHAR ucGpioPinBitShift[9]; /* at most 8 pin support 255 VIDs, termintate with 0xff */
- UCHAR ucReserved;
-} ATOM_VOLTAGE_CONTROL;
-
-/* Define ucVoltageControlId */
+typedef struct _ATOM_CONNECTOR_HPDPIN_LUT_RECORD //record for ATOM_CONNECTOR_HPDPIN_LUT_RECORD_TYPE
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucHPDPINMap[MAX_NUMBER_OF_EXT_HPDPIN_LUT_ENTRIES]; //An fixed size array which maps external pins to internal GPIO_PIN_INFO table
+}ATOM_CONNECTOR_HPDPIN_LUT_RECORD;
+
+typedef struct _ATOM_CONNECTOR_AUXDDC_LUT_RECORD //record for ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ ATOM_I2C_ID_CONFIG ucAUXDDCMap[MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES]; //An fixed size array which maps external pins to internal DDC ID
+}ATOM_CONNECTOR_AUXDDC_LUT_RECORD;
+
+typedef struct _ATOM_OBJECT_LINK_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ USHORT usObjectID; //could be connector, encorder or other object in object.h
+}ATOM_OBJECT_LINK_RECORD;
+
+typedef struct _ATOM_CONNECTOR_REMOTE_CAP_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ USHORT usReserved;
+}ATOM_CONNECTOR_REMOTE_CAP_RECORD;
+
+/****************************************************************************/
+// ASIC voltage data table
+/****************************************************************************/
+typedef struct _ATOM_VOLTAGE_INFO_HEADER
+{
+ USHORT usVDDCBaseLevel; //In number of 50mv unit
+ USHORT usReserved; //For possible extension table offset
+ UCHAR ucNumOfVoltageEntries;
+ UCHAR ucBytesPerVoltageEntry;
+ UCHAR ucVoltageStep; //Indicating in how many mv increament is one step, 0.5mv unit
+ UCHAR ucDefaultVoltageEntry;
+ UCHAR ucVoltageControlI2cLine;
+ UCHAR ucVoltageControlAddress;
+ UCHAR ucVoltageControlOffset;
+}ATOM_VOLTAGE_INFO_HEADER;
+
+typedef struct _ATOM_VOLTAGE_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_VOLTAGE_INFO_HEADER viHeader;
+ UCHAR ucVoltageEntries[64]; //64 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries*ucBytesPerVoltageEntry
+}ATOM_VOLTAGE_INFO;
+
+
+typedef struct _ATOM_VOLTAGE_FORMULA
+{
+ USHORT usVoltageBaseLevel; // In number of 1mv unit
+ USHORT usVoltageStep; // Indicating in how many mv increament is one step, 1mv unit
+ UCHAR ucNumOfVoltageEntries; // Number of Voltage Entry, which indicate max Voltage
+ UCHAR ucFlag; // bit0=0 :step is 1mv =1 0.5mv
+ UCHAR ucBaseVID; // if there is no lookup table, VID= BaseVID + ( Vol - BaseLevle ) /VoltageStep
+ UCHAR ucReserved;
+ UCHAR ucVIDAdjustEntries[32]; // 32 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries
+}ATOM_VOLTAGE_FORMULA;
+
+typedef struct _VOLTAGE_LUT_ENTRY
+{
+ USHORT usVoltageCode; // The Voltage ID, either GPIO or I2C code
+ USHORT usVoltageValue; // The corresponding Voltage Value, in mV
+}VOLTAGE_LUT_ENTRY;
+
+typedef struct _ATOM_VOLTAGE_FORMULA_V2
+{
+ UCHAR ucNumOfVoltageEntries; // Number of Voltage Entry, which indicate max Voltage
+ UCHAR ucReserved[3];
+ VOLTAGE_LUT_ENTRY asVIDAdjustEntries[32];// 32 is for allocation, the actual number of entries is in ucNumOfVoltageEntries
+}ATOM_VOLTAGE_FORMULA_V2;
+
+typedef struct _ATOM_VOLTAGE_CONTROL
+{
+ UCHAR ucVoltageControlId; //Indicate it is controlled by I2C or GPIO or HW state machine
+ UCHAR ucVoltageControlI2cLine;
+ UCHAR ucVoltageControlAddress;
+ UCHAR ucVoltageControlOffset;
+ USHORT usGpioPin_AIndex; //GPIO_PAD register index
+ UCHAR ucGpioPinBitShift[9]; //at most 8 pin support 255 VIDs, termintate with 0xff
+ UCHAR ucReserved;
+}ATOM_VOLTAGE_CONTROL;
+
+// Define ucVoltageControlId
#define VOLTAGE_CONTROLLED_BY_HW 0x00
#define VOLTAGE_CONTROLLED_BY_I2C_MASK 0x7F
#define VOLTAGE_CONTROLLED_BY_GPIO 0x80
-#define VOLTAGE_CONTROL_ID_LM64 0x01 /* I2C control, used for R5xx Core Voltage */
-#define VOLTAGE_CONTROL_ID_DAC 0x02 /* I2C control, used for R5xx/R6xx MVDDC,MVDDQ or VDDCI */
-#define VOLTAGE_CONTROL_ID_VT116xM 0x03 /* I2C control, used for R6xx Core Voltage */
-#define VOLTAGE_CONTROL_ID_DS4402 0x04
-
-typedef struct _ATOM_VOLTAGE_OBJECT {
- UCHAR ucVoltageType; /* Indicate Voltage Source: VDDC, MVDDC, MVDDQ or MVDDCI */
- UCHAR ucSize; /* Size of Object */
- ATOM_VOLTAGE_CONTROL asControl; /* describ how to control */
- ATOM_VOLTAGE_FORMULA asFormula; /* Indicate How to convert real Voltage to VID */
-} ATOM_VOLTAGE_OBJECT;
-
-typedef struct _ATOM_VOLTAGE_OBJECT_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_VOLTAGE_OBJECT asVoltageObj[3]; /* Info for Voltage control */
-} ATOM_VOLTAGE_OBJECT_INFO;
-
-typedef struct _ATOM_LEAKID_VOLTAGE {
- UCHAR ucLeakageId;
- UCHAR ucReserved;
- USHORT usVoltage;
-} ATOM_LEAKID_VOLTAGE;
-
-typedef struct _ATOM_ASIC_PROFILE_VOLTAGE {
- UCHAR ucProfileId;
- UCHAR ucReserved;
- USHORT usSize;
- USHORT usEfuseSpareStartAddr;
- USHORT usFuseIndex[8]; /* from LSB to MSB, Max 8bit,end of 0xffff if less than 8 efuse id, */
- ATOM_LEAKID_VOLTAGE asLeakVol[2]; /* Leakid and relatd voltage */
-} ATOM_ASIC_PROFILE_VOLTAGE;
-
-/* ucProfileId */
-#define ATOM_ASIC_PROFILE_ID_EFUSE_VOLTAGE 1
+#define VOLTAGE_CONTROL_ID_LM64 0x01 //I2C control, used for R5xx Core Voltage
+#define VOLTAGE_CONTROL_ID_DAC 0x02 //I2C control, used for R5xx/R6xx MVDDC,MVDDQ or VDDCI
+#define VOLTAGE_CONTROL_ID_VT116xM 0x03 //I2C control, used for R6xx Core Voltage
+#define VOLTAGE_CONTROL_ID_DS4402 0x04
+
+typedef struct _ATOM_VOLTAGE_OBJECT
+{
+ UCHAR ucVoltageType; //Indicate Voltage Source: VDDC, MVDDC, MVDDQ or MVDDCI
+ UCHAR ucSize; //Size of Object
+ ATOM_VOLTAGE_CONTROL asControl; //describ how to control
+ ATOM_VOLTAGE_FORMULA asFormula; //Indicate How to convert real Voltage to VID
+}ATOM_VOLTAGE_OBJECT;
+
+typedef struct _ATOM_VOLTAGE_OBJECT_V2
+{
+ UCHAR ucVoltageType; //Indicate Voltage Source: VDDC, MVDDC, MVDDQ or MVDDCI
+ UCHAR ucSize; //Size of Object
+ ATOM_VOLTAGE_CONTROL asControl; //describ how to control
+ ATOM_VOLTAGE_FORMULA_V2 asFormula; //Indicate How to convert real Voltage to VID
+}ATOM_VOLTAGE_OBJECT_V2;
+
+typedef struct _ATOM_VOLTAGE_OBJECT_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_VOLTAGE_OBJECT asVoltageObj[3]; //Info for Voltage control
+}ATOM_VOLTAGE_OBJECT_INFO;
+
+typedef struct _ATOM_VOLTAGE_OBJECT_INFO_V2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_VOLTAGE_OBJECT_V2 asVoltageObj[3]; //Info for Voltage control
+}ATOM_VOLTAGE_OBJECT_INFO_V2;
+
+typedef struct _ATOM_LEAKID_VOLTAGE
+{
+ UCHAR ucLeakageId;
+ UCHAR ucReserved;
+ USHORT usVoltage;
+}ATOM_LEAKID_VOLTAGE;
+
+typedef struct _ATOM_ASIC_PROFILE_VOLTAGE
+{
+ UCHAR ucProfileId;
+ UCHAR ucReserved;
+ USHORT usSize;
+ USHORT usEfuseSpareStartAddr;
+ USHORT usFuseIndex[8]; //from LSB to MSB, Max 8bit,end of 0xffff if less than 8 efuse id,
+ ATOM_LEAKID_VOLTAGE asLeakVol[2]; //Leakid and relatd voltage
+}ATOM_ASIC_PROFILE_VOLTAGE;
+
+//ucProfileId
+#define ATOM_ASIC_PROFILE_ID_EFUSE_VOLTAGE 1
#define ATOM_ASIC_PROFILE_ID_EFUSE_PERFORMANCE_VOLTAGE 1
#define ATOM_ASIC_PROFILE_ID_EFUSE_THERMAL_VOLTAGE 2
-typedef struct _ATOM_ASIC_PROFILING_INFO {
- ATOM_COMMON_TABLE_HEADER asHeader;
- ATOM_ASIC_PROFILE_VOLTAGE asVoltage;
-} ATOM_ASIC_PROFILING_INFO;
-
-typedef struct _ATOM_POWER_SOURCE_OBJECT {
- UCHAR ucPwrSrcId; /* Power source */
- UCHAR ucPwrSensorType; /* GPIO, I2C or none */
- UCHAR ucPwrSensId; /* if GPIO detect, it is GPIO id, if I2C detect, it is I2C id */
- UCHAR ucPwrSensSlaveAddr; /* Slave address if I2C detect */
- UCHAR ucPwrSensRegIndex; /* I2C register Index if I2C detect */
- UCHAR ucPwrSensRegBitMask; /* detect which bit is used if I2C detect */
- UCHAR ucPwrSensActiveState; /* high active or low active */
- UCHAR ucReserve[3]; /* reserve */
- USHORT usSensPwr; /* in unit of watt */
-} ATOM_POWER_SOURCE_OBJECT;
-
-typedef struct _ATOM_POWER_SOURCE_INFO {
- ATOM_COMMON_TABLE_HEADER asHeader;
- UCHAR asPwrbehave[16];
- ATOM_POWER_SOURCE_OBJECT asPwrObj[1];
-} ATOM_POWER_SOURCE_INFO;
-
-/* Define ucPwrSrcId */
+typedef struct _ATOM_ASIC_PROFILING_INFO
+{
+ ATOM_COMMON_TABLE_HEADER asHeader;
+ ATOM_ASIC_PROFILE_VOLTAGE asVoltage;
+}ATOM_ASIC_PROFILING_INFO;
+
+typedef struct _ATOM_POWER_SOURCE_OBJECT
+{
+ UCHAR ucPwrSrcId; // Power source
+ UCHAR ucPwrSensorType; // GPIO, I2C or none
+ UCHAR ucPwrSensId; // if GPIO detect, it is GPIO id, if I2C detect, it is I2C id
+ UCHAR ucPwrSensSlaveAddr; // Slave address if I2C detect
+ UCHAR ucPwrSensRegIndex; // I2C register Index if I2C detect
+ UCHAR ucPwrSensRegBitMask; // detect which bit is used if I2C detect
+ UCHAR ucPwrSensActiveState; // high active or low active
+ UCHAR ucReserve[3]; // reserve
+ USHORT usSensPwr; // in unit of watt
+}ATOM_POWER_SOURCE_OBJECT;
+
+typedef struct _ATOM_POWER_SOURCE_INFO
+{
+ ATOM_COMMON_TABLE_HEADER asHeader;
+ UCHAR asPwrbehave[16];
+ ATOM_POWER_SOURCE_OBJECT asPwrObj[1];
+}ATOM_POWER_SOURCE_INFO;
+
+
+//Define ucPwrSrcId
#define POWERSOURCE_PCIE_ID1 0x00
#define POWERSOURCE_6PIN_CONNECTOR_ID1 0x01
#define POWERSOURCE_8PIN_CONNECTOR_ID1 0x02
#define POWERSOURCE_6PIN_CONNECTOR_ID2 0x04
#define POWERSOURCE_8PIN_CONNECTOR_ID2 0x08
-/* define ucPwrSensorId */
+//define ucPwrSensorId
#define POWER_SENSOR_ALWAYS 0x00
#define POWER_SENSOR_GPIO 0x01
#define POWER_SENSOR_I2C 0x02
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V6
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulBootUpEngineClock;
+ ULONG ulDentistVCOFreq;
+ ULONG ulBootUpUMAClock;
+ ULONG ulReserved1[8];
+ ULONG ulBootUpReqDisplayVector;
+ ULONG ulOtherDisplayMisc;
+ ULONG ulGPUCapInfo;
+ ULONG ulReserved2[3];
+ ULONG ulSystemConfig;
+ ULONG ulCPUCapInfo;
+ USHORT usMaxNBVoltage;
+ USHORT usMinNBVoltage;
+ USHORT usBootUpNBVoltage;
+ USHORT usExtDispConnInfoOffset;
+ UCHAR ucHtcTmpLmt;
+ UCHAR ucTjOffset;
+ UCHAR ucMemoryType;
+ UCHAR ucUMAChannelNumber;
+ ULONG ulCSR_M3_ARB_CNTL_DEFAULT[10];
+ ULONG ulCSR_M3_ARB_CNTL_UVD[10];
+ ULONG ulCSR_M3_ARB_CNTL_FS3D[10];
+ ULONG ulReserved3[42];
+ ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo;
+}ATOM_INTEGRATED_SYSTEM_INFO_V6;
+
+/**********************************************************************************************************************
+// ATOM_INTEGRATED_SYSTEM_INFO_V6 Description
+//ulBootUpEngineClock: VBIOS bootup Engine clock frequency, in 10kHz unit.
+//ulDentistVCOFreq: Dentist VCO clock in 10kHz unit.
+//ulBootUpUMAClock: System memory boot up clock frequency in 10Khz unit.
+//ulReserved1[8] Reserved by now, must be 0x0.
+//ulBootUpReqDisplayVector VBIOS boot up display IDs
+// ATOM_DEVICE_CRT1_SUPPORT 0x0001
+// ATOM_DEVICE_CRT2_SUPPORT 0x0010
+// ATOM_DEVICE_DFP1_SUPPORT 0x0008
+// ATOM_DEVICE_DFP6_SUPPORT 0x0040
+// ATOM_DEVICE_DFP2_SUPPORT 0x0080
+// ATOM_DEVICE_DFP3_SUPPORT 0x0200
+// ATOM_DEVICE_DFP4_SUPPORT 0x0400
+// ATOM_DEVICE_DFP5_SUPPORT 0x0800
+// ATOM_DEVICE_LCD1_SUPPORT 0x0002
+//ulOtherDisplayMisc Other display related flags, not defined yet.
+//ulGPUCapInfo TBD
+//ulReserved2[3] must be 0x0 for the reserved.
+//ulSystemConfig TBD
+//ulCPUCapInfo TBD
+//usMaxNBVoltage High NB voltage in unit of mv, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse.
+//usMinNBVoltage Low NB voltage in unit of mv, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse.
+//usBootUpNBVoltage Boot up NB voltage in unit of mv.
+//ucHtcTmpLmt Bit [22:16] of D24F3x64 Thermal Control (HTC) Register.
+//ucTjOffset Bit [28:22] of D24F3xE4 Thermtrip Status Register,may not be needed.
+//ucMemoryType [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved.
+//ucUMAChannelNumber System memory channel numbers.
+//usExtDispConnectionInfoOffset ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO offset relative to beginning of this table.
+//ulCSR_M3_ARB_CNTL_DEFAULT[10] Arrays with values for CSR M3 arbiter for default
+//ulCSR_M3_ARB_CNTL_UVD[10] Arrays with values for CSR M3 arbiter for UVD playback.
+//ulCSR_M3_ARB_CNTL_FS3D[10] Arrays with values for CSR M3 arbiter for Full Screen 3D applications.
+**********************************************************************************************************************/
+
/**************************************************************************/
-/* This portion is only used when ext thermal chip or engine/memory clock SS chip is populated on a design */
-/* Memory SS Info Table */
-/* Define Memory Clock SS chip ID */
+// This portion is only used when ext thermal chip or engine/memory clock SS chip is populated on a design
+//Memory SS Info Table
+//Define Memory Clock SS chip ID
#define ICS91719 1
#define ICS91720 2
-/* Define one structure to inform SW a "block of data" writing to external SS chip via I2C protocol */
-typedef struct _ATOM_I2C_DATA_RECORD {
- UCHAR ucNunberOfBytes; /* Indicates how many bytes SW needs to write to the external ASIC for one block, besides to "Start" and "Stop" */
- UCHAR ucI2CData[1]; /* I2C data in bytes, should be less than 16 bytes usually */
-} ATOM_I2C_DATA_RECORD;
-
-/* Define one structure to inform SW how many blocks of data writing to external SS chip via I2C protocol, in addition to other information */
-typedef struct _ATOM_I2C_DEVICE_SETUP_INFO {
- ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; /* I2C line and HW/SW assisted cap. */
- UCHAR ucSSChipID; /* SS chip being used */
- UCHAR ucSSChipSlaveAddr; /* Slave Address to set up this SS chip */
- UCHAR ucNumOfI2CDataRecords; /* number of data block */
- ATOM_I2C_DATA_RECORD asI2CData[1];
-} ATOM_I2C_DEVICE_SETUP_INFO;
-
-/* ========================================================================================== */
-typedef struct _ATOM_ASIC_MVDD_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_I2C_DEVICE_SETUP_INFO asI2CSetup[1];
-} ATOM_ASIC_MVDD_INFO;
-
-/* ========================================================================================== */
+//Define one structure to inform SW a "block of data" writing to external SS chip via I2C protocol
+typedef struct _ATOM_I2C_DATA_RECORD
+{
+ UCHAR ucNunberOfBytes; //Indicates how many bytes SW needs to write to the external ASIC for one block, besides to "Start" and "Stop"
+ UCHAR ucI2CData[1]; //I2C data in bytes, should be less than 16 bytes usually
+}ATOM_I2C_DATA_RECORD;
+
+
+//Define one structure to inform SW how many blocks of data writing to external SS chip via I2C protocol, in addition to other information
+typedef struct _ATOM_I2C_DEVICE_SETUP_INFO
+{
+ ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; //I2C line and HW/SW assisted cap.
+ UCHAR ucSSChipID; //SS chip being used
+ UCHAR ucSSChipSlaveAddr; //Slave Address to set up this SS chip
+ UCHAR ucNumOfI2CDataRecords; //number of data block
+ ATOM_I2C_DATA_RECORD asI2CData[1];
+}ATOM_I2C_DEVICE_SETUP_INFO;
+
+//==========================================================================================
+typedef struct _ATOM_ASIC_MVDD_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_I2C_DEVICE_SETUP_INFO asI2CSetup[1];
+}ATOM_ASIC_MVDD_INFO;
+
+//==========================================================================================
#define ATOM_MCLK_SS_INFO ATOM_ASIC_MVDD_INFO
-/* ========================================================================================== */
+//==========================================================================================
/**************************************************************************/
-typedef struct _ATOM_ASIC_SS_ASSIGNMENT {
- ULONG ulTargetClockRange; /* Clock Out frequence (VCO ), in unit of 10Khz */
- USHORT usSpreadSpectrumPercentage; /* in unit of 0.01% */
- USHORT usSpreadRateInKhz; /* in unit of kHz, modulation freq */
- UCHAR ucClockIndication; /* Indicate which clock source needs SS */
- UCHAR ucSpreadSpectrumMode; /* Bit1=0 Down Spread,=1 Center Spread. */
- UCHAR ucReserved[2];
-} ATOM_ASIC_SS_ASSIGNMENT;
-
-/* Define ucSpreadSpectrumType */
+typedef struct _ATOM_ASIC_SS_ASSIGNMENT
+{
+ ULONG ulTargetClockRange; //Clock Out frequence (VCO ), in unit of 10Khz
+ USHORT usSpreadSpectrumPercentage; //in unit of 0.01%
+ USHORT usSpreadRateInKhz; //in unit of kHz, modulation freq
+ UCHAR ucClockIndication; //Indicate which clock source needs SS
+ UCHAR ucSpreadSpectrumMode; //Bit1=0 Down Spread,=1 Center Spread.
+ UCHAR ucReserved[2];
+}ATOM_ASIC_SS_ASSIGNMENT;
+
+//Define ucClockIndication, SW uses the IDs below to search if the SS is requried/enabled on a clock branch/signal type.
+//SS is not required or enabled if a match is not found.
#define ASIC_INTERNAL_MEMORY_SS 1
#define ASIC_INTERNAL_ENGINE_SS 2
-#define ASIC_INTERNAL_UVD_SS 3
+#define ASIC_INTERNAL_UVD_SS 3
+#define ASIC_INTERNAL_SS_ON_TMDS 4
+#define ASIC_INTERNAL_SS_ON_HDMI 5
+#define ASIC_INTERNAL_SS_ON_LVDS 6
+#define ASIC_INTERNAL_SS_ON_DP 7
+#define ASIC_INTERNAL_SS_ON_DCPLL 8
+
+typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V2
+{
+ ULONG ulTargetClockRange; //For mem/engine/uvd, Clock Out frequence (VCO ), in unit of 10Khz
+ //For TMDS/HDMI/LVDS, it is pixel clock , for DP, it is link clock ( 27000 or 16200 )
+ USHORT usSpreadSpectrumPercentage; //in unit of 0.01%
+ USHORT usSpreadRateIn10Hz; //in unit of 10Hz, modulation freq
+ UCHAR ucClockIndication; //Indicate which clock source needs SS
+ UCHAR ucSpreadSpectrumMode; //Bit0=0 Down Spread,=1 Center Spread, bit1=0: internal SS bit1=1: external SS
+ UCHAR ucReserved[2];
+}ATOM_ASIC_SS_ASSIGNMENT_V2;
+
+//ucSpreadSpectrumMode
+//#define ATOM_SS_DOWN_SPREAD_MODE_MASK 0x00000000
+//#define ATOM_SS_DOWN_SPREAD_MODE 0x00000000
+//#define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001
+//#define ATOM_SS_CENTRE_SPREAD_MODE 0x00000001
+//#define ATOM_INTERNAL_SS_MASK 0x00000000
+//#define ATOM_EXTERNAL_SS_MASK 0x00000002
+
+typedef struct _ATOM_ASIC_INTERNAL_SS_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_ASIC_SS_ASSIGNMENT asSpreadSpectrum[4];
+}ATOM_ASIC_INTERNAL_SS_INFO;
-typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_ASIC_SS_ASSIGNMENT asSpreadSpectrum[4];
-} ATOM_ASIC_INTERNAL_SS_INFO;
+typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_ASIC_SS_ASSIGNMENT_V2 asSpreadSpectrum[1]; //this is point only.
+}ATOM_ASIC_INTERNAL_SS_INFO_V2;
-/* ==============================Scratch Pad Definition Portion=============================== */
+typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V3
+{
+ ULONG ulTargetClockRange; //For mem/engine/uvd, Clock Out frequence (VCO ), in unit of 10Khz
+ //For TMDS/HDMI/LVDS, it is pixel clock , for DP, it is link clock ( 27000 or 16200 )
+ USHORT usSpreadSpectrumPercentage; //in unit of 0.01%
+ USHORT usSpreadRateIn10Hz; //in unit of 10Hz, modulation freq
+ UCHAR ucClockIndication; //Indicate which clock source needs SS
+ UCHAR ucSpreadSpectrumMode; //Bit0=0 Down Spread,=1 Center Spread, bit1=0: internal SS bit1=1: external SS
+ UCHAR ucReserved[2];
+}ATOM_ASIC_SS_ASSIGNMENT_V3;
+
+typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_ASIC_SS_ASSIGNMENT_V3 asSpreadSpectrum[1]; //this is pointer only.
+}ATOM_ASIC_INTERNAL_SS_INFO_V3;
+
+
+//==============================Scratch Pad Definition Portion===============================
#define ATOM_DEVICE_CONNECT_INFO_DEF 0
#define ATOM_ROM_LOCATION_DEF 1
#define ATOM_TV_STANDARD_DEF 2
@@ -2995,7 +3852,8 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_I2C_CHANNEL_STATUS_DEF 8
#define ATOM_I2C_CHANNEL_STATUS1_DEF 9
-/* BIOS_0_SCRATCH Definition */
+
+// BIOS_0_SCRATCH Definition
#define ATOM_S0_CRT1_MONO 0x00000001L
#define ATOM_S0_CRT1_COLOR 0x00000002L
#define ATOM_S0_CRT1_MASK (ATOM_S0_CRT1_MONO+ATOM_S0_CRT1_COLOR)
@@ -3008,6 +3866,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S0_CV_DIN_A 0x00000020L
#define ATOM_S0_CV_MASK_A (ATOM_S0_CV_A+ATOM_S0_CV_DIN_A)
+
#define ATOM_S0_CRT2_MONO 0x00000100L
#define ATOM_S0_CRT2_COLOR 0x00000200L
#define ATOM_S0_CRT2_MASK (ATOM_S0_CRT2_MONO+ATOM_S0_CRT2_COLOR)
@@ -3025,28 +3884,27 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S0_DFP2 0x00020000L
#define ATOM_S0_LCD1 0x00040000L
#define ATOM_S0_LCD2 0x00080000L
-#define ATOM_S0_TV2 0x00100000L
-#define ATOM_S0_DFP3 0x00200000L
-#define ATOM_S0_DFP4 0x00400000L
-#define ATOM_S0_DFP5 0x00800000L
+#define ATOM_S0_DFP6 0x00100000L
+#define ATOM_S0_DFP3 0x00200000L
+#define ATOM_S0_DFP4 0x00400000L
+#define ATOM_S0_DFP5 0x00800000L
-#define ATOM_S0_DFP_MASK \
- (ATOM_S0_DFP1 | ATOM_S0_DFP2 | ATOM_S0_DFP3 | ATOM_S0_DFP4 | ATOM_S0_DFP5)
+#define ATOM_S0_DFP_MASK ATOM_S0_DFP1 | ATOM_S0_DFP2 | ATOM_S0_DFP3 | ATOM_S0_DFP4 | ATOM_S0_DFP5 | ATOM_S0_DFP6
-#define ATOM_S0_FAD_REGISTER_BUG 0x02000000L /* If set, indicates we are running a PCIE asic with */
- /* the FAD/HDP reg access bug. Bit is read by DAL */
+#define ATOM_S0_FAD_REGISTER_BUG 0x02000000L // If set, indicates we are running a PCIE asic with
+ // the FAD/HDP reg access bug. Bit is read by DAL, this is obsolete from RV5xx
#define ATOM_S0_THERMAL_STATE_MASK 0x1C000000L
#define ATOM_S0_THERMAL_STATE_SHIFT 26
#define ATOM_S0_SYSTEM_POWER_STATE_MASK 0xE0000000L
-#define ATOM_S0_SYSTEM_POWER_STATE_SHIFT 29
+#define ATOM_S0_SYSTEM_POWER_STATE_SHIFT 29
#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_AC 1
#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_DC 2
#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LITEAC 3
-/* Byte aligned definition for BIOS usage */
+//Byte aligned defintion for BIOS usage
#define ATOM_S0_CRT1_MONOb0 0x01
#define ATOM_S0_CRT1_COLORb0 0x02
#define ATOM_S0_CRT1_MASKb0 (ATOM_S0_CRT1_MONOb0+ATOM_S0_CRT1_COLORb0)
@@ -3076,8 +3934,11 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S0_DFP2b2 0x02
#define ATOM_S0_LCD1b2 0x04
#define ATOM_S0_LCD2b2 0x08
-#define ATOM_S0_TV2b2 0x10
-#define ATOM_S0_DFP3b2 0x20
+#define ATOM_S0_DFP6b2 0x10
+#define ATOM_S0_DFP3b2 0x20
+#define ATOM_S0_DFP4b2 0x40
+#define ATOM_S0_DFP5b2 0x80
+
#define ATOM_S0_THERMAL_STATE_MASKb3 0x1C
#define ATOM_S0_THERMAL_STATE_SHIFTb3 2
@@ -3085,43 +3946,20 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S0_SYSTEM_POWER_STATE_MASKb3 0xE0
#define ATOM_S0_LCD1_SHIFT 18
-/* BIOS_1_SCRATCH Definition */
+// BIOS_1_SCRATCH Definition
#define ATOM_S1_ROM_LOCATION_MASK 0x0000FFFFL
#define ATOM_S1_PCI_BUS_DEV_MASK 0xFFFF0000L
-/* BIOS_2_SCRATCH Definition */
+// BIOS_2_SCRATCH Definition
#define ATOM_S2_TV1_STANDARD_MASK 0x0000000FL
#define ATOM_S2_CURRENT_BL_LEVEL_MASK 0x0000FF00L
#define ATOM_S2_CURRENT_BL_LEVEL_SHIFT 8
-#define ATOM_S2_CRT1_DPMS_STATE 0x00010000L
-#define ATOM_S2_LCD1_DPMS_STATE 0x00020000L
-#define ATOM_S2_TV1_DPMS_STATE 0x00040000L
-#define ATOM_S2_DFP1_DPMS_STATE 0x00080000L
-#define ATOM_S2_CRT2_DPMS_STATE 0x00100000L
-#define ATOM_S2_LCD2_DPMS_STATE 0x00200000L
-#define ATOM_S2_TV2_DPMS_STATE 0x00400000L
-#define ATOM_S2_DFP2_DPMS_STATE 0x00800000L
-#define ATOM_S2_CV_DPMS_STATE 0x01000000L
-#define ATOM_S2_DFP3_DPMS_STATE 0x02000000L
-#define ATOM_S2_DFP4_DPMS_STATE 0x04000000L
-#define ATOM_S2_DFP5_DPMS_STATE 0x08000000L
-
-#define ATOM_S2_DFP_DPM_STATE \
- (ATOM_S2_DFP1_DPMS_STATE | ATOM_S2_DFP2_DPMS_STATE | \
- ATOM_S2_DFP3_DPMS_STATE | ATOM_S2_DFP4_DPMS_STATE | \
- ATOM_S2_DFP5_DPMS_STATE)
-
-#define ATOM_S2_DEVICE_DPMS_STATE \
- (ATOM_S2_CRT1_DPMS_STATE + ATOM_S2_LCD1_DPMS_STATE + \
- ATOM_S2_TV1_DPMS_STATE + ATOM_S2_DFP_DPMS_STATE + \
- ATOM_S2_CRT2_DPMS_STATE + ATOM_S2_LCD2_DPMS_STATE + \
- ATOM_S2_TV2_DPMS_STATE + ATOM_S2_CV_DPMS_STATE)
-
#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK 0x0C000000L
#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK_SHIFT 26
#define ATOM_S2_FORCEDLOWPWRMODE_STATE_CHANGE 0x10000000L
+#define ATOM_S2_DEVICE_DPMS_STATE 0x00010000L
#define ATOM_S2_VRI_BRIGHT_ENABLE 0x20000000L
#define ATOM_S2_DISPLAY_ROTATION_0_DEGREE 0x0
@@ -3131,21 +3969,11 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S2_DISPLAY_ROTATION_DEGREE_SHIFT 30
#define ATOM_S2_DISPLAY_ROTATION_ANGLE_MASK 0xC0000000L
-/* Byte aligned definition for BIOS usage */
+
+//Byte aligned defintion for BIOS usage
#define ATOM_S2_TV1_STANDARD_MASKb0 0x0F
#define ATOM_S2_CURRENT_BL_LEVEL_MASKb1 0xFF
-#define ATOM_S2_CRT1_DPMS_STATEb2 0x01
-#define ATOM_S2_LCD1_DPMS_STATEb2 0x02
-#define ATOM_S2_TV1_DPMS_STATEb2 0x04
-#define ATOM_S2_DFP1_DPMS_STATEb2 0x08
-#define ATOM_S2_CRT2_DPMS_STATEb2 0x10
-#define ATOM_S2_LCD2_DPMS_STATEb2 0x20
-#define ATOM_S2_TV2_DPMS_STATEb2 0x40
-#define ATOM_S2_DFP2_DPMS_STATEb2 0x80
-#define ATOM_S2_CV_DPMS_STATEb3 0x01
-#define ATOM_S2_DFP3_DPMS_STATEb3 0x02
-#define ATOM_S2_DFP4_DPMS_STATEb3 0x04
-#define ATOM_S2_DFP5_DPMS_STATEb3 0x08
+#define ATOM_S2_DEVICE_DPMS_STATEb2 0x01
#define ATOM_S2_DEVICE_DPMS_MASKw1 0x3FF
#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASKb3 0x0C
@@ -3153,21 +3981,22 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S2_VRI_BRIGHT_ENABLEb3 0x20
#define ATOM_S2_ROTATION_STATE_MASKb3 0xC0
-/* BIOS_3_SCRATCH Definition */
+
+// BIOS_3_SCRATCH Definition
#define ATOM_S3_CRT1_ACTIVE 0x00000001L
#define ATOM_S3_LCD1_ACTIVE 0x00000002L
#define ATOM_S3_TV1_ACTIVE 0x00000004L
#define ATOM_S3_DFP1_ACTIVE 0x00000008L
#define ATOM_S3_CRT2_ACTIVE 0x00000010L
#define ATOM_S3_LCD2_ACTIVE 0x00000020L
-#define ATOM_S3_TV2_ACTIVE 0x00000040L
+#define ATOM_S3_DFP6_ACTIVE 0x00000040L
#define ATOM_S3_DFP2_ACTIVE 0x00000080L
#define ATOM_S3_CV_ACTIVE 0x00000100L
#define ATOM_S3_DFP3_ACTIVE 0x00000200L
#define ATOM_S3_DFP4_ACTIVE 0x00000400L
#define ATOM_S3_DFP5_ACTIVE 0x00000800L
-#define ATOM_S3_DEVICE_ACTIVE_MASK 0x000003FFL
+#define ATOM_S3_DEVICE_ACTIVE_MASK 0x00000FFFL
#define ATOM_S3_LCD_FULLEXPANSION_ACTIVE 0x00001000L
#define ATOM_S3_LCD_EXPANSION_ASPEC_RATIO_ACTIVE 0x00002000L
@@ -3178,7 +4007,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S3_DFP1_CRTC_ACTIVE 0x00080000L
#define ATOM_S3_CRT2_CRTC_ACTIVE 0x00100000L
#define ATOM_S3_LCD2_CRTC_ACTIVE 0x00200000L
-#define ATOM_S3_TV2_CRTC_ACTIVE 0x00400000L
+#define ATOM_S3_DFP6_CRTC_ACTIVE 0x00400000L
#define ATOM_S3_DFP2_CRTC_ACTIVE 0x00800000L
#define ATOM_S3_CV_CRTC_ACTIVE 0x01000000L
#define ATOM_S3_DFP3_CRTC_ACTIVE 0x02000000L
@@ -3187,17 +4016,18 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S3_DEVICE_CRTC_ACTIVE_MASK 0x0FFF0000L
#define ATOM_S3_ASIC_GUI_ENGINE_HUNG 0x20000000L
+//Below two definitions are not supported in pplib, but in the old powerplay in DAL
#define ATOM_S3_ALLOW_FAST_PWR_SWITCH 0x40000000L
#define ATOM_S3_RQST_GPU_USE_MIN_PWR 0x80000000L
-/* Byte aligned definition for BIOS usage */
+//Byte aligned defintion for BIOS usage
#define ATOM_S3_CRT1_ACTIVEb0 0x01
#define ATOM_S3_LCD1_ACTIVEb0 0x02
#define ATOM_S3_TV1_ACTIVEb0 0x04
#define ATOM_S3_DFP1_ACTIVEb0 0x08
#define ATOM_S3_CRT2_ACTIVEb0 0x10
#define ATOM_S3_LCD2_ACTIVEb0 0x20
-#define ATOM_S3_TV2_ACTIVEb0 0x40
+#define ATOM_S3_DFP6_ACTIVEb0 0x40
#define ATOM_S3_DFP2_ACTIVEb0 0x80
#define ATOM_S3_CV_ACTIVEb1 0x01
#define ATOM_S3_DFP3_ACTIVEb1 0x02
@@ -3212,7 +4042,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S3_DFP1_CRTC_ACTIVEb2 0x08
#define ATOM_S3_CRT2_CRTC_ACTIVEb2 0x10
#define ATOM_S3_LCD2_CRTC_ACTIVEb2 0x20
-#define ATOM_S3_TV2_CRTC_ACTIVEb2 0x40
+#define ATOM_S3_DFP6_CRTC_ACTIVEb2 0x40
#define ATOM_S3_DFP2_CRTC_ACTIVEb2 0x80
#define ATOM_S3_CV_CRTC_ACTIVEb3 0x01
#define ATOM_S3_DFP3_CRTC_ACTIVEb3 0x02
@@ -3221,35 +4051,31 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S3_ACTIVE_CRTC2w1 0xFFF
-#define ATOM_S3_ASIC_GUI_ENGINE_HUNGb3 0x20
-#define ATOM_S3_ALLOW_FAST_PWR_SWITCHb3 0x40
-#define ATOM_S3_RQST_GPU_USE_MIN_PWRb3 0x80
-
-/* BIOS_4_SCRATCH Definition */
+// BIOS_4_SCRATCH Definition
#define ATOM_S4_LCD1_PANEL_ID_MASK 0x000000FFL
#define ATOM_S4_LCD1_REFRESH_MASK 0x0000FF00L
#define ATOM_S4_LCD1_REFRESH_SHIFT 8
-/* Byte aligned definition for BIOS usage */
+//Byte aligned defintion for BIOS usage
#define ATOM_S4_LCD1_PANEL_ID_MASKb0 0x0FF
#define ATOM_S4_LCD1_REFRESH_MASKb1 ATOM_S4_LCD1_PANEL_ID_MASKb0
#define ATOM_S4_VRAM_INFO_MASKb2 ATOM_S4_LCD1_PANEL_ID_MASKb0
-/* BIOS_5_SCRATCH Definition, BIOS_5_SCRATCH is used by Firmware only !!!! */
+// BIOS_5_SCRATCH Definition, BIOS_5_SCRATCH is used by Firmware only !!!!
#define ATOM_S5_DOS_REQ_CRT1b0 0x01
#define ATOM_S5_DOS_REQ_LCD1b0 0x02
#define ATOM_S5_DOS_REQ_TV1b0 0x04
#define ATOM_S5_DOS_REQ_DFP1b0 0x08
#define ATOM_S5_DOS_REQ_CRT2b0 0x10
#define ATOM_S5_DOS_REQ_LCD2b0 0x20
-#define ATOM_S5_DOS_REQ_TV2b0 0x40
+#define ATOM_S5_DOS_REQ_DFP6b0 0x40
#define ATOM_S5_DOS_REQ_DFP2b0 0x80
#define ATOM_S5_DOS_REQ_CVb1 0x01
#define ATOM_S5_DOS_REQ_DFP3b1 0x02
#define ATOM_S5_DOS_REQ_DFP4b1 0x04
#define ATOM_S5_DOS_REQ_DFP5b1 0x08
-#define ATOM_S5_DOS_REQ_DEVICEw0 0x03FF
+#define ATOM_S5_DOS_REQ_DEVICEw0 0x0FFF
#define ATOM_S5_DOS_REQ_CRT1 0x0001
#define ATOM_S5_DOS_REQ_LCD1 0x0002
@@ -3257,22 +4083,21 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S5_DOS_REQ_DFP1 0x0008
#define ATOM_S5_DOS_REQ_CRT2 0x0010
#define ATOM_S5_DOS_REQ_LCD2 0x0020
-#define ATOM_S5_DOS_REQ_TV2 0x0040
+#define ATOM_S5_DOS_REQ_DFP6 0x0040
#define ATOM_S5_DOS_REQ_DFP2 0x0080
#define ATOM_S5_DOS_REQ_CV 0x0100
-#define ATOM_S5_DOS_REQ_DFP3 0x0200
-#define ATOM_S5_DOS_REQ_DFP4 0x0400
-#define ATOM_S5_DOS_REQ_DFP5 0x0800
+#define ATOM_S5_DOS_REQ_DFP3 0x0200
+#define ATOM_S5_DOS_REQ_DFP4 0x0400
+#define ATOM_S5_DOS_REQ_DFP5 0x0800
#define ATOM_S5_DOS_FORCE_CRT1b2 ATOM_S5_DOS_REQ_CRT1b0
#define ATOM_S5_DOS_FORCE_TV1b2 ATOM_S5_DOS_REQ_TV1b0
#define ATOM_S5_DOS_FORCE_CRT2b2 ATOM_S5_DOS_REQ_CRT2b0
#define ATOM_S5_DOS_FORCE_CVb3 ATOM_S5_DOS_REQ_CVb1
-#define ATOM_S5_DOS_FORCE_DEVICEw1 \
- (ATOM_S5_DOS_FORCE_CRT1b2 + ATOM_S5_DOS_FORCE_TV1b2 + \
- ATOM_S5_DOS_FORCE_CRT2b2 + (ATOM_S5_DOS_FORCE_CVb3 << 8))
+#define ATOM_S5_DOS_FORCE_DEVICEw1 (ATOM_S5_DOS_FORCE_CRT1b2+ATOM_S5_DOS_FORCE_TV1b2+ATOM_S5_DOS_FORCE_CRT2b2+\
+ (ATOM_S5_DOS_FORCE_CVb3<<8))
-/* BIOS_6_SCRATCH Definition */
+// BIOS_6_SCRATCH Definition
#define ATOM_S6_DEVICE_CHANGE 0x00000001L
#define ATOM_S6_SCALER_CHANGE 0x00000002L
#define ATOM_S6_LID_CHANGE 0x00000004L
@@ -3285,11 +4110,11 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S6_HW_I2C_BUSY_STATE 0x00000200L
#define ATOM_S6_THERMAL_STATE_CHANGE 0x00000400L
#define ATOM_S6_INTERRUPT_SET_BY_BIOS 0x00000800L
-#define ATOM_S6_REQ_LCD_EXPANSION_FULL 0x00001000L /* Normal expansion Request bit for LCD */
-#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO 0x00002000L /* Aspect ratio expansion Request bit for LCD */
+#define ATOM_S6_REQ_LCD_EXPANSION_FULL 0x00001000L //Normal expansion Request bit for LCD
+#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO 0x00002000L //Aspect ratio expansion Request bit for LCD
-#define ATOM_S6_DISPLAY_STATE_CHANGE 0x00004000L /* This bit is recycled when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_H_expansion */
-#define ATOM_S6_I2C_STATE_CHANGE 0x00008000L /* This bit is recycled,when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_V_expansion */
+#define ATOM_S6_DISPLAY_STATE_CHANGE 0x00004000L //This bit is recycled when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_H_expansion
+#define ATOM_S6_I2C_STATE_CHANGE 0x00008000L //This bit is recycled,when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_V_expansion
#define ATOM_S6_ACC_REQ_CRT1 0x00010000L
#define ATOM_S6_ACC_REQ_LCD1 0x00020000L
@@ -3297,7 +4122,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S6_ACC_REQ_DFP1 0x00080000L
#define ATOM_S6_ACC_REQ_CRT2 0x00100000L
#define ATOM_S6_ACC_REQ_LCD2 0x00200000L
-#define ATOM_S6_ACC_REQ_TV2 0x00400000L
+#define ATOM_S6_ACC_REQ_DFP6 0x00400000L
#define ATOM_S6_ACC_REQ_DFP2 0x00800000L
#define ATOM_S6_ACC_REQ_CV 0x01000000L
#define ATOM_S6_ACC_REQ_DFP3 0x02000000L
@@ -3310,7 +4135,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S6_VRI_BRIGHTNESS_CHANGE 0x40000000L
#define ATOM_S6_CONFIG_DISPLAY_CHANGE_MASK 0x80000000L
-/* Byte aligned definition for BIOS usage */
+//Byte aligned defintion for BIOS usage
#define ATOM_S6_DEVICE_CHANGEb0 0x01
#define ATOM_S6_SCALER_CHANGEb0 0x02
#define ATOM_S6_LID_CHANGEb0 0x04
@@ -3320,11 +4145,11 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S6_LID_STATEb0 0x40
#define ATOM_S6_DOCK_STATEb0 0x80
#define ATOM_S6_CRITICAL_STATEb1 0x01
-#define ATOM_S6_HW_I2C_BUSY_STATEb1 0x02
+#define ATOM_S6_HW_I2C_BUSY_STATEb1 0x02
#define ATOM_S6_THERMAL_STATE_CHANGEb1 0x04
#define ATOM_S6_INTERRUPT_SET_BY_BIOSb1 0x08
-#define ATOM_S6_REQ_LCD_EXPANSION_FULLb1 0x10
-#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIOb1 0x20
+#define ATOM_S6_REQ_LCD_EXPANSION_FULLb1 0x10
+#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIOb1 0x20
#define ATOM_S6_ACC_REQ_CRT1b2 0x01
#define ATOM_S6_ACC_REQ_LCD1b2 0x02
@@ -3332,12 +4157,12 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S6_ACC_REQ_DFP1b2 0x08
#define ATOM_S6_ACC_REQ_CRT2b2 0x10
#define ATOM_S6_ACC_REQ_LCD2b2 0x20
-#define ATOM_S6_ACC_REQ_TV2b2 0x40
+#define ATOM_S6_ACC_REQ_DFP6b2 0x40
#define ATOM_S6_ACC_REQ_DFP2b2 0x80
#define ATOM_S6_ACC_REQ_CVb3 0x01
-#define ATOM_S6_ACC_REQ_DFP3b3 0x02
-#define ATOM_S6_ACC_REQ_DFP4b3 0x04
-#define ATOM_S6_ACC_REQ_DFP5b3 0x08
+#define ATOM_S6_ACC_REQ_DFP3b3 0x02
+#define ATOM_S6_ACC_REQ_DFP4b3 0x04
+#define ATOM_S6_ACC_REQ_DFP5b3 0x08
#define ATOM_S6_ACC_REQ_DEVICEw1 ATOM_S5_DOS_REQ_DEVICEw0
#define ATOM_S6_SYSTEM_POWER_MODE_CHANGEb3 0x10
@@ -3366,7 +4191,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT 30
#define ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT 31
-/* BIOS_7_SCRATCH Definition, BIOS_7_SCRATCH is used by Firmware only !!!! */
+// BIOS_7_SCRATCH Definition, BIOS_7_SCRATCH is used by Firmware only !!!!
#define ATOM_S7_DOS_MODE_TYPEb0 0x03
#define ATOM_S7_DOS_MODE_VGAb0 0x00
#define ATOM_S7_DOS_MODE_VESAb0 0x01
@@ -3378,220 +4203,194 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
#define ATOM_S7_DOS_8BIT_DAC_EN_SHIFT 8
-/* BIOS_8_SCRATCH Definition */
+// BIOS_8_SCRATCH Definition
#define ATOM_S8_I2C_CHANNEL_BUSY_MASK 0x00000FFFF
-#define ATOM_S8_I2C_HW_ENGINE_BUSY_MASK 0x0FFFF0000
+#define ATOM_S8_I2C_HW_ENGINE_BUSY_MASK 0x0FFFF0000
#define ATOM_S8_I2C_CHANNEL_BUSY_SHIFT 0
#define ATOM_S8_I2C_ENGINE_BUSY_SHIFT 16
-/* BIOS_9_SCRATCH Definition */
-#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_MASK
+// BIOS_9_SCRATCH Definition
+#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_MASK
#define ATOM_S9_I2C_CHANNEL_COMPLETED_MASK 0x0000FFFF
#endif
-#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_MASK
+#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_MASK
#define ATOM_S9_I2C_CHANNEL_ABORTED_MASK 0xFFFF0000
#endif
-#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT
+#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT
#define ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT 0
#endif
-#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT
+#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT
#define ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT 16
#endif
+
#define ATOM_FLAG_SET 0x20
#define ATOM_FLAG_CLEAR 0
-#define CLEAR_ATOM_S6_ACC_MODE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_ACC_MODE_SHIFT | ATOM_FLAG_CLEAR)
-#define SET_ATOM_S6_DEVICE_CHANGE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_DEVICE_CHANGE_SHIFT | ATOM_FLAG_SET)
-#define SET_ATOM_S6_VRI_BRIGHTNESS_CHANGE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT | ATOM_FLAG_SET)
-#define SET_ATOM_S6_SCALER_CHANGE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_SCALER_CHANGE_SHIFT | ATOM_FLAG_SET)
-#define SET_ATOM_S6_LID_CHANGE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_LID_CHANGE_SHIFT | ATOM_FLAG_SET)
-
-#define SET_ATOM_S6_LID_STATE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) |\
- ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_SET)
-#define CLEAR_ATOM_S6_LID_STATE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_CLEAR)
-
-#define SET_ATOM_S6_DOCK_CHANGE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8)| \
- ATOM_S6_DOCKING_CHANGE_SHIFT | ATOM_FLAG_SET)
-#define SET_ATOM_S6_DOCK_STATE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_SET)
-#define CLEAR_ATOM_S6_DOCK_STATE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_CLEAR)
-
-#define SET_ATOM_S6_THERMAL_STATE_CHANGE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_THERMAL_STATE_CHANGE_SHIFT | ATOM_FLAG_SET)
-#define SET_ATOM_S6_SYSTEM_POWER_MODE_CHANGE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT | ATOM_FLAG_SET)
-#define SET_ATOM_S6_INTERRUPT_SET_BY_BIOS \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT | ATOM_FLAG_SET)
-
-#define SET_ATOM_S6_CRITICAL_STATE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_SET)
-#define CLEAR_ATOM_S6_CRITICAL_STATE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_CLEAR)
-
-#define SET_ATOM_S6_REQ_SCALER \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_SET)
-#define CLEAR_ATOM_S6_REQ_SCALER \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_CLEAR )
-
-#define SET_ATOM_S6_REQ_SCALER_ARATIO \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_SET )
-#define CLEAR_ATOM_S6_REQ_SCALER_ARATIO \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_CLEAR )
-
-#define SET_ATOM_S6_I2C_STATE_CHANGE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_I2C_STATE_CHANGE_SHIFT | ATOM_FLAG_SET )
-
-#define SET_ATOM_S6_DISPLAY_STATE_CHANGE \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT | ATOM_FLAG_SET )
-
-#define SET_ATOM_S6_DEVICE_RECONFIG \
- ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
- ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT | ATOM_FLAG_SET)
-#define CLEAR_ATOM_S0_LCD1 \
- ((ATOM_DEVICE_CONNECT_INFO_DEF << 8 ) | \
- ATOM_S0_LCD1_SHIFT | ATOM_FLAG_CLEAR )
-#define SET_ATOM_S7_DOS_8BIT_DAC_EN \
- ((ATOM_DOS_MODE_INFO_DEF << 8) | \
- ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_SET )
-#define CLEAR_ATOM_S7_DOS_8BIT_DAC_EN \
- ((ATOM_DOS_MODE_INFO_DEF << 8) | \
- ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_CLEAR )
+#define CLEAR_ATOM_S6_ACC_MODE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_ACC_MODE_SHIFT | ATOM_FLAG_CLEAR)
+#define SET_ATOM_S6_DEVICE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DEVICE_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_VRI_BRIGHTNESS_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_SCALER_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_SCALER_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_LID_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_CHANGE_SHIFT | ATOM_FLAG_SET)
-/****************************************************************************/
-/* Portion II: Definitinos only used in Driver */
+#define SET_ATOM_S6_LID_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S6_LID_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_CLEAR)
+
+#define SET_ATOM_S6_DOCK_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCKING_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_DOCK_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S6_DOCK_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_CLEAR)
+
+#define SET_ATOM_S6_THERMAL_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_THERMAL_STATE_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_SYSTEM_POWER_MODE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_INTERRUPT_SET_BY_BIOS ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT | ATOM_FLAG_SET)
+
+#define SET_ATOM_S6_CRITICAL_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S6_CRITICAL_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_CLEAR)
+
+#define SET_ATOM_S6_REQ_SCALER ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S6_REQ_SCALER ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_CLEAR )
+
+#define SET_ATOM_S6_REQ_SCALER_ARATIO ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_SET )
+#define CLEAR_ATOM_S6_REQ_SCALER_ARATIO ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_CLEAR )
+
+#define SET_ATOM_S6_I2C_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_I2C_STATE_CHANGE_SHIFT | ATOM_FLAG_SET )
+
+#define SET_ATOM_S6_DISPLAY_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT | ATOM_FLAG_SET )
+
+#define SET_ATOM_S6_DEVICE_RECONFIG ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S0_LCD1 ((ATOM_DEVICE_CONNECT_INFO_DEF << 8 )| ATOM_S0_LCD1_SHIFT | ATOM_FLAG_CLEAR )
+#define SET_ATOM_S7_DOS_8BIT_DAC_EN ((ATOM_DOS_MODE_INFO_DEF << 8 )|ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_SET )
+#define CLEAR_ATOM_S7_DOS_8BIT_DAC_EN ((ATOM_DOS_MODE_INFO_DEF << 8 )|ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_CLEAR )
+
+/****************************************************************************/
+//Portion II: Definitinos only used in Driver
/****************************************************************************/
-/* Macros used by driver */
+// Macros used by driver
+#ifdef __cplusplus
+#define GetIndexIntoMasterTable(MasterOrData, FieldName) ((reinterpret_cast<char*>(&(static_cast<ATOM_MASTER_LIST_OF_##MasterOrData##_TABLES*>(0))->FieldName)-static_cast<char*>(0))/sizeof(USHORT))
-#define GetIndexIntoMasterTable(MasterOrData, FieldName) (((char *)(&((ATOM_MASTER_LIST_OF_##MasterOrData##_TABLES *)0)->FieldName)-(char *)0)/sizeof(USHORT))
+#define GET_COMMAND_TABLE_COMMANDSET_REVISION(TABLE_HEADER_OFFSET) (((static_cast<ATOM_COMMON_TABLE_HEADER*>(TABLE_HEADER_OFFSET))->ucTableFormatRevision )&0x3F)
+#define GET_COMMAND_TABLE_PARAMETER_REVISION(TABLE_HEADER_OFFSET) (((static_cast<ATOM_COMMON_TABLE_HEADER*>(TABLE_HEADER_OFFSET))->ucTableContentRevision)&0x3F)
+#else // not __cplusplus
+#define GetIndexIntoMasterTable(MasterOrData, FieldName) (((char*)(&((ATOM_MASTER_LIST_OF_##MasterOrData##_TABLES*)0)->FieldName)-(char*)0)/sizeof(USHORT))
#define GET_COMMAND_TABLE_COMMANDSET_REVISION(TABLE_HEADER_OFFSET) ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableFormatRevision)&0x3F)
#define GET_COMMAND_TABLE_PARAMETER_REVISION(TABLE_HEADER_OFFSET) ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableContentRevision)&0x3F)
+#endif // __cplusplus
#define GET_DATA_TABLE_MAJOR_REVISION GET_COMMAND_TABLE_COMMANDSET_REVISION
#define GET_DATA_TABLE_MINOR_REVISION GET_COMMAND_TABLE_PARAMETER_REVISION
-/****************************************************************************/
-/* Portion III: Definitinos only used in VBIOS */
+/****************************************************************************/
+//Portion III: Definitinos only used in VBIOS
/****************************************************************************/
#define ATOM_DAC_SRC 0x80
#define ATOM_SRC_DAC1 0
#define ATOM_SRC_DAC2 0x80
-#ifdef UEFI_BUILD
-#define USHORT UTEMP
-#endif
-
-typedef struct _MEMORY_PLLINIT_PARAMETERS {
- ULONG ulTargetMemoryClock; /* In 10Khz unit */
- UCHAR ucAction; /* not define yet */
- UCHAR ucFbDiv_Hi; /* Fbdiv Hi byte */
- UCHAR ucFbDiv; /* FB value */
- UCHAR ucPostDiv; /* Post div */
-} MEMORY_PLLINIT_PARAMETERS;
+typedef struct _MEMORY_PLLINIT_PARAMETERS
+{
+ ULONG ulTargetMemoryClock; //In 10Khz unit
+ UCHAR ucAction; //not define yet
+ UCHAR ucFbDiv_Hi; //Fbdiv Hi byte
+ UCHAR ucFbDiv; //FB value
+ UCHAR ucPostDiv; //Post div
+}MEMORY_PLLINIT_PARAMETERS;
#define MEMORY_PLLINIT_PS_ALLOCATION MEMORY_PLLINIT_PARAMETERS
-#define GPIO_PIN_WRITE 0x01
+
+#define GPIO_PIN_WRITE 0x01
#define GPIO_PIN_READ 0x00
-typedef struct _GPIO_PIN_CONTROL_PARAMETERS {
- UCHAR ucGPIO_ID; /* return value, read from GPIO pins */
- UCHAR ucGPIOBitShift; /* define which bit in uGPIOBitVal need to be update */
- UCHAR ucGPIOBitVal; /* Set/Reset corresponding bit defined in ucGPIOBitMask */
- UCHAR ucAction; /* =GPIO_PIN_WRITE: Read; =GPIO_PIN_READ: Write */
-} GPIO_PIN_CONTROL_PARAMETERS;
-
-typedef struct _ENABLE_SCALER_PARAMETERS {
- UCHAR ucScaler; /* ATOM_SCALER1, ATOM_SCALER2 */
- UCHAR ucEnable; /* ATOM_SCALER_DISABLE or ATOM_SCALER_CENTER or ATOM_SCALER_EXPANSION */
- UCHAR ucTVStandard; /* */
- UCHAR ucPadding[1];
-} ENABLE_SCALER_PARAMETERS;
-#define ENABLE_SCALER_PS_ALLOCATION ENABLE_SCALER_PARAMETERS
-
-/* ucEnable: */
+typedef struct _GPIO_PIN_CONTROL_PARAMETERS
+{
+ UCHAR ucGPIO_ID; //return value, read from GPIO pins
+ UCHAR ucGPIOBitShift; //define which bit in uGPIOBitVal need to be update
+ UCHAR ucGPIOBitVal; //Set/Reset corresponding bit defined in ucGPIOBitMask
+ UCHAR ucAction; //=GPIO_PIN_WRITE: Read; =GPIO_PIN_READ: Write
+}GPIO_PIN_CONTROL_PARAMETERS;
+
+typedef struct _ENABLE_SCALER_PARAMETERS
+{
+ UCHAR ucScaler; // ATOM_SCALER1, ATOM_SCALER2
+ UCHAR ucEnable; // ATOM_SCALER_DISABLE or ATOM_SCALER_CENTER or ATOM_SCALER_EXPANSION
+ UCHAR ucTVStandard; //
+ UCHAR ucPadding[1];
+}ENABLE_SCALER_PARAMETERS;
+#define ENABLE_SCALER_PS_ALLOCATION ENABLE_SCALER_PARAMETERS
+
+//ucEnable:
#define SCALER_BYPASS_AUTO_CENTER_NO_REPLICATION 0
#define SCALER_BYPASS_AUTO_CENTER_AUTO_REPLICATION 1
#define SCALER_ENABLE_2TAP_ALPHA_MODE 2
#define SCALER_ENABLE_MULTITAP_MODE 3
-typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS {
- ULONG usHWIconHorzVertPosn; /* Hardware Icon Vertical position */
- UCHAR ucHWIconVertOffset; /* Hardware Icon Vertical offset */
- UCHAR ucHWIconHorzOffset; /* Hardware Icon Horizontal offset */
- UCHAR ucSelection; /* ATOM_CURSOR1 or ATOM_ICON1 or ATOM_CURSOR2 or ATOM_ICON2 */
- UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */
-} ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS;
-
-typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION {
- ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS sEnableIcon;
- ENABLE_CRTC_PARAMETERS sReserved;
-} ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION;
-
-typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS {
- USHORT usHight; /* Image Hight */
- USHORT usWidth; /* Image Width */
- UCHAR ucSurface; /* Surface 1 or 2 */
- UCHAR ucPadding[3];
-} ENABLE_GRAPH_SURFACE_PARAMETERS;
-
-typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2 {
- USHORT usHight; /* Image Hight */
- USHORT usWidth; /* Image Width */
- UCHAR ucSurface; /* Surface 1 or 2 */
- UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */
- UCHAR ucPadding[2];
-} ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2;
-
-typedef struct _ENABLE_GRAPH_SURFACE_PS_ALLOCATION {
- ENABLE_GRAPH_SURFACE_PARAMETERS sSetSurface;
- ENABLE_YUV_PS_ALLOCATION sReserved; /* Don't set this one */
-} ENABLE_GRAPH_SURFACE_PS_ALLOCATION;
-
-typedef struct _MEMORY_CLEAN_UP_PARAMETERS {
- USHORT usMemoryStart; /* in 8Kb boundry, offset from memory base address */
- USHORT usMemorySize; /* 8Kb blocks aligned */
-} MEMORY_CLEAN_UP_PARAMETERS;
+typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS
+{
+ ULONG usHWIconHorzVertPosn; // Hardware Icon Vertical position
+ UCHAR ucHWIconVertOffset; // Hardware Icon Vertical offset
+ UCHAR ucHWIconHorzOffset; // Hardware Icon Horizontal offset
+ UCHAR ucSelection; // ATOM_CURSOR1 or ATOM_ICON1 or ATOM_CURSOR2 or ATOM_ICON2
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+}ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS;
+
+typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION
+{
+ ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS sEnableIcon;
+ ENABLE_CRTC_PARAMETERS sReserved;
+}ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION;
+
+typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS
+{
+ USHORT usHight; // Image Hight
+ USHORT usWidth; // Image Width
+ UCHAR ucSurface; // Surface 1 or 2
+ UCHAR ucPadding[3];
+}ENABLE_GRAPH_SURFACE_PARAMETERS;
+
+typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2
+{
+ USHORT usHight; // Image Hight
+ USHORT usWidth; // Image Width
+ UCHAR ucSurface; // Surface 1 or 2
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucPadding[2];
+}ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2;
+
+typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS_V1_3
+{
+ USHORT usHight; // Image Hight
+ USHORT usWidth; // Image Width
+ UCHAR ucSurface; // Surface 1 or 2
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ USHORT usDeviceId; // Active Device Id for this surface. If no device, set to 0.
+}ENABLE_GRAPH_SURFACE_PARAMETERS_V1_3;
+
+typedef struct _ENABLE_GRAPH_SURFACE_PS_ALLOCATION
+{
+ ENABLE_GRAPH_SURFACE_PARAMETERS sSetSurface;
+ ENABLE_YUV_PS_ALLOCATION sReserved; // Don't set this one
+}ENABLE_GRAPH_SURFACE_PS_ALLOCATION;
+
+typedef struct _MEMORY_CLEAN_UP_PARAMETERS
+{
+ USHORT usMemoryStart; //in 8Kb boundry, offset from memory base address
+ USHORT usMemorySize; //8Kb blocks aligned
+}MEMORY_CLEAN_UP_PARAMETERS;
#define MEMORY_CLEAN_UP_PS_ALLOCATION MEMORY_CLEAN_UP_PARAMETERS
-typedef struct _GET_DISPLAY_SURFACE_SIZE_PARAMETERS {
- USHORT usX_Size; /* When use as input parameter, usX_Size indicates which CRTC */
- USHORT usY_Size;
-} GET_DISPLAY_SURFACE_SIZE_PARAMETERS;
+typedef struct _GET_DISPLAY_SURFACE_SIZE_PARAMETERS
+{
+ USHORT usX_Size; //When use as input parameter, usX_Size indicates which CRTC
+ USHORT usY_Size;
+}GET_DISPLAY_SURFACE_SIZE_PARAMETERS;
-typedef struct _INDIRECT_IO_ACCESS {
- ATOM_COMMON_TABLE_HEADER sHeader;
- UCHAR IOAccessSequence[256];
+typedef struct _INDIRECT_IO_ACCESS
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR IOAccessSequence[256];
} INDIRECT_IO_ACCESS;
#define INDIRECT_READ 0x00
@@ -3615,93 +4414,108 @@ typedef struct _INDIRECT_IO_ACCESS {
#define INDIRECT_IO_NBMISC_READ INDIRECT_IO_NBMISC | INDIRECT_READ
#define INDIRECT_IO_NBMISC_WRITE INDIRECT_IO_NBMISC | INDIRECT_WRITE
-typedef struct _ATOM_OEM_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;
-} ATOM_OEM_INFO;
-
-typedef struct _ATOM_TV_MODE {
- UCHAR ucVMode_Num; /* Video mode number */
- UCHAR ucTV_Mode_Num; /* Internal TV mode number */
-} ATOM_TV_MODE;
-
-typedef struct _ATOM_BIOS_INT_TVSTD_MODE {
- ATOM_COMMON_TABLE_HEADER sHeader;
- USHORT usTV_Mode_LUT_Offset; /* Pointer to standard to internal number conversion table */
- USHORT usTV_FIFO_Offset; /* Pointer to FIFO entry table */
- USHORT usNTSC_Tbl_Offset; /* Pointer to SDTV_Mode_NTSC table */
- USHORT usPAL_Tbl_Offset; /* Pointer to SDTV_Mode_PAL table */
- USHORT usCV_Tbl_Offset; /* Pointer to SDTV_Mode_PAL table */
-} ATOM_BIOS_INT_TVSTD_MODE;
-
-typedef struct _ATOM_TV_MODE_SCALER_PTR {
- USHORT ucFilter0_Offset; /* Pointer to filter format 0 coefficients */
- USHORT usFilter1_Offset; /* Pointer to filter format 0 coefficients */
- UCHAR ucTV_Mode_Num;
-} ATOM_TV_MODE_SCALER_PTR;
-
-typedef struct _ATOM_STANDARD_VESA_TIMING {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_DTD_FORMAT aModeTimings[16]; /* 16 is not the real array number, just for initial allocation */
-} ATOM_STANDARD_VESA_TIMING;
-
-typedef struct _ATOM_STD_FORMAT {
- USHORT usSTD_HDisp;
- USHORT usSTD_VDisp;
- USHORT usSTD_RefreshRate;
- USHORT usReserved;
-} ATOM_STD_FORMAT;
-
-typedef struct _ATOM_VESA_TO_EXTENDED_MODE {
- USHORT usVESA_ModeNumber;
- USHORT usExtendedModeNumber;
-} ATOM_VESA_TO_EXTENDED_MODE;
-
-typedef struct _ATOM_VESA_TO_INTENAL_MODE_LUT {
- ATOM_COMMON_TABLE_HEADER sHeader;
- ATOM_VESA_TO_EXTENDED_MODE asVESA_ToExtendedModeInfo[76];
-} ATOM_VESA_TO_INTENAL_MODE_LUT;
+typedef struct _ATOM_OEM_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;
+}ATOM_OEM_INFO;
+
+typedef struct _ATOM_TV_MODE
+{
+ UCHAR ucVMode_Num; //Video mode number
+ UCHAR ucTV_Mode_Num; //Internal TV mode number
+}ATOM_TV_MODE;
+
+typedef struct _ATOM_BIOS_INT_TVSTD_MODE
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usTV_Mode_LUT_Offset; // Pointer to standard to internal number conversion table
+ USHORT usTV_FIFO_Offset; // Pointer to FIFO entry table
+ USHORT usNTSC_Tbl_Offset; // Pointer to SDTV_Mode_NTSC table
+ USHORT usPAL_Tbl_Offset; // Pointer to SDTV_Mode_PAL table
+ USHORT usCV_Tbl_Offset; // Pointer to SDTV_Mode_PAL table
+}ATOM_BIOS_INT_TVSTD_MODE;
+
+
+typedef struct _ATOM_TV_MODE_SCALER_PTR
+{
+ USHORT ucFilter0_Offset; //Pointer to filter format 0 coefficients
+ USHORT usFilter1_Offset; //Pointer to filter format 0 coefficients
+ UCHAR ucTV_Mode_Num;
+}ATOM_TV_MODE_SCALER_PTR;
+
+typedef struct _ATOM_STANDARD_VESA_TIMING
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_DTD_FORMAT aModeTimings[16]; // 16 is not the real array number, just for initial allocation
+}ATOM_STANDARD_VESA_TIMING;
+
+
+typedef struct _ATOM_STD_FORMAT
+{
+ USHORT usSTD_HDisp;
+ USHORT usSTD_VDisp;
+ USHORT usSTD_RefreshRate;
+ USHORT usReserved;
+}ATOM_STD_FORMAT;
+
+typedef struct _ATOM_VESA_TO_EXTENDED_MODE
+{
+ USHORT usVESA_ModeNumber;
+ USHORT usExtendedModeNumber;
+}ATOM_VESA_TO_EXTENDED_MODE;
+
+typedef struct _ATOM_VESA_TO_INTENAL_MODE_LUT
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_VESA_TO_EXTENDED_MODE asVESA_ToExtendedModeInfo[76];
+}ATOM_VESA_TO_INTENAL_MODE_LUT;
/*************** ATOM Memory Related Data Structure ***********************/
-typedef struct _ATOM_MEMORY_VENDOR_BLOCK {
- UCHAR ucMemoryType;
- UCHAR ucMemoryVendor;
- UCHAR ucAdjMCId;
- UCHAR ucDynClkId;
- ULONG ulDllResetClkRange;
-} ATOM_MEMORY_VENDOR_BLOCK;
-
-typedef struct _ATOM_MEMORY_SETTING_ID_CONFIG {
+typedef struct _ATOM_MEMORY_VENDOR_BLOCK{
+ UCHAR ucMemoryType;
+ UCHAR ucMemoryVendor;
+ UCHAR ucAdjMCId;
+ UCHAR ucDynClkId;
+ ULONG ulDllResetClkRange;
+}ATOM_MEMORY_VENDOR_BLOCK;
+
+
+typedef struct _ATOM_MEMORY_SETTING_ID_CONFIG{
#if ATOM_BIG_ENDIAN
- ULONG ucMemBlkId:8;
- ULONG ulMemClockRange:24;
+ ULONG ucMemBlkId:8;
+ ULONG ulMemClockRange:24;
#else
- ULONG ulMemClockRange:24;
- ULONG ucMemBlkId:8;
+ ULONG ulMemClockRange:24;
+ ULONG ucMemBlkId:8;
#endif
-} ATOM_MEMORY_SETTING_ID_CONFIG;
-
-typedef union _ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS {
- ATOM_MEMORY_SETTING_ID_CONFIG slAccess;
- ULONG ulAccess;
-} ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS;
-
-typedef struct _ATOM_MEMORY_SETTING_DATA_BLOCK {
- ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS ulMemoryID;
- ULONG aulMemData[1];
-} ATOM_MEMORY_SETTING_DATA_BLOCK;
-
-typedef struct _ATOM_INIT_REG_INDEX_FORMAT {
- USHORT usRegIndex; /* MC register index */
- UCHAR ucPreRegDataLength; /* offset in ATOM_INIT_REG_DATA_BLOCK.saRegDataBuf */
-} ATOM_INIT_REG_INDEX_FORMAT;
-
-typedef struct _ATOM_INIT_REG_BLOCK {
- USHORT usRegIndexTblSize; /* size of asRegIndexBuf */
- USHORT usRegDataBlkSize; /* size of ATOM_MEMORY_SETTING_DATA_BLOCK */
- ATOM_INIT_REG_INDEX_FORMAT asRegIndexBuf[1];
- ATOM_MEMORY_SETTING_DATA_BLOCK asRegDataBuf[1];
-} ATOM_INIT_REG_BLOCK;
+}ATOM_MEMORY_SETTING_ID_CONFIG;
+
+typedef union _ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS
+{
+ ATOM_MEMORY_SETTING_ID_CONFIG slAccess;
+ ULONG ulAccess;
+}ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS;
+
+
+typedef struct _ATOM_MEMORY_SETTING_DATA_BLOCK{
+ ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS ulMemoryID;
+ ULONG aulMemData[1];
+}ATOM_MEMORY_SETTING_DATA_BLOCK;
+
+
+typedef struct _ATOM_INIT_REG_INDEX_FORMAT{
+ USHORT usRegIndex; // MC register index
+ UCHAR ucPreRegDataLength; // offset in ATOM_INIT_REG_DATA_BLOCK.saRegDataBuf
+}ATOM_INIT_REG_INDEX_FORMAT;
+
+
+typedef struct _ATOM_INIT_REG_BLOCK{
+ USHORT usRegIndexTblSize; //size of asRegIndexBuf
+ USHORT usRegDataBlkSize; //size of ATOM_MEMORY_SETTING_DATA_BLOCK
+ ATOM_INIT_REG_INDEX_FORMAT asRegIndexBuf[1];
+ ATOM_MEMORY_SETTING_DATA_BLOCK asRegDataBuf[1];
+}ATOM_INIT_REG_BLOCK;
#define END_OF_REG_INDEX_BLOCK 0x0ffff
#define END_OF_REG_DATA_BLOCK 0x00000000
@@ -3716,16 +4530,19 @@ typedef struct _ATOM_INIT_REG_BLOCK {
#define INDEX_ACCESS_RANGE_END (INDEX_ACCESS_RANGE_BEGIN + 1)
#define VALUE_INDEX_ACCESS_SINGLE (INDEX_ACCESS_RANGE_END + 1)
-typedef struct _ATOM_MC_INIT_PARAM_TABLE {
- ATOM_COMMON_TABLE_HEADER sHeader;
- USHORT usAdjustARB_SEQDataOffset;
- USHORT usMCInitMemTypeTblOffset;
- USHORT usMCInitCommonTblOffset;
- USHORT usMCInitPowerDownTblOffset;
- ULONG ulARB_SEQDataBuf[32];
- ATOM_INIT_REG_BLOCK asMCInitMemType;
- ATOM_INIT_REG_BLOCK asMCInitCommon;
-} ATOM_MC_INIT_PARAM_TABLE;
+
+typedef struct _ATOM_MC_INIT_PARAM_TABLE
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usAdjustARB_SEQDataOffset;
+ USHORT usMCInitMemTypeTblOffset;
+ USHORT usMCInitCommonTblOffset;
+ USHORT usMCInitPowerDownTblOffset;
+ ULONG ulARB_SEQDataBuf[32];
+ ATOM_INIT_REG_BLOCK asMCInitMemType;
+ ATOM_INIT_REG_BLOCK asMCInitCommon;
+}ATOM_MC_INIT_PARAM_TABLE;
+
#define _4Mx16 0x2
#define _4Mx32 0x3
@@ -3751,221 +4568,272 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE {
#define QIMONDA INFINEON
#define PROMOS MOSEL
+#define KRETON INFINEON
-/* ///////////Support for GDDR5 MC uCode to reside in upper 64K of ROM///////////// */
+/////////////Support for GDDR5 MC uCode to reside in upper 64K of ROM/////////////
#define UCODE_ROM_START_ADDRESS 0x1c000
-#define UCODE_SIGNATURE 0x4375434d /* 'MCuC' - MC uCode */
-
-/* uCode block header for reference */
-
-typedef struct _MCuCodeHeader {
- ULONG ulSignature;
- UCHAR ucRevision;
- UCHAR ucChecksum;
- UCHAR ucReserved1;
- UCHAR ucReserved2;
- USHORT usParametersLength;
- USHORT usUCodeLength;
- USHORT usReserved1;
- USHORT usReserved2;
+#define UCODE_SIGNATURE 0x4375434d // 'MCuC' - MC uCode
+
+//uCode block header for reference
+
+typedef struct _MCuCodeHeader
+{
+ ULONG ulSignature;
+ UCHAR ucRevision;
+ UCHAR ucChecksum;
+ UCHAR ucReserved1;
+ UCHAR ucReserved2;
+ USHORT usParametersLength;
+ USHORT usUCodeLength;
+ USHORT usReserved1;
+ USHORT usReserved2;
} MCuCodeHeader;
-/* //////////////////////////////////////////////////////////////////////////////// */
+//////////////////////////////////////////////////////////////////////////////////
#define ATOM_MAX_NUMBER_OF_VRAM_MODULE 16
#define ATOM_VRAM_MODULE_MEMORY_VENDOR_ID_MASK 0xF
-typedef struct _ATOM_VRAM_MODULE_V1 {
- ULONG ulReserved;
- USHORT usEMRSValue;
- USHORT usMRSValue;
- USHORT usReserved;
- UCHAR ucExtMemoryID; /* An external indicator (by hardcode, callback or pin) to tell what is the current memory module */
- UCHAR ucMemoryType; /* [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] reserved; */
- UCHAR ucMemoryVenderID; /* Predefined,never change across designs or memory type/vender */
- UCHAR ucMemoryDeviceCfg; /* [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32... */
- UCHAR ucRow; /* Number of Row,in power of 2; */
- UCHAR ucColumn; /* Number of Column,in power of 2; */
- UCHAR ucBank; /* Nunber of Bank; */
- UCHAR ucRank; /* Number of Rank, in power of 2 */
- UCHAR ucChannelNum; /* Number of channel; */
- UCHAR ucChannelConfig; /* [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2 */
- UCHAR ucDefaultMVDDQ_ID; /* Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data; */
- UCHAR ucDefaultMVDDC_ID; /* Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data; */
- UCHAR ucReserved[2];
-} ATOM_VRAM_MODULE_V1;
-
-typedef struct _ATOM_VRAM_MODULE_V2 {
- ULONG ulReserved;
- ULONG ulFlags; /* To enable/disable functionalities based on memory type */
- ULONG ulEngineClock; /* Override of default engine clock for particular memory type */
- ULONG ulMemoryClock; /* Override of default memory clock for particular memory type */
- USHORT usEMRS2Value; /* EMRS2 Value is used for GDDR2 and GDDR4 memory type */
- USHORT usEMRS3Value; /* EMRS3 Value is used for GDDR2 and GDDR4 memory type */
- USHORT usEMRSValue;
- USHORT usMRSValue;
- USHORT usReserved;
- UCHAR ucExtMemoryID; /* An external indicator (by hardcode, callback or pin) to tell what is the current memory module */
- UCHAR ucMemoryType; /* [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now; */
- UCHAR ucMemoryVenderID; /* Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed */
- UCHAR ucMemoryDeviceCfg; /* [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32... */
- UCHAR ucRow; /* Number of Row,in power of 2; */
- UCHAR ucColumn; /* Number of Column,in power of 2; */
- UCHAR ucBank; /* Nunber of Bank; */
- UCHAR ucRank; /* Number of Rank, in power of 2 */
- UCHAR ucChannelNum; /* Number of channel; */
- UCHAR ucChannelConfig; /* [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2 */
- UCHAR ucDefaultMVDDQ_ID; /* Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data; */
- UCHAR ucDefaultMVDDC_ID; /* Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data; */
- UCHAR ucRefreshRateFactor;
- UCHAR ucReserved[3];
-} ATOM_VRAM_MODULE_V2;
-
-typedef struct _ATOM_MEMORY_TIMING_FORMAT {
- ULONG ulClkRange; /* memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing */
- union {
- USHORT usMRS; /* mode register */
- USHORT usDDR3_MR0;
- };
- union {
- USHORT usEMRS; /* extended mode register */
- USHORT usDDR3_MR1;
- };
- UCHAR ucCL; /* CAS latency */
- UCHAR ucWL; /* WRITE Latency */
- UCHAR uctRAS; /* tRAS */
- UCHAR uctRC; /* tRC */
- UCHAR uctRFC; /* tRFC */
- UCHAR uctRCDR; /* tRCDR */
- UCHAR uctRCDW; /* tRCDW */
- UCHAR uctRP; /* tRP */
- UCHAR uctRRD; /* tRRD */
- UCHAR uctWR; /* tWR */
- UCHAR uctWTR; /* tWTR */
- UCHAR uctPDIX; /* tPDIX */
- UCHAR uctFAW; /* tFAW */
- UCHAR uctAOND; /* tAOND */
- union {
- struct {
- UCHAR ucflag; /* flag to control memory timing calculation. bit0= control EMRS2 Infineon */
- UCHAR ucReserved;
- };
- USHORT usDDR3_MR2;
- };
-} ATOM_MEMORY_TIMING_FORMAT;
-
-typedef struct _ATOM_MEMORY_TIMING_FORMAT_V1 {
- ULONG ulClkRange; /* memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing */
- USHORT usMRS; /* mode register */
- USHORT usEMRS; /* extended mode register */
- UCHAR ucCL; /* CAS latency */
- UCHAR ucWL; /* WRITE Latency */
- UCHAR uctRAS; /* tRAS */
- UCHAR uctRC; /* tRC */
- UCHAR uctRFC; /* tRFC */
- UCHAR uctRCDR; /* tRCDR */
- UCHAR uctRCDW; /* tRCDW */
- UCHAR uctRP; /* tRP */
- UCHAR uctRRD; /* tRRD */
- UCHAR uctWR; /* tWR */
- UCHAR uctWTR; /* tWTR */
- UCHAR uctPDIX; /* tPDIX */
- UCHAR uctFAW; /* tFAW */
- UCHAR uctAOND; /* tAOND */
- UCHAR ucflag; /* flag to control memory timing calculation. bit0= control EMRS2 Infineon */
-/* ///////////////////////GDDR parameters/////////////////////////////////// */
- UCHAR uctCCDL; /* */
- UCHAR uctCRCRL; /* */
- UCHAR uctCRCWL; /* */
- UCHAR uctCKE; /* */
- UCHAR uctCKRSE; /* */
- UCHAR uctCKRSX; /* */
- UCHAR uctFAW32; /* */
- UCHAR ucReserved1; /* */
- UCHAR ucReserved2; /* */
- UCHAR ucTerminator;
-} ATOM_MEMORY_TIMING_FORMAT_V1;
-
-typedef struct _ATOM_MEMORY_FORMAT {
- ULONG ulDllDisClock; /* memory DLL will be disable when target memory clock is below this clock */
- union {
- USHORT usEMRS2Value; /* EMRS2 Value is used for GDDR2 and GDDR4 memory type */
- USHORT usDDR3_Reserved; /* Not used for DDR3 memory */
- };
- union {
- USHORT usEMRS3Value; /* EMRS3 Value is used for GDDR2 and GDDR4 memory type */
- USHORT usDDR3_MR3; /* Used for DDR3 memory */
- };
- UCHAR ucMemoryType; /* [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now; */
- UCHAR ucMemoryVenderID; /* Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed */
- UCHAR ucRow; /* Number of Row,in power of 2; */
- UCHAR ucColumn; /* Number of Column,in power of 2; */
- UCHAR ucBank; /* Nunber of Bank; */
- UCHAR ucRank; /* Number of Rank, in power of 2 */
- UCHAR ucBurstSize; /* burst size, 0= burst size=4 1= burst size=8 */
- UCHAR ucDllDisBit; /* position of DLL Enable/Disable bit in EMRS ( Extended Mode Register ) */
- UCHAR ucRefreshRateFactor; /* memory refresh rate in unit of ms */
- UCHAR ucDensity; /* _8Mx32, _16Mx32, _16Mx16, _32Mx16 */
- UCHAR ucPreamble; /* [7:4] Write Preamble, [3:0] Read Preamble */
- UCHAR ucMemAttrib; /* Memory Device Addribute, like RDBI/WDBI etc */
- ATOM_MEMORY_TIMING_FORMAT asMemTiming[5]; /* Memory Timing block sort from lower clock to higher clock */
-} ATOM_MEMORY_FORMAT;
-
-typedef struct _ATOM_VRAM_MODULE_V3 {
- ULONG ulChannelMapCfg; /* board dependent paramenter:Channel combination */
- USHORT usSize; /* size of ATOM_VRAM_MODULE_V3 */
- USHORT usDefaultMVDDQ; /* board dependent parameter:Default Memory Core Voltage */
- USHORT usDefaultMVDDC; /* board dependent parameter:Default Memory IO Voltage */
- UCHAR ucExtMemoryID; /* An external indicator (by hardcode, callback or pin) to tell what is the current memory module */
- UCHAR ucChannelNum; /* board dependent parameter:Number of channel; */
- UCHAR ucChannelSize; /* board dependent parameter:32bit or 64bit */
- UCHAR ucVREFI; /* board dependnt parameter: EXT or INT +160mv to -140mv */
- UCHAR ucNPL_RT; /* board dependent parameter:NPL round trip delay, used for calculate memory timing parameters */
- UCHAR ucFlag; /* To enable/disable functionalities based on memory type */
- ATOM_MEMORY_FORMAT asMemory; /* describ all of video memory parameters from memory spec */
-} ATOM_VRAM_MODULE_V3;
-
-/* ATOM_VRAM_MODULE_V3.ucNPL_RT */
+typedef struct _ATOM_VRAM_MODULE_V1
+{
+ ULONG ulReserved;
+ USHORT usEMRSValue;
+ USHORT usMRSValue;
+ USHORT usReserved;
+ UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module
+ UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] reserved;
+ UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender
+ UCHAR ucMemoryDeviceCfg; // [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32...
+ UCHAR ucRow; // Number of Row,in power of 2;
+ UCHAR ucColumn; // Number of Column,in power of 2;
+ UCHAR ucBank; // Nunber of Bank;
+ UCHAR ucRank; // Number of Rank, in power of 2
+ UCHAR ucChannelNum; // Number of channel;
+ UCHAR ucChannelConfig; // [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2
+ UCHAR ucDefaultMVDDQ_ID; // Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data;
+ UCHAR ucDefaultMVDDC_ID; // Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data;
+ UCHAR ucReserved[2];
+}ATOM_VRAM_MODULE_V1;
+
+
+typedef struct _ATOM_VRAM_MODULE_V2
+{
+ ULONG ulReserved;
+ ULONG ulFlags; // To enable/disable functionalities based on memory type
+ ULONG ulEngineClock; // Override of default engine clock for particular memory type
+ ULONG ulMemoryClock; // Override of default memory clock for particular memory type
+ USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usEMRSValue;
+ USHORT usMRSValue;
+ USHORT usReserved;
+ UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module
+ UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now;
+ UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed
+ UCHAR ucMemoryDeviceCfg; // [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32...
+ UCHAR ucRow; // Number of Row,in power of 2;
+ UCHAR ucColumn; // Number of Column,in power of 2;
+ UCHAR ucBank; // Nunber of Bank;
+ UCHAR ucRank; // Number of Rank, in power of 2
+ UCHAR ucChannelNum; // Number of channel;
+ UCHAR ucChannelConfig; // [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2
+ UCHAR ucDefaultMVDDQ_ID; // Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data;
+ UCHAR ucDefaultMVDDC_ID; // Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data;
+ UCHAR ucRefreshRateFactor;
+ UCHAR ucReserved[3];
+}ATOM_VRAM_MODULE_V2;
+
+
+typedef struct _ATOM_MEMORY_TIMING_FORMAT
+{
+ ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing
+ union{
+ USHORT usMRS; // mode register
+ USHORT usDDR3_MR0;
+ };
+ union{
+ USHORT usEMRS; // extended mode register
+ USHORT usDDR3_MR1;
+ };
+ UCHAR ucCL; // CAS latency
+ UCHAR ucWL; // WRITE Latency
+ UCHAR uctRAS; // tRAS
+ UCHAR uctRC; // tRC
+ UCHAR uctRFC; // tRFC
+ UCHAR uctRCDR; // tRCDR
+ UCHAR uctRCDW; // tRCDW
+ UCHAR uctRP; // tRP
+ UCHAR uctRRD; // tRRD
+ UCHAR uctWR; // tWR
+ UCHAR uctWTR; // tWTR
+ UCHAR uctPDIX; // tPDIX
+ UCHAR uctFAW; // tFAW
+ UCHAR uctAOND; // tAOND
+ union
+ {
+ struct {
+ UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon
+ UCHAR ucReserved;
+ };
+ USHORT usDDR3_MR2;
+ };
+}ATOM_MEMORY_TIMING_FORMAT;
+
+
+typedef struct _ATOM_MEMORY_TIMING_FORMAT_V1
+{
+ ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing
+ USHORT usMRS; // mode register
+ USHORT usEMRS; // extended mode register
+ UCHAR ucCL; // CAS latency
+ UCHAR ucWL; // WRITE Latency
+ UCHAR uctRAS; // tRAS
+ UCHAR uctRC; // tRC
+ UCHAR uctRFC; // tRFC
+ UCHAR uctRCDR; // tRCDR
+ UCHAR uctRCDW; // tRCDW
+ UCHAR uctRP; // tRP
+ UCHAR uctRRD; // tRRD
+ UCHAR uctWR; // tWR
+ UCHAR uctWTR; // tWTR
+ UCHAR uctPDIX; // tPDIX
+ UCHAR uctFAW; // tFAW
+ UCHAR uctAOND; // tAOND
+ UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon
+////////////////////////////////////GDDR parameters///////////////////////////////////
+ UCHAR uctCCDL; //
+ UCHAR uctCRCRL; //
+ UCHAR uctCRCWL; //
+ UCHAR uctCKE; //
+ UCHAR uctCKRSE; //
+ UCHAR uctCKRSX; //
+ UCHAR uctFAW32; //
+ UCHAR ucMR5lo; //
+ UCHAR ucMR5hi; //
+ UCHAR ucTerminator;
+}ATOM_MEMORY_TIMING_FORMAT_V1;
+
+typedef struct _ATOM_MEMORY_TIMING_FORMAT_V2
+{
+ ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing
+ USHORT usMRS; // mode register
+ USHORT usEMRS; // extended mode register
+ UCHAR ucCL; // CAS latency
+ UCHAR ucWL; // WRITE Latency
+ UCHAR uctRAS; // tRAS
+ UCHAR uctRC; // tRC
+ UCHAR uctRFC; // tRFC
+ UCHAR uctRCDR; // tRCDR
+ UCHAR uctRCDW; // tRCDW
+ UCHAR uctRP; // tRP
+ UCHAR uctRRD; // tRRD
+ UCHAR uctWR; // tWR
+ UCHAR uctWTR; // tWTR
+ UCHAR uctPDIX; // tPDIX
+ UCHAR uctFAW; // tFAW
+ UCHAR uctAOND; // tAOND
+ UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon
+////////////////////////////////////GDDR parameters///////////////////////////////////
+ UCHAR uctCCDL; //
+ UCHAR uctCRCRL; //
+ UCHAR uctCRCWL; //
+ UCHAR uctCKE; //
+ UCHAR uctCKRSE; //
+ UCHAR uctCKRSX; //
+ UCHAR uctFAW32; //
+ UCHAR ucMR4lo; //
+ UCHAR ucMR4hi; //
+ UCHAR ucMR5lo; //
+ UCHAR ucMR5hi; //
+ UCHAR ucTerminator;
+ UCHAR ucReserved;
+}ATOM_MEMORY_TIMING_FORMAT_V2;
+
+typedef struct _ATOM_MEMORY_FORMAT
+{
+ ULONG ulDllDisClock; // memory DLL will be disable when target memory clock is below this clock
+ union{
+ USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usDDR3_Reserved; // Not used for DDR3 memory
+ };
+ union{
+ USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usDDR3_MR3; // Used for DDR3 memory
+ };
+ UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now;
+ UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed
+ UCHAR ucRow; // Number of Row,in power of 2;
+ UCHAR ucColumn; // Number of Column,in power of 2;
+ UCHAR ucBank; // Nunber of Bank;
+ UCHAR ucRank; // Number of Rank, in power of 2
+ UCHAR ucBurstSize; // burst size, 0= burst size=4 1= burst size=8
+ UCHAR ucDllDisBit; // position of DLL Enable/Disable bit in EMRS ( Extended Mode Register )
+ UCHAR ucRefreshRateFactor; // memory refresh rate in unit of ms
+ UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16
+ UCHAR ucPreamble; //[7:4] Write Preamble, [3:0] Read Preamble
+ UCHAR ucMemAttrib; // Memory Device Addribute, like RDBI/WDBI etc
+ ATOM_MEMORY_TIMING_FORMAT asMemTiming[5]; //Memory Timing block sort from lower clock to higher clock
+}ATOM_MEMORY_FORMAT;
+
+
+typedef struct _ATOM_VRAM_MODULE_V3
+{
+ ULONG ulChannelMapCfg; // board dependent paramenter:Channel combination
+ USHORT usSize; // size of ATOM_VRAM_MODULE_V3
+ USHORT usDefaultMVDDQ; // board dependent parameter:Default Memory Core Voltage
+ USHORT usDefaultMVDDC; // board dependent parameter:Default Memory IO Voltage
+ UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module
+ UCHAR ucChannelNum; // board dependent parameter:Number of channel;
+ UCHAR ucChannelSize; // board dependent parameter:32bit or 64bit
+ UCHAR ucVREFI; // board dependnt parameter: EXT or INT +160mv to -140mv
+ UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters
+ UCHAR ucFlag; // To enable/disable functionalities based on memory type
+ ATOM_MEMORY_FORMAT asMemory; // describ all of video memory parameters from memory spec
+}ATOM_VRAM_MODULE_V3;
+
+
+//ATOM_VRAM_MODULE_V3.ucNPL_RT
#define NPL_RT_MASK 0x0f
#define BATTERY_ODT_MASK 0xc0
#define ATOM_VRAM_MODULE ATOM_VRAM_MODULE_V3
-typedef struct _ATOM_VRAM_MODULE_V4 {
- ULONG ulChannelMapCfg; /* board dependent parameter: Channel combination */
- USHORT usModuleSize; /* size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE */
- USHORT usPrivateReserved; /* BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! */
- /* MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) */
- USHORT usReserved;
- UCHAR ucExtMemoryID; /* An external indicator (by hardcode, callback or pin) to tell what is the current memory module */
- UCHAR ucMemoryType; /* [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now; */
- UCHAR ucChannelNum; /* Number of channels present in this module config */
- UCHAR ucChannelWidth; /* 0 - 32 bits; 1 - 64 bits */
- UCHAR ucDensity; /* _8Mx32, _16Mx32, _16Mx16, _32Mx16 */
- UCHAR ucFlag; /* To enable/disable functionalities based on memory type */
- UCHAR ucMisc; /* bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8 */
- UCHAR ucVREFI; /* board dependent parameter */
- UCHAR ucNPL_RT; /* board dependent parameter:NPL round trip delay, used for calculate memory timing parameters */
- UCHAR ucPreamble; /* [7:4] Write Preamble, [3:0] Read Preamble */
- UCHAR ucMemorySize; /* BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! */
- /* Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros */
- UCHAR ucReserved[3];
-
-/* compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level */
- union {
- USHORT usEMRS2Value; /* EMRS2 Value is used for GDDR2 and GDDR4 memory type */
- USHORT usDDR3_Reserved;
- };
- union {
- USHORT usEMRS3Value; /* EMRS3 Value is used for GDDR2 and GDDR4 memory type */
- USHORT usDDR3_MR3; /* Used for DDR3 memory */
- };
- UCHAR ucMemoryVenderID; /* Predefined, If not predefined, vendor detection table gets executed */
- UCHAR ucRefreshRateFactor; /* [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) */
- UCHAR ucReserved2[2];
- ATOM_MEMORY_TIMING_FORMAT asMemTiming[5]; /* Memory Timing block sort from lower clock to higher clock */
-} ATOM_VRAM_MODULE_V4;
+typedef struct _ATOM_VRAM_MODULE_V4
+{
+ ULONG ulChannelMapCfg; // board dependent parameter: Channel combination
+ USHORT usModuleSize; // size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE
+ USHORT usPrivateReserved; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!!
+ // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS)
+ USHORT usReserved;
+ UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module
+ UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now;
+ UCHAR ucChannelNum; // Number of channels present in this module config
+ UCHAR ucChannelWidth; // 0 - 32 bits; 1 - 64 bits
+ UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16
+ UCHAR ucFlag; // To enable/disable functionalities based on memory type
+ UCHAR ucMisc; // bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8
+ UCHAR ucVREFI; // board dependent parameter
+ UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters
+ UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble
+ UCHAR ucMemorySize; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!!
+ // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros
+ UCHAR ucReserved[3];
+
+//compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level
+ union{
+ USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usDDR3_Reserved;
+ };
+ union{
+ USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usDDR3_MR3; // Used for DDR3 memory
+ };
+ UCHAR ucMemoryVenderID; // Predefined, If not predefined, vendor detection table gets executed
+ UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms)
+ UCHAR ucReserved2[2];
+ ATOM_MEMORY_TIMING_FORMAT asMemTiming[5];//Memory Timing block sort from lower clock to higher clock
+}ATOM_VRAM_MODULE_V4;
#define VRAM_MODULE_V4_MISC_RANK_MASK 0x3
#define VRAM_MODULE_V4_MISC_DUAL_RANK 0x1
@@ -3973,96 +4841,139 @@ typedef struct _ATOM_VRAM_MODULE_V4 {
#define VRAM_MODULE_V4_MISC_BL8 0x4
#define VRAM_MODULE_V4_MISC_DUAL_CS 0x10
-typedef struct _ATOM_VRAM_MODULE_V5 {
- ULONG ulChannelMapCfg; /* board dependent parameter: Channel combination */
- USHORT usModuleSize; /* size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE */
- USHORT usPrivateReserved; /* BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! */
- /* MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) */
- USHORT usReserved;
- UCHAR ucExtMemoryID; /* An external indicator (by hardcode, callback or pin) to tell what is the current memory module */
- UCHAR ucMemoryType; /* [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now; */
- UCHAR ucChannelNum; /* Number of channels present in this module config */
- UCHAR ucChannelWidth; /* 0 - 32 bits; 1 - 64 bits */
- UCHAR ucDensity; /* _8Mx32, _16Mx32, _16Mx16, _32Mx16 */
- UCHAR ucFlag; /* To enable/disable functionalities based on memory type */
- UCHAR ucMisc; /* bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8 */
- UCHAR ucVREFI; /* board dependent parameter */
- UCHAR ucNPL_RT; /* board dependent parameter:NPL round trip delay, used for calculate memory timing parameters */
- UCHAR ucPreamble; /* [7:4] Write Preamble, [3:0] Read Preamble */
- UCHAR ucMemorySize; /* BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! */
- /* Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros */
- UCHAR ucReserved[3];
+typedef struct _ATOM_VRAM_MODULE_V5
+{
+ ULONG ulChannelMapCfg; // board dependent parameter: Channel combination
+ USHORT usModuleSize; // size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE
+ USHORT usPrivateReserved; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!!
+ // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS)
+ USHORT usReserved;
+ UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module
+ UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now;
+ UCHAR ucChannelNum; // Number of channels present in this module config
+ UCHAR ucChannelWidth; // 0 - 32 bits; 1 - 64 bits
+ UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16
+ UCHAR ucFlag; // To enable/disable functionalities based on memory type
+ UCHAR ucMisc; // bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8
+ UCHAR ucVREFI; // board dependent parameter
+ UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters
+ UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble
+ UCHAR ucMemorySize; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!!
+ // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros
+ UCHAR ucReserved[3];
+
+//compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level
+ USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type
+ UCHAR ucMemoryVenderID; // Predefined, If not predefined, vendor detection table gets executed
+ UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms)
+ UCHAR ucFIFODepth; // FIFO depth supposes to be detected during vendor detection, but if we dont do vendor detection we have to hardcode FIFO Depth
+ UCHAR ucCDR_Bandwidth; // [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth
+ ATOM_MEMORY_TIMING_FORMAT_V1 asMemTiming[5];//Memory Timing block sort from lower clock to higher clock
+}ATOM_VRAM_MODULE_V5;
+
+typedef struct _ATOM_VRAM_MODULE_V6
+{
+ ULONG ulChannelMapCfg; // board dependent parameter: Channel combination
+ USHORT usModuleSize; // size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE
+ USHORT usPrivateReserved; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!!
+ // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS)
+ USHORT usReserved;
+ UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module
+ UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now;
+ UCHAR ucChannelNum; // Number of channels present in this module config
+ UCHAR ucChannelWidth; // 0 - 32 bits; 1 - 64 bits
+ UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16
+ UCHAR ucFlag; // To enable/disable functionalities based on memory type
+ UCHAR ucMisc; // bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8
+ UCHAR ucVREFI; // board dependent parameter
+ UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters
+ UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble
+ UCHAR ucMemorySize; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!!
+ // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros
+ UCHAR ucReserved[3];
+
+//compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level
+ USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type
+ UCHAR ucMemoryVenderID; // Predefined, If not predefined, vendor detection table gets executed
+ UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms)
+ UCHAR ucFIFODepth; // FIFO depth supposes to be detected during vendor detection, but if we dont do vendor detection we have to hardcode FIFO Depth
+ UCHAR ucCDR_Bandwidth; // [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth
+ ATOM_MEMORY_TIMING_FORMAT_V2 asMemTiming[5];//Memory Timing block sort from lower clock to higher clock
+}ATOM_VRAM_MODULE_V6;
+
+
+
+typedef struct _ATOM_VRAM_INFO_V2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucNumOfVRAMModule;
+ ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule;
+}ATOM_VRAM_INFO_V2;
-/* compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level */
- USHORT usEMRS2Value; /* EMRS2 Value is used for GDDR2 and GDDR4 memory type */
- USHORT usEMRS3Value; /* EMRS3 Value is used for GDDR2 and GDDR4 memory type */
- UCHAR ucMemoryVenderID; /* Predefined, If not predefined, vendor detection table gets executed */
- UCHAR ucRefreshRateFactor; /* [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) */
- UCHAR ucFIFODepth; /* FIFO depth supposes to be detected during vendor detection, but if we dont do vendor detection we have to hardcode FIFO Depth */
- UCHAR ucCDR_Bandwidth; /* [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth */
- ATOM_MEMORY_TIMING_FORMAT_V1 asMemTiming[5]; /* Memory Timing block sort from lower clock to higher clock */
-} ATOM_VRAM_MODULE_V5;
-
-typedef struct _ATOM_VRAM_INFO_V2 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- UCHAR ucNumOfVRAMModule;
- ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; /* just for allocation, real number of blocks is in ucNumOfVRAMModule; */
-} ATOM_VRAM_INFO_V2;
-
-typedef struct _ATOM_VRAM_INFO_V3 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- USHORT usMemAdjustTblOffset; /* offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting */
- USHORT usMemClkPatchTblOffset; /* offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting */
- USHORT usRerseved;
- UCHAR aVID_PinsShift[9]; /* 8 bit strap maximum+terminator */
- UCHAR ucNumOfVRAMModule;
- ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; /* just for allocation, real number of blocks is in ucNumOfVRAMModule; */
- ATOM_INIT_REG_BLOCK asMemPatch; /* for allocation */
- /* ATOM_INIT_REG_BLOCK aMemAdjust; */
-} ATOM_VRAM_INFO_V3;
+typedef struct _ATOM_VRAM_INFO_V3
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting
+ USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting
+ USHORT usRerseved;
+ UCHAR aVID_PinsShift[9]; // 8 bit strap maximum+terminator
+ UCHAR ucNumOfVRAMModule;
+ ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule;
+ ATOM_INIT_REG_BLOCK asMemPatch; // for allocation
+ // ATOM_INIT_REG_BLOCK aMemAdjust;
+}ATOM_VRAM_INFO_V3;
#define ATOM_VRAM_INFO_LAST ATOM_VRAM_INFO_V3
-typedef struct _ATOM_VRAM_INFO_V4 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- USHORT usMemAdjustTblOffset; /* offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting */
- USHORT usMemClkPatchTblOffset; /* offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting */
- USHORT usRerseved;
- UCHAR ucMemDQ7_0ByteRemap; /* DQ line byte remap, =0: Memory Data line BYTE0, =1: BYTE1, =2: BYTE2, =3: BYTE3 */
- ULONG ulMemDQ7_0BitRemap; /* each DQ line ( 7~0) use 3bits, like: DQ0=Bit[2:0], DQ1:[5:3], ... DQ7:[23:21] */
- UCHAR ucReservde[4];
- UCHAR ucNumOfVRAMModule;
- ATOM_VRAM_MODULE_V4 aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; /* just for allocation, real number of blocks is in ucNumOfVRAMModule; */
- ATOM_INIT_REG_BLOCK asMemPatch; /* for allocation */
- /* ATOM_INIT_REG_BLOCK aMemAdjust; */
-} ATOM_VRAM_INFO_V4;
-
-typedef struct _ATOM_VRAM_GPIO_DETECTION_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- UCHAR aVID_PinsShift[9]; /* 8 bit strap maximum+terminator */
-} ATOM_VRAM_GPIO_DETECTION_INFO;
-
-typedef struct _ATOM_MEMORY_TRAINING_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- UCHAR ucTrainingLoop;
- UCHAR ucReserved[3];
- ATOM_INIT_REG_BLOCK asMemTrainingSetting;
-} ATOM_MEMORY_TRAINING_INFO;
-
-typedef struct SW_I2C_CNTL_DATA_PARAMETERS {
- UCHAR ucControl;
- UCHAR ucData;
- UCHAR ucSatus;
- UCHAR ucTemp;
+typedef struct _ATOM_VRAM_INFO_V4
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting
+ USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting
+ USHORT usRerseved;
+ UCHAR ucMemDQ7_0ByteRemap; // DQ line byte remap, =0: Memory Data line BYTE0, =1: BYTE1, =2: BYTE2, =3: BYTE3
+ ULONG ulMemDQ7_0BitRemap; // each DQ line ( 7~0) use 3bits, like: DQ0=Bit[2:0], DQ1:[5:3], ... DQ7:[23:21]
+ UCHAR ucReservde[4];
+ UCHAR ucNumOfVRAMModule;
+ ATOM_VRAM_MODULE_V4 aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule;
+ ATOM_INIT_REG_BLOCK asMemPatch; // for allocation
+ // ATOM_INIT_REG_BLOCK aMemAdjust;
+}ATOM_VRAM_INFO_V4;
+
+typedef struct _ATOM_VRAM_GPIO_DETECTION_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR aVID_PinsShift[9]; //8 bit strap maximum+terminator
+}ATOM_VRAM_GPIO_DETECTION_INFO;
+
+
+typedef struct _ATOM_MEMORY_TRAINING_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucTrainingLoop;
+ UCHAR ucReserved[3];
+ ATOM_INIT_REG_BLOCK asMemTrainingSetting;
+}ATOM_MEMORY_TRAINING_INFO;
+
+
+typedef struct SW_I2C_CNTL_DATA_PARAMETERS
+{
+ UCHAR ucControl;
+ UCHAR ucData;
+ UCHAR ucSatus;
+ UCHAR ucTemp;
} SW_I2C_CNTL_DATA_PARAMETERS;
#define SW_I2C_CNTL_DATA_PS_ALLOCATION SW_I2C_CNTL_DATA_PARAMETERS
-typedef struct _SW_I2C_IO_DATA_PARAMETERS {
- USHORT GPIO_Info;
- UCHAR ucAct;
- UCHAR ucData;
-} SW_I2C_IO_DATA_PARAMETERS;
+typedef struct _SW_I2C_IO_DATA_PARAMETERS
+{
+ USHORT GPIO_Info;
+ UCHAR ucAct;
+ UCHAR ucData;
+ } SW_I2C_IO_DATA_PARAMETERS;
#define SW_I2C_IO_DATA_PS_ALLOCATION SW_I2C_IO_DATA_PARAMETERS
@@ -4087,127 +4998,136 @@ typedef struct _SW_I2C_IO_DATA_PARAMETERS {
#define SW_I2C_CNTL_CLOSE 5
#define SW_I2C_CNTL_WRITE1BIT 6
-/* ==============================VESA definition Portion=============================== */
+//==============================VESA definition Portion===============================
#define VESA_OEM_PRODUCT_REV '01.00'
-#define VESA_MODE_ATTRIBUTE_MODE_SUPPORT 0xBB /* refer to VBE spec p.32, no TTY support */
+#define VESA_MODE_ATTRIBUTE_MODE_SUPPORT 0xBB //refer to VBE spec p.32, no TTY support
#define VESA_MODE_WIN_ATTRIBUTE 7
#define VESA_WIN_SIZE 64
-typedef struct _PTR_32_BIT_STRUCTURE {
- USHORT Offset16;
- USHORT Segment16;
+typedef struct _PTR_32_BIT_STRUCTURE
+{
+ USHORT Offset16;
+ USHORT Segment16;
} PTR_32_BIT_STRUCTURE;
-typedef union _PTR_32_BIT_UNION {
- PTR_32_BIT_STRUCTURE SegmentOffset;
- ULONG Ptr32_Bit;
+typedef union _PTR_32_BIT_UNION
+{
+ PTR_32_BIT_STRUCTURE SegmentOffset;
+ ULONG Ptr32_Bit;
} PTR_32_BIT_UNION;
-typedef struct _VBE_1_2_INFO_BLOCK_UPDATABLE {
- UCHAR VbeSignature[4];
- USHORT VbeVersion;
- PTR_32_BIT_UNION OemStringPtr;
- UCHAR Capabilities[4];
- PTR_32_BIT_UNION VideoModePtr;
- USHORT TotalMemory;
+typedef struct _VBE_1_2_INFO_BLOCK_UPDATABLE
+{
+ UCHAR VbeSignature[4];
+ USHORT VbeVersion;
+ PTR_32_BIT_UNION OemStringPtr;
+ UCHAR Capabilities[4];
+ PTR_32_BIT_UNION VideoModePtr;
+ USHORT TotalMemory;
} VBE_1_2_INFO_BLOCK_UPDATABLE;
-typedef struct _VBE_2_0_INFO_BLOCK_UPDATABLE {
- VBE_1_2_INFO_BLOCK_UPDATABLE CommonBlock;
- USHORT OemSoftRev;
- PTR_32_BIT_UNION OemVendorNamePtr;
- PTR_32_BIT_UNION OemProductNamePtr;
- PTR_32_BIT_UNION OemProductRevPtr;
+
+typedef struct _VBE_2_0_INFO_BLOCK_UPDATABLE
+{
+ VBE_1_2_INFO_BLOCK_UPDATABLE CommonBlock;
+ USHORT OemSoftRev;
+ PTR_32_BIT_UNION OemVendorNamePtr;
+ PTR_32_BIT_UNION OemProductNamePtr;
+ PTR_32_BIT_UNION OemProductRevPtr;
} VBE_2_0_INFO_BLOCK_UPDATABLE;
-typedef union _VBE_VERSION_UNION {
- VBE_2_0_INFO_BLOCK_UPDATABLE VBE_2_0_InfoBlock;
- VBE_1_2_INFO_BLOCK_UPDATABLE VBE_1_2_InfoBlock;
+typedef union _VBE_VERSION_UNION
+{
+ VBE_2_0_INFO_BLOCK_UPDATABLE VBE_2_0_InfoBlock;
+ VBE_1_2_INFO_BLOCK_UPDATABLE VBE_1_2_InfoBlock;
} VBE_VERSION_UNION;
-typedef struct _VBE_INFO_BLOCK {
- VBE_VERSION_UNION UpdatableVBE_Info;
- UCHAR Reserved[222];
- UCHAR OemData[256];
+typedef struct _VBE_INFO_BLOCK
+{
+ VBE_VERSION_UNION UpdatableVBE_Info;
+ UCHAR Reserved[222];
+ UCHAR OemData[256];
} VBE_INFO_BLOCK;
-typedef struct _VBE_FP_INFO {
- USHORT HSize;
- USHORT VSize;
- USHORT FPType;
- UCHAR RedBPP;
- UCHAR GreenBPP;
- UCHAR BlueBPP;
- UCHAR ReservedBPP;
- ULONG RsvdOffScrnMemSize;
- ULONG RsvdOffScrnMEmPtr;
- UCHAR Reserved[14];
+typedef struct _VBE_FP_INFO
+{
+ USHORT HSize;
+ USHORT VSize;
+ USHORT FPType;
+ UCHAR RedBPP;
+ UCHAR GreenBPP;
+ UCHAR BlueBPP;
+ UCHAR ReservedBPP;
+ ULONG RsvdOffScrnMemSize;
+ ULONG RsvdOffScrnMEmPtr;
+ UCHAR Reserved[14];
} VBE_FP_INFO;
-typedef struct _VESA_MODE_INFO_BLOCK {
-/* Mandatory information for all VBE revisions */
- USHORT ModeAttributes; /* dw ? ; mode attributes */
- UCHAR WinAAttributes; /* db ? ; window A attributes */
- UCHAR WinBAttributes; /* db ? ; window B attributes */
- USHORT WinGranularity; /* dw ? ; window granularity */
- USHORT WinSize; /* dw ? ; window size */
- USHORT WinASegment; /* dw ? ; window A start segment */
- USHORT WinBSegment; /* dw ? ; window B start segment */
- ULONG WinFuncPtr; /* dd ? ; real mode pointer to window function */
- USHORT BytesPerScanLine; /* dw ? ; bytes per scan line */
-
-/* ; Mandatory information for VBE 1.2 and above */
- USHORT XResolution; /* dw ? ; horizontal resolution in pixels or characters */
- USHORT YResolution; /* dw ? ; vertical resolution in pixels or characters */
- UCHAR XCharSize; /* db ? ; character cell width in pixels */
- UCHAR YCharSize; /* db ? ; character cell height in pixels */
- UCHAR NumberOfPlanes; /* db ? ; number of memory planes */
- UCHAR BitsPerPixel; /* db ? ; bits per pixel */
- UCHAR NumberOfBanks; /* db ? ; number of banks */
- UCHAR MemoryModel; /* db ? ; memory model type */
- UCHAR BankSize; /* db ? ; bank size in KB */
- UCHAR NumberOfImagePages; /* db ? ; number of images */
- UCHAR ReservedForPageFunction; /* db 1 ; reserved for page function */
-
-/* ; Direct Color fields(required for direct/6 and YUV/7 memory models) */
- UCHAR RedMaskSize; /* db ? ; size of direct color red mask in bits */
- UCHAR RedFieldPosition; /* db ? ; bit position of lsb of red mask */
- UCHAR GreenMaskSize; /* db ? ; size of direct color green mask in bits */
- UCHAR GreenFieldPosition; /* db ? ; bit position of lsb of green mask */
- UCHAR BlueMaskSize; /* db ? ; size of direct color blue mask in bits */
- UCHAR BlueFieldPosition; /* db ? ; bit position of lsb of blue mask */
- UCHAR RsvdMaskSize; /* db ? ; size of direct color reserved mask in bits */
- UCHAR RsvdFieldPosition; /* db ? ; bit position of lsb of reserved mask */
- UCHAR DirectColorModeInfo; /* db ? ; direct color mode attributes */
-
-/* ; Mandatory information for VBE 2.0 and above */
- ULONG PhysBasePtr; /* dd ? ; physical address for flat memory frame buffer */
- ULONG Reserved_1; /* dd 0 ; reserved - always set to 0 */
- USHORT Reserved_2; /* dw 0 ; reserved - always set to 0 */
-
-/* ; Mandatory information for VBE 3.0 and above */
- USHORT LinBytesPerScanLine; /* dw ? ; bytes per scan line for linear modes */
- UCHAR BnkNumberOfImagePages; /* db ? ; number of images for banked modes */
- UCHAR LinNumberOfImagPages; /* db ? ; number of images for linear modes */
- UCHAR LinRedMaskSize; /* db ? ; size of direct color red mask(linear modes) */
- UCHAR LinRedFieldPosition; /* db ? ; bit position of lsb of red mask(linear modes) */
- UCHAR LinGreenMaskSize; /* db ? ; size of direct color green mask(linear modes) */
- UCHAR LinGreenFieldPosition; /* db ? ; bit position of lsb of green mask(linear modes) */
- UCHAR LinBlueMaskSize; /* db ? ; size of direct color blue mask(linear modes) */
- UCHAR LinBlueFieldPosition; /* db ? ; bit position of lsb of blue mask(linear modes) */
- UCHAR LinRsvdMaskSize; /* db ? ; size of direct color reserved mask(linear modes) */
- UCHAR LinRsvdFieldPosition; /* db ? ; bit position of lsb of reserved mask(linear modes) */
- ULONG MaxPixelClock; /* dd ? ; maximum pixel clock(in Hz) for graphics mode */
- UCHAR Reserved; /* db 190 dup (0) */
+typedef struct _VESA_MODE_INFO_BLOCK
+{
+// Mandatory information for all VBE revisions
+ USHORT ModeAttributes; // dw ? ; mode attributes
+ UCHAR WinAAttributes; // db ? ; window A attributes
+ UCHAR WinBAttributes; // db ? ; window B attributes
+ USHORT WinGranularity; // dw ? ; window granularity
+ USHORT WinSize; // dw ? ; window size
+ USHORT WinASegment; // dw ? ; window A start segment
+ USHORT WinBSegment; // dw ? ; window B start segment
+ ULONG WinFuncPtr; // dd ? ; real mode pointer to window function
+ USHORT BytesPerScanLine;// dw ? ; bytes per scan line
+
+//; Mandatory information for VBE 1.2 and above
+ USHORT XResolution; // dw ? ; horizontal resolution in pixels or characters
+ USHORT YResolution; // dw ? ; vertical resolution in pixels or characters
+ UCHAR XCharSize; // db ? ; character cell width in pixels
+ UCHAR YCharSize; // db ? ; character cell height in pixels
+ UCHAR NumberOfPlanes; // db ? ; number of memory planes
+ UCHAR BitsPerPixel; // db ? ; bits per pixel
+ UCHAR NumberOfBanks; // db ? ; number of banks
+ UCHAR MemoryModel; // db ? ; memory model type
+ UCHAR BankSize; // db ? ; bank size in KB
+ UCHAR NumberOfImagePages;// db ? ; number of images
+ UCHAR ReservedForPageFunction;//db 1 ; reserved for page function
+
+//; Direct Color fields(required for direct/6 and YUV/7 memory models)
+ UCHAR RedMaskSize; // db ? ; size of direct color red mask in bits
+ UCHAR RedFieldPosition; // db ? ; bit position of lsb of red mask
+ UCHAR GreenMaskSize; // db ? ; size of direct color green mask in bits
+ UCHAR GreenFieldPosition; // db ? ; bit position of lsb of green mask
+ UCHAR BlueMaskSize; // db ? ; size of direct color blue mask in bits
+ UCHAR BlueFieldPosition; // db ? ; bit position of lsb of blue mask
+ UCHAR RsvdMaskSize; // db ? ; size of direct color reserved mask in bits
+ UCHAR RsvdFieldPosition; // db ? ; bit position of lsb of reserved mask
+ UCHAR DirectColorModeInfo;// db ? ; direct color mode attributes
+
+//; Mandatory information for VBE 2.0 and above
+ ULONG PhysBasePtr; // dd ? ; physical address for flat memory frame buffer
+ ULONG Reserved_1; // dd 0 ; reserved - always set to 0
+ USHORT Reserved_2; // dw 0 ; reserved - always set to 0
+
+//; Mandatory information for VBE 3.0 and above
+ USHORT LinBytesPerScanLine; // dw ? ; bytes per scan line for linear modes
+ UCHAR BnkNumberOfImagePages;// db ? ; number of images for banked modes
+ UCHAR LinNumberOfImagPages; // db ? ; number of images for linear modes
+ UCHAR LinRedMaskSize; // db ? ; size of direct color red mask(linear modes)
+ UCHAR LinRedFieldPosition; // db ? ; bit position of lsb of red mask(linear modes)
+ UCHAR LinGreenMaskSize; // db ? ; size of direct color green mask(linear modes)
+ UCHAR LinGreenFieldPosition;// db ? ; bit position of lsb of green mask(linear modes)
+ UCHAR LinBlueMaskSize; // db ? ; size of direct color blue mask(linear modes)
+ UCHAR LinBlueFieldPosition; // db ? ; bit position of lsb of blue mask(linear modes)
+ UCHAR LinRsvdMaskSize; // db ? ; size of direct color reserved mask(linear modes)
+ UCHAR LinRsvdFieldPosition; // db ? ; bit position of lsb of reserved mask(linear modes)
+ ULONG MaxPixelClock; // dd ? ; maximum pixel clock(in Hz) for graphics mode
+ UCHAR Reserved; // db 190 dup (0)
} VESA_MODE_INFO_BLOCK;
-/* BIOS function CALLS */
-#define ATOM_BIOS_EXTENDED_FUNCTION_CODE 0xA0 /* ATI Extended Function code */
+// BIOS function CALLS
+#define ATOM_BIOS_EXTENDED_FUNCTION_CODE 0xA0 // ATI Extended Function code
#define ATOM_BIOS_FUNCTION_COP_MODE 0x00
#define ATOM_BIOS_FUNCTION_SHORT_QUERY1 0x04
#define ATOM_BIOS_FUNCTION_SHORT_QUERY2 0x05
#define ATOM_BIOS_FUNCTION_SHORT_QUERY3 0x06
-#define ATOM_BIOS_FUNCTION_GET_DDC 0x0B
+#define ATOM_BIOS_FUNCTION_GET_DDC 0x0B
#define ATOM_BIOS_FUNCTION_ASIC_DSTATE 0x0E
#define ATOM_BIOS_FUNCTION_DEBUG_PLAY 0x0F
#define ATOM_BIOS_FUNCTION_STV_STD 0x16
@@ -4217,100 +5137,135 @@ typedef struct _VESA_MODE_INFO_BLOCK {
#define ATOM_BIOS_FUNCTION_PANEL_CONTROL 0x82
#define ATOM_BIOS_FUNCTION_OLD_DEVICE_DET 0x83
#define ATOM_BIOS_FUNCTION_OLD_DEVICE_SWITCH 0x84
-#define ATOM_BIOS_FUNCTION_HW_ICON 0x8A
+#define ATOM_BIOS_FUNCTION_HW_ICON 0x8A
#define ATOM_BIOS_FUNCTION_SET_CMOS 0x8B
-#define SUB_FUNCTION_UPDATE_DISPLAY_INFO 0x8000 /* Sub function 80 */
-#define SUB_FUNCTION_UPDATE_EXPANSION_INFO 0x8100 /* Sub function 80 */
+#define SUB_FUNCTION_UPDATE_DISPLAY_INFO 0x8000 // Sub function 80
+#define SUB_FUNCTION_UPDATE_EXPANSION_INFO 0x8100 // Sub function 80
#define ATOM_BIOS_FUNCTION_DISPLAY_INFO 0x8D
#define ATOM_BIOS_FUNCTION_DEVICE_ON_OFF 0x8E
-#define ATOM_BIOS_FUNCTION_VIDEO_STATE 0x8F
-#define ATOM_SUB_FUNCTION_GET_CRITICAL_STATE 0x0300 /* Sub function 03 */
-#define ATOM_SUB_FUNCTION_GET_LIDSTATE 0x0700 /* Sub function 7 */
-#define ATOM_SUB_FUNCTION_THERMAL_STATE_NOTICE 0x1400 /* Notify caller the current thermal state */
-#define ATOM_SUB_FUNCTION_CRITICAL_STATE_NOTICE 0x8300 /* Notify caller the current critical state */
-#define ATOM_SUB_FUNCTION_SET_LIDSTATE 0x8500 /* Sub function 85 */
-#define ATOM_SUB_FUNCTION_GET_REQ_DISPLAY_FROM_SBIOS_MODE 0x8900 /* Sub function 89 */
-#define ATOM_SUB_FUNCTION_INFORM_ADC_SUPPORT 0x9400 /* Notify caller that ADC is supported */
-
-#define ATOM_BIOS_FUNCTION_VESA_DPMS 0x4F10 /* Set DPMS */
-#define ATOM_SUB_FUNCTION_SET_DPMS 0x0001 /* BL: Sub function 01 */
-#define ATOM_SUB_FUNCTION_GET_DPMS 0x0002 /* BL: Sub function 02 */
-#define ATOM_PARAMETER_VESA_DPMS_ON 0x0000 /* BH Parameter for DPMS ON. */
-#define ATOM_PARAMETER_VESA_DPMS_STANDBY 0x0100 /* BH Parameter for DPMS STANDBY */
-#define ATOM_PARAMETER_VESA_DPMS_SUSPEND 0x0200 /* BH Parameter for DPMS SUSPEND */
-#define ATOM_PARAMETER_VESA_DPMS_OFF 0x0400 /* BH Parameter for DPMS OFF */
-#define ATOM_PARAMETER_VESA_DPMS_REDUCE_ON 0x0800 /* BH Parameter for DPMS REDUCE ON (NOT SUPPORTED) */
+#define ATOM_BIOS_FUNCTION_VIDEO_STATE 0x8F
+#define ATOM_SUB_FUNCTION_GET_CRITICAL_STATE 0x0300 // Sub function 03
+#define ATOM_SUB_FUNCTION_GET_LIDSTATE 0x0700 // Sub function 7
+#define ATOM_SUB_FUNCTION_THERMAL_STATE_NOTICE 0x1400 // Notify caller the current thermal state
+#define ATOM_SUB_FUNCTION_CRITICAL_STATE_NOTICE 0x8300 // Notify caller the current critical state
+#define ATOM_SUB_FUNCTION_SET_LIDSTATE 0x8500 // Sub function 85
+#define ATOM_SUB_FUNCTION_GET_REQ_DISPLAY_FROM_SBIOS_MODE 0x8900// Sub function 89
+#define ATOM_SUB_FUNCTION_INFORM_ADC_SUPPORT 0x9400 // Notify caller that ADC is supported
+
+
+#define ATOM_BIOS_FUNCTION_VESA_DPMS 0x4F10 // Set DPMS
+#define ATOM_SUB_FUNCTION_SET_DPMS 0x0001 // BL: Sub function 01
+#define ATOM_SUB_FUNCTION_GET_DPMS 0x0002 // BL: Sub function 02
+#define ATOM_PARAMETER_VESA_DPMS_ON 0x0000 // BH Parameter for DPMS ON.
+#define ATOM_PARAMETER_VESA_DPMS_STANDBY 0x0100 // BH Parameter for DPMS STANDBY
+#define ATOM_PARAMETER_VESA_DPMS_SUSPEND 0x0200 // BH Parameter for DPMS SUSPEND
+#define ATOM_PARAMETER_VESA_DPMS_OFF 0x0400 // BH Parameter for DPMS OFF
+#define ATOM_PARAMETER_VESA_DPMS_REDUCE_ON 0x0800 // BH Parameter for DPMS REDUCE ON (NOT SUPPORTED)
#define ATOM_BIOS_RETURN_CODE_MASK 0x0000FF00L
#define ATOM_BIOS_REG_HIGH_MASK 0x0000FF00L
#define ATOM_BIOS_REG_LOW_MASK 0x000000FFL
-/* structure used for VBIOS only */
+// structure used for VBIOS only
-/* DispOutInfoTable */
-typedef struct _ASIC_TRANSMITTER_INFO {
+//DispOutInfoTable
+typedef struct _ASIC_TRANSMITTER_INFO
+{
USHORT usTransmitterObjId;
USHORT usSupportDevice;
- UCHAR ucTransmitterCmdTblId;
- UCHAR ucConfig;
- UCHAR ucEncoderID; /* available 1st encoder ( default ) */
- UCHAR ucOptionEncoderID; /* available 2nd encoder ( optional ) */
- UCHAR uc2ndEncoderID;
- UCHAR ucReserved;
-} ASIC_TRANSMITTER_INFO;
-
-typedef struct _ASIC_ENCODER_INFO {
+ UCHAR ucTransmitterCmdTblId;
+ UCHAR ucConfig;
+ UCHAR ucEncoderID; //available 1st encoder ( default )
+ UCHAR ucOptionEncoderID; //available 2nd encoder ( optional )
+ UCHAR uc2ndEncoderID;
+ UCHAR ucReserved;
+}ASIC_TRANSMITTER_INFO;
+
+typedef struct _ASIC_ENCODER_INFO
+{
UCHAR ucEncoderID;
UCHAR ucEncoderConfig;
- USHORT usEncoderCmdTblId;
-} ASIC_ENCODER_INFO;
+ USHORT usEncoderCmdTblId;
+}ASIC_ENCODER_INFO;
+
+typedef struct _ATOM_DISP_OUT_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT ptrTransmitterInfo;
+ USHORT ptrEncoderInfo;
+ ASIC_TRANSMITTER_INFO asTransmitterInfo[1];
+ ASIC_ENCODER_INFO asEncoderInfo[1];
+}ATOM_DISP_OUT_INFO;
-typedef struct _ATOM_DISP_OUT_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
+typedef struct _ATOM_DISP_OUT_INFO_V2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
USHORT ptrTransmitterInfo;
USHORT ptrEncoderInfo;
- ASIC_TRANSMITTER_INFO asTransmitterInfo[1];
- ASIC_ENCODER_INFO asEncoderInfo[1];
-} ATOM_DISP_OUT_INFO;
+ USHORT ptrMainCallParserFar; // direct address of main parser call in VBIOS binary.
+ ASIC_TRANSMITTER_INFO asTransmitterInfo[1];
+ ASIC_ENCODER_INFO asEncoderInfo[1];
+}ATOM_DISP_OUT_INFO_V2;
-/* DispDevicePriorityInfo */
-typedef struct _ATOM_DISPLAY_DEVICE_PRIORITY_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
+// DispDevicePriorityInfo
+typedef struct _ATOM_DISPLAY_DEVICE_PRIORITY_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
USHORT asDevicePriority[16];
-} ATOM_DISPLAY_DEVICE_PRIORITY_INFO;
-
-/* ProcessAuxChannelTransactionTable */
-typedef struct _PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS {
- USHORT lpAuxRequest;
- USHORT lpDataOut;
- UCHAR ucChannelID;
- union {
- UCHAR ucReplyStatus;
- UCHAR ucDelay;
+}ATOM_DISPLAY_DEVICE_PRIORITY_INFO;
+
+//ProcessAuxChannelTransactionTable
+typedef struct _PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS
+{
+ USHORT lpAuxRequest;
+ USHORT lpDataOut;
+ UCHAR ucChannelID;
+ union
+ {
+ UCHAR ucReplyStatus;
+ UCHAR ucDelay;
+ };
+ UCHAR ucDataOutLen;
+ UCHAR ucReserved;
+}PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS;
+
+//ProcessAuxChannelTransactionTable
+typedef struct _PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2
+{
+ USHORT lpAuxRequest;
+ USHORT lpDataOut;
+ UCHAR ucChannelID;
+ union
+ {
+ UCHAR ucReplyStatus;
+ UCHAR ucDelay;
};
- UCHAR ucDataOutLen;
- UCHAR ucReserved;
-} PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS;
+ UCHAR ucDataOutLen;
+ UCHAR ucHPD_ID; //=0: HPD1, =1: HPD2, =2: HPD3, =3: HPD4, =4: HPD5, =5: HPD6
+}PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2;
#define PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS
-/* GetSinkType */
+//GetSinkType
-typedef struct _DP_ENCODER_SERVICE_PARAMETERS {
+typedef struct _DP_ENCODER_SERVICE_PARAMETERS
+{
USHORT ucLinkClock;
- union {
- UCHAR ucConfig; /* for DP training command */
- UCHAR ucI2cId; /* use for GET_SINK_TYPE command */
+ union
+ {
+ UCHAR ucConfig; // for DP training command
+ UCHAR ucI2cId; // use for GET_SINK_TYPE command
};
UCHAR ucAction;
UCHAR ucStatus;
UCHAR ucLaneNum;
UCHAR ucReserved[2];
-} DP_ENCODER_SERVICE_PARAMETERS;
+}DP_ENCODER_SERVICE_PARAMETERS;
-/* ucAction */
+// ucAction
#define ATOM_DP_ACTION_GET_SINK_TYPE 0x01
+/* obselete */
#define ATOM_DP_ACTION_TRAINING_START 0x02
#define ATOM_DP_ACTION_TRAINING_COMPLETE 0x03
#define ATOM_DP_ACTION_TRAINING_PATTERN_SEL 0x04
@@ -4318,7 +5273,7 @@ typedef struct _DP_ENCODER_SERVICE_PARAMETERS {
#define ATOM_DP_ACTION_GET_VSWING_PREEMP 0x06
#define ATOM_DP_ACTION_BLANKING 0x07
-/* ucConfig */
+// ucConfig
#define ATOM_DP_CONFIG_ENCODER_SEL_MASK 0x03
#define ATOM_DP_CONFIG_DIG1_ENCODER 0x00
#define ATOM_DP_CONFIG_DIG2_ENCODER 0x01
@@ -4326,14 +5281,14 @@ typedef struct _DP_ENCODER_SERVICE_PARAMETERS {
#define ATOM_DP_CONFIG_LINK_SEL_MASK 0x04
#define ATOM_DP_CONFIG_LINK_A 0x00
#define ATOM_DP_CONFIG_LINK_B 0x04
-
+/* /obselete */
#define DP_ENCODER_SERVICE_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS
-/* DP_TRAINING_TABLE */
-#define DPCD_SET_LINKRATE_LANENUM_PATTERN1_TBL_ADDR ATOM_DP_TRAINING_TBL_ADDR
+// DP_TRAINING_TABLE
+#define DPCD_SET_LINKRATE_LANENUM_PATTERN1_TBL_ADDR ATOM_DP_TRAINING_TBL_ADDR
#define DPCD_SET_SS_CNTL_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 8 )
-#define DPCD_SET_LANE_VSWING_PREEMP_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 16)
-#define DPCD_SET_TRAINING_PATTERN0_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 24)
+#define DPCD_SET_LANE_VSWING_PREEMP_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 16 )
+#define DPCD_SET_TRAINING_PATTERN0_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 24 )
#define DPCD_SET_TRAINING_PATTERN2_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 32)
#define DPCD_GET_LINKRATE_LANENUM_SS_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 40)
#define DPCD_GET_LANE_STATUS_ADJUST_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 48)
@@ -4341,183 +5296,241 @@ typedef struct _DP_ENCODER_SERVICE_PARAMETERS {
#define DP_I2C_AUX_DDC_WRITE_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 64)
#define DP_I2C_AUX_DDC_READ_START_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 72)
#define DP_I2C_AUX_DDC_READ_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 76)
-#define DP_I2C_AUX_DDC_READ_END_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 80)
+#define DP_I2C_AUX_DDC_WRITE_END_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 80)
+#define DP_I2C_AUX_DDC_READ_END_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 84)
-typedef struct _PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS {
- UCHAR ucI2CSpeed;
- union {
- UCHAR ucRegIndex;
- UCHAR ucStatus;
+typedef struct _PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS
+{
+ UCHAR ucI2CSpeed;
+ union
+ {
+ UCHAR ucRegIndex;
+ UCHAR ucStatus;
};
- USHORT lpI2CDataOut;
- UCHAR ucFlag;
- UCHAR ucTransBytes;
- UCHAR ucSlaveAddr;
- UCHAR ucLineNumber;
-} PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS;
+ USHORT lpI2CDataOut;
+ UCHAR ucFlag;
+ UCHAR ucTransBytes;
+ UCHAR ucSlaveAddr;
+ UCHAR ucLineNumber;
+}PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS;
#define PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS
-/* ucFlag */
+//ucFlag
#define HW_I2C_WRITE 1
#define HW_I2C_READ 0
+#define I2C_2BYTE_ADDR 0x02
+typedef struct _SET_HWBLOCK_INSTANCE_PARAMETER_V2
+{
+ UCHAR ucHWBlkInst; // HW block instance, 0, 1, 2, ...
+ UCHAR ucReserved[3];
+}SET_HWBLOCK_INSTANCE_PARAMETER_V2;
+
+#define HWBLKINST_INSTANCE_MASK 0x07
+#define HWBLKINST_HWBLK_MASK 0xF0
+#define HWBLKINST_HWBLK_SHIFT 0x04
+
+//ucHWBlock
+#define SELECT_DISP_ENGINE 0
+#define SELECT_DISP_PLL 1
+#define SELECT_DCIO_UNIPHY_LINK0 2
+#define SELECT_DCIO_UNIPHY_LINK1 3
+#define SELECT_DCIO_IMPCAL 4
+#define SELECT_DCIO_DIG 6
+#define SELECT_CRTC_PIXEL_RATE 7
+
+/****************************************************************************/
+//Portion VI: Definitinos for vbios MC scratch registers that driver used
/****************************************************************************/
-/* Portion VI: Definitinos being oboselete */
+
+#define MC_MISC0__MEMORY_TYPE_MASK 0xF0000000
+#define MC_MISC0__MEMORY_TYPE__GDDR1 0x10000000
+#define MC_MISC0__MEMORY_TYPE__DDR2 0x20000000
+#define MC_MISC0__MEMORY_TYPE__GDDR3 0x30000000
+#define MC_MISC0__MEMORY_TYPE__GDDR4 0x40000000
+#define MC_MISC0__MEMORY_TYPE__GDDR5 0x50000000
+#define MC_MISC0__MEMORY_TYPE__DDR3 0xB0000000
+
+/****************************************************************************/
+//Portion VI: Definitinos being oboselete
/****************************************************************************/
-/* ========================================================================================== */
-/* Remove the definitions below when driver is ready! */
-typedef struct _ATOM_DAC_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- USHORT usMaxFrequency; /* in 10kHz unit */
- USHORT usReserved;
-} ATOM_DAC_INFO;
-
-typedef struct _COMPASSIONATE_DATA {
- ATOM_COMMON_TABLE_HEADER sHeader;
-
- /* ============================== DAC1 portion */
- UCHAR ucDAC1_BG_Adjustment;
- UCHAR ucDAC1_DAC_Adjustment;
- USHORT usDAC1_FORCE_Data;
- /* ============================== DAC2 portion */
- UCHAR ucDAC2_CRT2_BG_Adjustment;
- UCHAR ucDAC2_CRT2_DAC_Adjustment;
- USHORT usDAC2_CRT2_FORCE_Data;
- USHORT usDAC2_CRT2_MUX_RegisterIndex;
- UCHAR ucDAC2_CRT2_MUX_RegisterInfo; /* Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low */
- UCHAR ucDAC2_NTSC_BG_Adjustment;
- UCHAR ucDAC2_NTSC_DAC_Adjustment;
- USHORT usDAC2_TV1_FORCE_Data;
- USHORT usDAC2_TV1_MUX_RegisterIndex;
- UCHAR ucDAC2_TV1_MUX_RegisterInfo; /* Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low */
- UCHAR ucDAC2_CV_BG_Adjustment;
- UCHAR ucDAC2_CV_DAC_Adjustment;
- USHORT usDAC2_CV_FORCE_Data;
- USHORT usDAC2_CV_MUX_RegisterIndex;
- UCHAR ucDAC2_CV_MUX_RegisterInfo; /* Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low */
- UCHAR ucDAC2_PAL_BG_Adjustment;
- UCHAR ucDAC2_PAL_DAC_Adjustment;
- USHORT usDAC2_TV2_FORCE_Data;
-} COMPASSIONATE_DATA;
+//==========================================================================================
+//Remove the definitions below when driver is ready!
+typedef struct _ATOM_DAC_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usMaxFrequency; // in 10kHz unit
+ USHORT usReserved;
+}ATOM_DAC_INFO;
+
+
+typedef struct _COMPASSIONATE_DATA
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+
+ //============================== DAC1 portion
+ UCHAR ucDAC1_BG_Adjustment;
+ UCHAR ucDAC1_DAC_Adjustment;
+ USHORT usDAC1_FORCE_Data;
+ //============================== DAC2 portion
+ UCHAR ucDAC2_CRT2_BG_Adjustment;
+ UCHAR ucDAC2_CRT2_DAC_Adjustment;
+ USHORT usDAC2_CRT2_FORCE_Data;
+ USHORT usDAC2_CRT2_MUX_RegisterIndex;
+ UCHAR ucDAC2_CRT2_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low
+ UCHAR ucDAC2_NTSC_BG_Adjustment;
+ UCHAR ucDAC2_NTSC_DAC_Adjustment;
+ USHORT usDAC2_TV1_FORCE_Data;
+ USHORT usDAC2_TV1_MUX_RegisterIndex;
+ UCHAR ucDAC2_TV1_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low
+ UCHAR ucDAC2_CV_BG_Adjustment;
+ UCHAR ucDAC2_CV_DAC_Adjustment;
+ USHORT usDAC2_CV_FORCE_Data;
+ USHORT usDAC2_CV_MUX_RegisterIndex;
+ UCHAR ucDAC2_CV_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low
+ UCHAR ucDAC2_PAL_BG_Adjustment;
+ UCHAR ucDAC2_PAL_DAC_Adjustment;
+ USHORT usDAC2_TV2_FORCE_Data;
+}COMPASSIONATE_DATA;
/****************************Supported Device Info Table Definitions**********************/
-/* ucConnectInfo: */
-/* [7:4] - connector type */
-/* = 1 - VGA connector */
-/* = 2 - DVI-I */
-/* = 3 - DVI-D */
-/* = 4 - DVI-A */
-/* = 5 - SVIDEO */
-/* = 6 - COMPOSITE */
-/* = 7 - LVDS */
-/* = 8 - DIGITAL LINK */
-/* = 9 - SCART */
-/* = 0xA - HDMI_type A */
-/* = 0xB - HDMI_type B */
-/* = 0xE - Special case1 (DVI+DIN) */
-/* Others=TBD */
-/* [3:0] - DAC Associated */
-/* = 0 - no DAC */
-/* = 1 - DACA */
-/* = 2 - DACB */
-/* = 3 - External DAC */
-/* Others=TBD */
-/* */
-
-typedef struct _ATOM_CONNECTOR_INFO {
+// ucConnectInfo:
+// [7:4] - connector type
+// = 1 - VGA connector
+// = 2 - DVI-I
+// = 3 - DVI-D
+// = 4 - DVI-A
+// = 5 - SVIDEO
+// = 6 - COMPOSITE
+// = 7 - LVDS
+// = 8 - DIGITAL LINK
+// = 9 - SCART
+// = 0xA - HDMI_type A
+// = 0xB - HDMI_type B
+// = 0xE - Special case1 (DVI+DIN)
+// Others=TBD
+// [3:0] - DAC Associated
+// = 0 - no DAC
+// = 1 - DACA
+// = 2 - DACB
+// = 3 - External DAC
+// Others=TBD
+//
+
+typedef struct _ATOM_CONNECTOR_INFO
+{
#if ATOM_BIG_ENDIAN
- UCHAR bfConnectorType:4;
- UCHAR bfAssociatedDAC:4;
+ UCHAR bfConnectorType:4;
+ UCHAR bfAssociatedDAC:4;
#else
- UCHAR bfAssociatedDAC:4;
- UCHAR bfConnectorType:4;
+ UCHAR bfAssociatedDAC:4;
+ UCHAR bfConnectorType:4;
#endif
-} ATOM_CONNECTOR_INFO;
+}ATOM_CONNECTOR_INFO;
+
+typedef union _ATOM_CONNECTOR_INFO_ACCESS
+{
+ ATOM_CONNECTOR_INFO sbfAccess;
+ UCHAR ucAccess;
+}ATOM_CONNECTOR_INFO_ACCESS;
-typedef union _ATOM_CONNECTOR_INFO_ACCESS {
- ATOM_CONNECTOR_INFO sbfAccess;
- UCHAR ucAccess;
-} ATOM_CONNECTOR_INFO_ACCESS;
+typedef struct _ATOM_CONNECTOR_INFO_I2C
+{
+ ATOM_CONNECTOR_INFO_ACCESS sucConnectorInfo;
+ ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;
+}ATOM_CONNECTOR_INFO_I2C;
-typedef struct _ATOM_CONNECTOR_INFO_I2C {
- ATOM_CONNECTOR_INFO_ACCESS sucConnectorInfo;
- ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;
-} ATOM_CONNECTOR_INFO_I2C;
-typedef struct _ATOM_SUPPORTED_DEVICES_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- USHORT usDeviceSupport;
- ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO];
-} ATOM_SUPPORTED_DEVICES_INFO;
+typedef struct _ATOM_SUPPORTED_DEVICES_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usDeviceSupport;
+ ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO];
+}ATOM_SUPPORTED_DEVICES_INFO;
#define NO_INT_SRC_MAPPED 0xFF
-typedef struct _ATOM_CONNECTOR_INC_SRC_BITMAP {
- UCHAR ucIntSrcBitmap;
-} ATOM_CONNECTOR_INC_SRC_BITMAP;
-
-typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- USHORT usDeviceSupport;
- ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2];
- ATOM_CONNECTOR_INC_SRC_BITMAP
- asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2];
-} ATOM_SUPPORTED_DEVICES_INFO_2;
-
-typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- USHORT usDeviceSupport;
- ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE];
- ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE];
-} ATOM_SUPPORTED_DEVICES_INFO_2d1;
+typedef struct _ATOM_CONNECTOR_INC_SRC_BITMAP
+{
+ UCHAR ucIntSrcBitmap;
+}ATOM_CONNECTOR_INC_SRC_BITMAP;
+
+typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usDeviceSupport;
+ ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2];
+ ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2];
+}ATOM_SUPPORTED_DEVICES_INFO_2;
+
+typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2d1
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usDeviceSupport;
+ ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE];
+ ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE];
+}ATOM_SUPPORTED_DEVICES_INFO_2d1;
#define ATOM_SUPPORTED_DEVICES_INFO_LAST ATOM_SUPPORTED_DEVICES_INFO_2d1
-typedef struct _ATOM_MISC_CONTROL_INFO {
- USHORT usFrequency;
- UCHAR ucPLL_ChargePump; /* PLL charge-pump gain control */
- UCHAR ucPLL_DutyCycle; /* PLL duty cycle control */
- UCHAR ucPLL_VCO_Gain; /* PLL VCO gain control */
- UCHAR ucPLL_VoltageSwing; /* PLL driver voltage swing control */
-} ATOM_MISC_CONTROL_INFO;
+
+
+typedef struct _ATOM_MISC_CONTROL_INFO
+{
+ USHORT usFrequency;
+ UCHAR ucPLL_ChargePump; // PLL charge-pump gain control
+ UCHAR ucPLL_DutyCycle; // PLL duty cycle control
+ UCHAR ucPLL_VCO_Gain; // PLL VCO gain control
+ UCHAR ucPLL_VoltageSwing; // PLL driver voltage swing control
+}ATOM_MISC_CONTROL_INFO;
+
#define ATOM_MAX_MISC_INFO 4
-typedef struct _ATOM_TMDS_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- USHORT usMaxFrequency; /* in 10Khz */
- ATOM_MISC_CONTROL_INFO asMiscInfo[ATOM_MAX_MISC_INFO];
-} ATOM_TMDS_INFO;
+typedef struct _ATOM_TMDS_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usMaxFrequency; // in 10Khz
+ ATOM_MISC_CONTROL_INFO asMiscInfo[ATOM_MAX_MISC_INFO];
+}ATOM_TMDS_INFO;
+
+
+typedef struct _ATOM_ENCODER_ANALOG_ATTRIBUTE
+{
+ UCHAR ucTVStandard; //Same as TV standards defined above,
+ UCHAR ucPadding[1];
+}ATOM_ENCODER_ANALOG_ATTRIBUTE;
-typedef struct _ATOM_ENCODER_ANALOG_ATTRIBUTE {
- UCHAR ucTVStandard; /* Same as TV standards defined above, */
- UCHAR ucPadding[1];
-} ATOM_ENCODER_ANALOG_ATTRIBUTE;
+typedef struct _ATOM_ENCODER_DIGITAL_ATTRIBUTE
+{
+ UCHAR ucAttribute; //Same as other digital encoder attributes defined above
+ UCHAR ucPadding[1];
+}ATOM_ENCODER_DIGITAL_ATTRIBUTE;
-typedef struct _ATOM_ENCODER_DIGITAL_ATTRIBUTE {
- UCHAR ucAttribute; /* Same as other digital encoder attributes defined above */
- UCHAR ucPadding[1];
-} ATOM_ENCODER_DIGITAL_ATTRIBUTE;
+typedef union _ATOM_ENCODER_ATTRIBUTE
+{
+ ATOM_ENCODER_ANALOG_ATTRIBUTE sAlgAttrib;
+ ATOM_ENCODER_DIGITAL_ATTRIBUTE sDigAttrib;
+}ATOM_ENCODER_ATTRIBUTE;
-typedef union _ATOM_ENCODER_ATTRIBUTE {
- ATOM_ENCODER_ANALOG_ATTRIBUTE sAlgAttrib;
- ATOM_ENCODER_DIGITAL_ATTRIBUTE sDigAttrib;
-} ATOM_ENCODER_ATTRIBUTE;
-typedef struct _DVO_ENCODER_CONTROL_PARAMETERS {
- USHORT usPixelClock;
- USHORT usEncoderID;
- UCHAR ucDeviceType; /* Use ATOM_DEVICE_xxx1_Index to indicate device type only. */
- UCHAR ucAction; /* ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT */
- ATOM_ENCODER_ATTRIBUTE usDevAttr;
-} DVO_ENCODER_CONTROL_PARAMETERS;
+typedef struct _DVO_ENCODER_CONTROL_PARAMETERS
+{
+ USHORT usPixelClock;
+ USHORT usEncoderID;
+ UCHAR ucDeviceType; //Use ATOM_DEVICE_xxx1_Index to indicate device type only.
+ UCHAR ucAction; //ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT
+ ATOM_ENCODER_ATTRIBUTE usDevAttr;
+}DVO_ENCODER_CONTROL_PARAMETERS;
+
+typedef struct _DVO_ENCODER_CONTROL_PS_ALLOCATION
+{
+ DVO_ENCODER_CONTROL_PARAMETERS sDVOEncoder;
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion
+}DVO_ENCODER_CONTROL_PS_ALLOCATION;
-typedef struct _DVO_ENCODER_CONTROL_PS_ALLOCATION {
- DVO_ENCODER_CONTROL_PARAMETERS sDVOEncoder;
- WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; /* Caller doesn't need to init this portion */
-} DVO_ENCODER_CONTROL_PS_ALLOCATION;
#define ATOM_XTMDS_ASIC_SI164_ID 1
#define ATOM_XTMDS_ASIC_SI178_ID 2
@@ -4526,27 +5539,30 @@ typedef struct _DVO_ENCODER_CONTROL_PS_ALLOCATION {
#define ATOM_XTMDS_SUPPORTED_DUALLINK 0x00000002
#define ATOM_XTMDS_MVPU_FPGA 0x00000004
-typedef struct _ATOM_XTMDS_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- USHORT usSingleLinkMaxFrequency;
- ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; /* Point the ID on which I2C is used to control external chip */
- UCHAR ucXtransimitterID;
- UCHAR ucSupportedLink; /* Bit field, bit0=1, single link supported;bit1=1,dual link supported */
- UCHAR ucSequnceAlterID; /* Even with the same external TMDS asic, it's possible that the program seqence alters */
- /* due to design. This ID is used to alert driver that the sequence is not "standard"! */
- UCHAR ucMasterAddress; /* Address to control Master xTMDS Chip */
- UCHAR ucSlaveAddress; /* Address to control Slave xTMDS Chip */
-} ATOM_XTMDS_INFO;
-
-typedef struct _DFP_DPMS_STATUS_CHANGE_PARAMETERS {
- UCHAR ucEnable; /* ATOM_ENABLE=On or ATOM_DISABLE=Off */
- UCHAR ucDevice; /* ATOM_DEVICE_DFP1_INDEX.... */
- UCHAR ucPadding[2];
-} DFP_DPMS_STATUS_CHANGE_PARAMETERS;
+
+typedef struct _ATOM_XTMDS_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usSingleLinkMaxFrequency;
+ ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; //Point the ID on which I2C is used to control external chip
+ UCHAR ucXtransimitterID;
+ UCHAR ucSupportedLink; // Bit field, bit0=1, single link supported;bit1=1,dual link supported
+ UCHAR ucSequnceAlterID; // Even with the same external TMDS asic, it's possible that the program seqence alters
+ // due to design. This ID is used to alert driver that the sequence is not "standard"!
+ UCHAR ucMasterAddress; // Address to control Master xTMDS Chip
+ UCHAR ucSlaveAddress; // Address to control Slave xTMDS Chip
+}ATOM_XTMDS_INFO;
+
+typedef struct _DFP_DPMS_STATUS_CHANGE_PARAMETERS
+{
+ UCHAR ucEnable; // ATOM_ENABLE=On or ATOM_DISABLE=Off
+ UCHAR ucDevice; // ATOM_DEVICE_DFP1_INDEX....
+ UCHAR ucPadding[2];
+}DFP_DPMS_STATUS_CHANGE_PARAMETERS;
/****************************Legacy Power Play Table Definitions **********************/
-/* Definitions for ulPowerPlayMiscInfo */
+//Definitions for ulPowerPlayMiscInfo
#define ATOM_PM_MISCINFO_SPLIT_CLOCK 0x00000000L
#define ATOM_PM_MISCINFO_USING_MCLK_SRC 0x00000001L
#define ATOM_PM_MISCINFO_USING_SCLK_SRC 0x00000002L
@@ -4558,8 +5574,8 @@ typedef struct _DFP_DPMS_STATUS_CHANGE_PARAMETERS {
#define ATOM_PM_MISCINFO_ENGINE_CLOCK_CONTRL_EN 0x00000020L
#define ATOM_PM_MISCINFO_MEMORY_CLOCK_CONTRL_EN 0x00000040L
-#define ATOM_PM_MISCINFO_PROGRAM_VOLTAGE 0x00000080L /* When this bit set, ucVoltageDropIndex is not an index for GPIO pin, but a voltage ID that SW needs program */
-
+#define ATOM_PM_MISCINFO_PROGRAM_VOLTAGE 0x00000080L //When this bit set, ucVoltageDropIndex is not an index for GPIO pin, but a voltage ID that SW needs program
+
#define ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN 0x00000100L
#define ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN 0x00000200L
#define ATOM_PM_MISCINFO_ASIC_SLEEP_MODE_EN 0x00000400L
@@ -4569,22 +5585,22 @@ typedef struct _DFP_DPMS_STATUS_CHANGE_PARAMETERS {
#define ATOM_PM_MISCINFO_LOW_LCD_REFRESH_RATE 0x00004000L
#define ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE 0x00008000L
-#define ATOM_PM_MISCINFO_OVER_CLOCK_MODE 0x00010000L
+#define ATOM_PM_MISCINFO_OVER_CLOCK_MODE 0x00010000L
#define ATOM_PM_MISCINFO_OVER_DRIVE_MODE 0x00020000L
#define ATOM_PM_MISCINFO_POWER_SAVING_MODE 0x00040000L
#define ATOM_PM_MISCINFO_THERMAL_DIODE_MODE 0x00080000L
-#define ATOM_PM_MISCINFO_FRAME_MODULATION_MASK 0x00300000L /* 0-FM Disable, 1-2 level FM, 2-4 level FM, 3-Reserved */
-#define ATOM_PM_MISCINFO_FRAME_MODULATION_SHIFT 20
+#define ATOM_PM_MISCINFO_FRAME_MODULATION_MASK 0x00300000L //0-FM Disable, 1-2 level FM, 2-4 level FM, 3-Reserved
+#define ATOM_PM_MISCINFO_FRAME_MODULATION_SHIFT 20
#define ATOM_PM_MISCINFO_DYN_CLK_3D_IDLE 0x00400000L
#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2 0x00800000L
#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4 0x01000000L
-#define ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN 0x02000000L /* When set, Dynamic */
-#define ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN 0x04000000L /* When set, Dynamic */
-#define ATOM_PM_MISCINFO_3D_ACCELERATION_EN 0x08000000L /* When set, This mode is for acceleated 3D mode */
+#define ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN 0x02000000L //When set, Dynamic
+#define ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN 0x04000000L //When set, Dynamic
+#define ATOM_PM_MISCINFO_3D_ACCELERATION_EN 0x08000000L //When set, This mode is for acceleated 3D mode
-#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_MASK 0x70000000L /* 1-Optimal Battery Life Group, 2-High Battery, 3-Balanced, 4-High Performance, 5- Optimal Performance (Default state with Default clocks) */
+#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_MASK 0x70000000L //1-Optimal Battery Life Group, 2-High Battery, 3-Balanced, 4-High Performance, 5- Optimal Performance (Default state with Default clocks)
#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_SHIFT 28
#define ATOM_PM_MISCINFO_ENABLE_BACK_BIAS 0x80000000L
@@ -4594,55 +5610,59 @@ typedef struct _DFP_DPMS_STATUS_CHANGE_PARAMETERS {
#define ATOM_PM_MISCINFO2_FS3D_OVERDRIVE_INFO 0x00000008L
#define ATOM_PM_MISCINFO2_FORCEDLOWPWR_MODE 0x00000010L
#define ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN 0x00000020L
-#define ATOM_PM_MISCINFO2_VIDEO_PLAYBACK_CAPABLE 0x00000040L /* If this bit is set in multi-pp mode, then driver will pack up one with the minior power consumption. */
- /* If it's not set in any pp mode, driver will use its default logic to pick a pp mode in video playback */
+#define ATOM_PM_MISCINFO2_VIDEO_PLAYBACK_CAPABLE 0x00000040L //If this bit is set in multi-pp mode, then driver will pack up one with the minior power consumption.
+ //If it's not set in any pp mode, driver will use its default logic to pick a pp mode in video playback
#define ATOM_PM_MISCINFO2_NOT_VALID_ON_DC 0x00000080L
#define ATOM_PM_MISCINFO2_STUTTER_MODE_EN 0x00000100L
-#define ATOM_PM_MISCINFO2_UVD_SUPPORT_MODE 0x00000200L
-
-/* ucTableFormatRevision=1 */
-/* ucTableContentRevision=1 */
-typedef struct _ATOM_POWERMODE_INFO {
- ULONG ulMiscInfo; /* The power level should be arranged in ascending order */
- ULONG ulReserved1; /* must set to 0 */
- ULONG ulReserved2; /* must set to 0 */
- USHORT usEngineClock;
- USHORT usMemoryClock;
- UCHAR ucVoltageDropIndex; /* index to GPIO table */
- UCHAR ucSelectedPanel_RefreshRate; /* panel refresh rate */
- UCHAR ucMinTemperature;
- UCHAR ucMaxTemperature;
- UCHAR ucNumPciELanes; /* number of PCIE lanes */
-} ATOM_POWERMODE_INFO;
-
-/* ucTableFormatRevision=2 */
-/* ucTableContentRevision=1 */
-typedef struct _ATOM_POWERMODE_INFO_V2 {
- ULONG ulMiscInfo; /* The power level should be arranged in ascending order */
- ULONG ulMiscInfo2;
- ULONG ulEngineClock;
- ULONG ulMemoryClock;
- UCHAR ucVoltageDropIndex; /* index to GPIO table */
- UCHAR ucSelectedPanel_RefreshRate; /* panel refresh rate */
- UCHAR ucMinTemperature;
- UCHAR ucMaxTemperature;
- UCHAR ucNumPciELanes; /* number of PCIE lanes */
-} ATOM_POWERMODE_INFO_V2;
-
-/* ucTableFormatRevision=2 */
-/* ucTableContentRevision=2 */
-typedef struct _ATOM_POWERMODE_INFO_V3 {
- ULONG ulMiscInfo; /* The power level should be arranged in ascending order */
- ULONG ulMiscInfo2;
- ULONG ulEngineClock;
- ULONG ulMemoryClock;
- UCHAR ucVoltageDropIndex; /* index to Core (VDDC) votage table */
- UCHAR ucSelectedPanel_RefreshRate; /* panel refresh rate */
- UCHAR ucMinTemperature;
- UCHAR ucMaxTemperature;
- UCHAR ucNumPciELanes; /* number of PCIE lanes */
- UCHAR ucVDDCI_VoltageDropIndex; /* index to VDDCI votage table */
-} ATOM_POWERMODE_INFO_V3;
+#define ATOM_PM_MISCINFO2_UVD_SUPPORT_MODE 0x00000200L
+
+//ucTableFormatRevision=1
+//ucTableContentRevision=1
+typedef struct _ATOM_POWERMODE_INFO
+{
+ ULONG ulMiscInfo; //The power level should be arranged in ascending order
+ ULONG ulReserved1; // must set to 0
+ ULONG ulReserved2; // must set to 0
+ USHORT usEngineClock;
+ USHORT usMemoryClock;
+ UCHAR ucVoltageDropIndex; // index to GPIO table
+ UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate
+ UCHAR ucMinTemperature;
+ UCHAR ucMaxTemperature;
+ UCHAR ucNumPciELanes; // number of PCIE lanes
+}ATOM_POWERMODE_INFO;
+
+//ucTableFormatRevision=2
+//ucTableContentRevision=1
+typedef struct _ATOM_POWERMODE_INFO_V2
+{
+ ULONG ulMiscInfo; //The power level should be arranged in ascending order
+ ULONG ulMiscInfo2;
+ ULONG ulEngineClock;
+ ULONG ulMemoryClock;
+ UCHAR ucVoltageDropIndex; // index to GPIO table
+ UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate
+ UCHAR ucMinTemperature;
+ UCHAR ucMaxTemperature;
+ UCHAR ucNumPciELanes; // number of PCIE lanes
+}ATOM_POWERMODE_INFO_V2;
+
+//ucTableFormatRevision=2
+//ucTableContentRevision=2
+typedef struct _ATOM_POWERMODE_INFO_V3
+{
+ ULONG ulMiscInfo; //The power level should be arranged in ascending order
+ ULONG ulMiscInfo2;
+ ULONG ulEngineClock;
+ ULONG ulMemoryClock;
+ UCHAR ucVoltageDropIndex; // index to Core (VDDC) votage table
+ UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate
+ UCHAR ucMinTemperature;
+ UCHAR ucMaxTemperature;
+ UCHAR ucNumPciELanes; // number of PCIE lanes
+ UCHAR ucVDDCI_VoltageDropIndex; // index to VDDCI votage table
+}ATOM_POWERMODE_INFO_V3;
+
#define ATOM_MAX_NUMBEROF_POWER_BLOCK 8
@@ -4655,40 +5675,44 @@ typedef struct _ATOM_POWERMODE_INFO_V3 {
#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_MUA6649 0x04
#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_LM64 0x05
#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_F75375 0x06
-#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ASC7512 0x07 /* Andigilog */
-
-typedef struct _ATOM_POWERPLAY_INFO {
- ATOM_COMMON_TABLE_HEADER sHeader;
- UCHAR ucOverdriveThermalController;
- UCHAR ucOverdriveI2cLine;
- UCHAR ucOverdriveIntBitmap;
- UCHAR ucOverdriveControllerAddress;
- UCHAR ucSizeOfPowerModeEntry;
- UCHAR ucNumOfPowerModeEntries;
- ATOM_POWERMODE_INFO asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
-} ATOM_POWERPLAY_INFO;
-
-typedef struct _ATOM_POWERPLAY_INFO_V2 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- UCHAR ucOverdriveThermalController;
- UCHAR ucOverdriveI2cLine;
- UCHAR ucOverdriveIntBitmap;
- UCHAR ucOverdriveControllerAddress;
- UCHAR ucSizeOfPowerModeEntry;
- UCHAR ucNumOfPowerModeEntries;
- ATOM_POWERMODE_INFO_V2 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
-} ATOM_POWERPLAY_INFO_V2;
-
-typedef struct _ATOM_POWERPLAY_INFO_V3 {
- ATOM_COMMON_TABLE_HEADER sHeader;
- UCHAR ucOverdriveThermalController;
- UCHAR ucOverdriveI2cLine;
- UCHAR ucOverdriveIntBitmap;
- UCHAR ucOverdriveControllerAddress;
- UCHAR ucSizeOfPowerModeEntry;
- UCHAR ucNumOfPowerModeEntries;
- ATOM_POWERMODE_INFO_V3 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
-} ATOM_POWERPLAY_INFO_V3;
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ASC7512 0x07 // Andigilog
+
+
+typedef struct _ATOM_POWERPLAY_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucOverdriveThermalController;
+ UCHAR ucOverdriveI2cLine;
+ UCHAR ucOverdriveIntBitmap;
+ UCHAR ucOverdriveControllerAddress;
+ UCHAR ucSizeOfPowerModeEntry;
+ UCHAR ucNumOfPowerModeEntries;
+ ATOM_POWERMODE_INFO asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
+}ATOM_POWERPLAY_INFO;
+
+typedef struct _ATOM_POWERPLAY_INFO_V2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucOverdriveThermalController;
+ UCHAR ucOverdriveI2cLine;
+ UCHAR ucOverdriveIntBitmap;
+ UCHAR ucOverdriveControllerAddress;
+ UCHAR ucSizeOfPowerModeEntry;
+ UCHAR ucNumOfPowerModeEntries;
+ ATOM_POWERMODE_INFO_V2 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
+}ATOM_POWERPLAY_INFO_V2;
+
+typedef struct _ATOM_POWERPLAY_INFO_V3
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucOverdriveThermalController;
+ UCHAR ucOverdriveI2cLine;
+ UCHAR ucOverdriveIntBitmap;
+ UCHAR ucOverdriveControllerAddress;
+ UCHAR ucSizeOfPowerModeEntry;
+ UCHAR ucNumOfPowerModeEntries;
+ ATOM_POWERMODE_INFO_V3 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
+}ATOM_POWERPLAY_INFO_V3;
/* New PPlib */
/**************************************************************************/
@@ -4873,40 +5897,42 @@ typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO
UCHAR ucMaxHTLinkWidth; // From SBIOS - {2, 4, 8, 16}
UCHAR ucMinHTLinkWidth; // From SBIOS - {2, 4, 8, 16}. Effective only if CDLW enabled. Minimum down stream width could be bigger as display BW requriement.
USHORT usHTLinkFreq; // See definition ATOM_PPLIB_RS780_HTLINKFREQ_xxx or in MHz(>=200).
- ULONG ulFlags;
+ ULONG ulFlags;
} ATOM_PPLIB_RS780_CLOCK_INFO;
-#define ATOM_PPLIB_RS780_VOLTAGE_NONE 0
-#define ATOM_PPLIB_RS780_VOLTAGE_LOW 1
-#define ATOM_PPLIB_RS780_VOLTAGE_HIGH 2
-#define ATOM_PPLIB_RS780_VOLTAGE_VARIABLE 3
+#define ATOM_PPLIB_RS780_VOLTAGE_NONE 0
+#define ATOM_PPLIB_RS780_VOLTAGE_LOW 1
+#define ATOM_PPLIB_RS780_VOLTAGE_HIGH 2
+#define ATOM_PPLIB_RS780_VOLTAGE_VARIABLE 3
#define ATOM_PPLIB_RS780_SPMCLK_NONE 0 // We cannot change the side port memory clock, leave it as it is.
#define ATOM_PPLIB_RS780_SPMCLK_LOW 1
#define ATOM_PPLIB_RS780_SPMCLK_HIGH 2
-#define ATOM_PPLIB_RS780_HTLINKFREQ_NONE 0
-#define ATOM_PPLIB_RS780_HTLINKFREQ_LOW 1
-#define ATOM_PPLIB_RS780_HTLINKFREQ_HIGH 2
+#define ATOM_PPLIB_RS780_HTLINKFREQ_NONE 0
+#define ATOM_PPLIB_RS780_HTLINKFREQ_LOW 1
+#define ATOM_PPLIB_RS780_HTLINKFREQ_HIGH 2
/**************************************************************************/
-/* Following definitions are for compatiblity issue in different SW components. */
+
+// Following definitions are for compatiblity issue in different SW components.
#define ATOM_MASTER_DATA_TABLE_REVISION 0x01
-#define Object_Info Object_Header
+#define Object_Info Object_Header
#define AdjustARB_SEQ MC_InitParameter
#define VRAM_GPIO_DetectionInfo VoltageObjectInfo
-#define ASIC_VDDCI_Info ASIC_ProfilingInfo
+#define ASIC_VDDCI_Info ASIC_ProfilingInfo
#define ASIC_MVDDQ_Info MemoryTrainingInfo
-#define SS_Info PPLL_SS_Info
+#define SS_Info PPLL_SS_Info
#define ASIC_MVDDC_Info ASIC_InternalSS_Info
#define DispDevicePriorityInfo SaveRestoreInfo
#define DispOutInfo TV_VideoMode
+
#define ATOM_ENCODER_OBJECT_TABLE ATOM_OBJECT_TABLE
#define ATOM_CONNECTOR_OBJECT_TABLE ATOM_OBJECT_TABLE
-/* New device naming, remove them when both DAL/VBIOS is ready */
+//New device naming, remove them when both DAL/VBIOS is ready
#define DFP2I_OUTPUT_CONTROL_PARAMETERS CRT1_OUTPUT_CONTROL_PARAMETERS
#define DFP2I_OUTPUT_CONTROL_PS_ALLOCATION DFP2I_OUTPUT_CONTROL_PARAMETERS
@@ -4921,7 +5947,7 @@ typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO
#define ATOM_DEVICE_DFP1I_INDEX ATOM_DEVICE_DFP1_INDEX
#define ATOM_DEVICE_DFP1X_INDEX ATOM_DEVICE_DFP2_INDEX
-
+
#define ATOM_DEVICE_DFP2I_INDEX 0x00000009
#define ATOM_DEVICE_DFP2I_SUPPORT (0x1L << ATOM_DEVICE_DFP2I_INDEX)
@@ -4939,7 +5965,7 @@ typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO
#define ATOM_S3_DFP2I_ACTIVEb1 0x02
-#define ATOM_S3_DFP1I_ACTIVE ATOM_S3_DFP1_ACTIVE
+#define ATOM_S3_DFP1I_ACTIVE ATOM_S3_DFP1_ACTIVE
#define ATOM_S3_DFP1X_ACTIVE ATOM_S3_DFP2_ACTIVE
#define ATOM_S3_DFP2I_ACTIVE 0x00000200L
@@ -4958,14 +5984,14 @@ typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO
#define ATOM_S6_ACC_REQ_DFP2Ib3 0x02
#define ATOM_S6_ACC_REQ_DFP2I 0x02000000L
-#define TMDS1XEncoderControl DVOEncoderControl
+#define TMDS1XEncoderControl DVOEncoderControl
#define DFP1XOutputControl DVOOutputControl
#define ExternalDFPOutputControl DFP1XOutputControl
#define EnableExternalTMDS_Encoder TMDS1XEncoderControl
#define DFP1IOutputControl TMDSAOutputControl
-#define DFP2IOutputControl LVTMAOutputControl
+#define DFP2IOutputControl LVTMAOutputControl
#define DAC1_ENCODER_CONTROL_PARAMETERS DAC_ENCODER_CONTROL_PARAMETERS
#define DAC1_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION
@@ -4974,7 +6000,7 @@ typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO
#define DAC2_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION
#define ucDac1Standard ucDacStandard
-#define ucDac2Standard ucDacStandard
+#define ucDac2Standard ucDacStandard
#define TMDS1EncoderControl TMDSAEncoderControl
#define TMDS2EncoderControl LVTMAEncoderControl
@@ -4984,12 +6010,56 @@ typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO
#define CRT1OutputControl DAC1OutputControl
#define CRT2OutputControl DAC2OutputControl
-/* These two lines will be removed for sure in a few days, will follow up with Michael V. */
+//These two lines will be removed for sure in a few days, will follow up with Michael V.
#define EnableLVDS_SS EnableSpreadSpectrumOnPPLL
-#define ENABLE_LVDS_SS_PARAMETERS_V3 ENABLE_SPREAD_SPECTRUM_ON_PPLL
+#define ENABLE_LVDS_SS_PARAMETERS_V3 ENABLE_SPREAD_SPECTRUM_ON_PPLL
+
+//#define ATOM_S2_CRT1_DPMS_STATE 0x00010000L
+//#define ATOM_S2_LCD1_DPMS_STATE ATOM_S2_CRT1_DPMS_STATE
+//#define ATOM_S2_TV1_DPMS_STATE ATOM_S2_CRT1_DPMS_STATE
+//#define ATOM_S2_DFP1_DPMS_STATE ATOM_S2_CRT1_DPMS_STATE
+//#define ATOM_S2_CRT2_DPMS_STATE ATOM_S2_CRT1_DPMS_STATE
+
+#define ATOM_S6_ACC_REQ_TV2 0x00400000L
+#define ATOM_DEVICE_TV2_INDEX 0x00000006
+#define ATOM_DEVICE_TV2_SUPPORT (0x1L << ATOM_DEVICE_TV2_INDEX)
+#define ATOM_S0_TV2 0x00100000L
+#define ATOM_S3_TV2_ACTIVE ATOM_S3_DFP6_ACTIVE
+#define ATOM_S3_TV2_CRTC_ACTIVE ATOM_S3_DFP6_CRTC_ACTIVE
+
+//
+#define ATOM_S2_CRT1_DPMS_STATE 0x00010000L
+#define ATOM_S2_LCD1_DPMS_STATE 0x00020000L
+#define ATOM_S2_TV1_DPMS_STATE 0x00040000L
+#define ATOM_S2_DFP1_DPMS_STATE 0x00080000L
+#define ATOM_S2_CRT2_DPMS_STATE 0x00100000L
+#define ATOM_S2_LCD2_DPMS_STATE 0x00200000L
+#define ATOM_S2_TV2_DPMS_STATE 0x00400000L
+#define ATOM_S2_DFP2_DPMS_STATE 0x00800000L
+#define ATOM_S2_CV_DPMS_STATE 0x01000000L
+#define ATOM_S2_DFP3_DPMS_STATE 0x02000000L
+#define ATOM_S2_DFP4_DPMS_STATE 0x04000000L
+#define ATOM_S2_DFP5_DPMS_STATE 0x08000000L
+
+#define ATOM_S2_CRT1_DPMS_STATEb2 0x01
+#define ATOM_S2_LCD1_DPMS_STATEb2 0x02
+#define ATOM_S2_TV1_DPMS_STATEb2 0x04
+#define ATOM_S2_DFP1_DPMS_STATEb2 0x08
+#define ATOM_S2_CRT2_DPMS_STATEb2 0x10
+#define ATOM_S2_LCD2_DPMS_STATEb2 0x20
+#define ATOM_S2_TV2_DPMS_STATEb2 0x40
+#define ATOM_S2_DFP2_DPMS_STATEb2 0x80
+#define ATOM_S2_CV_DPMS_STATEb3 0x01
+#define ATOM_S2_DFP3_DPMS_STATEb3 0x02
+#define ATOM_S2_DFP4_DPMS_STATEb3 0x04
+#define ATOM_S2_DFP5_DPMS_STATEb3 0x08
+
+#define ATOM_S3_ASIC_GUI_ENGINE_HUNGb3 0x20
+#define ATOM_S3_ALLOW_FAST_PWR_SWITCHb3 0x40
+#define ATOM_S3_RQST_GPU_USE_MIN_PWRb3 0x80
/*********************************************************************************/
-#pragma pack() /* BIOS data must use byte aligment */
+#pragma pack() // BIOS data must use byte aligment
#endif /* _ATOMBIOS_H */
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 260fcf59f00c..dd9fdf560611 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -245,21 +245,25 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
switch (mode) {
case DRM_MODE_DPMS_ON:
- atombios_enable_crtc(crtc, 1);
+ atombios_enable_crtc(crtc, ATOM_ENABLE);
if (ASIC_IS_DCE3(rdev))
- atombios_enable_crtc_memreq(crtc, 1);
- atombios_blank_crtc(crtc, 0);
- drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
+ atombios_enable_crtc_memreq(crtc, ATOM_ENABLE);
+ atombios_blank_crtc(crtc, ATOM_DISABLE);
+ /* XXX re-enable when interrupt support is added */
+ if (!ASIC_IS_DCE4(rdev))
+ drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
radeon_crtc_load_lut(crtc);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
- drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
- atombios_blank_crtc(crtc, 1);
+ /* XXX re-enable when interrupt support is added */
+ if (!ASIC_IS_DCE4(rdev))
+ drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
+ atombios_blank_crtc(crtc, ATOM_ENABLE);
if (ASIC_IS_DCE3(rdev))
- atombios_enable_crtc_memreq(crtc, 0);
- atombios_enable_crtc(crtc, 0);
+ atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
+ atombios_enable_crtc(crtc, ATOM_DISABLE);
break;
}
}
@@ -307,7 +311,6 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
args.ucCRTC = radeon_crtc->crtc_id;
- printk("executing set crtc dtd timing\n");
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
@@ -347,10 +350,14 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc,
args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
args.ucCRTC = radeon_crtc->crtc_id;
- printk("executing set crtc timing\n");
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
+union atom_enable_ss {
+ ENABLE_LVDS_SS_PARAMETERS legacy;
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
+};
+
static void atombios_set_ss(struct drm_crtc *crtc, int enable)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
@@ -360,11 +367,14 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable)
struct radeon_encoder *radeon_encoder = NULL;
struct radeon_encoder_atom_dig *dig = NULL;
int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
- ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION args;
- ENABLE_LVDS_SS_PARAMETERS legacy_args;
+ union atom_enable_ss args;
uint16_t percentage = 0;
uint8_t type = 0, step = 0, delay = 0, range = 0;
+ /* XXX add ss support for DCE4 */
+ if (ASIC_IS_DCE4(rdev))
+ return;
+
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc == crtc) {
radeon_encoder = to_radeon_encoder(encoder);
@@ -388,80 +398,97 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable)
if (!radeon_encoder)
return;
+ memset(&args, 0, sizeof(args));
if (ASIC_IS_AVIVO(rdev)) {
- memset(&args, 0, sizeof(args));
- args.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
- args.ucSpreadSpectrumType = type;
- args.ucSpreadSpectrumStep = step;
- args.ucSpreadSpectrumDelay = delay;
- args.ucSpreadSpectrumRange = range;
- args.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
- args.ucEnable = enable;
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ args.v1.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
+ args.v1.ucSpreadSpectrumType = type;
+ args.v1.ucSpreadSpectrumStep = step;
+ args.v1.ucSpreadSpectrumDelay = delay;
+ args.v1.ucSpreadSpectrumRange = range;
+ args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
+ args.v1.ucEnable = enable;
} else {
- memset(&legacy_args, 0, sizeof(legacy_args));
- legacy_args.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
- legacy_args.ucSpreadSpectrumType = type;
- legacy_args.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2;
- legacy_args.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4;
- legacy_args.ucEnable = enable;
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&legacy_args);
+ args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
+ args.legacy.ucSpreadSpectrumType = type;
+ args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2;
+ args.legacy.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4;
+ args.legacy.ucEnable = enable;
}
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
-void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
+union adjust_pixel_clock {
+ ADJUST_DISPLAY_PLL_PS_ALLOCATION v1;
+ ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3;
+};
+
+static u32 atombios_adjust_pll(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct radeon_pll *pll)
{
- struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
struct drm_encoder *encoder = NULL;
struct radeon_encoder *radeon_encoder = NULL;
- uint8_t frev, crev;
- int index;
- SET_PIXEL_CLOCK_PS_ALLOCATION args;
- PIXEL_CLOCK_PARAMETERS *spc1_ptr;
- PIXEL_CLOCK_PARAMETERS_V2 *spc2_ptr;
- PIXEL_CLOCK_PARAMETERS_V3 *spc3_ptr;
- uint32_t pll_clock = mode->clock;
- uint32_t adjusted_clock;
- uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
- struct radeon_pll *pll;
- int pll_flags = 0;
+ u32 adjusted_clock = mode->clock;
+ int encoder_mode = 0;
- memset(&args, 0, sizeof(args));
+ /* reset the pll flags */
+ pll->flags = 0;
+
+ /* select the PLL algo */
+ if (ASIC_IS_AVIVO(rdev)) {
+ if (radeon_new_pll == 0)
+ pll->algo = PLL_ALGO_LEGACY;
+ else
+ pll->algo = PLL_ALGO_NEW;
+ } else {
+ if (radeon_new_pll == 1)
+ pll->algo = PLL_ALGO_NEW;
+ else
+ pll->algo = PLL_ALGO_LEGACY;
+ }
if (ASIC_IS_AVIVO(rdev)) {
if ((rdev->family == CHIP_RS600) ||
(rdev->family == CHIP_RS690) ||
(rdev->family == CHIP_RS740))
- pll_flags |= (RADEON_PLL_USE_FRAC_FB_DIV |
- RADEON_PLL_PREFER_CLOSEST_LOWER);
+ pll->flags |= (RADEON_PLL_USE_FRAC_FB_DIV |
+ RADEON_PLL_PREFER_CLOSEST_LOWER);
if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */
- pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
+ pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
else
- pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
+ pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
} else {
- pll_flags |= RADEON_PLL_LEGACY;
+ pll->flags |= RADEON_PLL_LEGACY;
if (mode->clock > 200000) /* range limits??? */
- pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
+ pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
else
- pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
+ pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
}
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc == crtc) {
- if (!ASIC_IS_AVIVO(rdev)) {
- if (encoder->encoder_type !=
- DRM_MODE_ENCODER_DAC)
- pll_flags |= RADEON_PLL_NO_ODD_POST_DIV;
- if (encoder->encoder_type ==
- DRM_MODE_ENCODER_LVDS)
- pll_flags |= RADEON_PLL_USE_REF_DIV;
- }
radeon_encoder = to_radeon_encoder(encoder);
+ encoder_mode = atombios_get_encoder_mode(encoder);
+ if (ASIC_IS_AVIVO(rdev)) {
+ /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
+ if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
+ adjusted_clock = mode->clock * 2;
+ /* LVDS PLL quirks */
+ if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) {
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ pll->algo = dig->pll_algo;
+ }
+ } else {
+ if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
+ pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
+ if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS)
+ pll->flags |= RADEON_PLL_USE_REF_DIV;
+ }
break;
}
}
@@ -471,46 +498,173 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
* special hw requirements.
*/
if (ASIC_IS_DCE3(rdev)) {
- ADJUST_DISPLAY_PLL_PS_ALLOCATION adjust_pll_args;
+ union adjust_pixel_clock args;
+ u8 frev, crev;
+ int index;
+
+ index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
+ atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
+ &crev);
+
+ memset(&args, 0, sizeof(args));
+
+ switch (frev) {
+ case 1:
+ switch (crev) {
+ case 1:
+ case 2:
+ args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
+ args.v1.ucTransmitterID = radeon_encoder->encoder_id;
+ args.v1.ucEncodeMode = encoder_mode;
+
+ atom_execute_table(rdev->mode_info.atom_context,
+ index, (uint32_t *)&args);
+ adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
+ break;
+ case 3:
+ args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10);
+ args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;
+ args.v3.sInput.ucEncodeMode = encoder_mode;
+ args.v3.sInput.ucDispPllConfig = 0;
+ if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+ if (encoder_mode == ATOM_ENCODER_MODE_DP)
+ args.v3.sInput.ucDispPllConfig |=
+ DISPPLL_CONFIG_COHERENT_MODE;
+ else {
+ if (dig->coherent_mode)
+ args.v3.sInput.ucDispPllConfig |=
+ DISPPLL_CONFIG_COHERENT_MODE;
+ if (mode->clock > 165000)
+ args.v3.sInput.ucDispPllConfig |=
+ DISPPLL_CONFIG_DUAL_LINK;
+ }
+ } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ /* may want to enable SS on DP/eDP eventually */
+ args.v3.sInput.ucDispPllConfig |=
+ DISPPLL_CONFIG_SS_ENABLE;
+ if (mode->clock > 165000)
+ args.v3.sInput.ucDispPllConfig |=
+ DISPPLL_CONFIG_DUAL_LINK;
+ }
+ atom_execute_table(rdev->mode_info.atom_context,
+ index, (uint32_t *)&args);
+ adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
+ if (args.v3.sOutput.ucRefDiv) {
+ pll->flags |= RADEON_PLL_USE_REF_DIV;
+ pll->reference_div = args.v3.sOutput.ucRefDiv;
+ }
+ if (args.v3.sOutput.ucPostDiv) {
+ pll->flags |= RADEON_PLL_USE_POST_DIV;
+ pll->post_div = args.v3.sOutput.ucPostDiv;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d %d\n", frev, crev);
+ return adjusted_clock;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d %d\n", frev, crev);
+ return adjusted_clock;
+ }
+ }
+ return adjusted_clock;
+}
+
+union set_pixel_clock {
+ SET_PIXEL_CLOCK_PS_ALLOCATION base;
+ PIXEL_CLOCK_PARAMETERS v1;
+ PIXEL_CLOCK_PARAMETERS_V2 v2;
+ PIXEL_CLOCK_PARAMETERS_V3 v3;
+ PIXEL_CLOCK_PARAMETERS_V5 v5;
+};
+
+static void atombios_crtc_set_dcpll(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ u8 frev, crev;
+ int index;
+ union set_pixel_clock args;
+
+ memset(&args, 0, sizeof(args));
+
+ index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
+ atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
+ &crev);
- if (!encoder)
+ switch (frev) {
+ case 1:
+ switch (crev) {
+ case 5:
+ /* if the default dcpll clock is specified,
+ * SetPixelClock provides the dividers
+ */
+ args.v5.ucCRTC = ATOM_CRTC_INVALID;
+ args.v5.usPixelClock = rdev->clock.default_dispclk;
+ args.v5.ucPpll = ATOM_DCPLL;
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d %d\n", frev, crev);
return;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d %d\n", frev, crev);
+ return;
+ }
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
- memset(&adjust_pll_args, 0, sizeof(adjust_pll_args));
- adjust_pll_args.usPixelClock = cpu_to_le16(mode->clock / 10);
- adjust_pll_args.ucTransmitterID = radeon_encoder->encoder_id;
- adjust_pll_args.ucEncodeMode = atombios_get_encoder_mode(encoder);
+static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
+{
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct drm_encoder *encoder = NULL;
+ struct radeon_encoder *radeon_encoder = NULL;
+ u8 frev, crev;
+ int index;
+ union set_pixel_clock args;
+ u32 pll_clock = mode->clock;
+ u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
+ struct radeon_pll *pll;
+ u32 adjusted_clock;
+ int encoder_mode = 0;
- index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
- atom_execute_table(rdev->mode_info.atom_context,
- index, (uint32_t *)&adjust_pll_args);
- adjusted_clock = le16_to_cpu(adjust_pll_args.usPixelClock) * 10;
- } else {
- /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
- if (ASIC_IS_AVIVO(rdev) &&
- (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1))
- adjusted_clock = mode->clock * 2;
- else
- adjusted_clock = mode->clock;
+ memset(&args, 0, sizeof(args));
+
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ if (encoder->crtc == crtc) {
+ radeon_encoder = to_radeon_encoder(encoder);
+ encoder_mode = atombios_get_encoder_mode(encoder);
+ break;
+ }
}
- if (radeon_crtc->crtc_id == 0)
+ if (!radeon_encoder)
+ return;
+
+ switch (radeon_crtc->pll_id) {
+ case ATOM_PPLL1:
pll = &rdev->clock.p1pll;
- else
+ break;
+ case ATOM_PPLL2:
pll = &rdev->clock.p2pll;
+ break;
+ case ATOM_DCPLL:
+ case ATOM_PPLL_INVALID:
+ pll = &rdev->clock.dcpll;
+ break;
+ }
- if (ASIC_IS_AVIVO(rdev)) {
- if (radeon_new_pll)
- radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock,
- &fb_div, &frac_fb_div,
- &ref_div, &post_div, pll_flags);
- else
- radeon_compute_pll(pll, adjusted_clock, &pll_clock,
- &fb_div, &frac_fb_div,
- &ref_div, &post_div, pll_flags);
- } else
- radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
- &ref_div, &post_div, pll_flags);
+ /* adjust pixel clock as needed */
+ adjusted_clock = atombios_adjust_pll(crtc, mode, pll);
+
+ radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
+ &ref_div, &post_div);
index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
@@ -520,46 +674,47 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
case 1:
switch (crev) {
case 1:
- spc1_ptr = (PIXEL_CLOCK_PARAMETERS *) & args.sPCLKInput;
- spc1_ptr->usPixelClock = cpu_to_le16(mode->clock / 10);
- spc1_ptr->usRefDiv = cpu_to_le16(ref_div);
- spc1_ptr->usFbDiv = cpu_to_le16(fb_div);
- spc1_ptr->ucFracFbDiv = frac_fb_div;
- spc1_ptr->ucPostDiv = post_div;
- spc1_ptr->ucPpll =
- radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
- spc1_ptr->ucCRTC = radeon_crtc->crtc_id;
- spc1_ptr->ucRefDivSrc = 1;
+ args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
+ args.v1.usRefDiv = cpu_to_le16(ref_div);
+ args.v1.usFbDiv = cpu_to_le16(fb_div);
+ args.v1.ucFracFbDiv = frac_fb_div;
+ args.v1.ucPostDiv = post_div;
+ args.v1.ucPpll = radeon_crtc->pll_id;
+ args.v1.ucCRTC = radeon_crtc->crtc_id;
+ args.v1.ucRefDivSrc = 1;
break;
case 2:
- spc2_ptr =
- (PIXEL_CLOCK_PARAMETERS_V2 *) & args.sPCLKInput;
- spc2_ptr->usPixelClock = cpu_to_le16(mode->clock / 10);
- spc2_ptr->usRefDiv = cpu_to_le16(ref_div);
- spc2_ptr->usFbDiv = cpu_to_le16(fb_div);
- spc2_ptr->ucFracFbDiv = frac_fb_div;
- spc2_ptr->ucPostDiv = post_div;
- spc2_ptr->ucPpll =
- radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
- spc2_ptr->ucCRTC = radeon_crtc->crtc_id;
- spc2_ptr->ucRefDivSrc = 1;
+ args.v2.usPixelClock = cpu_to_le16(mode->clock / 10);
+ args.v2.usRefDiv = cpu_to_le16(ref_div);
+ args.v2.usFbDiv = cpu_to_le16(fb_div);
+ args.v2.ucFracFbDiv = frac_fb_div;
+ args.v2.ucPostDiv = post_div;
+ args.v2.ucPpll = radeon_crtc->pll_id;
+ args.v2.ucCRTC = radeon_crtc->crtc_id;
+ args.v2.ucRefDivSrc = 1;
break;
case 3:
- if (!encoder)
- return;
- spc3_ptr =
- (PIXEL_CLOCK_PARAMETERS_V3 *) & args.sPCLKInput;
- spc3_ptr->usPixelClock = cpu_to_le16(mode->clock / 10);
- spc3_ptr->usRefDiv = cpu_to_le16(ref_div);
- spc3_ptr->usFbDiv = cpu_to_le16(fb_div);
- spc3_ptr->ucFracFbDiv = frac_fb_div;
- spc3_ptr->ucPostDiv = post_div;
- spc3_ptr->ucPpll =
- radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
- spc3_ptr->ucMiscInfo = (radeon_crtc->crtc_id << 2);
- spc3_ptr->ucTransmitterId = radeon_encoder->encoder_id;
- spc3_ptr->ucEncoderMode =
- atombios_get_encoder_mode(encoder);
+ args.v3.usPixelClock = cpu_to_le16(mode->clock / 10);
+ args.v3.usRefDiv = cpu_to_le16(ref_div);
+ args.v3.usFbDiv = cpu_to_le16(fb_div);
+ args.v3.ucFracFbDiv = frac_fb_div;
+ args.v3.ucPostDiv = post_div;
+ args.v3.ucPpll = radeon_crtc->pll_id;
+ args.v3.ucMiscInfo = (radeon_crtc->pll_id << 2);
+ args.v3.ucTransmitterId = radeon_encoder->encoder_id;
+ args.v3.ucEncoderMode = encoder_mode;
+ break;
+ case 5:
+ args.v5.ucCRTC = radeon_crtc->crtc_id;
+ args.v5.usPixelClock = cpu_to_le16(mode->clock / 10);
+ args.v5.ucRefDiv = ref_div;
+ args.v5.usFbDiv = cpu_to_le16(fb_div);
+ args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
+ args.v5.ucPostDiv = post_div;
+ args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
+ args.v5.ucTransmitterID = radeon_encoder->encoder_id;
+ args.v5.ucEncoderMode = encoder_mode;
+ args.v5.ucPpll = radeon_crtc->pll_id;
break;
default:
DRM_ERROR("Unknown table version %d %d\n", frev, crev);
@@ -571,12 +726,145 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
return;
}
- printk("executing set pll\n");
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
-int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
+static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_framebuffer *radeon_fb;
+ struct drm_gem_object *obj;
+ struct radeon_bo *rbo;
+ uint64_t fb_location;
+ uint32_t fb_format, fb_pitch_pixels, tiling_flags;
+ int r;
+
+ /* no fb bound */
+ if (!crtc->fb) {
+ DRM_DEBUG("No FB bound\n");
+ return 0;
+ }
+
+ radeon_fb = to_radeon_framebuffer(crtc->fb);
+
+ /* Pin framebuffer & get tilling informations */
+ obj = radeon_fb->obj;
+ rbo = obj->driver_private;
+ r = radeon_bo_reserve(rbo, false);
+ if (unlikely(r != 0))
+ return r;
+ r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
+ if (unlikely(r != 0)) {
+ radeon_bo_unreserve(rbo);
+ return -EINVAL;
+ }
+ radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
+ radeon_bo_unreserve(rbo);
+
+ switch (crtc->fb->bits_per_pixel) {
+ case 8:
+ fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) |
+ EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED));
+ break;
+ case 15:
+ fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
+ EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555));
+ break;
+ case 16:
+ fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
+ EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565));
+ break;
+ case 24:
+ case 32:
+ fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
+ EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888));
+ break;
+ default:
+ DRM_ERROR("Unsupported screen depth %d\n",
+ crtc->fb->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ switch (radeon_crtc->crtc_id) {
+ case 0:
+ WREG32(AVIVO_D1VGA_CONTROL, 0);
+ break;
+ case 1:
+ WREG32(AVIVO_D2VGA_CONTROL, 0);
+ break;
+ case 2:
+ WREG32(EVERGREEN_D3VGA_CONTROL, 0);
+ break;
+ case 3:
+ WREG32(EVERGREEN_D4VGA_CONTROL, 0);
+ break;
+ case 4:
+ WREG32(EVERGREEN_D5VGA_CONTROL, 0);
+ break;
+ case 5:
+ WREG32(EVERGREEN_D6VGA_CONTROL, 0);
+ break;
+ default:
+ break;
+ }
+
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
+ upper_32_bits(fb_location));
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
+ upper_32_bits(fb_location));
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+ (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+ (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
+ WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
+
+ WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
+ WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
+ WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0);
+ WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0);
+ WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
+ WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
+
+ fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
+ WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
+ WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
+
+ WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
+ crtc->mode.vdisplay);
+ x &= ~3;
+ y &= ~1;
+ WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset,
+ (x << 16) | y);
+ WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
+ (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
+
+ if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
+ WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset,
+ EVERGREEN_INTERLEAVE_EN);
+ else
+ WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
+
+ if (old_fb && old_fb != crtc->fb) {
+ radeon_fb = to_radeon_framebuffer(old_fb);
+ rbo = radeon_fb->obj->driver_private;
+ r = radeon_bo_reserve(rbo, false);
+ if (unlikely(r != 0))
+ return r;
+ radeon_bo_unpin(rbo);
+ radeon_bo_unreserve(rbo);
+ }
+
+ /* Bytes per pixel may have changed */
+ radeon_bandwidth_update(rdev);
+
+ return 0;
+}
+
+static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
@@ -706,6 +994,84 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
return 0;
}
+int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+
+ if (ASIC_IS_DCE4(rdev))
+ return evergreen_crtc_set_base(crtc, x, y, old_fb);
+ else if (ASIC_IS_AVIVO(rdev))
+ return avivo_crtc_set_base(crtc, x, y, old_fb);
+ else
+ return radeon_crtc_set_base(crtc, x, y, old_fb);
+}
+
+/* properly set additional regs when using atombios */
+static void radeon_legacy_atom_fixup(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ u32 disp_merge_cntl;
+
+ switch (radeon_crtc->crtc_id) {
+ case 0:
+ disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL);
+ disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
+ WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl);
+ break;
+ case 1:
+ disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
+ disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
+ WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl);
+ WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID));
+ WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID));
+ break;
+ }
+}
+
+static int radeon_atom_pick_pll(struct drm_crtc *crtc)
+{
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct drm_encoder *test_encoder;
+ struct drm_crtc *test_crtc;
+ uint32_t pll_in_use = 0;
+
+ if (ASIC_IS_DCE4(rdev)) {
+ /* if crtc is driving DP and we have an ext clock, use that */
+ list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
+ if (test_encoder->crtc && (test_encoder->crtc == crtc)) {
+ if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) {
+ if (rdev->clock.dp_extclk)
+ return ATOM_PPLL_INVALID;
+ }
+ }
+ }
+
+ /* otherwise, pick one of the plls */
+ list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
+ struct radeon_crtc *radeon_test_crtc;
+
+ if (crtc == test_crtc)
+ continue;
+
+ radeon_test_crtc = to_radeon_crtc(test_crtc);
+ if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) &&
+ (radeon_test_crtc->pll_id <= ATOM_PPLL2))
+ pll_in_use |= (1 << radeon_test_crtc->pll_id);
+ }
+ if (!(pll_in_use & 1))
+ return ATOM_PPLL1;
+ return ATOM_PPLL2;
+ } else
+ return radeon_crtc->crtc_id;
+
+}
+
int atombios_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -717,19 +1083,27 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
/* TODO color tiling */
+ /* pick pll */
+ radeon_crtc->pll_id = radeon_atom_pick_pll(crtc);
+
atombios_set_ss(crtc, 0);
+ /* always set DCPLL */
+ if (ASIC_IS_DCE4(rdev))
+ atombios_crtc_set_dcpll(crtc);
atombios_crtc_set_pll(crtc, adjusted_mode);
atombios_set_ss(crtc, 1);
- atombios_crtc_set_timing(crtc, adjusted_mode);
- if (ASIC_IS_AVIVO(rdev))
- atombios_crtc_set_base(crtc, x, y, old_fb);
+ if (ASIC_IS_DCE4(rdev))
+ atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
+ else if (ASIC_IS_AVIVO(rdev))
+ atombios_crtc_set_timing(crtc, adjusted_mode);
else {
+ atombios_crtc_set_timing(crtc, adjusted_mode);
if (radeon_crtc->crtc_id == 0)
atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
- radeon_crtc_set_base(crtc, x, y, old_fb);
- radeon_legacy_atom_set_surface(crtc);
+ radeon_legacy_atom_fixup(crtc);
}
+ atombios_crtc_set_base(crtc, x, y, old_fb);
atombios_overscan_setup(crtc, mode, adjusted_mode);
atombios_scaler_setup(crtc);
return 0;
@@ -746,14 +1120,14 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
static void atombios_crtc_prepare(struct drm_crtc *crtc)
{
+ atombios_lock_crtc(crtc, ATOM_ENABLE);
atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
- atombios_lock_crtc(crtc, 1);
}
static void atombios_crtc_commit(struct drm_crtc *crtc)
{
atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
- atombios_lock_crtc(crtc, 0);
+ atombios_lock_crtc(crtc, ATOM_DISABLE);
}
static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
@@ -769,8 +1143,37 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
void radeon_atombios_init_crtc(struct drm_device *dev,
struct radeon_crtc *radeon_crtc)
{
- if (radeon_crtc->crtc_id == 1)
- radeon_crtc->crtc_offset =
- AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL;
+ struct radeon_device *rdev = dev->dev_private;
+
+ if (ASIC_IS_DCE4(rdev)) {
+ switch (radeon_crtc->crtc_id) {
+ case 0:
+ default:
+ radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET;
+ break;
+ case 1:
+ radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET;
+ break;
+ case 2:
+ radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET;
+ break;
+ case 3:
+ radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET;
+ break;
+ case 4:
+ radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET;
+ break;
+ case 5:
+ radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET;
+ break;
+ }
+ } else {
+ if (radeon_crtc->crtc_id == 1)
+ radeon_crtc->crtc_offset =
+ AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL;
+ else
+ radeon_crtc->crtc_offset = 0;
+ }
+ radeon_crtc->pll_id = -1;
drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
}
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index 3eb0ca5b3d73..8a133bda00a2 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -321,6 +321,10 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
train_set[lane] = v | p;
}
+union aux_channel_transaction {
+ PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
+ PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
+};
/* radeon aux chan functions */
bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
@@ -329,39 +333,45 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
{
struct drm_device *dev = chan->dev;
struct radeon_device *rdev = dev->dev_private;
- PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION args;
+ union aux_channel_transaction args;
int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
unsigned char *base;
+ int retry_count = 0;
memset(&args, 0, sizeof(args));
base = (unsigned char *)rdev->mode_info.atom_context->scratch;
+retry:
memcpy(base, req_bytes, num_bytes);
- args.lpAuxRequest = 0;
- args.lpDataOut = 16;
- args.ucDataOutLen = 0;
- args.ucChannelID = chan->rec.i2c_id;
- args.ucDelay = delay / 10;
+ args.v1.lpAuxRequest = 0;
+ args.v1.lpDataOut = 16;
+ args.v1.ucDataOutLen = 0;
+ args.v1.ucChannelID = chan->rec.i2c_id;
+ args.v1.ucDelay = delay / 10;
+ if (ASIC_IS_DCE4(rdev))
+ args.v2.ucHPD_ID = chan->rec.hpd_id;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
- if (args.ucReplyStatus) {
- DRM_DEBUG("failed to get auxch %02x%02x %02x %02x 0x%02x %02x\n",
+ if (args.v1.ucReplyStatus && !args.v1.ucDataOutLen) {
+ if (args.v1.ucReplyStatus == 0x20 && retry_count++ < 10)
+ goto retry;
+ DRM_DEBUG("failed to get auxch %02x%02x %02x %02x 0x%02x %02x after %d retries\n",
req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3],
- chan->rec.i2c_id, args.ucReplyStatus);
+ chan->rec.i2c_id, args.v1.ucReplyStatus, retry_count);
return false;
}
- if (args.ucDataOutLen && read_byte && read_buf_len) {
- if (read_buf_len < args.ucDataOutLen) {
+ if (args.v1.ucDataOutLen && read_byte && read_buf_len) {
+ if (read_buf_len < args.v1.ucDataOutLen) {
DRM_ERROR("Buffer to small for return answer %d %d\n",
- read_buf_len, args.ucDataOutLen);
+ read_buf_len, args.v1.ucDataOutLen);
return false;
}
{
- int len = min(read_buf_len, args.ucDataOutLen);
+ int len = min(read_buf_len, args.v1.ucDataOutLen);
memcpy(read_byte, base + 16, len);
}
}
@@ -468,7 +478,7 @@ void radeon_dp_set_link_config(struct drm_connector *connector,
struct radeon_connector *radeon_connector;
struct radeon_connector_atom_dig *dig_connector;
- if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) ||
+ if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) &&
(connector->connector_type != DRM_MODE_CONNECTOR_eDP))
return;
@@ -583,7 +593,7 @@ void dp_link_train(struct drm_encoder *encoder,
u8 train_set[4];
int i;
- if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) ||
+ if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) &&
(connector->connector_type != DRM_MODE_CONNECTOR_eDP))
return;
@@ -596,21 +606,14 @@ void dp_link_train(struct drm_encoder *encoder,
return;
dig_connector = radeon_connector->con_priv;
- if (ASIC_IS_DCE32(rdev)) {
- if (dig->dig_block)
- enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER;
- else
- enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER;
- if (dig_connector->linkb)
- enc_id |= ATOM_DP_CONFIG_LINK_B;
- else
- enc_id |= ATOM_DP_CONFIG_LINK_A;
- } else {
- if (dig_connector->linkb)
- enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER | ATOM_DP_CONFIG_LINK_B;
- else
- enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER | ATOM_DP_CONFIG_LINK_A;
- }
+ if (dig->dig_encoder)
+ enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER;
+ else
+ enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER;
+ if (dig_connector->linkb)
+ enc_id |= ATOM_DP_CONFIG_LINK_B;
+ else
+ enc_id |= ATOM_DP_CONFIG_LINK_A;
memset(link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
if (dig_connector->dp_clock == 270000)
@@ -629,12 +632,19 @@ void dp_link_train(struct drm_encoder *encoder,
dp_set_link_bw_lanes(radeon_connector, link_configuration);
/* disable downspread on the sink */
dp_set_downspread(radeon_connector, 0);
- /* start training on the source */
- radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_START,
- dig_connector->dp_clock, enc_id, 0);
- /* set training pattern 1 on the source */
- radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
- dig_connector->dp_clock, enc_id, 0);
+ if (ASIC_IS_DCE4(rdev)) {
+ /* start training on the source */
+ atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_START);
+ /* set training pattern 1 on the source */
+ atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1);
+ } else {
+ /* start training on the source */
+ radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_START,
+ dig_connector->dp_clock, enc_id, 0);
+ /* set training pattern 1 on the source */
+ radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
+ dig_connector->dp_clock, enc_id, 0);
+ }
/* set initial vs/emph */
memset(train_set, 0, 4);
@@ -694,8 +704,11 @@ void dp_link_train(struct drm_encoder *encoder,
/* set training pattern 2 on the sink */
dp_set_training(radeon_connector, DP_TRAINING_PATTERN_2);
/* set training pattern 2 on the source */
- radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
- dig_connector->dp_clock, enc_id, 1);
+ if (ASIC_IS_DCE4(rdev))
+ atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2);
+ else
+ radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
+ dig_connector->dp_clock, enc_id, 1);
/* channel equalization loop */
tries = 0;
@@ -732,7 +745,11 @@ void dp_link_train(struct drm_encoder *encoder,
>> DP_TRAIN_PRE_EMPHASIS_SHIFT);
/* disable the training pattern on the sink */
- dp_set_training(radeon_connector, DP_TRAINING_PATTERN_DISABLE);
+ if (ASIC_IS_DCE4(rdev))
+ atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE);
+ else
+ radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,
+ dig_connector->dp_clock, enc_id, 0);
radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,
dig_connector->dp_clock, enc_id, 0);
diff --git a/drivers/gpu/drm/radeon/avivod.h b/drivers/gpu/drm/radeon/avivod.h
index d4e6e6e4a938..3c391e7e9fd4 100644
--- a/drivers/gpu/drm/radeon/avivod.h
+++ b/drivers/gpu/drm/radeon/avivod.h
@@ -30,11 +30,13 @@
#define D1CRTC_CONTROL 0x6080
#define CRTC_EN (1 << 0)
+#define D1CRTC_STATUS 0x609c
#define D1CRTC_UPDATE_LOCK 0x60E8
#define D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110
#define D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118
#define D2CRTC_CONTROL 0x6880
+#define D2CRTC_STATUS 0x689c
#define D2CRTC_UPDATE_LOCK 0x68E8
#define D2GRPH_PRIMARY_SURFACE_ADDRESS 0x6910
#define D2GRPH_SECONDARY_SURFACE_ADDRESS 0x6918
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
new file mode 100644
index 000000000000..bd2e7aa85c1d
--- /dev/null
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -0,0 +1,767 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Alex Deucher
+ */
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+#include "drmP.h"
+#include "radeon.h"
+#include "radeon_drm.h"
+#include "rv770d.h"
+#include "atom.h"
+#include "avivod.h"
+#include "evergreen_reg.h"
+
+static void evergreen_gpu_init(struct radeon_device *rdev);
+void evergreen_fini(struct radeon_device *rdev);
+
+bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
+{
+ bool connected = false;
+ /* XXX */
+ return connected;
+}
+
+void evergreen_hpd_set_polarity(struct radeon_device *rdev,
+ enum radeon_hpd_id hpd)
+{
+ /* XXX */
+}
+
+void evergreen_hpd_init(struct radeon_device *rdev)
+{
+ /* XXX */
+}
+
+
+void evergreen_bandwidth_update(struct radeon_device *rdev)
+{
+ /* XXX */
+}
+
+void evergreen_hpd_fini(struct radeon_device *rdev)
+{
+ /* XXX */
+}
+
+static int evergreen_mc_wait_for_idle(struct radeon_device *rdev)
+{
+ unsigned i;
+ u32 tmp;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ /* read MC_STATUS */
+ tmp = RREG32(SRBM_STATUS) & 0x1F00;
+ if (!tmp)
+ return 0;
+ udelay(1);
+ }
+ return -1;
+}
+
+/*
+ * GART
+ */
+int evergreen_pcie_gart_enable(struct radeon_device *rdev)
+{
+ u32 tmp;
+ int r, i;
+
+ if (rdev->gart.table.vram.robj == NULL) {
+ dev_err(rdev->dev, "No VRAM object for PCIE GART.\n");
+ return -EINVAL;
+ }
+ r = radeon_gart_table_vram_pin(rdev);
+ if (r)
+ return r;
+ radeon_gart_restore(rdev);
+ /* Setup L2 cache */
+ WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING |
+ ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+ EFFECTIVE_L2_QUEUE_SIZE(7));
+ WREG32(VM_L2_CNTL2, 0);
+ WREG32(VM_L2_CNTL3, BANK_SELECT(0) | CACHE_UPDATE_MODE(2));
+ /* Setup TLB control */
+ tmp = ENABLE_L1_TLB | ENABLE_L1_FRAGMENT_PROCESSING |
+ SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+ SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU |
+ EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5);
+ WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp);
+ WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp);
+ WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp);
+ WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);
+ WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12);
+ WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12);
+ WREG32(VM_CONTEXT0_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) |
+ RANGE_PROTECTION_FAULT_ENABLE_DEFAULT);
+ WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR,
+ (u32)(rdev->dummy_page.addr >> 12));
+ for (i = 1; i < 7; i++)
+ WREG32(VM_CONTEXT0_CNTL + (i * 4), 0);
+
+ r600_pcie_gart_tlb_flush(rdev);
+ rdev->gart.ready = true;
+ return 0;
+}
+
+void evergreen_pcie_gart_disable(struct radeon_device *rdev)
+{
+ u32 tmp;
+ int i, r;
+
+ /* Disable all tables */
+ for (i = 0; i < 7; i++)
+ WREG32(VM_CONTEXT0_CNTL + (i * 4), 0);
+
+ /* Setup L2 cache */
+ WREG32(VM_L2_CNTL, ENABLE_L2_FRAGMENT_PROCESSING |
+ EFFECTIVE_L2_QUEUE_SIZE(7));
+ WREG32(VM_L2_CNTL2, 0);
+ WREG32(VM_L2_CNTL3, BANK_SELECT(0) | CACHE_UPDATE_MODE(2));
+ /* Setup TLB control */
+ tmp = EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5);
+ WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp);
+ WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp);
+ WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp);
+ if (rdev->gart.table.vram.robj) {
+ r = radeon_bo_reserve(rdev->gart.table.vram.robj, false);
+ if (likely(r == 0)) {
+ radeon_bo_kunmap(rdev->gart.table.vram.robj);
+ radeon_bo_unpin(rdev->gart.table.vram.robj);
+ radeon_bo_unreserve(rdev->gart.table.vram.robj);
+ }
+ }
+}
+
+void evergreen_pcie_gart_fini(struct radeon_device *rdev)
+{
+ evergreen_pcie_gart_disable(rdev);
+ radeon_gart_table_vram_free(rdev);
+ radeon_gart_fini(rdev);
+}
+
+
+void evergreen_agp_enable(struct radeon_device *rdev)
+{
+ u32 tmp;
+ int i;
+
+ /* Setup L2 cache */
+ WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING |
+ ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+ EFFECTIVE_L2_QUEUE_SIZE(7));
+ WREG32(VM_L2_CNTL2, 0);
+ WREG32(VM_L2_CNTL3, BANK_SELECT(0) | CACHE_UPDATE_MODE(2));
+ /* Setup TLB control */
+ tmp = ENABLE_L1_TLB | ENABLE_L1_FRAGMENT_PROCESSING |
+ SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+ SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU |
+ EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5);
+ WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp);
+ WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp);
+ WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp);
+ for (i = 0; i < 7; i++)
+ WREG32(VM_CONTEXT0_CNTL + (i * 4), 0);
+}
+
+static void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
+{
+ save->vga_control[0] = RREG32(D1VGA_CONTROL);
+ save->vga_control[1] = RREG32(D2VGA_CONTROL);
+ save->vga_control[2] = RREG32(EVERGREEN_D3VGA_CONTROL);
+ save->vga_control[3] = RREG32(EVERGREEN_D4VGA_CONTROL);
+ save->vga_control[4] = RREG32(EVERGREEN_D5VGA_CONTROL);
+ save->vga_control[5] = RREG32(EVERGREEN_D6VGA_CONTROL);
+ save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
+ save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
+ save->crtc_control[0] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
+ save->crtc_control[1] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
+ save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET);
+ save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
+ save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET);
+ save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
+
+ /* Stop all video */
+ WREG32(VGA_RENDER_CONTROL, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+
+ WREG32(D1VGA_CONTROL, 0);
+ WREG32(D2VGA_CONTROL, 0);
+ WREG32(EVERGREEN_D3VGA_CONTROL, 0);
+ WREG32(EVERGREEN_D4VGA_CONTROL, 0);
+ WREG32(EVERGREEN_D5VGA_CONTROL, 0);
+ WREG32(EVERGREEN_D6VGA_CONTROL, 0);
+}
+
+static void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save)
+{
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
+ upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
+ (u32)rdev->mc.vram_start);
+
+ WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start);
+ /* Unlock host access */
+ WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);
+ mdelay(1);
+ /* Restore video state */
+ WREG32(D1VGA_CONTROL, save->vga_control[0]);
+ WREG32(D2VGA_CONTROL, save->vga_control[1]);
+ WREG32(EVERGREEN_D3VGA_CONTROL, save->vga_control[2]);
+ WREG32(EVERGREEN_D4VGA_CONTROL, save->vga_control[3]);
+ WREG32(EVERGREEN_D5VGA_CONTROL, save->vga_control[4]);
+ WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, save->crtc_control[0]);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, save->crtc_control[1]);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]);
+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+ WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
+}
+
+static void evergreen_mc_program(struct radeon_device *rdev)
+{
+ struct evergreen_mc_save save;
+ u32 tmp;
+ int i, j;
+
+ /* Initialize HDP */
+ for (i = 0, j = 0; i < 32; i++, j += 0x18) {
+ WREG32((0x2c14 + j), 0x00000000);
+ WREG32((0x2c18 + j), 0x00000000);
+ WREG32((0x2c1c + j), 0x00000000);
+ WREG32((0x2c20 + j), 0x00000000);
+ WREG32((0x2c24 + j), 0x00000000);
+ }
+ WREG32(HDP_REG_COHERENCY_FLUSH_CNTL, 0);
+
+ evergreen_mc_stop(rdev, &save);
+ if (evergreen_mc_wait_for_idle(rdev)) {
+ dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+ }
+ /* Lockout access through VGA aperture*/
+ WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE);
+ /* Update configuration */
+ if (rdev->flags & RADEON_IS_AGP) {
+ if (rdev->mc.vram_start < rdev->mc.gtt_start) {
+ /* VRAM before AGP */
+ WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
+ rdev->mc.vram_start >> 12);
+ WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+ rdev->mc.gtt_end >> 12);
+ } else {
+ /* VRAM after AGP */
+ WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
+ rdev->mc.gtt_start >> 12);
+ WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+ rdev->mc.vram_end >> 12);
+ }
+ } else {
+ WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
+ rdev->mc.vram_start >> 12);
+ WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+ rdev->mc.vram_end >> 12);
+ }
+ WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0);
+ tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16;
+ tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF);
+ WREG32(MC_VM_FB_LOCATION, tmp);
+ WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8));
+ WREG32(HDP_NONSURFACE_INFO, (2 << 7));
+ WREG32(HDP_NONSURFACE_SIZE, (rdev->mc.mc_vram_size - 1) | 0x3FF);
+ if (rdev->flags & RADEON_IS_AGP) {
+ WREG32(MC_VM_AGP_TOP, rdev->mc.gtt_end >> 16);
+ WREG32(MC_VM_AGP_BOT, rdev->mc.gtt_start >> 16);
+ WREG32(MC_VM_AGP_BASE, rdev->mc.agp_base >> 22);
+ } else {
+ WREG32(MC_VM_AGP_BASE, 0);
+ WREG32(MC_VM_AGP_TOP, 0x0FFFFFFF);
+ WREG32(MC_VM_AGP_BOT, 0x0FFFFFFF);
+ }
+ if (evergreen_mc_wait_for_idle(rdev)) {
+ dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+ }
+ evergreen_mc_resume(rdev, &save);
+ /* we need to own VRAM, so turn off the VGA renderer here
+ * to stop it overwriting our objects */
+ rv515_vga_render_disable(rdev);
+}
+
+#if 0
+/*
+ * CP.
+ */
+static void evergreen_cp_stop(struct radeon_device *rdev)
+{
+ /* XXX */
+}
+
+
+static int evergreen_cp_load_microcode(struct radeon_device *rdev)
+{
+ /* XXX */
+
+ return 0;
+}
+
+
+/*
+ * Core functions
+ */
+static u32 evergreen_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
+ u32 num_backends,
+ u32 backend_disable_mask)
+{
+ u32 backend_map = 0;
+
+ return backend_map;
+}
+#endif
+
+static void evergreen_gpu_init(struct radeon_device *rdev)
+{
+ /* XXX */
+}
+
+int evergreen_mc_init(struct radeon_device *rdev)
+{
+ fixed20_12 a;
+ u32 tmp;
+ int chansize, numchan;
+
+ /* Get VRAM informations */
+ rdev->mc.vram_is_ddr = true;
+ tmp = RREG32(MC_ARB_RAMCFG);
+ if (tmp & CHANSIZE_OVERRIDE) {
+ chansize = 16;
+ } else if (tmp & CHANSIZE_MASK) {
+ chansize = 64;
+ } else {
+ chansize = 32;
+ }
+ tmp = RREG32(MC_SHARED_CHMAP);
+ switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+ case 0:
+ default:
+ numchan = 1;
+ break;
+ case 1:
+ numchan = 2;
+ break;
+ case 2:
+ numchan = 4;
+ break;
+ case 3:
+ numchan = 8;
+ break;
+ }
+ rdev->mc.vram_width = numchan * chansize;
+ /* Could aper size report 0 ? */
+ rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+ rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ /* Setup GPU memory space */
+ /* size in MB on evergreen */
+ rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+ rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+ rdev->mc.visible_vram_size = rdev->mc.aper_size;
+ /* FIXME remove this once we support unmappable VRAM */
+ if (rdev->mc.mc_vram_size > rdev->mc.aper_size) {
+ rdev->mc.mc_vram_size = rdev->mc.aper_size;
+ rdev->mc.real_vram_size = rdev->mc.aper_size;
+ }
+ r600_vram_gtt_location(rdev, &rdev->mc);
+ /* FIXME: we should enforce default clock in case GPU is not in
+ * default setup
+ */
+ a.full = rfixed_const(100);
+ rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk);
+ rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a);
+ return 0;
+}
+
+int evergreen_gpu_reset(struct radeon_device *rdev)
+{
+ /* FIXME: implement for evergreen */
+ return 0;
+}
+
+static int evergreen_startup(struct radeon_device *rdev)
+{
+#if 0
+ int r;
+
+ if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
+ r = r600_init_microcode(rdev);
+ if (r) {
+ DRM_ERROR("Failed to load firmware!\n");
+ return r;
+ }
+ }
+#endif
+ evergreen_mc_program(rdev);
+#if 0
+ if (rdev->flags & RADEON_IS_AGP) {
+ evergreem_agp_enable(rdev);
+ } else {
+ r = evergreen_pcie_gart_enable(rdev);
+ if (r)
+ return r;
+ }
+#endif
+ evergreen_gpu_init(rdev);
+#if 0
+ if (!rdev->r600_blit.shader_obj) {
+ r = r600_blit_init(rdev);
+ if (r) {
+ DRM_ERROR("radeon: failed blitter (%d).\n", r);
+ return r;
+ }
+ }
+
+ r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+ if (unlikely(r != 0))
+ return r;
+ r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
+ &rdev->r600_blit.shader_gpu_addr);
+ radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+ if (r) {
+ DRM_ERROR("failed to pin blit object %d\n", r);
+ return r;
+ }
+
+ /* Enable IRQ */
+ r = r600_irq_init(rdev);
+ if (r) {
+ DRM_ERROR("radeon: IH init failed (%d).\n", r);
+ radeon_irq_kms_fini(rdev);
+ return r;
+ }
+ r600_irq_set(rdev);
+
+ r = radeon_ring_init(rdev, rdev->cp.ring_size);
+ if (r)
+ return r;
+ r = evergreen_cp_load_microcode(rdev);
+ if (r)
+ return r;
+ r = r600_cp_resume(rdev);
+ if (r)
+ return r;
+ /* write back buffer are not vital so don't worry about failure */
+ r600_wb_enable(rdev);
+#endif
+ return 0;
+}
+
+int evergreen_resume(struct radeon_device *rdev)
+{
+ int r;
+
+ /* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
+ * posting will perform necessary task to bring back GPU into good
+ * shape.
+ */
+ /* post card */
+ atom_asic_init(rdev->mode_info.atom_context);
+ /* Initialize clocks */
+ r = radeon_clocks_init(rdev);
+ if (r) {
+ return r;
+ }
+
+ r = evergreen_startup(rdev);
+ if (r) {
+ DRM_ERROR("r600 startup failed on resume\n");
+ return r;
+ }
+#if 0
+ r = r600_ib_test(rdev);
+ if (r) {
+ DRM_ERROR("radeon: failled testing IB (%d).\n", r);
+ return r;
+ }
+#endif
+ return r;
+
+}
+
+int evergreen_suspend(struct radeon_device *rdev)
+{
+#if 0
+ int r;
+
+ /* FIXME: we should wait for ring to be empty */
+ r700_cp_stop(rdev);
+ rdev->cp.ready = false;
+ r600_wb_disable(rdev);
+ evergreen_pcie_gart_disable(rdev);
+ /* unpin shaders bo */
+ r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+ if (likely(r == 0)) {
+ radeon_bo_unpin(rdev->r600_blit.shader_obj);
+ radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+ }
+#endif
+ return 0;
+}
+
+static bool evergreen_card_posted(struct radeon_device *rdev)
+{
+ u32 reg;
+
+ /* first check CRTCs */
+ reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) |
+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) |
+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) |
+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) |
+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
+ if (reg & EVERGREEN_CRTC_MASTER_EN)
+ return true;
+
+ /* then check MEM_SIZE, in case the crtcs are off */
+ if (RREG32(CONFIG_MEMSIZE))
+ return true;
+
+ return false;
+}
+
+/* Plan is to move initialization in that function and use
+ * helper function so that radeon_device_init pretty much
+ * do nothing more than calling asic specific function. This
+ * should also allow to remove a bunch of callback function
+ * like vram_info.
+ */
+int evergreen_init(struct radeon_device *rdev)
+{
+ int r;
+
+ r = radeon_dummy_page_init(rdev);
+ if (r)
+ return r;
+ /* This don't do much */
+ r = radeon_gem_init(rdev);
+ if (r)
+ return r;
+ /* Read BIOS */
+ if (!radeon_get_bios(rdev)) {
+ if (ASIC_IS_AVIVO(rdev))
+ return -EINVAL;
+ }
+ /* Must be an ATOMBIOS */
+ if (!rdev->is_atom_bios) {
+ dev_err(rdev->dev, "Expecting atombios for R600 GPU\n");
+ return -EINVAL;
+ }
+ r = radeon_atombios_init(rdev);
+ if (r)
+ return r;
+ /* Post card if necessary */
+ if (!evergreen_card_posted(rdev)) {
+ if (!rdev->bios) {
+ dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
+ return -EINVAL;
+ }
+ DRM_INFO("GPU not posted. posting now...\n");
+ atom_asic_init(rdev->mode_info.atom_context);
+ }
+ /* Initialize scratch registers */
+ r600_scratch_init(rdev);
+ /* Initialize surface registers */
+ radeon_surface_init(rdev);
+ /* Initialize clocks */
+ radeon_get_clock_info(rdev->ddev);
+ r = radeon_clocks_init(rdev);
+ if (r)
+ return r;
+ /* Initialize power management */
+ radeon_pm_init(rdev);
+ /* Fence driver */
+ r = radeon_fence_driver_init(rdev);
+ if (r)
+ return r;
+ /* initialize AGP */
+ if (rdev->flags & RADEON_IS_AGP) {
+ r = radeon_agp_init(rdev);
+ if (r)
+ radeon_agp_disable(rdev);
+ }
+ /* initialize memory controller */
+ r = evergreen_mc_init(rdev);
+ if (r)
+ return r;
+ /* Memory manager */
+ r = radeon_bo_init(rdev);
+ if (r)
+ return r;
+#if 0
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+
+ rdev->cp.ring_obj = NULL;
+ r600_ring_init(rdev, 1024 * 1024);
+
+ rdev->ih.ring_obj = NULL;
+ r600_ih_ring_init(rdev, 64 * 1024);
+
+ r = r600_pcie_gart_init(rdev);
+ if (r)
+ return r;
+#endif
+ rdev->accel_working = false;
+ r = evergreen_startup(rdev);
+ if (r) {
+ evergreen_suspend(rdev);
+ /*r600_wb_fini(rdev);*/
+ /*radeon_ring_fini(rdev);*/
+ /*evergreen_pcie_gart_fini(rdev);*/
+ rdev->accel_working = false;
+ }
+ if (rdev->accel_working) {
+ r = radeon_ib_pool_init(rdev);
+ if (r) {
+ DRM_ERROR("radeon: failed initializing IB pool (%d).\n", r);
+ rdev->accel_working = false;
+ }
+ r = r600_ib_test(rdev);
+ if (r) {
+ DRM_ERROR("radeon: failed testing IB (%d).\n", r);
+ rdev->accel_working = false;
+ }
+ }
+ return 0;
+}
+
+void evergreen_fini(struct radeon_device *rdev)
+{
+ evergreen_suspend(rdev);
+#if 0
+ r600_blit_fini(rdev);
+ r600_irq_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ radeon_ring_fini(rdev);
+ r600_wb_fini(rdev);
+ evergreen_pcie_gart_fini(rdev);
+#endif
+ radeon_gem_fini(rdev);
+ radeon_fence_driver_fini(rdev);
+ radeon_clocks_fini(rdev);
+ radeon_agp_fini(rdev);
+ radeon_bo_fini(rdev);
+ radeon_atombios_fini(rdev);
+ kfree(rdev->bios);
+ rdev->bios = NULL;
+ radeon_dummy_page_fini(rdev);
+}
diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h
new file mode 100644
index 000000000000..f7c7c9643433
--- /dev/null
+++ b/drivers/gpu/drm/radeon/evergreen_reg.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Alex Deucher
+ */
+#ifndef __EVERGREEN_REG_H__
+#define __EVERGREEN_REG_H__
+
+/* evergreen */
+#define EVERGREEN_VGA_MEMORY_BASE_ADDRESS 0x310
+#define EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH 0x324
+#define EVERGREEN_D3VGA_CONTROL 0x3e0
+#define EVERGREEN_D4VGA_CONTROL 0x3e4
+#define EVERGREEN_D5VGA_CONTROL 0x3e8
+#define EVERGREEN_D6VGA_CONTROL 0x3ec
+
+#define EVERGREEN_P1PLL_SS_CNTL 0x414
+#define EVERGREEN_P2PLL_SS_CNTL 0x454
+# define EVERGREEN_PxPLL_SS_EN (1 << 12)
+/* GRPH blocks at 0x6800, 0x7400, 0x10000, 0x10c00, 0x11800, 0x12400 */
+#define EVERGREEN_GRPH_ENABLE 0x6800
+#define EVERGREEN_GRPH_CONTROL 0x6804
+# define EVERGREEN_GRPH_DEPTH(x) (((x) & 0x3) << 0)
+# define EVERGREEN_GRPH_DEPTH_8BPP 0
+# define EVERGREEN_GRPH_DEPTH_16BPP 1
+# define EVERGREEN_GRPH_DEPTH_32BPP 2
+# define EVERGREEN_GRPH_FORMAT(x) (((x) & 0x7) << 8)
+/* 8 BPP */
+# define EVERGREEN_GRPH_FORMAT_INDEXED 0
+/* 16 BPP */
+# define EVERGREEN_GRPH_FORMAT_ARGB1555 0
+# define EVERGREEN_GRPH_FORMAT_ARGB565 1
+# define EVERGREEN_GRPH_FORMAT_ARGB4444 2
+# define EVERGREEN_GRPH_FORMAT_AI88 3
+# define EVERGREEN_GRPH_FORMAT_MONO16 4
+# define EVERGREEN_GRPH_FORMAT_BGRA5551 5
+/* 32 BPP */
+# define EVERGREEN_GRPH_FORMAT_ARGB8888 0
+# define EVERGREEN_GRPH_FORMAT_ARGB2101010 1
+# define EVERGREEN_GRPH_FORMAT_32BPP_DIG 2
+# define EVERGREEN_GRPH_FORMAT_8B_ARGB2101010 3
+# define EVERGREEN_GRPH_FORMAT_BGRA1010102 4
+# define EVERGREEN_GRPH_FORMAT_8B_BGRA1010102 5
+# define EVERGREEN_GRPH_FORMAT_RGB111110 6
+# define EVERGREEN_GRPH_FORMAT_BGR101111 7
+#define EVERGREEN_GRPH_SWAP_CONTROL 0x680c
+# define EVERGREEN_GRPH_ENDIAN_SWAP(x) (((x) & 0x3) << 0)
+# define EVERGREEN_GRPH_ENDIAN_NONE 0
+# define EVERGREEN_GRPH_ENDIAN_8IN16 1
+# define EVERGREEN_GRPH_ENDIAN_8IN32 2
+# define EVERGREEN_GRPH_ENDIAN_8IN64 3
+# define EVERGREEN_GRPH_RED_CROSSBAR(x) (((x) & 0x3) << 4)
+# define EVERGREEN_GRPH_RED_SEL_R 0
+# define EVERGREEN_GRPH_RED_SEL_G 1
+# define EVERGREEN_GRPH_RED_SEL_B 2
+# define EVERGREEN_GRPH_RED_SEL_A 3
+# define EVERGREEN_GRPH_GREEN_CROSSBAR(x) (((x) & 0x3) << 6)
+# define EVERGREEN_GRPH_GREEN_SEL_G 0
+# define EVERGREEN_GRPH_GREEN_SEL_B 1
+# define EVERGREEN_GRPH_GREEN_SEL_A 2
+# define EVERGREEN_GRPH_GREEN_SEL_R 3
+# define EVERGREEN_GRPH_BLUE_CROSSBAR(x) (((x) & 0x3) << 8)
+# define EVERGREEN_GRPH_BLUE_SEL_B 0
+# define EVERGREEN_GRPH_BLUE_SEL_A 1
+# define EVERGREEN_GRPH_BLUE_SEL_R 2
+# define EVERGREEN_GRPH_BLUE_SEL_G 3
+# define EVERGREEN_GRPH_ALPHA_CROSSBAR(x) (((x) & 0x3) << 10)
+# define EVERGREEN_GRPH_ALPHA_SEL_A 0
+# define EVERGREEN_GRPH_ALPHA_SEL_R 1
+# define EVERGREEN_GRPH_ALPHA_SEL_G 2
+# define EVERGREEN_GRPH_ALPHA_SEL_B 3
+#define EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS 0x6810
+#define EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS 0x6814
+# define EVERGREEN_GRPH_DFQ_ENABLE (1 << 0)
+# define EVERGREEN_GRPH_SURFACE_ADDRESS_MASK 0xffffff00
+#define EVERGREEN_GRPH_PITCH 0x6818
+#define EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x681c
+#define EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x6820
+#define EVERGREEN_GRPH_SURFACE_OFFSET_X 0x6824
+#define EVERGREEN_GRPH_SURFACE_OFFSET_Y 0x6828
+#define EVERGREEN_GRPH_X_START 0x682c
+#define EVERGREEN_GRPH_Y_START 0x6830
+#define EVERGREEN_GRPH_X_END 0x6834
+#define EVERGREEN_GRPH_Y_END 0x6838
+
+/* CUR blocks at 0x6998, 0x7598, 0x10198, 0x10d98, 0x11998, 0x12598 */
+#define EVERGREEN_CUR_CONTROL 0x6998
+# define EVERGREEN_CURSOR_EN (1 << 0)
+# define EVERGREEN_CURSOR_MODE(x) (((x) & 0x3) << 8)
+# define EVERGREEN_CURSOR_MONO 0
+# define EVERGREEN_CURSOR_24_1 1
+# define EVERGREEN_CURSOR_24_8_PRE_MULT 2
+# define EVERGREEN_CURSOR_24_8_UNPRE_MULT 3
+# define EVERGREEN_CURSOR_2X_MAGNIFY (1 << 16)
+# define EVERGREEN_CURSOR_FORCE_MC_ON (1 << 20)
+# define EVERGREEN_CURSOR_URGENT_CONTROL(x) (((x) & 0x7) << 24)
+# define EVERGREEN_CURSOR_URGENT_ALWAYS 0
+# define EVERGREEN_CURSOR_URGENT_1_8 1
+# define EVERGREEN_CURSOR_URGENT_1_4 2
+# define EVERGREEN_CURSOR_URGENT_3_8 3
+# define EVERGREEN_CURSOR_URGENT_1_2 4
+#define EVERGREEN_CUR_SURFACE_ADDRESS 0x699c
+# define EVERGREEN_CUR_SURFACE_ADDRESS_MASK 0xfffff000
+#define EVERGREEN_CUR_SIZE 0x69a0
+#define EVERGREEN_CUR_SURFACE_ADDRESS_HIGH 0x69a4
+#define EVERGREEN_CUR_POSITION 0x69a8
+#define EVERGREEN_CUR_HOT_SPOT 0x69ac
+#define EVERGREEN_CUR_COLOR1 0x69b0
+#define EVERGREEN_CUR_COLOR2 0x69b4
+#define EVERGREEN_CUR_UPDATE 0x69b8
+# define EVERGREEN_CURSOR_UPDATE_PENDING (1 << 0)
+# define EVERGREEN_CURSOR_UPDATE_TAKEN (1 << 1)
+# define EVERGREEN_CURSOR_UPDATE_LOCK (1 << 16)
+# define EVERGREEN_CURSOR_DISABLE_MULTIPLE_UPDATE (1 << 24)
+
+/* LUT blocks at 0x69e0, 0x75e0, 0x101e0, 0x10de0, 0x119e0, 0x125e0 */
+#define EVERGREEN_DC_LUT_RW_MODE 0x69e0
+#define EVERGREEN_DC_LUT_RW_INDEX 0x69e4
+#define EVERGREEN_DC_LUT_SEQ_COLOR 0x69e8
+#define EVERGREEN_DC_LUT_PWL_DATA 0x69ec
+#define EVERGREEN_DC_LUT_30_COLOR 0x69f0
+#define EVERGREEN_DC_LUT_VGA_ACCESS_ENABLE 0x69f4
+#define EVERGREEN_DC_LUT_WRITE_EN_MASK 0x69f8
+#define EVERGREEN_DC_LUT_AUTOFILL 0x69fc
+#define EVERGREEN_DC_LUT_CONTROL 0x6a00
+#define EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE 0x6a04
+#define EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN 0x6a08
+#define EVERGREEN_DC_LUT_BLACK_OFFSET_RED 0x6a0c
+#define EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE 0x6a10
+#define EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN 0x6a14
+#define EVERGREEN_DC_LUT_WHITE_OFFSET_RED 0x6a18
+
+#define EVERGREEN_DATA_FORMAT 0x6b00
+# define EVERGREEN_INTERLEAVE_EN (1 << 0)
+#define EVERGREEN_DESKTOP_HEIGHT 0x6b04
+
+#define EVERGREEN_VIEWPORT_START 0x6d70
+#define EVERGREEN_VIEWPORT_SIZE 0x6d74
+
+/* display controller offsets used for crtc/cur/lut/grph/viewport/etc. */
+#define EVERGREEN_CRTC0_REGISTER_OFFSET (0x6df0 - 0x6df0)
+#define EVERGREEN_CRTC1_REGISTER_OFFSET (0x79f0 - 0x6df0)
+#define EVERGREEN_CRTC2_REGISTER_OFFSET (0x105f0 - 0x6df0)
+#define EVERGREEN_CRTC3_REGISTER_OFFSET (0x111f0 - 0x6df0)
+#define EVERGREEN_CRTC4_REGISTER_OFFSET (0x11df0 - 0x6df0)
+#define EVERGREEN_CRTC5_REGISTER_OFFSET (0x129f0 - 0x6df0)
+
+/* CRTC blocks at 0x6df0, 0x79f0, 0x105f0, 0x111f0, 0x11df0, 0x129f0 */
+#define EVERGREEN_CRTC_CONTROL 0x6e70
+# define EVERGREEN_CRTC_MASTER_EN (1 << 0)
+#define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4
+
+#define EVERGREEN_DC_GPIO_HPD_MASK 0x64b0
+#define EVERGREEN_DC_GPIO_HPD_A 0x64b4
+#define EVERGREEN_DC_GPIO_HPD_EN 0x64b8
+#define EVERGREEN_DC_GPIO_HPD_Y 0x64bc
+
+#endif
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 8760d66e058a..91eb762eb3f9 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -197,13 +197,13 @@ int r100_pci_gart_enable(struct radeon_device *rdev)
{
uint32_t tmp;
+ radeon_gart_restore(rdev);
/* discard memory request outside of configured range */
tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS;
WREG32(RADEON_AIC_CNTL, tmp);
/* set address range for PCI address translate */
- WREG32(RADEON_AIC_LO_ADDR, rdev->mc.gtt_location);
- tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
- WREG32(RADEON_AIC_HI_ADDR, tmp);
+ WREG32(RADEON_AIC_LO_ADDR, rdev->mc.gtt_start);
+ WREG32(RADEON_AIC_HI_ADDR, rdev->mc.gtt_end);
/* set PCI GART page-table base address */
WREG32(RADEON_AIC_PT_BASE, rdev->gart.table_addr);
tmp = RREG32(RADEON_AIC_CNTL) | RADEON_PCIGART_TRANSLATE_EN;
@@ -312,9 +312,11 @@ int r100_irq_process(struct radeon_device *rdev)
/* Vertical blank interrupts */
if (status & RADEON_CRTC_VBLANK_STAT) {
drm_handle_vblank(rdev->ddev, 0);
+ wake_up(&rdev->irq.vblank_queue);
}
if (status & RADEON_CRTC2_VBLANK_STAT) {
drm_handle_vblank(rdev->ddev, 1);
+ wake_up(&rdev->irq.vblank_queue);
}
if (status & RADEON_FP_DETECT_STAT) {
queue_hotplug = true;
@@ -354,14 +356,20 @@ u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc)
return RREG32(RADEON_CRTC2_CRNT_FRAME);
}
+/* Who ever call radeon_fence_emit should call ring_lock and ask
+ * for enough space (today caller are ib schedule and buffer move) */
void r100_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence)
{
- /* Who ever call radeon_fence_emit should call ring_lock and ask
- * for enough space (today caller are ib schedule and buffer move) */
+ /* We have to make sure that caches are flushed before
+ * CPU might read something from VRAM. */
+ radeon_ring_write(rdev, PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0));
+ radeon_ring_write(rdev, RADEON_RB3D_DC_FLUSH_ALL);
+ radeon_ring_write(rdev, PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0));
+ radeon_ring_write(rdev, RADEON_RB3D_ZC_FLUSH_ALL);
/* Wait until IDLE & CLEAN */
- radeon_ring_write(rdev, PACKET0(0x1720, 0));
- radeon_ring_write(rdev, (1 << 16) | (1 << 17));
+ radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
+ radeon_ring_write(rdev, RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_3D_IDLECLEAN);
radeon_ring_write(rdev, PACKET0(RADEON_HOST_PATH_CNTL, 0));
radeon_ring_write(rdev, rdev->config.r100.hdp_cntl |
RADEON_HDP_READ_BUFFER_INVALIDATE);
@@ -1504,6 +1512,7 @@ static int r100_packet3_check(struct radeon_cs_parser *p,
DRM_ERROR("PRIM_WALK must be 3 for IMMD draw\n");
return -EINVAL;
}
+ track->vtx_size = r100_get_vtx_size(radeon_get_ib_value(p, idx + 0));
track->vap_vf_cntl = radeon_get_ib_value(p, idx + 1);
track->immd_dwords = pkt->count - 1;
r = r100_cs_track_check(p->rdev, track);
@@ -1694,7 +1703,7 @@ int r100_gui_wait_for_idle(struct radeon_device *rdev)
}
for (i = 0; i < rdev->usec_timeout; i++) {
tmp = RREG32(RADEON_RBBM_STATUS);
- if (!(tmp & (1 << 31))) {
+ if (!(tmp & RADEON_RBBM_ACTIVE)) {
return 0;
}
DRM_UDELAY(1);
@@ -1709,8 +1718,8 @@ int r100_mc_wait_for_idle(struct radeon_device *rdev)
for (i = 0; i < rdev->usec_timeout; i++) {
/* read MC_STATUS */
- tmp = RREG32(0x0150);
- if (tmp & (1 << 2)) {
+ tmp = RREG32(RADEON_MC_STATUS);
+ if (tmp & RADEON_MC_IDLE) {
return 0;
}
DRM_UDELAY(1);
@@ -1783,7 +1792,7 @@ int r100_gpu_reset(struct radeon_device *rdev)
}
/* Check if GPU is idle */
status = RREG32(RADEON_RBBM_STATUS);
- if (status & (1 << 31)) {
+ if (status & RADEON_RBBM_ACTIVE) {
DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
return -1;
}
@@ -1793,6 +1802,9 @@ int r100_gpu_reset(struct radeon_device *rdev)
void r100_set_common_regs(struct radeon_device *rdev)
{
+ struct drm_device *dev = rdev->ddev;
+ bool force_dac2 = false;
+
/* set these so they don't interfere with anything */
WREG32(RADEON_OV0_SCALE_CNTL, 0);
WREG32(RADEON_SUBPIC_CNTL, 0);
@@ -1801,6 +1813,68 @@ void r100_set_common_regs(struct radeon_device *rdev)
WREG32(RADEON_DVI_I2C_CNTL_1, 0);
WREG32(RADEON_CAP0_TRIG_CNTL, 0);
WREG32(RADEON_CAP1_TRIG_CNTL, 0);
+
+ /* always set up dac2 on rn50 and some rv100 as lots
+ * of servers seem to wire it up to a VGA port but
+ * don't report it in the bios connector
+ * table.
+ */
+ switch (dev->pdev->device) {
+ /* RN50 */
+ case 0x515e:
+ case 0x5969:
+ force_dac2 = true;
+ break;
+ /* RV100*/
+ case 0x5159:
+ case 0x515a:
+ /* DELL triple head servers */
+ if ((dev->pdev->subsystem_vendor == 0x1028 /* DELL */) &&
+ ((dev->pdev->subsystem_device == 0x016c) ||
+ (dev->pdev->subsystem_device == 0x016d) ||
+ (dev->pdev->subsystem_device == 0x016e) ||
+ (dev->pdev->subsystem_device == 0x016f) ||
+ (dev->pdev->subsystem_device == 0x0170) ||
+ (dev->pdev->subsystem_device == 0x017d) ||
+ (dev->pdev->subsystem_device == 0x017e) ||
+ (dev->pdev->subsystem_device == 0x0183) ||
+ (dev->pdev->subsystem_device == 0x018a) ||
+ (dev->pdev->subsystem_device == 0x019a)))
+ force_dac2 = true;
+ break;
+ }
+
+ if (force_dac2) {
+ u32 disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG);
+ u32 tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
+ u32 dac2_cntl = RREG32(RADEON_DAC_CNTL2);
+
+ /* For CRT on DAC2, don't turn it on if BIOS didn't
+ enable it, even it's detected.
+ */
+
+ /* force it to crtc0 */
+ dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL;
+ dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL;
+ disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
+
+ /* set up the TV DAC */
+ tv_dac_cntl &= ~(RADEON_TV_DAC_PEDESTAL |
+ RADEON_TV_DAC_STD_MASK |
+ RADEON_TV_DAC_RDACPD |
+ RADEON_TV_DAC_GDACPD |
+ RADEON_TV_DAC_BDACPD |
+ RADEON_TV_DAC_BGADJ_MASK |
+ RADEON_TV_DAC_DACADJ_MASK);
+ tv_dac_cntl |= (RADEON_TV_DAC_NBLANK |
+ RADEON_TV_DAC_NHOLD |
+ RADEON_TV_DAC_STD_PS2 |
+ (0x58 << 16));
+
+ WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
+ WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug);
+ WREG32(RADEON_DAC_CNTL2, dac2_cntl);
+ }
}
/*
@@ -1882,17 +1956,20 @@ static u32 r100_get_accessible_vram(struct radeon_device *rdev)
void r100_vram_init_sizes(struct radeon_device *rdev)
{
u64 config_aper_size;
- u32 accessible;
+ /* work out accessible VRAM */
+ rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+ rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ rdev->mc.visible_vram_size = r100_get_accessible_vram(rdev);
+ /* FIXME we don't use the second aperture yet when we could use it */
+ if (rdev->mc.visible_vram_size > rdev->mc.aper_size)
+ rdev->mc.visible_vram_size = rdev->mc.aper_size;
config_aper_size = RREG32(RADEON_CONFIG_APER_SIZE);
-
if (rdev->flags & RADEON_IS_IGP) {
uint32_t tom;
/* read NB_TOM to get the amount of ram stolen for the GPU */
tom = RREG32(RADEON_NB_TOM);
rdev->mc.real_vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16);
- /* for IGPs we need to keep VRAM where it was put by the BIOS */
- rdev->mc.vram_location = (tom & 0xffff) << 16;
WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size);
rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
} else {
@@ -1904,30 +1981,19 @@ void r100_vram_init_sizes(struct radeon_device *rdev)
rdev->mc.real_vram_size = 8192 * 1024;
WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size);
}
- /* let driver place VRAM */
- rdev->mc.vram_location = 0xFFFFFFFFUL;
- /* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM -
- * Novell bug 204882 + along with lots of ubuntu ones */
+ /* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM -
+ * Novell bug 204882 + along with lots of ubuntu ones
+ */
if (config_aper_size > rdev->mc.real_vram_size)
rdev->mc.mc_vram_size = config_aper_size;
else
rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
}
-
- /* work out accessible VRAM */
- accessible = r100_get_accessible_vram(rdev);
-
- rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
- rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
-
- if (accessible > rdev->mc.aper_size)
- accessible = rdev->mc.aper_size;
-
- if (rdev->mc.mc_vram_size > rdev->mc.aper_size)
+ /* FIXME remove this once we support unmappable VRAM */
+ if (rdev->mc.mc_vram_size > rdev->mc.aper_size) {
rdev->mc.mc_vram_size = rdev->mc.aper_size;
-
- if (rdev->mc.real_vram_size > rdev->mc.aper_size)
rdev->mc.real_vram_size = rdev->mc.aper_size;
+ }
}
void r100_vga_set_state(struct radeon_device *rdev, bool state)
@@ -1944,11 +2010,18 @@ void r100_vga_set_state(struct radeon_device *rdev, bool state)
WREG32(RADEON_CONFIG_CNTL, temp);
}
-void r100_vram_info(struct radeon_device *rdev)
+void r100_mc_init(struct radeon_device *rdev)
{
- r100_vram_get_type(rdev);
+ u64 base;
+ r100_vram_get_type(rdev);
r100_vram_init_sizes(rdev);
+ base = rdev->mc.aper_base;
+ if (rdev->flags & RADEON_IS_IGP)
+ base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16;
+ radeon_vram_location(rdev, &rdev->mc, base);
+ if (!(rdev->flags & RADEON_IS_AGP))
+ radeon_gtt_location(rdev, &rdev->mc);
}
@@ -3219,10 +3292,9 @@ void r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save)
void r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save)
{
/* Update base address for crtc */
- WREG32(R_00023C_DISPLAY_BASE_ADDR, rdev->mc.vram_location);
+ WREG32(R_00023C_DISPLAY_BASE_ADDR, rdev->mc.vram_start);
if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
- WREG32(R_00033C_CRTC2_DISPLAY_BASE_ADDR,
- rdev->mc.vram_location);
+ WREG32(R_00033C_CRTC2_DISPLAY_BASE_ADDR, rdev->mc.vram_start);
}
/* Restore CRTC registers */
WREG8(R_0003C2_GENMO_WT, save->GENMO_WT);
@@ -3368,7 +3440,6 @@ int r100_suspend(struct radeon_device *rdev)
void r100_fini(struct radeon_device *rdev)
{
- r100_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -3384,34 +3455,6 @@ void r100_fini(struct radeon_device *rdev)
rdev->bios = NULL;
}
-int r100_mc_init(struct radeon_device *rdev)
-{
- int r;
- u32 tmp;
-
- /* Setup GPU memory space */
- rdev->mc.vram_location = 0xFFFFFFFFUL;
- rdev->mc.gtt_location = 0xFFFFFFFFUL;
- if (rdev->flags & RADEON_IS_IGP) {
- tmp = G_00015C_MC_FB_START(RREG32(R_00015C_NB_TOM));
- rdev->mc.vram_location = tmp << 16;
- }
- if (rdev->flags & RADEON_IS_AGP) {
- r = radeon_agp_init(rdev);
- if (r) {
- printk(KERN_WARNING "[drm] Disabling AGP\n");
- rdev->flags &= ~RADEON_IS_AGP;
- rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
- } else {
- rdev->mc.gtt_location = rdev->mc.agp_base;
- }
- }
- r = radeon_mc_setup(rdev);
- if (r)
- return r;
- return 0;
-}
-
int r100_init(struct radeon_device *rdev)
{
int r;
@@ -3454,12 +3497,15 @@ int r100_init(struct radeon_device *rdev)
radeon_get_clock_info(rdev->ddev);
/* Initialize power management */
radeon_pm_init(rdev);
- /* Get vram informations */
- r100_vram_info(rdev);
- /* Initialize memory controller (also test AGP) */
- r = r100_mc_init(rdev);
- if (r)
- return r;
+ /* initialize AGP */
+ if (rdev->flags & RADEON_IS_AGP) {
+ r = radeon_agp_init(rdev);
+ if (r) {
+ radeon_agp_disable(rdev);
+ }
+ }
+ /* initialize VRAM */
+ r100_mc_init(rdev);
/* Fence driver */
r = radeon_fence_driver_init(rdev);
if (r)
@@ -3482,13 +3528,12 @@ int r100_init(struct radeon_device *rdev)
if (r) {
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
- r100_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
+ radeon_irq_kms_fini(rdev);
if (rdev->flags & RADEON_IS_PCI)
r100_pci_gart_fini(rdev);
- radeon_irq_kms_fini(rdev);
rdev->accel_working = false;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c
index 20942127c46b..1146c9909c2c 100644
--- a/drivers/gpu/drm/radeon/r200.c
+++ b/drivers/gpu/drm/radeon/r200.c
@@ -31,6 +31,7 @@
#include "radeon_reg.h"
#include "radeon.h"
+#include "r100d.h"
#include "r200_reg_safe.h"
#include "r100_track.h"
@@ -79,6 +80,51 @@ static int r200_get_vtx_size_0(uint32_t vtx_fmt_0)
return vtx_size;
}
+int r200_copy_dma(struct radeon_device *rdev,
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ unsigned num_pages,
+ struct radeon_fence *fence)
+{
+ uint32_t size;
+ uint32_t cur_size;
+ int i, num_loops;
+ int r = 0;
+
+ /* radeon pitch is /64 */
+ size = num_pages << PAGE_SHIFT;
+ num_loops = DIV_ROUND_UP(size, 0x1FFFFF);
+ r = radeon_ring_lock(rdev, num_loops * 4 + 64);
+ if (r) {
+ DRM_ERROR("radeon: moving bo (%d).\n", r);
+ return r;
+ }
+ /* Must wait for 2D idle & clean before DMA or hangs might happen */
+ radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
+ radeon_ring_write(rdev, (1 << 16));
+ for (i = 0; i < num_loops; i++) {
+ cur_size = size;
+ if (cur_size > 0x1FFFFF) {
+ cur_size = 0x1FFFFF;
+ }
+ size -= cur_size;
+ radeon_ring_write(rdev, PACKET0(0x720, 2));
+ radeon_ring_write(rdev, src_offset);
+ radeon_ring_write(rdev, dst_offset);
+ radeon_ring_write(rdev, cur_size | (1 << 31) | (1 << 30));
+ src_offset += cur_size;
+ dst_offset += cur_size;
+ }
+ radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
+ radeon_ring_write(rdev, RADEON_WAIT_DMA_GUI_IDLE);
+ if (fence) {
+ r = radeon_fence_emit(rdev, fence);
+ }
+ radeon_ring_unlock_commit(rdev);
+ return r;
+}
+
+
static int r200_get_vtx_size_1(uint32_t vtx_fmt_1)
{
int vtx_size, i, tex_size;
@@ -371,13 +417,16 @@ int r200_packet0_check(struct radeon_cs_parser *p,
case 5:
case 6:
case 7:
+ /* 1D/2D */
track->textures[i].tex_coord_type = 0;
break;
case 1:
- track->textures[i].tex_coord_type = 1;
+ /* CUBE */
+ track->textures[i].tex_coord_type = 2;
break;
case 2:
- track->textures[i].tex_coord_type = 2;
+ /* 3D */
+ track->textures[i].tex_coord_type = 1;
break;
}
break;
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 0051d11b907c..4cef90cd74e5 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -117,18 +117,19 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev)
r = radeon_gart_table_vram_pin(rdev);
if (r)
return r;
+ radeon_gart_restore(rdev);
/* discard memory request outside of configured range */
tmp = RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD;
WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp);
- WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, rdev->mc.gtt_location);
- tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - RADEON_GPU_PAGE_SIZE;
+ WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, rdev->mc.gtt_start);
+ tmp = rdev->mc.gtt_end & ~RADEON_GPU_PAGE_MASK;
WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, tmp);
WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0);
WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0);
table_addr = rdev->gart.table_addr;
WREG32_PCIE(RADEON_PCIE_TX_GART_BASE, table_addr);
/* FIXME: setup default page */
- WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, rdev->mc.vram_location);
+ WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, rdev->mc.vram_start);
WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_HI, 0);
/* Clear error */
WREG32_PCIE(0x18, 0);
@@ -174,18 +175,20 @@ void r300_fence_ring_emit(struct radeon_device *rdev,
/* Who ever call radeon_fence_emit should call ring_lock and ask
* for enough space (today caller are ib schedule and buffer move) */
/* Write SC register so SC & US assert idle */
- radeon_ring_write(rdev, PACKET0(0x43E0, 0));
+ radeon_ring_write(rdev, PACKET0(R300_RE_SCISSORS_TL, 0));
radeon_ring_write(rdev, 0);
- radeon_ring_write(rdev, PACKET0(0x43E4, 0));
+ radeon_ring_write(rdev, PACKET0(R300_RE_SCISSORS_BR, 0));
radeon_ring_write(rdev, 0);
/* Flush 3D cache */
- radeon_ring_write(rdev, PACKET0(0x4E4C, 0));
- radeon_ring_write(rdev, (2 << 0));
- radeon_ring_write(rdev, PACKET0(0x4F18, 0));
- radeon_ring_write(rdev, (1 << 0));
+ radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
+ radeon_ring_write(rdev, R300_RB3D_DC_FLUSH);
+ radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0));
+ radeon_ring_write(rdev, R300_ZC_FLUSH);
/* Wait until IDLE & CLEAN */
- radeon_ring_write(rdev, PACKET0(0x1720, 0));
- radeon_ring_write(rdev, (1 << 17) | (1 << 16) | (1 << 9));
+ radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
+ radeon_ring_write(rdev, (RADEON_WAIT_3D_IDLECLEAN |
+ RADEON_WAIT_2D_IDLECLEAN |
+ RADEON_WAIT_DMA_GUI_IDLE));
radeon_ring_write(rdev, PACKET0(RADEON_HOST_PATH_CNTL, 0));
radeon_ring_write(rdev, rdev->config.r300.hdp_cntl |
RADEON_HDP_READ_BUFFER_INVALIDATE);
@@ -198,50 +201,6 @@ void r300_fence_ring_emit(struct radeon_device *rdev,
radeon_ring_write(rdev, RADEON_SW_INT_FIRE);
}
-int r300_copy_dma(struct radeon_device *rdev,
- uint64_t src_offset,
- uint64_t dst_offset,
- unsigned num_pages,
- struct radeon_fence *fence)
-{
- uint32_t size;
- uint32_t cur_size;
- int i, num_loops;
- int r = 0;
-
- /* radeon pitch is /64 */
- size = num_pages << PAGE_SHIFT;
- num_loops = DIV_ROUND_UP(size, 0x1FFFFF);
- r = radeon_ring_lock(rdev, num_loops * 4 + 64);
- if (r) {
- DRM_ERROR("radeon: moving bo (%d).\n", r);
- return r;
- }
- /* Must wait for 2D idle & clean before DMA or hangs might happen */
- radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0 ));
- radeon_ring_write(rdev, (1 << 16));
- for (i = 0; i < num_loops; i++) {
- cur_size = size;
- if (cur_size > 0x1FFFFF) {
- cur_size = 0x1FFFFF;
- }
- size -= cur_size;
- radeon_ring_write(rdev, PACKET0(0x720, 2));
- radeon_ring_write(rdev, src_offset);
- radeon_ring_write(rdev, dst_offset);
- radeon_ring_write(rdev, cur_size | (1 << 31) | (1 << 30));
- src_offset += cur_size;
- dst_offset += cur_size;
- }
- radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
- radeon_ring_write(rdev, RADEON_WAIT_DMA_GUI_IDLE);
- if (fence) {
- r = radeon_fence_emit(rdev, fence);
- }
- radeon_ring_unlock_commit(rdev);
- return r;
-}
-
void r300_ring_start(struct radeon_device *rdev)
{
unsigned gb_tile_config;
@@ -281,8 +240,8 @@ void r300_ring_start(struct radeon_device *rdev)
radeon_ring_write(rdev,
RADEON_WAIT_2D_IDLECLEAN |
RADEON_WAIT_3D_IDLECLEAN);
- radeon_ring_write(rdev, PACKET0(0x170C, 0));
- radeon_ring_write(rdev, 1 << 31);
+ radeon_ring_write(rdev, PACKET0(R300_DST_PIPE_CONFIG, 0));
+ radeon_ring_write(rdev, R300_PIPE_AUTO_CONFIG);
radeon_ring_write(rdev, PACKET0(R300_GB_SELECT, 0));
radeon_ring_write(rdev, 0);
radeon_ring_write(rdev, PACKET0(R300_GB_ENABLE, 0));
@@ -349,8 +308,8 @@ int r300_mc_wait_for_idle(struct radeon_device *rdev)
for (i = 0; i < rdev->usec_timeout; i++) {
/* read MC_STATUS */
- tmp = RREG32(0x0150);
- if (tmp & (1 << 4)) {
+ tmp = RREG32(RADEON_MC_STATUS);
+ if (tmp & R300_MC_IDLE) {
return 0;
}
DRM_UDELAY(1);
@@ -395,8 +354,8 @@ void r300_gpu_init(struct radeon_device *rdev)
"programming pipes. Bad things might happen.\n");
}
- tmp = RREG32(0x170C);
- WREG32(0x170C, tmp | (1 << 31));
+ tmp = RREG32(R300_DST_PIPE_CONFIG);
+ WREG32(R300_DST_PIPE_CONFIG, tmp | R300_PIPE_AUTO_CONFIG);
WREG32(R300_RB2D_DSTCACHE_MODE,
R300_DC_AUTOFLUSH_ENABLE |
@@ -437,8 +396,8 @@ int r300_ga_reset(struct radeon_device *rdev)
/* GA still busy soft reset it */
WREG32(0x429C, 0x200);
WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0);
- WREG32(0x43E0, 0);
- WREG32(0x43E4, 0);
+ WREG32(R300_RE_SCISSORS_TL, 0);
+ WREG32(R300_RE_SCISSORS_BR, 0);
WREG32(0x24AC, 0);
}
/* Wait to prevent race in RBBM_STATUS */
@@ -488,7 +447,7 @@ int r300_gpu_reset(struct radeon_device *rdev)
}
/* Check if GPU is idle */
status = RREG32(RADEON_RBBM_STATUS);
- if (status & (1 << 31)) {
+ if (status & RADEON_RBBM_ACTIVE) {
DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
return -1;
}
@@ -500,20 +459,28 @@ int r300_gpu_reset(struct radeon_device *rdev)
/*
* r300,r350,rv350,rv380 VRAM info
*/
-void r300_vram_info(struct radeon_device *rdev)
+void r300_mc_init(struct radeon_device *rdev)
{
- uint32_t tmp;
+ u64 base;
+ u32 tmp;
/* DDR for all card after R300 & IGP */
rdev->mc.vram_is_ddr = true;
tmp = RREG32(RADEON_MEM_CNTL);
- if (tmp & R300_MEM_NUM_CHANNELS_MASK) {
- rdev->mc.vram_width = 128;
- } else {
- rdev->mc.vram_width = 64;
+ tmp &= R300_MEM_NUM_CHANNELS_MASK;
+ switch (tmp) {
+ case 0: rdev->mc.vram_width = 64; break;
+ case 1: rdev->mc.vram_width = 128; break;
+ case 2: rdev->mc.vram_width = 256; break;
+ default: rdev->mc.vram_width = 128; break;
}
-
r100_vram_init_sizes(rdev);
+ base = rdev->mc.aper_base;
+ if (rdev->flags & RADEON_IS_IGP)
+ base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16;
+ radeon_vram_location(rdev, &rdev->mc, base);
+ if (!(rdev->flags & RADEON_IS_AGP))
+ radeon_gtt_location(rdev, &rdev->mc);
}
void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes)
@@ -575,6 +542,40 @@ void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes)
}
+int rv370_get_pcie_lanes(struct radeon_device *rdev)
+{
+ u32 link_width_cntl;
+
+ if (rdev->flags & RADEON_IS_IGP)
+ return 0;
+
+ if (!(rdev->flags & RADEON_IS_PCIE))
+ return 0;
+
+ /* FIXME wait for idle */
+
+ if (rdev->family < CHIP_R600)
+ link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+ else
+ link_width_cntl = RREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+
+ switch ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) >> RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT) {
+ case RADEON_PCIE_LC_LINK_WIDTH_X0:
+ return 0;
+ case RADEON_PCIE_LC_LINK_WIDTH_X1:
+ return 1;
+ case RADEON_PCIE_LC_LINK_WIDTH_X2:
+ return 2;
+ case RADEON_PCIE_LC_LINK_WIDTH_X4:
+ return 4;
+ case RADEON_PCIE_LC_LINK_WIDTH_X8:
+ return 8;
+ case RADEON_PCIE_LC_LINK_WIDTH_X16:
+ default:
+ return 16;
+ }
+}
+
#if defined(CONFIG_DEBUG_FS)
static int rv370_debugfs_pcie_gart_info(struct seq_file *m, void *data)
{
@@ -704,6 +705,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
tile_flags |= R300_TXO_MACRO_TILE;
if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
tile_flags |= R300_TXO_MICRO_TILE;
+ else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE)
+ tile_flags |= R300_TXO_MICRO_TILE_SQUARE;
tmp = idx_value + ((u32)reloc->lobj.gpu_offset);
tmp |= tile_flags;
@@ -754,6 +757,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
tile_flags |= R300_COLOR_TILE_ENABLE;
if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
tile_flags |= R300_COLOR_MICROTILE_ENABLE;
+ else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE)
+ tile_flags |= R300_COLOR_MICROTILE_SQUARE_ENABLE;
tmp = idx_value & ~(0x7 << 16);
tmp |= tile_flags;
@@ -825,7 +830,9 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
tile_flags |= R300_DEPTHMACROTILE_ENABLE;
if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
- tile_flags |= R300_DEPTHMICROTILE_TILED;;
+ tile_flags |= R300_DEPTHMICROTILE_TILED;
+ else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE)
+ tile_flags |= R300_DEPTHMICROTILE_TILED_SQUARE;
tmp = idx_value & ~(0x7 << 16);
tmp |= tile_flags;
@@ -1327,7 +1334,6 @@ int r300_suspend(struct radeon_device *rdev)
void r300_fini(struct radeon_device *rdev)
{
- r300_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -1385,12 +1391,15 @@ int r300_init(struct radeon_device *rdev)
radeon_get_clock_info(rdev->ddev);
/* Initialize power management */
radeon_pm_init(rdev);
- /* Get vram informations */
- r300_vram_info(rdev);
- /* Initialize memory controller (also test AGP) */
- r = r420_mc_init(rdev);
- if (r)
- return r;
+ /* initialize AGP */
+ if (rdev->flags & RADEON_IS_AGP) {
+ r = radeon_agp_init(rdev);
+ if (r) {
+ radeon_agp_disable(rdev);
+ }
+ }
+ /* initialize memory controller */
+ r300_mc_init(rdev);
/* Fence driver */
r = radeon_fence_driver_init(rdev);
if (r)
@@ -1418,15 +1427,15 @@ int r300_init(struct radeon_device *rdev)
if (r) {
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
- r300_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
+ radeon_irq_kms_fini(rdev);
if (rdev->flags & RADEON_IS_PCIE)
rv370_pcie_gart_fini(rdev);
if (rdev->flags & RADEON_IS_PCI)
r100_pci_gart_fini(rdev);
- radeon_irq_kms_fini(rdev);
+ radeon_agp_fini(rdev);
rdev->accel_working = false;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/r300_cmdbuf.c b/drivers/gpu/drm/radeon/r300_cmdbuf.c
index 34bffa0e4b73..ea46d558e8f3 100644
--- a/drivers/gpu/drm/radeon/r300_cmdbuf.c
+++ b/drivers/gpu/drm/radeon/r300_cmdbuf.c
@@ -33,6 +33,7 @@
#include "drmP.h"
#include "drm.h"
+#include "drm_buffer.h"
#include "radeon_drm.h"
#include "radeon_drv.h"
#include "r300_reg.h"
@@ -299,46 +300,42 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
int reg;
int sz;
int i;
- int values[64];
+ u32 *value;
RING_LOCALS;
sz = header.packet0.count;
reg = (header.packet0.reghi << 8) | header.packet0.reglo;
if ((sz > 64) || (sz < 0)) {
- DRM_ERROR
- ("Cannot emit more than 64 values at a time (reg=%04x sz=%d)\n",
- reg, sz);
+ DRM_ERROR("Cannot emit more than 64 values at a time (reg=%04x sz=%d)\n",
+ reg, sz);
return -EINVAL;
}
+
for (i = 0; i < sz; i++) {
- values[i] = ((int *)cmdbuf->buf)[i];
switch (r300_reg_flags[(reg >> 2) + i]) {
case MARK_SAFE:
break;
case MARK_CHECK_OFFSET:
- if (!radeon_check_offset(dev_priv, (u32) values[i])) {
- DRM_ERROR
- ("Offset failed range check (reg=%04x sz=%d)\n",
- reg, sz);
+ value = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
+ if (!radeon_check_offset(dev_priv, *value)) {
+ DRM_ERROR("Offset failed range check (reg=%04x sz=%d)\n",
+ reg, sz);
return -EINVAL;
}
break;
default:
DRM_ERROR("Register %04x failed check as flag=%02x\n",
- reg + i * 4, r300_reg_flags[(reg >> 2) + i]);
+ reg + i * 4, r300_reg_flags[(reg >> 2) + i]);
return -EINVAL;
}
}
BEGIN_RING(1 + sz);
OUT_RING(CP_PACKET0(reg, sz - 1));
- OUT_RING_TABLE(values, sz);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
ADVANCE_RING();
- cmdbuf->buf += sz * 4;
- cmdbuf->bufsz -= sz * 4;
-
return 0;
}
@@ -362,7 +359,7 @@ static __inline__ int r300_emit_packet0(drm_radeon_private_t *dev_priv,
if (!sz)
return 0;
- if (sz * 4 > cmdbuf->bufsz)
+ if (sz * 4 > drm_buffer_unprocessed(cmdbuf->buffer))
return -EINVAL;
if (reg + sz * 4 >= 0x10000) {
@@ -380,12 +377,9 @@ static __inline__ int r300_emit_packet0(drm_radeon_private_t *dev_priv,
BEGIN_RING(1 + sz);
OUT_RING(CP_PACKET0(reg, sz - 1));
- OUT_RING_TABLE((int *)cmdbuf->buf, sz);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
ADVANCE_RING();
- cmdbuf->buf += sz * 4;
- cmdbuf->bufsz -= sz * 4;
-
return 0;
}
@@ -407,7 +401,7 @@ static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv,
if (!sz)
return 0;
- if (sz * 16 > cmdbuf->bufsz)
+ if (sz * 16 > drm_buffer_unprocessed(cmdbuf->buffer))
return -EINVAL;
/* VAP is very sensitive so we purge cache before we program it
@@ -426,7 +420,7 @@ static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv,
BEGIN_RING(3 + sz * 4);
OUT_RING_REG(R300_VAP_PVS_UPLOAD_ADDRESS, addr);
OUT_RING(CP_PACKET0_TABLE(R300_VAP_PVS_UPLOAD_DATA, sz * 4 - 1));
- OUT_RING_TABLE((int *)cmdbuf->buf, sz * 4);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz * 4);
ADVANCE_RING();
BEGIN_RING(2);
@@ -434,9 +428,6 @@ static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv,
OUT_RING(0);
ADVANCE_RING();
- cmdbuf->buf += sz * 16;
- cmdbuf->bufsz -= sz * 16;
-
return 0;
}
@@ -449,14 +440,14 @@ static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv,
{
RING_LOCALS;
- if (8 * 4 > cmdbuf->bufsz)
+ if (8 * 4 > drm_buffer_unprocessed(cmdbuf->buffer))
return -EINVAL;
BEGIN_RING(10);
OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 8));
OUT_RING(R300_PRIM_TYPE_POINT | R300_PRIM_WALK_RING |
(1 << R300_PRIM_NUM_VERTICES_SHIFT));
- OUT_RING_TABLE((int *)cmdbuf->buf, 8);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, 8);
ADVANCE_RING();
BEGIN_RING(4);
@@ -468,9 +459,6 @@ static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv,
/* set flush flag */
dev_priv->track_flush |= RADEON_FLUSH_EMITED;
- cmdbuf->buf += 8 * 4;
- cmdbuf->bufsz -= 8 * 4;
-
return 0;
}
@@ -480,28 +468,29 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
{
int count, i, k;
#define MAX_ARRAY_PACKET 64
- u32 payload[MAX_ARRAY_PACKET];
+ u32 *data;
u32 narrays;
RING_LOCALS;
- count = (header >> 16) & 0x3fff;
+ count = (header & RADEON_CP_PACKET_COUNT_MASK) >> 16;
if ((count + 1) > MAX_ARRAY_PACKET) {
DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
count);
return -EINVAL;
}
- memset(payload, 0, MAX_ARRAY_PACKET * 4);
- memcpy(payload, cmdbuf->buf + 4, (count + 1) * 4);
-
/* carefully check packet contents */
- narrays = payload[0];
+ /* We have already read the header so advance the buffer. */
+ drm_buffer_advance(cmdbuf->buffer, 4);
+
+ narrays = *(u32 *)drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
k = 0;
i = 1;
while ((k < narrays) && (i < (count + 1))) {
i++; /* skip attribute field */
- if (!radeon_check_offset(dev_priv, payload[i])) {
+ data = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
+ if (!radeon_check_offset(dev_priv, *data)) {
DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
@@ -512,7 +501,8 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
if (k == narrays)
break;
/* have one more to process, they come in pairs */
- if (!radeon_check_offset(dev_priv, payload[i])) {
+ data = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
+ if (!radeon_check_offset(dev_priv, *data)) {
DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
@@ -533,30 +523,30 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
BEGIN_RING(count + 2);
OUT_RING(header);
- OUT_RING_TABLE(payload, count + 1);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, count + 1);
ADVANCE_RING();
- cmdbuf->buf += (count + 2) * 4;
- cmdbuf->bufsz -= (count + 2) * 4;
-
return 0;
}
static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
- u32 *cmd = (u32 *) cmdbuf->buf;
+ u32 *cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
int count, ret;
RING_LOCALS;
- count=(cmd[0]>>16) & 0x3fff;
- if (cmd[0] & 0x8000) {
- u32 offset;
+ count = (*cmd & RADEON_CP_PACKET_COUNT_MASK) >> 16;
- if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
+ if (*cmd & 0x8000) {
+ u32 offset;
+ u32 *cmd1 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
+ if (*cmd1 & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
| RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
- offset = cmd[2] << 10;
+
+ u32 *cmd2 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2);
+ offset = *cmd2 << 10;
ret = !radeon_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt first offset is %08X\n", offset);
@@ -564,9 +554,10 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
}
}
- if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
- (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
- offset = cmd[3] << 10;
+ if ((*cmd1 & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
+ (*cmd1 & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
+ u32 *cmd3 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 3);
+ offset = *cmd3 << 10;
ret = !radeon_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt second offset is %08X\n", offset);
@@ -577,28 +568,25 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
}
BEGIN_RING(count+2);
- OUT_RING(cmd[0]);
- OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, count + 2);
ADVANCE_RING();
- cmdbuf->buf += (count+2)*4;
- cmdbuf->bufsz -= (count+2)*4;
-
return 0;
}
static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
- u32 *cmd;
+ u32 *cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
+ u32 *cmd1 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
int count;
int expected_count;
RING_LOCALS;
- cmd = (u32 *) cmdbuf->buf;
- count = (cmd[0]>>16) & 0x3fff;
- expected_count = cmd[1] >> 16;
- if (!(cmd[1] & R300_VAP_VF_CNTL__INDEX_SIZE_32bit))
+ count = (*cmd & RADEON_CP_PACKET_COUNT_MASK) >> 16;
+
+ expected_count = *cmd1 >> 16;
+ if (!(*cmd1 & R300_VAP_VF_CNTL__INDEX_SIZE_32bit))
expected_count = (expected_count+1)/2;
if (count && count != expected_count) {
@@ -608,55 +596,53 @@ static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv,
}
BEGIN_RING(count+2);
- OUT_RING(cmd[0]);
- OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, count + 2);
ADVANCE_RING();
- cmdbuf->buf += (count+2)*4;
- cmdbuf->bufsz -= (count+2)*4;
-
if (!count) {
- drm_r300_cmd_header_t header;
+ drm_r300_cmd_header_t stack_header, *header;
+ u32 *cmd1, *cmd2, *cmd3;
- if (cmdbuf->bufsz < 4*4 + sizeof(header)) {
+ if (drm_buffer_unprocessed(cmdbuf->buffer)
+ < 4*4 + sizeof(stack_header)) {
DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER, but stream is too short.\n");
return -EINVAL;
}
- header.u = *(unsigned int *)cmdbuf->buf;
+ header = drm_buffer_read_object(cmdbuf->buffer,
+ sizeof(stack_header), &stack_header);
- cmdbuf->buf += sizeof(header);
- cmdbuf->bufsz -= sizeof(header);
- cmd = (u32 *) cmdbuf->buf;
+ cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
+ cmd1 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
+ cmd2 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2);
+ cmd3 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 3);
- if (header.header.cmd_type != R300_CMD_PACKET3 ||
- header.packet3.packet != R300_CMD_PACKET3_RAW ||
- cmd[0] != CP_PACKET3(RADEON_CP_INDX_BUFFER, 2)) {
+ if (header->header.cmd_type != R300_CMD_PACKET3 ||
+ header->packet3.packet != R300_CMD_PACKET3_RAW ||
+ *cmd != CP_PACKET3(RADEON_CP_INDX_BUFFER, 2)) {
DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER.\n");
return -EINVAL;
}
- if ((cmd[1] & 0x8000ffff) != 0x80000810) {
- DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
+ if ((*cmd1 & 0x8000ffff) != 0x80000810) {
+ DRM_ERROR("Invalid indx_buffer reg address %08X\n",
+ *cmd1);
return -EINVAL;
}
- if (!radeon_check_offset(dev_priv, cmd[2])) {
- DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
+ if (!radeon_check_offset(dev_priv, *cmd2)) {
+ DRM_ERROR("Invalid indx_buffer offset is %08X\n",
+ *cmd2);
return -EINVAL;
}
- if (cmd[3] != expected_count) {
+ if (*cmd3 != expected_count) {
DRM_ERROR("INDX_BUFFER: buffer size %i, expected %i\n",
- cmd[3], expected_count);
+ *cmd3, expected_count);
return -EINVAL;
}
BEGIN_RING(4);
- OUT_RING(cmd[0]);
- OUT_RING_TABLE((int *)(cmdbuf->buf + 4), 3);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, 4);
ADVANCE_RING();
-
- cmdbuf->buf += 4*4;
- cmdbuf->bufsz -= 4*4;
}
return 0;
@@ -665,39 +651,39 @@ static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv,
static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
- u32 header;
+ u32 *header;
int count;
RING_LOCALS;
- if (4 > cmdbuf->bufsz)
+ if (4 > drm_buffer_unprocessed(cmdbuf->buffer))
return -EINVAL;
/* Fixme !! This simply emits a packet without much checking.
We need to be smarter. */
/* obtain first word - actual packet3 header */
- header = *(u32 *) cmdbuf->buf;
+ header = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
/* Is it packet 3 ? */
- if ((header >> 30) != 0x3) {
- DRM_ERROR("Not a packet3 header (0x%08x)\n", header);
+ if ((*header >> 30) != 0x3) {
+ DRM_ERROR("Not a packet3 header (0x%08x)\n", *header);
return -EINVAL;
}
- count = (header >> 16) & 0x3fff;
+ count = (*header >> 16) & 0x3fff;
/* Check again now that we know how much data to expect */
- if ((count + 2) * 4 > cmdbuf->bufsz) {
+ if ((count + 2) * 4 > drm_buffer_unprocessed(cmdbuf->buffer)) {
DRM_ERROR
("Expected packet3 of length %d but have only %d bytes left\n",
- (count + 2) * 4, cmdbuf->bufsz);
+ (count + 2) * 4, drm_buffer_unprocessed(cmdbuf->buffer));
return -EINVAL;
}
/* Is it a packet type we know about ? */
- switch (header & 0xff00) {
+ switch (*header & 0xff00) {
case RADEON_3D_LOAD_VBPNTR: /* load vertex array pointers */
- return r300_emit_3d_load_vbpntr(dev_priv, cmdbuf, header);
+ return r300_emit_3d_load_vbpntr(dev_priv, cmdbuf, *header);
case RADEON_CNTL_BITBLT_MULTI:
return r300_emit_bitblt_multi(dev_priv, cmdbuf);
@@ -723,18 +709,14 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
/* these packets are safe */
break;
default:
- DRM_ERROR("Unknown packet3 header (0x%08x)\n", header);
+ DRM_ERROR("Unknown packet3 header (0x%08x)\n", *header);
return -EINVAL;
}
BEGIN_RING(count + 2);
- OUT_RING(header);
- OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, count + 2);
ADVANCE_RING();
- cmdbuf->buf += (count + 2) * 4;
- cmdbuf->bufsz -= (count + 2) * 4;
-
return 0;
}
@@ -748,8 +730,7 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv,
{
int n;
int ret;
- char *orig_buf = cmdbuf->buf;
- int orig_bufsz = cmdbuf->bufsz;
+ int orig_iter = cmdbuf->buffer->iterator;
/* This is a do-while-loop so that we run the interior at least once,
* even if cmdbuf->nbox is 0. Compare r300_emit_cliprects for rationale.
@@ -761,8 +742,7 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv,
if (ret)
return ret;
- cmdbuf->buf = orig_buf;
- cmdbuf->bufsz = orig_bufsz;
+ cmdbuf->buffer->iterator = orig_iter;
}
switch (header.packet3.packet) {
@@ -785,9 +765,9 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv,
break;
default:
- DRM_ERROR("bad packet3 type %i at %p\n",
+ DRM_ERROR("bad packet3 type %i at byte %d\n",
header.packet3.packet,
- cmdbuf->buf - sizeof(header));
+ cmdbuf->buffer->iterator - (int)sizeof(header));
return -EINVAL;
}
@@ -923,12 +903,13 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
drm_r300_cmd_header_t header)
{
u32 *ref_age_base;
- u32 i, buf_idx, h_pending;
- u64 ptr_addr;
+ u32 i, *buf_idx, h_pending;
+ u64 *ptr_addr;
+ u64 stack_ptr_addr;
RING_LOCALS;
- if (cmdbuf->bufsz <
- (sizeof(u64) + header.scratch.n_bufs * sizeof(buf_idx))) {
+ if (drm_buffer_unprocessed(cmdbuf->buffer) <
+ (sizeof(u64) + header.scratch.n_bufs * sizeof(*buf_idx))) {
return -EINVAL;
}
@@ -938,36 +919,35 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
dev_priv->scratch_ages[header.scratch.reg]++;
- ptr_addr = get_unaligned((u64 *)cmdbuf->buf);
- ref_age_base = (u32 *)(unsigned long)ptr_addr;
-
- cmdbuf->buf += sizeof(u64);
- cmdbuf->bufsz -= sizeof(u64);
+ ptr_addr = drm_buffer_read_object(cmdbuf->buffer,
+ sizeof(stack_ptr_addr), &stack_ptr_addr);
+ ref_age_base = (u32 *)(unsigned long)*ptr_addr;
for (i=0; i < header.scratch.n_bufs; i++) {
- buf_idx = *(u32 *)cmdbuf->buf;
- buf_idx *= 2; /* 8 bytes per buf */
+ buf_idx = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
+ *buf_idx *= 2; /* 8 bytes per buf */
- if (DRM_COPY_TO_USER(ref_age_base + buf_idx, &dev_priv->scratch_ages[header.scratch.reg], sizeof(u32))) {
+ if (DRM_COPY_TO_USER(ref_age_base + *buf_idx,
+ &dev_priv->scratch_ages[header.scratch.reg],
+ sizeof(u32)))
return -EINVAL;
- }
- if (DRM_COPY_FROM_USER(&h_pending, ref_age_base + buf_idx + 1, sizeof(u32))) {
+ if (DRM_COPY_FROM_USER(&h_pending,
+ ref_age_base + *buf_idx + 1,
+ sizeof(u32)))
return -EINVAL;
- }
- if (h_pending == 0) {
+ if (h_pending == 0)
return -EINVAL;
- }
h_pending--;
- if (DRM_COPY_TO_USER(ref_age_base + buf_idx + 1, &h_pending, sizeof(u32))) {
+ if (DRM_COPY_TO_USER(ref_age_base + *buf_idx + 1,
+ &h_pending,
+ sizeof(u32)))
return -EINVAL;
- }
- cmdbuf->buf += sizeof(buf_idx);
- cmdbuf->bufsz -= sizeof(buf_idx);
+ drm_buffer_advance(cmdbuf->buffer, sizeof(*buf_idx));
}
BEGIN_RING(2);
@@ -1009,19 +989,16 @@ static inline int r300_emit_r500fp(drm_radeon_private_t *dev_priv,
DRM_DEBUG("r500fp %d %d type: %d\n", sz, addr, type);
if (!sz)
return 0;
- if (sz * stride * 4 > cmdbuf->bufsz)
+ if (sz * stride * 4 > drm_buffer_unprocessed(cmdbuf->buffer))
return -EINVAL;
BEGIN_RING(3 + sz * stride);
OUT_RING_REG(R500_GA_US_VECTOR_INDEX, addr);
OUT_RING(CP_PACKET0_TABLE(R500_GA_US_VECTOR_DATA, sz * stride - 1));
- OUT_RING_TABLE((int *)cmdbuf->buf, sz * stride);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz * stride);
ADVANCE_RING();
- cmdbuf->buf += sz * stride * 4;
- cmdbuf->bufsz -= sz * stride * 4;
-
return 0;
}
@@ -1053,19 +1030,18 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
goto cleanup;
}
- while (cmdbuf->bufsz >= sizeof(drm_r300_cmd_header_t)) {
+ while (drm_buffer_unprocessed(cmdbuf->buffer)
+ >= sizeof(drm_r300_cmd_header_t)) {
int idx;
- drm_r300_cmd_header_t header;
-
- header.u = *(unsigned int *)cmdbuf->buf;
+ drm_r300_cmd_header_t *header, stack_header;
- cmdbuf->buf += sizeof(header);
- cmdbuf->bufsz -= sizeof(header);
+ header = drm_buffer_read_object(cmdbuf->buffer,
+ sizeof(stack_header), &stack_header);
- switch (header.header.cmd_type) {
+ switch (header->header.cmd_type) {
case R300_CMD_PACKET0:
DRM_DEBUG("R300_CMD_PACKET0\n");
- ret = r300_emit_packet0(dev_priv, cmdbuf, header);
+ ret = r300_emit_packet0(dev_priv, cmdbuf, *header);
if (ret) {
DRM_ERROR("r300_emit_packet0 failed\n");
goto cleanup;
@@ -1074,7 +1050,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
case R300_CMD_VPU:
DRM_DEBUG("R300_CMD_VPU\n");
- ret = r300_emit_vpu(dev_priv, cmdbuf, header);
+ ret = r300_emit_vpu(dev_priv, cmdbuf, *header);
if (ret) {
DRM_ERROR("r300_emit_vpu failed\n");
goto cleanup;
@@ -1083,7 +1059,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
case R300_CMD_PACKET3:
DRM_DEBUG("R300_CMD_PACKET3\n");
- ret = r300_emit_packet3(dev_priv, cmdbuf, header);
+ ret = r300_emit_packet3(dev_priv, cmdbuf, *header);
if (ret) {
DRM_ERROR("r300_emit_packet3 failed\n");
goto cleanup;
@@ -1117,8 +1093,8 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
int i;
RING_LOCALS;
- BEGIN_RING(header.delay.count);
- for (i = 0; i < header.delay.count; i++)
+ BEGIN_RING(header->delay.count);
+ for (i = 0; i < header->delay.count; i++)
OUT_RING(RADEON_CP_PACKET2);
ADVANCE_RING();
}
@@ -1126,7 +1102,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
case R300_CMD_DMA_DISCARD:
DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
- idx = header.dma.buf_idx;
+ idx = header->dma.buf_idx;
if (idx < 0 || idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
idx, dma->buf_count - 1);
@@ -1149,12 +1125,12 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
case R300_CMD_WAIT:
DRM_DEBUG("R300_CMD_WAIT\n");
- r300_cmd_wait(dev_priv, header);
+ r300_cmd_wait(dev_priv, *header);
break;
case R300_CMD_SCRATCH:
DRM_DEBUG("R300_CMD_SCRATCH\n");
- ret = r300_scratch(dev_priv, cmdbuf, header);
+ ret = r300_scratch(dev_priv, cmdbuf, *header);
if (ret) {
DRM_ERROR("r300_scratch failed\n");
goto cleanup;
@@ -1168,16 +1144,16 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
goto cleanup;
}
DRM_DEBUG("R300_CMD_R500FP\n");
- ret = r300_emit_r500fp(dev_priv, cmdbuf, header);
+ ret = r300_emit_r500fp(dev_priv, cmdbuf, *header);
if (ret) {
DRM_ERROR("r300_emit_r500fp failed\n");
goto cleanup;
}
break;
default:
- DRM_ERROR("bad cmd_type %i at %p\n",
- header.header.cmd_type,
- cmdbuf->buf - sizeof(header));
+ DRM_ERROR("bad cmd_type %i at byte %d\n",
+ header->header.cmd_type,
+ cmdbuf->buffer->iterator - (int)sizeof(*header));
ret = -EINVAL;
goto cleanup;
}
diff --git a/drivers/gpu/drm/radeon/r300_reg.h b/drivers/gpu/drm/radeon/r300_reg.h
index 1735a2b69580..1a0d5362cd79 100644
--- a/drivers/gpu/drm/radeon/r300_reg.h
+++ b/drivers/gpu/drm/radeon/r300_reg.h
@@ -952,6 +952,7 @@
# define R300_TXO_ENDIAN_HALFDW_SWAP (3 << 0)
# define R300_TXO_MACRO_TILE (1 << 2)
# define R300_TXO_MICRO_TILE (1 << 3)
+# define R300_TXO_MICRO_TILE_SQUARE (2 << 3)
# define R300_TXO_OFFSET_MASK 0xffffffe0
# define R300_TXO_OFFSET_SHIFT 5
/* END: Guess from R200 */
@@ -1360,6 +1361,7 @@
# define R300_COLORPITCH_MASK 0x00001FF8 /* GUESS */
# define R300_COLOR_TILE_ENABLE (1 << 16) /* GUESS */
# define R300_COLOR_MICROTILE_ENABLE (1 << 17) /* GUESS */
+# define R300_COLOR_MICROTILE_SQUARE_ENABLE (2 << 17)
# define R300_COLOR_ENDIAN_NO_SWAP (0 << 18) /* GUESS */
# define R300_COLOR_ENDIAN_WORD_SWAP (1 << 18) /* GUESS */
# define R300_COLOR_ENDIAN_DWORD_SWAP (2 << 18) /* GUESS */
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index 053404e71a9d..c7593b8f58ee 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -40,30 +40,6 @@ static void r420_set_reg_safe(struct radeon_device *rdev)
rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r420_reg_safe_bm);
}
-int r420_mc_init(struct radeon_device *rdev)
-{
- int r;
-
- /* Setup GPU memory space */
- rdev->mc.vram_location = 0xFFFFFFFFUL;
- rdev->mc.gtt_location = 0xFFFFFFFFUL;
- if (rdev->flags & RADEON_IS_AGP) {
- r = radeon_agp_init(rdev);
- if (r) {
- printk(KERN_WARNING "[drm] Disabling AGP\n");
- rdev->flags &= ~RADEON_IS_AGP;
- rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
- } else {
- rdev->mc.gtt_location = rdev->mc.agp_base;
- }
- }
- r = radeon_mc_setup(rdev);
- if (r) {
- return r;
- }
- return 0;
-}
-
void r420_pipes_init(struct radeon_device *rdev)
{
unsigned tmp;
@@ -71,7 +47,8 @@ void r420_pipes_init(struct radeon_device *rdev)
unsigned num_pipes;
/* GA_ENHANCE workaround TCL deadlock issue */
- WREG32(0x4274, (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3));
+ WREG32(R300_GA_ENHANCE, R300_GA_DEADLOCK_CNTL | R300_GA_FASTSYNC_CNTL |
+ (1 << 2) | (1 << 3));
/* add idle wait as per freedesktop.org bug 24041 */
if (r100_gui_wait_for_idle(rdev)) {
printk(KERN_WARNING "Failed to wait GUI idle while "
@@ -99,17 +76,17 @@ void r420_pipes_init(struct radeon_device *rdev)
tmp = (7 << 1);
break;
}
- WREG32(0x42C8, (1 << num_pipes) - 1);
+ WREG32(R500_SU_REG_DEST, (1 << num_pipes) - 1);
/* Sub pixel 1/12 so we can have 4K rendering according to doc */
- tmp |= (1 << 4) | (1 << 0);
- WREG32(0x4018, tmp);
+ tmp |= R300_TILE_SIZE_16 | R300_ENABLE_TILING;
+ WREG32(R300_GB_TILE_CONFIG, tmp);
if (r100_gui_wait_for_idle(rdev)) {
printk(KERN_WARNING "Failed to wait GUI idle while "
"programming pipes. Bad things might happen.\n");
}
- tmp = RREG32(0x170C);
- WREG32(0x170C, tmp | (1 << 31));
+ tmp = RREG32(R300_DST_PIPE_CONFIG);
+ WREG32(R300_DST_PIPE_CONFIG, tmp | R300_PIPE_AUTO_CONFIG);
WREG32(R300_RB2D_DSTCACHE_MODE,
RREG32(R300_RB2D_DSTCACHE_MODE) |
@@ -350,13 +327,15 @@ int r420_init(struct radeon_device *rdev)
radeon_get_clock_info(rdev->ddev);
/* Initialize power management */
radeon_pm_init(rdev);
- /* Get vram informations */
- r300_vram_info(rdev);
- /* Initialize memory controller (also test AGP) */
- r = r420_mc_init(rdev);
- if (r) {
- return r;
+ /* initialize AGP */
+ if (rdev->flags & RADEON_IS_AGP) {
+ r = radeon_agp_init(rdev);
+ if (r) {
+ radeon_agp_disable(rdev);
+ }
}
+ /* initialize memory controller */
+ r300_mc_init(rdev);
r420_debugfs(rdev);
/* Fence driver */
r = radeon_fence_driver_init(rdev);
@@ -391,16 +370,15 @@ int r420_init(struct radeon_device *rdev)
if (r) {
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
- r420_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
+ radeon_irq_kms_fini(rdev);
if (rdev->flags & RADEON_IS_PCIE)
rv370_pcie_gart_fini(rdev);
if (rdev->flags & RADEON_IS_PCI)
r100_pci_gart_fini(rdev);
radeon_agp_fini(rdev);
- radeon_irq_kms_fini(rdev);
rdev->accel_working = false;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h
index 74ad89bdf2b5..0cf2ad2a5585 100644
--- a/drivers/gpu/drm/radeon/r500_reg.h
+++ b/drivers/gpu/drm/radeon/r500_reg.h
@@ -717,54 +717,62 @@
#define AVIVO_DVOA_BIT_DEPTH_CONTROL 0x7988
#define AVIVO_DC_GPIO_HPD_A 0x7e94
-
-#define AVIVO_GPIO_0 0x7e30
-#define AVIVO_GPIO_1 0x7e40
-#define AVIVO_GPIO_2 0x7e50
-#define AVIVO_GPIO_3 0x7e60
-
#define AVIVO_DC_GPIO_HPD_Y 0x7e9c
-#define AVIVO_I2C_STATUS 0x7d30
-# define AVIVO_I2C_STATUS_DONE (1 << 0)
-# define AVIVO_I2C_STATUS_NACK (1 << 1)
-# define AVIVO_I2C_STATUS_HALT (1 << 2)
-# define AVIVO_I2C_STATUS_GO (1 << 3)
-# define AVIVO_I2C_STATUS_MASK 0x7
-/* If radeon_mm_i2c is to be believed, this is HALT, NACK, and maybe
- * DONE? */
-# define AVIVO_I2C_STATUS_CMD_RESET 0x7
-# define AVIVO_I2C_STATUS_CMD_WAIT (1 << 3)
-#define AVIVO_I2C_STOP 0x7d34
-#define AVIVO_I2C_START_CNTL 0x7d38
-# define AVIVO_I2C_START (1 << 8)
-# define AVIVO_I2C_CONNECTOR0 (0 << 16)
-# define AVIVO_I2C_CONNECTOR1 (1 << 16)
-#define R520_I2C_START (1<<0)
-#define R520_I2C_STOP (1<<1)
-#define R520_I2C_RX (1<<2)
-#define R520_I2C_EN (1<<8)
-#define R520_I2C_DDC1 (0<<16)
-#define R520_I2C_DDC2 (1<<16)
-#define R520_I2C_DDC3 (2<<16)
-#define R520_I2C_DDC_MASK (3<<16)
-#define AVIVO_I2C_CONTROL2 0x7d3c
-# define AVIVO_I2C_7D3C_SIZE_SHIFT 8
-# define AVIVO_I2C_7D3C_SIZE_MASK (0xf << 8)
-#define AVIVO_I2C_CONTROL3 0x7d40
-/* Reading is done 4 bytes at a time: read the bottom 8 bits from
- * 7d44, four times in a row.
- * Writing is a little more complex. First write DATA with
- * 0xnnnnnnzz, then 0xnnnnnnyy, where nnnnnn is some non-deterministic
- * magic number, zz is, I think, the slave address, and yy is the byte
- * you want to write. */
-#define AVIVO_I2C_DATA 0x7d44
-#define R520_I2C_ADDR_COUNT_MASK (0x7)
-#define R520_I2C_DATA_COUNT_SHIFT (8)
-#define R520_I2C_DATA_COUNT_MASK (0xF00)
-#define AVIVO_I2C_CNTL 0x7d50
-# define AVIVO_I2C_EN (1 << 0)
-# define AVIVO_I2C_RESET (1 << 8)
+#define AVIVO_DC_I2C_STATUS1 0x7d30
+# define AVIVO_DC_I2C_DONE (1 << 0)
+# define AVIVO_DC_I2C_NACK (1 << 1)
+# define AVIVO_DC_I2C_HALT (1 << 2)
+# define AVIVO_DC_I2C_GO (1 << 3)
+#define AVIVO_DC_I2C_RESET 0x7d34
+# define AVIVO_DC_I2C_SOFT_RESET (1 << 0)
+# define AVIVO_DC_I2C_ABORT (1 << 8)
+#define AVIVO_DC_I2C_CONTROL1 0x7d38
+# define AVIVO_DC_I2C_START (1 << 0)
+# define AVIVO_DC_I2C_STOP (1 << 1)
+# define AVIVO_DC_I2C_RECEIVE (1 << 2)
+# define AVIVO_DC_I2C_EN (1 << 8)
+# define AVIVO_DC_I2C_PIN_SELECT(x) ((x) << 16)
+# define AVIVO_SEL_DDC1 0
+# define AVIVO_SEL_DDC2 1
+# define AVIVO_SEL_DDC3 2
+#define AVIVO_DC_I2C_CONTROL2 0x7d3c
+# define AVIVO_DC_I2C_ADDR_COUNT(x) ((x) << 0)
+# define AVIVO_DC_I2C_DATA_COUNT(x) ((x) << 8)
+#define AVIVO_DC_I2C_CONTROL3 0x7d40
+# define AVIVO_DC_I2C_DATA_DRIVE_EN (1 << 0)
+# define AVIVO_DC_I2C_DATA_DRIVE_SEL (1 << 1)
+# define AVIVO_DC_I2C_CLK_DRIVE_EN (1 << 7)
+# define AVIVO_DC_I2C_RD_INTRA_BYTE_DELAY(x) ((x) << 8)
+# define AVIVO_DC_I2C_WR_INTRA_BYTE_DELAY(x) ((x) << 16)
+# define AVIVO_DC_I2C_TIME_LIMIT(x) ((x) << 24)
+#define AVIVO_DC_I2C_DATA 0x7d44
+#define AVIVO_DC_I2C_INTERRUPT_CONTROL 0x7d48
+# define AVIVO_DC_I2C_INTERRUPT_STATUS (1 << 0)
+# define AVIVO_DC_I2C_INTERRUPT_AK (1 << 8)
+# define AVIVO_DC_I2C_INTERRUPT_ENABLE (1 << 16)
+#define AVIVO_DC_I2C_ARBITRATION 0x7d50
+# define AVIVO_DC_I2C_SW_WANTS_TO_USE_I2C (1 << 0)
+# define AVIVO_DC_I2C_SW_CAN_USE_I2C (1 << 1)
+# define AVIVO_DC_I2C_SW_DONE_USING_I2C (1 << 8)
+# define AVIVO_DC_I2C_HW_NEEDS_I2C (1 << 9)
+# define AVIVO_DC_I2C_ABORT_HDCP_I2C (1 << 16)
+# define AVIVO_DC_I2C_HW_USING_I2C (1 << 17)
+
+#define AVIVO_DC_GPIO_DDC1_MASK 0x7e40
+#define AVIVO_DC_GPIO_DDC1_A 0x7e44
+#define AVIVO_DC_GPIO_DDC1_EN 0x7e48
+#define AVIVO_DC_GPIO_DDC1_Y 0x7e4c
+
+#define AVIVO_DC_GPIO_DDC2_MASK 0x7e50
+#define AVIVO_DC_GPIO_DDC2_A 0x7e54
+#define AVIVO_DC_GPIO_DDC2_EN 0x7e58
+#define AVIVO_DC_GPIO_DDC2_Y 0x7e5c
+
+#define AVIVO_DC_GPIO_DDC3_MASK 0x7e60
+#define AVIVO_DC_GPIO_DDC3_A 0x7e64
+#define AVIVO_DC_GPIO_DDC3_EN 0x7e68
+#define AVIVO_DC_GPIO_DDC3_Y 0x7e6c
#define AVIVO_DISP_INTERRUPT_STATUS 0x7edc
# define AVIVO_D1_VBLANK_INTERRUPT (1 << 4)
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index 9a189072f2b9..2b8a5dd13516 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -119,13 +119,15 @@ static void r520_vram_get_type(struct radeon_device *rdev)
rdev->mc.vram_width *= 2;
}
-void r520_vram_info(struct radeon_device *rdev)
+void r520_mc_init(struct radeon_device *rdev)
{
fixed20_12 a;
r520_vram_get_type(rdev);
-
r100_vram_init_sizes(rdev);
+ radeon_vram_location(rdev, &rdev->mc, 0);
+ if (!(rdev->flags & RADEON_IS_AGP))
+ radeon_gtt_location(rdev, &rdev->mc);
/* FIXME: we should enforce default clock in case GPU is not in
* default setup
*/
@@ -267,12 +269,15 @@ int r520_init(struct radeon_device *rdev)
radeon_get_clock_info(rdev->ddev);
/* Initialize power management */
radeon_pm_init(rdev);
- /* Get vram informations */
- r520_vram_info(rdev);
- /* Initialize memory controller (also test AGP) */
- r = r420_mc_init(rdev);
- if (r)
- return r;
+ /* initialize AGP */
+ if (rdev->flags & RADEON_IS_AGP) {
+ r = radeon_agp_init(rdev);
+ if (r) {
+ radeon_agp_disable(rdev);
+ }
+ }
+ /* initialize memory controller */
+ r520_mc_init(rdev);
rv515_debugfs(rdev);
/* Fence driver */
r = radeon_fence_driver_init(rdev);
@@ -294,13 +299,12 @@ int r520_init(struct radeon_device *rdev)
if (r) {
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
- rv515_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
+ radeon_irq_kms_fini(rdev);
rv370_pcie_gart_fini(rdev);
radeon_agp_fini(rdev);
- radeon_irq_kms_fini(rdev);
rdev->accel_working = false;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index f5ff3490929f..c52290197292 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -353,23 +353,14 @@ void r600_hpd_fini(struct radeon_device *rdev)
/*
* R600 PCIE GART
*/
-int r600_gart_clear_page(struct radeon_device *rdev, int i)
-{
- void __iomem *ptr = (void *)rdev->gart.table.vram.ptr;
- u64 pte;
-
- if (i < 0 || i > rdev->gart.num_gpu_pages)
- return -EINVAL;
- pte = 0;
- writeq(pte, ((void __iomem *)ptr) + (i * 8));
- return 0;
-}
-
void r600_pcie_gart_tlb_flush(struct radeon_device *rdev)
{
unsigned i;
u32 tmp;
+ /* flush hdp cache so updates hit vram */
+ WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
+
WREG32(VM_CONTEXT0_INVALIDATION_LOW_ADDR, rdev->mc.gtt_start >> 12);
WREG32(VM_CONTEXT0_INVALIDATION_HIGH_ADDR, (rdev->mc.gtt_end - 1) >> 12);
WREG32(VM_CONTEXT0_REQUEST_RESPONSE, REQUEST_TYPE(1));
@@ -416,6 +407,7 @@ int r600_pcie_gart_enable(struct radeon_device *rdev)
r = radeon_gart_table_vram_pin(rdev);
if (r)
return r;
+ radeon_gart_restore(rdev);
/* Setup L2 cache */
WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING |
@@ -619,12 +611,73 @@ static void r600_mc_program(struct radeon_device *rdev)
rv515_vga_render_disable(rdev);
}
+/**
+ * r600_vram_gtt_location - try to find VRAM & GTT location
+ * @rdev: radeon device structure holding all necessary informations
+ * @mc: memory controller structure holding memory informations
+ *
+ * Function will place try to place VRAM at same place as in CPU (PCI)
+ * address space as some GPU seems to have issue when we reprogram at
+ * different address space.
+ *
+ * If there is not enough space to fit the unvisible VRAM after the
+ * aperture then we limit the VRAM size to the aperture.
+ *
+ * If we are using AGP then place VRAM adjacent to AGP aperture are we need
+ * them to be in one from GPU point of view so that we can program GPU to
+ * catch access outside them (weird GPU policy see ??).
+ *
+ * This function will never fails, worst case are limiting VRAM or GTT.
+ *
+ * Note: GTT start, end, size should be initialized before calling this
+ * function on AGP platform.
+ */
+void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc)
+{
+ u64 size_bf, size_af;
+
+ if (mc->mc_vram_size > 0xE0000000) {
+ /* leave room for at least 512M GTT */
+ dev_warn(rdev->dev, "limiting VRAM\n");
+ mc->real_vram_size = 0xE0000000;
+ mc->mc_vram_size = 0xE0000000;
+ }
+ if (rdev->flags & RADEON_IS_AGP) {
+ size_bf = mc->gtt_start;
+ size_af = 0xFFFFFFFF - mc->gtt_end + 1;
+ if (size_bf > size_af) {
+ if (mc->mc_vram_size > size_bf) {
+ dev_warn(rdev->dev, "limiting VRAM\n");
+ mc->real_vram_size = size_bf;
+ mc->mc_vram_size = size_bf;
+ }
+ mc->vram_start = mc->gtt_start - mc->mc_vram_size;
+ } else {
+ if (mc->mc_vram_size > size_af) {
+ dev_warn(rdev->dev, "limiting VRAM\n");
+ mc->real_vram_size = size_af;
+ mc->mc_vram_size = size_af;
+ }
+ mc->vram_start = mc->gtt_end;
+ }
+ mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
+ dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n",
+ mc->mc_vram_size >> 20, mc->vram_start,
+ mc->vram_end, mc->real_vram_size >> 20);
+ } else {
+ u64 base = 0;
+ if (rdev->flags & RADEON_IS_IGP)
+ base = (RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24;
+ radeon_vram_location(rdev, &rdev->mc, base);
+ radeon_gtt_location(rdev, mc);
+ }
+}
+
int r600_mc_init(struct radeon_device *rdev)
{
fixed20_12 a;
u32 tmp;
int chansize, numchan;
- int r;
/* Get VRAM informations */
rdev->mc.vram_is_ddr = true;
@@ -659,78 +712,21 @@ int r600_mc_init(struct radeon_device *rdev)
/* Setup GPU memory space */
rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE);
rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE);
-
- if (rdev->mc.mc_vram_size > rdev->mc.aper_size)
+ rdev->mc.visible_vram_size = rdev->mc.aper_size;
+ /* FIXME remove this once we support unmappable VRAM */
+ if (rdev->mc.mc_vram_size > rdev->mc.aper_size) {
rdev->mc.mc_vram_size = rdev->mc.aper_size;
-
- if (rdev->mc.real_vram_size > rdev->mc.aper_size)
rdev->mc.real_vram_size = rdev->mc.aper_size;
-
- if (rdev->flags & RADEON_IS_AGP) {
- r = radeon_agp_init(rdev);
- if (r)
- return r;
- /* gtt_size is setup by radeon_agp_init */
- rdev->mc.gtt_location = rdev->mc.agp_base;
- tmp = 0xFFFFFFFFUL - rdev->mc.agp_base - rdev->mc.gtt_size;
- /* Try to put vram before or after AGP because we
- * we want SYSTEM_APERTURE to cover both VRAM and
- * AGP so that GPU can catch out of VRAM/AGP access
- */
- if (rdev->mc.gtt_location > rdev->mc.mc_vram_size) {
- /* Enough place before */
- rdev->mc.vram_location = rdev->mc.gtt_location -
- rdev->mc.mc_vram_size;
- } else if (tmp > rdev->mc.mc_vram_size) {
- /* Enough place after */
- rdev->mc.vram_location = rdev->mc.gtt_location +
- rdev->mc.gtt_size;
- } else {
- /* Try to setup VRAM then AGP might not
- * not work on some card
- */
- rdev->mc.vram_location = 0x00000000UL;
- rdev->mc.gtt_location = rdev->mc.mc_vram_size;
- }
- } else {
- rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
- rdev->mc.vram_location = (RREG32(MC_VM_FB_LOCATION) &
- 0xFFFF) << 24;
- tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size;
- if ((0xFFFFFFFFUL - tmp) >= rdev->mc.gtt_size) {
- /* Enough place after vram */
- rdev->mc.gtt_location = tmp;
- } else if (rdev->mc.vram_location >= rdev->mc.gtt_size) {
- /* Enough place before vram */
- rdev->mc.gtt_location = 0;
- } else {
- /* Not enough place after or before shrink
- * gart size
- */
- if (rdev->mc.vram_location > (0xFFFFFFFFUL - tmp)) {
- rdev->mc.gtt_location = 0;
- rdev->mc.gtt_size = rdev->mc.vram_location;
- } else {
- rdev->mc.gtt_location = tmp;
- rdev->mc.gtt_size = 0xFFFFFFFFUL - tmp;
- }
- }
- rdev->mc.gtt_location = rdev->mc.mc_vram_size;
}
- rdev->mc.vram_start = rdev->mc.vram_location;
- rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
- rdev->mc.gtt_start = rdev->mc.gtt_location;
- rdev->mc.gtt_end = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
+ r600_vram_gtt_location(rdev, &rdev->mc);
/* FIXME: we should enforce default clock in case GPU is not in
* default setup
*/
a.full = rfixed_const(100);
rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk);
rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a);
-
if (rdev->flags & RADEON_IS_IGP)
rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
-
return 0;
}
@@ -985,6 +981,9 @@ void r600_gpu_init(struct radeon_device *rdev)
{
u32 tiling_config;
u32 ramcfg;
+ u32 backend_map;
+ u32 cc_rb_backend_disable;
+ u32 cc_gc_shader_pipe_config;
u32 tmp;
int i, j;
u32 sq_config;
@@ -1094,8 +1093,11 @@ void r600_gpu_init(struct radeon_device *rdev)
default:
break;
}
+ rdev->config.r600.tiling_npipes = rdev->config.r600.max_tile_pipes;
+ rdev->config.r600.tiling_nbanks = 4 << ((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
tiling_config |= BANK_TILING((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
tiling_config |= GROUP_SIZE(0);
+ rdev->config.r600.tiling_group_size = 256;
tmp = (ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
if (tmp > 3) {
tiling_config |= ROW_TILING(3);
@@ -1105,24 +1107,33 @@ void r600_gpu_init(struct radeon_device *rdev)
tiling_config |= SAMPLE_SPLIT(tmp);
}
tiling_config |= BANK_SWAPS(1);
- tmp = r600_get_tile_pipe_to_backend_map(rdev->config.r600.max_tile_pipes,
- rdev->config.r600.max_backends,
- (0xff << rdev->config.r600.max_backends) & 0xff);
- tiling_config |= BACKEND_MAP(tmp);
+
+ cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000;
+ cc_rb_backend_disable |=
+ BACKEND_DISABLE((R6XX_MAX_BACKENDS_MASK << rdev->config.r600.max_backends) & R6XX_MAX_BACKENDS_MASK);
+
+ cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00;
+ cc_gc_shader_pipe_config |=
+ INACTIVE_QD_PIPES((R6XX_MAX_PIPES_MASK << rdev->config.r600.max_pipes) & R6XX_MAX_PIPES_MASK);
+ cc_gc_shader_pipe_config |=
+ INACTIVE_SIMDS((R6XX_MAX_SIMDS_MASK << rdev->config.r600.max_simds) & R6XX_MAX_SIMDS_MASK);
+
+ backend_map = r600_get_tile_pipe_to_backend_map(rdev->config.r600.max_tile_pipes,
+ (R6XX_MAX_BACKENDS -
+ r600_count_pipe_bits((cc_rb_backend_disable &
+ R6XX_MAX_BACKENDS_MASK) >> 16)),
+ (cc_rb_backend_disable >> 16));
+
+ tiling_config |= BACKEND_MAP(backend_map);
WREG32(GB_TILING_CONFIG, tiling_config);
WREG32(DCP_TILING_CONFIG, tiling_config & 0xffff);
WREG32(HDP_TILING_CONFIG, tiling_config & 0xffff);
- tmp = BACKEND_DISABLE((R6XX_MAX_BACKENDS_MASK << rdev->config.r600.max_backends) & R6XX_MAX_BACKENDS_MASK);
- WREG32(CC_RB_BACKEND_DISABLE, tmp);
-
/* Setup pipes */
- tmp = INACTIVE_QD_PIPES((R6XX_MAX_PIPES_MASK << rdev->config.r600.max_pipes) & R6XX_MAX_PIPES_MASK);
- tmp |= INACTIVE_SIMDS((R6XX_MAX_SIMDS_MASK << rdev->config.r600.max_simds) & R6XX_MAX_SIMDS_MASK);
- WREG32(CC_GC_SHADER_PIPE_CONFIG, tmp);
- WREG32(GC_USER_SHADER_PIPE_CONFIG, tmp);
+ WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
+ WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
- tmp = R6XX_MAX_BACKENDS - r600_count_pipe_bits(tmp & INACTIVE_QD_PIPES_MASK);
+ tmp = R6XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8);
WREG32(VGT_OUT_DEALLOC_CNTL, (tmp * 4) & DEALLOC_DIST_MASK);
WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, ((tmp * 4) - 2) & VTX_REUSE_DEPTH_MASK);
@@ -1658,6 +1669,12 @@ void r600_ring_init(struct radeon_device *rdev, unsigned ring_size)
rdev->cp.align_mask = 16 - 1;
}
+void r600_cp_fini(struct radeon_device *rdev)
+{
+ r600_cp_stop(rdev);
+ radeon_ring_fini(rdev);
+}
+
/*
* GPU scratch registers helpers function.
@@ -1781,34 +1798,40 @@ void r600_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence)
{
/* Also consider EVENT_WRITE_EOP. it handles the interrupts + timestamps + events */
+
+ radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0));
+ radeon_ring_write(rdev, CACHE_FLUSH_AND_INV_EVENT);
+ /* wait for 3D idle clean */
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+ radeon_ring_write(rdev, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
+ radeon_ring_write(rdev, WAIT_3D_IDLE_bit | WAIT_3D_IDLECLEAN_bit);
/* Emit fence sequence & fire IRQ */
radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
radeon_ring_write(rdev, ((rdev->fence_drv.scratch_reg - PACKET3_SET_CONFIG_REG_OFFSET) >> 2));
radeon_ring_write(rdev, fence->seq);
- radeon_ring_write(rdev, PACKET0(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0));
- radeon_ring_write(rdev, 1);
/* CP_INTERRUPT packet 3 no longer exists, use packet 0 */
radeon_ring_write(rdev, PACKET0(CP_INT_STATUS, 0));
radeon_ring_write(rdev, RB_INT_STAT);
}
-int r600_copy_dma(struct radeon_device *rdev,
- uint64_t src_offset,
- uint64_t dst_offset,
- unsigned num_pages,
- struct radeon_fence *fence)
-{
- /* FIXME: implement */
- return 0;
-}
-
int r600_copy_blit(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_pages, struct radeon_fence *fence)
{
- r600_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE);
+ int r;
+
+ mutex_lock(&rdev->r600_blit.mutex);
+ rdev->r600_blit.vb_ib = NULL;
+ r = r600_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE);
+ if (r) {
+ if (rdev->r600_blit.vb_ib)
+ radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
+ mutex_unlock(&rdev->r600_blit.mutex);
+ return r;
+ }
r600_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE);
r600_blit_done_copy(rdev, fence);
+ mutex_unlock(&rdev->r600_blit.mutex);
return 0;
}
@@ -1864,26 +1887,25 @@ int r600_startup(struct radeon_device *rdev)
return r;
}
r600_gpu_init(rdev);
-
- if (!rdev->r600_blit.shader_obj) {
- r = r600_blit_init(rdev);
+ r = r600_blit_init(rdev);
+ if (r) {
+ r600_blit_fini(rdev);
+ rdev->asic->copy = NULL;
+ dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
+ }
+ /* pin copy shader into vram */
+ if (rdev->r600_blit.shader_obj) {
+ r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+ if (unlikely(r != 0))
+ return r;
+ r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
+ &rdev->r600_blit.shader_gpu_addr);
+ radeon_bo_unreserve(rdev->r600_blit.shader_obj);
if (r) {
- DRM_ERROR("radeon: failed blitter (%d).\n", r);
+ dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
return r;
}
}
-
- r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
- if (unlikely(r != 0))
- return r;
- r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
- &rdev->r600_blit.shader_gpu_addr);
- radeon_bo_unreserve(rdev->r600_blit.shader_obj);
- if (r) {
- dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
- return r;
- }
-
/* Enable IRQ */
r = r600_irq_init(rdev);
if (r) {
@@ -1948,6 +1970,13 @@ int r600_resume(struct radeon_device *rdev)
DRM_ERROR("radeon: failled testing IB (%d).\n", r);
return r;
}
+
+ r = r600_audio_init(rdev);
+ if (r) {
+ DRM_ERROR("radeon: audio resume failed\n");
+ return r;
+ }
+
return r;
}
@@ -1955,17 +1984,21 @@ int r600_suspend(struct radeon_device *rdev)
{
int r;
+ r600_audio_fini(rdev);
/* FIXME: we should wait for ring to be empty */
r600_cp_stop(rdev);
rdev->cp.ready = false;
+ r600_irq_suspend(rdev);
r600_wb_disable(rdev);
r600_pcie_gart_disable(rdev);
/* unpin shaders bo */
- r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
- if (unlikely(r != 0))
- return r;
- radeon_bo_unpin(rdev->r600_blit.shader_obj);
- radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+ if (rdev->r600_blit.shader_obj) {
+ r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+ if (!r) {
+ radeon_bo_unpin(rdev->r600_blit.shader_obj);
+ radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+ }
+ }
return 0;
}
@@ -2026,6 +2059,11 @@ int r600_init(struct radeon_device *rdev)
r = radeon_fence_driver_init(rdev);
if (r)
return r;
+ if (rdev->flags & RADEON_IS_AGP) {
+ r = radeon_agp_init(rdev);
+ if (r)
+ radeon_agp_disable(rdev);
+ }
r = r600_mc_init(rdev);
if (r)
return r;
@@ -2051,22 +2089,25 @@ int r600_init(struct radeon_device *rdev)
rdev->accel_working = true;
r = r600_startup(rdev);
if (r) {
- r600_suspend(rdev);
+ dev_err(rdev->dev, "disabling GPU acceleration\n");
+ r600_cp_fini(rdev);
r600_wb_fini(rdev);
- radeon_ring_fini(rdev);
+ r600_irq_fini(rdev);
+ radeon_irq_kms_fini(rdev);
r600_pcie_gart_fini(rdev);
rdev->accel_working = false;
}
if (rdev->accel_working) {
r = radeon_ib_pool_init(rdev);
if (r) {
- DRM_ERROR("radeon: failed initializing IB pool (%d).\n", r);
- rdev->accel_working = false;
- }
- r = r600_ib_test(rdev);
- if (r) {
- DRM_ERROR("radeon: failed testing IB (%d).\n", r);
+ dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
rdev->accel_working = false;
+ } else {
+ r = r600_ib_test(rdev);
+ if (r) {
+ dev_err(rdev->dev, "IB test failed (%d).\n", r);
+ rdev->accel_working = false;
+ }
}
}
@@ -2078,20 +2119,17 @@ int r600_init(struct radeon_device *rdev)
void r600_fini(struct radeon_device *rdev)
{
- /* Suspend operations */
- r600_suspend(rdev);
-
r600_audio_fini(rdev);
r600_blit_fini(rdev);
+ r600_cp_fini(rdev);
+ r600_wb_fini(rdev);
r600_irq_fini(rdev);
radeon_irq_kms_fini(rdev);
- radeon_ring_fini(rdev);
- r600_wb_fini(rdev);
r600_pcie_gart_fini(rdev);
+ radeon_agp_fini(rdev);
radeon_gem_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_clocks_fini(rdev);
- radeon_agp_fini(rdev);
radeon_bo_fini(rdev);
radeon_atombios_fini(rdev);
kfree(rdev->bios);
@@ -2197,14 +2235,14 @@ void r600_ih_ring_init(struct radeon_device *rdev, unsigned ring_size)
rb_bufsz = drm_order(ring_size / 4);
ring_size = (1 << rb_bufsz) * 4;
rdev->ih.ring_size = ring_size;
- rdev->ih.align_mask = 4 - 1;
+ rdev->ih.ptr_mask = rdev->ih.ring_size - 1;
+ rdev->ih.rptr = 0;
}
-static int r600_ih_ring_alloc(struct radeon_device *rdev, unsigned ring_size)
+static int r600_ih_ring_alloc(struct radeon_device *rdev)
{
int r;
- rdev->ih.ring_size = ring_size;
/* Allocate ring buffer */
if (rdev->ih.ring_obj == NULL) {
r = radeon_bo_create(rdev, NULL, rdev->ih.ring_size,
@@ -2234,9 +2272,6 @@ static int r600_ih_ring_alloc(struct radeon_device *rdev, unsigned ring_size)
return r;
}
}
- rdev->ih.ptr_mask = (rdev->cp.ring_size / 4) - 1;
- rdev->ih.rptr = 0;
-
return 0;
}
@@ -2386,7 +2421,7 @@ int r600_irq_init(struct radeon_device *rdev)
u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
/* allocate ring */
- ret = r600_ih_ring_alloc(rdev, rdev->ih.ring_size);
+ ret = r600_ih_ring_alloc(rdev);
if (ret)
return ret;
@@ -2449,10 +2484,15 @@ int r600_irq_init(struct radeon_device *rdev)
return ret;
}
-void r600_irq_fini(struct radeon_device *rdev)
+void r600_irq_suspend(struct radeon_device *rdev)
{
r600_disable_interrupts(rdev);
r600_rlc_stop(rdev);
+}
+
+void r600_irq_fini(struct radeon_device *rdev)
+{
+ r600_irq_suspend(rdev);
r600_ih_ring_fini(rdev);
}
@@ -2467,8 +2507,12 @@ int r600_irq_set(struct radeon_device *rdev)
return -EINVAL;
}
/* don't enable anything if the ih is disabled */
- if (!rdev->ih.enabled)
+ if (!rdev->ih.enabled) {
+ r600_disable_interrupts(rdev);
+ /* force the active interrupt state to all disabled */
+ r600_disable_interrupt_state(rdev);
return 0;
+ }
if (ASIC_IS_DCE3(rdev)) {
hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
@@ -2638,16 +2682,18 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev)
wptr = RREG32(IH_RB_WPTR);
if (wptr & RB_OVERFLOW) {
- WARN_ON(1);
- /* XXX deal with overflow */
- DRM_ERROR("IH RB overflow\n");
+ /* When a ring buffer overflow happen start parsing interrupt
+ * from the last not overwritten vector (wptr + 16). Hopefully
+ * this should allow us to catchup.
+ */
+ dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n",
+ wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask);
+ rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask;
tmp = RREG32(IH_RB_CNTL);
tmp |= IH_WPTR_OVERFLOW_CLEAR;
WREG32(IH_RB_CNTL, tmp);
}
- wptr = wptr & WPTR_OFFSET_MASK;
-
- return wptr;
+ return (wptr & rdev->ih.ptr_mask);
}
/* r600 IV Ring
@@ -2683,12 +2729,13 @@ int r600_irq_process(struct radeon_device *rdev)
u32 wptr = r600_get_ih_wptr(rdev);
u32 rptr = rdev->ih.rptr;
u32 src_id, src_data;
- u32 last_entry = rdev->ih.ring_size - 16;
u32 ring_index, disp_int, disp_int_cont, disp_int_cont2;
unsigned long flags;
bool queue_hotplug = false;
DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
+ if (!rdev->ih.enabled)
+ return IRQ_NONE;
spin_lock_irqsave(&rdev->ih.lock, flags);
@@ -2718,6 +2765,7 @@ restart_ih:
case 0: /* D1 vblank */
if (disp_int & LB_D1_VBLANK_INTERRUPT) {
drm_handle_vblank(rdev->ddev, 0);
+ wake_up(&rdev->irq.vblank_queue);
disp_int &= ~LB_D1_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D1 vblank\n");
}
@@ -2738,6 +2786,7 @@ restart_ih:
case 0: /* D2 vblank */
if (disp_int & LB_D2_VBLANK_INTERRUPT) {
drm_handle_vblank(rdev->ddev, 1);
+ wake_up(&rdev->irq.vblank_queue);
disp_int &= ~LB_D2_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D2 vblank\n");
}
@@ -2817,10 +2866,8 @@ restart_ih:
}
/* wptr/rptr are in bytes! */
- if (rptr == last_entry)
- rptr = 0;
- else
- rptr += 16;
+ rptr += 16;
+ rptr &= rdev->ih.ptr_mask;
}
/* make sure wptr hasn't changed while processing */
wptr = r600_get_ih_wptr(rdev);
@@ -2888,3 +2935,18 @@ int r600_debugfs_mc_info_init(struct radeon_device *rdev)
return 0;
#endif
}
+
+/**
+ * r600_ioctl_wait_idle - flush host path cache on wait idle ioctl
+ * rdev: radeon device structure
+ * bo: buffer object struct which userspace is waiting for idle
+ *
+ * Some R6XX/R7XX doesn't seems to take into account HDP flush performed
+ * through ring buffer, this leads to corruption in rendering, see
+ * http://bugzilla.kernel.org/show_bug.cgi?id=15186 to avoid this we
+ * directly perform HDP flush by writing register through MMIO.
+ */
+void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo)
+{
+ WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
+}
diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c
index 99e2c3891a7d..db928016d034 100644
--- a/drivers/gpu/drm/radeon/r600_audio.c
+++ b/drivers/gpu/drm/radeon/r600_audio.c
@@ -147,15 +147,23 @@ static void r600_audio_update_hdmi(unsigned long param)
}
/*
+ * turn on/off audio engine
+ */
+static void r600_audio_engine_enable(struct radeon_device *rdev, bool enable)
+{
+ DRM_INFO("%s audio support", enable ? "Enabling" : "Disabling");
+ WREG32_P(R600_AUDIO_ENABLE, enable ? 0x81000000 : 0x0, ~0x81000000);
+}
+
+/*
* initialize the audio vars and register the update timer
*/
int r600_audio_init(struct radeon_device *rdev)
{
- if (!r600_audio_chipset_supported(rdev))
+ if (!radeon_audio || !r600_audio_chipset_supported(rdev))
return 0;
- DRM_INFO("%s audio support", radeon_audio ? "Enabling" : "Disabling");
- WREG32_P(R600_AUDIO_ENABLE, radeon_audio ? 0x81000000 : 0x0, ~0x81000000);
+ r600_audio_engine_enable(rdev, true);
rdev->audio_channels = -1;
rdev->audio_rate = -1;
@@ -258,10 +266,10 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
*/
void r600_audio_fini(struct radeon_device *rdev)
{
- if (!r600_audio_chipset_supported(rdev))
+ if (!radeon_audio || !r600_audio_chipset_supported(rdev))
return;
- WREG32_P(R600_AUDIO_ENABLE, 0x0, ~0x81000000);
-
del_timer(&rdev->audio_timer);
+
+ r600_audio_engine_enable(rdev, false);
}
diff --git a/drivers/gpu/drm/radeon/r600_blit.c b/drivers/gpu/drm/radeon/r600_blit.c
index 5ea432347589..f4fb88ece2bb 100644
--- a/drivers/gpu/drm/radeon/r600_blit.c
+++ b/drivers/gpu/drm/radeon/r600_blit.c
@@ -49,7 +49,7 @@ set_render_target(drm_radeon_private_t *dev_priv, int format, int w, int h, u64
RING_LOCALS;
DRM_DEBUG("\n");
- h = (h + 7) & ~7;
+ h = ALIGN(h, 8);
if (h < 8)
h = 8;
diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c
index 8787ea89dc6e..f6c6c77db7e0 100644
--- a/drivers/gpu/drm/radeon/r600_blit_kms.c
+++ b/drivers/gpu/drm/radeon/r600_blit_kms.c
@@ -25,7 +25,7 @@ set_render_target(struct radeon_device *rdev, int format,
u32 cb_color_info;
int pitch, slice;
- h = (h + 7) & ~7;
+ h = ALIGN(h, 8);
if (h < 8)
h = 8;
@@ -396,15 +396,13 @@ set_default_state(struct radeon_device *rdev)
NUM_ES_STACK_ENTRIES(num_es_stack_entries));
/* emit an IB pointing at default state */
- dwords = (rdev->r600_blit.state_len + 0xf) & ~0xf;
+ dwords = ALIGN(rdev->r600_blit.state_len, 0x10);
gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.state_offset;
radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
radeon_ring_write(rdev, gpu_addr & 0xFFFFFFFC);
radeon_ring_write(rdev, upper_32_bits(gpu_addr) & 0xFF);
radeon_ring_write(rdev, dwords);
- radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0));
- radeon_ring_write(rdev, CACHE_FLUSH_AND_INV_EVENT);
/* SQ config */
radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 6));
radeon_ring_write(rdev, (SQ_CONFIG - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
@@ -449,6 +447,7 @@ int r600_blit_init(struct radeon_device *rdev)
u32 packet2s[16];
int num_packet2s = 0;
+ mutex_init(&rdev->r600_blit.mutex);
rdev->r600_blit.state_offset = 0;
if (rdev->family >= CHIP_RV770)
@@ -512,14 +511,16 @@ void r600_blit_fini(struct radeon_device *rdev)
{
int r;
+ if (rdev->r600_blit.shader_obj == NULL)
+ return;
+ /* If we can't reserve the bo, unref should be enough to destroy
+ * it when it becomes idle.
+ */
r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
- if (unlikely(r != 0)) {
- dev_err(rdev->dev, "(%d) can't finish r600 blit\n", r);
- goto out_unref;
+ if (!r) {
+ radeon_bo_unpin(rdev->r600_blit.shader_obj);
+ radeon_bo_unreserve(rdev->r600_blit.shader_obj);
}
- radeon_bo_unpin(rdev->r600_blit.shader_obj);
- radeon_bo_unreserve(rdev->r600_blit.shader_obj);
-out_unref:
radeon_bo_unref(&rdev->r600_blit.shader_obj);
}
@@ -540,9 +541,6 @@ int r600_vb_ib_get(struct radeon_device *rdev)
void r600_vb_ib_put(struct radeon_device *rdev)
{
radeon_fence_emit(rdev, rdev->r600_blit.vb_ib->fence);
- mutex_lock(&rdev->ib_pool.mutex);
- list_add_tail(&rdev->r600_blit.vb_ib->list, &rdev->ib_pool.scheduled_ibs);
- mutex_unlock(&rdev->ib_pool.mutex);
radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
}
@@ -555,7 +553,8 @@ int r600_blit_prepare_copy(struct radeon_device *rdev, int size_bytes)
int dwords_per_loop = 76, num_loops;
r = r600_vb_ib_get(rdev);
- WARN_ON(r);
+ if (r)
+ return r;
/* set_render_target emits 2 extra dwords on rv6xx */
if (rdev->family > CHIP_R600 && rdev->family < CHIP_RV770)
@@ -577,11 +576,12 @@ int r600_blit_prepare_copy(struct radeon_device *rdev, int size_bytes)
ring_size = num_loops * dwords_per_loop;
/* set default + shaders */
ring_size += 40; /* shaders + def state */
- ring_size += 7; /* fence emit for VB IB */
+ ring_size += 10; /* fence emit for VB IB */
ring_size += 5; /* done copy */
- ring_size += 7; /* fence emit for done copy */
+ ring_size += 10; /* fence emit for done copy */
r = radeon_ring_lock(rdev, ring_size);
- WARN_ON(r);
+ if (r)
+ return r;
set_default_state(rdev); /* 14 */
set_shaders(rdev); /* 26 */
@@ -592,13 +592,6 @@ void r600_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence)
{
int r;
- radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0));
- radeon_ring_write(rdev, CACHE_FLUSH_AND_INV_EVENT);
- /* wait for 3D idle clean */
- radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
- radeon_ring_write(rdev, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
- radeon_ring_write(rdev, WAIT_3D_IDLE_bit | WAIT_3D_IDLECLEAN_bit);
-
if (rdev->r600_blit.vb_ib)
r600_vb_ib_put(rdev);
diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.c b/drivers/gpu/drm/radeon/r600_blit_shaders.c
index d745e815c2e8..a112c59f9d82 100644
--- a/drivers/gpu/drm/radeon/r600_blit_shaders.c
+++ b/drivers/gpu/drm/radeon/r600_blit_shaders.c
@@ -9,11 +9,6 @@ const u32 r6xx_default_state[] =
0xc0012800,
0x80000000,
0x80000000,
- 0xc0004600,
- 0x00000016,
- 0xc0016800,
- 0x00000010,
- 0x00028000,
0xc0016800,
0x00000010,
0x00008000,
@@ -531,11 +526,6 @@ const u32 r7xx_default_state[] =
0xc0012800,
0x80000000,
0x80000000,
- 0xc0004600,
- 0x00000016,
- 0xc0016800,
- 0x00000010,
- 0x00028000,
0xc0016800,
0x00000010,
0x00008000,
diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c
index 6d5a711c2e91..40416c068d9f 100644
--- a/drivers/gpu/drm/radeon/r600_cp.c
+++ b/drivers/gpu/drm/radeon/r600_cp.c
@@ -734,8 +734,8 @@ static void r600_gfx_init(struct drm_device *dev,
u32 hdp_host_path_cntl;
u32 backend_map;
u32 gb_tiling_config = 0;
- u32 cc_rb_backend_disable = 0;
- u32 cc_gc_shader_pipe_config = 0;
+ u32 cc_rb_backend_disable;
+ u32 cc_gc_shader_pipe_config;
u32 ramcfg;
/* setup chip specs */
@@ -857,29 +857,44 @@ static void r600_gfx_init(struct drm_device *dev,
gb_tiling_config |= R600_BANK_SWAPS(1);
- backend_map = r600_get_tile_pipe_to_backend_map(dev_priv->r600_max_tile_pipes,
- dev_priv->r600_max_backends,
- (0xff << dev_priv->r600_max_backends) & 0xff);
- gb_tiling_config |= R600_BACKEND_MAP(backend_map);
+ cc_rb_backend_disable = RADEON_READ(R600_CC_RB_BACKEND_DISABLE) & 0x00ff0000;
+ cc_rb_backend_disable |=
+ R600_BACKEND_DISABLE((R6XX_MAX_BACKENDS_MASK << dev_priv->r600_max_backends) & R6XX_MAX_BACKENDS_MASK);
- cc_gc_shader_pipe_config =
+ cc_gc_shader_pipe_config = RADEON_READ(R600_CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00;
+ cc_gc_shader_pipe_config |=
R600_INACTIVE_QD_PIPES((R6XX_MAX_PIPES_MASK << dev_priv->r600_max_pipes) & R6XX_MAX_PIPES_MASK);
cc_gc_shader_pipe_config |=
R600_INACTIVE_SIMDS((R6XX_MAX_SIMDS_MASK << dev_priv->r600_max_simds) & R6XX_MAX_SIMDS_MASK);
- cc_rb_backend_disable =
- R600_BACKEND_DISABLE((R6XX_MAX_BACKENDS_MASK << dev_priv->r600_max_backends) & R6XX_MAX_BACKENDS_MASK);
+ backend_map = r600_get_tile_pipe_to_backend_map(dev_priv->r600_max_tile_pipes,
+ (R6XX_MAX_BACKENDS -
+ r600_count_pipe_bits((cc_rb_backend_disable &
+ R6XX_MAX_BACKENDS_MASK) >> 16)),
+ (cc_rb_backend_disable >> 16));
+ gb_tiling_config |= R600_BACKEND_MAP(backend_map);
RADEON_WRITE(R600_GB_TILING_CONFIG, gb_tiling_config);
RADEON_WRITE(R600_DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
RADEON_WRITE(R600_HDP_TILING_CONFIG, (gb_tiling_config & 0xffff));
+ if (gb_tiling_config & 0xc0) {
+ dev_priv->r600_group_size = 512;
+ } else {
+ dev_priv->r600_group_size = 256;
+ }
+ dev_priv->r600_npipes = 1 << ((gb_tiling_config >> 1) & 0x7);
+ if (gb_tiling_config & 0x30) {
+ dev_priv->r600_nbanks = 8;
+ } else {
+ dev_priv->r600_nbanks = 4;
+ }
RADEON_WRITE(R600_CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
RADEON_WRITE(R600_CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
RADEON_WRITE(R600_GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
num_qd_pipes =
- R6XX_MAX_BACKENDS - r600_count_pipe_bits(cc_gc_shader_pipe_config & R600_INACTIVE_QD_PIPES_MASK);
+ R6XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & R600_INACTIVE_QD_PIPES_MASK) >> 8);
RADEON_WRITE(R600_VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & R600_DEALLOC_DIST_MASK);
RADEON_WRITE(R600_VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & R600_VTX_REUSE_DEPTH_MASK);
@@ -1151,7 +1166,8 @@ static void r600_gfx_init(struct drm_device *dev,
}
-static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
+static u32 r700_get_tile_pipe_to_backend_map(drm_radeon_private_t *dev_priv,
+ u32 num_tile_pipes,
u32 num_backends,
u32 backend_disable_mask)
{
@@ -1162,6 +1178,7 @@ static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
u32 swizzle_pipe[R7XX_MAX_PIPES];
u32 cur_backend;
u32 i;
+ bool force_no_swizzle;
if (num_tile_pipes > R7XX_MAX_PIPES)
num_tile_pipes = R7XX_MAX_PIPES;
@@ -1191,6 +1208,18 @@ static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
if (enabled_backends_count != num_backends)
num_backends = enabled_backends_count;
+ switch (dev_priv->flags & RADEON_FAMILY_MASK) {
+ case CHIP_RV770:
+ case CHIP_RV730:
+ force_no_swizzle = false;
+ break;
+ case CHIP_RV710:
+ case CHIP_RV740:
+ default:
+ force_no_swizzle = true;
+ break;
+ }
+
memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R7XX_MAX_PIPES);
switch (num_tile_pipes) {
case 1:
@@ -1201,49 +1230,100 @@ static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
swizzle_pipe[1] = 1;
break;
case 3:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 1;
+ if (force_no_swizzle) {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 1;
+ swizzle_pipe[2] = 2;
+ } else {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 2;
+ swizzle_pipe[2] = 1;
+ }
break;
case 4:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 3;
- swizzle_pipe[3] = 1;
+ if (force_no_swizzle) {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 1;
+ swizzle_pipe[2] = 2;
+ swizzle_pipe[3] = 3;
+ } else {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 2;
+ swizzle_pipe[2] = 3;
+ swizzle_pipe[3] = 1;
+ }
break;
case 5:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 1;
- swizzle_pipe[4] = 3;
+ if (force_no_swizzle) {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 1;
+ swizzle_pipe[2] = 2;
+ swizzle_pipe[3] = 3;
+ swizzle_pipe[4] = 4;
+ } else {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 2;
+ swizzle_pipe[2] = 4;
+ swizzle_pipe[3] = 1;
+ swizzle_pipe[4] = 3;
+ }
break;
case 6:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 5;
- swizzle_pipe[4] = 3;
- swizzle_pipe[5] = 1;
+ if (force_no_swizzle) {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 1;
+ swizzle_pipe[2] = 2;
+ swizzle_pipe[3] = 3;
+ swizzle_pipe[4] = 4;
+ swizzle_pipe[5] = 5;
+ } else {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 2;
+ swizzle_pipe[2] = 4;
+ swizzle_pipe[3] = 5;
+ swizzle_pipe[4] = 3;
+ swizzle_pipe[5] = 1;
+ }
break;
case 7:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 6;
- swizzle_pipe[4] = 3;
- swizzle_pipe[5] = 1;
- swizzle_pipe[6] = 5;
+ if (force_no_swizzle) {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 1;
+ swizzle_pipe[2] = 2;
+ swizzle_pipe[3] = 3;
+ swizzle_pipe[4] = 4;
+ swizzle_pipe[5] = 5;
+ swizzle_pipe[6] = 6;
+ } else {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 2;
+ swizzle_pipe[2] = 4;
+ swizzle_pipe[3] = 6;
+ swizzle_pipe[4] = 3;
+ swizzle_pipe[5] = 1;
+ swizzle_pipe[6] = 5;
+ }
break;
case 8:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 6;
- swizzle_pipe[4] = 3;
- swizzle_pipe[5] = 1;
- swizzle_pipe[6] = 7;
- swizzle_pipe[7] = 5;
+ if (force_no_swizzle) {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 1;
+ swizzle_pipe[2] = 2;
+ swizzle_pipe[3] = 3;
+ swizzle_pipe[4] = 4;
+ swizzle_pipe[5] = 5;
+ swizzle_pipe[6] = 6;
+ swizzle_pipe[7] = 7;
+ } else {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 2;
+ swizzle_pipe[2] = 4;
+ swizzle_pipe[3] = 6;
+ swizzle_pipe[4] = 3;
+ swizzle_pipe[5] = 1;
+ swizzle_pipe[6] = 7;
+ swizzle_pipe[7] = 5;
+ }
break;
}
@@ -1264,8 +1344,10 @@ static void r700_gfx_init(struct drm_device *dev,
drm_radeon_private_t *dev_priv)
{
int i, j, num_qd_pipes;
+ u32 ta_aux_cntl;
u32 sx_debug_1;
u32 smx_dc_ctl0;
+ u32 db_debug3;
u32 num_gs_verts_per_thread;
u32 vgt_gs_per_es;
u32 gs_prim_buffer_depth = 0;
@@ -1276,8 +1358,8 @@ static void r700_gfx_init(struct drm_device *dev,
u32 sq_dyn_gpr_size_simd_ab_0;
u32 backend_map;
u32 gb_tiling_config = 0;
- u32 cc_rb_backend_disable = 0;
- u32 cc_gc_shader_pipe_config = 0;
+ u32 cc_rb_backend_disable;
+ u32 cc_gc_shader_pipe_config;
u32 mc_arb_ramcfg;
u32 db_debug4;
@@ -1428,35 +1510,51 @@ static void r700_gfx_init(struct drm_device *dev,
gb_tiling_config |= R600_BANK_SWAPS(1);
- backend_map = r700_get_tile_pipe_to_backend_map(dev_priv->r600_max_tile_pipes,
- dev_priv->r600_max_backends,
- (0xff << dev_priv->r600_max_backends) & 0xff);
- gb_tiling_config |= R600_BACKEND_MAP(backend_map);
+ cc_rb_backend_disable = RADEON_READ(R600_CC_RB_BACKEND_DISABLE) & 0x00ff0000;
+ cc_rb_backend_disable |=
+ R600_BACKEND_DISABLE((R7XX_MAX_BACKENDS_MASK << dev_priv->r600_max_backends) & R7XX_MAX_BACKENDS_MASK);
- cc_gc_shader_pipe_config =
+ cc_gc_shader_pipe_config = RADEON_READ(R600_CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00;
+ cc_gc_shader_pipe_config |=
R600_INACTIVE_QD_PIPES((R7XX_MAX_PIPES_MASK << dev_priv->r600_max_pipes) & R7XX_MAX_PIPES_MASK);
cc_gc_shader_pipe_config |=
R600_INACTIVE_SIMDS((R7XX_MAX_SIMDS_MASK << dev_priv->r600_max_simds) & R7XX_MAX_SIMDS_MASK);
- cc_rb_backend_disable =
- R600_BACKEND_DISABLE((R7XX_MAX_BACKENDS_MASK << dev_priv->r600_max_backends) & R7XX_MAX_BACKENDS_MASK);
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV740)
+ backend_map = 0x28;
+ else
+ backend_map = r700_get_tile_pipe_to_backend_map(dev_priv,
+ dev_priv->r600_max_tile_pipes,
+ (R7XX_MAX_BACKENDS -
+ r600_count_pipe_bits((cc_rb_backend_disable &
+ R7XX_MAX_BACKENDS_MASK) >> 16)),
+ (cc_rb_backend_disable >> 16));
+ gb_tiling_config |= R600_BACKEND_MAP(backend_map);
RADEON_WRITE(R600_GB_TILING_CONFIG, gb_tiling_config);
RADEON_WRITE(R600_DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
RADEON_WRITE(R600_HDP_TILING_CONFIG, (gb_tiling_config & 0xffff));
+ if (gb_tiling_config & 0xc0) {
+ dev_priv->r600_group_size = 512;
+ } else {
+ dev_priv->r600_group_size = 256;
+ }
+ dev_priv->r600_npipes = 1 << ((gb_tiling_config >> 1) & 0x7);
+ if (gb_tiling_config & 0x30) {
+ dev_priv->r600_nbanks = 8;
+ } else {
+ dev_priv->r600_nbanks = 4;
+ }
RADEON_WRITE(R600_CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
RADEON_WRITE(R600_CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
- RADEON_WRITE(R600_GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
RADEON_WRITE(R700_CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable);
RADEON_WRITE(R700_CGTS_SYS_TCC_DISABLE, 0);
RADEON_WRITE(R700_CGTS_TCC_DISABLE, 0);
- RADEON_WRITE(R700_CGTS_USER_SYS_TCC_DISABLE, 0);
- RADEON_WRITE(R700_CGTS_USER_TCC_DISABLE, 0);
num_qd_pipes =
- R7XX_MAX_BACKENDS - r600_count_pipe_bits(cc_gc_shader_pipe_config & R600_INACTIVE_QD_PIPES_MASK);
+ R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & R600_INACTIVE_QD_PIPES_MASK) >> 8);
RADEON_WRITE(R600_VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & R600_DEALLOC_DIST_MASK);
RADEON_WRITE(R600_VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & R600_VTX_REUSE_DEPTH_MASK);
@@ -1466,10 +1564,8 @@ static void r700_gfx_init(struct drm_device *dev,
RADEON_WRITE(R600_CP_MEQ_THRESHOLDS, R700_STQ_SPLIT(0x30));
- RADEON_WRITE(R600_TA_CNTL_AUX, (R600_DISABLE_CUBE_ANISO |
- R600_SYNC_GRADIENT |
- R600_SYNC_WALKER |
- R600_SYNC_ALIGNER));
+ ta_aux_cntl = RADEON_READ(R600_TA_CNTL_AUX);
+ RADEON_WRITE(R600_TA_CNTL_AUX, ta_aux_cntl | R600_DISABLE_CUBE_ANISO);
sx_debug_1 = RADEON_READ(R700_SX_DEBUG_1);
sx_debug_1 |= R700_ENABLE_NEW_SMX_ADDRESS;
@@ -1480,14 +1576,28 @@ static void r700_gfx_init(struct drm_device *dev,
smx_dc_ctl0 |= R700_CACHE_DEPTH((dev_priv->r700_sx_num_of_sets * 64) - 1);
RADEON_WRITE(R600_SMX_DC_CTL0, smx_dc_ctl0);
- RADEON_WRITE(R700_SMX_EVENT_CTL, (R700_ES_FLUSH_CTL(4) |
- R700_GS_FLUSH_CTL(4) |
- R700_ACK_FLUSH_CTL(3) |
- R700_SYNC_FLUSH_CTL));
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) != CHIP_RV740)
+ RADEON_WRITE(R700_SMX_EVENT_CTL, (R700_ES_FLUSH_CTL(4) |
+ R700_GS_FLUSH_CTL(4) |
+ R700_ACK_FLUSH_CTL(3) |
+ R700_SYNC_FLUSH_CTL));
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV770)
- RADEON_WRITE(R700_DB_DEBUG3, R700_DB_CLK_OFF_DELAY(0x1f));
- else {
+ db_debug3 = RADEON_READ(R700_DB_DEBUG3);
+ db_debug3 &= ~R700_DB_CLK_OFF_DELAY(0x1f);
+ switch (dev_priv->flags & RADEON_FAMILY_MASK) {
+ case CHIP_RV770:
+ case CHIP_RV740:
+ db_debug3 |= R700_DB_CLK_OFF_DELAY(0x1f);
+ break;
+ case CHIP_RV710:
+ case CHIP_RV730:
+ default:
+ db_debug3 |= R700_DB_CLK_OFF_DELAY(2);
+ break;
+ }
+ RADEON_WRITE(R700_DB_DEBUG3, db_debug3);
+
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) != CHIP_RV770) {
db_debug4 = RADEON_READ(RV700_DB_DEBUG4);
db_debug4 |= RV700_DISABLE_TILE_COVERED_FOR_PS_ITER;
RADEON_WRITE(RV700_DB_DEBUG4, db_debug4);
@@ -1516,10 +1626,10 @@ static void r700_gfx_init(struct drm_device *dev,
R600_ALU_UPDATE_FIFO_HIWATER(0x8));
switch (dev_priv->flags & RADEON_FAMILY_MASK) {
case CHIP_RV770:
- sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x1);
- break;
case CHIP_RV730:
case CHIP_RV710:
+ sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x1);
+ break;
case CHIP_RV740:
default:
sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x4);
@@ -2526,3 +2636,12 @@ out:
mutex_unlock(&dev_priv->cs_mutex);
return r;
}
+
+void r600_cs_legacy_get_tiling_conf(struct drm_device *dev, u32 *npipes, u32 *nbanks, u32 *group_size)
+{
+ struct drm_radeon_private *dev_priv = dev->dev_private;
+
+ *npipes = dev_priv->r600_npipes;
+ *nbanks = dev_priv->r600_nbanks;
+ *group_size = dev_priv->r600_group_size;
+}
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index 44060b92d9e6..cd2c63bce501 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -28,6 +28,7 @@
#include "drmP.h"
#include "radeon.h"
#include "r600d.h"
+#include "r600_reg_safe.h"
static int r600_cs_packet_next_reloc_mm(struct radeon_cs_parser *p,
struct radeon_cs_reloc **cs_reloc);
@@ -35,6 +36,312 @@ static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p,
struct radeon_cs_reloc **cs_reloc);
typedef int (*next_reloc_t)(struct radeon_cs_parser*, struct radeon_cs_reloc**);
static next_reloc_t r600_cs_packet_next_reloc = &r600_cs_packet_next_reloc_mm;
+extern void r600_cs_legacy_get_tiling_conf(struct drm_device *dev, u32 *npipes, u32 *nbanks, u32 *group_size);
+
+
+struct r600_cs_track {
+ /* configuration we miror so that we use same code btw kms/ums */
+ u32 group_size;
+ u32 nbanks;
+ u32 npipes;
+ /* value we track */
+ u32 nsamples;
+ u32 cb_color_base_last[8];
+ struct radeon_bo *cb_color_bo[8];
+ u32 cb_color_bo_offset[8];
+ struct radeon_bo *cb_color_frag_bo[8];
+ struct radeon_bo *cb_color_tile_bo[8];
+ u32 cb_color_info[8];
+ u32 cb_color_size_idx[8];
+ u32 cb_target_mask;
+ u32 cb_shader_mask;
+ u32 cb_color_size[8];
+ u32 vgt_strmout_en;
+ u32 vgt_strmout_buffer_en;
+ u32 db_depth_control;
+ u32 db_depth_info;
+ u32 db_depth_size_idx;
+ u32 db_depth_view;
+ u32 db_depth_size;
+ u32 db_offset;
+ struct radeon_bo *db_bo;
+};
+
+static inline int r600_bpe_from_format(u32 *bpe, u32 format)
+{
+ switch (format) {
+ case V_038004_COLOR_8:
+ case V_038004_COLOR_4_4:
+ case V_038004_COLOR_3_3_2:
+ case V_038004_FMT_1:
+ *bpe = 1;
+ break;
+ case V_038004_COLOR_16:
+ case V_038004_COLOR_16_FLOAT:
+ case V_038004_COLOR_8_8:
+ case V_038004_COLOR_5_6_5:
+ case V_038004_COLOR_6_5_5:
+ case V_038004_COLOR_1_5_5_5:
+ case V_038004_COLOR_4_4_4_4:
+ case V_038004_COLOR_5_5_5_1:
+ *bpe = 2;
+ break;
+ case V_038004_FMT_8_8_8:
+ *bpe = 3;
+ break;
+ case V_038004_COLOR_32:
+ case V_038004_COLOR_32_FLOAT:
+ case V_038004_COLOR_16_16:
+ case V_038004_COLOR_16_16_FLOAT:
+ case V_038004_COLOR_8_24:
+ case V_038004_COLOR_8_24_FLOAT:
+ case V_038004_COLOR_24_8:
+ case V_038004_COLOR_24_8_FLOAT:
+ case V_038004_COLOR_10_11_11:
+ case V_038004_COLOR_10_11_11_FLOAT:
+ case V_038004_COLOR_11_11_10:
+ case V_038004_COLOR_11_11_10_FLOAT:
+ case V_038004_COLOR_2_10_10_10:
+ case V_038004_COLOR_8_8_8_8:
+ case V_038004_COLOR_10_10_10_2:
+ case V_038004_FMT_5_9_9_9_SHAREDEXP:
+ case V_038004_FMT_32_AS_8:
+ case V_038004_FMT_32_AS_8_8:
+ *bpe = 4;
+ break;
+ case V_038004_COLOR_X24_8_32_FLOAT:
+ case V_038004_COLOR_32_32:
+ case V_038004_COLOR_32_32_FLOAT:
+ case V_038004_COLOR_16_16_16_16:
+ case V_038004_COLOR_16_16_16_16_FLOAT:
+ *bpe = 8;
+ break;
+ case V_038004_FMT_16_16_16:
+ case V_038004_FMT_16_16_16_FLOAT:
+ *bpe = 6;
+ break;
+ case V_038004_FMT_32_32_32:
+ case V_038004_FMT_32_32_32_FLOAT:
+ *bpe = 12;
+ break;
+ case V_038004_COLOR_32_32_32_32:
+ case V_038004_COLOR_32_32_32_32_FLOAT:
+ *bpe = 16;
+ break;
+ case V_038004_FMT_GB_GR:
+ case V_038004_FMT_BG_RG:
+ case V_038004_COLOR_INVALID:
+ *bpe = 16;
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void r600_cs_track_init(struct r600_cs_track *track)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ track->cb_color_base_last[i] = 0;
+ track->cb_color_size[i] = 0;
+ track->cb_color_size_idx[i] = 0;
+ track->cb_color_info[i] = 0;
+ track->cb_color_bo[i] = NULL;
+ track->cb_color_bo_offset[i] = 0xFFFFFFFF;
+ }
+ track->cb_target_mask = 0xFFFFFFFF;
+ track->cb_shader_mask = 0xFFFFFFFF;
+ track->db_bo = NULL;
+ /* assume the biggest format and that htile is enabled */
+ track->db_depth_info = 7 | (1 << 25);
+ track->db_depth_view = 0xFFFFC000;
+ track->db_depth_size = 0xFFFFFFFF;
+ track->db_depth_size_idx = 0;
+ track->db_depth_control = 0xFFFFFFFF;
+}
+
+static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
+{
+ struct r600_cs_track *track = p->track;
+ u32 bpe = 0, pitch, slice_tile_max, size, tmp, height;
+ volatile u32 *ib = p->ib->ptr;
+
+ if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
+ dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
+ return -EINVAL;
+ }
+ size = radeon_bo_size(track->cb_color_bo[i]);
+ if (r600_bpe_from_format(&bpe, G_0280A0_FORMAT(track->cb_color_info[i]))) {
+ dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08X)\n",
+ __func__, __LINE__, G_0280A0_FORMAT(track->cb_color_info[i]),
+ i, track->cb_color_info[i]);
+ return -EINVAL;
+ }
+ pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) << 3;
+ slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1;
+ if (!pitch) {
+ dev_warn(p->dev, "%s:%d cb pitch (%d) for %d invalid (0x%08X)\n",
+ __func__, __LINE__, pitch, i, track->cb_color_size[i]);
+ return -EINVAL;
+ }
+ height = size / (pitch * bpe);
+ if (height > 8192)
+ height = 8192;
+ switch (G_0280A0_ARRAY_MODE(track->cb_color_info[i])) {
+ case V_0280A0_ARRAY_LINEAR_GENERAL:
+ case V_0280A0_ARRAY_LINEAR_ALIGNED:
+ if (pitch & 0x3f) {
+ dev_warn(p->dev, "%s:%d cb pitch (%d x %d = %d) invalid\n",
+ __func__, __LINE__, pitch, bpe, pitch * bpe);
+ return -EINVAL;
+ }
+ if ((pitch * bpe) & (track->group_size - 1)) {
+ dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ break;
+ case V_0280A0_ARRAY_1D_TILED_THIN1:
+ if ((pitch * 8 * bpe * track->nsamples) & (track->group_size - 1)) {
+ dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ height &= ~0x7;
+ if (!height)
+ height = 8;
+ break;
+ case V_0280A0_ARRAY_2D_TILED_THIN1:
+ if (pitch & ((8 * track->nbanks) - 1)) {
+ dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ tmp = pitch * 8 * bpe * track->nsamples;
+ tmp = tmp / track->nbanks;
+ if (tmp & (track->group_size - 1)) {
+ dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ height &= ~((16 * track->npipes) - 1);
+ if (!height)
+ height = 16 * track->npipes;
+ break;
+ default:
+ dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
+ G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i,
+ track->cb_color_info[i]);
+ return -EINVAL;
+ }
+ /* check offset */
+ tmp = height * pitch;
+ if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
+ dev_warn(p->dev, "%s offset[%d] %d to big\n", __func__, i, track->cb_color_bo_offset[i]);
+ return -EINVAL;
+ }
+ /* limit max tile */
+ tmp = (height * pitch) >> 6;
+ if (tmp < slice_tile_max)
+ slice_tile_max = tmp;
+ tmp = S_028060_PITCH_TILE_MAX((pitch >> 3) - 1) |
+ S_028060_SLICE_TILE_MAX(slice_tile_max - 1);
+ ib[track->cb_color_size_idx[i]] = tmp;
+ return 0;
+}
+
+static int r600_cs_track_check(struct radeon_cs_parser *p)
+{
+ struct r600_cs_track *track = p->track;
+ u32 tmp;
+ int r, i;
+ volatile u32 *ib = p->ib->ptr;
+
+ /* on legacy kernel we don't perform advanced check */
+ if (p->rdev == NULL)
+ return 0;
+ /* we don't support out buffer yet */
+ if (track->vgt_strmout_en || track->vgt_strmout_buffer_en) {
+ dev_warn(p->dev, "this kernel doesn't support SMX output buffer\n");
+ return -EINVAL;
+ }
+ /* check that we have a cb for each enabled target, we don't check
+ * shader_mask because it seems mesa isn't always setting it :(
+ */
+ tmp = track->cb_target_mask;
+ for (i = 0; i < 8; i++) {
+ if ((tmp >> (i * 4)) & 0xF) {
+ /* at least one component is enabled */
+ if (track->cb_color_bo[i] == NULL) {
+ dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
+ __func__, __LINE__, track->cb_target_mask, track->cb_shader_mask, i);
+ return -EINVAL;
+ }
+ /* perform rewrite of CB_COLOR[0-7]_SIZE */
+ r = r600_cs_track_validate_cb(p, i);
+ if (r)
+ return r;
+ }
+ }
+ /* Check depth buffer */
+ if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
+ G_028800_Z_ENABLE(track->db_depth_control)) {
+ u32 nviews, bpe, ntiles;
+ if (track->db_bo == NULL) {
+ dev_warn(p->dev, "z/stencil with no depth buffer\n");
+ return -EINVAL;
+ }
+ if (G_028010_TILE_SURFACE_ENABLE(track->db_depth_info)) {
+ dev_warn(p->dev, "this kernel doesn't support z/stencil htile\n");
+ return -EINVAL;
+ }
+ switch (G_028010_FORMAT(track->db_depth_info)) {
+ case V_028010_DEPTH_16:
+ bpe = 2;
+ break;
+ case V_028010_DEPTH_X8_24:
+ case V_028010_DEPTH_8_24:
+ case V_028010_DEPTH_X8_24_FLOAT:
+ case V_028010_DEPTH_8_24_FLOAT:
+ case V_028010_DEPTH_32_FLOAT:
+ bpe = 4;
+ break;
+ case V_028010_DEPTH_X24_8_32_FLOAT:
+ bpe = 8;
+ break;
+ default:
+ dev_warn(p->dev, "z/stencil with invalid format %d\n", G_028010_FORMAT(track->db_depth_info));
+ return -EINVAL;
+ }
+ if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) {
+ if (!track->db_depth_size_idx) {
+ dev_warn(p->dev, "z/stencil buffer size not set\n");
+ return -EINVAL;
+ }
+ printk_once(KERN_WARNING "You have old & broken userspace please consider updating mesa\n");
+ tmp = radeon_bo_size(track->db_bo) - track->db_offset;
+ tmp = (tmp / bpe) >> 6;
+ if (!tmp) {
+ dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %ld)\n",
+ track->db_depth_size, bpe, track->db_offset,
+ radeon_bo_size(track->db_bo));
+ return -EINVAL;
+ }
+ ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
+ } else {
+ ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
+ nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
+ tmp = ntiles * bpe * 64 * nviews;
+ if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
+ dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %d have %ld)\n",
+ track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
+ radeon_bo_size(track->db_bo));
+ return -EINVAL;
+ }
+ }
+ }
+ return 0;
+}
/**
* r600_cs_packet_parse() - parse cp packet and point ib index to next packet
@@ -177,6 +484,28 @@ static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p,
}
/**
+ * r600_cs_packet_next_is_pkt3_nop() - test if next packet is packet3 nop for reloc
+ * @parser: parser structure holding parsing context.
+ *
+ * Check next packet is relocation packet3, do bo validation and compute
+ * GPU offset using the provided start.
+ **/
+static inline int r600_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p)
+{
+ struct radeon_cs_packet p3reloc;
+ int r;
+
+ r = r600_cs_packet_parse(p, &p3reloc, p->idx);
+ if (r) {
+ return 0;
+ }
+ if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) {
+ return 0;
+ }
+ return 1;
+}
+
+/**
* r600_cs_packet_next_vline() - parse userspace VLINE packet
* @parser: parser structure holding parsing context.
*
@@ -333,10 +662,339 @@ static int r600_cs_parse_packet0(struct radeon_cs_parser *p,
return 0;
}
+/**
+ * r600_cs_check_reg() - check if register is authorized or not
+ * @parser: parser structure holding parsing context
+ * @reg: register we are testing
+ * @idx: index into the cs buffer
+ *
+ * This function will test against r600_reg_safe_bm and return 0
+ * if register is safe. If register is not flag as safe this function
+ * will test it against a list of register needind special handling.
+ */
+static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
+{
+ struct r600_cs_track *track = (struct r600_cs_track *)p->track;
+ struct radeon_cs_reloc *reloc;
+ u32 last_reg = ARRAY_SIZE(r600_reg_safe_bm);
+ u32 m, i, tmp, *ib;
+ int r;
+
+ i = (reg >> 7);
+ if (i > last_reg) {
+ dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
+ return -EINVAL;
+ }
+ m = 1 << ((reg >> 2) & 31);
+ if (!(r600_reg_safe_bm[i] & m))
+ return 0;
+ ib = p->ib->ptr;
+ switch (reg) {
+ /* force following reg to 0 in an attemp to disable out buffer
+ * which will need us to better understand how it works to perform
+ * security check on it (Jerome)
+ */
+ case R_0288A8_SQ_ESGS_RING_ITEMSIZE:
+ case R_008C44_SQ_ESGS_RING_SIZE:
+ case R_0288B0_SQ_ESTMP_RING_ITEMSIZE:
+ case R_008C54_SQ_ESTMP_RING_SIZE:
+ case R_0288C0_SQ_FBUF_RING_ITEMSIZE:
+ case R_008C74_SQ_FBUF_RING_SIZE:
+ case R_0288B4_SQ_GSTMP_RING_ITEMSIZE:
+ case R_008C5C_SQ_GSTMP_RING_SIZE:
+ case R_0288AC_SQ_GSVS_RING_ITEMSIZE:
+ case R_008C4C_SQ_GSVS_RING_SIZE:
+ case R_0288BC_SQ_PSTMP_RING_ITEMSIZE:
+ case R_008C6C_SQ_PSTMP_RING_SIZE:
+ case R_0288C4_SQ_REDUC_RING_ITEMSIZE:
+ case R_008C7C_SQ_REDUC_RING_SIZE:
+ case R_0288B8_SQ_VSTMP_RING_ITEMSIZE:
+ case R_008C64_SQ_VSTMP_RING_SIZE:
+ case R_0288C8_SQ_GS_VERT_ITEMSIZE:
+ /* get value to populate the IB don't remove */
+ tmp =radeon_get_ib_value(p, idx);
+ ib[idx] = 0;
+ break;
+ case R_028800_DB_DEPTH_CONTROL:
+ track->db_depth_control = radeon_get_ib_value(p, idx);
+ break;
+ case R_028010_DB_DEPTH_INFO:
+ track->db_depth_info = radeon_get_ib_value(p, idx);
+ break;
+ case R_028004_DB_DEPTH_VIEW:
+ track->db_depth_view = radeon_get_ib_value(p, idx);
+ break;
+ case R_028000_DB_DEPTH_SIZE:
+ track->db_depth_size = radeon_get_ib_value(p, idx);
+ track->db_depth_size_idx = idx;
+ break;
+ case R_028AB0_VGT_STRMOUT_EN:
+ track->vgt_strmout_en = radeon_get_ib_value(p, idx);
+ break;
+ case R_028B20_VGT_STRMOUT_BUFFER_EN:
+ track->vgt_strmout_buffer_en = radeon_get_ib_value(p, idx);
+ break;
+ case R_028238_CB_TARGET_MASK:
+ track->cb_target_mask = radeon_get_ib_value(p, idx);
+ break;
+ case R_02823C_CB_SHADER_MASK:
+ track->cb_shader_mask = radeon_get_ib_value(p, idx);
+ break;
+ case R_028C04_PA_SC_AA_CONFIG:
+ tmp = G_028C04_MSAA_NUM_SAMPLES(radeon_get_ib_value(p, idx));
+ track->nsamples = 1 << tmp;
+ break;
+ case R_0280A0_CB_COLOR0_INFO:
+ case R_0280A4_CB_COLOR1_INFO:
+ case R_0280A8_CB_COLOR2_INFO:
+ case R_0280AC_CB_COLOR3_INFO:
+ case R_0280B0_CB_COLOR4_INFO:
+ case R_0280B4_CB_COLOR5_INFO:
+ case R_0280B8_CB_COLOR6_INFO:
+ case R_0280BC_CB_COLOR7_INFO:
+ tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4;
+ track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
+ break;
+ case R_028060_CB_COLOR0_SIZE:
+ case R_028064_CB_COLOR1_SIZE:
+ case R_028068_CB_COLOR2_SIZE:
+ case R_02806C_CB_COLOR3_SIZE:
+ case R_028070_CB_COLOR4_SIZE:
+ case R_028074_CB_COLOR5_SIZE:
+ case R_028078_CB_COLOR6_SIZE:
+ case R_02807C_CB_COLOR7_SIZE:
+ tmp = (reg - R_028060_CB_COLOR0_SIZE) / 4;
+ track->cb_color_size[tmp] = radeon_get_ib_value(p, idx);
+ track->cb_color_size_idx[tmp] = idx;
+ break;
+ /* This register were added late, there is userspace
+ * which does provide relocation for those but set
+ * 0 offset. In order to avoid breaking old userspace
+ * we detect this and set address to point to last
+ * CB_COLOR0_BASE, note that if userspace doesn't set
+ * CB_COLOR0_BASE before this register we will report
+ * error. Old userspace always set CB_COLOR0_BASE
+ * before any of this.
+ */
+ case R_0280E0_CB_COLOR0_FRAG:
+ case R_0280E4_CB_COLOR1_FRAG:
+ case R_0280E8_CB_COLOR2_FRAG:
+ case R_0280EC_CB_COLOR3_FRAG:
+ case R_0280F0_CB_COLOR4_FRAG:
+ case R_0280F4_CB_COLOR5_FRAG:
+ case R_0280F8_CB_COLOR6_FRAG:
+ case R_0280FC_CB_COLOR7_FRAG:
+ tmp = (reg - R_0280E0_CB_COLOR0_FRAG) / 4;
+ if (!r600_cs_packet_next_is_pkt3_nop(p)) {
+ if (!track->cb_color_base_last[tmp]) {
+ dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg);
+ return -EINVAL;
+ }
+ ib[idx] = track->cb_color_base_last[tmp];
+ printk_once(KERN_WARNING "You have old & broken userspace "
+ "please consider updating mesa & xf86-video-ati\n");
+ track->cb_color_frag_bo[tmp] = track->cb_color_bo[tmp];
+ } else {
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
+ return -EINVAL;
+ }
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->cb_color_frag_bo[tmp] = reloc->robj;
+ }
+ break;
+ case R_0280C0_CB_COLOR0_TILE:
+ case R_0280C4_CB_COLOR1_TILE:
+ case R_0280C8_CB_COLOR2_TILE:
+ case R_0280CC_CB_COLOR3_TILE:
+ case R_0280D0_CB_COLOR4_TILE:
+ case R_0280D4_CB_COLOR5_TILE:
+ case R_0280D8_CB_COLOR6_TILE:
+ case R_0280DC_CB_COLOR7_TILE:
+ tmp = (reg - R_0280C0_CB_COLOR0_TILE) / 4;
+ if (!r600_cs_packet_next_is_pkt3_nop(p)) {
+ if (!track->cb_color_base_last[tmp]) {
+ dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg);
+ return -EINVAL;
+ }
+ ib[idx] = track->cb_color_base_last[tmp];
+ printk_once(KERN_WARNING "You have old & broken userspace "
+ "please consider updating mesa & xf86-video-ati\n");
+ track->cb_color_tile_bo[tmp] = track->cb_color_bo[tmp];
+ } else {
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
+ return -EINVAL;
+ }
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->cb_color_tile_bo[tmp] = reloc->robj;
+ }
+ break;
+ case CB_COLOR0_BASE:
+ case CB_COLOR1_BASE:
+ case CB_COLOR2_BASE:
+ case CB_COLOR3_BASE:
+ case CB_COLOR4_BASE:
+ case CB_COLOR5_BASE:
+ case CB_COLOR6_BASE:
+ case CB_COLOR7_BASE:
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ tmp = (reg - CB_COLOR0_BASE) / 4;
+ track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->cb_color_base_last[tmp] = ib[idx];
+ track->cb_color_bo[tmp] = reloc->robj;
+ break;
+ case DB_DEPTH_BASE:
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ track->db_offset = radeon_get_ib_value(p, idx);
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->db_bo = reloc->robj;
+ break;
+ case DB_HTILE_DATA_BASE:
+ case SQ_PGM_START_FS:
+ case SQ_PGM_START_ES:
+ case SQ_PGM_START_VS:
+ case SQ_PGM_START_GS:
+ case SQ_PGM_START_PS:
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ break;
+ default:
+ dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static inline unsigned minify(unsigned size, unsigned levels)
+{
+ size = size >> levels;
+ if (size < 1)
+ size = 1;
+ return size;
+}
+
+static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels,
+ unsigned w0, unsigned h0, unsigned d0, unsigned bpe,
+ unsigned *l0_size, unsigned *mipmap_size)
+{
+ unsigned offset, i, level, face;
+ unsigned width, height, depth, rowstride, size;
+
+ w0 = minify(w0, 0);
+ h0 = minify(h0, 0);
+ d0 = minify(d0, 0);
+ for(i = 0, offset = 0, level = blevel; i < nlevels; i++, level++) {
+ width = minify(w0, i);
+ height = minify(h0, i);
+ depth = minify(d0, i);
+ for(face = 0; face < nfaces; face++) {
+ rowstride = ((width * bpe) + 255) & ~255;
+ size = height * rowstride * depth;
+ offset += size;
+ offset = (offset + 0x1f) & ~0x1f;
+ }
+ }
+ *l0_size = (((w0 * bpe) + 255) & ~255) * h0 * d0;
+ *mipmap_size = offset;
+ if (!blevel)
+ *mipmap_size -= *l0_size;
+ if (!nlevels)
+ *mipmap_size = *l0_size;
+}
+
+/**
+ * r600_check_texture_resource() - check if register is authorized or not
+ * @p: parser structure holding parsing context
+ * @idx: index into the cs buffer
+ * @texture: texture's bo structure
+ * @mipmap: mipmap's bo structure
+ *
+ * This function will check that the resource has valid field and that
+ * the texture and mipmap bo object are big enough to cover this resource.
+ */
+static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
+ struct radeon_bo *texture,
+ struct radeon_bo *mipmap)
+{
+ u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0;
+ u32 word0, word1, l0_size, mipmap_size;
+
+ /* on legacy kernel we don't perform advanced check */
+ if (p->rdev == NULL)
+ return 0;
+ word0 = radeon_get_ib_value(p, idx + 0);
+ word1 = radeon_get_ib_value(p, idx + 1);
+ w0 = G_038000_TEX_WIDTH(word0) + 1;
+ h0 = G_038004_TEX_HEIGHT(word1) + 1;
+ d0 = G_038004_TEX_DEPTH(word1);
+ nfaces = 1;
+ switch (G_038000_DIM(word0)) {
+ case V_038000_SQ_TEX_DIM_1D:
+ case V_038000_SQ_TEX_DIM_2D:
+ case V_038000_SQ_TEX_DIM_3D:
+ break;
+ case V_038000_SQ_TEX_DIM_CUBEMAP:
+ nfaces = 6;
+ break;
+ case V_038000_SQ_TEX_DIM_1D_ARRAY:
+ case V_038000_SQ_TEX_DIM_2D_ARRAY:
+ case V_038000_SQ_TEX_DIM_2D_MSAA:
+ case V_038000_SQ_TEX_DIM_2D_ARRAY_MSAA:
+ default:
+ dev_warn(p->dev, "this kernel doesn't support %d texture dim\n", G_038000_DIM(word0));
+ return -EINVAL;
+ }
+ if (r600_bpe_from_format(&bpe, G_038004_DATA_FORMAT(word1))) {
+ dev_warn(p->dev, "%s:%d texture invalid format %d\n",
+ __func__, __LINE__, G_038004_DATA_FORMAT(word1));
+ return -EINVAL;
+ }
+ word0 = radeon_get_ib_value(p, idx + 4);
+ word1 = radeon_get_ib_value(p, idx + 5);
+ blevel = G_038010_BASE_LEVEL(word0);
+ nlevels = G_038014_LAST_LEVEL(word1);
+ r600_texture_size(nfaces, blevel, nlevels, w0, h0, d0, bpe, &l0_size, &mipmap_size);
+ /* using get ib will give us the offset into the texture bo */
+ word0 = radeon_get_ib_value(p, idx + 2);
+ if ((l0_size + word0) > radeon_bo_size(texture)) {
+ dev_warn(p->dev, "texture bo too small (%d %d %d %d -> %d have %ld)\n",
+ w0, h0, bpe, word0, l0_size, radeon_bo_size(texture));
+ return -EINVAL;
+ }
+ /* using get ib will give us the offset into the mipmap bo */
+ word0 = radeon_get_ib_value(p, idx + 3);
+ if ((mipmap_size + word0) > radeon_bo_size(mipmap)) {
+ dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n",
+ w0, h0, bpe, blevel, nlevels, word0, mipmap_size, radeon_bo_size(texture));
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int r600_packet3_check(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt)
{
struct radeon_cs_reloc *reloc;
+ struct r600_cs_track *track;
volatile u32 *ib;
unsigned idx;
unsigned i;
@@ -344,6 +1002,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
int r;
u32 idx_value;
+ track = (struct r600_cs_track *)p->track;
ib = p->ib->ptr;
idx = pkt->idx + 1;
idx_value = radeon_get_ib_value(p, idx);
@@ -380,12 +1039,22 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
}
ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ r = r600_cs_track_check(p);
+ if (r) {
+ dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
+ return r;
+ }
break;
case PACKET3_DRAW_INDEX_AUTO:
if (pkt->count != 1) {
DRM_ERROR("bad DRAW_INDEX_AUTO\n");
return -EINVAL;
}
+ r = r600_cs_track_check(p);
+ if (r) {
+ dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx);
+ return r;
+ }
break;
case PACKET3_DRAW_INDEX_IMMD_BE:
case PACKET3_DRAW_INDEX_IMMD:
@@ -393,6 +1062,11 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
DRM_ERROR("bad DRAW_INDEX_IMMD\n");
return -EINVAL;
}
+ r = r600_cs_track_check(p);
+ if (r) {
+ dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
+ return r;
+ }
break;
case PACKET3_WAIT_REG_MEM:
if (pkt->count != 5) {
@@ -465,30 +1139,9 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
}
for (i = 0; i < pkt->count; i++) {
reg = start_reg + (4 * i);
- switch (reg) {
- case SQ_ESGS_RING_BASE:
- case SQ_GSVS_RING_BASE:
- case SQ_ESTMP_RING_BASE:
- case SQ_GSTMP_RING_BASE:
- case SQ_VSTMP_RING_BASE:
- case SQ_PSTMP_RING_BASE:
- case SQ_FBUF_RING_BASE:
- case SQ_REDUC_RING_BASE:
- case SX_MEMORY_EXPORT_BASE:
- r = r600_cs_packet_next_reloc(p, &reloc);
- if (r) {
- DRM_ERROR("bad SET_CONFIG_REG "
- "0x%04X\n", reg);
- return -EINVAL;
- }
- ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
- break;
- case CP_COHER_BASE:
- /* use PACKET3_SURFACE_SYNC */
- return -EINVAL;
- default:
- break;
- }
+ r = r600_cs_check_reg(p, reg, idx+1+i);
+ if (r)
+ return r;
}
break;
case PACKET3_SET_CONTEXT_REG:
@@ -502,55 +1155,9 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
}
for (i = 0; i < pkt->count; i++) {
reg = start_reg + (4 * i);
- switch (reg) {
- case DB_DEPTH_BASE:
- case DB_HTILE_DATA_BASE:
- case CB_COLOR0_BASE:
- case CB_COLOR1_BASE:
- case CB_COLOR2_BASE:
- case CB_COLOR3_BASE:
- case CB_COLOR4_BASE:
- case CB_COLOR5_BASE:
- case CB_COLOR6_BASE:
- case CB_COLOR7_BASE:
- case SQ_PGM_START_FS:
- case SQ_PGM_START_ES:
- case SQ_PGM_START_VS:
- case SQ_PGM_START_GS:
- case SQ_PGM_START_PS:
- r = r600_cs_packet_next_reloc(p, &reloc);
- if (r) {
- DRM_ERROR("bad SET_CONTEXT_REG "
- "0x%04X\n", reg);
- return -EINVAL;
- }
- ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
- break;
- case VGT_DMA_BASE:
- case VGT_DMA_BASE_HI:
- /* These should be handled by DRAW_INDEX packet 3 */
- case VGT_STRMOUT_BASE_OFFSET_0:
- case VGT_STRMOUT_BASE_OFFSET_1:
- case VGT_STRMOUT_BASE_OFFSET_2:
- case VGT_STRMOUT_BASE_OFFSET_3:
- case VGT_STRMOUT_BASE_OFFSET_HI_0:
- case VGT_STRMOUT_BASE_OFFSET_HI_1:
- case VGT_STRMOUT_BASE_OFFSET_HI_2:
- case VGT_STRMOUT_BASE_OFFSET_HI_3:
- case VGT_STRMOUT_BUFFER_BASE_0:
- case VGT_STRMOUT_BUFFER_BASE_1:
- case VGT_STRMOUT_BUFFER_BASE_2:
- case VGT_STRMOUT_BUFFER_BASE_3:
- case VGT_STRMOUT_BUFFER_OFFSET_0:
- case VGT_STRMOUT_BUFFER_OFFSET_1:
- case VGT_STRMOUT_BUFFER_OFFSET_2:
- case VGT_STRMOUT_BUFFER_OFFSET_3:
- /* These should be handled by STRMOUT_BUFFER packet 3 */
- DRM_ERROR("bad context reg: 0x%08x\n", reg);
- return -EINVAL;
- default:
- break;
- }
+ r = r600_cs_check_reg(p, reg, idx+1+i);
+ if (r)
+ return r;
}
break;
case PACKET3_SET_RESOURCE:
@@ -567,6 +1174,9 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
return -EINVAL;
}
for (i = 0; i < (pkt->count / 7); i++) {
+ struct radeon_bo *texture, *mipmap;
+ u32 size, offset;
+
switch (G__SQ_VTX_CONSTANT_TYPE(radeon_get_ib_value(p, idx+(i*7)+6+1))) {
case SQ_TEX_VTX_VALID_TEXTURE:
/* tex base */
@@ -576,6 +1186,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
return -EINVAL;
}
ib[idx+1+(i*7)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ texture = reloc->robj;
/* tex mip base */
r = r600_cs_packet_next_reloc(p, &reloc);
if (r) {
@@ -583,6 +1194,11 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
return -EINVAL;
}
ib[idx+1+(i*7)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ mipmap = reloc->robj;
+ r = r600_check_texture_resource(p, idx+(i*7)+1,
+ texture, mipmap);
+ if (r)
+ return r;
break;
case SQ_TEX_VTX_VALID_BUFFER:
/* vtx base */
@@ -591,6 +1207,13 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
DRM_ERROR("bad SET_RESOURCE\n");
return -EINVAL;
}
+ offset = radeon_get_ib_value(p, idx+1+(i*7)+0);
+ size = radeon_get_ib_value(p, idx+1+(i*7)+1);
+ if (p->rdev && (size + offset) > radeon_bo_size(reloc->robj)) {
+ /* force size to size of the buffer */
+ dev_warn(p->dev, "vbo resource seems too big for the bo\n");
+ ib[idx+1+(i*7)+1] = radeon_bo_size(reloc->robj);
+ }
ib[idx+1+(i*7)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff);
ib[idx+1+(i*7)+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
break;
@@ -678,11 +1301,31 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
int r600_cs_parse(struct radeon_cs_parser *p)
{
struct radeon_cs_packet pkt;
+ struct r600_cs_track *track;
int r;
+ if (p->track == NULL) {
+ /* initialize tracker, we are in kms */
+ track = kzalloc(sizeof(*track), GFP_KERNEL);
+ if (track == NULL)
+ return -ENOMEM;
+ r600_cs_track_init(track);
+ if (p->rdev->family < CHIP_RV770) {
+ track->npipes = p->rdev->config.r600.tiling_npipes;
+ track->nbanks = p->rdev->config.r600.tiling_nbanks;
+ track->group_size = p->rdev->config.r600.tiling_group_size;
+ } else if (p->rdev->family <= CHIP_RV740) {
+ track->npipes = p->rdev->config.rv770.tiling_npipes;
+ track->nbanks = p->rdev->config.rv770.tiling_nbanks;
+ track->group_size = p->rdev->config.rv770.tiling_group_size;
+ }
+ p->track = track;
+ }
do {
r = r600_cs_packet_parse(p, &pkt, p->idx);
if (r) {
+ kfree(p->track);
+ p->track = NULL;
return r;
}
p->idx += pkt.count + 2;
@@ -697,9 +1340,13 @@ int r600_cs_parse(struct radeon_cs_parser *p)
break;
default:
DRM_ERROR("Unknown packet type %d !\n", pkt.type);
+ kfree(p->track);
+ p->track = NULL;
return -EINVAL;
}
if (r) {
+ kfree(p->track);
+ p->track = NULL;
return r;
}
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
@@ -709,6 +1356,8 @@ int r600_cs_parse(struct radeon_cs_parser *p)
mdelay(1);
}
#endif
+ kfree(p->track);
+ p->track = NULL;
return 0;
}
@@ -751,15 +1400,24 @@ int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp,
{
struct radeon_cs_parser parser;
struct radeon_cs_chunk *ib_chunk;
- struct radeon_ib fake_ib;
+ struct radeon_ib fake_ib;
+ struct r600_cs_track *track;
int r;
+ /* initialize tracker */
+ track = kzalloc(sizeof(*track), GFP_KERNEL);
+ if (track == NULL)
+ return -ENOMEM;
+ r600_cs_track_init(track);
+ r600_cs_legacy_get_tiling_conf(dev, &track->npipes, &track->nbanks, &track->group_size);
/* initialize parser */
memset(&parser, 0, sizeof(struct radeon_cs_parser));
parser.filp = filp;
+ parser.dev = &dev->pdev->dev;
parser.rdev = NULL;
parser.family = family;
parser.ib = &fake_ib;
+ parser.track = track;
fake_ib.ptr = ib;
r = radeon_cs_parser_init(&parser, data);
if (r) {
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 05894edadab4..5b2e4d442823 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -882,4 +882,494 @@
#define S_000E60_SOFT_RESET_VMC(x) (((x) & 1) << 17)
#define R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480
+
+#define R_028C04_PA_SC_AA_CONFIG 0x028C04
+#define S_028C04_MSAA_NUM_SAMPLES(x) (((x) & 0x3) << 0)
+#define G_028C04_MSAA_NUM_SAMPLES(x) (((x) >> 0) & 0x3)
+#define C_028C04_MSAA_NUM_SAMPLES 0xFFFFFFFC
+#define S_028C04_AA_MASK_CENTROID_DTMN(x) (((x) & 0x1) << 4)
+#define G_028C04_AA_MASK_CENTROID_DTMN(x) (((x) >> 4) & 0x1)
+#define C_028C04_AA_MASK_CENTROID_DTMN 0xFFFFFFEF
+#define S_028C04_MAX_SAMPLE_DIST(x) (((x) & 0xF) << 13)
+#define G_028C04_MAX_SAMPLE_DIST(x) (((x) >> 13) & 0xF)
+#define C_028C04_MAX_SAMPLE_DIST 0xFFFE1FFF
+#define R_0280E0_CB_COLOR0_FRAG 0x0280E0
+#define S_0280E0_BASE_256B(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_0280E0_BASE_256B(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_0280E0_BASE_256B 0x00000000
+#define R_0280E4_CB_COLOR1_FRAG 0x0280E4
+#define R_0280E8_CB_COLOR2_FRAG 0x0280E8
+#define R_0280EC_CB_COLOR3_FRAG 0x0280EC
+#define R_0280F0_CB_COLOR4_FRAG 0x0280F0
+#define R_0280F4_CB_COLOR5_FRAG 0x0280F4
+#define R_0280F8_CB_COLOR6_FRAG 0x0280F8
+#define R_0280FC_CB_COLOR7_FRAG 0x0280FC
+#define R_0280C0_CB_COLOR0_TILE 0x0280C0
+#define S_0280C0_BASE_256B(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_0280C0_BASE_256B(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_0280C0_BASE_256B 0x00000000
+#define R_0280C4_CB_COLOR1_TILE 0x0280C4
+#define R_0280C8_CB_COLOR2_TILE 0x0280C8
+#define R_0280CC_CB_COLOR3_TILE 0x0280CC
+#define R_0280D0_CB_COLOR4_TILE 0x0280D0
+#define R_0280D4_CB_COLOR5_TILE 0x0280D4
+#define R_0280D8_CB_COLOR6_TILE 0x0280D8
+#define R_0280DC_CB_COLOR7_TILE 0x0280DC
+#define R_0280A0_CB_COLOR0_INFO 0x0280A0
+#define S_0280A0_ENDIAN(x) (((x) & 0x3) << 0)
+#define G_0280A0_ENDIAN(x) (((x) >> 0) & 0x3)
+#define C_0280A0_ENDIAN 0xFFFFFFFC
+#define S_0280A0_FORMAT(x) (((x) & 0x3F) << 2)
+#define G_0280A0_FORMAT(x) (((x) >> 2) & 0x3F)
+#define C_0280A0_FORMAT 0xFFFFFF03
+#define V_0280A0_COLOR_INVALID 0x00000000
+#define V_0280A0_COLOR_8 0x00000001
+#define V_0280A0_COLOR_4_4 0x00000002
+#define V_0280A0_COLOR_3_3_2 0x00000003
+#define V_0280A0_COLOR_16 0x00000005
+#define V_0280A0_COLOR_16_FLOAT 0x00000006
+#define V_0280A0_COLOR_8_8 0x00000007
+#define V_0280A0_COLOR_5_6_5 0x00000008
+#define V_0280A0_COLOR_6_5_5 0x00000009
+#define V_0280A0_COLOR_1_5_5_5 0x0000000A
+#define V_0280A0_COLOR_4_4_4_4 0x0000000B
+#define V_0280A0_COLOR_5_5_5_1 0x0000000C
+#define V_0280A0_COLOR_32 0x0000000D
+#define V_0280A0_COLOR_32_FLOAT 0x0000000E
+#define V_0280A0_COLOR_16_16 0x0000000F
+#define V_0280A0_COLOR_16_16_FLOAT 0x00000010
+#define V_0280A0_COLOR_8_24 0x00000011
+#define V_0280A0_COLOR_8_24_FLOAT 0x00000012
+#define V_0280A0_COLOR_24_8 0x00000013
+#define V_0280A0_COLOR_24_8_FLOAT 0x00000014
+#define V_0280A0_COLOR_10_11_11 0x00000015
+#define V_0280A0_COLOR_10_11_11_FLOAT 0x00000016
+#define V_0280A0_COLOR_11_11_10 0x00000017
+#define V_0280A0_COLOR_11_11_10_FLOAT 0x00000018
+#define V_0280A0_COLOR_2_10_10_10 0x00000019
+#define V_0280A0_COLOR_8_8_8_8 0x0000001A
+#define V_0280A0_COLOR_10_10_10_2 0x0000001B
+#define V_0280A0_COLOR_X24_8_32_FLOAT 0x0000001C
+#define V_0280A0_COLOR_32_32 0x0000001D
+#define V_0280A0_COLOR_32_32_FLOAT 0x0000001E
+#define V_0280A0_COLOR_16_16_16_16 0x0000001F
+#define V_0280A0_COLOR_16_16_16_16_FLOAT 0x00000020
+#define V_0280A0_COLOR_32_32_32_32 0x00000022
+#define V_0280A0_COLOR_32_32_32_32_FLOAT 0x00000023
+#define S_0280A0_ARRAY_MODE(x) (((x) & 0xF) << 8)
+#define G_0280A0_ARRAY_MODE(x) (((x) >> 8) & 0xF)
+#define C_0280A0_ARRAY_MODE 0xFFFFF0FF
+#define V_0280A0_ARRAY_LINEAR_GENERAL 0x00000000
+#define V_0280A0_ARRAY_LINEAR_ALIGNED 0x00000001
+#define V_0280A0_ARRAY_1D_TILED_THIN1 0x00000002
+#define V_0280A0_ARRAY_2D_TILED_THIN1 0x00000004
+#define S_0280A0_NUMBER_TYPE(x) (((x) & 0x7) << 12)
+#define G_0280A0_NUMBER_TYPE(x) (((x) >> 12) & 0x7)
+#define C_0280A0_NUMBER_TYPE 0xFFFF8FFF
+#define S_0280A0_READ_SIZE(x) (((x) & 0x1) << 15)
+#define G_0280A0_READ_SIZE(x) (((x) >> 15) & 0x1)
+#define C_0280A0_READ_SIZE 0xFFFF7FFF
+#define S_0280A0_COMP_SWAP(x) (((x) & 0x3) << 16)
+#define G_0280A0_COMP_SWAP(x) (((x) >> 16) & 0x3)
+#define C_0280A0_COMP_SWAP 0xFFFCFFFF
+#define S_0280A0_TILE_MODE(x) (((x) & 0x3) << 18)
+#define G_0280A0_TILE_MODE(x) (((x) >> 18) & 0x3)
+#define C_0280A0_TILE_MODE 0xFFF3FFFF
+#define S_0280A0_BLEND_CLAMP(x) (((x) & 0x1) << 20)
+#define G_0280A0_BLEND_CLAMP(x) (((x) >> 20) & 0x1)
+#define C_0280A0_BLEND_CLAMP 0xFFEFFFFF
+#define S_0280A0_CLEAR_COLOR(x) (((x) & 0x1) << 21)
+#define G_0280A0_CLEAR_COLOR(x) (((x) >> 21) & 0x1)
+#define C_0280A0_CLEAR_COLOR 0xFFDFFFFF
+#define S_0280A0_BLEND_BYPASS(x) (((x) & 0x1) << 22)
+#define G_0280A0_BLEND_BYPASS(x) (((x) >> 22) & 0x1)
+#define C_0280A0_BLEND_BYPASS 0xFFBFFFFF
+#define S_0280A0_BLEND_FLOAT32(x) (((x) & 0x1) << 23)
+#define G_0280A0_BLEND_FLOAT32(x) (((x) >> 23) & 0x1)
+#define C_0280A0_BLEND_FLOAT32 0xFF7FFFFF
+#define S_0280A0_SIMPLE_FLOAT(x) (((x) & 0x1) << 24)
+#define G_0280A0_SIMPLE_FLOAT(x) (((x) >> 24) & 0x1)
+#define C_0280A0_SIMPLE_FLOAT 0xFEFFFFFF
+#define S_0280A0_ROUND_MODE(x) (((x) & 0x1) << 25)
+#define G_0280A0_ROUND_MODE(x) (((x) >> 25) & 0x1)
+#define C_0280A0_ROUND_MODE 0xFDFFFFFF
+#define S_0280A0_TILE_COMPACT(x) (((x) & 0x1) << 26)
+#define G_0280A0_TILE_COMPACT(x) (((x) >> 26) & 0x1)
+#define C_0280A0_TILE_COMPACT 0xFBFFFFFF
+#define S_0280A0_SOURCE_FORMAT(x) (((x) & 0x1) << 27)
+#define G_0280A0_SOURCE_FORMAT(x) (((x) >> 27) & 0x1)
+#define C_0280A0_SOURCE_FORMAT 0xF7FFFFFF
+#define R_0280A4_CB_COLOR1_INFO 0x0280A4
+#define R_0280A8_CB_COLOR2_INFO 0x0280A8
+#define R_0280AC_CB_COLOR3_INFO 0x0280AC
+#define R_0280B0_CB_COLOR4_INFO 0x0280B0
+#define R_0280B4_CB_COLOR5_INFO 0x0280B4
+#define R_0280B8_CB_COLOR6_INFO 0x0280B8
+#define R_0280BC_CB_COLOR7_INFO 0x0280BC
+#define R_028060_CB_COLOR0_SIZE 0x028060
+#define S_028060_PITCH_TILE_MAX(x) (((x) & 0x3FF) << 0)
+#define G_028060_PITCH_TILE_MAX(x) (((x) >> 0) & 0x3FF)
+#define C_028060_PITCH_TILE_MAX 0xFFFFFC00
+#define S_028060_SLICE_TILE_MAX(x) (((x) & 0xFFFFF) << 10)
+#define G_028060_SLICE_TILE_MAX(x) (((x) >> 10) & 0xFFFFF)
+#define C_028060_SLICE_TILE_MAX 0xC00003FF
+#define R_028064_CB_COLOR1_SIZE 0x028064
+#define R_028068_CB_COLOR2_SIZE 0x028068
+#define R_02806C_CB_COLOR3_SIZE 0x02806C
+#define R_028070_CB_COLOR4_SIZE 0x028070
+#define R_028074_CB_COLOR5_SIZE 0x028074
+#define R_028078_CB_COLOR6_SIZE 0x028078
+#define R_02807C_CB_COLOR7_SIZE 0x02807C
+#define R_028238_CB_TARGET_MASK 0x028238
+#define S_028238_TARGET0_ENABLE(x) (((x) & 0xF) << 0)
+#define G_028238_TARGET0_ENABLE(x) (((x) >> 0) & 0xF)
+#define C_028238_TARGET0_ENABLE 0xFFFFFFF0
+#define S_028238_TARGET1_ENABLE(x) (((x) & 0xF) << 4)
+#define G_028238_TARGET1_ENABLE(x) (((x) >> 4) & 0xF)
+#define C_028238_TARGET1_ENABLE 0xFFFFFF0F
+#define S_028238_TARGET2_ENABLE(x) (((x) & 0xF) << 8)
+#define G_028238_TARGET2_ENABLE(x) (((x) >> 8) & 0xF)
+#define C_028238_TARGET2_ENABLE 0xFFFFF0FF
+#define S_028238_TARGET3_ENABLE(x) (((x) & 0xF) << 12)
+#define G_028238_TARGET3_ENABLE(x) (((x) >> 12) & 0xF)
+#define C_028238_TARGET3_ENABLE 0xFFFF0FFF
+#define S_028238_TARGET4_ENABLE(x) (((x) & 0xF) << 16)
+#define G_028238_TARGET4_ENABLE(x) (((x) >> 16) & 0xF)
+#define C_028238_TARGET4_ENABLE 0xFFF0FFFF
+#define S_028238_TARGET5_ENABLE(x) (((x) & 0xF) << 20)
+#define G_028238_TARGET5_ENABLE(x) (((x) >> 20) & 0xF)
+#define C_028238_TARGET5_ENABLE 0xFF0FFFFF
+#define S_028238_TARGET6_ENABLE(x) (((x) & 0xF) << 24)
+#define G_028238_TARGET6_ENABLE(x) (((x) >> 24) & 0xF)
+#define C_028238_TARGET6_ENABLE 0xF0FFFFFF
+#define S_028238_TARGET7_ENABLE(x) (((x) & 0xF) << 28)
+#define G_028238_TARGET7_ENABLE(x) (((x) >> 28) & 0xF)
+#define C_028238_TARGET7_ENABLE 0x0FFFFFFF
+#define R_02823C_CB_SHADER_MASK 0x02823C
+#define S_02823C_OUTPUT0_ENABLE(x) (((x) & 0xF) << 0)
+#define G_02823C_OUTPUT0_ENABLE(x) (((x) >> 0) & 0xF)
+#define C_02823C_OUTPUT0_ENABLE 0xFFFFFFF0
+#define S_02823C_OUTPUT1_ENABLE(x) (((x) & 0xF) << 4)
+#define G_02823C_OUTPUT1_ENABLE(x) (((x) >> 4) & 0xF)
+#define C_02823C_OUTPUT1_ENABLE 0xFFFFFF0F
+#define S_02823C_OUTPUT2_ENABLE(x) (((x) & 0xF) << 8)
+#define G_02823C_OUTPUT2_ENABLE(x) (((x) >> 8) & 0xF)
+#define C_02823C_OUTPUT2_ENABLE 0xFFFFF0FF
+#define S_02823C_OUTPUT3_ENABLE(x) (((x) & 0xF) << 12)
+#define G_02823C_OUTPUT3_ENABLE(x) (((x) >> 12) & 0xF)
+#define C_02823C_OUTPUT3_ENABLE 0xFFFF0FFF
+#define S_02823C_OUTPUT4_ENABLE(x) (((x) & 0xF) << 16)
+#define G_02823C_OUTPUT4_ENABLE(x) (((x) >> 16) & 0xF)
+#define C_02823C_OUTPUT4_ENABLE 0xFFF0FFFF
+#define S_02823C_OUTPUT5_ENABLE(x) (((x) & 0xF) << 20)
+#define G_02823C_OUTPUT5_ENABLE(x) (((x) >> 20) & 0xF)
+#define C_02823C_OUTPUT5_ENABLE 0xFF0FFFFF
+#define S_02823C_OUTPUT6_ENABLE(x) (((x) & 0xF) << 24)
+#define G_02823C_OUTPUT6_ENABLE(x) (((x) >> 24) & 0xF)
+#define C_02823C_OUTPUT6_ENABLE 0xF0FFFFFF
+#define S_02823C_OUTPUT7_ENABLE(x) (((x) & 0xF) << 28)
+#define G_02823C_OUTPUT7_ENABLE(x) (((x) >> 28) & 0xF)
+#define C_02823C_OUTPUT7_ENABLE 0x0FFFFFFF
+#define R_028AB0_VGT_STRMOUT_EN 0x028AB0
+#define S_028AB0_STREAMOUT(x) (((x) & 0x1) << 0)
+#define G_028AB0_STREAMOUT(x) (((x) >> 0) & 0x1)
+#define C_028AB0_STREAMOUT 0xFFFFFFFE
+#define R_028B20_VGT_STRMOUT_BUFFER_EN 0x028B20
+#define S_028B20_BUFFER_0_EN(x) (((x) & 0x1) << 0)
+#define G_028B20_BUFFER_0_EN(x) (((x) >> 0) & 0x1)
+#define C_028B20_BUFFER_0_EN 0xFFFFFFFE
+#define S_028B20_BUFFER_1_EN(x) (((x) & 0x1) << 1)
+#define G_028B20_BUFFER_1_EN(x) (((x) >> 1) & 0x1)
+#define C_028B20_BUFFER_1_EN 0xFFFFFFFD
+#define S_028B20_BUFFER_2_EN(x) (((x) & 0x1) << 2)
+#define G_028B20_BUFFER_2_EN(x) (((x) >> 2) & 0x1)
+#define C_028B20_BUFFER_2_EN 0xFFFFFFFB
+#define S_028B20_BUFFER_3_EN(x) (((x) & 0x1) << 3)
+#define G_028B20_BUFFER_3_EN(x) (((x) >> 3) & 0x1)
+#define C_028B20_BUFFER_3_EN 0xFFFFFFF7
+#define S_028B20_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_028B20_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_028B20_SIZE 0x00000000
+#define R_038000_SQ_TEX_RESOURCE_WORD0_0 0x038000
+#define S_038000_DIM(x) (((x) & 0x7) << 0)
+#define G_038000_DIM(x) (((x) >> 0) & 0x7)
+#define C_038000_DIM 0xFFFFFFF8
+#define V_038000_SQ_TEX_DIM_1D 0x00000000
+#define V_038000_SQ_TEX_DIM_2D 0x00000001
+#define V_038000_SQ_TEX_DIM_3D 0x00000002
+#define V_038000_SQ_TEX_DIM_CUBEMAP 0x00000003
+#define V_038000_SQ_TEX_DIM_1D_ARRAY 0x00000004
+#define V_038000_SQ_TEX_DIM_2D_ARRAY 0x00000005
+#define V_038000_SQ_TEX_DIM_2D_MSAA 0x00000006
+#define V_038000_SQ_TEX_DIM_2D_ARRAY_MSAA 0x00000007
+#define S_038000_TILE_MODE(x) (((x) & 0xF) << 3)
+#define G_038000_TILE_MODE(x) (((x) >> 3) & 0xF)
+#define C_038000_TILE_MODE 0xFFFFFF87
+#define S_038000_TILE_TYPE(x) (((x) & 0x1) << 7)
+#define G_038000_TILE_TYPE(x) (((x) >> 7) & 0x1)
+#define C_038000_TILE_TYPE 0xFFFFFF7F
+#define S_038000_PITCH(x) (((x) & 0x7FF) << 8)
+#define G_038000_PITCH(x) (((x) >> 8) & 0x7FF)
+#define C_038000_PITCH 0xFFF800FF
+#define S_038000_TEX_WIDTH(x) (((x) & 0x1FFF) << 19)
+#define G_038000_TEX_WIDTH(x) (((x) >> 19) & 0x1FFF)
+#define C_038000_TEX_WIDTH 0x0007FFFF
+#define R_038004_SQ_TEX_RESOURCE_WORD1_0 0x038004
+#define S_038004_TEX_HEIGHT(x) (((x) & 0x1FFF) << 0)
+#define G_038004_TEX_HEIGHT(x) (((x) >> 0) & 0x1FFF)
+#define C_038004_TEX_HEIGHT 0xFFFFE000
+#define S_038004_TEX_DEPTH(x) (((x) & 0x1FFF) << 13)
+#define G_038004_TEX_DEPTH(x) (((x) >> 13) & 0x1FFF)
+#define C_038004_TEX_DEPTH 0xFC001FFF
+#define S_038004_DATA_FORMAT(x) (((x) & 0x3F) << 26)
+#define G_038004_DATA_FORMAT(x) (((x) >> 26) & 0x3F)
+#define C_038004_DATA_FORMAT 0x03FFFFFF
+#define V_038004_COLOR_INVALID 0x00000000
+#define V_038004_COLOR_8 0x00000001
+#define V_038004_COLOR_4_4 0x00000002
+#define V_038004_COLOR_3_3_2 0x00000003
+#define V_038004_COLOR_16 0x00000005
+#define V_038004_COLOR_16_FLOAT 0x00000006
+#define V_038004_COLOR_8_8 0x00000007
+#define V_038004_COLOR_5_6_5 0x00000008
+#define V_038004_COLOR_6_5_5 0x00000009
+#define V_038004_COLOR_1_5_5_5 0x0000000A
+#define V_038004_COLOR_4_4_4_4 0x0000000B
+#define V_038004_COLOR_5_5_5_1 0x0000000C
+#define V_038004_COLOR_32 0x0000000D
+#define V_038004_COLOR_32_FLOAT 0x0000000E
+#define V_038004_COLOR_16_16 0x0000000F
+#define V_038004_COLOR_16_16_FLOAT 0x00000010
+#define V_038004_COLOR_8_24 0x00000011
+#define V_038004_COLOR_8_24_FLOAT 0x00000012
+#define V_038004_COLOR_24_8 0x00000013
+#define V_038004_COLOR_24_8_FLOAT 0x00000014
+#define V_038004_COLOR_10_11_11 0x00000015
+#define V_038004_COLOR_10_11_11_FLOAT 0x00000016
+#define V_038004_COLOR_11_11_10 0x00000017
+#define V_038004_COLOR_11_11_10_FLOAT 0x00000018
+#define V_038004_COLOR_2_10_10_10 0x00000019
+#define V_038004_COLOR_8_8_8_8 0x0000001A
+#define V_038004_COLOR_10_10_10_2 0x0000001B
+#define V_038004_COLOR_X24_8_32_FLOAT 0x0000001C
+#define V_038004_COLOR_32_32 0x0000001D
+#define V_038004_COLOR_32_32_FLOAT 0x0000001E
+#define V_038004_COLOR_16_16_16_16 0x0000001F
+#define V_038004_COLOR_16_16_16_16_FLOAT 0x00000020
+#define V_038004_COLOR_32_32_32_32 0x00000022
+#define V_038004_COLOR_32_32_32_32_FLOAT 0x00000023
+#define V_038004_FMT_1 0x00000025
+#define V_038004_FMT_GB_GR 0x00000027
+#define V_038004_FMT_BG_RG 0x00000028
+#define V_038004_FMT_32_AS_8 0x00000029
+#define V_038004_FMT_32_AS_8_8 0x0000002A
+#define V_038004_FMT_5_9_9_9_SHAREDEXP 0x0000002B
+#define V_038004_FMT_8_8_8 0x0000002C
+#define V_038004_FMT_16_16_16 0x0000002D
+#define V_038004_FMT_16_16_16_FLOAT 0x0000002E
+#define V_038004_FMT_32_32_32 0x0000002F
+#define V_038004_FMT_32_32_32_FLOAT 0x00000030
+#define R_038010_SQ_TEX_RESOURCE_WORD4_0 0x038010
+#define S_038010_FORMAT_COMP_X(x) (((x) & 0x3) << 0)
+#define G_038010_FORMAT_COMP_X(x) (((x) >> 0) & 0x3)
+#define C_038010_FORMAT_COMP_X 0xFFFFFFFC
+#define S_038010_FORMAT_COMP_Y(x) (((x) & 0x3) << 2)
+#define G_038010_FORMAT_COMP_Y(x) (((x) >> 2) & 0x3)
+#define C_038010_FORMAT_COMP_Y 0xFFFFFFF3
+#define S_038010_FORMAT_COMP_Z(x) (((x) & 0x3) << 4)
+#define G_038010_FORMAT_COMP_Z(x) (((x) >> 4) & 0x3)
+#define C_038010_FORMAT_COMP_Z 0xFFFFFFCF
+#define S_038010_FORMAT_COMP_W(x) (((x) & 0x3) << 6)
+#define G_038010_FORMAT_COMP_W(x) (((x) >> 6) & 0x3)
+#define C_038010_FORMAT_COMP_W 0xFFFFFF3F
+#define S_038010_NUM_FORMAT_ALL(x) (((x) & 0x3) << 8)
+#define G_038010_NUM_FORMAT_ALL(x) (((x) >> 8) & 0x3)
+#define C_038010_NUM_FORMAT_ALL 0xFFFFFCFF
+#define S_038010_SRF_MODE_ALL(x) (((x) & 0x1) << 10)
+#define G_038010_SRF_MODE_ALL(x) (((x) >> 10) & 0x1)
+#define C_038010_SRF_MODE_ALL 0xFFFFFBFF
+#define S_038010_FORCE_DEGAMMA(x) (((x) & 0x1) << 11)
+#define G_038010_FORCE_DEGAMMA(x) (((x) >> 11) & 0x1)
+#define C_038010_FORCE_DEGAMMA 0xFFFFF7FF
+#define S_038010_ENDIAN_SWAP(x) (((x) & 0x3) << 12)
+#define G_038010_ENDIAN_SWAP(x) (((x) >> 12) & 0x3)
+#define C_038010_ENDIAN_SWAP 0xFFFFCFFF
+#define S_038010_REQUEST_SIZE(x) (((x) & 0x3) << 14)
+#define G_038010_REQUEST_SIZE(x) (((x) >> 14) & 0x3)
+#define C_038010_REQUEST_SIZE 0xFFFF3FFF
+#define S_038010_DST_SEL_X(x) (((x) & 0x7) << 16)
+#define G_038010_DST_SEL_X(x) (((x) >> 16) & 0x7)
+#define C_038010_DST_SEL_X 0xFFF8FFFF
+#define S_038010_DST_SEL_Y(x) (((x) & 0x7) << 19)
+#define G_038010_DST_SEL_Y(x) (((x) >> 19) & 0x7)
+#define C_038010_DST_SEL_Y 0xFFC7FFFF
+#define S_038010_DST_SEL_Z(x) (((x) & 0x7) << 22)
+#define G_038010_DST_SEL_Z(x) (((x) >> 22) & 0x7)
+#define C_038010_DST_SEL_Z 0xFE3FFFFF
+#define S_038010_DST_SEL_W(x) (((x) & 0x7) << 25)
+#define G_038010_DST_SEL_W(x) (((x) >> 25) & 0x7)
+#define C_038010_DST_SEL_W 0xF1FFFFFF
+#define S_038010_BASE_LEVEL(x) (((x) & 0xF) << 28)
+#define G_038010_BASE_LEVEL(x) (((x) >> 28) & 0xF)
+#define C_038010_BASE_LEVEL 0x0FFFFFFF
+#define R_038014_SQ_TEX_RESOURCE_WORD5_0 0x038014
+#define S_038014_LAST_LEVEL(x) (((x) & 0xF) << 0)
+#define G_038014_LAST_LEVEL(x) (((x) >> 0) & 0xF)
+#define C_038014_LAST_LEVEL 0xFFFFFFF0
+#define S_038014_BASE_ARRAY(x) (((x) & 0x1FFF) << 4)
+#define G_038014_BASE_ARRAY(x) (((x) >> 4) & 0x1FFF)
+#define C_038014_BASE_ARRAY 0xFFFE000F
+#define S_038014_LAST_ARRAY(x) (((x) & 0x1FFF) << 17)
+#define G_038014_LAST_ARRAY(x) (((x) >> 17) & 0x1FFF)
+#define C_038014_LAST_ARRAY 0xC001FFFF
+#define R_0288A8_SQ_ESGS_RING_ITEMSIZE 0x0288A8
+#define S_0288A8_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
+#define G_0288A8_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
+#define C_0288A8_ITEMSIZE 0xFFFF8000
+#define R_008C44_SQ_ESGS_RING_SIZE 0x008C44
+#define S_008C44_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_008C44_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_008C44_MEM_SIZE 0x00000000
+#define R_0288B0_SQ_ESTMP_RING_ITEMSIZE 0x0288B0
+#define S_0288B0_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
+#define G_0288B0_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
+#define C_0288B0_ITEMSIZE 0xFFFF8000
+#define R_008C54_SQ_ESTMP_RING_SIZE 0x008C54
+#define S_008C54_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_008C54_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_008C54_MEM_SIZE 0x00000000
+#define R_0288C0_SQ_FBUF_RING_ITEMSIZE 0x0288C0
+#define S_0288C0_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
+#define G_0288C0_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
+#define C_0288C0_ITEMSIZE 0xFFFF8000
+#define R_008C74_SQ_FBUF_RING_SIZE 0x008C74
+#define S_008C74_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_008C74_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_008C74_MEM_SIZE 0x00000000
+#define R_0288B4_SQ_GSTMP_RING_ITEMSIZE 0x0288B4
+#define S_0288B4_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
+#define G_0288B4_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
+#define C_0288B4_ITEMSIZE 0xFFFF8000
+#define R_008C5C_SQ_GSTMP_RING_SIZE 0x008C5C
+#define S_008C5C_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_008C5C_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_008C5C_MEM_SIZE 0x00000000
+#define R_0288AC_SQ_GSVS_RING_ITEMSIZE 0x0288AC
+#define S_0288AC_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
+#define G_0288AC_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
+#define C_0288AC_ITEMSIZE 0xFFFF8000
+#define R_008C4C_SQ_GSVS_RING_SIZE 0x008C4C
+#define S_008C4C_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_008C4C_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_008C4C_MEM_SIZE 0x00000000
+#define R_0288BC_SQ_PSTMP_RING_ITEMSIZE 0x0288BC
+#define S_0288BC_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
+#define G_0288BC_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
+#define C_0288BC_ITEMSIZE 0xFFFF8000
+#define R_008C6C_SQ_PSTMP_RING_SIZE 0x008C6C
+#define S_008C6C_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_008C6C_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_008C6C_MEM_SIZE 0x00000000
+#define R_0288C4_SQ_REDUC_RING_ITEMSIZE 0x0288C4
+#define S_0288C4_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
+#define G_0288C4_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
+#define C_0288C4_ITEMSIZE 0xFFFF8000
+#define R_008C7C_SQ_REDUC_RING_SIZE 0x008C7C
+#define S_008C7C_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_008C7C_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_008C7C_MEM_SIZE 0x00000000
+#define R_0288B8_SQ_VSTMP_RING_ITEMSIZE 0x0288B8
+#define S_0288B8_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
+#define G_0288B8_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
+#define C_0288B8_ITEMSIZE 0xFFFF8000
+#define R_008C64_SQ_VSTMP_RING_SIZE 0x008C64
+#define S_008C64_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_008C64_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_008C64_MEM_SIZE 0x00000000
+#define R_0288C8_SQ_GS_VERT_ITEMSIZE 0x0288C8
+#define S_0288C8_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
+#define G_0288C8_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
+#define C_0288C8_ITEMSIZE 0xFFFF8000
+#define R_028010_DB_DEPTH_INFO 0x028010
+#define S_028010_FORMAT(x) (((x) & 0x7) << 0)
+#define G_028010_FORMAT(x) (((x) >> 0) & 0x7)
+#define C_028010_FORMAT 0xFFFFFFF8
+#define V_028010_DEPTH_INVALID 0x00000000
+#define V_028010_DEPTH_16 0x00000001
+#define V_028010_DEPTH_X8_24 0x00000002
+#define V_028010_DEPTH_8_24 0x00000003
+#define V_028010_DEPTH_X8_24_FLOAT 0x00000004
+#define V_028010_DEPTH_8_24_FLOAT 0x00000005
+#define V_028010_DEPTH_32_FLOAT 0x00000006
+#define V_028010_DEPTH_X24_8_32_FLOAT 0x00000007
+#define S_028010_READ_SIZE(x) (((x) & 0x1) << 3)
+#define G_028010_READ_SIZE(x) (((x) >> 3) & 0x1)
+#define C_028010_READ_SIZE 0xFFFFFFF7
+#define S_028010_ARRAY_MODE(x) (((x) & 0xF) << 15)
+#define G_028010_ARRAY_MODE(x) (((x) >> 15) & 0xF)
+#define C_028010_ARRAY_MODE 0xFFF87FFF
+#define S_028010_TILE_SURFACE_ENABLE(x) (((x) & 0x1) << 25)
+#define G_028010_TILE_SURFACE_ENABLE(x) (((x) >> 25) & 0x1)
+#define C_028010_TILE_SURFACE_ENABLE 0xFDFFFFFF
+#define S_028010_TILE_COMPACT(x) (((x) & 0x1) << 26)
+#define G_028010_TILE_COMPACT(x) (((x) >> 26) & 0x1)
+#define C_028010_TILE_COMPACT 0xFBFFFFFF
+#define S_028010_ZRANGE_PRECISION(x) (((x) & 0x1) << 31)
+#define G_028010_ZRANGE_PRECISION(x) (((x) >> 31) & 0x1)
+#define C_028010_ZRANGE_PRECISION 0x7FFFFFFF
+#define R_028000_DB_DEPTH_SIZE 0x028000
+#define S_028000_PITCH_TILE_MAX(x) (((x) & 0x3FF) << 0)
+#define G_028000_PITCH_TILE_MAX(x) (((x) >> 0) & 0x3FF)
+#define C_028000_PITCH_TILE_MAX 0xFFFFFC00
+#define S_028000_SLICE_TILE_MAX(x) (((x) & 0xFFFFF) << 10)
+#define G_028000_SLICE_TILE_MAX(x) (((x) >> 10) & 0xFFFFF)
+#define C_028000_SLICE_TILE_MAX 0xC00003FF
+#define R_028004_DB_DEPTH_VIEW 0x028004
+#define S_028004_SLICE_START(x) (((x) & 0x7FF) << 0)
+#define G_028004_SLICE_START(x) (((x) >> 0) & 0x7FF)
+#define C_028004_SLICE_START 0xFFFFF800
+#define S_028004_SLICE_MAX(x) (((x) & 0x7FF) << 13)
+#define G_028004_SLICE_MAX(x) (((x) >> 13) & 0x7FF)
+#define C_028004_SLICE_MAX 0xFF001FFF
+#define R_028800_DB_DEPTH_CONTROL 0x028800
+#define S_028800_STENCIL_ENABLE(x) (((x) & 0x1) << 0)
+#define G_028800_STENCIL_ENABLE(x) (((x) >> 0) & 0x1)
+#define C_028800_STENCIL_ENABLE 0xFFFFFFFE
+#define S_028800_Z_ENABLE(x) (((x) & 0x1) << 1)
+#define G_028800_Z_ENABLE(x) (((x) >> 1) & 0x1)
+#define C_028800_Z_ENABLE 0xFFFFFFFD
+#define S_028800_Z_WRITE_ENABLE(x) (((x) & 0x1) << 2)
+#define G_028800_Z_WRITE_ENABLE(x) (((x) >> 2) & 0x1)
+#define C_028800_Z_WRITE_ENABLE 0xFFFFFFFB
+#define S_028800_ZFUNC(x) (((x) & 0x7) << 4)
+#define G_028800_ZFUNC(x) (((x) >> 4) & 0x7)
+#define C_028800_ZFUNC 0xFFFFFF8F
+#define S_028800_BACKFACE_ENABLE(x) (((x) & 0x1) << 7)
+#define G_028800_BACKFACE_ENABLE(x) (((x) >> 7) & 0x1)
+#define C_028800_BACKFACE_ENABLE 0xFFFFFF7F
+#define S_028800_STENCILFUNC(x) (((x) & 0x7) << 8)
+#define G_028800_STENCILFUNC(x) (((x) >> 8) & 0x7)
+#define C_028800_STENCILFUNC 0xFFFFF8FF
+#define S_028800_STENCILFAIL(x) (((x) & 0x7) << 11)
+#define G_028800_STENCILFAIL(x) (((x) >> 11) & 0x7)
+#define C_028800_STENCILFAIL 0xFFFFC7FF
+#define S_028800_STENCILZPASS(x) (((x) & 0x7) << 14)
+#define G_028800_STENCILZPASS(x) (((x) >> 14) & 0x7)
+#define C_028800_STENCILZPASS 0xFFFE3FFF
+#define S_028800_STENCILZFAIL(x) (((x) & 0x7) << 17)
+#define G_028800_STENCILZFAIL(x) (((x) >> 17) & 0x7)
+#define C_028800_STENCILZFAIL 0xFFF1FFFF
+#define S_028800_STENCILFUNC_BF(x) (((x) & 0x7) << 20)
+#define G_028800_STENCILFUNC_BF(x) (((x) >> 20) & 0x7)
+#define C_028800_STENCILFUNC_BF 0xFF8FFFFF
+#define S_028800_STENCILFAIL_BF(x) (((x) & 0x7) << 23)
+#define G_028800_STENCILFAIL_BF(x) (((x) >> 23) & 0x7)
+#define C_028800_STENCILFAIL_BF 0xFC7FFFFF
+#define S_028800_STENCILZPASS_BF(x) (((x) & 0x7) << 26)
+#define G_028800_STENCILZPASS_BF(x) (((x) >> 26) & 0x7)
+#define C_028800_STENCILZPASS_BF 0xE3FFFFFF
+#define S_028800_STENCILZFAIL_BF(x) (((x) & 0x7) << 29)
+#define G_028800_STENCILZFAIL_BF(x) (((x) >> 29) & 0x7)
+#define C_028800_STENCILZFAIL_BF 0x1FFFFFFF
+
#endif
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index eb5f99b9469d..829e26e8a4bb 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -89,6 +89,7 @@ extern int radeon_testing;
extern int radeon_connector_table;
extern int radeon_tv;
extern int radeon_new_pll;
+extern int radeon_dynpm;
extern int radeon_audio;
/*
@@ -96,6 +97,7 @@ extern int radeon_audio;
* symbol;
*/
#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */
+/* RADEON_IB_POOL_SIZE must be a power of 2 */
#define RADEON_IB_POOL_SIZE 16
#define RADEON_DEBUGFS_MAX_NUM_FILES 32
#define RADEONFB_CONN_LIMIT 4
@@ -117,6 +119,21 @@ struct radeon_device;
/*
* BIOS.
*/
+#define ATRM_BIOS_PAGE 4096
+
+#if defined(CONFIG_VGA_SWITCHEROO)
+bool radeon_atrm_supported(struct pci_dev *pdev);
+int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len);
+#else
+static inline bool radeon_atrm_supported(struct pci_dev *pdev)
+{
+ return false;
+}
+
+static inline int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len){
+ return -EINVAL;
+}
+#endif
bool radeon_get_bios(struct radeon_device *rdev);
@@ -137,17 +154,23 @@ void radeon_dummy_page_fini(struct radeon_device *rdev);
struct radeon_clock {
struct radeon_pll p1pll;
struct radeon_pll p2pll;
+ struct radeon_pll dcpll;
struct radeon_pll spll;
struct radeon_pll mpll;
/* 10 Khz units */
uint32_t default_mclk;
uint32_t default_sclk;
+ uint32_t default_dispclk;
+ uint32_t dp_extclk;
};
/*
* Power management
*/
int radeon_pm_init(struct radeon_device *rdev);
+void radeon_pm_compute_clocks(struct radeon_device *rdev);
+void radeon_combios_get_power_modes(struct radeon_device *rdev);
+void radeon_atombios_get_power_modes(struct radeon_device *rdev);
/*
* Fences.
@@ -274,6 +297,7 @@ union radeon_gart_table {
};
#define RADEON_GPU_PAGE_SIZE 4096
+#define RADEON_GPU_PAGE_MASK (RADEON_GPU_PAGE_SIZE - 1)
struct radeon_gart {
dma_addr_t table_addr;
@@ -308,21 +332,19 @@ struct radeon_mc {
/* for some chips with <= 32MB we need to lie
* about vram size near mc fb location */
u64 mc_vram_size;
- u64 gtt_location;
+ u64 visible_vram_size;
u64 gtt_size;
u64 gtt_start;
u64 gtt_end;
- u64 vram_location;
u64 vram_start;
u64 vram_end;
unsigned vram_width;
u64 real_vram_size;
int vram_mtrr;
bool vram_is_ddr;
- bool igp_sideport_enabled;
+ bool igp_sideport_enabled;
};
-int radeon_mc_setup(struct radeon_device *rdev);
bool radeon_combios_sideport_present(struct radeon_device *rdev);
bool radeon_atombios_sideport_present(struct radeon_device *rdev);
@@ -347,6 +369,7 @@ struct radeon_irq {
bool sw_int;
/* FIXME: use a define max crtc rather than hardcode it */
bool crtc_vblank_int[2];
+ wait_queue_head_t vblank_queue;
/* FIXME: use defines for max hpd/dacs */
bool hpd[6];
spinlock_t sw_lock;
@@ -363,11 +386,12 @@ void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev);
*/
struct radeon_ib {
struct list_head list;
- unsigned long idx;
+ unsigned idx;
uint64_t gpu_addr;
struct radeon_fence *fence;
- uint32_t *ptr;
+ uint32_t *ptr;
uint32_t length_dw;
+ bool free;
};
/*
@@ -377,10 +401,10 @@ struct radeon_ib {
struct radeon_ib_pool {
struct mutex mutex;
struct radeon_bo *robj;
- struct list_head scheduled_ibs;
+ struct list_head bogus_ib;
struct radeon_ib ibs[RADEON_IB_POOL_SIZE];
bool ready;
- DECLARE_BITMAP(alloc_bm, RADEON_IB_POOL_SIZE);
+ unsigned head_id;
};
struct radeon_cp {
@@ -410,13 +434,13 @@ struct r600_ih {
unsigned wptr_old;
unsigned ring_size;
uint64_t gpu_addr;
- uint32_t align_mask;
uint32_t ptr_mask;
spinlock_t lock;
bool enabled;
};
struct r600_blit {
+ struct mutex mutex;
struct radeon_bo *shader_obj;
u64 shader_gpu_addr;
u32 vs_offset, ps_offset;
@@ -432,6 +456,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib);
int radeon_ib_pool_init(struct radeon_device *rdev);
void radeon_ib_pool_fini(struct radeon_device *rdev);
int radeon_ib_test(struct radeon_device *rdev);
+extern void radeon_ib_bogus_add(struct radeon_device *rdev, struct radeon_ib *ib);
/* Ring access between begin & end cannot sleep */
void radeon_ring_free_size(struct radeon_device *rdev);
int radeon_ring_lock(struct radeon_device *rdev, unsigned ndw);
@@ -465,6 +490,7 @@ struct radeon_cs_chunk {
};
struct radeon_cs_parser {
+ struct device *dev;
struct radeon_device *rdev;
struct drm_file *filp;
/* chunks */
@@ -568,7 +594,99 @@ struct radeon_wb {
* Equation between gpu/memory clock and available bandwidth is hw dependent
* (type of memory, bus size, efficiency, ...)
*/
+enum radeon_pm_state {
+ PM_STATE_DISABLED,
+ PM_STATE_MINIMUM,
+ PM_STATE_PAUSED,
+ PM_STATE_ACTIVE
+};
+enum radeon_pm_action {
+ PM_ACTION_NONE,
+ PM_ACTION_MINIMUM,
+ PM_ACTION_DOWNCLOCK,
+ PM_ACTION_UPCLOCK
+};
+
+enum radeon_voltage_type {
+ VOLTAGE_NONE = 0,
+ VOLTAGE_GPIO,
+ VOLTAGE_VDDC,
+ VOLTAGE_SW
+};
+
+enum radeon_pm_state_type {
+ POWER_STATE_TYPE_DEFAULT,
+ POWER_STATE_TYPE_POWERSAVE,
+ POWER_STATE_TYPE_BATTERY,
+ POWER_STATE_TYPE_BALANCED,
+ POWER_STATE_TYPE_PERFORMANCE,
+};
+
+enum radeon_pm_clock_mode_type {
+ POWER_MODE_TYPE_DEFAULT,
+ POWER_MODE_TYPE_LOW,
+ POWER_MODE_TYPE_MID,
+ POWER_MODE_TYPE_HIGH,
+};
+
+struct radeon_voltage {
+ enum radeon_voltage_type type;
+ /* gpio voltage */
+ struct radeon_gpio_rec gpio;
+ u32 delay; /* delay in usec from voltage drop to sclk change */
+ bool active_high; /* voltage drop is active when bit is high */
+ /* VDDC voltage */
+ u8 vddc_id; /* index into vddc voltage table */
+ u8 vddci_id; /* index into vddci voltage table */
+ bool vddci_enabled;
+ /* r6xx+ sw */
+ u32 voltage;
+};
+
+struct radeon_pm_non_clock_info {
+ /* pcie lanes */
+ int pcie_lanes;
+ /* standardized non-clock flags */
+ u32 flags;
+};
+
+struct radeon_pm_clock_info {
+ /* memory clock */
+ u32 mclk;
+ /* engine clock */
+ u32 sclk;
+ /* voltage info */
+ struct radeon_voltage voltage;
+ /* standardized clock flags - not sure we'll need these */
+ u32 flags;
+};
+
+struct radeon_power_state {
+ enum radeon_pm_state_type type;
+ /* XXX: use a define for num clock modes */
+ struct radeon_pm_clock_info clock_info[8];
+ /* number of valid clock modes in this power state */
+ int num_clock_modes;
+ struct radeon_pm_clock_info *default_clock_mode;
+ /* non clock info about this state */
+ struct radeon_pm_non_clock_info non_clock_info;
+ bool voltage_drop_active;
+};
+
+/*
+ * Some modes are overclocked by very low value, accept them
+ */
+#define RADEON_MODE_OVERCLOCK_MARGIN 500 /* 5 MHz */
+
struct radeon_pm {
+ struct mutex mutex;
+ struct delayed_work idle_work;
+ enum radeon_pm_state state;
+ enum radeon_pm_action planned_action;
+ unsigned long action_timeout;
+ bool downclocked;
+ int active_crtcs;
+ int req_vblank;
fixed20_12 max_bandwidth;
fixed20_12 igp_sideport_mclk;
fixed20_12 igp_system_mclk;
@@ -580,6 +698,15 @@ struct radeon_pm {
fixed20_12 core_bandwidth;
fixed20_12 sclk;
fixed20_12 needed_bandwidth;
+ /* XXX: use a define for num power modes */
+ struct radeon_power_state power_state[8];
+ /* number of valid power states */
+ int num_power_states;
+ struct radeon_power_state *current_power_state;
+ struct radeon_pm_clock_info *current_clock_mode;
+ struct radeon_power_state *requested_power_state;
+ struct radeon_pm_clock_info *requested_clock_mode;
+ struct radeon_power_state *default_power_state;
};
@@ -649,6 +776,7 @@ struct radeon_asic {
void (*set_engine_clock)(struct radeon_device *rdev, uint32_t eng_clock);
uint32_t (*get_memory_clock)(struct radeon_device *rdev);
void (*set_memory_clock)(struct radeon_device *rdev, uint32_t mem_clock);
+ int (*get_pcie_lanes)(struct radeon_device *rdev);
void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);
void (*set_clock_gating)(struct radeon_device *rdev, int enable);
int (*set_surface_reg)(struct radeon_device *rdev, int reg,
@@ -660,6 +788,13 @@ struct radeon_asic {
void (*hpd_fini)(struct radeon_device *rdev);
bool (*hpd_sense)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
void (*hpd_set_polarity)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
+ /* ioctl hw specific callback. Some hw might want to perform special
+ * operation on specific ioctl. For instance on wait idle some hw
+ * might want to perform and HDP flush through MMIO as it seems that
+ * some R6XX/R7XX hw doesn't take HDP flush into account if programmed
+ * through ring.
+ */
+ void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo);
};
/*
@@ -692,6 +827,9 @@ struct r600_asic {
unsigned sx_max_export_pos_size;
unsigned sx_max_export_smx_size;
unsigned sq_num_cf_insts;
+ unsigned tiling_nbanks;
+ unsigned tiling_npipes;
+ unsigned tiling_group_size;
};
struct rv770_asic {
@@ -712,6 +850,9 @@ struct rv770_asic {
unsigned sc_prim_fifo_size;
unsigned sc_hiz_tile_fifo_size;
unsigned sc_earlyz_tile_fifo_fize;
+ unsigned tiling_nbanks;
+ unsigned tiling_npipes;
+ unsigned tiling_group_size;
};
union radeon_asic_config {
@@ -821,6 +962,8 @@ struct radeon_device {
struct r600_ih ih; /* r6/700 interrupt ring */
struct workqueue_struct *wq;
struct work_struct hotplug_work;
+ int num_crtc; /* number of crtcs */
+ struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
/* audio stuff */
struct timer_list audio_timer;
@@ -829,6 +972,8 @@ struct radeon_device {
int audio_bits_per_sample;
uint8_t audio_status_bits;
uint8_t audio_category_code;
+
+ bool powered_down;
};
int radeon_device_init(struct radeon_device *rdev,
@@ -847,7 +992,7 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
static inline uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg)
{
- if (reg < 0x10000)
+ if (reg < rdev->rmmio_size)
return readl(((void __iomem *)rdev->rmmio) + reg);
else {
writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX);
@@ -857,7 +1002,7 @@ static inline uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg)
static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
{
- if (reg < 0x10000)
+ if (reg < rdev->rmmio_size)
writel(v, ((void __iomem *)rdev->rmmio) + reg);
else {
writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX);
@@ -886,6 +1031,8 @@ static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32
#define WREG32_MC(reg, v) rdev->mc_wreg(rdev, (reg), (v))
#define RREG32_PCIE(reg) rv370_pcie_rreg(rdev, (reg))
#define WREG32_PCIE(reg, v) rv370_pcie_wreg(rdev, (reg), (v))
+#define RREG32_PCIE_P(reg) rdev->pciep_rreg(rdev, (reg))
+#define WREG32_PCIE_P(reg, v) rdev->pciep_wreg(rdev, (reg), (v))
#define WREG32_P(reg, val, mask) \
do { \
uint32_t tmp_ = RREG32(reg); \
@@ -947,7 +1094,7 @@ void r100_pll_errata_after_index(struct radeon_device *rdev);
#define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600))
#define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620))
#define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730))
-
+#define ASIC_IS_DCE4(rdev) ((rdev->family >= CHIP_CEDAR))
/*
* BIOS helpers.
@@ -1006,6 +1153,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
#define radeon_set_engine_clock(rdev, e) (rdev)->asic->set_engine_clock((rdev), (e))
#define radeon_get_memory_clock(rdev) (rdev)->asic->get_memory_clock((rdev))
#define radeon_set_memory_clock(rdev, e) (rdev)->asic->set_memory_clock((rdev), (e))
+#define radeon_get_pcie_lanes(rdev) (rdev)->asic->get_pcie_lanes((rdev))
#define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->set_pcie_lanes((rdev), (l))
#define radeon_set_clock_gating(rdev, e) (rdev)->asic->set_clock_gating((rdev), (e))
#define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->set_surface_reg((rdev), (r), (f), (p), (o), (s)))
@@ -1017,7 +1165,10 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
#define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd))
/* Common functions */
+/* AGP */
+extern void radeon_agp_disable(struct radeon_device *rdev);
extern int radeon_gart_table_vram_pin(struct radeon_device *rdev);
+extern void radeon_gart_restore(struct radeon_device *rdev);
extern int radeon_modeset_init(struct radeon_device *rdev);
extern void radeon_modeset_fini(struct radeon_device *rdev);
extern bool radeon_card_posted(struct radeon_device *rdev);
@@ -1031,6 +1182,10 @@ extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enabl
extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain);
extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);
+extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base);
+extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
+extern int radeon_resume_kms(struct drm_device *dev);
+extern int radeon_suspend_kms(struct drm_device *dev, pm_message_t state);
/* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */
struct r100_mc_save {
@@ -1085,7 +1240,7 @@ extern void r200_set_safe_registers(struct radeon_device *rdev);
/* r300,r350,rv350,rv370,rv380 */
extern void r300_set_reg_safe(struct radeon_device *rdev);
extern void r300_mc_program(struct radeon_device *rdev);
-extern void r300_vram_info(struct radeon_device *rdev);
+extern void r300_mc_init(struct radeon_device *rdev);
extern void r300_clock_startup(struct radeon_device *rdev);
extern int r300_mc_wait_for_idle(struct radeon_device *rdev);
extern int rv370_pcie_gart_init(struct radeon_device *rdev);
@@ -1094,7 +1249,6 @@ extern int rv370_pcie_gart_enable(struct radeon_device *rdev);
extern void rv370_pcie_gart_disable(struct radeon_device *rdev);
/* r420,r423,rv410 */
-extern int r420_mc_init(struct radeon_device *rdev);
extern u32 r420_mc_rreg(struct radeon_device *rdev, u32 reg);
extern void r420_mc_wreg(struct radeon_device *rdev, u32 reg, u32 v);
extern int r420_debugfs_pipes_info_init(struct radeon_device *rdev);
@@ -1136,12 +1290,13 @@ extern void rs690_line_buffer_adjust(struct radeon_device *rdev,
struct drm_display_mode *mode2);
/* r600, rv610, rv630, rv620, rv635, rv670, rs780, rs880 */
+extern void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
extern bool r600_card_posted(struct radeon_device *rdev);
extern void r600_cp_stop(struct radeon_device *rdev);
extern void r600_ring_init(struct radeon_device *rdev, unsigned ring_size);
extern int r600_cp_resume(struct radeon_device *rdev);
+extern void r600_cp_fini(struct radeon_device *rdev);
extern int r600_count_pipe_bits(uint32_t val);
-extern int r600_gart_clear_page(struct radeon_device *rdev, int i);
extern int r600_mc_wait_for_idle(struct radeon_device *rdev);
extern int r600_pcie_gart_init(struct radeon_device *rdev);
extern void r600_pcie_gart_tlb_flush(struct radeon_device *rdev);
@@ -1160,7 +1315,8 @@ extern int r600_irq_init(struct radeon_device *rdev);
extern void r600_irq_fini(struct radeon_device *rdev);
extern void r600_ih_ring_init(struct radeon_device *rdev, unsigned ring_size);
extern int r600_irq_set(struct radeon_device *rdev);
-
+extern void r600_irq_suspend(struct radeon_device *rdev);
+/* r600 audio */
extern int r600_audio_init(struct radeon_device *rdev);
extern int r600_audio_tmds_index(struct drm_encoder *encoder);
extern void r600_audio_set_clock(struct drm_encoder *encoder, int clock);
@@ -1176,6 +1332,14 @@ extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder,
uint8_t status_bits,
uint8_t category_code);
+/* evergreen */
+struct evergreen_mc_save {
+ u32 vga_control[6];
+ u32 vga_render_control;
+ u32 vga_hdp_control;
+ u32 crtc_control[6];
+};
+
#include "radeon_object.h"
#endif
diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c
index 220f454ea9fa..c4457791dff1 100644
--- a/drivers/gpu/drm/radeon/radeon_agp.c
+++ b/drivers/gpu/drm/radeon/radeon_agp.c
@@ -144,9 +144,19 @@ int radeon_agp_init(struct radeon_device *rdev)
ret = drm_agp_info(rdev->ddev, &info);
if (ret) {
+ drm_agp_release(rdev->ddev);
DRM_ERROR("Unable to get AGP info: %d\n", ret);
return ret;
}
+
+ if (rdev->ddev->agp->agp_info.aper_size < 32) {
+ drm_agp_release(rdev->ddev);
+ dev_warn(rdev->dev, "AGP aperture too small (%zuM) "
+ "need at least 32M, disabling AGP\n",
+ rdev->ddev->agp->agp_info.aper_size);
+ return -EINVAL;
+ }
+
mode.mode = info.mode;
agp_status = (RREG32(RADEON_AGP_STATUS) | RADEON_AGPv3_MODE) & mode.mode;
is_v3 = !!(agp_status & RADEON_AGPv3_MODE);
@@ -221,11 +231,16 @@ int radeon_agp_init(struct radeon_device *rdev)
ret = drm_agp_enable(rdev->ddev, mode);
if (ret) {
DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode);
+ drm_agp_release(rdev->ddev);
return ret;
}
rdev->mc.agp_base = rdev->ddev->agp->agp_info.aper_base;
rdev->mc.gtt_size = rdev->ddev->agp->agp_info.aper_size << 20;
+ rdev->mc.gtt_start = rdev->mc.agp_base;
+ rdev->mc.gtt_end = rdev->mc.gtt_start + rdev->mc.gtt_size - 1;
+ dev_info(rdev->dev, "GTT: %lluM 0x%08llX - 0x%08llX\n",
+ rdev->mc.gtt_size >> 20, rdev->mc.gtt_start, rdev->mc.gtt_end);
/* workaround some hw issues */
if (rdev->family < CHIP_R200) {
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index f2fbd2e4e9df..d3a157b2bcb7 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -43,7 +43,7 @@ void radeon_atom_set_memory_clock(struct radeon_device *rdev, uint32_t mem_clock
void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
/*
- * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280
+ * r100,rv100,rs100,rv200,rs200
*/
extern int r100_init(struct radeon_device *rdev);
extern void r100_fini(struct radeon_device *rdev);
@@ -108,6 +108,7 @@ static struct radeon_asic r100_asic = {
.set_engine_clock = &radeon_legacy_set_engine_clock,
.get_memory_clock = &radeon_legacy_get_memory_clock,
.set_memory_clock = NULL,
+ .get_pcie_lanes = NULL,
.set_pcie_lanes = NULL,
.set_clock_gating = &radeon_legacy_set_clock_gating,
.set_surface_reg = r100_set_surface_reg,
@@ -117,6 +118,52 @@ static struct radeon_asic r100_asic = {
.hpd_fini = &r100_hpd_fini,
.hpd_sense = &r100_hpd_sense,
.hpd_set_polarity = &r100_hpd_set_polarity,
+ .ioctl_wait_idle = NULL,
+};
+
+/*
+ * r200,rv250,rs300,rv280
+ */
+extern int r200_copy_dma(struct radeon_device *rdev,
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ unsigned num_pages,
+ struct radeon_fence *fence);
+static struct radeon_asic r200_asic = {
+ .init = &r100_init,
+ .fini = &r100_fini,
+ .suspend = &r100_suspend,
+ .resume = &r100_resume,
+ .vga_set_state = &r100_vga_set_state,
+ .gpu_reset = &r100_gpu_reset,
+ .gart_tlb_flush = &r100_pci_gart_tlb_flush,
+ .gart_set_page = &r100_pci_gart_set_page,
+ .cp_commit = &r100_cp_commit,
+ .ring_start = &r100_ring_start,
+ .ring_test = &r100_ring_test,
+ .ring_ib_execute = &r100_ring_ib_execute,
+ .irq_set = &r100_irq_set,
+ .irq_process = &r100_irq_process,
+ .get_vblank_counter = &r100_get_vblank_counter,
+ .fence_ring_emit = &r100_fence_ring_emit,
+ .cs_parse = &r100_cs_parse,
+ .copy_blit = &r100_copy_blit,
+ .copy_dma = &r200_copy_dma,
+ .copy = &r100_copy_blit,
+ .get_engine_clock = &radeon_legacy_get_engine_clock,
+ .set_engine_clock = &radeon_legacy_set_engine_clock,
+ .get_memory_clock = &radeon_legacy_get_memory_clock,
+ .set_memory_clock = NULL,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = &radeon_legacy_set_clock_gating,
+ .set_surface_reg = r100_set_surface_reg,
+ .clear_surface_reg = r100_clear_surface_reg,
+ .bandwidth_update = &r100_bandwidth_update,
+ .hpd_init = &r100_hpd_init,
+ .hpd_fini = &r100_hpd_fini,
+ .hpd_sense = &r100_hpd_sense,
+ .hpd_set_polarity = &r100_hpd_set_polarity,
+ .ioctl_wait_idle = NULL,
};
@@ -137,11 +184,8 @@ extern int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t
extern uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg);
extern void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes);
-extern int r300_copy_dma(struct radeon_device *rdev,
- uint64_t src_offset,
- uint64_t dst_offset,
- unsigned num_pages,
- struct radeon_fence *fence);
+extern int rv370_get_pcie_lanes(struct radeon_device *rdev);
+
static struct radeon_asic r300_asic = {
.init = &r300_init,
.fini = &r300_fini,
@@ -161,12 +205,13 @@ static struct radeon_asic r300_asic = {
.fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
- .copy_dma = &r300_copy_dma,
+ .copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit,
.get_engine_clock = &radeon_legacy_get_engine_clock,
.set_engine_clock = &radeon_legacy_set_engine_clock,
.get_memory_clock = &radeon_legacy_get_memory_clock,
.set_memory_clock = NULL,
+ .get_pcie_lanes = &rv370_get_pcie_lanes,
.set_pcie_lanes = &rv370_set_pcie_lanes,
.set_clock_gating = &radeon_legacy_set_clock_gating,
.set_surface_reg = r100_set_surface_reg,
@@ -176,6 +221,45 @@ static struct radeon_asic r300_asic = {
.hpd_fini = &r100_hpd_fini,
.hpd_sense = &r100_hpd_sense,
.hpd_set_polarity = &r100_hpd_set_polarity,
+ .ioctl_wait_idle = NULL,
+};
+
+
+static struct radeon_asic r300_asic_pcie = {
+ .init = &r300_init,
+ .fini = &r300_fini,
+ .suspend = &r300_suspend,
+ .resume = &r300_resume,
+ .vga_set_state = &r100_vga_set_state,
+ .gpu_reset = &r300_gpu_reset,
+ .gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
+ .gart_set_page = &rv370_pcie_gart_set_page,
+ .cp_commit = &r100_cp_commit,
+ .ring_start = &r300_ring_start,
+ .ring_test = &r100_ring_test,
+ .ring_ib_execute = &r100_ring_ib_execute,
+ .irq_set = &r100_irq_set,
+ .irq_process = &r100_irq_process,
+ .get_vblank_counter = &r100_get_vblank_counter,
+ .fence_ring_emit = &r300_fence_ring_emit,
+ .cs_parse = &r300_cs_parse,
+ .copy_blit = &r100_copy_blit,
+ .copy_dma = &r200_copy_dma,
+ .copy = &r100_copy_blit,
+ .get_engine_clock = &radeon_legacy_get_engine_clock,
+ .set_engine_clock = &radeon_legacy_set_engine_clock,
+ .get_memory_clock = &radeon_legacy_get_memory_clock,
+ .set_memory_clock = NULL,
+ .set_pcie_lanes = &rv370_set_pcie_lanes,
+ .set_clock_gating = &radeon_legacy_set_clock_gating,
+ .set_surface_reg = r100_set_surface_reg,
+ .clear_surface_reg = r100_clear_surface_reg,
+ .bandwidth_update = &r100_bandwidth_update,
+ .hpd_init = &r100_hpd_init,
+ .hpd_fini = &r100_hpd_fini,
+ .hpd_sense = &r100_hpd_sense,
+ .hpd_set_polarity = &r100_hpd_set_polarity,
+ .ioctl_wait_idle = NULL,
};
/*
@@ -204,12 +288,13 @@ static struct radeon_asic r420_asic = {
.fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
- .copy_dma = &r300_copy_dma,
+ .copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit,
.get_engine_clock = &radeon_atom_get_engine_clock,
.set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = &rv370_get_pcie_lanes,
.set_pcie_lanes = &rv370_set_pcie_lanes,
.set_clock_gating = &radeon_atom_set_clock_gating,
.set_surface_reg = r100_set_surface_reg,
@@ -219,6 +304,7 @@ static struct radeon_asic r420_asic = {
.hpd_fini = &r100_hpd_fini,
.hpd_sense = &r100_hpd_sense,
.hpd_set_polarity = &r100_hpd_set_polarity,
+ .ioctl_wait_idle = NULL,
};
@@ -252,12 +338,13 @@ static struct radeon_asic rs400_asic = {
.fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
- .copy_dma = &r300_copy_dma,
+ .copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit,
.get_engine_clock = &radeon_legacy_get_engine_clock,
.set_engine_clock = &radeon_legacy_set_engine_clock,
.get_memory_clock = &radeon_legacy_get_memory_clock,
.set_memory_clock = NULL,
+ .get_pcie_lanes = NULL,
.set_pcie_lanes = NULL,
.set_clock_gating = &radeon_legacy_set_clock_gating,
.set_surface_reg = r100_set_surface_reg,
@@ -267,6 +354,7 @@ static struct radeon_asic rs400_asic = {
.hpd_fini = &r100_hpd_fini,
.hpd_sense = &r100_hpd_sense,
.hpd_set_polarity = &r100_hpd_set_polarity,
+ .ioctl_wait_idle = NULL,
};
@@ -310,19 +398,23 @@ static struct radeon_asic rs600_asic = {
.fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
- .copy_dma = &r300_copy_dma,
+ .copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit,
.get_engine_clock = &radeon_atom_get_engine_clock,
.set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = NULL,
.set_pcie_lanes = NULL,
.set_clock_gating = &radeon_atom_set_clock_gating,
+ .set_surface_reg = r100_set_surface_reg,
+ .clear_surface_reg = r100_clear_surface_reg,
.bandwidth_update = &rs600_bandwidth_update,
.hpd_init = &rs600_hpd_init,
.hpd_fini = &rs600_hpd_fini,
.hpd_sense = &rs600_hpd_sense,
.hpd_set_polarity = &rs600_hpd_set_polarity,
+ .ioctl_wait_idle = NULL,
};
@@ -355,12 +447,13 @@ static struct radeon_asic rs690_asic = {
.fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
- .copy_dma = &r300_copy_dma,
- .copy = &r300_copy_dma,
+ .copy_dma = &r200_copy_dma,
+ .copy = &r200_copy_dma,
.get_engine_clock = &radeon_atom_get_engine_clock,
.set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = NULL,
.set_pcie_lanes = NULL,
.set_clock_gating = &radeon_atom_set_clock_gating,
.set_surface_reg = r100_set_surface_reg,
@@ -370,6 +463,7 @@ static struct radeon_asic rs690_asic = {
.hpd_fini = &rs600_hpd_fini,
.hpd_sense = &rs600_hpd_sense,
.hpd_set_polarity = &rs600_hpd_set_polarity,
+ .ioctl_wait_idle = NULL,
};
@@ -406,12 +500,13 @@ static struct radeon_asic rv515_asic = {
.fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
- .copy_dma = &r300_copy_dma,
+ .copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit,
.get_engine_clock = &radeon_atom_get_engine_clock,
.set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = &rv370_get_pcie_lanes,
.set_pcie_lanes = &rv370_set_pcie_lanes,
.set_clock_gating = &radeon_atom_set_clock_gating,
.set_surface_reg = r100_set_surface_reg,
@@ -421,6 +516,7 @@ static struct radeon_asic rv515_asic = {
.hpd_fini = &rs600_hpd_fini,
.hpd_sense = &rs600_hpd_sense,
.hpd_set_polarity = &rs600_hpd_set_polarity,
+ .ioctl_wait_idle = NULL,
};
@@ -448,12 +544,13 @@ static struct radeon_asic r520_asic = {
.fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
- .copy_dma = &r300_copy_dma,
+ .copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit,
.get_engine_clock = &radeon_atom_get_engine_clock,
.set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = &rv370_get_pcie_lanes,
.set_pcie_lanes = &rv370_set_pcie_lanes,
.set_clock_gating = &radeon_atom_set_clock_gating,
.set_surface_reg = r100_set_surface_reg,
@@ -463,6 +560,7 @@ static struct radeon_asic r520_asic = {
.hpd_fini = &rs600_hpd_fini,
.hpd_sense = &rs600_hpd_sense,
.hpd_set_polarity = &rs600_hpd_set_polarity,
+ .ioctl_wait_idle = NULL,
};
/*
@@ -504,6 +602,7 @@ void r600_hpd_fini(struct radeon_device *rdev);
bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
void r600_hpd_set_polarity(struct radeon_device *rdev,
enum radeon_hpd_id hpd);
+extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo);
static struct radeon_asic r600_asic = {
.init = &r600_init,
@@ -529,8 +628,9 @@ static struct radeon_asic r600_asic = {
.set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = &rv370_get_pcie_lanes,
.set_pcie_lanes = NULL,
- .set_clock_gating = &radeon_atom_set_clock_gating,
+ .set_clock_gating = NULL,
.set_surface_reg = r600_set_surface_reg,
.clear_surface_reg = r600_clear_surface_reg,
.bandwidth_update = &rv515_bandwidth_update,
@@ -538,6 +638,7 @@ static struct radeon_asic r600_asic = {
.hpd_fini = &r600_hpd_fini,
.hpd_sense = &r600_hpd_sense,
.hpd_set_polarity = &r600_hpd_set_polarity,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
};
/*
@@ -573,6 +674,7 @@ static struct radeon_asic rv770_asic = {
.set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = &rv370_get_pcie_lanes,
.set_pcie_lanes = NULL,
.set_clock_gating = &radeon_atom_set_clock_gating,
.set_surface_reg = r600_set_surface_reg,
@@ -582,6 +684,57 @@ static struct radeon_asic rv770_asic = {
.hpd_fini = &r600_hpd_fini,
.hpd_sense = &r600_hpd_sense,
.hpd_set_polarity = &r600_hpd_set_polarity,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
+};
+
+/*
+ * evergreen
+ */
+int evergreen_init(struct radeon_device *rdev);
+void evergreen_fini(struct radeon_device *rdev);
+int evergreen_suspend(struct radeon_device *rdev);
+int evergreen_resume(struct radeon_device *rdev);
+int evergreen_gpu_reset(struct radeon_device *rdev);
+void evergreen_bandwidth_update(struct radeon_device *rdev);
+void evergreen_hpd_init(struct radeon_device *rdev);
+void evergreen_hpd_fini(struct radeon_device *rdev);
+bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
+void evergreen_hpd_set_polarity(struct radeon_device *rdev,
+ enum radeon_hpd_id hpd);
+
+static struct radeon_asic evergreen_asic = {
+ .init = &evergreen_init,
+ .fini = &evergreen_fini,
+ .suspend = &evergreen_suspend,
+ .resume = &evergreen_resume,
+ .cp_commit = NULL,
+ .gpu_reset = &evergreen_gpu_reset,
+ .vga_set_state = &r600_vga_set_state,
+ .gart_tlb_flush = &r600_pcie_gart_tlb_flush,
+ .gart_set_page = &rs600_gart_set_page,
+ .ring_test = NULL,
+ .ring_ib_execute = NULL,
+ .irq_set = NULL,
+ .irq_process = NULL,
+ .get_vblank_counter = NULL,
+ .fence_ring_emit = NULL,
+ .cs_parse = NULL,
+ .copy_blit = NULL,
+ .copy_dma = NULL,
+ .copy = NULL,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = NULL,
+ .set_surface_reg = r600_set_surface_reg,
+ .clear_surface_reg = r600_clear_surface_reg,
+ .bandwidth_update = &evergreen_bandwidth_update,
+ .hpd_init = &evergreen_hpd_init,
+ .hpd_fini = &evergreen_hpd_fini,
+ .hpd_sense = &evergreen_hpd_sense,
+ .hpd_set_polarity = &evergreen_hpd_set_polarity,
};
#endif
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index fa82ca74324e..93783b15c81d 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -159,8 +159,15 @@ static struct radeon_hpd radeon_atom_get_hpd_info_from_gpio(struct radeon_device
struct radeon_gpio_rec *gpio)
{
struct radeon_hpd hpd;
+ u32 reg;
+
+ if (ASIC_IS_DCE4(rdev))
+ reg = EVERGREEN_DC_GPIO_HPD_A;
+ else
+ reg = AVIVO_DC_GPIO_HPD_A;
+
hpd.gpio = *gpio;
- if (gpio->reg == AVIVO_DC_GPIO_HPD_A) {
+ if (gpio->reg == reg) {
switch(gpio->mask) {
case (1 << 0):
hpd.hpd = RADEON_HPD_1;
@@ -206,6 +213,15 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
*connector_type = DRM_MODE_CONNECTOR_DVID;
}
+ /* Asrock RS600 board lists the DVI port as HDMI */
+ if ((dev->pdev->device == 0x7941) &&
+ (dev->pdev->subsystem_vendor == 0x1849) &&
+ (dev->pdev->subsystem_device == 0x7941)) {
+ if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
+ (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
+ *connector_type = DRM_MODE_CONNECTOR_DVID;
+ }
+
/* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */
if ((dev->pdev->device == 0x7941) &&
(dev->pdev->subsystem_vendor == 0x147b) &&
@@ -287,6 +303,15 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
*connector_type = DRM_MODE_CONNECTOR_DVID;
}
+ /* XFX Pine Group device rv730 reports no VGA DDC lines
+ * even though they are wired up to record 0x93
+ */
+ if ((dev->pdev->device == 0x9498) &&
+ (dev->pdev->subsystem_vendor == 0x1682) &&
+ (dev->pdev->subsystem_device == 0x2452)) {
+ struct radeon_device *rdev = dev->dev_private;
+ *i2c_bus = radeon_lookup_i2c_gpio(rdev, 0x93);
+ }
return true;
}
@@ -556,6 +581,9 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
ddc_bus.valid = false;
}
+ /* needed for aux chan transactions */
+ ddc_bus.hpd_id = hpd.hpd ? (hpd.hpd - 1) : 0;
+
conn_id = le16_to_cpu(path->usConnObjectId);
if (!radeon_atom_apply_quirks
@@ -820,6 +848,7 @@ union firmware_info {
ATOM_FIRMWARE_INFO_V1_2 info_12;
ATOM_FIRMWARE_INFO_V1_3 info_13;
ATOM_FIRMWARE_INFO_V1_4 info_14;
+ ATOM_FIRMWARE_INFO_V2_1 info_21;
};
bool radeon_atom_get_clock_info(struct drm_device *dev)
@@ -831,6 +860,7 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
uint8_t frev, crev;
struct radeon_pll *p1pll = &rdev->clock.p1pll;
struct radeon_pll *p2pll = &rdev->clock.p2pll;
+ struct radeon_pll *dcpll = &rdev->clock.dcpll;
struct radeon_pll *spll = &rdev->clock.spll;
struct radeon_pll *mpll = &rdev->clock.mpll;
uint16_t data_offset;
@@ -933,8 +963,19 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
rdev->clock.default_mclk =
le32_to_cpu(firmware_info->info.ulDefaultMemoryClock);
+ if (ASIC_IS_DCE4(rdev)) {
+ rdev->clock.default_dispclk =
+ le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq);
+ if (rdev->clock.default_dispclk == 0)
+ rdev->clock.default_dispclk = 60000; /* 600 Mhz */
+ rdev->clock.dp_extclk =
+ le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq);
+ }
+ *dcpll = *p1pll;
+
return true;
}
+
return false;
}
@@ -1073,6 +1114,30 @@ static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct
return ss;
}
+static void radeon_atom_apply_lvds_quirks(struct drm_device *dev,
+ struct radeon_encoder_atom_dig *lvds)
+{
+
+ /* Toshiba A300-1BU laptop panel doesn't like new pll divider algo */
+ if ((dev->pdev->device == 0x95c4) &&
+ (dev->pdev->subsystem_vendor == 0x1179) &&
+ (dev->pdev->subsystem_device == 0xff50)) {
+ if ((lvds->native_mode.hdisplay == 1280) &&
+ (lvds->native_mode.vdisplay == 800))
+ lvds->pll_algo = PLL_ALGO_LEGACY;
+ }
+
+ /* Dell Studio 15 laptop panel doesn't like new pll divider algo */
+ if ((dev->pdev->device == 0x95c4) &&
+ (dev->pdev->subsystem_vendor == 0x1028) &&
+ (dev->pdev->subsystem_device == 0x029f)) {
+ if ((lvds->native_mode.hdisplay == 1280) &&
+ (lvds->native_mode.vdisplay == 800))
+ lvds->pll_algo = PLL_ALGO_LEGACY;
+ }
+
+}
+
union lvds_info {
struct _ATOM_LVDS_INFO info;
struct _ATOM_LVDS_INFO_V12 info_12;
@@ -1143,6 +1208,21 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
lvds->ss = radeon_atombios_get_ss_info(encoder, lvds_info->info.ucSS_Id);
+ if (ASIC_IS_AVIVO(rdev)) {
+ if (radeon_new_pll == 0)
+ lvds->pll_algo = PLL_ALGO_LEGACY;
+ else
+ lvds->pll_algo = PLL_ALGO_NEW;
+ } else {
+ if (radeon_new_pll == 1)
+ lvds->pll_algo = PLL_ALGO_NEW;
+ else
+ lvds->pll_algo = PLL_ALGO_LEGACY;
+ }
+
+ /* LVDS quirks */
+ radeon_atom_apply_lvds_quirks(dev, lvds);
+
encoder->native_mode = lvds->native_mode;
}
return lvds;
@@ -1367,20 +1447,375 @@ radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)
return tv_dac;
}
-void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable)
+union power_info {
+ struct _ATOM_POWERPLAY_INFO info;
+ struct _ATOM_POWERPLAY_INFO_V2 info_2;
+ struct _ATOM_POWERPLAY_INFO_V3 info_3;
+ struct _ATOM_PPLIB_POWERPLAYTABLE info_4;
+};
+
+void radeon_atombios_get_power_modes(struct radeon_device *rdev)
{
- DYNAMIC_CLOCK_GATING_PS_ALLOCATION args;
- int index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating);
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+ u16 data_offset;
+ u8 frev, crev;
+ u32 misc, misc2 = 0, sclk, mclk;
+ union power_info *power_info;
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+ struct _ATOM_PPLIB_STATE *power_state;
+ int num_modes = 0, i, j;
+ int state_index = 0, mode_index = 0;
- args.ucEnable = enable;
+ atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset);
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+ rdev->pm.default_power_state = NULL;
+
+ if (power_info) {
+ if (frev < 4) {
+ num_modes = power_info->info.ucNumOfPowerModeEntries;
+ if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK)
+ num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK;
+ for (i = 0; i < num_modes; i++) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
+ switch (frev) {
+ case 1:
+ rdev->pm.power_state[state_index].num_clock_modes = 1;
+ rdev->pm.power_state[state_index].clock_info[0].mclk =
+ le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock);
+ rdev->pm.power_state[state_index].clock_info[0].sclk =
+ le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock);
+ /* skip invalid modes */
+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
+ (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
+ continue;
+ /* skip overclock modes for now */
+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk >
+ rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
+ (rdev->pm.power_state[state_index].clock_info[0].sclk >
+ rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
+ continue;
+ rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
+ power_info->info.asPowerPlayInfo[i].ucNumPciELanes;
+ misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo);
+ if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type =
+ VOLTAGE_GPIO;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
+ radeon_lookup_gpio(rdev,
+ power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex);
+ if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ true;
+ else
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ false;
+ } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type =
+ VOLTAGE_VDDC;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
+ power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex;
+ }
+ /* order matters! */
+ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_POWERSAVE;
+ if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BATTERY;
+ if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BATTERY;
+ if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BALANCED;
+ if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_PERFORMANCE;
+ if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_DEFAULT;
+ rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
+ rdev->pm.power_state[state_index].default_clock_mode =
+ &rdev->pm.power_state[state_index].clock_info[0];
+ }
+ state_index++;
+ break;
+ case 2:
+ rdev->pm.power_state[state_index].num_clock_modes = 1;
+ rdev->pm.power_state[state_index].clock_info[0].mclk =
+ le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock);
+ rdev->pm.power_state[state_index].clock_info[0].sclk =
+ le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock);
+ /* skip invalid modes */
+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
+ (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
+ continue;
+ /* skip overclock modes for now */
+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk >
+ rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
+ (rdev->pm.power_state[state_index].clock_info[0].sclk >
+ rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
+ continue;
+ rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
+ power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes;
+ misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo);
+ misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2);
+ if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type =
+ VOLTAGE_GPIO;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
+ radeon_lookup_gpio(rdev,
+ power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex);
+ if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ true;
+ else
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ false;
+ } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type =
+ VOLTAGE_VDDC;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
+ power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex;
+ }
+ /* order matters! */
+ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_POWERSAVE;
+ if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BATTERY;
+ if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BATTERY;
+ if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BALANCED;
+ if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_PERFORMANCE;
+ if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BALANCED;
+ if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_DEFAULT;
+ rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
+ rdev->pm.power_state[state_index].default_clock_mode =
+ &rdev->pm.power_state[state_index].clock_info[0];
+ }
+ state_index++;
+ break;
+ case 3:
+ rdev->pm.power_state[state_index].num_clock_modes = 1;
+ rdev->pm.power_state[state_index].clock_info[0].mclk =
+ le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock);
+ rdev->pm.power_state[state_index].clock_info[0].sclk =
+ le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock);
+ /* skip invalid modes */
+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
+ (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
+ continue;
+ /* skip overclock modes for now */
+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk >
+ rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
+ (rdev->pm.power_state[state_index].clock_info[0].sclk >
+ rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
+ continue;
+ rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
+ power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes;
+ misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo);
+ misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2);
+ if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type =
+ VOLTAGE_GPIO;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
+ radeon_lookup_gpio(rdev,
+ power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex);
+ if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ true;
+ else
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ false;
+ } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type =
+ VOLTAGE_VDDC;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
+ power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex;
+ if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled =
+ true;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id =
+ power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex;
+ }
+ }
+ /* order matters! */
+ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_POWERSAVE;
+ if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BATTERY;
+ if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BATTERY;
+ if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BALANCED;
+ if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_PERFORMANCE;
+ if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BALANCED;
+ if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_DEFAULT;
+ rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
+ rdev->pm.power_state[state_index].default_clock_mode =
+ &rdev->pm.power_state[state_index].clock_info[0];
+ }
+ state_index++;
+ break;
+ }
+ }
+ } else if (frev == 4) {
+ for (i = 0; i < power_info->info_4.ucNumStates; i++) {
+ mode_index = 0;
+ power_state = (struct _ATOM_PPLIB_STATE *)
+ (mode_info->atom_context->bios +
+ data_offset +
+ le16_to_cpu(power_info->info_4.usStateArrayOffset) +
+ i * power_info->info_4.ucStateEntrySize);
+ non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+ (mode_info->atom_context->bios +
+ data_offset +
+ le16_to_cpu(power_info->info_4.usNonClockInfoArrayOffset) +
+ (power_state->ucNonClockStateIndex *
+ power_info->info_4.ucNonClockSize));
+ for (j = 0; j < (power_info->info_4.ucStateEntrySize - 1); j++) {
+ if (rdev->flags & RADEON_IS_IGP) {
+ struct _ATOM_PPLIB_RS780_CLOCK_INFO *clock_info =
+ (struct _ATOM_PPLIB_RS780_CLOCK_INFO *)
+ (mode_info->atom_context->bios +
+ data_offset +
+ le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) +
+ (power_state->ucClockStateIndices[j] *
+ power_info->info_4.ucClockInfoSize));
+ sclk = le16_to_cpu(clock_info->usLowEngineClockLow);
+ sclk |= clock_info->ucLowEngineClockHigh << 16;
+ rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
+ /* skip invalid modes */
+ if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)
+ continue;
+ /* skip overclock modes for now */
+ if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk >
+ rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)
+ continue;
+ rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
+ VOLTAGE_SW;
+ rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
+ clock_info->usVDDC;
+ mode_index++;
+ } else {
+ struct _ATOM_PPLIB_R600_CLOCK_INFO *clock_info =
+ (struct _ATOM_PPLIB_R600_CLOCK_INFO *)
+ (mode_info->atom_context->bios +
+ data_offset +
+ le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) +
+ (power_state->ucClockStateIndices[j] *
+ power_info->info_4.ucClockInfoSize));
+ sclk = le16_to_cpu(clock_info->usEngineClockLow);
+ sclk |= clock_info->ucEngineClockHigh << 16;
+ mclk = le16_to_cpu(clock_info->usMemoryClockLow);
+ mclk |= clock_info->ucMemoryClockHigh << 16;
+ rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
+ rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
+ /* skip invalid modes */
+ if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) ||
+ (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0))
+ continue;
+ /* skip overclock modes for now */
+ if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk >
+ rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
+ (rdev->pm.power_state[state_index].clock_info[mode_index].sclk >
+ rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
+ continue;
+ rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
+ VOLTAGE_SW;
+ rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
+ clock_info->usVDDC;
+ mode_index++;
+ }
+ }
+ rdev->pm.power_state[state_index].num_clock_modes = mode_index;
+ if (mode_index) {
+ misc = le32_to_cpu(non_clock_info->ulCapsAndSettings);
+ misc2 = le16_to_cpu(non_clock_info->usClassification);
+ rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
+ ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
+ ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
+ switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
+ case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BATTERY;
+ break;
+ case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BALANCED;
+ break;
+ case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_PERFORMANCE;
+ break;
+ }
+ if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_DEFAULT;
+ rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
+ rdev->pm.power_state[state_index].default_clock_mode =
+ &rdev->pm.power_state[state_index].clock_info[mode_index - 1];
+ }
+ state_index++;
+ }
+ }
+ }
+ } else {
+ /* XXX figure out some good default low power mode for cards w/out power tables */
+ }
+
+ if (rdev->pm.default_power_state == NULL) {
+ /* add the default mode */
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_DEFAULT;
+ rdev->pm.power_state[state_index].num_clock_modes = 1;
+ rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
+ rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
+ rdev->pm.power_state[state_index].default_clock_mode =
+ &rdev->pm.power_state[state_index].clock_info[0];
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
+ if (rdev->asic->get_pcie_lanes)
+ rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev);
+ else
+ rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16;
+ rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
+ state_index++;
+ }
+ rdev->pm.num_power_states = state_index;
+
+ rdev->pm.current_power_state = rdev->pm.default_power_state;
+ rdev->pm.current_clock_mode =
+ rdev->pm.default_power_state->default_clock_mode;
}
-void radeon_atom_static_pwrmgt_setup(struct radeon_device *rdev, int enable)
+void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable)
{
- ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION args;
- int index = GetIndexIntoMasterTable(COMMAND, EnableASIC_StaticPwrMgt);
+ DYNAMIC_CLOCK_GATING_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating);
args.ucEnable = enable;
diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
new file mode 100644
index 000000000000..3f557c4151e0
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2010 Red Hat Inc.
+ * Author : Dave Airlie <airlied@redhat.com>
+ *
+ * Licensed under GPLv2
+ *
+ * ATPX support for both Intel/ATI
+ */
+#include <linux/vga_switcheroo.h>
+#include <acpi/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <linux/pci.h>
+
+#define ATPX_VERSION 0
+#define ATPX_GPU_PWR 2
+#define ATPX_MUX_SELECT 3
+
+#define ATPX_INTEGRATED 0
+#define ATPX_DISCRETE 1
+
+#define ATPX_MUX_IGD 0
+#define ATPX_MUX_DISCRETE 1
+
+static struct radeon_atpx_priv {
+ bool atpx_detected;
+ /* handle for device - and atpx */
+ acpi_handle dhandle;
+ acpi_handle atpx_handle;
+ acpi_handle atrm_handle;
+} radeon_atpx_priv;
+
+/* retrieve the ROM in 4k blocks */
+static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
+ int offset, int len)
+{
+ acpi_status status;
+ union acpi_object atrm_arg_elements[2], *obj;
+ struct acpi_object_list atrm_arg;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
+
+ atrm_arg.count = 2;
+ atrm_arg.pointer = &atrm_arg_elements[0];
+
+ atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
+ atrm_arg_elements[0].integer.value = offset;
+
+ atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
+ atrm_arg_elements[1].integer.value = len;
+
+ status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
+ return -ENODEV;
+ }
+
+ obj = (union acpi_object *)buffer.pointer;
+ memcpy(bios+offset, obj->buffer.pointer, len);
+ kfree(buffer.pointer);
+ return len;
+}
+
+bool radeon_atrm_supported(struct pci_dev *pdev)
+{
+ /* get the discrete ROM only via ATRM */
+ if (!radeon_atpx_priv.atpx_detected)
+ return false;
+
+ if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
+ return false;
+ return true;
+}
+
+
+int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len)
+{
+ return radeon_atrm_call(radeon_atpx_priv.atrm_handle, bios, offset, len);
+}
+
+static int radeon_atpx_get_version(acpi_handle handle)
+{
+ acpi_status status;
+ union acpi_object atpx_arg_elements[2], *obj;
+ struct acpi_object_list atpx_arg;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ atpx_arg.count = 2;
+ atpx_arg.pointer = &atpx_arg_elements[0];
+
+ atpx_arg_elements[0].type = ACPI_TYPE_INTEGER;
+ atpx_arg_elements[0].integer.value = ATPX_VERSION;
+
+ atpx_arg_elements[1].type = ACPI_TYPE_INTEGER;
+ atpx_arg_elements[1].integer.value = ATPX_VERSION;
+
+ status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk("%s: failed to call ATPX: %s\n", __func__, acpi_format_exception(status));
+ return -ENOSYS;
+ }
+ obj = (union acpi_object *)buffer.pointer;
+ if (obj && (obj->type == ACPI_TYPE_BUFFER))
+ printk(KERN_INFO "radeon atpx: version is %d\n", *((u8 *)(obj->buffer.pointer) + 2));
+ kfree(buffer.pointer);
+ return 0;
+}
+
+static int radeon_atpx_execute(acpi_handle handle, int cmd_id, u16 value)
+{
+ acpi_status status;
+ union acpi_object atpx_arg_elements[2];
+ struct acpi_object_list atpx_arg;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ uint8_t buf[4] = {0};
+
+ if (!handle)
+ return -EINVAL;
+
+ atpx_arg.count = 2;
+ atpx_arg.pointer = &atpx_arg_elements[0];
+
+ atpx_arg_elements[0].type = ACPI_TYPE_INTEGER;
+ atpx_arg_elements[0].integer.value = cmd_id;
+
+ buf[2] = value & 0xff;
+ buf[3] = (value >> 8) & 0xff;
+
+ atpx_arg_elements[1].type = ACPI_TYPE_BUFFER;
+ atpx_arg_elements[1].buffer.length = 4;
+ atpx_arg_elements[1].buffer.pointer = buf;
+
+ status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk("%s: failed to call ATPX: %s\n", __func__, acpi_format_exception(status));
+ return -ENOSYS;
+ }
+ kfree(buffer.pointer);
+
+ return 0;
+}
+
+static int radeon_atpx_set_discrete_state(acpi_handle handle, int state)
+{
+ return radeon_atpx_execute(handle, ATPX_GPU_PWR, state);
+}
+
+static int radeon_atpx_switch_mux(acpi_handle handle, int mux_id)
+{
+ return radeon_atpx_execute(handle, ATPX_MUX_SELECT, mux_id);
+}
+
+
+static int radeon_atpx_switchto(enum vga_switcheroo_client_id id)
+{
+ if (id == VGA_SWITCHEROO_IGD)
+ radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 0);
+ else
+ radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 1);
+ return 0;
+}
+
+static int radeon_atpx_power_state(enum vga_switcheroo_client_id id,
+ enum vga_switcheroo_state state)
+{
+ /* on w500 ACPI can't change intel gpu state */
+ if (id == VGA_SWITCHEROO_IGD)
+ return 0;
+
+ radeon_atpx_set_discrete_state(radeon_atpx_priv.atpx_handle, state);
+ return 0;
+}
+
+static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
+{
+ acpi_handle dhandle, atpx_handle, atrm_handle;
+ acpi_status status;
+
+ dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
+ if (!dhandle)
+ return false;
+
+ status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
+ if (ACPI_FAILURE(status))
+ return false;
+
+ status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
+ if (ACPI_FAILURE(status))
+ return false;
+
+ radeon_atpx_priv.dhandle = dhandle;
+ radeon_atpx_priv.atpx_handle = atpx_handle;
+ radeon_atpx_priv.atrm_handle = atrm_handle;
+ return true;
+}
+
+static int radeon_atpx_init(void)
+{
+ /* set up the ATPX handle */
+
+ radeon_atpx_get_version(radeon_atpx_priv.atpx_handle);
+ return 0;
+}
+
+static int radeon_atpx_get_client_id(struct pci_dev *pdev)
+{
+ if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
+ return VGA_SWITCHEROO_IGD;
+ else
+ return VGA_SWITCHEROO_DIS;
+}
+
+static struct vga_switcheroo_handler radeon_atpx_handler = {
+ .switchto = radeon_atpx_switchto,
+ .power_state = radeon_atpx_power_state,
+ .init = radeon_atpx_init,
+ .get_client_id = radeon_atpx_get_client_id,
+};
+
+static bool radeon_atpx_detect(void)
+{
+ char acpi_method_name[255] = { 0 };
+ struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
+ struct pci_dev *pdev = NULL;
+ bool has_atpx = false;
+ int vga_count = 0;
+
+ while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
+ vga_count++;
+
+ has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
+ }
+
+ if (has_atpx && vga_count == 2) {
+ acpi_get_name(radeon_atpx_priv.atpx_handle, ACPI_FULL_PATHNAME, &buffer);
+ printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n",
+ acpi_method_name);
+ radeon_atpx_priv.atpx_detected = true;
+ return true;
+ }
+ return false;
+}
+
+void radeon_register_atpx_handler(void)
+{
+ bool r;
+
+ /* detect if we have any ATPX + 2 VGA in the system */
+ r = radeon_atpx_detect();
+ if (!r)
+ return;
+
+ vga_switcheroo_register_handler(&radeon_atpx_handler);
+}
+
+void radeon_unregister_atpx_handler(void)
+{
+ vga_switcheroo_unregister_handler();
+}
diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c
index 4ddfd4b5bc51..7932dc4d6b90 100644
--- a/drivers/gpu/drm/radeon/radeon_benchmark.c
+++ b/drivers/gpu/drm/radeon/radeon_benchmark.c
@@ -65,31 +65,42 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize,
if (r) {
goto out_cleanup;
}
- start_jiffies = jiffies;
- for (i = 0; i < n; i++) {
- r = radeon_fence_create(rdev, &fence);
- if (r) {
- goto out_cleanup;
+
+ /* r100 doesn't have dma engine so skip the test */
+ if (rdev->asic->copy_dma) {
+
+ start_jiffies = jiffies;
+ for (i = 0; i < n; i++) {
+ r = radeon_fence_create(rdev, &fence);
+ if (r) {
+ goto out_cleanup;
+ }
+
+ r = radeon_copy_dma(rdev, saddr, daddr,
+ size / RADEON_GPU_PAGE_SIZE, fence);
+
+ if (r) {
+ goto out_cleanup;
+ }
+ r = radeon_fence_wait(fence, false);
+ if (r) {
+ goto out_cleanup;
+ }
+ radeon_fence_unref(&fence);
}
- r = radeon_copy_dma(rdev, saddr, daddr, size / RADEON_GPU_PAGE_SIZE, fence);
- if (r) {
- goto out_cleanup;
+ end_jiffies = jiffies;
+ time = end_jiffies - start_jiffies;
+ time = jiffies_to_msecs(time);
+ if (time > 0) {
+ i = ((n * size) >> 10) / time;
+ printk(KERN_INFO "radeon: dma %u bo moves of %ukb from"
+ " %d to %d in %lums (%ukb/ms %ukb/s %uM/s)\n",
+ n, size >> 10,
+ sdomain, ddomain, time,
+ i, i * 1000, (i * 1000) / 1024);
}
- r = radeon_fence_wait(fence, false);
- if (r) {
- goto out_cleanup;
- }
- radeon_fence_unref(&fence);
- }
- end_jiffies = jiffies;
- time = end_jiffies - start_jiffies;
- time = jiffies_to_msecs(time);
- if (time > 0) {
- i = ((n * size) >> 10) / time;
- printk(KERN_INFO "radeon: dma %u bo moves of %ukb from %d to %d"
- " in %lums (%ukb/ms %ukb/s %uM/s)\n", n, size >> 10,
- sdomain, ddomain, time, i, i * 1000, (i * 1000) / 1024);
}
+
start_jiffies = jiffies;
for (i = 0; i < n; i++) {
r = radeon_fence_create(rdev, &fence);
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index 906921740c60..557240460526 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -30,6 +30,7 @@
#include "radeon.h"
#include "atom.h"
+#include <linux/vga_switcheroo.h>
/*
* BIOS.
*/
@@ -62,7 +63,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev)
iounmap(bios);
return false;
}
- memcpy(rdev->bios, bios, size);
+ memcpy_fromio(rdev->bios, bios, size);
iounmap(bios);
return true;
}
@@ -93,6 +94,38 @@ static bool radeon_read_bios(struct radeon_device *rdev)
return true;
}
+/* ATRM is used to get the BIOS on the discrete cards in
+ * dual-gpu systems.
+ */
+static bool radeon_atrm_get_bios(struct radeon_device *rdev)
+{
+ int ret;
+ int size = 64 * 1024;
+ int i;
+
+ if (!radeon_atrm_supported(rdev->pdev))
+ return false;
+
+ rdev->bios = kmalloc(size, GFP_KERNEL);
+ if (!rdev->bios) {
+ DRM_ERROR("Unable to allocate bios\n");
+ return false;
+ }
+
+ for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
+ ret = radeon_atrm_get_bios_chunk(rdev->bios,
+ (i * ATRM_BIOS_PAGE),
+ ATRM_BIOS_PAGE);
+ if (ret <= 0)
+ break;
+ }
+
+ if (i == 0 || rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
+ kfree(rdev->bios);
+ return false;
+ }
+ return true;
+}
static bool r700_read_disabled_bios(struct radeon_device *rdev)
{
uint32_t viph_control;
@@ -388,16 +421,16 @@ static bool radeon_read_disabled_bios(struct radeon_device *rdev)
return legacy_read_disabled_bios(rdev);
}
+
bool radeon_get_bios(struct radeon_device *rdev)
{
bool r;
uint16_t tmp;
- if (rdev->flags & RADEON_IS_IGP) {
+ r = radeon_atrm_get_bios(rdev);
+ if (r == false)
r = igp_read_bios_from_vram(rdev);
- if (r == false)
- r = radeon_read_bios(rdev);
- } else
+ if (r == false)
r = radeon_read_bios(rdev);
if (r == false) {
r = radeon_read_disabled_bios(rdev);
@@ -408,6 +441,13 @@ bool radeon_get_bios(struct radeon_device *rdev)
return false;
}
if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
+ printk("BIOS signature incorrect %x %x\n", rdev->bios[0], rdev->bios[1]);
+ goto free_bios;
+ }
+
+ tmp = RBIOS16(0x18);
+ if (RBIOS8(tmp + 0x14) != 0x0) {
+ DRM_INFO("Not an x86 BIOS ROM, not using.\n");
goto free_bios;
}
diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c
index 812f24dbc2a8..f64936cc4dd9 100644
--- a/drivers/gpu/drm/radeon/radeon_clocks.c
+++ b/drivers/gpu/drm/radeon/radeon_clocks.c
@@ -56,7 +56,7 @@ uint32_t radeon_legacy_get_engine_clock(struct radeon_device *rdev)
else if (post_div == 3)
sclk >>= 2;
else if (post_div == 4)
- sclk >>= 4;
+ sclk >>= 3;
return sclk;
}
@@ -86,7 +86,7 @@ uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev)
else if (post_div == 3)
mclk >>= 2;
else if (post_div == 4)
- mclk >>= 4;
+ mclk >>= 3;
return mclk;
}
@@ -96,6 +96,7 @@ void radeon_get_clock_info(struct drm_device *dev)
struct radeon_device *rdev = dev->dev_private;
struct radeon_pll *p1pll = &rdev->clock.p1pll;
struct radeon_pll *p2pll = &rdev->clock.p2pll;
+ struct radeon_pll *dcpll = &rdev->clock.dcpll;
struct radeon_pll *spll = &rdev->clock.spll;
struct radeon_pll *mpll = &rdev->clock.mpll;
int ret;
@@ -204,6 +205,17 @@ void radeon_get_clock_info(struct drm_device *dev)
p2pll->max_frac_feedback_div = 0;
}
+ /* dcpll is DCE4 only */
+ dcpll->min_post_div = 2;
+ dcpll->max_post_div = 0x7f;
+ dcpll->min_frac_feedback_div = 0;
+ dcpll->max_frac_feedback_div = 9;
+ dcpll->min_ref_div = 2;
+ dcpll->max_ref_div = 0x3ff;
+ dcpll->min_feedback_div = 4;
+ dcpll->max_feedback_div = 0xfff;
+ dcpll->best_vco = 0;
+
p1pll->min_ref_div = 2;
p1pll->max_ref_div = 0x3ff;
p1pll->min_feedback_div = 4;
@@ -846,8 +858,10 @@ int radeon_static_clocks_init(struct drm_device *dev)
/* XXX make sure engine is idle */
if (radeon_dynclks != -1) {
- if (radeon_dynclks)
- radeon_set_clock_gating(rdev, 1);
+ if (radeon_dynclks) {
+ if (rdev->asic->set_clock_gating)
+ radeon_set_clock_gating(rdev, 1);
+ }
}
radeon_apply_clock_quirks(rdev);
return 0;
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index 579c8920e081..e9ea38ece375 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -150,6 +150,9 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
int rev;
uint16_t offset = 0, check_offset;
+ if (!rdev->bios)
+ return 0;
+
switch (table) {
/* absolute offset tables */
case COMBIOS_ASIC_INIT_1_TABLE:
@@ -443,6 +446,39 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
}
+bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
+{
+ int edid_info;
+ struct edid *edid;
+ edid_info = combios_get_table_offset(rdev->ddev, COMBIOS_HARDCODED_EDID_TABLE);
+ if (!edid_info)
+ return false;
+
+ edid = kmalloc(EDID_LENGTH * (DRM_MAX_EDID_EXT_NUM + 1),
+ GFP_KERNEL);
+ if (edid == NULL)
+ return false;
+
+ memcpy((unsigned char *)edid,
+ (unsigned char *)(rdev->bios + edid_info), EDID_LENGTH);
+
+ if (!drm_edid_is_valid(edid)) {
+ kfree(edid);
+ return false;
+ }
+
+ rdev->mode_info.bios_hardcoded_edid = edid;
+ return true;
+}
+
+struct edid *
+radeon_combios_get_hardcoded_edid(struct radeon_device *rdev)
+{
+ if (rdev->mode_info.bios_hardcoded_edid)
+ return rdev->mode_info.bios_hardcoded_edid;
+ return NULL;
+}
+
static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rdev,
int ddc_line)
{
@@ -486,9 +522,65 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
i2c.y_data_reg = ddc_line;
}
- if (rdev->family < CHIP_R200)
- i2c.hw_capable = false;
- else {
+ switch (rdev->family) {
+ case CHIP_R100:
+ case CHIP_RV100:
+ case CHIP_RS100:
+ case CHIP_RV200:
+ case CHIP_RS200:
+ case CHIP_RS300:
+ switch (ddc_line) {
+ case RADEON_GPIO_DVI_DDC:
+ /* in theory this should be hw capable,
+ * but it doesn't seem to work
+ */
+ i2c.hw_capable = false;
+ break;
+ default:
+ i2c.hw_capable = false;
+ break;
+ }
+ break;
+ case CHIP_R200:
+ switch (ddc_line) {
+ case RADEON_GPIO_DVI_DDC:
+ case RADEON_GPIO_MONID:
+ i2c.hw_capable = true;
+ break;
+ default:
+ i2c.hw_capable = false;
+ break;
+ }
+ break;
+ case CHIP_RV250:
+ case CHIP_RV280:
+ switch (ddc_line) {
+ case RADEON_GPIO_VGA_DDC:
+ case RADEON_GPIO_DVI_DDC:
+ case RADEON_GPIO_CRT2_DDC:
+ i2c.hw_capable = true;
+ break;
+ default:
+ i2c.hw_capable = false;
+ break;
+ }
+ break;
+ case CHIP_R300:
+ case CHIP_R350:
+ switch (ddc_line) {
+ case RADEON_GPIO_VGA_DDC:
+ case RADEON_GPIO_DVI_DDC:
+ i2c.hw_capable = true;
+ break;
+ default:
+ i2c.hw_capable = false;
+ break;
+ }
+ break;
+ case CHIP_RV350:
+ case CHIP_RV380:
+ case CHIP_RS400:
+ case CHIP_RS480:
switch (ddc_line) {
case RADEON_GPIO_VGA_DDC:
case RADEON_GPIO_DVI_DDC:
@@ -504,9 +596,14 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
i2c.hw_capable = false;
break;
}
+ break;
+ default:
+ i2c.hw_capable = false;
+ break;
}
i2c.mm_i2c = false;
i2c.i2c_id = 0;
+ i2c.hpd_id = 0;
if (ddc_line)
i2c.valid = true;
@@ -527,9 +624,6 @@ bool radeon_combios_get_clock_info(struct drm_device *dev)
int8_t rev;
uint16_t sclk, mclk;
- if (rdev->bios == NULL)
- return false;
-
pll_info = combios_get_table_offset(dev, COMBIOS_PLL_INFO_TABLE);
if (pll_info) {
rev = RBIOS8(pll_info);
@@ -654,9 +748,6 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct
if (!p_dac)
return NULL;
- if (rdev->bios == NULL)
- goto out;
-
/* check CRT table */
dac_info = combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE);
if (dac_info) {
@@ -673,7 +764,6 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct
found = 1;
}
-out:
if (!found) /* fallback to defaults */
radeon_legacy_get_primary_dac_info_from_table(rdev, p_dac);
@@ -687,9 +777,6 @@ radeon_combios_get_tv_info(struct radeon_device *rdev)
uint16_t tv_info;
enum radeon_tv_std tv_std = TV_STD_NTSC;
- if (rdev->bios == NULL)
- return tv_std;
-
tv_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE);
if (tv_info) {
if (RBIOS8(tv_info + 6) == 'T') {
@@ -793,9 +880,6 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct
if (!tv_dac)
return NULL;
- if (rdev->bios == NULL)
- goto out;
-
/* first check TV table */
dac_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE);
if (dac_info) {
@@ -857,7 +941,6 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct
}
}
-out:
if (!found) /* fallback to defaults */
radeon_legacy_get_tv_dac_info_from_table(rdev, tv_dac);
@@ -945,11 +1028,6 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder
int tmp, i;
struct radeon_encoder_lvds *lvds = NULL;
- if (rdev->bios == NULL) {
- lvds = radeon_legacy_get_lvds_info_from_regs(rdev);
- goto out;
- }
-
lcd_info = combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE);
if (lcd_info) {
@@ -971,8 +1049,7 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder
lvds->native_mode.vdisplay);
lvds->panel_vcc_delay = RBIOS16(lcd_info + 0x2c);
- if (lvds->panel_vcc_delay > 2000 || lvds->panel_vcc_delay < 0)
- lvds->panel_vcc_delay = 2000;
+ lvds->panel_vcc_delay = min_t(u16, lvds->panel_vcc_delay, 2000);
lvds->panel_pwr_delay = RBIOS8(lcd_info + 0x24);
lvds->panel_digon_delay = RBIOS16(lcd_info + 0x38) & 0xf;
@@ -1051,7 +1128,7 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder
DRM_INFO("No panel info found in BIOS\n");
lvds = radeon_legacy_get_lvds_info_from_regs(rdev);
}
-out:
+
if (lvds)
encoder->native_mode = lvds->native_mode;
return lvds;
@@ -1103,9 +1180,6 @@ bool radeon_legacy_get_tmds_info_from_combios(struct radeon_encoder *encoder,
int i, n;
uint8_t ver;
- if (rdev->bios == NULL)
- return false;
-
tmds_info = combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE);
if (tmds_info) {
@@ -1185,9 +1259,6 @@ bool radeon_legacy_get_ext_tmds_info_from_combios(struct radeon_encoder *encoder
enum radeon_combios_ddc gpio;
struct radeon_i2c_bus_rec i2c_bus;
- if (rdev->bios == NULL)
- return false;
-
tmds->i2c_bus = NULL;
if (rdev->flags & RADEON_IS_IGP) {
offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE);
@@ -1254,7 +1325,10 @@ bool radeon_legacy_get_ext_tmds_info_from_combios(struct radeon_encoder *encoder
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
break;
case DDC_LCD: /* MM i2c */
- DRM_ERROR("MM i2c requires hw i2c engine\n");
+ i2c_bus.valid = true;
+ i2c_bus.hw_capable = true;
+ i2c_bus.mm_i2c = true;
+ tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
break;
default:
DRM_ERROR("Unsupported gpio %d\n", gpio);
@@ -1280,47 +1354,47 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
rdev->mode_info.connector_table = radeon_connector_table;
if (rdev->mode_info.connector_table == CT_NONE) {
#ifdef CONFIG_PPC_PMAC
- if (machine_is_compatible("PowerBook3,3")) {
+ if (of_machine_is_compatible("PowerBook3,3")) {
/* powerbook with VGA */
rdev->mode_info.connector_table = CT_POWERBOOK_VGA;
- } else if (machine_is_compatible("PowerBook3,4") ||
- machine_is_compatible("PowerBook3,5")) {
+ } else if (of_machine_is_compatible("PowerBook3,4") ||
+ of_machine_is_compatible("PowerBook3,5")) {
/* powerbook with internal tmds */
rdev->mode_info.connector_table = CT_POWERBOOK_INTERNAL;
- } else if (machine_is_compatible("PowerBook5,1") ||
- machine_is_compatible("PowerBook5,2") ||
- machine_is_compatible("PowerBook5,3") ||
- machine_is_compatible("PowerBook5,4") ||
- machine_is_compatible("PowerBook5,5")) {
+ } else if (of_machine_is_compatible("PowerBook5,1") ||
+ of_machine_is_compatible("PowerBook5,2") ||
+ of_machine_is_compatible("PowerBook5,3") ||
+ of_machine_is_compatible("PowerBook5,4") ||
+ of_machine_is_compatible("PowerBook5,5")) {
/* powerbook with external single link tmds (sil164) */
rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL;
- } else if (machine_is_compatible("PowerBook5,6")) {
+ } else if (of_machine_is_compatible("PowerBook5,6")) {
/* powerbook with external dual or single link tmds */
rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL;
- } else if (machine_is_compatible("PowerBook5,7") ||
- machine_is_compatible("PowerBook5,8") ||
- machine_is_compatible("PowerBook5,9")) {
+ } else if (of_machine_is_compatible("PowerBook5,7") ||
+ of_machine_is_compatible("PowerBook5,8") ||
+ of_machine_is_compatible("PowerBook5,9")) {
/* PowerBook6,2 ? */
/* powerbook with external dual link tmds (sil1178?) */
rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL;
- } else if (machine_is_compatible("PowerBook4,1") ||
- machine_is_compatible("PowerBook4,2") ||
- machine_is_compatible("PowerBook4,3") ||
- machine_is_compatible("PowerBook6,3") ||
- machine_is_compatible("PowerBook6,5") ||
- machine_is_compatible("PowerBook6,7")) {
+ } else if (of_machine_is_compatible("PowerBook4,1") ||
+ of_machine_is_compatible("PowerBook4,2") ||
+ of_machine_is_compatible("PowerBook4,3") ||
+ of_machine_is_compatible("PowerBook6,3") ||
+ of_machine_is_compatible("PowerBook6,5") ||
+ of_machine_is_compatible("PowerBook6,7")) {
/* ibook */
rdev->mode_info.connector_table = CT_IBOOK;
- } else if (machine_is_compatible("PowerMac4,4")) {
+ } else if (of_machine_is_compatible("PowerMac4,4")) {
/* emac */
rdev->mode_info.connector_table = CT_EMAC;
- } else if (machine_is_compatible("PowerMac10,1")) {
+ } else if (of_machine_is_compatible("PowerMac10,1")) {
/* mini with internal tmds */
rdev->mode_info.connector_table = CT_MINI_INTERNAL;
- } else if (machine_is_compatible("PowerMac10,2")) {
+ } else if (of_machine_is_compatible("PowerMac10,2")) {
/* mini with external tmds */
rdev->mode_info.connector_table = CT_MINI_EXTERNAL;
- } else if (machine_is_compatible("PowerMac12,1")) {
+ } else if (of_machine_is_compatible("PowerMac12,1")) {
/* PowerMac8,1 ? */
/* imac g5 isight */
rdev->mode_info.connector_table = CT_IMAC_G5_ISIGHT;
@@ -1910,9 +1984,6 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
struct radeon_i2c_bus_rec ddc_i2c;
struct radeon_hpd hpd;
- if (rdev->bios == NULL)
- return false;
-
conn_info = combios_get_table_offset(dev, COMBIOS_CONNECTOR_INFO_TABLE);
if (conn_info) {
for (i = 0; i < 4; i++) {
@@ -2279,6 +2350,115 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
return true;
}
+void radeon_combios_get_power_modes(struct radeon_device *rdev)
+{
+ struct drm_device *dev = rdev->ddev;
+ u16 offset, misc, misc2 = 0;
+ u8 rev, blocks, tmp;
+ int state_index = 0;
+
+ rdev->pm.default_power_state = NULL;
+
+ if (rdev->flags & RADEON_IS_MOBILITY) {
+ offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE);
+ if (offset) {
+ rev = RBIOS8(offset);
+ blocks = RBIOS8(offset + 0x2);
+ /* power mode 0 tends to be the only valid one */
+ rdev->pm.power_state[state_index].num_clock_modes = 1;
+ rdev->pm.power_state[state_index].clock_info[0].mclk = RBIOS32(offset + 0x5 + 0x2);
+ rdev->pm.power_state[state_index].clock_info[0].sclk = RBIOS32(offset + 0x5 + 0x6);
+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
+ (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
+ goto default_mode;
+ /* skip overclock modes for now */
+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk >
+ rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
+ (rdev->pm.power_state[state_index].clock_info[0].sclk >
+ rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
+ goto default_mode;
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_BATTERY;
+ misc = RBIOS16(offset + 0x5 + 0x0);
+ if (rev > 4)
+ misc2 = RBIOS16(offset + 0x5 + 0xe);
+ if (misc & 0x4) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO;
+ if (misc & 0x8)
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ true;
+ else
+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
+ false;
+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.valid = true;
+ if (rev < 6) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.reg =
+ RBIOS16(offset + 0x5 + 0xb) * 4;
+ tmp = RBIOS8(offset + 0x5 + 0xd);
+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.mask = (1 << tmp);
+ } else {
+ u8 entries = RBIOS8(offset + 0x5 + 0xb);
+ u16 voltage_table_offset = RBIOS16(offset + 0x5 + 0xc);
+ if (entries && voltage_table_offset) {
+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.reg =
+ RBIOS16(voltage_table_offset) * 4;
+ tmp = RBIOS8(voltage_table_offset + 0x2);
+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.mask = (1 << tmp);
+ } else
+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.valid = false;
+ }
+ switch ((misc2 & 0x700) >> 8) {
+ case 0:
+ default:
+ rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 0;
+ break;
+ case 1:
+ rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 33;
+ break;
+ case 2:
+ rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 66;
+ break;
+ case 3:
+ rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 99;
+ break;
+ case 4:
+ rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 132;
+ break;
+ }
+ } else
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
+ if (rev > 6)
+ rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
+ RBIOS8(offset + 0x5 + 0x10);
+ state_index++;
+ } else {
+ /* XXX figure out some good default low power mode for mobility cards w/out power tables */
+ }
+ } else {
+ /* XXX figure out some good default low power mode for desktop cards */
+ }
+
+default_mode:
+ /* add the default mode */
+ rdev->pm.power_state[state_index].type =
+ POWER_STATE_TYPE_DEFAULT;
+ rdev->pm.power_state[state_index].num_clock_modes = 1;
+ rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
+ rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
+ rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0];
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
+ if (rdev->asic->get_pcie_lanes)
+ rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev);
+ else
+ rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16;
+ rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
+ rdev->pm.num_power_states = state_index + 1;
+
+ rdev->pm.current_power_state = rdev->pm.default_power_state;
+ rdev->pm.current_clock_mode =
+ rdev->pm.default_power_state->default_clock_mode;
+}
+
void radeon_external_tmds_setup(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
@@ -2290,23 +2470,21 @@ void radeon_external_tmds_setup(struct drm_encoder *encoder)
switch (tmds->dvo_chip) {
case DVO_SIL164:
/* sil 164 */
- radeon_i2c_do_lock(tmds->i2c_bus, 1);
- radeon_i2c_sw_put_byte(tmds->i2c_bus,
- tmds->slave_addr,
- 0x08, 0x30);
- radeon_i2c_sw_put_byte(tmds->i2c_bus,
+ radeon_i2c_put_byte(tmds->i2c_bus,
+ tmds->slave_addr,
+ 0x08, 0x30);
+ radeon_i2c_put_byte(tmds->i2c_bus,
tmds->slave_addr,
0x09, 0x00);
- radeon_i2c_sw_put_byte(tmds->i2c_bus,
- tmds->slave_addr,
- 0x0a, 0x90);
- radeon_i2c_sw_put_byte(tmds->i2c_bus,
- tmds->slave_addr,
- 0x0c, 0x89);
- radeon_i2c_sw_put_byte(tmds->i2c_bus,
+ radeon_i2c_put_byte(tmds->i2c_bus,
+ tmds->slave_addr,
+ 0x0a, 0x90);
+ radeon_i2c_put_byte(tmds->i2c_bus,
+ tmds->slave_addr,
+ 0x0c, 0x89);
+ radeon_i2c_put_byte(tmds->i2c_bus,
tmds->slave_addr,
0x08, 0x3b);
- radeon_i2c_do_lock(tmds->i2c_bus, 0);
break;
case DVO_SIL1178:
/* sil 1178 - untested */
@@ -2339,9 +2517,6 @@ bool radeon_combios_external_tmds_setup(struct drm_encoder *encoder)
uint32_t reg, val, and_mask, or_mask;
struct radeon_encoder_ext_tmds *tmds = radeon_encoder->enc_priv;
- if (rdev->bios == NULL)
- return false;
-
if (!tmds)
return false;
@@ -2391,11 +2566,9 @@ bool radeon_combios_external_tmds_setup(struct drm_encoder *encoder)
index++;
val = RBIOS8(index);
index++;
- radeon_i2c_do_lock(tmds->i2c_bus, 1);
- radeon_i2c_sw_put_byte(tmds->i2c_bus,
- slave_addr,
- reg, val);
- radeon_i2c_do_lock(tmds->i2c_bus, 0);
+ radeon_i2c_put_byte(tmds->i2c_bus,
+ slave_addr,
+ reg, val);
break;
default:
DRM_ERROR("Unknown id %d\n", id >> 13);
@@ -2448,11 +2621,9 @@ bool radeon_combios_external_tmds_setup(struct drm_encoder *encoder)
reg = id & 0x1fff;
val = RBIOS8(index);
index += 1;
- radeon_i2c_do_lock(tmds->i2c_bus, 1);
- radeon_i2c_sw_put_byte(tmds->i2c_bus,
- tmds->slave_addr,
- reg, val);
- radeon_i2c_do_lock(tmds->i2c_bus, 0);
+ radeon_i2c_put_byte(tmds->i2c_bus,
+ tmds->slave_addr,
+ reg, val);
break;
default:
DRM_ERROR("Unknown id %d\n", id >> 13);
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 55266416fa47..ee0083f982d8 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -479,10 +479,8 @@ static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connec
ret = connector_status_connected;
else {
if (radeon_connector->ddc_bus) {
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
radeon_connector->edid = drm_get_edid(&radeon_connector->base,
&radeon_connector->ddc_bus->adapter);
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
if (radeon_connector->edid)
ret = connector_status_connected;
}
@@ -580,24 +578,21 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct drm_encoder *encoder;
struct drm_encoder_helper_funcs *encoder_funcs;
- bool dret;
+ bool dret = false;
enum drm_connector_status ret = connector_status_disconnected;
encoder = radeon_best_single_encoder(connector);
if (!encoder)
ret = connector_status_disconnected;
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
- dret = radeon_ddc_probe(radeon_connector);
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
+ if (radeon_connector->ddc_bus)
+ dret = radeon_ddc_probe(radeon_connector);
if (dret) {
if (radeon_connector->edid) {
kfree(radeon_connector->edid);
radeon_connector->edid = NULL;
}
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
if (!radeon_connector->edid) {
DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
@@ -740,19 +735,16 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect
struct drm_mode_object *obj;
int i;
enum drm_connector_status ret = connector_status_disconnected;
- bool dret;
+ bool dret = false;
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
- dret = radeon_ddc_probe(radeon_connector);
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
+ if (radeon_connector->ddc_bus)
+ dret = radeon_ddc_probe(radeon_connector);
if (dret) {
if (radeon_connector->edid) {
kfree(radeon_connector->edid);
radeon_connector->edid = NULL;
}
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
if (!radeon_connector->edid) {
DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
@@ -776,7 +768,7 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect
* connected and the DVI port disconnected. If the edid doesn't
* say HDMI, vice versa.
*/
- if (radeon_connector->shared_ddc && connector_status_connected) {
+ if (radeon_connector->shared_ddc && (ret == connector_status_connected)) {
struct drm_device *dev = connector->dev;
struct drm_connector *list_connector;
struct radeon_connector *list_radeon_connector;
@@ -948,7 +940,7 @@ static void radeon_dp_connector_destroy(struct drm_connector *connector)
if (radeon_connector->edid)
kfree(radeon_connector->edid);
if (radeon_dig_connector->dp_i2c_bus)
- radeon_i2c_destroy(radeon_dig_connector->dp_i2c_bus);
+ radeon_i2c_destroy_dp(radeon_dig_connector->dp_i2c_bus);
kfree(radeon_connector->con_priv);
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
@@ -984,12 +976,10 @@ static enum drm_connector_status radeon_dp_detect(struct drm_connector *connecto
ret = connector_status_connected;
}
} else {
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
if (radeon_ddc_probe(radeon_connector)) {
radeon_dig_connector->dp_sink_type = sink_type;
ret = connector_status_connected;
}
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
}
return ret;
@@ -1056,8 +1046,7 @@ radeon_add_atom_connector(struct drm_device *dev,
return;
}
if (radeon_connector->ddc_bus && i2c_bus->valid) {
- if (memcmp(&radeon_connector->ddc_bus->rec, i2c_bus,
- sizeof(struct radeon_i2c_bus_rec)) == 0) {
+ if (radeon_connector->ddc_bus->rec.i2c_id == i2c_bus->i2c_id) {
radeon_connector->shared_ddc = true;
shared_ddc = true;
}
@@ -1343,7 +1332,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
radeon_connector->dac_load_detect = false;
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.load_detect_property,
- 1);
+ radeon_connector->dac_load_detect);
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.tv_std_property,
radeon_combios_get_tv_info(rdev));
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index 06123ba31d31..dc6eba6b96dd 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -1644,6 +1644,7 @@ static int radeon_do_resume_cp(struct drm_device *dev, struct drm_file *file_pri
radeon_cp_load_microcode(dev_priv);
radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
+ dev_priv->have_z_offset = 0;
radeon_do_engine_reset(dev);
radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index 65590a0f1d93..70ba02ed7723 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -86,7 +86,7 @@ int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
&p->validated);
}
}
- return radeon_bo_list_validate(&p->validated, p->ib->fence);
+ return radeon_bo_list_validate(&p->validated);
}
int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
@@ -189,18 +189,13 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)
{
unsigned i;
- if (error) {
- radeon_bo_list_unvalidate(&parser->validated,
- parser->ib->fence);
- } else {
- radeon_bo_list_unreserve(&parser->validated);
+ if (!error && parser->ib) {
+ radeon_bo_list_fence(&parser->validated, parser->ib->fence);
}
+ radeon_bo_list_unreserve(&parser->validated);
for (i = 0; i < parser->nrelocs; i++) {
- if (parser->relocs[i].gobj) {
- mutex_lock(&parser->rdev->ddev->struct_mutex);
- drm_gem_object_unreference(parser->relocs[i].gobj);
- mutex_unlock(&parser->rdev->ddev->struct_mutex);
- }
+ if (parser->relocs[i].gobj)
+ drm_gem_object_unreference_unlocked(parser->relocs[i].gobj);
}
kfree(parser->track);
kfree(parser->relocs);
@@ -231,6 +226,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
memset(&parser, 0, sizeof(struct radeon_cs_parser));
parser.filp = filp;
parser.rdev = rdev;
+ parser.dev = rdev->dev;
r = radeon_cs_parser_init(&parser, data);
if (r) {
DRM_ERROR("Failed to initialize parser !\n");
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index 28772a37009c..b7023fff89eb 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -36,7 +36,14 @@ static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
uint32_t cur_lock;
- if (ASIC_IS_AVIVO(rdev)) {
+ if (ASIC_IS_DCE4(rdev)) {
+ cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
+ if (lock)
+ cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
+ else
+ cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
+ WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
+ } else if (ASIC_IS_AVIVO(rdev)) {
cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
if (lock)
cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
@@ -58,7 +65,10 @@ static void radeon_hide_cursor(struct drm_crtc *crtc)
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct radeon_device *rdev = crtc->dev->dev_private;
- if (ASIC_IS_AVIVO(rdev)) {
+ if (ASIC_IS_DCE4(rdev)) {
+ WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
+ WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT));
+ } else if (ASIC_IS_AVIVO(rdev)) {
WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
WREG32(RADEON_MM_DATA, (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
} else {
@@ -81,10 +91,14 @@ static void radeon_show_cursor(struct drm_crtc *crtc)
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct radeon_device *rdev = crtc->dev->dev_private;
- if (ASIC_IS_AVIVO(rdev)) {
+ if (ASIC_IS_DCE4(rdev)) {
+ WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
+ WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
+ EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT));
+ } else if (ASIC_IS_AVIVO(rdev)) {
WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
- (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
+ (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
} else {
switch (radeon_crtc->crtc_id) {
case 0:
@@ -109,7 +123,10 @@ static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct radeon_device *rdev = crtc->dev->dev_private;
- if (ASIC_IS_AVIVO(rdev)) {
+ if (ASIC_IS_DCE4(rdev)) {
+ WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 0);
+ WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr);
+ } else if (ASIC_IS_AVIVO(rdev)) {
if (rdev->family >= CHIP_RV770) {
if (radeon_crtc->crtc_id)
WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, 0);
@@ -169,17 +186,13 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc,
unpin:
if (radeon_crtc->cursor_bo) {
radeon_gem_object_unpin(radeon_crtc->cursor_bo);
- mutex_lock(&crtc->dev->struct_mutex);
- drm_gem_object_unreference(radeon_crtc->cursor_bo);
- mutex_unlock(&crtc->dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo);
}
radeon_crtc->cursor_bo = obj;
return 0;
fail:
- mutex_lock(&crtc->dev->struct_mutex);
- drm_gem_object_unreference(obj);
- mutex_unlock(&crtc->dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(obj);
return 0;
}
@@ -201,7 +214,20 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
yorigin = CURSOR_HEIGHT - 1;
radeon_lock_cursor(crtc, true);
- if (ASIC_IS_AVIVO(rdev)) {
+ if (ASIC_IS_DCE4(rdev)) {
+ /* cursors are offset into the total surface */
+ x += crtc->x;
+ y += crtc->y;
+ DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
+
+ /* XXX: check if evergreen has the same issues as avivo chips */
+ WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset,
+ ((xorigin ? 0 : x) << 16) |
+ (yorigin ? 0 : y));
+ WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
+ WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
+ ((radeon_crtc->cursor_width - 1) << 16) | (radeon_crtc->cursor_height - 1));
+ } else if (ASIC_IS_AVIVO(rdev)) {
int w = radeon_crtc->cursor_width;
int i = 0;
struct drm_crtc *crtc_p;
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 0c51f8e46613..e28e4ed5f720 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -30,6 +30,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/radeon_drm.h>
#include <linux/vgaarb.h>
+#include <linux/vga_switcheroo.h>
#include "radeon_reg.h"
#include "radeon.h"
#include "radeon_asic.h"
@@ -100,80 +101,103 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
}
}
-/*
- * MC common functions
+/**
+ * radeon_vram_location - try to find VRAM location
+ * @rdev: radeon device structure holding all necessary informations
+ * @mc: memory controller structure holding memory informations
+ * @base: base address at which to put VRAM
+ *
+ * Function will place try to place VRAM at base address provided
+ * as parameter (which is so far either PCI aperture address or
+ * for IGP TOM base address).
+ *
+ * If there is not enough space to fit the unvisible VRAM in the 32bits
+ * address space then we limit the VRAM size to the aperture.
+ *
+ * If we are using AGP and if the AGP aperture doesn't allow us to have
+ * room for all the VRAM than we restrict the VRAM to the PCI aperture
+ * size and print a warning.
+ *
+ * This function will never fails, worst case are limiting VRAM.
+ *
+ * Note: GTT start, end, size should be initialized before calling this
+ * function on AGP platform.
+ *
+ * Note: We don't explictly enforce VRAM start to be aligned on VRAM size,
+ * this shouldn't be a problem as we are using the PCI aperture as a reference.
+ * Otherwise this would be needed for rv280, all r3xx, and all r4xx, but
+ * not IGP.
+ *
+ * Note: we use mc_vram_size as on some board we need to program the mc to
+ * cover the whole aperture even if VRAM size is inferior to aperture size
+ * Novell bug 204882 + along with lots of ubuntu ones
+ *
+ * Note: when limiting vram it's safe to overwritte real_vram_size because
+ * we are not in case where real_vram_size is inferior to mc_vram_size (ie
+ * note afected by bogus hw of Novell bug 204882 + along with lots of ubuntu
+ * ones)
+ *
+ * Note: IGP TOM addr should be the same as the aperture addr, we don't
+ * explicitly check for that thought.
+ *
+ * FIXME: when reducing VRAM size align new size on power of 2.
*/
-int radeon_mc_setup(struct radeon_device *rdev)
+void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base)
+{
+ mc->vram_start = base;
+ if (mc->mc_vram_size > (0xFFFFFFFF - base + 1)) {
+ dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n");
+ mc->real_vram_size = mc->aper_size;
+ mc->mc_vram_size = mc->aper_size;
+ }
+ mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
+ if (rdev->flags & RADEON_IS_AGP && mc->vram_end > mc->gtt_start && mc->vram_end <= mc->gtt_end) {
+ dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n");
+ mc->real_vram_size = mc->aper_size;
+ mc->mc_vram_size = mc->aper_size;
+ }
+ mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
+ dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n",
+ mc->mc_vram_size >> 20, mc->vram_start,
+ mc->vram_end, mc->real_vram_size >> 20);
+}
+
+/**
+ * radeon_gtt_location - try to find GTT location
+ * @rdev: radeon device structure holding all necessary informations
+ * @mc: memory controller structure holding memory informations
+ *
+ * Function will place try to place GTT before or after VRAM.
+ *
+ * If GTT size is bigger than space left then we ajust GTT size.
+ * Thus function will never fails.
+ *
+ * FIXME: when reducing GTT size align new size on power of 2.
+ */
+void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc)
{
- uint32_t tmp;
+ u64 size_af, size_bf;
- /* Some chips have an "issue" with the memory controller, the
- * location must be aligned to the size. We just align it down,
- * too bad if we walk over the top of system memory, we don't
- * use DMA without a remapped anyway.
- * Affected chips are rv280, all r3xx, and all r4xx, but not IGP
- */
- /* FGLRX seems to setup like this, VRAM a 0, then GART.
- */
- /*
- * Note: from R6xx the address space is 40bits but here we only
- * use 32bits (still have to see a card which would exhaust 4G
- * address space).
- */
- if (rdev->mc.vram_location != 0xFFFFFFFFUL) {
- /* vram location was already setup try to put gtt after
- * if it fits */
- tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size;
- tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1);
- if ((0xFFFFFFFFUL - tmp) >= rdev->mc.gtt_size) {
- rdev->mc.gtt_location = tmp;
- } else {
- if (rdev->mc.gtt_size >= rdev->mc.vram_location) {
- printk(KERN_ERR "[drm] GTT too big to fit "
- "before or after vram location.\n");
- return -EINVAL;
- }
- rdev->mc.gtt_location = 0;
- }
- } else if (rdev->mc.gtt_location != 0xFFFFFFFFUL) {
- /* gtt location was already setup try to put vram before
- * if it fits */
- if (rdev->mc.mc_vram_size < rdev->mc.gtt_location) {
- rdev->mc.vram_location = 0;
- } else {
- tmp = rdev->mc.gtt_location + rdev->mc.gtt_size;
- tmp += (rdev->mc.mc_vram_size - 1);
- tmp &= ~(rdev->mc.mc_vram_size - 1);
- if ((0xFFFFFFFFUL - tmp) >= rdev->mc.mc_vram_size) {
- rdev->mc.vram_location = tmp;
- } else {
- printk(KERN_ERR "[drm] vram too big to fit "
- "before or after GTT location.\n");
- return -EINVAL;
- }
+ size_af = 0xFFFFFFFF - mc->vram_end;
+ size_bf = mc->vram_start;
+ if (size_bf > size_af) {
+ if (mc->gtt_size > size_bf) {
+ dev_warn(rdev->dev, "limiting GTT\n");
+ mc->gtt_size = size_bf;
}
+ mc->gtt_start = mc->vram_start - mc->gtt_size;
} else {
- rdev->mc.vram_location = 0;
- tmp = rdev->mc.mc_vram_size;
- tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1);
- rdev->mc.gtt_location = tmp;
- }
- rdev->mc.vram_start = rdev->mc.vram_location;
- rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
- rdev->mc.gtt_start = rdev->mc.gtt_location;
- rdev->mc.gtt_end = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
- DRM_INFO("radeon: VRAM %uM\n", (unsigned)(rdev->mc.mc_vram_size >> 20));
- DRM_INFO("radeon: VRAM from 0x%08X to 0x%08X\n",
- (unsigned)rdev->mc.vram_location,
- (unsigned)(rdev->mc.vram_location + rdev->mc.mc_vram_size - 1));
- DRM_INFO("radeon: GTT %uM\n", (unsigned)(rdev->mc.gtt_size >> 20));
- DRM_INFO("radeon: GTT from 0x%08X to 0x%08X\n",
- (unsigned)rdev->mc.gtt_location,
- (unsigned)(rdev->mc.gtt_location + rdev->mc.gtt_size - 1));
- return 0;
+ if (mc->gtt_size > size_af) {
+ dev_warn(rdev->dev, "limiting GTT\n");
+ mc->gtt_size = size_af;
+ }
+ mc->gtt_start = mc->vram_end + 1;
+ }
+ mc->gtt_end = mc->gtt_start + mc->gtt_size - 1;
+ dev_info(rdev->dev, "GTT: %lluM 0x%08llX - 0x%08llX\n",
+ mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end);
}
-
/*
* GPU helpers function.
*/
@@ -182,7 +206,16 @@ bool radeon_card_posted(struct radeon_device *rdev)
uint32_t reg;
/* first check CRTCs */
- if (ASIC_IS_AVIVO(rdev)) {
+ if (ASIC_IS_DCE4(rdev)) {
+ reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) |
+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) |
+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) |
+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) |
+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
+ if (reg & EVERGREEN_CRTC_MASTER_EN)
+ return true;
+ } else if (ASIC_IS_AVIVO(rdev)) {
reg = RREG32(AVIVO_D1CRTC_CONTROL) |
RREG32(AVIVO_D2CRTC_CONTROL);
if (reg & AVIVO_CRTC_EN) {
@@ -229,6 +262,8 @@ bool radeon_boot_test_post_card(struct radeon_device *rdev)
int radeon_dummy_page_init(struct radeon_device *rdev)
{
+ if (rdev->dummy_page.page)
+ return 0;
rdev->dummy_page.page = alloc_page(GFP_DMA32 | GFP_KERNEL | __GFP_ZERO);
if (rdev->dummy_page.page == NULL)
return -ENOMEM;
@@ -310,7 +345,7 @@ void radeon_register_accessor_init(struct radeon_device *rdev)
rdev->mc_rreg = &rs600_mc_rreg;
rdev->mc_wreg = &rs600_mc_wreg;
}
- if (rdev->family >= CHIP_R600) {
+ if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_RV740)) {
rdev->pciep_rreg = &r600_pciep_rreg;
rdev->pciep_wreg = &r600_pciep_wreg;
}
@@ -329,21 +364,22 @@ int radeon_asic_init(struct radeon_device *rdev)
case CHIP_RS100:
case CHIP_RV200:
case CHIP_RS200:
+ rdev->asic = &r100_asic;
+ break;
case CHIP_R200:
case CHIP_RV250:
case CHIP_RS300:
case CHIP_RV280:
- rdev->asic = &r100_asic;
+ rdev->asic = &r200_asic;
break;
case CHIP_R300:
case CHIP_R350:
case CHIP_RV350:
case CHIP_RV380:
- rdev->asic = &r300_asic;
- if (rdev->flags & RADEON_IS_PCIE) {
- rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush;
- rdev->asic->gart_set_page = &rv370_pcie_gart_set_page;
- }
+ if (rdev->flags & RADEON_IS_PCIE)
+ rdev->asic = &r300_asic_pcie;
+ else
+ rdev->asic = &r300_asic;
break;
case CHIP_R420:
case CHIP_R423:
@@ -387,6 +423,13 @@ int radeon_asic_init(struct radeon_device *rdev)
case CHIP_RV740:
rdev->asic = &rv770_asic;
break;
+ case CHIP_CEDAR:
+ case CHIP_REDWOOD:
+ case CHIP_JUNIPER:
+ case CHIP_CYPRESS:
+ case CHIP_HEMLOCK:
+ rdev->asic = &evergreen_asic;
+ break;
default:
/* FIXME: not supported yet */
return -EINVAL;
@@ -544,6 +587,7 @@ void radeon_agp_disable(struct radeon_device *rdev)
rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush;
rdev->asic->gart_set_page = &r100_pci_gart_set_page;
}
+ rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
}
void radeon_check_arguments(struct radeon_device *rdev)
@@ -612,6 +656,36 @@ void radeon_check_arguments(struct radeon_device *rdev)
}
}
+static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+ struct radeon_device *rdev = dev->dev_private;
+ pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
+ if (state == VGA_SWITCHEROO_ON) {
+ printk(KERN_INFO "radeon: switched on\n");
+ /* don't suspend or resume card normally */
+ rdev->powered_down = false;
+ radeon_resume_kms(dev);
+ } else {
+ printk(KERN_INFO "radeon: switched off\n");
+ radeon_suspend_kms(dev, pmm);
+ /* don't suspend or resume card normally */
+ rdev->powered_down = true;
+ }
+}
+
+static bool radeon_switcheroo_can_switch(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+ bool can_switch;
+
+ spin_lock(&dev->count_lock);
+ can_switch = (dev->open_count == 0);
+ spin_unlock(&dev->count_lock);
+ return can_switch;
+}
+
+
int radeon_device_init(struct radeon_device *rdev,
struct drm_device *ddev,
struct pci_dev *pdev,
@@ -637,11 +711,14 @@ int radeon_device_init(struct radeon_device *rdev,
mutex_init(&rdev->cs_mutex);
mutex_init(&rdev->ib_pool.mutex);
mutex_init(&rdev->cp.mutex);
+ mutex_init(&rdev->dc_hw_i2c_mutex);
if (rdev->family >= CHIP_R600)
spin_lock_init(&rdev->ih.lock);
mutex_init(&rdev->gem.mutex);
+ mutex_init(&rdev->pm.mutex);
rwlock_init(&rdev->fence_drv.lock);
INIT_LIST_HEAD(&rdev->gem.objects);
+ init_waitqueue_head(&rdev->irq.vblank_queue);
/* setup workqueue */
rdev->wq = create_workqueue("radeon");
@@ -691,6 +768,9 @@ int radeon_device_init(struct radeon_device *rdev,
/* this will fail for cards that aren't VGA class devices, just
* ignore it */
vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode);
+ vga_switcheroo_register_client(rdev->pdev,
+ radeon_switcheroo_set_state,
+ radeon_switcheroo_can_switch);
r = radeon_init(rdev);
if (r)
@@ -722,6 +802,7 @@ void radeon_device_fini(struct radeon_device *rdev)
rdev->shutdown = true;
radeon_fini(rdev);
destroy_workqueue(rdev->wq);
+ vga_switcheroo_unregister_client(rdev->pdev);
vga_client_register(rdev->pdev, NULL, NULL, NULL);
iounmap(rdev->rmmio);
rdev->rmmio = NULL;
@@ -745,6 +826,8 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
}
rdev = dev->dev_private;
+ if (rdev->powered_down)
+ return 0;
/* unpin the front buffers */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb);
@@ -790,6 +873,9 @@ int radeon_resume_kms(struct drm_device *dev)
{
struct radeon_device *rdev = dev->dev_private;
+ if (rdev->powered_down)
+ return 0;
+
acquire_console_sem();
pci_set_power_state(dev->pdev, PCI_D0);
pci_restore_state(dev->pdev);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 0ec491ead2ff..ba8d806dcf39 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -68,6 +68,36 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc)
WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id);
}
+static void evergreen_crtc_load_lut(struct drm_crtc *crtc)
+{
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ int i;
+
+ DRM_DEBUG("%d\n", radeon_crtc->crtc_id);
+ WREG32(EVERGREEN_DC_LUT_CONTROL + radeon_crtc->crtc_offset, 0);
+
+ WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0);
+ WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN + radeon_crtc->crtc_offset, 0);
+ WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_RED + radeon_crtc->crtc_offset, 0);
+
+ WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE + radeon_crtc->crtc_offset, 0xffff);
+ WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN + radeon_crtc->crtc_offset, 0xffff);
+ WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_RED + radeon_crtc->crtc_offset, 0xffff);
+
+ WREG32(EVERGREEN_DC_LUT_RW_MODE, radeon_crtc->crtc_id);
+ WREG32(EVERGREEN_DC_LUT_WRITE_EN_MASK, 0x00000007);
+
+ WREG32(EVERGREEN_DC_LUT_RW_INDEX, 0);
+ for (i = 0; i < 256; i++) {
+ WREG32(EVERGREEN_DC_LUT_30_COLOR,
+ (radeon_crtc->lut_r[i] << 20) |
+ (radeon_crtc->lut_g[i] << 10) |
+ (radeon_crtc->lut_b[i] << 0));
+ }
+}
+
static void legacy_crtc_load_lut(struct drm_crtc *crtc)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
@@ -100,7 +130,9 @@ void radeon_crtc_load_lut(struct drm_crtc *crtc)
if (!crtc->enabled)
return;
- if (ASIC_IS_AVIVO(rdev))
+ if (ASIC_IS_DCE4(rdev))
+ evergreen_crtc_load_lut(crtc);
+ else if (ASIC_IS_AVIVO(rdev))
avivo_crtc_load_lut(crtc);
else
legacy_crtc_load_lut(crtc);
@@ -278,7 +310,7 @@ static void radeon_print_display_setup(struct drm_device *dev)
DRM_INFO(" %s\n", connector_names[connector->connector_type]);
if (radeon_connector->hpd.hpd != RADEON_HPD_NONE)
DRM_INFO(" %s\n", hpd_names[radeon_connector->hpd.hpd]);
- if (radeon_connector->ddc_bus)
+ if (radeon_connector->ddc_bus) {
DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
radeon_connector->ddc_bus->rec.mask_clk_reg,
radeon_connector->ddc_bus->rec.mask_data_reg,
@@ -288,6 +320,15 @@ static void radeon_print_display_setup(struct drm_device *dev)
radeon_connector->ddc_bus->rec.en_data_reg,
radeon_connector->ddc_bus->rec.y_clk_reg,
radeon_connector->ddc_bus->rec.y_data_reg);
+ } else {
+ if (connector->connector_type == DRM_MODE_CONNECTOR_VGA ||
+ connector->connector_type == DRM_MODE_CONNECTOR_DVII ||
+ connector->connector_type == DRM_MODE_CONNECTOR_DVID ||
+ connector->connector_type == DRM_MODE_CONNECTOR_DVIA ||
+ connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
+ connector->connector_type == DRM_MODE_CONNECTOR_HDMIB)
+ DRM_INFO(" DDC: no ddc bus - possible BIOS bug - please report to xorg-driver-ati@lists.x.org\n");
+ }
DRM_INFO(" Encoders:\n");
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
radeon_encoder = to_radeon_encoder(encoder);
@@ -352,22 +393,25 @@ static bool radeon_setup_enc_conn(struct drm_device *dev)
int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
{
+ struct drm_device *dev = radeon_connector->base.dev;
+ struct radeon_device *rdev = dev->dev_private;
int ret = 0;
if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
(radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
- if (dig->dp_i2c_bus)
+ if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
+ dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus)
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &dig->dp_i2c_bus->adapter);
}
if (!radeon_connector->ddc_bus)
return -1;
if (!radeon_connector->edid) {
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
}
-
+ /* some servers provide a hardcoded edid in rom for KVMs */
+ if (!radeon_connector->edid)
+ radeon_connector->edid = radeon_combios_get_hardcoded_edid(rdev);
if (radeon_connector->edid) {
drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
@@ -385,9 +429,7 @@ static int radeon_ddc_dump(struct drm_connector *connector)
if (!radeon_connector->ddc_bus)
return -1;
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter);
- radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
if (edid) {
kfree(edid);
}
@@ -404,17 +446,18 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d)
return n;
}
-void radeon_compute_pll(struct radeon_pll *pll,
- uint64_t freq,
- uint32_t *dot_clock_p,
- uint32_t *fb_div_p,
- uint32_t *frac_fb_div_p,
- uint32_t *ref_div_p,
- uint32_t *post_div_p,
- int flags)
+static void radeon_compute_pll_legacy(struct radeon_pll *pll,
+ uint64_t freq,
+ uint32_t *dot_clock_p,
+ uint32_t *fb_div_p,
+ uint32_t *frac_fb_div_p,
+ uint32_t *ref_div_p,
+ uint32_t *post_div_p)
{
uint32_t min_ref_div = pll->min_ref_div;
uint32_t max_ref_div = pll->max_ref_div;
+ uint32_t min_post_div = pll->min_post_div;
+ uint32_t max_post_div = pll->max_post_div;
uint32_t min_fractional_feed_div = 0;
uint32_t max_fractional_feed_div = 0;
uint32_t best_vco = pll->best_vco;
@@ -430,7 +473,7 @@ void radeon_compute_pll(struct radeon_pll *pll,
DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div);
freq = freq * 1000;
- if (flags & RADEON_PLL_USE_REF_DIV)
+ if (pll->flags & RADEON_PLL_USE_REF_DIV)
min_ref_div = max_ref_div = pll->reference_div;
else {
while (min_ref_div < max_ref_div-1) {
@@ -445,19 +488,22 @@ void radeon_compute_pll(struct radeon_pll *pll,
}
}
- if (flags & RADEON_PLL_USE_FRAC_FB_DIV) {
+ if (pll->flags & RADEON_PLL_USE_POST_DIV)
+ min_post_div = max_post_div = pll->post_div;
+
+ if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
min_fractional_feed_div = pll->min_frac_feedback_div;
max_fractional_feed_div = pll->max_frac_feedback_div;
}
- for (post_div = pll->min_post_div; post_div <= pll->max_post_div; ++post_div) {
+ for (post_div = min_post_div; post_div <= max_post_div; ++post_div) {
uint32_t ref_div;
- if ((flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
+ if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
continue;
/* legacy radeons only have a few post_divs */
- if (flags & RADEON_PLL_LEGACY) {
+ if (pll->flags & RADEON_PLL_LEGACY) {
if ((post_div == 5) ||
(post_div == 7) ||
(post_div == 9) ||
@@ -504,7 +550,7 @@ void radeon_compute_pll(struct radeon_pll *pll,
tmp += (uint64_t)pll->reference_freq * 1000 * frac_feedback_div;
current_freq = radeon_div(tmp, ref_div * post_div);
- if (flags & RADEON_PLL_PREFER_CLOSEST_LOWER) {
+ if (pll->flags & RADEON_PLL_PREFER_CLOSEST_LOWER) {
error = freq - current_freq;
error = error < 0 ? 0xffffffff : error;
} else
@@ -531,12 +577,12 @@ void radeon_compute_pll(struct radeon_pll *pll,
best_freq = current_freq;
best_error = error;
best_vco_diff = vco_diff;
- } else if (((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) ||
- ((flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) ||
- ((flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) ||
- ((flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) ||
- ((flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) ||
- ((flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) {
+ } else if (((pll->flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) ||
+ ((pll->flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) ||
+ ((pll->flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) ||
+ ((pll->flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) ||
+ ((pll->flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) ||
+ ((pll->flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) {
best_post_div = post_div;
best_ref_div = ref_div;
best_feedback_div = feedback_div;
@@ -566,96 +612,194 @@ void radeon_compute_pll(struct radeon_pll *pll,
*post_div_p = best_post_div;
}
-void radeon_compute_pll_avivo(struct radeon_pll *pll,
- uint64_t freq,
- uint32_t *dot_clock_p,
- uint32_t *fb_div_p,
- uint32_t *frac_fb_div_p,
- uint32_t *ref_div_p,
- uint32_t *post_div_p,
- int flags)
+static bool
+calc_fb_div(struct radeon_pll *pll,
+ uint32_t freq,
+ uint32_t post_div,
+ uint32_t ref_div,
+ uint32_t *fb_div,
+ uint32_t *fb_div_frac)
{
- fixed20_12 m, n, frac_n, p, f_vco, f_pclk, best_freq;
- fixed20_12 pll_out_max, pll_out_min;
- fixed20_12 pll_in_max, pll_in_min;
- fixed20_12 reference_freq;
- fixed20_12 error, ffreq, a, b;
-
- pll_out_max.full = rfixed_const(pll->pll_out_max);
- pll_out_min.full = rfixed_const(pll->pll_out_min);
- pll_in_max.full = rfixed_const(pll->pll_in_max);
- pll_in_min.full = rfixed_const(pll->pll_in_min);
- reference_freq.full = rfixed_const(pll->reference_freq);
- do_div(freq, 10);
+ fixed20_12 feedback_divider, a, b;
+ u32 vco_freq;
+
+ vco_freq = freq * post_div;
+ /* feedback_divider = vco_freq * ref_div / pll->reference_freq; */
+ a.full = rfixed_const(pll->reference_freq);
+ feedback_divider.full = rfixed_const(vco_freq);
+ feedback_divider.full = rfixed_div(feedback_divider, a);
+ a.full = rfixed_const(ref_div);
+ feedback_divider.full = rfixed_mul(feedback_divider, a);
+
+ if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
+ /* feedback_divider = floor((feedback_divider * 10.0) + 0.5) * 0.1; */
+ a.full = rfixed_const(10);
+ feedback_divider.full = rfixed_mul(feedback_divider, a);
+ feedback_divider.full += rfixed_const_half(0);
+ feedback_divider.full = rfixed_floor(feedback_divider);
+ feedback_divider.full = rfixed_div(feedback_divider, a);
+
+ /* *fb_div = floor(feedback_divider); */
+ a.full = rfixed_floor(feedback_divider);
+ *fb_div = rfixed_trunc(a);
+ /* *fb_div_frac = fmod(feedback_divider, 1.0) * 10.0; */
+ a.full = rfixed_const(10);
+ b.full = rfixed_mul(feedback_divider, a);
+
+ feedback_divider.full = rfixed_floor(feedback_divider);
+ feedback_divider.full = rfixed_mul(feedback_divider, a);
+ feedback_divider.full = b.full - feedback_divider.full;
+ *fb_div_frac = rfixed_trunc(feedback_divider);
+ } else {
+ /* *fb_div = floor(feedback_divider + 0.5); */
+ feedback_divider.full += rfixed_const_half(0);
+ feedback_divider.full = rfixed_floor(feedback_divider);
+
+ *fb_div = rfixed_trunc(feedback_divider);
+ *fb_div_frac = 0;
+ }
+
+ if (((*fb_div) < pll->min_feedback_div) || ((*fb_div) > pll->max_feedback_div))
+ return false;
+ else
+ return true;
+}
+
+static bool
+calc_fb_ref_div(struct radeon_pll *pll,
+ uint32_t freq,
+ uint32_t post_div,
+ uint32_t *fb_div,
+ uint32_t *fb_div_frac,
+ uint32_t *ref_div)
+{
+ fixed20_12 ffreq, max_error, error, pll_out, a;
+ u32 vco;
+
ffreq.full = rfixed_const(freq);
- error.full = rfixed_const(100 * 100);
+ /* max_error = ffreq * 0.0025; */
+ a.full = rfixed_const(400);
+ max_error.full = rfixed_div(ffreq, a);
+
+ for ((*ref_div) = pll->min_ref_div; (*ref_div) < pll->max_ref_div; ++(*ref_div)) {
+ if (calc_fb_div(pll, freq, post_div, (*ref_div), fb_div, fb_div_frac)) {
+ vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac));
+ vco = vco / ((*ref_div) * 10);
+
+ if ((vco < pll->pll_out_min) || (vco > pll->pll_out_max))
+ continue;
- /* max p */
- p.full = rfixed_div(pll_out_max, ffreq);
- p.full = rfixed_floor(p);
+ /* pll_out = vco / post_div; */
+ a.full = rfixed_const(post_div);
+ pll_out.full = rfixed_const(vco);
+ pll_out.full = rfixed_div(pll_out, a);
- /* min m */
- m.full = rfixed_div(reference_freq, pll_in_max);
- m.full = rfixed_ceil(m);
+ if (pll_out.full >= ffreq.full) {
+ error.full = pll_out.full - ffreq.full;
+ if (error.full <= max_error.full)
+ return true;
+ }
+ }
+ }
+ return false;
+}
- while (1) {
- n.full = rfixed_div(ffreq, reference_freq);
- n.full = rfixed_mul(n, m);
- n.full = rfixed_mul(n, p);
+static void radeon_compute_pll_new(struct radeon_pll *pll,
+ uint64_t freq,
+ uint32_t *dot_clock_p,
+ uint32_t *fb_div_p,
+ uint32_t *frac_fb_div_p,
+ uint32_t *ref_div_p,
+ uint32_t *post_div_p)
+{
+ u32 fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0;
+ u32 best_freq = 0, vco_frequency;
- f_vco.full = rfixed_div(n, m);
- f_vco.full = rfixed_mul(f_vco, reference_freq);
+ /* freq = freq / 10; */
+ do_div(freq, 10);
- f_pclk.full = rfixed_div(f_vco, p);
+ if (pll->flags & RADEON_PLL_USE_POST_DIV) {
+ post_div = pll->post_div;
+ if ((post_div < pll->min_post_div) || (post_div > pll->max_post_div))
+ goto done;
+
+ vco_frequency = freq * post_div;
+ if ((vco_frequency < pll->pll_out_min) || (vco_frequency > pll->pll_out_max))
+ goto done;
+
+ if (pll->flags & RADEON_PLL_USE_REF_DIV) {
+ ref_div = pll->reference_div;
+ if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
+ goto done;
+ if (!calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
+ goto done;
+ }
+ } else {
+ for (post_div = pll->max_post_div; post_div >= pll->min_post_div; --post_div) {
+ if (pll->flags & RADEON_PLL_LEGACY) {
+ if ((post_div == 5) ||
+ (post_div == 7) ||
+ (post_div == 9) ||
+ (post_div == 10) ||
+ (post_div == 11))
+ continue;
+ }
- if (f_pclk.full > ffreq.full)
- error.full = f_pclk.full - ffreq.full;
- else
- error.full = ffreq.full - f_pclk.full;
- error.full = rfixed_div(error, f_pclk);
- a.full = rfixed_const(100 * 100);
- error.full = rfixed_mul(error, a);
-
- a.full = rfixed_mul(m, p);
- a.full = rfixed_div(n, a);
- best_freq.full = rfixed_mul(reference_freq, a);
-
- if (rfixed_trunc(error) < 25)
- break;
-
- a.full = rfixed_const(1);
- m.full = m.full + a.full;
- a.full = rfixed_div(reference_freq, m);
- if (a.full >= pll_in_min.full)
- continue;
+ if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
+ continue;
- m.full = rfixed_div(reference_freq, pll_in_max);
- m.full = rfixed_ceil(m);
- a.full= rfixed_const(1);
- p.full = p.full - a.full;
- a.full = rfixed_mul(p, ffreq);
- if (a.full >= pll_out_min.full)
- continue;
- else {
- DRM_ERROR("Unable to find pll dividers\n");
- break;
+ vco_frequency = freq * post_div;
+ if ((vco_frequency < pll->pll_out_min) || (vco_frequency > pll->pll_out_max))
+ continue;
+ if (pll->flags & RADEON_PLL_USE_REF_DIV) {
+ ref_div = pll->reference_div;
+ if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
+ goto done;
+ if (calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
+ break;
+ } else {
+ if (calc_fb_ref_div(pll, freq, post_div, &fb_div, &fb_div_frac, &ref_div))
+ break;
+ }
}
}
- a.full = rfixed_const(10);
- b.full = rfixed_mul(n, a);
+ best_freq = pll->reference_freq * 10 * fb_div;
+ best_freq += pll->reference_freq * fb_div_frac;
+ best_freq = best_freq / (ref_div * post_div);
- frac_n.full = rfixed_floor(n);
- frac_n.full = rfixed_mul(frac_n, a);
- frac_n.full = b.full - frac_n.full;
+done:
+ if (best_freq == 0)
+ DRM_ERROR("Couldn't find valid PLL dividers\n");
- *dot_clock_p = rfixed_trunc(best_freq);
- *fb_div_p = rfixed_trunc(n);
- *frac_fb_div_p = rfixed_trunc(frac_n);
- *ref_div_p = rfixed_trunc(m);
- *post_div_p = rfixed_trunc(p);
+ *dot_clock_p = best_freq / 10;
+ *fb_div_p = fb_div;
+ *frac_fb_div_p = fb_div_frac;
+ *ref_div_p = ref_div;
+ *post_div_p = post_div;
+
+ DRM_DEBUG("%u %d.%d, %d, %d\n", *dot_clock_p, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p);
+}
- DRM_DEBUG("%u %d.%d, %d, %d\n", *dot_clock_p * 10, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p);
+void radeon_compute_pll(struct radeon_pll *pll,
+ uint64_t freq,
+ uint32_t *dot_clock_p,
+ uint32_t *fb_div_p,
+ uint32_t *frac_fb_div_p,
+ uint32_t *ref_div_p,
+ uint32_t *post_div_p)
+{
+ switch (pll->algo) {
+ case PLL_ALGO_NEW:
+ radeon_compute_pll_new(pll, freq, dot_clock_p, fb_div_p,
+ frac_fb_div_p, ref_div_p, post_div_p);
+ break;
+ case PLL_ALGO_LEGACY:
+ default:
+ radeon_compute_pll_legacy(pll, freq, dot_clock_p, fb_div_p,
+ frac_fb_div_p, ref_div_p, post_div_p);
+ break;
+ }
}
static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
@@ -666,12 +810,8 @@ static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
if (fb->fbdev)
radeonfb_remove(dev, fb);
- if (radeon_fb->obj) {
- radeon_gem_object_unpin(radeon_fb->obj);
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(radeon_fb->obj);
- mutex_unlock(&dev->struct_mutex);
- }
+ if (radeon_fb->obj)
+ drm_gem_object_unreference_unlocked(radeon_fb->obj);
drm_framebuffer_cleanup(fb);
kfree(radeon_fb);
}
@@ -715,7 +855,11 @@ radeon_user_framebuffer_create(struct drm_device *dev,
struct drm_gem_object *obj;
obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
-
+ if (obj == NULL) {
+ dev_err(&dev->pdev->dev, "No GEM object associated to handle 0x%08X, "
+ "can't create framebuffer\n", mode_cmd->handle);
+ return NULL;
+ }
return radeon_framebuffer_create(dev, mode_cmd, obj);
}
@@ -803,7 +947,7 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)
int radeon_modeset_init(struct radeon_device *rdev)
{
- int num_crtc = 2, i;
+ int i;
int ret;
drm_mode_config_init(rdev->ddev);
@@ -826,11 +970,23 @@ int radeon_modeset_init(struct radeon_device *rdev)
return ret;
}
+ /* check combios for a valid hardcoded EDID - Sun servers */
+ if (!rdev->is_atom_bios) {
+ /* check for hardcoded EDID in BIOS */
+ radeon_combios_check_hardcoded_edid(rdev);
+ }
+
if (rdev->flags & RADEON_SINGLE_CRTC)
- num_crtc = 1;
+ rdev->num_crtc = 1;
+ else {
+ if (ASIC_IS_DCE4(rdev))
+ rdev->num_crtc = 6;
+ else
+ rdev->num_crtc = 2;
+ }
/* allocate crtcs */
- for (i = 0; i < num_crtc; i++) {
+ for (i = 0; i < rdev->num_crtc; i++) {
radeon_crtc_init(rdev->ddev, i);
}
@@ -847,6 +1003,8 @@ int radeon_modeset_init(struct radeon_device *rdev)
void radeon_modeset_fini(struct radeon_device *rdev)
{
+ kfree(rdev->mode_info.bios_hardcoded_edid);
+
if (rdev->mode_info.mode_config_initialized) {
radeon_hpd_fini(rdev);
drm_mode_config_cleanup(rdev->ddev);
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 8ba3de7994d4..6eec0ece6a6c 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -40,9 +40,11 @@
/*
* KMS wrapper.
+ * - 2.0.0 - initial interface
+ * - 2.1.0 - add square tiling interface
*/
#define KMS_DRIVER_MAJOR 2
-#define KMS_DRIVER_MINOR 0
+#define KMS_DRIVER_MINOR 1
#define KMS_DRIVER_PATCHLEVEL 0
int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
int radeon_driver_unload_kms(struct drm_device *dev);
@@ -86,7 +88,8 @@ int radeon_benchmarking = 0;
int radeon_testing = 0;
int radeon_connector_table = 0;
int radeon_tv = 1;
-int radeon_new_pll = 1;
+int radeon_new_pll = -1;
+int radeon_dynpm = -1;
int radeon_audio = 1;
MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
@@ -122,9 +125,12 @@ module_param_named(connector_table, radeon_connector_table, int, 0444);
MODULE_PARM_DESC(tv, "TV enable (0 = disable)");
module_param_named(tv, radeon_tv, int, 0444);
-MODULE_PARM_DESC(new_pll, "Select new PLL code for AVIVO chips");
+MODULE_PARM_DESC(new_pll, "Select new PLL code");
module_param_named(new_pll, radeon_new_pll, int, 0444);
+MODULE_PARM_DESC(dynpm, "Disable/Enable dynamic power management (1 = enable)");
+module_param_named(dynpm, radeon_dynpm, int, 0444);
+
MODULE_PARM_DESC(audio, "Audio enable (0 = disable)");
module_param_named(audio, radeon_audio, int, 0444);
@@ -339,6 +345,7 @@ static int __init radeon_init(void)
driver = &kms_driver;
driver->driver_features |= DRIVER_MODESET;
driver->num_ioctls = radeon_max_kms_ioctl;
+ radeon_register_atpx_handler();
}
/* if the vga console setting is enabled still
* let modprobe override it */
@@ -348,6 +355,7 @@ static int __init radeon_init(void)
static void __exit radeon_exit(void)
{
drm_exit(driver);
+ radeon_unregister_atpx_handler();
}
module_init(radeon_init);
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h
index e13785282a82..ec55f2b23c22 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.h
+++ b/drivers/gpu/drm/radeon/radeon_drv.h
@@ -106,9 +106,10 @@
* 1.29- R500 3D cmd buffer support
* 1.30- Add support for occlusion queries
* 1.31- Add support for num Z pipes from GET_PARAM
+ * 1.32- fixes for rv740 setup
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 31
+#define DRIVER_MINOR 32
#define DRIVER_PATCHLEVEL 0
enum radeon_cp_microcode_version {
@@ -267,6 +268,8 @@ typedef struct drm_radeon_private {
u32 scratch_ages[5];
+ int have_z_offset;
+
/* starting from here on, data is preserved accross an open */
uint32_t flags; /* see radeon_chip_flags */
resource_size_t fb_aper_offset;
@@ -294,6 +297,9 @@ typedef struct drm_radeon_private {
int r700_sc_prim_fifo_size;
int r700_sc_hiz_tile_fifo_size;
int r700_sc_earlyz_tile_fifo_fize;
+ int r600_group_size;
+ int r600_npipes;
+ int r600_nbanks;
struct mutex cs_mutex;
u32 cs_id_scnt;
@@ -309,9 +315,11 @@ typedef struct drm_radeon_buf_priv {
u32 age;
} drm_radeon_buf_priv_t;
+struct drm_buffer;
+
typedef struct drm_radeon_kcmd_buffer {
int bufsz;
- char *buf;
+ struct drm_buffer *buffer;
int nbox;
struct drm_clip_rect __user *boxes;
} drm_radeon_kcmd_buffer_t;
@@ -454,6 +462,15 @@ extern void r600_blit_swap(struct drm_device *dev,
int sx, int sy, int dx, int dy,
int w, int h, int src_pitch, int dst_pitch, int cpp);
+/* atpx handler */
+#if defined(CONFIG_VGA_SWITCHEROO)
+void radeon_register_atpx_handler(void);
+void radeon_unregister_atpx_handler(void);
+#else
+static inline void radeon_register_atpx_handler(void) {}
+static inline void radeon_unregister_atpx_handler(void) {}
+#endif
+
/* Flags for stats.boxes
*/
#define RADEON_BOX_DMA_IDLE 0x1
@@ -2121,4 +2138,32 @@ extern void radeon_commit_ring(drm_radeon_private_t *dev_priv);
write &= mask; \
} while (0)
+/**
+ * Copy given number of dwords from drm buffer to the ring buffer.
+ */
+#define OUT_RING_DRM_BUFFER(buf, sz) do { \
+ int _size = (sz) * 4; \
+ struct drm_buffer *_buf = (buf); \
+ int _part_size; \
+ while (_size > 0) { \
+ _part_size = _size; \
+ \
+ if (write + _part_size/4 > mask) \
+ _part_size = ((mask + 1) - write)*4; \
+ \
+ if (drm_buffer_index(_buf) + _part_size > PAGE_SIZE) \
+ _part_size = PAGE_SIZE - drm_buffer_index(_buf);\
+ \
+ \
+ \
+ memcpy(ring + write, &_buf->data[drm_buffer_page(_buf)] \
+ [drm_buffer_index(_buf)], _part_size); \
+ \
+ _size -= _part_size; \
+ write = (write + _part_size/4) & mask; \
+ drm_buffer_advance(_buf, _part_size); \
+ } \
+} while (0)
+
+
#endif /* __RADEON_DRV_H__ */
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index 82eb551970b9..bc926ea0a530 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -53,7 +53,7 @@ static uint32_t radeon_encoder_clones(struct drm_encoder *encoder)
/* DVO requires 2x ppll clocks depending on tmds chip */
if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT)
return index_mask;
-
+
count = -1;
list_for_each_entry(clone_encoder, &dev->mode_config.encoder_list, head) {
struct radeon_encoder *radeon_clone = to_radeon_encoder(clone_encoder);
@@ -156,6 +156,26 @@ radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t
return ret;
}
+static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder)
+{
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ switch (radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_LVDS:
+ case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
+ case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+ case ENCODER_OBJECT_ID_INTERNAL_DVO1:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ case ENCODER_OBJECT_ID_INTERNAL_DDI:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ return true;
+ default:
+ return false;
+ }
+}
void
radeon_link_encoder_connector(struct drm_device *dev)
{
@@ -202,12 +222,38 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder)
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
radeon_connector = to_radeon_connector(connector);
- if (radeon_encoder->devices & radeon_connector->devices)
+ if (radeon_encoder->active_device & radeon_connector->devices)
return connector;
}
return NULL;
}
+static struct radeon_connector_atom_dig *
+radeon_get_atom_connector_priv_from_encoder(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct drm_connector *connector;
+ struct radeon_connector *radeon_connector;
+ struct radeon_connector_atom_dig *dig_connector;
+
+ if (!rdev->is_atom_bios)
+ return NULL;
+
+ connector = radeon_get_connector_for_encoder(encoder);
+ if (!connector)
+ return NULL;
+
+ radeon_connector = to_radeon_connector(connector);
+
+ if (!radeon_connector->con_priv)
+ return NULL;
+
+ dig_connector = radeon_connector->con_priv;
+
+ return dig_connector;
+}
+
static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -216,6 +262,9 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
+ /* adjust pm to upcoming mode change */
+ radeon_pm_compute_clocks(rdev);
+
/* set the active encoder to connector routing */
radeon_encoder_set_active_device(encoder);
drm_mode_set_crtcinfo(adjusted_mode, 0);
@@ -438,34 +487,20 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ struct radeon_connector_atom_dig *dig_connector =
+ radeon_get_atom_connector_priv_from_encoder(encoder);
union lvds_encoder_control args;
int index = 0;
int hdmi_detected = 0;
uint8_t frev, crev;
- struct radeon_encoder_atom_dig *dig;
- struct drm_connector *connector;
- struct radeon_connector *radeon_connector;
- struct radeon_connector_atom_dig *dig_connector;
-
- connector = radeon_get_connector_for_encoder(encoder);
- if (!connector)
- return;
-
- radeon_connector = to_radeon_connector(connector);
- if (!radeon_encoder->enc_priv)
+ if (!dig || !dig_connector)
return;
- dig = radeon_encoder->enc_priv;
-
- if (!radeon_connector->con_priv)
- return;
-
- if (drm_detect_hdmi_monitor(radeon_connector->edid))
+ if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI)
hdmi_detected = 1;
- dig_connector = radeon_connector->con_priv;
-
memset(&args, 0, sizeof(args));
switch (radeon_encoder->encoder_id) {
@@ -566,7 +601,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
{
struct drm_connector *connector;
struct radeon_connector *radeon_connector;
- struct radeon_connector_atom_dig *radeon_dig_connector;
+ struct radeon_connector_atom_dig *dig_connector;
connector = radeon_get_connector_for_encoder(encoder);
if (!connector)
@@ -597,9 +632,9 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
break;
case DRM_MODE_CONNECTOR_DisplayPort:
case DRM_MODE_CONNECTOR_eDP:
- radeon_dig_connector = radeon_connector->con_priv;
- if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
- (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
+ dig_connector = radeon_connector->con_priv;
+ if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
+ (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
return ATOM_ENCODER_MODE_DP;
else if (drm_detect_hdmi_monitor(radeon_connector->edid))
return ATOM_ENCODER_MODE_HDMI;
@@ -636,6 +671,18 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
* - 2 DIG encoder blocks.
* DIG1/2 can drive UNIPHY0/1/2 link A or link B
*
+ * DCE 4.0
+ * - 3 DIG transmitter blocks UNPHY0/1/2 (links A and B).
+ * Supports up to 6 digital outputs
+ * - 6 DIG encoder blocks.
+ * - DIG to PHY mapping is hardcoded
+ * DIG1 drives UNIPHY0 link A, A+B
+ * DIG2 drives UNIPHY0 link B
+ * DIG3 drives UNIPHY1 link A, A+B
+ * DIG4 drives UNIPHY1 link B
+ * DIG5 drives UNIPHY2 link A, A+B
+ * DIG6 drives UNIPHY2 link B
+ *
* Routing
* crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links)
* Examples:
@@ -644,108 +691,78 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
* crtc0 -> dig1 -> UNIPHY2 link A -> LVDS
* crtc1 -> dig2 -> UNIPHY1 link B+A -> TMDS/HDMI
*/
-static void
+
+union dig_encoder_control {
+ DIG_ENCODER_CONTROL_PS_ALLOCATION v1;
+ DIG_ENCODER_CONTROL_PARAMETERS_V2 v2;
+ DIG_ENCODER_CONTROL_PARAMETERS_V3 v3;
+};
+
+void
atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- DIG_ENCODER_CONTROL_PS_ALLOCATION args;
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ struct radeon_connector_atom_dig *dig_connector =
+ radeon_get_atom_connector_priv_from_encoder(encoder);
+ union dig_encoder_control args;
int index = 0, num = 0;
uint8_t frev, crev;
- struct radeon_encoder_atom_dig *dig;
- struct drm_connector *connector;
- struct radeon_connector *radeon_connector;
- struct radeon_connector_atom_dig *dig_connector;
- connector = radeon_get_connector_for_encoder(encoder);
- if (!connector)
+ if (!dig || !dig_connector)
return;
- radeon_connector = to_radeon_connector(connector);
-
- if (!radeon_connector->con_priv)
- return;
-
- dig_connector = radeon_connector->con_priv;
-
- if (!radeon_encoder->enc_priv)
- return;
-
- dig = radeon_encoder->enc_priv;
-
memset(&args, 0, sizeof(args));
- if (ASIC_IS_DCE32(rdev)) {
- if (dig->dig_block)
+ if (ASIC_IS_DCE4(rdev))
+ index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl);
+ else {
+ if (dig->dig_encoder)
index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
else
index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
- num = dig->dig_block + 1;
- } else {
- switch (radeon_encoder->encoder_id) {
- case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
- /* XXX doesn't really matter which dig encoder we pick as long as it's
- * not already in use
- */
- if (dig_connector->linkb)
- index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
- else
- index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
- num = 1;
- break;
- case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
- /* Only dig2 encoder can drive LVTMA */
- index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
- num = 2;
- break;
- }
}
+ num = dig->dig_encoder + 1;
atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev);
- args.ucAction = action;
- args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+ args.v1.ucAction = action;
+ args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+ args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder);
- if (ASIC_IS_DCE32(rdev)) {
+ if (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
+ if (dig_connector->dp_clock == 270000)
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
+ args.v1.ucLaneNum = dig_connector->dp_lane_count;
+ } else if (radeon_encoder->pixel_clock > 165000)
+ args.v1.ucLaneNum = 8;
+ else
+ args.v1.ucLaneNum = 4;
+
+ if (ASIC_IS_DCE4(rdev)) {
+ args.v3.acConfig.ucDigSel = dig->dig_encoder;
+ args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+ } else {
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
- args.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
+ args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
- args.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2;
break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
- args.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3;
- break;
- }
- } else {
- switch (radeon_encoder->encoder_id) {
- case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
- args.ucConfig = ATOM_ENCODER_CONFIG_TRANSMITTER1;
- break;
- case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
- args.ucConfig = ATOM_ENCODER_CONFIG_TRANSMITTER2;
+ args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3;
break;
}
+ if (dig_connector->linkb)
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
+ else
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
}
- args.ucEncoderMode = atombios_get_encoder_mode(encoder);
-
- if (args.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
- if (dig_connector->dp_clock == 270000)
- args.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
- args.ucLaneNum = dig_connector->dp_lane_count;
- } else if (radeon_encoder->pixel_clock > 165000)
- args.ucLaneNum = 8;
- else
- args.ucLaneNum = 4;
-
- if (dig_connector->linkb)
- args.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
- else
- args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
-
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
@@ -753,6 +770,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
union dig_transmitter_control {
DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
+ DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3;
};
void
@@ -761,37 +779,29 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ struct radeon_connector_atom_dig *dig_connector =
+ radeon_get_atom_connector_priv_from_encoder(encoder);
+ struct drm_connector *connector;
+ struct radeon_connector *radeon_connector;
union dig_transmitter_control args;
int index = 0, num = 0;
uint8_t frev, crev;
- struct radeon_encoder_atom_dig *dig;
- struct drm_connector *connector;
- struct radeon_connector *radeon_connector;
- struct radeon_connector_atom_dig *dig_connector;
bool is_dp = false;
+ int pll_id = 0;
- connector = radeon_get_connector_for_encoder(encoder);
- if (!connector)
+ if (!dig || !dig_connector)
return;
+ connector = radeon_get_connector_for_encoder(encoder);
radeon_connector = to_radeon_connector(connector);
- if (!radeon_encoder->enc_priv)
- return;
-
- dig = radeon_encoder->enc_priv;
-
- if (!radeon_connector->con_priv)
- return;
-
- dig_connector = radeon_connector->con_priv;
-
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP)
is_dp = true;
memset(&args, 0, sizeof(args));
- if (ASIC_IS_DCE32(rdev))
+ if (ASIC_IS_DCE32(rdev) || ASIC_IS_DCE4(rdev))
index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
else {
switch (radeon_encoder->encoder_id) {
@@ -821,8 +831,55 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
else
args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
}
- if (ASIC_IS_DCE32(rdev)) {
- if (dig->dig_block)
+ if (ASIC_IS_DCE4(rdev)) {
+ if (is_dp)
+ args.v3.ucLaneNum = dig_connector->dp_lane_count;
+ else if (radeon_encoder->pixel_clock > 165000)
+ args.v3.ucLaneNum = 8;
+ else
+ args.v3.ucLaneNum = 4;
+
+ if (dig_connector->linkb) {
+ args.v3.acConfig.ucLinkSel = 1;
+ args.v3.acConfig.ucEncoderSel = 1;
+ }
+
+ /* Select the PLL for the PHY
+ * DP PHY should be clocked from external src if there is
+ * one.
+ */
+ if (encoder->crtc) {
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+ pll_id = radeon_crtc->pll_id;
+ }
+ if (is_dp && rdev->clock.dp_extclk)
+ args.v3.acConfig.ucRefClkSource = 2; /* external src */
+ else
+ args.v3.acConfig.ucRefClkSource = pll_id;
+
+ switch (radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ args.v3.acConfig.ucTransmitterSel = 0;
+ num = 0;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ args.v3.acConfig.ucTransmitterSel = 1;
+ num = 1;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ args.v3.acConfig.ucTransmitterSel = 2;
+ num = 2;
+ break;
+ }
+
+ if (is_dp)
+ args.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */
+ else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+ if (dig->coherent_mode)
+ args.v3.acConfig.fCoherentMode = 1;
+ }
+ } else if (ASIC_IS_DCE32(rdev)) {
+ if (dig->dig_encoder == 1)
args.v2.acConfig.ucEncoderSel = 1;
if (dig_connector->linkb)
args.v2.acConfig.ucLinkSel = 1;
@@ -851,15 +908,13 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
} else {
args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
+ if (dig->dig_encoder)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
+ else
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
+
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
- /* XXX doesn't really matter which dig encoder we pick as long as it's
- * not already in use
- */
- if (dig_connector->linkb)
- args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
- else
- args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
if (rdev->flags & RADEON_IS_IGP) {
if (radeon_encoder->pixel_clock > 165000) {
if (dig_connector->igp_lane_info & 0x3)
@@ -878,10 +933,6 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
}
}
break;
- case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
- /* Only dig2 encoder can drive LVTMA */
- args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
- break;
}
if (radeon_encoder->pixel_clock > 165000)
@@ -1029,9 +1080,12 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+
+ /* adjust pm to dpms change */
+ radeon_pm_compute_clocks(rdev);
}
-union crtc_sourc_param {
+union crtc_source_param {
SELECT_CRTC_SOURCE_PS_ALLOCATION v1;
SELECT_CRTC_SOURCE_PARAMETERS_V2 v2;
};
@@ -1043,9 +1097,10 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
- union crtc_sourc_param args;
+ union crtc_source_param args;
int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
uint8_t frev, crev;
+ struct radeon_encoder_atom_dig *dig;
memset(&args, 0, sizeof(args));
@@ -1109,40 +1164,32 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
- if (ASIC_IS_DCE32(rdev)) {
- if (radeon_crtc->crtc_id)
- args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
- else
- args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
- } else {
- struct drm_connector *connector;
- struct radeon_connector *radeon_connector;
- struct radeon_connector_atom_dig *dig_connector;
-
- connector = radeon_get_connector_for_encoder(encoder);
- if (!connector)
- return;
- radeon_connector = to_radeon_connector(connector);
- if (!radeon_connector->con_priv)
- return;
- dig_connector = radeon_connector->con_priv;
-
- /* XXX doesn't really matter which dig encoder we pick as long as it's
- * not already in use
- */
- if (dig_connector->linkb)
- args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
- else
- args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ dig = radeon_encoder->enc_priv;
+ switch (dig->dig_encoder) {
+ case 0:
+ args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
+ break;
+ case 1:
+ args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
+ break;
+ case 2:
+ args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
+ break;
+ case 3:
+ args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
+ break;
+ case 4:
+ args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
+ break;
+ case 5:
+ args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
+ break;
}
break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID;
break;
- case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
- /* Only dig2 encoder can drive LVTMA */
- args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
- break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
@@ -1195,6 +1242,7 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
}
/* set scaler clears this on some chips */
+ /* XXX check DCE4 */
if (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))) {
if (ASIC_IS_AVIVO(rdev) && (mode->flags & DRM_MODE_FLAG_INTERLACE))
WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
@@ -1202,6 +1250,74 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
}
}
+static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_encoder *test_encoder;
+ struct radeon_encoder_atom_dig *dig;
+ uint32_t dig_enc_in_use = 0;
+
+ if (ASIC_IS_DCE4(rdev)) {
+ struct radeon_connector_atom_dig *dig_connector =
+ radeon_get_atom_connector_priv_from_encoder(encoder);
+
+ switch (radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ if (dig_connector->linkb)
+ return 1;
+ else
+ return 0;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ if (dig_connector->linkb)
+ return 3;
+ else
+ return 2;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ if (dig_connector->linkb)
+ return 5;
+ else
+ return 4;
+ break;
+ }
+ }
+
+ /* on DCE32 and encoder can driver any block so just crtc id */
+ if (ASIC_IS_DCE32(rdev)) {
+ return radeon_crtc->crtc_id;
+ }
+
+ /* on DCE3 - LVTMA can only be driven by DIGB */
+ list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
+ struct radeon_encoder *radeon_test_encoder;
+
+ if (encoder == test_encoder)
+ continue;
+
+ if (!radeon_encoder_is_digital(test_encoder))
+ continue;
+
+ radeon_test_encoder = to_radeon_encoder(test_encoder);
+ dig = radeon_test_encoder->enc_priv;
+
+ if (dig->dig_encoder >= 0)
+ dig_enc_in_use |= (1 << dig->dig_encoder);
+ }
+
+ if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) {
+ if (dig_enc_in_use & 0x2)
+ DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n");
+ return 1;
+ }
+ if (!(dig_enc_in_use & 1))
+ return 0;
+ return 1;
+}
+
static void
radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
@@ -1214,12 +1330,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
if (radeon_encoder->active_device &
(ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) {
- if (radeon_encoder->enc_priv) {
- struct radeon_encoder_atom_dig *dig;
-
- dig = radeon_encoder->enc_priv;
- dig->dig_block = radeon_crtc->crtc_id;
- }
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ if (dig)
+ dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
}
radeon_encoder->pixel_clock = adjusted_mode->clock;
@@ -1244,15 +1357,26 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
- /* disable the encoder and transmitter */
- atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
- atombios_dig_encoder_setup(encoder, ATOM_DISABLE);
-
- /* setup and enable the encoder and transmitter */
- atombios_dig_encoder_setup(encoder, ATOM_ENABLE);
- atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
- atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
- atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
+ if (ASIC_IS_DCE4(rdev)) {
+ /* disable the transmitter */
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
+ /* setup and enable the encoder */
+ atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP);
+
+ /* init and enable the transmitter */
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
+ } else {
+ /* disable the encoder and transmitter */
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
+ atombios_dig_encoder_setup(encoder, ATOM_DISABLE);
+
+ /* setup and enable the encoder and transmitter */
+ atombios_dig_encoder_setup(encoder, ATOM_ENABLE);
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
+ }
break;
case ENCODER_OBJECT_ID_INTERNAL_DDI:
atombios_ddia_setup(encoder, ATOM_ENABLE);
@@ -1272,7 +1396,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
}
atombios_apply_encoder_quirks(encoder, adjusted_mode);
- r600_hdmi_setmode(encoder, adjusted_mode);
+ /* XXX */
+ if (!ASIC_IS_DCE4(rdev))
+ r600_hdmi_setmode(encoder, adjusted_mode);
}
static bool
@@ -1379,7 +1505,13 @@ static void radeon_atom_encoder_commit(struct drm_encoder *encoder)
static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig;
radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+ if (radeon_encoder_is_digital(encoder)) {
+ dig = radeon_encoder->enc_priv;
+ dig->dig_encoder = -1;
+ }
radeon_encoder->active_device = 0;
}
@@ -1436,6 +1568,7 @@ radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder)
/* coherent mode by default */
dig->coherent_mode = true;
+ dig->dig_encoder = -1;
return dig;
}
@@ -1463,10 +1596,18 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su
return;
encoder = &radeon_encoder->base;
- if (rdev->flags & RADEON_SINGLE_CRTC)
+ switch (rdev->num_crtc) {
+ case 1:
encoder->possible_crtcs = 0x1;
- else
+ break;
+ case 2:
+ default:
encoder->possible_crtcs = 0x3;
+ break;
+ case 6:
+ encoder->possible_crtcs = 0x3f;
+ break;
+ }
radeon_encoder->enc_priv = NULL;
diff --git a/drivers/gpu/drm/radeon/radeon_family.h b/drivers/gpu/drm/radeon/radeon_family.h
index 797972e344a6..93c7d5d41914 100644
--- a/drivers/gpu/drm/radeon/radeon_family.h
+++ b/drivers/gpu/drm/radeon/radeon_family.h
@@ -75,6 +75,11 @@ enum radeon_family {
CHIP_RV730,
CHIP_RV710,
CHIP_RV740,
+ CHIP_CEDAR,
+ CHIP_REDWOOD,
+ CHIP_JUNIPER,
+ CHIP_CYPRESS,
+ CHIP_HEMLOCK,
CHIP_LAST,
};
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 3ba213d1b06c..8fccbf29235e 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -39,6 +39,8 @@
#include "drm_fb_helper.h"
+#include <linux/vga_switcheroo.h>
+
struct radeon_fb_device {
struct drm_fb_helper helper;
struct radeon_framebuffer *rfb;
@@ -148,7 +150,6 @@ int radeonfb_create(struct drm_device *dev,
unsigned long tmp;
bool fb_tiled = false; /* useful for testing */
u32 tiling_flags = 0;
- int crtc_count;
mode_cmd.width = surface_width;
mode_cmd.height = surface_height;
@@ -239,16 +240,12 @@ int radeonfb_create(struct drm_device *dev,
rfbdev = info->par;
rfbdev->helper.funcs = &radeon_fb_helper_funcs;
rfbdev->helper.dev = dev;
- if (rdev->flags & RADEON_SINGLE_CRTC)
- crtc_count = 1;
- else
- crtc_count = 2;
- ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, crtc_count,
+ ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, rdev->num_crtc,
RADEONFB_CONN_LIMIT);
if (ret)
goto out_unref;
- memset_io(fbptr, 0xff, aligned_size);
+ memset_io(fbptr, 0x0, aligned_size);
strcpy(info->fix.id, "radeondrmfb");
@@ -257,7 +254,7 @@ int radeonfb_create(struct drm_device *dev,
info->flags = FBINFO_DEFAULT;
info->fbops = &radeonfb_ops;
- tmp = fb_gpuaddr - rdev->mc.vram_location;
+ tmp = fb_gpuaddr - rdev->mc.vram_start;
info->fix.smem_start = rdev->mc.aper_base + tmp;
info->fix.smem_len = size;
info->screen_base = fbptr;
@@ -291,6 +288,7 @@ int radeonfb_create(struct drm_device *dev,
rfbdev->rdev = rdev;
mutex_unlock(&rdev->ddev->struct_mutex);
+ vga_switcheroo_client_fb_set(rdev->ddev->pdev, info);
return 0;
out_unref:
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
index e73d56e83fa6..1770d3c07fd0 100644
--- a/drivers/gpu/drm/radeon/radeon_gart.c
+++ b/drivers/gpu/drm/radeon/radeon_gart.c
@@ -139,6 +139,7 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
unsigned t;
unsigned p;
int i, j;
+ u64 page_base;
if (!rdev->gart.ready) {
WARN(1, "trying to unbind memory to unitialized GART !\n");
@@ -151,9 +152,11 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p],
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
rdev->gart.pages[p] = NULL;
- rdev->gart.pages_addr[p] = 0;
+ rdev->gart.pages_addr[p] = rdev->dummy_page.addr;
+ page_base = rdev->gart.pages_addr[p];
for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
- radeon_gart_set_page(rdev, t, 0);
+ radeon_gart_set_page(rdev, t, page_base);
+ page_base += RADEON_GPU_PAGE_SIZE;
}
}
}
@@ -199,8 +202,26 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
return 0;
}
+void radeon_gart_restore(struct radeon_device *rdev)
+{
+ int i, j, t;
+ u64 page_base;
+
+ for (i = 0, t = 0; i < rdev->gart.num_cpu_pages; i++) {
+ page_base = rdev->gart.pages_addr[i];
+ for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
+ radeon_gart_set_page(rdev, t, page_base);
+ page_base += RADEON_GPU_PAGE_SIZE;
+ }
+ }
+ mb();
+ radeon_gart_tlb_flush(rdev);
+}
+
int radeon_gart_init(struct radeon_device *rdev)
{
+ int r, i;
+
if (rdev->gart.pages) {
return 0;
}
@@ -209,6 +230,9 @@ int radeon_gart_init(struct radeon_device *rdev)
DRM_ERROR("Page size is smaller than GPU page size!\n");
return -EINVAL;
}
+ r = radeon_dummy_page_init(rdev);
+ if (r)
+ return r;
/* Compute table size */
rdev->gart.num_cpu_pages = rdev->mc.gtt_size / PAGE_SIZE;
rdev->gart.num_gpu_pages = rdev->mc.gtt_size / RADEON_GPU_PAGE_SIZE;
@@ -227,6 +251,10 @@ int radeon_gart_init(struct radeon_device *rdev)
radeon_gart_fini(rdev);
return -ENOMEM;
}
+ /* set GART entry to point to the dummy page by default */
+ for (i = 0; i < rdev->gart.num_cpu_pages; i++) {
+ rdev->gart.pages_addr[i] = rdev->dummy_page.addr;
+ }
return 0;
}
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
index 0e1325e18534..ef92d147d8f0 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -69,9 +69,7 @@ int radeon_gem_object_create(struct radeon_device *rdev, int size,
if (r != -ERESTARTSYS)
DRM_ERROR("Failed to allocate GEM object (%d, %d, %u, %d)\n",
size, initial_domain, alignment, r);
- mutex_lock(&rdev->ddev->struct_mutex);
- drm_gem_object_unreference(gobj);
- mutex_unlock(&rdev->ddev->struct_mutex);
+ drm_gem_object_unreference_unlocked(gobj);
return r;
}
gobj->driver_private = robj;
@@ -202,14 +200,10 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
}
r = drm_gem_handle_create(filp, gobj, &handle);
if (r) {
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gobj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(gobj);
return r;
}
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_handle_unreference(gobj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_handle_unreference_unlocked(gobj);
args->handle = handle;
return 0;
}
@@ -236,9 +230,7 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
r = radeon_gem_set_domain(gobj, args->read_domains, args->write_domain);
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gobj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(gobj);
return r;
}
@@ -255,9 +247,7 @@ int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
}
robj = gobj->driver_private;
args->addr_ptr = radeon_bo_mmap_offset(robj);
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gobj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(gobj);
return 0;
}
@@ -288,9 +278,7 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
default:
break;
}
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gobj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(gobj);
return r;
}
@@ -308,9 +296,10 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
}
robj = gobj->driver_private;
r = radeon_bo_wait(robj, NULL, false);
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gobj);
- mutex_unlock(&dev->struct_mutex);
+ /* callback hw specific functions if any */
+ if (robj->rdev->asic->ioctl_wait_idle)
+ robj->rdev->asic->ioctl_wait_idle(robj->rdev, robj);
+ drm_gem_object_unreference_unlocked(gobj);
return r;
}
@@ -328,9 +317,7 @@ int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
robj = gobj->driver_private;
r = radeon_bo_set_tiling_flags(robj, args->tiling_flags, args->pitch);
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gobj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(gobj);
return r;
}
@@ -353,8 +340,6 @@ int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
radeon_bo_get_tiling_flags(rbo, &args->tiling_flags, &args->pitch);
radeon_bo_unreserve(rbo);
out:
- mutex_lock(&dev->struct_mutex);
- drm_gem_object_unreference(gobj);
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference_unlocked(gobj);
return r;
}
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
index da3da1e89d00..4ae50c19589f 100644
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
@@ -26,6 +26,7 @@
#include "drmP.h"
#include "radeon_drm.h"
#include "radeon.h"
+#include "atom.h"
/**
* radeon_ddc_probe
@@ -59,7 +60,7 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector)
}
-void radeon_i2c_do_lock(struct radeon_i2c_chan *i2c, int lock_state)
+static void radeon_i2c_do_lock(struct radeon_i2c_chan *i2c, int lock_state)
{
struct radeon_device *rdev = i2c->dev->dev_private;
struct radeon_i2c_bus_rec *rec = &i2c->rec;
@@ -71,13 +72,25 @@ void radeon_i2c_do_lock(struct radeon_i2c_chan *i2c, int lock_state)
*/
if (rec->hw_capable) {
if ((rdev->family >= CHIP_R200) && !ASIC_IS_AVIVO(rdev)) {
- if (rec->a_clk_reg == RADEON_GPIO_MONID) {
+ u32 reg;
+
+ if (rdev->family >= CHIP_RV350)
+ reg = RADEON_GPIO_MONID;
+ else if ((rdev->family == CHIP_R300) ||
+ (rdev->family == CHIP_R350))
+ reg = RADEON_GPIO_DVI_DDC;
+ else
+ reg = RADEON_GPIO_CRT2_DDC;
+
+ mutex_lock(&rdev->dc_hw_i2c_mutex);
+ if (rec->a_clk_reg == reg) {
WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1)));
} else {
WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3)));
}
+ mutex_unlock(&rdev->dc_hw_i2c_mutex);
}
}
@@ -168,6 +181,692 @@ static void set_data(void *i2c_priv, int data)
WREG32(rec->en_data_reg, val);
}
+static u32 radeon_get_i2c_prescale(struct radeon_device *rdev)
+{
+ struct radeon_pll *spll = &rdev->clock.spll;
+ u32 sclk = radeon_get_engine_clock(rdev);
+ u32 prescale = 0;
+ u32 n, m;
+ u8 loop;
+ int i2c_clock;
+
+ switch (rdev->family) {
+ case CHIP_R100:
+ case CHIP_RV100:
+ case CHIP_RS100:
+ case CHIP_RV200:
+ case CHIP_RS200:
+ case CHIP_R200:
+ case CHIP_RV250:
+ case CHIP_RS300:
+ case CHIP_RV280:
+ case CHIP_R300:
+ case CHIP_R350:
+ case CHIP_RV350:
+ n = (spll->reference_freq) / (4 * 6);
+ for (loop = 1; loop < 255; loop++) {
+ if ((loop * (loop - 1)) > n)
+ break;
+ }
+ m = loop - 1;
+ prescale = m | (loop << 8);
+ break;
+ case CHIP_RV380:
+ case CHIP_RS400:
+ case CHIP_RS480:
+ case CHIP_R420:
+ case CHIP_R423:
+ case CHIP_RV410:
+ sclk = radeon_get_engine_clock(rdev);
+ prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
+ break;
+ case CHIP_RS600:
+ case CHIP_RS690:
+ case CHIP_RS740:
+ /* todo */
+ break;
+ case CHIP_RV515:
+ case CHIP_R520:
+ case CHIP_RV530:
+ case CHIP_RV560:
+ case CHIP_RV570:
+ case CHIP_R580:
+ i2c_clock = 50;
+ sclk = radeon_get_engine_clock(rdev);
+ if (rdev->family == CHIP_R520)
+ prescale = (127 << 8) + ((sclk * 10) / (4 * 127 * i2c_clock));
+ else
+ prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
+ break;
+ case CHIP_R600:
+ case CHIP_RV610:
+ case CHIP_RV630:
+ case CHIP_RV670:
+ /* todo */
+ break;
+ case CHIP_RV620:
+ case CHIP_RV635:
+ case CHIP_RS780:
+ case CHIP_RS880:
+ case CHIP_RV770:
+ case CHIP_RV730:
+ case CHIP_RV710:
+ case CHIP_RV740:
+ /* todo */
+ break;
+ case CHIP_CEDAR:
+ case CHIP_REDWOOD:
+ case CHIP_JUNIPER:
+ case CHIP_CYPRESS:
+ case CHIP_HEMLOCK:
+ /* todo */
+ break;
+ default:
+ DRM_ERROR("i2c: unhandled radeon chip\n");
+ break;
+ }
+ return prescale;
+}
+
+
+/* hw i2c engine for r1xx-4xx hardware
+ * hw can buffer up to 15 bytes
+ */
+static int r100_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
+ struct radeon_device *rdev = i2c->dev->dev_private;
+ struct radeon_i2c_bus_rec *rec = &i2c->rec;
+ struct i2c_msg *p;
+ int i, j, k, ret = num;
+ u32 prescale;
+ u32 i2c_cntl_0, i2c_cntl_1, i2c_data;
+ u32 tmp, reg;
+
+ mutex_lock(&rdev->dc_hw_i2c_mutex);
+ /* take the pm lock since we need a constant sclk */
+ mutex_lock(&rdev->pm.mutex);
+
+ prescale = radeon_get_i2c_prescale(rdev);
+
+ reg = ((prescale << RADEON_I2C_PRESCALE_SHIFT) |
+ RADEON_I2C_START |
+ RADEON_I2C_STOP |
+ RADEON_I2C_GO);
+
+ if (rdev->is_atom_bios) {
+ tmp = RREG32(RADEON_BIOS_6_SCRATCH);
+ WREG32(RADEON_BIOS_6_SCRATCH, tmp | ATOM_S6_HW_I2C_BUSY_STATE);
+ }
+
+ if (rec->mm_i2c) {
+ i2c_cntl_0 = RADEON_I2C_CNTL_0;
+ i2c_cntl_1 = RADEON_I2C_CNTL_1;
+ i2c_data = RADEON_I2C_DATA;
+ } else {
+ i2c_cntl_0 = RADEON_DVI_I2C_CNTL_0;
+ i2c_cntl_1 = RADEON_DVI_I2C_CNTL_1;
+ i2c_data = RADEON_DVI_I2C_DATA;
+
+ switch (rdev->family) {
+ case CHIP_R100:
+ case CHIP_RV100:
+ case CHIP_RS100:
+ case CHIP_RV200:
+ case CHIP_RS200:
+ case CHIP_RS300:
+ switch (rec->mask_clk_reg) {
+ case RADEON_GPIO_DVI_DDC:
+ /* no gpio select bit */
+ break;
+ default:
+ DRM_ERROR("gpio not supported with hw i2c\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ break;
+ case CHIP_R200:
+ /* only bit 4 on r200 */
+ switch (rec->mask_clk_reg) {
+ case RADEON_GPIO_DVI_DDC:
+ reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1);
+ break;
+ case RADEON_GPIO_MONID:
+ reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3);
+ break;
+ default:
+ DRM_ERROR("gpio not supported with hw i2c\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ break;
+ case CHIP_RV250:
+ case CHIP_RV280:
+ /* bits 3 and 4 */
+ switch (rec->mask_clk_reg) {
+ case RADEON_GPIO_DVI_DDC:
+ reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1);
+ break;
+ case RADEON_GPIO_VGA_DDC:
+ reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC2);
+ break;
+ case RADEON_GPIO_CRT2_DDC:
+ reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3);
+ break;
+ default:
+ DRM_ERROR("gpio not supported with hw i2c\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ break;
+ case CHIP_R300:
+ case CHIP_R350:
+ /* only bit 4 on r300/r350 */
+ switch (rec->mask_clk_reg) {
+ case RADEON_GPIO_VGA_DDC:
+ reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1);
+ break;
+ case RADEON_GPIO_DVI_DDC:
+ reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3);
+ break;
+ default:
+ DRM_ERROR("gpio not supported with hw i2c\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ break;
+ case CHIP_RV350:
+ case CHIP_RV380:
+ case CHIP_R420:
+ case CHIP_R423:
+ case CHIP_RV410:
+ case CHIP_RS400:
+ case CHIP_RS480:
+ /* bits 3 and 4 */
+ switch (rec->mask_clk_reg) {
+ case RADEON_GPIO_VGA_DDC:
+ reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1);
+ break;
+ case RADEON_GPIO_DVI_DDC:
+ reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC2);
+ break;
+ case RADEON_GPIO_MONID:
+ reg |= R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3);
+ break;
+ default:
+ DRM_ERROR("gpio not supported with hw i2c\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ break;
+ default:
+ DRM_ERROR("unsupported asic\n");
+ ret = -EINVAL;
+ goto done;
+ break;
+ }
+ }
+
+ /* check for bus probe */
+ p = &msgs[0];
+ if ((num == 1) && (p->len == 0)) {
+ WREG32(i2c_cntl_0, (RADEON_I2C_DONE |
+ RADEON_I2C_NACK |
+ RADEON_I2C_HALT |
+ RADEON_I2C_SOFT_RST));
+ WREG32(i2c_data, (p->addr << 1) & 0xff);
+ WREG32(i2c_data, 0);
+ WREG32(i2c_cntl_1, ((1 << RADEON_I2C_DATA_COUNT_SHIFT) |
+ (1 << RADEON_I2C_ADDR_COUNT_SHIFT) |
+ RADEON_I2C_EN |
+ (48 << RADEON_I2C_TIME_LIMIT_SHIFT)));
+ WREG32(i2c_cntl_0, reg);
+ for (k = 0; k < 32; k++) {
+ udelay(10);
+ tmp = RREG32(i2c_cntl_0);
+ if (tmp & RADEON_I2C_GO)
+ continue;
+ tmp = RREG32(i2c_cntl_0);
+ if (tmp & RADEON_I2C_DONE)
+ break;
+ else {
+ DRM_DEBUG("i2c write error 0x%08x\n", tmp);
+ WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT);
+ ret = -EIO;
+ goto done;
+ }
+ }
+ goto done;
+ }
+
+ for (i = 0; i < num; i++) {
+ p = &msgs[i];
+ for (j = 0; j < p->len; j++) {
+ if (p->flags & I2C_M_RD) {
+ WREG32(i2c_cntl_0, (RADEON_I2C_DONE |
+ RADEON_I2C_NACK |
+ RADEON_I2C_HALT |
+ RADEON_I2C_SOFT_RST));
+ WREG32(i2c_data, ((p->addr << 1) & 0xff) | 0x1);
+ WREG32(i2c_cntl_1, ((1 << RADEON_I2C_DATA_COUNT_SHIFT) |
+ (1 << RADEON_I2C_ADDR_COUNT_SHIFT) |
+ RADEON_I2C_EN |
+ (48 << RADEON_I2C_TIME_LIMIT_SHIFT)));
+ WREG32(i2c_cntl_0, reg | RADEON_I2C_RECEIVE);
+ for (k = 0; k < 32; k++) {
+ udelay(10);
+ tmp = RREG32(i2c_cntl_0);
+ if (tmp & RADEON_I2C_GO)
+ continue;
+ tmp = RREG32(i2c_cntl_0);
+ if (tmp & RADEON_I2C_DONE)
+ break;
+ else {
+ DRM_DEBUG("i2c read error 0x%08x\n", tmp);
+ WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT);
+ ret = -EIO;
+ goto done;
+ }
+ }
+ p->buf[j] = RREG32(i2c_data) & 0xff;
+ } else {
+ WREG32(i2c_cntl_0, (RADEON_I2C_DONE |
+ RADEON_I2C_NACK |
+ RADEON_I2C_HALT |
+ RADEON_I2C_SOFT_RST));
+ WREG32(i2c_data, (p->addr << 1) & 0xff);
+ WREG32(i2c_data, p->buf[j]);
+ WREG32(i2c_cntl_1, ((1 << RADEON_I2C_DATA_COUNT_SHIFT) |
+ (1 << RADEON_I2C_ADDR_COUNT_SHIFT) |
+ RADEON_I2C_EN |
+ (48 << RADEON_I2C_TIME_LIMIT_SHIFT)));
+ WREG32(i2c_cntl_0, reg);
+ for (k = 0; k < 32; k++) {
+ udelay(10);
+ tmp = RREG32(i2c_cntl_0);
+ if (tmp & RADEON_I2C_GO)
+ continue;
+ tmp = RREG32(i2c_cntl_0);
+ if (tmp & RADEON_I2C_DONE)
+ break;
+ else {
+ DRM_DEBUG("i2c write error 0x%08x\n", tmp);
+ WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT);
+ ret = -EIO;
+ goto done;
+ }
+ }
+ }
+ }
+ }
+
+done:
+ WREG32(i2c_cntl_0, 0);
+ WREG32(i2c_cntl_1, 0);
+ WREG32(i2c_cntl_0, (RADEON_I2C_DONE |
+ RADEON_I2C_NACK |
+ RADEON_I2C_HALT |
+ RADEON_I2C_SOFT_RST));
+
+ if (rdev->is_atom_bios) {
+ tmp = RREG32(RADEON_BIOS_6_SCRATCH);
+ tmp &= ~ATOM_S6_HW_I2C_BUSY_STATE;
+ WREG32(RADEON_BIOS_6_SCRATCH, tmp);
+ }
+
+ mutex_unlock(&rdev->pm.mutex);
+ mutex_unlock(&rdev->dc_hw_i2c_mutex);
+
+ return ret;
+}
+
+/* hw i2c engine for r5xx hardware
+ * hw can buffer up to 15 bytes
+ */
+static int r500_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
+ struct radeon_device *rdev = i2c->dev->dev_private;
+ struct radeon_i2c_bus_rec *rec = &i2c->rec;
+ struct i2c_msg *p;
+ int i, j, remaining, current_count, buffer_offset, ret = num;
+ u32 prescale;
+ u32 tmp, reg;
+ u32 saved1, saved2;
+
+ mutex_lock(&rdev->dc_hw_i2c_mutex);
+ /* take the pm lock since we need a constant sclk */
+ mutex_lock(&rdev->pm.mutex);
+
+ prescale = radeon_get_i2c_prescale(rdev);
+
+ /* clear gpio mask bits */
+ tmp = RREG32(rec->mask_clk_reg);
+ tmp &= ~rec->mask_clk_mask;
+ WREG32(rec->mask_clk_reg, tmp);
+ tmp = RREG32(rec->mask_clk_reg);
+
+ tmp = RREG32(rec->mask_data_reg);
+ tmp &= ~rec->mask_data_mask;
+ WREG32(rec->mask_data_reg, tmp);
+ tmp = RREG32(rec->mask_data_reg);
+
+ /* clear pin values */
+ tmp = RREG32(rec->a_clk_reg);
+ tmp &= ~rec->a_clk_mask;
+ WREG32(rec->a_clk_reg, tmp);
+ tmp = RREG32(rec->a_clk_reg);
+
+ tmp = RREG32(rec->a_data_reg);
+ tmp &= ~rec->a_data_mask;
+ WREG32(rec->a_data_reg, tmp);
+ tmp = RREG32(rec->a_data_reg);
+
+ /* set the pins to input */
+ tmp = RREG32(rec->en_clk_reg);
+ tmp &= ~rec->en_clk_mask;
+ WREG32(rec->en_clk_reg, tmp);
+ tmp = RREG32(rec->en_clk_reg);
+
+ tmp = RREG32(rec->en_data_reg);
+ tmp &= ~rec->en_data_mask;
+ WREG32(rec->en_data_reg, tmp);
+ tmp = RREG32(rec->en_data_reg);
+
+ /* */
+ tmp = RREG32(RADEON_BIOS_6_SCRATCH);
+ WREG32(RADEON_BIOS_6_SCRATCH, tmp | ATOM_S6_HW_I2C_BUSY_STATE);
+ saved1 = RREG32(AVIVO_DC_I2C_CONTROL1);
+ saved2 = RREG32(0x494);
+ WREG32(0x494, saved2 | 0x1);
+
+ WREG32(AVIVO_DC_I2C_ARBITRATION, AVIVO_DC_I2C_SW_WANTS_TO_USE_I2C);
+ for (i = 0; i < 50; i++) {
+ udelay(1);
+ if (RREG32(AVIVO_DC_I2C_ARBITRATION) & AVIVO_DC_I2C_SW_CAN_USE_I2C)
+ break;
+ }
+ if (i == 50) {
+ DRM_ERROR("failed to get i2c bus\n");
+ ret = -EBUSY;
+ goto done;
+ }
+
+ reg = AVIVO_DC_I2C_START | AVIVO_DC_I2C_STOP | AVIVO_DC_I2C_EN;
+ switch (rec->mask_clk_reg) {
+ case AVIVO_DC_GPIO_DDC1_MASK:
+ reg |= AVIVO_DC_I2C_PIN_SELECT(AVIVO_SEL_DDC1);
+ break;
+ case AVIVO_DC_GPIO_DDC2_MASK:
+ reg |= AVIVO_DC_I2C_PIN_SELECT(AVIVO_SEL_DDC2);
+ break;
+ case AVIVO_DC_GPIO_DDC3_MASK:
+ reg |= AVIVO_DC_I2C_PIN_SELECT(AVIVO_SEL_DDC3);
+ break;
+ default:
+ DRM_ERROR("gpio not supported with hw i2c\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* check for bus probe */
+ p = &msgs[0];
+ if ((num == 1) && (p->len == 0)) {
+ WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE |
+ AVIVO_DC_I2C_NACK |
+ AVIVO_DC_I2C_HALT));
+ WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET);
+ udelay(1);
+ WREG32(AVIVO_DC_I2C_RESET, 0);
+
+ WREG32(AVIVO_DC_I2C_DATA, (p->addr << 1) & 0xff);
+ WREG32(AVIVO_DC_I2C_DATA, 0);
+
+ WREG32(AVIVO_DC_I2C_CONTROL3, AVIVO_DC_I2C_TIME_LIMIT(48));
+ WREG32(AVIVO_DC_I2C_CONTROL2, (AVIVO_DC_I2C_ADDR_COUNT(1) |
+ AVIVO_DC_I2C_DATA_COUNT(1) |
+ (prescale << 16)));
+ WREG32(AVIVO_DC_I2C_CONTROL1, reg);
+ WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO);
+ for (j = 0; j < 200; j++) {
+ udelay(50);
+ tmp = RREG32(AVIVO_DC_I2C_STATUS1);
+ if (tmp & AVIVO_DC_I2C_GO)
+ continue;
+ tmp = RREG32(AVIVO_DC_I2C_STATUS1);
+ if (tmp & AVIVO_DC_I2C_DONE)
+ break;
+ else {
+ DRM_DEBUG("i2c write error 0x%08x\n", tmp);
+ WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT);
+ ret = -EIO;
+ goto done;
+ }
+ }
+ goto done;
+ }
+
+ for (i = 0; i < num; i++) {
+ p = &msgs[i];
+ remaining = p->len;
+ buffer_offset = 0;
+ if (p->flags & I2C_M_RD) {
+ while (remaining) {
+ if (remaining > 15)
+ current_count = 15;
+ else
+ current_count = remaining;
+ WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE |
+ AVIVO_DC_I2C_NACK |
+ AVIVO_DC_I2C_HALT));
+ WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET);
+ udelay(1);
+ WREG32(AVIVO_DC_I2C_RESET, 0);
+
+ WREG32(AVIVO_DC_I2C_DATA, ((p->addr << 1) & 0xff) | 0x1);
+ WREG32(AVIVO_DC_I2C_CONTROL3, AVIVO_DC_I2C_TIME_LIMIT(48));
+ WREG32(AVIVO_DC_I2C_CONTROL2, (AVIVO_DC_I2C_ADDR_COUNT(1) |
+ AVIVO_DC_I2C_DATA_COUNT(current_count) |
+ (prescale << 16)));
+ WREG32(AVIVO_DC_I2C_CONTROL1, reg | AVIVO_DC_I2C_RECEIVE);
+ WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO);
+ for (j = 0; j < 200; j++) {
+ udelay(50);
+ tmp = RREG32(AVIVO_DC_I2C_STATUS1);
+ if (tmp & AVIVO_DC_I2C_GO)
+ continue;
+ tmp = RREG32(AVIVO_DC_I2C_STATUS1);
+ if (tmp & AVIVO_DC_I2C_DONE)
+ break;
+ else {
+ DRM_DEBUG("i2c read error 0x%08x\n", tmp);
+ WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT);
+ ret = -EIO;
+ goto done;
+ }
+ }
+ for (j = 0; j < current_count; j++)
+ p->buf[buffer_offset + j] = RREG32(AVIVO_DC_I2C_DATA) & 0xff;
+ remaining -= current_count;
+ buffer_offset += current_count;
+ }
+ } else {
+ while (remaining) {
+ if (remaining > 15)
+ current_count = 15;
+ else
+ current_count = remaining;
+ WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE |
+ AVIVO_DC_I2C_NACK |
+ AVIVO_DC_I2C_HALT));
+ WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET);
+ udelay(1);
+ WREG32(AVIVO_DC_I2C_RESET, 0);
+
+ WREG32(AVIVO_DC_I2C_DATA, (p->addr << 1) & 0xff);
+ for (j = 0; j < current_count; j++)
+ WREG32(AVIVO_DC_I2C_DATA, p->buf[buffer_offset + j]);
+
+ WREG32(AVIVO_DC_I2C_CONTROL3, AVIVO_DC_I2C_TIME_LIMIT(48));
+ WREG32(AVIVO_DC_I2C_CONTROL2, (AVIVO_DC_I2C_ADDR_COUNT(1) |
+ AVIVO_DC_I2C_DATA_COUNT(current_count) |
+ (prescale << 16)));
+ WREG32(AVIVO_DC_I2C_CONTROL1, reg);
+ WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO);
+ for (j = 0; j < 200; j++) {
+ udelay(50);
+ tmp = RREG32(AVIVO_DC_I2C_STATUS1);
+ if (tmp & AVIVO_DC_I2C_GO)
+ continue;
+ tmp = RREG32(AVIVO_DC_I2C_STATUS1);
+ if (tmp & AVIVO_DC_I2C_DONE)
+ break;
+ else {
+ DRM_DEBUG("i2c write error 0x%08x\n", tmp);
+ WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT);
+ ret = -EIO;
+ goto done;
+ }
+ }
+ remaining -= current_count;
+ buffer_offset += current_count;
+ }
+ }
+ }
+
+done:
+ WREG32(AVIVO_DC_I2C_STATUS1, (AVIVO_DC_I2C_DONE |
+ AVIVO_DC_I2C_NACK |
+ AVIVO_DC_I2C_HALT));
+ WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET);
+ udelay(1);
+ WREG32(AVIVO_DC_I2C_RESET, 0);
+
+ WREG32(AVIVO_DC_I2C_ARBITRATION, AVIVO_DC_I2C_SW_DONE_USING_I2C);
+ WREG32(AVIVO_DC_I2C_CONTROL1, saved1);
+ WREG32(0x494, saved2);
+ tmp = RREG32(RADEON_BIOS_6_SCRATCH);
+ tmp &= ~ATOM_S6_HW_I2C_BUSY_STATE;
+ WREG32(RADEON_BIOS_6_SCRATCH, tmp);
+
+ mutex_unlock(&rdev->pm.mutex);
+ mutex_unlock(&rdev->dc_hw_i2c_mutex);
+
+ return ret;
+}
+
+static int radeon_sw_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
+ int ret;
+
+ radeon_i2c_do_lock(i2c, 1);
+ ret = i2c_transfer(&i2c->algo.radeon.bit_adapter, msgs, num);
+ radeon_i2c_do_lock(i2c, 0);
+
+ return ret;
+}
+
+static int radeon_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
+ struct radeon_device *rdev = i2c->dev->dev_private;
+ struct radeon_i2c_bus_rec *rec = &i2c->rec;
+ int ret;
+
+ switch (rdev->family) {
+ case CHIP_R100:
+ case CHIP_RV100:
+ case CHIP_RS100:
+ case CHIP_RV200:
+ case CHIP_RS200:
+ case CHIP_R200:
+ case CHIP_RV250:
+ case CHIP_RS300:
+ case CHIP_RV280:
+ case CHIP_R300:
+ case CHIP_R350:
+ case CHIP_RV350:
+ case CHIP_RV380:
+ case CHIP_R420:
+ case CHIP_R423:
+ case CHIP_RV410:
+ case CHIP_RS400:
+ case CHIP_RS480:
+ if (rec->hw_capable)
+ ret = r100_hw_i2c_xfer(i2c_adap, msgs, num);
+ else
+ ret = radeon_sw_i2c_xfer(i2c_adap, msgs, num);
+ break;
+ case CHIP_RS600:
+ case CHIP_RS690:
+ case CHIP_RS740:
+ /* XXX fill in hw i2c implementation */
+ ret = radeon_sw_i2c_xfer(i2c_adap, msgs, num);
+ break;
+ case CHIP_RV515:
+ case CHIP_R520:
+ case CHIP_RV530:
+ case CHIP_RV560:
+ case CHIP_RV570:
+ case CHIP_R580:
+ if (rec->hw_capable) {
+ if (rec->mm_i2c)
+ ret = r100_hw_i2c_xfer(i2c_adap, msgs, num);
+ else
+ ret = r500_hw_i2c_xfer(i2c_adap, msgs, num);
+ } else
+ ret = radeon_sw_i2c_xfer(i2c_adap, msgs, num);
+ break;
+ case CHIP_R600:
+ case CHIP_RV610:
+ case CHIP_RV630:
+ case CHIP_RV670:
+ /* XXX fill in hw i2c implementation */
+ ret = radeon_sw_i2c_xfer(i2c_adap, msgs, num);
+ break;
+ case CHIP_RV620:
+ case CHIP_RV635:
+ case CHIP_RS780:
+ case CHIP_RS880:
+ case CHIP_RV770:
+ case CHIP_RV730:
+ case CHIP_RV710:
+ case CHIP_RV740:
+ /* XXX fill in hw i2c implementation */
+ ret = radeon_sw_i2c_xfer(i2c_adap, msgs, num);
+ break;
+ case CHIP_CEDAR:
+ case CHIP_REDWOOD:
+ case CHIP_JUNIPER:
+ case CHIP_CYPRESS:
+ case CHIP_HEMLOCK:
+ /* XXX fill in hw i2c implementation */
+ ret = radeon_sw_i2c_xfer(i2c_adap, msgs, num);
+ break;
+ default:
+ DRM_ERROR("i2c: unhandled radeon chip\n");
+ ret = -EIO;
+ break;
+ }
+
+ return ret;
+}
+
+static u32 radeon_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm radeon_i2c_algo = {
+ .master_xfer = radeon_i2c_xfer,
+ .functionality = radeon_i2c_func,
+};
+
struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
struct radeon_i2c_bus_rec *rec,
const char *name)
@@ -179,23 +878,36 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
if (i2c == NULL)
return NULL;
- i2c->adapter.owner = THIS_MODULE;
- i2c->dev = dev;
- i2c_set_adapdata(&i2c->adapter, i2c);
- i2c->adapter.algo_data = &i2c->algo.bit;
- i2c->algo.bit.setsda = set_data;
- i2c->algo.bit.setscl = set_clock;
- i2c->algo.bit.getsda = get_data;
- i2c->algo.bit.getscl = get_clock;
- i2c->algo.bit.udelay = 20;
+ /* set the internal bit adapter */
+ i2c->algo.radeon.bit_adapter.owner = THIS_MODULE;
+ i2c_set_adapdata(&i2c->algo.radeon.bit_adapter, i2c);
+ sprintf(i2c->algo.radeon.bit_adapter.name, "Radeon internal i2c bit bus %s", name);
+ i2c->algo.radeon.bit_adapter.algo_data = &i2c->algo.radeon.bit_data;
+ i2c->algo.radeon.bit_data.setsda = set_data;
+ i2c->algo.radeon.bit_data.setscl = set_clock;
+ i2c->algo.radeon.bit_data.getsda = get_data;
+ i2c->algo.radeon.bit_data.getscl = get_clock;
+ i2c->algo.radeon.bit_data.udelay = 20;
/* vesa says 2.2 ms is enough, 1 jiffy doesn't seem to always
* make this, 2 jiffies is a lot more reliable */
- i2c->algo.bit.timeout = 2;
- i2c->algo.bit.data = i2c;
+ i2c->algo.radeon.bit_data.timeout = 2;
+ i2c->algo.radeon.bit_data.data = i2c;
+ ret = i2c_bit_add_bus(&i2c->algo.radeon.bit_adapter);
+ if (ret) {
+ DRM_ERROR("Failed to register internal bit i2c %s\n", name);
+ goto out_free;
+ }
+ /* set the radeon i2c adapter */
+ i2c->dev = dev;
i2c->rec = *rec;
- ret = i2c_bit_add_bus(&i2c->adapter);
+ i2c->adapter.owner = THIS_MODULE;
+ i2c_set_adapdata(&i2c->adapter, i2c);
+ sprintf(i2c->adapter.name, "Radeon i2c %s", name);
+ i2c->adapter.algo_data = &i2c->algo.radeon;
+ i2c->adapter.algo = &radeon_i2c_algo;
+ ret = i2c_add_adapter(&i2c->adapter);
if (ret) {
- DRM_INFO("Failed to register i2c %s\n", name);
+ DRM_ERROR("Failed to register i2c %s\n", name);
goto out_free;
}
@@ -237,11 +949,19 @@ out_free:
}
-
void radeon_i2c_destroy(struct radeon_i2c_chan *i2c)
{
if (!i2c)
return;
+ i2c_del_adapter(&i2c->algo.radeon.bit_adapter);
+ i2c_del_adapter(&i2c->adapter);
+ kfree(i2c);
+}
+
+void radeon_i2c_destroy_dp(struct radeon_i2c_chan *i2c)
+{
+ if (!i2c)
+ return;
i2c_del_adapter(&i2c->adapter);
kfree(i2c);
@@ -252,10 +972,10 @@ struct drm_encoder *radeon_best_encoder(struct drm_connector *connector)
return NULL;
}
-void radeon_i2c_sw_get_byte(struct radeon_i2c_chan *i2c_bus,
- u8 slave_addr,
- u8 addr,
- u8 *val)
+void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus,
+ u8 slave_addr,
+ u8 addr,
+ u8 *val)
{
u8 out_buf[2];
u8 in_buf[2];
@@ -286,10 +1006,10 @@ void radeon_i2c_sw_get_byte(struct radeon_i2c_chan *i2c_bus,
}
}
-void radeon_i2c_sw_put_byte(struct radeon_i2c_chan *i2c_bus,
- u8 slave_addr,
- u8 addr,
- u8 val)
+void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus,
+ u8 slave_addr,
+ u8 addr,
+ u8 val)
{
uint8_t out_buf[2];
struct i2c_msg msg = {
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index f23b05606eb5..20ec276e7596 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -30,6 +30,8 @@
#include "radeon.h"
#include "radeon_drm.h"
+#include <linux/vga_switcheroo.h>
+
int radeon_driver_unload_kms(struct drm_device *dev)
{
struct radeon_device *rdev = dev->dev_private;
@@ -136,6 +138,7 @@ int radeon_driver_firstopen_kms(struct drm_device *dev)
void radeon_driver_lastclose_kms(struct drm_device *dev)
{
+ vga_switcheroo_process_delayed_switch();
}
int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
@@ -276,17 +279,17 @@ struct drm_ioctl_desc radeon_ioctls_kms[] = {
DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc_kms, DRM_AUTH),
DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free_kms, DRM_AUTH),
/* KMS */
- DRM_IOCTL_DEF(DRM_RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_RADEON_INFO, radeon_info_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_RADEON_INFO, radeon_info_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED),
};
int radeon_max_kms_ioctl = DRM_ARRAY_SIZE(radeon_ioctls_kms);
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index cc27485a07ad..df23d6a01d02 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -339,69 +339,6 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
}
}
-/* properly set crtc bpp when using atombios */
-void radeon_legacy_atom_set_surface(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
- int format;
- uint32_t crtc_gen_cntl;
- uint32_t disp_merge_cntl;
- uint32_t crtc_pitch;
-
- switch (crtc->fb->bits_per_pixel) {
- case 8:
- format = 2;
- break;
- case 15: /* 555 */
- format = 3;
- break;
- case 16: /* 565 */
- format = 4;
- break;
- case 24: /* RGB */
- format = 5;
- break;
- case 32: /* xRGB */
- format = 6;
- break;
- default:
- return;
- }
-
- crtc_pitch = ((((crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8)) * crtc->fb->bits_per_pixel) +
- ((crtc->fb->bits_per_pixel * 8) - 1)) /
- (crtc->fb->bits_per_pixel * 8));
- crtc_pitch |= crtc_pitch << 16;
-
- WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
-
- switch (radeon_crtc->crtc_id) {
- case 0:
- disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL);
- disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
- WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl);
-
- crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL) & 0xfffff0ff;
- crtc_gen_cntl |= (format << 8);
- crtc_gen_cntl |= RADEON_CRTC_EXT_DISP_EN;
- WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl);
- break;
- case 1:
- disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
- disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
- WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl);
-
- crtc_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL) & 0xfffff0ff;
- crtc_gen_cntl |= (format << 8);
- WREG32(RADEON_CRTC2_GEN_CNTL, crtc_gen_cntl);
- WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID));
- WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID));
- break;
- }
-}
-
int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
@@ -466,7 +403,7 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
/* if scanout was in GTT this really wouldn't work */
/* crtc offset is from display base addr not FB location */
- radeon_crtc->legacy_display_base_addr = rdev->mc.vram_location;
+ radeon_crtc->legacy_display_base_addr = rdev->mc.vram_start;
base -= radeon_crtc->legacy_display_base_addr;
@@ -645,29 +582,6 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
? RADEON_CRTC_V_SYNC_POL
: 0));
- /* TODO -> Dell Server */
- if (0) {
- uint32_t disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG);
- uint32_t tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
- uint32_t dac2_cntl = RREG32(RADEON_DAC_CNTL2);
- uint32_t crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
-
- dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL;
- dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL;
-
- /* For CRT on DAC2, don't turn it on if BIOS didn't
- enable it, even it's detected.
- */
- disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
- tv_dac_cntl &= ~((1<<2) | (3<<8) | (7<<24) | (0xff<<16));
- tv_dac_cntl |= (0x03 | (2<<8) | (0x58<<16));
-
- WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
- WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug);
- WREG32(RADEON_DAC_CNTL2, dac2_cntl);
- WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
- }
-
if (radeon_crtc->crtc_id) {
uint32_t crtc2_gen_cntl;
uint32_t disp2_merge_cntl;
@@ -755,7 +669,6 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
uint32_t post_divider = 0;
uint32_t freq = 0;
uint8_t pll_gain;
- int pll_flags = RADEON_PLL_LEGACY;
bool use_bios_divs = false;
/* PLL registers */
uint32_t pll_ref_div = 0;
@@ -789,10 +702,16 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
else
pll = &rdev->clock.p1pll;
+ pll->flags = RADEON_PLL_LEGACY;
+ if (radeon_new_pll == 1)
+ pll->algo = PLL_ALGO_NEW;
+ else
+ pll->algo = PLL_ALGO_LEGACY;
+
if (mode->clock > 200000) /* range limits??? */
- pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
+ pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
else
- pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
+ pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc == crtc) {
@@ -804,7 +723,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
}
if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
- pll_flags |= RADEON_PLL_NO_ODD_POST_DIV;
+ pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) {
if (!rdev->is_atom_bios) {
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
@@ -819,7 +738,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
}
}
}
- pll_flags |= RADEON_PLL_USE_REF_DIV;
+ pll->flags |= RADEON_PLL_USE_REF_DIV;
}
}
}
@@ -829,8 +748,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
if (!use_bios_divs) {
radeon_compute_pll(pll, mode->clock,
&freq, &feedback_div, &frac_fb_div,
- &reference_div, &post_divider,
- pll_flags);
+ &reference_div, &post_divider);
for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
if (post_div->divider == post_divider)
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index 38e45e231ef5..cf389ce50a8a 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
@@ -115,6 +115,9 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
else
radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+
+ /* adjust pm to dpms change */
+ radeon_pm_compute_clocks(rdev);
}
static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder)
@@ -214,6 +217,11 @@ static bool radeon_legacy_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+
+ /* adjust pm to upcoming mode change */
+ radeon_pm_compute_clocks(rdev);
/* set the active encoder to connector routing */
radeon_encoder_set_active_device(encoder);
@@ -285,6 +293,9 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode
radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
else
radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+
+ /* adjust pm to dpms change */
+ radeon_pm_compute_clocks(rdev);
}
static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder)
@@ -470,6 +481,9 @@ static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode)
radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
else
radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+
+ /* adjust pm to dpms change */
+ radeon_pm_compute_clocks(rdev);
}
static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder)
@@ -635,6 +649,9 @@ static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode)
radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
else
radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+
+ /* adjust pm to dpms change */
+ radeon_pm_compute_clocks(rdev);
}
static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder)
@@ -842,6 +859,9 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode)
radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
else
radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+
+ /* adjust pm to dpms change */
+ radeon_pm_compute_clocks(rdev);
}
static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder)
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 91cb041cb40d..1702b820aa4d 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -83,6 +83,8 @@ struct radeon_i2c_bus_rec {
bool valid;
/* id used by atom */
uint8_t i2c_id;
+ /* id used by atom */
+ uint8_t hpd_id;
/* can be used with hw i2c engine */
bool hw_capable;
/* uses multi-media i2c engine */
@@ -113,6 +115,7 @@ struct radeon_tmds_pll {
#define RADEON_MAX_BIOS_CONNECTOR 16
+/* pll flags */
#define RADEON_PLL_USE_BIOS_DIVS (1 << 0)
#define RADEON_PLL_NO_ODD_POST_DIV (1 << 1)
#define RADEON_PLL_USE_REF_DIV (1 << 2)
@@ -125,16 +128,30 @@ struct radeon_tmds_pll {
#define RADEON_PLL_PREFER_HIGH_POST_DIV (1 << 9)
#define RADEON_PLL_USE_FRAC_FB_DIV (1 << 10)
#define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11)
+#define RADEON_PLL_USE_POST_DIV (1 << 12)
+
+/* pll algo */
+enum radeon_pll_algo {
+ PLL_ALGO_LEGACY,
+ PLL_ALGO_NEW
+};
struct radeon_pll {
- uint16_t reference_freq;
- uint16_t reference_div;
+ /* reference frequency */
+ uint32_t reference_freq;
+
+ /* fixed dividers */
+ uint32_t reference_div;
+ uint32_t post_div;
+
+ /* pll in/out limits */
uint32_t pll_in_min;
uint32_t pll_in_max;
uint32_t pll_out_min;
uint32_t pll_out_max;
- uint16_t xclk;
+ uint32_t best_vco;
+ /* divider limits */
uint32_t min_ref_div;
uint32_t max_ref_div;
uint32_t min_post_div;
@@ -143,7 +160,19 @@ struct radeon_pll {
uint32_t max_feedback_div;
uint32_t min_frac_feedback_div;
uint32_t max_frac_feedback_div;
- uint32_t best_vco;
+
+ /* flags for the current clock */
+ uint32_t flags;
+
+ /* pll id */
+ uint32_t id;
+ /* pll algo */
+ enum radeon_pll_algo algo;
+};
+
+struct i2c_algo_radeon_data {
+ struct i2c_adapter bit_adapter;
+ struct i2c_algo_bit_data bit_data;
};
struct radeon_i2c_chan {
@@ -151,7 +180,7 @@ struct radeon_i2c_chan {
struct drm_device *dev;
union {
struct i2c_algo_dp_aux_data dp;
- struct i2c_algo_bit_data bit;
+ struct i2c_algo_radeon_data radeon;
} algo;
struct radeon_i2c_bus_rec rec;
};
@@ -180,7 +209,7 @@ struct radeon_mode_info {
struct card_info *atom_card_info;
enum radeon_connector_table connector_table;
bool mode_config_initialized;
- struct radeon_crtc *crtcs[2];
+ struct radeon_crtc *crtcs[6];
/* DVI-I properties */
struct drm_property *coherent_mode_property;
/* DAC enable load detect */
@@ -189,7 +218,8 @@ struct radeon_mode_info {
struct drm_property *tv_std_property;
/* legacy TMDS PLL detect */
struct drm_property *tmds_pll_property;
-
+ /* hardcoded DFP edid from BIOS */
+ struct edid *bios_hardcoded_edid;
};
#define MAX_H_CODE_TIMING_LEN 32
@@ -224,6 +254,7 @@ struct radeon_crtc {
fixed20_12 vsc;
fixed20_12 hsc;
struct drm_display_mode native_mode;
+ int pll_id;
};
struct radeon_encoder_primary_dac {
@@ -286,10 +317,11 @@ struct radeon_atom_ss {
struct radeon_encoder_atom_dig {
/* atom dig */
bool coherent_mode;
- int dig_block;
+ int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB */
/* atom lvds */
uint32_t lvds_misc;
uint16_t panel_pwr_delay;
+ enum radeon_pll_algo pll_algo;
struct radeon_atom_ss *ss;
/* panel mode */
struct drm_display_mode native_mode;
@@ -385,6 +417,7 @@ extern void dp_link_train(struct drm_encoder *encoder,
struct drm_connector *connector);
extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
+extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action);
extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,
int action, uint8_t lane_num,
uint8_t lane_set);
@@ -398,14 +431,15 @@ extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
struct radeon_i2c_bus_rec *rec,
const char *name);
extern void radeon_i2c_destroy(struct radeon_i2c_chan *i2c);
-extern void radeon_i2c_sw_get_byte(struct radeon_i2c_chan *i2c_bus,
- u8 slave_addr,
- u8 addr,
- u8 *val);
-extern void radeon_i2c_sw_put_byte(struct radeon_i2c_chan *i2c,
- u8 slave_addr,
- u8 addr,
- u8 val);
+extern void radeon_i2c_destroy_dp(struct radeon_i2c_chan *i2c);
+extern void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus,
+ u8 slave_addr,
+ u8 addr,
+ u8 *val);
+extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c,
+ u8 slave_addr,
+ u8 addr,
+ u8 val);
extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
@@ -417,17 +451,7 @@ extern void radeon_compute_pll(struct radeon_pll *pll,
uint32_t *fb_div_p,
uint32_t *frac_fb_div_p,
uint32_t *ref_div_p,
- uint32_t *post_div_p,
- int flags);
-
-extern void radeon_compute_pll_avivo(struct radeon_pll *pll,
- uint64_t freq,
- uint32_t *dot_clock_p,
- uint32_t *fb_div_p,
- uint32_t *frac_fb_div_p,
- uint32_t *ref_div_p,
- uint32_t *post_div_p,
- int flags);
+ uint32_t *post_div_p);
extern void radeon_setup_encoder_clones(struct drm_device *dev);
@@ -453,7 +477,6 @@ extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode);
extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb);
-extern void radeon_legacy_atom_set_surface(struct drm_crtc *crtc);
extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
struct drm_file *file_priv,
@@ -463,6 +486,9 @@ extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
int x, int y);
+extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);
+extern struct edid *
+radeon_combios_get_hardcoded_edid(struct radeon_device *rdev);
extern bool radeon_atom_get_clock_info(struct drm_device *dev);
extern bool radeon_combios_get_clock_info(struct drm_device *dev);
extern struct radeon_encoder_atom_dig *
@@ -521,7 +547,6 @@ void radeon_atombios_init_crtc(struct drm_device *dev,
struct radeon_crtc *radeon_crtc);
void radeon_legacy_init_crtc(struct drm_device *dev,
struct radeon_crtc *radeon_crtc);
-extern void radeon_i2c_do_lock(struct radeon_i2c_chan *i2c, int lock_state);
void radeon_get_clock_info(struct drm_device *dev);
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 4e636de877b2..fc9d00ac6b15 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -178,7 +178,6 @@ int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr)
{
int r, i;
- radeon_ttm_placement_from_domain(bo, domain);
if (bo->pin_count) {
bo->pin_count++;
if (gpu_addr)
@@ -186,6 +185,8 @@ int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr)
return 0;
}
radeon_ttm_placement_from_domain(bo, domain);
+ /* force to pin into visible video ram */
+ bo->placement.lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
for (i = 0; i < bo->placement.num_placement; i++)
bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
@@ -220,7 +221,8 @@ int radeon_bo_unpin(struct radeon_bo *bo)
int radeon_bo_evict_vram(struct radeon_device *rdev)
{
- if (rdev->flags & RADEON_IS_IGP) {
+ /* late 2.6.33 fix IGP hibernate - we need pm ops to do this correct */
+ if (0 && (rdev->flags & RADEON_IS_IGP)) {
if (rdev->mc.igp_sideport_enabled == false)
/* Useless to evict on IGP chips */
return 0;
@@ -305,11 +307,10 @@ void radeon_bo_list_unreserve(struct list_head *head)
}
}
-int radeon_bo_list_validate(struct list_head *head, void *fence)
+int radeon_bo_list_validate(struct list_head *head)
{
struct radeon_bo_list *lobj;
struct radeon_bo *bo;
- struct radeon_fence *old_fence = NULL;
int r;
r = radeon_bo_list_reserve(head);
@@ -333,32 +334,27 @@ int radeon_bo_list_validate(struct list_head *head, void *fence)
}
lobj->gpu_offset = radeon_bo_gpu_offset(bo);
lobj->tiling_flags = bo->tiling_flags;
- if (fence) {
- old_fence = (struct radeon_fence *)bo->tbo.sync_obj;
- bo->tbo.sync_obj = radeon_fence_ref(fence);
- bo->tbo.sync_obj_arg = NULL;
- }
- if (old_fence) {
- radeon_fence_unref(&old_fence);
- }
}
return 0;
}
-void radeon_bo_list_unvalidate(struct list_head *head, void *fence)
+void radeon_bo_list_fence(struct list_head *head, void *fence)
{
struct radeon_bo_list *lobj;
- struct radeon_fence *old_fence;
-
- if (fence)
- list_for_each_entry(lobj, head, list) {
- old_fence = to_radeon_fence(lobj->bo->tbo.sync_obj);
- if (old_fence == fence) {
- lobj->bo->tbo.sync_obj = NULL;
- radeon_fence_unref(&old_fence);
- }
+ struct radeon_bo *bo;
+ struct radeon_fence *old_fence = NULL;
+
+ list_for_each_entry(lobj, head, list) {
+ bo = lobj->bo;
+ spin_lock(&bo->tbo.lock);
+ old_fence = (struct radeon_fence *)bo->tbo.sync_obj;
+ bo->tbo.sync_obj = radeon_fence_ref(fence);
+ bo->tbo.sync_obj_arg = NULL;
+ spin_unlock(&bo->tbo.lock);
+ if (old_fence) {
+ radeon_fence_unref(&old_fence);
}
- radeon_bo_list_unreserve(head);
+ }
}
int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
index a02f18011ad1..7ab43de1e244 100644
--- a/drivers/gpu/drm/radeon/radeon_object.h
+++ b/drivers/gpu/drm/radeon/radeon_object.h
@@ -156,8 +156,8 @@ extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj,
struct list_head *head);
extern int radeon_bo_list_reserve(struct list_head *head);
extern void radeon_bo_list_unreserve(struct list_head *head);
-extern int radeon_bo_list_validate(struct list_head *head, void *fence);
-extern void radeon_bo_list_unvalidate(struct list_head *head, void *fence);
+extern int radeon_bo_list_validate(struct list_head *head);
+extern void radeon_bo_list_fence(struct list_head *head, void *fence);
extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
struct vm_area_struct *vma);
extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo,
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 8bce64cdc320..d4d1c39a0e99 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -18,21 +18,413 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Rafał Miłecki <zajec5@gmail.com>
+ * Alex Deucher <alexdeucher@gmail.com>
*/
#include "drmP.h"
#include "radeon.h"
+#include "avivod.h"
-int radeon_debugfs_pm_init(struct radeon_device *rdev);
+#define RADEON_IDLE_LOOP_MS 100
+#define RADEON_RECLOCK_DELAY_MS 200
+#define RADEON_WAIT_VBLANK_TIMEOUT 200
+
+static void radeon_pm_set_clocks_locked(struct radeon_device *rdev);
+static void radeon_pm_set_clocks(struct radeon_device *rdev);
+static void radeon_pm_idle_work_handler(struct work_struct *work);
+static int radeon_debugfs_pm_init(struct radeon_device *rdev);
+
+static const char *pm_state_names[4] = {
+ "PM_STATE_DISABLED",
+ "PM_STATE_MINIMUM",
+ "PM_STATE_PAUSED",
+ "PM_STATE_ACTIVE"
+};
+
+static const char *pm_state_types[5] = {
+ "Default",
+ "Powersave",
+ "Battery",
+ "Balanced",
+ "Performance",
+};
+
+static void radeon_print_power_mode_info(struct radeon_device *rdev)
+{
+ int i, j;
+ bool is_default;
+
+ DRM_INFO("%d Power State(s)\n", rdev->pm.num_power_states);
+ for (i = 0; i < rdev->pm.num_power_states; i++) {
+ if (rdev->pm.default_power_state == &rdev->pm.power_state[i])
+ is_default = true;
+ else
+ is_default = false;
+ DRM_INFO("State %d %s %s\n", i,
+ pm_state_types[rdev->pm.power_state[i].type],
+ is_default ? "(default)" : "");
+ if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP))
+ DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].non_clock_info.pcie_lanes);
+ DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes);
+ for (j = 0; j < rdev->pm.power_state[i].num_clock_modes; j++) {
+ if (rdev->flags & RADEON_IS_IGP)
+ DRM_INFO("\t\t%d engine: %d\n",
+ j,
+ rdev->pm.power_state[i].clock_info[j].sclk * 10);
+ else
+ DRM_INFO("\t\t%d engine/memory: %d/%d\n",
+ j,
+ rdev->pm.power_state[i].clock_info[j].sclk * 10,
+ rdev->pm.power_state[i].clock_info[j].mclk * 10);
+ }
+ }
+}
+
+static struct radeon_power_state * radeon_pick_power_state(struct radeon_device *rdev,
+ enum radeon_pm_state_type type)
+{
+ int i, j;
+ enum radeon_pm_state_type wanted_types[2];
+ int wanted_count;
+
+ switch (type) {
+ case POWER_STATE_TYPE_DEFAULT:
+ default:
+ return rdev->pm.default_power_state;
+ case POWER_STATE_TYPE_POWERSAVE:
+ if (rdev->flags & RADEON_IS_MOBILITY) {
+ wanted_types[0] = POWER_STATE_TYPE_POWERSAVE;
+ wanted_types[1] = POWER_STATE_TYPE_BATTERY;
+ wanted_count = 2;
+ } else {
+ wanted_types[0] = POWER_STATE_TYPE_PERFORMANCE;
+ wanted_count = 1;
+ }
+ break;
+ case POWER_STATE_TYPE_BATTERY:
+ if (rdev->flags & RADEON_IS_MOBILITY) {
+ wanted_types[0] = POWER_STATE_TYPE_BATTERY;
+ wanted_types[1] = POWER_STATE_TYPE_POWERSAVE;
+ wanted_count = 2;
+ } else {
+ wanted_types[0] = POWER_STATE_TYPE_PERFORMANCE;
+ wanted_count = 1;
+ }
+ break;
+ case POWER_STATE_TYPE_BALANCED:
+ case POWER_STATE_TYPE_PERFORMANCE:
+ wanted_types[0] = type;
+ wanted_count = 1;
+ break;
+ }
+
+ for (i = 0; i < wanted_count; i++) {
+ for (j = 0; j < rdev->pm.num_power_states; j++) {
+ if (rdev->pm.power_state[j].type == wanted_types[i])
+ return &rdev->pm.power_state[j];
+ }
+ }
+
+ return rdev->pm.default_power_state;
+}
+
+static struct radeon_pm_clock_info * radeon_pick_clock_mode(struct radeon_device *rdev,
+ struct radeon_power_state *power_state,
+ enum radeon_pm_clock_mode_type type)
+{
+ switch (type) {
+ case POWER_MODE_TYPE_DEFAULT:
+ default:
+ return power_state->default_clock_mode;
+ case POWER_MODE_TYPE_LOW:
+ return &power_state->clock_info[0];
+ case POWER_MODE_TYPE_MID:
+ if (power_state->num_clock_modes > 2)
+ return &power_state->clock_info[1];
+ else
+ return &power_state->clock_info[0];
+ break;
+ case POWER_MODE_TYPE_HIGH:
+ return &power_state->clock_info[power_state->num_clock_modes - 1];
+ }
+
+}
+
+static void radeon_get_power_state(struct radeon_device *rdev,
+ enum radeon_pm_action action)
+{
+ switch (action) {
+ case PM_ACTION_MINIMUM:
+ rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_BATTERY);
+ rdev->pm.requested_clock_mode =
+ radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_LOW);
+ break;
+ case PM_ACTION_DOWNCLOCK:
+ rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_POWERSAVE);
+ rdev->pm.requested_clock_mode =
+ radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_MID);
+ break;
+ case PM_ACTION_UPCLOCK:
+ rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_DEFAULT);
+ rdev->pm.requested_clock_mode =
+ radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_HIGH);
+ break;
+ case PM_ACTION_NONE:
+ default:
+ DRM_ERROR("Requested mode for not defined action\n");
+ return;
+ }
+ DRM_INFO("Requested: e: %d m: %d p: %d\n",
+ rdev->pm.requested_clock_mode->sclk,
+ rdev->pm.requested_clock_mode->mclk,
+ rdev->pm.requested_power_state->non_clock_info.pcie_lanes);
+}
+
+static void radeon_set_power_state(struct radeon_device *rdev)
+{
+ /* if *_clock_mode are the same, *_power_state are as well */
+ if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode)
+ return;
+
+ DRM_INFO("Setting: e: %d m: %d p: %d\n",
+ rdev->pm.requested_clock_mode->sclk,
+ rdev->pm.requested_clock_mode->mclk,
+ rdev->pm.requested_power_state->non_clock_info.pcie_lanes);
+ /* set pcie lanes */
+ /* set voltage */
+ /* set engine clock */
+ radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk);
+ /* set memory clock */
+
+ rdev->pm.current_power_state = rdev->pm.requested_power_state;
+ rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode;
+}
int radeon_pm_init(struct radeon_device *rdev)
{
+ rdev->pm.state = PM_STATE_DISABLED;
+ rdev->pm.planned_action = PM_ACTION_NONE;
+ rdev->pm.downclocked = false;
+
+ if (rdev->bios) {
+ if (rdev->is_atom_bios)
+ radeon_atombios_get_power_modes(rdev);
+ else
+ radeon_combios_get_power_modes(rdev);
+ radeon_print_power_mode_info(rdev);
+ }
+
if (radeon_debugfs_pm_init(rdev)) {
DRM_ERROR("Failed to register debugfs file for PM!\n");
}
+ INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler);
+
+ if (radeon_dynpm != -1 && radeon_dynpm) {
+ rdev->pm.state = PM_STATE_PAUSED;
+ DRM_INFO("radeon: dynamic power management enabled\n");
+ }
+
+ DRM_INFO("radeon: power management initialized\n");
+
return 0;
}
+void radeon_pm_compute_clocks(struct radeon_device *rdev)
+{
+ struct drm_device *ddev = rdev->ddev;
+ struct drm_connector *connector;
+ struct radeon_crtc *radeon_crtc;
+ int count = 0;
+
+ if (rdev->pm.state == PM_STATE_DISABLED)
+ return;
+
+ mutex_lock(&rdev->pm.mutex);
+
+ rdev->pm.active_crtcs = 0;
+ list_for_each_entry(connector,
+ &ddev->mode_config.connector_list, head) {
+ if (connector->encoder &&
+ connector->dpms != DRM_MODE_DPMS_OFF) {
+ radeon_crtc = to_radeon_crtc(connector->encoder->crtc);
+ rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id);
+ ++count;
+ }
+ }
+
+ if (count > 1) {
+ if (rdev->pm.state == PM_STATE_ACTIVE) {
+ cancel_delayed_work(&rdev->pm.idle_work);
+
+ rdev->pm.state = PM_STATE_PAUSED;
+ rdev->pm.planned_action = PM_ACTION_UPCLOCK;
+ if (rdev->pm.downclocked)
+ radeon_pm_set_clocks(rdev);
+
+ DRM_DEBUG("radeon: dynamic power management deactivated\n");
+ }
+ } else if (count == 1) {
+ /* TODO: Increase clocks if needed for current mode */
+
+ if (rdev->pm.state == PM_STATE_MINIMUM) {
+ rdev->pm.state = PM_STATE_ACTIVE;
+ rdev->pm.planned_action = PM_ACTION_UPCLOCK;
+ radeon_pm_set_clocks(rdev);
+
+ queue_delayed_work(rdev->wq, &rdev->pm.idle_work,
+ msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
+ }
+ else if (rdev->pm.state == PM_STATE_PAUSED) {
+ rdev->pm.state = PM_STATE_ACTIVE;
+ queue_delayed_work(rdev->wq, &rdev->pm.idle_work,
+ msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
+ DRM_DEBUG("radeon: dynamic power management activated\n");
+ }
+ }
+ else { /* count == 0 */
+ if (rdev->pm.state != PM_STATE_MINIMUM) {
+ cancel_delayed_work(&rdev->pm.idle_work);
+
+ rdev->pm.state = PM_STATE_MINIMUM;
+ rdev->pm.planned_action = PM_ACTION_MINIMUM;
+ radeon_pm_set_clocks(rdev);
+ }
+ }
+
+ mutex_unlock(&rdev->pm.mutex);
+}
+
+static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish)
+{
+ u32 stat_crtc1 = 0, stat_crtc2 = 0;
+ bool in_vbl = true;
+
+ if (ASIC_IS_AVIVO(rdev)) {
+ if (rdev->pm.active_crtcs & (1 << 0)) {
+ stat_crtc1 = RREG32(D1CRTC_STATUS);
+ if (!(stat_crtc1 & 1))
+ in_vbl = false;
+ }
+ if (rdev->pm.active_crtcs & (1 << 1)) {
+ stat_crtc2 = RREG32(D2CRTC_STATUS);
+ if (!(stat_crtc2 & 1))
+ in_vbl = false;
+ }
+ }
+ if (in_vbl == false)
+ DRM_INFO("not in vbl for pm change %08x %08x at %s\n", stat_crtc1,
+ stat_crtc2, finish ? "exit" : "entry");
+ return in_vbl;
+}
+static void radeon_pm_set_clocks_locked(struct radeon_device *rdev)
+{
+ /*radeon_fence_wait_last(rdev);*/
+ switch (rdev->pm.planned_action) {
+ case PM_ACTION_UPCLOCK:
+ rdev->pm.downclocked = false;
+ break;
+ case PM_ACTION_DOWNCLOCK:
+ rdev->pm.downclocked = true;
+ break;
+ case PM_ACTION_MINIMUM:
+ break;
+ case PM_ACTION_NONE:
+ DRM_ERROR("%s: PM_ACTION_NONE\n", __func__);
+ break;
+ }
+
+ /* check if we are in vblank */
+ radeon_pm_debug_check_in_vbl(rdev, false);
+ radeon_set_power_state(rdev);
+ radeon_pm_debug_check_in_vbl(rdev, true);
+ rdev->pm.planned_action = PM_ACTION_NONE;
+}
+
+static void radeon_pm_set_clocks(struct radeon_device *rdev)
+{
+ radeon_get_power_state(rdev, rdev->pm.planned_action);
+ mutex_lock(&rdev->cp.mutex);
+
+ if (rdev->pm.active_crtcs & (1 << 0)) {
+ rdev->pm.req_vblank |= (1 << 0);
+ drm_vblank_get(rdev->ddev, 0);
+ }
+ if (rdev->pm.active_crtcs & (1 << 1)) {
+ rdev->pm.req_vblank |= (1 << 1);
+ drm_vblank_get(rdev->ddev, 1);
+ }
+ if (rdev->pm.active_crtcs)
+ wait_event_interruptible_timeout(
+ rdev->irq.vblank_queue, 0,
+ msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT));
+ if (rdev->pm.req_vblank & (1 << 0)) {
+ rdev->pm.req_vblank &= ~(1 << 0);
+ drm_vblank_put(rdev->ddev, 0);
+ }
+ if (rdev->pm.req_vblank & (1 << 1)) {
+ rdev->pm.req_vblank &= ~(1 << 1);
+ drm_vblank_put(rdev->ddev, 1);
+ }
+
+ radeon_pm_set_clocks_locked(rdev);
+ mutex_unlock(&rdev->cp.mutex);
+}
+
+static void radeon_pm_idle_work_handler(struct work_struct *work)
+{
+ struct radeon_device *rdev;
+ rdev = container_of(work, struct radeon_device,
+ pm.idle_work.work);
+
+ mutex_lock(&rdev->pm.mutex);
+ if (rdev->pm.state == PM_STATE_ACTIVE) {
+ unsigned long irq_flags;
+ int not_processed = 0;
+
+ read_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
+ if (!list_empty(&rdev->fence_drv.emited)) {
+ struct list_head *ptr;
+ list_for_each(ptr, &rdev->fence_drv.emited) {
+ /* count up to 3, that's enought info */
+ if (++not_processed >= 3)
+ break;
+ }
+ }
+ read_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
+
+ if (not_processed >= 3) { /* should upclock */
+ if (rdev->pm.planned_action == PM_ACTION_DOWNCLOCK) {
+ rdev->pm.planned_action = PM_ACTION_NONE;
+ } else if (rdev->pm.planned_action == PM_ACTION_NONE &&
+ rdev->pm.downclocked) {
+ rdev->pm.planned_action =
+ PM_ACTION_UPCLOCK;
+ rdev->pm.action_timeout = jiffies +
+ msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS);
+ }
+ } else if (not_processed == 0) { /* should downclock */
+ if (rdev->pm.planned_action == PM_ACTION_UPCLOCK) {
+ rdev->pm.planned_action = PM_ACTION_NONE;
+ } else if (rdev->pm.planned_action == PM_ACTION_NONE &&
+ !rdev->pm.downclocked) {
+ rdev->pm.planned_action =
+ PM_ACTION_DOWNCLOCK;
+ rdev->pm.action_timeout = jiffies +
+ msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS);
+ }
+ }
+
+ if (rdev->pm.planned_action != PM_ACTION_NONE &&
+ jiffies > rdev->pm.action_timeout) {
+ radeon_pm_set_clocks(rdev);
+ }
+ }
+ mutex_unlock(&rdev->pm.mutex);
+
+ queue_delayed_work(rdev->wq, &rdev->pm.idle_work,
+ msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
+}
+
/*
* Debugfs info
*/
@@ -44,11 +436,14 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev;
struct radeon_device *rdev = dev->dev_private;
+ seq_printf(m, "state: %s\n", pm_state_names[rdev->pm.state]);
seq_printf(m, "default engine clock: %u0 kHz\n", rdev->clock.default_sclk);
seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev));
seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk);
if (rdev->asic->get_memory_clock)
seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev));
+ if (rdev->asic->get_pcie_lanes)
+ seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev));
return 0;
}
@@ -58,7 +453,7 @@ static struct drm_info_list radeon_pm_info_list[] = {
};
#endif
-int radeon_debugfs_pm_init(struct radeon_device *rdev)
+static int radeon_debugfs_pm_init(struct radeon_device *rdev)
{
#if defined(CONFIG_DEBUG_FS)
return radeon_debugfs_add_files(rdev, radeon_pm_info_list, ARRAY_SIZE(radeon_pm_info_list));
diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h
index 6d0a009dd4a1..5c0dc082d330 100644
--- a/drivers/gpu/drm/radeon/radeon_reg.h
+++ b/drivers/gpu/drm/radeon/radeon_reg.h
@@ -54,7 +54,7 @@
#include "r300_reg.h"
#include "r500_reg.h"
#include "r600_reg.h"
-
+#include "evergreen_reg.h"
#define RADEON_MC_AGP_LOCATION 0x014c
#define RADEON_MC_AGP_START_MASK 0x0000FFFF
@@ -1060,32 +1060,38 @@
/* Multimedia I2C bus */
#define RADEON_I2C_CNTL_0 0x0090
-#define RADEON_I2C_DONE (1 << 0)
-#define RADEON_I2C_NACK (1 << 1)
-#define RADEON_I2C_HALT (1 << 2)
-#define RADEON_I2C_SOFT_RST (1 << 5)
-#define RADEON_I2C_DRIVE_EN (1 << 6)
-#define RADEON_I2C_DRIVE_SEL (1 << 7)
-#define RADEON_I2C_START (1 << 8)
-#define RADEON_I2C_STOP (1 << 9)
-#define RADEON_I2C_RECEIVE (1 << 10)
-#define RADEON_I2C_ABORT (1 << 11)
-#define RADEON_I2C_GO (1 << 12)
-#define RADEON_I2C_PRESCALE_SHIFT 16
+# define RADEON_I2C_DONE (1 << 0)
+# define RADEON_I2C_NACK (1 << 1)
+# define RADEON_I2C_HALT (1 << 2)
+# define RADEON_I2C_SOFT_RST (1 << 5)
+# define RADEON_I2C_DRIVE_EN (1 << 6)
+# define RADEON_I2C_DRIVE_SEL (1 << 7)
+# define RADEON_I2C_START (1 << 8)
+# define RADEON_I2C_STOP (1 << 9)
+# define RADEON_I2C_RECEIVE (1 << 10)
+# define RADEON_I2C_ABORT (1 << 11)
+# define RADEON_I2C_GO (1 << 12)
+# define RADEON_I2C_PRESCALE_SHIFT 16
#define RADEON_I2C_CNTL_1 0x0094
-#define RADEON_I2C_DATA_COUNT_SHIFT 0
-#define RADEON_I2C_ADDR_COUNT_SHIFT 4
-#define RADEON_I2C_INTRA_BYTE_DELAY_SHIFT 8
-#define RADEON_I2C_SEL (1 << 16)
-#define RADEON_I2C_EN (1 << 17)
-#define RADEON_I2C_TIME_LIMIT_SHIFT 24
+# define RADEON_I2C_DATA_COUNT_SHIFT 0
+# define RADEON_I2C_ADDR_COUNT_SHIFT 4
+# define RADEON_I2C_INTRA_BYTE_DELAY_SHIFT 8
+# define RADEON_I2C_SEL (1 << 16)
+# define RADEON_I2C_EN (1 << 17)
+# define RADEON_I2C_TIME_LIMIT_SHIFT 24
#define RADEON_I2C_DATA 0x0098
#define RADEON_DVI_I2C_CNTL_0 0x02e0
# define R200_DVI_I2C_PIN_SEL(x) ((x) << 3)
-# define R200_SEL_DDC1 0 /* 0x60 - VGA_DDC */
-# define R200_SEL_DDC2 1 /* 0x64 - DVI_DDC */
-# define R200_SEL_DDC3 2 /* 0x68 - MONID_DDC */
+# define R200_SEL_DDC1 0 /* depends on asic */
+# define R200_SEL_DDC2 1 /* depends on asic */
+# define R200_SEL_DDC3 2 /* depends on asic */
+# define RADEON_SW_WANTS_TO_USE_DVI_I2C (1 << 13)
+# define RADEON_SW_CAN_USE_DVI_I2C (1 << 13)
+# define RADEON_SW_DONE_USING_DVI_I2C (1 << 14)
+# define RADEON_HW_NEEDS_DVI_I2C (1 << 14)
+# define RADEON_ABORT_HW_DVI_I2C (1 << 15)
+# define RADEON_HW_USING_DVI_I2C (1 << 15)
#define RADEON_DVI_I2C_CNTL_1 0x02e4
#define RADEON_DVI_I2C_DATA 0x02e8
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index 4d12b2d17b4d..e50513a62735 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -34,6 +34,36 @@
int radeon_debugfs_ib_init(struct radeon_device *rdev);
+void radeon_ib_bogus_cleanup(struct radeon_device *rdev)
+{
+ struct radeon_ib *ib, *n;
+
+ list_for_each_entry_safe(ib, n, &rdev->ib_pool.bogus_ib, list) {
+ list_del(&ib->list);
+ vfree(ib->ptr);
+ kfree(ib);
+ }
+}
+
+void radeon_ib_bogus_add(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+ struct radeon_ib *bib;
+
+ bib = kmalloc(sizeof(*bib), GFP_KERNEL);
+ if (bib == NULL)
+ return;
+ bib->ptr = vmalloc(ib->length_dw * 4);
+ if (bib->ptr == NULL) {
+ kfree(bib);
+ return;
+ }
+ memcpy(bib->ptr, ib->ptr, ib->length_dw * 4);
+ bib->length_dw = ib->length_dw;
+ mutex_lock(&rdev->ib_pool.mutex);
+ list_add_tail(&bib->list, &rdev->ib_pool.bogus_ib);
+ mutex_unlock(&rdev->ib_pool.mutex);
+}
+
/*
* IB.
*/
@@ -41,68 +71,55 @@ int radeon_ib_get(struct radeon_device *rdev, struct radeon_ib **ib)
{
struct radeon_fence *fence;
struct radeon_ib *nib;
- unsigned long i;
- int r = 0;
+ int r = 0, i, c;
*ib = NULL;
r = radeon_fence_create(rdev, &fence);
if (r) {
- DRM_ERROR("failed to create fence for new IB\n");
+ dev_err(rdev->dev, "failed to create fence for new IB\n");
return r;
}
mutex_lock(&rdev->ib_pool.mutex);
- i = find_first_zero_bit(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE);
- if (i < RADEON_IB_POOL_SIZE) {
- set_bit(i, rdev->ib_pool.alloc_bm);
- rdev->ib_pool.ibs[i].length_dw = 0;
- *ib = &rdev->ib_pool.ibs[i];
- mutex_unlock(&rdev->ib_pool.mutex);
- goto out;
+ for (i = rdev->ib_pool.head_id, c = 0, nib = NULL; c < RADEON_IB_POOL_SIZE; c++, i++) {
+ i &= (RADEON_IB_POOL_SIZE - 1);
+ if (rdev->ib_pool.ibs[i].free) {
+ nib = &rdev->ib_pool.ibs[i];
+ break;
+ }
}
- if (list_empty(&rdev->ib_pool.scheduled_ibs)) {
- /* we go do nothings here */
+ if (nib == NULL) {
+ /* This should never happen, it means we allocated all
+ * IB and haven't scheduled one yet, return EBUSY to
+ * userspace hoping that on ioctl recall we get better
+ * luck
+ */
+ dev_err(rdev->dev, "no free indirect buffer !\n");
mutex_unlock(&rdev->ib_pool.mutex);
- DRM_ERROR("all IB allocated none scheduled.\n");
- r = -EINVAL;
- goto out;
+ radeon_fence_unref(&fence);
+ return -EBUSY;
}
- /* get the first ib on the scheduled list */
- nib = list_entry(rdev->ib_pool.scheduled_ibs.next,
- struct radeon_ib, list);
- if (nib->fence == NULL) {
- /* we go do nothings here */
+ rdev->ib_pool.head_id = (nib->idx + 1) & (RADEON_IB_POOL_SIZE - 1);
+ nib->free = false;
+ if (nib->fence) {
mutex_unlock(&rdev->ib_pool.mutex);
- DRM_ERROR("IB %lu scheduled without a fence.\n", nib->idx);
- r = -EINVAL;
- goto out;
- }
- mutex_unlock(&rdev->ib_pool.mutex);
-
- r = radeon_fence_wait(nib->fence, false);
- if (r) {
- DRM_ERROR("radeon: IB(%lu:0x%016lX:%u)\n", nib->idx,
- (unsigned long)nib->gpu_addr, nib->length_dw);
- DRM_ERROR("radeon: GPU lockup detected, fail to get a IB\n");
- goto out;
+ r = radeon_fence_wait(nib->fence, false);
+ if (r) {
+ dev_err(rdev->dev, "error waiting fence of IB(%u:0x%016lX:%u)\n",
+ nib->idx, (unsigned long)nib->gpu_addr, nib->length_dw);
+ mutex_lock(&rdev->ib_pool.mutex);
+ nib->free = true;
+ mutex_unlock(&rdev->ib_pool.mutex);
+ radeon_fence_unref(&fence);
+ return r;
+ }
+ mutex_lock(&rdev->ib_pool.mutex);
}
radeon_fence_unref(&nib->fence);
-
+ nib->fence = fence;
nib->length_dw = 0;
-
- /* scheduled list is accessed here */
- mutex_lock(&rdev->ib_pool.mutex);
- list_del(&nib->list);
- INIT_LIST_HEAD(&nib->list);
mutex_unlock(&rdev->ib_pool.mutex);
-
*ib = nib;
-out:
- if (r) {
- radeon_fence_unref(&fence);
- } else {
- (*ib)->fence = fence;
- }
- return r;
+ return 0;
}
void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib)
@@ -113,19 +130,10 @@ void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib)
if (tmp == NULL) {
return;
}
- mutex_lock(&rdev->ib_pool.mutex);
- if (!list_empty(&tmp->list) && !radeon_fence_signaled(tmp->fence)) {
- /* IB is scheduled & not signaled don't do anythings */
- mutex_unlock(&rdev->ib_pool.mutex);
- return;
- }
- list_del(&tmp->list);
- INIT_LIST_HEAD(&tmp->list);
- if (tmp->fence)
+ if (!tmp->fence->emited)
radeon_fence_unref(&tmp->fence);
-
- tmp->length_dw = 0;
- clear_bit(tmp->idx, rdev->ib_pool.alloc_bm);
+ mutex_lock(&rdev->ib_pool.mutex);
+ tmp->free = true;
mutex_unlock(&rdev->ib_pool.mutex);
}
@@ -135,7 +143,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
if (!ib->length_dw || !rdev->cp.ready) {
/* TODO: Nothings in the ib we should report. */
- DRM_ERROR("radeon: couldn't schedule IB(%lu).\n", ib->idx);
+ DRM_ERROR("radeon: couldn't schedule IB(%u).\n", ib->idx);
return -EINVAL;
}
@@ -148,7 +156,8 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
radeon_ring_ib_execute(rdev, ib);
radeon_fence_emit(rdev, ib->fence);
mutex_lock(&rdev->ib_pool.mutex);
- list_add_tail(&ib->list, &rdev->ib_pool.scheduled_ibs);
+ /* once scheduled IB is considered free and protected by the fence */
+ ib->free = true;
mutex_unlock(&rdev->ib_pool.mutex);
radeon_ring_unlock_commit(rdev);
return 0;
@@ -163,8 +172,8 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
if (rdev->ib_pool.robj)
return 0;
+ INIT_LIST_HEAD(&rdev->ib_pool.bogus_ib);
/* Allocate 1M object buffer */
- INIT_LIST_HEAD(&rdev->ib_pool.scheduled_ibs);
r = radeon_bo_create(rdev, NULL, RADEON_IB_POOL_SIZE*64*1024,
true, RADEON_GEM_DOMAIN_GTT,
&rdev->ib_pool.robj);
@@ -195,9 +204,9 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
rdev->ib_pool.ibs[i].ptr = ptr + offset;
rdev->ib_pool.ibs[i].idx = i;
rdev->ib_pool.ibs[i].length_dw = 0;
- INIT_LIST_HEAD(&rdev->ib_pool.ibs[i].list);
+ rdev->ib_pool.ibs[i].free = true;
}
- bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE);
+ rdev->ib_pool.head_id = 0;
rdev->ib_pool.ready = true;
DRM_INFO("radeon: ib pool ready.\n");
if (radeon_debugfs_ib_init(rdev)) {
@@ -214,7 +223,8 @@ void radeon_ib_pool_fini(struct radeon_device *rdev)
return;
}
mutex_lock(&rdev->ib_pool.mutex);
- bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE);
+ radeon_ib_bogus_cleanup(rdev);
+
if (rdev->ib_pool.robj) {
r = radeon_bo_reserve(rdev->ib_pool.robj, false);
if (likely(r == 0)) {
@@ -363,7 +373,7 @@ static int radeon_debugfs_ib_info(struct seq_file *m, void *data)
if (ib == NULL) {
return 0;
}
- seq_printf(m, "IB %04lu\n", ib->idx);
+ seq_printf(m, "IB %04u\n", ib->idx);
seq_printf(m, "IB fence %p\n", ib->fence);
seq_printf(m, "IB size %05u dwords\n", ib->length_dw);
for (i = 0; i < ib->length_dw; i++) {
@@ -372,15 +382,49 @@ static int radeon_debugfs_ib_info(struct seq_file *m, void *data)
return 0;
}
+static int radeon_debugfs_ib_bogus_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct radeon_device *rdev = node->info_ent->data;
+ struct radeon_ib *ib;
+ unsigned i;
+
+ mutex_lock(&rdev->ib_pool.mutex);
+ if (list_empty(&rdev->ib_pool.bogus_ib)) {
+ mutex_unlock(&rdev->ib_pool.mutex);
+ seq_printf(m, "no bogus IB recorded\n");
+ return 0;
+ }
+ ib = list_first_entry(&rdev->ib_pool.bogus_ib, struct radeon_ib, list);
+ list_del_init(&ib->list);
+ mutex_unlock(&rdev->ib_pool.mutex);
+ seq_printf(m, "IB size %05u dwords\n", ib->length_dw);
+ for (i = 0; i < ib->length_dw; i++) {
+ seq_printf(m, "[%05u]=0x%08X\n", i, ib->ptr[i]);
+ }
+ vfree(ib->ptr);
+ kfree(ib);
+ return 0;
+}
+
static struct drm_info_list radeon_debugfs_ib_list[RADEON_IB_POOL_SIZE];
static char radeon_debugfs_ib_names[RADEON_IB_POOL_SIZE][32];
+
+static struct drm_info_list radeon_debugfs_ib_bogus_info_list[] = {
+ {"radeon_ib_bogus", radeon_debugfs_ib_bogus_info, 0, NULL},
+};
#endif
int radeon_debugfs_ib_init(struct radeon_device *rdev)
{
#if defined(CONFIG_DEBUG_FS)
unsigned i;
+ int r;
+ radeon_debugfs_ib_bogus_info_list[0].data = rdev;
+ r = radeon_debugfs_add_files(rdev, radeon_debugfs_ib_bogus_info_list, 1);
+ if (r)
+ return r;
for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
sprintf(radeon_debugfs_ib_names[i], "radeon_ib_%04u", i);
radeon_debugfs_ib_list[i].name = radeon_debugfs_ib_names[i];
diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c
index 067167cb39ca..40ab6d9c3736 100644
--- a/drivers/gpu/drm/radeon/radeon_state.c
+++ b/drivers/gpu/drm/radeon/radeon_state.c
@@ -29,6 +29,7 @@
#include "drmP.h"
#include "drm.h"
+#include "drm_buffer.h"
#include "drm_sarea.h"
#include "radeon_drm.h"
#include "radeon_drv.h"
@@ -91,21 +92,27 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
dev_priv,
struct drm_file *file_priv,
- int id, u32 *data)
+ int id, struct drm_buffer *buf)
{
+ u32 *data;
switch (id) {
case RADEON_EMIT_PP_MISC:
- if (radeon_check_and_fixup_offset(dev_priv, file_priv,
- &data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) {
+ data = drm_buffer_pointer_to_dword(buf,
+ (RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4);
+
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) {
DRM_ERROR("Invalid depth buffer offset\n");
return -EINVAL;
}
+ dev_priv->have_z_offset = 1;
break;
case RADEON_EMIT_PP_CNTL:
- if (radeon_check_and_fixup_offset(dev_priv, file_priv,
- &data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) {
+ data = drm_buffer_pointer_to_dword(buf,
+ (RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4);
+
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) {
DRM_ERROR("Invalid colour buffer offset\n");
return -EINVAL;
}
@@ -117,8 +124,8 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
case R200_EMIT_PP_TXOFFSET_3:
case R200_EMIT_PP_TXOFFSET_4:
case R200_EMIT_PP_TXOFFSET_5:
- if (radeon_check_and_fixup_offset(dev_priv, file_priv,
- &data[0])) {
+ data = drm_buffer_pointer_to_dword(buf, 0);
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) {
DRM_ERROR("Invalid R200 texture offset\n");
return -EINVAL;
}
@@ -127,8 +134,9 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
case RADEON_EMIT_PP_TXFILTER_0:
case RADEON_EMIT_PP_TXFILTER_1:
case RADEON_EMIT_PP_TXFILTER_2:
- if (radeon_check_and_fixup_offset(dev_priv, file_priv,
- &data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) {
+ data = drm_buffer_pointer_to_dword(buf,
+ (RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4);
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) {
DRM_ERROR("Invalid R100 texture offset\n");
return -EINVAL;
}
@@ -142,9 +150,10 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
case R200_EMIT_PP_CUBIC_OFFSETS_5:{
int i;
for (i = 0; i < 5; i++) {
+ data = drm_buffer_pointer_to_dword(buf, i);
if (radeon_check_and_fixup_offset(dev_priv,
file_priv,
- &data[i])) {
+ data)) {
DRM_ERROR
("Invalid R200 cubic texture offset\n");
return -EINVAL;
@@ -158,9 +167,10 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:{
int i;
for (i = 0; i < 5; i++) {
+ data = drm_buffer_pointer_to_dword(buf, i);
if (radeon_check_and_fixup_offset(dev_priv,
file_priv,
- &data[i])) {
+ data)) {
DRM_ERROR
("Invalid R100 cubic texture offset\n");
return -EINVAL;
@@ -269,23 +279,24 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
cmdbuf,
unsigned int *cmdsz)
{
- u32 *cmd = (u32 *) cmdbuf->buf;
+ u32 *cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
u32 offset, narrays;
int count, i, k;
- *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);
+ count = ((*cmd & RADEON_CP_PACKET_COUNT_MASK) >> 16);
+ *cmdsz = 2 + count;
- if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) {
+ if ((*cmd & 0xc0000000) != RADEON_CP_PACKET3) {
DRM_ERROR("Not a type 3 packet\n");
return -EINVAL;
}
- if (4 * *cmdsz > cmdbuf->bufsz) {
+ if (4 * *cmdsz > drm_buffer_unprocessed(cmdbuf->buffer)) {
DRM_ERROR("Packet size larger than size of data provided\n");
return -EINVAL;
}
- switch(cmd[0] & 0xff00) {
+ switch (*cmd & 0xff00) {
/* XXX Are there old drivers needing other packets? */
case RADEON_3D_DRAW_IMMD:
@@ -312,7 +323,6 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
break;
case RADEON_3D_LOAD_VBPNTR:
- count = (cmd[0] >> 16) & 0x3fff;
if (count > 18) { /* 12 arrays max */
DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
@@ -321,13 +331,16 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
}
/* carefully check packet contents */
- narrays = cmd[1] & ~0xc000;
+ cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
+
+ narrays = *cmd & ~0xc000;
k = 0;
i = 2;
while ((k < narrays) && (i < (count + 2))) {
i++; /* skip attribute field */
+ cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
if (radeon_check_and_fixup_offset(dev_priv, file_priv,
- &cmd[i])) {
+ cmd)) {
DRM_ERROR
("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
k, i);
@@ -338,8 +351,10 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
if (k == narrays)
break;
/* have one more to process, they come in pairs */
+ cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
+
if (radeon_check_and_fixup_offset(dev_priv,
- file_priv, &cmd[i]))
+ file_priv, cmd))
{
DRM_ERROR
("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
@@ -363,7 +378,9 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
DRM_ERROR("Invalid 3d packet for r200-class chip\n");
return -EINVAL;
}
- if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[1])) {
+
+ cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv, cmd)) {
DRM_ERROR("Invalid rndr_gen_indx offset\n");
return -EINVAL;
}
@@ -374,12 +391,15 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
DRM_ERROR("Invalid 3d packet for r100-class chip\n");
return -EINVAL;
}
- if ((cmd[1] & 0x8000ffff) != 0x80000810) {
- DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
+
+ cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
+ if ((*cmd & 0x8000ffff) != 0x80000810) {
+ DRM_ERROR("Invalid indx_buffer reg address %08X\n", *cmd);
return -EINVAL;
}
- if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[2])) {
- DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
+ cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2);
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv, cmd)) {
+ DRM_ERROR("Invalid indx_buffer offset is %08X\n", *cmd);
return -EINVAL;
}
break;
@@ -388,31 +408,34 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
case RADEON_CNTL_PAINT_MULTI:
case RADEON_CNTL_BITBLT_MULTI:
/* MSB of opcode: next DWORD GUI_CNTL */
- if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
+ cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
+ if (*cmd & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
| RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
- offset = cmd[2] << 10;
+ u32 *cmd2 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2);
+ offset = *cmd2 << 10;
if (radeon_check_and_fixup_offset
(dev_priv, file_priv, &offset)) {
DRM_ERROR("Invalid first packet offset\n");
return -EINVAL;
}
- cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10;
+ *cmd2 = (*cmd2 & 0xffc00000) | offset >> 10;
}
- if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
- (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
- offset = cmd[3] << 10;
+ if ((*cmd & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
+ (*cmd & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
+ u32 *cmd3 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 3);
+ offset = *cmd << 10;
if (radeon_check_and_fixup_offset
(dev_priv, file_priv, &offset)) {
DRM_ERROR("Invalid second packet offset\n");
return -EINVAL;
}
- cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
+ *cmd3 = (*cmd3 & 0xffc00000) | offset >> 10;
}
break;
default:
- DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00);
+ DRM_ERROR("Invalid packet type %x\n", *cmd & 0xff00);
return -EINVAL;
}
@@ -876,6 +899,11 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev,
if (tmp & RADEON_BACK)
flags |= RADEON_FRONT;
}
+ if (flags & (RADEON_DEPTH|RADEON_STENCIL)) {
+ if (!dev_priv->have_z_offset)
+ printk_once(KERN_ERR "radeon: illegal depth clear request. Buggy mesa detected - please update.\n");
+ flags &= ~(RADEON_DEPTH | RADEON_STENCIL);
+ }
if (flags & (RADEON_FRONT | RADEON_BACK)) {
@@ -1065,7 +1093,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev,
/* judging by the first tile offset needed, could possibly
directly address/clear 4x4 tiles instead of 8x2 * 4x4
macro tiles, though would still need clear mask for
- right/bottom if truely 4x4 granularity is desired ? */
+ right/bottom if truly 4x4 granularity is desired ? */
OUT_RING(tileoffset * 16);
/* the number of tiles to clear */
OUT_RING(nrtilesx + 1);
@@ -2611,7 +2639,6 @@ static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
{
int id = (int)header.packet.packet_id;
int sz, reg;
- int *data = (int *)cmdbuf->buf;
RING_LOCALS;
if (id >= RADEON_MAX_STATE_PACKETS)
@@ -2620,23 +2647,22 @@ static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
sz = packet[id].len;
reg = packet[id].start;
- if (sz * sizeof(int) > cmdbuf->bufsz) {
+ if (sz * sizeof(u32) > drm_buffer_unprocessed(cmdbuf->buffer)) {
DRM_ERROR("Packet size provided larger than data provided\n");
return -EINVAL;
}
- if (radeon_check_and_fixup_packets(dev_priv, file_priv, id, data)) {
+ if (radeon_check_and_fixup_packets(dev_priv, file_priv, id,
+ cmdbuf->buffer)) {
DRM_ERROR("Packet verification failed\n");
return -EINVAL;
}
BEGIN_RING(sz + 1);
OUT_RING(CP_PACKET0(reg, (sz - 1)));
- OUT_RING_TABLE(data, sz);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
ADVANCE_RING();
- cmdbuf->buf += sz * sizeof(int);
- cmdbuf->bufsz -= sz * sizeof(int);
return 0;
}
@@ -2653,10 +2679,8 @@ static __inline__ int radeon_emit_scalars(drm_radeon_private_t *dev_priv,
OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
- OUT_RING_TABLE(cmdbuf->buf, sz);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
ADVANCE_RING();
- cmdbuf->buf += sz * sizeof(int);
- cmdbuf->bufsz -= sz * sizeof(int);
return 0;
}
@@ -2675,10 +2699,8 @@ static __inline__ int radeon_emit_scalars2(drm_radeon_private_t *dev_priv,
OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
- OUT_RING_TABLE(cmdbuf->buf, sz);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
ADVANCE_RING();
- cmdbuf->buf += sz * sizeof(int);
- cmdbuf->bufsz -= sz * sizeof(int);
return 0;
}
@@ -2696,11 +2718,9 @@ static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
- OUT_RING_TABLE(cmdbuf->buf, sz);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
ADVANCE_RING();
- cmdbuf->buf += sz * sizeof(int);
- cmdbuf->bufsz -= sz * sizeof(int);
return 0;
}
@@ -2714,7 +2734,7 @@ static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
if (!sz)
return 0;
- if (sz * 4 > cmdbuf->bufsz)
+ if (sz * 4 > drm_buffer_unprocessed(cmdbuf->buffer))
return -EINVAL;
BEGIN_RING(5 + sz);
@@ -2722,11 +2742,9 @@ static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
- OUT_RING_TABLE(cmdbuf->buf, sz);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
ADVANCE_RING();
- cmdbuf->buf += sz * sizeof(int);
- cmdbuf->bufsz -= sz * sizeof(int);
return 0;
}
@@ -2748,11 +2766,9 @@ static int radeon_emit_packet3(struct drm_device * dev,
}
BEGIN_RING(cmdsz);
- OUT_RING_TABLE(cmdbuf->buf, cmdsz);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, cmdsz);
ADVANCE_RING();
- cmdbuf->buf += cmdsz * 4;
- cmdbuf->bufsz -= cmdsz * 4;
return 0;
}
@@ -2805,16 +2821,16 @@ static int radeon_emit_packet3_cliprect(struct drm_device *dev,
}
BEGIN_RING(cmdsz);
- OUT_RING_TABLE(cmdbuf->buf, cmdsz);
+ OUT_RING_DRM_BUFFER(cmdbuf->buffer, cmdsz);
ADVANCE_RING();
} while (++i < cmdbuf->nbox);
if (cmdbuf->nbox == 1)
cmdbuf->nbox = 0;
+ return 0;
out:
- cmdbuf->buf += cmdsz * 4;
- cmdbuf->bufsz -= cmdsz * 4;
+ drm_buffer_advance(cmdbuf->buffer, cmdsz * 4);
return 0;
}
@@ -2847,16 +2863,16 @@ static int radeon_emit_wait(struct drm_device * dev, int flags)
return 0;
}
-static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv)
+static int radeon_cp_cmdbuf(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf = NULL;
+ drm_radeon_cmd_header_t stack_header;
int idx;
drm_radeon_kcmd_buffer_t *cmdbuf = data;
- drm_radeon_cmd_header_t header;
- int orig_nbox, orig_bufsz;
- char *kbuf = NULL;
+ int orig_nbox;
LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -2871,17 +2887,16 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file
* races between checking values and using those values in other code,
* and simply to avoid a lot of function calls to copy in data.
*/
- orig_bufsz = cmdbuf->bufsz;
- if (orig_bufsz != 0) {
- kbuf = kmalloc(cmdbuf->bufsz, GFP_KERNEL);
- if (kbuf == NULL)
- return -ENOMEM;
- if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf->buf,
- cmdbuf->bufsz)) {
- kfree(kbuf);
- return -EFAULT;
- }
- cmdbuf->buf = kbuf;
+ if (cmdbuf->bufsz != 0) {
+ int rv;
+ void __user *buffer = cmdbuf->buffer;
+ rv = drm_buffer_alloc(&cmdbuf->buffer, cmdbuf->bufsz);
+ if (rv)
+ return rv;
+ rv = drm_buffer_copy_from_user(cmdbuf->buffer, buffer,
+ cmdbuf->bufsz);
+ if (rv)
+ return rv;
}
orig_nbox = cmdbuf->nbox;
@@ -2890,24 +2905,24 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file
int temp;
temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf);
- if (orig_bufsz != 0)
- kfree(kbuf);
+ if (cmdbuf->bufsz != 0)
+ drm_buffer_free(cmdbuf->buffer);
return temp;
}
/* microcode_version != r300 */
- while (cmdbuf->bufsz >= sizeof(header)) {
+ while (drm_buffer_unprocessed(cmdbuf->buffer) >= sizeof(stack_header)) {
- header.i = *(int *)cmdbuf->buf;
- cmdbuf->buf += sizeof(header);
- cmdbuf->bufsz -= sizeof(header);
+ drm_radeon_cmd_header_t *header;
+ header = drm_buffer_read_object(cmdbuf->buffer,
+ sizeof(stack_header), &stack_header);
- switch (header.header.cmd_type) {
+ switch (header->header.cmd_type) {
case RADEON_CMD_PACKET:
DRM_DEBUG("RADEON_CMD_PACKET\n");
if (radeon_emit_packets
- (dev_priv, file_priv, header, cmdbuf)) {
+ (dev_priv, file_priv, *header, cmdbuf)) {
DRM_ERROR("radeon_emit_packets failed\n");
goto err;
}
@@ -2915,7 +2930,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file
case RADEON_CMD_SCALARS:
DRM_DEBUG("RADEON_CMD_SCALARS\n");
- if (radeon_emit_scalars(dev_priv, header, cmdbuf)) {
+ if (radeon_emit_scalars(dev_priv, *header, cmdbuf)) {
DRM_ERROR("radeon_emit_scalars failed\n");
goto err;
}
@@ -2923,7 +2938,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file
case RADEON_CMD_VECTORS:
DRM_DEBUG("RADEON_CMD_VECTORS\n");
- if (radeon_emit_vectors(dev_priv, header, cmdbuf)) {
+ if (radeon_emit_vectors(dev_priv, *header, cmdbuf)) {
DRM_ERROR("radeon_emit_vectors failed\n");
goto err;
}
@@ -2931,7 +2946,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file
case RADEON_CMD_DMA_DISCARD:
DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
- idx = header.dma.buf_idx;
+ idx = header->dma.buf_idx;
if (idx < 0 || idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
idx, dma->buf_count - 1);
@@ -2968,7 +2983,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file
case RADEON_CMD_SCALARS2:
DRM_DEBUG("RADEON_CMD_SCALARS2\n");
- if (radeon_emit_scalars2(dev_priv, header, cmdbuf)) {
+ if (radeon_emit_scalars2(dev_priv, *header, cmdbuf)) {
DRM_ERROR("radeon_emit_scalars2 failed\n");
goto err;
}
@@ -2976,37 +2991,37 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file
case RADEON_CMD_WAIT:
DRM_DEBUG("RADEON_CMD_WAIT\n");
- if (radeon_emit_wait(dev, header.wait.flags)) {
+ if (radeon_emit_wait(dev, header->wait.flags)) {
DRM_ERROR("radeon_emit_wait failed\n");
goto err;
}
break;
case RADEON_CMD_VECLINEAR:
DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
- if (radeon_emit_veclinear(dev_priv, header, cmdbuf)) {
+ if (radeon_emit_veclinear(dev_priv, *header, cmdbuf)) {
DRM_ERROR("radeon_emit_veclinear failed\n");
goto err;
}
break;
default:
- DRM_ERROR("bad cmd_type %d at %p\n",
- header.header.cmd_type,
- cmdbuf->buf - sizeof(header));
+ DRM_ERROR("bad cmd_type %d at byte %d\n",
+ header->header.cmd_type,
+ cmdbuf->buffer->iterator);
goto err;
}
}
- if (orig_bufsz != 0)
- kfree(kbuf);
+ if (cmdbuf->bufsz != 0)
+ drm_buffer_free(cmdbuf->buffer);
DRM_DEBUG("DONE\n");
COMMIT_RING();
return 0;
err:
- if (orig_bufsz != 0)
- kfree(kbuf);
+ if (cmdbuf->bufsz != 0)
+ drm_buffer_free(cmdbuf->buffer);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c
index 9f5e2f929da9..313c96bc09da 100644
--- a/drivers/gpu/drm/radeon/radeon_test.c
+++ b/drivers/gpu/drm/radeon/radeon_test.c
@@ -186,7 +186,7 @@ void radeon_test_moves(struct radeon_device *rdev)
radeon_bo_kunmap(gtt_obj[i]);
DRM_INFO("Tested GTT->VRAM and VRAM->GTT copy for GTT offset 0x%llx\n",
- gtt_addr - rdev->mc.gtt_location);
+ gtt_addr - rdev->mc.gtt_start);
}
out_cleanup:
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 58b5adf974ca..43c5ab34b634 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -150,7 +150,7 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
man->default_caching = TTM_PL_FLAG_CACHED;
break;
case TTM_PL_TT:
- man->gpu_offset = rdev->mc.gtt_location;
+ man->gpu_offset = rdev->mc.gtt_start;
man->available_caching = TTM_PL_MASK_CACHING;
man->default_caching = TTM_PL_FLAG_CACHED;
man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | TTM_MEMTYPE_FLAG_CMA;
@@ -180,7 +180,7 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
break;
case TTM_PL_VRAM:
/* "On-card" video ram */
- man->gpu_offset = rdev->mc.vram_location;
+ man->gpu_offset = rdev->mc.vram_start;
man->flags = TTM_MEMTYPE_FLAG_FIXED |
TTM_MEMTYPE_FLAG_NEEDS_IOREMAP |
TTM_MEMTYPE_FLAG_MAPPABLE;
@@ -262,10 +262,10 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
switch (old_mem->mem_type) {
case TTM_PL_VRAM:
- old_start += rdev->mc.vram_location;
+ old_start += rdev->mc.vram_start;
break;
case TTM_PL_TT:
- old_start += rdev->mc.gtt_location;
+ old_start += rdev->mc.gtt_start;
break;
default:
DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
@@ -273,10 +273,10 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
}
switch (new_mem->mem_type) {
case TTM_PL_VRAM:
- new_start += rdev->mc.vram_location;
+ new_start += rdev->mc.vram_start;
break;
case TTM_PL_TT:
- new_start += rdev->mc.gtt_location;
+ new_start += rdev->mc.gtt_start;
break;
default:
DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
diff --git a/drivers/gpu/drm/radeon/reg_srcs/r200 b/drivers/gpu/drm/radeon/reg_srcs/r200
index 6021c8849a16..c29ac434ac9c 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/r200
+++ b/drivers/gpu/drm/radeon/reg_srcs/r200
@@ -91,6 +91,8 @@ r200 0x3294
0x22b8 SE_TCL_TEX_CYL_WRAP_CTL
0x22c0 SE_TCL_UCP_VERT_BLEND_CNTL
0x22c4 SE_TCL_POINT_SPRITE_CNTL
+0x22d0 SE_PVS_CNTL
+0x22d4 SE_PVS_CONST_CNTL
0x2648 RE_POINTSIZE
0x26c0 RE_TOP_LEFT
0x26c4 RE_MISC
diff --git a/drivers/gpu/drm/radeon/reg_srcs/r600 b/drivers/gpu/drm/radeon/reg_srcs/r600
new file mode 100644
index 000000000000..8f414a5f520f
--- /dev/null
+++ b/drivers/gpu/drm/radeon/reg_srcs/r600
@@ -0,0 +1,837 @@
+r600 0x9400
+0x000287A0 R7xx_CB_SHADER_CONTROL
+0x00028230 R7xx_PA_SC_EDGERULE
+0x000286C8 R7xx_SPI_THREAD_GROUPING
+0x00008D8C R7xx_SQ_DYN_GPR_CNTL_PS_FLUSH_REQ
+0x000088C4 VGT_CACHE_INVALIDATION
+0x00028A50 VGT_ENHANCE
+0x000088CC VGT_ES_PER_GS
+0x00028A2C VGT_GROUP_DECR
+0x00028A28 VGT_GROUP_FIRST_DECR
+0x00028A24 VGT_GROUP_PRIM_TYPE
+0x00028A30 VGT_GROUP_VECT_0_CNTL
+0x00028A38 VGT_GROUP_VECT_0_FMT_CNTL
+0x00028A34 VGT_GROUP_VECT_1_CNTL
+0x00028A3C VGT_GROUP_VECT_1_FMT_CNTL
+0x00028A40 VGT_GS_MODE
+0x00028A6C VGT_GS_OUT_PRIM_TYPE
+0x000088C8 VGT_GS_PER_ES
+0x000088E8 VGT_GS_PER_VS
+0x000088D4 VGT_GS_VERTEX_REUSE
+0x00028A14 VGT_HOS_CNTL
+0x00028A18 VGT_HOS_MAX_TESS_LEVEL
+0x00028A1C VGT_HOS_MIN_TESS_LEVEL
+0x00028A20 VGT_HOS_REUSE_DEPTH
+0x0000895C VGT_INDEX_TYPE
+0x00028408 VGT_INDX_OFFSET
+0x00028AA0 VGT_INSTANCE_STEP_RATE_0
+0x00028AA4 VGT_INSTANCE_STEP_RATE_1
+0x000088C0 VGT_LAST_COPY_STATE
+0x00028400 VGT_MAX_VTX_INDX
+0x000088D8 VGT_MC_LAT_CNTL
+0x00028404 VGT_MIN_VTX_INDX
+0x00028A94 VGT_MULTI_PRIM_IB_RESET_EN
+0x0002840C VGT_MULTI_PRIM_IB_RESET_INDX
+0x00008970 VGT_NUM_INDICES
+0x00008974 VGT_NUM_INSTANCES
+0x00028A10 VGT_OUTPUT_PATH_CNTL
+0x00028C5C VGT_OUT_DEALLOC_CNTL
+0x00028A84 VGT_PRIMITIVEID_EN
+0x00008958 VGT_PRIMITIVE_TYPE
+0x00028AB4 VGT_REUSE_OFF
+0x00028C58 VGT_VERTEX_REUSE_BLOCK_CNTL
+0x00028AB8 VGT_VTX_CNT_EN
+0x000088B0 VGT_VTX_VECT_EJECT_REG
+0x00028810 PA_CL_CLIP_CNTL
+0x00008A14 PA_CL_ENHANCE
+0x00028C14 PA_CL_GB_HORZ_CLIP_ADJ
+0x00028C18 PA_CL_GB_HORZ_DISC_ADJ
+0x00028C0C PA_CL_GB_VERT_CLIP_ADJ
+0x00028C10 PA_CL_GB_VERT_DISC_ADJ
+0x00028820 PA_CL_NANINF_CNTL
+0x00028E1C PA_CL_POINT_CULL_RAD
+0x00028E18 PA_CL_POINT_SIZE
+0x00028E10 PA_CL_POINT_X_RAD
+0x00028E14 PA_CL_POINT_Y_RAD
+0x00028E2C PA_CL_UCP_0_W
+0x00028E3C PA_CL_UCP_1_W
+0x00028E4C PA_CL_UCP_2_W
+0x00028E5C PA_CL_UCP_3_W
+0x00028E6C PA_CL_UCP_4_W
+0x00028E7C PA_CL_UCP_5_W
+0x00028E20 PA_CL_UCP_0_X
+0x00028E30 PA_CL_UCP_1_X
+0x00028E40 PA_CL_UCP_2_X
+0x00028E50 PA_CL_UCP_3_X
+0x00028E60 PA_CL_UCP_4_X
+0x00028E70 PA_CL_UCP_5_X
+0x00028E24 PA_CL_UCP_0_Y
+0x00028E34 PA_CL_UCP_1_Y
+0x00028E44 PA_CL_UCP_2_Y
+0x00028E54 PA_CL_UCP_3_Y
+0x00028E64 PA_CL_UCP_4_Y
+0x00028E74 PA_CL_UCP_5_Y
+0x00028E28 PA_CL_UCP_0_Z
+0x00028E38 PA_CL_UCP_1_Z
+0x00028E48 PA_CL_UCP_2_Z
+0x00028E58 PA_CL_UCP_3_Z
+0x00028E68 PA_CL_UCP_4_Z
+0x00028E78 PA_CL_UCP_5_Z
+0x00028440 PA_CL_VPORT_XOFFSET_0
+0x00028458 PA_CL_VPORT_XOFFSET_1
+0x00028470 PA_CL_VPORT_XOFFSET_2
+0x00028488 PA_CL_VPORT_XOFFSET_3
+0x000284A0 PA_CL_VPORT_XOFFSET_4
+0x000284B8 PA_CL_VPORT_XOFFSET_5
+0x000284D0 PA_CL_VPORT_XOFFSET_6
+0x000284E8 PA_CL_VPORT_XOFFSET_7
+0x00028500 PA_CL_VPORT_XOFFSET_8
+0x00028518 PA_CL_VPORT_XOFFSET_9
+0x00028530 PA_CL_VPORT_XOFFSET_10
+0x00028548 PA_CL_VPORT_XOFFSET_11
+0x00028560 PA_CL_VPORT_XOFFSET_12
+0x00028578 PA_CL_VPORT_XOFFSET_13
+0x00028590 PA_CL_VPORT_XOFFSET_14
+0x000285A8 PA_CL_VPORT_XOFFSET_15
+0x0002843C PA_CL_VPORT_XSCALE_0
+0x00028454 PA_CL_VPORT_XSCALE_1
+0x0002846C PA_CL_VPORT_XSCALE_2
+0x00028484 PA_CL_VPORT_XSCALE_3
+0x0002849C PA_CL_VPORT_XSCALE_4
+0x000284B4 PA_CL_VPORT_XSCALE_5
+0x000284CC PA_CL_VPORT_XSCALE_6
+0x000284E4 PA_CL_VPORT_XSCALE_7
+0x000284FC PA_CL_VPORT_XSCALE_8
+0x00028514 PA_CL_VPORT_XSCALE_9
+0x0002852C PA_CL_VPORT_XSCALE_10
+0x00028544 PA_CL_VPORT_XSCALE_11
+0x0002855C PA_CL_VPORT_XSCALE_12
+0x00028574 PA_CL_VPORT_XSCALE_13
+0x0002858C PA_CL_VPORT_XSCALE_14
+0x000285A4 PA_CL_VPORT_XSCALE_15
+0x00028448 PA_CL_VPORT_YOFFSET_0
+0x00028460 PA_CL_VPORT_YOFFSET_1
+0x00028478 PA_CL_VPORT_YOFFSET_2
+0x00028490 PA_CL_VPORT_YOFFSET_3
+0x000284A8 PA_CL_VPORT_YOFFSET_4
+0x000284C0 PA_CL_VPORT_YOFFSET_5
+0x000284D8 PA_CL_VPORT_YOFFSET_6
+0x000284F0 PA_CL_VPORT_YOFFSET_7
+0x00028508 PA_CL_VPORT_YOFFSET_8
+0x00028520 PA_CL_VPORT_YOFFSET_9
+0x00028538 PA_CL_VPORT_YOFFSET_10
+0x00028550 PA_CL_VPORT_YOFFSET_11
+0x00028568 PA_CL_VPORT_YOFFSET_12
+0x00028580 PA_CL_VPORT_YOFFSET_13
+0x00028598 PA_CL_VPORT_YOFFSET_14
+0x000285B0 PA_CL_VPORT_YOFFSET_15
+0x00028444 PA_CL_VPORT_YSCALE_0
+0x0002845C PA_CL_VPORT_YSCALE_1
+0x00028474 PA_CL_VPORT_YSCALE_2
+0x0002848C PA_CL_VPORT_YSCALE_3
+0x000284A4 PA_CL_VPORT_YSCALE_4
+0x000284BC PA_CL_VPORT_YSCALE_5
+0x000284D4 PA_CL_VPORT_YSCALE_6
+0x000284EC PA_CL_VPORT_YSCALE_7
+0x00028504 PA_CL_VPORT_YSCALE_8
+0x0002851C PA_CL_VPORT_YSCALE_9
+0x00028534 PA_CL_VPORT_YSCALE_10
+0x0002854C PA_CL_VPORT_YSCALE_11
+0x00028564 PA_CL_VPORT_YSCALE_12
+0x0002857C PA_CL_VPORT_YSCALE_13
+0x00028594 PA_CL_VPORT_YSCALE_14
+0x000285AC PA_CL_VPORT_YSCALE_15
+0x00028450 PA_CL_VPORT_ZOFFSET_0
+0x00028468 PA_CL_VPORT_ZOFFSET_1
+0x00028480 PA_CL_VPORT_ZOFFSET_2
+0x00028498 PA_CL_VPORT_ZOFFSET_3
+0x000284B0 PA_CL_VPORT_ZOFFSET_4
+0x000284C8 PA_CL_VPORT_ZOFFSET_5
+0x000284E0 PA_CL_VPORT_ZOFFSET_6
+0x000284F8 PA_CL_VPORT_ZOFFSET_7
+0x00028510 PA_CL_VPORT_ZOFFSET_8
+0x00028528 PA_CL_VPORT_ZOFFSET_9
+0x00028540 PA_CL_VPORT_ZOFFSET_10
+0x00028558 PA_CL_VPORT_ZOFFSET_11
+0x00028570 PA_CL_VPORT_ZOFFSET_12
+0x00028588 PA_CL_VPORT_ZOFFSET_13
+0x000285A0 PA_CL_VPORT_ZOFFSET_14
+0x000285B8 PA_CL_VPORT_ZOFFSET_15
+0x0002844C PA_CL_VPORT_ZSCALE_0
+0x00028464 PA_CL_VPORT_ZSCALE_1
+0x0002847C PA_CL_VPORT_ZSCALE_2
+0x00028494 PA_CL_VPORT_ZSCALE_3
+0x000284AC PA_CL_VPORT_ZSCALE_4
+0x000284C4 PA_CL_VPORT_ZSCALE_5
+0x000284DC PA_CL_VPORT_ZSCALE_6
+0x000284F4 PA_CL_VPORT_ZSCALE_7
+0x0002850C PA_CL_VPORT_ZSCALE_8
+0x00028524 PA_CL_VPORT_ZSCALE_9
+0x0002853C PA_CL_VPORT_ZSCALE_10
+0x00028554 PA_CL_VPORT_ZSCALE_11
+0x0002856C PA_CL_VPORT_ZSCALE_12
+0x00028584 PA_CL_VPORT_ZSCALE_13
+0x0002859C PA_CL_VPORT_ZSCALE_14
+0x000285B4 PA_CL_VPORT_ZSCALE_15
+0x0002881C PA_CL_VS_OUT_CNTL
+0x00028818 PA_CL_VTE_CNTL
+0x00028C48 PA_SC_AA_MASK
+0x00008B40 PA_SC_AA_SAMPLE_LOCS_2S
+0x00008B44 PA_SC_AA_SAMPLE_LOCS_4S
+0x00008B48 PA_SC_AA_SAMPLE_LOCS_8S_WD0
+0x00008B4C PA_SC_AA_SAMPLE_LOCS_8S_WD1
+0x00028C20 PA_SC_AA_SAMPLE_LOCS_8S_WD1_MCTX
+0x00028C1C PA_SC_AA_SAMPLE_LOCS_MCTX
+0x00028214 PA_SC_CLIPRECT_0_BR
+0x0002821C PA_SC_CLIPRECT_1_BR
+0x00028224 PA_SC_CLIPRECT_2_BR
+0x0002822C PA_SC_CLIPRECT_3_BR
+0x00028210 PA_SC_CLIPRECT_0_TL
+0x00028218 PA_SC_CLIPRECT_1_TL
+0x00028220 PA_SC_CLIPRECT_2_TL
+0x00028228 PA_SC_CLIPRECT_3_TL
+0x0002820C PA_SC_CLIPRECT_RULE
+0x00008BF0 PA_SC_ENHANCE
+0x00028244 PA_SC_GENERIC_SCISSOR_BR
+0x00028240 PA_SC_GENERIC_SCISSOR_TL
+0x00028C00 PA_SC_LINE_CNTL
+0x00028A0C PA_SC_LINE_STIPPLE
+0x00008B10 PA_SC_LINE_STIPPLE_STATE
+0x00028A4C PA_SC_MODE_CNTL
+0x00028A48 PA_SC_MPASS_PS_CNTL
+0x00008B20 PA_SC_MULTI_CHIP_CNTL
+0x00028034 PA_SC_SCREEN_SCISSOR_BR
+0x00028030 PA_SC_SCREEN_SCISSOR_TL
+0x00028254 PA_SC_VPORT_SCISSOR_0_BR
+0x0002825C PA_SC_VPORT_SCISSOR_1_BR
+0x00028264 PA_SC_VPORT_SCISSOR_2_BR
+0x0002826C PA_SC_VPORT_SCISSOR_3_BR
+0x00028274 PA_SC_VPORT_SCISSOR_4_BR
+0x0002827C PA_SC_VPORT_SCISSOR_5_BR
+0x00028284 PA_SC_VPORT_SCISSOR_6_BR
+0x0002828C PA_SC_VPORT_SCISSOR_7_BR
+0x00028294 PA_SC_VPORT_SCISSOR_8_BR
+0x0002829C PA_SC_VPORT_SCISSOR_9_BR
+0x000282A4 PA_SC_VPORT_SCISSOR_10_BR
+0x000282AC PA_SC_VPORT_SCISSOR_11_BR
+0x000282B4 PA_SC_VPORT_SCISSOR_12_BR
+0x000282BC PA_SC_VPORT_SCISSOR_13_BR
+0x000282C4 PA_SC_VPORT_SCISSOR_14_BR
+0x000282CC PA_SC_VPORT_SCISSOR_15_BR
+0x00028250 PA_SC_VPORT_SCISSOR_0_TL
+0x00028258 PA_SC_VPORT_SCISSOR_1_TL
+0x00028260 PA_SC_VPORT_SCISSOR_2_TL
+0x00028268 PA_SC_VPORT_SCISSOR_3_TL
+0x00028270 PA_SC_VPORT_SCISSOR_4_TL
+0x00028278 PA_SC_VPORT_SCISSOR_5_TL
+0x00028280 PA_SC_VPORT_SCISSOR_6_TL
+0x00028288 PA_SC_VPORT_SCISSOR_7_TL
+0x00028290 PA_SC_VPORT_SCISSOR_8_TL
+0x00028298 PA_SC_VPORT_SCISSOR_9_TL
+0x000282A0 PA_SC_VPORT_SCISSOR_10_TL
+0x000282A8 PA_SC_VPORT_SCISSOR_11_TL
+0x000282B0 PA_SC_VPORT_SCISSOR_12_TL
+0x000282B8 PA_SC_VPORT_SCISSOR_13_TL
+0x000282C0 PA_SC_VPORT_SCISSOR_14_TL
+0x000282C8 PA_SC_VPORT_SCISSOR_15_TL
+0x000282D4 PA_SC_VPORT_ZMAX_0
+0x000282DC PA_SC_VPORT_ZMAX_1
+0x000282E4 PA_SC_VPORT_ZMAX_2
+0x000282EC PA_SC_VPORT_ZMAX_3
+0x000282F4 PA_SC_VPORT_ZMAX_4
+0x000282FC PA_SC_VPORT_ZMAX_5
+0x00028304 PA_SC_VPORT_ZMAX_6
+0x0002830C PA_SC_VPORT_ZMAX_7
+0x00028314 PA_SC_VPORT_ZMAX_8
+0x0002831C PA_SC_VPORT_ZMAX_9
+0x00028324 PA_SC_VPORT_ZMAX_10
+0x0002832C PA_SC_VPORT_ZMAX_11
+0x00028334 PA_SC_VPORT_ZMAX_12
+0x0002833C PA_SC_VPORT_ZMAX_13
+0x00028344 PA_SC_VPORT_ZMAX_14
+0x0002834C PA_SC_VPORT_ZMAX_15
+0x000282D0 PA_SC_VPORT_ZMIN_0
+0x000282D8 PA_SC_VPORT_ZMIN_1
+0x000282E0 PA_SC_VPORT_ZMIN_2
+0x000282E8 PA_SC_VPORT_ZMIN_3
+0x000282F0 PA_SC_VPORT_ZMIN_4
+0x000282F8 PA_SC_VPORT_ZMIN_5
+0x00028300 PA_SC_VPORT_ZMIN_6
+0x00028308 PA_SC_VPORT_ZMIN_7
+0x00028310 PA_SC_VPORT_ZMIN_8
+0x00028318 PA_SC_VPORT_ZMIN_9
+0x00028320 PA_SC_VPORT_ZMIN_10
+0x00028328 PA_SC_VPORT_ZMIN_11
+0x00028330 PA_SC_VPORT_ZMIN_12
+0x00028338 PA_SC_VPORT_ZMIN_13
+0x00028340 PA_SC_VPORT_ZMIN_14
+0x00028348 PA_SC_VPORT_ZMIN_15
+0x00028200 PA_SC_WINDOW_OFFSET
+0x00028208 PA_SC_WINDOW_SCISSOR_BR
+0x00028204 PA_SC_WINDOW_SCISSOR_TL
+0x00028A08 PA_SU_LINE_CNTL
+0x00028A04 PA_SU_POINT_MINMAX
+0x00028A00 PA_SU_POINT_SIZE
+0x00028E0C PA_SU_POLY_OFFSET_BACK_OFFSET
+0x00028E08 PA_SU_POLY_OFFSET_BACK_SCALE
+0x00028DFC PA_SU_POLY_OFFSET_CLAMP
+0x00028DF8 PA_SU_POLY_OFFSET_DB_FMT_CNTL
+0x00028E04 PA_SU_POLY_OFFSET_FRONT_OFFSET
+0x00028E00 PA_SU_POLY_OFFSET_FRONT_SCALE
+0x00028814 PA_SU_SC_MODE_CNTL
+0x00028C08 PA_SU_VTX_CNTL
+0x00008C00 SQ_CONFIG
+0x00008C04 SQ_GPR_RESOURCE_MGMT_1
+0x00008C08 SQ_GPR_RESOURCE_MGMT_2
+0x00008C10 SQ_STACK_RESOURCE_MGMT_1
+0x00008C14 SQ_STACK_RESOURCE_MGMT_2
+0x00008C0C SQ_THREAD_RESOURCE_MGMT
+0x00028380 SQ_VTX_SEMANTIC_0
+0x00028384 SQ_VTX_SEMANTIC_1
+0x00028388 SQ_VTX_SEMANTIC_2
+0x0002838C SQ_VTX_SEMANTIC_3
+0x00028390 SQ_VTX_SEMANTIC_4
+0x00028394 SQ_VTX_SEMANTIC_5
+0x00028398 SQ_VTX_SEMANTIC_6
+0x0002839C SQ_VTX_SEMANTIC_7
+0x000283A0 SQ_VTX_SEMANTIC_8
+0x000283A4 SQ_VTX_SEMANTIC_9
+0x000283A8 SQ_VTX_SEMANTIC_10
+0x000283AC SQ_VTX_SEMANTIC_11
+0x000283B0 SQ_VTX_SEMANTIC_12
+0x000283B4 SQ_VTX_SEMANTIC_13
+0x000283B8 SQ_VTX_SEMANTIC_14
+0x000283BC SQ_VTX_SEMANTIC_15
+0x000283C0 SQ_VTX_SEMANTIC_16
+0x000283C4 SQ_VTX_SEMANTIC_17
+0x000283C8 SQ_VTX_SEMANTIC_18
+0x000283CC SQ_VTX_SEMANTIC_19
+0x000283D0 SQ_VTX_SEMANTIC_20
+0x000283D4 SQ_VTX_SEMANTIC_21
+0x000283D8 SQ_VTX_SEMANTIC_22
+0x000283DC SQ_VTX_SEMANTIC_23
+0x000283E0 SQ_VTX_SEMANTIC_24
+0x000283E4 SQ_VTX_SEMANTIC_25
+0x000283E8 SQ_VTX_SEMANTIC_26
+0x000283EC SQ_VTX_SEMANTIC_27
+0x000283F0 SQ_VTX_SEMANTIC_28
+0x000283F4 SQ_VTX_SEMANTIC_29
+0x000283F8 SQ_VTX_SEMANTIC_30
+0x000283FC SQ_VTX_SEMANTIC_31
+0x000288E0 SQ_VTX_SEMANTIC_CLEAR
+0x0003CFF4 SQ_VTX_START_INST_LOC
+0x0003C000 SQ_TEX_SAMPLER_WORD0_0
+0x0003C004 SQ_TEX_SAMPLER_WORD1_0
+0x0003C008 SQ_TEX_SAMPLER_WORD2_0
+0x00030000 SQ_ALU_CONSTANT0_0
+0x00030004 SQ_ALU_CONSTANT1_0
+0x00030008 SQ_ALU_CONSTANT2_0
+0x0003000C SQ_ALU_CONSTANT3_0
+0x0003E380 SQ_BOOL_CONST_0
+0x0003E384 SQ_BOOL_CONST_1
+0x0003E388 SQ_BOOL_CONST_2
+0x0003E200 SQ_LOOP_CONST_0
+0x0003E200 SQ_LOOP_CONST_DX10_0
+0x000281C0 SQ_ALU_CONST_BUFFER_SIZE_GS_0
+0x000281C4 SQ_ALU_CONST_BUFFER_SIZE_GS_1
+0x000281C8 SQ_ALU_CONST_BUFFER_SIZE_GS_2
+0x000281CC SQ_ALU_CONST_BUFFER_SIZE_GS_3
+0x000281D0 SQ_ALU_CONST_BUFFER_SIZE_GS_4
+0x000281D4 SQ_ALU_CONST_BUFFER_SIZE_GS_5
+0x000281D8 SQ_ALU_CONST_BUFFER_SIZE_GS_6
+0x000281DC SQ_ALU_CONST_BUFFER_SIZE_GS_7
+0x000281E0 SQ_ALU_CONST_BUFFER_SIZE_GS_8
+0x000281E4 SQ_ALU_CONST_BUFFER_SIZE_GS_9
+0x000281E8 SQ_ALU_CONST_BUFFER_SIZE_GS_10
+0x000281EC SQ_ALU_CONST_BUFFER_SIZE_GS_11
+0x000281F0 SQ_ALU_CONST_BUFFER_SIZE_GS_12
+0x000281F4 SQ_ALU_CONST_BUFFER_SIZE_GS_13
+0x000281F8 SQ_ALU_CONST_BUFFER_SIZE_GS_14
+0x000281FC SQ_ALU_CONST_BUFFER_SIZE_GS_15
+0x00028140 SQ_ALU_CONST_BUFFER_SIZE_PS_0
+0x00028144 SQ_ALU_CONST_BUFFER_SIZE_PS_1
+0x00028148 SQ_ALU_CONST_BUFFER_SIZE_PS_2
+0x0002814C SQ_ALU_CONST_BUFFER_SIZE_PS_3
+0x00028150 SQ_ALU_CONST_BUFFER_SIZE_PS_4
+0x00028154 SQ_ALU_CONST_BUFFER_SIZE_PS_5
+0x00028158 SQ_ALU_CONST_BUFFER_SIZE_PS_6
+0x0002815C SQ_ALU_CONST_BUFFER_SIZE_PS_7
+0x00028160 SQ_ALU_CONST_BUFFER_SIZE_PS_8
+0x00028164 SQ_ALU_CONST_BUFFER_SIZE_PS_9
+0x00028168 SQ_ALU_CONST_BUFFER_SIZE_PS_10
+0x0002816C SQ_ALU_CONST_BUFFER_SIZE_PS_11
+0x00028170 SQ_ALU_CONST_BUFFER_SIZE_PS_12
+0x00028174 SQ_ALU_CONST_BUFFER_SIZE_PS_13
+0x00028178 SQ_ALU_CONST_BUFFER_SIZE_PS_14
+0x0002817C SQ_ALU_CONST_BUFFER_SIZE_PS_15
+0x00028180 SQ_ALU_CONST_BUFFER_SIZE_VS_0
+0x00028184 SQ_ALU_CONST_BUFFER_SIZE_VS_1
+0x00028188 SQ_ALU_CONST_BUFFER_SIZE_VS_2
+0x0002818C SQ_ALU_CONST_BUFFER_SIZE_VS_3
+0x00028190 SQ_ALU_CONST_BUFFER_SIZE_VS_4
+0x00028194 SQ_ALU_CONST_BUFFER_SIZE_VS_5
+0x00028198 SQ_ALU_CONST_BUFFER_SIZE_VS_6
+0x0002819C SQ_ALU_CONST_BUFFER_SIZE_VS_7
+0x000281A0 SQ_ALU_CONST_BUFFER_SIZE_VS_8
+0x000281A4 SQ_ALU_CONST_BUFFER_SIZE_VS_9
+0x000281A8 SQ_ALU_CONST_BUFFER_SIZE_VS_10
+0x000281AC SQ_ALU_CONST_BUFFER_SIZE_VS_11
+0x000281B0 SQ_ALU_CONST_BUFFER_SIZE_VS_12
+0x000281B4 SQ_ALU_CONST_BUFFER_SIZE_VS_13
+0x000281B8 SQ_ALU_CONST_BUFFER_SIZE_VS_14
+0x000281BC SQ_ALU_CONST_BUFFER_SIZE_VS_15
+0x000289C0 SQ_ALU_CONST_CACHE_GS_0
+0x000289C4 SQ_ALU_CONST_CACHE_GS_1
+0x000289C8 SQ_ALU_CONST_CACHE_GS_2
+0x000289CC SQ_ALU_CONST_CACHE_GS_3
+0x000289D0 SQ_ALU_CONST_CACHE_GS_4
+0x000289D4 SQ_ALU_CONST_CACHE_GS_5
+0x000289D8 SQ_ALU_CONST_CACHE_GS_6
+0x000289DC SQ_ALU_CONST_CACHE_GS_7
+0x000289E0 SQ_ALU_CONST_CACHE_GS_8
+0x000289E4 SQ_ALU_CONST_CACHE_GS_9
+0x000289E8 SQ_ALU_CONST_CACHE_GS_10
+0x000289EC SQ_ALU_CONST_CACHE_GS_11
+0x000289F0 SQ_ALU_CONST_CACHE_GS_12
+0x000289F4 SQ_ALU_CONST_CACHE_GS_13
+0x000289F8 SQ_ALU_CONST_CACHE_GS_14
+0x000289FC SQ_ALU_CONST_CACHE_GS_15
+0x00028940 SQ_ALU_CONST_CACHE_PS_0
+0x00028944 SQ_ALU_CONST_CACHE_PS_1
+0x00028948 SQ_ALU_CONST_CACHE_PS_2
+0x0002894C SQ_ALU_CONST_CACHE_PS_3
+0x00028950 SQ_ALU_CONST_CACHE_PS_4
+0x00028954 SQ_ALU_CONST_CACHE_PS_5
+0x00028958 SQ_ALU_CONST_CACHE_PS_6
+0x0002895C SQ_ALU_CONST_CACHE_PS_7
+0x00028960 SQ_ALU_CONST_CACHE_PS_8
+0x00028964 SQ_ALU_CONST_CACHE_PS_9
+0x00028968 SQ_ALU_CONST_CACHE_PS_10
+0x0002896C SQ_ALU_CONST_CACHE_PS_11
+0x00028970 SQ_ALU_CONST_CACHE_PS_12
+0x00028974 SQ_ALU_CONST_CACHE_PS_13
+0x00028978 SQ_ALU_CONST_CACHE_PS_14
+0x0002897C SQ_ALU_CONST_CACHE_PS_15
+0x00028980 SQ_ALU_CONST_CACHE_VS_0
+0x00028984 SQ_ALU_CONST_CACHE_VS_1
+0x00028988 SQ_ALU_CONST_CACHE_VS_2
+0x0002898C SQ_ALU_CONST_CACHE_VS_3
+0x00028990 SQ_ALU_CONST_CACHE_VS_4
+0x00028994 SQ_ALU_CONST_CACHE_VS_5
+0x00028998 SQ_ALU_CONST_CACHE_VS_6
+0x0002899C SQ_ALU_CONST_CACHE_VS_7
+0x000289A0 SQ_ALU_CONST_CACHE_VS_8
+0x000289A4 SQ_ALU_CONST_CACHE_VS_9
+0x000289A8 SQ_ALU_CONST_CACHE_VS_10
+0x000289AC SQ_ALU_CONST_CACHE_VS_11
+0x000289B0 SQ_ALU_CONST_CACHE_VS_12
+0x000289B4 SQ_ALU_CONST_CACHE_VS_13
+0x000289B8 SQ_ALU_CONST_CACHE_VS_14
+0x000289BC SQ_ALU_CONST_CACHE_VS_15
+0x000288D8 SQ_PGM_CF_OFFSET_ES
+0x000288DC SQ_PGM_CF_OFFSET_FS
+0x000288D4 SQ_PGM_CF_OFFSET_GS
+0x000288CC SQ_PGM_CF_OFFSET_PS
+0x000288D0 SQ_PGM_CF_OFFSET_VS
+0x00028854 SQ_PGM_EXPORTS_PS
+0x00028890 SQ_PGM_RESOURCES_ES
+0x000288A4 SQ_PGM_RESOURCES_FS
+0x0002887C SQ_PGM_RESOURCES_GS
+0x00028850 SQ_PGM_RESOURCES_PS
+0x00028868 SQ_PGM_RESOURCES_VS
+0x00009100 SPI_CONFIG_CNTL
+0x0000913C SPI_CONFIG_CNTL_1
+0x000286DC SPI_FOG_CNTL
+0x000286E4 SPI_FOG_FUNC_BIAS
+0x000286E0 SPI_FOG_FUNC_SCALE
+0x000286D8 SPI_INPUT_Z
+0x000286D4 SPI_INTERP_CONTROL_0
+0x00028644 SPI_PS_INPUT_CNTL_0
+0x00028648 SPI_PS_INPUT_CNTL_1
+0x0002864C SPI_PS_INPUT_CNTL_2
+0x00028650 SPI_PS_INPUT_CNTL_3
+0x00028654 SPI_PS_INPUT_CNTL_4
+0x00028658 SPI_PS_INPUT_CNTL_5
+0x0002865C SPI_PS_INPUT_CNTL_6
+0x00028660 SPI_PS_INPUT_CNTL_7
+0x00028664 SPI_PS_INPUT_CNTL_8
+0x00028668 SPI_PS_INPUT_CNTL_9
+0x0002866C SPI_PS_INPUT_CNTL_10
+0x00028670 SPI_PS_INPUT_CNTL_11
+0x00028674 SPI_PS_INPUT_CNTL_12
+0x00028678 SPI_PS_INPUT_CNTL_13
+0x0002867C SPI_PS_INPUT_CNTL_14
+0x00028680 SPI_PS_INPUT_CNTL_15
+0x00028684 SPI_PS_INPUT_CNTL_16
+0x00028688 SPI_PS_INPUT_CNTL_17
+0x0002868C SPI_PS_INPUT_CNTL_18
+0x00028690 SPI_PS_INPUT_CNTL_19
+0x00028694 SPI_PS_INPUT_CNTL_20
+0x00028698 SPI_PS_INPUT_CNTL_21
+0x0002869C SPI_PS_INPUT_CNTL_22
+0x000286A0 SPI_PS_INPUT_CNTL_23
+0x000286A4 SPI_PS_INPUT_CNTL_24
+0x000286A8 SPI_PS_INPUT_CNTL_25
+0x000286AC SPI_PS_INPUT_CNTL_26
+0x000286B0 SPI_PS_INPUT_CNTL_27
+0x000286B4 SPI_PS_INPUT_CNTL_28
+0x000286B8 SPI_PS_INPUT_CNTL_29
+0x000286BC SPI_PS_INPUT_CNTL_30
+0x000286C0 SPI_PS_INPUT_CNTL_31
+0x000286CC SPI_PS_IN_CONTROL_0
+0x000286D0 SPI_PS_IN_CONTROL_1
+0x000286C4 SPI_VS_OUT_CONFIG
+0x00028614 SPI_VS_OUT_ID_0
+0x00028618 SPI_VS_OUT_ID_1
+0x0002861C SPI_VS_OUT_ID_2
+0x00028620 SPI_VS_OUT_ID_3
+0x00028624 SPI_VS_OUT_ID_4
+0x00028628 SPI_VS_OUT_ID_5
+0x0002862C SPI_VS_OUT_ID_6
+0x00028630 SPI_VS_OUT_ID_7
+0x00028634 SPI_VS_OUT_ID_8
+0x00028638 SPI_VS_OUT_ID_9
+0x00028438 SX_ALPHA_REF
+0x00028410 SX_ALPHA_TEST_CONTROL
+0x00028350 SX_MISC
+0x0000A020 SMX_DC_CTL0
+0x0000A024 SMX_DC_CTL1
+0x0000A028 SMX_DC_CTL2
+0x00009608 TC_CNTL
+0x00009604 TC_INVALIDATE
+0x00009490 TD_CNTL
+0x00009400 TD_FILTER4
+0x00009404 TD_FILTER4_1
+0x00009408 TD_FILTER4_2
+0x0000940C TD_FILTER4_3
+0x00009410 TD_FILTER4_4
+0x00009414 TD_FILTER4_5
+0x00009418 TD_FILTER4_6
+0x0000941C TD_FILTER4_7
+0x00009420 TD_FILTER4_8
+0x00009424 TD_FILTER4_9
+0x00009428 TD_FILTER4_10
+0x0000942C TD_FILTER4_11
+0x00009430 TD_FILTER4_12
+0x00009434 TD_FILTER4_13
+0x00009438 TD_FILTER4_14
+0x0000943C TD_FILTER4_15
+0x00009440 TD_FILTER4_16
+0x00009444 TD_FILTER4_17
+0x00009448 TD_FILTER4_18
+0x0000944C TD_FILTER4_19
+0x00009450 TD_FILTER4_20
+0x00009454 TD_FILTER4_21
+0x00009458 TD_FILTER4_22
+0x0000945C TD_FILTER4_23
+0x00009460 TD_FILTER4_24
+0x00009464 TD_FILTER4_25
+0x00009468 TD_FILTER4_26
+0x0000946C TD_FILTER4_27
+0x00009470 TD_FILTER4_28
+0x00009474 TD_FILTER4_29
+0x00009478 TD_FILTER4_30
+0x0000947C TD_FILTER4_31
+0x00009480 TD_FILTER4_32
+0x00009484 TD_FILTER4_33
+0x00009488 TD_FILTER4_34
+0x0000948C TD_FILTER4_35
+0x0000A80C TD_GS_SAMPLER0_BORDER_ALPHA
+0x0000A81C TD_GS_SAMPLER1_BORDER_ALPHA
+0x0000A82C TD_GS_SAMPLER2_BORDER_ALPHA
+0x0000A83C TD_GS_SAMPLER3_BORDER_ALPHA
+0x0000A84C TD_GS_SAMPLER4_BORDER_ALPHA
+0x0000A85C TD_GS_SAMPLER5_BORDER_ALPHA
+0x0000A86C TD_GS_SAMPLER6_BORDER_ALPHA
+0x0000A87C TD_GS_SAMPLER7_BORDER_ALPHA
+0x0000A88C TD_GS_SAMPLER8_BORDER_ALPHA
+0x0000A89C TD_GS_SAMPLER9_BORDER_ALPHA
+0x0000A8AC TD_GS_SAMPLER10_BORDER_ALPHA
+0x0000A8BC TD_GS_SAMPLER11_BORDER_ALPHA
+0x0000A8CC TD_GS_SAMPLER12_BORDER_ALPHA
+0x0000A8DC TD_GS_SAMPLER13_BORDER_ALPHA
+0x0000A8EC TD_GS_SAMPLER14_BORDER_ALPHA
+0x0000A8FC TD_GS_SAMPLER15_BORDER_ALPHA
+0x0000A90C TD_GS_SAMPLER16_BORDER_ALPHA
+0x0000A91C TD_GS_SAMPLER17_BORDER_ALPHA
+0x0000A808 TD_GS_SAMPLER0_BORDER_BLUE
+0x0000A818 TD_GS_SAMPLER1_BORDER_BLUE
+0x0000A828 TD_GS_SAMPLER2_BORDER_BLUE
+0x0000A838 TD_GS_SAMPLER3_BORDER_BLUE
+0x0000A848 TD_GS_SAMPLER4_BORDER_BLUE
+0x0000A858 TD_GS_SAMPLER5_BORDER_BLUE
+0x0000A868 TD_GS_SAMPLER6_BORDER_BLUE
+0x0000A878 TD_GS_SAMPLER7_BORDER_BLUE
+0x0000A888 TD_GS_SAMPLER8_BORDER_BLUE
+0x0000A898 TD_GS_SAMPLER9_BORDER_BLUE
+0x0000A8A8 TD_GS_SAMPLER10_BORDER_BLUE
+0x0000A8B8 TD_GS_SAMPLER11_BORDER_BLUE
+0x0000A8C8 TD_GS_SAMPLER12_BORDER_BLUE
+0x0000A8D8 TD_GS_SAMPLER13_BORDER_BLUE
+0x0000A8E8 TD_GS_SAMPLER14_BORDER_BLUE
+0x0000A8F8 TD_GS_SAMPLER15_BORDER_BLUE
+0x0000A908 TD_GS_SAMPLER16_BORDER_BLUE
+0x0000A918 TD_GS_SAMPLER17_BORDER_BLUE
+0x0000A804 TD_GS_SAMPLER0_BORDER_GREEN
+0x0000A814 TD_GS_SAMPLER1_BORDER_GREEN
+0x0000A824 TD_GS_SAMPLER2_BORDER_GREEN
+0x0000A834 TD_GS_SAMPLER3_BORDER_GREEN
+0x0000A844 TD_GS_SAMPLER4_BORDER_GREEN
+0x0000A854 TD_GS_SAMPLER5_BORDER_GREEN
+0x0000A864 TD_GS_SAMPLER6_BORDER_GREEN
+0x0000A874 TD_GS_SAMPLER7_BORDER_GREEN
+0x0000A884 TD_GS_SAMPLER8_BORDER_GREEN
+0x0000A894 TD_GS_SAMPLER9_BORDER_GREEN
+0x0000A8A4 TD_GS_SAMPLER10_BORDER_GREEN
+0x0000A8B4 TD_GS_SAMPLER11_BORDER_GREEN
+0x0000A8C4 TD_GS_SAMPLER12_BORDER_GREEN
+0x0000A8D4 TD_GS_SAMPLER13_BORDER_GREEN
+0x0000A8E4 TD_GS_SAMPLER14_BORDER_GREEN
+0x0000A8F4 TD_GS_SAMPLER15_BORDER_GREEN
+0x0000A904 TD_GS_SAMPLER16_BORDER_GREEN
+0x0000A914 TD_GS_SAMPLER17_BORDER_GREEN
+0x0000A800 TD_GS_SAMPLER0_BORDER_RED
+0x0000A810 TD_GS_SAMPLER1_BORDER_RED
+0x0000A820 TD_GS_SAMPLER2_BORDER_RED
+0x0000A830 TD_GS_SAMPLER3_BORDER_RED
+0x0000A840 TD_GS_SAMPLER4_BORDER_RED
+0x0000A850 TD_GS_SAMPLER5_BORDER_RED
+0x0000A860 TD_GS_SAMPLER6_BORDER_RED
+0x0000A870 TD_GS_SAMPLER7_BORDER_RED
+0x0000A880 TD_GS_SAMPLER8_BORDER_RED
+0x0000A890 TD_GS_SAMPLER9_BORDER_RED
+0x0000A8A0 TD_GS_SAMPLER10_BORDER_RED
+0x0000A8B0 TD_GS_SAMPLER11_BORDER_RED
+0x0000A8C0 TD_GS_SAMPLER12_BORDER_RED
+0x0000A8D0 TD_GS_SAMPLER13_BORDER_RED
+0x0000A8E0 TD_GS_SAMPLER14_BORDER_RED
+0x0000A8F0 TD_GS_SAMPLER15_BORDER_RED
+0x0000A900 TD_GS_SAMPLER16_BORDER_RED
+0x0000A910 TD_GS_SAMPLER17_BORDER_RED
+0x0000A40C TD_PS_SAMPLER0_BORDER_ALPHA
+0x0000A41C TD_PS_SAMPLER1_BORDER_ALPHA
+0x0000A42C TD_PS_SAMPLER2_BORDER_ALPHA
+0x0000A43C TD_PS_SAMPLER3_BORDER_ALPHA
+0x0000A44C TD_PS_SAMPLER4_BORDER_ALPHA
+0x0000A45C TD_PS_SAMPLER5_BORDER_ALPHA
+0x0000A46C TD_PS_SAMPLER6_BORDER_ALPHA
+0x0000A47C TD_PS_SAMPLER7_BORDER_ALPHA
+0x0000A48C TD_PS_SAMPLER8_BORDER_ALPHA
+0x0000A49C TD_PS_SAMPLER9_BORDER_ALPHA
+0x0000A4AC TD_PS_SAMPLER10_BORDER_ALPHA
+0x0000A4BC TD_PS_SAMPLER11_BORDER_ALPHA
+0x0000A4CC TD_PS_SAMPLER12_BORDER_ALPHA
+0x0000A4DC TD_PS_SAMPLER13_BORDER_ALPHA
+0x0000A4EC TD_PS_SAMPLER14_BORDER_ALPHA
+0x0000A4FC TD_PS_SAMPLER15_BORDER_ALPHA
+0x0000A50C TD_PS_SAMPLER16_BORDER_ALPHA
+0x0000A51C TD_PS_SAMPLER17_BORDER_ALPHA
+0x0000A408 TD_PS_SAMPLER0_BORDER_BLUE
+0x0000A418 TD_PS_SAMPLER1_BORDER_BLUE
+0x0000A428 TD_PS_SAMPLER2_BORDER_BLUE
+0x0000A438 TD_PS_SAMPLER3_BORDER_BLUE
+0x0000A448 TD_PS_SAMPLER4_BORDER_BLUE
+0x0000A458 TD_PS_SAMPLER5_BORDER_BLUE
+0x0000A468 TD_PS_SAMPLER6_BORDER_BLUE
+0x0000A478 TD_PS_SAMPLER7_BORDER_BLUE
+0x0000A488 TD_PS_SAMPLER8_BORDER_BLUE
+0x0000A498 TD_PS_SAMPLER9_BORDER_BLUE
+0x0000A4A8 TD_PS_SAMPLER10_BORDER_BLUE
+0x0000A4B8 TD_PS_SAMPLER11_BORDER_BLUE
+0x0000A4C8 TD_PS_SAMPLER12_BORDER_BLUE
+0x0000A4D8 TD_PS_SAMPLER13_BORDER_BLUE
+0x0000A4E8 TD_PS_SAMPLER14_BORDER_BLUE
+0x0000A4F8 TD_PS_SAMPLER15_BORDER_BLUE
+0x0000A508 TD_PS_SAMPLER16_BORDER_BLUE
+0x0000A518 TD_PS_SAMPLER17_BORDER_BLUE
+0x0000A404 TD_PS_SAMPLER0_BORDER_GREEN
+0x0000A414 TD_PS_SAMPLER1_BORDER_GREEN
+0x0000A424 TD_PS_SAMPLER2_BORDER_GREEN
+0x0000A434 TD_PS_SAMPLER3_BORDER_GREEN
+0x0000A444 TD_PS_SAMPLER4_BORDER_GREEN
+0x0000A454 TD_PS_SAMPLER5_BORDER_GREEN
+0x0000A464 TD_PS_SAMPLER6_BORDER_GREEN
+0x0000A474 TD_PS_SAMPLER7_BORDER_GREEN
+0x0000A484 TD_PS_SAMPLER8_BORDER_GREEN
+0x0000A494 TD_PS_SAMPLER9_BORDER_GREEN
+0x0000A4A4 TD_PS_SAMPLER10_BORDER_GREEN
+0x0000A4B4 TD_PS_SAMPLER11_BORDER_GREEN
+0x0000A4C4 TD_PS_SAMPLER12_BORDER_GREEN
+0x0000A4D4 TD_PS_SAMPLER13_BORDER_GREEN
+0x0000A4E4 TD_PS_SAMPLER14_BORDER_GREEN
+0x0000A4F4 TD_PS_SAMPLER15_BORDER_GREEN
+0x0000A504 TD_PS_SAMPLER16_BORDER_GREEN
+0x0000A514 TD_PS_SAMPLER17_BORDER_GREEN
+0x0000A400 TD_PS_SAMPLER0_BORDER_RED
+0x0000A410 TD_PS_SAMPLER1_BORDER_RED
+0x0000A420 TD_PS_SAMPLER2_BORDER_RED
+0x0000A430 TD_PS_SAMPLER3_BORDER_RED
+0x0000A440 TD_PS_SAMPLER4_BORDER_RED
+0x0000A450 TD_PS_SAMPLER5_BORDER_RED
+0x0000A460 TD_PS_SAMPLER6_BORDER_RED
+0x0000A470 TD_PS_SAMPLER7_BORDER_RED
+0x0000A480 TD_PS_SAMPLER8_BORDER_RED
+0x0000A490 TD_PS_SAMPLER9_BORDER_RED
+0x0000A4A0 TD_PS_SAMPLER10_BORDER_RED
+0x0000A4B0 TD_PS_SAMPLER11_BORDER_RED
+0x0000A4C0 TD_PS_SAMPLER12_BORDER_RED
+0x0000A4D0 TD_PS_SAMPLER13_BORDER_RED
+0x0000A4E0 TD_PS_SAMPLER14_BORDER_RED
+0x0000A4F0 TD_PS_SAMPLER15_BORDER_RED
+0x0000A500 TD_PS_SAMPLER16_BORDER_RED
+0x0000A510 TD_PS_SAMPLER17_BORDER_RED
+0x0000AA00 TD_PS_SAMPLER0_CLEARTYPE_KERNEL
+0x0000AA04 TD_PS_SAMPLER1_CLEARTYPE_KERNEL
+0x0000AA08 TD_PS_SAMPLER2_CLEARTYPE_KERNEL
+0x0000AA0C TD_PS_SAMPLER3_CLEARTYPE_KERNEL
+0x0000AA10 TD_PS_SAMPLER4_CLEARTYPE_KERNEL
+0x0000AA14 TD_PS_SAMPLER5_CLEARTYPE_KERNEL
+0x0000AA18 TD_PS_SAMPLER6_CLEARTYPE_KERNEL
+0x0000AA1C TD_PS_SAMPLER7_CLEARTYPE_KERNEL
+0x0000AA20 TD_PS_SAMPLER8_CLEARTYPE_KERNEL
+0x0000AA24 TD_PS_SAMPLER9_CLEARTYPE_KERNEL
+0x0000AA28 TD_PS_SAMPLER10_CLEARTYPE_KERNEL
+0x0000AA2C TD_PS_SAMPLER11_CLEARTYPE_KERNEL
+0x0000AA30 TD_PS_SAMPLER12_CLEARTYPE_KERNEL
+0x0000AA34 TD_PS_SAMPLER13_CLEARTYPE_KERNEL
+0x0000AA38 TD_PS_SAMPLER14_CLEARTYPE_KERNEL
+0x0000AA3C TD_PS_SAMPLER15_CLEARTYPE_KERNEL
+0x0000AA40 TD_PS_SAMPLER16_CLEARTYPE_KERNEL
+0x0000AA44 TD_PS_SAMPLER17_CLEARTYPE_KERNEL
+0x0000A60C TD_VS_SAMPLER0_BORDER_ALPHA
+0x0000A61C TD_VS_SAMPLER1_BORDER_ALPHA
+0x0000A62C TD_VS_SAMPLER2_BORDER_ALPHA
+0x0000A63C TD_VS_SAMPLER3_BORDER_ALPHA
+0x0000A64C TD_VS_SAMPLER4_BORDER_ALPHA
+0x0000A65C TD_VS_SAMPLER5_BORDER_ALPHA
+0x0000A66C TD_VS_SAMPLER6_BORDER_ALPHA
+0x0000A67C TD_VS_SAMPLER7_BORDER_ALPHA
+0x0000A68C TD_VS_SAMPLER8_BORDER_ALPHA
+0x0000A69C TD_VS_SAMPLER9_BORDER_ALPHA
+0x0000A6AC TD_VS_SAMPLER10_BORDER_ALPHA
+0x0000A6BC TD_VS_SAMPLER11_BORDER_ALPHA
+0x0000A6CC TD_VS_SAMPLER12_BORDER_ALPHA
+0x0000A6DC TD_VS_SAMPLER13_BORDER_ALPHA
+0x0000A6EC TD_VS_SAMPLER14_BORDER_ALPHA
+0x0000A6FC TD_VS_SAMPLER15_BORDER_ALPHA
+0x0000A70C TD_VS_SAMPLER16_BORDER_ALPHA
+0x0000A71C TD_VS_SAMPLER17_BORDER_ALPHA
+0x0000A608 TD_VS_SAMPLER0_BORDER_BLUE
+0x0000A618 TD_VS_SAMPLER1_BORDER_BLUE
+0x0000A628 TD_VS_SAMPLER2_BORDER_BLUE
+0x0000A638 TD_VS_SAMPLER3_BORDER_BLUE
+0x0000A648 TD_VS_SAMPLER4_BORDER_BLUE
+0x0000A658 TD_VS_SAMPLER5_BORDER_BLUE
+0x0000A668 TD_VS_SAMPLER6_BORDER_BLUE
+0x0000A678 TD_VS_SAMPLER7_BORDER_BLUE
+0x0000A688 TD_VS_SAMPLER8_BORDER_BLUE
+0x0000A698 TD_VS_SAMPLER9_BORDER_BLUE
+0x0000A6A8 TD_VS_SAMPLER10_BORDER_BLUE
+0x0000A6B8 TD_VS_SAMPLER11_BORDER_BLUE
+0x0000A6C8 TD_VS_SAMPLER12_BORDER_BLUE
+0x0000A6D8 TD_VS_SAMPLER13_BORDER_BLUE
+0x0000A6E8 TD_VS_SAMPLER14_BORDER_BLUE
+0x0000A6F8 TD_VS_SAMPLER15_BORDER_BLUE
+0x0000A708 TD_VS_SAMPLER16_BORDER_BLUE
+0x0000A718 TD_VS_SAMPLER17_BORDER_BLUE
+0x0000A604 TD_VS_SAMPLER0_BORDER_GREEN
+0x0000A614 TD_VS_SAMPLER1_BORDER_GREEN
+0x0000A624 TD_VS_SAMPLER2_BORDER_GREEN
+0x0000A634 TD_VS_SAMPLER3_BORDER_GREEN
+0x0000A644 TD_VS_SAMPLER4_BORDER_GREEN
+0x0000A654 TD_VS_SAMPLER5_BORDER_GREEN
+0x0000A664 TD_VS_SAMPLER6_BORDER_GREEN
+0x0000A674 TD_VS_SAMPLER7_BORDER_GREEN
+0x0000A684 TD_VS_SAMPLER8_BORDER_GREEN
+0x0000A694 TD_VS_SAMPLER9_BORDER_GREEN
+0x0000A6A4 TD_VS_SAMPLER10_BORDER_GREEN
+0x0000A6B4 TD_VS_SAMPLER11_BORDER_GREEN
+0x0000A6C4 TD_VS_SAMPLER12_BORDER_GREEN
+0x0000A6D4 TD_VS_SAMPLER13_BORDER_GREEN
+0x0000A6E4 TD_VS_SAMPLER14_BORDER_GREEN
+0x0000A6F4 TD_VS_SAMPLER15_BORDER_GREEN
+0x0000A704 TD_VS_SAMPLER16_BORDER_GREEN
+0x0000A714 TD_VS_SAMPLER17_BORDER_GREEN
+0x0000A600 TD_VS_SAMPLER0_BORDER_RED
+0x0000A610 TD_VS_SAMPLER1_BORDER_RED
+0x0000A620 TD_VS_SAMPLER2_BORDER_RED
+0x0000A630 TD_VS_SAMPLER3_BORDER_RED
+0x0000A640 TD_VS_SAMPLER4_BORDER_RED
+0x0000A650 TD_VS_SAMPLER5_BORDER_RED
+0x0000A660 TD_VS_SAMPLER6_BORDER_RED
+0x0000A670 TD_VS_SAMPLER7_BORDER_RED
+0x0000A680 TD_VS_SAMPLER8_BORDER_RED
+0x0000A690 TD_VS_SAMPLER9_BORDER_RED
+0x0000A6A0 TD_VS_SAMPLER10_BORDER_RED
+0x0000A6B0 TD_VS_SAMPLER11_BORDER_RED
+0x0000A6C0 TD_VS_SAMPLER12_BORDER_RED
+0x0000A6D0 TD_VS_SAMPLER13_BORDER_RED
+0x0000A6E0 TD_VS_SAMPLER14_BORDER_RED
+0x0000A6F0 TD_VS_SAMPLER15_BORDER_RED
+0x0000A700 TD_VS_SAMPLER16_BORDER_RED
+0x0000A710 TD_VS_SAMPLER17_BORDER_RED
+0x00009508 TA_CNTL_AUX
+0x0002802C DB_DEPTH_CLEAR
+0x00028D24 DB_HTILE_SURFACE
+0x00028D34 DB_PREFETCH_LIMIT
+0x00028D30 DB_PRELOAD_CONTROL
+0x00028D0C DB_RENDER_CONTROL
+0x00028D10 DB_RENDER_OVERRIDE
+0x0002880C DB_SHADER_CONTROL
+0x00028D2C DB_SRESULTS_COMPARE_STATE1
+0x00028430 DB_STENCILREFMASK
+0x00028434 DB_STENCILREFMASK_BF
+0x00028028 DB_STENCIL_CLEAR
+0x00028780 CB_BLEND0_CONTROL
+0x00028784 CB_BLEND1_CONTROL
+0x00028788 CB_BLEND2_CONTROL
+0x0002878C CB_BLEND3_CONTROL
+0x00028790 CB_BLEND4_CONTROL
+0x00028794 CB_BLEND5_CONTROL
+0x00028798 CB_BLEND6_CONTROL
+0x0002879C CB_BLEND7_CONTROL
+0x00028804 CB_BLEND_CONTROL
+0x00028420 CB_BLEND_ALPHA
+0x0002841C CB_BLEND_BLUE
+0x00028418 CB_BLEND_GREEN
+0x00028414 CB_BLEND_RED
+0x0002812C CB_CLEAR_ALPHA
+0x00028128 CB_CLEAR_BLUE
+0x00028124 CB_CLEAR_GREEN
+0x00028120 CB_CLEAR_RED
+0x00028C30 CB_CLRCMP_CONTROL
+0x00028C38 CB_CLRCMP_DST
+0x00028C3C CB_CLRCMP_MSK
+0x00028C34 CB_CLRCMP_SRC
+0x00028100 CB_COLOR0_MASK
+0x00028104 CB_COLOR1_MASK
+0x00028108 CB_COLOR2_MASK
+0x0002810C CB_COLOR3_MASK
+0x00028110 CB_COLOR4_MASK
+0x00028114 CB_COLOR5_MASK
+0x00028118 CB_COLOR6_MASK
+0x0002811C CB_COLOR7_MASK
+0x00028080 CB_COLOR0_VIEW
+0x00028084 CB_COLOR1_VIEW
+0x00028088 CB_COLOR2_VIEW
+0x0002808C CB_COLOR3_VIEW
+0x00028090 CB_COLOR4_VIEW
+0x00028094 CB_COLOR5_VIEW
+0x00028098 CB_COLOR6_VIEW
+0x0002809C CB_COLOR7_VIEW
+0x00028808 CB_COLOR_CONTROL
+0x0002842C CB_FOG_BLUE
+0x00028428 CB_FOG_GREEN
+0x00028424 CB_FOG_RED
+0x00008040 WAIT_UNTIL
+0x00008950 CC_GC_SHADER_PIPE_CONFIG
+0x00008954 GC_USER_SHADER_PIPE_CONFIG
+0x00009714 VC_ENHANCE
+0x00009830 DB_DEBUG
+0x00009838 DB_WATERMARKS
+0x00028D28 DB_SRESULTS_COMPARE_STATE0
+0x00028D44 DB_ALPHA_TO_MASK
+0x00009504 TA_CNTL
+0x00009700 VC_CNTL
+0x00009718 VC_CONFIG
+0x0000A02C SMX_DC_MC_INTF_CTL
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index 9f5418983e2a..626d51891ee9 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -113,6 +113,7 @@ int rs400_gart_enable(struct radeon_device *rdev)
uint32_t size_reg;
uint32_t tmp;
+ radeon_gart_restore(rdev);
tmp = RREG32_MC(RS690_AIC_CTRL_SCRATCH);
tmp |= RS690_DIS_OUT_OF_PCI_GART_ACCESS;
WREG32_MC(RS690_AIC_CTRL_SCRATCH, tmp);
@@ -150,9 +151,8 @@ int rs400_gart_enable(struct radeon_device *rdev)
WREG32(RADEON_AGP_BASE, 0xFFFFFFFF);
WREG32(RS480_AGP_BASE_2, 0);
}
- tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
- tmp = REG_SET(RS690_MC_AGP_TOP, tmp >> 16);
- tmp |= REG_SET(RS690_MC_AGP_START, rdev->mc.gtt_location >> 16);
+ tmp = REG_SET(RS690_MC_AGP_TOP, rdev->mc.gtt_end >> 16);
+ tmp |= REG_SET(RS690_MC_AGP_START, rdev->mc.gtt_start >> 16);
if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) {
WREG32_MC(RS690_MCCFG_AGP_LOCATION, tmp);
tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
@@ -223,26 +223,47 @@ int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
return 0;
}
+int rs400_mc_wait_for_idle(struct radeon_device *rdev)
+{
+ unsigned i;
+ uint32_t tmp;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ /* read MC_STATUS */
+ tmp = RREG32(0x0150);
+ if (tmp & (1 << 2)) {
+ return 0;
+ }
+ DRM_UDELAY(1);
+ }
+ return -1;
+}
+
void rs400_gpu_init(struct radeon_device *rdev)
{
/* FIXME: HDP same place on rs400 ? */
r100_hdp_reset(rdev);
/* FIXME: is this correct ? */
r420_pipes_init(rdev);
- if (r300_mc_wait_for_idle(rdev)) {
- printk(KERN_WARNING "Failed to wait MC idle while "
- "programming pipes. Bad things might happen.\n");
+ if (rs400_mc_wait_for_idle(rdev)) {
+ printk(KERN_WARNING "rs400: Failed to wait MC idle while "
+ "programming pipes. Bad things might happen. %08x\n", RREG32(0x150));
}
}
-void rs400_vram_info(struct radeon_device *rdev)
+void rs400_mc_init(struct radeon_device *rdev)
{
+ u64 base;
+
rs400_gart_adjust_size(rdev);
+ rdev->mc.igp_sideport_enabled = radeon_combios_sideport_present(rdev);
/* DDR for all card after R300 & IGP */
rdev->mc.vram_is_ddr = true;
rdev->mc.vram_width = 128;
-
r100_vram_init_sizes(rdev);
+ base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16;
+ radeon_vram_location(rdev, &rdev->mc, base);
+ radeon_gtt_location(rdev, &rdev->mc);
}
uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg)
@@ -346,22 +367,6 @@ static int rs400_debugfs_pcie_gart_info_init(struct radeon_device *rdev)
#endif
}
-static int rs400_mc_init(struct radeon_device *rdev)
-{
- int r;
- u32 tmp;
-
- /* Setup GPU memory space */
- tmp = RREG32(R_00015C_NB_TOM);
- rdev->mc.vram_location = G_00015C_MC_FB_START(tmp) << 16;
- rdev->mc.gtt_location = 0xFFFFFFFFUL;
- r = radeon_mc_setup(rdev);
- rdev->mc.igp_sideport_enabled = radeon_combios_sideport_present(rdev);
- if (r)
- return r;
- return 0;
-}
-
void rs400_mc_program(struct radeon_device *rdev)
{
struct r100_mc_save save;
@@ -370,8 +375,8 @@ void rs400_mc_program(struct radeon_device *rdev)
r100_mc_stop(rdev, &save);
/* Wait for mc idle */
- if (r300_mc_wait_for_idle(rdev))
- dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n");
+ if (rs400_mc_wait_for_idle(rdev))
+ dev_warn(rdev->dev, "rs400: Wait MC idle timeout before updating MC.\n");
WREG32(R_000148_MC_FB_LOCATION,
S_000148_MC_FB_START(rdev->mc.vram_start >> 16) |
S_000148_MC_FB_TOP(rdev->mc.vram_end >> 16));
@@ -448,7 +453,6 @@ int rs400_suspend(struct radeon_device *rdev)
void rs400_fini(struct radeon_device *rdev)
{
- rs400_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -501,12 +505,8 @@ int rs400_init(struct radeon_device *rdev)
radeon_get_clock_info(rdev->ddev);
/* Initialize power management */
radeon_pm_init(rdev);
- /* Get vram informations */
- rs400_vram_info(rdev);
- /* Initialize memory controller (also test AGP) */
- r = rs400_mc_init(rdev);
- if (r)
- return r;
+ /* initialize memory controller */
+ rs400_mc_init(rdev);
/* Fence driver */
r = radeon_fence_driver_init(rdev);
if (r)
@@ -527,7 +527,6 @@ int rs400_init(struct radeon_device *rdev)
if (r) {
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
- rs400_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index d5255751e7b3..47f046b78c6b 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -45,23 +45,6 @@
void rs600_gpu_init(struct radeon_device *rdev);
int rs600_mc_wait_for_idle(struct radeon_device *rdev);
-int rs600_mc_init(struct radeon_device *rdev)
-{
- /* read back the MC value from the hw */
- int r;
- u32 tmp;
-
- /* Setup GPU memory space */
- tmp = RREG32_MC(R_000004_MC_FB_LOCATION);
- rdev->mc.vram_location = G_000004_MC_FB_START(tmp) << 16;
- rdev->mc.gtt_location = 0xffffffffUL;
- r = radeon_mc_setup(rdev);
- rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
- if (r)
- return r;
- return 0;
-}
-
/* hpd for digital panel detect/disconnect */
bool rs600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
{
@@ -213,6 +196,7 @@ int rs600_gart_enable(struct radeon_device *rdev)
r = radeon_gart_table_vram_pin(rdev);
if (r)
return r;
+ radeon_gart_restore(rdev);
/* Enable bus master */
tmp = RREG32(R_00004C_BUS_CNTL) & C_00004C_BUS_MASTER_DIS;
WREG32(R_00004C_BUS_CNTL, tmp);
@@ -406,10 +390,14 @@ int rs600_irq_process(struct radeon_device *rdev)
if (G_000044_SW_INT(status))
radeon_fence_process(rdev);
/* Vertical blank interrupts */
- if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int))
+ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) {
drm_handle_vblank(rdev->ddev, 0);
- if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int))
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int)) {
drm_handle_vblank(rdev->ddev, 1);
+ wake_up(&rdev->irq.vblank_queue);
+ }
if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) {
queue_hotplug = true;
DRM_DEBUG("HPD1\n");
@@ -470,22 +458,22 @@ void rs600_gpu_init(struct radeon_device *rdev)
dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n");
}
-void rs600_vram_info(struct radeon_device *rdev)
+void rs600_mc_init(struct radeon_device *rdev)
{
+ u64 base;
+
+ rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+ rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
rdev->mc.vram_is_ddr = true;
rdev->mc.vram_width = 128;
-
rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
-
- rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
- rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
-
- if (rdev->mc.mc_vram_size > rdev->mc.aper_size)
- rdev->mc.mc_vram_size = rdev->mc.aper_size;
-
- if (rdev->mc.real_vram_size > rdev->mc.aper_size)
- rdev->mc.real_vram_size = rdev->mc.aper_size;
+ rdev->mc.visible_vram_size = rdev->mc.aper_size;
+ rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
+ base = RREG32_MC(R_000004_MC_FB_LOCATION);
+ base = G_000004_MC_FB_START(base) << 16;
+ radeon_vram_location(rdev, &rdev->mc, base);
+ radeon_gtt_location(rdev, &rdev->mc);
}
void rs600_bandwidth_update(struct radeon_device *rdev)
@@ -610,7 +598,6 @@ int rs600_suspend(struct radeon_device *rdev)
void rs600_fini(struct radeon_device *rdev)
{
- rs600_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -662,12 +649,8 @@ int rs600_init(struct radeon_device *rdev)
radeon_get_clock_info(rdev->ddev);
/* Initialize power management */
radeon_pm_init(rdev);
- /* Get vram informations */
- rs600_vram_info(rdev);
- /* Initialize memory controller (also test AGP) */
- r = rs600_mc_init(rdev);
- if (r)
- return r;
+ /* initialize memory controller */
+ rs600_mc_init(rdev);
rs600_debugfs(rdev);
/* Fence driver */
r = radeon_fence_driver_init(rdev);
@@ -689,7 +672,6 @@ int rs600_init(struct radeon_device *rdev)
if (r) {
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
- rs600_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index cd31da913771..83b9174f76f2 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -129,27 +129,21 @@ void rs690_pm_info(struct radeon_device *rdev)
rdev->pm.sideport_bandwidth.full = rfixed_div(rdev->pm.sideport_bandwidth, tmp);
}
-void rs690_vram_info(struct radeon_device *rdev)
+void rs690_mc_init(struct radeon_device *rdev)
{
fixed20_12 a;
+ u64 base;
rs400_gart_adjust_size(rdev);
-
rdev->mc.vram_is_ddr = true;
rdev->mc.vram_width = 128;
-
rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
-
rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
-
- if (rdev->mc.mc_vram_size > rdev->mc.aper_size)
- rdev->mc.mc_vram_size = rdev->mc.aper_size;
-
- if (rdev->mc.real_vram_size > rdev->mc.aper_size)
- rdev->mc.real_vram_size = rdev->mc.aper_size;
-
+ rdev->mc.visible_vram_size = rdev->mc.aper_size;
+ base = RREG32_MC(R_000100_MCCFG_FB_LOCATION);
+ base = G_000100_MC_FB_START(base) << 16;
rs690_pm_info(rdev);
/* FIXME: we should enforce default clock in case GPU is not in
* default setup
@@ -160,22 +154,9 @@ void rs690_vram_info(struct radeon_device *rdev)
a.full = rfixed_const(16);
/* core_bandwidth = sclk(Mhz) * 16 */
rdev->pm.core_bandwidth.full = rfixed_div(rdev->pm.sclk, a);
-}
-
-static int rs690_mc_init(struct radeon_device *rdev)
-{
- int r;
- u32 tmp;
-
- /* Setup GPU memory space */
- tmp = RREG32_MC(R_000100_MCCFG_FB_LOCATION);
- rdev->mc.vram_location = G_000100_MC_FB_START(tmp) << 16;
- rdev->mc.gtt_location = 0xFFFFFFFFUL;
- r = radeon_mc_setup(rdev);
rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
- if (r)
- return r;
- return 0;
+ radeon_vram_location(rdev, &rdev->mc, base);
+ radeon_gtt_location(rdev, &rdev->mc);
}
void rs690_line_buffer_adjust(struct radeon_device *rdev,
@@ -676,7 +657,6 @@ int rs690_suspend(struct radeon_device *rdev)
void rs690_fini(struct radeon_device *rdev)
{
- rs690_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -729,12 +709,8 @@ int rs690_init(struct radeon_device *rdev)
radeon_get_clock_info(rdev->ddev);
/* Initialize power management */
radeon_pm_init(rdev);
- /* Get vram informations */
- rs690_vram_info(rdev);
- /* Initialize memory controller (also test AGP) */
- r = rs690_mc_init(rdev);
- if (r)
- return r;
+ /* initialize memory controller */
+ rs690_mc_init(rdev);
rv515_debugfs(rdev);
/* Fence driver */
r = radeon_fence_driver_init(rdev);
@@ -756,7 +732,6 @@ int rs690_init(struct radeon_device *rdev)
if (r) {
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
- rs690_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index 62756717b044..bea747da123f 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -277,13 +277,15 @@ static void rv515_vram_get_type(struct radeon_device *rdev)
}
}
-void rv515_vram_info(struct radeon_device *rdev)
+void rv515_mc_init(struct radeon_device *rdev)
{
fixed20_12 a;
rv515_vram_get_type(rdev);
-
r100_vram_init_sizes(rdev);
+ radeon_vram_location(rdev, &rdev->mc, 0);
+ if (!(rdev->flags & RADEON_IS_AGP))
+ radeon_gtt_location(rdev, &rdev->mc);
/* FIXME: we should enforce default clock in case GPU is not in
* default setup
*/
@@ -537,7 +539,6 @@ void rv515_set_safe_registers(struct radeon_device *rdev)
void rv515_fini(struct radeon_device *rdev)
{
- rv515_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -588,12 +589,15 @@ int rv515_init(struct radeon_device *rdev)
radeon_get_clock_info(rdev->ddev);
/* Initialize power management */
radeon_pm_init(rdev);
- /* Get vram informations */
- rv515_vram_info(rdev);
- /* Initialize memory controller (also test AGP) */
- r = r420_mc_init(rdev);
- if (r)
- return r;
+ /* initialize AGP */
+ if (rdev->flags & RADEON_IS_AGP) {
+ r = radeon_agp_init(rdev);
+ if (r) {
+ radeon_agp_disable(rdev);
+ }
+ }
+ /* initialize memory controller */
+ rv515_mc_init(rdev);
rv515_debugfs(rdev);
/* Fence driver */
r = radeon_fence_driver_init(rdev);
@@ -615,13 +619,12 @@ int rv515_init(struct radeon_device *rdev)
if (r) {
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
- rv515_suspend(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
+ radeon_irq_kms_fini(rdev);
rv370_pcie_gart_fini(rdev);
radeon_agp_fini(rdev);
- radeon_irq_kms_fini(rdev);
rdev->accel_working = false;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 59c71245fb91..37887dee12af 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -56,6 +56,7 @@ int rv770_pcie_gart_enable(struct radeon_device *rdev)
r = radeon_gart_table_vram_pin(rdev);
if (r)
return r;
+ radeon_gart_restore(rdev);
/* Setup L2 cache */
WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING |
ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
@@ -273,9 +274,10 @@ static int rv770_cp_load_microcode(struct radeon_device *rdev)
/*
* Core functions
*/
-static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
- u32 num_backends,
- u32 backend_disable_mask)
+static u32 r700_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
+ u32 num_tile_pipes,
+ u32 num_backends,
+ u32 backend_disable_mask)
{
u32 backend_map = 0;
u32 enabled_backends_mask;
@@ -284,6 +286,7 @@ static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
u32 swizzle_pipe[R7XX_MAX_PIPES];
u32 cur_backend;
u32 i;
+ bool force_no_swizzle;
if (num_tile_pipes > R7XX_MAX_PIPES)
num_tile_pipes = R7XX_MAX_PIPES;
@@ -313,6 +316,18 @@ static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
if (enabled_backends_count != num_backends)
num_backends = enabled_backends_count;
+ switch (rdev->family) {
+ case CHIP_RV770:
+ case CHIP_RV730:
+ force_no_swizzle = false;
+ break;
+ case CHIP_RV710:
+ case CHIP_RV740:
+ default:
+ force_no_swizzle = true;
+ break;
+ }
+
memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R7XX_MAX_PIPES);
switch (num_tile_pipes) {
case 1:
@@ -323,49 +338,100 @@ static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
swizzle_pipe[1] = 1;
break;
case 3:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 1;
+ if (force_no_swizzle) {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 1;
+ swizzle_pipe[2] = 2;
+ } else {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 2;
+ swizzle_pipe[2] = 1;
+ }
break;
case 4:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 3;
- swizzle_pipe[3] = 1;
+ if (force_no_swizzle) {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 1;
+ swizzle_pipe[2] = 2;
+ swizzle_pipe[3] = 3;
+ } else {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 2;
+ swizzle_pipe[2] = 3;
+ swizzle_pipe[3] = 1;
+ }
break;
case 5:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 1;
- swizzle_pipe[4] = 3;
+ if (force_no_swizzle) {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 1;
+ swizzle_pipe[2] = 2;
+ swizzle_pipe[3] = 3;
+ swizzle_pipe[4] = 4;
+ } else {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 2;
+ swizzle_pipe[2] = 4;
+ swizzle_pipe[3] = 1;
+ swizzle_pipe[4] = 3;
+ }
break;
case 6:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 5;
- swizzle_pipe[4] = 3;
- swizzle_pipe[5] = 1;
+ if (force_no_swizzle) {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 1;
+ swizzle_pipe[2] = 2;
+ swizzle_pipe[3] = 3;
+ swizzle_pipe[4] = 4;
+ swizzle_pipe[5] = 5;
+ } else {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 2;
+ swizzle_pipe[2] = 4;
+ swizzle_pipe[3] = 5;
+ swizzle_pipe[4] = 3;
+ swizzle_pipe[5] = 1;
+ }
break;
case 7:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 6;
- swizzle_pipe[4] = 3;
- swizzle_pipe[5] = 1;
- swizzle_pipe[6] = 5;
+ if (force_no_swizzle) {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 1;
+ swizzle_pipe[2] = 2;
+ swizzle_pipe[3] = 3;
+ swizzle_pipe[4] = 4;
+ swizzle_pipe[5] = 5;
+ swizzle_pipe[6] = 6;
+ } else {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 2;
+ swizzle_pipe[2] = 4;
+ swizzle_pipe[3] = 6;
+ swizzle_pipe[4] = 3;
+ swizzle_pipe[5] = 1;
+ swizzle_pipe[6] = 5;
+ }
break;
case 8:
- swizzle_pipe[0] = 0;
- swizzle_pipe[1] = 2;
- swizzle_pipe[2] = 4;
- swizzle_pipe[3] = 6;
- swizzle_pipe[4] = 3;
- swizzle_pipe[5] = 1;
- swizzle_pipe[6] = 7;
- swizzle_pipe[7] = 5;
+ if (force_no_swizzle) {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 1;
+ swizzle_pipe[2] = 2;
+ swizzle_pipe[3] = 3;
+ swizzle_pipe[4] = 4;
+ swizzle_pipe[5] = 5;
+ swizzle_pipe[6] = 6;
+ swizzle_pipe[7] = 7;
+ } else {
+ swizzle_pipe[0] = 0;
+ swizzle_pipe[1] = 2;
+ swizzle_pipe[2] = 4;
+ swizzle_pipe[3] = 6;
+ swizzle_pipe[4] = 3;
+ swizzle_pipe[5] = 1;
+ swizzle_pipe[6] = 7;
+ swizzle_pipe[7] = 5;
+ }
break;
}
@@ -385,8 +451,10 @@ static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
static void rv770_gpu_init(struct radeon_device *rdev)
{
int i, j, num_qd_pipes;
+ u32 ta_aux_cntl;
u32 sx_debug_1;
u32 smx_dc_ctl0;
+ u32 db_debug3;
u32 num_gs_verts_per_thread;
u32 vgt_gs_per_es;
u32 gs_prim_buffer_depth = 0;
@@ -515,6 +583,7 @@ static void rv770_gpu_init(struct radeon_device *rdev)
switch (rdev->config.rv770.max_tile_pipes) {
case 1:
+ default:
gb_tiling_config |= PIPE_TILING(0);
break;
case 2:
@@ -526,16 +595,17 @@ static void rv770_gpu_init(struct radeon_device *rdev)
case 8:
gb_tiling_config |= PIPE_TILING(3);
break;
- default:
- break;
}
+ rdev->config.rv770.tiling_npipes = rdev->config.rv770.max_tile_pipes;
if (rdev->family == CHIP_RV770)
gb_tiling_config |= BANK_TILING(1);
else
gb_tiling_config |= BANK_TILING((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
+ rdev->config.rv770.tiling_nbanks = 4 << ((gb_tiling_config >> 4) & 0x3);
gb_tiling_config |= GROUP_SIZE(0);
+ rdev->config.rv770.tiling_group_size = 256;
if (((mc_arb_ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT) > 3) {
gb_tiling_config |= ROW_TILING(3);
@@ -549,18 +619,27 @@ static void rv770_gpu_init(struct radeon_device *rdev)
gb_tiling_config |= BANK_SWAPS(1);
- backend_map = r700_get_tile_pipe_to_backend_map(rdev->config.rv770.max_tile_pipes,
- rdev->config.rv770.max_backends,
- (0xff << rdev->config.rv770.max_backends) & 0xff);
- gb_tiling_config |= BACKEND_MAP(backend_map);
+ cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000;
+ cc_rb_backend_disable |=
+ BACKEND_DISABLE((R7XX_MAX_BACKENDS_MASK << rdev->config.rv770.max_backends) & R7XX_MAX_BACKENDS_MASK);
- cc_gc_shader_pipe_config =
+ cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00;
+ cc_gc_shader_pipe_config |=
INACTIVE_QD_PIPES((R7XX_MAX_PIPES_MASK << rdev->config.rv770.max_pipes) & R7XX_MAX_PIPES_MASK);
cc_gc_shader_pipe_config |=
INACTIVE_SIMDS((R7XX_MAX_SIMDS_MASK << rdev->config.rv770.max_simds) & R7XX_MAX_SIMDS_MASK);
- cc_rb_backend_disable =
- BACKEND_DISABLE((R7XX_MAX_BACKENDS_MASK << rdev->config.rv770.max_backends) & R7XX_MAX_BACKENDS_MASK);
+ if (rdev->family == CHIP_RV740)
+ backend_map = 0x28;
+ else
+ backend_map = r700_get_tile_pipe_to_backend_map(rdev,
+ rdev->config.rv770.max_tile_pipes,
+ (R7XX_MAX_BACKENDS -
+ r600_count_pipe_bits((cc_rb_backend_disable &
+ R7XX_MAX_BACKENDS_MASK) >> 16)),
+ (cc_rb_backend_disable >> 16));
+ gb_tiling_config |= BACKEND_MAP(backend_map);
+
WREG32(GB_TILING_CONFIG, gb_tiling_config);
WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
@@ -568,16 +647,13 @@ static void rv770_gpu_init(struct radeon_device *rdev)
WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
- WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
+ WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable);
- WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable);
WREG32(CGTS_SYS_TCC_DISABLE, 0);
WREG32(CGTS_TCC_DISABLE, 0);
- WREG32(CGTS_USER_SYS_TCC_DISABLE, 0);
- WREG32(CGTS_USER_TCC_DISABLE, 0);
num_qd_pipes =
- R7XX_MAX_BACKENDS - r600_count_pipe_bits(cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK);
+ R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8);
WREG32(VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & DEALLOC_DIST_MASK);
WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & VTX_REUSE_DEPTH_MASK);
@@ -587,10 +663,8 @@ static void rv770_gpu_init(struct radeon_device *rdev)
WREG32(CP_MEQ_THRESHOLDS, STQ_SPLIT(0x30));
- WREG32(TA_CNTL_AUX, (DISABLE_CUBE_ANISO |
- SYNC_GRADIENT |
- SYNC_WALKER |
- SYNC_ALIGNER));
+ ta_aux_cntl = RREG32(TA_CNTL_AUX);
+ WREG32(TA_CNTL_AUX, ta_aux_cntl | DISABLE_CUBE_ANISO);
sx_debug_1 = RREG32(SX_DEBUG_1);
sx_debug_1 |= ENABLE_NEW_SMX_ADDRESS;
@@ -601,14 +675,28 @@ static void rv770_gpu_init(struct radeon_device *rdev)
smx_dc_ctl0 |= CACHE_DEPTH((rdev->config.rv770.sx_num_of_sets * 64) - 1);
WREG32(SMX_DC_CTL0, smx_dc_ctl0);
- WREG32(SMX_EVENT_CTL, (ES_FLUSH_CTL(4) |
- GS_FLUSH_CTL(4) |
- ACK_FLUSH_CTL(3) |
- SYNC_FLUSH_CTL));
+ if (rdev->family != CHIP_RV740)
+ WREG32(SMX_EVENT_CTL, (ES_FLUSH_CTL(4) |
+ GS_FLUSH_CTL(4) |
+ ACK_FLUSH_CTL(3) |
+ SYNC_FLUSH_CTL));
- if (rdev->family == CHIP_RV770)
- WREG32(DB_DEBUG3, DB_CLK_OFF_DELAY(0x1f));
- else {
+ db_debug3 = RREG32(DB_DEBUG3);
+ db_debug3 &= ~DB_CLK_OFF_DELAY(0x1f);
+ switch (rdev->family) {
+ case CHIP_RV770:
+ case CHIP_RV740:
+ db_debug3 |= DB_CLK_OFF_DELAY(0x1f);
+ break;
+ case CHIP_RV710:
+ case CHIP_RV730:
+ default:
+ db_debug3 |= DB_CLK_OFF_DELAY(2);
+ break;
+ }
+ WREG32(DB_DEBUG3, db_debug3);
+
+ if (rdev->family != CHIP_RV770) {
db_debug4 = RREG32(DB_DEBUG4);
db_debug4 |= DISABLE_TILE_COVERED_FOR_PS_ITER;
WREG32(DB_DEBUG4, db_debug4);
@@ -637,10 +725,10 @@ static void rv770_gpu_init(struct radeon_device *rdev)
ALU_UPDATE_FIFO_HIWATER(0x8));
switch (rdev->family) {
case CHIP_RV770:
- sq_ms_fifo_sizes |= FETCH_FIFO_HIWATER(0x1);
- break;
case CHIP_RV730:
case CHIP_RV710:
+ sq_ms_fifo_sizes |= FETCH_FIFO_HIWATER(0x1);
+ break;
case CHIP_RV740:
default:
sq_ms_fifo_sizes |= FETCH_FIFO_HIWATER(0x4);
@@ -779,7 +867,6 @@ int rv770_mc_init(struct radeon_device *rdev)
fixed20_12 a;
u32 tmp;
int chansize, numchan;
- int r;
/* Get VRAM informations */
rdev->mc.vram_is_ddr = true;
@@ -814,48 +901,13 @@ int rv770_mc_init(struct radeon_device *rdev)
/* Setup GPU memory space */
rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE);
rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE);
-
- if (rdev->mc.mc_vram_size > rdev->mc.aper_size)
+ rdev->mc.visible_vram_size = rdev->mc.aper_size;
+ /* FIXME remove this once we support unmappable VRAM */
+ if (rdev->mc.mc_vram_size > rdev->mc.aper_size) {
rdev->mc.mc_vram_size = rdev->mc.aper_size;
-
- if (rdev->mc.real_vram_size > rdev->mc.aper_size)
rdev->mc.real_vram_size = rdev->mc.aper_size;
-
- if (rdev->flags & RADEON_IS_AGP) {
- r = radeon_agp_init(rdev);
- if (r)
- return r;
- /* gtt_size is setup by radeon_agp_init */
- rdev->mc.gtt_location = rdev->mc.agp_base;
- tmp = 0xFFFFFFFFUL - rdev->mc.agp_base - rdev->mc.gtt_size;
- /* Try to put vram before or after AGP because we
- * we want SYSTEM_APERTURE to cover both VRAM and
- * AGP so that GPU can catch out of VRAM/AGP access
- */
- if (rdev->mc.gtt_location > rdev->mc.mc_vram_size) {
- /* Enough place before */
- rdev->mc.vram_location = rdev->mc.gtt_location -
- rdev->mc.mc_vram_size;
- } else if (tmp > rdev->mc.mc_vram_size) {
- /* Enough place after */
- rdev->mc.vram_location = rdev->mc.gtt_location +
- rdev->mc.gtt_size;
- } else {
- /* Try to setup VRAM then AGP might not
- * not work on some card
- */
- rdev->mc.vram_location = 0x00000000UL;
- rdev->mc.gtt_location = rdev->mc.mc_vram_size;
- }
- } else {
- rdev->mc.vram_location = 0x00000000UL;
- rdev->mc.gtt_location = rdev->mc.mc_vram_size;
- rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
}
- rdev->mc.vram_start = rdev->mc.vram_location;
- rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
- rdev->mc.gtt_start = rdev->mc.gtt_location;
- rdev->mc.gtt_end = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
+ r600_vram_gtt_location(rdev, &rdev->mc);
/* FIXME: we should enforce default clock in case GPU is not in
* default setup
*/
@@ -864,6 +916,7 @@ int rv770_mc_init(struct radeon_device *rdev)
rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a);
return 0;
}
+
int rv770_gpu_reset(struct radeon_device *rdev)
{
/* FIXME: implement any rv770 specific bits */
@@ -891,26 +944,25 @@ static int rv770_startup(struct radeon_device *rdev)
return r;
}
rv770_gpu_init(rdev);
-
- if (!rdev->r600_blit.shader_obj) {
- r = r600_blit_init(rdev);
+ r = r600_blit_init(rdev);
+ if (r) {
+ r600_blit_fini(rdev);
+ rdev->asic->copy = NULL;
+ dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
+ }
+ /* pin copy shader into vram */
+ if (rdev->r600_blit.shader_obj) {
+ r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+ if (unlikely(r != 0))
+ return r;
+ r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
+ &rdev->r600_blit.shader_gpu_addr);
+ radeon_bo_unreserve(rdev->r600_blit.shader_obj);
if (r) {
- DRM_ERROR("radeon: failed blitter (%d).\n", r);
+ DRM_ERROR("failed to pin blit object %d\n", r);
return r;
}
}
-
- r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
- if (unlikely(r != 0))
- return r;
- r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
- &rdev->r600_blit.shader_gpu_addr);
- radeon_bo_unreserve(rdev->r600_blit.shader_obj);
- if (r) {
- DRM_ERROR("failed to pin blit object %d\n", r);
- return r;
- }
-
/* Enable IRQ */
r = r600_irq_init(rdev);
if (r) {
@@ -972,13 +1024,16 @@ int rv770_suspend(struct radeon_device *rdev)
/* FIXME: we should wait for ring to be empty */
r700_cp_stop(rdev);
rdev->cp.ready = false;
+ r600_irq_suspend(rdev);
r600_wb_disable(rdev);
rv770_pcie_gart_disable(rdev);
/* unpin shaders bo */
- r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
- if (likely(r == 0)) {
- radeon_bo_unpin(rdev->r600_blit.shader_obj);
- radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+ if (rdev->r600_blit.shader_obj) {
+ r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+ if (likely(r == 0)) {
+ radeon_bo_unpin(rdev->r600_blit.shader_obj);
+ radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+ }
}
return 0;
}
@@ -1037,6 +1092,12 @@ int rv770_init(struct radeon_device *rdev)
r = radeon_fence_driver_init(rdev);
if (r)
return r;
+ /* initialize AGP */
+ if (rdev->flags & RADEON_IS_AGP) {
+ r = radeon_agp_init(rdev);
+ if (r)
+ radeon_agp_disable(rdev);
+ }
r = rv770_mc_init(rdev);
if (r)
return r;
@@ -1062,22 +1123,25 @@ int rv770_init(struct radeon_device *rdev)
rdev->accel_working = true;
r = rv770_startup(rdev);
if (r) {
- rv770_suspend(rdev);
+ dev_err(rdev->dev, "disabling GPU acceleration\n");
+ r600_cp_fini(rdev);
r600_wb_fini(rdev);
- radeon_ring_fini(rdev);
+ r600_irq_fini(rdev);
+ radeon_irq_kms_fini(rdev);
rv770_pcie_gart_fini(rdev);
rdev->accel_working = false;
}
if (rdev->accel_working) {
r = radeon_ib_pool_init(rdev);
if (r) {
- DRM_ERROR("radeon: failed initializing IB pool (%d).\n", r);
- rdev->accel_working = false;
- }
- r = r600_ib_test(rdev);
- if (r) {
- DRM_ERROR("radeon: failed testing IB (%d).\n", r);
+ dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
rdev->accel_working = false;
+ } else {
+ r = r600_ib_test(rdev);
+ if (r) {
+ dev_err(rdev->dev, "IB test failed (%d).\n", r);
+ rdev->accel_working = false;
+ }
}
}
return 0;
@@ -1085,13 +1149,11 @@ int rv770_init(struct radeon_device *rdev)
void rv770_fini(struct radeon_device *rdev)
{
- rv770_suspend(rdev);
-
r600_blit_fini(rdev);
+ r600_cp_fini(rdev);
+ r600_wb_fini(rdev);
r600_irq_fini(rdev);
radeon_irq_kms_fini(rdev);
- radeon_ring_fini(rdev);
- r600_wb_fini(rdev);
rv770_pcie_gart_fini(rdev);
radeon_gem_fini(rdev);
radeon_fence_driver_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h
index a1367ab6f261..9506f8cb99e0 100644
--- a/drivers/gpu/drm/radeon/rv770d.h
+++ b/drivers/gpu/drm/radeon/rv770d.h
@@ -343,4 +343,6 @@
#define WAIT_UNTIL 0x8040
+#define SRBM_STATUS 0x0E50
+
#endif
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 2920f9a279e1..89c38c49066f 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -128,7 +128,7 @@ static struct attribute *ttm_bo_global_attrs[] = {
NULL
};
-static struct sysfs_ops ttm_bo_global_ops = {
+static const struct sysfs_ops ttm_bo_global_ops = {
.show = &ttm_bo_global_show
};
@@ -426,7 +426,8 @@ moved:
bdev->man[bo->mem.mem_type].gpu_offset;
bo->cur_placement = bo->mem.placement;
spin_unlock(&bo->lock);
- }
+ } else
+ bo->offset = 0;
return 0;
@@ -523,52 +524,44 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all)
static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all)
{
struct ttm_bo_global *glob = bdev->glob;
- struct ttm_buffer_object *entry, *nentry;
- struct list_head *list, *next;
- int ret;
+ struct ttm_buffer_object *entry = NULL;
+ int ret = 0;
spin_lock(&glob->lru_lock);
- list_for_each_safe(list, next, &bdev->ddestroy) {
- entry = list_entry(list, struct ttm_buffer_object, ddestroy);
- nentry = NULL;
+ if (list_empty(&bdev->ddestroy))
+ goto out_unlock;
- /*
- * Protect the next list entry from destruction while we
- * unlock the lru_lock.
- */
+ entry = list_first_entry(&bdev->ddestroy,
+ struct ttm_buffer_object, ddestroy);
+ kref_get(&entry->list_kref);
- if (next != &bdev->ddestroy) {
- nentry = list_entry(next, struct ttm_buffer_object,
- ddestroy);
+ for (;;) {
+ struct ttm_buffer_object *nentry = NULL;
+
+ if (entry->ddestroy.next != &bdev->ddestroy) {
+ nentry = list_first_entry(&entry->ddestroy,
+ struct ttm_buffer_object, ddestroy);
kref_get(&nentry->list_kref);
}
- kref_get(&entry->list_kref);
spin_unlock(&glob->lru_lock);
ret = ttm_bo_cleanup_refs(entry, remove_all);
kref_put(&entry->list_kref, ttm_bo_release_list);
+ entry = nentry;
+
+ if (ret || !entry)
+ goto out;
spin_lock(&glob->lru_lock);
- if (nentry) {
- bool next_onlist = !list_empty(next);
- spin_unlock(&glob->lru_lock);
- kref_put(&nentry->list_kref, ttm_bo_release_list);
- spin_lock(&glob->lru_lock);
- /*
- * Someone might have raced us and removed the
- * next entry from the list. We don't bother restarting
- * list traversal.
- */
-
- if (!next_onlist)
- break;
- }
- if (ret)
+ if (list_empty(&entry->ddestroy))
break;
}
- ret = !list_empty(&bdev->ddestroy);
- spin_unlock(&glob->lru_lock);
+out_unlock:
+ spin_unlock(&glob->lru_lock);
+out:
+ if (entry)
+ kref_put(&entry->list_kref, ttm_bo_release_list);
return ret;
}
@@ -950,6 +943,14 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
ttm_flag_masked(&cur_flags, placement->busy_placement[i],
~TTM_PL_MASK_MEMTYPE);
+
+ if (mem_type == TTM_PL_SYSTEM) {
+ mem->mem_type = mem_type;
+ mem->placement = cur_flags;
+ mem->mm_node = NULL;
+ return 0;
+ }
+
ret = ttm_bo_mem_force_space(bo, mem_type, placement, mem,
interruptible, no_wait);
if (ret == 0 && mem->mm_node) {
@@ -1019,6 +1020,12 @@ static int ttm_bo_mem_compat(struct ttm_placement *placement,
struct ttm_mem_reg *mem)
{
int i;
+ struct drm_mm_node *node = mem->mm_node;
+
+ if (node && placement->lpfn != 0 &&
+ (node->start < placement->fpfn ||
+ node->start + node->size > placement->lpfn))
+ return -1;
for (i = 0; i < placement->num_placement; i++) {
if ((placement->placement[i] & mem->placement &
@@ -1844,6 +1851,9 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
* anyone tries to access a ttm page.
*/
+ if (bo->bdev->driver->swap_notify)
+ bo->bdev->driver->swap_notify(bo);
+
ret = ttm_tt_swapout(bo->ttm, bo->persistant_swap_storage);
out:
@@ -1864,3 +1874,4 @@ void ttm_bo_swapout_all(struct ttm_bo_device *bdev)
while (ttm_bo_swapout(&bdev->glob->shrink) == 0)
;
}
+EXPORT_SYMBOL(ttm_bo_swapout_all);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index 2ecf7d0c64f6..5ca37a58a98c 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -53,7 +53,6 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
{
struct ttm_tt *ttm = bo->ttm;
struct ttm_mem_reg *old_mem = &bo->mem;
- uint32_t save_flags = old_mem->placement;
int ret;
if (old_mem->mem_type != TTM_PL_SYSTEM) {
@@ -62,7 +61,6 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
ttm_flag_masked(&old_mem->placement, TTM_PL_FLAG_SYSTEM,
TTM_PL_MASK_MEM);
old_mem->mem_type = TTM_PL_SYSTEM;
- save_flags = old_mem->placement;
}
ret = ttm_tt_set_placement_caching(ttm, new_mem->placement);
@@ -77,7 +75,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
*old_mem = *new_mem;
new_mem->mm_node = NULL;
- ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE);
+
return 0;
}
EXPORT_SYMBOL(ttm_bo_move_ttm);
@@ -219,7 +217,6 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
void *old_iomap;
void *new_iomap;
int ret;
- uint32_t save_flags = old_mem->placement;
unsigned long i;
unsigned long page;
unsigned long add = 0;
@@ -270,7 +267,6 @@ out2:
*old_mem = *new_mem;
new_mem->mm_node = NULL;
- ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE);
if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) && (ttm != NULL)) {
ttm_tt_unbind(ttm);
@@ -537,7 +533,6 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type];
struct ttm_mem_reg *old_mem = &bo->mem;
int ret;
- uint32_t save_flags = old_mem->placement;
struct ttm_buffer_object *ghost_obj;
void *tmp_obj = NULL;
@@ -598,7 +593,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
*old_mem = *new_mem;
new_mem->mm_node = NULL;
- ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE);
+
return 0;
}
EXPORT_SYMBOL(ttm_bo_move_accel_cleanup);
diff --git a/drivers/gpu/drm/ttm/ttm_lock.c b/drivers/gpu/drm/ttm/ttm_lock.c
index f619ebcaa4ec..3d172ef04ee1 100644
--- a/drivers/gpu/drm/ttm/ttm_lock.c
+++ b/drivers/gpu/drm/ttm/ttm_lock.c
@@ -288,6 +288,7 @@ void ttm_suspend_unlock(struct ttm_lock *lock)
wake_up_all(&lock->queue);
spin_unlock(&lock->lock);
}
+EXPORT_SYMBOL(ttm_suspend_unlock);
static bool __ttm_suspend_lock(struct ttm_lock *lock)
{
@@ -309,3 +310,4 @@ void ttm_suspend_lock(struct ttm_lock *lock)
{
wait_event(lock->queue, __ttm_suspend_lock(lock));
}
+EXPORT_SYMBOL(ttm_suspend_lock);
diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c
index f5245c02b8fd..eb143e04d402 100644
--- a/drivers/gpu/drm/ttm/ttm_memory.c
+++ b/drivers/gpu/drm/ttm/ttm_memory.c
@@ -152,7 +152,7 @@ static struct attribute *ttm_mem_zone_attrs[] = {
NULL
};
-static struct sysfs_ops ttm_mem_zone_ops = {
+static const struct sysfs_ops ttm_mem_zone_ops = {
.show = &ttm_mem_zone_show,
.store = &ttm_mem_zone_store
};
diff --git a/drivers/gpu/drm/ttm/ttm_object.c b/drivers/gpu/drm/ttm/ttm_object.c
index 1099abac824b..75e9d6f86ba4 100644
--- a/drivers/gpu/drm/ttm/ttm_object.c
+++ b/drivers/gpu/drm/ttm/ttm_object.c
@@ -109,8 +109,8 @@ struct ttm_ref_object {
struct drm_hash_item hash;
struct list_head head;
struct kref kref;
- struct ttm_base_object *obj;
enum ttm_ref_type ref_type;
+ struct ttm_base_object *obj;
struct ttm_object_file *tfile;
};
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index 9c2b1cc5dba5..a759170763bb 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -196,23 +196,34 @@ EXPORT_SYMBOL(ttm_tt_populate);
#ifdef CONFIG_X86
static inline int ttm_tt_set_page_caching(struct page *p,
- enum ttm_caching_state c_state)
+ enum ttm_caching_state c_old,
+ enum ttm_caching_state c_new)
{
+ int ret = 0;
+
if (PageHighMem(p))
return 0;
- switch (c_state) {
- case tt_cached:
- return set_pages_wb(p, 1);
- case tt_wc:
- return set_memory_wc((unsigned long) page_address(p), 1);
- default:
- return set_pages_uc(p, 1);
+ if (c_old != tt_cached) {
+ /* p isn't in the default caching state, set it to
+ * writeback first to free its current memtype. */
+
+ ret = set_pages_wb(p, 1);
+ if (ret)
+ return ret;
}
+
+ if (c_new == tt_wc)
+ ret = set_memory_wc((unsigned long) page_address(p), 1);
+ else if (c_new == tt_uncached)
+ ret = set_pages_uc(p, 1);
+
+ return ret;
}
#else /* CONFIG_X86 */
static inline int ttm_tt_set_page_caching(struct page *p,
- enum ttm_caching_state c_state)
+ enum ttm_caching_state c_old,
+ enum ttm_caching_state c_new)
{
return 0;
}
@@ -245,7 +256,9 @@ static int ttm_tt_set_caching(struct ttm_tt *ttm,
for (i = 0; i < ttm->num_pages; ++i) {
cur_page = ttm->pages[i];
if (likely(cur_page != NULL)) {
- ret = ttm_tt_set_page_caching(cur_page, c_state);
+ ret = ttm_tt_set_page_caching(cur_page,
+ ttm->caching_state,
+ c_state);
if (unlikely(ret != 0))
goto out_err;
}
@@ -259,7 +272,7 @@ out_err:
for (j = 0; j < i; ++j) {
cur_page = ttm->pages[j];
if (likely(cur_page != NULL)) {
- (void)ttm_tt_set_page_caching(cur_page,
+ (void)ttm_tt_set_page_caching(cur_page, c_state,
ttm->caching_state);
}
}
@@ -467,7 +480,7 @@ static int ttm_tt_swapin(struct ttm_tt *ttm)
void *from_virtual;
void *to_virtual;
int i;
- int ret;
+ int ret = -ENOMEM;
if (ttm->page_flags & TTM_PAGE_FLAG_USER) {
ret = ttm_tt_set_user(ttm, ttm->tsk, ttm->start,
@@ -486,8 +499,10 @@ static int ttm_tt_swapin(struct ttm_tt *ttm)
for (i = 0; i < ttm->num_pages; ++i) {
from_page = read_mapping_page(swap_space, i, NULL);
- if (IS_ERR(from_page))
+ if (IS_ERR(from_page)) {
+ ret = PTR_ERR(from_page);
goto out_err;
+ }
to_page = __ttm_tt_get_page(ttm, i);
if (unlikely(to_page == NULL))
goto out_err;
@@ -510,7 +525,7 @@ static int ttm_tt_swapin(struct ttm_tt *ttm)
return 0;
out_err:
ttm_tt_free_alloced_pages(ttm);
- return -ENOMEM;
+ return ret;
}
int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage)
@@ -522,6 +537,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage)
void *from_virtual;
void *to_virtual;
int i;
+ int ret = -ENOMEM;
BUG_ON(ttm->state != tt_unbound && ttm->state != tt_unpopulated);
BUG_ON(ttm->caching_state != tt_cached);
@@ -544,7 +560,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage)
0);
if (unlikely(IS_ERR(swap_storage))) {
printk(KERN_ERR "Failed allocating swap storage.\n");
- return -ENOMEM;
+ return PTR_ERR(swap_storage);
}
} else
swap_storage = persistant_swap_storage;
@@ -556,9 +572,10 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage)
if (unlikely(from_page == NULL))
continue;
to_page = read_mapping_page(swap_space, i, NULL);
- if (unlikely(to_page == NULL))
+ if (unlikely(IS_ERR(to_page))) {
+ ret = PTR_ERR(to_page);
goto out_err;
-
+ }
preempt_disable();
from_virtual = kmap_atomic(from_page, KM_USER0);
to_virtual = kmap_atomic(to_page, KM_USER1);
@@ -582,5 +599,5 @@ out_err:
if (!persistant_swap_storage)
fput(swap_storage);
- return -ENOMEM;
+ return ret;
}
diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c
index 5935b8842e86..34079f251cd4 100644
--- a/drivers/gpu/drm/via/via_irq.c
+++ b/drivers/gpu/drm/via/via_irq.c
@@ -150,7 +150,7 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
cur_irq++;
}
- /* Acknowlege interrupts */
+ /* Acknowledge interrupts */
VIA_WRITE(VIA_REG_INTERRUPT, status);
@@ -165,7 +165,7 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
u32 status;
if (dev_priv) {
- /* Acknowlege interrupts */
+ /* Acknowledge interrupts */
status = VIA_READ(VIA_REG_INTERRUPT);
VIA_WRITE(VIA_REG_INTERRUPT, status |
dev_priv->irq_pending_mask);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
index d6f2d2b882e9..825ebe3d89d5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
@@ -48,6 +48,15 @@ struct ttm_placement vmw_vram_placement = {
.busy_placement = &vram_placement_flags
};
+struct ttm_placement vmw_vram_sys_placement = {
+ .fpfn = 0,
+ .lpfn = 0,
+ .num_placement = 1,
+ .placement = &vram_placement_flags,
+ .num_busy_placement = 1,
+ .busy_placement = &sys_placement_flags
+};
+
struct ttm_placement vmw_vram_ne_placement = {
.fpfn = 0,
.lpfn = 0,
@@ -172,6 +181,18 @@ static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp)
return 0;
}
+static void vmw_move_notify(struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *new_mem)
+{
+ if (new_mem->mem_type != TTM_PL_SYSTEM)
+ vmw_dmabuf_gmr_unbind(bo);
+}
+
+static void vmw_swap_notify(struct ttm_buffer_object *bo)
+{
+ vmw_dmabuf_gmr_unbind(bo);
+}
+
/**
* FIXME: We're using the old vmware polling method to sync.
* Do this with fences instead.
@@ -225,5 +246,7 @@ struct ttm_bo_driver vmw_bo_driver = {
.sync_obj_wait = vmw_sync_obj_wait,
.sync_obj_flush = vmw_sync_obj_flush,
.sync_obj_unref = vmw_sync_obj_unref,
- .sync_obj_ref = vmw_sync_obj_ref
+ .sync_obj_ref = vmw_sync_obj_ref,
+ .move_notify = vmw_move_notify,
+ .swap_notify = vmw_swap_notify
};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 1db1ef30be2b..0c9c0811f42d 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -147,6 +147,8 @@ static char *vmw_devname = "vmwgfx";
static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
static void vmw_master_init(struct vmw_master *);
+static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
+ void *ptr);
static void vmw_print_capabilities(uint32_t capabilities)
{
@@ -207,6 +209,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
{
struct vmw_private *dev_priv;
int ret;
+ uint32_t svga_id;
dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
if (unlikely(dev_priv == NULL)) {
@@ -217,6 +220,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->dev = dev;
dev_priv->vmw_chipset = chipset;
+ dev_priv->last_read_sequence = (uint32_t) -100;
mutex_init(&dev_priv->hw_mutex);
mutex_init(&dev_priv->cmdbuf_mutex);
rwlock_init(&dev_priv->resource_lock);
@@ -236,6 +240,16 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->mmio_start = pci_resource_start(dev->pdev, 2);
mutex_lock(&dev_priv->hw_mutex);
+
+ vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2);
+ svga_id = vmw_read(dev_priv, SVGA_REG_ID);
+ if (svga_id != SVGA_ID_2) {
+ ret = -ENOSYS;
+ DRM_ERROR("Unsuported SVGA ID 0x%x\n", svga_id);
+ mutex_unlock(&dev_priv->hw_mutex);
+ goto out_err0;
+ }
+
dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES);
if (dev_priv->capabilities & SVGA_CAP_GMR) {
@@ -334,22 +348,24 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
*/
DRM_INFO("It appears like vesafb is loaded. "
- "Ignore above error if any. Entering stealth mode.\n");
+ "Ignore above error if any.\n");
ret = pci_request_region(dev->pdev, 2, "vmwgfx stealth probe");
if (unlikely(ret != 0)) {
DRM_ERROR("Failed reserving the SVGA MMIO resource.\n");
goto out_no_device;
}
- vmw_kms_init(dev_priv);
- vmw_overlay_init(dev_priv);
- } else {
- ret = vmw_request_device(dev_priv);
- if (unlikely(ret != 0))
- goto out_no_device;
- vmw_kms_init(dev_priv);
- vmw_overlay_init(dev_priv);
- vmw_fb_init(dev_priv);
}
+ ret = vmw_request_device(dev_priv);
+ if (unlikely(ret != 0))
+ goto out_no_device;
+ vmw_kms_init(dev_priv);
+ vmw_overlay_init(dev_priv);
+ vmw_fb_init(dev_priv);
+
+ dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier;
+ register_pm_notifier(&dev_priv->pm_nb);
+
+ DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ? "Have 3D\n" : "No 3D\n");
return 0;
@@ -385,17 +401,17 @@ static int vmw_driver_unload(struct drm_device *dev)
DRM_INFO(VMWGFX_DRIVER_NAME " unload.\n");
- if (!dev_priv->stealth) {
- vmw_fb_close(dev_priv);
- vmw_kms_close(dev_priv);
- vmw_overlay_close(dev_priv);
- vmw_release_device(dev_priv);
- pci_release_regions(dev->pdev);
- } else {
- vmw_kms_close(dev_priv);
- vmw_overlay_close(dev_priv);
+ unregister_pm_notifier(&dev_priv->pm_nb);
+
+ vmw_fb_close(dev_priv);
+ vmw_kms_close(dev_priv);
+ vmw_overlay_close(dev_priv);
+ vmw_release_device(dev_priv);
+ if (dev_priv->stealth)
pci_release_region(dev->pdev, 2);
- }
+ else
+ pci_release_regions(dev->pdev);
+
if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
drm_irq_uninstall(dev_priv->dev);
if (dev->devname == vmw_devname)
@@ -564,11 +580,6 @@ static int vmw_master_set(struct drm_device *dev,
int ret = 0;
DRM_INFO("Master set.\n");
- if (dev_priv->stealth) {
- ret = vmw_request_device(dev_priv);
- if (unlikely(ret != 0))
- return ret;
- }
if (active) {
BUG_ON(active != &dev_priv->fbdev_master);
@@ -628,18 +639,11 @@ static void vmw_master_drop(struct drm_device *dev,
ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
- if (dev_priv->stealth) {
- ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM);
- if (unlikely(ret != 0))
- DRM_ERROR("Unable to clean VRAM on master drop.\n");
- vmw_release_device(dev_priv);
- }
dev_priv->active_master = &dev_priv->fbdev_master;
ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
ttm_vt_unlock(&dev_priv->fbdev_master.lock);
- if (!dev_priv->stealth)
- vmw_fb_on(dev_priv);
+ vmw_fb_on(dev_priv);
}
@@ -650,6 +654,57 @@ static void vmw_remove(struct pci_dev *pdev)
drm_put_dev(dev);
}
+static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
+ void *ptr)
+{
+ struct vmw_private *dev_priv =
+ container_of(nb, struct vmw_private, pm_nb);
+ struct vmw_master *vmaster = dev_priv->active_master;
+
+ switch (val) {
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+ ttm_suspend_lock(&vmaster->lock);
+
+ /**
+ * This empties VRAM and unbinds all GMR bindings.
+ * Buffer contents is moved to swappable memory.
+ */
+ ttm_bo_swapout_all(&dev_priv->bdev);
+ break;
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ ttm_suspend_unlock(&vmaster->lock);
+ break;
+ case PM_RESTORE_PREPARE:
+ break;
+ case PM_POST_RESTORE:
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
+ * These might not be needed with the virtual SVGA device.
+ */
+
+int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+ return 0;
+}
+
+int vmw_pci_resume(struct pci_dev *pdev)
+{
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ return pci_enable_device(pdev);
+}
+
static struct drm_driver driver = {
.driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
DRIVER_MODESET,
@@ -689,7 +744,9 @@ static struct drm_driver driver = {
.name = VMWGFX_DRIVER_NAME,
.id_table = vmw_pci_id_list,
.probe = vmw_probe,
- .remove = vmw_remove
+ .remove = vmw_remove,
+ .suspend = vmw_pci_suspend,
+ .resume = vmw_pci_resume
},
.name = VMWGFX_DRIVER_NAME,
.desc = VMWGFX_DRIVER_DESC,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index e61bd85b6975..356dc935ec13 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -32,16 +32,17 @@
#include "drmP.h"
#include "vmwgfx_drm.h"
#include "drm_hashtab.h"
+#include "linux/suspend.h"
#include "ttm/ttm_bo_driver.h"
#include "ttm/ttm_object.h"
#include "ttm/ttm_lock.h"
#include "ttm/ttm_execbuf_util.h"
#include "ttm/ttm_module.h"
-#define VMWGFX_DRIVER_DATE "20090724"
-#define VMWGFX_DRIVER_MAJOR 0
-#define VMWGFX_DRIVER_MINOR 1
-#define VMWGFX_DRIVER_PATCHLEVEL 2
+#define VMWGFX_DRIVER_DATE "20100209"
+#define VMWGFX_DRIVER_MAJOR 1
+#define VMWGFX_DRIVER_MINOR 0
+#define VMWGFX_DRIVER_PATCHLEVEL 0
#define VMWGFX_FILE_PAGE_OFFSET 0x00100000
#define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
#define VMWGFX_MAX_RELOCATIONS 2048
@@ -95,6 +96,8 @@ struct vmw_surface {
struct drm_vmw_size *sizes;
uint32_t num_sizes;
+ bool scanout;
+
/* TODO so far just a extra pointer */
struct vmw_cursor_snooper snooper;
};
@@ -110,6 +113,7 @@ struct vmw_fifo_state {
unsigned long static_buffer_size;
bool using_bounce_buffer;
uint32_t capabilities;
+ struct mutex fifo_mutex;
struct rw_semaphore rwsem;
};
@@ -210,7 +214,7 @@ struct vmw_private {
* Fencing and IRQs.
*/
- uint32_t fence_seq;
+ atomic_t fence_seq;
wait_queue_head_t fence_queue;
wait_queue_head_t fifo_queue;
atomic_t fence_queue_waiters;
@@ -258,6 +262,7 @@ struct vmw_private {
struct vmw_master *active_master;
struct vmw_master fbdev_master;
+ struct notifier_block pm_nb;
};
static inline struct vmw_private *vmw_priv(struct drm_device *dev)
@@ -353,6 +358,7 @@ extern int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
struct vmw_dma_buffer *bo);
extern int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv,
struct vmw_dma_buffer *bo);
+extern void vmw_dmabuf_gmr_unbind(struct ttm_buffer_object *bo);
extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
@@ -386,6 +392,7 @@ extern int vmw_fifo_send_fence(struct vmw_private *dev_priv,
uint32_t *sequence);
extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason);
extern int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma);
+extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv);
/**
* TTM glue - vmwgfx_ttm_glue.c
@@ -401,6 +408,7 @@ extern int vmw_mmap(struct file *filp, struct vm_area_struct *vma);
extern struct ttm_placement vmw_vram_placement;
extern struct ttm_placement vmw_vram_ne_placement;
+extern struct ttm_placement vmw_vram_sys_placement;
extern struct ttm_placement vmw_sys_placement;
extern struct ttm_bo_driver vmw_bo_driver;
extern int vmw_dma_quiescent(struct drm_device *dev);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 2e92da567403..0897359b3e4e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -182,25 +182,19 @@ static int vmw_cmd_present_check(struct vmw_private *dev_priv,
return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.sid);
}
-static int vmw_cmd_dma(struct vmw_private *dev_priv,
- struct vmw_sw_context *sw_context,
- SVGA3dCmdHeader *header)
+static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
+ struct vmw_sw_context *sw_context,
+ SVGAGuestPtr *ptr,
+ struct vmw_dma_buffer **vmw_bo_p)
{
- uint32_t handle;
struct vmw_dma_buffer *vmw_bo = NULL;
struct ttm_buffer_object *bo;
- struct vmw_surface *srf = NULL;
- struct vmw_dma_cmd {
- SVGA3dCmdHeader header;
- SVGA3dCmdSurfaceDMA dma;
- } *cmd;
+ uint32_t handle = ptr->gmrId;
struct vmw_relocation *reloc;
- int ret;
uint32_t cur_validate_node;
struct ttm_validate_buffer *val_buf;
+ int ret;
- cmd = container_of(header, struct vmw_dma_cmd, header);
- handle = cmd->dma.guest.ptr.gmrId;
ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo);
if (unlikely(ret != 0)) {
DRM_ERROR("Could not find or use GMR region.\n");
@@ -209,14 +203,14 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
bo = &vmw_bo->base;
if (unlikely(sw_context->cur_reloc >= VMWGFX_MAX_RELOCATIONS)) {
- DRM_ERROR("Max number of DMA commands per submission"
+ DRM_ERROR("Max number relocations per submission"
" exceeded\n");
ret = -EINVAL;
goto out_no_reloc;
}
reloc = &sw_context->relocs[sw_context->cur_reloc++];
- reloc->location = &cmd->dma.guest.ptr;
+ reloc->location = ptr;
cur_validate_node = vmw_dmabuf_validate_node(bo, sw_context->cur_val_buf);
if (unlikely(cur_validate_node >= VMWGFX_MAX_GMRS)) {
@@ -234,7 +228,89 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
list_add_tail(&val_buf->head, &sw_context->validate_nodes);
++sw_context->cur_val_buf;
}
+ *vmw_bo_p = vmw_bo;
+ return 0;
+
+out_no_reloc:
+ vmw_dmabuf_unreference(&vmw_bo);
+ vmw_bo_p = NULL;
+ return ret;
+}
+
+static int vmw_cmd_end_query(struct vmw_private *dev_priv,
+ struct vmw_sw_context *sw_context,
+ SVGA3dCmdHeader *header)
+{
+ struct vmw_dma_buffer *vmw_bo;
+ struct vmw_query_cmd {
+ SVGA3dCmdHeader header;
+ SVGA3dCmdEndQuery q;
+ } *cmd;
+ int ret;
+ cmd = container_of(header, struct vmw_query_cmd, header);
+ ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+ if (unlikely(ret != 0))
+ return ret;
+
+ ret = vmw_translate_guest_ptr(dev_priv, sw_context,
+ &cmd->q.guestResult,
+ &vmw_bo);
+ if (unlikely(ret != 0))
+ return ret;
+
+ vmw_dmabuf_unreference(&vmw_bo);
+ return 0;
+}
+
+static int vmw_cmd_wait_query(struct vmw_private *dev_priv,
+ struct vmw_sw_context *sw_context,
+ SVGA3dCmdHeader *header)
+{
+ struct vmw_dma_buffer *vmw_bo;
+ struct vmw_query_cmd {
+ SVGA3dCmdHeader header;
+ SVGA3dCmdWaitForQuery q;
+ } *cmd;
+ int ret;
+
+ cmd = container_of(header, struct vmw_query_cmd, header);
+ ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+ if (unlikely(ret != 0))
+ return ret;
+
+ ret = vmw_translate_guest_ptr(dev_priv, sw_context,
+ &cmd->q.guestResult,
+ &vmw_bo);
+ if (unlikely(ret != 0))
+ return ret;
+
+ vmw_dmabuf_unreference(&vmw_bo);
+ return 0;
+}
+
+
+static int vmw_cmd_dma(struct vmw_private *dev_priv,
+ struct vmw_sw_context *sw_context,
+ SVGA3dCmdHeader *header)
+{
+ struct vmw_dma_buffer *vmw_bo = NULL;
+ struct ttm_buffer_object *bo;
+ struct vmw_surface *srf = NULL;
+ struct vmw_dma_cmd {
+ SVGA3dCmdHeader header;
+ SVGA3dCmdSurfaceDMA dma;
+ } *cmd;
+ int ret;
+
+ cmd = container_of(header, struct vmw_dma_cmd, header);
+ ret = vmw_translate_guest_ptr(dev_priv, sw_context,
+ &cmd->dma.guest.ptr,
+ &vmw_bo);
+ if (unlikely(ret != 0))
+ return ret;
+
+ bo = &vmw_bo->base;
ret = vmw_user_surface_lookup_handle(dev_priv, sw_context->tfile,
cmd->dma.host.sid, &srf);
if (ret) {
@@ -379,8 +455,8 @@ static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = {
VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_draw),
VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check),
VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_cid_check),
- VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_cid_check),
- VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_QUERY, &vmw_cmd_cid_check),
+ VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_end_query),
+ VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_QUERY, &vmw_cmd_wait_query),
VMW_CMD_DEF(SVGA_3D_CMD_PRESENT_READBACK, &vmw_cmd_ok),
VMW_CMD_DEF(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN,
&vmw_cmd_blt_surf_screen_check)
@@ -490,10 +566,29 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL)
return 0;
+ /**
+ * Put BO in VRAM, only if there is space.
+ */
+
+ ret = ttm_bo_validate(bo, &vmw_vram_sys_placement, true, false);
+ if (unlikely(ret == -ERESTARTSYS))
+ return ret;
+
+ /**
+ * Otherwise, set it up as GMR.
+ */
+
+ if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL)
+ return 0;
+
ret = vmw_gmr_bind(dev_priv, bo);
if (likely(ret == 0 || ret == -ERESTARTSYS))
return ret;
+ /**
+ * If that failed, try VRAM again, this time evicting
+ * previous contents.
+ */
ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false);
return ret;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
index 641dde76ada1..a93367041cdc 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -559,6 +559,9 @@ int vmw_fb_init(struct vmw_private *vmw_priv)
info->pixmap.scan_align = 1;
#endif
+ info->aperture_base = vmw_priv->vram_start;
+ info->aperture_size = vmw_priv->vram_size;
+
/*
* Dirty & Deferred IO
*/
@@ -649,14 +652,6 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
if (unlikely(ret != 0))
goto err_unlock;
- if (vmw_bo->gmr_bound) {
- vmw_gmr_unbind(vmw_priv, vmw_bo->gmr_id);
- spin_lock(&bo->glob->lru_lock);
- ida_remove(&vmw_priv->gmr_ida, vmw_bo->gmr_id);
- spin_unlock(&bo->glob->lru_lock);
- vmw_bo->gmr_bound = NULL;
- }
-
ret = ttm_bo_validate(bo, &ne_placement, false, false);
ttm_bo_unreserve(bo);
err_unlock:
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
index 01feb48af333..39d43a01d846 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
@@ -29,6 +29,25 @@
#include "drmP.h"
#include "ttm/ttm_placement.h"
+bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
+{
+ __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+ uint32_t fifo_min, hwversion;
+
+ fifo_min = ioread32(fifo_mem + SVGA_FIFO_MIN);
+ if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int))
+ return false;
+
+ hwversion = ioread32(fifo_mem + SVGA_FIFO_3D_HWVERSION);
+ if (hwversion == 0)
+ return false;
+
+ if (hwversion < SVGA3D_HWVERSION_WS65_B1)
+ return false;
+
+ return true;
+}
+
int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
{
__le32 __iomem *fifo_mem = dev_priv->mmio_virt;
@@ -55,6 +74,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
fifo->reserved_size = 0;
fifo->using_bounce_buffer = false;
+ mutex_init(&fifo->fifo_mutex);
init_rwsem(&fifo->rwsem);
/*
@@ -98,8 +118,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
(unsigned int) min,
(unsigned int) fifo->capabilities);
- dev_priv->fence_seq = (uint32_t) -100;
- dev_priv->last_read_sequence = (uint32_t) -100;
+ atomic_set(&dev_priv->fence_seq, dev_priv->last_read_sequence);
iowrite32(dev_priv->last_read_sequence, fifo_mem + SVGA_FIFO_FENCE);
return vmw_fifo_send_fence(dev_priv, &dummy);
@@ -265,7 +284,7 @@ void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes)
uint32_t reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE;
int ret;
- down_write(&fifo_state->rwsem);
+ mutex_lock(&fifo_state->fifo_mutex);
max = ioread32(fifo_mem + SVGA_FIFO_MAX);
min = ioread32(fifo_mem + SVGA_FIFO_MIN);
next_cmd = ioread32(fifo_mem + SVGA_FIFO_NEXT_CMD);
@@ -333,7 +352,7 @@ void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes)
}
out_err:
fifo_state->reserved_size = 0;
- up_write(&fifo_state->rwsem);
+ mutex_unlock(&fifo_state->fifo_mutex);
return NULL;
}
@@ -408,6 +427,7 @@ void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes)
}
+ down_write(&fifo_state->rwsem);
if (fifo_state->using_bounce_buffer || reserveable) {
next_cmd += bytes;
if (next_cmd >= max)
@@ -419,8 +439,9 @@ void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes)
if (reserveable)
iowrite32(0, fifo_mem + SVGA_FIFO_RESERVED);
mb();
- vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
up_write(&fifo_state->rwsem);
+ vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+ mutex_unlock(&fifo_state->fifo_mutex);
}
int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence)
@@ -433,9 +454,7 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence)
fm = vmw_fifo_reserve(dev_priv, bytes);
if (unlikely(fm == NULL)) {
- down_write(&fifo_state->rwsem);
- *sequence = dev_priv->fence_seq;
- up_write(&fifo_state->rwsem);
+ *sequence = atomic_read(&dev_priv->fence_seq);
ret = -ENOMEM;
(void)vmw_fallback_wait(dev_priv, false, true, *sequence,
false, 3*HZ);
@@ -443,7 +462,7 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence)
}
do {
- *sequence = dev_priv->fence_seq++;
+ *sequence = atomic_add_return(1, &dev_priv->fence_seq);
} while (*sequence == 0);
if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE)) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index 5fa6a4ed238a..1c7a316454d8 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -43,11 +43,17 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
param->value = vmw_overlay_num_free_overlays(dev_priv);
break;
case DRM_VMW_PARAM_3D:
- param->value = dev_priv->capabilities & SVGA_CAP_3D ? 1 : 0;
+ param->value = vmw_fifo_have_3d(dev_priv) ? 1 : 0;
break;
case DRM_VMW_PARAM_FIFO_OFFSET:
param->value = dev_priv->mmio_start;
break;
+ case DRM_VMW_PARAM_HW_CAPS:
+ param->value = dev_priv->capabilities;
+ break;
+ case DRM_VMW_PARAM_FIFO_CAPS:
+ param->value = dev_priv->fifo.capabilities;
+ break;
default:
DRM_ERROR("Illegal vmwgfx get param request: %d\n",
param->param);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
index d40086fc8647..4d7cb5393860 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
@@ -85,19 +85,12 @@ bool vmw_fence_signaled(struct vmw_private *dev_priv,
return true;
/**
- * Below is to signal stale fences that have wrapped.
- * First, block fence submission.
- */
-
- down_read(&fifo_state->rwsem);
-
- /**
* Then check if the sequence is higher than what we've actually
* emitted. Then the fence is stale and signaled.
*/
- ret = ((dev_priv->fence_seq - sequence) > VMW_FENCE_WRAP);
- up_read(&fifo_state->rwsem);
+ ret = ((atomic_read(&dev_priv->fence_seq) - sequence)
+ > VMW_FENCE_WRAP);
return ret;
}
@@ -127,7 +120,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
if (fifo_idle)
down_read(&fifo_state->rwsem);
- signal_seq = dev_priv->fence_seq;
+ signal_seq = atomic_read(&dev_priv->fence_seq);
ret = 0;
for (;;) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index b1af76e371c3..31f9afed0a63 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -553,9 +553,7 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
} *cmd;
int i, increment = 1;
- if (!num_clips ||
- !(dev_priv->fifo.capabilities &
- SVGA_FIFO_CAP_SCREEN_OBJECT)) {
+ if (!num_clips) {
num_clips = 1;
clips = &norect;
norect.x1 = norect.y1 = 0;
@@ -574,10 +572,10 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
for (i = 0; i < num_clips; i++, clips += increment) {
cmd[i].header = cpu_to_le32(SVGA_CMD_UPDATE);
- cmd[i].body.x = cpu_to_le32(clips[i].x1);
- cmd[i].body.y = cpu_to_le32(clips[i].y1);
- cmd[i].body.width = cpu_to_le32(clips[i].x2 - clips[i].x1);
- cmd[i].body.height = cpu_to_le32(clips[i].y2 - clips[i].y1);
+ cmd[i].body.x = cpu_to_le32(clips->x1);
+ cmd[i].body.y = cpu_to_le32(clips->y1);
+ cmd[i].body.width = cpu_to_le32(clips->x2 - clips->x1);
+ cmd[i].body.height = cpu_to_le32(clips->y2 - clips->y1);
}
vmw_fifo_commit(dev_priv, sizeof(*cmd) * num_clips);
@@ -709,6 +707,9 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
if (ret)
goto try_dmabuf;
+ if (!surface->scanout)
+ goto err_not_scanout;
+
ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
mode_cmd->width, mode_cmd->height);
@@ -742,6 +743,13 @@ try_dmabuf:
}
return &vfb->base;
+
+err_not_scanout:
+ DRM_ERROR("surface not marked as scanout\n");
+ /* vmw_user_surface_lookup takes one ref */
+ vmw_surface_unreference(&surface);
+
+ return NULL;
}
static int vmw_kms_fb_changed(struct drm_device *dev)
@@ -761,10 +769,10 @@ int vmw_kms_init(struct vmw_private *dev_priv)
drm_mode_config_init(dev);
dev->mode_config.funcs = &vmw_kms_funcs;
- dev->mode_config.min_width = 640;
- dev->mode_config.min_height = 480;
- dev->mode_config.max_width = 2048;
- dev->mode_config.max_height = 2048;
+ dev->mode_config.min_width = 1;
+ dev->mode_config.min_height = 1;
+ dev->mode_config.max_width = dev_priv->fb_max_width;
+ dev->mode_config.max_height = dev_priv->fb_max_height;
ret = vmw_kms_init_legacy_display_system(dev_priv);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
index bb6e6a096d25..5b6eabeb7f51 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
@@ -104,7 +104,6 @@ static int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv,
bool pin, bool interruptible)
{
struct ttm_buffer_object *bo = &buf->base;
- struct ttm_bo_global *glob = bo->glob;
struct ttm_placement *overlay_placement = &vmw_vram_placement;
int ret;
@@ -116,14 +115,6 @@ static int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv,
if (unlikely(ret != 0))
goto err;
- if (buf->gmr_bound) {
- vmw_gmr_unbind(dev_priv, buf->gmr_id);
- spin_lock(&glob->lru_lock);
- ida_remove(&dev_priv->gmr_ida, buf->gmr_id);
- spin_unlock(&glob->lru_lock);
- buf->gmr_bound = NULL;
- }
-
if (pin)
overlay_placement = &vmw_vram_ne_placement;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index c012d5927f65..f8fbbc67a406 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -574,6 +574,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
srf->flags = req->flags;
srf->format = req->format;
+ srf->scanout = req->scanout;
memcpy(srf->mip_levels, req->mip_levels, sizeof(srf->mip_levels));
srf->num_sizes = 0;
for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i)
@@ -599,6 +600,26 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
if (unlikely(ret != 0))
goto out_err1;
+ if (srf->scanout &&
+ srf->num_sizes == 1 &&
+ srf->sizes[0].width == 64 &&
+ srf->sizes[0].height == 64 &&
+ srf->format == SVGA3D_A8R8G8B8) {
+
+ srf->snooper.image = kmalloc(64 * 64 * 4, GFP_KERNEL);
+ /* clear the image */
+ if (srf->snooper.image) {
+ memset(srf->snooper.image, 0x00, 64 * 64 * 4);
+ } else {
+ DRM_ERROR("Failed to allocate cursor_image\n");
+ ret = -ENOMEM;
+ goto out_err1;
+ }
+ } else {
+ srf->snooper.image = NULL;
+ }
+ srf->snooper.crtc = NULL;
+
user_srf->base.shareable = false;
user_srf->base.tfile = NULL;
@@ -622,24 +643,6 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
return ret;
}
- if (srf->flags & (1 << 9) &&
- srf->num_sizes == 1 &&
- srf->sizes[0].width == 64 &&
- srf->sizes[0].height == 64 &&
- srf->format == SVGA3D_A8R8G8B8) {
-
- srf->snooper.image = kmalloc(64 * 64 * 4, GFP_KERNEL);
- /* clear the image */
- if (srf->snooper.image)
- memset(srf->snooper.image, 0x00, 64 * 64 * 4);
- else
- DRM_ERROR("Failed to allocate cursor_image\n");
-
- } else {
- srf->snooper.image = NULL;
- }
- srf->snooper.crtc = NULL;
-
rep->sid = user_srf->base.hash.key;
if (rep->sid == SVGA3D_INVALID_ID)
DRM_ERROR("Created bad Surface ID.\n");
@@ -754,20 +757,29 @@ static size_t vmw_dmabuf_acc_size(struct ttm_bo_global *glob,
return bo_user_size + page_array_size;
}
-void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo)
+void vmw_dmabuf_gmr_unbind(struct ttm_buffer_object *bo)
{
struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
struct ttm_bo_global *glob = bo->glob;
struct vmw_private *dev_priv =
container_of(bo->bdev, struct vmw_private, bdev);
- ttm_mem_global_free(glob->mem_glob, bo->acc_size);
if (vmw_bo->gmr_bound) {
vmw_gmr_unbind(dev_priv, vmw_bo->gmr_id);
spin_lock(&glob->lru_lock);
ida_remove(&dev_priv->gmr_ida, vmw_bo->gmr_id);
spin_unlock(&glob->lru_lock);
+ vmw_bo->gmr_bound = false;
}
+}
+
+void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo)
+{
+ struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
+ struct ttm_bo_global *glob = bo->glob;
+
+ vmw_dmabuf_gmr_unbind(bo);
+ ttm_mem_global_free(glob->mem_glob, bo->acc_size);
kfree(vmw_bo);
}
@@ -813,18 +825,10 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv,
static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo)
{
struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo);
- struct vmw_dma_buffer *vmw_bo = &vmw_user_bo->dma;
struct ttm_bo_global *glob = bo->glob;
- struct vmw_private *dev_priv =
- container_of(bo->bdev, struct vmw_private, bdev);
+ vmw_dmabuf_gmr_unbind(bo);
ttm_mem_global_free(glob->mem_glob, bo->acc_size);
- if (vmw_bo->gmr_bound) {
- vmw_gmr_unbind(dev_priv, vmw_bo->gmr_id);
- spin_lock(&glob->lru_lock);
- ida_remove(&dev_priv->gmr_ida, vmw_bo->gmr_id);
- spin_unlock(&glob->lru_lock);
- }
kfree(vmw_user_bo);
}
@@ -868,7 +872,7 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
}
ret = vmw_dmabuf_init(dev_priv, &vmw_user_bo->dma, req->size,
- &vmw_vram_placement, true,
+ &vmw_vram_sys_placement, true,
&vmw_user_dmabuf_destroy);
if (unlikely(ret != 0))
return ret;
diff --git a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig
index 790e675b13eb..61ab4daf0bbb 100644
--- a/drivers/gpu/vga/Kconfig
+++ b/drivers/gpu/vga/Kconfig
@@ -8,3 +8,22 @@ config VGA_ARB
are accessed at same time they need some kind of coordination. Please
see Documentation/vgaarbiter.txt for more details. Select this to
enable VGA arbiter.
+
+config VGA_ARB_MAX_GPUS
+ int "Maximum number of GPUs"
+ default 16
+ depends on VGA_ARB
+ help
+ Reserves space in the kernel to maintain resource locking for
+ multiple GPUS. The overhead for each GPU is very small.
+
+config VGA_SWITCHEROO
+ bool "Laptop Hybrid Grapics - GPU switching support"
+ depends on X86
+ depends on ACPI
+ help
+ Many laptops released in 2008/9/10 have two gpus with a multiplxer
+ to switch between them. This adds support for dynamic switching when
+ X isn't running and delayed switching until the next logoff. This
+ features is called hybrid graphics, ATI PowerXpress, and Nvidia
+ HybridPower.
diff --git a/drivers/gpu/vga/Makefile b/drivers/gpu/vga/Makefile
index 7cc8c1ed645b..14ca30b75d0a 100644
--- a/drivers/gpu/vga/Makefile
+++ b/drivers/gpu/vga/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_VGA_ARB) += vgaarb.o
+obj-$(CONFIG_VGA_SWITCHEROO) += vga_switcheroo.o
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
new file mode 100644
index 000000000000..d6d1149d525d
--- /dev/null
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2010 Red Hat Inc.
+ * Author : Dave Airlie <airlied@redhat.com>
+ *
+ *
+ * Licensed under GPLv2
+ *
+ * vga_switcheroo.c - Support for laptop with dual GPU using one set of outputs
+
+ Switcher interface - methods require for ATPX and DCM
+ - switchto - this throws the output MUX switch
+ - discrete_set_power - sets the power state for the discrete card
+
+ GPU driver interface
+ - set_gpu_state - this should do the equiv of s/r for the card
+ - this should *not* set the discrete power state
+ - switch_check - check if the device is in a position to switch now
+ */
+
+#include <linux/module.h>
+#include <linux/dmi.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/fb.h>
+
+#include <linux/pci.h>
+#include <linux/vga_switcheroo.h>
+
+struct vga_switcheroo_client {
+ struct pci_dev *pdev;
+ struct fb_info *fb_info;
+ int pwr_state;
+ void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state);
+ bool (*can_switch)(struct pci_dev *pdev);
+ int id;
+ bool active;
+};
+
+static DEFINE_MUTEX(vgasr_mutex);
+
+struct vgasr_priv {
+
+ bool active;
+ bool delayed_switch_active;
+ enum vga_switcheroo_client_id delayed_client_id;
+
+ struct dentry *debugfs_root;
+ struct dentry *switch_file;
+
+ int registered_clients;
+ struct vga_switcheroo_client clients[VGA_SWITCHEROO_MAX_CLIENTS];
+
+ struct vga_switcheroo_handler *handler;
+};
+
+static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv);
+static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
+
+/* only one switcheroo per system */
+static struct vgasr_priv vgasr_priv;
+
+int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
+{
+ mutex_lock(&vgasr_mutex);
+ if (vgasr_priv.handler) {
+ mutex_unlock(&vgasr_mutex);
+ return -EINVAL;
+ }
+
+ vgasr_priv.handler = handler;
+ mutex_unlock(&vgasr_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(vga_switcheroo_register_handler);
+
+void vga_switcheroo_unregister_handler(void)
+{
+ mutex_lock(&vgasr_mutex);
+ vgasr_priv.handler = NULL;
+ mutex_unlock(&vgasr_mutex);
+}
+EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
+
+static void vga_switcheroo_enable(void)
+{
+ int i;
+ int ret;
+ /* call the handler to init */
+ vgasr_priv.handler->init();
+
+ for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
+ ret = vgasr_priv.handler->get_client_id(vgasr_priv.clients[i].pdev);
+ if (ret < 0)
+ return;
+
+ vgasr_priv.clients[i].id = ret;
+ }
+ vga_switcheroo_debugfs_init(&vgasr_priv);
+ vgasr_priv.active = true;
+}
+
+int vga_switcheroo_register_client(struct pci_dev *pdev,
+ void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state),
+ bool (*can_switch)(struct pci_dev *pdev))
+{
+ int index;
+
+ mutex_lock(&vgasr_mutex);
+ /* don't do IGD vs DIS here */
+ if (vgasr_priv.registered_clients & 1)
+ index = 1;
+ else
+ index = 0;
+
+ vgasr_priv.clients[index].pwr_state = VGA_SWITCHEROO_ON;
+ vgasr_priv.clients[index].pdev = pdev;
+ vgasr_priv.clients[index].set_gpu_state = set_gpu_state;
+ vgasr_priv.clients[index].can_switch = can_switch;
+ vgasr_priv.clients[index].id = -1;
+ if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
+ vgasr_priv.clients[index].active = true;
+
+ vgasr_priv.registered_clients |= (1 << index);
+
+ /* if we get two clients + handler */
+ if (vgasr_priv.registered_clients == 0x3 && vgasr_priv.handler) {
+ printk(KERN_INFO "vga_switcheroo: enabled\n");
+ vga_switcheroo_enable();
+ }
+ mutex_unlock(&vgasr_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(vga_switcheroo_register_client);
+
+void vga_switcheroo_unregister_client(struct pci_dev *pdev)
+{
+ int i;
+
+ mutex_lock(&vgasr_mutex);
+ for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
+ if (vgasr_priv.clients[i].pdev == pdev) {
+ vgasr_priv.registered_clients &= ~(1 << i);
+ break;
+ }
+ }
+
+ printk(KERN_INFO "vga_switcheroo: disabled\n");
+ vga_switcheroo_debugfs_fini(&vgasr_priv);
+ vgasr_priv.active = false;
+ mutex_unlock(&vgasr_mutex);
+}
+EXPORT_SYMBOL(vga_switcheroo_unregister_client);
+
+void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
+ struct fb_info *info)
+{
+ int i;
+
+ mutex_lock(&vgasr_mutex);
+ for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
+ if (vgasr_priv.clients[i].pdev == pdev) {
+ vgasr_priv.clients[i].fb_info = info;
+ break;
+ }
+ }
+ mutex_unlock(&vgasr_mutex);
+}
+EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
+
+static int vga_switcheroo_show(struct seq_file *m, void *v)
+{
+ int i;
+ mutex_lock(&vgasr_mutex);
+ for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
+ seq_printf(m, "%d:%c:%s:%s\n", i,
+ vgasr_priv.clients[i].active ? '+' : ' ',
+ vgasr_priv.clients[i].pwr_state ? "Pwr" : "Off",
+ pci_name(vgasr_priv.clients[i].pdev));
+ }
+ mutex_unlock(&vgasr_mutex);
+ return 0;
+}
+
+static int vga_switcheroo_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, vga_switcheroo_show, NULL);
+}
+
+static int vga_switchon(struct vga_switcheroo_client *client)
+{
+ int ret;
+
+ ret = vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON);
+ /* call the driver callback to turn on device */
+ client->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON);
+ client->pwr_state = VGA_SWITCHEROO_ON;
+ return 0;
+}
+
+static int vga_switchoff(struct vga_switcheroo_client *client)
+{
+ /* call the driver callback to turn off device */
+ client->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF);
+ vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF);
+ client->pwr_state = VGA_SWITCHEROO_OFF;
+ return 0;
+}
+
+static int vga_switchto(struct vga_switcheroo_client *new_client)
+{
+ int ret;
+ int i;
+ struct vga_switcheroo_client *active = NULL;
+
+ if (new_client->active == true)
+ return 0;
+
+ for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
+ if (vgasr_priv.clients[i].active == true) {
+ active = &vgasr_priv.clients[i];
+ break;
+ }
+ }
+ if (!active)
+ return 0;
+
+ /* power up the first device */
+ ret = pci_enable_device(new_client->pdev);
+ if (ret)
+ return ret;
+
+ if (new_client->pwr_state == VGA_SWITCHEROO_OFF)
+ vga_switchon(new_client);
+
+ /* swap shadow resource to denote boot VGA device has changed so X starts on new device */
+ active->active = false;
+
+ active->pdev->resource[PCI_ROM_RESOURCE].flags &= ~IORESOURCE_ROM_SHADOW;
+ new_client->pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+
+ if (new_client->fb_info) {
+ struct fb_event event;
+ event.info = new_client->fb_info;
+ fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event);
+ }
+
+ ret = vgasr_priv.handler->switchto(new_client->id);
+ if (ret)
+ return ret;
+
+ if (active->pwr_state == VGA_SWITCHEROO_ON)
+ vga_switchoff(active);
+
+ new_client->active = true;
+ return 0;
+}
+
+static ssize_t
+vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ char usercmd[64];
+ const char *pdev_name;
+ int i, ret;
+ bool delay = false, can_switch;
+ int client_id = -1;
+ struct vga_switcheroo_client *client = NULL;
+
+ if (cnt > 63)
+ cnt = 63;
+
+ if (copy_from_user(usercmd, ubuf, cnt))
+ return -EFAULT;
+
+ mutex_lock(&vgasr_mutex);
+
+ if (!vgasr_priv.active)
+ return -EINVAL;
+
+ /* pwr off the device not in use */
+ if (strncmp(usercmd, "OFF", 3) == 0) {
+ for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
+ if (vgasr_priv.clients[i].active)
+ continue;
+ if (vgasr_priv.clients[i].pwr_state == VGA_SWITCHEROO_ON)
+ vga_switchoff(&vgasr_priv.clients[i]);
+ }
+ goto out;
+ }
+ /* pwr on the device not in use */
+ if (strncmp(usercmd, "ON", 2) == 0) {
+ for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
+ if (vgasr_priv.clients[i].active)
+ continue;
+ if (vgasr_priv.clients[i].pwr_state == VGA_SWITCHEROO_OFF)
+ vga_switchon(&vgasr_priv.clients[i]);
+ }
+ goto out;
+ }
+
+ /* request a delayed switch - test can we switch now */
+ if (strncmp(usercmd, "DIGD", 4) == 0) {
+ client_id = VGA_SWITCHEROO_IGD;
+ delay = true;
+ }
+
+ if (strncmp(usercmd, "DDIS", 4) == 0) {
+ client_id = VGA_SWITCHEROO_DIS;
+ delay = true;
+ }
+
+ if (strncmp(usercmd, "IGD", 3) == 0)
+ client_id = VGA_SWITCHEROO_IGD;
+
+ if (strncmp(usercmd, "DIS", 3) == 0)
+ client_id = VGA_SWITCHEROO_DIS;
+
+ if (client_id == -1)
+ goto out;
+
+ for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
+ if (vgasr_priv.clients[i].id == client_id) {
+ client = &vgasr_priv.clients[i];
+ break;
+ }
+ }
+
+ vgasr_priv.delayed_switch_active = false;
+ /* okay we want a switch - test if devices are willing to switch */
+ can_switch = true;
+ for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
+ can_switch = vgasr_priv.clients[i].can_switch(vgasr_priv.clients[i].pdev);
+ if (can_switch == false) {
+ printk(KERN_ERR "vga_switcheroo: client %d refused switch\n", i);
+ break;
+ }
+ }
+
+ if (can_switch == false && delay == false)
+ goto out;
+
+ if (can_switch == true) {
+ pdev_name = pci_name(client->pdev);
+ ret = vga_switchto(client);
+ if (ret)
+ printk(KERN_ERR "vga_switcheroo: switching failed %d\n", ret);
+ } else {
+ printk(KERN_INFO "vga_switcheroo: setting delayed switch to client %d\n", client->id);
+ vgasr_priv.delayed_switch_active = true;
+ vgasr_priv.delayed_client_id = client_id;
+
+ /* we should at least power up the card to
+ make the switch faster */
+ if (client->pwr_state == VGA_SWITCHEROO_OFF)
+ vga_switchon(client);
+ }
+
+out:
+ mutex_unlock(&vgasr_mutex);
+ return cnt;
+}
+
+static const struct file_operations vga_switcheroo_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = vga_switcheroo_debugfs_open,
+ .write = vga_switcheroo_debugfs_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv)
+{
+ if (priv->switch_file) {
+ debugfs_remove(priv->switch_file);
+ priv->switch_file = NULL;
+ }
+ if (priv->debugfs_root) {
+ debugfs_remove(priv->debugfs_root);
+ priv->debugfs_root = NULL;
+ }
+}
+
+static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv)
+{
+ /* already initialised */
+ if (priv->debugfs_root)
+ return 0;
+ priv->debugfs_root = debugfs_create_dir("vgaswitcheroo", NULL);
+
+ if (!priv->debugfs_root) {
+ printk(KERN_ERR "vga_switcheroo: Cannot create /sys/kernel/debug/vgaswitcheroo\n");
+ goto fail;
+ }
+
+ priv->switch_file = debugfs_create_file("switch", 0644,
+ priv->debugfs_root, NULL, &vga_switcheroo_debugfs_fops);
+ if (!priv->switch_file) {
+ printk(KERN_ERR "vga_switcheroo: cannot create /sys/kernel/debug/vgaswitcheroo/switch\n");
+ goto fail;
+ }
+ return 0;
+fail:
+ vga_switcheroo_debugfs_fini(priv);
+ return -1;
+}
+
+int vga_switcheroo_process_delayed_switch(void)
+{
+ struct vga_switcheroo_client *client = NULL;
+ const char *pdev_name;
+ bool can_switch = true;
+ int i;
+ int ret;
+ int err = -EINVAL;
+
+ mutex_lock(&vgasr_mutex);
+ if (!vgasr_priv.delayed_switch_active)
+ goto err;
+
+ printk(KERN_INFO "vga_switcheroo: processing delayed switch to %d\n", vgasr_priv.delayed_client_id);
+
+ for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
+ if (vgasr_priv.clients[i].id == vgasr_priv.delayed_client_id)
+ client = &vgasr_priv.clients[i];
+ can_switch = vgasr_priv.clients[i].can_switch(vgasr_priv.clients[i].pdev);
+ if (can_switch == false) {
+ printk(KERN_ERR "vga_switcheroo: client %d refused switch\n", i);
+ break;
+ }
+ }
+
+ if (can_switch == false || client == NULL)
+ goto err;
+
+ pdev_name = pci_name(client->pdev);
+ ret = vga_switchto(client);
+ if (ret)
+ printk(KERN_ERR "vga_switcheroo: delayed switching failed %d\n", ret);
+
+ vgasr_priv.delayed_switch_active = false;
+ err = 0;
+err:
+ mutex_unlock(&vgasr_mutex);
+ return err;
+}
+EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch);
+
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index 1ac0c93603c9..8827814d0735 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -688,7 +688,7 @@ EXPORT_SYMBOL(vga_client_register);
* the arbiter.
*/
-#define MAX_USER_CARDS 16
+#define MAX_USER_CARDS CONFIG_VGA_ARB_MAX_GPUS
#define PCI_INVALID_CARD ((struct pci_dev *)-1UL)
/*
@@ -954,6 +954,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
}
} else if (strncmp(curr_pos, "target ", 7) == 0) {
+ struct pci_bus *pbus;
unsigned int domain, bus, devfn;
struct vga_device *vgadev;
@@ -961,7 +962,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
remaining -= 7;
pr_devel("client 0x%p called 'target'\n", priv);
/* if target is default */
- if (!strncmp(buf, "default", 7))
+ if (!strncmp(curr_pos, "default", 7))
pdev = pci_dev_get(vga_default_device());
else {
if (!vga_pci_str_to_vars(curr_pos, remaining,
@@ -969,18 +970,31 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
ret_val = -EPROTO;
goto done;
}
-
- pdev = pci_get_bus_and_slot(bus, devfn);
+ pr_devel("vgaarb: %s ==> %x:%x:%x.%x\n", curr_pos,
+ domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+ pbus = pci_find_bus(domain, bus);
+ pr_devel("vgaarb: pbus %p\n", pbus);
+ if (pbus == NULL) {
+ pr_err("vgaarb: invalid PCI domain and/or bus address %x:%x\n",
+ domain, bus);
+ ret_val = -ENODEV;
+ goto done;
+ }
+ pdev = pci_get_slot(pbus, devfn);
+ pr_devel("vgaarb: pdev %p\n", pdev);
if (!pdev) {
- pr_info("vgaarb: invalid PCI address!\n");
+ pr_err("vgaarb: invalid PCI address %x:%x\n",
+ bus, devfn);
ret_val = -ENODEV;
goto done;
}
}
vgadev = vgadev_find(pdev);
+ pr_devel("vgaarb: vgadev %p\n", vgadev);
if (vgadev == NULL) {
- pr_info("vgaarb: this pci device is not a vga device\n");
+ pr_err("vgaarb: this pci device is not a vga device\n");
pci_dev_put(pdev);
ret_val = -ENODEV;
goto done;
@@ -998,7 +1012,8 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
}
}
if (i == MAX_USER_CARDS) {
- pr_err("vgaarb: maximum user cards number reached!\n");
+ pr_err("vgaarb: maximum user cards (%d) number reached!\n",
+ MAX_USER_CARDS);
pci_dev_put(pdev);
/* XXX: which value to return? */
ret_val = -ENOMEM;
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 24d90ea246ce..71d4c0703629 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -55,6 +55,12 @@ source "drivers/hid/usbhid/Kconfig"
menu "Special HID drivers"
depends on HID
+config HID_3M_PCT
+ tristate "3M PCT"
+ depends on USB_HID
+ ---help---
+ Support for 3M PCT touch screens.
+
config HID_A4TECH
tristate "A4 tech" if EMBEDDED
depends on USB_HID
@@ -183,6 +189,23 @@ config LOGIRUMBLEPAD2_FF
Say Y here if you want to enable force feedback support for Logitech
Rumblepad 2 devices.
+config LOGIG940_FF
+ bool "Logitech Flight System G940 force feedback support"
+ depends on HID_LOGITECH
+ select INPUT_FF_MEMLESS
+ help
+ Say Y here if you want to enable force feedback support for Logitech
+ Flight System G940 devices.
+
+config HID_MAGICMOUSE
+ tristate "Apple MagicMouse multi-touch support"
+ depends on BT_HIDP
+ ---help---
+ Support for the Apple Magic Mouse multi-touch.
+
+ Say Y here if you want support for the multi-touch features of the
+ Apple Wireless "Magic" Mouse.
+
config HID_MICROSOFT
tristate "Microsoft" if EMBEDDED
depends on USB_HID
@@ -190,6 +213,12 @@ config HID_MICROSOFT
---help---
Support for Microsoft devices that are not fully compliant with HID standard.
+config HID_MOSART
+ tristate "MosArt"
+ depends on USB_HID
+ ---help---
+ Support for MosArt dual-touch panels.
+
config HID_MONTEREY
tristate "Monterey" if EMBEDDED
depends on USB_HID
@@ -198,12 +227,18 @@ config HID_MONTEREY
Support for Monterey Genius KB29E.
config HID_NTRIG
- tristate "NTrig" if EMBEDDED
+ tristate "NTrig"
depends on USB_HID
- default !EMBEDDED
---help---
Support for N-Trig touch screen.
+config HID_ORTEK
+ tristate "Ortek" if EMBEDDED
+ depends on USB_HID
+ default !EMBEDDED
+ ---help---
+ Support for Ortek WKB-2000 wireless keyboard + mouse trackpad.
+
config HID_PANTHERLORD
tristate "Pantherlord support" if EMBEDDED
depends on USB_HID
@@ -227,6 +262,12 @@ config HID_PETALYNX
---help---
Support for Petalynx Maxter remote control.
+config HID_QUANTA
+ tristate "Quanta Optical Touch"
+ depends on USB_HID
+ ---help---
+ Support for Quanta Optical Touch dual-touch panels.
+
config HID_SAMSUNG
tristate "Samsung" if EMBEDDED
depends on USB_HID
@@ -241,6 +282,12 @@ config HID_SONY
---help---
Support for Sony PS3 controller.
+config HID_STANTUM
+ tristate "Stantum"
+ depends on USB_HID
+ ---help---
+ Support for Stantum multitouch panel.
+
config HID_SUNPLUS
tristate "Sunplus" if EMBEDDED
depends on USB_HID
@@ -305,9 +352,8 @@ config THRUSTMASTER_FF
Rumble Force or Force Feedback Wheel.
config HID_WACOM
- tristate "Wacom Bluetooth devices support" if EMBEDDED
+ tristate "Wacom Bluetooth devices support"
depends on BT_HIDP
- default !EMBEDDED
---help---
Support for Wacom Graphire Bluetooth tablet.
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 0de2dff5542c..0b2618f092ca 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -18,7 +18,11 @@ endif
ifdef CONFIG_LOGIRUMBLEPAD2_FF
hid-logitech-objs += hid-lg2ff.o
endif
+ifdef CONFIG_LOGIG940_FF
+ hid-logitech-objs += hid-lg3ff.o
+endif
+obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
@@ -31,14 +35,19 @@ obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o
obj-$(CONFIG_HID_KYE) += hid-kye.o
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
+obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
+obj-$(CONFIG_HID_MOSART) += hid-mosart.o
obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
+obj-$(CONFIG_HID_ORTEK) += hid-ortek.o
+obj-$(CONFIG_HID_QUANTA) += hid-quanta.o
obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
obj-$(CONFIG_HID_SONY) += hid-sony.o
+obj-$(CONFIG_HID_STANTUM) += hid-stantum.o
obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o
obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o
obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c
new file mode 100644
index 000000000000..2370aefc86b2
--- /dev/null
+++ b/drivers/hid/hid-3m-pct.c
@@ -0,0 +1,290 @@
+/*
+ * HID driver for 3M PCT multitouch panels
+ *
+ * Copyright (c) 2009 Stephane Chatty <chatty@enac.fr>
+ *
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_DESCRIPTION("3M PCT multitouch panels");
+MODULE_LICENSE("GPL");
+
+#include "hid-ids.h"
+
+struct mmm_finger {
+ __s32 x, y;
+ __u8 rank;
+ bool touch, valid;
+};
+
+struct mmm_data {
+ struct mmm_finger f[10];
+ __u8 curid, num;
+ bool touch, valid;
+};
+
+static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ switch (usage->hid & HID_USAGE_PAGE) {
+
+ case HID_UP_BUTTON:
+ return -1;
+
+ case HID_UP_GENDESK:
+ switch (usage->hid) {
+ case HID_GD_X:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_X);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_X,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ case HID_GD_Y:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_Y);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_Y,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ }
+ return 0;
+
+ case HID_UP_DIGITIZER:
+ switch (usage->hid) {
+ /* we do not want to map these: no input-oriented meaning */
+ case 0x14:
+ case 0x23:
+ case HID_DG_INPUTMODE:
+ case HID_DG_DEVICEINDEX:
+ case HID_DG_CONTACTCOUNT:
+ case HID_DG_CONTACTMAX:
+ case HID_DG_INRANGE:
+ case HID_DG_CONFIDENCE:
+ return -1;
+ case HID_DG_TIPSWITCH:
+ /* touchscreen emulation */
+ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+ return 1;
+ case HID_DG_CONTACTID:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TRACKING_ID);
+ return 1;
+ }
+ /* let hid-input decide for the others */
+ return 0;
+
+ case 0xff000000:
+ /* we do not want to map these: no input-oriented meaning */
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (usage->type == EV_KEY || usage->type == EV_ABS)
+ clear_bit(usage->code, *bit);
+
+ return 0;
+}
+
+/*
+ * this function is called when a whole packet has been received and processed,
+ * so that it can decide what to send to the input layer.
+ */
+static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
+{
+ struct mmm_finger *oldest = 0;
+ bool pressed = false, released = false;
+ int i;
+
+ /*
+ * we need to iterate on all fingers to decide if we have a press
+ * or a release event in our touchscreen emulation.
+ */
+ for (i = 0; i < 10; ++i) {
+ struct mmm_finger *f = &md->f[i];
+ if (!f->valid) {
+ /* this finger is just placeholder data, ignore */
+ } else if (f->touch) {
+ /* this finger is on the screen */
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i);
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
+ input_mt_sync(input);
+ /*
+ * touchscreen emulation: maintain the age rank
+ * of this finger, decide if we have a press
+ */
+ if (f->rank == 0) {
+ f->rank = ++(md->num);
+ if (f->rank == 1)
+ pressed = true;
+ }
+ if (f->rank == 1)
+ oldest = f;
+ } else {
+ /* this finger took off the screen */
+ /* touchscreen emulation: maintain age rank of others */
+ int j;
+
+ for (j = 0; j < 10; ++j) {
+ struct mmm_finger *g = &md->f[j];
+ if (g->rank > f->rank) {
+ g->rank--;
+ if (g->rank == 1)
+ oldest = g;
+ }
+ }
+ f->rank = 0;
+ --(md->num);
+ if (md->num == 0)
+ released = true;
+ }
+ f->valid = 0;
+ }
+
+ /* touchscreen emulation */
+ if (oldest) {
+ if (pressed)
+ input_event(input, EV_KEY, BTN_TOUCH, 1);
+ input_event(input, EV_ABS, ABS_X, oldest->x);
+ input_event(input, EV_ABS, ABS_Y, oldest->y);
+ } else if (released) {
+ input_event(input, EV_KEY, BTN_TOUCH, 0);
+ }
+}
+
+/*
+ * this function is called upon all reports
+ * so that we can accumulate contact point information,
+ * and call input_mt_sync after each point.
+ */
+static int mmm_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct mmm_data *md = hid_get_drvdata(hid);
+ /*
+ * strangely, this function can be called before
+ * field->hidinput is initialized!
+ */
+ if (hid->claimed & HID_CLAIMED_INPUT) {
+ struct input_dev *input = field->hidinput->input;
+ switch (usage->hid) {
+ case HID_DG_TIPSWITCH:
+ md->touch = value;
+ break;
+ case HID_DG_CONFIDENCE:
+ md->valid = value;
+ break;
+ case HID_DG_CONTACTID:
+ if (md->valid) {
+ md->curid = value;
+ md->f[value].touch = md->touch;
+ md->f[value].valid = 1;
+ }
+ break;
+ case HID_GD_X:
+ if (md->valid)
+ md->f[md->curid].x = value;
+ break;
+ case HID_GD_Y:
+ if (md->valid)
+ md->f[md->curid].y = value;
+ break;
+ case HID_DG_CONTACTCOUNT:
+ mmm_filter_event(md, input);
+ break;
+ }
+ }
+
+ /* we have handled the hidinput part, now remains hiddev */
+ if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
+
+ return 1;
+}
+
+static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+ struct mmm_data *md;
+
+ md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL);
+ if (!md) {
+ dev_err(&hdev->dev, "cannot allocate 3M data\n");
+ return -ENOMEM;
+ }
+ hid_set_drvdata(hdev, md);
+
+ ret = hid_parse(hdev);
+ if (!ret)
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+ if (ret)
+ kfree(md);
+ return ret;
+}
+
+static void mmm_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+ hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id mmm_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, mmm_devices);
+
+static const struct hid_usage_id mmm_grabbed_usages[] = {
+ { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
+static struct hid_driver mmm_driver = {
+ .name = "3m-pct",
+ .id_table = mmm_devices,
+ .probe = mmm_probe,
+ .remove = mmm_remove,
+ .input_mapping = mmm_input_mapping,
+ .input_mapped = mmm_input_mapped,
+ .usage_table = mmm_grabbed_usages,
+ .event = mmm_event,
+};
+
+static int __init mmm_init(void)
+{
+ return hid_register_driver(&mmm_driver);
+}
+
+static void __exit mmm_exit(void)
+{
+ hid_unregister_driver(&mmm_driver);
+}
+
+module_init(mmm_init);
+module_exit(mmm_exit);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 5b4d66dc1a05..78286b184ace 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -40,6 +40,11 @@ module_param(fnmode, uint, 0644);
MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
"[1] = fkeyslast, 2 = fkeysfirst)");
+static unsigned int iso_layout = 1;
+module_param(iso_layout, uint, 0644);
+MODULE_PARM_DESC(iso_layout, "Enable/Disable hardcoded ISO-layout of the keyboard. "
+ "(0 = disabled, [1] = enabled)");
+
struct apple_sc {
unsigned long quirks;
unsigned int fn_on;
@@ -199,11 +204,13 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
}
}
- if (asc->quirks & APPLE_ISO_KEYBOARD) {
- trans = apple_find_translation(apple_iso_keyboard, usage->code);
- if (trans) {
- input_event(input, usage->type, trans->to, value);
- return 1;
+ if (iso_layout) {
+ if (asc->quirks & APPLE_ISO_KEYBOARD) {
+ trans = apple_find_translation(apple_iso_keyboard, usage->code);
+ if (trans) {
+ input_event(input, usage->type, trans->to, value);
+ return 1;
+ }
}
}
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index eabe5f87c6c1..368fbb0c4ca6 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -4,7 +4,7 @@
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2006-2010 Jiri Kosina
*/
/*
@@ -51,7 +51,7 @@ EXPORT_SYMBOL_GPL(hid_debug);
* Register a new report for a device.
*/
-static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
+struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
{
struct hid_report_enum *report_enum = device->report_enum + type;
struct hid_report *report;
@@ -75,6 +75,7 @@ static struct hid_report *hid_register_report(struct hid_device *device, unsigne
return report;
}
+EXPORT_SYMBOL_GPL(hid_register_report);
/*
* Register a new field for this report.
@@ -387,7 +388,8 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
__u32 data;
unsigned n;
- if (item->size == 0) {
+ /* Local delimiter could have value 0, which allows size to be 0 */
+ if (item->size == 0 && item->tag != HID_LOCAL_ITEM_TAG_DELIMITER) {
dbg_hid("item data expected for local item\n");
return -1;
}
@@ -1248,11 +1250,13 @@ EXPORT_SYMBOL_GPL(hid_disconnect);
/* a list of devices for which there is a specialized driver on HID bus */
static const struct hid_device_id hid_blacklist[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
@@ -1324,6 +1328,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
@@ -1337,10 +1342,15 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
@@ -1543,8 +1553,9 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)},
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2)},
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)},
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
{ HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
@@ -1661,8 +1672,6 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
- { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 6abd0369aedb..cd4ece6fdfb9 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -864,13 +864,13 @@ static const char **names[EV_MAX + 1] = {
[EV_SND] = sounds, [EV_REP] = repeats,
};
-void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f) {
-
+static void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f)
+{
seq_printf(f, "%s.%s", events[type] ? events[type] : "?",
names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
}
-void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f)
+static void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f)
{
int i, j, k;
struct hid_report *report;
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 010368e649ed..72c05f90553c 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -18,6 +18,9 @@
#ifndef HID_IDS_H_FILE
#define HID_IDS_H_FILE
+#define USB_VENDOR_ID_3M 0x0596
+#define USB_DEVICE_ID_3M1968 0x0500
+
#define USB_VENDOR_ID_A4TECH 0x09da
#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
#define USB_DEVICE_ID_A4TECH_X5_005D 0x000a
@@ -56,6 +59,7 @@
#define USB_VENDOR_ID_APPLE 0x05ac
#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
+#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
@@ -96,9 +100,12 @@
#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241
#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
-#define USB_VENDOR_ID_ASUS 0x0b05
-#define USB_DEVICE_ID_ASUS_LCM 0x1726
-#define USB_DEVICE_ID_ASUS_LCM2 0x175b
+#define USB_VENDOR_ID_ASUS 0x0486
+#define USB_DEVICE_ID_ASUS_T91MT 0x0185
+
+#define USB_VENDOR_ID_ASUSTEK 0x0b05
+#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726
+#define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b
#define USB_VENDOR_ID_ATEN 0x0557
#define USB_DEVICE_ID_ATEN_UC100KM 0x2004
@@ -169,6 +176,9 @@
#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
+#define USB_VENDOR_ID_ETURBOTOUCH 0x22b9
+#define USB_DEVICE_ID_ETURBOTOUCH 0x0006
+
#define USB_VENDOR_ID_ETT 0x0664
#define USB_DEVICE_ID_TC5UH 0x0309
@@ -303,6 +313,7 @@
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219
#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283
#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286
+#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287
#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
#define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
@@ -365,6 +376,9 @@
#define USB_VENDOR_ID_ONTRAK 0x0a07
#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
+#define USB_VENDOR_ID_ORTEK 0x05a4
+#define USB_DEVICE_ID_ORTEK_WKB2000 0x2000
+
#define USB_VENDOR_ID_PANJIT 0x134c
#define USB_VENDOR_ID_PANTHERLORD 0x0810
@@ -382,9 +396,16 @@
#define USB_VENDOR_ID_POWERCOM 0x0d9f
#define USB_DEVICE_ID_POWERCOM_UPS 0x0002
+#define USB_VENDOR_ID_PRODIGE 0x05af
+#define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062
+
#define USB_VENDOR_ID_SAITEK 0x06a3
#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
+#define USB_VENDOR_ID_QUANTA 0x0408
+#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000
+#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001
+
#define USB_VENDOR_ID_SAMSUNG 0x0419
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
@@ -396,18 +417,20 @@
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST 0x0046
+#define USB_VENDOR_ID_STANTUM 0x1f87
+#define USB_DEVICE_ID_MTP 0x0002
+
#define USB_VENDOR_ID_SUN 0x0430
#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
#define USB_VENDOR_ID_SUNPLUS 0x04fc
#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
-#define USB_VENDOR_ID_TENX 0x1130
-#define USB_DEVICE_ID_TENX_IBUDDY1 0x0001
-#define USB_DEVICE_ID_TENX_IBUDDY2 0x0002
-
#define USB_VENDOR_ID_THRUSTMASTER 0x044f
+#define USB_VENDOR_ID_TOUCHPACK 0x1bfd
+#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688
+
#define USB_VENDOR_ID_TOPMAX 0x0663
#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 5862b0f3b55d..7a0d2e4661a1 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2000-2001 Vojtech Pavlik
- * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2006-2010 Jiri Kosina
*
* HID to Linux Input mapping
*/
@@ -68,22 +68,25 @@ static const struct {
#define map_key_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \
&max, EV_KEY, (c))
-static inline int match_scancode(int code, int scancode)
+static inline int match_scancode(unsigned int code, unsigned int scancode)
{
if (scancode == 0)
return 1;
- return ((code & (HID_USAGE_PAGE | HID_USAGE)) == scancode);
+
+ return (code & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
}
-static inline int match_keycode(int code, int keycode)
+static inline int match_keycode(unsigned int code, unsigned int keycode)
{
if (keycode == 0)
return 1;
- return (code == keycode);
+
+ return code == keycode;
}
static struct hid_usage *hidinput_find_key(struct hid_device *hid,
- int scancode, int keycode)
+ unsigned int scancode,
+ unsigned int keycode)
{
int i, j, k;
struct hid_report *report;
@@ -105,8 +108,8 @@ static struct hid_usage *hidinput_find_key(struct hid_device *hid,
return NULL;
}
-static int hidinput_getkeycode(struct input_dev *dev, int scancode,
- int *keycode)
+static int hidinput_getkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int *keycode)
{
struct hid_device *hid = input_get_drvdata(dev);
struct hid_usage *usage;
@@ -119,16 +122,13 @@ static int hidinput_getkeycode(struct input_dev *dev, int scancode,
return -EINVAL;
}
-static int hidinput_setkeycode(struct input_dev *dev, int scancode,
- int keycode)
+static int hidinput_setkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int keycode)
{
struct hid_device *hid = input_get_drvdata(dev);
struct hid_usage *usage;
int old_keycode;
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
-
usage = hidinput_find_key(hid, scancode, 0);
if (usage) {
old_keycode = usage->code;
@@ -193,12 +193,17 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break;
case HID_UP_BUTTON:
- code = ((usage->hid - 1) & 0xf);
+ code = ((usage->hid - 1) & HID_USAGE);
switch (field->application) {
case HID_GD_MOUSE:
case HID_GD_POINTER: code += 0x110; break;
- case HID_GD_JOYSTICK: code += 0x120; break;
+ case HID_GD_JOYSTICK:
+ if (code <= 0xf)
+ code += BTN_JOYSTICK;
+ else
+ code += BTN_TRIGGER_HAPPY;
+ break;
case HID_GD_GAMEPAD: code += 0x130; break;
default:
switch (field->physical) {
@@ -400,6 +405,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x192: map_key_clear(KEY_CALC); break;
case 0x194: map_key_clear(KEY_FILE); break;
case 0x196: map_key_clear(KEY_WWW); break;
+ case 0x199: map_key_clear(KEY_CHAT); break;
case 0x19c: map_key_clear(KEY_LOGOFF); break;
case 0x19e: map_key_clear(KEY_COFFEE); break;
case 0x1a6: map_key_clear(KEY_HELP); break;
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index 9fcd3d017ab3..3677c9037a11 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -34,6 +34,7 @@
#define LG_FF 0x200
#define LG_FF2 0x400
#define LG_RDESC_REL_ABS 0x800
+#define LG_FF3 0x1000
/*
* Certain Logitech keyboards send in report #3 keys which are far
@@ -266,7 +267,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
- if (quirks & (LG_FF | LG_FF2))
+ if (quirks & (LG_FF | LG_FF2 | LG_FF3))
connect_mask &= ~HID_CONNECT_FF;
ret = hid_hw_start(hdev, connect_mask);
@@ -279,6 +280,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
lgff_init(hdev);
if (quirks & LG_FF2)
lg2ff_init(hdev);
+ if (quirks & LG_FF3)
+ lg3ff_init(hdev);
return 0;
err_free:
@@ -331,6 +334,8 @@ static const struct hid_device_id lg_devices[] = {
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
.driver_data = LG_FF2 },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
+ .driver_data = LG_FF3 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
.driver_data = LG_RDESC_REL_ABS },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
index bf31592eaf79..ce2ac8672624 100644
--- a/drivers/hid/hid-lg.h
+++ b/drivers/hid/hid-lg.h
@@ -13,4 +13,10 @@ int lg2ff_init(struct hid_device *hdev);
static inline int lg2ff_init(struct hid_device *hdev) { return -1; }
#endif
+#ifdef CONFIG_LOGIG940_FF
+int lg3ff_init(struct hid_device *hdev);
+#else
+static inline int lg3ff_init(struct hid_device *hdev) { return -1; }
+#endif
+
#endif
diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c
new file mode 100644
index 000000000000..4002832ee4af
--- /dev/null
+++ b/drivers/hid/hid-lg3ff.c
@@ -0,0 +1,176 @@
+/*
+ * Force feedback support for Logitech Flight System G940
+ *
+ * Copyright (c) 2009 Gary Stein <LordCnidarian@gmail.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+
+#include "usbhid/usbhid.h"
+#include "hid-lg.h"
+
+/*
+ * G940 Theory of Operation (from experimentation)
+ *
+ * There are 63 fields (only 3 of them currently used)
+ * 0 - seems to be command field
+ * 1 - 30 deal with the x axis
+ * 31 -60 deal with the y axis
+ *
+ * Field 1 is x axis constant force
+ * Field 31 is y axis constant force
+ *
+ * other interesting fields 1,2,3,4 on x axis
+ * (same for 31,32,33,34 on y axis)
+ *
+ * 0 0 127 127 makes the joystick autocenter hard
+ *
+ * 127 0 127 127 makes the joystick loose on the right,
+ * but stops all movemnt left
+ *
+ * -127 0 -127 -127 makes the joystick loose on the left,
+ * but stops all movement right
+ *
+ * 0 0 -127 -127 makes the joystick rattle very hard
+ *
+ * I'm sure these are effects that I don't know enough about them
+ */
+
+struct lg3ff_device {
+ struct hid_report *report;
+};
+
+static int hid_lg3ff_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+ int x, y;
+
+/*
+ * Maxusage should always be 63 (maximum fields)
+ * likely a better way to ensure this data is clean
+ */
+ memset(report->field[0]->value, 0, sizeof(__s32)*report->field[0]->maxusage);
+
+ switch (effect->type) {
+ case FF_CONSTANT:
+/*
+ * Already clamped in ff_memless
+ * 0 is center (different then other logitech)
+ */
+ x = effect->u.ramp.start_level;
+ y = effect->u.ramp.end_level;
+
+ /* send command byte */
+ report->field[0]->value[0] = 0x51;
+
+/*
+ * Sign backwards from other Force3d pro
+ * which get recast here in two's complement 8 bits
+ */
+ report->field[0]->value[1] = (unsigned char)(-x);
+ report->field[0]->value[31] = (unsigned char)(-y);
+
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+ break;
+ }
+ return 0;
+}
+static void hid_lg3ff_set_autocenter(struct input_dev *dev, u16 magnitude)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+
+/*
+ * Auto Centering probed from device
+ * NOTE: deadman's switch on G940 must be covered
+ * for effects to work
+ */
+ report->field[0]->value[0] = 0x51;
+ report->field[0]->value[1] = 0x00;
+ report->field[0]->value[2] = 0x00;
+ report->field[0]->value[3] = 0x7F;
+ report->field[0]->value[4] = 0x7F;
+ report->field[0]->value[31] = 0x00;
+ report->field[0]->value[32] = 0x00;
+ report->field[0]->value[33] = 0x7F;
+ report->field[0]->value[34] = 0x7F;
+
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+
+static const signed short ff3_joystick_ac[] = {
+ FF_CONSTANT,
+ FF_AUTOCENTER,
+ -1
+};
+
+int lg3ff_init(struct hid_device *hid)
+{
+ struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+ struct hid_report *report;
+ struct hid_field *field;
+ const signed short *ff_bits = ff3_joystick_ac;
+ int error;
+ int i;
+
+ /* Find the report to use */
+ if (list_empty(report_list)) {
+ err_hid("No output report found");
+ return -1;
+ }
+
+ /* Check that the report looks ok */
+ report = list_entry(report_list->next, struct hid_report, list);
+ if (!report) {
+ err_hid("NULL output report");
+ return -1;
+ }
+
+ field = report->field[0];
+ if (!field) {
+ err_hid("NULL field");
+ return -1;
+ }
+
+ /* Assume single fixed device G940 */
+ for (i = 0; ff_bits[i] >= 0; i++)
+ set_bit(ff_bits[i], dev->ffbit);
+
+ error = input_ff_create_memless(dev, NULL, hid_lg3ff_play);
+ if (error)
+ return error;
+
+ if (test_bit(FF_AUTOCENTER, dev->ffbit))
+ dev->ff->set_autocenter = hid_lg3ff_set_autocenter;
+
+ dev_info(&hid->dev, "Force feedback for Logitech Flight System G940 by "
+ "Gary Stein <LordCnidarian@gmail.com>\n");
+ return 0;
+}
+
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c
index 987abebe0829..61142b76a9b1 100644
--- a/drivers/hid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -67,6 +67,7 @@ static const struct dev_type devices[] = {
{ 0x046d, 0xc219, ff_rumble },
{ 0x046d, 0xc283, ff_joystick },
{ 0x046d, 0xc286, ff_joystick_ac },
+ { 0x046d, 0xc287, ff_joystick_ac },
{ 0x046d, 0xc293, ff_joystick },
{ 0x046d, 0xc294, ff_wheel },
{ 0x046d, 0xc295, ff_joystick },
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
new file mode 100644
index 000000000000..4a3a94f2b10c
--- /dev/null
+++ b/drivers/hid/hid-magicmouse.c
@@ -0,0 +1,449 @@
+/*
+ * Apple "Magic" Wireless Mouse driver
+ *
+ * Copyright (c) 2010 Michael Poole <mdpoole@troilus.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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+static bool emulate_3button = true;
+module_param(emulate_3button, bool, 0644);
+MODULE_PARM_DESC(emulate_3button, "Emulate a middle button");
+
+static int middle_button_start = -350;
+static int middle_button_stop = +350;
+
+static bool emulate_scroll_wheel = true;
+module_param(emulate_scroll_wheel, bool, 0644);
+MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel");
+
+static bool report_touches = true;
+module_param(report_touches, bool, 0644);
+MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)");
+
+static bool report_undeciphered;
+module_param(report_undeciphered, bool, 0644);
+MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event");
+
+#define TOUCH_REPORT_ID 0x29
+/* These definitions are not precise, but they're close enough. (Bits
+ * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem
+ * to be some kind of bit mask -- 0x20 may be a near-field reading,
+ * and 0x40 is actual contact, and 0x10 may be a start/stop or change
+ * indication.)
+ */
+#define TOUCH_STATE_MASK 0xf0
+#define TOUCH_STATE_NONE 0x00
+#define TOUCH_STATE_START 0x30
+#define TOUCH_STATE_DRAG 0x40
+
+/**
+ * struct magicmouse_sc - Tracks Magic Mouse-specific data.
+ * @input: Input device through which we report events.
+ * @quirks: Currently unused.
+ * @last_timestamp: Timestamp from most recent (18-bit) touch report
+ * (units of milliseconds over short windows, but seems to
+ * increase faster when there are no touches).
+ * @delta_time: 18-bit difference between the two most recent touch
+ * reports from the mouse.
+ * @ntouches: Number of touches in most recent touch report.
+ * @scroll_accel: Number of consecutive scroll motions.
+ * @scroll_jiffies: Time of last scroll motion.
+ * @touches: Most recent data for a touch, indexed by tracking ID.
+ * @tracking_ids: Mapping of current touch input data to @touches.
+ */
+struct magicmouse_sc {
+ struct input_dev *input;
+ unsigned long quirks;
+
+ int last_timestamp;
+ int delta_time;
+ int ntouches;
+ int scroll_accel;
+ unsigned long scroll_jiffies;
+
+ struct {
+ short x;
+ short y;
+ short scroll_y;
+ u8 size;
+ } touches[16];
+ int tracking_ids[16];
+};
+
+static int magicmouse_firm_touch(struct magicmouse_sc *msc)
+{
+ int touch = -1;
+ int ii;
+
+ /* If there is only one "firm" touch, set touch to its
+ * tracking ID.
+ */
+ for (ii = 0; ii < msc->ntouches; ii++) {
+ int idx = msc->tracking_ids[ii];
+ if (msc->touches[idx].size < 8) {
+ /* Ignore this touch. */
+ } else if (touch >= 0) {
+ touch = -1;
+ break;
+ } else {
+ touch = idx;
+ }
+ }
+
+ return touch;
+}
+
+static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state)
+{
+ int last_state = test_bit(BTN_LEFT, msc->input->key) << 0 |
+ test_bit(BTN_RIGHT, msc->input->key) << 1 |
+ test_bit(BTN_MIDDLE, msc->input->key) << 2;
+
+ if (emulate_3button) {
+ int id;
+
+ /* If some button was pressed before, keep it held
+ * down. Otherwise, if there's exactly one firm
+ * touch, use that to override the mouse's guess.
+ */
+ if (state == 0) {
+ /* The button was released. */
+ } else if (last_state != 0) {
+ state = last_state;
+ } else if ((id = magicmouse_firm_touch(msc)) >= 0) {
+ int x = msc->touches[id].x;
+ if (x < middle_button_start)
+ state = 1;
+ else if (x > middle_button_stop)
+ state = 2;
+ else
+ state = 4;
+ } /* else: we keep the mouse's guess */
+
+ input_report_key(msc->input, BTN_MIDDLE, state & 4);
+ }
+
+ input_report_key(msc->input, BTN_LEFT, state & 1);
+ input_report_key(msc->input, BTN_RIGHT, state & 2);
+
+ if (state != last_state)
+ msc->scroll_accel = 0;
+}
+
+static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata)
+{
+ struct input_dev *input = msc->input;
+ __s32 x_y = tdata[0] << 8 | tdata[1] << 16 | tdata[2] << 24;
+ int misc = tdata[5] | tdata[6] << 8;
+ int id = (misc >> 6) & 15;
+ int x = x_y << 12 >> 20;
+ int y = -(x_y >> 20);
+
+ /* Store tracking ID and other fields. */
+ msc->tracking_ids[raw_id] = id;
+ msc->touches[id].x = x;
+ msc->touches[id].y = y;
+ msc->touches[id].size = misc & 63;
+
+ /* If requested, emulate a scroll wheel by detecting small
+ * vertical touch motions along the middle of the mouse.
+ */
+ if (emulate_scroll_wheel &&
+ middle_button_start < x && x < middle_button_stop) {
+ static const int accel_profile[] = {
+ 256, 228, 192, 160, 128, 96, 64, 32,
+ };
+ unsigned long now = jiffies;
+ int step = msc->touches[id].scroll_y - y;
+
+ /* Reset acceleration after half a second. */
+ if (time_after(now, msc->scroll_jiffies + HZ / 2))
+ msc->scroll_accel = 0;
+
+ /* Calculate and apply the scroll motion. */
+ switch (tdata[7] & TOUCH_STATE_MASK) {
+ case TOUCH_STATE_START:
+ msc->touches[id].scroll_y = y;
+ msc->scroll_accel = min_t(int, msc->scroll_accel + 1,
+ ARRAY_SIZE(accel_profile) - 1);
+ break;
+ case TOUCH_STATE_DRAG:
+ step = step / accel_profile[msc->scroll_accel];
+ if (step != 0) {
+ msc->touches[id].scroll_y = y;
+ msc->scroll_jiffies = now;
+ input_report_rel(input, REL_WHEEL, step);
+ }
+ break;
+ }
+ }
+
+ /* Generate the input events for this touch. */
+ if (report_touches) {
+ int orientation = (misc >> 10) - 32;
+
+ input_report_abs(input, ABS_MT_TRACKING_ID, id);
+ input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]);
+ input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]);
+ input_report_abs(input, ABS_MT_ORIENTATION, orientation);
+ input_report_abs(input, ABS_MT_POSITION_X, x);
+ input_report_abs(input, ABS_MT_POSITION_Y, y);
+
+ if (report_undeciphered)
+ input_event(input, EV_MSC, MSC_RAW, tdata[7]);
+
+ input_mt_sync(input);
+ }
+}
+
+static int magicmouse_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data, int size)
+{
+ struct magicmouse_sc *msc = hid_get_drvdata(hdev);
+ struct input_dev *input = msc->input;
+ int x, y, ts, ii, clicks;
+
+ switch (data[0]) {
+ case 0x10:
+ if (size != 6)
+ return 0;
+ x = (__s16)(data[2] | data[3] << 8);
+ y = (__s16)(data[4] | data[5] << 8);
+ clicks = data[1];
+ break;
+ case TOUCH_REPORT_ID:
+ /* Expect six bytes of prefix, and N*8 bytes of touch data. */
+ if (size < 6 || ((size - 6) % 8) != 0)
+ return 0;
+ ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
+ msc->delta_time = (ts - msc->last_timestamp) & 0x3ffff;
+ msc->last_timestamp = ts;
+ msc->ntouches = (size - 6) / 8;
+ for (ii = 0; ii < msc->ntouches; ii++)
+ magicmouse_emit_touch(msc, ii, data + ii * 8 + 6);
+ /* When emulating three-button mode, it is important
+ * to have the current touch information before
+ * generating a click event.
+ */
+ x = (signed char)data[1];
+ y = (signed char)data[2];
+ clicks = data[3];
+ break;
+ case 0x20: /* Theoretically battery status (0-100), but I have
+ * never seen it -- maybe it is only upon request.
+ */
+ case 0x60: /* Unknown, maybe laser on/off. */
+ case 0x61: /* Laser reflection status change.
+ * data[1]: 0 = spotted, 1 = lost
+ */
+ default:
+ return 0;
+ }
+
+ magicmouse_emit_buttons(msc, clicks & 3);
+ input_report_rel(input, REL_X, x);
+ input_report_rel(input, REL_Y, y);
+ input_sync(input);
+ return 1;
+}
+
+static int magicmouse_input_open(struct input_dev *dev)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+
+ return hid->ll_driver->open(hid);
+}
+
+static void magicmouse_input_close(struct input_dev *dev)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+
+ hid->ll_driver->close(hid);
+}
+
+static void magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev)
+{
+ input_set_drvdata(input, hdev);
+ input->event = hdev->ll_driver->hidinput_input_event;
+ input->open = magicmouse_input_open;
+ input->close = magicmouse_input_close;
+
+ input->name = hdev->name;
+ input->phys = hdev->phys;
+ input->uniq = hdev->uniq;
+ input->id.bustype = hdev->bus;
+ input->id.vendor = hdev->vendor;
+ input->id.product = hdev->product;
+ input->id.version = hdev->version;
+ input->dev.parent = hdev->dev.parent;
+
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(BTN_LEFT, input->keybit);
+ __set_bit(BTN_RIGHT, input->keybit);
+ if (emulate_3button)
+ __set_bit(BTN_MIDDLE, input->keybit);
+ __set_bit(BTN_TOOL_FINGER, input->keybit);
+
+ __set_bit(EV_REL, input->evbit);
+ __set_bit(REL_X, input->relbit);
+ __set_bit(REL_Y, input->relbit);
+ if (emulate_scroll_wheel)
+ __set_bit(REL_WHEEL, input->relbit);
+
+ if (report_touches) {
+ __set_bit(EV_ABS, input->evbit);
+
+ input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
+ input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 4, 0);
+ input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 4, 0);
+ input_set_abs_params(input, ABS_MT_ORIENTATION, -32, 31, 1, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_X, -1100, 1358,
+ 4, 0);
+ /* Note: Touch Y position from the device is inverted relative
+ * to how pointer motion is reported (and relative to how USB
+ * HID recommends the coordinates work). This driver keeps
+ * the origin at the same position, and just uses the additive
+ * inverse of the reported Y.
+ */
+ input_set_abs_params(input, ABS_MT_POSITION_Y, -1589, 2047,
+ 4, 0);
+ }
+
+ if (report_undeciphered) {
+ __set_bit(EV_MSC, input->evbit);
+ __set_bit(MSC_RAW, input->mscbit);
+ }
+}
+
+static int magicmouse_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ __u8 feature_1[] = { 0xd7, 0x01 };
+ __u8 feature_2[] = { 0xf8, 0x01, 0x32 };
+ struct input_dev *input;
+ struct magicmouse_sc *msc;
+ struct hid_report *report;
+ int ret;
+
+ msc = kzalloc(sizeof(*msc), GFP_KERNEL);
+ if (msc == NULL) {
+ dev_err(&hdev->dev, "can't alloc magicmouse descriptor\n");
+ return -ENOMEM;
+ }
+
+ msc->quirks = id->driver_data;
+ hid_set_drvdata(hdev, msc);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "magicmouse hid parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "magicmouse hw start failed\n");
+ goto err_free;
+ }
+
+ report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID);
+ if (!report) {
+ dev_err(&hdev->dev, "unable to register touch report\n");
+ ret = -ENOMEM;
+ goto err_stop_hw;
+ }
+ report->size = 6;
+
+ ret = hdev->hid_output_raw_report(hdev, feature_1, sizeof(feature_1),
+ HID_FEATURE_REPORT);
+ if (ret != sizeof(feature_1)) {
+ dev_err(&hdev->dev, "unable to request touch data (1:%d)\n",
+ ret);
+ goto err_stop_hw;
+ }
+ ret = hdev->hid_output_raw_report(hdev, feature_2,
+ sizeof(feature_2), HID_FEATURE_REPORT);
+ if (ret != sizeof(feature_2)) {
+ dev_err(&hdev->dev, "unable to request touch data (2:%d)\n",
+ ret);
+ goto err_stop_hw;
+ }
+
+ input = input_allocate_device();
+ if (!input) {
+ dev_err(&hdev->dev, "can't alloc input device\n");
+ ret = -ENOMEM;
+ goto err_stop_hw;
+ }
+ magicmouse_setup_input(input, hdev);
+
+ ret = input_register_device(input);
+ if (ret) {
+ dev_err(&hdev->dev, "input device registration failed\n");
+ goto err_input;
+ }
+ msc->input = input;
+
+ return 0;
+err_input:
+ input_free_device(input);
+err_stop_hw:
+ hid_hw_stop(hdev);
+err_free:
+ kfree(msc);
+ return ret;
+}
+
+static void magicmouse_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id magic_mice[] = {
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE),
+ .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, magic_mice);
+
+static struct hid_driver magicmouse_driver = {
+ .name = "magicmouse",
+ .id_table = magic_mice,
+ .probe = magicmouse_probe,
+ .remove = magicmouse_remove,
+ .raw_event = magicmouse_raw_event,
+};
+
+static int __init magicmouse_init(void)
+{
+ int ret;
+
+ ret = hid_register_driver(&magicmouse_driver);
+ if (ret)
+ printk(KERN_ERR "can't register magicmouse driver\n");
+
+ return ret;
+}
+
+static void __exit magicmouse_exit(void)
+{
+ hid_unregister_driver(&magicmouse_driver);
+}
+
+module_init(magicmouse_init);
+module_exit(magicmouse_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c
new file mode 100644
index 000000000000..c8718168fe42
--- /dev/null
+++ b/drivers/hid/hid-mosart.c
@@ -0,0 +1,273 @@
+/*
+ * HID driver for the multitouch panel on the ASUS EeePC T91MT
+ *
+ * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
+ * Copyright (c) 2010 Teemu Tuominen <teemu.tuominen@cybercom.com>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_DESCRIPTION("MosArt dual-touch panel");
+MODULE_LICENSE("GPL");
+
+#include "hid-ids.h"
+
+struct mosart_data {
+ __u16 x, y;
+ __u8 id;
+ bool valid; /* valid finger data, or just placeholder? */
+ bool first; /* is this the first finger in this frame? */
+ bool activity_now; /* at least one active finger in this frame? */
+ bool activity; /* at least one active finger previously? */
+};
+
+static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ switch (usage->hid & HID_USAGE_PAGE) {
+
+ case HID_UP_GENDESK:
+ switch (usage->hid) {
+ case HID_GD_X:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_X);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_X,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ case HID_GD_Y:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_Y);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_Y,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ }
+ return 0;
+
+ case HID_UP_DIGITIZER:
+ switch (usage->hid) {
+ case HID_DG_CONFIDENCE:
+ case HID_DG_TIPSWITCH:
+ case HID_DG_INPUTMODE:
+ case HID_DG_DEVICEINDEX:
+ case HID_DG_CONTACTCOUNT:
+ case HID_DG_CONTACTMAX:
+ case HID_DG_TIPPRESSURE:
+ case HID_DG_WIDTH:
+ case HID_DG_HEIGHT:
+ return -1;
+ case HID_DG_INRANGE:
+ /* touchscreen emulation */
+ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+ return 1;
+
+ case HID_DG_CONTACTID:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TRACKING_ID);
+ return 1;
+
+ }
+ return 0;
+
+ case 0xff000000:
+ /* ignore HID features */
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (usage->type == EV_KEY || usage->type == EV_ABS)
+ clear_bit(usage->code, *bit);
+
+ return 0;
+}
+
+/*
+ * this function is called when a whole finger has been parsed,
+ * so that it can decide what to send to the input layer.
+ */
+static void mosart_filter_event(struct mosart_data *td, struct input_dev *input)
+{
+ td->first = !td->first; /* touchscreen emulation */
+
+ if (!td->valid) {
+ /*
+ * touchscreen emulation: if no finger in this frame is valid
+ * and there previously was finger activity, this is a release
+ */
+ if (!td->first && !td->activity_now && td->activity) {
+ input_event(input, EV_KEY, BTN_TOUCH, 0);
+ td->activity = false;
+ }
+ return;
+ }
+
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
+
+ input_mt_sync(input);
+ td->valid = false;
+
+ /* touchscreen emulation: if first active finger in this frame... */
+ if (!td->activity_now) {
+ /* if there was no previous activity, emit touch event */
+ if (!td->activity) {
+ input_event(input, EV_KEY, BTN_TOUCH, 1);
+ td->activity = true;
+ }
+ td->activity_now = true;
+ /* and in any case this is our preferred finger */
+ input_event(input, EV_ABS, ABS_X, td->x);
+ input_event(input, EV_ABS, ABS_Y, td->y);
+ }
+}
+
+
+static int mosart_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct mosart_data *td = hid_get_drvdata(hid);
+
+ if (hid->claimed & HID_CLAIMED_INPUT) {
+ struct input_dev *input = field->hidinput->input;
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ td->valid = !!value;
+ break;
+ case HID_GD_X:
+ td->x = value;
+ break;
+ case HID_GD_Y:
+ td->y = value;
+ mosart_filter_event(td, input);
+ break;
+ case HID_DG_CONTACTID:
+ td->id = value;
+ break;
+ case HID_DG_CONTACTCOUNT:
+ /* touch emulation: this is the last field in a frame */
+ td->first = false;
+ td->activity_now = false;
+ break;
+ case HID_DG_CONFIDENCE:
+ case HID_DG_TIPSWITCH:
+ /* avoid interference from generic hidinput handling */
+ break;
+
+ default:
+ /* fallback to the generic hidinput handling */
+ return 0;
+ }
+ }
+
+ /* we have handled the hidinput part, now remains hiddev */
+ if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
+
+ return 1;
+}
+
+static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+ struct mosart_data *td;
+
+
+ td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL);
+ if (!td) {
+ dev_err(&hdev->dev, "cannot allocate MosArt data\n");
+ return -ENOMEM;
+ }
+ td->valid = false;
+ td->activity = false;
+ td->activity_now = false;
+ td->first = false;
+ hid_set_drvdata(hdev, td);
+
+ /* currently, it's better to have one evdev device only */
+#if 0
+ hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+#endif
+
+ ret = hid_parse(hdev);
+ if (ret == 0)
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+ if (ret == 0) {
+ struct hid_report_enum *re = hdev->report_enum
+ + HID_FEATURE_REPORT;
+ struct hid_report *r = re->report_id_hash[7];
+
+ r->field[0]->value[0] = 0x02;
+ usbhid_submit_report(hdev, r, USB_DIR_OUT);
+ } else
+ kfree(td);
+
+ return ret;
+}
+
+static void mosart_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+ hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id mosart_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, mosart_devices);
+
+static const struct hid_usage_id mosart_grabbed_usages[] = {
+ { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
+static struct hid_driver mosart_driver = {
+ .name = "mosart",
+ .id_table = mosart_devices,
+ .probe = mosart_probe,
+ .remove = mosart_remove,
+ .input_mapping = mosart_input_mapping,
+ .input_mapped = mosart_input_mapped,
+ .usage_table = mosart_grabbed_usages,
+ .event = mosart_event,
+};
+
+static int __init mosart_init(void)
+{
+ return hid_register_driver(&mosart_driver);
+}
+
+static void __exit mosart_exit(void)
+{
+ hid_unregister_driver(&mosart_driver);
+}
+
+module_init(mosart_init);
+module_exit(mosart_exit);
+
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 49ce69d7bba7..3234c729a895 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -25,11 +25,16 @@
EV_KEY, (c))
struct ntrig_data {
- __s32 x, y, id, w, h;
- char reading_a_point, found_contact_id;
- char pen_active;
- char finger_active;
- char inverted;
+ /* Incoming raw values for a single contact */
+ __u16 x, y, w, h;
+ __u16 id;
+ __u8 confidence;
+
+ bool reading_mt;
+ __u8 first_contact_confidence;
+
+ __u8 mt_footer[4];
+ __u8 mt_foot_count;
};
/*
@@ -42,8 +47,11 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
- switch (usage->hid & HID_USAGE_PAGE) {
+ /* No special mappings needed for the pen and single touch */
+ if (field->physical)
+ return 0;
+ switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
@@ -66,18 +74,12 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_UP_DIGITIZER:
switch (usage->hid) {
/* we do not want to map these for now */
- case HID_DG_CONTACTID: /* value is useless */
+ case HID_DG_CONTACTID: /* Not trustworthy, squelch for now */
case HID_DG_INPUTMODE:
case HID_DG_DEVICEINDEX:
- case HID_DG_CONTACTCOUNT:
case HID_DG_CONTACTMAX:
return -1;
- /* original mapping by Rafi Rubin */
- case HID_DG_CONFIDENCE:
- nt_map_key_clear(BTN_TOOL_DOUBLETAP);
- return 1;
-
/* width/height mapped on TouchMajor/TouchMinor/Orientation */
case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max,
@@ -104,6 +106,10 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
+ /* No special mappings needed for the pen and single touch */
+ if (field->physical)
+ return 0;
+
if (usage->type == EV_KEY || usage->type == EV_REL
|| usage->type == EV_ABS)
clear_bit(usage->code, *bit);
@@ -123,31 +129,30 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
struct input_dev *input = field->hidinput->input;
struct ntrig_data *nd = hid_get_drvdata(hid);
+ /* No special handling needed for the pen */
+ if (field->application == HID_DG_PEN)
+ return 0;
+
if (hid->claimed & HID_CLAIMED_INPUT) {
switch (usage->hid) {
-
- case HID_DG_INRANGE:
- if (field->application & 0x3)
- nd->pen_active = (value != 0);
- else
- nd->finger_active = (value != 0);
- return 0;
-
- case HID_DG_INVERT:
- nd->inverted = value;
- return 0;
-
+ case 0xff000001:
+ /* Tag indicating the start of a multitouch group */
+ nd->reading_mt = 1;
+ nd->first_contact_confidence = 0;
+ break;
+ case HID_DG_CONFIDENCE:
+ nd->confidence = value;
+ break;
case HID_GD_X:
nd->x = value;
- nd->reading_a_point = 1;
+ /* Clear the contact footer */
+ nd->mt_foot_count = 0;
break;
case HID_GD_Y:
nd->y = value;
break;
case HID_DG_CONTACTID:
nd->id = value;
- /* we receive this only when in multitouch mode */
- nd->found_contact_id = 1;
break;
case HID_DG_WIDTH:
nd->w = value;
@@ -159,35 +164,13 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
* report received in a finger event. We want
* to emit a normal (X, Y) position
*/
- if (!nd->found_contact_id) {
- if (nd->pen_active && nd->finger_active) {
- input_report_key(input, BTN_TOOL_DOUBLETAP, 0);
- input_report_key(input, BTN_TOOL_DOUBLETAP, 1);
- }
+ if (!nd->reading_mt) {
+ input_report_key(input, BTN_TOOL_DOUBLETAP,
+ (nd->confidence != 0));
input_event(input, EV_ABS, ABS_X, nd->x);
input_event(input, EV_ABS, ABS_Y, nd->y);
}
break;
- case HID_DG_TIPPRESSURE:
- /*
- * when in single touch mode, this is the last
- * report received in a pen event. We want
- * to emit a normal (X, Y) position
- */
- if (! nd->found_contact_id) {
- if (nd->pen_active && nd->finger_active) {
- input_report_key(input,
- nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN
- , 0);
- input_report_key(input,
- nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN
- , 1);
- }
- input_event(input, EV_ABS, ABS_X, nd->x);
- input_event(input, EV_ABS, ABS_Y, nd->y);
- input_event(input, EV_ABS, ABS_PRESSURE, value);
- }
- break;
case 0xff000002:
/*
* we receive this when the device is in multitouch
@@ -195,10 +178,34 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
* this usage tells if the contact point is real
* or a placeholder
*/
- if (!nd->reading_a_point || value != 1)
+
+ /* Shouldn't get more than 4 footer packets, so skip */
+ if (nd->mt_foot_count >= 4)
break;
+
+ nd->mt_footer[nd->mt_foot_count++] = value;
+
+ /* if the footer isn't complete break */
+ if (nd->mt_foot_count != 4)
+ break;
+
+ /* Pen activity signal, trigger end of touch. */
+ if (nd->mt_footer[2]) {
+ nd->confidence = 0;
+ break;
+ }
+
+ /* If the contact was invalid */
+ if (!(nd->confidence && nd->mt_footer[0])
+ || nd->w <= 250
+ || nd->h <= 190) {
+ nd->confidence = 0;
+ break;
+ }
+
/* emit a normal (X, Y) for the first point only */
if (nd->id == 0) {
+ nd->first_contact_confidence = nd->confidence;
input_event(input, EV_ABS, ABS_X, nd->x);
input_event(input, EV_ABS, ABS_Y, nd->y);
}
@@ -220,8 +227,39 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
ABS_MT_TOUCH_MINOR, nd->w);
}
input_mt_sync(field->hidinput->input);
- nd->reading_a_point = 0;
- nd->found_contact_id = 0;
+ break;
+
+ case HID_DG_CONTACTCOUNT: /* End of a multitouch group */
+ if (!nd->reading_mt)
+ break;
+
+ nd->reading_mt = 0;
+
+ if (nd->first_contact_confidence) {
+ switch (value) {
+ case 0: /* for single touch devices */
+ case 1:
+ input_report_key(input,
+ BTN_TOOL_DOUBLETAP, 1);
+ break;
+ case 2:
+ input_report_key(input,
+ BTN_TOOL_TRIPLETAP, 1);
+ break;
+ case 3:
+ default:
+ input_report_key(input,
+ BTN_TOOL_QUADTAP, 1);
+ }
+ input_report_key(input, BTN_TOUCH, 1);
+ } else {
+ input_report_key(input,
+ BTN_TOOL_DOUBLETAP, 0);
+ input_report_key(input,
+ BTN_TOOL_TRIPLETAP, 0);
+ input_report_key(input,
+ BTN_TOOL_QUADTAP, 0);
+ }
break;
default:
@@ -231,8 +269,8 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
}
/* we have handled the hidinput part, now remains hiddev */
- if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
- hid->hiddev_hid_event(hid, field, usage, value);
+ if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
return 1;
}
@@ -241,23 +279,67 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
struct ntrig_data *nd;
+ struct hid_input *hidinput;
+ struct input_dev *input;
+
+ if (id->driver_data)
+ hdev->quirks |= HID_QUIRK_MULTI_INPUT;
nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL);
if (!nd) {
dev_err(&hdev->dev, "cannot allocate N-Trig data\n");
return -ENOMEM;
}
- nd->reading_a_point = 0;
- nd->found_contact_id = 0;
+
+ nd->reading_mt = 0;
hid_set_drvdata(hdev, nd);
ret = hid_parse(hdev);
- if (!ret)
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
- if (ret)
- kfree (nd);
+ list_for_each_entry(hidinput, &hdev->inputs, list) {
+ input = hidinput->input;
+ switch (hidinput->report->field[0]->application) {
+ case HID_DG_PEN:
+ input->name = "N-Trig Pen";
+ break;
+ case HID_DG_TOUCHSCREEN:
+ __clear_bit(BTN_TOOL_PEN, input->keybit);
+ /*
+ * A little something special to enable
+ * two and three finger taps.
+ */
+ __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
+ __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
+ __set_bit(BTN_TOOL_QUADTAP, input->keybit);
+ /*
+ * The physical touchscreen (single touch)
+ * input has a value for physical, whereas
+ * the multitouch only has logical input
+ * fields.
+ */
+ input->name =
+ (hidinput->report->field[0]
+ ->physical) ?
+ "N-Trig Touchscreen" :
+ "N-Trig MultiTouch";
+ break;
+ }
+ }
+
+ return 0;
+err_free:
+ kfree(nd);
return ret;
}
@@ -276,7 +358,7 @@ MODULE_DEVICE_TABLE(hid, ntrig_devices);
static const struct hid_usage_id ntrig_grabbed_usages[] = {
{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
- { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
};
static struct hid_driver ntrig_driver = {
diff --git a/drivers/hid/hid-ortek.c b/drivers/hid/hid-ortek.c
new file mode 100644
index 000000000000..aa9a960f73a4
--- /dev/null
+++ b/drivers/hid/hid-ortek.c
@@ -0,0 +1,56 @@
+/*
+ * HID driver for Ortek WKB-2000 (wireless keyboard + mouse trackpad).
+ * Fixes LogicalMaximum error in USB report description, see
+ * http://bugzilla.kernel.org/show_bug.cgi?id=14787
+ *
+ * Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static void ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int rsize)
+{
+ if (rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) {
+ dev_info(&hdev->dev, "Fixing up Ortek WKB-2000 "
+ "report descriptor.\n");
+ rdesc[55] = 0x92;
+ }
+}
+
+static const struct hid_device_id ortek_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, ortek_devices);
+
+static struct hid_driver ortek_driver = {
+ .name = "ortek",
+ .id_table = ortek_devices,
+ .report_fixup = ortek_report_fixup
+};
+
+static int __init ortek_init(void)
+{
+ return hid_register_driver(&ortek_driver);
+}
+
+static void __exit ortek_exit(void)
+{
+ hid_unregister_driver(&ortek_driver);
+}
+
+module_init(ortek_init);
+module_exit(ortek_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-quanta.c b/drivers/hid/hid-quanta.c
new file mode 100644
index 000000000000..01dd51c4986c
--- /dev/null
+++ b/drivers/hid/hid-quanta.c
@@ -0,0 +1,260 @@
+/*
+ * HID driver for Quanta Optical Touch dual-touch panels
+ *
+ * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
+ *
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_DESCRIPTION("Quanta dual-touch panel");
+MODULE_LICENSE("GPL");
+
+#include "hid-ids.h"
+
+struct quanta_data {
+ __u16 x, y;
+ __u8 id;
+ bool valid; /* valid finger data, or just placeholder? */
+ bool first; /* is this the first finger in this frame? */
+ bool activity_now; /* at least one active finger in this frame? */
+ bool activity; /* at least one active finger previously? */
+};
+
+static int quanta_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ switch (usage->hid & HID_USAGE_PAGE) {
+
+ case HID_UP_GENDESK:
+ switch (usage->hid) {
+ case HID_GD_X:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_X);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_X,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ case HID_GD_Y:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_Y);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_Y,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ }
+ return 0;
+
+ case HID_UP_DIGITIZER:
+ switch (usage->hid) {
+ case HID_DG_CONFIDENCE:
+ case HID_DG_TIPSWITCH:
+ case HID_DG_INPUTMODE:
+ case HID_DG_DEVICEINDEX:
+ case HID_DG_CONTACTCOUNT:
+ case HID_DG_CONTACTMAX:
+ case HID_DG_TIPPRESSURE:
+ case HID_DG_WIDTH:
+ case HID_DG_HEIGHT:
+ return -1;
+ case HID_DG_INRANGE:
+ /* touchscreen emulation */
+ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+ return 1;
+ case HID_DG_CONTACTID:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TRACKING_ID);
+ return 1;
+ }
+ return 0;
+
+ case 0xff000000:
+ /* ignore vendor-specific features */
+ return -1;
+ }
+
+ return 0;
+}
+
+static int quanta_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (usage->type == EV_KEY || usage->type == EV_ABS)
+ clear_bit(usage->code, *bit);
+
+ return 0;
+}
+
+/*
+ * this function is called when a whole finger has been parsed,
+ * so that it can decide what to send to the input layer.
+ */
+static void quanta_filter_event(struct quanta_data *td, struct input_dev *input)
+{
+
+ td->first = !td->first; /* touchscreen emulation */
+
+ if (!td->valid) {
+ /*
+ * touchscreen emulation: if no finger in this frame is valid
+ * and there previously was finger activity, this is a release
+ */
+ if (!td->first && !td->activity_now && td->activity) {
+ input_event(input, EV_KEY, BTN_TOUCH, 0);
+ td->activity = false;
+ }
+ return;
+ }
+
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
+
+ input_mt_sync(input);
+ td->valid = false;
+
+ /* touchscreen emulation: if first active finger in this frame... */
+ if (!td->activity_now) {
+ /* if there was no previous activity, emit touch event */
+ if (!td->activity) {
+ input_event(input, EV_KEY, BTN_TOUCH, 1);
+ td->activity = true;
+ }
+ td->activity_now = true;
+ /* and in any case this is our preferred finger */
+ input_event(input, EV_ABS, ABS_X, td->x);
+ input_event(input, EV_ABS, ABS_Y, td->y);
+ }
+}
+
+
+static int quanta_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct quanta_data *td = hid_get_drvdata(hid);
+
+ if (hid->claimed & HID_CLAIMED_INPUT) {
+ struct input_dev *input = field->hidinput->input;
+
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ td->valid = !!value;
+ break;
+ case HID_GD_X:
+ td->x = value;
+ break;
+ case HID_GD_Y:
+ td->y = value;
+ quanta_filter_event(td, input);
+ break;
+ case HID_DG_CONTACTID:
+ td->id = value;
+ break;
+ case HID_DG_CONTACTCOUNT:
+ /* touch emulation: this is the last field in a frame */
+ td->first = false;
+ td->activity_now = false;
+ break;
+ case HID_DG_CONFIDENCE:
+ case HID_DG_TIPSWITCH:
+ /* avoid interference from generic hidinput handling */
+ break;
+
+ default:
+ /* fallback to the generic hidinput handling */
+ return 0;
+ }
+ }
+
+ /* we have handled the hidinput part, now remains hiddev */
+ if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
+
+ return 1;
+}
+
+static int quanta_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+ struct quanta_data *td;
+
+ td = kmalloc(sizeof(struct quanta_data), GFP_KERNEL);
+ if (!td) {
+ dev_err(&hdev->dev, "cannot allocate Quanta Touch data\n");
+ return -ENOMEM;
+ }
+ td->valid = false;
+ td->activity = false;
+ td->activity_now = false;
+ td->first = false;
+ hid_set_drvdata(hdev, td);
+
+ ret = hid_parse(hdev);
+ if (!ret)
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+ if (ret)
+ kfree(td);
+
+ return ret;
+}
+
+static void quanta_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+ hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id quanta_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+ USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+ USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, quanta_devices);
+
+static const struct hid_usage_id quanta_grabbed_usages[] = {
+ { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
+static struct hid_driver quanta_driver = {
+ .name = "quanta-touch",
+ .id_table = quanta_devices,
+ .probe = quanta_probe,
+ .remove = quanta_remove,
+ .input_mapping = quanta_input_mapping,
+ .input_mapped = quanta_input_mapped,
+ .usage_table = quanta_grabbed_usages,
+ .event = quanta_event,
+};
+
+static int __init quanta_init(void)
+{
+ return hid_register_driver(&quanta_driver);
+}
+
+static void __exit quanta_exit(void)
+{
+ hid_unregister_driver(&quanta_driver);
+}
+
+module_init(quanta_init);
+module_exit(quanta_exit);
+
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 4e8450228a24..9bf00d77d92b 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -48,7 +48,7 @@ static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
* to "operational". Without this, the ps3 controller will not report any
* events.
*/
-static int sony_set_operational(struct hid_device *hdev)
+static int sony_set_operational_usb(struct hid_device *hdev)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct usb_device *dev = interface_to_usbdev(intf);
@@ -73,6 +73,12 @@ static int sony_set_operational(struct hid_device *hdev)
return ret;
}
+static int sony_set_operational_bt(struct hid_device *hdev)
+{
+ unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 };
+ return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
+}
+
static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
@@ -81,7 +87,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
sc = kzalloc(sizeof(*sc), GFP_KERNEL);
if (sc == NULL) {
- dev_err(&hdev->dev, "can't alloc apple descriptor\n");
+ dev_err(&hdev->dev, "can't alloc sony descriptor\n");
return -ENOMEM;
}
@@ -101,7 +107,17 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
- ret = sony_set_operational(hdev);
+ switch (hdev->bus) {
+ case BUS_USB:
+ ret = sony_set_operational_usb(hdev);
+ break;
+ case BUS_BLUETOOTH:
+ ret = sony_set_operational_bt(hdev);
+ break;
+ default:
+ ret = 0;
+ }
+
if (ret < 0)
goto err_stop;
@@ -121,6 +137,7 @@ static void sony_remove(struct hid_device *hdev)
static const struct hid_device_id sony_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
.driver_data = VAIO_RDESC_CONSTANT },
{ }
diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c
new file mode 100644
index 000000000000..2e592a06654e
--- /dev/null
+++ b/drivers/hid/hid-stantum.c
@@ -0,0 +1,283 @@
+/*
+ * HID driver for Stantum multitouch panels
+ *
+ * Copyright (c) 2009 Stephane Chatty <chatty@enac.fr>
+ *
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_DESCRIPTION("Stantum HID multitouch panels");
+MODULE_LICENSE("GPL");
+
+#include "hid-ids.h"
+
+struct stantum_data {
+ __s32 x, y, z, w, h; /* x, y, pressure, width, height */
+ __u16 id; /* touch id */
+ bool valid; /* valid finger data, or just placeholder? */
+ bool first; /* first finger in the HID packet? */
+ bool activity; /* at least one active finger so far? */
+};
+
+static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ switch (usage->hid & HID_USAGE_PAGE) {
+
+ case HID_UP_GENDESK:
+ switch (usage->hid) {
+ case HID_GD_X:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_X);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_X,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ case HID_GD_Y:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_Y);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_Y,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
+ return 1;
+ }
+ return 0;
+
+ case HID_UP_DIGITIZER:
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ case HID_DG_CONFIDENCE:
+ case HID_DG_INPUTMODE:
+ case HID_DG_DEVICEINDEX:
+ case HID_DG_CONTACTCOUNT:
+ case HID_DG_CONTACTMAX:
+ return -1;
+
+ case HID_DG_TIPSWITCH:
+ /* touchscreen emulation */
+ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+ return 1;
+
+ case HID_DG_WIDTH:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TOUCH_MAJOR);
+ return 1;
+ case HID_DG_HEIGHT:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TOUCH_MINOR);
+ input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
+ 1, 1, 0, 0);
+ return 1;
+ case HID_DG_TIPPRESSURE:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_PRESSURE);
+ return 1;
+
+ case HID_DG_CONTACTID:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TRACKING_ID);
+ return 1;
+
+ }
+ return 0;
+
+ case 0xff000000:
+ /* no input-oriented meaning */
+ return -1;
+ }
+
+ return 0;
+}
+
+static int stantum_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (usage->type == EV_KEY || usage->type == EV_ABS)
+ clear_bit(usage->code, *bit);
+
+ return 0;
+}
+
+/*
+ * this function is called when a whole finger has been parsed,
+ * so that it can decide what to send to the input layer.
+ */
+static void stantum_filter_event(struct stantum_data *sd,
+ struct input_dev *input)
+{
+ bool wide;
+
+ if (!sd->valid) {
+ /*
+ * touchscreen emulation: if the first finger is not valid and
+ * there previously was finger activity, this is a release
+ */
+ if (sd->first && sd->activity) {
+ input_event(input, EV_KEY, BTN_TOUCH, 0);
+ sd->activity = false;
+ }
+ return;
+ }
+
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, sd->id);
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, sd->x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, sd->y);
+
+ wide = (sd->w > sd->h);
+ input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, wide ? sd->w : sd->h);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, wide ? sd->h : sd->w);
+
+ input_event(input, EV_ABS, ABS_MT_PRESSURE, sd->z);
+
+ input_mt_sync(input);
+ sd->valid = false;
+
+ /* touchscreen emulation */
+ if (sd->first) {
+ if (!sd->activity) {
+ input_event(input, EV_KEY, BTN_TOUCH, 1);
+ sd->activity = true;
+ }
+ input_event(input, EV_ABS, ABS_X, sd->x);
+ input_event(input, EV_ABS, ABS_Y, sd->y);
+ }
+ sd->first = false;
+}
+
+
+static int stantum_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct stantum_data *sd = hid_get_drvdata(hid);
+
+ if (hid->claimed & HID_CLAIMED_INPUT) {
+ struct input_dev *input = field->hidinput->input;
+
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ /* this is the last field in a finger */
+ stantum_filter_event(sd, input);
+ break;
+ case HID_DG_WIDTH:
+ sd->w = value;
+ break;
+ case HID_DG_HEIGHT:
+ sd->h = value;
+ break;
+ case HID_GD_X:
+ sd->x = value;
+ break;
+ case HID_GD_Y:
+ sd->y = value;
+ break;
+ case HID_DG_TIPPRESSURE:
+ sd->z = value;
+ break;
+ case HID_DG_CONTACTID:
+ sd->id = value;
+ break;
+ case HID_DG_CONFIDENCE:
+ sd->valid = !!value;
+ break;
+ case 0xff000002:
+ /* this comes only before the first finger */
+ sd->first = true;
+ break;
+
+ default:
+ /* ignore the others */
+ return 1;
+ }
+ }
+
+ /* we have handled the hidinput part, now remains hiddev */
+ if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
+
+ return 1;
+}
+
+static int stantum_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int ret;
+ struct stantum_data *sd;
+
+ sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL);
+ if (!sd) {
+ dev_err(&hdev->dev, "cannot allocate Stantum data\n");
+ return -ENOMEM;
+ }
+ sd->valid = false;
+ sd->first = false;
+ sd->activity = false;
+ hid_set_drvdata(hdev, sd);
+
+ ret = hid_parse(hdev);
+ if (!ret)
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+ if (ret)
+ kfree(sd);
+
+ return ret;
+}
+
+static void stantum_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+ hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id stantum_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, stantum_devices);
+
+static const struct hid_usage_id stantum_grabbed_usages[] = {
+ { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
+static struct hid_driver stantum_driver = {
+ .name = "stantum",
+ .id_table = stantum_devices,
+ .probe = stantum_probe,
+ .remove = stantum_remove,
+ .input_mapping = stantum_input_mapping,
+ .input_mapped = stantum_input_mapped,
+ .usage_table = stantum_grabbed_usages,
+ .event = stantum_event,
+};
+
+static int __init stantum_init(void)
+{
+ return hid_register_driver(&stantum_driver);
+}
+
+static void __exit stantum_exit(void)
+{
+ hid_unregister_driver(&stantum_driver);
+}
+
+module_init(stantum_init);
+module_exit(stantum_exit);
+
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index 12dcda529201..8d3b46f5d149 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -156,7 +156,9 @@ static int wacom_probe(struct hid_device *hdev,
struct hid_input *hidinput;
struct input_dev *input;
struct wacom_data *wdata;
+ char rep_data[2];
int ret;
+ int limit;
wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
if (wdata == NULL) {
@@ -166,6 +168,7 @@ static int wacom_probe(struct hid_device *hdev,
hid_set_drvdata(hdev, wdata);
+ /* Parse the HID report now */
ret = hid_parse(hdev);
if (ret) {
dev_err(&hdev->dev, "parse failed\n");
@@ -178,6 +181,31 @@ static int wacom_probe(struct hid_device *hdev,
goto err_free;
}
+ /*
+ * Note that if the raw queries fail, it's not a hard failure and it
+ * is safe to continue
+ */
+
+ /* Set Wacom mode2 */
+ rep_data[0] = 0x03; rep_data[1] = 0x00;
+ limit = 3;
+ do {
+ ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+ HID_FEATURE_REPORT);
+ } while (ret < 0 && limit-- > 0);
+ if (ret < 0)
+ dev_warn(&hdev->dev, "failed to poke device #1, %d\n", ret);
+
+ /* 0x06 - high reporting speed, 0x05 - low speed */
+ rep_data[0] = 0x06; rep_data[1] = 0x00;
+ limit = 3;
+ do {
+ ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+ HID_FEATURE_REPORT);
+ } while (ret < 0 && limit-- > 0);
+ if (ret < 0)
+ dev_warn(&hdev->dev, "failed to poke device #2, %d\n", ret);
+
hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
input = hidinput->input;
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index cdd136942bca..d04476700b7b 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -134,7 +134,7 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
goto out;
}
- ret = dev->hid_output_raw_report(dev, buf, count);
+ ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT);
out:
kfree(buf);
return ret;
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index e2997a8d5e1b..56d06cd8075b 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -5,7 +5,7 @@
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
* Copyright (c) 2007-2008 Oliver Neukum
- * Copyright (c) 2006-2009 Jiri Kosina
+ * Copyright (c) 2006-2010 Jiri Kosina
*/
/*
@@ -316,6 +316,7 @@ static int hid_submit_out(struct hid_device *hid)
err_hid("usb_submit_urb(out) failed");
return -1;
}
+ usbhid->last_out = jiffies;
} else {
/*
* queue work to wake up the device.
@@ -377,6 +378,7 @@ static int hid_submit_ctrl(struct hid_device *hid)
err_hid("usb_submit_urb(ctrl) failed");
return -1;
}
+ usbhid->last_ctrl = jiffies;
} else {
/*
* queue work to wake up the device.
@@ -512,9 +514,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
usbhid->out[usbhid->outhead].report = report;
usbhid->outhead = head;
- if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
+ if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) {
if (hid_submit_out(hid))
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+ } else {
+ /*
+ * the queue is known to run
+ * but an earlier request may be stuck
+ * we may need to time out
+ * no race because this is called under
+ * spinlock
+ */
+ if (time_after(jiffies, usbhid->last_out + HZ * 5))
+ usb_unlink_urb(usbhid->urbout);
+ }
return;
}
@@ -535,9 +548,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
usbhid->ctrl[usbhid->ctrlhead].dir = dir;
usbhid->ctrlhead = head;
- if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+ if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) {
if (hid_submit_ctrl(hid))
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+ } else {
+ /*
+ * the queue is known to run
+ * but an earlier request may be stuck
+ * we may need to time out
+ * no race because this is called under
+ * spinlock
+ */
+ if (time_after(jiffies, usbhid->last_ctrl + HZ * 5))
+ usb_unlink_urb(usbhid->urbctrl);
+ }
}
void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
@@ -774,7 +798,8 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
return 0;
}
-static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count)
+static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count,
+ unsigned char report_type)
{
struct usbhid_device *usbhid = hid->driver_data;
struct usb_device *dev = hid_to_usb_dev(hid);
@@ -785,7 +810,7 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_REPORT,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ((HID_OUTPUT_REPORT + 1) << 8) | *buf,
+ ((report_type + 1) << 8) | *buf,
interface->desc.bInterfaceNumber, buf + 1, count - 1,
USB_CTRL_SET_TIMEOUT);
@@ -981,9 +1006,6 @@ static int usbhid_start(struct hid_device *hid)
spin_lock_init(&usbhid->lock);
- usbhid->intf = intf;
- usbhid->ifnum = interface->desc.bInterfaceNumber;
-
usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
if (!usbhid->urbctrl) {
ret = -ENOMEM;
@@ -1154,6 +1176,8 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
hid->driver_data = usbhid;
usbhid->hid = hid;
+ usbhid->intf = intf;
+ usbhid->ifnum = interface->desc.bInterfaceNumber;
ret = hid_add_device(hid);
if (ret) {
@@ -1342,7 +1366,7 @@ static int hid_reset_resume(struct usb_interface *intf)
#endif /* CONFIG_PM */
-static struct usb_device_id hid_usb_ids [] = {
+static const struct usb_device_id hid_usb_ids[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
.bInterfaceClass = USB_INTERFACE_CLASS_HID },
{ } /* Terminating entry */
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 38773dc2821b..7844280897d1 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -43,8 +43,10 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
+ { USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
@@ -57,6 +59,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 867e08433e4b..433602aed468 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -265,9 +265,10 @@ static int hiddev_release(struct inode * inode, struct file * file)
static int hiddev_open(struct inode *inode, struct file *file)
{
struct hiddev_list *list;
- int res;
+ int res, i;
- int i = iminor(inode) - HIDDEV_MINOR_BASE;
+ lock_kernel();
+ i = iminor(inode) - HIDDEV_MINOR_BASE;
if (i >= HIDDEV_MINORS || i < 0 || !hiddev_table[i])
return -ENODEV;
@@ -313,10 +314,12 @@ static int hiddev_open(struct inode *inode, struct file *file)
usbhid_open(hid);
}
+ unlock_kernel();
return 0;
bail:
file->private_data = NULL;
kfree(list);
+ unlock_kernel();
return res;
}
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 08f505ca2e3d..ec20400c7f29 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -80,12 +80,14 @@ struct usbhid_device {
unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */
char *ctrlbuf; /* Control buffer */
dma_addr_t ctrlbuf_dma; /* Control buffer dma */
+ unsigned long last_ctrl; /* record of last output for timeouts */
struct urb *urbout; /* Output URB */
struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */
unsigned char outhead, outtail; /* Output pipe fifo head & tail */
char *outbuf; /* Output buffer */
dma_addr_t outbuf_dma; /* Output buffer dma */
+ unsigned long last_out; /* record of last output for timeouts */
spinlock_t lock; /* fifo spinlock */
unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 68cf87749a42..e4595e6147b4 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -170,6 +170,16 @@ config SENSORS_ADM9240
This driver can also be built as a module. If so, the module
will be called adm9240.
+config SENSORS_ADT7411
+ tristate "Analog Devices ADT7411"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Analog Devices
+ ADT7411 voltage and temperature monitoring chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called adt7411.
+
config SENSORS_ADT7462
tristate "Analog Devices ADT7462"
depends on I2C && EXPERIMENTAL
@@ -190,20 +200,6 @@ config SENSORS_ADT7470
This driver can also be built as a module. If so, the module
will be called adt7470.
-config SENSORS_ADT7473
- tristate "Analog Devices ADT7473 (DEPRECATED)"
- depends on I2C && EXPERIMENTAL
- select SENSORS_ADT7475
- help
- If you say yes here you get support for the Analog Devices
- ADT7473 temperature monitoring chips.
-
- This driver is deprecated, you should use the adt7475 driver
- instead.
-
- This driver can also be built as a module. If so, the module
- will be called adt7473.
-
config SENSORS_ADT7475
tristate "Analog Devices ADT7473, ADT7475, ADT7476 and ADT7490"
depends on I2C && EXPERIMENTAL
@@ -216,6 +212,19 @@ config SENSORS_ADT7475
This driver can also be build as a module. If so, the module
will be called adt7475.
+config SENSORS_ASC7621
+ tristate "Andigilog aSC7621"
+ depends on HWMON && I2C
+ help
+ If you say yes here you get support for the aSC7621
+ family of SMBus sensors chip found on most Intel X48, X38, 975,
+ 965 and 945 desktop boards. Currently supported chips:
+ aSC7621
+ aSC7621a
+
+ This driver can also be built as a module. If so, the module
+ will be called asc7621.
+
config SENSORS_K8TEMP
tristate "AMD Athlon64/FX or Opteron temperature sensor"
depends on X86 && PCI && EXPERIMENTAL
@@ -563,9 +572,10 @@ config SENSORS_LM90
depends on I2C
help
If you say yes here you get support for National Semiconductor LM90,
- LM86, LM89 and LM99, Analog Devices ADM1032 and ADT7461, and Maxim
+ LM86, LM89 and LM99, Analog Devices ADM1032 and ADT7461, Maxim
MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
- MAX6680, MAX6681 and MAX6692 sensor chips.
+ MAX6680, MAX6681 and MAX6692, and Winbond/Nuvoton W83L771AWG/ASG
+ sensor chips.
This driver can also be built as a module. If so, the module
will be called lm90.
@@ -909,7 +919,8 @@ config SENSORS_W83793
select HWMON_VID
help
If you say yes here you get support for the Winbond W83793
- hardware monitoring chip.
+ hardware monitoring chip, including support for the integrated
+ watchdog.
This driver can also be built as a module. If so, the module
will be called w83793.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 4bc215c0953f..4aa1a3d112ad 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -29,12 +29,13 @@ obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
+obj-$(CONFIG_SENSORS_ADT7411) += adt7411.o
obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o
obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
-obj-$(CONFIG_SENSORS_ADT7473) += adt7473.o
obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_AMS) += ams/
+obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
diff --git a/drivers/hwmon/adcxx.c b/drivers/hwmon/adcxx.c
index 5e9e095f1136..74d9c5195e44 100644
--- a/drivers/hwmon/adcxx.c
+++ b/drivers/hwmon/adcxx.c
@@ -62,18 +62,23 @@ static ssize_t adcxx_read(struct device *dev,
struct spi_device *spi = to_spi_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adcxx *adc = dev_get_drvdata(&spi->dev);
- u8 tx_buf[2] = { attr->index << 3 }; /* other bits are don't care */
+ u8 tx_buf[2];
u8 rx_buf[2];
int status;
- int value;
+ u32 value;
if (mutex_lock_interruptible(&adc->lock))
return -ERESTARTSYS;
- status = spi_write_then_read(spi, tx_buf, sizeof(tx_buf),
- rx_buf, sizeof(rx_buf));
+ if (adc->channels == 1) {
+ status = spi_read(spi, rx_buf, sizeof(rx_buf));
+ } else {
+ tx_buf[0] = attr->index << 3; /* other bits are don't care */
+ status = spi_write_then_read(spi, tx_buf, sizeof(tx_buf),
+ rx_buf, sizeof(rx_buf));
+ }
if (status < 0) {
- dev_warn(dev, "spi_write_then_read failed with status %d\n",
+ dev_warn(dev, "SPI synch. transfer failed with status %d\n",
status);
goto out;
}
diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c
new file mode 100644
index 000000000000..3471884e42d2
--- /dev/null
+++ b/drivers/hwmon/adt7411.c
@@ -0,0 +1,366 @@
+/*
+ * Driver for the ADT7411 (I2C/SPI 8 channel 10 bit ADC & temperature-sensor)
+ *
+ * Copyright (C) 2008, 2010 Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * TODO: SPI, support for external temperature sensor
+ * use power-down mode for suspend?, interrupt handling?
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#define ADT7411_REG_INT_TEMP_VDD_LSB 0x03
+#define ADT7411_REG_EXT_TEMP_AIN14_LSB 0x04
+#define ADT7411_REG_VDD_MSB 0x06
+#define ADT7411_REG_INT_TEMP_MSB 0x07
+#define ADT7411_REG_EXT_TEMP_AIN1_MSB 0x08
+
+#define ADT7411_REG_CFG1 0x18
+#define ADT7411_CFG1_START_MONITOR (1 << 0)
+
+#define ADT7411_REG_CFG2 0x19
+#define ADT7411_CFG2_DISABLE_AVG (1 << 5)
+
+#define ADT7411_REG_CFG3 0x1a
+#define ADT7411_CFG3_ADC_CLK_225 (1 << 0)
+#define ADT7411_CFG3_REF_VDD (1 << 4)
+
+#define ADT7411_REG_DEVICE_ID 0x4d
+#define ADT7411_REG_MANUFACTURER_ID 0x4e
+
+#define ADT7411_DEVICE_ID 0x2
+#define ADT7411_MANUFACTURER_ID 0x41
+
+static const unsigned short normal_i2c[] = { 0x48, 0x4a, 0x4b, I2C_CLIENT_END };
+
+struct adt7411_data {
+ struct mutex device_lock; /* for "atomic" device accesses */
+ struct mutex update_lock;
+ unsigned long next_update;
+ int vref_cached;
+ struct device *hwmon_dev;
+};
+
+/*
+ * When reading a register containing (up to 4) lsb, all associated
+ * msb-registers get locked by the hardware. After _one_ of those msb is read,
+ * _all_ are unlocked. In order to use this locking correctly, reading lsb/msb
+ * is protected here with a mutex, too.
+ */
+static int adt7411_read_10_bit(struct i2c_client *client, u8 lsb_reg,
+ u8 msb_reg, u8 lsb_shift)
+{
+ struct adt7411_data *data = i2c_get_clientdata(client);
+ int val, tmp;
+
+ mutex_lock(&data->device_lock);
+
+ val = i2c_smbus_read_byte_data(client, lsb_reg);
+ if (val < 0)
+ goto exit_unlock;
+
+ tmp = (val >> lsb_shift) & 3;
+ val = i2c_smbus_read_byte_data(client, msb_reg);
+
+ if (val >= 0)
+ val = (val << 2) | tmp;
+
+ exit_unlock:
+ mutex_unlock(&data->device_lock);
+
+ return val;
+}
+
+static int adt7411_modify_bit(struct i2c_client *client, u8 reg, u8 bit,
+ bool flag)
+{
+ struct adt7411_data *data = i2c_get_clientdata(client);
+ int ret, val;
+
+ mutex_lock(&data->device_lock);
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret < 0)
+ goto exit_unlock;
+
+ if (flag)
+ val = ret | bit;
+ else
+ val = ret & ~bit;
+
+ ret = i2c_smbus_write_byte_data(client, reg, val);
+
+ exit_unlock:
+ mutex_unlock(&data->device_lock);
+ return ret;
+}
+
+static ssize_t adt7411_show_vdd(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret = adt7411_read_10_bit(client, ADT7411_REG_INT_TEMP_VDD_LSB,
+ ADT7411_REG_VDD_MSB, 2);
+
+ return ret < 0 ? ret : sprintf(buf, "%u\n", ret * 7000 / 1024);
+}
+
+static ssize_t adt7411_show_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int val = adt7411_read_10_bit(client, ADT7411_REG_INT_TEMP_VDD_LSB,
+ ADT7411_REG_INT_TEMP_MSB, 0);
+
+ if (val < 0)
+ return val;
+
+ val = val & 0x200 ? val - 0x400 : val; /* 10 bit signed */
+
+ return sprintf(buf, "%d\n", val * 250);
+}
+
+static ssize_t adt7411_show_input(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7411_data *data = i2c_get_clientdata(client);
+ int val;
+ u8 lsb_reg, lsb_shift;
+
+ mutex_lock(&data->update_lock);
+ if (time_after_eq(jiffies, data->next_update)) {
+ val = i2c_smbus_read_byte_data(client, ADT7411_REG_CFG3);
+ if (val < 0)
+ goto exit_unlock;
+
+ if (val & ADT7411_CFG3_REF_VDD) {
+ val = adt7411_read_10_bit(client,
+ ADT7411_REG_INT_TEMP_VDD_LSB,
+ ADT7411_REG_VDD_MSB, 2);
+ if (val < 0)
+ goto exit_unlock;
+
+ data->vref_cached = val * 7000 / 1024;
+ } else {
+ data->vref_cached = 2250;
+ }
+
+ data->next_update = jiffies + HZ;
+ }
+
+ lsb_reg = ADT7411_REG_EXT_TEMP_AIN14_LSB + (nr >> 2);
+ lsb_shift = 2 * (nr & 0x03);
+ val = adt7411_read_10_bit(client, lsb_reg,
+ ADT7411_REG_EXT_TEMP_AIN1_MSB + nr, lsb_shift);
+ if (val < 0)
+ goto exit_unlock;
+
+ val = sprintf(buf, "%u\n", val * data->vref_cached / 1024);
+ exit_unlock:
+ mutex_unlock(&data->update_lock);
+ return val;
+}
+
+static ssize_t adt7411_show_bit(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret = i2c_smbus_read_byte_data(client, attr2->index);
+
+ return ret < 0 ? ret : sprintf(buf, "%u\n", !!(ret & attr2->nr));
+}
+
+static ssize_t adt7411_set_bit(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute_2 *s_attr2 = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7411_data *data = i2c_get_clientdata(client);
+ int ret;
+ unsigned long flag;
+
+ ret = strict_strtoul(buf, 0, &flag);
+ if (ret || flag > 1)
+ return -EINVAL;
+
+ ret = adt7411_modify_bit(client, s_attr2->index, s_attr2->nr, flag);
+
+ /* force update */
+ mutex_lock(&data->update_lock);
+ data->next_update = jiffies;
+ mutex_unlock(&data->update_lock);
+
+ return ret < 0 ? ret : count;
+}
+
+#define ADT7411_BIT_ATTR(__name, __reg, __bit) \
+ SENSOR_DEVICE_ATTR_2(__name, S_IRUGO | S_IWUSR, adt7411_show_bit, \
+ adt7411_set_bit, __bit, __reg)
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, adt7411_show_temp, NULL);
+static DEVICE_ATTR(in0_input, S_IRUGO, adt7411_show_vdd, NULL);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, adt7411_show_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, adt7411_show_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, adt7411_show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, adt7411_show_input, NULL, 3);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, adt7411_show_input, NULL, 4);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, adt7411_show_input, NULL, 5);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, adt7411_show_input, NULL, 6);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, adt7411_show_input, NULL, 7);
+static ADT7411_BIT_ATTR(no_average, ADT7411_REG_CFG2, ADT7411_CFG2_DISABLE_AVG);
+static ADT7411_BIT_ATTR(fast_sampling, ADT7411_REG_CFG3, ADT7411_CFG3_ADC_CLK_225);
+static ADT7411_BIT_ATTR(adc_ref_vdd, ADT7411_REG_CFG3, ADT7411_CFG3_REF_VDD);
+
+static struct attribute *adt7411_attrs[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_in0_input.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_no_average.dev_attr.attr,
+ &sensor_dev_attr_fast_sampling.dev_attr.attr,
+ &sensor_dev_attr_adc_ref_vdd.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adt7411_attr_grp = {
+ .attrs = adt7411_attrs,
+};
+
+static int adt7411_detect(struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ int val;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ val = i2c_smbus_read_byte_data(client, ADT7411_REG_MANUFACTURER_ID);
+ if (val < 0 || val != ADT7411_MANUFACTURER_ID) {
+ dev_dbg(&client->dev, "Wrong manufacturer ID. Got %d, "
+ "expected %d\n", val, ADT7411_MANUFACTURER_ID);
+ return -ENODEV;
+ }
+
+ val = i2c_smbus_read_byte_data(client, ADT7411_REG_DEVICE_ID);
+ if (val < 0 || val != ADT7411_DEVICE_ID) {
+ dev_dbg(&client->dev, "Wrong device ID. Got %d, "
+ "expected %d\n", val, ADT7411_DEVICE_ID);
+ return -ENODEV;
+ }
+
+ strlcpy(info->type, "adt7411", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int __devinit adt7411_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adt7411_data *data;
+ int ret;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->device_lock);
+ mutex_init(&data->update_lock);
+
+ ret = adt7411_modify_bit(client, ADT7411_REG_CFG1,
+ ADT7411_CFG1_START_MONITOR, 1);
+ if (ret < 0)
+ goto exit_free;
+
+ /* force update on first occasion */
+ data->next_update = jiffies;
+
+ ret = sysfs_create_group(&client->dev.kobj, &adt7411_attr_grp);
+ if (ret)
+ goto exit_free;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ dev_info(&client->dev, "successfully registered\n");
+
+ return 0;
+
+ exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
+ exit_free:
+ i2c_set_clientdata(client, NULL);
+ kfree(data);
+ return ret;
+}
+
+static int __devexit adt7411_remove(struct i2c_client *client)
+{
+ struct adt7411_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
+ i2c_set_clientdata(client, NULL);
+ kfree(data);
+ return 0;
+}
+
+static const struct i2c_device_id adt7411_id[] = {
+ { "adt7411", 0 },
+ { }
+};
+
+static struct i2c_driver adt7411_driver = {
+ .driver = {
+ .name = "adt7411",
+ },
+ .probe = adt7411_probe,
+ .remove = __devexit_p(adt7411_remove),
+ .id_table = adt7411_id,
+ .detect = adt7411_detect,
+ .address_list = normal_i2c,
+ .class = I2C_CLASS_HWMON,
+};
+
+static int __init sensors_adt7411_init(void)
+{
+ return i2c_add_driver(&adt7411_driver);
+}
+module_init(sensors_adt7411_init)
+
+static void __exit sensors_adt7411_exit(void)
+{
+ i2c_del_driver(&adt7411_driver);
+}
+module_exit(sensors_adt7411_exit)
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de> and "
+ "Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("ADT7411 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c
index a31e77c776ae..b8156b4893bb 100644
--- a/drivers/hwmon/adt7462.c
+++ b/drivers/hwmon/adt7462.c
@@ -179,7 +179,7 @@ static const unsigned short normal_i2c[] = { 0x58, 0x5C, I2C_CLIENT_END };
*
* Some, but not all, of these voltages have low/high limits.
*/
-#define ADT7462_VOLT_COUNT 12
+#define ADT7462_VOLT_COUNT 13
#define ADT7462_VENDOR 0x41
#define ADT7462_DEVICE 0x62
diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c
deleted file mode 100644
index 434576f61c84..000000000000
--- a/drivers/hwmon/adt7473.c
+++ /dev/null
@@ -1,1180 +0,0 @@
-/*
- * A hwmon driver for the Analog Devices ADT7473
- * Copyright (C) 2007 IBM
- *
- * Author: Darrick J. Wong <djwong@us.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/err.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/log2.h>
-
-/* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x2C, 0x2D, 0x2E, I2C_CLIENT_END };
-
-/* ADT7473 registers */
-#define ADT7473_REG_BASE_ADDR 0x20
-
-#define ADT7473_REG_VOLT_BASE_ADDR 0x21
-#define ADT7473_REG_VOLT_MIN_BASE_ADDR 0x46
-
-#define ADT7473_REG_TEMP_BASE_ADDR 0x25
-#define ADT7473_REG_TEMP_LIMITS_BASE_ADDR 0x4E
-#define ADT7473_REG_TEMP_TMIN_BASE_ADDR 0x67
-#define ADT7473_REG_TEMP_TMAX_BASE_ADDR 0x6A
-
-#define ADT7473_REG_FAN_BASE_ADDR 0x28
-#define ADT7473_REG_FAN_MIN_BASE_ADDR 0x54
-
-#define ADT7473_REG_PWM_BASE_ADDR 0x30
-#define ADT7473_REG_PWM_MIN_BASE_ADDR 0x64
-#define ADT7473_REG_PWM_MAX_BASE_ADDR 0x38
-#define ADT7473_REG_PWM_BHVR_BASE_ADDR 0x5C
-#define ADT7473_PWM_BHVR_MASK 0xE0
-#define ADT7473_PWM_BHVR_SHIFT 5
-
-#define ADT7473_REG_CFG1 0x40
-#define ADT7473_CFG1_START 0x01
-#define ADT7473_CFG1_READY 0x04
-#define ADT7473_REG_CFG2 0x73
-#define ADT7473_REG_CFG3 0x78
-#define ADT7473_REG_CFG4 0x7D
-#define ADT7473_CFG4_MAX_DUTY_AT_OVT 0x08
-#define ADT7473_REG_CFG5 0x7C
-#define ADT7473_CFG5_TEMP_TWOS 0x01
-#define ADT7473_CFG5_TEMP_OFFSET 0x02
-
-#define ADT7473_REG_DEVICE 0x3D
-#define ADT7473_VENDOR 0x41
-#define ADT7473_REG_VENDOR 0x3E
-#define ADT7473_DEVICE 0x73
-#define ADT7473_REG_REVISION 0x3F
-#define ADT7473_REV_68 0x68
-#define ADT7473_REV_69 0x69
-
-#define ADT7473_REG_ALARM1 0x41
-#define ADT7473_VCCP_ALARM 0x02
-#define ADT7473_VCC_ALARM 0x04
-#define ADT7473_R1T_ALARM 0x10
-#define ADT7473_LT_ALARM 0x20
-#define ADT7473_R2T_ALARM 0x40
-#define ADT7473_OOL 0x80
-#define ADT7473_REG_ALARM2 0x42
-#define ADT7473_OVT_ALARM 0x02
-#define ADT7473_FAN1_ALARM 0x04
-#define ADT7473_FAN2_ALARM 0x08
-#define ADT7473_FAN3_ALARM 0x10
-#define ADT7473_FAN4_ALARM 0x20
-#define ADT7473_R1T_SHORT 0x40
-#define ADT7473_R2T_SHORT 0x80
-
-#define ALARM2(x) ((x) << 8)
-
-#define ADT7473_VOLT_COUNT 2
-#define ADT7473_REG_VOLT(x) (ADT7473_REG_VOLT_BASE_ADDR + (x))
-#define ADT7473_REG_VOLT_MIN(x) (ADT7473_REG_VOLT_MIN_BASE_ADDR + ((x) * 2))
-#define ADT7473_REG_VOLT_MAX(x) (ADT7473_REG_VOLT_MIN_BASE_ADDR + \
- ((x) * 2) + 1)
-
-#define ADT7473_TEMP_COUNT 3
-#define ADT7473_REG_TEMP(x) (ADT7473_REG_TEMP_BASE_ADDR + (x))
-#define ADT7473_REG_TEMP_MIN(x) (ADT7473_REG_TEMP_LIMITS_BASE_ADDR + ((x) * 2))
-#define ADT7473_REG_TEMP_MAX(x) (ADT7473_REG_TEMP_LIMITS_BASE_ADDR + \
- ((x) * 2) + 1)
-#define ADT7473_REG_TEMP_TMIN(x) (ADT7473_REG_TEMP_TMIN_BASE_ADDR + (x))
-#define ADT7473_REG_TEMP_TMAX(x) (ADT7473_REG_TEMP_TMAX_BASE_ADDR + (x))
-
-#define ADT7473_FAN_COUNT 4
-#define ADT7473_REG_FAN(x) (ADT7473_REG_FAN_BASE_ADDR + ((x) * 2))
-#define ADT7473_REG_FAN_MIN(x) (ADT7473_REG_FAN_MIN_BASE_ADDR + ((x) * 2))
-
-#define ADT7473_PWM_COUNT 3
-#define ADT7473_REG_PWM(x) (ADT7473_REG_PWM_BASE_ADDR + (x))
-#define ADT7473_REG_PWM_MAX(x) (ADT7473_REG_PWM_MAX_BASE_ADDR + (x))
-#define ADT7473_REG_PWM_MIN(x) (ADT7473_REG_PWM_MIN_BASE_ADDR + (x))
-#define ADT7473_REG_PWM_BHVR(x) (ADT7473_REG_PWM_BHVR_BASE_ADDR + (x))
-
-/* How often do we reread sensors values? (In jiffies) */
-#define SENSOR_REFRESH_INTERVAL (2 * HZ)
-
-/* How often do we reread sensor limit values? (In jiffies) */
-#define LIMIT_REFRESH_INTERVAL (60 * HZ)
-
-/* datasheet says to divide this number by the fan reading to get fan rpm */
-#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x))
-#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM
-#define FAN_PERIOD_INVALID 65535
-#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
-
-struct adt7473_data {
- struct device *hwmon_dev;
- struct attribute_group attrs;
- struct mutex lock;
- char sensors_valid;
- char limits_valid;
- unsigned long sensors_last_updated; /* In jiffies */
- unsigned long limits_last_updated; /* In jiffies */
-
- u8 volt[ADT7473_VOLT_COUNT];
- s8 volt_min[ADT7473_VOLT_COUNT];
- s8 volt_max[ADT7473_VOLT_COUNT];
-
- s8 temp[ADT7473_TEMP_COUNT];
- s8 temp_min[ADT7473_TEMP_COUNT];
- s8 temp_max[ADT7473_TEMP_COUNT];
- s8 temp_tmin[ADT7473_TEMP_COUNT];
- /* This is called the !THERM limit in the datasheet */
- s8 temp_tmax[ADT7473_TEMP_COUNT];
-
- u16 fan[ADT7473_FAN_COUNT];
- u16 fan_min[ADT7473_FAN_COUNT];
-
- u8 pwm[ADT7473_PWM_COUNT];
- u8 pwm_max[ADT7473_PWM_COUNT];
- u8 pwm_min[ADT7473_PWM_COUNT];
- u8 pwm_behavior[ADT7473_PWM_COUNT];
-
- u8 temp_twos_complement;
- u8 temp_offset;
-
- u16 alarm;
- u8 max_duty_at_overheat;
-};
-
-static int adt7473_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
-static int adt7473_detect(struct i2c_client *client,
- struct i2c_board_info *info);
-static int adt7473_remove(struct i2c_client *client);
-
-static const struct i2c_device_id adt7473_id[] = {
- { "adt7473", 0 },
- { }
-};
-
-static struct i2c_driver adt7473_driver = {
- .class = I2C_CLASS_HWMON,
- .driver = {
- .name = "adt7473",
- },
- .probe = adt7473_probe,
- .remove = adt7473_remove,
- .id_table = adt7473_id,
- .detect = adt7473_detect,
- .address_list = normal_i2c,
-};
-
-/*
- * 16-bit registers on the ADT7473 are low-byte first. The data sheet says
- * that the low byte must be read before the high byte.
- */
-static inline int adt7473_read_word_data(struct i2c_client *client, u8 reg)
-{
- u16 foo;
- foo = i2c_smbus_read_byte_data(client, reg);
- foo |= ((u16)i2c_smbus_read_byte_data(client, reg + 1) << 8);
- return foo;
-}
-
-static inline int adt7473_write_word_data(struct i2c_client *client, u8 reg,
- u16 value)
-{
- return i2c_smbus_write_byte_data(client, reg, value & 0xFF)
- && i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
-}
-
-static void adt7473_init_client(struct i2c_client *client)
-{
- int reg = i2c_smbus_read_byte_data(client, ADT7473_REG_CFG1);
-
- if (!(reg & ADT7473_CFG1_READY)) {
- dev_err(&client->dev, "Chip not ready.\n");
- } else {
- /* start monitoring */
- i2c_smbus_write_byte_data(client, ADT7473_REG_CFG1,
- reg | ADT7473_CFG1_START);
- }
-}
-
-static struct adt7473_data *adt7473_update_device(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- unsigned long local_jiffies = jiffies;
- u8 cfg;
- int i;
-
- mutex_lock(&data->lock);
- if (time_before(local_jiffies, data->sensors_last_updated +
- SENSOR_REFRESH_INTERVAL)
- && data->sensors_valid)
- goto no_sensor_update;
-
- for (i = 0; i < ADT7473_VOLT_COUNT; i++)
- data->volt[i] = i2c_smbus_read_byte_data(client,
- ADT7473_REG_VOLT(i));
-
- /* Determine temperature encoding */
- cfg = i2c_smbus_read_byte_data(client, ADT7473_REG_CFG5);
- data->temp_twos_complement = (cfg & ADT7473_CFG5_TEMP_TWOS);
-
- /*
- * What does this do? it implies a variable temperature sensor
- * offset, but the datasheet doesn't say anything about this bit
- * and other parts of the datasheet imply that "offset64" mode
- * means that you shift temp values by -64 if the above bit was set.
- */
- data->temp_offset = (cfg & ADT7473_CFG5_TEMP_OFFSET);
-
- for (i = 0; i < ADT7473_TEMP_COUNT; i++)
- data->temp[i] = i2c_smbus_read_byte_data(client,
- ADT7473_REG_TEMP(i));
-
- for (i = 0; i < ADT7473_FAN_COUNT; i++)
- data->fan[i] = adt7473_read_word_data(client,
- ADT7473_REG_FAN(i));
-
- for (i = 0; i < ADT7473_PWM_COUNT; i++)
- data->pwm[i] = i2c_smbus_read_byte_data(client,
- ADT7473_REG_PWM(i));
-
- data->alarm = i2c_smbus_read_byte_data(client, ADT7473_REG_ALARM1);
- if (data->alarm & ADT7473_OOL)
- data->alarm |= ALARM2(i2c_smbus_read_byte_data(client,
- ADT7473_REG_ALARM2));
-
- data->sensors_last_updated = local_jiffies;
- data->sensors_valid = 1;
-
-no_sensor_update:
- if (time_before(local_jiffies, data->limits_last_updated +
- LIMIT_REFRESH_INTERVAL)
- && data->limits_valid)
- goto out;
-
- for (i = 0; i < ADT7473_VOLT_COUNT; i++) {
- data->volt_min[i] = i2c_smbus_read_byte_data(client,
- ADT7473_REG_VOLT_MIN(i));
- data->volt_max[i] = i2c_smbus_read_byte_data(client,
- ADT7473_REG_VOLT_MAX(i));
- }
-
- for (i = 0; i < ADT7473_TEMP_COUNT; i++) {
- data->temp_min[i] = i2c_smbus_read_byte_data(client,
- ADT7473_REG_TEMP_MIN(i));
- data->temp_max[i] = i2c_smbus_read_byte_data(client,
- ADT7473_REG_TEMP_MAX(i));
- data->temp_tmin[i] = i2c_smbus_read_byte_data(client,
- ADT7473_REG_TEMP_TMIN(i));
- data->temp_tmax[i] = i2c_smbus_read_byte_data(client,
- ADT7473_REG_TEMP_TMAX(i));
- }
-
- for (i = 0; i < ADT7473_FAN_COUNT; i++)
- data->fan_min[i] = adt7473_read_word_data(client,
- ADT7473_REG_FAN_MIN(i));
-
- for (i = 0; i < ADT7473_PWM_COUNT; i++) {
- data->pwm_max[i] = i2c_smbus_read_byte_data(client,
- ADT7473_REG_PWM_MAX(i));
- data->pwm_min[i] = i2c_smbus_read_byte_data(client,
- ADT7473_REG_PWM_MIN(i));
- data->pwm_behavior[i] = i2c_smbus_read_byte_data(client,
- ADT7473_REG_PWM_BHVR(i));
- }
-
- i = i2c_smbus_read_byte_data(client, ADT7473_REG_CFG4);
- data->max_duty_at_overheat = !!(i & ADT7473_CFG4_MAX_DUTY_AT_OVT);
-
- data->limits_last_updated = local_jiffies;
- data->limits_valid = 1;
-
-out:
- mutex_unlock(&data->lock);
- return data;
-}
-
-/*
- * Conversions
- */
-
-/* IN are scaled acording to built-in resistors */
-static const int adt7473_scaling[] = { /* .001 Volts */
- 2250, 3300
-};
-#define SCALE(val, from, to) (((val) * (to) + ((from) / 2)) / (from))
-
-static int decode_volt(int volt_index, u8 raw)
-{
- return SCALE(raw, 192, adt7473_scaling[volt_index]);
-}
-
-static u8 encode_volt(int volt_index, int cooked)
-{
- int raw = SCALE(cooked, adt7473_scaling[volt_index], 192);
- return SENSORS_LIMIT(raw, 0, 255);
-}
-
-static ssize_t show_volt_min(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- decode_volt(attr->index, data->volt_min[attr->index]));
-}
-
-static ssize_t set_volt_min(struct device *dev,
- struct device_attribute *devattr,
- const char *buf,
- size_t count)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- long volt;
-
- if (strict_strtol(buf, 10, &volt))
- return -EINVAL;
-
- volt = encode_volt(attr->index, volt);
-
- mutex_lock(&data->lock);
- data->volt_min[attr->index] = volt;
- i2c_smbus_write_byte_data(client, ADT7473_REG_VOLT_MIN(attr->index),
- volt);
- mutex_unlock(&data->lock);
-
- return count;
-}
-
-static ssize_t show_volt_max(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- decode_volt(attr->index, data->volt_max[attr->index]));
-}
-
-static ssize_t set_volt_max(struct device *dev,
- struct device_attribute *devattr,
- const char *buf,
- size_t count)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- long volt;
-
- if (strict_strtol(buf, 10, &volt))
- return -EINVAL;
-
- volt = encode_volt(attr->index, volt);
-
- mutex_lock(&data->lock);
- data->volt_max[attr->index] = volt;
- i2c_smbus_write_byte_data(client, ADT7473_REG_VOLT_MAX(attr->index),
- volt);
- mutex_unlock(&data->lock);
-
- return count;
-}
-
-static ssize_t show_volt(struct device *dev, struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
-
- return sprintf(buf, "%d\n",
- decode_volt(attr->index, data->volt[attr->index]));
-}
-
-/*
- * This chip can report temperature data either as a two's complement
- * number in the range -128 to 127, or as an unsigned number that must
- * be offset by 64.
- */
-static int decode_temp(u8 twos_complement, u8 raw)
-{
- return twos_complement ? (s8)raw : raw - 64;
-}
-
-static u8 encode_temp(u8 twos_complement, int cooked)
-{
- u8 ret = twos_complement ? cooked & 0xFF : cooked + 64;
- return SENSORS_LIMIT(ret, 0, 255);
-}
-
-static ssize_t show_temp_min(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n", 1000 * decode_temp(
- data->temp_twos_complement,
- data->temp_min[attr->index]));
-}
-
-static ssize_t set_temp_min(struct device *dev,
- struct device_attribute *devattr,
- const char *buf,
- size_t count)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- long temp;
-
- if (strict_strtol(buf, 10, &temp))
- return -EINVAL;
-
- temp = DIV_ROUND_CLOSEST(temp, 1000);
- temp = encode_temp(data->temp_twos_complement, temp);
-
- mutex_lock(&data->lock);
- data->temp_min[attr->index] = temp;
- i2c_smbus_write_byte_data(client, ADT7473_REG_TEMP_MIN(attr->index),
- temp);
- mutex_unlock(&data->lock);
-
- return count;
-}
-
-static ssize_t show_temp_max(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n", 1000 * decode_temp(
- data->temp_twos_complement,
- data->temp_max[attr->index]));
-}
-
-static ssize_t set_temp_max(struct device *dev,
- struct device_attribute *devattr,
- const char *buf,
- size_t count)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- long temp;
-
- if (strict_strtol(buf, 10, &temp))
- return -EINVAL;
-
- temp = DIV_ROUND_CLOSEST(temp, 1000);
- temp = encode_temp(data->temp_twos_complement, temp);
-
- mutex_lock(&data->lock);
- data->temp_max[attr->index] = temp;
- i2c_smbus_write_byte_data(client, ADT7473_REG_TEMP_MAX(attr->index),
- temp);
- mutex_unlock(&data->lock);
-
- return count;
-}
-
-static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n", 1000 * decode_temp(
- data->temp_twos_complement,
- data->temp[attr->index]));
-}
-
-static ssize_t show_fan_min(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
-
- if (FAN_DATA_VALID(data->fan_min[attr->index]))
- return sprintf(buf, "%d\n",
- FAN_PERIOD_TO_RPM(data->fan_min[attr->index]));
- else
- return sprintf(buf, "0\n");
-}
-
-static ssize_t set_fan_min(struct device *dev,
- struct device_attribute *devattr,
- const char *buf, size_t count)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- long temp;
-
- if (strict_strtol(buf, 10, &temp) || !temp)
- return -EINVAL;
-
- temp = FAN_RPM_TO_PERIOD(temp);
- temp = SENSORS_LIMIT(temp, 1, 65534);
-
- mutex_lock(&data->lock);
- data->fan_min[attr->index] = temp;
- adt7473_write_word_data(client, ADT7473_REG_FAN_MIN(attr->index), temp);
- mutex_unlock(&data->lock);
-
- return count;
-}
-
-static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
-
- if (FAN_DATA_VALID(data->fan[attr->index]))
- return sprintf(buf, "%d\n",
- FAN_PERIOD_TO_RPM(data->fan[attr->index]));
- else
- return sprintf(buf, "0\n");
-}
-
-static ssize_t show_max_duty_at_crit(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
-{
- struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n", data->max_duty_at_overheat);
-}
-
-static ssize_t set_max_duty_at_crit(struct device *dev,
- struct device_attribute *devattr,
- const char *buf,
- size_t count)
-{
- u8 reg;
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- long temp;
-
- if (strict_strtol(buf, 10, &temp))
- return -EINVAL;
-
- mutex_lock(&data->lock);
- data->max_duty_at_overheat = !!temp;
- reg = i2c_smbus_read_byte_data(client, ADT7473_REG_CFG4);
- if (temp)
- reg |= ADT7473_CFG4_MAX_DUTY_AT_OVT;
- else
- reg &= ~ADT7473_CFG4_MAX_DUTY_AT_OVT;
- i2c_smbus_write_byte_data(client, ADT7473_REG_CFG4, reg);
- mutex_unlock(&data->lock);
-
- return count;
-}
-
-static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n", data->pwm[attr->index]);
-}
-
-static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
- const char *buf, size_t count)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- long temp;
-
- if (strict_strtol(buf, 10, &temp))
- return -EINVAL;
-
- temp = SENSORS_LIMIT(temp, 0, 255);
-
- mutex_lock(&data->lock);
- data->pwm[attr->index] = temp;
- i2c_smbus_write_byte_data(client, ADT7473_REG_PWM(attr->index), temp);
- mutex_unlock(&data->lock);
-
- return count;
-}
-
-static ssize_t show_pwm_max(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n", data->pwm_max[attr->index]);
-}
-
-static ssize_t set_pwm_max(struct device *dev,
- struct device_attribute *devattr,
- const char *buf,
- size_t count)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- long temp;
-
- if (strict_strtol(buf, 10, &temp))
- return -EINVAL;
-
- temp = SENSORS_LIMIT(temp, 0, 255);
-
- mutex_lock(&data->lock);
- data->pwm_max[attr->index] = temp;
- i2c_smbus_write_byte_data(client, ADT7473_REG_PWM_MAX(attr->index),
- temp);
- mutex_unlock(&data->lock);
-
- return count;
-}
-
-static ssize_t show_pwm_min(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n", data->pwm_min[attr->index]);
-}
-
-static ssize_t set_pwm_min(struct device *dev,
- struct device_attribute *devattr,
- const char *buf,
- size_t count)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- long temp;
-
- if (strict_strtol(buf, 10, &temp))
- return -EINVAL;
-
- temp = SENSORS_LIMIT(temp, 0, 255);
-
- mutex_lock(&data->lock);
- data->pwm_min[attr->index] = temp;
- i2c_smbus_write_byte_data(client, ADT7473_REG_PWM_MIN(attr->index),
- temp);
- mutex_unlock(&data->lock);
-
- return count;
-}
-
-static ssize_t show_temp_tmax(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n", 1000 * decode_temp(
- data->temp_twos_complement,
- data->temp_tmax[attr->index]));
-}
-
-static ssize_t set_temp_tmax(struct device *dev,
- struct device_attribute *devattr,
- const char *buf,
- size_t count)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- long temp;
-
- if (strict_strtol(buf, 10, &temp))
- return -EINVAL;
-
- temp = DIV_ROUND_CLOSEST(temp, 1000);
- temp = encode_temp(data->temp_twos_complement, temp);
-
- mutex_lock(&data->lock);
- data->temp_tmax[attr->index] = temp;
- i2c_smbus_write_byte_data(client, ADT7473_REG_TEMP_TMAX(attr->index),
- temp);
- mutex_unlock(&data->lock);
-
- return count;
-}
-
-static ssize_t show_temp_tmin(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n", 1000 * decode_temp(
- data->temp_twos_complement,
- data->temp_tmin[attr->index]));
-}
-
-static ssize_t set_temp_tmin(struct device *dev,
- struct device_attribute *devattr,
- const char *buf,
- size_t count)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- long temp;
-
- if (strict_strtol(buf, 10, &temp))
- return -EINVAL;
-
- temp = DIV_ROUND_CLOSEST(temp, 1000);
- temp = encode_temp(data->temp_twos_complement, temp);
-
- mutex_lock(&data->lock);
- data->temp_tmin[attr->index] = temp;
- i2c_smbus_write_byte_data(client, ADT7473_REG_TEMP_TMIN(attr->index),
- temp);
- mutex_unlock(&data->lock);
-
- return count;
-}
-
-static ssize_t show_pwm_enable(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
-
- switch (data->pwm_behavior[attr->index] >> ADT7473_PWM_BHVR_SHIFT) {
- case 3:
- return sprintf(buf, "0\n");
- case 7:
- return sprintf(buf, "1\n");
- default:
- return sprintf(buf, "2\n");
- }
-}
-
-static ssize_t set_pwm_enable(struct device *dev,
- struct device_attribute *devattr,
- const char *buf,
- size_t count)
-{
- u8 reg;
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- long temp;
-
- if (strict_strtol(buf, 10, &temp))
- return -EINVAL;
-
- switch (temp) {
- case 0:
- temp = 3;
- break;
- case 1:
- temp = 7;
- break;
- case 2:
- /* Enter automatic mode with fans off */
- temp = 4;
- break;
- default:
- return -EINVAL;
- }
-
- mutex_lock(&data->lock);
- reg = i2c_smbus_read_byte_data(client,
- ADT7473_REG_PWM_BHVR(attr->index));
- reg = (temp << ADT7473_PWM_BHVR_SHIFT) |
- (reg & ~ADT7473_PWM_BHVR_MASK);
- i2c_smbus_write_byte_data(client, ADT7473_REG_PWM_BHVR(attr->index),
- reg);
- data->pwm_behavior[attr->index] = reg;
- mutex_unlock(&data->lock);
-
- return count;
-}
-
-static ssize_t show_pwm_auto_temp(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
- int bhvr = data->pwm_behavior[attr->index] >> ADT7473_PWM_BHVR_SHIFT;
-
- switch (bhvr) {
- case 3:
- case 4:
- case 7:
- return sprintf(buf, "0\n");
- case 0:
- case 1:
- case 5:
- case 6:
- return sprintf(buf, "%d\n", bhvr + 1);
- case 2:
- return sprintf(buf, "4\n");
- }
- /* shouldn't ever get here */
- BUG();
-}
-
-static ssize_t set_pwm_auto_temp(struct device *dev,
- struct device_attribute *devattr,
- const char *buf,
- size_t count)
-{
- u8 reg;
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7473_data *data = i2c_get_clientdata(client);
- long temp;
-
- if (strict_strtol(buf, 10, &temp))
- return -EINVAL;
-
- switch (temp) {
- case 1:
- case 2:
- case 6:
- case 7:
- temp--;
- break;
- case 0:
- temp = 4;
- break;
- default:
- return -EINVAL;
- }
-
- mutex_lock(&data->lock);
- reg = i2c_smbus_read_byte_data(client,
- ADT7473_REG_PWM_BHVR(attr->index));
- reg = (temp << ADT7473_PWM_BHVR_SHIFT) |
- (reg & ~ADT7473_PWM_BHVR_MASK);
- i2c_smbus_write_byte_data(client, ADT7473_REG_PWM_BHVR(attr->index),
- reg);
- data->pwm_behavior[attr->index] = reg;
- mutex_unlock(&data->lock);
-
- return count;
-}
-
-static ssize_t show_alarm(struct device *dev,
- struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7473_data *data = adt7473_update_device(dev);
-
- if (data->alarm & attr->index)
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-
-static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, show_volt_max,
- set_volt_max, 0);
-static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, show_volt_max,
- set_volt_max, 1);
-
-static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, show_volt_min,
- set_volt_min, 0);
-static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, show_volt_min,
- set_volt_min, 1);
-
-static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_volt, NULL, 0);
-static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_volt, NULL, 1);
-
-static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL,
- ADT7473_VCCP_ALARM);
-static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL,
- ADT7473_VCC_ALARM);
-
-static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
- set_temp_max, 0);
-static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
- set_temp_max, 1);
-static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_max,
- set_temp_max, 2);
-
-static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
- set_temp_min, 0);
-static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
- set_temp_min, 1);
-static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_temp_min,
- set_temp_min, 2);
-
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
-
-static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL,
- ADT7473_R1T_ALARM | ALARM2(ADT7473_R1T_SHORT));
-static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL,
- ADT7473_LT_ALARM);
-static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL,
- ADT7473_R2T_ALARM | ALARM2(ADT7473_R2T_SHORT));
-
-static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
- set_fan_min, 0);
-static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
- set_fan_min, 1);
-static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
- set_fan_min, 2);
-static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
- set_fan_min, 3);
-
-static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
-static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
-static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
-static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
-
-static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL,
- ALARM2(ADT7473_FAN1_ALARM));
-static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL,
- ALARM2(ADT7473_FAN2_ALARM));
-static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL,
- ALARM2(ADT7473_FAN3_ALARM));
-static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL,
- ALARM2(ADT7473_FAN4_ALARM));
-
-static SENSOR_DEVICE_ATTR(pwm_use_point2_pwm_at_crit, S_IWUSR | S_IRUGO,
- show_max_duty_at_crit, set_max_duty_at_crit, 0);
-
-static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
-static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
-static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
-
-static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
- show_pwm_min, set_pwm_min, 0);
-static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
- show_pwm_min, set_pwm_min, 1);
-static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
- show_pwm_min, set_pwm_min, 2);
-
-static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
- show_pwm_max, set_pwm_max, 0);
-static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
- show_pwm_max, set_pwm_max, 1);
-static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
- show_pwm_max, set_pwm_max, 2);
-
-static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, S_IWUSR | S_IRUGO,
- show_temp_tmin, set_temp_tmin, 0);
-static SENSOR_DEVICE_ATTR(temp2_auto_point1_temp, S_IWUSR | S_IRUGO,
- show_temp_tmin, set_temp_tmin, 1);
-static SENSOR_DEVICE_ATTR(temp3_auto_point1_temp, S_IWUSR | S_IRUGO,
- show_temp_tmin, set_temp_tmin, 2);
-
-static SENSOR_DEVICE_ATTR(temp1_auto_point2_temp, S_IWUSR | S_IRUGO,
- show_temp_tmax, set_temp_tmax, 0);
-static SENSOR_DEVICE_ATTR(temp2_auto_point2_temp, S_IWUSR | S_IRUGO,
- show_temp_tmax, set_temp_tmax, 1);
-static SENSOR_DEVICE_ATTR(temp3_auto_point2_temp, S_IWUSR | S_IRUGO,
- show_temp_tmax, set_temp_tmax, 2);
-
-static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
- set_pwm_enable, 0);
-static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
- set_pwm_enable, 1);
-static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
- set_pwm_enable, 2);
-
-static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IWUSR | S_IRUGO,
- show_pwm_auto_temp, set_pwm_auto_temp, 0);
-static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IWUSR | S_IRUGO,
- show_pwm_auto_temp, set_pwm_auto_temp, 1);
-static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO,
- show_pwm_auto_temp, set_pwm_auto_temp, 2);
-
-static struct attribute *adt7473_attr[] =
-{
- &sensor_dev_attr_in1_max.dev_attr.attr,
- &sensor_dev_attr_in2_max.dev_attr.attr,
- &sensor_dev_attr_in1_min.dev_attr.attr,
- &sensor_dev_attr_in2_min.dev_attr.attr,
- &sensor_dev_attr_in1_input.dev_attr.attr,
- &sensor_dev_attr_in2_input.dev_attr.attr,
- &sensor_dev_attr_in1_alarm.dev_attr.attr,
- &sensor_dev_attr_in2_alarm.dev_attr.attr,
-
- &sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp2_max.dev_attr.attr,
- &sensor_dev_attr_temp3_max.dev_attr.attr,
- &sensor_dev_attr_temp1_min.dev_attr.attr,
- &sensor_dev_attr_temp2_min.dev_attr.attr,
- &sensor_dev_attr_temp3_min.dev_attr.attr,
- &sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp2_input.dev_attr.attr,
- &sensor_dev_attr_temp3_input.dev_attr.attr,
- &sensor_dev_attr_temp1_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_alarm.dev_attr.attr,
- &sensor_dev_attr_temp3_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
- &sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
- &sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr,
- &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
- &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
- &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
-
- &sensor_dev_attr_fan1_min.dev_attr.attr,
- &sensor_dev_attr_fan2_min.dev_attr.attr,
- &sensor_dev_attr_fan3_min.dev_attr.attr,
- &sensor_dev_attr_fan4_min.dev_attr.attr,
- &sensor_dev_attr_fan1_input.dev_attr.attr,
- &sensor_dev_attr_fan2_input.dev_attr.attr,
- &sensor_dev_attr_fan3_input.dev_attr.attr,
- &sensor_dev_attr_fan4_input.dev_attr.attr,
- &sensor_dev_attr_fan1_alarm.dev_attr.attr,
- &sensor_dev_attr_fan2_alarm.dev_attr.attr,
- &sensor_dev_attr_fan3_alarm.dev_attr.attr,
- &sensor_dev_attr_fan4_alarm.dev_attr.attr,
-
- &sensor_dev_attr_pwm_use_point2_pwm_at_crit.dev_attr.attr,
-
- &sensor_dev_attr_pwm1.dev_attr.attr,
- &sensor_dev_attr_pwm2.dev_attr.attr,
- &sensor_dev_attr_pwm3.dev_attr.attr,
- &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
- &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
- &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
- &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
- &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
- &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
-
- &sensor_dev_attr_pwm1_enable.dev_attr.attr,
- &sensor_dev_attr_pwm2_enable.dev_attr.attr,
- &sensor_dev_attr_pwm3_enable.dev_attr.attr,
- &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
- &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
- &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
-
- NULL
-};
-
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int adt7473_detect(struct i2c_client *client,
- struct i2c_board_info *info)
-{
- struct i2c_adapter *adapter = client->adapter;
- int vendor, device, revision;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -ENODEV;
-
- vendor = i2c_smbus_read_byte_data(client, ADT7473_REG_VENDOR);
- if (vendor != ADT7473_VENDOR)
- return -ENODEV;
-
- device = i2c_smbus_read_byte_data(client, ADT7473_REG_DEVICE);
- if (device != ADT7473_DEVICE)
- return -ENODEV;
-
- revision = i2c_smbus_read_byte_data(client, ADT7473_REG_REVISION);
- if (revision != ADT7473_REV_68 && revision != ADT7473_REV_69)
- return -ENODEV;
-
- strlcpy(info->type, "adt7473", I2C_NAME_SIZE);
-
- return 0;
-}
-
-static int adt7473_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct adt7473_data *data;
- int err;
-
- data = kzalloc(sizeof(struct adt7473_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
-
- i2c_set_clientdata(client, data);
- mutex_init(&data->lock);
-
- dev_info(&client->dev, "%s chip found\n", client->name);
-
- /* Initialize the ADT7473 chip */
- adt7473_init_client(client);
-
- /* Register sysfs hooks */
- data->attrs.attrs = adt7473_attr;
- err = sysfs_create_group(&client->dev.kobj, &data->attrs);
- if (err)
- goto exit_free;
-
- data->hwmon_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto exit_remove;
- }
-
- return 0;
-
-exit_remove:
- sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_free:
- kfree(data);
-exit:
- return err;
-}
-
-static int adt7473_remove(struct i2c_client *client)
-{
- struct adt7473_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &data->attrs);
- kfree(data);
- return 0;
-}
-
-static int __init adt7473_init(void)
-{
- pr_notice("The adt7473 driver is deprecated, please use the adt7475 "
- "driver instead\n");
- return i2c_add_driver(&adt7473_driver);
-}
-
-static void __exit adt7473_exit(void)
-{
- i2c_del_driver(&adt7473_driver);
-}
-
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
-MODULE_DESCRIPTION("ADT7473 driver");
-MODULE_LICENSE("GPL");
-
-module_init(adt7473_init);
-module_exit(adt7473_exit);
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c
index 1c89d922d619..fa9708c2d723 100644
--- a/drivers/hwmon/amc6821.c
+++ b/drivers/hwmon/amc6821.c
@@ -686,7 +686,6 @@ static ssize_t set_fan1_div(
data->fan1_div = 4;
break;
default:
- mutex_unlock(&data->update_lock);
count = -EINVAL;
goto EXIT;
}
diff --git a/drivers/hwmon/ams/ams-core.c b/drivers/hwmon/ams/ams-core.c
index 6c9ace1b76f6..2ad62c339cd2 100644
--- a/drivers/hwmon/ams/ams-core.c
+++ b/drivers/hwmon/ams/ams-core.c
@@ -213,7 +213,7 @@ int __init ams_init(void)
return -ENODEV;
}
-void ams_exit(void)
+void ams_sensor_detach(void)
{
/* Remove input device */
ams_input_exit();
@@ -221,9 +221,6 @@ void ams_exit(void)
/* Remove attributes */
device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
- /* Shut down implementation */
- ams_info.exit();
-
/* Flush interrupt worker
*
* We do this after ams_info.exit(), because an interrupt might
@@ -239,6 +236,12 @@ void ams_exit(void)
pmf_unregister_irq_client(&ams_freefall_client);
}
+static void __exit ams_exit(void)
+{
+ /* Shut down implementation */
+ ams_info.exit();
+}
+
MODULE_AUTHOR("Stelian Pop, Michael Hanselmann");
MODULE_DESCRIPTION("Apple Motion Sensor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ams/ams-i2c.c b/drivers/hwmon/ams/ams-i2c.c
index 2cbf8a6506c7..abeecd27b484 100644
--- a/drivers/hwmon/ams/ams-i2c.c
+++ b/drivers/hwmon/ams/ams-i2c.c
@@ -238,6 +238,8 @@ static int ams_i2c_probe(struct i2c_client *client,
static int ams_i2c_remove(struct i2c_client *client)
{
if (ams_info.has_device) {
+ ams_sensor_detach();
+
/* Disable interrupts */
ams_i2c_set_irq(AMS_IRQ_ALL, 0);
diff --git a/drivers/hwmon/ams/ams-pmu.c b/drivers/hwmon/ams/ams-pmu.c
index fb18b3d3162b..4f61b3ee1b08 100644
--- a/drivers/hwmon/ams/ams-pmu.c
+++ b/drivers/hwmon/ams/ams-pmu.c
@@ -133,6 +133,8 @@ static void ams_pmu_get_xyz(s8 *x, s8 *y, s8 *z)
static void ams_pmu_exit(void)
{
+ ams_sensor_detach();
+
/* Disable interrupts */
ams_pmu_set_irq(AMS_IRQ_ALL, 0);
diff --git a/drivers/hwmon/ams/ams.h b/drivers/hwmon/ams/ams.h
index 5ed387b0bd9a..b28d7e27a031 100644
--- a/drivers/hwmon/ams/ams.h
+++ b/drivers/hwmon/ams/ams.h
@@ -61,6 +61,7 @@ extern struct ams ams_info;
extern void ams_sensors(s8 *x, s8 *y, s8 *z);
extern int ams_sensor_attach(void);
+extern void ams_sensor_detach(void);
extern int ams_pmu_init(struct device_node *np);
extern int ams_i2c_init(struct device_node *np);
diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c
new file mode 100644
index 000000000000..7f948105d8ad
--- /dev/null
+++ b/drivers/hwmon/asc7621.c
@@ -0,0 +1,1255 @@
+/*
+ * asc7621.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
+ * Copyright (c) 2007, 2010 George Joseph <george.joseph@fairview5.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {
+ 0x2c, 0x2d, 0x2e, I2C_CLIENT_END
+};
+
+enum asc7621_type {
+ asc7621,
+ asc7621a
+};
+
+#define INTERVAL_HIGH (HZ + HZ / 2)
+#define INTERVAL_LOW (1 * 60 * HZ)
+#define PRI_NONE 0
+#define PRI_LOW 1
+#define PRI_HIGH 2
+#define FIRST_CHIP asc7621
+#define LAST_CHIP asc7621a
+
+struct asc7621_chip {
+ char *name;
+ enum asc7621_type chip_type;
+ u8 company_reg;
+ u8 company_id;
+ u8 verstep_reg;
+ u8 verstep_id;
+ unsigned short *addresses;
+};
+
+static struct asc7621_chip asc7621_chips[] = {
+ {
+ .name = "asc7621",
+ .chip_type = asc7621,
+ .company_reg = 0x3e,
+ .company_id = 0x61,
+ .verstep_reg = 0x3f,
+ .verstep_id = 0x6c,
+ .addresses = normal_i2c,
+ },
+ {
+ .name = "asc7621a",
+ .chip_type = asc7621a,
+ .company_reg = 0x3e,
+ .company_id = 0x61,
+ .verstep_reg = 0x3f,
+ .verstep_id = 0x6d,
+ .addresses = normal_i2c,
+ },
+};
+
+/*
+ * Defines the highest register to be used, not the count.
+ * The actual count will probably be smaller because of gaps
+ * in the implementation (unused register locations).
+ * This define will safely set the array size of both the parameter
+ * and data arrays.
+ * This comes from the data sheet register description table.
+ */
+#define LAST_REGISTER 0xff
+
+struct asc7621_data {
+ struct i2c_client client;
+ struct device *class_dev;
+ struct mutex update_lock;
+ int valid; /* !=0 if following fields are valid */
+ unsigned long last_high_reading; /* In jiffies */
+ unsigned long last_low_reading; /* In jiffies */
+ /*
+ * Registers we care about occupy the corresponding index
+ * in the array. Registers we don't care about are left
+ * at 0.
+ */
+ u8 reg[LAST_REGISTER + 1];
+};
+
+/*
+ * Macro to get the parent asc7621_param structure
+ * from a sensor_device_attribute passed into the
+ * show/store functions.
+ */
+#define to_asc7621_param(_sda) \
+ container_of(_sda, struct asc7621_param, sda)
+
+/*
+ * Each parameter to be retrieved needs an asc7621_param structure
+ * allocated. It contains the sensor_device_attribute structure
+ * and the control info needed to retrieve the value from the register map.
+ */
+struct asc7621_param {
+ struct sensor_device_attribute sda;
+ u8 priority;
+ u8 msb[3];
+ u8 lsb[3];
+ u8 mask[3];
+ u8 shift[3];
+};
+
+/*
+ * This is the map that ultimately indicates whether we'll be
+ * retrieving a register value or not, and at what frequency.
+ */
+static u8 asc7621_register_priorities[255];
+
+static struct asc7621_data *asc7621_update_device(struct device *dev);
+
+static inline u8 read_byte(struct i2c_client *client, u8 reg)
+{
+ int res = i2c_smbus_read_byte_data(client, reg);
+ if (res < 0) {
+ dev_err(&client->dev,
+ "Unable to read from register 0x%02x.\n", reg);
+ return 0;
+ };
+ return res & 0xff;
+}
+
+static inline int write_byte(struct i2c_client *client, u8 reg, u8 data)
+{
+ int res = i2c_smbus_write_byte_data(client, reg, data);
+ if (res < 0) {
+ dev_err(&client->dev,
+ "Unable to write value 0x%02x to register 0x%02x.\n",
+ data, reg);
+ };
+ return res;
+}
+
+/*
+ * Data Handlers
+ * Each function handles the formatting, storage
+ * and retrieval of like parameters.
+ */
+
+#define SETUP_SHOW_data_param(d, a) \
+ struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
+ struct asc7621_data *data = asc7621_update_device(d); \
+ struct asc7621_param *param = to_asc7621_param(sda)
+
+#define SETUP_STORE_data_param(d, a) \
+ struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
+ struct i2c_client *client = to_i2c_client(d); \
+ struct asc7621_data *data = i2c_get_clientdata(client); \
+ struct asc7621_param *param = to_asc7621_param(sda)
+
+/*
+ * u8 is just what it sounds like...an unsigned byte with no
+ * special formatting.
+ */
+static ssize_t show_u8(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+
+ return sprintf(buf, "%u\n", data->reg[param->msb[0]]);
+}
+
+static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ SETUP_STORE_data_param(dev, attr);
+ long reqval;
+
+ if (strict_strtol(buf, 10, &reqval))
+ return -EINVAL;
+
+ reqval = SENSORS_LIMIT(reqval, 0, 255);
+
+ mutex_lock(&data->update_lock);
+ data->reg[param->msb[0]] = reqval;
+ write_byte(client, param->msb[0], reqval);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/*
+ * Many of the config values occupy only a few bits of a register.
+ */
+static ssize_t show_bitmask(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+
+ return sprintf(buf, "%u\n",
+ (data->reg[param->msb[0]] >> param->
+ shift[0]) & param->mask[0]);
+}
+
+static ssize_t store_bitmask(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ SETUP_STORE_data_param(dev, attr);
+ long reqval;
+ u8 currval;
+
+ if (strict_strtol(buf, 10, &reqval))
+ return -EINVAL;
+
+ reqval = SENSORS_LIMIT(reqval, 0, param->mask[0]);
+
+ reqval = (reqval & param->mask[0]) << param->shift[0];
+
+ mutex_lock(&data->update_lock);
+ currval = read_byte(client, param->msb[0]);
+ reqval |= (currval & ~(param->mask[0] << param->shift[0]));
+ data->reg[param->msb[0]] = reqval;
+ write_byte(client, param->msb[0], reqval);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/*
+ * 16 bit fan rpm values
+ * reported by the device as the number of 11.111us periods (90khz)
+ * between full fan rotations. Therefore...
+ * RPM = (90000 * 60) / register value
+ */
+static ssize_t show_fan16(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+ u16 regval;
+
+ mutex_lock(&data->update_lock);
+ regval = (data->reg[param->msb[0]] << 8) | data->reg[param->lsb[0]];
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%u\n",
+ (regval == 0 ? -1 : (regval) ==
+ 0xffff ? 0 : 5400000 / regval));
+}
+
+static ssize_t store_fan16(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ SETUP_STORE_data_param(dev, attr);
+ long reqval;
+
+ if (strict_strtol(buf, 10, &reqval))
+ return -EINVAL;
+
+ reqval =
+ (SENSORS_LIMIT((reqval) <= 0 ? 0 : 5400000 / (reqval), 0, 65534));
+
+ mutex_lock(&data->update_lock);
+ data->reg[param->msb[0]] = (reqval >> 8) & 0xff;
+ data->reg[param->lsb[0]] = reqval & 0xff;
+ write_byte(client, param->msb[0], data->reg[param->msb[0]]);
+ write_byte(client, param->lsb[0], data->reg[param->lsb[0]]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/*
+ * Voltages are scaled in the device so that the nominal voltage
+ * is 3/4ths of the 0-255 range (i.e. 192).
+ * If all voltages are 'normal' then all voltage registers will
+ * read 0xC0. This doesn't help us if we don't have a point of refernce.
+ * The data sheet however provides us with the full scale value for each
+ * which is stored in in_scaling. The sda->index parameter value provides
+ * the index into in_scaling.
+ *
+ * NOTE: The chip expects the first 2 inputs be 2.5 and 2.25 volts
+ * respectively. That doesn't mean that's what the motherboard provides. :)
+ */
+
+static int asc7621_in_scaling[] = {
+ 3320, 3000, 4380, 6640, 16000
+};
+
+static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+ u16 regval;
+ u8 nr = sda->index;
+
+ mutex_lock(&data->update_lock);
+ regval = (data->reg[param->msb[0]] * asc7621_in_scaling[nr]) / 256;
+
+ /* The LSB value is a 2-bit scaling of the MSB's LSbit value.
+ * I.E. If the maximim voltage for this input is 6640 millivolts then
+ * a MSB register value of 0 = 0mv and 255 = 6640mv.
+ * A 1 step change therefore represents 25.9mv (6640 / 256).
+ * The extra 2-bits therefore represent increments of 6.48mv.
+ */
+ regval += ((asc7621_in_scaling[nr] / 256) / 4) *
+ (data->reg[param->lsb[0]] >> 6);
+
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%u\n", regval);
+}
+
+/* 8 bit voltage values (the mins and maxs) */
+static ssize_t show_in8(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+ u8 nr = sda->index;
+
+ return sprintf(buf, "%u\n",
+ ((data->reg[param->msb[0]] *
+ asc7621_in_scaling[nr]) / 256));
+}
+
+static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ SETUP_STORE_data_param(dev, attr);
+ long reqval;
+ u8 nr = sda->index;
+
+ if (strict_strtol(buf, 10, &reqval))
+ return -EINVAL;
+
+ reqval = SENSORS_LIMIT(reqval, 0, asc7621_in_scaling[nr]);
+
+ reqval = (reqval * 255 + 128) / asc7621_in_scaling[nr];
+
+ mutex_lock(&data->update_lock);
+ data->reg[param->msb[0]] = reqval;
+ write_byte(client, param->msb[0], reqval);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_temp8(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+
+ return sprintf(buf, "%d\n", ((s8) data->reg[param->msb[0]]) * 1000);
+}
+
+static ssize_t store_temp8(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ SETUP_STORE_data_param(dev, attr);
+ long reqval;
+ s8 temp;
+
+ if (strict_strtol(buf, 10, &reqval))
+ return -EINVAL;
+
+ reqval = SENSORS_LIMIT(reqval, -127000, 127000);
+
+ temp = reqval / 1000;
+
+ mutex_lock(&data->update_lock);
+ data->reg[param->msb[0]] = temp;
+ write_byte(client, param->msb[0], temp);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/*
+ * Temperatures that occupy 2 bytes always have the whole
+ * number of degrees in the MSB with some part of the LSB
+ * indicating fractional degrees.
+ */
+
+/* mmmmmmmm.llxxxxxx */
+static ssize_t show_temp10(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+ u8 msb, lsb;
+ int temp;
+
+ mutex_lock(&data->update_lock);
+ msb = data->reg[param->msb[0]];
+ lsb = (data->reg[param->lsb[0]] >> 6) & 0x03;
+ temp = (((s8) msb) * 1000) + (lsb * 250);
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%d\n", temp);
+}
+
+/* mmmmmm.ll */
+static ssize_t show_temp62(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+ u8 regval = data->reg[param->msb[0]];
+ int temp = ((s8) (regval & 0xfc) * 1000) + ((regval & 0x03) * 250);
+
+ return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t store_temp62(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ SETUP_STORE_data_param(dev, attr);
+ long reqval, i, f;
+ s8 temp;
+
+ if (strict_strtol(buf, 10, &reqval))
+ return -EINVAL;
+
+ reqval = SENSORS_LIMIT(reqval, -32000, 31750);
+ i = reqval / 1000;
+ f = reqval - (i * 1000);
+ temp = i << 2;
+ temp |= f / 250;
+
+ mutex_lock(&data->update_lock);
+ data->reg[param->msb[0]] = temp;
+ write_byte(client, param->msb[0], temp);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/*
+ * The aSC7621 doesn't provide an "auto_point2". Instead, you
+ * specify the auto_point1 and a range. To keep with the sysfs
+ * hwmon specs, we synthesize the auto_point_2 from them.
+ */
+
+static u32 asc7621_range_map[] = {
+ 2000, 2500, 3330, 4000, 5000, 6670, 8000, 10000,
+ 13330, 16000, 20000, 26670, 32000, 40000, 53330, 80000,
+};
+
+static ssize_t show_ap2_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+ long auto_point1;
+ u8 regval;
+ int temp;
+
+ mutex_lock(&data->update_lock);
+ auto_point1 = ((s8) data->reg[param->msb[1]]) * 1000;
+ regval =
+ ((data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]);
+ temp = auto_point1 + asc7621_range_map[SENSORS_LIMIT(regval, 0, 15)];
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%d\n", temp);
+
+}
+
+static ssize_t store_ap2_temp(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ SETUP_STORE_data_param(dev, attr);
+ long reqval, auto_point1;
+ int i;
+ u8 currval, newval = 0;
+
+ if (strict_strtol(buf, 10, &reqval))
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ auto_point1 = data->reg[param->msb[1]] * 1000;
+ reqval = SENSORS_LIMIT(reqval, auto_point1 + 2000, auto_point1 + 80000);
+
+ for (i = ARRAY_SIZE(asc7621_range_map) - 1; i >= 0; i--) {
+ if (reqval >= auto_point1 + asc7621_range_map[i]) {
+ newval = i;
+ break;
+ }
+ }
+
+ newval = (newval & param->mask[0]) << param->shift[0];
+ currval = read_byte(client, param->msb[0]);
+ newval |= (currval & ~(param->mask[0] << param->shift[0]));
+ data->reg[param->msb[0]] = newval;
+ write_byte(client, param->msb[0], newval);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_pwm_ac(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+ u8 config, altbit, regval;
+ u8 map[] = {
+ 0x01, 0x02, 0x04, 0x1f, 0x00, 0x06, 0x07, 0x10,
+ 0x08, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
+ };
+
+ mutex_lock(&data->update_lock);
+ config = (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
+ altbit = (data->reg[param->msb[1]] >> param->shift[1]) & param->mask[1];
+ regval = config | (altbit << 3);
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%u\n", map[SENSORS_LIMIT(regval, 0, 15)]);
+}
+
+static ssize_t store_pwm_ac(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ SETUP_STORE_data_param(dev, attr);
+ unsigned long reqval;
+ u8 currval, config, altbit, newval;
+ u16 map[] = {
+ 0x04, 0x00, 0x01, 0xff, 0x02, 0xff, 0x05, 0x06,
+ 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
+ 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
+ };
+
+ if (strict_strtoul(buf, 10, &reqval))
+ return -EINVAL;
+
+ if (reqval > 31)
+ return -EINVAL;
+
+ reqval = map[reqval];
+ if (reqval == 0xff)
+ return -EINVAL;
+
+ config = reqval & 0x07;
+ altbit = (reqval >> 3) & 0x01;
+
+ config = (config & param->mask[0]) << param->shift[0];
+ altbit = (altbit & param->mask[1]) << param->shift[1];
+
+ mutex_lock(&data->update_lock);
+ currval = read_byte(client, param->msb[0]);
+ newval = config | (currval & ~(param->mask[0] << param->shift[0]));
+ newval = altbit | (newval & ~(param->mask[1] << param->shift[1]));
+ data->reg[param->msb[0]] = newval;
+ write_byte(client, param->msb[0], newval);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+ u8 config, altbit, minoff, val, newval;
+
+ mutex_lock(&data->update_lock);
+ config = (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
+ altbit = (data->reg[param->msb[1]] >> param->shift[1]) & param->mask[1];
+ minoff = (data->reg[param->msb[2]] >> param->shift[2]) & param->mask[2];
+ mutex_unlock(&data->update_lock);
+
+ val = config | (altbit << 3);
+ newval = 0;
+
+ if (val == 3 || val >= 10)
+ newval = 255;
+ else if (val == 4)
+ newval = 0;
+ else if (val == 7)
+ newval = 1;
+ else if (minoff == 1)
+ newval = 2;
+ else
+ newval = 3;
+
+ return sprintf(buf, "%u\n", newval);
+}
+
+static ssize_t store_pwm_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ SETUP_STORE_data_param(dev, attr);
+ long reqval;
+ u8 currval, config, altbit, newval, minoff = 255;
+
+ if (strict_strtol(buf, 10, &reqval))
+ return -EINVAL;
+
+ switch (reqval) {
+ case 0:
+ newval = 0x04;
+ break;
+ case 1:
+ newval = 0x07;
+ break;
+ case 2:
+ newval = 0x00;
+ minoff = 1;
+ break;
+ case 3:
+ newval = 0x00;
+ minoff = 0;
+ break;
+ case 255:
+ newval = 0x03;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ config = newval & 0x07;
+ altbit = (newval >> 3) & 0x01;
+
+ mutex_lock(&data->update_lock);
+ config = (config & param->mask[0]) << param->shift[0];
+ altbit = (altbit & param->mask[1]) << param->shift[1];
+ currval = read_byte(client, param->msb[0]);
+ newval = config | (currval & ~(param->mask[0] << param->shift[0]));
+ newval = altbit | (newval & ~(param->mask[1] << param->shift[1]));
+ data->reg[param->msb[0]] = newval;
+ write_byte(client, param->msb[0], newval);
+ if (minoff < 255) {
+ minoff = (minoff & param->mask[2]) << param->shift[2];
+ currval = read_byte(client, param->msb[2]);
+ newval =
+ minoff | (currval & ~(param->mask[2] << param->shift[2]));
+ data->reg[param->msb[2]] = newval;
+ write_byte(client, param->msb[2], newval);
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static u32 asc7621_pwm_freq_map[] = {
+ 10, 15, 23, 30, 38, 47, 62, 94,
+ 23000, 24000, 25000, 26000, 27000, 28000, 29000, 30000
+};
+
+static ssize_t show_pwm_freq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+ u8 regval =
+ (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
+
+ regval = SENSORS_LIMIT(regval, 0, 15);
+
+ return sprintf(buf, "%u\n", asc7621_pwm_freq_map[regval]);
+}
+
+static ssize_t store_pwm_freq(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ SETUP_STORE_data_param(dev, attr);
+ unsigned long reqval;
+ u8 currval, newval = 255;
+ int i;
+
+ if (strict_strtoul(buf, 10, &reqval))
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(asc7621_pwm_freq_map); i++) {
+ if (reqval == asc7621_pwm_freq_map[i]) {
+ newval = i;
+ break;
+ }
+ }
+ if (newval == 255)
+ return -EINVAL;
+
+ newval = (newval & param->mask[0]) << param->shift[0];
+
+ mutex_lock(&data->update_lock);
+ currval = read_byte(client, param->msb[0]);
+ newval |= (currval & ~(param->mask[0] << param->shift[0]));
+ data->reg[param->msb[0]] = newval;
+ write_byte(client, param->msb[0], newval);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static u32 asc7621_pwm_auto_spinup_map[] = {
+ 0, 100, 250, 400, 700, 1000, 2000, 4000
+};
+
+static ssize_t show_pwm_ast(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+ u8 regval =
+ (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
+
+ regval = SENSORS_LIMIT(regval, 0, 7);
+
+ return sprintf(buf, "%u\n", asc7621_pwm_auto_spinup_map[regval]);
+
+}
+
+static ssize_t store_pwm_ast(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ SETUP_STORE_data_param(dev, attr);
+ long reqval;
+ u8 currval, newval = 255;
+ u32 i;
+
+ if (strict_strtol(buf, 10, &reqval))
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(asc7621_pwm_auto_spinup_map); i++) {
+ if (reqval == asc7621_pwm_auto_spinup_map[i]) {
+ newval = i;
+ break;
+ }
+ }
+ if (newval == 255)
+ return -EINVAL;
+
+ newval = (newval & param->mask[0]) << param->shift[0];
+
+ mutex_lock(&data->update_lock);
+ currval = read_byte(client, param->msb[0]);
+ newval |= (currval & ~(param->mask[0] << param->shift[0]));
+ data->reg[param->msb[0]] = newval;
+ write_byte(client, param->msb[0], newval);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static u32 asc7621_temp_smoothing_time_map[] = {
+ 35000, 17600, 11800, 7000, 4400, 3000, 1600, 800
+};
+
+static ssize_t show_temp_st(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ SETUP_SHOW_data_param(dev, attr);
+ u8 regval =
+ (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
+ regval = SENSORS_LIMIT(regval, 0, 7);
+
+ return sprintf(buf, "%u\n", asc7621_temp_smoothing_time_map[regval]);
+}
+
+static ssize_t store_temp_st(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ SETUP_STORE_data_param(dev, attr);
+ long reqval;
+ u8 currval, newval = 255;
+ u32 i;
+
+ if (strict_strtol(buf, 10, &reqval))
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(asc7621_temp_smoothing_time_map); i++) {
+ if (reqval == asc7621_temp_smoothing_time_map[i]) {
+ newval = i;
+ break;
+ }
+ }
+
+ if (newval == 255)
+ return -EINVAL;
+
+ newval = (newval & param->mask[0]) << param->shift[0];
+
+ mutex_lock(&data->update_lock);
+ currval = read_byte(client, param->msb[0]);
+ newval |= (currval & ~(param->mask[0] << param->shift[0]));
+ data->reg[param->msb[0]] = newval;
+ write_byte(client, param->msb[0], newval);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/*
+ * End of data handlers
+ *
+ * These defines do nothing more than make the table easier
+ * to read when wrapped at column 80.
+ */
+
+/*
+ * Creates a variable length array inititalizer.
+ * VAA(1,3,5,7) would produce {1,3,5,7}
+ */
+#define VAA(args...) {args}
+
+#define PREAD(name, n, pri, rm, rl, m, s, r) \
+ {.sda = SENSOR_ATTR(name, S_IRUGO, show_##r, NULL, n), \
+ .priority = pri, .msb[0] = rm, .lsb[0] = rl, .mask[0] = m, \
+ .shift[0] = s,}
+
+#define PWRITE(name, n, pri, rm, rl, m, s, r) \
+ {.sda = SENSOR_ATTR(name, S_IRUGO | S_IWUSR, show_##r, store_##r, n), \
+ .priority = pri, .msb[0] = rm, .lsb[0] = rl, .mask[0] = m, \
+ .shift[0] = s,}
+
+/*
+ * PWRITEM assumes that the initializers for the .msb, .lsb, .mask and .shift
+ * were created using the VAA macro.
+ */
+#define PWRITEM(name, n, pri, rm, rl, m, s, r) \
+ {.sda = SENSOR_ATTR(name, S_IRUGO | S_IWUSR, show_##r, store_##r, n), \
+ .priority = pri, .msb = rm, .lsb = rl, .mask = m, .shift = s,}
+
+static struct asc7621_param asc7621_params[] = {
+ PREAD(in0_input, 0, PRI_HIGH, 0x20, 0x13, 0, 0, in10),
+ PREAD(in1_input, 1, PRI_HIGH, 0x21, 0x18, 0, 0, in10),
+ PREAD(in2_input, 2, PRI_HIGH, 0x22, 0x11, 0, 0, in10),
+ PREAD(in3_input, 3, PRI_HIGH, 0x23, 0x12, 0, 0, in10),
+ PREAD(in4_input, 4, PRI_HIGH, 0x24, 0x14, 0, 0, in10),
+
+ PWRITE(in0_min, 0, PRI_LOW, 0x44, 0, 0, 0, in8),
+ PWRITE(in1_min, 1, PRI_LOW, 0x46, 0, 0, 0, in8),
+ PWRITE(in2_min, 2, PRI_LOW, 0x48, 0, 0, 0, in8),
+ PWRITE(in3_min, 3, PRI_LOW, 0x4a, 0, 0, 0, in8),
+ PWRITE(in4_min, 4, PRI_LOW, 0x4c, 0, 0, 0, in8),
+
+ PWRITE(in0_max, 0, PRI_LOW, 0x45, 0, 0, 0, in8),
+ PWRITE(in1_max, 1, PRI_LOW, 0x47, 0, 0, 0, in8),
+ PWRITE(in2_max, 2, PRI_LOW, 0x49, 0, 0, 0, in8),
+ PWRITE(in3_max, 3, PRI_LOW, 0x4b, 0, 0, 0, in8),
+ PWRITE(in4_max, 4, PRI_LOW, 0x4d, 0, 0, 0, in8),
+
+ PREAD(in0_alarm, 0, PRI_LOW, 0x41, 0, 0x01, 0, bitmask),
+ PREAD(in1_alarm, 1, PRI_LOW, 0x41, 0, 0x01, 1, bitmask),
+ PREAD(in2_alarm, 2, PRI_LOW, 0x41, 0, 0x01, 2, bitmask),
+ PREAD(in3_alarm, 3, PRI_LOW, 0x41, 0, 0x01, 3, bitmask),
+ PREAD(in4_alarm, 4, PRI_LOW, 0x42, 0, 0x01, 0, bitmask),
+
+ PREAD(fan1_input, 0, PRI_HIGH, 0x29, 0x28, 0, 0, fan16),
+ PREAD(fan2_input, 1, PRI_HIGH, 0x2b, 0x2a, 0, 0, fan16),
+ PREAD(fan3_input, 2, PRI_HIGH, 0x2d, 0x2c, 0, 0, fan16),
+ PREAD(fan4_input, 3, PRI_HIGH, 0x2f, 0x2e, 0, 0, fan16),
+
+ PWRITE(fan1_min, 0, PRI_LOW, 0x55, 0x54, 0, 0, fan16),
+ PWRITE(fan2_min, 1, PRI_LOW, 0x57, 0x56, 0, 0, fan16),
+ PWRITE(fan3_min, 2, PRI_LOW, 0x59, 0x58, 0, 0, fan16),
+ PWRITE(fan4_min, 3, PRI_LOW, 0x5b, 0x5a, 0, 0, fan16),
+
+ PREAD(fan1_alarm, 0, PRI_LOW, 0x42, 0, 0x01, 0, bitmask),
+ PREAD(fan2_alarm, 1, PRI_LOW, 0x42, 0, 0x01, 1, bitmask),
+ PREAD(fan3_alarm, 2, PRI_LOW, 0x42, 0, 0x01, 2, bitmask),
+ PREAD(fan4_alarm, 3, PRI_LOW, 0x42, 0, 0x01, 3, bitmask),
+
+ PREAD(temp1_input, 0, PRI_HIGH, 0x25, 0x10, 0, 0, temp10),
+ PREAD(temp2_input, 1, PRI_HIGH, 0x26, 0x15, 0, 0, temp10),
+ PREAD(temp3_input, 2, PRI_HIGH, 0x27, 0x16, 0, 0, temp10),
+ PREAD(temp4_input, 3, PRI_HIGH, 0x33, 0x17, 0, 0, temp10),
+ PREAD(temp5_input, 4, PRI_HIGH, 0xf7, 0xf6, 0, 0, temp10),
+ PREAD(temp6_input, 5, PRI_HIGH, 0xf9, 0xf8, 0, 0, temp10),
+ PREAD(temp7_input, 6, PRI_HIGH, 0xfb, 0xfa, 0, 0, temp10),
+ PREAD(temp8_input, 7, PRI_HIGH, 0xfd, 0xfc, 0, 0, temp10),
+
+ PWRITE(temp1_min, 0, PRI_LOW, 0x4e, 0, 0, 0, temp8),
+ PWRITE(temp2_min, 1, PRI_LOW, 0x50, 0, 0, 0, temp8),
+ PWRITE(temp3_min, 2, PRI_LOW, 0x52, 0, 0, 0, temp8),
+ PWRITE(temp4_min, 3, PRI_LOW, 0x34, 0, 0, 0, temp8),
+
+ PWRITE(temp1_max, 0, PRI_LOW, 0x4f, 0, 0, 0, temp8),
+ PWRITE(temp2_max, 1, PRI_LOW, 0x51, 0, 0, 0, temp8),
+ PWRITE(temp3_max, 2, PRI_LOW, 0x53, 0, 0, 0, temp8),
+ PWRITE(temp4_max, 3, PRI_LOW, 0x35, 0, 0, 0, temp8),
+
+ PREAD(temp1_alarm, 0, PRI_LOW, 0x41, 0, 0x01, 4, bitmask),
+ PREAD(temp2_alarm, 1, PRI_LOW, 0x41, 0, 0x01, 5, bitmask),
+ PREAD(temp3_alarm, 2, PRI_LOW, 0x41, 0, 0x01, 6, bitmask),
+ PREAD(temp4_alarm, 3, PRI_LOW, 0x43, 0, 0x01, 0, bitmask),
+
+ PWRITE(temp1_source, 0, PRI_LOW, 0x02, 0, 0x07, 4, bitmask),
+ PWRITE(temp2_source, 1, PRI_LOW, 0x02, 0, 0x07, 0, bitmask),
+ PWRITE(temp3_source, 2, PRI_LOW, 0x03, 0, 0x07, 4, bitmask),
+ PWRITE(temp4_source, 3, PRI_LOW, 0x03, 0, 0x07, 0, bitmask),
+
+ PWRITE(temp1_smoothing_enable, 0, PRI_LOW, 0x62, 0, 0x01, 3, bitmask),
+ PWRITE(temp2_smoothing_enable, 1, PRI_LOW, 0x63, 0, 0x01, 7, bitmask),
+ PWRITE(temp3_smoothing_enable, 2, PRI_LOW, 0x64, 0, 0x01, 3, bitmask),
+ PWRITE(temp4_smoothing_enable, 3, PRI_LOW, 0x3c, 0, 0x01, 3, bitmask),
+
+ PWRITE(temp1_smoothing_time, 0, PRI_LOW, 0x62, 0, 0x07, 0, temp_st),
+ PWRITE(temp2_smoothing_time, 1, PRI_LOW, 0x63, 0, 0x07, 4, temp_st),
+ PWRITE(temp3_smoothing_time, 2, PRI_LOW, 0x63, 0, 0x07, 0, temp_st),
+ PWRITE(temp4_smoothing_time, 3, PRI_LOW, 0x3c, 0, 0x07, 0, temp_st),
+
+ PWRITE(temp1_auto_point1_temp_hyst, 0, PRI_LOW, 0x6d, 0, 0x0f, 4,
+ bitmask),
+ PWRITE(temp2_auto_point1_temp_hyst, 1, PRI_LOW, 0x6d, 0, 0x0f, 0,
+ bitmask),
+ PWRITE(temp3_auto_point1_temp_hyst, 2, PRI_LOW, 0x6e, 0, 0x0f, 4,
+ bitmask),
+ PWRITE(temp4_auto_point1_temp_hyst, 3, PRI_LOW, 0x6e, 0, 0x0f, 0,
+ bitmask),
+
+ PREAD(temp1_auto_point2_temp_hyst, 0, PRI_LOW, 0x6d, 0, 0x0f, 4,
+ bitmask),
+ PREAD(temp2_auto_point2_temp_hyst, 1, PRI_LOW, 0x6d, 0, 0x0f, 0,
+ bitmask),
+ PREAD(temp3_auto_point2_temp_hyst, 2, PRI_LOW, 0x6e, 0, 0x0f, 4,
+ bitmask),
+ PREAD(temp4_auto_point2_temp_hyst, 3, PRI_LOW, 0x6e, 0, 0x0f, 0,
+ bitmask),
+
+ PWRITE(temp1_auto_point1_temp, 0, PRI_LOW, 0x67, 0, 0, 0, temp8),
+ PWRITE(temp2_auto_point1_temp, 1, PRI_LOW, 0x68, 0, 0, 0, temp8),
+ PWRITE(temp3_auto_point1_temp, 2, PRI_LOW, 0x69, 0, 0, 0, temp8),
+ PWRITE(temp4_auto_point1_temp, 3, PRI_LOW, 0x3b, 0, 0, 0, temp8),
+
+ PWRITEM(temp1_auto_point2_temp, 0, PRI_LOW, VAA(0x5f, 0x67), VAA(0),
+ VAA(0x0f), VAA(4), ap2_temp),
+ PWRITEM(temp2_auto_point2_temp, 1, PRI_LOW, VAA(0x60, 0x68), VAA(0),
+ VAA(0x0f), VAA(4), ap2_temp),
+ PWRITEM(temp3_auto_point2_temp, 2, PRI_LOW, VAA(0x61, 0x69), VAA(0),
+ VAA(0x0f), VAA(4), ap2_temp),
+ PWRITEM(temp4_auto_point2_temp, 3, PRI_LOW, VAA(0x3c, 0x3b), VAA(0),
+ VAA(0x0f), VAA(4), ap2_temp),
+
+ PWRITE(temp1_crit, 0, PRI_LOW, 0x6a, 0, 0, 0, temp8),
+ PWRITE(temp2_crit, 1, PRI_LOW, 0x6b, 0, 0, 0, temp8),
+ PWRITE(temp3_crit, 2, PRI_LOW, 0x6c, 0, 0, 0, temp8),
+ PWRITE(temp4_crit, 3, PRI_LOW, 0x3d, 0, 0, 0, temp8),
+
+ PWRITE(temp5_enable, 4, PRI_LOW, 0x0e, 0, 0x01, 0, bitmask),
+ PWRITE(temp6_enable, 5, PRI_LOW, 0x0e, 0, 0x01, 1, bitmask),
+ PWRITE(temp7_enable, 6, PRI_LOW, 0x0e, 0, 0x01, 2, bitmask),
+ PWRITE(temp8_enable, 7, PRI_LOW, 0x0e, 0, 0x01, 3, bitmask),
+
+ PWRITE(remote1_offset, 0, PRI_LOW, 0x1c, 0, 0, 0, temp62),
+ PWRITE(remote2_offset, 1, PRI_LOW, 0x1d, 0, 0, 0, temp62),
+
+ PWRITE(pwm1, 0, PRI_HIGH, 0x30, 0, 0, 0, u8),
+ PWRITE(pwm2, 1, PRI_HIGH, 0x31, 0, 0, 0, u8),
+ PWRITE(pwm3, 2, PRI_HIGH, 0x32, 0, 0, 0, u8),
+
+ PWRITE(pwm1_invert, 0, PRI_LOW, 0x5c, 0, 0x01, 4, bitmask),
+ PWRITE(pwm2_invert, 1, PRI_LOW, 0x5d, 0, 0x01, 4, bitmask),
+ PWRITE(pwm3_invert, 2, PRI_LOW, 0x5e, 0, 0x01, 4, bitmask),
+
+ PWRITEM(pwm1_enable, 0, PRI_LOW, VAA(0x5c, 0x5c, 0x62), VAA(0, 0, 0),
+ VAA(0x07, 0x01, 0x01), VAA(5, 3, 5), pwm_enable),
+ PWRITEM(pwm2_enable, 1, PRI_LOW, VAA(0x5d, 0x5d, 0x62), VAA(0, 0, 0),
+ VAA(0x07, 0x01, 0x01), VAA(5, 3, 6), pwm_enable),
+ PWRITEM(pwm3_enable, 2, PRI_LOW, VAA(0x5e, 0x5e, 0x62), VAA(0, 0, 0),
+ VAA(0x07, 0x01, 0x01), VAA(5, 3, 7), pwm_enable),
+
+ PWRITEM(pwm1_auto_channels, 0, PRI_LOW, VAA(0x5c, 0x5c), VAA(0, 0),
+ VAA(0x07, 0x01), VAA(5, 3), pwm_ac),
+ PWRITEM(pwm2_auto_channels, 1, PRI_LOW, VAA(0x5d, 0x5d), VAA(0, 0),
+ VAA(0x07, 0x01), VAA(5, 3), pwm_ac),
+ PWRITEM(pwm3_auto_channels, 2, PRI_LOW, VAA(0x5e, 0x5e), VAA(0, 0),
+ VAA(0x07, 0x01), VAA(5, 3), pwm_ac),
+
+ PWRITE(pwm1_auto_point1_pwm, 0, PRI_LOW, 0x64, 0, 0, 0, u8),
+ PWRITE(pwm2_auto_point1_pwm, 1, PRI_LOW, 0x65, 0, 0, 0, u8),
+ PWRITE(pwm3_auto_point1_pwm, 2, PRI_LOW, 0x66, 0, 0, 0, u8),
+
+ PWRITE(pwm1_auto_point2_pwm, 0, PRI_LOW, 0x38, 0, 0, 0, u8),
+ PWRITE(pwm2_auto_point2_pwm, 1, PRI_LOW, 0x39, 0, 0, 0, u8),
+ PWRITE(pwm3_auto_point2_pwm, 2, PRI_LOW, 0x3a, 0, 0, 0, u8),
+
+ PWRITE(pwm1_freq, 0, PRI_LOW, 0x5f, 0, 0x0f, 0, pwm_freq),
+ PWRITE(pwm2_freq, 1, PRI_LOW, 0x60, 0, 0x0f, 0, pwm_freq),
+ PWRITE(pwm3_freq, 2, PRI_LOW, 0x61, 0, 0x0f, 0, pwm_freq),
+
+ PREAD(pwm1_auto_zone_assigned, 0, PRI_LOW, 0, 0, 0x03, 2, bitmask),
+ PREAD(pwm2_auto_zone_assigned, 1, PRI_LOW, 0, 0, 0x03, 4, bitmask),
+ PREAD(pwm3_auto_zone_assigned, 2, PRI_LOW, 0, 0, 0x03, 6, bitmask),
+
+ PWRITE(pwm1_auto_spinup_time, 0, PRI_LOW, 0x5c, 0, 0x07, 0, pwm_ast),
+ PWRITE(pwm2_auto_spinup_time, 1, PRI_LOW, 0x5d, 0, 0x07, 0, pwm_ast),
+ PWRITE(pwm3_auto_spinup_time, 2, PRI_LOW, 0x5e, 0, 0x07, 0, pwm_ast),
+
+ PWRITE(peci_enable, 0, PRI_LOW, 0x40, 0, 0x01, 4, bitmask),
+ PWRITE(peci_avg, 0, PRI_LOW, 0x36, 0, 0x07, 0, bitmask),
+ PWRITE(peci_domain, 0, PRI_LOW, 0x36, 0, 0x01, 3, bitmask),
+ PWRITE(peci_legacy, 0, PRI_LOW, 0x36, 0, 0x01, 4, bitmask),
+ PWRITE(peci_diode, 0, PRI_LOW, 0x0e, 0, 0x07, 4, bitmask),
+ PWRITE(peci_4domain, 0, PRI_LOW, 0x0e, 0, 0x01, 4, bitmask),
+
+};
+
+static struct asc7621_data *asc7621_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct asc7621_data *data = i2c_get_clientdata(client);
+ int i;
+
+/*
+ * The asc7621 chips guarantee consistent reads of multi-byte values
+ * regardless of the order of the reads. No special logic is needed
+ * so we can just read the registers in whatever order they appear
+ * in the asc7621_params array.
+ */
+
+ mutex_lock(&data->update_lock);
+
+ /* Read all the high priority registers */
+
+ if (!data->valid ||
+ time_after(jiffies, data->last_high_reading + INTERVAL_HIGH)) {
+
+ for (i = 0; i < ARRAY_SIZE(asc7621_register_priorities); i++) {
+ if (asc7621_register_priorities[i] == PRI_HIGH) {
+ data->reg[i] =
+ i2c_smbus_read_byte_data(client, i) & 0xff;
+ }
+ }
+ data->last_high_reading = jiffies;
+ }; /* last_reading */
+
+ /* Read all the low priority registers. */
+
+ if (!data->valid ||
+ time_after(jiffies, data->last_low_reading + INTERVAL_LOW)) {
+
+ for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
+ if (asc7621_register_priorities[i] == PRI_LOW) {
+ data->reg[i] =
+ i2c_smbus_read_byte_data(client, i) & 0xff;
+ }
+ }
+ data->last_low_reading = jiffies;
+ }; /* last_reading */
+
+ data->valid = 1;
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+/*
+ * Standard detection and initialization below
+ *
+ * Helper function that checks if an address is valid
+ * for a particular chip.
+ */
+
+static inline int valid_address_for_chip(int chip_type, int address)
+{
+ int i;
+
+ for (i = 0; asc7621_chips[chip_type].addresses[i] != I2C_CLIENT_END;
+ i++) {
+ if (asc7621_chips[chip_type].addresses[i] == address)
+ return 1;
+ }
+ return 0;
+}
+
+static void asc7621_init_client(struct i2c_client *client)
+{
+ int value;
+
+ /* Warn if part was not "READY" */
+
+ value = read_byte(client, 0x40);
+
+ if (value & 0x02) {
+ dev_err(&client->dev,
+ "Client (%d,0x%02x) config is locked.\n",
+ i2c_adapter_id(client->adapter), client->addr);
+ };
+ if (!(value & 0x04)) {
+ dev_err(&client->dev, "Client (%d,0x%02x) is not ready.\n",
+ i2c_adapter_id(client->adapter), client->addr);
+ };
+
+/*
+ * Start monitoring
+ *
+ * Try to clear LOCK, Set START, save everything else
+ */
+ value = (value & ~0x02) | 0x01;
+ write_byte(client, 0x40, value & 0xff);
+
+}
+
+static int
+asc7621_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct asc7621_data *data;
+ int i, err;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ data = kzalloc(sizeof(struct asc7621_data), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ data->valid = 0;
+ mutex_init(&data->update_lock);
+
+ /* Initialize the asc7621 chip */
+ asc7621_init_client(client);
+
+ /* Create the sysfs entries */
+ for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
+ err =
+ device_create_file(&client->dev,
+ &(asc7621_params[i].sda.dev_attr));
+ if (err)
+ goto exit_remove;
+ }
+
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
+ }
+
+ return 0;
+
+exit_remove:
+ for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
+ device_remove_file(&client->dev,
+ &(asc7621_params[i].sda.dev_attr));
+ }
+
+ i2c_set_clientdata(client, NULL);
+ kfree(data);
+ return err;
+}
+
+static int asc7621_detect(struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ int company, verstep, chip_index;
+ struct device *dev;
+
+ dev = &client->dev;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ for (chip_index = FIRST_CHIP; chip_index <= LAST_CHIP; chip_index++) {
+
+ if (!valid_address_for_chip(chip_index, client->addr))
+ continue;
+
+ company = read_byte(client,
+ asc7621_chips[chip_index].company_reg);
+ verstep = read_byte(client,
+ asc7621_chips[chip_index].verstep_reg);
+
+ if (company == asc7621_chips[chip_index].company_id &&
+ verstep == asc7621_chips[chip_index].verstep_id) {
+ strlcpy(client->name, asc7621_chips[chip_index].name,
+ I2C_NAME_SIZE);
+ strlcpy(info->type, asc7621_chips[chip_index].name,
+ I2C_NAME_SIZE);
+
+ dev_info(&adapter->dev, "Matched %s\n",
+ asc7621_chips[chip_index].name);
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+static int asc7621_remove(struct i2c_client *client)
+{
+ struct asc7621_data *data = i2c_get_clientdata(client);
+ int i;
+
+ hwmon_device_unregister(data->class_dev);
+
+ for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
+ device_remove_file(&client->dev,
+ &(asc7621_params[i].sda.dev_attr));
+ }
+
+ i2c_set_clientdata(client, NULL);
+ kfree(data);
+ return 0;
+}
+
+static const struct i2c_device_id asc7621_id[] = {
+ {"asc7621", asc7621},
+ {"asc7621a", asc7621a},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, asc7621_id);
+
+static struct i2c_driver asc7621_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "asc7621",
+ },
+ .probe = asc7621_probe,
+ .remove = asc7621_remove,
+ .id_table = asc7621_id,
+ .detect = asc7621_detect,
+ .address_list = normal_i2c,
+};
+
+static int __init sm_asc7621_init(void)
+{
+ int i, j;
+/*
+ * Collect all the registers needed into a single array.
+ * This way, if a register isn't actually used for anything,
+ * we don't retrieve it.
+ */
+
+ for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) {
+ for (j = 0; j < ARRAY_SIZE(asc7621_params[i].msb); j++)
+ asc7621_register_priorities[asc7621_params[i].msb[j]] =
+ asc7621_params[i].priority;
+ for (j = 0; j < ARRAY_SIZE(asc7621_params[i].lsb); j++)
+ asc7621_register_priorities[asc7621_params[i].lsb[j]] =
+ asc7621_params[i].priority;
+ }
+ return i2c_add_driver(&asc7621_driver);
+}
+
+static void __exit sm_asc7621_exit(void)
+{
+ i2c_del_driver(&asc7621_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("George Joseph");
+MODULE_DESCRIPTION("Andigilog aSC7621 and aSC7621a driver");
+
+module_init(sm_asc7621_init);
+module_exit(sm_asc7621_exit);
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index 6811346c1c62..028284f544e3 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -1329,17 +1329,16 @@ static int atk_add(struct acpi_device *device)
&buf, ACPI_TYPE_PACKAGE);
if (ret != AE_OK) {
dev_dbg(&device->dev, "atk: method MBIF not found\n");
- err = -ENODEV;
- goto out;
- }
-
- obj = buf.pointer;
- if (obj->package.count >= 2 &&
- obj->package.elements[1].type == ACPI_TYPE_STRING) {
- dev_dbg(&device->dev, "board ID = %s\n",
- obj->package.elements[1].string.pointer);
+ } else {
+ obj = buf.pointer;
+ if (obj->package.count >= 2) {
+ union acpi_object *id = &obj->package.elements[1];
+ if (id->type == ACPI_TYPE_STRING)
+ dev_dbg(&device->dev, "board ID = %s\n",
+ id->string.pointer);
+ }
+ ACPI_FREE(buf.pointer);
}
- ACPI_FREE(buf.pointer);
err = atk_probe_if(data);
if (err) {
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index bd0fc67e804b..0627f7a5b9b8 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -267,7 +267,7 @@ struct fschmd_data {
struct list_head list; /* member of the watchdog_data_list */
struct kref kref;
struct miscdevice watchdog_miscdev;
- int kind;
+ enum chips kind;
unsigned long watchdog_is_open;
char watchdog_expect_close;
char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
@@ -325,8 +325,7 @@ static ssize_t show_in_value(struct device *dev,
int index = to_sensor_dev_attr(devattr)->index;
struct fschmd_data *data = fschmd_update_device(dev);
- /* fscher / fschrc - 1 as data->kind is an array index, not a chips */
- if (data->kind == (fscher - 1) || data->kind >= (fschrc - 1))
+ if (data->kind == fscher || data->kind >= fschrc)
return sprintf(buf, "%d\n", (data->volt[index] * dmi_vref *
dmi_mult[index]) / 255 + dmi_offset[index]);
else
@@ -492,7 +491,7 @@ static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
int val = data->fan_min[index];
/* 0 = allow turning off (except on the syl), 1-255 = 50-100% */
- if (val || data->kind == fscsyl - 1)
+ if (val || data->kind == fscsyl)
val = val / 2 + 128;
return sprintf(buf, "%d\n", val);
@@ -506,7 +505,7 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
unsigned long v = simple_strtoul(buf, NULL, 10);
/* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
- if (v || data->kind == fscsyl - 1) {
+ if (v || data->kind == fscsyl) {
v = SENSORS_LIMIT(v, 128, 255);
v = (v - 128) * 2 + 1;
}
@@ -768,6 +767,7 @@ leave:
static int watchdog_open(struct inode *inode, struct file *filp)
{
struct fschmd_data *pos, *data = NULL;
+ int watchdog_is_open;
/* We get called from drivers/char/misc.c with misc_mtx hold, and we
call misc_register() from fschmd_probe() with watchdog_data_mutex
@@ -782,10 +782,12 @@ static int watchdog_open(struct inode *inode, struct file *filp)
}
}
/* Note we can never not have found data, so we don't check for this */
- kref_get(&data->kref);
+ watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open);
+ if (!watchdog_is_open)
+ kref_get(&data->kref);
mutex_unlock(&watchdog_data_mutex);
- if (test_and_set_bit(0, &data->watchdog_is_open))
+ if (watchdog_is_open)
return -EBUSY;
/* Start the watchdog */
@@ -1034,7 +1036,7 @@ static int fschmd_detect(struct i2c_client *client,
else
return -ENODEV;
- strlcpy(info->type, fschmd_id[kind - 1].name, I2C_NAME_SIZE);
+ strlcpy(info->type, fschmd_id[kind].name, I2C_NAME_SIZE);
return 0;
}
@@ -1062,6 +1064,7 @@ static int fschmd_probe(struct i2c_client *client,
(where the client is found through a data ptr instead of the
otherway around) */
data->client = client;
+ data->kind = kind;
if (kind == fscpos) {
/* The Poseidon has hardwired temp limits, fill these
@@ -1082,9 +1085,6 @@ static int fschmd_probe(struct i2c_client *client,
}
}
- /* i2c kind goes from 1-6, we want from 0-5 to address arrays */
- data->kind = kind - 1;
-
/* Read in some never changing registers */
data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
data->global_control = i2c_smbus_read_byte_data(client,
diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c
index 19c01a49f6be..09ea12e0a551 100644
--- a/drivers/hwmon/g760a.c
+++ b/drivers/hwmon/g760a.c
@@ -68,7 +68,7 @@ struct g760a_data {
#define PWM_FROM_CNT(cnt) (0xff-(cnt))
#define PWM_TO_CNT(pwm) (0xff-(pwm))
-unsigned int rpm_from_cnt(u8 val, u32 clk, u16 div)
+static inline unsigned int rpm_from_cnt(u8 val, u32 clk, u16 div)
{
return ((val == 0x00) ? 0 : ((clk*30)/(val*div)));
}
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 0ffe84d190bb..1002befd87d5 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -1,40 +1,40 @@
/*
- it87.c - Part of lm_sensors, Linux kernel modules for hardware
- monitoring.
-
- The IT8705F is an LPC-based Super I/O part that contains UARTs, a
- parallel port, an IR port, a MIDI port, a floppy controller, etc., in
- addition to an Environment Controller (Enhanced Hardware Monitor and
- Fan Controller)
-
- This driver supports only the Environment Controller in the IT8705F and
- similar parts. The other devices are supported by different drivers.
-
- Supports: IT8705F Super I/O chip w/LPC interface
- IT8712F Super I/O chip w/LPC interface
- IT8716F Super I/O chip w/LPC interface
- IT8718F Super I/O chip w/LPC interface
- IT8720F Super I/O chip w/LPC interface
- IT8726F Super I/O chip w/LPC interface
- Sis950 A clone of the IT8705F
-
- Copyright (C) 2001 Chris Gauthron
- Copyright (C) 2005-2007 Jean Delvare <khali@linux-fr.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.
-
- 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.
-*/
+ * it87.c - Part of lm_sensors, Linux kernel modules for hardware
+ * monitoring.
+ *
+ * The IT8705F is an LPC-based Super I/O part that contains UARTs, a
+ * parallel port, an IR port, a MIDI port, a floppy controller, etc., in
+ * addition to an Environment Controller (Enhanced Hardware Monitor and
+ * Fan Controller)
+ *
+ * This driver supports only the Environment Controller in the IT8705F and
+ * similar parts. The other devices are supported by different drivers.
+ *
+ * Supports: IT8705F Super I/O chip w/LPC interface
+ * IT8712F Super I/O chip w/LPC interface
+ * IT8716F Super I/O chip w/LPC interface
+ * IT8718F Super I/O chip w/LPC interface
+ * IT8720F Super I/O chip w/LPC interface
+ * IT8726F Super I/O chip w/LPC interface
+ * Sis950 A clone of the IT8705F
+ *
+ * Copyright (C) 2001 Chris Gauthron
+ * Copyright (C) 2005-2010 Jean Delvare <khali@linux-fr.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.
+ *
+ * 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/module.h>
#include <linux/init.h>
@@ -128,6 +128,7 @@ superio_exit(void)
#define IT87_SIO_GPIO5_REG 0x29
#define IT87_SIO_PINX2_REG 0x2c /* Pin selection */
#define IT87_SIO_VID_REG 0xfc /* VID value */
+#define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */
/* Update battery voltage after every reading if true */
static int update_vbat;
@@ -187,9 +188,13 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
#define IT87_REG_VIN_ENABLE 0x50
#define IT87_REG_TEMP_ENABLE 0x51
+#define IT87_REG_BEEP_ENABLE 0x5c
#define IT87_REG_CHIPID 0x58
+#define IT87_REG_AUTO_TEMP(nr, i) (0x60 + (nr) * 8 + (i))
+#define IT87_REG_AUTO_PWM(nr, i) (0x65 + (nr) * 8 + (i))
+
#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255))
#define IN_FROM_REG(val) ((val) * 16)
@@ -246,6 +251,7 @@ struct it87_sio_data {
/* Values read from Super-I/O config space */
u8 revision;
u8 vid_value;
+ u8 beep_pin;
/* Features skipped based on config or DMI */
u8 skip_vid;
u8 skip_fan;
@@ -279,9 +285,21 @@ struct it87_data {
u8 vid; /* Register encoding, combined */
u8 vrm;
u32 alarms; /* Register encoding, combined */
+ u8 beeps; /* Register encoding */
u8 fan_main_ctrl; /* Register value */
u8 fan_ctl; /* Register value */
- u8 manual_pwm_ctl[3]; /* manual PWM value set by user */
+
+ /* The following 3 arrays correspond to the same registers. The
+ * meaning of bits 6-0 depends on the value of bit 7, and we want
+ * to preserve settings on mode changes, so we have to track all
+ * values separately. */
+ u8 pwm_ctrl[3]; /* Register value */
+ u8 pwm_duty[3]; /* Manual PWM value set by user (bit 6-0) */
+ u8 pwm_temp_map[3]; /* PWM to temp. chan. mapping (bits 1-0) */
+
+ /* Automatic fan speed control registers */
+ u8 auto_pwm[3][4]; /* [nr][3] is hard-coded */
+ s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */
};
static inline int has_16bit_fans(const struct it87_data *data)
@@ -296,6 +314,15 @@ static inline int has_16bit_fans(const struct it87_data *data)
|| data->type == it8720;
}
+static inline int has_old_autopwm(const struct it87_data *data)
+{
+ /* The old automatic fan speed control interface is implemented
+ by IT8705F chips up to revision F and IT8712F chips up to
+ revision G. */
+ return (data->type == it87 && data->revision < 0x03)
+ || (data->type == it8712 && data->revision < 0x08);
+}
+
static int it87_probe(struct platform_device *pdev);
static int __devexit it87_remove(struct platform_device *pdev);
@@ -352,7 +379,10 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct it87_data *data = dev_get_drvdata(dev);
- unsigned long val = simple_strtoul(buf, NULL, 10);
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val) < 0)
+ return -EINVAL;
mutex_lock(&data->update_lock);
data->in_min[nr] = IN_TO_REG(val);
@@ -368,7 +398,10 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct it87_data *data = dev_get_drvdata(dev);
- unsigned long val = simple_strtoul(buf, NULL, 10);
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val) < 0)
+ return -EINVAL;
mutex_lock(&data->update_lock);
data->in_max[nr] = IN_TO_REG(val);
@@ -441,7 +474,10 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct it87_data *data = dev_get_drvdata(dev);
- int val = simple_strtol(buf, NULL, 10);
+ long val;
+
+ if (strict_strtol(buf, 10, &val) < 0)
+ return -EINVAL;
mutex_lock(&data->update_lock);
data->temp_high[nr] = TEMP_TO_REG(val);
@@ -456,7 +492,10 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct it87_data *data = dev_get_drvdata(dev);
- int val = simple_strtol(buf, NULL, 10);
+ long val;
+
+ if (strict_strtol(buf, 10, &val) < 0)
+ return -EINVAL;
mutex_lock(&data->update_lock);
data->temp_low[nr] = TEMP_TO_REG(val);
@@ -483,8 +522,9 @@ static ssize_t show_sensor(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct it87_data *data = it87_update_device(dev);
- u8 reg = data->sensor; /* In case the value is updated while we use it */
-
+ u8 reg = data->sensor; /* In case the value is updated while
+ we use it */
+
if (reg & (1 << nr))
return sprintf(buf, "3\n"); /* thermal diode */
if (reg & (8 << nr))
@@ -498,7 +538,10 @@ static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct it87_data *data = dev_get_drvdata(dev);
- int val = simple_strtol(buf, NULL, 10);
+ long val;
+
+ if (strict_strtol(buf, 10, &val) < 0)
+ return -EINVAL;
mutex_lock(&data->update_lock);
@@ -511,9 +554,9 @@ static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
}
/* 3 = thermal diode; 4 = thermistor; 0 = disabled */
if (val == 3)
- data->sensor |= 1 << nr;
+ data->sensor |= 1 << nr;
else if (val == 4)
- data->sensor |= 8 << nr;
+ data->sensor |= 8 << nr;
else if (val != 0) {
mutex_unlock(&data->update_lock);
return -EINVAL;
@@ -531,6 +574,19 @@ show_sensor_offset(2);
show_sensor_offset(3);
/* 3 Fans */
+
+static int pwm_mode(const struct it87_data *data, int nr)
+{
+ int ctrl = data->fan_main_ctrl & (1 << nr);
+
+ if (ctrl == 0) /* Full speed */
+ return 0;
+ if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
+ return 2;
+ else /* Manual mode */
+ return 1;
+}
+
static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -538,7 +594,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct it87_data *data = it87_update_device(dev);
- return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr],
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
DIV_FROM_REG(data->fan_div[nr])));
}
static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
@@ -548,8 +604,8 @@ static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct it87_data *data = it87_update_device(dev);
- return sprintf(buf,"%d\n",
- FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])));
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
+ DIV_FROM_REG(data->fan_div[nr])));
}
static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -560,14 +616,14 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
}
-static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t show_pwm_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct it87_data *data = it87_update_device(dev);
- return sprintf(buf,"%d\n", (data->fan_main_ctrl & (1 << nr)) ? 1 : 0);
+ return sprintf(buf, "%d\n", pwm_mode(data, nr));
}
static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -576,7 +632,7 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct it87_data *data = it87_update_device(dev);
- return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]);
+ return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm_duty[nr]));
}
static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -593,15 +649,24 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct it87_data *data = dev_get_drvdata(dev);
- int val = simple_strtol(buf, NULL, 10);
+ long val;
u8 reg;
+ if (strict_strtol(buf, 10, &val) < 0)
+ return -EINVAL;
+
mutex_lock(&data->update_lock);
reg = it87_read_value(data, IT87_REG_FAN_DIV);
switch (nr) {
- case 0: data->fan_div[nr] = reg & 0x07; break;
- case 1: data->fan_div[nr] = (reg >> 3) & 0x07; break;
- case 2: data->fan_div[nr] = (reg & 0x40) ? 3 : 1; break;
+ case 0:
+ data->fan_div[nr] = reg & 0x07;
+ break;
+ case 1:
+ data->fan_div[nr] = (reg >> 3) & 0x07;
+ break;
+ case 2:
+ data->fan_div[nr] = (reg & 0x40) ? 3 : 1;
+ break;
}
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
@@ -616,10 +681,13 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct it87_data *data = dev_get_drvdata(dev);
- unsigned long val = simple_strtoul(buf, NULL, 10);
+ unsigned long val;
int min;
u8 old;
+ if (strict_strtoul(buf, 10, &val) < 0)
+ return -EINVAL;
+
mutex_lock(&data->update_lock);
old = it87_read_value(data, IT87_REG_FAN_DIV);
@@ -651,6 +719,32 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
mutex_unlock(&data->update_lock);
return count;
}
+
+/* Returns 0 if OK, -EINVAL otherwise */
+static int check_trip_points(struct device *dev, int nr)
+{
+ const struct it87_data *data = dev_get_drvdata(dev);
+ int i, err = 0;
+
+ if (has_old_autopwm(data)) {
+ for (i = 0; i < 3; i++) {
+ if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
+ err = -EINVAL;
+ }
+ for (i = 0; i < 2; i++) {
+ if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
+ err = -EINVAL;
+ }
+ }
+
+ if (err) {
+ dev_err(dev, "Inconsistent trip points, not switching to "
+ "automatic mode\n");
+ dev_err(dev, "Adjust the trip points and try again\n");
+ }
+ return err;
+}
+
static ssize_t set_pwm_enable(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
@@ -658,7 +752,16 @@ static ssize_t set_pwm_enable(struct device *dev,
int nr = sensor_attr->index;
struct it87_data *data = dev_get_drvdata(dev);
- int val = simple_strtol(buf, NULL, 10);
+ long val;
+
+ if (strict_strtol(buf, 10, &val) < 0 || val < 0 || val > 2)
+ return -EINVAL;
+
+ /* Check trip points before switching to automatic mode */
+ if (val == 2) {
+ if (check_trip_points(dev, nr) < 0)
+ return -EINVAL;
+ }
mutex_lock(&data->update_lock);
@@ -669,16 +772,18 @@ static ssize_t set_pwm_enable(struct device *dev,
it87_write_value(data, IT87_REG_FAN_CTL, tmp | (1 << nr));
/* set on/off mode */
data->fan_main_ctrl &= ~(1 << nr);
- it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
- } else if (val == 1) {
+ it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
+ data->fan_main_ctrl);
+ } else {
+ if (val == 1) /* Manual mode */
+ data->pwm_ctrl[nr] = data->pwm_duty[nr];
+ else /* Automatic mode */
+ data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
+ it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
/* set SmartGuardian mode */
data->fan_main_ctrl |= (1 << nr);
- it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
- /* set saved pwm value, clear FAN_CTLX PWM mode bit */
- it87_write_value(data, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
- } else {
- mutex_unlock(&data->update_lock);
- return -EINVAL;
+ it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
+ data->fan_main_ctrl);
}
mutex_unlock(&data->update_lock);
@@ -691,15 +796,19 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct it87_data *data = dev_get_drvdata(dev);
- int val = simple_strtol(buf, NULL, 10);
+ long val;
- if (val < 0 || val > 255)
+ if (strict_strtol(buf, 10, &val) < 0 || val < 0 || val > 255)
return -EINVAL;
mutex_lock(&data->update_lock);
- data->manual_pwm_ctl[nr] = val;
- if (data->fan_main_ctrl & (1 << nr))
- it87_write_value(data, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
+ data->pwm_duty[nr] = PWM_TO_REG(val);
+ /* If we are in manual mode, write the duty cycle immediately;
+ * otherwise, just store it for later use. */
+ if (!(data->pwm_ctrl[nr] & 0x80)) {
+ data->pwm_ctrl[nr] = data->pwm_duty[nr];
+ it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
+ }
mutex_unlock(&data->update_lock);
return count;
}
@@ -707,9 +816,12 @@ static ssize_t set_pwm_freq(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct it87_data *data = dev_get_drvdata(dev);
- unsigned long val = simple_strtoul(buf, NULL, 10);
+ unsigned long val;
int i;
+ if (strict_strtoul(buf, 10, &val) < 0)
+ return -EINVAL;
+
/* Search for the nearest available frequency */
for (i = 0; i < 7; i++) {
if (val > (pwm_freq[i] + pwm_freq[i+1]) / 2)
@@ -724,6 +836,132 @@ static ssize_t set_pwm_freq(struct device *dev,
return count;
}
+static ssize_t show_pwm_temp_map(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
+ struct it87_data *data = it87_update_device(dev);
+ int map;
+
+ if (data->pwm_temp_map[nr] < 3)
+ map = 1 << data->pwm_temp_map[nr];
+ else
+ map = 0; /* Should never happen */
+ return sprintf(buf, "%d\n", map);
+}
+static ssize_t set_pwm_temp_map(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
+ struct it87_data *data = dev_get_drvdata(dev);
+ long val;
+ u8 reg;
+
+ /* This check can go away if we ever support automatic fan speed
+ control on newer chips. */
+ if (!has_old_autopwm(data)) {
+ dev_notice(dev, "Mapping change disabled for safety reasons\n");
+ return -EINVAL;
+ }
+
+ if (strict_strtol(buf, 10, &val) < 0)
+ return -EINVAL;
+
+ switch (val) {
+ case (1 << 0):
+ reg = 0x00;
+ break;
+ case (1 << 1):
+ reg = 0x01;
+ break;
+ case (1 << 2):
+ reg = 0x02;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->update_lock);
+ data->pwm_temp_map[nr] = reg;
+ /* If we are in automatic mode, write the temp mapping immediately;
+ * otherwise, just store it for later use. */
+ if (data->pwm_ctrl[nr] & 0x80) {
+ data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
+ it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_auto_pwm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct it87_data *data = it87_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int point = sensor_attr->index;
+
+ return sprintf(buf, "%d\n", PWM_FROM_REG(data->auto_pwm[nr][point]));
+}
+
+static ssize_t set_auto_pwm(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct it87_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int point = sensor_attr->index;
+ long val;
+
+ if (strict_strtol(buf, 10, &val) < 0 || val < 0 || val > 255)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->auto_pwm[nr][point] = PWM_TO_REG(val);
+ it87_write_value(data, IT87_REG_AUTO_PWM(nr, point),
+ data->auto_pwm[nr][point]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_auto_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct it87_data *data = it87_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int point = sensor_attr->index;
+
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->auto_temp[nr][point]));
+}
+
+static ssize_t set_auto_temp(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct it87_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int point = sensor_attr->index;
+ long val;
+
+ if (strict_strtol(buf, 10, &val) < 0 || val < -128000 || val > 127000)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->auto_temp[nr][point] = TEMP_TO_REG(val);
+ it87_write_value(data, IT87_REG_AUTO_TEMP(nr, point),
+ data->auto_temp[nr][point]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
#define show_fan_offset(offset) \
static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
@@ -744,7 +982,36 @@ static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
show_pwm, set_pwm, offset - 1); \
static DEVICE_ATTR(pwm##offset##_freq, \
(offset == 1 ? S_IRUGO | S_IWUSR : S_IRUGO), \
- show_pwm_freq, (offset == 1 ? set_pwm_freq : NULL));
+ show_pwm_freq, (offset == 1 ? set_pwm_freq : NULL)); \
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels_temp, \
+ S_IRUGO | S_IWUSR, show_pwm_temp_map, set_pwm_temp_map, \
+ offset - 1); \
+static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_pwm, \
+ S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \
+ offset - 1, 0); \
+static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point2_pwm, \
+ S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \
+ offset - 1, 1); \
+static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point3_pwm, \
+ S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \
+ offset - 1, 2); \
+static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point4_pwm, \
+ S_IRUGO, show_auto_pwm, NULL, offset - 1, 3); \
+static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_temp, \
+ S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \
+ offset - 1, 1); \
+static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_temp_hyst, \
+ S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \
+ offset - 1, 0); \
+static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point2_temp, \
+ S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \
+ offset - 1, 2); \
+static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point3_temp, \
+ S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \
+ offset - 1, 3); \
+static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point4_temp, \
+ S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \
+ offset - 1, 4);
show_pwm_offset(1);
show_pwm_offset(2);
@@ -775,7 +1042,10 @@ static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct it87_data *data = dev_get_drvdata(dev);
- int val = simple_strtol(buf, NULL, 10);
+ long val;
+
+ if (strict_strtol(buf, 10, &val) < 0)
+ return -EINVAL;
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN16_TO_REG(val);
@@ -805,7 +1075,8 @@ show_fan16_offset(4);
show_fan16_offset(5);
/* Alarms */
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%u\n", data->alarms);
@@ -836,27 +1107,78 @@ static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 16);
static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 17);
static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 18);
-static ssize_t
-show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct it87_data *data = it87_update_device(dev);
+ return sprintf(buf, "%u\n", (data->beeps >> bitnr) & 1);
+}
+static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct it87_data *data = dev_get_drvdata(dev);
+ long val;
+
+ if (strict_strtol(buf, 10, &val) < 0
+ || (val != 0 && val != 1))
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
+ if (val)
+ data->beeps |= (1 << bitnr);
+ else
+ data->beeps &= ~(1 << bitnr);
+ it87_write_value(data, IT87_REG_BEEP_ENABLE, data->beeps);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
+ show_beep, set_beep, 1);
+static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO, show_beep, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO, show_beep, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO, show_beep, NULL, 1);
+static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO, show_beep, NULL, 1);
+static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO, show_beep, NULL, 1);
+static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO, show_beep, NULL, 1);
+static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO, show_beep, NULL, 1);
+/* fanX_beep writability is set later */
+static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO, show_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO, show_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO, show_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(fan4_beep, S_IRUGO, show_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(fan5_beep, S_IRUGO, show_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
+ show_beep, set_beep, 2);
+static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO, show_beep, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO, show_beep, NULL, 2);
+
+static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct it87_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", data->vrm);
}
-static ssize_t
-store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct it87_data *data = dev_get_drvdata(dev);
- u32 val;
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val) < 0)
+ return -EINVAL;
- val = simple_strtoul(buf, NULL, 10);
data->vrm = val;
return count;
}
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
-static ssize_t
-show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
@@ -931,51 +1253,176 @@ static const struct attribute_group it87_group = {
.attrs = it87_attributes,
};
-static struct attribute *it87_attributes_opt[] = {
+static struct attribute *it87_attributes_beep[] = {
+ &sensor_dev_attr_in0_beep.dev_attr.attr,
+ &sensor_dev_attr_in1_beep.dev_attr.attr,
+ &sensor_dev_attr_in2_beep.dev_attr.attr,
+ &sensor_dev_attr_in3_beep.dev_attr.attr,
+ &sensor_dev_attr_in4_beep.dev_attr.attr,
+ &sensor_dev_attr_in5_beep.dev_attr.attr,
+ &sensor_dev_attr_in6_beep.dev_attr.attr,
+ &sensor_dev_attr_in7_beep.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_beep.dev_attr.attr,
+ &sensor_dev_attr_temp2_beep.dev_attr.attr,
+ &sensor_dev_attr_temp3_beep.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group it87_group_beep = {
+ .attrs = it87_attributes_beep,
+};
+
+static struct attribute *it87_attributes_fan16[5][3+1] = { {
&sensor_dev_attr_fan1_input16.dev_attr.attr,
&sensor_dev_attr_fan1_min16.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ NULL
+}, {
&sensor_dev_attr_fan2_input16.dev_attr.attr,
&sensor_dev_attr_fan2_min16.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ NULL
+}, {
&sensor_dev_attr_fan3_input16.dev_attr.attr,
&sensor_dev_attr_fan3_min16.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+ NULL
+}, {
&sensor_dev_attr_fan4_input16.dev_attr.attr,
&sensor_dev_attr_fan4_min16.dev_attr.attr,
+ &sensor_dev_attr_fan4_alarm.dev_attr.attr,
+ NULL
+}, {
&sensor_dev_attr_fan5_input16.dev_attr.attr,
&sensor_dev_attr_fan5_min16.dev_attr.attr,
+ &sensor_dev_attr_fan5_alarm.dev_attr.attr,
+ NULL
+} };
+
+static const struct attribute_group it87_group_fan16[5] = {
+ { .attrs = it87_attributes_fan16[0] },
+ { .attrs = it87_attributes_fan16[1] },
+ { .attrs = it87_attributes_fan16[2] },
+ { .attrs = it87_attributes_fan16[3] },
+ { .attrs = it87_attributes_fan16[4] },
+};
+static struct attribute *it87_attributes_fan[3][4+1] = { {
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ NULL
+}, {
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ NULL
+}, {
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan3_div.dev_attr.attr,
-
- &sensor_dev_attr_fan1_alarm.dev_attr.attr,
- &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&sensor_dev_attr_fan3_alarm.dev_attr.attr,
- &sensor_dev_attr_fan4_alarm.dev_attr.attr,
- &sensor_dev_attr_fan5_alarm.dev_attr.attr,
+ NULL
+} };
+
+static const struct attribute_group it87_group_fan[3] = {
+ { .attrs = it87_attributes_fan[0] },
+ { .attrs = it87_attributes_fan[1] },
+ { .attrs = it87_attributes_fan[2] },
+};
+
+static const struct attribute_group *
+it87_get_fan_group(const struct it87_data *data)
+{
+ return has_16bit_fans(data) ? it87_group_fan16 : it87_group_fan;
+}
+static struct attribute *it87_attributes_pwm[3][4+1] = { {
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
- &sensor_dev_attr_pwm2_enable.dev_attr.attr,
- &sensor_dev_attr_pwm3_enable.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
- &sensor_dev_attr_pwm2.dev_attr.attr,
- &sensor_dev_attr_pwm3.dev_attr.attr,
&dev_attr_pwm1_freq.attr,
+ &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
&dev_attr_pwm2_freq.attr,
+ &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
&dev_attr_pwm3_freq.attr,
+ &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
+ NULL
+} };
+
+static const struct attribute_group it87_group_pwm[3] = {
+ { .attrs = it87_attributes_pwm[0] },
+ { .attrs = it87_attributes_pwm[1] },
+ { .attrs = it87_attributes_pwm[2] },
+};
+static struct attribute *it87_attributes_autopwm[3][9+1] = { {
+ &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr,
+ NULL
+} };
+
+static const struct attribute_group it87_group_autopwm[3] = {
+ { .attrs = it87_attributes_autopwm[0] },
+ { .attrs = it87_attributes_autopwm[1] },
+ { .attrs = it87_attributes_autopwm[2] },
+};
+
+static struct attribute *it87_attributes_fan_beep[] = {
+ &sensor_dev_attr_fan1_beep.dev_attr.attr,
+ &sensor_dev_attr_fan2_beep.dev_attr.attr,
+ &sensor_dev_attr_fan3_beep.dev_attr.attr,
+ &sensor_dev_attr_fan4_beep.dev_attr.attr,
+ &sensor_dev_attr_fan5_beep.dev_attr.attr,
+};
+
+static struct attribute *it87_attributes_vid[] = {
&dev_attr_vrm.attr,
&dev_attr_cpu0_vid.attr,
NULL
};
-static const struct attribute_group it87_group_opt = {
- .attrs = it87_attributes_opt,
+static const struct attribute_group it87_group_vid = {
+ .attrs = it87_attributes_vid,
};
/* SuperIO detection - will change isa_address if a chip is found */
@@ -1035,6 +1482,10 @@ static int __init it87_find(unsigned short *address,
if (sio_data->type == it87) {
/* The IT8705F doesn't have VID pins at all */
sio_data->skip_vid = 1;
+
+ /* The IT8705F has a different LD number for GPIO */
+ superio_select(5);
+ sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else {
int reg;
@@ -1068,7 +1519,11 @@ static int __init it87_find(unsigned short *address,
pr_info("it87: in3 is VCC (+5V)\n");
if (reg & (1 << 1))
pr_info("it87: in7 is VCCH (+5V Stand-By)\n");
+
+ sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
}
+ if (sio_data->beep_pin)
+ pr_info("it87: Beeping is supported\n");
/* Disable specific features based on DMI strings */
board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
@@ -1093,14 +1548,46 @@ exit:
return err;
}
+static void it87_remove_files(struct device *dev)
+{
+ struct it87_data *data = platform_get_drvdata(pdev);
+ struct it87_sio_data *sio_data = dev->platform_data;
+ const struct attribute_group *fan_group = it87_get_fan_group(data);
+ int i;
+
+ sysfs_remove_group(&dev->kobj, &it87_group);
+ if (sio_data->beep_pin)
+ sysfs_remove_group(&dev->kobj, &it87_group_beep);
+ for (i = 0; i < 5; i++) {
+ if (!(data->has_fan & (1 << i)))
+ continue;
+ sysfs_remove_group(&dev->kobj, &fan_group[i]);
+ if (sio_data->beep_pin)
+ sysfs_remove_file(&dev->kobj,
+ it87_attributes_fan_beep[i]);
+ }
+ for (i = 0; i < 3; i++) {
+ if (sio_data->skip_pwm & (1 << 0))
+ continue;
+ sysfs_remove_group(&dev->kobj, &it87_group_pwm[i]);
+ if (has_old_autopwm(data))
+ sysfs_remove_group(&dev->kobj,
+ &it87_group_autopwm[i]);
+ }
+ if (!sio_data->skip_vid)
+ sysfs_remove_group(&dev->kobj, &it87_group_vid);
+}
+
static int __devinit it87_probe(struct platform_device *pdev)
{
struct it87_data *data;
struct resource *res;
struct device *dev = &pdev->dev;
struct it87_sio_data *sio_data = dev->platform_data;
- int err = 0;
+ const struct attribute_group *fan_group;
+ int err = 0, i;
int enable_pwm_interface;
+ int fan_beep_need_rw;
static const char *names[] = {
"it87",
"it8712",
@@ -1118,7 +1605,8 @@ static int __devinit it87_probe(struct platform_device *pdev)
goto ERROR0;
}
- if (!(data = kzalloc(sizeof(struct it87_data), GFP_KERNEL))) {
+ data = kzalloc(sizeof(struct it87_data), GFP_KERNEL);
+ if (!data) {
err = -ENOMEM;
goto ERROR1;
}
@@ -1146,120 +1634,60 @@ static int __devinit it87_probe(struct platform_device *pdev)
it87_init_device(pdev);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&dev->kobj, &it87_group)))
+ err = sysfs_create_group(&dev->kobj, &it87_group);
+ if (err)
goto ERROR2;
+ if (sio_data->beep_pin) {
+ err = sysfs_create_group(&dev->kobj, &it87_group_beep);
+ if (err)
+ goto ERROR4;
+ }
+
/* Do not create fan files for disabled fans */
- if (has_16bit_fans(data)) {
- /* 16-bit tachometers */
- if (data->has_fan & (1 << 0)) {
- if ((err = device_create_file(dev,
- &sensor_dev_attr_fan1_input16.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan1_min16.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan1_alarm.dev_attr)))
- goto ERROR4;
- }
- if (data->has_fan & (1 << 1)) {
- if ((err = device_create_file(dev,
- &sensor_dev_attr_fan2_input16.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan2_min16.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan2_alarm.dev_attr)))
- goto ERROR4;
- }
- if (data->has_fan & (1 << 2)) {
- if ((err = device_create_file(dev,
- &sensor_dev_attr_fan3_input16.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan3_min16.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan3_alarm.dev_attr)))
- goto ERROR4;
- }
- if (data->has_fan & (1 << 3)) {
- if ((err = device_create_file(dev,
- &sensor_dev_attr_fan4_input16.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan4_min16.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan4_alarm.dev_attr)))
- goto ERROR4;
- }
- if (data->has_fan & (1 << 4)) {
- if ((err = device_create_file(dev,
- &sensor_dev_attr_fan5_input16.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan5_min16.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan5_alarm.dev_attr)))
- goto ERROR4;
- }
- } else {
- /* 8-bit tachometers with clock divider */
- if (data->has_fan & (1 << 0)) {
- if ((err = device_create_file(dev,
- &sensor_dev_attr_fan1_input.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan1_min.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan1_div.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan1_alarm.dev_attr)))
- goto ERROR4;
- }
- if (data->has_fan & (1 << 1)) {
- if ((err = device_create_file(dev,
- &sensor_dev_attr_fan2_input.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan2_min.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan2_div.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan2_alarm.dev_attr)))
- goto ERROR4;
- }
- if (data->has_fan & (1 << 2)) {
- if ((err = device_create_file(dev,
- &sensor_dev_attr_fan3_input.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan3_min.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan3_div.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_fan3_alarm.dev_attr)))
+ fan_group = it87_get_fan_group(data);
+ fan_beep_need_rw = 1;
+ for (i = 0; i < 5; i++) {
+ if (!(data->has_fan & (1 << i)))
+ continue;
+ err = sysfs_create_group(&dev->kobj, &fan_group[i]);
+ if (err)
+ goto ERROR4;
+
+ if (sio_data->beep_pin) {
+ err = sysfs_create_file(&dev->kobj,
+ it87_attributes_fan_beep[i]);
+ if (err)
goto ERROR4;
+ if (!fan_beep_need_rw)
+ continue;
+
+ /* As we have a single beep enable bit for all fans,
+ * only the first enabled fan has a writable attribute
+ * for it. */
+ if (sysfs_chmod_file(&dev->kobj,
+ it87_attributes_fan_beep[i],
+ S_IRUGO | S_IWUSR))
+ dev_dbg(dev, "chmod +w fan%d_beep failed\n",
+ i + 1);
+ fan_beep_need_rw = 0;
}
}
if (enable_pwm_interface) {
- if (!(sio_data->skip_pwm & (1 << 0))) {
- if ((err = device_create_file(dev,
- &sensor_dev_attr_pwm1_enable.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_pwm1.dev_attr))
- || (err = device_create_file(dev,
- &dev_attr_pwm1_freq)))
- goto ERROR4;
- }
- if (!(sio_data->skip_pwm & (1 << 1))) {
- if ((err = device_create_file(dev,
- &sensor_dev_attr_pwm2_enable.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_pwm2.dev_attr))
- || (err = device_create_file(dev,
- &dev_attr_pwm2_freq)))
+ for (i = 0; i < 3; i++) {
+ if (sio_data->skip_pwm & (1 << i))
+ continue;
+ err = sysfs_create_group(&dev->kobj,
+ &it87_group_pwm[i]);
+ if (err)
goto ERROR4;
- }
- if (!(sio_data->skip_pwm & (1 << 2))) {
- if ((err = device_create_file(dev,
- &sensor_dev_attr_pwm3_enable.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_pwm3.dev_attr))
- || (err = device_create_file(dev,
- &dev_attr_pwm3_freq)))
+
+ if (!has_old_autopwm(data))
+ continue;
+ err = sysfs_create_group(&dev->kobj,
+ &it87_group_autopwm[i]);
+ if (err)
goto ERROR4;
}
}
@@ -1268,10 +1696,8 @@ static int __devinit it87_probe(struct platform_device *pdev)
data->vrm = vid_which_vrm();
/* VID reading from Super-I/O config space if available */
data->vid = sio_data->vid_value;
- if ((err = device_create_file(dev,
- &dev_attr_vrm))
- || (err = device_create_file(dev,
- &dev_attr_cpu0_vid)))
+ err = sysfs_create_group(&dev->kobj, &it87_group_vid);
+ if (err)
goto ERROR4;
}
@@ -1284,8 +1710,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
return 0;
ERROR4:
- sysfs_remove_group(&dev->kobj, &it87_group);
- sysfs_remove_group(&dev->kobj, &it87_group_opt);
+ it87_remove_files(dev);
ERROR2:
platform_set_drvdata(pdev, NULL);
kfree(data);
@@ -1300,8 +1725,7 @@ static int __devexit it87_remove(struct platform_device *pdev)
struct it87_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&pdev->dev.kobj, &it87_group);
- sysfs_remove_group(&pdev->dev.kobj, &it87_group_opt);
+ it87_remove_files(&pdev->dev);
release_region(data->addr, IT87_EC_EXTENT);
platform_set_drvdata(pdev, NULL);
@@ -1387,15 +1811,18 @@ static void __devinit it87_init_device(struct platform_device *pdev)
int tmp, i;
u8 mask;
- /* initialize to sane defaults:
- * - if the chip is in manual pwm mode, this will be overwritten with
- * the actual settings on the chip (so in this case, initialization
- * is not needed)
- * - if in automatic or on/off mode, we could switch to manual mode,
- * read the registers and set manual_pwm_ctl accordingly, but currently
- * this is not implemented, so we initialize to something sane */
+ /* For each PWM channel:
+ * - If it is in automatic mode, setting to manual mode should set
+ * the fan to full speed by default.
+ * - If it is in manual mode, we need a mapping to temperature
+ * channels to use when later setting to automatic mode later.
+ * Use a 1:1 mapping by default (we are clueless.)
+ * In both cases, the value can (and should) be changed by the user
+ * prior to switching to a different mode. */
for (i = 0; i < 3; i++) {
- data->manual_pwm_ctl[i] = 0xff;
+ data->pwm_temp_map[i] = i;
+ data->pwm_duty[i] = 0x7f; /* Full speed */
+ data->auto_pwm[i][3] = 0x7f; /* Full speed, hard-coded */
}
/* Some chips seem to have default value 0xff for all limit
@@ -1436,7 +1863,8 @@ static void __devinit it87_init_device(struct platform_device *pdev)
if ((data->fan_main_ctrl & mask) == 0) {
/* Enable all fan tachometers */
data->fan_main_ctrl |= mask;
- it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+ it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
+ data->fan_main_ctrl);
}
data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
@@ -1461,30 +1889,32 @@ static void __devinit it87_init_device(struct platform_device *pdev)
/* Fan input pins may be used for alternative functions */
data->has_fan &= ~sio_data->skip_fan;
- /* Set current fan mode registers and the default settings for the
- * other mode registers */
- for (i = 0; i < 3; i++) {
- if (data->fan_main_ctrl & (1 << i)) {
- /* pwm mode */
- tmp = it87_read_value(data, IT87_REG_PWM(i));
- if (tmp & 0x80) {
- /* automatic pwm - not yet implemented, but
- * leave the settings made by the BIOS alone
- * until a change is requested via the sysfs
- * interface */
- } else {
- /* manual pwm */
- data->manual_pwm_ctl[i] = PWM_FROM_REG(tmp);
- }
- }
- }
-
/* Start monitoring */
it87_write_value(data, IT87_REG_CONFIG,
(it87_read_value(data, IT87_REG_CONFIG) & 0x36)
| (update_vbat ? 0x41 : 0x01));
}
+static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
+{
+ data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr));
+ if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
+ data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
+ else /* Manual mode */
+ data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
+
+ if (has_old_autopwm(data)) {
+ int i;
+
+ for (i = 0; i < 5 ; i++)
+ data->auto_temp[nr][i] = it87_read_value(data,
+ IT87_REG_AUTO_TEMP(nr, i));
+ for (i = 0; i < 3 ; i++)
+ data->auto_pwm[nr][i] = it87_read_value(data,
+ IT87_REG_AUTO_PWM(nr, i));
+ }
+}
+
static struct it87_data *it87_update_device(struct device *dev)
{
struct it87_data *data = dev_get_drvdata(dev);
@@ -1494,24 +1924,22 @@ static struct it87_data *it87_update_device(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
-
if (update_vbat) {
/* Cleared after each update, so reenable. Value
- returned by this read will be previous value */
+ returned by this read will be previous value */
it87_write_value(data, IT87_REG_CONFIG,
- it87_read_value(data, IT87_REG_CONFIG) | 0x40);
+ it87_read_value(data, IT87_REG_CONFIG) | 0x40);
}
for (i = 0; i <= 7; i++) {
data->in[i] =
- it87_read_value(data, IT87_REG_VIN(i));
+ it87_read_value(data, IT87_REG_VIN(i));
data->in_min[i] =
- it87_read_value(data, IT87_REG_VIN_MIN(i));
+ it87_read_value(data, IT87_REG_VIN_MIN(i));
data->in_max[i] =
- it87_read_value(data, IT87_REG_VIN_MAX(i));
+ it87_read_value(data, IT87_REG_VIN_MAX(i));
}
/* in8 (battery) has no limit registers */
- data->in[8] =
- it87_read_value(data, IT87_REG_VIN(8));
+ data->in[8] = it87_read_value(data, IT87_REG_VIN(8));
for (i = 0; i < 5; i++) {
/* Skip disabled fans */
@@ -1519,7 +1947,7 @@ static struct it87_data *it87_update_device(struct device *dev)
continue;
data->fan_min[i] =
- it87_read_value(data, IT87_REG_FAN_MIN[i]);
+ it87_read_value(data, IT87_REG_FAN_MIN[i]);
data->fan[i] = it87_read_value(data,
IT87_REG_FAN[i]);
/* Add high byte if in 16-bit mode */
@@ -1532,11 +1960,11 @@ static struct it87_data *it87_update_device(struct device *dev)
}
for (i = 0; i < 3; i++) {
data->temp[i] =
- it87_read_value(data, IT87_REG_TEMP(i));
+ it87_read_value(data, IT87_REG_TEMP(i));
data->temp_high[i] =
- it87_read_value(data, IT87_REG_TEMP_HIGH(i));
+ it87_read_value(data, IT87_REG_TEMP_HIGH(i));
data->temp_low[i] =
- it87_read_value(data, IT87_REG_TEMP_LOW(i));
+ it87_read_value(data, IT87_REG_TEMP_LOW(i));
}
/* Newer chips don't have clock dividers */
@@ -1551,9 +1979,13 @@ static struct it87_data *it87_update_device(struct device *dev)
it87_read_value(data, IT87_REG_ALARM1) |
(it87_read_value(data, IT87_REG_ALARM2) << 8) |
(it87_read_value(data, IT87_REG_ALARM3) << 16);
+ data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
+
data->fan_main_ctrl = it87_read_value(data,
IT87_REG_FAN_MAIN_CTRL);
data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
+ for (i = 0; i < 3; i++)
+ it87_update_pwm_ctrl(data, i);
data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
/* The 8705 does not have VID capability.
@@ -1628,7 +2060,7 @@ exit:
static int __init sm_it87_init(void)
{
int err;
- unsigned short isa_address=0;
+ unsigned short isa_address = 0;
struct it87_sio_data sio_data;
memset(&sio_data, 0, sizeof(struct it87_sio_data));
@@ -1640,7 +2072,7 @@ static int __init sm_it87_init(void)
return err;
err = it87_device_add(isa_address, &sio_data);
- if (err){
+ if (err) {
platform_driver_unregister(&it87_driver);
return err;
}
@@ -1661,7 +2093,8 @@ MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8720F/8726F, SiS950 driver");
module_param(update_vbat, bool, 0);
MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
module_param(fix_pwm_polarity, bool, 0);
-MODULE_PARM_DESC(fix_pwm_polarity, "Force PWM polarity to active high (DANGEROUS)");
+MODULE_PARM_DESC(fix_pwm_polarity,
+ "Force PWM polarity to active high (DANGEROUS)");
MODULE_LICENSE("GPL");
module_init(sm_it87_init);
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index cadcbd90ff3b..72ff2c4e757d 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -851,17 +851,16 @@ static struct lm78_data *lm78_update_device(struct device *dev)
static int __init lm78_isa_found(unsigned short address)
{
int val, save, found = 0;
-
- /* We have to request the region in two parts because some
- boards declare base+4 to base+7 as a PNP device */
- if (!request_region(address, 4, "lm78")) {
- pr_debug("lm78: Failed to request low part of region\n");
- return 0;
- }
- if (!request_region(address + 4, 4, "lm78")) {
- pr_debug("lm78: Failed to request high part of region\n");
- release_region(address, 4);
- return 0;
+ int port;
+
+ /* Some boards declare base+0 to base+7 as a PNP device, some base+4
+ * to base+7 and some base+5 to base+6. So we better request each port
+ * individually for the probing phase. */
+ for (port = address; port < address + LM78_EXTENT; port++) {
+ if (!request_region(port, 1, "lm78")) {
+ pr_debug("lm78: Failed to request port 0x%x\n", port);
+ goto release;
+ }
}
#define REALLY_SLOW_IO
@@ -925,8 +924,8 @@ static int __init lm78_isa_found(unsigned short address)
val & 0x80 ? "LM79" : "LM78", (int)address);
release:
- release_region(address + 4, 4);
- release_region(address, 4);
+ for (port--; port >= address; port--)
+ release_region(port, 1);
return found;
}
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 7c9bdc167426..7cc2708871ab 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -1,7 +1,7 @@
/*
* lm90.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
- * Copyright (C) 2003-2009 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
*
* Based on the lm83 driver. The LM90 is a sensor chip made by National
* Semiconductor. It reports up to two temperatures (its own plus up to
@@ -93,7 +93,8 @@
static const unsigned short normal_i2c[] = {
0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
-enum chips { lm90, adm1032, lm99, lm86, max6657, adt7461, max6680, max6646 };
+enum chips { lm90, adm1032, lm99, lm86, max6657, adt7461, max6680, max6646,
+ w83l771 };
/*
* The LM90 registers
@@ -151,6 +152,7 @@ static int lm90_detect(struct i2c_client *client, struct i2c_board_info *info);
static int lm90_probe(struct i2c_client *client,
const struct i2c_device_id *id);
static void lm90_init_client(struct i2c_client *client);
+static void lm90_alert(struct i2c_client *client, unsigned int flag);
static int lm90_remove(struct i2c_client *client);
static struct lm90_data *lm90_update_device(struct device *dev);
@@ -173,6 +175,7 @@ static const struct i2c_device_id lm90_id[] = {
{ "max6659", max6657 },
{ "max6680", max6680 },
{ "max6681", max6680 },
+ { "w83l771", w83l771 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm90_id);
@@ -184,6 +187,7 @@ static struct i2c_driver lm90_driver = {
},
.probe = lm90_probe,
.remove = lm90_remove,
+ .alert = lm90_alert,
.id_table = lm90_id,
.detect = lm90_detect,
.address_list = normal_i2c,
@@ -201,6 +205,9 @@ struct lm90_data {
int kind;
int flags;
+ u8 config_orig; /* Original configuration register value */
+ u8 alert_alarms; /* Which alarm bits trigger ALERT# */
+
/* registers values */
s8 temp8[4]; /* 0: local low limit
1: local high limit
@@ -758,6 +765,14 @@ static int lm90_detect(struct i2c_client *new_client,
&& reg_convrate <= 0x07) {
name = "max6646";
}
+ } else
+ if (address == 0x4C
+ && man_id == 0x5C) { /* Winbond/Nuvoton */
+ if ((chip_id & 0xFE) == 0x10 /* W83L771AWG/ASG */
+ && (reg_config1 & 0x2A) == 0x00
+ && reg_convrate <= 0x08) {
+ name = "w83l771";
+ }
}
if (!name) { /* identification failed */
@@ -794,6 +809,19 @@ static int lm90_probe(struct i2c_client *new_client,
new_client->flags &= ~I2C_CLIENT_PEC;
}
+ /* Different devices have different alarm bits triggering the
+ * ALERT# output */
+ switch (data->kind) {
+ case lm90:
+ case lm99:
+ case lm86:
+ data->alert_alarms = 0x7b;
+ break;
+ default:
+ data->alert_alarms = 0x7c;
+ break;
+ }
+
/* Initialize the LM90 chip */
lm90_init_client(new_client);
@@ -830,7 +858,7 @@ exit:
static void lm90_init_client(struct i2c_client *client)
{
- u8 config, config_orig;
+ u8 config;
struct lm90_data *data = i2c_get_clientdata(client);
/*
@@ -842,7 +870,7 @@ static void lm90_init_client(struct i2c_client *client)
dev_warn(&client->dev, "Initialization failed!\n");
return;
}
- config_orig = config;
+ data->config_orig = config;
/* Check Temperature Range Select */
if (data->kind == adt7461) {
@@ -860,7 +888,7 @@ static void lm90_init_client(struct i2c_client *client)
}
config &= 0xBF; /* run */
- if (config != config_orig) /* Only write if changed */
+ if (config != data->config_orig) /* Only write if changed */
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
}
@@ -875,10 +903,46 @@ static int lm90_remove(struct i2c_client *client)
device_remove_file(&client->dev,
&sensor_dev_attr_temp2_offset.dev_attr);
+ /* Restore initial configuration */
+ i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
+ data->config_orig);
+
kfree(data);
return 0;
}
+static void lm90_alert(struct i2c_client *client, unsigned int flag)
+{
+ struct lm90_data *data = i2c_get_clientdata(client);
+ u8 config, alarms;
+
+ lm90_read_reg(client, LM90_REG_R_STATUS, &alarms);
+ if ((alarms & 0x7f) == 0) {
+ dev_info(&client->dev, "Everything OK\n");
+ } else {
+ if (alarms & 0x61)
+ dev_warn(&client->dev,
+ "temp%d out of range, please check!\n", 1);
+ if (alarms & 0x1a)
+ dev_warn(&client->dev,
+ "temp%d out of range, please check!\n", 2);
+ if (alarms & 0x04)
+ dev_warn(&client->dev,
+ "temp%d diode open, please check!\n", 2);
+
+ /* Disable ALERT# output, because these chips don't implement
+ SMBus alert correctly; they should only hold the alert line
+ low briefly. */
+ if ((data->kind == adm1032 || data->kind == adt7461)
+ && (alarms & data->alert_alarms)) {
+ dev_dbg(&client->dev, "Disabling ALERT#\n");
+ lm90_read_reg(client, LM90_REG_R_CONFIG1, &config);
+ i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
+ config | 0x80);
+ }
+ }
+}
+
static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value)
{
int err;
@@ -966,6 +1030,21 @@ static struct lm90_data *lm90_update_device(struct device *dev)
}
lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms);
+ /* Re-enable ALERT# output if it was originally enabled and
+ * relevant alarms are all clear */
+ if ((data->config_orig & 0x80) == 0
+ && (data->alarms & data->alert_alarms) == 0) {
+ u8 config;
+
+ lm90_read_reg(client, LM90_REG_R_CONFIG1, &config);
+ if (config & 0x80) {
+ dev_dbg(&client->dev, "Re-enabling ALERT#\n");
+ i2c_smbus_write_byte_data(client,
+ LM90_REG_W_CONFIG1,
+ config & ~0x80);
+ }
+ }
+
data->last_updated = jiffies;
data->valid = 1;
}
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 9ca97818bd4b..8fa462f2b570 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -488,7 +488,7 @@ static int __init smsc47m1_find(unsigned short *addr,
}
/* Restore device to its initial state */
-static void __init smsc47m1_restore(const struct smsc47m1_sio_data *sio_data)
+static void smsc47m1_restore(const struct smsc47m1_sio_data *sio_data)
{
if ((sio_data->activate & 0x01) == 0) {
superio_enter();
diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c
index a13b30e8d8d8..d14a1af9f550 100644
--- a/drivers/hwmon/tmp401.c
+++ b/drivers/hwmon/tmp401.c
@@ -134,7 +134,7 @@ struct tmp401_data {
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
- int kind;
+ enum chips kind;
/* register values */
u8 status;
@@ -524,7 +524,7 @@ static int tmp401_detect(struct i2c_client *client,
if (reg > 15)
return -ENODEV;
- strlcpy(info->type, tmp401_id[kind - 1].name, I2C_NAME_SIZE);
+ strlcpy(info->type, tmp401_id[kind].name, I2C_NAME_SIZE);
return 0;
}
@@ -572,8 +572,7 @@ static int tmp401_probe(struct i2c_client *client,
goto exit_remove;
}
- dev_info(&client->dev, "Detected TI %s chip\n",
- names[data->kind - 1]);
+ dev_info(&client->dev, "Detected TI %s chip\n", names[data->kind]);
return 0;
diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
index 4f7c051e2d7b..738c472ece27 100644
--- a/drivers/hwmon/tmp421.c
+++ b/drivers/hwmon/tmp421.c
@@ -61,9 +61,9 @@ static const u8 TMP421_TEMP_LSB[4] = { 0x10, 0x11, 0x12, 0x13 };
#define TMP423_DEVICE_ID 0x23
static const struct i2c_device_id tmp421_id[] = {
- { "tmp421", tmp421 },
- { "tmp422", tmp422 },
- { "tmp423", tmp423 },
+ { "tmp421", 2 },
+ { "tmp422", 3 },
+ { "tmp423", 4 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp421_id);
@@ -73,21 +73,23 @@ struct tmp421_data {
struct mutex update_lock;
char valid;
unsigned long last_updated;
- int kind;
+ int channels;
u8 config;
s16 temp[4];
};
static int temp_from_s16(s16 reg)
{
- int temp = reg;
+ /* Mask out status bits */
+ int temp = reg & ~0xf;
return (temp * 1000 + 128) / 256;
}
static int temp_from_u16(u16 reg)
{
- int temp = reg;
+ /* Mask out status bits */
+ int temp = reg & ~0xf;
/* Add offset for extended temperature range. */
temp -= 64 * 256;
@@ -107,7 +109,7 @@ static struct tmp421_data *tmp421_update_device(struct device *dev)
data->config = i2c_smbus_read_byte_data(client,
TMP421_CONFIG_REG_1);
- for (i = 0; i <= data->kind; i++) {
+ for (i = 0; i < data->channels; i++) {
data->temp[i] = i2c_smbus_read_byte_data(client,
TMP421_TEMP_MSB[i]) << 8;
data->temp[i] |= i2c_smbus_read_byte_data(client,
@@ -166,7 +168,7 @@ static mode_t tmp421_is_visible(struct kobject *kobj, struct attribute *a,
devattr = container_of(a, struct device_attribute, attr);
index = to_sensor_dev_attr(devattr)->index;
- if (data->kind > index)
+ if (index < data->channels)
return a->mode;
return 0;
@@ -252,9 +254,9 @@ static int tmp421_detect(struct i2c_client *client,
return -ENODEV;
}
- strlcpy(info->type, tmp421_id[kind - 1].name, I2C_NAME_SIZE);
+ strlcpy(info->type, tmp421_id[kind].name, I2C_NAME_SIZE);
dev_info(&adapter->dev, "Detected TI %s chip at 0x%02x\n",
- names[kind - 1], client->addr);
+ names[kind], client->addr);
return 0;
}
@@ -271,7 +273,7 @@ static int tmp421_probe(struct i2c_client *client,
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
- data->kind = id->driver_data;
+ data->channels = id->driver_data;
err = tmp421_init_client(client);
if (err)
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index d47b4c9949c2..e6078c9f0e27 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -948,8 +948,7 @@ static int __devinit vt8231_pci_probe(struct pci_dev *dev,
address = val & ~(VT8231_EXTENT - 1);
if (address == 0) {
- dev_err(&dev->dev, "base address not set -\
- upgrade BIOS or use force_addr=0xaddr\n");
+ dev_err(&dev->dev, "base address not set - upgrade BIOS or use force_addr=0xaddr\n");
return -ENODEV;
}
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index 05f9225b6f94..32d4adee73db 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -1793,17 +1793,17 @@ static int __init
w83781d_isa_found(unsigned short address)
{
int val, save, found = 0;
-
- /* We have to request the region in two parts because some
- boards declare base+4 to base+7 as a PNP device */
- if (!request_region(address, 4, "w83781d")) {
- pr_debug("w83781d: Failed to request low part of region\n");
- return 0;
- }
- if (!request_region(address + 4, 4, "w83781d")) {
- pr_debug("w83781d: Failed to request high part of region\n");
- release_region(address, 4);
- return 0;
+ int port;
+
+ /* Some boards declare base+0 to base+7 as a PNP device, some base+4
+ * to base+7 and some base+5 to base+6. So we better request each port
+ * individually for the probing phase. */
+ for (port = address; port < address + W83781D_EXTENT; port++) {
+ if (!request_region(port, 1, "w83781d")) {
+ pr_debug("w83781d: Failed to request port 0x%x\n",
+ port);
+ goto release;
+ }
}
#define REALLY_SLOW_IO
@@ -1877,8 +1877,8 @@ w83781d_isa_found(unsigned short address)
val == 0x30 ? "W83782D" : "W83781D", (int)address);
release:
- release_region(address + 4, 4);
- release_region(address, 4);
+ for (port--; port >= address; port--)
+ release_region(port, 1);
return found;
}
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 9a2022b67495..9de81a4c15a2 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -3,6 +3,10 @@
Copyright (C) 2006 Winbond Electronics Corp.
Yuan Mu
Rudolf Marek <r.marek@assembler.cz>
+ Copyright (C) 2009-2010 Sven Anders <anders@anduras.de>, ANDURAS AG.
+ Watchdog driver part
+ (Based partially on fschmd driver,
+ Copyright 2007-2008 by Hans de Goede)
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
@@ -35,6 +39,16 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/fs.h>
+#include <linux/watchdog.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kref.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+/* Default values */
+#define WATCHDOG_TIMEOUT 2 /* 2 minute default timeout */
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
@@ -51,6 +65,18 @@ static int reset;
module_param(reset, bool, 0);
MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
+static int timeout = WATCHDOG_TIMEOUT; /* default timeout in minutes */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,
+ "Watchdog timeout in minutes. 2<= timeout <=255 (default="
+ __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
/*
Address 0x00, 0x0d, 0x0e, 0x0f in all three banks are reserved
as ID, Bank Select registers
@@ -72,6 +98,11 @@ MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
#define W83793_REG_VID_LATCHB 0x08
#define W83793_REG_VID_CTRL 0x59
+#define W83793_REG_WDT_LOCK 0x01
+#define W83793_REG_WDT_ENABLE 0x02
+#define W83793_REG_WDT_STATUS 0x03
+#define W83793_REG_WDT_TIMEOUT 0x04
+
static u16 W83793_REG_TEMP_MODE[2] = { 0x5e, 0x5f };
#define TEMP_READ 0
@@ -223,8 +254,37 @@ struct w83793_data {
u8 tolerance[3]; /* Temp tolerance(Smart Fan I/II) */
u8 sf2_pwm[6][7]; /* Smart FanII: Fan duty cycle */
u8 sf2_temp[6][7]; /* Smart FanII: Temp level point */
+
+ /* watchdog */
+ struct i2c_client *client;
+ struct mutex watchdog_lock;
+ struct list_head list; /* member of the watchdog_data_list */
+ struct kref kref;
+ struct miscdevice watchdog_miscdev;
+ unsigned long watchdog_is_open;
+ char watchdog_expect_close;
+ char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
+ unsigned int watchdog_caused_reboot;
+ int watchdog_timeout; /* watchdog timeout in minutes */
};
+/* Somewhat ugly :( global data pointer list with all devices, so that
+ we can find our device data as when using misc_register. There is no
+ other method to get to one's device data from the open file-op and
+ for usage in the reboot notifier callback. */
+static LIST_HEAD(watchdog_data_list);
+
+/* Note this lock not only protect list access, but also data.kref access */
+static DEFINE_MUTEX(watchdog_data_mutex);
+
+/* Release our data struct when we're detached from the i2c client *and* all
+ references to our watchdog device are released */
+static void w83793_release_resources(struct kref *ref)
+{
+ struct w83793_data *data = container_of(ref, struct w83793_data, kref);
+ kfree(data);
+}
+
static u8 w83793_read_value(struct i2c_client *client, u16 reg);
static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value);
static int w83793_probe(struct i2c_client *client,
@@ -1063,14 +1123,349 @@ static void w83793_init_client(struct i2c_client *client)
/* Start monitoring */
w83793_write_value(client, W83793_REG_CONFIG,
w83793_read_value(client, W83793_REG_CONFIG) | 0x01);
+}
+
+/*
+ * Watchdog routines
+ */
+
+static int watchdog_set_timeout(struct w83793_data *data, int timeout)
+{
+ int ret, mtimeout;
+
+ mtimeout = DIV_ROUND_UP(timeout, 60);
+
+ if (mtimeout > 255)
+ return -EINVAL;
+
+ mutex_lock(&data->watchdog_lock);
+ if (!data->client) {
+ ret = -ENODEV;
+ goto leave;
+ }
+
+ data->watchdog_timeout = mtimeout;
+
+ /* Set Timeout value (in Minutes) */
+ w83793_write_value(data->client, W83793_REG_WDT_TIMEOUT,
+ data->watchdog_timeout);
+
+ ret = mtimeout * 60;
+
+leave:
+ mutex_unlock(&data->watchdog_lock);
+ return ret;
+}
+
+static int watchdog_get_timeout(struct w83793_data *data)
+{
+ int timeout;
+
+ mutex_lock(&data->watchdog_lock);
+ timeout = data->watchdog_timeout * 60;
+ mutex_unlock(&data->watchdog_lock);
+
+ return timeout;
+}
+
+static int watchdog_trigger(struct w83793_data *data)
+{
+ int ret = 0;
+
+ mutex_lock(&data->watchdog_lock);
+ if (!data->client) {
+ ret = -ENODEV;
+ goto leave;
+ }
+
+ /* Set Timeout value (in Minutes) */
+ w83793_write_value(data->client, W83793_REG_WDT_TIMEOUT,
+ data->watchdog_timeout);
+
+leave:
+ mutex_unlock(&data->watchdog_lock);
+ return ret;
+}
+
+static int watchdog_enable(struct w83793_data *data)
+{
+ int ret = 0;
+
+ mutex_lock(&data->watchdog_lock);
+ if (!data->client) {
+ ret = -ENODEV;
+ goto leave;
+ }
+
+ /* Set initial timeout */
+ w83793_write_value(data->client, W83793_REG_WDT_TIMEOUT,
+ data->watchdog_timeout);
+
+ /* Enable Soft Watchdog */
+ w83793_write_value(data->client, W83793_REG_WDT_LOCK, 0x55);
+
+leave:
+ mutex_unlock(&data->watchdog_lock);
+ return ret;
+}
+
+static int watchdog_disable(struct w83793_data *data)
+{
+ int ret = 0;
+
+ mutex_lock(&data->watchdog_lock);
+ if (!data->client) {
+ ret = -ENODEV;
+ goto leave;
+ }
+
+ /* Disable Soft Watchdog */
+ w83793_write_value(data->client, W83793_REG_WDT_LOCK, 0xAA);
+
+leave:
+ mutex_unlock(&data->watchdog_lock);
+ return ret;
+}
+
+static int watchdog_open(struct inode *inode, struct file *filp)
+{
+ struct w83793_data *pos, *data = NULL;
+ int watchdog_is_open;
+
+ /* We get called from drivers/char/misc.c with misc_mtx hold, and we
+ call misc_register() from w83793_probe() with watchdog_data_mutex
+ hold, as misc_register() takes the misc_mtx lock, this is a possible
+ deadlock, so we use mutex_trylock here. */
+ if (!mutex_trylock(&watchdog_data_mutex))
+ return -ERESTARTSYS;
+ list_for_each_entry(pos, &watchdog_data_list, list) {
+ if (pos->watchdog_miscdev.minor == iminor(inode)) {
+ data = pos;
+ break;
+ }
+ }
+
+ /* Check, if device is already open */
+ watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open);
+
+ /* Increase data reference counter (if not already done).
+ Note we can never not have found data, so we don't check for this */
+ if (!watchdog_is_open)
+ kref_get(&data->kref);
+
+ mutex_unlock(&watchdog_data_mutex);
+
+ /* Check, if device is already open and possibly issue error */
+ if (watchdog_is_open)
+ return -EBUSY;
+
+ /* Enable Soft Watchdog */
+ watchdog_enable(data);
+
+ /* Store pointer to data into filp's private data */
+ filp->private_data = data;
+
+ return nonseekable_open(inode, filp);
+}
+
+static int watchdog_close(struct inode *inode, struct file *filp)
+{
+ struct w83793_data *data = filp->private_data;
+ if (data->watchdog_expect_close) {
+ watchdog_disable(data);
+ data->watchdog_expect_close = 0;
+ } else {
+ watchdog_trigger(data);
+ dev_crit(&data->client->dev,
+ "unexpected close, not stopping watchdog!\n");
+ }
+
+ clear_bit(0, &data->watchdog_is_open);
+
+ /* Decrease data reference counter */
+ mutex_lock(&watchdog_data_mutex);
+ kref_put(&data->kref, w83793_release_resources);
+ mutex_unlock(&watchdog_data_mutex);
+
+ return 0;
+}
+
+static ssize_t watchdog_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ size_t ret;
+ struct w83793_data *data = filp->private_data;
+
+ if (count) {
+ if (!nowayout) {
+ size_t i;
+
+ /* Clear it in case it was set with a previous write */
+ data->watchdog_expect_close = 0;
+
+ for (i = 0; i != count; i++) {
+ char c;
+ if (get_user(c, buf + i))
+ return -EFAULT;
+ if (c == 'V')
+ data->watchdog_expect_close = 1;
+ }
+ }
+ ret = watchdog_trigger(data);
+ if (ret < 0)
+ return ret;
+ }
+ return count;
+}
+
+static int watchdog_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ static struct watchdog_info ident = {
+ .options = WDIOF_KEEPALIVEPING |
+ WDIOF_SETTIMEOUT |
+ WDIOF_CARDRESET,
+ .identity = "w83793 watchdog"
+ };
+
+ int val, ret = 0;
+ struct w83793_data *data = filp->private_data;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (!nowayout)
+ ident.options |= WDIOF_MAGICCLOSE;
+ if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
+ ret = -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ val = data->watchdog_caused_reboot ? WDIOF_CARDRESET : 0;
+ ret = put_user(val, (int __user *)arg);
+ break;
+
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, (int __user *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ ret = watchdog_trigger(data);
+ break;
+
+ case WDIOC_GETTIMEOUT:
+ val = watchdog_get_timeout(data);
+ ret = put_user(val, (int __user *)arg);
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(val, (int __user *)arg)) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = watchdog_set_timeout(data, val);
+ if (ret > 0)
+ ret = put_user(ret, (int __user *)arg);
+ break;
+
+ case WDIOC_SETOPTIONS:
+ if (get_user(val, (int __user *)arg)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ if (val & WDIOS_DISABLECARD)
+ ret = watchdog_disable(data);
+ else if (val & WDIOS_ENABLECARD)
+ ret = watchdog_enable(data);
+ else
+ ret = -EINVAL;
+
+ break;
+ default:
+ ret = -ENOTTY;
+ }
+
+ return ret;
+}
+
+static const struct file_operations watchdog_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .open = watchdog_open,
+ .release = watchdog_close,
+ .write = watchdog_write,
+ .ioctl = watchdog_ioctl,
+};
+
+/*
+ * Notifier for system down
+ */
+
+static int watchdog_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ struct w83793_data *data = NULL;
+
+ if (code == SYS_DOWN || code == SYS_HALT) {
+
+ /* Disable each registered watchdog */
+ mutex_lock(&watchdog_data_mutex);
+ list_for_each_entry(data, &watchdog_data_list, list) {
+ if (data->watchdog_miscdev.minor)
+ watchdog_disable(data);
+ }
+ mutex_unlock(&watchdog_data_mutex);
+ }
+
+ return NOTIFY_DONE;
}
+/*
+ * The WDT needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+
+static struct notifier_block watchdog_notifier = {
+ .notifier_call = watchdog_notify_sys,
+};
+
+/*
+ * Init / remove routines
+ */
+
static int w83793_remove(struct i2c_client *client)
{
struct w83793_data *data = i2c_get_clientdata(client);
struct device *dev = &client->dev;
- int i;
+ int i, tmp;
+
+ /* Unregister the watchdog (if registered) */
+ if (data->watchdog_miscdev.minor) {
+ misc_deregister(&data->watchdog_miscdev);
+
+ if (data->watchdog_is_open) {
+ dev_warn(&client->dev,
+ "i2c client detached with watchdog open! "
+ "Stopping watchdog.\n");
+ watchdog_disable(data);
+ }
+
+ mutex_lock(&watchdog_data_mutex);
+ list_del(&data->list);
+ mutex_unlock(&watchdog_data_mutex);
+
+ /* Tell the watchdog code the client is gone */
+ mutex_lock(&data->watchdog_lock);
+ data->client = NULL;
+ mutex_unlock(&data->watchdog_lock);
+ }
+
+ /* Reset Configuration Register to Disable Watch Dog Registers */
+ tmp = w83793_read_value(client, W83793_REG_CONFIG);
+ w83793_write_value(client, W83793_REG_CONFIG, tmp & ~0x04);
+
+ unregister_reboot_notifier(&watchdog_notifier);
hwmon_device_unregister(data->hwmon_dev);
@@ -1099,7 +1494,10 @@ static int w83793_remove(struct i2c_client *client)
if (data->lm75[1] != NULL)
i2c_unregister_device(data->lm75[1]);
- kfree(data);
+ /* Decrease data reference counter */
+ mutex_lock(&watchdog_data_mutex);
+ kref_put(&data->kref, w83793_release_resources);
+ mutex_unlock(&watchdog_data_mutex);
return 0;
}
@@ -1203,6 +1601,7 @@ static int w83793_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
+ const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
struct w83793_data *data;
int i, tmp, val, err;
int files_fan = ARRAY_SIZE(w83793_left_fan) / 7;
@@ -1218,6 +1617,14 @@ static int w83793_probe(struct i2c_client *client,
i2c_set_clientdata(client, data);
data->bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL);
mutex_init(&data->update_lock);
+ mutex_init(&data->watchdog_lock);
+ INIT_LIST_HEAD(&data->list);
+ kref_init(&data->kref);
+
+ /* Store client pointer in our data struct for watchdog usage
+ (where the client is found through a data ptr instead of the
+ otherway around) */
+ data->client = client;
err = w83793_detect_subclients(client);
if (err)
@@ -1380,8 +1787,77 @@ static int w83793_probe(struct i2c_client *client,
goto exit_remove;
}
+ /* Watchdog initialization */
+
+ /* Register boot notifier */
+ err = register_reboot_notifier(&watchdog_notifier);
+ if (err != 0) {
+ dev_err(&client->dev,
+ "cannot register reboot notifier (err=%d)\n", err);
+ goto exit_devunreg;
+ }
+
+ /* Enable Watchdog registers.
+ Set Configuration Register to Enable Watch Dog Registers
+ (Bit 2) = XXXX, X1XX. */
+ tmp = w83793_read_value(client, W83793_REG_CONFIG);
+ w83793_write_value(client, W83793_REG_CONFIG, tmp | 0x04);
+
+ /* Set the default watchdog timeout */
+ data->watchdog_timeout = timeout;
+
+ /* Check, if last reboot was caused by watchdog */
+ data->watchdog_caused_reboot =
+ w83793_read_value(data->client, W83793_REG_WDT_STATUS) & 0x01;
+
+ /* Disable Soft Watchdog during initialiation */
+ watchdog_disable(data);
+
+ /* We take the data_mutex lock early so that watchdog_open() cannot
+ run when misc_register() has completed, but we've not yet added
+ our data to the watchdog_data_list (and set the default timeout) */
+ mutex_lock(&watchdog_data_mutex);
+ for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) {
+ /* Register our watchdog part */
+ snprintf(data->watchdog_name, sizeof(data->watchdog_name),
+ "watchdog%c", (i == 0) ? '\0' : ('0' + i));
+ data->watchdog_miscdev.name = data->watchdog_name;
+ data->watchdog_miscdev.fops = &watchdog_fops;
+ data->watchdog_miscdev.minor = watchdog_minors[i];
+
+ err = misc_register(&data->watchdog_miscdev);
+ if (err == -EBUSY)
+ continue;
+ if (err) {
+ data->watchdog_miscdev.minor = 0;
+ dev_err(&client->dev,
+ "Registering watchdog chardev: %d\n", err);
+ break;
+ }
+
+ list_add(&data->list, &watchdog_data_list);
+
+ dev_info(&client->dev,
+ "Registered watchdog chardev major 10, minor: %d\n",
+ watchdog_minors[i]);
+ break;
+ }
+ if (i == ARRAY_SIZE(watchdog_minors)) {
+ data->watchdog_miscdev.minor = 0;
+ dev_warn(&client->dev, "Couldn't register watchdog chardev "
+ "(due to no free minor)\n");
+ }
+
+ mutex_unlock(&watchdog_data_mutex);
+
return 0;
+ /* Unregister hwmon device */
+
+exit_devunreg:
+
+ hwmon_device_unregister(data->hwmon_dev);
+
/* Unregister sysfs hooks */
exit_remove:
@@ -1628,7 +2104,7 @@ static void __exit sensors_w83793_exit(void)
i2c_del_driver(&w83793_driver);
}
-MODULE_AUTHOR("Yuan Mu");
+MODULE_AUTHOR("Yuan Mu, Sven Anders");
MODULE_DESCRIPTION("w83793 driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 8d8a00e5a30e..d06083fdffbb 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -61,9 +61,18 @@ config I2C_HELPER_AUTO
In doubt, say Y.
+config I2C_SMBUS
+ tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO
+ help
+ Say Y here if you want support for SMBus extensions to the I2C
+ specification. At the moment, the only supported extension is
+ the SMBus alert protocol.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-smbus.
+
source drivers/i2c/algos/Kconfig
source drivers/i2c/busses/Kconfig
-source drivers/i2c/chips/Kconfig
config I2C_DEBUG_CORE
bool "I2C Core debugging messages"
@@ -88,12 +97,4 @@ config I2C_DEBUG_BUS
a problem with I2C support and want to see more of what is going
on.
-config I2C_DEBUG_CHIP
- bool "I2C Chip debugging messages"
- help
- Say Y here if you want the I2C chip drivers to produce a bunch of
- debug messages to the system log. Select this if you are having
- a problem with I2C support and want to see more of what is going
- on.
-
endif # I2C
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index ba26e6cbe74e..a7d9b4be9bb3 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -4,8 +4,9 @@
obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o
obj-$(CONFIG_I2C) += i2c-core.o
+obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
-obj-y += busses/ chips/ algos/
+obj-y += algos/ busses/
ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index e25e13980af3..e8d568c3fb09 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -522,6 +522,12 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
int i, ret;
unsigned short nak_ok;
+ if (adap->pre_xfer) {
+ ret = adap->pre_xfer(i2c_adap);
+ if (ret < 0)
+ return ret;
+ }
+
bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
i2c_start(adap);
for (i = 0; i < num; i++) {
@@ -570,6 +576,9 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
bailout:
bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
i2c_stop(adap);
+
+ if (adap->post_xfer)
+ adap->post_xfer(i2c_adap);
return ret;
}
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index 78d42aae0089..dcdaf8e675bf 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -453,8 +453,6 @@ static int pca_init(struct i2c_adapter *adap)
*/
int raise_fall_time;
- struct i2c_algo_pca_data *pca_data = adap->algo_data;
-
/* Ignore the reset function from the module,
* we can use the parallel bus reset
*/
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index 7ce75775ec73..6b6bd06202b2 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -176,7 +176,7 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
*/
if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) {
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp));
- return -ENXIO; /* definetly not PCF8584 */
+ return -ENXIO; /* definitely not PCF8584 */
}
/* load own address in S0, effective address is (own << 1) */
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 5f318ce29770..9c6170cd9aac 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -77,7 +77,7 @@ config I2C_AMD8111
will be called i2c-amd8111.
config I2C_I801
- tristate "Intel 82801 (ICH)"
+ tristate "Intel 82801 (ICH/PCH)"
depends on PCI
help
If you say yes to this option, support will be included for the Intel
@@ -97,7 +97,8 @@ config I2C_I801
ICH9
Tolapai
ICH10
- PCH
+ 3400/5 Series (PCH)
+ Cougar Point (PCH)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -105,6 +106,8 @@ config I2C_I801
config I2C_ISCH
tristate "Intel SCH SMBus 1.0"
depends on PCI
+ select MFD_CORE
+ select LPC_SCH
help
Say Y here if you want to use SMBus controller on the Intel SCH
based systems.
@@ -418,13 +421,12 @@ config I2C_IXP2000
instead.
config I2C_MPC
- tristate "MPC107/824x/85xx/52xx/86xx"
+ tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
depends on PPC32
help
If you say yes to this option, support will be included for the
- built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
- MPC85xx/MPC8641 family processors. The driver may also work on 52xx
- family processors, though interrupts are known not to work.
+ built-in I2C interface on the MPC107, Tsi107, MPC512x, MPC52xx,
+ MPC8240, MPC8245, MPC83xx, MPC85xx and MPC8641 family processors.
This driver can also be built as a module. If so, the module
will be called i2c-mpc.
@@ -439,6 +441,13 @@ config I2C_MV64XXX
This driver can also be built as a module. If so, the module
will be called i2c-mv64xxx.
+config I2C_NOMADIK
+ tristate "ST-Ericsson Nomadik/Ux500 I2C Controller"
+ depends on PLAT_NOMADIK
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface from ST-Ericsson's Nomadik and Ux500 architectures.
+
config I2C_OCORES
tristate "OpenCores I2C Controller"
depends on EXPERIMENTAL
@@ -564,12 +573,33 @@ config I2C_VERSATILE
This driver can also be built as a module. If so, the module
will be called i2c-versatile.
+config I2C_OCTEON
+ tristate "Cavium OCTEON I2C bus support"
+ depends on CPU_CAVIUM_OCTEON
+ help
+ Say yes if you want to support the I2C serial bus on Cavium
+ OCTEON SOC.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-octeon.
+
+config I2C_XILINX
+ tristate "Xilinx I2C Controller"
+ depends on EXPERIMENTAL && HAS_IOMEM
+ help
+ If you say yes to this option, support will be included for the
+ Xilinx I2C controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called xilinx_i2c.
+
comment "External I2C/SMBus adapter drivers"
config I2C_PARPORT
tristate "Parallel port adapter"
depends on PARPORT
select I2C_ALGOBIT
+ select I2C_SMBUS
help
This supports parallel port I2C adapters such as the ones made by
Philips or Velleman, Analog Devices evaluation boards, and more.
@@ -593,6 +623,7 @@ config I2C_PARPORT
config I2C_PARPORT_LIGHT
tristate "Parallel port adapter (light)"
select I2C_ALGOBIT
+ select I2C_SMBUS
help
This supports parallel port I2C adapters such as the ones made by
Philips or Velleman, Analog Devices evaluation boards, and more.
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 302c551977bb..097236f631e8 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
+obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
@@ -54,6 +55,8 @@ obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
+obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
+obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
# External I2C/SMBus adapter drivers
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index 8de7d7b87bb0..bd8f1e4d9e6c 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -480,7 +480,7 @@ static struct i2c_adapter ali1535_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id ali1535_ids[] = {
+static const struct pci_device_id ali1535_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ },
};
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index f70f46582c6c..a409cfcf0629 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -87,9 +87,9 @@ static int ali1563_transaction(struct i2c_adapter * a, int size)
outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2);
timeout = ALI1563_MAX_TIMEOUT;
- do
+ do {
msleep(1);
- while (((data = inb_p(SMB_HST_STS)) & HST_STS_BUSY) && --timeout);
+ } while (((data = inb_p(SMB_HST_STS)) & HST_STS_BUSY) && --timeout);
dev_dbg(&a->dev, "Transaction (post): STS=%02x, CNTL1=%02x, "
"CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
@@ -157,9 +157,9 @@ static int ali1563_block_start(struct i2c_adapter * a)
outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2);
timeout = ALI1563_MAX_TIMEOUT;
- do
+ do {
msleep(1);
- while (!((data = inb_p(SMB_HST_STS)) & HST_STS_DONE) && --timeout);
+ } while (!((data = inb_p(SMB_HST_STS)) & HST_STS_DONE) && --timeout);
dev_dbg(&a->dev, "Block (post): STS=%02x, CNTL1=%02x, "
"CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
@@ -417,7 +417,7 @@ static void __devexit ali1563_remove(struct pci_dev * dev)
ali1563_shutdown(dev);
}
-static struct pci_device_id __devinitdata ali1563_id_table[] = {
+static const struct pci_device_id ali1563_id_table[] __devinitconst = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) },
{},
};
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index e7e3205f1286..659f63f5e4af 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -477,7 +477,7 @@ static struct i2c_adapter ali15x3_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id ali15x3_ids[] = {
+static const struct pci_device_id ali15x3_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 8f0b90ef8c76..c5a9fa488e7f 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -308,7 +308,7 @@ static const char* chipname[] = {
"nVidia nForce", "AMD8111",
};
-static struct pci_device_id amd756_ids[] = {
+static const struct pci_device_id amd756_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B),
.driver_data = AMD756 },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413),
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index 5b4ad86ca166..d0dc970d7370 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -351,7 +351,7 @@ static const struct i2c_algorithm smbus_algorithm = {
};
-static struct pci_device_id amd8111_ids[] = {
+static const struct pci_device_id amd8111_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c
index 9e18ef97f156..3e72b69aa7f8 100644
--- a/drivers/i2c/busses/i2c-designware.c
+++ b/drivers/i2c/busses/i2c-designware.c
@@ -497,13 +497,13 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
int i;
if (abort_source & DW_IC_TX_ABRT_NOACK) {
- for_each_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+ for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
dev_dbg(dev->dev,
"%s: %s\n", __func__, abort_sources[i]);
return -EREMOTEIO;
}
- for_each_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+ for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
if (abort_source & DW_IC_TX_ARB_LOST)
diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
index bec9b845dd16..c767295ad1fb 100644
--- a/drivers/i2c/busses/i2c-hydra.c
+++ b/drivers/i2c/busses/i2c-hydra.c
@@ -105,7 +105,7 @@ static struct i2c_adapter hydra_adap = {
.algo_data = &hydra_bit_data,
};
-static struct pci_device_id hydra_ids[] = {
+static const struct pci_device_id hydra_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index df6ab553f975..299b918455a3 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -41,7 +41,8 @@
Tolapai 0x5032 32 hard yes yes yes
ICH10 0x3a30 32 hard yes yes yes
ICH10 0x3a60 32 hard yes yes yes
- PCH 0x3b30 32 hard yes yes yes
+ 3400/5 Series (PCH) 0x3b30 32 hard yes yes yes
+ Cougar Point (PCH) 0x1c22 32 hard yes yes yes
Features supported by this driver:
Software PEC no
@@ -415,9 +416,11 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
data->block[0] = 32; /* max for SMBus block reads */
}
+ /* Experience has shown that the block buffer can only be used for
+ SMBus (not I2C) block transactions, even though the datasheet
+ doesn't mention this limitation. */
if ((i801_features & FEATURE_BLOCK_BUFFER)
- && !(command == I2C_SMBUS_I2C_BLOCK_DATA
- && read_write == I2C_SMBUS_READ)
+ && command != I2C_SMBUS_I2C_BLOCK_DATA
&& i801_set_block_buffer_mode() == 0)
result = i801_block_transaction_by_block(data, read_write,
hwpec);
@@ -561,7 +564,7 @@ static struct i2c_adapter i801_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id i801_ids[] = {
+static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) },
@@ -578,6 +581,7 @@ static struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CPT_SMBUS) },
{ 0, }
};
@@ -707,6 +711,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
case PCI_DEVICE_ID_INTEL_ICH10_4:
case PCI_DEVICE_ID_INTEL_ICH10_5:
case PCI_DEVICE_ID_INTEL_PCH_SMBUS:
+ case PCI_DEVICE_ID_INTEL_CPT_SMBUS:
i801_features |= FEATURE_I2C_BLOCK_READ;
/* fall through */
case PCI_DEVICE_ID_INTEL_82801DB_3:
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index e3654d683e15..32375bddae7d 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -226,7 +226,6 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
temp = readb(i2c_imx->base + IMX_I2C_I2CR);
temp &= ~(I2CR_MSTA | I2CR_MTX);
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
- i2c_imx->stopped = 1;
}
if (cpu_is_mx1()) {
/*
@@ -236,8 +235,10 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
udelay(i2c_imx->disable_delay);
}
- if (!i2c_imx->stopped)
+ if (!i2c_imx->stopped) {
i2c_imx_bus_busy(i2c_imx, 0);
+ i2c_imx->stopped = 1;
+ }
/* Disable I2C controller */
writeb(0, i2c_imx->base + IMX_I2C_I2CR);
@@ -496,22 +497,23 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
}
res_size = resource_size(res);
+
+ if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
+ ret = -EBUSY;
+ goto fail0;
+ }
+
base = ioremap(res->start, res_size);
if (!base) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -EIO;
- goto fail0;
+ goto fail1;
}
i2c_imx = kzalloc(sizeof(struct imx_i2c_struct), GFP_KERNEL);
if (!i2c_imx) {
dev_err(&pdev->dev, "can't allocate interface\n");
ret = -ENOMEM;
- goto fail1;
- }
-
- if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
- ret = -EBUSY;
goto fail2;
}
@@ -582,11 +584,11 @@ fail5:
fail4:
clk_put(i2c_imx->clk);
fail3:
- release_mem_region(i2c_imx->res->start, resource_size(res));
-fail2:
kfree(i2c_imx);
-fail1:
+fail2:
iounmap(base);
+fail1:
+ release_mem_region(res->start, resource_size(res));
fail0:
if (pdata && pdata->exit)
pdata->exit(&pdev->dev);
@@ -618,14 +620,13 @@ static int __exit i2c_imx_remove(struct platform_device *pdev)
clk_put(i2c_imx->clk);
- release_mem_region(i2c_imx->res->start, resource_size(i2c_imx->res));
iounmap(i2c_imx->base);
+ release_mem_region(i2c_imx->res->start, resource_size(i2c_imx->res));
kfree(i2c_imx);
return 0;
}
static struct platform_driver i2c_imx_driver = {
- .probe = i2c_imx_probe,
.remove = __exit_p(i2c_imx_remove),
.driver = {
.name = DRIVER_NAME,
diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c
index dba6eb053e2f..ddc258edb34f 100644
--- a/drivers/i2c/busses/i2c-isch.c
+++ b/drivers/i2c/busses/i2c-isch.c
@@ -27,7 +27,7 @@
*/
#include <linux/module.h>
-#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/stddef.h>
@@ -46,12 +46,6 @@
#define SMBHSTDAT1 (7 + sch_smba)
#define SMBBLKDAT (0x20 + sch_smba)
-/* count for request_region */
-#define SMBIOSIZE 64
-
-/* PCI Address Constants */
-#define SMBBA_SCH 0x40
-
/* Other settings */
#define MAX_TIMEOUT 500
@@ -63,7 +57,6 @@
#define SCH_BLOCK_DATA 0x05
static unsigned short sch_smba;
-static struct pci_driver sch_driver;
static struct i2c_adapter sch_adapter;
/*
@@ -256,37 +249,23 @@ static struct i2c_adapter sch_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id sch_ids[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, sch_ids);
-
-static int __devinit sch_probe(struct pci_dev *dev,
- const struct pci_device_id *id)
+static int __devinit smbus_sch_probe(struct platform_device *dev)
{
+ struct resource *res;
int retval;
- unsigned int smba;
- pci_read_config_dword(dev, SMBBA_SCH, &smba);
- if (!(smba & (1 << 31))) {
- dev_err(&dev->dev, "SMBus I/O space disabled!\n");
- return -ENODEV;
- }
+ res = platform_get_resource(dev, IORESOURCE_IO, 0);
+ if (!res)
+ return -EBUSY;
- sch_smba = (unsigned short)smba;
- if (sch_smba == 0) {
- dev_err(&dev->dev, "SMBus base address uninitialized!\n");
- return -ENODEV;
- }
- if (acpi_check_region(sch_smba, SMBIOSIZE, sch_driver.name))
- return -ENODEV;
- if (!request_region(sch_smba, SMBIOSIZE, sch_driver.name)) {
+ if (!request_region(res->start, resource_size(res), dev->name)) {
dev_err(&dev->dev, "SMBus region 0x%x already in use!\n",
sch_smba);
return -EBUSY;
}
+
+ sch_smba = res->start;
+
dev_dbg(&dev->dev, "SMBA = 0x%X\n", sch_smba);
/* set up the sysfs linkage to our parent device */
@@ -298,37 +277,43 @@ static int __devinit sch_probe(struct pci_dev *dev,
retval = i2c_add_adapter(&sch_adapter);
if (retval) {
dev_err(&dev->dev, "Couldn't register adapter!\n");
- release_region(sch_smba, SMBIOSIZE);
+ release_region(res->start, resource_size(res));
sch_smba = 0;
}
return retval;
}
-static void __devexit sch_remove(struct pci_dev *dev)
+static int __devexit smbus_sch_remove(struct platform_device *pdev)
{
+ struct resource *res;
if (sch_smba) {
i2c_del_adapter(&sch_adapter);
- release_region(sch_smba, SMBIOSIZE);
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(res->start, resource_size(res));
sch_smba = 0;
}
+
+ return 0;
}
-static struct pci_driver sch_driver = {
- .name = "isch_smbus",
- .id_table = sch_ids,
- .probe = sch_probe,
- .remove = __devexit_p(sch_remove),
+static struct platform_driver smbus_sch_driver = {
+ .driver = {
+ .name = "isch_smbus",
+ .owner = THIS_MODULE,
+ },
+ .probe = smbus_sch_probe,
+ .remove = __devexit_p(smbus_sch_remove),
};
static int __init i2c_sch_init(void)
{
- return pci_register_driver(&sch_driver);
+ return platform_driver_register(&smbus_sch_driver);
}
static void __exit i2c_sch_exit(void)
{
- pci_unregister_driver(&sch_driver);
+ platform_driver_unregister(&smbus_sch_driver);
}
MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>");
@@ -337,3 +322,4 @@ MODULE_LICENSE("GPL");
module_init(i2c_sch_init);
module_exit(i2c_sch_exit);
+MODULE_ALIAS("platform:isch_smbus");
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index f627001108b8..78a15af32942 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -31,6 +31,9 @@
#define DRV_NAME "mpc-i2c"
+#define MPC_I2C_CLOCK_LEGACY 0
+#define MPC_I2C_CLOCK_PRESERVE (~0U)
+
#define MPC_I2C_FDR 0x04
#define MPC_I2C_CR 0x08
#define MPC_I2C_SR 0x0c
@@ -66,10 +69,9 @@ struct mpc_i2c_divider {
u16 fdr; /* including dfsrr */
};
-struct mpc_i2c_match_data {
- void (*setclock)(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler);
+struct mpc_i2c_data {
+ void (*setup)(struct device_node *node, struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler);
u32 prescaler;
};
@@ -164,8 +166,8 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
return 0;
}
-#ifdef CONFIG_PPC_MPC52xx
-static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = {
+#if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC512x)
+static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] __devinitconst = {
{20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23},
{28, 0x24}, {30, 0x01}, {32, 0x25}, {34, 0x02},
{36, 0x26}, {40, 0x27}, {44, 0x04}, {48, 0x28},
@@ -186,14 +188,15 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = {
{10240, 0x9d}, {12288, 0x9e}, {15360, 0x9f}
};
-int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int prescaler)
+static int __devinit mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
+ int prescaler)
{
const struct mpc_i2c_divider *div = NULL;
unsigned int pvr = mfspr(SPRN_PVR);
u32 divider;
int i;
- if (!clock)
+ if (clock == MPC_I2C_CLOCK_LEGACY)
return -EINVAL;
/* Determine divider value */
@@ -215,12 +218,18 @@ int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int prescaler)
return div ? (int)div->fdr : -EINVAL;
}
-static void mpc_i2c_setclock_52xx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
int ret, fdr;
+ if (clock == MPC_I2C_CLOCK_PRESERVE) {
+ dev_dbg(i2c->dev, "using fdr %d\n",
+ readb(i2c->base + MPC_I2C_FDR));
+ return;
+ }
+
ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler);
fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */
@@ -229,16 +238,52 @@ static void mpc_i2c_setclock_52xx(struct device_node *node,
if (ret >= 0)
dev_info(i2c->dev, "clock %d Hz (fdr=%d)\n", clock, fdr);
}
-#else /* !CONFIG_PPC_MPC52xx */
-static void mpc_i2c_setclock_52xx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+#else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */
+static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
+{
+}
+#endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */
+
+#ifdef CONFIG_PPC_MPC512x
+static void __devinit mpc_i2c_setup_512x(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
+{
+ struct device_node *node_ctrl;
+ void __iomem *ctrl;
+ const u32 *pval;
+ u32 idx;
+
+ /* Enable I2C interrupts for mpc5121 */
+ node_ctrl = of_find_compatible_node(NULL, NULL,
+ "fsl,mpc5121-i2c-ctrl");
+ if (node_ctrl) {
+ ctrl = of_iomap(node_ctrl, 0);
+ if (ctrl) {
+ /* Interrupt enable bits for i2c-0/1/2: bit 24/26/28 */
+ pval = of_get_property(node, "reg", NULL);
+ idx = (*pval & 0xff) / 0x20;
+ setbits32(ctrl, 1 << (24 + idx * 2));
+ iounmap(ctrl);
+ }
+ of_node_put(node_ctrl);
+ }
+
+ /* The clock setup for the 52xx works also fine for the 512x */
+ mpc_i2c_setup_52xx(node, i2c, clock, prescaler);
+}
+#else /* CONFIG_PPC_MPC512x */
+static void __devinit mpc_i2c_setup_512x(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
}
-#endif /* CONFIG_PPC_MPC52xx*/
+#endif /* CONFIG_PPC_MPC512x */
#ifdef CONFIG_FSL_SOC
-static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = {
+static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] __devinitconst = {
{160, 0x0120}, {192, 0x0121}, {224, 0x0122}, {256, 0x0123},
{288, 0x0100}, {320, 0x0101}, {352, 0x0601}, {384, 0x0102},
{416, 0x0602}, {448, 0x0126}, {480, 0x0103}, {512, 0x0127},
@@ -258,7 +303,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = {
{49152, 0x011e}, {61440, 0x011f}
};
-u32 mpc_i2c_get_sec_cfg_8xxx(void)
+static u32 __devinit mpc_i2c_get_sec_cfg_8xxx(void)
{
struct device_node *node = NULL;
u32 __iomem *reg;
@@ -287,13 +332,14 @@ u32 mpc_i2c_get_sec_cfg_8xxx(void)
return val;
}
-int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, u32 prescaler)
+static int __devinit mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
+ u32 prescaler)
{
const struct mpc_i2c_divider *div = NULL;
u32 divider;
int i;
- if (!clock)
+ if (clock == MPC_I2C_CLOCK_LEGACY)
return -EINVAL;
/* Determine proper divider value */
@@ -320,12 +366,19 @@ int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, u32 prescaler)
return div ? (int)div->fdr : -EINVAL;
}
-static void mpc_i2c_setclock_8xxx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
int ret, fdr;
+ if (clock == MPC_I2C_CLOCK_PRESERVE) {
+ dev_dbg(i2c->dev, "using dfsrr %d, fdr %d\n",
+ readb(i2c->base + MPC_I2C_DFSRR),
+ readb(i2c->base + MPC_I2C_FDR));
+ return;
+ }
+
ret = mpc_i2c_get_fdr_8xxx(node, clock, prescaler);
fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */
@@ -338,9 +391,9 @@ static void mpc_i2c_setclock_8xxx(struct device_node *node,
}
#else /* !CONFIG_FSL_SOC */
-static void mpc_i2c_setclock_8xxx(struct device_node *node,
- struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock, u32 prescaler)
{
}
#endif /* CONFIG_FSL_SOC */
@@ -494,7 +547,7 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
{
struct mpc_i2c *i2c;
const u32 *prop;
- u32 clock = 0;
+ u32 clock = MPC_I2C_CLOCK_LEGACY;
int result = 0;
int plen;
@@ -523,21 +576,21 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
}
}
- if (!of_get_property(op->node, "fsl,preserve-clocking", NULL)) {
+ if (of_get_property(op->node, "fsl,preserve-clocking", NULL)) {
+ clock = MPC_I2C_CLOCK_PRESERVE;
+ } else {
prop = of_get_property(op->node, "clock-frequency", &plen);
if (prop && plen == sizeof(u32))
clock = *prop;
+ }
- if (match->data) {
- struct mpc_i2c_match_data *data =
- (struct mpc_i2c_match_data *)match->data;
- data->setclock(op->node, i2c, clock, data->prescaler);
- } else {
- /* Backwards compatibility */
- if (of_get_property(op->node, "dfsrr", NULL))
- mpc_i2c_setclock_8xxx(op->node, i2c,
- clock, 0);
- }
+ if (match->data) {
+ struct mpc_i2c_data *data = match->data;
+ data->setup(op->node, i2c, clock, data->prescaler);
+ } else {
+ /* Backwards compatibility */
+ if (of_get_property(op->node, "dfsrr", NULL))
+ mpc_i2c_setup_8xxx(op->node, i2c, clock, 0);
}
dev_set_drvdata(&op->dev, i2c);
@@ -582,47 +635,42 @@ static int __devexit fsl_i2c_remove(struct of_device *op)
return 0;
};
+static struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
+ .setup = mpc_i2c_setup_512x,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
+ .setup = mpc_i2c_setup_52xx,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
+ .setup = mpc_i2c_setup_8xxx,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
+ .setup = mpc_i2c_setup_8xxx,
+ .prescaler = 2,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
+ .setup = mpc_i2c_setup_8xxx,
+ .prescaler = 3,
+};
+
static const struct of_device_id mpc_i2c_of_match[] = {
- {.compatible = "mpc5200-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_52xx,
- },
- },
- {.compatible = "fsl,mpc5200b-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_52xx,
- },
- },
- {.compatible = "fsl,mpc5200-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_52xx,
- },
- },
- {.compatible = "fsl,mpc8313-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_8xxx,
- },
- },
- {.compatible = "fsl,mpc8543-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_8xxx,
- .prescaler = 2,
- },
- },
- {.compatible = "fsl,mpc8544-i2c",
- .data = &(struct mpc_i2c_match_data) {
- .setclock = mpc_i2c_setclock_8xxx,
- .prescaler = 3,
- },
+ {.compatible = "mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
+ {.compatible = "fsl,mpc5200b-i2c", .data = &mpc_i2c_data_52xx, },
+ {.compatible = "fsl,mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
+ {.compatible = "fsl,mpc5121-i2c", .data = &mpc_i2c_data_512x, },
+ {.compatible = "fsl,mpc8313-i2c", .data = &mpc_i2c_data_8313, },
+ {.compatible = "fsl,mpc8543-i2c", .data = &mpc_i2c_data_8543, },
+ {.compatible = "fsl,mpc8544-i2c", .data = &mpc_i2c_data_8544, },
/* Backward compatibility */
- },
{.compatible = "fsl-i2c", },
{},
};
-
MODULE_DEVICE_TABLE(of, mpc_i2c_of_match);
-
/* Structure for a device driver */
static struct of_platform_driver mpc_i2c_driver = {
.match_table = mpc_i2c_of_match,
@@ -655,5 +703,5 @@ module_exit(fsl_i2c_exit);
MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and "
- "MPC824x/85xx/52xx processors");
+ "MPC824x/83xx/85xx/86xx/512x/52xx processors");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index ec11d1c4e77b..4a700587ef18 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -308,7 +308,7 @@ static struct i2c_algorithm smbus_algorithm = {
};
-static struct pci_device_id nforce2_ids[] = {
+static const struct pci_device_id nforce2_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
new file mode 100644
index 000000000000..a15f731fa451
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -0,0 +1,959 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson
+ * Copyright (C) 2009 STMicroelectronics
+ *
+ * I2C master mode controller driver, used in Nomadik 8815
+ * and Ux500 platforms.
+ *
+ * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
+ * Author: Sachin Verma <sachin.verma@st.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.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/i2c.h>
+
+#define DRIVER_NAME "nmk-i2c"
+
+/* I2C Controller register offsets */
+#define I2C_CR (0x000)
+#define I2C_SCR (0x004)
+#define I2C_HSMCR (0x008)
+#define I2C_MCR (0x00C)
+#define I2C_TFR (0x010)
+#define I2C_SR (0x014)
+#define I2C_RFR (0x018)
+#define I2C_TFTR (0x01C)
+#define I2C_RFTR (0x020)
+#define I2C_DMAR (0x024)
+#define I2C_BRCR (0x028)
+#define I2C_IMSCR (0x02C)
+#define I2C_RISR (0x030)
+#define I2C_MISR (0x034)
+#define I2C_ICR (0x038)
+
+/* Control registers */
+#define I2C_CR_PE (0x1 << 0) /* Peripheral Enable */
+#define I2C_CR_OM (0x3 << 1) /* Operating mode */
+#define I2C_CR_SAM (0x1 << 3) /* Slave addressing mode */
+#define I2C_CR_SM (0x3 << 4) /* Speed mode */
+#define I2C_CR_SGCM (0x1 << 6) /* Slave general call mode */
+#define I2C_CR_FTX (0x1 << 7) /* Flush Transmit */
+#define I2C_CR_FRX (0x1 << 8) /* Flush Receive */
+#define I2C_CR_DMA_TX_EN (0x1 << 9) /* DMA Tx enable */
+#define I2C_CR_DMA_RX_EN (0x1 << 10) /* DMA Rx Enable */
+#define I2C_CR_DMA_SLE (0x1 << 11) /* DMA sync. logic enable */
+#define I2C_CR_LM (0x1 << 12) /* Loopback mode */
+#define I2C_CR_FON (0x3 << 13) /* Filtering on */
+#define I2C_CR_FS (0x3 << 15) /* Force stop enable */
+
+/* Master controller (MCR) register */
+#define I2C_MCR_OP (0x1 << 0) /* Operation */
+#define I2C_MCR_A7 (0x7f << 1) /* 7-bit address */
+#define I2C_MCR_EA10 (0x7 << 8) /* 10-bit Extended address */
+#define I2C_MCR_SB (0x1 << 11) /* Extended address */
+#define I2C_MCR_AM (0x3 << 12) /* Address type */
+#define I2C_MCR_STOP (0x1 << 14) /* Stop condition */
+#define I2C_MCR_LENGTH (0x7ff << 15) /* Transaction length */
+
+/* Status register (SR) */
+#define I2C_SR_OP (0x3 << 0) /* Operation */
+#define I2C_SR_STATUS (0x3 << 2) /* controller status */
+#define I2C_SR_CAUSE (0x7 << 4) /* Abort cause */
+#define I2C_SR_TYPE (0x3 << 7) /* Receive type */
+#define I2C_SR_LENGTH (0x7ff << 9) /* Transfer length */
+
+/* Interrupt mask set/clear (IMSCR) bits */
+#define I2C_IT_TXFE (0x1 << 0)
+#define I2C_IT_TXFNE (0x1 << 1)
+#define I2C_IT_TXFF (0x1 << 2)
+#define I2C_IT_TXFOVR (0x1 << 3)
+#define I2C_IT_RXFE (0x1 << 4)
+#define I2C_IT_RXFNF (0x1 << 5)
+#define I2C_IT_RXFF (0x1 << 6)
+#define I2C_IT_RFSR (0x1 << 16)
+#define I2C_IT_RFSE (0x1 << 17)
+#define I2C_IT_WTSR (0x1 << 18)
+#define I2C_IT_MTD (0x1 << 19)
+#define I2C_IT_STD (0x1 << 20)
+#define I2C_IT_MAL (0x1 << 24)
+#define I2C_IT_BERR (0x1 << 25)
+#define I2C_IT_MTDWS (0x1 << 28)
+
+#define GEN_MASK(val, mask, sb) (((val) << (sb)) & (mask))
+
+/* some bits in ICR are reserved */
+#define I2C_CLEAR_ALL_INTS 0x131f007f
+
+/* first three msb bits are reserved */
+#define IRQ_MASK(mask) (mask & 0x1fffffff)
+
+/* maximum threshold value */
+#define MAX_I2C_FIFO_THRESHOLD 15
+
+enum i2c_status {
+ I2C_NOP,
+ I2C_ON_GOING,
+ I2C_OK,
+ I2C_ABORT
+};
+
+/* operation */
+enum i2c_operation {
+ I2C_NO_OPERATION = 0xff,
+ I2C_WRITE = 0x00,
+ I2C_READ = 0x01
+};
+
+/* controller response timeout in ms */
+#define I2C_TIMEOUT_MS 500
+
+/**
+ * struct i2c_nmk_client - client specific data
+ * @slave_adr: 7-bit slave address
+ * @count: no. bytes to be transfered
+ * @buffer: client data buffer
+ * @xfer_bytes: bytes transfered till now
+ * @operation: current I2C operation
+ */
+struct i2c_nmk_client {
+ unsigned short slave_adr;
+ unsigned long count;
+ unsigned char *buffer;
+ unsigned long xfer_bytes;
+ enum i2c_operation operation;
+};
+
+/**
+ * struct nmk_i2c_dev - private data structure of the controller
+ * @pdev: parent platform device
+ * @adap: corresponding I2C adapter
+ * @irq: interrupt line for the controller
+ * @virtbase: virtual io memory area
+ * @clk: hardware i2c block clock
+ * @cfg: machine provided controller configuration
+ * @cli: holder of client specific data
+ * @stop: stop condition
+ * @xfer_complete: acknowledge completion for a I2C message
+ * @result: controller propogated result
+ */
+struct nmk_i2c_dev {
+ struct platform_device *pdev;
+ struct i2c_adapter adap;
+ int irq;
+ void __iomem *virtbase;
+ struct clk *clk;
+ struct nmk_i2c_controller cfg;
+ struct i2c_nmk_client cli;
+ int stop;
+ struct completion xfer_complete;
+ int result;
+};
+
+/* controller's abort causes */
+static const char *abort_causes[] = {
+ "no ack received after address transmission",
+ "no ack received during data phase",
+ "ack received after xmission of master code",
+ "master lost arbitration",
+ "slave restarts",
+ "slave reset",
+ "overflow, maxsize is 2047 bytes",
+};
+
+static inline void i2c_set_bit(void __iomem *reg, u32 mask)
+{
+ writel(readl(reg) | mask, reg);
+}
+
+static inline void i2c_clr_bit(void __iomem *reg, u32 mask)
+{
+ writel(readl(reg) & ~mask, reg);
+}
+
+/**
+ * flush_i2c_fifo() - This function flushes the I2C FIFO
+ * @dev: private data of I2C Driver
+ *
+ * This function flushes the I2C Tx and Rx FIFOs. It returns
+ * 0 on successful flushing of FIFO
+ */
+static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
+{
+#define LOOP_ATTEMPTS 10
+ int i;
+ unsigned long timeout;
+
+ /*
+ * flush the transmit and receive FIFO. The flushing
+ * operation takes several cycles before to be completed.
+ * On the completion, the I2C internal logic clears these
+ * bits, until then no one must access Tx, Rx FIFO and
+ * should poll on these bits waiting for the completion.
+ */
+ writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR);
+
+ for (i = 0; i < LOOP_ATTEMPTS; i++) {
+ timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT_MS);
+
+ while (!time_after(jiffies, timeout)) {
+ if ((readl(dev->virtbase + I2C_CR) &
+ (I2C_CR_FTX | I2C_CR_FRX)) == 0)
+ return 0;
+ }
+ }
+
+ dev_err(&dev->pdev->dev, "flushing operation timed out "
+ "giving up after %d attempts", LOOP_ATTEMPTS);
+
+ return -ETIMEDOUT;
+}
+
+/**
+ * disable_all_interrupts() - Disable all interrupts of this I2c Bus
+ * @dev: private data of I2C Driver
+ */
+static void disable_all_interrupts(struct nmk_i2c_dev *dev)
+{
+ u32 mask = IRQ_MASK(0);
+ writel(mask, dev->virtbase + I2C_IMSCR);
+}
+
+/**
+ * clear_all_interrupts() - Clear all interrupts of I2C Controller
+ * @dev: private data of I2C Driver
+ */
+static void clear_all_interrupts(struct nmk_i2c_dev *dev)
+{
+ u32 mask;
+ mask = IRQ_MASK(I2C_CLEAR_ALL_INTS);
+ writel(mask, dev->virtbase + I2C_ICR);
+}
+
+/**
+ * init_hw() - initialize the I2C hardware
+ * @dev: private data of I2C Driver
+ */
+static int init_hw(struct nmk_i2c_dev *dev)
+{
+ int stat;
+
+ stat = flush_i2c_fifo(dev);
+ if (stat)
+ return stat;
+
+ /* disable the controller */
+ i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
+
+ disable_all_interrupts(dev);
+
+ clear_all_interrupts(dev);
+
+ dev->cli.operation = I2C_NO_OPERATION;
+
+ return 0;
+}
+
+/* enable peripheral, master mode operation */
+#define DEFAULT_I2C_REG_CR ((1 << 1) | I2C_CR_PE)
+
+/**
+ * load_i2c_mcr_reg() - load the MCR register
+ * @dev: private data of controller
+ */
+static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev)
+{
+ u32 mcr = 0;
+
+ /* 7-bit address transaction */
+ mcr |= GEN_MASK(1, I2C_MCR_AM, 12);
+ mcr |= GEN_MASK(dev->cli.slave_adr, I2C_MCR_A7, 1);
+
+ /* start byte procedure not applied */
+ mcr |= GEN_MASK(0, I2C_MCR_SB, 11);
+
+ /* check the operation, master read/write? */
+ if (dev->cli.operation == I2C_WRITE)
+ mcr |= GEN_MASK(I2C_WRITE, I2C_MCR_OP, 0);
+ else
+ mcr |= GEN_MASK(I2C_READ, I2C_MCR_OP, 0);
+
+ /* stop or repeated start? */
+ if (dev->stop)
+ mcr |= GEN_MASK(1, I2C_MCR_STOP, 14);
+ else
+ mcr &= ~(GEN_MASK(1, I2C_MCR_STOP, 14));
+
+ mcr |= GEN_MASK(dev->cli.count, I2C_MCR_LENGTH, 15);
+
+ return mcr;
+}
+
+/**
+ * setup_i2c_controller() - setup the controller
+ * @dev: private data of controller
+ */
+static void setup_i2c_controller(struct nmk_i2c_dev *dev)
+{
+ u32 brcr1, brcr2;
+ u32 i2c_clk, div;
+
+ writel(0x0, dev->virtbase + I2C_CR);
+ writel(0x0, dev->virtbase + I2C_HSMCR);
+ writel(0x0, dev->virtbase + I2C_TFTR);
+ writel(0x0, dev->virtbase + I2C_RFTR);
+ writel(0x0, dev->virtbase + I2C_DMAR);
+
+ /*
+ * set the slsu:
+ *
+ * slsu defines the data setup time after SCL clock
+ * stretching in terms of i2c clk cycles. The
+ * needed setup time for the three modes are 250ns,
+ * 100ns, 10ns repectively thus leading to the values
+ * of 14, 6, 2 for a 48 MHz i2c clk.
+ */
+ writel(dev->cfg.slsu << 16, dev->virtbase + I2C_SCR);
+
+ i2c_clk = clk_get_rate(dev->clk);
+
+ /* fallback to std. mode if machine has not provided it */
+ if (dev->cfg.clk_freq == 0)
+ dev->cfg.clk_freq = 100000;
+
+ /*
+ * The spec says, in case of std. mode the divider is
+ * 2 whereas it is 3 for fast and fastplus mode of
+ * operation. TODO - high speed support.
+ */
+ div = (dev->cfg.clk_freq > 100000) ? 3 : 2;
+
+ /*
+ * generate the mask for baud rate counters. The controller
+ * has two baud rate counters. One is used for High speed
+ * operation, and the other is for std, fast mode, fast mode
+ * plus operation. Currently we do not supprt high speed mode
+ * so set brcr1 to 0.
+ */
+ brcr1 = 0 << 16;
+ brcr2 = (i2c_clk/(dev->cfg.clk_freq * div)) & 0xffff;
+
+ /* set the baud rate counter register */
+ writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
+
+ /*
+ * set the speed mode. Currently we support
+ * only standard and fast mode of operation
+ * TODO - support for fast mode plus (upto 1Mb/s)
+ * and high speed (up to 3.4 Mb/s)
+ */
+ if (dev->cfg.sm > I2C_FREQ_MODE_FAST) {
+ dev_err(&dev->pdev->dev, "do not support this mode "
+ "defaulting to std. mode\n");
+ brcr2 = i2c_clk/(100000 * 2) & 0xffff;
+ writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
+ writel(I2C_FREQ_MODE_STANDARD << 4,
+ dev->virtbase + I2C_CR);
+ }
+ writel(dev->cfg.sm << 4, dev->virtbase + I2C_CR);
+
+ /* set the Tx and Rx FIFO threshold */
+ writel(dev->cfg.tft, dev->virtbase + I2C_TFTR);
+ writel(dev->cfg.rft, dev->virtbase + I2C_RFTR);
+}
+
+/**
+ * read_i2c() - Read from I2C client device
+ * @dev: private data of I2C Driver
+ *
+ * This function reads from i2c client device when controller is in
+ * master mode. There is a completion timeout. If there is no transfer
+ * before timeout error is returned.
+ */
+static int read_i2c(struct nmk_i2c_dev *dev)
+{
+ u32 status = 0;
+ u32 mcr;
+ u32 irq_mask = 0;
+ int timeout;
+
+ mcr = load_i2c_mcr_reg(dev);
+ writel(mcr, dev->virtbase + I2C_MCR);
+
+ /* load the current CR value */
+ writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR,
+ dev->virtbase + I2C_CR);
+
+ /* enable the controller */
+ i2c_set_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+
+ init_completion(&dev->xfer_complete);
+
+ /* enable interrupts by setting the mask */
+ irq_mask = (I2C_IT_RXFNF | I2C_IT_RXFF |
+ I2C_IT_MAL | I2C_IT_BERR);
+
+ if (dev->stop)
+ irq_mask |= I2C_IT_MTD;
+ else
+ irq_mask |= I2C_IT_MTDWS;
+
+ irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask);
+
+ writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
+ dev->virtbase + I2C_IMSCR);
+
+ timeout = wait_for_completion_interruptible_timeout(
+ &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+
+ if (timeout < 0) {
+ dev_err(&dev->pdev->dev,
+ "wait_for_completion_interruptible_timeout"
+ "returned %d waiting for event\n", timeout);
+ status = timeout;
+ }
+
+ if (timeout == 0) {
+ /* controler has timedout, re-init the h/w */
+ dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
+ (void) init_hw(dev);
+ status = -ETIMEDOUT;
+ }
+
+ return status;
+}
+
+/**
+ * write_i2c() - Write data to I2C client.
+ * @dev: private data of I2C Driver
+ *
+ * This function writes data to I2C client
+ */
+static int write_i2c(struct nmk_i2c_dev *dev)
+{
+ u32 status = 0;
+ u32 mcr;
+ u32 irq_mask = 0;
+ int timeout;
+
+ mcr = load_i2c_mcr_reg(dev);
+
+ writel(mcr, dev->virtbase + I2C_MCR);
+
+ /* load the current CR value */
+ writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR,
+ dev->virtbase + I2C_CR);
+
+ /* enable the controller */
+ i2c_set_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
+
+ init_completion(&dev->xfer_complete);
+
+ /* enable interrupts by settings the masks */
+ irq_mask = (I2C_IT_TXFNE | I2C_IT_TXFOVR |
+ I2C_IT_MAL | I2C_IT_BERR);
+
+ /*
+ * check if we want to transfer a single or multiple bytes, if so
+ * set the MTDWS bit (Master Transaction Done Without Stop)
+ * to start repeated start operation
+ */
+ if (dev->stop)
+ irq_mask |= I2C_IT_MTD;
+ else
+ irq_mask |= I2C_IT_MTDWS;
+
+ irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask);
+
+ writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
+ dev->virtbase + I2C_IMSCR);
+
+ timeout = wait_for_completion_interruptible_timeout(
+ &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+
+ if (timeout < 0) {
+ dev_err(&dev->pdev->dev,
+ "wait_for_completion_interruptible_timeout"
+ "returned %d waiting for event\n", timeout);
+ status = timeout;
+ }
+
+ if (timeout == 0) {
+ /* controler has timedout, re-init the h/w */
+ dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
+ (void) init_hw(dev);
+ status = -ETIMEDOUT;
+ }
+
+ return status;
+}
+
+/**
+ * nmk_i2c_xfer() - I2C transfer function used by kernel framework
+ * @i2c_adap - Adapter pointer to the controller
+ * @msgs[] - Pointer to data to be written.
+ * @num_msgs - Number of messages to be executed
+ *
+ * This is the function called by the generic kernel i2c_transfer()
+ * or i2c_smbus...() API calls. Note that this code is protected by the
+ * semaphore set in the kernel i2c_transfer() function.
+ *
+ * NOTE:
+ * READ TRANSFER : We impose a restriction of the first message to be the
+ * index message for any read transaction.
+ * - a no index is coded as '0',
+ * - 2byte big endian index is coded as '3'
+ * !!! msg[0].buf holds the actual index.
+ * This is compatible with generic messages of smbus emulator
+ * that send a one byte index.
+ * eg. a I2C transation to read 2 bytes from index 0
+ * idx = 0;
+ * msg[0].addr = client->addr;
+ * msg[0].flags = 0x0;
+ * msg[0].len = 1;
+ * msg[0].buf = &idx;
+ *
+ * msg[1].addr = client->addr;
+ * msg[1].flags = I2C_M_RD;
+ * msg[1].len = 2;
+ * msg[1].buf = rd_buff
+ * i2c_transfer(adap, msg, 2);
+ *
+ * WRITE TRANSFER : The I2C standard interface interprets all data as payload.
+ * If you want to emulate an SMBUS write transaction put the
+ * index as first byte(or first and second) in the payload.
+ * eg. a I2C transation to write 2 bytes from index 1
+ * wr_buff[0] = 0x1;
+ * wr_buff[1] = 0x23;
+ * wr_buff[2] = 0x46;
+ * msg[0].flags = 0x0;
+ * msg[0].len = 3;
+ * msg[0].buf = wr_buff;
+ * i2c_transfer(adap, msg, 1);
+ *
+ * To read or write a block of data (multiple bytes) using SMBUS emulation
+ * please use the i2c_smbus_read_i2c_block_data()
+ * or i2c_smbus_write_i2c_block_data() API
+ */
+static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num_msgs)
+{
+ int status;
+ int i;
+ u32 cause;
+ struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
+
+ status = init_hw(dev);
+ if (status)
+ return status;
+
+ /* setup the i2c controller */
+ setup_i2c_controller(dev);
+
+ for (i = 0; i < num_msgs; i++) {
+ if (unlikely(msgs[i].flags & I2C_M_TEN)) {
+ dev_err(&dev->pdev->dev, "10 bit addressing"
+ "not supported\n");
+ return -EINVAL;
+ }
+ dev->cli.slave_adr = msgs[i].addr;
+ dev->cli.buffer = msgs[i].buf;
+ dev->cli.count = msgs[i].len;
+ dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
+ dev->result = 0;
+
+ if (msgs[i].flags & I2C_M_RD) {
+ /* it is a read operation */
+ dev->cli.operation = I2C_READ;
+ status = read_i2c(dev);
+ } else {
+ /* write operation */
+ dev->cli.operation = I2C_WRITE;
+ status = write_i2c(dev);
+ }
+ if (status || (dev->result)) {
+ /* get the abort cause */
+ cause = (readl(dev->virtbase + I2C_SR) >> 4) & 0x7;
+ dev_err(&dev->pdev->dev, "error during I2C"
+ "message xfer: %d\n", cause);
+ dev_err(&dev->pdev->dev, "%s\n",
+ cause >= ARRAY_SIZE(abort_causes)
+ ? "unknown reason" : abort_causes[cause]);
+ return status;
+ }
+ mdelay(1);
+ }
+ /* return the no. messages processed */
+ if (status)
+ return status;
+ else
+ return num_msgs;
+}
+
+/**
+ * disable_interrupts() - disable the interrupts
+ * @dev: private data of controller
+ */
+static int disable_interrupts(struct nmk_i2c_dev *dev, u32 irq)
+{
+ irq = IRQ_MASK(irq);
+ writel(readl(dev->virtbase + I2C_IMSCR) & ~(I2C_CLEAR_ALL_INTS & irq),
+ dev->virtbase + I2C_IMSCR);
+ return 0;
+}
+
+/**
+ * i2c_irq_handler() - interrupt routine
+ * @irq: interrupt number
+ * @arg: data passed to the handler
+ *
+ * This is the interrupt handler for the i2c driver. Currently
+ * it handles the major interrupts like Rx & Tx FIFO management
+ * interrupts, master transaction interrupts, arbitration and
+ * bus error interrupts. The rest of the interrupts are treated as
+ * unhandled.
+ */
+static irqreturn_t i2c_irq_handler(int irq, void *arg)
+{
+ struct nmk_i2c_dev *dev = arg;
+ u32 tft, rft;
+ u32 count;
+ u32 misr;
+ u32 src = 0;
+
+ /* load Tx FIFO and Rx FIFO threshold values */
+ tft = readl(dev->virtbase + I2C_TFTR);
+ rft = readl(dev->virtbase + I2C_RFTR);
+
+ /* read interrupt status register */
+ misr = readl(dev->virtbase + I2C_MISR);
+
+ src = __ffs(misr);
+ switch ((1 << src)) {
+
+ /* Transmit FIFO nearly empty interrupt */
+ case I2C_IT_TXFNE:
+ {
+ if (dev->cli.operation == I2C_READ) {
+ /*
+ * in read operation why do we care for writing?
+ * so disable the Transmit FIFO interrupt
+ */
+ disable_interrupts(dev, I2C_IT_TXFNE);
+ } else {
+ for (count = (MAX_I2C_FIFO_THRESHOLD - tft - 2);
+ (count > 0) &&
+ (dev->cli.count != 0);
+ count--) {
+ /* write to the Tx FIFO */
+ writeb(*dev->cli.buffer,
+ dev->virtbase + I2C_TFR);
+ dev->cli.buffer++;
+ dev->cli.count--;
+ dev->cli.xfer_bytes++;
+ }
+ /*
+ * if done, close the transfer by disabling the
+ * corresponding TXFNE interrupt
+ */
+ if (dev->cli.count == 0)
+ disable_interrupts(dev, I2C_IT_TXFNE);
+ }
+ }
+ break;
+
+ /*
+ * Rx FIFO nearly full interrupt.
+ * This is set when the numer of entries in Rx FIFO is
+ * greater or equal than the threshold value programmed
+ * in RFT
+ */
+ case I2C_IT_RXFNF:
+ for (count = rft; count > 0; count--) {
+ /* Read the Rx FIFO */
+ *dev->cli.buffer = readb(dev->virtbase + I2C_RFR);
+ dev->cli.buffer++;
+ }
+ dev->cli.count -= rft;
+ dev->cli.xfer_bytes += rft;
+ break;
+
+ /* Rx FIFO full */
+ case I2C_IT_RXFF:
+ for (count = MAX_I2C_FIFO_THRESHOLD; count > 0; count--) {
+ *dev->cli.buffer = readb(dev->virtbase + I2C_RFR);
+ dev->cli.buffer++;
+ }
+ dev->cli.count -= MAX_I2C_FIFO_THRESHOLD;
+ dev->cli.xfer_bytes += MAX_I2C_FIFO_THRESHOLD;
+ break;
+
+ /* Master Transaction Done with/without stop */
+ case I2C_IT_MTD:
+ case I2C_IT_MTDWS:
+ if (dev->cli.operation == I2C_READ) {
+ while (!readl(dev->virtbase + I2C_RISR) & I2C_IT_RXFE) {
+ if (dev->cli.count == 0)
+ break;
+ *dev->cli.buffer =
+ readb(dev->virtbase + I2C_RFR);
+ dev->cli.buffer++;
+ dev->cli.count--;
+ dev->cli.xfer_bytes++;
+ }
+ }
+
+ i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTD);
+ i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTDWS);
+
+ disable_interrupts(dev,
+ (I2C_IT_TXFNE | I2C_IT_TXFE | I2C_IT_TXFF
+ | I2C_IT_TXFOVR | I2C_IT_RXFNF
+ | I2C_IT_RXFF | I2C_IT_RXFE));
+
+ if (dev->cli.count) {
+ dev->result = -1;
+ dev_err(&dev->pdev->dev, "%lu bytes still remain to be"
+ "xfered\n", dev->cli.count);
+ (void) init_hw(dev);
+ }
+ complete(&dev->xfer_complete);
+
+ break;
+
+ /* Master Arbitration lost interrupt */
+ case I2C_IT_MAL:
+ dev->result = -1;
+ (void) init_hw(dev);
+
+ i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL);
+ complete(&dev->xfer_complete);
+
+ break;
+
+ /*
+ * Bus Error interrupt.
+ * This happens when an unexpected start/stop condition occurs
+ * during the transaction.
+ */
+ case I2C_IT_BERR:
+ dev->result = -1;
+ /* get the status */
+ if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT)
+ (void) init_hw(dev);
+
+ i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_BERR);
+ complete(&dev->xfer_complete);
+
+ break;
+
+ /*
+ * Tx FIFO overrun interrupt.
+ * This is set when a write operation in Tx FIFO is performed and
+ * the Tx FIFO is full.
+ */
+ case I2C_IT_TXFOVR:
+ dev->result = -1;
+ (void) init_hw(dev);
+
+ dev_err(&dev->pdev->dev, "Tx Fifo Over run\n");
+ complete(&dev->xfer_complete);
+
+ break;
+
+ /* unhandled interrupts by this driver - TODO*/
+ case I2C_IT_TXFE:
+ case I2C_IT_TXFF:
+ case I2C_IT_RXFE:
+ case I2C_IT_RFSR:
+ case I2C_IT_RFSE:
+ case I2C_IT_WTSR:
+ case I2C_IT_STD:
+ dev_err(&dev->pdev->dev, "unhandled Interrupt\n");
+ break;
+ default:
+ dev_err(&dev->pdev->dev, "spurious Interrupt..\n");
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C
+ | I2C_FUNC_SMBUS_BYTE_DATA
+ | I2C_FUNC_SMBUS_WORD_DATA
+ | I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm nmk_i2c_algo = {
+ .master_xfer = nmk_i2c_xfer,
+ .functionality = nmk_i2c_functionality
+};
+
+static int __devinit nmk_i2c_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct resource *res;
+ struct nmk_i2c_controller *pdata =
+ pdev->dev.platform_data;
+ struct nmk_i2c_dev *dev;
+ struct i2c_adapter *adap;
+
+ dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ dev_err(&pdev->dev, "cannot allocate memory\n");
+ ret = -ENOMEM;
+ goto err_no_mem;
+ }
+
+ dev->pdev = pdev;
+ platform_set_drvdata(pdev, dev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENOENT;
+ goto err_no_resource;
+ }
+
+ if (request_mem_region(res->start, resource_size(res),
+ DRIVER_NAME "I/O region") == NULL) {
+ ret = -EBUSY;
+ goto err_no_region;
+ }
+
+ dev->virtbase = ioremap(res->start, resource_size(res));
+ if (!dev->virtbase) {
+ ret = -ENOMEM;
+ goto err_no_ioremap;
+ }
+
+ dev->irq = platform_get_irq(pdev, 0);
+ ret = request_irq(dev->irq, i2c_irq_handler, IRQF_DISABLED,
+ DRIVER_NAME, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot claim the irq %d\n", dev->irq);
+ goto err_irq;
+ }
+
+ dev->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ dev_err(&pdev->dev, "could not get i2c clock\n");
+ ret = PTR_ERR(dev->clk);
+ goto err_no_clk;
+ }
+
+ clk_enable(dev->clk);
+
+ adap = &dev->adap;
+ adap->dev.parent = &pdev->dev;
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adap->algo = &nmk_i2c_algo;
+
+ /* fetch the controller id */
+ adap->nr = pdev->id;
+
+ /* fetch the controller configuration from machine */
+ dev->cfg.clk_freq = pdata->clk_freq;
+ dev->cfg.slsu = pdata->slsu;
+ dev->cfg.tft = pdata->tft;
+ dev->cfg.rft = pdata->rft;
+ dev->cfg.sm = pdata->sm;
+
+ i2c_set_adapdata(adap, dev);
+
+ ret = init_hw(dev);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "error in initializing i2c hardware\n");
+ goto err_init_hw;
+ }
+
+ dev_dbg(&pdev->dev, "initialize I2C%d bus on virtual "
+ "base %p\n", pdev->id, dev->virtbase);
+
+ ret = i2c_add_numbered_adapter(adap);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add adapter\n");
+ goto err_add_adap;
+ }
+
+ return 0;
+
+ err_init_hw:
+ clk_disable(dev->clk);
+ err_add_adap:
+ clk_put(dev->clk);
+ err_no_clk:
+ free_irq(dev->irq, dev);
+ err_irq:
+ iounmap(dev->virtbase);
+ err_no_ioremap:
+ release_mem_region(res->start, resource_size(res));
+ err_no_region:
+ platform_set_drvdata(pdev, NULL);
+ err_no_resource:
+ kfree(dev);
+ err_no_mem:
+
+ return ret;
+}
+
+static int __devexit nmk_i2c_remove(struct platform_device *pdev)
+{
+ struct nmk_i2c_dev *dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&dev->adap);
+ flush_i2c_fifo(dev);
+ disable_all_interrupts(dev);
+ clear_all_interrupts(dev);
+ /* disable the controller */
+ i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+ free_irq(dev->irq, dev);
+ iounmap(dev->virtbase);
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ platform_set_drvdata(pdev, NULL);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct platform_driver nmk_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+ .probe = nmk_i2c_probe,
+ .remove = __devexit_p(nmk_i2c_remove),
+};
+
+static int __init nmk_i2c_init(void)
+{
+ return platform_driver_register(&nmk_i2c_driver);
+}
+
+static void __exit nmk_i2c_exit(void)
+{
+ platform_driver_unregister(&nmk_i2c_driver);
+}
+
+subsys_initcall(nmk_i2c_init);
+module_exit(nmk_i2c_exit);
+
+MODULE_AUTHOR("Sachin Verma, Srinidhi KASAGAR");
+MODULE_DESCRIPTION("Nomadik/Ux500 I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
new file mode 100644
index 000000000000..60375504fa49
--- /dev/null
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -0,0 +1,651 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick.ext@nsn.com
+ *
+ * Portions Copyright (C) 2010 Cavium Networks, Inc.
+ *
+ * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <asm/octeon/octeon.h>
+
+#define DRV_NAME "i2c-octeon"
+
+/* The previous out-of-tree version was implicitly version 1.0. */
+#define DRV_VERSION "2.0"
+
+/* register offsets */
+#define SW_TWSI 0x00
+#define TWSI_INT 0x10
+
+/* Controller command patterns */
+#define SW_TWSI_V 0x8000000000000000ull
+#define SW_TWSI_EOP_TWSI_DATA 0x0C00000100000000ull
+#define SW_TWSI_EOP_TWSI_CTL 0x0C00000200000000ull
+#define SW_TWSI_EOP_TWSI_CLKCTL 0x0C00000300000000ull
+#define SW_TWSI_EOP_TWSI_STAT 0x0C00000300000000ull
+#define SW_TWSI_EOP_TWSI_RST 0x0C00000700000000ull
+#define SW_TWSI_OP_TWSI_CLK 0x0800000000000000ull
+#define SW_TWSI_R 0x0100000000000000ull
+
+/* Controller command and status bits */
+#define TWSI_CTL_CE 0x80
+#define TWSI_CTL_ENAB 0x40
+#define TWSI_CTL_STA 0x20
+#define TWSI_CTL_STP 0x10
+#define TWSI_CTL_IFLG 0x08
+#define TWSI_CTL_AAK 0x04
+
+/* Some status values */
+#define STAT_START 0x08
+#define STAT_RSTART 0x10
+#define STAT_TXADDR_ACK 0x18
+#define STAT_TXDATA_ACK 0x28
+#define STAT_RXADDR_ACK 0x40
+#define STAT_RXDATA_ACK 0x50
+#define STAT_IDLE 0xF8
+
+struct octeon_i2c {
+ wait_queue_head_t queue;
+ struct i2c_adapter adap;
+ int irq;
+ int twsi_freq;
+ int sys_freq;
+ resource_size_t twsi_phys;
+ void __iomem *twsi_base;
+ resource_size_t regsize;
+ struct device *dev;
+};
+
+/**
+ * octeon_i2c_write_sw - write an I2C core register.
+ * @i2c: The struct octeon_i2c.
+ * @eop_reg: Register selector.
+ * @data: Value to be written.
+ *
+ * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
+ */
+static void octeon_i2c_write_sw(struct octeon_i2c *i2c,
+ u64 eop_reg,
+ u8 data)
+{
+ u64 tmp;
+
+ __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI);
+ do {
+ tmp = __raw_readq(i2c->twsi_base + SW_TWSI);
+ } while ((tmp & SW_TWSI_V) != 0);
+}
+
+/**
+ * octeon_i2c_read_sw - write an I2C core register.
+ * @i2c: The struct octeon_i2c.
+ * @eop_reg: Register selector.
+ *
+ * Returns the data.
+ *
+ * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
+ */
+static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
+{
+ u64 tmp;
+
+ __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI);
+ do {
+ tmp = __raw_readq(i2c->twsi_base + SW_TWSI);
+ } while ((tmp & SW_TWSI_V) != 0);
+
+ return tmp & 0xFF;
+}
+
+/**
+ * octeon_i2c_write_int - write the TWSI_INT register
+ * @i2c: The struct octeon_i2c.
+ * @data: Value to be written.
+ */
+static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
+{
+ u64 tmp;
+
+ __raw_writeq(data, i2c->twsi_base + TWSI_INT);
+ tmp = __raw_readq(i2c->twsi_base + TWSI_INT);
+}
+
+/**
+ * octeon_i2c_int_enable - enable the TS interrupt.
+ * @i2c: The struct octeon_i2c.
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in
+ * the SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_int_enable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_write_int(i2c, 0x40);
+}
+
+/**
+ * octeon_i2c_int_disable - disable the TS interrupt.
+ * @i2c: The struct octeon_i2c.
+ */
+static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_write_int(i2c, 0);
+}
+
+/**
+ * octeon_i2c_unblock - unblock the bus.
+ * @i2c: The struct octeon_i2c.
+ *
+ * If there was a reset while a device was driving 0 to bus,
+ * bus is blocked. We toggle it free manually by some clock
+ * cycles and send a stop.
+ */
+static void octeon_i2c_unblock(struct octeon_i2c *i2c)
+{
+ int i;
+
+ dev_dbg(i2c->dev, "%s\n", __func__);
+ for (i = 0; i < 9; i++) {
+ octeon_i2c_write_int(i2c, 0x0);
+ udelay(5);
+ octeon_i2c_write_int(i2c, 0x200);
+ udelay(5);
+ }
+ octeon_i2c_write_int(i2c, 0x300);
+ udelay(5);
+ octeon_i2c_write_int(i2c, 0x100);
+ udelay(5);
+ octeon_i2c_write_int(i2c, 0x0);
+}
+
+/**
+ * octeon_i2c_isr - the interrupt service routine.
+ * @int: The irq, unused.
+ * @dev_id: Our struct octeon_i2c.
+ */
+static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
+{
+ struct octeon_i2c *i2c = dev_id;
+
+ octeon_i2c_int_disable(i2c);
+ wake_up_interruptible(&i2c->queue);
+
+ return IRQ_HANDLED;
+}
+
+
+static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
+{
+ return (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_CTL) & TWSI_CTL_IFLG) != 0;
+}
+
+/**
+ * octeon_i2c_wait - wait for the IFLG to be set.
+ * @i2c: The struct octeon_i2c.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_wait(struct octeon_i2c *i2c)
+{
+ int result;
+
+ octeon_i2c_int_enable(i2c);
+
+ result = wait_event_interruptible_timeout(i2c->queue,
+ octeon_i2c_test_iflg(i2c),
+ i2c->adap.timeout);
+
+ octeon_i2c_int_disable(i2c);
+
+ if (result < 0) {
+ dev_dbg(i2c->dev, "%s: wait interrupted\n", __func__);
+ return result;
+ } else if (result == 0) {
+ dev_dbg(i2c->dev, "%s: timeout\n", __func__);
+ result = -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+/**
+ * octeon_i2c_start - send START to the bus.
+ * @i2c: The struct octeon_i2c.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_start(struct octeon_i2c *i2c)
+{
+ u8 data;
+ int result;
+
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+ TWSI_CTL_ENAB | TWSI_CTL_STA);
+
+ result = octeon_i2c_wait(i2c);
+ if (result) {
+ if (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT) == STAT_IDLE) {
+ /*
+ * Controller refused to send start flag May
+ * be a client is holding SDA low - let's try
+ * to free it.
+ */
+ octeon_i2c_unblock(i2c);
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+ TWSI_CTL_ENAB | TWSI_CTL_STA);
+
+ result = octeon_i2c_wait(i2c);
+ }
+ if (result)
+ return result;
+ }
+
+ data = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+ if ((data != STAT_START) && (data != STAT_RSTART)) {
+ dev_err(i2c->dev, "%s: bad status (0x%x)\n", __func__, data);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * octeon_i2c_stop - send STOP to the bus.
+ * @i2c: The struct octeon_i2c.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_stop(struct octeon_i2c *i2c)
+{
+ u8 data;
+
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+ TWSI_CTL_ENAB | TWSI_CTL_STP);
+
+ data = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+
+ if (data != STAT_IDLE) {
+ dev_err(i2c->dev, "%s: bad status(0x%x)\n", __func__, data);
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ * octeon_i2c_write - send data to the bus.
+ * @i2c: The struct octeon_i2c.
+ * @target: Target address.
+ * @data: Pointer to the data to be sent.
+ * @length: Length of the data.
+ *
+ * The address is sent over the bus, then the data.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
+ const u8 *data, int length)
+{
+ int i, result;
+ u8 tmp;
+
+ result = octeon_i2c_start(i2c);
+ if (result)
+ return result;
+
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, target << 1);
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+
+ for (i = 0; i < length; i++) {
+ tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+ if ((tmp != STAT_TXADDR_ACK) && (tmp != STAT_TXDATA_ACK)) {
+ dev_err(i2c->dev,
+ "%s: bad status before write (0x%x)\n",
+ __func__, tmp);
+ return -EIO;
+ }
+
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, data[i]);
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+ }
+
+ return 0;
+}
+
+/**
+ * octeon_i2c_read - receive data from the bus.
+ * @i2c: The struct octeon_i2c.
+ * @target: Target address.
+ * @data: Pointer to the location to store the datae .
+ * @length: Length of the data.
+ *
+ * The address is sent over the bus, then the data is read.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
+ u8 *data, int length)
+{
+ int i, result;
+ u8 tmp;
+
+ if (length < 1)
+ return -EINVAL;
+
+ result = octeon_i2c_start(i2c);
+ if (result)
+ return result;
+
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, (target<<1) | 1);
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+
+ for (i = 0; i < length; i++) {
+ tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+ if ((tmp != STAT_RXDATA_ACK) && (tmp != STAT_RXADDR_ACK)) {
+ dev_err(i2c->dev,
+ "%s: bad status before read (0x%x)\n",
+ __func__, tmp);
+ return -EIO;
+ }
+
+ if (i+1 < length)
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+ TWSI_CTL_ENAB | TWSI_CTL_AAK);
+ else
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+ TWSI_CTL_ENAB);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+
+ data[i] = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_DATA);
+ }
+ return 0;
+}
+
+/**
+ * octeon_i2c_xfer - The driver's master_xfer function.
+ * @adap: Pointer to the i2c_adapter structure.
+ * @msgs: Pointer to the messages to be processed.
+ * @num: Length of the MSGS array.
+ *
+ * Returns the number of messages processed, or a negative errno on
+ * failure.
+ */
+static int octeon_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_msg *pmsg;
+ int i;
+ int ret = 0;
+ struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+
+ for (i = 0; ret == 0 && i < num; i++) {
+ pmsg = &msgs[i];
+ dev_dbg(i2c->dev,
+ "Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n",
+ pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->len, pmsg->addr, i + 1, num);
+ if (pmsg->flags & I2C_M_RD)
+ ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
+ pmsg->len);
+ else
+ ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf,
+ pmsg->len);
+ }
+ octeon_i2c_stop(i2c);
+
+ return (ret != 0) ? ret : num;
+}
+
+static u32 octeon_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm octeon_i2c_algo = {
+ .master_xfer = octeon_i2c_xfer,
+ .functionality = octeon_i2c_functionality,
+};
+
+static struct i2c_adapter octeon_i2c_ops = {
+ .owner = THIS_MODULE,
+ .name = "OCTEON adapter",
+ .algo = &octeon_i2c_algo,
+ .timeout = 2,
+};
+
+/**
+ * octeon_i2c_setclock - Calculate and set clock divisors.
+ */
+static int __init octeon_i2c_setclock(struct octeon_i2c *i2c)
+{
+ int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
+ int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000;
+
+ for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
+ /*
+ * An mdiv value of less than 2 seems to not work well
+ * with ds1337 RTCs, so we constrain it to larger
+ * values.
+ */
+ for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) {
+ /*
+ * For given ndiv and mdiv values check the
+ * two closest thp values.
+ */
+ tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
+ tclk *= (1 << ndiv_idx);
+ thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
+ for (inc = 0; inc <= 1; inc++) {
+ thp_idx = thp_base + inc;
+ if (thp_idx < 5 || thp_idx > 0xff)
+ continue;
+
+ foscl = i2c->sys_freq / (2 * (thp_idx + 1));
+ foscl = foscl / (1 << ndiv_idx);
+ foscl = foscl / (mdiv_idx + 1) / 10;
+ diff = abs(foscl - i2c->twsi_freq);
+ if (diff < delta_hz) {
+ delta_hz = diff;
+ thp = thp_idx;
+ mdiv = mdiv_idx;
+ ndiv = ndiv_idx;
+ }
+ }
+ }
+ }
+ octeon_i2c_write_sw(i2c, SW_TWSI_OP_TWSI_CLK, thp);
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
+
+ return 0;
+}
+
+static int __init octeon_i2c_initlowlevel(struct octeon_i2c *i2c)
+{
+ u8 status;
+ int tries;
+
+ /* disable high level controller, enable bus access */
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+ /* reset controller */
+ octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_RST, 0);
+
+ for (tries = 10; tries; tries--) {
+ udelay(1);
+ status = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+ if (status == STAT_IDLE)
+ return 0;
+ }
+ dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n", __func__, status);
+ return -EIO;
+}
+
+static int __devinit octeon_i2c_probe(struct platform_device *pdev)
+{
+ int irq, result = 0;
+ struct octeon_i2c *i2c;
+ struct octeon_i2c_data *i2c_data;
+ struct resource *res_mem;
+
+ /* All adaptors have an irq. */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+ if (!i2c) {
+ dev_err(&pdev->dev, "kzalloc failed\n");
+ result = -ENOMEM;
+ goto out;
+ }
+ i2c->dev = &pdev->dev;
+ i2c_data = pdev->dev.platform_data;
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (res_mem == NULL) {
+ dev_err(i2c->dev, "found no memory resource\n");
+ result = -ENXIO;
+ goto fail_region;
+ }
+
+ if (i2c_data == NULL) {
+ dev_err(i2c->dev, "no I2C frequency data\n");
+ result = -ENXIO;
+ goto fail_region;
+ }
+
+ i2c->twsi_phys = res_mem->start;
+ i2c->regsize = resource_size(res_mem);
+ i2c->twsi_freq = i2c_data->i2c_freq;
+ i2c->sys_freq = i2c_data->sys_freq;
+
+ if (!request_mem_region(i2c->twsi_phys, i2c->regsize, res_mem->name)) {
+ dev_err(i2c->dev, "request_mem_region failed\n");
+ goto fail_region;
+ }
+ i2c->twsi_base = ioremap(i2c->twsi_phys, i2c->regsize);
+
+ init_waitqueue_head(&i2c->queue);
+
+ i2c->irq = irq;
+
+ result = request_irq(i2c->irq, octeon_i2c_isr, 0, DRV_NAME, i2c);
+ if (result < 0) {
+ dev_err(i2c->dev, "failed to attach interrupt\n");
+ goto fail_irq;
+ }
+
+ result = octeon_i2c_initlowlevel(i2c);
+ if (result) {
+ dev_err(i2c->dev, "init low level failed\n");
+ goto fail_add;
+ }
+
+ result = octeon_i2c_setclock(i2c);
+ if (result) {
+ dev_err(i2c->dev, "clock init failed\n");
+ goto fail_add;
+ }
+
+ i2c->adap = octeon_i2c_ops;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ platform_set_drvdata(pdev, i2c);
+
+ result = i2c_add_numbered_adapter(&i2c->adap);
+ if (result < 0) {
+ dev_err(i2c->dev, "failed to add adapter\n");
+ goto fail_add;
+ }
+
+ dev_info(i2c->dev, "version %s\n", DRV_VERSION);
+
+ return result;
+
+fail_add:
+ platform_set_drvdata(pdev, NULL);
+ free_irq(i2c->irq, i2c);
+fail_irq:
+ iounmap(i2c->twsi_base);
+ release_mem_region(i2c->twsi_phys, i2c->regsize);
+fail_region:
+ kfree(i2c);
+out:
+ return result;
+};
+
+static int __devexit octeon_i2c_remove(struct platform_device *pdev)
+{
+ struct octeon_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ platform_set_drvdata(pdev, NULL);
+ free_irq(i2c->irq, i2c);
+ iounmap(i2c->twsi_base);
+ release_mem_region(i2c->twsi_phys, i2c->regsize);
+ kfree(i2c);
+ return 0;
+};
+
+static struct platform_driver octeon_i2c_driver = {
+ .probe = octeon_i2c_probe,
+ .remove = __devexit_p(octeon_i2c_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ },
+};
+
+static int __init octeon_i2c_init(void)
+{
+ int rv;
+
+ rv = platform_driver_register(&octeon_i2c_driver);
+ return rv;
+}
+
+static void __exit octeon_i2c_exit(void)
+{
+ platform_driver_unregister(&octeon_i2c_driver);
+}
+
+MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);
+
+module_init(octeon_i2c_init);
+module_exit(octeon_i2c_exit);
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 0037e31076ba..c7c237537f81 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -49,24 +49,24 @@
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
#define OMAP_I2C_REV_REG 0x00
-#define OMAP_I2C_IE_REG 0x04
-#define OMAP_I2C_STAT_REG 0x08
-#define OMAP_I2C_IV_REG 0x0c
+#define OMAP_I2C_IE_REG 0x01
+#define OMAP_I2C_STAT_REG 0x02
+#define OMAP_I2C_IV_REG 0x03
/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
-#define OMAP_I2C_WE_REG 0x0c
-#define OMAP_I2C_SYSS_REG 0x10
-#define OMAP_I2C_BUF_REG 0x14
-#define OMAP_I2C_CNT_REG 0x18
-#define OMAP_I2C_DATA_REG 0x1c
-#define OMAP_I2C_SYSC_REG 0x20
-#define OMAP_I2C_CON_REG 0x24
-#define OMAP_I2C_OA_REG 0x28
-#define OMAP_I2C_SA_REG 0x2c
-#define OMAP_I2C_PSC_REG 0x30
-#define OMAP_I2C_SCLL_REG 0x34
-#define OMAP_I2C_SCLH_REG 0x38
-#define OMAP_I2C_SYSTEST_REG 0x3c
-#define OMAP_I2C_BUFSTAT_REG 0x40
+#define OMAP_I2C_WE_REG 0x03
+#define OMAP_I2C_SYSS_REG 0x04
+#define OMAP_I2C_BUF_REG 0x05
+#define OMAP_I2C_CNT_REG 0x06
+#define OMAP_I2C_DATA_REG 0x07
+#define OMAP_I2C_SYSC_REG 0x08
+#define OMAP_I2C_CON_REG 0x09
+#define OMAP_I2C_OA_REG 0x0a
+#define OMAP_I2C_SA_REG 0x0b
+#define OMAP_I2C_PSC_REG 0x0c
+#define OMAP_I2C_SCLL_REG 0x0d
+#define OMAP_I2C_SCLH_REG 0x0e
+#define OMAP_I2C_SYSTEST_REG 0x0f
+#define OMAP_I2C_BUFSTAT_REG 0x10
/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */
@@ -161,6 +161,7 @@ struct omap_i2c_dev {
struct device *dev;
void __iomem *base; /* virtual */
int irq;
+ int reg_shift; /* bit shift for I2C register addresses */
struct clk *iclk; /* Interface clock */
struct clk *fclk; /* Functional clock */
struct completion cmd_complete;
@@ -189,12 +190,12 @@ struct omap_i2c_dev {
static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
int reg, u16 val)
{
- __raw_writew(val, i2c_dev->base + reg);
+ __raw_writew(val, i2c_dev->base + (reg << i2c_dev->reg_shift));
}
static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
{
- return __raw_readw(i2c_dev->base + reg);
+ return __raw_readw(i2c_dev->base + (reg << i2c_dev->reg_shift));
}
static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev)
@@ -849,7 +850,7 @@ static const struct i2c_algorithm omap_i2c_algo = {
.functionality = omap_i2c_func,
};
-static int __init
+static int __devinit
omap_i2c_probe(struct platform_device *pdev)
{
struct omap_i2c_dev *dev;
@@ -924,6 +925,11 @@ omap_i2c_probe(struct platform_device *pdev)
dev->b_hw = 1; /* Enable hardware fixes */
}
+ if (cpu_is_omap7xx())
+ dev->reg_shift = 1;
+ else
+ dev->reg_shift = 2;
+
/* reset ASAP, clearing any IRQs */
omap_i2c_init(dev);
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index 322c5691e38e..5f41ec0f72d2 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------ *
* i2c-parport-light.c I2C bus over parallel port *
* ------------------------------------------------------------------------ *
- Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
Based on older i2c-velleman.c driver
Copyright (C) 1995-2000 Simon G. Vogl
@@ -27,10 +27,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-smbus.h>
#include <asm/io.h>
#include "i2c-parport.h"
@@ -43,6 +45,10 @@ static u16 base;
module_param(base, ushort, 0);
MODULE_PARM_DESC(base, "Base I/O address");
+static int irq;
+module_param(irq, int, 0);
+MODULE_PARM_DESC(irq, "IRQ (optional)");
+
/* ----- Low-level parallel port access ----------------------------------- */
static inline void port_write(unsigned char p, unsigned char d)
@@ -119,6 +125,16 @@ static struct i2c_adapter parport_adapter = {
.name = "Parallel port adapter (light)",
};
+/* SMBus alert support */
+static struct i2c_smbus_alert_setup alert_data = {
+ .alert_edge_triggered = 1,
+};
+static struct i2c_client *ara;
+static struct lineop parport_ctrl_irq = {
+ .val = (1 << 4),
+ .port = CTRL,
+};
+
static int __devinit i2c_parport_probe(struct platform_device *pdev)
{
int err;
@@ -127,18 +143,39 @@ static int __devinit i2c_parport_probe(struct platform_device *pdev)
parport_setsda(NULL, 1);
parport_setscl(NULL, 1);
/* Other init if needed (power on...) */
- if (adapter_parm[type].init.val)
+ if (adapter_parm[type].init.val) {
line_set(1, &adapter_parm[type].init);
+ /* Give powered devices some time to settle */
+ msleep(100);
+ }
parport_adapter.dev.parent = &pdev->dev;
err = i2c_bit_add_bus(&parport_adapter);
- if (err)
+ if (err) {
dev_err(&pdev->dev, "Unable to register with I2C\n");
- return err;
+ return err;
+ }
+
+ /* Setup SMBus alert if supported */
+ if (adapter_parm[type].smbus_alert && irq) {
+ alert_data.irq = irq;
+ ara = i2c_setup_smbus_alert(&parport_adapter, &alert_data);
+ if (ara)
+ line_set(1, &parport_ctrl_irq);
+ else
+ dev_warn(&pdev->dev, "Failed to register ARA client\n");
+ }
+
+ return 0;
}
static int __devexit i2c_parport_remove(struct platform_device *pdev)
{
+ if (ara) {
+ line_set(0, &parport_ctrl_irq);
+ i2c_unregister_device(ara);
+ ara = NULL;
+ }
i2c_del_adapter(&parport_adapter);
/* Un-init if needed (power off...) */
@@ -205,6 +242,9 @@ static int __init i2c_parport_init(void)
if (!request_region(base, 3, DRVNAME))
return -EBUSY;
+ if (irq != 0)
+ pr_info(DRVNAME ": using irq %d\n", irq);
+
if (!adapter_parm[type].getscl.val)
parport_algo_data.getscl = NULL;
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
index 0d8998610c74..220fca7f23a6 100644
--- a/drivers/i2c/busses/i2c-parport.c
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------ *
* i2c-parport.c I2C bus over parallel port *
* ------------------------------------------------------------------------ *
- Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
Based on older i2c-philips-par.c driver
Copyright (C) 1995-2000 Simon G. Vogl
@@ -27,9 +27,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <linux/parport.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-smbus.h>
#include "i2c-parport.h"
/* ----- Device list ------------------------------------------------------ */
@@ -38,6 +40,8 @@ struct i2c_par {
struct pardevice *pdev;
struct i2c_adapter adapter;
struct i2c_algo_bit_data algo_data;
+ struct i2c_smbus_alert_setup alert_data;
+ struct i2c_client *ara;
struct i2c_par *next;
};
@@ -143,6 +147,19 @@ static struct i2c_algo_bit_data parport_algo_data = {
/* ----- I2c and parallel port call-back functions and structures --------- */
+void i2c_parport_irq(void *data)
+{
+ struct i2c_par *adapter = data;
+ struct i2c_client *ara = adapter->ara;
+
+ if (ara) {
+ dev_dbg(&ara->dev, "SMBus alert received\n");
+ i2c_handle_smbus_alert(ara);
+ } else
+ dev_dbg(&adapter->adapter.dev,
+ "SMBus alert received but no ARA client!\n");
+}
+
static void i2c_parport_attach (struct parport *port)
{
struct i2c_par *adapter;
@@ -154,8 +171,9 @@ static void i2c_parport_attach (struct parport *port)
}
pr_debug("i2c-parport: attaching to %s\n", port->name);
+ parport_disable_irq(port);
adapter->pdev = parport_register_device(port, "i2c-parport",
- NULL, NULL, NULL, PARPORT_FLAG_EXCL, NULL);
+ NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter);
if (!adapter->pdev) {
printk(KERN_ERR "i2c-parport: Unable to register with parport\n");
goto ERROR0;
@@ -185,14 +203,29 @@ static void i2c_parport_attach (struct parport *port)
parport_setsda(port, 1);
parport_setscl(port, 1);
/* Other init if needed (power on...) */
- if (adapter_parm[type].init.val)
+ if (adapter_parm[type].init.val) {
line_set(port, 1, &adapter_parm[type].init);
+ /* Give powered devices some time to settle */
+ msleep(100);
+ }
if (i2c_bit_add_bus(&adapter->adapter) < 0) {
printk(KERN_ERR "i2c-parport: Unable to register with I2C\n");
goto ERROR1;
}
+ /* Setup SMBus alert if supported */
+ if (adapter_parm[type].smbus_alert) {
+ adapter->alert_data.alert_edge_triggered = 1;
+ adapter->ara = i2c_setup_smbus_alert(&adapter->adapter,
+ &adapter->alert_data);
+ if (adapter->ara)
+ parport_enable_irq(port);
+ else
+ printk(KERN_WARNING "i2c-parport: Failed to register "
+ "ARA client\n");
+ }
+
/* Add the new adapter to the list */
adapter->next = adapter_list;
adapter_list = adapter;
@@ -213,6 +246,10 @@ static void i2c_parport_detach (struct parport *port)
for (prev = NULL, adapter = adapter_list; adapter;
prev = adapter, adapter = adapter->next) {
if (adapter->pdev->port == port) {
+ if (adapter->ara) {
+ parport_disable_irq(port);
+ i2c_unregister_device(adapter->ara);
+ }
i2c_del_adapter(&adapter->adapter);
/* Un-init if needed (power off...) */
diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h
index ed69d846cb95..a9f66816546c 100644
--- a/drivers/i2c/busses/i2c-parport.h
+++ b/drivers/i2c/busses/i2c-parport.h
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------ *
* i2c-parport.h I2C bus over parallel port *
* ------------------------------------------------------------------------ *
- Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.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
@@ -38,6 +38,7 @@ struct adapter_parm {
struct lineop getsda;
struct lineop getscl;
struct lineop init;
+ unsigned int smbus_alert:1;
};
static struct adapter_parm adapter_parm[] = {
@@ -73,6 +74,7 @@ static struct adapter_parm adapter_parm[] = {
.setscl = { 0x01, DATA, 1 },
.getsda = { 0x10, STAT, 1 },
.init = { 0xf0, DATA, 0 },
+ .smbus_alert = 1,
},
/* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
{
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
index adf0fbb902f0..0d20ff46a518 100644
--- a/drivers/i2c/busses/i2c-pasemi.c
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -400,7 +400,7 @@ static void __devexit pasemi_smb_remove(struct pci_dev *dev)
kfree(smbus);
}
-static struct pci_device_id pasemi_smb_ids[] = {
+static const struct pci_device_id pasemi_smb_ids[] = {
{ PCI_DEVICE(0x1959, 0xa003) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index 0ed68e2ccd22..f7346a9bd95f 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -75,7 +75,7 @@ static int pca_isa_waitforcompletion(void *pd)
unsigned long timeout;
if (irq > -1) {
- ret = wait_event_interruptible_timeout(pca_wait,
+ ret = wait_event_timeout(pca_wait,
pca_isa_readbyte(pd, I2C_PCA_CON)
& I2C_PCA_CON_SI, pca_isa_ops.timeout);
} else {
@@ -96,7 +96,7 @@ static void pca_isa_resetchip(void *pd)
}
static irqreturn_t pca_handler(int this_irq, void *dev_id) {
- wake_up_interruptible(&pca_wait);
+ wake_up(&pca_wait);
return IRQ_HANDLED;
}
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c
index c4df9d411cd5..5b2213df5ed0 100644
--- a/drivers/i2c/busses/i2c-pca-platform.c
+++ b/drivers/i2c/busses/i2c-pca-platform.c
@@ -84,7 +84,7 @@ static int i2c_pca_pf_waitforcompletion(void *pd)
unsigned long timeout;
if (i2c->irq) {
- ret = wait_event_interruptible_timeout(i2c->wait,
+ ret = wait_event_timeout(i2c->wait,
i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
& I2C_PCA_CON_SI, i2c->adap.timeout);
} else {
@@ -122,7 +122,7 @@ static irqreturn_t i2c_pca_pf_handler(int this_irq, void *dev_id)
if ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
return IRQ_NONE;
- wake_up_interruptible(&i2c->wait);
+ wake_up(&i2c->wait);
return IRQ_HANDLED;
}
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 1e245e9cad31..ee9da6fcf69a 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -324,12 +324,12 @@ static int piix4_transaction(void)
else
msleep(1);
- while ((timeout++ < MAX_TIMEOUT) &&
+ while ((++timeout < MAX_TIMEOUT) &&
((temp = inb_p(SMBHSTSTS)) & 0x01))
msleep(1);
/* If the SMBus is still busy, we give up */
- if (timeout >= MAX_TIMEOUT) {
+ if (timeout == MAX_TIMEOUT) {
dev_err(&piix4_adapter.dev, "SMBus Timeout!\n");
result = -ETIMEDOUT;
}
@@ -472,7 +472,7 @@ static struct i2c_adapter piix4_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id piix4_ids[] = {
+static const struct pci_device_id piix4_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) },
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index 5d1c2603a130..9532dee6b580 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -20,15 +20,15 @@
#include <linux/platform_device.h>
#include <linux/i2c-pnx.h>
#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
#include <mach/hardware.h>
#include <mach/i2c.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
#define I2C_PNX_TIMEOUT 10 /* msec */
#define I2C_PNX_SPEED_KHZ 100
#define I2C_PNX_REGION_SIZE 0x100
-#define PNX_DEFAULT_FREQ 13 /* MHz */
static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
{
@@ -50,22 +50,21 @@ static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
return (timeout <= 0);
}
-static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap)
+static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *data = adap->algo_data;
- struct timer_list *timer = &data->mif.timer;
- int expires = I2C_PNX_TIMEOUT / (1000 / HZ);
+ struct timer_list *timer = &alg_data->mif.timer;
+ unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT);
if (expires <= 1)
expires = 2;
del_timer_sync(timer);
- dev_dbg(&adap->dev, "Timer armed at %lu plus %u jiffies.\n",
+ dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n",
jiffies, expires);
timer->expires = jiffies + expires;
- timer->data = (unsigned long)adap;
+ timer->data = (unsigned long)&alg_data;
add_timer(timer);
}
@@ -77,34 +76,34 @@ static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap)
*
* Generate a START signal in the desired mode.
*/
-static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
+static int i2c_pnx_start(unsigned char slave_addr,
+ struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
-
- dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __func__,
+ dev_dbg(&alg_data->adapter.dev, "%s(): addr 0x%x mode %d\n", __func__,
slave_addr, alg_data->mif.mode);
/* Check for 7 bit slave addresses only */
if (slave_addr & ~0x7f) {
- dev_err(&adap->dev, "%s: Invalid slave address %x. "
- "Only 7-bit addresses are supported\n",
- adap->name, slave_addr);
+ dev_err(&alg_data->adapter.dev,
+ "%s: Invalid slave address %x. Only 7-bit addresses are supported\n",
+ alg_data->adapter.name, slave_addr);
return -EINVAL;
}
/* First, make sure bus is idle */
if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) {
/* Somebody else is monopolizing the bus */
- dev_err(&adap->dev, "%s: Bus busy. Slave addr = %02x, "
- "cntrl = %x, stat = %x\n",
- adap->name, slave_addr,
- ioread32(I2C_REG_CTL(alg_data)),
- ioread32(I2C_REG_STS(alg_data)));
+ dev_err(&alg_data->adapter.dev,
+ "%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n",
+ alg_data->adapter.name, slave_addr,
+ ioread32(I2C_REG_CTL(alg_data)),
+ ioread32(I2C_REG_STS(alg_data)));
return -EBUSY;
} else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) {
/* Sorry, we lost the bus */
- dev_err(&adap->dev, "%s: Arbitration failure. "
- "Slave addr = %02x\n", adap->name, slave_addr);
+ dev_err(&alg_data->adapter.dev,
+ "%s: Arbitration failure. Slave addr = %02x\n",
+ alg_data->adapter.name, slave_addr);
return -EIO;
}
@@ -115,14 +114,14 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi,
I2C_REG_STS(alg_data));
- dev_dbg(&adap->dev, "%s(): sending %#x\n", __func__,
+ dev_dbg(&alg_data->adapter.dev, "%s(): sending %#x\n", __func__,
(slave_addr << 1) | start_bit | alg_data->mif.mode);
/* Write the slave address, START bit and R/W bit */
iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode,
I2C_REG_TX(alg_data));
- dev_dbg(&adap->dev, "%s(): exit\n", __func__);
+ dev_dbg(&alg_data->adapter.dev, "%s(): exit\n", __func__);
return 0;
}
@@ -133,13 +132,12 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
*
* Generate a STOP signal to terminate the master transaction.
*/
-static void i2c_pnx_stop(struct i2c_adapter *adap)
+static void i2c_pnx_stop(struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
/* Only 1 msec max timeout due to interrupt context */
long timeout = 1000;
- dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
/* Write a STOP bit to TX FIFO */
@@ -153,7 +151,7 @@ static void i2c_pnx_stop(struct i2c_adapter *adap)
timeout--;
}
- dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
}
@@ -163,36 +161,29 @@ static void i2c_pnx_stop(struct i2c_adapter *adap)
*
* Sends one byte of data to the slave
*/
-static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
+static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
u32 val;
- dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
if (alg_data->mif.len > 0) {
/* We still have something to talk about... */
val = *alg_data->mif.buf++;
- if (alg_data->mif.len == 1) {
- val |= stop_bit;
- if (!alg_data->last)
- val |= start_bit;
- }
-
alg_data->mif.len--;
iowrite32(val, I2C_REG_TX(alg_data));
- dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __func__,
- val, alg_data->mif.len + 1);
+ dev_dbg(&alg_data->adapter.dev, "%s(): xmit %#x [%d]\n",
+ __func__, val, alg_data->mif.len + 1);
if (alg_data->mif.len == 0) {
if (alg_data->last) {
/* Wait until the STOP is seen. */
if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
- dev_err(&adap->dev, "The bus is still "
- "active after timeout\n");
+ dev_err(&alg_data->adapter.dev,
+ "The bus is still active after timeout\n");
}
/* Disable master interrupts */
iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
@@ -201,14 +192,15 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
del_timer_sync(&alg_data->mif.timer);
- dev_dbg(&adap->dev, "%s(): Waking up xfer routine.\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Waking up xfer routine.\n",
__func__);
complete(&alg_data->mif.complete);
}
} else if (alg_data->mif.len == 0) {
/* zero-sized transfer */
- i2c_pnx_stop(adap);
+ i2c_pnx_stop(alg_data);
/* Disable master interrupts. */
iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
@@ -217,13 +209,14 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
/* Stop timer. */
del_timer_sync(&alg_data->mif.timer);
- dev_dbg(&adap->dev, "%s(): Waking up xfer routine after "
- "zero-xfer.\n", __func__);
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Waking up xfer routine after zero-xfer.\n",
+ __func__);
complete(&alg_data->mif.complete);
}
- dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
return 0;
@@ -235,28 +228,23 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
*
* Reads one byte data from the slave
*/
-static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
+static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
unsigned int val = 0;
u32 ctl = 0;
- dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
/* Check, whether there is already data,
* or we didn't 'ask' for it yet.
*/
if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) {
- dev_dbg(&adap->dev, "%s(): Write dummy data to fill "
- "Rx-fifo...\n", __func__);
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Write dummy data to fill Rx-fifo...\n",
+ __func__);
if (alg_data->mif.len == 1) {
- /* Last byte, do not acknowledge next rcv. */
- val |= stop_bit;
- if (!alg_data->last)
- val |= start_bit;
-
/*
* Enable interrupt RFDAIE (data in Rx fifo),
* and disable DRMIE (need data for Tx)
@@ -281,16 +269,16 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
if (alg_data->mif.len > 0) {
val = ioread32(I2C_REG_RX(alg_data));
*alg_data->mif.buf++ = (u8) (val & 0xff);
- dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __func__, val,
- alg_data->mif.len);
+ dev_dbg(&alg_data->adapter.dev, "%s(): rcv 0x%x [%d]\n",
+ __func__, val, alg_data->mif.len);
alg_data->mif.len--;
if (alg_data->mif.len == 0) {
if (alg_data->last)
/* Wait until the STOP is seen. */
if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
- dev_err(&adap->dev, "The bus is still "
- "active after timeout\n");
+ dev_err(&alg_data->adapter.dev,
+ "The bus is still active after timeout\n");
/* Disable master interrupts */
ctl = ioread32(I2C_REG_CTL(alg_data));
@@ -304,7 +292,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
}
}
- dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
return 0;
@@ -312,11 +300,11 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
{
+ struct i2c_pnx_algo_data *alg_data = dev_id;
u32 stat, ctl;
- struct i2c_adapter *adap = dev_id;
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
- dev_dbg(&adap->dev, "%s(): mstat = %x mctrl = %x, mode = %d\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): mstat = %x mctrl = %x, mode = %d\n",
__func__,
ioread32(I2C_REG_STS(alg_data)),
ioread32(I2C_REG_CTL(alg_data)),
@@ -339,10 +327,10 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
complete(&alg_data->mif.complete);
} else if (stat & mstatus_nai) {
/* Slave did not acknowledge, generate a STOP */
- dev_dbg(&adap->dev, "%s(): "
- "Slave did not acknowledge, generating a STOP.\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Slave did not acknowledge, generating a STOP.\n",
__func__);
- i2c_pnx_stop(adap);
+ i2c_pnx_stop(alg_data);
/* Disable master interrupts. */
ctl = ioread32(I2C_REG_CTL(alg_data));
@@ -368,9 +356,9 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
*/
if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) {
if (alg_data->mif.mode == I2C_SMBUS_WRITE) {
- i2c_pnx_master_xmit(adap);
+ i2c_pnx_master_xmit(alg_data);
} else if (alg_data->mif.mode == I2C_SMBUS_READ) {
- i2c_pnx_master_rcv(adap);
+ i2c_pnx_master_rcv(alg_data);
}
}
}
@@ -379,7 +367,8 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
stat = ioread32(I2C_REG_STS(alg_data));
iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data));
- dev_dbg(&adap->dev, "%s(): exiting, stat = %x ctrl = %x.\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): exiting, stat = %x ctrl = %x.\n",
__func__, ioread32(I2C_REG_STS(alg_data)),
ioread32(I2C_REG_CTL(alg_data)));
@@ -388,14 +377,13 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
static void i2c_pnx_timeout(unsigned long data)
{
- struct i2c_adapter *adap = (struct i2c_adapter *)data;
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)data;
u32 ctl;
- dev_err(&adap->dev, "Master timed out. stat = %04x, cntrl = %04x. "
- "Resetting master...\n",
- ioread32(I2C_REG_STS(alg_data)),
- ioread32(I2C_REG_CTL(alg_data)));
+ dev_err(&alg_data->adapter.dev,
+ "Master timed out. stat = %04x, cntrl = %04x. Resetting master...\n",
+ ioread32(I2C_REG_STS(alg_data)),
+ ioread32(I2C_REG_CTL(alg_data)));
/* Reset master and disable interrupts */
ctl = ioread32(I2C_REG_CTL(alg_data));
@@ -409,15 +397,14 @@ static void i2c_pnx_timeout(unsigned long data)
complete(&alg_data->mif.complete);
}
-static inline void bus_reset_if_active(struct i2c_adapter *adap)
+static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data)
{
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
u32 stat;
if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) {
- dev_err(&adap->dev,
+ dev_err(&alg_data->adapter.dev,
"%s: Bus is still active after xfer. Reset it...\n",
- adap->name);
+ alg_data->adapter.name);
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
I2C_REG_CTL(alg_data));
wait_reset(I2C_PNX_TIMEOUT, alg_data);
@@ -451,10 +438,11 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
struct i2c_pnx_algo_data *alg_data = adap->algo_data;
u32 stat = ioread32(I2C_REG_STS(alg_data));
- dev_dbg(&adap->dev, "%s(): entering: %d messages, stat = %04x.\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): entering: %d messages, stat = %04x.\n",
__func__, num, ioread32(I2C_REG_STS(alg_data)));
- bus_reset_if_active(adap);
+ bus_reset_if_active(alg_data);
/* Process transactions in a loop. */
for (i = 0; rc >= 0 && i < num; i++) {
@@ -464,9 +452,9 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
addr = pmsg->addr;
if (pmsg->flags & I2C_M_TEN) {
- dev_err(&adap->dev,
+ dev_err(&alg_data->adapter.dev,
"%s: 10 bits addr not supported!\n",
- adap->name);
+ alg_data->adapter.name);
rc = -EINVAL;
break;
}
@@ -478,11 +466,10 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
alg_data->mif.ret = 0;
alg_data->last = (i == num - 1);
- dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __func__,
- alg_data->mif.mode,
- alg_data->mif.len);
+ dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n",
+ __func__, alg_data->mif.mode, alg_data->mif.len);
- i2c_pnx_arm_timer(adap);
+ i2c_pnx_arm_timer(alg_data);
/* initialize the completion var */
init_completion(&alg_data->mif.complete);
@@ -493,7 +480,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
I2C_REG_CTL(alg_data));
/* Put start-code and slave-address on the bus. */
- rc = i2c_pnx_start(addr, adap);
+ rc = i2c_pnx_start(addr, alg_data);
if (rc < 0)
break;
@@ -502,31 +489,32 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if (!(rc = alg_data->mif.ret))
completed++;
- dev_dbg(&adap->dev, "%s(): Complete, return code = %d.\n",
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Complete, return code = %d.\n",
__func__, rc);
/* Clear TDI and AFI bits in case they are set. */
if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) {
- dev_dbg(&adap->dev,
+ dev_dbg(&alg_data->adapter.dev,
"%s: TDI still set... clearing now.\n",
- adap->name);
+ alg_data->adapter.name);
iowrite32(stat, I2C_REG_STS(alg_data));
}
if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) {
- dev_dbg(&adap->dev,
+ dev_dbg(&alg_data->adapter.dev,
"%s: AFI still set... clearing now.\n",
- adap->name);
+ alg_data->adapter.name);
iowrite32(stat, I2C_REG_STS(alg_data));
}
}
- bus_reset_if_active(adap);
+ bus_reset_if_active(alg_data);
/* Cleanup to be sure... */
alg_data->mif.buf = NULL;
alg_data->mif.len = 0;
- dev_dbg(&adap->dev, "%s(): exiting, stat = %x\n",
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
if (completed != num)
@@ -545,69 +533,92 @@ static struct i2c_algorithm pnx_algorithm = {
.functionality = i2c_pnx_func,
};
+#ifdef CONFIG_PM
static int i2c_pnx_controller_suspend(struct platform_device *pdev,
pm_message_t state)
{
- struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
- return i2c_pnx->suspend(pdev, state);
+ struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+
+ /* FIXME: shouldn't this be clk_disable? */
+ clk_enable(alg_data->clk);
+
+ return 0;
}
static int i2c_pnx_controller_resume(struct platform_device *pdev)
{
- struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
- return i2c_pnx->resume(pdev);
+ struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+
+ return clk_enable(alg_data->clk);
}
+#else
+#define i2c_pnx_controller_suspend NULL
+#define i2c_pnx_controller_resume NULL
+#endif
static int __devinit i2c_pnx_probe(struct platform_device *pdev)
{
unsigned long tmp;
int ret = 0;
struct i2c_pnx_algo_data *alg_data;
- int freq_mhz;
+ unsigned long freq;
struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data;
- if (!i2c_pnx || !i2c_pnx->adapter) {
+ if (!i2c_pnx || !i2c_pnx->name) {
dev_err(&pdev->dev, "%s: no platform data supplied\n",
__func__);
ret = -EINVAL;
goto out;
}
- platform_set_drvdata(pdev, i2c_pnx);
-
- if (i2c_pnx->calculate_input_freq)
- freq_mhz = i2c_pnx->calculate_input_freq(pdev);
- else {
- freq_mhz = PNX_DEFAULT_FREQ;
- dev_info(&pdev->dev, "Setting bus frequency to default value: "
- "%d MHz\n", freq_mhz);
+ alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL);
+ if (!alg_data) {
+ ret = -ENOMEM;
+ goto err_kzalloc;
}
- i2c_pnx->adapter->algo = &pnx_algorithm;
+ platform_set_drvdata(pdev, alg_data);
+
+ strlcpy(alg_data->adapter.name, i2c_pnx->name,
+ sizeof(alg_data->adapter.name));
+ alg_data->adapter.dev.parent = &pdev->dev;
+ alg_data->adapter.algo = &pnx_algorithm;
+ alg_data->adapter.algo_data = alg_data;
+ alg_data->adapter.nr = pdev->id;
+ alg_data->i2c_pnx = i2c_pnx;
+
+ alg_data->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(alg_data->clk)) {
+ ret = PTR_ERR(alg_data->clk);
+ goto out_drvdata;
+ }
- alg_data = i2c_pnx->adapter->algo_data;
init_timer(&alg_data->mif.timer);
alg_data->mif.timer.function = i2c_pnx_timeout;
- alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter;
+ alg_data->mif.timer.data = (unsigned long)alg_data;
/* Register I/O resource */
- if (!request_mem_region(alg_data->base, I2C_PNX_REGION_SIZE,
+ if (!request_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE,
pdev->name)) {
dev_err(&pdev->dev,
"I/O region 0x%08x for I2C already in use.\n",
- alg_data->base);
+ i2c_pnx->base);
ret = -ENODEV;
- goto out_drvdata;
+ goto out_clkget;
}
- if (!(alg_data->ioaddr =
- (u32)ioremap(alg_data->base, I2C_PNX_REGION_SIZE))) {
+ alg_data->ioaddr = ioremap(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+ if (!alg_data->ioaddr) {
dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n");
ret = -ENOMEM;
goto out_release;
}
- i2c_pnx->set_clock_run(pdev);
+ ret = clk_enable(alg_data->clk);
+ if (ret)
+ goto out_unmap;
+
+ freq = clk_get_rate(alg_data->clk);
/*
* Clock Divisor High This value is the number of system clocks
@@ -620,45 +631,47 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
* the deglitching filter length.
*/
- tmp = ((freq_mhz * 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
+ tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
iowrite32(tmp, I2C_REG_CKH(alg_data));
iowrite32(tmp, I2C_REG_CKL(alg_data));
iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data));
if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) {
ret = -ENODEV;
- goto out_unmap;
+ goto out_clock;
}
init_completion(&alg_data->mif.complete);
- ret = request_irq(alg_data->irq, i2c_pnx_interrupt,
- 0, pdev->name, i2c_pnx->adapter);
+ ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt,
+ 0, pdev->name, alg_data);
if (ret)
goto out_clock;
/* Register this adapter with the I2C subsystem */
- i2c_pnx->adapter->dev.parent = &pdev->dev;
- i2c_pnx->adapter->nr = pdev->id;
- ret = i2c_add_numbered_adapter(i2c_pnx->adapter);
+ ret = i2c_add_numbered_adapter(&alg_data->adapter);
if (ret < 0) {
dev_err(&pdev->dev, "I2C: Failed to add bus\n");
goto out_irq;
}
dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
- i2c_pnx->adapter->name, alg_data->base, alg_data->irq);
+ alg_data->adapter.name, i2c_pnx->base, i2c_pnx->irq);
return 0;
out_irq:
- free_irq(alg_data->irq, i2c_pnx->adapter);
+ free_irq(i2c_pnx->irq, alg_data);
out_clock:
- i2c_pnx->set_clock_stop(pdev);
+ clk_disable(alg_data->clk);
out_unmap:
- iounmap((void *)alg_data->ioaddr);
+ iounmap(alg_data->ioaddr);
out_release:
- release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
+ release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+out_clkget:
+ clk_put(alg_data->clk);
out_drvdata:
+ kfree(alg_data);
+err_kzalloc:
platform_set_drvdata(pdev, NULL);
out:
return ret;
@@ -666,15 +679,16 @@ out:
static int __devexit i2c_pnx_remove(struct platform_device *pdev)
{
- struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
- struct i2c_adapter *adap = i2c_pnx->adapter;
- struct i2c_pnx_algo_data *alg_data = adap->algo_data;
-
- free_irq(alg_data->irq, i2c_pnx->adapter);
- i2c_del_adapter(adap);
- i2c_pnx->set_clock_stop(pdev);
- iounmap((void *)alg_data->ioaddr);
- release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
+ struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+ struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx;
+
+ free_irq(i2c_pnx->irq, alg_data);
+ i2c_del_adapter(&alg_data->adapter);
+ clk_disable(alg_data->clk);
+ iounmap(alg_data->ioaddr);
+ release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+ clk_put(alg_data->clk);
+ kfree(alg_data);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 1c440a70ec61..b289ec99eeba 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -122,9 +122,14 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len);
if (rc) {
- dev_err(&adap->dev,
- "I2C transfer at 0x%02x failed, size %d, err %d\n",
- addrdir >> 1, size, rc);
+ if (rc == -ENXIO)
+ dev_dbg(&adap->dev,
+ "I2C transfer at 0x%02x failed, size %d, "
+ "err %d\n", addrdir >> 1, size, rc);
+ else
+ dev_err(&adap->dev,
+ "I2C transfer at 0x%02x failed, size %d, "
+ "err %d\n", addrdir >> 1, size, rc);
goto bail;
}
@@ -175,10 +180,16 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
goto bail;
}
rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
- if (rc < 0)
- dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
- addrdir & 1 ? "read from" : "write to", addrdir >> 1,
- rc);
+ if (rc < 0) {
+ if (rc == -ENXIO)
+ dev_dbg(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+ addrdir & 1 ? "read from" : "write to",
+ addrdir >> 1, rc);
+ else
+ dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+ addrdir & 1 ? "read from" : "write to",
+ addrdir >> 1, rc);
+ }
bail:
pmac_i2c_close(bus);
return rc < 0 ? rc : 1;
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 7647a20523a0..90ffbf6f9d4f 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -12,7 +12,7 @@
*
* History:
* Apr 2002: Initial version [CS]
- * Jun 2002: Properly seperated algo/adap [FB]
+ * Jun 2002: Properly separated algo/adap [FB]
* Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem]
* Jan 2003: added limited signal handling [Kai-Uwe Bloem]
* Sep 2004: Major rework to ensure efficient bus handling [RMK]
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index 844569f7d8b7..55a71370c79b 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -369,7 +369,7 @@ static struct i2c_adapter sis5595_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id sis5595_ids[] __devinitdata = {
+static const struct pci_device_id sis5595_ids[] __devinitconst = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index 68cff7af7013..2309c7f1bde2 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -468,7 +468,7 @@ static struct i2c_adapter sis630_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id sis630_ids[] __devinitdata = {
+static const struct pci_device_id sis630_ids[] __devinitconst = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
{ 0, }
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index 1649963b00dc..d43d8f8943dd 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -245,7 +245,7 @@ static struct i2c_adapter sis96x_adapter = {
.algo = &smbus_algorithm,
};
-static struct pci_device_id sis96x_ids[] = {
+static const struct pci_device_id sis96x_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
index b1c050ff311d..b5b1bbf37d3c 100644
--- a/drivers/i2c/busses/i2c-tiny-usb.c
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
+#include <linux/types.h>
/* include interfaces to usb layer */
#include <linux/usb.h>
@@ -30,11 +31,13 @@
#define CMD_I2C_IO_BEGIN (1<<0)
#define CMD_I2C_IO_END (1<<1)
-/* i2c bit delay, default is 10us -> 100kHz */
-static int delay = 10;
-module_param(delay, int, 0);
-MODULE_PARM_DESC(delay, "bit delay in microseconds, "
- "e.g. 10 for 100kHz (default is 100kHz)");
+/* i2c bit delay, default is 10us -> 100kHz max
+ (in practice, due to additional delays in the i2c bitbanging
+ code this results in a i2c clock of about 50kHz) */
+static unsigned short delay = 10;
+module_param(delay, ushort, 0);
+MODULE_PARM_DESC(delay, "bit delay in microseconds "
+ "(default is 10us for 100kHz max)");
static int usb_read(struct i2c_adapter *adapter, int cmd,
int value, int index, void *data, int len);
@@ -109,7 +112,7 @@ static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
static u32 usb_func(struct i2c_adapter *adapter)
{
- u32 func;
+ __le32 func;
/* get functionality from adapter */
if (usb_read(adapter, CMD_GET_FUNC, 0, 0, &func, sizeof(func)) !=
@@ -118,7 +121,7 @@ static u32 usb_func(struct i2c_adapter *adapter)
return 0;
}
- return func;
+ return le32_to_cpu(func);
}
/* This is the actual algorithm we define */
@@ -136,7 +139,7 @@ static const struct i2c_algorithm usb_algorithm = {
* Future Technology Devices International Ltd., later a pair was
* bought from EZPrototypes
*/
-static struct usb_device_id i2c_tiny_usb_table [] = {
+static const struct usb_device_id i2c_tiny_usb_table[] = {
{ USB_DEVICE(0x0403, 0xc631) }, /* FTDI */
{ USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */
{ } /* Terminating entry */
@@ -216,8 +219,7 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
"i2c-tiny-usb at bus %03d device %03d",
dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
- if (usb_write(&dev->adapter, CMD_SET_DELAY,
- cpu_to_le16(delay), 0, NULL, 0) != 0) {
+ if (usb_write(&dev->adapter, CMD_SET_DELAY, delay, 0, NULL, 0) != 0) {
dev_err(&dev->adapter.dev,
"failure setting delay to %dus\n", delay);
retval = -EIO;
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
index 8b24f192103a..de78283bddbe 100644
--- a/drivers/i2c/busses/i2c-via.c
+++ b/drivers/i2c/busses/i2c-via.c
@@ -89,7 +89,7 @@ static struct i2c_adapter vt586b_adapter = {
};
-static struct pci_device_id vt586b_ids[] __devinitdata = {
+static const struct pci_device_id vt586b_ids[] __devinitconst = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index e4b1543015af..d57292e5dae0 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -165,10 +165,10 @@ static int vt596_transaction(u8 size)
do {
msleep(1);
temp = inb_p(SMBHSTSTS);
- } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
+ } while ((temp & 0x01) && (++timeout < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */
- if (timeout >= MAX_TIMEOUT) {
+ if (timeout == MAX_TIMEOUT) {
result = -ETIMEDOUT;
dev_err(&vt596_adapter.dev, "SMBus timeout!\n");
}
@@ -444,7 +444,7 @@ release_region:
return error;
}
-static struct pci_device_id vt596_ids[] = {
+static const struct pci_device_id vt596_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3),
.driver_data = SMBBA1 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3),
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
new file mode 100644
index 000000000000..f0ef8da6c554
--- /dev/null
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -0,0 +1,825 @@
+/*
+ * i2c-xiic.c
+ * Copyright (c) 2002-2007 Xilinx Inc.
+ * Copyright (c) 2009-2010 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ *
+ * This code was implemented by Mocean Laboratories AB when porting linux
+ * to the automotive development board Russellville. The copyright holder
+ * as seen in the header is Intel corporation.
+ * Mocean Laboratories forked off the GNU/Linux platform work into a
+ * separate company called Pelagicore AB, which commited the code to the
+ * kernel.
+ */
+
+/* Supports:
+ * Xilinx IIC
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/i2c-xiic.h>
+#include <linux/io.h>
+
+#define DRIVER_NAME "xiic-i2c"
+
+enum xilinx_i2c_state {
+ STATE_DONE,
+ STATE_ERROR,
+ STATE_START
+};
+
+/**
+ * struct xiic_i2c - Internal representation of the XIIC I2C bus
+ * @base: Memory base of the HW registers
+ * @wait: Wait queue for callers
+ * @adap: Kernel adapter representation
+ * @tx_msg: Messages from above to be sent
+ * @lock: Mutual exclusion
+ * @tx_pos: Current pos in TX message
+ * @nmsgs: Number of messages in tx_msg
+ * @state: See STATE_
+ * @rx_msg: Current RX message
+ * @rx_pos: Position within current RX message
+ */
+struct xiic_i2c {
+ void __iomem *base;
+ wait_queue_head_t wait;
+ struct i2c_adapter adap;
+ struct i2c_msg *tx_msg;
+ spinlock_t lock;
+ unsigned int tx_pos;
+ unsigned int nmsgs;
+ enum xilinx_i2c_state state;
+ struct i2c_msg *rx_msg;
+ int rx_pos;
+};
+
+
+#define XIIC_MSB_OFFSET 0
+#define XIIC_REG_OFFSET (0x100+XIIC_MSB_OFFSET)
+
+/*
+ * Register offsets in bytes from RegisterBase. Three is added to the
+ * base offset to access LSB (IBM style) of the word
+ */
+#define XIIC_CR_REG_OFFSET (0x00+XIIC_REG_OFFSET) /* Control Register */
+#define XIIC_SR_REG_OFFSET (0x04+XIIC_REG_OFFSET) /* Status Register */
+#define XIIC_DTR_REG_OFFSET (0x08+XIIC_REG_OFFSET) /* Data Tx Register */
+#define XIIC_DRR_REG_OFFSET (0x0C+XIIC_REG_OFFSET) /* Data Rx Register */
+#define XIIC_ADR_REG_OFFSET (0x10+XIIC_REG_OFFSET) /* Address Register */
+#define XIIC_TFO_REG_OFFSET (0x14+XIIC_REG_OFFSET) /* Tx FIFO Occupancy */
+#define XIIC_RFO_REG_OFFSET (0x18+XIIC_REG_OFFSET) /* Rx FIFO Occupancy */
+#define XIIC_TBA_REG_OFFSET (0x1C+XIIC_REG_OFFSET) /* 10 Bit Address reg */
+#define XIIC_RFD_REG_OFFSET (0x20+XIIC_REG_OFFSET) /* Rx FIFO Depth reg */
+#define XIIC_GPO_REG_OFFSET (0x24+XIIC_REG_OFFSET) /* Output Register */
+
+/* Control Register masks */
+#define XIIC_CR_ENABLE_DEVICE_MASK 0x01 /* Device enable = 1 */
+#define XIIC_CR_TX_FIFO_RESET_MASK 0x02 /* Transmit FIFO reset=1 */
+#define XIIC_CR_MSMS_MASK 0x04 /* Master starts Txing=1 */
+#define XIIC_CR_DIR_IS_TX_MASK 0x08 /* Dir of tx. Txing=1 */
+#define XIIC_CR_NO_ACK_MASK 0x10 /* Tx Ack. NO ack = 1 */
+#define XIIC_CR_REPEATED_START_MASK 0x20 /* Repeated start = 1 */
+#define XIIC_CR_GENERAL_CALL_MASK 0x40 /* Gen Call enabled = 1 */
+
+/* Status Register masks */
+#define XIIC_SR_GEN_CALL_MASK 0x01 /* 1=a mstr issued a GC */
+#define XIIC_SR_ADDR_AS_SLAVE_MASK 0x02 /* 1=when addr as slave */
+#define XIIC_SR_BUS_BUSY_MASK 0x04 /* 1 = bus is busy */
+#define XIIC_SR_MSTR_RDING_SLAVE_MASK 0x08 /* 1=Dir: mstr <-- slave */
+#define XIIC_SR_TX_FIFO_FULL_MASK 0x10 /* 1 = Tx FIFO full */
+#define XIIC_SR_RX_FIFO_FULL_MASK 0x20 /* 1 = Rx FIFO full */
+#define XIIC_SR_RX_FIFO_EMPTY_MASK 0x40 /* 1 = Rx FIFO empty */
+#define XIIC_SR_TX_FIFO_EMPTY_MASK 0x80 /* 1 = Tx FIFO empty */
+
+/* Interrupt Status Register masks Interrupt occurs when... */
+#define XIIC_INTR_ARB_LOST_MASK 0x01 /* 1 = arbitration lost */
+#define XIIC_INTR_TX_ERROR_MASK 0x02 /* 1=Tx error/msg complete */
+#define XIIC_INTR_TX_EMPTY_MASK 0x04 /* 1 = Tx FIFO/reg empty */
+#define XIIC_INTR_RX_FULL_MASK 0x08 /* 1=Rx FIFO/reg=OCY level */
+#define XIIC_INTR_BNB_MASK 0x10 /* 1 = Bus not busy */
+#define XIIC_INTR_AAS_MASK 0x20 /* 1 = when addr as slave */
+#define XIIC_INTR_NAAS_MASK 0x40 /* 1 = not addr as slave */
+#define XIIC_INTR_TX_HALF_MASK 0x80 /* 1 = TX FIFO half empty */
+
+/* The following constants specify the depth of the FIFOs */
+#define IIC_RX_FIFO_DEPTH 16 /* Rx fifo capacity */
+#define IIC_TX_FIFO_DEPTH 16 /* Tx fifo capacity */
+
+/* The following constants specify groups of interrupts that are typically
+ * enabled or disables at the same time
+ */
+#define XIIC_TX_INTERRUPTS \
+(XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)
+
+#define XIIC_TX_RX_INTERRUPTS (XIIC_INTR_RX_FULL_MASK | XIIC_TX_INTERRUPTS)
+
+/* The following constants are used with the following macros to specify the
+ * operation, a read or write operation.
+ */
+#define XIIC_READ_OPERATION 1
+#define XIIC_WRITE_OPERATION 0
+
+/*
+ * Tx Fifo upper bit masks.
+ */
+#define XIIC_TX_DYN_START_MASK 0x0100 /* 1 = Set dynamic start */
+#define XIIC_TX_DYN_STOP_MASK 0x0200 /* 1 = Set dynamic stop */
+
+/*
+ * The following constants define the register offsets for the Interrupt
+ * registers. There are some holes in the memory map for reserved addresses
+ * to allow other registers to be added and still match the memory map of the
+ * interrupt controller registers
+ */
+#define XIIC_DGIER_OFFSET 0x1C /* Device Global Interrupt Enable Register */
+#define XIIC_IISR_OFFSET 0x20 /* Interrupt Status Register */
+#define XIIC_IIER_OFFSET 0x28 /* Interrupt Enable Register */
+#define XIIC_RESETR_OFFSET 0x40 /* Reset Register */
+
+#define XIIC_RESET_MASK 0xAUL
+
+/*
+ * The following constant is used for the device global interrupt enable
+ * register, to enable all interrupts for the device, this is the only bit
+ * in the register
+ */
+#define XIIC_GINTR_ENABLE_MASK 0x80000000UL
+
+#define xiic_tx_space(i2c) ((i2c)->tx_msg->len - (i2c)->tx_pos)
+#define xiic_rx_space(i2c) ((i2c)->rx_msg->len - (i2c)->rx_pos)
+
+static void xiic_start_xfer(struct xiic_i2c *i2c);
+static void __xiic_start_xfer(struct xiic_i2c *i2c);
+
+static inline void xiic_setreg8(struct xiic_i2c *i2c, int reg, u8 value)
+{
+ iowrite8(value, i2c->base + reg);
+}
+
+static inline u8 xiic_getreg8(struct xiic_i2c *i2c, int reg)
+{
+ return ioread8(i2c->base + reg);
+}
+
+static inline void xiic_setreg16(struct xiic_i2c *i2c, int reg, u16 value)
+{
+ iowrite16(value, i2c->base + reg);
+}
+
+static inline void xiic_setreg32(struct xiic_i2c *i2c, int reg, int value)
+{
+ iowrite32(value, i2c->base + reg);
+}
+
+static inline int xiic_getreg32(struct xiic_i2c *i2c, int reg)
+{
+ return ioread32(i2c->base + reg);
+}
+
+static inline void xiic_irq_dis(struct xiic_i2c *i2c, u32 mask)
+{
+ u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+ xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier & ~mask);
+}
+
+static inline void xiic_irq_en(struct xiic_i2c *i2c, u32 mask)
+{
+ u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+ xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier | mask);
+}
+
+static inline void xiic_irq_clr(struct xiic_i2c *i2c, u32 mask)
+{
+ u32 isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
+ xiic_setreg32(i2c, XIIC_IISR_OFFSET, isr & mask);
+}
+
+static inline void xiic_irq_clr_en(struct xiic_i2c *i2c, u32 mask)
+{
+ xiic_irq_clr(i2c, mask);
+ xiic_irq_en(i2c, mask);
+}
+
+static void xiic_clear_rx_fifo(struct xiic_i2c *i2c)
+{
+ u8 sr;
+ for (sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET);
+ !(sr & XIIC_SR_RX_FIFO_EMPTY_MASK);
+ sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET))
+ xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+}
+
+static void xiic_reinit(struct xiic_i2c *i2c)
+{
+ xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
+
+ /* Set receive Fifo depth to maximum (zero based). */
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, IIC_RX_FIFO_DEPTH - 1);
+
+ /* Reset Tx Fifo. */
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_TX_FIFO_RESET_MASK);
+
+ /* Enable IIC Device, remove Tx Fifo reset & disable general call. */
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK);
+
+ /* make sure RX fifo is empty */
+ xiic_clear_rx_fifo(i2c);
+
+ /* Enable interrupts */
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+
+ xiic_irq_clr_en(i2c, XIIC_INTR_AAS_MASK | XIIC_INTR_ARB_LOST_MASK);
+}
+
+static void xiic_deinit(struct xiic_i2c *i2c)
+{
+ u8 cr;
+
+ xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
+
+ /* Disable IIC Device. */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & ~XIIC_CR_ENABLE_DEVICE_MASK);
+}
+
+static void xiic_read_rx(struct xiic_i2c *i2c)
+{
+ u8 bytes_in_fifo;
+ int i;
+
+ bytes_in_fifo = xiic_getreg8(i2c, XIIC_RFO_REG_OFFSET) + 1;
+
+ dev_dbg(i2c->adap.dev.parent, "%s entry, bytes in fifo: %d, msg: %d"
+ ", SR: 0x%x, CR: 0x%x\n",
+ __func__, bytes_in_fifo, xiic_rx_space(i2c),
+ xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+
+ if (bytes_in_fifo > xiic_rx_space(i2c))
+ bytes_in_fifo = xiic_rx_space(i2c);
+
+ for (i = 0; i < bytes_in_fifo; i++)
+ i2c->rx_msg->buf[i2c->rx_pos++] =
+ xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET,
+ (xiic_rx_space(i2c) > IIC_RX_FIFO_DEPTH) ?
+ IIC_RX_FIFO_DEPTH - 1 : xiic_rx_space(i2c) - 1);
+}
+
+static int xiic_tx_fifo_space(struct xiic_i2c *i2c)
+{
+ /* return the actual space left in the FIFO */
+ return IIC_TX_FIFO_DEPTH - xiic_getreg8(i2c, XIIC_TFO_REG_OFFSET) - 1;
+}
+
+static void xiic_fill_tx_fifo(struct xiic_i2c *i2c)
+{
+ u8 fifo_space = xiic_tx_fifo_space(i2c);
+ int len = xiic_tx_space(i2c);
+
+ len = (len > fifo_space) ? fifo_space : len;
+
+ dev_dbg(i2c->adap.dev.parent, "%s entry, len: %d, fifo space: %d\n",
+ __func__, len, fifo_space);
+
+ while (len--) {
+ u16 data = i2c->tx_msg->buf[i2c->tx_pos++];
+ if ((xiic_tx_space(i2c) == 0) && (i2c->nmsgs == 1)) {
+ /* last message in transfer -> STOP */
+ data |= XIIC_TX_DYN_STOP_MASK;
+ dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__);
+
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
+ } else
+ xiic_setreg8(i2c, XIIC_DTR_REG_OFFSET, data);
+ }
+}
+
+static void xiic_wakeup(struct xiic_i2c *i2c, int code)
+{
+ i2c->tx_msg = NULL;
+ i2c->rx_msg = NULL;
+ i2c->nmsgs = 0;
+ i2c->state = code;
+ wake_up(&i2c->wait);
+}
+
+static void xiic_process(struct xiic_i2c *i2c)
+{
+ u32 pend, isr, ier;
+ u32 clr = 0;
+
+ /* Get the interrupt Status from the IPIF. There is no clearing of
+ * interrupts in the IPIF. Interrupts must be cleared at the source.
+ * To find which interrupts are pending; AND interrupts pending with
+ * interrupts masked.
+ */
+ isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
+ ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+ pend = isr & ier;
+
+ dev_dbg(i2c->adap.dev.parent, "%s entry, IER: 0x%x, ISR: 0x%x, "
+ "pend: 0x%x, SR: 0x%x, msg: %p, nmsgs: %d\n",
+ __func__, ier, isr, pend, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
+ i2c->tx_msg, i2c->nmsgs);
+
+ /* Do not processes a devices interrupts if the device has no
+ * interrupts pending
+ */
+ if (!pend)
+ return;
+
+ /* Service requesting interrupt */
+ if ((pend & XIIC_INTR_ARB_LOST_MASK) ||
+ ((pend & XIIC_INTR_TX_ERROR_MASK) &&
+ !(pend & XIIC_INTR_RX_FULL_MASK))) {
+ /* bus arbritration lost, or...
+ * Transmit error _OR_ RX completed
+ * if this happens when RX_FULL is not set
+ * this is probably a TX error
+ */
+
+ dev_dbg(i2c->adap.dev.parent, "%s error\n", __func__);
+
+ /* dynamic mode seem to suffer from problems if we just flushes
+ * fifos and the next message is a TX with len 0 (only addr)
+ * reset the IP instead of just flush fifos
+ */
+ xiic_reinit(i2c);
+
+ if (i2c->tx_msg)
+ xiic_wakeup(i2c, STATE_ERROR);
+
+ } else if (pend & XIIC_INTR_RX_FULL_MASK) {
+ /* Receive register/FIFO is full */
+
+ clr = XIIC_INTR_RX_FULL_MASK;
+ if (!i2c->rx_msg) {
+ dev_dbg(i2c->adap.dev.parent,
+ "%s unexpexted RX IRQ\n", __func__);
+ xiic_clear_rx_fifo(i2c);
+ goto out;
+ }
+
+ xiic_read_rx(i2c);
+ if (xiic_rx_space(i2c) == 0) {
+ /* this is the last part of the message */
+ i2c->rx_msg = NULL;
+
+ /* also clear TX error if there (RX complete) */
+ clr |= (isr & XIIC_INTR_TX_ERROR_MASK);
+
+ dev_dbg(i2c->adap.dev.parent,
+ "%s end of message, nmsgs: %d\n",
+ __func__, i2c->nmsgs);
+
+ /* send next message if this wasn't the last,
+ * otherwise the transfer will be finialise when
+ * receiving the bus not busy interrupt
+ */
+ if (i2c->nmsgs > 1) {
+ i2c->nmsgs--;
+ i2c->tx_msg++;
+ dev_dbg(i2c->adap.dev.parent,
+ "%s will start next...\n", __func__);
+
+ __xiic_start_xfer(i2c);
+ }
+ }
+ } else if (pend & XIIC_INTR_BNB_MASK) {
+ /* IIC bus has transitioned to not busy */
+ clr = XIIC_INTR_BNB_MASK;
+
+ /* The bus is not busy, disable BusNotBusy interrupt */
+ xiic_irq_dis(i2c, XIIC_INTR_BNB_MASK);
+
+ if (!i2c->tx_msg)
+ goto out;
+
+ if ((i2c->nmsgs == 1) && !i2c->rx_msg &&
+ xiic_tx_space(i2c) == 0)
+ xiic_wakeup(i2c, STATE_DONE);
+ else
+ xiic_wakeup(i2c, STATE_ERROR);
+
+ } else if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) {
+ /* Transmit register/FIFO is empty or ½ empty */
+
+ clr = pend &
+ (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK);
+
+ if (!i2c->tx_msg) {
+ dev_dbg(i2c->adap.dev.parent,
+ "%s unexpexted TX IRQ\n", __func__);
+ goto out;
+ }
+
+ xiic_fill_tx_fifo(i2c);
+
+ /* current message sent and there is space in the fifo */
+ if (!xiic_tx_space(i2c) && xiic_tx_fifo_space(i2c) >= 2) {
+ dev_dbg(i2c->adap.dev.parent,
+ "%s end of message sent, nmsgs: %d\n",
+ __func__, i2c->nmsgs);
+ if (i2c->nmsgs > 1) {
+ i2c->nmsgs--;
+ i2c->tx_msg++;
+ __xiic_start_xfer(i2c);
+ } else {
+ xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
+
+ dev_dbg(i2c->adap.dev.parent,
+ "%s Got TX IRQ but no more to do...\n",
+ __func__);
+ }
+ } else if (!xiic_tx_space(i2c) && (i2c->nmsgs == 1))
+ /* current frame is sent and is last,
+ * make sure to disable tx half
+ */
+ xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
+ } else {
+ /* got IRQ which is not acked */
+ dev_err(i2c->adap.dev.parent, "%s Got unexpected IRQ\n",
+ __func__);
+ clr = pend;
+ }
+out:
+ dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr);
+
+ xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr);
+}
+
+static int xiic_bus_busy(struct xiic_i2c *i2c)
+{
+ u8 sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET);
+
+ return (sr & XIIC_SR_BUS_BUSY_MASK) ? -EBUSY : 0;
+}
+
+static int xiic_busy(struct xiic_i2c *i2c)
+{
+ int tries = 3;
+ int err;
+
+ if (i2c->tx_msg)
+ return -EBUSY;
+
+ /* for instance if previous transfer was terminated due to TX error
+ * it might be that the bus is on it's way to become available
+ * give it at most 3 ms to wake
+ */
+ err = xiic_bus_busy(i2c);
+ while (err && tries--) {
+ mdelay(1);
+ err = xiic_bus_busy(i2c);
+ }
+
+ return err;
+}
+
+static void xiic_start_recv(struct xiic_i2c *i2c)
+{
+ u8 rx_watermark;
+ struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg;
+
+ /* Clear and enable Rx full interrupt. */
+ xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK);
+
+ /* we want to get all but last byte, because the TX_ERROR IRQ is used
+ * to inidicate error ACK on the address, and negative ack on the last
+ * received byte, so to not mix them receive all but last.
+ * In the case where there is only one byte to receive
+ * we can check if ERROR and RX full is set at the same time
+ */
+ rx_watermark = msg->len;
+ if (rx_watermark > IIC_RX_FIFO_DEPTH)
+ rx_watermark = IIC_RX_FIFO_DEPTH;
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rx_watermark - 1);
+
+ if (!(msg->flags & I2C_M_NOSTART))
+ /* write the address */
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
+ (msg->addr << 1) | XIIC_READ_OPERATION |
+ XIIC_TX_DYN_START_MASK);
+
+ xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
+
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
+ msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0));
+ if (i2c->nmsgs == 1)
+ /* very last, enable bus not busy as well */
+ xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
+
+ /* the message is tx:ed */
+ i2c->tx_pos = msg->len;
+}
+
+static void xiic_start_send(struct xiic_i2c *i2c)
+{
+ struct i2c_msg *msg = i2c->tx_msg;
+
+ xiic_irq_clr(i2c, XIIC_INTR_TX_ERROR_MASK);
+
+ dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d, "
+ "ISR: 0x%x, CR: 0x%x\n",
+ __func__, msg, msg->len, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ /* write the address */
+ u16 data = ((msg->addr << 1) & 0xfe) | XIIC_WRITE_OPERATION |
+ XIIC_TX_DYN_START_MASK;
+ if ((i2c->nmsgs == 1) && msg->len == 0)
+ /* no data and last message -> add STOP */
+ data |= XIIC_TX_DYN_STOP_MASK;
+
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
+ }
+
+ xiic_fill_tx_fifo(i2c);
+
+ /* Clear any pending Tx empty, Tx Error and then enable them. */
+ xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK |
+ XIIC_INTR_BNB_MASK);
+}
+
+static irqreturn_t xiic_isr(int irq, void *dev_id)
+{
+ struct xiic_i2c *i2c = dev_id;
+
+ spin_lock(&i2c->lock);
+ /* disable interrupts globally */
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, 0);
+
+ dev_dbg(i2c->adap.dev.parent, "%s entry\n", __func__);
+
+ xiic_process(i2c);
+
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+ spin_unlock(&i2c->lock);
+
+ return IRQ_HANDLED;
+}
+
+static void __xiic_start_xfer(struct xiic_i2c *i2c)
+{
+ int first = 1;
+ int fifo_space = xiic_tx_fifo_space(i2c);
+ dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, fifos space: %d\n",
+ __func__, i2c->tx_msg, fifo_space);
+
+ if (!i2c->tx_msg)
+ return;
+
+ i2c->rx_pos = 0;
+ i2c->tx_pos = 0;
+ i2c->state = STATE_START;
+ while ((fifo_space >= 2) && (first || (i2c->nmsgs > 1))) {
+ if (!first) {
+ i2c->nmsgs--;
+ i2c->tx_msg++;
+ i2c->tx_pos = 0;
+ } else
+ first = 0;
+
+ if (i2c->tx_msg->flags & I2C_M_RD) {
+ /* we dont date putting several reads in the FIFO */
+ xiic_start_recv(i2c);
+ return;
+ } else {
+ xiic_start_send(i2c);
+ if (xiic_tx_space(i2c) != 0) {
+ /* the message could not be completely sent */
+ break;
+ }
+ }
+
+ fifo_space = xiic_tx_fifo_space(i2c);
+ }
+
+ /* there are more messages or the current one could not be completely
+ * put into the FIFO, also enable the half empty interrupt
+ */
+ if (i2c->nmsgs > 1 || xiic_tx_space(i2c))
+ xiic_irq_clr_en(i2c, XIIC_INTR_TX_HALF_MASK);
+
+}
+
+static void xiic_start_xfer(struct xiic_i2c *i2c)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+ xiic_reinit(i2c);
+ /* disable interrupts globally */
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, 0);
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ __xiic_start_xfer(i2c);
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+}
+
+static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct xiic_i2c *i2c = i2c_get_adapdata(adap);
+ int err;
+
+ dev_dbg(adap->dev.parent, "%s entry SR: 0x%x\n", __func__,
+ xiic_getreg8(i2c, XIIC_SR_REG_OFFSET));
+
+ err = xiic_busy(i2c);
+ if (err)
+ return err;
+
+ i2c->tx_msg = msgs;
+ i2c->nmsgs = num;
+
+ xiic_start_xfer(i2c);
+
+ if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
+ (i2c->state == STATE_DONE), HZ))
+ return (i2c->state == STATE_DONE) ? num : -EIO;
+ else {
+ i2c->tx_msg = NULL;
+ i2c->rx_msg = NULL;
+ i2c->nmsgs = 0;
+ return -ETIMEDOUT;
+ }
+}
+
+static u32 xiic_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm xiic_algorithm = {
+ .master_xfer = xiic_xfer,
+ .functionality = xiic_func,
+};
+
+static struct i2c_adapter xiic_adapter = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &xiic_algorithm,
+};
+
+
+static int __devinit xiic_i2c_probe(struct platform_device *pdev)
+{
+ struct xiic_i2c *i2c;
+ struct xiic_i2c_platform_data *pdata;
+ struct resource *res;
+ int ret, irq;
+ u8 i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ goto resource_missing;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ goto resource_missing;
+
+ pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data;
+ if (!pdata)
+ return -EINVAL;
+
+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "Memory region busy\n");
+ ret = -EBUSY;
+ goto request_mem_failed;
+ }
+
+ i2c->base = ioremap(res->start, resource_size(res));
+ if (!i2c->base) {
+ dev_err(&pdev->dev, "Unable to map registers\n");
+ ret = -EIO;
+ goto map_failed;
+ }
+
+ /* hook up driver to tree */
+ platform_set_drvdata(pdev, i2c);
+ i2c->adap = xiic_adapter;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &pdev->dev;
+
+ xiic_reinit(i2c);
+
+ spin_lock_init(&i2c->lock);
+ init_waitqueue_head(&i2c->wait);
+ ret = request_irq(irq, xiic_isr, 0, pdev->name, i2c);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ goto request_irq_failed;
+ }
+
+ /* add i2c adapter to i2c tree */
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add adapter\n");
+ goto add_adapter_failed;
+ }
+
+ /* add in known devices to the bus */
+ for (i = 0; i < pdata->num_devices; i++)
+ i2c_new_device(&i2c->adap, pdata->devices + i);
+
+ return 0;
+
+add_adapter_failed:
+ free_irq(irq, i2c);
+request_irq_failed:
+ xiic_deinit(i2c);
+ iounmap(i2c->base);
+map_failed:
+ release_mem_region(res->start, resource_size(res));
+request_mem_failed:
+ kfree(i2c);
+
+ return ret;
+resource_missing:
+ dev_err(&pdev->dev, "IRQ or Memory resource is missing\n");
+ return -ENOENT;
+}
+
+static int __devexit xiic_i2c_remove(struct platform_device* pdev)
+{
+ struct xiic_i2c *i2c = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ /* remove adapter & data */
+ i2c_del_adapter(&i2c->adap);
+
+ xiic_deinit(i2c);
+
+ platform_set_drvdata(pdev, NULL);
+
+ free_irq(platform_get_irq(pdev, 0), i2c);
+
+ iounmap(i2c->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(i2c);
+
+ return 0;
+}
+
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:"DRIVER_NAME);
+
+static struct platform_driver xiic_i2c_driver = {
+ .probe = xiic_i2c_probe,
+ .remove = __devexit_p(xiic_i2c_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init xiic_i2c_init(void)
+{
+ return platform_driver_register(&xiic_i2c_driver);
+}
+
+static void __exit xiic_i2c_exit(void)
+{
+ platform_driver_unregister(&xiic_i2c_driver);
+}
+
+module_init(xiic_i2c_init);
+module_exit(xiic_i2c_exit);
+
+MODULE_AUTHOR("info@mocean-labs.com");
+MODULE_DESCRIPTION("Xilinx I2C bus driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
deleted file mode 100644
index ae4539d99bef..000000000000
--- a/drivers/i2c/chips/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# Miscellaneous I2C chip drivers configuration
-#
-# *** DEPRECATED! Do not add new entries! See Makefile ***
-#
-
-menu "Miscellaneous I2C Chip support"
-
-config SENSORS_TSL2550
- tristate "Taos TSL2550 ambient light sensor"
- depends on EXPERIMENTAL
- help
- If you say yes here you get support for the Taos TSL2550
- ambient light sensor.
-
- This driver can also be built as a module. If so, the module
- will be called tsl2550.
-
-endmenu
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
deleted file mode 100644
index fe0af0f81f2d..000000000000
--- a/drivers/i2c/chips/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for miscellaneous I2C chip drivers.
-#
-# Do not add new drivers to this directory! It is DEPRECATED.
-#
-# Device drivers are better grouped according to the functionality they
-# implement rather than to the bus they are connected to. In particular:
-# * Hardware monitoring chip drivers go to drivers/hwmon
-# * RTC chip drivers go to drivers/rtc
-# * I/O expander drivers go to drivers/gpio
-#
-
-obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
-
-ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
-
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 0ac2f90ab840..3202a86f420e 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -34,6 +34,7 @@
#include <linux/hardirq.h>
#include <linux/irqflags.h>
#include <linux/rwsem.h>
+#include <linux/pm_runtime.h>
#include <asm/uaccess.h>
#include "i2c-core.h"
@@ -184,6 +185,52 @@ static int i2c_device_pm_resume(struct device *dev)
#define i2c_device_pm_resume NULL
#endif
+#ifdef CONFIG_PM_RUNTIME
+static int i2c_device_runtime_suspend(struct device *dev)
+{
+ const struct dev_pm_ops *pm;
+
+ if (!dev->driver)
+ return 0;
+ pm = dev->driver->pm;
+ if (!pm || !pm->runtime_suspend)
+ return 0;
+ return pm->runtime_suspend(dev);
+}
+
+static int i2c_device_runtime_resume(struct device *dev)
+{
+ const struct dev_pm_ops *pm;
+
+ if (!dev->driver)
+ return 0;
+ pm = dev->driver->pm;
+ if (!pm || !pm->runtime_resume)
+ return 0;
+ return pm->runtime_resume(dev);
+}
+
+static int i2c_device_runtime_idle(struct device *dev)
+{
+ const struct dev_pm_ops *pm = NULL;
+ int ret;
+
+ if (dev->driver)
+ pm = dev->driver->pm;
+ if (pm && pm->runtime_idle) {
+ ret = pm->runtime_idle(dev);
+ if (ret)
+ return ret;
+ }
+
+ return pm_runtime_suspend(dev);
+}
+#else
+#define i2c_device_runtime_suspend NULL
+#define i2c_device_runtime_resume NULL
+#define i2c_device_runtime_idle NULL
+#endif
+
static int i2c_device_suspend(struct device *dev, pm_message_t mesg)
{
struct i2c_client *client = i2c_verify_client(dev);
@@ -248,9 +295,12 @@ static const struct attribute_group *i2c_dev_attr_groups[] = {
NULL
};
-const static struct dev_pm_ops i2c_device_pm_ops = {
+static const struct dev_pm_ops i2c_device_pm_ops = {
.suspend = i2c_device_pm_suspend,
.resume = i2c_device_pm_resume,
+ .runtime_suspend = i2c_device_runtime_suspend,
+ .runtime_resume = i2c_device_runtime_resume,
+ .runtime_idle = i2c_device_runtime_idle,
};
struct bus_type i2c_bus_type = {
@@ -843,6 +893,9 @@ int i2c_del_adapter(struct i2c_adapter *adap)
adap->dev.parent);
#endif
+ /* device name is gone after device_unregister */
+ dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
+
/* clean up the sysfs representation */
init_completion(&adap->dev_released);
device_unregister(&adap->dev);
@@ -855,8 +908,6 @@ int i2c_del_adapter(struct i2c_adapter *adap)
idr_remove(&i2c_adapter_idr, adap->nr);
mutex_unlock(&core_lock);
- dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
-
/* Clear the device structure in case this adapter is ever going to be
added again */
memset(&adap->dev, 0, sizeof(adap->dev));
@@ -1132,7 +1183,7 @@ EXPORT_SYMBOL(i2c_transfer);
* i2c_master_send - issue a single I2C message in master transmit mode
* @client: Handle to slave device
* @buf: Data that will be written to the slave
- * @count: How many bytes to write
+ * @count: How many bytes to write, must be less than 64k since msg.len is u16
*
* Returns negative errno, or else the number of bytes written.
*/
@@ -1159,7 +1210,7 @@ EXPORT_SYMBOL(i2c_master_send);
* i2c_master_recv - issue a single I2C message in master receive mode
* @client: Handle to slave device
* @buf: Where to store data read from slave
- * @count: How many bytes to read
+ * @count: How many bytes to read, must be less than 64k since msg.len is u16
*
* Returns negative errno, or else the number of bytes read.
*/
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
new file mode 100644
index 000000000000..7a8201ed2181
--- /dev/null
+++ b/drivers/i2c/i2c-smbus.c
@@ -0,0 +1,262 @@
+/*
+ * i2c-smbus.c - SMBus extensions to the I2C protocol
+ *
+ * Copyright (C) 2008 David Brownell
+ * Copyright (C) 2010 Jean Delvare <khali@linux-fr.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.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
+
+struct i2c_smbus_alert {
+ unsigned int alert_edge_triggered:1;
+ int irq;
+ struct work_struct alert;
+ struct i2c_client *ara; /* Alert response address */
+};
+
+struct alert_data {
+ unsigned short addr;
+ u8 flag:1;
+};
+
+/* If this is the alerting device, notify its driver */
+static int smbus_do_alert(struct device *dev, void *addrp)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ struct alert_data *data = addrp;
+
+ if (!client || client->addr != data->addr)
+ return 0;
+ if (client->flags & I2C_CLIENT_TEN)
+ return 0;
+
+ /*
+ * Drivers should either disable alerts, or provide at least
+ * a minimal handler. Lock so client->driver won't change.
+ */
+ device_lock(dev);
+ if (client->driver) {
+ if (client->driver->alert)
+ client->driver->alert(client, data->flag);
+ else
+ dev_warn(&client->dev, "no driver alert()!\n");
+ } else
+ dev_dbg(&client->dev, "alert with no driver\n");
+ device_unlock(dev);
+
+ /* Stop iterating after we find the device */
+ return -EBUSY;
+}
+
+/*
+ * The alert IRQ handler needs to hand work off to a task which can issue
+ * SMBus calls, because those sleeping calls can't be made in IRQ context.
+ */
+static void smbus_alert(struct work_struct *work)
+{
+ struct i2c_smbus_alert *alert;
+ struct i2c_client *ara;
+ unsigned short prev_addr = 0; /* Not a valid address */
+
+ alert = container_of(work, struct i2c_smbus_alert, alert);
+ ara = alert->ara;
+
+ for (;;) {
+ s32 status;
+ struct alert_data data;
+
+ /*
+ * Devices with pending alerts reply in address order, low
+ * to high, because of slave transmit arbitration. After
+ * responding, an SMBus device stops asserting SMBALERT#.
+ *
+ * Note that SMBus 2.0 reserves 10-bit addresess for future
+ * use. We neither handle them, nor try to use PEC here.
+ */
+ status = i2c_smbus_read_byte(ara);
+ if (status < 0)
+ break;
+
+ data.flag = status & 1;
+ data.addr = status >> 1;
+
+ if (data.addr == prev_addr) {
+ dev_warn(&ara->dev, "Duplicate SMBALERT# from dev "
+ "0x%02x, skipping\n", data.addr);
+ break;
+ }
+ dev_dbg(&ara->dev, "SMBALERT# from dev 0x%02x, flag %d\n",
+ data.addr, data.flag);
+
+ /* Notify driver for the device which issued the alert */
+ device_for_each_child(&ara->adapter->dev, &data,
+ smbus_do_alert);
+ prev_addr = data.addr;
+ }
+
+ /* We handled all alerts; re-enable level-triggered IRQs */
+ if (!alert->alert_edge_triggered)
+ enable_irq(alert->irq);
+}
+
+static irqreturn_t smbalert_irq(int irq, void *d)
+{
+ struct i2c_smbus_alert *alert = d;
+
+ /* Disable level-triggered IRQs until we handle them */
+ if (!alert->alert_edge_triggered)
+ disable_irq_nosync(irq);
+
+ schedule_work(&alert->alert);
+ return IRQ_HANDLED;
+}
+
+/* Setup SMBALERT# infrastructure */
+static int smbalert_probe(struct i2c_client *ara,
+ const struct i2c_device_id *id)
+{
+ struct i2c_smbus_alert_setup *setup = ara->dev.platform_data;
+ struct i2c_smbus_alert *alert;
+ struct i2c_adapter *adapter = ara->adapter;
+ int res;
+
+ alert = kzalloc(sizeof(struct i2c_smbus_alert), GFP_KERNEL);
+ if (!alert)
+ return -ENOMEM;
+
+ alert->alert_edge_triggered = setup->alert_edge_triggered;
+ alert->irq = setup->irq;
+ INIT_WORK(&alert->alert, smbus_alert);
+ alert->ara = ara;
+
+ if (setup->irq > 0) {
+ res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq,
+ 0, "smbus_alert", alert);
+ if (res) {
+ kfree(alert);
+ return res;
+ }
+ }
+
+ i2c_set_clientdata(ara, alert);
+ dev_info(&adapter->dev, "supports SMBALERT#, %s trigger\n",
+ setup->alert_edge_triggered ? "edge" : "level");
+
+ return 0;
+}
+
+/* IRQ resource is managed so it is freed automatically */
+static int smbalert_remove(struct i2c_client *ara)
+{
+ struct i2c_smbus_alert *alert = i2c_get_clientdata(ara);
+
+ cancel_work_sync(&alert->alert);
+
+ i2c_set_clientdata(ara, NULL);
+ kfree(alert);
+ return 0;
+}
+
+static const struct i2c_device_id smbalert_ids[] = {
+ { "smbus_alert", 0 },
+ { /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, smbalert_ids);
+
+static struct i2c_driver smbalert_driver = {
+ .driver = {
+ .name = "smbus_alert",
+ },
+ .probe = smbalert_probe,
+ .remove = smbalert_remove,
+ .id_table = smbalert_ids,
+};
+
+/**
+ * i2c_setup_smbus_alert - Setup SMBus alert support
+ * @adapter: the target adapter
+ * @setup: setup data for the SMBus alert handler
+ * Context: can sleep
+ *
+ * Setup handling of the SMBus alert protocol on a given I2C bus segment.
+ *
+ * Handling can be done either through our IRQ handler, or by the
+ * adapter (from its handler, periodic polling, or whatever).
+ *
+ * NOTE that if we manage the IRQ, we *MUST* know if it's level or
+ * edge triggered in order to hand it to the workqueue correctly.
+ * If triggering the alert seems to wedge the system, you probably
+ * should have said it's level triggered.
+ *
+ * This returns the ara client, which should be saved for later use with
+ * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL
+ * to indicate an error.
+ */
+struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
+ struct i2c_smbus_alert_setup *setup)
+{
+ struct i2c_board_info ara_board_info = {
+ I2C_BOARD_INFO("smbus_alert", 0x0c),
+ .platform_data = setup,
+ };
+
+ return i2c_new_device(adapter, &ara_board_info);
+}
+EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert);
+
+/**
+ * i2c_handle_smbus_alert - Handle an SMBus alert
+ * @ara: the ARA client on the relevant adapter
+ * Context: can't sleep
+ *
+ * Helper function to be called from an I2C bus driver's interrupt
+ * handler. It will schedule the alert work, in turn calling the
+ * corresponding I2C device driver's alert function.
+ *
+ * It is assumed that ara is a valid i2c client previously returned by
+ * i2c_setup_smbus_alert().
+ */
+int i2c_handle_smbus_alert(struct i2c_client *ara)
+{
+ struct i2c_smbus_alert *alert = i2c_get_clientdata(ara);
+
+ return schedule_work(&alert->alert);
+}
+EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert);
+
+static int __init i2c_smbus_init(void)
+{
+ return i2c_add_driver(&smbalert_driver);
+}
+
+static void __exit i2c_smbus_exit(void)
+{
+ i2c_del_driver(&smbalert_driver);
+}
+
+module_init(i2c_smbus_init);
+module_exit(i2c_smbus_exit);
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("SMBus protocol extensions support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c
index 878f8ec6dbe1..57d00caefc86 100644
--- a/drivers/ide/aec62xx.c
+++ b/drivers/ide/aec62xx.c
@@ -81,15 +81,15 @@ static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entr
return chipset_table->ultra_settings;
}
-static void aec6210_set_mode(ide_drive_t *drive, const u8 speed)
+static void aec6210_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
struct ide_host *host = pci_get_drvdata(dev);
struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
u16 d_conf = 0;
u8 ultra = 0, ultra_conf = 0;
u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
+ const u8 speed = drive->dma_mode;
unsigned long flags;
local_irq_save(flags);
@@ -109,15 +109,15 @@ static void aec6210_set_mode(ide_drive_t *drive, const u8 speed)
local_irq_restore(flags);
}
-static void aec6260_set_mode(ide_drive_t *drive, const u8 speed)
+static void aec6260_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
struct ide_host *host = pci_get_drvdata(dev);
struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
u8 unit = drive->dn & 1;
u8 tmp1 = 0, tmp2 = 0;
u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
+ const u8 speed = drive->dma_mode;
unsigned long flags;
local_irq_save(flags);
@@ -134,9 +134,10 @@ static void aec6260_set_mode(ide_drive_t *drive, const u8 speed)
local_irq_restore(flags);
}
-static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void aec_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- drive->hwif->port_ops->set_dma_mode(drive, pio + XFER_PIO_0);
+ drive->dma_mode = drive->pio_mode;
+ hwif->port_ops->set_dma_mode(hwif, drive);
}
static int init_chipset_aec62xx(struct pci_dev *dev)
diff --git a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c
index 90da1f953ed0..25b9fe3a9f8e 100644
--- a/drivers/ide/ali14xx.c
+++ b/drivers/ide/ali14xx.c
@@ -109,13 +109,14 @@ static DEFINE_SPINLOCK(ali14xx_lock);
* This function computes timing parameters
* and sets controller registers accordingly.
*/
-static void ali14xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void ali14xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
int driveNum;
int time1, time2;
u8 param1, param2, param3, param4;
unsigned long flags;
int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
/* calculate timing, according to PIO mode */
diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
index 0abc43f3101e..2c8016ad0e26 100644
--- a/drivers/ide/alim15x3.c
+++ b/drivers/ide/alim15x3.c
@@ -8,7 +8,7 @@
* Copyright (C) 2002 Alan Cox
* ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang@ali.com.tw>
* Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
- * Copyright (C) 2007 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
+ * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
*
* (U)DMA capable version of ali 1533/1543(C), 1535(D)
*
@@ -48,61 +48,84 @@ static u8 m5229_revision;
static u8 chip_is_1543c_e;
static struct pci_dev *isa_dev;
+static void ali_fifo_control(ide_hwif_t *hwif, ide_drive_t *drive, int on)
+{
+ struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ int pio_fifo = 0x54 + hwif->channel;
+ u8 fifo;
+ int shift = 4 * (drive->dn & 1);
+
+ pci_read_config_byte(pdev, pio_fifo, &fifo);
+ fifo &= ~(0x0F << shift);
+ fifo |= (on << shift);
+ pci_write_config_byte(pdev, pio_fifo, fifo);
+}
+
+static void ali_program_timings(ide_hwif_t *hwif, ide_drive_t *drive,
+ struct ide_timing *t, u8 ultra)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ int port = hwif->channel ? 0x5c : 0x58;
+ int udmat = 0x56 + hwif->channel;
+ u8 unit = drive->dn & 1, udma;
+ int shift = 4 * unit;
+
+ /* Set up the UDMA */
+ pci_read_config_byte(dev, udmat, &udma);
+ udma &= ~(0x0F << shift);
+ udma |= ultra << shift;
+ pci_write_config_byte(dev, udmat, udma);
+
+ if (t == NULL)
+ return;
+
+ t->setup = clamp_val(t->setup, 1, 8) & 7;
+ t->act8b = clamp_val(t->act8b, 1, 8) & 7;
+ t->rec8b = clamp_val(t->rec8b, 1, 16) & 15;
+ t->active = clamp_val(t->active, 1, 8) & 7;
+ t->recover = clamp_val(t->recover, 1, 16) & 15;
+
+ pci_write_config_byte(dev, port, t->setup);
+ pci_write_config_byte(dev, port + 1, (t->act8b << 4) | t->rec8b);
+ pci_write_config_byte(dev, port + unit + 2,
+ (t->active << 4) | t->recover);
+}
+
/**
* ali_set_pio_mode - set host controller for PIO mode
+ * @hwif: port
* @drive: drive
- * @pio: PIO mode number
*
* Program the controller for the given PIO mode.
*/
-static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void ali_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
- int s_time = t->setup, a_time = t->active, c_time = t->cycle;
- u8 s_clc, a_clc, r_clc;
- unsigned long flags;
+ ide_drive_t *pair = ide_get_pair_dev(drive);
int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
- int port = hwif->channel ? 0x5c : 0x58;
- int portFIFO = hwif->channel ? 0x55 : 0x54;
- u8 cd_dma_fifo = 0, unit = drive->dn & 1;
-
- if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
- s_clc = 0;
- if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
- a_clc = 0;
-
- if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
- r_clc = 1;
- } else {
- if (r_clc >= 16)
- r_clc = 0;
+ unsigned long T = 1000000 / bus_speed; /* PCI clock based */
+ struct ide_timing t;
+
+ ide_timing_compute(drive, drive->pio_mode, &t, T, 1);
+ if (pair) {
+ struct ide_timing p;
+
+ ide_timing_compute(pair, pair->pio_mode, &p, T, 1);
+ ide_timing_merge(&p, &t, &t,
+ IDE_TIMING_SETUP | IDE_TIMING_8BIT);
+ if (pair->dma_mode) {
+ ide_timing_compute(pair, pair->dma_mode, &p, T, 1);
+ ide_timing_merge(&p, &t, &t,
+ IDE_TIMING_SETUP | IDE_TIMING_8BIT);
+ }
}
- local_irq_save(flags);
-
+
/*
* PIO mode => ATA FIFO on, ATAPI FIFO off
*/
- pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
- if (drive->media==ide_disk) {
- if (unit) {
- pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50);
- } else {
- pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05);
- }
- } else {
- if (unit) {
- pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F);
- } else {
- pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0);
- }
- }
-
- pci_write_config_byte(dev, port, s_clc);
- pci_write_config_byte(dev, port + unit + 2, (a_clc << 4) | r_clc);
- local_irq_restore(flags);
+ ali_fifo_control(hwif, drive, (drive->media == ide_disk) ? 0x05 : 0x00);
+
+ ali_program_timings(hwif, drive, &t, 0);
}
/**
@@ -132,44 +155,42 @@ static u8 ali_udma_filter(ide_drive_t *drive)
/**
* ali_set_dma_mode - set host controller for DMA mode
+ * @hwif: port
* @drive: drive
- * @speed: DMA mode
*
* Configure the hardware for the desired IDE transfer mode.
*/
-static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void ali_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
+ static u8 udma_timing[7] = { 0xC, 0xB, 0xA, 0x9, 0x8, 0xF, 0xD };
struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 speed1 = speed;
- u8 unit = drive->dn & 1;
+ ide_drive_t *pair = ide_get_pair_dev(drive);
+ int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
+ unsigned long T = 1000000 / bus_speed; /* PCI clock based */
+ const u8 speed = drive->dma_mode;
u8 tmpbyte = 0x00;
- int m5229_udma = (hwif->channel) ? 0x57 : 0x56;
-
- if (speed == XFER_UDMA_6)
- speed1 = 0x47;
+ struct ide_timing t;
if (speed < XFER_UDMA_0) {
- u8 ultra_enable = (unit) ? 0x7f : 0xf7;
- /*
- * clear "ultra enable" bit
- */
- pci_read_config_byte(dev, m5229_udma, &tmpbyte);
- tmpbyte &= ultra_enable;
- pci_write_config_byte(dev, m5229_udma, tmpbyte);
-
- /*
- * FIXME: Oh, my... DMA timings are never set.
- */
+ ide_timing_compute(drive, drive->dma_mode, &t, T, 1);
+ if (pair) {
+ struct ide_timing p;
+
+ ide_timing_compute(pair, pair->pio_mode, &p, T, 1);
+ ide_timing_merge(&p, &t, &t,
+ IDE_TIMING_SETUP | IDE_TIMING_8BIT);
+ if (pair->dma_mode) {
+ ide_timing_compute(pair, pair->dma_mode,
+ &p, T, 1);
+ ide_timing_merge(&p, &t, &t,
+ IDE_TIMING_SETUP | IDE_TIMING_8BIT);
+ }
+ }
+ ali_program_timings(hwif, drive, &t, 0);
} else {
- pci_read_config_byte(dev, m5229_udma, &tmpbyte);
- tmpbyte &= (0x0f << ((1-unit) << 2));
- /*
- * enable ultra dma and set timing
- */
- tmpbyte |= ((0x08 | ((4-speed1)&0x07)) << (unit << 2));
- pci_write_config_byte(dev, m5229_udma, tmpbyte);
+ ali_program_timings(hwif, drive, NULL,
+ udma_timing[speed - XFER_UDMA_0]);
if (speed >= XFER_UDMA_3) {
pci_read_config_byte(dev, 0x4b, &tmpbyte);
tmpbyte |= 1;
@@ -355,19 +376,13 @@ static int ali_cable_override(struct pci_dev *pdev)
*
* This checks if the controller and the cable are capable
* of UDMA66 transfers. It doesn't check the drives.
- * But see note 2 below!
- *
- * FIXME: frobs bits that are not defined on newer ALi devicea
*/
static u8 ali_cable_detect(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long flags;
u8 cbl = ATA_CBL_PATA40, tmpbyte;
- local_irq_save(flags);
-
if (m5229_revision >= 0xC2) {
/*
* m5229 80-pin cable detection (from Host View)
@@ -387,8 +402,6 @@ static u8 ali_cable_detect(ide_hwif_t *hwif)
}
}
- local_irq_restore(flags);
-
return cbl;
}
@@ -584,6 +597,6 @@ static void __exit ali15x3_ide_exit(void)
module_init(ali15x3_ide_init);
module_exit(ali15x3_ide_exit);
-MODULE_AUTHOR("Michael Aubry, Andrzej Krzysztofowicz, CJ, Andre Hedrick, Alan Cox");
+MODULE_AUTHOR("Michael Aubry, Andrzej Krzysztofowicz, CJ, Andre Hedrick, Alan Cox, Bartlomiej Zolnierkiewicz");
MODULE_DESCRIPTION("PCI driver module for ALi 15x3 IDE");
MODULE_LICENSE("GPL");
diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
index 628cd2e5fed8..3747b2561f09 100644
--- a/drivers/ide/amd74xx.c
+++ b/drivers/ide/amd74xx.c
@@ -3,7 +3,7 @@
* IDE driver for Linux.
*
* Copyright (c) 2000-2002 Vojtech Pavlik
- * Copyright (c) 2007-2008 Bartlomiej Zolnierkiewicz
+ * Copyright (c) 2007-2010 Bartlomiej Zolnierkiewicz
*
* Based on the work of:
* Andre Hedrick
@@ -70,7 +70,8 @@ static void amd_set_speed(struct pci_dev *dev, u8 dn, u8 udma_mask,
default: return;
}
- pci_write_config_byte(dev, AMD_UDMA_TIMING + offset + (3 - dn), t);
+ if (timing->udma)
+ pci_write_config_byte(dev, AMD_UDMA_TIMING + offset + 3 - dn, t);
}
/*
@@ -78,14 +79,14 @@ static void amd_set_speed(struct pci_dev *dev, u8 dn, u8 udma_mask,
* to a desired transfer mode. It also can be called by upper layers.
*/
-static void amd_set_drive(ide_drive_t *drive, const u8 speed)
+static void amd_set_drive(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
ide_drive_t *peer = ide_get_pair_dev(drive);
struct ide_timing t, p;
int T, UT;
u8 udma_mask = hwif->ultra_mask;
+ const u8 speed = drive->dma_mode;
T = 1000000000 / amd_clock;
UT = (udma_mask == ATA_UDMA2) ? T : (T / 2);
@@ -93,7 +94,7 @@ static void amd_set_drive(ide_drive_t *drive, const u8 speed)
ide_timing_compute(drive, speed, &t, T, UT);
if (peer) {
- ide_timing_compute(peer, peer->current_speed, &p, T, UT);
+ ide_timing_compute(peer, peer->pio_mode, &p, T, UT);
ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
}
@@ -107,9 +108,10 @@ static void amd_set_drive(ide_drive_t *drive, const u8 speed)
* amd_set_pio_mode() is a callback from upper layers for PIO-only tuning.
*/
-static void amd_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void amd_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- amd_set_drive(drive, XFER_PIO_0 + pio);
+ drive->dma_mode = drive->pio_mode;
+ amd_set_drive(hwif, drive);
}
static void amd7409_cable_detect(struct pci_dev *dev)
@@ -340,6 +342,6 @@ static void __exit amd74xx_ide_exit(void)
module_init(amd74xx_ide_init);
module_exit(amd74xx_ide_exit);
-MODULE_AUTHOR("Vojtech Pavlik");
+MODULE_AUTHOR("Vojtech Pavlik, Bartlomiej Zolnierkiewicz");
MODULE_DESCRIPTION("AMD PCI IDE driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/ide/at91_ide.c b/drivers/ide/at91_ide.c
index 248219a89a68..000a78e5246c 100644
--- a/drivers/ide/at91_ide.c
+++ b/drivers/ide/at91_ide.c
@@ -172,11 +172,12 @@ static void at91_ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
leave_16bit(chipselect, mode);
}
-static void at91_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void at91_ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
struct ide_timing *timing;
- u8 chipselect = drive->hwif->select_data;
+ u8 chipselect = hwif->select_data;
int use_iordy = 0;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
pdbg("chipselect %u pio %u\n", chipselect, pio);
diff --git a/drivers/ide/atiixp.c b/drivers/ide/atiixp.c
index 837322b10a4c..15f0ead89f5c 100644
--- a/drivers/ide/atiixp.c
+++ b/drivers/ide/atiixp.c
@@ -42,19 +42,20 @@ static DEFINE_SPINLOCK(atiixp_lock);
/**
* atiixp_set_pio_mode - set host controller for PIO mode
+ * @hwif: port
* @drive: drive
- * @pio: PIO mode number
*
* Set the interface PIO mode.
*/
-static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void atiixp_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
unsigned long flags;
int timing_shift = (drive->dn ^ 1) * 8;
u32 pio_timing_data;
u16 pio_mode_data;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
spin_lock_irqsave(&atiixp_lock, flags);
@@ -74,21 +75,22 @@ static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
/**
* atiixp_set_dma_mode - set host controller for DMA mode
+ * @hwif: port
* @drive: drive
- * @speed: DMA mode
*
* Set a ATIIXP host controller to the desired DMA mode. This involves
* programming the right timing data into the PCI configuration space.
*/
-static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void atiixp_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
unsigned long flags;
int timing_shift = (drive->dn ^ 1) * 8;
u32 tmp32;
u16 tmp16;
u16 udma_ctl = 0;
+ const u8 speed = drive->dma_mode;
spin_lock_irqsave(&atiixp_lock, flags);
diff --git a/drivers/ide/au1xxx-ide.c b/drivers/ide/au1xxx-ide.c
index 87cef0c440ad..b26c23416fa7 100644
--- a/drivers/ide/au1xxx-ide.c
+++ b/drivers/ide/au1xxx-ide.c
@@ -56,8 +56,8 @@ static inline void auide_insw(unsigned long port, void *addr, u32 count)
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
- if(!put_dest_flags(ahwif->rx_chan, (void*)addr, count << 1,
- DDMA_FLAGS_NOIE)) {
+ if (!au1xxx_dbdma_put_dest(ahwif->rx_chan, virt_to_phys(addr),
+ count << 1, DDMA_FLAGS_NOIE)) {
printk(KERN_ERR "%s failed %d\n", __func__, __LINE__);
return;
}
@@ -74,8 +74,8 @@ static inline void auide_outsw(unsigned long port, void *addr, u32 count)
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
- if(!put_source_flags(ahwif->tx_chan, (void*)addr,
- count << 1, DDMA_FLAGS_NOIE)) {
+ if (!au1xxx_dbdma_put_source(ahwif->tx_chan, virt_to_phys(addr),
+ count << 1, DDMA_FLAGS_NOIE)) {
printk(KERN_ERR "%s failed %d\n", __func__, __LINE__);
return;
}
@@ -99,12 +99,11 @@ static void au1xxx_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
}
#endif
-static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void au1xxx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
- /* set pio mode! */
- switch(pio) {
+ switch (drive->pio_mode - XFER_PIO_0) {
case 0:
mem_sttime = SBC_IDE_TIMING(PIO0);
@@ -161,11 +160,11 @@ static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio)
au_writel(mem_stcfg,MEM_STCFG2);
}
-static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void auide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
- switch(speed) {
+ switch (drive->dma_mode) {
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
case XFER_MW_DMA_2:
mem_sttime = SBC_IDE_TIMING(MDMA2);
@@ -246,17 +245,14 @@ static int auide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
flags = DDMA_FLAGS_NOIE;
if (iswrite) {
- if(!put_source_flags(ahwif->tx_chan,
- (void*) sg_virt(sg),
- tc, flags)) {
+ if (!au1xxx_dbdma_put_source(ahwif->tx_chan,
+ sg_phys(sg), tc, flags)) {
printk(KERN_ERR "%s failed %d\n",
__func__, __LINE__);
}
- } else
- {
- if(!put_dest_flags(ahwif->rx_chan,
- (void*) sg_virt(sg),
- tc, flags)) {
+ } else {
+ if (!au1xxx_dbdma_put_dest(ahwif->rx_chan,
+ sg_phys(sg), tc, flags)) {
printk(KERN_ERR "%s failed %d\n",
__func__, __LINE__);
}
@@ -300,8 +296,8 @@ static int auide_dma_test_irq(ide_drive_t *drive)
*/
drive->waiting_for_dma++;
if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
- printk(KERN_WARNING "%s: timeout waiting for ddma to \
- complete\n", drive->name);
+ printk(KERN_WARNING "%s: timeout waiting for ddma to complete\n",
+ drive->name);
return 1;
}
udelay(10);
diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c
index 1a32d62ed86b..d2b8b272bc27 100644
--- a/drivers/ide/cmd640.c
+++ b/drivers/ide/cmd640.c
@@ -572,9 +572,10 @@ static void cmd640_set_mode(ide_drive_t *drive, unsigned int index,
program_drive_counts(drive, index);
}
-static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void cmd640_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
unsigned int index = 0, cycle_time;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
u8 b;
switch (pio) {
@@ -605,7 +606,7 @@ static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio)
}
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-static void cmd640_init_dev(ide_drive_t *drive)
+static void __init cmd640_init_dev(ide_drive_t *drive)
{
unsigned int i = drive->hwif->channel * 2 + (drive->dn & 1);
diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
index f2500c8826bb..5f80312e636b 100644
--- a/drivers/ide/cmd64x.c
+++ b/drivers/ide/cmd64x.c
@@ -7,6 +7,7 @@
* Copyright (C) 1998 David S. Miller (davem@redhat.com)
*
* Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
* Copyright (C) 2007,2009 MontaVista Software, Inc. <source@mvista.com>
*/
@@ -50,72 +51,42 @@
#define UDIDETCR1 0x7B
#define DTPR1 0x7C
-static u8 quantize_timing(int timing, int quant)
-{
- return (timing + quant - 1) / quant;
-}
-
-/*
- * This routine calculates active/recovery counts and then writes them into
- * the chipset registers.
- */
-static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time)
+static void cmd64x_program_timings(ide_drive_t *drive, u8 mode)
{
+ ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- int clock_time = 1000 / (ide_pci_clk ? ide_pci_clk : 33);
- u8 cycle_count, active_count, recovery_count, drwtim;
+ int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
+ const unsigned long T = 1000000 / bus_speed;
static const u8 recovery_values[] =
{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
+ static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
+ static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3};
+ struct ide_timing t;
+ u8 arttim = 0;
- cycle_count = quantize_timing( cycle_time, clock_time);
- active_count = quantize_timing(active_time, clock_time);
- recovery_count = cycle_count - active_count;
+ ide_timing_compute(drive, mode, &t, T, 0);
/*
* In case we've got too long recovery phase, try to lengthen
* the active phase
*/
- if (recovery_count > 16) {
- active_count += recovery_count - 16;
- recovery_count = 16;
+ if (t.recover > 16) {
+ t.active += t.recover - 16;
+ t.recover = 16;
}
- if (active_count > 16) /* shouldn't actually happen... */
- active_count = 16;
+ if (t.active > 16) /* shouldn't actually happen... */
+ t.active = 16;
/*
* Convert values to internal chipset representation
*/
- recovery_count = recovery_values[recovery_count];
- active_count &= 0x0f;
+ t.recover = recovery_values[t.recover];
+ t.active &= 0x0f;
/* Program the active/recovery counts into the DRWTIM register */
- drwtim = (active_count << 4) | recovery_count;
- (void) pci_write_config_byte(dev, drwtim_regs[drive->dn], drwtim);
-}
-
-/*
- * This routine writes into the chipset registers
- * PIO setup/active/recovery timings.
- */
-static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
- unsigned long setup_count;
- unsigned int cycle_time;
- u8 arttim = 0;
-
- static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
- static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
-
- cycle_time = ide_pio_cycle_time(drive, pio);
-
- program_cycle_times(drive, cycle_time, t->active);
-
- setup_count = quantize_timing(t->setup,
- 1000 / (ide_pci_clk ? ide_pci_clk : 33));
+ pci_write_config_byte(dev, drwtim_regs[drive->dn],
+ (t.active << 4) | t.recover);
/*
* The primary channel has individual address setup timing registers
@@ -126,15 +97,21 @@ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
if (hwif->channel) {
ide_drive_t *pair = ide_get_pair_dev(drive);
- ide_set_drivedata(drive, (void *)setup_count);
+ if (pair) {
+ struct ide_timing tp;
- if (pair)
- setup_count = max_t(u8, setup_count,
- (unsigned long)ide_get_drivedata(pair));
+ ide_timing_compute(pair, pair->pio_mode, &tp, T, 0);
+ ide_timing_merge(&t, &tp, &t, IDE_TIMING_SETUP);
+ if (pair->dma_mode) {
+ ide_timing_compute(pair, pair->dma_mode,
+ &tp, T, 0);
+ ide_timing_merge(&tp, &t, &t, IDE_TIMING_SETUP);
+ }
+ }
}
- if (setup_count > 5) /* shouldn't actually happen... */
- setup_count = 5;
+ if (t.setup > 5) /* shouldn't actually happen... */
+ t.setup = 5;
/*
* Program the address setup clocks into the ARTTIM registers.
@@ -144,7 +121,7 @@ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
if (hwif->channel)
arttim &= ~ARTTIM23_INTR_CH1;
arttim &= ~0xc0;
- arttim |= setup_values[setup_count];
+ arttim |= setup_values[t.setup];
(void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
}
@@ -153,8 +130,10 @@ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
* Special cases are 8: prefetch off, 9: prefetch on (both never worked)
*/
-static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void cmd64x_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
+
/*
* Filter out the prefetch control values
* to prevent PIO5 from being programmed
@@ -162,20 +141,18 @@ static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio)
if (pio == 8 || pio == 9)
return;
- cmd64x_tune_pio(drive, pio);
+ cmd64x_program_timings(drive, XFER_PIO_0 + pio);
}
-static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void cmd64x_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
u8 unit = drive->dn & 0x01;
u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0;
+ const u8 speed = drive->dma_mode;
- if (speed >= XFER_SW_DMA_0) {
- (void) pci_read_config_byte(dev, pciU, &regU);
- regU &= ~(unit ? 0xCA : 0x35);
- }
+ pci_read_config_byte(dev, pciU, &regU);
+ regU &= ~(unit ? 0xCA : 0x35);
switch(speed) {
case XFER_UDMA_5:
@@ -197,18 +174,13 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
regU |= unit ? 0xC2 : 0x31;
break;
case XFER_MW_DMA_2:
- program_cycle_times(drive, 120, 70);
- break;
case XFER_MW_DMA_1:
- program_cycle_times(drive, 150, 80);
- break;
case XFER_MW_DMA_0:
- program_cycle_times(drive, 480, 215);
+ cmd64x_program_timings(drive, speed);
break;
}
- if (speed >= XFER_SW_DMA_0)
- (void) pci_write_config_byte(dev, pciU, regU);
+ pci_write_config_byte(dev, pciU, regU);
}
static void cmd648_clear_irq(ide_drive_t *drive)
@@ -471,6 +443,6 @@ static void __exit cmd64x_ide_exit(void)
module_init(cmd64x_ide_init);
module_exit(cmd64x_ide_exit);
-MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick");
+MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick, Bartlomiej Zolnierkiewicz");
MODULE_DESCRIPTION("PCI driver module for CMD64x IDE");
MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cs5520.c b/drivers/ide/cs5520.c
index 09f98ed0731f..2c1e5f7cd261 100644
--- a/drivers/ide/cs5520.c
+++ b/drivers/ide/cs5520.c
@@ -57,11 +57,11 @@ static struct pio_clocks cs5520_pio_clocks[]={
{1, 2, 1}
};
-static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void cs5520_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *pdev = to_pci_dev(hwif->dev);
int controller = drive->dn > 1 ? 1 : 0;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
/* 8bit CAT/CRT - 8bit command timing for channel */
pci_write_config_byte(pdev, 0x62 + controller,
@@ -81,11 +81,12 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
(cs5520_pio_clocks[pio].assert));
}
-static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void cs5520_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
printk(KERN_ERR "cs55x0: bad ide timing.\n");
- cs5520_set_pio_mode(drive, 0);
+ drive->pio_mode = XFER_PIO_0 + 0;
+ cs5520_set_pio_mode(hwif, drive);
}
static const struct ide_port_ops cs5520_port_ops = {
diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
index 40bf05eddf6e..4dc4eb92b076 100644
--- a/drivers/ide/cs5530.c
+++ b/drivers/ide/cs5530.c
@@ -41,8 +41,8 @@ static unsigned int cs5530_pio_timings[2][5] = {
/**
* cs5530_set_pio_mode - set host controller for PIO mode
+ * @hwif: port
* @drive: drive
- * @pio: PIO mode number
*
* Handles setting of PIO mode for the chipset.
*
@@ -50,10 +50,11 @@ static unsigned int cs5530_pio_timings[2][5] = {
* will have valid default PIO timings set up before we get here.
*/
-static void cs5530_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void cs5530_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- unsigned long basereg = CS5530_BASEREG(drive->hwif);
+ unsigned long basereg = CS5530_BASEREG(hwif);
unsigned int format = (inl(basereg + 4) >> 31) & 1;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3));
}
@@ -99,12 +100,12 @@ out:
return mask;
}
-static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
+static void cs5530_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
unsigned long basereg;
unsigned int reg, timings = 0;
- switch (mode) {
+ switch (drive->dma_mode) {
case XFER_UDMA_0: timings = 0x00921250; break;
case XFER_UDMA_1: timings = 0x00911140; break;
case XFER_UDMA_2: timings = 0x00911030; break;
@@ -112,7 +113,7 @@ static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
case XFER_MW_DMA_1: timings = 0x00012121; break;
case XFER_MW_DMA_2: timings = 0x00002020; break;
}
- basereg = CS5530_BASEREG(drive->hwif);
+ basereg = CS5530_BASEREG(hwif);
reg = inl(basereg + 4); /* get drive0 config register */
timings |= reg & 0x80000000; /* preserve PIO format bit */
if ((drive-> dn & 1) == 0) { /* are we configuring drive0? */
diff --git a/drivers/ide/cs5535.c b/drivers/ide/cs5535.c
index b883838adc24..5059fafadf29 100644
--- a/drivers/ide/cs5535.c
+++ b/drivers/ide/cs5535.c
@@ -86,7 +86,7 @@ static void cs5535_set_speed(ide_drive_t *drive, const u8 speed)
cmd = pioa = speed - XFER_PIO_0;
if (pair) {
- u8 piob = ide_get_best_pio_mode(pair, 255, 4);
+ u8 piob = pair->pio_mode - XFER_PIO_0;
if (piob < cmd)
cmd = piob;
@@ -129,28 +129,28 @@ static void cs5535_set_speed(ide_drive_t *drive, const u8 speed)
/**
* cs5535_set_dma_mode - set host controller for DMA mode
+ * @hwif: port
* @drive: drive
- * @speed: DMA mode
*
* Programs the chipset for DMA mode.
*/
-static void cs5535_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void cs5535_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- cs5535_set_speed(drive, speed);
+ cs5535_set_speed(drive, drive->dma_mode);
}
/**
* cs5535_set_pio_mode - set host controller for PIO mode
+ * @hwif: port
* @drive: drive
- * @pio: PIO mode number
*
* A callback from the upper layers for PIO-only tuning.
*/
-static void cs5535_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void cs5535_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- cs5535_set_speed(drive, XFER_PIO_0 + pio);
+ cs5535_set_speed(drive, drive->pio_mode);
}
static u8 cs5535_cable_detect(ide_hwif_t *hwif)
diff --git a/drivers/ide/cs5536.c b/drivers/ide/cs5536.c
index 9623b852c616..24214ab60ac0 100644
--- a/drivers/ide/cs5536.c
+++ b/drivers/ide/cs5536.c
@@ -125,11 +125,11 @@ static u8 cs5536_cable_detect(ide_hwif_t *hwif)
/**
* cs5536_set_pio_mode - PIO timing setup
+ * @hwif: ATA port
* @drive: ATA device
- * @pio: PIO mode number
*/
-static void cs5536_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void cs5536_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
static const u8 drv_timings[5] = {
0x98, 0x55, 0x32, 0x21, 0x20,
@@ -143,15 +143,16 @@ static void cs5536_set_pio_mode(ide_drive_t *drive, const u8 pio)
0x99, 0x92, 0x90, 0x22, 0x20,
};
- struct pci_dev *pdev = to_pci_dev(drive->hwif->dev);
+ struct pci_dev *pdev = to_pci_dev(hwif->dev);
ide_drive_t *pair = ide_get_pair_dev(drive);
int cshift = (drive->dn & 1) ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;
unsigned long timings = (unsigned long)ide_get_drivedata(drive);
u32 cast;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
u8 cmd_pio = pio;
if (pair)
- cmd_pio = min(pio, ide_get_best_pio_mode(pair, 255, 4));
+ cmd_pio = min_t(u8, pio, pair->pio_mode - XFER_PIO_0);
timings &= (IDE_DRV_MASK << 8);
timings |= drv_timings[pio];
@@ -172,11 +173,11 @@ static void cs5536_set_pio_mode(ide_drive_t *drive, const u8 pio)
/**
* cs5536_set_dma_mode - DMA timing setup
+ * @hwif: ATA port
* @drive: ATA device
- * @mode: DMA mode
*/
-static void cs5536_set_dma_mode(ide_drive_t *drive, const u8 mode)
+static void cs5536_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
static const u8 udma_timings[6] = {
0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6,
@@ -186,10 +187,11 @@ static void cs5536_set_dma_mode(ide_drive_t *drive, const u8 mode)
0x67, 0x21, 0x20,
};
- struct pci_dev *pdev = to_pci_dev(drive->hwif->dev);
+ struct pci_dev *pdev = to_pci_dev(hwif->dev);
int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT;
unsigned long timings = (unsigned long)ide_get_drivedata(drive);
u32 etc;
+ const u8 mode = drive->dma_mode;
cs5536_read(pdev, ETC, &etc);
diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
index d6e2cbbc53a0..9383f67deae1 100644
--- a/drivers/ide/cy82c693.c
+++ b/drivers/ide/cy82c693.c
@@ -1,43 +1,11 @@
/*
* Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
* Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator
+ * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
*
* CYPRESS CY82C693 chipset IDE controller
*
* The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
- * Writing the driver was quite simple, since most of the job is
- * done by the generic pci-ide support.
- * The hard part was finding the CY82C693's datasheet on Cypress's
- * web page :-(. But Altavista solved this problem :-).
- *
- *
- * Notes:
- * - I recently got a 16.8G IBM DTTA, so I was able to test it with
- * a large and fast disk - the results look great, so I'd say the
- * driver is working fine :-)
- * hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA
- * - this is my first linux driver, so there's probably a lot of room
- * for optimizations and bug fixing, so feel free to do it.
- * - if using PIO mode it's a good idea to set the PIO mode and
- * 32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda
- * - I had some problems with my IBM DHEA with PIO modes < 2
- * (lost interrupts) ?????
- * - first tests with DMA look okay, they seem to work, but there is a
- * problem with sound - the BusMaster IDE TimeOut should fixed this
- *
- * Ancient History:
- * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693
- * ASK@1999-01-23: v0.33 made a few minor code clean ups
- * removed DMA clock speed setting by default
- * added boot message
- * ASK@1998-11-01: v0.32 added support to set BusMaster IDE TimeOut
- * added support to set DMA Controller Clock Speed
- * ASK@1998-10-31: v0.31 fixed problem with setting to high DMA modes
- * on some drives.
- * ASK@1998-10-29: v0.3 added support to set DMA modes
- * ASK@1998-10-28: v0.2 added support to set PIO modes
- * ASK@1998-10-27: v0.1 first version - chipset detection
- *
*/
#include <linux/module.h>
@@ -81,87 +49,13 @@
#define CY82_INDEX_CHANNEL1 0x31
#define CY82_INDEX_TIMEOUT 0x32
-/* the min and max PCI bus speed in MHz - from datasheet */
-#define CY82C963_MIN_BUS_SPEED 25
-#define CY82C963_MAX_BUS_SPEED 33
-
-/* the struct for the PIO mode timings */
-typedef struct pio_clocks_s {
- u8 address_time; /* Address setup (clocks) */
- u8 time_16r; /* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */
- u8 time_16w; /* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */
- u8 time_8; /* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */
-} pio_clocks_t;
-
-/*
- * calc clocks using bus_speed
- * returns (rounded up) time in bus clocks for time in ns
- */
-static int calc_clk(int time, int bus_speed)
-{
- int clocks;
-
- clocks = (time*bus_speed+999)/1000 - 1;
-
- if (clocks < 0)
- clocks = 0;
-
- if (clocks > 0x0F)
- clocks = 0x0F;
-
- return clocks;
-}
-
-/*
- * compute the values for the clock registers for PIO
- * mode and pci_clk [MHz] speed
- *
- * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used
- * for mode 3 and 4 drives 8 and 16-bit timings are the same
- *
- */
-static void compute_clocks(u8 pio, pio_clocks_t *p_pclk)
-{
- struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
- int clk1, clk2;
- int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
-
- /* we don't check against CY82C693's min and max speed,
- * so you can play with the idebus=xx parameter
- */
-
- /* let's calc the address setup time clocks */
- p_pclk->address_time = (u8)calc_clk(t->setup, bus_speed);
-
- /* let's calc the active and recovery time clocks */
- clk1 = calc_clk(t->active, bus_speed);
-
- /* calc recovery timing */
- clk2 = t->cycle - t->active - t->setup;
-
- clk2 = calc_clk(clk2, bus_speed);
-
- clk1 = (clk1<<4)|clk2; /* combine active and recovery clocks */
-
- /* note: we use the same values for 16bit IOR and IOW
- * those are all the same, since I don't have other
- * timings than those from ide-lib.c
- */
-
- p_pclk->time_16r = (u8)clk1;
- p_pclk->time_16w = (u8)clk1;
-
- /* what are good values for 8bit ?? */
- p_pclk->time_8 = (u8)clk1;
-}
-
/*
* set DMA mode a specific channel for CY82C693
*/
-static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
+static void cy82c693_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
+ const u8 mode = drive->dma_mode;
u8 single = (mode & 0x10) >> 4, index = 0, data = 0;
index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0;
@@ -186,12 +80,14 @@ static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
outb(data, CY82_DATA_PORT);
}
-static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
- pio_clocks_t pclk;
+ int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
+ const unsigned long T = 1000000 / bus_speed;
unsigned int addrCtrl;
+ struct ide_timing t;
+ u8 time_16, time_8;
/* select primary or secondary channel */
if (hwif->index > 0) { /* drive is on the secondary channel */
@@ -204,8 +100,12 @@ static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
}
}
- /* let's calc the values for this PIO mode */
- compute_clocks(pio, &pclk);
+ ide_timing_compute(drive, drive->pio_mode, &t, T, 1);
+
+ time_16 = clamp_val(t.recover - 1, 0, 15) |
+ (clamp_val(t.active - 1, 0, 15) << 4);
+ time_8 = clamp_val(t.act8b - 1, 0, 15) |
+ (clamp_val(t.rec8b - 1, 0, 15) << 4);
/* now let's write the clocks registers */
if ((drive->dn & 1) == 0) {
@@ -217,13 +117,13 @@ static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
addrCtrl &= (~0xF);
- addrCtrl |= (unsigned int)pclk.address_time;
+ addrCtrl |= clamp_val(t.setup - 1, 0, 15);
pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
/* now let's set the remaining registers */
- pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
- pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
- pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
+ pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, time_16);
+ pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, time_16);
+ pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, time_8);
} else {
/*
* set slave drive
@@ -233,13 +133,13 @@ static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
addrCtrl &= (~0xF0);
- addrCtrl |= ((unsigned int)pclk.address_time<<4);
+ addrCtrl |= (clamp_val(t.setup - 1, 0, 15) << 4);
pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
/* now let's set the remaining registers */
- pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r);
- pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w);
- pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8);
+ pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, time_16);
+ pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, time_16);
+ pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, time_8);
}
}
@@ -325,6 +225,6 @@ static void __exit cy82c693_ide_exit(void)
module_init(cy82c693_ide_init);
module_exit(cy82c693_ide_exit);
-MODULE_AUTHOR("Andreas Krebs, Andre Hedrick");
+MODULE_AUTHOR("Andreas Krebs, Andre Hedrick, Bartlomiej Zolnierkiewicz");
MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE");
MODULE_LICENSE("GPL");
diff --git a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c
index c6b138122981..6929f7fce93a 100644
--- a/drivers/ide/dtc2278.c
+++ b/drivers/ide/dtc2278.c
@@ -68,11 +68,11 @@ static void sub22 (char b, char c)
static DEFINE_SPINLOCK(dtc2278_lock);
-static void dtc2278_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void dtc2278_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
unsigned long flags;
- if (pio >= 3) {
+ if (drive->pio_mode >= XFER_PIO_3) {
spin_lock_irqsave(&dtc2278_lock, flags);
/*
* This enables PIO mode4 (3?) on the first interface
diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
index 4d90ac2dbb1b..b885c1d548f5 100644
--- a/drivers/ide/hpt366.c
+++ b/drivers/ide/hpt366.c
@@ -627,14 +627,14 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info)
return info->timings->clock_table[info->clock][i];
}
-static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
+static void hpt3xx_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
struct hpt_info *info = hpt3xx_get_info(hwif->dev);
struct hpt_timings *t = info->timings;
u8 itr_addr = 0x40 + (drive->dn * 4);
u32 old_itr = 0;
+ const u8 speed = drive->dma_mode;
u32 new_itr = get_speed_setting(speed, info);
u32 itr_mask = speed < XFER_MW_DMA_0 ? t->pio_mask :
(speed < XFER_UDMA_0 ? t->dma_mask :
@@ -651,9 +651,10 @@ static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
pci_write_config_dword(dev, itr_addr, new_itr);
}
-static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void hpt3xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- hpt3xx_set_mode(drive, XFER_PIO_0 + pio);
+ drive->dma_mode = drive->pio_mode;
+ hpt3xx_set_mode(hwif, drive);
}
static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c
index aafed8060e17..d81e49680c3f 100644
--- a/drivers/ide/ht6560b.c
+++ b/drivers/ide/ht6560b.c
@@ -279,9 +279,10 @@ static void ht_set_prefetch(ide_drive_t *drive, u8 state)
#endif
}
-static void ht6560b_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void ht6560b_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
unsigned long flags, config;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
u8 timing;
switch (pio) {
diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c
index 0f67f1abbbd3..4a697a238e28 100644
--- a/drivers/ide/icside.c
+++ b/drivers/ide/icside.c
@@ -65,6 +65,8 @@ static struct cardinfo icside_cardinfo_v6_2 = {
};
struct icside_state {
+ unsigned int channel;
+ unsigned int enabled;
void __iomem *irq_port;
void __iomem *ioc_base;
unsigned int sel;
@@ -114,11 +116,18 @@ static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
struct icside_state *state = ec->irq_data;
void __iomem *base = state->irq_port;
- writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
- readb(base + ICS_ARCIN_V6_INTROFFSET_2);
+ state->enabled = 1;
- writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
- readb(base + ICS_ARCIN_V6_INTROFFSET_1);
+ switch (state->channel) {
+ case 0:
+ writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
+ readb(base + ICS_ARCIN_V6_INTROFFSET_2);
+ break;
+ case 1:
+ writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
+ readb(base + ICS_ARCIN_V6_INTROFFSET_1);
+ break;
+ }
}
/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
@@ -128,6 +137,8 @@ static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
{
struct icside_state *state = ec->irq_data;
+ state->enabled = 0;
+
readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
}
@@ -149,6 +160,44 @@ static const expansioncard_ops_t icside_ops_arcin_v6 = {
.irqpending = icside_irqpending_arcin_v6,
};
+/*
+ * Handle routing of interrupts. This is called before
+ * we write the command to the drive.
+ */
+static void icside_maskproc(ide_drive_t *drive, int mask)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct expansion_card *ec = ECARD_DEV(hwif->dev);
+ struct icside_state *state = ecard_get_drvdata(ec);
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ state->channel = hwif->channel;
+
+ if (state->enabled && !mask) {
+ switch (hwif->channel) {
+ case 0:
+ writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+ readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+ break;
+ case 1:
+ writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+ readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+ break;
+ }
+ } else {
+ readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+ readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+ }
+
+ local_irq_restore(flags);
+}
+
+static const struct ide_port_ops icside_v6_no_dma_port_ops = {
+ .maskproc = icside_maskproc,
+};
+
#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
/*
* SG-DMA support.
@@ -185,10 +234,11 @@ static const expansioncard_ops_t icside_ops_arcin_v6 = {
* MW1 80 50 50 150 C
* MW2 70 25 25 120 C
*/
-static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
+static void icside_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
unsigned long cycle_time;
int use_dma_info = 0;
+ const u8 xfer_mode = drive->dma_mode;
switch (xfer_mode) {
case XFER_MW_DMA_2:
@@ -228,6 +278,7 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
static const struct ide_port_ops icside_v6_port_ops = {
.set_dma_mode = icside_set_dma_mode,
+ .maskproc = icside_maskproc,
};
static void icside_dma_host_set(ide_drive_t *drive, int on)
@@ -272,6 +323,11 @@ static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
BUG_ON(dma_channel_active(ec->dma));
/*
+ * Ensure that we have the right interrupt routed.
+ */
+ icside_maskproc(drive, 0);
+
+ /*
* Route the DMA signals to the correct interface.
*/
writeb(state->sel | hwif->channel, state->ioc_base);
@@ -399,6 +455,7 @@ err_free:
static const struct ide_port_info icside_v6_port_info __initdata = {
.init_dma = icside_dma_off_init,
+ .port_ops = &icside_v6_no_dma_port_ops,
.dma_ops = &icside_v6_dma_ops,
.host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO,
.mwdma_mask = ATA_MWDMA2,
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index c0cf45a11b93..5cb01e5c323c 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -108,11 +108,11 @@ bool ide_port_acpi(ide_hwif_t *hwif)
* Returns 0 on success, <0 on error.
*/
static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
- acpi_integer *pcidevfn)
+ u64 *pcidevfn)
{
struct pci_dev *pdev = to_pci_dev(dev);
unsigned int bus, devnum, func;
- acpi_integer addr;
+ u64 addr;
acpi_handle dev_handle;
acpi_status status;
struct acpi_device_info *dinfo = NULL;
@@ -122,7 +122,7 @@ static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
devnum = PCI_SLOT(pdev->devfn);
func = PCI_FUNC(pdev->devfn);
/* ACPI _ADR encoding for PCI bus: */
- addr = (acpi_integer)(devnum << 16 | func);
+ addr = (u64)(devnum << 16 | func);
DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
@@ -169,7 +169,7 @@ static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
{
struct device *dev = hwif->gendev.parent;
acpi_handle uninitialized_var(dev_handle);
- acpi_integer pcidevfn;
+ u64 pcidevfn;
acpi_handle chan_handle;
int err;
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
index dd6396384c25..ab87e4f7cec9 100644
--- a/drivers/ide/ide-cs.c
+++ b/drivers/ide/ide-cs.c
@@ -121,19 +121,11 @@ static int ide_probe(struct pcmcia_device *link)
static void ide_detach(struct pcmcia_device *link)
{
ide_info_t *info = link->priv;
- ide_hwif_t *hwif = info->host->ports[0];
- unsigned long data_addr, ctl_addr;
dev_dbg(&link->dev, "ide_detach(0x%p)\n", link);
- data_addr = hwif->io_ports.data_addr;
- ctl_addr = hwif->io_ports.ctl_addr;
-
ide_release(link);
- release_region(ctl_addr, 1);
- release_region(data_addr, 8);
-
kfree(info);
} /* ide_detach */
@@ -354,12 +346,19 @@ static void ide_release(struct pcmcia_device *link)
dev_dbg(&link->dev, "ide_release(0x%p)\n", link);
- if (info->ndev)
- /* FIXME: if this fails we need to queue the cleanup somehow
- -- need to investigate the required PCMCIA magic */
+ if (info->ndev) {
+ ide_hwif_t *hwif = host->ports[0];
+ unsigned long data_addr, ctl_addr;
+
+ data_addr = hwif->io_ports.data_addr;
+ ctl_addr = hwif->io_ports.ctl_addr;
+
ide_host_remove(host);
+ info->ndev = 0;
- info->ndev = 0;
+ release_region(ctl_addr, 1);
+ release_region(data_addr, 8);
+ }
pcmcia_disable_device(link);
} /* ide_release */
diff --git a/drivers/ide/ide-devsets.c b/drivers/ide/ide-devsets.c
index 1099bf7cf968..c6935c78757c 100644
--- a/drivers/ide/ide-devsets.c
+++ b/drivers/ide/ide-devsets.c
@@ -105,15 +105,17 @@ static int set_pio_mode(ide_drive_t *drive, int arg)
return -ENOSYS;
if (set_pio_mode_abuse(drive->hwif, arg)) {
+ drive->pio_mode = arg + XFER_PIO_0;
+
if (arg == 8 || arg == 9) {
unsigned long flags;
/* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
spin_lock_irqsave(&hwif->lock, flags);
- port_ops->set_pio_mode(drive, arg);
+ port_ops->set_pio_mode(hwif, drive);
spin_unlock_irqrestore(&hwif->lock, flags);
} else
- port_ops->set_pio_mode(drive, arg);
+ port_ops->set_pio_mode(hwif, drive);
} else {
int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 7f878017b736..3b128dce9c3a 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -679,7 +679,7 @@ static void ide_disk_setup(ide_drive_t *drive)
if (max_s > hwif->rqsize)
max_s = hwif->rqsize;
- blk_queue_max_sectors(q, max_s);
+ blk_queue_max_hw_sectors(q, max_s);
}
printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index fefbdfc8db06..efd907623469 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -486,7 +486,7 @@ static void ide_floppy_setup(ide_drive_t *drive)
drive->atapi_flags |= IDE_AFLAG_ZIP_DRIVE;
/* This value will be visible in the /proc/ide/hdx/settings */
drive->pc_delay = IDEFLOPPY_PC_DELAY;
- blk_queue_max_sectors(drive->queue, 64);
+ blk_queue_max_hw_sectors(drive->queue, 64);
}
/*
@@ -494,7 +494,7 @@ static void ide_floppy_setup(ide_drive_t *drive)
* nasty clicking noises without it, so please don't remove this.
*/
if (strncmp((char *)&id[ATA_ID_PROD], "IOMEGA Clik!", 11) == 0) {
- blk_queue_max_sectors(drive->queue, 64);
+ blk_queue_max_hw_sectors(drive->queue, 64);
drive->atapi_flags |= IDE_AFLAG_CLIK_DRIVE;
/* IOMEGA Clik! drives do not support lock/unlock commands */
drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 222c1ef65fb9..376f2dc410c5 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -231,7 +231,7 @@ u8 eighty_ninty_three(ide_drive_t *drive)
u16 *id = drive->id;
int ivb = ide_in_drive_list(id, ivb_list);
- if (hwif->cbl == ATA_CBL_PATA40_SHORT)
+ if (hwif->cbl == ATA_CBL_SATA || hwif->cbl == ATA_CBL_PATA40_SHORT)
return 1;
if (ivb)
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 4d76ba473097..fbedd35feb44 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -774,7 +774,7 @@ static int ide_init_queue(ide_drive_t *drive)
if (hwif->rqsize < max_sectors)
max_sectors = hwif->rqsize;
- blk_queue_max_sectors(q, max_sectors);
+ blk_queue_max_hw_sectors(q, max_sectors);
#ifdef CONFIG_PCI
/* When we have an IOMMU, we may have a problem where pci_map_sg()
@@ -790,8 +790,7 @@ static int ide_init_queue(ide_drive_t *drive)
max_sg_entries >>= 1;
#endif /* CONFIG_PCI */
- blk_queue_max_hw_segments(q, max_sg_entries);
- blk_queue_max_phys_segments(q, max_sg_entries);
+ blk_queue_max_segments(q, max_sg_entries);
/* assign drive queue */
drive->queue = q;
@@ -1043,6 +1042,8 @@ static void ide_port_init_devices(ide_hwif_t *hwif)
if (hwif->host_flags & IDE_HFLAG_NO_UNMASK_IRQS)
drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
+ drive->pio_mode = XFER_PIO_0;
+
if (port_ops && port_ops->init_dev)
port_ops->init_dev(drive);
}
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 6a0e62542167..b07232880ec9 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -1365,7 +1365,7 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
* supported here, and not in the corresponding block interface. Our own
* ide-tape ioctls are supported on both interfaces.
*/
-static int idetape_chrdev_ioctl(struct inode *inode, struct file *file,
+static long do_idetape_chrdev_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct ide_tape_obj *tape = file->private_data;
@@ -1420,6 +1420,16 @@ static int idetape_chrdev_ioctl(struct inode *inode, struct file *file,
}
}
+static long idetape_chrdev_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ long ret;
+ lock_kernel();
+ ret = do_idetape_chrdev_ioctl(file, cmd, arg);
+ unlock_kernel();
+ return ret;
+}
+
/*
* Do a mode sense page 0 with block descriptor and if it succeeds set the tape
* block size with the reported value.
@@ -1888,7 +1898,7 @@ static const struct file_operations idetape_fops = {
.owner = THIS_MODULE,
.read = idetape_chrdev_read,
.write = idetape_chrdev_write,
- .ioctl = idetape_chrdev_ioctl,
+ .unlocked_ioctl = idetape_chrdev_ioctl,
.open = idetape_chrdev_open,
.release = idetape_chrdev_release,
};
diff --git a/drivers/ide/ide-timings.c b/drivers/ide/ide-timings.c
index 001a56365be5..0e05f75934c9 100644
--- a/drivers/ide/ide-timings.c
+++ b/drivers/ide/ide-timings.c
@@ -166,12 +166,13 @@ int ide_timing_compute(ide_drive_t *drive, u8 speed,
if (id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
memset(&p, 0, sizeof(p));
- if (speed <= XFER_PIO_2)
- p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
- else if ((speed <= XFER_PIO_4) ||
- (speed == XFER_PIO_5 && !ata_id_is_cfa(id)))
- p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
- else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+ if (speed >= XFER_PIO_0 && speed < XFER_SW_DMA_0) {
+ if (speed <= XFER_PIO_2)
+ p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
+ else if ((speed <= XFER_PIO_4) ||
+ (speed == XFER_PIO_5 && !ata_id_is_cfa(id)))
+ p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
+ } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
p.cycle = id[ATA_ID_EIDE_DMA_MIN];
ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B);
@@ -185,11 +186,10 @@ int ide_timing_compute(ide_drive_t *drive, u8 speed,
/*
* Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
* S.M.A.R.T and some other commands. We have to ensure that the
- * DMA cycle timing is slower/equal than the fastest PIO timing.
+ * DMA cycle timing is slower/equal than the current PIO timing.
*/
if (speed >= XFER_SW_DMA_0) {
- u8 pio = ide_get_best_pio_mode(drive, 255, 5);
- ide_timing_compute(drive, XFER_PIO_0 + pio, &p, T, UT);
+ ide_timing_compute(drive, drive->pio_mode, &p, T, UT);
ide_timing_merge(&p, t, t, IDE_TIMING_ALL);
}
diff --git a/drivers/ide/ide-xfer-mode.c b/drivers/ide/ide-xfer-mode.c
index 46d203ce60cc..5fc8d5c17de9 100644
--- a/drivers/ide/ide-xfer-mode.c
+++ b/drivers/ide/ide-xfer-mode.c
@@ -58,7 +58,7 @@ EXPORT_SYMBOL(ide_xfer_verbose);
* This is used by most chipset support modules when "auto-tuning".
*/
-u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
+static u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
{
u16 *id = drive->id;
int pio_mode = -1, overridden = 0;
@@ -105,7 +105,6 @@ u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
return pio_mode;
}
-EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
int ide_pio_need_iordy(ide_drive_t *drive, const u8 pio)
{
@@ -135,17 +134,20 @@ int ide_set_pio_mode(ide_drive_t *drive, const u8 mode)
* set transfer mode on the device in ->set_pio_mode method...
*/
if (port_ops->set_dma_mode == NULL) {
- port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
+ drive->pio_mode = mode;
+ port_ops->set_pio_mode(hwif, drive);
return 0;
}
if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
if (ide_config_drive_speed(drive, mode))
return -1;
- port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
+ drive->pio_mode = mode;
+ port_ops->set_pio_mode(hwif, drive);
return 0;
} else {
- port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
+ drive->pio_mode = mode;
+ port_ops->set_pio_mode(hwif, drive);
return ide_config_drive_speed(drive, mode);
}
}
@@ -164,10 +166,12 @@ int ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
if (ide_config_drive_speed(drive, mode))
return -1;
- port_ops->set_dma_mode(drive, mode);
+ drive->dma_mode = mode;
+ port_ops->set_dma_mode(hwif, drive);
return 0;
} else {
- port_ops->set_dma_mode(drive, mode);
+ drive->dma_mode = mode;
+ port_ops->set_dma_mode(hwif, drive);
return ide_config_drive_speed(drive, mode);
}
}
diff --git a/drivers/ide/it8172.c b/drivers/ide/it8172.c
index 0d266a5b524d..560e66d07659 100644
--- a/drivers/ide/it8172.c
+++ b/drivers/ide/it8172.c
@@ -37,12 +37,12 @@
#define DRV_NAME "IT8172"
-static void it8172_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void it8172_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
u16 drive_enables;
u32 drive_timing;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
/*
* The highest value of DIOR/DIOW pulse width and recovery time
@@ -77,14 +77,14 @@ static void it8172_set_pio_mode(ide_drive_t *drive, const u8 pio)
pci_write_config_dword(dev, 0x44, drive_timing);
}
-static void it8172_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void it8172_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
int a_speed = 3 << (drive->dn * 4);
int u_flag = 1 << drive->dn;
int u_speed = 0;
u8 reg48, reg4a;
+ const u8 speed = drive->dma_mode;
pci_read_config_byte(dev, 0x48, &reg48);
pci_read_config_byte(dev, 0x4a, &reg4a);
@@ -98,14 +98,14 @@ static void it8172_set_dma_mode(ide_drive_t *drive, const u8 speed)
pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
} else {
const u8 mwdma_to_pio[] = { 0, 3, 4 };
- u8 pio;
pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
- pio = mwdma_to_pio[speed - XFER_MW_DMA_0];
+ drive->pio_mode =
+ mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0;
- it8172_set_pio_mode(drive, pio);
+ it8172_set_pio_mode(hwif, drive);
}
}
diff --git a/drivers/ide/it8213.c b/drivers/ide/it8213.c
index 47976167796a..46816ba26416 100644
--- a/drivers/ide/it8213.c
+++ b/drivers/ide/it8213.c
@@ -17,15 +17,14 @@
/**
* it8213_set_pio_mode - set host controller for PIO mode
+ * @hwif: port
* @drive: drive
- * @pio: PIO mode number
*
* Set the interface PIO mode.
*/
-static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void it8213_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
int is_slave = drive->dn & 1;
int master_port = 0x40;
@@ -35,6 +34,7 @@ static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
u8 slave_data;
static DEFINE_SPINLOCK(tune_lock);
int control = 0;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
static const u8 timings[][2] = {
{ 0, 0 },
@@ -74,15 +74,14 @@ static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
/**
* it8213_set_dma_mode - set host controller for DMA mode
+ * @hwif: port
* @drive: drive
- * @speed: DMA mode
*
* Tune the ITE chipset for the DMA mode.
*/
-static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void it8213_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
u8 maslave = 0x40;
int a_speed = 3 << (drive->dn * 4);
@@ -92,6 +91,7 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
int u_speed = 0;
u16 reg4042, reg4a;
u8 reg48, reg54, reg55;
+ const u8 speed = drive->dma_mode;
pci_read_config_word(dev, maslave, &reg4042);
pci_read_config_byte(dev, 0x48, &reg48);
@@ -120,7 +120,6 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
} else {
const u8 mwdma_to_pio[] = { 0, 3, 4 };
- u8 pio;
if (reg48 & u_flag)
pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
@@ -132,11 +131,12 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
if (speed >= XFER_MW_DMA_0)
- pio = mwdma_to_pio[speed - XFER_MW_DMA_0];
+ drive->pio_mode =
+ mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0;
else
- pio = 2; /* only SWDMA2 is allowed */
+ drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */
- it8213_set_pio_mode(drive, pio);
+ it8213_set_pio_mode(hwif, drive);
}
}
diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c
index 51aa745246dc..b2709c733485 100644
--- a/drivers/ide/it821x.c
+++ b/drivers/ide/it821x.c
@@ -228,18 +228,18 @@ static void it821x_clock_strategy(ide_drive_t *drive)
/**
* it821x_set_pio_mode - set host controller for PIO mode
+ * @hwif: port
* @drive: drive
- * @pio: PIO mode number
*
* Tune the host to the desired PIO mode taking into the consideration
* the maximum PIO mode supported by the other device on the cable.
*/
-static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void it821x_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct it821x_dev *itdev = ide_get_hwifdata(hwif);
ide_drive_t *pair = ide_get_pair_dev(drive);
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
u8 unit = drive->dn & 1, set_pio = pio;
/* Spec says 89 ref driver uses 88 */
@@ -252,7 +252,7 @@ static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
* on the cable.
*/
if (pair) {
- u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
+ u8 pair_pio = pair->pio_mode - XFER_PIO_0;
/* trim PIO to the slowest of the master/slave */
if (pair_pio < set_pio)
set_pio = pair_pio;
@@ -393,14 +393,16 @@ static int it821x_dma_end(ide_drive_t *drive)
/**
* it821x_set_dma_mode - set host controller for DMA mode
+ * @hwif: port
* @drive: drive
- * @speed: DMA mode
*
* Tune the ITE chipset for the desired DMA mode.
*/
-static void it821x_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void it821x_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
+ const u8 speed = drive->dma_mode;
+
/*
* MWDMA tuning is really hard because our MWDMA and PIO
* timings are kept in the same place. We can switch in the
diff --git a/drivers/ide/jmicron.c b/drivers/ide/jmicron.c
index bf2be6431b20..74c2c4a6d909 100644
--- a/drivers/ide/jmicron.c
+++ b/drivers/ide/jmicron.c
@@ -80,19 +80,19 @@ static u8 jmicron_cable_detect(ide_hwif_t *hwif)
return ATA_CBL_PATA80;
}
-static void jmicron_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void jmicron_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
}
/**
* jmicron_set_dma_mode - set host controller for DMA mode
+ * @hwif: port
* @drive: drive
- * @mode: DMA mode
*
* As the JMicron snoops for timings we don't need to do anything here.
*/
-static void jmicron_set_dma_mode(ide_drive_t *drive, const u8 mode)
+static void jmicron_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
}
diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c
index f1d70d6630fe..1a53a4c375ed 100644
--- a/drivers/ide/opti621.c
+++ b/drivers/ide/opti621.c
@@ -8,77 +8,6 @@
* Jan Harkes <jaharkes@cwi.nl>,
* Mark Lord <mlord@pobox.com>
* Some parts of code are from ali14xx.c and from rz1000.c.
- *
- * OPTi is trademark of OPTi, Octek is trademark of Octek.
- *
- * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps
- * and disassembled/traced setupvic.exe (DOS program).
- * It increases kernel code about 2 kB.
- * I don't have this card no more, but I hope I can get some in case
- * of needed development.
- * My card is Octek PIDE 1.01 (on card) or OPTiViC (program).
- * It has a place for a secondary connector in circuit, but nothing
- * is there. Also BIOS says no address for
- * secondary controller (see bellow in ide_init_opti621).
- * I've only tested this on my system, which only has one disk.
- * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus
- * is at 20 MHz (I have DX2/80, I tried PCI at 40, but I got random
- * lockups). I tried the OCTEK double speed CD-ROM and
- * it does not work! But I can't boot DOS also, so it's probably
- * hardware fault. I have connected Conner 80MB, the Seagate 850MB (no
- * problems) and Seagate 1GB (as slave, WD as master). My experiences
- * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes
- * it slows to about 100kB/s! I don't know why and I have
- * not this drive now, so I can't try it again.
- * I write this driver because I lost the paper ("manual") with
- * settings of jumpers on the card and I have to boot Linux with
- * Loadlin except LILO, cause I have to run the setupvic.exe program
- * already or I get disk errors (my test: rpm -Vf
- * /usr/X11R6/bin/XF86_SVGA - or any big file).
- * Some numbers from hdparm -t /dev/hda:
- * Timing buffer-cache reads: 32 MB in 3.02 seconds =10.60 MB/sec
- * Timing buffered disk reads: 16 MB in 5.52 seconds = 2.90 MB/sec
- * I have 4 Megs/s before, but I don't know why (maybe changes
- * in hdparm test).
- * After release of 0.1, I got some successful reports, so it might work.
- *
- * The main problem with OPTi is that some timings for master
- * and slave must be the same. For example, if you have master
- * PIO 3 and slave PIO 0, driver have to set some timings of
- * master for PIO 0. Second problem is that opti621_set_pio_mode
- * got only one drive to set, but have to set both drives.
- * This is solved in compute_pios. If you don't set
- * the second drive, compute_pios use ide_get_best_pio_mode
- * for autoselect mode (you can change it to PIO 0, if you want).
- * If you then set the second drive to another PIO, the old value
- * (automatically selected) will be overrided by yours.
- * There is a 25/33MHz switch in configuration
- * register, but driver is written for use at any frequency.
- *
- * Version 0.1, Nov 8, 1996
- * by Jaromir Koutek, for 2.1.8.
- * Initial version of driver.
- *
- * Version 0.2
- * Number 0.2 skipped.
- *
- * Version 0.3, Nov 29, 1997
- * by Mark Lord (probably), for 2.1.68
- * Updates for use with new IDE block driver.
- *
- * Version 0.4, Dec 14, 1997
- * by Jan Harkes
- * Fixed some errors and cleaned the code.
- *
- * Version 0.5, Jan 2, 1998
- * by Jaromir Koutek
- * Updates for use with (again) new IDE block driver.
- * Update of documentation.
- *
- * Version 0.6, Jan 2, 1999
- * by Jaromir Koutek
- * Reversed to version 0.3 of the driver, because
- * 0.5 doesn't work.
*/
#include <linux/types.h>
@@ -133,12 +62,12 @@ static u8 read_reg(int reg)
return ret;
}
-static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void opti621_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
ide_drive_t *pair = ide_get_pair_dev(drive);
unsigned long flags;
- unsigned long mode = XFER_PIO_0 + pio, pair_mode;
+ unsigned long mode = drive->pio_mode, pair_mode;
+ const u8 pio = mode - XFER_PIO_0;
u8 tim, misc, addr_pio = pio, clk;
/* DRDY is default 2 (by OPTi Databook) */
diff --git a/drivers/ide/palm_bk3710.c b/drivers/ide/palm_bk3710.c
index f8eddf05ecb8..9e8f4e1b0cc9 100644
--- a/drivers/ide/palm_bk3710.c
+++ b/drivers/ide/palm_bk3710.c
@@ -166,7 +166,7 @@ static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
writel(val32, base + BK3710_DATRCVR);
if (mate) {
- u8 mode2 = ide_get_best_pio_mode(mate, 255, 4);
+ u8 mode2 = mate->pio_mode - XFER_PIO_0;
if (mode2 < mode)
mode = mode2;
@@ -188,10 +188,11 @@ static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
writel(val32, base + BK3710_REGRCVR);
}
-static void palm_bk3710_set_dma_mode(ide_drive_t *drive, u8 xferspeed)
+static void palm_bk3710_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
int is_slave = drive->dn & 1;
- void __iomem *base = (void *)drive->hwif->dma_base;
+ void __iomem *base = (void *)hwif->dma_base;
+ const u8 xferspeed = drive->dma_mode;
if (xferspeed >= XFER_UDMA_0) {
palm_bk3710_setudmamode(base, is_slave,
@@ -203,12 +204,13 @@ static void palm_bk3710_set_dma_mode(ide_drive_t *drive, u8 xferspeed)
}
}
-static void palm_bk3710_set_pio_mode(ide_drive_t *drive, u8 pio)
+static void palm_bk3710_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
unsigned int cycle_time;
int is_slave = drive->dn & 1;
ide_drive_t *mate;
- void __iomem *base = (void *)drive->hwif->dma_base;
+ void __iomem *base = (void *)hwif->dma_base;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
/*
* Obtain the drive PIO data for tuning the Palm Chip registers
diff --git a/drivers/ide/pdc202xx_new.c b/drivers/ide/pdc202xx_new.c
index 65ba8239e7b5..9546fe2a93f7 100644
--- a/drivers/ide/pdc202xx_new.c
+++ b/drivers/ide/pdc202xx_new.c
@@ -129,11 +129,11 @@ static struct udma_timing {
{ 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */
};
-static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void pdcnew_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
+ const u8 speed = drive->dma_mode;
/*
* IDE core issues SETFEATURES_XFER to the drive first (thanks to
@@ -167,11 +167,11 @@ static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed)
}
}
-static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void pdcnew_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
if (max_dma_rate(dev) == 4) {
set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c);
diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c
index 35161dd840a0..c5f3841af360 100644
--- a/drivers/ide/pdc202xx_old.c
+++ b/drivers/ide/pdc202xx_old.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2006-2007, 2009 MontaVista Software, Inc.
- * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
*
* Portions Copyright (C) 1999 Promise Technology, Inc.
* Author: Frank Tiernan (frankt@promise.com)
@@ -21,23 +21,15 @@
#define DRV_NAME "pdc202xx_old"
-static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
-
-static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
+static void pdc202xx_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
u8 drive_pci = 0x60 + (drive->dn << 2);
+ const u8 speed = drive->dma_mode;
u8 AP = 0, BP = 0, CP = 0;
u8 TA = 0, TB = 0, TC = 0;
- /*
- * TODO: do this once per channel
- */
- if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
- pdc_old_disable_66MHz_clock(hwif);
-
pci_read_config_byte(dev, drive_pci, &AP);
pci_read_config_byte(dev, drive_pci + 1, &BP);
pci_read_config_byte(dev, drive_pci + 2, &CP);
@@ -84,9 +76,10 @@ static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
}
}
-static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void pdc202xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
+ drive->dma_mode = drive->pio_mode;
+ pdc202xx_set_mode(hwif, drive);
}
static int pdc202xx_test_irq(ide_hwif_t *hwif)
@@ -100,13 +93,13 @@ static int pdc202xx_test_irq(ide_hwif_t *hwif)
* bit 7: error, bit 6: interrupting,
* bit 5: FIFO full, bit 4: FIFO empty
*/
- return ((sc1d & 0x50) == 0x40) ? 1 : 0;
+ return ((sc1d & 0x50) == 0x50) ? 1 : 0;
} else {
/*
* bit 3: error, bit 2: interrupting,
* bit 1: FIFO full, bit 0: FIFO empty
*/
- return ((sc1d & 0x05) == 0x04) ? 1 : 0;
+ return ((sc1d & 0x05) == 0x05) ? 1 : 0;
}
}
@@ -145,6 +138,11 @@ static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
}
+static void pdc2026x_init_hwif(ide_hwif_t *hwif)
+{
+ pdc_old_disable_66MHz_clock(hwif);
+}
+
static void pdc202xx_dma_start(ide_drive_t *drive)
{
if (drive->current_speed > XFER_UDMA_2)
@@ -261,6 +259,7 @@ static const struct ide_dma_ops pdc2026x_dma_ops = {
{ \
.name = DRV_NAME, \
.init_chipset = init_chipset_pdc202xx, \
+ .init_hwif = pdc2026x_init_hwif, \
.port_ops = &pdc2026x_port_ops, \
.dma_ops = &pdc2026x_dma_ops, \
.host_flags = IDE_HFLAGS_PDC202XX, \
@@ -356,6 +355,6 @@ static void __exit pdc202xx_ide_exit(void)
module_init(pdc202xx_ide_init);
module_exit(pdc202xx_ide_exit);
-MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan, Bartlomiej Zolnierkiewicz");
MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
MODULE_LICENSE("GPL");
diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c
index bf14f39bd3a7..1bdca49e5a03 100644
--- a/drivers/ide/piix.c
+++ b/drivers/ide/piix.c
@@ -59,15 +59,14 @@ static int no_piix_dma;
/**
* piix_set_pio_mode - set host controller for PIO mode
+ * @port: port
* @drive: drive
- * @pio: PIO mode number
*
* Set the interface PIO mode based upon the settings done by AMI BIOS.
*/
-static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void piix_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
int is_slave = drive->dn & 1;
int master_port = hwif->channel ? 0x42 : 0x40;
@@ -77,6 +76,7 @@ static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
u8 slave_data;
static DEFINE_SPINLOCK(tune_lock);
int control = 0;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
/* ISP RTC */
static const u8 timings[][2]= {
@@ -127,16 +127,15 @@ static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
/**
* piix_set_dma_mode - set host controller for DMA mode
+ * @hwif: port
* @drive: drive
- * @speed: DMA mode
*
* Set a PIIX host controller to the desired DMA mode. This involves
* programming the right timing data into the PCI configuration space.
*/
-static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void piix_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
u8 maslave = hwif->channel ? 0x42 : 0x40;
int a_speed = 3 << (drive->dn * 4);
@@ -147,6 +146,7 @@ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
int sitre;
u16 reg4042, reg4a;
u8 reg48, reg54, reg55;
+ const u8 speed = drive->dma_mode;
pci_read_config_word(dev, maslave, &reg4042);
sitre = (reg4042 & 0x4000) ? 1 : 0;
@@ -176,7 +176,6 @@ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
} else {
const u8 mwdma_to_pio[] = { 0, 3, 4 };
- u8 pio;
if (reg48 & u_flag)
pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
@@ -188,11 +187,12 @@ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
if (speed >= XFER_MW_DMA_0)
- pio = mwdma_to_pio[speed - XFER_MW_DMA_0];
+ drive->pio_mode =
+ mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0;
else
- pio = 2; /* only SWDMA2 is allowed */
+ drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */
- piix_set_pio_mode(drive, pio);
+ piix_set_pio_mode(hwif, drive);
}
}
diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c
index 7a4e788cab2f..850ee452e9bb 100644
--- a/drivers/ide/pmac.c
+++ b/drivers/ide/pmac.c
@@ -496,12 +496,11 @@ static void pmac_write_devctl(ide_hwif_t *hwif, u8 ctl)
/*
* Old tuning functions (called on hdparm -p), sets up drive PIO timings
*/
-static void
-pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void pmac_ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
pmac_ide_hwif_t *pmif =
(pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
struct ide_timing *tim = ide_timing_find_mode(XFER_PIO_0 + pio);
u32 *timings, t;
unsigned accessTicks, recTicks;
@@ -778,14 +777,14 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
#endif
}
-static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void pmac_ide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
pmac_ide_hwif_t *pmif =
(pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
int ret = 0;
u32 *timings, *timings2, tl[2];
u8 unit = drive->dn & 1;
+ const u8 speed = drive->dma_mode;
timings = &pmif->timings[unit];
timings2 = &pmif->timings[unit+2];
@@ -1651,8 +1650,8 @@ pmac_ide_dma_test_irq (ide_drive_t *drive)
if ((status & FLUSH) == 0)
break;
if (++timeout > 100) {
- printk(KERN_WARNING "ide%d, ide_dma_test_irq \
- timeout flushing channel\n", hwif->index);
+ printk(KERN_WARNING "ide%d, ide_dma_test_irq timeout flushing channel\n",
+ hwif->index);
break;
}
}
diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c
index 74696edc8d1d..3f0244fd8e62 100644
--- a/drivers/ide/qd65xx.c
+++ b/drivers/ide/qd65xx.c
@@ -189,15 +189,13 @@ static void qd_set_timing (ide_drive_t *drive, u8 timing)
printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
}
-static void qd6500_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void qd6500_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
u16 *id = drive->id;
int active_time = 175;
int recovery_time = 415; /* worst case values from the dos driver */
- /*
- * FIXME: use "pio" value
- */
+ /* FIXME: use drive->pio_mode value */
if (!qd_find_disk_type(drive, &active_time, &recovery_time) &&
(id[ATA_ID_OLD_PIO_MODES] & 0xff) && (id[ATA_ID_FIELD_VALID] & 2) &&
id[ATA_ID_EIDE_PIO] >= 240) {
@@ -211,9 +209,9 @@ static void qd6500_set_pio_mode(ide_drive_t *drive, const u8 pio)
active_time, recovery_time));
}
-static void qd6580_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void qd6580_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
unsigned int cycle_time;
int active_time = 175;
diff --git a/drivers/ide/sc1200.c b/drivers/ide/sc1200.c
index d467478d68da..134f1fd13866 100644
--- a/drivers/ide/sc1200.c
+++ b/drivers/ide/sc1200.c
@@ -122,13 +122,13 @@ out:
return mask;
}
-static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
+static void sc1200_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
unsigned int reg, timings;
unsigned short pci_clock;
unsigned int basereg = hwif->channel ? 0x50 : 0x40;
+ const u8 mode = drive->dma_mode;
static const u32 udma_timing[3][3] = {
{ 0x00921250, 0x00911140, 0x00911030 },
@@ -193,10 +193,10 @@ static int sc1200_dma_end(ide_drive_t *drive)
* will have valid default PIO timings set up before we get here.
*/
-static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void sc1200_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
int mode = -1;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
/*
* bad abuse of ->set_pio_mode interface
diff --git a/drivers/ide/scc_pata.c b/drivers/ide/scc_pata.c
index 1104bb301eb9..b7f5b0c4310c 100644
--- a/drivers/ide/scc_pata.c
+++ b/drivers/ide/scc_pata.c
@@ -199,16 +199,15 @@ scc_ide_outsl(unsigned long port, void *addr, u32 count)
/**
* scc_set_pio_mode - set host controller for PIO mode
+ * @hwif: port
* @drive: drive
- * @pio: PIO mode number
*
* Load the timing settings for this device mode into the
* controller.
*/
-static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void scc_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct scc_ports *ports = ide_get_hwifdata(hwif);
unsigned long ctl_base = ports->ctl;
unsigned long cckctrl_port = ctl_base + 0xff0;
@@ -216,6 +215,7 @@ static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio)
unsigned long pioct_port = ctl_base + 0x004;
unsigned long reg;
int offset;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
reg = in_be32((void __iomem *)cckctrl_port);
if (reg & CCKCTRL_ATACLKOEN) {
@@ -231,16 +231,15 @@ static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio)
/**
* scc_set_dma_mode - set host controller for DMA mode
+ * @hwif: port
* @drive: drive
- * @speed: DMA mode
*
* Load the timing settings for this device mode into the
* controller.
*/
-static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void scc_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct scc_ports *ports = ide_get_hwifdata(hwif);
unsigned long ctl_base = ports->ctl;
unsigned long cckctrl_port = ctl_base + 0xff0;
@@ -254,6 +253,7 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
int offset, idx;
unsigned long reg;
unsigned long jcactsel;
+ const u8 speed = drive->dma_mode;
reg = in_be32((void __iomem *)cckctrl_port);
if (reg & CCKCTRL_ATACLKOEN) {
@@ -872,20 +872,18 @@ static struct pci_driver scc_pci_driver = {
.remove = __devexit_p(scc_remove),
};
-static int scc_ide_init(void)
+static int __init scc_ide_init(void)
{
return ide_pci_register_driver(&scc_pci_driver);
}
-module_init(scc_ide_init);
-/* -- No exit code?
-static void scc_ide_exit(void)
+static void __exit scc_ide_exit(void)
{
- ide_pci_unregister_driver(&scc_pci_driver);
+ pci_unregister_driver(&scc_pci_driver);
}
-module_exit(scc_ide_exit);
- */
+module_init(scc_ide_init);
+module_exit(scc_ide_exit);
MODULE_DESCRIPTION("PCI driver module for Toshiba SCC IDE");
MODULE_LICENSE("GPL");
diff --git a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
index b6554ef92716..35fb8dabb55d 100644
--- a/drivers/ide/serverworks.c
+++ b/drivers/ide/serverworks.c
@@ -2,7 +2,7 @@
* Copyright (C) 1998-2000 Michel Aubry
* Copyright (C) 1998-2000 Andrzej Krzysztofowicz
* Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
* Portions copyright (c) 2001 Sun Microsystems
*
*
@@ -52,8 +52,6 @@ static const char *svwks_bad_ata100[] = {
NULL
};
-static struct pci_dev *isa_dev;
-
static int check_in_drive_lists (ide_drive_t *drive, const char **list)
{
char *m = (char *)&drive->id[ATA_ID_PROD];
@@ -67,26 +65,14 @@ static int check_in_drive_lists (ide_drive_t *drive, const char **list)
static u8 svwks_udma_filter(ide_drive_t *drive)
{
struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- u8 mask = 0;
- if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE)
+ if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) {
return 0x1f;
- if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
- u32 reg = 0;
- if (isa_dev)
- pci_read_config_dword(isa_dev, 0x64, &reg);
-
- /*
- * Don't enable UDMA on disk devices for the moment
- */
- if(drive->media == ide_disk)
- return 0;
- /* Check the OSB4 DMA33 enable bit */
- return ((reg & 0x00004000) == 0x00004000) ? 0x07 : 0;
} else if (dev->revision < SVWKS_CSB5_REVISION_NEW) {
return 0x07;
- } else if (dev->revision >= SVWKS_CSB5_REVISION_NEW) {
- u8 btr = 0, mode;
+ } else {
+ u8 btr = 0, mode, mask;
+
pci_read_config_byte(dev, 0x5A, &btr);
mode = btr & 0x3;
@@ -101,13 +87,9 @@ static u8 svwks_udma_filter(ide_drive_t *drive)
case 1: mask = 0x07; break;
default: mask = 0x00; break;
}
- }
- if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
- (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
- (!(PCI_FUNC(dev->devfn) & 1)))
- mask = 0x1f;
- return mask;
+ return mask;
+ }
}
static u8 svwks_csb_check (struct pci_dev *dev)
@@ -124,12 +106,13 @@ static u8 svwks_csb_check (struct pci_dev *dev)
return 0;
}
-static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void svwks_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]);
@@ -145,14 +128,14 @@ static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio)
}
}
-static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void svwks_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
static const u8 dma_modes[] = { 0x77, 0x21, 0x20 };
static const u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 };
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
+ const u8 speed = drive->dma_mode;
u8 unit = drive->dn & 1;
u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0;
@@ -185,8 +168,9 @@ static int init_chipset_svwks(struct pci_dev *dev)
/* OSB4 : South Bridge and IDE */
if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
- isa_dev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
- PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+ struct pci_dev *isa_dev =
+ pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
if (isa_dev) {
pci_read_config_dword(isa_dev, 0x64, &reg);
reg &= ~0x00002000; /* disable 600ns interrupt mask */
@@ -195,6 +179,7 @@ static int init_chipset_svwks(struct pci_dev *dev)
"enabled.\n", pci_name(dev));
reg |= 0x00004000; /* enable UDMA/33 support */
pci_write_config_dword(isa_dev, 0x64, reg);
+ pci_dev_put(isa_dev);
}
}
@@ -343,7 +328,6 @@ static u8 svwks_cable_detect(ide_hwif_t *hwif)
static const struct ide_port_ops osb4_port_ops = {
.set_pio_mode = svwks_set_pio_mode,
.set_dma_mode = svwks_set_dma_mode,
- .udma_filter = svwks_udma_filter,
};
static const struct ide_port_ops svwks_port_ops = {
@@ -460,6 +444,6 @@ static void __exit svwks_ide_exit(void)
module_init(svwks_ide_init);
module_exit(svwks_ide_exit);
-MODULE_AUTHOR("Michael Aubry. Andrzej Krzysztofowicz, Andre Hedrick");
+MODULE_AUTHOR("Michael Aubry. Andrzej Krzysztofowicz, Andre Hedrick, Bartlomiej Zolnierkiewicz");
MODULE_DESCRIPTION("PCI driver module for Serverworks OSB4/CSB5/CSB6 IDE");
MODULE_LICENSE("GPL");
diff --git a/drivers/ide/sgiioc4.c b/drivers/ide/sgiioc4.c
index b7d61dc64096..e3ea591f66d3 100644
--- a/drivers/ide/sgiioc4.c
+++ b/drivers/ide/sgiioc4.c
@@ -255,7 +255,7 @@ static int sgiioc4_dma_end(ide_drive_t *drive)
return dma_stat;
}
-static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void sgiioc4_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
}
diff --git a/drivers/ide/siimage.c b/drivers/ide/siimage.c
index d95df528562f..ddeda444a27a 100644
--- a/drivers/ide/siimage.c
+++ b/drivers/ide/siimage.c
@@ -229,19 +229,18 @@ static u8 sil_sata_udma_filter(ide_drive_t *drive)
/**
* sil_set_pio_mode - set host controller for PIO mode
+ * @hwif: port
* @drive: drive
- * @pio: PIO mode number
*
* Load the timing settings for this device mode into the
* controller.
*/
-static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
+static void sil_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
static const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
static const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
ide_drive_t *pair = ide_get_pair_dev(drive);
u32 speedt = 0;
@@ -249,6 +248,7 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
unsigned long addr = siimage_seldev(drive, 0x04);
unsigned long tfaddr = siimage_selreg(hwif, 0x02);
unsigned long base = (unsigned long)hwif->hwif_data;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
u8 tf_pio = pio;
u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
u8 addr_mask = hwif->channel ? (mmio ? 0xF4 : 0x84)
@@ -258,7 +258,7 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
/* trim *taskfile* PIO to the slowest of the master/slave */
if (pair) {
- u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
+ u8 pair_pio = pair->pio_mode - XFER_PIO_0;
if (pair_pio < tf_pio)
tf_pio = pair_pio;
@@ -289,19 +289,18 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
/**
* sil_set_dma_mode - set host controller for DMA mode
+ * @hwif: port
* @drive: drive
- * @speed: DMA mode
*
* Tune the SiI chipset for the desired DMA mode.
*/
-static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void sil_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
static const u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
static const u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
static const u16 dma[] = { 0x2208, 0x10C2, 0x10C1 };
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
unsigned long base = (unsigned long)hwif->hwif_data;
u16 ultra = 0, multi = 0;
@@ -311,6 +310,7 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
: (mmio ? 0xB4 : 0x80);
unsigned long ma = siimage_seldev(drive, 0x08);
unsigned long ua = siimage_seldev(drive, 0x0C);
+ const u8 speed = drive->dma_mode;
scsc = sil_ioread8 (dev, base + (mmio ? 0x4A : 0x8A));
mode = sil_ioread8 (dev, base + addr_mask);
diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
index 468706082fb5..db7f4e761dbc 100644
--- a/drivers/ide/sis5513.c
+++ b/drivers/ide/sis5513.c
@@ -290,10 +290,10 @@ static void config_drive_art_rwp(ide_drive_t *drive)
pci_write_config_byte(dev, 0x4b, rw_prefetch);
}
-static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void sis_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
config_drive_art_rwp(drive);
- sis_program_timings(drive, XFER_PIO_0 + pio);
+ sis_program_timings(drive, drive->pio_mode);
}
static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode)
@@ -340,8 +340,10 @@ static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode)
sis_ata33_program_udma_timings(drive, mode);
}
-static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void sis_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
+ const u8 speed = drive->dma_mode;
+
if (speed >= XFER_UDMA_0)
sis_program_udma_timings(drive, speed);
else
diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
index 3c2bbf0057ea..f21dc2ad7682 100644
--- a/drivers/ide/sl82c105.c
+++ b/drivers/ide/sl82c105.c
@@ -63,12 +63,13 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
/*
* Configure the chipset for PIO mode.
*/
-static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void sl82c105_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
unsigned long timings = (unsigned long)ide_get_drivedata(drive);
int reg = 0x44 + drive->dn * 4;
u16 drv_ctrl;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
drv_ctrl = get_pio_timings(drive, pio);
@@ -91,11 +92,12 @@ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
/*
* Configure the chipset for DMA mode.
*/
-static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void sl82c105_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200};
unsigned long timings = (unsigned long)ide_get_drivedata(drive);
u16 drv_ctrl;
+ const u8 speed = drive->dma_mode;
drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0];
diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c
index 1ccfb40e7215..864ffe0e26d9 100644
--- a/drivers/ide/slc90e66.c
+++ b/drivers/ide/slc90e66.c
@@ -18,9 +18,8 @@
static DEFINE_SPINLOCK(slc90e66_lock);
-static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void slc90e66_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
int is_slave = drive->dn & 1;
int master_port = hwif->channel ? 0x42 : 0x40;
@@ -29,6 +28,8 @@ static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
u16 master_data;
u8 slave_data;
int control = 0;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
+
/* ISP RTC */
static const u8 timings[][2] = {
{ 0, 0 },
@@ -71,14 +72,14 @@ static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
spin_unlock_irqrestore(&slc90e66_lock, flags);
}
-static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void slc90e66_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
u8 maslave = hwif->channel ? 0x42 : 0x40;
int sitre = 0, a_speed = 7 << (drive->dn * 4);
int u_speed = 0, u_flag = 1 << drive->dn;
u16 reg4042, reg44, reg48, reg4a;
+ const u8 speed = drive->dma_mode;
pci_read_config_word(dev, maslave, &reg4042);
sitre = (reg4042 & 0x4000) ? 1 : 0;
@@ -98,7 +99,6 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
}
} else {
const u8 mwdma_to_pio[] = { 0, 3, 4 };
- u8 pio;
if (reg48 & u_flag)
pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
@@ -106,11 +106,12 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
if (speed >= XFER_MW_DMA_0)
- pio = mwdma_to_pio[speed - XFER_MW_DMA_0];
+ drive->pio_mode =
+ mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0;
else
- pio = 2; /* only SWDMA2 is allowed */
+ drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */
- slc90e66_set_pio_mode(drive, pio);
+ slc90e66_set_pio_mode(hwif, drive);
}
}
diff --git a/drivers/ide/tc86c001.c b/drivers/ide/tc86c001.c
index 05a93d6baecc..e444d24934b3 100644
--- a/drivers/ide/tc86c001.c
+++ b/drivers/ide/tc86c001.c
@@ -13,11 +13,11 @@
#define DRV_NAME "tc86c001"
-static void tc86c001_set_mode(ide_drive_t *drive, const u8 speed)
+static void tc86c001_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00);
u16 mode, scr = inw(scr_port);
+ const u8 speed = drive->dma_mode;
switch (speed) {
case XFER_UDMA_4: mode = 0x00c0; break;
@@ -41,9 +41,10 @@ static void tc86c001_set_mode(ide_drive_t *drive, const u8 speed)
outw(scr, scr_port);
}
-static void tc86c001_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void tc86c001_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- tc86c001_set_mode(drive, XFER_PIO_0 + pio);
+ drive->dma_mode = drive->pio_mode;
+ tc86c001_set_mode(hwif, drive);
}
/*
diff --git a/drivers/ide/triflex.c b/drivers/ide/triflex.c
index 8773c3ba7462..7953447eae0f 100644
--- a/drivers/ide/triflex.c
+++ b/drivers/ide/triflex.c
@@ -34,9 +34,8 @@
#define DRV_NAME "triflex"
-static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
+static void triflex_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
u32 triflex_timings = 0;
u16 timing = 0;
@@ -44,7 +43,7 @@ static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
pci_read_config_dword(dev, channel_offset, &triflex_timings);
- switch(speed) {
+ switch (drive->dma_mode) {
case XFER_MW_DMA_2:
timing = 0x0103;
break;
@@ -82,9 +81,10 @@ static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
pci_write_config_dword(dev, channel_offset, triflex_timings);
}
-static void triflex_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void triflex_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- triflex_set_mode(drive, XFER_PIO_0 + pio);
+ drive->dma_mode = drive->pio_mode;
+ triflex_set_mode(hwif, drive);
}
static const struct ide_port_ops triflex_port_ops = {
diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c
index fd59c0d235b5..1d80f1fdbc97 100644
--- a/drivers/ide/tx4938ide.c
+++ b/drivers/ide/tx4938ide.c
@@ -56,16 +56,15 @@ static void tx4938ide_tune_ebusc(unsigned int ebus_ch,
&tx4938_ebuscptr->cr[ebus_ch]);
}
-static void tx4938ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void tx4938ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
struct tx4938ide_platform_info *pdata = hwif->dev->platform_data;
- u8 safe = pio;
+ u8 safe = drive->pio_mode - XFER_PIO_0;
ide_drive_t *pair;
pair = ide_get_pair_dev(drive);
if (pair)
- safe = min(safe, ide_get_best_pio_mode(pair, 255, 5));
+ safe = min(safe, pair->pio_mode - XFER_PIO_0);
tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, safe);
}
diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c
index 64b58ecc3f0e..3c7367751873 100644
--- a/drivers/ide/tx4939ide.c
+++ b/drivers/ide/tx4939ide.c
@@ -104,17 +104,17 @@ static void tx4939ide_writeb(u8 val, void __iomem *base, u32 reg)
#define TX4939IDE_BASE(hwif) ((void __iomem *)(hwif)->extra_base)
-static void tx4939ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void tx4939ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
int is_slave = drive->dn;
u32 mask, val;
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
u8 safe = pio;
ide_drive_t *pair;
pair = ide_get_pair_dev(drive);
if (pair)
- safe = min(safe, ide_get_best_pio_mode(pair, 255, 4));
+ safe = min(safe, pair->pio_mode - XFER_PIO_0);
/*
* Update Command Transfer Mode for master/slave and Data
* Transfer Mode for this drive.
@@ -125,10 +125,10 @@ static void tx4939ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
/* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */
}
-static void tx4939ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
+static void tx4939ide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
u32 mask, val;
+ const u8 mode = drive->dma_mode;
/* Update Data Transfer Mode for this drive. */
if (mode >= XFER_UDMA_0)
diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c
index 60f936e2319c..47adcd09cb26 100644
--- a/drivers/ide/umc8672.c
+++ b/drivers/ide/umc8672.c
@@ -104,10 +104,11 @@ static void umc_set_speeds(u8 speeds[])
speeds[0], speeds[1], speeds[2], speeds[3]);
}
-static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void umc_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif, *mate = hwif->mate;
+ ide_hwif_t *mate = hwif->mate;
unsigned long uninitialized_var(flags);
+ const u8 pio = drive->pio_mode - XFER_PIO_0;
printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
drive->name, pio, pio_to_umc[pio]);
diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
index 028de26a25fe..e65d010b708d 100644
--- a/drivers/ide/via82cxxx.c
+++ b/drivers/ide/via82cxxx.c
@@ -6,7 +6,7 @@
* vt8235, vt8237, vt8237a
*
* Copyright (c) 2000-2002 Vojtech Pavlik
- * Copyright (c) 2007 Bartlomiej Zolnierkiewicz
+ * Copyright (c) 2007-2010 Bartlomiej Zolnierkiewicz
*
* Based on the work of:
* Michel Aubry
@@ -54,6 +54,11 @@
#define VIA_NO_UNMASK 0x08 /* Doesn't work with IRQ unmasking on */
#define VIA_BAD_ID 0x10 /* Has wrong vendor ID (0x1107) */
#define VIA_BAD_AST 0x20 /* Don't touch Address Setup Timing */
+#define VIA_SATA_PATA 0x80 /* SATA/PATA combined configuration */
+
+enum {
+ VIA_IDFLAG_SINGLE = (1 << 1), /* single channel controller */
+};
/*
* VIA SouthBridge chips.
@@ -67,11 +72,13 @@ static struct via_isa_bridge {
u8 udma_mask;
u8 flags;
} via_isa_bridges[] = {
- { "vx855", PCI_DEVICE_ID_VIA_VX855, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
- { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
- { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vx855", PCI_DEVICE_ID_VIA_VX855, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
+ { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
+ { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
+ { "vt8261", PCI_DEVICE_ID_VIA_8261, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
{ "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
{ "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt6415", PCI_DEVICE_ID_VIA_6410, 0x00, 0xff, ATA_UDMA6, VIA_BAD_AST },
{ "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
{ "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
{ "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
@@ -92,6 +99,7 @@ static struct via_isa_bridge {
{ "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, 0x00, VIA_SET_FIFO },
{ "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK },
{ "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+ { "vtxxxx", PCI_DEVICE_ID_VIA_ANON, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
{ NULL }
};
@@ -102,6 +110,7 @@ struct via82cxxx_dev
{
struct via_isa_bridge *via_config;
unsigned int via_80w;
+ u8 cached_device[2];
};
/**
@@ -137,30 +146,45 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
case ATA_UDMA4: t = timing->udma ? (0xe8 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x0f; break;
case ATA_UDMA5: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x07; break;
case ATA_UDMA6: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x07; break;
- default: return;
}
- pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t);
+ /* Set UDMA unless device is not UDMA capable */
+ if (vdev->via_config->udma_mask) {
+ u8 udma_etc;
+
+ pci_read_config_byte(dev, VIA_UDMA_TIMING + 3 - dn, &udma_etc);
+
+ /* clear transfer mode bit */
+ udma_etc &= ~0x20;
+
+ if (timing->udma) {
+ /* preserve 80-wire cable detection bit */
+ udma_etc &= 0x10;
+ udma_etc |= t;
+ }
+
+ pci_write_config_byte(dev, VIA_UDMA_TIMING + 3 - dn, udma_etc);
+ }
}
/**
* via_set_drive - configure transfer mode
+ * @hwif: port
* @drive: Drive to set up
- * @speed: desired speed
*
* via_set_drive() computes timing values configures the chipset to
* a desired transfer mode. It also can be called by upper layers.
*/
-static void via_set_drive(ide_drive_t *drive, const u8 speed)
+static void via_set_drive(ide_hwif_t *hwif, ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
ide_drive_t *peer = ide_get_pair_dev(drive);
struct pci_dev *dev = to_pci_dev(hwif->dev);
struct ide_host *host = pci_get_drvdata(dev);
struct via82cxxx_dev *vdev = host->host_priv;
struct ide_timing t, p;
unsigned int T, UT;
+ const u8 speed = drive->dma_mode;
T = 1000000000 / via_clock;
@@ -175,7 +199,7 @@ static void via_set_drive(ide_drive_t *drive, const u8 speed)
ide_timing_compute(drive, speed, &t, T, UT);
if (peer) {
- ide_timing_compute(peer, peer->current_speed, &p, T, UT);
+ ide_timing_compute(peer, peer->pio_mode, &p, T, UT);
ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
}
@@ -184,22 +208,24 @@ static void via_set_drive(ide_drive_t *drive, const u8 speed)
/**
* via_set_pio_mode - set host controller for PIO mode
+ * @hwif: port
* @drive: drive
- * @pio: PIO mode number
*
* A callback from the upper layers for PIO-only tuning.
*/
-static void via_set_pio_mode(ide_drive_t *drive, const u8 pio)
+static void via_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
- via_set_drive(drive, XFER_PIO_0 + pio);
+ drive->dma_mode = drive->pio_mode;
+ via_set_drive(hwif, drive);
}
static struct via_isa_bridge *via_config_find(struct pci_dev **isa)
{
struct via_isa_bridge *via_config;
- for (via_config = via_isa_bridges; via_config->id; via_config++)
+ for (via_config = via_isa_bridges;
+ via_config->id != PCI_DEVICE_ID_VIA_ANON; via_config++)
if ((*isa = pci_get_device(PCI_VENDOR_ID_VIA +
!!(via_config->flags & VIA_BAD_ID),
via_config->id, NULL))) {
@@ -362,6 +388,9 @@ static u8 via82cxxx_cable_detect(ide_hwif_t *hwif)
if (via_cable_override(pdev))
return ATA_CBL_PATA40_SHORT;
+ if ((vdev->via_config->flags & VIA_SATA_PATA) && hwif->channel == 0)
+ return ATA_CBL_SATA;
+
if ((vdev->via_80w >> hwif->channel) & 1)
return ATA_CBL_PATA80;
else
@@ -374,10 +403,66 @@ static const struct ide_port_ops via_port_ops = {
.cable_detect = via82cxxx_cable_detect,
};
+static void via_write_devctl(ide_hwif_t *hwif, u8 ctl)
+{
+ struct via82cxxx_dev *vdev = hwif->host->host_priv;
+
+ outb(ctl, hwif->io_ports.ctl_addr);
+ outb(vdev->cached_device[hwif->channel], hwif->io_ports.device_addr);
+}
+
+static void __via_dev_select(ide_drive_t *drive, u8 select)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct via82cxxx_dev *vdev = hwif->host->host_priv;
+
+ outb(select, hwif->io_ports.device_addr);
+ vdev->cached_device[hwif->channel] = select;
+}
+
+static void via_dev_select(ide_drive_t *drive)
+{
+ __via_dev_select(drive, drive->select | ATA_DEVICE_OBS);
+}
+
+static void via_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+
+ if (valid & IDE_VALID_FEATURE)
+ outb(tf->feature, io_ports->feature_addr);
+ if (valid & IDE_VALID_NSECT)
+ outb(tf->nsect, io_ports->nsect_addr);
+ if (valid & IDE_VALID_LBAL)
+ outb(tf->lbal, io_ports->lbal_addr);
+ if (valid & IDE_VALID_LBAM)
+ outb(tf->lbam, io_ports->lbam_addr);
+ if (valid & IDE_VALID_LBAH)
+ outb(tf->lbah, io_ports->lbah_addr);
+ if (valid & IDE_VALID_DEVICE)
+ __via_dev_select(drive, tf->device);
+}
+
+const struct ide_tp_ops via_tp_ops = {
+ .exec_command = ide_exec_command,
+ .read_status = ide_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .write_devctl = via_write_devctl,
+
+ .dev_select = via_dev_select,
+ .tf_load = via_tf_load,
+ .tf_read = ide_tf_read,
+
+ .input_data = ide_input_data,
+ .output_data = ide_output_data,
+};
+
static const struct ide_port_info via82cxxx_chipset __devinitdata = {
.name = DRV_NAME,
.init_chipset = init_chipset_via82cxxx,
.enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
+ .tp_ops = &via_tp_ops,
.port_ops = &via_port_ops,
.host_flags = IDE_HFLAG_PIO_NO_BLACKLIST |
IDE_HFLAG_POST_SET_MODE |
@@ -402,11 +487,6 @@ static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_i
* Find the ISA bridge and check we know what it is.
*/
via_config = via_config_find(&isa);
- if (!via_config->id) {
- printk(KERN_WARNING DRV_NAME " %s: unknown chipset, skipping\n",
- pci_name(dev));
- return -ENODEV;
- }
/*
* Print the boot message.
@@ -436,10 +516,13 @@ static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_i
via_clock = 33333;
}
- if (idx == 0)
- d.host_flags |= IDE_HFLAG_NO_AUTODMA;
- else
+ if (idx == 1)
d.enablebits[1].reg = d.enablebits[0].reg = 0;
+ else
+ d.host_flags |= IDE_HFLAG_NO_AUTODMA;
+
+ if (idx == VIA_IDFLAG_SINGLE)
+ d.host_flags |= IDE_HFLAG_SINGLE;
if ((via_config->flags & VIA_NO_UNMASK) == 0)
d.host_flags |= IDE_HFLAG_UNMASK_IRQS;
@@ -475,8 +558,9 @@ static const struct pci_device_id via_pci_tbl[] = {
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), 0 },
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), 0 },
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_CX700_IDE), 0 },
- { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_VX855_IDE), 0 },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_VX855_IDE), VIA_IDFLAG_SINGLE },
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), 1 },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6415), 1 },
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), 1 },
{ 0, },
};
@@ -504,6 +588,6 @@ static void __exit via_ide_exit(void)
module_init(via_ide_init);
module_exit(via_ide_exit);
-MODULE_AUTHOR("Vojtech Pavlik, Michel Aubry, Jeff Garzik, Andre Hedrick");
+MODULE_AUTHOR("Vojtech Pavlik, Bartlomiej Zolnierkiewicz, Michel Aubry, Jeff Garzik, Andre Hedrick");
MODULE_DESCRIPTION("PCI driver module for VIA IDE");
MODULE_LICENSE("GPL");
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 5122b5a8aa2d..18350213479e 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -19,7 +19,6 @@
#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <linux/freezer.h>
-#include <linux/semaphore.h>
#include <asm/atomic.h>
#include "csr.h"
@@ -1397,9 +1396,9 @@ static int update_pdrv(struct device *dev, void *data)
pdrv = container_of(drv, struct hpsb_protocol_driver,
driver);
if (pdrv->update) {
- down(&ud->device.sem);
+ device_lock(&ud->device);
error = pdrv->update(ud);
- up(&ud->device.sem);
+ device_unlock(&ud->device);
}
if (error)
device_release_driver(&ud->device);
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index 9555fd253865..bf47fee79808 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -1452,7 +1452,7 @@ static int __devinit add_card(struct pci_dev *dev,
PRINT(KERN_ERR, lynx->id, "unable to read bus info block from i2c");
} else {
PRINT(KERN_INFO, lynx->id, "got bus info block from serial eeprom");
- /* FIXME: probably we shoud rewrite the max_rec, max_ROM(1394a),
+ /* FIXME: probably we should rewrite the max_rec, max_ROM(1394a),
* generation(1394a) and link_spd(1394a) field and recalculate
* the CRC */
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index f199896c4113..c88696a6cf8a 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -2020,7 +2020,7 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev)
if (lu->workarounds & SBP2_WORKAROUND_POWER_CONDITION)
sdev->start_stop_pwr_cond = 1;
if (lu->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
- blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
+ blk_queue_max_hw_sectors(sdev->request_queue, 128 * 1024 / 512);
blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
return 0;
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index dd0db67bf8d7..975adce5f40c 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -20,6 +20,7 @@ config INFINIBAND_USER_MAD
config INFINIBAND_USER_ACCESS
tristate "InfiniBand userspace access (verbs and CM)"
+ select ANON_INODES
---help---
Userspace InfiniBand access support. This enables the
kernel side of userspace verbs and the userspace
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 5130fc55b8e2..764787ebe8d8 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -3597,7 +3597,7 @@ static ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr,
atomic_long_read(&group->counter[cm_attr->index]));
}
-static struct sysfs_ops cm_counter_ops = {
+static const struct sysfs_ops cm_counter_ops = {
.show = cm_show_counter
};
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index cc9b5940fa97..875e34e0b235 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -2115,9 +2115,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
if (ret)
goto err1;
- if (cma_loopback_addr(addr)) {
- ret = cma_bind_loopback(id_priv);
- } else if (!cma_zero_addr(addr)) {
+ if (!cma_any_addr(addr)) {
ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
if (ret)
goto err1;
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 7522008fda86..e351b1548535 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -1193,10 +1193,7 @@ static int method_in_use(struct ib_mad_mgmt_method_table **method,
{
int i;
- for (i = find_first_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS);
- i < IB_MGMT_MAX_METHODS;
- i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS,
- 1+i)) {
+ for_each_set_bit(i, mad_reg_req->method_mask, IB_MGMT_MAX_METHODS) {
if ((*method)->agent[i]) {
printk(KERN_ERR PFX "Method %d already in use\n", i);
return -EINVAL;
@@ -1330,13 +1327,9 @@ static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req,
goto error3;
/* Finally, add in methods being registered */
- for (i = find_first_bit(mad_reg_req->method_mask,
- IB_MGMT_MAX_METHODS);
- i < IB_MGMT_MAX_METHODS;
- i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS,
- 1+i)) {
+ for_each_set_bit(i, mad_reg_req->method_mask, IB_MGMT_MAX_METHODS)
(*method)->agent[i] = agent_priv;
- }
+
return 0;
error3:
@@ -1429,13 +1422,9 @@ check_in_use:
goto error4;
/* Finally, add in methods being registered */
- for (i = find_first_bit(mad_reg_req->method_mask,
- IB_MGMT_MAX_METHODS);
- i < IB_MGMT_MAX_METHODS;
- i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS,
- 1+i)) {
+ for_each_set_bit(i, mad_reg_req->method_mask, IB_MGMT_MAX_METHODS)
(*method)->agent[i] = agent_priv;
- }
+
return 0;
error4:
@@ -2964,6 +2953,9 @@ static void ib_mad_remove_device(struct ib_device *device)
{
int i, num_ports, cur_port;
+ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
+ return;
+
if (device->node_type == RDMA_NODE_IB_SWITCH) {
num_ports = 1;
cur_port = 0;
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 158a214da2f7..1558bb7fc74d 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -79,7 +79,7 @@ static ssize_t port_attr_show(struct kobject *kobj,
return port_attr->show(p, port_attr, buf);
}
-static struct sysfs_ops port_sysfs_ops = {
+static const struct sysfs_ops port_sysfs_ops = {
.show = port_attr_show
};
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
index f504c9b00c1b..017d6e24448f 100644
--- a/drivers/infiniband/core/ucm.c
+++ b/drivers/infiniband/core/ucm.c
@@ -1215,15 +1215,18 @@ static void ib_ucm_release_dev(struct device *dev)
ucm_dev = container_of(dev, struct ib_ucm_device, dev);
cdev_del(&ucm_dev->cdev);
- clear_bit(ucm_dev->devnum, dev_map);
+ if (ucm_dev->devnum < IB_UCM_MAX_DEVICES)
+ clear_bit(ucm_dev->devnum, dev_map);
+ else
+ clear_bit(ucm_dev->devnum - IB_UCM_MAX_DEVICES, dev_map);
kfree(ucm_dev);
}
static const struct file_operations ucm_fops = {
- .owner = THIS_MODULE,
- .open = ib_ucm_open,
+ .owner = THIS_MODULE,
+ .open = ib_ucm_open,
.release = ib_ucm_close,
- .write = ib_ucm_write,
+ .write = ib_ucm_write,
.poll = ib_ucm_poll,
};
@@ -1237,8 +1240,32 @@ static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
+static dev_t overflow_maj;
+static DECLARE_BITMAP(overflow_map, IB_UCM_MAX_DEVICES);
+static int find_overflow_devnum(void)
+{
+ int ret;
+
+ if (!overflow_maj) {
+ ret = alloc_chrdev_region(&overflow_maj, 0, IB_UCM_MAX_DEVICES,
+ "infiniband_cm");
+ if (ret) {
+ printk(KERN_ERR "ucm: couldn't register dynamic device number\n");
+ return ret;
+ }
+ }
+
+ ret = find_first_zero_bit(overflow_map, IB_UCM_MAX_DEVICES);
+ if (ret >= IB_UCM_MAX_DEVICES)
+ return -1;
+
+ return ret;
+}
+
static void ib_ucm_add_one(struct ib_device *device)
{
+ int devnum;
+ dev_t base;
struct ib_ucm_device *ucm_dev;
if (!device->alloc_ucontext ||
@@ -1251,16 +1278,25 @@ static void ib_ucm_add_one(struct ib_device *device)
ucm_dev->ib_dev = device;
- ucm_dev->devnum = find_first_zero_bit(dev_map, IB_UCM_MAX_DEVICES);
- if (ucm_dev->devnum >= IB_UCM_MAX_DEVICES)
- goto err;
-
- set_bit(ucm_dev->devnum, dev_map);
+ devnum = find_first_zero_bit(dev_map, IB_UCM_MAX_DEVICES);
+ if (devnum >= IB_UCM_MAX_DEVICES) {
+ devnum = find_overflow_devnum();
+ if (devnum < 0)
+ goto err;
+
+ ucm_dev->devnum = devnum + IB_UCM_MAX_DEVICES;
+ base = devnum + overflow_maj;
+ set_bit(devnum, overflow_map);
+ } else {
+ ucm_dev->devnum = devnum;
+ base = devnum + IB_UCM_BASE_DEV;
+ set_bit(devnum, dev_map);
+ }
cdev_init(&ucm_dev->cdev, &ucm_fops);
ucm_dev->cdev.owner = THIS_MODULE;
kobject_set_name(&ucm_dev->cdev.kobj, "ucm%d", ucm_dev->devnum);
- if (cdev_add(&ucm_dev->cdev, IB_UCM_BASE_DEV + ucm_dev->devnum, 1))
+ if (cdev_add(&ucm_dev->cdev, base, 1))
goto err;
ucm_dev->dev.class = &cm_class;
@@ -1281,7 +1317,10 @@ err_dev:
device_unregister(&ucm_dev->dev);
err_cdev:
cdev_del(&ucm_dev->cdev);
- clear_bit(ucm_dev->devnum, dev_map);
+ if (ucm_dev->devnum < IB_UCM_MAX_DEVICES)
+ clear_bit(devnum, dev_map);
+ else
+ clear_bit(devnum, overflow_map);
err:
kfree(ucm_dev);
return;
@@ -1297,11 +1336,8 @@ static void ib_ucm_remove_one(struct ib_device *device)
device_unregister(&ucm_dev->dev);
}
-static ssize_t show_abi_version(struct class *class, char *buf)
-{
- return sprintf(buf, "%d\n", IB_USER_CM_ABI_VERSION);
-}
-static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
+static CLASS_ATTR_STRING(abi_version, S_IRUGO,
+ __stringify(IB_USER_CM_ABI_VERSION));
static int __init ib_ucm_init(void)
{
@@ -1314,7 +1350,7 @@ static int __init ib_ucm_init(void)
goto error1;
}
- ret = class_create_file(&cm_class, &class_attr_abi_version);
+ ret = class_create_file(&cm_class, &class_attr_abi_version.attr);
if (ret) {
printk(KERN_ERR "ucm: couldn't create abi_version attribute\n");
goto error2;
@@ -1328,7 +1364,7 @@ static int __init ib_ucm_init(void)
return 0;
error3:
- class_remove_file(&cm_class, &class_attr_abi_version);
+ class_remove_file(&cm_class, &class_attr_abi_version.attr);
error2:
unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
error1:
@@ -1338,8 +1374,10 @@ error1:
static void __exit ib_ucm_cleanup(void)
{
ib_unregister_client(&ucm_client);
- class_remove_file(&cm_class, &class_attr_abi_version);
+ class_remove_file(&cm_class, &class_attr_abi_version.attr);
unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
+ if (overflow_maj)
+ unregister_chrdev_region(overflow_maj, IB_UCM_MAX_DEVICES);
idr_destroy(&ctx_id_table);
}
diff --git a/drivers/infiniband/core/ud_header.c b/drivers/infiniband/core/ud_header.c
index 8ec7876bedcf..650b501eb142 100644
--- a/drivers/infiniband/core/ud_header.c
+++ b/drivers/infiniband/core/ud_header.c
@@ -181,6 +181,7 @@ static const struct ib_field deth_table[] = {
* ib_ud_header_init - Initialize UD header structure
* @payload_bytes:Length of packet payload
* @grh_present:GRH flag (if non-zero, GRH will be included)
+ * @immediate_present: specify if immediate data should be used
* @header:Structure to initialize
*
* ib_ud_header_init() initializes the lrh.link_version, lrh.link_next_header,
@@ -191,21 +192,13 @@ static const struct ib_field deth_table[] = {
*/
void ib_ud_header_init(int payload_bytes,
int grh_present,
+ int immediate_present,
struct ib_ud_header *header)
{
- int header_len;
u16 packet_length;
memset(header, 0, sizeof *header);
- header_len =
- IB_LRH_BYTES +
- IB_BTH_BYTES +
- IB_DETH_BYTES;
- if (grh_present) {
- header_len += IB_GRH_BYTES;
- }
-
header->lrh.link_version = 0;
header->lrh.link_next_header =
grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
@@ -231,7 +224,8 @@ void ib_ud_header_init(int payload_bytes,
header->lrh.packet_length = cpu_to_be16(packet_length);
- if (header->immediate_present)
+ header->immediate_present = immediate_present;
+ if (immediate_present)
header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
else
header->bth.opcode = IB_OPCODE_UD_SEND_ONLY;
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index 6f7c096abf13..4f906f0614f0 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -136,7 +136,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
down_write(&current->mm->mmap_sem);
locked = npages + current->mm->locked_vm;
- lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
+ lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) {
ret = -ENOMEM;
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index 7de02969ed7d..04b585e86cb2 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -65,12 +65,9 @@ enum {
};
/*
- * Our lifetime rules for these structs are the following: each time a
- * device special file is opened, we look up the corresponding struct
- * ib_umad_port by minor in the umad_port[] table while holding the
- * port_lock. If this lookup succeeds, we take a reference on the
- * ib_umad_port's struct ib_umad_device while still holding the
- * port_lock; if the lookup fails, we fail the open(). We drop these
+ * Our lifetime rules for these structs are the following:
+ * device special file is opened, we take a reference on the
+ * ib_umad_port's struct ib_umad_device. We drop these
* references in the corresponding close().
*
* In addition to references coming from open character devices, there
@@ -78,19 +75,14 @@ enum {
* module's reference taken when allocating the ib_umad_device in
* ib_umad_add_one().
*
- * When destroying an ib_umad_device, we clear all of its
- * ib_umad_ports from umad_port[] while holding port_lock before
- * dropping the module's reference to the ib_umad_device. This is
- * always safe because any open() calls will either succeed and obtain
- * a reference before we clear the umad_port[] entries, or fail after
- * we clear the umad_port[] entries.
+ * When destroying an ib_umad_device, we drop the module's reference.
*/
struct ib_umad_port {
- struct cdev *cdev;
+ struct cdev cdev;
struct device *dev;
- struct cdev *sm_cdev;
+ struct cdev sm_cdev;
struct device *sm_dev;
struct semaphore sm_sem;
@@ -136,7 +128,6 @@ static struct class *umad_class;
static const dev_t base_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE);
static DEFINE_SPINLOCK(port_lock);
-static struct ib_umad_port *umad_port[IB_UMAD_MAX_PORTS];
static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS);
static void ib_umad_add_one(struct ib_device *device);
@@ -496,8 +487,8 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
ah_attr.ah_flags = IB_AH_GRH;
memcpy(ah_attr.grh.dgid.raw, packet->mad.hdr.gid, 16);
ah_attr.grh.sgid_index = packet->mad.hdr.gid_index;
- ah_attr.grh.flow_label = be32_to_cpu(packet->mad.hdr.flow_label);
- ah_attr.grh.hop_limit = packet->mad.hdr.hop_limit;
+ ah_attr.grh.flow_label = be32_to_cpu(packet->mad.hdr.flow_label);
+ ah_attr.grh.hop_limit = packet->mad.hdr.hop_limit;
ah_attr.grh.traffic_class = packet->mad.hdr.traffic_class;
}
@@ -528,9 +519,9 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
goto err_ah;
}
- packet->msg->ah = ah;
+ packet->msg->ah = ah;
packet->msg->timeout_ms = packet->mad.hdr.timeout_ms;
- packet->msg->retries = packet->mad.hdr.retries;
+ packet->msg->retries = packet->mad.hdr.retries;
packet->msg->context[0] = packet;
/* Copy MAD header. Any RMPP header is already in place. */
@@ -779,15 +770,11 @@ static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd,
/*
* ib_umad_open() does not need the BKL:
*
- * - umad_port[] accesses are protected by port_lock, the
- * ib_umad_port structures are properly reference counted, and
+ * - the ib_umad_port structures are properly reference counted, and
* everything else is purely local to the file being created, so
* races against other open calls are not a problem;
* - the ioctl method does not affect any global state outside of the
* file structure being operated on;
- * - the port is added to umad_port[] as the last part of module
- * initialization so the open method will either immediately run
- * -ENXIO, or all required initialization will be done.
*/
static int ib_umad_open(struct inode *inode, struct file *filp)
{
@@ -795,13 +782,10 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
struct ib_umad_file *file;
int ret = 0;
- spin_lock(&port_lock);
- port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE];
+ port = container_of(inode->i_cdev, struct ib_umad_port, cdev);
if (port)
kref_get(&port->umad_dev->ref);
- spin_unlock(&port_lock);
-
- if (!port)
+ else
return -ENXIO;
mutex_lock(&port->file_mutex);
@@ -872,16 +856,16 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
}
static const struct file_operations umad_fops = {
- .owner = THIS_MODULE,
- .read = ib_umad_read,
- .write = ib_umad_write,
- .poll = ib_umad_poll,
+ .owner = THIS_MODULE,
+ .read = ib_umad_read,
+ .write = ib_umad_write,
+ .poll = ib_umad_poll,
.unlocked_ioctl = ib_umad_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = ib_umad_compat_ioctl,
+ .compat_ioctl = ib_umad_compat_ioctl,
#endif
- .open = ib_umad_open,
- .release = ib_umad_close
+ .open = ib_umad_open,
+ .release = ib_umad_close
};
static int ib_umad_sm_open(struct inode *inode, struct file *filp)
@@ -892,13 +876,10 @@ static int ib_umad_sm_open(struct inode *inode, struct file *filp)
};
int ret;
- spin_lock(&port_lock);
- port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE - IB_UMAD_MAX_PORTS];
+ port = container_of(inode->i_cdev, struct ib_umad_port, sm_cdev);
if (port)
kref_get(&port->umad_dev->ref);
- spin_unlock(&port_lock);
-
- if (!port)
+ else
return -ENXIO;
if (filp->f_flags & O_NONBLOCK) {
@@ -949,8 +930,8 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp)
}
static const struct file_operations umad_sm_fops = {
- .owner = THIS_MODULE,
- .open = ib_umad_sm_open,
+ .owner = THIS_MODULE,
+ .open = ib_umad_sm_open,
.release = ib_umad_sm_close
};
@@ -984,22 +965,54 @@ static ssize_t show_port(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
-static ssize_t show_abi_version(struct class *class, char *buf)
+static CLASS_ATTR_STRING(abi_version, S_IRUGO,
+ __stringify(IB_USER_MAD_ABI_VERSION));
+
+static dev_t overflow_maj;
+static DECLARE_BITMAP(overflow_map, IB_UMAD_MAX_PORTS);
+static int find_overflow_devnum(void)
{
- return sprintf(buf, "%d\n", IB_USER_MAD_ABI_VERSION);
+ int ret;
+
+ if (!overflow_maj) {
+ ret = alloc_chrdev_region(&overflow_maj, 0, IB_UMAD_MAX_PORTS * 2,
+ "infiniband_mad");
+ if (ret) {
+ printk(KERN_ERR "user_mad: couldn't register dynamic device number\n");
+ return ret;
+ }
+ }
+
+ ret = find_first_zero_bit(overflow_map, IB_UMAD_MAX_PORTS);
+ if (ret >= IB_UMAD_MAX_PORTS)
+ return -1;
+
+ return ret;
}
-static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
static int ib_umad_init_port(struct ib_device *device, int port_num,
struct ib_umad_port *port)
{
+ int devnum;
+ dev_t base;
+
spin_lock(&port_lock);
- port->dev_num = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS);
- if (port->dev_num >= IB_UMAD_MAX_PORTS) {
+ devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS);
+ if (devnum >= IB_UMAD_MAX_PORTS) {
spin_unlock(&port_lock);
- return -1;
+ devnum = find_overflow_devnum();
+ if (devnum < 0)
+ return -1;
+
+ spin_lock(&port_lock);
+ port->dev_num = devnum + IB_UMAD_MAX_PORTS;
+ base = devnum + overflow_maj;
+ set_bit(devnum, overflow_map);
+ } else {
+ port->dev_num = devnum;
+ base = devnum + base_dev;
+ set_bit(devnum, dev_map);
}
- set_bit(port->dev_num, dev_map);
spin_unlock(&port_lock);
port->ib_dev = device;
@@ -1008,17 +1021,14 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
mutex_init(&port->file_mutex);
INIT_LIST_HEAD(&port->file_list);
- port->cdev = cdev_alloc();
- if (!port->cdev)
- return -1;
- port->cdev->owner = THIS_MODULE;
- port->cdev->ops = &umad_fops;
- kobject_set_name(&port->cdev->kobj, "umad%d", port->dev_num);
- if (cdev_add(port->cdev, base_dev + port->dev_num, 1))
+ cdev_init(&port->cdev, &umad_fops);
+ port->cdev.owner = THIS_MODULE;
+ kobject_set_name(&port->cdev.kobj, "umad%d", port->dev_num);
+ if (cdev_add(&port->cdev, base, 1))
goto err_cdev;
port->dev = device_create(umad_class, device->dma_device,
- port->cdev->dev, port,
+ port->cdev.dev, port,
"umad%d", port->dev_num);
if (IS_ERR(port->dev))
goto err_cdev;
@@ -1028,17 +1038,15 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
if (device_create_file(port->dev, &dev_attr_port))
goto err_dev;
- port->sm_cdev = cdev_alloc();
- if (!port->sm_cdev)
- goto err_dev;
- port->sm_cdev->owner = THIS_MODULE;
- port->sm_cdev->ops = &umad_sm_fops;
- kobject_set_name(&port->sm_cdev->kobj, "issm%d", port->dev_num);
- if (cdev_add(port->sm_cdev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1))
+ base += IB_UMAD_MAX_PORTS;
+ cdev_init(&port->sm_cdev, &umad_sm_fops);
+ port->sm_cdev.owner = THIS_MODULE;
+ kobject_set_name(&port->sm_cdev.kobj, "issm%d", port->dev_num);
+ if (cdev_add(&port->sm_cdev, base, 1))
goto err_sm_cdev;
port->sm_dev = device_create(umad_class, device->dma_device,
- port->sm_cdev->dev, port,
+ port->sm_cdev.dev, port,
"issm%d", port->dev_num);
if (IS_ERR(port->sm_dev))
goto err_sm_cdev;
@@ -1048,24 +1056,23 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
if (device_create_file(port->sm_dev, &dev_attr_port))
goto err_sm_dev;
- spin_lock(&port_lock);
- umad_port[port->dev_num] = port;
- spin_unlock(&port_lock);
-
return 0;
err_sm_dev:
- device_destroy(umad_class, port->sm_cdev->dev);
+ device_destroy(umad_class, port->sm_cdev.dev);
err_sm_cdev:
- cdev_del(port->sm_cdev);
+ cdev_del(&port->sm_cdev);
err_dev:
- device_destroy(umad_class, port->cdev->dev);
+ device_destroy(umad_class, port->cdev.dev);
err_cdev:
- cdev_del(port->cdev);
- clear_bit(port->dev_num, dev_map);
+ cdev_del(&port->cdev);
+ if (port->dev_num < IB_UMAD_MAX_PORTS)
+ clear_bit(devnum, dev_map);
+ else
+ clear_bit(devnum, overflow_map);
return -1;
}
@@ -1079,15 +1086,11 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
dev_set_drvdata(port->dev, NULL);
dev_set_drvdata(port->sm_dev, NULL);
- device_destroy(umad_class, port->cdev->dev);
- device_destroy(umad_class, port->sm_cdev->dev);
+ device_destroy(umad_class, port->cdev.dev);
+ device_destroy(umad_class, port->sm_cdev.dev);
- cdev_del(port->cdev);
- cdev_del(port->sm_cdev);
-
- spin_lock(&port_lock);
- umad_port[port->dev_num] = NULL;
- spin_unlock(&port_lock);
+ cdev_del(&port->cdev);
+ cdev_del(&port->sm_cdev);
mutex_lock(&port->file_mutex);
@@ -1106,7 +1109,10 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
mutex_unlock(&port->file_mutex);
- clear_bit(port->dev_num, dev_map);
+ if (port->dev_num < IB_UMAD_MAX_PORTS)
+ clear_bit(port->dev_num, dev_map);
+ else
+ clear_bit(port->dev_num - IB_UMAD_MAX_PORTS, overflow_map);
}
static void ib_umad_add_one(struct ib_device *device)
@@ -1185,7 +1191,7 @@ static int __init ib_umad_init(void)
goto out_chrdev;
}
- ret = class_create_file(umad_class, &class_attr_abi_version);
+ ret = class_create_file(umad_class, &class_attr_abi_version.attr);
if (ret) {
printk(KERN_ERR "user_mad: couldn't create abi_version attribute\n");
goto out_class;
@@ -1214,6 +1220,8 @@ static void __exit ib_umad_cleanup(void)
ib_unregister_client(&umad_client);
class_destroy(umad_class);
unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2);
+ if (overflow_maj)
+ unregister_chrdev_region(overflow_maj, IB_UMAD_MAX_PORTS * 2);
}
module_init(ib_umad_init);
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index b3ea9587dc80..a078e5624d22 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -41,6 +41,7 @@
#include <linux/idr.h>
#include <linux/mutex.h>
#include <linux/completion.h>
+#include <linux/cdev.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_umem.h>
@@ -69,23 +70,23 @@
struct ib_uverbs_device {
struct kref ref;
+ int num_comp_vectors;
struct completion comp;
- int devnum;
- struct cdev *cdev;
struct device *dev;
struct ib_device *ib_dev;
- int num_comp_vectors;
+ int devnum;
+ struct cdev cdev;
};
struct ib_uverbs_event_file {
struct kref ref;
+ int is_async;
struct ib_uverbs_file *uverbs_file;
spinlock_t lock;
+ int is_closed;
wait_queue_head_t poll_wait;
struct fasync_struct *async_queue;
struct list_head event_list;
- int is_async;
- int is_closed;
};
struct ib_uverbs_file {
@@ -145,7 +146,7 @@ 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);
+ int is_async);
struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd);
void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 112d3970222a..f71cf138d674 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -301,10 +301,15 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
resp.num_comp_vectors = file->device->num_comp_vectors;
- filp = ib_uverbs_alloc_event_file(file, 1, &resp.async_fd);
+ ret = get_unused_fd();
+ if (ret < 0)
+ goto err_free;
+ resp.async_fd = ret;
+
+ filp = ib_uverbs_alloc_event_file(file, 1);
if (IS_ERR(filp)) {
ret = PTR_ERR(filp);
- goto err_free;
+ goto err_fd;
}
if (copy_to_user((void __user *) (unsigned long) cmd.response,
@@ -332,9 +337,11 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
return in_len;
err_file:
- put_unused_fd(resp.async_fd);
fput(filp);
+err_fd:
+ put_unused_fd(resp.async_fd);
+
err_free:
ibdev->dealloc_ucontext(ucontext);
@@ -715,6 +722,7 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file,
struct ib_uverbs_create_comp_channel cmd;
struct ib_uverbs_create_comp_channel_resp resp;
struct file *filp;
+ int ret;
if (out_len < sizeof resp)
return -ENOSPC;
@@ -722,9 +730,16 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file,
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- filp = ib_uverbs_alloc_event_file(file, 0, &resp.fd);
- if (IS_ERR(filp))
+ ret = get_unused_fd();
+ if (ret < 0)
+ return ret;
+ resp.fd = ret;
+
+ filp = ib_uverbs_alloc_event_file(file, 0);
+ if (IS_ERR(filp)) {
+ put_unused_fd(resp.fd);
return PTR_ERR(filp);
+ }
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp)) {
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 5f284ffd430e..d805cf365c8d 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -42,8 +42,8 @@
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/file.h>
-#include <linux/mount.h>
#include <linux/cdev.h>
+#include <linux/anon_inodes.h>
#include <asm/uaccess.h>
@@ -53,8 +53,6 @@ MODULE_AUTHOR("Roland Dreier");
MODULE_DESCRIPTION("InfiniBand userspace verbs access");
MODULE_LICENSE("Dual BSD/GPL");
-#define INFINIBANDEVENTFS_MAGIC 0x49426576 /* "IBev" */
-
enum {
IB_UVERBS_MAJOR = 231,
IB_UVERBS_BASE_MINOR = 192,
@@ -75,44 +73,41 @@ DEFINE_IDR(ib_uverbs_qp_idr);
DEFINE_IDR(ib_uverbs_srq_idr);
static DEFINE_SPINLOCK(map_lock);
-static struct ib_uverbs_device *dev_table[IB_UVERBS_MAX_DEVICES];
static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
const char __user *buf, int in_len,
int out_len) = {
- [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context,
- [IB_USER_VERBS_CMD_QUERY_DEVICE] = ib_uverbs_query_device,
- [IB_USER_VERBS_CMD_QUERY_PORT] = ib_uverbs_query_port,
- [IB_USER_VERBS_CMD_ALLOC_PD] = ib_uverbs_alloc_pd,
- [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd,
- [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr,
- [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr,
+ [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context,
+ [IB_USER_VERBS_CMD_QUERY_DEVICE] = ib_uverbs_query_device,
+ [IB_USER_VERBS_CMD_QUERY_PORT] = ib_uverbs_query_port,
+ [IB_USER_VERBS_CMD_ALLOC_PD] = ib_uverbs_alloc_pd,
+ [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd,
+ [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr,
+ [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr,
[IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel,
- [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq,
- [IB_USER_VERBS_CMD_RESIZE_CQ] = ib_uverbs_resize_cq,
- [IB_USER_VERBS_CMD_POLL_CQ] = ib_uverbs_poll_cq,
- [IB_USER_VERBS_CMD_REQ_NOTIFY_CQ] = ib_uverbs_req_notify_cq,
- [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq,
- [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp,
- [IB_USER_VERBS_CMD_QUERY_QP] = ib_uverbs_query_qp,
- [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp,
- [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp,
- [IB_USER_VERBS_CMD_POST_SEND] = ib_uverbs_post_send,
- [IB_USER_VERBS_CMD_POST_RECV] = ib_uverbs_post_recv,
- [IB_USER_VERBS_CMD_POST_SRQ_RECV] = ib_uverbs_post_srq_recv,
- [IB_USER_VERBS_CMD_CREATE_AH] = ib_uverbs_create_ah,
- [IB_USER_VERBS_CMD_DESTROY_AH] = ib_uverbs_destroy_ah,
- [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast,
- [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast,
- [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq,
- [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq,
- [IB_USER_VERBS_CMD_QUERY_SRQ] = ib_uverbs_query_srq,
- [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq,
+ [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq,
+ [IB_USER_VERBS_CMD_RESIZE_CQ] = ib_uverbs_resize_cq,
+ [IB_USER_VERBS_CMD_POLL_CQ] = ib_uverbs_poll_cq,
+ [IB_USER_VERBS_CMD_REQ_NOTIFY_CQ] = ib_uverbs_req_notify_cq,
+ [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq,
+ [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp,
+ [IB_USER_VERBS_CMD_QUERY_QP] = ib_uverbs_query_qp,
+ [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp,
+ [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp,
+ [IB_USER_VERBS_CMD_POST_SEND] = ib_uverbs_post_send,
+ [IB_USER_VERBS_CMD_POST_RECV] = ib_uverbs_post_recv,
+ [IB_USER_VERBS_CMD_POST_SRQ_RECV] = ib_uverbs_post_srq_recv,
+ [IB_USER_VERBS_CMD_CREATE_AH] = ib_uverbs_create_ah,
+ [IB_USER_VERBS_CMD_DESTROY_AH] = ib_uverbs_destroy_ah,
+ [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast,
+ [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast,
+ [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq,
+ [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq,
+ [IB_USER_VERBS_CMD_QUERY_SRQ] = ib_uverbs_query_srq,
+ [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq,
};
-static struct vfsmount *uverbs_event_mnt;
-
static void ib_uverbs_add_one(struct ib_device *device);
static void ib_uverbs_remove_one(struct ib_device *device);
@@ -370,7 +365,7 @@ static int ib_uverbs_event_close(struct inode *inode, struct file *filp)
static const struct file_operations uverbs_event_fops = {
.owner = THIS_MODULE,
- .read = ib_uverbs_event_read,
+ .read = ib_uverbs_event_read,
.poll = ib_uverbs_event_poll,
.release = ib_uverbs_event_close,
.fasync = ib_uverbs_event_fasync
@@ -489,12 +484,10 @@ void ib_uverbs_event_handler(struct ib_event_handler *handler,
}
struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
- int is_async, int *fd)
+ int is_async)
{
struct ib_uverbs_event_file *ev_file;
- struct path path;
struct file *filp;
- int ret;
ev_file = kmalloc(sizeof *ev_file, GFP_KERNEL);
if (!ev_file)
@@ -509,38 +502,12 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
ev_file->is_async = is_async;
ev_file->is_closed = 0;
- *fd = get_unused_fd();
- if (*fd < 0) {
- ret = *fd;
- goto err;
- }
-
- /*
- * fops_get() can't fail here, because we're coming from a
- * system call on a uverbs file, which will already have a
- * module reference.
- */
- path.mnt = uverbs_event_mnt;
- path.dentry = uverbs_event_mnt->mnt_root;
- path_get(&path);
- filp = alloc_file(&path, FMODE_READ, fops_get(&uverbs_event_fops));
- if (!filp) {
- ret = -ENFILE;
- goto err_fd;
- }
-
- filp->private_data = ev_file;
+ filp = anon_inode_getfile("[infinibandevent]", &uverbs_event_fops,
+ ev_file, O_RDONLY);
+ if (IS_ERR(filp))
+ kfree(ev_file);
return filp;
-
-err_fd:
- fops_put(&uverbs_event_fops);
- path_put(&path);
- put_unused_fd(*fd);
-
-err:
- kfree(ev_file);
- return ERR_PTR(ret);
}
/*
@@ -617,14 +584,12 @@ static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma)
/*
* ib_uverbs_open() does not need the BKL:
*
- * - dev_table[] accesses are protected by map_lock, the
- * ib_uverbs_device structures are properly reference counted, and
+ * - the ib_uverbs_device structures are properly reference counted and
* everything else is purely local to the file being created, so
* races against other open calls are not a problem;
* - there is no ioctl method to race against;
- * - the device is added to dev_table[] as the last part of module
- * initialization, the open method will either immediately run
- * -ENXIO, or all required initialization will be done.
+ * - the open method will either immediately run -ENXIO, or all
+ * required initialization will be done.
*/
static int ib_uverbs_open(struct inode *inode, struct file *filp)
{
@@ -632,13 +597,10 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
struct ib_uverbs_file *file;
int ret;
- spin_lock(&map_lock);
- dev = dev_table[iminor(inode) - IB_UVERBS_BASE_MINOR];
+ dev = container_of(inode->i_cdev, struct ib_uverbs_device, cdev);
if (dev)
kref_get(&dev->ref);
- spin_unlock(&map_lock);
-
- if (!dev)
+ else
return -ENXIO;
if (!try_module_get(dev->ib_dev->owner)) {
@@ -685,17 +647,17 @@ static int ib_uverbs_close(struct inode *inode, struct file *filp)
}
static const struct file_operations uverbs_fops = {
- .owner = THIS_MODULE,
- .write = ib_uverbs_write,
- .open = ib_uverbs_open,
+ .owner = THIS_MODULE,
+ .write = ib_uverbs_write,
+ .open = ib_uverbs_open,
.release = ib_uverbs_close
};
static const struct file_operations uverbs_mmap_fops = {
- .owner = THIS_MODULE,
- .write = ib_uverbs_write,
+ .owner = THIS_MODULE,
+ .write = ib_uverbs_write,
.mmap = ib_uverbs_mmap,
- .open = ib_uverbs_open,
+ .open = ib_uverbs_open,
.release = ib_uverbs_close
};
@@ -729,14 +691,41 @@ static ssize_t show_dev_abi_version(struct device *device,
}
static DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL);
-static ssize_t show_abi_version(struct class *class, char *buf)
+static CLASS_ATTR_STRING(abi_version, S_IRUGO,
+ __stringify(IB_USER_VERBS_ABI_VERSION));
+
+static dev_t overflow_maj;
+static DECLARE_BITMAP(overflow_map, IB_UVERBS_MAX_DEVICES);
+
+/*
+ * If we have more than IB_UVERBS_MAX_DEVICES, dynamically overflow by
+ * requesting a new major number and doubling the number of max devices we
+ * support. It's stupid, but simple.
+ */
+static int find_overflow_devnum(void)
{
- return sprintf(buf, "%d\n", IB_USER_VERBS_ABI_VERSION);
+ int ret;
+
+ if (!overflow_maj) {
+ ret = alloc_chrdev_region(&overflow_maj, 0, IB_UVERBS_MAX_DEVICES,
+ "infiniband_verbs");
+ if (ret) {
+ printk(KERN_ERR "user_verbs: couldn't register dynamic device number\n");
+ return ret;
+ }
+ }
+
+ ret = find_first_zero_bit(overflow_map, IB_UVERBS_MAX_DEVICES);
+ if (ret >= IB_UVERBS_MAX_DEVICES)
+ return -1;
+
+ return ret;
}
-static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
static void ib_uverbs_add_one(struct ib_device *device)
{
+ int devnum;
+ dev_t base;
struct ib_uverbs_device *uverbs_dev;
if (!device->alloc_ucontext)
@@ -750,28 +739,36 @@ static void ib_uverbs_add_one(struct ib_device *device)
init_completion(&uverbs_dev->comp);
spin_lock(&map_lock);
- uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
- if (uverbs_dev->devnum >= IB_UVERBS_MAX_DEVICES) {
+ devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
+ if (devnum >= IB_UVERBS_MAX_DEVICES) {
spin_unlock(&map_lock);
- goto err;
+ devnum = find_overflow_devnum();
+ if (devnum < 0)
+ goto err;
+
+ spin_lock(&map_lock);
+ uverbs_dev->devnum = devnum + IB_UVERBS_MAX_DEVICES;
+ base = devnum + overflow_maj;
+ set_bit(devnum, overflow_map);
+ } else {
+ uverbs_dev->devnum = devnum;
+ base = devnum + IB_UVERBS_BASE_DEV;
+ set_bit(devnum, dev_map);
}
- set_bit(uverbs_dev->devnum, dev_map);
spin_unlock(&map_lock);
uverbs_dev->ib_dev = device;
uverbs_dev->num_comp_vectors = device->num_comp_vectors;
- uverbs_dev->cdev = cdev_alloc();
- if (!uverbs_dev->cdev)
- goto err;
- uverbs_dev->cdev->owner = THIS_MODULE;
- uverbs_dev->cdev->ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops;
- kobject_set_name(&uverbs_dev->cdev->kobj, "uverbs%d", uverbs_dev->devnum);
- if (cdev_add(uverbs_dev->cdev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1))
+ cdev_init(&uverbs_dev->cdev, NULL);
+ uverbs_dev->cdev.owner = THIS_MODULE;
+ uverbs_dev->cdev.ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops;
+ kobject_set_name(&uverbs_dev->cdev.kobj, "uverbs%d", uverbs_dev->devnum);
+ if (cdev_add(&uverbs_dev->cdev, base, 1))
goto err_cdev;
uverbs_dev->dev = device_create(uverbs_class, device->dma_device,
- uverbs_dev->cdev->dev, uverbs_dev,
+ uverbs_dev->cdev.dev, uverbs_dev,
"uverbs%d", uverbs_dev->devnum);
if (IS_ERR(uverbs_dev->dev))
goto err_cdev;
@@ -781,20 +778,19 @@ static void ib_uverbs_add_one(struct ib_device *device)
if (device_create_file(uverbs_dev->dev, &dev_attr_abi_version))
goto err_class;
- spin_lock(&map_lock);
- dev_table[uverbs_dev->devnum] = uverbs_dev;
- spin_unlock(&map_lock);
-
ib_set_client_data(device, &uverbs_client, uverbs_dev);
return;
err_class:
- device_destroy(uverbs_class, uverbs_dev->cdev->dev);
+ device_destroy(uverbs_class, uverbs_dev->cdev.dev);
err_cdev:
- cdev_del(uverbs_dev->cdev);
- clear_bit(uverbs_dev->devnum, dev_map);
+ cdev_del(&uverbs_dev->cdev);
+ if (uverbs_dev->devnum < IB_UVERBS_MAX_DEVICES)
+ clear_bit(devnum, dev_map);
+ else
+ clear_bit(devnum, overflow_map);
err:
kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
@@ -811,35 +807,19 @@ static void ib_uverbs_remove_one(struct ib_device *device)
return;
dev_set_drvdata(uverbs_dev->dev, NULL);
- device_destroy(uverbs_class, uverbs_dev->cdev->dev);
- cdev_del(uverbs_dev->cdev);
+ device_destroy(uverbs_class, uverbs_dev->cdev.dev);
+ cdev_del(&uverbs_dev->cdev);
- spin_lock(&map_lock);
- dev_table[uverbs_dev->devnum] = NULL;
- spin_unlock(&map_lock);
-
- clear_bit(uverbs_dev->devnum, dev_map);
+ if (uverbs_dev->devnum < IB_UVERBS_MAX_DEVICES)
+ clear_bit(uverbs_dev->devnum, dev_map);
+ else
+ clear_bit(uverbs_dev->devnum - IB_UVERBS_MAX_DEVICES, overflow_map);
kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
wait_for_completion(&uverbs_dev->comp);
kfree(uverbs_dev);
}
-static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data,
- struct vfsmount *mnt)
-{
- return get_sb_pseudo(fs_type, "infinibandevent:", NULL,
- INFINIBANDEVENTFS_MAGIC, mnt);
-}
-
-static struct file_system_type uverbs_event_fs = {
- /* No owner field so module can be unloaded */
- .name = "infinibandeventfs",
- .get_sb = uverbs_event_get_sb,
- .kill_sb = kill_litter_super
-};
-
static int __init ib_uverbs_init(void)
{
int ret;
@@ -858,39 +838,20 @@ static int __init ib_uverbs_init(void)
goto out_chrdev;
}
- ret = class_create_file(uverbs_class, &class_attr_abi_version);
+ ret = class_create_file(uverbs_class, &class_attr_abi_version.attr);
if (ret) {
printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n");
goto out_class;
}
- ret = register_filesystem(&uverbs_event_fs);
- if (ret) {
- printk(KERN_ERR "user_verbs: couldn't register infinibandeventfs\n");
- goto out_class;
- }
-
- uverbs_event_mnt = kern_mount(&uverbs_event_fs);
- if (IS_ERR(uverbs_event_mnt)) {
- ret = PTR_ERR(uverbs_event_mnt);
- printk(KERN_ERR "user_verbs: couldn't mount infinibandeventfs\n");
- goto out_fs;
- }
-
ret = ib_register_client(&uverbs_client);
if (ret) {
printk(KERN_ERR "user_verbs: couldn't register client\n");
- goto out_mnt;
+ goto out_class;
}
return 0;
-out_mnt:
- mntput(uverbs_event_mnt);
-
-out_fs:
- unregister_filesystem(&uverbs_event_fs);
-
out_class:
class_destroy(uverbs_class);
@@ -904,10 +865,10 @@ out:
static void __exit ib_uverbs_cleanup(void)
{
ib_unregister_client(&uverbs_client);
- mntput(uverbs_event_mnt);
- unregister_filesystem(&uverbs_event_fs);
class_destroy(uverbs_class);
unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES);
+ if (overflow_maj)
+ unregister_chrdev_region(overflow_maj, IB_UVERBS_MAX_DEVICES);
idr_destroy(&ib_uverbs_pd_idr);
idr_destroy(&ib_uverbs_mr_idr);
idr_destroy(&ib_uverbs_mw_idr);
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 0677fc7dfd51..a28e862f2d68 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -109,7 +109,6 @@ int cxio_hal_cq_op(struct cxio_rdev *rdev_p, struct t3_cq *cq,
while (!CQ_VLD_ENTRY(rptr, cq->size_log2, cqe)) {
udelay(1);
if (i++ > 1000000) {
- BUG_ON(1);
printk(KERN_ERR "%s: stalled rnic\n",
rdev_p->dev_name);
return -EIO;
@@ -155,7 +154,7 @@ static int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev_p, u32 qpid)
return iwch_cxgb3_ofld_send(rdev_p->t3cdev_p, skb);
}
-int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
+int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq, int kernel)
{
struct rdma_cq_setup setup;
int size = (1UL << (cq->size_log2)) * sizeof(struct t3_cqe);
@@ -163,12 +162,12 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
cq->cqid = cxio_hal_get_cqid(rdev_p->rscp);
if (!cq->cqid)
return -ENOMEM;
- cq->sw_queue = kzalloc(size, GFP_KERNEL);
- if (!cq->sw_queue)
- return -ENOMEM;
- cq->queue = dma_alloc_coherent(&(rdev_p->rnic_info.pdev->dev),
- (1UL << (cq->size_log2)) *
- sizeof(struct t3_cqe),
+ if (kernel) {
+ cq->sw_queue = kzalloc(size, GFP_KERNEL);
+ if (!cq->sw_queue)
+ return -ENOMEM;
+ }
+ cq->queue = dma_alloc_coherent(&(rdev_p->rnic_info.pdev->dev), size,
&(cq->dma_addr), GFP_KERNEL);
if (!cq->queue) {
kfree(cq->sw_queue);
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h
index f3d440cc68f2..073373c2c560 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h
@@ -53,7 +53,7 @@
#define T3_MAX_PBL_SIZE 256
#define T3_MAX_RQ_SIZE 1024
#define T3_MAX_QP_DEPTH (T3_MAX_RQ_SIZE-1)
-#define T3_MAX_CQ_DEPTH 8192
+#define T3_MAX_CQ_DEPTH 262144
#define T3_MAX_NUM_STAG (1<<15)
#define T3_MAX_MR_SIZE 0x100000000ULL
#define T3_PAGESIZE_MASK 0xffff000 /* 4KB-128MB */
@@ -157,7 +157,7 @@ int cxio_rdev_open(struct cxio_rdev *rdev);
void cxio_rdev_close(struct cxio_rdev *rdev);
int cxio_hal_cq_op(struct cxio_rdev *rdev, struct t3_cq *cq,
enum t3_cq_opcode op, u32 credit);
-int cxio_create_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
+int cxio_create_cq(struct cxio_rdev *rdev, struct t3_cq *cq, int kernel);
int cxio_destroy_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
int cxio_resize_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
void cxio_release_ucontext(struct cxio_rdev *rdev, struct cxio_ucontext *uctx);
diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h
index a197a5b7ac7f..15073b2da1c5 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_wr.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h
@@ -730,7 +730,22 @@ struct t3_cq {
static inline void cxio_set_wq_in_error(struct t3_wq *wq)
{
- wq->queue->wq_in_err.err = 1;
+ wq->queue->wq_in_err.err |= 1;
+}
+
+static inline void cxio_disable_wq_db(struct t3_wq *wq)
+{
+ wq->queue->wq_in_err.err |= 2;
+}
+
+static inline void cxio_enable_wq_db(struct t3_wq *wq)
+{
+ wq->queue->wq_in_err.err &= ~2;
+}
+
+static inline int cxio_wq_db_enabled(struct t3_wq *wq)
+{
+ return !(wq->queue->wq_in_err.err & 2);
}
static inline struct t3_cqe *cxio_next_hw_cqe(struct t3_cq *cq)
diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c
index b0ea0105ddf6..63f975f3e30f 100644
--- a/drivers/infiniband/hw/cxgb3/iwch.c
+++ b/drivers/infiniband/hw/cxgb3/iwch.c
@@ -65,6 +65,46 @@ struct cxgb3_client t3c_client = {
static LIST_HEAD(dev_list);
static DEFINE_MUTEX(dev_mutex);
+static int disable_qp_db(int id, void *p, void *data)
+{
+ struct iwch_qp *qhp = p;
+
+ cxio_disable_wq_db(&qhp->wq);
+ return 0;
+}
+
+static int enable_qp_db(int id, void *p, void *data)
+{
+ struct iwch_qp *qhp = p;
+
+ if (data)
+ ring_doorbell(qhp->rhp->rdev.ctrl_qp.doorbell, qhp->wq.qpid);
+ cxio_enable_wq_db(&qhp->wq);
+ return 0;
+}
+
+static void disable_dbs(struct iwch_dev *rnicp)
+{
+ spin_lock_irq(&rnicp->lock);
+ idr_for_each(&rnicp->qpidr, disable_qp_db, NULL);
+ spin_unlock_irq(&rnicp->lock);
+}
+
+static void enable_dbs(struct iwch_dev *rnicp, int ring_db)
+{
+ spin_lock_irq(&rnicp->lock);
+ idr_for_each(&rnicp->qpidr, enable_qp_db,
+ (void *)(unsigned long)ring_db);
+ spin_unlock_irq(&rnicp->lock);
+}
+
+static void iwch_db_drop_task(struct work_struct *work)
+{
+ struct iwch_dev *rnicp = container_of(work, struct iwch_dev,
+ db_drop_task.work);
+ enable_dbs(rnicp, 1);
+}
+
static void rnic_init(struct iwch_dev *rnicp)
{
PDBG("%s iwch_dev %p\n", __func__, rnicp);
@@ -72,6 +112,7 @@ static void rnic_init(struct iwch_dev *rnicp)
idr_init(&rnicp->qpidr);
idr_init(&rnicp->mmidr);
spin_lock_init(&rnicp->lock);
+ INIT_DELAYED_WORK(&rnicp->db_drop_task, iwch_db_drop_task);
rnicp->attr.max_qps = T3_MAX_NUM_QP - 32;
rnicp->attr.max_wrs = T3_MAX_QP_DEPTH;
@@ -147,6 +188,9 @@ static void close_rnic_dev(struct t3cdev *tdev)
mutex_lock(&dev_mutex);
list_for_each_entry_safe(dev, tmp, &dev_list, entry) {
if (dev->rdev.t3cdev_p == tdev) {
+ dev->rdev.flags = CXIO_ERROR_FATAL;
+ synchronize_net();
+ cancel_delayed_work_sync(&dev->db_drop_task);
list_del(&dev->entry);
iwch_unregister_device(dev);
cxio_rdev_close(&dev->rdev);
@@ -165,7 +209,8 @@ static void iwch_event_handler(struct t3cdev *tdev, u32 evt, u32 port_id)
struct cxio_rdev *rdev = tdev->ulp;
struct iwch_dev *rnicp;
struct ib_event event;
- u32 portnum = port_id + 1;
+ u32 portnum = port_id + 1;
+ int dispatch = 0;
if (!rdev)
return;
@@ -173,22 +218,51 @@ static void iwch_event_handler(struct t3cdev *tdev, u32 evt, u32 port_id)
switch (evt) {
case OFFLOAD_STATUS_DOWN: {
rdev->flags = CXIO_ERROR_FATAL;
+ synchronize_net();
event.event = IB_EVENT_DEVICE_FATAL;
+ dispatch = 1;
break;
}
case OFFLOAD_PORT_DOWN: {
event.event = IB_EVENT_PORT_ERR;
+ dispatch = 1;
break;
}
case OFFLOAD_PORT_UP: {
event.event = IB_EVENT_PORT_ACTIVE;
+ dispatch = 1;
+ break;
+ }
+ case OFFLOAD_DB_FULL: {
+ disable_dbs(rnicp);
+ break;
+ }
+ case OFFLOAD_DB_EMPTY: {
+ enable_dbs(rnicp, 1);
+ break;
+ }
+ case OFFLOAD_DB_DROP: {
+ unsigned long delay = 1000;
+ unsigned short r;
+
+ disable_dbs(rnicp);
+ get_random_bytes(&r, 2);
+ delay += r & 1023;
+
+ /*
+ * delay is between 1000-2023 usecs.
+ */
+ schedule_delayed_work(&rnicp->db_drop_task,
+ usecs_to_jiffies(delay));
break;
}
}
- event.device = &rnicp->ibdev;
- event.element.port_num = portnum;
- ib_dispatch_event(&event);
+ if (dispatch) {
+ event.device = &rnicp->ibdev;
+ event.element.port_num = portnum;
+ ib_dispatch_event(&event);
+ }
return;
}
diff --git a/drivers/infiniband/hw/cxgb3/iwch.h b/drivers/infiniband/hw/cxgb3/iwch.h
index 84735506333f..a1c44578e039 100644
--- a/drivers/infiniband/hw/cxgb3/iwch.h
+++ b/drivers/infiniband/hw/cxgb3/iwch.h
@@ -36,6 +36,7 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/idr.h>
+#include <linux/workqueue.h>
#include <rdma/ib_verbs.h>
@@ -110,6 +111,7 @@ struct iwch_dev {
struct idr mmidr;
spinlock_t lock;
struct list_head entry;
+ struct delayed_work db_drop_task;
};
static inline struct iwch_dev *to_iwch_dev(struct ib_device *ibdev)
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 66b41351910a..d94388b81a40 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -1371,15 +1371,8 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
tim.mac_addr = req->dst_mac;
tim.vlan_tag = ntohs(req->vlan_tag);
if (tdev->ctl(tdev, GET_IFF_FROM_MAC, &tim) < 0 || !tim.dev) {
- printk(KERN_ERR
- "%s bad dst mac %02x %02x %02x %02x %02x %02x\n",
- __func__,
- req->dst_mac[0],
- req->dst_mac[1],
- req->dst_mac[2],
- req->dst_mac[3],
- req->dst_mac[4],
- req->dst_mac[5]);
+ printk(KERN_ERR "%s bad dst mac %pM\n",
+ __func__, req->dst_mac);
goto reject;
}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index ed7175549ebd..47b35c6608d2 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -187,7 +187,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
entries = roundup_pow_of_two(entries);
chp->cq.size_log2 = ilog2(entries);
- if (cxio_create_cq(&rhp->rdev, &chp->cq)) {
+ if (cxio_create_cq(&rhp->rdev, &chp->cq, !ucontext)) {
kfree(chp);
return ERR_PTR(-ENOMEM);
}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index 3eb8cecf81d7..b4d893de3650 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -452,7 +452,8 @@ int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
++(qhp->wq.sq_wptr);
}
spin_unlock_irqrestore(&qhp->lock, flag);
- ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);
+ if (cxio_wq_db_enabled(&qhp->wq))
+ ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);
out:
if (err)
@@ -514,7 +515,8 @@ int iwch_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
num_wrs--;
}
spin_unlock_irqrestore(&qhp->lock, flag);
- ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);
+ if (cxio_wq_db_enabled(&qhp->wq))
+ ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);
out:
if (err)
@@ -597,7 +599,8 @@ int iwch_bind_mw(struct ib_qp *qp,
++(qhp->wq.sq_wptr);
spin_unlock_irqrestore(&qhp->lock, flag);
- ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);
+ if (cxio_wq_db_enabled(&qhp->wq))
+ ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);
return err;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index 42be0b15084b..b2b6fea2b141 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -548,11 +548,10 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq)
struct ehca_eq *eq = &shca->eq;
struct ehca_eqe_cache_entry *eqe_cache = eq->eqe_cache;
u64 eqe_value, ret;
- unsigned long flags;
int eqe_cnt, i;
int eq_empty = 0;
- spin_lock_irqsave(&eq->irq_spinlock, flags);
+ spin_lock(&eq->irq_spinlock);
if (is_irq) {
const int max_query_cnt = 100;
int query_cnt = 0;
@@ -643,7 +642,7 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq)
} while (1);
unlock_irq_spinlock:
- spin_unlock_irqrestore(&eq->irq_spinlock, flags);
+ spin_unlock(&eq->irq_spinlock);
}
void ehca_tasklet_eq(unsigned long data)
diff --git a/drivers/infiniband/hw/ehca/ehca_qes.h b/drivers/infiniband/hw/ehca/ehca_qes.h
index 5d28e3e98a20..90c4efa67586 100644
--- a/drivers/infiniband/hw/ehca/ehca_qes.h
+++ b/drivers/infiniband/hw/ehca/ehca_qes.h
@@ -46,7 +46,7 @@
#include "ehca_tools.h"
-/* virtual scatter gather entry to specify remote adresses with length */
+/* virtual scatter gather entry to specify remote addresses with length */
struct ehca_vsgentry {
u64 vaddr;
u32 lkey;
@@ -148,7 +148,7 @@ struct ehca_wqe {
u32 immediate_data;
union {
struct {
- u64 remote_virtual_adress;
+ u64 remote_virtual_address;
u32 rkey;
u32 reserved;
u64 atomic_1st_op_dma_len;
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 0338f1fabe8a..b105f664d3ef 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -55,9 +55,7 @@ static struct kmem_cache *qp_cache;
/*
* attributes not supported by query qp
*/
-#define QP_ATTR_QUERY_NOT_SUPPORTED (IB_QP_MAX_DEST_RD_ATOMIC | \
- IB_QP_MAX_QP_RD_ATOMIC | \
- IB_QP_ACCESS_FLAGS | \
+#define QP_ATTR_QUERY_NOT_SUPPORTED (IB_QP_ACCESS_FLAGS | \
IB_QP_EN_SQD_ASYNC_NOTIFY)
/*
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index e3ec7fdd67bd..9a3fbfca9b41 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -269,7 +269,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
/* no break is intentional here */
case IB_QPT_RC:
/* TODO: atomic not implemented */
- wqe_p->u.nud.remote_virtual_adress =
+ wqe_p->u.nud.remote_virtual_address =
send_wr->wr.rdma.remote_addr;
wqe_p->u.nud.rkey = send_wr->wr.rdma.rkey;
diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c
index 8c1213f8916a..dba8f9f8b996 100644
--- a/drivers/infiniband/hw/ehca/ehca_sqp.c
+++ b/drivers/infiniband/hw/ehca/ehca_sqp.c
@@ -222,7 +222,7 @@ int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
{
int ret;
- if (!port_num || port_num > ibdev->phys_port_cnt)
+ if (!port_num || port_num > ibdev->phys_port_cnt || !in_wc)
return IB_MAD_RESULT_FAILURE;
/* accept only pma request */
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index b3684060465e..100da8542bba 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -346,10 +346,8 @@ static int ipathfs_fill_super(struct super_block *sb, void *data,
list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
spin_unlock_irqrestore(&ipath_devs_lock, flags);
ret = create_device_files(sb, dd);
- if (ret) {
- deactivate_locked_super(sb);
+ if (ret)
goto bail;
- }
spin_lock_irqsave(&ipath_devs_lock, flags);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c
index 82878e348627..eb7d59abd12d 100644
--- a/drivers/infiniband/hw/ipath/ipath_user_pages.c
+++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c
@@ -59,8 +59,7 @@ static int __get_user_pages(unsigned long start_page, size_t num_pages,
size_t got;
int ret;
- lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >>
- PAGE_SHIFT;
+ lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
if (num_pages > lock_limit) {
ret = -ENOMEM;
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 2a97c964b9ef..ae75389937d6 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1214,7 +1214,7 @@ out:
static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
void *wqe, unsigned *mlx_seg_len)
{
- struct ib_device *ib_dev = &to_mdev(sqp->qp.ibqp.device)->ib_dev;
+ struct ib_device *ib_dev = sqp->qp.ibqp.device;
struct mlx4_wqe_mlx_seg *mlx = wqe;
struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
@@ -1228,7 +1228,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
for (i = 0; i < wr->num_sge; ++i)
send_size += wr->sg_list[i].length;
- ib_ud_header_init(send_size, mlx4_ib_ah_grh_present(ah), &sqp->ud_header);
+ ib_ud_header_init(send_size, mlx4_ib_ah_grh_present(ah), 0, &sqp->ud_header);
sqp->ud_header.lrh.service_level =
be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28;
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index c10576fa60c1..d2d172e6289c 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -1494,7 +1494,7 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
u16 pkey;
ib_ud_header_init(256, /* assume a MAD */
- mthca_ah_grh_present(to_mah(wr->wr.ud.ah)),
+ mthca_ah_grh_present(to_mah(wr->wr.ud.ah)), 0,
&sqp->ud_header);
err = mthca_read_ah(dev, to_mah(wr->wr.ud.ah), &sqp->ud_header);
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index b9d09bafd6c1..4272c52e38a4 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -110,6 +110,7 @@ static unsigned int sysfs_idx_addr;
static struct pci_device_id nes_pci_table[] = {
{PCI_VENDOR_ID_NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020, PCI_ANY_ID, PCI_ANY_ID},
+ {PCI_VENDOR_ID_NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020_KR, PCI_ANY_ID, PCI_ANY_ID},
{0}
};
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index 98840564bb2f..cc78fee1dd51 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -64,8 +64,9 @@
* NetEffect PCI vendor id and NE010 PCI device id.
*/
#ifndef PCI_VENDOR_ID_NETEFFECT /* not in pci.ids yet */
-#define PCI_VENDOR_ID_NETEFFECT 0x1678
-#define PCI_DEVICE_ID_NETEFFECT_NE020 0x0100
+#define PCI_VENDOR_ID_NETEFFECT 0x1678
+#define PCI_DEVICE_ID_NETEFFECT_NE020 0x0100
+#define PCI_DEVICE_ID_NETEFFECT_NE020_KR 0x0110
#endif
#define NE020_REV 4
@@ -193,8 +194,8 @@ extern u32 cm_packets_created;
extern u32 cm_packets_received;
extern u32 cm_packets_dropped;
extern u32 cm_packets_retrans;
-extern u32 cm_listens_created;
-extern u32 cm_listens_destroyed;
+extern atomic_t cm_listens_created;
+extern atomic_t cm_listens_destroyed;
extern u32 cm_backlog_drops;
extern atomic_t cm_loopbacks;
extern atomic_t cm_nodes_created;
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 39468c277036..2a49ee40b520 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -67,8 +67,8 @@ u32 cm_packets_dropped;
u32 cm_packets_retrans;
u32 cm_packets_created;
u32 cm_packets_received;
-u32 cm_listens_created;
-u32 cm_listens_destroyed;
+atomic_t cm_listens_created;
+atomic_t cm_listens_destroyed;
u32 cm_backlog_drops;
atomic_t cm_loopbacks;
atomic_t cm_nodes_created;
@@ -1011,9 +1011,10 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
event.cm_info.loc_port =
loopback->loc_port;
event.cm_info.cm_id = loopback->cm_id;
+ add_ref_cm_node(loopback);
+ loopback->state = NES_CM_STATE_CLOSED;
cm_event_connect_error(&event);
cm_node->state = NES_CM_STATE_LISTENER_DESTROYED;
- loopback->state = NES_CM_STATE_CLOSED;
rem_ref_cm_node(cm_node->cm_core,
cm_node);
@@ -1042,7 +1043,7 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
kfree(listener);
listener = NULL;
ret = 0;
- cm_listens_destroyed++;
+ atomic_inc(&cm_listens_destroyed);
} else {
spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
}
@@ -3172,7 +3173,7 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node);
return err;
}
- cm_listens_created++;
+ atomic_inc(&cm_listens_created);
}
cm_id->add_ref(cm_id);
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index b1c2cbb88f09..925075557dc2 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -748,16 +748,28 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
if (hw_rev != NE020_REV) {
/* init serdes 0 */
- if (wide_ppm_offset && (nesadapter->phy_type[0] == NES_PHY_TYPE_CX4))
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000FFFAA);
- else
+ switch (nesadapter->phy_type[0]) {
+ case NES_PHY_TYPE_CX4:
+ if (wide_ppm_offset)
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000FFFAA);
+ else
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
+ break;
+ case NES_PHY_TYPE_KR:
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x00000000);
+ break;
+ case NES_PHY_TYPE_PUMA_1G:
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
-
- if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0);
sds |= 0x00000100;
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds);
+ break;
+ default:
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
+ break;
}
+
if (!OneG_Mode)
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0, 0x11110000);
@@ -778,6 +790,9 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
if (wide_ppm_offset)
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000FFFAA);
break;
+ case NES_PHY_TYPE_KR:
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x00000000);
+ break;
case NES_PHY_TYPE_PUMA_1G:
sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
sds |= 0x000000100;
@@ -1279,115 +1294,115 @@ int nes_destroy_cqp(struct nes_device *nesdev)
/**
- * nes_init_phy
+ * nes_init_1g_phy
*/
-int nes_init_phy(struct nes_device *nesdev)
+int nes_init_1g_phy(struct nes_device *nesdev, u8 phy_type, u8 phy_index)
{
- struct nes_adapter *nesadapter = nesdev->nesadapter;
u32 counter = 0;
- u32 sds;
- u32 mac_index = nesdev->mac_index;
- u32 tx_config = 0;
u16 phy_data;
- u32 temp_phy_data = 0;
- u32 temp_phy_data2 = 0;
- u8 phy_type = nesadapter->phy_type[mac_index];
- u8 phy_index = nesadapter->phy_index[mac_index];
-
- if ((nesadapter->OneG_Mode) &&
- (phy_type != NES_PHY_TYPE_PUMA_1G)) {
- nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index);
- if (phy_type == NES_PHY_TYPE_1G) {
- tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
- tx_config &= 0xFFFFFFE3;
- tx_config |= 0x04;
- nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
- }
+ int ret = 0;
- nes_read_1G_phy_reg(nesdev, 1, phy_index, &phy_data);
- nes_write_1G_phy_reg(nesdev, 23, phy_index, 0xb000);
+ nes_read_1G_phy_reg(nesdev, 1, phy_index, &phy_data);
+ nes_write_1G_phy_reg(nesdev, 23, phy_index, 0xb000);
- /* Reset the PHY */
- nes_write_1G_phy_reg(nesdev, 0, phy_index, 0x8000);
- udelay(100);
- counter = 0;
- do {
- nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
- if (counter++ > 100)
- break;
- } while (phy_data & 0x8000);
-
- /* Setting no phy loopback */
- phy_data &= 0xbfff;
- phy_data |= 0x1140;
- nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data);
+ /* Reset the PHY */
+ nes_write_1G_phy_reg(nesdev, 0, phy_index, 0x8000);
+ udelay(100);
+ counter = 0;
+ do {
nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
- nes_read_1G_phy_reg(nesdev, 0x17, phy_index, &phy_data);
- nes_read_1G_phy_reg(nesdev, 0x1e, phy_index, &phy_data);
-
- /* Setting the interrupt mask */
- nes_read_1G_phy_reg(nesdev, 0x19, phy_index, &phy_data);
- nes_write_1G_phy_reg(nesdev, 0x19, phy_index, 0xffee);
- nes_read_1G_phy_reg(nesdev, 0x19, phy_index, &phy_data);
+ if (counter++ > 100) {
+ ret = -1;
+ break;
+ }
+ } while (phy_data & 0x8000);
+
+ /* Setting no phy loopback */
+ phy_data &= 0xbfff;
+ phy_data |= 0x1140;
+ nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data);
+ nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
+ nes_read_1G_phy_reg(nesdev, 0x17, phy_index, &phy_data);
+ nes_read_1G_phy_reg(nesdev, 0x1e, phy_index, &phy_data);
+
+ /* Setting the interrupt mask */
+ nes_read_1G_phy_reg(nesdev, 0x19, phy_index, &phy_data);
+ nes_write_1G_phy_reg(nesdev, 0x19, phy_index, 0xffee);
+ nes_read_1G_phy_reg(nesdev, 0x19, phy_index, &phy_data);
+
+ /* turning on flow control */
+ nes_read_1G_phy_reg(nesdev, 4, phy_index, &phy_data);
+ nes_write_1G_phy_reg(nesdev, 4, phy_index, (phy_data & ~(0x03E0)) | 0xc00);
+ nes_read_1G_phy_reg(nesdev, 4, phy_index, &phy_data);
+
+ /* Clear Half duplex */
+ nes_read_1G_phy_reg(nesdev, 9, phy_index, &phy_data);
+ nes_write_1G_phy_reg(nesdev, 9, phy_index, phy_data & ~(0x0100));
+ nes_read_1G_phy_reg(nesdev, 9, phy_index, &phy_data);
+
+ nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
+ nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data | 0x0300);
+
+ return ret;
+}
- /* turning on flow control */
- nes_read_1G_phy_reg(nesdev, 4, phy_index, &phy_data);
- nes_write_1G_phy_reg(nesdev, 4, phy_index, (phy_data & ~(0x03E0)) | 0xc00);
- nes_read_1G_phy_reg(nesdev, 4, phy_index, &phy_data);
- /* Clear Half duplex */
- nes_read_1G_phy_reg(nesdev, 9, phy_index, &phy_data);
- nes_write_1G_phy_reg(nesdev, 9, phy_index, phy_data & ~(0x0100));
- nes_read_1G_phy_reg(nesdev, 9, phy_index, &phy_data);
+/**
+ * nes_init_2025_phy
+ */
+int nes_init_2025_phy(struct nes_device *nesdev, u8 phy_type, u8 phy_index)
+{
+ u32 temp_phy_data = 0;
+ u32 temp_phy_data2 = 0;
+ u32 counter = 0;
+ u32 sds;
+ u32 mac_index = nesdev->mac_index;
+ int ret = 0;
+ unsigned int first_attempt = 1;
- nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
- nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data | 0x0300);
+ /* Check firmware heartbeat */
+ nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ udelay(1500);
+ nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
+ temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- return 0;
+ if (temp_phy_data != temp_phy_data2) {
+ nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7fd);
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ if ((temp_phy_data & 0xff) > 0x20)
+ return 0;
+ printk(PFX "Reinitialize external PHY\n");
}
- if ((phy_type == NES_PHY_TYPE_IRIS) ||
- (phy_type == NES_PHY_TYPE_ARGUS) ||
- (phy_type == NES_PHY_TYPE_SFP_D)) {
- /* setup 10G MDIO operation */
- tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
- tx_config &= 0xFFFFFFE3;
- tx_config |= 0x15;
- nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
- }
- if ((phy_type == NES_PHY_TYPE_ARGUS) ||
- (phy_type == NES_PHY_TYPE_SFP_D)) {
- u32 first_time = 1;
+ /* no heartbeat, configure the PHY */
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0x0000, 0x8000);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0000);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052);
- /* Check firmware heartbeat */
- nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
- temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- udelay(1500);
- nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
- temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ switch (phy_type) {
+ case NES_PHY_TYPE_ARGUS:
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x000C);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0008);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0001);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0098);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00);
- if (temp_phy_data != temp_phy_data2) {
- nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7fd);
- temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- if ((temp_phy_data & 0xff) > 0x20)
- return 0;
- printk(PFX "Reinitializing PHY\n");
- }
+ /* setup LEDs */
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x0007);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x000A);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0009);
+ break;
- /* no heartbeat, configure the PHY */
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0x0000, 0x8000);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0000);
+ case NES_PHY_TYPE_SFP_D:
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052);
- if (phy_type == NES_PHY_TYPE_ARGUS) {
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x000C);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0008);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0001);
- } else {
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x0004);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0038);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0013);
- }
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x0004);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0038);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0013);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0098);
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00);
@@ -1395,71 +1410,136 @@ int nes_init_phy(struct nes_device *nesdev)
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x0007);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x000A);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0009);
+ break;
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0028, 0xA528);
+ case NES_PHY_TYPE_KR:
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x000C);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0010);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0013);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0080);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00);
+
+ /* setup LEDs */
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x000B);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x0003);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0004);
+
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0022, 0x406D);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0023, 0x0020);
+ break;
+ }
+
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0028, 0xA528);
- /* Bring PHY out of reset */
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0002);
+ /* Bring PHY out of reset */
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0002);
- /* Check for heartbeat */
- counter = 0;
- mdelay(690);
+ /* Check for heartbeat */
+ counter = 0;
+ mdelay(690);
+ nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ do {
+ if (counter++ > 150) {
+ printk(PFX "No PHY heartbeat\n");
+ break;
+ }
+ mdelay(1);
nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
+ temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ } while ((temp_phy_data2 == temp_phy_data));
+
+ /* wait for tracking */
+ counter = 0;
+ do {
+ nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7fd);
temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- do {
- if (counter++ > 150) {
- printk(PFX "No PHY heartbeat\n");
+ if (counter++ > 300) {
+ if (((temp_phy_data & 0xff) == 0x0) && first_attempt) {
+ first_attempt = 0;
+ counter = 0;
+ /* reset AMCC PHY and try again */
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x00c0);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x0040);
+ continue;
+ } else {
+ ret = 1;
break;
}
- mdelay(1);
- nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
- temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- } while ((temp_phy_data2 == temp_phy_data));
-
- /* wait for tracking */
- counter = 0;
- do {
- nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7fd);
- temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- if (counter++ > 300) {
- if (((temp_phy_data & 0xff) == 0x0) && first_time) {
- first_time = 0;
- counter = 0;
- /* reset AMCC PHY and try again */
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x00c0);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x0040);
- continue;
- } else {
- printk(PFX "PHY did not track\n");
- break;
- }
- }
- mdelay(10);
- } while ((temp_phy_data & 0xff) < 0x30);
-
- /* setup signal integrity */
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd003, 0x0000);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00D, 0x00FE);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00E, 0x0032);
+ }
+ mdelay(10);
+ } while ((temp_phy_data & 0xff) < 0x30);
+
+ /* setup signal integrity */
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd003, 0x0000);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00D, 0x00FE);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00E, 0x0032);
+ if (phy_type == NES_PHY_TYPE_KR) {
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00F, 0x000C);
+ } else {
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00F, 0x0002);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc314, 0x0063);
+ }
+
+ /* reset serdes */
+ sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + mac_index * 0x200);
+ sds |= 0x1;
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + mac_index * 0x200, sds);
+ sds &= 0xfffffffe;
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + mac_index * 0x200, sds);
+
+ counter = 0;
+ while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040)
+ && (counter++ < 5000))
+ ;
+
+ return ret;
+}
+
+
+/**
+ * nes_init_phy
+ */
+int nes_init_phy(struct nes_device *nesdev)
+{
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 mac_index = nesdev->mac_index;
+ u32 tx_config = 0;
+ unsigned long flags;
+ u8 phy_type = nesadapter->phy_type[mac_index];
+ u8 phy_index = nesadapter->phy_index[mac_index];
+ int ret = 0;
- /* reset serdes */
- sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 +
- mac_index * 0x200);
- sds |= 0x1;
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 +
- mac_index * 0x200, sds);
- sds &= 0xfffffffe;
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 +
- mac_index * 0x200, sds);
-
- counter = 0;
- while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040)
- && (counter++ < 5000))
- ;
+ tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
+ if (phy_type == NES_PHY_TYPE_1G) {
+ /* setup 1G MDIO operation */
+ tx_config &= 0xFFFFFFE3;
+ tx_config |= 0x04;
+ } else {
+ /* setup 10G MDIO operation */
+ tx_config &= 0xFFFFFFE3;
+ tx_config |= 0x15;
}
- return 0;
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
+
+ spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags);
+
+ switch (phy_type) {
+ case NES_PHY_TYPE_1G:
+ ret = nes_init_1g_phy(nesdev, phy_type, phy_index);
+ break;
+ case NES_PHY_TYPE_ARGUS:
+ case NES_PHY_TYPE_SFP_D:
+ case NES_PHY_TYPE_KR:
+ ret = nes_init_2025_phy(nesdev, phy_type, phy_index);
+ break;
+ }
+
+ spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags);
+
+ return ret;
}
@@ -1819,9 +1899,14 @@ void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
u16 wqe_fragment_index;
u64 wqe_frag;
u32 cqp_head;
+ u32 wqm_cfg0;
unsigned long flags;
int ret;
+ /* clear wqe stall before destroying NIC QP */
+ wqm_cfg0 = nes_read_indexed(nesdev, NES_IDX_WQM_CONFIG0);
+ nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG0, wqm_cfg0 & 0xFFFF7FFF);
+
/* Free remaining NIC receive buffers */
while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) {
nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail];
@@ -1940,6 +2025,9 @@ void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase,
nesvnic->nic_pbase);
+
+ /* restore old wqm_cfg0 value */
+ nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG0, wqm_cfg0);
}
/**
@@ -2460,23 +2548,9 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
}
} else {
switch (nesadapter->phy_type[mac_index]) {
- case NES_PHY_TYPE_IRIS:
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1);
- temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- u32temp = 20;
- do {
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1);
- phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- if ((phy_data == temp_phy_data) || (!(--u32temp)))
- break;
- temp_phy_data = phy_data;
- } while (1);
- nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
- __func__, phy_data, nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP");
- break;
-
case NES_PHY_TYPE_ARGUS:
case NES_PHY_TYPE_SFP_D:
+ case NES_PHY_TYPE_KR:
/* clear the alarms */
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0x0008);
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc001);
@@ -3352,8 +3426,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
u16 async_event_id;
u8 tcp_state;
u8 iwarp_state;
- int must_disconn = 1;
- int must_terminate = 0;
struct ib_event ibevent;
nes_debug(NES_DBG_AEQ, "\n");
@@ -3367,6 +3439,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
BUG_ON(!context);
}
+ /* context is nesqp unless async_event_id == CQ ERROR */
+ nesqp = (struct nes_qp *)(unsigned long)context;
async_event_id = (u16)aeq_info;
tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT;
iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT;
@@ -3378,8 +3452,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
switch (async_event_id) {
case NES_AEQE_AEID_LLP_FIN_RECEIVED:
- nesqp = (struct nes_qp *)(unsigned long)context;
-
if (nesqp->term_flags)
return; /* Ignore it, wait for close complete */
@@ -3394,79 +3466,48 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
async_event_id, nesqp->last_aeq, tcp_state);
}
- if ((tcp_state != NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
- (nesqp->ibqp_state != IB_QPS_RTS)) {
- /* FIN Received but tcp state or IB state moved on,
- should expect a close complete */
- return;
- }
-
+ break;
case NES_AEQE_AEID_LLP_CLOSE_COMPLETE:
- nesqp = (struct nes_qp *)(unsigned long)context;
if (nesqp->term_flags) {
nes_terminate_done(nesqp, 0);
return;
}
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_hw_modify_qp(nesdev, nesqp, NES_CQP_QP_IWARP_STATE_CLOSING, 0, 0);
+ nes_cm_disconn(nesqp);
+ break;
- case NES_AEQE_AEID_LLP_CONNECTION_RESET:
case NES_AEQE_AEID_RESET_SENT:
- nesqp = (struct nes_qp *)(unsigned long)context;
- if (async_event_id == NES_AEQE_AEID_RESET_SENT) {
- tcp_state = NES_AEQE_TCP_STATE_CLOSED;
- }
+ tcp_state = NES_AEQE_TCP_STATE_CLOSED;
spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = iwarp_state;
nesqp->hw_tcp_state = tcp_state;
nesqp->last_aeq = async_event_id;
-
- if ((tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
- (tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT)) {
- nesqp->hte_added = 0;
- next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE;
- }
-
- if ((nesqp->ibqp_state == IB_QPS_RTS) &&
- ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
- (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
- switch (nesqp->hw_iwarp_state) {
- case NES_AEQE_IWARP_STATE_RTS:
- next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
- nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING;
- break;
- case NES_AEQE_IWARP_STATE_TERMINATE:
- must_disconn = 0; /* terminate path takes care of disconn */
- if (nesqp->term_flags == 0)
- must_terminate = 1;
- break;
- }
- } else {
- if (async_event_id == NES_AEQE_AEID_LLP_FIN_RECEIVED) {
- /* FIN Received but ib state not RTS,
- close complete will be on its way */
- must_disconn = 0;
- }
- }
+ nesqp->hte_added = 0;
spin_unlock_irqrestore(&nesqp->lock, flags);
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE;
+ nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0);
+ nes_cm_disconn(nesqp);
+ break;
- if (must_terminate)
- nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL);
- else if (must_disconn) {
- if (next_iwarp_state) {
- nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X\n",
- nesqp->hwqp.qp_id, next_iwarp_state);
- nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0);
- }
- nes_cm_disconn(nesqp);
- }
+ case NES_AEQE_AEID_LLP_CONNECTION_RESET:
+ if (atomic_read(&nesqp->close_timer_started))
+ return;
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_cm_disconn(nesqp);
break;
case NES_AEQE_AEID_TERMINATE_SENT:
- nesqp = (struct nes_qp *)(unsigned long)context;
nes_terminate_send_fin(nesdev, nesqp, aeqe);
break;
case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED:
- nesqp = (struct nes_qp *)(unsigned long)context;
nes_terminate_received(nesdev, nesqp, aeqe);
break;
@@ -3480,7 +3521,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER:
case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION:
case NES_AEQE_AEID_AMP_TO_WRAP:
- nesqp = (struct nes_qp *)(unsigned long)context;
+ printk(KERN_ERR PFX "QP[%u] async_event_id=0x%04X IB_EVENT_QP_ACCESS_ERR\n",
+ nesqp->hwqp.qp_id, async_event_id);
nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_ACCESS_ERR);
break;
@@ -3488,7 +3530,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL:
case NES_AEQE_AEID_DDP_UBE_INVALID_MO:
case NES_AEQE_AEID_DDP_UBE_INVALID_QN:
- nesqp = (struct nes_qp *)(unsigned long)context;
if (iwarp_opcode(nesqp, aeq_info) > IWARP_OPCODE_TERM) {
aeq_info &= 0xffff0000;
aeq_info |= NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE;
@@ -3530,7 +3571,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
case NES_AEQE_AEID_STAG_ZERO_INVALID:
case NES_AEQE_AEID_ROE_INVALID_RDMA_READ_REQUEST:
case NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP:
- nesqp = (struct nes_qp *)(unsigned long)context;
+ printk(KERN_ERR PFX "QP[%u] async_event_id=0x%04X IB_EVENT_QP_FATAL\n",
+ nesqp->hwqp.qp_id, async_event_id);
nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL);
break;
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
index 084be0ee689b..bbbfe9fc5a5a 100644
--- a/drivers/infiniband/hw/nes/nes_hw.h
+++ b/drivers/infiniband/hw/nes/nes_hw.h
@@ -37,12 +37,12 @@
#define NES_PHY_TYPE_CX4 1
#define NES_PHY_TYPE_1G 2
-#define NES_PHY_TYPE_IRIS 3
#define NES_PHY_TYPE_ARGUS 4
#define NES_PHY_TYPE_PUMA_1G 5
#define NES_PHY_TYPE_PUMA_10G 6
#define NES_PHY_TYPE_GLADIUS 7
#define NES_PHY_TYPE_SFP_D 8
+#define NES_PHY_TYPE_KR 9
#define NES_MULTICAST_PF_MAX 8
@@ -160,6 +160,7 @@ enum indexed_regs {
NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI = 0x7004,
NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO = 0x7008,
NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI = 0x700c,
+ NES_IDX_WQM_CONFIG0 = 0x5000,
NES_IDX_WQM_CONFIG1 = 0x5004,
NES_IDX_CM_CONFIG = 0x5100,
NES_IDX_NIC_LOGPORT_TO_PHYPORT = 0x6000,
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index ab1102780186..91fdde382e82 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -810,6 +810,20 @@ static int nes_netdev_set_mac_address(struct net_device *netdev, void *p)
}
+static void set_allmulti(struct nes_device *nesdev, u32 nic_active_bit)
+{
+ u32 nic_active;
+
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
+ nic_active |= nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
+ nic_active &= ~nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
+}
+
+#define get_addr(addrs, index) ((addrs) + (index) * ETH_ALEN)
+
/**
* nes_netdev_set_multicast_list
*/
@@ -818,7 +832,6 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
struct nes_vnic *nesvnic = netdev_priv(netdev);
struct nes_device *nesdev = nesvnic->nesdev;
struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
- struct dev_mc_list *multicast_addr;
u32 nic_active_bit;
u32 nic_active;
u32 perfect_filter_register_address;
@@ -831,6 +844,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
nics_per_function, 4);
u8 max_pft_entries_avaiable = NES_PFT_SIZE - pft_entries_preallocated;
unsigned long flags;
+ int mc_count = netdev_mc_count(netdev);
spin_lock_irqsave(&nesadapter->resource_lock, flags);
nic_active_bit = 1 << nesvnic->nic_index;
@@ -845,12 +859,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
mc_all_on = 1;
} else if ((netdev->flags & IFF_ALLMULTI) ||
(nesvnic->nic_index > 3)) {
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
- nic_active |= nic_active_bit;
- nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
- nic_active &= ~nic_active_bit;
- nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
+ set_allmulti(nesdev, nic_active_bit);
mc_all_on = 1;
} else {
nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
@@ -862,19 +871,30 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
}
nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscous = %d, All Multicast = %d.\n",
- netdev->mc_count, !!(netdev->flags & IFF_PROMISC),
+ mc_count, !!(netdev->flags & IFF_PROMISC),
!!(netdev->flags & IFF_ALLMULTI));
if (!mc_all_on) {
- multicast_addr = netdev->mc_list;
+ char *addrs;
+ int i;
+ struct dev_mc_list *mcaddr;
+
+ addrs = kmalloc(ETH_ALEN * mc_count, GFP_ATOMIC);
+ if (!addrs) {
+ set_allmulti(nesdev, nic_active_bit);
+ goto unlock;
+ }
+ i = 0;
+ netdev_for_each_mc_addr(mcaddr, netdev)
+ memcpy(get_addr(addrs, i++),
+ mcaddr->dmi_addr, ETH_ALEN);
+
perfect_filter_register_address = NES_IDX_PERFECT_FILTER_LOW +
pft_entries_preallocated * 0x8;
- for (mc_index = 0; mc_index < max_pft_entries_avaiable;
- mc_index++) {
- while (multicast_addr && nesvnic->mcrq_mcast_filter &&
+ for (i = 0, mc_index = 0; mc_index < max_pft_entries_avaiable;
+ mc_index++) {
+ while (i < mc_count && nesvnic->mcrq_mcast_filter &&
((mc_nic_index = nesvnic->mcrq_mcast_filter(nesvnic,
- multicast_addr->dmi_addr)) == 0)) {
- multicast_addr = multicast_addr->next;
- }
+ get_addr(addrs, i++))) == 0));
if (mc_nic_index < 0)
mc_nic_index = nesvnic->nic_index;
while (nesadapter->pft_mcast_map[mc_index] < 16 &&
@@ -890,17 +910,19 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
}
if (mc_index >= max_pft_entries_avaiable)
break;
- if (multicast_addr) {
+ if (i < mc_count) {
+ char *addr = get_addr(addrs, i++);
+
nes_debug(NES_DBG_NIC_RX, "Assigning MC Address %pM to register 0x%04X nic_idx=%d\n",
- multicast_addr->dmi_addr,
+ addr,
perfect_filter_register_address+(mc_index * 8),
mc_nic_index);
- macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8;
- macaddr_high += (u16)multicast_addr->dmi_addr[1];
- macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24;
- macaddr_low += ((u32)multicast_addr->dmi_addr[3]) << 16;
- macaddr_low += ((u32)multicast_addr->dmi_addr[4]) << 8;
- macaddr_low += (u32)multicast_addr->dmi_addr[5];
+ macaddr_high = ((u16) addr[0]) << 8;
+ macaddr_high += (u16) addr[1];
+ macaddr_low = ((u32) addr[2]) << 24;
+ macaddr_low += ((u32) addr[3]) << 16;
+ macaddr_low += ((u32) addr[4]) << 8;
+ macaddr_low += (u32) addr[5];
nes_write_indexed(nesdev,
perfect_filter_register_address+(mc_index * 8),
macaddr_low);
@@ -908,7 +930,6 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
perfect_filter_register_address+4+(mc_index * 8),
(u32)macaddr_high | NES_MAC_ADDR_VALID |
((((u32)(1<<mc_nic_index)) << 16)));
- multicast_addr = multicast_addr->next;
nesadapter->pft_mcast_map[mc_index] =
nesvnic->nic_index;
} else {
@@ -920,21 +941,13 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
nesadapter->pft_mcast_map[mc_index] = 255;
}
}
+ kfree(addrs);
/* PFT is not large enough */
- if (multicast_addr && multicast_addr->next) {
- nic_active = nes_read_indexed(nesdev,
- NES_IDX_NIC_MULTICAST_ALL);
- nic_active |= nic_active_bit;
- nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL,
- nic_active);
- nic_active = nes_read_indexed(nesdev,
- NES_IDX_NIC_UNICAST_ALL);
- nic_active &= ~nic_active_bit;
- nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL,
- nic_active);
- }
+ if (i < mc_count)
+ set_allmulti(nesdev, nic_active_bit);
}
+unlock:
spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
}
@@ -1230,8 +1243,8 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
target_stat_values[++index] = cm_packets_received;
target_stat_values[++index] = cm_packets_dropped;
target_stat_values[++index] = cm_packets_retrans;
- target_stat_values[++index] = cm_listens_created;
- target_stat_values[++index] = cm_listens_destroyed;
+ target_stat_values[++index] = atomic_read(&cm_listens_created);
+ target_stat_values[++index] = atomic_read(&cm_listens_destroyed);
target_stat_values[++index] = cm_backlog_drops;
target_stat_values[++index] = atomic_read(&cm_loopbacks);
target_stat_values[++index] = atomic_read(&cm_nodes_created);
@@ -1461,9 +1474,9 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd
}
return 0;
}
- if ((phy_type == NES_PHY_TYPE_IRIS) ||
- (phy_type == NES_PHY_TYPE_ARGUS) ||
- (phy_type == NES_PHY_TYPE_SFP_D)) {
+ if ((phy_type == NES_PHY_TYPE_ARGUS) ||
+ (phy_type == NES_PHY_TYPE_SFP_D) ||
+ (phy_type == NES_PHY_TYPE_KR)) {
et_cmd->transceiver = XCVR_EXTERNAL;
et_cmd->port = PORT_FIBRE;
et_cmd->supported = SUPPORTED_FIBRE;
@@ -1582,9 +1595,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
struct nes_vnic *nesvnic;
struct net_device *netdev;
struct nic_qp_map *curr_qp_map;
- u32 u32temp;
- u16 phy_data;
- u16 temp_phy_data;
+ u8 phy_type = nesdev->nesadapter->phy_type[nesdev->mac_index];
netdev = alloc_etherdev(sizeof(struct nes_vnic));
if (!netdev) {
@@ -1692,66 +1703,51 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
if ((nesdev->netdev_count == 0) &&
((PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index) ||
- ((nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) &&
+ ((phy_type == NES_PHY_TYPE_PUMA_1G) &&
(((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) ||
((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) {
- /*
- * nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n",
- * NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesvnic->logical_port & 1)));
- */
+ u32 u32temp;
+ u32 link_mask;
+ u32 link_val;
+
u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
(0x200 * (nesdev->mac_index & 1)));
- if (nesdev->nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G) {
+ if (phy_type != NES_PHY_TYPE_PUMA_1G) {
u32temp |= 0x00200000;
nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
(0x200 * (nesdev->mac_index & 1)), u32temp);
}
- u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
- (0x200 * (nesdev->mac_index & 1)));
-
- if ((u32temp&0x0f1f0000) == 0x0f0f0000) {
- if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_IRIS) {
- nes_init_phy(nesdev);
- nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1);
- temp_phy_data = (u16)nes_read_indexed(nesdev,
- NES_IDX_MAC_MDIO_CONTROL);
- u32temp = 20;
- do {
- nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1);
- phy_data = (u16)nes_read_indexed(nesdev,
- NES_IDX_MAC_MDIO_CONTROL);
- if ((phy_data == temp_phy_data) || (!(--u32temp)))
- break;
- temp_phy_data = phy_data;
- } while (1);
- if (phy_data & 4) {
- nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
- nesvnic->linkup = 1;
- } else {
- nes_debug(NES_DBG_INIT, "The Link is DOWN!!.\n");
- }
+ /* Check and set linkup here. This is for back to back */
+ /* configuration where second port won't get link interrupt */
+ switch (phy_type) {
+ case NES_PHY_TYPE_PUMA_1G:
+ if (nesdev->mac_index < 2) {
+ link_mask = 0x01010000;
+ link_val = 0x01010000;
} else {
- nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
- nesvnic->linkup = 1;
- }
- } else if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) {
- nes_debug(NES_DBG_INIT, "mac_index=%d, logical_port=%d, u32temp=0x%04X, PCI_FUNC=%d\n",
- nesdev->mac_index, nesvnic->logical_port, u32temp, PCI_FUNC(nesdev->pcidev->devfn));
- if (((nesdev->mac_index < 2) && ((u32temp&0x01010000) == 0x01010000)) ||
- ((nesdev->mac_index > 1) && ((u32temp&0x02020000) == 0x02020000))) {
- nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
- nesvnic->linkup = 1;
+ link_mask = 0x02020000;
+ link_val = 0x02020000;
}
+ break;
+ default:
+ link_mask = 0x0f1f0000;
+ link_val = 0x0f0f0000;
+ break;
}
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+ (0x200 * (nesdev->mac_index & 1)));
+ if ((u32temp & link_mask) == link_val)
+ nesvnic->linkup = 1;
+
/* clear the MAC interrupt status, assumes direct logical to physical mapping */
u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index));
nes_debug(NES_DBG_INIT, "Phy interrupt status = 0x%X.\n", u32temp);
nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index), u32temp);
- if (nesdev->nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_IRIS)
- nes_init_phy(nesdev);
-
+ nes_init_phy(nesdev);
}
return netdev;
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index 64d3136e3747..69928296d74b 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -228,7 +228,7 @@ static int nes_bind_mw(struct ib_qp *ibqp, struct ib_mw *ibmw,
/* Check for SQ overflow */
if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) {
spin_unlock_irqrestore(&nesqp->lock, flags);
- return -EINVAL;
+ return -ENOMEM;
}
wqe = &nesqp->hwqp.sq_vbase[head];
@@ -1323,6 +1323,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
nesqp->nesqp_context->aeq_token_low = cpu_to_le32((u32)((unsigned long)(nesqp)));
nesqp->nesqp_context->aeq_token_high = cpu_to_le32((u32)(upper_32_bits((unsigned long)(nesqp))));
nesqp->nesqp_context->ird_ord_sizes = cpu_to_le32(NES_QPCONTEXT_ORDIRD_ALSMM |
+ NES_QPCONTEXT_ORDIRD_AAH |
((((u32)nesadapter->max_irrq_wr) <<
NES_QPCONTEXT_ORDIRD_IRDSIZE_SHIFT) & NES_QPCONTEXT_ORDIRD_IRDSIZE_MASK));
if (disable_mpa_crc) {
@@ -3294,7 +3295,7 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
/* Check for SQ overflow */
if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) {
- err = -EINVAL;
+ err = -ENOMEM;
break;
}
@@ -3577,7 +3578,7 @@ static int nes_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
}
/* Check for RQ overflow */
if (((head + (2 * qsize) - nesqp->hwqp.rq_tail) % qsize) == (qsize - 1)) {
- err = -EINVAL;
+ err = -ENOMEM;
break;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 30bdf427ee6d..bc658373ad55 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -708,6 +708,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_cm_tx_buf *tx_req;
u64 addr;
+ int rc;
if (unlikely(skb->len > tx->mtu)) {
ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
@@ -739,9 +740,10 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
tx_req->mapping = addr;
- if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1),
- addr, skb->len))) {
- ipoib_warn(priv, "post_send failed\n");
+ rc = post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1),
+ addr, skb->len);
+ if (unlikely(rc)) {
+ ipoib_warn(priv, "post_send failed, error %d\n", rc);
++dev->stats.tx_errors;
ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
@@ -752,6 +754,8 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
if (++priv->tx_outstanding == ipoib_sendq_size) {
ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n",
tx->qp->qp_num);
+ if (ib_req_notify_cq(priv->send_cq, IB_CQ_NEXT_COMP))
+ ipoib_warn(priv, "request notify on send CQ failed\n");
netif_stop_queue(dev);
}
}
@@ -1374,7 +1378,7 @@ static void ipoib_cm_skb_reap(struct work_struct *work)
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else if (skb->protocol == htons(ETH_P_IPV6))
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, priv->dev);
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
#endif
dev_kfree_skb_any(skb);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
index e9795f60e5d6..d10b4ec68d28 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
@@ -55,9 +55,7 @@ static int ipoib_get_coalesce(struct net_device *dev,
struct ipoib_dev_priv *priv = netdev_priv(dev);
coal->rx_coalesce_usecs = priv->ethtool.coalesce_usecs;
- coal->tx_coalesce_usecs = priv->ethtool.coalesce_usecs;
coal->rx_max_coalesced_frames = priv->ethtool.max_coalesced_frames;
- coal->tx_max_coalesced_frames = priv->ethtool.max_coalesced_frames;
return 0;
}
@@ -69,10 +67,8 @@ static int ipoib_set_coalesce(struct net_device *dev,
int ret;
/*
- * Since IPoIB uses a single CQ for both rx and tx, we assume
- * that rx params dictate the configuration. These values are
- * saved in the private data and returned when ipoib_get_coalesce()
- * is called.
+ * These values are saved in the private data and returned
+ * when ipoib_get_coalesce() is called
*/
if (coal->rx_coalesce_usecs > 0xffff ||
coal->rx_max_coalesced_frames > 0xffff)
@@ -85,8 +81,6 @@ static int ipoib_set_coalesce(struct net_device *dev,
return ret;
}
- coal->tx_coalesce_usecs = coal->rx_coalesce_usecs;
- coal->tx_max_coalesced_frames = coal->rx_max_coalesced_frames;
priv->ethtool.coalesce_usecs = coal->rx_coalesce_usecs;
priv->ethtool.max_coalesced_frames = coal->rx_max_coalesced_frames;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 8c91d9f37ada..5df40b128f81 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -529,7 +529,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_tx_buf *tx_req;
- int hlen;
+ int hlen, rc;
void *phead;
if (skb_is_gso(skb)) {
@@ -585,9 +585,10 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
netif_stop_queue(dev);
}
- if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
- address->ah, qpn, tx_req, phead, hlen))) {
- ipoib_warn(priv, "post_send failed\n");
+ rc = post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
+ address->ah, qpn, tx_req, phead, hlen);
+ if (unlikely(rc)) {
+ ipoib_warn(priv, "post_send failed, error %d\n", rc);
++dev->stats.tx_errors;
--priv->tx_outstanding;
ipoib_dma_unmap_tx(priv->ca, tx_req);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 8763c1ea5eb4..d41ea27be5e1 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -811,7 +811,7 @@ void ipoib_mcast_restart_task(struct work_struct *work)
clear_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags);
/* Mark all of the entries that are found or don't exist */
- for (mclist = dev->mc_list; mclist; mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
union ib_gid mgid;
if (!ipoib_mcast_addr_is_valid(mclist->dmi_addr,
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 5f7a6fca0a4d..71237f8f78f7 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -128,6 +128,28 @@ static int iscsi_iser_pdu_alloc(struct iscsi_task *task, uint8_t opcode)
return 0;
}
+int iser_initialize_task_headers(struct iscsi_task *task,
+ struct iser_tx_desc *tx_desc)
+{
+ struct iscsi_iser_conn *iser_conn = task->conn->dd_data;
+ struct iser_device *device = iser_conn->ib_conn->device;
+ struct iscsi_iser_task *iser_task = task->dd_data;
+ u64 dma_addr;
+
+ dma_addr = ib_dma_map_single(device->ib_device, (void *)tx_desc,
+ ISER_HEADERS_LEN, DMA_TO_DEVICE);
+ if (ib_dma_mapping_error(device->ib_device, dma_addr))
+ return -ENOMEM;
+
+ tx_desc->dma_addr = dma_addr;
+ tx_desc->tx_sg[0].addr = tx_desc->dma_addr;
+ tx_desc->tx_sg[0].length = ISER_HEADERS_LEN;
+ tx_desc->tx_sg[0].lkey = device->mr->lkey;
+
+ iser_task->headers_initialized = 1;
+ iser_task->iser_conn = iser_conn;
+ return 0;
+}
/**
* iscsi_iser_task_init - Initialize task
* @task: iscsi task
@@ -137,17 +159,17 @@ static int iscsi_iser_pdu_alloc(struct iscsi_task *task, uint8_t opcode)
static int
iscsi_iser_task_init(struct iscsi_task *task)
{
- struct iscsi_iser_conn *iser_conn = task->conn->dd_data;
struct iscsi_iser_task *iser_task = task->dd_data;
+ if (!iser_task->headers_initialized)
+ if (iser_initialize_task_headers(task, &iser_task->desc))
+ return -ENOMEM;
+
/* mgmt task */
- if (!task->sc) {
- iser_task->desc.data = task->data;
+ if (!task->sc)
return 0;
- }
iser_task->command_sent = 0;
- iser_task->iser_conn = iser_conn;
iser_task_rdma_init(iser_task);
return 0;
}
@@ -168,7 +190,7 @@ iscsi_iser_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
{
int error = 0;
- iser_dbg("task deq [cid %d itt 0x%x]\n", conn->id, task->itt);
+ iser_dbg("mtask xmit [cid %d itt 0x%x]\n", conn->id, task->itt);
error = iser_send_control(conn, task);
@@ -178,9 +200,6 @@ iscsi_iser_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
* - if yes, the task is recycled at iscsi_complete_pdu
* - if no, the task is recycled at iser_snd_completion
*/
- if (error && error != -ENOBUFS)
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-
return error;
}
@@ -232,7 +251,7 @@ iscsi_iser_task_xmit(struct iscsi_task *task)
task->imm_count, task->unsol_r2t.data_length);
}
- iser_dbg("task deq [cid %d itt 0x%x]\n",
+ iser_dbg("ctask xmit [cid %d itt 0x%x]\n",
conn->id, task->itt);
/* Send the cmd PDU */
@@ -248,8 +267,6 @@ iscsi_iser_task_xmit(struct iscsi_task *task)
error = iscsi_iser_task_xmit_unsol_data(conn, task);
iscsi_iser_task_xmit_exit:
- if (error && error != -ENOBUFS)
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return error;
}
@@ -283,7 +300,7 @@ iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
* due to issues with the login code re iser sematics
* this not set in iscsi_conn_setup - FIXME
*/
- conn->max_recv_dlength = 128;
+ conn->max_recv_dlength = ISER_RECV_DATA_SEG_LEN;
iser_conn = conn->dd_data;
conn->dd_data = iser_conn;
@@ -401,7 +418,7 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep,
struct Scsi_Host *shost;
struct iser_conn *ib_conn;
- shost = iscsi_host_alloc(&iscsi_iser_sht, 0, 1);
+ shost = iscsi_host_alloc(&iscsi_iser_sht, 0, 0);
if (!shost)
return NULL;
shost->transportt = iscsi_iser_scsi_transport;
@@ -675,7 +692,7 @@ static int __init iser_init(void)
memset(&ig, 0, sizeof(struct iser_global));
ig.desc_cache = kmem_cache_create("iser_descriptors",
- sizeof (struct iser_desc),
+ sizeof(struct iser_tx_desc),
0, SLAB_HWCACHE_ALIGN,
NULL);
if (ig.desc_cache == NULL)
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 9d529cae1f0d..036934cdcb92 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -102,9 +102,9 @@
#define ISER_MAX_TX_MISC_PDUS 6 /* NOOP_OUT(2), TEXT(1), *
* SCSI_TMFUNC(2), LOGOUT(1) */
-#define ISER_QP_MAX_RECV_DTOS (ISCSI_DEF_XMIT_CMDS_MAX + \
- ISER_MAX_RX_MISC_PDUS + \
- ISER_MAX_TX_MISC_PDUS)
+#define ISER_QP_MAX_RECV_DTOS (ISCSI_DEF_XMIT_CMDS_MAX)
+
+#define ISER_MIN_POSTED_RX (ISCSI_DEF_XMIT_CMDS_MAX >> 2)
/* the max TX (send) WR supported by the iSER QP is defined by *
* max_send_wr = T * (1 + D) + C ; D is how many inflight dataouts we expect *
@@ -132,6 +132,12 @@ struct iser_hdr {
__be64 read_va;
} __attribute__((packed));
+/* Constant PDU lengths calculations */
+#define ISER_HEADERS_LEN (sizeof(struct iser_hdr) + sizeof(struct iscsi_hdr))
+
+#define ISER_RECV_DATA_SEG_LEN 128
+#define ISER_RX_PAYLOAD_SIZE (ISER_HEADERS_LEN + ISER_RECV_DATA_SEG_LEN)
+#define ISER_RX_LOGIN_SIZE (ISER_HEADERS_LEN + ISCSI_DEF_MAX_RECV_SEG_LEN)
/* Length of an object name string */
#define ISER_OBJECT_NAME_SIZE 64
@@ -187,51 +193,43 @@ struct iser_regd_buf {
struct iser_mem_reg reg; /* memory registration info */
void *virt_addr;
struct iser_device *device; /* device->device for dma_unmap */
- u64 dma_addr; /* if non zero, addr for dma_unmap */
enum dma_data_direction direction; /* direction for dma_unmap */
unsigned int data_size;
- atomic_t ref_count; /* refcount, freed when dec to 0 */
-};
-
-#define MAX_REGD_BUF_VECTOR_LEN 2
-
-struct iser_dto {
- struct iscsi_iser_task *task;
- struct iser_conn *ib_conn;
- int notify_enable;
-
- /* vector of registered buffers */
- unsigned int regd_vector_len;
- struct iser_regd_buf *regd[MAX_REGD_BUF_VECTOR_LEN];
-
- /* offset into the registered buffer may be specified */
- unsigned int offset[MAX_REGD_BUF_VECTOR_LEN];
-
- /* a smaller size may be specified, if 0, then full size is used */
- unsigned int used_sz[MAX_REGD_BUF_VECTOR_LEN];
};
enum iser_desc_type {
- ISCSI_RX,
ISCSI_TX_CONTROL ,
ISCSI_TX_SCSI_COMMAND,
ISCSI_TX_DATAOUT
};
-struct iser_desc {
+struct iser_tx_desc {
struct iser_hdr iser_header;
struct iscsi_hdr iscsi_header;
- struct iser_regd_buf hdr_regd_buf;
- void *data; /* used by RX & TX_CONTROL */
- struct iser_regd_buf data_regd_buf; /* used by RX & TX_CONTROL */
enum iser_desc_type type;
- struct iser_dto dto;
+ u64 dma_addr;
+ /* sg[0] points to iser/iscsi headers, sg[1] optionally points to either
+ of immediate data, unsolicited data-out or control (login,text) */
+ struct ib_sge tx_sg[2];
+ int num_sge;
};
+#define ISER_RX_PAD_SIZE (256 - (ISER_RX_PAYLOAD_SIZE + \
+ sizeof(u64) + sizeof(struct ib_sge)))
+struct iser_rx_desc {
+ struct iser_hdr iser_header;
+ struct iscsi_hdr iscsi_header;
+ char data[ISER_RECV_DATA_SEG_LEN];
+ u64 dma_addr;
+ struct ib_sge rx_sg;
+ char pad[ISER_RX_PAD_SIZE];
+} __attribute__((packed));
+
struct iser_device {
struct ib_device *ib_device;
struct ib_pd *pd;
- struct ib_cq *cq;
+ struct ib_cq *rx_cq;
+ struct ib_cq *tx_cq;
struct ib_mr *mr;
struct tasklet_struct cq_tasklet;
struct list_head ig_list; /* entry in ig devices list */
@@ -250,15 +248,18 @@ struct iser_conn {
struct ib_fmr_pool *fmr_pool; /* pool of IB FMRs */
int disc_evt_flag; /* disconn event delivered */
wait_queue_head_t wait; /* waitq for conn/disconn */
- atomic_t post_recv_buf_count; /* posted rx count */
+ int post_recv_buf_count; /* posted rx count */
atomic_t post_send_buf_count; /* posted tx count */
- atomic_t unexpected_pdu_count;/* count of received *
- * unexpected pdus *
- * not yet retired */
char name[ISER_OBJECT_NAME_SIZE];
struct iser_page_vec *page_vec; /* represents SG to fmr maps*
* maps serialized as tx is*/
struct list_head conn_list; /* entry in ig conn list */
+
+ char *login_buf;
+ u64 login_dma;
+ unsigned int rx_desc_head;
+ struct iser_rx_desc *rx_descs;
+ struct ib_recv_wr rx_wr[ISER_MIN_POSTED_RX];
};
struct iscsi_iser_conn {
@@ -267,7 +268,7 @@ struct iscsi_iser_conn {
};
struct iscsi_iser_task {
- struct iser_desc desc;
+ struct iser_tx_desc desc;
struct iscsi_iser_conn *iser_conn;
enum iser_task_status status;
int command_sent; /* set if command sent */
@@ -275,6 +276,7 @@ struct iscsi_iser_task {
struct iser_regd_buf rdma_regd[ISER_DIRS_NUM];/* regd rdma buf */
struct iser_data_buf data[ISER_DIRS_NUM]; /* orig. data des*/
struct iser_data_buf data_copy[ISER_DIRS_NUM];/* contig. copy */
+ int headers_initialized;
};
struct iser_page_vec {
@@ -322,22 +324,17 @@ void iser_conn_put(struct iser_conn *ib_conn);
void iser_conn_terminate(struct iser_conn *ib_conn);
-void iser_rcv_completion(struct iser_desc *desc,
- unsigned long dto_xfer_len);
+void iser_rcv_completion(struct iser_rx_desc *desc,
+ unsigned long dto_xfer_len,
+ struct iser_conn *ib_conn);
-void iser_snd_completion(struct iser_desc *desc);
+void iser_snd_completion(struct iser_tx_desc *desc, struct iser_conn *ib_conn);
void iser_task_rdma_init(struct iscsi_iser_task *task);
void iser_task_rdma_finalize(struct iscsi_iser_task *task);
-void iser_dto_buffs_release(struct iser_dto *dto);
-
-int iser_regd_buff_release(struct iser_regd_buf *regd_buf);
-
-void iser_reg_single(struct iser_device *device,
- struct iser_regd_buf *regd_buf,
- enum dma_data_direction direction);
+void iser_free_rx_descriptors(struct iser_conn *ib_conn);
void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *task,
enum iser_data_dir cmd_dir);
@@ -356,11 +353,9 @@ int iser_reg_page_vec(struct iser_conn *ib_conn,
void iser_unreg_mem(struct iser_mem_reg *mem_reg);
-int iser_post_recv(struct iser_desc *rx_desc);
-int iser_post_send(struct iser_desc *tx_desc);
-
-int iser_conn_state_comp(struct iser_conn *ib_conn,
- enum iser_ib_conn_state comp);
+int iser_post_recvl(struct iser_conn *ib_conn);
+int iser_post_recvm(struct iser_conn *ib_conn, int count);
+int iser_post_send(struct iser_conn *ib_conn, struct iser_tx_desc *tx_desc);
int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
struct iser_data_buf *data,
@@ -368,4 +363,6 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
enum dma_data_direction dma_dir);
void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task);
+int iser_initialize_task_headers(struct iscsi_task *task,
+ struct iser_tx_desc *tx_desc);
#endif
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 9de640200ad3..0b9ef0716588 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -39,29 +39,6 @@
#include "iscsi_iser.h"
-/* Constant PDU lengths calculations */
-#define ISER_TOTAL_HEADERS_LEN (sizeof (struct iser_hdr) + \
- sizeof (struct iscsi_hdr))
-
-/* iser_dto_add_regd_buff - increments the reference count for *
- * the registered buffer & adds it to the DTO object */
-static void iser_dto_add_regd_buff(struct iser_dto *dto,
- struct iser_regd_buf *regd_buf,
- unsigned long use_offset,
- unsigned long use_size)
-{
- int add_idx;
-
- atomic_inc(&regd_buf->ref_count);
-
- add_idx = dto->regd_vector_len;
- dto->regd[add_idx] = regd_buf;
- dto->used_sz[add_idx] = use_size;
- dto->offset[add_idx] = use_offset;
-
- dto->regd_vector_len++;
-}
-
/* Register user buffer memory and initialize passive rdma
* dto descriptor. Total data size is stored in
* iser_task->data[ISER_DIR_IN].data_len
@@ -122,9 +99,9 @@ iser_prepare_write_cmd(struct iscsi_task *task,
struct iscsi_iser_task *iser_task = task->dd_data;
struct iser_regd_buf *regd_buf;
int err;
- struct iser_dto *send_dto = &iser_task->desc.dto;
struct iser_hdr *hdr = &iser_task->desc.iser_header;
struct iser_data_buf *buf_out = &iser_task->data[ISER_DIR_OUT];
+ struct ib_sge *tx_dsg = &iser_task->desc.tx_sg[1];
err = iser_dma_map_task_data(iser_task,
buf_out,
@@ -163,135 +140,100 @@ iser_prepare_write_cmd(struct iscsi_task *task,
if (imm_sz > 0) {
iser_dbg("Cmd itt:%d, WRITE, adding imm.data sz: %d\n",
task->itt, imm_sz);
- iser_dto_add_regd_buff(send_dto,
- regd_buf,
- 0,
- imm_sz);
+ tx_dsg->addr = regd_buf->reg.va;
+ tx_dsg->length = imm_sz;
+ tx_dsg->lkey = regd_buf->reg.lkey;
+ iser_task->desc.num_sge = 2;
}
return 0;
}
-/**
- * iser_post_receive_control - allocates, initializes and posts receive DTO.
- */
-static int iser_post_receive_control(struct iscsi_conn *conn)
+/* creates a new tx descriptor and adds header regd buffer */
+static void iser_create_send_desc(struct iser_conn *ib_conn,
+ struct iser_tx_desc *tx_desc)
{
- struct iscsi_iser_conn *iser_conn = conn->dd_data;
- struct iser_desc *rx_desc;
- struct iser_regd_buf *regd_hdr;
- struct iser_regd_buf *regd_data;
- struct iser_dto *recv_dto = NULL;
- struct iser_device *device = iser_conn->ib_conn->device;
- int rx_data_size, err;
- int posts, outstanding_unexp_pdus;
-
- /* for the login sequence we must support rx of upto 8K; login is done
- * after conn create/bind (connect) and conn stop/bind (reconnect),
- * what's common for both schemes is that the connection is not started
- */
- if (conn->c_stage != ISCSI_CONN_STARTED)
- rx_data_size = ISCSI_DEF_MAX_RECV_SEG_LEN;
- else /* FIXME till user space sets conn->max_recv_dlength correctly */
- rx_data_size = 128;
-
- outstanding_unexp_pdus =
- atomic_xchg(&iser_conn->ib_conn->unexpected_pdu_count, 0);
-
- /*
- * in addition to the response buffer, replace those consumed by
- * unexpected pdus.
- */
- for (posts = 0; posts < 1 + outstanding_unexp_pdus; posts++) {
- rx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO);
- if (rx_desc == NULL) {
- iser_err("Failed to alloc desc for post recv %d\n",
- posts);
- err = -ENOMEM;
- goto post_rx_cache_alloc_failure;
- }
- rx_desc->type = ISCSI_RX;
- rx_desc->data = kmalloc(rx_data_size, GFP_NOIO);
- if (rx_desc->data == NULL) {
- iser_err("Failed to alloc data buf for post recv %d\n",
- posts);
- err = -ENOMEM;
- goto post_rx_kmalloc_failure;
- }
-
- recv_dto = &rx_desc->dto;
- recv_dto->ib_conn = iser_conn->ib_conn;
- recv_dto->regd_vector_len = 0;
+ struct iser_device *device = ib_conn->device;
- regd_hdr = &rx_desc->hdr_regd_buf;
- memset(regd_hdr, 0, sizeof(struct iser_regd_buf));
- regd_hdr->device = device;
- regd_hdr->virt_addr = rx_desc; /* == &rx_desc->iser_header */
- regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN;
+ ib_dma_sync_single_for_cpu(device->ib_device,
+ tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE);
- iser_reg_single(device, regd_hdr, DMA_FROM_DEVICE);
-
- iser_dto_add_regd_buff(recv_dto, regd_hdr, 0, 0);
+ memset(&tx_desc->iser_header, 0, sizeof(struct iser_hdr));
+ tx_desc->iser_header.flags = ISER_VER;
- regd_data = &rx_desc->data_regd_buf;
- memset(regd_data, 0, sizeof(struct iser_regd_buf));
- regd_data->device = device;
- regd_data->virt_addr = rx_desc->data;
- regd_data->data_size = rx_data_size;
+ tx_desc->num_sge = 1;
- iser_reg_single(device, regd_data, DMA_FROM_DEVICE);
+ if (tx_desc->tx_sg[0].lkey != device->mr->lkey) {
+ tx_desc->tx_sg[0].lkey = device->mr->lkey;
+ iser_dbg("sdesc %p lkey mismatch, fixing\n", tx_desc);
+ }
+}
- iser_dto_add_regd_buff(recv_dto, regd_data, 0, 0);
- err = iser_post_recv(rx_desc);
- if (err) {
- iser_err("Failed iser_post_recv for post %d\n", posts);
- goto post_rx_post_recv_failure;
- }
+int iser_alloc_rx_descriptors(struct iser_conn *ib_conn)
+{
+ int i, j;
+ u64 dma_addr;
+ struct iser_rx_desc *rx_desc;
+ struct ib_sge *rx_sg;
+ struct iser_device *device = ib_conn->device;
+
+ ib_conn->rx_descs = kmalloc(ISER_QP_MAX_RECV_DTOS *
+ sizeof(struct iser_rx_desc), GFP_KERNEL);
+ if (!ib_conn->rx_descs)
+ goto rx_desc_alloc_fail;
+
+ rx_desc = ib_conn->rx_descs;
+
+ for (i = 0; i < ISER_QP_MAX_RECV_DTOS; i++, rx_desc++) {
+ dma_addr = ib_dma_map_single(device->ib_device, (void *)rx_desc,
+ ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+ if (ib_dma_mapping_error(device->ib_device, dma_addr))
+ goto rx_desc_dma_map_failed;
+
+ rx_desc->dma_addr = dma_addr;
+
+ rx_sg = &rx_desc->rx_sg;
+ rx_sg->addr = rx_desc->dma_addr;
+ rx_sg->length = ISER_RX_PAYLOAD_SIZE;
+ rx_sg->lkey = device->mr->lkey;
}
- /* all posts successful */
- return 0;
-post_rx_post_recv_failure:
- iser_dto_buffs_release(recv_dto);
- kfree(rx_desc->data);
-post_rx_kmalloc_failure:
- kmem_cache_free(ig.desc_cache, rx_desc);
-post_rx_cache_alloc_failure:
- if (posts > 0) {
- /*
- * response buffer posted, but did not replace all unexpected
- * pdu recv bufs. Ignore error, retry occurs next send
- */
- outstanding_unexp_pdus -= (posts - 1);
- err = 0;
- }
- atomic_add(outstanding_unexp_pdus,
- &iser_conn->ib_conn->unexpected_pdu_count);
+ ib_conn->rx_desc_head = 0;
+ return 0;
- return err;
+rx_desc_dma_map_failed:
+ rx_desc = ib_conn->rx_descs;
+ for (j = 0; j < i; j++, rx_desc++)
+ ib_dma_unmap_single(device->ib_device, rx_desc->dma_addr,
+ ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+ kfree(ib_conn->rx_descs);
+ ib_conn->rx_descs = NULL;
+rx_desc_alloc_fail:
+ iser_err("failed allocating rx descriptors / data buffers\n");
+ return -ENOMEM;
}
-/* creates a new tx descriptor and adds header regd buffer */
-static void iser_create_send_desc(struct iscsi_iser_conn *iser_conn,
- struct iser_desc *tx_desc)
+void iser_free_rx_descriptors(struct iser_conn *ib_conn)
{
- struct iser_regd_buf *regd_hdr = &tx_desc->hdr_regd_buf;
- struct iser_dto *send_dto = &tx_desc->dto;
+ int i;
+ struct iser_rx_desc *rx_desc;
+ struct iser_device *device = ib_conn->device;
- memset(regd_hdr, 0, sizeof(struct iser_regd_buf));
- regd_hdr->device = iser_conn->ib_conn->device;
- regd_hdr->virt_addr = tx_desc; /* == &tx_desc->iser_header */
- regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN;
+ if (ib_conn->login_buf) {
+ ib_dma_unmap_single(device->ib_device, ib_conn->login_dma,
+ ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE);
+ kfree(ib_conn->login_buf);
+ }
- send_dto->ib_conn = iser_conn->ib_conn;
- send_dto->notify_enable = 1;
- send_dto->regd_vector_len = 0;
+ if (!ib_conn->rx_descs)
+ return;
- memset(&tx_desc->iser_header, 0, sizeof(struct iser_hdr));
- tx_desc->iser_header.flags = ISER_VER;
-
- iser_dto_add_regd_buff(send_dto, regd_hdr, 0, 0);
+ rx_desc = ib_conn->rx_descs;
+ for (i = 0; i < ISER_QP_MAX_RECV_DTOS; i++, rx_desc++)
+ ib_dma_unmap_single(device->ib_device, rx_desc->dma_addr,
+ ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+ kfree(ib_conn->rx_descs);
}
/**
@@ -301,46 +243,23 @@ int iser_conn_set_full_featured_mode(struct iscsi_conn *conn)
{
struct iscsi_iser_conn *iser_conn = conn->dd_data;
- int i;
- /*
- * FIXME this value should be declared to the target during login with
- * the MaxOutstandingUnexpectedPDUs key when supported
- */
- int initial_post_recv_bufs_num = ISER_MAX_RX_MISC_PDUS;
-
- iser_dbg("Initially post: %d\n", initial_post_recv_bufs_num);
+ iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX);
/* Check that there is no posted recv or send buffers left - */
/* they must be consumed during the login phase */
- BUG_ON(atomic_read(&iser_conn->ib_conn->post_recv_buf_count) != 0);
+ BUG_ON(iser_conn->ib_conn->post_recv_buf_count != 0);
BUG_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0);
- /* Initial post receive buffers */
- for (i = 0; i < initial_post_recv_bufs_num; i++) {
- if (iser_post_receive_control(conn) != 0) {
- iser_err("Failed to post recv bufs at:%d conn:0x%p\n",
- i, conn);
- return -ENOMEM;
- }
- }
- iser_dbg("Posted %d post recv bufs, conn:0x%p\n", i, conn);
- return 0;
-}
+ if (iser_alloc_rx_descriptors(iser_conn->ib_conn))
+ return -ENOMEM;
-static int
-iser_check_xmit(struct iscsi_conn *conn, void *task)
-{
- struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ /* Initial post receive buffers */
+ if (iser_post_recvm(iser_conn->ib_conn, ISER_MIN_POSTED_RX))
+ return -ENOMEM;
- if (atomic_read(&iser_conn->ib_conn->post_send_buf_count) ==
- ISER_QP_MAX_REQ_DTOS) {
- iser_dbg("%ld can't xmit task %p\n",jiffies,task);
- return -ENOBUFS;
- }
return 0;
}
-
/**
* iser_send_command - send command PDU
*/
@@ -349,27 +268,18 @@ int iser_send_command(struct iscsi_conn *conn,
{
struct iscsi_iser_conn *iser_conn = conn->dd_data;
struct iscsi_iser_task *iser_task = task->dd_data;
- struct iser_dto *send_dto = NULL;
unsigned long edtl;
- int err = 0;
+ int err;
struct iser_data_buf *data_buf;
struct iscsi_cmd *hdr = (struct iscsi_cmd *)task->hdr;
struct scsi_cmnd *sc = task->sc;
-
- if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
- iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
- return -EPERM;
- }
- if (iser_check_xmit(conn, task))
- return -ENOBUFS;
+ struct iser_tx_desc *tx_desc = &iser_task->desc;
edtl = ntohl(hdr->data_length);
/* build the tx desc regd header and add it to the tx desc dto */
- iser_task->desc.type = ISCSI_TX_SCSI_COMMAND;
- send_dto = &iser_task->desc.dto;
- send_dto->task = iser_task;
- iser_create_send_desc(iser_conn, &iser_task->desc);
+ tx_desc->type = ISCSI_TX_SCSI_COMMAND;
+ iser_create_send_desc(iser_conn->ib_conn, tx_desc);
if (hdr->flags & ISCSI_FLAG_CMD_READ)
data_buf = &iser_task->data[ISER_DIR_IN];
@@ -398,23 +308,13 @@ int iser_send_command(struct iscsi_conn *conn,
goto send_command_error;
}
- iser_reg_single(iser_conn->ib_conn->device,
- send_dto->regd[0], DMA_TO_DEVICE);
-
- if (iser_post_receive_control(conn) != 0) {
- iser_err("post_recv failed!\n");
- err = -ENOMEM;
- goto send_command_error;
- }
-
iser_task->status = ISER_TASK_STATUS_STARTED;
- err = iser_post_send(&iser_task->desc);
+ err = iser_post_send(iser_conn->ib_conn, tx_desc);
if (!err)
return 0;
send_command_error:
- iser_dto_buffs_release(send_dto);
iser_err("conn %p failed task->itt %d err %d\n",conn, task->itt, err);
return err;
}
@@ -428,20 +328,13 @@ int iser_send_data_out(struct iscsi_conn *conn,
{
struct iscsi_iser_conn *iser_conn = conn->dd_data;
struct iscsi_iser_task *iser_task = task->dd_data;
- struct iser_desc *tx_desc = NULL;
- struct iser_dto *send_dto = NULL;
+ struct iser_tx_desc *tx_desc = NULL;
+ struct iser_regd_buf *regd_buf;
unsigned long buf_offset;
unsigned long data_seg_len;
uint32_t itt;
int err = 0;
-
- if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
- iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
- return -EPERM;
- }
-
- if (iser_check_xmit(conn, task))
- return -ENOBUFS;
+ struct ib_sge *tx_dsg;
itt = (__force uint32_t)hdr->itt;
data_seg_len = ntoh24(hdr->dlength);
@@ -450,28 +343,25 @@ int iser_send_data_out(struct iscsi_conn *conn,
iser_dbg("%s itt %d dseg_len %d offset %d\n",
__func__,(int)itt,(int)data_seg_len,(int)buf_offset);
- tx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO);
+ tx_desc = kmem_cache_zalloc(ig.desc_cache, GFP_ATOMIC);
if (tx_desc == NULL) {
iser_err("Failed to alloc desc for post dataout\n");
return -ENOMEM;
}
tx_desc->type = ISCSI_TX_DATAOUT;
+ tx_desc->iser_header.flags = ISER_VER;
memcpy(&tx_desc->iscsi_header, hdr, sizeof(struct iscsi_hdr));
- /* build the tx desc regd header and add it to the tx desc dto */
- send_dto = &tx_desc->dto;
- send_dto->task = iser_task;
- iser_create_send_desc(iser_conn, tx_desc);
-
- iser_reg_single(iser_conn->ib_conn->device,
- send_dto->regd[0], DMA_TO_DEVICE);
+ /* build the tx desc */
+ iser_initialize_task_headers(task, tx_desc);
- /* all data was registered for RDMA, we can use the lkey */
- iser_dto_add_regd_buff(send_dto,
- &iser_task->rdma_regd[ISER_DIR_OUT],
- buf_offset,
- data_seg_len);
+ regd_buf = &iser_task->rdma_regd[ISER_DIR_OUT];
+ tx_dsg = &tx_desc->tx_sg[1];
+ tx_dsg->addr = regd_buf->reg.va + buf_offset;
+ tx_dsg->length = data_seg_len;
+ tx_dsg->lkey = regd_buf->reg.lkey;
+ tx_desc->num_sge = 2;
if (buf_offset + data_seg_len > iser_task->data[ISER_DIR_OUT].data_len) {
iser_err("Offset:%ld & DSL:%ld in Data-Out "
@@ -485,12 +375,11 @@ int iser_send_data_out(struct iscsi_conn *conn,
itt, buf_offset, data_seg_len);
- err = iser_post_send(tx_desc);
+ err = iser_post_send(iser_conn->ib_conn, tx_desc);
if (!err)
return 0;
send_data_out_error:
- iser_dto_buffs_release(send_dto);
kmem_cache_free(ig.desc_cache, tx_desc);
iser_err("conn %p failed err %d\n",conn, err);
return err;
@@ -501,64 +390,44 @@ int iser_send_control(struct iscsi_conn *conn,
{
struct iscsi_iser_conn *iser_conn = conn->dd_data;
struct iscsi_iser_task *iser_task = task->dd_data;
- struct iser_desc *mdesc = &iser_task->desc;
- struct iser_dto *send_dto = NULL;
+ struct iser_tx_desc *mdesc = &iser_task->desc;
unsigned long data_seg_len;
int err = 0;
- struct iser_regd_buf *regd_buf;
struct iser_device *device;
- unsigned char opcode;
-
- if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
- iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
- return -EPERM;
- }
-
- if (iser_check_xmit(conn, task))
- return -ENOBUFS;
/* build the tx desc regd header and add it to the tx desc dto */
mdesc->type = ISCSI_TX_CONTROL;
- send_dto = &mdesc->dto;
- send_dto->task = NULL;
- iser_create_send_desc(iser_conn, mdesc);
+ iser_create_send_desc(iser_conn->ib_conn, mdesc);
device = iser_conn->ib_conn->device;
- iser_reg_single(device, send_dto->regd[0], DMA_TO_DEVICE);
-
data_seg_len = ntoh24(task->hdr->dlength);
if (data_seg_len > 0) {
- regd_buf = &mdesc->data_regd_buf;
- memset(regd_buf, 0, sizeof(struct iser_regd_buf));
- regd_buf->device = device;
- regd_buf->virt_addr = task->data;
- regd_buf->data_size = task->data_count;
- iser_reg_single(device, regd_buf,
- DMA_TO_DEVICE);
- iser_dto_add_regd_buff(send_dto, regd_buf,
- 0,
- data_seg_len);
+ struct ib_sge *tx_dsg = &mdesc->tx_sg[1];
+ if (task != conn->login_task) {
+ iser_err("data present on non login task!!!\n");
+ goto send_control_error;
+ }
+ memcpy(iser_conn->ib_conn->login_buf, task->data,
+ task->data_count);
+ tx_dsg->addr = iser_conn->ib_conn->login_dma;
+ tx_dsg->length = data_seg_len;
+ tx_dsg->lkey = device->mr->lkey;
+ mdesc->num_sge = 2;
}
- opcode = task->hdr->opcode & ISCSI_OPCODE_MASK;
-
- /* post recv buffer for response if one is expected */
- if (!(opcode == ISCSI_OP_NOOP_OUT && task->hdr->itt == RESERVED_ITT)) {
- if (iser_post_receive_control(conn) != 0) {
- iser_err("post_rcv_buff failed!\n");
- err = -ENOMEM;
+ if (task == conn->login_task) {
+ err = iser_post_recvl(iser_conn->ib_conn);
+ if (err)
goto send_control_error;
- }
}
- err = iser_post_send(mdesc);
+ err = iser_post_send(iser_conn->ib_conn, mdesc);
if (!err)
return 0;
send_control_error:
- iser_dto_buffs_release(send_dto);
iser_err("conn %p failed err %d\n",conn, err);
return err;
}
@@ -566,104 +435,71 @@ send_control_error:
/**
* iser_rcv_dto_completion - recv DTO completion
*/
-void iser_rcv_completion(struct iser_desc *rx_desc,
- unsigned long dto_xfer_len)
+void iser_rcv_completion(struct iser_rx_desc *rx_desc,
+ unsigned long rx_xfer_len,
+ struct iser_conn *ib_conn)
{
- struct iser_dto *dto = &rx_desc->dto;
- struct iscsi_iser_conn *conn = dto->ib_conn->iser_conn;
- struct iscsi_task *task;
- struct iscsi_iser_task *iser_task;
+ struct iscsi_iser_conn *conn = ib_conn->iser_conn;
struct iscsi_hdr *hdr;
- char *rx_data = NULL;
- int rx_data_len = 0;
- unsigned char opcode;
-
- hdr = &rx_desc->iscsi_header;
+ u64 rx_dma;
+ int rx_buflen, outstanding, count, err;
+
+ /* differentiate between login to all other PDUs */
+ if ((char *)rx_desc == ib_conn->login_buf) {
+ rx_dma = ib_conn->login_dma;
+ rx_buflen = ISER_RX_LOGIN_SIZE;
+ } else {
+ rx_dma = rx_desc->dma_addr;
+ rx_buflen = ISER_RX_PAYLOAD_SIZE;
+ }
- iser_dbg("op 0x%x itt 0x%x\n", hdr->opcode,hdr->itt);
+ ib_dma_sync_single_for_cpu(ib_conn->device->ib_device, rx_dma,
+ rx_buflen, DMA_FROM_DEVICE);
- if (dto_xfer_len > ISER_TOTAL_HEADERS_LEN) { /* we have data */
- rx_data_len = dto_xfer_len - ISER_TOTAL_HEADERS_LEN;
- rx_data = dto->regd[1]->virt_addr;
- rx_data += dto->offset[1];
- }
+ hdr = &rx_desc->iscsi_header;
- opcode = hdr->opcode & ISCSI_OPCODE_MASK;
-
- if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
- spin_lock(&conn->iscsi_conn->session->lock);
- task = iscsi_itt_to_ctask(conn->iscsi_conn, hdr->itt);
- if (task)
- __iscsi_get_task(task);
- spin_unlock(&conn->iscsi_conn->session->lock);
-
- if (!task)
- iser_err("itt can't be matched to task!!! "
- "conn %p opcode %d itt %d\n",
- conn->iscsi_conn, opcode, hdr->itt);
- else {
- iser_task = task->dd_data;
- iser_dbg("itt %d task %p\n",hdr->itt, task);
- iser_task->status = ISER_TASK_STATUS_COMPLETED;
- iser_task_rdma_finalize(iser_task);
- iscsi_put_task(task);
- }
- }
- iser_dto_buffs_release(dto);
+ iser_dbg("op 0x%x itt 0x%x dlen %d\n", hdr->opcode,
+ hdr->itt, (int)(rx_xfer_len - ISER_HEADERS_LEN));
- iscsi_iser_recv(conn->iscsi_conn, hdr, rx_data, rx_data_len);
+ iscsi_iser_recv(conn->iscsi_conn, hdr,
+ rx_desc->data, rx_xfer_len - ISER_HEADERS_LEN);
- kfree(rx_desc->data);
- kmem_cache_free(ig.desc_cache, rx_desc);
+ ib_dma_sync_single_for_device(ib_conn->device->ib_device, rx_dma,
+ rx_buflen, DMA_FROM_DEVICE);
/* decrementing conn->post_recv_buf_count only --after-- freeing the *
* task eliminates the need to worry on tasks which are completed in *
* parallel to the execution of iser_conn_term. So the code that waits *
* for the posted rx bufs refcount to become zero handles everything */
- atomic_dec(&conn->ib_conn->post_recv_buf_count);
+ conn->ib_conn->post_recv_buf_count--;
- /*
- * if an unexpected PDU was received then the recv wr consumed must
- * be replaced, this is done in the next send of a control-type PDU
- */
- if (opcode == ISCSI_OP_NOOP_IN && hdr->itt == RESERVED_ITT) {
- /* nop-in with itt = 0xffffffff */
- atomic_inc(&conn->ib_conn->unexpected_pdu_count);
- }
- else if (opcode == ISCSI_OP_ASYNC_EVENT) {
- /* asyncronous message */
- atomic_inc(&conn->ib_conn->unexpected_pdu_count);
+ if (rx_dma == ib_conn->login_dma)
+ return;
+
+ outstanding = ib_conn->post_recv_buf_count;
+ if (outstanding + ISER_MIN_POSTED_RX <= ISER_QP_MAX_RECV_DTOS) {
+ count = min(ISER_QP_MAX_RECV_DTOS - outstanding,
+ ISER_MIN_POSTED_RX);
+ err = iser_post_recvm(ib_conn, count);
+ if (err)
+ iser_err("posting %d rx bufs err %d\n", count, err);
}
- /* a reject PDU consumes the recv buf posted for the response */
}
-void iser_snd_completion(struct iser_desc *tx_desc)
+void iser_snd_completion(struct iser_tx_desc *tx_desc,
+ struct iser_conn *ib_conn)
{
- struct iser_dto *dto = &tx_desc->dto;
- struct iser_conn *ib_conn = dto->ib_conn;
- struct iscsi_iser_conn *iser_conn = ib_conn->iser_conn;
- struct iscsi_conn *conn = iser_conn->iscsi_conn;
struct iscsi_task *task;
- int resume_tx = 0;
-
- iser_dbg("Initiator, Data sent dto=0x%p\n", dto);
-
- iser_dto_buffs_release(dto);
+ struct iser_device *device = ib_conn->device;
- if (tx_desc->type == ISCSI_TX_DATAOUT)
+ if (tx_desc->type == ISCSI_TX_DATAOUT) {
+ ib_dma_unmap_single(device->ib_device, tx_desc->dma_addr,
+ ISER_HEADERS_LEN, DMA_TO_DEVICE);
kmem_cache_free(ig.desc_cache, tx_desc);
-
- if (atomic_read(&iser_conn->ib_conn->post_send_buf_count) ==
- ISER_QP_MAX_REQ_DTOS)
- resume_tx = 1;
+ }
atomic_dec(&ib_conn->post_send_buf_count);
- if (resume_tx) {
- iser_dbg("%ld resuming tx\n",jiffies);
- iscsi_conn_queue_work(conn);
- }
-
if (tx_desc->type == ISCSI_TX_CONTROL) {
/* this arithmetic is legal by libiscsi dd_data allocation */
task = (void *) ((long)(void *)tx_desc -
@@ -692,7 +528,6 @@ void iser_task_rdma_init(struct iscsi_iser_task *iser_task)
void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task)
{
- int deferred;
int is_rdma_aligned = 1;
struct iser_regd_buf *regd;
@@ -710,32 +545,17 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task)
if (iser_task->dir[ISER_DIR_IN]) {
regd = &iser_task->rdma_regd[ISER_DIR_IN];
- deferred = iser_regd_buff_release(regd);
- if (deferred) {
- iser_err("%d references remain for BUF-IN rdma reg\n",
- atomic_read(&regd->ref_count));
- }
+ if (regd->reg.is_fmr)
+ iser_unreg_mem(&regd->reg);
}
if (iser_task->dir[ISER_DIR_OUT]) {
regd = &iser_task->rdma_regd[ISER_DIR_OUT];
- deferred = iser_regd_buff_release(regd);
- if (deferred) {
- iser_err("%d references remain for BUF-OUT rdma reg\n",
- atomic_read(&regd->ref_count));
- }
+ if (regd->reg.is_fmr)
+ iser_unreg_mem(&regd->reg);
}
/* if the data was unaligned, it was already unmapped and then copied */
if (is_rdma_aligned)
iser_dma_unmap_task_data(iser_task);
}
-
-void iser_dto_buffs_release(struct iser_dto *dto)
-{
- int i;
-
- for (i = 0; i < dto->regd_vector_len; i++)
- iser_regd_buff_release(dto->regd[i]);
-}
-
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index 274c883ef3ea..fb88d6896b67 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -41,62 +41,6 @@
#define ISER_KMALLOC_THRESHOLD 0x20000 /* 128K - kmalloc limit */
/**
- * Decrements the reference count for the
- * registered buffer & releases it
- *
- * returns 0 if released, 1 if deferred
- */
-int iser_regd_buff_release(struct iser_regd_buf *regd_buf)
-{
- struct ib_device *dev;
-
- if ((atomic_read(&regd_buf->ref_count) == 0) ||
- atomic_dec_and_test(&regd_buf->ref_count)) {
- /* if we used the dma mr, unreg is just NOP */
- if (regd_buf->reg.is_fmr)
- iser_unreg_mem(&regd_buf->reg);
-
- if (regd_buf->dma_addr) {
- dev = regd_buf->device->ib_device;
- ib_dma_unmap_single(dev,
- regd_buf->dma_addr,
- regd_buf->data_size,
- regd_buf->direction);
- }
- /* else this regd buf is associated with task which we */
- /* dma_unmap_single/sg later */
- return 0;
- } else {
- iser_dbg("Release deferred, regd.buff: 0x%p\n", regd_buf);
- return 1;
- }
-}
-
-/**
- * iser_reg_single - fills registered buffer descriptor with
- * registration information
- */
-void iser_reg_single(struct iser_device *device,
- struct iser_regd_buf *regd_buf,
- enum dma_data_direction direction)
-{
- u64 dma_addr;
-
- dma_addr = ib_dma_map_single(device->ib_device,
- regd_buf->virt_addr,
- regd_buf->data_size, direction);
- BUG_ON(ib_dma_mapping_error(device->ib_device, dma_addr));
-
- regd_buf->reg.lkey = device->mr->lkey;
- regd_buf->reg.len = regd_buf->data_size;
- regd_buf->reg.va = dma_addr;
- regd_buf->reg.is_fmr = 0;
-
- regd_buf->dma_addr = dma_addr;
- regd_buf->direction = direction;
-}
-
-/**
* iser_start_rdma_unaligned_sg
*/
static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
@@ -109,10 +53,10 @@ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
unsigned long cmd_data_len = data->data_len;
if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
- mem = (void *)__get_free_pages(GFP_NOIO,
+ mem = (void *)__get_free_pages(GFP_ATOMIC,
ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
else
- mem = kmalloc(cmd_data_len, GFP_NOIO);
+ mem = kmalloc(cmd_data_len, GFP_ATOMIC);
if (mem == NULL) {
iser_err("Failed to allocate mem size %d %d for copying sglist\n",
@@ -474,9 +418,5 @@ int iser_reg_rdma_mem(struct iscsi_iser_task *iser_task,
return err;
}
}
-
- /* take a reference on this regd buf such that it will not be released *
- * (eg in send dto completion) before we get the scsi response */
- atomic_inc(&regd_buf->ref_count);
return 0;
}
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 8579f32ce38e..308d17bb5146 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -37,9 +37,8 @@
#include "iscsi_iser.h"
#define ISCSI_ISER_MAX_CONN 8
-#define ISER_MAX_CQ_LEN ((ISER_QP_MAX_RECV_DTOS + \
- ISER_QP_MAX_REQ_DTOS) * \
- ISCSI_ISER_MAX_CONN)
+#define ISER_MAX_RX_CQ_LEN (ISER_QP_MAX_RECV_DTOS * ISCSI_ISER_MAX_CONN)
+#define ISER_MAX_TX_CQ_LEN (ISER_QP_MAX_REQ_DTOS * ISCSI_ISER_MAX_CONN)
static void iser_cq_tasklet_fn(unsigned long data);
static void iser_cq_callback(struct ib_cq *cq, void *cq_context);
@@ -67,15 +66,23 @@ static int iser_create_device_ib_res(struct iser_device *device)
if (IS_ERR(device->pd))
goto pd_err;
- device->cq = ib_create_cq(device->ib_device,
+ device->rx_cq = ib_create_cq(device->ib_device,
iser_cq_callback,
iser_cq_event_callback,
(void *)device,
- ISER_MAX_CQ_LEN, 0);
- if (IS_ERR(device->cq))
- goto cq_err;
+ ISER_MAX_RX_CQ_LEN, 0);
+ if (IS_ERR(device->rx_cq))
+ goto rx_cq_err;
- if (ib_req_notify_cq(device->cq, IB_CQ_NEXT_COMP))
+ device->tx_cq = ib_create_cq(device->ib_device,
+ NULL, iser_cq_event_callback,
+ (void *)device,
+ ISER_MAX_TX_CQ_LEN, 0);
+
+ if (IS_ERR(device->tx_cq))
+ goto tx_cq_err;
+
+ if (ib_req_notify_cq(device->rx_cq, IB_CQ_NEXT_COMP))
goto cq_arm_err;
tasklet_init(&device->cq_tasklet,
@@ -93,8 +100,10 @@ static int iser_create_device_ib_res(struct iser_device *device)
dma_mr_err:
tasklet_kill(&device->cq_tasklet);
cq_arm_err:
- ib_destroy_cq(device->cq);
-cq_err:
+ ib_destroy_cq(device->tx_cq);
+tx_cq_err:
+ ib_destroy_cq(device->rx_cq);
+rx_cq_err:
ib_dealloc_pd(device->pd);
pd_err:
iser_err("failed to allocate an IB resource\n");
@@ -112,11 +121,13 @@ static void iser_free_device_ib_res(struct iser_device *device)
tasklet_kill(&device->cq_tasklet);
(void)ib_dereg_mr(device->mr);
- (void)ib_destroy_cq(device->cq);
+ (void)ib_destroy_cq(device->tx_cq);
+ (void)ib_destroy_cq(device->rx_cq);
(void)ib_dealloc_pd(device->pd);
device->mr = NULL;
- device->cq = NULL;
+ device->tx_cq = NULL;
+ device->rx_cq = NULL;
device->pd = NULL;
}
@@ -129,13 +140,23 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn)
{
struct iser_device *device;
struct ib_qp_init_attr init_attr;
- int ret;
+ int ret = -ENOMEM;
struct ib_fmr_pool_param params;
BUG_ON(ib_conn->device == NULL);
device = ib_conn->device;
+ ib_conn->login_buf = kmalloc(ISER_RX_LOGIN_SIZE, GFP_KERNEL);
+ if (!ib_conn->login_buf) {
+ goto alloc_err;
+ ret = -ENOMEM;
+ }
+
+ ib_conn->login_dma = ib_dma_map_single(ib_conn->device->ib_device,
+ (void *)ib_conn->login_buf, ISER_RX_LOGIN_SIZE,
+ DMA_FROM_DEVICE);
+
ib_conn->page_vec = kmalloc(sizeof(struct iser_page_vec) +
(sizeof(u64) * (ISCSI_ISER_SG_TABLESIZE +1)),
GFP_KERNEL);
@@ -169,12 +190,12 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn)
init_attr.event_handler = iser_qp_event_callback;
init_attr.qp_context = (void *)ib_conn;
- init_attr.send_cq = device->cq;
- init_attr.recv_cq = device->cq;
+ init_attr.send_cq = device->tx_cq;
+ init_attr.recv_cq = device->rx_cq;
init_attr.cap.max_send_wr = ISER_QP_MAX_REQ_DTOS;
init_attr.cap.max_recv_wr = ISER_QP_MAX_RECV_DTOS;
- init_attr.cap.max_send_sge = MAX_REGD_BUF_VECTOR_LEN;
- init_attr.cap.max_recv_sge = 2;
+ init_attr.cap.max_send_sge = 2;
+ init_attr.cap.max_recv_sge = 1;
init_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
init_attr.qp_type = IB_QPT_RC;
@@ -192,6 +213,7 @@ qp_err:
(void)ib_destroy_fmr_pool(ib_conn->fmr_pool);
fmr_pool_err:
kfree(ib_conn->page_vec);
+ kfree(ib_conn->login_buf);
alloc_err:
iser_err("unable to alloc mem or create resource, err %d\n", ret);
return ret;
@@ -278,17 +300,6 @@ static void iser_device_try_release(struct iser_device *device)
mutex_unlock(&ig.device_list_mutex);
}
-int iser_conn_state_comp(struct iser_conn *ib_conn,
- enum iser_ib_conn_state comp)
-{
- int ret;
-
- spin_lock_bh(&ib_conn->lock);
- ret = (ib_conn->state == comp);
- spin_unlock_bh(&ib_conn->lock);
- return ret;
-}
-
static int iser_conn_state_comp_exch(struct iser_conn *ib_conn,
enum iser_ib_conn_state comp,
enum iser_ib_conn_state exch)
@@ -314,7 +325,7 @@ static void iser_conn_release(struct iser_conn *ib_conn)
mutex_lock(&ig.connlist_mutex);
list_del(&ib_conn->conn_list);
mutex_unlock(&ig.connlist_mutex);
-
+ iser_free_rx_descriptors(ib_conn);
iser_free_ib_conn_res(ib_conn);
ib_conn->device = NULL;
/* on EVENT_ADDR_ERROR there's no device yet for this conn */
@@ -442,7 +453,7 @@ static void iser_disconnected_handler(struct rdma_cm_id *cma_id)
ISCSI_ERR_CONN_FAILED);
/* Complete the termination process if no posts are pending */
- if ((atomic_read(&ib_conn->post_recv_buf_count) == 0) &&
+ if (ib_conn->post_recv_buf_count == 0 &&
(atomic_read(&ib_conn->post_send_buf_count) == 0)) {
ib_conn->state = ISER_CONN_DOWN;
wake_up_interruptible(&ib_conn->wait);
@@ -489,9 +500,8 @@ void iser_conn_init(struct iser_conn *ib_conn)
{
ib_conn->state = ISER_CONN_INIT;
init_waitqueue_head(&ib_conn->wait);
- atomic_set(&ib_conn->post_recv_buf_count, 0);
+ ib_conn->post_recv_buf_count = 0;
atomic_set(&ib_conn->post_send_buf_count, 0);
- atomic_set(&ib_conn->unexpected_pdu_count, 0);
atomic_set(&ib_conn->refcount, 1);
INIT_LIST_HEAD(&ib_conn->conn_list);
spin_lock_init(&ib_conn->lock);
@@ -626,136 +636,97 @@ void iser_unreg_mem(struct iser_mem_reg *reg)
reg->mem_h = NULL;
}
-/**
- * iser_dto_to_iov - builds IOV from a dto descriptor
- */
-static void iser_dto_to_iov(struct iser_dto *dto, struct ib_sge *iov, int iov_len)
+int iser_post_recvl(struct iser_conn *ib_conn)
{
- int i;
- struct ib_sge *sge;
- struct iser_regd_buf *regd_buf;
-
- if (dto->regd_vector_len > iov_len) {
- iser_err("iov size %d too small for posting dto of len %d\n",
- iov_len, dto->regd_vector_len);
- BUG();
- }
+ struct ib_recv_wr rx_wr, *rx_wr_failed;
+ struct ib_sge sge;
+ int ib_ret;
- for (i = 0; i < dto->regd_vector_len; i++) {
- sge = &iov[i];
- regd_buf = dto->regd[i];
-
- sge->addr = regd_buf->reg.va;
- sge->length = regd_buf->reg.len;
- sge->lkey = regd_buf->reg.lkey;
-
- if (dto->used_sz[i] > 0) /* Adjust size */
- sge->length = dto->used_sz[i];
-
- /* offset and length should not exceed the regd buf length */
- if (sge->length + dto->offset[i] > regd_buf->reg.len) {
- iser_err("Used len:%ld + offset:%d, exceed reg.buf.len:"
- "%ld in dto:0x%p [%d], va:0x%08lX\n",
- (unsigned long)sge->length, dto->offset[i],
- (unsigned long)regd_buf->reg.len, dto, i,
- (unsigned long)sge->addr);
- BUG();
- }
+ sge.addr = ib_conn->login_dma;
+ sge.length = ISER_RX_LOGIN_SIZE;
+ sge.lkey = ib_conn->device->mr->lkey;
- sge->addr += dto->offset[i]; /* Adjust offset */
+ rx_wr.wr_id = (unsigned long)ib_conn->login_buf;
+ rx_wr.sg_list = &sge;
+ rx_wr.num_sge = 1;
+ rx_wr.next = NULL;
+
+ ib_conn->post_recv_buf_count++;
+ ib_ret = ib_post_recv(ib_conn->qp, &rx_wr, &rx_wr_failed);
+ if (ib_ret) {
+ iser_err("ib_post_recv failed ret=%d\n", ib_ret);
+ ib_conn->post_recv_buf_count--;
}
+ return ib_ret;
}
-/**
- * iser_post_recv - Posts a receive buffer.
- *
- * returns 0 on success, -1 on failure
- */
-int iser_post_recv(struct iser_desc *rx_desc)
+int iser_post_recvm(struct iser_conn *ib_conn, int count)
{
- int ib_ret, ret_val = 0;
- struct ib_recv_wr recv_wr, *recv_wr_failed;
- struct ib_sge iov[2];
- struct iser_conn *ib_conn;
- struct iser_dto *recv_dto = &rx_desc->dto;
-
- /* Retrieve conn */
- ib_conn = recv_dto->ib_conn;
-
- iser_dto_to_iov(recv_dto, iov, 2);
+ struct ib_recv_wr *rx_wr, *rx_wr_failed;
+ int i, ib_ret;
+ unsigned int my_rx_head = ib_conn->rx_desc_head;
+ struct iser_rx_desc *rx_desc;
+
+ for (rx_wr = ib_conn->rx_wr, i = 0; i < count; i++, rx_wr++) {
+ rx_desc = &ib_conn->rx_descs[my_rx_head];
+ rx_wr->wr_id = (unsigned long)rx_desc;
+ rx_wr->sg_list = &rx_desc->rx_sg;
+ rx_wr->num_sge = 1;
+ rx_wr->next = rx_wr + 1;
+ my_rx_head = (my_rx_head + 1) & (ISER_QP_MAX_RECV_DTOS - 1);
+ }
- recv_wr.next = NULL;
- recv_wr.sg_list = iov;
- recv_wr.num_sge = recv_dto->regd_vector_len;
- recv_wr.wr_id = (unsigned long)rx_desc;
+ rx_wr--;
+ rx_wr->next = NULL; /* mark end of work requests list */
- atomic_inc(&ib_conn->post_recv_buf_count);
- ib_ret = ib_post_recv(ib_conn->qp, &recv_wr, &recv_wr_failed);
+ ib_conn->post_recv_buf_count += count;
+ ib_ret = ib_post_recv(ib_conn->qp, ib_conn->rx_wr, &rx_wr_failed);
if (ib_ret) {
iser_err("ib_post_recv failed ret=%d\n", ib_ret);
- atomic_dec(&ib_conn->post_recv_buf_count);
- ret_val = -1;
- }
-
- return ret_val;
+ ib_conn->post_recv_buf_count -= count;
+ } else
+ ib_conn->rx_desc_head = my_rx_head;
+ return ib_ret;
}
+
/**
* iser_start_send - Initiate a Send DTO operation
*
* returns 0 on success, -1 on failure
*/
-int iser_post_send(struct iser_desc *tx_desc)
+int iser_post_send(struct iser_conn *ib_conn, struct iser_tx_desc *tx_desc)
{
- int ib_ret, ret_val = 0;
+ int ib_ret;
struct ib_send_wr send_wr, *send_wr_failed;
- struct ib_sge iov[MAX_REGD_BUF_VECTOR_LEN];
- struct iser_conn *ib_conn;
- struct iser_dto *dto = &tx_desc->dto;
- ib_conn = dto->ib_conn;
-
- iser_dto_to_iov(dto, iov, MAX_REGD_BUF_VECTOR_LEN);
+ ib_dma_sync_single_for_device(ib_conn->device->ib_device,
+ tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE);
send_wr.next = NULL;
send_wr.wr_id = (unsigned long)tx_desc;
- send_wr.sg_list = iov;
- send_wr.num_sge = dto->regd_vector_len;
+ send_wr.sg_list = tx_desc->tx_sg;
+ send_wr.num_sge = tx_desc->num_sge;
send_wr.opcode = IB_WR_SEND;
- send_wr.send_flags = dto->notify_enable ? IB_SEND_SIGNALED : 0;
+ send_wr.send_flags = IB_SEND_SIGNALED;
atomic_inc(&ib_conn->post_send_buf_count);
ib_ret = ib_post_send(ib_conn->qp, &send_wr, &send_wr_failed);
if (ib_ret) {
- iser_err("Failed to start SEND DTO, dto: 0x%p, IOV len: %d\n",
- dto, dto->regd_vector_len);
iser_err("ib_post_send failed, ret:%d\n", ib_ret);
atomic_dec(&ib_conn->post_send_buf_count);
- ret_val = -1;
}
-
- return ret_val;
+ return ib_ret;
}
-static void iser_handle_comp_error(struct iser_desc *desc)
+static void iser_handle_comp_error(struct iser_tx_desc *desc,
+ struct iser_conn *ib_conn)
{
- struct iser_dto *dto = &desc->dto;
- struct iser_conn *ib_conn = dto->ib_conn;
-
- iser_dto_buffs_release(dto);
-
- if (desc->type == ISCSI_RX) {
- kfree(desc->data);
+ if (desc && desc->type == ISCSI_TX_DATAOUT)
kmem_cache_free(ig.desc_cache, desc);
- atomic_dec(&ib_conn->post_recv_buf_count);
- } else { /* type is TX control/command/dataout */
- if (desc->type == ISCSI_TX_DATAOUT)
- kmem_cache_free(ig.desc_cache, desc);
- atomic_dec(&ib_conn->post_send_buf_count);
- }
- if (atomic_read(&ib_conn->post_recv_buf_count) == 0 &&
+ if (ib_conn->post_recv_buf_count == 0 &&
atomic_read(&ib_conn->post_send_buf_count) == 0) {
/* getting here when the state is UP means that the conn is *
* being terminated asynchronously from the iSCSI layer's *
@@ -774,32 +745,74 @@ static void iser_handle_comp_error(struct iser_desc *desc)
}
}
+static int iser_drain_tx_cq(struct iser_device *device)
+{
+ struct ib_cq *cq = device->tx_cq;
+ struct ib_wc wc;
+ struct iser_tx_desc *tx_desc;
+ struct iser_conn *ib_conn;
+ int completed_tx = 0;
+
+ while (ib_poll_cq(cq, 1, &wc) == 1) {
+ tx_desc = (struct iser_tx_desc *) (unsigned long) wc.wr_id;
+ ib_conn = wc.qp->qp_context;
+ if (wc.status == IB_WC_SUCCESS) {
+ if (wc.opcode == IB_WC_SEND)
+ iser_snd_completion(tx_desc, ib_conn);
+ else
+ iser_err("expected opcode %d got %d\n",
+ IB_WC_SEND, wc.opcode);
+ } else {
+ iser_err("tx id %llx status %d vend_err %x\n",
+ wc.wr_id, wc.status, wc.vendor_err);
+ atomic_dec(&ib_conn->post_send_buf_count);
+ iser_handle_comp_error(tx_desc, ib_conn);
+ }
+ completed_tx++;
+ }
+ return completed_tx;
+}
+
+
static void iser_cq_tasklet_fn(unsigned long data)
{
struct iser_device *device = (struct iser_device *)data;
- struct ib_cq *cq = device->cq;
+ struct ib_cq *cq = device->rx_cq;
struct ib_wc wc;
- struct iser_desc *desc;
+ struct iser_rx_desc *desc;
unsigned long xfer_len;
+ struct iser_conn *ib_conn;
+ int completed_tx, completed_rx;
+ completed_tx = completed_rx = 0;
while (ib_poll_cq(cq, 1, &wc) == 1) {
- desc = (struct iser_desc *) (unsigned long) wc.wr_id;
+ desc = (struct iser_rx_desc *) (unsigned long) wc.wr_id;
BUG_ON(desc == NULL);
-
+ ib_conn = wc.qp->qp_context;
if (wc.status == IB_WC_SUCCESS) {
- if (desc->type == ISCSI_RX) {
+ if (wc.opcode == IB_WC_RECV) {
xfer_len = (unsigned long)wc.byte_len;
- iser_rcv_completion(desc, xfer_len);
- } else /* type == ISCSI_TX_CONTROL/SCSI_CMD/DOUT */
- iser_snd_completion(desc);
+ iser_rcv_completion(desc, xfer_len, ib_conn);
+ } else
+ iser_err("expected opcode %d got %d\n",
+ IB_WC_RECV, wc.opcode);
} else {
- iser_err("comp w. error op %d status %d\n",desc->type,wc.status);
- iser_handle_comp_error(desc);
+ if (wc.status != IB_WC_WR_FLUSH_ERR)
+ iser_err("rx id %llx status %d vend_err %x\n",
+ wc.wr_id, wc.status, wc.vendor_err);
+ ib_conn->post_recv_buf_count--;
+ iser_handle_comp_error(NULL, ib_conn);
}
+ completed_rx++;
+ if (!(completed_rx & 63))
+ completed_tx += iser_drain_tx_cq(device);
}
/* #warning "it is assumed here that arming CQ only once its empty" *
* " would not cause interrupts to be missed" */
ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+
+ completed_tx += iser_drain_tx_cq(device);
+ iser_dbg("got %d rx %d tx completions\n", completed_rx, completed_tx);
}
static void iser_cq_callback(struct ib_cq *cq, void *cq_context)
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 54c8fe25c423..ed3f9ebae882 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -80,7 +80,8 @@ MODULE_PARM_DESC(mellanox_workarounds,
static void srp_add_one(struct ib_device *device);
static void srp_remove_one(struct ib_device *device);
-static void srp_completion(struct ib_cq *cq, void *target_ptr);
+static void srp_recv_completion(struct ib_cq *cq, void *target_ptr);
+static void srp_send_completion(struct ib_cq *cq, void *target_ptr);
static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
static struct scsi_transport_template *ib_srp_transport_template;
@@ -227,14 +228,21 @@ static int srp_create_target_ib(struct srp_target_port *target)
if (!init_attr)
return -ENOMEM;
- target->cq = ib_create_cq(target->srp_host->srp_dev->dev,
- srp_completion, NULL, target, SRP_CQ_SIZE, 0);
- if (IS_ERR(target->cq)) {
- ret = PTR_ERR(target->cq);
- goto out;
+ target->recv_cq = ib_create_cq(target->srp_host->srp_dev->dev,
+ srp_recv_completion, NULL, target, SRP_RQ_SIZE, 0);
+ if (IS_ERR(target->recv_cq)) {
+ ret = PTR_ERR(target->recv_cq);
+ goto err;
}
- ib_req_notify_cq(target->cq, IB_CQ_NEXT_COMP);
+ target->send_cq = ib_create_cq(target->srp_host->srp_dev->dev,
+ srp_send_completion, NULL, target, SRP_SQ_SIZE, 0);
+ if (IS_ERR(target->send_cq)) {
+ ret = PTR_ERR(target->send_cq);
+ goto err_recv_cq;
+ }
+
+ ib_req_notify_cq(target->recv_cq, IB_CQ_NEXT_COMP);
init_attr->event_handler = srp_qp_event;
init_attr->cap.max_send_wr = SRP_SQ_SIZE;
@@ -243,24 +251,32 @@ static int srp_create_target_ib(struct srp_target_port *target)
init_attr->cap.max_send_sge = 1;
init_attr->sq_sig_type = IB_SIGNAL_ALL_WR;
init_attr->qp_type = IB_QPT_RC;
- init_attr->send_cq = target->cq;
- init_attr->recv_cq = target->cq;
+ init_attr->send_cq = target->send_cq;
+ init_attr->recv_cq = target->recv_cq;
target->qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr);
if (IS_ERR(target->qp)) {
ret = PTR_ERR(target->qp);
- ib_destroy_cq(target->cq);
- goto out;
+ goto err_send_cq;
}
ret = srp_init_qp(target, target->qp);
- if (ret) {
- ib_destroy_qp(target->qp);
- ib_destroy_cq(target->cq);
- goto out;
- }
+ if (ret)
+ goto err_qp;
-out:
+ kfree(init_attr);
+ return 0;
+
+err_qp:
+ ib_destroy_qp(target->qp);
+
+err_send_cq:
+ ib_destroy_cq(target->send_cq);
+
+err_recv_cq:
+ ib_destroy_cq(target->recv_cq);
+
+err:
kfree(init_attr);
return ret;
}
@@ -270,7 +286,8 @@ static void srp_free_target_ib(struct srp_target_port *target)
int i;
ib_destroy_qp(target->qp);
- ib_destroy_cq(target->cq);
+ ib_destroy_cq(target->send_cq);
+ ib_destroy_cq(target->recv_cq);
for (i = 0; i < SRP_RQ_SIZE; ++i)
srp_free_iu(target->srp_host, target->rx_ring[i]);
@@ -568,7 +585,9 @@ static int srp_reconnect_target(struct srp_target_port *target)
if (ret)
goto err;
- while (ib_poll_cq(target->cq, 1, &wc) > 0)
+ while (ib_poll_cq(target->recv_cq, 1, &wc) > 0)
+ ; /* nothing */
+ while (ib_poll_cq(target->send_cq, 1, &wc) > 0)
; /* nothing */
spin_lock_irq(target->scsi_host->host_lock);
@@ -851,7 +870,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
struct srp_iu *iu;
u8 opcode;
- iu = target->rx_ring[wc->wr_id & ~SRP_OP_RECV];
+ iu = target->rx_ring[wc->wr_id];
dev = target->srp_host->srp_dev->dev;
ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len,
@@ -898,7 +917,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
DMA_FROM_DEVICE);
}
-static void srp_completion(struct ib_cq *cq, void *target_ptr)
+static void srp_recv_completion(struct ib_cq *cq, void *target_ptr)
{
struct srp_target_port *target = target_ptr;
struct ib_wc wc;
@@ -907,17 +926,31 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr)
while (ib_poll_cq(cq, 1, &wc) > 0) {
if (wc.status) {
shost_printk(KERN_ERR, target->scsi_host,
- PFX "failed %s status %d\n",
- wc.wr_id & SRP_OP_RECV ? "receive" : "send",
+ PFX "failed receive status %d\n",
wc.status);
target->qp_in_error = 1;
break;
}
- if (wc.wr_id & SRP_OP_RECV)
- srp_handle_recv(target, &wc);
- else
- ++target->tx_tail;
+ srp_handle_recv(target, &wc);
+ }
+}
+
+static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
+{
+ struct srp_target_port *target = target_ptr;
+ struct ib_wc wc;
+
+ while (ib_poll_cq(cq, 1, &wc) > 0) {
+ if (wc.status) {
+ shost_printk(KERN_ERR, target->scsi_host,
+ PFX "failed send status %d\n",
+ wc.status);
+ target->qp_in_error = 1;
+ break;
+ }
+
+ ++target->tx_tail;
}
}
@@ -930,7 +963,7 @@ static int __srp_post_recv(struct srp_target_port *target)
int ret;
next = target->rx_head & (SRP_RQ_SIZE - 1);
- wr.wr_id = next | SRP_OP_RECV;
+ wr.wr_id = next;
iu = target->rx_ring[next];
list.addr = iu->dma;
@@ -970,6 +1003,8 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
{
s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2;
+ srp_send_completion(target->send_cq, target);
+
if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
return NULL;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index e185b907fc12..5a80eac6fdaa 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -60,7 +60,6 @@ enum {
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),
@@ -69,8 +68,6 @@ enum {
SRP_FMR_DIRTY_SIZE = SRP_FMR_POOL_SIZE / 4
};
-#define SRP_OP_RECV (1 << 31)
-
enum srp_target_state {
SRP_TARGET_LIVE,
SRP_TARGET_CONNECTING,
@@ -133,7 +130,8 @@ struct srp_target_port {
int path_query_id;
struct ib_cm_id *cm_id;
- struct ib_cq *cq;
+ struct ib_cq *recv_cq;
+ struct ib_cq *send_cq;
struct ib_qp *qp;
int max_ti_iu_len;
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index dee6706038aa..2ee6c7a68bdc 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -59,7 +59,8 @@ static void evdev_pass_event(struct evdev_client *client,
client->head &= EVDEV_BUFFER_SIZE - 1;
spin_unlock(&client->buffer_lock);
- kill_fasync(&client->fasync, SIGIO, POLL_IN);
+ if (event->type == EV_SYN)
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
/*
@@ -277,6 +278,8 @@ static int evdev_open(struct inode *inode, struct file *file)
goto err_free_client;
file->private_data = client;
+ nonseekable_open(inode, file);
+
return 0;
err_free_client:
@@ -512,7 +515,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
struct input_absinfo abs;
struct ff_effect effect;
int __user *ip = (int __user *)p;
- int i, t, u, v;
+ unsigned int i, t, u, v;
int error;
switch (cmd) {
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
index b04930f7ea7d..7392992da424 100644
--- a/drivers/input/gameport/emu10k1-gp.c
+++ b/drivers/input/gameport/emu10k1-gp.c
@@ -46,7 +46,7 @@ struct emu {
int size;
};
-static struct pci_device_id emu_tbl[] = {
+static const struct pci_device_id emu_tbl[] = {
{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
{ 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
index 8a1810f88b9e..14d3f3e208a2 100644
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -140,7 +140,7 @@ static void __devexit fm801_gp_remove(struct pci_dev *pci)
}
}
-static struct pci_device_id fm801_gp_id_table[] = {
+static const struct pci_device_id fm801_gp_id_table[] = {
{ PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0 }
};
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index ac11be08585e..7e18bcf05a66 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -11,6 +11,8 @@
* the Free Software Foundation.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/ioport.h>
@@ -190,9 +192,8 @@ static int gameport_bind_driver(struct gameport *gameport, struct gameport_drive
error = device_bind_driver(&gameport->dev);
if (error) {
- printk(KERN_WARNING
- "gameport: device_bind_driver() failed "
- "for %s (%s) and %s, error: %d\n",
+ dev_warn(&gameport->dev,
+ "device_bind_driver() failed for %s (%s) and %s, error: %d\n",
gameport->phys, gameport->name,
drv->description, error);
drv->disconnect(gameport);
@@ -209,9 +210,9 @@ static void gameport_find_driver(struct gameport *gameport)
error = device_attach(&gameport->dev);
if (error < 0)
- printk(KERN_WARNING
- "gameport: device_attach() failed for %s (%s), error: %d\n",
- gameport->phys, gameport->name, error);
+ dev_warn(&gameport->dev,
+ "device_attach() failed for %s (%s), error: %d\n",
+ gameport->phys, gameport->name, error);
}
@@ -262,17 +263,14 @@ static int gameport_queue_event(void *object, struct module *owner,
event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
if (!event) {
- printk(KERN_ERR
- "gameport: Not enough memory to queue event %d\n",
- event_type);
+ pr_err("Not enough memory to queue event %d\n", event_type);
retval = -ENOMEM;
goto out;
}
if (!try_module_get(owner)) {
- printk(KERN_WARNING
- "gameport: Can't get module reference, dropping event %d\n",
- event_type);
+ pr_warning("Can't get module reference, dropping event %d\n",
+ event_type);
kfree(event);
retval = -EINVAL;
goto out;
@@ -298,14 +296,12 @@ static void gameport_free_event(struct gameport_event *event)
static void gameport_remove_duplicate_events(struct gameport_event *event)
{
- struct list_head *node, *next;
- struct gameport_event *e;
+ struct gameport_event *e, *next;
unsigned long flags;
spin_lock_irqsave(&gameport_event_lock, flags);
- list_for_each_safe(node, next, &gameport_event_list) {
- e = list_entry(node, struct gameport_event, node);
+ list_for_each_entry_safe(e, next, &gameport_event_list, node) {
if (event->object == e->object) {
/*
* If this event is of different type we should not
@@ -315,7 +311,7 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
if (event->type != e->type)
break;
- list_del_init(node);
+ list_del_init(&e->node);
gameport_free_event(e);
}
}
@@ -325,23 +321,18 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
static struct gameport_event *gameport_get_event(void)
{
- struct gameport_event *event;
- struct list_head *node;
+ struct gameport_event *event = NULL;
unsigned long flags;
spin_lock_irqsave(&gameport_event_lock, flags);
- if (list_empty(&gameport_event_list)) {
- spin_unlock_irqrestore(&gameport_event_lock, flags);
- return NULL;
+ if (!list_empty(&gameport_event_list)) {
+ event = list_first_entry(&gameport_event_list,
+ struct gameport_event, node);
+ list_del_init(&event->node);
}
- node = gameport_event_list.next;
- event = list_entry(node, struct gameport_event, node);
- list_del_init(node);
-
spin_unlock_irqrestore(&gameport_event_lock, flags);
-
return event;
}
@@ -360,16 +351,14 @@ static void gameport_handle_event(void)
if ((event = gameport_get_event())) {
switch (event->type) {
- case GAMEPORT_REGISTER_PORT:
- gameport_add_port(event->object);
- break;
- case GAMEPORT_ATTACH_DRIVER:
- gameport_attach_driver(event->object);
- break;
+ case GAMEPORT_REGISTER_PORT:
+ gameport_add_port(event->object);
+ break;
- default:
- break;
+ case GAMEPORT_ATTACH_DRIVER:
+ gameport_attach_driver(event->object);
+ break;
}
gameport_remove_duplicate_events(event);
@@ -385,16 +374,14 @@ static void gameport_handle_event(void)
*/
static void gameport_remove_pending_events(void *object)
{
- struct list_head *node, *next;
- struct gameport_event *event;
+ struct gameport_event *event, *next;
unsigned long flags;
spin_lock_irqsave(&gameport_event_lock, flags);
- list_for_each_safe(node, next, &gameport_event_list) {
- event = list_entry(node, struct gameport_event, node);
+ list_for_each_entry_safe(event, next, &gameport_event_list, node) {
if (event->object == object) {
- list_del_init(node);
+ list_del_init(&event->node);
gameport_free_event(event);
}
}
@@ -441,7 +428,6 @@ static int gameport_thread(void *nothing)
kthread_should_stop() || !list_empty(&gameport_event_list));
} while (!kthread_should_stop());
- printk(KERN_DEBUG "gameport: kgameportd exiting\n");
return 0;
}
@@ -453,6 +439,7 @@ static int gameport_thread(void *nothing)
static ssize_t gameport_show_description(struct device *dev, struct device_attribute *attr, char *buf)
{
struct gameport *gameport = to_gameport_port(dev);
+
return sprintf(buf, "%s\n", gameport->name);
}
@@ -521,7 +508,8 @@ static void gameport_init_port(struct gameport *gameport)
mutex_init(&gameport->drv_mutex);
device_initialize(&gameport->dev);
- dev_set_name(&gameport->dev, "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1);
+ dev_set_name(&gameport->dev, "gameport%lu",
+ (unsigned long)atomic_inc_return(&gameport_no) - 1);
gameport->dev.bus = &gameport_bus;
gameport->dev.release = gameport_release_port;
if (gameport->parent)
@@ -550,19 +538,17 @@ static void gameport_add_port(struct gameport *gameport)
list_add_tail(&gameport->node, &gameport_list);
if (gameport->io)
- printk(KERN_INFO "gameport: %s is %s, io %#x, speed %dkHz\n",
- gameport->name, gameport->phys, gameport->io, gameport->speed);
+ dev_info(&gameport->dev, "%s is %s, io %#x, speed %dkHz\n",
+ gameport->name, gameport->phys, gameport->io, gameport->speed);
else
- printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n",
+ dev_info(&gameport->dev, "%s is %s, speed %dkHz\n",
gameport->name, gameport->phys, gameport->speed);
error = device_add(&gameport->dev);
if (error)
- printk(KERN_ERR
- "gameport: device_add() failed for %s (%s), error: %d\n",
+ dev_err(&gameport->dev,
+ "device_add() failed for %s (%s), error: %d\n",
gameport->phys, gameport->name, error);
- else
- gameport->registered = 1;
}
/*
@@ -584,10 +570,8 @@ static void gameport_destroy_port(struct gameport *gameport)
gameport->parent = NULL;
}
- if (gameport->registered) {
+ if (device_is_registered(&gameport->dev))
device_del(&gameport->dev);
- gameport->registered = 0;
- }
list_del_init(&gameport->node);
@@ -705,8 +689,7 @@ static void gameport_attach_driver(struct gameport_driver *drv)
error = driver_attach(&drv->driver);
if (error)
- printk(KERN_ERR
- "gameport: driver_attach() failed for %s, error: %d\n",
+ pr_err("driver_attach() failed for %s, error: %d\n",
drv->driver.name, error);
}
@@ -727,8 +710,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner
error = driver_register(&drv->driver);
if (error) {
- printk(KERN_ERR
- "gameport: driver_register() failed for %s, error: %d\n",
+ pr_err("driver_register() failed for %s, error: %d\n",
drv->driver.name, error);
return error;
}
@@ -828,7 +810,7 @@ static int __init gameport_init(void)
error = bus_register(&gameport_bus);
if (error) {
- printk(KERN_ERR "gameport: failed to register gameport bus, error: %d\n", error);
+ pr_err("failed to register gameport bus, error: %d\n", error);
return error;
}
@@ -836,7 +818,7 @@ static int __init gameport_init(void)
if (IS_ERR(gameport_task)) {
bus_unregister(&gameport_bus);
error = PTR_ERR(gameport_task);
- printk(KERN_ERR "gameport: Failed to start kgameportd, error: %d\n", error);
+ pr_err("Failed to start kgameportd, error: %d\n", error);
return error;
}
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
index db556b71ddda..7c217848613e 100644
--- a/drivers/input/gameport/ns558.c
+++ b/drivers/input/gameport/ns558.c
@@ -166,7 +166,7 @@ static int ns558_isa_probe(int io)
#ifdef CONFIG_PNP
-static struct pnp_device_id pnp_devids[] = {
+static const struct pnp_device_id pnp_devids[] = {
{ .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */
{ .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */
{ .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */
diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h
index 47cd9eaee66a..4d8ea32e8a00 100644
--- a/drivers/input/input-compat.h
+++ b/drivers/input/input-compat.h
@@ -21,8 +21,6 @@
you why the ifdefs are needed? Think about it again. -AK */
#ifdef CONFIG_X86_64
# define INPUT_COMPAT_TEST is_compat_task()
-#elif defined(CONFIG_IA64)
-# define INPUT_COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current))
#elif defined(CONFIG_S390)
# define INPUT_COMPAT_TEST test_thread_flag(TIF_31BIT)
#elif defined(CONFIG_MIPS)
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index aa6713b4a988..291d9393d359 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -100,6 +100,12 @@ static void input_close_polled_device(struct input_dev *input)
struct input_polled_dev *dev = input_get_drvdata(input);
cancel_delayed_work_sync(&dev->work);
+ /*
+ * Clean up work struct to remove references to the workqueue.
+ * It may be destroyed by the next call. This causes problems
+ * at next device open-close in case of poll_interval == 0.
+ */
+ INIT_DELAYED_WORK(&dev->work, dev->work.work.func);
input_polldev_stop_workqueue();
if (dev->close)
diff --git a/drivers/input/input.c b/drivers/input/input.c
index ab060710688f..e2aad0a51826 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -24,6 +24,7 @@
#include <linux/mutex.h>
#include <linux/rcupdate.h>
#include <linux/smp_lock.h>
+#include "input-compat.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input core");
@@ -45,6 +46,7 @@ static unsigned int input_abs_bypass_init_data[] __initdata = {
ABS_MT_TOOL_TYPE,
ABS_MT_BLOB_ID,
ABS_MT_TRACKING_ID,
+ ABS_MT_PRESSURE,
0
};
static unsigned long input_abs_bypass[BITS_TO_LONGS(ABS_CNT)];
@@ -85,12 +87,14 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
}
/*
- * Pass event through all open handles. This function is called with
+ * Pass event first through all filters and then, if event has not been
+ * filtered out, through all open handles. This function is called with
* dev->event_lock held and interrupts disabled.
*/
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
+ struct input_handler *handler;
struct input_handle *handle;
rcu_read_lock();
@@ -98,11 +102,25 @@ static void input_pass_event(struct input_dev *dev,
handle = rcu_dereference(dev->grab);
if (handle)
handle->handler->event(handle, type, code, value);
- else
- list_for_each_entry_rcu(handle, &dev->h_list, d_node)
- if (handle->open)
- handle->handler->event(handle,
- type, code, value);
+ else {
+ bool filtered = false;
+
+ list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
+ if (!handle->open)
+ continue;
+
+ handler = handle->handler;
+ if (!handler->filter) {
+ if (filtered)
+ break;
+
+ handler->event(handle, type, code, value);
+
+ } else if (handler->filter(handle, type, code, value))
+ filtered = true;
+ }
+ }
+
rcu_read_unlock();
}
@@ -564,7 +582,8 @@ static int input_fetch_keycode(struct input_dev *dev, int scancode)
}
static int input_default_getkeycode(struct input_dev *dev,
- int scancode, int *keycode)
+ unsigned int scancode,
+ unsigned int *keycode)
{
if (!dev->keycodesize)
return -EINVAL;
@@ -578,7 +597,8 @@ static int input_default_getkeycode(struct input_dev *dev,
}
static int input_default_setkeycode(struct input_dev *dev,
- int scancode, int keycode)
+ unsigned int scancode,
+ unsigned int keycode)
{
int old_keycode;
int i;
@@ -613,12 +633,12 @@ static int input_default_setkeycode(struct input_dev *dev,
}
}
- clear_bit(old_keycode, dev->keybit);
- set_bit(keycode, dev->keybit);
+ __clear_bit(old_keycode, dev->keybit);
+ __set_bit(keycode, dev->keybit);
for (i = 0; i < dev->keycodemax; i++) {
if (input_fetch_keycode(dev, i) == old_keycode) {
- set_bit(old_keycode, dev->keybit);
+ __set_bit(old_keycode, dev->keybit);
break; /* Setting the bit twice is useless, so break */
}
}
@@ -636,11 +656,9 @@ static int input_default_setkeycode(struct input_dev *dev,
* This function should be called by anyone interested in retrieving current
* keymap. Presently keyboard and evdev handlers use it.
*/
-int input_get_keycode(struct input_dev *dev, int scancode, int *keycode)
+int input_get_keycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int *keycode)
{
- if (scancode < 0)
- return -EINVAL;
-
return dev->getkeycode(dev, scancode, keycode);
}
EXPORT_SYMBOL(input_get_keycode);
@@ -654,16 +672,14 @@ EXPORT_SYMBOL(input_get_keycode);
* This function should be called by anyone needing to update current
* keymap. Presently keyboard and evdev handlers use it.
*/
-int input_set_keycode(struct input_dev *dev, int scancode, int keycode)
+int input_set_keycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int keycode)
{
unsigned long flags;
int old_keycode;
int retval;
- if (scancode < 0)
- return -EINVAL;
-
- if (keycode < 0 || keycode > KEY_MAX)
+ if (keycode > KEY_MAX)
return -EINVAL;
spin_lock_irqsave(&dev->event_lock, flags);
@@ -676,6 +692,9 @@ int input_set_keycode(struct input_dev *dev, int scancode, int keycode)
if (retval)
goto out;
+ /* Make sure KEY_RESERVED did not get enabled. */
+ __clear_bit(KEY_RESERVED, dev->keybit);
+
/*
* Simulate keyup event if keycode is not present
* in the keymap anymore
@@ -703,12 +722,13 @@ EXPORT_SYMBOL(input_set_keycode);
if (i != BITS_TO_LONGS(max)) \
continue;
-static const struct input_device_id *input_match_device(const struct input_device_id *id,
+static const struct input_device_id *input_match_device(struct input_handler *handler,
struct input_dev *dev)
{
+ const struct input_device_id *id;
int i;
- for (; id->flags || id->driver_info; id++) {
+ for (id = handler->id_table; id->flags || id->driver_info; id++) {
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
if (id->bustype != dev->id.bustype)
@@ -736,7 +756,8 @@ static const struct input_device_id *input_match_device(const struct input_devic
MATCH_BIT(ffbit, FF_MAX);
MATCH_BIT(swbit, SW_MAX);
- return id;
+ if (!handler->match || handler->match(handler, dev))
+ return id;
}
return NULL;
@@ -747,10 +768,7 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
const struct input_device_id *id;
int error;
- if (handler->blacklist && input_match_device(handler->blacklist, dev))
- return -ENODEV;
-
- id = input_match_device(handler->id_table, dev);
+ id = input_match_device(handler, dev);
if (!id)
return -ENODEV;
@@ -764,6 +782,40 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
return error;
}
+#ifdef CONFIG_COMPAT
+
+static int input_bits_to_string(char *buf, int buf_size,
+ unsigned long bits, bool skip_empty)
+{
+ int len = 0;
+
+ if (INPUT_COMPAT_TEST) {
+ u32 dword = bits >> 32;
+ if (dword || !skip_empty)
+ len += snprintf(buf, buf_size, "%x ", dword);
+
+ dword = bits & 0xffffffffUL;
+ if (dword || !skip_empty || len)
+ len += snprintf(buf + len, max(buf_size - len, 0),
+ "%x", dword);
+ } else {
+ if (bits || !skip_empty)
+ len += snprintf(buf, buf_size, "%lx", bits);
+ }
+
+ return len;
+}
+
+#else /* !CONFIG_COMPAT */
+
+static int input_bits_to_string(char *buf, int buf_size,
+ unsigned long bits, bool skip_empty)
+{
+ return bits || !skip_empty ?
+ snprintf(buf, buf_size, "%lx", bits) : 0;
+}
+
+#endif
#ifdef CONFIG_PROC_FS
@@ -832,14 +884,25 @@ static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
unsigned long *bitmap, int max)
{
int i;
-
- for (i = BITS_TO_LONGS(max) - 1; i > 0; i--)
- if (bitmap[i])
- break;
+ bool skip_empty = true;
+ char buf[18];
seq_printf(seq, "B: %s=", name);
- for (; i >= 0; i--)
- seq_printf(seq, "%lx%s", bitmap[i], i > 0 ? " " : "");
+
+ for (i = BITS_TO_LONGS(max) - 1; i >= 0; i--) {
+ if (input_bits_to_string(buf, sizeof(buf),
+ bitmap[i], skip_empty)) {
+ skip_empty = false;
+ seq_printf(seq, "%s%s", buf, i > 0 ? " " : "");
+ }
+ }
+
+ /*
+ * If no output was produced print a single 0.
+ */
+ if (skip_empty)
+ seq_puts(seq, "0");
+
seq_putc(seq, '\n');
}
@@ -941,6 +1004,8 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v)
union input_seq_state *state = (union input_seq_state *)&seq->private;
seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);
+ if (handler->filter)
+ seq_puts(seq, " (filter)");
if (handler->fops)
seq_printf(seq, " Minor=%d", handler->minor);
seq_putc(seq, '\n');
@@ -1128,14 +1193,23 @@ static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
{
int i;
int len = 0;
+ bool skip_empty = true;
+
+ for (i = BITS_TO_LONGS(max) - 1; i >= 0; i--) {
+ len += input_bits_to_string(buf + len, max(buf_size - len, 0),
+ bitmap[i], skip_empty);
+ if (len) {
+ skip_empty = false;
+ if (i > 0)
+ len += snprintf(buf + len, max(buf_size - len, 0), " ");
+ }
+ }
- for (i = BITS_TO_LONGS(max) - 1; i > 0; i--)
- if (bitmap[i])
- break;
-
- for (; i >= 0; i--)
- len += snprintf(buf + len, max(buf_size - len, 0),
- "%lx%s", bitmap[i], i > 0 ? " " : "");
+ /*
+ * If no output was produced print a single 0.
+ */
+ if (len == 0)
+ len = snprintf(buf, buf_size, "%d", 0);
if (add_cr)
len += snprintf(buf + len, max(buf_size - len, 0), "\n");
@@ -1150,7 +1224,8 @@ static ssize_t input_dev_show_cap_##bm(struct device *dev, \
{ \
struct input_dev *input_dev = to_input_dev(dev); \
int len = input_print_bitmap(buf, PAGE_SIZE, \
- input_dev->bm##bit, ev##_MAX, 1); \
+ input_dev->bm##bit, ev##_MAX, \
+ true); \
return min_t(int, len, PAGE_SIZE); \
} \
static DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL)
@@ -1214,7 +1289,7 @@ static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
len = input_print_bitmap(&env->buf[env->buflen - 1],
sizeof(env->buf) - env->buflen,
- bitmap, max, 0);
+ bitmap, max, false);
if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
@@ -1494,6 +1569,25 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
}
EXPORT_SYMBOL(input_set_capability);
+#define INPUT_CLEANSE_BITMASK(dev, type, bits) \
+ do { \
+ if (!test_bit(EV_##type, dev->evbit)) \
+ memset(dev->bits##bit, 0, \
+ sizeof(dev->bits##bit)); \
+ } while (0)
+
+static void input_cleanse_bitmasks(struct input_dev *dev)
+{
+ INPUT_CLEANSE_BITMASK(dev, KEY, key);
+ INPUT_CLEANSE_BITMASK(dev, REL, rel);
+ INPUT_CLEANSE_BITMASK(dev, ABS, abs);
+ INPUT_CLEANSE_BITMASK(dev, MSC, msc);
+ INPUT_CLEANSE_BITMASK(dev, LED, led);
+ INPUT_CLEANSE_BITMASK(dev, SND, snd);
+ INPUT_CLEANSE_BITMASK(dev, FF, ff);
+ INPUT_CLEANSE_BITMASK(dev, SW, sw);
+}
+
/**
* input_register_device - register device with input core
* @dev: device to be registered
@@ -1513,13 +1607,19 @@ int input_register_device(struct input_dev *dev)
const char *path;
int error;
+ /* Every input device generates EV_SYN/SYN_REPORT events. */
__set_bit(EV_SYN, dev->evbit);
+ /* KEY_RESERVED is not supposed to be transmitted to userspace. */
+ __clear_bit(KEY_RESERVED, dev->keybit);
+
+ /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
+ input_cleanse_bitmasks(dev);
+
/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
*/
-
init_timer(&dev->timer);
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
dev->timer.data = (long) dev;
@@ -1719,7 +1819,16 @@ int input_register_handle(struct input_handle *handle)
error = mutex_lock_interruptible(&dev->mutex);
if (error)
return error;
- list_add_tail_rcu(&handle->d_node, &dev->h_list);
+
+ /*
+ * Filters go to the head of the list, normal handlers
+ * to the tail.
+ */
+ if (handler->filter)
+ list_add_rcu(&handle->d_node, &dev->h_list);
+ else
+ list_add_tail_rcu(&handle->d_node, &dev->h_list);
+
mutex_unlock(&dev->mutex);
/*
@@ -1770,35 +1879,37 @@ static int input_open_file(struct inode *inode, struct file *file)
const struct file_operations *old_fops, *new_fops = NULL;
int err;
- lock_kernel();
+ err = mutex_lock_interruptible(&input_mutex);
+ if (err)
+ return err;
+
/* No load-on-demand here? */
handler = input_table[iminor(inode) >> 5];
- if (!handler || !(new_fops = fops_get(handler->fops))) {
- err = -ENODEV;
- goto out;
- }
+ if (handler)
+ new_fops = fops_get(handler->fops);
+
+ mutex_unlock(&input_mutex);
/*
* That's _really_ odd. Usually NULL ->open means "nothing special",
* not "no device". Oh, well...
*/
- if (!new_fops->open) {
+ if (!new_fops || !new_fops->open) {
fops_put(new_fops);
err = -ENODEV;
goto out;
}
+
old_fops = file->f_op;
file->f_op = new_fops;
err = new_fops->open(inode, file);
-
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
out:
- unlock_kernel();
return err;
}
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index b1bd6dd32286..c52bec4d0530 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -286,6 +286,8 @@ static int joydev_open(struct inode *inode, struct file *file)
goto err_free_client;
file->private_data = client;
+ nonseekable_open(inode, file);
+
return 0;
err_free_client:
@@ -775,6 +777,20 @@ static void joydev_cleanup(struct joydev *joydev)
input_close_device(handle);
}
+
+static bool joydev_match(struct input_handler *handler, struct input_dev *dev)
+{
+ /* Avoid touchpads and touchscreens */
+ if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit))
+ return false;
+
+ /* Avoid tablets, digitisers and similar devices */
+ if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_DIGI, dev->keybit))
+ return false;
+
+ return true;
+}
+
static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
@@ -894,22 +910,6 @@ static void joydev_disconnect(struct input_handle *handle)
put_device(&joydev->dev);
}
-static const struct input_device_id joydev_blacklist[] = {
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
- INPUT_DEVICE_ID_MATCH_KEYBIT,
- .evbit = { BIT_MASK(EV_KEY) },
- .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
- }, /* Avoid itouchpads and touchscreens */
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
- INPUT_DEVICE_ID_MATCH_KEYBIT,
- .evbit = { BIT_MASK(EV_KEY) },
- .keybit = { [BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_DIGI) },
- }, /* Avoid tablets, digitisers and similar devices */
- { } /* Terminating entry */
-};
-
static const struct input_device_id joydev_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
@@ -936,13 +936,13 @@ MODULE_DEVICE_TABLE(input, joydev_ids);
static struct input_handler joydev_handler = {
.event = joydev_event,
+ .match = joydev_match,
.connect = joydev_connect,
.disconnect = joydev_disconnect,
.fops = &joydev_fops,
.minor = JOYDEV_MINOR_BASE,
.name = "joydev",
.id_table = joydev_ids,
- .blacklist = joydev_blacklist,
};
static int __init joydev_init(void)
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index b11419590cfe..5b596165b571 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -221,6 +221,7 @@ config JOYSTICK_DB9
config JOYSTICK_GAMECON
tristate "Multisystem, NES, SNES, N64, PSX joysticks and gamepads"
depends on PARPORT
+ select INPUT_FF_MEMLESS
---help---
Say Y here if you have a Nintendo Entertainment System gamepad,
Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 07a32aff5a31..7a55714a1486 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -30,6 +30,8 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/module.h>
@@ -61,48 +63,73 @@ MODULE_PARM_DESC(map3, "Describes third set of devices");
/* see also gs_psx_delay parameter in PSX support section */
-#define GC_SNES 1
-#define GC_NES 2
-#define GC_NES4 3
-#define GC_MULTI 4
-#define GC_MULTI2 5
-#define GC_N64 6
-#define GC_PSX 7
-#define GC_DDR 8
-#define GC_SNESMOUSE 9
-
-#define GC_MAX 9
+enum gc_type {
+ GC_NONE = 0,
+ GC_SNES,
+ GC_NES,
+ GC_NES4,
+ GC_MULTI,
+ GC_MULTI2,
+ GC_N64,
+ GC_PSX,
+ GC_DDR,
+ GC_SNESMOUSE,
+ GC_MAX
+};
#define GC_REFRESH_TIME HZ/100
+struct gc_pad {
+ struct input_dev *dev;
+ enum gc_type type;
+ char phys[32];
+};
+
struct gc {
struct pardevice *pd;
+ struct gc_pad pads[GC_MAX_DEVICES];
struct input_dev *dev[GC_MAX_DEVICES];
struct timer_list timer;
- unsigned char pads[GC_MAX + 1];
+ int pad_count[GC_MAX];
int used;
struct mutex mutex;
- char phys[GC_MAX_DEVICES][32];
+};
+
+struct gc_subdev {
+ unsigned int idx;
};
static struct gc *gc_base[3];
-static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
+static const int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
+
+static const char *gc_names[] = {
+ NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
+ "Multisystem 2-button joystick", "N64 controller", "PSX controller",
+ "PSX DDR controller", "SNES mouse"
+};
-static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
- "Multisystem 2-button joystick", "N64 controller", "PSX controller",
- "PSX DDR controller", "SNES mouse" };
/*
* N64 support.
*/
-static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
-static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START };
+static const unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
+static const short gc_n64_btn[] = {
+ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,
+ BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START
+};
#define GC_N64_LENGTH 32 /* N64 bit length, not including stop bit */
-#define GC_N64_REQUEST_LENGTH 37 /* transmit request sequence is 9 bits long */
+#define GC_N64_STOP_LENGTH 5 /* Length of encoded stop bit */
+#define GC_N64_CMD_00 0x11111111UL
+#define GC_N64_CMD_01 0xd1111111UL
+#define GC_N64_CMD_03 0xdd111111UL
+#define GC_N64_CMD_1b 0xdd1dd111UL
+#define GC_N64_CMD_c0 0x111111ddUL
+#define GC_N64_CMD_80 0x1111111dUL
+#define GC_N64_STOP_BIT 0x1d /* Encoded stop bit */
+#define GC_N64_REQUEST_DATA GC_N64_CMD_01 /* the request data command */
#define GC_N64_DELAY 133 /* delay between transmit request, and response ready (us) */
-#define GC_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */
#define GC_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */
/* GC_N64_DWS > 24 is known to fail */
#define GC_N64_POWER_W 0xe2 /* power during write (transmit request) */
@@ -114,8 +141,40 @@ static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL,
#define GC_N64_CLOCK 0x02 /* clock bits for read */
/*
+ * Used for rumble code.
+ */
+
+/* Send encoded command */
+static void gc_n64_send_command(struct gc *gc, unsigned long cmd,
+ unsigned char target)
+{
+ struct parport *port = gc->pd->port;
+ int i;
+
+ for (i = 0; i < GC_N64_LENGTH; i++) {
+ unsigned char data = (cmd >> i) & 1 ? target : 0;
+ parport_write_data(port, GC_N64_POWER_W | data);
+ udelay(GC_N64_DWS);
+ }
+}
+
+/* Send stop bit */
+static void gc_n64_send_stop_bit(struct gc *gc, unsigned char target)
+{
+ struct parport *port = gc->pd->port;
+ int i;
+
+ for (i = 0; i < GC_N64_STOP_LENGTH; i++) {
+ unsigned char data = (GC_N64_STOP_BIT >> i) & 1 ? target : 0;
+ parport_write_data(port, GC_N64_POWER_W | data);
+ udelay(GC_N64_DWS);
+ }
+}
+
+/*
* gc_n64_read_packet() reads an N64 packet.
- * Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
+ * Each pad uses one bit per byte. So all pads connected to this port
+ * are read in parallel.
*/
static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
@@ -128,14 +187,13 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
*/
local_irq_save(flags);
- for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) {
- parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0));
- udelay(GC_N64_DWS);
- }
+ gc_n64_send_command(gc, GC_N64_REQUEST_DATA, GC_N64_OUT);
+ gc_n64_send_stop_bit(gc, GC_N64_OUT);
local_irq_restore(flags);
/*
- * Wait for the pad response to be loaded into the 33-bit register of the adapter
+ * Wait for the pad response to be loaded into the 33-bit register
+ * of the adapter.
*/
udelay(GC_N64_DELAY);
@@ -146,13 +204,15 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
for (i = 0; i < GC_N64_LENGTH; i++) {
parport_write_data(gc->pd->port, GC_N64_POWER_R);
+ udelay(2);
data[i] = parport_read_status(gc->pd->port);
parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK);
}
/*
- * We must wait 200 ms here for the controller to reinitialize before the next read request.
- * No worries as long as gc_read is polled less frequently than this.
+ * We must wait 200 ms here for the controller to reinitialize before
+ * the next read request. No worries as long as gc_read is polled less
+ * frequently than this.
*/
}
@@ -160,45 +220,112 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
static void gc_n64_process_packet(struct gc *gc)
{
unsigned char data[GC_N64_LENGTH];
- signed char axes[2];
struct input_dev *dev;
int i, j, s;
+ signed char x, y;
gc_n64_read_packet(gc, data);
for (i = 0; i < GC_MAX_DEVICES; i++) {
- dev = gc->dev[i];
- if (!dev)
+ if (gc->pads[i].type != GC_N64)
continue;
+ dev = gc->pads[i].dev;
s = gc_status_bit[i];
- if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) {
+ if (s & ~(data[8] | data[9])) {
- axes[0] = axes[1] = 0;
+ x = y = 0;
for (j = 0; j < 8; j++) {
if (data[23 - j] & s)
- axes[0] |= 1 << j;
+ x |= 1 << j;
if (data[31 - j] & s)
- axes[1] |= 1 << j;
+ y |= 1 << j;
}
- input_report_abs(dev, ABS_X, axes[0]);
- input_report_abs(dev, ABS_Y, -axes[1]);
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, -y);
- input_report_abs(dev, ABS_HAT0X, !(s & data[6]) - !(s & data[7]));
- input_report_abs(dev, ABS_HAT0Y, !(s & data[4]) - !(s & data[5]));
+ input_report_abs(dev, ABS_HAT0X,
+ !(s & data[6]) - !(s & data[7]));
+ input_report_abs(dev, ABS_HAT0Y,
+ !(s & data[4]) - !(s & data[5]));
for (j = 0; j < 10; j++)
- input_report_key(dev, gc_n64_btn[j], s & data[gc_n64_bytes[j]]);
+ input_report_key(dev, gc_n64_btn[j],
+ s & data[gc_n64_bytes[j]]);
input_sync(dev);
}
}
}
+static int gc_n64_play_effect(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ int i;
+ unsigned long flags;
+ struct gc *gc = input_get_drvdata(dev);
+ struct gc_subdev *sdev = data;
+ unsigned char target = 1 << sdev->idx; /* select desired pin */
+
+ if (effect->type == FF_RUMBLE) {
+ struct ff_rumble_effect *rumble = &effect->u.rumble;
+ unsigned int cmd =
+ rumble->strong_magnitude || rumble->weak_magnitude ?
+ GC_N64_CMD_01 : GC_N64_CMD_00;
+
+ local_irq_save(flags);
+
+ /* Init Rumble - 0x03, 0x80, 0x01, (34)0x80 */
+ gc_n64_send_command(gc, GC_N64_CMD_03, target);
+ gc_n64_send_command(gc, GC_N64_CMD_80, target);
+ gc_n64_send_command(gc, GC_N64_CMD_01, target);
+ for (i = 0; i < 32; i++)
+ gc_n64_send_command(gc, GC_N64_CMD_80, target);
+ gc_n64_send_stop_bit(gc, target);
+
+ udelay(GC_N64_DELAY);
+
+ /* Now start or stop it - 0x03, 0xc0, 0zx1b, (32)0x01/0x00 */
+ gc_n64_send_command(gc, GC_N64_CMD_03, target);
+ gc_n64_send_command(gc, GC_N64_CMD_c0, target);
+ gc_n64_send_command(gc, GC_N64_CMD_1b, target);
+ for (i = 0; i < 32; i++)
+ gc_n64_send_command(gc, cmd, target);
+ gc_n64_send_stop_bit(gc, target);
+
+ local_irq_restore(flags);
+
+ }
+
+ return 0;
+}
+
+static int __init gc_n64_init_ff(struct input_dev *dev, int i)
+{
+ struct gc_subdev *sdev;
+ int err;
+
+ sdev = kmalloc(sizeof(*sdev), GFP_KERNEL);
+ if (!sdev)
+ return -ENOMEM;
+
+ sdev->idx = i;
+
+ input_set_capability(dev, EV_FF, FF_RUMBLE);
+
+ err = input_ff_create_memless(dev, sdev, gc_n64_play_effect);
+ if (err) {
+ kfree(sdev);
+ return err;
+ }
+
+ return 0;
+}
+
/*
* NES/SNES support.
*/
@@ -214,9 +341,11 @@ static void gc_n64_process_packet(struct gc *gc)
#define GC_NES_CLOCK 0x01
#define GC_NES_LATCH 0x02
-static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
-static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
-static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR };
+static const unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
+static const unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
+static const short gc_snes_btn[] = {
+ BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR
+};
/*
* gc_nes_read_packet() reads a NES/SNES packet.
@@ -244,40 +373,51 @@ static void gc_nes_read_packet(struct gc *gc, int length, unsigned char *data)
static void gc_nes_process_packet(struct gc *gc)
{
unsigned char data[GC_SNESMOUSE_LENGTH];
+ struct gc_pad *pad;
struct input_dev *dev;
int i, j, s, len;
char x_rel, y_rel;
- len = gc->pads[GC_SNESMOUSE] ? GC_SNESMOUSE_LENGTH :
- (gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH);
+ len = gc->pad_count[GC_SNESMOUSE] ? GC_SNESMOUSE_LENGTH :
+ (gc->pad_count[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH);
gc_nes_read_packet(gc, len, data);
for (i = 0; i < GC_MAX_DEVICES; i++) {
+ pad = &gc->pads[i];
dev = gc->dev[i];
- if (!dev)
- continue;
-
s = gc_status_bit[i];
- if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
+ switch (pad->type) {
+
+ case GC_NES:
+
input_report_abs(dev, ABS_X, !(s & data[6]) - !(s & data[7]));
input_report_abs(dev, ABS_Y, !(s & data[4]) - !(s & data[5]));
- }
- if (s & gc->pads[GC_NES])
for (j = 0; j < 4; j++)
- input_report_key(dev, gc_snes_btn[j], s & data[gc_nes_bytes[j]]);
+ input_report_key(dev, gc_snes_btn[j],
+ s & data[gc_nes_bytes[j]]);
+ input_sync(dev);
+ break;
+
+ case GC_SNES:
+
+ input_report_abs(dev, ABS_X, !(s & data[6]) - !(s & data[7]));
+ input_report_abs(dev, ABS_Y, !(s & data[4]) - !(s & data[5]));
- if (s & gc->pads[GC_SNES])
for (j = 0; j < 8; j++)
- input_report_key(dev, gc_snes_btn[j], s & data[gc_snes_bytes[j]]);
+ input_report_key(dev, gc_snes_btn[j],
+ s & data[gc_snes_bytes[j]]);
+ input_sync(dev);
+ break;
- if (s & gc->pads[GC_SNESMOUSE]) {
+ case GC_SNESMOUSE:
/*
- * The 4 unused bits from SNES controllers appear to be ID bits
- * so use them to make sure iwe are dealing with a mouse.
+ * The 4 unused bits from SNES controllers appear
+ * to be ID bits so use them to make sure we are
+ * dealing with a mouse.
* gamepad is connected. This is important since
* my SNES gamepad sends 1's for bits 16-31, which
* cause the mouse pointer to quickly move to the
@@ -310,9 +450,14 @@ static void gc_nes_process_packet(struct gc *gc)
y_rel = -y_rel;
input_report_rel(dev, REL_Y, y_rel);
}
+
+ input_sync(dev);
}
+ break;
+
+ default:
+ break;
}
- input_sync(dev);
}
}
@@ -340,29 +485,35 @@ static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data)
static void gc_multi_process_packet(struct gc *gc)
{
unsigned char data[GC_MULTI2_LENGTH];
+ int data_len = gc->pad_count[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH;
+ struct gc_pad *pad;
struct input_dev *dev;
int i, s;
- gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data);
+ gc_multi_read_packet(gc, data_len, data);
for (i = 0; i < GC_MAX_DEVICES; i++) {
-
- dev = gc->dev[i];
- if (!dev)
- continue;
-
+ pad = &gc->pads[i];
+ dev = pad->dev;
s = gc_status_bit[i];
- if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) {
- input_report_abs(dev, ABS_X, !(s & data[2]) - !(s & data[3]));
- input_report_abs(dev, ABS_Y, !(s & data[0]) - !(s & data[1]));
- input_report_key(dev, BTN_TRIGGER, s & data[4]);
- }
-
- if (s & gc->pads[GC_MULTI2])
+ switch (pad->type) {
+ case GC_MULTI2:
input_report_key(dev, BTN_THUMB, s & data[5]);
+ /* fall through */
- input_sync(dev);
+ case GC_MULTI:
+ input_report_abs(dev, ABS_X,
+ !(s & data[2]) - !(s & data[3]));
+ input_report_abs(dev, ABS_Y,
+ !(s & data[0]) - !(s & data[1]));
+ input_report_key(dev, BTN_TRIGGER, s & data[4]);
+ input_sync(dev);
+ break;
+
+ default:
+ break;
+ }
}
}
@@ -398,30 +549,41 @@ static int gc_psx_delay = GC_PSX_DELAY;
module_param_named(psx_delay, gc_psx_delay, uint, 0);
MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)");
-static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
-static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
- BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
-static short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 };
+static const short gc_psx_abs[] = {
+ ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y
+};
+static const short gc_psx_btn[] = {
+ BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
+ BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR
+};
+static const short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 };
/*
* gc_psx_command() writes 8bit command and reads 8bit data from
* the psx pad.
*/
-static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_MAX_DEVICES])
+static void gc_psx_command(struct gc *gc, int b, unsigned char *data)
{
+ struct parport *port = gc->pd->port;
int i, j, cmd, read;
- for (i = 0; i < GC_MAX_DEVICES; i++)
- data[i] = 0;
+ memset(data, 0, GC_MAX_DEVICES);
for (i = 0; i < GC_PSX_LENGTH; i++, b >>= 1) {
cmd = (b & 1) ? GC_PSX_COMMAND : 0;
- parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
+ parport_write_data(port, cmd | GC_PSX_POWER);
udelay(gc_psx_delay);
- read = parport_read_status(gc->pd->port) ^ 0x80;
- for (j = 0; j < GC_MAX_DEVICES; j++)
- data[j] |= (read & gc_status_bit[j] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) ? (1 << i) : 0;
+
+ read = parport_read_status(port) ^ 0x80;
+
+ for (j = 0; j < GC_MAX_DEVICES; j++) {
+ struct gc_pad *pad = &gc->pads[i];
+
+ if (pad->type == GC_PSX || pad->type == GC_DDR)
+ data[j] |= (read & gc_status_bit[j]) ? (1 << i) : 0;
+ }
+
parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
udelay(gc_psx_delay);
}
@@ -432,31 +594,40 @@ static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_MAX_DEVIC
* device identifier code.
*/
-static void gc_psx_read_packet(struct gc *gc, unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES],
+static void gc_psx_read_packet(struct gc *gc,
+ unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES],
unsigned char id[GC_MAX_DEVICES])
{
int i, j, max_len = 0;
unsigned long flags;
unsigned char data2[GC_MAX_DEVICES];
- parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */
+ /* Select pad */
+ parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
udelay(gc_psx_delay);
- parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */
+ /* Deselect, begin command */
+ parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER);
udelay(gc_psx_delay);
local_irq_save(flags);
- gc_psx_command(gc, 0x01, data2); /* Access pad */
- gc_psx_command(gc, 0x42, id); /* Get device ids */
- gc_psx_command(gc, 0, data2); /* Dump status */
+ gc_psx_command(gc, 0x01, data2); /* Access pad */
+ gc_psx_command(gc, 0x42, id); /* Get device ids */
+ gc_psx_command(gc, 0, data2); /* Dump status */
+
+ /* Find the longest pad */
+ for (i = 0; i < GC_MAX_DEVICES; i++) {
+ struct gc_pad *pad = &gc->pads[i];
- for (i =0; i < GC_MAX_DEVICES; i++) /* Find the longest pad */
- if((gc_status_bit[i] & (gc->pads[GC_PSX] | gc->pads[GC_DDR]))
- && (GC_PSX_LEN(id[i]) > max_len)
- && (GC_PSX_LEN(id[i]) <= GC_PSX_BYTES))
+ if ((pad->type == GC_PSX || pad->type == GC_DDR) &&
+ GC_PSX_LEN(id[i]) > max_len &&
+ GC_PSX_LEN(id[i]) <= GC_PSX_BYTES) {
max_len = GC_PSX_LEN(id[i]);
+ }
+ }
- for (i = 0; i < max_len; i++) { /* Read in all the data */
+ /* Read in all the data */
+ for (i = 0; i < max_len; i++) {
gc_psx_command(gc, 0, data2);
for (j = 0; j < GC_MAX_DEVICES; j++)
data[j][i] = data2[j];
@@ -466,86 +637,104 @@ static void gc_psx_read_packet(struct gc *gc, unsigned char data[GC_MAX_DEVICES]
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
- for(i = 0; i < GC_MAX_DEVICES; i++) /* Set id's to the real value */
+ /* Set id's to the real value */
+ for (i = 0; i < GC_MAX_DEVICES; i++)
id[i] = GC_PSX_ID(id[i]);
}
-static void gc_psx_process_packet(struct gc *gc)
+static void gc_psx_report_one(struct gc_pad *pad, unsigned char psx_type,
+ unsigned char *data)
{
- unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES];
- unsigned char id[GC_MAX_DEVICES];
- struct input_dev *dev;
- int i, j;
+ struct input_dev *dev = pad->dev;
+ int i;
- gc_psx_read_packet(gc, data, id);
+ switch (psx_type) {
- for (i = 0; i < GC_MAX_DEVICES; i++) {
+ case GC_PSX_RUMBLE:
- dev = gc->dev[i];
- if (!dev)
- continue;
+ input_report_key(dev, BTN_THUMBL, ~data[0] & 0x04);
+ input_report_key(dev, BTN_THUMBR, ~data[0] & 0x02);
- switch (id[i]) {
+ case GC_PSX_NEGCON:
+ case GC_PSX_ANALOG:
- case GC_PSX_RUMBLE:
+ if (pad->type == GC_DDR) {
+ for (i = 0; i < 4; i++)
+ input_report_key(dev, gc_psx_ddr_btn[i],
+ ~data[0] & (0x10 << i));
+ } else {
+ for (i = 0; i < 4; i++)
+ input_report_abs(dev, gc_psx_abs[i + 2],
+ data[i + 2]);
- input_report_key(dev, BTN_THUMBL, ~data[i][0] & 0x04);
- input_report_key(dev, BTN_THUMBR, ~data[i][0] & 0x02);
+ input_report_abs(dev, ABS_X,
+ !!(data[0] & 0x80) * 128 + !(data[0] & 0x20) * 127);
+ input_report_abs(dev, ABS_Y,
+ !!(data[0] & 0x10) * 128 + !(data[0] & 0x40) * 127);
+ }
- case GC_PSX_NEGCON:
- case GC_PSX_ANALOG:
+ for (i = 0; i < 8; i++)
+ input_report_key(dev, gc_psx_btn[i], ~data[1] & (1 << i));
- if (gc->pads[GC_DDR] & gc_status_bit[i]) {
- for(j = 0; j < 4; j++)
- input_report_key(dev, gc_psx_ddr_btn[j], ~data[i][0] & (0x10 << j));
- } else {
- for (j = 0; j < 4; j++)
- input_report_abs(dev, gc_psx_abs[j + 2], data[i][j + 2]);
+ input_report_key(dev, BTN_START, ~data[0] & 0x08);
+ input_report_key(dev, BTN_SELECT, ~data[0] & 0x01);
- input_report_abs(dev, ABS_X, 128 + !(data[i][0] & 0x20) * 127 - !(data[i][0] & 0x80) * 128);
- input_report_abs(dev, ABS_Y, 128 + !(data[i][0] & 0x40) * 127 - !(data[i][0] & 0x10) * 128);
- }
+ input_sync(dev);
- for (j = 0; j < 8; j++)
- input_report_key(dev, gc_psx_btn[j], ~data[i][1] & (1 << j));
+ break;
- input_report_key(dev, BTN_START, ~data[i][0] & 0x08);
- input_report_key(dev, BTN_SELECT, ~data[i][0] & 0x01);
+ case GC_PSX_NORMAL:
- input_sync(dev);
+ if (pad->type == GC_DDR) {
+ for (i = 0; i < 4; i++)
+ input_report_key(dev, gc_psx_ddr_btn[i],
+ ~data[0] & (0x10 << i));
+ } else {
+ input_report_abs(dev, ABS_X,
+ !!(data[0] & 0x80) * 128 + !(data[0] & 0x20) * 127);
+ input_report_abs(dev, ABS_Y,
+ !!(data[0] & 0x10) * 128 + !(data[0] & 0x40) * 127);
- break;
-
- case GC_PSX_NORMAL:
- if (gc->pads[GC_DDR] & gc_status_bit[i]) {
- for(j = 0; j < 4; j++)
- input_report_key(dev, gc_psx_ddr_btn[j], ~data[i][0] & (0x10 << j));
- } else {
- input_report_abs(dev, ABS_X, 128 + !(data[i][0] & 0x20) * 127 - !(data[i][0] & 0x80) * 128);
- input_report_abs(dev, ABS_Y, 128 + !(data[i][0] & 0x40) * 127 - !(data[i][0] & 0x10) * 128);
-
- /* for some reason if the extra axes are left unset they drift */
- /* for (j = 0; j < 4; j++)
- input_report_abs(dev, gc_psx_abs[j + 2], 128);
- * This needs to be debugged properly,
- * maybe fuzz processing needs to be done in input_sync()
- * --vojtech
- */
- }
+ /*
+ * For some reason if the extra axes are left unset
+ * they drift.
+ * for (i = 0; i < 4; i++)
+ input_report_abs(dev, gc_psx_abs[i + 2], 128);
+ * This needs to be debugged properly,
+ * maybe fuzz processing needs to be done
+ * in input_sync()
+ * --vojtech
+ */
+ }
- for (j = 0; j < 8; j++)
- input_report_key(dev, gc_psx_btn[j], ~data[i][1] & (1 << j));
+ for (i = 0; i < 8; i++)
+ input_report_key(dev, gc_psx_btn[i], ~data[1] & (1 << i));
- input_report_key(dev, BTN_START, ~data[i][0] & 0x08);
- input_report_key(dev, BTN_SELECT, ~data[i][0] & 0x01);
+ input_report_key(dev, BTN_START, ~data[0] & 0x08);
+ input_report_key(dev, BTN_SELECT, ~data[0] & 0x01);
- input_sync(dev);
+ input_sync(dev);
- break;
+ break;
- case 0: /* not a pad, ignore */
- break;
- }
+ default: /* not a pad, ignore */
+ break;
+ }
+}
+
+static void gc_psx_process_packet(struct gc *gc)
+{
+ unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES];
+ unsigned char id[GC_MAX_DEVICES];
+ struct gc_pad *pad;
+ int i;
+
+ gc_psx_read_packet(gc, data, id);
+
+ for (i = 0; i < GC_MAX_DEVICES; i++) {
+ pad = &gc->pads[i];
+ if (pad->type == GC_PSX || pad->type == GC_DDR)
+ gc_psx_report_one(pad, id[i], data[i]);
}
}
@@ -561,28 +750,31 @@ static void gc_timer(unsigned long private)
* N64 pads - must be read first, any read confuses them for 200 us
*/
- if (gc->pads[GC_N64])
+ if (gc->pad_count[GC_N64])
gc_n64_process_packet(gc);
/*
* NES and SNES pads or mouse
*/
- if (gc->pads[GC_NES] || gc->pads[GC_SNES] || gc->pads[GC_SNESMOUSE])
+ if (gc->pad_count[GC_NES] ||
+ gc->pad_count[GC_SNES] ||
+ gc->pad_count[GC_SNESMOUSE]) {
gc_nes_process_packet(gc);
+ }
/*
* Multi and Multi2 joysticks
*/
- if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2])
+ if (gc->pad_count[GC_MULTI] || gc->pad_count[GC_MULTI2])
gc_multi_process_packet(gc);
/*
* PSX controllers
*/
- if (gc->pads[GC_PSX] || gc->pads[GC_DDR])
+ if (gc->pad_count[GC_PSX] || gc->pad_count[GC_DDR])
gc_psx_process_packet(gc);
mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
@@ -622,25 +814,29 @@ static void gc_close(struct input_dev *dev)
static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
{
+ struct gc_pad *pad = &gc->pads[idx];
struct input_dev *input_dev;
int i;
+ int err;
- if (!pad_type)
- return 0;
-
- if (pad_type < 1 || pad_type > GC_MAX) {
- printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", pad_type);
+ if (pad_type < 1 || pad_type >= GC_MAX) {
+ pr_err("Pad type %d unknown\n", pad_type);
return -EINVAL;
}
- gc->dev[idx] = input_dev = input_allocate_device();
+ pad->dev = input_dev = input_allocate_device();
if (!input_dev) {
- printk(KERN_ERR "gamecon.c: Not enough memory for input device\n");
+ pr_err("Not enough memory for input device\n");
return -ENOMEM;
}
+ pad->type = pad_type;
+
+ snprintf(pad->phys, sizeof(pad->phys),
+ "%s/input%d", gc->pd->port->name, idx);
+
input_dev->name = gc_names[pad_type];
- input_dev->phys = gc->phys[idx];
+ input_dev->phys = pad->phys;
input_dev->id.bustype = BUS_PARPORT;
input_dev->id.vendor = 0x0001;
input_dev->id.product = pad_type;
@@ -659,61 +855,76 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
} else
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
- gc->pads[0] |= gc_status_bit[idx];
- gc->pads[pad_type] |= gc_status_bit[idx];
+ gc->pad_count[pad_type]++;
switch (pad_type) {
- case GC_N64:
- for (i = 0; i < 10; i++)
- set_bit(gc_n64_btn[i], input_dev->keybit);
-
- for (i = 0; i < 2; i++) {
- input_set_abs_params(input_dev, ABS_X + i, -127, 126, 0, 2);
- input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0);
- }
-
- break;
-
- case GC_SNESMOUSE:
- set_bit(BTN_LEFT, input_dev->keybit);
- set_bit(BTN_RIGHT, input_dev->keybit);
- set_bit(REL_X, input_dev->relbit);
- set_bit(REL_Y, input_dev->relbit);
- break;
-
- case GC_SNES:
- for (i = 4; i < 8; i++)
- set_bit(gc_snes_btn[i], input_dev->keybit);
- case GC_NES:
- for (i = 0; i < 4; i++)
- set_bit(gc_snes_btn[i], input_dev->keybit);
- break;
-
- case GC_MULTI2:
- set_bit(BTN_THUMB, input_dev->keybit);
- case GC_MULTI:
- set_bit(BTN_TRIGGER, input_dev->keybit);
- break;
-
- case GC_PSX:
- for (i = 0; i < 6; i++)
- input_set_abs_params(input_dev, gc_psx_abs[i], 4, 252, 0, 2);
- for (i = 0; i < 12; i++)
- set_bit(gc_psx_btn[i], input_dev->keybit);
+ case GC_N64:
+ for (i = 0; i < 10; i++)
+ __set_bit(gc_n64_btn[i], input_dev->keybit);
- break;
+ for (i = 0; i < 2; i++) {
+ input_set_abs_params(input_dev, ABS_X + i, -127, 126, 0, 2);
+ input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0);
+ }
- case GC_DDR:
- for (i = 0; i < 4; i++)
- set_bit(gc_psx_ddr_btn[i], input_dev->keybit);
- for (i = 0; i < 12; i++)
- set_bit(gc_psx_btn[i], input_dev->keybit);
+ err = gc_n64_init_ff(input_dev, idx);
+ if (err) {
+ pr_warning("Failed to initiate rumble for N64 device %d\n", idx);
+ goto err_free_dev;
+ }
- break;
+ break;
+
+ case GC_SNESMOUSE:
+ __set_bit(BTN_LEFT, input_dev->keybit);
+ __set_bit(BTN_RIGHT, input_dev->keybit);
+ __set_bit(REL_X, input_dev->relbit);
+ __set_bit(REL_Y, input_dev->relbit);
+ break;
+
+ case GC_SNES:
+ for (i = 4; i < 8; i++)
+ __set_bit(gc_snes_btn[i], input_dev->keybit);
+ case GC_NES:
+ for (i = 0; i < 4; i++)
+ __set_bit(gc_snes_btn[i], input_dev->keybit);
+ break;
+
+ case GC_MULTI2:
+ __set_bit(BTN_THUMB, input_dev->keybit);
+ case GC_MULTI:
+ __set_bit(BTN_TRIGGER, input_dev->keybit);
+ break;
+
+ case GC_PSX:
+ for (i = 0; i < 6; i++)
+ input_set_abs_params(input_dev,
+ gc_psx_abs[i], 4, 252, 0, 2);
+ for (i = 0; i < 12; i++)
+ __set_bit(gc_psx_btn[i], input_dev->keybit);
+
+ break;
+
+ case GC_DDR:
+ for (i = 0; i < 4; i++)
+ __set_bit(gc_psx_ddr_btn[i], input_dev->keybit);
+ for (i = 0; i < 12; i++)
+ __set_bit(gc_psx_btn[i], input_dev->keybit);
+
+ break;
}
+ err = input_register_device(pad->dev);
+ if (err)
+ goto err_free_dev;
+
return 0;
+
+err_free_dev:
+ input_free_device(pad->dev);
+ pad->dev = NULL;
+ return err;
}
static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
@@ -722,52 +933,47 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
struct parport *pp;
struct pardevice *pd;
int i;
+ int count = 0;
int err;
pp = parport_find_number(parport);
if (!pp) {
- printk(KERN_ERR "gamecon.c: no such parport\n");
+ pr_err("no such parport %d\n", parport);
err = -EINVAL;
goto err_out;
}
pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
if (!pd) {
- printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n");
+ pr_err("parport busy already - lp.o loaded?\n");
err = -EBUSY;
goto err_put_pp;
}
gc = kzalloc(sizeof(struct gc), GFP_KERNEL);
if (!gc) {
- printk(KERN_ERR "gamecon.c: Not enough memory\n");
+ pr_err("Not enough memory\n");
err = -ENOMEM;
goto err_unreg_pardev;
}
mutex_init(&gc->mutex);
gc->pd = pd;
- init_timer(&gc->timer);
- gc->timer.data = (long) gc;
- gc->timer.function = gc_timer;
+ setup_timer(&gc->timer, gc_timer, (long) gc);
for (i = 0; i < n_pads && i < GC_MAX_DEVICES; i++) {
if (!pads[i])
continue;
- snprintf(gc->phys[i], sizeof(gc->phys[i]),
- "%s/input%d", gc->pd->port->name, i);
err = gc_setup_pad(gc, i, pads[i]);
if (err)
goto err_unreg_devs;
- err = input_register_device(gc->dev[i]);
- if (err)
- goto err_free_dev;
+ count++;
}
- if (!gc->pads[0]) {
- printk(KERN_ERR "gamecon.c: No valid devices specified\n");
+ if (count == 0) {
+ pr_err("No valid devices specified\n");
err = -EINVAL;
goto err_free_gc;
}
@@ -775,12 +981,10 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
parport_put_port(pp);
return gc;
- err_free_dev:
- input_free_device(gc->dev[i]);
err_unreg_devs:
while (--i >= 0)
- if (gc->dev[i])
- input_unregister_device(gc->dev[i]);
+ if (gc->pads[i].dev)
+ input_unregister_device(gc->pads[i].dev);
err_free_gc:
kfree(gc);
err_unreg_pardev:
@@ -796,8 +1000,8 @@ static void gc_remove(struct gc *gc)
int i;
for (i = 0; i < GC_MAX_DEVICES; i++)
- if (gc->dev[i])
- input_unregister_device(gc->dev[i]);
+ if (gc->pads[i].dev)
+ input_unregister_device(gc->pads[i].dev);
parport_unregister_device(gc->pd);
kfree(gc);
}
@@ -813,7 +1017,7 @@ static int __init gc_init(void)
continue;
if (gc_cfg[i].nargs < 2) {
- printk(KERN_ERR "gamecon.c: at least one device must be specified\n");
+ pr_err("at least one device must be specified\n");
err = -EINVAL;
break;
}
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index 67c207f5b1a1..45ac70eae0aa 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -277,7 +277,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
}
#ifdef RESET_WORKS
- if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) ||
+ if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) &&
(gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5)))) {
err = -ENODEV;
goto fail2;
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 482cb1204e43..9b3353b404da 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -86,9 +86,8 @@
/* xbox d-pads should map to buttons, as is required for DDR pads
but we map them to axes when possible to simplify things */
-#define MAP_DPAD_TO_BUTTONS 0
-#define MAP_DPAD_TO_AXES 1
-#define MAP_DPAD_UNKNOWN 2
+#define MAP_DPAD_TO_BUTTONS (1 << 0)
+#define MAP_TRIGGERS_TO_BUTTONS (1 << 1)
#define XTYPE_XBOX 0
#define XTYPE_XBOX360 1
@@ -99,57 +98,61 @@ static int dpad_to_buttons;
module_param(dpad_to_buttons, bool, S_IRUGO);
MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
+static int triggers_to_buttons;
+module_param(triggers_to_buttons, bool, S_IRUGO);
+MODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads");
+
static const struct xpad_device {
u16 idVendor;
u16 idProduct;
char *name;
- u8 dpad_mapping;
+ u8 mapping;
u8 xtype;
} xpad_device[] = {
- { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+ { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX },
+ { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
+ { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
+ { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
- { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x046d, 0xc242, "Logitech Chillstream Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
- { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+ { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
+ { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
+ { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
+ { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX },
+ { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX },
+ { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX },
+ { 0x0738, 0x4516, "Mad Catz Control Pad", 0, XTYPE_XBOX },
+ { 0x0738, 0x4522, "Mad Catz LumiCON", 0, XTYPE_XBOX },
+ { 0x0738, 0x4526, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX },
+ { 0x0738, 0x4536, "Mad Catz MicroCON", 0, XTYPE_XBOX },
{ 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
- { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
- { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
+ { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX },
+ { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
+ { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
- { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
- { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+ { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
+ { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX },
+ { 0x0c12, 0x8810, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
+ { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX },
+ { 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX },
+ { 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX },
+ { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX },
+ { 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX },
+ { 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX },
+ { 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
+ { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX },
+ { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX },
+ { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
+ { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
- { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
+ { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },
{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
- { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
- { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
+ { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
+ { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
- { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
- { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN }
+ { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+ { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
+ { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
};
/* buttons shared with xbox and xbox360 */
@@ -165,13 +168,20 @@ static const signed short xpad_btn[] = {
-1 /* terminating entry */
};
-/* only used if MAP_DPAD_TO_BUTTONS */
+/* used when dpad is mapped to nuttons */
static const signed short xpad_btn_pad[] = {
BTN_LEFT, BTN_RIGHT, /* d-pad left, right */
BTN_0, BTN_1, /* d-pad up, down (XXX names??) */
-1 /* terminating entry */
};
+/* used when triggers are mapped to buttons */
+static const signed short xpad_btn_triggers[] = {
+ BTN_TL2, BTN_TR2, /* triggers left/right */
+ -1
+};
+
+
static const signed short xpad360_btn[] = { /* buttons for x360 controller */
BTN_TL, BTN_TR, /* Button LB/RB */
BTN_MODE, /* The big X button */
@@ -181,16 +191,21 @@ static const signed short xpad360_btn[] = { /* buttons for x360 controller */
static const signed short xpad_abs[] = {
ABS_X, ABS_Y, /* left stick */
ABS_RX, ABS_RY, /* right stick */
- ABS_Z, ABS_RZ, /* triggers left/right */
-1 /* terminating entry */
};
-/* only used if MAP_DPAD_TO_AXES */
+/* used when dpad is mapped to axes */
static const signed short xpad_abs_pad[] = {
ABS_HAT0X, ABS_HAT0Y, /* d-pad axes */
-1 /* terminating entry */
};
+/* used when triggers are mapped to axes */
+static const signed short xpad_abs_triggers[] = {
+ ABS_Z, ABS_RZ, /* triggers left/right */
+ -1
+};
+
/* Xbox 360 has a vendor-specific class, so we cannot match it with only
* USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
* match against vendor id as well. Wired Xbox 360 devices have protocol 1,
@@ -246,7 +261,7 @@ struct usb_xpad {
char phys[64]; /* physical device path */
- int dpad_mapping; /* map d-pad to buttons or to axes */
+ int mapping; /* map d-pad to buttons or to axes */
int xtype; /* type of xbox device */
};
@@ -277,20 +292,25 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
~(__s16) le16_to_cpup((__le16 *)(data + 18)));
/* triggers left/right */
- input_report_abs(dev, ABS_Z, data[10]);
- input_report_abs(dev, ABS_RZ, data[11]);
+ if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+ input_report_key(dev, BTN_TL2, data[10]);
+ input_report_key(dev, BTN_TR2, data[11]);
+ } else {
+ input_report_abs(dev, ABS_Z, data[10]);
+ input_report_abs(dev, ABS_RZ, data[11]);
+ }
/* digital pad */
- if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
- input_report_abs(dev, ABS_HAT0X,
- !!(data[2] & 0x08) - !!(data[2] & 0x04));
- input_report_abs(dev, ABS_HAT0Y,
- !!(data[2] & 0x02) - !!(data[2] & 0x01));
- } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {
+ if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
input_report_key(dev, BTN_0, data[2] & 0x01); /* up */
input_report_key(dev, BTN_1, data[2] & 0x02); /* down */
+ } else {
+ input_report_abs(dev, ABS_HAT0X,
+ !!(data[2] & 0x08) - !!(data[2] & 0x04));
+ input_report_abs(dev, ABS_HAT0Y,
+ !!(data[2] & 0x02) - !!(data[2] & 0x01));
}
/* start/back buttons and stick press left/right */
@@ -328,17 +348,17 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
struct input_dev *dev = xpad->dev;
/* digital pad */
- if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
- input_report_abs(dev, ABS_HAT0X,
- !!(data[2] & 0x08) - !!(data[2] & 0x04));
- input_report_abs(dev, ABS_HAT0Y,
- !!(data[2] & 0x02) - !!(data[2] & 0x01));
- } else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) {
+ if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
/* dpad as buttons (right, left, down, up) */
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
input_report_key(dev, BTN_0, data[2] & 0x01); /* up */
input_report_key(dev, BTN_1, data[2] & 0x02); /* down */
+ } else {
+ input_report_abs(dev, ABS_HAT0X,
+ !!(data[2] & 0x08) - !!(data[2] & 0x04));
+ input_report_abs(dev, ABS_HAT0Y,
+ !!(data[2] & 0x02) - !!(data[2] & 0x01));
}
/* start/back buttons */
@@ -371,8 +391,13 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
~(__s16) le16_to_cpup((__le16 *)(data + 12)));
/* triggers left/right */
- input_report_abs(dev, ABS_Z, data[4]);
- input_report_abs(dev, ABS_RZ, data[5]);
+ if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+ input_report_key(dev, BTN_TL2, data[4]);
+ input_report_key(dev, BTN_TR2, data[5]);
+ } else {
+ input_report_abs(dev, ABS_Z, data[4]);
+ input_report_abs(dev, ABS_RZ, data[5]);
+ }
input_sync(dev);
}
@@ -446,7 +471,7 @@ static void xpad_irq_in(struct urb *urb)
}
exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
__func__, retval);
@@ -505,7 +530,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
struct usb_endpoint_descriptor *ep_irq_out;
int error = -ENOMEM;
- if (xpad->xtype != XTYPE_XBOX360)
+ if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
return 0;
xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN,
@@ -535,13 +560,13 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
static void xpad_stop_output(struct usb_xpad *xpad)
{
- if (xpad->xtype == XTYPE_XBOX360)
+ if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX)
usb_kill_urb(xpad->irq_out);
}
static void xpad_deinit_output(struct usb_xpad *xpad)
{
- if (xpad->xtype == XTYPE_XBOX360) {
+ if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX) {
usb_free_urb(xpad->irq_out);
usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
xpad->odata, xpad->odata_dma);
@@ -554,24 +579,45 @@ static void xpad_stop_output(struct usb_xpad *xpad) {}
#endif
#ifdef CONFIG_JOYSTICK_XPAD_FF
-static int xpad_play_effect(struct input_dev *dev, void *data,
- struct ff_effect *effect)
+static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
{
struct usb_xpad *xpad = input_get_drvdata(dev);
if (effect->type == FF_RUMBLE) {
__u16 strong = effect->u.rumble.strong_magnitude;
__u16 weak = effect->u.rumble.weak_magnitude;
- xpad->odata[0] = 0x00;
- xpad->odata[1] = 0x08;
- xpad->odata[2] = 0x00;
- xpad->odata[3] = strong / 256;
- xpad->odata[4] = weak / 256;
- xpad->odata[5] = 0x00;
- xpad->odata[6] = 0x00;
- xpad->odata[7] = 0x00;
- xpad->irq_out->transfer_buffer_length = 8;
- usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+
+ switch (xpad->xtype) {
+
+ case XTYPE_XBOX:
+ xpad->odata[0] = 0x00;
+ xpad->odata[1] = 0x06;
+ xpad->odata[2] = 0x00;
+ xpad->odata[3] = strong / 256; /* left actuator */
+ xpad->odata[4] = 0x00;
+ xpad->odata[5] = weak / 256; /* right actuator */
+ xpad->irq_out->transfer_buffer_length = 6;
+
+ return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+
+ case XTYPE_XBOX360:
+ xpad->odata[0] = 0x00;
+ xpad->odata[1] = 0x08;
+ xpad->odata[2] = 0x00;
+ xpad->odata[3] = strong / 256; /* left actuator? */
+ xpad->odata[4] = weak / 256; /* right actuator? */
+ xpad->odata[5] = 0x00;
+ xpad->odata[6] = 0x00;
+ xpad->odata[7] = 0x00;
+ xpad->irq_out->transfer_buffer_length = 8;
+
+ return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+
+ default:
+ dbg("%s - rumble command sent to unsupported xpad type: %d",
+ __func__, xpad->xtype);
+ return -1;
+ }
}
return 0;
@@ -579,7 +625,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data,
static int xpad_init_ff(struct usb_xpad *xpad)
{
- if (xpad->xtype != XTYPE_XBOX360)
+ if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
return 0;
input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
@@ -712,11 +758,11 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128);
break;
case ABS_Z:
- case ABS_RZ: /* the triggers */
+ case ABS_RZ: /* the triggers (if mapped to axes) */
input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
break;
case ABS_HAT0X:
- case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */
+ case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */
input_set_abs_params(input_dev, abs, -1, 1, 0, 0);
break;
}
@@ -752,10 +798,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
goto fail2;
xpad->udev = udev;
- xpad->dpad_mapping = xpad_device[i].dpad_mapping;
+ xpad->mapping = xpad_device[i].mapping;
xpad->xtype = xpad_device[i].xtype;
- if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN)
- xpad->dpad_mapping = !dpad_to_buttons;
+
if (xpad->xtype == XTYPE_UNKNOWN) {
if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
if (intf->cur_altsetting->desc.bInterfaceProtocol == 129)
@@ -764,7 +809,13 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad->xtype = XTYPE_XBOX360;
} else
xpad->xtype = XTYPE_XBOX;
+
+ if (dpad_to_buttons)
+ xpad->mapping |= MAP_DPAD_TO_BUTTONS;
+ if (triggers_to_buttons)
+ xpad->mapping |= MAP_TRIGGERS_TO_BUTTONS;
}
+
xpad->dev = input_dev;
usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
@@ -781,25 +832,37 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- /* set up buttons */
+ /* set up standard buttons and axes */
for (i = 0; xpad_common_btn[i] >= 0; i++)
- set_bit(xpad_common_btn[i], input_dev->keybit);
- if ((xpad->xtype == XTYPE_XBOX360) || (xpad->xtype == XTYPE_XBOX360W))
- for (i = 0; xpad360_btn[i] >= 0; i++)
- set_bit(xpad360_btn[i], input_dev->keybit);
- else
- for (i = 0; xpad_btn[i] >= 0; i++)
- set_bit(xpad_btn[i], input_dev->keybit);
- if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS)
- for (i = 0; xpad_btn_pad[i] >= 0; i++)
- set_bit(xpad_btn_pad[i], input_dev->keybit);
+ __set_bit(xpad_common_btn[i], input_dev->keybit);
- /* set up axes */
for (i = 0; xpad_abs[i] >= 0; i++)
xpad_set_up_abs(input_dev, xpad_abs[i]);
- if (xpad->dpad_mapping == MAP_DPAD_TO_AXES)
+
+ /* Now set up model-specific ones */
+ if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) {
+ for (i = 0; xpad360_btn[i] >= 0; i++)
+ __set_bit(xpad360_btn[i], input_dev->keybit);
+ } else {
+ for (i = 0; xpad_btn[i] >= 0; i++)
+ __set_bit(xpad_btn[i], input_dev->keybit);
+ }
+
+ if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
+ for (i = 0; xpad_btn_pad[i] >= 0; i++)
+ __set_bit(xpad_btn_pad[i], input_dev->keybit);
+ } else {
for (i = 0; xpad_abs_pad[i] >= 0; i++)
xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
+ }
+
+ if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+ for (i = 0; xpad_btn_triggers[i] >= 0; i++)
+ __set_bit(xpad_btn_triggers[i], input_dev->keybit);
+ } else {
+ for (i = 0; xpad_abs_triggers[i] >= 0; i++)
+ xpad_set_up_abs(input_dev, xpad_abs_triggers[i]);
+ }
error = xpad_init_output(intf, xpad);
if (error)
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 02c836e11813..64c102355f53 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -35,10 +35,10 @@ config KEYBOARD_ADP5520
be called adp5520-keys.
config KEYBOARD_ADP5588
- tristate "ADP5588 I2C QWERTY Keypad and IO Expander"
+ tristate "ADP5588/87 I2C QWERTY Keypad and IO Expander"
depends on I2C
help
- Say Y here if you want to use a ADP5588 attached to your
+ Say Y here if you want to use a ADP5588/87 attached to your
system I2C bus.
To compile this driver as a module, choose M here: the
@@ -144,13 +144,15 @@ config KEYBOARD_BFIN
module will be called bf54x-keys.
config KEYBOARD_CORGI
- tristate "Corgi keyboard"
+ tristate "Corgi keyboard (deprecated)"
depends on PXA_SHARPSL
- default y
help
Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx
series of PDAs.
+ This driver is now deprecated, use generic GPIO based matrix
+ keyboard driver instead.
+
To compile this driver as a module, choose M here: the
module will be called corgikbd.
@@ -292,6 +294,15 @@ config KEYBOARD_MAX7359
To compile this driver as a module, choose M here: the
module will be called max7359_keypad.
+config KEYBOARD_IMX
+ tristate "IMX keypad support"
+ depends on ARCH_MXC
+ help
+ Enable support for IMX keypad port.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx_keypad.
+
config KEYBOARD_NEWTON
tristate "Newton keyboard"
select SERIO
@@ -329,13 +340,15 @@ config KEYBOARD_PXA930_ROTARY
module will be called pxa930_rotary.
config KEYBOARD_SPITZ
- tristate "Spitz keyboard"
+ tristate "Spitz keyboard (deprecated)"
depends on PXA_SHARPSL
- default y
help
Say Y here to enable the keyboard on the Sharp Zaurus SL-C1000,
SL-C3000 and Sl-C3100 series of PDAs.
+ This driver is now deprecated, use generic GPIO based matrix
+ keyboard driver instead.
+
To compile this driver as a module, choose M here: the
module will be called spitzkbd.
@@ -363,7 +376,7 @@ config KEYBOARD_SUNKBD
config KEYBOARD_SH_KEYSC
tristate "SuperH KEYSC keypad support"
- depends on SUPERH
+ depends on SUPERH || ARCH_SHMOBILE
help
Say Y here if you want to use a keypad attached to the KEYSC block
on SuperH processors such as sh7722 and sh7343.
@@ -402,12 +415,14 @@ config KEYBOARD_TWL4030
module will be called twl4030_keypad.
config KEYBOARD_TOSA
- tristate "Tosa keyboard"
+ tristate "Tosa keyboard (deprecated)"
depends on MACH_TOSA
- default y
help
Say Y here to enable the keyboard on the Sharp Zaurus SL-6000x (Tosa)
+ This driver is now deprecated, use generic GPIO based matrix
+ keyboard driver instead.
+
To compile this driver as a module, choose M here: the
module will be called tosakbd.
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 78654ef65206..706c6b5ed5f4 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
+obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 1edb596d927b..b5142d2d5112 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -1,6 +1,7 @@
/*
* File: drivers/input/keyboard/adp5588_keys.c
- * Description: keypad driver for ADP5588 I2C QWERTY Keypad and IO Expander
+ * Description: keypad driver for ADP5588 and ADP5587
+ * I2C QWERTY Keypad and IO Expander
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2008-2009 Analog Devices Inc.
@@ -327,6 +328,7 @@ static const struct dev_pm_ops adp5588_dev_pm_ops = {
static const struct i2c_device_id adp5588_id[] = {
{ KBUILD_MODNAME, 0 },
+ { "adp5587-keys", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adp5588_id);
@@ -357,5 +359,5 @@ module_exit(adp5588_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("ADP5588 Keypad driver");
+MODULE_DESCRIPTION("ADP5588/87 Keypad driver");
MODULE_ALIAS("platform:adp5588-keys");
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 1f5e2ce327d6..d358ef8623f4 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -40,26 +40,26 @@ module_param_named(set, atkbd_set, int, 0);
MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)");
#if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
-static int atkbd_reset;
+static bool atkbd_reset;
#else
-static int atkbd_reset = 1;
+static bool atkbd_reset = true;
#endif
module_param_named(reset, atkbd_reset, bool, 0);
MODULE_PARM_DESC(reset, "Reset keyboard during initialization");
-static int atkbd_softrepeat;
+static bool atkbd_softrepeat;
module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
-static int atkbd_softraw = 1;
+static bool atkbd_softraw = true;
module_param_named(softraw, atkbd_softraw, bool, 0);
MODULE_PARM_DESC(softraw, "Use software generated rawmode");
-static int atkbd_scroll;
+static bool atkbd_scroll;
module_param_named(scroll, atkbd_scroll, bool, 0);
MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
-static int atkbd_extra;
+static bool atkbd_extra;
module_param_named(extra, atkbd_extra, bool, 0);
MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
@@ -153,16 +153,16 @@ static const unsigned short atkbd_unxlate_table[128] = {
#define ATKBD_RET_HANGEUL 0xf2
#define ATKBD_RET_ERR 0xff
-#define ATKBD_KEY_UNKNOWN 0
+#define ATKBD_KEY_UNKNOWN 0
#define ATKBD_KEY_NULL 255
-#define ATKBD_SCR_1 254
-#define ATKBD_SCR_2 253
-#define ATKBD_SCR_4 252
-#define ATKBD_SCR_8 251
-#define ATKBD_SCR_CLICK 250
-#define ATKBD_SCR_LEFT 249
-#define ATKBD_SCR_RIGHT 248
+#define ATKBD_SCR_1 0xfffe
+#define ATKBD_SCR_2 0xfffd
+#define ATKBD_SCR_4 0xfffc
+#define ATKBD_SCR_8 0xfffb
+#define ATKBD_SCR_CLICK 0xfffa
+#define ATKBD_SCR_LEFT 0xfff9
+#define ATKBD_SCR_RIGHT 0xfff8
#define ATKBD_SPECIAL ATKBD_SCR_RIGHT
@@ -177,7 +177,7 @@ static const unsigned short atkbd_unxlate_table[128] = {
#define ATKBD_XL_HANJA 0x20
static const struct {
- unsigned char keycode;
+ unsigned short keycode;
unsigned char set2;
} atkbd_scroll_keys[] = {
{ ATKBD_SCR_1, 0xc5 },
@@ -206,18 +206,18 @@ struct atkbd {
unsigned short keycode[ATKBD_KEYMAP_SIZE];
DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE);
unsigned char set;
- unsigned char translated;
- unsigned char extra;
- unsigned char write;
- unsigned char softrepeat;
- unsigned char softraw;
- unsigned char scroll;
- unsigned char enabled;
+ bool translated;
+ bool extra;
+ bool write;
+ bool softrepeat;
+ bool softraw;
+ bool scroll;
+ bool enabled;
/* Accessed only from interrupt */
unsigned char emul;
- unsigned char resend;
- unsigned char release;
+ bool resend;
+ bool release;
unsigned long xl_bit;
unsigned int last;
unsigned long time;
@@ -225,8 +225,10 @@ struct atkbd {
struct delayed_work event_work;
unsigned long event_jiffies;
- struct mutex event_mutex;
unsigned long event_mask;
+
+ /* Serializes reconnect(), attr->set() and event work */
+ struct mutex mutex;
};
/*
@@ -299,18 +301,18 @@ static const unsigned int xl_table[] = {
* Checks if we should mangle the scancode to extract 'release' bit
* in translated mode.
*/
-static int atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
+static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
{
int i;
if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1)
- return 0;
+ return false;
for (i = 0; i < ARRAY_SIZE(xl_table); i++)
if (code == xl_table[i])
return test_bit(i, &xl_bit);
- return 1;
+ return true;
}
/*
@@ -357,7 +359,7 @@ static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code
*/
static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
- unsigned int flags)
+ unsigned int flags)
{
struct atkbd *atkbd = serio_get_drvdata(serio);
struct input_dev *dev = atkbd->dev;
@@ -366,20 +368,18 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
int value;
unsigned short keycode;
-#ifdef ATKBD_DEBUG
- printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
-#endif
+ dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
#if !defined(__i386__) && !defined (__x86_64__)
if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
- printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags);
+ dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags);
serio_write(serio, ATKBD_CMD_RESEND);
- atkbd->resend = 1;
+ atkbd->resend = true;
goto out;
}
if (!flags && data == ATKBD_RET_ACK)
- atkbd->resend = 0;
+ atkbd->resend = false;
#endif
if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
@@ -410,32 +410,32 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
}
switch (code) {
- case ATKBD_RET_BAT:
- atkbd->enabled = 0;
- serio_reconnect(atkbd->ps2dev.serio);
- goto out;
- case ATKBD_RET_EMUL0:
- atkbd->emul = 1;
- goto out;
- case ATKBD_RET_EMUL1:
- atkbd->emul = 2;
- goto out;
- case ATKBD_RET_RELEASE:
- atkbd->release = 1;
- goto out;
- case ATKBD_RET_ACK:
- case ATKBD_RET_NAK:
- if (printk_ratelimit())
- printk(KERN_WARNING "atkbd.c: Spurious %s on %s. "
- "Some program might be trying access hardware directly.\n",
- data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
- goto out;
- case ATKBD_RET_ERR:
- atkbd->err_count++;
-#ifdef ATKBD_DEBUG
- printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
-#endif
- goto out;
+ case ATKBD_RET_BAT:
+ atkbd->enabled = false;
+ serio_reconnect(atkbd->ps2dev.serio);
+ goto out;
+ case ATKBD_RET_EMUL0:
+ atkbd->emul = 1;
+ goto out;
+ case ATKBD_RET_EMUL1:
+ atkbd->emul = 2;
+ goto out;
+ case ATKBD_RET_RELEASE:
+ atkbd->release = true;
+ goto out;
+ case ATKBD_RET_ACK:
+ case ATKBD_RET_NAK:
+ if (printk_ratelimit())
+ dev_warn(&serio->dev,
+ "Spurious %s on %s. "
+ "Some program might be trying access hardware directly.\n",
+ data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
+ goto out;
+ case ATKBD_RET_ERR:
+ atkbd->err_count++;
+ dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n",
+ serio->phys);
+ goto out;
}
code = atkbd_compat_scancode(atkbd, code);
@@ -449,71 +449,72 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
input_event(dev, EV_MSC, MSC_SCAN, code);
switch (keycode) {
- case ATKBD_KEY_NULL:
- break;
- case ATKBD_KEY_UNKNOWN:
- printk(KERN_WARNING
- "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n",
- atkbd->release ? "released" : "pressed",
- atkbd->translated ? "translated" : "raw",
- atkbd->set, code, serio->phys);
- printk(KERN_WARNING
- "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
- code & 0x80 ? "e0" : "", code & 0x7f);
- input_sync(dev);
- break;
- case ATKBD_SCR_1:
- scroll = 1 - atkbd->release * 2;
- break;
- case ATKBD_SCR_2:
- scroll = 2 - atkbd->release * 4;
- break;
- case ATKBD_SCR_4:
- scroll = 4 - atkbd->release * 8;
- break;
- case ATKBD_SCR_8:
- scroll = 8 - atkbd->release * 16;
- break;
- case ATKBD_SCR_CLICK:
- click = !atkbd->release;
- break;
- case ATKBD_SCR_LEFT:
- hscroll = -1;
- break;
- case ATKBD_SCR_RIGHT:
- hscroll = 1;
- break;
- default:
- if (atkbd->release) {
- value = 0;
- atkbd->last = 0;
- } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
- /* Workaround Toshiba laptop multiple keypress */
- value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
- } else {
- value = 1;
- atkbd->last = code;
- atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
- }
-
- input_event(dev, EV_KEY, keycode, value);
- input_sync(dev);
+ case ATKBD_KEY_NULL:
+ break;
+ case ATKBD_KEY_UNKNOWN:
+ dev_warn(&serio->dev,
+ "Unknown key %s (%s set %d, code %#x on %s).\n",
+ atkbd->release ? "released" : "pressed",
+ atkbd->translated ? "translated" : "raw",
+ atkbd->set, code, serio->phys);
+ dev_warn(&serio->dev,
+ "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
+ code & 0x80 ? "e0" : "", code & 0x7f);
+ input_sync(dev);
+ break;
+ case ATKBD_SCR_1:
+ scroll = 1;
+ break;
+ case ATKBD_SCR_2:
+ scroll = 2;
+ break;
+ case ATKBD_SCR_4:
+ scroll = 4;
+ break;
+ case ATKBD_SCR_8:
+ scroll = 8;
+ break;
+ case ATKBD_SCR_CLICK:
+ click = !atkbd->release;
+ break;
+ case ATKBD_SCR_LEFT:
+ hscroll = -1;
+ break;
+ case ATKBD_SCR_RIGHT:
+ hscroll = 1;
+ break;
+ default:
+ if (atkbd->release) {
+ value = 0;
+ atkbd->last = 0;
+ } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
+ /* Workaround Toshiba laptop multiple keypress */
+ value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
+ } else {
+ value = 1;
+ atkbd->last = code;
+ atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
+ }
+
+ input_event(dev, EV_KEY, keycode, value);
+ input_sync(dev);
- if (value && test_bit(code, atkbd->force_release_mask)) {
- input_report_key(dev, keycode, 0);
- input_sync(dev);
- }
+ if (value && test_bit(code, atkbd->force_release_mask)) {
+ input_report_key(dev, keycode, 0);
+ input_sync(dev);
+ }
}
if (atkbd->scroll) {
if (click != -1)
input_report_key(dev, BTN_MIDDLE, click);
- input_report_rel(dev, REL_WHEEL, scroll);
+ input_report_rel(dev, REL_WHEEL,
+ atkbd->release ? -scroll : scroll);
input_report_rel(dev, REL_HWHEEL, hscroll);
input_sync(dev);
}
- atkbd->release = 0;
+ atkbd->release = false;
out:
return IRQ_HANDLED;
}
@@ -577,7 +578,7 @@ static void atkbd_event_work(struct work_struct *work)
{
struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work);
- mutex_lock(&atkbd->event_mutex);
+ mutex_lock(&atkbd->mutex);
if (!atkbd->enabled) {
/*
@@ -596,7 +597,7 @@ static void atkbd_event_work(struct work_struct *work)
atkbd_set_repeat_rate(atkbd);
}
- mutex_unlock(&atkbd->event_mutex);
+ mutex_unlock(&atkbd->mutex);
}
/*
@@ -612,7 +613,7 @@ static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit)
atkbd->event_jiffies = jiffies;
set_bit(event_bit, &atkbd->event_mask);
- wmb();
+ mb();
schedule_delayed_work(&atkbd->event_work, delay);
}
@@ -632,17 +633,18 @@ static int atkbd_event(struct input_dev *dev,
switch (type) {
- case EV_LED:
- atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
- return 0;
+ case EV_LED:
+ atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
+ return 0;
- case EV_REP:
- if (!atkbd->softrepeat)
- atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
- return 0;
- }
+ case EV_REP:
+ if (!atkbd->softrepeat)
+ atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
+ return 0;
- return -1;
+ default:
+ return -1;
+ }
}
/*
@@ -653,7 +655,7 @@ static int atkbd_event(struct input_dev *dev,
static inline void atkbd_enable(struct atkbd *atkbd)
{
serio_pause_rx(atkbd->ps2dev.serio);
- atkbd->enabled = 1;
+ atkbd->enabled = true;
serio_continue_rx(atkbd->ps2dev.serio);
}
@@ -665,7 +667,7 @@ static inline void atkbd_enable(struct atkbd *atkbd)
static inline void atkbd_disable(struct atkbd *atkbd)
{
serio_pause_rx(atkbd->ps2dev.serio);
- atkbd->enabled = 0;
+ atkbd->enabled = false;
serio_continue_rx(atkbd->ps2dev.serio);
}
@@ -686,7 +688,9 @@ static int atkbd_probe(struct atkbd *atkbd)
if (atkbd_reset)
if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
- printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", ps2dev->serio->phys);
+ dev_warn(&ps2dev->serio->dev,
+ "keyboard reset failed on %s\n",
+ ps2dev->serio->phys);
/*
* Then we check the keyboard ID. We should get 0xab83 under normal conditions.
@@ -716,8 +720,9 @@ static int atkbd_probe(struct atkbd *atkbd)
atkbd->id = (param[0] << 8) | param[1];
if (atkbd->id == 0xaca1 && atkbd->translated) {
- printk(KERN_ERR "atkbd.c: NCD terminal keyboards are only supported on non-translating\n");
- printk(KERN_ERR "atkbd.c: controllers. Use i8042.direct=1 to disable translation.\n");
+ dev_err(&ps2dev->serio->dev,
+ "NCD terminal keyboards are only supported on non-translating controlelrs. "
+ "Use i8042.direct=1 to disable translation.\n");
return -1;
}
@@ -735,7 +740,7 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
struct ps2dev *ps2dev = &atkbd->ps2dev;
unsigned char param[2];
- atkbd->extra = 0;
+ atkbd->extra = false;
/*
* For known special keyboards we can go ahead and set the correct set.
* We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
@@ -754,7 +759,7 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
if (allow_extra) {
param[0] = 0x71;
if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
- atkbd->extra = 1;
+ atkbd->extra = true;
return 2;
}
}
@@ -819,7 +824,8 @@ static int atkbd_activate(struct atkbd *atkbd)
*/
if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
- printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
+ dev_err(&ps2dev->serio->dev,
+ "Failed to enable keyboard on %s\n",
ps2dev->serio->phys);
return -1;
}
@@ -849,13 +855,20 @@ static void atkbd_disconnect(struct serio *serio)
{
struct atkbd *atkbd = serio_get_drvdata(serio);
+ sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
+
atkbd_disable(atkbd);
- /* make sure we don't have a command in flight */
+ input_unregister_device(atkbd->dev);
+
+ /*
+ * Make sure we don't have a command in flight.
+ * Note that since atkbd->enabled is false event work will keep
+ * rescheduling itself until it gets canceled and will not try
+ * accessing freed input device or serio port.
+ */
cancel_delayed_work_sync(&atkbd->event_work);
- sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
- input_unregister_device(atkbd->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
kfree(atkbd);
@@ -1061,9 +1074,13 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
input_dev->keycodesize = sizeof(unsigned short);
input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
- for (i = 0; i < ATKBD_KEYMAP_SIZE; i++)
- if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
+ for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) {
+ if (atkbd->keycode[i] != KEY_RESERVED &&
+ atkbd->keycode[i] != ATKBD_KEY_NULL &&
+ atkbd->keycode[i] < ATKBD_SPECIAL) {
__set_bit(atkbd->keycode[i], input_dev->keybit);
+ }
+ }
}
/*
@@ -1087,16 +1104,18 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
atkbd->dev = dev;
ps2_init(&atkbd->ps2dev, serio);
INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work);
- mutex_init(&atkbd->event_mutex);
+ mutex_init(&atkbd->mutex);
switch (serio->id.type) {
- case SERIO_8042_XL:
- atkbd->translated = 1;
- case SERIO_8042:
- if (serio->write)
- atkbd->write = 1;
- break;
+ case SERIO_8042_XL:
+ atkbd->translated = true;
+ /* Fall through */
+
+ case SERIO_8042:
+ if (serio->write)
+ atkbd->write = true;
+ break;
}
atkbd->softraw = atkbd_softraw;
@@ -1104,7 +1123,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
atkbd->scroll = atkbd_scroll;
if (atkbd->softrepeat)
- atkbd->softraw = 1;
+ atkbd->softraw = true;
serio_set_drvdata(serio, atkbd);
@@ -1160,19 +1179,24 @@ static int atkbd_reconnect(struct serio *serio)
{
struct atkbd *atkbd = serio_get_drvdata(serio);
struct serio_driver *drv = serio->drv;
+ int retval = -1;
if (!atkbd || !drv) {
- printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
+ dev_dbg(&serio->dev,
+ "reconnect request, but serio is disconnected, ignoring...\n");
return -1;
}
+ mutex_lock(&atkbd->mutex);
+
atkbd_disable(atkbd);
if (atkbd->write) {
if (atkbd_probe(atkbd))
- return -1;
+ goto out;
+
if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
- return -1;
+ goto out;
atkbd_activate(atkbd);
@@ -1190,8 +1214,11 @@ static int atkbd_reconnect(struct serio *serio)
}
atkbd_enable(atkbd);
+ retval = 0;
- return 0;
+ out:
+ mutex_unlock(&atkbd->mutex);
+ return retval;
}
static struct serio_device_id atkbd_serio_ids[] = {
@@ -1235,47 +1262,28 @@ static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
ssize_t (*handler)(struct atkbd *, char *))
{
struct serio *serio = to_serio_port(dev);
- int retval;
-
- retval = serio_pin_driver(serio);
- if (retval)
- return retval;
-
- if (serio->drv != &atkbd_drv) {
- retval = -ENODEV;
- goto out;
- }
-
- retval = handler((struct atkbd *)serio_get_drvdata(serio), buf);
+ struct atkbd *atkbd = serio_get_drvdata(serio);
-out:
- serio_unpin_driver(serio);
- return retval;
+ return handler(atkbd, buf);
}
static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
ssize_t (*handler)(struct atkbd *, const char *, size_t))
{
struct serio *serio = to_serio_port(dev);
- struct atkbd *atkbd;
+ struct atkbd *atkbd = serio_get_drvdata(serio);
int retval;
- retval = serio_pin_driver(serio);
+ retval = mutex_lock_interruptible(&atkbd->mutex);
if (retval)
return retval;
- if (serio->drv != &atkbd_drv) {
- retval = -ENODEV;
- goto out;
- }
-
- atkbd = serio_get_drvdata(serio);
atkbd_disable(atkbd);
retval = handler(atkbd, buf, count);
atkbd_enable(atkbd);
-out:
- serio_unpin_driver(serio);
+ mutex_unlock(&atkbd->mutex);
+
return retval;
}
@@ -1289,7 +1297,8 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
struct input_dev *old_dev, *new_dev;
unsigned long value;
int err;
- unsigned char old_extra, old_set;
+ bool old_extra;
+ unsigned char old_set;
if (!atkbd->write)
return -EIO;
@@ -1372,7 +1381,7 @@ static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t cou
struct input_dev *old_dev, *new_dev;
unsigned long value;
int err;
- unsigned char old_scroll;
+ bool old_scroll;
if (strict_strtoul(buf, 10, &value) || value > 1)
return -EINVAL;
@@ -1416,7 +1425,8 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
struct input_dev *old_dev, *new_dev;
unsigned long value;
int err;
- unsigned char old_set, old_extra;
+ unsigned char old_set;
+ bool old_extra;
if (!atkbd->write)
return -EIO;
@@ -1466,7 +1476,7 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t
struct input_dev *old_dev, *new_dev;
unsigned long value;
int err;
- unsigned char old_softrepeat, old_softraw;
+ bool old_softrepeat, old_softraw;
if (!atkbd->write)
return -EIO;
@@ -1486,7 +1496,7 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t
atkbd->dev = new_dev;
atkbd->softrepeat = value;
if (atkbd->softrepeat)
- atkbd->softraw = 1;
+ atkbd->softraw = true;
atkbd_set_device_attrs(atkbd);
err = input_register_device(atkbd->dev);
@@ -1516,7 +1526,7 @@ static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t co
struct input_dev *old_dev, *new_dev;
unsigned long value;
int err;
- unsigned char old_softraw;
+ bool old_softraw;
if (strict_strtoul(buf, 10, &value) || value > 1)
return -EINVAL;
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c
index fe376a27fe57..593c052416b9 100644
--- a/drivers/input/keyboard/bf54x-keys.c
+++ b/drivers/input/keyboard/bf54x-keys.c
@@ -162,7 +162,7 @@ static irqreturn_t bfin_kpad_isr(int irq, void *dev_id)
input_sync(input);
if (bfin_kpad_get_keypressed(bf54x_kpad)) {
- disable_irq(bf54x_kpad->irq);
+ disable_irq_nosync(bf54x_kpad->irq);
bf54x_kpad->lastkey = key;
mod_timer(&bf54x_kpad->timer,
jiffies + bf54x_kpad->keyup_test_jiffies);
diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c
index 6e52d855f637..d410d7a52f1d 100644
--- a/drivers/input/keyboard/davinci_keyscan.c
+++ b/drivers/input/keyboard/davinci_keyscan.c
@@ -174,6 +174,14 @@ static int __init davinci_ks_probe(struct platform_device *pdev)
struct davinci_ks_platform_data *pdata = pdev->dev.platform_data;
int error, i;
+ if (pdata->device_enable) {
+ error = pdata->device_enable(dev);
+ if (error < 0) {
+ dev_dbg(dev, "device enable function failed\n");
+ return error;
+ }
+ }
+
if (!pdata->keymap) {
dev_dbg(dev, "no keymap from pdata\n");
return -EINVAL;
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
index e45740429f7e..bd25a3af1664 100644
--- a/drivers/input/keyboard/ep93xx_keypad.c
+++ b/drivers/input/keyboard/ep93xx_keypad.c
@@ -69,7 +69,7 @@ struct ep93xx_keypad {
void __iomem *mmio_base;
- unsigned int matrix_keycodes[EP93XX_MATRIX_SIZE];
+ unsigned short keycodes[EP93XX_MATRIX_SIZE];
int key1;
int key2;
@@ -79,24 +79,6 @@ struct ep93xx_keypad {
bool enabled;
};
-static void ep93xx_keypad_build_keycode(struct ep93xx_keypad *keypad)
-{
- struct ep93xx_keypad_platform_data *pdata = keypad->pdata;
- struct input_dev *input_dev = keypad->input_dev;
- unsigned int *key;
- int i;
-
- key = &pdata->matrix_key_map[0];
- for (i = 0; i < pdata->matrix_key_map_size; i++, key++) {
- int row = KEY_ROW(*key);
- int col = KEY_COL(*key);
- int code = KEY_VAL(*key);
-
- keypad->matrix_keycodes[(row << 3) + col] = code;
- __set_bit(code, input_dev->keybit);
- }
-}
-
static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id)
{
struct ep93xx_keypad *keypad = dev_id;
@@ -107,10 +89,10 @@ static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id)
status = __raw_readl(keypad->mmio_base + KEY_REG);
keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT;
- key1 = keypad->matrix_keycodes[keycode];
+ key1 = keypad->keycodes[keycode];
keycode = (status & KEY_REG_KEY2_MASK) >> KEY_REG_KEY2_SHIFT;
- key2 = keypad->matrix_keycodes[keycode];
+ key2 = keypad->keycodes[keycode];
if (status & KEY_REG_2KEYS) {
if (keypad->key1 && key1 != keypad->key1 && key2 != keypad->key1)
@@ -256,6 +238,7 @@ static int ep93xx_keypad_resume(struct platform_device *pdev)
static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
{
struct ep93xx_keypad *keypad;
+ const struct matrix_keymap_data *keymap_data;
struct input_dev *input_dev;
struct resource *res;
int err;
@@ -270,6 +253,12 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
goto failed_free;
}
+ keymap_data = keypad->pdata->keymap_data;
+ if (!keymap_data) {
+ err = -EINVAL;
+ goto failed_free;
+ }
+
keypad->irq = platform_get_irq(pdev, 0);
if (!keypad->irq) {
err = -ENXIO;
@@ -317,9 +306,9 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
input_dev->open = ep93xx_keypad_open;
input_dev->close = ep93xx_keypad_close;
input_dev->dev.parent = &pdev->dev;
- input_dev->keycode = keypad->matrix_keycodes;
- input_dev->keycodesize = sizeof(keypad->matrix_keycodes[0]);
- input_dev->keycodemax = ARRAY_SIZE(keypad->matrix_keycodes);
+ input_dev->keycode = keypad->keycodes;
+ input_dev->keycodesize = sizeof(keypad->keycodes[0]);
+ input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
input_set_drvdata(input_dev, keypad);
@@ -327,7 +316,8 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT)
input_dev->evbit[0] |= BIT_MASK(EV_REP);
- ep93xx_keypad_build_keycode(keypad);
+ matrix_keypad_build_keymap(keymap_data, 3,
+ input_dev->keycode, input_dev->keybit);
platform_set_drvdata(pdev, keypad);
err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 1aff3b76effd..2b708aa85553 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -30,13 +30,289 @@ struct gpio_button_data {
struct input_dev *input;
struct timer_list timer;
struct work_struct work;
+ bool disabled;
};
struct gpio_keys_drvdata {
struct input_dev *input;
+ struct mutex disable_lock;
+ unsigned int n_buttons;
struct gpio_button_data data[0];
};
+/*
+ * SYSFS interface for enabling/disabling keys and switches:
+ *
+ * There are 4 attributes under /sys/devices/platform/gpio-keys/
+ * keys [ro] - bitmap of keys (EV_KEY) which can be
+ * disabled
+ * switches [ro] - bitmap of switches (EV_SW) which can be
+ * disabled
+ * disabled_keys [rw] - bitmap of keys currently disabled
+ * disabled_switches [rw] - bitmap of switches currently disabled
+ *
+ * Userland can change these values and hence disable event generation
+ * for each key (or switch). Disabling a key means its interrupt line
+ * is disabled.
+ *
+ * For example, if we have following switches set up as gpio-keys:
+ * SW_DOCK = 5
+ * SW_CAMERA_LENS_COVER = 9
+ * SW_KEYPAD_SLIDE = 10
+ * SW_FRONT_PROXIMITY = 11
+ * This is read from switches:
+ * 11-9,5
+ * Next we want to disable proximity (11) and dock (5), we write:
+ * 11,5
+ * to file disabled_switches. Now proximity and dock IRQs are disabled.
+ * This can be verified by reading the file disabled_switches:
+ * 11,5
+ * If we now want to enable proximity (11) switch we write:
+ * 5
+ * to disabled_switches.
+ *
+ * We can disable only those keys which don't allow sharing the irq.
+ */
+
+/**
+ * get_n_events_by_type() - returns maximum number of events per @type
+ * @type: type of button (%EV_KEY, %EV_SW)
+ *
+ * Return value of this function can be used to allocate bitmap
+ * large enough to hold all bits for given type.
+ */
+static inline int get_n_events_by_type(int type)
+{
+ BUG_ON(type != EV_SW && type != EV_KEY);
+
+ return (type == EV_KEY) ? KEY_CNT : SW_CNT;
+}
+
+/**
+ * gpio_keys_disable_button() - disables given GPIO button
+ * @bdata: button data for button to be disabled
+ *
+ * Disables button pointed by @bdata. This is done by masking
+ * IRQ line. After this function is called, button won't generate
+ * input events anymore. Note that one can only disable buttons
+ * that don't share IRQs.
+ *
+ * Make sure that @bdata->disable_lock is locked when entering
+ * this function to avoid races when concurrent threads are
+ * disabling buttons at the same time.
+ */
+static void gpio_keys_disable_button(struct gpio_button_data *bdata)
+{
+ if (!bdata->disabled) {
+ /*
+ * Disable IRQ and possible debouncing timer.
+ */
+ disable_irq(gpio_to_irq(bdata->button->gpio));
+ if (bdata->button->debounce_interval)
+ del_timer_sync(&bdata->timer);
+
+ bdata->disabled = true;
+ }
+}
+
+/**
+ * gpio_keys_enable_button() - enables given GPIO button
+ * @bdata: button data for button to be disabled
+ *
+ * Enables given button pointed by @bdata.
+ *
+ * Make sure that @bdata->disable_lock is locked when entering
+ * this function to avoid races with concurrent threads trying
+ * to enable the same button at the same time.
+ */
+static void gpio_keys_enable_button(struct gpio_button_data *bdata)
+{
+ if (bdata->disabled) {
+ enable_irq(gpio_to_irq(bdata->button->gpio));
+ bdata->disabled = false;
+ }
+}
+
+/**
+ * gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons
+ * @ddata: pointer to drvdata
+ * @buf: buffer where stringified bitmap is written
+ * @type: button type (%EV_KEY, %EV_SW)
+ * @only_disabled: does caller want only those buttons that are
+ * currently disabled or all buttons that can be
+ * disabled
+ *
+ * This function writes buttons that can be disabled to @buf. If
+ * @only_disabled is true, then @buf contains only those buttons
+ * that are currently disabled. Returns 0 on success or negative
+ * errno on failure.
+ */
+static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
+ char *buf, unsigned int type,
+ bool only_disabled)
+{
+ int n_events = get_n_events_by_type(type);
+ unsigned long *bits;
+ ssize_t ret;
+ int i;
+
+ bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
+ if (!bits)
+ return -ENOMEM;
+
+ for (i = 0; i < ddata->n_buttons; i++) {
+ struct gpio_button_data *bdata = &ddata->data[i];
+
+ if (bdata->button->type != type)
+ continue;
+
+ if (only_disabled && !bdata->disabled)
+ continue;
+
+ __set_bit(bdata->button->code, bits);
+ }
+
+ ret = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, bits, n_events);
+ buf[ret++] = '\n';
+ buf[ret] = '\0';
+
+ kfree(bits);
+
+ return ret;
+}
+
+/**
+ * gpio_keys_attr_store_helper() - enable/disable buttons based on given bitmap
+ * @ddata: pointer to drvdata
+ * @buf: buffer from userspace that contains stringified bitmap
+ * @type: button type (%EV_KEY, %EV_SW)
+ *
+ * This function parses stringified bitmap from @buf and disables/enables
+ * GPIO buttons accordinly. Returns 0 on success and negative error
+ * on failure.
+ */
+static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
+ const char *buf, unsigned int type)
+{
+ int n_events = get_n_events_by_type(type);
+ unsigned long *bits;
+ ssize_t error;
+ int i;
+
+ bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
+ if (!bits)
+ return -ENOMEM;
+
+ error = bitmap_parselist(buf, bits, n_events);
+ if (error)
+ goto out;
+
+ /* First validate */
+ for (i = 0; i < ddata->n_buttons; i++) {
+ struct gpio_button_data *bdata = &ddata->data[i];
+
+ if (bdata->button->type != type)
+ continue;
+
+ if (test_bit(bdata->button->code, bits) &&
+ !bdata->button->can_disable) {
+ error = -EINVAL;
+ goto out;
+ }
+ }
+
+ mutex_lock(&ddata->disable_lock);
+
+ for (i = 0; i < ddata->n_buttons; i++) {
+ struct gpio_button_data *bdata = &ddata->data[i];
+
+ if (bdata->button->type != type)
+ continue;
+
+ if (test_bit(bdata->button->code, bits))
+ gpio_keys_disable_button(bdata);
+ else
+ gpio_keys_enable_button(bdata);
+ }
+
+ mutex_unlock(&ddata->disable_lock);
+
+out:
+ kfree(bits);
+ return error;
+}
+
+#define ATTR_SHOW_FN(name, type, only_disabled) \
+static ssize_t gpio_keys_show_##name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct platform_device *pdev = to_platform_device(dev); \
+ struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \
+ \
+ return gpio_keys_attr_show_helper(ddata, buf, \
+ type, only_disabled); \
+}
+
+ATTR_SHOW_FN(keys, EV_KEY, false);
+ATTR_SHOW_FN(switches, EV_SW, false);
+ATTR_SHOW_FN(disabled_keys, EV_KEY, true);
+ATTR_SHOW_FN(disabled_switches, EV_SW, true);
+
+/*
+ * ATTRIBUTES:
+ *
+ * /sys/devices/platform/gpio-keys/keys [ro]
+ * /sys/devices/platform/gpio-keys/switches [ro]
+ */
+static DEVICE_ATTR(keys, S_IRUGO, gpio_keys_show_keys, NULL);
+static DEVICE_ATTR(switches, S_IRUGO, gpio_keys_show_switches, NULL);
+
+#define ATTR_STORE_FN(name, type) \
+static ssize_t gpio_keys_store_##name(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, \
+ size_t count) \
+{ \
+ struct platform_device *pdev = to_platform_device(dev); \
+ struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \
+ ssize_t error; \
+ \
+ error = gpio_keys_attr_store_helper(ddata, buf, type); \
+ if (error) \
+ return error; \
+ \
+ return count; \
+}
+
+ATTR_STORE_FN(disabled_keys, EV_KEY);
+ATTR_STORE_FN(disabled_switches, EV_SW);
+
+/*
+ * ATTRIBUTES:
+ *
+ * /sys/devices/platform/gpio-keys/disabled_keys [rw]
+ * /sys/devices/platform/gpio-keys/disables_switches [rw]
+ */
+static DEVICE_ATTR(disabled_keys, S_IWUSR | S_IRUGO,
+ gpio_keys_show_disabled_keys,
+ gpio_keys_store_disabled_keys);
+static DEVICE_ATTR(disabled_switches, S_IWUSR | S_IRUGO,
+ gpio_keys_show_disabled_switches,
+ gpio_keys_store_disabled_switches);
+
+static struct attribute *gpio_keys_attrs[] = {
+ &dev_attr_keys.attr,
+ &dev_attr_switches.attr,
+ &dev_attr_disabled_keys.attr,
+ &dev_attr_disabled_switches.attr,
+ NULL,
+};
+
+static struct attribute_group gpio_keys_attr_group = {
+ .attrs = gpio_keys_attrs,
+};
+
static void gpio_keys_report_event(struct gpio_button_data *bdata)
{
struct gpio_keys_button *button = bdata->button;
@@ -79,11 +355,13 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int __devinit gpio_keys_setup_key(struct device *dev,
+static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
struct gpio_button_data *bdata,
struct gpio_keys_button *button)
{
char *desc = button->desc ? button->desc : "gpio_keys";
+ struct device *dev = &pdev->dev;
+ unsigned long irqflags;
int irq, error;
setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);
@@ -112,10 +390,15 @@ static int __devinit gpio_keys_setup_key(struct device *dev,
goto fail3;
}
- error = request_irq(irq, gpio_keys_isr,
- IRQF_SHARED |
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- desc, bdata);
+ irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+ /*
+ * If platform has specified that the button can be disabled,
+ * we don't want it to share the interrupt line.
+ */
+ if (!button->can_disable)
+ irqflags |= IRQF_SHARED;
+
+ error = request_irq(irq, gpio_keys_isr, irqflags, desc, bdata);
if (error) {
dev_err(dev, "Unable to claim irq %d; error %d\n",
irq, error);
@@ -149,6 +432,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
goto fail1;
}
+ ddata->input = input;
+ ddata->n_buttons = pdata->nbuttons;
+ mutex_init(&ddata->disable_lock);
+
platform_set_drvdata(pdev, ddata);
input->name = pdev->name;
@@ -164,8 +451,6 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
if (pdata->rep)
__set_bit(EV_REP, input->evbit);
- ddata->input = input;
-
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_button_data *bdata = &ddata->data[i];
@@ -174,7 +459,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
bdata->input = input;
bdata->button = button;
- error = gpio_keys_setup_key(dev, bdata, button);
+ error = gpio_keys_setup_key(pdev, bdata, button);
if (error)
goto fail2;
@@ -184,13 +469,20 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
input_set_capability(input, type, button->code);
}
- error = input_register_device(input);
+ error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
if (error) {
- dev_err(dev, "Unable to register input device, "
- "error: %d\n", error);
+ dev_err(dev, "Unable to export keys/switches, error: %d\n",
+ error);
goto fail2;
}
+ error = input_register_device(input);
+ if (error) {
+ dev_err(dev, "Unable to register input device, error: %d\n",
+ error);
+ goto fail3;
+ }
+
/* get current state of buttons */
for (i = 0; i < pdata->nbuttons; i++)
gpio_keys_report_event(&ddata->data[i]);
@@ -200,6 +492,8 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
return 0;
+ fail3:
+ sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
fail2:
while (--i >= 0) {
free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
@@ -224,6 +518,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
struct input_dev *input = ddata->input;
int i;
+ sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
+
device_init_wakeup(&pdev->dev, 0);
for (i = 0; i < pdata->nbuttons; i++) {
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
new file mode 100644
index 000000000000..2ee5b798024d
--- /dev/null
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -0,0 +1,594 @@
+/*
+ * Driver for the IMX keypad port.
+ * Copyright (C) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.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.
+ *
+ * <<Power management needs to be implemented>>.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/timer.h>
+
+/*
+ * Keypad Controller registers (halfword)
+ */
+#define KPCR 0x00 /* Keypad Control Register */
+
+#define KPSR 0x02 /* Keypad Status Register */
+#define KBD_STAT_KPKD (0x1 << 0) /* Key Press Interrupt Status bit (w1c) */
+#define KBD_STAT_KPKR (0x1 << 1) /* Key Release Interrupt Status bit (w1c) */
+#define KBD_STAT_KDSC (0x1 << 2) /* Key Depress Synch Chain Status bit (w1c)*/
+#define KBD_STAT_KRSS (0x1 << 3) /* Key Release Synch Status bit (w1c)*/
+#define KBD_STAT_KDIE (0x1 << 8) /* Key Depress Interrupt Enable Status bit */
+#define KBD_STAT_KRIE (0x1 << 9) /* Key Release Interrupt Enable */
+#define KBD_STAT_KPPEN (0x1 << 10) /* Keypad Clock Enable */
+
+#define KDDR 0x04 /* Keypad Data Direction Register */
+#define KPDR 0x06 /* Keypad Data Register */
+
+#define MAX_MATRIX_KEY_ROWS 8
+#define MAX_MATRIX_KEY_COLS 8
+#define MATRIX_ROW_SHIFT 3
+
+#define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS)
+
+struct imx_keypad {
+
+ struct clk *clk;
+ struct input_dev *input_dev;
+ void __iomem *mmio_base;
+
+ int irq;
+ struct timer_list check_matrix_timer;
+
+ /*
+ * The matrix is stable only if no changes are detected after
+ * IMX_KEYPAD_SCANS_FOR_STABILITY scans
+ */
+#define IMX_KEYPAD_SCANS_FOR_STABILITY 3
+ int stable_count;
+
+ bool enabled;
+
+ /* Masks for enabled rows/cols */
+ unsigned short rows_en_mask;
+ unsigned short cols_en_mask;
+
+ unsigned short keycodes[MAX_MATRIX_KEY_NUM];
+
+ /*
+ * Matrix states:
+ * -stable: achieved after a complete debounce process.
+ * -unstable: used in the debouncing process.
+ */
+ unsigned short matrix_stable_state[MAX_MATRIX_KEY_COLS];
+ unsigned short matrix_unstable_state[MAX_MATRIX_KEY_COLS];
+};
+
+/* Scan the matrix and return the new state in *matrix_volatile_state. */
+static void imx_keypad_scan_matrix(struct imx_keypad *keypad,
+ unsigned short *matrix_volatile_state)
+{
+ int col;
+ unsigned short reg_val;
+
+ for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
+ if ((keypad->cols_en_mask & (1 << col)) == 0)
+ continue;
+ /*
+ * Discharge keypad capacitance:
+ * 2. write 1s on column data.
+ * 3. configure columns as totem-pole to discharge capacitance.
+ * 4. configure columns as open-drain.
+ */
+ reg_val = readw(keypad->mmio_base + KPDR);
+ reg_val |= 0xff00;
+ writew(reg_val, keypad->mmio_base + KPDR);
+
+ reg_val = readw(keypad->mmio_base + KPCR);
+ reg_val &= ~((keypad->cols_en_mask & 0xff) << 8);
+ writew(reg_val, keypad->mmio_base + KPCR);
+
+ udelay(2);
+
+ reg_val = readw(keypad->mmio_base + KPCR);
+ reg_val |= (keypad->cols_en_mask & 0xff) << 8;
+ writew(reg_val, keypad->mmio_base + KPCR);
+
+ /*
+ * 5. Write a single column to 0, others to 1.
+ * 6. Sample row inputs and save data.
+ * 7. Repeat steps 2 - 6 for remaining columns.
+ */
+ reg_val = readw(keypad->mmio_base + KPDR);
+ reg_val &= ~(1 << (8 + col));
+ writew(reg_val, keypad->mmio_base + KPDR);
+
+ /*
+ * Delay added to avoid propagating the 0 from column to row
+ * when scanning.
+ */
+ udelay(5);
+
+ /*
+ * 1s in matrix_volatile_state[col] means key pressures
+ * throw data from non enabled rows.
+ */
+ reg_val = readw(keypad->mmio_base + KPDR);
+ matrix_volatile_state[col] = (~reg_val) & keypad->rows_en_mask;
+ }
+
+ /*
+ * Return in standby mode:
+ * 9. write 0s to columns
+ */
+ reg_val = readw(keypad->mmio_base + KPDR);
+ reg_val &= 0x00ff;
+ writew(reg_val, keypad->mmio_base + KPDR);
+}
+
+/*
+ * Compare the new matrix state (volatile) with the stable one stored in
+ * keypad->matrix_stable_state and fire events if changes are detected.
+ */
+static void imx_keypad_fire_events(struct imx_keypad *keypad,
+ unsigned short *matrix_volatile_state)
+{
+ struct input_dev *input_dev = keypad->input_dev;
+ int row, col;
+
+ for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
+ unsigned short bits_changed;
+ int code;
+
+ if ((keypad->cols_en_mask & (1 << col)) == 0)
+ continue; /* Column is not enabled */
+
+ bits_changed = keypad->matrix_stable_state[col] ^
+ matrix_volatile_state[col];
+
+ if (bits_changed == 0)
+ continue; /* Column does not contain changes */
+
+ for (row = 0; row < MAX_MATRIX_KEY_ROWS; row++) {
+ if ((keypad->rows_en_mask & (1 << row)) == 0)
+ continue; /* Row is not enabled */
+ if ((bits_changed & (1 << row)) == 0)
+ continue; /* Row does not contain changes */
+
+ code = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
+ input_event(input_dev, EV_MSC, MSC_SCAN, code);
+ input_report_key(input_dev, keypad->keycodes[code],
+ matrix_volatile_state[col] & (1 << row));
+ dev_dbg(&input_dev->dev, "Event code: %d, val: %d",
+ keypad->keycodes[code],
+ matrix_volatile_state[col] & (1 << row));
+ }
+ }
+ input_sync(input_dev);
+}
+
+/*
+ * imx_keypad_check_for_events is the timer handler.
+ */
+static void imx_keypad_check_for_events(unsigned long data)
+{
+ struct imx_keypad *keypad = (struct imx_keypad *) data;
+ unsigned short matrix_volatile_state[MAX_MATRIX_KEY_COLS];
+ unsigned short reg_val;
+ bool state_changed, is_zero_matrix;
+ int i;
+
+ memset(matrix_volatile_state, 0, sizeof(matrix_volatile_state));
+
+ imx_keypad_scan_matrix(keypad, matrix_volatile_state);
+
+ state_changed = false;
+ for (i = 0; i < MAX_MATRIX_KEY_COLS; i++) {
+ if ((keypad->cols_en_mask & (1 << i)) == 0)
+ continue;
+
+ if (keypad->matrix_unstable_state[i] ^ matrix_volatile_state[i]) {
+ state_changed = true;
+ break;
+ }
+ }
+
+ /*
+ * If the matrix state is changed from the previous scan
+ * (Re)Begin the debouncing process, saving the new state in
+ * keypad->matrix_unstable_state.
+ * else
+ * Increase the count of number of scans with a stable state.
+ */
+ if (state_changed) {
+ memcpy(keypad->matrix_unstable_state, matrix_volatile_state,
+ sizeof(matrix_volatile_state));
+ keypad->stable_count = 0;
+ } else
+ keypad->stable_count++;
+
+ /*
+ * If the matrix is not as stable as we want reschedule scan
+ * in the near future.
+ */
+ if (keypad->stable_count < IMX_KEYPAD_SCANS_FOR_STABILITY) {
+ mod_timer(&keypad->check_matrix_timer,
+ jiffies + msecs_to_jiffies(10));
+ return;
+ }
+
+ /*
+ * If the matrix state is stable, fire the events and save the new
+ * stable state. Note, if the matrix is kept stable for longer
+ * (keypad->stable_count > IMX_KEYPAD_SCANS_FOR_STABILITY) all
+ * events have already been generated.
+ */
+ if (keypad->stable_count == IMX_KEYPAD_SCANS_FOR_STABILITY) {
+ imx_keypad_fire_events(keypad, matrix_volatile_state);
+
+ memcpy(keypad->matrix_stable_state, matrix_volatile_state,
+ sizeof(matrix_volatile_state));
+ }
+
+ is_zero_matrix = true;
+ for (i = 0; i < MAX_MATRIX_KEY_COLS; i++) {
+ if (matrix_volatile_state[i] != 0) {
+ is_zero_matrix = false;
+ break;
+ }
+ }
+
+
+ if (is_zero_matrix) {
+ /*
+ * All keys have been released. Enable only the KDI
+ * interrupt for future key presses (clear the KDI
+ * status bit and its sync chain before that).
+ */
+ reg_val = readw(keypad->mmio_base + KPSR);
+ reg_val |= KBD_STAT_KPKD | KBD_STAT_KDSC;
+ writew(reg_val, keypad->mmio_base + KPSR);
+
+ reg_val = readw(keypad->mmio_base + KPSR);
+ reg_val |= KBD_STAT_KDIE;
+ reg_val &= ~KBD_STAT_KRIE;
+ writew(reg_val, keypad->mmio_base + KPSR);
+ } else {
+ /*
+ * Some keys are still pressed. Schedule a rescan in
+ * attempt to detect multiple key presses and enable
+ * the KRI interrupt to react quickly to key release
+ * event.
+ */
+ mod_timer(&keypad->check_matrix_timer,
+ jiffies + msecs_to_jiffies(60));
+
+ reg_val = readw(keypad->mmio_base + KPSR);
+ reg_val |= KBD_STAT_KPKR | KBD_STAT_KRSS;
+ writew(reg_val, keypad->mmio_base + KPSR);
+
+ reg_val = readw(keypad->mmio_base + KPSR);
+ reg_val |= KBD_STAT_KRIE;
+ reg_val &= ~KBD_STAT_KDIE;
+ writew(reg_val, keypad->mmio_base + KPSR);
+ }
+}
+
+static irqreturn_t imx_keypad_irq_handler(int irq, void *dev_id)
+{
+ struct imx_keypad *keypad = dev_id;
+ unsigned short reg_val;
+
+ reg_val = readw(keypad->mmio_base + KPSR);
+
+ /* Disable both interrupt types */
+ reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE);
+ /* Clear interrupts status bits */
+ reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD;
+ writew(reg_val, keypad->mmio_base + KPSR);
+
+ if (keypad->enabled) {
+ /* The matrix is supposed to be changed */
+ keypad->stable_count = 0;
+
+ /* Schedule the scanning procedure near in the future */
+ mod_timer(&keypad->check_matrix_timer,
+ jiffies + msecs_to_jiffies(2));
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void imx_keypad_config(struct imx_keypad *keypad)
+{
+ unsigned short reg_val;
+
+ /*
+ * Include enabled rows in interrupt generation (KPCR[7:0])
+ * Configure keypad columns as open-drain (KPCR[15:8])
+ */
+ reg_val = readw(keypad->mmio_base + KPCR);
+ reg_val |= keypad->rows_en_mask & 0xff; /* rows */
+ reg_val |= (keypad->cols_en_mask & 0xff) << 8; /* cols */
+ writew(reg_val, keypad->mmio_base + KPCR);
+
+ /* Write 0's to KPDR[15:8] (Colums) */
+ reg_val = readw(keypad->mmio_base + KPDR);
+ reg_val &= 0x00ff;
+ writew(reg_val, keypad->mmio_base + KPDR);
+
+ /* Configure columns as output, rows as input (KDDR[15:0]) */
+ writew(0xff00, keypad->mmio_base + KDDR);
+
+ /*
+ * Clear Key Depress and Key Release status bit.
+ * Clear both synchronizer chain.
+ */
+ reg_val = readw(keypad->mmio_base + KPSR);
+ reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD |
+ KBD_STAT_KDSC | KBD_STAT_KRSS;
+ writew(reg_val, keypad->mmio_base + KPSR);
+
+ /* Enable KDI and disable KRI (avoid false release events). */
+ reg_val |= KBD_STAT_KDIE;
+ reg_val &= ~KBD_STAT_KRIE;
+ writew(reg_val, keypad->mmio_base + KPSR);
+}
+
+static void imx_keypad_inhibit(struct imx_keypad *keypad)
+{
+ unsigned short reg_val;
+
+ /* Inhibit KDI and KRI interrupts. */
+ reg_val = readw(keypad->mmio_base + KPSR);
+ reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE);
+ writew(reg_val, keypad->mmio_base + KPSR);
+
+ /* Colums as open drain and disable all rows */
+ writew(0xff00, keypad->mmio_base + KPCR);
+}
+
+static void imx_keypad_close(struct input_dev *dev)
+{
+ struct imx_keypad *keypad = input_get_drvdata(dev);
+
+ dev_dbg(&dev->dev, ">%s\n", __func__);
+
+ /* Mark keypad as being inactive */
+ keypad->enabled = false;
+ synchronize_irq(keypad->irq);
+ del_timer_sync(&keypad->check_matrix_timer);
+
+ imx_keypad_inhibit(keypad);
+
+ /* Disable clock unit */
+ clk_disable(keypad->clk);
+}
+
+static int imx_keypad_open(struct input_dev *dev)
+{
+ struct imx_keypad *keypad = input_get_drvdata(dev);
+
+ dev_dbg(&dev->dev, ">%s\n", __func__);
+
+ /* We became active from now */
+ keypad->enabled = true;
+
+ /* Enable the kpp clock */
+ clk_enable(keypad->clk);
+ imx_keypad_config(keypad);
+
+ /* Sanity control, not all the rows must be actived now. */
+ if ((readw(keypad->mmio_base + KPDR) & keypad->rows_en_mask) == 0) {
+ dev_err(&dev->dev,
+ "too many keys pressed, control pins initialisation\n");
+ goto open_err;
+ }
+
+ return 0;
+
+open_err:
+ imx_keypad_close(dev);
+ return -EIO;
+}
+
+static int __devinit imx_keypad_probe(struct platform_device *pdev)
+{
+ const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data;
+ struct imx_keypad *keypad;
+ struct input_dev *input_dev;
+ struct resource *res;
+ int irq, error, i;
+
+ if (keymap_data == NULL) {
+ dev_err(&pdev->dev, "no keymap defined\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq defined in platform data\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no I/O memory defined in platform data\n");
+ return -EINVAL;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ return -EBUSY;
+ }
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ dev_err(&pdev->dev, "failed to allocate the input device\n");
+ error = -ENOMEM;
+ goto failed_rel_mem;
+ }
+
+ keypad = kzalloc(sizeof(struct imx_keypad), GFP_KERNEL);
+ if (!keypad) {
+ dev_err(&pdev->dev, "not enough memory for driver data\n");
+ error = -ENOMEM;
+ goto failed_free_input;
+ }
+
+ keypad->input_dev = input_dev;
+ keypad->irq = irq;
+ keypad->stable_count = 0;
+
+ setup_timer(&keypad->check_matrix_timer,
+ imx_keypad_check_for_events, (unsigned long) keypad);
+
+ keypad->mmio_base = ioremap(res->start, resource_size(res));
+ if (keypad->mmio_base == NULL) {
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ error = -ENOMEM;
+ goto failed_free_priv;
+ }
+
+ keypad->clk = clk_get(&pdev->dev, "kpp");
+ if (IS_ERR(keypad->clk)) {
+ dev_err(&pdev->dev, "failed to get keypad clock\n");
+ error = PTR_ERR(keypad->clk);
+ goto failed_unmap;
+ }
+
+ /* Search for rows and cols enabled */
+ for (i = 0; i < keymap_data->keymap_size; i++) {
+ keypad->rows_en_mask |= 1 << KEY_ROW(keymap_data->keymap[i]);
+ keypad->cols_en_mask |= 1 << KEY_COL(keymap_data->keymap[i]);
+ }
+
+ if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) ||
+ keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
+ dev_err(&pdev->dev,
+ "invalid key data (too many rows or colums)\n");
+ error = -EINVAL;
+ goto failed_clock_put;
+ }
+ dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask);
+ dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask);
+
+ /* Init the Input device */
+ input_dev->name = pdev->name;
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->dev.parent = &pdev->dev;
+ input_dev->open = imx_keypad_open;
+ input_dev->close = imx_keypad_close;
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+ input_dev->keycode = keypad->keycodes;
+ input_dev->keycodesize = sizeof(keypad->keycodes[0]);
+ input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
+
+ matrix_keypad_build_keymap(keymap_data, MATRIX_ROW_SHIFT,
+ keypad->keycodes, input_dev->keybit);
+
+ input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+ input_set_drvdata(input_dev, keypad);
+
+ /* Ensure that the keypad will stay dormant until opened */
+ imx_keypad_inhibit(keypad);
+
+ error = request_irq(irq, imx_keypad_irq_handler, IRQF_DISABLED,
+ pdev->name, keypad);
+ if (error) {
+ dev_err(&pdev->dev, "failed to request IRQ\n");
+ goto failed_clock_put;
+ }
+
+ /* Register the input device */
+ error = input_register_device(input_dev);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register input device\n");
+ goto failed_free_irq;
+ }
+
+ platform_set_drvdata(pdev, keypad);
+ device_init_wakeup(&pdev->dev, 1);
+
+ return 0;
+
+failed_free_irq:
+ free_irq(irq, pdev);
+failed_clock_put:
+ clk_put(keypad->clk);
+failed_unmap:
+ iounmap(keypad->mmio_base);
+failed_free_priv:
+ kfree(keypad);
+failed_free_input:
+ input_free_device(input_dev);
+failed_rel_mem:
+ release_mem_region(res->start, resource_size(res));
+ return error;
+}
+
+static int __devexit imx_keypad_remove(struct platform_device *pdev)
+{
+ struct imx_keypad *keypad = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ dev_dbg(&pdev->dev, ">%s\n", __func__);
+
+ platform_set_drvdata(pdev, NULL);
+
+ input_unregister_device(keypad->input_dev);
+
+ free_irq(keypad->irq, keypad);
+ clk_put(keypad->clk);
+
+ iounmap(keypad->mmio_base);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(keypad);
+
+ return 0;
+}
+
+static struct platform_driver imx_keypad_driver = {
+ .driver = {
+ .name = "imx-keypad",
+ .owner = THIS_MODULE,
+ },
+ .probe = imx_keypad_probe,
+ .remove = __devexit_p(imx_keypad_remove),
+};
+
+static int __init imx_keypad_init(void)
+{
+ return platform_driver_register(&imx_keypad_driver);
+}
+
+static void __exit imx_keypad_exit(void)
+{
+ platform_driver_unregister(&imx_keypad_driver);
+}
+
+module_init(imx_keypad_init);
+module_exit(imx_keypad_exit);
+
+MODULE_AUTHOR("Alberto Panizzo <maramaopercheseimorto@gmail.com>");
+MODULE_DESCRIPTION("IMX Keypad Port Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-keypad");
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index 9caed30f3bbb..b1ab29861e1c 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -192,11 +192,18 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
{
struct locomokbd *locomokbd = dev_id;
+ u16 r;
+
+ r = locomo_readl(locomokbd->base + LOCOMO_KIC);
+ if ((r & 0x0001) == 0)
+ return IRQ_HANDLED;
+
+ locomo_writel(r & ~0x0100, locomokbd->base + LOCOMO_KIC); /* Ack */
+
/** wait chattering delay **/
udelay(100);
locomokbd_scankeyboard(locomokbd);
-
return IRQ_HANDLED;
}
@@ -210,6 +217,25 @@ static void locomokbd_timer_callback(unsigned long data)
locomokbd_scankeyboard(locomokbd);
}
+static int locomokbd_open(struct input_dev *dev)
+{
+ struct locomokbd *locomokbd = input_get_drvdata(dev);
+ u16 r;
+
+ r = locomo_readl(locomokbd->base + LOCOMO_KIC) | 0x0010;
+ locomo_writel(r, locomokbd->base + LOCOMO_KIC);
+ return 0;
+}
+
+static void locomokbd_close(struct input_dev *dev)
+{
+ struct locomokbd *locomokbd = input_get_drvdata(dev);
+ u16 r;
+
+ r = locomo_readl(locomokbd->base + LOCOMO_KIC) & ~0x0010;
+ locomo_writel(r, locomokbd->base + LOCOMO_KIC);
+}
+
static int __devinit locomokbd_probe(struct locomo_dev *dev)
{
struct locomokbd *locomokbd;
@@ -253,6 +279,8 @@ static int __devinit locomokbd_probe(struct locomo_dev *dev)
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
+ input_dev->open = locomokbd_open;
+ input_dev->close = locomokbd_close;
input_dev->dev.parent = &dev->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
@@ -261,6 +289,8 @@ static int __devinit locomokbd_probe(struct locomo_dev *dev)
input_dev->keycodesize = sizeof(locomokbd_keycode[0]);
input_dev->keycodemax = ARRAY_SIZE(locomokbd_keycode);
+ input_set_drvdata(input_dev, locomokbd);
+
memcpy(locomokbd->keycode, locomokbd_keycode, sizeof(locomokbd->keycode));
for (i = 0; i < LOCOMOKBD_NUMKEYS; i++)
set_bit(locomokbd->keycode[i], input_dev->keybit);
diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c
index 191cc51d6cf8..31f30087b591 100644
--- a/drivers/input/keyboard/qt2160.c
+++ b/drivers/input/keyboard/qt2160.c
@@ -362,7 +362,7 @@ static int __devexit qt2160_remove(struct i2c_client *client)
return 0;
}
-static struct i2c_device_id qt2160_idtable[] = {
+static const struct i2c_device_id qt2160_idtable[] = {
{ "qt2160", 0, },
{ }
};
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c
index 8e9380bfed40..854e2035cd6e 100644
--- a/drivers/input/keyboard/sh_keysc.c
+++ b/drivers/input/keyboard/sh_keysc.c
@@ -19,101 +19,141 @@
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/input/sh_keysc.h>
+#include <linux/bitmap.h>
#include <linux/clk.h>
#include <linux/io.h>
-#define KYCR1_OFFS 0x00
-#define KYCR2_OFFS 0x04
-#define KYINDR_OFFS 0x08
-#define KYOUTDR_OFFS 0x0c
-
-#define KYCR2_IRQ_LEVEL 0x10
-#define KYCR2_IRQ_DISABLED 0x00
-
static const struct {
unsigned char kymd, keyout, keyin;
} sh_keysc_mode[] = {
[SH_KEYSC_MODE_1] = { 0, 6, 5 },
[SH_KEYSC_MODE_2] = { 1, 5, 6 },
[SH_KEYSC_MODE_3] = { 2, 4, 7 },
+ [SH_KEYSC_MODE_4] = { 3, 6, 6 },
+ [SH_KEYSC_MODE_5] = { 4, 6, 7 },
+ [SH_KEYSC_MODE_6] = { 5, 7, 7 },
};
struct sh_keysc_priv {
void __iomem *iomem_base;
struct clk *clk;
- unsigned long last_keys;
+ DECLARE_BITMAP(last_keys, SH_KEYSC_MAXKEYS);
struct input_dev *input;
struct sh_keysc_info pdata;
};
+#define KYCR1 0
+#define KYCR2 1
+#define KYINDR 2
+#define KYOUTDR 3
+
+#define KYCR2_IRQ_LEVEL 0x10
+#define KYCR2_IRQ_DISABLED 0x00
+
+static unsigned long sh_keysc_read(struct sh_keysc_priv *p, int reg_nr)
+{
+ return ioread16(p->iomem_base + (reg_nr << 2));
+}
+
+static void sh_keysc_write(struct sh_keysc_priv *p, int reg_nr,
+ unsigned long value)
+{
+ iowrite16(value, p->iomem_base + (reg_nr << 2));
+}
+
+static void sh_keysc_level_mode(struct sh_keysc_priv *p,
+ unsigned long keys_set)
+{
+ struct sh_keysc_info *pdata = &p->pdata;
+
+ sh_keysc_write(p, KYOUTDR, 0);
+ sh_keysc_write(p, KYCR2, KYCR2_IRQ_LEVEL | (keys_set << 8));
+
+ if (pdata->kycr2_delay)
+ udelay(pdata->kycr2_delay);
+}
+
+static void sh_keysc_map_dbg(struct device *dev, unsigned long *map,
+ const char *str)
+{
+ int k;
+
+ for (k = 0; k < BITS_TO_LONGS(SH_KEYSC_MAXKEYS); k++)
+ dev_dbg(dev, "%s[%d] 0x%lx\n", str, k, map[k]);
+}
+
static irqreturn_t sh_keysc_isr(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
struct sh_keysc_info *pdata = &priv->pdata;
- unsigned long keys, keys1, keys0, mask;
+ int keyout_nr = sh_keysc_mode[pdata->mode].keyout;
+ int keyin_nr = sh_keysc_mode[pdata->mode].keyin;
+ DECLARE_BITMAP(keys, SH_KEYSC_MAXKEYS);
+ DECLARE_BITMAP(keys0, SH_KEYSC_MAXKEYS);
+ DECLARE_BITMAP(keys1, SH_KEYSC_MAXKEYS);
unsigned char keyin_set, tmp;
- int i, k;
+ int i, k, n;
dev_dbg(&pdev->dev, "isr!\n");
- keys1 = ~0;
- keys0 = 0;
+ bitmap_fill(keys1, SH_KEYSC_MAXKEYS);
+ bitmap_zero(keys0, SH_KEYSC_MAXKEYS);
do {
- keys = 0;
+ bitmap_zero(keys, SH_KEYSC_MAXKEYS);
keyin_set = 0;
- iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS);
+ sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED);
+
+ for (i = 0; i < keyout_nr; i++) {
+ n = keyin_nr * i;
- for (i = 0; i < sh_keysc_mode[pdata->mode].keyout; i++) {
- iowrite16(0xfff ^ (3 << (i * 2)),
- priv->iomem_base + KYOUTDR_OFFS);
+ /* drive one KEYOUT pin low, read KEYIN pins */
+ sh_keysc_write(priv, KYOUTDR, 0xffff ^ (3 << (i * 2)));
udelay(pdata->delay);
- tmp = ioread16(priv->iomem_base + KYINDR_OFFS);
- keys |= tmp << (sh_keysc_mode[pdata->mode].keyin * i);
- tmp ^= (1 << sh_keysc_mode[pdata->mode].keyin) - 1;
- keyin_set |= tmp;
- }
+ tmp = sh_keysc_read(priv, KYINDR);
- iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
- iowrite16(KYCR2_IRQ_LEVEL | (keyin_set << 8),
- priv->iomem_base + KYCR2_OFFS);
+ /* set bit if key press has been detected */
+ for (k = 0; k < keyin_nr; k++) {
+ if (tmp & (1 << k))
+ __set_bit(n + k, keys);
+ }
- if (pdata->kycr2_delay)
- udelay(pdata->kycr2_delay);
+ /* keep track of which KEYIN bits that have been set */
+ keyin_set |= tmp ^ ((1 << keyin_nr) - 1);
+ }
- keys ^= ~0;
- keys &= (1 << (sh_keysc_mode[pdata->mode].keyin *
- sh_keysc_mode[pdata->mode].keyout)) - 1;
- keys1 &= keys;
- keys0 |= keys;
+ sh_keysc_level_mode(priv, keyin_set);
- dev_dbg(&pdev->dev, "keys 0x%08lx\n", keys);
+ bitmap_complement(keys, keys, SH_KEYSC_MAXKEYS);
+ bitmap_and(keys1, keys1, keys, SH_KEYSC_MAXKEYS);
+ bitmap_or(keys0, keys0, keys, SH_KEYSC_MAXKEYS);
- } while (ioread16(priv->iomem_base + KYCR2_OFFS) & 0x01);
+ sh_keysc_map_dbg(&pdev->dev, keys, "keys");
- dev_dbg(&pdev->dev, "last_keys 0x%08lx keys0 0x%08lx keys1 0x%08lx\n",
- priv->last_keys, keys0, keys1);
+ } while (sh_keysc_read(priv, KYCR2) & 0x01);
+
+ sh_keysc_map_dbg(&pdev->dev, priv->last_keys, "last_keys");
+ sh_keysc_map_dbg(&pdev->dev, keys0, "keys0");
+ sh_keysc_map_dbg(&pdev->dev, keys1, "keys1");
for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
k = pdata->keycodes[i];
if (!k)
continue;
- mask = 1 << i;
-
- if (!((priv->last_keys ^ keys0) & mask))
+ if (test_bit(i, keys0) == test_bit(i, priv->last_keys))
continue;
- if ((keys1 | keys0) & mask) {
+ if (test_bit(i, keys1) || test_bit(i, keys0)) {
input_event(priv->input, EV_KEY, k, 1);
- priv->last_keys |= mask;
+ __set_bit(i, priv->last_keys);
}
- if (!(keys1 & mask)) {
+ if (!test_bit(i, keys1)) {
input_event(priv->input, EV_KEY, k, 0);
- priv->last_keys &= ~mask;
+ __clear_bit(i, priv->last_keys);
}
}
@@ -122,8 +162,6 @@ static irqreturn_t sh_keysc_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-#define res_size(res) ((res)->end - (res)->start + 1)
-
static int __devinit sh_keysc_probe(struct platform_device *pdev)
{
struct sh_keysc_priv *priv;
@@ -164,7 +202,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
memcpy(&priv->pdata, pdev->dev.platform_data, sizeof(priv->pdata));
pdata = &priv->pdata;
- priv->iomem_base = ioremap_nocache(res->start, res_size(res));
+ priv->iomem_base = ioremap_nocache(res->start, resource_size(res));
if (priv->iomem_base == NULL) {
dev_err(&pdev->dev, "failed to remap I/O memory\n");
error = -ENXIO;
@@ -220,10 +258,9 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
clk_enable(priv->clk);
- iowrite16((sh_keysc_mode[pdata->mode].kymd << 8) |
- pdata->scan_timing, priv->iomem_base + KYCR1_OFFS);
- iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
- iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS);
+ sh_keysc_write(priv, KYCR1, (sh_keysc_mode[pdata->mode].kymd << 8) |
+ pdata->scan_timing);
+ sh_keysc_level_mode(priv, 0);
device_init_wakeup(&pdev->dev, 1);
@@ -248,7 +285,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
{
struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
- iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS);
+ sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED);
input_unregister_device(priv->input);
free_irq(platform_get_irq(pdev, 0), pdev);
@@ -270,7 +307,7 @@ static int sh_keysc_suspend(struct device *dev)
int irq = platform_get_irq(pdev, 0);
unsigned short value;
- value = ioread16(priv->iomem_base + KYCR1_OFFS);
+ value = sh_keysc_read(priv, KYCR1);
if (device_may_wakeup(dev)) {
value |= 0x80;
@@ -279,7 +316,7 @@ static int sh_keysc_suspend(struct device *dev)
value &= ~0x80;
}
- iowrite16(value, priv->iomem_base + KYCR1_OFFS);
+ sh_keysc_write(priv, KYCR1, value);
return 0;
}
diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c
new file mode 100644
index 000000000000..69a48e8701b9
--- /dev/null
+++ b/drivers/input/misc/88pm860x_onkey.c
@@ -0,0 +1,155 @@
+/*
+ * 88pm860x_onkey.c - Marvell 88PM860x ONKEY driver
+ *
+ * Copyright (C) 2009-2010 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/88pm860x.h>
+
+#define PM8607_WAKEUP 0x0b
+
+#define LONG_ONKEY_EN (1 << 1)
+#define ONKEY_STATUS (1 << 0)
+
+struct pm860x_onkey_info {
+ struct input_dev *idev;
+ struct pm860x_chip *chip;
+ struct i2c_client *i2c;
+ struct device *dev;
+ int irq;
+};
+
+/* 88PM860x gives us an interrupt when ONKEY is held */
+static irqreturn_t pm860x_onkey_handler(int irq, void *data)
+{
+ struct pm860x_onkey_info *info = data;
+ int ret;
+
+ ret = pm860x_reg_read(info->i2c, PM8607_STATUS_2);
+ ret &= ONKEY_STATUS;
+ input_report_key(info->idev, KEY_POWER, ret);
+ input_sync(info->idev);
+
+ /* Enable 8-second long onkey detection */
+ pm860x_set_bits(info->i2c, PM8607_WAKEUP, 3, LONG_ONKEY_EN);
+ return IRQ_HANDLED;
+}
+
+static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
+{
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm860x_onkey_info *info;
+ int irq, ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No IRQ resource!\n");
+ return -EINVAL;
+ }
+
+ info = kzalloc(sizeof(struct pm860x_onkey_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->chip = chip;
+ info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
+ info->dev = &pdev->dev;
+ info->irq = irq + chip->irq_base;
+
+ info->idev = input_allocate_device();
+ if (!info->idev) {
+ dev_err(chip->dev, "Failed to allocate input dev\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ info->idev->name = "88pm860x_on";
+ info->idev->phys = "88pm860x_on/input0";
+ info->idev->id.bustype = BUS_I2C;
+ info->idev->dev.parent = &pdev->dev;
+ info->irq = irq;
+ info->idev->evbit[0] = BIT_MASK(EV_KEY);
+ info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+
+ ret = input_register_device(info->idev);
+ if (ret) {
+ dev_err(chip->dev, "Can't register input device: %d\n", ret);
+ goto out_reg;
+ }
+
+ ret = request_threaded_irq(info->irq, NULL, pm860x_onkey_handler,
+ IRQF_ONESHOT, "onkey", info);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+ info->irq, ret);
+ goto out_irq;
+ }
+
+ platform_set_drvdata(pdev, info);
+ return 0;
+
+out_irq:
+ input_unregister_device(info->idev);
+ kfree(info);
+ return ret;
+
+out_reg:
+ input_free_device(info->idev);
+out:
+ kfree(info);
+ return ret;
+}
+
+static int __devexit pm860x_onkey_remove(struct platform_device *pdev)
+{
+ struct pm860x_onkey_info *info = platform_get_drvdata(pdev);
+
+ free_irq(info->irq, info);
+ input_unregister_device(info->idev);
+ kfree(info);
+ return 0;
+}
+
+static struct platform_driver pm860x_onkey_driver = {
+ .driver = {
+ .name = "88pm860x-onkey",
+ .owner = THIS_MODULE,
+ },
+ .probe = pm860x_onkey_probe,
+ .remove = __devexit_p(pm860x_onkey_remove),
+};
+
+static int __init pm860x_onkey_init(void)
+{
+ return platform_driver_register(&pm860x_onkey_driver);
+}
+module_init(pm860x_onkey_init);
+
+static void __exit pm860x_onkey_exit(void)
+{
+ platform_driver_unregister(&pm860x_onkey_driver);
+}
+module_exit(pm860x_onkey_exit);
+
+MODULE_DESCRIPTION("Marvell 88PM860x ONKEY driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 16ec5233441c..23140a3bb8e0 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -12,6 +12,16 @@ menuconfig INPUT_MISC
if INPUT_MISC
+config INPUT_88PM860X_ONKEY
+ tristate "88PM860x ONKEY support"
+ depends on MFD_88PM860X
+ help
+ Support the ONKEY of Marvell 88PM860x PMICs as an input device
+ reporting power button status.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 88pm860x_onkey.
+
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
@@ -204,6 +214,17 @@ config INPUT_TWL4030_PWRBUTTON
To compile this driver as a module, choose M here. The module will
be called twl4030_pwrbutton.
+config INPUT_TWL4030_VIBRA
+ tristate "Support for TWL4030 Vibrator"
+ depends on TWL4030_CORE
+ select TWL4030_CODEC
+ select INPUT_FF_MEMLESS
+ help
+ This option enables support for TWL4030 Vibrator Driver.
+
+ To compile this driver as a module, choose M here. The module will
+ be called twl4030_vibra.
+
config INPUT_UINPUT
tristate "User level driver support"
help
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index a8b84854fb7b..7e95a5d474dc 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -4,6 +4,7 @@
# Each configuration option enables a list of files.
+obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o
obj-$(CONFIG_INPUT_APANEL) += apanel.o
obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
+obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_WINBOND_CIR) += winbond-cir.o
obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c
index 71b82434264d..a8d2b8db4e35 100644
--- a/drivers/input/misc/apanel.c
+++ b/drivers/input/misc/apanel.c
@@ -149,7 +149,7 @@ static void apanel_shutdown(struct i2c_client *client)
apanel_remove(client);
}
-static struct i2c_device_id apanel_id[] = {
+static const struct i2c_device_id apanel_id[] = {
{ "fujitsu_apanel", 0 },
{ }
};
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index 0501f0e65157..15be5430bc6d 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -474,10 +474,11 @@ static void ati_remote2_complete_key(struct urb *urb)
}
static int ati_remote2_getkeycode(struct input_dev *idev,
- int scancode, int *keycode)
+ unsigned int scancode, unsigned int *keycode)
{
struct ati_remote2 *ar2 = input_get_drvdata(idev);
- int index, mode;
+ unsigned int mode;
+ int index;
mode = scancode >> 8;
if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask))
@@ -491,10 +492,12 @@ static int ati_remote2_getkeycode(struct input_dev *idev,
return 0;
}
-static int ati_remote2_setkeycode(struct input_dev *idev, int scancode, int keycode)
+static int ati_remote2_setkeycode(struct input_dev *idev,
+ unsigned int scancode, unsigned int keycode)
{
struct ati_remote2 *ar2 = input_get_drvdata(idev);
- int index, mode, old_keycode;
+ unsigned int mode, old_keycode;
+ int index;
mode = scancode >> 8;
if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask))
@@ -504,9 +507,6 @@ static int ati_remote2_setkeycode(struct input_dev *idev, int scancode, int keyc
if (index < 0)
return -EINVAL;
- if (keycode < KEY_RESERVED || keycode > KEY_MAX)
- return -EINVAL;
-
old_keycode = ar2->keycode[mode][index];
ar2->keycode[mode][index] = keycode;
__set_bit(keycode, idev->keybit);
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index 1b871917340a..dfaa9a045ed8 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -47,7 +47,7 @@ static acpi_status acpi_atlas_button_setup(acpi_handle region_handle,
static acpi_status acpi_atlas_button_handler(u32 function,
acpi_physical_address address,
- u32 bit_width, acpi_integer *value,
+ u32 bit_width, u64 *value,
void *handler_context, void *region_context)
{
acpi_status status;
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index 3b9f588fc747..4ae07935985e 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -152,6 +152,13 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
goto exit_unregister_input;
}
+ err = gpio_direction_input(pdata->gpio_a);
+ if (err) {
+ dev_err(&pdev->dev, "unable to set GPIO %d for input\n",
+ pdata->gpio_a);
+ goto exit_unregister_input;
+ }
+
err = gpio_request(pdata->gpio_b, DRV_NAME);
if (err) {
dev_err(&pdev->dev, "unable to request GPIO %d\n",
@@ -159,6 +166,13 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
goto exit_free_gpio_a;
}
+ err = gpio_direction_input(pdata->gpio_b);
+ if (err) {
+ dev_err(&pdev->dev, "unable to set GPIO %d for input\n",
+ pdata->gpio_b);
+ goto exit_free_gpio_a;
+ }
+
/* request the IRQs */
err = request_irq(encoder->irq_a, &rotary_encoder_irq,
IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
new file mode 100644
index 000000000000..2fb79e064da3
--- /dev/null
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -0,0 +1,297 @@
+/*
+ * twl4030-vibra.c - TWL4030 Vibrator driver
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ *
+ * Written by Henrik Saari <henrik.saari@nokia.com>
+ * Updates by Felipe Balbi <felipe.balbi@nokia.com>
+ * Input by Jari Vanhala <ext-jari.vanhala@nokia.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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/i2c/twl.h>
+#include <linux/mfd/twl4030-codec.h>
+#include <linux/input.h>
+
+/* MODULE ID2 */
+#define LEDEN 0x00
+
+/* ForceFeedback */
+#define EFFECT_DIR_180_DEG 0x8000 /* range is 0 - 0xFFFF */
+
+struct vibra_info {
+ struct device *dev;
+ struct input_dev *input_dev;
+
+ struct workqueue_struct *workqueue;
+ struct work_struct play_work;
+
+ bool enabled;
+ int speed;
+ int direction;
+
+ bool coexist;
+};
+
+static void vibra_disable_leds(void)
+{
+ u8 reg;
+
+ /* Disable LEDA & LEDB, cannot be used with vibra (PWM) */
+ twl_i2c_read_u8(TWL4030_MODULE_LED, &reg, LEDEN);
+ reg &= ~0x03;
+ twl_i2c_write_u8(TWL4030_MODULE_LED, LEDEN, reg);
+}
+
+/* Powers H-Bridge and enables audio clk */
+static void vibra_enable(struct vibra_info *info)
+{
+ u8 reg;
+
+ twl4030_codec_enable_resource(TWL4030_CODEC_RES_POWER);
+
+ /* turn H-Bridge on */
+ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
+ &reg, TWL4030_REG_VIBRA_CTL);
+ twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+ (reg | TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL);
+
+ twl4030_codec_enable_resource(TWL4030_CODEC_RES_APLL);
+
+ info->enabled = true;
+}
+
+static void vibra_disable(struct vibra_info *info)
+{
+ u8 reg;
+
+ /* Power down H-Bridge */
+ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
+ &reg, TWL4030_REG_VIBRA_CTL);
+ twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+ (reg & ~TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL);
+
+ twl4030_codec_disable_resource(TWL4030_CODEC_RES_POWER);
+ twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL);
+
+ info->enabled = false;
+}
+
+static void vibra_play_work(struct work_struct *work)
+{
+ struct vibra_info *info = container_of(work,
+ struct vibra_info, play_work);
+ int dir;
+ int pwm;
+ u8 reg;
+
+ dir = info->direction;
+ pwm = info->speed;
+
+ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
+ &reg, TWL4030_REG_VIBRA_CTL);
+ if (pwm && (!info->coexist || !(reg & TWL4030_VIBRA_SEL))) {
+
+ if (!info->enabled)
+ vibra_enable(info);
+
+ /* set vibra rotation direction */
+ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
+ &reg, TWL4030_REG_VIBRA_CTL);
+ reg = (dir) ? (reg | TWL4030_VIBRA_DIR) :
+ (reg & ~TWL4030_VIBRA_DIR);
+ twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+ reg, TWL4030_REG_VIBRA_CTL);
+
+ /* set PWM, 1 = max, 255 = min */
+ twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+ 256 - pwm, TWL4030_REG_VIBRA_SET);
+ } else {
+ if (info->enabled)
+ vibra_disable(info);
+ }
+}
+
+/*** Input/ForceFeedback ***/
+
+static int vibra_play(struct input_dev *input, void *data,
+ struct ff_effect *effect)
+{
+ struct vibra_info *info = input_get_drvdata(input);
+
+ info->speed = effect->u.rumble.strong_magnitude >> 8;
+ if (!info->speed)
+ info->speed = effect->u.rumble.weak_magnitude >> 9;
+ info->direction = effect->direction < EFFECT_DIR_180_DEG ? 0 : 1;
+ queue_work(info->workqueue, &info->play_work);
+ return 0;
+}
+
+static int twl4030_vibra_open(struct input_dev *input)
+{
+ struct vibra_info *info = input_get_drvdata(input);
+
+ info->workqueue = create_singlethread_workqueue("vibra");
+ if (info->workqueue == NULL) {
+ dev_err(&input->dev, "couldn't create workqueue\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void twl4030_vibra_close(struct input_dev *input)
+{
+ struct vibra_info *info = input_get_drvdata(input);
+
+ cancel_work_sync(&info->play_work);
+ INIT_WORK(&info->play_work, vibra_play_work); /* cleanup */
+ destroy_workqueue(info->workqueue);
+ info->workqueue = NULL;
+
+ if (info->enabled)
+ vibra_disable(info);
+}
+
+/*** Module ***/
+#if CONFIG_PM
+static int twl4030_vibra_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct vibra_info *info = platform_get_drvdata(pdev);
+
+ if (info->enabled)
+ vibra_disable(info);
+
+ return 0;
+}
+
+static int twl4030_vibra_resume(struct device *dev)
+{
+ vibra_disable_leds();
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
+ twl4030_vibra_suspend, twl4030_vibra_resume);
+#endif
+
+static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
+{
+ struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data;
+ struct vibra_info *info;
+ int ret;
+
+ if (!pdata) {
+ dev_dbg(&pdev->dev, "platform_data not available\n");
+ return -EINVAL;
+ }
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->dev = &pdev->dev;
+ info->coexist = pdata->coexist;
+ INIT_WORK(&info->play_work, vibra_play_work);
+
+ info->input_dev = input_allocate_device();
+ if (info->input_dev == NULL) {
+ dev_err(&pdev->dev, "couldn't allocate input device\n");
+ ret = -ENOMEM;
+ goto err_kzalloc;
+ }
+
+ input_set_drvdata(info->input_dev, info);
+
+ info->input_dev->name = "twl4030:vibrator";
+ info->input_dev->id.version = 1;
+ info->input_dev->dev.parent = pdev->dev.parent;
+ info->input_dev->open = twl4030_vibra_open;
+ info->input_dev->close = twl4030_vibra_close;
+ __set_bit(FF_RUMBLE, info->input_dev->ffbit);
+
+ ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
+ if (ret < 0) {
+ dev_dbg(&pdev->dev, "couldn't register vibrator to FF\n");
+ goto err_ialloc;
+ }
+
+ ret = input_register_device(info->input_dev);
+ if (ret < 0) {
+ dev_dbg(&pdev->dev, "couldn't register input device\n");
+ goto err_iff;
+ }
+
+ vibra_disable_leds();
+
+ platform_set_drvdata(pdev, info);
+ return 0;
+
+err_iff:
+ input_ff_destroy(info->input_dev);
+err_ialloc:
+ input_free_device(info->input_dev);
+err_kzalloc:
+ kfree(info);
+ return ret;
+}
+
+static int __devexit twl4030_vibra_remove(struct platform_device *pdev)
+{
+ struct vibra_info *info = platform_get_drvdata(pdev);
+
+ /* this also free ff-memless and calls close if needed */
+ input_unregister_device(info->input_dev);
+ kfree(info);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver twl4030_vibra_driver = {
+ .probe = twl4030_vibra_probe,
+ .remove = __devexit_p(twl4030_vibra_remove),
+ .driver = {
+ .name = "twl4030_codec_vibra",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &twl4030_vibra_pm_ops,
+#endif
+ },
+};
+
+static int __init twl4030_vibra_init(void)
+{
+ return platform_driver_register(&twl4030_vibra_driver);
+}
+module_init(twl4030_vibra_init);
+
+static void __exit twl4030_vibra_exit(void)
+{
+ platform_driver_unregister(&twl4030_vibra_driver);
+}
+module_exit(twl4030_vibra_exit);
+
+MODULE_ALIAS("platform:twl4030_codec_vibra");
+
+MODULE_DESCRIPTION("TWL4030 Vibra driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nokia Corporation");
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index d3f57245420a..1477466076ad 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -34,7 +34,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uinput.h>
@@ -284,7 +283,6 @@ static int uinput_open(struct inode *inode, struct file *file)
if (!newdev)
return -ENOMEM;
- lock_kernel();
mutex_init(&newdev->mutex);
spin_lock_init(&newdev->requests_lock);
init_waitqueue_head(&newdev->requests_waitq);
@@ -292,7 +290,7 @@ static int uinput_open(struct inode *inode, struct file *file)
newdev->state = UIST_NEW_DEVICE;
file->private_data = newdev;
- unlock_kernel();
+ nonseekable_open(inode, file);
return 0;
}
diff --git a/drivers/input/misc/winbond-cir.c b/drivers/input/misc/winbond-cir.c
index 33309fe44e20..9c155a43abc2 100644
--- a/drivers/input/misc/winbond-cir.c
+++ b/drivers/input/misc/winbond-cir.c
@@ -385,26 +385,24 @@ wbcir_do_getkeycode(struct wbcir_data *data, u32 scancode)
}
static int
-wbcir_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+wbcir_getkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int *keycode)
{
struct wbcir_data *data = input_get_drvdata(dev);
- *keycode = (int)wbcir_do_getkeycode(data, (u32)scancode);
+ *keycode = wbcir_do_getkeycode(data, scancode);
return 0;
}
static int
-wbcir_setkeycode(struct input_dev *dev, int sscancode, int keycode)
+wbcir_setkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int keycode)
{
struct wbcir_data *data = input_get_drvdata(dev);
struct wbcir_keyentry *keyentry;
struct wbcir_keyentry *new_keyentry;
unsigned long flags;
unsigned int old_keycode = KEY_RESERVED;
- u32 scancode = (u32)sscancode;
-
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
new_keyentry = kmalloc(sizeof(*new_keyentry), GFP_KERNEL);
if (!new_keyentry)
@@ -538,6 +536,7 @@ wbcir_reset_irdata(struct wbcir_data *data)
data->irdata_count = 0;
data->irdata_off = 0;
data->irdata_error = 0;
+ data->idle_count = 0;
}
/* Adds one bit of irdata */
@@ -768,7 +767,7 @@ wbcir_parse_rc6(struct device *dev, struct wbcir_data *data)
return;
}
- dev_info(dev, "IR-RC6 ad 0x%02X cm 0x%02X cu 0x%04X "
+ dev_dbg(dev, "IR-RC6 ad 0x%02X cm 0x%02X cu 0x%04X "
"toggle %u mode %u scan 0x%08X\n",
address,
command,
@@ -1006,7 +1005,6 @@ wbcir_irq_handler(int irqno, void *cookie)
}
wbcir_reset_irdata(data);
- data->idle_count = 0;
}
out:
@@ -1018,7 +1016,7 @@ out:
/*****************************************************************************
*
- * SUSPEND/RESUME FUNCTIONS
+ * SETUP/INIT/SUSPEND/RESUME FUNCTIONS
*
*****************************************************************************/
@@ -1197,7 +1195,16 @@ finish:
}
/* Disable interrupts */
+ wbcir_select_bank(data, WBCIR_BANK_0);
outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
+
+ /*
+ * ACPI will set the HW disable bit for SP3 which means that the
+ * output signals are left in an undefined state which may cause
+ * spurious interrupts which we need to ignore until the hardware
+ * is reinitialized.
+ */
+ disable_irq(data->irq);
}
static int
@@ -1207,37 +1214,15 @@ wbcir_suspend(struct pnp_dev *device, pm_message_t state)
return 0;
}
-static int
-wbcir_resume(struct pnp_dev *device)
-{
- struct wbcir_data *data = pnp_get_drvdata(device);
-
- /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */
- wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
-
- /* Clear CEIR_EN */
- wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01);
-
- /* Enable interrupts */
- wbcir_reset_irdata(data);
- outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
-
- return 0;
-}
-
-
-
-/*****************************************************************************
- *
- * SETUP/INIT FUNCTIONS
- *
- *****************************************************************************/
-
static void
-wbcir_cfg_ceir(struct wbcir_data *data)
+wbcir_init_hw(struct wbcir_data *data)
{
u8 tmp;
+ /* Disable interrupts */
+ wbcir_select_bank(data, WBCIR_BANK_0);
+ outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
+
/* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */
tmp = protocol << 4;
if (invert)
@@ -1264,6 +1249,93 @@ wbcir_cfg_ceir(struct wbcir_data *data)
* set SP3_IRRX_SW to binary 01, helpfully not documented
*/
outb(0x10, data->ebase + WBCIR_REG_ECEIR_CTS);
+
+ /* Enable extended mode */
+ wbcir_select_bank(data, WBCIR_BANK_2);
+ outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1);
+
+ /*
+ * Configure baud generator, IR data will be sampled at
+ * a bitrate of: (24Mhz * prescaler) / (divisor * 16).
+ *
+ * The ECIR registers include a flag to change the
+ * 24Mhz clock freq to 48Mhz.
+ *
+ * It's not documented in the specs, but fifo levels
+ * other than 16 seems to be unsupported.
+ */
+
+ /* prescaler 1.0, tx/rx fifo lvl 16 */
+ outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2);
+
+ /* Set baud divisor to generate one byte per bit/cell */
+ switch (protocol) {
+ case IR_PROTOCOL_RC5:
+ outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL);
+ break;
+ case IR_PROTOCOL_RC6:
+ outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL);
+ break;
+ case IR_PROTOCOL_NEC:
+ outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL);
+ break;
+ }
+ outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
+
+ /* Set CEIR mode */
+ wbcir_select_bank(data, WBCIR_BANK_0);
+ outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR);
+ inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */
+ inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */
+
+ /* Disable RX demod, run-length encoding/decoding, set freq span */
+ wbcir_select_bank(data, WBCIR_BANK_7);
+ outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG);
+
+ /* Disable timer */
+ wbcir_select_bank(data, WBCIR_BANK_4);
+ outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1);
+
+ /* Enable MSR interrupt, Clear AUX_IRX */
+ wbcir_select_bank(data, WBCIR_BANK_5);
+ outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2);
+
+ /* Disable CRC */
+ wbcir_select_bank(data, WBCIR_BANK_6);
+ outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3);
+
+ /* Set RX/TX (de)modulation freq, not really used */
+ wbcir_select_bank(data, WBCIR_BANK_7);
+ outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC);
+ outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC);
+
+ /* Set invert and pin direction */
+ if (invert)
+ outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4);
+ else
+ outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4);
+
+ /* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */
+ wbcir_select_bank(data, WBCIR_BANK_0);
+ outb(0x97, data->sbase + WBCIR_REG_SP3_FCR);
+
+ /* Clear AUX status bits */
+ outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR);
+
+ /* Enable interrupts */
+ wbcir_reset_irdata(data);
+ outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
+}
+
+static int
+wbcir_resume(struct pnp_dev *device)
+{
+ struct wbcir_data *data = pnp_get_drvdata(device);
+
+ wbcir_init_hw(data);
+ enable_irq(data->irq);
+
+ return 0;
}
static int __devinit
@@ -1393,86 +1465,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
device_init_wakeup(&device->dev, 1);
- wbcir_cfg_ceir(data);
-
- /* Disable interrupts */
- wbcir_select_bank(data, WBCIR_BANK_0);
- outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
-
- /* Enable extended mode */
- wbcir_select_bank(data, WBCIR_BANK_2);
- outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1);
-
- /*
- * Configure baud generator, IR data will be sampled at
- * a bitrate of: (24Mhz * prescaler) / (divisor * 16).
- *
- * The ECIR registers include a flag to change the
- * 24Mhz clock freq to 48Mhz.
- *
- * It's not documented in the specs, but fifo levels
- * other than 16 seems to be unsupported.
- */
-
- /* prescaler 1.0, tx/rx fifo lvl 16 */
- outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2);
-
- /* Set baud divisor to generate one byte per bit/cell */
- switch (protocol) {
- case IR_PROTOCOL_RC5:
- outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL);
- break;
- case IR_PROTOCOL_RC6:
- outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL);
- break;
- case IR_PROTOCOL_NEC:
- outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL);
- break;
- }
- outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
-
- /* Set CEIR mode */
- wbcir_select_bank(data, WBCIR_BANK_0);
- outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR);
- inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */
- inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */
-
- /* Disable RX demod, run-length encoding/decoding, set freq span */
- wbcir_select_bank(data, WBCIR_BANK_7);
- outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG);
-
- /* Disable timer */
- wbcir_select_bank(data, WBCIR_BANK_4);
- outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1);
-
- /* Enable MSR interrupt, Clear AUX_IRX */
- wbcir_select_bank(data, WBCIR_BANK_5);
- outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2);
-
- /* Disable CRC */
- wbcir_select_bank(data, WBCIR_BANK_6);
- outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3);
-
- /* Set RX/TX (de)modulation freq, not really used */
- wbcir_select_bank(data, WBCIR_BANK_7);
- outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC);
- outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC);
-
- /* Set invert and pin direction */
- if (invert)
- outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4);
- else
- outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4);
-
- /* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */
- wbcir_select_bank(data, WBCIR_BANK_0);
- outb(0x97, data->sbase + WBCIR_REG_SP3_FCR);
-
- /* Clear AUX status bits */
- outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR);
-
- /* Enable interrupts */
- outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
+ wbcir_init_hw(data);
return 0;
diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c
index ba4f5dd7c60e..1e54bce72db5 100644
--- a/drivers/input/misc/wm831x-on.c
+++ b/drivers/input/misc/wm831x-on.c
@@ -97,8 +97,9 @@ static int __devinit wm831x_on_probe(struct platform_device *pdev)
wm831x_on->dev->phys = "wm831x_on/input0";
wm831x_on->dev->dev.parent = &pdev->dev;
- ret = wm831x_request_irq(wm831x, irq, wm831x_on_irq,
- IRQF_TRIGGER_RISING, "wm831x_on", wm831x_on);
+ ret = request_threaded_irq(irq, NULL, wm831x_on_irq,
+ IRQF_TRIGGER_RISING, "wm831x_on",
+ wm831x_on);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to request IRQ: %d\n", ret);
goto err_input_dev;
@@ -114,7 +115,7 @@ static int __devinit wm831x_on_probe(struct platform_device *pdev)
return 0;
err_irq:
- wm831x_free_irq(wm831x, irq, NULL);
+ free_irq(irq, wm831x_on);
err_input_dev:
input_free_device(wm831x_on->dev);
err:
@@ -127,7 +128,7 @@ static int __devexit wm831x_on_remove(struct platform_device *pdev)
struct wm831x_on *wm831x_on = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0);
- wm831x_free_irq(wm831x_on->wm831x, irq, wm831x_on);
+ free_irq(irq, wm831x_on);
cancel_delayed_work_sync(&wm831x_on->work);
input_unregister_device(wm831x_on->dev);
kfree(wm831x_on);
diff --git a/drivers/input/misc/yealink.h b/drivers/input/misc/yealink.h
index 48af0be9cbdf..1e0f52397010 100644
--- a/drivers/input/misc/yealink.h
+++ b/drivers/input/misc/yealink.h
@@ -127,7 +127,7 @@ struct yld_ctl_packet {
* yld_status struct.
*/
-/* LCD, each segment must be driven seperately.
+/* LCD, each segment must be driven separately.
*
* Layout:
*
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index f93c2c0daf1f..7490f1da4a53 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -63,6 +63,8 @@ static const struct alps_model_info alps_model_data[] = {
{ { 0x62, 0x02, 0x14 }, 0xcf, 0xcf,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
{ { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
+ { { 0x52, 0x01, 0x14 }, 0xff, 0xff,
+ ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
};
/*
@@ -118,40 +120,27 @@ static void alps_report_buttons(struct psmouse *psmouse,
struct input_dev *dev1, struct input_dev *dev2,
int left, int right, int middle)
{
- struct alps_data *priv = psmouse->private;
- const struct alps_model_info *model = priv->i;
-
- if (model->flags & ALPS_PS2_INTERLEAVED) {
- struct input_dev *dev;
+ struct input_dev *dev;
- /*
- * If shared button has already been reported on the
- * other device (dev2) then this event should be also
- * sent through that device.
- */
- dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1;
- input_report_key(dev, BTN_LEFT, left);
+ /*
+ * If shared button has already been reported on the
+ * other device (dev2) then this event should be also
+ * sent through that device.
+ */
+ dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1;
+ input_report_key(dev, BTN_LEFT, left);
- dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1;
- input_report_key(dev, BTN_RIGHT, right);
+ dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1;
+ input_report_key(dev, BTN_RIGHT, right);
- dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1;
- input_report_key(dev, BTN_MIDDLE, middle);
+ dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1;
+ input_report_key(dev, BTN_MIDDLE, middle);
- /*
- * Sync the _other_ device now, we'll do the first
- * device later once we report the rest of the events.
- */
- input_sync(dev2);
- } else {
- /*
- * For devices with non-interleaved packets we know what
- * device buttons belong to so we can simply report them.
- */
- input_report_key(dev1, BTN_LEFT, left);
- input_report_key(dev1, BTN_RIGHT, right);
- input_report_key(dev1, BTN_MIDDLE, middle);
- }
+ /*
+ * Sync the _other_ device now, we'll do the first
+ * device later once we report the rest of the events.
+ */
+ input_sync(dev2);
}
static void alps_process_packet(struct psmouse *psmouse)
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 908b5b44052f..53ec7ddd1826 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -205,8 +205,8 @@ struct atp {
bool overflow_warned;
int x_old; /* last reported x/y, */
int y_old; /* used for smoothing */
- signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS];
- signed char xy_old[ATP_XSENSORS + ATP_YSENSORS];
+ u8 xy_cur[ATP_XSENSORS + ATP_YSENSORS];
+ u8 xy_old[ATP_XSENSORS + ATP_YSENSORS];
int xy_acc[ATP_XSENSORS + ATP_YSENSORS];
int idlecount; /* number of empty packets */
struct work_struct work;
@@ -531,7 +531,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
/* accumulate the change */
- signed char change = dev->xy_old[i] - dev->xy_cur[i];
+ int change = dev->xy_old[i] - dev->xy_cur[i];
dev->xy_acc[i] -= change;
/* prevent down drifting */
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 0d1d33468b43..4f8fe0886b2a 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -139,6 +139,7 @@ struct tp_finger {
/* trackpad finger data size, empirically at least ten fingers */
#define SIZEOF_FINGER sizeof(struct tp_finger)
#define SIZEOF_ALL_FINGERS (16 * SIZEOF_FINGER)
+#define MAX_FINGER_ORIENTATION 16384
/* device-specific parameters */
struct bcm5974_param {
@@ -284,6 +285,26 @@ static void setup_events_to_report(struct input_dev *input_dev,
input_set_abs_params(input_dev, ABS_Y,
0, cfg->y.dim, cfg->y.fuzz, 0);
+ /* finger touch area */
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+ cfg->w.devmin, cfg->w.devmax, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
+ cfg->w.devmin, cfg->w.devmax, 0, 0);
+ /* finger approach area */
+ input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR,
+ cfg->w.devmin, cfg->w.devmax, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR,
+ cfg->w.devmin, cfg->w.devmax, 0, 0);
+ /* finger orientation */
+ input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
+ -MAX_FINGER_ORIENTATION,
+ MAX_FINGER_ORIENTATION, 0, 0);
+ /* finger position */
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ cfg->x.devmin, cfg->x.devmax, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ cfg->y.devmin, cfg->y.devmax, 0, 0);
+
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
@@ -310,13 +331,29 @@ static int report_bt_state(struct bcm5974 *dev, int size)
return 0;
}
+static void report_finger_data(struct input_dev *input,
+ const struct bcm5974_config *cfg,
+ const struct tp_finger *f)
+{
+ input_report_abs(input, ABS_MT_TOUCH_MAJOR, raw2int(f->force_major));
+ input_report_abs(input, ABS_MT_TOUCH_MINOR, raw2int(f->force_minor));
+ input_report_abs(input, ABS_MT_WIDTH_MAJOR, raw2int(f->size_major));
+ input_report_abs(input, ABS_MT_WIDTH_MINOR, raw2int(f->size_minor));
+ input_report_abs(input, ABS_MT_ORIENTATION,
+ MAX_FINGER_ORIENTATION - raw2int(f->orientation));
+ input_report_abs(input, ABS_MT_POSITION_X, raw2int(f->abs_x));
+ input_report_abs(input, ABS_MT_POSITION_Y,
+ cfg->y.devmin + cfg->y.devmax - raw2int(f->abs_y));
+ input_mt_sync(input);
+}
+
/* report trackpad data as logical trackpad state */
static int report_tp_state(struct bcm5974 *dev, int size)
{
const struct bcm5974_config *c = &dev->cfg;
const struct tp_finger *f;
struct input_dev *input = dev->input;
- int raw_p, raw_w, raw_x, raw_y, raw_n;
+ int raw_p, raw_w, raw_x, raw_y, raw_n, i;
int ptest, origin, ibt = 0, nmin = 0, nmax = 0;
int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
@@ -329,6 +366,11 @@ static int report_tp_state(struct bcm5974 *dev, int size)
/* always track the first finger; when detached, start over */
if (raw_n) {
+
+ /* report raw trackpad data */
+ for (i = 0; i < raw_n; i++)
+ report_finger_data(input, c, &f[i]);
+
raw_p = raw2int(f->force_major);
raw_w = raw2int(f->size_major);
raw_x = raw2int(f->abs_x);
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index 90be30e93556..9169d1591c1f 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -68,10 +68,6 @@ module_param(post_interrupt_delay, int, 0644);
MODULE_PARM_DESC(post_interrupt_delay,
"delay (ms) before recal after recal interrupt detected");
-static int autorecal = 1;
-module_param(autorecal, int, 0644);
-MODULE_PARM_DESC(autorecal, "enable recalibration in the driver");
-
/*
* When the touchpad gets ultra-sensitive, one can keep their finger 1/2"
* above the pad and still have it send packets. This causes a jump cursor
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 6d7aa10d10f0..7c1d7d420ae3 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -53,6 +53,12 @@ static const struct dmi_system_id __initconst lifebook_dmi_table[] = {
{
/* LifeBook B */
.matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Lifebook B Series"),
+ },
+ },
+ {
+ /* LifeBook B */
+ .matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B Series"),
},
},
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 401ac6b6edd4..d8c0c8d6992c 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -627,8 +627,15 @@ static int psmouse_extensions(struct psmouse *psmouse,
synaptics_hardware = true;
if (max_proto > PSMOUSE_IMEX) {
- if (!set_properties || synaptics_init(psmouse) == 0)
+/*
+ * Try activating protocol, but check if support is enabled first, since
+ * we try detecting Synaptics even when protocol is disabled.
+ */
+ if (synaptics_supported() &&
+ (!set_properties || synaptics_init(psmouse) == 0)) {
return PSMOUSE_SYNAPTICS;
+ }
+
/*
* Some Synaptics touchpads can emulate extended protocols (like IMPS/2).
* Unfortunately Logitech/Genius probes confuse some firmware versions so
@@ -683,19 +690,6 @@ static int psmouse_extensions(struct psmouse *psmouse,
max_proto = PSMOUSE_IMEX;
}
-/*
- * Try Finger Sensing Pad
- */
- if (max_proto > PSMOUSE_IMEX) {
- if (fsp_detect(psmouse, set_properties) == 0) {
- if (!set_properties || fsp_init(psmouse) == 0)
- return PSMOUSE_FSP;
-/*
- * Init failed, try basic relative protocols
- */
- max_proto = PSMOUSE_IMEX;
- }
- }
if (max_proto > PSMOUSE_IMEX) {
if (genius_detect(psmouse, set_properties) == 0)
@@ -712,6 +706,21 @@ static int psmouse_extensions(struct psmouse *psmouse,
}
/*
+ * Try Finger Sensing Pad. We do it here because its probe upsets
+ * Trackpoint devices (causing TP_READ_ID command to time out).
+ */
+ if (max_proto > PSMOUSE_IMEX) {
+ if (fsp_detect(psmouse, set_properties) == 0) {
+ if (!set_properties || fsp_init(psmouse) == 0)
+ return PSMOUSE_FSP;
+/*
+ * Init failed, try basic relative protocols
+ */
+ max_proto = PSMOUSE_IMEX;
+ }
+ }
+
+/*
* Reset to defaults in case the device got confused by extended
* protocol probes. Note that we follow up with full reset because
* some mice put themselves to sleep when they see PSMOUSE_RESET_DIS.
@@ -1132,7 +1141,14 @@ static void psmouse_cleanup(struct serio *serio)
psmouse_deactivate(parent);
}
- psmouse_deactivate(psmouse);
+ psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
+
+ /*
+ * Disable stream mode so cleanup routine can proceed undisturbed.
+ */
+ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
+ printk(KERN_WARNING "psmouse.c: Failed to disable mouse on %s\n",
+ psmouse->ps2dev.serio->phys);
if (psmouse->cleanup)
psmouse->cleanup(psmouse);
@@ -1450,24 +1466,10 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *de
struct serio *serio = to_serio_port(dev);
struct psmouse_attribute *attr = to_psmouse_attr(devattr);
struct psmouse *psmouse;
- int retval;
-
- retval = serio_pin_driver(serio);
- if (retval)
- return retval;
-
- if (serio->drv != &psmouse_drv) {
- retval = -ENODEV;
- goto out;
- }
psmouse = serio_get_drvdata(serio);
- retval = attr->show(psmouse, attr->data, buf);
-
-out:
- serio_unpin_driver(serio);
- return retval;
+ return attr->show(psmouse, attr->data, buf);
}
ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *devattr,
@@ -1478,18 +1480,9 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev
struct psmouse *psmouse, *parent = NULL;
int retval;
- retval = serio_pin_driver(serio);
- if (retval)
- return retval;
-
- if (serio->drv != &psmouse_drv) {
- retval = -ENODEV;
- goto out_unpin;
- }
-
retval = mutex_lock_interruptible(&psmouse_mutex);
if (retval)
- goto out_unpin;
+ goto out;
psmouse = serio_get_drvdata(serio);
@@ -1519,8 +1512,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev
out_unlock:
mutex_unlock(&psmouse_mutex);
- out_unpin:
- serio_unpin_driver(serio);
+ out:
return retval;
}
@@ -1582,9 +1574,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
}
mutex_unlock(&psmouse_mutex);
- serio_unpin_driver(serio);
serio_unregister_child_port(serio);
- serio_pin_driver_uninterruptible(serio);
mutex_lock(&psmouse_mutex);
if (serio->drv != &psmouse_drv) {
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index 77b9fd0b3fbf..81a6b81cb2fe 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -2,7 +2,7 @@
* Finger Sensing Pad PS/2 mouse driver.
*
* Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
- * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation.
+ * Copyright (C) 2005-2010 Tai-hwa Liang, Sentelic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -658,9 +658,9 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
if (packet[3] & BIT(1))
button_status |= 0x0f; /* wheel up */
if (packet[3] & BIT(2))
- button_status |= BIT(5);/* horizontal left */
+ button_status |= BIT(4);/* horizontal left */
if (packet[3] & BIT(3))
- button_status |= BIT(4);/* horizontal right */
+ button_status |= BIT(5);/* horizontal right */
/* push back to packet queue */
if (button_status != 0)
packet[3] = button_status;
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 05689e732191..d3f5243fa093 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -743,6 +743,11 @@ int synaptics_init(struct psmouse *psmouse)
return -1;
}
+bool synaptics_supported(void)
+{
+ return true;
+}
+
#else /* CONFIG_MOUSE_PS2_SYNAPTICS */
void __init synaptics_module_init(void)
@@ -754,5 +759,10 @@ int synaptics_init(struct psmouse *psmouse)
return -ENOSYS;
}
+bool synaptics_supported(void)
+{
+ return false;
+}
+
#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 838e7f2c9b30..f0f40a331dc8 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -109,5 +109,6 @@ void synaptics_module_init(void);
int synaptics_detect(struct psmouse *psmouse, bool set_properties);
int synaptics_init(struct psmouse *psmouse);
void synaptics_reset(struct psmouse *psmouse);
+bool synaptics_supported(void);
#endif /* _SYNAPTICS_H */
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index a13d80f7da17..f34b22bce4ff 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -15,7 +15,6 @@
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -542,10 +541,8 @@ static int mousedev_open(struct inode *inode, struct file *file)
if (i >= MOUSEDEV_MINORS)
return -ENODEV;
- lock_kernel();
error = mutex_lock_interruptible(&mousedev_table_mutex);
if (error) {
- unlock_kernel();
return error;
}
mousedev = mousedev_table[i];
@@ -554,7 +551,6 @@ static int mousedev_open(struct inode *inode, struct file *file)
mutex_unlock(&mousedev_table_mutex);
if (!mousedev) {
- unlock_kernel();
return -ENODEV;
}
@@ -575,7 +571,6 @@ static int mousedev_open(struct inode *inode, struct file *file)
goto err_free_client;
file->private_data = client;
- unlock_kernel();
return 0;
err_free_client:
@@ -583,7 +578,6 @@ static int mousedev_open(struct inode *inode, struct file *file)
kfree(client);
err_put_mousedev:
put_device(&mousedev->dev);
- unlock_kernel();
return error;
}
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 64b688daf48a..ead0494721d0 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -442,6 +442,13 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
},
},
{
+ /* Medion Akoya E1222 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "E122X"),
+ },
+ },
+ {
/* Mivvy M310 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "VIOOO"),
@@ -524,6 +531,13 @@ static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = {
*/
static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = {
{
+ /* Acer Aspire 5610 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
+ },
+ },
+ {
/* Acer Aspire 5630 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -617,6 +631,9 @@ static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id *
strlcat(i8042_pnp_kbd_name, pnp_dev_name(dev), sizeof(i8042_pnp_kbd_name));
}
+ /* Keyboard ports are always supposed to be wakeup-enabled */
+ device_set_wakeup_enable(&dev->dev, true);
+
i8042_pnp_kbd_devices++;
return 0;
}
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index d84a36e545f6..9302ba0e48f8 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -430,7 +430,7 @@ static bool i8042_filter(unsigned char data, unsigned char str,
}
if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) {
- dbg("Filtered out by platfrom filter\n");
+ dbg("Filtered out by platform filter\n");
return true;
}
@@ -1161,9 +1161,17 @@ static int i8042_pm_restore(struct device *dev)
return 0;
}
+static int i8042_pm_thaw(struct device *dev)
+{
+ i8042_interrupt(0, NULL);
+
+ return 0;
+}
+
static const struct dev_pm_ops i8042_pm_ops = {
.suspend = i8042_pm_reset,
.resume = i8042_pm_restore,
+ .thaw = i8042_pm_thaw,
.poweroff = i8042_pm_reset,
.restore = i8042_pm_restore,
};
@@ -1378,6 +1386,8 @@ static int __init i8042_probe(struct platform_device *dev)
{
int error;
+ i8042_platform_device = dev;
+
error = i8042_controller_selftest();
if (error)
return error;
@@ -1413,6 +1423,7 @@ static int __init i8042_probe(struct platform_device *dev)
i8042_free_aux_ports(); /* in case KBD failed but AUX not */
i8042_free_irqs();
i8042_controller_reset();
+ i8042_platform_device = NULL;
return error;
}
@@ -1422,6 +1433,7 @@ static int __devexit i8042_remove(struct platform_device *dev)
i8042_unregister_ports();
i8042_free_irqs();
i8042_controller_reset();
+ i8042_platform_device = NULL;
return 0;
}
@@ -1440,6 +1452,7 @@ static struct platform_driver i8042_driver = {
static int __init i8042_init(void)
{
+ struct platform_device *pdev;
int err;
dbg_init();
@@ -1452,31 +1465,18 @@ static int __init i8042_init(void)
if (err)
goto err_platform_exit;
- i8042_platform_device = platform_device_alloc("i8042", -1);
- if (!i8042_platform_device) {
- err = -ENOMEM;
+ pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0);
+ if (IS_ERR(pdev)) {
+ err = PTR_ERR(pdev);
goto err_platform_exit;
}
- err = platform_device_add(i8042_platform_device);
- if (err)
- goto err_free_device;
-
- err = platform_driver_probe(&i8042_driver, i8042_probe);
- if (err)
- goto err_del_device;
-
panic_blink = i8042_panic_blink;
return 0;
- err_del_device:
- platform_device_del(i8042_platform_device);
- err_free_device:
- platform_device_put(i8042_platform_device);
err_platform_exit:
i8042_platform_exit();
-
return err;
}
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
index 1dacbe0d9348..797314be7af2 100644
--- a/drivers/input/serio/pcips2.c
+++ b/drivers/input/serio/pcips2.c
@@ -186,7 +186,7 @@ static void __devexit pcips2_remove(struct pci_dev *dev)
pci_disable_device(dev);
}
-static struct pci_device_id pcips2_ids[] = {
+static const struct pci_device_id pcips2_ids[] = {
{
.vendor = 0x14f2, /* MOBILITY */
.device = 0x0123, /* Keyboard */
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index e0f30186d513..c3b626e9eae7 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -26,6 +26,8 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/serio.h>
@@ -119,11 +121,10 @@ static int serio_bind_driver(struct serio *serio, struct serio_driver *drv)
error = device_bind_driver(&serio->dev);
if (error) {
- printk(KERN_WARNING
- "serio: device_bind_driver() failed "
- "for %s (%s) and %s, error: %d\n",
- serio->phys, serio->name,
- drv->description, error);
+ dev_warn(&serio->dev,
+ "device_bind_driver() failed for %s (%s) and %s, error: %d\n",
+ serio->phys, serio->name,
+ drv->description, error);
serio_disconnect_driver(serio);
serio->dev.driver = NULL;
return error;
@@ -138,9 +139,9 @@ static void serio_find_driver(struct serio *serio)
error = device_attach(&serio->dev);
if (error < 0)
- printk(KERN_WARNING
- "serio: device_attach() failed for %s (%s), error: %d\n",
- serio->phys, serio->name, error);
+ dev_warn(&serio->dev,
+ "device_attach() failed for %s (%s), error: %d\n",
+ serio->phys, serio->name, error);
}
@@ -194,17 +195,14 @@ static int serio_queue_event(void *object, struct module *owner,
event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
if (!event) {
- printk(KERN_ERR
- "serio: Not enough memory to queue event %d\n",
- event_type);
+ pr_err("Not enough memory to queue event %d\n", event_type);
retval = -ENOMEM;
goto out;
}
if (!try_module_get(owner)) {
- printk(KERN_WARNING
- "serio: Can't get module reference, dropping event %d\n",
- event_type);
+ pr_warning("Can't get module reference, dropping event %d\n",
+ event_type);
kfree(event);
retval = -EINVAL;
goto out;
@@ -230,14 +228,12 @@ static void serio_free_event(struct serio_event *event)
static void serio_remove_duplicate_events(struct serio_event *event)
{
- struct list_head *node, *next;
- struct serio_event *e;
+ struct serio_event *e, *next;
unsigned long flags;
spin_lock_irqsave(&serio_event_lock, flags);
- list_for_each_safe(node, next, &serio_event_list) {
- e = list_entry(node, struct serio_event, node);
+ list_for_each_entry_safe(e, next, &serio_event_list, node) {
if (event->object == e->object) {
/*
* If this event is of different type we should not
@@ -247,7 +243,7 @@ static void serio_remove_duplicate_events(struct serio_event *event)
if (event->type != e->type)
break;
- list_del_init(node);
+ list_del_init(&e->node);
serio_free_event(e);
}
}
@@ -258,23 +254,18 @@ static void serio_remove_duplicate_events(struct serio_event *event)
static struct serio_event *serio_get_event(void)
{
- struct serio_event *event;
- struct list_head *node;
+ struct serio_event *event = NULL;
unsigned long flags;
spin_lock_irqsave(&serio_event_lock, flags);
- if (list_empty(&serio_event_list)) {
- spin_unlock_irqrestore(&serio_event_lock, flags);
- return NULL;
+ if (!list_empty(&serio_event_list)) {
+ event = list_first_entry(&serio_event_list,
+ struct serio_event, node);
+ list_del_init(&event->node);
}
- node = serio_event_list.next;
- event = list_entry(node, struct serio_event, node);
- list_del_init(node);
-
spin_unlock_irqrestore(&serio_event_lock, flags);
-
return event;
}
@@ -287,29 +278,27 @@ static void serio_handle_event(void)
while ((event = serio_get_event())) {
switch (event->type) {
- case SERIO_REGISTER_PORT:
- serio_add_port(event->object);
- break;
- case SERIO_RECONNECT_PORT:
- serio_reconnect_port(event->object);
- break;
+ case SERIO_REGISTER_PORT:
+ serio_add_port(event->object);
+ break;
- case SERIO_RESCAN_PORT:
- serio_disconnect_port(event->object);
- serio_find_driver(event->object);
- break;
+ case SERIO_RECONNECT_PORT:
+ serio_reconnect_port(event->object);
+ break;
- case SERIO_RECONNECT_CHAIN:
- serio_reconnect_chain(event->object);
- break;
+ case SERIO_RESCAN_PORT:
+ serio_disconnect_port(event->object);
+ serio_find_driver(event->object);
+ break;
- case SERIO_ATTACH_DRIVER:
- serio_attach_driver(event->object);
- break;
+ case SERIO_RECONNECT_CHAIN:
+ serio_reconnect_chain(event->object);
+ break;
- default:
- break;
+ case SERIO_ATTACH_DRIVER:
+ serio_attach_driver(event->object);
+ break;
}
serio_remove_duplicate_events(event);
@@ -325,16 +314,14 @@ static void serio_handle_event(void)
*/
static void serio_remove_pending_events(void *object)
{
- struct list_head *node, *next;
- struct serio_event *event;
+ struct serio_event *event, *next;
unsigned long flags;
spin_lock_irqsave(&serio_event_lock, flags);
- list_for_each_safe(node, next, &serio_event_list) {
- event = list_entry(node, struct serio_event, node);
+ list_for_each_entry_safe(event, next, &serio_event_list, node) {
if (event->object == object) {
- list_del_init(node);
+ list_del_init(&event->node);
serio_free_event(event);
}
}
@@ -380,7 +367,6 @@ static int serio_thread(void *nothing)
kthread_should_stop() || !list_empty(&serio_event_list));
} while (!kthread_should_stop());
- printk(KERN_DEBUG "serio: kseriod exiting\n");
return 0;
}
@@ -445,6 +431,11 @@ static struct attribute_group serio_id_attr_group = {
.attrs = serio_device_id_attrs,
};
+static const struct attribute_group *serio_device_attr_groups[] = {
+ &serio_id_attr_group,
+ NULL
+};
+
static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct serio *serio = to_serio_port(dev);
@@ -532,6 +523,7 @@ static void serio_init_port(struct serio *serio)
(long)atomic_inc_return(&serio_no) - 1);
serio->dev.bus = &serio_bus;
serio->dev.release = serio_release_port;
+ serio->dev.groups = serio_device_attr_groups;
if (serio->parent) {
serio->dev.parent = &serio->parent->dev;
serio->depth = serio->parent->depth + 1;
@@ -555,21 +547,15 @@ static void serio_add_port(struct serio *serio)
}
list_add_tail(&serio->node, &serio_list);
+
if (serio->start)
serio->start(serio);
+
error = device_add(&serio->dev);
if (error)
- printk(KERN_ERR
- "serio: device_add() failed for %s (%s), error: %d\n",
+ dev_err(&serio->dev,
+ "device_add() failed for %s (%s), error: %d\n",
serio->phys, serio->name, error);
- else {
- serio->registered = true;
- error = sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
- if (error)
- printk(KERN_ERR
- "serio: sysfs_create_group() failed for %s (%s), error: %d\n",
- serio->phys, serio->name, error);
- }
}
/*
@@ -596,11 +582,8 @@ static void serio_destroy_port(struct serio *serio)
serio->parent = NULL;
}
- if (serio->registered) {
- sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group);
+ if (device_is_registered(&serio->dev))
device_del(&serio->dev);
- serio->registered = false;
- }
list_del_init(&serio->node);
serio_remove_pending_events(serio);
@@ -798,9 +781,8 @@ static void serio_attach_driver(struct serio_driver *drv)
error = driver_attach(&drv->driver);
if (error)
- printk(KERN_WARNING
- "serio: driver_attach() failed for %s with error %d\n",
- drv->driver.name, error);
+ pr_warning("driver_attach() failed for %s with error %d\n",
+ drv->driver.name, error);
}
int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name)
@@ -820,8 +802,7 @@ int __serio_register_driver(struct serio_driver *drv, struct module *owner, cons
error = driver_register(&drv->driver);
if (error) {
- printk(KERN_ERR
- "serio: driver_register() failed for %s, error: %d\n",
+ pr_err("driver_register() failed for %s, error: %d\n",
drv->driver.name, error);
return error;
}
@@ -987,7 +968,7 @@ irqreturn_t serio_interrupt(struct serio *serio,
if (likely(serio->drv)) {
ret = serio->drv->interrupt(serio, data, dfl);
- } else if (!dfl && serio->registered) {
+ } else if (!dfl && device_is_registered(&serio->dev)) {
serio_rescan(serio);
ret = IRQ_HANDLED;
}
@@ -1018,7 +999,7 @@ static int __init serio_init(void)
error = bus_register(&serio_bus);
if (error) {
- printk(KERN_ERR "serio: failed to register serio bus, error: %d\n", error);
+ pr_err("Failed to register serio bus, error: %d\n", error);
return error;
}
@@ -1026,7 +1007,7 @@ static int __init serio_init(void)
if (IS_ERR(serio_task)) {
bus_unregister(&serio_bus);
error = PTR_ERR(serio_task);
- printk(KERN_ERR "serio: Failed to start kseriod, error: %d\n", error);
+ pr_err("Failed to start kseriod, error: %d\n", error);
return error;
}
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index 27fdaaffbb40..998664854440 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -81,12 +81,12 @@ static int serio_raw_open(struct inode *inode, struct file *file)
struct serio_raw_list *list;
int retval = 0;
- lock_kernel();
retval = mutex_lock_interruptible(&serio_raw_mutex);
if (retval)
- goto out_bkl;
+ return retval;
- if (!(serio_raw = serio_raw_locate(iminor(inode)))) {
+ serio_raw = serio_raw_locate(iminor(inode));
+ if (!serio_raw) {
retval = -ENODEV;
goto out;
}
@@ -96,7 +96,8 @@ static int serio_raw_open(struct inode *inode, struct file *file)
goto out;
}
- if (!(list = kzalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) {
+ list = kzalloc(sizeof(struct serio_raw_list), GFP_KERNEL);
+ if (!list) {
retval = -ENOMEM;
goto out;
}
@@ -109,8 +110,6 @@ static int serio_raw_open(struct inode *inode, struct file *file)
out:
mutex_unlock(&serio_raw_mutex);
-out_bkl:
- unlock_kernel();
return retval;
}
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c
index ebb22f88c842..8298e1f68234 100644
--- a/drivers/input/serio/xilinx_ps2.c
+++ b/drivers/input/serio/xilinx_ps2.c
@@ -270,7 +270,7 @@ static int __devinit xps2_of_probe(struct of_device *ofdev,
drvdata->irq = r_irq.start;
phys_addr = r_mem.start;
- remap_size = r_mem.end - r_mem.start + 1;
+ remap_size = resource_size(&r_mem);
if (!request_mem_region(phys_addr, remap_size, DRIVER_NAME)) {
dev_err(dev, "Couldn't lock memory region at 0x%08llX\n",
(unsigned long long)phys_addr);
@@ -344,7 +344,7 @@ static int __devexit xps2_of_remove(struct of_device *of_dev)
if (of_address_to_resource(of_dev->node, 0, &r_mem))
dev_err(dev, "invalid address\n");
else
- release_mem_region(r_mem.start, r_mem.end - r_mem.start + 1);
+ release_mem_region(r_mem.start, resource_size(&r_mem));
kfree(drvdata);
@@ -354,7 +354,7 @@ static int __devexit xps2_of_remove(struct of_device *of_dev)
}
/* Match table for of_platform binding */
-static struct of_device_id xps2_of_match[] __devinitdata = {
+static const struct of_device_id xps2_of_match[] __devinitconst = {
{ .compatible = "xlnx,xps-ps2-1.00.a", },
{ /* end of list */ },
};
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index fbd3987af57f..e6bde55e5203 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -64,7 +64,8 @@ struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
static int sparse_keymap_getkeycode(struct input_dev *dev,
- int scancode, int *keycode)
+ unsigned int scancode,
+ unsigned int *keycode)
{
const struct key_entry *key =
sparse_keymap_entry_from_scancode(dev, scancode);
@@ -78,7 +79,8 @@ static int sparse_keymap_getkeycode(struct input_dev *dev,
}
static int sparse_keymap_setkeycode(struct input_dev *dev,
- int scancode, int keycode)
+ unsigned int scancode,
+ unsigned int keycode)
{
struct key_entry *key;
int old_keycode;
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index 7d005a3616d7..4be039d7dcad 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -362,7 +362,7 @@ static const int macroKeyEvents[] = {
};
/***********************************************************************
- * Map values to strings and back. Every map shoudl have the following
+ * Map values to strings and back. Every map should have the following
* as its last element: { NULL, AIPTEK_INVALID_VALUE }.
*/
#define AIPTEK_INVALID_VALUE -1
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index 3d32d3f4e486..866a9ee1af1a 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -92,7 +92,7 @@ Scott Hill shill@gtcocalcomp.com
/* DATA STRUCTURES */
/* Device table */
-static struct usb_device_id gtco_usbid_table [] = {
+static const struct usb_device_id gtco_usbid_table[] = {
{ USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
{ USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
{ USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
index 16310f368dab..8fef1b689c69 100644
--- a/drivers/input/tablet/wacom.h
+++ b/drivers/input/tablet/wacom.h
@@ -85,6 +85,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/init.h>
#include <linux/usb/input.h>
#include <asm/unaligned.h>
@@ -120,6 +121,8 @@ struct wacom_combo {
struct urb *urb;
};
+extern const struct usb_device_id wacom_ids[];
+
extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo);
extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data);
extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data);
@@ -142,7 +145,5 @@ extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wa
extern void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern __u16 wacom_le16_to_cpu(unsigned char *data);
extern __u16 wacom_be16_to_cpu(unsigned char *data);
-extern struct wacom_features *get_wacom_feature(const struct usb_device_id *id);
-extern const struct usb_device_id *get_device_table(void);
#endif
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 072f33b3b2b0..8b5d2873f0c4 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -211,7 +211,8 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) |
BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS) |
BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_STYLUS2);
- input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
+ input_set_abs_params(input_dev, ABS_DISTANCE,
+ 0, wacom_wac->features.distance_max, 0, 0);
}
void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
@@ -261,7 +262,8 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_TOOL_BRUSH) |
BIT_MASK(BTN_TOOL_PENCIL) | BIT_MASK(BTN_TOOL_AIRBRUSH) |
BIT_MASK(BTN_TOOL_LENS) | BIT_MASK(BTN_STYLUS2);
- input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
+ input_set_abs_params(input_dev, ABS_DISTANCE,
+ 0, wacom_wac->features.distance_max, 0, 0);
input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
@@ -282,17 +284,19 @@ void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
- if (wacom_wac->features->device_type == BTN_TOOL_DOUBLETAP ||
- wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) {
- input_set_abs_params(input_dev, ABS_RX, 0, wacom_wac->features->x_phy, 0, 0);
- input_set_abs_params(input_dev, ABS_RY, 0, wacom_wac->features->y_phy, 0, 0);
- input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_DOUBLETAP);
+ struct wacom_features *features = &wacom_wac->features;
+
+ if (features->device_type == BTN_TOOL_DOUBLETAP ||
+ features->device_type == BTN_TOOL_TRIPLETAP) {
+ input_set_abs_params(input_dev, ABS_RX, 0, features->x_phy, 0, 0);
+ input_set_abs_params(input_dev, ABS_RY, 0, features->y_phy, 0, 0);
+ __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
}
}
void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
- if (wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) {
+ if (wacom_wac->features.device_type == BTN_TOOL_TRIPLETAP) {
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_TRIPLETAP);
input_dev->evbit[0] |= BIT_MASK(EV_MSC);
input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
@@ -367,7 +371,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
} else if (pen) {
/* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG)
- features->pktlen = WACOM_PKGLEN_PENABLED;
+ features->pktlen = WACOM_PKGLEN_GRAPHIRE;
features->device_type = BTN_TOOL_PEN;
features->x_max =
wacom_le16_to_cpu(&report[i + 3]);
@@ -406,7 +410,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
} else if (pen) {
/* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG)
- features->pktlen = WACOM_PKGLEN_PENABLED;
+ features->pktlen = WACOM_PKGLEN_GRAPHIRE;
features->device_type = BTN_TOOL_PEN;
features->y_max =
wacom_le16_to_cpu(&report[i + 3]);
@@ -532,21 +536,38 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
struct wacom_wac *wacom_wac;
struct wacom_features *features;
struct input_dev *input_dev;
- int error = -ENOMEM;
+ int error;
+
+ if (!id->driver_info)
+ return -EINVAL;
wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
input_dev = input_allocate_device();
- if (!wacom || !input_dev || !wacom_wac)
+ if (!wacom || !input_dev || !wacom_wac) {
+ error = -ENOMEM;
goto fail1;
+ }
- wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX, GFP_KERNEL, &wacom->data_dma);
- if (!wacom_wac->data)
+ wacom_wac->features = *((struct wacom_features *)id->driver_info);
+ features = &wacom_wac->features;
+ if (features->pktlen > WACOM_PKGLEN_MAX) {
+ error = -EINVAL;
goto fail1;
+ }
+
+ wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX,
+ GFP_KERNEL, &wacom->data_dma);
+ if (!wacom_wac->data) {
+ error = -ENOMEM;
+ goto fail1;
+ }
wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
- if (!wacom->irq)
+ if (!wacom->irq) {
+ error = -ENOMEM;
goto fail2;
+ }
wacom->usbdev = dev;
wacom->dev = input_dev;
@@ -555,11 +576,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
- wacom_wac->features = features = get_wacom_feature(id);
- BUG_ON(features->pktlen > WACOM_PKGLEN_MAX);
-
- input_dev->name = wacom_wac->features->name;
- wacom->wacom_wac = wacom_wac;
usb_to_input_id(dev, &input_dev->id);
input_dev->dev.parent = &intf->dev;
@@ -576,6 +592,19 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if (error)
goto fail2;
+ strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
+
+ if (features->type == TABLETPC || features->type == TABLETPC2FG) {
+ /* Append the device type to the name */
+ strlcat(wacom_wac->name,
+ features->device_type == BTN_TOOL_PEN ?
+ " Pen" : " Finger",
+ sizeof(wacom_wac->name));
+ }
+
+ input_dev->name = wacom_wac->name;
+ wacom->wacom_wac = wacom_wac;
+
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOUCH);
@@ -640,7 +669,7 @@ static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
static int wacom_resume(struct usb_interface *intf)
{
struct wacom *wacom = usb_get_intfdata(intf);
- struct wacom_features *features = wacom->wacom_wac->features;
+ struct wacom_features *features = &wacom->wacom_wac->features;
int rv;
mutex_lock(&wacom->lock);
@@ -663,6 +692,7 @@ static int wacom_reset_resume(struct usb_interface *intf)
static struct usb_driver wacom_driver = {
.name = "wacom",
+ .id_table = wacom_ids,
.probe = wacom_probe,
.disconnect = wacom_disconnect,
.suspend = wacom_suspend,
@@ -674,7 +704,7 @@ static struct usb_driver wacom_driver = {
static int __init wacom_init(void)
{
int result;
- wacom_driver.id_table = get_device_table();
+
result = usb_register(&wacom_driver);
if (result == 0)
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 1056f149fe31..b3ba3437a2eb 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -55,6 +55,7 @@ static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo)
static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
{
+ struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
int prox, pressure;
@@ -68,9 +69,9 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
if (prox) {
wacom->id[0] = ERASER_DEVICE_ID;
pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
- if (wacom->features->pressure_max > 255)
+ if (features->pressure_max > 255)
pressure = (pressure << 1) | ((data[4] >> 6) & 1);
- pressure += (wacom->features->pressure_max + 1) / 2;
+ pressure += (features->pressure_max + 1) / 2;
/*
* if going from out of proximity into proximity select between the eraser
@@ -152,20 +153,21 @@ static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo)
static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
{
+ struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
- int x, y, rw;
- static int penData = 0;
+ int x, y, prox;
+ int rw = 0;
+ int retval = 0;
if (data[0] != WACOM_REPORT_PENABLED) {
dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
- return 0;
+ goto exit;
}
- if (data[1] & 0x80) {
- /* in prox and not a pad data */
- penData = 1;
-
- switch ((data[1] >> 5) & 3) {
+ prox = data[1] & 0x80;
+ if (prox || wacom->id[0]) {
+ if (prox) {
+ switch ((data[1] >> 5) & 3) {
case 0: /* Pen */
wacom->tool[0] = BTN_TOOL_PEN;
@@ -179,25 +181,13 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
case 2: /* Mouse with wheel */
wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04);
- if (wacom->features->type == WACOM_G4 ||
- wacom->features->type == WACOM_MO) {
- rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
- wacom_report_rel(wcombo, REL_WHEEL, -rw);
- } else
- wacom_report_rel(wcombo, REL_WHEEL, -(signed char) data[6]);
/* fall through */
case 3: /* Mouse without wheel */
wacom->tool[0] = BTN_TOOL_MOUSE;
wacom->id[0] = CURSOR_DEVICE_ID;
- wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
- wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
- if (wacom->features->type == WACOM_G4 ||
- wacom->features->type == WACOM_MO)
- wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
- else
- wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
break;
+ }
}
x = wacom_le16_to_cpu(&data[2]);
y = wacom_le16_to_cpu(&data[4]);
@@ -208,36 +198,32 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01);
wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04);
- }
- wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */
- wacom_report_key(wcombo, wacom->tool[0], 1);
- } else if (wacom->id[0]) {
- wacom_report_abs(wcombo, ABS_X, 0);
- wacom_report_abs(wcombo, ABS_Y, 0);
- if (wacom->tool[0] == BTN_TOOL_MOUSE) {
- wacom_report_key(wcombo, BTN_LEFT, 0);
- wacom_report_key(wcombo, BTN_RIGHT, 0);
- wacom_report_abs(wcombo, ABS_DISTANCE, 0);
} else {
- wacom_report_abs(wcombo, ABS_PRESSURE, 0);
- wacom_report_key(wcombo, BTN_TOUCH, 0);
- wacom_report_key(wcombo, BTN_STYLUS, 0);
- wacom_report_key(wcombo, BTN_STYLUS2, 0);
+ wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
+ wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
+ if (features->type == WACOM_G4 ||
+ features->type == WACOM_MO) {
+ wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
+ rw = (signed)(data[7] & 0x04) - (data[7] & 0x03);
+ } else {
+ wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
+ rw = -(signed)data[6];
+ }
+ wacom_report_rel(wcombo, REL_WHEEL, rw);
}
- wacom->id[0] = 0;
- wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
- wacom_report_key(wcombo, wacom->tool[0], 0);
+
+ if (!prox)
+ wacom->id[0] = 0;
+ wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */
+ wacom_report_key(wcombo, wacom->tool[0], prox);
+ wacom_input_sync(wcombo); /* sync last event */
}
/* send pad data */
- switch (wacom->features->type) {
+ switch (features->type) {
case WACOM_G4:
- if (data[7] & 0xf8) {
- if (penData) {
- wacom_input_sync(wcombo); /* sync last event */
- if (!wacom->id[0])
- penData = 0;
- }
+ prox = data[7] & 0xf8;
+ if (prox || wacom->id[1]) {
wacom->id[1] = PAD_DEVICE_ID;
wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
@@ -245,29 +231,16 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
wacom_report_rel(wcombo, REL_WHEEL, rw);
wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0);
wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]);
- wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
- } else if (wacom->id[1]) {
- if (penData) {
- wacom_input_sync(wcombo); /* sync last event */
- if (!wacom->id[0])
- penData = 0;
- }
- wacom->id[1] = 0;
- wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
- wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
- wacom_report_rel(wcombo, REL_WHEEL, 0);
- wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
- wacom_report_abs(wcombo, ABS_MISC, 0);
+ if (!prox)
+ wacom->id[1] = 0;
+ wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]);
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
}
+ retval = 1;
break;
case WACOM_MO:
- if ((data[7] & 0xf8) || (data[8] & 0xff)) {
- if (penData) {
- wacom_input_sync(wcombo); /* sync last event */
- if (!wacom->id[0])
- penData = 0;
- }
+ prox = (data[7] & 0xf8) || data[8];
+ if (prox || wacom->id[1]) {
wacom->id[1] = PAD_DEVICE_ID;
wacom_report_key(wcombo, BTN_0, (data[7] & 0x08));
wacom_report_key(wcombo, BTN_1, (data[7] & 0x20));
@@ -275,36 +248,26 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
wacom_report_key(wcombo, BTN_5, (data[7] & 0x40));
wacom_report_abs(wcombo, ABS_WHEEL, (data[8] & 0x7f));
wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0);
+ if (!prox)
+ wacom->id[1] = 0;
wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]);
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
- } else if (wacom->id[1]) {
- if (penData) {
- wacom_input_sync(wcombo); /* sync last event */
- if (!wacom->id[0])
- penData = 0;
- }
- wacom->id[1] = 0;
- wacom_report_key(wcombo, BTN_0, (data[7] & 0x08));
- wacom_report_key(wcombo, BTN_1, (data[7] & 0x20));
- wacom_report_key(wcombo, BTN_4, (data[7] & 0x10));
- wacom_report_key(wcombo, BTN_5, (data[7] & 0x40));
- wacom_report_abs(wcombo, ABS_WHEEL, (data[8] & 0x7f));
- wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
- wacom_report_abs(wcombo, ABS_MISC, 0);
- wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
}
+ retval = 1;
break;
}
- return 1;
+exit:
+ return retval;
}
static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
{
+ struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
int idx = 0;
/* tool number */
- if (wacom->features->type == INTUOS)
+ if (features->type == INTUOS)
idx = data[1] & 0x01;
/* Enter report */
@@ -402,7 +365,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
wacom_report_key(wcombo, BTN_STYLUS2, 0);
wacom_report_key(wcombo, BTN_TOUCH, 0);
wacom_report_abs(wcombo, ABS_WHEEL, 0);
- if (wacom->features->type >= INTUOS3S)
+ if (features->type >= INTUOS3S)
wacom_report_abs(wcombo, ABS_Z, 0);
}
wacom_report_key(wcombo, wacom->tool[idx], 0);
@@ -416,13 +379,14 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
{
+ struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
unsigned int t;
/* general pen packet */
if ((data[1] & 0xb8) == 0xa0) {
t = (data[6] << 2) | ((data[7] >> 6) & 3);
- if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L)
+ if (features->type >= INTUOS4S && features->type <= INTUOS4L)
t = (t << 1) | (data[1] & 1);
wacom_report_abs(wcombo, ABS_PRESSURE, t);
wacom_report_abs(wcombo, ABS_TILT_X,
@@ -446,6 +410,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
{
+ struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
unsigned int t;
int idx = 0, result;
@@ -457,7 +422,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
}
/* tool number */
- if (wacom->features->type == INTUOS)
+ if (features->type == INTUOS)
idx = data[1] & 0x01;
/* pad packets. Works as a second tool and is always in prox */
@@ -466,7 +431,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
if (wacom->tool[1] != BTN_TOOL_FINGER)
wacom->tool[1] = BTN_TOOL_FINGER;
- if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) {
+ if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
wacom_report_key(wcombo, BTN_0, (data[2] & 0x01));
wacom_report_key(wcombo, BTN_1, (data[3] & 0x01));
wacom_report_key(wcombo, BTN_2, (data[3] & 0x02));
@@ -480,7 +445,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
/* Out of proximity, clear wheel value. */
wacom_report_abs(wcombo, ABS_WHEEL, 0);
}
- if (wacom->features->type != INTUOS4S) {
+ if (features->type != INTUOS4S) {
wacom_report_key(wcombo, BTN_7, (data[3] & 0x40));
wacom_report_key(wcombo, BTN_8, (data[3] & 0x80));
}
@@ -528,18 +493,20 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
return 0;
/* Only large Intuos support Lense Cursor */
- if ((wacom->tool[idx] == BTN_TOOL_LENS)
- && ((wacom->features->type == INTUOS3)
- || (wacom->features->type == INTUOS3S)
- || (wacom->features->type == INTUOS4)
- || (wacom->features->type == INTUOS4S)))
+ if (wacom->tool[idx] == BTN_TOOL_LENS &&
+ (features->type == INTUOS3 ||
+ features->type == INTUOS3S ||
+ features->type == INTUOS4 ||
+ features->type == INTUOS4S)) {
+
return 0;
+ }
/* Cintiq doesn't send data when RDY bit isn't set */
- if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
+ if (features->type == CINTIQ && !(data[1] & 0x40))
return 0;
- if (wacom->features->type >= INTUOS3S) {
+ if (features->type >= INTUOS3S) {
wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
@@ -557,7 +524,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
if (data[1] & 0x02) {
/* Rotation packet */
- if (wacom->features->type >= INTUOS3S) {
+ if (features->type >= INTUOS3S) {
/* I3 marker pen rotation */
t = (data[6] << 3) | ((data[7] >> 5) & 7);
t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
@@ -570,7 +537,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
((t - 1) / 2) : -t / 2);
}
- } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) {
+ } else if (!(data[1] & 0x10) && features->type < INTUOS3S) {
/* 4D mouse packet */
wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
@@ -583,7 +550,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
} else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
/* I4 mouse */
- if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) {
+ if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
wacom_report_key(wcombo, BTN_LEFT, data[6] & 0x01);
wacom_report_key(wcombo, BTN_MIDDLE, data[6] & 0x02);
wacom_report_key(wcombo, BTN_RIGHT, data[6] & 0x04);
@@ -604,13 +571,13 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
- ((data[8] & 0x02) >> 1));
/* I3 2D mouse side buttons */
- if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
+ if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40);
wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20);
}
}
- } else if ((wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L ||
- wacom->features->type == INTUOS4L) &&
+ } else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
+ features->type == INTUOS4L) &&
wacom->tool[idx] == BTN_TOOL_LENS) {
/* Lens cursor packets */
wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
@@ -631,9 +598,9 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
static void wacom_tpc_finger_in(struct wacom_wac *wacom, void *wcombo, char *data, int idx)
{
wacom_report_abs(wcombo, ABS_X,
- (data[2 + idx * 2] & 0xff) | ((data[3 + idx * 2] & 0x7f) << 8));
+ data[2 + idx * 2] | ((data[3 + idx * 2] & 0x7f) << 8));
wacom_report_abs(wcombo, ABS_Y,
- (data[6 + idx * 2] & 0xff) | ((data[7 + idx * 2] & 0x7f) << 8));
+ data[6 + idx * 2] | ((data[7 + idx * 2] & 0x7f) << 8));
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
wacom_report_key(wcombo, wacom->tool[idx], 1);
if (idx)
@@ -718,6 +685,7 @@ static void wacom_tpc_touch_in(struct wacom_wac *wacom, void *wcombo)
static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
{
+ struct wacom_features *features = &wacom->features;
char *data = wacom->data;
int prox = 0, pressure, idx = -1;
static int stylusInProx, touchInProx = 1, touchOut;
@@ -776,31 +744,24 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
touchInProx = 0;
- if (prox) { /* in prox */
- if (!wacom->id[0]) {
- /* Going into proximity select tool */
- wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
- if (wacom->tool[0] == BTN_TOOL_PEN)
- wacom->id[0] = STYLUS_DEVICE_ID;
- else
- wacom->id[0] = ERASER_DEVICE_ID;
- }
- wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
- wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10);
- wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2]));
- wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
- pressure = ((data[7] & 0x01) << 8) | data[6];
- if (pressure < 0)
- pressure = wacom->features->pressure_max + pressure + 1;
- wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
- wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x05);
- } else {
- wacom_report_abs(wcombo, ABS_X, 0);
- wacom_report_abs(wcombo, ABS_Y, 0);
- wacom_report_abs(wcombo, ABS_PRESSURE, 0);
- wacom_report_key(wcombo, BTN_STYLUS, 0);
- wacom_report_key(wcombo, BTN_STYLUS2, 0);
- wacom_report_key(wcombo, BTN_TOUCH, 0);
+ if (!wacom->id[0]) { /* first in prox */
+ /* Going into proximity select tool */
+ wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+ if (wacom->tool[0] == BTN_TOOL_PEN)
+ wacom->id[0] = STYLUS_DEVICE_ID;
+ else
+ wacom->id[0] = ERASER_DEVICE_ID;
+ }
+ wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
+ wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10);
+ wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2]));
+ wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
+ pressure = ((data[7] & 0x01) << 8) | data[6];
+ if (pressure < 0)
+ pressure = features->pressure_max + pressure + 1;
+ wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
+ wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x05);
+ if (!prox) { /* out-prox */
wacom->id[0] = 0;
/* pen is out so touch can be enabled now */
touchInProx = 1;
@@ -815,7 +776,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
{
- switch (wacom_wac->features->type) {
+ switch (wacom_wac->features.type) {
case PENPARTNER:
return wacom_penpartner_irq(wacom_wac, wcombo);
@@ -853,7 +814,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
- switch (wacom_wac->features->type) {
+ switch (wacom_wac->features.type) {
case WACOM_MO:
input_dev_mo(input_dev, wacom_wac);
case WACOM_G4:
@@ -888,7 +849,7 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
/* fall through */
case TABLETPC:
input_dev_tpc(input_dev, wacom_wac);
- if (wacom_wac->features->device_type != BTN_TOOL_PEN)
+ if (wacom_wac->features.device_type != BTN_TOOL_PEN)
break; /* no need to process stylus stuff */
/* fall through */
@@ -903,153 +864,201 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
return;
}
-static struct wacom_features wacom_features[] = {
- { "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, 0, PENPARTNER },
- { "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE },
- { "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE },
- { "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, 63, GRAPHIRE },
- { "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, GRAPHIRE },
- { "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE },
- { "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, WACOM_G4 },
- { "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, WACOM_G4 },
- { "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO },
- { "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, 63, WACOM_MO },
- { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE },
- { "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE },
- { "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, 63, GRAPHIRE },
- { "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE },
- { "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, 63, GRAPHIRE },
- { "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, 63, GRAPHIRE },
- { "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO },
- { "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE },
- { "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS },
- { "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS },
- { "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS },
- { "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS },
- { "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS },
- { "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, 0, PL },
- { "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, 0, PL },
- { "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, 0, PL },
- { "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, 0, PL },
- { "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, 0, PL },
- { "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, 0, PL },
- { "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, 0, PL },
- { "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL },
- { "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, 0, PL },
- { "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL },
- { "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL },
- { "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL },
- { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, 0, PTU },
- { "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS },
- { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS },
- { "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS },
- { "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS },
- { "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS },
- { "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, 63, INTUOS3S },
- { "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, 63, INTUOS3 },
- { "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, 63, INTUOS3 },
- { "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, 63, INTUOS3L },
- { "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, 63, INTUOS3L },
- { "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, 63, INTUOS3 },
- { "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, 63, INTUOS3S },
- { "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, 63, INTUOS4S },
- { "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, INTUOS4 },
- { "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, INTUOS4L },
- { "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, 63, INTUOS4L },
- { "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, 63, CINTIQ },
- { "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, 63, WACOM_BEE },
- { "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE },
- { "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL },
- { "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC },
- { "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC },
- { "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC },
- { "Wacom ISDv4 9F", WACOM_PKGLEN_PENABLED, 26202, 16325, 255, 0, TABLETPC },
- { "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG },
- { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG },
- { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS },
+static const struct wacom_features wacom_features_0x00 =
+ { "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, 0, PENPARTNER };
+static const struct wacom_features wacom_features_0x10 =
+ { "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x11 =
+ { "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x12 =
+ { "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x13 =
+ { "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x14 =
+ { "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x15 =
+ { "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, WACOM_G4 };
+static const struct wacom_features wacom_features_0x16 =
+ { "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, WACOM_G4 };
+static const struct wacom_features wacom_features_0x17 =
+ { "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO };
+static const struct wacom_features wacom_features_0x18 =
+ { "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, 63, WACOM_MO };
+static const struct wacom_features wacom_features_0x19 =
+ { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x60 =
+ { "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x61 =
+ { "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x62 =
+ { "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x63 =
+ { "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x64 =
+ { "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x65 =
+ { "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO };
+static const struct wacom_features wacom_features_0x69 =
+ { "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x20 =
+ { "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x21 =
+ { "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x22 =
+ { "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x23 =
+ { "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x24 =
+ { "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x30 =
+ { "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, 0, PL };
+static const struct wacom_features wacom_features_0x31 =
+ { "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, 0, PL };
+static const struct wacom_features wacom_features_0x32 =
+ { "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, 0, PL };
+static const struct wacom_features wacom_features_0x33 =
+ { "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, 0, PL };
+static const struct wacom_features wacom_features_0x34 =
+ { "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, 0, PL };
+static const struct wacom_features wacom_features_0x35 =
+ { "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, 0, PL };
+static const struct wacom_features wacom_features_0x37 =
+ { "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, 0, PL };
+static const struct wacom_features wacom_features_0x38 =
+ { "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL };
+static const struct wacom_features wacom_features_0x39 =
+ { "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, 0, PL };
+static const struct wacom_features wacom_features_0xC4 =
+ { "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL };
+static const struct wacom_features wacom_features_0xC0 =
+ { "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL };
+static const struct wacom_features wacom_features_0xC2 =
+ { "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL };
+static const struct wacom_features wacom_features_0x03 =
+ { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, 0, PTU };
+static const struct wacom_features wacom_features_0x41 =
+ { "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x42 =
+ { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x43 =
+ { "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x44 =
+ { "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x45 =
+ { "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0xB0 =
+ { "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, 63, INTUOS3S };
+static const struct wacom_features wacom_features_0xB1 =
+ { "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, 63, INTUOS3 };
+static const struct wacom_features wacom_features_0xB2 =
+ { "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, 63, INTUOS3 };
+static const struct wacom_features wacom_features_0xB3 =
+ { "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, 63, INTUOS3L };
+static const struct wacom_features wacom_features_0xB4 =
+ { "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, 63, INTUOS3L };
+static const struct wacom_features wacom_features_0xB5 =
+ { "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, 63, INTUOS3 };
+static const struct wacom_features wacom_features_0xB7 =
+ { "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, 63, INTUOS3S };
+static const struct wacom_features wacom_features_0xB8 =
+ { "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, 63, INTUOS4S };
+static const struct wacom_features wacom_features_0xB9 =
+ { "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, INTUOS4 };
+static const struct wacom_features wacom_features_0xBA =
+ { "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, INTUOS4L };
+static const struct wacom_features wacom_features_0xBB =
+ { "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, 63, INTUOS4L };
+static const struct wacom_features wacom_features_0x3F =
+ { "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, 63, CINTIQ };
+static const struct wacom_features wacom_features_0xC5 =
+ { "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, 63, WACOM_BEE };
+static const struct wacom_features wacom_features_0xC6 =
+ { "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE };
+static const struct wacom_features wacom_features_0xC7 =
+ { "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL };
+static const struct wacom_features wacom_features_0x90 =
+ { "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC };
+static const struct wacom_features wacom_features_0x93 =
+ { "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC };
+static const struct wacom_features wacom_features_0x9A =
+ { "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC };
+static const struct wacom_features wacom_features_0x9F =
+ { "Wacom ISDv4 9F", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC };
+static const struct wacom_features wacom_features_0xE2 =
+ { "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG };
+static const struct wacom_features wacom_features_0xE3 =
+ { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG };
+static const struct wacom_features wacom_features_0x47 =
+ { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS };
+
+#define USB_DEVICE_WACOM(prod) \
+ USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \
+ .driver_info = (kernel_ulong_t)&wacom_features_##prod
+
+const struct usb_device_id wacom_ids[] = {
+ { USB_DEVICE_WACOM(0x00) },
+ { USB_DEVICE_WACOM(0x10) },
+ { USB_DEVICE_WACOM(0x11) },
+ { USB_DEVICE_WACOM(0x12) },
+ { USB_DEVICE_WACOM(0x13) },
+ { USB_DEVICE_WACOM(0x14) },
+ { USB_DEVICE_WACOM(0x15) },
+ { USB_DEVICE_WACOM(0x16) },
+ { USB_DEVICE_WACOM(0x17) },
+ { USB_DEVICE_WACOM(0x18) },
+ { USB_DEVICE_WACOM(0x19) },
+ { USB_DEVICE_WACOM(0x60) },
+ { USB_DEVICE_WACOM(0x61) },
+ { USB_DEVICE_WACOM(0x62) },
+ { USB_DEVICE_WACOM(0x63) },
+ { USB_DEVICE_WACOM(0x64) },
+ { USB_DEVICE_WACOM(0x65) },
+ { USB_DEVICE_WACOM(0x69) },
+ { USB_DEVICE_WACOM(0x20) },
+ { USB_DEVICE_WACOM(0x21) },
+ { USB_DEVICE_WACOM(0x22) },
+ { USB_DEVICE_WACOM(0x23) },
+ { USB_DEVICE_WACOM(0x24) },
+ { USB_DEVICE_WACOM(0x30) },
+ { USB_DEVICE_WACOM(0x31) },
+ { USB_DEVICE_WACOM(0x32) },
+ { USB_DEVICE_WACOM(0x33) },
+ { USB_DEVICE_WACOM(0x34) },
+ { USB_DEVICE_WACOM(0x35) },
+ { USB_DEVICE_WACOM(0x37) },
+ { USB_DEVICE_WACOM(0x38) },
+ { USB_DEVICE_WACOM(0x39) },
+ { USB_DEVICE_WACOM(0xC4) },
+ { USB_DEVICE_WACOM(0xC0) },
+ { USB_DEVICE_WACOM(0xC2) },
+ { USB_DEVICE_WACOM(0x03) },
+ { USB_DEVICE_WACOM(0x41) },
+ { USB_DEVICE_WACOM(0x42) },
+ { USB_DEVICE_WACOM(0x43) },
+ { USB_DEVICE_WACOM(0x44) },
+ { USB_DEVICE_WACOM(0x45) },
+ { USB_DEVICE_WACOM(0xB0) },
+ { USB_DEVICE_WACOM(0xB1) },
+ { USB_DEVICE_WACOM(0xB2) },
+ { USB_DEVICE_WACOM(0xB3) },
+ { USB_DEVICE_WACOM(0xB4) },
+ { USB_DEVICE_WACOM(0xB5) },
+ { USB_DEVICE_WACOM(0xB7) },
+ { USB_DEVICE_WACOM(0xB8) },
+ { USB_DEVICE_WACOM(0xB9) },
+ { USB_DEVICE_WACOM(0xBA) },
+ { USB_DEVICE_WACOM(0xBB) },
+ { USB_DEVICE_WACOM(0x3F) },
+ { USB_DEVICE_WACOM(0xC5) },
+ { USB_DEVICE_WACOM(0xC6) },
+ { USB_DEVICE_WACOM(0xC7) },
+ { USB_DEVICE_WACOM(0x90) },
+ { USB_DEVICE_WACOM(0x93) },
+ { USB_DEVICE_WACOM(0x9A) },
+ { USB_DEVICE_WACOM(0x9F) },
+ { USB_DEVICE_WACOM(0xE2) },
+ { USB_DEVICE_WACOM(0xE3) },
+ { USB_DEVICE_WACOM(0x47) },
{ }
};
-
-static struct usb_device_id wacom_ids[] = {
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x17) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x18) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x19) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x65) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x69) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC4) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC2) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB8) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB9) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBA) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBB) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC5) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC6) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC7) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x90) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x93) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9A) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9F) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE2) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE3) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
- { }
-};
-
-const struct usb_device_id *get_device_table(void)
-{
- const struct usb_device_id *id_table = wacom_ids;
-
- return id_table;
-}
-
-struct wacom_features * get_wacom_feature(const struct usb_device_id *id)
-{
- int index = id - wacom_ids;
- struct wacom_features *wf = &wacom_features[index];
-
- return wf;
-}
-
MODULE_DEVICE_TABLE(usb, wacom_ids);
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index ee01e1902785..b50cf04e61a8 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -15,11 +15,10 @@
/* packet length for individual models */
#define WACOM_PKGLEN_PENPRTN 7
#define WACOM_PKGLEN_GRAPHIRE 8
-#define WACOM_PKGLEN_BBFUN 9
-#define WACOM_PKGLEN_INTUOS 10
-#define WACOM_PKGLEN_PENABLED 8
+#define WACOM_PKGLEN_BBFUN 9
+#define WACOM_PKGLEN_INTUOS 10
#define WACOM_PKGLEN_TPC1FG 5
-#define WACOM_PKGLEN_TPC2FG 14
+#define WACOM_PKGLEN_TPC2FG 14
/* device IDs */
#define STYLUS_DEVICE_ID 0x02
@@ -58,7 +57,7 @@ enum {
};
struct wacom_features {
- char *name;
+ const char *name;
int pktlen;
int x_max;
int y_max;
@@ -73,11 +72,12 @@ struct wacom_features {
};
struct wacom_wac {
+ char name[64];
unsigned char *data;
- int tool[2];
- int id[2];
- __u32 serial[2];
- struct wacom_features *features;
+ int tool[2];
+ int id[2];
+ __u32 serial[2];
+ struct wacom_features features;
};
#endif
diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c
new file mode 100644
index 000000000000..286bb490a9f2
--- /dev/null
+++ b/drivers/input/touchscreen/88pm860x-ts.c
@@ -0,0 +1,236 @@
+/*
+ * Touchscreen driver for Marvell 88PM860x
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/mfd/88pm860x.h>
+
+#define MEAS_LEN (8)
+#define ACCURATE_BIT (12)
+
+/* touch register */
+#define MEAS_EN3 (0x52)
+
+#define MEAS_TSIX_1 (0x8D)
+#define MEAS_TSIX_2 (0x8E)
+#define MEAS_TSIY_1 (0x8F)
+#define MEAS_TSIY_2 (0x90)
+#define MEAS_TSIZ1_1 (0x91)
+#define MEAS_TSIZ1_2 (0x92)
+#define MEAS_TSIZ2_1 (0x93)
+#define MEAS_TSIZ2_2 (0x94)
+
+/* bit definitions of touch */
+#define MEAS_PD_EN (1 << 3)
+#define MEAS_TSIX_EN (1 << 4)
+#define MEAS_TSIY_EN (1 << 5)
+#define MEAS_TSIZ1_EN (1 << 6)
+#define MEAS_TSIZ2_EN (1 << 7)
+
+struct pm860x_touch {
+ struct input_dev *idev;
+ struct i2c_client *i2c;
+ struct pm860x_chip *chip;
+ int irq;
+ int res_x; /* resistor of Xplate */
+};
+
+static irqreturn_t pm860x_touch_handler(int irq, void *data)
+{
+ struct pm860x_touch *touch = data;
+ struct pm860x_chip *chip = touch->chip;
+ unsigned char buf[MEAS_LEN];
+ int x, y, pen_down;
+ int z1, z2, rt = 0;
+ int ret;
+
+ ret = pm860x_bulk_read(touch->i2c, MEAS_TSIX_1, MEAS_LEN, buf);
+ if (ret < 0)
+ goto out;
+
+ pen_down = buf[1] & (1 << 6);
+ x = ((buf[0] & 0xFF) << 4) | (buf[1] & 0x0F);
+ y = ((buf[2] & 0xFF) << 4) | (buf[3] & 0x0F);
+ z1 = ((buf[4] & 0xFF) << 4) | (buf[5] & 0x0F);
+ z2 = ((buf[6] & 0xFF) << 4) | (buf[7] & 0x0F);
+
+ if (pen_down) {
+ if ((x != 0) && (z1 != 0) && (touch->res_x != 0)) {
+ rt = z2 / z1 - 1;
+ rt = (rt * touch->res_x * x) >> ACCURATE_BIT;
+ dev_dbg(chip->dev, "z1:%d, z2:%d, rt:%d\n",
+ z1, z2, rt);
+ }
+ input_report_abs(touch->idev, ABS_X, x);
+ input_report_abs(touch->idev, ABS_Y, y);
+ input_report_abs(touch->idev, ABS_PRESSURE, rt);
+ input_report_key(touch->idev, BTN_TOUCH, 1);
+ dev_dbg(chip->dev, "pen down at [%d, %d].\n", x, y);
+ } else {
+ input_report_abs(touch->idev, ABS_PRESSURE, 0);
+ input_report_key(touch->idev, BTN_TOUCH, 0);
+ dev_dbg(chip->dev, "pen release\n");
+ }
+ input_sync(touch->idev);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int pm860x_touch_open(struct input_dev *dev)
+{
+ struct pm860x_touch *touch = input_get_drvdata(dev);
+ int data, ret;
+
+ data = MEAS_PD_EN | MEAS_TSIX_EN | MEAS_TSIY_EN
+ | MEAS_TSIZ1_EN | MEAS_TSIZ2_EN;
+ ret = pm860x_set_bits(touch->i2c, MEAS_EN3, data, data);
+ if (ret < 0)
+ goto out;
+ return 0;
+out:
+ return ret;
+}
+
+static void pm860x_touch_close(struct input_dev *dev)
+{
+ struct pm860x_touch *touch = input_get_drvdata(dev);
+ int data;
+
+ data = MEAS_PD_EN | MEAS_TSIX_EN | MEAS_TSIY_EN
+ | MEAS_TSIZ1_EN | MEAS_TSIZ2_EN;
+ pm860x_set_bits(touch->i2c, MEAS_EN3, data, 0);
+}
+
+static int __devinit pm860x_touch_probe(struct platform_device *pdev)
+{
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm860x_platform_data *pm860x_pdata = \
+ pdev->dev.parent->platform_data;
+ struct pm860x_touch_pdata *pdata = NULL;
+ struct pm860x_touch *touch;
+ int irq, ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No IRQ resource!\n");
+ return -EINVAL;
+ }
+
+ if (!pm860x_pdata) {
+ dev_err(&pdev->dev, "platform data is missing\n");
+ return -EINVAL;
+ }
+
+ pdata = pm860x_pdata->touch;
+ if (!pdata) {
+ dev_err(&pdev->dev, "touchscreen data is missing\n");
+ return -EINVAL;
+ }
+
+ touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL);
+ if (touch == NULL)
+ return -ENOMEM;
+ dev_set_drvdata(&pdev->dev, touch);
+
+ touch->idev = input_allocate_device();
+ if (touch->idev == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate input device!\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ touch->idev->name = "88pm860x-touch";
+ touch->idev->phys = "88pm860x/input0";
+ touch->idev->id.bustype = BUS_I2C;
+ touch->idev->dev.parent = &pdev->dev;
+ touch->idev->open = pm860x_touch_open;
+ touch->idev->close = pm860x_touch_close;
+ touch->chip = chip;
+ touch->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
+ touch->irq = irq + chip->irq_base;
+ touch->res_x = pdata->res_x;
+ input_set_drvdata(touch->idev, touch);
+
+ ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler,
+ IRQF_ONESHOT, "touch", touch);
+ if (ret < 0)
+ goto out_irq;
+
+ __set_bit(EV_ABS, touch->idev->evbit);
+ __set_bit(ABS_X, touch->idev->absbit);
+ __set_bit(ABS_Y, touch->idev->absbit);
+ __set_bit(ABS_PRESSURE, touch->idev->absbit);
+ __set_bit(EV_SYN, touch->idev->evbit);
+ __set_bit(EV_KEY, touch->idev->evbit);
+ __set_bit(BTN_TOUCH, touch->idev->keybit);
+
+ input_set_abs_params(touch->idev, ABS_X, 0, 1 << ACCURATE_BIT, 0, 0);
+ input_set_abs_params(touch->idev, ABS_Y, 0, 1 << ACCURATE_BIT, 0, 0);
+ input_set_abs_params(touch->idev, ABS_PRESSURE, 0, 1 << ACCURATE_BIT,
+ 0, 0);
+
+ ret = input_register_device(touch->idev);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to register touch!\n");
+ goto out_rg;
+ }
+
+ platform_set_drvdata(pdev, touch);
+ return 0;
+out_rg:
+ free_irq(touch->irq, touch);
+out_irq:
+ input_free_device(touch->idev);
+out:
+ kfree(touch);
+ return ret;
+}
+
+static int __devexit pm860x_touch_remove(struct platform_device *pdev)
+{
+ struct pm860x_touch *touch = platform_get_drvdata(pdev);
+
+ input_unregister_device(touch->idev);
+ free_irq(touch->irq, touch);
+ platform_set_drvdata(pdev, NULL);
+ kfree(touch);
+ return 0;
+}
+
+static struct platform_driver pm860x_touch_driver = {
+ .driver = {
+ .name = "88pm860x-touch",
+ .owner = THIS_MODULE,
+ },
+ .probe = pm860x_touch_probe,
+ .remove = __devexit_p(pm860x_touch_remove),
+};
+
+static int __init pm860x_touch_init(void)
+{
+ return platform_driver_register(&pm860x_touch_driver);
+}
+module_init(pm860x_touch_init);
+
+static void __exit pm860x_touch_exit(void)
+{
+ platform_driver_unregister(&pm860x_touch_driver);
+}
+module_exit(pm860x_touch_exit);
+
+MODULE_DESCRIPTION("Touchscreen driver for Marvell Semiconductor 88PM860x");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:88pm860x-touch");
+
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index dfafc76da4fb..8a8fa4d2d6a8 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -11,18 +11,31 @@ menuconfig INPUT_TOUCHSCREEN
if INPUT_TOUCHSCREEN
+config TOUCHSCREEN_88PM860X
+ tristate "Marvell 88PM860x touchscreen"
+ depends on MFD_88PM860X
+ help
+ Say Y here if you have a 88PM860x PMIC and want to enable
+ support for the built-in touchscreen.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called 88pm860x-ts.
+
config TOUCHSCREEN_ADS7846
- tristate "ADS7846/TSC2046 and ADS7843 based touchscreens"
+ tristate "ADS7846/TSC2046/AD7873 and AD(S)7843 based touchscreens"
depends on SPI_MASTER
depends on HWMON = n || HWMON
help
Say Y here if you have a touchscreen interface using the
- ADS7846/TSC2046 or ADS7843 controller, and your board-specific
- setup code includes that in its table of SPI devices.
+ ADS7846/TSC2046/AD7873 or ADS7843/AD7843 controller,
+ and your board-specific setup code includes that in its
+ table of SPI devices.
If HWMON is selected, and the driver is told the reference voltage
on your board, you will also get hwmon interfaces for the voltage
- (and on ads7846/tsc2046, temperature) sensors of this chip.
+ (and on ads7846/tsc2046/ad7873, temperature) sensors of this chip.
If unsure, say N (but it's safe to say "Y").
@@ -90,7 +103,6 @@ config TOUCHSCREEN_CORGI
tristate "SharpSL (Corgi and Spitz series) touchscreen driver (DEPRECATED)"
depends on PXA_SHARPSL
select CORGI_SSP_DEPRECATED
- default y
help
Say Y here to enable the driver for the touchscreen on the
Sharp SL-C7xx and SL-Cxx00 series of PDAs.
@@ -537,6 +549,11 @@ config TOUCHSCREEN_USB_ETT_TC5UH
bool "ET&T TC5UH touchscreen controler support" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
+config TOUCHSCREEN_USB_NEXIO
+ default y
+ bool "NEXIO/iNexio device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
config TOUCHSCREEN_TOUCHIT213
tristate "Sahara TouchIT-213 touchscreen"
select SERIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index d61a3b4def9a..7fef7d5cca23 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -6,6 +6,7 @@
wm97xx-ts-y := wm97xx-core.o
+obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o
obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c
index eb83939c705e..e019d53d1ab4 100644
--- a/drivers/input/touchscreen/ad7877.c
+++ b/drivers/input/touchscreen/ad7877.c
@@ -46,7 +46,7 @@
#include <linux/spi/ad7877.h>
#include <asm/irq.h>
-#define TS_PEN_UP_TIMEOUT msecs_to_jiffies(50)
+#define TS_PEN_UP_TIMEOUT msecs_to_jiffies(100)
#define MAX_SPI_FREQ_HZ 20000000
#define MAX_12BIT ((1<<12)-1)
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index c21e6d3a8844..794d070c6900 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -47,6 +47,7 @@
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
#include <linux/i2c.h>
+#include <linux/gpio.h>
#include <linux/spi/ad7879.h>
@@ -132,7 +133,9 @@ struct ad7879 {
struct input_dev *input;
struct work_struct work;
struct timer_list timer;
-
+#ifdef CONFIG_GPIOLIB
+ struct gpio_chip gc;
+#endif
struct mutex mutex;
unsigned disabled:1; /* P: mutex */
@@ -150,11 +153,9 @@ struct ad7879 {
u8 median;
u16 x_plate_ohms;
u16 pressure_max;
- u16 gpio_init;
u16 cmd_crtl1;
u16 cmd_crtl2;
u16 cmd_crtl3;
- unsigned gpio:1;
};
static int ad7879_read(bus_device *, u8);
@@ -237,24 +238,6 @@ static irqreturn_t ad7879_irq(int irq, void *handle)
static void ad7879_setup(struct ad7879 *ts)
{
- ts->cmd_crtl3 = AD7879_YPLUS_BIT |
- AD7879_XPLUS_BIT |
- AD7879_Z2_BIT |
- AD7879_Z1_BIT |
- AD7879_TEMPMASK_BIT |
- AD7879_AUXVBATMASK_BIT |
- AD7879_GPIOALERTMASK_BIT;
-
- ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR |
- AD7879_AVG(ts->averaging) |
- AD7879_MFS(ts->median) |
- AD7879_FCD(ts->first_conversion_delay) |
- ts->gpio_init;
-
- ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |
- AD7879_ACQ(ts->acquisition_time) |
- AD7879_TMR(ts->pen_down_acc_interval);
-
ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
@@ -324,48 +307,132 @@ static ssize_t ad7879_disable_store(struct device *dev,
static DEVICE_ATTR(disable, 0664, ad7879_disable_show, ad7879_disable_store);
-static ssize_t ad7879_gpio_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static struct attribute *ad7879_attributes[] = {
+ &dev_attr_disable.attr,
+ NULL
+};
+
+static const struct attribute_group ad7879_attr_group = {
+ .attrs = ad7879_attributes,
+};
+
+#ifdef CONFIG_GPIOLIB
+static int ad7879_gpio_direction_input(struct gpio_chip *chip,
+ unsigned gpio)
{
- struct ad7879 *ts = dev_get_drvdata(dev);
+ struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+ int err;
- return sprintf(buf, "%u\n", ts->gpio);
+ mutex_lock(&ts->mutex);
+ ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIODIR | AD7879_GPIOPOL;
+ err = ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+ mutex_unlock(&ts->mutex);
+
+ return err;
}
-static ssize_t ad7879_gpio_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int ad7879_gpio_direction_output(struct gpio_chip *chip,
+ unsigned gpio, int level)
{
- struct ad7879 *ts = dev_get_drvdata(dev);
- unsigned long val;
- int error;
+ struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+ int err;
- error = strict_strtoul(buf, 10, &val);
- if (error)
- return error;
+ mutex_lock(&ts->mutex);
+ ts->cmd_crtl2 &= ~AD7879_GPIODIR;
+ ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIOPOL;
+ if (level)
+ ts->cmd_crtl2 |= AD7879_GPIO_DATA;
+ else
+ ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
+
+ err = ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+ mutex_unlock(&ts->mutex);
+
+ return err;
+}
+
+static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+ u16 val;
mutex_lock(&ts->mutex);
- ts->gpio = !!val;
- error = ad7879_write(ts->bus, AD7879_REG_CTRL2,
- ts->gpio ?
- ts->cmd_crtl2 & ~AD7879_GPIO_DATA :
- ts->cmd_crtl2 | AD7879_GPIO_DATA);
+ val = ad7879_read(ts->bus, AD7879_REG_CTRL2);
mutex_unlock(&ts->mutex);
- return error ? : count;
+ return !!(val & AD7879_GPIO_DATA);
}
-static DEVICE_ATTR(gpio, 0664, ad7879_gpio_show, ad7879_gpio_store);
+static void ad7879_gpio_set_value(struct gpio_chip *chip,
+ unsigned gpio, int value)
+{
+ struct ad7879 *ts = container_of(chip, struct ad7879, gc);
-static struct attribute *ad7879_attributes[] = {
- &dev_attr_disable.attr,
- &dev_attr_gpio.attr,
- NULL
-};
+ mutex_lock(&ts->mutex);
+ if (value)
+ ts->cmd_crtl2 |= AD7879_GPIO_DATA;
+ else
+ ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
-static const struct attribute_group ad7879_attr_group = {
- .attrs = ad7879_attributes,
-};
+ ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+ mutex_unlock(&ts->mutex);
+}
+
+static int __devinit ad7879_gpio_add(struct device *dev)
+{
+ struct ad7879 *ts = dev_get_drvdata(dev);
+ struct ad7879_platform_data *pdata = dev->platform_data;
+ int ret = 0;
+
+ if (pdata->gpio_export) {
+ ts->gc.direction_input = ad7879_gpio_direction_input;
+ ts->gc.direction_output = ad7879_gpio_direction_output;
+ ts->gc.get = ad7879_gpio_get_value;
+ ts->gc.set = ad7879_gpio_set_value;
+ ts->gc.can_sleep = 1;
+ ts->gc.base = pdata->gpio_base;
+ ts->gc.ngpio = 1;
+ ts->gc.label = "AD7879-GPIO";
+ ts->gc.owner = THIS_MODULE;
+ ts->gc.dev = dev;
+
+ ret = gpiochip_add(&ts->gc);
+ if (ret)
+ dev_err(dev, "failed to register gpio %d\n",
+ ts->gc.base);
+ }
+
+ return ret;
+}
+
+/*
+ * We mark ad7879_gpio_remove inline so there is a chance the code
+ * gets discarded when not needed. We can't do __devinit/__devexit
+ * markup since it is used in both probe and remove methods.
+ */
+static inline void ad7879_gpio_remove(struct device *dev)
+{
+ struct ad7879 *ts = dev_get_drvdata(dev);
+ struct ad7879_platform_data *pdata = dev->platform_data;
+ int ret;
+
+ if (pdata->gpio_export) {
+ ret = gpiochip_remove(&ts->gc);
+ if (ret)
+ dev_err(dev, "failed to remove gpio %d\n",
+ ts->gc.base);
+ }
+}
+#else
+static inline int ad7879_gpio_add(struct device *dev)
+{
+ return 0;
+}
+
+static inline void ad7879_gpio_remove(struct device *dev)
+{
+}
+#endif
static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
{
@@ -403,12 +470,6 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
ts->median = pdata->median;
- if (pdata->gpio_output)
- ts->gpio_init = AD7879_GPIO_EN |
- (pdata->gpio_default ? 0 : AD7879_GPIO_DATA);
- else
- ts->gpio_init = AD7879_GPIO_EN | AD7879_GPIODIR;
-
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&bus->dev));
input_dev->name = "AD7879 Touchscreen";
@@ -446,6 +507,23 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
goto err_free_mem;
}
+ ts->cmd_crtl3 = AD7879_YPLUS_BIT |
+ AD7879_XPLUS_BIT |
+ AD7879_Z2_BIT |
+ AD7879_Z1_BIT |
+ AD7879_TEMPMASK_BIT |
+ AD7879_AUXVBATMASK_BIT |
+ AD7879_GPIOALERTMASK_BIT;
+
+ ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR |
+ AD7879_AVG(ts->averaging) |
+ AD7879_MFS(ts->median) |
+ AD7879_FCD(ts->first_conversion_delay);
+
+ ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |
+ AD7879_ACQ(ts->acquisition_time) |
+ AD7879_TMR(ts->pen_down_acc_interval);
+
ad7879_setup(ts);
err = request_irq(bus->irq, ad7879_irq,
@@ -460,15 +538,21 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
if (err)
goto err_free_irq;
- err = input_register_device(input_dev);
+ err = ad7879_gpio_add(&bus->dev);
if (err)
goto err_remove_attr;
+ err = input_register_device(input_dev);
+ if (err)
+ goto err_remove_gpio;
+
dev_info(&bus->dev, "Rev.%d touchscreen, irq %d\n",
revid >> 8, bus->irq);
return 0;
+err_remove_gpio:
+ ad7879_gpio_remove(&bus->dev);
err_remove_attr:
sysfs_remove_group(&bus->dev.kobj, &ad7879_attr_group);
err_free_irq:
@@ -481,6 +565,7 @@ err_free_mem:
static int __devexit ad7879_destroy(bus_device *bus, struct ad7879 *ts)
{
+ ad7879_gpio_remove(&bus->dev);
ad7879_disable(ts);
sysfs_remove_group(&ts->bus->dev.kobj, &ad7879_attr_group);
free_irq(ts->bus->irq, ts);
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 52d2ca147d8f..532279cda0e4 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -27,6 +27,7 @@
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
+#include <linux/regulator/consumer.h>
#include <asm/irq.h>
/*
@@ -35,6 +36,7 @@
* TSC2046 is just newer ads7846 silicon.
* Support for ads7843 tested on Atmel at91sam926x-EK.
* Support for ads7845 has only been stubbed in.
+ * Support for Analog Devices AD7873 and AD7843 tested.
*
* IRQ handling needs a workaround because of a shortcoming in handling
* edge triggered IRQs on some platforms like the OMAP1/2. These
@@ -85,6 +87,7 @@ struct ads7846 {
char name[32];
struct spi_device *spi;
+ struct regulator *reg;
#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
struct attribute_group *attr_group;
@@ -788,6 +791,8 @@ static void ads7846_disable(struct ads7846 *ts)
}
}
+ regulator_disable(ts->reg);
+
/* we know the chip's in lowpower mode since we always
* leave it that way after every request
*/
@@ -799,6 +804,8 @@ static void ads7846_enable(struct ads7846 *ts)
if (!ts->disabled)
return;
+ regulator_enable(ts->reg);
+
ts->disabled = 0;
ts->irq_disabled = 0;
enable_irq(ts->spi->irq);
@@ -815,6 +822,9 @@ static int ads7846_suspend(struct spi_device *spi, pm_message_t message)
spin_unlock_irq(&ts->lock);
+ if (device_may_wakeup(&ts->spi->dev))
+ enable_irq_wake(ts->spi->irq);
+
return 0;
}
@@ -823,6 +833,9 @@ static int ads7846_resume(struct spi_device *spi)
{
struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+ if (device_may_wakeup(&ts->spi->dev))
+ disable_irq_wake(ts->spi->irq);
+
spin_lock_irq(&ts->lock);
ts->is_suspended = 0;
@@ -978,6 +991,15 @@ static int __devinit ads7846_probe(struct spi_device *spi)
vref = pdata->keep_vref_on;
+ if (ts->model == 7873) {
+ /* The AD7873 is almost identical to the ADS7846
+ * keep VREF off during differential/ratiometric
+ * conversion modes
+ */
+ ts->model = 7846;
+ vref = 0;
+ }
+
/* set up the transfers to read touchscreen state; this assumes we
* use formula #2 for pressure, not #3.
*/
@@ -1139,6 +1161,19 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->last_msg = m;
+ ts->reg = regulator_get(&spi->dev, "vcc");
+ if (IS_ERR(ts->reg)) {
+ dev_err(&spi->dev, "unable to get regulator: %ld\n",
+ PTR_ERR(ts->reg));
+ goto err_free_gpio;
+ }
+
+ err = regulator_enable(ts->reg);
+ if (err) {
+ dev_err(&spi->dev, "unable to enable regulator: %d\n", err);
+ goto err_put_regulator;
+ }
+
if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
spi->dev.driver->name, ts)) {
dev_info(&spi->dev,
@@ -1148,7 +1183,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi->dev.driver->name, ts);
if (err) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
- goto err_free_gpio;
+ goto err_disable_regulator;
}
}
@@ -1172,6 +1207,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
if (err)
goto err_remove_attr_group;
+ device_init_wakeup(&spi->dev, pdata->wakeup);
+
return 0;
err_remove_attr_group:
@@ -1180,6 +1217,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ads784x_hwmon_unregister(spi, ts);
err_free_irq:
free_irq(spi->irq, ts);
+ err_disable_regulator:
+ regulator_disable(ts->reg);
+ err_put_regulator:
+ regulator_put(ts->reg);
err_free_gpio:
if (ts->gpio_pendown != -1)
gpio_free(ts->gpio_pendown);
@@ -1197,6 +1238,8 @@ static int __devexit ads7846_remove(struct spi_device *spi)
{
struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+ device_init_wakeup(&spi->dev, false);
+
ads784x_hwmon_unregister(spi, ts);
input_unregister_device(ts->input);
@@ -1208,6 +1251,9 @@ static int __devexit ads7846_remove(struct spi_device *spi)
/* suspend left the IRQ disabled */
enable_irq(ts->spi->irq);
+ regulator_disable(ts->reg);
+ regulator_put(ts->reg);
+
if (ts->gpio_pendown != -1)
gpio_free(ts->gpio_pendown);
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 8f38c5e55ce6..486d31ba9c09 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -72,45 +72,49 @@ static void elo_process_data_10(struct elo *elo, unsigned char data)
struct input_dev *dev = elo->dev;
elo->data[elo->idx] = data;
- switch (elo->idx++) {
- case 0:
- elo->csum = 0xaa;
- if (data != ELO10_LEAD_BYTE) {
- pr_debug("elo: unsynchronized data: 0x%02x\n", data);
- elo->idx = 0;
- }
- break;
- case 9:
+ switch (elo->idx++) {
+ case 0:
+ elo->csum = 0xaa;
+ if (data != ELO10_LEAD_BYTE) {
+ dev_dbg(&elo->serio->dev,
+ "unsynchronized data: 0x%02x\n", data);
elo->idx = 0;
- if (data != elo->csum) {
- pr_debug("elo: bad checksum: 0x%02x, expected 0x%02x\n",
- data, elo->csum);
- break;
- }
- if (elo->data[1] != elo->expected_packet) {
- if (elo->data[1] != ELO10_TOUCH_PACKET)
- pr_debug("elo: unexpected packet: 0x%02x\n",
- elo->data[1]);
- break;
- }
- if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) {
- input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
- input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
- if (elo->data[2] & ELO10_PRESSURE)
- input_report_abs(dev, ABS_PRESSURE,
- (elo->data[8] << 8) | elo->data[7]);
- input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH);
- input_sync(dev);
- } else if (elo->data[1] == ELO10_ACK_PACKET) {
- if (elo->data[2] == '0')
- elo->expected_packet = ELO10_TOUCH_PACKET;
- complete(&elo->cmd_done);
- } else {
- memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN);
- elo->expected_packet = ELO10_ACK_PACKET;
- }
+ }
+ break;
+
+ case 9:
+ elo->idx = 0;
+ if (data != elo->csum) {
+ dev_dbg(&elo->serio->dev,
+ "bad checksum: 0x%02x, expected 0x%02x\n",
+ data, elo->csum);
+ break;
+ }
+ if (elo->data[1] != elo->expected_packet) {
+ if (elo->data[1] != ELO10_TOUCH_PACKET)
+ dev_dbg(&elo->serio->dev,
+ "unexpected packet: 0x%02x\n",
+ elo->data[1]);
break;
+ }
+ if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) {
+ input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
+ input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
+ if (elo->data[2] & ELO10_PRESSURE)
+ input_report_abs(dev, ABS_PRESSURE,
+ (elo->data[8] << 8) | elo->data[7]);
+ input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH);
+ input_sync(dev);
+ } else if (elo->data[1] == ELO10_ACK_PACKET) {
+ if (elo->data[2] == '0')
+ elo->expected_packet = ELO10_TOUCH_PACKET;
+ complete(&elo->cmd_done);
+ } else {
+ memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN);
+ elo->expected_packet = ELO10_ACK_PACKET;
+ }
+ break;
}
elo->csum += data;
}
@@ -123,42 +127,53 @@ static void elo_process_data_6(struct elo *elo, unsigned char data)
switch (elo->idx++) {
- case 0: if ((data & 0xc0) != 0xc0) elo->idx = 0; break;
- case 1: if ((data & 0xc0) != 0x80) elo->idx = 0; break;
- case 2: if ((data & 0xc0) != 0x40) elo->idx = 0; break;
-
- case 3:
- if (data & 0xc0) {
- elo->idx = 0;
- break;
- }
+ case 0:
+ if ((data & 0xc0) != 0xc0)
+ elo->idx = 0;
+ break;
- input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f));
- input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f));
+ case 1:
+ if ((data & 0xc0) != 0x80)
+ elo->idx = 0;
+ break;
- if (elo->id == 2) {
- input_report_key(dev, BTN_TOUCH, 1);
- input_sync(dev);
- elo->idx = 0;
- }
+ case 2:
+ if ((data & 0xc0) != 0x40)
+ elo->idx = 0;
+ break;
+ case 3:
+ if (data & 0xc0) {
+ elo->idx = 0;
break;
+ }
- case 4:
- if (data) {
- input_sync(dev);
- elo->idx = 0;
- }
- break;
+ input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f));
+ input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f));
- case 5:
- if ((data & 0xf0) == 0) {
- input_report_abs(dev, ABS_PRESSURE, elo->data[5]);
- input_report_key(dev, BTN_TOUCH, !!elo->data[5]);
- }
+ if (elo->id == 2) {
+ input_report_key(dev, BTN_TOUCH, 1);
input_sync(dev);
elo->idx = 0;
- break;
+ }
+
+ break;
+
+ case 4:
+ if (data) {
+ input_sync(dev);
+ elo->idx = 0;
+ }
+ break;
+
+ case 5:
+ if ((data & 0xf0) == 0) {
+ input_report_abs(dev, ABS_PRESSURE, elo->data[5]);
+ input_report_key(dev, BTN_TOUCH, !!elo->data[5]);
+ }
+ input_sync(dev);
+ elo->idx = 0;
+ break;
}
}
@@ -170,17 +185,17 @@ static void elo_process_data_3(struct elo *elo, unsigned char data)
switch (elo->idx++) {
- case 0:
- if ((data & 0x7f) != 0x01)
- elo->idx = 0;
- break;
- case 2:
- input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80));
- input_report_abs(dev, ABS_X, elo->data[1]);
- input_report_abs(dev, ABS_Y, elo->data[2]);
- input_sync(dev);
+ case 0:
+ if ((data & 0x7f) != 0x01)
elo->idx = 0;
- break;
+ break;
+ case 2:
+ input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80));
+ input_report_abs(dev, ABS_X, elo->data[1]);
+ input_report_abs(dev, ABS_Y, elo->data[2]);
+ input_sync(dev);
+ elo->idx = 0;
+ break;
}
}
@@ -189,19 +204,19 @@ static irqreturn_t elo_interrupt(struct serio *serio,
{
struct elo *elo = serio_get_drvdata(serio);
- switch(elo->id) {
- case 0:
- elo_process_data_10(elo, data);
- break;
-
- case 1:
- case 2:
- elo_process_data_6(elo, data);
- break;
-
- case 3:
- elo_process_data_3(elo, data);
- break;
+ switch (elo->id) {
+ case 0:
+ elo_process_data_10(elo, data);
+ break;
+
+ case 1:
+ case 2:
+ elo_process_data_6(elo, data);
+ break;
+
+ case 3:
+ elo_process_data_3(elo, data);
+ break;
}
return IRQ_HANDLED;
@@ -261,10 +276,10 @@ static int elo_setup_10(struct elo *elo)
if (packet[3] & ELO10_PRESSURE)
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
- printk(KERN_INFO "elo: %sTouch touchscreen, fw: %02x.%02x, "
- "features: 0x%02x, controller: 0x%02x\n",
- elo_types[(packet[1] -'0') & 0x03],
- packet[5], packet[4], packet[3], packet[7]);
+ dev_info(&elo->serio->dev,
+ "%sTouch touchscreen, fw: %02x.%02x, features: 0x%02x, controller: 0x%02x\n",
+ elo_types[(packet[1] -'0') & 0x03],
+ packet[5], packet[4], packet[3], packet[7]);
return 0;
}
@@ -330,24 +345,24 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
switch (elo->id) {
- case 0: /* 10-byte protocol */
- if (elo_setup_10(elo))
- goto fail3;
+ case 0: /* 10-byte protocol */
+ if (elo_setup_10(elo))
+ goto fail3;
- break;
+ break;
- case 1: /* 6-byte protocol */
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0);
+ case 1: /* 6-byte protocol */
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0);
- case 2: /* 4-byte protocol */
- input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0);
- break;
+ case 2: /* 4-byte protocol */
+ input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0);
+ break;
- case 3: /* 3-byte protocol */
- input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0);
- break;
+ case 3: /* 3-byte protocol */
+ input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0);
+ break;
}
err = input_register_device(elo->dev);
diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c
index 6cdcf2a6e036..b6b8b1c7ecea 100644
--- a/drivers/input/touchscreen/mainstone-wm97xx.c
+++ b/drivers/input/touchscreen/mainstone-wm97xx.c
@@ -153,6 +153,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
if (pressure)
p = MODR;
+ dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
+ x, y, p);
+
/* are samples valid */
if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
(y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c
index be115b3b65eb..be54fd639aca 100644
--- a/drivers/input/touchscreen/mc13783_ts.c
+++ b/drivers/input/touchscreen/mc13783_ts.c
@@ -44,7 +44,7 @@ static irqreturn_t mc13783_ts_handler(int irq, void *data)
{
struct mc13783_ts_priv *priv = data;
- mc13783_ackirq(priv->mc13783, irq);
+ mc13783_irq_ack(priv->mc13783, irq);
/*
* Kick off reading coordinates. Note that if work happens already
@@ -135,7 +135,7 @@ static int mc13783_ts_open(struct input_dev *dev)
mc13783_lock(priv->mc13783);
- mc13783_ackirq(priv->mc13783, MC13783_IRQ_TS);
+ mc13783_irq_ack(priv->mc13783, MC13783_IRQ_TS);
ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_TS,
mc13783_ts_handler, MC13783_TS_NAME, priv);
diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c
index 6386b441ef85..3755a47d053c 100644
--- a/drivers/input/touchscreen/s3c2410_ts.c
+++ b/drivers/input/touchscreen/s3c2410_ts.c
@@ -128,27 +128,29 @@ static void touch_timer_fire(unsigned long data)
down = get_down(data0, data1);
- if (ts.count == (1 << ts.shift)) {
- ts.xp >>= ts.shift;
- ts.yp >>= ts.shift;
+ if (down) {
+ if (ts.count == (1 << ts.shift)) {
+ ts.xp >>= ts.shift;
+ ts.yp >>= ts.shift;
- dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n",
- __func__, ts.xp, ts.yp, ts.count);
+ dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n",
+ __func__, ts.xp, ts.yp, ts.count);
- input_report_abs(ts.input, ABS_X, ts.xp);
- input_report_abs(ts.input, ABS_Y, ts.yp);
+ input_report_abs(ts.input, ABS_X, ts.xp);
+ input_report_abs(ts.input, ABS_Y, ts.yp);
- input_report_key(ts.input, BTN_TOUCH, 1);
- input_sync(ts.input);
+ input_report_key(ts.input, BTN_TOUCH, 1);
+ input_sync(ts.input);
- ts.xp = 0;
- ts.yp = 0;
- ts.count = 0;
- }
+ ts.xp = 0;
+ ts.yp = 0;
+ ts.count = 0;
+ }
- if (down) {
s3c_adc_start(ts.client, 0, 1 << ts.shift);
} else {
+ ts.xp = 0;
+ ts.yp = 0;
ts.count = 0;
input_report_key(ts.input, BTN_TOUCH, 0);
@@ -401,6 +403,7 @@ static int s3c2410ts_resume(struct device *dev)
struct s3c2410_ts_mach_info *info = pdev->dev.platform_data;
clk_enable(ts.clock);
+ enable_irq(ts.irq_tc);
/* Initialise registers */
if ((info->delay & 0xffff) > 0)
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index 7ef0d1420d3c..be23780e8a3e 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -358,7 +358,7 @@ static int __devexit tsc2007_remove(struct i2c_client *client)
return 0;
}
-static struct i2c_device_id tsc2007_idtable[] = {
+static const struct i2c_device_id tsc2007_idtable[] = {
{ "tsc2007", 0 },
{ }
};
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 09a5e7341bd5..99330bbdbac7 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -15,6 +15,7 @@
* - GoTop Super_Q2/GogoPen/PenPower tablets
* - JASTEC USB touch controller/DigiTech DTR-02U
* - Zytronic capacitive touchscreen
+ * - NEXIO/iNexio
*
* Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -95,6 +96,7 @@ struct usbtouch_device_info {
int (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt);
int (*init) (struct usbtouch_usb *usbtouch);
+ void (*exit) (struct usbtouch_usb *usbtouch);
};
/* a usbtouch device */
@@ -104,11 +106,12 @@ struct usbtouch_usb {
unsigned char *buffer;
int buf_len;
struct urb *irq;
- struct usb_device *udev;
+ struct usb_interface *interface;
struct input_dev *input;
struct usbtouch_device_info *type;
char name[128];
char phys[64];
+ void *priv;
int x, y;
int touch, press;
@@ -133,6 +136,7 @@ enum {
DEVTYPE_E2I,
DEVTYPE_ZYTRONIC,
DEVTYPE_TC5UH,
+ DEVTYPE_NEXIO,
};
#define USB_DEVICE_HID_CLASS(vend, prod) \
@@ -144,7 +148,7 @@ enum {
.bInterfaceClass = USB_INTERFACE_CLASS_HID, \
.bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE
-static struct usb_device_id usbtouch_devices[] = {
+static const struct usb_device_id usbtouch_devices[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
/* ignore the HID capable devices, handled by usbhid */
{USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
@@ -222,6 +226,14 @@ static struct usb_device_id usbtouch_devices[] = {
{USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH},
#endif
+#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
+ /* data interface only */
+ {USB_DEVICE_AND_INTERFACE_INFO(0x10f0, 0x2002, 0x0a, 0x00, 0x00),
+ .driver_info = DEVTYPE_NEXIO},
+ {USB_DEVICE_AND_INTERFACE_INFO(0x1870, 0x0001, 0x0a, 0x00, 0x00),
+ .driver_info = DEVTYPE_NEXIO},
+#endif
+
{}
};
@@ -234,8 +246,9 @@ static struct usb_device_id usbtouch_devices[] = {
static int e2i_init(struct usbtouch_usb *usbtouch)
{
int ret;
+ struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
- ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
0x01, 0x02, 0x0000, 0x0081,
NULL, 0, USB_CTRL_SET_TIMEOUT);
@@ -344,8 +357,9 @@ static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
static int mtouch_init(struct usbtouch_usb *usbtouch)
{
int ret, i;
+ struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
- ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
MTOUCHUSB_RESET,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
@@ -356,7 +370,7 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
msleep(150);
for (i = 0; i < 3; i++) {
- ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
MTOUCHUSB_ASYNC_REPORT,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
@@ -489,7 +503,7 @@ static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
{
- struct usb_device *dev = usbtouch->udev;
+ struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
int ret = -ENOMEM;
unsigned char *buf;
@@ -618,8 +632,8 @@ static int idealtek_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
- dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1] ;
- dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3] ;
+ dev->x = (pkt[2] << 8) | pkt[1];
+ dev->y = (pkt[4] << 8) | pkt[3];
dev->press = pkt[5] & 0xff;
dev->touch = pkt[0] & 0x01;
@@ -690,6 +704,229 @@ static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
#endif
/*****************************************************************************
+ * NEXIO Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
+
+#define NEXIO_TIMEOUT 5000
+#define NEXIO_BUFSIZE 1024
+#define NEXIO_THRESHOLD 50
+
+struct nexio_priv {
+ struct urb *ack;
+ unsigned char *ack_buf;
+};
+
+struct nexio_touch_packet {
+ u8 flags; /* 0xe1 = touch, 0xe1 = release */
+ __be16 data_len; /* total bytes of touch data */
+ __be16 x_len; /* bytes for X axis */
+ __be16 y_len; /* bytes for Y axis */
+ u8 data[];
+} __attribute__ ((packed));
+
+static unsigned char nexio_ack_pkt[2] = { 0xaa, 0x02 };
+static unsigned char nexio_init_pkt[4] = { 0x82, 0x04, 0x0a, 0x0f };
+
+static void nexio_ack_complete(struct urb *urb)
+{
+}
+
+static int nexio_init(struct usbtouch_usb *usbtouch)
+{
+ struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
+ struct usb_host_interface *interface = usbtouch->interface->cur_altsetting;
+ struct nexio_priv *priv;
+ int ret = -ENOMEM;
+ int actual_len, i;
+ unsigned char *buf;
+ char *firmware_ver = NULL, *device_name = NULL;
+ int input_ep = 0, output_ep = 0;
+
+ /* find first input and output endpoint */
+ for (i = 0; i < interface->desc.bNumEndpoints; i++) {
+ if (!input_ep &&
+ usb_endpoint_dir_in(&interface->endpoint[i].desc))
+ input_ep = interface->endpoint[i].desc.bEndpointAddress;
+ if (!output_ep &&
+ usb_endpoint_dir_out(&interface->endpoint[i].desc))
+ output_ep = interface->endpoint[i].desc.bEndpointAddress;
+ }
+ if (!input_ep || !output_ep)
+ return -ENXIO;
+
+ buf = kmalloc(NEXIO_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ goto out_buf;
+
+ /* two empty reads */
+ for (i = 0; i < 2; i++) {
+ ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep),
+ buf, NEXIO_BUFSIZE, &actual_len,
+ NEXIO_TIMEOUT);
+ if (ret < 0)
+ goto out_buf;
+ }
+
+ /* send init command */
+ memcpy(buf, nexio_init_pkt, sizeof(nexio_init_pkt));
+ ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, output_ep),
+ buf, sizeof(nexio_init_pkt), &actual_len,
+ NEXIO_TIMEOUT);
+ if (ret < 0)
+ goto out_buf;
+
+ /* read replies */
+ for (i = 0; i < 3; i++) {
+ memset(buf, 0, NEXIO_BUFSIZE);
+ ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep),
+ buf, NEXIO_BUFSIZE, &actual_len,
+ NEXIO_TIMEOUT);
+ if (ret < 0 || actual_len < 1 || buf[1] != actual_len)
+ continue;
+ switch (buf[0]) {
+ case 0x83: /* firmware version */
+ if (!firmware_ver)
+ firmware_ver = kstrdup(&buf[2], GFP_KERNEL);
+ break;
+ case 0x84: /* device name */
+ if (!device_name)
+ device_name = kstrdup(&buf[2], GFP_KERNEL);
+ break;
+ }
+ }
+
+ printk(KERN_INFO "Nexio device: %s, firmware version: %s\n",
+ device_name, firmware_ver);
+
+ kfree(firmware_ver);
+ kfree(device_name);
+
+ /* prepare ACK URB */
+ ret = -ENOMEM;
+
+ usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
+ if (!usbtouch->priv)
+ goto out_buf;
+
+ priv = usbtouch->priv;
+
+ priv->ack_buf = kmalloc(sizeof(nexio_ack_pkt), GFP_KERNEL);
+ if (!priv->ack_buf)
+ goto err_priv;
+
+ memcpy(priv->ack_buf, nexio_ack_pkt, sizeof(nexio_ack_pkt));
+
+ priv->ack = usb_alloc_urb(0, GFP_KERNEL);
+ if (!priv->ack) {
+ dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
+ goto err_ack_buf;
+ }
+
+ usb_fill_bulk_urb(priv->ack, dev, usb_sndbulkpipe(dev, output_ep),
+ priv->ack_buf, sizeof(nexio_ack_pkt),
+ nexio_ack_complete, usbtouch);
+ ret = 0;
+ goto out_buf;
+
+err_ack_buf:
+ kfree(priv->ack_buf);
+err_priv:
+ kfree(priv);
+out_buf:
+ kfree(buf);
+ return ret;
+}
+
+static void nexio_exit(struct usbtouch_usb *usbtouch)
+{
+ struct nexio_priv *priv = usbtouch->priv;
+
+ usb_kill_urb(priv->ack);
+ usb_free_urb(priv->ack);
+ kfree(priv->ack_buf);
+ kfree(priv);
+}
+
+static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
+{
+ int x, y, begin_x, begin_y, end_x, end_y, w, h, ret;
+ struct nexio_touch_packet *packet = (void *) pkt;
+ struct nexio_priv *priv = usbtouch->priv;
+
+ /* got touch data? */
+ if ((pkt[0] & 0xe0) != 0xe0)
+ return 0;
+
+ /* send ACK */
+ ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
+
+ if (!usbtouch->type->max_xc) {
+ usbtouch->type->max_xc = 2 * be16_to_cpu(packet->x_len);
+ input_set_abs_params(usbtouch->input, ABS_X, 0,
+ 2 * be16_to_cpu(packet->x_len), 0, 0);
+ usbtouch->type->max_yc = 2 * be16_to_cpu(packet->y_len);
+ input_set_abs_params(usbtouch->input, ABS_Y, 0,
+ 2 * be16_to_cpu(packet->y_len), 0, 0);
+ }
+ /*
+ * The device reports state of IR sensors on X and Y axes.
+ * Each byte represents "darkness" percentage (0-100) of one element.
+ * 17" touchscreen reports only 64 x 52 bytes so the resolution is low.
+ * This also means that there's a limited multi-touch capability but
+ * it's disabled (and untested) here as there's no X driver for that.
+ */
+ begin_x = end_x = begin_y = end_y = -1;
+ for (x = 0; x < be16_to_cpu(packet->x_len); x++) {
+ if (begin_x == -1 && packet->data[x] > NEXIO_THRESHOLD) {
+ begin_x = x;
+ continue;
+ }
+ if (end_x == -1 && begin_x != -1 && packet->data[x] < NEXIO_THRESHOLD) {
+ end_x = x - 1;
+ for (y = be16_to_cpu(packet->x_len);
+ y < be16_to_cpu(packet->data_len); y++) {
+ if (begin_y == -1 && packet->data[y] > NEXIO_THRESHOLD) {
+ begin_y = y - be16_to_cpu(packet->x_len);
+ continue;
+ }
+ if (end_y == -1 &&
+ begin_y != -1 && packet->data[y] < NEXIO_THRESHOLD) {
+ end_y = y - 1 - be16_to_cpu(packet->x_len);
+ w = end_x - begin_x;
+ h = end_y - begin_y;
+#if 0
+ /* multi-touch */
+ input_report_abs(usbtouch->input,
+ ABS_MT_TOUCH_MAJOR, max(w,h));
+ input_report_abs(usbtouch->input,
+ ABS_MT_TOUCH_MINOR, min(x,h));
+ input_report_abs(usbtouch->input,
+ ABS_MT_POSITION_X, 2*begin_x+w);
+ input_report_abs(usbtouch->input,
+ ABS_MT_POSITION_Y, 2*begin_y+h);
+ input_report_abs(usbtouch->input,
+ ABS_MT_ORIENTATION, w > h);
+ input_mt_sync(usbtouch->input);
+#endif
+ /* single touch */
+ usbtouch->x = 2 * begin_x + w;
+ usbtouch->y = 2 * begin_y + h;
+ usbtouch->touch = packet->flags & 0x01;
+ begin_y = end_y = -1;
+ return 1;
+ }
+ }
+ begin_x = end_x = -1;
+ }
+
+ }
+ return 0;
+}
+#endif
+
+
+/*****************************************************************************
* the different device descriptors
*/
#ifdef MULTI_PACKET
@@ -809,9 +1046,9 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
[DEVTYPE_GENERAL_TOUCH] = {
.min_xc = 0x0,
- .max_xc = 0x0500,
+ .max_xc = 0x7fff,
.min_yc = 0x0,
- .max_yc = 0x0500,
+ .max_yc = 0x7fff,
.rept_size = 7,
.read_data = general_touch_read_data,
},
@@ -873,6 +1110,16 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.read_data = tc5uh_read_data,
},
#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
+ [DEVTYPE_NEXIO] = {
+ .rept_size = 128,
+ .irq_always = true,
+ .read_data = nexio_read_data,
+ .init = nexio_init,
+ .exit = nexio_exit,
+ },
+#endif
};
@@ -998,6 +1245,7 @@ static void usbtouch_irq(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
+ case -EPIPE:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
__func__, urb->status);
@@ -1021,7 +1269,7 @@ static int usbtouch_open(struct input_dev *input)
{
struct usbtouch_usb *usbtouch = input_get_drvdata(input);
- usbtouch->irq->dev = usbtouch->udev;
+ usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface);
if (!usbtouch->type->irq_always) {
if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
@@ -1048,13 +1296,23 @@ static void usbtouch_free_buffers(struct usb_device *udev,
kfree(usbtouch->buffer);
}
+static struct usb_endpoint_descriptor *
+usbtouch_get_input_endpoint(struct usb_host_interface *interface)
+{
+ int i;
+
+ for (i = 0; i < interface->desc.bNumEndpoints; i++)
+ if (usb_endpoint_dir_in(&interface->endpoint[i].desc))
+ return &interface->endpoint[i].desc;
+
+ return NULL;
+}
static int usbtouch_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usbtouch_usb *usbtouch;
struct input_dev *input_dev;
- struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev(intf);
struct usbtouch_device_info *type;
@@ -1064,8 +1322,9 @@ static int usbtouch_probe(struct usb_interface *intf,
if (id->driver_info == DEVTYPE_IGNORE)
return -ENODEV;
- interface = intf->cur_altsetting;
- endpoint = &interface->endpoint[0].desc;
+ endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);
+ if (!endpoint)
+ return -ENXIO;
usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL);
input_dev = input_allocate_device();
@@ -1094,7 +1353,7 @@ static int usbtouch_probe(struct usb_interface *intf,
goto out_free_buffers;
}
- usbtouch->udev = udev;
+ usbtouch->interface = intf;
usbtouch->input = input_dev;
if (udev->manufacturer)
@@ -1133,12 +1392,18 @@ static int usbtouch_probe(struct usb_interface *intf,
input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
type->max_press, 0, 0);
- usb_fill_int_urb(usbtouch->irq, usbtouch->udev,
- usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress),
+ if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)
+ usb_fill_int_urb(usbtouch->irq, udev,
+ usb_rcvintpipe(udev, endpoint->bEndpointAddress),
usbtouch->data, type->rept_size,
usbtouch_irq, usbtouch, endpoint->bInterval);
+ else
+ usb_fill_bulk_urb(usbtouch->irq, udev,
+ usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),
+ usbtouch->data, type->rept_size,
+ usbtouch_irq, usbtouch);
- usbtouch->irq->dev = usbtouch->udev;
+ usbtouch->irq->dev = udev;
usbtouch->irq->transfer_dma = usbtouch->data_dma;
usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -1147,23 +1412,37 @@ static int usbtouch_probe(struct usb_interface *intf,
err = type->init(usbtouch);
if (err) {
dbg("%s - type->init() failed, err: %d", __func__, err);
- goto out_free_buffers;
+ goto out_free_urb;
}
}
err = input_register_device(usbtouch->input);
if (err) {
dbg("%s - input_register_device failed, err: %d", __func__, err);
- goto out_free_buffers;
+ goto out_do_exit;
}
usb_set_intfdata(intf, usbtouch);
- if (usbtouch->type->irq_always)
- usb_submit_urb(usbtouch->irq, GFP_KERNEL);
+ if (usbtouch->type->irq_always) {
+ err = usb_submit_urb(usbtouch->irq, GFP_KERNEL);
+ if (err) {
+ err("%s - usb_submit_urb failed with result: %d",
+ __func__, err);
+ goto out_unregister_input;
+ }
+ }
return 0;
+out_unregister_input:
+ input_unregister_device(input_dev);
+ input_dev = NULL;
+out_do_exit:
+ if (type->exit)
+ type->exit(usbtouch);
+out_free_urb:
+ usb_free_urb(usbtouch->irq);
out_free_buffers:
usbtouch_free_buffers(udev, usbtouch);
out_free:
@@ -1186,6 +1465,8 @@ static void usbtouch_disconnect(struct usb_interface *intf)
/* this will stop IO via close */
input_unregister_device(usbtouch->input);
usb_free_urb(usbtouch->irq);
+ if (usbtouch->type->exit)
+ usbtouch->type->exit(usbtouch);
usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch);
kfree(usbtouch);
}
diff --git a/drivers/input/touchscreen/zylonite-wm97xx.c b/drivers/input/touchscreen/zylonite-wm97xx.c
index eca54dbdf493..048849867643 100644
--- a/drivers/input/touchscreen/zylonite-wm97xx.c
+++ b/drivers/input/touchscreen/zylonite-wm97xx.c
@@ -118,6 +118,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
if (pressure)
p = MODR;
+ dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
+ x, y, p);
+
/* are samples valid */
if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
(y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c
index c721c0a23eb8..d30436fee476 100644
--- a/drivers/input/xen-kbdfront.c
+++ b/drivers/input/xen-kbdfront.c
@@ -321,7 +321,7 @@ InitWait:
}
}
-static struct xenbus_device_id xenkbd_ids[] = {
+static const struct xenbus_device_id xenkbd_ids[] = {
{ "vkbd" },
{ "" }
};
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig
index 022a19452953..4fb601670de3 100644
--- a/drivers/isdn/Kconfig
+++ b/drivers/isdn/Kconfig
@@ -7,15 +7,14 @@ menuconfig ISDN
depends on NET
depends on !S390
---help---
- ISDN ("Integrated Services Digital Networks", called RNIS in France)
- is a special type of fully digital telephone service; it's mostly
- used to connect to your Internet service provider (with SLIP or
- PPP). The main advantage is that the speed is higher than ordinary
- modem/telephone connections, and that you can have voice
- conversations while downloading stuff. It only works if your
- computer is equipped with an ISDN card and both you and your service
- provider purchased an ISDN line from the phone company. For
- details, read <http://www.alumni.caltech.edu/~dank/isdn/> on the WWW.
+ ISDN ("Integrated Services Digital Network", called RNIS in France)
+ is a fully digital telephone service that can be used for voice and
+ data connections. If your computer is equipped with an ISDN
+ adapter you can use it to connect to your Internet service provider
+ (with SLIP or PPP) faster than via a conventional telephone modem
+ (though still much slower than with DSL) or to make and accept
+ voice calls (eg. turning your PC into a software answering machine
+ or PABX).
Select this option if you want your kernel to support ISDN.
@@ -39,17 +38,22 @@ menuconfig ISDN_I4L
It is still available, though, for use with adapters that are not
supported by the new CAPI subsystem yet.
-source "drivers/isdn/mISDN/Kconfig"
-
source "drivers/isdn/i4l/Kconfig"
menuconfig ISDN_CAPI
tristate "CAPI 2.0 subsystem"
help
- This provides the CAPI (Common ISDN Application Programming
- Interface, a standard making it easy for programs to access ISDN
- hardware, see <http://www.capi.org/>. This is needed for AVM's set
- of active ISDN controllers like B1, T1, M1.
+ This provides CAPI (the Common ISDN Application Programming
+ Interface) Version 2.0, a standard making it easy for programs to
+ access ISDN hardware in a device independent way. (For details see
+ <http://www.capi.org/>.) CAPI supports making and accepting voice
+ and data connections, controlling call options and protocols,
+ as well as ISDN supplementary services like call forwarding or
+ three-party conferences (if supported by the specific hardware
+ driver).
+
+ Select this option and the appropriate hardware driver below if
+ you have an ISDN adapter supported by the CAPI subsystem.
if ISDN_CAPI
@@ -61,4 +65,13 @@ endif # ISDN_CAPI
source "drivers/isdn/gigaset/Kconfig"
+source "drivers/isdn/hysdn/Kconfig"
+
+source "drivers/isdn/mISDN/Kconfig"
+
+config ISDN_HDLC
+ tristate
+ select CRC_CCITT
+ select BITREVERSE
+
endif # ISDN
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index b2a04755c96a..a168e8a891be 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -17,8 +17,7 @@ config CAPI_TRACE
If unsure, say Y.
config ISDN_CAPI_MIDDLEWARE
- bool "CAPI2.0 Middleware support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ bool "CAPI2.0 Middleware support"
help
This option will enhance the capabilities of the /dev/capi20
interface. It will provide a means of moving a data connection,
@@ -35,18 +34,19 @@ config ISDN_CAPI_CAPI20
Y/M here.
config ISDN_CAPI_CAPIFS_BOOL
- bool "CAPI2.0 filesystem support"
+ bool "CAPI2.0 filesystem support (DEPRECATED)"
depends on ISDN_CAPI_MIDDLEWARE && ISDN_CAPI_CAPI20
+ help
+ This option provides a special file system, similar to /dev/pts with
+ device nodes for the special ttys established by using the
+ middleware extension above.
+ You no longer need this, udev fully replaces it. This feature is
+ scheduled for removal.
config ISDN_CAPI_CAPIFS
tristate
depends on ISDN_CAPI_CAPIFS_BOOL
default ISDN_CAPI_CAPI20
- help
- This option provides a special file system, similar to /dev/pts with
- device nodes for the special ttys established by using the
- middleware extension above. If you want to use pppd with
- pppdcapiplugin to dial up to your ISP, say Y here.
config ISDN_CAPI_CAPIDRV
tristate "CAPI2.0 capidrv interface support"
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 65bf91e16a42..ee5837522f5a 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -23,16 +23,13 @@
#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/wait.h>
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
#include <linux/tty.h>
-#ifdef CONFIG_PPP
#include <linux/netdevice.h>
#include <linux/ppp_defs.h>
#include <linux/if_ppp.h>
-#endif /* CONFIG_PPP */
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
@@ -41,35 +38,29 @@
#include <linux/moduleparam.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capicmd.h>
-#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
-#include "capifs.h"
-#endif
-static char *revision = "$Revision: 1.1.2.7 $";
+#include "capifs.h"
MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
-#undef _DEBUG_REFCOUNT /* alloc/free and open/close debug */
#undef _DEBUG_TTYFUNCS /* call to tty_driver */
#undef _DEBUG_DATAFLOW /* data flow */
/* -------- driver information -------------------------------------- */
static struct class *capi_class;
-
static int capi_major = 68; /* allocated */
+
+module_param_named(major, capi_major, uint, 0);
+
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-#define CAPINC_NR_PORTS 32
+#define CAPINC_NR_PORTS 32
#define CAPINC_MAX_PORTS 256
-static int capi_ttymajor = 191;
+
static int capi_ttyminors = CAPINC_NR_PORTS;
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-module_param_named(major, capi_major, uint, 0);
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-module_param_named(ttymajor, capi_ttymajor, uint, 0);
module_param_named(ttyminors, capi_ttyminors, uint, 0);
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
@@ -83,53 +74,43 @@ module_param_named(ttyminors, capi_ttyminors, uint, 0);
struct capidev;
struct capincci;
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
struct capiminor;
-struct datahandle_queue {
+struct ackqueue_entry {
struct list_head list;
u16 datahandle;
};
struct capiminor {
- struct list_head list;
- struct capincci *nccip;
+ struct kref kref;
+
unsigned int minor;
+ struct dentry *capifs_dentry;
- struct capi20_appl *ap;
- u32 ncci;
- u16 datahandle;
- u16 msgid;
+ struct capi20_appl *ap;
+ u32 ncci;
+ atomic_t datahandle;
+ atomic_t msgid;
- struct tty_struct *tty;
+ struct tty_port port;
int ttyinstop;
int ttyoutstop;
- struct sk_buff *ttyskb;
- atomic_t ttyopencount;
- struct sk_buff_head inqueue;
- int inbytes;
- struct sk_buff_head outqueue;
- int outbytes;
+ struct sk_buff_head inqueue;
+
+ struct sk_buff_head outqueue;
+ int outbytes;
+ struct sk_buff *outskb;
+ spinlock_t outlock;
/* transmit path */
struct list_head ackqueue;
int nack;
spinlock_t ackqlock;
};
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-
-/* FIXME: The following lock is a sledgehammer-workaround to a
- * locking issue with the capiminor (and maybe other) data structure(s).
- * Access to this data is done in a racy way and crashes the machine with
- * a FritzCard DSL driver; sooner or later. This is a workaround
- * which trades scalability vs stability, so it doesn't crash the kernel anymore.
- * The correct (and scalable) fix for the issue seems to require
- * an API change to the drivers... . */
-static DEFINE_SPINLOCK(workaround_lock);
struct capincci {
- struct capincci *next;
+ struct list_head list;
u32 ncci;
struct capidev *cdev;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -146,28 +127,28 @@ struct capidev {
struct sk_buff_head recvqueue;
wait_queue_head_t recvwait;
- struct capincci *nccis;
+ struct list_head nccis;
- struct mutex ncci_list_mtx;
+ struct mutex lock;
};
/* -------- global variables ---------------------------------------- */
-static DEFINE_RWLOCK(capidev_list_lock);
+static DEFINE_MUTEX(capidev_list_lock);
static LIST_HEAD(capidev_list);
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-static DEFINE_RWLOCK(capiminor_list_lock);
-static LIST_HEAD(capiminor_list);
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+static DEFINE_SPINLOCK(capiminors_lock);
+static struct capiminor **capiminors;
+
+static struct tty_driver *capinc_tty_driver;
+
/* -------- datahandles --------------------------------------------- */
-static int capincci_add_ack(struct capiminor *mp, u16 datahandle)
+static int capiminor_add_ack(struct capiminor *mp, u16 datahandle)
{
- struct datahandle_queue *n;
- unsigned long flags;
+ struct ackqueue_entry *n;
n = kmalloc(sizeof(*n), GFP_ATOMIC);
if (unlikely(!n)) {
@@ -176,253 +157,246 @@ static int capincci_add_ack(struct capiminor *mp, u16 datahandle)
}
n->datahandle = datahandle;
INIT_LIST_HEAD(&n->list);
- spin_lock_irqsave(&mp->ackqlock, flags);
+ spin_lock_bh(&mp->ackqlock);
list_add_tail(&n->list, &mp->ackqueue);
mp->nack++;
- spin_unlock_irqrestore(&mp->ackqlock, flags);
+ spin_unlock_bh(&mp->ackqlock);
return 0;
}
static int capiminor_del_ack(struct capiminor *mp, u16 datahandle)
{
- struct datahandle_queue *p, *tmp;
- unsigned long flags;
+ struct ackqueue_entry *p, *tmp;
- spin_lock_irqsave(&mp->ackqlock, flags);
+ spin_lock_bh(&mp->ackqlock);
list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
if (p->datahandle == datahandle) {
list_del(&p->list);
- kfree(p);
mp->nack--;
- spin_unlock_irqrestore(&mp->ackqlock, flags);
+ spin_unlock_bh(&mp->ackqlock);
+ kfree(p);
return 0;
}
}
- spin_unlock_irqrestore(&mp->ackqlock, flags);
+ spin_unlock_bh(&mp->ackqlock);
return -1;
}
static void capiminor_del_all_ack(struct capiminor *mp)
{
- struct datahandle_queue *p, *tmp;
- unsigned long flags;
+ struct ackqueue_entry *p, *tmp;
- spin_lock_irqsave(&mp->ackqlock, flags);
list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
list_del(&p->list);
kfree(p);
mp->nack--;
}
- spin_unlock_irqrestore(&mp->ackqlock, flags);
}
/* -------- struct capiminor ---------------------------------------- */
+static const struct tty_port_operations capiminor_port_ops; /* we have none */
+
static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
{
- struct capiminor *mp, *p;
- unsigned int minor = 0;
- unsigned long flags;
+ struct capiminor *mp;
+ struct device *dev;
+ unsigned int minor;
- mp = kzalloc(sizeof(*mp), GFP_ATOMIC);
+ mp = kzalloc(sizeof(*mp), GFP_KERNEL);
if (!mp) {
printk(KERN_ERR "capi: can't alloc capiminor\n");
return NULL;
}
+ kref_init(&mp->kref);
+
mp->ap = ap;
mp->ncci = ncci;
- mp->msgid = 0;
- atomic_set(&mp->ttyopencount,0);
INIT_LIST_HEAD(&mp->ackqueue);
spin_lock_init(&mp->ackqlock);
skb_queue_head_init(&mp->inqueue);
skb_queue_head_init(&mp->outqueue);
+ spin_lock_init(&mp->outlock);
- /* Allocate the least unused minor number.
- */
- write_lock_irqsave(&capiminor_list_lock, flags);
- if (list_empty(&capiminor_list))
- list_add(&mp->list, &capiminor_list);
- else {
- list_for_each_entry(p, &capiminor_list, list) {
- if (p->minor > minor)
- break;
- minor++;
- }
-
- if (minor < capi_ttyminors) {
- mp->minor = minor;
- list_add(&mp->list, p->list.prev);
+ tty_port_init(&mp->port);
+ mp->port.ops = &capiminor_port_ops;
+
+ /* Allocate the least unused minor number. */
+ spin_lock(&capiminors_lock);
+ for (minor = 0; minor < capi_ttyminors; minor++)
+ if (!capiminors[minor]) {
+ capiminors[minor] = mp;
+ break;
}
- }
- write_unlock_irqrestore(&capiminor_list_lock, flags);
+ spin_unlock(&capiminors_lock);
- if (!(minor < capi_ttyminors)) {
+ if (minor == capi_ttyminors) {
printk(KERN_NOTICE "capi: out of minors\n");
- kfree(mp);
- return NULL;
+ goto err_out1;
}
+ mp->minor = minor;
+
+ dev = tty_register_device(capinc_tty_driver, minor, NULL);
+ if (IS_ERR(dev))
+ goto err_out2;
+
return mp;
+
+err_out2:
+ spin_lock(&capiminors_lock);
+ capiminors[minor] = NULL;
+ spin_unlock(&capiminors_lock);
+
+err_out1:
+ kfree(mp);
+ return NULL;
}
-static void capiminor_free(struct capiminor *mp)
+static void capiminor_destroy(struct kref *kref)
{
- unsigned long flags;
-
- write_lock_irqsave(&capiminor_list_lock, flags);
- list_del(&mp->list);
- write_unlock_irqrestore(&capiminor_list_lock, flags);
+ struct capiminor *mp = container_of(kref, struct capiminor, kref);
- kfree_skb(mp->ttyskb);
- mp->ttyskb = NULL;
+ kfree_skb(mp->outskb);
skb_queue_purge(&mp->inqueue);
skb_queue_purge(&mp->outqueue);
capiminor_del_all_ack(mp);
kfree(mp);
}
-static struct capiminor *capiminor_find(unsigned int minor)
+static struct capiminor *capiminor_get(unsigned int minor)
{
- struct list_head *l;
- struct capiminor *p = NULL;
+ struct capiminor *mp;
- read_lock(&capiminor_list_lock);
- list_for_each(l, &capiminor_list) {
- p = list_entry(l, struct capiminor, list);
- if (p->minor == minor)
- break;
- }
- read_unlock(&capiminor_list_lock);
- if (l == &capiminor_list)
- return NULL;
+ spin_lock(&capiminors_lock);
+ mp = capiminors[minor];
+ if (mp)
+ kref_get(&mp->kref);
+ spin_unlock(&capiminors_lock);
- return p;
+ return mp;
+}
+
+static inline void capiminor_put(struct capiminor *mp)
+{
+ kref_put(&mp->kref, capiminor_destroy);
+}
+
+static void capiminor_free(struct capiminor *mp)
+{
+ tty_unregister_device(capinc_tty_driver, mp->minor);
+
+ spin_lock(&capiminors_lock);
+ capiminors[mp->minor] = NULL;
+ spin_unlock(&capiminors_lock);
+
+ capiminor_put(mp);
}
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
/* -------- struct capincci ----------------------------------------- */
-static struct capincci *capincci_alloc(struct capidev *cdev, u32 ncci)
+static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np)
{
- struct capincci *np, **pp;
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- struct capiminor *mp = NULL;
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ struct capiminor *mp;
+ dev_t device;
- np = kzalloc(sizeof(*np), GFP_ATOMIC);
- if (!np)
- return NULL;
- np->ncci = ncci;
- np->cdev = cdev;
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- mp = NULL;
- if (cdev->userflags & CAPIFLAG_HIGHJACKING)
- mp = np->minorp = capiminor_alloc(&cdev->ap, ncci);
+ if (!(cdev->userflags & CAPIFLAG_HIGHJACKING))
+ return;
+
+ mp = np->minorp = capiminor_alloc(&cdev->ap, np->ncci);
if (mp) {
- mp->nccip = np;
-#ifdef _DEBUG_REFCOUNT
- printk(KERN_DEBUG "set mp->nccip\n");
-#endif
-#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
- capifs_new_ncci(mp->minor, MKDEV(capi_ttymajor, mp->minor));
-#endif
+ device = MKDEV(capinc_tty_driver->major, mp->minor);
+ mp->capifs_dentry = capifs_new_ncci(mp->minor, device);
}
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- for (pp=&cdev->nccis; *pp; pp = &(*pp)->next)
- ;
- *pp = np;
- return np;
}
-static void capincci_free(struct capidev *cdev, u32 ncci)
+static void capincci_free_minor(struct capincci *np)
{
- struct capincci *np, **pp;
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- struct capiminor *mp;
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ struct capiminor *mp = np->minorp;
+ struct tty_struct *tty;
- pp=&cdev->nccis;
- while (*pp) {
- np = *pp;
- if (ncci == 0xffffffff || np->ncci == ncci) {
- *pp = (*pp)->next;
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- if ((mp = np->minorp) != NULL) {
-#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
- capifs_free_ncci(mp->minor);
-#endif
- if (mp->tty) {
- mp->nccip = NULL;
-#ifdef _DEBUG_REFCOUNT
- printk(KERN_DEBUG "reset mp->nccip\n");
-#endif
- tty_hangup(mp->tty);
- } else {
- capiminor_free(mp);
- }
- }
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- kfree(np);
- if (*pp == NULL) return;
- } else {
- pp = &(*pp)->next;
+ if (mp) {
+ capifs_free_ncci(mp->capifs_dentry);
+
+ tty = tty_port_tty_get(&mp->port);
+ if (tty) {
+ tty_vhangup(tty);
+ tty_kref_put(tty);
}
+
+ capiminor_free(mp);
}
}
-static struct capincci *capincci_find(struct capidev *cdev, u32 ncci)
+static inline unsigned int capincci_minor_opencount(struct capincci *np)
{
- struct capincci *p;
+ struct capiminor *mp = np->minorp;
+ unsigned int count = 0;
+ struct tty_struct *tty;
- for (p=cdev->nccis; p ; p = p->next) {
- if (p->ncci == ncci)
- break;
+ if (mp) {
+ tty = tty_port_tty_get(&mp->port);
+ if (tty) {
+ count = tty->count;
+ tty_kref_put(tty);
+ }
}
- return p;
+ return count;
}
-/* -------- struct capidev ------------------------------------------ */
+#else /* !CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+static inline void
+capincci_alloc_minor(struct capidev *cdev, struct capincci *np) { }
+static inline void capincci_free_minor(struct capincci *np) { }
-static struct capidev *capidev_alloc(void)
+static inline unsigned int capincci_minor_opencount(struct capincci *np)
{
- struct capidev *cdev;
- unsigned long flags;
+ return 0;
+}
- cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
- if (!cdev)
+#endif /* !CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+static struct capincci *capincci_alloc(struct capidev *cdev, u32 ncci)
+{
+ struct capincci *np;
+
+ np = kzalloc(sizeof(*np), GFP_KERNEL);
+ if (!np)
return NULL;
+ np->ncci = ncci;
+ np->cdev = cdev;
- mutex_init(&cdev->ncci_list_mtx);
- skb_queue_head_init(&cdev->recvqueue);
- init_waitqueue_head(&cdev->recvwait);
- write_lock_irqsave(&capidev_list_lock, flags);
- list_add_tail(&cdev->list, &capidev_list);
- write_unlock_irqrestore(&capidev_list_lock, flags);
- return cdev;
+ capincci_alloc_minor(cdev, np);
+
+ list_add_tail(&np->list, &cdev->nccis);
+
+ return np;
}
-static void capidev_free(struct capidev *cdev)
+static void capincci_free(struct capidev *cdev, u32 ncci)
{
- unsigned long flags;
+ struct capincci *np, *tmp;
- if (cdev->ap.applid) {
- capi20_release(&cdev->ap);
- cdev->ap.applid = 0;
- }
- skb_queue_purge(&cdev->recvqueue);
+ list_for_each_entry_safe(np, tmp, &cdev->nccis, list)
+ if (ncci == 0xffffffff || np->ncci == ncci) {
+ capincci_free_minor(np);
+ list_del(&np->list);
+ kfree(np);
+ }
+}
- mutex_lock(&cdev->ncci_list_mtx);
- capincci_free(cdev, 0xffffffff);
- mutex_unlock(&cdev->ncci_list_mtx);
+static struct capincci *capincci_find(struct capidev *cdev, u32 ncci)
+{
+ struct capincci *np;
- write_lock_irqsave(&capidev_list_lock, flags);
- list_del(&cdev->list);
- write_unlock_irqrestore(&capidev_list_lock, flags);
- kfree(cdev);
+ list_for_each_entry(np, &cdev->nccis, list)
+ if (np->ncci == ncci)
+ return np;
+ return NULL;
}
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -432,7 +406,7 @@ static struct sk_buff *
gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
{
struct sk_buff *nskb;
- nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_ATOMIC);
+ nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_KERNEL);
if (nskb) {
u16 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4+4+2);
unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN);
@@ -440,7 +414,7 @@ gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
capimsg_setu16(s, 2, mp->ap->applid);
capimsg_setu8 (s, 4, CAPI_DATA_B3);
capimsg_setu8 (s, 5, CAPI_RESP);
- capimsg_setu16(s, 6, mp->msgid++);
+ capimsg_setu16(s, 6, atomic_inc_return(&mp->msgid));
capimsg_setu32(s, 8, mp->ncci);
capimsg_setu16(s, 12, datahandle);
}
@@ -449,122 +423,156 @@ gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
{
+ unsigned int datalen = skb->len - CAPIMSG_LEN(skb->data);
+ struct tty_struct *tty;
struct sk_buff *nskb;
- int datalen;
u16 errcode, datahandle;
struct tty_ldisc *ld;
-
- datalen = skb->len - CAPIMSG_LEN(skb->data);
- if (mp->tty == NULL)
- {
+ int ret = -1;
+
+ tty = tty_port_tty_get(&mp->port);
+ if (!tty) {
#ifdef _DEBUG_DATAFLOW
printk(KERN_DEBUG "capi: currently no receiver\n");
#endif
return -1;
}
- ld = tty_ldisc_ref(mp->tty);
- if (ld == NULL)
- return -1;
+ ld = tty_ldisc_ref(tty);
+ if (!ld) {
+ /* fatal error, do not requeue */
+ ret = 0;
+ kfree_skb(skb);
+ goto deref_tty;
+ }
+
if (ld->ops->receive_buf == NULL) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
#endif
- goto bad;
+ /* fatal error, do not requeue */
+ goto free_skb;
}
if (mp->ttyinstop) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: recv tty throttled\n");
#endif
- goto bad;
+ goto deref_ldisc;
}
- if (mp->tty->receive_room < datalen) {
+
+ if (tty->receive_room < datalen) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: no room in tty\n");
#endif
- goto bad;
+ goto deref_ldisc;
}
- if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) {
+
+ nskb = gen_data_b3_resp_for(mp, skb);
+ if (!nskb) {
printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
- goto bad;
+ goto deref_ldisc;
}
- datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
+
+ datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4);
+
errcode = capi20_put_message(mp->ap, nskb);
- if (errcode != CAPI_NOERROR) {
+
+ if (errcode == CAPI_NOERROR) {
+ skb_pull(skb, CAPIMSG_LEN(skb->data));
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
+ datahandle, skb->len);
+#endif
+ ld->ops->receive_buf(tty, skb->data, NULL, skb->len);
+ } else {
printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
errcode);
kfree_skb(nskb);
- goto bad;
+
+ if (errcode == CAPI_SENDQUEUEFULL)
+ goto deref_ldisc;
}
- (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
-#ifdef _DEBUG_DATAFLOW
- printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
- datahandle, skb->len);
-#endif
- ld->ops->receive_buf(mp->tty, skb->data, NULL, skb->len);
+
+free_skb:
+ ret = 0;
kfree_skb(skb);
+
+deref_ldisc:
tty_ldisc_deref(ld);
- return 0;
-bad:
- tty_ldisc_deref(ld);
- return -1;
+
+deref_tty:
+ tty_kref_put(tty);
+ return ret;
}
static void handle_minor_recv(struct capiminor *mp)
{
struct sk_buff *skb;
- while ((skb = skb_dequeue(&mp->inqueue)) != NULL) {
- unsigned int len = skb->len;
- mp->inbytes -= len;
+
+ while ((skb = skb_dequeue(&mp->inqueue)) != NULL)
if (handle_recv_skb(mp, skb) < 0) {
skb_queue_head(&mp->inqueue, skb);
- mp->inbytes += len;
return;
}
- }
}
-static int handle_minor_send(struct capiminor *mp)
+static void handle_minor_send(struct capiminor *mp)
{
+ struct tty_struct *tty;
struct sk_buff *skb;
u16 len;
- int count = 0;
u16 errcode;
u16 datahandle;
- if (mp->tty && mp->ttyoutstop) {
+ tty = tty_port_tty_get(&mp->port);
+ if (!tty)
+ return;
+
+ if (mp->ttyoutstop) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: send: tty stopped\n");
#endif
- return 0;
+ tty_kref_put(tty);
+ return;
}
- while ((skb = skb_dequeue(&mp->outqueue)) != NULL) {
- datahandle = mp->datahandle;
+ while (1) {
+ spin_lock_bh(&mp->outlock);
+ skb = __skb_dequeue(&mp->outqueue);
+ if (!skb) {
+ spin_unlock_bh(&mp->outlock);
+ break;
+ }
len = (u16)skb->len;
+ mp->outbytes -= len;
+ spin_unlock_bh(&mp->outlock);
+
+ datahandle = atomic_inc_return(&mp->datahandle);
skb_push(skb, CAPI_DATA_B3_REQ_LEN);
memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
capimsg_setu16(skb->data, 2, mp->ap->applid);
capimsg_setu8 (skb->data, 4, CAPI_DATA_B3);
capimsg_setu8 (skb->data, 5, CAPI_REQ);
- capimsg_setu16(skb->data, 6, mp->msgid++);
+ capimsg_setu16(skb->data, 6, atomic_inc_return(&mp->msgid));
capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */
capimsg_setu32(skb->data, 12, (u32)(long)skb->data);/* Data32 */
capimsg_setu16(skb->data, 16, len); /* Data length */
capimsg_setu16(skb->data, 18, datahandle);
capimsg_setu16(skb->data, 20, 0); /* Flags */
- if (capincci_add_ack(mp, datahandle) < 0) {
+ if (capiminor_add_ack(mp, datahandle) < 0) {
skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
- skb_queue_head(&mp->outqueue, skb);
- return count;
+
+ spin_lock_bh(&mp->outlock);
+ __skb_queue_head(&mp->outqueue, skb);
+ mp->outbytes += len;
+ spin_unlock_bh(&mp->outlock);
+
+ break;
}
errcode = capi20_put_message(mp->ap, skb);
if (errcode == CAPI_NOERROR) {
- mp->datahandle++;
- count++;
- mp->outbytes -= len;
#ifdef _DEBUG_DATAFLOW
printk(KERN_DEBUG "capi: DATA_B3_REQ %u len=%u\n",
datahandle, len);
@@ -575,16 +583,20 @@ static int handle_minor_send(struct capiminor *mp)
if (errcode == CAPI_SENDQUEUEFULL) {
skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
- skb_queue_head(&mp->outqueue, skb);
+
+ spin_lock_bh(&mp->outlock);
+ __skb_queue_head(&mp->outqueue, skb);
+ mp->outbytes += len;
+ spin_unlock_bh(&mp->outlock);
+
break;
}
/* ups, drop packet */
printk(KERN_ERR "capi: put_message = %x\n", errcode);
- mp->outbytes -= len;
kfree_skb(skb);
}
- return count;
+ tty_kref_put(tty);
}
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
@@ -594,65 +606,56 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
{
struct capidev *cdev = ap->private;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ struct tty_struct *tty;
struct capiminor *mp;
u16 datahandle;
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
struct capincci *np;
- u32 ncci;
- unsigned long flags;
+
+ mutex_lock(&cdev->lock);
if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) {
u16 info = CAPIMSG_U16(skb->data, 12); // Info field
- if ((info & 0xff00) == 0) {
- mutex_lock(&cdev->ncci_list_mtx);
+ if ((info & 0xff00) == 0)
capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
- mutex_unlock(&cdev->ncci_list_mtx);
- }
}
- if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND) {
- mutex_lock(&cdev->ncci_list_mtx);
+ if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND)
capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
- mutex_unlock(&cdev->ncci_list_mtx);
- }
- spin_lock_irqsave(&workaround_lock, flags);
+
if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
skb_queue_tail(&cdev->recvqueue, skb);
wake_up_interruptible(&cdev->recvwait);
- spin_unlock_irqrestore(&workaround_lock, flags);
- return;
+ goto unlock_out;
}
- ncci = CAPIMSG_CONTROL(skb->data);
- for (np = cdev->nccis; np && np->ncci != ncci; np = np->next)
- ;
+
+ np = capincci_find(cdev, CAPIMSG_CONTROL(skb->data));
if (!np) {
printk(KERN_ERR "BUG: capi_signal: ncci not found\n");
skb_queue_tail(&cdev->recvqueue, skb);
wake_up_interruptible(&cdev->recvwait);
- spin_unlock_irqrestore(&workaround_lock, flags);
- return;
+ goto unlock_out;
}
+
#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
skb_queue_tail(&cdev->recvqueue, skb);
wake_up_interruptible(&cdev->recvwait);
+
#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
mp = np->minorp;
if (!mp) {
skb_queue_tail(&cdev->recvqueue, skb);
wake_up_interruptible(&cdev->recvwait);
- spin_unlock_irqrestore(&workaround_lock, flags);
- return;
+ goto unlock_out;
}
-
-
if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
-
datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2);
#ifdef _DEBUG_DATAFLOW
printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n",
datahandle, skb->len-CAPIMSG_LEN(skb->data));
#endif
skb_queue_tail(&mp->inqueue, skb);
- mp->inbytes += skb->len;
+
handle_minor_recv(mp);
} else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) {
@@ -664,10 +667,13 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2));
#endif
kfree_skb(skb);
- (void)capiminor_del_ack(mp, datahandle);
- if (mp->tty)
- tty_wakeup(mp->tty);
- (void)handle_minor_send(mp);
+ capiminor_del_ack(mp, datahandle);
+ tty = tty_port_tty_get(&mp->port);
+ if (tty) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
+ }
+ handle_minor_send(mp);
} else {
/* ups, let capi application handle it :-) */
@@ -675,7 +681,9 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
wake_up_interruptible(&cdev->recvwait);
}
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- spin_unlock_irqrestore(&workaround_lock, flags);
+
+unlock_out:
+ mutex_unlock(&cdev->lock);
}
/* -------- file_operations for capidev ----------------------------- */
@@ -686,24 +694,19 @@ capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
struct capidev *cdev = (struct capidev *)file->private_data;
struct sk_buff *skb;
size_t copied;
+ int err;
if (!cdev->ap.applid)
return -ENODEV;
- if ((skb = skb_dequeue(&cdev->recvqueue)) == NULL) {
-
+ skb = skb_dequeue(&cdev->recvqueue);
+ if (!skb) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
-
- for (;;) {
- interruptible_sleep_on(&cdev->recvwait);
- if ((skb = skb_dequeue(&cdev->recvqueue)) != NULL)
- break;
- if (signal_pending(current))
- break;
- }
- if (skb == NULL)
- return -ERESTARTNOHAND;
+ err = wait_event_interruptible(cdev->recvwait,
+ (skb = skb_dequeue(&cdev->recvqueue)));
+ if (err)
+ return err;
}
if (skb->len > count) {
skb_queue_head(&cdev->recvqueue, skb);
@@ -753,9 +756,9 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos
CAPIMSG_SETAPPID(skb->data, cdev->ap.applid);
if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) {
- mutex_lock(&cdev->ncci_list_mtx);
+ mutex_lock(&cdev->lock);
capincci_free(cdev, CAPIMSG_NCCI(skb->data));
- mutex_unlock(&cdev->ncci_list_mtx);
+ mutex_unlock(&cdev->lock);
}
cdev->errcode = capi20_put_message(&cdev->ap, skb);
@@ -788,30 +791,35 @@ capi_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct capidev *cdev = file->private_data;
- struct capi20_appl *ap = &cdev->ap;
capi_ioctl_struct data;
int retval = -EINVAL;
void __user *argp = (void __user *)arg;
switch (cmd) {
case CAPI_REGISTER:
- {
- if (ap->applid)
- return -EEXIST;
+ mutex_lock(&cdev->lock);
- if (copy_from_user(&cdev->ap.rparam, argp,
- sizeof(struct capi_register_params)))
- return -EFAULT;
-
- cdev->ap.private = cdev;
- cdev->ap.recv_message = capi_recv_message;
- cdev->errcode = capi20_register(ap);
- if (cdev->errcode) {
- ap->applid = 0;
- return -EIO;
- }
+ if (cdev->ap.applid) {
+ retval = -EEXIST;
+ goto register_out;
+ }
+ if (copy_from_user(&cdev->ap.rparam, argp,
+ sizeof(struct capi_register_params))) {
+ retval = -EFAULT;
+ goto register_out;
+ }
+ cdev->ap.private = cdev;
+ cdev->ap.recv_message = capi_recv_message;
+ cdev->errcode = capi20_register(&cdev->ap);
+ retval = (int)cdev->ap.applid;
+ if (cdev->errcode) {
+ cdev->ap.applid = 0;
+ retval = -EIO;
}
- return (int)ap->applid;
+
+register_out:
+ mutex_unlock(&cdev->lock);
+ return retval;
case CAPI_GET_VERSION:
{
@@ -910,101 +918,104 @@ capi_ioctl(struct inode *inode, struct file *file,
return 0;
case CAPI_SET_FLAGS:
- case CAPI_CLR_FLAGS:
- {
- unsigned userflags;
- if (copy_from_user(&userflags, argp,
- sizeof(userflags)))
- return -EFAULT;
- if (cmd == CAPI_SET_FLAGS)
- cdev->userflags |= userflags;
- else
- cdev->userflags &= ~userflags;
- }
- return 0;
+ case CAPI_CLR_FLAGS: {
+ unsigned userflags;
+
+ if (copy_from_user(&userflags, argp, sizeof(userflags)))
+ return -EFAULT;
+ mutex_lock(&cdev->lock);
+ if (cmd == CAPI_SET_FLAGS)
+ cdev->userflags |= userflags;
+ else
+ cdev->userflags &= ~userflags;
+ mutex_unlock(&cdev->lock);
+ return 0;
+ }
case CAPI_GET_FLAGS:
if (copy_to_user(argp, &cdev->userflags,
sizeof(cdev->userflags)))
return -EFAULT;
return 0;
- case CAPI_NCCI_OPENCOUNT:
- {
- struct capincci *nccip;
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- struct capiminor *mp;
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- unsigned ncci;
- int count = 0;
- if (copy_from_user(&ncci, argp, sizeof(ncci)))
- return -EFAULT;
+ case CAPI_NCCI_OPENCOUNT: {
+ struct capincci *nccip;
+ unsigned ncci;
+ int count = 0;
- mutex_lock(&cdev->ncci_list_mtx);
- if ((nccip = capincci_find(cdev, (u32) ncci)) == NULL) {
- mutex_unlock(&cdev->ncci_list_mtx);
- return 0;
- }
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- if ((mp = nccip->minorp) != NULL) {
- count += atomic_read(&mp->ttyopencount);
- }
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- mutex_unlock(&cdev->ncci_list_mtx);
- return count;
- }
- return 0;
+ if (copy_from_user(&ncci, argp, sizeof(ncci)))
+ return -EFAULT;
+
+ mutex_lock(&cdev->lock);
+ nccip = capincci_find(cdev, (u32)ncci);
+ if (nccip)
+ count = capincci_minor_opencount(nccip);
+ mutex_unlock(&cdev->lock);
+ return count;
+ }
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- case CAPI_NCCI_GETUNIT:
- {
- struct capincci *nccip;
- struct capiminor *mp;
- unsigned ncci;
- int unit = 0;
- if (copy_from_user(&ncci, argp,
- sizeof(ncci)))
- return -EFAULT;
- mutex_lock(&cdev->ncci_list_mtx);
- nccip = capincci_find(cdev, (u32) ncci);
- if (!nccip || (mp = nccip->minorp) == NULL) {
- mutex_unlock(&cdev->ncci_list_mtx);
- return -ESRCH;
- }
- unit = mp->minor;
- mutex_unlock(&cdev->ncci_list_mtx);
- return unit;
+ case CAPI_NCCI_GETUNIT: {
+ struct capincci *nccip;
+ struct capiminor *mp;
+ unsigned ncci;
+ int unit = -ESRCH;
+
+ if (copy_from_user(&ncci, argp, sizeof(ncci)))
+ return -EFAULT;
+
+ mutex_lock(&cdev->lock);
+ nccip = capincci_find(cdev, (u32)ncci);
+ if (nccip) {
+ mp = nccip->minorp;
+ if (mp)
+ unit = mp->minor;
}
- return 0;
+ mutex_unlock(&cdev->lock);
+ return unit;
+ }
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+ default:
+ return -EINVAL;
}
- return -EINVAL;
}
-static int
-capi_open(struct inode *inode, struct file *file)
+static int capi_open(struct inode *inode, struct file *file)
{
- int ret;
-
- lock_kernel();
- if (file->private_data)
- ret = -EEXIST;
- else if ((file->private_data = capidev_alloc()) == NULL)
- ret = -ENOMEM;
- else
- ret = nonseekable_open(inode, file);
- unlock_kernel();
- return ret;
+ struct capidev *cdev;
+
+ cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+ if (!cdev)
+ return -ENOMEM;
+
+ mutex_init(&cdev->lock);
+ skb_queue_head_init(&cdev->recvqueue);
+ init_waitqueue_head(&cdev->recvwait);
+ INIT_LIST_HEAD(&cdev->nccis);
+ file->private_data = cdev;
+
+ mutex_lock(&capidev_list_lock);
+ list_add_tail(&cdev->list, &capidev_list);
+ mutex_unlock(&capidev_list_lock);
+
+ return nonseekable_open(inode, file);
}
-static int
-capi_release(struct inode *inode, struct file *file)
+static int capi_release(struct inode *inode, struct file *file)
{
- struct capidev *cdev = (struct capidev *)file->private_data;
+ struct capidev *cdev = file->private_data;
- capidev_free(cdev);
- file->private_data = NULL;
-
+ mutex_lock(&capidev_list_lock);
+ list_del(&cdev->list);
+ mutex_unlock(&capidev_list_lock);
+
+ if (cdev->ap.applid)
+ capi20_release(&cdev->ap);
+ skb_queue_purge(&cdev->recvqueue);
+ capincci_free(cdev, 0xffffffff);
+
+ kfree(cdev);
return 0;
}
@@ -1023,182 +1034,159 @@ static const struct file_operations capi_fops =
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
/* -------- tty_operations for capincci ----------------------------- */
-static int capinc_tty_open(struct tty_struct * tty, struct file * file)
+static int
+capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{
- struct capiminor *mp;
- unsigned long flags;
+ int idx = tty->index;
+ struct capiminor *mp = capiminor_get(idx);
+ int ret = tty_init_termios(tty);
+
+ if (ret == 0) {
+ tty_driver_kref_get(driver);
+ tty->count++;
+ tty->driver_data = mp;
+ driver->ttys[idx] = tty;
+ } else
+ capiminor_put(mp);
+ return ret;
+}
- if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == NULL)
- return -ENXIO;
- if (mp->nccip == NULL)
- return -ENXIO;
+static void capinc_tty_cleanup(struct tty_struct *tty)
+{
+ struct capiminor *mp = tty->driver_data;
+ tty->driver_data = NULL;
+ capiminor_put(mp);
+}
- tty->driver_data = (void *)mp;
+static int capinc_tty_open(struct tty_struct *tty, struct file *filp)
+{
+ struct capiminor *mp = tty->driver_data;
+ int err;
+
+ err = tty_port_open(&mp->port, tty, filp);
+ if (err)
+ return err;
- spin_lock_irqsave(&workaround_lock, flags);
- if (atomic_read(&mp->ttyopencount) == 0)
- mp->tty = tty;
- atomic_inc(&mp->ttyopencount);
-#ifdef _DEBUG_REFCOUNT
- printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount));
-#endif
handle_minor_recv(mp);
- spin_unlock_irqrestore(&workaround_lock, flags);
return 0;
}
-static void capinc_tty_close(struct tty_struct * tty, struct file * file)
+static void capinc_tty_close(struct tty_struct *tty, struct file *filp)
{
- struct capiminor *mp;
-
- mp = (struct capiminor *)tty->driver_data;
- if (mp) {
- if (atomic_dec_and_test(&mp->ttyopencount)) {
-#ifdef _DEBUG_REFCOUNT
- printk(KERN_DEBUG "capinc_tty_close lastclose\n");
-#endif
- tty->driver_data = NULL;
- mp->tty = NULL;
- }
-#ifdef _DEBUG_REFCOUNT
- printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount));
-#endif
- if (mp->nccip == NULL)
- capiminor_free(mp);
- }
+ struct capiminor *mp = tty->driver_data;
-#ifdef _DEBUG_REFCOUNT
- printk(KERN_DEBUG "capinc_tty_close\n");
-#endif
+ tty_port_close(&mp->port, tty, filp);
}
-static int capinc_tty_write(struct tty_struct * tty,
+static int capinc_tty_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
- struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ struct capiminor *mp = tty->driver_data;
struct sk_buff *skb;
- unsigned long flags;
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_write(count=%d)\n", count);
#endif
- if (!mp || !mp->nccip) {
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_write: mp or mp->ncci NULL\n");
-#endif
- return 0;
- }
-
- spin_lock_irqsave(&workaround_lock, flags);
- skb = mp->ttyskb;
+ spin_lock_bh(&mp->outlock);
+ skb = mp->outskb;
if (skb) {
- mp->ttyskb = NULL;
- skb_queue_tail(&mp->outqueue, skb);
+ mp->outskb = NULL;
+ __skb_queue_tail(&mp->outqueue, skb);
mp->outbytes += skb->len;
}
skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_ATOMIC);
if (!skb) {
printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n");
- spin_unlock_irqrestore(&workaround_lock, flags);
+ spin_unlock_bh(&mp->outlock);
return -ENOMEM;
}
skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
memcpy(skb_put(skb, count), buf, count);
- skb_queue_tail(&mp->outqueue, skb);
+ __skb_queue_tail(&mp->outqueue, skb);
mp->outbytes += skb->len;
- (void)handle_minor_send(mp);
- (void)handle_minor_recv(mp);
- spin_unlock_irqrestore(&workaround_lock, flags);
+ spin_unlock_bh(&mp->outlock);
+
+ handle_minor_send(mp);
+
return count;
}
static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ struct capiminor *mp = tty->driver_data;
+ bool invoke_send = false;
struct sk_buff *skb;
- unsigned long flags;
int ret = 1;
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
#endif
- if (!mp || !mp->nccip) {
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n");
-#endif
- return 0;
- }
-
- spin_lock_irqsave(&workaround_lock, flags);
- skb = mp->ttyskb;
+ spin_lock_bh(&mp->outlock);
+ skb = mp->outskb;
if (skb) {
if (skb_tailroom(skb) > 0) {
*(skb_put(skb, 1)) = ch;
- spin_unlock_irqrestore(&workaround_lock, flags);
- return 1;
+ goto unlock_out;
}
- mp->ttyskb = NULL;
- skb_queue_tail(&mp->outqueue, skb);
+ mp->outskb = NULL;
+ __skb_queue_tail(&mp->outqueue, skb);
mp->outbytes += skb->len;
- (void)handle_minor_send(mp);
+ invoke_send = true;
}
+
skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+CAPI_MAX_BLKSIZE, GFP_ATOMIC);
if (skb) {
skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
*(skb_put(skb, 1)) = ch;
- mp->ttyskb = skb;
+ mp->outskb = skb;
} else {
printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
ret = 0;
}
- spin_unlock_irqrestore(&workaround_lock, flags);
+
+unlock_out:
+ spin_unlock_bh(&mp->outlock);
+
+ if (invoke_send)
+ handle_minor_send(mp);
+
return ret;
}
static void capinc_tty_flush_chars(struct tty_struct *tty)
{
- struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ struct capiminor *mp = tty->driver_data;
struct sk_buff *skb;
- unsigned long flags;
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_flush_chars\n");
#endif
- if (!mp || !mp->nccip) {
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_flush_chars: mp or mp->ncci NULL\n");
-#endif
- return;
- }
-
- spin_lock_irqsave(&workaround_lock, flags);
- skb = mp->ttyskb;
+ spin_lock_bh(&mp->outlock);
+ skb = mp->outskb;
if (skb) {
- mp->ttyskb = NULL;
- skb_queue_tail(&mp->outqueue, skb);
+ mp->outskb = NULL;
+ __skb_queue_tail(&mp->outqueue, skb);
mp->outbytes += skb->len;
- (void)handle_minor_send(mp);
- }
- (void)handle_minor_recv(mp);
- spin_unlock_irqrestore(&workaround_lock, flags);
+ spin_unlock_bh(&mp->outlock);
+
+ handle_minor_send(mp);
+ } else
+ spin_unlock_bh(&mp->outlock);
+
+ handle_minor_recv(mp);
}
static int capinc_tty_write_room(struct tty_struct *tty)
{
- struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ struct capiminor *mp = tty->driver_data;
int room;
- if (!mp || !mp->nccip) {
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_write_room: mp or mp->ncci NULL\n");
-#endif
- return 0;
- }
+
room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue);
room *= CAPI_MAX_BLKSIZE;
#ifdef _DEBUG_TTYFUNCS
@@ -1209,13 +1197,8 @@ static int capinc_tty_write_room(struct tty_struct *tty)
static int capinc_tty_chars_in_buffer(struct tty_struct *tty)
{
- struct capiminor *mp = (struct capiminor *)tty->driver_data;
- if (!mp || !mp->nccip) {
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_chars_in_buffer: mp or mp->ncci NULL\n");
-#endif
- return 0;
- }
+ struct capiminor *mp = tty->driver_data;
+
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n",
mp->outbytes, mp->nack,
@@ -1244,62 +1227,55 @@ static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios * old
#endif
}
-static void capinc_tty_throttle(struct tty_struct * tty)
+static void capinc_tty_throttle(struct tty_struct *tty)
{
- struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ struct capiminor *mp = tty->driver_data;
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_throttle\n");
#endif
- if (mp)
- mp->ttyinstop = 1;
+ mp->ttyinstop = 1;
}
-static void capinc_tty_unthrottle(struct tty_struct * tty)
+static void capinc_tty_unthrottle(struct tty_struct *tty)
{
- struct capiminor *mp = (struct capiminor *)tty->driver_data;
- unsigned long flags;
+ struct capiminor *mp = tty->driver_data;
+
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_unthrottle\n");
#endif
- if (mp) {
- spin_lock_irqsave(&workaround_lock, flags);
- mp->ttyinstop = 0;
- handle_minor_recv(mp);
- spin_unlock_irqrestore(&workaround_lock, flags);
- }
+ mp->ttyinstop = 0;
+ handle_minor_recv(mp);
}
static void capinc_tty_stop(struct tty_struct *tty)
{
- struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ struct capiminor *mp = tty->driver_data;
+
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_stop\n");
#endif
- if (mp) {
- mp->ttyoutstop = 1;
- }
+ mp->ttyoutstop = 1;
}
static void capinc_tty_start(struct tty_struct *tty)
{
- struct capiminor *mp = (struct capiminor *)tty->driver_data;
- unsigned long flags;
+ struct capiminor *mp = tty->driver_data;
+
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_start\n");
#endif
- if (mp) {
- spin_lock_irqsave(&workaround_lock, flags);
- mp->ttyoutstop = 0;
- (void)handle_minor_send(mp);
- spin_unlock_irqrestore(&workaround_lock, flags);
- }
+ mp->ttyoutstop = 0;
+ handle_minor_send(mp);
}
static void capinc_tty_hangup(struct tty_struct *tty)
{
+ struct capiminor *mp = tty->driver_data;
+
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_hangup\n");
#endif
+ tty_port_hangup(&mp->port);
}
static int capinc_tty_break_ctl(struct tty_struct *tty, int state)
@@ -1331,8 +1307,6 @@ static void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
#endif
}
-static struct tty_driver *capinc_tty_driver;
-
static const struct tty_operations capinc_ops = {
.open = capinc_tty_open,
.close = capinc_tty_close,
@@ -1352,25 +1326,34 @@ static const struct tty_operations capinc_ops = {
.flush_buffer = capinc_tty_flush_buffer,
.set_ldisc = capinc_tty_set_ldisc,
.send_xchar = capinc_tty_send_xchar,
+ .install = capinc_tty_install,
+ .cleanup = capinc_tty_cleanup,
};
-static int capinc_tty_init(void)
+static int __init capinc_tty_init(void)
{
struct tty_driver *drv;
-
+ int err;
+
if (capi_ttyminors > CAPINC_MAX_PORTS)
capi_ttyminors = CAPINC_MAX_PORTS;
if (capi_ttyminors <= 0)
capi_ttyminors = CAPINC_NR_PORTS;
- drv = alloc_tty_driver(capi_ttyminors);
- if (!drv)
+ capiminors = kzalloc(sizeof(struct capi_minor *) * capi_ttyminors,
+ GFP_KERNEL);
+ if (!capiminors)
return -ENOMEM;
+ drv = alloc_tty_driver(capi_ttyminors);
+ if (!drv) {
+ kfree(capiminors);
+ return -ENOMEM;
+ }
drv->owner = THIS_MODULE;
drv->driver_name = "capi_nc";
drv->name = "capi";
- drv->major = capi_ttymajor;
+ drv->major = 0;
drv->minor_start = 0;
drv->type = TTY_DRIVER_TYPE_SERIAL;
drv->subtype = SERIAL_TYPE_NORMAL;
@@ -1379,27 +1362,39 @@ static int capinc_tty_init(void)
drv->init_termios.c_oflag = OPOST | ONLCR;
drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
drv->init_termios.c_lflag = 0;
- drv->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_RESET_TERMIOS;
+ drv->flags =
+ TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(drv, &capinc_ops);
- if (tty_register_driver(drv)) {
+
+ err = tty_register_driver(drv);
+ if (err) {
put_tty_driver(drv);
+ kfree(capiminors);
printk(KERN_ERR "Couldn't register capi_nc driver\n");
- return -1;
+ return err;
}
capinc_tty_driver = drv;
return 0;
}
-static void capinc_tty_exit(void)
+static void __exit capinc_tty_exit(void)
{
- struct tty_driver *drv = capinc_tty_driver;
- int retval;
- if ((retval = tty_unregister_driver(drv)))
- printk(KERN_ERR "capi: failed to unregister capi_nc driver (%d)\n", retval);
- put_tty_driver(drv);
+ tty_unregister_driver(capinc_tty_driver);
+ put_tty_driver(capinc_tty_driver);
+ kfree(capiminors);
}
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+#else /* !CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+static inline int capinc_tty_init(void)
+{
+ return 0;
+}
+
+static inline void capinc_tty_exit(void) { }
+
+#endif /* !CONFIG_ISDN_CAPI_MIDDLEWARE */
/* -------- /proc functions ----------------------------------------- */
@@ -1407,134 +1402,91 @@ static void capinc_tty_exit(void)
* /proc/capi/capi20:
* minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
*/
-static int proc_capidev_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int capi20_proc_show(struct seq_file *m, void *v)
{
struct capidev *cdev;
struct list_head *l;
- int len = 0;
- read_lock(&capidev_list_lock);
+ mutex_lock(&capidev_list_lock);
list_for_each(l, &capidev_list) {
cdev = list_entry(l, struct capidev, list);
- len += sprintf(page+len, "0 %d %lu %lu %lu %lu\n",
+ seq_printf(m, "0 %d %lu %lu %lu %lu\n",
cdev->ap.applid,
cdev->ap.nrecvctlpkt,
cdev->ap.nrecvdatapkt,
cdev->ap.nsentctlpkt,
cdev->ap.nsentdatapkt);
- if (len <= off) {
- off -= len;
- len = 0;
- } else {
- if (len-off > count)
- goto endloop;
- }
}
+ mutex_unlock(&capidev_list_lock);
+ return 0;
+}
-endloop:
- read_unlock(&capidev_list_lock);
- if (len < count)
- *eof = 1;
- if (len > count) len = count;
- if (len < 0) len = 0;
- return len;
+static int capi20_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, capi20_proc_show, NULL);
}
+static const struct file_operations capi20_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = capi20_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/*
* /proc/capi/capi20ncci:
* applid ncci
*/
-static int proc_capincci_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int capi20ncci_proc_show(struct seq_file *m, void *v)
{
- struct capidev *cdev;
- struct capincci *np;
- struct list_head *l;
- int len = 0;
+ struct capidev *cdev;
+ struct capincci *np;
- read_lock(&capidev_list_lock);
- list_for_each(l, &capidev_list) {
- cdev = list_entry(l, struct capidev, list);
- for (np=cdev->nccis; np; np = np->next) {
- len += sprintf(page+len, "%d 0x%x\n",
- cdev->ap.applid,
- np->ncci);
- if (len <= off) {
- off -= len;
- len = 0;
- } else {
- if (len-off > count)
- goto endloop;
- }
- }
+ mutex_lock(&capidev_list_lock);
+ list_for_each_entry(cdev, &capidev_list, list) {
+ mutex_lock(&cdev->lock);
+ list_for_each_entry(np, &cdev->nccis, list)
+ seq_printf(m, "%d 0x%x\n", cdev->ap.applid, np->ncci);
+ mutex_unlock(&cdev->lock);
}
-endloop:
- read_unlock(&capidev_list_lock);
- *start = page+off;
- if (len < count)
- *eof = 1;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ mutex_unlock(&capidev_list_lock);
+ return 0;
+}
+
+static int capi20ncci_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, capi20ncci_proc_show, NULL);
}
-static struct procfsentries {
- char *name;
- mode_t mode;
- int (*read_proc)(char *page, char **start, off_t off,
- int count, int *eof, void *data);
- struct proc_dir_entry *procent;
-} procfsentries[] = {
- /* { "capi", S_IFDIR, 0 }, */
- { "capi/capi20", 0 , proc_capidev_read_proc },
- { "capi/capi20ncci", 0 , proc_capincci_read_proc },
+static const struct file_operations capi20ncci_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = capi20ncci_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
};
static void __init proc_init(void)
{
- int nelem = ARRAY_SIZE(procfsentries);
- int i;
-
- for (i=0; i < nelem; i++) {
- struct procfsentries *p = procfsentries + i;
- p->procent = create_proc_entry(p->name, p->mode, NULL);
- if (p->procent) p->procent->read_proc = p->read_proc;
- }
+ proc_create("capi/capi20", 0, NULL, &capi20_proc_fops);
+ proc_create("capi/capi20ncci", 0, NULL, &capi20ncci_proc_fops);
}
static void __exit proc_exit(void)
{
- int nelem = ARRAY_SIZE(procfsentries);
- int i;
-
- for (i=nelem-1; i >= 0; i--) {
- struct procfsentries *p = procfsentries + i;
- if (p->procent) {
- remove_proc_entry(p->name, NULL);
- p->procent = NULL;
- }
- }
+ remove_proc_entry("capi/capi20", NULL);
+ remove_proc_entry("capi/capi20ncci", NULL);
}
/* -------- init function and module interface ---------------------- */
-static char rev[32];
-
static int __init capi_init(void)
{
- char *p;
- char *compileinfo;
+ const char *compileinfo;
int major_ret;
- if ((p = strchr(revision, ':')) != NULL && p[1]) {
- strlcpy(rev, p + 2, sizeof(rev));
- if ((p = strchr(rev, '$')) != NULL && p > rev)
- *(p-1) = 0;
- } else
- strcpy(rev, "1.0");
-
major_ret = register_chrdev(capi_major, "capi20", &capi_fops);
if (major_ret < 0) {
printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
@@ -1548,28 +1500,24 @@ static int __init capi_init(void)
device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi");
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
if (capinc_tty_init() < 0) {
device_destroy(capi_class, MKDEV(capi_major, 0));
class_destroy(capi_class);
unregister_chrdev(capi_major, "capi20");
return -ENOMEM;
}
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
proc_init();
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
compileinfo = " (middleware+capifs)";
-#else
+#elif defined(CONFIG_ISDN_CAPI_MIDDLEWARE)
compileinfo = " (no capifs)";
-#endif
#else
compileinfo = " (no middleware)";
#endif
- printk(KERN_NOTICE "capi20: Rev %s: started up with major %d%s\n",
- rev, capi_major, compileinfo);
+ printk(KERN_NOTICE "CAPI 2.0 started up with major %d%s\n",
+ capi_major, compileinfo);
return 0;
}
@@ -1582,10 +1530,7 @@ static void __exit capi_exit(void)
class_destroy(capi_class);
unregister_chrdev(capi_major, "capi20");
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
capinc_tty_exit();
-#endif
- printk(KERN_NOTICE "capi: Rev %s: unloaded\n", rev);
}
module_init(capi_init);
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index 66b7d7a86474..bf55ed5f38e3 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -24,6 +24,7 @@
#include <linux/isdn.h>
#include <linux/isdnif.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/ctype.h>
@@ -34,7 +35,6 @@
#include <linux/isdn/capicmd.h>
#include "capidrv.h"
-static char *revision = "$Revision: 1.1.2.2 $";
static int debugmode = 0;
MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");
@@ -2210,96 +2210,73 @@ static int capidrv_delcontr(u16 contr)
}
-static void lower_callback(unsigned int cmd, u32 contr, void *data)
+static int
+lower_callback(struct notifier_block *nb, unsigned long val, void *v)
{
+ capi_profile profile;
+ u32 contr = (long)v;
- switch (cmd) {
- case KCI_CONTRUP:
+ switch (val) {
+ case CAPICTR_UP:
printk(KERN_INFO "capidrv: controller %hu up\n", contr);
- (void) capidrv_addcontr(contr, (capi_profile *) data);
+ if (capi20_get_profile(contr, &profile) == CAPI_NOERROR)
+ (void) capidrv_addcontr(contr, &profile);
break;
- case KCI_CONTRDOWN:
+ case CAPICTR_DOWN:
printk(KERN_INFO "capidrv: controller %hu down\n", contr);
(void) capidrv_delcontr(contr);
break;
}
+ return NOTIFY_OK;
}
/*
* /proc/capi/capidrv:
* nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
*/
-static int proc_capidrv_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int capidrv_proc_show(struct seq_file *m, void *v)
{
- int len = 0;
-
- len += sprintf(page+len, "%lu %lu %lu %lu\n",
+ seq_printf(m, "%lu %lu %lu %lu\n",
global.ap.nrecvctlpkt,
global.ap.nrecvdatapkt,
global.ap.nsentctlpkt,
global.ap.nsentdatapkt);
- if (off+count >= len)
- *eof = 1;
- if (len < off)
- return 0;
- *start = page + off;
- return ((count < len-off) ? count : len-off);
+ return 0;
}
-static struct procfsentries {
- char *name;
- mode_t mode;
- int (*read_proc)(char *page, char **start, off_t off,
- int count, int *eof, void *data);
- struct proc_dir_entry *procent;
-} procfsentries[] = {
- /* { "capi", S_IFDIR, 0 }, */
- { "capi/capidrv", 0 , proc_capidrv_read_proc },
+static int capidrv_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, capidrv_proc_show, NULL);
+}
+
+static const struct file_operations capidrv_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = capidrv_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
};
static void __init proc_init(void)
{
- int nelem = ARRAY_SIZE(procfsentries);
- int i;
-
- for (i=0; i < nelem; i++) {
- struct procfsentries *p = procfsentries + i;
- p->procent = create_proc_entry(p->name, p->mode, NULL);
- if (p->procent) p->procent->read_proc = p->read_proc;
- }
+ proc_create("capi/capidrv", 0, NULL, &capidrv_proc_fops);
}
static void __exit proc_exit(void)
{
- int nelem = ARRAY_SIZE(procfsentries);
- int i;
-
- for (i=nelem-1; i >= 0; i--) {
- struct procfsentries *p = procfsentries + i;
- if (p->procent) {
- remove_proc_entry(p->name, NULL);
- p->procent = NULL;
- }
- }
+ remove_proc_entry("capi/capidrv", NULL);
}
+static struct notifier_block capictr_nb = {
+ .notifier_call = lower_callback,
+};
+
static int __init capidrv_init(void)
{
capi_profile profile;
- char rev[32];
- char *p;
u32 ncontr, contr;
u16 errcode;
- if ((p = strchr(revision, ':')) != NULL && p[1]) {
- strncpy(rev, p + 2, sizeof(rev));
- rev[sizeof(rev)-1] = 0;
- if ((p = strchr(rev, '$')) != NULL && p > rev)
- *(p-1) = 0;
- } else
- strcpy(rev, "1.0");
-
global.ap.rparam.level3cnt = -2; /* number of bchannels twice */
global.ap.rparam.datablkcnt = 16;
global.ap.rparam.datablklen = 2048;
@@ -2310,7 +2287,7 @@ static int __init capidrv_init(void)
return -EIO;
}
- capi20_set_callback(&global.ap, lower_callback);
+ register_capictr_notifier(&capictr_nb);
errcode = capi20_get_profile(0, &profile);
if (errcode != CAPI_NOERROR) {
@@ -2327,29 +2304,15 @@ static int __init capidrv_init(void)
}
proc_init();
- printk(KERN_NOTICE "capidrv: Rev %s: loaded\n", rev);
return 0;
}
static void __exit capidrv_exit(void)
{
- char rev[32];
- char *p;
-
- if ((p = strchr(revision, ':')) != NULL) {
- strncpy(rev, p + 1, sizeof(rev));
- rev[sizeof(rev)-1] = 0;
- if ((p = strchr(rev, '$')) != NULL)
- *p = 0;
- } else {
- strcpy(rev, " ??? ");
- }
-
+ unregister_capictr_notifier(&capictr_nb);
capi20_release(&global.ap);
proc_exit();
-
- printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
}
module_init(capidrv_init);
diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
index 9f8f67b6c07f..8596bd1a4d26 100644
--- a/drivers/isdn/capi/capifs.c
+++ b/drivers/isdn/capi/capifs.c
@@ -25,14 +25,10 @@ MODULE_LICENSE("GPL");
/* ------------------------------------------------------------------ */
-static char *revision = "$Revision: 1.1.2.3 $";
-
-/* ------------------------------------------------------------------ */
-
#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N')
static struct vfsmount *capifs_mnt;
-static struct dentry *capifs_root;
+static int capifs_mnt_count;
static struct {
int setuid;
@@ -118,7 +114,7 @@ capifs_fill_super(struct super_block *s, void *data, int silent)
inode->i_fop = &simple_dir_operations;
inode->i_nlink = 2;
- capifs_root = s->s_root = d_alloc_root(inode);
+ s->s_root = d_alloc_root(inode);
if (s->s_root)
return 0;
@@ -141,82 +137,98 @@ static struct file_system_type capifs_fs_type = {
.kill_sb = kill_anon_super,
};
-static struct dentry *get_node(int num)
+static struct dentry *new_ncci(unsigned int number, dev_t device)
{
- char s[10];
- struct dentry *root = capifs_root;
+ struct super_block *s = capifs_mnt->mnt_sb;
+ struct dentry *root = s->s_root;
+ struct dentry *dentry;
+ struct inode *inode;
+ char name[10];
+ int namelen;
+
mutex_lock(&root->d_inode->i_mutex);
- return lookup_one_len(s, root, sprintf(s, "%d", num));
-}
-void capifs_new_ncci(unsigned int number, dev_t device)
-{
- struct dentry *dentry;
- struct inode *inode = new_inode(capifs_mnt->mnt_sb);
- if (!inode)
- return;
- inode->i_ino = number+2;
+ namelen = sprintf(name, "%d", number);
+ dentry = lookup_one_len(name, root, namelen);
+ if (IS_ERR(dentry)) {
+ dentry = NULL;
+ goto unlock_out;
+ }
- dentry = get_node(number);
+ if (dentry->d_inode) {
+ dput(dentry);
+ dentry = NULL;
+ goto unlock_out;
+ }
+
+ inode = new_inode(s);
+ if (!inode) {
+ dput(dentry);
+ dentry = NULL;
+ goto unlock_out;
+ }
/* config contents is protected by root's i_mutex */
inode->i_uid = config.setuid ? config.uid : current_fsuid();
inode->i_gid = config.setgid ? config.gid : current_fsgid();
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_ino = number + 2;
init_special_inode(inode, S_IFCHR|config.mode, device);
- //inode->i_op = &capifs_file_inode_operations;
- if (!IS_ERR(dentry) && !dentry->d_inode)
- d_instantiate(dentry, inode);
- mutex_unlock(&capifs_root->d_inode->i_mutex);
+ d_instantiate(dentry, inode);
+ dget(dentry);
+
+unlock_out:
+ mutex_unlock(&root->d_inode->i_mutex);
+
+ return dentry;
}
-void capifs_free_ncci(unsigned int number)
+struct dentry *capifs_new_ncci(unsigned int number, dev_t device)
{
- struct dentry *dentry = get_node(number);
-
- if (!IS_ERR(dentry)) {
- struct inode *inode = dentry->d_inode;
- if (inode) {
- inode->i_nlink--;
- d_delete(dentry);
- dput(dentry);
- }
+ struct dentry *dentry;
+
+ if (simple_pin_fs(&capifs_fs_type, &capifs_mnt, &capifs_mnt_count) < 0)
+ return NULL;
+
+ dentry = new_ncci(number, device);
+ if (!dentry)
+ simple_release_fs(&capifs_mnt, &capifs_mnt_count);
+
+ return dentry;
+}
+
+void capifs_free_ncci(struct dentry *dentry)
+{
+ struct dentry *root = capifs_mnt->mnt_sb->s_root;
+ struct inode *inode;
+
+ if (!dentry)
+ return;
+
+ mutex_lock(&root->d_inode->i_mutex);
+
+ inode = dentry->d_inode;
+ if (inode) {
+ drop_nlink(inode);
+ d_delete(dentry);
dput(dentry);
}
- mutex_unlock(&capifs_root->d_inode->i_mutex);
+ dput(dentry);
+
+ mutex_unlock(&root->d_inode->i_mutex);
+
+ simple_release_fs(&capifs_mnt, &capifs_mnt_count);
}
static int __init capifs_init(void)
{
- char rev[32];
- char *p;
- int err;
-
- if ((p = strchr(revision, ':')) != NULL && p[1]) {
- strlcpy(rev, p + 2, sizeof(rev));
- if ((p = strchr(rev, '$')) != NULL && p > rev)
- *(p-1) = 0;
- } else
- strcpy(rev, "1.0");
-
- err = register_filesystem(&capifs_fs_type);
- if (!err) {
- capifs_mnt = kern_mount(&capifs_fs_type);
- if (IS_ERR(capifs_mnt)) {
- err = PTR_ERR(capifs_mnt);
- unregister_filesystem(&capifs_fs_type);
- }
- }
- if (!err)
- printk(KERN_NOTICE "capifs: Rev %s\n", rev);
- return err;
+ return register_filesystem(&capifs_fs_type);
}
static void __exit capifs_exit(void)
{
unregister_filesystem(&capifs_fs_type);
- mntput(capifs_mnt);
}
EXPORT_SYMBOL(capifs_new_ncci);
diff --git a/drivers/isdn/capi/capifs.h b/drivers/isdn/capi/capifs.h
index d0bd4c3c430a..e193d1189531 100644
--- a/drivers/isdn/capi/capifs.h
+++ b/drivers/isdn/capi/capifs.h
@@ -7,5 +7,22 @@
*
*/
-void capifs_new_ncci(unsigned int num, dev_t device);
-void capifs_free_ncci(unsigned int num);
+#include <linux/dcache.h>
+
+#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
+
+struct dentry *capifs_new_ncci(unsigned int num, dev_t device);
+void capifs_free_ncci(struct dentry *dentry);
+
+#else
+
+static inline struct dentry *capifs_new_ncci(unsigned int num, dev_t device)
+{
+ return NULL;
+}
+
+static inline void capifs_free_ncci(struct dentry *dentry)
+{
+}
+
+#endif
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
index dc506ab99cac..ce9b05b9e93a 100644
--- a/drivers/isdn/capi/kcapi.c
+++ b/drivers/isdn/capi/kcapi.c
@@ -34,10 +34,7 @@
#include <linux/b1lli.h>
#endif
#include <linux/mutex.h>
-
-static char *revision = "$Revision: 1.1.2.8 $";
-
-/* ------------------------------------------------------------- */
+#include <linux/rcupdate.h>
static int showcapimsgs = 0;
@@ -48,12 +45,10 @@ module_param(showcapimsgs, uint, 0);
/* ------------------------------------------------------------- */
-struct capi_notifier {
+struct capictr_event {
struct work_struct work;
- unsigned int cmd;
+ unsigned int type;
u32 controller;
- u16 applid;
- u32 ncci;
};
/* ------------------------------------------------------------- */
@@ -65,30 +60,31 @@ static char capi_manufakturer[64] = "AVM Berlin";
#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
LIST_HEAD(capi_drivers);
-DEFINE_RWLOCK(capi_drivers_list_lock);
+DEFINE_MUTEX(capi_drivers_lock);
-static DEFINE_RWLOCK(application_lock);
-static DEFINE_MUTEX(controller_mutex);
+struct capi_ctr *capi_controller[CAPI_MAXCONTR];
+DEFINE_MUTEX(capi_controller_lock);
struct capi20_appl *capi_applications[CAPI_MAXAPPL];
-struct capi_ctr *capi_cards[CAPI_MAXCONTR];
-static int ncards;
+static int ncontrollers;
+
+static BLOCKING_NOTIFIER_HEAD(ctr_notifier_list);
/* -------- controller ref counting -------------------------------------- */
static inline struct capi_ctr *
-capi_ctr_get(struct capi_ctr *card)
+capi_ctr_get(struct capi_ctr *ctr)
{
- if (!try_module_get(card->owner))
+ if (!try_module_get(ctr->owner))
return NULL;
- return card;
+ return ctr;
}
static inline void
-capi_ctr_put(struct capi_ctr *card)
+capi_ctr_put(struct capi_ctr *ctr)
{
- module_put(card->owner);
+ module_put(ctr->owner);
}
/* ------------------------------------------------------------- */
@@ -98,7 +94,7 @@ static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr)
if (contr - 1 >= CAPI_MAXCONTR)
return NULL;
- return capi_cards[contr - 1];
+ return capi_controller[contr - 1];
}
static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
@@ -106,7 +102,7 @@ static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
if (applid - 1 >= CAPI_MAXAPPL)
return NULL;
- return capi_applications[applid - 1];
+ return rcu_dereference(capi_applications[applid - 1]);
}
/* -------- util functions ------------------------------------ */
@@ -148,106 +144,159 @@ static inline int capi_subcmd_valid(u8 subcmd)
/* ------------------------------------------------------------ */
-static void register_appl(struct capi_ctr *card, u16 applid, capi_register_params *rparam)
+static void
+register_appl(struct capi_ctr *ctr, u16 applid, capi_register_params *rparam)
{
- card = capi_ctr_get(card);
+ ctr = capi_ctr_get(ctr);
- if (card)
- card->register_appl(card, applid, rparam);
+ if (ctr)
+ ctr->register_appl(ctr, applid, rparam);
else
- printk(KERN_WARNING "%s: cannot get card resources\n", __func__);
+ printk(KERN_WARNING "%s: cannot get controller resources\n",
+ __func__);
}
-static void release_appl(struct capi_ctr *card, u16 applid)
+static void release_appl(struct capi_ctr *ctr, u16 applid)
{
DBG("applid %#x", applid);
- card->release_appl(card, applid);
- capi_ctr_put(card);
+ ctr->release_appl(ctr, applid);
+ capi_ctr_put(ctr);
}
-/* -------- KCI_CONTRUP --------------------------------------- */
-
static void notify_up(u32 contr)
{
- struct capi_ctr *card = get_capi_ctr_by_nr(contr);
struct capi20_appl *ap;
+ struct capi_ctr *ctr;
u16 applid;
- if (showcapimsgs & 1) {
+ mutex_lock(&capi_controller_lock);
+
+ if (showcapimsgs & 1)
printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
- }
- if (!card) {
+
+ ctr = get_capi_ctr_by_nr(contr);
+ if (ctr) {
+ if (ctr->state == CAPI_CTR_RUNNING)
+ goto unlock_out;
+
+ ctr->state = CAPI_CTR_RUNNING;
+
+ for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
+ ap = get_capi_appl_by_nr(applid);
+ if (!ap)
+ continue;
+ register_appl(ctr, applid, &ap->rparam);
+ }
+
+ wake_up_interruptible_all(&ctr->state_wait_queue);
+ } else
printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
- return;
- }
- for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
- ap = get_capi_appl_by_nr(applid);
- if (!ap || ap->release_in_progress) continue;
- register_appl(card, applid, &ap->rparam);
- if (ap->callback && !ap->release_in_progress)
- ap->callback(KCI_CONTRUP, contr, &card->profile);
- }
-}
-/* -------- KCI_CONTRDOWN ------------------------------------- */
+unlock_out:
+ mutex_unlock(&capi_controller_lock);
+}
-static void notify_down(u32 contr)
+static void ctr_down(struct capi_ctr *ctr, int new_state)
{
struct capi20_appl *ap;
u16 applid;
- if (showcapimsgs & 1) {
- printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);
- }
+ if (ctr->state == CAPI_CTR_DETECTED || ctr->state == CAPI_CTR_DETACHED)
+ return;
+
+ ctr->state = new_state;
+
+ memset(ctr->manu, 0, sizeof(ctr->manu));
+ memset(&ctr->version, 0, sizeof(ctr->version));
+ memset(&ctr->profile, 0, sizeof(ctr->profile));
+ memset(ctr->serial, 0, sizeof(ctr->serial));
for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
ap = get_capi_appl_by_nr(applid);
- if (ap && ap->callback && !ap->release_in_progress)
- ap->callback(KCI_CONTRDOWN, contr, NULL);
+ if (ap)
+ capi_ctr_put(ctr);
}
+
+ wake_up_interruptible_all(&ctr->state_wait_queue);
}
-static void notify_handler(struct work_struct *work)
+static void notify_down(u32 contr)
{
- struct capi_notifier *np =
- container_of(work, struct capi_notifier, work);
+ struct capi_ctr *ctr;
- switch (np->cmd) {
- case KCI_CONTRUP:
- notify_up(np->controller);
+ mutex_lock(&capi_controller_lock);
+
+ if (showcapimsgs & 1)
+ printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);
+
+ ctr = get_capi_ctr_by_nr(contr);
+ if (ctr)
+ ctr_down(ctr, CAPI_CTR_DETECTED);
+ else
+ printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
+
+ mutex_unlock(&capi_controller_lock);
+}
+
+static int
+notify_handler(struct notifier_block *nb, unsigned long val, void *v)
+{
+ u32 contr = (long)v;
+
+ switch (val) {
+ case CAPICTR_UP:
+ notify_up(contr);
break;
- case KCI_CONTRDOWN:
- notify_down(np->controller);
+ case CAPICTR_DOWN:
+ notify_down(contr);
break;
}
+ return NOTIFY_OK;
+}
+
+static void do_notify_work(struct work_struct *work)
+{
+ struct capictr_event *event =
+ container_of(work, struct capictr_event, work);
- kfree(np);
+ blocking_notifier_call_chain(&ctr_notifier_list, event->type,
+ (void *)(long)event->controller);
+ kfree(event);
}
/*
* The notifier will result in adding/deleteing of devices. Devices can
* only removed in user process, not in bh.
*/
-static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci)
+static int notify_push(unsigned int event_type, u32 controller)
{
- struct capi_notifier *np = kmalloc(sizeof(*np), GFP_ATOMIC);
+ struct capictr_event *event = kmalloc(sizeof(*event), GFP_ATOMIC);
- if (!np)
+ if (!event)
return -ENOMEM;
- INIT_WORK(&np->work, notify_handler);
- np->cmd = cmd;
- np->controller = controller;
- np->applid = applid;
- np->ncci = ncci;
+ INIT_WORK(&event->work, do_notify_work);
+ event->type = event_type;
+ event->controller = controller;
- schedule_work(&np->work);
+ schedule_work(&event->work);
return 0;
}
-
+int register_capictr_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&ctr_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_capictr_notifier);
+
+int unregister_capictr_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&ctr_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_capictr_notifier);
+
/* -------- Receiver ------------------------------------------ */
static void recv_handler(struct work_struct *work)
@@ -273,68 +322,70 @@ static void recv_handler(struct work_struct *work)
/**
* capi_ctr_handle_message() - handle incoming CAPI message
- * @card: controller descriptor structure.
+ * @ctr: controller descriptor structure.
* @appl: application ID.
* @skb: message.
*
* Called by hardware driver to pass a CAPI message to the application.
*/
-void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb)
+void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,
+ struct sk_buff *skb)
{
struct capi20_appl *ap;
int showctl = 0;
u8 cmd, subcmd;
- unsigned long flags;
_cdebbuf *cdb;
- if (card->cardstate != CARD_RUNNING) {
+ if (ctr->state != CAPI_CTR_RUNNING) {
cdb = capi_message2str(skb->data);
if (cdb) {
printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s",
- card->cnr, cdb->buf);
+ ctr->cnr, cdb->buf);
cdebbuf_free(cdb);
} else
printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n",
- card->cnr);
+ ctr->cnr);
goto error;
}
cmd = CAPIMSG_COMMAND(skb->data);
subcmd = CAPIMSG_SUBCOMMAND(skb->data);
if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
- card->nrecvdatapkt++;
- if (card->traceflag > 2) showctl |= 2;
+ ctr->nrecvdatapkt++;
+ if (ctr->traceflag > 2)
+ showctl |= 2;
} else {
- card->nrecvctlpkt++;
- if (card->traceflag) showctl |= 2;
+ ctr->nrecvctlpkt++;
+ if (ctr->traceflag)
+ showctl |= 2;
}
- showctl |= (card->traceflag & 1);
+ showctl |= (ctr->traceflag & 1);
if (showctl & 2) {
if (showctl & 1) {
printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n",
- card->cnr, CAPIMSG_APPID(skb->data),
+ ctr->cnr, CAPIMSG_APPID(skb->data),
capi_cmd2str(cmd, subcmd),
CAPIMSG_LEN(skb->data));
} else {
cdb = capi_message2str(skb->data);
if (cdb) {
printk(KERN_DEBUG "kcapi: got [%03d] %s\n",
- card->cnr, cdb->buf);
+ ctr->cnr, cdb->buf);
cdebbuf_free(cdb);
} else
printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n",
- card->cnr, CAPIMSG_APPID(skb->data),
+ ctr->cnr, CAPIMSG_APPID(skb->data),
capi_cmd2str(cmd, subcmd),
CAPIMSG_LEN(skb->data));
}
}
- read_lock_irqsave(&application_lock, flags);
+ rcu_read_lock();
ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
- if ((!ap) || (ap->release_in_progress)) {
- read_unlock_irqrestore(&application_lock, flags);
+ if (!ap) {
+ rcu_read_unlock();
cdb = capi_message2str(skb->data);
if (cdb) {
printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
@@ -348,7 +399,7 @@ void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *s
}
skb_queue_tail(&ap->recv_queue, skb);
schedule_work(&ap->recv_work);
- read_unlock_irqrestore(&application_lock, flags);
+ rcu_read_unlock();
return;
@@ -360,74 +411,54 @@ EXPORT_SYMBOL(capi_ctr_handle_message);
/**
* capi_ctr_ready() - signal CAPI controller ready
- * @card: controller descriptor structure.
+ * @ctr: controller descriptor structure.
*
* Called by hardware driver to signal that the controller is up and running.
*/
-void capi_ctr_ready(struct capi_ctr * card)
+void capi_ctr_ready(struct capi_ctr *ctr)
{
- card->cardstate = CARD_RUNNING;
-
- printk(KERN_NOTICE "kcapi: card [%03d] \"%s\" ready.\n",
- card->cnr, card->name);
+ printk(KERN_NOTICE "kcapi: controller [%03d] \"%s\" ready.\n",
+ ctr->cnr, ctr->name);
- notify_push(KCI_CONTRUP, card->cnr, 0, 0);
+ notify_push(CAPICTR_UP, ctr->cnr);
}
EXPORT_SYMBOL(capi_ctr_ready);
/**
* capi_ctr_down() - signal CAPI controller not ready
- * @card: controller descriptor structure.
+ * @ctr: controller descriptor structure.
*
* Called by hardware driver to signal that the controller is down and
* unavailable for use.
*/
-void capi_ctr_down(struct capi_ctr * card)
+void capi_ctr_down(struct capi_ctr *ctr)
{
- u16 appl;
-
- DBG("");
-
- if (card->cardstate == CARD_DETECTED)
- return;
-
- card->cardstate = CARD_DETECTED;
-
- memset(card->manu, 0, sizeof(card->manu));
- memset(&card->version, 0, sizeof(card->version));
- memset(&card->profile, 0, sizeof(card->profile));
- memset(card->serial, 0, sizeof(card->serial));
-
- for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
- struct capi20_appl *ap = get_capi_appl_by_nr(appl);
- if (!ap || ap->release_in_progress)
- continue;
-
- capi_ctr_put(card);
- }
-
- printk(KERN_NOTICE "kcapi: card [%03d] down.\n", card->cnr);
+ printk(KERN_NOTICE "kcapi: controller [%03d] down.\n", ctr->cnr);
- notify_push(KCI_CONTRDOWN, card->cnr, 0, 0);
+ notify_push(CAPICTR_DOWN, ctr->cnr);
}
EXPORT_SYMBOL(capi_ctr_down);
/**
* capi_ctr_suspend_output() - suspend controller
- * @card: controller descriptor structure.
+ * @ctr: controller descriptor structure.
*
* Called by hardware driver to stop data flow.
+ *
+ * Note: The caller is responsible for synchronizing concurrent state changes
+ * as well as invocations of capi_ctr_handle_message.
*/
-void capi_ctr_suspend_output(struct capi_ctr *card)
+void capi_ctr_suspend_output(struct capi_ctr *ctr)
{
- if (!card->blocked) {
- printk(KERN_DEBUG "kcapi: card [%03d] suspend\n", card->cnr);
- card->blocked = 1;
+ if (!ctr->blocked) {
+ printk(KERN_DEBUG "kcapi: controller [%03d] suspend\n",
+ ctr->cnr);
+ ctr->blocked = 1;
}
}
@@ -435,16 +466,20 @@ EXPORT_SYMBOL(capi_ctr_suspend_output);
/**
* capi_ctr_resume_output() - resume controller
- * @card: controller descriptor structure.
+ * @ctr: controller descriptor structure.
*
* Called by hardware driver to resume data flow.
+ *
+ * Note: The caller is responsible for synchronizing concurrent state changes
+ * as well as invocations of capi_ctr_handle_message.
*/
-void capi_ctr_resume_output(struct capi_ctr *card)
+void capi_ctr_resume_output(struct capi_ctr *ctr)
{
- if (card->blocked) {
- printk(KERN_DEBUG "kcapi: card [%03d] resume\n", card->cnr);
- card->blocked = 0;
+ if (ctr->blocked) {
+ printk(KERN_DEBUG "kcapi: controller [%03d] resumed\n",
+ ctr->cnr);
+ ctr->blocked = 0;
}
}
@@ -454,53 +489,48 @@ EXPORT_SYMBOL(capi_ctr_resume_output);
/**
* attach_capi_ctr() - register CAPI controller
- * @card: controller descriptor structure.
+ * @ctr: controller descriptor structure.
*
* Called by hardware driver to register a controller with the CAPI subsystem.
* Return value: 0 on success, error code < 0 on error
*/
-int
-attach_capi_ctr(struct capi_ctr *card)
+int attach_capi_ctr(struct capi_ctr *ctr)
{
int i;
- mutex_lock(&controller_mutex);
+ mutex_lock(&capi_controller_lock);
for (i = 0; i < CAPI_MAXCONTR; i++) {
- if (capi_cards[i] == NULL)
+ if (!capi_controller[i])
break;
}
if (i == CAPI_MAXCONTR) {
- mutex_unlock(&controller_mutex);
+ mutex_unlock(&capi_controller_lock);
printk(KERN_ERR "kcapi: out of controller slots\n");
return -EBUSY;
}
- capi_cards[i] = card;
-
- mutex_unlock(&controller_mutex);
-
- card->nrecvctlpkt = 0;
- card->nrecvdatapkt = 0;
- card->nsentctlpkt = 0;
- card->nsentdatapkt = 0;
- card->cnr = i + 1;
- card->cardstate = CARD_DETECTED;
- card->blocked = 0;
- card->traceflag = showcapimsgs;
-
- sprintf(card->procfn, "capi/controllers/%d", card->cnr);
- card->procent = create_proc_entry(card->procfn, 0, NULL);
- if (card->procent) {
- card->procent->read_proc =
- (int (*)(char *,char **,off_t,int,int *,void *))
- card->ctr_read_proc;
- card->procent->data = card;
- }
+ capi_controller[i] = ctr;
+
+ ctr->nrecvctlpkt = 0;
+ ctr->nrecvdatapkt = 0;
+ ctr->nsentctlpkt = 0;
+ ctr->nsentdatapkt = 0;
+ ctr->cnr = i + 1;
+ ctr->state = CAPI_CTR_DETECTED;
+ ctr->blocked = 0;
+ ctr->traceflag = showcapimsgs;
+ init_waitqueue_head(&ctr->state_wait_queue);
- ncards++;
- printk(KERN_NOTICE "kcapi: Controller [%03d]: %s attached\n",
- card->cnr, card->name);
+ sprintf(ctr->procfn, "capi/controllers/%d", ctr->cnr);
+ ctr->procent = proc_create_data(ctr->procfn, 0, NULL, ctr->proc_fops, ctr);
+
+ ncontrollers++;
+
+ mutex_unlock(&capi_controller_lock);
+
+ printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n",
+ ctr->cnr, ctr->name);
return 0;
}
@@ -508,29 +538,38 @@ EXPORT_SYMBOL(attach_capi_ctr);
/**
* detach_capi_ctr() - unregister CAPI controller
- * @card: controller descriptor structure.
+ * @ctr: controller descriptor structure.
*
* Called by hardware driver to remove the registration of a controller
* with the CAPI subsystem.
* Return value: 0 on success, error code < 0 on error
*/
-int detach_capi_ctr(struct capi_ctr *card)
+int detach_capi_ctr(struct capi_ctr *ctr)
{
- if (card->cardstate != CARD_DETECTED)
- capi_ctr_down(card);
+ int err = 0;
- ncards--;
+ mutex_lock(&capi_controller_lock);
- if (card->procent) {
- remove_proc_entry(card->procfn, NULL);
- card->procent = NULL;
+ ctr_down(ctr, CAPI_CTR_DETACHED);
+
+ if (capi_controller[ctr->cnr - 1] != ctr) {
+ err = -EINVAL;
+ goto unlock_out;
}
- capi_cards[card->cnr - 1] = NULL;
- printk(KERN_NOTICE "kcapi: Controller [%03d]: %s unregistered\n",
- card->cnr, card->name);
+ capi_controller[ctr->cnr - 1] = NULL;
+ ncontrollers--;
- return 0;
+ if (ctr->procent)
+ remove_proc_entry(ctr->procfn, NULL);
+
+ printk(KERN_NOTICE "kcapi: controller [%03d]: %s unregistered\n",
+ ctr->cnr, ctr->name);
+
+unlock_out:
+ mutex_unlock(&capi_controller_lock);
+
+ return err;
}
EXPORT_SYMBOL(detach_capi_ctr);
@@ -544,11 +583,9 @@ EXPORT_SYMBOL(detach_capi_ctr);
void register_capi_driver(struct capi_driver *driver)
{
- unsigned long flags;
-
- write_lock_irqsave(&capi_drivers_list_lock, flags);
+ mutex_lock(&capi_drivers_lock);
list_add_tail(&driver->list, &capi_drivers);
- write_unlock_irqrestore(&capi_drivers_list_lock, flags);
+ mutex_unlock(&capi_drivers_lock);
}
EXPORT_SYMBOL(register_capi_driver);
@@ -562,11 +599,9 @@ EXPORT_SYMBOL(register_capi_driver);
void unregister_capi_driver(struct capi_driver *driver)
{
- unsigned long flags;
-
- write_lock_irqsave(&capi_drivers_list_lock, flags);
+ mutex_lock(&capi_drivers_lock);
list_del(&driver->list);
- write_unlock_irqrestore(&capi_drivers_list_lock, flags);
+ mutex_unlock(&capi_drivers_lock);
}
EXPORT_SYMBOL(unregister_capi_driver);
@@ -584,12 +619,21 @@ EXPORT_SYMBOL(unregister_capi_driver);
u16 capi20_isinstalled(void)
{
+ u16 ret = CAPI_REGNOTINSTALLED;
int i;
- for (i = 0; i < CAPI_MAXCONTR; i++) {
- if (capi_cards[i] && capi_cards[i]->cardstate == CARD_RUNNING)
- return CAPI_NOERROR;
- }
- return CAPI_REGNOTINSTALLED;
+
+ mutex_lock(&capi_controller_lock);
+
+ for (i = 0; i < CAPI_MAXCONTR; i++)
+ if (capi_controller[i] &&
+ capi_controller[i]->state == CAPI_CTR_RUNNING) {
+ ret = CAPI_NOERROR;
+ break;
+ }
+
+ mutex_unlock(&capi_controller_lock);
+
+ return ret;
}
EXPORT_SYMBOL(capi20_isinstalled);
@@ -610,46 +654,43 @@ u16 capi20_register(struct capi20_appl *ap)
{
int i;
u16 applid;
- unsigned long flags;
DBG("");
if (ap->rparam.datablklen < 128)
return CAPI_LOGBLKSIZETOSMALL;
- write_lock_irqsave(&application_lock, flags);
+ ap->nrecvctlpkt = 0;
+ ap->nrecvdatapkt = 0;
+ ap->nsentctlpkt = 0;
+ ap->nsentdatapkt = 0;
+ mutex_init(&ap->recv_mtx);
+ skb_queue_head_init(&ap->recv_queue);
+ INIT_WORK(&ap->recv_work, recv_handler);
+ ap->release_in_progress = 0;
+
+ mutex_lock(&capi_controller_lock);
for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
if (capi_applications[applid - 1] == NULL)
break;
}
if (applid > CAPI_MAXAPPL) {
- write_unlock_irqrestore(&application_lock, flags);
+ mutex_unlock(&capi_controller_lock);
return CAPI_TOOMANYAPPLS;
}
ap->applid = applid;
capi_applications[applid - 1] = ap;
- ap->nrecvctlpkt = 0;
- ap->nrecvdatapkt = 0;
- ap->nsentctlpkt = 0;
- ap->nsentdatapkt = 0;
- ap->callback = NULL;
- mutex_init(&ap->recv_mtx);
- skb_queue_head_init(&ap->recv_queue);
- INIT_WORK(&ap->recv_work, recv_handler);
- ap->release_in_progress = 0;
-
- write_unlock_irqrestore(&application_lock, flags);
-
- mutex_lock(&controller_mutex);
for (i = 0; i < CAPI_MAXCONTR; i++) {
- if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
+ if (!capi_controller[i] ||
+ capi_controller[i]->state != CAPI_CTR_RUNNING)
continue;
- register_appl(capi_cards[i], applid, &ap->rparam);
+ register_appl(capi_controller[i], applid, &ap->rparam);
}
- mutex_unlock(&controller_mutex);
+
+ mutex_unlock(&capi_controller_lock);
if (showcapimsgs & 1) {
printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
@@ -673,22 +714,24 @@ EXPORT_SYMBOL(capi20_register);
u16 capi20_release(struct capi20_appl *ap)
{
int i;
- unsigned long flags;
DBG("applid %#x", ap->applid);
- write_lock_irqsave(&application_lock, flags);
+ mutex_lock(&capi_controller_lock);
+
ap->release_in_progress = 1;
capi_applications[ap->applid - 1] = NULL;
- write_unlock_irqrestore(&application_lock, flags);
- mutex_lock(&controller_mutex);
+ synchronize_rcu();
+
for (i = 0; i < CAPI_MAXCONTR; i++) {
- if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
+ if (!capi_controller[i] ||
+ capi_controller[i]->state != CAPI_CTR_RUNNING)
continue;
- release_appl(capi_cards[i], ap->applid);
+ release_appl(capi_controller[i], ap->applid);
}
- mutex_unlock(&controller_mutex);
+
+ mutex_unlock(&capi_controller_lock);
flush_scheduled_work();
skb_queue_purge(&ap->recv_queue);
@@ -713,13 +756,13 @@ EXPORT_SYMBOL(capi20_release);
u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
{
- struct capi_ctr *card;
+ struct capi_ctr *ctr;
int showctl = 0;
u8 cmd, subcmd;
DBG("applid %#x", ap->applid);
- if (ncards == 0)
+ if (ncontrollers == 0)
return CAPI_REGNOTINSTALLED;
if ((ap->applid == 0) || ap->release_in_progress)
return CAPI_ILLAPPNR;
@@ -727,28 +770,33 @@ u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
|| !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
|| !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
- card = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
- if (!card || card->cardstate != CARD_RUNNING) {
- card = get_capi_ctr_by_nr(1); // XXX why?
- if (!card || card->cardstate != CARD_RUNNING)
- return CAPI_REGNOTINSTALLED;
- }
- if (card->blocked)
+
+ /*
+ * The controller reference is protected by the existence of the
+ * application passed to us. We assume that the caller properly
+ * synchronizes this service with capi20_release.
+ */
+ ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
+ if (!ctr || ctr->state != CAPI_CTR_RUNNING)
+ return CAPI_REGNOTINSTALLED;
+ if (ctr->blocked)
return CAPI_SENDQUEUEFULL;
cmd = CAPIMSG_COMMAND(skb->data);
subcmd = CAPIMSG_SUBCOMMAND(skb->data);
if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
- card->nsentdatapkt++;
+ ctr->nsentdatapkt++;
ap->nsentdatapkt++;
- if (card->traceflag > 2) showctl |= 2;
+ if (ctr->traceflag > 2)
+ showctl |= 2;
} else {
- card->nsentctlpkt++;
+ ctr->nsentctlpkt++;
ap->nsentctlpkt++;
- if (card->traceflag) showctl |= 2;
+ if (ctr->traceflag)
+ showctl |= 2;
}
- showctl |= (card->traceflag & 1);
+ showctl |= (ctr->traceflag & 1);
if (showctl & 2) {
if (showctl & 1) {
printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n",
@@ -771,7 +819,7 @@ u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
CAPIMSG_LEN(skb->data));
}
}
- return card->send_message(card, skb);
+ return ctr->send_message(ctr, skb);
}
EXPORT_SYMBOL(capi20_put_message);
@@ -788,17 +836,25 @@ EXPORT_SYMBOL(capi20_put_message);
u16 capi20_get_manufacturer(u32 contr, u8 *buf)
{
- struct capi_ctr *card;
+ struct capi_ctr *ctr;
+ u16 ret;
if (contr == 0) {
strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
return CAPI_NOERROR;
}
- card = get_capi_ctr_by_nr(contr);
- if (!card || card->cardstate != CARD_RUNNING)
- return CAPI_REGNOTINSTALLED;
- strlcpy(buf, card->manu, CAPI_MANUFACTURER_LEN);
- return CAPI_NOERROR;
+
+ mutex_lock(&capi_controller_lock);
+
+ ctr = get_capi_ctr_by_nr(contr);
+ if (ctr && ctr->state == CAPI_CTR_RUNNING) {
+ strlcpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN);
+ ret = CAPI_NOERROR;
+ } else
+ ret = CAPI_REGNOTINSTALLED;
+
+ mutex_unlock(&capi_controller_lock);
+ return ret;
}
EXPORT_SYMBOL(capi20_get_manufacturer);
@@ -815,18 +871,25 @@ EXPORT_SYMBOL(capi20_get_manufacturer);
u16 capi20_get_version(u32 contr, struct capi_version *verp)
{
- struct capi_ctr *card;
+ struct capi_ctr *ctr;
+ u16 ret;
if (contr == 0) {
*verp = driver_version;
return CAPI_NOERROR;
}
- card = get_capi_ctr_by_nr(contr);
- if (!card || card->cardstate != CARD_RUNNING)
- return CAPI_REGNOTINSTALLED;
- memcpy((void *) verp, &card->version, sizeof(capi_version));
- return CAPI_NOERROR;
+ mutex_lock(&capi_controller_lock);
+
+ ctr = get_capi_ctr_by_nr(contr);
+ if (ctr && ctr->state == CAPI_CTR_RUNNING) {
+ memcpy(verp, &ctr->version, sizeof(capi_version));
+ ret = CAPI_NOERROR;
+ } else
+ ret = CAPI_REGNOTINSTALLED;
+
+ mutex_unlock(&capi_controller_lock);
+ return ret;
}
EXPORT_SYMBOL(capi20_get_version);
@@ -843,18 +906,25 @@ EXPORT_SYMBOL(capi20_get_version);
u16 capi20_get_serial(u32 contr, u8 *serial)
{
- struct capi_ctr *card;
+ struct capi_ctr *ctr;
+ u16 ret;
if (contr == 0) {
strlcpy(serial, driver_serial, CAPI_SERIAL_LEN);
return CAPI_NOERROR;
}
- card = get_capi_ctr_by_nr(contr);
- if (!card || card->cardstate != CARD_RUNNING)
- return CAPI_REGNOTINSTALLED;
- strlcpy((void *) serial, card->serial, CAPI_SERIAL_LEN);
- return CAPI_NOERROR;
+ mutex_lock(&capi_controller_lock);
+
+ ctr = get_capi_ctr_by_nr(contr);
+ if (ctr && ctr->state == CAPI_CTR_RUNNING) {
+ strlcpy(serial, ctr->serial, CAPI_SERIAL_LEN);
+ ret = CAPI_NOERROR;
+ } else
+ ret = CAPI_REGNOTINSTALLED;
+
+ mutex_unlock(&capi_controller_lock);
+ return ret;
}
EXPORT_SYMBOL(capi20_get_serial);
@@ -871,23 +941,65 @@ EXPORT_SYMBOL(capi20_get_serial);
u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
{
- struct capi_ctr *card;
+ struct capi_ctr *ctr;
+ u16 ret;
if (contr == 0) {
- profp->ncontroller = ncards;
+ profp->ncontroller = ncontrollers;
return CAPI_NOERROR;
}
- card = get_capi_ctr_by_nr(contr);
- if (!card || card->cardstate != CARD_RUNNING)
- return CAPI_REGNOTINSTALLED;
- memcpy((void *) profp, &card->profile,
- sizeof(struct capi_profile));
- return CAPI_NOERROR;
+ mutex_lock(&capi_controller_lock);
+
+ ctr = get_capi_ctr_by_nr(contr);
+ if (ctr && ctr->state == CAPI_CTR_RUNNING) {
+ memcpy(profp, &ctr->profile, sizeof(struct capi_profile));
+ ret = CAPI_NOERROR;
+ } else
+ ret = CAPI_REGNOTINSTALLED;
+
+ mutex_unlock(&capi_controller_lock);
+ return ret;
}
EXPORT_SYMBOL(capi20_get_profile);
+/* Must be called with capi_controller_lock held. */
+static int wait_on_ctr_state(struct capi_ctr *ctr, unsigned int state)
+{
+ DEFINE_WAIT(wait);
+ int retval = 0;
+
+ ctr = capi_ctr_get(ctr);
+ if (!ctr)
+ return -ESRCH;
+
+ for (;;) {
+ prepare_to_wait(&ctr->state_wait_queue, &wait,
+ TASK_INTERRUPTIBLE);
+
+ if (ctr->state == state)
+ break;
+ if (ctr->state == CAPI_CTR_DETACHED) {
+ retval = -ESRCH;
+ break;
+ }
+ if (signal_pending(current)) {
+ retval = -EINTR;
+ break;
+ }
+
+ mutex_unlock(&capi_controller_lock);
+ schedule();
+ mutex_lock(&capi_controller_lock);
+ }
+ finish_wait(&ctr->state_wait_queue, &wait);
+
+ capi_ctr_put(ctr);
+
+ return retval;
+}
+
#ifdef AVMB1_COMPAT
static int old_capi_manufacturer(unsigned int cmd, void __user *data)
{
@@ -895,11 +1007,10 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
avmb1_extcarddef cdef;
avmb1_resetdef rdef;
capicardparams cparams;
- struct capi_ctr *card;
+ struct capi_ctr *ctr;
struct capi_driver *driver = NULL;
capiloaddata ldata;
struct list_head *l;
- unsigned long flags;
int retval;
switch (cmd) {
@@ -919,7 +1030,8 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
cparams.irq = cdef.irq;
cparams.cardnr = cdef.cardnr;
- read_lock_irqsave(&capi_drivers_list_lock, flags);
+ mutex_lock(&capi_drivers_lock);
+
switch (cdef.cardtype) {
case AVM_CARDTYPE_B1:
list_for_each(l, &capi_drivers) {
@@ -940,18 +1052,15 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
break;
}
if (!driver) {
- read_unlock_irqrestore(&capi_drivers_list_lock, flags);
printk(KERN_ERR "kcapi: driver not loaded.\n");
- return -EIO;
- }
- if (!driver->add_card) {
- read_unlock_irqrestore(&capi_drivers_list_lock, flags);
+ retval = -EIO;
+ } else if (!driver->add_card) {
printk(KERN_ERR "kcapi: driver has no add card function.\n");
- return -EIO;
- }
+ retval = -EIO;
+ } else
+ retval = driver->add_card(driver, &cparams);
- retval = driver->add_card(driver, &cparams);
- read_unlock_irqrestore(&capi_drivers_list_lock, flags);
+ mutex_unlock(&capi_drivers_lock);
return retval;
case AVMB1_LOAD:
@@ -968,27 +1077,30 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
sizeof(avmb1_loadandconfigdef)))
return -EFAULT;
}
- card = get_capi_ctr_by_nr(ldef.contr);
- if (!card)
- return -EINVAL;
- card = capi_ctr_get(card);
- if (!card)
- return -ESRCH;
- if (card->load_firmware == NULL) {
+
+ mutex_lock(&capi_controller_lock);
+
+ ctr = get_capi_ctr_by_nr(ldef.contr);
+ if (!ctr) {
+ retval = -EINVAL;
+ goto load_unlock_out;
+ }
+
+ if (ctr->load_firmware == NULL) {
printk(KERN_DEBUG "kcapi: load: no load function\n");
- capi_ctr_put(card);
- return -ESRCH;
+ retval = -ESRCH;
+ goto load_unlock_out;
}
if (ldef.t4file.len <= 0) {
printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
- capi_ctr_put(card);
- return -EINVAL;
+ retval = -EINVAL;
+ goto load_unlock_out;
}
if (ldef.t4file.data == NULL) {
printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
- capi_ctr_put(card);
- return -EINVAL;
+ retval = -EINVAL;
+ goto load_unlock_out;
}
ldata.firmware.user = 1;
@@ -998,54 +1110,49 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
ldata.configuration.data = ldef.t4config.data;
ldata.configuration.len = ldef.t4config.len;
- if (card->cardstate != CARD_DETECTED) {
+ if (ctr->state != CAPI_CTR_DETECTED) {
printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
- capi_ctr_put(card);
- return -EBUSY;
+ retval = -EBUSY;
+ goto load_unlock_out;
}
- card->cardstate = CARD_LOADING;
-
- retval = card->load_firmware(card, &ldata);
+ ctr->state = CAPI_CTR_LOADING;
+ retval = ctr->load_firmware(ctr, &ldata);
if (retval) {
- card->cardstate = CARD_DETECTED;
- capi_ctr_put(card);
- return retval;
+ ctr->state = CAPI_CTR_DETECTED;
+ goto load_unlock_out;
}
- while (card->cardstate != CARD_RUNNING) {
-
- msleep_interruptible(100); /* 0.1 sec */
+ retval = wait_on_ctr_state(ctr, CAPI_CTR_RUNNING);
- if (signal_pending(current)) {
- capi_ctr_put(card);
- return -EINTR;
- }
- }
- capi_ctr_put(card);
- return 0;
+load_unlock_out:
+ mutex_unlock(&capi_controller_lock);
+ return retval;
case AVMB1_RESETCARD:
if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef)))
return -EFAULT;
- card = get_capi_ctr_by_nr(rdef.contr);
- if (!card)
- return -ESRCH;
- if (card->cardstate == CARD_DETECTED)
- return 0;
+ retval = 0;
- card->reset_ctr(card);
+ mutex_lock(&capi_controller_lock);
- while (card->cardstate > CARD_DETECTED) {
+ ctr = get_capi_ctr_by_nr(rdef.contr);
+ if (!ctr) {
+ retval = -ESRCH;
+ goto reset_unlock_out;
+ }
- msleep_interruptible(100); /* 0.1 sec */
+ if (ctr->state == CAPI_CTR_DETECTED)
+ goto reset_unlock_out;
- if (signal_pending(current))
- return -EINTR;
- }
- return 0;
+ ctr->reset_ctr(ctr);
+
+ retval = wait_on_ctr_state(ctr, CAPI_CTR_DETECTED);
+reset_unlock_out:
+ mutex_unlock(&capi_controller_lock);
+ return retval;
}
return -EINVAL;
}
@@ -1062,7 +1169,8 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
int capi20_manufacturer(unsigned int cmd, void __user *data)
{
- struct capi_ctr *card;
+ struct capi_ctr *ctr;
+ int retval;
switch (cmd) {
#ifdef AVMB1_COMPAT
@@ -1080,14 +1188,20 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef)))
return -EFAULT;
- card = get_capi_ctr_by_nr(fdef.contr);
- if (!card)
- return -ESRCH;
+ mutex_lock(&capi_controller_lock);
+
+ ctr = get_capi_ctr_by_nr(fdef.contr);
+ if (ctr) {
+ ctr->traceflag = fdef.flag;
+ printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n",
+ ctr->cnr, ctr->traceflag);
+ retval = 0;
+ } else
+ retval = -ESRCH;
+
+ mutex_unlock(&capi_controller_lock);
- card->traceflag = fdef.flag;
- printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n",
- card->cnr, card->traceflag);
- return 0;
+ return retval;
}
case KCAPI_CMD_ADDCARD:
{
@@ -1095,7 +1209,6 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
struct capi_driver *driver = NULL;
capicardparams cparams;
kcapi_carddef cdef;
- int retval;
if ((retval = copy_from_user(&cdef, data, sizeof(cdef))))
return retval;
@@ -1107,6 +1220,8 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
cparams.cardtype = 0;
cdef.driver[sizeof(cdef.driver)-1] = 0;
+ mutex_lock(&capi_drivers_lock);
+
list_for_each(l, &capi_drivers) {
driver = list_entry(l, struct capi_driver, list);
if (strcmp(driver->name, cdef.driver) == 0)
@@ -1115,15 +1230,15 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
if (driver == NULL) {
printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
cdef.driver);
- return -ESRCH;
- }
-
- if (!driver->add_card) {
+ retval = -ESRCH;
+ } else if (!driver->add_card) {
printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
- return -EIO;
- }
+ retval = -EIO;
+ } else
+ retval = driver->add_card(driver, &cparams);
- return driver->add_card(driver, &cparams);
+ mutex_unlock(&capi_drivers_lock);
+ return retval;
}
default:
@@ -1137,30 +1252,6 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
EXPORT_SYMBOL(capi20_manufacturer);
-/* temporary hack */
-
-/**
- * capi20_set_callback() - set CAPI application notification callback function
- * @ap: CAPI application descriptor structure.
- * @callback: callback function (NULL to remove).
- *
- * If not NULL, the callback function will be called to notify the
- * application of the addition or removal of a controller.
- * The first argument (cmd) will tell whether the controller was added
- * (KCI_CONTRUP) or removed (KCI_CONTRDOWN).
- * The second argument (contr) will be the controller number.
- * For cmd==KCI_CONTRUP the third argument (data) will be a pointer to the
- * new controller's capability profile structure.
- */
-
-void capi20_set_callback(struct capi20_appl *ap,
- void (*callback) (unsigned int cmd, __u32 contr, void *data))
-{
- ap->callback = callback;
-}
-
-EXPORT_SYMBOL(capi20_set_callback);
-
/* ------------------------------------------------------------- */
/* -------- Init & Cleanup ------------------------------------- */
/* ------------------------------------------------------------- */
@@ -1169,27 +1260,21 @@ EXPORT_SYMBOL(capi20_set_callback);
* init / exit functions
*/
+static struct notifier_block capictr_nb = {
+ .notifier_call = notify_handler,
+ .priority = INT_MAX,
+};
+
static int __init kcapi_init(void)
{
- char *p;
- char rev[32];
- int ret;
-
- ret = cdebug_init();
- if (ret)
- return ret;
- kcapi_proc_init();
-
- if ((p = strchr(revision, ':')) != NULL && p[1]) {
- strlcpy(rev, p + 2, sizeof(rev));
- if ((p = strchr(rev, '$')) != NULL && p > rev)
- *(p-1) = 0;
- } else
- strcpy(rev, "1.0");
+ int err;
- printk(KERN_NOTICE "CAPI Subsystem Rev %s\n", rev);
+ register_capictr_notifier(&capictr_nb);
- return 0;
+ err = cdebug_init();
+ if (!err)
+ kcapi_proc_init();
+ return err;
}
static void __exit kcapi_exit(void)
diff --git a/drivers/isdn/capi/kcapi.h b/drivers/isdn/capi/kcapi.h
index 244711f7f838..f4620b38ec51 100644
--- a/drivers/isdn/capi/kcapi.h
+++ b/drivers/isdn/capi/kcapi.h
@@ -24,16 +24,19 @@ printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \
#endif
enum {
- CARD_DETECTED = 1,
- CARD_LOADING = 2,
- CARD_RUNNING = 3,
+ CAPI_CTR_DETACHED = 0,
+ CAPI_CTR_DETECTED = 1,
+ CAPI_CTR_LOADING = 2,
+ CAPI_CTR_RUNNING = 3,
};
extern struct list_head capi_drivers;
-extern rwlock_t capi_drivers_list_lock;
+extern struct mutex capi_drivers_lock;
+
+extern struct capi_ctr *capi_controller[CAPI_MAXCONTR];
+extern struct mutex capi_controller_lock;
extern struct capi20_appl *capi_applications[CAPI_MAXAPPL];
-extern struct capi_ctr *capi_cards[CAPI_MAXCONTR];
#ifdef CONFIG_PROC_FS
diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c
index 09d4db764d22..ea2dff602e49 100644
--- a/drivers/isdn/capi/kcapi_proc.c
+++ b/drivers/isdn/capi/kcapi_proc.c
@@ -15,13 +15,12 @@
#include <linux/seq_file.h>
#include <linux/init.h>
-static char *
-cardstate2str(unsigned short cardstate)
+static char *state2str(unsigned short state)
{
- switch (cardstate) {
- case CARD_DETECTED: return "detected";
- case CARD_LOADING: return "loading";
- case CARD_RUNNING: return "running";
+ switch (state) {
+ case CAPI_CTR_DETECTED: return "detected";
+ case CAPI_CTR_LOADING: return "loading";
+ case CAPI_CTR_RUNNING: return "running";
default: return "???";
}
}
@@ -36,9 +35,12 @@ cardstate2str(unsigned short cardstate)
// ---------------------------------------------------------------------------
static void *controller_start(struct seq_file *seq, loff_t *pos)
+ __acquires(capi_controller_lock)
{
+ mutex_lock(&capi_controller_lock);
+
if (*pos < CAPI_MAXCONTR)
- return &capi_cards[*pos];
+ return &capi_controller[*pos];
return NULL;
}
@@ -47,13 +49,15 @@ static void *controller_next(struct seq_file *seq, void *v, loff_t *pos)
{
++*pos;
if (*pos < CAPI_MAXCONTR)
- return &capi_cards[*pos];
+ return &capi_controller[*pos];
return NULL;
}
static void controller_stop(struct seq_file *seq, void *v)
+ __releases(capi_controller_lock)
{
+ mutex_unlock(&capi_controller_lock);
}
static int controller_show(struct seq_file *seq, void *v)
@@ -65,7 +69,7 @@ static int controller_show(struct seq_file *seq, void *v)
seq_printf(seq, "%d %-10s %-8s %-16s %s\n",
ctr->cnr, ctr->driver_name,
- cardstate2str(ctr->cardstate),
+ state2str(ctr->state),
ctr->name,
ctr->procinfo ? ctr->procinfo(ctr) : "");
@@ -135,9 +139,11 @@ static const struct file_operations proc_contrstats_ops = {
// applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
// ---------------------------------------------------------------------------
-static void *
-applications_start(struct seq_file *seq, loff_t *pos)
+static void *applications_start(struct seq_file *seq, loff_t *pos)
+ __acquires(capi_controller_lock)
{
+ mutex_lock(&capi_controller_lock);
+
if (*pos < CAPI_MAXAPPL)
return &capi_applications[*pos];
@@ -154,9 +160,10 @@ applications_next(struct seq_file *seq, void *v, loff_t *pos)
return NULL;
}
-static void
-applications_stop(struct seq_file *seq, void *v)
+static void applications_stop(struct seq_file *seq, void *v)
+ __releases(capi_controller_lock)
{
+ mutex_unlock(&capi_controller_lock);
}
static int
@@ -239,9 +246,9 @@ static const struct file_operations proc_applstats_ops = {
// ---------------------------------------------------------------------------
static void *capi_driver_start(struct seq_file *seq, loff_t *pos)
- __acquires(&capi_drivers_list_lock)
+ __acquires(&capi_drivers_lock)
{
- read_lock(&capi_drivers_list_lock);
+ mutex_lock(&capi_drivers_lock);
return seq_list_start(&capi_drivers, *pos);
}
@@ -251,9 +258,9 @@ static void *capi_driver_next(struct seq_file *seq, void *v, loff_t *pos)
}
static void capi_driver_stop(struct seq_file *seq, void *v)
- __releases(&capi_drivers_list_lock)
+ __releases(&capi_drivers_lock)
{
- read_unlock(&capi_drivers_list_lock);
+ mutex_unlock(&capi_drivers_lock);
}
static int capi_driver_show(struct seq_file *seq, void *v)
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c
index ccb2a7b7c41d..c5016bd2d94f 100644
--- a/drivers/isdn/gigaset/asyncdata.c
+++ b/drivers/isdn/gigaset/asyncdata.c
@@ -40,6 +40,8 @@ static inline int muststuff(unsigned char c)
* Append received bytes to the command response buffer and forward them
* line by line to the response handler. Exit whenever a mode/state change
* might have occurred.
+ * Note: Received lines may be terminated by CR, LF, or CR LF, which will be
+ * removed before passing the line to the response handler.
* Return value:
* number of processed bytes
*/
@@ -65,14 +67,14 @@ static unsigned cmd_loop(unsigned numbytes, struct inbuf_t *inbuf)
/* --v-- fall through --v-- */
case '\r':
/* end of message line, pass to response handler */
- gig_dbg(DEBUG_TRANSCMD, "%s: End of Message (%d Bytes)",
- __func__, cbytes);
if (cbytes >= MAX_RESP_SIZE) {
dev_warn(cs->dev, "response too large (%d)\n",
cbytes);
cbytes = MAX_RESP_SIZE;
}
cs->cbytes = cbytes;
+ gigaset_dbg_buffer(DEBUG_TRANSCMD, "received response",
+ cbytes, cs->respdata);
gigaset_handle_modem_response(cs);
cbytes = 0;
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 95ebc5129895..0be15c70c16d 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -347,12 +347,7 @@ static inline void error_hangup(struct bc_state *bcs)
{
struct cardstate *cs = bcs->cs;
- 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))
- dev_err(cs->dev, "event queue full\n");
-
+ gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL);
gigaset_schedule_event(cs);
}
@@ -1706,8 +1701,7 @@ static void complete_cb(struct cardstate *cs)
/* unqueue completed buffer */
cs->cmdbytes -= cs->curlen;
- gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD,
- "write_command: sent %u bytes, %u left",
+ gig_dbg(DEBUG_OUTPUT, "write_command: sent %u bytes, %u left",
cs->curlen, cs->cmdbytes);
if (cb->next != NULL) {
cs->cmdbuf = cb->next;
@@ -1881,13 +1875,13 @@ static int start_cbsend(struct cardstate *cs)
/* check if suspend requested */
if (ucs->basstate & BS_SUSPEND) {
- gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "suspending");
+ gig_dbg(DEBUG_OUTPUT, "suspending");
return -EHOSTUNREACH;
}
/* check if AT channel is open */
if (!(ucs->basstate & BS_ATOPEN)) {
- gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open");
+ gig_dbg(DEBUG_OUTPUT, "AT channel not open");
rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT);
if (rc < 0) {
/* flush command queue */
@@ -2251,7 +2245,7 @@ static int gigaset_probe(struct usb_interface *interface,
int i, j;
int rc;
- gig_dbg(DEBUG_ANY,
+ gig_dbg(DEBUG_INIT,
"%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
__func__, le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
@@ -2259,7 +2253,7 @@ static int gigaset_probe(struct usb_interface *interface,
/* set required alternate setting */
hostif = interface->cur_altsetting;
if (hostif->desc.bAlternateSetting != 3) {
- gig_dbg(DEBUG_ANY,
+ gig_dbg(DEBUG_INIT,
"%s: wrong alternate setting %d - trying to switch",
__func__, hostif->desc.bAlternateSetting);
if (usb_set_interface(udev, hostif->desc.bInterfaceNumber, 3)
diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c
index 3f5cd06af104..6643d6533ccb 100644
--- a/drivers/isdn/gigaset/capi.c
+++ b/drivers/isdn/gigaset/capi.c
@@ -13,6 +13,8 @@
#include "gigaset.h"
#include <linux/ctype.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/isdn/capilli.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
@@ -169,20 +171,6 @@ static inline void ignore_cstruct_param(struct cardstate *cs, _cstruct param,
}
/*
- * check for legal hex digit
- */
-static inline int ishexdigit(char c)
-{
- if (c >= '0' && c <= '9')
- return 1;
- if (c >= 'A' && c <= 'F')
- return 1;
- if (c >= 'a' && c <= 'f')
- return 1;
- return 0;
-}
-
-/*
* convert hex to binary
*/
static inline u8 hex2bin(char c)
@@ -202,7 +190,7 @@ static int encode_ie(char *in, u8 *out, int maxlen)
{
int l = 0;
while (*in) {
- if (!ishexdigit(in[0]) || !ishexdigit(in[1]) || l >= maxlen)
+ if (!isxdigit(in[0]) || !isxdigit(in[1]) || l >= maxlen)
return -1;
out[++l] = (hex2bin(in[0]) << 4) + hex2bin(in[1]);
in += 2;
@@ -1425,9 +1413,10 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,
/* queue & schedule EV_DIAL event */
if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, commands,
- bcs->at_state.seq_index, NULL))
- goto oom;
- gig_dbg(DEBUG_CMD, "scheduling DIAL");
+ bcs->at_state.seq_index, NULL)) {
+ info = CAPI_MSGOSRESOURCEERR;
+ goto error;
+ }
gigaset_schedule_event(cs);
ap->connected = APCONN_SETUP;
send_conf(iif, ap, skb, CapiSuccess);
@@ -1541,7 +1530,6 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif,
if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state,
EV_ACCEPT, NULL, 0, NULL))
return;
- gig_dbg(DEBUG_CMD, "scheduling ACCEPT");
gigaset_schedule_event(cs);
return;
@@ -1582,7 +1570,6 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif,
if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state,
EV_HUP, NULL, 0, NULL))
return;
- gig_dbg(DEBUG_CMD, "scheduling HUP");
gigaset_schedule_event(cs);
return;
}
@@ -1665,11 +1652,9 @@ static void do_connect_b3_resp(struct gigaset_capi_ctr *iif,
/* trigger hangup, causing eventual DISCONNECT_IND */
if (!gigaset_add_event(cs, &bcs->at_state,
EV_HUP, NULL, 0, NULL)) {
- dev_err(cs->dev, "%s: out of memory\n", __func__);
dev_kfree_skb_any(skb);
return;
}
- gig_dbg(DEBUG_CMD, "scheduling HUP");
gigaset_schedule_event(cs);
/* emit DISCONNECT_B3_IND */
@@ -1768,11 +1753,9 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif,
/* trigger hangup, causing eventual DISCONNECT_IND */
if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) {
- dev_err(cs->dev, "%s: out of memory\n", __func__);
send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
return;
}
- gig_dbg(DEBUG_CMD, "scheduling HUP");
gigaset_schedule_event(cs);
/* emit reply */
@@ -1815,11 +1798,9 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif,
/* trigger hangup, causing eventual DISCONNECT_B3_IND */
if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state,
EV_HUP, NULL, 0, NULL)) {
- dev_err(cs->dev, "%s: out of memory\n", __func__);
send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
return;
}
- gig_dbg(DEBUG_CMD, "scheduling HUP");
gigaset_schedule_event(cs);
/* NCPI parameter: not applicable for B3 Transparent */
@@ -2106,35 +2087,22 @@ static char *gigaset_procinfo(struct capi_ctr *ctr)
return ctr->name; /* ToDo: more? */
}
-/**
- * gigaset_ctr_read_proc() - build controller proc file entry
- * @page: buffer of PAGE_SIZE bytes for receiving the entry.
- * @start: unused.
- * @off: unused.
- * @count: unused.
- * @eof: unused.
- * @ctr: controller descriptor structure.
- *
- * Return value: length of generated entry
- */
-static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
- int count, int *eof, struct capi_ctr *ctr)
+static int gigaset_proc_show(struct seq_file *m, void *v)
{
+ struct capi_ctr *ctr = m->private;
struct cardstate *cs = ctr->driverdata;
char *s;
int i;
- int len = 0;
- len += sprintf(page+len, "%-16s %s\n", "name", ctr->name);
- len += sprintf(page+len, "%-16s %s %s\n", "dev",
+
+ seq_printf(m, "%-16s %s\n", "name", ctr->name);
+ seq_printf(m, "%-16s %s %s\n", "dev",
dev_driver_string(cs->dev), dev_name(cs->dev));
- len += sprintf(page+len, "%-16s %d\n", "id", cs->myid);
+ seq_printf(m, "%-16s %d\n", "id", cs->myid);
if (cs->gotfwver)
- len += sprintf(page+len, "%-16s %d.%d.%d.%d\n", "firmware",
+ seq_printf(m, "%-16s %d.%d.%d.%d\n", "firmware",
cs->fwver[0], cs->fwver[1], cs->fwver[2], cs->fwver[3]);
- len += sprintf(page+len, "%-16s %d\n", "channels",
- cs->channels);
- len += sprintf(page+len, "%-16s %s\n", "onechannel",
- cs->onechannel ? "yes" : "no");
+ seq_printf(m, "%-16s %d\n", "channels", cs->channels);
+ seq_printf(m, "%-16s %s\n", "onechannel", cs->onechannel ? "yes" : "no");
switch (cs->mode) {
case M_UNKNOWN:
@@ -2152,7 +2120,7 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
default:
s = "??";
}
- len += sprintf(page+len, "%-16s %s\n", "mode", s);
+ seq_printf(m, "%-16s %s\n", "mode", s);
switch (cs->mstate) {
case MS_UNINITIALIZED:
@@ -2176,25 +2144,21 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
default:
s = "??";
}
- len += sprintf(page+len, "%-16s %s\n", "mstate", s);
+ seq_printf(m, "%-16s %s\n", "mstate", s);
- len += sprintf(page+len, "%-16s %s\n", "running",
- cs->running ? "yes" : "no");
- len += sprintf(page+len, "%-16s %s\n", "connected",
- cs->connected ? "yes" : "no");
- len += sprintf(page+len, "%-16s %s\n", "isdn_up",
- cs->isdn_up ? "yes" : "no");
- len += sprintf(page+len, "%-16s %s\n", "cidmode",
- cs->cidmode ? "yes" : "no");
+ seq_printf(m, "%-16s %s\n", "running", cs->running ? "yes" : "no");
+ seq_printf(m, "%-16s %s\n", "connected", cs->connected ? "yes" : "no");
+ seq_printf(m, "%-16s %s\n", "isdn_up", cs->isdn_up ? "yes" : "no");
+ seq_printf(m, "%-16s %s\n", "cidmode", cs->cidmode ? "yes" : "no");
for (i = 0; i < cs->channels; i++) {
- len += sprintf(page+len, "[%d]%-13s %d\n", i, "corrupted",
+ seq_printf(m, "[%d]%-13s %d\n", i, "corrupted",
cs->bcs[i].corrupted);
- len += sprintf(page+len, "[%d]%-13s %d\n", i, "trans_down",
+ seq_printf(m, "[%d]%-13s %d\n", i, "trans_down",
cs->bcs[i].trans_down);
- len += sprintf(page+len, "[%d]%-13s %d\n", i, "trans_up",
+ seq_printf(m, "[%d]%-13s %d\n", i, "trans_up",
cs->bcs[i].trans_up);
- len += sprintf(page+len, "[%d]%-13s %d\n", i, "chstate",
+ seq_printf(m, "[%d]%-13s %d\n", i, "chstate",
cs->bcs[i].chstate);
switch (cs->bcs[i].proto2) {
case L2_BITSYNC:
@@ -2209,11 +2173,23 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
default:
s = "??";
}
- len += sprintf(page+len, "[%d]%-13s %s\n", i, "proto2", s);
+ seq_printf(m, "[%d]%-13s %s\n", i, "proto2", s);
}
- return len;
+ return 0;
}
+static int gigaset_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, gigaset_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations gigaset_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = gigaset_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
static struct capi_driver capi_driver_gigaset = {
.name = "gigaset",
@@ -2256,7 +2232,7 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
iif->ctr.release_appl = gigaset_release_appl;
iif->ctr.send_message = gigaset_send_message;
iif->ctr.procinfo = gigaset_procinfo;
- iif->ctr.ctr_read_proc = gigaset_ctr_read_proc;
+ iif->ctr.proc_fops = &gigaset_proc_fops;
INIT_LIST_HEAD(&iif->appls);
skb_queue_head_init(&iif->sendqueue);
atomic_set(&iif->sendqlen, 0);
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 664b0c519c3e..85de3399a2f2 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -149,10 +149,8 @@ static int test_timeout(struct at_state_t *at_state)
return 0;
}
- if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL,
- at_state->timer_index, NULL))
- dev_err(at_state->cs->dev, "%s: out of memory\n",
- __func__);
+ gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL,
+ at_state->timer_index, NULL);
return 1;
}
@@ -180,7 +178,7 @@ static void timer_tick(unsigned long data)
if (cs->running) {
mod_timer(&cs->timer, jiffies + msecs_to_jiffies(GIG_TICK));
if (timeout) {
- gig_dbg(DEBUG_CMD, "scheduling timeout");
+ gig_dbg(DEBUG_EVENT, "scheduling timeout");
tasklet_schedule(&cs->event_tasklet);
}
}
@@ -194,14 +192,14 @@ int gigaset_get_channel(struct bc_state *bcs)
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->use_count || !try_module_get(bcs->cs->driver->owner)) {
- gig_dbg(DEBUG_ANY, "could not allocate channel %d",
+ gig_dbg(DEBUG_CHANNEL, "could not allocate channel %d",
bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
return 0;
}
++bcs->use_count;
bcs->busy = 1;
- gig_dbg(DEBUG_ANY, "allocated channel %d", bcs->channel);
+ gig_dbg(DEBUG_CHANNEL, "allocated channel %d", bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
return 1;
}
@@ -213,7 +211,7 @@ struct bc_state *gigaset_get_free_channel(struct cardstate *cs)
spin_lock_irqsave(&cs->lock, flags);
if (!try_module_get(cs->driver->owner)) {
- gig_dbg(DEBUG_ANY,
+ gig_dbg(DEBUG_CHANNEL,
"could not get module for allocating channel");
spin_unlock_irqrestore(&cs->lock, flags);
return NULL;
@@ -223,12 +221,12 @@ struct bc_state *gigaset_get_free_channel(struct cardstate *cs)
++cs->bcs[i].use_count;
cs->bcs[i].busy = 1;
spin_unlock_irqrestore(&cs->lock, flags);
- gig_dbg(DEBUG_ANY, "allocated channel %d", i);
+ gig_dbg(DEBUG_CHANNEL, "allocated channel %d", i);
return cs->bcs + i;
}
module_put(cs->driver->owner);
spin_unlock_irqrestore(&cs->lock, flags);
- gig_dbg(DEBUG_ANY, "no free channel");
+ gig_dbg(DEBUG_CHANNEL, "no free channel");
return NULL;
}
@@ -238,14 +236,15 @@ void gigaset_free_channel(struct bc_state *bcs)
spin_lock_irqsave(&bcs->cs->lock, flags);
if (!bcs->busy) {
- gig_dbg(DEBUG_ANY, "could not free channel %d", bcs->channel);
+ gig_dbg(DEBUG_CHANNEL, "could not free channel %d",
+ bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
return;
}
--bcs->use_count;
bcs->busy = 0;
module_put(bcs->cs->driver->owner);
- gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel);
+ gig_dbg(DEBUG_CHANNEL, "freed channel %d", bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
}
@@ -258,14 +257,15 @@ int gigaset_get_channels(struct cardstate *cs)
for (i = 0; i < cs->channels; ++i)
if (cs->bcs[i].use_count) {
spin_unlock_irqrestore(&cs->lock, flags);
- gig_dbg(DEBUG_ANY, "could not allocate all channels");
+ gig_dbg(DEBUG_CHANNEL,
+ "could not allocate all channels");
return 0;
}
for (i = 0; i < cs->channels; ++i)
++cs->bcs[i].use_count;
spin_unlock_irqrestore(&cs->lock, flags);
- gig_dbg(DEBUG_ANY, "allocated all channels");
+ gig_dbg(DEBUG_CHANNEL, "allocated all channels");
return 1;
}
@@ -275,7 +275,7 @@ void gigaset_free_channels(struct cardstate *cs)
unsigned long flags;
int i;
- gig_dbg(DEBUG_ANY, "unblocking all channels");
+ gig_dbg(DEBUG_CHANNEL, "unblocking all channels");
spin_lock_irqsave(&cs->lock, flags);
for (i = 0; i < cs->channels; ++i)
--cs->bcs[i].use_count;
@@ -287,7 +287,7 @@ void gigaset_block_channels(struct cardstate *cs)
unsigned long flags;
int i;
- gig_dbg(DEBUG_ANY, "blocking all channels");
+ gig_dbg(DEBUG_CHANNEL, "blocking all channels");
spin_lock_irqsave(&cs->lock, flags);
for (i = 0; i < cs->channels; ++i)
++cs->bcs[i].use_count;
@@ -338,6 +338,8 @@ struct event_t *gigaset_add_event(struct cardstate *cs,
unsigned next, tail;
struct event_t *event = NULL;
+ gig_dbg(DEBUG_EVENT, "queueing event %d", type);
+
spin_lock_irqsave(&cs->ev_lock, flags);
tail = cs->ev_tail;
@@ -934,11 +936,8 @@ int gigaset_start(struct cardstate *cs)
if (!gigaset_add_event(cs, &cs->at_state, EV_START, NULL, 0, NULL)) {
cs->waiting = 0;
- dev_err(cs->dev, "%s: out of memory\n", __func__);
goto error;
}
-
- gig_dbg(DEBUG_CMD, "scheduling START");
gigaset_schedule_event(cs);
wait_event(cs->waitqueue, !cs->waiting);
@@ -973,12 +972,8 @@ int gigaset_shutdown(struct cardstate *cs)
cs->waiting = 1;
- if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) {
- dev_err(cs->dev, "%s: out of memory\n", __func__);
+ if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL))
goto exit;
- }
-
- gig_dbg(DEBUG_CMD, "scheduling SHUTDOWN");
gigaset_schedule_event(cs);
wait_event(cs->waitqueue, !cs->waiting);
@@ -1004,12 +999,8 @@ void gigaset_stop(struct cardstate *cs)
cs->waiting = 1;
- if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL)) {
- dev_err(cs->dev, "%s: out of memory\n", __func__);
+ if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL))
goto exit;
- }
-
- gig_dbg(DEBUG_CMD, "scheduling STOP");
gigaset_schedule_event(cs);
wait_event(cs->waitqueue, !cs->waiting);
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index ddeb0456d202..c8f89b78b233 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -427,7 +427,7 @@ static int isdn_getnum(char *p)
{
int v = -1;
- gig_dbg(DEBUG_TRANSCMD, "string: %s", p);
+ gig_dbg(DEBUG_EVENT, "string: %s", p);
while (*p >= '0' && *p <= '9')
v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p++) - '0');
@@ -444,7 +444,7 @@ static int isdn_gethex(char *p)
int v = 0;
int c;
- gig_dbg(DEBUG_TRANSCMD, "string: %s", p);
+ gig_dbg(DEBUG_EVENT, "string: %s", p);
if (!*p)
return -1;
@@ -517,7 +517,6 @@ void gigaset_handle_modem_response(struct cardstate *cs)
return;
}
cs->respdata[len] = 0;
- gig_dbg(DEBUG_TRANSCMD, "raw string: '%s'", cs->respdata);
argv[0] = cs->respdata;
params = 1;
if (cs->at_state.getstring) {
@@ -552,14 +551,14 @@ void gigaset_handle_modem_response(struct cardstate *cs)
for (j = 1; j < params; ++j)
argv[j][-1] = 0;
- gig_dbg(DEBUG_TRANSCMD, "CMD received: %s", argv[0]);
+ gig_dbg(DEBUG_EVENT, "CMD received: %s", argv[0]);
if (cid) {
--params;
- gig_dbg(DEBUG_TRANSCMD, "CID: %s", argv[params]);
+ gig_dbg(DEBUG_EVENT, "CID: %s", argv[params]);
}
- gig_dbg(DEBUG_TRANSCMD, "available params: %d", params - 1);
+ gig_dbg(DEBUG_EVENT, "available params: %d", params - 1);
for (j = 1; j < params; j++)
- gig_dbg(DEBUG_TRANSCMD, "param %d: %s", j, argv[j]);
+ gig_dbg(DEBUG_EVENT, "param %d: %s", j, argv[j]);
}
spin_lock_irqsave(&cs->ev_lock, flags);
@@ -642,7 +641,7 @@ void gigaset_handle_modem_response(struct cardstate *cs)
dev_err(cs->dev, "out of memory\n");
++curarg;
}
- gig_dbg(DEBUG_CMD, "string==%s",
+ gig_dbg(DEBUG_EVENT, "string==%s",
event->ptr ? (char *) event->ptr : "NULL");
break;
case RT_ZCAU:
@@ -669,7 +668,7 @@ void gigaset_handle_modem_response(struct cardstate *cs)
++curarg;
} else
event->parameter = -1;
- gig_dbg(DEBUG_CMD, "parameter==%d", event->parameter);
+ gig_dbg(DEBUG_EVENT, "parameter==%d", event->parameter);
break;
}
@@ -684,7 +683,7 @@ void gigaset_handle_modem_response(struct cardstate *cs)
spin_unlock_irqrestore(&cs->ev_lock, flags);
if (curarg != params)
- gig_dbg(DEBUG_ANY,
+ gig_dbg(DEBUG_EVENT,
"invalid number of processed parameters: %d/%d",
curarg, params);
}
@@ -705,8 +704,8 @@ static void disconnect(struct at_state_t **at_state_p)
/* revert to selected idle mode */
if (!cs->cidmode) {
cs->at_state.pending_commands |= PC_UMMODE;
+ gig_dbg(DEBUG_EVENT, "Scheduling PC_UMMODE");
cs->commands_pending = 1;
- gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
}
spin_unlock_irqrestore(&cs->lock, flags);
@@ -784,15 +783,15 @@ static void init_failed(struct cardstate *cs, int mode)
static void schedule_init(struct cardstate *cs, int state)
{
if (cs->at_state.pending_commands & PC_INIT) {
- gig_dbg(DEBUG_CMD, "not scheduling PC_INIT again");
+ gig_dbg(DEBUG_EVENT, "not scheduling PC_INIT again");
return;
}
cs->mstate = state;
cs->mode = M_UNKNOWN;
gigaset_block_channels(cs);
cs->at_state.pending_commands |= PC_INIT;
+ gig_dbg(DEBUG_EVENT, "Scheduling PC_INIT");
cs->commands_pending = 1;
- gig_dbg(DEBUG_CMD, "Scheduling PC_INIT");
}
/* Add "AT" to a command, add the cid, dle encode it, send the result to the
@@ -923,7 +922,7 @@ static void start_dial(struct at_state_t *at_state, void *data,
}
at_state->pending_commands |= PC_CID;
- gig_dbg(DEBUG_CMD, "Scheduling PC_CID");
+ gig_dbg(DEBUG_EVENT, "Scheduling PC_CID");
cs->commands_pending = 1;
return;
@@ -933,7 +932,7 @@ error:
commands[i] = NULL;
}
at_state->pending_commands |= PC_NOCID;
- gig_dbg(DEBUG_CMD, "Scheduling PC_NOCID");
+ gig_dbg(DEBUG_EVENT, "Scheduling PC_NOCID");
cs->commands_pending = 1;
return;
}
@@ -955,7 +954,7 @@ static void start_accept(struct at_state_t *at_state)
dev_err(at_state->cs->dev, "out of memory\n");
/* error reset */
at_state->pending_commands |= PC_HUP;
- gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
+ gig_dbg(DEBUG_EVENT, "Scheduling PC_HUP");
cs->commands_pending = 1;
return;
}
@@ -964,7 +963,7 @@ static void start_accept(struct at_state_t *at_state)
snprintf(bcs->commands[AT_ISO], 9, "^SISO=%u\r", bcs->channel + 1);
at_state->pending_commands |= PC_ACCEPT;
- gig_dbg(DEBUG_CMD, "Scheduling PC_ACCEPT");
+ gig_dbg(DEBUG_EVENT, "Scheduling PC_ACCEPT");
cs->commands_pending = 1;
}
@@ -1009,8 +1008,8 @@ static void do_shutdown(struct cardstate *cs)
if (cs->mstate == MS_READY) {
cs->mstate = MS_SHUTDOWN;
cs->at_state.pending_commands |= PC_SHUTDOWN;
+ gig_dbg(DEBUG_EVENT, "Scheduling PC_SHUTDOWN");
cs->commands_pending = 1;
- gig_dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN");
} else
finish_shutdown(cs);
}
@@ -1191,8 +1190,8 @@ static void do_action(int action, struct cardstate *cs,
}
spin_unlock_irqrestore(&cs->lock, flags);
cs->at_state.pending_commands |= PC_CIDMODE;
+ gig_dbg(DEBUG_EVENT, "Scheduling PC_CIDMODE");
cs->commands_pending = 1;
- gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
break;
case ACT_FAILINIT:
dev_warn(cs->dev, "Could not initialize the device.\n");
@@ -1443,7 +1442,7 @@ static void do_action(int action, struct cardstate *cs,
case ACT_GOTVER:
if (cs->gotfwver == 0) {
cs->gotfwver = 1;
- gig_dbg(DEBUG_ANY,
+ gig_dbg(DEBUG_EVENT,
"firmware version %02d.%03d.%02d.%02d",
cs->fwver[0], cs->fwver[1],
cs->fwver[2], cs->fwver[3]);
@@ -1481,8 +1480,8 @@ static void do_action(int action, struct cardstate *cs,
break;
case ACT_HUP:
at_state->pending_commands |= PC_HUP;
+ gig_dbg(DEBUG_EVENT, "Scheduling PC_HUP");
cs->commands_pending = 1;
- gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
break;
/* hotplug events */
@@ -1519,10 +1518,10 @@ static void do_action(int action, struct cardstate *cs,
cs->cidmode = ev->parameter;
if (ev->parameter) {
cs->at_state.pending_commands |= PC_CIDMODE;
- gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
+ gig_dbg(DEBUG_EVENT, "Scheduling PC_CIDMODE");
} else {
cs->at_state.pending_commands |= PC_UMMODE;
- gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
+ gig_dbg(DEBUG_EVENT, "Scheduling PC_UMMODE");
}
cs->commands_pending = 1;
}
@@ -1573,6 +1572,8 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
if (ev->cid >= 0) {
at_state = at_state_from_cid(cs, ev->cid);
if (!at_state) {
+ gig_dbg(DEBUG_EVENT, "event %d for invalid cid %d",
+ ev->type, ev->cid);
gigaset_add_event(cs, &cs->at_state, RSP_WRONG_CID,
NULL, 0, NULL);
return;
@@ -1580,13 +1581,13 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
} else {
at_state = ev->at_state;
if (at_state_invalid(cs, at_state)) {
- gig_dbg(DEBUG_ANY, "event for invalid at_state %p",
+ gig_dbg(DEBUG_EVENT, "event for invalid at_state %p",
at_state);
return;
}
}
- gig_dbg(DEBUG_CMD, "connection state %d, event %d",
+ gig_dbg(DEBUG_EVENT, "connection state %d, event %d",
at_state->ConState, ev->type);
bcs = at_state->bcs;
@@ -1600,11 +1601,11 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
if (ev->parameter != at_state->timer_index
|| !at_state->timer_active) {
ev->type = RSP_NONE; /* old timeout */
- gig_dbg(DEBUG_ANY, "old timeout");
+ gig_dbg(DEBUG_EVENT, "old timeout");
} else if (!at_state->waiting)
- gig_dbg(DEBUG_ANY, "timeout occurred");
+ gig_dbg(DEBUG_EVENT, "timeout occurred");
else
- gig_dbg(DEBUG_ANY, "stopped waiting");
+ gig_dbg(DEBUG_EVENT, "stopped waiting");
}
spin_unlock_irqrestore(&cs->lock, flags);
@@ -1712,11 +1713,11 @@ static void process_command_flags(struct cardstate *cs)
cs->commands_pending = 0;
if (cs->cur_at_seq) {
- gig_dbg(DEBUG_CMD, "not searching scheduled commands: busy");
+ gig_dbg(DEBUG_EVENT, "not searching scheduled commands: busy");
return;
}
- gig_dbg(DEBUG_CMD, "searching scheduled commands");
+ gig_dbg(DEBUG_EVENT, "searching scheduled commands");
sequence = SEQ_NONE;
@@ -1857,7 +1858,7 @@ static void process_command_flags(struct cardstate *cs)
switch (cs->mode) {
case M_UNIMODEM:
cs->at_state.pending_commands |= PC_CIDMODE;
- gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
+ gig_dbg(DEBUG_EVENT, "Scheduling PC_CIDMODE");
cs->commands_pending = 1;
return;
#ifdef GIG_MAYINITONDIAL
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index e963a6c2e86d..1875ab80b335 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -38,7 +38,7 @@
#define GIG_COMPAT {0, 4, 0, 0}
#define MAX_REC_PARAMS 10 /* Max. number of params in response string */
-#define MAX_RESP_SIZE 512 /* Max. size of a response string */
+#define MAX_RESP_SIZE 511 /* Max. size of a response string */
#define MAX_EVENTS 64 /* size of event queue */
@@ -78,9 +78,10 @@ enum debuglevel {
DEBUG_STREAM = 0x00040, /* application data stream I/O events */
DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */
DEBUG_LLDATA = 0x00100, /* sent/received LL data */
+ DEBUG_EVENT = 0x00200, /* event processing */
DEBUG_DRIVER = 0x00400, /* driver structure */
DEBUG_HDLC = 0x00800, /* M10x HDLC processing */
- DEBUG_WRITE = 0x01000, /* M105 data write */
+ DEBUG_CHANNEL = 0x01000, /* channel allocation/deallocation */
DEBUG_TRANSCMD = 0x02000, /* AT-COMMANDS+RESPONSES */
DEBUG_MCMD = 0x04000, /* COMMANDS THAT ARE SENT VERY OFTEN */
DEBUG_INIT = 0x08000, /* (de)allocation+initialization of data
@@ -498,7 +499,7 @@ struct cardstate {
spinlock_t ev_lock;
/* current modem response */
- unsigned char respdata[MAX_RESP_SIZE];
+ unsigned char respdata[MAX_RESP_SIZE+1];
unsigned cbytes;
/* private data of hardware drivers */
@@ -785,8 +786,6 @@ static inline void gigaset_schedule_event(struct cardstate *cs)
static inline void gigaset_bchannel_down(struct bc_state *bcs)
{
gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_CLOSED, NULL, 0, NULL);
-
- gig_dbg(DEBUG_CMD, "scheduling BC_CLOSED");
gigaset_schedule_event(bcs->cs);
}
@@ -795,8 +794,6 @@ static inline void gigaset_bchannel_down(struct bc_state *bcs)
static inline void gigaset_bchannel_up(struct bc_state *bcs)
{
gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_OPEN, NULL, 0, NULL);
-
- gig_dbg(DEBUG_CMD, "scheduling BC_OPEN");
gigaset_schedule_event(bcs->cs);
}
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
index c129ee47a8fb..f0acb9dc9e33 100644
--- a/drivers/isdn/gigaset/i4l.c
+++ b/drivers/isdn/gigaset/i4l.c
@@ -216,7 +216,7 @@ static int command_from_LL(isdn_ctrl *cntrl)
return -EINVAL;
case ISDN_CMD_DIAL:
- gig_dbg(DEBUG_ANY,
+ gig_dbg(DEBUG_CMD,
"ISDN_CMD_DIAL (phone: %s, msn: %s, si1: %d, si2: %d)",
cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn,
cntrl->parm.setup.si1, cntrl->parm.setup.si2);
@@ -304,11 +304,10 @@ static int command_from_LL(isdn_ctrl *cntrl)
gigaset_free_channel(bcs);
return -ENOMEM;
}
-
- gig_dbg(DEBUG_CMD, "scheduling DIAL");
gigaset_schedule_event(cs);
break;
case ISDN_CMD_ACCEPTD:
+ gig_dbg(DEBUG_CMD, "ISDN_CMD_ACCEPTD");
if (ch >= cs->channels) {
dev_err(cs->dev,
"ISDN_CMD_ACCEPTD: invalid channel (%d)\n", ch);
@@ -318,14 +317,11 @@ static int command_from_LL(isdn_ctrl *cntrl)
if (!gigaset_add_event(cs, &bcs->at_state,
EV_ACCEPT, NULL, 0, NULL))
return -ENOMEM;
-
- gig_dbg(DEBUG_CMD, "scheduling ACCEPT");
gigaset_schedule_event(cs);
break;
- case ISDN_CMD_ACCEPTB:
- break;
case ISDN_CMD_HANGUP:
+ gig_dbg(DEBUG_CMD, "ISDN_CMD_HANGUP");
if (ch >= cs->channels) {
dev_err(cs->dev,
"ISDN_CMD_HANGUP: invalid channel (%d)\n", ch);
@@ -335,8 +331,6 @@ static int command_from_LL(isdn_ctrl *cntrl)
if (!gigaset_add_event(cs, &bcs->at_state,
EV_HUP, NULL, 0, NULL))
return -ENOMEM;
-
- gig_dbg(DEBUG_CMD, "scheduling HUP");
gigaset_schedule_event(cs);
break;
@@ -376,6 +370,7 @@ static int command_from_LL(isdn_ctrl *cntrl)
}
break;
case ISDN_CMD_SETL3: /* Set L3 to given protocol */
+ gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL3");
if (ch >= cs->channels) {
dev_err(cs->dev,
"ISDN_CMD_SETL3: invalid channel (%d)\n", ch);
@@ -390,44 +385,9 @@ static int command_from_LL(isdn_ctrl *cntrl)
}
break;
- case ISDN_CMD_PROCEED:
- gig_dbg(DEBUG_ANY, "ISDN_CMD_PROCEED");
- break;
- case ISDN_CMD_ALERT:
- gig_dbg(DEBUG_ANY, "ISDN_CMD_ALERT");
- if (cntrl->arg >= cs->channels) {
- dev_err(cs->dev,
- "ISDN_CMD_ALERT: invalid channel (%d)\n",
- (int) cntrl->arg);
- return -EINVAL;
- }
- break;
- case ISDN_CMD_REDIR:
- gig_dbg(DEBUG_ANY, "ISDN_CMD_REDIR");
- break;
- case ISDN_CMD_PROT_IO:
- gig_dbg(DEBUG_ANY, "ISDN_CMD_PROT_IO");
- break;
- case ISDN_CMD_FAXCMD:
- gig_dbg(DEBUG_ANY, "ISDN_CMD_FAXCMD");
- break;
- case ISDN_CMD_GETL2:
- gig_dbg(DEBUG_ANY, "ISDN_CMD_GETL2");
- break;
- case ISDN_CMD_GETL3:
- gig_dbg(DEBUG_ANY, "ISDN_CMD_GETL3");
- break;
- case ISDN_CMD_GETEAZ:
- gig_dbg(DEBUG_ANY, "ISDN_CMD_GETEAZ");
- break;
- case ISDN_CMD_SETSIL:
- gig_dbg(DEBUG_ANY, "ISDN_CMD_SETSIL");
- break;
- case ISDN_CMD_GETSIL:
- gig_dbg(DEBUG_ANY, "ISDN_CMD_GETSIL");
- break;
+
default:
- dev_err(cs->dev, "unknown command %d from LL\n",
+ gig_dbg(DEBUG_CMD, "unknown command %d from LL",
cntrl->command);
return -EINVAL;
}
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index d2260b0055fc..a1bcbc21ff71 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -45,8 +45,6 @@ static int if_lock(struct cardstate *cs, int *arg)
cs->waiting = 0;
return -ENOMEM;
}
-
- gig_dbg(DEBUG_CMD, "scheduling IF_LOCK");
gigaset_schedule_event(cs);
wait_event(cs->waitqueue, !cs->waiting);
@@ -81,8 +79,6 @@ static int if_version(struct cardstate *cs, unsigned arg[4])
cs->waiting = 0;
return -ENOMEM;
}
-
- gig_dbg(DEBUG_CMD, "scheduling IF_VER");
gigaset_schedule_event(cs);
wait_event(cs->waitqueue, !cs->waiting);
@@ -274,7 +270,7 @@ static int if_ioctl(struct tty_struct *tty, struct file *file,
? -EFAULT : 0;
break;
default:
- gig_dbg(DEBUG_ANY, "%s: arg not supported - 0x%04x",
+ gig_dbg(DEBUG_IF, "%s: arg not supported - 0x%04x",
__func__, cmd);
retval = -ENOIOCTLCMD;
}
@@ -455,7 +451,7 @@ static void if_throttle(struct tty_struct *tty)
else if (!cs->open_count)
dev_warn(cs->dev, "%s: device not opened\n", __func__);
else
- gig_dbg(DEBUG_ANY, "%s: not implemented\n", __func__);
+ gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
mutex_unlock(&cs->mutex);
}
@@ -479,7 +475,7 @@ static void if_unthrottle(struct tty_struct *tty)
else if (!cs->open_count)
dev_warn(cs->dev, "%s: device not opened\n", __func__);
else
- gig_dbg(DEBUG_ANY, "%s: not implemented\n", __func__);
+ gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
mutex_unlock(&cs->mutex);
}
@@ -630,7 +626,7 @@ void gigaset_if_receive(struct cardstate *cs,
spin_lock_irqsave(&cs->lock, flags);
tty = cs->tty;
if (tty == NULL)
- gig_dbg(DEBUG_ANY, "receive on closed device");
+ gig_dbg(DEBUG_IF, "receive on closed device");
else {
tty_buffer_request_room(tty, len);
tty_insert_flip_string(tty, buffer, len);
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
index 85394a6ebae8..16fd3bd48883 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -905,29 +905,49 @@ void gigaset_isoc_receive(unsigned char *src, unsigned count,
/* == data input =========================================================== */
+/* process a block of received bytes in command mode (mstate != MS_LOCKED)
+ * Append received bytes to the command response buffer and forward them
+ * line by line to the response handler.
+ * Note: Received lines may be terminated by CR, LF, or CR LF, which will be
+ * removed before passing the line to the response handler.
+ */
static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf)
{
struct cardstate *cs = inbuf->cs;
unsigned cbytes = cs->cbytes;
+ unsigned char c;
while (numbytes--) {
- /* copy next character, check for end of line */
- switch (cs->respdata[cbytes] = *src++) {
- case '\r':
+ c = *src++;
+ switch (c) {
case '\n':
- /* end of line */
- gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
- __func__, cbytes);
- if (cbytes >= MAX_RESP_SIZE - 1)
- dev_warn(cs->dev, "response too large\n");
+ if (cbytes == 0 && cs->respdata[0] == '\r') {
+ /* collapse LF with preceding CR */
+ cs->respdata[0] = 0;
+ break;
+ }
+ /* --v-- fall through --v-- */
+ case '\r':
+ /* end of message line, pass to response handler */
+ if (cbytes >= MAX_RESP_SIZE) {
+ dev_warn(cs->dev, "response too large (%d)\n",
+ cbytes);
+ cbytes = MAX_RESP_SIZE;
+ }
cs->cbytes = cbytes;
+ gigaset_dbg_buffer(DEBUG_TRANSCMD, "received response",
+ cbytes, cs->respdata);
gigaset_handle_modem_response(cs);
cbytes = 0;
+
+ /* store EOL byte for CRLF collapsing */
+ cs->respdata[0] = c;
break;
default:
- /* advance in line buffer, checking for overflow */
- if (cbytes < MAX_RESP_SIZE - 1)
- cbytes++;
+ /* append to line buffer if possible */
+ if (cbytes < MAX_RESP_SIZE)
+ cs->respdata[cbytes] = c;
+ cbytes++;
}
}
@@ -958,8 +978,6 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
numbytes, src);
gigaset_if_receive(inbuf->cs, src, numbytes);
} else {
- gigaset_dbg_buffer(DEBUG_CMD, "received response",
- numbytes, src);
cmd_loop(src, numbytes, inbuf);
}
diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c
index 758a00c1d2e2..b69f73a0668f 100644
--- a/drivers/isdn/gigaset/proc.c
+++ b/drivers/isdn/gigaset/proc.c
@@ -48,8 +48,6 @@ static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr,
mutex_unlock(&cs->mutex);
return -ENOMEM;
}
-
- gig_dbg(DEBUG_CMD, "scheduling PROC_CIDMODE");
gigaset_schedule_event(cs);
wait_event(cs->waitqueue, !cs->waiting);
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index 3ab1daeb276b..9430a2bbb523 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -628,7 +628,7 @@ static int write_modem(struct cardstate *cs)
struct usb_cardstate *ucs = cs->hw.usb;
unsigned long flags;
- gig_dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len);
+ gig_dbg(DEBUG_OUTPUT, "len: %d...", bcs->tx_skb->len);
if (!bcs->tx_skb->len) {
dev_kfree_skb_any(bcs->tx_skb);
diff --git a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h
index d964f07e4a56..a70e8854461d 100644
--- a/drivers/isdn/hardware/avm/avmcard.h
+++ b/drivers/isdn/hardware/avm/avmcard.h
@@ -556,8 +556,7 @@ u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
void b1_parse_version(avmctrl_info *card);
irqreturn_t b1_interrupt(int interrupt, void *devptr);
-int b1ctl_read_proc(char *page, char **start, off_t off,
- int count, int *eof, struct capi_ctr *ctrl);
+extern const struct file_operations b1ctl_proc_fops;
avmcard_dmainfo *avmcard_dma_alloc(char *name, struct pci_dev *,
long rsize, long ssize);
@@ -577,7 +576,6 @@ void b1dma_register_appl(struct capi_ctr *ctrl,
capi_register_params *rp);
void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl);
u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
-int b1dmactl_read_proc(char *page, char **start, off_t off,
- int count, int *eof, struct capi_ctr *ctrl);
+extern const struct file_operations b1dmactl_proc_fops;
#endif /* _AVMCARD_H_ */
diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c
index a7c0083e78a7..c38fa0f4c729 100644
--- a/drivers/isdn/hardware/avm/b1.c
+++ b/drivers/isdn/hardware/avm/b1.c
@@ -12,6 +12,8 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
@@ -634,18 +636,17 @@ irqreturn_t b1_interrupt(int interrupt, void *devptr)
}
/* ------------------------------------------------------------- */
-int b1ctl_read_proc(char *page, char **start, off_t off,
- int count, int *eof, struct capi_ctr *ctrl)
+static int b1ctl_proc_show(struct seq_file *m, void *v)
{
+ struct capi_ctr *ctrl = m->private;
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
u8 flag;
- int len = 0;
char *s;
- len += sprintf(page+len, "%-16s %s\n", "name", card->name);
- len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
- len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
+ seq_printf(m, "%-16s %s\n", "name", card->name);
+ seq_printf(m, "%-16s 0x%x\n", "io", card->port);
+ seq_printf(m, "%-16s %d\n", "irq", card->irq);
switch (card->cardtype) {
case avm_b1isa: s = "B1 ISA"; break;
case avm_b1pci: s = "B1 PCI"; break;
@@ -658,20 +659,20 @@ int b1ctl_read_proc(char *page, char **start, off_t off,
case avm_c2: s = "C2"; break;
default: s = "???"; break;
}
- len += sprintf(page+len, "%-16s %s\n", "type", s);
+ seq_printf(m, "%-16s %s\n", "type", s);
if (card->cardtype == avm_t1isa)
- len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr);
+ seq_printf(m, "%-16s %d\n", "cardnr", card->cardnr);
if ((s = cinfo->version[VER_DRIVER]) != NULL)
- len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+ seq_printf(m, "%-16s %s\n", "ver_driver", s);
if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
- len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+ seq_printf(m, "%-16s %s\n", "ver_cardtype", s);
if ((s = cinfo->version[VER_SERIAL]) != NULL)
- len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+ seq_printf(m, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[3];
if (flag)
- len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
+ seq_printf(m, "%-16s%s%s%s%s%s%s%s\n",
"protocol",
(flag & 0x01) ? " DSS1" : "",
(flag & 0x02) ? " CT1" : "",
@@ -685,7 +686,7 @@ int b1ctl_read_proc(char *page, char **start, off_t off,
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[5];
if (flag)
- len += sprintf(page+len, "%-16s%s%s%s%s\n",
+ seq_printf(m, "%-16s%s%s%s%s\n",
"linetype",
(flag & 0x01) ? " point to point" : "",
(flag & 0x02) ? " point to multipoint" : "",
@@ -693,16 +694,25 @@ int b1ctl_read_proc(char *page, char **start, off_t off,
(flag & 0x04) ? " leased line with D-channel" : ""
);
}
- len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
-
- if (off+count >= len)
- *eof = 1;
- if (len < off)
- return 0;
- *start = page + off;
- return ((count < len-off) ? count : len-off);
+ seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname);
+
+ return 0;
+}
+
+static int b1ctl_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, b1ctl_proc_show, PDE(inode)->data);
}
+const struct file_operations b1ctl_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = b1ctl_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+EXPORT_SYMBOL(b1ctl_proc_fops);
+
/* ------------------------------------------------------------- */
#ifdef CONFIG_PCI
@@ -781,8 +791,6 @@ EXPORT_SYMBOL(b1_send_message);
EXPORT_SYMBOL(b1_parse_version);
EXPORT_SYMBOL(b1_interrupt);
-EXPORT_SYMBOL(b1ctl_read_proc);
-
static int __init b1_init(void)
{
char *p;
diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
index 0e84aaae43fd..124550d0dbf3 100644
--- a/drivers/isdn/hardware/avm/b1dma.c
+++ b/drivers/isdn/hardware/avm/b1dma.c
@@ -11,6 +11,8 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
@@ -855,21 +857,20 @@ u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
/* ------------------------------------------------------------- */
-int b1dmactl_read_proc(char *page, char **start, off_t off,
- int count, int *eof, struct capi_ctr *ctrl)
+static int b1dmactl_proc_show(struct seq_file *m, void *v)
{
+ struct capi_ctr *ctrl = m->private;
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
u8 flag;
- int len = 0;
char *s;
u32 txoff, txlen, rxoff, rxlen, csr;
unsigned long flags;
- len += sprintf(page+len, "%-16s %s\n", "name", card->name);
- len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
- len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
- len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
+ seq_printf(m, "%-16s %s\n", "name", card->name);
+ seq_printf(m, "%-16s 0x%x\n", "io", card->port);
+ seq_printf(m, "%-16s %d\n", "irq", card->irq);
+ seq_printf(m, "%-16s 0x%lx\n", "membase", card->membase);
switch (card->cardtype) {
case avm_b1isa: s = "B1 ISA"; break;
case avm_b1pci: s = "B1 PCI"; break;
@@ -882,18 +883,18 @@ int b1dmactl_read_proc(char *page, char **start, off_t off,
case avm_c2: s = "C2"; break;
default: s = "???"; break;
}
- len += sprintf(page+len, "%-16s %s\n", "type", s);
+ seq_printf(m, "%-16s %s\n", "type", s);
if ((s = cinfo->version[VER_DRIVER]) != NULL)
- len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+ seq_printf(m, "%-16s %s\n", "ver_driver", s);
if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
- len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+ seq_printf(m, "%-16s %s\n", "ver_cardtype", s);
if ((s = cinfo->version[VER_SERIAL]) != NULL)
- len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+ seq_printf(m, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[3];
if (flag)
- len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
+ seq_printf(m, "%-16s%s%s%s%s%s%s%s\n",
"protocol",
(flag & 0x01) ? " DSS1" : "",
(flag & 0x02) ? " CT1" : "",
@@ -907,7 +908,7 @@ int b1dmactl_read_proc(char *page, char **start, off_t off,
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[5];
if (flag)
- len += sprintf(page+len, "%-16s%s%s%s%s\n",
+ seq_printf(m, "%-16s%s%s%s%s\n",
"linetype",
(flag & 0x01) ? " point to point" : "",
(flag & 0x02) ? " point to multipoint" : "",
@@ -915,7 +916,7 @@ int b1dmactl_read_proc(char *page, char **start, off_t off,
(flag & 0x04) ? " leased line with D-channel" : ""
);
}
- len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
+ seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname);
spin_lock_irqsave(&card->lock, flags);
@@ -930,27 +931,30 @@ int b1dmactl_read_proc(char *page, char **start, off_t off,
spin_unlock_irqrestore(&card->lock, flags);
- len += sprintf(page+len, "%-16s 0x%lx\n",
- "csr (cached)", (unsigned long)card->csr);
- len += sprintf(page+len, "%-16s 0x%lx\n",
- "csr", (unsigned long)csr);
- len += sprintf(page+len, "%-16s %lu\n",
- "txoff", (unsigned long)txoff);
- len += sprintf(page+len, "%-16s %lu\n",
- "txlen", (unsigned long)txlen);
- len += sprintf(page+len, "%-16s %lu\n",
- "rxoff", (unsigned long)rxoff);
- len += sprintf(page+len, "%-16s %lu\n",
- "rxlen", (unsigned long)rxlen);
-
- if (off+count >= len)
- *eof = 1;
- if (len < off)
- return 0;
- *start = page + off;
- return ((count < len-off) ? count : len-off);
+ seq_printf(m, "%-16s 0x%lx\n", "csr (cached)", (unsigned long)card->csr);
+ seq_printf(m, "%-16s 0x%lx\n", "csr", (unsigned long)csr);
+ seq_printf(m, "%-16s %lu\n", "txoff", (unsigned long)txoff);
+ seq_printf(m, "%-16s %lu\n", "txlen", (unsigned long)txlen);
+ seq_printf(m, "%-16s %lu\n", "rxoff", (unsigned long)rxoff);
+ seq_printf(m, "%-16s %lu\n", "rxlen", (unsigned long)rxlen);
+
+ return 0;
+}
+
+static int b1dmactl_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, b1dmactl_proc_show, PDE(inode)->data);
}
+const struct file_operations b1dmactl_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = b1dmactl_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+EXPORT_SYMBOL(b1dmactl_proc_fops);
+
/* ------------------------------------------------------------- */
EXPORT_SYMBOL(b1dma_reset);
@@ -963,7 +967,6 @@ EXPORT_SYMBOL(b1dma_reset_ctr);
EXPORT_SYMBOL(b1dma_register_appl);
EXPORT_SYMBOL(b1dma_release_appl);
EXPORT_SYMBOL(b1dma_send_message);
-EXPORT_SYMBOL(b1dmactl_read_proc);
static int __init b1dma_init(void)
{
diff --git a/drivers/isdn/hardware/avm/b1isa.c b/drivers/isdn/hardware/avm/b1isa.c
index 6461a32bc838..ff5390546f92 100644
--- a/drivers/isdn/hardware/avm/b1isa.c
+++ b/drivers/isdn/hardware/avm/b1isa.c
@@ -121,7 +121,7 @@ static int b1isa_probe(struct pci_dev *pdev)
cinfo->capi_ctrl.load_firmware = b1_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1_reset_ctr;
cinfo->capi_ctrl.procinfo = b1isa_procinfo;
- cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
+ cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c
index 5b314a2c4049..c97e4315079d 100644
--- a/drivers/isdn/hardware/avm/b1pci.c
+++ b/drivers/isdn/hardware/avm/b1pci.c
@@ -112,7 +112,7 @@ static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev)
cinfo->capi_ctrl.load_firmware = b1_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1_reset_ctr;
cinfo->capi_ctrl.procinfo = b1pci_procinfo;
- cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
+ cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops;
strcpy(cinfo->capi_ctrl.name, card->name);
cinfo->capi_ctrl.owner = THIS_MODULE;
@@ -251,7 +251,7 @@ static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev)
cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr;
cinfo->capi_ctrl.procinfo = b1pciv4_procinfo;
- cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc;
+ cinfo->capi_ctrl.proc_fops = &b1dmactl_proc_fops;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
diff --git a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c
index 7740403b40e1..d6391e0afeea 100644
--- a/drivers/isdn/hardware/avm/b1pcmcia.c
+++ b/drivers/isdn/hardware/avm/b1pcmcia.c
@@ -108,7 +108,7 @@ static int b1pcmcia_add_card(unsigned int port, unsigned irq,
cinfo->capi_ctrl.load_firmware = b1_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1_reset_ctr;
cinfo->capi_ctrl.procinfo = b1pcmcia_procinfo;
- cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
+ cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
index 6833301a45fc..de6e6b311819 100644
--- a/drivers/isdn/hardware/avm/c4.c
+++ b/drivers/isdn/hardware/avm/c4.c
@@ -11,6 +11,8 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
@@ -1062,19 +1064,18 @@ static char *c4_procinfo(struct capi_ctr *ctrl)
return cinfo->infobuf;
}
-static int c4_read_proc(char *page, char **start, off_t off,
- int count, int *eof, struct capi_ctr *ctrl)
+static int c4_proc_show(struct seq_file *m, void *v)
{
+ struct capi_ctr *ctrl = m->private;
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
u8 flag;
- int len = 0;
char *s;
- len += sprintf(page+len, "%-16s %s\n", "name", card->name);
- len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
- len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
- len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
+ seq_printf(m, "%-16s %s\n", "name", card->name);
+ seq_printf(m, "%-16s 0x%x\n", "io", card->port);
+ seq_printf(m, "%-16s %d\n", "irq", card->irq);
+ seq_printf(m, "%-16s 0x%lx\n", "membase", card->membase);
switch (card->cardtype) {
case avm_b1isa: s = "B1 ISA"; break;
case avm_b1pci: s = "B1 PCI"; break;
@@ -1087,18 +1088,18 @@ static int c4_read_proc(char *page, char **start, off_t off,
case avm_c2: s = "C2"; break;
default: s = "???"; break;
}
- len += sprintf(page+len, "%-16s %s\n", "type", s);
+ seq_printf(m, "%-16s %s\n", "type", s);
if ((s = cinfo->version[VER_DRIVER]) != NULL)
- len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+ seq_printf(m, "%-16s %s\n", "ver_driver", s);
if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
- len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+ seq_printf(m, "%-16s %s\n", "ver_cardtype", s);
if ((s = cinfo->version[VER_SERIAL]) != NULL)
- len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+ seq_printf(m, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[3];
if (flag)
- len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
+ seq_printf(m, "%-16s%s%s%s%s%s%s%s\n",
"protocol",
(flag & 0x01) ? " DSS1" : "",
(flag & 0x02) ? " CT1" : "",
@@ -1112,7 +1113,7 @@ static int c4_read_proc(char *page, char **start, off_t off,
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[5];
if (flag)
- len += sprintf(page+len, "%-16s%s%s%s%s\n",
+ seq_printf(m, "%-16s%s%s%s%s\n",
"linetype",
(flag & 0x01) ? " point to point" : "",
(flag & 0x02) ? " point to multipoint" : "",
@@ -1120,16 +1121,24 @@ static int c4_read_proc(char *page, char **start, off_t off,
(flag & 0x04) ? " leased line with D-channel" : ""
);
}
- len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
-
- if (off+count >= len)
- *eof = 1;
- if (len < off)
- return 0;
- *start = page + off;
- return ((count < len-off) ? count : len-off);
+ seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname);
+
+ return 0;
}
+static int c4_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, c4_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations c4_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = c4_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/* ------------------------------------------------------------- */
static int c4_add_card(struct capicardparams *p, struct pci_dev *dev,
@@ -1201,7 +1210,7 @@ static int c4_add_card(struct capicardparams *p, struct pci_dev *dev,
cinfo->capi_ctrl.load_firmware = c4_load_firmware;
cinfo->capi_ctrl.reset_ctr = c4_reset_ctr;
cinfo->capi_ctrl.procinfo = c4_procinfo;
- cinfo->capi_ctrl.ctr_read_proc = c4_read_proc;
+ cinfo->capi_ctrl.proc_fops = &c4_proc_fops;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c
index 1c53fd49adb6..baeeb3c2a3ee 100644
--- a/drivers/isdn/hardware/avm/t1isa.c
+++ b/drivers/isdn/hardware/avm/t1isa.c
@@ -429,7 +429,7 @@ static int t1isa_probe(struct pci_dev *pdev, int cardnr)
cinfo->capi_ctrl.load_firmware = t1isa_load_firmware;
cinfo->capi_ctrl.reset_ctr = t1isa_reset_ctr;
cinfo->capi_ctrl.procinfo = t1isa_procinfo;
- cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
+ cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c
index e6d298d75146..5a3f83098018 100644
--- a/drivers/isdn/hardware/avm/t1pci.c
+++ b/drivers/isdn/hardware/avm/t1pci.c
@@ -119,7 +119,7 @@ static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev)
cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr;
cinfo->capi_ctrl.procinfo = t1pci_procinfo;
- cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc;
+ cinfo->capi_ctrl.proc_fops = &b1dmactl_proc_fops;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
diff --git a/drivers/isdn/hardware/eicon/capimain.c b/drivers/isdn/hardware/eicon/capimain.c
index 98fcdfc7ca55..0f073cd73763 100644
--- a/drivers/isdn/hardware/eicon/capimain.c
+++ b/drivers/isdn/hardware/eicon/capimain.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <asm/uaccess.h>
+#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include "os_capi.h"
@@ -75,25 +76,32 @@ void diva_os_free_message_buffer(diva_os_message_buffer_s * dmb)
/*
* proc function for controller info
*/
-static int diva_ctl_read_proc(char *page, char **start, off_t off,
- int count, int *eof, struct capi_ctr *ctrl)
+static int diva_ctl_proc_show(struct seq_file *m, void *v)
{
+ struct capi_ctr *ctrl = m->private;
diva_card *card = (diva_card *) ctrl->driverdata;
- int len = 0;
-
- len += sprintf(page + len, "%s\n", ctrl->name);
- len += sprintf(page + len, "Serial No. : %s\n", ctrl->serial);
- len += sprintf(page + len, "Id : %d\n", card->Id);
- len += sprintf(page + len, "Channels : %d\n", card->d.channels);
-
- if (off + count >= len)
- *eof = 1;
- if (len < off)
- return 0;
- *start = page + off;
- return ((count < len - off) ? count : len - off);
+
+ seq_printf(m, "%s\n", ctrl->name);
+ seq_printf(m, "Serial No. : %s\n", ctrl->serial);
+ seq_printf(m, "Id : %d\n", card->Id);
+ seq_printf(m, "Channels : %d\n", card->d.channels);
+
+ return 0;
+}
+
+static int diva_ctl_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, diva_ctl_proc_show, NULL);
}
+static const struct file_operations diva_ctl_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = diva_ctl_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/*
* set additional os settings in capi_ctr struct
*/
@@ -102,7 +110,7 @@ void diva_os_set_controller_struct(struct capi_ctr *ctrl)
ctrl->driver_name = DRIVERLNAME;
ctrl->load_firmware = NULL;
ctrl->reset_ctr = NULL;
- ctrl->ctr_read_proc = diva_ctl_read_proc;
+ ctrl->proc_fops = &diva_ctl_proc_fops;
ctrl->owner = THIS_MODULE;
}
diff --git a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c
index 993b14cf1778..5d06a7437824 100644
--- a/drivers/isdn/hardware/eicon/diva_didd.c
+++ b/drivers/isdn/hardware/eicon/diva_didd.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <net/net_namespace.h>
#include "platform.h"
@@ -62,39 +63,41 @@ static char *getrev(const char *revision)
return rev;
}
-static int
-proc_read(char *page, char **start, off_t off, int count, int *eof,
- void *data)
+static int divadidd_proc_show(struct seq_file *m, void *v)
{
- int len = 0;
char tmprev[32];
strcpy(tmprev, main_revision);
- len += sprintf(page + len, "%s\n", DRIVERNAME);
- len += sprintf(page + len, "name : %s\n", DRIVERLNAME);
- len += sprintf(page + len, "release : %s\n", DRIVERRELEASE_DIDD);
- len += sprintf(page + len, "build : %s(%s)\n",
+ seq_printf(m, "%s\n", DRIVERNAME);
+ seq_printf(m, "name : %s\n", DRIVERLNAME);
+ seq_printf(m, "release : %s\n", DRIVERRELEASE_DIDD);
+ seq_printf(m, "build : %s(%s)\n",
diva_didd_common_code_build, DIVA_BUILD);
- len += sprintf(page + len, "revision : %s\n", getrev(tmprev));
-
- if (off + count >= len)
- *eof = 1;
- if (len < off)
- return 0;
- *start = page + off;
- return ((count < len - off) ? count : len - off);
+ seq_printf(m, "revision : %s\n", getrev(tmprev));
+
+ return 0;
}
+static int divadidd_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, divadidd_proc_show, NULL);
+}
+
+static const struct file_operations divadidd_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = divadidd_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static int DIVA_INIT_FUNCTION create_proc(void)
{
proc_net_eicon = proc_mkdir("eicon", init_net.proc_net);
if (proc_net_eicon) {
- if ((proc_didd =
- create_proc_entry(DRIVERLNAME, S_IFREG | S_IRUGO,
- proc_net_eicon))) {
- proc_didd->read_proc = proc_read;
- }
+ proc_didd = proc_create(DRIVERLNAME, S_IRUGO, proc_net_eicon,
+ &divadidd_proc_fops);
return (1);
}
return (0);
diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c
index 69e71ebe7841..f577719ab3fa 100644
--- a/drivers/isdn/hardware/eicon/divasi.c
+++ b/drivers/isdn/hardware/eicon/divasi.c
@@ -17,6 +17,7 @@
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/skbuff.h>
+#include <linux/seq_file.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -86,39 +87,40 @@ static void diva_um_timer_function(unsigned long data);
extern struct proc_dir_entry *proc_net_eicon;
static struct proc_dir_entry *um_idi_proc_entry = NULL;
-static int
-um_idi_proc_read(char *page, char **start, off_t off, int count, int *eof,
- void *data)
+static int um_idi_proc_show(struct seq_file *m, void *v)
{
- int len = 0;
char tmprev[32];
- len += sprintf(page + len, "%s\n", DRIVERNAME);
- len += sprintf(page + len, "name : %s\n", DRIVERLNAME);
- len += sprintf(page + len, "release : %s\n", DRIVERRELEASE_IDI);
+ seq_printf(m, "%s\n", DRIVERNAME);
+ seq_printf(m, "name : %s\n", DRIVERLNAME);
+ seq_printf(m, "release : %s\n", DRIVERRELEASE_IDI);
strcpy(tmprev, main_revision);
- len += sprintf(page + len, "revision : %s\n", getrev(tmprev));
- len += sprintf(page + len, "build : %s\n", DIVA_BUILD);
- len += sprintf(page + len, "major : %d\n", major);
-
- if (off + count >= len)
- *eof = 1;
- if (len < off)
- return 0;
- *start = page + off;
- return ((count < len - off) ? count : len - off);
+ seq_printf(m, "revision : %s\n", getrev(tmprev));
+ seq_printf(m, "build : %s\n", DIVA_BUILD);
+ seq_printf(m, "major : %d\n", major);
+
+ return 0;
+}
+
+static int um_idi_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, um_idi_proc_show, NULL);
}
+static const struct file_operations um_idi_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = um_idi_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static int DIVA_INIT_FUNCTION create_um_idi_proc(void)
{
- um_idi_proc_entry = create_proc_entry(DRIVERLNAME,
- S_IFREG | S_IRUGO | S_IWUSR,
- proc_net_eicon);
+ um_idi_proc_entry = proc_create(DRIVERLNAME, S_IRUGO, proc_net_eicon,
+ &um_idi_proc_fops);
if (!um_idi_proc_entry)
return (0);
-
- um_idi_proc_entry->read_proc = um_idi_proc_read;
-
return (1);
}
diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c
index 040827288ec9..46d44a942624 100644
--- a/drivers/isdn/hardware/eicon/divasproc.c
+++ b/drivers/isdn/hardware/eicon/divasproc.c
@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/list.h>
#include <asm/uaccess.h>
@@ -141,14 +142,10 @@ void remove_divas_proc(void)
}
}
-/*
-** write group_optimization
-*/
-static int
-write_grp_opt(struct file *file, const char __user *buffer, unsigned long count,
- void *data)
+static ssize_t grp_opt_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *pos)
{
- diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+ diva_os_xdi_adapter_t *a = PDE(file->f_path.dentry->d_inode)->data;
PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
if ((count == 1) || (count == 2)) {
@@ -172,14 +169,10 @@ write_grp_opt(struct file *file, const char __user *buffer, unsigned long count,
return (-EINVAL);
}
-/*
-** write dynamic_l1_down
-*/
-static int
-write_d_l1_down(struct file *file, const char __user *buffer, unsigned long count,
- void *data)
+static ssize_t d_l1_down_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *pos)
{
- diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+ diva_os_xdi_adapter_t *a = PDE(file->f_path.dentry->d_inode)->data;
PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
if ((count == 1) || (count == 2)) {
@@ -203,63 +196,62 @@ write_d_l1_down(struct file *file, const char __user *buffer, unsigned long coun
return (-EINVAL);
}
-
-/*
-** read dynamic_l1_down
-*/
-static int
-read_d_l1_down(char *page, char **start, off_t off, int count, int *eof,
- void *data)
+static int d_l1_down_proc_show(struct seq_file *m, void *v)
{
- int len = 0;
- diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+ diva_os_xdi_adapter_t *a = m->private;
PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
- len += sprintf(page + len, "%s\n",
+ seq_printf(m, "%s\n",
(IoAdapter->capi_cfg.
cfg_1 & DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? "1" :
"0");
+ return 0;
+}
- if (off + count >= len)
- *eof = 1;
- if (len < off)
- return 0;
- *start = page + off;
- return ((count < len - off) ? count : len - off);
+static int d_l1_down_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, d_l1_down_proc_show, PDE(inode)->data);
}
-/*
-** read group_optimization
-*/
-static int
-read_grp_opt(char *page, char **start, off_t off, int count, int *eof,
- void *data)
+static const struct file_operations d_l1_down_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = d_l1_down_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = d_l1_down_proc_write,
+};
+
+static int grp_opt_proc_show(struct seq_file *m, void *v)
{
- int len = 0;
- diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+ diva_os_xdi_adapter_t *a = m->private;
PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
- len += sprintf(page + len, "%s\n",
+ seq_printf(m, "%s\n",
(IoAdapter->capi_cfg.
cfg_1 & DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON)
? "1" : "0");
+ return 0;
+}
- if (off + count >= len)
- *eof = 1;
- if (len < off)
- return 0;
- *start = page + off;
- return ((count < len - off) ? count : len - off);
+static int grp_opt_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, grp_opt_proc_show, PDE(inode)->data);
}
-/*
-** info write
-*/
-static int
-info_write(struct file *file, const char __user *buffer, unsigned long count,
- void *data)
+static const struct file_operations grp_opt_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = grp_opt_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = grp_opt_proc_write,
+};
+
+static ssize_t info_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *pos)
{
- diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+ diva_os_xdi_adapter_t *a = PDE(file->f_path.dentry->d_inode)->data;
PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
char c[4];
@@ -277,63 +269,46 @@ info_write(struct file *file, const char __user *buffer, unsigned long count,
return (-EINVAL);
}
-/*
-** info read
-*/
-static int
-info_read(char *page, char **start, off_t off, int count, int *eof,
- void *data)
+static int info_proc_show(struct seq_file *m, void *v)
{
int i = 0;
- int len = 0;
char *p;
char tmpser[16];
- diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+ diva_os_xdi_adapter_t *a = m->private;
PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
- len +=
- sprintf(page + len, "Name : %s\n",
- IoAdapter->Properties.Name);
- len += sprintf(page + len, "DSP state : %08x\n", a->dsp_mask);
- len += sprintf(page + len, "Channels : %02d\n",
- IoAdapter->Properties.Channels);
- len += sprintf(page + len, "E. max/used : %03d/%03d\n",
+ seq_printf(m, "Name : %s\n", IoAdapter->Properties.Name);
+ seq_printf(m, "DSP state : %08x\n", a->dsp_mask);
+ seq_printf(m, "Channels : %02d\n", IoAdapter->Properties.Channels);
+ seq_printf(m, "E. max/used : %03d/%03d\n",
IoAdapter->e_max, IoAdapter->e_count);
diva_get_vserial_number(IoAdapter, tmpser);
- len += sprintf(page + len, "Serial : %s\n", tmpser);
- len +=
- sprintf(page + len, "IRQ : %d\n",
- IoAdapter->irq_info.irq_nr);
- len += sprintf(page + len, "CardIndex : %d\n", a->CardIndex);
- len += sprintf(page + len, "CardOrdinal : %d\n", a->CardOrdinal);
- len += sprintf(page + len, "Controller : %d\n", a->controller);
- len += sprintf(page + len, "Bus-Type : %s\n",
+ seq_printf(m, "Serial : %s\n", tmpser);
+ seq_printf(m, "IRQ : %d\n", IoAdapter->irq_info.irq_nr);
+ seq_printf(m, "CardIndex : %d\n", a->CardIndex);
+ seq_printf(m, "CardOrdinal : %d\n", a->CardOrdinal);
+ seq_printf(m, "Controller : %d\n", a->controller);
+ seq_printf(m, "Bus-Type : %s\n",
(a->Bus ==
DIVAS_XDI_ADAPTER_BUS_ISA) ? "ISA" : "PCI");
- len += sprintf(page + len, "Port-Name : %s\n", a->port_name);
+ seq_printf(m, "Port-Name : %s\n", a->port_name);
if (a->Bus == DIVAS_XDI_ADAPTER_BUS_PCI) {
- len +=
- sprintf(page + len, "PCI-bus : %d\n",
- a->resources.pci.bus);
- len +=
- sprintf(page + len, "PCI-func : %d\n",
- a->resources.pci.func);
+ seq_printf(m, "PCI-bus : %d\n", a->resources.pci.bus);
+ seq_printf(m, "PCI-func : %d\n", a->resources.pci.func);
for (i = 0; i < 8; i++) {
if (a->resources.pci.bar[i]) {
- len +=
- sprintf(page + len,
+ seq_printf(m,
"Mem / I/O %d : 0x%x / mapped : 0x%lx",
i, a->resources.pci.bar[i],
(unsigned long) a->resources.
pci.addr[i]);
if (a->resources.pci.length[i]) {
- len +=
- sprintf(page + len,
+ seq_printf(m,
" / length : %d",
a->resources.pci.
length[i]);
}
- len += sprintf(page + len, "\n");
+ seq_putc(m, '\n');
}
}
}
@@ -353,16 +328,25 @@ info_read(char *page, char **start, off_t off, int count, int *eof,
} else {
p = "ready";
}
- len += sprintf(page + len, "State : %s\n", p);
+ seq_printf(m, "State : %s\n", p);
- if (off + count >= len)
- *eof = 1;
- if (len < off)
- return 0;
- *start = page + off;
- return ((count < len - off) ? count : len - off);
+ return 0;
+}
+
+static int info_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, info_proc_show, PDE(inode)->data);
}
+static const struct file_operations info_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = info_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = info_proc_write,
+};
+
/*
** adapter proc init/de-init
*/
@@ -380,28 +364,20 @@ int create_adapter_proc(diva_os_xdi_adapter_t * a)
return (0);
a->proc_adapter_dir = (void *) de;
- if (!(pe =
- create_proc_entry(info_proc_name, S_IFREG | S_IRUGO | S_IWUSR, de)))
+ pe = proc_create_data(info_proc_name, S_IRUGO | S_IWUSR, de,
+ &info_proc_fops, a);
+ if (!pe)
return (0);
a->proc_info = (void *) pe;
- pe->write_proc = info_write;
- pe->read_proc = info_read;
- pe->data = a;
- if ((pe = create_proc_entry(grp_opt_proc_name,
- S_IFREG | S_IRUGO | S_IWUSR, de))) {
+ pe = proc_create_data(grp_opt_proc_name, S_IRUGO | S_IWUSR, de,
+ &grp_opt_proc_fops, a);
+ if (pe)
a->proc_grp_opt = (void *) pe;
- pe->write_proc = write_grp_opt;
- pe->read_proc = read_grp_opt;
- pe->data = a;
- }
- if ((pe = create_proc_entry(d_l1_down_proc_name,
- S_IFREG | S_IRUGO | S_IWUSR, de))) {
+ pe = proc_create_data(d_l1_down_proc_name, S_IRUGO | S_IWUSR, de,
+ &d_l1_down_proc_fops, a);
+ if (pe)
a->proc_d_l1_down = (void *) pe;
- pe->write_proc = write_d_l1_down;
- pe->read_proc = read_d_l1_down;
- pe->data = a;
- }
DBG_TRC(("proc entry %s created", tmp));
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 1a1420d7a828..ad36df9b759c 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -2846,7 +2846,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx,
int conf;
if (ch < 0 || ch > 31)
- return EINVAL;
+ return -EINVAL;
oslot_tx = hc->chan[ch].slot_tx;
oslot_rx = hc->chan[ch].slot_rx;
conf = hc->chan[ch].conf;
diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
index 62441ba53b95..36c6c616a655 100644
--- a/drivers/isdn/hardware/mISDN/mISDNinfineon.c
+++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
@@ -1133,6 +1133,7 @@ inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err) {
kfree(sc);
release_card(card);
+ break;
} else
card->sc[i - 1] = sc;
}
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c
index 09095c747110..f0bc6fa95809 100644
--- a/drivers/isdn/hardware/mISDN/mISDNisar.c
+++ b/drivers/isdn/hardware/mISDN/mISDNisar.c
@@ -1712,13 +1712,13 @@ mISDNisar_init(struct isar_hw *isar, void *hw)
}
EXPORT_SYMBOL(mISDNisar_init);
-static int isar_mod_init(void)
+static int __init isar_mod_init(void)
{
pr_notice("mISDN: ISAR driver Rev. %s\n", ISAR_REV);
return 0;
}
-static void isar_mod_cleanup(void)
+static void __exit isar_mod_cleanup(void)
{
pr_notice("mISDN: ISAR module unloaded\n");
}
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c
index d3f1077b709b..2952a58c7a61 100644
--- a/drivers/isdn/hardware/mISDN/w6692.c
+++ b/drivers/isdn/hardware/mISDN/w6692.c
@@ -529,6 +529,7 @@ W6692_fill_Bfifo(struct w6692_ch *wch)
}
}
+#if 0
static int
setvolume(struct w6692_ch *wch, int mic, struct sk_buff *skb)
{
@@ -571,6 +572,7 @@ enable_pots(struct w6692_ch *wch)
WriteW6692(card, W_PCTL, card->pctl);
return 0;
}
+#endif
static int
disable_pots(struct w6692_ch *wch)
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
index 3464ebc4cdbc..452fde9edf86 100644
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -109,7 +109,7 @@ config HISAX_16_3
config HISAX_TELESPCI
bool "Teles PCI"
- depends on PCI && PCI_LEGACY && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
+ depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the Teles PCI.
See <file:Documentation/isdn/README.HiSax> on how to configure it.
@@ -237,7 +237,7 @@ config HISAX_MIC
config HISAX_NETJET
bool "NETjet card"
- depends on PCI && PCI_LEGACY && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
+ depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the NetJet from Traverse
Technologies.
@@ -248,7 +248,7 @@ config HISAX_NETJET
config HISAX_NETJET_U
bool "NETspider U card"
- depends on PCI && PCI_LEGACY && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
+ depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the Netspider U interface ISDN card
from Traverse Technologies.
@@ -287,7 +287,7 @@ config HISAX_HSTSAPHIR
config HISAX_BKM_A4T
bool "Telekom A4T card"
- depends on PCI && PCI_LEGACY
+ depends on PCI
help
This enables HiSax support for the Telekom A4T card.
@@ -297,7 +297,7 @@ config HISAX_BKM_A4T
config HISAX_SCT_QUADRO
bool "Scitel Quadro card"
- depends on PCI && PCI_LEGACY
+ depends on PCI
help
This enables HiSax support for the Scitel Quadro card.
@@ -316,7 +316,7 @@ config HISAX_GAZEL
config HISAX_HFC_PCI
bool "HFC PCI-Bus cards"
- depends on PCI && PCI_LEGACY && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
+ depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
@@ -325,7 +325,7 @@ config HISAX_HFC_PCI
config HISAX_W6692
bool "Winbond W6692 based cards"
- depends on PCI && PCI_LEGACY
+ depends on PCI
help
This enables HiSax support for Winbond W6692 based PCI ISDN cards.
@@ -341,7 +341,7 @@ config HISAX_HFC_SX
config HISAX_ENTERNOW_PCI
bool "Formula-n enter:now PCI card"
- depends on HISAX_NETJET && PCI && PCI_LEGACY && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
+ depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the Formula-n enter:now PCI
ISDN card.
@@ -412,7 +412,7 @@ config HISAX_HFC4S8S
config HISAX_FRITZ_PCIPNP
tristate "AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)"
- depends on PCI && PCI_LEGACY && EXPERIMENTAL
+ depends on PCI && EXPERIMENTAL
help
This enables the driver for the AVM Fritz!Card PCI,
Fritz!Card PCI v2 and Fritz!Card PnP.
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index 7cabc5a19492..14295a155e71 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -822,7 +822,7 @@ static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
#endif /* __ISAPNP__ */
-#ifndef CONFIG_PCI_LEGACY
+#ifndef CONFIG_PCI
static int __devinit avm_pci_setup(struct IsdnCardState *cs)
{
@@ -835,7 +835,7 @@ static struct pci_dev *dev_avm __devinitdata = NULL;
static int __devinit avm_pci_setup(struct IsdnCardState *cs)
{
- if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
+ if ((dev_avm = hisax_find_pci_device(PCI_VENDOR_ID_AVM,
PCI_DEVICE_ID_AVM_A1, dev_avm))) {
if (pci_enable_device(dev_avm))
@@ -864,7 +864,7 @@ static int __devinit avm_pci_setup(struct IsdnCardState *cs)
return (1);
}
-#endif /* CONFIG_PCI_LEGACY */
+#endif /* CONFIG_PCI */
int __devinit
setup_avm_pcipnp(struct IsdnCard *card)
diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
index 9ca2ee54cc94..9f2009c0b69c 100644
--- a/drivers/isdn/hisax/bkm_a4t.c
+++ b/drivers/isdn/hisax/bkm_a4t.c
@@ -340,7 +340,7 @@ setup_bkm_a4t(struct IsdnCard *card)
} else
return (0);
- while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN,
+ while ((dev_a4t = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN,
PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
ret = a4t_pci_probe(dev_a4t, cs, &found, &pci_memaddr);
if (!ret)
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index e1ff4717a8a6..e775706c60e3 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -301,7 +301,7 @@ setup_sct_quadro(struct IsdnCard *card)
(sub_vendor_id != PCI_VENDOR_ID_BERKOM)))
return (0);
if (cs->subtyp == SCT_1) {
- while ((dev_a8 = pci_find_device(PCI_VENDOR_ID_PLX,
+ while ((dev_a8 = hisax_find_pci_device(PCI_VENDOR_ID_PLX,
PCI_DEVICE_ID_PLX_9050, dev_a8))) {
sub_vendor_id = dev_a8->subsystem_vendor;
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 0b0c2e5d806b..780da9bda915 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -1148,7 +1148,7 @@ static int __devinit setup_diva_isapnp(struct IsdnCard *card)
#endif /* ISAPNP */
-#ifdef CONFIG_PCI_LEGACY
+#ifdef CONFIG_PCI
static struct pci_dev *dev_diva __devinitdata = NULL;
static struct pci_dev *dev_diva_u __devinitdata = NULL;
static struct pci_dev *dev_diva201 __devinitdata = NULL;
@@ -1159,21 +1159,21 @@ static int __devinit setup_diva_pci(struct IsdnCard *card)
struct IsdnCardState *cs = card->cs;
cs->subtyp = 0;
- if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
+ if ((dev_diva = hisax_find_pci_device(PCI_VENDOR_ID_EICON,
PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
if (pci_enable_device(dev_diva))
return(0);
cs->subtyp = DIVA_PCI;
cs->irq = dev_diva->irq;
cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
- } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
+ } else if ((dev_diva_u = hisax_find_pci_device(PCI_VENDOR_ID_EICON,
PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
if (pci_enable_device(dev_diva_u))
return(0);
cs->subtyp = DIVA_PCI;
cs->irq = dev_diva_u->irq;
cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
- } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
+ } else if ((dev_diva201 = hisax_find_pci_device(PCI_VENDOR_ID_EICON,
PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
if (pci_enable_device(dev_diva201))
return(0);
@@ -1183,7 +1183,7 @@ static int __devinit setup_diva_pci(struct IsdnCard *card)
(ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
cs->hw.diva.cfg_reg =
(ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
- } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
+ } else if ((dev_diva202 = hisax_find_pci_device(PCI_VENDOR_ID_EICON,
PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
if (pci_enable_device(dev_diva202))
return(0);
@@ -1229,14 +1229,14 @@ static int __devinit setup_diva_pci(struct IsdnCard *card)
return (1); /* card found */
}
-#else /* if !CONFIG_PCI_LEGACY */
+#else /* if !CONFIG_PCI */
static int __devinit setup_diva_pci(struct IsdnCard *card)
{
return (-1); /* card not found; continue search */
}
-#endif /* CONFIG_PCI_LEGACY */
+#endif /* CONFIG_PCI */
int __devinit
setup_diva(struct IsdnCard *card)
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index aa29d1cf16af..23c41fcd864e 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -1025,7 +1025,7 @@ setup_elsa_pcmcia(struct IsdnCard *card)
cs->irq);
}
-#ifdef CONFIG_PCI_LEGACY
+#ifdef CONFIG_PCI
static struct pci_dev *dev_qs1000 __devinitdata = NULL;
static struct pci_dev *dev_qs3000 __devinitdata = NULL;
@@ -1035,7 +1035,7 @@ setup_elsa_pci(struct IsdnCard *card)
struct IsdnCardState *cs = card->cs;
cs->subtyp = 0;
- if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+ if ((dev_qs1000 = hisax_find_pci_device(PCI_VENDOR_ID_ELSA,
PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
if (pci_enable_device(dev_qs1000))
return(0);
@@ -1043,7 +1043,7 @@ setup_elsa_pci(struct IsdnCard *card)
cs->irq = dev_qs1000->irq;
cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
- } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+ } else if ((dev_qs3000 = hisax_find_pci_device(PCI_VENDOR_ID_ELSA,
PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
if (pci_enable_device(dev_qs3000))
return(0);
@@ -1093,7 +1093,7 @@ setup_elsa_pci(struct IsdnCard *card)
{
return (1);
}
-#endif /* CONFIG_PCI_LEGACY */
+#endif /* CONFIG_PCI */
static int __devinit
setup_elsa_common(struct IsdnCard *card)
diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c
index 39f421ed8de8..26264abf1f58 100644
--- a/drivers/isdn/hisax/enternow_pci.c
+++ b/drivers/isdn/hisax/enternow_pci.c
@@ -406,7 +406,7 @@ setup_enternow_pci(struct IsdnCard *card)
for ( ;; )
{
- if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET,
PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
ret = en_pci_probe(dev_netjet, cs);
if (!ret)
diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c
index 0ea3b4607680..353982fc1436 100644
--- a/drivers/isdn/hisax/gazel.c
+++ b/drivers/isdn/hisax/gazel.c
@@ -531,7 +531,7 @@ setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
return (0);
}
-#ifdef CONFIG_PCI_LEGACY
+#ifdef CONFIG_PCI
static struct pci_dev *dev_tel __devinitdata = NULL;
static int __devinit
@@ -546,7 +546,7 @@ setup_gazelpci(struct IsdnCardState *cs)
found = 0;
seekcard = PCI_DEVICE_ID_PLX_R685;
for (nbseek = 0; nbseek < 4; nbseek++) {
- if ((dev_tel = pci_find_device(PCI_VENDOR_ID_PLX,
+ if ((dev_tel = hisax_find_pci_device(PCI_VENDOR_ID_PLX,
seekcard, dev_tel))) {
if (pci_enable_device(dev_tel))
return 1;
@@ -620,7 +620,7 @@ setup_gazelpci(struct IsdnCardState *cs)
return (0);
}
-#endif /* CONFIG_PCI_LEGACY */
+#endif /* CONFIG_PCI */
int __devinit
setup_gazel(struct IsdnCard *card)
@@ -640,7 +640,7 @@ setup_gazel(struct IsdnCard *card)
return (0);
} else {
-#ifdef CONFIG_PCI_LEGACY
+#ifdef CONFIG_PCI
if (setup_gazelpci(cs))
return (0);
#else
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 10914731b304..917cc84065bd 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -1658,7 +1658,7 @@ setup_hfcpci(struct IsdnCard *card)
i = 0;
while (id_list[i].vendor_id) {
- tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
+ tmp_hfcpci = hisax_find_pci_device(id_list[i].vendor_id,
id_list[i].device_id,
dev_hfcpci);
i++;
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 0685c1946969..832a87855ffb 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -1323,3 +1323,26 @@ void release_tei(struct IsdnCardState *cs);
char *HiSax_getrev(const char *revision);
int TeiNew(void);
void TeiFree(void);
+
+#ifdef CONFIG_PCI
+
+#include <linux/pci.h>
+
+/* adaptation wrapper for old usage
+ * WARNING! This is unfit for use in a PCI hotplug environment,
+ * as the returned PCI device can disappear at any moment in time.
+ * Callers should be converted to use pci_get_device() instead.
+ */
+static inline struct pci_dev *hisax_find_pci_device(unsigned int vendor,
+ unsigned int device,
+ struct pci_dev *from)
+{
+ struct pci_dev *pdev;
+
+ pci_dev_get(from);
+ pdev = pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
+ pci_dev_put(pdev);
+ return pdev;
+}
+
+#endif
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
index bfeb9b6aa043..6bde16c00fb5 100644
--- a/drivers/isdn/hisax/isar.c
+++ b/drivers/isdn/hisax/isar.c
@@ -138,7 +138,7 @@ waitrecmsg(struct IsdnCardState *cs, u_char *len,
while((!(cs->BC_Read_Reg(cs, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) &&
(timeout++ < maxdelay))
udelay(1);
- if (timeout >= maxdelay) {
+ if (timeout > maxdelay) {
printk(KERN_WARNING"isar recmsg IRQSTA timeout\n");
return(0);
}
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
index ef00633e1d2a..ccaa6e13310f 100644
--- a/drivers/isdn/hisax/niccy.c
+++ b/drivers/isdn/hisax/niccy.c
@@ -297,12 +297,12 @@ int __devinit setup_niccy(struct IsdnCard *card)
return 0;
}
} else {
-#ifdef CONFIG_PCI_LEGACY
+#ifdef CONFIG_PCI
static struct pci_dev *niccy_dev __devinitdata;
u_int pci_ioaddr;
cs->subtyp = 0;
- if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM,
+ if ((niccy_dev = hisax_find_pci_device(PCI_VENDOR_ID_SATSAGEM,
PCI_DEVICE_ID_SATSAGEM_NICCY,
niccy_dev))) {
if (pci_enable_device(niccy_dev))
@@ -354,7 +354,7 @@ int __devinit setup_niccy(struct IsdnCard *card)
printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
return 0;
-#endif /* CONFIG_PCI_LEGACY */
+#endif /* CONFIG_PCI */
}
printk(KERN_INFO "HiSax: NICCY %s config irq:%d data:0x%X ale:0x%X\n",
(cs->subtyp == 1) ? "PnP" : "PCI",
diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
index 8d36ccc87d81..2344e7b33448 100644
--- a/drivers/isdn/hisax/nj_s.c
+++ b/drivers/isdn/hisax/nj_s.c
@@ -276,7 +276,7 @@ setup_netjet_s(struct IsdnCard *card)
for ( ;; )
{
- if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET,
PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
ret = njs_pci_probe(dev_netjet, cs);
if (!ret)
diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c
index d306c946ffba..095e974aed80 100644
--- a/drivers/isdn/hisax/nj_u.c
+++ b/drivers/isdn/hisax/nj_u.c
@@ -240,7 +240,7 @@ setup_netjet_u(struct IsdnCard *card)
for ( ;; )
{
- if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET,
PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
ret = nju_pci_probe(dev_netjet, cs);
if (!ret)
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index 5569a522e2a1..69dfc8d29017 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -598,7 +598,7 @@ setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
}
#endif /* __ISAPNP__ */
-#ifdef CONFIG_PCI_LEGACY
+#ifdef CONFIG_PCI
static struct pci_dev *dev_sedl __devinitdata = NULL;
static int __devinit
@@ -607,7 +607,7 @@ setup_sedlbauer_pci(struct IsdnCard *card)
struct IsdnCardState *cs = card->cs;
u16 sub_vendor_id, sub_id;
- if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ if ((dev_sedl = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET,
PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
if (pci_enable_device(dev_sedl))
return(0);
@@ -673,7 +673,7 @@ setup_sedlbauer_pci(struct IsdnCard *card)
return (1);
}
-#endif /* CONFIG_PCI_LEGACY */
+#endif /* CONFIG_PCI */
int __devinit
setup_sedlbauer(struct IsdnCard *card)
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index 28b08de4673d..b85ceb3746ce 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -300,7 +300,7 @@ setup_telespci(struct IsdnCard *card)
if (cs->typ != ISDN_CTYPE_TELESPCI)
return (0);
- if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
+ if ((dev_tel = hisax_find_pci_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
if (pci_enable_device(dev_tel))
return(0);
cs->irq = dev_tel->irq;
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index c4d862c11a60..9d6e864023fe 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -1007,7 +1007,7 @@ setup_w6692(struct IsdnCard *card)
return (0);
while (id_list[id_idx].vendor_id) {
- dev_w6692 = pci_find_device(id_list[id_idx].vendor_id,
+ dev_w6692 = hisax_find_pci_device(id_list[id_idx].vendor_id,
id_list[id_idx].device_id,
dev_w6692);
if (dev_w6692) {
diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
index 4ffaa14b9fc4..fe874afa4f81 100644
--- a/drivers/isdn/hysdn/hycapi.c
+++ b/drivers/isdn/hysdn/hycapi.c
@@ -11,6 +11,8 @@
*/
#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
@@ -432,26 +434,16 @@ static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
return retval;
}
-/*********************************************************************
-hycapi_read_proc
-
-Informations provided in the /proc/capi-entries.
-
-*********************************************************************/
-
-static int hycapi_read_proc(char *page, char **start, off_t off,
- int count, int *eof, struct capi_ctr *ctrl)
+static int hycapi_proc_show(struct seq_file *m, void *v)
{
+ struct capi_ctr *ctrl = m->private;
hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
hysdn_card *card = cinfo->card;
- int len = 0;
char *s;
-#ifdef HYCAPI_PRINTFNAMES
- printk(KERN_NOTICE "hycapi_read_proc\n");
-#endif
- len += sprintf(page+len, "%-16s %s\n", "name", cinfo->cardname);
- len += sprintf(page+len, "%-16s 0x%x\n", "io", card->iobase);
- len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
+
+ seq_printf(m, "%-16s %s\n", "name", cinfo->cardname);
+ seq_printf(m, "%-16s 0x%x\n", "io", card->iobase);
+ seq_printf(m, "%-16s %d\n", "irq", card->irq);
switch (card->brdtype) {
case BD_PCCARD: s = "HYSDN Hycard"; break;
@@ -461,24 +453,32 @@ static int hycapi_read_proc(char *page, char **start, off_t off,
case BD_PLEXUS: s = "HYSDN Plexus30"; break;
default: s = "???"; break;
}
- len += sprintf(page+len, "%-16s %s\n", "type", s);
+ seq_printf(m, "%-16s %s\n", "type", s);
if ((s = cinfo->version[VER_DRIVER]) != NULL)
- len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+ seq_printf(m, "%-16s %s\n", "ver_driver", s);
if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
- len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+ seq_printf(m, "%-16s %s\n", "ver_cardtype", s);
if ((s = cinfo->version[VER_SERIAL]) != NULL)
- len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+ seq_printf(m, "%-16s %s\n", "ver_serial", s);
- len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
+ seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname);
- if (off+count >= len)
- *eof = 1;
- if (len < off)
- return 0;
- *start = page + off;
- return ((count < len-off) ? count : len-off);
+ return 0;
+}
+
+static int hycapi_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, hycapi_proc_show, PDE(inode)->data);
}
+static const struct file_operations hycapi_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = hycapi_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/**************************************************************
hycapi_load_firmware
@@ -774,7 +774,7 @@ hycapi_capi_create(hysdn_card *card)
ctrl->load_firmware = hycapi_load_firmware;
ctrl->reset_ctr = hycapi_reset_ctr;
ctrl->procinfo = hycapi_procinfo;
- ctrl->ctr_read_proc = hycapi_read_proc;
+ ctrl->proc_fops = &hycapi_proc_fops;
strcpy(ctrl->name, cinfo->cardname);
ctrl->owner = THIS_MODULE;
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
index 07c4e49f9e77..9c6650ea848e 100644
--- a/drivers/isdn/i4l/Kconfig
+++ b/drivers/isdn/i4l/Kconfig
@@ -134,14 +134,7 @@ source "drivers/isdn/sc/Kconfig"
source "drivers/isdn/act2000/Kconfig"
-source "drivers/isdn/hysdn/Kconfig"
-
endmenu
# end ISDN_I4L
endif
-config ISDN_HDLC
- tristate
- select CRC_CCITT
- select BITREVERSE
-
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index adb1e8c36b46..00c60e2e0ff7 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1347,7 +1347,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
/*
* isdn net devices manage lots of configuration variables as linked lists.
* Those lists must only be manipulated from user space. Some of the ioctl's
- * service routines access user space and are not atomic. Therefor, ioctl's
+ * service routines access user space and are not atomic. Therefore, ioctl's
* manipulating the lists and ioctl's sleeping while accessing the lists
* are serialized by means of a semaphore.
*/
diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c
index 43ff4d3b046e..6eac588e0a37 100644
--- a/drivers/isdn/mISDN/dsp_core.c
+++ b/drivers/isdn/mISDN/dsp_core.c
@@ -1114,7 +1114,7 @@ static struct Bprotocol DSP = {
.create = dspcreate
};
-static int dsp_init(void)
+static int __init dsp_init(void)
{
int err;
int tics;
@@ -1212,7 +1212,7 @@ static int dsp_init(void)
}
-static void dsp_cleanup(void)
+static void __exit dsp_cleanup(void)
{
mISDN_unregister_Bprotocol(&DSP);
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index f1e8af54dff0..325b1ad7d4b8 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -477,7 +477,7 @@ l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len)
printk(KERN_DEBUG "%s: received frame, parsing... (%d)\n",
__func__, len);
- /* check lenght */
+ /* check length */
if (len < 1+1+2) {
printk(KERN_WARNING "%s: packet error - length %d below "
"4 bytes\n", __func__, len);
@@ -1509,7 +1509,7 @@ l1oip_init(void)
printk(KERN_DEBUG "%s: interface %d is %s with %s.\n",
__func__, l1oip_cnt, pri ? "PRI" : "BRI",
bundle ? "bundled IP packet for all B-channels" :
- "seperate IP packets for every B-channel");
+ "separate IP packets for every B-channel");
hc = kzalloc(sizeof(struct l1oip), GFP_ATOMIC);
if (!hc) {
diff --git a/drivers/isdn/sc/hardware.h b/drivers/isdn/sc/hardware.h
index 9e6d5302bf8e..627324856ead 100644
--- a/drivers/isdn/sc/hardware.h
+++ b/drivers/isdn/sc/hardware.h
@@ -87,7 +87,7 @@
#define BRI_CHANNELS 2 /* Number of B channels */
#define BRI_BASEPG_VAL 0x98
#define BRI_MAGIC 0x60000 /* Magic Number */
-#define BRI_MEMSIZE 0x10000 /* Ammount of RAM (64K) */
+#define BRI_MEMSIZE 0x10000 /* Amount of RAM (64K) */
#define BRI_PARTNO "72-029"
#define BRI_FEATURES ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L3_TRANS;
/*
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 8a0e1ec95e4a..e0b64312e66a 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -17,6 +17,13 @@ config LEDS_CLASS
comment "LED drivers"
+config LEDS_88PM860X
+ tristate "LED Support for Marvell 88PM860x PMIC"
+ depends on LEDS_CLASS && MFD_88PM860X
+ help
+ This option enables support for on-chip LED drivers found on Marvell
+ Semiconductor 88PM8606 PMIC.
+
config LEDS_ATMEL_PWM
tristate "LED Support using Atmel PWM outputs"
depends on LEDS_CLASS && ATMEL_PWM
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 9e63869d7c0d..d76fb32b77c0 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_LEDS_CLASS) += led-class.o
obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
# LED Platform Drivers
+obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o
obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o
obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
new file mode 100644
index 000000000000..d196073a6aeb
--- /dev/null
+++ b/drivers/leds/leds-88pm860x.c
@@ -0,0 +1,325 @@
+/*
+ * LED driver for Marvell 88PM860x
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+#include <linux/mfd/88pm860x.h>
+
+#define LED_PWM_SHIFT (3)
+#define LED_PWM_MASK (0x1F)
+#define LED_CURRENT_MASK (0x07 << 5)
+
+#define LED_BLINK_ON_MASK (0x07)
+#define LED_BLINK_PERIOD_MASK (0x0F << 3)
+#define LED_BLINK_MASK (0x7F)
+
+#define LED_BLINK_ON(x) ((x & 0x7) * 66 + 66)
+#define LED_BLINK_PERIOD(x) ((x & 0xF) * 530 + 930)
+#define LED_BLINK_ON_MIN LED_BLINK_ON(0)
+#define LED_BLINK_ON_MAX LED_BLINK_ON(0x7)
+#define LED_BLINK_PERIOD_MIN LED_BLINK_PERIOD(0)
+#define LED_BLINK_PERIOD_MAX LED_BLINK_PERIOD(0xE)
+#define LED_TO_ON(x) ((x - 66) / 66)
+#define LED_TO_PERIOD(x) ((x - 930) / 530)
+
+#define LED1_BLINK_EN (1 << 1)
+#define LED2_BLINK_EN (1 << 2)
+
+enum {
+ SET_BRIGHTNESS,
+ SET_BLINK,
+};
+
+struct pm860x_led {
+ struct led_classdev cdev;
+ struct i2c_client *i2c;
+ struct work_struct work;
+ struct pm860x_chip *chip;
+ struct mutex lock;
+ char name[MFD_NAME_SIZE];
+
+ int port;
+ int iset;
+ int command;
+ int offset;
+ unsigned char brightness;
+ unsigned char current_brightness;
+
+ int blink_data;
+ int blink_time;
+ int blink_on;
+ int blink_off;
+};
+
+/* return offset of color register */
+static inline int __led_off(int port)
+{
+ int ret = -EINVAL;
+
+ switch (port) {
+ case PM8606_LED1_RED:
+ case PM8606_LED1_GREEN:
+ case PM8606_LED1_BLUE:
+ ret = port - PM8606_LED1_RED + PM8606_RGB1B;
+ break;
+ case PM8606_LED2_RED:
+ case PM8606_LED2_GREEN:
+ case PM8606_LED2_BLUE:
+ ret = port - PM8606_LED2_RED + PM8606_RGB2B;
+ break;
+ }
+ return ret;
+}
+
+/* return offset of blink register */
+static inline int __blink_off(int port)
+{
+ int ret = -EINVAL;
+
+ switch (port) {
+ case PM8606_LED1_RED:
+ case PM8606_LED1_GREEN:
+ case PM8606_LED1_BLUE:
+ ret = PM8606_RGB1A;
+ case PM8606_LED2_RED:
+ case PM8606_LED2_GREEN:
+ case PM8606_LED2_BLUE:
+ ret = PM8606_RGB2A;
+ }
+ return ret;
+}
+
+static inline int __blink_ctl_mask(int port)
+{
+ int ret = -EINVAL;
+
+ switch (port) {
+ case PM8606_LED1_RED:
+ case PM8606_LED1_GREEN:
+ case PM8606_LED1_BLUE:
+ ret = LED1_BLINK_EN;
+ break;
+ case PM8606_LED2_RED:
+ case PM8606_LED2_GREEN:
+ case PM8606_LED2_BLUE:
+ ret = LED2_BLINK_EN;
+ break;
+ }
+ return ret;
+}
+
+static int __led_set(struct pm860x_led *led, int command)
+{
+ struct pm860x_chip *chip = led->chip;
+ int mask, ret;
+
+ mutex_lock(&led->lock);
+ switch (command) {
+ case SET_BRIGHTNESS:
+ if ((led->current_brightness == 0) && led->brightness) {
+ if (led->iset) {
+ ret = pm860x_set_bits(led->i2c, led->offset,
+ LED_CURRENT_MASK, led->iset);
+ if (ret < 0)
+ goto out;
+ }
+ } else if (led->brightness == 0) {
+ ret = pm860x_set_bits(led->i2c, led->offset,
+ LED_CURRENT_MASK, 0);
+ if (ret < 0)
+ goto out;
+ }
+ ret = pm860x_set_bits(led->i2c, led->offset, LED_PWM_MASK,
+ led->brightness);
+ if (ret < 0)
+ goto out;
+ led->current_brightness = led->brightness;
+ dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n",
+ led->offset, led->brightness);
+ break;
+ case SET_BLINK:
+ ret = pm860x_set_bits(led->i2c, led->offset,
+ LED_BLINK_MASK, led->blink_data);
+ if (ret < 0)
+ goto out;
+
+ mask = __blink_ctl_mask(led->port);
+ ret = pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask);
+ if (ret < 0)
+ goto out;
+ dev_dbg(chip->dev, "LED blink delay on:%dms, delay off:%dms\n",
+ led->blink_on, led->blink_off);
+ break;
+ }
+out:
+ mutex_unlock(&led->lock);
+ return 0;
+}
+
+static void pm860x_led_work(struct work_struct *work)
+{
+ struct pm860x_led *led;
+
+ led = container_of(work, struct pm860x_led, work);
+ __led_set(led, led->command);
+}
+
+static void pm860x_led_set(struct led_classdev *cdev,
+ enum led_brightness value)
+{
+ struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev);
+
+ data->offset = __led_off(data->port);
+ data->brightness = value >> 3;
+ data->command = SET_BRIGHTNESS;
+ schedule_work(&data->work);
+}
+
+static int pm860x_led_blink(struct led_classdev *cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev);
+ int period, on;
+
+ on = *delay_on;
+ if ((on < LED_BLINK_ON_MIN) || (on > LED_BLINK_ON_MAX))
+ return -EINVAL;
+
+ on = LED_TO_ON(on);
+ on = LED_BLINK_ON(on);
+
+ period = on + *delay_off;
+ if ((period < LED_BLINK_PERIOD_MIN) || (period > LED_BLINK_PERIOD_MAX))
+ return -EINVAL;
+ period = LED_TO_PERIOD(period);
+ period = LED_BLINK_PERIOD(period);
+
+ data->offset = __blink_off(data->port);
+ data->blink_on = on;
+ data->blink_off = period - data->blink_on;
+ data->blink_data = (period << 3) | data->blink_on;
+ data->command = SET_BLINK;
+ schedule_work(&data->work);
+
+ return 0;
+}
+
+static int __check_device(struct pm860x_led_pdata *pdata, char *name)
+{
+ struct pm860x_led_pdata *p = pdata;
+ int ret = -EINVAL;
+
+ while (p && p->id) {
+ if ((p->id != PM8606_ID_LED) || (p->flags < 0))
+ break;
+
+ if (!strncmp(name, pm860x_led_name[p->flags],
+ MFD_NAME_SIZE)) {
+ ret = (int)p->flags;
+ break;
+ }
+ p++;
+ }
+ return ret;
+}
+
+static int pm860x_led_probe(struct platform_device *pdev)
+{
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm860x_platform_data *pm860x_pdata;
+ struct pm860x_led_pdata *pdata;
+ struct pm860x_led *data;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "No I/O resource!\n");
+ return -EINVAL;
+ }
+
+ if (pdev->dev.parent->platform_data) {
+ pm860x_pdata = pdev->dev.parent->platform_data;
+ pdata = pm860x_pdata->led;
+ } else
+ pdata = NULL;
+
+ data = kzalloc(sizeof(struct pm860x_led), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+ strncpy(data->name, res->name, MFD_NAME_SIZE);
+ dev_set_drvdata(&pdev->dev, data);
+ data->chip = chip;
+ data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion;
+ data->iset = pdata->iset;
+ data->port = __check_device(pdata, data->name);
+ if (data->port < 0)
+ return -EINVAL;
+
+ data->current_brightness = 0;
+ data->cdev.name = data->name;
+ data->cdev.brightness_set = pm860x_led_set;
+ data->cdev.blink_set = pm860x_led_blink;
+ mutex_init(&data->lock);
+ INIT_WORK(&data->work, pm860x_led_work);
+
+ ret = led_classdev_register(chip->dev, &data->cdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
+ goto out;
+ }
+ return 0;
+out:
+ kfree(data);
+ return ret;
+}
+
+static int pm860x_led_remove(struct platform_device *pdev)
+{
+ struct pm860x_led *data = platform_get_drvdata(pdev);
+
+ led_classdev_unregister(&data->cdev);
+ kfree(data);
+
+ return 0;
+}
+
+static struct platform_driver pm860x_led_driver = {
+ .driver = {
+ .name = "88pm860x-led",
+ .owner = THIS_MODULE,
+ },
+ .probe = pm860x_led_probe,
+ .remove = pm860x_led_remove,
+};
+
+static int __devinit pm860x_led_init(void)
+{
+ return platform_driver_register(&pm860x_led_driver);
+}
+module_init(pm860x_led_init);
+
+static void __devexit pm860x_led_exit(void)
+{
+ platform_driver_unregister(&pm860x_led_driver);
+}
+module_exit(pm860x_led_exit);
+
+MODULE_DESCRIPTION("LED driver for Marvell PM860x");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:88pm860x-led");
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 3d906833948d..fd85bde283a0 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -171,8 +171,8 @@ config INPUT_ADBHID
If unsure, say Y.
config MAC_EMUMOUSEBTN
- bool "Support for mouse button 2+3 emulation"
- select INPUT
+ tristate "Support for mouse button 2+3 emulation"
+ depends on SYSCTL && INPUT
help
This provides generic support for emulating the 2nd and 3rd mouse
button with keypresses. If you say Y here, the emulation is still
@@ -184,6 +184,9 @@ config MAC_EMUMOUSEBTN
If you have an Apple machine with a 1-button mouse, say Y here.
+ To compile this driver as a module, choose M here: the
+ module will be called mac_hid.
+
config THERM_WINDTUNNEL
tristate "Support for thermal management on Windtunnel G4s"
depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 23741cec45e3..1c4ee6e77937 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -317,13 +317,15 @@ static int __init adb_init(void)
break;
}
}
- if ((adb_controller == NULL) || adb_controller->init()) {
- printk(KERN_WARNING "Warning: no ADB interface detected\n");
+ if (adb_controller != NULL && adb_controller->init &&
+ adb_controller->init())
adb_controller = NULL;
+ if (adb_controller == NULL) {
+ printk(KERN_WARNING "Warning: no ADB interface detected\n");
} else {
#ifdef CONFIG_PPC
- if (machine_is_compatible("AAPL,PowerBook1998") ||
- machine_is_compatible("PowerBook1,1"))
+ if (of_machine_is_compatible("AAPL,PowerBook1998") ||
+ of_machine_is_compatible("PowerBook1,1"))
sleepy_trackpad = 1;
#endif /* CONFIG_PPC */
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
index 7b4ef5bb556b..e943d2a29253 100644
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -13,17 +13,197 @@
#include <linux/sysctl.h>
#include <linux/input.h>
#include <linux/module.h>
-#include <linux/kbd_kern.h>
+MODULE_LICENSE("GPL");
-static struct input_dev *emumousebtn;
-static int emumousebtn_input_register(void);
static int mouse_emulate_buttons;
static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */
static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */
-static int mouse_last_keycode;
-#if defined(CONFIG_SYSCTL)
+static struct input_dev *mac_hid_emumouse_dev;
+
+static int mac_hid_create_emumouse(void)
+{
+ static struct lock_class_key mac_hid_emumouse_dev_event_class;
+ static struct lock_class_key mac_hid_emumouse_dev_mutex_class;
+ int err;
+
+ mac_hid_emumouse_dev = input_allocate_device();
+ if (!mac_hid_emumouse_dev)
+ return -ENOMEM;
+
+ lockdep_set_class(&mac_hid_emumouse_dev->event_lock,
+ &mac_hid_emumouse_dev_event_class);
+ lockdep_set_class(&mac_hid_emumouse_dev->mutex,
+ &mac_hid_emumouse_dev_mutex_class);
+
+ mac_hid_emumouse_dev->name = "Macintosh mouse button emulation";
+ mac_hid_emumouse_dev->id.bustype = BUS_ADB;
+ mac_hid_emumouse_dev->id.vendor = 0x0001;
+ mac_hid_emumouse_dev->id.product = 0x0001;
+ mac_hid_emumouse_dev->id.version = 0x0100;
+
+ mac_hid_emumouse_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ mac_hid_emumouse_dev->keybit[BIT_WORD(BTN_MOUSE)] =
+ BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
+ mac_hid_emumouse_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+
+ err = input_register_device(mac_hid_emumouse_dev);
+ if (err) {
+ input_free_device(mac_hid_emumouse_dev);
+ mac_hid_emumouse_dev = NULL;
+ return err;
+ }
+
+ return 0;
+}
+
+static void mac_hid_destroy_emumouse(void)
+{
+ input_unregister_device(mac_hid_emumouse_dev);
+ mac_hid_emumouse_dev = NULL;
+}
+
+static bool mac_hid_emumouse_filter(struct input_handle *handle,
+ unsigned int type, unsigned int code,
+ int value)
+{
+ unsigned int btn;
+
+ if (type != EV_KEY)
+ return false;
+
+ if (code == mouse_button2_keycode)
+ btn = BTN_MIDDLE;
+ else if (code == mouse_button3_keycode)
+ btn = BTN_RIGHT;
+ else
+ return false;
+
+ input_report_key(mac_hid_emumouse_dev, btn, value);
+ input_sync(mac_hid_emumouse_dev);
+
+ return true;
+}
+
+static int mac_hid_emumouse_connect(struct input_handler *handler,
+ struct input_dev *dev,
+ const struct input_device_id *id)
+{
+ struct input_handle *handle;
+ int error;
+
+ /* Don't bind to ourselves */
+ if (dev == mac_hid_emumouse_dev)
+ return -ENODEV;
+
+ handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+ if (!handle)
+ return -ENOMEM;
+
+ handle->dev = dev;
+ handle->handler = handler;
+ handle->name = "mac-button-emul";
+
+ error = input_register_handle(handle);
+ if (error) {
+ printk(KERN_ERR
+ "mac_hid: Failed to register button emulation handle, "
+ "error %d\n", error);
+ goto err_free;
+ }
+
+ error = input_open_device(handle);
+ if (error) {
+ printk(KERN_ERR
+ "mac_hid: Failed to open input device, error %d\n",
+ error);
+ goto err_unregister;
+ }
+
+ return 0;
+
+ err_unregister:
+ input_unregister_handle(handle);
+ err_free:
+ kfree(handle);
+ return error;
+}
+
+static void mac_hid_emumouse_disconnect(struct input_handle *handle)
+{
+ input_close_device(handle);
+ input_unregister_handle(handle);
+ kfree(handle);
+}
+
+static const struct input_device_id mac_hid_emumouse_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+ .evbit = { BIT_MASK(EV_KEY) },
+ },
+ { },
+};
+
+MODULE_DEVICE_TABLE(input, mac_hid_emumouse_ids);
+
+static struct input_handler mac_hid_emumouse_handler = {
+ .filter = mac_hid_emumouse_filter,
+ .connect = mac_hid_emumouse_connect,
+ .disconnect = mac_hid_emumouse_disconnect,
+ .name = "mac-button-emul",
+ .id_table = mac_hid_emumouse_ids,
+};
+
+static int mac_hid_start_emulation(void)
+{
+ int err;
+
+ err = mac_hid_create_emumouse();
+ if (err)
+ return err;
+
+ err = input_register_handler(&mac_hid_emumouse_handler);
+ if (err) {
+ mac_hid_destroy_emumouse();
+ return err;
+ }
+
+ return 0;
+}
+
+static void mac_hid_stop_emulation(void)
+{
+ input_unregister_handler(&mac_hid_emumouse_handler);
+ mac_hid_destroy_emumouse();
+}
+
+static int mac_hid_toggle_emumouse(ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ int *valp = table->data;
+ int old_val = *valp;
+ int rc;
+
+ rc = proc_dointvec(table, write, buffer, lenp, ppos);
+
+ if (rc == 0 && write && *valp != old_val) {
+ if (*valp == 1)
+ rc = mac_hid_start_emulation();
+ else if (*valp == 0)
+ mac_hid_stop_emulation();
+ else
+ rc = -EINVAL;
+ }
+
+ /* Restore the old value in case of error */
+ if (rc)
+ *valp = old_val;
+
+ return rc;
+}
+
/* file(s) in /proc/sys/dev/mac_hid */
static ctl_table mac_hid_files[] = {
{
@@ -31,7 +211,7 @@ static ctl_table mac_hid_files[] = {
.data = &mouse_emulate_buttons,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = mac_hid_toggle_emumouse,
},
{
.procname = "mouse_button2_keycode",
@@ -74,75 +254,21 @@ static ctl_table mac_hid_root_dir[] = {
static struct ctl_table_header *mac_hid_sysctl_header;
-#endif /* endif CONFIG_SYSCTL */
-
-int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
-{
- switch (caller) {
- case 1:
- /* Called from keyboard.c */
- if (mouse_emulate_buttons
- && (keycode == mouse_button2_keycode
- || keycode == mouse_button3_keycode)) {
- if (mouse_emulate_buttons == 1) {
- input_report_key(emumousebtn,
- keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT,
- down);
- input_sync(emumousebtn);
- return 1;
- }
- mouse_last_keycode = down ? keycode : 0;
- }
- break;
- }
- return 0;
-}
-
-static struct lock_class_key emumousebtn_event_class;
-static struct lock_class_key emumousebtn_mutex_class;
-
-static int emumousebtn_input_register(void)
+static int __init mac_hid_init(void)
{
- int ret;
-
- emumousebtn = input_allocate_device();
- if (!emumousebtn)
+ mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir);
+ if (!mac_hid_sysctl_header)
return -ENOMEM;
- lockdep_set_class(&emumousebtn->event_lock, &emumousebtn_event_class);
- lockdep_set_class(&emumousebtn->mutex, &emumousebtn_mutex_class);
-
- emumousebtn->name = "Macintosh mouse button emulation";
- emumousebtn->id.bustype = BUS_ADB;
- emumousebtn->id.vendor = 0x0001;
- emumousebtn->id.product = 0x0001;
- emumousebtn->id.version = 0x0100;
-
- emumousebtn->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
- emumousebtn->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
- BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
- emumousebtn->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
-
- ret = input_register_device(emumousebtn);
- if (ret)
- input_free_device(emumousebtn);
-
- return ret;
+ return 0;
}
+module_init(mac_hid_init);
-static int __init mac_hid_init(void)
+static void __exit mac_hid_exit(void)
{
- int err;
-
- err = emumousebtn_input_register();
- if (err)
- return err;
-
-#if defined(CONFIG_SYSCTL)
- mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir);
-#endif /* CONFIG_SYSCTL */
+ unregister_sysctl_table(mac_hid_sysctl_header);
- return 0;
+ if (mouse_emulate_buttons)
+ mac_hid_stop_emulation();
}
-
-device_initcall(mac_hid_init);
+module_exit(mac_hid_exit);
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index 96faa799b82a..f96feeb6b9ce 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -660,7 +660,7 @@ static int smu_platform_probe(struct of_device* dev,
return 0;
}
-static struct of_device_id smu_platform_match[] =
+static const struct of_device_id smu_platform_match[] =
{
{
.type = "smu",
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index 5ff47ba7f2d0..c42eeb43042d 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -90,6 +90,8 @@ static struct task_struct *thread_therm = NULL;
static void write_both_fan_speed(struct thermostat *th, int speed);
static void write_fan_speed(struct thermostat *th, int speed, int fan);
+static void thermostat_create_files(void);
+static void thermostat_remove_files(void);
static int
write_reg(struct thermostat* th, int reg, u8 data)
@@ -161,6 +163,8 @@ remove_thermostat(struct i2c_client *client)
struct thermostat *th = i2c_get_clientdata(client);
int i;
+ thermostat_remove_files();
+
if (thread_therm != NULL) {
kthread_stop(thread_therm);
}
@@ -312,7 +316,7 @@ static void update_fans_speed (struct thermostat *th)
if (verbose)
printk(KERN_DEBUG "adt746x: Setting fans speed to %d "
- "(limit exceeded by %d on %s) \n",
+ "(limit exceeded by %d on %s)\n",
new_speed, var,
sensor_location[fan_number+1]);
write_both_fan_speed(th, new_speed);
@@ -449,6 +453,8 @@ static int probe_thermostat(struct i2c_client *client,
return -ENOMEM;
}
+ thermostat_create_files();
+
return 0;
}
@@ -566,7 +572,6 @@ thermostat_init(void)
struct device_node* np;
const u32 *prop;
int i = 0, offset = 0;
- int err;
np = of_find_node_by_name(NULL, "fan");
if (!np)
@@ -633,6 +638,17 @@ thermostat_init(void)
return -ENODEV;
}
+#ifndef CONFIG_I2C_POWERMAC
+ request_module("i2c-powermac");
+#endif
+
+ return i2c_add_driver(&thermostat_driver);
+}
+
+static void thermostat_create_files(void)
+{
+ int err;
+
err = device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature);
err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature);
err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_limit);
@@ -647,16 +663,9 @@ thermostat_init(void)
if (err)
printk(KERN_WARNING
"Failed to create tempertaure attribute file(s).\n");
-
-#ifndef CONFIG_I2C_POWERMAC
- request_module("i2c-powermac");
-#endif
-
- return i2c_add_driver(&thermostat_driver);
}
-static void __exit
-thermostat_exit(void)
+static void thermostat_remove_files(void)
{
if (of_dev) {
device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature);
@@ -673,9 +682,14 @@ thermostat_exit(void)
device_remove_file(&of_dev->dev,
&dev_attr_sensor2_fan_speed);
- of_device_unregister(of_dev);
}
+}
+
+static void __exit
+thermostat_exit(void)
+{
i2c_del_driver(&thermostat_driver);
+ of_device_unregister(of_dev);
}
module_init(thermostat_init);
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index ea32c7e5a9af..921373e4e3af 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -948,10 +948,16 @@ static void do_monitor_cpu_combined(void)
printk(KERN_WARNING "Warning ! Temperature way above maximum (%d) !\n",
temp_combi >> 16);
state0->overtemp += CPU_MAX_OVERTEMP / 4;
- } else if (temp_combi > (state0->mpu.tmax << 16))
+ } else if (temp_combi > (state0->mpu.tmax << 16)) {
state0->overtemp++;
- else
+ printk(KERN_WARNING "Temperature %d above max %d. overtemp %d\n",
+ temp_combi >> 16, state0->mpu.tmax, state0->overtemp);
+ } else {
+ if (state0->overtemp)
+ printk(KERN_WARNING "Temperature back down to %d\n",
+ temp_combi >> 16);
state0->overtemp = 0;
+ }
if (state0->overtemp >= CPU_MAX_OVERTEMP)
critical_state = 1;
if (state0->overtemp > 0) {
@@ -1023,10 +1029,16 @@ static void do_monitor_cpu_split(struct cpu_pid_state *state)
" (%d) !\n",
state->index, temp >> 16);
state->overtemp += CPU_MAX_OVERTEMP / 4;
- } else if (temp > (state->mpu.tmax << 16))
+ } else if (temp > (state->mpu.tmax << 16)) {
state->overtemp++;
- else
+ printk(KERN_WARNING "CPU %d temperature %d above max %d. overtemp %d\n",
+ state->index, temp >> 16, state->mpu.tmax, state->overtemp);
+ } else {
+ if (state->overtemp)
+ printk(KERN_WARNING "CPU %d temperature back down to %d\n",
+ state->index, temp >> 16);
state->overtemp = 0;
+ }
if (state->overtemp >= CPU_MAX_OVERTEMP)
critical_state = 1;
if (state->overtemp > 0) {
@@ -1085,10 +1097,16 @@ static void do_monitor_cpu_rack(struct cpu_pid_state *state)
" (%d) !\n",
state->index, temp >> 16);
state->overtemp = CPU_MAX_OVERTEMP / 4;
- } else if (temp > (state->mpu.tmax << 16))
+ } else if (temp > (state->mpu.tmax << 16)) {
state->overtemp++;
- else
+ printk(KERN_WARNING "CPU %d temperature %d above max %d. overtemp %d\n",
+ state->index, temp >> 16, state->mpu.tmax, state->overtemp);
+ } else {
+ if (state->overtemp)
+ printk(KERN_WARNING "CPU %d temperature back down to %d\n",
+ state->index, temp >> 16);
state->overtemp = 0;
+ }
if (state->overtemp >= CPU_MAX_OVERTEMP)
critical_state = 1;
if (state->overtemp > 0) {
@@ -1899,7 +1917,7 @@ static int create_control_loops(void)
*/
if (rackmac)
cpu_pid_type = CPU_PID_TYPE_RACKMAC;
- else if (machine_is_compatible("PowerMac7,3")
+ else if (of_machine_is_compatible("PowerMac7,3")
&& (cpu_count > 1)
&& fcu_fans[CPUA_PUMP_RPM_INDEX].id != FCU_FAN_ABSENT_ID
&& fcu_fans[CPUB_PUMP_RPM_INDEX].id != FCU_FAN_ABSENT_ID) {
@@ -2211,7 +2229,7 @@ static int fcu_of_remove(struct of_device* dev)
return 0;
}
-static struct of_device_id fcu_match[] =
+static const struct of_device_id fcu_match[] =
{
{
.type = "fcu",
@@ -2234,10 +2252,10 @@ static int __init therm_pm72_init(void)
{
struct device_node *np;
- rackmac = machine_is_compatible("RackMac3,1");
+ rackmac = of_machine_is_compatible("RackMac3,1");
- if (!machine_is_compatible("PowerMac7,2") &&
- !machine_is_compatible("PowerMac7,3") &&
+ if (!of_machine_is_compatible("PowerMac7,2") &&
+ !of_machine_is_compatible("PowerMac7,3") &&
!rackmac)
return -ENODEV;
diff --git a/drivers/macintosh/therm_pm72.h b/drivers/macintosh/therm_pm72.h
index 393cc9df94e1..df3680e2a22f 100644
--- a/drivers/macintosh/therm_pm72.h
+++ b/drivers/macintosh/therm_pm72.h
@@ -269,7 +269,7 @@ struct slots_pid_state
#define CPU_TEMP_HISTORY_SIZE 2
#define CPU_POWER_HISTORY_SIZE 10
#define CPU_PID_INTERVAL 1
-#define CPU_MAX_OVERTEMP 30
+#define CPU_MAX_OVERTEMP 90
#define CPUA_PUMP_RPM_INDEX 7
#define CPUB_PUMP_RPM_INDEX 8
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 3fbe41b0ac07..7fb8b4da35a7 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -457,7 +457,7 @@ therm_of_remove( struct of_device *dev )
return 0;
}
-static struct of_device_id therm_of_match[] = {{
+static const struct of_device_id therm_of_match[] = {{
.name = "fan",
.compatible = "adm1030"
}, {}
@@ -490,7 +490,7 @@ g4fan_init( void )
info = of_get_property(np, "thermal-info", NULL);
of_node_put(np);
- if( !info || !machine_is_compatible("PowerMac3,6") )
+ if( !info || !of_machine_is_compatible("PowerMac3,6") )
return -ENODEV;
if( info->id != 3 ) {
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 62dd1fdafecf..971bc9582a5f 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -89,7 +89,6 @@ static int cuda_fully_inited;
#ifdef CONFIG_ADB
static int cuda_probe(void);
-static int cuda_init(void);
static int cuda_send_request(struct adb_request *req, int sync);
static int cuda_adb_autopoll(int devs);
static int cuda_reset_adb_bus(void);
@@ -107,17 +106,42 @@ int cuda_request(struct adb_request *req,
#ifdef CONFIG_ADB
struct adb_driver via_cuda_driver = {
- "CUDA",
- cuda_probe,
- cuda_init,
- cuda_send_request,
- cuda_adb_autopoll,
- cuda_poll,
- cuda_reset_adb_bus
+ .name = "CUDA",
+ .probe = cuda_probe,
+ .send_request = cuda_send_request,
+ .autopoll = cuda_adb_autopoll,
+ .poll = cuda_poll,
+ .reset_bus = cuda_reset_adb_bus,
};
#endif /* CONFIG_ADB */
-#ifdef CONFIG_PPC
+#ifdef CONFIG_MAC
+int __init find_via_cuda(void)
+{
+ struct adb_request req;
+ int err;
+
+ if (macintosh_config->adb_type != MAC_ADB_CUDA)
+ return 0;
+
+ via = via1;
+ cuda_state = idle;
+
+ err = cuda_init_via();
+ if (err) {
+ printk(KERN_ERR "cuda_init_via() failed\n");
+ via = NULL;
+ return 0;
+ }
+
+ /* enable autopoll */
+ cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
+ while (!req.complete)
+ cuda_poll();
+
+ return 1;
+}
+#else
int __init find_via_cuda(void)
{
struct adb_request req;
@@ -175,7 +199,7 @@ int __init find_via_cuda(void)
vias = NULL;
return 0;
}
-#endif /* CONFIG_PPC */
+#endif /* !defined CONFIG_MAC */
static int __init via_cuda_start(void)
{
@@ -184,14 +208,14 @@ static int __init via_cuda_start(void)
#ifdef CONFIG_MAC
cuda_irq = IRQ_MAC_ADB;
-#else /* CONFIG_MAC */
+#else
cuda_irq = irq_of_parse_and_map(vias, 0);
if (cuda_irq == NO_IRQ) {
printk(KERN_ERR "via-cuda: can't map interrupts for %s\n",
vias->full_name);
return -ENODEV;
}
-#endif /* CONFIG_MAC */
+#endif
if (request_irq(cuda_irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
printk(KERN_ERR "via-cuda: can't request irq %d\n", cuda_irq);
@@ -216,28 +240,10 @@ cuda_probe(void)
#else
if (macintosh_config->adb_type != MAC_ADB_CUDA)
return -ENODEV;
- via = via1;
#endif
- return 0;
-}
-
-static int __init
-cuda_init(void)
-{
-#ifdef CONFIG_PPC
if (via == NULL)
return -ENODEV;
return 0;
-#else
- int err = cuda_init_via();
- if (err) {
- printk(KERN_ERR "cuda_init_via() failed\n");
- return -ENODEV;
- }
- out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */
-
- return via_cuda_start();
-#endif
}
#endif /* CONFIG_ADB */
@@ -430,9 +436,11 @@ cuda_poll(void)
/* cuda_interrupt only takes a normal lock, we disable
* interrupts here to avoid re-entering and thus deadlocking.
*/
- disable_irq(cuda_irq);
+ if (cuda_irq)
+ disable_irq(cuda_irq);
cuda_interrupt(0, NULL);
- enable_irq(cuda_irq);
+ if (cuda_irq)
+ enable_irq(cuda_irq);
}
static irqreturn_t
@@ -446,7 +454,7 @@ cuda_interrupt(int irq, void *arg)
spin_lock(&cuda_lock);
- /* On powermacs, this handler is registered for the VIA IRQ. But it uses
+ /* On powermacs, this handler is registered for the VIA IRQ. But they use
* just the shift register IRQ -- other VIA interrupt sources are disabled.
* On m68k macs, the VIA IRQ sources are dispatched individually. Unless
* we are polling, the shift register IRQ flag has already been cleared.
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
index a348bb0791d3..4f3c4479c16a 100644
--- a/drivers/macintosh/via-pmu-backlight.c
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -150,13 +150,13 @@ void __init pmu_backlight_init()
/* Special case for the old PowerBook since I can't test on it */
autosave =
- machine_is_compatible("AAPL,3400/2400") ||
- machine_is_compatible("AAPL,3500");
+ of_machine_is_compatible("AAPL,3400/2400") ||
+ of_machine_is_compatible("AAPL,3500");
if (!autosave &&
!pmac_has_backlight_type("pmu") &&
- !machine_is_compatible("AAPL,PowerBook1998") &&
- !machine_is_compatible("PowerBook1,1"))
+ !of_machine_is_compatible("AAPL,PowerBook1998") &&
+ !of_machine_is_compatible("PowerBook1,1"))
return;
snprintf(name, sizeof(name), "pmubl");
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index db379c381432..42764849eb78 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -463,8 +463,8 @@ static int __init via_pmu_dev_init(void)
#endif
#ifdef CONFIG_PPC32
- if (machine_is_compatible("AAPL,3400/2400") ||
- machine_is_compatible("AAPL,3500")) {
+ if (of_machine_is_compatible("AAPL,3400/2400") ||
+ of_machine_is_compatible("AAPL,3500")) {
int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
NULL, PMAC_MB_INFO_MODEL, 0);
pmu_battery_count = 1;
@@ -472,8 +472,8 @@ static int __init via_pmu_dev_init(void)
pmu_batteries[0].flags |= PMU_BATT_TYPE_COMET;
else
pmu_batteries[0].flags |= PMU_BATT_TYPE_HOOPER;
- } else if (machine_is_compatible("AAPL,PowerBook1998") ||
- machine_is_compatible("PowerBook1,1")) {
+ } else if (of_machine_is_compatible("AAPL,PowerBook1998") ||
+ of_machine_is_compatible("PowerBook1,1")) {
pmu_battery_count = 2;
pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART;
pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index 075b4d99e354..419795f4a2aa 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -321,6 +321,7 @@ int wf_register_sensor(struct wf_sensor *new_sr)
kref_init(&new_sr->ref);
list_add(&new_sr->link, &wf_sensors);
+ sysfs_attr_init(&new_sr->attr.attr);
new_sr->attr.attr.name = new_sr->name;
new_sr->attr.attr.mode = 0444;
new_sr->attr.show = wf_show_sensor;
@@ -468,9 +469,9 @@ static int __init windfarm_core_init(void)
DBG("wf: core loaded\n");
/* Don't register on old machines that use therm_pm72 for now */
- if (machine_is_compatible("PowerMac7,2") ||
- machine_is_compatible("PowerMac7,3") ||
- machine_is_compatible("RackMac3,1"))
+ if (of_machine_is_compatible("PowerMac7,2") ||
+ of_machine_is_compatible("PowerMac7,3") ||
+ of_machine_is_compatible("RackMac3,1"))
return -ENODEV;
platform_device_register(&wf_platform_device);
return 0;
diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c
index 900aade06198..1a77a7c97d0e 100644
--- a/drivers/macintosh/windfarm_cpufreq_clamp.c
+++ b/drivers/macintosh/windfarm_cpufreq_clamp.c
@@ -76,9 +76,9 @@ static int __init wf_cpufreq_clamp_init(void)
struct wf_control *clamp;
/* Don't register on old machines that use therm_pm72 for now */
- if (machine_is_compatible("PowerMac7,2") ||
- machine_is_compatible("PowerMac7,3") ||
- machine_is_compatible("RackMac3,1"))
+ if (of_machine_is_compatible("PowerMac7,2") ||
+ of_machine_is_compatible("PowerMac7,3") ||
+ of_machine_is_compatible("RackMac3,1"))
return -ENODEV;
clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index ed6426a10773..d8257d35afde 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -239,9 +239,9 @@ static struct i2c_driver wf_lm75_driver = {
static int __init wf_lm75_sensor_init(void)
{
/* Don't register on old machines that use therm_pm72 for now */
- if (machine_is_compatible("PowerMac7,2") ||
- machine_is_compatible("PowerMac7,3") ||
- machine_is_compatible("RackMac3,1"))
+ if (of_machine_is_compatible("PowerMac7,2") ||
+ of_machine_is_compatible("PowerMac7,3") ||
+ of_machine_is_compatible("RackMac3,1"))
return -ENODEV;
return i2c_add_driver(&wf_lm75_driver);
}
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c
index a67b349319e9..b486eb929fde 100644
--- a/drivers/macintosh/windfarm_max6690_sensor.c
+++ b/drivers/macintosh/windfarm_max6690_sensor.c
@@ -188,9 +188,9 @@ static struct i2c_driver wf_max6690_driver = {
static int __init wf_max6690_sensor_init(void)
{
/* Don't register on old machines that use therm_pm72 for now */
- if (machine_is_compatible("PowerMac7,2") ||
- machine_is_compatible("PowerMac7,3") ||
- machine_is_compatible("RackMac3,1"))
+ if (of_machine_is_compatible("PowerMac7,2") ||
+ of_machine_is_compatible("PowerMac7,3") ||
+ of_machine_is_compatible("RackMac3,1"))
return -ENODEV;
return i2c_add_driver(&wf_max6690_driver);
}
diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c
index 73d695dc9e50..e0ee80700cde 100644
--- a/drivers/macintosh/windfarm_pm112.c
+++ b/drivers/macintosh/windfarm_pm112.c
@@ -676,7 +676,7 @@ static int __init wf_pm112_init(void)
{
struct device_node *cpu;
- if (!machine_is_compatible("PowerMac11,2"))
+ if (!of_machine_is_compatible("PowerMac11,2"))
return -ENODEV;
/* Count the number of CPU cores */
diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c
index 66ec4fb115bb..947d4afa25ca 100644
--- a/drivers/macintosh/windfarm_pm121.c
+++ b/drivers/macintosh/windfarm_pm121.c
@@ -1008,7 +1008,7 @@ static int __init pm121_init(void)
{
int rc = -ENODEV;
- if (machine_is_compatible("PowerMac12,1"))
+ if (of_machine_is_compatible("PowerMac12,1"))
rc = pm121_init_pm();
if (rc == 0) {
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
index abbe206474f5..565d5b2adc95 100644
--- a/drivers/macintosh/windfarm_pm81.c
+++ b/drivers/macintosh/windfarm_pm81.c
@@ -779,8 +779,8 @@ static int __init wf_smu_init(void)
{
int rc = -ENODEV;
- if (machine_is_compatible("PowerMac8,1") ||
- machine_is_compatible("PowerMac8,2"))
+ if (of_machine_is_compatible("PowerMac8,1") ||
+ of_machine_is_compatible("PowerMac8,2"))
rc = wf_init_pm();
if (rc == 0) {
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
index 764c525b2117..bea99168ff35 100644
--- a/drivers/macintosh/windfarm_pm91.c
+++ b/drivers/macintosh/windfarm_pm91.c
@@ -711,7 +711,7 @@ static int __init wf_smu_init(void)
{
int rc = -ENODEV;
- if (machine_is_compatible("PowerMac9,1"))
+ if (of_machine_is_compatible("PowerMac9,1"))
rc = wf_init_pm();
if (rc == 0) {
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 6c68b9e5f5c4..43137b421f92 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -173,6 +173,7 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
fct->fan_type = pwm_fan;
fct->ctrl.type = pwm_fan ? WF_CONTROL_PWM_FAN : WF_CONTROL_RPM_FAN;
+ sysfs_attr_init(&fct->ctrl.attr.attr);
/* We use the name & location here the same way we do for SMU sensors,
* see the comment in windfarm_smu_sensors.c. The locations are a bit
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
index 9c567b93f417..3c193504bb80 100644
--- a/drivers/macintosh/windfarm_smu_sensors.c
+++ b/drivers/macintosh/windfarm_smu_sensors.c
@@ -363,9 +363,9 @@ smu_cpu_power_create(struct wf_sensor *volts, struct wf_sensor *amps)
* I yet have to figure out what's up with 8,2 and will have to
* adjust for later, unless we can 100% trust the SDB partition...
*/
- if ((machine_is_compatible("PowerMac8,1") ||
- machine_is_compatible("PowerMac8,2") ||
- machine_is_compatible("PowerMac9,1")) &&
+ if ((of_machine_is_compatible("PowerMac8,1") ||
+ of_machine_is_compatible("PowerMac8,2") ||
+ of_machine_is_compatible("PowerMac9,1")) &&
cpuvcp_version >= 2) {
pow->quadratic = 1;
DBG("windfarm: CPU Power using quadratic transform\n");
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index a93637223c8d..3bdbb6115702 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -1160,8 +1160,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
cc->start = tmpll;
- if (dm_get_device(ti, argv[3], cc->start, ti->len,
- dm_table_get_mode(ti->table), &cc->dev)) {
+ if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &cc->dev)) {
ti->error = "Device lookup failed";
goto bad_device;
}
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
index ebe7381f47c8..852052880d7a 100644
--- a/drivers/md/dm-delay.c
+++ b/drivers/md/dm-delay.c
@@ -156,8 +156,8 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad;
}
- if (dm_get_device(ti, argv[0], dc->start_read, ti->len,
- dm_table_get_mode(ti->table), &dc->dev_read)) {
+ if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table),
+ &dc->dev_read)) {
ti->error = "Device lookup failed";
goto bad;
}
@@ -177,8 +177,8 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad_dev_read;
}
- if (dm_get_device(ti, argv[3], dc->start_write, ti->len,
- dm_table_get_mode(ti->table), &dc->dev_write)) {
+ if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table),
+ &dc->dev_write)) {
ti->error = "Write device lookup failed";
goto bad_dev_read;
}
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 1d669322b27c..d7500e1c26f2 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -285,7 +285,8 @@ retry:
up_write(&_hash_lock);
}
-static int dm_hash_rename(uint32_t cookie, const char *old, const char *new)
+static int dm_hash_rename(uint32_t cookie, uint32_t *flags, const char *old,
+ const char *new)
{
char *new_name, *old_name;
struct hash_cell *hc;
@@ -344,7 +345,8 @@ static int dm_hash_rename(uint32_t cookie, const char *old, const char *new)
dm_table_put(table);
}
- dm_kobject_uevent(hc->md, KOBJ_CHANGE, cookie);
+ if (!dm_kobject_uevent(hc->md, KOBJ_CHANGE, cookie))
+ *flags |= DM_UEVENT_GENERATED_FLAG;
dm_put(hc->md);
up_write(&_hash_lock);
@@ -736,10 +738,10 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
__hash_remove(hc);
up_write(&_hash_lock);
- dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr);
+ if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr))
+ param->flags |= DM_UEVENT_GENERATED_FLAG;
dm_put(md);
- param->data_size = 0;
return 0;
}
@@ -773,7 +775,9 @@ static int dev_rename(struct dm_ioctl *param, size_t param_size)
return r;
param->data_size = 0;
- return dm_hash_rename(param->event_nr, param->name, new_name);
+
+ return dm_hash_rename(param->event_nr, &param->flags, param->name,
+ new_name);
}
static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
@@ -897,16 +901,17 @@ static int do_resume(struct dm_ioctl *param)
set_disk_ro(dm_disk(md), 1);
}
- if (dm_suspended_md(md))
+ if (dm_suspended_md(md)) {
r = dm_resume(md);
+ if (!r && !dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr))
+ param->flags |= DM_UEVENT_GENERATED_FLAG;
+ }
if (old_map)
dm_table_destroy(old_map);
- if (!r) {
- dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr);
+ if (!r)
r = __dev_status(md, param);
- }
dm_put(md);
return r;
@@ -1476,6 +1481,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param)
{
/* Always clear this flag */
param->flags &= ~DM_BUFFER_FULL_FLAG;
+ param->flags &= ~DM_UEVENT_GENERATED_FLAG;
/* Ignores parameters */
if (cmd == DM_REMOVE_ALL_CMD ||
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 82f7d6e6b1ea..9200dbf2391a 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -47,8 +47,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
lc->start = tmp;
- if (dm_get_device(ti, argv[0], lc->start, ti->len,
- dm_table_get_mode(ti->table), &lc->dev)) {
+ if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &lc->dev)) {
ti->error = "dm-linear: Device lookup failed";
goto bad;
}
diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c
index 54abf9e303b7..f1c8cae70b4b 100644
--- a/drivers/md/dm-log-userspace-transfer.c
+++ b/drivers/md/dm-log-userspace-transfer.c
@@ -172,11 +172,15 @@ int dm_consult_userspace(const char *uuid, uint64_t luid, int request_type,
{
int r = 0;
size_t dummy = 0;
- int overhead_size =
- sizeof(struct dm_ulog_request *) + sizeof(struct cn_msg);
+ int overhead_size = sizeof(struct dm_ulog_request) + sizeof(struct cn_msg);
struct dm_ulog_request *tfr = prealloced_ulog_tfr;
struct receiving_pkg pkg;
+ /*
+ * Given the space needed to hold the 'struct cn_msg' and
+ * 'struct dm_ulog_request' - do we have enough payload
+ * space remaining?
+ */
if (data_size > (DM_ULOG_PREALLOCED_SIZE - overhead_size)) {
DMINFO("Size of tfr exceeds preallocated size");
return -EINVAL;
@@ -191,7 +195,7 @@ resend:
*/
mutex_lock(&dm_ulog_lock);
- memset(tfr, 0, DM_ULOG_PREALLOCED_SIZE - overhead_size);
+ memset(tfr, 0, DM_ULOG_PREALLOCED_SIZE - sizeof(struct cn_msg));
memcpy(tfr->uuid, uuid, DM_UUID_LEN);
tfr->luid = luid;
tfr->seq = dm_ulog_seq++;
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 7035582786fb..5a08be0222db 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -543,8 +543,7 @@ static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti,
return -EINVAL;
}
- r = dm_get_device(ti, argv[0], 0, 0 /* FIXME */,
- FMODE_READ | FMODE_WRITE, &dev);
+ r = dm_get_device(ti, argv[0], FMODE_READ | FMODE_WRITE, &dev);
if (r)
return r;
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index e81345a1d08f..826bce7343b3 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -69,6 +69,7 @@ struct multipath {
struct list_head priority_groups;
unsigned pg_init_required; /* pg_init needs calling? */
unsigned pg_init_in_progress; /* Only one pg_init allowed at once */
+ wait_queue_head_t pg_init_wait; /* Wait for pg_init completion */
unsigned nr_valid_paths; /* Total number of usable paths */
struct pgpath *current_pgpath;
@@ -95,8 +96,6 @@ struct multipath {
mempool_t *mpio_pool;
struct mutex work_mutex;
-
- unsigned suspended; /* Don't create new I/O internally when set. */
};
/*
@@ -202,6 +201,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti)
m->queue_io = 1;
INIT_WORK(&m->process_queued_ios, process_queued_ios);
INIT_WORK(&m->trigger_event, trigger_event);
+ init_waitqueue_head(&m->pg_init_wait);
mutex_init(&m->work_mutex);
m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache);
if (!m->mpio_pool) {
@@ -235,6 +235,21 @@ static void free_multipath(struct multipath *m)
* Path selection
*-----------------------------------------------*/
+static void __pg_init_all_paths(struct multipath *m)
+{
+ struct pgpath *pgpath;
+
+ m->pg_init_count++;
+ m->pg_init_required = 0;
+ list_for_each_entry(pgpath, &m->current_pg->pgpaths, list) {
+ /* Skip failed paths */
+ if (!pgpath->is_active)
+ continue;
+ if (queue_work(kmpath_handlerd, &pgpath->activate_path))
+ m->pg_init_in_progress++;
+ }
+}
+
static void __switch_pg(struct multipath *m, struct pgpath *pgpath)
{
m->current_pg = pgpath->pg;
@@ -439,7 +454,7 @@ static void process_queued_ios(struct work_struct *work)
{
struct multipath *m =
container_of(work, struct multipath, process_queued_ios);
- struct pgpath *pgpath = NULL, *tmp;
+ struct pgpath *pgpath = NULL;
unsigned must_queue = 1;
unsigned long flags;
@@ -457,14 +472,9 @@ static void process_queued_ios(struct work_struct *work)
(!pgpath && !m->queue_if_no_path))
must_queue = 0;
- if (m->pg_init_required && !m->pg_init_in_progress && pgpath) {
- m->pg_init_count++;
- m->pg_init_required = 0;
- list_for_each_entry(tmp, &pgpath->pg->pgpaths, list) {
- if (queue_work(kmpath_handlerd, &tmp->activate_path))
- m->pg_init_in_progress++;
- }
- }
+ if (m->pg_init_required && !m->pg_init_in_progress && pgpath)
+ __pg_init_all_paths(m);
+
out:
spin_unlock_irqrestore(&m->lock, flags);
if (!must_queue)
@@ -597,8 +607,8 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
if (!p)
return ERR_PTR(-ENOMEM);
- r = dm_get_device(ti, shift(as), ti->begin, ti->len,
- dm_table_get_mode(ti->table), &p->path.dev);
+ r = dm_get_device(ti, shift(as), dm_table_get_mode(ti->table),
+ &p->path.dev);
if (r) {
ti->error = "error getting device";
goto bad;
@@ -890,9 +900,34 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
return r;
}
-static void flush_multipath_work(void)
+static void multipath_wait_for_pg_init_completion(struct multipath *m)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+
+ add_wait_queue(&m->pg_init_wait, &wait);
+
+ while (1) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+
+ spin_lock_irqsave(&m->lock, flags);
+ if (!m->pg_init_in_progress) {
+ spin_unlock_irqrestore(&m->lock, flags);
+ break;
+ }
+ spin_unlock_irqrestore(&m->lock, flags);
+
+ io_schedule();
+ }
+ set_current_state(TASK_RUNNING);
+
+ remove_wait_queue(&m->pg_init_wait, &wait);
+}
+
+static void flush_multipath_work(struct multipath *m)
{
flush_workqueue(kmpath_handlerd);
+ multipath_wait_for_pg_init_completion(m);
flush_workqueue(kmultipathd);
flush_scheduled_work();
}
@@ -901,7 +936,7 @@ static void multipath_dtr(struct dm_target *ti)
{
struct multipath *m = ti->private;
- flush_multipath_work();
+ flush_multipath_work(m);
free_multipath(m);
}
@@ -1128,8 +1163,7 @@ static int pg_init_limit_reached(struct multipath *m, struct pgpath *pgpath)
static void pg_init_done(void *data, int errors)
{
- struct dm_path *path = data;
- struct pgpath *pgpath = path_to_pgpath(path);
+ struct pgpath *pgpath = data;
struct priority_group *pg = pgpath->pg;
struct multipath *m = pg->m;
unsigned long flags;
@@ -1143,8 +1177,8 @@ static void pg_init_done(void *data, int errors)
errors = 0;
break;
}
- DMERR("Cannot failover device because scsi_dh_%s was not "
- "loaded.", m->hw_handler_name);
+ DMERR("Could not failover the device: Handler scsi_dh_%s "
+ "Error %d.", m->hw_handler_name, errors);
/*
* Fail path for now, so we do not ping pong
*/
@@ -1181,14 +1215,24 @@ static void pg_init_done(void *data, int errors)
m->current_pgpath = NULL;
m->current_pg = NULL;
}
- } else if (!m->pg_init_required) {
- m->queue_io = 0;
+ } else if (!m->pg_init_required)
pg->bypassed = 0;
- }
- m->pg_init_in_progress--;
- if (!m->pg_init_in_progress)
- queue_work(kmultipathd, &m->process_queued_ios);
+ if (--m->pg_init_in_progress)
+ /* Activations of other paths are still on going */
+ goto out;
+
+ if (!m->pg_init_required)
+ m->queue_io = 0;
+
+ queue_work(kmultipathd, &m->process_queued_ios);
+
+ /*
+ * Wake up any thread waiting to suspend.
+ */
+ wake_up(&m->pg_init_wait);
+
+out:
spin_unlock_irqrestore(&m->lock, flags);
}
@@ -1198,7 +1242,7 @@ static void activate_path(struct work_struct *work)
container_of(work, struct pgpath, activate_path);
scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev),
- pg_init_done, &pgpath->path);
+ pg_init_done, pgpath);
}
/*
@@ -1276,8 +1320,7 @@ static void multipath_postsuspend(struct dm_target *ti)
struct multipath *m = ti->private;
mutex_lock(&m->work_mutex);
- m->suspended = 1;
- flush_multipath_work();
+ flush_multipath_work(m);
mutex_unlock(&m->work_mutex);
}
@@ -1289,10 +1332,6 @@ static void multipath_resume(struct dm_target *ti)
struct multipath *m = (struct multipath *) ti->private;
unsigned long flags;
- mutex_lock(&m->work_mutex);
- m->suspended = 0;
- mutex_unlock(&m->work_mutex);
-
spin_lock_irqsave(&m->lock, flags);
m->queue_if_no_path = m->saved_queue_if_no_path;
spin_unlock_irqrestore(&m->lock, flags);
@@ -1428,11 +1467,6 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
mutex_lock(&m->work_mutex);
- if (m->suspended) {
- r = -EBUSY;
- goto out;
- }
-
if (dm_suspended(ti)) {
r = -EBUSY;
goto out;
@@ -1471,8 +1505,7 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
goto out;
}
- r = dm_get_device(ti, argv[1], ti->begin, ti->len,
- dm_table_get_mode(ti->table), &dev);
+ r = dm_get_device(ti, argv[1], dm_table_get_mode(ti->table), &dev);
if (r) {
DMWARN("message: error getting device %s",
argv[1]);
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index ad779bd13aec..ddda531723dc 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -465,9 +465,17 @@ static void map_region(struct dm_io_region *io, struct mirror *m,
static void hold_bio(struct mirror_set *ms, struct bio *bio)
{
/*
- * If device is suspended, complete the bio.
+ * Lock is required to avoid race condition during suspend
+ * process.
*/
+ spin_lock_irq(&ms->lock);
+
if (atomic_read(&ms->suspend)) {
+ spin_unlock_irq(&ms->lock);
+
+ /*
+ * If device is suspended, complete the bio.
+ */
if (dm_noflush_suspending(ms->ti))
bio_endio(bio, DM_ENDIO_REQUEUE);
else
@@ -478,7 +486,6 @@ static void hold_bio(struct mirror_set *ms, struct bio *bio)
/*
* Hold bio until the suspend is complete.
*/
- spin_lock_irq(&ms->lock);
bio_list_add(&ms->holds, bio);
spin_unlock_irq(&ms->lock);
}
@@ -724,7 +731,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
/*
* Dispatch io.
*/
- if (unlikely(ms->log_failure)) {
+ if (unlikely(ms->log_failure) && errors_handled(ms)) {
spin_lock_irq(&ms->lock);
bio_list_merge(&ms->failures, &sync);
spin_unlock_irq(&ms->lock);
@@ -737,9 +744,12 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
dm_rh_delay(ms->rh, bio);
while ((bio = bio_list_pop(&nosync))) {
- if (unlikely(ms->leg_failure) && errors_handled(ms))
- hold_bio(ms, bio);
- else {
+ if (unlikely(ms->leg_failure) && errors_handled(ms)) {
+ spin_lock_irq(&ms->lock);
+ bio_list_add(&ms->failures, bio);
+ spin_unlock_irq(&ms->lock);
+ wakeup_mirrord(ms);
+ } else {
map_bio(get_default_mirror(ms), bio);
generic_make_request(bio);
}
@@ -917,8 +927,7 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
return -EINVAL;
}
- if (dm_get_device(ti, argv[0], offset, ti->len,
- dm_table_get_mode(ti->table),
+ if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table),
&ms->mirror[mirror].dev)) {
ti->error = "Device lookup failure";
return -ENXIO;
@@ -1259,6 +1268,20 @@ static void mirror_presuspend(struct dm_target *ti)
atomic_set(&ms->suspend, 1);
/*
+ * Process bios in the hold list to start recovery waiting
+ * for bios in the hold list. After the process, no bio has
+ * a chance to be added in the hold list because ms->suspend
+ * is set.
+ */
+ spin_lock_irq(&ms->lock);
+ holds = ms->holds;
+ bio_list_init(&ms->holds);
+ spin_unlock_irq(&ms->lock);
+
+ while ((bio = bio_list_pop(&holds)))
+ hold_bio(ms, bio);
+
+ /*
* We must finish up all the work that we've
* generated (i.e. recovery work).
*/
@@ -1278,22 +1301,6 @@ static void mirror_presuspend(struct dm_target *ti)
* we know that all of our I/O has been pushed.
*/
flush_workqueue(ms->kmirrord_wq);
-
- /*
- * Now set ms->suspend is set and the workqueue flushed, no more
- * entries can be added to ms->hold list, so process it.
- *
- * Bios can still arrive concurrently with or after this
- * presuspend function, but they cannot join the hold list
- * because ms->suspend is set.
- */
- spin_lock_irq(&ms->lock);
- holds = ms->holds;
- bio_list_init(&ms->holds);
- spin_unlock_irq(&ms->lock);
-
- while ((bio = bio_list_pop(&holds)))
- hold_bio(ms, bio);
}
static void mirror_postsuspend(struct dm_target *ti)
diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c
index 5f19ceb6fe91..168bd38f5006 100644
--- a/drivers/md/dm-region-hash.c
+++ b/drivers/md/dm-region-hash.c
@@ -660,10 +660,9 @@ void dm_rh_recovery_end(struct dm_region *reg, int success)
spin_lock_irq(&rh->region_lock);
if (success)
list_add(&reg->list, &reg->rh->recovered_regions);
- else {
- reg->state = DM_RH_NOSYNC;
+ else
list_add(&reg->list, &reg->rh->failed_recovered_regions);
- }
+
spin_unlock_irq(&rh->region_lock);
rh->wakeup_workers(rh->context);
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index 7d08879689ac..c097d8a4823d 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -254,7 +254,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw,
* Issue the synchronous I/O from a different thread
* to avoid generic_make_request recursion.
*/
- INIT_WORK(&req.work, do_metadata);
+ INIT_WORK_ON_STACK(&req.work, do_metadata);
queue_work(ps->metadata_wq, &req.work);
flush_workqueue(ps->metadata_wq);
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index ee8eb283650d..54853773510c 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -83,10 +83,10 @@ struct dm_snapshot {
/* Whether or not owning mapped_device is suspended */
int suspended;
- mempool_t *pending_pool;
-
atomic_t pending_exceptions_count;
+ mempool_t *pending_pool;
+
struct dm_exception_table pending;
struct dm_exception_table complete;
@@ -96,6 +96,11 @@ struct dm_snapshot {
*/
spinlock_t pe_lock;
+ /* Chunks with outstanding reads */
+ spinlock_t tracked_chunk_lock;
+ mempool_t *tracked_chunk_pool;
+ struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE];
+
/* The on disk metadata handler */
struct dm_exception_store *store;
@@ -105,10 +110,12 @@ struct dm_snapshot {
struct bio_list queued_bios;
struct work_struct queued_bios_work;
- /* Chunks with outstanding reads */
- mempool_t *tracked_chunk_pool;
- spinlock_t tracked_chunk_lock;
- struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE];
+ /* Wait for events based on state_bits */
+ unsigned long state_bits;
+
+ /* Range of chunks currently being merged. */
+ chunk_t first_merging_chunk;
+ int num_merging_chunks;
/*
* The merge operation failed if this flag is set.
@@ -125,13 +132,6 @@ struct dm_snapshot {
*/
int merge_failed;
- /* Wait for events based on state_bits */
- unsigned long state_bits;
-
- /* Range of chunks currently being merged. */
- chunk_t first_merging_chunk;
- int num_merging_chunks;
-
/*
* Incoming bios that overlap with chunks being merged must wait
* for them to be committed.
@@ -1081,8 +1081,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
argv++;
argc--;
- r = dm_get_device(ti, cow_path, 0, 0,
- FMODE_READ | FMODE_WRITE, &s->cow);
+ r = dm_get_device(ti, cow_path, FMODE_READ | FMODE_WRITE, &s->cow);
if (r) {
ti->error = "Cannot get COW device";
goto bad_cow;
@@ -1098,7 +1097,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
argv += args_used;
argc -= args_used;
- r = dm_get_device(ti, origin_path, 0, ti->len, origin_mode, &s->origin);
+ r = dm_get_device(ti, origin_path, origin_mode, &s->origin);
if (r) {
ti->error = "Cannot get origin device";
goto bad_origin;
@@ -2100,8 +2099,7 @@ static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
return -EINVAL;
}
- r = dm_get_device(ti, argv[0], 0, ti->len,
- dm_table_get_mode(ti->table), &dev);
+ r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &dev);
if (r) {
ti->error = "Cannot get target device";
return r;
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index e0efc1adcaff..e610725db766 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -80,8 +80,7 @@ static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
if (sscanf(argv[1], "%llu", &start) != 1)
return -EINVAL;
- if (dm_get_device(ti, argv[0], start, sc->stripe_width,
- dm_table_get_mode(ti->table),
+ if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table),
&sc->stripe[stripe].dev))
return -ENXIO;
@@ -110,7 +109,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
stripes = simple_strtoul(argv[0], &end, 10);
- if (*end) {
+ if (!stripes || *end) {
ti->error = "Invalid stripe count";
return -EINVAL;
}
diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c
index f53392df7b97..84d2b91e4efb 100644
--- a/drivers/md/dm-sysfs.c
+++ b/drivers/md/dm-sysfs.c
@@ -75,25 +75,17 @@ static struct attribute *dm_attrs[] = {
NULL,
};
-static struct sysfs_ops dm_sysfs_ops = {
+static const struct sysfs_ops dm_sysfs_ops = {
.show = dm_attr_show,
};
/*
- * The sysfs structure is embedded in md struct, nothing to do here
- */
-static void dm_sysfs_release(struct kobject *kobj)
-{
-}
-
-/*
* dm kobject is embedded in mapped_device structure
* no need to define release function here
*/
static struct kobj_type dm_ktype = {
.sysfs_ops = &dm_sysfs_ops,
.default_attrs = dm_attrs,
- .release = dm_sysfs_release
};
/*
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index be625475cf6d..9924ea23032d 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -429,8 +429,7 @@ static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode,
* it's already present.
*/
static int __table_get_device(struct dm_table *t, struct dm_target *ti,
- const char *path, sector_t start, sector_t len,
- fmode_t mode, struct dm_dev **result)
+ const char *path, fmode_t mode, struct dm_dev **result)
{
int r;
dev_t uninitialized_var(dev);
@@ -503,16 +502,15 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
return 0;
}
- if (blk_stack_limits(limits, &q->limits, start << 9) < 0)
- DMWARN("%s: target device %s is misaligned: "
+ if (bdev_stack_limits(limits, bdev, start) < 0)
+ DMWARN("%s: adding target device %s caused an alignment inconsistency: "
"physical_block_size=%u, logical_block_size=%u, "
"alignment_offset=%u, start=%llu",
dm_device_name(ti->table->md), bdevname(bdev, b),
q->limits.physical_block_size,
q->limits.logical_block_size,
q->limits.alignment_offset,
- (unsigned long long) start << 9);
-
+ (unsigned long long) start << SECTOR_SHIFT);
/*
* Check if merge fn is supported.
@@ -528,11 +526,10 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
}
EXPORT_SYMBOL_GPL(dm_set_device_limits);
-int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
- sector_t len, fmode_t mode, struct dm_dev **result)
+int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
+ struct dm_dev **result)
{
- return __table_get_device(ti->table, ti, path,
- start, len, mode, result);
+ return __table_get_device(ti->table, ti, path, mode, result);
}
@@ -1026,9 +1023,9 @@ combine_limits:
* for the table.
*/
if (blk_stack_limits(limits, &ti_limits, 0) < 0)
- DMWARN("%s: target device "
+ DMWARN("%s: adding target device "
"(start sect %llu len %llu) "
- "is misaligned",
+ "caused an alignment inconsistency",
dm_device_name(table->md),
(unsigned long long) ti->begin,
(unsigned long long) ti->len);
@@ -1080,15 +1077,6 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
struct queue_limits *limits)
{
/*
- * Each target device in the table has a data area that should normally
- * be aligned such that the DM device's alignment_offset is 0.
- * FIXME: Propagate alignment_offsets up the stack and warn of
- * sub-optimal or inconsistent settings.
- */
- limits->alignment_offset = 0;
- limits->misaligned = 0;
-
- /*
* Copy table's limits to the DM device's request_queue
*/
q->limits = *limits;
@@ -1241,8 +1229,6 @@ void dm_table_unplug_all(struct dm_table *t)
struct mapped_device *dm_table_get_md(struct dm_table *t)
{
- dm_get(t->md);
-
return t->md;
}
diff --git a/drivers/md/dm-uevent.c b/drivers/md/dm-uevent.c
index c7c555a8c7b2..6b1e3b61b25e 100644
--- a/drivers/md/dm-uevent.c
+++ b/drivers/md/dm-uevent.c
@@ -187,7 +187,7 @@ void dm_path_uevent(enum dm_uevent_type event_type, struct dm_target *ti,
if (event_type >= ARRAY_SIZE(_dm_uevent_type_names)) {
DMERR("%s: Invalid event_type %d", __func__, event_type);
- goto out;
+ return;
}
event = dm_build_path_uevent(md, ti,
@@ -195,12 +195,9 @@ void dm_path_uevent(enum dm_uevent_type event_type, struct dm_target *ti,
_dm_uevent_type_names[event_type].name,
path, nr_valid_paths);
if (IS_ERR(event))
- goto out;
+ return;
dm_uevent_add(md, &event->elist);
-
-out:
- dm_put(md);
}
EXPORT_SYMBOL_GPL(dm_path_uevent);
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 3167480b532c..d21e1284604f 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -635,8 +635,10 @@ static void dec_pending(struct dm_io *io, int error)
if (!md->barrier_error && io_error != -EOPNOTSUPP)
md->barrier_error = io_error;
end_io_acct(io);
+ free_io(md, io);
} else {
end_io_acct(io);
+ free_io(md, io);
if (io_error != DM_ENDIO_REQUEUE) {
trace_block_bio_complete(md->queue, bio);
@@ -644,8 +646,6 @@ static void dec_pending(struct dm_io *io, int error)
bio_endio(bio, io_error);
}
}
-
- free_io(md, io);
}
}
@@ -1595,10 +1595,15 @@ static int dm_prep_fn(struct request_queue *q, struct request *rq)
return BLKPREP_OK;
}
-static void map_request(struct dm_target *ti, struct request *clone,
- struct mapped_device *md)
+/*
+ * Returns:
+ * 0 : the request has been processed (not requeued)
+ * !0 : the request has been requeued
+ */
+static int map_request(struct dm_target *ti, struct request *clone,
+ struct mapped_device *md)
{
- int r;
+ int r, requeued = 0;
struct dm_rq_target_io *tio = clone->end_io_data;
/*
@@ -1625,6 +1630,7 @@ static void map_request(struct dm_target *ti, struct request *clone,
case DM_MAPIO_REQUEUE:
/* The target wants to requeue the I/O */
dm_requeue_unmapped_request(clone);
+ requeued = 1;
break;
default:
if (r > 0) {
@@ -1636,6 +1642,8 @@ static void map_request(struct dm_target *ti, struct request *clone,
dm_kill_unmapped_request(clone, r);
break;
}
+
+ return requeued;
}
/*
@@ -1677,12 +1685,17 @@ static void dm_request_fn(struct request_queue *q)
atomic_inc(&md->pending[rq_data_dir(clone)]);
spin_unlock(q->queue_lock);
- map_request(ti, clone, md);
+ if (map_request(ti, clone, md))
+ goto requeued;
+
spin_lock_irq(q->queue_lock);
}
goto out;
+requeued:
+ spin_lock_irq(q->queue_lock);
+
plug_and_out:
if (!elv_queue_empty(q))
/* Some requests still remain, retry later */
@@ -2605,18 +2618,19 @@ out:
/*-----------------------------------------------------------------
* Event notification.
*---------------------------------------------------------------*/
-void dm_kobject_uevent(struct mapped_device *md, enum kobject_action action,
+int dm_kobject_uevent(struct mapped_device *md, enum kobject_action action,
unsigned cookie)
{
char udev_cookie[DM_COOKIE_LENGTH];
char *envp[] = { udev_cookie, NULL };
if (!cookie)
- kobject_uevent(&disk_to_dev(md->disk)->kobj, action);
+ return kobject_uevent(&disk_to_dev(md->disk)->kobj, action);
else {
snprintf(udev_cookie, DM_COOKIE_LENGTH, "%s=%u",
DM_COOKIE_ENV_VAR_NAME, cookie);
- kobject_uevent_env(&disk_to_dev(md->disk)->kobj, action, envp);
+ return kobject_uevent_env(&disk_to_dev(md->disk)->kobj,
+ action, envp);
}
}
@@ -2686,23 +2700,13 @@ int dm_suspended_md(struct mapped_device *md)
int dm_suspended(struct dm_target *ti)
{
- struct mapped_device *md = dm_table_get_md(ti->table);
- int r = dm_suspended_md(md);
-
- dm_put(md);
-
- return r;
+ return dm_suspended_md(dm_table_get_md(ti->table));
}
EXPORT_SYMBOL_GPL(dm_suspended);
int dm_noflush_suspending(struct dm_target *ti)
{
- struct mapped_device *md = dm_table_get_md(ti->table);
- int r = __noflush_suspending(md);
-
- dm_put(md);
-
- return r;
+ return __noflush_suspending(dm_table_get_md(ti->table));
}
EXPORT_SYMBOL_GPL(dm_noflush_suspending);
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 8dadaa5bc396..bad1724d4869 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -125,8 +125,8 @@ void dm_stripe_exit(void);
int dm_open_count(struct mapped_device *md);
int dm_lock_for_deletion(struct mapped_device *md);
-void dm_kobject_uevent(struct mapped_device *md, enum kobject_action action,
- unsigned cookie);
+int dm_kobject_uevent(struct mapped_device *md, enum kobject_action action,
+ unsigned cookie);
int dm_io_init(void);
void dm_io_exit(void);
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 00435bd20699..af2d39d603c7 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -177,7 +177,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
*/
if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
- blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+ blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
conf->array_sectors += rdev->sectors;
cnt++;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index dd3dfe42d5a9..fdc1890b6ac5 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -2642,7 +2642,7 @@ static void rdev_free(struct kobject *ko)
mdk_rdev_t *rdev = container_of(ko, mdk_rdev_t, kobj);
kfree(rdev);
}
-static struct sysfs_ops rdev_sysfs_ops = {
+static const struct sysfs_ops rdev_sysfs_ops = {
.show = rdev_attr_show,
.store = rdev_attr_store,
};
@@ -4059,7 +4059,7 @@ static void md_free(struct kobject *ko)
kfree(mddev);
}
-static struct sysfs_ops md_sysfs_ops = {
+static const struct sysfs_ops md_sysfs_ops = {
.show = md_attr_show,
.store = md_attr_store,
};
@@ -4075,8 +4075,10 @@ static void mddev_delayed_delete(struct work_struct *ws)
{
mddev_t *mddev = container_of(ws, mddev_t, del_work);
- if (mddev->private == &md_redundancy_group) {
+ if (mddev->private) {
sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
+ if (mddev->private != (void*)1)
+ sysfs_remove_group(&mddev->kobj, mddev->private);
if (mddev->sysfs_action)
sysfs_put(mddev->sysfs_action);
mddev->sysfs_action = NULL;
@@ -4287,10 +4289,7 @@ static int do_md_run(mddev_t * mddev)
sysfs_notify_dirent(rdev->sysfs_state);
}
- md_probe(mddev->unit, NULL, NULL);
disk = mddev->gendisk;
- if (!disk)
- return -ENOMEM;
spin_lock(&pers_lock);
pers = find_pers(mddev->level, mddev->clevel);
@@ -4530,8 +4529,8 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
mddev->queue->unplug_fn = NULL;
mddev->queue->backing_dev_info.congested_fn = NULL;
module_put(mddev->pers->owner);
- if (mddev->pers->sync_request)
- mddev->private = &md_redundancy_group;
+ if (mddev->pers->sync_request && mddev->private == NULL)
+ mddev->private = (void*)1;
mddev->pers = NULL;
/* tell userspace to handle 'inactive' */
sysfs_notify_dirent(mddev->sysfs_state);
@@ -4578,9 +4577,6 @@ out:
}
mddev->bitmap_info.offset = 0;
- /* make sure all md_delayed_delete calls have finished */
- flush_scheduled_work();
-
export_array(mddev);
mddev->array_sectors = 0;
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 32a662fc55c9..4b323f45ad74 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -308,7 +308,7 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
*/
if (q->merge_bvec_fn &&
queue_max_sectors(q) > (PAGE_SIZE>>9))
- blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+ blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
conf->working_disks++;
mddev->degraded--;
@@ -478,7 +478,7 @@ static int multipath_run (mddev_t *mddev)
* a merge_bvec_fn to be involved in multipath */
if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
- blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+ blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
if (!test_bit(Faulty, &rdev->flags))
conf->working_disks++;
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 77605cdceaf1..a1f7147b757f 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -182,7 +182,7 @@ static int create_strip_zones(mddev_t *mddev)
if (rdev1->bdev->bd_disk->queue->merge_bvec_fn &&
queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
- blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+ blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
if (!smallest || (rdev1->sectors < smallest->sectors))
smallest = rdev1;
@@ -325,7 +325,7 @@ static int raid0_run(mddev_t *mddev)
}
if (md_check_no_bitmap(mddev))
return -EINVAL;
- blk_queue_max_sectors(mddev->queue, mddev->chunk_sectors);
+ blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors);
mddev->queue->queue_lock = &mddev->queue->__queue_lock;
ret = create_strip_zones(mddev);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 859bd3ffe435..5a06122abd3b 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1158,7 +1158,7 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
*/
if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
- blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+ blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
p->head_position = 0;
rdev->raid_disk = mirror;
@@ -2103,7 +2103,7 @@ static int run(mddev_t *mddev)
*/
if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
- blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+ blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
}
mddev->degraded = 0;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index d119b7b75e71..7584f9ab9bcf 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1161,7 +1161,7 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
*/
if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
- blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+ blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
p->head_position = 0;
rdev->raid_disk = mirror;
@@ -2260,7 +2260,7 @@ static int run(mddev_t *mddev)
*/
if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9))
- blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
+ blk_queue_max_hw_sectors(mddev->queue, PAGE_SIZE>>9);
disk->head_position = 0;
}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index e84204eb12df..70ffbd071b2e 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3739,7 +3739,7 @@ static int bio_fits_rdev(struct bio *bi)
if ((bi->bi_size>>9) > queue_max_sectors(q))
return 0;
blk_recount_segments(q, bi);
- if (bi->bi_phys_segments > queue_max_phys_segments(q))
+ if (bi->bi_phys_segments > queue_max_segments(q))
return 0;
if (q->merge_bvec_fn)
@@ -4680,7 +4680,7 @@ static int raid5_alloc_percpu(raid5_conf_t *conf)
{
unsigned long cpu;
struct page *spare_page;
- struct raid5_percpu *allcpus;
+ struct raid5_percpu __percpu *allcpus;
void *scribble;
int err;
@@ -5136,9 +5136,8 @@ static int stop(mddev_t *mddev)
mddev->thread = NULL;
mddev->queue->backing_dev_info.congested_fn = NULL;
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
- sysfs_remove_group(&mddev->kobj, &raid5_attrs_group);
free_conf(conf);
- mddev->private = NULL;
+ mddev->private = &raid5_attrs_group;
return 0;
}
@@ -5464,11 +5463,11 @@ static int raid5_start_reshape(mddev_t *mddev)
!test_bit(Faulty, &rdev->flags)) {
if (raid5_add_disk(mddev, rdev) == 0) {
char nm[20];
- if (rdev->raid_disk >= conf->previous_raid_disks)
+ if (rdev->raid_disk >= conf->previous_raid_disks) {
set_bit(In_sync, &rdev->flags);
- else
+ added_devices++;
+ } else
rdev->recovery_offset = 0;
- added_devices++;
sprintf(nm, "rd%d", rdev->raid_disk);
if (sysfs_create_link(&mddev->kobj,
&rdev->kobj, nm))
@@ -5480,9 +5479,12 @@ static int raid5_start_reshape(mddev_t *mddev)
break;
}
+ /* When a reshape changes the number of devices, ->degraded
+ * is measured against the large of the pre and post number of
+ * devices.*/
if (mddev->delta_disks > 0) {
spin_lock_irqsave(&conf->device_lock, flags);
- mddev->degraded = (conf->raid_disks - conf->previous_raid_disks)
+ mddev->degraded += (conf->raid_disks - conf->previous_raid_disks)
- added_devices;
spin_unlock_irqrestore(&conf->device_lock, flags);
}
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index dd708359b451..0f86f5e36724 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -405,7 +405,7 @@ struct raid5_private_data {
* lists and performing address
* conversions
*/
- } *percpu;
+ } __percpu *percpu;
size_t scribble_len; /* size of scribble region must be
* associated with conf to handle
* cpu hotplug while reshaping
diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile
index df5ddb4bbbf7..171890e7a41d 100644
--- a/drivers/media/IR/Makefile
+++ b/drivers/media/IR/Makefile
@@ -1,5 +1,5 @@
ir-common-objs := ir-functions.o ir-keymaps.o
-ir-core-objs := ir-keytable.o
+ir-core-objs := ir-keytable.o ir-sysfs.o
obj-$(CONFIG_IR_CORE) += ir-core.o
obj-$(CONFIG_VIDEO_IR) += ir-common.o
diff --git a/drivers/media/IR/ir-functions.c b/drivers/media/IR/ir-functions.c
index 776a136616d6..ab06919ad5fc 100644
--- a/drivers/media/IR/ir-functions.c
+++ b/drivers/media/IR/ir-functions.c
@@ -52,7 +52,7 @@ static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
/* -------------------------------------------------------------------------- */
int ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
- int ir_type)
+ const u64 ir_type)
{
ir->ir_type = ir_type;
diff --git a/drivers/media/IR/ir-keymaps.c b/drivers/media/IR/ir-keymaps.c
index 9bbe6b1e9871..0efdefe75f32 100644
--- a/drivers/media/IR/ir-keymaps.c
+++ b/drivers/media/IR/ir-keymaps.c
@@ -3393,3 +3393,102 @@ struct ir_scancode_table ir_codes_nec_terratec_cinergy_xs_table = {
};
EXPORT_SYMBOL_GPL(ir_codes_nec_terratec_cinergy_xs_table);
+
+/* Leadtek Winfast TV USB II Deluxe remote
+ Magnus Alm <magnus.alm@gmail.com>
+ */
+static struct ir_scancode ir_codes_winfast_usbii_deluxe[] = {
+ { 0x62, KEY_0},
+ { 0x75, KEY_1},
+ { 0x76, KEY_2},
+ { 0x77, KEY_3},
+ { 0x79, KEY_4},
+ { 0x7a, KEY_5},
+ { 0x7b, KEY_6},
+ { 0x7d, KEY_7},
+ { 0x7e, KEY_8},
+ { 0x7f, KEY_9},
+
+ { 0x38, KEY_CAMERA}, /* SNAPSHOT */
+ { 0x37, KEY_RECORD}, /* RECORD */
+ { 0x35, KEY_TIME}, /* TIMESHIFT */
+
+ { 0x74, KEY_VOLUMEUP}, /* VOLUMEUP */
+ { 0x78, KEY_VOLUMEDOWN}, /* VOLUMEDOWN */
+ { 0x64, KEY_MUTE}, /* MUTE */
+
+ { 0x21, KEY_CHANNEL}, /* SURF */
+ { 0x7c, KEY_CHANNELUP}, /* CHANNELUP */
+ { 0x60, KEY_CHANNELDOWN}, /* CHANNELDOWN */
+ { 0x61, KEY_LAST}, /* LAST CHANNEL (RECALL) */
+
+ { 0x72, KEY_VIDEO}, /* INPUT MODES (TV/FM) */
+
+ { 0x70, KEY_POWER2}, /* TV ON/OFF */
+
+ { 0x39, KEY_CYCLEWINDOWS}, /* MINIMIZE (BOSS) */
+ { 0x3a, KEY_NEW}, /* PIP */
+ { 0x73, KEY_ZOOM}, /* FULLSECREEN */
+
+ { 0x66, KEY_INFO}, /* OSD (DISPLAY) */
+
+ { 0x31, KEY_DOT}, /* '.' */
+ { 0x63, KEY_ENTER}, /* ENTER */
+
+};
+struct ir_scancode_table ir_codes_winfast_usbii_deluxe_table = {
+ .scan = ir_codes_winfast_usbii_deluxe,
+ .size = ARRAY_SIZE(ir_codes_winfast_usbii_deluxe),
+};
+EXPORT_SYMBOL_GPL(ir_codes_winfast_usbii_deluxe_table);
+
+/* Kworld 315U
+ */
+static struct ir_scancode ir_codes_kworld_315u[] = {
+ { 0x6143, KEY_POWER },
+ { 0x6101, KEY_TUNER }, /* source */
+ { 0x610b, KEY_ZOOM },
+ { 0x6103, KEY_POWER2 }, /* shutdown */
+
+ { 0x6104, KEY_1 },
+ { 0x6108, KEY_2 },
+ { 0x6102, KEY_3 },
+ { 0x6109, KEY_CHANNELUP },
+
+ { 0x610f, KEY_4 },
+ { 0x6105, KEY_5 },
+ { 0x6106, KEY_6 },
+ { 0x6107, KEY_CHANNELDOWN },
+
+ { 0x610c, KEY_7 },
+ { 0x610d, KEY_8 },
+ { 0x610a, KEY_9 },
+ { 0x610e, KEY_VOLUMEUP },
+
+ { 0x6110, KEY_LAST },
+ { 0x6111, KEY_0 },
+ { 0x6112, KEY_ENTER },
+ { 0x6113, KEY_VOLUMEDOWN },
+
+ { 0x6114, KEY_RECORD },
+ { 0x6115, KEY_STOP },
+ { 0x6116, KEY_PLAY },
+ { 0x6117, KEY_MUTE },
+
+ { 0x6118, KEY_UP },
+ { 0x6119, KEY_DOWN },
+ { 0x611a, KEY_LEFT },
+ { 0x611b, KEY_RIGHT },
+
+ { 0x611c, KEY_RED },
+ { 0x611d, KEY_GREEN },
+ { 0x611e, KEY_YELLOW },
+ { 0x611f, KEY_BLUE },
+};
+
+struct ir_scancode_table ir_codes_kworld_315u_table = {
+ .scan = ir_codes_kworld_315u,
+ .size = ARRAY_SIZE(ir_codes_kworld_315u),
+ .ir_type = IR_TYPE_NEC,
+};
+EXPORT_SYMBOL_GPL(ir_codes_kworld_315u_table);
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index bff7a5356037..0a3b4ed38e48 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -13,7 +13,7 @@
*/
-#include <linux/usb/input.h>
+#include <linux/input.h>
#include <media/ir-common.h>
#define IR_TAB_MIN_SIZE 32
@@ -65,7 +65,7 @@ exit:
* In order to reduce the quantity of table resizes, it has a minimum
* table size of IR_TAB_MIN_SIZE.
*/
-int ir_roundup_tablesize(int n_elems)
+static int ir_roundup_tablesize(int n_elems)
{
size_t size;
@@ -81,7 +81,6 @@ int ir_roundup_tablesize(int n_elems)
return n_elems;
}
-EXPORT_SYMBOL_GPL(ir_roundup_tablesize);
/**
* ir_copy_table() - copies a keytable, discarding the unused entries
@@ -89,9 +88,11 @@ EXPORT_SYMBOL_GPL(ir_roundup_tablesize);
* @origin: origin table
*
* Copies all entries where the keycode is not KEY_UNKNOWN/KEY_RESERVED
+ * Also copies table size and table protocol.
+ * NOTE: It shouldn't copy the lock field
*/
-int ir_copy_table(struct ir_scancode_table *destin,
+static int ir_copy_table(struct ir_scancode_table *destin,
const struct ir_scancode_table *origin)
{
int i, j = 0;
@@ -105,12 +106,12 @@ int ir_copy_table(struct ir_scancode_table *destin,
j++;
}
destin->size = j;
+ destin->ir_type = origin->ir_type;
IR_dprintk(1, "Copied %d scancodes to the new keycode table\n", destin->size);
return 0;
}
-EXPORT_SYMBOL_GPL(ir_copy_table);
/**
* ir_getkeycode() - get a keycode at the evdev scancode ->keycode table
@@ -122,7 +123,7 @@ EXPORT_SYMBOL_GPL(ir_copy_table);
* If the key is not found, returns -EINVAL, otherwise, returns 0.
*/
static int ir_getkeycode(struct input_dev *dev,
- int scancode, int *keycode)
+ unsigned int scancode, unsigned int *keycode)
{
int elem;
struct ir_input_dev *ir_dev = input_get_drvdata(dev);
@@ -184,18 +185,14 @@ static void ir_delete_key(struct ir_scancode_table *rc_tab, int elem)
int newsize = rc_tab->size - 1;
int resize = ir_is_resize_needed(rc_tab, newsize);
struct ir_scancode *oldkeymap = rc_tab->scan;
- struct ir_scancode *newkeymap;
+ struct ir_scancode *newkeymap = NULL;
- if (resize) {
+ if (resize)
newkeymap = kzalloc(ir_roundup_tablesize(newsize) *
sizeof(*newkeymap), GFP_ATOMIC);
- /* There's no memory for resize. Keep the old table */
- if (!newkeymap)
- resize = 0;
- }
-
- if (!resize) {
+ /* There's no memory for resize. Keep the old table */
+ if (!resize || !newkeymap) {
newkeymap = oldkeymap;
/* We'll modify the live table. Lock it */
@@ -294,7 +291,7 @@ static int ir_insert_key(struct ir_scancode_table *rc_tab,
* If the key is not found, returns -EINVAL, otherwise, returns 0.
*/
static int ir_setkeycode(struct input_dev *dev,
- int scancode, int keycode)
+ unsigned int scancode, unsigned int keycode)
{
int rc = 0;
struct ir_input_dev *ir_dev = input_get_drvdata(dev);
@@ -399,12 +396,14 @@ EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
* @input_dev: the struct input_dev descriptor of the device
* @rc_tab: the struct ir_scancode_table table of scancode/keymap
*
- * This routine is used to initialize the input infrastructure to work with
- * an IR.
- * It should be called before registering the IR device.
+ * This routine is used to initialize the input infrastructure
+ * to work with an IR.
+ * It will register the input/evdev interface for the device and
+ * register the syfs code for IR class
*/
int ir_input_register(struct input_dev *input_dev,
- struct ir_scancode_table *rc_tab)
+ const struct ir_scancode_table *rc_tab,
+ const struct ir_dev_props *props)
{
struct ir_input_dev *ir_dev;
struct ir_scancode *keymap = rc_tab->scan;
@@ -417,19 +416,22 @@ int ir_input_register(struct input_dev *input_dev,
if (!ir_dev)
return -ENOMEM;
- spin_lock_init(&rc_tab->lock);
+ spin_lock_init(&ir_dev->rc_tab.lock);
ir_dev->rc_tab.size = ir_roundup_tablesize(rc_tab->size);
ir_dev->rc_tab.scan = kzalloc(ir_dev->rc_tab.size *
sizeof(struct ir_scancode), GFP_KERNEL);
- if (!ir_dev->rc_tab.scan)
+ if (!ir_dev->rc_tab.scan) {
+ kfree(ir_dev);
return -ENOMEM;
+ }
IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n",
ir_dev->rc_tab.size,
ir_dev->rc_tab.size * sizeof(ir_dev->rc_tab.scan));
ir_copy_table(&ir_dev->rc_tab, rc_tab);
+ ir_dev->props = props;
/* set the bits for the keys */
IR_dprintk(1, "key map size: %d\n", rc_tab->size);
@@ -447,16 +449,31 @@ int ir_input_register(struct input_dev *input_dev,
input_set_drvdata(input_dev, ir_dev);
rc = input_register_device(input_dev);
+ if (rc < 0)
+ goto err;
+
+ rc = ir_register_class(input_dev);
if (rc < 0) {
- kfree(rc_tab->scan);
- kfree(ir_dev);
- input_set_drvdata(input_dev, NULL);
+ input_unregister_device(input_dev);
+ goto err;
}
+ return 0;
+
+err:
+ kfree(rc_tab->scan);
+ kfree(ir_dev);
+ input_set_drvdata(input_dev, NULL);
return rc;
}
EXPORT_SYMBOL_GPL(ir_input_register);
+/**
+ * ir_input_unregister() - unregisters IR and frees resources
+ * @input_dev: the struct input_dev descriptor of the device
+
+ * This routine is used to free memory and de-register interfaces.
+ */
void ir_input_unregister(struct input_dev *dev)
{
struct ir_input_dev *ir_dev = input_get_drvdata(dev);
@@ -472,6 +489,8 @@ void ir_input_unregister(struct input_dev *dev)
kfree(rc_tab->scan);
rc_tab->scan = NULL;
+ ir_unregister_class(dev);
+
kfree(ir_dev);
input_unregister_device(dev);
}
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
new file mode 100644
index 000000000000..bf5fbcd84238
--- /dev/null
+++ b/drivers/media/IR/ir-sysfs.c
@@ -0,0 +1,211 @@
+/* ir-register.c - handle IR scancode->keycode tables
+ *
+ * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.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 version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/input.h>
+#include <linux/device.h>
+#include <media/ir-core.h>
+
+#define IRRCV_NUM_DEVICES 256
+
+/* bit array to represent IR sysfs device number */
+static unsigned long ir_core_dev_number;
+
+/* class for /sys/class/irrcv */
+static struct class *ir_input_class;
+
+/**
+ * show_protocol() - shows the current IR protocol
+ * @d: the device descriptor
+ * @mattr: the device attribute struct (unused)
+ * @buf: a pointer to the output buffer
+ *
+ * This routine is a callback routine for input read the IR protocol type.
+ * it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol.
+ * It returns the protocol name, as understood by the driver.
+ */
+static ssize_t show_protocol(struct device *d,
+ struct device_attribute *mattr, char *buf)
+{
+ char *s;
+ struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+ u64 ir_type = ir_dev->rc_tab.ir_type;
+
+ IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type);
+
+ /* FIXME: doesn't support multiple protocols at the same time */
+ if (ir_type == IR_TYPE_UNKNOWN)
+ s = "Unknown";
+ else if (ir_type == IR_TYPE_RC5)
+ s = "RC-5";
+ else if (ir_type == IR_TYPE_PD)
+ s = "Pulse/distance";
+ else if (ir_type == IR_TYPE_NEC)
+ s = "NEC";
+ else
+ s = "Other";
+
+ return sprintf(buf, "%s\n", s);
+}
+
+/**
+ * store_protocol() - shows the current IR protocol
+ * @d: the device descriptor
+ * @mattr: the device attribute struct (unused)
+ * @buf: a pointer to the input buffer
+ * @len: length of the input buffer
+ *
+ * This routine is a callback routine for changing the IR protocol type.
+ * it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol.
+ * It changes the IR the protocol name, if the IR type is recognized
+ * by the driver.
+ * If an unknown protocol name is used, returns -EINVAL.
+ */
+static ssize_t store_protocol(struct device *d,
+ struct device_attribute *mattr,
+ const char *data,
+ size_t len)
+{
+ struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+ u64 ir_type = IR_TYPE_UNKNOWN;
+ int rc = -EINVAL;
+ unsigned long flags;
+ char *buf;
+
+ buf = strsep((char **) &data, "\n");
+
+ if (!strcasecmp(buf, "rc-5"))
+ ir_type = IR_TYPE_RC5;
+ else if (!strcasecmp(buf, "pd"))
+ ir_type = IR_TYPE_PD;
+ else if (!strcasecmp(buf, "nec"))
+ ir_type = IR_TYPE_NEC;
+
+ if (ir_type == IR_TYPE_UNKNOWN) {
+ IR_dprintk(1, "Error setting protocol to %lld\n",
+ (long long)ir_type);
+ return -EINVAL;
+ }
+
+ if (ir_dev->props && ir_dev->props->change_protocol)
+ rc = ir_dev->props->change_protocol(ir_dev->props->priv,
+ ir_type);
+
+ if (rc < 0) {
+ IR_dprintk(1, "Error setting protocol to %lld\n",
+ (long long)ir_type);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
+ ir_dev->rc_tab.ir_type = ir_type;
+ spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
+
+ IR_dprintk(1, "Current protocol is %lld\n",
+ (long long)ir_type);
+
+ return len;
+}
+
+/*
+ * Static device attribute struct with the sysfs attributes for IR's
+ */
+static DEVICE_ATTR(current_protocol, S_IRUGO | S_IWUSR,
+ show_protocol, store_protocol);
+
+static struct attribute *ir_dev_attrs[] = {
+ &dev_attr_current_protocol.attr,
+ NULL,
+};
+
+/**
+ * ir_register_class() - creates the sysfs for /sys/class/irrcv/irrcv?
+ * @input_dev: the struct input_dev descriptor of the device
+ *
+ * This routine is used to register the syfs code for IR class
+ */
+int ir_register_class(struct input_dev *input_dev)
+{
+ int rc;
+ struct kobject *kobj;
+
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ int devno = find_first_zero_bit(&ir_core_dev_number,
+ IRRCV_NUM_DEVICES);
+
+ if (unlikely(devno < 0))
+ return devno;
+
+ ir_dev->attr.attrs = ir_dev_attrs;
+ ir_dev->class_dev = device_create(ir_input_class, NULL,
+ input_dev->dev.devt, ir_dev,
+ "irrcv%d", devno);
+ kobj = &ir_dev->class_dev->kobj;
+
+ printk(KERN_WARNING "Creating IR device %s\n", kobject_name(kobj));
+ rc = sysfs_create_group(kobj, &ir_dev->attr);
+ if (unlikely(rc < 0)) {
+ device_destroy(ir_input_class, input_dev->dev.devt);
+ return -ENOMEM;
+ }
+
+ ir_dev->devno = devno;
+ set_bit(devno, &ir_core_dev_number);
+
+ return 0;
+};
+
+/**
+ * ir_unregister_class() - removes the sysfs for sysfs for
+ * /sys/class/irrcv/irrcv?
+ * @input_dev: the struct input_dev descriptor of the device
+ *
+ * This routine is used to unregister the syfs code for IR class
+ */
+void ir_unregister_class(struct input_dev *input_dev)
+{
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct kobject *kobj;
+
+ clear_bit(ir_dev->devno, &ir_core_dev_number);
+
+ kobj = &ir_dev->class_dev->kobj;
+
+ sysfs_remove_group(kobj, &ir_dev->attr);
+ device_destroy(ir_input_class, input_dev->dev.devt);
+
+ kfree(ir_dev->attr.name);
+}
+
+/*
+ * Init/exit code for the module. Basically, creates/removes /sys/class/irrcv
+ */
+
+static int __init ir_core_init(void)
+{
+ ir_input_class = class_create(THIS_MODULE, "irrcv");
+ if (IS_ERR(ir_input_class)) {
+ printk(KERN_ERR "ir_core: unable to register irrcv class\n");
+ return PTR_ERR(ir_input_class);
+ }
+
+ return 0;
+}
+
+static void __exit ir_core_exit(void)
+{
+ class_destroy(ir_input_class);
+}
+
+module_init(ir_core_init);
+module_exit(ir_core_exit);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 7364b9642d00..fd8e1f45be36 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -423,14 +423,15 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status)
}
}
+int saa7146_vv_devinit(struct saa7146_dev *dev)
+{
+ return v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
+}
+EXPORT_SYMBOL_GPL(saa7146_vv_devinit);
+
int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
{
struct saa7146_vv *vv;
- int err;
-
- err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
- if (err)
- return err;
vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
if (vv == NULL) {
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index becbaadb3b77..5ed75263340a 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -1333,9 +1333,9 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
DEB_CAP(("vbuf:%p\n",vb));
- release_all_pagetables(dev, buf);
-
saa7146_dma_free(dev,q,buf);
+
+ release_all_pagetables(dev, buf);
}
static struct videobuf_queue_ops video_qops = {
diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c
index c190b0dedee4..2833137fa819 100644
--- a/drivers/media/common/tuners/tda8290.c
+++ b/drivers/media/common/tuners/tda8290.c
@@ -144,7 +144,8 @@ static void set_audio(struct dvb_frontend *fe,
}
if (params->mode == V4L2_TUNER_RADIO) {
- priv->tda8290_easy_mode = 0x01; /* Start with MN values */
+ /* Set TDA8295 to FM radio; Start TDA8290 with MN values */
+ priv->tda8290_easy_mode = (priv->ver & TDA8295) ? 0x80 : 0x01;
tuner_dbg("setting to radio FM\n");
} else {
tuner_dbg("setting tda829x to system %s\n", mode);
@@ -672,16 +673,19 @@ static int tda8290_probe(struct tuner_i2c_props *i2c_props)
static int tda8295_probe(struct tuner_i2c_props *i2c_props)
{
#define TDA8295_ID 0x8a
+#define TDA8295C2_ID 0x8b
unsigned char tda8295_id[] = { 0x2f, 0x00 };
/* detect tda8295 */
tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1);
tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1);
- if (tda8295_id[1] == TDA8295_ID) {
+ if ((tda8295_id[1] & 0xfe) == TDA8295_ID) {
if (debug)
- printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n",
- __func__, i2c_adapter_id(i2c_props->adap),
+ printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n",
+ __func__, (tda8295_id[1] == TDA8295_ID) ?
+ "tda8295c1" : "tda8295c2",
+ i2c_adapter_id(i2c_props->adap),
i2c_props->addr);
return 0;
}
diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c
index 2b876f3988c1..d9aaaca620c9 100644
--- a/drivers/media/common/tuners/tuner-types.c
+++ b/drivers/media/common/tuners/tuner-types.c
@@ -1337,6 +1337,22 @@ static struct tuner_params tuner_philips_cu1216l_params[] = {
},
};
+/* ---------------------- TUNER_SONY_BTF_PXN01Z ------------------------ */
+
+static struct tuner_range tuner_sony_btf_pxn01z_ranges[] = {
+ { 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 367.25 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x04, },
+};
+
+static struct tuner_params tuner_sony_btf_pxn01z_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_NTSC,
+ .ranges = tuner_sony_btf_pxn01z_ranges,
+ .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_ranges),
+ },
+};
+
/* --------------------------------------------------------------------- */
struct tunertype tuners[] = {
@@ -1805,6 +1821,11 @@ struct tunertype tuners[] = {
.name = "NXP TDA18271",
/* see tda18271-fe.c for details */
},
+ [TUNER_SONY_BTF_PXN01Z] = {
+ .name = "Sony BTF-Pxn01Z",
+ .params = tuner_sony_btf_pxn01z_params,
+ .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_params),
+ },
};
EXPORT_SYMBOL(tuners);
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c
index f270e605da83..be51c294b375 100644
--- a/drivers/media/common/tuners/tuner-xc2028.c
+++ b/drivers/media/common/tuners/tuner-xc2028.c
@@ -917,30 +917,68 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
* that xc2028 will be in a safe state.
* Maybe this might also be needed for DTV.
*/
- if (new_mode == T_ANALOG_TV)
+ if (new_mode == T_ANALOG_TV) {
rc = send_seq(priv, {0x00, 0x00});
- /*
- * Digital modes require an offset to adjust to the
- * proper frequency.
- * Analog modes require offset = 0
- */
- if (new_mode == T_DIGITAL_TV) {
- /* Sets the offset according with firmware */
+ /* Analog modes require offset = 0 */
+ } else {
+ /*
+ * Digital modes require an offset to adjust to the
+ * proper frequency. The offset depends on what
+ * firmware version is used.
+ */
+
+ /*
+ * Adjust to the center frequency. This is calculated by the
+ * formula: offset = 1.25MHz - BW/2
+ * For DTV 7/8, the firmware uses BW = 8000, so it needs a
+ * further adjustment to get the frequency center on VHF
+ */
if (priv->cur_fw.type & DTV6)
offset = 1750000;
else if (priv->cur_fw.type & DTV7)
offset = 2250000;
else /* DTV8 or DTV78 */
offset = 2750000;
+ if ((priv->cur_fw.type & DTV78) && freq < 470000000)
+ offset -= 500000;
/*
- * We must adjust the offset by 500kHz when
- * tuning a 7MHz VHF channel with DTV78 firmware
- * (used in Australia, Italy and Germany)
+ * xc3028 additional "magic"
+ * Depending on the firmware version, it needs some adjustments
+ * to properly centralize the frequency. This seems to be
+ * needed to compensate the SCODE table adjustments made by
+ * newer firmwares
*/
- if ((priv->cur_fw.type & DTV78) && freq < 470000000)
- offset -= 500000;
+
+#if 1
+ /*
+ * The proper adjustment would be to do it at s-code table.
+ * However, this didn't work, as reported by
+ * Robert Lowery <rglowery@exemail.com.au>
+ */
+
+ if (priv->cur_fw.type & DTV7)
+ offset += 500000;
+
+#else
+ /*
+ * Still need tests for XC3028L (firmware 3.2 or upper)
+ * So, for now, let's just comment the per-firmware
+ * version of this change. Reports with xc3028l working
+ * with and without the lines bellow are welcome
+ */
+
+ if (priv->firm_version < 0x0302) {
+ if (priv->cur_fw.type & DTV7)
+ offset += 500000;
+ } else {
+ if (priv->cur_fw.type & DTV7)
+ offset -= 300000;
+ else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */
+ offset += 200000;
+ }
+#endif
}
div = (freq - offset + DIV / 2) / DIV;
@@ -1097,17 +1135,24 @@ static int xc2028_set_params(struct dvb_frontend *fe,
/* All S-code tables need a 200kHz shift */
if (priv->ctrl.demod) {
- demod = priv->ctrl.demod + 200;
+ demod = priv->ctrl.demod;
+
+ /*
+ * Newer firmwares require a 200 kHz offset only for ATSC
+ */
+ if (type == ATSC || priv->firm_version < 0x0302)
+ demod += 200;
/*
* The DTV7 S-code table needs a 700 kHz shift.
- * Thanks to Terry Wu <terrywu2009@gmail.com> for reporting this
*
* DTV7 is only used in Australia. Germany or Italy may also
* use this firmware after initialization, but a tune to a UHF
* channel should then cause DTV78 to be used.
+ *
+ * Unfortunately, on real-field tests, the s-code offset
+ * didn't work as expected, as reported by
+ * Robert Lowery <rglowery@exemail.com.au>
*/
- if (type & DTV7)
- demod += 500;
}
return generic_set_freq(fe, p->frequency,
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 35d0817126e9..161ccfd471cb 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -72,6 +72,14 @@ comment "Supported Earthsoft PT1 Adapters"
depends on DVB_CORE && PCI && I2C
source "drivers/media/dvb/pt1/Kconfig"
+comment "Supported Mantis Adapters"
+ depends on DVB_CORE && PCI && I2C
+ source "drivers/media/dvb/mantis/Kconfig"
+
+comment "Supported nGene Adapters"
+ depends on DVB_CORE && PCI && I2C
+ source "drivers/media/dvb/ngene/Kconfig"
+
comment "Supported DVB Frontends"
depends on DVB_CORE
source "drivers/media/dvb/frontends/Kconfig"
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index 16d262ddb45d..a1a08758a6f2 100644
--- a/drivers/media/dvb/Makefile
+++ b/drivers/media/dvb/Makefile
@@ -2,6 +2,19 @@
# Makefile for the kernel multimedia device drivers.
#
-obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ pt1/
+obj-y := dvb-core/ \
+ frontends/ \
+ ttpci/ \
+ ttusb-dec/ \
+ ttusb-budget/ \
+ b2c2/ \
+ bt8xx/ \
+ dvb-usb/ \
+ pluto2/ \
+ siano/ \
+ dm1105/ \
+ pt1/ \
+ mantis/ \
+ ngene/
obj-$(CONFIG_DVB_FIREDTV) += firewire/
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index a24c125331f0..99d62094f908 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -576,43 +576,30 @@ static struct pci_driver bt878_pci_driver = {
.remove = __devexit_p(bt878_remove),
};
-static int bt878_pci_driver_registered;
-
/*******************************/
/* Module management functions */
/*******************************/
-static int bt878_init_module(void)
+static int __init bt878_init_module(void)
{
bt878_num = 0;
- bt878_pci_driver_registered = 0;
printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n",
(BT878_VERSION_CODE >> 16) & 0xff,
(BT878_VERSION_CODE >> 8) & 0xff,
BT878_VERSION_CODE & 0xff);
-/*
- bt878_check_chipset();
-*/
- /* later we register inside of bt878_find_audio_dma()
- * because we may want to ignore certain cards */
- bt878_pci_driver_registered = 1;
+
return pci_register_driver(&bt878_pci_driver);
}
-static void bt878_cleanup_module(void)
+static void __exit bt878_cleanup_module(void)
{
- if (bt878_pci_driver_registered) {
- bt878_pci_driver_registered = 0;
- pci_unregister_driver(&bt878_pci_driver);
- }
- return;
+ pci_unregister_driver(&bt878_pci_driver);
}
module_init(bt878_init_module);
module_exit(bt878_cleanup_module);
-//MODULE_AUTHOR("XXX");
MODULE_LICENSE("GPL");
/*
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 91353a6faf1d..8b0cde38984d 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1352,8 +1352,7 @@ static int dst_get_tuna(struct dst_state *state)
return retval;
}
if ((state->type_flags & DST_TYPE_HAS_VLF) &&
- !(state->dst_type == DST_TYPE_IS_CABLE) &&
- !(state->dst_type == DST_TYPE_IS_ATSC)) {
+ !(state->dst_type == DST_TYPE_IS_ATSC)) {
if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
@@ -1820,8 +1819,13 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
.frequency_max = 858000000,
.symbol_rate_min = 1000000,
.symbol_rate_max = 45000000,
- /* . symbol_rate_tolerance = ???,*/
- .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO
+ .caps = FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256
},
.release = dst_release,
diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig
index de3eeb0a8d6e..695239227cb7 100644
--- a/drivers/media/dvb/dm1105/Kconfig
+++ b/drivers/media/dvb/dm1105/Kconfig
@@ -8,6 +8,7 @@ config DVB_DM1105
select DVB_STB6000 if !DVB_FE_CUSTOMISE
select DVB_CX24116 if !DVB_FE_CUSTOMISE
select DVB_SI21XX if !DVB_FE_CUSTOMISE
+ select DVB_DS3000 if !DVB_FE_CUSTOMISE
select VIDEO_IR
help
Support for cards based on the SDMC DM1105 PCI chip like
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index f0f483ac8b89..383cca378b8c 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -43,6 +43,7 @@
#include "si21xx.h"
#include "cx24116.h"
#include "z0194a.h"
+#include "ds3000.h"
#define UNSET (-1U)
@@ -269,7 +270,7 @@ struct infrared {
u32 ir_command;
};
-struct dm1105dvb {
+struct dm1105_dev {
/* pci */
struct pci_dev *pdev;
u8 __iomem *io_mem;
@@ -308,31 +309,47 @@ struct dm1105dvb {
spinlock_t lock;
};
-#define dm_io_mem(reg) ((unsigned long)(&dm1105dvb->io_mem[reg]))
+#define dm_io_mem(reg) ((unsigned long)(&dev->io_mem[reg]))
+
+#define dm_readb(reg) inb(dm_io_mem(reg))
+#define dm_writeb(reg, value) outb((value), (dm_io_mem(reg)))
+
+#define dm_readw(reg) inw(dm_io_mem(reg))
+#define dm_writew(reg, value) outw((value), (dm_io_mem(reg)))
+
+#define dm_readl(reg) inl(dm_io_mem(reg))
+#define dm_writel(reg, value) outl((value), (dm_io_mem(reg)))
+
+#define dm_andorl(reg, mask, value) \
+ outl((inl(dm_io_mem(reg)) & ~(mask)) |\
+ ((value) & (mask)), (dm_io_mem(reg)))
+
+#define dm_setl(reg, bit) dm_andorl((reg), (bit), (bit))
+#define dm_clearl(reg, bit) dm_andorl((reg), (bit), 0)
static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg *msgs, int num)
{
- struct dm1105dvb *dm1105dvb ;
+ struct dm1105_dev *dev ;
int addr, rc, i, j, k, len, byte, data;
u8 status;
- dm1105dvb = i2c_adap->algo_data;
+ dev = i2c_adap->algo_data;
for (i = 0; i < num; i++) {
- outb(0x00, dm_io_mem(DM1105_I2CCTR));
+ dm_writeb(DM1105_I2CCTR, 0x00);
if (msgs[i].flags & I2C_M_RD) {
/* read bytes */
addr = msgs[i].addr << 1;
addr |= 1;
- outb(addr, dm_io_mem(DM1105_I2CDAT));
+ dm_writeb(DM1105_I2CDAT, addr);
for (byte = 0; byte < msgs[i].len; byte++)
- outb(0, dm_io_mem(DM1105_I2CDAT + byte + 1));
+ dm_writeb(DM1105_I2CDAT + byte + 1, 0);
- outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
+ dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
for (j = 0; j < 55; j++) {
mdelay(10);
- status = inb(dm_io_mem(DM1105_I2CSTS));
+ status = dm_readb(DM1105_I2CSTS);
if ((status & 0xc0) == 0x40)
break;
}
@@ -340,56 +357,54 @@ static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
return -1;
for (byte = 0; byte < msgs[i].len; byte++) {
- rc = inb(dm_io_mem(DM1105_I2CDAT + byte + 1));
+ rc = dm_readb(DM1105_I2CDAT + byte + 1);
if (rc < 0)
goto err;
msgs[i].buf[byte] = rc;
}
- } else {
- if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
- /* prepaired for cx24116 firmware */
- /* Write in small blocks */
- len = msgs[i].len - 1;
- k = 1;
- do {
- outb(msgs[i].addr << 1, dm_io_mem(DM1105_I2CDAT));
- outb(0xf7, dm_io_mem(DM1105_I2CDAT + 1));
- for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
- data = msgs[i].buf[k+byte];
- outb(data, dm_io_mem(DM1105_I2CDAT + byte + 2));
- }
- outb(0x82 + (len > 48 ? 48 : len), dm_io_mem(DM1105_I2CCTR));
- for (j = 0; j < 25; j++) {
- mdelay(10);
- status = inb(dm_io_mem(DM1105_I2CSTS));
- if ((status & 0xc0) == 0x40)
- break;
- }
-
- if (j >= 25)
- return -1;
-
- k += 48;
- len -= 48;
- } while (len > 0);
- } else {
- /* write bytes */
- outb(msgs[i].addr<<1, dm_io_mem(DM1105_I2CDAT));
- for (byte = 0; byte < msgs[i].len; byte++) {
- data = msgs[i].buf[byte];
- outb(data, dm_io_mem(DM1105_I2CDAT + byte + 1));
+ } else if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
+ /* prepaired for cx24116 firmware */
+ /* Write in small blocks */
+ len = msgs[i].len - 1;
+ k = 1;
+ do {
+ dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
+ dm_writeb(DM1105_I2CDAT + 1, 0xf7);
+ for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
+ data = msgs[i].buf[k + byte];
+ dm_writeb(DM1105_I2CDAT + byte + 2, data);
}
- outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
+ dm_writeb(DM1105_I2CCTR, 0x82 + (len > 48 ? 48 : len));
for (j = 0; j < 25; j++) {
mdelay(10);
- status = inb(dm_io_mem(DM1105_I2CSTS));
+ status = dm_readb(DM1105_I2CSTS);
if ((status & 0xc0) == 0x40)
break;
}
if (j >= 25)
return -1;
+
+ k += 48;
+ len -= 48;
+ } while (len > 0);
+ } else {
+ /* write bytes */
+ dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
+ for (byte = 0; byte < msgs[i].len; byte++) {
+ data = msgs[i].buf[byte];
+ dm_writeb(DM1105_I2CDAT + byte + 1, data);
}
+ dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
+ for (j = 0; j < 25; j++) {
+ mdelay(10);
+ status = dm_readb(DM1105_I2CSTS);
+ if ((status & 0xc0) == 0x40)
+ break;
+ }
+
+ if (j >= 25)
+ return -1;
}
}
return num;
@@ -407,22 +422,22 @@ static struct i2c_algorithm dm1105_algo = {
.functionality = functionality,
};
-static inline struct dm1105dvb *feed_to_dm1105dvb(struct dvb_demux_feed *feed)
+static inline struct dm1105_dev *feed_to_dm1105_dev(struct dvb_demux_feed *feed)
{
- return container_of(feed->demux, struct dm1105dvb, demux);
+ return container_of(feed->demux, struct dm1105_dev, demux);
}
-static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
+static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe)
{
- return container_of(fe->dvb, struct dm1105dvb, dvb_adapter);
+ return container_of(fe->dvb, struct dm1105_dev, dvb_adapter);
}
-static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
- struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
+ struct dm1105_dev *dev = frontend_to_dm1105_dev(fe);
u32 lnb_mask, lnb_13v, lnb_18v, lnb_off;
- switch (dm1105dvb->boardnr) {
+ switch (dev->boardnr) {
case DM1105_BOARD_AXESS_DM05:
lnb_mask = DM05_LNB_MASK;
lnb_off = DM05_LNB_OFF;
@@ -438,62 +453,67 @@ static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volta
lnb_18v = DM1105_LNB_18V;
}
- outl(lnb_mask, dm_io_mem(DM1105_GPIOCTR));
+ dm_writel(DM1105_GPIOCTR, lnb_mask);
if (voltage == SEC_VOLTAGE_18)
- outl(lnb_18v , dm_io_mem(DM1105_GPIOVAL));
+ dm_writel(DM1105_GPIOVAL, lnb_18v);
else if (voltage == SEC_VOLTAGE_13)
- outl(lnb_13v, dm_io_mem(DM1105_GPIOVAL));
+ dm_writel(DM1105_GPIOVAL, lnb_13v);
else
- outl(lnb_off, dm_io_mem(DM1105_GPIOVAL));
+ dm_writel(DM1105_GPIOVAL, lnb_off);
return 0;
}
-static void dm1105dvb_set_dma_addr(struct dm1105dvb *dm1105dvb)
+static void dm1105_set_dma_addr(struct dm1105_dev *dev)
{
- outl(cpu_to_le32(dm1105dvb->dma_addr), dm_io_mem(DM1105_STADR));
+ dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr));
}
-static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb)
+static int __devinit dm1105_dma_map(struct dm1105_dev *dev)
{
- dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr);
+ dev->ts_buf = pci_alloc_consistent(dev->pdev,
+ 6 * DM1105_DMA_BYTES,
+ &dev->dma_addr);
- return !dm1105dvb->ts_buf;
+ return !dev->ts_buf;
}
-static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb)
+static void dm1105_dma_unmap(struct dm1105_dev *dev)
{
- pci_free_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, dm1105dvb->ts_buf, dm1105dvb->dma_addr);
+ pci_free_consistent(dev->pdev,
+ 6 * DM1105_DMA_BYTES,
+ dev->ts_buf,
+ dev->dma_addr);
}
-static void dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb)
+static void dm1105_enable_irqs(struct dm1105_dev *dev)
{
- outb(INTMAK_ALLMASK, dm_io_mem(DM1105_INTMAK));
- outb(1, dm_io_mem(DM1105_CR));
+ dm_writeb(DM1105_INTMAK, INTMAK_ALLMASK);
+ dm_writeb(DM1105_CR, 1);
}
-static void dm1105dvb_disable_irqs(struct dm1105dvb *dm1105dvb)
+static void dm1105_disable_irqs(struct dm1105_dev *dev)
{
- outb(INTMAK_IRM, dm_io_mem(DM1105_INTMAK));
- outb(0, dm_io_mem(DM1105_CR));
+ dm_writeb(DM1105_INTMAK, INTMAK_IRM);
+ dm_writeb(DM1105_CR, 0);
}
-static int dm1105dvb_start_feed(struct dvb_demux_feed *f)
+static int dm1105_start_feed(struct dvb_demux_feed *f)
{
- struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
+ struct dm1105_dev *dev = feed_to_dm1105_dev(f);
- if (dm1105dvb->full_ts_users++ == 0)
- dm1105dvb_enable_irqs(dm1105dvb);
+ if (dev->full_ts_users++ == 0)
+ dm1105_enable_irqs(dev);
return 0;
}
-static int dm1105dvb_stop_feed(struct dvb_demux_feed *f)
+static int dm1105_stop_feed(struct dvb_demux_feed *f)
{
- struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
+ struct dm1105_dev *dev = feed_to_dm1105_dev(f);
- if (--dm1105dvb->full_ts_users == 0)
- dm1105dvb_disable_irqs(dm1105dvb);
+ if (--dev->full_ts_users == 0)
+ dm1105_disable_irqs(dev);
return 0;
}
@@ -517,68 +537,64 @@ static void dm1105_emit_key(struct work_struct *work)
/* work handler */
static void dm1105_dmx_buffer(struct work_struct *work)
{
- struct dm1105dvb *dm1105dvb =
- container_of(work, struct dm1105dvb, work);
+ struct dm1105_dev *dev = container_of(work, struct dm1105_dev, work);
unsigned int nbpackets;
- u32 oldwrp = dm1105dvb->wrp;
- u32 nextwrp = dm1105dvb->nextwrp;
+ u32 oldwrp = dev->wrp;
+ u32 nextwrp = dev->nextwrp;
- if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
- (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
- (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
- dm1105dvb->PacketErrorCount++;
+ if (!((dev->ts_buf[oldwrp] == 0x47) &&
+ (dev->ts_buf[oldwrp + 188] == 0x47) &&
+ (dev->ts_buf[oldwrp + 188 * 2] == 0x47))) {
+ dev->PacketErrorCount++;
/* bad packet found */
- if ((dm1105dvb->PacketErrorCount >= 2) &&
- (dm1105dvb->dmarst == 0)) {
- outb(1, dm_io_mem(DM1105_RST));
- dm1105dvb->wrp = 0;
- dm1105dvb->PacketErrorCount = 0;
- dm1105dvb->dmarst = 0;
+ if ((dev->PacketErrorCount >= 2) &&
+ (dev->dmarst == 0)) {
+ dm_writeb(DM1105_RST, 1);
+ dev->wrp = 0;
+ dev->PacketErrorCount = 0;
+ dev->dmarst = 0;
return;
}
}
if (nextwrp < oldwrp) {
- memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size,
- dm1105dvb->ts_buf, nextwrp);
- nbpackets = ((dm1105dvb->buffer_size - oldwrp) + nextwrp) / 188;
+ memcpy(dev->ts_buf + dev->buffer_size, dev->ts_buf, nextwrp);
+ nbpackets = ((dev->buffer_size - oldwrp) + nextwrp) / 188;
} else
nbpackets = (nextwrp - oldwrp) / 188;
- dm1105dvb->wrp = nextwrp;
- dvb_dmx_swfilter_packets(&dm1105dvb->demux,
- &dm1105dvb->ts_buf[oldwrp], nbpackets);
+ dev->wrp = nextwrp;
+ dvb_dmx_swfilter_packets(&dev->demux, &dev->ts_buf[oldwrp], nbpackets);
}
-static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
+static irqreturn_t dm1105_irq(int irq, void *dev_id)
{
- struct dm1105dvb *dm1105dvb = dev_id;
+ struct dm1105_dev *dev = dev_id;
/* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
- unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS));
- outb(intsts, dm_io_mem(DM1105_INTSTS));
+ unsigned int intsts = dm_readb(DM1105_INTSTS);
+ dm_writeb(DM1105_INTSTS, intsts);
switch (intsts) {
case INTSTS_TSIRQ:
case (INTSTS_TSIRQ | INTSTS_IR):
- dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) -
- inl(dm_io_mem(DM1105_STADR));
- queue_work(dm1105dvb->wq, &dm1105dvb->work);
+ dev->nextwrp = dm_readl(DM1105_WRP) - dm_readl(DM1105_STADR);
+ queue_work(dev->wq, &dev->work);
break;
case INTSTS_IR:
- dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));
- schedule_work(&dm1105dvb->ir.work);
+ dev->ir.ir_command = dm_readl(DM1105_IRCODE);
+ schedule_work(&dev->ir.work);
break;
}
return IRQ_HANDLED;
}
-int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
+int __devinit dm1105_ir_init(struct dm1105_dev *dm1105)
{
struct input_dev *input_dev;
struct ir_scancode_table *ir_codes = &ir_codes_dm1105_nec_table;
- int ir_type = IR_TYPE_OTHER;
+ u64 ir_type = IR_TYPE_OTHER;
int err = -ENOMEM;
input_dev = input_allocate_device();
@@ -611,51 +627,51 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
- err = ir_input_register(input_dev, ir_codes);
+ err = ir_input_register(input_dev, ir_codes, NULL);
return err;
}
-void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105)
+void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105)
{
ir_input_unregister(dm1105->ir.input_dev);
}
-static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb)
+static int __devinit dm1105_hw_init(struct dm1105_dev *dev)
{
- dm1105dvb_disable_irqs(dm1105dvb);
+ dm1105_disable_irqs(dev);
- outb(0, dm_io_mem(DM1105_HOST_CTR));
+ dm_writeb(DM1105_HOST_CTR, 0);
/*DATALEN 188,*/
- outb(188, dm_io_mem(DM1105_DTALENTH));
+ dm_writeb(DM1105_DTALENTH, 188);
/*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/
- outw(0xc10a, dm_io_mem(DM1105_TSCTR));
+ dm_writew(DM1105_TSCTR, 0xc10a);
/* map DMA and set address */
- dm1105dvb_dma_map(dm1105dvb);
- dm1105dvb_set_dma_addr(dm1105dvb);
+ dm1105_dma_map(dev);
+ dm1105_set_dma_addr(dev);
/* big buffer */
- outl(5*DM1105_DMA_BYTES, dm_io_mem(DM1105_RLEN));
- outb(47, dm_io_mem(DM1105_INTCNT));
+ dm_writel(DM1105_RLEN, 5 * DM1105_DMA_BYTES);
+ dm_writeb(DM1105_INTCNT, 47);
/* IR NEC mode enable */
- outb((DM1105_IR_EN | DM1105_SYS_CHK), dm_io_mem(DM1105_IRCTR));
- outb(0, dm_io_mem(DM1105_IRMODE));
- outw(0, dm_io_mem(DM1105_SYSTEMCODE));
+ dm_writeb(DM1105_IRCTR, (DM1105_IR_EN | DM1105_SYS_CHK));
+ dm_writeb(DM1105_IRMODE, 0);
+ dm_writew(DM1105_SYSTEMCODE, 0);
return 0;
}
-static void dm1105dvb_hw_exit(struct dm1105dvb *dm1105dvb)
+static void dm1105_hw_exit(struct dm1105_dev *dev)
{
- dm1105dvb_disable_irqs(dm1105dvb);
+ dm1105_disable_irqs(dev);
/* IR disable */
- outb(0, dm_io_mem(DM1105_IRCTR));
- outb(INTMAK_NONEMASK, dm_io_mem(DM1105_INTMAK));
+ dm_writeb(DM1105_IRCTR, 0);
+ dm_writeb(DM1105_INTMAK, INTMAK_NONEMASK);
- dm1105dvb_dma_unmap(dm1105dvb);
+ dm1105_dma_unmap(dev);
}
static struct stv0299_config sharp_z0194a_config = {
@@ -685,70 +701,79 @@ static struct cx24116_config serit_sp2633_config = {
.demod_address = 0x55,
};
-static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
+static struct ds3000_config dvbworld_ds3000_config = {
+ .demod_address = 0x68,
+};
+
+static int __devinit frontend_init(struct dm1105_dev *dev)
{
int ret;
- switch (dm1105dvb->boardnr) {
+ switch (dev->boardnr) {
case DM1105_BOARD_DVBWORLD_2004:
- dm1105dvb->fe = dvb_attach(
+ dev->fe = dvb_attach(
cx24116_attach, &serit_sp2633_config,
- &dm1105dvb->i2c_adap);
- if (dm1105dvb->fe)
- dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
+ &dev->i2c_adap);
+ if (dev->fe) {
+ dev->fe->ops.set_voltage = dm1105_set_voltage;
+ break;
+ }
+
+ dev->fe = dvb_attach(
+ ds3000_attach, &dvbworld_ds3000_config,
+ &dev->i2c_adap);
+ if (dev->fe)
+ dev->fe->ops.set_voltage = dm1105_set_voltage;
break;
case DM1105_BOARD_DVBWORLD_2002:
case DM1105_BOARD_AXESS_DM05:
default:
- dm1105dvb->fe = dvb_attach(
+ dev->fe = dvb_attach(
stv0299_attach, &sharp_z0194a_config,
- &dm1105dvb->i2c_adap);
- if (dm1105dvb->fe) {
- dm1105dvb->fe->ops.set_voltage =
- dm1105dvb_set_voltage;
- dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
- &dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
+ &dev->i2c_adap);
+ if (dev->fe) {
+ dev->fe->ops.set_voltage = dm1105_set_voltage;
+ dvb_attach(dvb_pll_attach, dev->fe, 0x60,
+ &dev->i2c_adap, DVB_PLL_OPERA1);
break;
}
- dm1105dvb->fe = dvb_attach(
+ dev->fe = dvb_attach(
stv0288_attach, &earda_config,
- &dm1105dvb->i2c_adap);
- if (dm1105dvb->fe) {
- dm1105dvb->fe->ops.set_voltage =
- dm1105dvb_set_voltage;
- dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
- &dm1105dvb->i2c_adap);
+ &dev->i2c_adap);
+ if (dev->fe) {
+ dev->fe->ops.set_voltage = dm1105_set_voltage;
+ dvb_attach(stb6000_attach, dev->fe, 0x61,
+ &dev->i2c_adap);
break;
}
- dm1105dvb->fe = dvb_attach(
+ dev->fe = dvb_attach(
si21xx_attach, &serit_config,
- &dm1105dvb->i2c_adap);
- if (dm1105dvb->fe)
- dm1105dvb->fe->ops.set_voltage =
- dm1105dvb_set_voltage;
+ &dev->i2c_adap);
+ if (dev->fe)
+ dev->fe->ops.set_voltage = dm1105_set_voltage;
}
- if (!dm1105dvb->fe) {
- dev_err(&dm1105dvb->pdev->dev, "could not attach frontend\n");
+ if (!dev->fe) {
+ dev_err(&dev->pdev->dev, "could not attach frontend\n");
return -ENODEV;
}
- ret = dvb_register_frontend(&dm1105dvb->dvb_adapter, dm1105dvb->fe);
+ ret = dvb_register_frontend(&dev->dvb_adapter, dev->fe);
if (ret < 0) {
- if (dm1105dvb->fe->ops.release)
- dm1105dvb->fe->ops.release(dm1105dvb->fe);
- dm1105dvb->fe = NULL;
+ if (dev->fe->ops.release)
+ dev->fe->ops.release(dev->fe);
+ dev->fe = NULL;
return ret;
}
return 0;
}
-static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
+static void __devinit dm1105_read_mac(struct dm1105_dev *dev, u8 *mac)
{
static u8 command[1] = { 0x28 };
@@ -766,47 +791,47 @@ static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
},
};
- dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
- dev_info(&dm1105dvb->pdev->dev, "MAC %pM\n", mac);
+ dm1105_i2c_xfer(&dev->i2c_adap, msg , 2);
+ dev_info(&dev->pdev->dev, "MAC %pM\n", mac);
}
static int __devinit dm1105_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- struct dm1105dvb *dm1105dvb;
+ struct dm1105_dev *dev;
struct dvb_adapter *dvb_adapter;
struct dvb_demux *dvbdemux;
struct dmx_demux *dmx;
int ret = -ENOMEM;
int i;
- dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
- if (!dm1105dvb)
+ dev = kzalloc(sizeof(struct dm1105_dev), GFP_KERNEL);
+ if (!dev)
return -ENOMEM;
/* board config */
- dm1105dvb->nr = dm1105_devcount;
- dm1105dvb->boardnr = UNSET;
- if (card[dm1105dvb->nr] < ARRAY_SIZE(dm1105_boards))
- dm1105dvb->boardnr = card[dm1105dvb->nr];
- for (i = 0; UNSET == dm1105dvb->boardnr &&
+ dev->nr = dm1105_devcount;
+ dev->boardnr = UNSET;
+ if (card[dev->nr] < ARRAY_SIZE(dm1105_boards))
+ dev->boardnr = card[dev->nr];
+ for (i = 0; UNSET == dev->boardnr &&
i < ARRAY_SIZE(dm1105_subids); i++)
if (pdev->subsystem_vendor ==
dm1105_subids[i].subvendor &&
pdev->subsystem_device ==
dm1105_subids[i].subdevice)
- dm1105dvb->boardnr = dm1105_subids[i].card;
+ dev->boardnr = dm1105_subids[i].card;
- if (UNSET == dm1105dvb->boardnr) {
- dm1105dvb->boardnr = DM1105_BOARD_UNKNOWN;
+ if (UNSET == dev->boardnr) {
+ dev->boardnr = DM1105_BOARD_UNKNOWN;
dm1105_card_list(pdev);
}
dm1105_devcount++;
- dm1105dvb->pdev = pdev;
- dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
- dm1105dvb->PacketErrorCount = 0;
- dm1105dvb->dmarst = 0;
+ dev->pdev = pdev;
+ dev->buffer_size = 5 * DM1105_DMA_BYTES;
+ dev->PacketErrorCount = 0;
+ dev->dmarst = 0;
ret = pci_enable_device(pdev);
if (ret < 0)
@@ -822,47 +847,47 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
if (ret < 0)
goto err_pci_disable_device;
- dm1105dvb->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
- if (!dm1105dvb->io_mem) {
+ dev->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
+ if (!dev->io_mem) {
ret = -EIO;
goto err_pci_release_regions;
}
- spin_lock_init(&dm1105dvb->lock);
- pci_set_drvdata(pdev, dm1105dvb);
+ spin_lock_init(&dev->lock);
+ pci_set_drvdata(pdev, dev);
- ret = dm1105dvb_hw_init(dm1105dvb);
+ ret = dm1105_hw_init(dev);
if (ret < 0)
goto err_pci_iounmap;
/* i2c */
- i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb);
- strcpy(dm1105dvb->i2c_adap.name, DRIVER_NAME);
- dm1105dvb->i2c_adap.owner = THIS_MODULE;
- dm1105dvb->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
- dm1105dvb->i2c_adap.dev.parent = &pdev->dev;
- dm1105dvb->i2c_adap.algo = &dm1105_algo;
- dm1105dvb->i2c_adap.algo_data = dm1105dvb;
- ret = i2c_add_adapter(&dm1105dvb->i2c_adap);
+ i2c_set_adapdata(&dev->i2c_adap, dev);
+ strcpy(dev->i2c_adap.name, DRIVER_NAME);
+ dev->i2c_adap.owner = THIS_MODULE;
+ dev->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
+ dev->i2c_adap.dev.parent = &pdev->dev;
+ dev->i2c_adap.algo = &dm1105_algo;
+ dev->i2c_adap.algo_data = dev;
+ ret = i2c_add_adapter(&dev->i2c_adap);
if (ret < 0)
- goto err_dm1105dvb_hw_exit;
+ goto err_dm1105_hw_exit;
/* dvb */
- ret = dvb_register_adapter(&dm1105dvb->dvb_adapter, DRIVER_NAME,
+ ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME,
THIS_MODULE, &pdev->dev, adapter_nr);
if (ret < 0)
goto err_i2c_del_adapter;
- dvb_adapter = &dm1105dvb->dvb_adapter;
+ dvb_adapter = &dev->dvb_adapter;
- dm1105dvb_read_mac(dm1105dvb, dvb_adapter->proposed_mac);
+ dm1105_read_mac(dev, dvb_adapter->proposed_mac);
- dvbdemux = &dm1105dvb->demux;
+ dvbdemux = &dev->demux;
dvbdemux->filternum = 256;
dvbdemux->feednum = 256;
- dvbdemux->start_feed = dm1105dvb_start_feed;
- dvbdemux->stop_feed = dm1105dvb_stop_feed;
+ dvbdemux->start_feed = dm1105_start_feed;
+ dvbdemux->stop_feed = dm1105_stop_feed;
dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
ret = dvb_dmx_init(dvbdemux);
@@ -870,113 +895,113 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
goto err_dvb_unregister_adapter;
dmx = &dvbdemux->dmx;
- dm1105dvb->dmxdev.filternum = 256;
- dm1105dvb->dmxdev.demux = dmx;
- dm1105dvb->dmxdev.capabilities = 0;
+ dev->dmxdev.filternum = 256;
+ dev->dmxdev.demux = dmx;
+ dev->dmxdev.capabilities = 0;
- ret = dvb_dmxdev_init(&dm1105dvb->dmxdev, dvb_adapter);
+ ret = dvb_dmxdev_init(&dev->dmxdev, dvb_adapter);
if (ret < 0)
goto err_dvb_dmx_release;
- dm1105dvb->hw_frontend.source = DMX_FRONTEND_0;
+ dev->hw_frontend.source = DMX_FRONTEND_0;
- ret = dmx->add_frontend(dmx, &dm1105dvb->hw_frontend);
+ ret = dmx->add_frontend(dmx, &dev->hw_frontend);
if (ret < 0)
goto err_dvb_dmxdev_release;
- dm1105dvb->mem_frontend.source = DMX_MEMORY_FE;
+ dev->mem_frontend.source = DMX_MEMORY_FE;
- ret = dmx->add_frontend(dmx, &dm1105dvb->mem_frontend);
+ ret = dmx->add_frontend(dmx, &dev->mem_frontend);
if (ret < 0)
goto err_remove_hw_frontend;
- ret = dmx->connect_frontend(dmx, &dm1105dvb->hw_frontend);
+ ret = dmx->connect_frontend(dmx, &dev->hw_frontend);
if (ret < 0)
goto err_remove_mem_frontend;
- ret = frontend_init(dm1105dvb);
+ ret = frontend_init(dev);
if (ret < 0)
goto err_disconnect_frontend;
- dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx);
- dm1105_ir_init(dm1105dvb);
+ dvb_net_init(dvb_adapter, &dev->dvbnet, dmx);
+ dm1105_ir_init(dev);
- INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);
- sprintf(dm1105dvb->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
- dm1105dvb->wq = create_singlethread_workqueue(dm1105dvb->wqn);
- if (!dm1105dvb->wq)
+ INIT_WORK(&dev->work, dm1105_dmx_buffer);
+ sprintf(dev->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
+ dev->wq = create_singlethread_workqueue(dev->wqn);
+ if (!dev->wq)
goto err_dvb_net;
- ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED,
- DRIVER_NAME, dm1105dvb);
+ ret = request_irq(pdev->irq, dm1105_irq, IRQF_SHARED,
+ DRIVER_NAME, dev);
if (ret < 0)
goto err_workqueue;
return 0;
err_workqueue:
- destroy_workqueue(dm1105dvb->wq);
+ destroy_workqueue(dev->wq);
err_dvb_net:
- dvb_net_release(&dm1105dvb->dvbnet);
+ dvb_net_release(&dev->dvbnet);
err_disconnect_frontend:
dmx->disconnect_frontend(dmx);
err_remove_mem_frontend:
- dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
+ dmx->remove_frontend(dmx, &dev->mem_frontend);
err_remove_hw_frontend:
- dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
+ dmx->remove_frontend(dmx, &dev->hw_frontend);
err_dvb_dmxdev_release:
- dvb_dmxdev_release(&dm1105dvb->dmxdev);
+ dvb_dmxdev_release(&dev->dmxdev);
err_dvb_dmx_release:
dvb_dmx_release(dvbdemux);
err_dvb_unregister_adapter:
dvb_unregister_adapter(dvb_adapter);
err_i2c_del_adapter:
- i2c_del_adapter(&dm1105dvb->i2c_adap);
-err_dm1105dvb_hw_exit:
- dm1105dvb_hw_exit(dm1105dvb);
+ i2c_del_adapter(&dev->i2c_adap);
+err_dm1105_hw_exit:
+ dm1105_hw_exit(dev);
err_pci_iounmap:
- pci_iounmap(pdev, dm1105dvb->io_mem);
+ pci_iounmap(pdev, dev->io_mem);
err_pci_release_regions:
pci_release_regions(pdev);
err_pci_disable_device:
pci_disable_device(pdev);
err_kfree:
pci_set_drvdata(pdev, NULL);
- kfree(dm1105dvb);
+ kfree(dev);
return ret;
}
static void __devexit dm1105_remove(struct pci_dev *pdev)
{
- struct dm1105dvb *dm1105dvb = pci_get_drvdata(pdev);
- struct dvb_adapter *dvb_adapter = &dm1105dvb->dvb_adapter;
- struct dvb_demux *dvbdemux = &dm1105dvb->demux;
+ struct dm1105_dev *dev = pci_get_drvdata(pdev);
+ struct dvb_adapter *dvb_adapter = &dev->dvb_adapter;
+ struct dvb_demux *dvbdemux = &dev->demux;
struct dmx_demux *dmx = &dvbdemux->dmx;
- dm1105_ir_exit(dm1105dvb);
+ dm1105_ir_exit(dev);
dmx->close(dmx);
- dvb_net_release(&dm1105dvb->dvbnet);
- if (dm1105dvb->fe)
- dvb_unregister_frontend(dm1105dvb->fe);
+ dvb_net_release(&dev->dvbnet);
+ if (dev->fe)
+ dvb_unregister_frontend(dev->fe);
dmx->disconnect_frontend(dmx);
- dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
- dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
- dvb_dmxdev_release(&dm1105dvb->dmxdev);
+ dmx->remove_frontend(dmx, &dev->mem_frontend);
+ dmx->remove_frontend(dmx, &dev->hw_frontend);
+ dvb_dmxdev_release(&dev->dmxdev);
dvb_dmx_release(dvbdemux);
dvb_unregister_adapter(dvb_adapter);
- if (&dm1105dvb->i2c_adap)
- i2c_del_adapter(&dm1105dvb->i2c_adap);
+ if (&dev->i2c_adap)
+ i2c_del_adapter(&dev->i2c_adap);
- dm1105dvb_hw_exit(dm1105dvb);
+ dm1105_hw_exit(dev);
synchronize_irq(pdev->irq);
- free_irq(pdev->irq, dm1105dvb);
- pci_iounmap(pdev, dm1105dvb->io_mem);
+ free_irq(pdev->irq, dev);
+ pci_iounmap(pdev, dev->io_mem);
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
dm1105_devcount--;
- kfree(dm1105dvb);
+ kfree(dev);
}
static struct pci_device_id dm1105_id_table[] __devinitdata = {
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index c37790ad92d0..9ddc57909d49 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -761,7 +761,6 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
- INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
init_timer(&dmxdevfilter->timer);
dvbdev->users++;
@@ -887,6 +886,7 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
dmxdevfilter->type = DMXDEV_TYPE_PES;
memcpy(&dmxdevfilter->params, params,
sizeof(struct dmx_pes_filter_params));
+ INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index b78cfb7d1897..67f189b7aa1f 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -426,16 +426,7 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
};
};
- if (dvb_demux_tscheck) {
- if (!demux->cnt_storage)
- demux->cnt_storage = vmalloc(MAX_PID + 1);
-
- if (!demux->cnt_storage) {
- printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
- dvb_demux_tscheck = 0;
- goto no_dvb_demux_tscheck;
- }
-
+ if (demux->cnt_storage) {
/* check pkt counter */
if (pid < MAX_PID) {
if (buf[1] & 0x80)
@@ -454,7 +445,6 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
};
/* end check */
};
-no_dvb_demux_tscheck:
list_for_each_entry(feed, &demux->feed_list, list_head) {
if ((feed->pid != pid) && (feed->pid != 0x2000))
@@ -1246,6 +1236,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed));
if (!dvbdemux->feed) {
vfree(dvbdemux->filter);
+ dvbdemux->filter = NULL;
return -ENOMEM;
}
for (i = 0; i < dvbdemux->filternum; i++) {
@@ -1257,6 +1248,13 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
dvbdemux->feed[i].index = i;
}
+ if (dvb_demux_tscheck) {
+ dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
+
+ if (!dvbdemux->cnt_storage)
+ printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
+ }
+
INIT_LIST_HEAD(&dvbdemux->frontend_list);
for (i = 0; i < DMX_TS_PES_OTHER; i++) {
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 07461222a7f5..55ea260572bf 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -1199,8 +1199,6 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
{
int r = 0;
- dtv_property_dump(tvp);
-
/* Allow the frontend to validate incoming properties */
if (fe->ops.get_property)
r = fe->ops.get_property(fe, tvp);
@@ -1323,6 +1321,8 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
r = -1;
}
+ dtv_property_dump(tvp);
+
return r;
}
@@ -1488,7 +1488,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
struct dvb_frontend_private *fepriv = fe->frontend_priv;
int err = -EOPNOTSUPP;
- dprintk ("%s\n", __func__);
+ dprintk("%s (%d)\n", __func__, _IOC_NR(cmd));
if (fepriv->exit)
return -ENODEV;
@@ -1536,8 +1536,7 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL;
- tvp = (struct dtv_property *) kmalloc(tvps->num *
- sizeof(struct dtv_property), GFP_KERNEL);
+ tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
if (!tvp) {
err = -ENOMEM;
goto out;
@@ -1569,8 +1568,7 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL;
- tvp = (struct dtv_property *) kmalloc(tvps->num *
- sizeof(struct dtv_property), GFP_KERNEL);
+ tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
if (!tvp) {
err = -ENOMEM;
goto out;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 52e4ce4304ee..80dda308ff74 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -214,14 +214,14 @@ struct dvb_tuner_ops {
int (*get_status)(struct dvb_frontend *fe, u32 *status);
int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
- /** These are provided seperately from set_params in order to facilitate silicon
- * tuners which require sophisticated tuning loops, controlling each parameter seperately. */
+ /** These are provided separately from set_params in order to facilitate silicon
+ * tuners which require sophisticated tuning loops, controlling each parameter separately. */
int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
/*
- * These are provided seperately from set_params in order to facilitate silicon
- * tuners which require sophisticated tuning loops, controlling each parameter seperately.
+ * These are provided separately from set_params in order to facilitate silicon
+ * tuners which require sophisticated tuning loops, controlling each parameter separately.
*/
int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 8b8558fcb042..441c0642b30a 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -504,6 +504,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
"bytes left in TS. Resyncing.\n", ts_remain);
priv->ule_sndu_len = 0;
priv->need_pusi = 1;
+ ts += TS_SZ;
continue;
}
@@ -949,11 +950,8 @@ static int dvb_net_filter_sec_set(struct net_device *dev,
(*secfilter)->filter_mask[10] = mac_mask[1];
(*secfilter)->filter_mask[11]=mac_mask[0];
- dprintk("%s: filter mac=%02x %02x %02x %02x %02x %02x\n",
- dev->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- dprintk("%s: filter mask=%02x %02x %02x %02x %02x %02x\n",
- dev->name, mac_mask[0], mac_mask[1], mac_mask[2],
- mac_mask[3], mac_mask[4], mac_mask[5]);
+ dprintk("%s: filter mac=%pM\n", dev->name, mac);
+ dprintk("%s: filter mask=%pM\n", dev->name, mac_mask);
return 0;
}
@@ -1141,18 +1139,18 @@ static void wq_set_multicast_list (struct work_struct *work)
} else if ((dev->flags & IFF_ALLMULTI)) {
dprintk("%s: allmulti mode\n", dev->name);
priv->rx_mode = RX_MODE_ALL_MULTI;
- } else if (dev->mc_count) {
+ } else if (!netdev_mc_empty(dev)) {
int mci;
struct dev_mc_list *mc;
dprintk("%s: set_mc_list, %d entries\n",
- dev->name, dev->mc_count);
+ dev->name, netdev_mc_count(dev));
priv->rx_mode = RX_MODE_MULTI;
priv->multi_num = 0;
for (mci = 0, mc=dev->mc_list;
- mci < dev->mc_count;
+ mci < netdev_mc_count(dev);
mc = mc->next, mci++) {
dvb_set_mc_filter(dev, mc);
}
@@ -1239,7 +1237,6 @@ static void dvb_net_setup(struct net_device *dev)
dev->header_ops = &dvb_header_ops;
dev->netdev_ops = &dvb_netdev_ops;
dev->mtu = 4096;
- dev->mc_count = 0;
dev->flags |= IFF_NOARP;
}
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
index 584bbd194dc8..a5712cd7c65f 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -89,6 +89,7 @@ void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
rbuf->pread = rbuf->pwrite;
rbuf->error = 0;
}
+EXPORT_SYMBOL(dvb_ringbuffer_flush);
void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
{
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 1b249897c9fb..e5f91f16ffa4 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -112,11 +112,13 @@ config DVB_USB_CXUSB
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select DVB_DIB7000P if !DVB_FE_CUSTOMISE
- select DVB_LGS8GL5 if !DVB_FE_CUSTOMISE
select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
+ select DVB_ATBM8830 if !DVB_FE_CUSTOMISE
+ select DVB_LGS8GXX if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_MAX2165 if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the Conexant USB2.0 hybrid reference design.
Currently, only DVB and ATSC modes are supported, analog mode
@@ -334,3 +336,11 @@ config DVB_USB_EC168
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
+
+config DVB_USB_AZ6027
+ tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support"
+ depends on DVB_USB
+ select DVB_STB0899 if !DVB_FE_CUSTOMISE
+ select DVB_STB6100 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the AZ6027 device
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 72c92cb69a22..1a192453b0e7 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -85,6 +85,9 @@ obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
dvb-usb-ec168-objs = ec168.o
obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
+dvb-usb-az6027-objs = az6027.o
+obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
+
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
# due to tuner-xc3028
EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 8b60a601fb82..d7975383d31b 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -21,6 +21,8 @@
*
*/
+#include <linux/hash.h>
+
#include "af9015.h"
#include "af9013.h"
#include "mt2060.h"
@@ -553,26 +555,45 @@ exit:
return ret;
}
-/* dump eeprom */
-static int af9015_eeprom_dump(struct dvb_usb_device *d)
+/* hash (and dump) eeprom */
+static int af9015_eeprom_hash(struct usb_device *udev)
{
- u8 reg, val;
+ static const unsigned int eeprom_size = 256;
+ unsigned int reg;
+ int ret;
+ u8 val, *eeprom;
+ struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
- for (reg = 0; ; reg++) {
- if (reg % 16 == 0) {
- if (reg)
- deb_info(KERN_CONT "\n");
- deb_info(KERN_DEBUG "%02x:", reg);
- }
- if (af9015_read_reg_i2c(d, AF9015_I2C_EEPROM, reg, &val) == 0)
- deb_info(KERN_CONT " %02x", val);
- else
- deb_info(KERN_CONT " --");
- if (reg == 0xff)
- break;
+ eeprom = kmalloc(eeprom_size, GFP_KERNEL);
+ if (eeprom == NULL)
+ return -ENOMEM;
+
+ for (reg = 0; reg < eeprom_size; reg++) {
+ req.addr = reg;
+ ret = af9015_rw_udev(udev, &req);
+ if (ret)
+ goto free;
+ eeprom[reg] = val;
}
- deb_info(KERN_CONT "\n");
- return 0;
+
+ if (dvb_usb_af9015_debug & 0x01)
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom,
+ eeprom_size);
+
+ BUG_ON(eeprom_size % 4);
+
+ af9015_config.eeprom_sum = 0;
+ for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) {
+ af9015_config.eeprom_sum *= GOLDEN_RATIO_PRIME_32;
+ af9015_config.eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]);
+ }
+
+ deb_info("%s: eeprom sum=%.8x\n", __func__, af9015_config.eeprom_sum);
+
+ ret = 0;
+free:
+ kfree(eeprom);
+ return ret;
}
static int af9015_download_ir_table(struct dvb_usb_device *d)
@@ -711,12 +732,132 @@ error:
return ret;
}
+struct af9015_setup {
+ unsigned int id;
+ struct dvb_usb_rc_key *rc_key_map;
+ unsigned int rc_key_map_size;
+ u8 *ir_table;
+ unsigned int ir_table_size;
+};
+
+static const struct af9015_setup *af9015_setup_match(unsigned int id,
+ const struct af9015_setup *table)
+{
+ for (; table->rc_key_map; table++)
+ if (table->id == id)
+ return table;
+ return NULL;
+}
+
+static const struct af9015_setup af9015_setup_modparam[] = {
+ { AF9015_REMOTE_A_LINK_DTU_M,
+ af9015_rc_keys_a_link, ARRAY_SIZE(af9015_rc_keys_a_link),
+ af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
+ { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+ af9015_rc_keys_msi, ARRAY_SIZE(af9015_rc_keys_msi),
+ af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
+ { AF9015_REMOTE_MYGICTV_U718,
+ af9015_rc_keys_mygictv, ARRAY_SIZE(af9015_rc_keys_mygictv),
+ af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
+ { AF9015_REMOTE_DIGITTRADE_DVB_T,
+ af9015_rc_keys_digittrade, ARRAY_SIZE(af9015_rc_keys_digittrade),
+ af9015_ir_table_digittrade, ARRAY_SIZE(af9015_ir_table_digittrade) },
+ { AF9015_REMOTE_AVERMEDIA_KS,
+ af9015_rc_keys_avermedia, ARRAY_SIZE(af9015_rc_keys_avermedia),
+ af9015_ir_table_avermedia_ks, ARRAY_SIZE(af9015_ir_table_avermedia_ks) },
+ { }
+};
+
+/* don't add new entries here anymore, use hashes instead */
+static const struct af9015_setup af9015_setup_usbids[] = {
+ { USB_VID_LEADTEK,
+ af9015_rc_keys_leadtek, ARRAY_SIZE(af9015_rc_keys_leadtek),
+ af9015_ir_table_leadtek, ARRAY_SIZE(af9015_ir_table_leadtek) },
+ { USB_VID_VISIONPLUS,
+ af9015_rc_keys_twinhan, ARRAY_SIZE(af9015_rc_keys_twinhan),
+ af9015_ir_table_twinhan, ARRAY_SIZE(af9015_ir_table_twinhan) },
+ { USB_VID_KWORLD_2, /* TODO: use correct rc keys */
+ af9015_rc_keys_twinhan, ARRAY_SIZE(af9015_rc_keys_twinhan),
+ af9015_ir_table_kworld, ARRAY_SIZE(af9015_ir_table_kworld) },
+ { USB_VID_AVERMEDIA,
+ af9015_rc_keys_avermedia, ARRAY_SIZE(af9015_rc_keys_avermedia),
+ af9015_ir_table_avermedia, ARRAY_SIZE(af9015_ir_table_avermedia) },
+ { USB_VID_MSI_2,
+ af9015_rc_keys_msi_digivox_iii, ARRAY_SIZE(af9015_rc_keys_msi_digivox_iii),
+ af9015_ir_table_msi_digivox_iii, ARRAY_SIZE(af9015_ir_table_msi_digivox_iii) },
+ { }
+};
+
+static const struct af9015_setup af9015_setup_hashes[] = {
+ { 0xb8feb708,
+ af9015_rc_keys_msi, ARRAY_SIZE(af9015_rc_keys_msi),
+ af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
+ { 0xa3703d00,
+ af9015_rc_keys_a_link, ARRAY_SIZE(af9015_rc_keys_a_link),
+ af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
+ { 0x9b7dc64e,
+ af9015_rc_keys_mygictv, ARRAY_SIZE(af9015_rc_keys_mygictv),
+ af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
+ { }
+};
+
+static void af9015_set_remote_config(struct usb_device *udev,
+ struct dvb_usb_device_properties *props)
+{
+ const struct af9015_setup *table = NULL;
+
+ if (dvb_usb_af9015_remote) {
+ /* load remote defined as module param */
+ table = af9015_setup_match(dvb_usb_af9015_remote,
+ af9015_setup_modparam);
+ } else {
+ u16 vendor = le16_to_cpu(udev->descriptor.idVendor);
+
+ table = af9015_setup_match(af9015_config.eeprom_sum,
+ af9015_setup_hashes);
+
+ if (!table && vendor == USB_VID_AFATECH) {
+ /* Check USB manufacturer and product strings and try
+ to determine correct remote in case of chip vendor
+ reference IDs are used.
+ DO NOT ADD ANYTHING NEW HERE. Use hashes instead.
+ */
+ char manufacturer[10];
+ memset(manufacturer, 0, sizeof(manufacturer));
+ usb_string(udev, udev->descriptor.iManufacturer,
+ manufacturer, sizeof(manufacturer));
+ if (!strcmp("MSI", manufacturer)) {
+ /* iManufacturer 1 MSI
+ iProduct 2 MSI K-VOX */
+ table = af9015_setup_match(
+ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+ af9015_setup_modparam);
+ } else if (udev->descriptor.idProduct ==
+ cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
+ table = &(const struct af9015_setup){ 0,
+ af9015_rc_keys_trekstor,
+ ARRAY_SIZE(af9015_rc_keys_trekstor),
+ af9015_ir_table_trekstor,
+ ARRAY_SIZE(af9015_ir_table_trekstor)
+ };
+ }
+ } else if (!table)
+ table = af9015_setup_match(vendor, af9015_setup_usbids);
+ }
+
+ if (table) {
+ props->rc_key_map = table->rc_key_map;
+ props->rc_key_map_size = table->rc_key_map_size;
+ af9015_config.ir_table = table->ir_table;
+ af9015_config.ir_table_size = table->ir_table_size;
+ }
+}
+
static int af9015_read_config(struct usb_device *udev)
{
int ret;
u8 val, i, offset = 0;
struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
- char manufacturer[10];
/* IR remote controller */
req.addr = AF9015_EEPROM_IR_MODE;
@@ -728,158 +869,18 @@ static int af9015_read_config(struct usb_device *udev)
}
if (ret)
goto error;
+
+ ret = af9015_eeprom_hash(udev);
+ if (ret)
+ goto error;
+
deb_info("%s: IR mode:%d\n", __func__, val);
for (i = 0; i < af9015_properties_count; i++) {
if (val == AF9015_IR_MODE_DISABLED) {
af9015_properties[i].rc_key_map = NULL;
af9015_properties[i].rc_key_map_size = 0;
- } else if (dvb_usb_af9015_remote) {
- /* load remote defined as module param */
- switch (dvb_usb_af9015_remote) {
- case AF9015_REMOTE_A_LINK_DTU_M:
- af9015_properties[i].rc_key_map =
- af9015_rc_keys_a_link;
- af9015_properties[i].rc_key_map_size =
- ARRAY_SIZE(af9015_rc_keys_a_link);
- af9015_config.ir_table = af9015_ir_table_a_link;
- af9015_config.ir_table_size =
- ARRAY_SIZE(af9015_ir_table_a_link);
- break;
- case AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3:
- af9015_properties[i].rc_key_map =
- af9015_rc_keys_msi;
- af9015_properties[i].rc_key_map_size =
- ARRAY_SIZE(af9015_rc_keys_msi);
- af9015_config.ir_table = af9015_ir_table_msi;
- af9015_config.ir_table_size =
- ARRAY_SIZE(af9015_ir_table_msi);
- break;
- case AF9015_REMOTE_MYGICTV_U718:
- af9015_properties[i].rc_key_map =
- af9015_rc_keys_mygictv;
- af9015_properties[i].rc_key_map_size =
- ARRAY_SIZE(af9015_rc_keys_mygictv);
- af9015_config.ir_table =
- af9015_ir_table_mygictv;
- af9015_config.ir_table_size =
- ARRAY_SIZE(af9015_ir_table_mygictv);
- break;
- case AF9015_REMOTE_DIGITTRADE_DVB_T:
- af9015_properties[i].rc_key_map =
- af9015_rc_keys_digittrade;
- af9015_properties[i].rc_key_map_size =
- ARRAY_SIZE(af9015_rc_keys_digittrade);
- af9015_config.ir_table =
- af9015_ir_table_digittrade;
- af9015_config.ir_table_size =
- ARRAY_SIZE(af9015_ir_table_digittrade);
- break;
- case AF9015_REMOTE_AVERMEDIA_KS:
- af9015_properties[i].rc_key_map =
- af9015_rc_keys_avermedia;
- af9015_properties[i].rc_key_map_size =
- ARRAY_SIZE(af9015_rc_keys_avermedia);
- af9015_config.ir_table =
- af9015_ir_table_avermedia_ks;
- af9015_config.ir_table_size =
- ARRAY_SIZE(af9015_ir_table_avermedia_ks);
- break;
- }
- } else {
- switch (le16_to_cpu(udev->descriptor.idVendor)) {
- case USB_VID_LEADTEK:
- af9015_properties[i].rc_key_map =
- af9015_rc_keys_leadtek;
- af9015_properties[i].rc_key_map_size =
- ARRAY_SIZE(af9015_rc_keys_leadtek);
- af9015_config.ir_table =
- af9015_ir_table_leadtek;
- af9015_config.ir_table_size =
- ARRAY_SIZE(af9015_ir_table_leadtek);
- break;
- case USB_VID_VISIONPLUS:
- af9015_properties[i].rc_key_map =
- af9015_rc_keys_twinhan;
- af9015_properties[i].rc_key_map_size =
- ARRAY_SIZE(af9015_rc_keys_twinhan);
- af9015_config.ir_table =
- af9015_ir_table_twinhan;
- af9015_config.ir_table_size =
- ARRAY_SIZE(af9015_ir_table_twinhan);
- break;
- case USB_VID_KWORLD_2:
- /* TODO: use correct rc keys */
- af9015_properties[i].rc_key_map =
- af9015_rc_keys_twinhan;
- af9015_properties[i].rc_key_map_size =
- ARRAY_SIZE(af9015_rc_keys_twinhan);
- af9015_config.ir_table = af9015_ir_table_kworld;
- af9015_config.ir_table_size =
- ARRAY_SIZE(af9015_ir_table_kworld);
- break;
- /* Check USB manufacturer and product strings and try
- to determine correct remote in case of chip vendor
- reference IDs are used. */
- case USB_VID_AFATECH:
- memset(manufacturer, 0, sizeof(manufacturer));
- usb_string(udev, udev->descriptor.iManufacturer,
- manufacturer, sizeof(manufacturer));
- if (!strcmp("Geniatech", manufacturer)) {
- /* iManufacturer 1 Geniatech
- iProduct 2 AF9015 */
- af9015_properties[i].rc_key_map =
- af9015_rc_keys_mygictv;
- af9015_properties[i].rc_key_map_size =
- ARRAY_SIZE(af9015_rc_keys_mygictv);
- af9015_config.ir_table =
- af9015_ir_table_mygictv;
- af9015_config.ir_table_size =
- ARRAY_SIZE(af9015_ir_table_mygictv);
- } else if (!strcmp("MSI", manufacturer)) {
- /* iManufacturer 1 MSI
- iProduct 2 MSI K-VOX */
- af9015_properties[i].rc_key_map =
- af9015_rc_keys_msi;
- af9015_properties[i].rc_key_map_size =
- ARRAY_SIZE(af9015_rc_keys_msi);
- af9015_config.ir_table =
- af9015_ir_table_msi;
- af9015_config.ir_table_size =
- ARRAY_SIZE(af9015_ir_table_msi);
- } else if (udev->descriptor.idProduct ==
- cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
- af9015_properties[i].rc_key_map =
- af9015_rc_keys_trekstor;
- af9015_properties[i].rc_key_map_size =
- ARRAY_SIZE(af9015_rc_keys_trekstor);
- af9015_config.ir_table =
- af9015_ir_table_trekstor;
- af9015_config.ir_table_size =
- ARRAY_SIZE(af9015_ir_table_trekstor);
- }
- break;
- case USB_VID_AVERMEDIA:
- af9015_properties[i].rc_key_map =
- af9015_rc_keys_avermedia;
- af9015_properties[i].rc_key_map_size =
- ARRAY_SIZE(af9015_rc_keys_avermedia);
- af9015_config.ir_table =
- af9015_ir_table_avermedia;
- af9015_config.ir_table_size =
- ARRAY_SIZE(af9015_ir_table_avermedia);
- break;
- case USB_VID_MSI_2:
- af9015_properties[i].rc_key_map =
- af9015_rc_keys_msi_digivox_iii;
- af9015_properties[i].rc_key_map_size =
- ARRAY_SIZE(af9015_rc_keys_msi_digivox_iii);
- af9015_config.ir_table =
- af9015_ir_table_msi_digivox_iii;
- af9015_config.ir_table_size =
- ARRAY_SIZE(af9015_ir_table_msi_digivox_iii);
- break;
- }
- }
+ } else
+ af9015_set_remote_config(udev, &af9015_properties[i]);
}
/* TS mode - one or two receivers */
@@ -1001,6 +1002,9 @@ static int af9015_read_config(struct usb_device *udev)
af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
af9015_af9013_config[i].rf_spec_inv = 1;
break;
+ case AF9013_TUNER_TDA18218:
+ warn("tuner NXP TDA18218 not supported yet");
+ return -ENODEV;
default:
warn("tuner id:%d not supported, please report!", val);
return -ENODEV;
@@ -1125,11 +1129,6 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
deb_info("%s: init I2C\n", __func__);
ret = af9015_i2c_init(adap->dev);
-
- /* dump eeprom (debug) */
- ret = af9015_eeprom_dump(adap->dev);
- if (ret)
- return ret;
} else {
/* select I2C adapter */
i2c_adap = &state->i2c_adap;
@@ -1295,6 +1294,8 @@ static struct usb_device_id af9015_usb_table[] = {
/* 25 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)},
+ {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)},
+ {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)},
{0},
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1381,7 +1382,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
},
{
.name = "DigitalNow TinyTwin DVB-T Receiver",
- .cold_ids = {&af9015_usb_table[5], NULL},
+ .cold_ids = {&af9015_usb_table[5],
+ &af9015_usb_table[28], NULL},
.warm_ids = {NULL},
},
{
@@ -1566,7 +1568,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.i2c_algo = &af9015_i2c_algo,
- .num_device_descs = 6, /* max 9 */
+ .num_device_descs = 7, /* max 9 */
.devices = {
{
.name = "AverMedia AVerTV Volar GPS 805 (A805)",
@@ -1600,6 +1602,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.cold_ids = {&af9015_usb_table[27], NULL},
.warm_ids = {NULL},
},
+ {
+ .name = "Leadtek WinFast DTV2000DS",
+ .cold_ids = {&af9015_usb_table[29], NULL},
+ .warm_ids = {NULL},
+ },
}
},
};
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
index 931c8515830d..ef36b1831490 100644
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ b/drivers/media/dvb/dvb-usb/af9015.h
@@ -107,6 +107,7 @@ struct af9015_config {
u16 mt2060_if1[2];
u16 firmware_size;
u16 firmware_checksum;
+ u32 eeprom_sum;
u8 *ir_table;
u16 ir_table_size;
};
diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c
new file mode 100644
index 000000000000..d7290b2c0913
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/az6027.c
@@ -0,0 +1,1151 @@
+/* DVB USB compliant Linux driver for the AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)
+ * receiver.
+ *
+ * Copyright (C) 2009 Adams.Xu <adams.xu@azwave.com.cn>
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "az6027.h"
+
+#include "stb0899_drv.h"
+#include "stb0899_reg.h"
+#include "stb0899_cfg.h"
+
+#include "stb6100.h"
+#include "stb6100_cfg.h"
+#include "dvb_ca_en50221.h"
+
+int dvb_usb_az6027_debug;
+module_param_named(debug, dvb_usb_az6027_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct az6027_device_state {
+ struct dvb_ca_en50221 ca;
+ struct mutex ca_mutex;
+ u8 power_state;
+};
+
+static const struct stb0899_s1_reg az6027_stb0899_s1_init_1[] = {
+
+ /* 0x0000000b, SYSREG */
+ { STB0899_DEV_ID , 0x30 },
+ { STB0899_DISCNTRL1 , 0x32 },
+ { STB0899_DISCNTRL2 , 0x80 },
+ { STB0899_DISRX_ST0 , 0x04 },
+ { STB0899_DISRX_ST1 , 0x00 },
+ { STB0899_DISPARITY , 0x00 },
+ { STB0899_DISFIFO , 0x00 },
+ { STB0899_DISSTATUS , 0x20 },
+ { STB0899_DISF22 , 0x99 },
+ { STB0899_DISF22RX , 0xa8 },
+ /* SYSREG ? */
+ { STB0899_ACRPRESC , 0x11 },
+ { STB0899_ACRDIV1 , 0x0a },
+ { STB0899_ACRDIV2 , 0x05 },
+ { STB0899_DACR1 , 0x00 },
+ { STB0899_DACR2 , 0x00 },
+ { STB0899_OUTCFG , 0x00 },
+ { STB0899_MODECFG , 0x00 },
+ { STB0899_IRQSTATUS_3 , 0xfe },
+ { STB0899_IRQSTATUS_2 , 0x03 },
+ { STB0899_IRQSTATUS_1 , 0x7c },
+ { STB0899_IRQSTATUS_0 , 0xf4 },
+ { STB0899_IRQMSK_3 , 0xf3 },
+ { STB0899_IRQMSK_2 , 0xfc },
+ { STB0899_IRQMSK_1 , 0xff },
+ { STB0899_IRQMSK_0 , 0xff },
+ { STB0899_IRQCFG , 0x00 },
+ { STB0899_I2CCFG , 0x88 },
+ { STB0899_I2CRPT , 0x58 },
+ { STB0899_IOPVALUE5 , 0x00 },
+ { STB0899_IOPVALUE4 , 0x33 },
+ { STB0899_IOPVALUE3 , 0x6d },
+ { STB0899_IOPVALUE2 , 0x90 },
+ { STB0899_IOPVALUE1 , 0x60 },
+ { STB0899_IOPVALUE0 , 0x00 },
+ { STB0899_GPIO00CFG , 0x82 },
+ { STB0899_GPIO01CFG , 0x82 },
+ { STB0899_GPIO02CFG , 0x82 },
+ { STB0899_GPIO03CFG , 0x82 },
+ { STB0899_GPIO04CFG , 0x82 },
+ { STB0899_GPIO05CFG , 0x82 },
+ { STB0899_GPIO06CFG , 0x82 },
+ { STB0899_GPIO07CFG , 0x82 },
+ { STB0899_GPIO08CFG , 0x82 },
+ { STB0899_GPIO09CFG , 0x82 },
+ { STB0899_GPIO10CFG , 0x82 },
+ { STB0899_GPIO11CFG , 0x82 },
+ { STB0899_GPIO12CFG , 0x82 },
+ { STB0899_GPIO13CFG , 0x82 },
+ { STB0899_GPIO14CFG , 0x82 },
+ { STB0899_GPIO15CFG , 0x82 },
+ { STB0899_GPIO16CFG , 0x82 },
+ { STB0899_GPIO17CFG , 0x82 },
+ { STB0899_GPIO18CFG , 0x82 },
+ { STB0899_GPIO19CFG , 0x82 },
+ { STB0899_GPIO20CFG , 0x82 },
+ { STB0899_SDATCFG , 0xb8 },
+ { STB0899_SCLTCFG , 0xba },
+ { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */
+ { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */
+ { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */
+ { STB0899_DIRCLKCFG , 0x82 },
+ { STB0899_CLKOUT27CFG , 0x7e },
+ { STB0899_STDBYCFG , 0x82 },
+ { STB0899_CS0CFG , 0x82 },
+ { STB0899_CS1CFG , 0x82 },
+ { STB0899_DISEQCOCFG , 0x20 },
+ { STB0899_GPIO32CFG , 0x82 },
+ { STB0899_GPIO33CFG , 0x82 },
+ { STB0899_GPIO34CFG , 0x82 },
+ { STB0899_GPIO35CFG , 0x82 },
+ { STB0899_GPIO36CFG , 0x82 },
+ { STB0899_GPIO37CFG , 0x82 },
+ { STB0899_GPIO38CFG , 0x82 },
+ { STB0899_GPIO39CFG , 0x82 },
+ { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
+ { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
+ { STB0899_FILTCTRL , 0x00 },
+ { STB0899_SYSCTRL , 0x01 },
+ { STB0899_STOPCLK1 , 0x20 },
+ { STB0899_STOPCLK2 , 0x00 },
+ { STB0899_INTBUFSTATUS , 0x00 },
+ { STB0899_INTBUFCTRL , 0x0a },
+ { 0xffff , 0xff },
+};
+
+static const struct stb0899_s1_reg az6027_stb0899_s1_init_3[] = {
+ { STB0899_DEMOD , 0x00 },
+ { STB0899_RCOMPC , 0xc9 },
+ { STB0899_AGC1CN , 0x01 },
+ { STB0899_AGC1REF , 0x10 },
+ { STB0899_RTC , 0x23 },
+ { STB0899_TMGCFG , 0x4e },
+ { STB0899_AGC2REF , 0x34 },
+ { STB0899_TLSR , 0x84 },
+ { STB0899_CFD , 0xf7 },
+ { STB0899_ACLC , 0x87 },
+ { STB0899_BCLC , 0x94 },
+ { STB0899_EQON , 0x41 },
+ { STB0899_LDT , 0xf1 },
+ { STB0899_LDT2 , 0xe3 },
+ { STB0899_EQUALREF , 0xb4 },
+ { STB0899_TMGRAMP , 0x10 },
+ { STB0899_TMGTHD , 0x30 },
+ { STB0899_IDCCOMP , 0xfd },
+ { STB0899_QDCCOMP , 0xff },
+ { STB0899_POWERI , 0x0c },
+ { STB0899_POWERQ , 0x0f },
+ { STB0899_RCOMP , 0x6c },
+ { STB0899_AGCIQIN , 0x80 },
+ { STB0899_AGC2I1 , 0x06 },
+ { STB0899_AGC2I2 , 0x00 },
+ { STB0899_TLIR , 0x30 },
+ { STB0899_RTF , 0x7f },
+ { STB0899_DSTATUS , 0x00 },
+ { STB0899_LDI , 0xbc },
+ { STB0899_CFRM , 0xea },
+ { STB0899_CFRL , 0x31 },
+ { STB0899_NIRM , 0x2b },
+ { STB0899_NIRL , 0x80 },
+ { STB0899_ISYMB , 0x1d },
+ { STB0899_QSYMB , 0xa6 },
+ { STB0899_SFRH , 0x2f },
+ { STB0899_SFRM , 0x68 },
+ { STB0899_SFRL , 0x40 },
+ { STB0899_SFRUPH , 0x2f },
+ { STB0899_SFRUPM , 0x68 },
+ { STB0899_SFRUPL , 0x40 },
+ { STB0899_EQUAI1 , 0x02 },
+ { STB0899_EQUAQ1 , 0xff },
+ { STB0899_EQUAI2 , 0x04 },
+ { STB0899_EQUAQ2 , 0x05 },
+ { STB0899_EQUAI3 , 0x02 },
+ { STB0899_EQUAQ3 , 0xfd },
+ { STB0899_EQUAI4 , 0x03 },
+ { STB0899_EQUAQ4 , 0x07 },
+ { STB0899_EQUAI5 , 0x08 },
+ { STB0899_EQUAQ5 , 0xf5 },
+ { STB0899_DSTATUS2 , 0x00 },
+ { STB0899_VSTATUS , 0x00 },
+ { STB0899_VERROR , 0x86 },
+ { STB0899_IQSWAP , 0x2a },
+ { STB0899_ECNT1M , 0x00 },
+ { STB0899_ECNT1L , 0x00 },
+ { STB0899_ECNT2M , 0x00 },
+ { STB0899_ECNT2L , 0x00 },
+ { STB0899_ECNT3M , 0x0a },
+ { STB0899_ECNT3L , 0xad },
+ { STB0899_FECAUTO1 , 0x06 },
+ { STB0899_FECM , 0x01 },
+ { STB0899_VTH12 , 0xb0 },
+ { STB0899_VTH23 , 0x7a },
+ { STB0899_VTH34 , 0x58 },
+ { STB0899_VTH56 , 0x38 },
+ { STB0899_VTH67 , 0x34 },
+ { STB0899_VTH78 , 0x24 },
+ { STB0899_PRVIT , 0xff },
+ { STB0899_VITSYNC , 0x19 },
+ { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+ { STB0899_TSULC , 0x42 },
+ { STB0899_RSLLC , 0x41 },
+ { STB0899_TSLPL , 0x12 },
+ { STB0899_TSCFGH , 0x0c },
+ { STB0899_TSCFGM , 0x00 },
+ { STB0899_TSCFGL , 0x00 },
+ { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */
+ { STB0899_RSSYNCDEL , 0x00 },
+ { STB0899_TSINHDELH , 0x02 },
+ { STB0899_TSINHDELM , 0x00 },
+ { STB0899_TSINHDELL , 0x00 },
+ { STB0899_TSLLSTKM , 0x1b },
+ { STB0899_TSLLSTKL , 0xb3 },
+ { STB0899_TSULSTKM , 0x00 },
+ { STB0899_TSULSTKL , 0x00 },
+ { STB0899_PCKLENUL , 0xbc },
+ { STB0899_PCKLENLL , 0xcc },
+ { STB0899_RSPCKLEN , 0xbd },
+ { STB0899_TSSTATUS , 0x90 },
+ { STB0899_ERRCTRL1 , 0xb6 },
+ { STB0899_ERRCTRL2 , 0x95 },
+ { STB0899_ERRCTRL3 , 0x8d },
+ { STB0899_DMONMSK1 , 0x27 },
+ { STB0899_DMONMSK0 , 0x03 },
+ { STB0899_DEMAPVIT , 0x5c },
+ { STB0899_PLPARM , 0x19 },
+ { STB0899_PDELCTRL , 0x48 },
+ { STB0899_PDELCTRL2 , 0x00 },
+ { STB0899_BBHCTRL1 , 0x00 },
+ { STB0899_BBHCTRL2 , 0x00 },
+ { STB0899_HYSTTHRESH , 0x77 },
+ { STB0899_MATCSTM , 0x00 },
+ { STB0899_MATCSTL , 0x00 },
+ { STB0899_UPLCSTM , 0x00 },
+ { STB0899_UPLCSTL , 0x00 },
+ { STB0899_DFLCSTM , 0x00 },
+ { STB0899_DFLCSTL , 0x00 },
+ { STB0899_SYNCCST , 0x00 },
+ { STB0899_SYNCDCSTM , 0x00 },
+ { STB0899_SYNCDCSTL , 0x00 },
+ { STB0899_ISI_ENTRY , 0x00 },
+ { STB0899_ISI_BIT_EN , 0x00 },
+ { STB0899_MATSTRM , 0xf0 },
+ { STB0899_MATSTRL , 0x02 },
+ { STB0899_UPLSTRM , 0x45 },
+ { STB0899_UPLSTRL , 0x60 },
+ { STB0899_DFLSTRM , 0xe3 },
+ { STB0899_DFLSTRL , 0x00 },
+ { STB0899_SYNCSTR , 0x47 },
+ { STB0899_SYNCDSTRM , 0x05 },
+ { STB0899_SYNCDSTRL , 0x18 },
+ { STB0899_CFGPDELSTATUS1 , 0x19 },
+ { STB0899_CFGPDELSTATUS2 , 0x2b },
+ { STB0899_BBFERRORM , 0x00 },
+ { STB0899_BBFERRORL , 0x01 },
+ { STB0899_UPKTERRORM , 0x00 },
+ { STB0899_UPKTERRORL , 0x00 },
+ { 0xffff , 0xff },
+};
+
+
+
+struct stb0899_config az6027_stb0899_config = {
+ .init_dev = az6027_stb0899_s1_init_1,
+ .init_s2_demod = stb0899_s2_init_2,
+ .init_s1_demod = az6027_stb0899_s1_init_3,
+ .init_s2_fec = stb0899_s2_init_4,
+ .init_tst = stb0899_s1_init_5,
+
+ .demod_address = 0xd0, /* 0x68, 0xd0 >> 1 */
+
+ .xtal_freq = 27000000,
+ .inversion = IQ_SWAP_ON, /* 1 */
+
+ .lo_clk = 76500000,
+ .hi_clk = 99000000,
+
+ .esno_ave = STB0899_DVBS2_ESNO_AVE,
+ .esno_quant = STB0899_DVBS2_ESNO_QUANT,
+ .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,
+ .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,
+ .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,
+ .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+ .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+ .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,
+ .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+ .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,
+ .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+ .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,
+ .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,
+
+ .tuner_get_frequency = stb6100_get_frequency,
+ .tuner_set_frequency = stb6100_set_frequency,
+ .tuner_set_bandwidth = stb6100_set_bandwidth,
+ .tuner_get_bandwidth = stb6100_get_bandwidth,
+ .tuner_set_rfsiggain = NULL,
+};
+
+struct stb6100_config az6027_stb6100_config = {
+ .tuner_address = 0xc0,
+ .refclock = 27000000,
+};
+
+
+/* check for mutex FIXME */
+int az6027_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+{
+ int ret = -1;
+ if (mutex_lock_interruptible(&d->usb_mutex))
+ return -EAGAIN;
+
+ ret = usb_control_msg(d->udev,
+ usb_rcvctrlpipe(d->udev, 0),
+ req,
+ USB_TYPE_VENDOR | USB_DIR_IN,
+ value,
+ index,
+ b,
+ blen,
+ 2000);
+
+ if (ret < 0) {
+ warn("usb in operation failed. (%d)", ret);
+ ret = -EIO;
+ } else
+ ret = 0;
+
+ deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index);
+ debug_dump(b, blen, deb_xfer);
+
+ mutex_unlock(&d->usb_mutex);
+ return ret;
+}
+
+static int az6027_usb_out_op(struct dvb_usb_device *d,
+ u8 req,
+ u16 value,
+ u16 index,
+ u8 *b,
+ int blen)
+{
+ int ret;
+
+ deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index);
+ debug_dump(b, blen, deb_xfer);
+
+ if (mutex_lock_interruptible(&d->usb_mutex))
+ return -EAGAIN;
+
+ ret = usb_control_msg(d->udev,
+ usb_sndctrlpipe(d->udev, 0),
+ req,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ value,
+ index,
+ b,
+ blen,
+ 2000);
+
+ if (ret != blen) {
+ warn("usb out operation failed. (%d)", ret);
+ mutex_unlock(&d->usb_mutex);
+ return -EIO;
+ } else{
+ mutex_unlock(&d->usb_mutex);
+ return 0;
+ }
+}
+
+static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+
+ deb_info("%s %d", __func__, onoff);
+
+ req = 0xBC;
+ value = onoff;
+ index = 0;
+ blen = 0;
+
+ ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+ if (ret != 0)
+ warn("usb out operation failed. (%d)", ret);
+
+ return ret;
+}
+
+/* keys for the enclosed remote control */
+static struct dvb_usb_rc_key az6027_rc_keys[] = {
+ { 0x01, KEY_1 },
+ { 0x02, KEY_2 },
+};
+
+/* remote control stuff (does not work with my box) */
+static int az6027_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ return 0;
+}
+
+/*
+int az6027_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 v = onoff;
+ return az6027_usb_out_op(d,0xBC,v,3,NULL,1);
+}
+*/
+
+static int az6027_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
+ int slot,
+ int address)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+ u8 b[12];
+
+ if (slot != 0)
+ return -EINVAL;
+
+ mutex_lock(&state->ca_mutex);
+
+ req = 0xC1;
+ value = address;
+ index = 0;
+ blen = 1;
+
+ ret = az6027_usb_in_op(d, req, value, index, b, blen);
+ if (ret < 0) {
+ warn("usb in operation failed. (%d)", ret);
+ ret = -EINVAL;
+ } else {
+ ret = b[0];
+ }
+
+ mutex_unlock(&state->ca_mutex);
+ return ret;
+}
+
+static int az6027_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
+ int slot,
+ int address,
+ u8 value)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+ int ret;
+ u8 req;
+ u16 value1;
+ u16 index;
+ int blen;
+
+ deb_info("%s %d", __func__, slot);
+ if (slot != 0)
+ return -EINVAL;
+
+ mutex_lock(&state->ca_mutex);
+ req = 0xC2;
+ value1 = address;
+ index = value;
+ blen = 0;
+
+ ret = az6027_usb_out_op(d, req, value1, index, NULL, blen);
+ if (ret != 0)
+ warn("usb out operation failed. (%d)", ret);
+
+ mutex_unlock(&state->ca_mutex);
+ return ret;
+}
+
+static int az6027_ci_read_cam_control(struct dvb_ca_en50221 *ca,
+ int slot,
+ u8 address)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+ u8 b[12];
+
+ if (slot != 0)
+ return -EINVAL;
+
+ mutex_lock(&state->ca_mutex);
+
+ req = 0xC3;
+ value = address;
+ index = 0;
+ blen = 2;
+
+ ret = az6027_usb_in_op(d, req, value, index, b, blen);
+ if (ret < 0) {
+ warn("usb in operation failed. (%d)", ret);
+ ret = -EINVAL;
+ } else {
+ if (b[0] == 0)
+ warn("Read CI IO error");
+
+ ret = b[1];
+ deb_info("read cam data = %x from 0x%x", b[1], value);
+ }
+
+ mutex_unlock(&state->ca_mutex);
+ return ret;
+}
+
+static int az6027_ci_write_cam_control(struct dvb_ca_en50221 *ca,
+ int slot,
+ u8 address,
+ u8 value)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+ int ret;
+ u8 req;
+ u16 value1;
+ u16 index;
+ int blen;
+
+ if (slot != 0)
+ return -EINVAL;
+
+ mutex_lock(&state->ca_mutex);
+ req = 0xC4;
+ value1 = address;
+ index = value;
+ blen = 0;
+
+ ret = az6027_usb_out_op(d, req, value1, index, NULL, blen);
+ if (ret != 0) {
+ warn("usb out operation failed. (%d)", ret);
+ goto failed;
+ }
+
+failed:
+ mutex_unlock(&state->ca_mutex);
+ return ret;
+}
+
+static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+ u8 b[12];
+
+ req = 0xC8;
+ value = 0;
+ index = 0;
+ blen = 1;
+
+ ret = az6027_usb_in_op(d, req, value, index, b, blen);
+ if (ret < 0) {
+ warn("usb in operation failed. (%d)", ret);
+ ret = -EIO;
+ } else{
+ ret = b[0];
+ }
+ return ret;
+}
+
+static int az6027_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+ int ret, i;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+
+ mutex_lock(&state->ca_mutex);
+
+ req = 0xC6;
+ value = 1;
+ index = 0;
+ blen = 0;
+
+ ret = az6027_usb_out_op(d, req, value, index, NULL, blen);
+ if (ret != 0) {
+ warn("usb out operation failed. (%d)", ret);
+ goto failed;
+ }
+
+ msleep(500);
+ req = 0xC6;
+ value = 0;
+ index = 0;
+ blen = 0;
+
+ ret = az6027_usb_out_op(d, req, value, index, NULL, blen);
+ if (ret != 0) {
+ warn("usb out operation failed. (%d)", ret);
+ goto failed;
+ }
+
+ for (i = 0; i < 15; i++) {
+ msleep(100);
+
+ if (CI_CamReady(ca, slot)) {
+ deb_info("CAM Ready");
+ break;
+ }
+ }
+ msleep(5000);
+
+failed:
+ mutex_unlock(&state->ca_mutex);
+ return ret;
+}
+
+static int az6027_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+ return 0;
+}
+
+static int az6027_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+
+ deb_info("%s", __func__);
+ mutex_lock(&state->ca_mutex);
+ req = 0xC7;
+ value = 1;
+ index = 0;
+ blen = 0;
+
+ ret = az6027_usb_out_op(d, req, value, index, NULL, blen);
+ if (ret != 0) {
+ warn("usb out operation failed. (%d)", ret);
+ goto failed;
+ }
+
+failed:
+ mutex_unlock(&state->ca_mutex);
+ return ret;
+}
+
+static int az6027_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+ struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+ u8 b[12];
+
+ mutex_lock(&state->ca_mutex);
+
+ req = 0xC5;
+ value = 0;
+ index = 0;
+ blen = 1;
+
+ ret = az6027_usb_in_op(d, req, value, index, b, blen);
+ if (ret < 0) {
+ warn("usb in operation failed. (%d)", ret);
+ ret = -EIO;
+ } else
+ ret = 0;
+
+ if (b[0] == 0) {
+ ret = 0;
+
+ } else if (b[0] == 1) {
+ ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
+ DVB_CA_EN50221_POLL_CAM_READY;
+ }
+
+ mutex_unlock(&state->ca_mutex);
+ return ret;
+}
+
+
+static void az6027_ci_uninit(struct dvb_usb_device *d)
+{
+ struct az6027_device_state *state;
+
+ deb_info("%s", __func__);
+
+ if (NULL == d)
+ return;
+
+ state = (struct az6027_device_state *)d->priv;
+ if (NULL == state)
+ return;
+
+ if (NULL == state->ca.data)
+ return;
+
+ dvb_ca_en50221_release(&state->ca);
+
+ memset(&state->ca, 0, sizeof(state->ca));
+}
+
+
+static int az6027_ci_init(struct dvb_usb_adapter *a)
+{
+ struct dvb_usb_device *d = a->dev;
+ struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+ int ret;
+
+ deb_info("%s", __func__);
+
+ mutex_init(&state->ca_mutex);
+
+ state->ca.owner = THIS_MODULE;
+ state->ca.read_attribute_mem = az6027_ci_read_attribute_mem;
+ state->ca.write_attribute_mem = az6027_ci_write_attribute_mem;
+ state->ca.read_cam_control = az6027_ci_read_cam_control;
+ state->ca.write_cam_control = az6027_ci_write_cam_control;
+ state->ca.slot_reset = az6027_ci_slot_reset;
+ state->ca.slot_shutdown = az6027_ci_slot_shutdown;
+ state->ca.slot_ts_enable = az6027_ci_slot_ts_enable;
+ state->ca.poll_slot_status = az6027_ci_poll_slot_status;
+ state->ca.data = d;
+
+ ret = dvb_ca_en50221_init(&a->dvb_adap,
+ &state->ca,
+ 0, /* flags */
+ 1);/* n_slots */
+ if (ret != 0) {
+ err("Cannot initialize CI: Error %d.", ret);
+ memset(&state->ca, 0, sizeof(state->ca));
+ return ret;
+ }
+
+ deb_info("CI initialized.");
+
+ return 0;
+}
+
+/*
+static int az6027_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])
+{
+ az6027_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6);
+ return 0;
+}
+*/
+
+static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+
+ u8 buf;
+ int ret;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+ struct i2c_msg i2c_msg = {
+ .addr = 0x99,
+ .flags = 0,
+ .buf = &buf,
+ .len = 1
+ };
+
+ /*
+ * 2 --18v
+ * 1 --13v
+ * 0 --off
+ */
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ buf = 1;
+ ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
+ break;
+
+ case SEC_VOLTAGE_18:
+ buf = 2;
+ ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
+ break;
+
+ case SEC_VOLTAGE_OFF:
+ buf = 0;
+ ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+static int az6027_frontend_poweron(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+
+ req = 0xBC;
+ value = 1; /* power on */
+ index = 3;
+ blen = 0;
+
+ ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+ if (ret != 0)
+ return -EIO;
+
+ return 0;
+}
+static int az6027_frontend_reset(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+
+ /* reset demodulator */
+ req = 0xC0;
+ value = 1; /* high */
+ index = 3;
+ blen = 0;
+
+ ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+ if (ret != 0)
+ return -EIO;
+
+ req = 0xC0;
+ value = 0; /* low */
+ index = 3;
+ blen = 0;
+ msleep_interruptible(200);
+
+ ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+ if (ret != 0)
+ return -EIO;
+
+ msleep_interruptible(200);
+
+ req = 0xC0;
+ value = 1; /*high */
+ index = 3;
+ blen = 0;
+
+ ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+ if (ret != 0)
+ return -EIO;
+
+ msleep_interruptible(200);
+ return 0;
+}
+
+static int az6027_frontend_tsbypass(struct dvb_usb_adapter *adap, int onoff)
+{
+ int ret;
+ u8 req;
+ u16 value;
+ u16 index;
+ int blen;
+
+ /* TS passthrough */
+ req = 0xC7;
+ value = onoff;
+ index = 0;
+ blen = 0;
+
+ ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+ if (ret != 0)
+ return -EIO;
+
+ return 0;
+}
+
+static int az6027_frontend_attach(struct dvb_usb_adapter *adap)
+{
+
+ az6027_frontend_poweron(adap);
+ az6027_frontend_reset(adap);
+
+ deb_info("adap = %p, dev = %p\n", adap, adap->dev);
+ adap->fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap);
+
+ if (adap->fe) {
+ deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address);
+ if (stb6100_attach(adap->fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) {
+ deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address);
+ adap->fe->ops.set_voltage = az6027_set_voltage;
+ az6027_ci_init(adap);
+ } else {
+ adap->fe = NULL;
+ }
+ } else
+ warn("no front-end attached\n");
+
+ az6027_frontend_tsbypass(adap, 0);
+
+ return 0;
+}
+
+static struct dvb_usb_device_properties az6027_properties;
+
+static void az6027_usb_disconnect(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ az6027_ci_uninit(d);
+ dvb_usb_device_exit(intf);
+}
+
+
+static int az6027_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf,
+ &az6027_properties,
+ THIS_MODULE,
+ NULL,
+ adapter_nr);
+}
+
+/* I2C */
+static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i = 0, j = 0, len = 0;
+ int ret;
+ u16 index;
+ u16 value;
+ int length;
+ u8 req;
+ u8 data[256];
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+ for (i = 0; i < num; i++) {
+
+ if (msg[i].addr == 0x99) {
+ req = 0xBE;
+ index = 0;
+ value = msg[i].buf[0] & 0x00ff;
+ length = 1;
+ az6027_usb_out_op(d, req, value, index, data, length);
+ }
+
+ if (msg[i].addr == 0xd0) {
+ /* write/read request */
+ if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
+ req = 0xB9;
+ index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
+ value = msg[i].addr + (msg[i].len << 8);
+ length = msg[i + 1].len + 6;
+ ret = az6027_usb_in_op(d, req, value, index, data, length);
+ len = msg[i + 1].len;
+ for (j = 0; j < len; j++)
+ msg[i + 1].buf[j] = data[j + 5];
+
+ i++;
+ } else {
+
+ if (msg[i].addr == 0xd0) {
+ /* demod 16bit addr */
+ req = 0xBD;
+ index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
+ value = msg[i].addr + (2 << 8);
+ length = msg[i].len - 2;
+ len = msg[i].len - 2;
+ for (j = 0; j < len; j++)
+ data[j] = msg[i].buf[j + 2];
+
+ }
+ az6027_usb_out_op(d, req, value, index, data, length);
+ }
+ }
+
+ if (msg[i].addr == 0xc0) {
+ if (msg[i].flags & I2C_M_RD) {
+
+ req = 0xB9;
+ index = 0x0;
+ value = msg[i].addr;
+ length = msg[i].len + 6;
+ ret = az6027_usb_in_op(d, req, value, index, data, length);
+ len = msg[i].len;
+ for (j = 0; j < len; j++)
+ msg[i].buf[j] = data[j + 5];
+
+ } else {
+
+ req = 0xBD;
+ index = msg[i].buf[0] & 0x00FF;
+ value = msg[i].addr + (1 << 8);
+ length = msg[i].len - 1;
+ len = msg[i].len - 1;
+
+ for (j = 0; j < len; j++)
+ data[j] = msg[i].buf[j + 1];
+
+ az6027_usb_out_op(d, req, value, index, data, length);
+ }
+ }
+ }
+ mutex_unlock(&d->i2c_mutex);
+
+ return i;
+}
+
+
+static u32 az6027_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm az6027_i2c_algo = {
+ .master_xfer = az6027_i2c_xfer,
+ .functionality = az6027_i2c_func,
+};
+
+int az6027_identify_state(struct usb_device *udev,
+ struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc,
+ int *cold)
+{
+ u8 b[16];
+ s16 ret = usb_control_msg(udev,
+ usb_rcvctrlpipe(udev, 0),
+ 0xb7,
+ USB_TYPE_VENDOR | USB_DIR_IN,
+ 6,
+ 0,
+ b,
+ 6,
+ USB_CTRL_GET_TIMEOUT);
+
+ *cold = ret <= 0;
+
+ deb_info("cold: %d\n", *cold);
+ return 0;
+}
+
+
+static struct usb_device_id az6027_usb_table[] = {
+ { USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_AZ6027) },
+ { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI) },
+ { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI) },
+ { },
+};
+
+MODULE_DEVICE_TABLE(usb, az6027_usb_table);
+
+static struct dvb_usb_device_properties az6027_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-az6027-03.fw",
+ .no_reconnect = 1,
+
+ .size_of_priv = sizeof(struct az6027_device_state),
+ .identify_state = az6027_identify_state,
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .streaming_ctrl = az6027_streaming_ctrl,
+ .frontend_attach = az6027_frontend_attach,
+
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 10,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+ }
+ },
+/*
+ .power_ctrl = az6027_power_ctrl,
+ .read_mac_address = az6027_read_mac_addr,
+ */
+ .rc_key_map = az6027_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(az6027_rc_keys),
+ .rc_interval = 400,
+ .rc_query = az6027_rc_query,
+ .i2c_algo = &az6027_i2c_algo,
+
+ .num_device_descs = 1,
+ .devices = {
+ {
+ .name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)",
+ .cold_ids = { &az6027_usb_table[0], NULL },
+ .warm_ids = { NULL },
+ },
+ { NULL },
+ }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver az6027_usb_driver = {
+ .name = "dvb_usb_az6027",
+ .probe = az6027_usb_probe,
+ .disconnect = az6027_usb_disconnect,
+ .id_table = az6027_usb_table,
+};
+
+/* module stuff */
+static int __init az6027_usb_module_init(void)
+{
+ int result;
+
+ result = usb_register(&az6027_usb_driver);
+ if (result) {
+ err("usb_register failed. (%d)", result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit az6027_usb_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&az6027_usb_driver);
+}
+
+module_init(az6027_usb_module_init);
+module_exit(az6027_usb_module_exit);
+
+MODULE_AUTHOR("Adams Xu <Adams.xu@azwave.com.cn>");
+MODULE_DESCRIPTION("Driver for AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/az6027.h b/drivers/media/dvb/dvb-usb/az6027.h
new file mode 100644
index 000000000000..f3afe17f3f3d
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/az6027.h
@@ -0,0 +1,14 @@
+#ifndef _DVB_USB_VP6027_H_
+#define _DVB_USB_VP6027_H_
+
+#define DVB_USB_LOG_PREFIX "az6027"
+#include "dvb-usb.h"
+
+
+extern int dvb_usb_az6027_debug;
+#define deb_info(args...) dprintk(dvb_usb_az6027_debug, 0x01, args)
+#define deb_xfer(args...) dprintk(dvb_usb_az6027_debug, 0x02, args)
+#define deb_rc(args...) dprintk(dvb_usb_az6027_debug, 0x04, args)
+#define deb_fe(args...) dprintk(dvb_usb_az6027_debug, 0x08, args)
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 05fb28e9c69e..a7b8405c291e 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -1184,6 +1184,9 @@ static struct atbm8830_config mygica_d689_atbm8830_cfg = {
.osc_clk_freq = 30400, /* in kHz */
.if_freq = 0, /* zero IF */
.zif_swap_iq = 1,
+ .agc_min = 0x2E,
+ .agc_max = 0x90,
+ .agc_hold_loop = 0,
};
static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index 495a90577c5f..83fc24a6c31a 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -42,7 +42,6 @@ struct dib0700_state {
u16 mt2060_if1[2];
u8 rc_toggle;
u8 rc_counter;
- u8 rc_func_version;
u8 is_dib7000pc;
u8 fw_use_new_i2c_api;
u8 disable_streaming_master_mode;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 0d3c9a9a33be..4f961d2d1817 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -471,14 +471,209 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
return dib0700_ctrl_wr(adap->dev, b, 4);
}
+/* Number of keypresses to ignore before start repeating */
+#define RC_REPEAT_DELAY_V1_20 10
+
+/* This is the structure of the RC response packet starting in firmware 1.20 */
+struct dib0700_rc_response {
+ u8 report_id;
+ u8 data_state;
+ u16 system;
+ u8 data;
+ u8 not_data;
+};
+#define RC_MSG_SIZE_V1_20 6
+
+static void dib0700_rc_urb_completion(struct urb *purb)
+{
+ struct dvb_usb_device *d = purb->context;
+ struct dvb_usb_rc_key *keymap;
+ struct dib0700_state *st;
+ struct dib0700_rc_response poll_reply;
+ u8 *buf;
+ int found = 0;
+ u32 event;
+ int state;
+ int i;
+
+ deb_info("%s()\n", __func__);
+ if (d == NULL)
+ return;
+
+ if (d->rc_input_dev == NULL) {
+ /* This will occur if disable_rc_polling=1 */
+ usb_free_urb(purb);
+ return;
+ }
+
+ keymap = d->props.rc_key_map;
+ st = d->priv;
+ buf = (u8 *)purb->transfer_buffer;
+
+ if (purb->status < 0) {
+ deb_info("discontinuing polling\n");
+ usb_free_urb(purb);
+ return;
+ }
+
+ if (purb->actual_length != RC_MSG_SIZE_V1_20) {
+ deb_info("malformed rc msg size=%d\n", purb->actual_length);
+ goto resubmit;
+ }
+
+ /* Set initial results in case we exit the function early */
+ event = 0;
+ state = REMOTE_NO_KEY_PRESSED;
+
+ deb_data("IR raw %02X %02X %02X %02X %02X %02X (len %d)\n", buf[0],
+ buf[1], buf[2], buf[3], buf[4], buf[5], purb->actual_length);
+
+ switch (dvb_usb_dib0700_ir_proto) {
+ case 0:
+ /* NEC Protocol */
+ poll_reply.report_id = 0;
+ poll_reply.data_state = 1;
+ poll_reply.system = buf[2];
+ poll_reply.data = buf[4];
+ poll_reply.not_data = buf[5];
+
+ /* NEC protocol sends repeat code as 0 0 0 FF */
+ if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
+ && (poll_reply.not_data == 0xff)) {
+ poll_reply.data_state = 2;
+ break;
+ }
+ break;
+ default:
+ /* RC5 Protocol */
+ poll_reply.report_id = buf[0];
+ poll_reply.data_state = buf[1];
+ poll_reply.system = (buf[2] << 8) | buf[3];
+ poll_reply.data = buf[4];
+ poll_reply.not_data = buf[5];
+ break;
+ }
+
+ if ((poll_reply.data + poll_reply.not_data) != 0xff) {
+ /* Key failed integrity check */
+ err("key failed integrity check: %04x %02x %02x",
+ poll_reply.system,
+ poll_reply.data, poll_reply.not_data);
+ goto resubmit;
+ }
+
+ deb_data("rid=%02x ds=%02x sm=%04x d=%02x nd=%02x\n",
+ poll_reply.report_id, poll_reply.data_state,
+ poll_reply.system, poll_reply.data, poll_reply.not_data);
+
+ /* Find the key in the map */
+ for (i = 0; i < d->props.rc_key_map_size; i++) {
+ if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
+ rc5_data(&keymap[i]) == poll_reply.data) {
+ event = keymap[i].event;
+ found = 1;
+ break;
+ }
+ }
+
+ if (found == 0) {
+ err("Unknown remote controller key: %04x %02x %02x",
+ poll_reply.system, poll_reply.data, poll_reply.not_data);
+ d->last_event = 0;
+ goto resubmit;
+ }
+
+ if (poll_reply.data_state == 1) {
+ /* New key hit */
+ st->rc_counter = 0;
+ event = keymap[i].event;
+ state = REMOTE_KEY_PRESSED;
+ d->last_event = keymap[i].event;
+ } else if (poll_reply.data_state == 2) {
+ /* Key repeated */
+ st->rc_counter++;
+
+ /* prevents unwanted double hits */
+ if (st->rc_counter > RC_REPEAT_DELAY_V1_20) {
+ event = d->last_event;
+ state = REMOTE_KEY_PRESSED;
+ st->rc_counter = RC_REPEAT_DELAY_V1_20;
+ }
+ } else {
+ err("Unknown data state [%d]", poll_reply.data_state);
+ }
+
+ switch (state) {
+ case REMOTE_NO_KEY_PRESSED:
+ break;
+ case REMOTE_KEY_PRESSED:
+ deb_info("key pressed\n");
+ d->last_event = event;
+ case REMOTE_KEY_REPEAT:
+ deb_info("key repeated\n");
+ input_event(d->rc_input_dev, EV_KEY, event, 1);
+ input_sync(d->rc_input_dev);
+ input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
+ input_sync(d->rc_input_dev);
+ break;
+ default:
+ break;
+ }
+
+resubmit:
+ /* Clean the buffer before we requeue */
+ memset(purb->transfer_buffer, 0, RC_MSG_SIZE_V1_20);
+
+ /* Requeue URB */
+ usb_submit_urb(purb, GFP_ATOMIC);
+}
+
int dib0700_rc_setup(struct dvb_usb_device *d)
{
+ struct dib0700_state *st = d->priv;
u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
- int i = dib0700_ctrl_wr(d, rc_setup, 3);
+ struct urb *purb;
+ int ret;
+ int i;
+
+ if (d->props.rc_key_map == NULL)
+ return 0;
+
+ /* Set the IR mode */
+ i = dib0700_ctrl_wr(d, rc_setup, 3);
if (i<0) {
err("ir protocol setup failed");
return -1;
}
+
+ if (st->fw_version < 0x10200)
+ return 0;
+
+ /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
+ purb = usb_alloc_urb(0, GFP_KERNEL);
+ if (purb == NULL) {
+ err("rc usb alloc urb failed\n");
+ return -1;
+ }
+
+ purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
+ if (purb->transfer_buffer == NULL) {
+ err("rc kzalloc failed\n");
+ usb_free_urb(purb);
+ return -1;
+ }
+
+ purb->status = -EINPROGRESS;
+ usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1),
+ purb->transfer_buffer, RC_MSG_SIZE_V1_20,
+ dib0700_rc_urb_completion, d);
+
+ ret = usb_submit_urb(purb, GFP_ATOMIC);
+ if (ret != 0) {
+ err("rc submit urb failed\n");
+ return -1;
+ }
+
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 44972d01bbd0..34eab05afc6c 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -472,20 +472,25 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
/* Number of keypresses to ignore before start repeating */
#define RC_REPEAT_DELAY 6
-#define RC_REPEAT_DELAY_V1_20 10
-
-
-/* Used by firmware versions < 1.20 (deprecated) */
-static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
- int *state)
+static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
u8 key[4];
int i;
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
struct dib0700_state *st = d->priv;
+
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
+
+ if (st->fw_version >= 0x10200) {
+ /* For 1.20 firmware , We need to keep the RC polling
+ callback so we can reuse the input device setup in
+ dvb-usb-remote.c. However, the actual work is being done
+ in the bulk URB completion handler. */
+ return 0;
+ }
+
i=dib0700_ctrl_rd(d,rc_request,2,key,4);
if (i<=0) {
err("RC Query Failed");
@@ -557,149 +562,6 @@ static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
return 0;
}
-/* This is the structure of the RC response packet starting in firmware 1.20 */
-struct dib0700_rc_response {
- u8 report_id;
- u8 data_state;
- u16 system;
- u8 data;
- u8 not_data;
-};
-
-/* This supports the new IR response format for firmware v1.20 */
-static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
- int *state)
-{
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
- struct dib0700_state *st = d->priv;
- struct dib0700_rc_response poll_reply;
- u8 buf[6];
- int i;
- int status;
- int actlen;
- int found = 0;
-
- /* Set initial results in case we exit the function early */
- *event = 0;
- *state = REMOTE_NO_KEY_PRESSED;
-
- /* Firmware v1.20 provides RC data via bulk endpoint 1 */
- status = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, 1), buf,
- sizeof(buf), &actlen, 50);
- if (status < 0) {
- /* No data available (meaning no key press) */
- return 0;
- }
-
-
- switch (dvb_usb_dib0700_ir_proto) {
- case 0:
- poll_reply.report_id = 0;
- poll_reply.data_state = 1;
- poll_reply.system = buf[2];
- poll_reply.data = buf[4];
- poll_reply.not_data = buf[5];
-
- /* NEC protocol sends repeat code as 0 0 0 FF */
- if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
- && (poll_reply.not_data == 0xff)) {
- poll_reply.data_state = 2;
- break;
- }
- break;
- default:
- if (actlen != sizeof(buf)) {
- /* We didn't get back the 6 byte message we expected */
- err("Unexpected RC response size [%d]", actlen);
- return -1;
- }
-
- poll_reply.report_id = buf[0];
- poll_reply.data_state = buf[1];
- poll_reply.system = (buf[2] << 8) | buf[3];
- poll_reply.data = buf[4];
- poll_reply.not_data = buf[5];
-
- break;
- }
-
- if ((poll_reply.data + poll_reply.not_data) != 0xff) {
- /* Key failed integrity check */
- err("key failed integrity check: %04x %02x %02x",
- poll_reply.system,
- poll_reply.data, poll_reply.not_data);
- return -1;
- }
-
-
- /* Find the key in the map */
- for (i = 0; i < d->props.rc_key_map_size; i++) {
- if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
- rc5_data(&keymap[i]) == poll_reply.data) {
- *event = keymap[i].event;
- found = 1;
- break;
- }
- }
-
- if (found == 0) {
- err("Unknown remote controller key: %04x %02x %02x",
- poll_reply.system,
- poll_reply.data, poll_reply.not_data);
- d->last_event = 0;
- return 0;
- }
-
- if (poll_reply.data_state == 1) {
- /* New key hit */
- st->rc_counter = 0;
- *event = keymap[i].event;
- *state = REMOTE_KEY_PRESSED;
- d->last_event = keymap[i].event;
- } else if (poll_reply.data_state == 2) {
- /* Key repeated */
- st->rc_counter++;
-
- /* prevents unwanted double hits */
- if (st->rc_counter > RC_REPEAT_DELAY_V1_20) {
- *event = d->last_event;
- *state = REMOTE_KEY_PRESSED;
- st->rc_counter = RC_REPEAT_DELAY_V1_20;
- }
- } else {
- err("Unknown data state [%d]", poll_reply.data_state);
- }
-
- return 0;
-}
-
-static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
- struct dib0700_state *st = d->priv;
-
- /* Because some people may have improperly named firmware files,
- let's figure out whether to use the new firmware call or the legacy
- call based on the firmware version embedded in the file */
- if (st->rc_func_version == 0) {
- u32 hwver, romver, ramver, fwtype;
- int ret = dib0700_get_version(d, &hwver, &romver, &ramver,
- &fwtype);
- if (ret < 0) {
- err("Could not determine version info");
- return -1;
- }
- if (ramver < 0x10200)
- st->rc_func_version = 1;
- else
- st->rc_func_version = 2;
- }
-
- if (st->rc_func_version == 2)
- return dib0700_rc_query_v1_20(d, event, state);
- else
- return dib0700_rc_query_legacy(d, event, state);
-}
-
static struct dvb_usb_rc_key dib0700_rc_keys[] = {
/* Key codes for the tiny Pinnacle remote*/
{ 0x0700, KEY_MUTE },
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index bc3581d58ced..ae8b57acfe05 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -64,6 +64,8 @@
#define USB_VID_HUMAX_COEX 0x10b9
#define USB_VID_774 0x7a69
#define USB_VID_EVOLUTEPC 0x1e59
+#define USB_VID_AZUREWAVE 0x13d3
+#define USB_VID_TECHNISAT 0x14f7
/* Product IDs */
#define USB_PID_ADSTECH_USB2_COLD 0xa333
@@ -138,6 +140,7 @@
#define USB_PID_TWINHAN_VP7021_COLD 0x3207
#define USB_PID_TWINHAN_VP7021_WARM 0x3208
#define USB_PID_TINYTWIN 0x3226
+#define USB_PID_TINYTWIN_2 0xe402
#define USB_PID_DNTV_TINYUSB2_COLD 0x3223
#define USB_PID_DNTV_TINYUSB2_WARM 0x3224
#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
@@ -209,6 +212,7 @@
#define USB_PID_PINNACLE_PCTV71E 0x022b
#define USB_PID_PINNACLE_PCTV72E 0x0236
#define USB_PID_PINNACLE_PCTV73E 0x0237
+#define USB_PID_PINNACLE_PCTV310E 0x3211
#define USB_PID_PINNACLE_PCTV801E 0x023a
#define USB_PID_PINNACLE_PCTV801E_SE 0x023b
#define USB_PID_PINNACLE_PCTV73A 0x0243
@@ -248,6 +252,7 @@
#define USB_PID_DIGIVOX_MINI_SL_WARM 0xe361
#define USB_PID_GRANDTEC_DVBT_USB2_COLD 0x0bc6
#define USB_PID_GRANDTEC_DVBT_USB2_WARM 0x0bc7
+#define USB_PID_WINFAST_DTV2000DS 0x6a04
#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025
#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00
@@ -290,5 +295,7 @@
#define USB_PID_FRIIO_WHITE 0x0001
#define USB_PID_TVWAY_PLUS 0x0002
#define USB_PID_SVEON_STV20 0xe39d
-
+#define USB_PID_AZUREWAVE_AZ6027 0x3275
+#define USB_PID_TERRATEC_DVBS2CI 0x3275
+#define USB_PID_TECHNISAT_USB2_HDCI 0x0002
#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index e331db8c77b2..5d91f70d2d2d 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -243,7 +243,7 @@ int dvb_usb_device_init(struct usb_interface *intf,
d = kzalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
if (d == NULL) {
err("no memory for 'struct dvb_usb_device'");
- return ret;
+ return -ENOMEM;
}
d->udev = udev;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 6b5ded9e7d5d..852fe89539cf 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -9,7 +9,7 @@
#include <linux/usb/input.h>
static int dvb_usb_getkeycode(struct input_dev *dev,
- int scancode, int *keycode)
+ unsigned int scancode, unsigned int *keycode)
{
struct dvb_usb_device *d = input_get_drvdata(dev);
@@ -39,7 +39,7 @@ static int dvb_usb_getkeycode(struct input_dev *dev,
}
static int dvb_usb_setkeycode(struct input_dev *dev,
- int scancode, int keycode)
+ unsigned int scancode, unsigned int keycode)
{
struct dvb_usb_device *d = input_get_drvdata(dev);
@@ -107,6 +107,7 @@ static void dvb_usb_read_remote_control(struct work_struct *work)
case REMOTE_KEY_REPEAT:
deb_rc("key repeated\n");
input_event(d->rc_input_dev, EV_KEY, event, 1);
+ input_sync(d->rc_input_dev);
input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
input_sync(d->rc_input_dev);
break;
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index 64132c0cf80d..accc65509b07 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -1,6 +1,7 @@
/* DVB USB framework compliant Linux driver for the
* DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
-* TeVii S600, S630, S650 Cards
+* TeVii S600, S630, S650,
+* Prof 1100, 7500 Cards
* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
*
* This program is free software; you can redistribute it and/or modify it
@@ -469,11 +470,13 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct usb_device *udev;
int ret = 0;
int len, i, j;
if (!d)
return -ENODEV;
+ udev = d->udev;
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
@@ -488,8 +491,13 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
}
case (DW2102_VOLTAGE_CTRL): {
u8 obuf[2];
+
+ obuf[0] = 1;
+ obuf[1] = msg[j].buf[1];/* off-on */
+ ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
+ obuf, 2, DW210X_WRITE_MSG);
obuf[0] = 3;
- obuf[1] = msg[j].buf[0];
+ obuf[1] = msg[j].buf[0];/* 13v-18v */
ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
obuf, 2, DW210X_WRITE_MSG);
break;
@@ -527,6 +535,17 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
i += 16;
len -= 16;
} while (len > 0);
+ } else if ((udev->descriptor.idProduct == 0x7500)
+ && (j < (num - 1))) {
+ /* write register addr before read */
+ u8 obuf[msg[j].len + 2];
+ obuf[0] = msg[j + 1].len;
+ obuf[1] = (msg[j].addr << 1);
+ memcpy(obuf + 2, msg[j].buf, msg[j].len);
+ ret = dw210x_op_rw(d->udev, 0x92, 0, 0,
+ obuf, msg[j].len + 2,
+ DW210X_WRITE_MSG);
+ break;
} else {
/* write registers */
u8 obuf[msg[j].len + 2];
@@ -651,18 +670,25 @@ static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
- static u8 command_13v[1] = {0x00};
- static u8 command_18v[1] = {0x01};
- struct i2c_msg msg[] = {
- {.addr = DW2102_VOLTAGE_CTRL, .flags = 0,
- .buf = command_13v, .len = 1},
+ static u8 command_13v[] = {0x00, 0x01};
+ static u8 command_18v[] = {0x01, 0x01};
+ static u8 command_off[] = {0x00, 0x00};
+ struct i2c_msg msg = {
+ .addr = DW2102_VOLTAGE_CTRL,
+ .flags = 0,
+ .buf = command_off,
+ .len = 2,
};
struct dvb_usb_adapter *udev_adap =
(struct dvb_usb_adapter *)(fe->dvb->priv);
if (voltage == SEC_VOLTAGE_18)
- msg[0].buf = command_18v;
- i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
+ msg.buf = command_18v;
+ else if (voltage == SEC_VOLTAGE_13)
+ msg.buf = command_13v;
+
+ i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);
+
return 0;
}
@@ -735,6 +761,18 @@ static struct stv6110_config dw2104_stv6110_config = {
.clk_div = 1,
};
+static struct stv0900_config prof_7500_stv0900_config = {
+ .demod_address = 0x6a,
+ .demod_mode = 0,
+ .xtal = 27000000,
+ .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+ .diseqc_mode = 2,/* 2/3 PWM */
+ .tun1_maddress = 0,/* 0x60 */
+ .tun1_adc = 0,/* 2 Vpp */
+ .path1_mode = 3,
+ .tun1_type = 3,
+};
+
static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
{
struct dvb_tuner_ops *tuner_ops = NULL;
@@ -882,6 +920,19 @@ static int s6x0_frontend_attach(struct dvb_usb_adapter *d)
return -EIO;
}
+static int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
+{
+ d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
+ &d->dev->i2c_adap, 0);
+ if (d->fe == NULL)
+ return -EIO;
+ d->fe->ops.set_voltage = dw210x_set_voltage;
+
+ info("Attached STV0900+STB6100A!\n");
+
+ return 0;
+}
+
static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@@ -1073,6 +1124,7 @@ static struct usb_device_id dw2102_table[] = {
{USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
{USB_DEVICE(0x3011, USB_PID_PROF_1100)},
{USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
+ {USB_DEVICE(0x3034, 0x7500)},
{ }
};
@@ -1387,9 +1439,30 @@ static struct dvb_usb_device_properties s6x0_properties = {
}
};
+struct dvb_usb_device_properties *p7500;
+static struct dvb_usb_device_description d7500 = {
+ "Prof 7500 USB DVB-S2",
+ {&dw2102_table[9], NULL},
+ {NULL},
+};
+
static int dw2102_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+
+ p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+ if (!p7500)
+ return -ENOMEM;
+ /* copy default structure */
+ memcpy(p7500, &s6x0_properties,
+ sizeof(struct dvb_usb_device_properties));
+ /* fill only different fields */
+ p7500->firmware = "dvb-usb-p7500.fw";
+ p7500->devices[0] = d7500;
+ p7500->rc_key_map = tbs_rc_keys;
+ p7500->rc_key_map_size = ARRAY_SIZE(tbs_rc_keys);
+ p7500->adapter->frontend_attach = prof_7500_frontend_attach;
+
if (0 == dvb_usb_device_init(intf, &dw2102_properties,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &dw2104_properties,
@@ -1397,6 +1470,8 @@ static int dw2102_probe(struct usb_interface *intf,
0 == dvb_usb_device_init(intf, &dw3101_properties,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &s6x0_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf, p7500,
THIS_MODULE, NULL, adapter_nr))
return 0;
@@ -1431,6 +1506,6 @@ MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
" DVB-C 3101 USB2.0,"
" TeVii S600, S630, S650, S660 USB2.0,"
- " Prof 1100 USB2.0 devices");
+ " Prof 1100, 7500 USB2.0 devices");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c
index ebb7b9fd115b..d14bd227b502 100644
--- a/drivers/media/dvb/dvb-usb/friio-fe.c
+++ b/drivers/media/dvb/dvb-usb/friio-fe.c
@@ -366,7 +366,7 @@ static u8 init_code[][2] = {
{0x76, 0x0C},
};
-const static int init_code_len = sizeof(init_code) / sizeof(u8[2]);
+static const int init_code_len = sizeof(init_code) / sizeof(u8[2]);
static int jdvbt90502_init(struct dvb_frontend *fe)
{
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index ef9b7bed13ff..737ffa36ac9c 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -16,6 +16,9 @@
#include "qt1010.h"
#include "tda1004x.h"
#include "tda827x.h"
+
+#include <media/tuner.h>
+#include "tuner-simple.h"
#include <asm/unaligned.h>
/* debug */
@@ -158,11 +161,14 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
case 0x93:
case 0x92:
+ case 0x83: /* pinnacle PCTV310e */
+ case 0x82:
m->rep_count = 0;
*state = REMOTE_KEY_PRESSED;
goto unlock;
case 0x91:
+ case 0x81: /* pinnacle PCTV310e */
/* prevent immediate auto-repeat */
if (++m->rep_count > 2)
*state = REMOTE_KEY_REPEAT;
@@ -546,6 +552,14 @@ static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
+static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ dvb_attach(simple_tuner_attach, adap->fe,
+ &adap->dev->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216ME_MK3);
+ return 0;
+}
+
/* device-specific initialization */
static struct m920x_inits megasky_rc_init [] = {
{ M9206_RC_INIT2, 0xa8 },
@@ -562,6 +576,18 @@ static struct m920x_inits tvwalkertwin_rc_init [] = {
{ } /* terminating entry */
};
+static struct m920x_inits pinnacle310e_init[] = {
+ /* without these the tuner don't work */
+ { 0xff20, 0x9b },
+ { 0xff22, 0x70 },
+
+ /* rc settings */
+ { 0xff50, 0x80 },
+ { M9206_RC_INIT1, 0x00 },
+ { M9206_RC_INIT2, 0xff },
+ { } /* terminating entry */
+};
+
/* ir keymaps */
static struct dvb_usb_rc_key megasky_rc_keys [] = {
{ 0x0012, KEY_POWER },
@@ -602,11 +628,68 @@ static struct dvb_usb_rc_key tvwalkertwin_rc_keys [] = {
{ 0x001e, KEY_VOLUMEUP },
};
+static struct dvb_usb_rc_key pinnacle310e_rc_keys[] = {
+ { 0x16, KEY_POWER },
+ { 0x17, KEY_FAVORITES },
+ { 0x0f, KEY_TEXT },
+ { 0x48, KEY_MEDIA }, /* preview */
+ { 0x1c, KEY_EPG },
+ { 0x04, KEY_LIST }, /* record list */
+ { 0x03, KEY_1 },
+ { 0x01, KEY_2 },
+ { 0x06, KEY_3 },
+ { 0x09, KEY_4 },
+ { 0x1d, KEY_5 },
+ { 0x1f, KEY_6 },
+ { 0x0d, KEY_7 },
+ { 0x19, KEY_8 },
+ { 0x1b, KEY_9 },
+ { 0x15, KEY_0 },
+ { 0x0c, KEY_CANCEL },
+ { 0x4a, KEY_CLEAR },
+ { 0x13, KEY_BACK },
+ { 0x00, KEY_TAB },
+ { 0x4b, KEY_UP },
+ { 0x4e, KEY_LEFT },
+ { 0x52, KEY_RIGHT },
+ { 0x51, KEY_DOWN },
+ { 0x4f, KEY_ENTER }, /* could also be KEY_OK */
+ { 0x1e, KEY_VOLUMEUP },
+ { 0x0a, KEY_VOLUMEDOWN },
+ { 0x05, KEY_CHANNELUP },
+ { 0x02, KEY_CHANNELDOWN },
+ { 0x11, KEY_RECORD },
+ { 0x14, KEY_PLAY },
+ { 0x4c, KEY_PAUSE },
+ { 0x1a, KEY_STOP },
+ { 0x40, KEY_REWIND },
+ { 0x12, KEY_FASTFORWARD },
+ { 0x41, KEY_PREVIOUSSONG }, /* Replay */
+ { 0x42, KEY_NEXTSONG }, /* Skip */
+ { 0x54, KEY_CAMERA }, /* Capture */
+/* { 0x50, KEY_SAP }, */ /* Sap */
+ { 0x47, KEY_CYCLEWINDOWS }, /* Pip */
+ { 0x4d, KEY_SCREEN }, /* FullScreen */
+ { 0x08, KEY_SUBTITLE },
+ { 0x0e, KEY_MUTE },
+/* { 0x49, KEY_LR }, */ /* L/R */
+ { 0x07, KEY_SLEEP }, /* Hibernate */
+ { 0x08, KEY_MEDIA }, /* A/V */
+ { 0x0e, KEY_MENU }, /* Recall */
+ { 0x45, KEY_ZOOMIN },
+ { 0x46, KEY_ZOOMOUT },
+ { 0x18, KEY_TV }, /* Red */
+ { 0x53, KEY_VCR }, /* Green */
+ { 0x5e, KEY_SAT }, /* Yellow */
+ { 0x5f, KEY_PLAYER }, /* Blue */
+};
+
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties megasky_properties;
static struct dvb_usb_device_properties digivox_mini_ii_properties;
static struct dvb_usb_device_properties tvwalkertwin_properties;
static struct dvb_usb_device_properties dposh_properties;
+static struct dvb_usb_device_properties pinnacle_pctv310e_properties;
static int m920x_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -652,6 +735,13 @@ static int m920x_probe(struct usb_interface *intf,
goto found;
}
+ ret = dvb_usb_device_init(intf, &pinnacle_pctv310e_properties,
+ THIS_MODULE, &d, adapter_nr);
+ if (ret == 0) {
+ rc_init_seq = pinnacle310e_init;
+ goto found;
+ }
+
return ret;
} else {
/* Another interface on a multi-tuner device */
@@ -682,6 +772,7 @@ static struct usb_device_id m920x_table [] = {
USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM) },
{ USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_COLD) },
{ USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_WARM) },
+ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_PINNACLE_PCTV310E) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, m920x_table);
@@ -895,6 +986,56 @@ static struct dvb_usb_device_properties dposh_properties = {
}
};
+static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .download_firmware = NULL,
+
+ .rc_interval = 100,
+ .rc_key_map = pinnacle310e_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(pinnacle310e_rc_keys),
+ .rc_query = m920x_rc_query,
+
+ .size_of_priv = sizeof(struct m920x_state),
+
+ .identify_state = m920x_identify_state,
+ .num_adapters = 1,
+ .adapter = {{
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+ .pid_filter_count = 8,
+ .pid_filter = m920x_pid_filter,
+ .pid_filter_ctrl = m920x_pid_filter_ctrl,
+
+ .frontend_attach = m920x_mt352_frontend_attach,
+ .tuner_attach = m920x_fmd1216me_tuner_attach,
+
+ .stream = {
+ .type = USB_ISOC,
+ .count = 5,
+ .endpoint = 0x84,
+ .u = {
+ .isoc = {
+ .framesperurb = 128,
+ .framesize = 564,
+ .interval = 1,
+ }
+ }
+ },
+ } },
+ .i2c_algo = &m920x_i2c_algo,
+
+ .num_device_descs = 1,
+ .devices = {
+ { "Pinnacle PCTV 310e",
+ { &m920x_table[6], NULL },
+ { NULL },
+ }
+ }
+};
+
static struct usb_driver m920x_driver = {
.name = "dvb_usb_m920x",
.probe = m920x_probe,
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h
index 37532890accd..3c061518ffc1 100644
--- a/drivers/media/dvb/dvb-usb/m920x.h
+++ b/drivers/media/dvb/dvb-usb/m920x.h
@@ -18,7 +18,7 @@
#define M9206_FW 0x30
#define M9206_MAX_FILTERS 8
-#define M9206_MAX_ADAPTERS 2
+#define M9206_MAX_ADAPTERS 4
/*
sequences found in logs:
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index d4e230941679..830557696ae6 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -138,7 +138,7 @@ static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
(msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0),
msg[i].buf,
msg[i].len
- )!= msg[i].len)) {
+ )) != msg[i].len) {
break;
}
if (dvb_usb_opera1_debug & 0x10)
diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c
index 7c5459c27b75..c3e0ec2dcfca 100644
--- a/drivers/media/dvb/firewire/firedtv-1394.c
+++ b/drivers/media/dvb/firewire/firedtv-1394.c
@@ -90,13 +90,14 @@ static inline struct node_entry *node_of(struct firedtv *fdtv)
return container_of(fdtv->device, struct unit_directory, device)->ne;
}
-static int node_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
+static int node_lock(struct firedtv *fdtv, u64 addr, void *data)
{
+ quadlet_t *d = data;
int ret;
- ret = hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP,
- (__force quadlet_t *)&data[1], (__force quadlet_t)data[0]);
- data[0] = data[1];
+ ret = hpsb_node_lock(node_of(fdtv), addr,
+ EXTCODE_COMPARE_SWAP, &d[1], d[0]);
+ d[0] = d[1];
return ret;
}
@@ -192,9 +193,13 @@ static int node_probe(struct device *dev)
int kv_len, err;
void *kv_str;
- kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t);
- kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
-
+ if (ud->model_name_kv) {
+ kv_len = (ud->model_name_kv->value.leaf.len - 2) * 4;
+ kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
+ } else {
+ kv_len = 0;
+ kv_str = NULL;
+ }
fdtv = fdtv_alloc(dev, &fdtv_1394_backend, kv_str, kv_len);
if (!fdtv)
return -ENOMEM;
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
index 50c42a4b972b..1b31bebc27d6 100644
--- a/drivers/media/dvb/firewire/firedtv-avc.c
+++ b/drivers/media/dvb/firewire/firedtv-avc.c
@@ -74,7 +74,6 @@
#define EN50221_TAG_CA_INFO 0x9f8031
struct avc_command_frame {
- int length;
u8 ctype;
u8 subunit;
u8 opcode;
@@ -82,13 +81,27 @@ struct avc_command_frame {
};
struct avc_response_frame {
- int length;
u8 response;
u8 subunit;
u8 opcode;
u8 operand[509];
};
+#define LAST_OPERAND (509 - 1)
+
+static inline void clear_operands(struct avc_command_frame *c, int from, int to)
+{
+ memset(&c->operand[from], 0, to - from + 1);
+}
+
+static void pad_operands(struct avc_command_frame *c, int from)
+{
+ int to = ALIGN(from, 4);
+
+ if (from <= to && to <= LAST_OPERAND)
+ clear_operands(c, from, to);
+}
+
#define AVC_DEBUG_READ_DESCRIPTOR 0x0001
#define AVC_DEBUG_DSIT 0x0002
#define AVC_DEBUG_DSD 0x0004
@@ -202,78 +215,65 @@ static void debug_pmt(char *msg, int length)
16, 1, msg, length, false);
}
-static int __avc_write(struct firedtv *fdtv,
- const struct avc_command_frame *c, struct avc_response_frame *r)
+static int avc_write(struct firedtv *fdtv)
{
int err, retry;
- if (r)
- fdtv->avc_reply_received = false;
+ fdtv->avc_reply_received = false;
for (retry = 0; retry < 6; retry++) {
if (unlikely(avc_debug))
- debug_fcp(&c->ctype, c->length);
+ debug_fcp(fdtv->avc_data, fdtv->avc_data_length);
err = fdtv->backend->write(fdtv, FCP_COMMAND_REGISTER,
- (void *)&c->ctype, c->length);
+ fdtv->avc_data, fdtv->avc_data_length);
if (err) {
- fdtv->avc_reply_received = true;
dev_err(fdtv->device, "FCP command write failed\n");
+
return err;
}
- if (!r)
- return 0;
-
/*
* AV/C specs say that answers should be sent within 150 ms.
* Time out after 200 ms.
*/
if (wait_event_timeout(fdtv->avc_wait,
fdtv->avc_reply_received,
- msecs_to_jiffies(200)) != 0) {
- r->length = fdtv->response_length;
- memcpy(&r->response, fdtv->response, r->length);
-
+ msecs_to_jiffies(200)) != 0)
return 0;
- }
}
dev_err(fdtv->device, "FCP response timed out\n");
+
return -ETIMEDOUT;
}
-static int avc_write(struct firedtv *fdtv,
- const struct avc_command_frame *c, struct avc_response_frame *r)
+static bool is_register_rc(struct avc_response_frame *r)
{
- int ret;
-
- if (mutex_lock_interruptible(&fdtv->avc_mutex))
- return -EINTR;
-
- ret = __avc_write(fdtv, c, r);
-
- mutex_unlock(&fdtv->avc_mutex);
- return ret;
+ return r->opcode == AVC_OPCODE_VENDOR &&
+ r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
+ r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
+ r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
+ r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
}
int avc_recv(struct firedtv *fdtv, void *data, size_t length)
{
- struct avc_response_frame *r =
- data - offsetof(struct avc_response_frame, response);
+ struct avc_response_frame *r = data;
if (unlikely(avc_debug))
debug_fcp(data, length);
- if (length >= 8 &&
- r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
- r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
- r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
- r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) {
- if (r->response == AVC_RESPONSE_CHANGED) {
- fdtv_handle_rc(fdtv,
- r->operand[4] << 8 | r->operand[5]);
+ if (length >= 8 && is_register_rc(r)) {
+ switch (r->response) {
+ case AVC_RESPONSE_CHANGED:
+ fdtv_handle_rc(fdtv, r->operand[4] << 8 | r->operand[5]);
schedule_work(&fdtv->remote_ctrl_work);
- } else if (r->response != AVC_RESPONSE_INTERIM) {
+ break;
+ case AVC_RESPONSE_INTERIM:
+ if (is_register_rc((void *)fdtv->avc_data))
+ goto wake;
+ break;
+ default:
dev_info(fdtv->device,
"remote control result = %d\n", r->response);
}
@@ -285,9 +285,9 @@ int avc_recv(struct firedtv *fdtv, void *data, size_t length)
return -EIO;
}
- memcpy(fdtv->response, data, length);
- fdtv->response_length = length;
-
+ memcpy(fdtv->avc_data, data, length);
+ fdtv->avc_data_length = length;
+wake:
fdtv->avc_reply_received = true;
wake_up(&fdtv->avc_wait);
@@ -318,10 +318,11 @@ static int add_pid_filter(struct firedtv *fdtv, u8 *operand)
* tuning command for setting the relative LNB frequency
* (not supported by the AVC standard)
*/
-static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
- struct dvb_frontend_parameters *params,
- struct avc_command_frame *c)
+static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
+ struct dvb_frontend_parameters *params)
{
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+
c->opcode = AVC_OPCODE_VENDOR;
c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
@@ -370,16 +371,18 @@ static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
c->operand[13] = 0x1;
c->operand[14] = 0xff;
c->operand[15] = 0xff;
- c->length = 20;
+
+ return 16;
} else {
- c->length = 16;
+ return 13;
}
}
-static void avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
- struct dvb_frontend_parameters *params,
- struct avc_command_frame *c)
+static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
+ struct dvb_frontend_parameters *params)
{
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+
c->opcode = AVC_OPCODE_DSD;
c->operand[0] = 0; /* source plug */
@@ -440,15 +443,14 @@ static void avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
c->operand[20] = 0x00;
c->operand[21] = 0x00;
- /* Add PIDs to filter */
- c->length = ALIGN(22 + add_pid_filter(fdtv, &c->operand[22]) + 3, 4);
+ return 22 + add_pid_filter(fdtv, &c->operand[22]);
}
-static void avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
- struct dvb_frontend_parameters *params,
- struct avc_command_frame *c)
+static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
+ struct dvb_frontend_parameters *params)
{
struct dvb_ofdm_parameters *ofdm = &params->u.ofdm;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
c->opcode = AVC_OPCODE_DSD;
@@ -543,55 +545,58 @@ static void avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
c->operand[15] = 0x00; /* network_ID[0] */
c->operand[16] = 0x00; /* network_ID[1] */
- /* Add PIDs to filter */
- c->length = ALIGN(17 + add_pid_filter(fdtv, &c->operand[17]) + 3, 4);
+ return 17 + add_pid_filter(fdtv, &c->operand[17]);
}
int avc_tuner_dsd(struct firedtv *fdtv,
struct dvb_frontend_parameters *params)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int pos, ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
switch (fdtv->type) {
case FIREDTV_DVB_S:
- case FIREDTV_DVB_S2: avc_tuner_tuneqpsk(fdtv, params, c); break;
- case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(fdtv, params, c); break;
- case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(fdtv, params, c); break;
+ case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, params); break;
+ case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, params); break;
+ case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, params); break;
default:
BUG();
}
+ pad_operands(c, pos);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
-
- msleep(500);
+ fdtv->avc_data_length = ALIGN(3 + pos, 4);
+ ret = avc_write(fdtv);
#if 0
- /* FIXME: */
- /* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */
+ /*
+ * FIXME:
+ * u8 *status was an out-parameter of avc_tuner_dsd, unused by caller.
+ * Check for AVC_RESPONSE_ACCEPTED here instead?
+ */
if (status)
*status = r->operand[2];
#endif
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ if (ret == 0)
+ msleep(500);
+
+ return ret;
}
int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
- int pos, k;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret, pos, k;
if (pidc > 16 && pidc != 0xff)
return -EINVAL;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -614,24 +619,27 @@ int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
c->operand[pos++] = 0x00; /* tableID */
c->operand[pos++] = 0x00; /* filter_length */
}
+ pad_operands(c, pos);
- c->length = ALIGN(3 + pos, 4);
+ fdtv->avc_data_length = ALIGN(3 + pos, 4);
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- msleep(50);
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ if (ret == 0)
+ msleep(50);
+
+ return ret;
}
int avc_tuner_get_ts(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
- int sl;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret, sl;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -646,26 +654,33 @@ int avc_tuner_get_ts(struct firedtv *fdtv)
c->operand[4] = 0x00; /* antenna number */
c->operand[5] = 0x0; /* system_specific_search_flags */
c->operand[6] = sl; /* system_specific_multiplex selection_length */
- c->operand[7] = 0x00; /* valid_flags [0] */
- c->operand[8] = 0x00; /* valid_flags [1] */
- c->operand[7 + sl] = 0x00; /* nr_of_dsit_sel_specs (always 0) */
+ /*
+ * operand[7]: valid_flags[0]
+ * operand[8]: valid_flags[1]
+ * operand[7 + sl]: nr_of_dsit_sel_specs (always 0)
+ */
+ clear_operands(c, 7, 24);
- c->length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
+ fdtv->avc_data_length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- msleep(250);
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ if (ret == 0)
+ msleep(250);
+
+ return ret;
}
int avc_identify_subunit(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -678,31 +693,34 @@ int avc_identify_subunit(struct firedtv *fdtv)
c->operand[4] = 0x08; /* length lowbyte */
c->operand[5] = 0x00; /* offset highbyte */
c->operand[6] = 0x0d; /* offset lowbyte */
+ clear_operands(c, 7, 8); /* padding */
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
if ((r->response != AVC_RESPONSE_STABLE &&
r->response != AVC_RESPONSE_ACCEPTED) ||
(r->operand[3] << 8) + r->operand[4] != 8) {
dev_err(fdtv->device, "cannot read subunit identifier\n");
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+out:
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
#define SIZEOF_ANTENNA_INPUT_INFO 22
int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
- int length;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int length, ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -710,27 +728,30 @@ int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
c->operand[0] = DESCRIPTOR_TUNER_STATUS;
c->operand[1] = 0xff; /* read_result_status */
- c->operand[2] = 0x00; /* reserved */
- c->operand[3] = 0; /* SIZEOF_ANTENNA_INPUT_INFO >> 8; */
- c->operand[4] = 0; /* SIZEOF_ANTENNA_INPUT_INFO & 0xff; */
- c->operand[5] = 0x00;
- c->operand[6] = 0x00;
-
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /*
+ * operand[2]: reserved
+ * operand[3]: SIZEOF_ANTENNA_INPUT_INFO >> 8
+ * operand[4]: SIZEOF_ANTENNA_INPUT_INFO & 0xff
+ */
+ clear_operands(c, 2, 31);
+
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
if (r->response != AVC_RESPONSE_STABLE &&
r->response != AVC_RESPONSE_ACCEPTED) {
dev_err(fdtv->device, "cannot read tuner status\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
length = r->operand[9];
if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) {
dev_err(fdtv->device, "got invalid tuner status\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
stat->active_system = r->operand[10];
@@ -766,20 +787,21 @@ int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
stat->ca_dvb_flag = r->operand[31] >> 3 & 1;
stat->ca_error_flag = r->operand[31] >> 2 & 1;
stat->ca_initialization_status = r->operand[31] >> 1 & 1;
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
char conttone, char nrdiseq,
struct dvb_diseqc_master_cmd *diseqcmd)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
- int i, j, k;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int pos, j, k, ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -789,41 +811,41 @@ int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL;
-
c->operand[4] = voltage;
c->operand[5] = nrdiseq;
- i = 6;
-
+ pos = 6;
for (j = 0; j < nrdiseq; j++) {
- c->operand[i++] = diseqcmd[j].msg_len;
+ c->operand[pos++] = diseqcmd[j].msg_len;
for (k = 0; k < diseqcmd[j].msg_len; k++)
- c->operand[i++] = diseqcmd[j].msg[k];
+ c->operand[pos++] = diseqcmd[j].msg[k];
}
+ c->operand[pos++] = burst;
+ c->operand[pos++] = conttone;
+ pad_operands(c, pos);
- c->operand[i++] = burst;
- c->operand[i++] = conttone;
-
- c->length = ALIGN(3 + i, 4);
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = ALIGN(3 + pos, 4);
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
if (r->response != AVC_RESPONSE_ACCEPTED) {
dev_err(fdtv->device, "LNB control failed\n");
- return -EINVAL;
+ ret = -EINVAL;
}
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_register_remote_control(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_NOTIFY;
c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7;
@@ -833,10 +855,16 @@ int avc_register_remote_control(struct firedtv *fdtv)
c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
+ c->operand[4] = 0; /* padding */
+
+ fdtv->avc_data_length = 8;
+ ret = avc_write(fdtv);
- c->length = 8;
+ /* FIXME: check response code? */
- return avc_write(fdtv, c, NULL);
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
void avc_remote_ctrl_work(struct work_struct *work)
@@ -851,11 +879,10 @@ void avc_remote_ctrl_work(struct work_struct *work)
#if 0 /* FIXME: unused */
int avc_tuner_host2ca(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -867,15 +894,16 @@ int avc_tuner_host2ca(struct firedtv *fdtv)
c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
- c->operand[6] = 0; /* more/last */
- c->operand[7] = 0; /* length */
+ clear_operands(c, 6, 8);
- c->length = 12;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
#endif
@@ -906,12 +934,11 @@ static int get_ca_object_length(struct avc_response_frame *r)
int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
- int pos;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int pos, ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_STATUS;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -923,11 +950,12 @@ int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
+ clear_operands(c, 6, LAST_OPERAND);
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
/* FIXME: check response code and validate response data */
@@ -939,18 +967,19 @@ int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
app_info[4] = 0x01;
memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]);
*len = app_info[3] + 4;
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
- int pos;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int pos, ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_STATUS;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -962,11 +991,14 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
+ clear_operands(c, 6, LAST_OPERAND);
- c->length = 12;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code and validate response data */
pos = get_ca_object_pos(r);
app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
@@ -976,17 +1008,18 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
app_info[4] = r->operand[pos + 0];
app_info[5] = r->operand[pos + 1];
*len = app_info[3] + 4;
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_ca_reset(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1002,19 +1035,20 @@ int avc_ca_reset(struct firedtv *fdtv)
c->operand[7] = 1; /* length */
c->operand[8] = 0; /* force hardware reset */
- c->length = 12;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
int list_management;
int program_info_length;
int pmt_cmd_id;
@@ -1022,11 +1056,12 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
int write_pos;
int es_info_length;
int crc32_csum;
+ int ret;
if (unlikely(avc_debug & AVC_DEBUG_APPLICATION_PMT))
debug_pmt(msg, length);
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1058,7 +1093,7 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
c->operand[12] = 0x02; /* Table id=2 */
c->operand[13] = 0x80; /* Section syntax + length */
- /* c->operand[14] = XXXprogram_info_length + 12; */
+
c->operand[15] = msg[1]; /* Program number */
c->operand[16] = msg[2];
c->operand[17] = 0x01; /* Version number=0 + current/next=1 */
@@ -1106,12 +1141,7 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
write_pos += es_info_length;
}
}
-
- /* CRC */
- c->operand[write_pos++] = 0x00;
- c->operand[write_pos++] = 0x00;
- c->operand[write_pos++] = 0x00;
- c->operand[write_pos++] = 0x00;
+ write_pos += 4; /* CRC */
c->operand[7] = 0x82;
c->operand[8] = (write_pos - 10) >> 8;
@@ -1123,28 +1153,31 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff;
c->operand[write_pos - 2] = (crc32_csum >> 8) & 0xff;
c->operand[write_pos - 1] = (crc32_csum >> 0) & 0xff;
+ pad_operands(c, write_pos);
- c->length = ALIGN(3 + write_pos, 4);
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = ALIGN(3 + write_pos, 4);
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
if (r->response != AVC_RESPONSE_ACCEPTED) {
dev_err(fdtv->device,
"CA PMT failed with response 0x%x\n", r->response);
- return -EFAULT;
+ ret = -EFAULT;
}
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_STATUS;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1156,28 +1189,28 @@ int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */
- c->operand[6] = 0; /* more/last */
- c->operand[7] = 0; /* length */
+ clear_operands(c, 6, LAST_OPERAND);
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
/* FIXME: check response code and validate response data */
*interval = r->operand[get_ca_object_pos(r)];
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_ca_enter_menu(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_STATUS;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1189,24 +1222,25 @@ int avc_ca_enter_menu(struct firedtv *fdtv)
c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU;
- c->operand[6] = 0; /* more/last */
- c->operand[7] = 0; /* length */
+ clear_operands(c, 6, 8);
- c->length = 12;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_STATUS;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1218,20 +1252,21 @@ int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_MMI;
- c->operand[6] = 0; /* more/last */
- c->operand[7] = 0; /* length */
+ clear_operands(c, 6, LAST_OPERAND);
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
/* FIXME: check response code and validate response data */
*len = get_ca_object_length(r);
memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len);
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL
@@ -1240,14 +1275,14 @@ static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
{
int ret;
- if (mutex_lock_interruptible(&fdtv->avc_mutex))
- return -EINTR;
+ mutex_lock(&fdtv->avc_mutex);
ret = fdtv->backend->read(fdtv, addr, data);
if (ret < 0)
dev_err(fdtv->device, "CMP: read I/O error\n");
mutex_unlock(&fdtv->avc_mutex);
+
return ret;
}
@@ -1255,14 +1290,19 @@ static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
{
int ret;
- if (mutex_lock_interruptible(&fdtv->avc_mutex))
- return -EINTR;
+ mutex_lock(&fdtv->avc_mutex);
+
+ /* data[] is stack-allocated and should not be DMA-mapped. */
+ memcpy(fdtv->avc_data, data, 8);
- ret = fdtv->backend->lock(fdtv, addr, data);
+ ret = fdtv->backend->lock(fdtv, addr, fdtv->avc_data);
if (ret < 0)
dev_err(fdtv->device, "CMP: lock I/O error\n");
+ else
+ memcpy(data, fdtv->avc_data, 8);
mutex_unlock(&fdtv->avc_mutex);
+
return ret;
}
diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c
index fc9996c13e13..079e8c5b0475 100644
--- a/drivers/media/dvb/firewire/firedtv-dvb.c
+++ b/drivers/media/dvb/firewire/firedtv-dvb.c
@@ -277,7 +277,6 @@ struct firedtv *fdtv_alloc(struct device *dev,
mutex_init(&fdtv->avc_mutex);
init_waitqueue_head(&fdtv->avc_wait);
- fdtv->avc_reply_received = true;
mutex_init(&fdtv->demux_mutex);
INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
index 6223bf01efe9..75afe4f81e33 100644
--- a/drivers/media/dvb/firewire/firedtv-fw.c
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -41,7 +41,7 @@ static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len,
return rcode != RCODE_COMPLETE ? -EIO : 0;
}
-static int node_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
+static int node_lock(struct firedtv *fdtv, u64 addr, void *data)
{
return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP);
}
@@ -239,47 +239,18 @@ static const struct fw_address_region fcp_region = {
};
/* Adjust the template string if models with longer names appear. */
-#define MAX_MODEL_NAME_LEN ((int)DIV_ROUND_UP(sizeof("FireDTV ????"), 4))
-
-static size_t model_name(u32 *directory, __be32 *buffer)
-{
- struct fw_csr_iterator ci;
- int i, length, key, value, last_key = 0;
- u32 *block = NULL;
-
- fw_csr_iterator_init(&ci, directory);
- while (fw_csr_iterator_next(&ci, &key, &value)) {
- if (last_key == CSR_MODEL &&
- key == (CSR_DESCRIPTOR | CSR_LEAF))
- block = ci.p - 1 + value;
- last_key = key;
- }
-
- if (block == NULL)
- return 0;
-
- length = min((int)(block[0] >> 16) - 2, MAX_MODEL_NAME_LEN);
- if (length <= 0)
- return 0;
-
- /* fast-forward to text string */
- block += 3;
-
- for (i = 0; i < length; i++)
- buffer[i] = cpu_to_be32(block[i]);
-
- return length * 4;
-}
+#define MAX_MODEL_NAME_LEN sizeof("FireDTV ????")
static int node_probe(struct device *dev)
{
struct firedtv *fdtv;
- __be32 name[MAX_MODEL_NAME_LEN];
+ char name[MAX_MODEL_NAME_LEN];
int name_len, err;
- name_len = model_name(fw_unit(dev)->directory, name);
+ name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
+ name, sizeof(name));
- fdtv = fdtv_alloc(dev, &backend, (char *)name, name_len);
+ fdtv = fdtv_alloc(dev, &backend, name, name_len >= 0 ? name_len : 0);
if (!fdtv)
return -ENOMEM;
diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h
index 35080dbb3c66..78cc28f36914 100644
--- a/drivers/media/dvb/firewire/firedtv.h
+++ b/drivers/media/dvb/firewire/firedtv.h
@@ -73,7 +73,7 @@ struct input_dev;
struct firedtv;
struct firedtv_backend {
- int (*lock)(struct firedtv *fdtv, u64 addr, __be32 data[]);
+ int (*lock)(struct firedtv *fdtv, u64 addr, void *data);
int (*read)(struct firedtv *fdtv, u64 addr, void *data);
int (*write)(struct firedtv *fdtv, u64 addr, void *data, size_t len);
int (*start_iso)(struct firedtv *fdtv);
@@ -114,8 +114,8 @@ struct firedtv {
unsigned long channel_active;
u16 channel_pid[16];
- size_t response_length;
- u8 response[512];
+ int avc_data_length;
+ u8 avc_data[512];
};
/* firedtv-1394.c */
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index a3b8b697349b..cd7f9b7cbffa 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -208,6 +208,14 @@ config DVB_DS3000
help
A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+config DVB_MB86A16
+ tristate "Fujitsu MB86A16 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S/DSS Direct Conversion reveiver.
+ Say Y when you want to support this frontend.
+
comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE
@@ -587,6 +595,17 @@ config DVB_ATBM8830
help
A DMB-TH tuner module. Say Y when you want to support this frontend.
+config DVB_TDA665x
+ tristate "TDA665x tuner"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ Support for tuner modules based on Philips TDA6650/TDA6651 chips.
+ Say Y when you want to support this chip.
+
+ Currently supported tuners:
+ * Panasonic ENV57H12D5 (ET-50DT)
+
comment "Tools to develop new frontends"
config DVB_DUMMY_FE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 47575cc7b699..874e8ada4d1d 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_DVB_TDA10048) += tda10048.o
obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
+obj-$(CONFIG_DVB_TDA665x) += tda665x.o
obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
@@ -80,3 +81,4 @@ obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o
obj-$(CONFIG_DVB_DS3000) += ds3000.o
+obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h
index 28b90c91c766..e90fa92b1c1d 100644
--- a/drivers/media/dvb/frontends/af9013.h
+++ b/drivers/media/dvb/frontends/af9013.h
@@ -44,6 +44,7 @@ enum af9013_tuner {
AF9013_TUNER_MT2060_2 = 147, /* Microtune */
AF9013_TUNER_TDA18271 = 156, /* NXP */
AF9013_TUNER_QT1010A = 162, /* Quantek */
+ AF9013_TUNER_TDA18218 = 179, /* NXP */
};
/* AF9013/5 GPIOs (mostly guessed)
diff --git a/drivers/media/dvb/frontends/atbm8830.c b/drivers/media/dvb/frontends/atbm8830.c
index 59881a5944eb..43aac2f85c2e 100644
--- a/drivers/media/dvb/frontends/atbm8830.c
+++ b/drivers/media/dvb/frontends/atbm8830.c
@@ -170,6 +170,19 @@ static int is_locked(struct atbm_state *priv, u8 *locked)
return 0;
}
+static int set_agc_config(struct atbm_state *priv,
+ u8 min, u8 max, u8 hold_loop)
+{
+ /* no effect if both min and max are zero */
+ if (!min && !max)
+ return 0;
+
+ atbm8830_write_reg(priv, REG_AGC_MIN, min);
+ atbm8830_write_reg(priv, REG_AGC_MAX, max);
+ atbm8830_write_reg(priv, REG_AGC_HOLD_LOOP, hold_loop);
+
+ return 0;
+}
static int set_static_channel_mode(struct atbm_state *priv)
{
@@ -227,6 +240,9 @@ static int atbm8830_init(struct dvb_frontend *fe)
/*Set IF frequency*/
set_if_freq(priv, cfg->if_freq);
+ /*Set AGC Config*/
+ set_agc_config(priv, cfg->agc_min, cfg->agc_max,
+ cfg->agc_hold_loop);
/*Set static channel mode*/
set_static_channel_mode(priv);
diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c
index 614552709a6f..7eac178f57b2 100644
--- a/drivers/media/dvb/frontends/dib0090.c
+++ b/drivers/media/dvb/frontends/dib0090.c
@@ -283,7 +283,7 @@ static int dib0090_sleep(struct dvb_frontend *fe)
return 0;
}
-extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
+void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
{
struct dib0090_state *state = fe->tuner_priv;
if (fast)
diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c
index 6f6fa29d9ea4..2aa97dd6a8af 100644
--- a/drivers/media/dvb/frontends/dib8000.c
+++ b/drivers/media/dvb/frontends/dib8000.c
@@ -1999,6 +1999,8 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
struct dib8000_state *state = fe->demodulator_priv;
int time, ret;
+ fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+
dib8000_set_output_mode(state, OUTMODE_HIGH_Z);
if (fe->ops.tuner_ops.set_params)
diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h
index d99619ae983c..b1ee20799639 100644
--- a/drivers/media/dvb/frontends/dib8000.h
+++ b/drivers/media/dvb/frontends/dib8000.h
@@ -100,7 +100,7 @@ static inline int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_
static inline enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return CT_SHUTDOWN,
+ return CT_SHUTDOWN;
}
static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
{
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
index e6f3d73db9d3..980e02f1575e 100644
--- a/drivers/media/dvb/frontends/dibx000_common.c
+++ b/drivers/media/dvb/frontends/dibx000_common.c
@@ -174,7 +174,7 @@ void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst)
EXPORT_SYMBOL(dibx000_exit_i2c_master);
-u32 systime()
+u32 systime(void)
{
struct timespec t;
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 3051b64aa17c..445fa1068064 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -192,8 +192,8 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
spi_bias *= qam_tab[p->constellation];
spi_bias /= p->code_rate_HP + 1;
spi_bias /= (guard_tab[p->guard_interval] + 32);
- spi_bias *= 1000ULL;
- spi_bias /= 1000ULL + ppm/1000;
+ spi_bias *= 1000;
+ spi_bias /= 1000 + ppm/1000;
spi_bias *= p->code_rate_HP;
val0x04 = (p->transmission_mode << 2) | p->guard_interval;
diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h
index 4fa6e52d1fe8..9cb11c9cae53 100644
--- a/drivers/media/dvb/frontends/lgdt3305.h
+++ b/drivers/media/dvb/frontends/lgdt3305.h
@@ -54,13 +54,13 @@ struct lgdt3305_config {
u16 usref_qam256; /* default: 0x2a80 */
/* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
- int deny_i2c_rptr:1;
+ unsigned int deny_i2c_rptr:1;
/* spectral inversion - 0:disabled 1:enabled */
- int spectral_inversion:1;
+ unsigned int spectral_inversion:1;
/* use RF AGC loop - 0:disabled 1:enabled */
- int rf_agc_loop:1;
+ unsigned int rf_agc_loop:1;
enum lgdt3305_mpeg_mode mpeg_mode;
enum lgdt3305_tp_clock_edge tpclk_edge;
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
index b181bf023ada..13437259eeac 100644
--- a/drivers/media/dvb/frontends/lnbp21.c
+++ b/drivers/media/dvb/frontends/lnbp21.c
@@ -158,7 +158,8 @@ static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
/* override frontend ops */
fe->ops.set_voltage = lnbp21_set_voltage;
fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
- fe->ops.set_tone = lnbp21_set_tone;
+ if (!(override_clear & LNBH24_TEN)) /*22kHz logic controlled by demod*/
+ fe->ops.set_tone = lnbp21_set_tone;
printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr);
return fe;
diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb/frontends/mb86a16.c
new file mode 100644
index 000000000000..d05f7500e0c5
--- /dev/null
+++ b/drivers/media/dvb/frontends/mb86a16.c
@@ -0,0 +1,1878 @@
+/*
+ Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include "dvb_frontend.h"
+#include "mb86a16.h"
+#include "mb86a16_priv.h"
+
+unsigned int verbose = 5;
+module_param(verbose, int, 0644);
+
+#define ABS(x) ((x) < 0 ? (-x) : (x))
+
+struct mb86a16_state {
+ struct i2c_adapter *i2c_adap;
+ const struct mb86a16_config *config;
+ struct dvb_frontend frontend;
+
+ /* tuning parameters */
+ int frequency;
+ int srate;
+
+ /* Internal stuff */
+ int master_clk;
+ int deci;
+ int csel;
+ int rsel;
+};
+
+#define MB86A16_ERROR 0
+#define MB86A16_NOTICE 1
+#define MB86A16_INFO 2
+#define MB86A16_DEBUG 3
+
+#define dprintk(x, y, z, format, arg...) do { \
+ if (z) { \
+ if ((x > MB86A16_ERROR) && (x > y)) \
+ printk(KERN_ERR "%s: " format "\n", __func__, ##arg); \
+ else if ((x > MB86A16_NOTICE) && (x > y)) \
+ printk(KERN_NOTICE "%s: " format "\n", __func__, ##arg); \
+ else if ((x > MB86A16_INFO) && (x > y)) \
+ printk(KERN_INFO "%s: " format "\n", __func__, ##arg); \
+ else if ((x > MB86A16_DEBUG) && (x > y)) \
+ printk(KERN_DEBUG "%s: " format "\n", __func__, ##arg); \
+ } else { \
+ if (x > y) \
+ printk(format, ##arg); \
+ } \
+} while (0)
+
+#define TRACE_IN dprintk(verbose, MB86A16_DEBUG, 1, "-->()")
+#define TRACE_OUT dprintk(verbose, MB86A16_DEBUG, 1, "()-->")
+
+static int mb86a16_write(struct mb86a16_state *state, u8 reg, u8 val)
+{
+ int ret;
+ u8 buf[] = { reg, val };
+
+ struct i2c_msg msg = {
+ .addr = state->config->demod_address,
+ .flags = 0,
+ .buf = buf,
+ .len = 2
+ };
+
+ dprintk(verbose, MB86A16_DEBUG, 1,
+ "writing to [0x%02x],Reg[0x%02x],Data[0x%02x]",
+ state->config->demod_address, buf[0], buf[1]);
+
+ ret = i2c_transfer(state->i2c_adap, &msg, 1);
+
+ return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val)
+{
+ int ret;
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = state->config->demod_address,
+ .flags = 0,
+ .buf = b0,
+ .len = 1
+ }, {
+ .addr = state->config->demod_address,
+ .flags = I2C_M_RD,
+ .buf = b1,
+ .len = 1
+ }
+ };
+ ret = i2c_transfer(state->i2c_adap, msg, 2);
+ if (ret != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)",
+ reg, ret);
+
+ return -EREMOTEIO;
+ }
+ *val = b1[0];
+
+ return ret;
+}
+
+static int CNTM_set(struct mb86a16_state *state,
+ unsigned char timint1,
+ unsigned char timint2,
+ unsigned char cnext)
+{
+ unsigned char val;
+
+ val = (timint1 << 4) | (timint2 << 2) | cnext;
+ if (mb86a16_write(state, MB86A16_CNTMR, val) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int smrt_set(struct mb86a16_state *state, int rate)
+{
+ int tmp ;
+ int m ;
+ unsigned char STOFS0, STOFS1;
+
+ m = 1 << state->deci;
+ tmp = (8192 * state->master_clk - 2 * m * rate * 8192 + state->master_clk / 2) / state->master_clk;
+
+ STOFS0 = tmp & 0x0ff;
+ STOFS1 = (tmp & 0xf00) >> 8;
+
+ if (mb86a16_write(state, MB86A16_SRATE1, (state->deci << 2) |
+ (state->csel << 1) |
+ state->rsel) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_SRATE2, STOFS0) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_SRATE3, STOFS1) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -1;
+}
+
+static int srst(struct mb86a16_state *state)
+{
+ if (mb86a16_write(state, MB86A16_RESET, 0x04) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+
+}
+
+static int afcex_data_set(struct mb86a16_state *state,
+ unsigned char AFCEX_L,
+ unsigned char AFCEX_H)
+{
+ if (mb86a16_write(state, MB86A16_AFCEXL, AFCEX_L) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_AFCEXH, AFCEX_H) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+
+ return -1;
+}
+
+static int afcofs_data_set(struct mb86a16_state *state,
+ unsigned char AFCEX_L,
+ unsigned char AFCEX_H)
+{
+ if (mb86a16_write(state, 0x58, AFCEX_L) < 0)
+ goto err;
+ if (mb86a16_write(state, 0x59, AFCEX_H) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int stlp_set(struct mb86a16_state *state,
+ unsigned char STRAS,
+ unsigned char STRBS)
+{
+ if (mb86a16_write(state, MB86A16_STRFILTCOEF1, (STRBS << 3) | (STRAS)) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int Vi_set(struct mb86a16_state *state, unsigned char ETH, unsigned char VIA)
+{
+ if (mb86a16_write(state, MB86A16_VISET2, 0x04) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_VISET3, 0xf5) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int initial_set(struct mb86a16_state *state)
+{
+ if (stlp_set(state, 5, 7))
+ goto err;
+
+ udelay(100);
+ if (afcex_data_set(state, 0, 0))
+ goto err;
+
+ udelay(100);
+ if (afcofs_data_set(state, 0, 0))
+ goto err;
+
+ udelay(100);
+ if (mb86a16_write(state, MB86A16_CRLFILTCOEF1, 0x16) < 0)
+ goto err;
+ if (mb86a16_write(state, 0x2f, 0x21) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_VIMAG, 0x38) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS1, 0x00) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS2, 0x1c) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS3, 0x20) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS4, 0x1e) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS5, 0x23) < 0)
+ goto err;
+ if (mb86a16_write(state, 0x54, 0xff) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_TSOUT, 0x00) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int S01T_set(struct mb86a16_state *state,
+ unsigned char s1t,
+ unsigned s0t)
+{
+ if (mb86a16_write(state, 0x33, (s1t << 3) | s0t) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+
+static int EN_set(struct mb86a16_state *state,
+ int cren,
+ int afcen)
+{
+ unsigned char val;
+
+ val = 0x7a | (cren << 7) | (afcen << 2);
+ if (mb86a16_write(state, 0x49, val) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int AFCEXEN_set(struct mb86a16_state *state,
+ int afcexen,
+ int smrt)
+{
+ unsigned char AFCA ;
+
+ if (smrt > 18875)
+ AFCA = 4;
+ else if (smrt > 9375)
+ AFCA = 3;
+ else if (smrt > 2250)
+ AFCA = 2;
+ else
+ AFCA = 1;
+
+ if (mb86a16_write(state, 0x2a, 0x02 | (afcexen << 5) | (AFCA << 2)) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int DAGC_data_set(struct mb86a16_state *state,
+ unsigned char DAGCA,
+ unsigned char DAGCW)
+{
+ if (mb86a16_write(state, 0x2d, (DAGCA << 3) | DAGCW) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static void smrt_info_get(struct mb86a16_state *state, int rate)
+{
+ if (rate >= 37501) {
+ state->deci = 0; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 30001) {
+ state->deci = 0; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 26251) {
+ state->deci = 0; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 22501) {
+ state->deci = 0; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 18751) {
+ state->deci = 1; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 15001) {
+ state->deci = 1; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 13126) {
+ state->deci = 1; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 11251) {
+ state->deci = 1; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 9376) {
+ state->deci = 2; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 7501) {
+ state->deci = 2; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 6563) {
+ state->deci = 2; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 5626) {
+ state->deci = 2; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 4688) {
+ state->deci = 3; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 3751) {
+ state->deci = 3; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 3282) {
+ state->deci = 3; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 2814) {
+ state->deci = 3; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 2344) {
+ state->deci = 4; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 1876) {
+ state->deci = 4; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 1641) {
+ state->deci = 4; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 1407) {
+ state->deci = 4; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 1172) {
+ state->deci = 5; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 939) {
+ state->deci = 5; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 821) {
+ state->deci = 5; state->csel = 1; state->rsel = 0;
+ } else {
+ state->deci = 5; state->csel = 1; state->rsel = 1;
+ }
+
+ if (state->csel == 0)
+ state->master_clk = 92000;
+ else
+ state->master_clk = 61333;
+
+}
+
+static int signal_det(struct mb86a16_state *state,
+ int smrt,
+ unsigned char *SIG)
+{
+
+ int ret ;
+ int smrtd ;
+ int wait_sym ;
+
+ u32 wait_t;
+ unsigned char S[3] ;
+ int i ;
+
+ if (*SIG > 45) {
+ if (CNTM_set(state, 2, 1, 2) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+ return -1;
+ }
+ wait_sym = 40000;
+ } else {
+ if (CNTM_set(state, 3, 1, 2) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+ return -1;
+ }
+ wait_sym = 80000;
+ }
+ for (i = 0; i < 3; i++) {
+ if (i == 0)
+ smrtd = smrt * 98 / 100;
+ else if (i == 1)
+ smrtd = smrt;
+ else
+ smrtd = smrt * 102 / 100;
+ smrt_info_get(state, smrtd);
+ smrt_set(state, smrtd);
+ srst(state);
+ wait_t = (wait_sym + 99 * smrtd / 100) / smrtd;
+ if (wait_t == 0)
+ wait_t = 1;
+ msleep_interruptible(10);
+ if (mb86a16_read(state, 0x37, &(S[i])) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+ }
+ if ((S[1] > S[0] * 112 / 100) &&
+ (S[1] > S[2] * 112 / 100)) {
+
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+ *SIG = S[1];
+
+ if (CNTM_set(state, 0, 1, 2) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+ return -1;
+ }
+
+ return ret;
+}
+
+static int rf_val_set(struct mb86a16_state *state,
+ int f,
+ int smrt,
+ unsigned char R)
+{
+ unsigned char C, F, B;
+ int M;
+ unsigned char rf_val[5];
+ int ack = -1;
+
+ if (smrt > 37750)
+ C = 1;
+ else if (smrt > 18875)
+ C = 2;
+ else if (smrt > 5500)
+ C = 3;
+ else
+ C = 4;
+
+ if (smrt > 30500)
+ F = 3;
+ else if (smrt > 9375)
+ F = 1;
+ else if (smrt > 4625)
+ F = 0;
+ else
+ F = 2;
+
+ if (f < 1060)
+ B = 0;
+ else if (f < 1175)
+ B = 1;
+ else if (f < 1305)
+ B = 2;
+ else if (f < 1435)
+ B = 3;
+ else if (f < 1570)
+ B = 4;
+ else if (f < 1715)
+ B = 5;
+ else if (f < 1845)
+ B = 6;
+ else if (f < 1980)
+ B = 7;
+ else if (f < 2080)
+ B = 8;
+ else
+ B = 9;
+
+ M = f * (1 << R) / 2;
+
+ rf_val[0] = 0x01 | (C << 3) | (F << 1);
+ rf_val[1] = (R << 5) | ((M & 0x1f000) >> 12);
+ rf_val[2] = (M & 0x00ff0) >> 4;
+ rf_val[3] = ((M & 0x0000f) << 4) | B;
+
+ /* Frequency Set */
+ if (mb86a16_write(state, 0x21, rf_val[0]) < 0)
+ ack = 0;
+ if (mb86a16_write(state, 0x22, rf_val[1]) < 0)
+ ack = 0;
+ if (mb86a16_write(state, 0x23, rf_val[2]) < 0)
+ ack = 0;
+ if (mb86a16_write(state, 0x24, rf_val[3]) < 0)
+ ack = 0;
+ if (mb86a16_write(state, 0x25, 0x01) < 0)
+ ack = 0;
+ if (ack == 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "RF Setup - I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int afcerr_chk(struct mb86a16_state *state)
+{
+ unsigned char AFCM_L, AFCM_H ;
+ int AFCM ;
+ int afcm, afcerr ;
+
+ if (mb86a16_read(state, 0x0e, &AFCM_L) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x0f, &AFCM_H) != 2)
+ goto err;
+
+ AFCM = (AFCM_H << 8) + AFCM_L;
+
+ if (AFCM > 2048)
+ afcm = AFCM - 4096;
+ else
+ afcm = AFCM;
+ afcerr = afcm * state->master_clk / 8192;
+
+ return afcerr;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int dagcm_val_get(struct mb86a16_state *state)
+{
+ int DAGCM;
+ unsigned char DAGCM_H, DAGCM_L;
+
+ if (mb86a16_read(state, 0x45, &DAGCM_L) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x46, &DAGCM_H) != 2)
+ goto err;
+
+ DAGCM = (DAGCM_H << 8) + DAGCM_L;
+
+ return DAGCM;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int mb86a16_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ u8 stat, stat2;
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ *status = 0;
+
+ if (mb86a16_read(state, MB86A16_SIG1, &stat) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_SIG2, &stat2) != 2)
+ goto err;
+ if ((stat > 25) && (stat2 > 25))
+ *status |= FE_HAS_SIGNAL;
+ if ((stat > 45) && (stat2 > 45))
+ *status |= FE_HAS_CARRIER;
+
+ if (mb86a16_read(state, MB86A16_STATUS, &stat) != 2)
+ goto err;
+
+ if (stat & 0x01)
+ *status |= FE_HAS_SYNC;
+ if (stat & 0x01)
+ *status |= FE_HAS_VITERBI;
+
+ if (mb86a16_read(state, MB86A16_FRAMESYNC, &stat) != 2)
+ goto err;
+
+ if ((stat & 0x0f) && (*status & FE_HAS_VITERBI))
+ *status |= FE_HAS_LOCK;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int sync_chk(struct mb86a16_state *state,
+ unsigned char *VIRM)
+{
+ unsigned char val;
+ int sync;
+
+ if (mb86a16_read(state, 0x0d, &val) != 2)
+ goto err;
+
+ dprintk(verbose, MB86A16_INFO, 1, "Status = %02x,", val);
+ sync = val & 0x01;
+ *VIRM = (val & 0x1c) >> 2;
+
+ return sync;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+
+}
+
+static int freqerr_chk(struct mb86a16_state *state,
+ int fTP,
+ int smrt,
+ int unit)
+{
+ unsigned char CRM, AFCML, AFCMH;
+ unsigned char temp1, temp2, temp3;
+ int crm, afcm, AFCM;
+ int crrerr, afcerr; /* kHz */
+ int frqerr; /* MHz */
+ int afcen, afcexen = 0;
+ int R, M, fOSC, fOSC_OFS;
+
+ if (mb86a16_read(state, 0x43, &CRM) != 2)
+ goto err;
+
+ if (CRM > 127)
+ crm = CRM - 256;
+ else
+ crm = CRM;
+
+ crrerr = smrt * crm / 256;
+ if (mb86a16_read(state, 0x49, &temp1) != 2)
+ goto err;
+
+ afcen = (temp1 & 0x04) >> 2;
+ if (afcen == 0) {
+ if (mb86a16_read(state, 0x2a, &temp1) != 2)
+ goto err;
+ afcexen = (temp1 & 0x20) >> 5;
+ }
+
+ if (afcen == 1) {
+ if (mb86a16_read(state, 0x0e, &AFCML) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x0f, &AFCMH) != 2)
+ goto err;
+ } else if (afcexen == 1) {
+ if (mb86a16_read(state, 0x2b, &AFCML) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x2c, &AFCMH) != 2)
+ goto err;
+ }
+ if ((afcen == 1) || (afcexen == 1)) {
+ smrt_info_get(state, smrt);
+ AFCM = ((AFCMH & 0x01) << 8) + AFCML;
+ if (AFCM > 255)
+ afcm = AFCM - 512;
+ else
+ afcm = AFCM;
+
+ afcerr = afcm * state->master_clk / 8192;
+ } else
+ afcerr = 0;
+
+ if (mb86a16_read(state, 0x22, &temp1) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x23, &temp2) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x24, &temp3) != 2)
+ goto err;
+
+ R = (temp1 & 0xe0) >> 5;
+ M = ((temp1 & 0x1f) << 12) + (temp2 << 4) + (temp3 >> 4);
+ if (R == 0)
+ fOSC = 2 * M;
+ else
+ fOSC = M;
+
+ fOSC_OFS = fOSC - fTP;
+
+ if (unit == 0) { /* MHz */
+ if (crrerr + afcerr + fOSC_OFS * 1000 >= 0)
+ frqerr = (crrerr + afcerr + fOSC_OFS * 1000 + 500) / 1000;
+ else
+ frqerr = (crrerr + afcerr + fOSC_OFS * 1000 - 500) / 1000;
+ } else { /* kHz */
+ frqerr = crrerr + afcerr + fOSC_OFS * 1000;
+ }
+
+ return frqerr;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static unsigned char vco_dev_get(struct mb86a16_state *state, int smrt)
+{
+ unsigned char R;
+
+ if (smrt > 9375)
+ R = 0;
+ else
+ R = 1;
+
+ return R;
+}
+
+static void swp_info_get(struct mb86a16_state *state,
+ int fOSC_start,
+ int smrt,
+ int v, int R,
+ int swp_ofs,
+ int *fOSC,
+ int *afcex_freq,
+ unsigned char *AFCEX_L,
+ unsigned char *AFCEX_H)
+{
+ int AFCEX ;
+ int crnt_swp_freq ;
+
+ crnt_swp_freq = fOSC_start * 1000 + v * swp_ofs;
+
+ if (R == 0)
+ *fOSC = (crnt_swp_freq + 1000) / 2000 * 2;
+ else
+ *fOSC = (crnt_swp_freq + 500) / 1000;
+
+ if (*fOSC >= crnt_swp_freq)
+ *afcex_freq = *fOSC * 1000 - crnt_swp_freq;
+ else
+ *afcex_freq = crnt_swp_freq - *fOSC * 1000;
+
+ AFCEX = *afcex_freq * 8192 / state->master_clk;
+ *AFCEX_L = AFCEX & 0x00ff;
+ *AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+
+static int swp_freq_calcuation(struct mb86a16_state *state, int i, int v, int *V, int vmax, int vmin,
+ int SIGMIN, int fOSC, int afcex_freq, int swp_ofs, unsigned char *SIG1)
+{
+ int swp_freq ;
+
+ if ((i % 2 == 1) && (v <= vmax)) {
+ /* positive v (case 1) */
+ if ((v - 1 == vmin) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v - 1) >= 0) &&
+ (*(V + 30 + v - 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v - 1) > SIGMIN)) {
+
+ swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+ *SIG1 = *(V + 30 + v - 1);
+ } else if ((v == vmax) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v - 1) >= 0) &&
+ (*(V + 30 + v) > *(V + 30 + v - 1)) &&
+ (*(V + 30 + v) > SIGMIN)) {
+ /* (case 2) */
+ swp_freq = fOSC * 1000 + afcex_freq;
+ *SIG1 = *(V + 30 + v);
+ } else if ((*(V + 30 + v) > 0) &&
+ (*(V + 30 + v - 1) > 0) &&
+ (*(V + 30 + v - 2) > 0) &&
+ (*(V + 30 + v - 3) > 0) &&
+ (*(V + 30 + v - 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v - 2) > *(V + 30 + v - 3)) &&
+ ((*(V + 30 + v - 1) > SIGMIN) ||
+ (*(V + 30 + v - 2) > SIGMIN))) {
+ /* (case 3) */
+ if (*(V + 30 + v - 1) >= *(V + 30 + v - 2)) {
+ swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+ *SIG1 = *(V + 30 + v - 1);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq - swp_ofs * 2;
+ *SIG1 = *(V + 30 + v - 2);
+ }
+ } else if ((v == vmax) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v - 1) >= 0) &&
+ (*(V + 30 + v - 2) >= 0) &&
+ (*(V + 30 + v) > *(V + 30 + v - 2)) &&
+ (*(V + 30 + v - 1) > *(V + 30 + v - 2)) &&
+ ((*(V + 30 + v) > SIGMIN) ||
+ (*(V + 30 + v - 1) > SIGMIN))) {
+ /* (case 4) */
+ if (*(V + 30 + v) >= *(V + 30 + v - 1)) {
+ swp_freq = fOSC * 1000 + afcex_freq;
+ *SIG1 = *(V + 30 + v);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+ *SIG1 = *(V + 30 + v - 1);
+ }
+ } else {
+ swp_freq = -1 ;
+ }
+ } else if ((i % 2 == 0) && (v >= vmin)) {
+ /* Negative v (case 1) */
+ if ((*(V + 30 + v) > 0) &&
+ (*(V + 30 + v + 1) > 0) &&
+ (*(V + 30 + v + 2) > 0) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v + 2)) &&
+ (*(V + 30 + v + 1) > SIGMIN)) {
+
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v + 1);
+ } else if ((v + 1 == vmax) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v + 1) >= 0) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v + 1) > SIGMIN)) {
+ /* (case 2) */
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v);
+ } else if ((v == vmin) &&
+ (*(V + 30 + v) > 0) &&
+ (*(V + 30 + v + 1) > 0) &&
+ (*(V + 30 + v + 2) > 0) &&
+ (*(V + 30 + v) > *(V + 30 + v + 1)) &&
+ (*(V + 30 + v) > *(V + 30 + v + 2)) &&
+ (*(V + 30 + v) > SIGMIN)) {
+ /* (case 3) */
+ swp_freq = fOSC * 1000 + afcex_freq;
+ *SIG1 = *(V + 30 + v);
+ } else if ((*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v + 1) >= 0) &&
+ (*(V + 30 + v + 2) >= 0) &&
+ (*(V + 30 + v + 3) >= 0) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v + 2) > *(V + 30 + v + 3)) &&
+ ((*(V + 30 + v + 1) > SIGMIN) ||
+ (*(V + 30 + v + 2) > SIGMIN))) {
+ /* (case 4) */
+ if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v + 1);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2;
+ *SIG1 = *(V + 30 + v + 2);
+ }
+ } else if ((*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v + 1) >= 0) &&
+ (*(V + 30 + v + 2) >= 0) &&
+ (*(V + 30 + v + 3) >= 0) &&
+ (*(V + 30 + v) > *(V + 30 + v + 2)) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v + 2)) &&
+ (*(V + 30 + v) > *(V + 30 + v + 3)) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v + 3)) &&
+ ((*(V + 30 + v) > SIGMIN) ||
+ (*(V + 30 + v + 1) > SIGMIN))) {
+ /* (case 5) */
+ if (*(V + 30 + v) >= *(V + 30 + v + 1)) {
+ swp_freq = fOSC * 1000 + afcex_freq;
+ *SIG1 = *(V + 30 + v);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v + 1);
+ }
+ } else if ((v + 2 == vmin) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v + 1) >= 0) &&
+ (*(V + 30 + v + 2) >= 0) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v + 2) > *(V + 30 + v)) &&
+ ((*(V + 30 + v + 1) > SIGMIN) ||
+ (*(V + 30 + v + 2) > SIGMIN))) {
+ /* (case 6) */
+ if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v + 1);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2;
+ *SIG1 = *(V + 30 + v + 2);
+ }
+ } else if ((vmax == 0) && (vmin == 0) && (*(V + 30 + v) > SIGMIN)) {
+ swp_freq = fOSC * 1000;
+ *SIG1 = *(V + 30 + v);
+ } else
+ swp_freq = -1;
+ } else
+ swp_freq = -1;
+
+ return swp_freq;
+}
+
+static void swp_info_get2(struct mb86a16_state *state,
+ int smrt,
+ int R,
+ int swp_freq,
+ int *afcex_freq,
+ int *fOSC,
+ unsigned char *AFCEX_L,
+ unsigned char *AFCEX_H)
+{
+ int AFCEX ;
+
+ if (R == 0)
+ *fOSC = (swp_freq + 1000) / 2000 * 2;
+ else
+ *fOSC = (swp_freq + 500) / 1000;
+
+ if (*fOSC >= swp_freq)
+ *afcex_freq = *fOSC * 1000 - swp_freq;
+ else
+ *afcex_freq = swp_freq - *fOSC * 1000;
+
+ AFCEX = *afcex_freq * 8192 / state->master_clk;
+ *AFCEX_L = AFCEX & 0x00ff;
+ *AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+static void afcex_info_get(struct mb86a16_state *state,
+ int afcex_freq,
+ unsigned char *AFCEX_L,
+ unsigned char *AFCEX_H)
+{
+ int AFCEX ;
+
+ AFCEX = afcex_freq * 8192 / state->master_clk;
+ *AFCEX_L = AFCEX & 0x00ff;
+ *AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+static int SEQ_set(struct mb86a16_state *state, unsigned char loop)
+{
+ /* SLOCK0 = 0 */
+ if (mb86a16_write(state, 0x32, 0x02 | (loop << 2)) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int iq_vt_set(struct mb86a16_state *state, unsigned char IQINV)
+{
+ /* Viterbi Rate, IQ Settings */
+ if (mb86a16_write(state, 0x06, 0xdf | (IQINV << 5)) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int FEC_srst(struct mb86a16_state *state)
+{
+ if (mb86a16_write(state, MB86A16_RESET, 0x02) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int S2T_set(struct mb86a16_state *state, unsigned char S2T)
+{
+ if (mb86a16_write(state, 0x34, 0x70 | S2T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int S45T_set(struct mb86a16_state *state, unsigned char S4T, unsigned char S5T)
+{
+ if (mb86a16_write(state, 0x35, 0x00 | (S5T << 4) | S4T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+
+static int mb86a16_set_fe(struct mb86a16_state *state)
+{
+ u8 agcval, cnmval;
+
+ int i, j;
+ int fOSC = 0;
+ int fOSC_start = 0;
+ int wait_t;
+ int fcp;
+ int swp_ofs;
+ int V[60];
+ u8 SIG1MIN;
+
+ unsigned char CREN, AFCEN, AFCEXEN;
+ unsigned char SIG1;
+ unsigned char TIMINT1, TIMINT2, TIMEXT;
+ unsigned char S0T, S1T;
+ unsigned char S2T;
+/* unsigned char S2T, S3T; */
+ unsigned char S4T, S5T;
+ unsigned char AFCEX_L, AFCEX_H;
+ unsigned char R;
+ unsigned char VIRM;
+ unsigned char ETH, VIA;
+ unsigned char junk;
+
+ int loop;
+ int ftemp;
+ int v, vmax, vmin;
+ int vmax_his, vmin_his;
+ int swp_freq, prev_swp_freq[20];
+ int prev_freq_num;
+ int signal_dupl;
+ int afcex_freq;
+ int signal;
+ int afcerr;
+ int temp_freq, delta_freq;
+ int dagcm[4];
+ int smrt_d;
+/* int freq_err; */
+ int n;
+ int ret = -1;
+ int sync;
+
+ dprintk(verbose, MB86A16_INFO, 1, "freq=%d Mhz, symbrt=%d Ksps", state->frequency, state->srate);
+
+ fcp = 3000;
+ swp_ofs = state->srate / 4;
+
+ for (i = 0; i < 60; i++)
+ V[i] = -1;
+
+ for (i = 0; i < 20; i++)
+ prev_swp_freq[i] = 0;
+
+ SIG1MIN = 25;
+
+ for (n = 0; ((n < 3) && (ret == -1)); n++) {
+ SEQ_set(state, 0);
+ iq_vt_set(state, 0);
+
+ CREN = 0;
+ AFCEN = 0;
+ AFCEXEN = 1;
+ TIMINT1 = 0;
+ TIMINT2 = 1;
+ TIMEXT = 2;
+ S1T = 0;
+ S0T = 0;
+
+ if (initial_set(state) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "initial set failed");
+ return -1;
+ }
+ if (DAGC_data_set(state, 3, 2) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+ return -1;
+ }
+ if (EN_set(state, CREN, AFCEN) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+ return -1; /* (0, 0) */
+ }
+ if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+ return -1; /* (1, smrt) = (1, symbolrate) */
+ }
+ if (CNTM_set(state, TIMINT1, TIMINT2, TIMEXT) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "CNTM set error");
+ return -1; /* (0, 1, 2) */
+ }
+ if (S01T_set(state, S1T, S0T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+ return -1; /* (0, 0) */
+ }
+ smrt_info_get(state, state->srate);
+ if (smrt_set(state, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt info get error");
+ return -1;
+ }
+
+ R = vco_dev_get(state, state->srate);
+ if (R == 1)
+ fOSC_start = state->frequency;
+
+ else if (R == 0) {
+ if (state->frequency % 2 == 0) {
+ fOSC_start = state->frequency;
+ } else {
+ fOSC_start = state->frequency + 1;
+ if (fOSC_start > 2150)
+ fOSC_start = state->frequency - 1;
+ }
+ }
+ loop = 1;
+ ftemp = fOSC_start * 1000;
+ vmax = 0 ;
+ while (loop == 1) {
+ ftemp = ftemp + swp_ofs;
+ vmax++;
+
+ /* Upper bound */
+ if (ftemp > 2150000) {
+ loop = 0;
+ vmax--;
+ } else {
+ if ((ftemp == 2150000) ||
+ (ftemp - state->frequency * 1000 >= fcp + state->srate / 4))
+ loop = 0;
+ }
+ }
+
+ loop = 1;
+ ftemp = fOSC_start * 1000;
+ vmin = 0 ;
+ while (loop == 1) {
+ ftemp = ftemp - swp_ofs;
+ vmin--;
+
+ /* Lower bound */
+ if (ftemp < 950000) {
+ loop = 0;
+ vmin++;
+ } else {
+ if ((ftemp == 950000) ||
+ (state->frequency * 1000 - ftemp >= fcp + state->srate / 4))
+ loop = 0;
+ }
+ }
+
+ wait_t = (8000 + state->srate / 2) / state->srate;
+ if (wait_t == 0)
+ wait_t = 1;
+
+ i = 0;
+ j = 0;
+ prev_freq_num = 0;
+ loop = 1;
+ signal = 0;
+ vmax_his = 0;
+ vmin_his = 0;
+ v = 0;
+
+ while (loop == 1) {
+ swp_info_get(state, fOSC_start, state->srate,
+ v, R, swp_ofs, &fOSC,
+ &afcex_freq, &AFCEX_L, &AFCEX_H);
+
+ udelay(100);
+ if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ udelay(100);
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+ return -1;
+ }
+ if (srst(state) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+ return -1;
+ }
+ msleep_interruptible(wait_t);
+
+ if (mb86a16_read(state, 0x37, &SIG1) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -1;
+ }
+ V[30 + v] = SIG1 ;
+ swp_freq = swp_freq_calcuation(state, i, v, V, vmax, vmin,
+ SIG1MIN, fOSC, afcex_freq,
+ swp_ofs, &SIG1); /* changed */
+
+ signal_dupl = 0;
+ for (j = 0; j < prev_freq_num; j++) {
+ if ((ABS(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) {
+ signal_dupl = 1;
+ dprintk(verbose, MB86A16_INFO, 1, "Probably Duplicate Signal, j = %d", j);
+ }
+ }
+ if ((signal_dupl == 0) && (swp_freq > 0) && (ABS(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) {
+ dprintk(verbose, MB86A16_DEBUG, 1, "------ Signal detect ------ [swp_freq=[%07d, srate=%05d]]", swp_freq, state->srate);
+ prev_swp_freq[prev_freq_num] = swp_freq;
+ prev_freq_num++;
+ swp_info_get2(state, state->srate, R, swp_freq,
+ &afcex_freq, &fOSC,
+ &AFCEX_L, &AFCEX_H);
+
+ if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+ return -1;
+ }
+ signal = signal_det(state, state->srate, &SIG1);
+ if (signal == 1) {
+ dprintk(verbose, MB86A16_ERROR, 1, "***** Signal Found *****");
+ loop = 0;
+ } else {
+ dprintk(verbose, MB86A16_ERROR, 1, "!!!!! No signal !!!!!, try again...");
+ smrt_info_get(state, state->srate);
+ if (smrt_set(state, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+ return -1;
+ }
+ }
+ }
+ if (v > vmax)
+ vmax_his = 1 ;
+ if (v < vmin)
+ vmin_his = 1 ;
+ i++;
+
+ if ((i % 2 == 1) && (vmax_his == 1))
+ i++;
+ if ((i % 2 == 0) && (vmin_his == 1))
+ i++;
+
+ if (i % 2 == 1)
+ v = (i + 1) / 2;
+ else
+ v = -i / 2;
+
+ if ((vmax_his == 1) && (vmin_his == 1))
+ loop = 0 ;
+ }
+
+ if (signal == 1) {
+ dprintk(verbose, MB86A16_INFO, 1, " Start Freq Error Check");
+ S1T = 7 ;
+ S0T = 1 ;
+ CREN = 0 ;
+ AFCEN = 1 ;
+ AFCEXEN = 0 ;
+
+ if (S01T_set(state, S1T, S0T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+ return -1;
+ }
+ smrt_info_get(state, state->srate);
+ if (smrt_set(state, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+ return -1;
+ }
+ if (EN_set(state, CREN, AFCEN) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+ return -1;
+ }
+ if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+ return -1;
+ }
+ afcex_info_get(state, afcex_freq, &AFCEX_L, &AFCEX_H);
+ if (afcofs_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCOFS data set error");
+ return -1;
+ }
+ if (srst(state) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+ return -1;
+ }
+ /* delay 4~200 */
+ wait_t = 200000 / state->master_clk + 200000 / state->srate;
+ msleep(wait_t);
+ afcerr = afcerr_chk(state);
+ if (afcerr == -1)
+ return -1;
+
+ swp_freq = fOSC * 1000 + afcerr ;
+ AFCEXEN = 1 ;
+ if (state->srate >= 1500)
+ smrt_d = state->srate / 3;
+ else
+ smrt_d = state->srate / 2;
+ smrt_info_get(state, smrt_d);
+ if (smrt_set(state, smrt_d) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+ return -1;
+ }
+ if (AFCEXEN_set(state, AFCEXEN, smrt_d) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+ return -1;
+ }
+ R = vco_dev_get(state, smrt_d);
+ if (DAGC_data_set(state, 2, 0) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+ return -1;
+ }
+ for (i = 0; i < 3; i++) {
+ temp_freq = swp_freq + (i - 1) * state->srate / 8;
+ swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+ if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+ return -1;
+ }
+ wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+ msleep(wait_t);
+ dagcm[i] = dagcm_val_get(state);
+ }
+ if ((dagcm[0] > dagcm[1]) &&
+ (dagcm[0] > dagcm[2]) &&
+ (dagcm[0] - dagcm[1] > 2 * (dagcm[2] - dagcm[1]))) {
+
+ temp_freq = swp_freq - 2 * state->srate / 8;
+ swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+ if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set");
+ return -1;
+ }
+ wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+ msleep(wait_t);
+ dagcm[3] = dagcm_val_get(state);
+ if (dagcm[3] > dagcm[1])
+ delta_freq = (dagcm[2] - dagcm[0] + dagcm[1] - dagcm[3]) * state->srate / 300;
+ else
+ delta_freq = 0;
+ } else if ((dagcm[2] > dagcm[1]) &&
+ (dagcm[2] > dagcm[0]) &&
+ (dagcm[2] - dagcm[1] > 2 * (dagcm[0] - dagcm[1]))) {
+
+ temp_freq = swp_freq + 2 * state->srate / 8;
+ swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+ if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set");
+ return -1;
+ }
+ wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+ msleep(wait_t);
+ dagcm[3] = dagcm_val_get(state);
+ if (dagcm[3] > dagcm[1])
+ delta_freq = (dagcm[2] - dagcm[0] + dagcm[3] - dagcm[1]) * state->srate / 300;
+ else
+ delta_freq = 0 ;
+
+ } else {
+ delta_freq = 0 ;
+ }
+ dprintk(verbose, MB86A16_INFO, 1, "SWEEP Frequency = %d", swp_freq);
+ swp_freq += delta_freq;
+ dprintk(verbose, MB86A16_INFO, 1, "Adjusting .., DELTA Freq = %d, SWEEP Freq=%d", delta_freq, swp_freq);
+ if (ABS(state->frequency * 1000 - swp_freq) > 3800) {
+ dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL !");
+ } else {
+
+ S1T = 0;
+ S0T = 3;
+ CREN = 1;
+ AFCEN = 0;
+ AFCEXEN = 1;
+
+ if (S01T_set(state, S1T, S0T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+ return -1;
+ }
+ if (DAGC_data_set(state, 0, 0) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+ return -1;
+ }
+ R = vco_dev_get(state, state->srate);
+ smrt_info_get(state, state->srate);
+ if (smrt_set(state, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+ return -1;
+ }
+ if (EN_set(state, CREN, AFCEN) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+ return -1;
+ }
+ if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+ return -1;
+ }
+ swp_info_get2(state, state->srate, R, swp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+ if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+ return -1;
+ }
+ if (srst(state) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+ return -1;
+ }
+ wait_t = 7 + (10000 + state->srate / 2) / state->srate;
+ if (wait_t == 0)
+ wait_t = 1;
+ msleep_interruptible(wait_t);
+ if (mb86a16_read(state, 0x37, &SIG1) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ if (SIG1 > 110) {
+ S2T = 4; S4T = 1; S5T = 6; ETH = 4; VIA = 6;
+ wait_t = 7 + (917504 + state->srate / 2) / state->srate;
+ } else if (SIG1 > 105) {
+ S2T = 4; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+ wait_t = 7 + (1048576 + state->srate / 2) / state->srate;
+ } else if (SIG1 > 85) {
+ S2T = 5; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+ wait_t = 7 + (1310720 + state->srate / 2) / state->srate;
+ } else if (SIG1 > 65) {
+ S2T = 6; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+ wait_t = 7 + (1572864 + state->srate / 2) / state->srate;
+ } else {
+ S2T = 7; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+ wait_t = 7 + (2097152 + state->srate / 2) / state->srate;
+ }
+ wait_t *= 2; /* FOS */
+ S2T_set(state, S2T);
+ S45T_set(state, S4T, S5T);
+ Vi_set(state, ETH, VIA);
+ srst(state);
+ msleep_interruptible(wait_t);
+ sync = sync_chk(state, &VIRM);
+ dprintk(verbose, MB86A16_INFO, 1, "-------- Viterbi=[%d] SYNC=[%d] ---------", VIRM, sync);
+ if (VIRM) {
+ if (VIRM == 4) {
+ /* 5/6 */
+ if (SIG1 > 110)
+ wait_t = (786432 + state->srate / 2) / state->srate;
+ else
+ wait_t = (1572864 + state->srate / 2) / state->srate;
+ if (state->srate < 5000)
+ /* FIXME ! , should be a long wait ! */
+ msleep_interruptible(wait_t);
+ else
+ msleep_interruptible(wait_t);
+
+ if (sync_chk(state, &junk) == 0) {
+ iq_vt_set(state, 1);
+ FEC_srst(state);
+ }
+ }
+ /* 1/2, 2/3, 3/4, 7/8 */
+ if (SIG1 > 110)
+ wait_t = (786432 + state->srate / 2) / state->srate;
+ else
+ wait_t = (1572864 + state->srate / 2) / state->srate;
+ msleep_interruptible(wait_t);
+ SEQ_set(state, 1);
+ } else {
+ dprintk(verbose, MB86A16_INFO, 1, "NO -- SYNC");
+ SEQ_set(state, 1);
+ ret = -1;
+ }
+ }
+ } else {
+ dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL");
+ ret = -1;
+ }
+
+ sync = sync_chk(state, &junk);
+ if (sync) {
+ dprintk(verbose, MB86A16_INFO, 1, "******* SYNC *******");
+ freqerr_chk(state, state->frequency, state->srate, 1);
+ ret = 0;
+ break;
+ }
+ }
+
+ mb86a16_read(state, 0x15, &agcval);
+ mb86a16_read(state, 0x26, &cnmval);
+ dprintk(verbose, MB86A16_INFO, 1, "AGC = %02x CNM = %02x", agcval, cnmval);
+
+ return ret;
+}
+
+static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe,
+ struct dvb_diseqc_master_cmd *cmd)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+ int i;
+ u8 regs;
+
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0)
+ goto err;
+
+ regs = 0x18;
+
+ if (cmd->msg_len > 5 || cmd->msg_len < 4)
+ return -EINVAL;
+
+ for (i = 0; i < cmd->msg_len; i++) {
+ if (mb86a16_write(state, regs, cmd->msg[i]) < 0)
+ goto err;
+
+ regs++;
+ }
+ i += 0x90;
+
+ msleep_interruptible(10);
+
+ if (mb86a16_write(state, MB86A16_DCC1, i) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ switch (burst) {
+ case SEC_MINI_A:
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+ MB86A16_DCC1_TBEN |
+ MB86A16_DCC1_TBO) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+ goto err;
+ break;
+ case SEC_MINI_B:
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+ MB86A16_DCC1_TBEN) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+ goto err;
+ break;
+ }
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int mb86a16_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ switch (tone) {
+ case SEC_TONE_ON:
+ if (mb86a16_write(state, MB86A16_TONEOUT2, 0x00) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+ MB86A16_DCC1_CTOE) < 0)
+
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+ goto err;
+ break;
+ case SEC_TONE_OFF:
+ if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0)
+ goto err;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ state->frequency = p->frequency / 1000;
+ state->srate = p->u.qpsk.symbol_rate / 1000;
+
+ if (!mb86a16_set_fe(state)) {
+ dprintk(verbose, MB86A16_ERROR, 1, "Succesfully acquired LOCK");
+ return DVBFE_ALGO_SEARCH_SUCCESS;
+ }
+
+ dprintk(verbose, MB86A16_ERROR, 1, "Lock acquisition failed!");
+ return DVBFE_ALGO_SEARCH_FAILED;
+}
+
+static void mb86a16_release(struct dvb_frontend *fe)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static int mb86a16_init(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static int mb86a16_sleep(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static int mb86a16_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ u8 ber_mon, ber_tab, ber_lsb, ber_mid, ber_msb, ber_tim, ber_rst;
+ u32 timer;
+
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ *ber = 0;
+ if (mb86a16_read(state, MB86A16_BERMON, &ber_mon) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_BERTAB, &ber_tab) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_BERLSB, &ber_lsb) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_BERMID, &ber_mid) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_BERMSB, &ber_msb) != 2)
+ goto err;
+ /* BER monitor invalid when BER_EN = 0 */
+ if (ber_mon & 0x04) {
+ /* coarse, fast calculation */
+ *ber = ber_tab & 0x1f;
+ dprintk(verbose, MB86A16_DEBUG, 1, "BER coarse=[0x%02x]", *ber);
+ if (ber_mon & 0x01) {
+ /*
+ * BER_SEL = 1, The monitored BER is the estimated
+ * value with a Reed-Solomon decoder error amount at
+ * the deinterleaver output.
+ * monitored BER is expressed as a 20 bit output in total
+ */
+ ber_rst = ber_mon >> 3;
+ *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb;
+ if (ber_rst == 0)
+ timer = 12500000;
+ if (ber_rst == 1)
+ timer = 25000000;
+ if (ber_rst == 2)
+ timer = 50000000;
+ if (ber_rst == 3)
+ timer = 100000000;
+
+ *ber /= timer;
+ dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber);
+ } else {
+ /*
+ * BER_SEL = 0, The monitored BER is the estimated
+ * value with a Viterbi decoder error amount at the
+ * QPSK demodulator output.
+ * monitored BER is expressed as a 24 bit output in total
+ */
+ ber_tim = ber_mon >> 1;
+ *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb;
+ if (ber_tim == 0)
+ timer = 16;
+ if (ber_tim == 1)
+ timer = 24;
+
+ *ber /= 2 ^ timer;
+ dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber);
+ }
+ }
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int mb86a16_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ u8 agcm = 0;
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ *strength = 0;
+ if (mb86a16_read(state, MB86A16_AGCM, &agcm) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ *strength = ((0xff - agcm) * 100) / 256;
+ dprintk(verbose, MB86A16_DEBUG, 1, "Signal strength=[%d %%]", (u8) *strength);
+ *strength = (0xffff - 0xff) + agcm;
+
+ return 0;
+}
+
+struct cnr {
+ u8 cn_reg;
+ u8 cn_val;
+};
+
+static const struct cnr cnr_tab[] = {
+ { 35, 2 },
+ { 40, 3 },
+ { 50, 4 },
+ { 60, 5 },
+ { 70, 6 },
+ { 80, 7 },
+ { 92, 8 },
+ { 103, 9 },
+ { 115, 10 },
+ { 138, 12 },
+ { 162, 15 },
+ { 180, 18 },
+ { 185, 19 },
+ { 189, 20 },
+ { 195, 22 },
+ { 199, 24 },
+ { 201, 25 },
+ { 202, 26 },
+ { 203, 27 },
+ { 205, 28 },
+ { 208, 30 }
+};
+
+static int mb86a16_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+ int i = 0;
+ int low_tide = 2, high_tide = 30, q_level;
+ u8 cn;
+
+ *snr = 0;
+ if (mb86a16_read(state, 0x26, &cn) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cnr_tab); i++) {
+ if (cn < cnr_tab[i].cn_reg) {
+ *snr = cnr_tab[i].cn_val;
+ break;
+ }
+ }
+ q_level = (*snr * 100) / (high_tide - low_tide);
+ dprintk(verbose, MB86A16_ERROR, 1, "SNR (Quality) = [%d dB], Level=%d %%", *snr, q_level);
+ *snr = (0xffff - 0xff) + *snr;
+
+ return 0;
+}
+
+static int mb86a16_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ u8 dist;
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ if (mb86a16_read(state, MB86A16_DISTMON, &dist) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+ *ucblocks = dist;
+
+ return 0;
+}
+
+static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe)
+{
+ return DVBFE_ALGO_CUSTOM;
+}
+
+static struct dvb_frontend_ops mb86a16_ops = {
+ .info = {
+ .name = "Fujitsu MB86A16 DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 3000,
+ .frequency_tolerance = 0,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .symbol_rate_tolerance = 500,
+ .caps = 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_QPSK |
+ FE_CAN_FEC_AUTO
+ },
+ .release = mb86a16_release,
+
+ .get_frontend_algo = mb86a16_frontend_algo,
+ .search = mb86a16_search,
+ .read_status = mb86a16_read_status,
+ .init = mb86a16_init,
+ .sleep = mb86a16_sleep,
+ .read_status = mb86a16_read_status,
+
+ .read_ber = mb86a16_read_ber,
+ .read_signal_strength = mb86a16_read_signal_strength,
+ .read_snr = mb86a16_read_snr,
+ .read_ucblocks = mb86a16_read_ucblocks,
+
+ .diseqc_send_master_cmd = mb86a16_send_diseqc_msg,
+ .diseqc_send_burst = mb86a16_send_diseqc_burst,
+ .set_tone = mb86a16_set_tone,
+};
+
+struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+ struct i2c_adapter *i2c_adap)
+{
+ u8 dev_id = 0;
+ struct mb86a16_state *state = NULL;
+
+ state = kmalloc(sizeof(struct mb86a16_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ state->config = config;
+ state->i2c_adap = i2c_adap;
+
+ mb86a16_read(state, 0x7f, &dev_id);
+ if (dev_id != 0xfe)
+ goto error;
+
+ memcpy(&state->frontend.ops, &mb86a16_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+ state->frontend.ops.set_voltage = state->config->set_voltage;
+
+ return &state->frontend;
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(mb86a16_attach);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Manu Abraham");
diff --git a/drivers/media/dvb/frontends/mb86a16.h b/drivers/media/dvb/frontends/mb86a16.h
new file mode 100644
index 000000000000..6ea8c376394f
--- /dev/null
+++ b/drivers/media/dvb/frontends/mb86a16.h
@@ -0,0 +1,52 @@
+/*
+ Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MB86A16_H
+#define __MB86A16_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+
+struct mb86a16_config {
+ u8 demod_address;
+
+ int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+};
+
+
+
+#if defined(CONFIG_DVB_MB86A16) || (defined(CONFIG_DVB_MB86A16_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+ struct i2c_adapter *i2c_adap);
+
+#else
+
+static inline struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+ struct i2c_adapter *i2c_adap)
+{
+ printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+
+#endif /* CONFIG_DVB_MB86A16 */
+
+#endif /* __MB86A16_H */
diff --git a/drivers/media/dvb/frontends/mb86a16_priv.h b/drivers/media/dvb/frontends/mb86a16_priv.h
new file mode 100644
index 000000000000..360a35acfe84
--- /dev/null
+++ b/drivers/media/dvb/frontends/mb86a16_priv.h
@@ -0,0 +1,151 @@
+/*
+ Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MB86A16_PRIV_H
+#define __MB86A16_PRIV_H
+
+#define MB86A16_TSOUT 0x00
+#define MB86A16_TSOUT_HIZSEL (0x01 << 5)
+#define MB86A16_TSOUT_HIZCNTI (0x01 << 4)
+#define MB86A16_TSOUT_MODE (0x01 << 3)
+#define MB86A16_TSOUT_ORDER (0x01 << 2)
+#define MB86A16_TSOUT_ERROR (0x01 << 1)
+#define Mb86A16_TSOUT_EDGE (0x01 << 0)
+
+#define MB86A16_FEC 0x01
+#define MB86A16_FEC_FSYNC (0x01 << 5)
+#define MB86A16_FEC_PCKB8 (0x01 << 4)
+#define MB86A16_FEC_DVDS (0x01 << 3)
+#define MB86A16_FEC_EREN (0x01 << 2)
+#define Mb86A16_FEC_RSEN (0x01 << 1)
+#define MB86A16_FEC_DIEN (0x01 << 0)
+
+#define MB86A16_AGC 0x02
+#define MB86A16_AGC_AGMD (0x01 << 6)
+#define MB86A16_AGC_AGCW (0x0f << 2)
+#define MB86A16_AGC_AGCP (0x01 << 1)
+#define MB86A16_AGC_AGCR (0x01 << 0)
+
+#define MB86A16_SRATE1 0x03
+#define MB86A16_SRATE1_DECI (0x07 << 2)
+#define MB86A16_SRATE1_CSEL (0x01 << 1)
+#define MB86A16_SRATE1_RSEL (0x01 << 0)
+
+#define MB86A16_SRATE2 0x04
+#define MB86A16_SRATE2_STOFSL (0xff << 0)
+
+#define MB86A16_SRATE3 0x05
+#define MB86A16_SRATE2_STOFSH (0xff << 0)
+
+#define MB86A16_VITERBI 0x06
+#define MB86A16_FRAMESYNC 0x07
+#define MB86A16_CRLFILTCOEF1 0x08
+#define MB86A16_CRLFILTCOEF2 0x09
+#define MB86A16_STRFILTCOEF1 0x0a
+#define MB86A16_STRFILTCOEF2 0x0b
+#define MB86A16_RESET 0x0c
+#define MB86A16_STATUS 0x0d
+#define MB86A16_AFCML 0x0e
+#define MB86A16_AFCMH 0x0f
+#define MB86A16_BERMON 0x10
+#define MB86A16_BERTAB 0x11
+#define MB86A16_BERLSB 0x12
+#define MB86A16_BERMID 0x13
+#define MB86A16_BERMSB 0x14
+#define MB86A16_AGCM 0x15
+
+#define MB86A16_DCC1 0x16
+#define MB86A16_DCC1_DISTA (0x01 << 7)
+#define MB86A16_DCC1_PRTY (0x01 << 6)
+#define MB86A16_DCC1_CTOE (0x01 << 5)
+#define MB86A16_DCC1_TBEN (0x01 << 4)
+#define MB86A16_DCC1_TBO (0x01 << 3)
+#define MB86A16_DCC1_NUM (0x07 << 0)
+
+#define MB86A16_DCC2 0x17
+#define MB86A16_DCC2_DCBST (0x01 << 0)
+
+#define MB86A16_DCC3 0x18
+#define MB86A16_DCC3_CODE0 (0xff << 0)
+
+#define MB86A16_DCC4 0x19
+#define MB86A16_DCC4_CODE1 (0xff << 0)
+
+#define MB86A16_DCC5 0x1a
+#define MB86A16_DCC5_CODE2 (0xff << 0)
+
+#define MB86A16_DCC6 0x1b
+#define MB86A16_DCC6_CODE3 (0xff << 0)
+
+#define MB86A16_DCC7 0x1c
+#define MB86A16_DCC7_CODE4 (0xff << 0)
+
+#define MB86A16_DCC8 0x1d
+#define MB86A16_DCC8_CODE5 (0xff << 0)
+
+#define MB86A16_DCCOUT 0x1e
+#define MB86A16_DCCOUT_DISEN (0x01 << 0)
+
+#define MB86A16_TONEOUT1 0x1f
+#define MB86A16_TONE_TDIVL (0xff << 0)
+
+#define MB86A16_TONEOUT2 0x20
+#define MB86A16_TONE_TMD (0x03 << 2)
+#define MB86A16_TONE_TDIVH (0x03 << 0)
+
+#define MB86A16_FREQ1 0x21
+#define MB86A16_FREQ2 0x22
+#define MB86A16_FREQ3 0x23
+#define MB86A16_FREQ4 0x24
+#define MB86A16_FREQSET 0x25
+#define MB86A16_CNM 0x26
+#define MB86A16_PORT0 0x27
+#define MB86A16_PORT1 0x28
+#define MB86A16_DRCFILT 0x29
+#define MB86A16_AFC 0x2a
+#define MB86A16_AFCEXL 0x2b
+#define MB86A16_AFCEXH 0x2c
+#define MB86A16_DAGC 0x2d
+#define MB86A16_SEQMODE 0x32
+#define MB86A16_S0S1T 0x33
+#define MB86A16_S2S3T 0x34
+#define MB86A16_S4S5T 0x35
+#define MB86A16_CNTMR 0x36
+#define MB86A16_SIG1 0x37
+#define MB86A16_SIG2 0x38
+#define MB86A16_VIMAG 0x39
+#define MB86A16_VISET1 0x3a
+#define MB86A16_VISET2 0x3b
+#define MB86A16_VISET3 0x3c
+#define MB86A16_FAGCS1 0x3d
+#define MB86A16_FAGCS2 0x3e
+#define MB86A16_FAGCS3 0x3f
+#define MB86A16_FAGCS4 0x40
+#define MB86A16_FAGCS5 0x41
+#define MB86A16_FAGCS6 0x42
+#define MB86A16_CRM 0x43
+#define MB86A16_STRM 0x44
+#define MB86A16_DAGCML 0x45
+#define MB86A16_DAGCMH 0x46
+#define MB86A16_QPSKTST 0x49
+#define MB86A16_DISTMON 0x52
+#define MB86A16_VERSION 0x7f
+
+#endif /* __MB86A16_PRIV_H */
diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c
index 9552a22ccffb..d21a327db629 100644
--- a/drivers/media/dvb/frontends/si21xx.c
+++ b/drivers/media/dvb/frontends/si21xx.c
@@ -97,8 +97,6 @@
#define LNB_SUPPLY_CTRL_REG_4 0xce
#define LNB_SUPPLY_STATUS_REG 0xcf
-#define FALSE 0
-#define TRUE 1
#define FAIL -1
#define PASS 0
@@ -718,7 +716,7 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
int fine_tune_freq;
unsigned char sample_rate = 0;
/* boolean */
- unsigned int inband_interferer_ind;
+ bool inband_interferer_ind;
/* INTERMEDIATE VALUES */
int icoarse_tune_freq; /* MHz */
@@ -728,15 +726,8 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
unsigned int x1;
unsigned int x2;
int i;
- unsigned int inband_interferer_div2[ALLOWABLE_FS_COUNT] = {
- FALSE, FALSE, FALSE, FALSE, FALSE,
- FALSE, FALSE, FALSE, FALSE, FALSE
- };
- unsigned int inband_interferer_div4[ALLOWABLE_FS_COUNT] = {
- FALSE, FALSE, FALSE, FALSE, FALSE,
- FALSE, FALSE, FALSE, FALSE, FALSE
- };
-
+ bool inband_interferer_div2[ALLOWABLE_FS_COUNT];
+ bool inband_interferer_div4[ALLOWABLE_FS_COUNT];
int status;
/* allowable sample rates for ADC in MHz */
@@ -762,7 +753,7 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
}
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
- inband_interferer_div2[i] = inband_interferer_div4[i] = FALSE;
+ inband_interferer_div2[i] = inband_interferer_div4[i] = false;
if_limit_high = -700000;
if_limit_low = -100000;
@@ -798,7 +789,7 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
if (((band_low < x1) && (x1 < band_high)) ||
((band_low < x2) && (x2 < band_high)))
- inband_interferer_div4[i] = TRUE;
+ inband_interferer_div4[i] = true;
}
@@ -811,25 +802,28 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
if (((band_low < x1) && (x1 < band_high)) ||
((band_low < x2) && (x2 < band_high)))
- inband_interferer_div2[i] = TRUE;
+ inband_interferer_div2[i] = true;
}
- inband_interferer_ind = TRUE;
- for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
- inband_interferer_ind &= inband_interferer_div2[i] |
- inband_interferer_div4[i];
+ inband_interferer_ind = true;
+ for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+ if (inband_interferer_div2[i] || inband_interferer_div4[i]) {
+ inband_interferer_ind = false;
+ break;
+ }
+ }
if (inband_interferer_ind) {
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
- if (inband_interferer_div2[i] == FALSE) {
+ if (!inband_interferer_div2[i]) {
sample_rate = (u8) afs[i];
break;
}
}
} else {
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
- if ((inband_interferer_div2[i] |
- inband_interferer_div4[i]) == FALSE) {
+ if ((inband_interferer_div2[i] ||
+ !inband_interferer_div4[i])) {
sample_rate = (u8) afs[i];
break;
}
diff --git a/drivers/media/dvb/frontends/stv0900.h b/drivers/media/dvb/frontends/stv0900.h
index 29c3fa85c227..e3e35d1ce838 100644
--- a/drivers/media/dvb/frontends/stv0900.h
+++ b/drivers/media/dvb/frontends/stv0900.h
@@ -49,6 +49,8 @@ struct stv0900_config {
u8 tun2_maddress;
u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
u8 tun2_adc;
+ u8 tun1_type;/* for now 3 for stb6100 auto, else - software */
+ u8 tun2_type;
/* Set device param to start dma */
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
};
diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c
index 8762c86044a5..01f8f1f802fd 100644
--- a/drivers/media/dvb/frontends/stv0900_core.c
+++ b/drivers/media/dvb/frontends/stv0900_core.c
@@ -177,7 +177,7 @@ u8 stv0900_read_reg(struct stv0900_internal *intp, u16 reg)
return buf;
}
-void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
+static void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
{
u8 position = 0, i = 0;
@@ -218,7 +218,7 @@ u8 stv0900_get_bits(struct stv0900_internal *intp, u32 label)
return val;
}
-enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp)
+static enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp)
{
s32 i;
@@ -282,7 +282,7 @@ enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp)
return STV0900_NO_ERROR;
}
-u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk)
+static u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk)
{
u32 mclk = 90000000, div = 0, ad_div = 0;
@@ -296,7 +296,7 @@ u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk)
return mclk;
}
-enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 mclk)
+static enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 mclk)
{
u32 m_div, clk_sel;
@@ -334,7 +334,7 @@ enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 mclk)
return STV0900_NO_ERROR;
}
-u32 stv0900_get_err_count(struct stv0900_internal *intp, int cntr,
+static u32 stv0900_get_err_count(struct stv0900_internal *intp, int cntr,
enum fe_stv0900_demod_num demod)
{
u32 lsb, msb, hsb, err_val;
@@ -567,6 +567,46 @@ void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
}
}
+u32 stv0900_get_freq_auto(struct stv0900_internal *intp, int demod)
+{
+ u32 freq, round;
+ /* Formulat :
+ Tuner_Frequency(MHz) = Regs / 64
+ Tuner_granularity(MHz) = Regs / 2048
+ real_Tuner_Frequency = Tuner_Frequency(MHz) - Tuner_granularity(MHz)
+ */
+ freq = (stv0900_get_bits(intp, TUN_RFFREQ2) << 10) +
+ (stv0900_get_bits(intp, TUN_RFFREQ1) << 2) +
+ stv0900_get_bits(intp, TUN_RFFREQ0);
+
+ freq = (freq * 1000) / 64;
+
+ round = (stv0900_get_bits(intp, TUN_RFRESTE1) >> 2) +
+ stv0900_get_bits(intp, TUN_RFRESTE0);
+
+ round = (round * 1000) / 2048;
+
+ return freq + round;
+}
+
+void stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
+ u32 Bandwidth, int demod)
+{
+ u32 tunerFrequency;
+ /* Formulat:
+ Tuner_frequency_reg= Frequency(MHz)*64
+ */
+ tunerFrequency = (Frequency * 64) / 1000;
+
+ stv0900_write_bits(intp, TUN_RFFREQ2, (tunerFrequency >> 10));
+ stv0900_write_bits(intp, TUN_RFFREQ1, (tunerFrequency >> 2) & 0xff);
+ stv0900_write_bits(intp, TUN_RFFREQ0, (tunerFrequency & 0x03));
+ /* Low Pass Filter = BW /2 (MHz)*/
+ stv0900_write_bits(intp, TUN_BW, Bandwidth / 2000000);
+ /* Tuner Write trig */
+ stv0900_write_reg(intp, TNRLD, 1);
+}
+
static s32 stv0900_get_rf_level(struct stv0900_internal *intp,
const struct stv0900_table *lookup,
enum fe_stv0900_demod_num demod)
@@ -1329,7 +1369,6 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
enum fe_stv0900_error error = STV0900_NO_ERROR;
enum fe_stv0900_error demodError = STV0900_NO_ERROR;
struct stv0900_internal *intp = NULL;
-
int selosci, i;
struct stv0900_inode *temp_int = find_inode(state->i2c_adap,
@@ -1345,7 +1384,14 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
} else {
state->internal = kmalloc(sizeof(struct stv0900_internal),
GFP_KERNEL);
+ if (state->internal == NULL)
+ return STV0900_INVALID_HANDLE;
temp_int = append_internal(state->internal);
+ if (temp_int == NULL) {
+ kfree(state->internal);
+ state->internal = NULL;
+ return STV0900_INVALID_HANDLE;
+ }
state->internal->dmds_used = 1;
state->internal->i2c_adap = state->i2c_adap;
state->internal->i2c_addr = state->config->demod_address;
@@ -1371,11 +1417,6 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
return error;
}
- if (state->internal == NULL) {
- error = STV0900_INVALID_HANDLE;
- return error;
- }
-
intp = state->internal;
intp->demod_mode = p_init->demod_mode;
@@ -1404,6 +1445,27 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0);
}
+ intp->tuner_type[0] = p_init->tuner1_type;
+ intp->tuner_type[1] = p_init->tuner2_type;
+ /* tuner init */
+ switch (p_init->tuner1_type) {
+ case 3: /*FE_AUTO_STB6100:*/
+ stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x3c);
+ stv0900_write_reg(intp, R0900_P1_TNRCFG2, 0x86);
+ stv0900_write_reg(intp, R0900_P1_TNRCFG3, 0x18);
+ stv0900_write_reg(intp, R0900_P1_TNRXTAL, 27); /* 27MHz */
+ stv0900_write_reg(intp, R0900_P1_TNRSTEPS, 0x05);
+ stv0900_write_reg(intp, R0900_P1_TNRGAIN, 0x17);
+ stv0900_write_reg(intp, R0900_P1_TNRADJ, 0x1f);
+ stv0900_write_reg(intp, R0900_P1_TNRCTL2, 0x0);
+ stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 3);
+ break;
+ /* case FE_SW_TUNER: */
+ default:
+ stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 6);
+ break;
+ }
+
stv0900_write_bits(intp, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress);
switch (p_init->tuner1_adc) {
case 1:
@@ -1413,6 +1475,27 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
break;
}
+ stv0900_write_reg(intp, R0900_P1_TNRLD, 1); /* hw tuner */
+
+ /* tuner init */
+ switch (p_init->tuner2_type) {
+ case 3: /*FE_AUTO_STB6100:*/
+ stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x3c);
+ stv0900_write_reg(intp, R0900_P2_TNRCFG2, 0x86);
+ stv0900_write_reg(intp, R0900_P2_TNRCFG3, 0x18);
+ stv0900_write_reg(intp, R0900_P2_TNRXTAL, 27); /* 27MHz */
+ stv0900_write_reg(intp, R0900_P2_TNRSTEPS, 0x05);
+ stv0900_write_reg(intp, R0900_P2_TNRGAIN, 0x17);
+ stv0900_write_reg(intp, R0900_P2_TNRADJ, 0x1f);
+ stv0900_write_reg(intp, R0900_P2_TNRCTL2, 0x0);
+ stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 3);
+ break;
+ /* case FE_SW_TUNER: */
+ default:
+ stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 6);
+ break;
+ }
+
stv0900_write_bits(intp, F0900_P2_TUN_MADDRESS, p_init->tun2_maddress);
switch (p_init->tuner2_adc) {
case 1:
@@ -1422,6 +1505,8 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
break;
}
+ stv0900_write_reg(intp, R0900_P2_TNRLD, 1); /* hw tuner */
+
stv0900_write_bits(intp, F0900_P1_TUN_IQSWAP, p_init->tun1_iq_inv);
stv0900_write_bits(intp, F0900_P2_TUN_IQSWAP, p_init->tun2_iq_inv);
stv0900_set_mclk(intp, 135000000);
@@ -1824,10 +1909,12 @@ struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
init_params.tun1_maddress = config->tun1_maddress;
init_params.tun1_iq_inv = STV0900_IQ_NORMAL;
init_params.tuner1_adc = config->tun1_adc;
+ init_params.tuner1_type = config->tun1_type;
init_params.path2_ts_clock = config->path2_mode;
init_params.ts_config = config->ts_config_regs;
init_params.tun2_maddress = config->tun2_maddress;
init_params.tuner2_adc = config->tun2_adc;
+ init_params.tuner2_type = config->tun2_type;
init_params.tun2_iq_inv = STV0900_IQ_SWAPPED;
err_stv0900 = stv0900_init_internal(&state->frontend,
diff --git a/drivers/media/dvb/frontends/stv0900_priv.h b/drivers/media/dvb/frontends/stv0900_priv.h
index d8ba8a984abe..b62b0f0a4fef 100644
--- a/drivers/media/dvb/frontends/stv0900_priv.h
+++ b/drivers/media/dvb/frontends/stv0900_priv.h
@@ -247,6 +247,7 @@ struct stv0900_init_params{
u8 tun1_maddress;
int tuner1_adc;
+ int tuner1_type;
/* IQ from the tuner1 to the demod */
enum stv0900_iq_inversion tun1_iq_inv;
@@ -254,6 +255,7 @@ struct stv0900_init_params{
u8 tun2_maddress;
int tuner2_adc;
+ int tuner2_type;
/* IQ from the tuner2 to the demod */
enum stv0900_iq_inversion tun2_iq_inv;
@@ -309,6 +311,8 @@ struct stv0900_internal{
s32 bw[2];
s32 symbol_rate[2];
s32 srch_range[2];
+ /* for software/auto tuner */
+ int tuner_type[2];
/* algorithm for search Blind, Cold or Warm*/
enum fe_stv0900_search_algo srch_algo[2];
@@ -394,4 +398,11 @@ extern enum
fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
enum fe_stv0900_demod_num demod);
+extern u32
+stv0900_get_freq_auto(struct stv0900_internal *intp, int demod);
+
+extern void
+stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
+ u32 Bandwidth, int demod);
+
#endif
diff --git a/drivers/media/dvb/frontends/stv0900_reg.h b/drivers/media/dvb/frontends/stv0900_reg.h
index 7b8edf192e97..731afe93a823 100644
--- a/drivers/media/dvb/frontends/stv0900_reg.h
+++ b/drivers/media/dvb/frontends/stv0900_reg.h
@@ -3174,17 +3174,21 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
#define R0900_P1_TNRRF1 0xf4e9
#define TNRRF1 REGx(R0900_P1_TNRRF1)
#define F0900_P1_TUN_RFFREQ2 0xf4e900ff
+#define TUN_RFFREQ2 FLDx(F0900_P1_TUN_RFFREQ2)
/*P1_TNRRF0*/
#define R0900_P1_TNRRF0 0xf4ea
#define TNRRF0 REGx(R0900_P1_TNRRF0)
#define F0900_P1_TUN_RFFREQ1 0xf4ea00ff
+#define TUN_RFFREQ1 FLDx(F0900_P1_TUN_RFFREQ1)
/*P1_TNRBW*/
#define R0900_P1_TNRBW 0xf4eb
#define TNRBW REGx(R0900_P1_TNRBW)
#define F0900_P1_TUN_RFFREQ0 0xf4eb00c0
+#define TUN_RFFREQ0 FLDx(F0900_P1_TUN_RFFREQ0)
#define F0900_P1_TUN_BW 0xf4eb003f
+#define TUN_BW FLDx(F0900_P1_TUN_BW)
/*P1_TNRADJ*/
#define R0900_P1_TNRADJ 0xf4ec
@@ -3234,11 +3238,13 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
#define F0900_P1_TUN_I2CLOCKED 0xf4f60010
#define F0900_P1_TUN_PROGDONE 0xf4f6000c
#define F0900_P1_TUN_RFRESTE1 0xf4f60003
+#define TUN_RFRESTE1 FLDx(F0900_P1_TUN_RFRESTE1)
/*P1_TNRRESTE*/
#define R0900_P1_TNRRESTE 0xf4f7
#define TNRRESTE REGx(R0900_P1_TNRRESTE)
#define F0900_P1_TUN_RFRESTE0 0xf4f700ff
+#define TUN_RFRESTE0 FLDx(F0900_P1_TUN_RFRESTE0)
/*P1_SMAPCOEF7*/
#define R0900_P1_SMAPCOEF7 0xf500
diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb/frontends/stv0900_sw.c
index b8da87fa637f..ba0709b2d433 100644
--- a/drivers/media/dvb/frontends/stv0900_sw.c
+++ b/drivers/media/dvb/frontends/stv0900_sw.c
@@ -193,7 +193,7 @@ static int stv0900_search_carr_sw_loop(struct stv0900_internal *intp,
return lock;
}
-int stv0900_sw_algo(struct stv0900_internal *intp,
+static int stv0900_sw_algo(struct stv0900_internal *intp,
enum fe_stv0900_demod_num demod)
{
int lock = FALSE,
@@ -606,7 +606,12 @@ static int stv0900_get_demod_cold_lock(struct dvb_frontend *fe,
tuner_freq -= (current_step * currier_step);
if (intp->chip_id <= 0x20) {
- stv0900_set_tuner(fe, tuner_freq, intp->bw[d]);
+ if (intp->tuner_type[d] == 3)
+ stv0900_set_tuner_auto(intp, tuner_freq,
+ intp->bw[d], demod);
+ else
+ stv0900_set_tuner(fe, tuner_freq, intp->bw[d]);
+
stv0900_write_reg(intp, DMDISTATE, 0x1c);
stv0900_write_reg(intp, CFRINIT1, 0);
stv0900_write_reg(intp, CFRINIT0, 0);
@@ -790,7 +795,7 @@ static enum fe_stv0900_fec stv0900_get_vit_fec(struct stv0900_internal *intp,
return prate;
}
-void stv0900_set_dvbs1_track_car_loop(struct stv0900_internal *intp,
+static void stv0900_set_dvbs1_track_car_loop(struct stv0900_internal *intp,
enum fe_stv0900_demod_num demod,
u32 srate)
{
@@ -976,8 +981,16 @@ static void stv0900_track_optimization(struct dvb_frontend *fe)
intp->rolloff) + 10000000;
if ((intp->chip_id >= 0x20) || (blind_tun_sw == 1)) {
- if (intp->srch_algo[demod] != STV0900_WARM_START)
- stv0900_set_bandwidth(fe, intp->bw[demod]);
+ if (intp->srch_algo[demod] != STV0900_WARM_START) {
+ if (intp->tuner_type[demod] == 3)
+ stv0900_set_tuner_auto(intp,
+ intp->freq[demod],
+ intp->bw[demod],
+ demod);
+ else
+ stv0900_set_bandwidth(fe,
+ intp->bw[demod]);
+ }
}
if ((intp->srch_algo[demod] == STV0900_BLIND_SEARCH) ||
@@ -1202,7 +1215,11 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
}
result->standard = stv0900_get_standard(fe, d);
- result->frequency = stv0900_get_tuner_freq(fe);
+ if (intp->tuner_type[demod] == 3)
+ result->frequency = stv0900_get_freq_auto(intp, d);
+ else
+ result->frequency = stv0900_get_tuner_freq(fe);
+
offsetFreq = stv0900_get_carr_freq(intp, intp->mclk, d) / 1000;
result->frequency += offsetFreq;
result->symbol_rate = stv0900_get_symbol_rate(intp, intp->mclk, d);
@@ -1213,6 +1230,9 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
result->pilot = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01;
result->frame_len = ((u32)stv0900_get_bits(intp, DEMOD_TYPE)) >> 1;
result->rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS);
+
+ dprintk("%s: modcode=0x%x \n", __func__, result->modcode);
+
switch (result->standard) {
case STV0900_DVBS2_STANDARD:
result->spectrum = stv0900_get_bits(intp, SPECINV_DEMOD);
@@ -1239,7 +1259,11 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
if ((intp->srch_algo[d] == STV0900_BLIND_SEARCH) ||
(intp->symbol_rate[d] < 10000000)) {
offsetFreq = result->frequency - intp->freq[d];
- intp->freq[d] = stv0900_get_tuner_freq(fe);
+ if (intp->tuner_type[demod] == 3)
+ intp->freq[d] = stv0900_get_freq_auto(intp, d);
+ else
+ intp->freq[d] = stv0900_get_tuner_freq(fe);
+
if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
range = STV0900_RANGEOK;
else if (ABS(offsetFreq) <=
@@ -1481,7 +1505,12 @@ static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe)
else
tuner_freq -= (current_step * currier_step);
- stv0900_set_tuner(fe, tuner_freq, intp->bw[demod]);
+ if (intp->tuner_type[demod] == 3)
+ stv0900_set_tuner_auto(intp, tuner_freq,
+ intp->bw[demod], demod);
+ else
+ stv0900_set_tuner(fe, tuner_freq,
+ intp->bw[demod]);
}
}
@@ -1608,7 +1637,8 @@ static int stv0900_blind_search_algo(struct dvb_frontend *fe)
agc2_int = stv0900_blind_check_agc2_min_level(intp, demod);
- if (agc2_int > STV0900_BLIND_SEARCH_AGC2_TH)
+ dprintk("%s agc2_int=%d agc2_th=%d \n", __func__, agc2_int, agc2_th);
+ if (agc2_int > agc2_th)
return FALSE;
if (intp->chip_id == 0x10)
@@ -1875,7 +1905,11 @@ enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe)
}
- stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]);
+ if (intp->tuner_type[demod] == 3)
+ stv0900_set_tuner_auto(intp, intp->freq[demod],
+ intp->bw[demod], demod);
+ else
+ stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]);
agc1_power = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1),
stv0900_get_bits(intp, AGCIQ_VALUE0));
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
index 1573466a5c74..c52c3357dc54 100644
--- a/drivers/media/dvb/frontends/stv090x.c
+++ b/drivers/media/dvb/frontends/stv090x.c
@@ -37,7 +37,82 @@
static unsigned int verbose;
module_param(verbose, int, 0644);
-struct mutex demod_lock;
+/* internal params node */
+struct stv090x_dev {
+ /* pointer for internal params, one for each pair of demods */
+ struct stv090x_internal *internal;
+ struct stv090x_dev *next_dev;
+};
+
+/* first internal params */
+static struct stv090x_dev *stv090x_first_dev;
+
+/* find chip by i2c adapter and i2c address */
+static struct stv090x_dev *find_dev(struct i2c_adapter *i2c_adap,
+ u8 i2c_addr)
+{
+ struct stv090x_dev *temp_dev = stv090x_first_dev;
+
+ /*
+ Search of the last stv0900 chip or
+ find it by i2c adapter and i2c address */
+ while ((temp_dev != NULL) &&
+ ((temp_dev->internal->i2c_adap != i2c_adap) ||
+ (temp_dev->internal->i2c_addr != i2c_addr))) {
+
+ temp_dev = temp_dev->next_dev;
+ }
+
+ return temp_dev;
+}
+
+/* deallocating chip */
+static void remove_dev(struct stv090x_internal *internal)
+{
+ struct stv090x_dev *prev_dev = stv090x_first_dev;
+ struct stv090x_dev *del_dev = find_dev(internal->i2c_adap,
+ internal->i2c_addr);
+
+ if (del_dev != NULL) {
+ if (del_dev == stv090x_first_dev) {
+ stv090x_first_dev = del_dev->next_dev;
+ } else {
+ while (prev_dev->next_dev != del_dev)
+ prev_dev = prev_dev->next_dev;
+
+ prev_dev->next_dev = del_dev->next_dev;
+ }
+
+ kfree(del_dev);
+ }
+}
+
+/* allocating new chip */
+static struct stv090x_dev *append_internal(struct stv090x_internal *internal)
+{
+ struct stv090x_dev *new_dev;
+ struct stv090x_dev *temp_dev;
+
+ new_dev = kmalloc(sizeof(struct stv090x_dev), GFP_KERNEL);
+ if (new_dev != NULL) {
+ new_dev->internal = internal;
+ new_dev->next_dev = NULL;
+
+ /* append to list */
+ if (stv090x_first_dev == NULL) {
+ stv090x_first_dev = new_dev;
+ } else {
+ temp_dev = stv090x_first_dev;
+ while (temp_dev->next_dev != NULL)
+ temp_dev = temp_dev->next_dev;
+
+ temp_dev->next_dev = new_dev;
+ }
+ }
+
+ return new_dev;
+}
+
/* DVBS1 and DSS C/N Lookup table */
static const struct stv090x_tab stv090x_s1cn_tab[] = {
@@ -683,6 +758,9 @@ static int stv090x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
struct stv090x_state *state = fe->demodulator_priv;
u32 reg;
+ if (enable)
+ mutex_lock(&state->internal->tuner_lock);
+
reg = STV090x_READ_DEMOD(state, I2CRPT);
if (enable) {
dprintk(FE_DEBUG, 1, "Enable Gate");
@@ -696,9 +774,14 @@ static int stv090x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
if ((STV090x_WRITE_DEMOD(state, I2CRPT, reg)) < 0)
goto err;
}
+
+ if (!enable)
+ mutex_unlock(&state->internal->tuner_lock);
+
return 0;
err:
dprintk(FE_ERROR, 1, "I/O error");
+ mutex_unlock(&state->internal->tuner_lock);
return -1;
}
@@ -755,13 +838,13 @@ static int stv090x_set_srate(struct stv090x_state *state, u32 srate)
if (srate > 60000000) {
sym = (srate << 4); /* SR * 2^16 / master_clk */
- sym /= (state->mclk >> 12);
+ sym /= (state->internal->mclk >> 12);
} else if (srate > 6000000) {
sym = (srate << 6);
- sym /= (state->mclk >> 10);
+ sym /= (state->internal->mclk >> 10);
} else {
sym = (srate << 9);
- sym /= (state->mclk >> 7);
+ sym /= (state->internal->mclk >> 7);
}
if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0x7f) < 0) /* MSB */
@@ -782,13 +865,13 @@ static int stv090x_set_max_srate(struct stv090x_state *state, u32 clk, u32 srate
srate = 105 * (srate / 100);
if (srate > 60000000) {
sym = (srate << 4); /* SR * 2^16 / master_clk */
- sym /= (state->mclk >> 12);
+ sym /= (state->internal->mclk >> 12);
} else if (srate > 6000000) {
sym = (srate << 6);
- sym /= (state->mclk >> 10);
+ sym /= (state->internal->mclk >> 10);
} else {
sym = (srate << 9);
- sym /= (state->mclk >> 7);
+ sym /= (state->internal->mclk >> 7);
}
if (sym < 0x7fff) {
@@ -816,13 +899,13 @@ static int stv090x_set_min_srate(struct stv090x_state *state, u32 clk, u32 srate
srate = 95 * (srate / 100);
if (srate > 60000000) {
sym = (srate << 4); /* SR * 2^16 / master_clk */
- sym /= (state->mclk >> 12);
+ sym /= (state->internal->mclk >> 12);
} else if (srate > 6000000) {
sym = (srate << 6);
- sym /= (state->mclk >> 10);
+ sym /= (state->internal->mclk >> 10);
} else {
sym = (srate << 9);
- sym /= (state->mclk >> 7);
+ sym /= (state->internal->mclk >> 7);
}
if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0x7f)) < 0) /* MSB */
@@ -1103,21 +1186,21 @@ static int stv090x_vitclk_ctl(struct stv090x_state *state, int enable)
switch (state->demod) {
case STV090x_DEMODULATOR_0:
- mutex_lock(&demod_lock);
+ mutex_lock(&state->internal->demod_lock);
reg = stv090x_read_reg(state, STV090x_STOPCLK2);
STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, enable);
if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
goto err;
- mutex_unlock(&demod_lock);
+ mutex_unlock(&state->internal->demod_lock);
break;
case STV090x_DEMODULATOR_1:
- mutex_lock(&demod_lock);
+ mutex_lock(&state->internal->demod_lock);
reg = stv090x_read_reg(state, STV090x_STOPCLK2);
STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, enable);
if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
goto err;
- mutex_unlock(&demod_lock);
+ mutex_unlock(&state->internal->demod_lock);
break;
default:
@@ -1126,14 +1209,14 @@ static int stv090x_vitclk_ctl(struct stv090x_state *state, int enable)
}
return 0;
err:
- mutex_unlock(&demod_lock);
+ mutex_unlock(&state->internal->demod_lock);
dprintk(FE_ERROR, 1, "I/O error");
return -1;
}
static int stv090x_dvbs_track_crl(struct stv090x_state *state)
{
- if (state->dev_ver >= 0x30) {
+ if (state->internal->dev_ver >= 0x30) {
/* Set ACLC BCLC optimised value vs SR */
if (state->srate >= 15000000) {
if (STV090x_WRITE_DEMOD(state, ACLC, 0x2b) < 0)
@@ -1215,7 +1298,7 @@ static int stv090x_delivery_search(struct stv090x_state *state)
if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0)
goto err;
- if (state->dev_ver <= 0x20) {
+ if (state->internal->dev_ver <= 0x20) {
/* enable S2 carrier loop */
if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
goto err;
@@ -1246,6 +1329,10 @@ static int stv090x_delivery_search(struct stv090x_state *state)
default:
/* enable DVB-S2 and DVB-S2 in Auto MODE */
reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+ STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+ STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+ if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+ goto err;
STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
@@ -1257,7 +1344,7 @@ static int stv090x_delivery_search(struct stv090x_state *state)
if (stv090x_dvbs_track_crl(state) < 0)
goto err;
- if (state->dev_ver <= 0x20) {
+ if (state->internal->dev_ver <= 0x20) {
/* enable S2 carrier loop */
if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
goto err;
@@ -1304,7 +1391,7 @@ static int stv090x_start_search(struct stv090x_state *state)
if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
goto err;
- if (state->dev_ver <= 0x20) {
+ if (state->internal->dev_ver <= 0x20) {
if (state->srate <= 5000000) {
if (STV090x_WRITE_DEMOD(state, CARCFG, 0x44) < 0)
goto err;
@@ -1348,7 +1435,7 @@ static int stv090x_start_search(struct stv090x_state *state)
* CFR max = +1MHz
*/
freq_abs = 1000 << 16;
- freq_abs /= (state->mclk / 1000);
+ freq_abs /= (state->internal->mclk / 1000);
freq = (s16) freq_abs;
} else {
/* COLD Start
@@ -1358,7 +1445,7 @@ static int stv090x_start_search(struct stv090x_state *state)
*/
freq_abs = (state->search_range / 2000) + 600;
freq_abs = freq_abs << 16;
- freq_abs /= (state->mclk / 1000);
+ freq_abs /= (state->internal->mclk / 1000);
freq = (s16) freq_abs;
}
@@ -1381,7 +1468,7 @@ static int stv090x_start_search(struct stv090x_state *state)
if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0) < 0)
goto err;
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
@@ -1418,10 +1505,10 @@ static int stv090x_start_search(struct stv090x_state *state)
if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0)
goto err;
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
/*Frequency offset detector setting*/
if (state->srate < 2000000) {
- if (state->dev_ver <= 0x20) {
+ if (state->internal->dev_ver <= 0x20) {
/* Cut 2 */
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x39) < 0)
goto err;
@@ -1512,7 +1599,7 @@ static int stv090x_get_agc2_min_level(struct stv090x_state *state)
steps = 1;
dir = 1;
- freq_step = (1000000 * 256) / (state->mclk / 256);
+ freq_step = (1000000 * 256) / (state->internal->mclk / 256);
freq_init = 0;
for (i = 0; i < steps; i++) {
@@ -1583,7 +1670,7 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
u32 srate_coarse = 0, agc2 = 0, car_step = 1200, reg;
u32 agc2th;
- if (state->dev_ver >= 0x30)
+ if (state->internal->dev_ver >= 0x30)
agc2th = 0x2e00;
else
agc2th = 0x1f00;
@@ -1619,13 +1706,13 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x50) < 0)
goto err;
- if (state->dev_ver >= 0x30) {
+ if (state->internal->dev_ver >= 0x30) {
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x99) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x98) < 0)
goto err;
- } else if (state->dev_ver >= 0x20) {
+ } else if (state->internal->dev_ver >= 0x20) {
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x6a) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0)
@@ -1677,7 +1764,7 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
STV090x_READ_DEMOD(state, AGC2I0);
}
agc2 /= 10;
- srate_coarse = stv090x_get_srate(state, state->mclk);
+ srate_coarse = stv090x_get_srate(state, state->internal->mclk);
cur_step++;
dir *= -1;
if ((tmg_cpt >= 5) && (agc2 < agc2th) &&
@@ -1695,12 +1782,12 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
if (state->config->tuner_set_frequency) {
if (state->config->tuner_set_frequency(fe, freq) < 0)
- goto err;
+ goto err_gateoff;
}
if (state->config->tuner_set_bandwidth) {
if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
- goto err;
+ goto err_gateoff;
}
if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -1713,7 +1800,7 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
if (state->config->tuner_get_status) {
if (state->config->tuner_get_status(fe, &reg) < 0)
- goto err;
+ goto err_gateoff;
}
if (reg)
@@ -1729,9 +1816,12 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
if (!tmg_lock)
srate_coarse = 0;
else
- srate_coarse = stv090x_get_srate(state, state->mclk);
+ srate_coarse = stv090x_get_srate(state, state->internal->mclk);
return srate_coarse;
+
+err_gateoff:
+ stv090x_i2c_gate_ctrl(fe, 0);
err:
dprintk(FE_ERROR, 1, "I/O error");
return -1;
@@ -1741,7 +1831,7 @@ static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
{
u32 srate_coarse, freq_coarse, sym, reg;
- srate_coarse = stv090x_get_srate(state, state->mclk);
+ srate_coarse = stv090x_get_srate(state, state->internal->mclk);
freq_coarse = STV090x_READ_DEMOD(state, CFR2) << 8;
freq_coarse |= STV090x_READ_DEMOD(state, CFR1);
sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
@@ -1767,10 +1857,10 @@ static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
goto err;
- if (state->dev_ver >= 0x30) {
+ if (state->internal->dev_ver >= 0x30) {
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x79) < 0)
goto err;
- } else if (state->dev_ver >= 0x20) {
+ } else if (state->internal->dev_ver >= 0x20) {
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
goto err;
}
@@ -1778,20 +1868,20 @@ static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
if (srate_coarse > 3000000) {
sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
sym = (sym / 1000) * 65536;
- sym /= (state->mclk / 1000);
+ sym /= (state->internal->mclk / 1000);
if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
goto err;
sym = 10 * (srate_coarse / 13); /* SFRLOW = SFR - 30% */
sym = (sym / 1000) * 65536;
- sym /= (state->mclk / 1000);
+ sym /= (state->internal->mclk / 1000);
if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
goto err;
sym = (srate_coarse / 1000) * 65536;
- sym /= (state->mclk / 1000);
+ sym /= (state->internal->mclk / 1000);
if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
@@ -1799,20 +1889,20 @@ static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
} else {
sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
sym = (sym / 100) * 65536;
- sym /= (state->mclk / 100);
+ sym /= (state->internal->mclk / 100);
if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
goto err;
sym = 10 * (srate_coarse / 14); /* SFRLOW = SFR - 30% */
sym = (sym / 100) * 65536;
- sym /= (state->mclk / 100);
+ sym /= (state->internal->mclk / 100);
if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
goto err;
sym = (srate_coarse / 100) * 65536;
- sym /= (state->mclk / 100);
+ sym /= (state->internal->mclk / 100);
if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
@@ -1874,18 +1964,19 @@ static int stv090x_blind_search(struct stv090x_state *state)
u32 agc2, reg, srate_coarse;
s32 cpt_fail, agc2_ovflw, i;
u8 k_ref, k_max, k_min;
- int coarse_fail, lock;
+ int coarse_fail = 0;
+ int lock;
k_max = 110;
k_min = 10;
agc2 = stv090x_get_agc2_min_level(state);
- if (agc2 > STV090x_SEARCH_AGC2_TH(state->dev_ver)) {
+ if (agc2 > STV090x_SEARCH_AGC2_TH(state->internal->dev_ver)) {
lock = 0;
} else {
- if (state->dev_ver <= 0x20) {
+ if (state->internal->dev_ver <= 0x20) {
if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0)
goto err;
} else {
@@ -1897,7 +1988,7 @@ static int stv090x_blind_search(struct stv090x_state *state)
if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0)
goto err;
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
@@ -1956,7 +2047,7 @@ static int stv090x_chk_tmg(struct stv090x_state *state)
u32 reg;
s32 tmg_cpt = 0, i;
u8 freq, tmg_thh, tmg_thl;
- int tmg_lock;
+ int tmg_lock = 0;
freq = STV090x_READ_DEMOD(state, CARFREQ);
tmg_thh = STV090x_READ_DEMOD(state, TMGTHRISE);
@@ -2080,12 +2171,12 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
if (state->config->tuner_set_frequency) {
if (state->config->tuner_set_frequency(fe, freq) < 0)
- goto err;
+ goto err_gateoff;
}
if (state->config->tuner_set_bandwidth) {
if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
- goto err;
+ goto err_gateoff;
}
if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -2098,7 +2189,7 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
if (state->config->tuner_get_status) {
if (state->config->tuner_get_status(fe, &reg) < 0)
- goto err;
+ goto err_gateoff;
}
if (reg)
@@ -2129,6 +2220,8 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
return lock;
+err_gateoff:
+ stv090x_i2c_gate_ctrl(fe, 0);
err:
dprintk(FE_ERROR, 1, "I/O error");
return -1;
@@ -2142,13 +2235,13 @@ static int stv090x_get_loop_params(struct stv090x_state *state, s32 *freq_inc, s
car_max = state->search_range / 1000;
car_max += car_max / 10;
car_max = 65536 * (car_max / 2);
- car_max /= (state->mclk / 1000);
+ car_max /= (state->internal->mclk / 1000);
if (car_max > 0x4000)
car_max = 0x4000 ; /* maxcarrier should be<= +-1/4 Mclk */
inc = srate;
- inc /= state->mclk / 1000;
+ inc /= state->internal->mclk / 1000;
inc *= 256;
inc *= 256;
inc /= 1000;
@@ -2209,7 +2302,7 @@ static int stv090x_chk_signal(struct stv090x_state *state)
car_max += (car_max / 10); /* 10% margin */
car_max = (65536 * car_max / 2);
- car_max /= state->mclk / 1000;
+ car_max /= state->internal->mclk / 1000;
if (car_max > 0x4000)
car_max = 0x4000;
@@ -2234,7 +2327,7 @@ static int stv090x_search_car_loop(struct stv090x_state *state, s32 inc, s32 tim
car_max = state->search_range / 1000;
car_max += (car_max / 10);
car_max = (65536 * car_max / 2);
- car_max /= (state->mclk / 1000);
+ car_max /= (state->internal->mclk / 1000);
if (car_max > 0x4000)
car_max = 0x4000;
@@ -2304,7 +2397,7 @@ static int stv090x_sw_algo(struct stv090x_state *state)
case STV090x_SEARCH_DVBS1:
case STV090x_SEARCH_DSS:
/* accelerate the frequency detector */
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3B) < 0)
goto err;
}
@@ -2315,7 +2408,7 @@ static int stv090x_sw_algo(struct stv090x_state *state)
break;
case STV090x_SEARCH_DVBS2:
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
goto err;
}
@@ -2328,7 +2421,7 @@ static int stv090x_sw_algo(struct stv090x_state *state)
case STV090x_SEARCH_AUTO:
default:
/* accelerate the frequency detector */
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3b) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
@@ -2350,7 +2443,7 @@ static int stv090x_sw_algo(struct stv090x_state *state)
/*run the SW search 2 times maximum*/
if (lock || no_signal || (trials == 2)) {
/*Check if the demod is not losing lock in DVBS2*/
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0)
@@ -2372,7 +2465,7 @@ static int stv090x_sw_algo(struct stv090x_state *state)
/*FALSE lock, The demod is loosing lock */
lock = 0;
if (trials < 2) {
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
goto err;
}
@@ -2422,11 +2515,11 @@ static s32 stv090x_get_car_freq(struct stv090x_state *state, u32 mclk)
derot |= STV090x_READ_DEMOD(state, CFR0);
derot = comp2(derot, 24);
- int_1 = state->mclk >> 12;
+ int_1 = mclk >> 12;
int_2 = derot >> 12;
/* carrier_frequency = MasterClock * Reg / 2^24 */
- tmp_1 = state->mclk % 0x1000;
+ tmp_1 = mclk % 0x1000;
tmp_2 = derot % 0x1000;
derot = (int_1 * int_2) +
@@ -2502,13 +2595,13 @@ static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *st
if (state->config->tuner_get_frequency) {
if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
- goto err;
+ goto err_gateoff;
}
if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
goto err;
- offst_freq = stv090x_get_car_freq(state, state->mclk) / 1000;
+ offst_freq = stv090x_get_car_freq(state, state->internal->mclk) / 1000;
state->frequency += offst_freq;
if (stv090x_get_viterbi(state) < 0)
@@ -2530,7 +2623,7 @@ static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *st
if (state->config->tuner_get_frequency) {
if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
- goto err;
+ goto err_gateoff;
}
if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -2550,6 +2643,9 @@ static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *st
}
return STV090x_OUTOFRANGE;
+
+err_gateoff:
+ stv090x_i2c_gate_ctrl(fe, 0);
err:
dprintk(FE_ERROR, 1, "I/O error");
return -1;
@@ -2579,7 +2675,7 @@ static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_mod
s32 i;
struct stv090x_long_frame_crloop *car_loop, *car_loop_qpsk_low, *car_loop_apsk_low;
- if (state->dev_ver == 0x20) {
+ if (state->internal->dev_ver == 0x20) {
car_loop = stv090x_s2_crl_cut20;
car_loop_qpsk_low = stv090x_s2_lowqpsk_crl_cut20;
car_loop_apsk_low = stv090x_s2_apsk_crl_cut20;
@@ -2700,7 +2796,7 @@ static u8 stv090x_optimize_carloop_short(struct stv090x_state *state)
break;
}
- if (state->dev_ver >= 0x30) {
+ if (state->internal->dev_ver >= 0x30) {
/* Cut 3.0 and up */
short_crl = stv090x_s2_short_crl_cut30;
} else {
@@ -2732,7 +2828,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0;
u32 reg;
- srate = stv090x_get_srate(state, state->mclk);
+ srate = stv090x_get_srate(state, state->internal->mclk);
srate += stv090x_get_tmgoffst(state, srate);
switch (state->delsys) {
@@ -2751,7 +2847,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
goto err;
- if (state->dev_ver >= 0x30) {
+ if (state->internal->dev_ver >= 0x30) {
if (stv090x_get_viterbi(state) < 0)
goto err;
@@ -2868,7 +2964,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
goto err;
}
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
if ((state->search_mode == STV090x_SEARCH_DVBS1) ||
(state->search_mode == STV090x_SEARCH_DSS) ||
(state->search_mode == STV090x_SEARCH_AUTO)) {
@@ -2890,7 +2986,8 @@ static int stv090x_optimize_track(struct stv090x_state *state)
if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x80) < 0)
goto err;
- if ((state->dev_ver >= 0x20) || (blind_tune == 1) || (state->srate < 10000000)) {
+ if ((state->internal->dev_ver >= 0x20) || (blind_tune == 1) ||
+ (state->srate < 10000000)) {
/* update initial carrier freq with the found freq offset */
if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
goto err;
@@ -2898,7 +2995,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
goto err;
state->tuner_bw = stv090x_car_width(srate, state->rolloff) + 10000000;
- if ((state->dev_ver >= 0x20) || (blind_tune == 1)) {
+ if ((state->internal->dev_ver >= 0x20) || (blind_tune == 1)) {
if (state->algo != STV090x_WARM_SEARCH) {
@@ -2907,7 +3004,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
if (state->config->tuner_set_bandwidth) {
if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
- goto err;
+ goto err_gateoff;
}
if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -2950,7 +3047,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
}
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
goto err;
}
@@ -2959,6 +3056,9 @@ static int stv090x_optimize_track(struct stv090x_state *state)
stv090x_set_vit_thtracq(state);
return 0;
+
+err_gateoff:
+ stv090x_i2c_gate_ctrl(fe, 0);
err:
dprintk(FE_ERROR, 1, "I/O error");
return -1;
@@ -3026,7 +3126,7 @@ static int stv090x_set_s2rolloff(struct stv090x_state *state)
{
u32 reg;
- if (state->dev_ver <= 0x20) {
+ if (state->internal->dev_ver <= 0x20) {
/* rolloff to auto mode if DVBS2 */
reg = STV090x_READ_DEMOD(state, DEMOD);
STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x00);
@@ -3062,7 +3162,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod stop */
goto err;
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
if (state->srate > 5000000) {
if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0)
goto err;
@@ -3102,7 +3202,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
goto err;
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
if (STV090x_WRITE_DEMOD(state, KREFTMG, 0x5a) < 0)
goto err;
if (state->algo == STV090x_COLD_SEARCH)
@@ -3120,9 +3220,11 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
if (stv090x_set_srate(state, state->srate) < 0)
goto err;
- if (stv090x_set_max_srate(state, state->mclk, state->srate) < 0)
+ if (stv090x_set_max_srate(state, state->internal->mclk,
+ state->srate) < 0)
goto err;
- if (stv090x_set_min_srate(state, state->mclk, state->srate) < 0)
+ if (stv090x_set_min_srate(state, state->internal->mclk,
+ state->srate) < 0)
goto err;
if (state->srate >= 10000000)
@@ -3136,18 +3238,21 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
goto err;
if (state->config->tuner_set_bbgain) {
- if (state->config->tuner_set_bbgain(fe, 10) < 0) /* 10dB */
- goto err;
+ reg = state->config->tuner_bbgain;
+ if (reg == 0)
+ reg = 10; /* default: 10dB */
+ if (state->config->tuner_set_bbgain(fe, reg) < 0)
+ goto err_gateoff;
}
if (state->config->tuner_set_frequency) {
if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
- goto err;
+ goto err_gateoff;
}
if (state->config->tuner_set_bandwidth) {
if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
- goto err;
+ goto err_gateoff;
}
if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -3155,21 +3260,21 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
msleep(50);
- if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
- goto err;
-
if (state->config->tuner_get_status) {
+ if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+ goto err;
if (state->config->tuner_get_status(fe, &reg) < 0)
+ goto err_gateoff;
+ if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
goto err;
- }
- if (reg)
- dprintk(FE_DEBUG, 1, "Tuner phase locked");
- else
- dprintk(FE_DEBUG, 1, "Tuner unlocked");
-
- if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
- goto err;
+ if (reg)
+ dprintk(FE_DEBUG, 1, "Tuner phase locked");
+ else {
+ dprintk(FE_DEBUG, 1, "Tuner unlocked");
+ return STV090x_NOCARRIER;
+ }
+ }
msleep(10);
agc1_power = MAKEWORD16(STV090x_READ_DEMOD(state, AGCIQIN1),
@@ -3194,7 +3299,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
reg = STV090x_READ_DEMOD(state, DEMOD);
STV090x_SETFIELD_Px(reg, SPECINV_CONTROL_FIELD, state->inversion);
- if (state->dev_ver <= 0x20) {
+ if (state->internal->dev_ver <= 0x20) {
/* rolloff to auto mode if DVBS2 */
STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 1);
} else {
@@ -3238,7 +3343,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
if ((lock) && (signal_state == STV090x_RANGEOK)) { /* signal within Range */
stv090x_optimize_track(state);
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
/* >= Cut 2.0 :release TS reset after
* demod lock and optimized Tracking
*/
@@ -3293,6 +3398,8 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
}
return signal_state;
+err_gateoff:
+ stv090x_i2c_gate_ctrl(fe, 0);
err:
dprintk(FE_ERROR, 1, "I/O error");
return -1;
@@ -3303,6 +3410,9 @@ static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_fron
struct stv090x_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *props = &fe->dtv_property_cache;
+ if (p->frequency == 0)
+ return DVBFE_ALGO_SEARCH_INVALID;
+
state->delsys = props->delivery_system;
state->frequency = p->frequency;
state->srate = p->u.qpsk.symbol_rate;
@@ -3353,7 +3463,8 @@ static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
if (STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD)) {
reg = STV090x_READ_DEMOD(state, TSSTATUS);
if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
- *status = FE_HAS_CARRIER |
+ *status = FE_HAS_SIGNAL |
+ FE_HAS_CARRIER |
FE_HAS_VITERBI |
FE_HAS_SYNC |
FE_HAS_LOCK;
@@ -3370,7 +3481,11 @@ static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
if (STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD)) {
reg = STV090x_READ_DEMOD(state, TSSTATUS);
if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
- *status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ *status = FE_HAS_SIGNAL |
+ FE_HAS_CARRIER |
+ FE_HAS_VITERBI |
+ FE_HAS_SYNC |
+ FE_HAS_LOCK;
}
}
}
@@ -3770,6 +3885,15 @@ static void stv090x_release(struct dvb_frontend *fe)
{
struct stv090x_state *state = fe->demodulator_priv;
+ state->internal->num_used--;
+ if (state->internal->num_used <= 0) {
+
+ dprintk(FE_ERROR, 1, "Actually removing");
+
+ remove_dev(state->internal);
+ kfree(state->internal);
+ }
+
kfree(state);
}
@@ -3901,10 +4025,10 @@ static int stv090x_set_mclk(struct stv090x_state *state, u32 mclk, u32 clk)
if (stv090x_write_reg(state, STV090x_NCOARSE, reg) < 0)
goto err;
- state->mclk = stv090x_get_mclk(state);
+ state->internal->mclk = stv090x_get_mclk(state);
/*Set the DiseqC frequency to 22KHz */
- div = state->mclk / 704000;
+ div = state->internal->mclk / 704000;
if (STV090x_WRITE_DEMOD(state, F22TX, div) < 0)
goto err;
if (STV090x_WRITE_DEMOD(state, F22RX, div) < 0)
@@ -3920,7 +4044,7 @@ static int stv090x_set_tspath(struct stv090x_state *state)
{
u32 reg;
- if (state->dev_ver >= 0x20) {
+ if (state->internal->dev_ver >= 0x20) {
switch (state->config->ts1_mode) {
case STV090x_TSMODE_PARALLEL_PUNCTURED:
case STV090x_TSMODE_DVBCI:
@@ -4092,6 +4216,71 @@ static int stv090x_set_tspath(struct stv090x_state *state)
default:
break;
}
+
+ if (state->config->ts1_clk > 0) {
+ u32 speed;
+
+ switch (state->config->ts1_mode) {
+ case STV090x_TSMODE_PARALLEL_PUNCTURED:
+ case STV090x_TSMODE_DVBCI:
+ default:
+ speed = state->internal->mclk /
+ (state->config->ts1_clk / 4);
+ if (speed < 0x08)
+ speed = 0x08;
+ if (speed > 0xFF)
+ speed = 0xFF;
+ break;
+ case STV090x_TSMODE_SERIAL_PUNCTURED:
+ case STV090x_TSMODE_SERIAL_CONTINUOUS:
+ speed = state->internal->mclk /
+ (state->config->ts1_clk / 32);
+ if (speed < 0x20)
+ speed = 0x20;
+ if (speed > 0xFF)
+ speed = 0xFF;
+ break;
+ }
+ reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+ STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+ goto err;
+ if (stv090x_write_reg(state, STV090x_P1_TSSPEED, speed) < 0)
+ goto err;
+ }
+
+ if (state->config->ts2_clk > 0) {
+ u32 speed;
+
+ switch (state->config->ts2_mode) {
+ case STV090x_TSMODE_PARALLEL_PUNCTURED:
+ case STV090x_TSMODE_DVBCI:
+ default:
+ speed = state->internal->mclk /
+ (state->config->ts2_clk / 4);
+ if (speed < 0x08)
+ speed = 0x08;
+ if (speed > 0xFF)
+ speed = 0xFF;
+ break;
+ case STV090x_TSMODE_SERIAL_PUNCTURED:
+ case STV090x_TSMODE_SERIAL_CONTINUOUS:
+ speed = state->internal->mclk /
+ (state->config->ts2_clk / 32);
+ if (speed < 0x20)
+ speed = 0x20;
+ if (speed > 0xFF)
+ speed = 0xFF;
+ break;
+ }
+ reg = stv090x_read_reg(state, STV090x_P2_TSCFGM);
+ STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+ if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0)
+ goto err;
+ if (stv090x_write_reg(state, STV090x_P2_TSSPEED, speed) < 0)
+ goto err;
+ }
+
reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
@@ -4120,6 +4309,15 @@ static int stv090x_init(struct dvb_frontend *fe)
const struct stv090x_config *config = state->config;
u32 reg;
+ if (state->internal->mclk == 0) {
+ stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */
+ msleep(5);
+ if (stv090x_write_reg(state, STV090x_SYNTCTRL,
+ 0x20 | config->clk_mode) < 0)
+ goto err;
+ stv090x_get_mclk(state);
+ }
+
if (stv090x_wakeup(fe) < 0) {
dprintk(FE_ERROR, 1, "Error waking device");
goto err;
@@ -4142,12 +4340,12 @@ static int stv090x_init(struct dvb_frontend *fe)
if (config->tuner_set_mode) {
if (config->tuner_set_mode(fe, TUNER_WAKE) < 0)
- goto err;
+ goto err_gateoff;
}
if (config->tuner_init) {
if (config->tuner_init(fe) < 0)
- goto err;
+ goto err_gateoff;
}
if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -4157,6 +4355,9 @@ static int stv090x_init(struct dvb_frontend *fe)
goto err;
return 0;
+
+err_gateoff:
+ stv090x_i2c_gate_ctrl(fe, 0);
err:
dprintk(FE_ERROR, 1, "I/O error");
return -1;
@@ -4188,16 +4389,26 @@ static int stv090x_setup(struct dvb_frontend *fe)
}
/* STV090x init */
- if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Stop Demod */
+
+ /* Stop Demod */
+ if (stv090x_write_reg(state, STV090x_P1_DMDISTATE, 0x5c) < 0)
+ goto err;
+ if (stv090x_write_reg(state, STV090x_P2_DMDISTATE, 0x5c) < 0)
goto err;
msleep(5);
- if (STV090x_WRITE_DEMOD(state, TNRCFG, 0x6c) < 0) /* check register ! (No Tuner Mode) */
+ /* Set No Tuner Mode */
+ if (stv090x_write_reg(state, STV090x_P1_TNRCFG, 0x6c) < 0)
+ goto err;
+ if (stv090x_write_reg(state, STV090x_P2_TNRCFG, 0x6c) < 0)
goto err;
+ /* I2C repeater OFF */
STV090x_SETFIELD_Px(reg, ENARPT_LEVEL_FIELD, config->repeater_level);
- if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0) /* repeater OFF */
+ if (stv090x_write_reg(state, STV090x_P1_I2CRPT, reg) < 0)
+ goto err;
+ if (stv090x_write_reg(state, STV090x_P2_I2CRPT, reg) < 0)
goto err;
if (stv090x_write_reg(state, STV090x_NCOARSE, 0x13) < 0) /* set PLL divider */
@@ -4216,8 +4427,8 @@ static int stv090x_setup(struct dvb_frontend *fe)
goto err;
}
- state->dev_ver = stv090x_read_reg(state, STV090x_MID);
- if (state->dev_ver >= 0x20) {
+ state->internal->dev_ver = stv090x_read_reg(state, STV090x_MID);
+ if (state->internal->dev_ver >= 0x20) {
if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0)
goto err;
@@ -4228,27 +4439,35 @@ static int stv090x_setup(struct dvb_frontend *fe)
goto err;
}
- } else if (state->dev_ver < 0x20) {
+ } else if (state->internal->dev_ver < 0x20) {
dprintk(FE_ERROR, 1, "ERROR: Unsupported Cut: 0x%02x!",
- state->dev_ver);
+ state->internal->dev_ver);
goto err;
- } else if (state->dev_ver > 0x30) {
+ } else if (state->internal->dev_ver > 0x30) {
/* we shouldn't bail out from here */
dprintk(FE_ERROR, 1, "INFO: Cut: 0x%02x probably incomplete support!",
- state->dev_ver);
+ state->internal->dev_ver);
}
- if (stv090x_write_reg(state, STV090x_TSTRES0, 0x80) < 0)
+ /* ADC1 range */
+ reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+ STV090x_SETFIELD(reg, ADC1_INMODE_FIELD,
+ (config->adc1_range == STV090x_ADC_1Vpp) ? 0 : 1);
+ if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
goto err;
- if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0)
+
+ /* ADC2 range */
+ reg = stv090x_read_reg(state, STV090x_TSTTNR3);
+ STV090x_SETFIELD(reg, ADC2_INMODE_FIELD,
+ (config->adc2_range == STV090x_ADC_1Vpp) ? 0 : 1);
+ if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0)
goto err;
- stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */
- msleep(5);
- if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0)
+ if (stv090x_write_reg(state, STV090x_TSTRES0, 0x80) < 0)
+ goto err;
+ if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0)
goto err;
- stv090x_get_mclk(state);
return 0;
err:
@@ -4299,6 +4518,7 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
enum stv090x_demodulator demod)
{
struct stv090x_state *state = NULL;
+ struct stv090x_dev *temp_int;
state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL);
if (state == NULL)
@@ -4314,8 +4534,32 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
state->device = config->device;
state->rolloff = STV090x_RO_35; /* default */
- if (state->demod == STV090x_DEMODULATOR_0)
- mutex_init(&demod_lock);
+ temp_int = find_dev(state->i2c,
+ state->config->address);
+
+ if ((temp_int != NULL) && (state->demod_mode == STV090x_DUAL)) {
+ state->internal = temp_int->internal;
+ state->internal->num_used++;
+ dprintk(FE_INFO, 1, "Found Internal Structure!");
+ dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x",
+ state->device == STV0900 ? "STV0900" : "STV0903",
+ demod,
+ state->internal->dev_ver);
+ return &state->frontend;
+ } else {
+ state->internal = kmalloc(sizeof(struct stv090x_internal),
+ GFP_KERNEL);
+ temp_int = append_internal(state->internal);
+ state->internal->num_used = 1;
+ state->internal->mclk = 0;
+ state->internal->dev_ver = 0;
+ state->internal->i2c_adap = state->i2c;
+ state->internal->i2c_addr = state->config->address;
+ dprintk(FE_INFO, 1, "Create New Internal Structure!");
+ }
+
+ mutex_init(&state->internal->demod_lock);
+ mutex_init(&state->internal->tuner_lock);
if (stv090x_sleep(&state->frontend) < 0) {
dprintk(FE_ERROR, 1, "Error putting device to sleep");
@@ -4331,10 +4575,10 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
goto error;
}
- dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x\n",
+ dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x",
state->device == STV0900 ? "STV0900" : "STV0903",
demod,
- state->dev_ver);
+ state->internal->dev_ver);
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb/frontends/stv090x.h
index b133807663ea..30f01a6902ac 100644
--- a/drivers/media/dvb/frontends/stv090x.h
+++ b/drivers/media/dvb/frontends/stv090x.h
@@ -60,6 +60,11 @@ enum stv090x_i2crpt {
STV090x_RPTLEVEL_2 = 7,
};
+enum stv090x_adc_range {
+ STV090x_ADC_2Vpp = 0,
+ STV090x_ADC_1Vpp = 1
+};
+
struct stv090x_config {
enum stv090x_device device;
enum stv090x_mode demod_mode;
@@ -68,13 +73,17 @@ struct stv090x_config {
u32 xtal; /* default: 8000000 */
u8 address; /* default: 0x68 */
- u32 ref_clk; /* default: 16000000 FIXME to tuner config */
-
u8 ts1_mode;
u8 ts2_mode;
+ u32 ts1_clk;
+ u32 ts2_clk;
enum stv090x_i2crpt repeater_level;
+ u8 tuner_bbgain; /* default: 10db */
+ enum stv090x_adc_range adc1_range; /* default: 2Vpp */
+ enum stv090x_adc_range adc2_range; /* default: 2Vpp */
+
bool diseqc_envelope_mode;
int (*tuner_init) (struct dvb_frontend *fe);
diff --git a/drivers/media/dvb/frontends/stv090x_priv.h b/drivers/media/dvb/frontends/stv090x_priv.h
index 5921a8d6c89f..5b780c80d496 100644
--- a/drivers/media/dvb/frontends/stv090x_priv.h
+++ b/drivers/media/dvb/frontends/stv090x_priv.h
@@ -230,11 +230,23 @@ struct stv090x_tab {
s32 read;
};
+struct stv090x_internal {
+ struct i2c_adapter *i2c_adap;
+ u8 i2c_addr;
+
+ struct mutex demod_lock; /* Lock access to shared register */
+ struct mutex tuner_lock; /* Lock access to tuners */
+ s32 mclk; /* Masterclock Divider factor */
+ u32 dev_ver;
+
+ int num_used;
+};
+
struct stv090x_state {
enum stv090x_device device;
enum stv090x_demodulator demod;
enum stv090x_mode demod_mode;
- u32 dev_ver;
+ struct stv090x_internal *internal;
struct i2c_adapter *i2c;
const struct stv090x_config *config;
@@ -256,11 +268,8 @@ struct stv090x_state {
u32 frequency;
u32 srate;
- s32 mclk; /* Masterclock Divider factor */
s32 tuner_bw;
- u32 tuner_refclk;
-
s32 search_range;
s32 DemodTimeout;
diff --git a/drivers/media/dvb/frontends/stv6110x.c b/drivers/media/dvb/frontends/stv6110x.c
index bcfcb652464c..f931ed07e92d 100644
--- a/drivers/media/dvb/frontends/stv6110x.c
+++ b/drivers/media/dvb/frontends/stv6110x.c
@@ -35,8 +35,6 @@ static unsigned int verbose;
module_param(verbose, int, 0644);
MODULE_PARM_DESC(verbose, "Set Verbosity level");
-static u8 stv6110x_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
-
static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data)
{
int ret;
@@ -58,12 +56,23 @@ static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data)
return 0;
}
-static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
+static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 data[], int len)
{
int ret;
const struct stv6110x_config *config = stv6110x->config;
- u8 buf[] = { reg, data };
- struct i2c_msg msg = { .addr = config->addr, .flags = 0, . buf = buf, .len = 2 };
+ u8 buf[len + 1];
+ struct i2c_msg msg = {
+ .addr = config->addr,
+ .flags = 0,
+ .buf = buf,
+ .len = len + 1
+ };
+
+ if (start + len > 8)
+ return -EINVAL;
+
+ buf[0] = start;
+ memcpy(&buf[1], data, len);
ret = i2c_transfer(stv6110x->i2c, &msg, 1);
if (ret != 1) {
@@ -74,18 +83,21 @@ static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
return 0;
}
+static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
+{
+ return stv6110x_write_regs(stv6110x, reg, &data, 1);
+}
+
static int stv6110x_init(struct dvb_frontend *fe)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
int ret;
- u8 i;
- for (i = 0; i < ARRAY_SIZE(stv6110x_regs); i++) {
- ret = stv6110x_write_reg(stv6110x, i, stv6110x_regs[i]);
- if (ret < 0) {
- dprintk(FE_ERROR, 1, "Initialization failed");
- return -1;
- }
+ ret = stv6110x_write_regs(stv6110x, 0, stv6110x->regs,
+ ARRAY_SIZE(stv6110x->regs));
+ if (ret < 0) {
+ dprintk(FE_ERROR, 1, "Initialization failed");
+ return -1;
}
return 0;
@@ -98,23 +110,23 @@ static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
s32 pVal, pCalc, rDivOpt = 0, pCalcOpt = 1000;
u8 i;
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
if (frequency <= 1023000) {
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
pVal = 40;
} else if (frequency <= 1300000) {
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
pVal = 40;
} else if (frequency <= 2046000) {
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
pVal = 20;
} else {
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
pVal = 20;
}
@@ -130,21 +142,21 @@ static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz;
divider = (divider + 5) / 10;
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt);
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider));
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider));
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider));
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider));
/* VCO Auto calibration */
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1);
- stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
- stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x_regs[STV6110x_TNG1]);
- stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x_regs[STV6110x_TNG0]);
- stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
+ stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]);
+ stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x->regs[STV6110x_TNG1]);
+ stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x->regs[STV6110x_TNG0]);
+ stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]);
for (i = 0; i < TRIALS; i++) {
- stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
- if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x_regs[STV6110x_STAT1]))
+ stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
+ if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x->regs[STV6110x_STAT1]))
break;
msleep(1);
}
@@ -156,14 +168,14 @@ static int stv6110x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
- stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x_regs[STV6110x_TNG1]);
- stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x_regs[STV6110x_TNG0]);
+ stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x->regs[STV6110x_TNG1]);
+ stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x->regs[STV6110x_TNG0]);
- *frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x_regs[STV6110x_TNG1]),
- STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x_regs[STV6110x_TNG0]))) * REFCLOCK_kHz;
+ *frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x->regs[STV6110x_TNG1]),
+ STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x->regs[STV6110x_TNG0]))) * REFCLOCK_kHz;
- *frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x_regs[STV6110x_TNG1]) +
- STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x_regs[STV6110x_TNG1])));
+ *frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x->regs[STV6110x_TNG1]) +
+ STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x->regs[STV6110x_TNG1])));
*frequency >>= 2;
@@ -179,27 +191,27 @@ static int stv6110x_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
halfbw = bandwidth >> 1;
if (halfbw > 36000000)
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */
else if (halfbw < 5000000)
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */
else
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */
- stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
- stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
+ stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]);
+ stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]);
for (i = 0; i < TRIALS; i++) {
- stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
- if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x_regs[STV6110x_STAT1]))
+ stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
+ if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x->regs[STV6110x_STAT1]))
break;
msleep(1);
}
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */
- stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */
+ stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]);
return 0;
}
@@ -208,8 +220,8 @@ static int stv6110x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
- stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x_regs[STV6110x_CTRL3]);
- *bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x_regs[STV6110x_CTRL3]) + 5) * 2000000;
+ stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x->regs[STV6110x_CTRL3]);
+ *bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x->regs[STV6110x_CTRL3]) + 5) * 2000000;
return 0;
}
@@ -222,20 +234,20 @@ static int stv6110x_set_refclock(struct dvb_frontend *fe, u32 refclock)
switch (refclock) {
default:
case 1:
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
break;
case 2:
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
break;
case 4:
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
break;
case 8:
case 0:
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
break;
}
- stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
+ stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]);
return 0;
}
@@ -244,8 +256,8 @@ static int stv6110x_get_bbgain(struct dvb_frontend *fe, u32 *gain)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
- stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x_regs[STV6110x_CTRL2]);
- *gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x_regs[STV6110x_CTRL2]);
+ stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x->regs[STV6110x_CTRL2]);
+ *gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x->regs[STV6110x_CTRL2]);
return 0;
}
@@ -254,8 +266,8 @@ static int stv6110x_set_bbgain(struct dvb_frontend *fe, u32 gain)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2);
- stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2);
+ stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]);
return 0;
}
@@ -267,19 +279,19 @@ static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode)
switch (mode) {
case TUNER_SLEEP:
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 0);
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 0);
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 0);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 0);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 0);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 0);
break;
case TUNER_WAKE:
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 1);
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 1);
- STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 1);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 1);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 1);
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 1);
break;
}
- ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
+ ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]);
if (ret < 0) {
dprintk(FE_ERROR, 1, "I/O Error");
return -EIO;
@@ -297,9 +309,9 @@ static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
- stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
+ stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
- if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x_regs[STV6110x_STAT1]))
+ if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x->regs[STV6110x_STAT1]))
*status = TUNER_PHASELOCKED;
else
*status = 0;
@@ -349,6 +361,8 @@ struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c)
{
struct stv6110x_state *stv6110x;
+ u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
+ int ret;
stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL);
if (stv6110x == NULL)
@@ -357,6 +371,44 @@ struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
stv6110x->i2c = i2c;
stv6110x->config = config;
stv6110x->devctl = &stv6110x_ctl;
+ memcpy(stv6110x->regs, default_regs, 8);
+
+ /* setup divider */
+ switch (stv6110x->config->clk_div) {
+ default:
+ case 1:
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
+ break;
+ case 2:
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
+ break;
+ case 4:
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
+ break;
+ case 8:
+ case 0:
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
+ break;
+ }
+
+ if (fe->ops.i2c_gate_ctrl) {
+ ret = fe->ops.i2c_gate_ctrl(fe, 1);
+ if (ret < 0)
+ goto error;
+ }
+
+ ret = stv6110x_write_regs(stv6110x, 0, stv6110x->regs,
+ ARRAY_SIZE(stv6110x->regs));
+ if (ret < 0) {
+ dprintk(FE_ERROR, 1, "Initialization failed");
+ goto error;
+ }
+
+ if (fe->ops.i2c_gate_ctrl) {
+ ret = fe->ops.i2c_gate_ctrl(fe, 0);
+ if (ret < 0)
+ goto error;
+ }
fe->tuner_priv = stv6110x;
fe->ops.tuner_ops = stv6110x_ops;
diff --git a/drivers/media/dvb/frontends/stv6110x.h b/drivers/media/dvb/frontends/stv6110x.h
index a38257080e01..2429ae6d7847 100644
--- a/drivers/media/dvb/frontends/stv6110x.h
+++ b/drivers/media/dvb/frontends/stv6110x.h
@@ -26,6 +26,7 @@
struct stv6110x_config {
u8 addr;
u32 refclk;
+ u8 clk_div; /* divisor value for the output clock */
};
enum tuner_mode {
diff --git a/drivers/media/dvb/frontends/stv6110x_priv.h b/drivers/media/dvb/frontends/stv6110x_priv.h
index 7260da633d49..0ec936a660a7 100644
--- a/drivers/media/dvb/frontends/stv6110x_priv.h
+++ b/drivers/media/dvb/frontends/stv6110x_priv.h
@@ -68,6 +68,7 @@
struct stv6110x_state {
struct i2c_adapter *i2c;
const struct stv6110x_config *config;
+ u8 regs[8];
struct stv6110x_devctl *devctl;
};
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 6c1dbf9288d8..6ca533ea0f0e 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -426,6 +426,10 @@ struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
id = tda10021_readreg(state, 0x1a);
if ((id & 0xf0) != 0x70) goto error;
+ /* Don't claim TDA10023 */
+ if (id == 0x7d)
+ goto error;
+
printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n",
state->config->demod_address, id);
diff --git a/drivers/media/dvb/frontends/tda665x.c b/drivers/media/dvb/frontends/tda665x.c
new file mode 100644
index 000000000000..c44fefe92d97
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda665x.c
@@ -0,0 +1,257 @@
+/*
+ TDA665x tuner driver
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/kernel.h>
+#include <linux/module.h>
+
+#include "dvb_frontend.h"
+#include "tda665x.h"
+
+struct tda665x_state {
+ struct dvb_frontend *fe;
+ struct i2c_adapter *i2c;
+ const struct tda665x_config *config;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+static int tda665x_read(struct tda665x_state *state, u8 *buf)
+{
+ const struct tda665x_config *config = state->config;
+ int err = 0;
+ struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD, .buf = buf, .len = 2 };
+
+ err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1)
+ goto exit;
+
+ return err;
+exit:
+ printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
+ return err;
+}
+
+static int tda665x_write(struct tda665x_state *state, u8 *buf, u8 length)
+{
+ const struct tda665x_config *config = state->config;
+ int err = 0;
+ struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = length };
+
+ err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1)
+ goto exit;
+
+ return err;
+exit:
+ printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
+ return err;
+}
+
+static int tda665x_get_state(struct dvb_frontend *fe,
+ enum tuner_param param,
+ struct tuner_state *tstate)
+{
+ struct tda665x_state *state = fe->tuner_priv;
+ int err = 0;
+
+ switch (param) {
+ case DVBFE_TUNER_FREQUENCY:
+ tstate->frequency = state->frequency;
+ break;
+ case DVBFE_TUNER_BANDWIDTH:
+ break;
+ default:
+ printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+static int tda665x_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct tda665x_state *state = fe->tuner_priv;
+ u8 result = 0;
+ int err = 0;
+
+ *status = 0;
+
+ err = tda665x_read(state, &result);
+ if (err < 0)
+ goto exit;
+
+ if ((result >> 6) & 0x01) {
+ printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__);
+ *status = 1;
+ }
+
+ return err;
+exit:
+ printk(KERN_ERR "%s: I/O Error\n", __func__);
+ return err;
+}
+
+static int tda665x_set_state(struct dvb_frontend *fe,
+ enum tuner_param param,
+ struct tuner_state *tstate)
+{
+ struct tda665x_state *state = fe->tuner_priv;
+ const struct tda665x_config *config = state->config;
+ u32 frequency, status = 0;
+ u8 buf[4];
+ int err = 0;
+
+ if (param & DVBFE_TUNER_FREQUENCY) {
+
+ frequency = tstate->frequency;
+ if ((frequency < config->frequency_max) || (frequency > config->frequency_min)) {
+ printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
+ return -EINVAL;
+ }
+
+ frequency += config->frequency_offst;
+ frequency *= config->ref_multiplier;
+ frequency += config->ref_divider >> 1;
+ frequency /= config->ref_divider;
+
+ buf[0] = (u8) ((frequency & 0x7f00) >> 8);
+ buf[1] = (u8) (frequency & 0x00ff) >> 0;
+ buf[2] = 0x80 | 0x40 | 0x02;
+ buf[3] = 0x00;
+
+ /* restore frequency */
+ frequency = tstate->frequency;
+
+ if (frequency < 153000000) {
+ /* VHF-L */
+ buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
+ if (frequency < 68000000)
+ buf[3] |= 0x40; /* 83uA */
+ if (frequency < 1040000000)
+ buf[3] |= 0x60; /* 122uA */
+ if (frequency < 1250000000)
+ buf[3] |= 0x80; /* 163uA */
+ else
+ buf[3] |= 0xa0; /* 254uA */
+ } else if (frequency < 438000000) {
+ /* VHF-H */
+ buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
+ if (frequency < 230000000)
+ buf[3] |= 0x40;
+ if (frequency < 300000000)
+ buf[3] |= 0x60;
+ else
+ buf[3] |= 0x80;
+ } else {
+ /* UHF */
+ buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
+ if (frequency < 470000000)
+ buf[3] |= 0x60;
+ if (frequency < 526000000)
+ buf[3] |= 0x80;
+ else
+ buf[3] |= 0xa0;
+ }
+
+ /* Set params */
+ err = tda665x_write(state, buf, 5);
+ if (err < 0)
+ goto exit;
+
+ /* sleep for some time */
+ printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
+ msleep(20);
+ /* check status */
+ err = tda665x_get_status(fe, &status);
+ if (err < 0)
+ goto exit;
+
+ if (status == 1) {
+ printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", __func__, status);
+ state->frequency = frequency; /* cache successful state */
+ } else {
+ printk(KERN_ERR "%s: No Phase lock: status=%d\n", __func__, status);
+ }
+ } else {
+ printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
+ return -EINVAL;
+ }
+
+ return 0;
+exit:
+ printk(KERN_ERR "%s: I/O Error\n", __func__);
+ return err;
+}
+
+static int tda665x_release(struct dvb_frontend *fe)
+{
+ struct tda665x_state *state = fe->tuner_priv;
+
+ fe->tuner_priv = NULL;
+ kfree(state);
+ return 0;
+}
+
+static struct dvb_tuner_ops tda665x_ops = {
+
+ .set_state = tda665x_set_state,
+ .get_state = tda665x_get_state,
+ .get_status = tda665x_get_status,
+ .release = tda665x_release
+};
+
+struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+ const struct tda665x_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct tda665x_state *state = NULL;
+ struct dvb_tuner_info *info;
+
+ state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL);
+ if (state == NULL)
+ goto exit;
+
+ state->config = config;
+ state->i2c = i2c;
+ state->fe = fe;
+ fe->tuner_priv = state;
+ fe->ops.tuner_ops = tda665x_ops;
+ info = &fe->ops.tuner_ops.info;
+
+ memcpy(info->name, config->name, sizeof(config->name));
+ info->frequency_min = config->frequency_min;
+ info->frequency_max = config->frequency_max;
+ info->frequency_step = config->frequency_offst;
+
+ printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name);
+
+ return fe;
+
+exit:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(tda665x_attach);
+
+MODULE_DESCRIPTION("TDA665x driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda665x.h b/drivers/media/dvb/frontends/tda665x.h
new file mode 100644
index 000000000000..ec7927aa75ae
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda665x.h
@@ -0,0 +1,52 @@
+/*
+ TDA665x tuner driver
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __TDA665x_H
+#define __TDA665x_H
+
+struct tda665x_config {
+ char name[128];
+
+ u8 addr;
+ u32 frequency_min;
+ u32 frequency_max;
+ u32 frequency_offst;
+ u32 ref_multiplier;
+ u32 ref_divider;
+};
+
+#if defined(CONFIG_DVB_TDA665x) || (defined(CONFIG_DVB_TDA665x_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+ const struct tda665x_config *config,
+ struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+ const struct tda665x_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+
+#endif /* CONFIG_DVB_TDA665x */
+
+#endif /* __TDA665x_H */
diff --git a/drivers/media/dvb/frontends/tda8261.c b/drivers/media/dvb/frontends/tda8261.c
index 320c3c36d8b2..614afcec05f1 100644
--- a/drivers/media/dvb/frontends/tda8261.c
+++ b/drivers/media/dvb/frontends/tda8261.c
@@ -39,7 +39,7 @@ static int tda8261_read(struct tda8261_state *state, u8 *buf)
{
const struct tda8261_config *config = state->config;
int err = 0;
- struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD,.buf = buf, .len = 2 };
+ struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD,.buf = buf, .len = 1 };
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
printk("%s: read error, err=%d\n", __func__, err);
diff --git a/drivers/media/dvb/frontends/zl10036.c b/drivers/media/dvb/frontends/zl10036.c
index 4e814ff22b23..34c5de491d2b 100644
--- a/drivers/media/dvb/frontends/zl10036.c
+++ b/drivers/media/dvb/frontends/zl10036.c
@@ -411,7 +411,7 @@ static int zl10036_init_regs(struct zl10036_state *state)
state->bf = 0xff;
if (!state->config->rf_loop_enable)
- zl10036_init_tab[1][2] |= 0x01;
+ zl10036_init_tab[1][0] |= 0x01;
deb_info("%s\n", __func__);
diff --git a/drivers/media/dvb/frontends/zl10039.c b/drivers/media/dvb/frontends/zl10039.c
index 11b29cb883e6..c085e58a94bf 100644
--- a/drivers/media/dvb/frontends/zl10039.c
+++ b/drivers/media/dvb/frontends/zl10039.c
@@ -287,7 +287,6 @@ struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
break;
default:
dprintk("Chip ID=%x does not match a known type\n", state->id);
- break;
goto error;
}
diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig
new file mode 100644
index 000000000000..f7b72a32adf3
--- /dev/null
+++ b/drivers/media/dvb/mantis/Kconfig
@@ -0,0 +1,32 @@
+config MANTIS_CORE
+ tristate "Mantis/Hopper PCI bridge based devices"
+ depends on PCI && I2C && INPUT
+
+ help
+ Support for PCI cards based on the Mantis and Hopper PCi bridge.
+
+ Say Y if you own such a device and want to use it.
+
+config DVB_MANTIS
+ tristate "MANTIS based cards"
+ depends on MANTIS_CORE && DVB_CORE && PCI && I2C
+ select DVB_MB86A16
+ select DVB_ZL10353
+ select DVB_STV0299
+ select DVB_PLL
+ help
+ Support for PCI cards based on the Mantis PCI bridge.
+ Say Y when you have a Mantis based DVB card and want to use it.
+
+ If unsure say N.
+
+config DVB_HOPPER
+ tristate "HOPPER based cards"
+ depends on MANTIS_CORE && DVB_CORE && PCI && I2C
+ select DVB_ZL10353
+ select DVB_PLL
+ help
+ Support for PCI cards based on the Hopper PCI bridge.
+ Say Y when you have a Hopper based DVB card and want to use it.
+
+ If unsure say N
diff --git a/drivers/media/dvb/mantis/Makefile b/drivers/media/dvb/mantis/Makefile
new file mode 100644
index 000000000000..98dc5cd258ac
--- /dev/null
+++ b/drivers/media/dvb/mantis/Makefile
@@ -0,0 +1,28 @@
+mantis_core-objs := mantis_ioc.o \
+ mantis_uart.o \
+ mantis_dma.o \
+ mantis_pci.o \
+ mantis_i2c.o \
+ mantis_dvb.o \
+ mantis_evm.o \
+ mantis_hif.o \
+ mantis_ca.o \
+ mantis_pcmcia.o \
+ mantis_input.o
+
+mantis-objs := mantis_cards.o \
+ mantis_vp1033.o \
+ mantis_vp1034.o \
+ mantis_vp1041.o \
+ mantis_vp2033.o \
+ mantis_vp2040.o \
+ mantis_vp3030.o
+
+hopper-objs := hopper_cards.o \
+ hopper_vp3028.o
+
+obj-$(CONFIG_MANTIS_CORE) += mantis_core.o
+obj-$(CONFIG_DVB_MANTIS) += mantis.o
+obj-$(CONFIG_DVB_HOPPER) += hopper.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c
new file mode 100644
index 000000000000..d073c61e3c0d
--- /dev/null
+++ b/drivers/media/dvb/mantis/hopper_cards.c
@@ -0,0 +1,275 @@
+/*
+ Hopper PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/irq.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "hopper_vp3028.h"
+#include "mantis_dma.h"
+#include "mantis_dvb.h"
+#include "mantis_uart.h"
+#include "mantis_ioc.h"
+#include "mantis_pci.h"
+#include "mantis_i2c.h"
+#include "mantis_reg.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+#define DRIVER_NAME "Hopper"
+
+static char *label[10] = {
+ "DMA",
+ "IRQ-0",
+ "IRQ-1",
+ "OCERR",
+ "PABRT",
+ "RIPRR",
+ "PPERR",
+ "FTRGT",
+ "RISCI",
+ "RACK"
+};
+
+static int devs;
+
+static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
+{
+ u32 stat = 0, mask = 0, lstat = 0, mstat = 0;
+ u32 rst_stat = 0, rst_mask = 0;
+
+ struct mantis_pci *mantis;
+ struct mantis_ca *ca;
+
+ mantis = (struct mantis_pci *) dev_id;
+ if (unlikely(mantis == NULL)) {
+ dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
+ return IRQ_NONE;
+ }
+ ca = mantis->mantis_ca;
+
+ stat = mmread(MANTIS_INT_STAT);
+ mask = mmread(MANTIS_INT_MASK);
+ mstat = lstat = stat & ~MANTIS_INT_RISCSTAT;
+ if (!(stat & mask))
+ return IRQ_NONE;
+
+ rst_mask = MANTIS_GPIF_WRACK |
+ MANTIS_GPIF_OTHERR |
+ MANTIS_SBUF_WSTO |
+ MANTIS_GPIF_EXTIRQ;
+
+ rst_stat = mmread(MANTIS_GPIF_STATUS);
+ rst_stat &= rst_mask;
+ mmwrite(rst_stat, MANTIS_GPIF_STATUS);
+
+ mantis->mantis_int_stat = stat;
+ mantis->mantis_int_mask = mask;
+ dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
+ if (stat & MANTIS_INT_RISCEN) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
+ }
+ if (stat & MANTIS_INT_IRQ0) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
+ mantis->gpif_status = rst_stat;
+ wake_up(&ca->hif_write_wq);
+ schedule_work(&ca->hif_evm_work);
+ }
+ if (stat & MANTIS_INT_IRQ1) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
+ schedule_work(&mantis->uart_work);
+ }
+ if (stat & MANTIS_INT_OCERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
+ }
+ if (stat & MANTIS_INT_PABORT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
+ }
+ if (stat & MANTIS_INT_RIPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
+ }
+ if (stat & MANTIS_INT_PPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
+ }
+ if (stat & MANTIS_INT_FTRGT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
+ }
+ if (stat & MANTIS_INT_RISCI) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
+ mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
+ tasklet_schedule(&mantis->tasklet);
+ }
+ if (stat & MANTIS_INT_I2CDONE) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
+ wake_up(&mantis->i2c_wq);
+ }
+ mmwrite(stat, MANTIS_INT_STAT);
+ stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE |
+ MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 |
+ MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 |
+ MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 |
+ MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 |
+ MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 |
+ MANTIS_INT_IRQ0 | MANTIS_INT_OCERR |
+ MANTIS_INT_PABORT | MANTIS_INT_RIPERR |
+ MANTIS_INT_PPERR | MANTIS_INT_FTRGT |
+ MANTIS_INT_RISCI);
+
+ if (stat)
+ dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
+
+ dprintk(MANTIS_DEBUG, 0, "\n");
+ return IRQ_HANDLED;
+}
+
+static int __devinit hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+ struct mantis_pci *mantis;
+ struct mantis_hwconfig *config;
+ int err = 0;
+
+ mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
+ if (mantis == NULL) {
+ printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
+ err = -ENOMEM;
+ goto fail0;
+ }
+
+ mantis->num = devs;
+ mantis->verbose = verbose;
+ mantis->pdev = pdev;
+ config = (struct mantis_hwconfig *) pci_id->driver_data;
+ config->irq_handler = &hopper_irq_handler;
+ mantis->hwconfig = config;
+
+ err = mantis_pci_init(mantis);
+ if (err) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_stream_control(mantis, STREAM_TO_HIF);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_i2c_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_get_mac(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_dma_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
+ goto fail3;
+ }
+
+ err = mantis_dvb_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
+ goto fail4;
+ }
+ devs++;
+
+ return err;
+
+fail4:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
+ mantis_dma_exit(mantis);
+
+fail3:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
+ mantis_i2c_exit(mantis);
+
+fail2:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
+ mantis_pci_exit(mantis);
+
+fail1:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
+ kfree(mantis);
+
+fail0:
+ return err;
+}
+
+static void __devexit hopper_pci_remove(struct pci_dev *pdev)
+{
+ struct mantis_pci *mantis = pci_get_drvdata(pdev);
+
+ if (mantis) {
+ mantis_dvb_exit(mantis);
+ mantis_dma_exit(mantis);
+ mantis_i2c_exit(mantis);
+ mantis_pci_exit(mantis);
+ kfree(mantis);
+ }
+ return;
+
+}
+
+static struct pci_device_id hopper_pci_table[] = {
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config),
+ { }
+};
+
+static struct pci_driver hopper_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = hopper_pci_table,
+ .probe = hopper_pci_probe,
+ .remove = hopper_pci_remove,
+};
+
+static int __devinit hopper_init(void)
+{
+ return pci_register_driver(&hopper_pci_driver);
+}
+
+static void __devexit hopper_exit(void)
+{
+ return pci_unregister_driver(&hopper_pci_driver);
+}
+
+module_init(hopper_init);
+module_exit(hopper_exit);
+
+MODULE_DESCRIPTION("HOPPER driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.c b/drivers/media/dvb/mantis/hopper_vp3028.c
new file mode 100644
index 000000000000..96674c78e86b
--- /dev/null
+++ b/drivers/media/dvb/mantis/hopper_vp3028.c
@@ -0,0 +1,88 @@
+/*
+ Hopper VP-3028 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "zl10353.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "hopper_vp3028.h"
+
+struct zl10353_config hopper_vp3028_config = {
+ .demod_address = 0x0f,
+};
+
+#define MANTIS_MODEL_NAME "VP-3028"
+#define MANTIS_DEV_TYPE "DVB-T"
+
+static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ int err = 0;
+
+ gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ err = mantis_frontend_power(mantis, POWER_ON);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 1);
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ msleep(250);
+ dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
+ fe = zl10353_attach(&hopper_vp3028_config, adapter);
+
+ if (!fe)
+ return -1;
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp3028_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_188,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp3028_frontend_init,
+ .power = GPIF_A00,
+ .reset = GPIF_A03,
+};
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.h b/drivers/media/dvb/mantis/hopper_vp3028.h
new file mode 100644
index 000000000000..57239498bc87
--- /dev/null
+++ b/drivers/media/dvb/mantis/hopper_vp3028.h
@@ -0,0 +1,30 @@
+/*
+ Hopper VP-3028 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_VP3028_H
+#define __MANTIS_VP3028_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_3028_DVB_T 0x0028
+
+extern struct mantis_hwconfig vp3028_config;
+
+#endif /* __MANTIS_VP3028_H */
diff --git a/drivers/media/dvb/mantis/mantis_ca.c b/drivers/media/dvb/mantis/mantis_ca.c
new file mode 100644
index 000000000000..403ce043d00e
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_ca.c
@@ -0,0 +1,207 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h"
+#include "mantis_hif.h"
+#include "mantis_reg.h"
+
+#include "mantis_ca.h"
+
+static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot);
+
+ if (slot != 0)
+ return -EINVAL;
+
+ return mantis_hif_read_mem(ca, addr);
+}
+
+static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot);
+
+ if (slot != 0)
+ return -EINVAL;
+
+ return mantis_hif_write_mem(ca, addr, data);
+}
+
+static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot);
+
+ if (slot != 0)
+ return -EINVAL;
+
+ return mantis_hif_read_iom(ca, addr);
+}
+
+static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot);
+
+ if (slot != 0)
+ return -EINVAL;
+
+ return mantis_hif_write_iom(ca, addr, data);
+}
+
+static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot);
+ udelay(500); /* Wait.. */
+ mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */
+ udelay(500);
+ mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */
+ msleep(1000);
+ dvb_ca_en50221_camready_irq(&ca->en50221, 0);
+
+ return 0;
+}
+
+static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot);
+
+ return 0;
+}
+
+static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot);
+/* mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */
+
+ return 0;
+}
+
+static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot);
+
+ if (ca->slot_state == MODULE_INSERTED) {
+ dprintk(MANTIS_DEBUG, 1, "CA Module present and ready");
+ return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+ } else {
+ dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready");
+ }
+
+ return 0;
+}
+
+int mantis_ca_init(struct mantis_pci *mantis)
+{
+ struct dvb_adapter *dvb_adapter = &mantis->dvb_adapter;
+ struct mantis_ca *ca;
+ int ca_flags = 0, result;
+
+ dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA");
+ ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL);
+ if (!ca) {
+ dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting ..");
+ result = -ENOMEM;
+ goto err;
+ }
+
+ ca->ca_priv = mantis;
+ mantis->mantis_ca = ca;
+ ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE;
+ /* register CA interface */
+ ca->en50221.owner = THIS_MODULE;
+ ca->en50221.read_attribute_mem = mantis_ca_read_attr_mem;
+ ca->en50221.write_attribute_mem = mantis_ca_write_attr_mem;
+ ca->en50221.read_cam_control = mantis_ca_read_cam_ctl;
+ ca->en50221.write_cam_control = mantis_ca_write_cam_ctl;
+ ca->en50221.slot_reset = mantis_ca_slot_reset;
+ ca->en50221.slot_shutdown = mantis_ca_slot_shutdown;
+ ca->en50221.slot_ts_enable = mantis_ts_control;
+ ca->en50221.poll_slot_status = mantis_slot_status;
+ ca->en50221.data = ca;
+
+ mutex_init(&ca->ca_lock);
+
+ init_waitqueue_head(&ca->hif_data_wq);
+ init_waitqueue_head(&ca->hif_opdone_wq);
+ init_waitqueue_head(&ca->hif_write_wq);
+
+ dprintk(MANTIS_ERROR, 1, "Registering EN50221 device");
+ result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1);
+ if (result != 0) {
+ dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result);
+ goto err;
+ }
+ dprintk(MANTIS_ERROR, 1, "Registered EN50221 device");
+ mantis_evmgr_init(ca);
+ return 0;
+err:
+ kfree(ca);
+ return result;
+}
+EXPORT_SYMBOL_GPL(mantis_ca_init);
+
+void mantis_ca_exit(struct mantis_pci *mantis)
+{
+ struct mantis_ca *ca = mantis->mantis_ca;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis CA exit");
+
+ mantis_evmgr_exit(ca);
+ dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device");
+ if (ca)
+ dvb_ca_en50221_release(&ca->en50221);
+
+ kfree(ca);
+}
+EXPORT_SYMBOL_GPL(mantis_ca_exit);
diff --git a/drivers/media/dvb/mantis/mantis_ca.h b/drivers/media/dvb/mantis/mantis_ca.h
new file mode 100644
index 000000000000..dc63e55f7eca
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_ca.h
@@ -0,0 +1,27 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_CA_H
+#define __MANTIS_CA_H
+
+extern int mantis_ca_init(struct mantis_pci *mantis);
+extern void mantis_ca_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_CA_H */
diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c
new file mode 100644
index 000000000000..16f1708fd3bc
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_cards.c
@@ -0,0 +1,305 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/irq.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+
+#include "mantis_vp1033.h"
+#include "mantis_vp1034.h"
+#include "mantis_vp1041.h"
+#include "mantis_vp2033.h"
+#include "mantis_vp2040.h"
+#include "mantis_vp3030.h"
+
+#include "mantis_dma.h"
+#include "mantis_ca.h"
+#include "mantis_dvb.h"
+#include "mantis_uart.h"
+#include "mantis_ioc.h"
+#include "mantis_pci.h"
+#include "mantis_i2c.h"
+#include "mantis_reg.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+static int devs;
+
+#define DRIVER_NAME "Mantis"
+
+static char *label[10] = {
+ "DMA",
+ "IRQ-0",
+ "IRQ-1",
+ "OCERR",
+ "PABRT",
+ "RIPRR",
+ "PPERR",
+ "FTRGT",
+ "RISCI",
+ "RACK"
+};
+
+static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
+{
+ u32 stat = 0, mask = 0, lstat = 0, mstat = 0;
+ u32 rst_stat = 0, rst_mask = 0;
+
+ struct mantis_pci *mantis;
+ struct mantis_ca *ca;
+
+ mantis = (struct mantis_pci *) dev_id;
+ if (unlikely(mantis == NULL)) {
+ dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
+ return IRQ_NONE;
+ }
+ ca = mantis->mantis_ca;
+
+ stat = mmread(MANTIS_INT_STAT);
+ mask = mmread(MANTIS_INT_MASK);
+ mstat = lstat = stat & ~MANTIS_INT_RISCSTAT;
+ if (!(stat & mask))
+ return IRQ_NONE;
+
+ rst_mask = MANTIS_GPIF_WRACK |
+ MANTIS_GPIF_OTHERR |
+ MANTIS_SBUF_WSTO |
+ MANTIS_GPIF_EXTIRQ;
+
+ rst_stat = mmread(MANTIS_GPIF_STATUS);
+ rst_stat &= rst_mask;
+ mmwrite(rst_stat, MANTIS_GPIF_STATUS);
+
+ mantis->mantis_int_stat = stat;
+ mantis->mantis_int_mask = mask;
+ dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
+ if (stat & MANTIS_INT_RISCEN) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
+ }
+ if (stat & MANTIS_INT_IRQ0) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
+ mantis->gpif_status = rst_stat;
+ wake_up(&ca->hif_write_wq);
+ schedule_work(&ca->hif_evm_work);
+ }
+ if (stat & MANTIS_INT_IRQ1) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
+ schedule_work(&mantis->uart_work);
+ }
+ if (stat & MANTIS_INT_OCERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
+ }
+ if (stat & MANTIS_INT_PABORT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
+ }
+ if (stat & MANTIS_INT_RIPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
+ }
+ if (stat & MANTIS_INT_PPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
+ }
+ if (stat & MANTIS_INT_FTRGT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
+ }
+ if (stat & MANTIS_INT_RISCI) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
+ mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
+ tasklet_schedule(&mantis->tasklet);
+ }
+ if (stat & MANTIS_INT_I2CDONE) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
+ wake_up(&mantis->i2c_wq);
+ }
+ mmwrite(stat, MANTIS_INT_STAT);
+ stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE |
+ MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 |
+ MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 |
+ MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 |
+ MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 |
+ MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 |
+ MANTIS_INT_IRQ0 | MANTIS_INT_OCERR |
+ MANTIS_INT_PABORT | MANTIS_INT_RIPERR |
+ MANTIS_INT_PPERR | MANTIS_INT_FTRGT |
+ MANTIS_INT_RISCI);
+
+ if (stat)
+ dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
+
+ dprintk(MANTIS_DEBUG, 0, "\n");
+ return IRQ_HANDLED;
+}
+
+static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+ struct mantis_pci *mantis;
+ struct mantis_hwconfig *config;
+ int err = 0;
+
+ mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
+ if (mantis == NULL) {
+ printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
+ err = -ENOMEM;
+ goto fail0;
+ }
+
+ mantis->num = devs;
+ mantis->verbose = verbose;
+ mantis->pdev = pdev;
+ config = (struct mantis_hwconfig *) pci_id->driver_data;
+ config->irq_handler = &mantis_irq_handler;
+ mantis->hwconfig = config;
+
+ err = mantis_pci_init(mantis);
+ if (err) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_stream_control(mantis, STREAM_TO_HIF);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_i2c_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_get_mac(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_dma_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
+ goto fail3;
+ }
+
+ err = mantis_dvb_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
+ goto fail4;
+ }
+ err = mantis_uart_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err);
+ goto fail6;
+ }
+
+ devs++;
+
+ return err;
+
+
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err);
+ mantis_uart_exit(mantis);
+
+fail6:
+fail4:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
+ mantis_dma_exit(mantis);
+
+fail3:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
+ mantis_i2c_exit(mantis);
+
+fail2:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
+ mantis_pci_exit(mantis);
+
+fail1:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
+ kfree(mantis);
+
+fail0:
+ return err;
+}
+
+static void __devexit mantis_pci_remove(struct pci_dev *pdev)
+{
+ struct mantis_pci *mantis = pci_get_drvdata(pdev);
+
+ if (mantis) {
+
+ mantis_uart_exit(mantis);
+ mantis_dvb_exit(mantis);
+ mantis_dma_exit(mantis);
+ mantis_i2c_exit(mantis);
+ mantis_pci_exit(mantis);
+ kfree(mantis);
+ }
+ return;
+}
+
+static struct pci_device_id mantis_pci_table[] = {
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config),
+ MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config),
+ MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config),
+ MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config),
+ MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config),
+ MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2033_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config),
+ { }
+};
+
+static struct pci_driver mantis_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = mantis_pci_table,
+ .probe = mantis_pci_probe,
+ .remove = mantis_pci_remove,
+};
+
+static int __devinit mantis_init(void)
+{
+ return pci_register_driver(&mantis_pci_driver);
+}
+
+static void __devexit mantis_exit(void)
+{
+ return pci_unregister_driver(&mantis_pci_driver);
+}
+
+module_init(mantis_init);
+module_exit(mantis_exit);
+
+MODULE_DESCRIPTION("MANTIS driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/mantis_common.h b/drivers/media/dvb/mantis/mantis_common.h
new file mode 100644
index 000000000000..d0b645a483c9
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_common.h
@@ -0,0 +1,179 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_COMMON_H
+#define __MANTIS_COMMON_H
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#include "mantis_uart.h"
+
+#include "mantis_link.h"
+
+#define MANTIS_ERROR 0
+#define MANTIS_NOTICE 1
+#define MANTIS_INFO 2
+#define MANTIS_DEBUG 3
+#define MANTIS_TMG 9
+
+#define dprintk(y, z, format, arg...) do { \
+ if (z) { \
+ if ((mantis->verbose > MANTIS_ERROR) && (mantis->verbose > y)) \
+ printk(KERN_ERR "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ else if ((mantis->verbose > MANTIS_NOTICE) && (mantis->verbose > y)) \
+ printk(KERN_NOTICE "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ else if ((mantis->verbose > MANTIS_INFO) && (mantis->verbose > y)) \
+ printk(KERN_INFO "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ else if ((mantis->verbose > MANTIS_DEBUG) && (mantis->verbose > y)) \
+ printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ else if ((mantis->verbose > MANTIS_TMG) && (mantis->verbose > y)) \
+ printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ } else { \
+ if (mantis->verbose > y) \
+ printk(format , ##arg); \
+ } \
+} while(0)
+
+#define mwrite(dat, addr) writel((dat), addr)
+#define mread(addr) readl(addr)
+
+#define mmwrite(dat, addr) mwrite((dat), (mantis->mmio + (addr)))
+#define mmread(addr) mread(mantis->mmio + (addr))
+
+#define MANTIS_TS_188 0
+#define MANTIS_TS_204 1
+
+#define TWINHAN_TECHNOLOGIES 0x1822
+#define MANTIS 0x4e35
+
+#define TECHNISAT 0x1ae4
+#define TERRATEC 0x153b
+
+#define MAKE_ENTRY(__subven, __subdev, __configptr) { \
+ .vendor = TWINHAN_TECHNOLOGIES, \
+ .device = MANTIS, \
+ .subvendor = (__subven), \
+ .subdevice = (__subdev), \
+ .driver_data = (unsigned long) (__configptr) \
+}
+
+enum mantis_i2c_mode {
+ MANTIS_PAGE_MODE = 0,
+ MANTIS_BYTE_MODE,
+};
+
+struct mantis_pci;
+
+struct mantis_hwconfig {
+ char *model_name;
+ char *dev_type;
+ u32 ts_size;
+
+ enum mantis_baud baud_rate;
+ enum mantis_parity parity;
+ u32 bytes;
+
+ irqreturn_t (*irq_handler)(int irq, void *dev_id);
+ int (*frontend_init)(struct mantis_pci *mantis, struct dvb_frontend *fe);
+
+ u8 power;
+ u8 reset;
+
+ enum mantis_i2c_mode i2c_mode;
+};
+
+struct mantis_pci {
+ unsigned int verbose;
+
+ /* PCI stuff */
+ u16 vendor_id;
+ u16 device_id;
+ u16 subsystem_vendor;
+ u16 subsystem_device;
+
+ u8 latency;
+
+ struct pci_dev *pdev;
+
+ unsigned long mantis_addr;
+ void __iomem *mmio;
+
+ u8 irq;
+ u8 revision;
+
+ unsigned int num;
+
+ /* RISC Core */
+ u32 finished_block;
+ u32 last_block;
+ u32 line_bytes;
+ u32 line_count;
+ u32 risc_pos;
+ u8 *buf_cpu;
+ dma_addr_t buf_dma;
+ u32 *risc_cpu;
+ dma_addr_t risc_dma;
+
+ struct tasklet_struct tasklet;
+
+ struct i2c_adapter adapter;
+ int i2c_rc;
+ wait_queue_head_t i2c_wq;
+ struct mutex i2c_lock;
+
+ /* DVB stuff */
+ struct dvb_adapter dvb_adapter;
+ struct dvb_frontend *fe;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_hw;
+ struct dmx_frontend fe_mem;
+ struct dvb_net dvbnet;
+
+ u8 feeds;
+
+ struct mantis_hwconfig *hwconfig;
+
+ u32 mantis_int_stat;
+ u32 mantis_int_mask;
+
+ /* board specific */
+ u8 mac_address[8];
+ u32 sub_vendor_id;
+ u32 sub_device_id;
+
+ /* A12 A13 A14 */
+ u32 gpio_status;
+
+ u32 gpif_status;
+
+ struct mantis_ca *mantis_ca;
+
+ wait_queue_head_t uart_wq;
+ struct work_struct uart_work;
+ spinlock_t uart_lock;
+
+ struct input_dev *rc;
+};
+
+#define MANTIS_HIF_STATUS (mantis->gpio_status)
+
+#endif /* __MANTIS_COMMON_H */
diff --git a/drivers/media/dvb/mantis/mantis_core.c b/drivers/media/dvb/mantis/mantis_core.c
new file mode 100644
index 000000000000..8113b23ce448
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_core.c
@@ -0,0 +1,238 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 "mantis_common.h"
+#include "mantis_core.h"
+#include "mantis_vp1033.h"
+#include "mantis_vp1034.h"
+#include "mantis_vp1041.h"
+#include "mantis_vp2033.h"
+#include "mantis_vp2040.h"
+#include "mantis_vp3030.h"
+
+static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
+{
+ int err;
+ struct i2c_msg msg[] = {
+ {
+ .addr = 0x50,
+ .flags = 0,
+ .buf = data,
+ .len = 1
+ }, {
+ .addr = 0x50,
+ .flags = I2C_M_RD,
+ .buf = data,
+ .len = length
+ },
+ };
+
+ err = i2c_transfer(&mantis->adapter, msg, 2);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1,
+ "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
+ err, data[0], data[1]);
+
+ return err;
+ }
+
+ return 0;
+}
+
+static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
+{
+ int err;
+
+ struct i2c_msg msg = {
+ .addr = 0x50,
+ .flags = 0,
+ .buf = data,
+ .len = length
+ };
+
+ err = i2c_transfer(&mantis->adapter, &msg, 1);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1,
+ "ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >",
+ err, length, data[0], data[1]);
+
+ return err;
+ }
+
+ return 0;
+}
+
+static int get_mac_address(struct mantis_pci *mantis)
+{
+ int err;
+
+ mantis->mac_address[0] = 0x08;
+ err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error");
+
+ return err;
+ }
+ dprintk(verbose, MANTIS_ERROR, 0,
+ " MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+ mantis->mac_address[0], mantis->mac_address[1],
+ mantis->mac_address[2], mantis->mac_address[3],
+ mantis->mac_address[4], mantis->mac_address[5]);
+
+ return 0;
+}
+
+#define MANTIS_MODEL_UNKNOWN "UNKNOWN"
+#define MANTIS_DEV_UNKNOWN "UNKNOWN"
+
+struct mantis_hwconfig unknown_device = {
+ .model_name = MANTIS_MODEL_UNKNOWN,
+ .dev_type = MANTIS_DEV_UNKNOWN,
+};
+
+static void mantis_load_config(struct mantis_pci *mantis)
+{
+ switch (mantis->subsystem_device) {
+ case MANTIS_VP_1033_DVB_S: /* VP-1033 */
+ mantis->hwconfig = &vp1033_mantis_config;
+ break;
+ case MANTIS_VP_1034_DVB_S: /* VP-1034 */
+ mantis->hwconfig = &vp1034_mantis_config;
+ break;
+ case MANTIS_VP_1041_DVB_S2: /* VP-1041 */
+ case TECHNISAT_SKYSTAR_HD2:
+ mantis->hwconfig = &vp1041_mantis_config;
+ break;
+ case MANTIS_VP_2033_DVB_C: /* VP-2033 */
+ mantis->hwconfig = &vp2033_mantis_config;
+ break;
+ case MANTIS_VP_2040_DVB_C: /* VP-2040 */
+ case TERRATEC_CINERGY_C_PCI: /* VP-2040 clone */
+ case TECHNISAT_CABLESTAR_HD2:
+ mantis->hwconfig = &vp2040_mantis_config;
+ break;
+ case MANTIS_VP_3030_DVB_T: /* VP-3030 */
+ mantis->hwconfig = &vp3030_mantis_config;
+ break;
+ default:
+ mantis->hwconfig = &unknown_device;
+ break;
+ }
+}
+
+int mantis_core_init(struct mantis_pci *mantis)
+{
+ int err = 0;
+
+ mantis_load_config(mantis);
+ dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
+ mantis->hwconfig->model_name, mantis->hwconfig->dev_type,
+ mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn));
+ dprintk(verbose, MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ",
+ mantis->revision,
+ mantis->subsystem_vendor, mantis->subsystem_device);
+ dprintk(verbose, MANTIS_ERROR, 0,
+ "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n",
+ mantis->pdev->irq, mantis->latency,
+ mantis->mantis_addr, mantis->mantis_mmio);
+
+ err = mantis_i2c_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed");
+ return err;
+ }
+ err = get_mac_address(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed");
+ return err;
+ }
+ err = mantis_dma_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed");
+ return err;
+ }
+ err = mantis_dvb_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed");
+ return err;
+ }
+ err = mantis_uart_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed");
+ return err;
+ }
+
+ return 0;
+}
+
+int mantis_core_exit(struct mantis_pci *mantis)
+{
+ mantis_dma_stop(mantis);
+ dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping");
+
+ mantis_uart_exit(mantis);
+ dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed");
+
+ if (mantis_dma_exit(mantis) < 0)
+ dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed");
+ if (mantis_dvb_exit(mantis) < 0)
+ dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed");
+ if (mantis_i2c_exit(mantis) < 0)
+ dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed");
+
+ return 0;
+}
+
+/* Turn the given bit on or off. */
+void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
+{
+ u32 cur;
+
+ cur = mmread(MANTIS_GPIF_ADDR);
+ if (value)
+ mantis->gpio_status = cur | (1 << bitpos);
+ else
+ mantis->gpio_status = cur & (~(1 << bitpos));
+
+ mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
+ mmwrite(0x00, MANTIS_GPIF_DOUT);
+ udelay(100);
+}
+
+/* direction = 0 , no CI passthrough ; 1 , CI passthrough */
+void mantis_set_direction(struct mantis_pci *mantis, int direction)
+{
+ u32 reg;
+
+ reg = mmread(0x28);
+ dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup");
+ if (direction == 0x01) {
+ /* to CI */
+ reg |= 0x04;
+ mmwrite(reg, 0x28);
+ reg &= 0xff - 0x04;
+ mmwrite(reg, 0x28);
+ } else {
+ reg &= 0xff - 0x04;
+ mmwrite(reg, 0x28);
+ reg |= 0x04;
+ mmwrite(reg, 0x28);
+ }
+}
diff --git a/drivers/media/dvb/mantis/mantis_core.h b/drivers/media/dvb/mantis/mantis_core.h
new file mode 100644
index 000000000000..833ee42e694e
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_core.h
@@ -0,0 +1,57 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_CORE_H
+#define __MANTIS_CORE_H
+
+#include "mantis_common.h"
+
+
+#define FE_TYPE_SAT 0
+#define FE_TYPE_CAB 1
+#define FE_TYPE_TER 2
+
+#define FE_TYPE_TS204 0
+#define FE_TYPE_TS188 1
+
+
+struct vendorname {
+ u8 *sub_vendor_name;
+ u32 sub_vendor_id;
+};
+
+struct devicetype {
+ u8 *sub_device_name;
+ u32 sub_device_id;
+ u8 device_type;
+ u32 type_flags;
+};
+
+
+extern int mantis_dma_init(struct mantis_pci *mantis);
+extern int mantis_dma_exit(struct mantis_pci *mantis);
+extern void mantis_dma_start(struct mantis_pci *mantis);
+extern void mantis_dma_stop(struct mantis_pci *mantis);
+extern int mantis_i2c_init(struct mantis_pci *mantis);
+extern int mantis_i2c_exit(struct mantis_pci *mantis);
+extern int mantis_core_init(struct mantis_pci *mantis);
+extern int mantis_core_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_CORE_H */
diff --git a/drivers/media/dvb/mantis/mantis_dma.c b/drivers/media/dvb/mantis/mantis_dma.c
new file mode 100644
index 000000000000..46202a4012aa
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_dma.c
@@ -0,0 +1,256 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/kernel.h>
+#include <asm/page.h>
+#include <linux/vmalloc.h>
+#include <linux/pci.h>
+
+#include <asm/irq.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_dma.h"
+
+#define RISC_WRITE (0x01 << 28)
+#define RISC_JUMP (0x07 << 28)
+#define RISC_IRQ (0x01 << 24)
+
+#define RISC_STATUS(status) ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16))
+#define RISC_FLUSH() (mantis->risc_pos = 0)
+#define RISC_INSTR(opcode) (mantis->risc_cpu[mantis->risc_pos++] = cpu_to_le32(opcode))
+
+#define MANTIS_BUF_SIZE (64 * 1024)
+#define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE >> 4)
+#define MANTIS_BLOCK_COUNT (1 << 4)
+#define MANTIS_RISC_SIZE PAGE_SIZE
+
+int mantis_dma_exit(struct mantis_pci *mantis)
+{
+ if (mantis->buf_cpu) {
+ dprintk(MANTIS_ERROR, 1,
+ "DMA=0x%lx cpu=0x%p size=%d",
+ (unsigned long) mantis->buf_dma,
+ mantis->buf_cpu,
+ MANTIS_BUF_SIZE);
+
+ pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE,
+ mantis->buf_cpu, mantis->buf_dma);
+
+ mantis->buf_cpu = NULL;
+ }
+ if (mantis->risc_cpu) {
+ dprintk(MANTIS_ERROR, 1,
+ "RISC=0x%lx cpu=0x%p size=%lx",
+ (unsigned long) mantis->risc_dma,
+ mantis->risc_cpu,
+ MANTIS_RISC_SIZE);
+
+ pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE,
+ mantis->risc_cpu, mantis->risc_dma);
+
+ mantis->risc_cpu = NULL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_dma_exit);
+
+static inline int mantis_alloc_buffers(struct mantis_pci *mantis)
+{
+ if (!mantis->buf_cpu) {
+ mantis->buf_cpu = pci_alloc_consistent(mantis->pdev,
+ MANTIS_BUF_SIZE,
+ &mantis->buf_dma);
+ if (!mantis->buf_cpu) {
+ dprintk(MANTIS_ERROR, 1,
+ "DMA buffer allocation failed");
+
+ goto err;
+ }
+ dprintk(MANTIS_ERROR, 1,
+ "DMA=0x%lx cpu=0x%p size=%d",
+ (unsigned long) mantis->buf_dma,
+ mantis->buf_cpu, MANTIS_BUF_SIZE);
+ }
+ if (!mantis->risc_cpu) {
+ mantis->risc_cpu = pci_alloc_consistent(mantis->pdev,
+ MANTIS_RISC_SIZE,
+ &mantis->risc_dma);
+
+ if (!mantis->risc_cpu) {
+ dprintk(MANTIS_ERROR, 1,
+ "RISC program allocation failed");
+
+ mantis_dma_exit(mantis);
+
+ goto err;
+ }
+ dprintk(MANTIS_ERROR, 1,
+ "RISC=0x%lx cpu=0x%p size=%lx",
+ (unsigned long) mantis->risc_dma,
+ mantis->risc_cpu, MANTIS_RISC_SIZE);
+ }
+
+ return 0;
+err:
+ dprintk(MANTIS_ERROR, 1, "Out of memory (?) .....");
+ return -ENOMEM;
+}
+
+static inline int mantis_calc_lines(struct mantis_pci *mantis)
+{
+ mantis->line_bytes = MANTIS_BLOCK_BYTES;
+ mantis->line_count = MANTIS_BLOCK_COUNT;
+
+ while (mantis->line_bytes > 4095) {
+ mantis->line_bytes >>= 1;
+ mantis->line_count <<= 1;
+ }
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]",
+ MANTIS_BLOCK_BYTES, mantis->line_bytes, mantis->line_count);
+
+ if (mantis->line_count > 255) {
+ dprintk(MANTIS_ERROR, 1, "Buffer size error");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int mantis_dma_init(struct mantis_pci *mantis)
+{
+ int err = 0;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis DMA init");
+ if (mantis_alloc_buffers(mantis) < 0) {
+ dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer");
+
+ /* Stop RISC Engine */
+ mmwrite(0, MANTIS_DMA_CTL);
+
+ goto err;
+ }
+ err = mantis_calc_lines(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "Mantis calc lines failed");
+
+ goto err;
+ }
+
+ return 0;
+err:
+ return err;
+}
+EXPORT_SYMBOL_GPL(mantis_dma_init);
+
+static inline void mantis_risc_program(struct mantis_pci *mantis)
+{
+ u32 buf_pos = 0;
+ u32 line;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program");
+ RISC_FLUSH();
+
+ dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u",
+ mantis->line_count, mantis->line_bytes);
+
+ for (line = 0; line < mantis->line_count; line++) {
+ dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d]", line);
+ if (!(buf_pos % MANTIS_BLOCK_BYTES)) {
+ RISC_INSTR(RISC_WRITE |
+ RISC_IRQ |
+ RISC_STATUS(((buf_pos / MANTIS_BLOCK_BYTES) +
+ (MANTIS_BLOCK_COUNT - 1)) %
+ MANTIS_BLOCK_COUNT) |
+ mantis->line_bytes);
+ } else {
+ RISC_INSTR(RISC_WRITE | mantis->line_bytes);
+ }
+ RISC_INSTR(mantis->buf_dma + buf_pos);
+ buf_pos += mantis->line_bytes;
+ }
+ RISC_INSTR(RISC_JUMP);
+ RISC_INSTR(mantis->risc_dma);
+}
+
+void mantis_dma_start(struct mantis_pci *mantis)
+{
+ dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine");
+
+ mantis_risc_program(mantis);
+ mmwrite(mantis->risc_dma, MANTIS_RISC_START);
+ mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+ mmwrite(0, MANTIS_DMA_CTL);
+ mantis->last_block = mantis->finished_block = 0;
+
+ mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK);
+
+ mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN
+ | MANTIS_RISC_EN, MANTIS_DMA_CTL);
+
+}
+
+void mantis_dma_stop(struct mantis_pci *mantis)
+{
+ u32 stat = 0, mask = 0;
+
+ stat = mmread(MANTIS_INT_STAT);
+ mask = mmread(MANTIS_INT_MASK);
+ dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine");
+
+ mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR);
+
+ mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN |
+ MANTIS_DCAP_EN |
+ MANTIS_RISC_EN)), MANTIS_DMA_CTL);
+
+ mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT);
+
+ mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI |
+ MANTIS_INT_RISCEN), MANTIS_INT_MASK);
+}
+
+
+void mantis_dma_xfer(unsigned long data)
+{
+ struct mantis_pci *mantis = (struct mantis_pci *) data;
+ struct mantis_hwconfig *config = mantis->hwconfig;
+
+ while (mantis->last_block != mantis->finished_block) {
+ dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]",
+ mantis->last_block, mantis->finished_block);
+
+ (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
+ (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES);
+ mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT;
+ }
+}
diff --git a/drivers/media/dvb/mantis/mantis_dma.h b/drivers/media/dvb/mantis/mantis_dma.h
new file mode 100644
index 000000000000..6be00fa82094
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_dma.h
@@ -0,0 +1,30 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_DMA_H
+#define __MANTIS_DMA_H
+
+extern int mantis_dma_init(struct mantis_pci *mantis);
+extern int mantis_dma_exit(struct mantis_pci *mantis);
+extern void mantis_dma_start(struct mantis_pci *mantis);
+extern void mantis_dma_stop(struct mantis_pci *mantis);
+extern void mantis_dma_xfer(unsigned long data);
+
+#endif /* __MANTIS_DMA_H */
diff --git a/drivers/media/dvb/mantis/mantis_dvb.c b/drivers/media/dvb/mantis/mantis_dvb.c
new file mode 100644
index 000000000000..99d82eec3b03
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_dvb.c
@@ -0,0 +1,296 @@
+/*
+ Mantis PCI bridge driver
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/kernel.h>
+#include <linux/bitops.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_dma.h"
+#include "mantis_ca.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+
+ switch (power) {
+ case POWER_ON:
+ dprintk(MANTIS_DEBUG, 1, "Power ON");
+ gpio_set_bits(mantis, config->power, POWER_ON);
+ msleep(100);
+ gpio_set_bits(mantis, config->power, POWER_ON);
+ msleep(100);
+ break;
+
+ case POWER_OFF:
+ dprintk(MANTIS_DEBUG, 1, "Power OFF");
+ gpio_set_bits(mantis, config->power, POWER_OFF);
+ msleep(100);
+ break;
+
+ default:
+ dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power);
+ return -1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_frontend_power);
+
+void mantis_frontend_soft_reset(struct mantis_pci *mantis)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+
+ dprintk(MANTIS_DEBUG, 1, "Frontend RESET");
+ gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 1);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 1);
+ msleep(100);
+
+ return;
+}
+EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset);
+
+static int mantis_frontend_shutdown(struct mantis_pci *mantis)
+{
+ int err;
+
+ mantis_frontend_soft_reset(mantis);
+ err = mantis_frontend_power(mantis, POWER_OFF);
+ if (err != 0) {
+ dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct mantis_pci *mantis = dvbdmx->priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed");
+ if (!dvbdmx->dmx.frontend) {
+ dprintk(MANTIS_DEBUG, 1, "no frontend ?");
+ return -EINVAL;
+ }
+
+ mantis->feeds++;
+ dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds);
+
+ if (mantis->feeds == 1) {
+ dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
+ mantis_dma_start(mantis);
+ }
+
+ return mantis->feeds;
+}
+
+static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct mantis_pci *mantis = dvbdmx->priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed");
+ if (!dvbdmx->dmx.frontend) {
+ dprintk(MANTIS_DEBUG, 1, "no frontend ?");
+ return -EINVAL;
+ }
+
+ mantis->feeds--;
+ if (mantis->feeds == 0) {
+ dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
+ mantis_dma_stop(mantis);
+ }
+
+ return 0;
+}
+
+int __devinit mantis_dvb_init(struct mantis_pci *mantis)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ int result = -1;
+
+ dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter");
+
+ result = dvb_register_adapter(&mantis->dvb_adapter,
+ "Mantis DVB adapter",
+ THIS_MODULE,
+ &mantis->pdev->dev,
+ adapter_nr);
+
+ if (result < 0) {
+
+ dprintk(MANTIS_ERROR, 1, "Error registering adapter");
+ return -ENODEV;
+ }
+
+ mantis->dvb_adapter.priv = mantis;
+ mantis->demux.dmx.capabilities = DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+
+ mantis->demux.priv = mantis;
+ mantis->demux.filternum = 256;
+ mantis->demux.feednum = 256;
+ mantis->demux.start_feed = mantis_dvb_start_feed;
+ mantis->demux.stop_feed = mantis_dvb_stop_feed;
+ mantis->demux.write_to_decoder = NULL;
+
+ dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init");
+ result = dvb_dmx_init(&mantis->demux);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+
+ goto err0;
+ }
+
+ mantis->dmxdev.filternum = 256;
+ mantis->dmxdev.demux = &mantis->demux.dmx;
+ mantis->dmxdev.capabilities = 0;
+ dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init");
+
+ result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter);
+ if (result < 0) {
+
+ dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result);
+ goto err1;
+ }
+
+ mantis->fe_hw.source = DMX_FRONTEND_0;
+ result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+ if (result < 0) {
+
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err2;
+ }
+
+ mantis->fe_mem.source = DMX_MEMORY_FE;
+ result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err3;
+ }
+
+ result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err4;
+ }
+
+ dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
+ tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis);
+ if (mantis->hwconfig) {
+ result = config->frontend_init(mantis, mantis->fe);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!");
+ goto err5;
+ } else {
+ if (mantis->fe == NULL) {
+ dprintk(MANTIS_ERROR, 1, "FE <NULL>");
+ goto err5;
+ }
+
+ if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed");
+
+ if (mantis->fe->ops.release)
+ mantis->fe->ops.release(mantis->fe);
+
+ mantis->fe = NULL;
+ goto err5;
+ }
+ }
+ }
+
+ return 0;
+
+ /* Error conditions .. */
+err5:
+ tasklet_kill(&mantis->tasklet);
+ dvb_net_release(&mantis->dvbnet);
+ dvb_unregister_frontend(mantis->fe);
+ dvb_frontend_detach(mantis->fe);
+err4:
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+
+err3:
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+
+err2:
+ dvb_dmxdev_release(&mantis->dmxdev);
+
+err1:
+ dvb_dmx_release(&mantis->demux);
+
+err0:
+ dvb_unregister_adapter(&mantis->dvb_adapter);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(mantis_dvb_init);
+
+int __devexit mantis_dvb_exit(struct mantis_pci *mantis)
+{
+ int err;
+
+ if (mantis->fe) {
+ /* mantis_ca_exit(mantis); */
+ err = mantis_frontend_shutdown(mantis);
+ if (err != 0)
+ dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err);
+ dvb_unregister_frontend(mantis->fe);
+ dvb_frontend_detach(mantis->fe);
+ }
+
+ tasklet_kill(&mantis->tasklet);
+ dvb_net_release(&mantis->dvbnet);
+
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+
+ dvb_dmxdev_release(&mantis->dmxdev);
+ dvb_dmx_release(&mantis->demux);
+
+ dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter");
+ dvb_unregister_adapter(&mantis->dvb_adapter);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_dvb_exit);
diff --git a/drivers/media/dvb/mantis/mantis_dvb.h b/drivers/media/dvb/mantis/mantis_dvb.h
new file mode 100644
index 000000000000..464199db304e
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_dvb.h
@@ -0,0 +1,35 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_DVB_H
+#define __MANTIS_DVB_H
+
+enum mantis_power {
+ POWER_OFF = 0,
+ POWER_ON = 1
+};
+
+extern int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power);
+extern void mantis_frontend_soft_reset(struct mantis_pci *mantis);
+
+extern int mantis_dvb_init(struct mantis_pci *mantis);
+extern int mantis_dvb_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_DVB_H */
diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/dvb/mantis/mantis_evm.c
new file mode 100644
index 000000000000..a7b369a439d6
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_evm.c
@@ -0,0 +1,117 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/kernel.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h"
+#include "mantis_hif.h"
+#include "mantis_reg.h"
+
+static void mantis_hifevm_work(struct work_struct *work)
+{
+ struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work);
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ u32 gpif_stat, gpif_mask;
+
+ gpif_stat = mmread(MANTIS_GPIF_STATUS);
+ gpif_mask = mmread(MANTIS_GPIF_IRQCFG);
+
+ if (gpif_stat & MANTIS_GPIF_DETSTAT) {
+ if (gpif_stat & MANTIS_CARD_PLUGIN) {
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Plugin", mantis->num);
+ mmwrite(0xdada0000, MANTIS_CARD_RESET);
+ mantis_event_cam_plugin(ca);
+ dvb_ca_en50221_camchange_irq(&ca->en50221,
+ 0,
+ DVB_CA_EN50221_CAMCHANGE_INSERTED);
+ }
+ } else {
+ if (gpif_stat & MANTIS_CARD_PLUGOUT) {
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Unplug", mantis->num);
+ mmwrite(0xdada0000, MANTIS_CARD_RESET);
+ mantis_event_cam_unplug(ca);
+ dvb_ca_en50221_camchange_irq(&ca->en50221,
+ 0,
+ DVB_CA_EN50221_CAMCHANGE_REMOVED);
+ }
+ }
+
+ if (mantis->gpif_status & MANTIS_GPIF_EXTIRQ)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Ext IRQ", mantis->num);
+
+ if (mantis->gpif_status & MANTIS_SBUF_WSTO)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Timeout", mantis->num);
+
+ if (mantis->gpif_status & MANTIS_GPIF_OTHERR)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Alignment Error", mantis->num);
+
+ if (gpif_stat & MANTIS_SBUF_OVFLW)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Overflow", mantis->num);
+
+ if (gpif_stat & MANTIS_GPIF_BRRDY)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Read Ready", mantis->num);
+
+ if (gpif_stat & MANTIS_GPIF_INTSTAT)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): GPIF IRQ", mantis->num);
+
+ if (gpif_stat & MANTIS_SBUF_EMPTY)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Empty", mantis->num);
+
+ if (gpif_stat & MANTIS_SBUF_OPDONE) {
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer operation complete", mantis->num);
+ ca->sbuf_status = MANTIS_SBUF_DATA_AVAIL;
+ ca->hif_event = MANTIS_SBUF_OPDONE;
+ wake_up(&ca->hif_opdone_wq);
+ }
+}
+
+int mantis_evmgr_init(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Initializing Mantis Host I/F Event manager");
+ INIT_WORK(&ca->hif_evm_work, mantis_hifevm_work);
+ mantis_pcmcia_init(ca);
+ schedule_work(&ca->hif_evm_work);
+ mantis_hif_init(ca);
+ return 0;
+}
+
+void mantis_evmgr_exit(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting");
+ flush_scheduled_work();
+ mantis_hif_exit(ca);
+ mantis_pcmcia_exit(ca);
+}
diff --git a/drivers/media/dvb/mantis/mantis_hif.c b/drivers/media/dvb/mantis/mantis_hif.c
new file mode 100644
index 000000000000..5772ebb3a69e
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_hif.c
@@ -0,0 +1,238 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+
+#include "mantis_hif.h"
+#include "mantis_link.h" /* temporary due to physical layer stuff */
+
+#include "mantis_reg.h"
+
+
+static int mantis_hif_sbuf_opdone_wait(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ int rc = 0;
+
+ if (wait_event_timeout(ca->hif_opdone_wq,
+ ca->hif_event & MANTIS_SBUF_OPDONE,
+ msecs_to_jiffies(500)) == -ERESTARTSYS) {
+
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Smart buffer operation timeout !", mantis->num);
+ rc = -EREMOTEIO;
+ }
+ dprintk(MANTIS_DEBUG, 1, "Smart Buffer Operation complete");
+ ca->hif_event &= ~MANTIS_SBUF_OPDONE;
+ return rc;
+}
+
+static int mantis_hif_write_wait(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 opdone = 0, timeout = 0;
+ int rc = 0;
+
+ if (wait_event_timeout(ca->hif_write_wq,
+ mantis->gpif_status & MANTIS_GPIF_WRACK,
+ msecs_to_jiffies(500)) == -ERESTARTSYS) {
+
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write ACK timed out !", mantis->num);
+ rc = -EREMOTEIO;
+ }
+ dprintk(MANTIS_DEBUG, 1, "Write Acknowledged");
+ mantis->gpif_status &= ~MANTIS_GPIF_WRACK;
+ while (!opdone) {
+ opdone = (mmread(MANTIS_GPIF_STATUS) & MANTIS_SBUF_OPDONE);
+ udelay(500);
+ timeout++;
+ if (timeout > 100) {
+ dprintk(MANTIS_ERROR, 1, "Adater(%d) Slot(0): Write operation timed out!", mantis->num);
+ rc = -ETIMEDOUT;
+ break;
+ }
+ }
+ dprintk(MANTIS_DEBUG, 1, "HIF Write success");
+ return rc;
+}
+
+
+int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 hif_addr = 0, data, count = 4;
+
+ dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Read", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+ hif_addr &= ~MANTIS_GPIF_PCMCIAIOM;
+ hif_addr |= MANTIS_HIF_STATUS;
+ hif_addr |= addr;
+
+ mmwrite(hif_addr, MANTIS_GPIF_BRADDR);
+ mmwrite(count, MANTIS_GPIF_BRBYTES);
+ udelay(20);
+ mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+ if (mantis_hif_sbuf_opdone_wait(ca) != 0) {
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): GPIF Smart Buffer operation failed", mantis->num);
+ mutex_unlock(&ca->ca_lock);
+ return -EREMOTEIO;
+ }
+ data = mmread(MANTIS_GPIF_DIN);
+ mutex_unlock(&ca->ca_lock);
+ dprintk(MANTIS_DEBUG, 1, "Mem Read: 0x%02x", data);
+ return (data >> 24) & 0xff;
+}
+
+int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data)
+{
+ struct mantis_slot *slot = ca->slot;
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 hif_addr = 0;
+
+ dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Write", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ hif_addr &= ~MANTIS_GPIF_HIFRDWRN;
+ hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+ hif_addr &= ~MANTIS_GPIF_PCMCIAIOM;
+ hif_addr |= MANTIS_HIF_STATUS;
+ hif_addr |= addr;
+
+ mmwrite(slot->slave_cfg, MANTIS_GPIF_CFGSLA); /* Slot0 alone for now */
+ mmwrite(hif_addr, MANTIS_GPIF_ADDR);
+ mmwrite(data, MANTIS_GPIF_DOUT);
+
+ if (mantis_hif_write_wait(ca) != 0) {
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+ mutex_unlock(&ca->ca_lock);
+ return -EREMOTEIO;
+ }
+ dprintk(MANTIS_DEBUG, 1, "Mem Write: (0x%02x to 0x%02x)", data, addr);
+ mutex_unlock(&ca->ca_lock);
+
+ return 0;
+}
+
+int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 data, hif_addr = 0;
+
+ dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Read", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+ hif_addr |= MANTIS_GPIF_PCMCIAIOM;
+ hif_addr |= MANTIS_HIF_STATUS;
+ hif_addr |= addr;
+
+ mmwrite(hif_addr, MANTIS_GPIF_BRADDR);
+ mmwrite(1, MANTIS_GPIF_BRBYTES);
+ udelay(20);
+ mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+ if (mantis_hif_sbuf_opdone_wait(ca) != 0) {
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+ mutex_unlock(&ca->ca_lock);
+ return -EREMOTEIO;
+ }
+ data = mmread(MANTIS_GPIF_DIN);
+ dprintk(MANTIS_DEBUG, 1, "I/O Read: 0x%02x", data);
+ udelay(50);
+ mutex_unlock(&ca->ca_lock);
+
+ return (u8) data;
+}
+
+int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 hif_addr = 0;
+
+ dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Write", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+ hif_addr &= ~MANTIS_GPIF_HIFRDWRN;
+ hif_addr |= MANTIS_GPIF_PCMCIAIOM;
+ hif_addr |= MANTIS_HIF_STATUS;
+ hif_addr |= addr;
+
+ mmwrite(hif_addr, MANTIS_GPIF_ADDR);
+ mmwrite(data, MANTIS_GPIF_DOUT);
+
+ if (mantis_hif_write_wait(ca) != 0) {
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+ mutex_unlock(&ca->ca_lock);
+ return -EREMOTEIO;
+ }
+ dprintk(MANTIS_DEBUG, 1, "I/O Write: (0x%02x to 0x%02x)", data, addr);
+ mutex_unlock(&ca->ca_lock);
+ udelay(50);
+
+ return 0;
+}
+
+int mantis_hif_init(struct mantis_ca *ca)
+{
+ struct mantis_slot *slot = ca->slot;
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 irqcfg;
+
+ slot[0].slave_cfg = 0x70773028;
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Initializing Mantis Host Interface", mantis->num);
+
+ mutex_lock(&ca->ca_lock);
+ irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+ irqcfg = MANTIS_MASK_BRRDY |
+ MANTIS_MASK_WRACK |
+ MANTIS_MASK_EXTIRQ |
+ MANTIS_MASK_WSTO |
+ MANTIS_MASK_OTHERR |
+ MANTIS_MASK_OVFLW;
+
+ mmwrite(irqcfg, MANTIS_GPIF_IRQCFG);
+ mutex_unlock(&ca->ca_lock);
+
+ return 0;
+}
+
+void mantis_hif_exit(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 irqcfg;
+
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Exiting Mantis Host Interface", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+ irqcfg &= ~MANTIS_MASK_BRRDY;
+ mmwrite(irqcfg, MANTIS_GPIF_IRQCFG);
+ mutex_unlock(&ca->ca_lock);
+}
diff --git a/drivers/media/dvb/mantis/mantis_hif.h b/drivers/media/dvb/mantis/mantis_hif.h
new file mode 100644
index 000000000000..9094f9ed2362
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_hif.h
@@ -0,0 +1,29 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_HIF_H
+#define __MANTIS_HIF_H
+
+#define MANTIS_HIF_MEMRD 1
+#define MANTIS_HIF_MEMWR 2
+#define MANTIS_HIF_IOMRD 3
+#define MANTIS_HIF_IOMWR 4
+
+#endif /* __MANTIS_HIF_H */
diff --git a/drivers/media/dvb/mantis/mantis_i2c.c b/drivers/media/dvb/mantis/mantis_i2c.c
new file mode 100644
index 000000000000..7870bcf9689a
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_i2c.c
@@ -0,0 +1,267 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 <asm/io.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_i2c.h"
+
+#define TRIALS 10000
+
+static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg)
+{
+ u32 rxd, i, stat, trials;
+
+ dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <R>[ ",
+ __func__, msg->addr);
+
+ for (i = 0; i < msg->len; i++) {
+ rxd = (msg->addr << 25) | (1 << 24)
+ | MANTIS_I2C_RATE_3
+ | MANTIS_I2C_STOP
+ | MANTIS_I2C_PGMODE;
+
+ if (i == (msg->len - 1))
+ rxd &= ~MANTIS_I2C_STOP;
+
+ mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
+ mmwrite(rxd, MANTIS_I2CDATA_CTL);
+
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CDONE)
+ break;
+ }
+
+ dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
+
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CRACK)
+ break;
+ }
+
+ dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
+
+ rxd = mmread(MANTIS_I2CDATA_CTL);
+ msg->buf[i] = (u8)((rxd >> 8) & 0xFF);
+ dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
+ }
+ dprintk(MANTIS_INFO, 0, "]\n");
+
+ return 0;
+}
+
+static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg)
+{
+ int i;
+ u32 txd = 0, stat, trials;
+
+ dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <W>[ ",
+ __func__, msg->addr);
+
+ for (i = 0; i < msg->len; i++) {
+ dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
+ txd = (msg->addr << 25) | (msg->buf[i] << 8)
+ | MANTIS_I2C_RATE_3
+ | MANTIS_I2C_STOP
+ | MANTIS_I2C_PGMODE;
+
+ if (i == (msg->len - 1))
+ txd &= ~MANTIS_I2C_STOP;
+
+ mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
+ mmwrite(txd, MANTIS_I2CDATA_CTL);
+
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CDONE)
+ break;
+ }
+
+ dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
+
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CRACK)
+ break;
+ }
+
+ dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
+ }
+ dprintk(MANTIS_INFO, 0, "]\n");
+
+ return 0;
+}
+
+static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+ int ret = 0, i = 0, trials;
+ u32 stat, data, txd;
+ struct mantis_pci *mantis;
+ struct mantis_hwconfig *config;
+
+ mantis = i2c_get_adapdata(adapter);
+ BUG_ON(!mantis);
+ config = mantis->hwconfig;
+ BUG_ON(!config);
+
+ dprintk(MANTIS_DEBUG, 1, "Messages:%d", num);
+ mutex_lock(&mantis->i2c_lock);
+
+ while (i < num) {
+ /* Byte MODE */
+ if ((config->i2c_mode & MANTIS_BYTE_MODE) &&
+ ((i + 1) < num) &&
+ (msgs[i].len < 2) &&
+ (msgs[i + 1].len < 2) &&
+ (msgs[i + 1].flags & I2C_M_RD)) {
+
+ dprintk(MANTIS_DEBUG, 0, " Byte MODE:\n");
+
+ /* Read operation */
+ txd = msgs[i].addr << 25 | (0x1 << 24)
+ | (msgs[i].buf[0] << 16)
+ | MANTIS_I2C_RATE_3;
+
+ mmwrite(txd, MANTIS_I2CDATA_CTL);
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CDONE)
+ break;
+ }
+
+ /* check for xfer completion */
+ if (stat & MANTIS_INT_I2CDONE) {
+ /* check xfer was acknowledged */
+ if (stat & MANTIS_INT_I2CRACK) {
+ data = mmread(MANTIS_I2CDATA_CTL);
+ msgs[i + 1].buf[0] = (data >> 8) & 0xff;
+ dprintk(MANTIS_DEBUG, 0, " Byte <%d> RXD=0x%02x [%02x]\n", 0x0, data, msgs[i + 1].buf[0]);
+ } else {
+ /* I/O error */
+ dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__);
+ ret = -EIO;
+ break;
+ }
+ } else {
+ /* I/O error */
+ dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__);
+ ret = -EIO;
+ break;
+ }
+ i += 2; /* Write/Read operation in one go */
+ }
+
+ if (i < num) {
+ if (msgs[i].flags & I2C_M_RD)
+ ret = mantis_i2c_read(mantis, &msgs[i]);
+ else
+ ret = mantis_i2c_write(mantis, &msgs[i]);
+
+ i++;
+ if (ret < 0)
+ goto bail_out;
+ }
+
+ }
+
+ mutex_unlock(&mantis->i2c_lock);
+
+ return num;
+
+bail_out:
+ mutex_unlock(&mantis->i2c_lock);
+ return ret;
+}
+
+static u32 mantis_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm mantis_algo = {
+ .master_xfer = mantis_i2c_xfer,
+ .functionality = mantis_i2c_func,
+};
+
+int __devinit mantis_i2c_init(struct mantis_pci *mantis)
+{
+ u32 intstat, intmask;
+ struct i2c_adapter *i2c_adapter = &mantis->adapter;
+ struct pci_dev *pdev = mantis->pdev;
+
+ init_waitqueue_head(&mantis->i2c_wq);
+ mutex_init(&mantis->i2c_lock);
+ strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name));
+ i2c_set_adapdata(i2c_adapter, mantis);
+
+ i2c_adapter->owner = THIS_MODULE;
+ i2c_adapter->class = I2C_CLASS_TV_DIGITAL;
+ i2c_adapter->algo = &mantis_algo;
+ i2c_adapter->algo_data = NULL;
+ i2c_adapter->timeout = 500;
+ i2c_adapter->retries = 3;
+ i2c_adapter->dev.parent = &pdev->dev;
+
+ mantis->i2c_rc = i2c_add_adapter(i2c_adapter);
+ if (mantis->i2c_rc < 0)
+ return mantis->i2c_rc;
+
+ dprintk(MANTIS_DEBUG, 1, "Initializing I2C ..");
+
+ intstat = mmread(MANTIS_INT_STAT);
+ intmask = mmread(MANTIS_INT_MASK);
+ mmwrite(intstat, MANTIS_INT_STAT);
+ dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
+ intmask = mmread(MANTIS_INT_MASK);
+ mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_i2c_init);
+
+int mantis_i2c_exit(struct mantis_pci *mantis)
+{
+ u32 intmask;
+
+ dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
+ intmask = mmread(MANTIS_INT_MASK);
+ mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);
+
+ dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter");
+ return i2c_del_adapter(&mantis->adapter);
+}
+EXPORT_SYMBOL_GPL(mantis_i2c_exit);
diff --git a/drivers/media/dvb/mantis/mantis_i2c.h b/drivers/media/dvb/mantis/mantis_i2c.h
new file mode 100644
index 000000000000..1342df2faed8
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_i2c.h
@@ -0,0 +1,30 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_I2C_H
+#define __MANTIS_I2C_H
+
+#define I2C_STOP (1 << 0)
+#define I2C_READ (1 << 1)
+
+extern int mantis_i2c_init(struct mantis_pci *mantis);
+extern int mantis_i2c_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_I2C_H */
diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c
new file mode 100644
index 000000000000..4675a3b53c7d
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_input.c
@@ -0,0 +1,148 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/input.h>
+#include <media/ir-common.h>
+#include <linux/pci.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_uart.h"
+
+static struct ir_scancode mantis_ir_table[] = {
+ { 0x29, KEY_POWER },
+ { 0x28, KEY_FAVORITES },
+ { 0x30, KEY_TEXT },
+ { 0x17, KEY_INFO }, /* Preview */
+ { 0x23, KEY_EPG },
+ { 0x3b, KEY_F22 }, /* Record List */
+ { 0x3c, KEY_1 },
+ { 0x3e, KEY_2 },
+ { 0x39, KEY_3 },
+ { 0x36, KEY_4 },
+ { 0x22, KEY_5 },
+ { 0x20, KEY_6 },
+ { 0x32, KEY_7 },
+ { 0x26, KEY_8 },
+ { 0x24, KEY_9 },
+ { 0x2a, KEY_0 },
+
+ { 0x33, KEY_CANCEL },
+ { 0x2c, KEY_BACK },
+ { 0x15, KEY_CLEAR },
+ { 0x3f, KEY_TAB },
+ { 0x10, KEY_ENTER },
+ { 0x14, KEY_UP },
+ { 0x0d, KEY_RIGHT },
+ { 0x0e, KEY_DOWN },
+ { 0x11, KEY_LEFT },
+
+ { 0x21, KEY_VOLUMEUP },
+ { 0x35, KEY_VOLUMEDOWN },
+ { 0x3d, KEY_CHANNELDOWN },
+ { 0x3a, KEY_CHANNELUP },
+ { 0x2e, KEY_RECORD },
+ { 0x2b, KEY_PLAY },
+ { 0x13, KEY_PAUSE },
+ { 0x25, KEY_STOP },
+
+ { 0x1f, KEY_REWIND },
+ { 0x2d, KEY_FASTFORWARD },
+ { 0x1e, KEY_PREVIOUS }, /* Replay |< */
+ { 0x1d, KEY_NEXT }, /* Skip >| */
+
+ { 0x0b, KEY_CAMERA }, /* Capture */
+ { 0x0f, KEY_LANGUAGE }, /* SAP */
+ { 0x18, KEY_MODE }, /* PIP */
+ { 0x12, KEY_ZOOM }, /* Full screen */
+ { 0x1c, KEY_SUBTITLE },
+ { 0x2f, KEY_MUTE },
+ { 0x16, KEY_F20 }, /* L/R */
+ { 0x38, KEY_F21 }, /* Hibernate */
+
+ { 0x37, KEY_SWITCHVIDEOMODE }, /* A/V */
+ { 0x31, KEY_AGAIN }, /* Recall */
+ { 0x1a, KEY_KPPLUS }, /* Zoom+ */
+ { 0x19, KEY_KPMINUS }, /* Zoom- */
+ { 0x27, KEY_RED },
+ { 0x0C, KEY_GREEN },
+ { 0x01, KEY_YELLOW },
+ { 0x00, KEY_BLUE },
+};
+
+struct ir_scancode_table ir_mantis = {
+ .scan = mantis_ir_table,
+ .size = ARRAY_SIZE(mantis_ir_table),
+};
+EXPORT_SYMBOL_GPL(ir_mantis);
+
+int mantis_input_init(struct mantis_pci *mantis)
+{
+ struct input_dev *rc;
+ struct ir_input_state rc_state;
+ char name[80], dev[80];
+ int err;
+
+ rc = input_allocate_device();
+ if (!rc) {
+ dprintk(MANTIS_ERROR, 1, "Input device allocate failed");
+ return -ENOMEM;
+ }
+
+ sprintf(name, "Mantis %s IR receiver", mantis->hwconfig->model_name);
+ sprintf(dev, "pci-%s/ir0", pci_name(mantis->pdev));
+
+ rc->name = name;
+ rc->phys = dev;
+
+ ir_input_init(rc, &rc_state, IR_TYPE_OTHER);
+
+ rc->id.bustype = BUS_PCI;
+ rc->id.vendor = mantis->vendor_id;
+ rc->id.product = mantis->device_id;
+ rc->id.version = 1;
+ rc->dev = mantis->pdev->dev;
+
+ err = ir_input_register(rc, &ir_mantis, NULL);
+ if (err) {
+ dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err);
+ input_free_device(rc);
+ return -ENODEV;
+ }
+
+ mantis->rc = rc;
+
+ return 0;
+}
+
+int mantis_exit(struct mantis_pci *mantis)
+{
+ struct input_dev *rc = mantis->rc;
+
+ ir_input_unregister(rc);
+
+ return 0;
+}
diff --git a/drivers/media/dvb/mantis/mantis_ioc.c b/drivers/media/dvb/mantis/mantis_ioc.c
new file mode 100644
index 000000000000..de148ded52d8
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_ioc.c
@@ -0,0 +1,130 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/kernel.h>
+#include <linux/i2c.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_ioc.h"
+
+static int read_eeprom_bytes(struct mantis_pci *mantis, u8 reg, u8 *data, u8 length)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+ int err;
+ u8 buf = reg;
+
+ struct i2c_msg msg[] = {
+ { .addr = 0x50, .flags = 0, .buf = &buf, .len = 1 },
+ { .addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = length },
+ };
+
+ err = i2c_transfer(adapter, msg, 2);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
+ err, data[0], data[1]);
+
+ return err;
+ }
+
+ return 0;
+}
+int mantis_get_mac(struct mantis_pci *mantis)
+{
+ int err;
+ u8 mac_addr[6] = {0};
+
+ err = read_eeprom_bytes(mantis, 0x08, mac_addr, 6);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis EEPROM read error <%d>", err);
+
+ return err;
+ }
+
+ dprintk(MANTIS_ERROR, 0,
+ " MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+ mac_addr[0],
+ mac_addr[1],
+ mac_addr[2],
+ mac_addr[3],
+ mac_addr[4],
+ mac_addr[5]);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_get_mac);
+
+/* Turn the given bit on or off. */
+void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
+{
+ u32 cur;
+
+ dprintk(MANTIS_DEBUG, 1, "Set Bit <%d> to <%d>", bitpos, value);
+ cur = mmread(MANTIS_GPIF_ADDR);
+ if (value)
+ mantis->gpio_status = cur | (1 << bitpos);
+ else
+ mantis->gpio_status = cur & (~(1 << bitpos));
+
+ dprintk(MANTIS_DEBUG, 1, "GPIO Value <%02x>", mantis->gpio_status);
+ mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
+ mmwrite(0x00, MANTIS_GPIF_DOUT);
+}
+EXPORT_SYMBOL_GPL(gpio_set_bits);
+
+int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl)
+{
+ u32 reg;
+
+ reg = mmread(MANTIS_CONTROL);
+ switch (stream_ctl) {
+ case STREAM_TO_HIF:
+ dprintk(MANTIS_DEBUG, 1, "Set stream to HIF");
+ reg &= 0xff - MANTIS_BYPASS;
+ mmwrite(reg, MANTIS_CONTROL);
+ reg |= MANTIS_BYPASS;
+ mmwrite(reg, MANTIS_CONTROL);
+ break;
+
+ case STREAM_TO_CAM:
+ dprintk(MANTIS_DEBUG, 1, "Set stream to CAM");
+ reg |= MANTIS_BYPASS;
+ mmwrite(reg, MANTIS_CONTROL);
+ reg &= 0xff - MANTIS_BYPASS;
+ mmwrite(reg, MANTIS_CONTROL);
+ break;
+ default:
+ dprintk(MANTIS_ERROR, 1, "Unknown MODE <%02x>", stream_ctl);
+ return -1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_stream_control);
diff --git a/drivers/media/dvb/mantis/mantis_ioc.h b/drivers/media/dvb/mantis/mantis_ioc.h
new file mode 100644
index 000000000000..188fe5a81614
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_ioc.h
@@ -0,0 +1,51 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_IOC_H
+#define __MANTIS_IOC_H
+
+#define GPIF_A00 0x00
+#define GPIF_A01 0x01
+#define GPIF_A02 0x02
+#define GPIF_A03 0x03
+#define GPIF_A04 0x04
+#define GPIF_A05 0x05
+#define GPIF_A06 0x06
+#define GPIF_A07 0x07
+#define GPIF_A08 0x08
+#define GPIF_A09 0x09
+#define GPIF_A10 0x0a
+#define GPIF_A11 0x0b
+
+#define GPIF_A12 0x0c
+#define GPIF_A13 0x0d
+#define GPIF_A14 0x0e
+
+enum mantis_stream_control {
+ STREAM_TO_HIF = 0,
+ STREAM_TO_CAM
+};
+
+extern int mantis_get_mac(struct mantis_pci *mantis);
+extern void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value);
+
+extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl);
+
+#endif /* __MANTIS_IOC_H */
diff --git a/drivers/media/dvb/mantis/mantis_link.h b/drivers/media/dvb/mantis/mantis_link.h
new file mode 100644
index 000000000000..2a814774a001
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_link.h
@@ -0,0 +1,83 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_LINK_H
+#define __MANTIS_LINK_H
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include "dvb_ca_en50221.h"
+
+enum mantis_sbuf_status {
+ MANTIS_SBUF_DATA_AVAIL = 1,
+ MANTIS_SBUF_DATA_EMPTY = 2,
+ MANTIS_SBUF_DATA_OVFLW = 3
+};
+
+struct mantis_slot {
+ u32 timeout;
+ u32 slave_cfg;
+ u32 bar;
+};
+
+/* Physical layer */
+enum mantis_slot_state {
+ MODULE_INSERTED = 3,
+ MODULE_XTRACTED = 4
+};
+
+struct mantis_ca {
+ struct mantis_slot slot[4];
+
+ struct work_struct hif_evm_work;
+
+ u32 hif_event;
+ wait_queue_head_t hif_opdone_wq;
+ wait_queue_head_t hif_brrdyw_wq;
+ wait_queue_head_t hif_data_wq;
+ wait_queue_head_t hif_write_wq; /* HIF Write op */
+
+ enum mantis_sbuf_status sbuf_status;
+
+ enum mantis_slot_state slot_state;
+
+ void *ca_priv;
+
+ struct dvb_ca_en50221 en50221;
+ struct mutex ca_lock;
+};
+
+/* CA */
+extern void mantis_event_cam_plugin(struct mantis_ca *ca);
+extern void mantis_event_cam_unplug(struct mantis_ca *ca);
+extern int mantis_pcmcia_init(struct mantis_ca *ca);
+extern void mantis_pcmcia_exit(struct mantis_ca *ca);
+extern int mantis_evmgr_init(struct mantis_ca *ca);
+extern void mantis_evmgr_exit(struct mantis_ca *ca);
+
+/* HIF */
+extern int mantis_hif_init(struct mantis_ca *ca);
+extern void mantis_hif_exit(struct mantis_ca *ca);
+extern int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr);
+extern int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data);
+extern int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr);
+extern int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data);
+
+#endif /* __MANTIS_LINK_H */
diff --git a/drivers/media/dvb/mantis/mantis_pci.c b/drivers/media/dvb/mantis/mantis_pci.c
new file mode 100644
index 000000000000..59feeb84aec7
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_pci.c
@@ -0,0 +1,172 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/moduleparam.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include <asm/irq.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_pci.h"
+
+#define DRIVER_NAME "Mantis Core"
+
+int __devinit mantis_pci_init(struct mantis_pci *mantis)
+{
+ u8 revision, latency;
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ struct pci_dev *pdev = mantis->pdev;
+ int err, ret = 0;
+
+ dprintk(MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
+ config->model_name,
+ config->dev_type,
+ mantis->pdev->bus->number,
+ PCI_SLOT(mantis->pdev->devfn),
+ PCI_FUNC(mantis->pdev->devfn));
+
+ err = pci_enable_device(pdev);
+ if (err != 0) {
+ ret = -ENODEV;
+ dprintk(MANTIS_ERROR, 1, "ERROR: PCI enable failed <%i>", err);
+ goto fail0;
+ }
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err != 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Unable to obtain 32 bit DMA <%i>", err);
+ ret = -ENOMEM;
+ goto fail1;
+ }
+
+ pci_set_master(pdev);
+
+ if (!request_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0),
+ DRIVER_NAME)) {
+
+ dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 Request failed !");
+ ret = -ENODEV;
+ goto fail1;
+ }
+
+ mantis->mmio = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+
+ if (!mantis->mmio) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 remap failed !");
+ ret = -ENODEV;
+ goto fail2;
+ }
+
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+ mantis->latency = latency;
+ mantis->revision = revision;
+
+ dprintk(MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ",
+ mantis->revision,
+ mantis->pdev->subsystem_vendor,
+ mantis->pdev->subsystem_device);
+
+ dprintk(MANTIS_ERROR, 0,
+ "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n",
+ mantis->pdev->irq,
+ mantis->latency,
+ mantis->mantis_addr,
+ mantis->mmio);
+
+ err = request_irq(pdev->irq,
+ config->irq_handler,
+ IRQF_SHARED,
+ DRIVER_NAME,
+ mantis);
+
+ if (err != 0) {
+
+ dprintk(MANTIS_ERROR, 1, "ERROR: IRQ registration failed ! <%d>", err);
+ ret = -ENODEV;
+ goto fail3;
+ }
+
+ pci_set_drvdata(pdev, mantis);
+ return ret;
+
+ /* Error conditions */
+fail3:
+ dprintk(MANTIS_ERROR, 1, "ERROR: <%d> I/O unmap", ret);
+ if (mantis->mmio)
+ iounmap(mantis->mmio);
+
+fail2:
+ dprintk(MANTIS_ERROR, 1, "ERROR: <%d> releasing regions", ret);
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+
+fail1:
+ dprintk(MANTIS_ERROR, 1, "ERROR: <%d> disabling device", ret);
+ pci_disable_device(pdev);
+
+fail0:
+ dprintk(MANTIS_ERROR, 1, "ERROR: <%d> exiting", ret);
+ pci_set_drvdata(pdev, NULL);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mantis_pci_init);
+
+void mantis_pci_exit(struct mantis_pci *mantis)
+{
+ struct pci_dev *pdev = mantis->pdev;
+
+ dprintk(MANTIS_NOTICE, 1, " mem: 0x%p", mantis->mmio);
+ free_irq(pdev->irq, mantis);
+ if (mantis->mmio) {
+ iounmap(mantis->mmio);
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ }
+
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+EXPORT_SYMBOL_GPL(mantis_pci_exit);
+
+MODULE_DESCRIPTION("Mantis PCI DTV bridge driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/mantis_pci.h b/drivers/media/dvb/mantis/mantis_pci.h
new file mode 100644
index 000000000000..65f004519086
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_pci.h
@@ -0,0 +1,27 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_PCI_H
+#define __MANTIS_PCI_H
+
+extern int mantis_pci_init(struct mantis_pci *mantis);
+extern void mantis_pci_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_PCI_H */
diff --git a/drivers/media/dvb/mantis/mantis_pcmcia.c b/drivers/media/dvb/mantis/mantis_pcmcia.c
new file mode 100644
index 000000000000..5cb545b913f6
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_pcmcia.c
@@ -0,0 +1,120 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/kernel.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h" /* temporary due to physical layer stuff */
+#include "mantis_reg.h"
+
+/*
+ * If Slot state is already PLUG_IN event and we are called
+ * again, definitely it is jitter alone
+ */
+void mantis_event_cam_plugin(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ u32 gpif_irqcfg;
+
+ if (ca->slot_state == MODULE_XTRACTED) {
+ dprintk(MANTIS_DEBUG, 1, "Event: CAM Plugged IN: Adapter(%d) Slot(0)", mantis->num);
+ udelay(50);
+ mmwrite(0xda000000, MANTIS_CARD_RESET);
+ gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+ gpif_irqcfg |= MANTIS_MASK_PLUGOUT;
+ gpif_irqcfg &= ~MANTIS_MASK_PLUGIN;
+ mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG);
+ udelay(500);
+ ca->slot_state = MODULE_INSERTED;
+ }
+ udelay(100);
+}
+
+/*
+ * If Slot state is already UN_PLUG event and we are called
+ * again, definitely it is jitter alone
+ */
+void mantis_event_cam_unplug(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ u32 gpif_irqcfg;
+
+ if (ca->slot_state == MODULE_INSERTED) {
+ dprintk(MANTIS_DEBUG, 1, "Event: CAM Unplugged: Adapter(%d) Slot(0)", mantis->num);
+ udelay(50);
+ mmwrite(0x00da0000, MANTIS_CARD_RESET);
+ gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+ gpif_irqcfg |= MANTIS_MASK_PLUGIN;
+ gpif_irqcfg &= ~MANTIS_MASK_PLUGOUT;
+ mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG);
+ udelay(500);
+ ca->slot_state = MODULE_XTRACTED;
+ }
+ udelay(100);
+}
+
+int mantis_pcmcia_init(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ u32 gpif_stat, card_stat;
+
+ mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK);
+ gpif_stat = mmread(MANTIS_GPIF_STATUS);
+ card_stat = mmread(MANTIS_GPIF_IRQCFG);
+
+ if (gpif_stat & MANTIS_GPIF_DETSTAT) {
+ dprintk(MANTIS_DEBUG, 1, "CAM found on Adapter(%d) Slot(0)", mantis->num);
+ mmwrite(card_stat | MANTIS_MASK_PLUGOUT, MANTIS_GPIF_IRQCFG);
+ ca->slot_state = MODULE_INSERTED;
+ dvb_ca_en50221_camchange_irq(&ca->en50221,
+ 0,
+ DVB_CA_EN50221_CAMCHANGE_INSERTED);
+ } else {
+ dprintk(MANTIS_DEBUG, 1, "Empty Slot on Adapter(%d) Slot(0)", mantis->num);
+ mmwrite(card_stat | MANTIS_MASK_PLUGIN, MANTIS_GPIF_IRQCFG);
+ ca->slot_state = MODULE_XTRACTED;
+ dvb_ca_en50221_camchange_irq(&ca->en50221,
+ 0,
+ DVB_CA_EN50221_CAMCHANGE_REMOVED);
+ }
+
+ return 0;
+}
+
+void mantis_pcmcia_exit(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ mmwrite(mmread(MANTIS_GPIF_STATUS) & (~MANTIS_CARD_PLUGOUT | ~MANTIS_CARD_PLUGIN), MANTIS_GPIF_STATUS);
+ mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ0, MANTIS_INT_MASK);
+}
diff --git a/drivers/media/dvb/mantis/mantis_reg.h b/drivers/media/dvb/mantis/mantis_reg.h
new file mode 100644
index 000000000000..7761f9dc7fe0
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_reg.h
@@ -0,0 +1,197 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_REG_H
+#define __MANTIS_REG_H
+
+/* Interrupts */
+#define MANTIS_INT_STAT 0x00
+#define MANTIS_INT_MASK 0x04
+
+#define MANTIS_INT_RISCSTAT (0x0f << 28)
+#define MANTIS_INT_RISCEN (0x01 << 27)
+#define MANTIS_INT_I2CRACK (0x01 << 26)
+
+/* #define MANTIS_INT_GPIF (0xff << 12) */
+
+#define MANTIS_INT_PCMCIA7 (0x01 << 19)
+#define MANTIS_INT_PCMCIA6 (0x01 << 18)
+#define MANTIS_INT_PCMCIA5 (0x01 << 17)
+#define MANTIS_INT_PCMCIA4 (0x01 << 16)
+#define MANTIS_INT_PCMCIA3 (0x01 << 15)
+#define MANTIS_INT_PCMCIA2 (0x01 << 14)
+#define MANTIS_INT_PCMCIA1 (0x01 << 13)
+#define MANTIS_INT_PCMCIA0 (0x01 << 12)
+#define MANTIS_INT_IRQ1 (0x01 << 11)
+#define MANTIS_INT_IRQ0 (0x01 << 10)
+#define MANTIS_INT_OCERR (0x01 << 8)
+#define MANTIS_INT_PABORT (0x01 << 7)
+#define MANTIS_INT_RIPERR (0x01 << 6)
+#define MANTIS_INT_PPERR (0x01 << 5)
+#define MANTIS_INT_FTRGT (0x01 << 3)
+#define MANTIS_INT_RISCI (0x01 << 1)
+#define MANTIS_INT_I2CDONE (0x01 << 0)
+
+/* DMA */
+#define MANTIS_DMA_CTL 0x08
+#define MANTIS_GPIF_RD (0xff << 24)
+#define MANTIS_GPIF_WR (0xff << 16)
+#define MANTIS_CPU_DO (0x01 << 10)
+#define MANTIS_DRV_DO (0x01 << 9)
+#define MANTIS_I2C_RD (0x01 << 7)
+#define MANTIS_I2C_WR (0x01 << 6)
+#define MANTIS_DCAP_MODE (0x01 << 5)
+#define MANTIS_FIFO_TP_4 (0x00 << 3)
+#define MANTIS_FIFO_TP_8 (0x01 << 3)
+#define MANTIS_FIFO_TP_16 (0x02 << 3)
+#define MANTIS_FIFO_EN (0x01 << 2)
+#define MANTIS_DCAP_EN (0x01 << 1)
+#define MANTIS_RISC_EN (0x01 << 0)
+
+/* DEBUG */
+#define MANTIS_DEBUGREG 0x0c
+#define MANTIS_DATINV (0x0e << 7)
+#define MANTIS_TOP_DEBUGSEL (0x07 << 4)
+#define MANTIS_PCMCIA_DEBUGSEL (0x0f << 0)
+
+#define MANTIS_RISC_START 0x10
+#define MANTIS_RISC_PC 0x14
+
+/* I2C */
+#define MANTIS_I2CDATA_CTL 0x18
+#define MANTIS_I2C_RATE_1 (0x00 << 6)
+#define MANTIS_I2C_RATE_2 (0x01 << 6)
+#define MANTIS_I2C_RATE_3 (0x02 << 6)
+#define MANTIS_I2C_RATE_4 (0x03 << 6)
+#define MANTIS_I2C_STOP (0x01 << 5)
+#define MANTIS_I2C_PGMODE (0x01 << 3)
+
+/* DATA */
+#define MANTIS_CMD_DATA_R1 0x20
+#define MANTIS_CMD_DATA_3 (0xff << 24)
+#define MANTIS_CMD_DATA_2 (0xff << 16)
+#define MANTIS_CMD_DATA_1 (0xff << 8)
+#define MANTIS_CMD_DATA_0 (0xff << 0)
+
+#define MANTIS_CMD_DATA_R2 0x24
+#define MANTIS_CMD_DATA_7 (0xff << 24)
+#define MANTIS_CMD_DATA_6 (0xff << 16)
+#define MANTIS_CMD_DATA_5 (0xff << 8)
+#define MANTIS_CMD_DATA_4 (0xff << 0)
+
+#define MANTIS_CONTROL 0x28
+#define MANTIS_DET (0x01 << 7)
+#define MANTIS_DAT_CF_EN (0x01 << 6)
+#define MANTIS_ACS (0x03 << 4)
+#define MANTIS_VCCEN (0x01 << 3)
+#define MANTIS_BYPASS (0x01 << 2)
+#define MANTIS_MRST (0x01 << 1)
+#define MANTIS_CRST_INT (0x01 << 0)
+
+#define MANTIS_GPIF_CFGSLA 0x84
+#define MANTIS_GPIF_WAITSMPL (0x07 << 28)
+#define MANTIS_GPIF_BYTEADDRSUB (0x01 << 25)
+#define MANTIS_GPIF_WAITPOL (0x01 << 24)
+#define MANTIS_GPIF_NCDELAY (0x07 << 20)
+#define MANTIS_GPIF_RW2CSDELAY (0x07 << 16)
+#define MANTIS_GPIF_SLFTIMEDMODE (0x01 << 15)
+#define MANTIS_GPIF_SLFTIMEDDELY (0x7f << 8)
+#define MANTIS_GPIF_DEVTYPE (0x07 << 4)
+#define MANTIS_GPIF_BIGENDIAN (0x01 << 3)
+#define MANTIS_GPIF_FETCHCMD (0x03 << 1)
+#define MANTIS_GPIF_HWORDDEV (0x01 << 0)
+
+#define MANTIS_GPIF_WSTOPER 0x90
+#define MANTIS_GPIF_WSTOPERWREN3 (0x01 << 31)
+#define MANTIS_GPIF_PARBOOTN (0x01 << 29)
+#define MANTIS_GPIF_WSTOPERSLID3 (0x1f << 24)
+#define MANTIS_GPIF_WSTOPERWREN2 (0x01 << 23)
+#define MANTIS_GPIF_WSTOPERSLID2 (0x1f << 16)
+#define MANTIS_GPIF_WSTOPERWREN1 (0x01 << 15)
+#define MANTIS_GPIF_WSTOPERSLID1 (0x1f << 8)
+#define MANTIS_GPIF_WSTOPERWREN0 (0x01 << 7)
+#define MANTIS_GPIF_WSTOPERSLID0 (0x1f << 0)
+
+#define MANTIS_GPIF_CS2RW 0x94
+#define MANTIS_GPIF_CS2RWWREN3 (0x01 << 31)
+#define MANTIS_GPIF_CS2RWDELY3 (0x3f << 24)
+#define MANTIS_GPIF_CS2RWWREN2 (0x01 << 23)
+#define MANTIS_GPIF_CS2RWDELY2 (0x3f << 16)
+#define MANTIS_GPIF_CS2RWWREN1 (0x01 << 15)
+#define MANTIS_GPIF_CS2RWDELY1 (0x3f << 8)
+#define MANTIS_GPIF_CS2RWWREN0 (0x01 << 7)
+#define MANTIS_GPIF_CS2RWDELY0 (0x3f << 0)
+
+#define MANTIS_GPIF_IRQCFG 0x98
+#define MANTIS_GPIF_IRQPOL (0x01 << 8)
+#define MANTIS_MASK_WRACK (0x01 << 7)
+#define MANTIS_MASK_BRRDY (0x01 << 6)
+#define MANTIS_MASK_OVFLW (0x01 << 5)
+#define MANTIS_MASK_OTHERR (0x01 << 4)
+#define MANTIS_MASK_WSTO (0x01 << 3)
+#define MANTIS_MASK_EXTIRQ (0x01 << 2)
+#define MANTIS_MASK_PLUGIN (0x01 << 1)
+#define MANTIS_MASK_PLUGOUT (0x01 << 0)
+
+#define MANTIS_GPIF_STATUS 0x9c
+#define MANTIS_SBUF_KILLOP (0x01 << 15)
+#define MANTIS_SBUF_OPDONE (0x01 << 14)
+#define MANTIS_SBUF_EMPTY (0x01 << 13)
+#define MANTIS_GPIF_DETSTAT (0x01 << 9)
+#define MANTIS_GPIF_INTSTAT (0x01 << 8)
+#define MANTIS_GPIF_WRACK (0x01 << 7)
+#define MANTIS_GPIF_BRRDY (0x01 << 6)
+#define MANTIS_SBUF_OVFLW (0x01 << 5)
+#define MANTIS_GPIF_OTHERR (0x01 << 4)
+#define MANTIS_SBUF_WSTO (0x01 << 3)
+#define MANTIS_GPIF_EXTIRQ (0x01 << 2)
+#define MANTIS_CARD_PLUGIN (0x01 << 1)
+#define MANTIS_CARD_PLUGOUT (0x01 << 0)
+
+#define MANTIS_GPIF_BRADDR 0xa0
+#define MANTIS_GPIF_PCMCIAREG (0x01 << 27)
+#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26)
+#define MANTIS_GPIF_BR_ADDR (0xfffffff << 0)
+
+#define MANTIS_GPIF_BRBYTES 0xa4
+#define MANTIS_GPIF_BRCNT (0xfff << 0)
+
+#define MANTIS_PCMCIA_RESET 0xa8
+#define MANTIS_PCMCIA_RSTVAL (0xff << 0)
+
+#define MANTIS_CARD_RESET 0xac
+
+#define MANTIS_GPIF_ADDR 0xb0
+#define MANTIS_GPIF_HIFRDWRN (0x01 << 31)
+#define MANTIS_GPIF_PCMCIAREG (0x01 << 27)
+#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26)
+#define MANTIS_GPIF_HIFADDR (0xfffffff << 0)
+
+#define MANTIS_GPIF_DOUT 0xb4
+#define MANTIS_GPIF_HIFDOUT (0xfffffff << 0)
+
+#define MANTIS_GPIF_DIN 0xb8
+#define MANTIS_GPIF_HIFDIN (0xfffffff << 0)
+
+#define MANTIS_GPIF_SPARE 0xbc
+#define MANTIS_GPIF_LOGICRD (0xffff << 16)
+#define MANTIS_GPIF_LOGICRW (0xffff << 0)
+
+#endif /* __MANTIS_REG_H */
diff --git a/drivers/media/dvb/mantis/mantis_uart.c b/drivers/media/dvb/mantis/mantis_uart.c
new file mode 100644
index 000000000000..7d2f2398fa8b
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_uart.c
@@ -0,0 +1,186 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/kernel.h>
+#include <linux/spinlock.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_uart.h"
+
+struct mantis_uart_params {
+ enum mantis_baud baud_rate;
+ enum mantis_parity parity;
+};
+
+static struct {
+ char string[7];
+} rates[5] = {
+ { "9600" },
+ { "19200" },
+ { "38400" },
+ { "57600" },
+ { "115200" }
+};
+
+static struct {
+ char string[5];
+} parity[3] = {
+ { "NONE" },
+ { "ODD" },
+ { "EVEN" }
+};
+
+#define UART_MAX_BUF 16
+
+int mantis_uart_read(struct mantis_pci *mantis, u8 *data)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ u32 stat = 0, i;
+
+ /* get data */
+ for (i = 0; i < (config->bytes + 1); i++) {
+
+ stat = mmread(MANTIS_UART_STAT);
+
+ if (stat & MANTIS_UART_RXFIFO_FULL) {
+ dprintk(MANTIS_ERROR, 1, "RX Fifo FULL");
+ }
+ data[i] = mmread(MANTIS_UART_RXD) & 0x3f;
+
+ dprintk(MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f);
+
+ if (data[i] & (1 << 7)) {
+ dprintk(MANTIS_ERROR, 1, "UART framing error");
+ return -EINVAL;
+ }
+ if (data[i] & (1 << 6)) {
+ dprintk(MANTIS_ERROR, 1, "UART parity error");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void mantis_uart_work(struct work_struct *work)
+{
+ struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work);
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ u8 buf[16];
+ int i;
+
+ mantis_uart_read(mantis, buf);
+
+ for (i = 0; i < (config->bytes + 1); i++)
+ dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]);
+
+ dprintk(MANTIS_DEBUG, 0, "\n");
+}
+
+static int mantis_uart_setup(struct mantis_pci *mantis,
+ struct mantis_uart_params *params)
+{
+ u32 reg;
+
+ mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL);
+
+ reg = mmread(MANTIS_UART_BAUD);
+
+ switch (params->baud_rate) {
+ case MANTIS_BAUD_9600:
+ reg |= 0xd8;
+ break;
+ case MANTIS_BAUD_19200:
+ reg |= 0x6c;
+ break;
+ case MANTIS_BAUD_38400:
+ reg |= 0x36;
+ break;
+ case MANTIS_BAUD_57600:
+ reg |= 0x23;
+ break;
+ case MANTIS_BAUD_115200:
+ reg |= 0x11;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mmwrite(reg, MANTIS_UART_BAUD);
+
+ return 0;
+}
+
+int mantis_uart_init(struct mantis_pci *mantis)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ struct mantis_uart_params params;
+
+ /* default parity: */
+ params.baud_rate = config->baud_rate;
+ params.parity = config->parity;
+ dprintk(MANTIS_INFO, 1, "Initializing UART @ %sbps parity:%s",
+ rates[params.baud_rate].string,
+ parity[params.parity].string);
+
+ init_waitqueue_head(&mantis->uart_wq);
+ spin_lock_init(&mantis->uart_lock);
+
+ INIT_WORK(&mantis->uart_work, mantis_uart_work);
+
+ /* disable interrupt */
+ mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+
+ mantis_uart_setup(mantis, &params);
+
+ /* default 1 byte */
+ mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD);
+
+ /* flush buffer */
+ mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL);
+
+ /* enable interrupt */
+ mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK);
+ mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL);
+
+ schedule_work(&mantis->uart_work);
+ dprintk(MANTIS_DEBUG, 1, "UART succesfully initialized");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_uart_init);
+
+void mantis_uart_exit(struct mantis_pci *mantis)
+{
+ /* disable interrupt */
+ mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+}
+EXPORT_SYMBOL_GPL(mantis_uart_exit);
diff --git a/drivers/media/dvb/mantis/mantis_uart.h b/drivers/media/dvb/mantis/mantis_uart.h
new file mode 100644
index 000000000000..ffb62a0a5a13
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_uart.h
@@ -0,0 +1,58 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_UART_H
+#define __MANTIS_UART_H
+
+#define MANTIS_UART_CTL 0xe0
+#define MANTIS_UART_RXINT (1 << 4)
+#define MANTIS_UART_RXFLUSH (1 << 2)
+
+#define MANTIS_UART_RXD 0xe8
+#define MANTIS_UART_BAUD 0xec
+
+#define MANTIS_UART_STAT 0xf0
+#define MANTIS_UART_RXFIFO_DATA (1 << 7)
+#define MANTIS_UART_RXFIFO_EMPTY (1 << 6)
+#define MANTIS_UART_RXFIFO_FULL (1 << 3)
+#define MANTIS_UART_FRAME_ERR (1 << 2)
+#define MANTIS_UART_PARITY_ERR (1 << 1)
+#define MANTIS_UART_RXTHRESH_INT (1 << 0)
+
+enum mantis_baud {
+ MANTIS_BAUD_9600 = 0,
+ MANTIS_BAUD_19200,
+ MANTIS_BAUD_38400,
+ MANTIS_BAUD_57600,
+ MANTIS_BAUD_115200
+};
+
+enum mantis_parity {
+ MANTIS_PARITY_NONE = 0,
+ MANTIS_PARITY_EVEN,
+ MANTIS_PARITY_ODD,
+};
+
+struct mantis_pci;
+
+extern int mantis_uart_init(struct mantis_pci *mantis);
+extern void mantis_uart_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_UART_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/dvb/mantis/mantis_vp1033.c
new file mode 100644
index 000000000000..4a723bda0031
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1033.c
@@ -0,0 +1,212 @@
+/*
+ Mantis VP-1033 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "stv0299.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1033.h"
+#include "mantis_reg.h"
+
+u8 lgtdqcs001f_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x2a,
+ 0x05, 0x85,
+ 0x06, 0x02,
+ 0x07, 0x00,
+ 0x08, 0x00,
+ 0x0c, 0x01,
+ 0x0d, 0x81,
+ 0x0e, 0x44,
+ 0x0f, 0x94,
+ 0x10, 0x3c,
+ 0x11, 0x84,
+ 0x12, 0xb9,
+ 0x13, 0xb5,
+ 0x14, 0x4f,
+ 0x15, 0xc9,
+ 0x16, 0x80,
+ 0x17, 0x36,
+ 0x18, 0xfb,
+ 0x19, 0xcf,
+ 0x1a, 0xbc,
+ 0x1c, 0x2b,
+ 0x1d, 0x27,
+ 0x1e, 0x00,
+ 0x1f, 0x0b,
+ 0x20, 0xa1,
+ 0x21, 0x60,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00,
+ 0x29, 0x28,
+ 0x2a, 0x14,
+ 0x2b, 0x0f,
+ 0x2c, 0x09,
+ 0x2d, 0x05,
+ 0x31, 0x1f,
+ 0x32, 0x19,
+ 0x33, 0xfc,
+ 0x34, 0x13,
+ 0xff, 0xff,
+};
+
+#define MANTIS_MODEL_NAME "VP-1033"
+#define MANTIS_DEV_TYPE "DVB-S/DSS"
+
+int lgtdqcs001f_tuner_set(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct mantis_pci *mantis = fe->dvb->priv;
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 buf[4];
+ u32 div;
+
+
+ struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)};
+
+ div = params->frequency / 250;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x83;
+ buf[3] = 0xc0;
+
+ if (params->frequency < 1531000)
+ buf[3] |= 0x04;
+ else
+ buf[3] &= ~0x04;
+ if (i2c_transfer(adapter, &msg, 1) < 0) {
+ dprintk(MANTIS_ERROR, 1, "Write: I2C Transfer failed");
+ return -EIO;
+ }
+ msleep_interruptible(100);
+
+ return 0;
+}
+
+int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe,
+ u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) {
+ aclk = 0xb7;
+ bclk = 0x47;
+ } else if (srate < 3000000) {
+ aclk = 0xb7;
+ bclk = 0x4b;
+ } else if (srate < 7000000) {
+ aclk = 0xb7;
+ bclk = 0x4f;
+ } else if (srate < 14000000) {
+ aclk = 0xb7;
+ bclk = 0x53;
+ } else if (srate < 30000000) {
+ aclk = 0xb6;
+ bclk = 0x53;
+ } else if (srate < 45000000) {
+ aclk = 0xb4;
+ bclk = 0x51;
+ }
+ stv0299_writereg(fe, 0x13, aclk);
+ stv0299_writereg(fe, 0x14, bclk);
+
+ stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg(fe, 0x21, ratio & 0xf0);
+
+ return 0;
+}
+
+struct stv0299_config lgtdqcs001f_config = {
+ .demod_address = 0x68,
+ .inittab = lgtdqcs001f_inittab,
+ .mclk = 88000000UL,
+ .invert = 0,
+ .skip_reinit = 0,
+ .volt13_op0_op1 = STV0299_VOLT13_OP0,
+ .min_delay_ms = 100,
+ .set_symbol_rate = lgtdqcs001f_set_symbol_rate,
+};
+
+static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+
+ dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)");
+ fe = stv0299_attach(&lgtdqcs001f_config, adapter);
+
+ if (fe) {
+ fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set;
+ dprintk(MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x",
+ lgtdqcs001f_config.demod_address);
+
+ dprintk(MANTIS_ERROR, 1, "Mantis DVB-S STV0299 frontend attach success");
+ } else {
+ return -1;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+ mantis->fe = fe;
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp1033_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_204,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp1033_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.h b/drivers/media/dvb/mantis/mantis_vp1033.h
new file mode 100644
index 000000000000..7daaa1bf127d
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1033.h
@@ -0,0 +1,30 @@
+/*
+ Mantis VP-1033 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_VP1033_H
+#define __MANTIS_VP1033_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_1033_DVB_S 0x0016
+
+extern struct mantis_hwconfig vp1033_config;
+
+#endif /* __MANTIS_VP1033_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.c b/drivers/media/dvb/mantis/mantis_vp1034.c
new file mode 100644
index 000000000000..8e6ae558ee57
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1034.c
@@ -0,0 +1,119 @@
+/*
+ Mantis VP-1034 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mb86a16.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1034.h"
+#include "mantis_reg.h"
+
+struct mb86a16_config vp1034_mb86a16_config = {
+ .demod_address = 0x08,
+ .set_voltage = vp1034_set_voltage,
+};
+
+#define MANTIS_MODEL_NAME "VP-1034"
+#define MANTIS_DEV_TYPE "DVB-S/DSS"
+
+int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct mantis_pci *mantis = fe->dvb->priv;
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ dprintk(MANTIS_ERROR, 1, "Polarization=[13V]");
+ gpio_set_bits(mantis, 13, 1);
+ gpio_set_bits(mantis, 14, 0);
+ break;
+ case SEC_VOLTAGE_18:
+ dprintk(MANTIS_ERROR, 1, "Polarization=[18V]");
+ gpio_set_bits(mantis, 13, 1);
+ gpio_set_bits(mantis, 14, 1);
+ break;
+ case SEC_VOLTAGE_OFF:
+ dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN");
+ break;
+ default:
+ dprintk(MANTIS_ERROR, 1, "Invalid = (%d)", (u32) voltage);
+ return -EINVAL;
+ }
+ mmwrite(0x00, MANTIS_GPIF_DOUT);
+
+ return 0;
+}
+
+static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+
+ dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)");
+ fe = mb86a16_attach(&vp1034_mb86a16_config, adapter);
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found MB86A16 DVB-S/DSS frontend @0x%02x",
+ vp1034_mb86a16_config.demod_address);
+
+ } else {
+ return -1;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+ mantis->fe = fe;
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp1034_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_204,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp1034_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.h b/drivers/media/dvb/mantis/mantis_vp1034.h
new file mode 100644
index 000000000000..323f38ef8e3d
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1034.h
@@ -0,0 +1,33 @@
+/*
+ Mantis VP-1034 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_VP1034_H
+#define __MANTIS_VP1034_H
+
+#include "dvb_frontend.h"
+#include "mantis_common.h"
+
+
+#define MANTIS_VP_1034_DVB_S 0x0014
+
+extern struct mantis_hwconfig vp1034_config;
+extern int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+
+#endif /* __MANTIS_VP1034_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.c b/drivers/media/dvb/mantis/mantis_vp1041.c
new file mode 100644
index 000000000000..515346dd31d0
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1041.c
@@ -0,0 +1,358 @@
+/*
+ Mantis VP-1041 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1041.h"
+#include "stb0899_reg.h"
+#include "stb0899_drv.h"
+#include "stb0899_cfg.h"
+#include "stb6100_cfg.h"
+#include "stb6100.h"
+#include "lnbp21.h"
+
+#define MANTIS_MODEL_NAME "VP-1041"
+#define MANTIS_DEV_TYPE "DSS/DVB-S/DVB-S2"
+
+static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = {
+
+ /* 0x0000000b, *//* SYSREG */
+ { STB0899_DEV_ID , 0x30 },
+ { STB0899_DISCNTRL1 , 0x32 },
+ { STB0899_DISCNTRL2 , 0x80 },
+ { STB0899_DISRX_ST0 , 0x04 },
+ { STB0899_DISRX_ST1 , 0x00 },
+ { STB0899_DISPARITY , 0x00 },
+ { STB0899_DISFIFO , 0x00 },
+ { STB0899_DISSTATUS , 0x20 },
+ { STB0899_DISF22 , 0x99 },
+ { STB0899_DISF22RX , 0xa8 },
+ /* SYSREG ? */
+ { STB0899_ACRPRESC , 0x11 },
+ { STB0899_ACRDIV1 , 0x0a },
+ { STB0899_ACRDIV2 , 0x05 },
+ { STB0899_DACR1 , 0x00 },
+ { STB0899_DACR2 , 0x00 },
+ { STB0899_OUTCFG , 0x00 },
+ { STB0899_MODECFG , 0x00 },
+ { STB0899_IRQSTATUS_3 , 0xfe },
+ { STB0899_IRQSTATUS_2 , 0x03 },
+ { STB0899_IRQSTATUS_1 , 0x7c },
+ { STB0899_IRQSTATUS_0 , 0xf4 },
+ { STB0899_IRQMSK_3 , 0xf3 },
+ { STB0899_IRQMSK_2 , 0xfc },
+ { STB0899_IRQMSK_1 , 0xff },
+ { STB0899_IRQMSK_0 , 0xff },
+ { STB0899_IRQCFG , 0x00 },
+ { STB0899_I2CCFG , 0x88 },
+ { STB0899_I2CRPT , 0x58 },
+ { STB0899_IOPVALUE5 , 0x00 },
+ { STB0899_IOPVALUE4 , 0x33 },
+ { STB0899_IOPVALUE3 , 0x6d },
+ { STB0899_IOPVALUE2 , 0x90 },
+ { STB0899_IOPVALUE1 , 0x60 },
+ { STB0899_IOPVALUE0 , 0x00 },
+ { STB0899_GPIO00CFG , 0x82 },
+ { STB0899_GPIO01CFG , 0x82 },
+ { STB0899_GPIO02CFG , 0x82 },
+ { STB0899_GPIO03CFG , 0x82 },
+ { STB0899_GPIO04CFG , 0x82 },
+ { STB0899_GPIO05CFG , 0x82 },
+ { STB0899_GPIO06CFG , 0x82 },
+ { STB0899_GPIO07CFG , 0x82 },
+ { STB0899_GPIO08CFG , 0x82 },
+ { STB0899_GPIO09CFG , 0x82 },
+ { STB0899_GPIO10CFG , 0x82 },
+ { STB0899_GPIO11CFG , 0x82 },
+ { STB0899_GPIO12CFG , 0x82 },
+ { STB0899_GPIO13CFG , 0x82 },
+ { STB0899_GPIO14CFG , 0x82 },
+ { STB0899_GPIO15CFG , 0x82 },
+ { STB0899_GPIO16CFG , 0x82 },
+ { STB0899_GPIO17CFG , 0x82 },
+ { STB0899_GPIO18CFG , 0x82 },
+ { STB0899_GPIO19CFG , 0x82 },
+ { STB0899_GPIO20CFG , 0x82 },
+ { STB0899_SDATCFG , 0xb8 },
+ { STB0899_SCLTCFG , 0xba },
+ { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */
+ { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */
+ { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */
+ { STB0899_DIRCLKCFG , 0x82 },
+ { STB0899_CLKOUT27CFG , 0x7e },
+ { STB0899_STDBYCFG , 0x82 },
+ { STB0899_CS0CFG , 0x82 },
+ { STB0899_CS1CFG , 0x82 },
+ { STB0899_DISEQCOCFG , 0x20 },
+ { STB0899_GPIO32CFG , 0x82 },
+ { STB0899_GPIO33CFG , 0x82 },
+ { STB0899_GPIO34CFG , 0x82 },
+ { STB0899_GPIO35CFG , 0x82 },
+ { STB0899_GPIO36CFG , 0x82 },
+ { STB0899_GPIO37CFG , 0x82 },
+ { STB0899_GPIO38CFG , 0x82 },
+ { STB0899_GPIO39CFG , 0x82 },
+ { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
+ { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
+ { STB0899_FILTCTRL , 0x00 },
+ { STB0899_SYSCTRL , 0x01 },
+ { STB0899_STOPCLK1 , 0x20 },
+ { STB0899_STOPCLK2 , 0x00 },
+ { STB0899_INTBUFSTATUS , 0x00 },
+ { STB0899_INTBUFCTRL , 0x0a },
+ { 0xffff , 0xff },
+};
+
+static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = {
+ { STB0899_DEMOD , 0x00 },
+ { STB0899_RCOMPC , 0xc9 },
+ { STB0899_AGC1CN , 0x01 },
+ { STB0899_AGC1REF , 0x10 },
+ { STB0899_RTC , 0x23 },
+ { STB0899_TMGCFG , 0x4e },
+ { STB0899_AGC2REF , 0x34 },
+ { STB0899_TLSR , 0x84 },
+ { STB0899_CFD , 0xf7 },
+ { STB0899_ACLC , 0x87 },
+ { STB0899_BCLC , 0x94 },
+ { STB0899_EQON , 0x41 },
+ { STB0899_LDT , 0xf1 },
+ { STB0899_LDT2 , 0xe3 },
+ { STB0899_EQUALREF , 0xb4 },
+ { STB0899_TMGRAMP , 0x10 },
+ { STB0899_TMGTHD , 0x30 },
+ { STB0899_IDCCOMP , 0xfd },
+ { STB0899_QDCCOMP , 0xff },
+ { STB0899_POWERI , 0x0c },
+ { STB0899_POWERQ , 0x0f },
+ { STB0899_RCOMP , 0x6c },
+ { STB0899_AGCIQIN , 0x80 },
+ { STB0899_AGC2I1 , 0x06 },
+ { STB0899_AGC2I2 , 0x00 },
+ { STB0899_TLIR , 0x30 },
+ { STB0899_RTF , 0x7f },
+ { STB0899_DSTATUS , 0x00 },
+ { STB0899_LDI , 0xbc },
+ { STB0899_CFRM , 0xea },
+ { STB0899_CFRL , 0x31 },
+ { STB0899_NIRM , 0x2b },
+ { STB0899_NIRL , 0x80 },
+ { STB0899_ISYMB , 0x1d },
+ { STB0899_QSYMB , 0xa6 },
+ { STB0899_SFRH , 0x2f },
+ { STB0899_SFRM , 0x68 },
+ { STB0899_SFRL , 0x40 },
+ { STB0899_SFRUPH , 0x2f },
+ { STB0899_SFRUPM , 0x68 },
+ { STB0899_SFRUPL , 0x40 },
+ { STB0899_EQUAI1 , 0x02 },
+ { STB0899_EQUAQ1 , 0xff },
+ { STB0899_EQUAI2 , 0x04 },
+ { STB0899_EQUAQ2 , 0x05 },
+ { STB0899_EQUAI3 , 0x02 },
+ { STB0899_EQUAQ3 , 0xfd },
+ { STB0899_EQUAI4 , 0x03 },
+ { STB0899_EQUAQ4 , 0x07 },
+ { STB0899_EQUAI5 , 0x08 },
+ { STB0899_EQUAQ5 , 0xf5 },
+ { STB0899_DSTATUS2 , 0x00 },
+ { STB0899_VSTATUS , 0x00 },
+ { STB0899_VERROR , 0x86 },
+ { STB0899_IQSWAP , 0x2a },
+ { STB0899_ECNT1M , 0x00 },
+ { STB0899_ECNT1L , 0x00 },
+ { STB0899_ECNT2M , 0x00 },
+ { STB0899_ECNT2L , 0x00 },
+ { STB0899_ECNT3M , 0x0a },
+ { STB0899_ECNT3L , 0xad },
+ { STB0899_FECAUTO1 , 0x06 },
+ { STB0899_FECM , 0x01 },
+ { STB0899_VTH12 , 0xb0 },
+ { STB0899_VTH23 , 0x7a },
+ { STB0899_VTH34 , 0x58 },
+ { STB0899_VTH56 , 0x38 },
+ { STB0899_VTH67 , 0x34 },
+ { STB0899_VTH78 , 0x24 },
+ { STB0899_PRVIT , 0xff },
+ { STB0899_VITSYNC , 0x19 },
+ { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+ { STB0899_TSULC , 0x42 },
+ { STB0899_RSLLC , 0x41 },
+ { STB0899_TSLPL , 0x12 },
+ { STB0899_TSCFGH , 0x0c },
+ { STB0899_TSCFGM , 0x00 },
+ { STB0899_TSCFGL , 0x00 },
+ { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */
+ { STB0899_RSSYNCDEL , 0x00 },
+ { STB0899_TSINHDELH , 0x02 },
+ { STB0899_TSINHDELM , 0x00 },
+ { STB0899_TSINHDELL , 0x00 },
+ { STB0899_TSLLSTKM , 0x1b },
+ { STB0899_TSLLSTKL , 0xb3 },
+ { STB0899_TSULSTKM , 0x00 },
+ { STB0899_TSULSTKL , 0x00 },
+ { STB0899_PCKLENUL , 0xbc },
+ { STB0899_PCKLENLL , 0xcc },
+ { STB0899_RSPCKLEN , 0xbd },
+ { STB0899_TSSTATUS , 0x90 },
+ { STB0899_ERRCTRL1 , 0xb6 },
+ { STB0899_ERRCTRL2 , 0x95 },
+ { STB0899_ERRCTRL3 , 0x8d },
+ { STB0899_DMONMSK1 , 0x27 },
+ { STB0899_DMONMSK0 , 0x03 },
+ { STB0899_DEMAPVIT , 0x5c },
+ { STB0899_PLPARM , 0x19 },
+ { STB0899_PDELCTRL , 0x48 },
+ { STB0899_PDELCTRL2 , 0x00 },
+ { STB0899_BBHCTRL1 , 0x00 },
+ { STB0899_BBHCTRL2 , 0x00 },
+ { STB0899_HYSTTHRESH , 0x77 },
+ { STB0899_MATCSTM , 0x00 },
+ { STB0899_MATCSTL , 0x00 },
+ { STB0899_UPLCSTM , 0x00 },
+ { STB0899_UPLCSTL , 0x00 },
+ { STB0899_DFLCSTM , 0x00 },
+ { STB0899_DFLCSTL , 0x00 },
+ { STB0899_SYNCCST , 0x00 },
+ { STB0899_SYNCDCSTM , 0x00 },
+ { STB0899_SYNCDCSTL , 0x00 },
+ { STB0899_ISI_ENTRY , 0x00 },
+ { STB0899_ISI_BIT_EN , 0x00 },
+ { STB0899_MATSTRM , 0xf0 },
+ { STB0899_MATSTRL , 0x02 },
+ { STB0899_UPLSTRM , 0x45 },
+ { STB0899_UPLSTRL , 0x60 },
+ { STB0899_DFLSTRM , 0xe3 },
+ { STB0899_DFLSTRL , 0x00 },
+ { STB0899_SYNCSTR , 0x47 },
+ { STB0899_SYNCDSTRM , 0x05 },
+ { STB0899_SYNCDSTRL , 0x18 },
+ { STB0899_CFGPDELSTATUS1 , 0x19 },
+ { STB0899_CFGPDELSTATUS2 , 0x2b },
+ { STB0899_BBFERRORM , 0x00 },
+ { STB0899_BBFERRORL , 0x01 },
+ { STB0899_UPKTERRORM , 0x00 },
+ { STB0899_UPKTERRORL , 0x00 },
+ { 0xffff , 0xff },
+};
+
+struct stb0899_config vp1041_stb0899_config = {
+ .init_dev = vp1041_stb0899_s1_init_1,
+ .init_s2_demod = stb0899_s2_init_2,
+ .init_s1_demod = vp1041_stb0899_s1_init_3,
+ .init_s2_fec = stb0899_s2_init_4,
+ .init_tst = stb0899_s1_init_5,
+
+ .demod_address = 0x68, /* 0xd0 >> 1 */
+
+ .xtal_freq = 27000000,
+ .inversion = IQ_SWAP_ON, /* 1 */
+
+ .lo_clk = 76500000,
+ .hi_clk = 99000000,
+
+ .esno_ave = STB0899_DVBS2_ESNO_AVE,
+ .esno_quant = STB0899_DVBS2_ESNO_QUANT,
+ .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,
+ .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,
+ .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,
+ .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+ .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+ .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,
+ .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+ .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,
+ .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+ .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,
+ .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,
+
+ .tuner_get_frequency = stb6100_get_frequency,
+ .tuner_set_frequency = stb6100_set_frequency,
+ .tuner_set_bandwidth = stb6100_set_bandwidth,
+ .tuner_get_bandwidth = stb6100_get_bandwidth,
+ .tuner_set_rfsiggain = NULL,
+};
+
+struct stb6100_config vp1041_stb6100_config = {
+ .tuner_address = 0x60,
+ .refclock = 27000000,
+};
+
+static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+ mantis->fe = stb0899_attach(&vp1041_stb0899_config, adapter);
+ if (mantis->fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found STB0899 DVB-S/DVB-S2 frontend @0x%02x",
+ vp1041_stb0899_config.demod_address);
+
+ if (stb6100_attach(mantis->fe, &vp1041_stb6100_config, adapter)) {
+ if (!lnbp21_attach(mantis->fe, adapter, 0, 0))
+ dprintk(MANTIS_ERROR, 1, "No LNBP21 found!");
+ }
+ } else {
+ return -EREMOTEIO;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+
+
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp1041_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_188,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp1041_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.h b/drivers/media/dvb/mantis/mantis_vp1041.h
new file mode 100644
index 000000000000..1ae5b3de8081
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1041.h
@@ -0,0 +1,33 @@
+/*
+ Mantis VP-1041 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_VP1041_H
+#define __MANTIS_VP1041_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_1041_DVB_S2 0x0031
+#define SKYSTAR_HD2_10 0x0001
+#define SKYSTAR_HD2_20 0x0003
+#define CINERGY_S2_PCI_HD 0x1179
+
+extern struct mantis_hwconfig vp1041_config;
+
+#endif /* __MANTIS_VP1041_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.c b/drivers/media/dvb/mantis/mantis_vp2033.c
new file mode 100644
index 000000000000..10ce81790a8c
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp2033.c
@@ -0,0 +1,187 @@
+/*
+ Mantis VP-2033 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "tda1002x.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp2033.h"
+
+#define MANTIS_MODEL_NAME "VP-2033"
+#define MANTIS_DEV_TYPE "DVB-C"
+
+struct tda1002x_config vp2033_tda1002x_cu1216_config = {
+ .demod_address = 0x18 >> 1,
+ .invert = 1,
+};
+
+struct tda10023_config vp2033_tda10023_cu1216_config = {
+ .demod_address = 0x18 >> 1,
+ .invert = 1,
+};
+
+static u8 read_pwm(struct mantis_pci *mantis)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = {
+ {.addr = 0x50, .flags = 0, .buf = &b, .len = 1},
+ {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1}
+ };
+
+ if ((i2c_transfer(adapter, msg, 2) != 2)
+ || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
+
+static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct mantis_pci *mantis = fe->dvb->priv;
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 buf[6];
+ struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)};
+ int i;
+
+#define CU1216_IF 36125000
+#define TUNER_MUL 62500
+
+ u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0xce;
+ buf[3] = (params->frequency < 150000000 ? 0x01 :
+ params->frequency < 445000000 ? 0x02 : 0x04);
+ buf[4] = 0xde;
+ buf[5] = 0x20;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) != 1)
+ return -EIO;
+
+ /* wait for the pll lock */
+ msg.flags = I2C_M_RD;
+ msg.len = 1;
+ for (i = 0; i < 20; i++) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40))
+ break;
+
+ msleep(10);
+ }
+
+ /* switch the charge pump to the lower current */
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = &buf[2];
+ buf[2] &= ~0x40;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+
+ dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
+ fe = tda10021_attach(&vp2033_tda1002x_cu1216_config,
+ adapter,
+ read_pwm(mantis));
+
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
+ vp2033_tda1002x_cu1216_config.demod_address);
+ } else {
+ fe = tda10023_attach(&vp2033_tda10023_cu1216_config,
+ adapter,
+ read_pwm(mantis));
+
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x",
+ vp2033_tda1002x_cu1216_config.demod_address);
+ }
+ }
+
+ if (fe) {
+ fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set;
+ dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success");
+ } else {
+ return -1;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+
+ mantis->fe = fe;
+ dprintk(MANTIS_DEBUG, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp2033_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_204,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp2033_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.h b/drivers/media/dvb/mantis/mantis_vp2033.h
new file mode 100644
index 000000000000..c55242b79d54
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp2033.h
@@ -0,0 +1,30 @@
+/*
+ Mantis VP-2033 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_VP2033_H
+#define __MANTIS_VP2033_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_2033_DVB_C 0x0008
+
+extern struct mantis_hwconfig vp2033_config;
+
+#endif /* __MANTIS_VP2033_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp2040.c b/drivers/media/dvb/mantis/mantis_vp2040.c
new file mode 100644
index 000000000000..a7ca233e800b
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp2040.c
@@ -0,0 +1,186 @@
+/*
+ Mantis VP-2040 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "tda1002x.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp2040.h"
+
+#define MANTIS_MODEL_NAME "VP-2040"
+#define MANTIS_DEV_TYPE "DVB-C"
+
+struct tda1002x_config vp2040_tda1002x_cu1216_config = {
+ .demod_address = 0x18 >> 1,
+ .invert = 1,
+};
+
+struct tda10023_config vp2040_tda10023_cu1216_config = {
+ .demod_address = 0x18 >> 1,
+ .invert = 1,
+};
+
+static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct mantis_pci *mantis = fe->dvb->priv;
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 buf[6];
+ struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)};
+ int i;
+
+#define CU1216_IF 36125000
+#define TUNER_MUL 62500
+
+ u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0xce;
+ buf[3] = (params->frequency < 150000000 ? 0x01 :
+ params->frequency < 445000000 ? 0x02 : 0x04);
+ buf[4] = 0xde;
+ buf[5] = 0x20;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) != 1)
+ return -EIO;
+
+ /* wait for the pll lock */
+ msg.flags = I2C_M_RD;
+ msg.len = 1;
+ for (i = 0; i < 20; i++) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40))
+ break;
+
+ msleep(10);
+ }
+
+ /* switch the charge pump to the lower current */
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = &buf[2];
+ buf[2] &= ~0x40;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static u8 read_pwm(struct mantis_pci *mantis)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = {
+ {.addr = 0x50, .flags = 0, .buf = &b, .len = 1},
+ {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1}
+ };
+
+ if ((i2c_transfer(adapter, msg, 2) != 2)
+ || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
+
+static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+
+ dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
+ fe = tda10021_attach(&vp2040_tda1002x_cu1216_config,
+ adapter,
+ read_pwm(mantis));
+
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
+ vp2040_tda1002x_cu1216_config.demod_address);
+ } else {
+ fe = tda10023_attach(&vp2040_tda10023_cu1216_config,
+ adapter,
+ read_pwm(mantis));
+
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x",
+ vp2040_tda1002x_cu1216_config.demod_address);
+ }
+ }
+
+ if (fe) {
+ fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set;
+ dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success");
+ } else {
+ return -1;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+ mantis->fe = fe;
+ dprintk(MANTIS_DEBUG, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp2040_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_204,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp2040_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp2040.h b/drivers/media/dvb/mantis/mantis_vp2040.h
new file mode 100644
index 000000000000..d125e219b685
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp2040.h
@@ -0,0 +1,32 @@
+/*
+ Mantis VP-2040 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_VP2040_H
+#define __MANTIS_VP2040_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_2040_DVB_C 0x0043
+#define CINERGY_C 0x1178
+#define CABLESTAR_HD2 0x0002
+
+extern struct mantis_hwconfig vp2040_config;
+
+#endif /* __MANTIS_VP2040_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp3028.c b/drivers/media/dvb/mantis/mantis_vp3028.c
new file mode 100644
index 000000000000..4155c838a18a
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp3028.c
@@ -0,0 +1,38 @@
+/*
+ Mantis VP-3028 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 "mantis_common.h"
+#include "mantis_vp3028.h"
+
+struct zl10353_config mantis_vp3028_config = {
+ .demod_address = 0x0f,
+};
+
+#define MANTIS_MODEL_NAME "VP-3028"
+#define MANTIS_DEV_TYPE "DVB-T"
+
+struct mantis_hwconfig vp3028_mantis_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_188,
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp3028.h b/drivers/media/dvb/mantis/mantis_vp3028.h
new file mode 100644
index 000000000000..b07be6adc522
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp3028.h
@@ -0,0 +1,33 @@
+/*
+ Mantis VP-3028 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_VP3028_H
+#define __MANTIS_VP3028_H
+
+#include "dvb_frontend.h"
+#include "mantis_common.h"
+#include "zl10353.h"
+
+#define MANTIS_VP_3028_DVB_T 0x0028
+
+extern struct zl10353_config mantis_vp3028_config;
+extern struct mantis_hwconfig vp3028_mantis_config;
+
+#endif /* __MANTIS_VP3028_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp3030.c b/drivers/media/dvb/mantis/mantis_vp3030.c
new file mode 100644
index 000000000000..1f4334214953
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp3030.c
@@ -0,0 +1,105 @@
+/*
+ Mantis VP-3030 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "zl10353.h"
+#include "tda665x.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp3030.h"
+
+struct zl10353_config mantis_vp3030_config = {
+ .demod_address = 0x0f,
+};
+
+struct tda665x_config env57h12d5_config = {
+ .name = "ENV57H12D5 (ET-50DT)",
+ .addr = 0x60,
+ .frequency_min = 47000000,
+ .frequency_max = 862000000,
+ .frequency_offst = 3616667,
+ .ref_multiplier = 6, /* 1/6 MHz */
+ .ref_divider = 100000, /* 1/6 MHz */
+};
+
+#define MANTIS_MODEL_NAME "VP-3030"
+#define MANTIS_DEV_TYPE "DVB-T"
+
+
+static int vp3030_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ int err = 0;
+
+ gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ err = mantis_frontend_power(mantis, POWER_ON);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 1);
+
+ if (err == 0) {
+ msleep(250);
+ dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
+ fe = zl10353_attach(&mantis_vp3030_config, adapter);
+
+ if (!fe)
+ return -1;
+
+ tda665x_attach(fe, &env57h12d5_config, adapter);
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+
+ }
+ mantis->fe = fe;
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp3030_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_188,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp3030_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+
+ .i2c_mode = MANTIS_BYTE_MODE
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp3030.h b/drivers/media/dvb/mantis/mantis_vp3030.h
new file mode 100644
index 000000000000..5f12c4266277
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp3030.h
@@ -0,0 +1,30 @@
+/*
+ Mantis VP-3030 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 __MANTIS_VP3030_H
+#define __MANTIS_VP3030_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_3030_DVB_T 0x0024
+
+extern struct mantis_hwconfig vp3030_config;
+
+#endif /* __MANTIS_VP3030_H */
diff --git a/drivers/media/dvb/ngene/Kconfig b/drivers/media/dvb/ngene/Kconfig
new file mode 100644
index 000000000000..3ec8e6fcbb1d
--- /dev/null
+++ b/drivers/media/dvb/ngene/Kconfig
@@ -0,0 +1,9 @@
+config DVB_NGENE
+ tristate "Micronas nGene support"
+ depends on DVB_CORE && PCI && I2C
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ select DVB_STV6110x if !DVB_FE_CUSTOMISE
+ select DVB_STV090x if !DVB_FE_CUSTOMISE
+ ---help---
+ Support for Micronas PCI express cards with nGene bridge.
+
diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile
new file mode 100644
index 000000000000..40435cad4819
--- /dev/null
+++ b/drivers/media/dvb/ngene/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the nGene device driver
+#
+
+ngene-objs := ngene-core.o
+
+obj-$(CONFIG_DVB_NGENE) += ngene.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/
+
diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c
new file mode 100644
index 000000000000..0150dfe7cfbb
--- /dev/null
+++ b/drivers/media/dvb/ngene/ngene-core.c
@@ -0,0 +1,2024 @@
+/*
+ * ngene.c: nGene PCIe bridge driver
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
+ * Modifications for new nGene firmware,
+ * support for EEPROM-copying,
+ * support for new dual DVB-S2 card prototype
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/smp_lock.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+#include <linux/byteorder/generic.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+
+#include "ngene.h"
+
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "lnbh24.h"
+
+static int one_adapter = 1;
+module_param(one_adapter, int, 0444);
+MODULE_PARM_DESC(one_adapter, "Use only one adapter.");
+
+
+static int debug;
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "Print debugging information.");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define COMMAND_TIMEOUT_WORKAROUND
+
+#define dprintk if (debug) printk
+
+#define DEVICE_NAME "ngene"
+
+#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr)))
+#define ngwritel(dat, adr) writel((dat), (char *)(dev->iomem + (adr)))
+#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr)))
+#define ngreadl(adr) readl(dev->iomem + (adr))
+#define ngreadb(adr) readb(dev->iomem + (adr))
+#define ngcpyto(adr, src, count) memcpy_toio((char *) \
+ (dev->iomem + (adr)), (src), (count))
+#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \
+ (dev->iomem + (adr)), (count))
+
+/****************************************************************************/
+/* nGene interrupt handler **************************************************/
+/****************************************************************************/
+
+static void event_tasklet(unsigned long data)
+{
+ struct ngene *dev = (struct ngene *)data;
+
+ while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) {
+ struct EVENT_BUFFER Event =
+ dev->EventQueue[dev->EventQueueReadIndex];
+ dev->EventQueueReadIndex =
+ (dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1);
+
+ if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify))
+ dev->TxEventNotify(dev, Event.TimeStamp);
+ if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify))
+ dev->RxEventNotify(dev, Event.TimeStamp,
+ Event.RXCharacter);
+ }
+}
+
+static void demux_tasklet(unsigned long data)
+{
+ struct ngene_channel *chan = (struct ngene_channel *)data;
+ struct SBufferHeader *Cur = chan->nextBuffer;
+
+ spin_lock_irq(&chan->state_lock);
+
+ while (Cur->ngeneBuffer.SR.Flags & 0x80) {
+ if (chan->mode & NGENE_IO_TSOUT) {
+ u32 Flags = chan->DataFormatFlags;
+ if (Cur->ngeneBuffer.SR.Flags & 0x20)
+ Flags |= BEF_OVERFLOW;
+ if (chan->pBufferExchange) {
+ if (!chan->pBufferExchange(chan,
+ Cur->Buffer1,
+ chan->Capture1Length,
+ Cur->ngeneBuffer.SR.
+ Clock, Flags)) {
+ /*
+ We didn't get data
+ Clear in service flag to make sure we
+ get called on next interrupt again.
+ leave fill/empty (0x80) flag alone
+ to avoid hardware running out of
+ buffers during startup, we hold only
+ in run state ( the source may be late
+ delivering data )
+ */
+
+ if (chan->HWState == HWSTATE_RUN) {
+ Cur->ngeneBuffer.SR.Flags &=
+ ~0x40;
+ break;
+ /* Stop proccessing stream */
+ }
+ } else {
+ /* We got a valid buffer,
+ so switch to run state */
+ chan->HWState = HWSTATE_RUN;
+ }
+ } else {
+ printk(KERN_ERR DEVICE_NAME ": OOPS\n");
+ if (chan->HWState == HWSTATE_RUN) {
+ Cur->ngeneBuffer.SR.Flags &= ~0x40;
+ break; /* Stop proccessing stream */
+ }
+ }
+ if (chan->AudioDTOUpdated) {
+ printk(KERN_INFO DEVICE_NAME
+ ": Update AudioDTO = %d\n",
+ chan->AudioDTOValue);
+ Cur->ngeneBuffer.SR.DTOUpdate =
+ chan->AudioDTOValue;
+ chan->AudioDTOUpdated = 0;
+ }
+ } else {
+ if (chan->HWState == HWSTATE_RUN) {
+ u32 Flags = 0;
+ if (Cur->ngeneBuffer.SR.Flags & 0x01)
+ Flags |= BEF_EVEN_FIELD;
+ if (Cur->ngeneBuffer.SR.Flags & 0x20)
+ Flags |= BEF_OVERFLOW;
+ if (chan->pBufferExchange)
+ chan->pBufferExchange(chan,
+ Cur->Buffer1,
+ chan->
+ Capture1Length,
+ Cur->ngeneBuffer.
+ SR.Clock, Flags);
+ if (chan->pBufferExchange2)
+ chan->pBufferExchange2(chan,
+ Cur->Buffer2,
+ chan->
+ Capture2Length,
+ Cur->ngeneBuffer.
+ SR.Clock, Flags);
+ } else if (chan->HWState != HWSTATE_STOP)
+ chan->HWState = HWSTATE_RUN;
+ }
+ Cur->ngeneBuffer.SR.Flags = 0x00;
+ Cur = Cur->Next;
+ }
+ chan->nextBuffer = Cur;
+
+ spin_unlock_irq(&chan->state_lock);
+}
+
+static irqreturn_t irq_handler(int irq, void *dev_id)
+{
+ struct ngene *dev = (struct ngene *)dev_id;
+ u32 icounts = 0;
+ irqreturn_t rc = IRQ_NONE;
+ u32 i = MAX_STREAM;
+ u8 *tmpCmdDoneByte;
+
+ if (dev->BootFirmware) {
+ icounts = ngreadl(NGENE_INT_COUNTS);
+ if (icounts != dev->icounts) {
+ ngwritel(0, FORCE_NMI);
+ dev->cmd_done = 1;
+ wake_up(&dev->cmd_wq);
+ dev->icounts = icounts;
+ rc = IRQ_HANDLED;
+ }
+ return rc;
+ }
+
+ ngwritel(0, FORCE_NMI);
+
+ spin_lock(&dev->cmd_lock);
+ tmpCmdDoneByte = dev->CmdDoneByte;
+ if (tmpCmdDoneByte &&
+ (*tmpCmdDoneByte ||
+ (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) {
+ dev->CmdDoneByte = NULL;
+ dev->cmd_done = 1;
+ wake_up(&dev->cmd_wq);
+ rc = IRQ_HANDLED;
+ }
+ spin_unlock(&dev->cmd_lock);
+
+ if (dev->EventBuffer->EventStatus & 0x80) {
+ u8 nextWriteIndex =
+ (dev->EventQueueWriteIndex + 1) &
+ (EVENT_QUEUE_SIZE - 1);
+ if (nextWriteIndex != dev->EventQueueReadIndex) {
+ dev->EventQueue[dev->EventQueueWriteIndex] =
+ *(dev->EventBuffer);
+ dev->EventQueueWriteIndex = nextWriteIndex;
+ } else {
+ printk(KERN_ERR DEVICE_NAME ": event overflow\n");
+ dev->EventQueueOverflowCount += 1;
+ dev->EventQueueOverflowFlag = 1;
+ }
+ dev->EventBuffer->EventStatus &= ~0x80;
+ tasklet_schedule(&dev->event_tasklet);
+ rc = IRQ_HANDLED;
+ }
+
+ while (i > 0) {
+ i--;
+ spin_lock(&dev->channel[i].state_lock);
+ /* if (dev->channel[i].State>=KSSTATE_RUN) { */
+ if (dev->channel[i].nextBuffer) {
+ if ((dev->channel[i].nextBuffer->
+ ngeneBuffer.SR.Flags & 0xC0) == 0x80) {
+ dev->channel[i].nextBuffer->
+ ngeneBuffer.SR.Flags |= 0x40;
+ tasklet_schedule(
+ &dev->channel[i].demux_tasklet);
+ rc = IRQ_HANDLED;
+ }
+ }
+ spin_unlock(&dev->channel[i].state_lock);
+ }
+
+ /* Request might have been processed by a previous call. */
+ return IRQ_HANDLED;
+}
+
+/****************************************************************************/
+/* nGene command interface **************************************************/
+/****************************************************************************/
+
+static void dump_command_io(struct ngene *dev)
+{
+ u8 buf[8], *b;
+
+ ngcpyfrom(buf, HOST_TO_NGENE, 8);
+ printk(KERN_ERR "host_to_ngene (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ HOST_TO_NGENE, buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7]);
+
+ ngcpyfrom(buf, NGENE_TO_HOST, 8);
+ printk(KERN_ERR "ngene_to_host (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ NGENE_TO_HOST, buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7]);
+
+ b = dev->hosttongene;
+ printk(KERN_ERR "dev->hosttongene (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
+
+ b = dev->ngenetohost;
+ printk(KERN_ERR "dev->ngenetohost (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
+}
+
+static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com)
+{
+ int ret;
+ u8 *tmpCmdDoneByte;
+
+ dev->cmd_done = 0;
+
+ if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) {
+ dev->BootFirmware = 1;
+ dev->icounts = ngreadl(NGENE_INT_COUNTS);
+ ngwritel(0, NGENE_COMMAND);
+ ngwritel(0, NGENE_COMMAND_HI);
+ ngwritel(0, NGENE_STATUS);
+ ngwritel(0, NGENE_STATUS_HI);
+ ngwritel(0, NGENE_EVENT);
+ ngwritel(0, NGENE_EVENT_HI);
+ } else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) {
+ u64 fwio = dev->PAFWInterfaceBuffer;
+
+ ngwritel(fwio & 0xffffffff, NGENE_COMMAND);
+ ngwritel(fwio >> 32, NGENE_COMMAND_HI);
+ ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS);
+ ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI);
+ ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT);
+ ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI);
+ }
+
+ memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2);
+
+ if (dev->BootFirmware)
+ ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2);
+
+ spin_lock_irq(&dev->cmd_lock);
+ tmpCmdDoneByte = dev->ngenetohost + com->out_len;
+ if (!com->out_len)
+ tmpCmdDoneByte++;
+ *tmpCmdDoneByte = 0;
+ dev->ngenetohost[0] = 0;
+ dev->ngenetohost[1] = 0;
+ dev->CmdDoneByte = tmpCmdDoneByte;
+ spin_unlock_irq(&dev->cmd_lock);
+
+ /* Notify 8051. */
+ ngwritel(1, FORCE_INT);
+
+ ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ);
+ if (!ret) {
+ /*ngwritel(0, FORCE_NMI);*/
+
+ printk(KERN_ERR DEVICE_NAME
+ ": Command timeout cmd=%02x prev=%02x\n",
+ com->cmd.hdr.Opcode, dev->prev_cmd);
+ dump_command_io(dev);
+ return -1;
+ }
+ if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH)
+ dev->BootFirmware = 0;
+
+ dev->prev_cmd = com->cmd.hdr.Opcode;
+
+ if (!com->out_len)
+ return 0;
+
+ memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len);
+
+ return 0;
+}
+
+static int ngene_command(struct ngene *dev, struct ngene_command *com)
+{
+ int result;
+
+ down(&dev->cmd_mutex);
+ result = ngene_command_mutex(dev, com);
+ up(&dev->cmd_mutex);
+ return result;
+}
+
+
+static int ngene_command_i2c_read(struct ngene *dev, u8 adr,
+ u8 *out, u8 outlen, u8 *in, u8 inlen, int flag)
+{
+ struct ngene_command com;
+
+ com.cmd.hdr.Opcode = CMD_I2C_READ;
+ com.cmd.hdr.Length = outlen + 3;
+ com.cmd.I2CRead.Device = adr << 1;
+ memcpy(com.cmd.I2CRead.Data, out, outlen);
+ com.cmd.I2CRead.Data[outlen] = inlen;
+ com.cmd.I2CRead.Data[outlen + 1] = 0;
+ com.in_len = outlen + 3;
+ com.out_len = inlen + 1;
+
+ if (ngene_command(dev, &com) < 0)
+ return -EIO;
+
+ if ((com.cmd.raw8[0] >> 1) != adr)
+ return -EIO;
+
+ if (flag)
+ memcpy(in, com.cmd.raw8, inlen + 1);
+ else
+ memcpy(in, com.cmd.raw8 + 1, inlen);
+ return 0;
+}
+
+static int ngene_command_i2c_write(struct ngene *dev, u8 adr,
+ u8 *out, u8 outlen)
+{
+ struct ngene_command com;
+
+
+ com.cmd.hdr.Opcode = CMD_I2C_WRITE;
+ com.cmd.hdr.Length = outlen + 1;
+ com.cmd.I2CRead.Device = adr << 1;
+ memcpy(com.cmd.I2CRead.Data, out, outlen);
+ com.in_len = outlen + 1;
+ com.out_len = 1;
+
+ if (ngene_command(dev, &com) < 0)
+ return -EIO;
+
+ if (com.cmd.raw8[0] == 1)
+ return -EIO;
+
+ return 0;
+}
+
+static int ngene_command_load_firmware(struct ngene *dev,
+ u8 *ngene_fw, u32 size)
+{
+#define FIRSTCHUNK (1024)
+ u32 cleft;
+ struct ngene_command com;
+
+ com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE;
+ com.cmd.hdr.Length = 0;
+ com.in_len = 0;
+ com.out_len = 0;
+
+ ngene_command(dev, &com);
+
+ cleft = (size + 3) & ~3;
+ if (cleft > FIRSTCHUNK) {
+ ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK,
+ cleft - FIRSTCHUNK);
+ cleft = FIRSTCHUNK;
+ }
+ ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft);
+
+ memset(&com, 0, sizeof(struct ngene_command));
+ com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH;
+ com.cmd.hdr.Length = 4;
+ com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA;
+ com.cmd.FWLoadFinish.Length = (unsigned short)cleft;
+ com.in_len = 4;
+ com.out_len = 0;
+
+ return ngene_command(dev, &com);
+}
+
+
+static int ngene_command_config_buf(struct ngene *dev, u8 config)
+{
+ struct ngene_command com;
+
+ com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER;
+ com.cmd.hdr.Length = 1;
+ com.cmd.ConfigureBuffers.config = config;
+ com.in_len = 1;
+ com.out_len = 0;
+
+ if (ngene_command(dev, &com) < 0)
+ return -EIO;
+ return 0;
+}
+
+static int ngene_command_config_free_buf(struct ngene *dev, u8 *config)
+{
+ struct ngene_command com;
+
+ com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER;
+ com.cmd.hdr.Length = 6;
+ memcpy(&com.cmd.ConfigureBuffers.config, config, 6);
+ com.in_len = 6;
+ com.out_len = 0;
+
+ if (ngene_command(dev, &com) < 0)
+ return -EIO;
+
+ return 0;
+}
+
+static int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level)
+{
+ struct ngene_command com;
+
+ com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN;
+ com.cmd.hdr.Length = 1;
+ com.cmd.SetGpioPin.select = select | (level << 7);
+ com.in_len = 1;
+ com.out_len = 0;
+
+ return ngene_command(dev, &com);
+}
+
+
+/*
+ 02000640 is sample on rising edge.
+ 02000740 is sample on falling edge.
+ 02000040 is ignore "valid" signal
+
+ 0: FD_CTL1 Bit 7,6 must be 0,1
+ 7 disable(fw controlled)
+ 6 0-AUX,1-TS
+ 5 0-par,1-ser
+ 4 0-lsb/1-msb
+ 3,2 reserved
+ 1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both
+ 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge
+ 2: FD_STA is read-only. 0-sync
+ 3: FD_INSYNC is number of 47s to trigger "in sync".
+ 4: FD_OUTSYNC is number of 47s to trigger "out of sync".
+ 5: FD_MAXBYTE1 is low-order of bytes per packet.
+ 6: FD_MAXBYTE2 is high-order of bytes per packet.
+ 7: Top byte is unused.
+*/
+
+/****************************************************************************/
+
+static u8 TSFeatureDecoderSetup[8 * 4] = {
+ 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,
+ 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */
+ 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */
+ 0x72, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */
+};
+
+/* Set NGENE I2S Config to 16 bit packed */
+static u8 I2SConfiguration[] = {
+ 0x00, 0x10, 0x00, 0x00,
+ 0x80, 0x10, 0x00, 0x00,
+};
+
+static u8 SPDIFConfiguration[10] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* Set NGENE I2S Config to transport stream compatible mode */
+
+static u8 TS_I2SConfiguration[4] = { 0x3E, 0x1A, 0x00, 0x00 }; /*3e 18 00 00 ?*/
+
+static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x20, 0x00, 0x00 };
+
+static u8 ITUDecoderSetup[4][16] = {
+ {0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20, /* SDTV */
+ 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00},
+ {0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
+ {0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00, /* HDTV 1080i50 */
+ 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
+ {0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, /* HDTV 1080i60 */
+ 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
+};
+
+/*
+ * 50 48 60 gleich
+ * 27p50 9f 00 22 80 42 69 18 ...
+ * 27p60 93 00 22 80 82 69 1c ...
+ */
+
+/* Maxbyte to 1144 (for raw data) */
+static u8 ITUFeatureDecoderSetup[8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00
+};
+
+static void FillTSBuffer(void *Buffer, int Length, u32 Flags)
+{
+ u32 *ptr = Buffer;
+
+ memset(Buffer, 0xff, Length);
+ while (Length > 0) {
+ if (Flags & DF_SWAP32)
+ *ptr = 0x471FFF10;
+ else
+ *ptr = 0x10FF1F47;
+ ptr += (188 / 4);
+ Length -= 188;
+ }
+}
+
+
+static void flush_buffers(struct ngene_channel *chan)
+{
+ u8 val;
+
+ do {
+ msleep(1);
+ spin_lock_irq(&chan->state_lock);
+ val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80;
+ spin_unlock_irq(&chan->state_lock);
+ } while (val);
+}
+
+static void clear_buffers(struct ngene_channel *chan)
+{
+ struct SBufferHeader *Cur = chan->nextBuffer;
+
+ do {
+ memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR));
+ if (chan->mode & NGENE_IO_TSOUT)
+ FillTSBuffer(Cur->Buffer1,
+ chan->Capture1Length,
+ chan->DataFormatFlags);
+ Cur = Cur->Next;
+ } while (Cur != chan->nextBuffer);
+
+ if (chan->mode & NGENE_IO_TSOUT) {
+ chan->nextBuffer->ngeneBuffer.SR.DTOUpdate =
+ chan->AudioDTOValue;
+ chan->AudioDTOUpdated = 0;
+
+ Cur = chan->TSIdleBuffer.Head;
+
+ do {
+ memset(&Cur->ngeneBuffer.SR, 0,
+ sizeof(Cur->ngeneBuffer.SR));
+ FillTSBuffer(Cur->Buffer1,
+ chan->Capture1Length,
+ chan->DataFormatFlags);
+ Cur = Cur->Next;
+ } while (Cur != chan->TSIdleBuffer.Head);
+ }
+}
+
+static int ngene_command_stream_control(struct ngene *dev, u8 stream,
+ u8 control, u8 mode, u8 flags)
+{
+ struct ngene_channel *chan = &dev->channel[stream];
+ struct ngene_command com;
+ u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300);
+ u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500);
+ u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700);
+ u16 BsSDO = 0x9B00;
+
+ /* down(&dev->stream_mutex); */
+ while (down_trylock(&dev->stream_mutex)) {
+ printk(KERN_INFO DEVICE_NAME ": SC locked\n");
+ msleep(1);
+ }
+ memset(&com, 0, sizeof(com));
+ com.cmd.hdr.Opcode = CMD_CONTROL;
+ com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2;
+ com.cmd.StreamControl.Stream = stream | (control ? 8 : 0);
+ if (chan->mode & NGENE_IO_TSOUT)
+ com.cmd.StreamControl.Stream |= 0x07;
+ com.cmd.StreamControl.Control = control |
+ (flags & SFLAG_ORDER_LUMA_CHROMA);
+ com.cmd.StreamControl.Mode = mode;
+ com.in_len = sizeof(struct FW_STREAM_CONTROL);
+ com.out_len = 0;
+
+ dprintk(KERN_INFO DEVICE_NAME
+ ": Stream=%02x, Control=%02x, Mode=%02x\n",
+ com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control,
+ com.cmd.StreamControl.Mode);
+
+ chan->Mode = mode;
+
+ if (!(control & 0x80)) {
+ spin_lock_irq(&chan->state_lock);
+ if (chan->State == KSSTATE_RUN) {
+ chan->State = KSSTATE_ACQUIRE;
+ chan->HWState = HWSTATE_STOP;
+ spin_unlock_irq(&chan->state_lock);
+ if (ngene_command(dev, &com) < 0) {
+ up(&dev->stream_mutex);
+ return -1;
+ }
+ /* clear_buffers(chan); */
+ flush_buffers(chan);
+ up(&dev->stream_mutex);
+ return 0;
+ }
+ spin_unlock_irq(&chan->state_lock);
+ up(&dev->stream_mutex);
+ return 0;
+ }
+
+ if (mode & SMODE_AUDIO_CAPTURE) {
+ com.cmd.StreamControl.CaptureBlockCount =
+ chan->Capture1Length / AUDIO_BLOCK_SIZE;
+ com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
+ } else if (mode & SMODE_TRANSPORT_STREAM) {
+ com.cmd.StreamControl.CaptureBlockCount =
+ chan->Capture1Length / TS_BLOCK_SIZE;
+ com.cmd.StreamControl.MaxLinesPerField =
+ chan->Capture1Length / TS_BLOCK_SIZE;
+ com.cmd.StreamControl.Buffer_Address =
+ chan->TSRingBuffer.PAHead;
+ if (chan->mode & NGENE_IO_TSOUT) {
+ com.cmd.StreamControl.BytesPerVBILine =
+ chan->Capture1Length / TS_BLOCK_SIZE;
+ com.cmd.StreamControl.Stream |= 0x07;
+ }
+ } else {
+ com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine;
+ com.cmd.StreamControl.MaxLinesPerField = chan->nLines;
+ com.cmd.StreamControl.MinLinesPerField = 100;
+ com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
+
+ if (mode & SMODE_VBI_CAPTURE) {
+ com.cmd.StreamControl.MaxVBILinesPerField =
+ chan->nVBILines;
+ com.cmd.StreamControl.MinVBILinesPerField = 0;
+ com.cmd.StreamControl.BytesPerVBILine =
+ chan->nBytesPerVBILine;
+ }
+ if (flags & SFLAG_COLORBAR)
+ com.cmd.StreamControl.Stream |= 0x04;
+ }
+
+ spin_lock_irq(&chan->state_lock);
+ if (mode & SMODE_AUDIO_CAPTURE) {
+ chan->nextBuffer = chan->RingBuffer.Head;
+ if (mode & SMODE_AUDIO_SPDIF) {
+ com.cmd.StreamControl.SetupDataLen =
+ sizeof(SPDIFConfiguration);
+ com.cmd.StreamControl.SetupDataAddr = BsSPI;
+ memcpy(com.cmd.StreamControl.SetupData,
+ SPDIFConfiguration, sizeof(SPDIFConfiguration));
+ } else {
+ com.cmd.StreamControl.SetupDataLen = 4;
+ com.cmd.StreamControl.SetupDataAddr = BsSDI;
+ memcpy(com.cmd.StreamControl.SetupData,
+ I2SConfiguration +
+ 4 * dev->card_info->i2s[stream], 4);
+ }
+ } else if (mode & SMODE_TRANSPORT_STREAM) {
+ chan->nextBuffer = chan->TSRingBuffer.Head;
+ if (stream >= STREAM_AUDIOIN1) {
+ if (chan->mode & NGENE_IO_TSOUT) {
+ com.cmd.StreamControl.SetupDataLen =
+ sizeof(TS_I2SOutConfiguration);
+ com.cmd.StreamControl.SetupDataAddr = BsSDO;
+ memcpy(com.cmd.StreamControl.SetupData,
+ TS_I2SOutConfiguration,
+ sizeof(TS_I2SOutConfiguration));
+ } else {
+ com.cmd.StreamControl.SetupDataLen =
+ sizeof(TS_I2SConfiguration);
+ com.cmd.StreamControl.SetupDataAddr = BsSDI;
+ memcpy(com.cmd.StreamControl.SetupData,
+ TS_I2SConfiguration,
+ sizeof(TS_I2SConfiguration));
+ }
+ } else {
+ com.cmd.StreamControl.SetupDataLen = 8;
+ com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10;
+ memcpy(com.cmd.StreamControl.SetupData,
+ TSFeatureDecoderSetup +
+ 8 * dev->card_info->tsf[stream], 8);
+ }
+ } else {
+ chan->nextBuffer = chan->RingBuffer.Head;
+ com.cmd.StreamControl.SetupDataLen =
+ 16 + sizeof(ITUFeatureDecoderSetup);
+ com.cmd.StreamControl.SetupDataAddr = BsUVI;
+ memcpy(com.cmd.StreamControl.SetupData,
+ ITUDecoderSetup[chan->itumode], 16);
+ memcpy(com.cmd.StreamControl.SetupData + 16,
+ ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup));
+ }
+ clear_buffers(chan);
+ chan->State = KSSTATE_RUN;
+ if (mode & SMODE_TRANSPORT_STREAM)
+ chan->HWState = HWSTATE_RUN;
+ else
+ chan->HWState = HWSTATE_STARTUP;
+ spin_unlock_irq(&chan->state_lock);
+
+ if (ngene_command(dev, &com) < 0) {
+ up(&dev->stream_mutex);
+ return -1;
+ }
+ up(&dev->stream_mutex);
+ return 0;
+}
+
+
+/****************************************************************************/
+/* I2C **********************************************************************/
+/****************************************************************************/
+
+static void ngene_i2c_set_bus(struct ngene *dev, int bus)
+{
+ if (!(dev->card_info->i2c_access & 2))
+ return;
+ if (dev->i2c_current_bus == bus)
+ return;
+
+ switch (bus) {
+ case 0:
+ ngene_command_gpio_set(dev, 3, 0);
+ ngene_command_gpio_set(dev, 2, 1);
+ break;
+
+ case 1:
+ ngene_command_gpio_set(dev, 2, 0);
+ ngene_command_gpio_set(dev, 3, 1);
+ break;
+ }
+ dev->i2c_current_bus = bus;
+}
+
+static int ngene_i2c_master_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg msg[], int num)
+{
+ struct ngene_channel *chan =
+ (struct ngene_channel *)i2c_get_adapdata(adapter);
+ struct ngene *dev = chan->dev;
+
+ down(&dev->i2c_switch_mutex);
+ ngene_i2c_set_bus(dev, chan->number);
+
+ if (num == 2 && msg[1].flags & I2C_M_RD && !(msg[0].flags & I2C_M_RD))
+ if (!ngene_command_i2c_read(dev, msg[0].addr,
+ msg[0].buf, msg[0].len,
+ msg[1].buf, msg[1].len, 0))
+ goto done;
+
+ if (num == 1 && !(msg[0].flags & I2C_M_RD))
+ if (!ngene_command_i2c_write(dev, msg[0].addr,
+ msg[0].buf, msg[0].len))
+ goto done;
+ if (num == 1 && (msg[0].flags & I2C_M_RD))
+ if (!ngene_command_i2c_read(dev, msg[0].addr, 0, 0,
+ msg[0].buf, msg[0].len, 0))
+ goto done;
+
+ up(&dev->i2c_switch_mutex);
+ return -EIO;
+
+done:
+ up(&dev->i2c_switch_mutex);
+ return num;
+}
+
+
+static u32 ngene_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm ngene_i2c_algo = {
+ .master_xfer = ngene_i2c_master_xfer,
+ .functionality = ngene_i2c_functionality,
+};
+
+static int ngene_i2c_init(struct ngene *dev, int dev_nr)
+{
+ struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter);
+
+ i2c_set_adapdata(adap, &(dev->channel[dev_nr]));
+ adap->class = I2C_CLASS_TV_DIGITAL | I2C_CLASS_TV_ANALOG;
+
+ strcpy(adap->name, "nGene");
+
+ adap->algo = &ngene_i2c_algo;
+ adap->algo_data = (void *)&(dev->channel[dev_nr]);
+ adap->dev.parent = &dev->pci_dev->dev;
+
+ return i2c_add_adapter(adap);
+}
+
+
+/****************************************************************************/
+/* DVB functions and API interface ******************************************/
+/****************************************************************************/
+
+static void swap_buffer(u32 *p, u32 len)
+{
+ while (len) {
+ *p = swab32(*p);
+ p++;
+ len -= 4;
+ }
+}
+
+
+static void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
+{
+ struct ngene_channel *chan = priv;
+
+
+#ifdef COMMAND_TIMEOUT_WORKAROUND
+ if (chan->users > 0)
+#endif
+ dvb_dmx_swfilter(&chan->demux, buf, len);
+ return 0;
+}
+
+u8 fill_ts[188] = { 0x47, 0x1f, 0xff, 0x10 };
+
+static void *tsout_exchange(void *priv, void *buf, u32 len,
+ u32 clock, u32 flags)
+{
+ struct ngene_channel *chan = priv;
+ struct ngene *dev = chan->dev;
+ u32 alen;
+
+ alen = dvb_ringbuffer_avail(&dev->tsout_rbuf);
+ alen -= alen % 188;
+
+ if (alen < len)
+ FillTSBuffer(buf + alen, len - alen, flags);
+ else
+ alen = len;
+ dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen);
+ if (flags & DF_SWAP32)
+ swap_buffer((u32 *)buf, alen);
+ wake_up_interruptible(&dev->tsout_rbuf.queue);
+ return buf;
+}
+
+
+static void set_transfer(struct ngene_channel *chan, int state)
+{
+ u8 control = 0, mode = 0, flags = 0;
+ struct ngene *dev = chan->dev;
+ int ret;
+
+ /*
+ printk(KERN_INFO DEVICE_NAME ": st %d\n", state);
+ msleep(100);
+ */
+
+ if (state) {
+ if (chan->running) {
+ printk(KERN_INFO DEVICE_NAME ": already running\n");
+ return;
+ }
+ } else {
+ if (!chan->running) {
+ printk(KERN_INFO DEVICE_NAME ": already stopped\n");
+ return;
+ }
+ }
+
+ if (dev->card_info->switch_ctrl)
+ dev->card_info->switch_ctrl(chan, 1, state ^ 1);
+
+ if (state) {
+ spin_lock_irq(&chan->state_lock);
+
+ /* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
+ ngreadl(0x9310)); */
+ dvb_ringbuffer_flush(&dev->tsout_rbuf);
+ control = 0x80;
+ if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+ chan->Capture1Length = 512 * 188;
+ mode = SMODE_TRANSPORT_STREAM;
+ }
+ if (chan->mode & NGENE_IO_TSOUT) {
+ chan->pBufferExchange = tsout_exchange;
+ /* 0x66666666 = 50MHz *2^33 /250MHz */
+ chan->AudioDTOValue = 0x66666666;
+ /* set_dto(chan, 38810700+1000); */
+ /* set_dto(chan, 19392658); */
+ }
+ if (chan->mode & NGENE_IO_TSIN)
+ chan->pBufferExchange = tsin_exchange;
+ /* ngwritel(0, 0x9310); */
+ spin_unlock_irq(&chan->state_lock);
+ } else
+ ;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
+ ngreadl(0x9310)); */
+
+ ret = ngene_command_stream_control(dev, chan->number,
+ control, mode, flags);
+ if (!ret)
+ chan->running = state;
+ else
+ printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n",
+ state);
+ if (!state) {
+ spin_lock_irq(&chan->state_lock);
+ chan->pBufferExchange = 0;
+ dvb_ringbuffer_flush(&dev->tsout_rbuf);
+ spin_unlock_irq(&chan->state_lock);
+ }
+}
+
+static int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct ngene_channel *chan = dvbdmx->priv;
+
+ if (chan->users == 0) {
+#ifdef COMMAND_TIMEOUT_WORKAROUND
+ if (!chan->running)
+#endif
+ set_transfer(chan, 1);
+ /* msleep(10); */
+ }
+
+ return ++chan->users;
+}
+
+static int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct ngene_channel *chan = dvbdmx->priv;
+
+ if (--chan->users)
+ return chan->users;
+
+#ifndef COMMAND_TIMEOUT_WORKAROUND
+ set_transfer(chan, 0);
+#endif
+
+ return 0;
+}
+
+
+
+static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
+ int (*start_feed)(struct dvb_demux_feed *),
+ int (*stop_feed)(struct dvb_demux_feed *),
+ void *priv)
+{
+ dvbdemux->priv = priv;
+
+ dvbdemux->filternum = 256;
+ dvbdemux->feednum = 256;
+ dvbdemux->start_feed = start_feed;
+ dvbdemux->stop_feed = stop_feed;
+ dvbdemux->write_to_decoder = 0;
+ dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING);
+ return dvb_dmx_init(dvbdemux);
+}
+
+static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
+ struct dvb_demux *dvbdemux,
+ struct dmx_frontend *hw_frontend,
+ struct dmx_frontend *mem_frontend,
+ struct dvb_adapter *dvb_adapter)
+{
+ int ret;
+
+ dmxdev->filternum = 256;
+ dmxdev->demux = &dvbdemux->dmx;
+ dmxdev->capabilities = 0;
+ ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
+ if (ret < 0)
+ return ret;
+
+ hw_frontend->source = DMX_FRONTEND_0;
+ dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
+ mem_frontend->source = DMX_MEMORY_FE;
+ dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
+ return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
+}
+
+
+/****************************************************************************/
+/* nGene hardware init and release functions ********************************/
+/****************************************************************************/
+
+static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb)
+{
+ struct SBufferHeader *Cur = rb->Head;
+ u32 j;
+
+ if (!Cur)
+ return;
+
+ for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) {
+ if (Cur->Buffer1)
+ pci_free_consistent(dev->pci_dev,
+ rb->Buffer1Length,
+ Cur->Buffer1,
+ Cur->scList1->Address);
+
+ if (Cur->Buffer2)
+ pci_free_consistent(dev->pci_dev,
+ rb->Buffer2Length,
+ Cur->Buffer2,
+ Cur->scList2->Address);
+ }
+
+ if (rb->SCListMem)
+ pci_free_consistent(dev->pci_dev, rb->SCListMemSize,
+ rb->SCListMem, rb->PASCListMem);
+
+ pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead);
+}
+
+static void free_idlebuffer(struct ngene *dev,
+ struct SRingBufferDescriptor *rb,
+ struct SRingBufferDescriptor *tb)
+{
+ int j;
+ struct SBufferHeader *Cur = tb->Head;
+
+ if (!rb->Head)
+ return;
+ free_ringbuffer(dev, rb);
+ for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) {
+ Cur->Buffer2 = 0;
+ Cur->scList2 = 0;
+ Cur->ngeneBuffer.Address_of_first_entry_2 = 0;
+ Cur->ngeneBuffer.Number_of_entries_2 = 0;
+ }
+}
+
+static void free_common_buffers(struct ngene *dev)
+{
+ u32 i;
+ struct ngene_channel *chan;
+
+ for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
+ chan = &dev->channel[i];
+ free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer);
+ free_ringbuffer(dev, &chan->RingBuffer);
+ free_ringbuffer(dev, &chan->TSRingBuffer);
+ }
+
+ if (dev->OverflowBuffer)
+ pci_free_consistent(dev->pci_dev,
+ OVERFLOW_BUFFER_SIZE,
+ dev->OverflowBuffer, dev->PAOverflowBuffer);
+
+ if (dev->FWInterfaceBuffer)
+ pci_free_consistent(dev->pci_dev,
+ 4096,
+ dev->FWInterfaceBuffer,
+ dev->PAFWInterfaceBuffer);
+}
+
+/****************************************************************************/
+/* Ring buffer handling *****************************************************/
+/****************************************************************************/
+
+static int create_ring_buffer(struct pci_dev *pci_dev,
+ struct SRingBufferDescriptor *descr, u32 NumBuffers)
+{
+ dma_addr_t tmp;
+ struct SBufferHeader *Head;
+ u32 i;
+ u32 MemSize = SIZEOF_SBufferHeader * NumBuffers;
+ u64 PARingBufferHead;
+ u64 PARingBufferCur;
+ u64 PARingBufferNext;
+ struct SBufferHeader *Cur, *Next;
+
+ descr->Head = 0;
+ descr->MemSize = 0;
+ descr->PAHead = 0;
+ descr->NumBuffers = 0;
+
+ if (MemSize < 4096)
+ MemSize = 4096;
+
+ Head = pci_alloc_consistent(pci_dev, MemSize, &tmp);
+ PARingBufferHead = tmp;
+
+ if (!Head)
+ return -ENOMEM;
+
+ memset(Head, 0, MemSize);
+
+ PARingBufferCur = PARingBufferHead;
+ Cur = Head;
+
+ for (i = 0; i < NumBuffers - 1; i++) {
+ Next = (struct SBufferHeader *)
+ (((u8 *) Cur) + SIZEOF_SBufferHeader);
+ PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader;
+ Cur->Next = Next;
+ Cur->ngeneBuffer.Next = PARingBufferNext;
+ Cur = Next;
+ PARingBufferCur = PARingBufferNext;
+ }
+ /* Last Buffer points back to first one */
+ Cur->Next = Head;
+ Cur->ngeneBuffer.Next = PARingBufferHead;
+
+ descr->Head = Head;
+ descr->MemSize = MemSize;
+ descr->PAHead = PARingBufferHead;
+ descr->NumBuffers = NumBuffers;
+
+ return 0;
+}
+
+static int AllocateRingBuffers(struct pci_dev *pci_dev,
+ dma_addr_t of,
+ struct SRingBufferDescriptor *pRingBuffer,
+ u32 Buffer1Length, u32 Buffer2Length)
+{
+ dma_addr_t tmp;
+ u32 i, j;
+ int status = 0;
+ u32 SCListMemSize = pRingBuffer->NumBuffers
+ * ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) :
+ NUM_SCATTER_GATHER_ENTRIES)
+ * sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+
+ u64 PASCListMem;
+ struct HW_SCATTER_GATHER_ELEMENT *SCListEntry;
+ u64 PASCListEntry;
+ struct SBufferHeader *Cur;
+ void *SCListMem;
+
+ if (SCListMemSize < 4096)
+ SCListMemSize = 4096;
+
+ SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp);
+
+ PASCListMem = tmp;
+ if (SCListMem == NULL)
+ return -ENOMEM;
+
+ memset(SCListMem, 0, SCListMemSize);
+
+ pRingBuffer->SCListMem = SCListMem;
+ pRingBuffer->PASCListMem = PASCListMem;
+ pRingBuffer->SCListMemSize = SCListMemSize;
+ pRingBuffer->Buffer1Length = Buffer1Length;
+ pRingBuffer->Buffer2Length = Buffer2Length;
+
+ SCListEntry = SCListMem;
+ PASCListEntry = PASCListMem;
+ Cur = pRingBuffer->Head;
+
+ for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) {
+ u64 PABuffer;
+
+ void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length,
+ &tmp);
+ PABuffer = tmp;
+
+ if (Buffer == NULL)
+ return -ENOMEM;
+
+ Cur->Buffer1 = Buffer;
+
+ SCListEntry->Address = PABuffer;
+ SCListEntry->Length = Buffer1Length;
+
+ Cur->scList1 = SCListEntry;
+ Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry;
+ Cur->ngeneBuffer.Number_of_entries_1 =
+ NUM_SCATTER_GATHER_ENTRIES;
+
+ SCListEntry += 1;
+ PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+
+#if NUM_SCATTER_GATHER_ENTRIES > 1
+ for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) {
+ SCListEntry->Address = of;
+ SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
+ SCListEntry += 1;
+ PASCListEntry +=
+ sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+ }
+#endif
+
+ if (!Buffer2Length)
+ continue;
+
+ Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp);
+ PABuffer = tmp;
+
+ if (Buffer == NULL)
+ return -ENOMEM;
+
+ Cur->Buffer2 = Buffer;
+
+ SCListEntry->Address = PABuffer;
+ SCListEntry->Length = Buffer2Length;
+
+ Cur->scList2 = SCListEntry;
+ Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry;
+ Cur->ngeneBuffer.Number_of_entries_2 =
+ NUM_SCATTER_GATHER_ENTRIES;
+
+ SCListEntry += 1;
+ PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+
+#if NUM_SCATTER_GATHER_ENTRIES > 1
+ for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) {
+ SCListEntry->Address = of;
+ SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
+ SCListEntry += 1;
+ PASCListEntry +=
+ sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+ }
+#endif
+
+ }
+
+ return status;
+}
+
+static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer,
+ struct SRingBufferDescriptor *pRingBuffer)
+{
+ int status = 0;
+
+ /* Copy pointer to scatter gather list in TSRingbuffer
+ structure for buffer 2
+ Load number of buffer
+ */
+ u32 n = pRingBuffer->NumBuffers;
+
+ /* Point to first buffer entry */
+ struct SBufferHeader *Cur = pRingBuffer->Head;
+ int i;
+ /* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */
+ for (i = 0; i < n; i++) {
+ Cur->Buffer2 = pIdleBuffer->Head->Buffer1;
+ Cur->scList2 = pIdleBuffer->Head->scList1;
+ Cur->ngeneBuffer.Address_of_first_entry_2 =
+ pIdleBuffer->Head->ngeneBuffer.
+ Address_of_first_entry_1;
+ Cur->ngeneBuffer.Number_of_entries_2 =
+ pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1;
+ Cur = Cur->Next;
+ }
+ return status;
+}
+
+static u32 RingBufferSizes[MAX_STREAM] = {
+ RING_SIZE_VIDEO,
+ RING_SIZE_VIDEO,
+ RING_SIZE_AUDIO,
+ RING_SIZE_AUDIO,
+ RING_SIZE_AUDIO,
+};
+
+static u32 Buffer1Sizes[MAX_STREAM] = {
+ MAX_VIDEO_BUFFER_SIZE,
+ MAX_VIDEO_BUFFER_SIZE,
+ MAX_AUDIO_BUFFER_SIZE,
+ MAX_AUDIO_BUFFER_SIZE,
+ MAX_AUDIO_BUFFER_SIZE
+};
+
+static u32 Buffer2Sizes[MAX_STREAM] = {
+ MAX_VBI_BUFFER_SIZE,
+ MAX_VBI_BUFFER_SIZE,
+ 0,
+ 0,
+ 0
+};
+
+
+static int AllocCommonBuffers(struct ngene *dev)
+{
+ int status = 0, i;
+
+ dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096,
+ &dev->PAFWInterfaceBuffer);
+ if (!dev->FWInterfaceBuffer)
+ return -ENOMEM;
+ dev->hosttongene = dev->FWInterfaceBuffer;
+ dev->ngenetohost = dev->FWInterfaceBuffer + 256;
+ dev->EventBuffer = dev->FWInterfaceBuffer + 512;
+
+ dev->OverflowBuffer = pci_alloc_consistent(dev->pci_dev,
+ OVERFLOW_BUFFER_SIZE,
+ &dev->PAOverflowBuffer);
+ if (!dev->OverflowBuffer)
+ return -ENOMEM;
+ memset(dev->OverflowBuffer, 0, OVERFLOW_BUFFER_SIZE);
+
+ for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
+ int type = dev->card_info->io_type[i];
+
+ dev->channel[i].State = KSSTATE_STOP;
+
+ if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) {
+ status = create_ring_buffer(dev->pci_dev,
+ &dev->channel[i].RingBuffer,
+ RingBufferSizes[i]);
+ if (status < 0)
+ break;
+
+ if (type & (NGENE_IO_TV | NGENE_IO_AIN)) {
+ status = AllocateRingBuffers(dev->pci_dev,
+ dev->
+ PAOverflowBuffer,
+ &dev->channel[i].
+ RingBuffer,
+ Buffer1Sizes[i],
+ Buffer2Sizes[i]);
+ if (status < 0)
+ break;
+ } else if (type & NGENE_IO_HDTV) {
+ status = AllocateRingBuffers(dev->pci_dev,
+ dev->
+ PAOverflowBuffer,
+ &dev->channel[i].
+ RingBuffer,
+ MAX_HDTV_BUFFER_SIZE,
+ 0);
+ if (status < 0)
+ break;
+ }
+ }
+
+ if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+
+ status = create_ring_buffer(dev->pci_dev,
+ &dev->channel[i].
+ TSRingBuffer, RING_SIZE_TS);
+ if (status < 0)
+ break;
+
+ status = AllocateRingBuffers(dev->pci_dev,
+ dev->PAOverflowBuffer,
+ &dev->channel[i].
+ TSRingBuffer,
+ MAX_TS_BUFFER_SIZE, 0);
+ if (status)
+ break;
+ }
+
+ if (type & NGENE_IO_TSOUT) {
+ status = create_ring_buffer(dev->pci_dev,
+ &dev->channel[i].
+ TSIdleBuffer, 1);
+ if (status < 0)
+ break;
+ status = AllocateRingBuffers(dev->pci_dev,
+ dev->PAOverflowBuffer,
+ &dev->channel[i].
+ TSIdleBuffer,
+ MAX_TS_BUFFER_SIZE, 0);
+ if (status)
+ break;
+ FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer,
+ &dev->channel[i].TSRingBuffer);
+ }
+ }
+ return status;
+}
+
+static void ngene_release_buffers(struct ngene *dev)
+{
+ if (dev->iomem)
+ iounmap(dev->iomem);
+ free_common_buffers(dev);
+ vfree(dev->tsout_buf);
+ vfree(dev->ain_buf);
+ vfree(dev->vin_buf);
+ vfree(dev);
+}
+
+static int ngene_get_buffers(struct ngene *dev)
+{
+ if (AllocCommonBuffers(dev))
+ return -ENOMEM;
+ if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) {
+ dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE);
+ if (!dev->tsout_buf)
+ return -ENOMEM;
+ dvb_ringbuffer_init(&dev->tsout_rbuf,
+ dev->tsout_buf, TSOUT_BUF_SIZE);
+ }
+ if (dev->card_info->io_type[2] & NGENE_IO_AIN) {
+ dev->ain_buf = vmalloc(AIN_BUF_SIZE);
+ if (!dev->ain_buf)
+ return -ENOMEM;
+ dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE);
+ }
+ if (dev->card_info->io_type[0] & NGENE_IO_HDTV) {
+ dev->vin_buf = vmalloc(VIN_BUF_SIZE);
+ if (!dev->vin_buf)
+ return -ENOMEM;
+ dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE);
+ }
+ dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0),
+ pci_resource_len(dev->pci_dev, 0));
+ if (!dev->iomem)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void ngene_init(struct ngene *dev)
+{
+ int i;
+
+ tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev);
+
+ memset_io(dev->iomem + 0xc000, 0x00, 0x220);
+ memset_io(dev->iomem + 0xc400, 0x00, 0x100);
+
+ for (i = 0; i < MAX_STREAM; i++) {
+ dev->channel[i].dev = dev;
+ dev->channel[i].number = i;
+ }
+
+ dev->fw_interface_version = 0;
+
+ ngwritel(0, NGENE_INT_ENABLE);
+
+ dev->icounts = ngreadl(NGENE_INT_COUNTS);
+
+ dev->device_version = ngreadl(DEV_VER) & 0x0f;
+ printk(KERN_INFO DEVICE_NAME ": Device version %d\n",
+ dev->device_version);
+}
+
+static int ngene_load_firm(struct ngene *dev)
+{
+ u32 size;
+ const struct firmware *fw = NULL;
+ u8 *ngene_fw;
+ char *fw_name;
+ int err, version;
+
+ version = dev->card_info->fw_version;
+
+ switch (version) {
+ default:
+ case 15:
+ version = 15;
+ size = 23466;
+ fw_name = "ngene_15.fw";
+ break;
+ case 16:
+ size = 23498;
+ fw_name = "ngene_16.fw";
+ break;
+ case 17:
+ size = 24446;
+ fw_name = "ngene_17.fw";
+ break;
+ }
+
+ if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) {
+ printk(KERN_ERR DEVICE_NAME
+ ": Could not load firmware file %s.\n", fw_name);
+ printk(KERN_INFO DEVICE_NAME
+ ": Copy %s to your hotplug directory!\n", fw_name);
+ return -1;
+ }
+ if (size != fw->size) {
+ printk(KERN_ERR DEVICE_NAME
+ ": Firmware %s has invalid size!", fw_name);
+ err = -1;
+ } else {
+ printk(KERN_INFO DEVICE_NAME
+ ": Loading firmware file %s.\n", fw_name);
+ ngene_fw = (u8 *) fw->data;
+ err = ngene_command_load_firmware(dev, ngene_fw, size);
+ }
+
+ release_firmware(fw);
+
+ return err;
+}
+
+static void ngene_stop(struct ngene *dev)
+{
+ down(&dev->cmd_mutex);
+ i2c_del_adapter(&(dev->channel[0].i2c_adapter));
+ i2c_del_adapter(&(dev->channel[1].i2c_adapter));
+ ngwritel(0, NGENE_INT_ENABLE);
+ ngwritel(0, NGENE_COMMAND);
+ ngwritel(0, NGENE_COMMAND_HI);
+ ngwritel(0, NGENE_STATUS);
+ ngwritel(0, NGENE_STATUS_HI);
+ ngwritel(0, NGENE_EVENT);
+ ngwritel(0, NGENE_EVENT_HI);
+ free_irq(dev->pci_dev->irq, dev);
+}
+
+static int ngene_start(struct ngene *dev)
+{
+ int stat;
+ int i;
+
+ pci_set_master(dev->pci_dev);
+ ngene_init(dev);
+
+ stat = request_irq(dev->pci_dev->irq, irq_handler,
+ IRQF_SHARED, "nGene",
+ (void *)dev);
+ if (stat < 0)
+ return stat;
+
+ init_waitqueue_head(&dev->cmd_wq);
+ init_waitqueue_head(&dev->tx_wq);
+ init_waitqueue_head(&dev->rx_wq);
+ sema_init(&dev->cmd_mutex, 1);
+ sema_init(&dev->stream_mutex, 1);
+ sema_init(&dev->pll_mutex, 1);
+ sema_init(&dev->i2c_switch_mutex, 1);
+ spin_lock_init(&dev->cmd_lock);
+ for (i = 0; i < MAX_STREAM; i++)
+ spin_lock_init(&dev->channel[i].state_lock);
+ ngwritel(1, TIMESTAMPS);
+
+ ngwritel(1, NGENE_INT_ENABLE);
+
+ stat = ngene_load_firm(dev);
+ if (stat < 0)
+ goto fail;
+
+ stat = ngene_i2c_init(dev, 0);
+ if (stat < 0)
+ goto fail;
+
+ stat = ngene_i2c_init(dev, 1);
+ if (stat < 0)
+ goto fail;
+
+ if (dev->card_info->fw_version == 17) {
+ u8 tsin4_config[6] = {
+ 3072 / 64, 3072 / 64, 0, 3072 / 64, 3072 / 64, 0};
+ u8 default_config[6] = {
+ 4096 / 64, 4096 / 64, 0, 2048 / 64, 2048 / 64, 0};
+ u8 *bconf = default_config;
+
+ if (dev->card_info->io_type[3] == NGENE_IO_TSIN)
+ bconf = tsin4_config;
+ dprintk(KERN_DEBUG DEVICE_NAME ": FW 17 buffer config\n");
+ stat = ngene_command_config_free_buf(dev, bconf);
+ } else {
+ int bconf = BUFFER_CONFIG_4422;
+ if (dev->card_info->io_type[3] == NGENE_IO_TSIN)
+ bconf = BUFFER_CONFIG_3333;
+ stat = ngene_command_config_buf(dev, bconf);
+ }
+ return stat;
+fail:
+ ngwritel(0, NGENE_INT_ENABLE);
+ free_irq(dev->pci_dev->irq, dev);
+ return stat;
+}
+
+
+
+/****************************************************************************/
+/* Switch control (I2C gates, etc.) *****************************************/
+/****************************************************************************/
+
+
+/****************************************************************************/
+/* Demod/tuner attachment ***************************************************/
+/****************************************************************************/
+
+static int tuner_attach_stv6110(struct ngene_channel *chan)
+{
+ struct stv090x_config *feconf = (struct stv090x_config *)
+ chan->dev->card_info->fe_config[chan->number];
+ struct stv6110x_config *tunerconf = (struct stv6110x_config *)
+ chan->dev->card_info->tuner_config[chan->number];
+ struct stv6110x_devctl *ctl;
+
+ ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf,
+ &chan->i2c_adapter);
+ if (ctl == NULL) {
+ printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n");
+ return -ENODEV;
+ }
+
+ feconf->tuner_init = ctl->tuner_init;
+ feconf->tuner_set_mode = ctl->tuner_set_mode;
+ feconf->tuner_set_frequency = ctl->tuner_set_frequency;
+ feconf->tuner_get_frequency = ctl->tuner_get_frequency;
+ feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+ feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+ feconf->tuner_set_bbgain = ctl->tuner_set_bbgain;
+ feconf->tuner_get_bbgain = ctl->tuner_get_bbgain;
+ feconf->tuner_set_refclk = ctl->tuner_set_refclk;
+ feconf->tuner_get_status = ctl->tuner_get_status;
+
+ return 0;
+}
+
+
+static int demod_attach_stv0900(struct ngene_channel *chan)
+{
+ struct stv090x_config *feconf = (struct stv090x_config *)
+ chan->dev->card_info->fe_config[chan->number];
+
+ chan->fe = dvb_attach(stv090x_attach,
+ feconf,
+ &chan->i2c_adapter,
+ chan->number == 0 ? STV090x_DEMODULATOR_0 :
+ STV090x_DEMODULATOR_1);
+ if (chan->fe == NULL) {
+ printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n");
+ return -ENODEV;
+ }
+
+ if (!dvb_attach(lnbh24_attach, chan->fe, &chan->i2c_adapter, 0,
+ 0, chan->dev->card_info->lnb[chan->number])) {
+ printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n");
+ dvb_frontend_detach(chan->fe);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static void release_channel(struct ngene_channel *chan)
+{
+ struct dvb_demux *dvbdemux = &chan->demux;
+ struct ngene *dev = chan->dev;
+ struct ngene_info *ni = dev->card_info;
+ int io = ni->io_type[chan->number];
+
+#ifdef COMMAND_TIMEOUT_WORKAROUND
+ if (chan->running)
+ set_transfer(chan, 0);
+#endif
+
+ tasklet_kill(&chan->demux_tasklet);
+
+ if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+ if (chan->fe) {
+ dvb_unregister_frontend(chan->fe);
+ dvb_frontend_detach(chan->fe);
+ chan->fe = 0;
+ }
+ dvbdemux->dmx.close(&dvbdemux->dmx);
+ dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+ &chan->hw_frontend);
+ dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+ &chan->mem_frontend);
+ dvb_dmxdev_release(&chan->dmxdev);
+ dvb_dmx_release(&chan->demux);
+
+ if (chan->number == 0 || !one_adapter)
+ dvb_unregister_adapter(&dev->adapter[chan->number]);
+ }
+}
+
+static int init_channel(struct ngene_channel *chan)
+{
+ int ret = 0, nr = chan->number;
+ struct dvb_adapter *adapter = NULL;
+ struct dvb_demux *dvbdemux = &chan->demux;
+ struct ngene *dev = chan->dev;
+ struct ngene_info *ni = dev->card_info;
+ int io = ni->io_type[nr];
+
+ tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan);
+ chan->users = 0;
+ chan->type = io;
+ chan->mode = chan->type; /* for now only one mode */
+
+ if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+ if (nr >= STREAM_AUDIOIN1)
+ chan->DataFormatFlags = DF_SWAP32;
+ if (nr == 0 || !one_adapter) {
+ adapter = &dev->adapter[nr];
+ ret = dvb_register_adapter(adapter, "nGene",
+ THIS_MODULE,
+ &chan->dev->pci_dev->dev,
+ adapter_nr);
+ if (ret < 0)
+ return ret;
+ } else {
+ adapter = &dev->adapter[0];
+ }
+
+ ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
+ ngene_start_feed,
+ ngene_stop_feed, chan);
+ ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux,
+ &chan->hw_frontend,
+ &chan->mem_frontend, adapter);
+ }
+
+ if (io & NGENE_IO_TSIN) {
+ chan->fe = NULL;
+ if (ni->demod_attach[nr])
+ ni->demod_attach[nr](chan);
+ if (chan->fe) {
+ if (dvb_register_frontend(adapter, chan->fe) < 0) {
+ if (chan->fe->ops.release)
+ chan->fe->ops.release(chan->fe);
+ chan->fe = NULL;
+ }
+ }
+ if (chan->fe && ni->tuner_attach[nr])
+ if (ni->tuner_attach[nr] (chan) < 0) {
+ printk(KERN_ERR DEVICE_NAME
+ ": Tuner attach failed on channel %d!\n",
+ nr);
+ }
+ }
+ return ret;
+}
+
+static int init_channels(struct ngene *dev)
+{
+ int i, j;
+
+ for (i = 0; i < MAX_STREAM; i++) {
+ if (init_channel(&dev->channel[i]) < 0) {
+ for (j = i - 1; j >= 0; j--)
+ release_channel(&dev->channel[j]);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************/
+/* device probe/remove calls ************************************************/
+/****************************************************************************/
+
+static void __devexit ngene_remove(struct pci_dev *pdev)
+{
+ struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev);
+ int i;
+
+ tasklet_kill(&dev->event_tasklet);
+ for (i = MAX_STREAM - 1; i >= 0; i--)
+ release_channel(&dev->channel[i]);
+ ngene_stop(dev);
+ ngene_release_buffers(dev);
+ pci_set_drvdata(pdev, 0);
+ pci_disable_device(pdev);
+}
+
+static int __devinit ngene_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *id)
+{
+ struct ngene *dev;
+ int stat = 0;
+
+ if (pci_enable_device(pci_dev) < 0)
+ return -ENODEV;
+
+ dev = vmalloc(sizeof(struct ngene));
+ if (dev == NULL) {
+ stat = -ENOMEM;
+ goto fail0;
+ }
+ memset(dev, 0, sizeof(struct ngene));
+
+ dev->pci_dev = pci_dev;
+ dev->card_info = (struct ngene_info *)id->driver_data;
+ printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name);
+
+ pci_set_drvdata(pci_dev, dev);
+
+ /* Alloc buffers and start nGene */
+ stat = ngene_get_buffers(dev);
+ if (stat < 0)
+ goto fail1;
+ stat = ngene_start(dev);
+ if (stat < 0)
+ goto fail1;
+
+ dev->i2c_current_bus = -1;
+
+ /* Register DVB adapters and devices for both channels */
+ if (init_channels(dev) < 0)
+ goto fail2;
+
+ return 0;
+
+fail2:
+ ngene_stop(dev);
+fail1:
+ ngene_release_buffers(dev);
+fail0:
+ pci_disable_device(pci_dev);
+ pci_set_drvdata(pci_dev, 0);
+ return stat;
+}
+
+/****************************************************************************/
+/* Card configs *************************************************************/
+/****************************************************************************/
+
+static struct stv090x_config fe_cineS2 = {
+ .device = STV0900,
+ .demod_mode = STV090x_DUAL,
+ .clk_mode = STV090x_CLK_EXT,
+
+ .xtal = 27000000,
+ .address = 0x68,
+
+ .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED,
+ .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+ .repeater_level = STV090x_RPTLEVEL_16,
+
+ .adc1_range = STV090x_ADC_1Vpp,
+ .adc2_range = STV090x_ADC_1Vpp,
+
+ .diseqc_envelope_mode = true,
+};
+
+static struct stv6110x_config tuner_cineS2_0 = {
+ .addr = 0x60,
+ .refclk = 27000000,
+ .clk_div = 1,
+};
+
+static struct stv6110x_config tuner_cineS2_1 = {
+ .addr = 0x63,
+ .refclk = 27000000,
+ .clk_div = 1,
+};
+
+static struct ngene_info ngene_info_cineS2 = {
+ .type = NGENE_SIDEWINDER,
+ .name = "Linux4Media cineS2 DVB-S2 Twin Tuner",
+ .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN},
+ .demod_attach = {demod_attach_stv0900, demod_attach_stv0900},
+ .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110},
+ .fe_config = {&fe_cineS2, &fe_cineS2},
+ .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1},
+ .lnb = {0x0b, 0x08},
+ .tsf = {3, 3},
+ .fw_version = 15,
+};
+
+static struct ngene_info ngene_info_satixs2 = {
+ .type = NGENE_SIDEWINDER,
+ .name = "Mystique SaTiX-S2 Dual",
+ .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN},
+ .demod_attach = {demod_attach_stv0900, demod_attach_stv0900},
+ .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110},
+ .fe_config = {&fe_cineS2, &fe_cineS2},
+ .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1},
+ .lnb = {0x0b, 0x08},
+ .tsf = {3, 3},
+ .fw_version = 15,
+};
+
+/****************************************************************************/
+
+
+
+/****************************************************************************/
+/* PCI Subsystem ID *********************************************************/
+/****************************************************************************/
+
+#define NGENE_ID(_subvend, _subdev, _driverdata) { \
+ .vendor = NGENE_VID, .device = NGENE_PID, \
+ .subvendor = _subvend, .subdevice = _subdev, \
+ .driver_data = (unsigned long) &_driverdata }
+
+/****************************************************************************/
+
+static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
+ NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2),
+ NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2),
+ NGENE_ID(0x18c3, 0xdb01, ngene_info_satixs2),
+ {0}
+};
+MODULE_DEVICE_TABLE(pci, ngene_id_tbl);
+
+/****************************************************************************/
+/* Init/Exit ****************************************************************/
+/****************************************************************************/
+
+static pci_ers_result_t ngene_error_detected(struct pci_dev *dev,
+ enum pci_channel_state state)
+{
+ printk(KERN_ERR DEVICE_NAME ": PCI error\n");
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+ if (state == pci_channel_io_frozen)
+ return PCI_ERS_RESULT_NEED_RESET;
+ return PCI_ERS_RESULT_CAN_RECOVER;
+}
+
+static pci_ers_result_t ngene_link_reset(struct pci_dev *dev)
+{
+ printk(KERN_INFO DEVICE_NAME ": link reset\n");
+ return 0;
+}
+
+static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev)
+{
+ printk(KERN_INFO DEVICE_NAME ": slot reset\n");
+ return 0;
+}
+
+static void ngene_resume(struct pci_dev *dev)
+{
+ printk(KERN_INFO DEVICE_NAME ": resume\n");
+}
+
+static struct pci_error_handlers ngene_errors = {
+ .error_detected = ngene_error_detected,
+ .link_reset = ngene_link_reset,
+ .slot_reset = ngene_slot_reset,
+ .resume = ngene_resume,
+};
+
+static struct pci_driver ngene_pci_driver = {
+ .name = "ngene",
+ .id_table = ngene_id_tbl,
+ .probe = ngene_probe,
+ .remove = __devexit_p(ngene_remove),
+ .err_handler = &ngene_errors,
+};
+
+static __init int module_init_ngene(void)
+{
+ printk(KERN_INFO
+ "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n");
+ return pci_register_driver(&ngene_pci_driver);
+}
+
+static __exit void module_exit_ngene(void)
+{
+ pci_unregister_driver(&ngene_pci_driver);
+}
+
+module_init(module_init_ngene);
+module_exit(module_exit_ngene);
+
+MODULE_DESCRIPTION("nGene");
+MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h
new file mode 100644
index 000000000000..a7eb29846310
--- /dev/null
+++ b/drivers/media/dvb/ngene/ngene.h
@@ -0,0 +1,859 @@
+/*
+ * ngene.h: nGene PCIe bridge driver
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _NGENE_H_
+#define _NGENE_H_
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <asm/dma.h>
+#include <linux/scatterlist.h>
+
+#include <linux/dvb/frontend.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_ringbuffer.h"
+
+#define NGENE_VID 0x18c3
+#define NGENE_PID 0x0720
+
+#ifndef VIDEO_CAP_VC1
+#define VIDEO_CAP_AVC 128
+#define VIDEO_CAP_H264 128
+#define VIDEO_CAP_VC1 256
+#define VIDEO_CAP_WMV9 256
+#define VIDEO_CAP_MPEG4 512
+#endif
+
+enum STREAM {
+ STREAM_VIDEOIN1 = 0, /* ITU656 or TS Input */
+ STREAM_VIDEOIN2,
+ STREAM_AUDIOIN1, /* I2S or SPI Input */
+ STREAM_AUDIOIN2,
+ STREAM_AUDIOOUT,
+ MAX_STREAM
+};
+
+enum SMODE_BITS {
+ SMODE_AUDIO_SPDIF = 0x20,
+ SMODE_AVSYNC = 0x10,
+ SMODE_TRANSPORT_STREAM = 0x08,
+ SMODE_AUDIO_CAPTURE = 0x04,
+ SMODE_VBI_CAPTURE = 0x02,
+ SMODE_VIDEO_CAPTURE = 0x01
+};
+
+enum STREAM_FLAG_BITS {
+ SFLAG_CHROMA_FORMAT_2COMP = 0x01, /* Chroma Format : 2's complement */
+ SFLAG_CHROMA_FORMAT_OFFSET = 0x00, /* Chroma Format : Binary offset */
+ SFLAG_ORDER_LUMA_CHROMA = 0x02, /* Byte order: Y,Cb,Y,Cr */
+ SFLAG_ORDER_CHROMA_LUMA = 0x00, /* Byte order: Cb,Y,Cr,Y */
+ SFLAG_COLORBAR = 0x04, /* Select colorbar */
+};
+
+#define PROGRAM_ROM 0x0000
+#define PROGRAM_SRAM 0x1000
+#define PERIPHERALS0 0x8000
+#define PERIPHERALS1 0x9000
+#define SHARED_BUFFER 0xC000
+
+#define HOST_TO_NGENE (SHARED_BUFFER+0x0000)
+#define NGENE_TO_HOST (SHARED_BUFFER+0x0100)
+#define NGENE_COMMAND (SHARED_BUFFER+0x0200)
+#define NGENE_COMMAND_HI (SHARED_BUFFER+0x0204)
+#define NGENE_STATUS (SHARED_BUFFER+0x0208)
+#define NGENE_STATUS_HI (SHARED_BUFFER+0x020C)
+#define NGENE_EVENT (SHARED_BUFFER+0x0210)
+#define NGENE_EVENT_HI (SHARED_BUFFER+0x0214)
+#define VARIABLES (SHARED_BUFFER+0x0210)
+
+#define NGENE_INT_COUNTS (SHARED_BUFFER+0x0260)
+#define NGENE_INT_ENABLE (SHARED_BUFFER+0x0264)
+#define NGENE_VBI_LINE_COUNT (SHARED_BUFFER+0x0268)
+
+#define BUFFER_GP_XMIT (SHARED_BUFFER+0x0800)
+#define BUFFER_GP_RECV (SHARED_BUFFER+0x0900)
+#define EEPROM_AREA (SHARED_BUFFER+0x0A00)
+
+#define SG_V_IN_1 (SHARED_BUFFER+0x0A80)
+#define SG_VBI_1 (SHARED_BUFFER+0x0B00)
+#define SG_A_IN_1 (SHARED_BUFFER+0x0B80)
+#define SG_V_IN_2 (SHARED_BUFFER+0x0C00)
+#define SG_VBI_2 (SHARED_BUFFER+0x0C80)
+#define SG_A_IN_2 (SHARED_BUFFER+0x0D00)
+#define SG_V_OUT (SHARED_BUFFER+0x0D80)
+#define SG_A_OUT2 (SHARED_BUFFER+0x0E00)
+
+#define DATA_A_IN_1 (SHARED_BUFFER+0x0E80)
+#define DATA_A_IN_2 (SHARED_BUFFER+0x0F00)
+#define DATA_A_OUT (SHARED_BUFFER+0x0F80)
+#define DATA_V_IN_1 (SHARED_BUFFER+0x1000)
+#define DATA_V_IN_2 (SHARED_BUFFER+0x2000)
+#define DATA_V_OUT (SHARED_BUFFER+0x3000)
+
+#define DATA_FIFO_AREA (SHARED_BUFFER+0x1000)
+
+#define TIMESTAMPS 0xA000
+#define SCRATCHPAD 0xA080
+#define FORCE_INT 0xA088
+#define FORCE_NMI 0xA090
+#define INT_STATUS 0xA0A0
+
+#define DEV_VER 0x9004
+
+#define FW_DEBUG_DEFAULT (PROGRAM_SRAM+0x00FF)
+
+struct SG_ADDR {
+ u64 start;
+ u64 curr;
+ u16 curr_ptr;
+ u16 elements;
+ u32 pad[3];
+} __attribute__ ((__packed__));
+
+struct SHARED_MEMORY {
+ /* C000 */
+ u32 HostToNgene[64];
+
+ /* C100 */
+ u32 NgeneToHost[64];
+
+ /* C200 */
+ u64 NgeneCommand;
+ u64 NgeneStatus;
+ u64 NgeneEvent;
+
+ /* C210 */
+ u8 pad1[0xc260 - 0xc218];
+
+ /* C260 */
+ u32 IntCounts;
+ u32 IntEnable;
+
+ /* C268 */
+ u8 pad2[0xd000 - 0xc268];
+
+} __attribute__ ((__packed__));
+
+struct BUFFER_STREAM_RESULTS {
+ u32 Clock; /* Stream time in 100ns units */
+ u16 RemainingLines; /* Remaining lines in this field.
+ 0 for complete field */
+ u8 FieldCount; /* Video field number */
+ u8 Flags; /* Bit 7 = Done, Bit 6 = seen, Bit 5 = overflow,
+ Bit 0 = FieldID */
+ u16 BlockCount; /* Audio block count (unused) */
+ u8 Reserved[2];
+ u32 DTOUpdate;
+} __attribute__ ((__packed__));
+
+struct HW_SCATTER_GATHER_ELEMENT {
+ u64 Address;
+ u32 Length;
+ u32 Reserved;
+} __attribute__ ((__packed__));
+
+struct BUFFER_HEADER {
+ u64 Next;
+ struct BUFFER_STREAM_RESULTS SR;
+
+ u32 Number_of_entries_1;
+ u32 Reserved5;
+ u64 Address_of_first_entry_1;
+
+ u32 Number_of_entries_2;
+ u32 Reserved7;
+ u64 Address_of_first_entry_2;
+} __attribute__ ((__packed__));
+
+struct EVENT_BUFFER {
+ u32 TimeStamp;
+ u8 GPIOStatus;
+ u8 UARTStatus;
+ u8 RXCharacter;
+ u8 EventStatus;
+ u32 Reserved[2];
+} __attribute__ ((__packed__));
+
+/* Firmware commands. */
+
+enum OPCODES {
+ CMD_NOP = 0,
+ CMD_FWLOAD_PREPARE = 0x01,
+ CMD_FWLOAD_FINISH = 0x02,
+ CMD_I2C_READ = 0x03,
+ CMD_I2C_WRITE = 0x04,
+
+ CMD_I2C_WRITE_NOSTOP = 0x05,
+ CMD_I2C_CONTINUE_WRITE = 0x06,
+ CMD_I2C_CONTINUE_WRITE_NOSTOP = 0x07,
+
+ CMD_DEBUG_OUTPUT = 0x09,
+
+ CMD_CONTROL = 0x10,
+ CMD_CONFIGURE_BUFFER = 0x11,
+ CMD_CONFIGURE_FREE_BUFFER = 0x12,
+
+ CMD_SPI_READ = 0x13,
+ CMD_SPI_WRITE = 0x14,
+
+ CMD_MEM_READ = 0x20,
+ CMD_MEM_WRITE = 0x21,
+ CMD_SFR_READ = 0x22,
+ CMD_SFR_WRITE = 0x23,
+ CMD_IRAM_READ = 0x24,
+ CMD_IRAM_WRITE = 0x25,
+ CMD_SET_GPIO_PIN = 0x26,
+ CMD_SET_GPIO_INT = 0x27,
+ CMD_CONFIGURE_UART = 0x28,
+ CMD_WRITE_UART = 0x29,
+ MAX_CMD
+};
+
+enum RESPONSES {
+ OK = 0,
+ ERROR = 1
+};
+
+struct FW_HEADER {
+ u8 Opcode;
+ u8 Length;
+} __attribute__ ((__packed__));
+
+struct FW_I2C_WRITE {
+ struct FW_HEADER hdr;
+ u8 Device;
+ u8 Data[250];
+} __attribute__ ((__packed__));
+
+struct FW_I2C_CONTINUE_WRITE {
+ struct FW_HEADER hdr;
+ u8 Data[250];
+} __attribute__ ((__packed__));
+
+struct FW_I2C_READ {
+ struct FW_HEADER hdr;
+ u8 Device;
+ u8 Data[252]; /* followed by two bytes of read data count */
+} __attribute__ ((__packed__));
+
+struct FW_SPI_WRITE {
+ struct FW_HEADER hdr;
+ u8 ModeSelect;
+ u8 Data[250];
+} __attribute__ ((__packed__));
+
+struct FW_SPI_READ {
+ struct FW_HEADER hdr;
+ u8 ModeSelect;
+ u8 Data[252]; /* followed by two bytes of read data count */
+} __attribute__ ((__packed__));
+
+struct FW_FWLOAD_PREPARE {
+ struct FW_HEADER hdr;
+} __attribute__ ((__packed__));
+
+struct FW_FWLOAD_FINISH {
+ struct FW_HEADER hdr;
+ u16 Address; /* address of final block */
+ u16 Length;
+} __attribute__ ((__packed__));
+
+/*
+ * Meaning of FW_STREAM_CONTROL::Mode bits:
+ * Bit 7: Loopback PEXin to PEXout using TVOut channel
+ * Bit 6: AVLOOP
+ * Bit 5: Audio select; 0=I2S, 1=SPDIF
+ * Bit 4: AVSYNC
+ * Bit 3: Enable transport stream
+ * Bit 2: Enable audio capture
+ * Bit 1: Enable ITU-Video VBI capture
+ * Bit 0: Enable ITU-Video capture
+ *
+ * Meaning of FW_STREAM_CONTROL::Control bits (see UVI1_CTL)
+ * Bit 7: continuous capture
+ * Bit 6: capture one field
+ * Bit 5: capture one frame
+ * Bit 4: unused
+ * Bit 3: starting field; 0=odd, 1=even
+ * Bit 2: sample size; 0=8-bit, 1=10-bit
+ * Bit 1: data format; 0=UYVY, 1=YUY2
+ * Bit 0: resets buffer pointers
+*/
+
+enum FSC_MODE_BITS {
+ SMODE_LOOPBACK = 0x80,
+ SMODE_AVLOOP = 0x40,
+ _SMODE_AUDIO_SPDIF = 0x20,
+ _SMODE_AVSYNC = 0x10,
+ _SMODE_TRANSPORT_STREAM = 0x08,
+ _SMODE_AUDIO_CAPTURE = 0x04,
+ _SMODE_VBI_CAPTURE = 0x02,
+ _SMODE_VIDEO_CAPTURE = 0x01
+};
+
+
+/* Meaning of FW_STREAM_CONTROL::Stream bits:
+ * Bit 3: Audio sample count: 0 = relative, 1 = absolute
+ * Bit 2: color bar select; 1=color bars, 0=CV3 decoder
+ * Bits 1-0: stream select, UVI1, UVI2, TVOUT
+ */
+
+struct FW_STREAM_CONTROL {
+ struct FW_HEADER hdr;
+ u8 Stream; /* Stream number (UVI1, UVI2, TVOUT) */
+ u8 Control; /* Value written to UVI1_CTL */
+ u8 Mode; /* Controls clock source */
+ u8 SetupDataLen; /* Length of setup data, MSB=1 write
+ backwards */
+ u16 CaptureBlockCount; /* Blocks (a 256 Bytes) to capture per buffer
+ for TS and Audio */
+ u64 Buffer_Address; /* Address of first buffer header */
+ u16 BytesPerVideoLine;
+ u16 MaxLinesPerField;
+ u16 MinLinesPerField;
+ u16 Reserved_1;
+ u16 BytesPerVBILine;
+ u16 MaxVBILinesPerField;
+ u16 MinVBILinesPerField;
+ u16 SetupDataAddr; /* ngene relative address of setup data */
+ u8 SetupData[32]; /* setup data */
+} __attribute__((__packed__));
+
+#define AUDIO_BLOCK_SIZE 256
+#define TS_BLOCK_SIZE 256
+
+struct FW_MEM_READ {
+ struct FW_HEADER hdr;
+ u16 address;
+} __attribute__ ((__packed__));
+
+struct FW_MEM_WRITE {
+ struct FW_HEADER hdr;
+ u16 address;
+ u8 data;
+} __attribute__ ((__packed__));
+
+struct FW_SFR_IRAM_READ {
+ struct FW_HEADER hdr;
+ u8 address;
+} __attribute__ ((__packed__));
+
+struct FW_SFR_IRAM_WRITE {
+ struct FW_HEADER hdr;
+ u8 address;
+ u8 data;
+} __attribute__ ((__packed__));
+
+struct FW_SET_GPIO_PIN {
+ struct FW_HEADER hdr;
+ u8 select;
+} __attribute__ ((__packed__));
+
+struct FW_SET_GPIO_INT {
+ struct FW_HEADER hdr;
+ u8 select;
+} __attribute__ ((__packed__));
+
+struct FW_SET_DEBUGMODE {
+ struct FW_HEADER hdr;
+ u8 debug_flags;
+} __attribute__ ((__packed__));
+
+struct FW_CONFIGURE_BUFFERS {
+ struct FW_HEADER hdr;
+ u8 config;
+} __attribute__ ((__packed__));
+
+enum _BUFFER_CONFIGS {
+ /* 4k UVI1, 4k UVI2, 2k AUD1, 2k AUD2 (standard usage) */
+ BUFFER_CONFIG_4422 = 0,
+ /* 3k UVI1, 3k UVI2, 3k AUD1, 3k AUD2 (4x TS input usage) */
+ BUFFER_CONFIG_3333 = 1,
+ /* 8k UVI1, 0k UVI2, 2k AUD1, 2k I2SOut (HDTV decoder usage) */
+ BUFFER_CONFIG_8022 = 2,
+ BUFFER_CONFIG_FW17 = 255, /* Use new FW 17 command */
+};
+
+struct FW_CONFIGURE_FREE_BUFFERS {
+ struct FW_HEADER hdr;
+ u8 UVI1_BufferLength;
+ u8 UVI2_BufferLength;
+ u8 TVO_BufferLength;
+ u8 AUD1_BufferLength;
+ u8 AUD2_BufferLength;
+ u8 TVA_BufferLength;
+} __attribute__ ((__packed__));
+
+struct FW_CONFIGURE_UART {
+ struct FW_HEADER hdr;
+ u8 UartControl;
+} __attribute__ ((__packed__));
+
+enum _UART_CONFIG {
+ _UART_BAUDRATE_19200 = 0,
+ _UART_BAUDRATE_9600 = 1,
+ _UART_BAUDRATE_4800 = 2,
+ _UART_BAUDRATE_2400 = 3,
+ _UART_RX_ENABLE = 0x40,
+ _UART_TX_ENABLE = 0x80,
+};
+
+struct FW_WRITE_UART {
+ struct FW_HEADER hdr;
+ u8 Data[252];
+} __attribute__ ((__packed__));
+
+
+struct ngene_command {
+ u32 in_len;
+ u32 out_len;
+ union {
+ u32 raw[64];
+ u8 raw8[256];
+ struct FW_HEADER hdr;
+ struct FW_I2C_WRITE I2CWrite;
+ struct FW_I2C_CONTINUE_WRITE I2CContinueWrite;
+ struct FW_I2C_READ I2CRead;
+ struct FW_STREAM_CONTROL StreamControl;
+ struct FW_FWLOAD_PREPARE FWLoadPrepare;
+ struct FW_FWLOAD_FINISH FWLoadFinish;
+ struct FW_MEM_READ MemoryRead;
+ struct FW_MEM_WRITE MemoryWrite;
+ struct FW_SFR_IRAM_READ SfrIramRead;
+ struct FW_SFR_IRAM_WRITE SfrIramWrite;
+ struct FW_SPI_WRITE SPIWrite;
+ struct FW_SPI_READ SPIRead;
+ struct FW_SET_GPIO_PIN SetGpioPin;
+ struct FW_SET_GPIO_INT SetGpioInt;
+ struct FW_SET_DEBUGMODE SetDebugMode;
+ struct FW_CONFIGURE_BUFFERS ConfigureBuffers;
+ struct FW_CONFIGURE_FREE_BUFFERS ConfigureFreeBuffers;
+ struct FW_CONFIGURE_UART ConfigureUart;
+ struct FW_WRITE_UART WriteUart;
+ } cmd;
+} __attribute__ ((__packed__));
+
+#define NGENE_INTERFACE_VERSION 0x103
+#define MAX_VIDEO_BUFFER_SIZE (417792) /* 288*1440 rounded up to next page */
+#define MAX_AUDIO_BUFFER_SIZE (8192) /* Gives room for about 23msec@48KHz */
+#define MAX_VBI_BUFFER_SIZE (28672) /* 1144*18 rounded up to next page */
+#define MAX_TS_BUFFER_SIZE (98304) /* 512*188 rounded up to next page */
+#define MAX_HDTV_BUFFER_SIZE (2080768) /* 541*1920*2 rounded up to next page
+ Max: (1920x1080i60) */
+
+#define OVERFLOW_BUFFER_SIZE (8192)
+
+#define RING_SIZE_VIDEO 4
+#define RING_SIZE_AUDIO 8
+#define RING_SIZE_TS 8
+
+#define NUM_SCATTER_GATHER_ENTRIES 8
+
+#define MAX_DMA_LENGTH (((MAX_VIDEO_BUFFER_SIZE + MAX_VBI_BUFFER_SIZE) * \
+ RING_SIZE_VIDEO * 2) + \
+ (MAX_AUDIO_BUFFER_SIZE * RING_SIZE_AUDIO * 2) + \
+ (MAX_TS_BUFFER_SIZE * RING_SIZE_TS * 4) + \
+ (RING_SIZE_VIDEO * PAGE_SIZE * 2) + \
+ (RING_SIZE_AUDIO * PAGE_SIZE * 2) + \
+ (RING_SIZE_TS * PAGE_SIZE * 4) + \
+ 8 * PAGE_SIZE + OVERFLOW_BUFFER_SIZE + PAGE_SIZE)
+
+#define EVENT_QUEUE_SIZE 16
+
+/* Gathers the current state of a single channel. */
+
+struct SBufferHeader {
+ struct BUFFER_HEADER ngeneBuffer; /* Physical descriptor */
+ struct SBufferHeader *Next;
+ void *Buffer1;
+ struct HW_SCATTER_GATHER_ELEMENT *scList1;
+ void *Buffer2;
+ struct HW_SCATTER_GATHER_ELEMENT *scList2;
+};
+
+/* Sizeof SBufferHeader aligned to next 64 Bit boundary (hw restriction) */
+#define SIZEOF_SBufferHeader ((sizeof(struct SBufferHeader) + 63) & ~63)
+
+enum HWSTATE {
+ HWSTATE_STOP,
+ HWSTATE_STARTUP,
+ HWSTATE_RUN,
+ HWSTATE_PAUSE,
+};
+
+enum KSSTATE {
+ KSSTATE_STOP,
+ KSSTATE_ACQUIRE,
+ KSSTATE_PAUSE,
+ KSSTATE_RUN,
+};
+
+struct SRingBufferDescriptor {
+ struct SBufferHeader *Head; /* Points to first buffer in ring buffer
+ structure*/
+ u64 PAHead; /* Physical address of first buffer */
+ u32 MemSize; /* Memory size of allocated ring buffers
+ (needed for freeing) */
+ u32 NumBuffers; /* Number of buffers in the ring */
+ u32 Buffer1Length; /* Allocated length of Buffer 1 */
+ u32 Buffer2Length; /* Allocated length of Buffer 2 */
+ void *SCListMem; /* Memory to hold scatter gather lists for this
+ ring */
+ u64 PASCListMem; /* Physical address .. */
+ u32 SCListMemSize; /* Size of this memory */
+};
+
+enum STREAMMODEFLAGS {
+ StreamMode_NONE = 0, /* Stream not used */
+ StreamMode_ANALOG = 1, /* Analog: Stream 0,1 = Video, 2,3 = Audio */
+ StreamMode_TSIN = 2, /* Transport stream input (all) */
+ StreamMode_HDTV = 4, /* HDTV: Maximum 1920x1080p30,1920x1080i60
+ (only stream 0) */
+ StreamMode_TSOUT = 8, /* Transport stream output (only stream 3) */
+};
+
+
+enum BufferExchangeFlags {
+ BEF_EVEN_FIELD = 0x00000001,
+ BEF_CONTINUATION = 0x00000002,
+ BEF_MORE_DATA = 0x00000004,
+ BEF_OVERFLOW = 0x00000008,
+ DF_SWAP32 = 0x00010000,
+};
+
+typedef void *(IBufferExchange)(void *, void *, u32, u32, u32);
+
+struct MICI_STREAMINFO {
+ IBufferExchange *pExchange;
+ IBufferExchange *pExchangeVBI; /* Secondary (VBI, ancillary) */
+ u8 Stream;
+ u8 Flags;
+ u8 Mode;
+ u8 Reserved;
+ u16 nLinesVideo;
+ u16 nBytesPerLineVideo;
+ u16 nLinesVBI;
+ u16 nBytesPerLineVBI;
+ u32 CaptureLength; /* Used for audio and transport stream */
+};
+
+/****************************************************************************/
+/* STRUCTS ******************************************************************/
+/****************************************************************************/
+
+/* sound hardware definition */
+#define MIXER_ADDR_TVTUNER 0
+#define MIXER_ADDR_LAST 0
+
+struct ngene_channel;
+
+/*struct sound chip*/
+
+struct mychip {
+ struct ngene_channel *chan;
+ struct snd_card *card;
+ struct pci_dev *pci;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm *pcm;
+ unsigned long port;
+ int irq;
+ spinlock_t mixer_lock;
+ spinlock_t lock;
+ int mixer_volume[MIXER_ADDR_LAST + 1][2];
+ int capture_source[MIXER_ADDR_LAST + 1][2];
+};
+
+#ifdef NGENE_V4L
+struct ngene_overlay {
+ int tvnorm;
+ struct v4l2_rect w;
+ enum v4l2_field field;
+ struct v4l2_clip *clips;
+ int nclips;
+ int setup_ok;
+};
+
+struct ngene_tvnorm {
+ int v4l2_id;
+ char *name;
+ u16 swidth, sheight; /* scaled standard width, height */
+ int tuner_norm;
+ int soundstd;
+};
+
+struct ngene_vopen {
+ struct ngene_channel *ch;
+ enum v4l2_priority prio;
+ int width;
+ int height;
+ int depth;
+ struct videobuf_queue vbuf_q;
+ struct videobuf_queue vbi;
+ int fourcc;
+ int picxcount;
+ int resources;
+ enum v4l2_buf_type type;
+ const struct ngene_format *fmt;
+
+ const struct ngene_format *ovfmt;
+ struct ngene_overlay ov;
+};
+#endif
+
+struct ngene_channel {
+ struct device device;
+ struct i2c_adapter i2c_adapter;
+
+ struct ngene *dev;
+ int number;
+ int type;
+ int mode;
+
+ struct dvb_frontend *fe;
+ struct dmxdev dmxdev;
+ struct dvb_demux demux;
+ struct dmx_frontend hw_frontend;
+ struct dmx_frontend mem_frontend;
+ int users;
+ struct video_device *v4l_dev;
+ struct tasklet_struct demux_tasklet;
+
+ struct SBufferHeader *nextBuffer;
+ enum KSSTATE State;
+ enum HWSTATE HWState;
+ u8 Stream;
+ u8 Flags;
+ u8 Mode;
+ IBufferExchange *pBufferExchange;
+ IBufferExchange *pBufferExchange2;
+
+ spinlock_t state_lock;
+ u16 nLines;
+ u16 nBytesPerLine;
+ u16 nVBILines;
+ u16 nBytesPerVBILine;
+ u16 itumode;
+ u32 Capture1Length;
+ u32 Capture2Length;
+ struct SRingBufferDescriptor RingBuffer;
+ struct SRingBufferDescriptor TSRingBuffer;
+ struct SRingBufferDescriptor TSIdleBuffer;
+
+ u32 DataFormatFlags;
+
+ int AudioDTOUpdated;
+ u32 AudioDTOValue;
+
+ int (*set_tone)(struct dvb_frontend *, fe_sec_tone_mode_t);
+ u8 lnbh;
+
+ /* stuff from analog driver */
+
+ int minor;
+ struct mychip *mychip;
+ struct snd_card *soundcard;
+ u8 *evenbuffer;
+ u8 dma_on;
+ int soundstreamon;
+ int audiomute;
+ int soundbuffisallocated;
+ int sndbuffflag;
+ int tun_rdy;
+ int dec_rdy;
+ int tun_dec_rdy;
+ int lastbufferflag;
+
+ struct ngene_tvnorm *tvnorms;
+ int tvnorm_num;
+ int tvnorm;
+
+#ifdef NGENE_V4L
+ int videousers;
+ struct v4l2_prio_state prio;
+ struct ngene_vopen init;
+ int resources;
+ struct v4l2_framebuffer fbuf;
+ struct ngene_buffer *screen; /* overlay */
+ struct list_head capture; /* video capture queue */
+ spinlock_t s_lock;
+ struct semaphore reslock;
+#endif
+
+ int running;
+};
+
+struct ngene;
+
+typedef void (rx_cb_t)(struct ngene *, u32, u8);
+typedef void (tx_cb_t)(struct ngene *, u32);
+
+struct ngene {
+ int nr;
+ struct pci_dev *pci_dev;
+ unsigned char *iomem;
+
+ /*struct i2c_adapter i2c_adapter;*/
+
+ u32 device_version;
+ u32 fw_interface_version;
+ u32 icounts;
+
+ u8 *CmdDoneByte;
+ int BootFirmware;
+ void *OverflowBuffer;
+ dma_addr_t PAOverflowBuffer;
+ void *FWInterfaceBuffer;
+ dma_addr_t PAFWInterfaceBuffer;
+ u8 *ngenetohost;
+ u8 *hosttongene;
+
+ struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE];
+ int EventQueueOverflowCount;
+ int EventQueueOverflowFlag;
+ struct tasklet_struct event_tasklet;
+ struct EVENT_BUFFER *EventBuffer;
+ int EventQueueWriteIndex;
+ int EventQueueReadIndex;
+
+ wait_queue_head_t cmd_wq;
+ int cmd_done;
+ struct semaphore cmd_mutex;
+ struct semaphore stream_mutex;
+ struct semaphore pll_mutex;
+ struct semaphore i2c_switch_mutex;
+ int i2c_current_channel;
+ int i2c_current_bus;
+ spinlock_t cmd_lock;
+
+ struct dvb_adapter adapter[MAX_STREAM];
+ struct ngene_channel channel[MAX_STREAM];
+
+ struct ngene_info *card_info;
+
+ tx_cb_t *TxEventNotify;
+ rx_cb_t *RxEventNotify;
+ int tx_busy;
+ wait_queue_head_t tx_wq;
+ wait_queue_head_t rx_wq;
+#define UART_RBUF_LEN 4096
+ u8 uart_rbuf[UART_RBUF_LEN];
+ int uart_rp, uart_wp;
+
+ u8 *tsout_buf;
+#define TSOUT_BUF_SIZE (512*188*8)
+ struct dvb_ringbuffer tsout_rbuf;
+
+ u8 *ain_buf;
+#define AIN_BUF_SIZE (128*1024)
+ struct dvb_ringbuffer ain_rbuf;
+
+
+ u8 *vin_buf;
+#define VIN_BUF_SIZE (4*1920*1080)
+ struct dvb_ringbuffer vin_rbuf;
+
+ unsigned long exp_val;
+ int prev_cmd;
+};
+
+struct ngene_info {
+ int type;
+#define NGENE_APP 0
+#define NGENE_TERRATEC 1
+#define NGENE_SIDEWINDER 2
+#define NGENE_RACER 3
+#define NGENE_VIPER 4
+#define NGENE_PYTHON 5
+#define NGENE_VBOX_V1 6
+#define NGENE_VBOX_V2 7
+
+ int fw_version;
+ char *name;
+
+ int io_type[MAX_STREAM];
+#define NGENE_IO_NONE 0
+#define NGENE_IO_TV 1
+#define NGENE_IO_HDTV 2
+#define NGENE_IO_TSIN 4
+#define NGENE_IO_TSOUT 8
+#define NGENE_IO_AIN 16
+
+ void *fe_config[4];
+ void *tuner_config[4];
+
+ int (*demod_attach[4])(struct ngene_channel *);
+ int (*tuner_attach[4])(struct ngene_channel *);
+
+ u8 avf[4];
+ u8 msp[4];
+ u8 demoda[4];
+ u8 lnb[4];
+ int i2c_access;
+ u8 ntsc;
+ u8 tsf[4];
+ u8 i2s[4];
+
+ int (*gate_ctrl)(struct dvb_frontend *, int);
+ int (*switch_ctrl)(struct ngene_channel *, int, int);
+};
+
+#ifdef NGENE_V4L
+struct ngene_format{
+ char *name;
+ int fourcc; /* video4linux 2 */
+ int btformat; /* BT848_COLOR_FMT_* */
+ int format;
+ int btswap; /* BT848_COLOR_CTL_* */
+ int depth; /* bit/pixel */
+ int flags;
+ int hshift, vshift; /* for planar modes */
+ int palette;
+};
+
+#define RESOURCE_OVERLAY 1
+#define RESOURCE_VIDEO 2
+#define RESOURCE_VBI 4
+
+struct ngene_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
+ /* ngene specific */
+ const struct ngene_format *fmt;
+ int tvnorm;
+ int btformat;
+ int btswap;
+};
+#endif
+
+
+#endif
+
+/* LocalWords: Endif
+ */
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
index 1067b22eb0c6..cff77e2eb557 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -62,6 +62,7 @@ static struct sms_board sms_boards[] = {
[SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
.name = "Hauppauge WinTV MiniStick",
.type = SMS_NOVA_B0,
+ .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
.board_cfg.leds_power = 26,
.board_cfg.led0 = 27,
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
index ca758bcb48c9..4bfd3451b568 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -1459,8 +1459,10 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
- &groupCfg) != 0)
- return -EINVAL;
+ &groupCfg) != 0) {
+ rc = -EINVAL;
+ goto free;
+ }
pMsg->msgData[1] = TranslatedPinNum;
pMsg->msgData[2] = GroupNum;
@@ -1490,6 +1492,7 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
else
sms_err("smscore_gpio_configure error");
}
+free:
kfree(buffer);
return rc;
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
index eec18aaf5512..8ecadecaa9d0 100644
--- a/drivers/media/dvb/siano/smscoreapi.h
+++ b/drivers/media/dvb/siano/smscoreapi.h
@@ -212,6 +212,8 @@ struct smscore_device_t {
#define MSG_SMS_DAB_CHANNEL 607
#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608
#define MSG_SMS_GET_PID_FILTER_LIST_RES 609
+#define MSG_SMS_GET_STATISTICS_RES 616
+#define MSG_SMS_GET_STATISTICS_REQ 615
#define MSG_SMS_HO_PER_SLICES_IND 630
#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651
#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652
@@ -339,7 +341,7 @@ struct SmsFirmware_ST {
/* Statistics information returned as response for
* SmsHostApiGetStatistics_Req */
-struct SMSHOSTLIB_STATISTICS_S {
+struct SMSHOSTLIB_STATISTICS_ST {
u32 Reserved; /* Reserved */
/* Common parameters */
@@ -424,6 +426,79 @@ struct SMSHOSTLIB_STATISTICS_S {
u32 ReservedFields[10]; /* Reserved */
};
+struct SmsMsgStatisticsInfo_ST {
+ u32 RequestResult;
+
+ struct SMSHOSTLIB_STATISTICS_ST Stat;
+
+ /* Split the calc of the SNR in DAB */
+ u32 Signal; /* dB */
+ u32 Noise; /* dB */
+
+};
+
+struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST {
+ /* Per-layer information */
+ u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
+ * 255 means layer does not exist */
+ u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET,
+ * 255 means layer does not exist */
+ u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
+ u32 BERErrorCount; /* Post Viterbi Error Bits Count */
+ u32 BERBitCount; /* Post Viterbi Total Bits Count */
+ u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
+ u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */
+ u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
+ u32 TotalTSPackets; /* Total number of transport-stream packets */
+ u32 TILdepthI; /* Time interleaver depth I parameter,
+ * 255 means layer does not exist */
+ u32 NumberOfSegments; /* Number of segments in layer A,
+ * 255 means layer does not exist */
+ u32 TMCCErrors; /* TMCC errors */
+};
+
+struct SMSHOSTLIB_STATISTICS_ISDBT_ST {
+ u32 StatisticsType; /* Enumerator identifying the type of the
+ * structure. Values are the same as
+ * SMSHOSTLIB_DEVICE_MODES_E
+ *
+ * This field MUST always be first in any
+ * statistics structure */
+
+ u32 FullSize; /* Total size of the structure returned by the modem.
+ * If the size requested by the host is smaller than
+ * FullSize, the struct will be truncated */
+
+ /* Common parameters */
+ u32 IsRfLocked; /* 0 - not locked, 1 - locked */
+ u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
+ u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
+
+ /* Reception quality */
+ s32 SNR; /* dB */
+ s32 RSSI; /* dBm */
+ s32 InBandPwr; /* In band power in dBM */
+ s32 CarrierOffset; /* Carrier Offset in Hz */
+
+ /* Transmission parameters */
+ u32 Frequency; /* Frequency in Hz */
+ u32 Bandwidth; /* Bandwidth in MHz */
+ u32 TransmissionMode; /* ISDB-T transmission mode */
+ u32 ModemState; /* 0 - Acquisition, 1 - Locked */
+ u32 GuardInterval; /* Guard Interval, 1 divided by value */
+ u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */
+ u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */
+ u32 NumOfLayers; /* Number of ISDB-T layers in the network */
+
+ /* Per-layer information */
+ /* Layers A, B and C */
+ struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3];
+ /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */
+
+ /* Interface information */
+ u32 SmsToHostTxErrors; /* Total number of transmission errors. */
+};
+
struct PID_STATISTICS_DATA_S {
struct PID_BURST_S {
u32 size;
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
index 68bf9fbd8fed..5f3939821ca3 100644
--- a/drivers/media/dvb/siano/smsdvb.c
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -116,6 +116,118 @@ static void sms_board_dvb3_event(struct smsdvb_client_t *client,
}
}
+
+static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
+ struct SMSHOSTLIB_STATISTICS_ST *p)
+{
+ if (sms_dbg & 2) {
+ printk(KERN_DEBUG "Reserved = %d", p->Reserved);
+ printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
+ printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
+ printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
+ printk(KERN_DEBUG "SNR = %d", p->SNR);
+ printk(KERN_DEBUG "BER = %d", p->BER);
+ printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
+ printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
+ printk(KERN_DEBUG "MFER = %d", p->MFER);
+ printk(KERN_DEBUG "RSSI = %d", p->RSSI);
+ printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
+ printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
+ printk(KERN_DEBUG "Frequency = %d", p->Frequency);
+ printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
+ printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
+ printk(KERN_DEBUG "ModemState = %d", p->ModemState);
+ printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
+ printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
+ printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
+ printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
+ printk(KERN_DEBUG "Constellation = %d", p->Constellation);
+ printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
+ printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
+ printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
+ printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
+ printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
+ printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
+ printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
+ printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
+ printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
+ printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
+ printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
+ printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
+ printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
+ printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
+ printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
+ printk(KERN_DEBUG "PreBER = %d", p->PreBER);
+ printk(KERN_DEBUG "CellId = %d", p->CellId);
+ printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
+ printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
+ printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
+ }
+
+ pReceptionData->IsDemodLocked = p->IsDemodLocked;
+
+ pReceptionData->SNR = p->SNR;
+ pReceptionData->BER = p->BER;
+ pReceptionData->BERErrorCount = p->BERErrorCount;
+ pReceptionData->InBandPwr = p->InBandPwr;
+ pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
+};
+
+
+static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
+ struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
+{
+ int i;
+
+ if (sms_dbg & 2) {
+ printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
+ printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
+ printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
+ printk(KERN_DEBUG "SNR = %d", p->SNR);
+ printk(KERN_DEBUG "RSSI = %d", p->RSSI);
+ printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
+ printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
+ printk(KERN_DEBUG "Frequency = %d", p->Frequency);
+ printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
+ printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
+ printk(KERN_DEBUG "ModemState = %d", p->ModemState);
+ printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
+ printk(KERN_DEBUG "SystemType = %d", p->SystemType);
+ printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
+ printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
+ printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
+
+ for (i = 0; i < 3; i++) {
+ printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
+ printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
+ printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
+ printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
+ printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
+ printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
+ printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
+ printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
+ printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
+ printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
+ printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
+ printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
+ }
+ }
+
+ pReceptionData->IsDemodLocked = p->IsDemodLocked;
+
+ pReceptionData->SNR = p->SNR;
+ pReceptionData->InBandPwr = p->InBandPwr;
+
+ pReceptionData->ErrorTSPackets = 0;
+ pReceptionData->BER = 0;
+ pReceptionData->BERErrorCount = 0;
+ for (i = 0; i < 3; i++) {
+ pReceptionData->BER += p->LayerInfo[i].BER;
+ pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
+ pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
+ }
+}
+
static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
{
struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
@@ -134,6 +246,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
break;
case MSG_SMS_RF_TUNE_RES:
+ case MSG_SMS_ISDBT_TUNE_RES:
complete(&client->tune_done);
break;
@@ -217,6 +330,40 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
is_status_update = true;
break;
}
+ case MSG_SMS_GET_STATISTICS_RES: {
+ union {
+ struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt;
+ struct SmsMsgStatisticsInfo_ST dvb;
+ } *p = (void *) (phdr + 1);
+ struct RECEPTION_STATISTICS_S *pReceptionData =
+ &client->sms_stat_dvb.ReceptionData;
+
+ sms_info("MSG_SMS_GET_STATISTICS_RES");
+
+ is_status_update = true;
+
+ switch (smscore_get_device_mode(client->coredev)) {
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
+ break;
+ default:
+ smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
+ }
+ if (!pReceptionData->IsDemodLocked) {
+ pReceptionData->SNR = 0;
+ pReceptionData->BER = 0;
+ pReceptionData->BERErrorCount = 0;
+ pReceptionData->InBandPwr = 0;
+ pReceptionData->ErrorTSPackets = 0;
+ }
+
+ complete(&client->tune_done);
+ break;
+ }
+ default:
+ sms_info("Unhandled message %d", phdr->msgType);
+
}
smscore_putbuffer(client->coredev, cb);
@@ -233,10 +380,10 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
DVB3_EVENT_UNC_ERR);
} else {
- /*client->fe_status =
- (phdr->msgType == MSG_SMS_NO_SIGNAL_IND) ?
- 0 : FE_HAS_SIGNAL;*/
- client->fe_status = 0;
+ if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
+ client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
+ else
+ client->fe_status = 0;
sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
}
}
@@ -325,6 +472,20 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
0 : -ETIME;
}
+static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
+{
+ int rc;
+ struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
+ DVBT_BDA_CONTROL_MSG_ID,
+ HIF_TASK,
+ sizeof(struct SmsMsgHdr_ST), 0 };
+
+ rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+ &client->tune_done);
+
+ return rc;
+}
+
static inline int led_feedback(struct smsdvb_client_t *client)
{
if (client->fe_status & FE_HAS_LOCK)
@@ -337,33 +498,43 @@ static inline int led_feedback(struct smsdvb_client_t *client)
static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
{
+ int rc;
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
+ rc = smsdvb_send_statistics_request(client);
+
*stat = client->fe_status;
led_feedback(client);
- return 0;
+ return rc;
}
static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
{
+ int rc;
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
+ rc = smsdvb_send_statistics_request(client);
+
*ber = client->sms_stat_dvb.ReceptionData.BER;
led_feedback(client);
- return 0;
+ return rc;
}
static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
+ int rc;
+
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
+ rc = smsdvb_send_statistics_request(client);
+
if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
*strength = 0;
else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
@@ -375,31 +546,37 @@ static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
led_feedback(client);
- return 0;
+ return rc;
}
static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
{
+ int rc;
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
+ rc = smsdvb_send_statistics_request(client);
+
*snr = client->sms_stat_dvb.ReceptionData.SNR;
led_feedback(client);
- return 0;
+ return rc;
}
static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
+ int rc;
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
+ rc = smsdvb_send_statistics_request(client);
+
*ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
led_feedback(client);
- return 0;
+ return rc;
}
static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
@@ -413,9 +590,10 @@ static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
return 0;
}
-static int smsdvb_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
+static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
@@ -429,24 +607,33 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
client->fe_status = FE_HAS_SIGNAL;
client->event_fe_state = -1;
client->event_unc_state = -1;
+ fe->dtv_property_cache.delivery_system = SYS_DVBT;
Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
Msg.Msg.msgDstId = HIF_TASK;
Msg.Msg.msgFlags = 0;
Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
Msg.Msg.msgLength = sizeof(Msg);
- Msg.Data[0] = fep->frequency;
+ Msg.Data[0] = c->frequency;
Msg.Data[2] = 12000000;
- sms_debug("freq %d band %d",
- fep->frequency, fep->u.ofdm.bandwidth);
+ sms_info("%s: freq %d band %d", __func__, c->frequency,
+ c->bandwidth_hz);
- switch (fep->u.ofdm.bandwidth) {
- case BANDWIDTH_8_MHZ: Msg.Data[1] = BW_8_MHZ; break;
- case BANDWIDTH_7_MHZ: Msg.Data[1] = BW_7_MHZ; break;
- case BANDWIDTH_6_MHZ: Msg.Data[1] = BW_6_MHZ; break;
- case BANDWIDTH_AUTO: return -EOPNOTSUPP;
- default: return -EINVAL;
+ switch (c->bandwidth_hz / 1000000) {
+ case 8:
+ Msg.Data[1] = BW_8_MHZ;
+ break;
+ case 7:
+ Msg.Data[1] = BW_7_MHZ;
+ break;
+ case 6:
+ Msg.Data[1] = BW_6_MHZ;
+ break;
+ case 0:
+ return -EOPNOTSUPP;
+ default:
+ return -EINVAL;
}
/* Disable LNA, if any. An error is returned if no LNA is present */
ret = sms_board_lna_control(client->coredev, 0);
@@ -470,6 +657,90 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
&client->tune_done);
}
+static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+
+ struct {
+ struct SmsMsgHdr_ST Msg;
+ u32 Data[4];
+ } Msg;
+
+ fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+
+ Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+ Msg.Msg.msgDstId = HIF_TASK;
+ Msg.Msg.msgFlags = 0;
+ Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ;
+ Msg.Msg.msgLength = sizeof(Msg);
+
+ if (c->isdbt_sb_segment_idx == -1)
+ c->isdbt_sb_segment_idx = 0;
+
+ switch (c->isdbt_sb_segment_count) {
+ case 3:
+ Msg.Data[1] = BW_ISDBT_3SEG;
+ break;
+ case 1:
+ Msg.Data[1] = BW_ISDBT_1SEG;
+ break;
+ case 0: /* AUTO */
+ switch (c->bandwidth_hz / 1000000) {
+ case 8:
+ case 7:
+ c->isdbt_sb_segment_count = 3;
+ Msg.Data[1] = BW_ISDBT_3SEG;
+ break;
+ case 6:
+ c->isdbt_sb_segment_count = 1;
+ Msg.Data[1] = BW_ISDBT_1SEG;
+ break;
+ default: /* Assumes 6 MHZ bw */
+ c->isdbt_sb_segment_count = 1;
+ c->bandwidth_hz = 6000;
+ Msg.Data[1] = BW_ISDBT_1SEG;
+ break;
+ }
+ break;
+ default:
+ sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
+ return -EINVAL;
+ }
+
+ Msg.Data[0] = c->frequency;
+ Msg.Data[2] = 12000000;
+ Msg.Data[3] = c->isdbt_sb_segment_idx;
+
+ sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
+ c->frequency, c->isdbt_sb_segment_count,
+ c->isdbt_sb_segment_idx);
+
+ return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+ &client->tune_done);
+}
+
+static int smsdvb_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+ struct smscore_device_t *coredev = client->coredev;
+
+ switch (smscore_get_device_mode(coredev)) {
+ case DEVICE_MODE_DVBT:
+ case DEVICE_MODE_DVBT_BDA:
+ return smsdvb_dvbt_set_frontend(fe, fep);
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ return smsdvb_isdbt_set_frontend(fe, fep);
+ default:
+ return -EINVAL;
+ }
+}
+
static int smsdvb_get_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *fep)
{
@@ -557,13 +828,6 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
/* device removal handled by onremove callback */
if (!arrival)
return 0;
-
- if (smscore_get_device_mode(coredev) != DEVICE_MODE_DVBT_BDA) {
- sms_err("SMS Device mode is not set for "
- "DVB operation.");
- return 0;
- }
-
client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
if (!client) {
sms_err("kmalloc() failed");
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
index e3d776feeaca..a56eac76e0f0 100644
--- a/drivers/media/dvb/siano/smsir.c
+++ b/drivers/media/dvb/siano/smsir.c
@@ -85,9 +85,9 @@ static struct keyboard_layout_map_t keyboard_layout_maps[] = {
{ } /* Terminating entry */
};
-u32 ir_pos;
-u32 ir_word;
-u32 ir_toggle;
+static u32 ir_pos;
+static u32 ir_word;
+static u32 ir_toggle;
#define RC5_PUSH_BIT(dst, bit, pos) \
{ dst <<= 1; dst |= bit; pos++; }
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index 23a1c6380d3f..b070e88d8c6b 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -268,8 +268,8 @@ int av7110_check_ir_config(struct av7110 *av7110, int force)
/* /proc/av7110_ir interface */
-static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *pos)
{
char *page;
u32 ir_config;
@@ -309,6 +309,10 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
return count;
}
+static const struct file_operations av7110_ir_proc_fops = {
+ .owner = THIS_MODULE,
+ .write = av7110_ir_proc_write,
+};
/* interrupt handler */
static void ir_handler(struct av7110 *av7110, u32 ircom)
@@ -368,11 +372,9 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
input_dev->timer.data = (unsigned long) &av7110->ir;
if (av_cnt == 1) {
- e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL);
- if (e) {
- e->write_proc = av7110_ir_write_proc;
+ e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops);
+ if (e)
e->size = 4 + 256 * sizeof(u16);
- }
}
tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir);
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 9782e0593733..49c2a817a06f 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -254,7 +254,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
budget_ci->ir.timer_keyup.function = msp430_ir_keyup;
budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir;
budget_ci->ir.last_raw = 0xffff; /* An impossible value */
- error = ir_input_register(input_dev, ir_codes);
+ error = ir_input_register(input_dev, ir_codes, NULL);
if (error) {
printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
return error;
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index e48380c48990..9fdf26cc6998 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -433,9 +433,8 @@ static struct stv090x_config tt1600_stv090x_config = {
.demod_mode = STV090x_SINGLE,
.clk_mode = STV090x_CLK_EXT,
- .xtal = 27000000,
+ .xtal = 13500000,
.address = 0x68,
- .ref_clk = 27000000,
.ts1_mode = STV090x_TSMODE_DVBCI,
.ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS,
@@ -457,6 +456,7 @@ static struct stv090x_config tt1600_stv090x_config = {
static struct stv6110x_config tt1600_stv6110x_config = {
.addr = 0x60,
.refclk = 27000000,
+ .clk_div = 2,
};
static struct isl6423_config tt1600_isl6423_config = {
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 3f40f375981b..83567b898d09 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -417,6 +417,18 @@ config RADIO_TEA5764_XTAL
Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N
here if TEA5764 reference frequency is connected in FREQIN.
+config RADIO_SAA7706H
+ tristate "SAA7706H Car Radio DSP"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ Say Y here if you want to use the SAA7706H Car radio Digital
+ Signal Processor, found for instance on the Russellville development
+ board. On the russellville the device is connected to internal
+ timberdale I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called SAA7706H.
+
config RADIO_TEF6862
tristate "TEF6862 Car Radio Enhanced Selectivity Tuner"
depends on I2C && VIDEO_V4L2
@@ -429,4 +441,15 @@ config RADIO_TEF6862
To compile this driver as a module, choose M here: the
module will be called TEF6862.
+config RADIO_TIMBERDALE
+ tristate "Enable the Timberdale radio driver"
+ depends on MFD_TIMBERDALE && VIDEO_V4L2
+ depends on I2C # for RADIO_SAA7706H
+ select RADIO_TEF6862
+ select RADIO_SAA7706H
+ ---help---
+ This is a kind of umbrella driver for the Radio Tuner and DSP
+ found behind the Timberdale FPGA on the Russellville board.
+ Enabling this driver will automatically select the DSP and tuner.
+
endif # RADIO_ADAPTERS
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index 01922ada6914..f615583b4837 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -23,6 +23,8 @@ obj-$(CONFIG_USB_DSBR) += dsbr100.o
obj-$(CONFIG_RADIO_SI470X) += si470x/
obj-$(CONFIG_USB_MR800) += radio-mr800.o
obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
+obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
+obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
new file mode 100644
index 000000000000..0de457f6e6eb
--- /dev/null
+++ b/drivers/media/radio/radio-timb.c
@@ -0,0 +1,244 @@
+/*
+ * radio-timb.c Timberdale FPGA Radio driver
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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/version.h>
+#include <linux/io.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <media/timb_radio.h>
+
+#define DRIVER_NAME "timb-radio"
+
+struct timbradio {
+ struct timb_radio_platform_data pdata;
+ struct v4l2_subdev *sd_tuner;
+ struct v4l2_subdev *sd_dsp;
+ struct video_device video_dev;
+ struct v4l2_device v4l2_dev;
+};
+
+
+static int timbradio_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+{
+ strlcpy(v->driver, DRIVER_NAME, sizeof(v->driver));
+ strlcpy(v->card, "Timberdale Radio", sizeof(v->card));
+ snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME);
+ v->version = KERNEL_VERSION(0, 0, 1);
+ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+}
+
+static int timbradio_vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ struct timbradio *tr = video_drvdata(file);
+ return v4l2_subdev_call(tr->sd_tuner, tuner, g_tuner, v);
+}
+
+static int timbradio_vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ struct timbradio *tr = video_drvdata(file);
+ return v4l2_subdev_call(tr->sd_tuner, tuner, s_tuner, v);
+}
+
+static int timbradio_vidioc_g_input(struct file *filp, void *priv,
+ unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int timbradio_vidioc_s_input(struct file *filp, void *priv,
+ unsigned int i)
+{
+ return i ? -EINVAL : 0;
+}
+
+static int timbradio_vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ a->index = 0;
+ strlcpy(a->name, "Radio", sizeof(a->name));
+ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+}
+
+static int timbradio_vidioc_s_audio(struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ return a->index ? -EINVAL : 0;
+}
+
+static int timbradio_vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct timbradio *tr = video_drvdata(file);
+ return v4l2_subdev_call(tr->sd_tuner, tuner, s_frequency, f);
+}
+
+static int timbradio_vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct timbradio *tr = video_drvdata(file);
+ return v4l2_subdev_call(tr->sd_tuner, tuner, g_frequency, f);
+}
+
+static int timbradio_vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct timbradio *tr = video_drvdata(file);
+ return v4l2_subdev_call(tr->sd_dsp, core, queryctrl, qc);
+}
+
+static int timbradio_vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct timbradio *tr = video_drvdata(file);
+ return v4l2_subdev_call(tr->sd_dsp, core, g_ctrl, ctrl);
+}
+
+static int timbradio_vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct timbradio *tr = video_drvdata(file);
+ return v4l2_subdev_call(tr->sd_dsp, core, s_ctrl, ctrl);
+}
+
+static const struct v4l2_ioctl_ops timbradio_ioctl_ops = {
+ .vidioc_querycap = timbradio_vidioc_querycap,
+ .vidioc_g_tuner = timbradio_vidioc_g_tuner,
+ .vidioc_s_tuner = timbradio_vidioc_s_tuner,
+ .vidioc_g_frequency = timbradio_vidioc_g_frequency,
+ .vidioc_s_frequency = timbradio_vidioc_s_frequency,
+ .vidioc_g_input = timbradio_vidioc_g_input,
+ .vidioc_s_input = timbradio_vidioc_s_input,
+ .vidioc_g_audio = timbradio_vidioc_g_audio,
+ .vidioc_s_audio = timbradio_vidioc_s_audio,
+ .vidioc_queryctrl = timbradio_vidioc_queryctrl,
+ .vidioc_g_ctrl = timbradio_vidioc_g_ctrl,
+ .vidioc_s_ctrl = timbradio_vidioc_s_ctrl
+};
+
+static const struct v4l2_file_operations timbradio_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = video_ioctl2,
+};
+
+static int __devinit timbradio_probe(struct platform_device *pdev)
+{
+ struct timb_radio_platform_data *pdata = pdev->dev.platform_data;
+ struct timbradio *tr;
+ int err;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "Platform data missing\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ tr = kzalloc(sizeof(*tr), GFP_KERNEL);
+ if (!tr) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ tr->pdata = *pdata;
+
+ strlcpy(tr->video_dev.name, "Timberdale Radio",
+ sizeof(tr->video_dev.name));
+ tr->video_dev.fops = &timbradio_fops;
+ tr->video_dev.ioctl_ops = &timbradio_ioctl_ops;
+ tr->video_dev.release = video_device_release_empty;
+ tr->video_dev.minor = -1;
+
+ strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
+ err = v4l2_device_register(NULL, &tr->v4l2_dev);
+ if (err)
+ goto err_v4l2_dev;
+
+ tr->video_dev.v4l2_dev = &tr->v4l2_dev;
+
+ err = video_register_device(&tr->video_dev, VFL_TYPE_RADIO, -1);
+ if (err) {
+ dev_err(&pdev->dev, "Error reg video\n");
+ goto err_video_req;
+ }
+
+ video_set_drvdata(&tr->video_dev, tr);
+
+ platform_set_drvdata(pdev, tr);
+ return 0;
+
+err_video_req:
+ video_device_release_empty(&tr->video_dev);
+ v4l2_device_unregister(&tr->v4l2_dev);
+err_v4l2_dev:
+ kfree(tr);
+err:
+ dev_err(&pdev->dev, "Failed to register: %d\n", err);
+
+ return err;
+}
+
+static int __devexit timbradio_remove(struct platform_device *pdev)
+{
+ struct timbradio *tr = platform_get_drvdata(pdev);
+
+ video_unregister_device(&tr->video_dev);
+ video_device_release_empty(&tr->video_dev);
+
+ v4l2_device_unregister(&tr->v4l2_dev);
+
+ kfree(tr);
+
+ return 0;
+}
+
+static struct platform_driver timbradio_platform_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = timbradio_probe,
+ .remove = timbradio_remove,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init timbradio_init(void)
+{
+ return platform_driver_register(&timbradio_platform_driver);
+}
+
+static void __exit timbradio_exit(void)
+{
+ platform_driver_unregister(&timbradio_platform_driver);
+}
+
+module_init(timbradio_init);
+module_exit(timbradio_exit);
+
+MODULE_DESCRIPTION("Timberdale Radio driver");
+MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:"DRIVER_NAME);
diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c
new file mode 100644
index 000000000000..5db5528a8b25
--- /dev/null
+++ b/drivers/media/radio/saa7706h.c
@@ -0,0 +1,451 @@
+/*
+ * saa7706.c Philips SAA7706H Car Radio DSP driver
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+#define DRIVER_NAME "saa7706h"
+
+/* the I2C memory map looks like this
+
+ $1C00 - $FFFF Not Used
+ $2200 - $3FFF Reserved YRAM (DSP2) space
+ $2000 - $21FF YRAM (DSP2)
+ $1FF0 - $1FFF Hardware Registers
+ $1280 - $1FEF Reserved XRAM (DSP2) space
+ $1000 - $127F XRAM (DSP2)
+ $0FFF DSP CONTROL
+ $0A00 - $0FFE Reserved
+ $0980 - $09FF Reserved YRAM (DSP1) space
+ $0800 - $097F YRAM (DSP1)
+ $0200 - $07FF Not Used
+ $0180 - $01FF Reserved XRAM (DSP1) space
+ $0000 - $017F XRAM (DSP1)
+*/
+
+#define SAA7706H_REG_CTRL 0x0fff
+#define SAA7706H_CTRL_BYP_PLL 0x0001
+#define SAA7706H_CTRL_PLL_DIV_MASK 0x003e
+#define SAA7706H_CTRL_PLL3_62975MHZ 0x003e
+#define SAA7706H_CTRL_DSP_TURBO 0x0040
+#define SAA7706H_CTRL_PC_RESET_DSP1 0x0080
+#define SAA7706H_CTRL_PC_RESET_DSP2 0x0100
+#define SAA7706H_CTRL_DSP1_ROM_EN_MASK 0x0600
+#define SAA7706H_CTRL_DSP1_FUNC_PROM 0x0000
+#define SAA7706H_CTRL_DSP2_ROM_EN_MASK 0x1800
+#define SAA7706H_CTRL_DSP2_FUNC_PROM 0x0000
+#define SAA7706H_CTRL_DIG_SIL_INTERPOL 0x8000
+
+#define SAA7706H_REG_EVALUATION 0x1ff0
+#define SAA7706H_EVAL_DISABLE_CHARGE_PUMP 0x000001
+#define SAA7706H_EVAL_DCS_CLOCK 0x000002
+#define SAA7706H_EVAL_GNDRC1_ENABLE 0x000004
+#define SAA7706H_EVAL_GNDRC2_ENABLE 0x000008
+
+#define SAA7706H_REG_CL_GEN1 0x1ff3
+#define SAA7706H_CL_GEN1_MIN_LOOPGAIN_MASK 0x00000f
+#define SAA7706H_CL_GEN1_LOOPGAIN_MASK 0x0000f0
+#define SAA7706H_CL_GEN1_COARSE_RATION 0xffff00
+
+#define SAA7706H_REG_CL_GEN2 0x1ff4
+#define SAA7706H_CL_GEN2_WSEDGE_FALLING 0x000001
+#define SAA7706H_CL_GEN2_STOP_VCO 0x000002
+#define SAA7706H_CL_GEN2_FRERUN 0x000004
+#define SAA7706H_CL_GEN2_ADAPTIVE 0x000008
+#define SAA7706H_CL_GEN2_FINE_RATIO_MASK 0x0ffff0
+
+#define SAA7706H_REG_CL_GEN4 0x1ff6
+#define SAA7706H_CL_GEN4_BYPASS_PLL1 0x001000
+#define SAA7706H_CL_GEN4_PLL1_DIV_MASK 0x03e000
+#define SAA7706H_CL_GEN4_DSP1_TURBO 0x040000
+
+#define SAA7706H_REG_SEL 0x1ff7
+#define SAA7706H_SEL_DSP2_SRCA_MASK 0x000007
+#define SAA7706H_SEL_DSP2_FMTA_MASK 0x000031
+#define SAA7706H_SEL_DSP2_SRCB_MASK 0x0001c0
+#define SAA7706H_SEL_DSP2_FMTB_MASK 0x000e00
+#define SAA7706H_SEL_DSP1_SRC_MASK 0x003000
+#define SAA7706H_SEL_DSP1_FMT_MASK 0x01c003
+#define SAA7706H_SEL_SPDIF2 0x020000
+#define SAA7706H_SEL_HOST_IO_FMT_MASK 0x1c0000
+#define SAA7706H_SEL_EN_HOST_IO 0x200000
+
+#define SAA7706H_REG_IAC 0x1ff8
+#define SAA7706H_REG_CLK_SET 0x1ff9
+#define SAA7706H_REG_CLK_COEFF 0x1ffa
+#define SAA7706H_REG_INPUT_SENS 0x1ffb
+#define SAA7706H_INPUT_SENS_RDS_VOL_MASK 0x0003f
+#define SAA7706H_INPUT_SENS_FM_VOL_MASK 0x00fc0
+#define SAA7706H_INPUT_SENS_FM_MPX 0x01000
+#define SAA7706H_INPUT_SENS_OFF_FILTER_A_EN 0x02000
+#define SAA7706H_INPUT_SENS_OFF_FILTER_B_EN 0x04000
+#define SAA7706H_REG_PHONE_NAV_AUDIO 0x1ffc
+#define SAA7706H_REG_IO_CONF_DSP2 0x1ffd
+#define SAA7706H_REG_STATUS_DSP2 0x1ffe
+#define SAA7706H_REG_PC_DSP2 0x1fff
+
+#define SAA7706H_DSP1_MOD0 0x0800
+#define SAA7706H_DSP1_ROM_VER 0x097f
+#define SAA7706H_DSP2_MPTR0 0x1000
+
+#define SAA7706H_DSP1_MODPNTR 0x0000
+
+#define SAA7706H_DSP2_XMEM_CONTLLCW 0x113e
+#define SAA7706H_DSP2_XMEM_BUSAMP 0x114a
+#define SAA7706H_DSP2_XMEM_FDACPNTR 0x11f9
+#define SAA7706H_DSP2_XMEM_IIS1PNTR 0x11fb
+
+#define SAA7706H_DSP2_YMEM_PVGA 0x212a
+#define SAA7706H_DSP2_YMEM_PVAT1 0x212b
+#define SAA7706H_DSP2_YMEM_PVAT 0x212c
+#define SAA7706H_DSP2_YMEM_ROM_VER 0x21ff
+
+#define SUPPORTED_DSP1_ROM_VER 0x667
+
+struct saa7706h_state {
+ struct v4l2_subdev sd;
+ unsigned muted;
+};
+
+static inline struct saa7706h_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct saa7706h_state, sd);
+}
+
+static int saa7706h_i2c_send(struct i2c_client *client, const u8 *data, int len)
+{
+ int err = i2c_master_send(client, data, len);
+ if (err == len)
+ return 0;
+ return err > 0 ? -EIO : err;
+}
+
+static int saa7706h_i2c_transfer(struct i2c_client *client,
+ struct i2c_msg *msgs, int num)
+{
+ int err = i2c_transfer(client->adapter, msgs, num);
+ if (err == num)
+ return 0;
+ return err > 0 ? -EIO : err;
+}
+
+static int saa7706h_set_reg24(struct v4l2_subdev *sd, u16 reg, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 buf[5];
+ int pos = 0;
+
+ buf[pos++] = reg >> 8;
+ buf[pos++] = reg;
+ buf[pos++] = val >> 16;
+ buf[pos++] = val >> 8;
+ buf[pos++] = val;
+
+ return saa7706h_i2c_send(client, buf, pos);
+}
+
+static int saa7706h_set_reg24_err(struct v4l2_subdev *sd, u16 reg, u32 val,
+ int *err)
+{
+ return *err ? *err : saa7706h_set_reg24(sd, reg, val);
+}
+
+static int saa7706h_set_reg16(struct v4l2_subdev *sd, u16 reg, u16 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 buf[4];
+ int pos = 0;
+
+ buf[pos++] = reg >> 8;
+ buf[pos++] = reg;
+ buf[pos++] = val >> 8;
+ buf[pos++] = val;
+
+ return saa7706h_i2c_send(client, buf, pos);
+}
+
+static int saa7706h_set_reg16_err(struct v4l2_subdev *sd, u16 reg, u16 val,
+ int *err)
+{
+ return *err ? *err : saa7706h_set_reg16(sd, reg, val);
+}
+
+static int saa7706h_get_reg16(struct v4l2_subdev *sd, u16 reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 buf[2];
+ int err;
+ u8 regaddr[] = {reg >> 8, reg};
+ struct i2c_msg msg[] = { {client->addr, 0, sizeof(regaddr), regaddr},
+ {client->addr, I2C_M_RD, sizeof(buf), buf} };
+
+ err = saa7706h_i2c_transfer(client, msg, ARRAY_SIZE(msg));
+ if (err)
+ return err;
+
+ return buf[0] << 8 | buf[1];
+}
+
+static int saa7706h_unmute(struct v4l2_subdev *sd)
+{
+ struct saa7706h_state *state = to_state(sd);
+ int err = 0;
+
+ err = saa7706h_set_reg16_err(sd, SAA7706H_REG_CTRL,
+ SAA7706H_CTRL_PLL3_62975MHZ | SAA7706H_CTRL_PC_RESET_DSP1 |
+ SAA7706H_CTRL_PC_RESET_DSP2, &err);
+
+ /* newer versions of the chip requires a small sleep after reset */
+ msleep(1);
+
+ err = saa7706h_set_reg16_err(sd, SAA7706H_REG_CTRL,
+ SAA7706H_CTRL_PLL3_62975MHZ, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_REG_EVALUATION, 0, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CL_GEN1, 0x040022, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CL_GEN2,
+ SAA7706H_CL_GEN2_WSEDGE_FALLING, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CL_GEN4, 0x024080, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_REG_SEL, 0x200080, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_REG_IAC, 0xf4caed, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CLK_SET, 0x124334, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CLK_COEFF, 0x004a1a,
+ &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_REG_INPUT_SENS, 0x0071c7,
+ &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_REG_PHONE_NAV_AUDIO,
+ 0x0e22ff, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_REG_IO_CONF_DSP2, 0x001ff8,
+ &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_REG_STATUS_DSP2, 0x080003,
+ &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_REG_PC_DSP2, 0x000004, &err);
+
+ err = saa7706h_set_reg16_err(sd, SAA7706H_DSP1_MOD0, 0x0c6c, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_MPTR0, 0x000b4b, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_DSP1_MODPNTR, 0x000600, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_DSP1_MODPNTR, 0x0000c0, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_CONTLLCW, 0x000819,
+ &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_CONTLLCW, 0x00085a,
+ &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_BUSAMP, 0x7fffff,
+ &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_FDACPNTR, 0x2000cb,
+ &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_IIS1PNTR, 0x2000cb,
+ &err);
+
+ err = saa7706h_set_reg16_err(sd, SAA7706H_DSP2_YMEM_PVGA, 0x0f80, &err);
+
+ err = saa7706h_set_reg16_err(sd, SAA7706H_DSP2_YMEM_PVAT1, 0x0800,
+ &err);
+
+ err = saa7706h_set_reg16_err(sd, SAA7706H_DSP2_YMEM_PVAT, 0x0800, &err);
+
+ err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_CONTLLCW, 0x000905,
+ &err);
+ if (!err)
+ state->muted = 0;
+ return err;
+}
+
+static int saa7706h_mute(struct v4l2_subdev *sd)
+{
+ struct saa7706h_state *state = to_state(sd);
+ int err;
+
+ err = saa7706h_set_reg16(sd, SAA7706H_REG_CTRL,
+ SAA7706H_CTRL_PLL3_62975MHZ | SAA7706H_CTRL_PC_RESET_DSP1 |
+ SAA7706H_CTRL_PC_RESET_DSP2);
+ if (!err)
+ state->muted = 1;
+ return err;
+}
+
+static int saa7706h_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+ }
+ return -EINVAL;
+}
+
+static int saa7706h_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct saa7706h_state *state = to_state(sd);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = state->muted;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int saa7706h_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value)
+ return saa7706h_mute(sd);
+ return saa7706h_unmute(sd);
+ }
+ return -EINVAL;
+}
+
+static int saa7706h_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7706H, 0);
+}
+
+static const struct v4l2_subdev_core_ops saa7706h_core_ops = {
+ .g_chip_ident = saa7706h_g_chip_ident,
+ .queryctrl = saa7706h_queryctrl,
+ .g_ctrl = saa7706h_g_ctrl,
+ .s_ctrl = saa7706h_s_ctrl,
+};
+
+static const struct v4l2_subdev_ops saa7706h_ops = {
+ .core = &saa7706h_core_ops,
+};
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static int __devinit saa7706h_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct saa7706h_state *state;
+ struct v4l2_subdev *sd;
+ int err;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
+ state = kmalloc(sizeof(struct saa7706h_state), GFP_KERNEL);
+ if (state == NULL)
+ return -ENOMEM;
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &saa7706h_ops);
+
+ /* check the rom versions */
+ err = saa7706h_get_reg16(sd, SAA7706H_DSP1_ROM_VER);
+ if (err < 0)
+ goto err;
+ if (err != SUPPORTED_DSP1_ROM_VER)
+ v4l2_warn(sd, "Unknown DSP1 ROM code version: 0x%x\n", err);
+
+ state->muted = 1;
+
+ /* startup in a muted state */
+ err = saa7706h_mute(sd);
+ if (err)
+ goto err;
+
+ return 0;
+
+err:
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
+
+ printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", err);
+
+ return err;
+}
+
+static int __devexit saa7706h_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ saa7706h_mute(sd);
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
+ return 0;
+}
+
+static const struct i2c_device_id saa7706h_id[] = {
+ {DRIVER_NAME, 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, saa7706h_id);
+
+static struct i2c_driver saa7706h_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+ .probe = saa7706h_probe,
+ .remove = saa7706h_remove,
+ .id_table = saa7706h_id,
+};
+
+static __init int saa7706h_init(void)
+{
+ return i2c_add_driver(&saa7706h_driver);
+}
+
+static __exit void saa7706h_exit(void)
+{
+ i2c_del_driver(&saa7706h_driver);
+}
+
+module_init(saa7706h_init);
+module_exit(saa7706h_exit);
+
+MODULE_DESCRIPTION("SAA7706H Car Radio DSP driver");
+MODULE_AUTHOR("Mocean Laboratories");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 4da0f150c6e2..47075fc71f11 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -724,7 +724,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
tuner->audmode = V4L2_TUNER_MODE_MONO;
/* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
- /* measured in units of db쨉V in 1 db increments (max at ~75 db쨉V) */
+ /* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */
tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
/* the ideal factor is 0xffff/75 = 873,8 */
tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index a96e1b9dd646..6f60841828da 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -590,8 +590,9 @@ int si470x_fops_release(struct file *file)
video_unregister_device(radio->videodev);
kfree(radio->int_in_buffer);
kfree(radio->buffer);
+ mutex_unlock(&radio->disconnect_lock);
kfree(radio);
- goto unlock;
+ goto done;
}
/* cancel read processes */
@@ -601,7 +602,6 @@ int si470x_fops_release(struct file *file)
retval = si470x_stop(radio);
usb_autopm_put_interface(radio->intf);
}
-unlock:
mutex_unlock(&radio->disconnect_lock);
done:
return retval;
@@ -842,9 +842,11 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
kfree(radio->int_in_buffer);
video_unregister_device(radio->videodev);
kfree(radio->buffer);
+ mutex_unlock(&radio->disconnect_lock);
kfree(radio);
+ } else {
+ mutex_unlock(&radio->disconnect_lock);
}
- mutex_unlock(&radio->disconnect_lock);
}
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 2f83be766d9f..f8fc8654693d 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -388,6 +388,15 @@ config VIDEO_TVP5150
To compile this driver as a module, choose M here: the
module will be called tvp5150.
+config VIDEO_TVP7002
+ tristate "Texas Instruments TVP7002 video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Texas Instruments TVP7002 video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tvp7002.
+
config VIDEO_VPX3220
tristate "vpx3220a, vpx3216b & vpx3214c video decoders"
depends on VIDEO_V4L2 && I2C
@@ -548,7 +557,6 @@ config VIDEO_VPSS_SYSTEM
depends on ARCH_DAVINCI
help
Support for vpss system module for video driver
- default y
config VIDEO_VPFE_CAPTURE
tristate "VPFE Video Capture Driver"
@@ -592,6 +600,19 @@ config VIDEO_DM355_CCDC
To compile this driver as a module, choose M here: the
module will be called vpfe.
+config VIDEO_ISIF
+ tristate "ISIF HW module"
+ depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables ISIF hw module. This is the hardware module for
+ configuring ISIF in VPFE to capture Raw Bayer RGB data from
+ a image sensor or YUV data from a YUV source.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
+
source "drivers/media/video/bt8xx/Kconfig"
config VIDEO_PMS
@@ -638,9 +659,14 @@ config VIDEO_W9966
information.
config VIDEO_CPIA
- tristate "CPiA Video For Linux"
+ tristate "CPiA Video For Linux (DEPRECATED)"
depends on VIDEO_V4L1
+ default n
---help---
+ This driver is DEPRECATED please use the gspca cpia1 module
+ instead. Note that you need atleast version 0.6.4 of libv4l for
+ the cpia1 gspca module.
+
This is the video4linux driver for cameras based on Vision's CPiA
(Colour Processor Interface ASIC), such as the Creative Labs Video
Blaster Webcam II. If you have one of these cameras, say Y here
@@ -944,6 +970,8 @@ source "drivers/media/video/hdpvr/Kconfig"
source "drivers/media/video/em28xx/Kconfig"
+source "drivers/media/video/tlg2300/Kconfig"
+
source "drivers/media/video/cx231xx/Kconfig"
source "drivers/media/video/usbvision/Kconfig"
@@ -955,6 +983,7 @@ source "drivers/media/video/et61x251/Kconfig"
config VIDEO_OVCAMCHIP
tristate "OmniVision Camera Chip support (DEPRECATED)"
depends on I2C && VIDEO_V4L1
+ default n
---help---
This driver is DEPRECATED please use the gspca ov519 module
instead. Note that for the ov511 / ov518 support of the gspca module
@@ -971,6 +1000,7 @@ config VIDEO_OVCAMCHIP
config USB_W9968CF
tristate "USB W996[87]CF JPEG Dual Mode Camera support (DEPRECATED)"
depends on VIDEO_V4L1 && I2C && VIDEO_OVCAMCHIP
+ default n
---help---
This driver is DEPRECATED please use the gspca ov519 module
instead. Note that for the w9968cf support of the gspca module
@@ -992,6 +1022,7 @@ config USB_W9968CF
config USB_OV511
tristate "USB OV511 Camera support (DEPRECATED)"
depends on VIDEO_V4L1
+ default n
---help---
This driver is DEPRECATED please use the gspca ov519 module
instead. Note that for the ov511 / ov518 support of the gspca module
@@ -1020,6 +1051,7 @@ source "drivers/media/video/sn9c102/Kconfig"
config USB_STV680
tristate "USB STV680 (Pencam) Camera support (DEPRECATED)"
depends on VIDEO_V4L1
+ default n
---help---
This driver is DEPRECATED please use the gspca stv0680 module
instead. Note that for the gspca stv0680 module you need
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 2af68ee84122..b88b6174a331 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
obj-$(CONFIG_VIDEO_VINO) += indycam.o
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
+obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
@@ -99,6 +100,7 @@ obj-$(CONFIG_VIDEO_MEYE) += meye.o
obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
+obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/
obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index 5bb0f9e71583..547e1a93c421 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -254,7 +254,7 @@ static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
v4l2_err(sd, "no notify found!\n");
if (std & V4L2_STD_NTSC) {
- v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
+ v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL);
bt819_setbit(decoder, 0x01, 0, 1);
bt819_setbit(decoder, 0x01, 1, 0);
bt819_setbit(decoder, 0x01, 5, 0);
@@ -263,7 +263,7 @@ static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
/* bt819_setbit(decoder, 0x1a, 5, 1); */
timing = &timing_data[1];
} else if (std & V4L2_STD_PAL) {
- v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
+ v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL);
bt819_setbit(decoder, 0x01, 0, 1);
bt819_setbit(decoder, 0x01, 1, 1);
bt819_setbit(decoder, 0x01, 5, 1);
@@ -288,7 +288,7 @@ static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
bt819_write(decoder, 0x08, (timing->hscale >> 8) & 0xff);
bt819_write(decoder, 0x09, timing->hscale & 0xff);
decoder->norm = std;
- v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, 0);
+ v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL);
return 0;
}
@@ -306,7 +306,7 @@ static int bt819_s_routing(struct v4l2_subdev *sd,
v4l2_err(sd, "no notify found!\n");
if (decoder->input != input) {
- v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, 0);
+ v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL);
decoder->input = input;
/* select mode */
if (decoder->input == 0) {
@@ -316,7 +316,7 @@ static int bt819_s_routing(struct v4l2_subdev *sd,
bt819_setbit(decoder, 0x0b, 6, 1);
bt819_setbit(decoder, 0x1a, 1, 0);
}
- v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, 0);
+ v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL);
}
return 0;
}
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 12279f6d9bc4..716870ae85d5 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -4404,7 +4404,7 @@ static void rv605_muxsel(struct bttv *btv, unsigned int input)
/* Tibet Systems 'Progress DVR' CS16 muxsel helper [Chris Fanning]
*
* The CS16 (available on eBay cheap) is a PCI board with four Fusion
- * 878A chips, a PCI bridge, an Atmel microcontroller, four sync seperator
+ * 878A chips, a PCI bridge, an Atmel microcontroller, four sync separator
* chips, ten eight input analog multiplexors, a not chip and a few
* other components.
*
@@ -4426,7 +4426,7 @@ static void rv605_muxsel(struct bttv *btv, unsigned int input)
*
* There is an ATMEL microcontroller with an 8031 core on board. I have not
* determined what function (if any) it provides. With the microcontroller
- * and sync seperator chips a guess is that it might have to do with video
+ * and sync separator chips a guess is that it might have to do with video
* switching and maybe some digital I/O.
*/
static void tibetCS16_muxsel(struct bttv *btv, unsigned int input)
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 3182a406bdd1..cb46e8fa8aaa 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -81,6 +81,7 @@ static int video_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
static int radio_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
static int vbi_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
static int debug_latency;
+static int disable_ir;
static unsigned int fdsr;
@@ -107,6 +108,7 @@ module_param(bttv_gpio, int, 0644);
module_param(bttv_debug, int, 0644);
module_param(irq_debug, int, 0644);
module_param(debug_latency, int, 0644);
+module_param(disable_ir, int, 0444);
module_param(fdsr, int, 0444);
module_param(gbuffers, int, 0444);
@@ -139,6 +141,7 @@ MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
+MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default "
@@ -4461,7 +4464,10 @@ static int __devinit bttv_probe(struct pci_dev *dev,
request_modules(btv);
}
- bttv_input_init(btv);
+ if (!disable_ir) {
+ init_bttv_i2c_ir(btv);
+ bttv_input_init(btv);
+ }
/* everything is fine */
bttv_num++;
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 63aa31a041e8..407fa61e4cda 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -388,7 +388,12 @@ int __devinit init_bttv_i2c(struct bttv *btv)
if (0 == btv->i2c_rc && i2c_scan)
do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client);
- /* Instantiate the IR receiver device, if present */
+ return btv->i2c_rc;
+}
+
+/* Instantiate the I2C IR receiver device, if present */
+void __devinit init_bttv_i2c_ir(struct bttv *btv)
+{
if (0 == btv->i2c_rc) {
struct i2c_board_info info;
/* The external IR receiver is at i2c address 0x34 (0x35 for
@@ -408,7 +413,6 @@ int __devinit init_bttv_i2c(struct bttv *btv)
strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list);
}
- return btv->i2c_rc;
}
int __devexit fini_bttv_i2c(struct bttv *btv)
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 277a092e1214..b320dbd635aa 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -247,7 +247,7 @@ int bttv_input_init(struct bttv *btv)
struct card_ir *ir;
struct ir_scancode_table *ir_codes = NULL;
struct input_dev *input_dev;
- int ir_type = IR_TYPE_OTHER;
+ u64 ir_type = IR_TYPE_OTHER;
int err = -ENOMEM;
if (!btv->has_remote)
@@ -389,7 +389,7 @@ int bttv_input_init(struct bttv *btv)
bttv_ir_start(btv, ir);
/* all done */
- err = ir_input_register(btv->remote->dev, ir_codes);
+ err = ir_input_register(btv->remote->dev, ir_codes, NULL);
if (err)
goto err_out_stop;
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index a1d0e9c9f286..6cccc2a17eee 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -279,6 +279,7 @@ extern unsigned int bttv_debug;
extern unsigned int bttv_gpio;
extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
extern int init_bttv_i2c(struct bttv *btv);
+extern void init_bttv_i2c_ir(struct bttv *btv);
extern int fini_bttv_i2c(struct bttv *btv);
#define bttv_printk if (bttv_verbose) printk
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 7bb9c1ec7819..cbbf7e80d2cf 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -1907,7 +1907,6 @@ static int cafe_pci_probe(struct pci_dev *pdev,
goto out_free;
mutex_init(&cam->s_mutex);
- mutex_lock(&cam->s_mutex);
spin_lock_init(&cam->dev_lock);
cam->state = S_NOTREADY;
cafe_set_config_needed(cam, 1);
@@ -1947,7 +1946,6 @@ static int cafe_pci_probe(struct pci_dev *pdev,
* because the sensor could attach in this call chain, leading to
* unsightly deadlocks.
*/
- mutex_unlock(&cam->s_mutex); /* attach can deadlock */
ret = cafe_smbus_setup(cam);
if (ret)
goto out_freeirq;
@@ -1973,7 +1971,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
cam->vdev.v4l2_dev = &cam->v4l2_dev;
ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
if (ret)
- goto out_smbus;
+ goto out_unlock;
video_set_drvdata(&cam->vdev, cam);
/*
@@ -1988,6 +1986,8 @@ static int cafe_pci_probe(struct pci_dev *pdev,
mutex_unlock(&cam->s_mutex);
return 0;
+out_unlock:
+ mutex_unlock(&cam->s_mutex);
out_smbus:
cafe_smbus_shutdown(cam);
out_freeirq:
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 551ddf216a4b..933ae4c8cb9a 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -3737,9 +3737,6 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
return -EINVAL;
- if (!cam || !cam->ops)
- return -ENODEV;
-
/* make this _really_ smp-safe */
if (mutex_lock_interruptible(&cam->busy_lock))
return -EINTR;
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
index e8a50a611ebc..baf7e91ee0f5 100644
--- a/drivers/media/video/cx18/Kconfig
+++ b/drivers/media/video/cx18/Kconfig
@@ -19,3 +19,14 @@ config VIDEO_CX18
To compile this driver as a module, choose M here: the
module will be called cx18.
+
+config VIDEO_CX18_ALSA
+ tristate "Conexant 23418 DMA audio support"
+ depends on VIDEO_CX18 && SND && EXPERIMENTAL
+ select SND_PCM
+ ---help---
+ This is a video4linux driver for direct (DMA) audio on
+ Conexant 23418 based TV cards using ALSA.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx18-alsa.
diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile
index f7bf0edf93f9..2fadd9ded340 100644
--- a/drivers/media/video/cx18/Makefile
+++ b/drivers/media/video/cx18/Makefile
@@ -3,8 +3,10 @@ cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.
cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \
cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \
cx18-dvb.o cx18-io.o
+cx18-alsa-objs := cx18-alsa-main.o cx18-alsa-pcm.o
obj-$(CONFIG_VIDEO_CX18) += cx18.o
+obj-$(CONFIG_VIDEO_CX18_ALSA) += cx18-alsa.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/cx18/cx18-alsa-main.c b/drivers/media/video/cx18/cx18-alsa-main.c
new file mode 100644
index 000000000000..eb41d7ec65b9
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-alsa-main.c
@@ -0,0 +1,293 @@
+/*
+ * ALSA interface to cx18 PCM capture streams
+ *
+ * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * Portions of this work were sponsored by ONELAN Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+
+#include <media/v4l2-device.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+
+#include "cx18-driver.h"
+#include "cx18-version.h"
+#include "cx18-alsa.h"
+#include "cx18-alsa-mixer.h"
+#include "cx18-alsa-pcm.h"
+
+int cx18_alsa_debug;
+
+#define CX18_DEBUG_ALSA_INFO(fmt, arg...) \
+ do { \
+ if (cx18_alsa_debug & 2) \
+ printk(KERN_INFO "%s: " fmt, "cx18-alsa", ## arg); \
+ } while (0);
+
+module_param_named(debug, cx18_alsa_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+ "Debug level (bitmask). Default: 0\n"
+ "\t\t\t 1/0x0001: warning\n"
+ "\t\t\t 2/0x0002: info\n");
+
+MODULE_AUTHOR("Andy Walls");
+MODULE_DESCRIPTION("CX23418 ALSA Interface");
+MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder");
+MODULE_LICENSE("GPL");
+
+MODULE_VERSION(CX18_VERSION);
+
+static inline
+struct snd_cx18_card *to_snd_cx18_card(struct v4l2_device *v4l2_dev)
+{
+ return to_cx18(v4l2_dev)->alsa;
+}
+
+static inline
+struct snd_cx18_card *p_to_snd_cx18_card(struct v4l2_device **v4l2_dev)
+{
+ return container_of(v4l2_dev, struct snd_cx18_card, v4l2_dev);
+}
+
+static void snd_cx18_card_free(struct snd_cx18_card *cxsc)
+{
+ if (cxsc == NULL)
+ return;
+
+ if (cxsc->v4l2_dev != NULL)
+ to_cx18(cxsc->v4l2_dev)->alsa = NULL;
+
+ /* FIXME - take any other stopping actions needed */
+
+ kfree(cxsc);
+}
+
+static void snd_cx18_card_private_free(struct snd_card *sc)
+{
+ if (sc == NULL)
+ return;
+ snd_cx18_card_free(sc->private_data);
+ sc->private_data = NULL;
+ sc->private_free = NULL;
+}
+
+static int snd_cx18_card_create(struct v4l2_device *v4l2_dev,
+ struct snd_card *sc,
+ struct snd_cx18_card **cxsc)
+{
+ *cxsc = kzalloc(sizeof(struct snd_cx18_card), GFP_KERNEL);
+ if (*cxsc == NULL)
+ return -ENOMEM;
+
+ (*cxsc)->v4l2_dev = v4l2_dev;
+ (*cxsc)->sc = sc;
+
+ sc->private_data = *cxsc;
+ sc->private_free = snd_cx18_card_private_free;
+
+ return 0;
+}
+
+static int snd_cx18_card_set_names(struct snd_cx18_card *cxsc)
+{
+ struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
+ struct snd_card *sc = cxsc->sc;
+
+ /* sc->driver is used by alsa-lib's configurator: simple, unique */
+ strlcpy(sc->driver, "CX23418", sizeof(sc->driver));
+
+ /* sc->shortname is a symlink in /proc/asound: CX18-M -> cardN */
+ snprintf(sc->shortname, sizeof(sc->shortname), "CX18-%d",
+ cx->instance);
+
+ /* sc->longname is read from /proc/asound/cards */
+ snprintf(sc->longname, sizeof(sc->longname),
+ "CX23418 #%d %s TV/FM Radio/Line-In Capture",
+ cx->instance, cx->card_name);
+
+ return 0;
+}
+
+static int snd_cx18_init(struct v4l2_device *v4l2_dev)
+{
+ struct cx18 *cx = to_cx18(v4l2_dev);
+ struct snd_card *sc = NULL;
+ struct snd_cx18_card *cxsc;
+ int ret;
+
+ /* Numbrs steps from "Writing an ALSA Driver" by Takashi Iwai */
+
+ /* (1) Check and increment the device index */
+ /* This is a no-op for us. We'll use the cx->instance */
+
+ /* (2) Create a card instance */
+ ret = snd_card_create(SNDRV_DEFAULT_IDX1, /* use first available id */
+ SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
+ THIS_MODULE, 0, &sc);
+ if (ret) {
+ CX18_ALSA_ERR("%s: snd_card_create() failed with err %d\n",
+ __func__, ret);
+ goto err_exit;
+ }
+
+ /* (3) Create a main component */
+ ret = snd_cx18_card_create(v4l2_dev, sc, &cxsc);
+ if (ret) {
+ CX18_ALSA_ERR("%s: snd_cx18_card_create() failed with err %d\n",
+ __func__, ret);
+ goto err_exit_free;
+ }
+
+ /* (4) Set the driver ID and name strings */
+ snd_cx18_card_set_names(cxsc);
+
+
+ ret = snd_cx18_pcm_create(cxsc);
+ if (ret) {
+ CX18_ALSA_ERR("%s: snd_cx18_pcm_create() failed with err %d\n",
+ __func__, ret);
+ goto err_exit_free;
+ }
+ /* FIXME - proc files */
+
+ /* (7) Set the driver data and return 0 */
+ /* We do this out of normal order for PCI drivers to avoid races */
+ cx->alsa = cxsc;
+
+ /* (6) Register the card instance */
+ ret = snd_card_register(sc);
+ if (ret) {
+ cx->alsa = NULL;
+ CX18_ALSA_ERR("%s: snd_card_register() failed with err %d\n",
+ __func__, ret);
+ goto err_exit_free;
+ }
+
+ return 0;
+
+err_exit_free:
+ if (sc != NULL)
+ snd_card_free(sc);
+err_exit:
+ return ret;
+}
+
+int cx18_alsa_load(struct cx18 *cx)
+{
+ struct v4l2_device *v4l2_dev = &cx->v4l2_dev;
+ struct cx18_stream *s;
+
+ if (v4l2_dev == NULL) {
+ printk(KERN_ERR "cx18-alsa: %s: struct v4l2_device * is NULL\n",
+ __func__);
+ return 0;
+ }
+
+ cx = to_cx18(v4l2_dev);
+ if (cx == NULL) {
+ printk(KERN_ERR "cx18-alsa cx is NULL\n");
+ return 0;
+ }
+
+ s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM];
+ if (s->video_dev == NULL) {
+ CX18_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - "
+ "skipping\n", __func__);
+ return 0;
+ }
+
+ if (cx->alsa != NULL) {
+ CX18_ALSA_ERR("%s: struct snd_cx18_card * already exists\n",
+ __func__);
+ return 0;
+ }
+
+ if (snd_cx18_init(v4l2_dev)) {
+ CX18_ALSA_ERR("%s: failed to create struct snd_cx18_card\n",
+ __func__);
+ } else {
+ CX18_DEBUG_ALSA_INFO("%s: created cx18 ALSA interface instance "
+ "\n", __func__);
+ }
+ return 0;
+}
+
+static int __init cx18_alsa_init(void)
+{
+ printk(KERN_INFO "cx18-alsa: module loading...\n");
+ cx18_ext_init = &cx18_alsa_load;
+ return 0;
+}
+
+static void __exit snd_cx18_exit(struct snd_cx18_card *cxsc)
+{
+ struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
+
+ /* FIXME - pointer checks & shutdown cxsc */
+
+ snd_card_free(cxsc->sc);
+ cx->alsa = NULL;
+}
+
+static int __exit cx18_alsa_exit_callback(struct device *dev, void *data)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+ struct snd_cx18_card *cxsc;
+
+ if (v4l2_dev == NULL) {
+ printk(KERN_ERR "cx18-alsa: %s: struct v4l2_device * is NULL\n",
+ __func__);
+ return 0;
+ }
+
+ cxsc = to_snd_cx18_card(v4l2_dev);
+ if (cxsc == NULL) {
+ CX18_ALSA_WARN("%s: struct snd_cx18_card * is NULL\n",
+ __func__);
+ return 0;
+ }
+
+ snd_cx18_exit(cxsc);
+ return 0;
+}
+
+static void __exit cx18_alsa_exit(void)
+{
+ struct device_driver *drv;
+ int ret;
+
+ printk(KERN_INFO "cx18-alsa: module unloading...\n");
+
+ drv = driver_find("cx18", &pci_bus_type);
+ ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback);
+ put_driver(drv);
+
+ cx18_ext_init = NULL;
+ printk(KERN_INFO "cx18-alsa: module unload complete\n");
+}
+
+module_init(cx18_alsa_init);
+module_exit(cx18_alsa_exit);
diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.c b/drivers/media/video/cx18/cx18-alsa-mixer.c
new file mode 100644
index 000000000000..ef21114309fe
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-alsa-mixer.c
@@ -0,0 +1,175 @@
+/*
+ * ALSA mixer controls for the
+ * ALSA interface to cx18 PCM capture streams
+ *
+ * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+
+#include "cx18-alsa.h"
+#include "cx18-driver.h"
+
+/*
+ * Note the cx18-av-core volume scale is funny, due to the alignment of the
+ * scale with another chip's range:
+ *
+ * v4l2_control value /512 indicated dB actual dB reg 0x8d4
+ * 0x0000 - 0x01ff 0 -119 -96 228
+ * 0x0200 - 0x02ff 1 -118 -96 228
+ * ...
+ * 0x2c00 - 0x2dff 22 -97 -96 228
+ * 0x2e00 - 0x2fff 23 -96 -96 228
+ * 0x3000 - 0x31ff 24 -95 -95 226
+ * ...
+ * 0xee00 - 0xefff 119 0 0 36
+ * ...
+ * 0xfe00 - 0xffff 127 +8 +8 20
+ */
+static inline int dB_to_cx18_av_vol(int dB)
+{
+ if (dB < -96)
+ dB = -96;
+ else if (dB > 8)
+ dB = 8;
+ return (dB + 119) << 9;
+}
+
+static inline int cx18_av_vol_to_dB(int v)
+{
+ if (v < (23 << 9))
+ v = (23 << 9);
+ else if (v > (127 << 9))
+ v = (127 << 9);
+ return (v >> 9) - 119;
+}
+
+static int snd_cx18_mixer_tv_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ /* We're already translating values, just keep this control in dB */
+ uinfo->value.integer.min = -96;
+ uinfo->value.integer.max = 8;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int snd_cx18_mixer_tv_vol_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *uctl)
+{
+ struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl);
+ struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
+ struct v4l2_control vctrl;
+ int ret;
+
+ vctrl.id = V4L2_CID_AUDIO_VOLUME;
+ vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
+
+ snd_cx18_lock(cxsc);
+ ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl);
+ snd_cx18_unlock(cxsc);
+
+ if (!ret)
+ uctl->value.integer.value[0] = cx18_av_vol_to_dB(vctrl.value);
+ return ret;
+}
+
+static int snd_cx18_mixer_tv_vol_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *uctl)
+{
+ struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl);
+ struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
+ struct v4l2_control vctrl;
+ int ret;
+
+ vctrl.id = V4L2_CID_AUDIO_VOLUME;
+ vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
+
+ snd_cx18_lock(cxsc);
+
+ /* Fetch current state */
+ ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl);
+
+ if (ret ||
+ (cx18_av_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) {
+
+ /* Set, if needed */
+ vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
+ ret = v4l2_subdev_call(cx->sd_av, core, s_ctrl, &vctrl);
+ if (!ret)
+ ret = 1; /* Indicate control was changed w/o error */
+ }
+ snd_cx18_unlock(cxsc);
+
+ return ret;
+}
+
+
+/* This is a bit of overkill, the slider is already in dB internally */
+static DECLARE_TLV_DB_SCALE(snd_cx18_mixer_tv_vol_db_scale, -9600, 100, 0);
+
+static struct snd_kcontrol_new snd_cx18_mixer_tv_vol __initdata = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog TV Capture Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .info = snd_cx18_mixer_tv_volume_info,
+ .get = snd_cx18_mixer_tv_volume_get,
+ .put = snd_cx18_mixer_tv_volume_put,
+ .tlv.p = snd_cx18_mixer_tv_vol_db_scale
+};
+
+/* FIXME - add mute switch and balance, bass, treble sliders:
+ V4L2_CID_AUDIO_MUTE
+
+ V4L2_CID_AUDIO_BALANCE
+
+ V4L2_CID_AUDIO_BASS
+ V4L2_CID_AUDIO_TREBLE
+*/
+
+/* FIXME - add stereo, lang1, lang2, mono menu */
+/* FIXME - add CS5345 I2S volume for HVR-1600 */
+
+int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc)
+{
+ struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
+ struct snd_card *sc = cxsc->sc;
+ int ret;
+
+ strlcpy(sc->mixername, "CX23418 Mixer", sizeof(sc->mixername));
+
+ ret = snd_ctl_add(sc, snd_ctl_new1(snd_cx18_mixer_tv_vol, cxsc));
+ if (ret) {
+ CX18_ALSA_WARN("%s: failed to add %s control, err %d\n",
+ __func__, snd_cx18_mixer_tv_vol.name, ret);
+ }
+ return ret;
+}
diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.h b/drivers/media/video/cx18/cx18-alsa-mixer.h
new file mode 100644
index 000000000000..2d418db000fe
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-alsa-mixer.h
@@ -0,0 +1,23 @@
+/*
+ * ALSA mixer controls for the
+ * ALSA interface to cx18 PCM capture streams
+ *
+ * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ */
+
+int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc);
diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.c b/drivers/media/video/cx18/cx18-alsa-pcm.c
new file mode 100644
index 000000000000..2bd312daeb1e
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-alsa-pcm.c
@@ -0,0 +1,354 @@
+/*
+ * ALSA PCM device for the
+ * ALSA interface to cx18 PCM capture streams
+ *
+ * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * Portions of this work were sponsored by ONELAN Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include "cx18-driver.h"
+#include "cx18-queue.h"
+#include "cx18-streams.h"
+#include "cx18-fileops.h"
+#include "cx18-alsa.h"
+
+static unsigned int pcm_debug;
+module_param(pcm_debug, int, 0644);
+MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm");
+
+#define dprintk(fmt, arg...) do { \
+ if (pcm_debug) \
+ printk(KERN_INFO "cx18-alsa-pcm %s: " fmt, \
+ __func__, ##arg); \
+ } while (0)
+
+static struct snd_pcm_hardware snd_cx18_hw_capture = {
+ .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID,
+
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+ .rates = SNDRV_PCM_RATE_48000,
+
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */
+ .period_bytes_min = 64, /* 12544/2, */
+ .period_bytes_max = 12544,
+ .periods_min = 2,
+ .periods_max = 98, /* 12544, */
+};
+
+void cx18_alsa_announce_pcm_data(struct snd_cx18_card *cxsc, u8 *pcm_data,
+ size_t num_bytes)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
+ unsigned int oldptr;
+ unsigned int stride;
+ int period_elapsed = 0;
+ int length;
+
+ dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zd\n", cxsc,
+ pcm_data, num_bytes);
+
+ substream = cxsc->capture_pcm_substream;
+ if (substream == NULL) {
+ dprintk("substream was NULL\n");
+ return;
+ }
+
+ runtime = substream->runtime;
+ if (runtime == NULL) {
+ dprintk("runtime was NULL\n");
+ return;
+ }
+
+ stride = runtime->frame_bits >> 3;
+ if (stride == 0) {
+ dprintk("stride is zero\n");
+ return;
+ }
+
+ length = num_bytes / stride;
+ if (length == 0) {
+ dprintk("%s: length was zero\n", __func__);
+ return;
+ }
+
+ if (runtime->dma_area == NULL) {
+ dprintk("dma area was NULL - ignoring\n");
+ return;
+ }
+
+ oldptr = cxsc->hwptr_done_capture;
+ if (oldptr + length >= runtime->buffer_size) {
+ unsigned int cnt =
+ runtime->buffer_size - oldptr;
+ memcpy(runtime->dma_area + oldptr * stride, pcm_data,
+ cnt * stride);
+ memcpy(runtime->dma_area, pcm_data + cnt * stride,
+ length * stride - cnt * stride);
+ } else {
+ memcpy(runtime->dma_area + oldptr * stride, pcm_data,
+ length * stride);
+ }
+ snd_pcm_stream_lock(substream);
+
+ cxsc->hwptr_done_capture += length;
+ if (cxsc->hwptr_done_capture >=
+ runtime->buffer_size)
+ cxsc->hwptr_done_capture -=
+ runtime->buffer_size;
+
+ cxsc->capture_transfer_done += length;
+ if (cxsc->capture_transfer_done >=
+ runtime->period_size) {
+ cxsc->capture_transfer_done -=
+ runtime->period_size;
+ period_elapsed = 1;
+ }
+
+ snd_pcm_stream_unlock(substream);
+
+ if (period_elapsed)
+ snd_pcm_period_elapsed(substream);
+}
+
+static int snd_cx18_pcm_capture_open(struct snd_pcm_substream *substream)
+{
+ struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
+ struct cx18 *cx = to_cx18(v4l2_dev);
+ struct cx18_stream *s;
+ struct cx18_open_id item;
+ int ret;
+
+ /* Instruct the cx18 to start sending packets */
+ snd_cx18_lock(cxsc);
+ s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM];
+
+ item.cx = cx;
+ item.type = s->type;
+ item.open_id = cx->open_id++;
+
+ /* See if the stream is available */
+ if (cx18_claim_stream(&item, item.type)) {
+ /* No, it's already in use */
+ snd_cx18_unlock(cxsc);
+ return -EBUSY;
+ }
+
+ if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) ||
+ test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ /* We're already streaming. No additional action required */
+ snd_cx18_unlock(cxsc);
+ return 0;
+ }
+
+
+ runtime->hw = snd_cx18_hw_capture;
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ cxsc->capture_pcm_substream = substream;
+ runtime->private_data = cx;
+
+ cx->pcm_announce_callback = cx18_alsa_announce_pcm_data;
+
+ /* Not currently streaming, so start it up */
+ set_bit(CX18_F_S_STREAMING, &s->s_flags);
+ ret = cx18_start_v4l2_encode_stream(s);
+ snd_cx18_unlock(cxsc);
+
+ return 0;
+}
+
+static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+ struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+ struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
+ struct cx18 *cx = to_cx18(v4l2_dev);
+ struct cx18_stream *s;
+ int ret;
+
+ /* Instruct the cx18 to stop sending packets */
+ snd_cx18_lock(cxsc);
+ s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM];
+ ret = cx18_stop_v4l2_encode_stream(s, 0);
+ clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+
+ cx18_release_stream(s);
+
+ cx->pcm_announce_callback = NULL;
+ snd_cx18_unlock(cxsc);
+
+ return 0;
+}
+
+static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+ size_t size)
+{
+ struct snd_pcm_runtime *runtime = subs->runtime;
+
+ dprintk("Allocating vbuffer\n");
+ if (runtime->dma_area) {
+ if (runtime->dma_bytes > size)
+ return 0;
+
+ vfree(runtime->dma_area);
+ }
+ runtime->dma_area = vmalloc(size);
+ if (!runtime->dma_area)
+ return -ENOMEM;
+
+ runtime->dma_bytes = size;
+
+ return 0;
+}
+
+static int snd_cx18_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ int ret;
+
+ dprintk("%s called\n", __func__);
+
+ ret = snd_pcm_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+ return 0;
+}
+
+static int snd_cx18_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+ unsigned long flags;
+
+ spin_lock_irqsave(&cxsc->slock, flags);
+ if (substream->runtime->dma_area) {
+ dprintk("freeing pcm capture region\n");
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_area = NULL;
+ }
+ spin_unlock_irqrestore(&cxsc->slock, flags);
+
+ return 0;
+}
+
+static int snd_cx18_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+
+ cxsc->hwptr_done_capture = 0;
+ cxsc->capture_transfer_done = 0;
+
+ return 0;
+}
+
+static int snd_cx18_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ return 0;
+}
+
+static
+snd_pcm_uframes_t snd_cx18_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ unsigned long flags;
+ snd_pcm_uframes_t hwptr_done;
+ struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+
+ spin_lock_irqsave(&cxsc->slock, flags);
+ hwptr_done = cxsc->hwptr_done_capture;
+ spin_unlock_irqrestore(&cxsc->slock, flags);
+
+ return hwptr_done;
+}
+
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+ unsigned long offset)
+{
+ void *pageptr = subs->runtime->dma_area + offset;
+
+ return vmalloc_to_page(pageptr);
+}
+
+static struct snd_pcm_ops snd_cx18_pcm_capture_ops = {
+ .open = snd_cx18_pcm_capture_open,
+ .close = snd_cx18_pcm_capture_close,
+ .ioctl = snd_cx18_pcm_ioctl,
+ .hw_params = snd_cx18_pcm_hw_params,
+ .hw_free = snd_cx18_pcm_hw_free,
+ .prepare = snd_cx18_pcm_prepare,
+ .trigger = snd_cx18_pcm_trigger,
+ .pointer = snd_cx18_pcm_pointer,
+ .page = snd_pcm_get_vmalloc_page,
+};
+
+int snd_cx18_pcm_create(struct snd_cx18_card *cxsc)
+{
+ struct snd_pcm *sp;
+ struct snd_card *sc = cxsc->sc;
+ struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
+ struct cx18 *cx = to_cx18(v4l2_dev);
+ int ret;
+
+ ret = snd_pcm_new(sc, "CX23418 PCM",
+ 0, /* PCM device 0, the only one for this card */
+ 0, /* 0 playback substreams */
+ 1, /* 1 capture substream */
+ &sp);
+ if (ret) {
+ CX18_ALSA_ERR("%s: snd_cx18_pcm_create() failed with err %d\n",
+ __func__, ret);
+ goto err_exit;
+ }
+
+ spin_lock_init(&cxsc->slock);
+
+ snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_cx18_pcm_capture_ops);
+ sp->info_flags = 0;
+ sp->private_data = cxsc;
+ strlcpy(sp->name, cx->card_name, sizeof(sp->name));
+
+ return 0;
+
+err_exit:
+ return ret;
+}
diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.h b/drivers/media/video/cx18/cx18-alsa-pcm.h
new file mode 100644
index 000000000000..325662c647a0
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-alsa-pcm.h
@@ -0,0 +1,27 @@
+/*
+ * ALSA PCM device for the
+ * ALSA interface to cx18 PCM capture streams
+ *
+ * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ */
+
+int __init snd_cx18_pcm_create(struct snd_cx18_card *cxsc);
+
+/* Used by cx18-mailbox to announce the PCM data to the module */
+void cx18_alsa_announce_pcm_data(struct snd_cx18_card *card, u8 *pcm_data,
+ size_t num_bytes);
diff --git a/drivers/media/video/cx18/cx18-alsa.h b/drivers/media/video/cx18/cx18-alsa.h
new file mode 100644
index 000000000000..88a1cde7540b
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-alsa.h
@@ -0,0 +1,75 @@
+/*
+ * ALSA interface to cx18 PCM capture streams
+ *
+ * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ */
+
+struct snd_card;
+
+struct snd_cx18_card {
+ struct v4l2_device *v4l2_dev;
+ struct snd_card *sc;
+ unsigned int capture_transfer_done;
+ unsigned int hwptr_done_capture;
+ struct snd_pcm_substream *capture_pcm_substream;
+ spinlock_t slock;
+};
+
+extern int cx18_alsa_debug;
+
+/*
+ * File operations that manipulate the encoder or video or audio subdevices
+ * need to be serialized. Use the same lock we use for v4l2 file ops.
+ */
+static inline void snd_cx18_lock(struct snd_cx18_card *cxsc)
+{
+ struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
+ mutex_lock(&cx->serialize_lock);
+}
+
+static inline void snd_cx18_unlock(struct snd_cx18_card *cxsc)
+{
+ struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
+ mutex_unlock(&cx->serialize_lock);
+}
+
+#define CX18_ALSA_DBGFLG_WARN (1 << 0)
+#define CX18_ALSA_DBGFLG_WARN (1 << 0)
+#define CX18_ALSA_DBGFLG_INFO (1 << 1)
+
+#define CX18_ALSA_DEBUG(x, type, fmt, args...) \
+ do { \
+ if ((x) & cx18_alsa_debug) \
+ printk(KERN_INFO "%s-alsa: " type ": " fmt, \
+ v4l2_dev->name , ## args); \
+ } while (0)
+
+#define CX18_ALSA_DEBUG_WARN(fmt, args...) \
+ CX18_ALSA_DEBUG(CX18_ALSA_DBGFLG_WARN, "warning", fmt , ## args)
+
+#define CX18_ALSA_DEBUG_INFO(fmt, args...) \
+ CX18_ALSA_DEBUG(CX18_ALSA_DBGFLG_INFO, "info", fmt , ## args)
+
+#define CX18_ALSA_ERR(fmt, args...) \
+ printk(KERN_ERR "%s-alsa: " fmt, v4l2_dev->name , ## args)
+
+#define CX18_ALSA_WARN(fmt, args...) \
+ printk(KERN_WARNING "%s-alsa: " fmt, v4l2_dev->name , ## args)
+
+#define CX18_ALSA_INFO(fmt, args...) \
+ printk(KERN_INFO "%s-alsa: " fmt, v4l2_dev->name , ## args)
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index f11e47a58286..f808fb6fc1c1 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -393,7 +393,7 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = {
.gpio_init.direction = 0x7,
.gpio_audio_input = { .mask = 0x7,
.tuner = 0x6, .linein = 0x2, .radio = 0x2 },
- .xceive_pin = 15,
+ .xceive_pin = 1,
.pci_list = cx18_pci_leadtek_pvr2100,
.i2c = &cx18_i2c_std,
};
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 7f65a47f12e1..c95a86ba33b0 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -47,6 +47,10 @@
setting this to 1 you ensure that radio0 is now also radio1. */
int cx18_first_minor;
+/* Callback for registering extensions */
+int (*cx18_ext_init)(struct cx18 *);
+EXPORT_SYMBOL(cx18_ext_init);
+
/* add your revision and whatnot here */
static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
{PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
@@ -91,7 +95,7 @@ static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE;
static int enc_ts_bufs = -1;
static int enc_mpg_bufs = -1;
-static int enc_idx_bufs = -1;
+static int enc_idx_bufs = CX18_MAX_FW_MDLS_PER_STREAM;
static int enc_yuv_bufs = -1;
static int enc_vbi_bufs = -1;
static int enc_pcm_bufs = -1;
@@ -196,14 +200,17 @@ MODULE_PARM_DESC(enc_mpg_bufs,
"Number of encoder MPG buffers\n"
"\t\t\tDefault is computed from other enc_mpg_* parameters");
MODULE_PARM_DESC(enc_idx_buffers,
- "Encoder IDX buffer memory (MB). (enc_idx_bufs can override)\n"
- "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_IDX_BUFFERS));
+ "(Deprecated) Encoder IDX buffer memory (MB)\n"
+ "\t\t\tIgnored, except 0 disables IDX buffer allocations\n"
+ "\t\t\tDefault: 1 [Enabled]");
MODULE_PARM_DESC(enc_idx_bufsize,
"Size of an encoder IDX buffer (kB)\n"
- "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_IDX_BUFSIZE));
+ "\t\t\tAllowed values are multiples of 1.5 kB rounded up\n"
+ "\t\t\t(multiples of size required for 64 index entries)\n"
+ "\t\t\tDefault: 2");
MODULE_PARM_DESC(enc_idx_bufs,
"Number of encoder IDX buffers\n"
- "\t\t\tDefault is computed from other enc_idx_* parameters");
+ "\t\t\tDefault: " __stringify(CX18_MAX_FW_MDLS_PER_STREAM));
MODULE_PARM_DESC(enc_yuv_buffers,
"Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n"
"\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
@@ -231,7 +238,8 @@ MODULE_PARM_DESC(enc_pcm_bufs,
"Number of encoder PCM buffers\n"
"\t\t\tDefault is computed from other enc_pcm_* parameters");
-MODULE_PARM_DESC(cx18_first_minor, "Set device node number assigned to first card");
+MODULE_PARM_DESC(cx18_first_minor,
+ "Set device node number assigned to first card");
MODULE_AUTHOR("Hans Verkuil");
MODULE_DESCRIPTION("CX23418 driver");
@@ -240,6 +248,28 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(CX18_VERSION);
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+ struct cx18 *dev = container_of(work, struct cx18, request_module_wk);
+
+ /* Make sure cx18-alsa module is loaded */
+ request_module("cx18-alsa");
+
+ /* Initialize cx18-alsa for this instance of the cx18 device */
+ if (cx18_ext_init != NULL)
+ cx18_ext_init(dev);
+}
+
+static void request_modules(struct cx18 *dev)
+{
+ INIT_WORK(&dev->request_module_wk, request_module_async);
+ schedule_work(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#endif /* CONFIG_MODULES */
+
/* Generic utility functions */
int cx18_msleep_timeout(unsigned int msecs, int intr)
{
@@ -501,7 +531,12 @@ static void cx18_process_options(struct cx18 *cx)
/*
* YUV is a special case where the stream_buf_size needs to be
* an integral multiple of 33.75 kB (storage for 32 screens
- * lines to maintain alignment in case of lost buffers
+ * lines to maintain alignment in case of lost buffers).
+ *
+ * IDX is a special case where the stream_buf_size should be
+ * an integral multiple of 1.5 kB (storage for 64 index entries
+ * to maintain alignment in case of lost buffers).
+ *
*/
if (i == CX18_ENC_STREAM_TYPE_YUV) {
cx->stream_buf_size[i] *= 1024;
@@ -511,15 +546,24 @@ static void cx18_process_options(struct cx18 *cx)
if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE)
cx->stream_buf_size[i] =
CX18_UNIT_ENC_YUV_BUFSIZE;
+ } else if (i == CX18_ENC_STREAM_TYPE_IDX) {
+ cx->stream_buf_size[i] *= 1024;
+ cx->stream_buf_size[i] -=
+ (cx->stream_buf_size[i] % CX18_UNIT_ENC_IDX_BUFSIZE);
+
+ if (cx->stream_buf_size[i] < CX18_UNIT_ENC_IDX_BUFSIZE)
+ cx->stream_buf_size[i] =
+ CX18_UNIT_ENC_IDX_BUFSIZE;
}
/*
- * YUV is a special case where the stream_buf_size is
+ * YUV and IDX are special cases where the stream_buf_size is
* now in bytes.
* VBI is a special case where the stream_buf_size is fixed
* and already in bytes
*/
if (i == CX18_ENC_STREAM_TYPE_VBI ||
- i == CX18_ENC_STREAM_TYPE_YUV) {
+ i == CX18_ENC_STREAM_TYPE_YUV ||
+ i == CX18_ENC_STREAM_TYPE_IDX) {
if (cx->stream_buffers[i] < 0) {
cx->stream_buffers[i] =
cx->options.megabytes[i] * 1024 * 1024
@@ -1032,6 +1076,10 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
}
CX18_INFO("Initialized card: %s\n", cx->card_name);
+
+ /* Load cx18 submodules (cx18-alsa) */
+ request_modules(cx);
+
return 0;
free_streams:
@@ -1220,6 +1268,7 @@ static void cx18_remove(struct pci_dev *pci_dev)
kfree(cx);
}
+
/* define a pci_driver for card detection */
static struct pci_driver cx18_pci_driver = {
.name = "cx18",
@@ -1230,7 +1279,8 @@ static struct pci_driver cx18_pci_driver = {
static int __init module_start(void)
{
- printk(KERN_INFO "cx18: Start initialization, version %s\n", CX18_VERSION);
+ printk(KERN_INFO "cx18: Start initialization, version %s\n",
+ CX18_VERSION);
/* Validate parameters */
if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index e3f7911a7385..23ad6d548dc5 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -126,10 +126,22 @@
#define CX18_625_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 576/32)
#define CX18_525_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 480/32)
+/* IDX buffer size should be a multiple of the index entry size from the chip */
+struct cx18_enc_idx_entry {
+ __le32 length;
+ __le32 offset_low;
+ __le32 offset_high;
+ __le32 flags;
+ __le32 pts_low;
+ __le32 pts_high;
+} __attribute__ ((packed));
+#define CX18_UNIT_ENC_IDX_BUFSIZE \
+ (sizeof(struct cx18_enc_idx_entry) * V4L2_ENC_IDX_ENTRIES)
+
/* DMA buffer, default size in kB allocated */
#define CX18_DEFAULT_ENC_TS_BUFSIZE 32
#define CX18_DEFAULT_ENC_MPG_BUFSIZE 32
-#define CX18_DEFAULT_ENC_IDX_BUFSIZE 32
+#define CX18_DEFAULT_ENC_IDX_BUFSIZE (CX18_UNIT_ENC_IDX_BUFSIZE * 1 / 1024 + 1)
#define CX18_DEFAULT_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 3 / 1024 + 1)
#define CX18_DEFAULT_ENC_PCM_BUFSIZE 4
@@ -234,16 +246,8 @@
#define CX18_WARN_DEV(dev, fmt, args...) v4l2_warn(dev, fmt , ## args)
#define CX18_INFO_DEV(dev, fmt, args...) v4l2_info(dev, fmt , ## args)
-/* Values for CX18_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */
-#define MPEG_FRAME_TYPE_IFRAME 1
-#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3
-#define MPEG_FRAME_TYPE_ALL 7
-
-#define CX18_MAX_PGM_INDEX (400)
-
extern int cx18_debug;
-
struct cx18_options {
int megabytes[CX18_MAX_STREAMS]; /* Size in megabytes of each stream */
int cardtype; /* force card type on load */
@@ -276,6 +280,18 @@ struct cx18_options {
#define CX18_SLICED_TYPE_WSS_625 (5)
#define CX18_SLICED_TYPE_VPS (7)
+/**
+ * list_entry_is_past_end - check if a previous loop cursor is off list end
+ * @pos: the type * previously used as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Check if the entry's list_head is the head of the list, thus it's not a
+ * real entry but was the loop cursor that walked past the end
+ */
+#define list_entry_is_past_end(pos, head, member) \
+ (&pos->member == (head))
+
struct cx18_buffer {
struct list_head list;
dma_addr_t dma_handle;
@@ -558,6 +574,10 @@ struct cx18 {
int stream_buffers[CX18_MAX_STREAMS]; /* # of buffers for each stream */
int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */
struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */
+ struct snd_cx18_card *alsa; /* ALSA interface for PCM capture stream */
+ void (*pcm_announce_callback)(struct snd_cx18_card *card, u8 *pcm_data,
+ size_t num_bytes);
+
unsigned long i_flags; /* global cx18 flags */
atomic_t ana_capturing; /* count number of active analog capture streams */
atomic_t tot_capturing; /* total count number of active capture streams */
@@ -575,12 +595,6 @@ struct cx18 {
struct vbi_info vbi;
- u32 pgm_info_offset;
- u32 pgm_info_num;
- u32 pgm_info_write_idx;
- u32 pgm_info_read_idx;
- struct v4l2_enc_idx_entry pgm_info[CX18_MAX_PGM_INDEX];
-
u64 mpg_data_received;
u64 vbi_data_inserted;
@@ -623,6 +637,9 @@ struct cx18 {
u32 active_input;
v4l2_std_id std;
v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */
+
+ /* Used for cx18-alsa module loading */
+ struct work_struct request_module_wk;
};
static inline struct cx18 *to_cx18(struct v4l2_device *v4l2_dev)
@@ -630,6 +647,9 @@ static inline struct cx18 *to_cx18(struct v4l2_device *v4l2_dev)
return container_of(v4l2_dev, struct cx18, v4l2_dev);
}
+/* cx18 extensions to be loaded */
+extern int (*cx18_ext_init)(struct cx18 *);
+
/* Globals */
extern int cx18_first_minor;
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
index 71ad2d1b4c2c..0ae2c2e1eab5 100644
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -213,10 +213,14 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
struct cx18_stream *stream = (struct cx18_stream *) demux->priv;
- struct cx18 *cx = stream->cx;
+ struct cx18 *cx;
int ret;
u32 v;
+ if (!stream)
+ return -EINVAL;
+
+ cx = stream->cx;
CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n",
feed->pid, feed->index);
@@ -253,12 +257,10 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
if (!demux->dmx.frontend)
return -EINVAL;
- if (!stream)
- return -EINVAL;
-
mutex_lock(&stream->dvb.feedlock);
if (stream->dvb.feeding++ == 0) {
CX18_DEBUG_INFO("Starting Transport DMA\n");
+ mutex_lock(&cx->serialize_lock);
set_bit(CX18_F_S_STREAMING, &stream->s_flags);
ret = cx18_start_v4l2_encode_stream(stream);
if (ret < 0) {
@@ -267,6 +269,7 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
if (stream->dvb.feeding == 0)
clear_bit(CX18_F_S_STREAMING, &stream->s_flags);
}
+ mutex_unlock(&cx->serialize_lock);
} else
ret = 0;
mutex_unlock(&stream->dvb.feedlock);
@@ -279,17 +282,20 @@ static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
struct cx18_stream *stream = (struct cx18_stream *)demux->priv;
- struct cx18 *cx = stream->cx;
+ struct cx18 *cx;
int ret = -EINVAL;
- CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n",
- feed->pid, feed->index);
-
if (stream) {
+ cx = stream->cx;
+ CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n",
+ feed->pid, feed->index);
+
mutex_lock(&stream->dvb.feedlock);
if (--stream->dvb.feeding == 0) {
CX18_DEBUG_INFO("Stopping Transport DMA\n");
+ mutex_lock(&cx->serialize_lock);
ret = cx18_stop_v4l2_encode_stream(stream, 0);
+ mutex_unlock(&cx->serialize_lock);
} else
ret = 0;
mutex_unlock(&stream->dvb.feedlock);
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index c0885c69fd89..863ce7758239 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -37,15 +37,21 @@
/* This function tries to claim the stream for a specific file descriptor.
If no one else is using this stream then the stream is claimed and
- associated VBI streams are also automatically claimed.
+ associated VBI and IDX streams are also automatically claimed.
Possible error returns: -EBUSY if someone else has claimed
the stream or 0 on success. */
-static int cx18_claim_stream(struct cx18_open_id *id, int type)
+int cx18_claim_stream(struct cx18_open_id *id, int type)
{
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[type];
- struct cx18_stream *s_vbi;
- int vbi_type;
+ struct cx18_stream *s_assoc;
+
+ /* Nothing should ever try to directly claim the IDX stream */
+ if (type == CX18_ENC_STREAM_TYPE_IDX) {
+ CX18_WARN("MPEG Index stream cannot be claimed "
+ "directly, but something tried.\n");
+ return -EINVAL;
+ }
if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
/* someone already claimed this stream */
@@ -67,32 +73,47 @@ static int cx18_claim_stream(struct cx18_open_id *id, int type)
}
s->id = id->open_id;
- /* CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
- (provided VBI insertion is on and sliced VBI is selected), for all
- other streams we're done */
- if (type == CX18_ENC_STREAM_TYPE_MPG &&
- cx->vbi.insert_mpeg && !cx18_raw_vbi(cx)) {
- vbi_type = CX18_ENC_STREAM_TYPE_VBI;
- } else {
+ /*
+ * CX18_ENC_STREAM_TYPE_MPG needs to claim:
+ * CX18_ENC_STREAM_TYPE_VBI, if VBI insertion is on for sliced VBI, or
+ * CX18_ENC_STREAM_TYPE_IDX, if VBI insertion is off for sliced VBI
+ * (We don't yet fix up MPEG Index entries for our inserted packets).
+ *
+ * For all other streams we're done.
+ */
+ if (type != CX18_ENC_STREAM_TYPE_MPG)
return 0;
- }
- s_vbi = &cx->streams[vbi_type];
- set_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags);
+ s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
+ if (cx->vbi.insert_mpeg && !cx18_raw_vbi(cx))
+ s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+ else if (!cx18_stream_enabled(s_assoc))
+ return 0;
+
+ set_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags);
/* mark that it is used internally */
- set_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags);
+ set_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags);
return 0;
}
+EXPORT_SYMBOL(cx18_claim_stream);
/* This function releases a previously claimed stream. It will take into
account associated VBI streams. */
-static void cx18_release_stream(struct cx18_stream *s)
+void cx18_release_stream(struct cx18_stream *s)
{
struct cx18 *cx = s->cx;
- struct cx18_stream *s_vbi;
+ struct cx18_stream *s_assoc;
s->id = -1;
+ if (s->type == CX18_ENC_STREAM_TYPE_IDX) {
+ /*
+ * The IDX stream is only used internally, and can
+ * only be indirectly unclaimed by unclaiming the MPG stream.
+ */
+ return;
+ }
+
if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) {
/* this stream is still in use internally */
@@ -105,25 +126,36 @@ static void cx18_release_stream(struct cx18_stream *s)
cx18_flush_queues(s);
- /* CX18_ENC_STREAM_TYPE_MPG needs to release CX18_ENC_STREAM_TYPE_VBI,
- for all other streams we're done */
- if (s->type == CX18_ENC_STREAM_TYPE_MPG)
- s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
- else
+ /*
+ * CX18_ENC_STREAM_TYPE_MPG needs to release the
+ * CX18_ENC_STREAM_TYPE_VBI and/or CX18_ENC_STREAM_TYPE_IDX streams.
+ *
+ * For all other streams we're done.
+ */
+ if (s->type != CX18_ENC_STREAM_TYPE_MPG)
return;
- /* clear internal use flag */
- if (!test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags)) {
- /* was already cleared */
- return;
+ /* Unclaim the associated MPEG Index stream */
+ s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
+ if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) {
+ clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags);
+ cx18_flush_queues(s_assoc);
}
- if (s_vbi->id != -1) {
- /* VBI stream still claimed by a file descriptor */
- return;
+
+ /* Unclaim the associated VBI stream */
+ s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+ if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) {
+ if (s_assoc->id == -1) {
+ /*
+ * The VBI stream is not still claimed by a file
+ * descriptor, so completely unclaim it.
+ */
+ clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags);
+ cx18_flush_queues(s_assoc);
+ }
}
- clear_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags);
- cx18_flush_queues(s_vbi);
}
+EXPORT_SYMBOL(cx18_release_stream);
static void cx18_dualwatch(struct cx18 *cx)
{
@@ -177,9 +209,7 @@ static struct cx18_mdl *cx18_get_mdl(struct cx18_stream *s, int non_block,
*err = 0;
while (1) {
if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
- /* Process pending program info updates and pending
- VBI data */
-
+ /* Process pending program updates and VBI data */
if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) {
cx->dualwatch_jiffies = jiffies;
cx18_dualwatch(cx);
@@ -362,18 +392,6 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
return len;
}
-/**
- * list_entry_is_past_end - check if a previous loop cursor is off list end
- * @pos: the type * previously used as a loop cursor.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- *
- * Check if the entry's list_head is the head of the list, thus it's not a
- * real entry but was the loop cursor that walked past the end
- */
-#define list_entry_is_past_end(pos, head, member) \
- (&pos->member == (head))
-
static size_t cx18_copy_mdl_to_user(struct cx18_stream *s,
struct cx18_mdl *mdl, char __user *ubuf, size_t ucount)
{
@@ -498,6 +516,7 @@ int cx18_start_capture(struct cx18_open_id *id)
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];
struct cx18_stream *s_vbi;
+ struct cx18_stream *s_idx;
if (s->type == CX18_ENC_STREAM_TYPE_RAD) {
/* you cannot read from these stream types. */
@@ -516,25 +535,33 @@ int cx18_start_capture(struct cx18_open_id *id)
return 0;
}
- /* Start VBI capture if required */
+ /* Start associated VBI or IDX stream capture if required */
s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
- if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
- test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
- !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
- /* Note: the CX18_ENC_STREAM_TYPE_VBI is claimed
- automatically when the MPG stream is claimed.
- We only need to start the VBI capturing. */
- if (cx18_start_v4l2_encode_stream(s_vbi)) {
- CX18_DEBUG_WARN("VBI capture start failed\n");
-
- /* Failure, clean up and return an error */
- clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
- clear_bit(CX18_F_S_STREAMING, &s->s_flags);
- /* also releases the associated VBI stream */
- cx18_release_stream(s);
- return -EIO;
+ s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
+ /*
+ * The VBI and IDX streams should have been claimed
+ * automatically, if for internal use, when the MPG stream was
+ * claimed. We only need to start these streams capturing.
+ */
+ if (test_bit(CX18_F_S_INTERNAL_USE, &s_idx->s_flags) &&
+ !test_and_set_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) {
+ if (cx18_start_v4l2_encode_stream(s_idx)) {
+ CX18_DEBUG_WARN("IDX capture start failed\n");
+ clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags);
+ goto start_failed;
+ }
+ CX18_DEBUG_INFO("IDX capture started\n");
+ }
+ if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+ !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
+ if (cx18_start_v4l2_encode_stream(s_vbi)) {
+ CX18_DEBUG_WARN("VBI capture start failed\n");
+ clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
+ goto start_failed;
+ }
+ CX18_DEBUG_INFO("VBI insertion started\n");
}
- CX18_DEBUG_INFO("VBI insertion started\n");
}
/* Tell the card to start capturing */
@@ -547,19 +574,29 @@ int cx18_start_capture(struct cx18_open_id *id)
return 0;
}
- /* failure, clean up */
+start_failed:
CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name);
- /* Note: the CX18_ENC_STREAM_TYPE_VBI is released
- automatically when the MPG stream is released.
- We only need to stop the VBI capturing. */
- if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
- test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
- cx18_stop_v4l2_encode_stream(s_vbi, 0);
- clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
+ /*
+ * The associated VBI and IDX streams for internal use are released
+ * automatically when the MPG stream is released. We only need to stop
+ * the associated stream.
+ */
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
+ /* Stop the IDX stream which is always for internal use */
+ if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) {
+ cx18_stop_v4l2_encode_stream(s_idx, 0);
+ clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags);
+ }
+ /* Stop the VBI stream, if only running for internal use */
+ if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
+ !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
+ cx18_stop_v4l2_encode_stream(s_vbi, 0);
+ clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
+ }
}
clear_bit(CX18_F_S_STREAMING, &s->s_flags);
- cx18_release_stream(s);
+ cx18_release_stream(s); /* Also releases associated streams */
return -EIO;
}
@@ -618,6 +655,8 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
{
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];
+ struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+ struct cx18_stream *s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
CX18_DEBUG_IOCTL("close() of %s\n", s->name);
@@ -625,17 +664,19 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
/* Stop capturing */
if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
- struct cx18_stream *s_vbi =
- &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
-
CX18_DEBUG_INFO("close stopping capture\n");
- /* Special case: a running VBI capture for VBI insertion
- in the mpeg stream. Need to stop that too. */
- if (id->type == CX18_ENC_STREAM_TYPE_MPG &&
- test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
- !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
- CX18_DEBUG_INFO("close stopping embedded VBI capture\n");
- cx18_stop_v4l2_encode_stream(s_vbi, 0);
+ if (id->type == CX18_ENC_STREAM_TYPE_MPG) {
+ /* Stop internal use associated VBI and IDX streams */
+ if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
+ !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
+ CX18_DEBUG_INFO("close stopping embedded VBI "
+ "capture\n");
+ cx18_stop_v4l2_encode_stream(s_vbi, 0);
+ }
+ if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) {
+ CX18_DEBUG_INFO("close stopping IDX capture\n");
+ cx18_stop_v4l2_encode_stream(s_idx, 0);
+ }
}
if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags))
diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h
index 92e2d5dab936..5c8fcb884f0a 100644
--- a/drivers/media/video/cx18/cx18-fileops.h
+++ b/drivers/media/video/cx18/cx18-fileops.h
@@ -34,3 +34,6 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
void cx18_mute(struct cx18 *cx);
void cx18_unmute(struct cx18 *cx);
+/* Shared with cx18-alsa module */
+int cx18_claim_stream(struct cx18_open_id *id, int type);
+void cx18_release_stream(struct cx18_stream *s);
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 3e4fc192fdec..b81dd0ea8eb9 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -775,10 +775,143 @@ static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
return 0;
}
+static int _cx18_process_idx_data(struct cx18_buffer *buf,
+ struct v4l2_enc_idx *idx)
+{
+ int consumed, remaining;
+ struct v4l2_enc_idx_entry *e_idx;
+ struct cx18_enc_idx_entry *e_buf;
+
+ /* Frame type lookup: 1=I, 2=P, 4=B */
+ const int mapping[8] = {
+ -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P,
+ -1, V4L2_ENC_IDX_FRAME_B, -1, -1, -1
+ };
+
+ /*
+ * Assumption here is that a buf holds an integral number of
+ * struct cx18_enc_idx_entry objects and is properly aligned.
+ * This is enforced by the module options on IDX buffer sizes.
+ */
+ remaining = buf->bytesused - buf->readpos;
+ consumed = 0;
+ e_idx = &idx->entry[idx->entries];
+ e_buf = (struct cx18_enc_idx_entry *) &buf->buf[buf->readpos];
+
+ while (remaining >= sizeof(struct cx18_enc_idx_entry) &&
+ idx->entries < V4L2_ENC_IDX_ENTRIES) {
+
+ e_idx->offset = (((u64) le32_to_cpu(e_buf->offset_high)) << 32)
+ | le32_to_cpu(e_buf->offset_low);
+
+ e_idx->pts = (((u64) (le32_to_cpu(e_buf->pts_high) & 1)) << 32)
+ | le32_to_cpu(e_buf->pts_low);
+
+ e_idx->length = le32_to_cpu(e_buf->length);
+
+ e_idx->flags = mapping[le32_to_cpu(e_buf->flags) & 0x7];
+
+ e_idx->reserved[0] = 0;
+ e_idx->reserved[1] = 0;
+
+ idx->entries++;
+ e_idx = &idx->entry[idx->entries];
+ e_buf++;
+
+ remaining -= sizeof(struct cx18_enc_idx_entry);
+ consumed += sizeof(struct cx18_enc_idx_entry);
+ }
+
+ /* Swallow any partial entries at the end, if there are any */
+ if (remaining > 0 && remaining < sizeof(struct cx18_enc_idx_entry))
+ consumed += remaining;
+
+ buf->readpos += consumed;
+ return consumed;
+}
+
+static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl,
+ struct v4l2_enc_idx *idx)
+{
+ if (s->type != CX18_ENC_STREAM_TYPE_IDX)
+ return -EINVAL;
+
+ if (mdl->curr_buf == NULL)
+ mdl->curr_buf = list_first_entry(&mdl->buf_list,
+ struct cx18_buffer, list);
+
+ if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) {
+ /*
+ * For some reason we've exhausted the buffers, but the MDL
+ * object still said some data was unread.
+ * Fix that and bail out.
+ */
+ mdl->readpos = mdl->bytesused;
+ return 0;
+ }
+
+ list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) {
+
+ /* Skip any empty buffers in the MDL */
+ if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused)
+ continue;
+
+ mdl->readpos += _cx18_process_idx_data(mdl->curr_buf, idx);
+
+ /* exit when MDL drained or request satisfied */
+ if (idx->entries >= V4L2_ENC_IDX_ENTRIES ||
+ mdl->curr_buf->readpos < mdl->curr_buf->bytesused ||
+ mdl->readpos >= mdl->bytesused)
+ break;
+ }
+ return 0;
+}
+
static int cx18_g_enc_index(struct file *file, void *fh,
struct v4l2_enc_idx *idx)
{
- return -EINVAL;
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+ struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
+ s32 tmp;
+ struct cx18_mdl *mdl;
+
+ if (!cx18_stream_enabled(s)) /* Module options inhibited IDX stream */
+ return -EINVAL;
+
+ /* Compute the best case number of entries we can buffer */
+ tmp = s->buffers -
+ s->bufs_per_mdl * CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN;
+ if (tmp <= 0)
+ tmp = 1;
+ tmp = tmp * s->buf_size / sizeof(struct cx18_enc_idx_entry);
+
+ /* Fill out the header of the return structure */
+ idx->entries = 0;
+ idx->entries_cap = tmp;
+ memset(idx->reserved, 0, sizeof(idx->reserved));
+
+ /* Pull IDX MDLs and buffers from q_full and populate the entries */
+ do {
+ mdl = cx18_dequeue(s, &s->q_full);
+ if (mdl == NULL) /* No more IDX data right now */
+ break;
+
+ /* Extract the Index entry data from the MDL and buffers */
+ cx18_process_idx_data(s, mdl, idx);
+ if (mdl->readpos < mdl->bytesused) {
+ /* We finished with data remaining, push the MDL back */
+ cx18_push(s, mdl, &s->q_full);
+ break;
+ }
+
+ /* We drained this MDL, schedule it to go to the firmware */
+ cx18_enqueue(s, mdl, &s->q_free);
+
+ } while (idx->entries < V4L2_ENC_IDX_ENTRIES);
+
+ /* Tell the work handler to send free IDX MDLs to the firmware */
+ cx18_stream_load_fw_queue(s);
+ return 0;
}
static int cx18_encoder_cmd(struct file *file, void *fh,
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index f231dd09c720..6dcce297752f 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -29,6 +29,7 @@
#include "cx18-mailbox.h"
#include "cx18-queue.h"
#include "cx18-streams.h"
+#include "cx18-alsa-pcm.h" /* FIXME make configurable */
static const char *rpu_str[] = { "APU", "CPU", "EPU", "HPU" };
@@ -157,6 +158,34 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
}
}
+
+static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s,
+ struct cx18_mdl *mdl)
+{
+ struct cx18_buffer *buf;
+
+ if (mdl->bytesused == 0)
+ return;
+
+ /* We ignore mdl and buf readpos accounting here - it doesn't matter */
+
+ /* The likely case */
+ if (list_is_singular(&mdl->buf_list)) {
+ buf = list_first_entry(&mdl->buf_list, struct cx18_buffer,
+ list);
+ if (buf->bytesused)
+ cx->pcm_announce_callback(cx->alsa, buf->buf,
+ buf->bytesused);
+ return;
+ }
+
+ list_for_each_entry(buf, &mdl->buf_list, list) {
+ if (buf->bytesused == 0)
+ break;
+ cx->pcm_announce_callback(cx->alsa, buf->buf, buf->bytesused);
+ }
+}
+
static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
{
u32 handle, mdl_ack_count, id;
@@ -223,11 +252,21 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n",
s->name, mdl->bytesused);
- if (s->type != CX18_ENC_STREAM_TYPE_TS)
- cx18_enqueue(s, mdl, &s->q_full);
- else {
+ if (s->type == CX18_ENC_STREAM_TYPE_TS) {
cx18_mdl_send_to_dvb(s, mdl);
cx18_enqueue(s, mdl, &s->q_free);
+ } else if (s->type == CX18_ENC_STREAM_TYPE_PCM) {
+ /* Pass the data to cx18-alsa */
+ if (cx->pcm_announce_callback != NULL) {
+ cx18_mdl_send_to_alsa(cx, s, mdl);
+ cx18_enqueue(s, mdl, &s->q_free);
+ } else {
+ cx18_enqueue(s, mdl, &s->q_full);
+ }
+ } else {
+ cx18_enqueue(s, mdl, &s->q_full);
+ if (s->type == CX18_ENC_STREAM_TYPE_IDX)
+ cx18_stream_rotate_idx_mdls(cx);
}
}
/* Put as many MDLs as possible back into fw use */
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
index 63304823cef5..aefc8c8cf3c1 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -419,6 +419,9 @@ void cx18_stream_free(struct cx18_stream *s)
{
struct cx18_mdl *mdl;
struct cx18_buffer *buf;
+ struct cx18 *cx = s->cx;
+
+ CX18_DEBUG_INFO("Deallocating buffers for %s stream\n", s->name);
/* move all buffers to buf_pool and all MDLs to q_idle */
cx18_unload_queues(s);
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 987a9308d938..054450f65a60 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -319,11 +319,27 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
/* Teardown all streams */
for (type = 0; type < CX18_MAX_STREAMS; type++) {
- if (cx->streams[type].dvb.enabled) {
- cx18_dvb_unregister(&cx->streams[type]);
- cx->streams[type].dvb.enabled = false;
+
+ /* No struct video_device, but can have buffers allocated */
+ if (type == CX18_ENC_STREAM_TYPE_TS) {
+ if (cx->streams[type].dvb.enabled) {
+ cx18_dvb_unregister(&cx->streams[type]);
+ cx->streams[type].dvb.enabled = false;
+ cx18_stream_free(&cx->streams[type]);
+ }
+ continue;
+ }
+
+ /* No struct video_device, but can have buffers allocated */
+ if (type == CX18_ENC_STREAM_TYPE_IDX) {
+ if (cx->stream_buffers[type] != 0) {
+ cx->stream_buffers[type] = 0;
+ cx18_stream_free(&cx->streams[type]);
+ }
+ continue;
}
+ /* If struct video_device exists, can have buffers allocated */
vdev = cx->streams[type].video_dev;
cx->streams[type].video_dev = NULL;
@@ -447,6 +463,32 @@ static void cx18_vbi_setup(struct cx18_stream *s)
cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
}
+void cx18_stream_rotate_idx_mdls(struct cx18 *cx)
+{
+ struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
+ struct cx18_mdl *mdl;
+
+ if (!cx18_stream_enabled(s))
+ return;
+
+ /* Return if the firmware is not running low on MDLs */
+ if ((atomic_read(&s->q_free.depth) + atomic_read(&s->q_busy.depth)) >=
+ CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN)
+ return;
+
+ /* Return if there are no MDLs to rotate back to the firmware */
+ if (atomic_read(&s->q_full.depth) < 2)
+ return;
+
+ /*
+ * Take the oldest IDX MDL still holding data, and discard its index
+ * entries by scheduling the MDL to go back to the firmware
+ */
+ mdl = cx18_dequeue(s, &s->q_full);
+ if (mdl != NULL)
+ cx18_enqueue(s, mdl, &s->q_free);
+}
+
static
struct cx18_queue *_cx18_stream_put_mdl_fw(struct cx18_stream *s,
struct cx18_mdl *mdl)
@@ -546,8 +588,9 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
struct cx18 *cx = s->cx;
int captype = 0;
struct cx18_api_func_private priv;
+ struct cx18_stream *s_idx;
- if (s->video_dev == NULL && s->dvb.enabled == 0)
+ if (!cx18_stream_enabled(s))
return -EINVAL;
CX18_DEBUG_INFO("Start encoder stream %s\n", s->name);
@@ -561,6 +604,9 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
cx->search_pack_header = 0;
break;
+ case CX18_ENC_STREAM_TYPE_IDX:
+ captype = CAPTURE_CHANNEL_TYPE_INDEX;
+ break;
case CX18_ENC_STREAM_TYPE_TS:
captype = CAPTURE_CHANNEL_TYPE_TS;
break;
@@ -635,11 +681,13 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
cx18_vbi_setup(s);
/*
- * assign program index info.
- * Mask 7: select I/P/B, Num_req: 400 max
- * FIXME - currently we have this hardcoded as disabled
+ * Select to receive I, P, and B frame index entries, if the
+ * index stream is enabled. Otherwise disable index entry
+ * generation.
*/
- cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0);
+ s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
+ cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 2,
+ s->handle, cx18_stream_enabled(s_idx) ? 7 : 0);
/* Call out to the common CX2341x API setup for user controls */
priv.cx = cx;
@@ -697,6 +745,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
atomic_inc(&cx->tot_capturing);
return 0;
}
+EXPORT_SYMBOL(cx18_start_v4l2_encode_stream);
void cx18_stop_all_captures(struct cx18 *cx)
{
@@ -705,7 +754,7 @@ void cx18_stop_all_captures(struct cx18 *cx)
for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) {
struct cx18_stream *s = &cx->streams[i];
- if (s->video_dev == NULL && s->dvb.enabled == 0)
+ if (!cx18_stream_enabled(s))
continue;
if (test_bit(CX18_F_S_STREAMING, &s->s_flags))
cx18_stop_v4l2_encode_stream(s, 0);
@@ -717,7 +766,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
struct cx18 *cx = s->cx;
unsigned long then;
- if (s->video_dev == NULL && s->dvb.enabled == 0)
+ if (!cx18_stream_enabled(s))
return -EINVAL;
/* This function assumes that you are allowed to stop the capture
@@ -762,6 +811,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
return 0;
}
+EXPORT_SYMBOL(cx18_stop_v4l2_encode_stream);
u32 cx18_find_handle(struct cx18 *cx)
{
@@ -789,7 +839,7 @@ struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle)
s = &cx->streams[i];
if (s->handle != handle)
continue;
- if (s->video_dev || s->dvb.enabled)
+ if (cx18_stream_enabled(s))
return s;
}
return NULL;
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h
index 4a01db5e5a35..0bff0fa29763 100644
--- a/drivers/media/video/cx18/cx18-streams.h
+++ b/drivers/media/video/cx18/cx18-streams.h
@@ -28,6 +28,16 @@ int cx18_streams_setup(struct cx18 *cx);
int cx18_streams_register(struct cx18 *cx);
void cx18_streams_cleanup(struct cx18 *cx, int unregister);
+#define CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN (3)
+void cx18_stream_rotate_idx_mdls(struct cx18 *cx);
+
+static inline bool cx18_stream_enabled(struct cx18_stream *s)
+{
+ return s->video_dev || s->dvb.enabled ||
+ (s->type == CX18_ENC_STREAM_TYPE_IDX &&
+ s->cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] != 0);
+}
+
/* Related to submission of mdls to firmware */
static inline void cx18_stream_load_fw_queue(struct cx18_stream *s)
{
diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h
index 9c0b5bb1b019..3e1aec4bcfde 100644
--- a/drivers/media/video/cx18/cx18-version.h
+++ b/drivers/media/video/cx18/cx18-version.h
@@ -24,7 +24,7 @@
#define CX18_DRIVER_NAME "cx18"
#define CX18_DRIVER_VERSION_MAJOR 1
-#define CX18_DRIVER_VERSION_MINOR 3
+#define CX18_DRIVER_VERSION_MINOR 4
#define CX18_DRIVER_VERSION_PATCHLEVEL 0
#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
index 868806effdcf..2c00980acfcb 100644
--- a/drivers/media/video/cx18/cx23418.h
+++ b/drivers/media/video/cx18/cx23418.h
@@ -191,7 +191,8 @@
#define CX18_CPU_SET_MEDIAN_CORING (CPU_CMD_MASK_CAPTURE | 0x000E)
/* Description: This command set the picture type mask for index file
- IN[0] - 0 = disable index file output
+ IN[0] - Task handle (ignored by firmware)
+ IN[1] - 0 = disable index file output
1 = output I picture
2 = P picture
4 = B picture
diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/video/cx231xx/cx231xx-dvb.c
index c5082a4e8ced..64e025e2bdf1 100644
--- a/drivers/media/video/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/video/cx231xx/cx231xx-dvb.c
@@ -464,9 +464,9 @@ static int dvb_init(struct cx231xx *dev)
/* define general-purpose callback pointer */
dvb->frontend->callback = cx231xx_tuner_callback;
- if (dvb_attach(xc5000_attach, dev->dvb->frontend,
+ if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
&dev->i2c_bus[1].i2c_adap,
- &cnxt_rde250_tunerconfig) < 0) {
+ &cnxt_rde250_tunerconfig)) {
result = -EINVAL;
goto out_free;
}
@@ -486,9 +486,9 @@ static int dvb_init(struct cx231xx *dev)
/* define general-purpose callback pointer */
dvb->frontend->callback = cx231xx_tuner_callback;
- if (dvb_attach(xc5000_attach, dev->dvb->frontend,
+ if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
&dev->i2c_bus[1].i2c_adap,
- &cnxt_rde250_tunerconfig) < 0) {
+ &cnxt_rde250_tunerconfig)) {
result = -EINVAL;
goto out_free;
}
diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c
index 15826f98b688..c5771db3bfce 100644
--- a/drivers/media/video/cx231xx/cx231xx-input.c
+++ b/drivers/media/video/cx231xx/cx231xx-input.c
@@ -216,7 +216,7 @@ int cx231xx_ir_init(struct cx231xx *dev)
cx231xx_ir_start(ir);
/* all done */
- err = ir_input_register(ir->input, dev->board.ir_codes);
+ err = ir_input_register(ir->input, dev->board.ir_codes, NULL);
if (err)
goto err_out_stop;
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index 88c0d2481118..2ab97ad7b6fb 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -681,7 +681,7 @@ static char *cmd_to_str(int cmd)
case CX2341X_ENC_SET_VIDEO_ID:
return "SET_VIDEO_ID";
case CX2341X_ENC_SET_PCR_ID:
- return "SET_PCR_PID";
+ return "SET_PCR_ID";
case CX2341X_ENC_SET_FRAME_RATE:
return "SET_FRAME_RATE";
case CX2341X_ENC_SET_FRAME_SIZE:
@@ -693,7 +693,7 @@ static char *cmd_to_str(int cmd)
case CX2341X_ENC_SET_ASPECT_RATIO:
return "SET_ASPECT_RATIO";
case CX2341X_ENC_SET_DNR_FILTER_MODE:
- return "SET_DNR_FILTER_PROPS";
+ return "SET_DNR_FILTER_MODE";
case CX2341X_ENC_SET_DNR_FILTER_PROPS:
return "SET_DNR_FILTER_PROPS";
case CX2341X_ENC_SET_CORING_LEVELS:
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index 1ec48169277d..d639186f645d 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -274,6 +274,31 @@ struct cx23885_board cx23885_boards[] = {
.portb = CX23885_MPEG_DVB,
.portc = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_LEADTEK_WINFAST_PXTV1200] = {
+ .name = "LEADTEK WinFast PxTV1200",
+ .porta = CX23885_ANALOG_VIDEO,
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0x61,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN2_CH1 |
+ CX25840_VIN5_CH2 |
+ CX25840_NONE0_CH3,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_COMPOSITE1,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_SVIDEO_LUMA3 |
+ CX25840_SVIDEO_CHROMA4,
+ }, {
+ .type = CX23885_VMUX_COMPONENT,
+ .vmux = CX25840_VIN7_CH1 |
+ CX25840_VIN6_CH2 |
+ CX25840_VIN8_CH3 |
+ CX25840_COMPONENT_ON,
+ } },
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -417,6 +442,10 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x14f1,
.subdevice = 0x8578,
.card = CX23885_BOARD_MYGICA_X8558PRO,
+ }, {
+ .subvendor = 0x107d,
+ .subdevice = 0x6f22,
+ .card = CX23885_BOARD_LEADTEK_WINFAST_PXTV1200,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -617,6 +646,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
/* Tuner Reset Command */
bitmask = 0x04;
break;
@@ -769,6 +799,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
/* GPIO-2 xc3028 tuner reset */
/* The following GPIO's are on the internal AVCore (cx25840) */
@@ -1076,6 +1107,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_MYGICA_X8506:
case CX23885_BOARD_MAGICPRO_PROHDTVE2:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[2].i2c_adap,
"cx25840", "cx25840", 0x88 >> 1, NULL);
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index e45d2df08138..939079d7bbb9 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -542,6 +542,9 @@ static struct atbm8830_config mygica_x8558pro_atbm8830_cfg1 = {
.osc_clk_freq = 30400, /* in kHz */
.if_freq = 0, /* zero IF */
.zif_swap_iq = 1,
+ .agc_min = 0x2E,
+ .agc_max = 0xFF,
+ .agc_hold_loop = 0,
};
static struct max2165_config mygic_x8558pro_max2165_cfg1 = {
@@ -558,6 +561,9 @@ static struct atbm8830_config mygica_x8558pro_atbm8830_cfg2 = {
.osc_clk_freq = 30400, /* in kHz */
.if_freq = 0, /* zero IF */
.zif_swap_iq = 1,
+ .agc_min = 0x2E,
+ .agc_max = 0xFF,
+ .agc_hold_loop = 0,
};
static struct max2165_config mygic_x8558pro_max2165_cfg2 = {
@@ -994,15 +1000,8 @@ static int dvb_register(struct cx23885_tsport *port)
netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
memcpy(port->frontends.adapter.proposed_mac,
cinfo.port[port->nr - 1].mac, 6);
- printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC="
- "%02X:%02X:%02X:%02X:%02X:%02X\n",
- port->nr,
- port->frontends.adapter.proposed_mac[0],
- port->frontends.adapter.proposed_mac[1],
- port->frontends.adapter.proposed_mac[2],
- port->frontends.adapter.proposed_mac[3],
- port->frontends.adapter.proposed_mac[4],
- port->frontends.adapter.proposed_mac[5]);
+ printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n",
+ port->nr, port->frontends.adapter.proposed_mac);
netup_ci_init(port);
break;
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
index 768eec92ccf9..9c6620f86dca 100644
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -397,7 +397,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
dev->ir_input = ir;
cx23885_input_ir_start(dev);
- ret = ir_input_register(ir->dev, ir_codes);
+ ret = ir_input_register(ir->dev, ir_codes, NULL);
if (ret)
goto err_out_stop;
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index 8934d61cf660..2d3ac8b83dc3 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -36,6 +36,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include "cx23885-ioctl.h"
+#include "tuner-xc2028.h"
MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
@@ -1505,6 +1506,18 @@ int cx23885_video_register(struct cx23885_dev *dev)
tun_setup.tuner_callback = cx23885_tuner_callback;
v4l2_subdev_call(sd, tuner, s_type_addr, &tun_setup);
+
+ if (dev->board == CX23885_BOARD_LEADTEK_WINFAST_PXTV1200) {
+ struct xc2028_ctrl ctrl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64
+ };
+ struct v4l2_priv_tun_config cfg = {
+ .tuner = dev->tuner_type,
+ .priv = &ctrl
+ };
+ v4l2_subdev_call(sd, tuner, s_config, &cfg);
+ }
}
}
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index 08b3f6b136a0..0e3a98d243c5 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -81,6 +81,7 @@
#define CX23885_BOARD_COMPRO_VIDEOMATE_E800 25
#define CX23885_BOARD_HAUPPAUGE_HVR1290 26
#define CX23885_BOARD_MYGICA_X8558PRO 27
+#define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 385ecd58f1c0..f2461cd3de5a 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -734,10 +734,8 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n",
vid_input);
reg = vid_input & 0xff;
- if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON)
- is_composite = 0;
- else if ((vid_input & CX25840_COMPONENT_ON) == 0)
- is_composite = 1;
+ is_composite = !is_component &&
+ ((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON);
v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n",
reg, is_composite);
@@ -1347,30 +1345,59 @@ static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
}
#endif
+static int cx25840_s_audio_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 v;
+
+ if (is_cx2583x(state) || is_cx2388x(state) || is_cx231xx(state))
+ return 0;
+
+ v4l_dbg(1, cx25840_debug, client, "%s audio output\n",
+ enable ? "enable" : "disable");
+
+ if (enable) {
+ v = cx25840_read(client, 0x115) | 0x80;
+ cx25840_write(client, 0x115, v);
+ v = cx25840_read(client, 0x116) | 0x03;
+ cx25840_write(client, 0x116, v);
+ } else {
+ v = cx25840_read(client, 0x115) & ~(0x80);
+ cx25840_write(client, 0x115, v);
+ v = cx25840_read(client, 0x116) & ~(0x03);
+ cx25840_write(client, 0x116, v);
+ }
+ return 0;
+}
+
static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 v;
- v4l_dbg(1, cx25840_debug, client, "%s output\n",
+ v4l_dbg(1, cx25840_debug, client, "%s video output\n",
enable ? "enable" : "disable");
if (enable) {
if (is_cx2388x(state) || is_cx231xx(state)) {
- u8 v = (cx25840_read(client, 0x421) | 0x0b);
+ v = cx25840_read(client, 0x421) | 0x0b;
cx25840_write(client, 0x421, v);
} else {
- cx25840_write(client, 0x115,
- is_cx2583x(state) ? 0x0c : 0x8c);
- cx25840_write(client, 0x116,
- is_cx2583x(state) ? 0x04 : 0x07);
+ v = cx25840_read(client, 0x115) | 0x0c;
+ cx25840_write(client, 0x115, v);
+ v = cx25840_read(client, 0x116) | 0x04;
+ cx25840_write(client, 0x116, v);
}
} else {
if (is_cx2388x(state) || is_cx231xx(state)) {
- u8 v = cx25840_read(client, 0x421) & ~(0x0b);
+ v = cx25840_read(client, 0x421) & ~(0x0b);
cx25840_write(client, 0x421, v);
} else {
- cx25840_write(client, 0x115, 0x00);
- cx25840_write(client, 0x116, 0x00);
+ v = cx25840_read(client, 0x115) & ~(0x0c);
+ cx25840_write(client, 0x115, v);
+ v = cx25840_read(client, 0x116) & ~(0x04);
+ cx25840_write(client, 0x116, v);
}
}
return 0;
@@ -1601,6 +1628,7 @@ static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = {
static const struct v4l2_subdev_audio_ops cx25840_audio_ops = {
.s_clock_freq = cx25840_s_clock_freq,
.s_routing = cx25840_s_audio_routing,
+ .s_stream = cx25840_s_audio_stream,
};
static const struct v4l2_subdev_video_ops cx25840_video_ops = {
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 5a67445dd6ed..64b350df78e3 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -583,16 +583,18 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
{
snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
struct cx88_core *core=chip->core;
- int v, b;
+ int left, right, v, b;
int changed = 0;
u32 old;
- b = value->value.integer.value[1] - value->value.integer.value[0];
+ left = value->value.integer.value[0] & 0x3f;
+ right = value->value.integer.value[1] & 0x3f;
+ b = right - left;
if (b < 0) {
- v = 0x3f - value->value.integer.value[0];
+ v = 0x3f - left;
b = (-b) | 0x40;
} else {
- v = 0x3f - value->value.integer.value[1];
+ v = 0x3f - right;
}
/* Do we really know this will always be called with IRQs on? */
spin_lock_irq(&chip->reg_lock);
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index d844f2aaa01d..eaf0ee7de832 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1466,6 +1466,18 @@ static const struct cx88_board cx88_boards[] = {
.audioroute = 8,
},
},
+ [CX88_BOARD_SAMSUNG_SMT_7020] = {
+ .name = "Samsung SMT 7020 DVB-S",
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = { {
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ } },
+ .mpeg = CX88_MPEG_DVB,
+ },
[CX88_BOARD_ADSTECH_PTV_390] = {
.name = "ADS Tech Instant Video PCI",
.tuner_type = TUNER_ABSENT,
@@ -2355,6 +2367,14 @@ static const struct cx88_subid cx88_subids[] = {
.subvendor = 0x0070,
.subdevice = 0x1404,
.card = CX88_BOARD_HAUPPAUGE_HVR3000,
+ }, {
+ .subvendor = 0x18ac,
+ .subdevice = 0xdc00,
+ .card = CX88_BOARD_SAMSUNG_SMT_7020,
+ }, {
+ .subvendor = 0x18ac,
+ .subdevice = 0xdccd,
+ .card = CX88_BOARD_SAMSUNG_SMT_7020,
},{
.subvendor = 0x1461,
.subdevice = 0xc111, /* AverMedia M150-D */
@@ -2633,6 +2653,9 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */
/* known */
break;
+ case CX88_BOARD_SAMSUNG_SMT_7020:
+ cx_set(MO_GP0_IO, 0x008989FF);
+ break;
default:
warn_printk(core, "warning: unknown hauppauge model #%d\n",
tv.model);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index b14296923250..94ab862f0219 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -674,6 +674,194 @@ static int cx8802_alloc_frontends(struct cx8802_dev *dev)
return 0;
}
+
+
+static u8 samsung_smt_7020_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x7D,
+ 0x05, 0x0F,
+ 0x06, 0x02,
+ 0x07, 0x00,
+ 0x08, 0x60,
+
+ 0x0A, 0xC2,
+ 0x0B, 0x00,
+ 0x0C, 0x01,
+ 0x0D, 0x81,
+ 0x0E, 0x44,
+ 0x0F, 0x09,
+ 0x10, 0x3C,
+ 0x11, 0x84,
+ 0x12, 0xDA,
+ 0x13, 0x99,
+ 0x14, 0x8D,
+ 0x15, 0xCE,
+ 0x16, 0xE8,
+ 0x17, 0x43,
+ 0x18, 0x1C,
+ 0x19, 0x1B,
+ 0x1A, 0x1D,
+
+ 0x1C, 0x12,
+ 0x1D, 0x00,
+ 0x1E, 0x00,
+ 0x1F, 0x00,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+
+ 0x28, 0x02,
+ 0x29, 0x28,
+ 0x2A, 0x14,
+ 0x2B, 0x0F,
+ 0x2C, 0x09,
+ 0x2D, 0x05,
+
+ 0x31, 0x1F,
+ 0x32, 0x19,
+ 0x33, 0xFC,
+ 0x34, 0x13,
+ 0xff, 0xff,
+};
+
+
+static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct cx8802_dev *dev = fe->dvb->priv;
+ u8 buf[4];
+ u32 div;
+ struct i2c_msg msg = {
+ .addr = 0x61,
+ .flags = 0,
+ .buf = buf,
+ .len = sizeof(buf) };
+
+ div = params->frequency / 125;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x84; /* 0xC4 */
+ buf[3] = 0x00;
+
+ if (params->frequency < 1500000)
+ buf[3] |= 0x10;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(&dev->core->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static int samsung_smt_7020_set_tone(struct dvb_frontend *fe,
+ fe_sec_tone_mode_t tone)
+{
+ struct cx8802_dev *dev = fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ cx_set(MO_GP0_IO, 0x0800);
+
+ switch (tone) {
+ case SEC_TONE_ON:
+ cx_set(MO_GP0_IO, 0x08);
+ break;
+ case SEC_TONE_OFF:
+ cx_clear(MO_GP0_IO, 0x08);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
+{
+ struct cx8802_dev *dev = fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ u8 data;
+ struct i2c_msg msg = {
+ .addr = 8,
+ .flags = 0,
+ .buf = &data,
+ .len = sizeof(data) };
+
+ cx_set(MO_GP0_IO, 0x8000);
+
+ switch (voltage) {
+ case SEC_VOLTAGE_OFF:
+ break;
+ case SEC_VOLTAGE_13:
+ data = ISL6421_EN1 | ISL6421_LLC1;
+ cx_clear(MO_GP0_IO, 0x80);
+ break;
+ case SEC_VOLTAGE_18:
+ data = ISL6421_EN1 | ISL6421_LLC1 | ISL6421_VSEL1;
+ cx_clear(MO_GP0_IO, 0x80);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ return (i2c_transfer(&dev->core->i2c_adap, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int samsung_smt_7020_stv0299_set_symbol_rate(struct dvb_frontend *fe,
+ u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) {
+ aclk = 0xb7;
+ bclk = 0x47;
+ } else if (srate < 3000000) {
+ aclk = 0xb7;
+ bclk = 0x4b;
+ } else if (srate < 7000000) {
+ aclk = 0xb7;
+ bclk = 0x4f;
+ } else if (srate < 14000000) {
+ aclk = 0xb7;
+ bclk = 0x53;
+ } else if (srate < 30000000) {
+ aclk = 0xb6;
+ bclk = 0x53;
+ } else if (srate < 45000000) {
+ aclk = 0xb4;
+ bclk = 0x51;
+ }
+
+ stv0299_writereg(fe, 0x13, aclk);
+ stv0299_writereg(fe, 0x14, bclk);
+ stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg(fe, 0x21, ratio & 0xf0);
+
+ return 0;
+}
+
+
+static struct stv0299_config samsung_stv0299_config = {
+ .demod_address = 0x68,
+ .inittab = samsung_smt_7020_inittab,
+ .mclk = 88000000UL,
+ .invert = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0299_LOCKOUTPUT_LK,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = samsung_smt_7020_stv0299_set_symbol_rate,
+};
+
static int dvb_register(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
@@ -1203,6 +1391,32 @@ static int dvb_register(struct cx8802_dev *dev)
}
break;
}
+ case CX88_BOARD_SAMSUNG_SMT_7020:
+ dev->ts_gen_cntrl = 0x08;
+
+ cx_set(MO_GP0_IO, 0x0101);
+
+ cx_clear(MO_GP0_IO, 0x01);
+ mdelay(100);
+ cx_set(MO_GP0_IO, 0x01);
+ mdelay(200);
+
+ fe0->dvb.frontend = dvb_attach(stv0299_attach,
+ &samsung_stv0299_config,
+ &dev->core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.set_params =
+ samsung_smt_7020_tuner_set_params;
+ fe0->dvb.frontend->tuner_priv =
+ &dev->core->i2c_adap;
+ fe0->dvb.frontend->ops.set_voltage =
+ samsung_smt_7020_set_voltage;
+ fe0->dvb.frontend->ops.set_tone =
+ samsung_smt_7020_set_tone;
+ }
+
+ break;
+
default:
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
core->name);
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index f9fda18b410c..de180d4d5a21 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -192,7 +192,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
struct cx88_IR *ir;
struct input_dev *input_dev;
struct ir_scancode_table *ir_codes = NULL;
- int ir_type = IR_TYPE_OTHER;
+ u64 ir_type = IR_TYPE_OTHER;
int err = -ENOMEM;
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
@@ -383,7 +383,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
cx88_ir_start(core, ir);
/* all done */
- err = ir_input_register(ir->input, ir_codes);
+ err = ir_input_register(ir->input, ir_codes, NULL);
if (err)
goto err_out_stop;
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index bb5104893411..338af77f7f01 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -110,6 +110,9 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
case CX88_BOARD_PCHDTV_HD5500:
cx_write(TS_SOP_STAT, 1<<13);
break;
+ case CX88_BOARD_SAMSUNG_SMT_7020:
+ cx_write(TS_SOP_STAT, 0x00);
+ break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index b1499bf604ea..48b6c04fb497 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -239,6 +239,7 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_WINFAST_DTV1800H 81
#define CX88_BOARD_WINFAST_DTV2000H_J 82
#define CX88_BOARD_PROF_7301 83
+#define CX88_BOARD_SAMSUNG_SMT_7020 84
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
index ee43876adb06..0f505086774c 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/media/video/dabusb.c
@@ -616,10 +616,12 @@ static int dabusb_open (struct inode *inode, struct file *file)
{
int devnum = iminor(inode);
pdabusb_t s;
+ int r;
if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
return -EIO;
+ lock_kernel();
s = &dabusb[devnum - DABUSB_MINOR];
dbg("dabusb_open");
@@ -634,6 +636,7 @@ static int dabusb_open (struct inode *inode, struct file *file)
msleep_interruptible(500);
if (signal_pending (current)) {
+ unlock_kernel();
return -EAGAIN;
}
mutex_lock(&s->mutex);
@@ -641,6 +644,7 @@ static int dabusb_open (struct inode *inode, struct file *file)
if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
mutex_unlock(&s->mutex);
dev_err(&s->usbdev->dev, "set_interface failed\n");
+ unlock_kernel();
return -EINVAL;
}
s->opened = 1;
@@ -649,7 +653,9 @@ static int dabusb_open (struct inode *inode, struct file *file)
file->f_pos = 0;
file->private_data = s;
- return nonseekable_open(inode, file);
+ r = nonseekable_open(inode, file);
+ unlock_kernel();
+ return r;
}
static int dabusb_release (struct inode *inode, struct file *file)
@@ -913,6 +919,8 @@ static void __exit dabusb_cleanup (void)
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("dabusb/firmware.fw");
+MODULE_FIRMWARE("dabusb/bitstream.bin");
module_param(buffers, int, 0);
MODULE_PARM_DESC (buffers, "Number of buffers (default=256)");
diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile
index 1a8b8f3f182e..a37955745aaa 100644
--- a/drivers/media/video/davinci/Makefile
+++ b/drivers/media/video/davinci/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o
obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o
obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o
obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o
+obj-$(CONFIG_VIDEO_ISIF) += isif.o
diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c
index 314390016370..c29ac88ffd78 100644
--- a/drivers/media/video/davinci/dm355_ccdc.c
+++ b/drivers/media/video/davinci/dm355_ccdc.c
@@ -37,8 +37,12 @@
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/videodev2.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
#include <media/davinci/dm355_ccdc.h>
#include <media/davinci/vpss.h>
+
#include "dm355_ccdc_regs.h"
#include "ccdc_hw_device.h"
@@ -46,67 +50,75 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CCDC Driver for DM355");
MODULE_AUTHOR("Texas Instruments");
-static struct device *dev;
-
-/* Object for CCDC raw mode */
-static struct ccdc_params_raw ccdc_hw_params_raw = {
- .pix_fmt = CCDC_PIXFMT_RAW,
- .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
- .win = CCDC_WIN_VGA,
- .fid_pol = VPFE_PINPOL_POSITIVE,
- .vd_pol = VPFE_PINPOL_POSITIVE,
- .hd_pol = VPFE_PINPOL_POSITIVE,
- .gain = {
- .r_ye = 256,
- .gb_g = 256,
- .gr_cy = 256,
- .b_mg = 256
- },
- .config_params = {
- .datasft = 2,
- .data_sz = CCDC_DATA_10BITS,
- .mfilt1 = CCDC_NO_MEDIAN_FILTER1,
- .mfilt2 = CCDC_NO_MEDIAN_FILTER2,
- .alaw = {
- .gama_wd = 2,
+static struct ccdc_oper_config {
+ struct device *dev;
+ /* CCDC interface type */
+ enum vpfe_hw_if_type if_type;
+ /* Raw Bayer configuration */
+ struct ccdc_params_raw bayer;
+ /* YCbCr configuration */
+ struct ccdc_params_ycbcr ycbcr;
+ /* Master clock */
+ struct clk *mclk;
+ /* slave clock */
+ struct clk *sclk;
+ /* ccdc base address */
+ void __iomem *base_addr;
+} ccdc_cfg = {
+ /* Raw configurations */
+ .bayer = {
+ .pix_fmt = CCDC_PIXFMT_RAW,
+ .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+ .win = CCDC_WIN_VGA,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .gain = {
+ .r_ye = 256,
+ .gb_g = 256,
+ .gr_cy = 256,
+ .b_mg = 256
},
- .blk_clamp = {
- .sample_pixel = 1,
- .dc_sub = 25
- },
- .col_pat_field0 = {
- .olop = CCDC_GREEN_BLUE,
- .olep = CCDC_BLUE,
- .elop = CCDC_RED,
- .elep = CCDC_GREEN_RED
- },
- .col_pat_field1 = {
- .olop = CCDC_GREEN_BLUE,
- .olep = CCDC_BLUE,
- .elop = CCDC_RED,
- .elep = CCDC_GREEN_RED
+ .config_params = {
+ .datasft = 2,
+ .mfilt1 = CCDC_NO_MEDIAN_FILTER1,
+ .mfilt2 = CCDC_NO_MEDIAN_FILTER2,
+ .alaw = {
+ .gama_wd = 2,
+ },
+ .blk_clamp = {
+ .sample_pixel = 1,
+ .dc_sub = 25
+ },
+ .col_pat_field0 = {
+ .olop = CCDC_GREEN_BLUE,
+ .olep = CCDC_BLUE,
+ .elop = CCDC_RED,
+ .elep = CCDC_GREEN_RED
+ },
+ .col_pat_field1 = {
+ .olop = CCDC_GREEN_BLUE,
+ .olep = CCDC_BLUE,
+ .elop = CCDC_RED,
+ .elep = CCDC_GREEN_RED
+ },
},
},
+ /* YCbCr configuration */
+ .ycbcr = {
+ .win = CCDC_WIN_PAL,
+ .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+ .frm_fmt = CCDC_FRMFMT_INTERLACED,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .bt656_enable = 1,
+ .pix_order = CCDC_PIXORDER_CBYCRY,
+ .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
+ },
};
-/* Object for CCDC ycbcr mode */
-static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = {
- .win = CCDC_WIN_PAL,
- .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
- .frm_fmt = CCDC_FRMFMT_INTERLACED,
- .fid_pol = VPFE_PINPOL_POSITIVE,
- .vd_pol = VPFE_PINPOL_POSITIVE,
- .hd_pol = VPFE_PINPOL_POSITIVE,
- .bt656_enable = 1,
- .pix_order = CCDC_PIXORDER_CBYCRY,
- .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
-};
-
-static enum vpfe_hw_if_type ccdc_if_type;
-static void *__iomem ccdc_base_addr;
-static int ccdc_addr_size;
-
/* Raw Bayer formats */
static u32 ccdc_raw_bayer_pix_formats[] =
{V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
@@ -118,18 +130,12 @@ static u32 ccdc_raw_yuv_pix_formats[] =
/* register access routines */
static inline u32 regr(u32 offset)
{
- return __raw_readl(ccdc_base_addr + offset);
+ return __raw_readl(ccdc_cfg.base_addr + offset);
}
static inline void regw(u32 val, u32 offset)
{
- __raw_writel(val, ccdc_base_addr + offset);
-}
-
-static void ccdc_set_ccdc_base(void *addr, int size)
-{
- ccdc_base_addr = addr;
- ccdc_addr_size = size;
+ __raw_writel(val, ccdc_cfg.base_addr + offset);
}
static void ccdc_enable(int en)
@@ -153,12 +159,12 @@ static void ccdc_enable_output_to_sdram(int en)
static void ccdc_config_gain_offset(void)
{
/* configure gain */
- regw(ccdc_hw_params_raw.gain.r_ye, RYEGAIN);
- regw(ccdc_hw_params_raw.gain.gr_cy, GRCYGAIN);
- regw(ccdc_hw_params_raw.gain.gb_g, GBGGAIN);
- regw(ccdc_hw_params_raw.gain.b_mg, BMGGAIN);
+ regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN);
+ regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN);
+ regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN);
+ regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN);
/* configure offset */
- regw(ccdc_hw_params_raw.ccdc_offset, OFFSET);
+ regw(ccdc_cfg.bayer.ccdc_offset, OFFSET);
}
/*
@@ -169,7 +175,7 @@ static int ccdc_restore_defaults(void)
{
int i;
- dev_dbg(dev, "\nstarting ccdc_restore_defaults...");
+ dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults...");
/* set all registers to zero */
for (i = 0; i <= CCDC_REG_LAST; i += 4)
regw(0, i);
@@ -180,30 +186,29 @@ static int ccdc_restore_defaults(void)
regw(CULH_DEFAULT, CULH);
regw(CULV_DEFAULT, CULV);
/* Set default Gain and Offset */
- ccdc_hw_params_raw.gain.r_ye = GAIN_DEFAULT;
- ccdc_hw_params_raw.gain.gb_g = GAIN_DEFAULT;
- ccdc_hw_params_raw.gain.gr_cy = GAIN_DEFAULT;
- ccdc_hw_params_raw.gain.b_mg = GAIN_DEFAULT;
+ ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT;
+ ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT;
+ ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT;
+ ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT;
ccdc_config_gain_offset();
regw(OUTCLIP_DEFAULT, OUTCLIP);
regw(LSCCFG2_DEFAULT, LSCCFG2);
/* select ccdc input */
if (vpss_select_ccdc_source(VPSS_CCDCIN)) {
- dev_dbg(dev, "\ncouldn't select ccdc input source");
+ dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source");
return -EFAULT;
}
/* select ccdc clock */
if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) {
- dev_dbg(dev, "\ncouldn't enable ccdc clock");
+ dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock");
return -EFAULT;
}
- dev_dbg(dev, "\nEnd of ccdc_restore_defaults...");
+ dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults...");
return 0;
}
static int ccdc_open(struct device *device)
{
- dev = device;
return ccdc_restore_defaults();
}
@@ -226,7 +231,7 @@ static void ccdc_setwin(struct v4l2_rect *image_win,
int vert_start, vert_nr_lines;
int mid_img = 0;
- dev_dbg(dev, "\nStarting ccdc_setwin...");
+ dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
/*
* ppc - per pixel count. indicates how many pixels per cell
@@ -260,45 +265,46 @@ static void ccdc_setwin(struct v4l2_rect *image_win,
regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0);
regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1);
regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV);
- dev_dbg(dev, "\nEnd of ccdc_setwin...");
+ dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
}
static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
{
if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT ||
ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) {
- dev_dbg(dev, "Invalid value of data shift\n");
+ dev_dbg(ccdc_cfg.dev, "Invalid value of data shift\n");
return -EINVAL;
}
if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 ||
ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) {
- dev_dbg(dev, "Invalid value of median filter1\n");
+ dev_dbg(ccdc_cfg.dev, "Invalid value of median filter1\n");
return -EINVAL;
}
if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 ||
ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) {
- dev_dbg(dev, "Invalid value of median filter2\n");
+ dev_dbg(ccdc_cfg.dev, "Invalid value of median filter2\n");
return -EINVAL;
}
if ((ccdcparam->med_filt_thres < 0) ||
(ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) {
- dev_dbg(dev, "Invalid value of median filter threshold\n");
+ dev_dbg(ccdc_cfg.dev,
+ "Invalid value of median filter thresold\n");
return -EINVAL;
}
if (ccdcparam->data_sz < CCDC_DATA_16BITS ||
ccdcparam->data_sz > CCDC_DATA_8BITS) {
- dev_dbg(dev, "Invalid value of data size\n");
+ dev_dbg(ccdc_cfg.dev, "Invalid value of data size\n");
return -EINVAL;
}
if (ccdcparam->alaw.enable) {
if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 ||
ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) {
- dev_dbg(dev, "Invalid value of ALAW\n");
+ dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n");
return -EINVAL;
}
}
@@ -306,12 +312,14 @@ static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
if (ccdcparam->blk_clamp.b_clamp_enable) {
if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS ||
ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) {
- dev_dbg(dev, "Invalid value of sample pixel\n");
+ dev_dbg(ccdc_cfg.dev,
+ "Invalid value of sample pixel\n");
return -EINVAL;
}
if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES ||
ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) {
- dev_dbg(dev, "Invalid value of sample lines\n");
+ dev_dbg(ccdc_cfg.dev,
+ "Invalid value of sample lines\n");
return -EINVAL;
}
}
@@ -325,18 +333,18 @@ static int ccdc_set_params(void __user *params)
int x;
/* only raw module parameters can be set through the IOCTL */
- if (ccdc_if_type != VPFE_RAW_BAYER)
+ if (ccdc_cfg.if_type != VPFE_RAW_BAYER)
return -EINVAL;
x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
if (x) {
- dev_dbg(dev, "ccdc_set_params: error in copying ccdc"
+ dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc"
"params, %d\n", x);
return -EFAULT;
}
if (!validate_ccdc_param(&ccdc_raw_params)) {
- memcpy(&ccdc_hw_params_raw.config_params,
+ memcpy(&ccdc_cfg.bayer.config_params,
&ccdc_raw_params,
sizeof(ccdc_raw_params));
return 0;
@@ -347,11 +355,11 @@ static int ccdc_set_params(void __user *params)
/* This function will configure CCDC for YCbCr video capture */
static void ccdc_config_ycbcr(void)
{
- struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr;
+ struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
u32 temp;
/* first set the CCDC power on defaults values in all registers */
- dev_dbg(dev, "\nStarting ccdc_config_ycbcr...");
+ dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
ccdc_restore_defaults();
/* configure pixel format & video frame format */
@@ -403,7 +411,7 @@ static void ccdc_config_ycbcr(void)
regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST);
}
- dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n");
+ dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
}
/*
@@ -483,7 +491,7 @@ int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
*/
if (count) {
- dev_err(dev, "defect table write timeout !!!\n");
+ dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n");
return -1;
}
return 0;
@@ -605,12 +613,12 @@ static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0,
/* This function will configure CCDC for Raw mode image capture */
static int ccdc_config_raw(void)
{
- struct ccdc_params_raw *params = &ccdc_hw_params_raw;
+ struct ccdc_params_raw *params = &ccdc_cfg.bayer;
struct ccdc_config_params_raw *config_params =
- &ccdc_hw_params_raw.config_params;
+ &ccdc_cfg.bayer.config_params;
unsigned int val;
- dev_dbg(dev, "\nStarting ccdc_config_raw...");
+ dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
/* restore power on defaults to register */
ccdc_restore_defaults();
@@ -659,7 +667,7 @@ static int ccdc_config_raw(void)
val |= (config_params->datasft & CCDC_DATASFT_MASK) <<
CCDC_DATASFT_SHIFT;
regw(val , MODESET);
- dev_dbg(dev, "\nWriting 0x%x to MODESET...\n", val);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val);
/* Configure the Median Filter threshold */
regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT);
@@ -681,7 +689,7 @@ static int ccdc_config_raw(void)
(config_params->mfilt2 << CCDC_MFILT2_SHIFT));
regw(val, GAMMAWD);
- dev_dbg(dev, "\nWriting 0x%x to GAMMAWD...\n", val);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val);
/* configure video window */
ccdc_setwin(&params->win, params->frm_fmt, 1);
@@ -706,7 +714,7 @@ static int ccdc_config_raw(void)
/* Configure the Gain & offset control */
ccdc_config_gain_offset();
- dev_dbg(dev, "\nWriting %x to COLPTN...\n", val);
+ dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val);
/* Configure DATAOFST register */
val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) <<
@@ -726,7 +734,7 @@ static int ccdc_config_raw(void)
CCDC_HSIZE_VAL_MASK;
/* adjust to multiple of 32 */
- dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n",
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
(((params->win.width) + 31) >> 5) &
CCDC_HSIZE_VAL_MASK);
} else {
@@ -734,7 +742,7 @@ static int ccdc_config_raw(void)
val |= (((params->win.width * 2) + 31) >> 5) &
CCDC_HSIZE_VAL_MASK;
- dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n",
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
(((params->win.width * 2) + 31) >> 5) &
CCDC_HSIZE_VAL_MASK);
}
@@ -745,34 +753,34 @@ static int ccdc_config_raw(void)
if (params->image_invert_enable) {
/* For interlace inverse mode */
regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST);
- dev_dbg(dev, "\nWriting %x to SDOFST...\n",
+ dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
CCDC_SDOFST_INTERLACE_INVERSE);
} else {
/* For interlace non inverse mode */
regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST);
- dev_dbg(dev, "\nWriting %x to SDOFST...\n",
+ dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
CCDC_SDOFST_INTERLACE_NORMAL);
}
} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
if (params->image_invert_enable) {
/* For progessive inverse mode */
regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST);
- dev_dbg(dev, "\nWriting %x to SDOFST...\n",
+ dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
CCDC_SDOFST_PROGRESSIVE_INVERSE);
} else {
/* For progessive non inverse mode */
regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST);
- dev_dbg(dev, "\nWriting %x to SDOFST...\n",
+ dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
CCDC_SDOFST_PROGRESSIVE_NORMAL);
}
}
- dev_dbg(dev, "\nend of ccdc_config_raw...");
+ dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
return 0;
}
static int ccdc_configure(void)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
return ccdc_config_raw();
else
ccdc_config_ycbcr();
@@ -781,23 +789,23 @@ static int ccdc_configure(void)
static int ccdc_set_buftype(enum ccdc_buftype buf_type)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
- ccdc_hw_params_raw.buf_type = buf_type;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_cfg.bayer.buf_type = buf_type;
else
- ccdc_hw_params_ycbcr.buf_type = buf_type;
+ ccdc_cfg.ycbcr.buf_type = buf_type;
return 0;
}
static enum ccdc_buftype ccdc_get_buftype(void)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
- return ccdc_hw_params_raw.buf_type;
- return ccdc_hw_params_ycbcr.buf_type;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ return ccdc_cfg.bayer.buf_type;
+ return ccdc_cfg.ycbcr.buf_type;
}
static int ccdc_enum_pix(u32 *pix, int i)
{
int ret = -EINVAL;
- if (ccdc_if_type == VPFE_RAW_BAYER) {
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
*pix = ccdc_raw_bayer_pix_formats[i];
ret = 0;
@@ -813,20 +821,19 @@ static int ccdc_enum_pix(u32 *pix, int i)
static int ccdc_set_pixel_format(u32 pixfmt)
{
- struct ccdc_a_law *alaw =
- &ccdc_hw_params_raw.config_params.alaw;
+ struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
- if (ccdc_if_type == VPFE_RAW_BAYER) {
- ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+ ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
if (pixfmt == V4L2_PIX_FMT_SBGGR8)
alaw->enable = 1;
else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
return -EINVAL;
} else {
if (pixfmt == V4L2_PIX_FMT_YUYV)
- ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+ ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
else if (pixfmt == V4L2_PIX_FMT_UYVY)
- ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
else
return -EINVAL;
}
@@ -834,17 +841,16 @@ static int ccdc_set_pixel_format(u32 pixfmt)
}
static u32 ccdc_get_pixel_format(void)
{
- struct ccdc_a_law *alaw =
- &ccdc_hw_params_raw.config_params.alaw;
+ struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
u32 pixfmt;
- if (ccdc_if_type == VPFE_RAW_BAYER)
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
if (alaw->enable)
pixfmt = V4L2_PIX_FMT_SBGGR8;
else
pixfmt = V4L2_PIX_FMT_SBGGR16;
else {
- if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+ if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
pixfmt = V4L2_PIX_FMT_YUYV;
else
pixfmt = V4L2_PIX_FMT_UYVY;
@@ -853,53 +859,53 @@ static u32 ccdc_get_pixel_format(void)
}
static int ccdc_set_image_window(struct v4l2_rect *win)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
- ccdc_hw_params_raw.win = *win;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_cfg.bayer.win = *win;
else
- ccdc_hw_params_ycbcr.win = *win;
+ ccdc_cfg.ycbcr.win = *win;
return 0;
}
static void ccdc_get_image_window(struct v4l2_rect *win)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
- *win = ccdc_hw_params_raw.win;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ *win = ccdc_cfg.bayer.win;
else
- *win = ccdc_hw_params_ycbcr.win;
+ *win = ccdc_cfg.ycbcr.win;
}
static unsigned int ccdc_get_line_length(void)
{
struct ccdc_config_params_raw *config_params =
- &ccdc_hw_params_raw.config_params;
+ &ccdc_cfg.bayer.config_params;
unsigned int len;
- if (ccdc_if_type == VPFE_RAW_BAYER) {
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
if ((config_params->alaw.enable) ||
(config_params->data_sz == CCDC_DATA_8BITS))
- len = ccdc_hw_params_raw.win.width;
+ len = ccdc_cfg.bayer.win.width;
else
- len = ccdc_hw_params_raw.win.width * 2;
+ len = ccdc_cfg.bayer.win.width * 2;
} else
- len = ccdc_hw_params_ycbcr.win.width * 2;
+ len = ccdc_cfg.ycbcr.win.width * 2;
return ALIGN(len, 32);
}
static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
- ccdc_hw_params_raw.frm_fmt = frm_fmt;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_cfg.bayer.frm_fmt = frm_fmt;
else
- ccdc_hw_params_ycbcr.frm_fmt = frm_fmt;
+ ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
return 0;
}
static enum ccdc_frmfmt ccdc_get_frame_format(void)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
- return ccdc_hw_params_raw.frm_fmt;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ return ccdc_cfg.bayer.frm_fmt;
else
- return ccdc_hw_params_ycbcr.frm_fmt;
+ return ccdc_cfg.ycbcr.frm_fmt;
}
static int ccdc_getfid(void)
@@ -916,14 +922,14 @@ static inline void ccdc_setfbaddr(unsigned long addr)
static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
{
- ccdc_if_type = params->if_type;
+ ccdc_cfg.if_type = params->if_type;
switch (params->if_type) {
case VPFE_BT656:
case VPFE_YCBCR_SYNC_16:
case VPFE_YCBCR_SYNC_8:
- ccdc_hw_params_ycbcr.vd_pol = params->vdpol;
- ccdc_hw_params_ycbcr.hd_pol = params->hdpol;
+ ccdc_cfg.ycbcr.vd_pol = params->vdpol;
+ ccdc_cfg.ycbcr.hd_pol = params->hdpol;
break;
default:
/* TODO add support for raw bayer here */
@@ -938,7 +944,6 @@ static struct ccdc_hw_device ccdc_hw_dev = {
.hw_ops = {
.open = ccdc_open,
.close = ccdc_close,
- .set_ccdc_base = ccdc_set_ccdc_base,
.enable = ccdc_enable,
.enable_out_to_sdram = ccdc_enable_output_to_sdram,
.set_hw_if_params = ccdc_set_hw_if_params,
@@ -959,19 +964,118 @@ static struct ccdc_hw_device ccdc_hw_dev = {
},
};
-static int __init dm355_ccdc_init(void)
+static int __init dm355_ccdc_probe(struct platform_device *pdev)
{
- printk(KERN_NOTICE "dm355_ccdc_init\n");
- if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
- return -1;
- printk(KERN_NOTICE "%s is registered with vpfe.\n",
- ccdc_hw_dev.name);
+ void (*setup_pinmux)(void);
+ struct resource *res;
+ int status = 0;
+
+ /*
+ * first try to register with vpfe. If not correct platform, then we
+ * don't have to iomap
+ */
+ status = vpfe_register_ccdc_device(&ccdc_hw_dev);
+ if (status < 0)
+ return status;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ status = -ENODEV;
+ goto fail_nores;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), res->name);
+ if (!res) {
+ status = -EBUSY;
+ goto fail_nores;
+ }
+
+ ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
+ if (!ccdc_cfg.base_addr) {
+ status = -ENOMEM;
+ goto fail_nomem;
+ }
+
+ /* Get and enable Master clock */
+ ccdc_cfg.mclk = clk_get(&pdev->dev, "master");
+ if (IS_ERR(ccdc_cfg.mclk)) {
+ status = PTR_ERR(ccdc_cfg.mclk);
+ goto fail_nomap;
+ }
+ if (clk_enable(ccdc_cfg.mclk)) {
+ status = -ENODEV;
+ goto fail_mclk;
+ }
+
+ /* Get and enable Slave clock */
+ ccdc_cfg.sclk = clk_get(&pdev->dev, "slave");
+ if (IS_ERR(ccdc_cfg.sclk)) {
+ status = PTR_ERR(ccdc_cfg.sclk);
+ goto fail_mclk;
+ }
+ if (clk_enable(ccdc_cfg.sclk)) {
+ status = -ENODEV;
+ goto fail_sclk;
+ }
+
+ /* Platform data holds setup_pinmux function ptr */
+ if (NULL == pdev->dev.platform_data) {
+ status = -ENODEV;
+ goto fail_sclk;
+ }
+ setup_pinmux = pdev->dev.platform_data;
+ /*
+ * setup Mux configuration for ccdc which may be different for
+ * different SoCs using this CCDC
+ */
+ setup_pinmux();
+ ccdc_cfg.dev = &pdev->dev;
+ printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
return 0;
+fail_sclk:
+ clk_put(ccdc_cfg.sclk);
+fail_mclk:
+ clk_put(ccdc_cfg.mclk);
+fail_nomap:
+ iounmap(ccdc_cfg.base_addr);
+fail_nomem:
+ release_mem_region(res->start, resource_size(res));
+fail_nores:
+ vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+ return status;
}
-static void __exit dm355_ccdc_exit(void)
+static int dm355_ccdc_remove(struct platform_device *pdev)
{
+ struct resource *res;
+
+ clk_put(ccdc_cfg.mclk);
+ clk_put(ccdc_cfg.sclk);
+ iounmap(ccdc_cfg.base_addr);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+ return 0;
+}
+
+static struct platform_driver dm355_ccdc_driver = {
+ .driver = {
+ .name = "dm355_ccdc",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(dm355_ccdc_remove),
+ .probe = dm355_ccdc_probe,
+};
+
+static int __init dm355_ccdc_init(void)
+{
+ return platform_driver_register(&dm355_ccdc_driver);
+}
+
+static void __exit dm355_ccdc_exit(void)
+{
+ platform_driver_unregister(&dm355_ccdc_driver);
}
module_init(dm355_ccdc_init);
diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c
index d5fa193f32d2..0c394cade22a 100644
--- a/drivers/media/video/davinci/dm644x_ccdc.c
+++ b/drivers/media/video/davinci/dm644x_ccdc.c
@@ -37,8 +37,12 @@
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/videodev2.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
#include <media/davinci/dm644x_ccdc.h>
#include <media/davinci/vpss.h>
+
#include "dm644x_ccdc_regs.h"
#include "ccdc_hw_device.h"
@@ -46,32 +50,44 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CCDC Driver for DM6446");
MODULE_AUTHOR("Texas Instruments");
-static struct device *dev;
-
-/* Object for CCDC raw mode */
-static struct ccdc_params_raw ccdc_hw_params_raw = {
- .pix_fmt = CCDC_PIXFMT_RAW,
- .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
- .win = CCDC_WIN_VGA,
- .fid_pol = VPFE_PINPOL_POSITIVE,
- .vd_pol = VPFE_PINPOL_POSITIVE,
- .hd_pol = VPFE_PINPOL_POSITIVE,
- .config_params = {
- .data_sz = CCDC_DATA_10BITS,
+static struct ccdc_oper_config {
+ struct device *dev;
+ /* CCDC interface type */
+ enum vpfe_hw_if_type if_type;
+ /* Raw Bayer configuration */
+ struct ccdc_params_raw bayer;
+ /* YCbCr configuration */
+ struct ccdc_params_ycbcr ycbcr;
+ /* Master clock */
+ struct clk *mclk;
+ /* slave clock */
+ struct clk *sclk;
+ /* ccdc base address */
+ void __iomem *base_addr;
+} ccdc_cfg = {
+ /* Raw configurations */
+ .bayer = {
+ .pix_fmt = CCDC_PIXFMT_RAW,
+ .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+ .win = CCDC_WIN_VGA,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .config_params = {
+ .data_sz = CCDC_DATA_10BITS,
+ },
+ },
+ .ycbcr = {
+ .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+ .frm_fmt = CCDC_FRMFMT_INTERLACED,
+ .win = CCDC_WIN_PAL,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .bt656_enable = 1,
+ .pix_order = CCDC_PIXORDER_CBYCRY,
+ .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
},
-};
-
-/* Object for CCDC ycbcr mode */
-static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = {
- .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
- .frm_fmt = CCDC_FRMFMT_INTERLACED,
- .win = CCDC_WIN_PAL,
- .fid_pol = VPFE_PINPOL_POSITIVE,
- .vd_pol = VPFE_PINPOL_POSITIVE,
- .hd_pol = VPFE_PINPOL_POSITIVE,
- .bt656_enable = 1,
- .pix_order = CCDC_PIXORDER_CBYCRY,
- .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
};
#define CCDC_MAX_RAW_YUV_FORMATS 2
@@ -84,25 +100,15 @@ static u32 ccdc_raw_bayer_pix_formats[] =
static u32 ccdc_raw_yuv_pix_formats[] =
{V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
-static void *__iomem ccdc_base_addr;
-static int ccdc_addr_size;
-static enum vpfe_hw_if_type ccdc_if_type;
-
/* register access routines */
static inline u32 regr(u32 offset)
{
- return __raw_readl(ccdc_base_addr + offset);
+ return __raw_readl(ccdc_cfg.base_addr + offset);
}
static inline void regw(u32 val, u32 offset)
{
- __raw_writel(val, ccdc_base_addr + offset);
-}
-
-static void ccdc_set_ccdc_base(void *addr, int size)
-{
- ccdc_base_addr = addr;
- ccdc_addr_size = size;
+ __raw_writel(val, ccdc_cfg.base_addr + offset);
}
static void ccdc_enable(int flag)
@@ -132,7 +138,7 @@ void ccdc_setwin(struct v4l2_rect *image_win,
int vert_start, vert_nr_lines;
int val = 0, mid_img = 0;
- dev_dbg(dev, "\nStarting ccdc_setwin...");
+ dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
/*
* ppc - per pixel count. indicates how many pixels per cell
* output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
@@ -171,7 +177,7 @@ void ccdc_setwin(struct v4l2_rect *image_win,
regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start,
CCDC_VERT_START);
regw(vert_nr_lines, CCDC_VERT_LINES);
- dev_dbg(dev, "\nEnd of ccdc_setwin...");
+ dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
}
static void ccdc_readregs(void)
@@ -179,39 +185,39 @@ static void ccdc_readregs(void)
unsigned int val = 0;
val = regr(CCDC_ALAW);
- dev_notice(dev, "\nReading 0x%x to ALAW...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val);
val = regr(CCDC_CLAMP);
- dev_notice(dev, "\nReading 0x%x to CLAMP...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val);
val = regr(CCDC_DCSUB);
- dev_notice(dev, "\nReading 0x%x to DCSUB...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val);
val = regr(CCDC_BLKCMP);
- dev_notice(dev, "\nReading 0x%x to BLKCMP...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val);
val = regr(CCDC_FPC_ADDR);
- dev_notice(dev, "\nReading 0x%x to FPC_ADDR...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val);
val = regr(CCDC_FPC);
- dev_notice(dev, "\nReading 0x%x to FPC...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val);
val = regr(CCDC_FMTCFG);
- dev_notice(dev, "\nReading 0x%x to FMTCFG...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val);
val = regr(CCDC_COLPTN);
- dev_notice(dev, "\nReading 0x%x to COLPTN...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val);
val = regr(CCDC_FMT_HORZ);
- dev_notice(dev, "\nReading 0x%x to FMT_HORZ...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val);
val = regr(CCDC_FMT_VERT);
- dev_notice(dev, "\nReading 0x%x to FMT_VERT...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val);
val = regr(CCDC_HSIZE_OFF);
- dev_notice(dev, "\nReading 0x%x to HSIZE_OFF...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val);
val = regr(CCDC_SDOFST);
- dev_notice(dev, "\nReading 0x%x to SDOFST...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val);
val = regr(CCDC_VP_OUT);
- dev_notice(dev, "\nReading 0x%x to VP_OUT...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val);
val = regr(CCDC_SYN_MODE);
- dev_notice(dev, "\nReading 0x%x to SYN_MODE...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val);
val = regr(CCDC_HORZ_INFO);
- dev_notice(dev, "\nReading 0x%x to HORZ_INFO...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val);
val = regr(CCDC_VERT_START);
- dev_notice(dev, "\nReading 0x%x to VERT_START...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val);
val = regr(CCDC_VERT_LINES);
- dev_notice(dev, "\nReading 0x%x to VERT_LINES...\n", val);
+ dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val);
}
static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
@@ -220,7 +226,7 @@ static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) ||
(ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) ||
(ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) {
- dev_dbg(dev, "\nInvalid data line select");
+ dev_dbg(ccdc_cfg.dev, "\nInvalid data line select");
return -1;
}
}
@@ -230,7 +236,7 @@ static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
{
struct ccdc_config_params_raw *config_params =
- &ccdc_hw_params_raw.config_params;
+ &ccdc_cfg.bayer.config_params;
unsigned int *fpc_virtaddr = NULL;
unsigned int *fpc_physaddr = NULL;
@@ -266,7 +272,7 @@ static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
FP_NUM_BYTES));
if (fpc_virtaddr == NULL) {
- dev_dbg(dev,
+ dev_dbg(ccdc_cfg.dev,
"\nUnable to allocate memory for FPC");
return -EFAULT;
}
@@ -279,7 +285,7 @@ static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
if (copy_from_user(fpc_virtaddr,
(void __user *)raw_params->fault_pxl.fpc_table_addr,
config_params->fault_pxl.fp_num * FP_NUM_BYTES)) {
- dev_dbg(dev, "\n copy_from_user failed");
+ dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed");
return -EFAULT;
}
config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr;
@@ -289,7 +295,7 @@ static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
static int ccdc_close(struct device *dev)
{
struct ccdc_config_params_raw *config_params =
- &ccdc_hw_params_raw.config_params;
+ &ccdc_cfg.bayer.config_params;
unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL;
fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
@@ -323,9 +329,8 @@ static void ccdc_restore_defaults(void)
static int ccdc_open(struct device *device)
{
- dev = device;
ccdc_restore_defaults();
- if (ccdc_if_type == VPFE_RAW_BAYER)
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
ccdc_enable_vport(1);
return 0;
}
@@ -341,12 +346,12 @@ static int ccdc_set_params(void __user *params)
struct ccdc_config_params_raw ccdc_raw_params;
int x;
- if (ccdc_if_type != VPFE_RAW_BAYER)
+ if (ccdc_cfg.if_type != VPFE_RAW_BAYER)
return -EINVAL;
x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
if (x) {
- dev_dbg(dev, "ccdc_set_params: error in copying"
+ dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying"
"ccdc params, %d\n", x);
return -EFAULT;
}
@@ -364,10 +369,10 @@ static int ccdc_set_params(void __user *params)
*/
void ccdc_config_ycbcr(void)
{
- struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr;
+ struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
u32 syn_mode;
- dev_dbg(dev, "\nStarting ccdc_config_ycbcr...");
+ dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
/*
* first restore the CCDC registers to default values
* This is important since we assume default values to be set in
@@ -428,7 +433,7 @@ void ccdc_config_ycbcr(void)
regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST);
ccdc_sbl_reset();
- dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n");
+ dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
ccdc_readregs();
}
@@ -440,9 +445,9 @@ static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
/* configure DCSub */
val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK;
regw(val, CCDC_DCSUB);
- dev_dbg(dev, "\nWriting 0x%x to DCSUB...\n", val);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val);
regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP);
- dev_dbg(dev, "\nWriting 0x0000 to CLAMP...\n");
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n");
return;
}
/*
@@ -457,10 +462,10 @@ static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE);
regw(val, CCDC_CLAMP);
- dev_dbg(dev, "\nWriting 0x%x to CLAMP...\n", val);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val);
/* If Black clamping is enable then make dcsub 0 */
regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB);
- dev_dbg(dev, "\nWriting 0x00000000 to DCSUB...\n");
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n");
}
static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
@@ -490,17 +495,17 @@ static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)
/* Configure Fault pixel if needed */
regw(fpc->fpc_table_addr, CCDC_FPC_ADDR);
- dev_dbg(dev, "\nWriting 0x%x to FPC_ADDR...\n",
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n",
(fpc->fpc_table_addr));
/* Write the FPC params with FPC disable */
val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK;
regw(val, CCDC_FPC);
- dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val);
/* read the FPC register */
val = regr(CCDC_FPC) | CCDC_FPC_ENABLE;
regw(val, CCDC_FPC);
- dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val);
}
/*
@@ -509,13 +514,13 @@ static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)
*/
void ccdc_config_raw(void)
{
- struct ccdc_params_raw *params = &ccdc_hw_params_raw;
+ struct ccdc_params_raw *params = &ccdc_cfg.bayer;
struct ccdc_config_params_raw *config_params =
- &ccdc_hw_params_raw.config_params;
+ &ccdc_cfg.bayer.config_params;
unsigned int syn_mode = 0;
unsigned int val;
- dev_dbg(dev, "\nStarting ccdc_config_raw...");
+ dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
/* Reset CCDC */
ccdc_restore_defaults();
@@ -545,7 +550,7 @@ void ccdc_config_raw(void)
val = ((config_params->alaw.gama_wd &
CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE);
regw(val, CCDC_ALAW);
- dev_dbg(dev, "\nWriting 0x%x to ALAW...\n", val);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val);
}
/* Configure video window */
@@ -582,11 +587,11 @@ void ccdc_config_raw(void)
/* Write value in FMTCFG */
regw(val, CCDC_FMTCFG);
- dev_dbg(dev, "\nWriting 0x%x to FMTCFG...\n", val);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val);
/* Configure the color pattern according to mt9t001 sensor */
regw(CCDC_COLPTN_VAL, CCDC_COLPTN);
- dev_dbg(dev, "\nWriting 0xBB11BB11 to COLPTN...\n");
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n");
/*
* Configure Data formatter(Video port) pixel selection
* (FMT_HORZ, FMT_VERT)
@@ -596,7 +601,7 @@ void ccdc_config_raw(void)
(params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK);
regw(val, CCDC_FMT_HORZ);
- dev_dbg(dev, "\nWriting 0x%x to FMT_HORZ...\n", val);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val);
val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK)
<< CCDC_FMT_VERT_FMTSLV_SHIFT;
if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
@@ -604,13 +609,13 @@ void ccdc_config_raw(void)
else
val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK;
- dev_dbg(dev, "\nparams->win.height 0x%x ...\n",
+ dev_dbg(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n",
params->win.height);
regw(val, CCDC_FMT_VERT);
- dev_dbg(dev, "\nWriting 0x%x to FMT_VERT...\n", val);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val);
- dev_dbg(dev, "\nbelow regw(val, FMT_VERT)...");
+ dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)...");
/*
* Configure Horizontal offset register. If pack 8 is enabled then
@@ -631,17 +636,17 @@ void ccdc_config_raw(void)
if (params->image_invert_enable) {
/* For intelace inverse mode */
regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST);
- dev_dbg(dev, "\nWriting 0x4B6D to SDOFST...\n");
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n");
}
else {
/* For intelace non inverse mode */
regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST);
- dev_dbg(dev, "\nWriting 0x0249 to SDOFST...\n");
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n");
}
} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST);
- dev_dbg(dev, "\nWriting 0x0000 to SDOFST...\n");
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n");
}
/*
@@ -662,18 +667,18 @@ void ccdc_config_raw(void)
val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK;
regw(val, CCDC_VP_OUT);
- dev_dbg(dev, "\nWriting 0x%x to VP_OUT...\n", val);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val);
regw(syn_mode, CCDC_SYN_MODE);
- dev_dbg(dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode);
+ dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode);
ccdc_sbl_reset();
- dev_dbg(dev, "\nend of ccdc_config_raw...");
+ dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
ccdc_readregs();
}
static int ccdc_configure(void)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
ccdc_config_raw();
else
ccdc_config_ycbcr();
@@ -682,24 +687,24 @@ static int ccdc_configure(void)
static int ccdc_set_buftype(enum ccdc_buftype buf_type)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
- ccdc_hw_params_raw.buf_type = buf_type;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_cfg.bayer.buf_type = buf_type;
else
- ccdc_hw_params_ycbcr.buf_type = buf_type;
+ ccdc_cfg.ycbcr.buf_type = buf_type;
return 0;
}
static enum ccdc_buftype ccdc_get_buftype(void)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
- return ccdc_hw_params_raw.buf_type;
- return ccdc_hw_params_ycbcr.buf_type;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ return ccdc_cfg.bayer.buf_type;
+ return ccdc_cfg.ycbcr.buf_type;
}
static int ccdc_enum_pix(u32 *pix, int i)
{
int ret = -EINVAL;
- if (ccdc_if_type == VPFE_RAW_BAYER) {
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
*pix = ccdc_raw_bayer_pix_formats[i];
ret = 0;
@@ -715,17 +720,17 @@ static int ccdc_enum_pix(u32 *pix, int i)
static int ccdc_set_pixel_format(u32 pixfmt)
{
- if (ccdc_if_type == VPFE_RAW_BAYER) {
- ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+ ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
if (pixfmt == V4L2_PIX_FMT_SBGGR8)
- ccdc_hw_params_raw.config_params.alaw.enable = 1;
+ ccdc_cfg.bayer.config_params.alaw.enable = 1;
else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
return -EINVAL;
} else {
if (pixfmt == V4L2_PIX_FMT_YUYV)
- ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+ ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
else if (pixfmt == V4L2_PIX_FMT_UYVY)
- ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
else
return -EINVAL;
}
@@ -734,17 +739,16 @@ static int ccdc_set_pixel_format(u32 pixfmt)
static u32 ccdc_get_pixel_format(void)
{
- struct ccdc_a_law *alaw =
- &ccdc_hw_params_raw.config_params.alaw;
+ struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
u32 pixfmt;
- if (ccdc_if_type == VPFE_RAW_BAYER)
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
if (alaw->enable)
pixfmt = V4L2_PIX_FMT_SBGGR8;
else
pixfmt = V4L2_PIX_FMT_SBGGR16;
else {
- if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+ if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
pixfmt = V4L2_PIX_FMT_YUYV;
else
pixfmt = V4L2_PIX_FMT_UYVY;
@@ -754,53 +758,53 @@ static u32 ccdc_get_pixel_format(void)
static int ccdc_set_image_window(struct v4l2_rect *win)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
- ccdc_hw_params_raw.win = *win;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_cfg.bayer.win = *win;
else
- ccdc_hw_params_ycbcr.win = *win;
+ ccdc_cfg.ycbcr.win = *win;
return 0;
}
static void ccdc_get_image_window(struct v4l2_rect *win)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
- *win = ccdc_hw_params_raw.win;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ *win = ccdc_cfg.bayer.win;
else
- *win = ccdc_hw_params_ycbcr.win;
+ *win = ccdc_cfg.ycbcr.win;
}
static unsigned int ccdc_get_line_length(void)
{
struct ccdc_config_params_raw *config_params =
- &ccdc_hw_params_raw.config_params;
+ &ccdc_cfg.bayer.config_params;
unsigned int len;
- if (ccdc_if_type == VPFE_RAW_BAYER) {
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
if ((config_params->alaw.enable) ||
(config_params->data_sz == CCDC_DATA_8BITS))
- len = ccdc_hw_params_raw.win.width;
+ len = ccdc_cfg.bayer.win.width;
else
- len = ccdc_hw_params_raw.win.width * 2;
+ len = ccdc_cfg.bayer.win.width * 2;
} else
- len = ccdc_hw_params_ycbcr.win.width * 2;
+ len = ccdc_cfg.ycbcr.win.width * 2;
return ALIGN(len, 32);
}
static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
- ccdc_hw_params_raw.frm_fmt = frm_fmt;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc_cfg.bayer.frm_fmt = frm_fmt;
else
- ccdc_hw_params_ycbcr.frm_fmt = frm_fmt;
+ ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
return 0;
}
static enum ccdc_frmfmt ccdc_get_frame_format(void)
{
- if (ccdc_if_type == VPFE_RAW_BAYER)
- return ccdc_hw_params_raw.frm_fmt;
+ if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ return ccdc_cfg.bayer.frm_fmt;
else
- return ccdc_hw_params_ycbcr.frm_fmt;
+ return ccdc_cfg.ycbcr.frm_fmt;
}
static int ccdc_getfid(void)
@@ -816,14 +820,14 @@ static inline void ccdc_setfbaddr(unsigned long addr)
static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
{
- ccdc_if_type = params->if_type;
+ ccdc_cfg.if_type = params->if_type;
switch (params->if_type) {
case VPFE_BT656:
case VPFE_YCBCR_SYNC_16:
case VPFE_YCBCR_SYNC_8:
- ccdc_hw_params_ycbcr.vd_pol = params->vdpol;
- ccdc_hw_params_ycbcr.hd_pol = params->hdpol;
+ ccdc_cfg.ycbcr.vd_pol = params->vdpol;
+ ccdc_cfg.ycbcr.hd_pol = params->hdpol;
break;
default:
/* TODO add support for raw bayer here */
@@ -838,7 +842,6 @@ static struct ccdc_hw_device ccdc_hw_dev = {
.hw_ops = {
.open = ccdc_open,
.close = ccdc_close,
- .set_ccdc_base = ccdc_set_ccdc_base,
.reset = ccdc_sbl_reset,
.enable = ccdc_enable,
.set_hw_if_params = ccdc_set_hw_if_params,
@@ -859,19 +862,105 @@ static struct ccdc_hw_device ccdc_hw_dev = {
},
};
-static int __init dm644x_ccdc_init(void)
+static int __init dm644x_ccdc_probe(struct platform_device *pdev)
{
- printk(KERN_NOTICE "dm644x_ccdc_init\n");
- if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
- return -1;
- printk(KERN_NOTICE "%s is registered with vpfe.\n",
- ccdc_hw_dev.name);
+ struct resource *res;
+ int status = 0;
+
+ /*
+ * first try to register with vpfe. If not correct platform, then we
+ * don't have to iomap
+ */
+ status = vpfe_register_ccdc_device(&ccdc_hw_dev);
+ if (status < 0)
+ return status;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ status = -ENODEV;
+ goto fail_nores;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), res->name);
+ if (!res) {
+ status = -EBUSY;
+ goto fail_nores;
+ }
+
+ ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
+ if (!ccdc_cfg.base_addr) {
+ status = -ENOMEM;
+ goto fail_nomem;
+ }
+
+ /* Get and enable Master clock */
+ ccdc_cfg.mclk = clk_get(&pdev->dev, "master");
+ if (IS_ERR(ccdc_cfg.mclk)) {
+ status = PTR_ERR(ccdc_cfg.mclk);
+ goto fail_nomap;
+ }
+ if (clk_enable(ccdc_cfg.mclk)) {
+ status = -ENODEV;
+ goto fail_mclk;
+ }
+
+ /* Get and enable Slave clock */
+ ccdc_cfg.sclk = clk_get(&pdev->dev, "slave");
+ if (IS_ERR(ccdc_cfg.sclk)) {
+ status = PTR_ERR(ccdc_cfg.sclk);
+ goto fail_mclk;
+ }
+ if (clk_enable(ccdc_cfg.sclk)) {
+ status = -ENODEV;
+ goto fail_sclk;
+ }
+ ccdc_cfg.dev = &pdev->dev;
+ printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
return 0;
+fail_sclk:
+ clk_put(ccdc_cfg.sclk);
+fail_mclk:
+ clk_put(ccdc_cfg.mclk);
+fail_nomap:
+ iounmap(ccdc_cfg.base_addr);
+fail_nomem:
+ release_mem_region(res->start, resource_size(res));
+fail_nores:
+ vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+ return status;
}
-static void __exit dm644x_ccdc_exit(void)
+static int dm644x_ccdc_remove(struct platform_device *pdev)
{
+ struct resource *res;
+
+ clk_put(ccdc_cfg.mclk);
+ clk_put(ccdc_cfg.sclk);
+ iounmap(ccdc_cfg.base_addr);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+ return 0;
+}
+
+static struct platform_driver dm644x_ccdc_driver = {
+ .driver = {
+ .name = "dm644x_ccdc",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(dm644x_ccdc_remove),
+ .probe = dm644x_ccdc_probe,
+};
+
+static int __init dm644x_ccdc_init(void)
+{
+ return platform_driver_register(&dm644x_ccdc_driver);
+}
+
+static void __exit dm644x_ccdc_exit(void)
+{
+ platform_driver_unregister(&dm644x_ccdc_driver);
}
module_init(dm644x_ccdc_init);
diff --git a/drivers/media/video/davinci/isif.c b/drivers/media/video/davinci/isif.c
new file mode 100644
index 000000000000..29c29c668596
--- /dev/null
+++ b/drivers/media/video/davinci/isif.c
@@ -0,0 +1,1172 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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
+ *
+ * Image Sensor Interface (ISIF) driver
+ *
+ * This driver is for configuring the ISIF IP available on DM365 or any other
+ * TI SoCs. This is used for capturing yuv or bayer video or image data
+ * from a decoder or sensor. This IP is similar to the CCDC IP on DM355
+ * and DM6446, but with enhanced or additional ip blocks. The driver
+ * configures the ISIF upon commands from the vpfe bridge driver through
+ * ccdc_hw_device interface.
+ *
+ * TODO: 1) Raw bayer parameter settings and bayer capture
+ * 2) Add support for control ioctl
+ */
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/videodev2.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <mach/mux.h>
+
+#include <media/davinci/isif.h>
+#include <media/davinci/vpss.h>
+
+#include "isif_regs.h"
+#include "ccdc_hw_device.h"
+
+/* Defaults for module configuration parameters */
+static struct isif_config_params_raw isif_config_defaults = {
+ .linearize = {
+ .en = 0,
+ .corr_shft = ISIF_NO_SHIFT,
+ .scale_fact = {1, 0},
+ },
+ .df_csc = {
+ .df_or_csc = 0,
+ .csc = {
+ .en = 0,
+ },
+ },
+ .dfc = {
+ .en = 0,
+ },
+ .bclamp = {
+ .en = 0,
+ },
+ .gain_offset = {
+ .gain = {
+ .r_ye = {1, 0},
+ .gr_cy = {1, 0},
+ .gb_g = {1, 0},
+ .b_mg = {1, 0},
+ },
+ },
+ .culling = {
+ .hcpat_odd = 0xff,
+ .hcpat_even = 0xff,
+ .vcpat = 0xff,
+ },
+ .compress = {
+ .alg = ISIF_ALAW,
+ },
+};
+
+/* ISIF operation configuration */
+static struct isif_oper_config {
+ struct device *dev;
+ enum vpfe_hw_if_type if_type;
+ struct isif_ycbcr_config ycbcr;
+ struct isif_params_raw bayer;
+ enum isif_data_pack data_pack;
+ /* Master clock */
+ struct clk *mclk;
+ /* ISIF base address */
+ void __iomem *base_addr;
+ /* ISIF Linear Table 0 */
+ void __iomem *linear_tbl0_addr;
+ /* ISIF Linear Table 1 */
+ void __iomem *linear_tbl1_addr;
+} isif_cfg = {
+ .ycbcr = {
+ .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+ .frm_fmt = CCDC_FRMFMT_INTERLACED,
+ .win = ISIF_WIN_NTSC,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .pix_order = CCDC_PIXORDER_CBYCRY,
+ .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED,
+ },
+ .bayer = {
+ .pix_fmt = CCDC_PIXFMT_RAW,
+ .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+ .win = ISIF_WIN_VGA,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .gain = {
+ .r_ye = {1, 0},
+ .gr_cy = {1, 0},
+ .gb_g = {1, 0},
+ .b_mg = {1, 0},
+ },
+ .cfa_pat = ISIF_CFA_PAT_MOSAIC,
+ .data_msb = ISIF_BIT_MSB_11,
+ .config_params = {
+ .data_shift = ISIF_NO_SHIFT,
+ .col_pat_field0 = {
+ .olop = ISIF_GREEN_BLUE,
+ .olep = ISIF_BLUE,
+ .elop = ISIF_RED,
+ .elep = ISIF_GREEN_RED,
+ },
+ .col_pat_field1 = {
+ .olop = ISIF_GREEN_BLUE,
+ .olep = ISIF_BLUE,
+ .elop = ISIF_RED,
+ .elep = ISIF_GREEN_RED,
+ },
+ .test_pat_gen = 0,
+ },
+ },
+ .data_pack = ISIF_DATA_PACK8,
+};
+
+/* Raw Bayer formats */
+static const u32 isif_raw_bayer_pix_formats[] = {
+ V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
+
+/* Raw YUV formats */
+static const u32 isif_raw_yuv_pix_formats[] = {
+ V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
+
+/* register access routines */
+static inline u32 regr(u32 offset)
+{
+ return __raw_readl(isif_cfg.base_addr + offset);
+}
+
+static inline void regw(u32 val, u32 offset)
+{
+ __raw_writel(val, isif_cfg.base_addr + offset);
+}
+
+/* reg_modify() - read, modify and write register */
+static inline u32 reg_modify(u32 mask, u32 val, u32 offset)
+{
+ u32 new_val = (regr(offset) & ~mask) | (val & mask);
+
+ regw(new_val, offset);
+ return new_val;
+}
+
+static inline void regw_lin_tbl(u32 val, u32 offset, int i)
+{
+ if (!i)
+ __raw_writel(val, isif_cfg.linear_tbl0_addr + offset);
+ else
+ __raw_writel(val, isif_cfg.linear_tbl1_addr + offset);
+}
+
+static void isif_disable_all_modules(void)
+{
+ /* disable BC */
+ regw(0, CLAMPCFG);
+ /* disable vdfc */
+ regw(0, DFCCTL);
+ /* disable CSC */
+ regw(0, CSCCTL);
+ /* disable linearization */
+ regw(0, LINCFG0);
+ /* disable other modules here as they are supported */
+}
+
+static void isif_enable(int en)
+{
+ if (!en) {
+ /* Before disable isif, disable all ISIF modules */
+ isif_disable_all_modules();
+ /*
+ * wait for next VD. Assume lowest scan rate is 12 Hz. So
+ * 100 msec delay is good enough
+ */
+ msleep(100);
+ }
+ reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN);
+}
+
+static void isif_enable_output_to_sdram(int en)
+{
+ reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
+}
+
+static void isif_config_culling(struct isif_cul *cul)
+{
+ u32 val;
+
+ /* Horizontal pattern */
+ val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd;
+ regw(val, CULH);
+
+ /* vertical pattern */
+ regw(cul->vcpat, CULV);
+
+ /* LPF */
+ reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT,
+ cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
+}
+
+static void isif_config_gain_offset(void)
+{
+ struct isif_gain_offsets_adj *gain_off_p =
+ &isif_cfg.bayer.config_params.gain_offset;
+ u32 val;
+
+ val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) |
+ (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) |
+ (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) |
+ (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) |
+ (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) |
+ (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT);
+
+ reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
+
+ val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) |
+ gain_off_p->gain.r_ye.decimal;
+ regw(val, CRGAIN);
+
+ val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) |
+ gain_off_p->gain.gr_cy.decimal;
+ regw(val, CGRGAIN);
+
+ val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) |
+ gain_off_p->gain.gb_g.decimal;
+ regw(val, CGBGAIN);
+
+ val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) |
+ gain_off_p->gain.b_mg.decimal;
+ regw(val, CBGAIN);
+
+ regw(gain_off_p->offset, COFSTA);
+}
+
+static void isif_restore_defaults(void)
+{
+ enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
+
+ dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults...");
+ isif_cfg.bayer.config_params = isif_config_defaults;
+ /* Enable clock to ISIF, IPIPEIF and BL */
+ vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
+ vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
+ vpss_enable_clock(VPSS_BL_CLOCK, 1);
+ /* Set default offset and gain */
+ isif_config_gain_offset();
+ vpss_select_ccdc_source(source);
+ dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults...");
+}
+
+static int isif_open(struct device *device)
+{
+ isif_restore_defaults();
+ return 0;
+}
+
+/* This function will configure the window size to be capture in ISIF reg */
+static void isif_setwin(struct v4l2_rect *image_win,
+ enum ccdc_frmfmt frm_fmt, int ppc)
+{
+ int horz_start, horz_nr_pixels;
+ int vert_start, vert_nr_lines;
+ int mid_img = 0;
+
+ dev_dbg(isif_cfg.dev, "\nStarting isif_setwin...");
+ /*
+ * ppc - per pixel count. indicates how many pixels per cell
+ * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
+ * raw capture this is 1
+ */
+ horz_start = image_win->left << (ppc - 1);
+ horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
+
+ /* Writing the horizontal info into the registers */
+ regw(horz_start & START_PX_HOR_MASK, SPH);
+ regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
+ vert_start = image_win->top;
+
+ if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ vert_nr_lines = (image_win->height >> 1) - 1;
+ vert_start >>= 1;
+ /* To account for VD since line 0 doesn't have any data */
+ vert_start += 1;
+ } else {
+ /* To account for VD since line 0 doesn't have any data */
+ vert_start += 1;
+ vert_nr_lines = image_win->height - 1;
+ /* configure VDINT0 and VDINT1 */
+ mid_img = vert_start + (image_win->height / 2);
+ regw(mid_img, VDINT1);
+ }
+
+ regw(0, VDINT0);
+ regw(vert_start & START_VER_ONE_MASK, SLV0);
+ regw(vert_start & START_VER_TWO_MASK, SLV1);
+ regw(vert_nr_lines & NUM_LINES_VER, LNV);
+}
+
+static void isif_config_bclamp(struct isif_black_clamp *bc)
+{
+ u32 val;
+
+ /*
+ * DC Offset is always added to image data irrespective of bc enable
+ * status
+ */
+ regw(bc->dc_offset, CLDCOFST);
+
+ if (bc->en) {
+ val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT;
+
+ /* Enable BC and horizontal clamp caculation paramaters */
+ val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT);
+
+ regw(val, CLAMPCFG);
+
+ if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) {
+ /*
+ * Window count for calculation
+ * Base window selection
+ * pixel limit
+ * Horizontal size of window
+ * vertical size of the window
+ * Horizontal start position of the window
+ * Vertical start position of the window
+ */
+ val = bc->horz.win_count_calc |
+ ((!!bc->horz.base_win_sel_calc) <<
+ ISIF_HORZ_BC_WIN_SEL_SHIFT) |
+ ((!!bc->horz.clamp_pix_limit) <<
+ ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
+ (bc->horz.win_h_sz_calc <<
+ ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
+ (bc->horz.win_v_sz_calc <<
+ ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
+ regw(val, CLHWIN0);
+
+ regw(bc->horz.win_start_h_calc, CLHWIN1);
+ regw(bc->horz.win_start_v_calc, CLHWIN2);
+ }
+
+ /* vertical clamp caculation paramaters */
+
+ /* Reset clamp value sel for previous line */
+ val |=
+ (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) |
+ (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT);
+ regw(val, CLVWIN0);
+
+ /* Optical Black horizontal start position */
+ regw(bc->vert.ob_start_h, CLVWIN1);
+ /* Optical Black vertical start position */
+ regw(bc->vert.ob_start_v, CLVWIN2);
+ /* Optical Black vertical size for calculation */
+ regw(bc->vert.ob_v_sz_calc, CLVWIN3);
+ /* Vertical start position for BC subtraction */
+ regw(bc->vert_start_sub, CLSV);
+ }
+}
+
+static void isif_config_linearization(struct isif_linearize *linearize)
+{
+ u32 val, i;
+
+ if (!linearize->en) {
+ regw(0, LINCFG0);
+ return;
+ }
+
+ /* shift value for correction & enable linearization (set lsb) */
+ val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1;
+ regw(val, LINCFG0);
+
+ /* Scale factor */
+ val = ((!!linearize->scale_fact.integer) <<
+ ISIF_LIN_SCALE_FACT_INTEG_SHIFT) |
+ linearize->scale_fact.decimal;
+ regw(val, LINCFG1);
+
+ for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) {
+ if (i % 2)
+ regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1);
+ else
+ regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0);
+ }
+}
+
+static int isif_config_dfc(struct isif_dfc *vdfc)
+{
+ /* initialize retries to loop for max ~ 250 usec */
+ u32 val, count, retries = loops_per_jiffy / (4000/HZ);
+ int i;
+
+ if (!vdfc->en)
+ return 0;
+
+ /* Correction mode */
+ val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT);
+
+ /* Correct whole line or partial */
+ if (vdfc->corr_whole_line)
+ val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
+
+ /* level shift value */
+ val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT;
+
+ regw(val, DFCCTL);
+
+ /* Defect saturation level */
+ regw(vdfc->def_sat_level, VDFSATLV);
+
+ regw(vdfc->table[0].pos_vert, DFCMEM0);
+ regw(vdfc->table[0].pos_horz, DFCMEM1);
+ if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
+ vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
+ regw(vdfc->table[0].level_at_pos, DFCMEM2);
+ regw(vdfc->table[0].level_up_pixels, DFCMEM3);
+ regw(vdfc->table[0].level_low_pixels, DFCMEM4);
+ }
+
+ /* set DFCMARST and set DFCMWR */
+ val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1;
+ regw(val, DFCMEMCTL);
+
+ count = retries;
+ while (count && (regr(DFCMEMCTL) & 0x1))
+ count--;
+
+ if (!count) {
+ dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n");
+ return -1;
+ }
+
+ for (i = 1; i < vdfc->num_vdefects; i++) {
+ regw(vdfc->table[i].pos_vert, DFCMEM0);
+ regw(vdfc->table[i].pos_horz, DFCMEM1);
+ if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
+ vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
+ regw(vdfc->table[i].level_at_pos, DFCMEM2);
+ regw(vdfc->table[i].level_up_pixels, DFCMEM3);
+ regw(vdfc->table[i].level_low_pixels, DFCMEM4);
+ }
+ val = regr(DFCMEMCTL);
+ /* clear DFCMARST and set DFCMWR */
+ val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);
+ val |= 1;
+ regw(val, DFCMEMCTL);
+
+ count = retries;
+ while (count && (regr(DFCMEMCTL) & 0x1))
+ count--;
+
+ if (!count) {
+ dev_err(isif_cfg.dev,
+ "defect table write timeout !!!\n");
+ return -1;
+ }
+ }
+ if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) {
+ /* Extra cycle needed */
+ regw(0, DFCMEM0);
+ regw(0x1FFF, DFCMEM1);
+ regw(1, DFCMEMCTL);
+ }
+
+ /* enable VDFC */
+ reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT),
+ DFCCTL);
+ return 0;
+}
+
+static void isif_config_csc(struct isif_df_csc *df_csc)
+{
+ u32 val1 = 0, val2 = 0, i;
+
+ if (!df_csc->csc.en) {
+ regw(0, CSCCTL);
+ return;
+ }
+ for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) {
+ if ((i % 2) == 0) {
+ /* CSCM - LSB */
+ val1 = (df_csc->csc.coeff[i].integer <<
+ ISIF_CSC_COEF_INTEG_SHIFT) |
+ df_csc->csc.coeff[i].decimal;
+ } else {
+
+ /* CSCM - MSB */
+ val2 = (df_csc->csc.coeff[i].integer <<
+ ISIF_CSC_COEF_INTEG_SHIFT) |
+ df_csc->csc.coeff[i].decimal;
+ val2 <<= ISIF_CSCM_MSB_SHIFT;
+ val2 |= val1;
+ regw(val2, (CSCM0 + ((i - 1) << 1)));
+ }
+ }
+
+ /* program the active area */
+ regw(df_csc->start_pix, FMTSPH);
+ /*
+ * one extra pixel as required for CSC. Actually number of
+ * pixel - 1 should be configured in this register. So we
+ * need to subtract 1 before writing to FMTSPH, but we will
+ * not do this since csc requires one extra pixel
+ */
+ regw(df_csc->num_pixels, FMTLNH);
+ regw(df_csc->start_line, FMTSLV);
+ /*
+ * one extra line as required for CSC. See reason documented for
+ * num_pixels
+ */
+ regw(df_csc->num_lines, FMTLNV);
+
+ /* Enable CSC */
+ regw(1, CSCCTL);
+}
+
+static int isif_config_raw(void)
+{
+ struct isif_params_raw *params = &isif_cfg.bayer;
+ struct isif_config_params_raw *module_params =
+ &isif_cfg.bayer.config_params;
+ struct vpss_pg_frame_size frame_size;
+ struct vpss_sync_pol sync;
+ u32 val;
+
+ dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n");
+
+ /*
+ * Configure CCDCFG register:-
+ * Set CCD Not to swap input since input is RAW data
+ * Set FID detection function to Latch at V-Sync
+ * Set WENLOG - isif valid area
+ * Set TRGSEL
+ * Set EXTRG
+ * Packed to 8 or 16 bits
+ */
+
+ val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
+ ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
+ ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack;
+
+ dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val);
+ regw(val, CCDCFG);
+
+ /*
+ * Configure the vertical sync polarity(MODESET.VDPOL)
+ * Configure the horizontal sync polarity (MODESET.HDPOL)
+ * Configure frame id polarity (MODESET.FLDPOL)
+ * Configure data polarity
+ * Configure External WEN Selection
+ * Configure frame format(progressive or interlace)
+ * Configure pixel format (Input mode)
+ * Configure the data shift
+ */
+
+ val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) |
+ (params->hd_pol << ISIF_HD_POL_SHIFT) |
+ (params->fid_pol << ISIF_FID_POL_SHIFT) |
+ (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) |
+ (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) |
+ (params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
+ (params->pix_fmt << ISIF_INPUT_SHIFT) |
+ (params->config_params.data_shift << ISIF_DATASFT_SHIFT);
+
+ regw(val, MODESET);
+ dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val);
+
+ /*
+ * Configure GAMMAWD register
+ * CFA pattern setting
+ */
+ val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT;
+
+ /* Gamma msb */
+ if (module_params->compress.alg == ISIF_ALAW)
+ val |= ISIF_ALAW_ENABLE;
+
+ val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT);
+ regw(val, CGAMMAWD);
+
+ /* Configure DPCM compression settings */
+ if (module_params->compress.alg == ISIF_DPCM) {
+ val = BIT(ISIF_DPCM_EN_SHIFT) |
+ (module_params->compress.pred <<
+ ISIF_DPCM_PREDICTOR_SHIFT);
+ }
+
+ regw(val, MISC);
+
+ /* Configure Gain & Offset */
+ isif_config_gain_offset();
+
+ /* Configure Color pattern */
+ val = (params->config_params.col_pat_field0.olop) |
+ (params->config_params.col_pat_field0.olep << 2) |
+ (params->config_params.col_pat_field0.elop << 4) |
+ (params->config_params.col_pat_field0.elep << 6) |
+ (params->config_params.col_pat_field1.olop << 8) |
+ (params->config_params.col_pat_field1.olep << 10) |
+ (params->config_params.col_pat_field1.elop << 12) |
+ (params->config_params.col_pat_field1.elep << 14);
+ regw(val, CCOLP);
+ dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val);
+
+ /* Configure HSIZE register */
+ val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT;
+
+ /* calculate line offset in 32 bytes based on pack value */
+ if (isif_cfg.data_pack == ISIF_PACK_8BIT)
+ val |= ((params->win.width + 31) >> 5);
+ else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
+ val |= (((params->win.width +
+ (params->win.width >> 2)) + 31) >> 5);
+ else
+ val |= (((params->win.width * 2) + 31) >> 5);
+ regw(val, HSIZE);
+
+ /* Configure SDOFST register */
+ if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ if (params->image_invert_en) {
+ /* For interlace inverse mode */
+ regw(0x4B6D, SDOFST);
+ dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n");
+ } else {
+ /* For interlace non inverse mode */
+ regw(0x0B6D, SDOFST);
+ dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n");
+ }
+ } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+ if (params->image_invert_en) {
+ /* For progressive inverse mode */
+ regw(0x4000, SDOFST);
+ dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n");
+ } else {
+ /* For progressive non inverse mode */
+ regw(0x0000, SDOFST);
+ dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n");
+ }
+ }
+
+ /* Configure video window */
+ isif_setwin(&params->win, params->frm_fmt, 1);
+
+ /* Configure Black Clamp */
+ isif_config_bclamp(&module_params->bclamp);
+
+ /* Configure Vertical Defection Pixel Correction */
+ if (isif_config_dfc(&module_params->dfc) < 0)
+ return -EFAULT;
+
+ if (!module_params->df_csc.df_or_csc)
+ /* Configure Color Space Conversion */
+ isif_config_csc(&module_params->df_csc);
+
+ isif_config_linearization(&module_params->linearize);
+
+ /* Configure Culling */
+ isif_config_culling(&module_params->culling);
+
+ /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */
+ regw(module_params->horz_offset, DATAHOFST);
+ regw(module_params->vert_offset, DATAVOFST);
+
+ /* Setup test pattern if enabled */
+ if (params->config_params.test_pat_gen) {
+ /* Use the HD/VD pol settings from user */
+ sync.ccdpg_hdpol = params->hd_pol;
+ sync.ccdpg_vdpol = params->vd_pol;
+ dm365_vpss_set_sync_pol(sync);
+ frame_size.hlpfr = isif_cfg.bayer.win.width;
+ frame_size.pplen = isif_cfg.bayer.win.height;
+ dm365_vpss_set_pg_frame_size(frame_size);
+ vpss_select_ccdc_source(VPSS_PGLPBK);
+ }
+
+ dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n");
+ return 0;
+}
+
+static int isif_set_buftype(enum ccdc_buftype buf_type)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ isif_cfg.bayer.buf_type = buf_type;
+ else
+ isif_cfg.ycbcr.buf_type = buf_type;
+
+ return 0;
+
+}
+static enum ccdc_buftype isif_get_buftype(void)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ return isif_cfg.bayer.buf_type;
+
+ return isif_cfg.ycbcr.buf_type;
+}
+
+static int isif_enum_pix(u32 *pix, int i)
+{
+ int ret = -EINVAL;
+
+ if (isif_cfg.if_type == VPFE_RAW_BAYER) {
+ if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) {
+ *pix = isif_raw_bayer_pix_formats[i];
+ ret = 0;
+ }
+ } else {
+ if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) {
+ *pix = isif_raw_yuv_pix_formats[i];
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+static int isif_set_pixel_format(unsigned int pixfmt)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER) {
+ if (pixfmt == V4L2_PIX_FMT_SBGGR8) {
+ if ((isif_cfg.bayer.config_params.compress.alg !=
+ ISIF_ALAW) &&
+ (isif_cfg.bayer.config_params.compress.alg !=
+ ISIF_DPCM)) {
+ dev_dbg(isif_cfg.dev,
+ "Either configure A-Law or DPCM\n");
+ return -EINVAL;
+ }
+ isif_cfg.data_pack = ISIF_PACK_8BIT;
+ } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) {
+ isif_cfg.bayer.config_params.compress.alg =
+ ISIF_NO_COMPRESSION;
+ isif_cfg.data_pack = ISIF_PACK_16BIT;
+ } else
+ return -EINVAL;
+ isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+ } else {
+ if (pixfmt == V4L2_PIX_FMT_YUYV)
+ isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+ else if (pixfmt == V4L2_PIX_FMT_UYVY)
+ isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ else
+ return -EINVAL;
+ isif_cfg.data_pack = ISIF_PACK_8BIT;
+ }
+ return 0;
+}
+
+static u32 isif_get_pixel_format(void)
+{
+ u32 pixfmt;
+
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW ||
+ isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM)
+ pixfmt = V4L2_PIX_FMT_SBGGR8;
+ else
+ pixfmt = V4L2_PIX_FMT_SBGGR16;
+ else {
+ if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+ pixfmt = V4L2_PIX_FMT_YUYV;
+ else
+ pixfmt = V4L2_PIX_FMT_UYVY;
+ }
+ return pixfmt;
+}
+
+static int isif_set_image_window(struct v4l2_rect *win)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER) {
+ isif_cfg.bayer.win.top = win->top;
+ isif_cfg.bayer.win.left = win->left;
+ isif_cfg.bayer.win.width = win->width;
+ isif_cfg.bayer.win.height = win->height;
+ } else {
+ isif_cfg.ycbcr.win.top = win->top;
+ isif_cfg.ycbcr.win.left = win->left;
+ isif_cfg.ycbcr.win.width = win->width;
+ isif_cfg.ycbcr.win.height = win->height;
+ }
+ return 0;
+}
+
+static void isif_get_image_window(struct v4l2_rect *win)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ *win = isif_cfg.bayer.win;
+ else
+ *win = isif_cfg.ycbcr.win;
+}
+
+static unsigned int isif_get_line_length(void)
+{
+ unsigned int len;
+
+ if (isif_cfg.if_type == VPFE_RAW_BAYER) {
+ if (isif_cfg.data_pack == ISIF_PACK_8BIT)
+ len = ((isif_cfg.bayer.win.width));
+ else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
+ len = (((isif_cfg.bayer.win.width * 2) +
+ (isif_cfg.bayer.win.width >> 2)));
+ else
+ len = (((isif_cfg.bayer.win.width * 2)));
+ } else
+ len = (((isif_cfg.ycbcr.win.width * 2)));
+ return ALIGN(len, 32);
+}
+
+static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ isif_cfg.bayer.frm_fmt = frm_fmt;
+ else
+ isif_cfg.ycbcr.frm_fmt = frm_fmt;
+ return 0;
+}
+static enum ccdc_frmfmt isif_get_frame_format(void)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ return isif_cfg.bayer.frm_fmt;
+ return isif_cfg.ycbcr.frm_fmt;
+}
+
+static int isif_getfid(void)
+{
+ return (regr(MODESET) >> 15) & 0x1;
+}
+
+/* misc operations */
+static void isif_setfbaddr(unsigned long addr)
+{
+ regw((addr >> 21) & 0x07ff, CADU);
+ regw((addr >> 5) & 0x0ffff, CADL);
+}
+
+static int isif_set_hw_if_params(struct vpfe_hw_if_param *params)
+{
+ isif_cfg.if_type = params->if_type;
+
+ switch (params->if_type) {
+ case VPFE_BT656:
+ case VPFE_BT656_10BIT:
+ case VPFE_YCBCR_SYNC_8:
+ isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
+ isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ break;
+ case VPFE_BT1120:
+ case VPFE_YCBCR_SYNC_16:
+ isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT;
+ isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ break;
+ case VPFE_RAW_BAYER:
+ isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+ break;
+ default:
+ dev_dbg(isif_cfg.dev, "Invalid interface type\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* This function will configure ISIF for YCbCr parameters. */
+static int isif_config_ycbcr(void)
+{
+ struct isif_ycbcr_config *params = &isif_cfg.ycbcr;
+ struct vpss_pg_frame_size frame_size;
+ u32 modeset = 0, ccdcfg = 0;
+ struct vpss_sync_pol sync;
+
+ dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr...");
+
+ /* configure pixel format or input mode */
+ modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) |
+ (params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
+ (params->fid_pol << ISIF_FID_POL_SHIFT) |
+ (params->hd_pol << ISIF_HD_POL_SHIFT) |
+ (params->vd_pol << ISIF_VD_POL_SHIFT);
+
+ /* pack the data to 8-bit ISIFCFG */
+ switch (isif_cfg.if_type) {
+ case VPFE_BT656:
+ if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
+ dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+ return -EINVAL;
+ }
+ modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT);
+ regw(3, REC656IF);
+ ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR;
+ break;
+ case VPFE_BT656_10BIT:
+ if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
+ dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+ return -EINVAL;
+ }
+ /* setup BT.656, embedded sync */
+ regw(3, REC656IF);
+ /* enable 10 bit mode in ccdcfg */
+ ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR |
+ ISIF_BW656_ENABLE;
+ break;
+ case VPFE_BT1120:
+ if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
+ dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+ return -EINVAL;
+ }
+ regw(3, REC656IF);
+ break;
+
+ case VPFE_YCBCR_SYNC_8:
+ ccdcfg |= ISIF_DATA_PACK8;
+ ccdcfg |= ISIF_YCINSWP_YCBCR;
+ if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
+ dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+ return -EINVAL;
+ }
+ break;
+ case VPFE_YCBCR_SYNC_16:
+ if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
+ dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ /* should never come here */
+ dev_dbg(isif_cfg.dev, "Invalid interface type\n");
+ return -EINVAL;
+ }
+
+ regw(modeset, MODESET);
+
+ /* Set up pix order */
+ ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT;
+
+ regw(ccdcfg, CCDCFG);
+
+ /* configure video window */
+ if ((isif_cfg.if_type == VPFE_BT1120) ||
+ (isif_cfg.if_type == VPFE_YCBCR_SYNC_16))
+ isif_setwin(&params->win, params->frm_fmt, 1);
+ else
+ isif_setwin(&params->win, params->frm_fmt, 2);
+
+ /*
+ * configure the horizontal line offset
+ * this is done by rounding up width to a multiple of 16 pixels
+ * and multiply by two to account for y:cb:cr 4:2:2 data
+ */
+ regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE);
+
+ /* configure the memory line offset */
+ if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) &&
+ (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED))
+ /* two fields are interleaved in memory */
+ regw(0x00000249, SDOFST);
+
+ /* Setup test pattern if enabled */
+ if (isif_cfg.bayer.config_params.test_pat_gen) {
+ sync.ccdpg_hdpol = params->hd_pol;
+ sync.ccdpg_vdpol = params->vd_pol;
+ dm365_vpss_set_sync_pol(sync);
+ dm365_vpss_set_pg_frame_size(frame_size);
+ }
+ return 0;
+}
+
+static int isif_configure(void)
+{
+ if (isif_cfg.if_type == VPFE_RAW_BAYER)
+ return isif_config_raw();
+ return isif_config_ycbcr();
+}
+
+static int isif_close(struct device *device)
+{
+ /* copy defaults to module params */
+ isif_cfg.bayer.config_params = isif_config_defaults;
+ return 0;
+}
+
+static struct ccdc_hw_device isif_hw_dev = {
+ .name = "ISIF",
+ .owner = THIS_MODULE,
+ .hw_ops = {
+ .open = isif_open,
+ .close = isif_close,
+ .enable = isif_enable,
+ .enable_out_to_sdram = isif_enable_output_to_sdram,
+ .set_hw_if_params = isif_set_hw_if_params,
+ .configure = isif_configure,
+ .set_buftype = isif_set_buftype,
+ .get_buftype = isif_get_buftype,
+ .enum_pix = isif_enum_pix,
+ .set_pixel_format = isif_set_pixel_format,
+ .get_pixel_format = isif_get_pixel_format,
+ .set_frame_format = isif_set_frame_format,
+ .get_frame_format = isif_get_frame_format,
+ .set_image_window = isif_set_image_window,
+ .get_image_window = isif_get_image_window,
+ .get_line_length = isif_get_line_length,
+ .setfbaddr = isif_setfbaddr,
+ .getfid = isif_getfid,
+ },
+};
+
+static int __init isif_probe(struct platform_device *pdev)
+{
+ void (*setup_pinmux)(void);
+ struct resource *res;
+ void *__iomem addr;
+ int status = 0, i;
+
+ /*
+ * first try to register with vpfe. If not correct platform, then we
+ * don't have to iomap
+ */
+ status = vpfe_register_ccdc_device(&isif_hw_dev);
+ if (status < 0)
+ return status;
+
+ /* Get and enable Master clock */
+ isif_cfg.mclk = clk_get(&pdev->dev, "master");
+ if (IS_ERR(isif_cfg.mclk)) {
+ status = PTR_ERR(isif_cfg.mclk);
+ goto fail_mclk;
+ }
+ if (clk_enable(isif_cfg.mclk)) {
+ status = -ENODEV;
+ goto fail_mclk;
+ }
+
+ /* Platform data holds setup_pinmux function ptr */
+ if (NULL == pdev->dev.platform_data) {
+ status = -ENODEV;
+ goto fail_mclk;
+ }
+ setup_pinmux = pdev->dev.platform_data;
+ /*
+ * setup Mux configuration for ccdc which may be different for
+ * different SoCs using this CCDC
+ */
+ setup_pinmux();
+
+ i = 0;
+ /* Get the ISIF base address, linearization table0 and table1 addr. */
+ while (i < 3) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res) {
+ status = -ENODEV;
+ goto fail_nobase_res;
+ }
+ res = request_mem_region(res->start, resource_size(res),
+ res->name);
+ if (!res) {
+ status = -EBUSY;
+ goto fail_nobase_res;
+ }
+ addr = ioremap_nocache(res->start, resource_size(res));
+ if (!addr) {
+ status = -ENOMEM;
+ goto fail_base_iomap;
+ }
+ switch (i) {
+ case 0:
+ /* ISIF base address */
+ isif_cfg.base_addr = addr;
+ break;
+ case 1:
+ /* ISIF linear tbl0 address */
+ isif_cfg.linear_tbl0_addr = addr;
+ break;
+ default:
+ /* ISIF linear tbl0 address */
+ isif_cfg.linear_tbl1_addr = addr;
+ break;
+ }
+ i++;
+ }
+ isif_cfg.dev = &pdev->dev;
+
+ printk(KERN_NOTICE "%s is registered with vpfe.\n",
+ isif_hw_dev.name);
+ return 0;
+fail_base_iomap:
+ release_mem_region(res->start, resource_size(res));
+ i--;
+fail_nobase_res:
+ if (isif_cfg.base_addr)
+ iounmap(isif_cfg.base_addr);
+ if (isif_cfg.linear_tbl0_addr)
+ iounmap(isif_cfg.linear_tbl0_addr);
+
+ while (i >= 0) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ release_mem_region(res->start, resource_size(res));
+ i--;
+ }
+fail_mclk:
+ clk_put(isif_cfg.mclk);
+ vpfe_unregister_ccdc_device(&isif_hw_dev);
+ return status;
+}
+
+static int isif_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+ int i = 0;
+
+ iounmap(isif_cfg.base_addr);
+ iounmap(isif_cfg.linear_tbl0_addr);
+ iounmap(isif_cfg.linear_tbl1_addr);
+ while (i < 3) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ i++;
+ }
+ vpfe_unregister_ccdc_device(&isif_hw_dev);
+ return 0;
+}
+
+static struct platform_driver isif_driver = {
+ .driver = {
+ .name = "isif",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(isif_remove),
+ .probe = isif_probe,
+};
+
+static int __init isif_init(void)
+{
+ return platform_driver_register(&isif_driver);
+}
+
+static void isif_exit(void)
+{
+ platform_driver_unregister(&isif_driver);
+}
+
+module_init(isif_init);
+module_exit(isif_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/davinci/isif_regs.h b/drivers/media/video/davinci/isif_regs.h
new file mode 100644
index 000000000000..f7b8893a2957
--- /dev/null
+++ b/drivers/media/video/davinci/isif_regs.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _ISIF_REGS_H
+#define _ISIF_REGS_H
+
+/* ISIF registers relative offsets */
+#define SYNCEN 0x00
+#define MODESET 0x04
+#define HDW 0x08
+#define VDW 0x0c
+#define PPLN 0x10
+#define LPFR 0x14
+#define SPH 0x18
+#define LNH 0x1c
+#define SLV0 0x20
+#define SLV1 0x24
+#define LNV 0x28
+#define CULH 0x2c
+#define CULV 0x30
+#define HSIZE 0x34
+#define SDOFST 0x38
+#define CADU 0x3c
+#define CADL 0x40
+#define LINCFG0 0x44
+#define LINCFG1 0x48
+#define CCOLP 0x4c
+#define CRGAIN 0x50
+#define CGRGAIN 0x54
+#define CGBGAIN 0x58
+#define CBGAIN 0x5c
+#define COFSTA 0x60
+#define FLSHCFG0 0x64
+#define FLSHCFG1 0x68
+#define FLSHCFG2 0x6c
+#define VDINT0 0x70
+#define VDINT1 0x74
+#define VDINT2 0x78
+#define MISC 0x7c
+#define CGAMMAWD 0x80
+#define REC656IF 0x84
+#define CCDCFG 0x88
+/*****************************************************
+* Defect Correction registers
+*****************************************************/
+#define DFCCTL 0x8c
+#define VDFSATLV 0x90
+#define DFCMEMCTL 0x94
+#define DFCMEM0 0x98
+#define DFCMEM1 0x9c
+#define DFCMEM2 0xa0
+#define DFCMEM3 0xa4
+#define DFCMEM4 0xa8
+/****************************************************
+* Black Clamp registers
+****************************************************/
+#define CLAMPCFG 0xac
+#define CLDCOFST 0xb0
+#define CLSV 0xb4
+#define CLHWIN0 0xb8
+#define CLHWIN1 0xbc
+#define CLHWIN2 0xc0
+#define CLVRV 0xc4
+#define CLVWIN0 0xc8
+#define CLVWIN1 0xcc
+#define CLVWIN2 0xd0
+#define CLVWIN3 0xd4
+/****************************************************
+* Lense Shading Correction
+****************************************************/
+#define DATAHOFST 0xd8
+#define DATAVOFST 0xdc
+#define LSCHVAL 0xe0
+#define LSCVVAL 0xe4
+#define TWODLSCCFG 0xe8
+#define TWODLSCOFST 0xec
+#define TWODLSCINI 0xf0
+#define TWODLSCGRBU 0xf4
+#define TWODLSCGRBL 0xf8
+#define TWODLSCGROF 0xfc
+#define TWODLSCORBU 0x100
+#define TWODLSCORBL 0x104
+#define TWODLSCOROF 0x108
+#define TWODLSCIRQEN 0x10c
+#define TWODLSCIRQST 0x110
+/****************************************************
+* Data formatter
+****************************************************/
+#define FMTCFG 0x114
+#define FMTPLEN 0x118
+#define FMTSPH 0x11c
+#define FMTLNH 0x120
+#define FMTSLV 0x124
+#define FMTLNV 0x128
+#define FMTRLEN 0x12c
+#define FMTHCNT 0x130
+#define FMTAPTR_BASE 0x134
+/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */
+#define FMTAPTR(i) (FMTAPTR_BASE + (i * 4))
+#define FMTPGMVF0 0x174
+#define FMTPGMVF1 0x178
+#define FMTPGMAPU0 0x17c
+#define FMTPGMAPU1 0x180
+#define FMTPGMAPS0 0x184
+#define FMTPGMAPS1 0x188
+#define FMTPGMAPS2 0x18c
+#define FMTPGMAPS3 0x190
+#define FMTPGMAPS4 0x194
+#define FMTPGMAPS5 0x198
+#define FMTPGMAPS6 0x19c
+#define FMTPGMAPS7 0x1a0
+/************************************************
+* Color Space Converter
+************************************************/
+#define CSCCTL 0x1a4
+#define CSCM0 0x1a8
+#define CSCM1 0x1ac
+#define CSCM2 0x1b0
+#define CSCM3 0x1b4
+#define CSCM4 0x1b8
+#define CSCM5 0x1bc
+#define CSCM6 0x1c0
+#define CSCM7 0x1c4
+#define OBWIN0 0x1c8
+#define OBWIN1 0x1cc
+#define OBWIN2 0x1d0
+#define OBWIN3 0x1d4
+#define OBVAL0 0x1d8
+#define OBVAL1 0x1dc
+#define OBVAL2 0x1e0
+#define OBVAL3 0x1e4
+#define OBVAL4 0x1e8
+#define OBVAL5 0x1ec
+#define OBVAL6 0x1f0
+#define OBVAL7 0x1f4
+#define CLKCTL 0x1f8
+
+/* Masks & Shifts below */
+#define START_PX_HOR_MASK 0x7FFF
+#define NUM_PX_HOR_MASK 0x7FFF
+#define START_VER_ONE_MASK 0x7FFF
+#define START_VER_TWO_MASK 0x7FFF
+#define NUM_LINES_VER 0x7FFF
+
+/* gain - offset masks */
+#define GAIN_INTEGER_SHIFT 9
+#define OFFSET_MASK 0xFFF
+#define GAIN_SDRAM_EN_SHIFT 12
+#define GAIN_IPIPE_EN_SHIFT 13
+#define GAIN_H3A_EN_SHIFT 14
+#define OFST_SDRAM_EN_SHIFT 8
+#define OFST_IPIPE_EN_SHIFT 9
+#define OFST_H3A_EN_SHIFT 10
+#define GAIN_OFFSET_EN_MASK 0x7700
+
+/* Culling */
+#define CULL_PAT_EVEN_LINE_SHIFT 8
+
+/* CCDCFG register */
+#define ISIF_YCINSWP_RAW (0x00 << 4)
+#define ISIF_YCINSWP_YCBCR (0x01 << 4)
+#define ISIF_CCDCFG_FIDMD_LATCH_VSYNC (0x00 << 6)
+#define ISIF_CCDCFG_WENLOG_AND (0x00 << 8)
+#define ISIF_CCDCFG_TRGSEL_WEN (0x00 << 9)
+#define ISIF_CCDCFG_EXTRG_DISABLE (0x00 << 10)
+#define ISIF_LATCH_ON_VSYNC_DISABLE (0x01 << 15)
+#define ISIF_LATCH_ON_VSYNC_ENABLE (0x00 << 15)
+#define ISIF_DATA_PACK_MASK 3
+#define ISIF_DATA_PACK16 0
+#define ISIF_DATA_PACK12 1
+#define ISIF_DATA_PACK8 2
+#define ISIF_PIX_ORDER_SHIFT 11
+#define ISIF_BW656_ENABLE (0x01 << 5)
+
+/* MODESET registers */
+#define ISIF_VDHDOUT_INPUT (0x00 << 0)
+#define ISIF_INPUT_SHIFT 12
+#define ISIF_RAW_INPUT_MODE 0
+#define ISIF_FID_POL_SHIFT 4
+#define ISIF_HD_POL_SHIFT 3
+#define ISIF_VD_POL_SHIFT 2
+#define ISIF_DATAPOL_NORMAL 0
+#define ISIF_DATAPOL_SHIFT 6
+#define ISIF_EXWEN_DISABLE 0
+#define ISIF_EXWEN_SHIFT 5
+#define ISIF_FRM_FMT_SHIFT 7
+#define ISIF_DATASFT_SHIFT 8
+#define ISIF_LPF_SHIFT 14
+#define ISIF_LPF_MASK 1
+
+/* GAMMAWD registers */
+#define ISIF_ALAW_GAMA_WD_MASK 0xF
+#define ISIF_ALAW_GAMA_WD_SHIFT 1
+#define ISIF_ALAW_ENABLE 1
+#define ISIF_GAMMAWD_CFA_SHIFT 5
+
+/* HSIZE registers */
+#define ISIF_HSIZE_FLIP_MASK 1
+#define ISIF_HSIZE_FLIP_SHIFT 12
+
+/* MISC registers */
+#define ISIF_DPCM_EN_SHIFT 12
+#define ISIF_DPCM_PREDICTOR_SHIFT 13
+
+/* Black clamp related */
+#define ISIF_BC_MODE_COLOR_SHIFT 4
+#define ISIF_HORZ_BC_MODE_SHIFT 1
+#define ISIF_HORZ_BC_WIN_SEL_SHIFT 5
+#define ISIF_HORZ_BC_PIX_LIMIT_SHIFT 6
+#define ISIF_HORZ_BC_WIN_H_SIZE_SHIFT 8
+#define ISIF_HORZ_BC_WIN_V_SIZE_SHIFT 12
+#define ISIF_VERT_BC_RST_VAL_SEL_SHIFT 4
+#define ISIF_VERT_BC_LINE_AVE_COEF_SHIFT 8
+
+/* VDFC registers */
+#define ISIF_VDFC_EN_SHIFT 4
+#define ISIF_VDFC_CORR_MOD_SHIFT 5
+#define ISIF_VDFC_CORR_WHOLE_LN_SHIFT 7
+#define ISIF_VDFC_LEVEL_SHFT_SHIFT 8
+#define ISIF_VDFC_POS_MASK 0x1FFF
+#define ISIF_DFCMEMCTL_DFCMARST_SHIFT 2
+
+/* CSC registers */
+#define ISIF_CSC_COEF_INTEG_MASK 7
+#define ISIF_CSC_COEF_DECIMAL_MASK 0x1f
+#define ISIF_CSC_COEF_INTEG_SHIFT 5
+#define ISIF_CSCM_MSB_SHIFT 8
+#define ISIF_DF_CSC_SPH_MASK 0x1FFF
+#define ISIF_DF_CSC_LNH_MASK 0x1FFF
+#define ISIF_DF_CSC_SLV_MASK 0x1FFF
+#define ISIF_DF_CSC_LNV_MASK 0x1FFF
+#define ISIF_DF_NUMLINES 0x7FFF
+#define ISIF_DF_NUMPIX 0x1FFF
+
+/* Offsets for LSC/DFC/Gain */
+#define ISIF_DATA_H_OFFSET_MASK 0x1FFF
+#define ISIF_DATA_V_OFFSET_MASK 0x1FFF
+
+/* Linearization */
+#define ISIF_LIN_CORRSFT_SHIFT 4
+#define ISIF_LIN_SCALE_FACT_INTEG_SHIFT 10
+
+
+/* Pattern registers */
+#define ISIF_PG_EN (1 << 3)
+#define ISIF_SEL_PG_SRC (3 << 4)
+#define ISIF_PG_VD_POL_SHIFT 0
+#define ISIF_PG_HD_POL_SHIFT 1
+
+/*random other junk*/
+#define ISIF_SYNCEN_VDHDEN_MASK (1 << 0)
+#define ISIF_SYNCEN_WEN_MASK (1 << 1)
+#define ISIF_SYNCEN_WEN_SHIFT 1
+
+#endif
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
index de22bc9faf21..885cd54499cf 100644
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -107,9 +107,6 @@ struct ccdc_config {
int vpfe_probed;
/* name of ccdc device */
char name[32];
- /* for storing mem maps for CCDC */
- int ccdc_addr_size;
- void *__iomem ccdc_addr;
};
/* data structures */
@@ -229,7 +226,6 @@ int vpfe_register_ccdc_device(struct ccdc_hw_device *dev)
BUG_ON(!dev->hw_ops.set_image_window);
BUG_ON(!dev->hw_ops.get_image_window);
BUG_ON(!dev->hw_ops.get_line_length);
- BUG_ON(!dev->hw_ops.setfbaddr);
BUG_ON(!dev->hw_ops.getfid);
mutex_lock(&ccdc_lock);
@@ -240,25 +236,23 @@ int vpfe_register_ccdc_device(struct ccdc_hw_device *dev)
* walk through it during vpfe probe
*/
printk(KERN_ERR "vpfe capture not initialized\n");
- ret = -1;
+ ret = -EFAULT;
goto unlock;
}
if (strcmp(dev->name, ccdc_cfg->name)) {
/* ignore this ccdc */
- ret = -1;
+ ret = -EINVAL;
goto unlock;
}
if (ccdc_dev) {
printk(KERN_ERR "ccdc already registered\n");
- ret = -1;
+ ret = -EINVAL;
goto unlock;
}
ccdc_dev = dev;
- dev->hw_ops.set_ccdc_base(ccdc_cfg->ccdc_addr,
- ccdc_cfg->ccdc_addr_size);
unlock:
mutex_unlock(&ccdc_lock);
return ret;
@@ -1786,61 +1780,6 @@ static struct vpfe_device *vpfe_initialize(void)
return vpfe_dev;
}
-static void vpfe_disable_clock(struct vpfe_device *vpfe_dev)
-{
- struct vpfe_config *vpfe_cfg = vpfe_dev->cfg;
-
- clk_disable(vpfe_cfg->vpssclk);
- clk_put(vpfe_cfg->vpssclk);
- clk_disable(vpfe_cfg->slaveclk);
- clk_put(vpfe_cfg->slaveclk);
- v4l2_info(vpfe_dev->pdev->driver,
- "vpfe vpss master & slave clocks disabled\n");
-}
-
-static int vpfe_enable_clock(struct vpfe_device *vpfe_dev)
-{
- struct vpfe_config *vpfe_cfg = vpfe_dev->cfg;
- int ret = -ENOENT;
-
- vpfe_cfg->vpssclk = clk_get(vpfe_dev->pdev, "vpss_master");
- if (NULL == vpfe_cfg->vpssclk) {
- v4l2_err(vpfe_dev->pdev->driver, "No clock defined for"
- "vpss_master\n");
- return ret;
- }
-
- if (clk_enable(vpfe_cfg->vpssclk)) {
- v4l2_err(vpfe_dev->pdev->driver,
- "vpfe vpss master clock not enabled\n");
- goto out;
- }
- v4l2_info(vpfe_dev->pdev->driver,
- "vpfe vpss master clock enabled\n");
-
- vpfe_cfg->slaveclk = clk_get(vpfe_dev->pdev, "vpss_slave");
- if (NULL == vpfe_cfg->slaveclk) {
- v4l2_err(vpfe_dev->pdev->driver,
- "No clock defined for vpss slave\n");
- goto out;
- }
-
- if (clk_enable(vpfe_cfg->slaveclk)) {
- v4l2_err(vpfe_dev->pdev->driver,
- "vpfe vpss slave clock not enabled\n");
- goto out;
- }
- v4l2_info(vpfe_dev->pdev->driver, "vpfe vpss slave clock enabled\n");
- return 0;
-out:
- if (vpfe_cfg->vpssclk)
- clk_put(vpfe_cfg->vpssclk);
- if (vpfe_cfg->slaveclk)
- clk_put(vpfe_cfg->slaveclk);
-
- return -1;
-}
-
/*
* vpfe_probe : This function creates device entries by register
* itself to the V4L2 driver and initializes fields of each
@@ -1870,7 +1809,7 @@ static __init int vpfe_probe(struct platform_device *pdev)
if (NULL == pdev->dev.platform_data) {
v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n");
- ret = -ENOENT;
+ ret = -ENODEV;
goto probe_free_dev_mem;
}
@@ -1884,18 +1823,13 @@ static __init int vpfe_probe(struct platform_device *pdev)
goto probe_free_dev_mem;
}
- /* enable vpss clocks */
- ret = vpfe_enable_clock(vpfe_dev);
- if (ret)
- goto probe_free_dev_mem;
-
mutex_lock(&ccdc_lock);
/* Allocate memory for ccdc configuration */
ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL);
if (NULL == ccdc_cfg) {
v4l2_err(pdev->dev.driver,
"Memory allocation failed for ccdc_cfg\n");
- goto probe_disable_clock;
+ goto probe_free_dev_mem;
}
strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32);
@@ -1904,61 +1838,34 @@ static __init int vpfe_probe(struct platform_device *pdev)
if (!res1) {
v4l2_err(pdev->dev.driver,
"Unable to get interrupt for VINT0\n");
- ret = -ENOENT;
- goto probe_disable_clock;
+ ret = -ENODEV;
+ goto probe_free_ccdc_cfg_mem;
}
vpfe_dev->ccdc_irq0 = res1->start;
/* Get VINT1 irq resource */
- res1 = platform_get_resource(pdev,
- IORESOURCE_IRQ, 1);
+ res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
if (!res1) {
v4l2_err(pdev->dev.driver,
"Unable to get interrupt for VINT1\n");
- ret = -ENOENT;
- goto probe_disable_clock;
+ ret = -ENODEV;
+ goto probe_free_ccdc_cfg_mem;
}
vpfe_dev->ccdc_irq1 = res1->start;
- /* Get address base of CCDC */
- res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res1) {
- v4l2_err(pdev->dev.driver,
- "Unable to get register address map\n");
- ret = -ENOENT;
- goto probe_disable_clock;
- }
-
- ccdc_cfg->ccdc_addr_size = res1->end - res1->start + 1;
- if (!request_mem_region(res1->start, ccdc_cfg->ccdc_addr_size,
- pdev->dev.driver->name)) {
- v4l2_err(pdev->dev.driver,
- "Failed request_mem_region for ccdc base\n");
- ret = -ENXIO;
- goto probe_disable_clock;
- }
- ccdc_cfg->ccdc_addr = ioremap_nocache(res1->start,
- ccdc_cfg->ccdc_addr_size);
- if (!ccdc_cfg->ccdc_addr) {
- v4l2_err(pdev->dev.driver, "Unable to ioremap ccdc addr\n");
- ret = -ENXIO;
- goto probe_out_release_mem1;
- }
-
ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED,
"vpfe_capture0", vpfe_dev);
if (0 != ret) {
v4l2_err(pdev->dev.driver, "Unable to request interrupt\n");
- goto probe_out_unmap1;
+ goto probe_free_ccdc_cfg_mem;
}
/* Allocate memory for video device */
vfd = video_device_alloc();
if (NULL == vfd) {
ret = -ENOMEM;
- v4l2_err(pdev->dev.driver,
- "Unable to alloc video device\n");
+ v4l2_err(pdev->dev.driver, "Unable to alloc video device\n");
goto probe_out_release_irq;
}
@@ -2073,12 +1980,7 @@ probe_out_video_release:
video_device_release(vpfe_dev->video_dev);
probe_out_release_irq:
free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
-probe_out_unmap1:
- iounmap(ccdc_cfg->ccdc_addr);
-probe_out_release_mem1:
- release_mem_region(res1->start, res1->end - res1->start + 1);
-probe_disable_clock:
- vpfe_disable_clock(vpfe_dev);
+probe_free_ccdc_cfg_mem:
mutex_unlock(&ccdc_lock);
kfree(ccdc_cfg);
probe_free_dev_mem:
@@ -2092,7 +1994,6 @@ probe_free_dev_mem:
static int __devexit vpfe_remove(struct platform_device *pdev)
{
struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev);
- struct resource *res;
v4l2_info(pdev->dev.driver, "vpfe_remove\n");
@@ -2100,12 +2001,6 @@ static int __devexit vpfe_remove(struct platform_device *pdev)
kfree(vpfe_dev->sd);
v4l2_device_unregister(&vpfe_dev->v4l2_dev);
video_unregister_device(vpfe_dev->video_dev);
- mutex_lock(&ccdc_lock);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, res->end - res->start + 1);
- iounmap(ccdc_cfg->ccdc_addr);
- mutex_unlock(&ccdc_lock);
- vpfe_disable_clock(vpfe_dev);
kfree(vpfe_dev);
kfree(ccdc_cfg);
return 0;
diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c
index 7ee72ecd3d81..7918680917d0 100644
--- a/drivers/media/video/davinci/vpss.c
+++ b/drivers/media/video/davinci/vpss.c
@@ -15,7 +15,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * common vpss driver for all video drivers.
+ * common vpss system module platform driver for all video drivers.
*/
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -35,12 +35,52 @@ MODULE_AUTHOR("Texas Instruments");
/* DM644x defines */
#define DM644X_SBL_PCR_VPSS (4)
+#define DM355_VPSSBL_INTSEL 0x10
+#define DM355_VPSSBL_EVTSEL 0x14
/* vpss BL register offsets */
#define DM355_VPSSBL_CCDCMUX 0x1c
/* vpss CLK register offsets */
#define DM355_VPSSCLK_CLKCTRL 0x04
/* masks and shifts */
#define VPSS_HSSISEL_SHIFT 4
+/*
+ * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4,
+ * IPIPE_INT1_SDR - vpss_int5
+ */
+#define DM355_VPSSBL_INTSEL_DEFAULT 0xff83ff10
+/* VENCINT - vpss_int8 */
+#define DM355_VPSSBL_EVTSEL_DEFAULT 0x4
+
+#define DM365_ISP5_PCCR 0x04
+#define DM365_ISP5_INTSEL1 0x10
+#define DM365_ISP5_INTSEL2 0x14
+#define DM365_ISP5_INTSEL3 0x18
+#define DM365_ISP5_CCDCMUX 0x20
+#define DM365_ISP5_PG_FRAME_SIZE 0x28
+#define DM365_VPBE_CLK_CTRL 0x00
+/*
+ * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1,
+ * AF - vpss_int3
+ */
+#define DM365_ISP5_INTSEL1_DEFAULT 0x0b1f0100
+/* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */
+#define DM365_ISP5_INTSEL2_DEFAULT 0x1f0a0f1f
+/* VENC - vpss_int8 */
+#define DM365_ISP5_INTSEL3_DEFAULT 0x00000015
+
+/* masks and shifts for DM365*/
+#define DM365_CCDC_PG_VD_POL_SHIFT 0
+#define DM365_CCDC_PG_HD_POL_SHIFT 1
+
+#define CCD_SRC_SEL_MASK (BIT_MASK(5) | BIT_MASK(4))
+#define CCD_SRC_SEL_SHIFT 4
+
+/* Different SoC platforms supported by this driver */
+enum vpss_platform_type {
+ DM644X,
+ DM355,
+ DM365,
+};
/*
* vpss operations. Depends on platform. Not all functions are available
@@ -59,13 +99,9 @@ struct vpss_hw_ops {
/* vpss configuration */
struct vpss_oper_config {
- __iomem void *vpss_bl_regs_base;
- __iomem void *vpss_regs_base;
- struct resource *r1;
- resource_size_t len1;
- struct resource *r2;
- resource_size_t len2;
- char vpss_name[32];
+ __iomem void *vpss_regs_base0;
+ __iomem void *vpss_regs_base1;
+ enum vpss_platform_type platform;
spinlock_t vpss_lock;
struct vpss_hw_ops hw_ops;
};
@@ -75,22 +111,46 @@ static struct vpss_oper_config oper_cfg;
/* register access routines */
static inline u32 bl_regr(u32 offset)
{
- return __raw_readl(oper_cfg.vpss_bl_regs_base + offset);
+ return __raw_readl(oper_cfg.vpss_regs_base0 + offset);
}
static inline void bl_regw(u32 val, u32 offset)
{
- __raw_writel(val, oper_cfg.vpss_bl_regs_base + offset);
+ __raw_writel(val, oper_cfg.vpss_regs_base0 + offset);
}
static inline u32 vpss_regr(u32 offset)
{
- return __raw_readl(oper_cfg.vpss_regs_base + offset);
+ return __raw_readl(oper_cfg.vpss_regs_base1 + offset);
}
static inline void vpss_regw(u32 val, u32 offset)
{
- __raw_writel(val, oper_cfg.vpss_regs_base + offset);
+ __raw_writel(val, oper_cfg.vpss_regs_base1 + offset);
+}
+
+/* For DM365 only */
+static inline u32 isp5_read(u32 offset)
+{
+ return __raw_readl(oper_cfg.vpss_regs_base0 + offset);
+}
+
+/* For DM365 only */
+static inline void isp5_write(u32 val, u32 offset)
+{
+ __raw_writel(val, oper_cfg.vpss_regs_base0 + offset);
+}
+
+static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
+{
+ u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK;
+
+ /* if we are using pattern generator, enable it */
+ if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG)
+ temp |= 0x08;
+
+ temp |= (src_sel << CCD_SRC_SEL_SHIFT);
+ isp5_write(temp, DM365_ISP5_CCDCMUX);
}
static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
@@ -101,9 +161,9 @@ static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
{
if (!oper_cfg.hw_ops.select_ccdc_source)
- return -1;
+ return -EINVAL;
- dm355_select_ccdc_source(src_sel);
+ oper_cfg.hw_ops.select_ccdc_source(src_sel);
return 0;
}
EXPORT_SYMBOL(vpss_select_ccdc_source);
@@ -114,7 +174,7 @@ static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
if (wbl_sel < VPSS_PCR_AEW_WBL_0 ||
wbl_sel > VPSS_PCR_CCDC_WBL_O)
- return -1;
+ return -EINVAL;
/* writing a 0 clear the overflow */
mask = ~(mask << wbl_sel);
@@ -126,7 +186,7 @@ static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
{
if (!oper_cfg.hw_ops.clear_wbl_overflow)
- return -1;
+ return -EINVAL;
return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel);
}
@@ -166,7 +226,7 @@ static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en)
default:
printk(KERN_ERR "dm355_enable_clock:"
" Invalid selector: %d\n", clock_sel);
- return -1;
+ return -EINVAL;
}
spin_lock_irqsave(&oper_cfg.vpss_lock, flags);
@@ -181,100 +241,221 @@ static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en)
return 0;
}
+static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en)
+{
+ unsigned long flags;
+ u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR;
+ u32 (*read)(u32 offset) = isp5_read;
+ void(*write)(u32 val, u32 offset) = isp5_write;
+
+ switch (clock_sel) {
+ case VPSS_BL_CLOCK:
+ break;
+ case VPSS_CCDC_CLOCK:
+ shift = 1;
+ break;
+ case VPSS_H3A_CLOCK:
+ shift = 2;
+ break;
+ case VPSS_RSZ_CLOCK:
+ shift = 3;
+ break;
+ case VPSS_IPIPE_CLOCK:
+ shift = 4;
+ break;
+ case VPSS_IPIPEIF_CLOCK:
+ shift = 5;
+ break;
+ case VPSS_PCLK_INTERNAL:
+ shift = 6;
+ break;
+ case VPSS_PSYNC_CLOCK_SEL:
+ shift = 7;
+ break;
+ case VPSS_VPBE_CLOCK:
+ read = vpss_regr;
+ write = vpss_regw;
+ offset = DM365_VPBE_CLK_CTRL;
+ break;
+ case VPSS_VENC_CLOCK_SEL:
+ shift = 2;
+ read = vpss_regr;
+ write = vpss_regw;
+ offset = DM365_VPBE_CLK_CTRL;
+ break;
+ case VPSS_LDC_CLOCK:
+ shift = 3;
+ read = vpss_regr;
+ write = vpss_regw;
+ offset = DM365_VPBE_CLK_CTRL;
+ break;
+ case VPSS_FDIF_CLOCK:
+ shift = 4;
+ read = vpss_regr;
+ write = vpss_regw;
+ offset = DM365_VPBE_CLK_CTRL;
+ break;
+ case VPSS_OSD_CLOCK_SEL:
+ shift = 6;
+ read = vpss_regr;
+ write = vpss_regw;
+ offset = DM365_VPBE_CLK_CTRL;
+ break;
+ case VPSS_LDC_CLOCK_SEL:
+ shift = 7;
+ read = vpss_regr;
+ write = vpss_regw;
+ offset = DM365_VPBE_CLK_CTRL;
+ break;
+ default:
+ printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n",
+ clock_sel);
+ return -1;
+ }
+
+ spin_lock_irqsave(&oper_cfg.vpss_lock, flags);
+ utemp = read(offset);
+ if (!en) {
+ mask = ~mask;
+ utemp &= (mask << shift);
+ } else
+ utemp |= (mask << shift);
+
+ write(utemp, offset);
+ spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags);
+
+ return 0;
+}
+
int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en)
{
if (!oper_cfg.hw_ops.enable_clock)
- return -1;
+ return -EINVAL;
return oper_cfg.hw_ops.enable_clock(clock_sel, en);
}
EXPORT_SYMBOL(vpss_enable_clock);
+void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync)
+{
+ int val = 0;
+ val = isp5_read(DM365_ISP5_CCDCMUX);
+
+ val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT);
+ val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT);
+
+ isp5_write(val, DM365_ISP5_CCDCMUX);
+}
+EXPORT_SYMBOL(dm365_vpss_set_sync_pol);
+
+void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)
+{
+ int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16;
+
+ current_reg |= (frame_size.pplen - 1);
+ isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE);
+}
+EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size);
+
static int __init vpss_probe(struct platform_device *pdev)
{
- int status, dm355 = 0;
+ struct resource *r1, *r2;
+ char *platform_name;
+ int status;
if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "no platform data\n");
return -ENOENT;
}
- strcpy(oper_cfg.vpss_name, pdev->dev.platform_data);
- if (!strcmp(oper_cfg.vpss_name, "dm355_vpss"))
- dm355 = 1;
- else if (strcmp(oper_cfg.vpss_name, "dm644x_vpss")) {
+ platform_name = pdev->dev.platform_data;
+ if (!strcmp(platform_name, "dm355_vpss"))
+ oper_cfg.platform = DM355;
+ else if (!strcmp(platform_name, "dm365_vpss"))
+ oper_cfg.platform = DM365;
+ else if (!strcmp(platform_name, "dm644x_vpss"))
+ oper_cfg.platform = DM644X;
+ else {
dev_err(&pdev->dev, "vpss driver not supported on"
" this platform\n");
return -ENODEV;
}
- dev_info(&pdev->dev, "%s vpss probed\n", oper_cfg.vpss_name);
- oper_cfg.r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!oper_cfg.r1)
+ dev_info(&pdev->dev, "%s vpss probed\n", platform_name);
+ r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r1)
return -ENOENT;
- oper_cfg.len1 = oper_cfg.r1->end - oper_cfg.r1->start + 1;
-
- oper_cfg.r1 = request_mem_region(oper_cfg.r1->start, oper_cfg.len1,
- oper_cfg.r1->name);
- if (!oper_cfg.r1)
+ r1 = request_mem_region(r1->start, resource_size(r1), r1->name);
+ if (!r1)
return -EBUSY;
- oper_cfg.vpss_bl_regs_base = ioremap(oper_cfg.r1->start, oper_cfg.len1);
- if (!oper_cfg.vpss_bl_regs_base) {
+ oper_cfg.vpss_regs_base0 = ioremap(r1->start, resource_size(r1));
+ if (!oper_cfg.vpss_regs_base0) {
status = -EBUSY;
goto fail1;
}
- if (dm355) {
- oper_cfg.r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!oper_cfg.r2) {
+ if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) {
+ r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!r2) {
status = -ENOENT;
goto fail2;
}
- oper_cfg.len2 = oper_cfg.r2->end - oper_cfg.r2->start + 1;
- oper_cfg.r2 = request_mem_region(oper_cfg.r2->start,
- oper_cfg.len2,
- oper_cfg.r2->name);
- if (!oper_cfg.r2) {
+ r2 = request_mem_region(r2->start, resource_size(r2), r2->name);
+ if (!r2) {
status = -EBUSY;
goto fail2;
}
- oper_cfg.vpss_regs_base = ioremap(oper_cfg.r2->start,
- oper_cfg.len2);
- if (!oper_cfg.vpss_regs_base) {
+ oper_cfg.vpss_regs_base1 = ioremap(r2->start,
+ resource_size(r2));
+ if (!oper_cfg.vpss_regs_base1) {
status = -EBUSY;
goto fail3;
}
}
- if (dm355) {
+ if (oper_cfg.platform == DM355) {
oper_cfg.hw_ops.enable_clock = dm355_enable_clock;
oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source;
+ /* Setup vpss interrupts */
+ bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL);
+ bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL);
+ } else if (oper_cfg.platform == DM365) {
+ oper_cfg.hw_ops.enable_clock = dm365_enable_clock;
+ oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source;
+ /* Setup vpss interrupts */
+ isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1);
+ isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2);
+ isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3);
} else
oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow;
spin_lock_init(&oper_cfg.vpss_lock);
- dev_info(&pdev->dev, "%s vpss probe success\n", oper_cfg.vpss_name);
+ dev_info(&pdev->dev, "%s vpss probe success\n", platform_name);
return 0;
fail3:
- release_mem_region(oper_cfg.r2->start, oper_cfg.len2);
+ release_mem_region(r2->start, resource_size(r2));
fail2:
- iounmap(oper_cfg.vpss_bl_regs_base);
+ iounmap(oper_cfg.vpss_regs_base0);
fail1:
- release_mem_region(oper_cfg.r1->start, oper_cfg.len1);
+ release_mem_region(r1->start, resource_size(r1));
return status;
}
static int __devexit vpss_remove(struct platform_device *pdev)
{
- iounmap(oper_cfg.vpss_bl_regs_base);
- release_mem_region(oper_cfg.r1->start, oper_cfg.len1);
- if (!strcmp(oper_cfg.vpss_name, "dm355_vpss")) {
- iounmap(oper_cfg.vpss_regs_base);
- release_mem_region(oper_cfg.r2->start, oper_cfg.len2);
+ struct resource *res;
+
+ iounmap(oper_cfg.vpss_regs_base0);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+ if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) {
+ iounmap(oper_cfg.vpss_regs_base1);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ release_mem_region(res->start, resource_size(res));
}
return 0;
}
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 25100001ffff..ecbcefb08739 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -232,6 +232,12 @@ static struct em28xx_reg_seq vc211a_enable[] = {
{ -1, -1, -1, -1},
};
+static struct em28xx_reg_seq dikom_dk300_digital[] = {
+ {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10},
+ {EM2880_R04_GPO, 0x08, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+
/*
* Board definitions
@@ -461,21 +467,30 @@ struct em28xx_board em28xx_boards[] = {
.name = "Leadtek Winfast USB II Deluxe",
.valid = EM28XX_BOARD_NOT_VALIDATED,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
- .tda9887_conf = TDA9887_PRESENT,
+ .has_ir_i2c = 1,
+ .tvaudio_addr = 0x58,
+ .tda9887_conf = TDA9887_PRESENT |
+ TDA9887_PORT2_ACTIVE |
+ TDA9887_QSS,
.decoder = EM28XX_SAA711X,
+ .adecoder = EM28XX_TVAUDIO,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
- .vmux = SAA7115_COMPOSITE2,
- .amux = EM28XX_AMUX_VIDEO,
+ .vmux = SAA7115_COMPOSITE4,
+ .amux = EM28XX_AMUX_AUX,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = SAA7115_COMPOSITE0,
+ .vmux = SAA7115_COMPOSITE5,
.amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
- .vmux = SAA7115_COMPOSITE0,
+ .vmux = SAA7115_SVIDEO3,
.amux = EM28XX_AMUX_LINE_IN,
} },
+ .radio = {
+ .type = EM28XX_RADIO,
+ .amux = EM28XX_AMUX_AUX,
+ }
},
[EM2820_BOARD_VIDEOLOGY_20K14XUSB] = {
.name = "Videology 20K14XUSB USB2.0",
@@ -730,11 +745,12 @@ struct em28xx_board em28xx_boards[] = {
[EM2880_BOARD_TERRATEC_HYBRID_XS_FR] = {
.name = "Terratec Hybrid XS Secam",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
.has_msp34xx = 1,
.tuner_type = TUNER_XC2028,
.tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
+ .has_dvb = 1,
+ .dvb_gpio = default_digital,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
@@ -1265,6 +1281,7 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA711X,
.has_dvb = 1,
.dvb_gpio = em2882_kworld_315u_digital,
+ .ir_codes = &ir_codes_kworld_315u_table,
.xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE,
/* Analog mode - still not ready */
@@ -1431,6 +1448,21 @@ struct em28xx_board em28xx_boards[] = {
.gpio = hauppauge_wintv_hvr_900_analog,
} },
},
+ [EM2882_BOARD_DIKOM_DK300] = {
+ .name = "Dikom DK300",
+ .tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
+ .decoder = EM28XX_TVP5150,
+ .mts_firmware = 1,
+ .has_dvb = 1,
+ .dvb_gpio = dikom_dk300_digital,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = TVP5150_COMPOSITE0,
+ .amux = EM28XX_AMUX_VIDEO,
+ .gpio = default_analog,
+ } },
+ },
[EM2883_BOARD_KWORLD_HYBRID_330U] = {
.name = "Kworld PlusTV HD Hybrid 330",
.tuner_type = TUNER_XC2028,
@@ -1751,6 +1783,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = {
{0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028},
{0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028},
{0x63f653bd, EM2870_BOARD_REDDO_DVB_C_USB_BOX, TUNER_ABSENT},
+ {0x4e913442, EM2882_BOARD_DIKOM_DK300, TUNER_XC2028},
};
/* I2C devicelist hash table for devices with generic USB IDs */
@@ -2103,6 +2136,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
ctl->demod = XC3028_FE_DEFAULT;
break;
case EM2883_BOARD_KWORLD_HYBRID_330U:
+ case EM2882_BOARD_DIKOM_DK300:
ctl->demod = XC3028_FE_CHINA;
ctl->fname = XC2028_DEFAULT_FIRMWARE;
break;
@@ -2259,9 +2293,12 @@ static int em28xx_hint_board(struct em28xx *dev)
/* ----------------------------------------------------------------------- */
void em28xx_register_i2c_ir(struct em28xx *dev)
{
+ /* Leadtek winfast tv USBII deluxe can find a non working IR-device */
+ /* at address 0x18, so if that address is needed for another board in */
+ /* the future, please put it after 0x1f. */
struct i2c_board_info info;
const unsigned short addr_list[] = {
- 0x30, 0x47, I2C_CLIENT_END
+ 0x1f, 0x30, 0x47, I2C_CLIENT_END
};
if (disable_ir)
@@ -2288,6 +2325,10 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
dev->init_data.ir_codes = &ir_codes_rc5_hauppauge_new_table;
dev->init_data.get_key = em28xx_get_key_em_haup;
dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
+ case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
+ dev->init_data.ir_codes = &ir_codes_winfast_usbii_deluxe_table;;
+ dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
+ dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)";
break;
}
@@ -2381,6 +2422,31 @@ void em28xx_card_setup(struct em28xx *dev)
em28xx_gpio_set(dev, dev->board.tuner_gpio);
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
break;
+
+/*
+ * The Dikom DK300 is detected as an Kworld VS-DVB-T 323UR.
+ *
+ * This occurs because they share identical USB vendor and
+ * product IDs.
+ *
+ * What we do here is look up the EEPROM hash of the Dikom
+ * and if it is found then we decide that we do not have
+ * a Kworld and reset the device to the Dikom instead.
+ *
+ * This solution is only valid if they do not share eeprom
+ * hash identities which has not been determined as yet.
+ */
+ case EM2882_BOARD_KWORLD_VS_DVBT:
+ if (!em28xx_hint_board(dev))
+ em28xx_set_model(dev);
+
+ /* In cases where we had to use a board hint, the call to
+ em28xx_set_mode() in em28xx_pre_card_setup() was a no-op,
+ so make the call now so the analog GPIOs are set properly
+ before probing the i2c bus. */
+ em28xx_gpio_set(dev, dev->board.tuner_gpio);
+ em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
+ break;
}
#if defined(CONFIG_MODULES) && defined(MODULE)
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index b311d4514bdf..5a37eccbd7d6 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -691,9 +691,15 @@ int em28xx_set_outfmt(struct em28xx *dev)
if (em28xx_vbi_supported(dev) == 1) {
vinctrl |= EM28XX_VINCTRL_VBI_RAW;
em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
- em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
- em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, 0xb4);
- em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, 0x0c);
+ em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
+ em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
+ if (dev->norm & V4L2_STD_525_60) {
+ /* NTSC */
+ em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
+ } else if (dev->norm & V4L2_STD_625_50) {
+ /* PAL */
+ em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
+ }
}
return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
@@ -760,6 +766,13 @@ int em28xx_resolution_set(struct em28xx *dev)
width = norm_maxw(dev);
height = norm_maxh(dev);
+ /* Properly setup VBI */
+ dev->vbi_width = 720;
+ if (dev->norm & V4L2_STD_525_60)
+ dev->vbi_height = 12;
+ else
+ dev->vbi_height = 18;
+
if (!dev->progressive)
height >>= norm_maxh(dev);
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index cc0505eb900f..1b96356b3ab2 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -502,7 +502,9 @@ static int dvb_init(struct em28xx *dev)
}
break;
case EM2880_BOARD_TERRATEC_HYBRID_XS:
+ case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
case EM2881_BOARD_PINNACLE_HYBRID_PRO:
+ case EM2882_BOARD_DIKOM_DK300:
dvb->frontend = dvb_attach(zl10353_attach,
&em28xx_zl10353_xc3028_no_i2c_gate,
&dev->i2c_adap);
@@ -606,6 +608,7 @@ static int dvb_fini(struct em28xx *dev)
if (dev->dvb) {
unregister_dvb(dev->dvb);
+ kfree(dev->dvb);
dev->dvb = NULL;
}
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index af0d935c29be..1fb754e20875 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -75,6 +75,10 @@ struct em28xx_IR {
unsigned int repeat_interval;
int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
+
+ /* IR device properties */
+
+ struct ir_dev_props props;
};
/**********************************************************
@@ -180,6 +184,36 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
return 1;
}
+int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char subaddr, keydetect, key;
+
+ struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, .buf = &subaddr, .len = 1},
+
+ { .addr = ir->c->addr, .flags = I2C_M_RD, .buf = &keydetect, .len = 1} };
+
+ subaddr = 0x10;
+ if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
+ i2cdprintk("read error\n");
+ return -EIO;
+ }
+ if (keydetect == 0x00)
+ return 0;
+
+ subaddr = 0x00;
+ msg[1].buf = &key;
+ if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
+ i2cdprintk("read error\n");
+ return -EIO;
+ }
+ if (key == 0x00)
+ return 0;
+
+ *ir_key = key;
+ *ir_raw = key;
+ return 1;
+}
+
/**********************************************************
Poll based get keycode functions
**********************************************************/
@@ -336,35 +370,28 @@ static void em28xx_ir_stop(struct em28xx_IR *ir)
cancel_delayed_work_sync(&ir->work);
}
-int em28xx_ir_init(struct em28xx *dev)
+int em28xx_ir_change_protocol(void *priv, u64 ir_type)
{
- struct em28xx_IR *ir;
- struct input_dev *input_dev;
- u8 ir_config;
- int err = -ENOMEM;
-
- if (dev->board.ir_codes == NULL) {
- /* No remote control support */
- return 0;
- }
-
- ir = kzalloc(sizeof(*ir), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev)
- goto err_out_free;
-
- ir->input = input_dev;
- ir_config = EM2874_IR_RC5;
+ int rc = 0;
+ struct em28xx_IR *ir = priv;
+ struct em28xx *dev = ir->dev;
+ u8 ir_config = EM2874_IR_RC5;
/* Adjust xclk based o IR table for RC5/NEC tables */
- if (dev->board.ir_codes->ir_type == IR_TYPE_RC5) {
+
+ dev->board.ir_codes->ir_type = IR_TYPE_OTHER;
+ if (ir_type == IR_TYPE_RC5) {
dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
ir->full_code = 1;
- } else if (dev->board.ir_codes->ir_type == IR_TYPE_NEC) {
+ } else if (ir_type == IR_TYPE_NEC) {
dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
ir_config = EM2874_IR_NEC;
ir->full_code = 1;
- }
+ } else
+ rc = -EINVAL;
+
+ dev->board.ir_codes->ir_type = ir_type;
+
em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
EM28XX_XCLK_IR_RC5_MODE);
@@ -380,9 +407,42 @@ int em28xx_ir_init(struct em28xx *dev)
break;
default:
printk("Unrecognized em28xx chip id: IR not supported\n");
- goto err_out_free;
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+int em28xx_ir_init(struct em28xx *dev)
+{
+ struct em28xx_IR *ir;
+ struct input_dev *input_dev;
+ int err = -ENOMEM;
+
+ if (dev->board.ir_codes == NULL) {
+ /* No remote control support */
+ return 0;
}
+ ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ir || !input_dev)
+ goto err_out_free;
+
+ /* record handles to ourself */
+ ir->dev = dev;
+ dev->ir = ir;
+
+ ir->input = input_dev;
+
+ /*
+ * em2874 supports more protocols. For now, let's just announce
+ * the two protocols that were already tested
+ */
+ ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
+ ir->props.priv = ir;
+ ir->props.change_protocol = em28xx_ir_change_protocol;
+
/* This is how often we ask the chip for IR information */
ir->polling = 100; /* ms */
@@ -393,6 +453,8 @@ int em28xx_ir_init(struct em28xx *dev)
usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
strlcat(ir->phys, "/input0", sizeof(ir->phys));
+ /* Set IR protocol */
+ em28xx_ir_change_protocol(ir, dev->board.ir_codes->ir_type);
err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER);
if (err < 0)
goto err_out_free;
@@ -405,14 +467,13 @@ int em28xx_ir_init(struct em28xx *dev)
input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
input_dev->dev.parent = &dev->udev->dev;
- /* record handles to ourself */
- ir->dev = dev;
- dev->ir = ir;
+
em28xx_ir_start(ir);
/* all done */
- err = ir_input_register(ir->input, dev->board.ir_codes);
+ err = ir_input_register(ir->input, dev->board.ir_codes,
+ &ir->props);
if (err)
goto err_out_stop;
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h
index 058ac87639ce..91e90559642b 100644
--- a/drivers/media/video/em28xx/em28xx-reg.h
+++ b/drivers/media/video/em28xx/em28xx-reg.h
@@ -173,8 +173,8 @@
/* em2874 IR config register (0x50) */
#define EM2874_IR_NEC 0x00
#define EM2874_IR_RC5 0x04
-#define EM2874_IR_RC5_MODE_0 0x08
-#define EM2874_IR_RC5_MODE_6A 0x0b
+#define EM2874_IR_RC6_MODE_0 0x08
+#define EM2874_IR_RC6_MODE_6A 0x0b
/* em2874 Transport Stream Enable Register (0x5f) */
#define EM2874_TS1_CAPTURE_ENABLE (1 << 0)
diff --git a/drivers/media/video/em28xx/em28xx-vbi.c b/drivers/media/video/em28xx/em28xx-vbi.c
index 94943e5a1529..c7dce39823d8 100644
--- a/drivers/media/video/em28xx/em28xx-vbi.c
+++ b/drivers/media/video/em28xx/em28xx-vbi.c
@@ -71,7 +71,11 @@ free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
static int
vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
{
- *size = 720 * 12 * 2;
+ struct em28xx_fh *fh = q->priv_data;
+ struct em28xx *dev = fh->dev;
+
+ *size = dev->vbi_width * dev->vbi_height * 2;
+
if (0 == *count)
*count = vbibufs;
if (*count < 2)
@@ -85,19 +89,18 @@ static int
vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
enum v4l2_field field)
{
+ struct em28xx_fh *fh = q->priv_data;
+ struct em28xx *dev = fh->dev;
struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
int rc = 0;
- unsigned int size;
-
- size = 720 * 12 * 2;
- buf->vb.size = size;
+ buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
- buf->vb.width = 720;
- buf->vb.height = 12;
+ buf->vb.width = dev->vbi_width;
+ buf->vb.height = dev->vbi_height;
buf->vb.field = field;
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 849b18c94037..ac2bd935927e 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -282,7 +282,7 @@ static void em28xx_copy_vbi(struct em28xx *dev,
{
void *startwrite, *startread;
int offset;
- int bytesperline = 720;
+ int bytesperline = dev->vbi_width;
if (dev == NULL) {
em28xx_isocdbg("dev is null\n");
@@ -323,8 +323,8 @@ static void em28xx_copy_vbi(struct em28xx *dev,
/* Make sure the bottom field populates the second half of the frame */
if (buf->top_field == 0) {
- startwrite += bytesperline * 0x0c;
- offset += bytesperline * 0x0c;
+ startwrite += bytesperline * dev->vbi_height;
+ offset += bytesperline * dev->vbi_height;
}
memcpy(startwrite, startread, len);
@@ -578,8 +578,7 @@ static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb)
dev->cur_field = p[2];
}
- /* FIXME: get rid of hard-coded value */
- vbi_size = 720 * 0x0c;
+ vbi_size = dev->vbi_width * dev->vbi_height;
if (dev->capture_type == 0) {
if (dev->vbi_read >= vbi_size) {
@@ -1850,18 +1849,27 @@ static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *format)
{
- format->fmt.vbi.samples_per_line = 720;
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ format->fmt.vbi.samples_per_line = dev->vbi_width;
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
format->fmt.vbi.offset = 0;
format->fmt.vbi.flags = 0;
+ format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+ format->fmt.vbi.count[0] = dev->vbi_height;
+ format->fmt.vbi.count[1] = dev->vbi_height;
/* Varies by video standard (NTSC, PAL, etc.) */
- /* FIXME: hard-coded for NTSC support */
- format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */
- format->fmt.vbi.count[0] = 12;
- format->fmt.vbi.count[1] = 12;
- format->fmt.vbi.start[0] = 10;
- format->fmt.vbi.start[1] = 273;
+ if (dev->norm & V4L2_STD_525_60) {
+ /* NTSC */
+ format->fmt.vbi.start[0] = 10;
+ format->fmt.vbi.start[1] = 273;
+ } else if (dev->norm & V4L2_STD_625_50) {
+ /* PAL */
+ format->fmt.vbi.start[0] = 6;
+ format->fmt.vbi.start[1] = 318;
+ }
return 0;
}
@@ -1869,18 +1877,27 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *format)
{
- format->fmt.vbi.samples_per_line = 720;
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ format->fmt.vbi.samples_per_line = dev->vbi_width;
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
format->fmt.vbi.offset = 0;
format->fmt.vbi.flags = 0;
+ format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+ format->fmt.vbi.count[0] = dev->vbi_height;
+ format->fmt.vbi.count[1] = dev->vbi_height;
/* Varies by video standard (NTSC, PAL, etc.) */
- /* FIXME: hard-coded for NTSC support */
- format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */
- format->fmt.vbi.count[0] = 12;
- format->fmt.vbi.count[1] = 12;
- format->fmt.vbi.start[0] = 10;
- format->fmt.vbi.start[1] = 273;
+ if (dev->norm & V4L2_STD_525_60) {
+ /* NTSC */
+ format->fmt.vbi.start[0] = 10;
+ format->fmt.vbi.start[1] = 273;
+ } else if (dev->norm & V4L2_STD_625_50) {
+ /* PAL */
+ format->fmt.vbi.start[0] = 6;
+ format->fmt.vbi.start[1] = 318;
+ }
return 0;
}
@@ -1922,7 +1939,8 @@ static int vidioc_querybuf(struct file *file, void *priv,
At a minimum, it causes a crash in zvbi since it does
a memcpy based on the source buffer length */
int result = videobuf_querybuf(&fh->vb_vbiq, b);
- b->length = 17280;
+ b->length = dev->vbi_width * dev->vbi_height * 2;
+
return result;
}
}
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 80d9b4fa1b97..ba6fe5daff84 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -111,6 +111,7 @@
#define EM2861_BOARD_GADMEI_UTV330PLUS 72
#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73
#define EM2800_BOARD_VC211A 74
+#define EM2882_BOARD_DIKOM_DK300 75
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -552,7 +553,8 @@ struct em28xx {
int capture_type;
int vbi_read;
unsigned char cur_field;
-
+ unsigned int vbi_width;
+ unsigned int vbi_height; /* lines per field */
struct work_struct request_module_wk;
@@ -693,6 +695,8 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
u32 *ir_raw);
+int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key,
+ u32 *ir_raw);
void em28xx_register_snapshot_button(struct em28xx *dev);
void em28xx_deregister_snapshot_button(struct em28xx *dev);
diff --git a/drivers/media/video/et61x251/Kconfig b/drivers/media/video/et61x251/Kconfig
index dcc1a0335440..87981b078fe6 100644
--- a/drivers/media/video/et61x251/Kconfig
+++ b/drivers/media/video/et61x251/Kconfig
@@ -1,7 +1,11 @@
config USB_ET61X251
- tristate "USB ET61X[12]51 PC Camera Controller support"
+ tristate "USB ET61X[12]51 PC Camera Controller support (DEPRECATED)"
depends on VIDEO_V4L2
+ default n
---help---
+ This driver is DEPRECATED please use the gspca zc3xx module
+ instead.
+
Say Y here if you want support for cameras based on Etoms ET61X151
or ET61X251 PC Camera Controllers.
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index 609d65b0b10d..e0060c1f0544 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -21,6 +21,15 @@ source "drivers/media/video/gspca/m5602/Kconfig"
source "drivers/media/video/gspca/stv06xx/Kconfig"
source "drivers/media/video/gspca/gl860/Kconfig"
+config USB_GSPCA_BENQ
+ tristate "Benq USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for the Benq DC E300 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_benq.
+
config USB_GSPCA_CONEX
tristate "Conexant Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
@@ -30,6 +39,17 @@ config USB_GSPCA_CONEX
To compile this driver as a module, choose M here: the
module will be called gspca_conex.
+config USB_GSPCA_CPIA1
+ tristate "cpia CPiA (version 1) Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for USB cameras based on the cpia
+ CPiA chip. Note that you need atleast version 0.6.4 of libv4l for
+ applications to understand the videoformat generated by this driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_cpia1.
+
config USB_GSPCA_ETOMS
tristate "Etoms USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
@@ -86,15 +106,25 @@ config USB_GSPCA_OV519
module will be called gspca_ov519.
config USB_GSPCA_OV534
- tristate "OV534 USB Camera Driver"
+ tristate "OV534 OV772x USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
help
- Say Y here if you want support for cameras based on the OV534 chip.
- (e.g. Sony Playstation EYE)
+ Say Y here if you want support for cameras based on the OV534 chip
+ and sensor OV772x (e.g. Sony Playstation EYE)
To compile this driver as a module, choose M here: the
module will be called gspca_ov534.
+config USB_GSPCA_OV534_9
+ tristate "OV534 OV965x USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the OV534 chip
+ and sensor OV965x (e.g. Hercules Dualpix)
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_ov534_9.
+
config USB_GSPCA_PAC207
tristate "Pixart PAC207 USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
@@ -122,6 +152,16 @@ config USB_GSPCA_PAC7311
To compile this driver as a module, choose M here: the
module will be called gspca_pac7311.
+config USB_GSPCA_SN9C2028
+ tristate "SONIX Dual-Mode USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want streaming support for Sonix SN9C2028 cameras.
+ These are supported as stillcams in libgphoto2/camlibs/sonix.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sn9c2028.
+
config USB_GSPCA_SN9C20X
tristate "SN9C20X USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index ff2c7279d82e..6e4cf1ce01c9 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -1,5 +1,7 @@
obj-$(CONFIG_USB_GSPCA) += gspca_main.o
+obj-$(CONFIG_USB_GSPCA_BENQ) += gspca_benq.o
obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o
+obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o
obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o
obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o
obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o
@@ -7,9 +9,11 @@ obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o
obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o
obj-$(CONFIG_USB_GSPCA_OV534) += gspca_ov534.o
+obj-$(CONFIG_USB_GSPCA_OV534_9) += gspca_ov534_9.o
obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o
obj-$(CONFIG_USB_GSPCA_PAC7302) += gspca_pac7302.o
obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o
+obj-$(CONFIG_USB_GSPCA_SN9C2028) += gspca_sn9c2028.o
obj-$(CONFIG_USB_GSPCA_SN9C20X) += gspca_sn9c20x.o
obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o
obj-$(CONFIG_USB_GSPCA_SONIXJ) += gspca_sonixj.o
@@ -30,7 +34,9 @@ obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o
obj-$(CONFIG_USB_GSPCA_ZC3XX) += gspca_zc3xx.o
gspca_main-objs := gspca.o
+gspca_benq-objs := benq.o
gspca_conex-objs := conex.o
+gspca_cpia1-objs := cpia1.o
gspca_etoms-objs := etoms.o
gspca_finepix-objs := finepix.o
gspca_jeilinj-objs := jeilinj.o
@@ -38,9 +44,11 @@ gspca_mars-objs := mars.o
gspca_mr97310a-objs := mr97310a.o
gspca_ov519-objs := ov519.o
gspca_ov534-objs := ov534.o
+gspca_ov534_9-objs := ov534_9.o
gspca_pac207-objs := pac207.o
gspca_pac7302-objs := pac7302.o
gspca_pac7311-objs := pac7311.o
+gspca_sn9c2028-objs := sn9c2028.o
gspca_sn9c20x-objs := sn9c20x.o
gspca_sonixb-objs := sonixb.o
gspca_sonixj-objs := sonixj.o
diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/video/gspca/benq.c
new file mode 100644
index 000000000000..43ac4af8d3ed
--- /dev/null
+++ b/drivers/media/video/gspca/benq.c
@@ -0,0 +1,322 @@
+/*
+ * Benq DC E300 subdriver
+ *
+ * Copyright (C) 2009 Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * 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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "benq"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("Benq DC E300 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+};
+
+/* V4L2 controls supported by the driver */
+static const struct ctrl sd_ctrls[] = {
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG},
+};
+
+static void sd_isoc_irq(struct urb *urb);
+
+/* -- write a register -- */
+static void reg_w(struct gspca_dev *gspca_dev,
+ u16 value, u16 index)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x02,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value,
+ index,
+ NULL,
+ 0,
+ 500);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_w err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ gspca_dev->cam.cam_mode = vga_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
+ gspca_dev->cam.no_urb_create = 1;
+ gspca_dev->cam.reverse_alts = 1;
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+ int ret;
+
+ ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface,
+ gspca_dev->nbalt - 1);
+ if (ret < 0) {
+ err("usb_set_interface failed");
+ return ret;
+ }
+/* reg_w(gspca_dev, 0x0003, 0x0002); */
+ return 0;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct urb *urb;
+ int i, n;
+
+ /* create 4 URBs - 2 on endpoint 0x83 and 2 on 0x082 */
+#if MAX_NURBS < 4
+#error "Not enough URBs in the gspca table"
+#endif
+#define SD_PKT_SZ 64
+#define SD_NPKT 32
+ for (n = 0; n < 4; n++) {
+ urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL);
+ if (!urb) {
+ err("usb_alloc_urb failed");
+ return -ENOMEM;
+ }
+ gspca_dev->urb[n] = urb;
+ urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,
+ SD_PKT_SZ * SD_NPKT,
+ GFP_KERNEL,
+ &urb->transfer_dma);
+
+ if (urb->transfer_buffer == NULL) {
+ err("usb_buffer_alloc failed");
+ return -ENOMEM;
+ }
+ urb->dev = gspca_dev->dev;
+ urb->context = gspca_dev;
+ urb->transfer_buffer_length = SD_PKT_SZ * SD_NPKT;
+ urb->pipe = usb_rcvisocpipe(gspca_dev->dev,
+ n & 1 ? 0x82 : 0x83);
+ urb->transfer_flags = URB_ISO_ASAP
+ | URB_NO_TRANSFER_DMA_MAP;
+ urb->interval = 1;
+ urb->complete = sd_isoc_irq;
+ urb->number_of_packets = SD_NPKT;
+ for (i = 0; i < SD_NPKT; i++) {
+ urb->iso_frame_desc[i].length = SD_PKT_SZ;
+ urb->iso_frame_desc[i].offset = SD_PKT_SZ * i;
+ }
+ }
+
+ return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev, 0x003c, 0x0003);
+ reg_w(gspca_dev, 0x003c, 0x0004);
+ reg_w(gspca_dev, 0x003c, 0x0005);
+ reg_w(gspca_dev, 0x003c, 0x0006);
+ reg_w(gspca_dev, 0x003c, 0x0007);
+ usb_set_interface(gspca_dev->dev, gspca_dev->iface, gspca_dev->nbalt - 1);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ /* unused */
+}
+
+/* reception of an URB */
+static void sd_isoc_irq(struct urb *urb)
+{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+ struct urb *urb0;
+ u8 *data;
+ int i, st;
+
+ PDEBUG(D_PACK, "sd isoc irq");
+ if (!gspca_dev->streaming)
+ return;
+ if (urb->status != 0) {
+ if (urb->status == -ESHUTDOWN)
+ return; /* disconnection */
+#ifdef CONFIG_PM
+ if (gspca_dev->frozen)
+ return;
+#endif
+ PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+ return;
+ }
+
+ /* if this is a control URN (ep 0x83), wait */
+ if (urb == gspca_dev->urb[0] || urb == gspca_dev->urb[2])
+ return;
+
+ /* scan both received URBs */
+ if (urb == gspca_dev->urb[1])
+ urb0 = gspca_dev->urb[0];
+ else
+ urb0 = gspca_dev->urb[2];
+ for (i = 0; i < urb->number_of_packets; i++) {
+
+ /* check the packet status and length */
+ if (urb0->iso_frame_desc[i].actual_length != SD_PKT_SZ
+ || urb->iso_frame_desc[i].actual_length != SD_PKT_SZ) {
+ PDEBUG(D_ERR, "ISOC bad lengths %d / %d",
+ urb0->iso_frame_desc[i].actual_length,
+ urb->iso_frame_desc[i].actual_length);
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ continue;
+ }
+ st = urb0->iso_frame_desc[i].status;
+ if (st == 0)
+ st = urb->iso_frame_desc[i].status;
+ if (st) {
+ PDEBUG(D_ERR,
+ "ISOC data error: [%d] status=%d",
+ i, st);
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ continue;
+ }
+
+ /*
+ * The images are received in URBs of different endpoints
+ * (0x83 and 0x82).
+ * Image pieces in URBs of ep 0x83 are continuated in URBs of
+ * ep 0x82 of the same index.
+ * The packets in the URBs of endpoint 0x83 start with:
+ * - 80 ba/bb 00 00 = start of image followed by 'ff d8'
+ * - 04 ba/bb oo oo = image piece
+ * where 'oo oo' is the image offset
+ (not cheked)
+ * - (other -> bad frame)
+ * The images are JPEG encoded with full header and
+ * normal ff escape.
+ * The end of image ('ff d9') may occur in any URB.
+ * (not cheked)
+ */
+ data = (u8 *) urb0->transfer_buffer
+ + urb0->iso_frame_desc[i].offset;
+ if (data[0] == 0x80 && (data[1] & 0xfe) == 0xba) {
+
+ /* new image */
+ gspca_frame_add(gspca_dev, LAST_PACKET,
+ NULL, 0);
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ data + 4, SD_PKT_SZ - 4);
+ } else if (data[0] == 0x04 && (data[1] & 0xfe) == 0xba) {
+ gspca_frame_add(gspca_dev, INTER_PACKET,
+ data + 4, SD_PKT_SZ - 4);
+ } else {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ continue;
+ }
+ data = (u8 *) urb->transfer_buffer
+ + urb->iso_frame_desc[i].offset;
+ gspca_frame_add(gspca_dev, INTER_PACKET,
+ data, SD_PKT_SZ);
+ }
+
+ /* resubmit the URBs */
+ st = usb_submit_urb(urb0, GFP_ATOMIC);
+ if (st < 0)
+ PDEBUG(D_ERR|D_PACK, "usb_submit_urb(0) ret %d", st);
+ st = usb_submit_urb(urb, GFP_ATOMIC);
+ if (st < 0)
+ PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st);
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .isoc_init = sd_isoc_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x04a5, 0x3035)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ int ret;
+
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
+ info("registered");
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/coarse_expo_autogain.h b/drivers/media/video/gspca/coarse_expo_autogain.h
new file mode 100644
index 000000000000..1cb9d941eaf6
--- /dev/null
+++ b/drivers/media/video/gspca/coarse_expo_autogain.h
@@ -0,0 +1,116 @@
+/*
+ * Auto gain algorithm for camera's with a coarse exposure control
+ *
+ * Copyright (C) 2010 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ */
+
+/* Autogain + exposure algorithm for cameras with a coarse exposure control
+ (usually this means we can only control the clockdiv to change exposure)
+ As changing the clockdiv so that the fps drops from 30 to 15 fps for
+ example, will lead to a huge exposure change (it effectively doubles),
+ this algorithm normally tries to only adjust the gain (between 40 and
+ 80 %) and if that does not help, only then changes exposure. This leads
+ to a much more stable image then using the knee algorithm which at
+ certain points of the knee graph will only try to adjust exposure,
+ which leads to oscilating as one exposure step is huge.
+
+ Note this assumes that the sd struct for the cam in question has
+ exp_too_high_cnt and exp_too_high_cnt int members for use by this function.
+
+ Returns 0 if no changes were made, 1 if the gain and or exposure settings
+ where changed. */
+static int gspca_coarse_grained_expo_autogain(struct gspca_dev *gspca_dev,
+ int avg_lum, int desired_avg_lum, int deadzone)
+{
+ int i, steps, gain, orig_gain, exposure, orig_exposure;
+ int gain_low, gain_high;
+ const struct ctrl *gain_ctrl = NULL;
+ const struct ctrl *exposure_ctrl = NULL;
+ struct sd *sd = (struct sd *) gspca_dev;
+ int retval = 0;
+
+ for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
+ if (gspca_dev->ctrl_dis & (1 << i))
+ continue;
+ if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN)
+ gain_ctrl = &gspca_dev->sd_desc->ctrls[i];
+ if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE)
+ exposure_ctrl = &gspca_dev->sd_desc->ctrls[i];
+ }
+ if (!gain_ctrl || !exposure_ctrl) {
+ PDEBUG(D_ERR, "Error: gspca_coarse_grained_expo_autogain "
+ "called on cam without gain or exposure");
+ return 0;
+ }
+
+ if (gain_ctrl->get(gspca_dev, &gain) ||
+ exposure_ctrl->get(gspca_dev, &exposure))
+ return 0;
+
+ orig_gain = gain;
+ orig_exposure = exposure;
+ gain_low =
+ (gain_ctrl->qctrl.maximum - gain_ctrl->qctrl.minimum) / 5 * 2;
+ gain_low += gain_ctrl->qctrl.minimum;
+ gain_high =
+ (gain_ctrl->qctrl.maximum - gain_ctrl->qctrl.minimum) / 5 * 4;
+ gain_high += gain_ctrl->qctrl.minimum;
+
+ /* If we are of a multiple of deadzone, do multiple steps to reach the
+ desired lumination fast (with the risc of a slight overshoot) */
+ steps = (desired_avg_lum - avg_lum) / deadzone;
+
+ PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
+ avg_lum, desired_avg_lum, steps);
+
+ if ((gain + steps) > gain_high &&
+ sd->exposure < exposure_ctrl->qctrl.maximum) {
+ gain = gain_high;
+ sd->exp_too_low_cnt++;
+ } else if ((gain + steps) < gain_low &&
+ sd->exposure > exposure_ctrl->qctrl.minimum) {
+ gain = gain_low;
+ sd->exp_too_high_cnt++;
+ } else {
+ gain += steps;
+ if (gain > gain_ctrl->qctrl.maximum)
+ gain = gain_ctrl->qctrl.maximum;
+ else if (gain < gain_ctrl->qctrl.minimum)
+ gain = gain_ctrl->qctrl.minimum;
+ sd->exp_too_high_cnt = 0;
+ sd->exp_too_low_cnt = 0;
+ }
+
+ if (sd->exp_too_high_cnt > 3) {
+ exposure--;
+ sd->exp_too_high_cnt = 0;
+ } else if (sd->exp_too_low_cnt > 3) {
+ exposure++;
+ sd->exp_too_low_cnt = 0;
+ }
+
+ if (gain != orig_gain) {
+ gain_ctrl->set(gspca_dev, gain);
+ retval = 1;
+ }
+ if (exposure != orig_exposure) {
+ exposure_ctrl->set(gspca_dev, exposure);
+ retval = 1;
+ }
+
+ return retval;
+}
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
index c98b5d69c438..19fe6b24c9a3 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/video/gspca/conex.c
@@ -52,7 +52,7 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
@@ -1032,7 +1032,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
}
/* sub-driver description */
-static struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c
new file mode 100644
index 000000000000..82945ed5cbe5
--- /dev/null
+++ b/drivers/media/video/gspca/cpia1.c
@@ -0,0 +1,2022 @@
+/*
+ * cpia CPiA (1) gspca driver
+ *
+ * Copyright (C) 2010 Hans de Goede <hdgoede@redhat.com>
+ *
+ * This module is adapted from the in kernel v4l1 cpia driver which is :
+ *
+ * (C) Copyright 1999-2000 Peter Pregler
+ * (C) Copyright 1999-2000 Scott J. Bertin
+ * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
+ * (C) Copyright 2000 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "cpia1"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>");
+MODULE_DESCRIPTION("Vision CPiA");
+MODULE_LICENSE("GPL");
+
+/* constant value's */
+#define MAGIC_0 0x19
+#define MAGIC_1 0x68
+#define DATA_IN 0xC0
+#define DATA_OUT 0x40
+#define VIDEOSIZE_QCIF 0 /* 176x144 */
+#define VIDEOSIZE_CIF 1 /* 352x288 */
+#define SUBSAMPLE_420 0
+#define SUBSAMPLE_422 1
+#define YUVORDER_YUYV 0
+#define YUVORDER_UYVY 1
+#define NOT_COMPRESSED 0
+#define COMPRESSED 1
+#define NO_DECIMATION 0
+#define DECIMATION_ENAB 1
+#define EOI 0xff /* End Of Image */
+#define EOL 0xfd /* End Of Line */
+#define FRAME_HEADER_SIZE 64
+
+/* Image grab modes */
+#define CPIA_GRAB_SINGLE 0
+#define CPIA_GRAB_CONTINEOUS 1
+
+/* Compression parameters */
+#define CPIA_COMPRESSION_NONE 0
+#define CPIA_COMPRESSION_AUTO 1
+#define CPIA_COMPRESSION_MANUAL 2
+#define CPIA_COMPRESSION_TARGET_QUALITY 0
+#define CPIA_COMPRESSION_TARGET_FRAMERATE 1
+
+/* Return offsets for GetCameraState */
+#define SYSTEMSTATE 0
+#define GRABSTATE 1
+#define STREAMSTATE 2
+#define FATALERROR 3
+#define CMDERROR 4
+#define DEBUGFLAGS 5
+#define VPSTATUS 6
+#define ERRORCODE 7
+
+/* SystemState */
+#define UNINITIALISED_STATE 0
+#define PASS_THROUGH_STATE 1
+#define LO_POWER_STATE 2
+#define HI_POWER_STATE 3
+#define WARM_BOOT_STATE 4
+
+/* GrabState */
+#define GRAB_IDLE 0
+#define GRAB_ACTIVE 1
+#define GRAB_DONE 2
+
+/* StreamState */
+#define STREAM_NOT_READY 0
+#define STREAM_READY 1
+#define STREAM_OPEN 2
+#define STREAM_PAUSED 3
+#define STREAM_FINISHED 4
+
+/* Fatal Error, CmdError, and DebugFlags */
+#define CPIA_FLAG 1
+#define SYSTEM_FLAG 2
+#define INT_CTRL_FLAG 4
+#define PROCESS_FLAG 8
+#define COM_FLAG 16
+#define VP_CTRL_FLAG 32
+#define CAPTURE_FLAG 64
+#define DEBUG_FLAG 128
+
+/* VPStatus */
+#define VP_STATE_OK 0x00
+
+#define VP_STATE_FAILED_VIDEOINIT 0x01
+#define VP_STATE_FAILED_AECACBINIT 0x02
+#define VP_STATE_AEC_MAX 0x04
+#define VP_STATE_ACB_BMAX 0x08
+
+#define VP_STATE_ACB_RMIN 0x10
+#define VP_STATE_ACB_GMIN 0x20
+#define VP_STATE_ACB_RMAX 0x40
+#define VP_STATE_ACB_GMAX 0x80
+
+/* default (minimum) compensation values */
+#define COMP_RED 220
+#define COMP_GREEN1 214
+#define COMP_GREEN2 COMP_GREEN1
+#define COMP_BLUE 230
+
+/* exposure status */
+#define EXPOSURE_VERY_LIGHT 0
+#define EXPOSURE_LIGHT 1
+#define EXPOSURE_NORMAL 2
+#define EXPOSURE_DARK 3
+#define EXPOSURE_VERY_DARK 4
+
+#define CPIA_MODULE_CPIA (0 << 5)
+#define CPIA_MODULE_SYSTEM (1 << 5)
+#define CPIA_MODULE_VP_CTRL (5 << 5)
+#define CPIA_MODULE_CAPTURE (6 << 5)
+#define CPIA_MODULE_DEBUG (7 << 5)
+
+#define INPUT (DATA_IN << 8)
+#define OUTPUT (DATA_OUT << 8)
+
+#define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
+#define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
+#define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
+#define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
+#define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
+#define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
+#define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
+#define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
+
+#define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
+#define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
+#define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
+#define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
+#define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
+#define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
+#define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
+#define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
+#define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
+#define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
+#define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
+#define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
+#define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
+
+#define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
+#define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
+#define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
+#define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
+#define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
+#define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
+#define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
+#define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
+#define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
+#define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
+#define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
+#define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
+#define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
+#define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
+#define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
+#define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
+#define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
+
+#define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
+#define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
+#define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
+#define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
+#define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
+#define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
+#define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
+#define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
+#define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
+#define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
+#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
+#define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
+#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
+#define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
+#define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
+
+#define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
+#define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
+#define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
+#define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
+#define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
+#define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
+#define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
+#define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
+
+#define ROUND_UP_EXP_FOR_FLICKER 15
+
+/* Constants for automatic frame rate adjustment */
+#define MAX_EXP 302
+#define MAX_EXP_102 255
+#define LOW_EXP 140
+#define VERY_LOW_EXP 70
+#define TC 94
+#define EXP_ACC_DARK 50
+#define EXP_ACC_LIGHT 90
+#define HIGH_COMP_102 160
+#define MAX_COMP 239
+#define DARK_TIME 3
+#define LIGHT_TIME 3
+
+#define FIRMWARE_VERSION(x, y) (sd->params.version.firmwareVersion == (x) && \
+ sd->params.version.firmwareRevision == (y))
+
+/* Developer's Guide Table 5 p 3-34
+ * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
+static u8 flicker_jumps[2][2][4] =
+{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
+ { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
+};
+
+struct cam_params {
+ struct {
+ u8 firmwareVersion;
+ u8 firmwareRevision;
+ u8 vcVersion;
+ u8 vcRevision;
+ } version;
+ struct {
+ u16 vendor;
+ u16 product;
+ u16 deviceRevision;
+ } pnpID;
+ struct {
+ u8 vpVersion;
+ u8 vpRevision;
+ u16 cameraHeadID;
+ } vpVersion;
+ struct {
+ u8 systemState;
+ u8 grabState;
+ u8 streamState;
+ u8 fatalError;
+ u8 cmdError;
+ u8 debugFlags;
+ u8 vpStatus;
+ u8 errorCode;
+ } status;
+ struct {
+ u8 brightness;
+ u8 contrast;
+ u8 saturation;
+ } colourParams;
+ struct {
+ u8 gainMode;
+ u8 expMode;
+ u8 compMode;
+ u8 centreWeight;
+ u8 gain;
+ u8 fineExp;
+ u8 coarseExpLo;
+ u8 coarseExpHi;
+ u8 redComp;
+ u8 green1Comp;
+ u8 green2Comp;
+ u8 blueComp;
+ } exposure;
+ struct {
+ u8 balanceMode;
+ u8 redGain;
+ u8 greenGain;
+ u8 blueGain;
+ } colourBalance;
+ struct {
+ u8 divisor;
+ u8 baserate;
+ } sensorFps;
+ struct {
+ u8 gain1;
+ u8 gain2;
+ u8 gain4;
+ u8 gain8;
+ } apcor;
+ struct {
+ u8 disabled;
+ u8 flickerMode;
+ u8 coarseJump;
+ u8 allowableOverExposure;
+ } flickerControl;
+ struct {
+ u8 gain1;
+ u8 gain2;
+ u8 gain4;
+ u8 gain8;
+ } vlOffset;
+ struct {
+ u8 mode;
+ u8 decimation;
+ } compression;
+ struct {
+ u8 frTargeting;
+ u8 targetFR;
+ u8 targetQ;
+ } compressionTarget;
+ struct {
+ u8 yThreshold;
+ u8 uvThreshold;
+ } yuvThreshold;
+ struct {
+ u8 hysteresis;
+ u8 threshMax;
+ u8 smallStep;
+ u8 largeStep;
+ u8 decimationHysteresis;
+ u8 frDiffStepThresh;
+ u8 qDiffStepThresh;
+ u8 decimationThreshMod;
+ } compressionParams;
+ struct {
+ u8 videoSize; /* CIF/QCIF */
+ u8 subSample;
+ u8 yuvOrder;
+ } format;
+ struct { /* Intel QX3 specific data */
+ u8 qx3_detected; /* a QX3 is present */
+ u8 toplight; /* top light lit , R/W */
+ u8 bottomlight; /* bottom light lit, R/W */
+ u8 button; /* snapshot button pressed (R/O) */
+ u8 cradled; /* microscope is in cradle (R/O) */
+ } qx3;
+ struct {
+ u8 colStart; /* skip first 8*colStart pixels */
+ u8 colEnd; /* finish at 8*colEnd pixels */
+ u8 rowStart; /* skip first 4*rowStart lines */
+ u8 rowEnd; /* finish at 4*rowEnd lines */
+ } roi;
+ u8 ecpTiming;
+ u8 streamStartLine;
+};
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ struct cam_params params; /* camera settings */
+
+ atomic_t cam_exposure;
+ atomic_t fps;
+ int exposure_count;
+ u8 exposure_status;
+ u8 mainsFreq; /* 0 = 50hz, 1 = 60hz */
+ u8 first_frame;
+ u8 freq;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcomptarget(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 100,
+ .step = 1,
+#define BRIGHTNESS_DEF 50
+ .default_value = BRIGHTNESS_DEF,
+ .flags = 0,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 96,
+ .step = 8,
+#define CONTRAST_DEF 48
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 100,
+ .step = 1,
+#define SATURATION_DEF 50
+ .default_value = SATURATION_DEF,
+ },
+ .set = sd_setsaturation,
+ .get = sd_getsaturation,
+ },
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light frequency filter",
+ .minimum = 0,
+ .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
+ .step = 1,
+#define FREQ_DEF 1
+ .default_value = FREQ_DEF,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq,
+ },
+ {
+ {
+#define V4L2_CID_COMP_TARGET V4L2_CID_PRIVATE_BASE
+ .id = V4L2_CID_COMP_TARGET,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Compression Target",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define COMP_TARGET_DEF CPIA_COMPRESSION_TARGET_QUALITY
+ .default_value = COMP_TARGET_DEF,
+ },
+ .set = sd_setcomptarget,
+ .get = sd_getcomptarget,
+ },
+};
+
+static const struct v4l2_pix_format mode[] = {
+ {160, 120, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
+ /* The sizeimage is trial and error, as with low framerates
+ the camera will pad out usb frames, making the image
+ data larger then strictly necessary */
+ .bytesperline = 160,
+ .sizeimage = 65536,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 3},
+ {176, 144, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
+ .bytesperline = 172,
+ .sizeimage = 65536,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 262144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 262144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+/**********************************************************************
+ *
+ * General functions
+ *
+ **********************************************************************/
+
+static int cpia_usb_transferCmd(struct gspca_dev *gspca_dev, u8 *command)
+{
+ u8 requesttype;
+ unsigned int pipe;
+ int ret, databytes = command[6] | (command[7] << 8);
+ /* Sometimes we see spurious EPIPE errors */
+ int retries = 3;
+
+ if (command[0] == DATA_IN) {
+ pipe = usb_rcvctrlpipe(gspca_dev->dev, 0);
+ requesttype = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ } else if (command[0] == DATA_OUT) {
+ pipe = usb_sndctrlpipe(gspca_dev->dev, 0);
+ requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ } else {
+ PDEBUG(D_ERR, "Unexpected first byte of command: %x",
+ command[0]);
+ return -EINVAL;
+ }
+
+retry:
+ ret = usb_control_msg(gspca_dev->dev, pipe,
+ command[1],
+ requesttype,
+ command[2] | (command[3] << 8),
+ command[4] | (command[5] << 8),
+ gspca_dev->usb_buf, databytes, 1000);
+
+ if (ret < 0)
+ PDEBUG(D_ERR, "usb_control_msg %02x, error %d", command[1],
+ ret);
+
+ if (ret == -EPIPE && retries > 0) {
+ retries--;
+ goto retry;
+ }
+
+ return (ret < 0) ? ret : 0;
+}
+
+/* send an arbitrary command to the camera */
+static int do_command(struct gspca_dev *gspca_dev, u16 command,
+ u8 a, u8 b, u8 c, u8 d)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret, datasize;
+ u8 cmd[8];
+
+ switch (command) {
+ case CPIA_COMMAND_GetCPIAVersion:
+ case CPIA_COMMAND_GetPnPID:
+ case CPIA_COMMAND_GetCameraStatus:
+ case CPIA_COMMAND_GetVPVersion:
+ case CPIA_COMMAND_GetColourParams:
+ case CPIA_COMMAND_GetColourBalance:
+ case CPIA_COMMAND_GetExposure:
+ datasize = 8;
+ break;
+ case CPIA_COMMAND_ReadMCPorts:
+ case CPIA_COMMAND_ReadVCRegs:
+ datasize = 4;
+ break;
+ default:
+ datasize = 0;
+ break;
+ }
+
+ cmd[0] = command >> 8;
+ cmd[1] = command & 0xff;
+ cmd[2] = a;
+ cmd[3] = b;
+ cmd[4] = c;
+ cmd[5] = d;
+ cmd[6] = datasize;
+ cmd[7] = 0;
+
+ ret = cpia_usb_transferCmd(gspca_dev, cmd);
+ if (ret)
+ return ret;
+
+ switch (command) {
+ case CPIA_COMMAND_GetCPIAVersion:
+ sd->params.version.firmwareVersion = gspca_dev->usb_buf[0];
+ sd->params.version.firmwareRevision = gspca_dev->usb_buf[1];
+ sd->params.version.vcVersion = gspca_dev->usb_buf[2];
+ sd->params.version.vcRevision = gspca_dev->usb_buf[3];
+ break;
+ case CPIA_COMMAND_GetPnPID:
+ sd->params.pnpID.vendor =
+ gspca_dev->usb_buf[0] | (gspca_dev->usb_buf[1] << 8);
+ sd->params.pnpID.product =
+ gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8);
+ sd->params.pnpID.deviceRevision =
+ gspca_dev->usb_buf[4] | (gspca_dev->usb_buf[5] << 8);
+ break;
+ case CPIA_COMMAND_GetCameraStatus:
+ sd->params.status.systemState = gspca_dev->usb_buf[0];
+ sd->params.status.grabState = gspca_dev->usb_buf[1];
+ sd->params.status.streamState = gspca_dev->usb_buf[2];
+ sd->params.status.fatalError = gspca_dev->usb_buf[3];
+ sd->params.status.cmdError = gspca_dev->usb_buf[4];
+ sd->params.status.debugFlags = gspca_dev->usb_buf[5];
+ sd->params.status.vpStatus = gspca_dev->usb_buf[6];
+ sd->params.status.errorCode = gspca_dev->usb_buf[7];
+ break;
+ case CPIA_COMMAND_GetVPVersion:
+ sd->params.vpVersion.vpVersion = gspca_dev->usb_buf[0];
+ sd->params.vpVersion.vpRevision = gspca_dev->usb_buf[1];
+ sd->params.vpVersion.cameraHeadID =
+ gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8);
+ break;
+ case CPIA_COMMAND_GetColourParams:
+ sd->params.colourParams.brightness = gspca_dev->usb_buf[0];
+ sd->params.colourParams.contrast = gspca_dev->usb_buf[1];
+ sd->params.colourParams.saturation = gspca_dev->usb_buf[2];
+ break;
+ case CPIA_COMMAND_GetColourBalance:
+ sd->params.colourBalance.redGain = gspca_dev->usb_buf[0];
+ sd->params.colourBalance.greenGain = gspca_dev->usb_buf[1];
+ sd->params.colourBalance.blueGain = gspca_dev->usb_buf[2];
+ break;
+ case CPIA_COMMAND_GetExposure:
+ sd->params.exposure.gain = gspca_dev->usb_buf[0];
+ sd->params.exposure.fineExp = gspca_dev->usb_buf[1];
+ sd->params.exposure.coarseExpLo = gspca_dev->usb_buf[2];
+ sd->params.exposure.coarseExpHi = gspca_dev->usb_buf[3];
+ sd->params.exposure.redComp = gspca_dev->usb_buf[4];
+ sd->params.exposure.green1Comp = gspca_dev->usb_buf[5];
+ sd->params.exposure.green2Comp = gspca_dev->usb_buf[6];
+ sd->params.exposure.blueComp = gspca_dev->usb_buf[7];
+ break;
+
+ case CPIA_COMMAND_ReadMCPorts:
+ if (!sd->params.qx3.qx3_detected)
+ break;
+ /* test button press */
+ sd->params.qx3.button = ((gspca_dev->usb_buf[1] & 0x02) == 0);
+ if (sd->params.qx3.button) {
+ /* button pressed - unlock the latch */
+ do_command(gspca_dev, CPIA_COMMAND_WriteMCPort,
+ 3, 0xDF, 0xDF, 0);
+ do_command(gspca_dev, CPIA_COMMAND_WriteMCPort,
+ 3, 0xFF, 0xFF, 0);
+ }
+
+ /* test whether microscope is cradled */
+ sd->params.qx3.cradled = ((gspca_dev->usb_buf[2] & 0x40) == 0);
+ break;
+ }
+
+ return 0;
+}
+
+/* send a command to the camera with an additional data transaction */
+static int do_command_extended(struct gspca_dev *gspca_dev, u16 command,
+ u8 a, u8 b, u8 c, u8 d,
+ u8 e, u8 f, u8 g, u8 h,
+ u8 i, u8 j, u8 k, u8 l)
+{
+ u8 cmd[8];
+
+ cmd[0] = command >> 8;
+ cmd[1] = command & 0xff;
+ cmd[2] = a;
+ cmd[3] = b;
+ cmd[4] = c;
+ cmd[5] = d;
+ cmd[6] = 8;
+ cmd[7] = 0;
+ gspca_dev->usb_buf[0] = e;
+ gspca_dev->usb_buf[1] = f;
+ gspca_dev->usb_buf[2] = g;
+ gspca_dev->usb_buf[3] = h;
+ gspca_dev->usb_buf[4] = i;
+ gspca_dev->usb_buf[5] = j;
+ gspca_dev->usb_buf[6] = k;
+ gspca_dev->usb_buf[7] = l;
+
+ return cpia_usb_transferCmd(gspca_dev, cmd);
+}
+
+/* find_over_exposure
+ * Finds a suitable value of OverExposure for use with SetFlickerCtrl
+ * Some calculation is required because this value changes with the brightness
+ * set with SetColourParameters
+ *
+ * Parameters: Brightness - last brightness value set with SetColourParameters
+ *
+ * Returns: OverExposure value to use with SetFlickerCtrl
+ */
+#define FLICKER_MAX_EXPOSURE 250
+#define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
+#define FLICKER_BRIGHTNESS_CONSTANT 59
+static int find_over_exposure(int brightness)
+{
+ int MaxAllowableOverExposure, OverExposure;
+
+ MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
+ FLICKER_BRIGHTNESS_CONSTANT;
+
+ if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE)
+ OverExposure = MaxAllowableOverExposure;
+ else
+ OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
+
+ return OverExposure;
+}
+#undef FLICKER_MAX_EXPOSURE
+#undef FLICKER_ALLOWABLE_OVER_EXPOSURE
+#undef FLICKER_BRIGHTNESS_CONSTANT
+
+/* initialise cam_data structure */
+static void reset_camera_params(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam_params *params = &sd->params;
+
+ /* The following parameter values are the defaults from
+ * "Software Developer's Guide for CPiA Cameras". Any changes
+ * to the defaults are noted in comments. */
+ params->colourParams.brightness = BRIGHTNESS_DEF;
+ params->colourParams.contrast = CONTRAST_DEF;
+ params->colourParams.saturation = SATURATION_DEF;
+ params->exposure.gainMode = 4;
+ params->exposure.expMode = 2; /* AEC */
+ params->exposure.compMode = 1;
+ params->exposure.centreWeight = 1;
+ params->exposure.gain = 0;
+ params->exposure.fineExp = 0;
+ params->exposure.coarseExpLo = 185;
+ params->exposure.coarseExpHi = 0;
+ params->exposure.redComp = COMP_RED;
+ params->exposure.green1Comp = COMP_GREEN1;
+ params->exposure.green2Comp = COMP_GREEN2;
+ params->exposure.blueComp = COMP_BLUE;
+ params->colourBalance.balanceMode = 2; /* ACB */
+ params->colourBalance.redGain = 32;
+ params->colourBalance.greenGain = 6;
+ params->colourBalance.blueGain = 92;
+ params->apcor.gain1 = 0x18;
+ params->apcor.gain2 = 0x16;
+ params->apcor.gain4 = 0x24;
+ params->apcor.gain8 = 0x34;
+ params->flickerControl.flickerMode = 0;
+ params->flickerControl.disabled = 1;
+
+ params->flickerControl.coarseJump =
+ flicker_jumps[sd->mainsFreq]
+ [params->sensorFps.baserate]
+ [params->sensorFps.divisor];
+ params->flickerControl.allowableOverExposure =
+ find_over_exposure(params->colourParams.brightness);
+ params->vlOffset.gain1 = 20;
+ params->vlOffset.gain2 = 24;
+ params->vlOffset.gain4 = 26;
+ params->vlOffset.gain8 = 26;
+ params->compressionParams.hysteresis = 3;
+ params->compressionParams.threshMax = 11;
+ params->compressionParams.smallStep = 1;
+ params->compressionParams.largeStep = 3;
+ params->compressionParams.decimationHysteresis = 2;
+ params->compressionParams.frDiffStepThresh = 5;
+ params->compressionParams.qDiffStepThresh = 3;
+ params->compressionParams.decimationThreshMod = 2;
+ /* End of default values from Software Developer's Guide */
+
+ /* Set Sensor FPS to 15fps. This seems better than 30fps
+ * for indoor lighting. */
+ params->sensorFps.divisor = 1;
+ params->sensorFps.baserate = 1;
+
+ params->yuvThreshold.yThreshold = 6; /* From windows driver */
+ params->yuvThreshold.uvThreshold = 6; /* From windows driver */
+
+ params->format.subSample = SUBSAMPLE_420;
+ params->format.yuvOrder = YUVORDER_YUYV;
+
+ params->compression.mode = CPIA_COMPRESSION_AUTO;
+ params->compression.decimation = NO_DECIMATION;
+
+ params->compressionTarget.frTargeting = COMP_TARGET_DEF;
+ params->compressionTarget.targetFR = 15; /* From windows driver */
+ params->compressionTarget.targetQ = 5; /* From windows driver */
+
+ params->qx3.qx3_detected = 0;
+ params->qx3.toplight = 0;
+ params->qx3.bottomlight = 0;
+ params->qx3.button = 0;
+ params->qx3.cradled = 0;
+}
+
+static void printstatus(struct cam_params *params)
+{
+ PDEBUG(D_PROBE, "status: %02x %02x %02x %02x %02x %02x %02x %02x",
+ params->status.systemState, params->status.grabState,
+ params->status.streamState, params->status.fatalError,
+ params->status.cmdError, params->status.debugFlags,
+ params->status.vpStatus, params->status.errorCode);
+}
+
+static int goto_low_power(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ ret = do_command(gspca_dev, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0);
+ if (ret)
+ return ret;
+
+ do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+ if (ret)
+ return ret;
+
+ if (sd->params.status.systemState != LO_POWER_STATE) {
+ if (sd->params.status.systemState != WARM_BOOT_STATE) {
+ PDEBUG(D_ERR,
+ "unexpected state after lo power cmd: %02x",
+ sd->params.status.systemState);
+ printstatus(&sd->params);
+ }
+ return -EIO;
+ }
+
+ PDEBUG(D_CONF, "camera now in LOW power state");
+ return 0;
+}
+
+static int goto_high_power(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ ret = do_command(gspca_dev, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0);
+ if (ret)
+ return ret;
+
+ msleep_interruptible(40); /* windows driver does it too */
+
+ if (signal_pending(current))
+ return -EINTR;
+
+ do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+ if (ret)
+ return ret;
+
+ if (sd->params.status.systemState != HI_POWER_STATE) {
+ PDEBUG(D_ERR, "unexpected state after hi power cmd: %02x",
+ sd->params.status.systemState);
+ printstatus(&sd->params);
+ return -EIO;
+ }
+
+ PDEBUG(D_CONF, "camera now in HIGH power state");
+ return 0;
+}
+
+static int get_version_information(struct gspca_dev *gspca_dev)
+{
+ int ret;
+
+ /* GetCPIAVersion */
+ ret = do_command(gspca_dev, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
+ if (ret)
+ return ret;
+
+ /* GetPnPID */
+ return do_command(gspca_dev, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
+}
+
+static int save_camera_state(struct gspca_dev *gspca_dev)
+{
+ int ret;
+
+ ret = do_command(gspca_dev, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
+ if (ret)
+ return ret;
+
+ return do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+}
+
+int command_setformat(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ ret = do_command(gspca_dev, CPIA_COMMAND_SetFormat,
+ sd->params.format.videoSize,
+ sd->params.format.subSample,
+ sd->params.format.yuvOrder, 0);
+ if (ret)
+ return ret;
+
+ return do_command(gspca_dev, CPIA_COMMAND_SetROI,
+ sd->params.roi.colStart, sd->params.roi.colEnd,
+ sd->params.roi.rowStart, sd->params.roi.rowEnd);
+}
+
+int command_setcolourparams(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ return do_command(gspca_dev, CPIA_COMMAND_SetColourParams,
+ sd->params.colourParams.brightness,
+ sd->params.colourParams.contrast,
+ sd->params.colourParams.saturation, 0);
+}
+
+int command_setapcor(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ return do_command(gspca_dev, CPIA_COMMAND_SetApcor,
+ sd->params.apcor.gain1,
+ sd->params.apcor.gain2,
+ sd->params.apcor.gain4,
+ sd->params.apcor.gain8);
+}
+
+int command_setvloffset(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ return do_command(gspca_dev, CPIA_COMMAND_SetVLOffset,
+ sd->params.vlOffset.gain1,
+ sd->params.vlOffset.gain2,
+ sd->params.vlOffset.gain4,
+ sd->params.vlOffset.gain8);
+}
+
+int command_setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure,
+ sd->params.exposure.gainMode,
+ 1,
+ sd->params.exposure.compMode,
+ sd->params.exposure.centreWeight,
+ sd->params.exposure.gain,
+ sd->params.exposure.fineExp,
+ sd->params.exposure.coarseExpLo,
+ sd->params.exposure.coarseExpHi,
+ sd->params.exposure.redComp,
+ sd->params.exposure.green1Comp,
+ sd->params.exposure.green2Comp,
+ sd->params.exposure.blueComp);
+ if (ret)
+ return ret;
+
+ if (sd->params.exposure.expMode != 1) {
+ ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure,
+ 0,
+ sd->params.exposure.expMode,
+ 0, 0,
+ sd->params.exposure.gain,
+ sd->params.exposure.fineExp,
+ sd->params.exposure.coarseExpLo,
+ sd->params.exposure.coarseExpHi,
+ 0, 0, 0, 0);
+ }
+
+ return ret;
+}
+
+int command_setcolourbalance(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->params.colourBalance.balanceMode == 1) {
+ int ret;
+
+ ret = do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,
+ 1,
+ sd->params.colourBalance.redGain,
+ sd->params.colourBalance.greenGain,
+ sd->params.colourBalance.blueGain);
+ if (ret)
+ return ret;
+
+ return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,
+ 3, 0, 0, 0);
+ }
+ if (sd->params.colourBalance.balanceMode == 2) {
+ return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,
+ 2, 0, 0, 0);
+ }
+ if (sd->params.colourBalance.balanceMode == 3) {
+ return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,
+ 3, 0, 0, 0);
+ }
+
+ return -EINVAL;
+}
+
+int command_setcompressiontarget(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ return do_command(gspca_dev, CPIA_COMMAND_SetCompressionTarget,
+ sd->params.compressionTarget.frTargeting,
+ sd->params.compressionTarget.targetFR,
+ sd->params.compressionTarget.targetQ, 0);
+}
+
+int command_setyuvtresh(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ return do_command(gspca_dev, CPIA_COMMAND_SetYUVThresh,
+ sd->params.yuvThreshold.yThreshold,
+ sd->params.yuvThreshold.uvThreshold, 0, 0);
+}
+
+int command_setcompressionparams(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ return do_command_extended(gspca_dev,
+ CPIA_COMMAND_SetCompressionParams,
+ 0, 0, 0, 0,
+ sd->params.compressionParams.hysteresis,
+ sd->params.compressionParams.threshMax,
+ sd->params.compressionParams.smallStep,
+ sd->params.compressionParams.largeStep,
+ sd->params.compressionParams.decimationHysteresis,
+ sd->params.compressionParams.frDiffStepThresh,
+ sd->params.compressionParams.qDiffStepThresh,
+ sd->params.compressionParams.decimationThreshMod);
+}
+
+int command_setcompression(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ return do_command(gspca_dev, CPIA_COMMAND_SetCompression,
+ sd->params.compression.mode,
+ sd->params.compression.decimation, 0, 0);
+}
+
+int command_setsensorfps(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ return do_command(gspca_dev, CPIA_COMMAND_SetSensorFPS,
+ sd->params.sensorFps.divisor,
+ sd->params.sensorFps.baserate, 0, 0);
+}
+
+int command_setflickerctrl(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ return do_command(gspca_dev, CPIA_COMMAND_SetFlickerCtrl,
+ sd->params.flickerControl.flickerMode,
+ sd->params.flickerControl.coarseJump,
+ sd->params.flickerControl.allowableOverExposure,
+ 0);
+}
+
+int command_setecptiming(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ return do_command(gspca_dev, CPIA_COMMAND_SetECPTiming,
+ sd->params.ecpTiming, 0, 0, 0);
+}
+
+int command_pause(struct gspca_dev *gspca_dev)
+{
+ return do_command(gspca_dev, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
+}
+
+int command_resume(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ return do_command(gspca_dev, CPIA_COMMAND_InitStreamCap,
+ 0, sd->params.streamStartLine, 0, 0);
+}
+
+int command_setlights(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret, p1, p2;
+
+ if (!sd->params.qx3.qx3_detected)
+ return 0;
+
+ p1 = (sd->params.qx3.bottomlight == 0) << 1;
+ p2 = (sd->params.qx3.toplight == 0) << 3;
+
+ ret = do_command(gspca_dev, CPIA_COMMAND_WriteVCReg,
+ 0x90, 0x8F, 0x50, 0);
+ if (ret)
+ return ret;
+
+ return do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 2, 0,
+ p1 | p2 | 0xE0, 0);
+}
+
+static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply)
+{
+ /* Everything in here is from the Windows driver */
+/* define for compgain calculation */
+#if 0
+#define COMPGAIN(base, curexp, newexp) \
+ (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
+#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
+ (u16)((float)curexp * (float)(u8)(curcomp + 128) / \
+ (float)(u8)(basecomp - 128))
+#else
+ /* equivalent functions without floating point math */
+#define COMPGAIN(base, curexp, newexp) \
+ (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2 * newexp)))
+#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
+ (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
+#endif
+
+ struct sd *sd = (struct sd *) gspca_dev;
+ int currentexp = sd->params.exposure.coarseExpLo +
+ sd->params.exposure.coarseExpHi * 256;
+ int ret, startexp;
+
+ if (on) {
+ int cj = sd->params.flickerControl.coarseJump;
+ sd->params.flickerControl.flickerMode = 1;
+ sd->params.flickerControl.disabled = 0;
+ if (sd->params.exposure.expMode != 2) {
+ sd->params.exposure.expMode = 2;
+ sd->exposure_status = EXPOSURE_NORMAL;
+ }
+ currentexp = currentexp << sd->params.exposure.gain;
+ sd->params.exposure.gain = 0;
+ /* round down current exposure to nearest value */
+ startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
+ if (startexp < 1)
+ startexp = 1;
+ startexp = (startexp * cj) - 1;
+ if (FIRMWARE_VERSION(1, 2))
+ while (startexp > MAX_EXP_102)
+ startexp -= cj;
+ else
+ while (startexp > MAX_EXP)
+ startexp -= cj;
+ sd->params.exposure.coarseExpLo = startexp & 0xff;
+ sd->params.exposure.coarseExpHi = startexp >> 8;
+ if (currentexp > startexp) {
+ if (currentexp > (2 * startexp))
+ currentexp = 2 * startexp;
+ sd->params.exposure.redComp =
+ COMPGAIN(COMP_RED, currentexp, startexp);
+ sd->params.exposure.green1Comp =
+ COMPGAIN(COMP_GREEN1, currentexp, startexp);
+ sd->params.exposure.green2Comp =
+ COMPGAIN(COMP_GREEN2, currentexp, startexp);
+ sd->params.exposure.blueComp =
+ COMPGAIN(COMP_BLUE, currentexp, startexp);
+ } else {
+ sd->params.exposure.redComp = COMP_RED;
+ sd->params.exposure.green1Comp = COMP_GREEN1;
+ sd->params.exposure.green2Comp = COMP_GREEN2;
+ sd->params.exposure.blueComp = COMP_BLUE;
+ }
+ if (FIRMWARE_VERSION(1, 2))
+ sd->params.exposure.compMode = 0;
+ else
+ sd->params.exposure.compMode = 1;
+
+ sd->params.apcor.gain1 = 0x18;
+ sd->params.apcor.gain2 = 0x18;
+ sd->params.apcor.gain4 = 0x16;
+ sd->params.apcor.gain8 = 0x14;
+ } else {
+ sd->params.flickerControl.flickerMode = 0;
+ sd->params.flickerControl.disabled = 1;
+ /* Average equivalent coarse for each comp channel */
+ startexp = EXP_FROM_COMP(COMP_RED,
+ sd->params.exposure.redComp, currentexp);
+ startexp += EXP_FROM_COMP(COMP_GREEN1,
+ sd->params.exposure.green1Comp, currentexp);
+ startexp += EXP_FROM_COMP(COMP_GREEN2,
+ sd->params.exposure.green2Comp, currentexp);
+ startexp += EXP_FROM_COMP(COMP_BLUE,
+ sd->params.exposure.blueComp, currentexp);
+ startexp = startexp >> 2;
+ while (startexp > MAX_EXP && sd->params.exposure.gain <
+ sd->params.exposure.gainMode - 1) {
+ startexp = startexp >> 1;
+ ++sd->params.exposure.gain;
+ }
+ if (FIRMWARE_VERSION(1, 2) && startexp > MAX_EXP_102)
+ startexp = MAX_EXP_102;
+ if (startexp > MAX_EXP)
+ startexp = MAX_EXP;
+ sd->params.exposure.coarseExpLo = startexp & 0xff;
+ sd->params.exposure.coarseExpHi = startexp >> 8;
+ sd->params.exposure.redComp = COMP_RED;
+ sd->params.exposure.green1Comp = COMP_GREEN1;
+ sd->params.exposure.green2Comp = COMP_GREEN2;
+ sd->params.exposure.blueComp = COMP_BLUE;
+ sd->params.exposure.compMode = 1;
+ sd->params.apcor.gain1 = 0x18;
+ sd->params.apcor.gain2 = 0x16;
+ sd->params.apcor.gain4 = 0x24;
+ sd->params.apcor.gain8 = 0x34;
+ }
+ sd->params.vlOffset.gain1 = 20;
+ sd->params.vlOffset.gain2 = 24;
+ sd->params.vlOffset.gain4 = 26;
+ sd->params.vlOffset.gain8 = 26;
+
+ if (apply) {
+ ret = command_setexposure(gspca_dev);
+ if (ret)
+ return ret;
+
+ ret = command_setapcor(gspca_dev);
+ if (ret)
+ return ret;
+
+ ret = command_setvloffset(gspca_dev);
+ if (ret)
+ return ret;
+
+ ret = command_setflickerctrl(gspca_dev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+#undef EXP_FROM_COMP
+#undef COMPGAIN
+}
+
+/* monitor the exposure and adjust the sensor frame rate if needed */
+static void monitor_exposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 exp_acc, bcomp, gain, coarseL, cmd[8];
+ int ret, light_exp, dark_exp, very_dark_exp;
+ int old_exposure, new_exposure, framerate;
+ int setfps = 0, setexp = 0, setflicker = 0;
+
+ /* get necessary stats and register settings from camera */
+ /* do_command can't handle this, so do it ourselves */
+ cmd[0] = CPIA_COMMAND_ReadVPRegs >> 8;
+ cmd[1] = CPIA_COMMAND_ReadVPRegs & 0xff;
+ cmd[2] = 30;
+ cmd[3] = 4;
+ cmd[4] = 9;
+ cmd[5] = 8;
+ cmd[6] = 8;
+ cmd[7] = 0;
+ ret = cpia_usb_transferCmd(gspca_dev, cmd);
+ if (ret) {
+ PDEBUG(D_ERR, "ReadVPRegs(30,4,9,8) - failed: %d", ret);
+ return;
+ }
+ exp_acc = gspca_dev->usb_buf[0];
+ bcomp = gspca_dev->usb_buf[1];
+ gain = gspca_dev->usb_buf[2];
+ coarseL = gspca_dev->usb_buf[3];
+
+ light_exp = sd->params.colourParams.brightness +
+ TC - 50 + EXP_ACC_LIGHT;
+ if (light_exp > 255)
+ light_exp = 255;
+ dark_exp = sd->params.colourParams.brightness +
+ TC - 50 - EXP_ACC_DARK;
+ if (dark_exp < 0)
+ dark_exp = 0;
+ very_dark_exp = dark_exp / 2;
+
+ old_exposure = sd->params.exposure.coarseExpHi * 256 +
+ sd->params.exposure.coarseExpLo;
+
+ if (!sd->params.flickerControl.disabled) {
+ /* Flicker control on */
+ int max_comp = FIRMWARE_VERSION(1, 2) ? MAX_COMP :
+ HIGH_COMP_102;
+ bcomp += 128; /* decode */
+ if (bcomp >= max_comp && exp_acc < dark_exp) {
+ /* dark */
+ if (exp_acc < very_dark_exp) {
+ /* very dark */
+ if (sd->exposure_status == EXPOSURE_VERY_DARK)
+ ++sd->exposure_count;
+ else {
+ sd->exposure_status =
+ EXPOSURE_VERY_DARK;
+ sd->exposure_count = 1;
+ }
+ } else {
+ /* just dark */
+ if (sd->exposure_status == EXPOSURE_DARK)
+ ++sd->exposure_count;
+ else {
+ sd->exposure_status = EXPOSURE_DARK;
+ sd->exposure_count = 1;
+ }
+ }
+ } else if (old_exposure <= LOW_EXP || exp_acc > light_exp) {
+ /* light */
+ if (old_exposure <= VERY_LOW_EXP) {
+ /* very light */
+ if (sd->exposure_status == EXPOSURE_VERY_LIGHT)
+ ++sd->exposure_count;
+ else {
+ sd->exposure_status =
+ EXPOSURE_VERY_LIGHT;
+ sd->exposure_count = 1;
+ }
+ } else {
+ /* just light */
+ if (sd->exposure_status == EXPOSURE_LIGHT)
+ ++sd->exposure_count;
+ else {
+ sd->exposure_status = EXPOSURE_LIGHT;
+ sd->exposure_count = 1;
+ }
+ }
+ } else {
+ /* not dark or light */
+ sd->exposure_status = EXPOSURE_NORMAL;
+ }
+ } else {
+ /* Flicker control off */
+ if (old_exposure >= MAX_EXP && exp_acc < dark_exp) {
+ /* dark */
+ if (exp_acc < very_dark_exp) {
+ /* very dark */
+ if (sd->exposure_status == EXPOSURE_VERY_DARK)
+ ++sd->exposure_count;
+ else {
+ sd->exposure_status =
+ EXPOSURE_VERY_DARK;
+ sd->exposure_count = 1;
+ }
+ } else {
+ /* just dark */
+ if (sd->exposure_status == EXPOSURE_DARK)
+ ++sd->exposure_count;
+ else {
+ sd->exposure_status = EXPOSURE_DARK;
+ sd->exposure_count = 1;
+ }
+ }
+ } else if (old_exposure <= LOW_EXP || exp_acc > light_exp) {
+ /* light */
+ if (old_exposure <= VERY_LOW_EXP) {
+ /* very light */
+ if (sd->exposure_status == EXPOSURE_VERY_LIGHT)
+ ++sd->exposure_count;
+ else {
+ sd->exposure_status =
+ EXPOSURE_VERY_LIGHT;
+ sd->exposure_count = 1;
+ }
+ } else {
+ /* just light */
+ if (sd->exposure_status == EXPOSURE_LIGHT)
+ ++sd->exposure_count;
+ else {
+ sd->exposure_status = EXPOSURE_LIGHT;
+ sd->exposure_count = 1;
+ }
+ }
+ } else {
+ /* not dark or light */
+ sd->exposure_status = EXPOSURE_NORMAL;
+ }
+ }
+
+ framerate = atomic_read(&sd->fps);
+ if (framerate > 30 || framerate < 1)
+ framerate = 1;
+
+ if (!sd->params.flickerControl.disabled) {
+ /* Flicker control on */
+ if ((sd->exposure_status == EXPOSURE_VERY_DARK ||
+ sd->exposure_status == EXPOSURE_DARK) &&
+ sd->exposure_count >= DARK_TIME * framerate &&
+ sd->params.sensorFps.divisor < 3) {
+
+ /* dark for too long */
+ ++sd->params.sensorFps.divisor;
+ setfps = 1;
+
+ sd->params.flickerControl.coarseJump =
+ flicker_jumps[sd->mainsFreq]
+ [sd->params.sensorFps.baserate]
+ [sd->params.sensorFps.divisor];
+ setflicker = 1;
+
+ new_exposure = sd->params.flickerControl.coarseJump-1;
+ while (new_exposure < old_exposure / 2)
+ new_exposure +=
+ sd->params.flickerControl.coarseJump;
+ sd->params.exposure.coarseExpLo = new_exposure & 0xff;
+ sd->params.exposure.coarseExpHi = new_exposure >> 8;
+ setexp = 1;
+ sd->exposure_status = EXPOSURE_NORMAL;
+ PDEBUG(D_CONF, "Automatically decreasing sensor_fps");
+
+ } else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT ||
+ sd->exposure_status == EXPOSURE_LIGHT) &&
+ sd->exposure_count >= LIGHT_TIME * framerate &&
+ sd->params.sensorFps.divisor > 0) {
+
+ /* light for too long */
+ int max_exp = FIRMWARE_VERSION(1, 2) ? MAX_EXP_102 :
+ MAX_EXP;
+ --sd->params.sensorFps.divisor;
+ setfps = 1;
+
+ sd->params.flickerControl.coarseJump =
+ flicker_jumps[sd->mainsFreq]
+ [sd->params.sensorFps.baserate]
+ [sd->params.sensorFps.divisor];
+ setflicker = 1;
+
+ new_exposure = sd->params.flickerControl.coarseJump-1;
+ while (new_exposure < 2 * old_exposure &&
+ new_exposure +
+ sd->params.flickerControl.coarseJump < max_exp)
+ new_exposure +=
+ sd->params.flickerControl.coarseJump;
+ sd->params.exposure.coarseExpLo = new_exposure & 0xff;
+ sd->params.exposure.coarseExpHi = new_exposure >> 8;
+ setexp = 1;
+ sd->exposure_status = EXPOSURE_NORMAL;
+ PDEBUG(D_CONF, "Automatically increasing sensor_fps");
+ }
+ } else {
+ /* Flicker control off */
+ if ((sd->exposure_status == EXPOSURE_VERY_DARK ||
+ sd->exposure_status == EXPOSURE_DARK) &&
+ sd->exposure_count >= DARK_TIME * framerate &&
+ sd->params.sensorFps.divisor < 3) {
+
+ /* dark for too long */
+ ++sd->params.sensorFps.divisor;
+ setfps = 1;
+
+ if (sd->params.exposure.gain > 0) {
+ --sd->params.exposure.gain;
+ setexp = 1;
+ }
+ sd->exposure_status = EXPOSURE_NORMAL;
+ PDEBUG(D_CONF, "Automatically decreasing sensor_fps");
+
+ } else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT ||
+ sd->exposure_status == EXPOSURE_LIGHT) &&
+ sd->exposure_count >= LIGHT_TIME * framerate &&
+ sd->params.sensorFps.divisor > 0) {
+
+ /* light for too long */
+ --sd->params.sensorFps.divisor;
+ setfps = 1;
+
+ if (sd->params.exposure.gain <
+ sd->params.exposure.gainMode - 1) {
+ ++sd->params.exposure.gain;
+ setexp = 1;
+ }
+ sd->exposure_status = EXPOSURE_NORMAL;
+ PDEBUG(D_CONF, "Automatically increasing sensor_fps");
+ }
+ }
+
+ if (setexp)
+ command_setexposure(gspca_dev);
+
+ if (setfps)
+ command_setsensorfps(gspca_dev);
+
+ if (setflicker)
+ command_setflickerctrl(gspca_dev);
+}
+
+/*-----------------------------------------------------------------*/
+/* if flicker is switched off, this function switches it back on.It checks,
+ however, that conditions are suitable before restarting it.
+ This should only be called for firmware version 1.2.
+
+ It also adjust the colour balance when an exposure step is detected - as
+ long as flicker is running
+*/
+static void restart_flicker(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int cam_exposure, old_exp;
+
+ if (!FIRMWARE_VERSION(1, 2))
+ return;
+
+ cam_exposure = atomic_read(&sd->cam_exposure);
+
+ if (sd->params.flickerControl.flickerMode == 0 ||
+ cam_exposure == 0)
+ return;
+
+ old_exp = sd->params.exposure.coarseExpLo +
+ sd->params.exposure.coarseExpHi*256;
+ /*
+ see how far away camera exposure is from a valid
+ flicker exposure value
+ */
+ cam_exposure %= sd->params.flickerControl.coarseJump;
+ if (!sd->params.flickerControl.disabled &&
+ cam_exposure <= sd->params.flickerControl.coarseJump - 3) {
+ /* Flicker control auto-disabled */
+ sd->params.flickerControl.disabled = 1;
+ }
+
+ if (sd->params.flickerControl.disabled &&
+ old_exp > sd->params.flickerControl.coarseJump +
+ ROUND_UP_EXP_FOR_FLICKER) {
+ /* exposure is now high enough to switch
+ flicker control back on */
+ set_flicker(gspca_dev, 1, 1);
+ }
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct cam *cam;
+
+ reset_camera_params(gspca_dev);
+
+ PDEBUG(D_PROBE, "cpia CPiA camera detected (vid/pid 0x%04X:0x%04X)",
+ id->idVendor, id->idProduct);
+
+ cam = &gspca_dev->cam;
+ cam->cam_mode = mode;
+ cam->nmodes = ARRAY_SIZE(mode);
+
+ sd_setfreq(gspca_dev, FREQ_DEF);
+
+ return 0;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int priv, ret;
+
+ /* Start the camera in low power mode */
+ if (goto_low_power(gspca_dev)) {
+ if (sd->params.status.systemState != WARM_BOOT_STATE) {
+ PDEBUG(D_ERR, "unexpected systemstate: %02x",
+ sd->params.status.systemState);
+ printstatus(&sd->params);
+ return -ENODEV;
+ }
+
+ /* FIXME: this is just dirty trial and error */
+ ret = goto_high_power(gspca_dev);
+ if (ret)
+ return ret;
+
+ ret = do_command(gspca_dev, CPIA_COMMAND_DiscardFrame,
+ 0, 0, 0, 0);
+ if (ret)
+ return ret;
+
+ ret = goto_low_power(gspca_dev);
+ if (ret)
+ return ret;
+ }
+
+ /* procedure described in developer's guide p3-28 */
+
+ /* Check the firmware version. */
+ sd->params.version.firmwareVersion = 0;
+ get_version_information(gspca_dev);
+ if (sd->params.version.firmwareVersion != 1) {
+ PDEBUG(D_ERR, "only firmware version 1 is supported (got: %d)",
+ sd->params.version.firmwareVersion);
+ return -ENODEV;
+ }
+
+ /* A bug in firmware 1-02 limits gainMode to 2 */
+ if (sd->params.version.firmwareRevision <= 2 &&
+ sd->params.exposure.gainMode > 2) {
+ sd->params.exposure.gainMode = 2;
+ }
+
+ /* set QX3 detected flag */
+ sd->params.qx3.qx3_detected = (sd->params.pnpID.vendor == 0x0813 &&
+ sd->params.pnpID.product == 0x0001);
+
+ /* The fatal error checking should be done after
+ * the camera powers up (developer's guide p 3-38) */
+
+ /* Set streamState before transition to high power to avoid bug
+ * in firmware 1-02 */
+ ret = do_command(gspca_dev, CPIA_COMMAND_ModifyCameraStatus,
+ STREAMSTATE, 0, STREAM_NOT_READY, 0);
+ if (ret)
+ return ret;
+
+ /* GotoHiPower */
+ ret = goto_high_power(gspca_dev);
+ if (ret)
+ return ret;
+
+ /* Check the camera status */
+ ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+ if (ret)
+ return ret;
+
+ if (sd->params.status.fatalError) {
+ PDEBUG(D_ERR, "fatal_error: %04x, vp_status: %04x",
+ sd->params.status.fatalError,
+ sd->params.status.vpStatus);
+ return -EIO;
+ }
+
+ /* VPVersion can't be retrieved before the camera is in HiPower,
+ * so get it here instead of in get_version_information. */
+ ret = do_command(gspca_dev, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
+ if (ret)
+ return ret;
+
+ /* Determine video mode settings */
+ sd->params.streamStartLine = 120;
+
+ priv = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+ if (priv & 0x01) { /* crop */
+ sd->params.roi.colStart = 2;
+ sd->params.roi.rowStart = 6;
+ } else {
+ sd->params.roi.colStart = 0;
+ sd->params.roi.rowStart = 0;
+ }
+
+ if (priv & 0x02) { /* quarter */
+ sd->params.format.videoSize = VIDEOSIZE_QCIF;
+ sd->params.roi.colStart /= 2;
+ sd->params.roi.rowStart /= 2;
+ sd->params.streamStartLine /= 2;
+ } else
+ sd->params.format.videoSize = VIDEOSIZE_CIF;
+
+ sd->params.roi.colEnd = sd->params.roi.colStart +
+ (gspca_dev->width >> 3);
+ sd->params.roi.rowEnd = sd->params.roi.rowStart +
+ (gspca_dev->height >> 2);
+
+ /* And now set the camera to a known state */
+ ret = do_command(gspca_dev, CPIA_COMMAND_SetGrabMode,
+ CPIA_GRAB_CONTINEOUS, 0, 0, 0);
+ if (ret)
+ return ret;
+ /* We start with compression disabled, as we need one uncompressed
+ frame to handle later compressed frames */
+ ret = do_command(gspca_dev, CPIA_COMMAND_SetCompression,
+ CPIA_COMPRESSION_NONE,
+ NO_DECIMATION, 0, 0);
+ if (ret)
+ return ret;
+ ret = command_setcompressiontarget(gspca_dev);
+ if (ret)
+ return ret;
+ ret = command_setcolourparams(gspca_dev);
+ if (ret)
+ return ret;
+ ret = command_setformat(gspca_dev);
+ if (ret)
+ return ret;
+ ret = command_setyuvtresh(gspca_dev);
+ if (ret)
+ return ret;
+ ret = command_setecptiming(gspca_dev);
+ if (ret)
+ return ret;
+ ret = command_setcompressionparams(gspca_dev);
+ if (ret)
+ return ret;
+ ret = command_setexposure(gspca_dev);
+ if (ret)
+ return ret;
+ ret = command_setcolourbalance(gspca_dev);
+ if (ret)
+ return ret;
+ ret = command_setsensorfps(gspca_dev);
+ if (ret)
+ return ret;
+ ret = command_setapcor(gspca_dev);
+ if (ret)
+ return ret;
+ ret = command_setflickerctrl(gspca_dev);
+ if (ret)
+ return ret;
+ ret = command_setvloffset(gspca_dev);
+ if (ret)
+ return ret;
+
+ /* Start stream */
+ ret = command_resume(gspca_dev);
+ if (ret)
+ return ret;
+
+ /* Wait 6 frames before turning compression on for the sensor to get
+ all settings and AEC/ACB to settle */
+ sd->first_frame = 6;
+ sd->exposure_status = EXPOSURE_NORMAL;
+ sd->exposure_count = 0;
+ atomic_set(&sd->cam_exposure, 0);
+ atomic_set(&sd->fps, 0);
+
+ return 0;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ command_pause(gspca_dev);
+
+ /* save camera state for later open (developers guide ch 3.5.3) */
+ save_camera_state(gspca_dev);
+
+ /* GotoLoPower */
+ goto_low_power(gspca_dev);
+
+ /* Update the camera status */
+ do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ /* Start / Stop the camera to make sure we are talking to
+ a supported camera, and to get some information from it
+ to print. */
+ ret = sd_start(gspca_dev);
+ if (ret)
+ return ret;
+
+ sd_stopN(gspca_dev);
+
+ PDEBUG(D_PROBE, "CPIA Version: %d.%02d (%d.%d)",
+ sd->params.version.firmwareVersion,
+ sd->params.version.firmwareRevision,
+ sd->params.version.vcVersion,
+ sd->params.version.vcRevision);
+ PDEBUG(D_PROBE, "CPIA PnP-ID: %04x:%04x:%04x",
+ sd->params.pnpID.vendor, sd->params.pnpID.product,
+ sd->params.pnpID.deviceRevision);
+ PDEBUG(D_PROBE, "VP-Version: %d.%d %04x",
+ sd->params.vpVersion.vpVersion,
+ sd->params.vpVersion.vpRevision,
+ sd->params.vpVersion.cameraHeadID);
+
+ return 0;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data,
+ int len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* Check for SOF */
+ if (len >= 64 &&
+ data[0] == MAGIC_0 && data[1] == MAGIC_1 &&
+ data[16] == sd->params.format.videoSize &&
+ data[17] == sd->params.format.subSample &&
+ data[18] == sd->params.format.yuvOrder &&
+ data[24] == sd->params.roi.colStart &&
+ data[25] == sd->params.roi.colEnd &&
+ data[26] == sd->params.roi.rowStart &&
+ data[27] == sd->params.roi.rowEnd) {
+ struct gspca_frame *frame = gspca_get_i_frame(gspca_dev);
+
+ atomic_set(&sd->cam_exposure, data[39] * 2);
+ atomic_set(&sd->fps, data[41]);
+
+ if (frame == NULL) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ }
+
+ /* Check for proper EOF for last frame */
+ if ((frame->data_end - frame->data) > 4 &&
+ frame->data_end[-4] == 0xff &&
+ frame->data_end[-3] == 0xff &&
+ frame->data_end[-2] == 0xff &&
+ frame->data_end[-1] == 0xff)
+ gspca_frame_add(gspca_dev, LAST_PACKET,
+ NULL, 0);
+
+ gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
+ return;
+ }
+
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+static void sd_dq_callback(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* Set the normal compression settings once we have captured a
+ few uncompressed frames (and AEC has hopefully settled) */
+ if (sd->first_frame) {
+ sd->first_frame--;
+ if (sd->first_frame == 0)
+ command_setcompression(gspca_dev);
+ }
+
+ /* Switch flicker control back on if it got turned off */
+ restart_flicker(gspca_dev);
+
+ /* If AEC is enabled, monitor the exposure and
+ adjust the sensor frame rate if needed */
+ if (sd->params.exposure.expMode == 2)
+ monitor_exposure(gspca_dev);
+
+ /* Update our knowledge of the camera state */
+ do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+ if (sd->params.qx3.qx3_detected)
+ do_command(gspca_dev, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ sd->params.colourParams.brightness = val;
+ sd->params.flickerControl.allowableOverExposure =
+ find_over_exposure(sd->params.colourParams.brightness);
+ if (gspca_dev->streaming) {
+ ret = command_setcolourparams(gspca_dev);
+ if (ret)
+ return ret;
+ return command_setflickerctrl(gspca_dev);
+ }
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->params.colourParams.brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->params.colourParams.contrast = val;
+ if (gspca_dev->streaming)
+ return command_setcolourparams(gspca_dev);
+
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->params.colourParams.contrast;
+ return 0;
+}
+
+static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->params.colourParams.saturation = val;
+ if (gspca_dev->streaming)
+ return command_setcolourparams(gspca_dev);
+
+ return 0;
+}
+
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->params.colourParams.saturation;
+ return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int on;
+
+ switch (val) {
+ case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+ on = 0;
+ break;
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ on = 1;
+ sd->mainsFreq = 0;
+ break;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ on = 1;
+ sd->mainsFreq = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ sd->freq = val;
+ sd->params.flickerControl.coarseJump =
+ flicker_jumps[sd->mainsFreq]
+ [sd->params.sensorFps.baserate]
+ [sd->params.sensorFps.divisor];
+
+ return set_flicker(gspca_dev, on, gspca_dev->streaming);
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->freq;
+ return 0;
+}
+
+static int sd_setcomptarget(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->params.compressionTarget.frTargeting = val;
+ if (gspca_dev->streaming)
+ return command_setcompressiontarget(gspca_dev);
+
+ return 0;
+}
+
+static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->params.compressionTarget.frTargeting;
+ return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ switch (menu->id) {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (menu->index) {
+ case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+ strcpy((char *) menu->name, "NoFliker");
+ return 0;
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+ break;
+ case V4L2_CID_COMP_TARGET:
+ switch (menu->index) {
+ case CPIA_COMPRESSION_TARGET_QUALITY:
+ strcpy((char *) menu->name, "Quality");
+ return 0;
+ case CPIA_COMPRESSION_TARGET_FRAMERATE:
+ strcpy((char *) menu->name, "Framerate");
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .dq_callback = sd_dq_callback,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0553, 0x0002)},
+ {USB_DEVICE(0x0813, 0x0001)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ int ret;
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c
index fdf4c0ec5e7a..ecd4d743d2bc 100644
--- a/drivers/media/video/gspca/etoms.c
+++ b/drivers/media/video/gspca/etoms.c
@@ -52,7 +52,7 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
@@ -851,7 +851,7 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
}
/* sub-driver description */
-static struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c
index 4878c8f66543..9e42476c0eaf 100644
--- a/drivers/media/video/gspca/gl860/gl860.c
+++ b/drivers/media/video/gspca/gl860/gl860.c
@@ -161,7 +161,7 @@ static int gl860_build_control_table(struct gspca_dev *gspca_dev)
/*==================== sud-driver structure initialisation =================*/
-static struct sd_desc sd_desc_mi1320 = {
+static const struct sd_desc sd_desc_mi1320 = {
.name = MODULE_NAME,
.ctrls = sd_ctrls_mi1320,
.nctrls = GL860_NCTRLS,
@@ -174,7 +174,7 @@ static struct sd_desc sd_desc_mi1320 = {
.dq_callback = sd_callback,
};
-static struct sd_desc sd_desc_mi2020 = {
+static const struct sd_desc sd_desc_mi2020 = {
.name = MODULE_NAME,
.ctrls = sd_ctrls_mi2020,
.nctrls = GL860_NCTRLS,
@@ -187,7 +187,7 @@ static struct sd_desc sd_desc_mi2020 = {
.dq_callback = sd_callback,
};
-static struct sd_desc sd_desc_mi2020b = {
+static const struct sd_desc sd_desc_mi2020b = {
.name = MODULE_NAME,
.ctrls = sd_ctrls_mi2020b,
.nctrls = GL860_NCTRLS,
@@ -200,7 +200,7 @@ static struct sd_desc sd_desc_mi2020b = {
.dq_callback = sd_callback,
};
-static struct sd_desc sd_desc_ov2640 = {
+static const struct sd_desc sd_desc_ov2640 = {
.name = MODULE_NAME,
.ctrls = sd_ctrls_ov2640,
.nctrls = GL860_NCTRLS,
@@ -213,7 +213,7 @@ static struct sd_desc sd_desc_ov2640 = {
.dq_callback = sd_callback,
};
-static struct sd_desc sd_desc_ov9655 = {
+static const struct sd_desc sd_desc_ov9655 = {
.name = MODULE_NAME,
.ctrls = sd_ctrls_ov9655,
.nctrls = GL860_NCTRLS,
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index e930a67d526b..222af479150b 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -3,6 +3,9 @@
*
* Copyright (C) 2008-2009 Jean-Francois Moine (http://moinejf.free.fr)
*
+ * Camera button input handling by Márton Németh
+ * Copyright (C) 2009-2010 Márton Németh <nm127@freemail.hu>
+ *
* 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
@@ -37,6 +40,11 @@
#include "gspca.h"
+#ifdef CONFIG_INPUT
+#include <linux/input.h>
+#include <linux/usb/input.h>
+#endif
+
/* global values */
#define DEF_NURBS 3 /* default number of URBs */
#if DEF_NURBS > MAX_NURBS
@@ -47,7 +55,7 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 8, 0)
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 9, 0)
#ifdef GSPCA_DEBUG
int gspca_debug = D_ERR | D_PROBE;
@@ -104,15 +112,185 @@ static const struct vm_operations_struct gspca_vm_ops = {
.close = gspca_vm_close,
};
+/*
+ * Input and interrupt endpoint handling functions
+ */
+#ifdef CONFIG_INPUT
+static void int_irq(struct urb *urb)
+{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+ int ret;
+
+ ret = urb->status;
+ switch (ret) {
+ case 0:
+ if (gspca_dev->sd_desc->int_pkt_scan(gspca_dev,
+ urb->transfer_buffer, urb->actual_length) < 0) {
+ PDEBUG(D_ERR, "Unknown packet received");
+ }
+ break;
+
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ENODEV:
+ case -ESHUTDOWN:
+ /* Stop is requested either by software or hardware is gone,
+ * keep the ret value non-zero and don't resubmit later.
+ */
+ break;
+
+ default:
+ PDEBUG(D_ERR, "URB error %i, resubmitting", urb->status);
+ urb->status = 0;
+ ret = 0;
+ }
+
+ if (ret == 0) {
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret < 0)
+ PDEBUG(D_ERR, "Resubmit URB failed with error %i", ret);
+ }
+}
+
+static int gspca_input_connect(struct gspca_dev *dev)
+{
+ struct input_dev *input_dev;
+ int err = 0;
+
+ dev->input_dev = NULL;
+ if (dev->sd_desc->int_pkt_scan || dev->sd_desc->other_input) {
+ input_dev = input_allocate_device();
+ if (!input_dev)
+ return -ENOMEM;
+
+ usb_make_path(dev->dev, dev->phys, sizeof(dev->phys));
+ strlcat(dev->phys, "/input0", sizeof(dev->phys));
+
+ input_dev->name = dev->sd_desc->name;
+ input_dev->phys = dev->phys;
+
+ usb_to_input_id(dev->dev, &input_dev->id);
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY);
+ input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
+ input_dev->dev.parent = &dev->dev->dev;
+
+ err = input_register_device(input_dev);
+ if (err) {
+ PDEBUG(D_ERR, "Input device registration failed "
+ "with error %i", err);
+ input_dev->dev.parent = NULL;
+ input_free_device(input_dev);
+ } else {
+ dev->input_dev = input_dev;
+ }
+ }
+
+ return err;
+}
+
+static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev,
+ struct usb_endpoint_descriptor *ep)
+{
+ unsigned int buffer_len;
+ int interval;
+ struct urb *urb;
+ struct usb_device *dev;
+ void *buffer = NULL;
+ int ret = -EINVAL;
+
+ buffer_len = ep->wMaxPacketSize;
+ interval = ep->bInterval;
+ PDEBUG(D_PROBE, "found int in endpoint: 0x%x, "
+ "buffer_len=%u, interval=%u",
+ ep->bEndpointAddress, buffer_len, interval);
+
+ dev = gspca_dev->dev;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ buffer = usb_buffer_alloc(dev, ep->wMaxPacketSize,
+ GFP_KERNEL, &urb->transfer_dma);
+ if (!buffer) {
+ ret = -ENOMEM;
+ goto error_buffer;
+ }
+ usb_fill_int_urb(urb, dev,
+ usb_rcvintpipe(dev, ep->bEndpointAddress),
+ buffer, buffer_len,
+ int_irq, (void *)gspca_dev, interval);
+ gspca_dev->int_urb = urb;
+ ret = usb_submit_urb(urb, GFP_KERNEL);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "submit URB failed with error %i", ret);
+ goto error_submit;
+ }
+ return ret;
+
+error_submit:
+ usb_buffer_free(dev,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer,
+ urb->transfer_dma);
+error_buffer:
+ usb_free_urb(urb);
+error:
+ return ret;
+}
+
+static void gspca_input_create_urb(struct gspca_dev *gspca_dev)
+{
+ struct usb_interface *intf;
+ struct usb_host_interface *intf_desc;
+ struct usb_endpoint_descriptor *ep;
+ int i;
+
+ if (gspca_dev->sd_desc->int_pkt_scan) {
+ intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+ intf_desc = intf->cur_altsetting;
+ for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
+ ep = &intf_desc->endpoint[i].desc;
+ if (usb_endpoint_dir_in(ep) &&
+ usb_endpoint_xfer_int(ep)) {
+
+ alloc_and_submit_int_urb(gspca_dev, ep);
+ break;
+ }
+ }
+ }
+}
+
+static void gspca_input_destroy_urb(struct gspca_dev *gspca_dev)
+{
+ struct urb *urb;
+
+ urb = gspca_dev->int_urb;
+ if (urb) {
+ gspca_dev->int_urb = NULL;
+ usb_kill_urb(urb);
+ usb_buffer_free(gspca_dev->dev,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer,
+ urb->transfer_dma);
+ usb_free_urb(urb);
+ }
+}
+#else
+#define gspca_input_connect(gspca_dev) 0
+#define gspca_input_create_urb(gspca_dev)
+#define gspca_input_destroy_urb(gspca_dev)
+#endif
+
/* get the current input frame buffer */
struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev)
{
struct gspca_frame *frame;
- int i;
- i = gspca_dev->fr_i;
- i = gspca_dev->fr_queue[i];
- frame = &gspca_dev->frame[i];
+ frame = gspca_dev->cur_frame;
if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
!= V4L2_BUF_FLAG_QUEUED)
return NULL;
@@ -486,11 +664,13 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
i, ep->desc.bEndpointAddress);
gspca_dev->alt = i; /* memorize the current alt setting */
if (gspca_dev->nbalt > 1) {
+ gspca_input_destroy_urb(gspca_dev);
ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
if (ret < 0) {
err("set alt %d err %d", i, ret);
- return NULL;
+ ep = NULL;
}
+ gspca_input_create_urb(gspca_dev);
}
return ep;
}
@@ -534,26 +714,22 @@ static int create_urbs(struct gspca_dev *gspca_dev,
nurbs = 1;
}
- gspca_dev->nurbs = nurbs;
for (n = 0; n < nurbs; n++) {
urb = usb_alloc_urb(npkt, GFP_KERNEL);
if (!urb) {
err("usb_alloc_urb failed");
- destroy_urbs(gspca_dev);
return -ENOMEM;
}
+ gspca_dev->urb[n] = urb;
urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,
bsize,
GFP_KERNEL,
&urb->transfer_dma);
if (urb->transfer_buffer == NULL) {
- usb_free_urb(urb);
- err("usb_buffer_urb failed");
- destroy_urbs(gspca_dev);
+ err("usb_buffer_alloc failed");
return -ENOMEM;
}
- gspca_dev->urb[n] = urb;
urb->dev = gspca_dev->dev;
urb->context = gspca_dev;
urb->transfer_buffer_length = bsize;
@@ -585,6 +761,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
static int gspca_init_transfer(struct gspca_dev *gspca_dev)
{
struct usb_host_endpoint *ep;
+ struct urb *urb;
int n, ret;
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
@@ -595,6 +772,8 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
goto out;
}
+ gspca_dev->usb_err = 0;
+
/* set the higher alternate setting and
* loop until urb submit succeeds */
if (gspca_dev->cam.reverse_alts)
@@ -613,10 +792,15 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
goto out;
}
for (;;) {
- PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);
- ret = create_urbs(gspca_dev, ep);
- if (ret < 0)
- goto out;
+ if (!gspca_dev->cam.no_urb_create) {
+ PDEBUG(D_STREAM, "init transfer alt %d",
+ gspca_dev->alt);
+ ret = create_urbs(gspca_dev, ep);
+ if (ret < 0) {
+ destroy_urbs(gspca_dev);
+ goto out;
+ }
+ }
/* clear the bulk endpoint */
if (gspca_dev->cam.bulk)
@@ -636,8 +820,11 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
break;
/* submit the URBs */
- for (n = 0; n < gspca_dev->nurbs; n++) {
- ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL);
+ for (n = 0; n < MAX_NURBS; n++) {
+ urb = gspca_dev->urb[n];
+ if (urb == NULL)
+ break;
+ ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret < 0)
break;
}
@@ -694,7 +881,9 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev)
if (gspca_dev->sd_desc->stopN)
gspca_dev->sd_desc->stopN(gspca_dev);
destroy_urbs(gspca_dev);
+ gspca_input_destroy_urb(gspca_dev);
gspca_set_alt0(gspca_dev);
+ gspca_input_create_urb(gspca_dev);
}
/* always call stop0 to free the subdriver's resources */
@@ -1815,6 +2004,8 @@ static int vidioc_qbuf(struct file *file, void *priv,
/* put the buffer in the 'queued' queue */
i = gspca_dev->fr_q;
gspca_dev->fr_queue[i] = index;
+ if (gspca_dev->fr_i == i)
+ gspca_dev->cur_frame = frame;
gspca_dev->fr_q = (i + 1) % gspca_dev->nframes;
PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d",
gspca_dev->fr_q,
@@ -2058,11 +2249,12 @@ int gspca_dev_probe(struct usb_interface *intf,
PDEBUG(D_ERR, "Too many config");
return -ENODEV;
}
+
+ /* the USB video interface must be the first one */
interface = &intf->cur_altsetting->desc;
- if (interface->bInterfaceNumber > 0) {
- PDEBUG(D_ERR, "intf != 0");
+ if (dev->config->desc.bNumInterfaces != 1 &&
+ interface->bInterfaceNumber != 0)
return -ENODEV;
- }
/* create the device */
if (dev_size < sizeof *gspca_dev)
@@ -2094,6 +2286,10 @@ int gspca_dev_probe(struct usb_interface *intf,
goto out;
gspca_set_default_mode(gspca_dev);
+ ret = gspca_input_connect(gspca_dev);
+ if (ret)
+ goto out;
+
mutex_init(&gspca_dev->usb_lock);
mutex_init(&gspca_dev->read_lock);
mutex_init(&gspca_dev->queue_lock);
@@ -2114,8 +2310,15 @@ int gspca_dev_probe(struct usb_interface *intf,
usb_set_intfdata(intf, gspca_dev);
PDEBUG(D_PROBE, "%s created", video_device_node_name(&gspca_dev->vdev));
+
+ gspca_input_create_urb(gspca_dev);
+
return 0;
out:
+#ifdef CONFIG_INPUT
+ if (gspca_dev->input_dev)
+ input_unregister_device(gspca_dev->input_dev);
+#endif
kfree(gspca_dev->usb_buf);
kfree(gspca_dev);
return ret;
@@ -2131,6 +2334,9 @@ EXPORT_SYMBOL(gspca_dev_probe);
void gspca_disconnect(struct usb_interface *intf)
{
struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+#ifdef CONFIG_INPUT
+ struct input_dev *input_dev;
+#endif
PDEBUG(D_PROBE, "%s disconnect",
video_device_node_name(&gspca_dev->vdev));
@@ -2142,6 +2348,15 @@ void gspca_disconnect(struct usb_interface *intf)
wake_up_interruptible(&gspca_dev->wq);
}
+#ifdef CONFIG_INPUT
+ gspca_input_destroy_urb(gspca_dev);
+ input_dev = gspca_dev->input_dev;
+ if (input_dev) {
+ gspca_dev->input_dev = NULL;
+ input_unregister_device(input_dev);
+ }
+#endif
+
/* the device is freed at exit of this function */
gspca_dev->dev = NULL;
mutex_unlock(&gspca_dev->usb_lock);
@@ -2167,6 +2382,7 @@ int gspca_suspend(struct usb_interface *intf, pm_message_t message)
if (gspca_dev->sd_desc->stopN)
gspca_dev->sd_desc->stopN(gspca_dev);
destroy_urbs(gspca_dev);
+ gspca_input_destroy_urb(gspca_dev);
gspca_set_alt0(gspca_dev);
if (gspca_dev->sd_desc->stop0)
gspca_dev->sd_desc->stop0(gspca_dev);
@@ -2180,6 +2396,7 @@ int gspca_resume(struct usb_interface *intf)
gspca_dev->frozen = 0;
gspca_dev->sd_desc->init(gspca_dev);
+ gspca_input_create_urb(gspca_dev);
if (gspca_dev->streaming)
return gspca_init_transfer(gspca_dev);
return 0;
@@ -2203,6 +2420,8 @@ int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
int retval = 0;
for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
+ if (gspca_dev->ctrl_dis & (1 << i))
+ continue;
if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN)
gain_ctrl = &gspca_dev->sd_desc->ctrls[i];
if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE)
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 59c7941da999..02c696a22be0 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -48,26 +48,27 @@ extern int gspca_debug;
/* used to list framerates supported by a camera mode (resolution) */
struct framerates {
- int *rates;
+ const u8 *rates;
int nrates;
};
/* device information - set at probe time */
struct cam {
- int bulk_size; /* buffer size when image transfer by bulk */
const struct v4l2_pix_format *cam_mode; /* size nmodes */
- char nmodes;
const struct framerates *mode_framerates; /* must have size nmode,
* just like cam_mode */
- __u8 bulk_nurbs; /* number of URBs in bulk mode
+ u32 bulk_size; /* buffer size when image transfer by bulk */
+ u32 input_flags; /* value for ENUM_INPUT status flags */
+ u8 nmodes; /* size of cam_mode */
+ u8 no_urb_create; /* don't create transfer URBs */
+ u8 bulk_nurbs; /* number of URBs in bulk mode
* - cannot be > MAX_NURBS
* - when 0 and bulk_size != 0 means
* 1 URB and submit done by subdriver */
u8 bulk; /* image transfer by 0:isoc / 1:bulk */
u8 npkt; /* number of packets in an ISOC message
* 0 is the default value: 32 packets */
- u32 input_flags; /* value for ENUM_INPUT status flags */
- char reverse_alts; /* Alt settings are in high to low order */
+ u8 reverse_alts; /* Alt settings are in high to low order */
};
struct gspca_dev;
@@ -90,6 +91,9 @@ typedef int (*cam_qmnu_op) (struct gspca_dev *,
typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
u8 *data,
int len);
+typedef int (*cam_int_pkt_op) (struct gspca_dev *gspca_dev,
+ u8 *data,
+ int len);
struct ctrl {
struct v4l2_queryctrl qctrl;
@@ -125,6 +129,12 @@ struct sd_desc {
cam_reg_op get_register;
#endif
cam_ident_op get_chip_ident;
+#ifdef CONFIG_INPUT
+ cam_int_pkt_op int_pkt_scan;
+ /* other_input makes the gspca core create gspca_dev->input even when
+ int_pkt_scan is NULL, for cams with non interrupt driven buttons */
+ u8 other_input;
+#endif
};
/* packet types when moving from iso buf to frame buf */
@@ -147,6 +157,10 @@ struct gspca_dev {
struct module *module; /* subdriver handling the device */
struct usb_device *dev;
struct file *capt_file; /* file doing video capture */
+#ifdef CONFIG_INPUT
+ struct input_dev *input_dev;
+ char phys[64]; /* physical device path */
+#endif
struct cam cam; /* device information */
const struct sd_desc *sd_desc; /* subdriver description */
@@ -156,6 +170,9 @@ struct gspca_dev {
#define USB_BUF_SZ 64
__u8 *usb_buf; /* buffer for USB exchanges */
struct urb *urb[MAX_NURBS];
+#ifdef CONFIG_INPUT
+ struct urb *int_urb;
+#endif
__u8 *frbuf; /* buffer for nframes */
struct gspca_frame frame[GSPCA_MAX_FRAMES];
@@ -187,7 +204,6 @@ struct gspca_dev {
char users; /* number of opens */
char present; /* device connected */
char nbufread; /* number of buffers for read() */
- char nurbs; /* number of allocated URBs */
char memory; /* memory type (V4L2_MEMORY_xxx) */
__u8 iface; /* USB interface number */
__u8 alt; /* USB alternate setting */
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/drivers/media/video/gspca/m5602/m5602_mt9m111.c
index 8d071dff6944..c0722fa64606 100644
--- a/drivers/media/video/gspca/m5602/m5602_mt9m111.c
+++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.c
@@ -48,7 +48,7 @@ static struct v4l2_pix_format mt9m111_modes[] = {
}
};
-const static struct ctrl mt9m111_ctrls[] = {
+static const struct ctrl mt9m111_ctrls[] = {
#define VFLIP_IDX 0
{
{
@@ -171,7 +171,7 @@ int mt9m111_probe(struct sd *sd)
return -ENODEV;
}
- info("Probing for a mt9m111 sensor");
+ PDEBUG(D_PROBE, "Probing for a mt9m111 sensor");
/* Do the preinit */
for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) {
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.c b/drivers/media/video/gspca/m5602/m5602_ov7660.c
index 2a28b74cb3f9..62c1cbf06666 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov7660.c
+++ b/drivers/media/video/gspca/m5602/m5602_ov7660.c
@@ -33,7 +33,7 @@ static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-const static struct ctrl ov7660_ctrls[] = {
+static const struct ctrl ov7660_ctrls[] = {
#define GAIN_IDX 1
{
{
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.h b/drivers/media/video/gspca/m5602/m5602_ov7660.h
index f5588ebe667c..4d9dcf29da2e 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov7660.h
+++ b/drivers/media/video/gspca/m5602/m5602_ov7660.h
@@ -94,7 +94,7 @@ int ov7660_start(struct sd *sd);
int ov7660_stop(struct sd *sd);
void ov7660_disconnect(struct sd *sd);
-const static struct m5602_sensor ov7660 = {
+static const struct m5602_sensor ov7660 = {
.name = "ov7660",
.i2c_slave_id = 0x42,
.i2c_regW = 1,
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c
index 923cdd5f7a6b..069ba0044f8b 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov9650.c
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.c
@@ -307,7 +307,7 @@ int ov9650_probe(struct sd *sd)
return -ENODEV;
}
- info("Probing for an ov9650 sensor");
+ PDEBUG(D_PROBE, "Probing for an ov9650 sensor");
/* Run the pre-init before probing the sensor */
for (i = 0; i < ARRAY_SIZE(preinit_ov9650) && !err; i++) {
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.c b/drivers/media/video/gspca/m5602/m5602_po1030.c
index 8d74d8065b79..925b87d66f40 100644
--- a/drivers/media/video/gspca/m5602/m5602_po1030.c
+++ b/drivers/media/video/gspca/m5602/m5602_po1030.c
@@ -205,7 +205,7 @@ int po1030_probe(struct sd *sd)
return -ENODEV;
}
- info("Probing for a po1030 sensor");
+ PDEBUG(D_PROBE, "Probing for a po1030 sensor");
/* Run the pre-init to actually probe the unit */
for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) {
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
index aa2f3c7e2cb5..da0a38c78708 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -48,6 +48,12 @@ static
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
}
}, {
+ .ident = "Fujitsu-Siemens Amilo Xi 2428",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
+ }
+ }, {
.ident = "Fujitsu-Siemens Amilo Xi 2528",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
@@ -242,7 +248,7 @@ int s5k4aa_probe(struct sd *sd)
return -ENODEV;
}
- info("Probing for a s5k4aa sensor");
+ PDEBUG(D_PROBE, "Probing for a s5k4aa sensor");
/* Preinit the sensor */
for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
index 6b89f33a4ce0..fbd91545497a 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
@@ -143,7 +143,7 @@ int s5k83a_probe(struct sd *sd)
return -ENODEV;
}
- info("Probing for a s5k83a sensor");
+ PDEBUG(D_PROBE, "Probing for a s5k83a sensor");
/* Preinit the sensor */
for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index 9cf8d68c71bf..3d9229e22b25 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -54,7 +54,7 @@ static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c
index 9154870e07d2..33744e724eaa 100644
--- a/drivers/media/video/gspca/mr97310a.c
+++ b/drivers/media/video/gspca/mr97310a.c
@@ -57,6 +57,14 @@
#define MR97310A_GAIN_MAX 31
#define MR97310A_GAIN_DEFAULT 25
+#define MR97310A_CONTRAST_MIN 0
+#define MR97310A_CONTRAST_MAX 31
+#define MR97310A_CONTRAST_DEFAULT 23
+
+#define MR97310A_CS_GAIN_MIN 0
+#define MR97310A_CS_GAIN_MAX 0x7ff
+#define MR97310A_CS_GAIN_DEFAULT 0x110
+
#define MR97310A_MIN_CLOCKDIV_MIN 3
#define MR97310A_MIN_CLOCKDIV_MAX 8
#define MR97310A_MIN_CLOCKDIV_DEFAULT 3
@@ -82,7 +90,8 @@ struct sd {
int brightness;
u16 exposure;
- u8 gain;
+ u32 gain;
+ u8 contrast;
u8 min_clockdiv;
};
@@ -98,6 +107,8 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val);
@@ -105,11 +116,13 @@ static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val);
static void setbrightness(struct gspca_dev *gspca_dev);
static void setexposure(struct gspca_dev *gspca_dev);
static void setgain(struct gspca_dev *gspca_dev);
+static void setcontrast(struct gspca_dev *gspca_dev);
/* V4L2 controls supported by the driver */
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
/* Separate brightness control description for Argus QuickClix as it has
- different limits from the other mr97310a cameras */
+ * different limits from the other mr97310a cameras, and separate gain
+ * control for Sakar CyberPix camera. */
{
#define NORM_BRIGHTNESS_IDX 0
{
@@ -171,7 +184,37 @@ static struct ctrl sd_ctrls[] = {
.get = sd_getgain,
},
{
-#define MIN_CLOCKDIV_IDX 4
+#define SAKAR_CS_GAIN_IDX 4
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = MR97310A_CS_GAIN_MIN,
+ .maximum = MR97310A_CS_GAIN_MAX,
+ .step = 1,
+ .default_value = MR97310A_CS_GAIN_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
+ },
+ {
+#define CONTRAST_IDX 5
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = MR97310A_CONTRAST_MIN,
+ .maximum = MR97310A_CONTRAST_MAX,
+ .step = 1,
+ .default_value = MR97310A_CONTRAST_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+#define MIN_CLOCKDIV_IDX 6
{
.id = V4L2_CID_PRIVATE_BASE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -327,7 +370,6 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
if (err_code < 0)
return err_code;
- err_code = mr_write(gspca_dev, 1);
data[0] = 0x19;
data[1] = 0x51;
err_code = mr_write(gspca_dev, 2);
@@ -437,6 +479,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
+ int gain_default = MR97310A_GAIN_DEFAULT;
int err_code;
cam = &gspca_dev->cam;
@@ -460,12 +503,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
if (err_code < 0)
return err_code;
+ /* Now, the query for sensor type. */
+ err_code = cam_get_response16(gspca_dev, 0x07, 1);
+ if (err_code < 0)
+ return err_code;
+
if (id->idProduct == 0x0110 || id->idProduct == 0x010e) {
sd->cam_type = CAM_TYPE_CIF;
cam->nmodes--;
- err_code = cam_get_response16(gspca_dev, 0x06, 1);
- if (err_code < 0)
- return err_code;
/*
* All but one of the known CIF cameras share the same USB ID,
* but two different init routines are in use, and the control
@@ -473,12 +518,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
* of the two known varieties is connected!
*
* A list of known CIF cameras follows. They all report either
- * 0002 for type 0 or 0003 for type 1.
+ * 0200 for type 0 or 0300 for type 1.
* If you have another to report, please do
*
* Name sd->sensor_type reported by
*
- * Sakar Spy-shot 0 T. Kilgore
+ * Sakar 56379 Spy-shot 0 T. Kilgore
* Innovage 0 T. Kilgore
* Vivitar Mini 0 H. De Goede
* Vivitar Mini 0 E. Rodriguez
@@ -487,7 +532,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
* Philips dig. keych. 1 T. Kilgore
* Trust Spyc@m 100 1 A. Jacobs
*/
- switch (gspca_dev->usb_buf[1]) {
+ switch (gspca_dev->usb_buf[0]) {
case 2:
sd->sensor_type = 0;
break;
@@ -504,20 +549,19 @@ static int sd_config(struct gspca_dev *gspca_dev,
} else {
sd->cam_type = CAM_TYPE_VGA;
- err_code = cam_get_response16(gspca_dev, 0x07, 1);
- if (err_code < 0)
- return err_code;
-
/*
- * Here is a table of the responses to the previous command
- * from the known MR97310A VGA cameras.
+ * Here is a table of the responses to the query for sensor
+ * type, from the known MR97310A VGA cameras. Six different
+ * cameras of which five share the same USB ID.
*
* Name gspca_dev->usb_buf[] sd->sensor_type
* sd->do_lcd_stop
* Aiptek Pencam VGA+ 0300 0 1
- * ION digital 0350 0 1
+ * ION digital 0300 0 1
* Argus DC-1620 0450 1 0
* Argus QuickClix 0420 1 1
+ * Sakar 77379 Digital 0350 0 1
+ * Sakar 1638x CyberPix 0120 0 2
*
* Based upon these results, we assume default settings
* and then correct as necessary, as follows.
@@ -527,10 +571,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->sensor_type = 1;
sd->do_lcd_stop = 0;
sd->adj_colors = 0;
- if ((gspca_dev->usb_buf[0] != 0x03) &&
+ if (gspca_dev->usb_buf[0] == 0x01) {
+ sd->sensor_type = 2;
+ } else if ((gspca_dev->usb_buf[0] != 0x03) &&
(gspca_dev->usb_buf[0] != 0x04)) {
PDEBUG(D_ERR, "Unknown VGA Sensor id Byte 0: %02x",
- gspca_dev->usb_buf[1]);
+ gspca_dev->usb_buf[0]);
PDEBUG(D_ERR, "Defaults assumed, may not work");
PDEBUG(D_ERR, "Please report this");
}
@@ -560,7 +606,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
PDEBUG(D_PROBE, "MR97310A VGA camera detected, sensor: %d",
sd->sensor_type);
}
- /* Stop streaming as we've started it to probe the sensor type. */
+ /* Stop streaming as we've started it only to probe the sensor type. */
sd_stopN(gspca_dev);
if (force_sensor_type != -1) {
@@ -574,9 +620,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* No brightness for sensor_type 0 */
if (sd->sensor_type == 0)
gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
- (1 << ARGUS_QC_BRIGHTNESS_IDX);
+ (1 << ARGUS_QC_BRIGHTNESS_IDX) |
+ (1 << CONTRAST_IDX) |
+ (1 << SAKAR_CS_GAIN_IDX);
else
gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) |
+ (1 << CONTRAST_IDX) |
+ (1 << SAKAR_CS_GAIN_IDX) |
(1 << MIN_CLOCKDIV_IDX);
} else {
/* All controls need to be disabled if VGA sensor_type is 0 */
@@ -585,17 +635,30 @@ static int sd_config(struct gspca_dev *gspca_dev,
(1 << ARGUS_QC_BRIGHTNESS_IDX) |
(1 << EXPOSURE_IDX) |
(1 << GAIN_IDX) |
+ (1 << CONTRAST_IDX) |
+ (1 << SAKAR_CS_GAIN_IDX) |
(1 << MIN_CLOCKDIV_IDX);
- else if (sd->do_lcd_stop)
+ else if (sd->sensor_type == 2) {
+ gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
+ (1 << ARGUS_QC_BRIGHTNESS_IDX) |
+ (1 << GAIN_IDX) |
+ (1 << MIN_CLOCKDIV_IDX);
+ gain_default = MR97310A_CS_GAIN_DEFAULT;
+ } else if (sd->do_lcd_stop)
/* Argus QuickClix has different brightness limits */
- gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX);
+ gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
+ (1 << CONTRAST_IDX) |
+ (1 << SAKAR_CS_GAIN_IDX);
else
- gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX);
+ gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) |
+ (1 << CONTRAST_IDX) |
+ (1 << SAKAR_CS_GAIN_IDX);
}
sd->brightness = MR97310A_BRIGHTNESS_DEFAULT;
sd->exposure = MR97310A_EXPOSURE_DEFAULT;
- sd->gain = MR97310A_GAIN_DEFAULT;
+ sd->gain = gain_default;
+ sd->contrast = MR97310A_CONTRAST_DEFAULT;
sd->min_clockdiv = MR97310A_MIN_CLOCKDIV_DEFAULT;
return 0;
@@ -697,6 +760,12 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
{0x13, 0x00, {0x01}, 1},
{0, 0, {0}, 0}
};
+ /* Without this command the cam won't work with USB-UHCI */
+ gspca_dev->usb_buf[0] = 0x0a;
+ gspca_dev->usb_buf[1] = 0x00;
+ err_code = mr_write(gspca_dev, 2);
+ if (err_code < 0)
+ return err_code;
err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data,
ARRAY_SIZE(cif_sensor1_init_data));
}
@@ -717,6 +786,10 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
data[5] = 0x00;
data[10] = 0x91;
}
+ if (sd->sensor_type == 2) {
+ data[5] = 0x00;
+ data[10] = 0x18;
+ }
switch (gspca_dev->width) {
case 160:
@@ -731,6 +804,10 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
data[4] = 0x78; /* reg 3, V size/4 */
data[6] = 0x04; /* reg 5, H start */
data[8] = 0x03; /* reg 7, V start */
+ if (sd->sensor_type == 2) {
+ data[6] = 2;
+ data[8] = 1;
+ }
if (sd->do_lcd_stop)
data[8] = 0x04; /* Bayer tile shifted */
break;
@@ -753,7 +830,6 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
return err_code;
if (!sd->sensor_type) {
- /* The only known sensor_type 0 cam is the Argus DC-1620 */
const struct sensor_w_data vga_sensor0_init_data[] = {
{0x01, 0x00, {0x0c, 0x00, 0x04}, 3},
{0x14, 0x00, {0x01, 0xe4, 0x02, 0x84}, 4},
@@ -764,7 +840,7 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
};
err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data,
ARRAY_SIZE(vga_sensor0_init_data));
- } else { /* sd->sensor_type = 1 */
+ } else if (sd->sensor_type == 1) {
const struct sensor_w_data color_adj[] = {
{0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
/* adjusted blue, green, red gain correct
@@ -802,6 +878,48 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data,
ARRAY_SIZE(vga_sensor1_init_data));
+ } else { /* sensor type == 2 */
+ const struct sensor_w_data vga_sensor2_init_data[] = {
+
+ {0x01, 0x00, {0x48}, 1},
+ {0x02, 0x00, {0x22}, 1},
+ /* Reg 3 msb and 4 is lsb of the exposure setting*/
+ {0x05, 0x00, {0x10}, 1},
+ {0x06, 0x00, {0x00}, 1},
+ {0x07, 0x00, {0x00}, 1},
+ {0x08, 0x00, {0x00}, 1},
+ {0x09, 0x00, {0x00}, 1},
+ /* The following are used in the gain control
+ * which is BTW completely borked in the OEM driver
+ * The values for each color go from 0 to 0x7ff
+ *{0x0a, 0x00, {0x01}, 1}, green1 gain msb
+ *{0x0b, 0x00, {0x10}, 1}, green1 gain lsb
+ *{0x0c, 0x00, {0x01}, 1}, red gain msb
+ *{0x0d, 0x00, {0x10}, 1}, red gain lsb
+ *{0x0e, 0x00, {0x01}, 1}, blue gain msb
+ *{0x0f, 0x00, {0x10}, 1}, blue gain lsb
+ *{0x10, 0x00, {0x01}, 1}, green2 gain msb
+ *{0x11, 0x00, {0x10}, 1}, green2 gain lsb
+ */
+ {0x12, 0x00, {0x00}, 1},
+ {0x13, 0x00, {0x04}, 1}, /* weird effect on colors */
+ {0x14, 0x00, {0x00}, 1},
+ {0x15, 0x00, {0x06}, 1},
+ {0x16, 0x00, {0x01}, 1},
+ {0x17, 0x00, {0xe2}, 1}, /* vertical alignment */
+ {0x18, 0x00, {0x02}, 1},
+ {0x19, 0x00, {0x82}, 1}, /* don't mess with */
+ {0x1a, 0x00, {0x00}, 1},
+ {0x1b, 0x00, {0x20}, 1},
+ /* {0x1c, 0x00, {0x17}, 1}, contrast control */
+ {0x1d, 0x00, {0x80}, 1}, /* moving causes a mess */
+ {0x1e, 0x00, {0x08}, 1}, /* moving jams the camera */
+ {0x1f, 0x00, {0x0c}, 1},
+ {0x20, 0x00, {0x00}, 1},
+ {0, 0, {0}, 0}
+ };
+ err_code = sensor_write_regs(gspca_dev, vga_sensor2_init_data,
+ ARRAY_SIZE(vga_sensor2_init_data));
}
return err_code;
}
@@ -834,6 +952,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
return err_code;
setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
setexposure(gspca_dev);
setgain(gspca_dev);
@@ -893,7 +1012,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
static void setexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int exposure;
+ int exposure = MR97310A_EXPOSURE_DEFAULT;
u8 buf[2];
if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX))
@@ -905,6 +1024,11 @@ static void setexposure(struct gspca_dev *gspca_dev)
exposure = (sd->exposure * 9267) / 10000 + 300;
sensor_write1(gspca_dev, 3, exposure >> 4);
sensor_write1(gspca_dev, 4, exposure & 0x0f);
+ } else if (sd->sensor_type == 2) {
+ exposure = sd->exposure;
+ exposure >>= 3;
+ sensor_write1(gspca_dev, 3, exposure >> 8);
+ sensor_write1(gspca_dev, 4, exposure & 0xff);
} else {
/* We have both a clock divider and an exposure register.
We first calculate the clock divider, as that determines
@@ -943,17 +1067,34 @@ static void setexposure(struct gspca_dev *gspca_dev)
static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ u8 gainreg;
- if (gspca_dev->ctrl_dis & (1 << GAIN_IDX))
+ if ((gspca_dev->ctrl_dis & (1 << GAIN_IDX)) &&
+ (gspca_dev->ctrl_dis & (1 << SAKAR_CS_GAIN_IDX)))
return;
- if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) {
+ if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1)
sensor_write1(gspca_dev, 0x0e, sd->gain);
- } else {
+ else if (sd->cam_type == CAM_TYPE_VGA && sd->sensor_type == 2)
+ for (gainreg = 0x0a; gainreg < 0x11; gainreg += 2) {
+ sensor_write1(gspca_dev, gainreg, sd->gain >> 8);
+ sensor_write1(gspca_dev, gainreg + 1, sd->gain & 0xff);
+ }
+ else
sensor_write1(gspca_dev, 0x10, sd->gain);
- }
}
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (gspca_dev->ctrl_dis & (1 << CONTRAST_IDX))
+ return;
+
+ sensor_write1(gspca_dev, 0x1c, sd->contrast);
+}
+
+
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1008,6 +1149,25 @@ static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index b4f965731244..f36e11a0458d 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -38,6 +38,7 @@
*/
#define MODULE_NAME "ov519"
+#include <linux/input.h>
#include "gspca.h"
MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
@@ -70,6 +71,9 @@ struct sd {
char invert_led;
#define BRIDGE_INVERT_LED 8
+ char snapshot_pressed;
+ char snapshot_needs_reset;
+
/* Determined by sensor type */
__u8 sif;
@@ -99,10 +103,12 @@ struct sd {
#define SEN_OV66308AF 5
#define SEN_OV7610 6
#define SEN_OV7620 7
-#define SEN_OV7640 8
-#define SEN_OV7670 9
-#define SEN_OV76BE 10
-#define SEN_OV8610 11
+#define SEN_OV7620AE 8
+#define SEN_OV7640 9
+#define SEN_OV7648 10
+#define SEN_OV7670 11
+#define SEN_OV76BE 12
+#define SEN_OV8610 13
u8 sensor_addr;
int sensor_width;
@@ -139,6 +145,7 @@ static void setautobrightness(struct sd *sd);
static void setfreq(struct sd *sd);
static const struct ctrl sd_ctrls[] = {
+#define BRIGHTNESS_IDX 0
{
{
.id = V4L2_CID_BRIGHTNESS,
@@ -153,6 +160,7 @@ static const struct ctrl sd_ctrls[] = {
.set = sd_setbrightness,
.get = sd_getbrightness,
},
+#define CONTRAST_IDX 1
{
{
.id = V4L2_CID_CONTRAST,
@@ -167,6 +175,7 @@ static const struct ctrl sd_ctrls[] = {
.set = sd_setcontrast,
.get = sd_getcontrast,
},
+#define COLOR_IDX 2
{
{
.id = V4L2_CID_SATURATION,
@@ -503,7 +512,7 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
/*
* The FX2 chip does not give us a zero length read at end of frame.
* It does, however, give a short read at the end of a frame, if
- * neccessary, rather than run two frames together.
+ * necessary, rather than run two frames together.
*
* By choosing the right bulk transfer size, we are guaranteed to always
* get a short read for the last read of each frame. Frame sizes are
@@ -2554,7 +2563,7 @@ static int ov7xx0_configure(struct sd *sd)
/* I don't know what's different about the 76BE yet. */
if (i2c_r(sd, 0x15) & 1) {
PDEBUG(D_PROBE, "Sensor is an OV7620AE");
- sd->sensor = SEN_OV7620;
+ sd->sensor = SEN_OV7620AE;
} else {
PDEBUG(D_PROBE, "Sensor is an OV76BE");
sd->sensor = SEN_OV76BE;
@@ -2588,7 +2597,7 @@ static int ov7xx0_configure(struct sd *sd)
break;
case 0x48:
PDEBUG(D_PROBE, "Sensor is an OV7648");
- sd->sensor = SEN_OV7640; /* FIXME */
+ sd->sensor = SEN_OV7648;
break;
default:
PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low);
@@ -2680,6 +2689,36 @@ static void ov51x_led_control(struct sd *sd, int on)
}
}
+static void sd_reset_snapshot(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (!sd->snapshot_needs_reset)
+ return;
+
+ /* Note it is important that we clear sd->snapshot_needs_reset,
+ before actually clearing the snapshot state in the bridge
+ otherwise we might race with the pkt_scan interrupt handler */
+ sd->snapshot_needs_reset = 0;
+
+ switch (sd->bridge) {
+ case BRIDGE_OV511:
+ case BRIDGE_OV511PLUS:
+ reg_w(sd, R51x_SYS_SNAP, 0x02);
+ reg_w(sd, R51x_SYS_SNAP, 0x00);
+ break;
+ case BRIDGE_OV518:
+ case BRIDGE_OV518PLUS:
+ reg_w(sd, R51x_SYS_SNAP, 0x02); /* Reset */
+ reg_w(sd, R51x_SYS_SNAP, 0x01); /* Enable */
+ break;
+ case BRIDGE_OV519:
+ reg_w(sd, R51x_SYS_RESET, 0x40);
+ reg_w(sd, R51x_SYS_RESET, 0x00);
+ break;
+ }
+}
+
static int ov51x_upload_quan_tables(struct sd *sd)
{
const unsigned char yQuanTable511[] = {
@@ -3115,7 +3154,11 @@ static int sd_config(struct gspca_dev *gspca_dev,
(1 << OV7670_FREQ_IDX);
}
sd->quality = QUALITY_DEF;
- if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670)
+ if (sd->sensor == SEN_OV7640 ||
+ sd->sensor == SEN_OV7648)
+ gspca_dev->ctrl_dis |= (1 << AUTOBRIGHT_IDX) |
+ (1 << CONTRAST_IDX);
+ if (sd->sensor == SEN_OV7670)
gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT_IDX;
/* OV8610 Frequency filter control should work but needs testing */
if (sd->sensor == SEN_OV8610)
@@ -3169,10 +3212,12 @@ static int sd_init(struct gspca_dev *gspca_dev)
return -EIO;
break;
case SEN_OV7620:
+ case SEN_OV7620AE:
if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
return -EIO;
break;
case SEN_OV7640:
+ case SEN_OV7648:
if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
return -EIO;
break;
@@ -3246,7 +3291,9 @@ static int ov511_mode_init_regs(struct sd *sd)
/* Note once the FIXME's in mode_init_ov_sensor_regs() are fixed
for more sensors we need to do this for them too */
case SEN_OV7620:
+ case SEN_OV7620AE:
case SEN_OV7640:
+ case SEN_OV7648:
case SEN_OV76BE:
if (sd->gspca_dev.width == 320)
interlaced = 1;
@@ -3377,7 +3424,7 @@ static int ov518_mode_init_regs(struct sd *sd)
if (sd->bridge == BRIDGE_OV518PLUS) {
switch (sd->sensor) {
- case SEN_OV7620:
+ case SEN_OV7620AE:
if (sd->gspca_dev.width == 320) {
reg_w(sd, 0x20, 0x00);
reg_w(sd, 0x21, 0x19);
@@ -3386,6 +3433,10 @@ static int ov518_mode_init_regs(struct sd *sd)
reg_w(sd, 0x21, 0x1f);
}
break;
+ case SEN_OV7620:
+ reg_w(sd, 0x20, 0x00);
+ reg_w(sd, 0x21, 0x19);
+ break;
default:
reg_w(sd, 0x21, 0x19);
}
@@ -3488,7 +3539,8 @@ static int ov519_mode_init_regs(struct sd *sd)
if (write_regvals(sd, mode_init_519,
ARRAY_SIZE(mode_init_519)))
return -EIO;
- if (sd->sensor == SEN_OV7640) {
+ if (sd->sensor == SEN_OV7640 ||
+ sd->sensor == SEN_OV7648) {
/* Select 8-bit input mode */
reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10);
}
@@ -3503,6 +3555,9 @@ static int ov519_mode_init_regs(struct sd *sd)
if (sd->sensor == SEN_OV7670 &&
sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv)
reg_w(sd, OV519_R12_X_OFFSETL, 0x04);
+ else if (sd->sensor == SEN_OV7648 &&
+ sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv)
+ reg_w(sd, OV519_R12_X_OFFSETL, 0x01);
else
reg_w(sd, OV519_R12_X_OFFSETL, 0x00);
reg_w(sd, OV519_R13_X_OFFSETH, 0x00);
@@ -3520,6 +3575,7 @@ static int ov519_mode_init_regs(struct sd *sd)
sd->clockdiv = 0;
switch (sd->sensor) {
case SEN_OV7640:
+ case SEN_OV7648:
switch (sd->frame_rate) {
default:
/* case 30: */
@@ -3649,6 +3705,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
break;
case SEN_OV7620:
+ case SEN_OV7620AE:
case SEN_OV76BE:
i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
@@ -3663,13 +3720,16 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e);
break;
case SEN_OV7640:
+ case SEN_OV7648:
i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
-/* i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); */
-/* i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); */
-/* i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); */
-/* i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); */
-/* i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); */
+ /* Setting this undocumented bit in qvga mode removes a very
+ annoying vertical shaking of the image */
+ i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
+ /* Unknown */
+ i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
+ /* Allow higher automatic gain (to allow higher framerates) */
+ i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
i2c_w_mask(sd, 0x12, 0x04, 0x04); /* AWB: 1 */
break;
case SEN_OV7670:
@@ -3795,11 +3855,13 @@ static int set_ov_sensor_window(struct sd *sd)
}
break;
case SEN_OV7620:
+ case SEN_OV7620AE:
hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */
hwebase = 0x2f;
vwsbase = vwebase = 0x05;
break;
case SEN_OV7640:
+ case SEN_OV7648:
hwsbase = 0x1a;
hwebase = 0x1a;
vwsbase = vwebase = 0x03;
@@ -3893,6 +3955,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
setautobrightness(sd);
setfreq(sd);
+ /* Force clear snapshot state in case the snapshot button was
+ pressed while we weren't streaming */
+ sd->snapshot_needs_reset = 1;
+ sd_reset_snapshot(gspca_dev);
+ sd->snapshot_pressed = 0;
+
ret = ov51x_restart(sd);
if (ret < 0)
goto out;
@@ -3919,6 +3987,34 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
w9968cf_stop0(sd);
}
+static void ov51x_handle_button(struct gspca_dev *gspca_dev, u8 state)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->snapshot_pressed != state) {
+#ifdef CONFIG_INPUT
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, state);
+ input_sync(gspca_dev->input_dev);
+#endif
+ if (state)
+ sd->snapshot_needs_reset = 1;
+
+ sd->snapshot_pressed = state;
+ } else {
+ /* On the ov511 / ov519 we need to reset the button state
+ multiple times, as resetting does not work as long as the
+ button stays pressed */
+ switch (sd->bridge) {
+ case BRIDGE_OV511:
+ case BRIDGE_OV511PLUS:
+ case BRIDGE_OV519:
+ if (state)
+ sd->snapshot_needs_reset = 1;
+ break;
+ }
+ }
+}
+
static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
u8 *in, /* isoc packet */
int len) /* iso packet length */
@@ -3940,6 +4036,7 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
*/
if (!(in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) &&
(in[8] & 0x08)) {
+ ov51x_handle_button(gspca_dev, (in[8] >> 2) & 1);
if (in[8] & 0x80) {
/* Frame end */
if ((in[9] + 1) * 8 != gspca_dev->width ||
@@ -3977,6 +4074,7 @@ static void ov518_pkt_scan(struct gspca_dev *gspca_dev,
/* A false positive here is likely, until OVT gives me
* the definitive SOF/EOF format */
if ((!(data[0] | data[1] | data[2] | data[3] | data[5])) && data[6]) {
+ ov51x_handle_button(gspca_dev, (data[6] >> 1) & 1);
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
sd->packet_nr = 0;
@@ -4024,6 +4122,9 @@ static void ov519_pkt_scan(struct gspca_dev *gspca_dev,
if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) {
switch (data[3]) {
case 0x50: /* start of frame */
+ /* Don't check the button state here, as the state
+ usually (always ?) changes at EOF and checking it
+ here leads to unnecessary snapshot state resets. */
#define HDRSZ 16
data += HDRSZ;
len -= HDRSZ;
@@ -4035,6 +4136,7 @@ static void ov519_pkt_scan(struct gspca_dev *gspca_dev,
gspca_dev->last_packet_type = DISCARD_PACKET;
return;
case 0x51: /* end of frame */
+ ov51x_handle_button(gspca_dev, data[11] & 1);
if (data[9] != 0)
gspca_dev->last_packet_type = DISCARD_PACKET;
gspca_frame_add(gspca_dev, LAST_PACKET,
@@ -4103,9 +4205,11 @@ static void setbrightness(struct gspca_dev *gspca_dev)
case SEN_OV6630:
case SEN_OV66308AF:
case SEN_OV7640:
+ case SEN_OV7648:
i2c_w(sd, OV7610_REG_BRT, val);
break;
case SEN_OV7620:
+ case SEN_OV7620AE:
/* 7620 doesn't like manual changes when in auto mode */
if (!sd->autobrightness)
i2c_w(sd, OV7610_REG_BRT, val);
@@ -4142,7 +4246,8 @@ static void setcontrast(struct gspca_dev *gspca_dev)
i2c_w(sd, 0x64, ctab[val >> 5]);
break;
}
- case SEN_OV7620: {
+ case SEN_OV7620:
+ case SEN_OV7620AE: {
static const __u8 ctab[] = {
0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
@@ -4152,10 +4257,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
i2c_w(sd, 0x64, ctab[val >> 4]);
break;
}
- case SEN_OV7640:
- /* Use gain control instead. */
- i2c_w(sd, OV7610_REG_GAIN, val >> 2);
- break;
case SEN_OV7670:
/* check that this isn't just the same as ov7610 */
i2c_w(sd, OV7670_REG_CONTRAS, val >> 1);
@@ -4179,6 +4280,7 @@ static void setcolors(struct gspca_dev *gspca_dev)
i2c_w(sd, OV7610_REG_SAT, val);
break;
case SEN_OV7620:
+ case SEN_OV7620AE:
/* Use UV gamma control instead. Bits 0 & 7 are reserved. */
/* rc = ov_i2c_write(sd->dev, 0x62, (val >> 9) & 0x7e);
if (rc < 0)
@@ -4186,6 +4288,7 @@ static void setcolors(struct gspca_dev *gspca_dev)
i2c_w(sd, OV7610_REG_SAT, val);
break;
case SEN_OV7640:
+ case SEN_OV7648:
i2c_w(sd, OV7610_REG_SAT, val & 0xf0);
break;
case SEN_OV7670:
@@ -4198,7 +4301,8 @@ static void setcolors(struct gspca_dev *gspca_dev)
static void setautobrightness(struct sd *sd)
{
- if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670 ||
+ if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7648 ||
+ sd->sensor == SEN_OV7670 ||
sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
return;
@@ -4475,9 +4579,13 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
+ .dq_callback = sd_reset_snapshot,
.querymenu = sd_querymenu,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
+#ifdef CONFIG_INPUT
+ .other_input = 1,
+#endif
};
/* -- module initialisation -- */
@@ -4494,7 +4602,8 @@ static const __devinitdata struct usb_device_id device_table[] = {
.driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
{USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 },
- {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x054c, 0x0155),
+ .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
{USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 },
{USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 },
{USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 },
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index 4dbb882c83dc..957e05e2d08f 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -1,5 +1,5 @@
/*
- * ov534 gspca driver
+ * ov534-ov772x gspca driver
*
* Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it>
* Copyright (C) 2008 Jim Paris <jim@jtan.com>
@@ -68,12 +68,7 @@ struct sd {
s8 sharpness;
u8 hflip;
u8 vflip;
- u8 satur;
- u8 lightfreq;
- u8 sensor;
-#define SENSOR_OV772X 0
-#define SENSOR_OV965X 1
};
/* V4L2 controls supported by the driver */
@@ -101,12 +96,8 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls_ov772x[] = {
+static const struct ctrl sd_ctrls[] = {
{ /* 0 */
{
.id = V4L2_CID_BRIGHTNESS,
@@ -115,8 +106,8 @@ static struct ctrl sd_ctrls_ov772x[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define BRIGHTNESS_77_DEF 20
- .default_value = BRIGHTNESS_77_DEF,
+#define BRIGHTNESS_DEF 20
+ .default_value = BRIGHTNESS_DEF,
},
.set = sd_setbrightness,
.get = sd_getbrightness,
@@ -129,8 +120,8 @@ static struct ctrl sd_ctrls_ov772x[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define CONTRAST_77_DEF 37
- .default_value = CONTRAST_77_DEF,
+#define CONTRAST_DEF 37
+ .default_value = CONTRAST_DEF,
},
.set = sd_setcontrast,
.get = sd_getcontrast,
@@ -157,8 +148,8 @@ static struct ctrl sd_ctrls_ov772x[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define EXPO_77_DEF 120
- .default_value = EXPO_77_DEF,
+#define EXPO_DEF 120
+ .default_value = EXPO_DEF,
},
.set = sd_setexposure,
.get = sd_getexposure,
@@ -213,13 +204,13 @@ static struct ctrl sd_ctrls_ov772x[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define AUTOGAIN_77_DEF 0
- .default_value = AUTOGAIN_77_DEF,
+#define AUTOGAIN_DEF 0
+ .default_value = AUTOGAIN_DEF,
},
.set = sd_setautogain,
.get = sd_getautogain,
},
-#define AWB_77_IDX 8
+#define AWB_IDX 8
{ /* 8 */
{
.id = V4L2_CID_AUTO_WHITE_BALANCE,
@@ -242,8 +233,8 @@ static struct ctrl sd_ctrls_ov772x[] = {
.minimum = 0,
.maximum = 63,
.step = 1,
-#define SHARPNESS_77_DEF 0
- .default_value = SHARPNESS_77_DEF,
+#define SHARPNESS_DEF 0
+ .default_value = SHARPNESS_DEF,
},
.set = sd_setsharpness,
.get = sd_getsharpness,
@@ -277,107 +268,6 @@ static struct ctrl sd_ctrls_ov772x[] = {
.get = sd_getvflip,
},
};
-static struct ctrl sd_ctrls_ov965x[] = {
- { /* 0 */
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 15,
- .step = 1,
-#define BRIGHTNESS_96_DEF 7
- .default_value = BRIGHTNESS_96_DEF,
- },
- .set = sd_setbrightness,
- .get = sd_getbrightness,
- },
- { /* 1 */
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 15,
- .step = 1,
-#define CONTRAST_96_DEF 3
- .default_value = CONTRAST_96_DEF,
- },
- .set = sd_setcontrast,
- .get = sd_getcontrast,
- },
- { /* 2 */
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Autogain",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
-#define AUTOGAIN_96_DEF 1
- .default_value = AUTOGAIN_96_DEF,
- },
- .set = sd_setautogain,
- .get = sd_getautogain,
- },
-#define EXPO_96_IDX 3
- { /* 3 */
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
-#define EXPO_96_DEF 0
- .default_value = EXPO_96_DEF,
- },
- .set = sd_setexposure,
- .get = sd_getexposure,
- },
- { /* 4 */
- {
- .id = V4L2_CID_SHARPNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Sharpness",
- .minimum = -1, /* -1 = auto */
- .maximum = 4,
- .step = 1,
-#define SHARPNESS_96_DEF -1
- .default_value = SHARPNESS_96_DEF,
- },
- .set = sd_setsharpness,
- .get = sd_getsharpness,
- },
- { /* 5 */
- {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 4,
- .step = 1,
-#define SATUR_DEF 2
- .default_value = SATUR_DEF,
- },
- .set = sd_setsatur,
- .get = sd_getsatur,
- },
- {
- {
- .id = V4L2_CID_POWER_LINE_FREQUENCY,
- .type = V4L2_CTRL_TYPE_MENU,
- .name = "Light frequency filter",
- .minimum = 0,
- .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
- .step = 1,
-#define FREQ_DEF 0
- .default_value = FREQ_DEF,
- },
- .set = sd_setfreq,
- .get = sd_getfreq,
- },
-};
static const struct v4l2_pix_format ov772x_mode[] = {
{320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
@@ -392,35 +282,21 @@ static const struct v4l2_pix_format ov772x_mode[] = {
.priv = 0},
};
-static const struct v4l2_pix_format ov965x_mode[] = {
- {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 320,
- .sizeimage = 320 * 240 * 3 / 8 + 590,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 4},
- {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 640,
- .sizeimage = 640 * 480 * 3 / 8 + 590,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 3},
- {800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 800,
- .sizeimage = 800 * 600 * 3 / 8 + 590,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 2},
- {1024, 768, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 1024,
- .sizeimage = 1024 * 768 * 3 / 8 + 590,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 1},
- {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 1280,
- .sizeimage = 1280 * 1024 * 3 / 8 + 590,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 0},
+static const u8 qvga_rates[] = {125, 100, 75, 60, 50, 40, 30};
+static const u8 vga_rates[] = {60, 50, 40, 30, 15};
+
+static const struct framerates ov772x_framerates[] = {
+ { /* 320x240 */
+ .rates = qvga_rates,
+ .nrates = ARRAY_SIZE(qvga_rates),
+ },
+ { /* 640x480 */
+ .rates = vga_rates,
+ .nrates = ARRAY_SIZE(vga_rates),
+ },
};
-static const u8 bridge_init_ov772x[][2] = {
+static const u8 bridge_init[][2] = {
{ 0xc2, 0x0c },
{ 0x88, 0xf8 },
{ 0xc3, 0x69 },
@@ -478,7 +354,7 @@ static const u8 bridge_init_ov772x[][2] = {
{ 0xc1, 0x3c },
{ 0xc2, 0x0c },
};
-static const u8 sensor_init_ov772x[][2] = {
+static const u8 sensor_init[][2] = {
{ 0x12, 0x80 },
{ 0x11, 0x01 },
/*fixme: better have a delay?*/
@@ -571,7 +447,7 @@ static const u8 sensor_init_ov772x[][2] = {
{ 0x8e, 0x00 }, /* De-noise threshold */
{ 0x0c, 0xd0 }
};
-static const u8 bridge_start_ov772x_vga[][2] = {
+static const u8 bridge_start_vga[][2] = {
{0x1c, 0x00},
{0x1d, 0x40},
{0x1d, 0x02},
@@ -582,7 +458,7 @@ static const u8 bridge_start_ov772x_vga[][2] = {
{0xc0, 0x50},
{0xc1, 0x3c},
};
-static const u8 sensor_start_ov772x_vga[][2] = {
+static const u8 sensor_start_vga[][2] = {
{0x12, 0x00},
{0x17, 0x26},
{0x18, 0xa0},
@@ -592,7 +468,7 @@ static const u8 sensor_start_ov772x_vga[][2] = {
{0x2c, 0xf0},
{0x65, 0x20},
};
-static const u8 bridge_start_ov772x_qvga[][2] = {
+static const u8 bridge_start_qvga[][2] = {
{0x1c, 0x00},
{0x1d, 0x40},
{0x1d, 0x02},
@@ -603,7 +479,7 @@ static const u8 bridge_start_ov772x_qvga[][2] = {
{0xc0, 0x28},
{0xc1, 0x1e},
};
-static const u8 sensor_start_ov772x_qvga[][2] = {
+static const u8 sensor_start_qvga[][2] = {
{0x12, 0x40},
{0x17, 0x3f},
{0x18, 0x50},
@@ -614,571 +490,6 @@ static const u8 sensor_start_ov772x_qvga[][2] = {
{0x65, 0x2f},
};
-static const u8 bridge_init_ov965x[][2] = {
- {0x88, 0xf8},
- {0x89, 0xff},
- {0x76, 0x03},
- {0x92, 0x03},
- {0x95, 0x10},
- {0xe2, 0x00},
- {0xe7, 0x3e},
- {0x8d, 0x1c},
- {0x8e, 0x00},
- {0x8f, 0x00},
- {0x1f, 0x00},
- {0xc3, 0xf9},
- {0x89, 0xff},
- {0x88, 0xf8},
- {0x76, 0x03},
- {0x92, 0x01},
- {0x93, 0x18},
- {0x1c, 0x0a},
- {0x1d, 0x48},
- {0xc0, 0x50},
- {0xc1, 0x3c},
- {0x34, 0x05},
- {0xc2, 0x0c},
- {0xc3, 0xf9},
- {0x34, 0x05},
- {0xe7, 0x2e},
- {0x31, 0xf9},
- {0x35, 0x02},
- {0xd9, 0x10},
- {0x25, 0x42},
- {0x94, 0x11},
-};
-
-static const u8 sensor_init_ov965x[][2] = {
- {0x12, 0x80}, /* com7 - SSCB reset */
- {0x00, 0x00}, /* gain */
- {0x01, 0x80}, /* blue */
- {0x02, 0x80}, /* red */
- {0x03, 0x1b}, /* vref */
- {0x04, 0x03}, /* com1 - exposure low bits */
- {0x0b, 0x57}, /* ver */
- {0x0e, 0x61}, /* com5 */
- {0x0f, 0x42}, /* com6 */
- {0x11, 0x00}, /* clkrc */
- {0x12, 0x02}, /* com7 - 15fps VGA YUYV */
- {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
- {0x14, 0x28}, /* com9 */
- {0x16, 0x24}, /* reg16 */
- {0x17, 0x1d}, /* hstart*/
- {0x18, 0xbd}, /* hstop */
- {0x19, 0x01}, /* vstrt */
- {0x1a, 0x81}, /* vstop*/
- {0x1e, 0x04}, /* mvfp */
- {0x24, 0x3c}, /* aew */
- {0x25, 0x36}, /* aeb */
- {0x26, 0x71}, /* vpt */
- {0x27, 0x08}, /* bbias */
- {0x28, 0x08}, /* gbbias */
- {0x29, 0x15}, /* gr com */
- {0x2a, 0x00}, /* exhch */
- {0x2b, 0x00}, /* exhcl */
- {0x2c, 0x08}, /* rbias */
- {0x32, 0xff}, /* href */
- {0x33, 0x00}, /* chlf */
- {0x34, 0x3f}, /* aref1 */
- {0x35, 0x00}, /* aref2 */
- {0x36, 0xf8}, /* aref3 */
- {0x38, 0x72}, /* adc2 */
- {0x39, 0x57}, /* aref4 */
- {0x3a, 0x80}, /* tslb - yuyv */
- {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */
- {0x3d, 0x99}, /* com13 */
- {0x3f, 0xc1}, /* edge */
- {0x40, 0xc0}, /* com15 */
- {0x41, 0x40}, /* com16 */
- {0x42, 0xc0}, /* com17 */
- {0x43, 0x0a}, /* rsvd */
- {0x44, 0xf0},
- {0x45, 0x46},
- {0x46, 0x62},
- {0x47, 0x2a},
- {0x48, 0x3c},
- {0x4a, 0xfc},
- {0x4b, 0xfc},
- {0x4c, 0x7f},
- {0x4d, 0x7f},
- {0x4e, 0x7f},
- {0x4f, 0x98}, /* matrix */
- {0x50, 0x98},
- {0x51, 0x00},
- {0x52, 0x28},
- {0x53, 0x70},
- {0x54, 0x98},
- {0x58, 0x1a}, /* matrix coef sign */
- {0x59, 0x85}, /* AWB control */
- {0x5a, 0xa9},
- {0x5b, 0x64},
- {0x5c, 0x84},
- {0x5d, 0x53},
- {0x5e, 0x0e},
- {0x5f, 0xf0}, /* AWB blue limit */
- {0x60, 0xf0}, /* AWB red limit */
- {0x61, 0xf0}, /* AWB green limit */
- {0x62, 0x00}, /* lcc1 */
- {0x63, 0x00}, /* lcc2 */
- {0x64, 0x02}, /* lcc3 */
- {0x65, 0x16}, /* lcc4 */
- {0x66, 0x01}, /* lcc5 */
- {0x69, 0x02}, /* hv */
- {0x6b, 0x5a}, /* dbvl */
- {0x6c, 0x04},
- {0x6d, 0x55},
- {0x6e, 0x00},
- {0x6f, 0x9d},
- {0x70, 0x21}, /* dnsth */
- {0x71, 0x78},
- {0x72, 0x00}, /* poidx */
- {0x73, 0x01}, /* pckdv */
- {0x74, 0x3a}, /* xindx */
- {0x75, 0x35}, /* yindx */
- {0x76, 0x01},
- {0x77, 0x02},
- {0x7a, 0x12}, /* gamma curve */
- {0x7b, 0x08},
- {0x7c, 0x16},
- {0x7d, 0x30},
- {0x7e, 0x5e},
- {0x7f, 0x72},
- {0x80, 0x82},
- {0x81, 0x8e},
- {0x82, 0x9a},
- {0x83, 0xa4},
- {0x84, 0xac},
- {0x85, 0xb8},
- {0x86, 0xc3},
- {0x87, 0xd6},
- {0x88, 0xe6},
- {0x89, 0xf2},
- {0x8a, 0x03},
- {0x8c, 0x89}, /* com19 */
- {0x14, 0x28}, /* com9 */
- {0x90, 0x7d},
- {0x91, 0x7b},
- {0x9d, 0x03}, /* lcc6 */
- {0x9e, 0x04}, /* lcc7 */
- {0x9f, 0x7a},
- {0xa0, 0x79},
- {0xa1, 0x40}, /* aechm */
- {0xa4, 0x50}, /* com21 */
- {0xa5, 0x68}, /* com26 */
- {0xa6, 0x4a}, /* AWB green */
- {0xa8, 0xc1}, /* refa8 */
- {0xa9, 0xef}, /* refa9 */
- {0xaa, 0x92},
- {0xab, 0x04},
- {0xac, 0x80}, /* black level control */
- {0xad, 0x80},
- {0xae, 0x80},
- {0xaf, 0x80},
- {0xb2, 0xf2},
- {0xb3, 0x20},
- {0xb4, 0x20}, /* ctrlb4 */
- {0xb5, 0x00},
- {0xb6, 0xaf},
- {0xbb, 0xae},
- {0xbc, 0x7f}, /* ADC channel offsets */
- {0xdb, 0x7f},
- {0xbe, 0x7f},
- {0xbf, 0x7f},
- {0xc0, 0xe2},
- {0xc1, 0xc0},
- {0xc2, 0x01},
- {0xc3, 0x4e},
- {0xc6, 0x85},
- {0xc7, 0x80}, /* com24 */
- {0xc9, 0xe0},
- {0xca, 0xe8},
- {0xcb, 0xf0},
- {0xcc, 0xd8},
- {0xcd, 0xf1},
- {0x4f, 0x98}, /* matrix */
- {0x50, 0x98},
- {0x51, 0x00},
- {0x52, 0x28},
- {0x53, 0x70},
- {0x54, 0x98},
- {0x58, 0x1a},
- {0xff, 0x41}, /* read 41, write ff 00 */
- {0x41, 0x40}, /* com16 */
-
- {0xc5, 0x03}, /* 60 Hz banding filter */
- {0x6a, 0x02}, /* 50 Hz banding filter */
-
- {0x12, 0x62}, /* com7 - 30fps VGA YUV */
- {0x36, 0xfa}, /* aref3 */
- {0x69, 0x0a}, /* hv */
- {0x8c, 0x89}, /* com22 */
- {0x14, 0x28}, /* com9 */
- {0x3e, 0x0c},
- {0x41, 0x40}, /* com16 */
- {0x72, 0x00},
- {0x73, 0x00},
- {0x74, 0x3a},
- {0x75, 0x35},
- {0x76, 0x01},
- {0xc7, 0x80},
- {0x03, 0x12}, /* vref */
- {0x17, 0x16}, /* hstart */
- {0x18, 0x02}, /* hstop */
- {0x19, 0x01}, /* vstrt */
- {0x1a, 0x3d}, /* vstop */
- {0x32, 0xff}, /* href */
- {0xc0, 0xaa},
-};
-
-static const u8 bridge_init_ov965x_2[][2] = {
- {0x94, 0xaa},
- {0xf1, 0x60},
- {0xe5, 0x04},
- {0xc0, 0x50},
- {0xc1, 0x3c},
- {0x8c, 0x00},
- {0x8d, 0x1c},
- {0x34, 0x05},
-
- {0xc2, 0x0c},
- {0xc3, 0xf9},
- {0xda, 0x01},
- {0x50, 0x00},
- {0x51, 0xa0},
- {0x52, 0x3c},
- {0x53, 0x00},
- {0x54, 0x00},
- {0x55, 0x00},
- {0x57, 0x00},
- {0x5c, 0x00},
- {0x5a, 0xa0},
- {0x5b, 0x78},
- {0x35, 0x02},
- {0xd9, 0x10},
- {0x94, 0x11},
-};
-
-static const u8 sensor_init_ov965x_2[][2] = {
- {0x3b, 0xc4},
- {0x1e, 0x04}, /* mvfp */
- {0x13, 0xe0}, /* com8 */
- {0x00, 0x00}, /* gain */
- {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
- {0x11, 0x03}, /* clkrc */
- {0x6b, 0x5a}, /* dblv */
- {0x6a, 0x05},
- {0xc5, 0x07},
- {0xa2, 0x4b},
- {0xa3, 0x3e},
- {0x2d, 0x00},
- {0xff, 0x42}, /* read 42, write ff 00 */
- {0x42, 0xc0}, /* com17 */
- {0x2d, 0x00},
- {0xff, 0x42}, /* read 42, write ff 00 */
- {0x42, 0xc1}, /* com17 */
-/* sharpness */
- {0x3f, 0x01},
- {0xff, 0x42}, /* read 42, write ff 00 */
- {0x42, 0xc1}, /* com17 */
-/* saturation */
- {0x4f, 0x98}, /* matrix */
- {0x50, 0x98},
- {0x51, 0x00},
- {0x52, 0x28},
- {0x53, 0x70},
- {0x54, 0x98},
- {0x58, 0x1a},
- {0xff, 0x41}, /* read 41, write ff 00 */
- {0x41, 0x40}, /* com16 */
-/* contrast */
- {0x56, 0x40},
-/* brightness */
- {0x55, 0x8f},
-/* expo */
- {0x10, 0x25}, /* aech - exposure high bits */
- {0xff, 0x13}, /* read 13, write ff 00 */
- {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
-};
-
-static const u8 sensor_start_ov965x_1_vga[][2] = { /* same for qvga */
- {0x12, 0x62}, /* com7 - 30fps VGA YUV */
- {0x36, 0xfa}, /* aref3 */
- {0x69, 0x0a}, /* hv */
- {0x8c, 0x89}, /* com22 */
- {0x14, 0x28}, /* com9 */
- {0x3e, 0x0c}, /* com14 */
- {0x41, 0x40}, /* com16 */
- {0x72, 0x00},
- {0x73, 0x00},
- {0x74, 0x3a},
- {0x75, 0x35},
- {0x76, 0x01},
- {0xc7, 0x80}, /* com24 */
- {0x03, 0x12}, /* vref */
- {0x17, 0x16}, /* hstart */
- {0x18, 0x02}, /* hstop */
- {0x19, 0x01}, /* vstrt */
- {0x1a, 0x3d}, /* vstop */
- {0x32, 0xff}, /* href */
- {0xc0, 0xaa},
-};
-
-static const u8 sensor_start_ov965x_1_svga[][2] = {
- {0x12, 0x02}, /* com7 - YUYV - VGA 15 full resolution */
- {0x36, 0xf8}, /* aref3 */
- {0x69, 0x02}, /* hv */
- {0x8c, 0x0d}, /* com22 */
- {0x3e, 0x0c}, /* com14 */
- {0x41, 0x40}, /* com16 */
- {0x72, 0x00},
- {0x73, 0x01},
- {0x74, 0x3a},
- {0x75, 0x35},
- {0x76, 0x01},
- {0xc7, 0x80}, /* com24 */
- {0x03, 0x1b}, /* vref */
- {0x17, 0x1d}, /* hstart */
- {0x18, 0xbd}, /* hstop */
- {0x19, 0x01}, /* vstrt */
- {0x1a, 0x81}, /* vstop */
- {0x32, 0xff}, /* href */
- {0xc0, 0xe2},
-};
-
-static const u8 sensor_start_ov965x_1_xga[][2] = {
- {0x12, 0x02}, /* com7 */
- {0x36, 0xf8}, /* aref3 */
- {0x69, 0x02}, /* hv */
- {0x8c, 0x89}, /* com22 */
- {0x14, 0x28}, /* com9 */
- {0x3e, 0x0c}, /* com14 */
- {0x41, 0x40}, /* com16 */
- {0x72, 0x00},
- {0x73, 0x01},
- {0x74, 0x3a},
- {0x75, 0x35},
- {0x76, 0x01},
- {0xc7, 0x80}, /* com24 */
- {0x03, 0x1b}, /* vref */
- {0x17, 0x1d}, /* hstart */
- {0x18, 0xbd}, /* hstop */
- {0x19, 0x01}, /* vstrt */
- {0x1a, 0x81}, /* vstop */
- {0x32, 0xff}, /* href */
- {0xc0, 0xe2},
-};
-
-static const u8 sensor_start_ov965x_1_sxga[][2] = {
- {0x12, 0x02}, /* com7 */
- {0x36, 0xf8}, /* aref3 */
- {0x69, 0x02}, /* hv */
- {0x8c, 0x89}, /* com22 */
- {0x14, 0x28}, /* com9 */
- {0x3e, 0x0c}, /* com14 */
- {0x41, 0x40}, /* com16 */
- {0x72, 0x00},
- {0x73, 0x01},
- {0x74, 0x3a},
- {0x75, 0x35},
- {0x76, 0x01},
- {0xc7, 0x80}, /* com24 */
- {0x03, 0x1b}, /* vref */
- {0x17, 0x1d}, /* hstart */
- {0x18, 0x02}, /* hstop */
- {0x19, 0x01}, /* vstrt */
- {0x1a, 0x81}, /* vstop */
- {0x32, 0xff}, /* href */
- {0xc0, 0xe2},
-};
-
-static const u8 bridge_start_ov965x_qvga[][2] = {
- {0x94, 0xaa},
- {0xf1, 0x60},
- {0xe5, 0x04},
- {0xc0, 0x50},
- {0xc1, 0x3c},
- {0x8c, 0x00},
- {0x8d, 0x1c},
- {0x34, 0x05},
-
- {0xc2, 0x4c},
- {0xc3, 0xf9},
- {0xda, 0x00},
- {0x50, 0x00},
- {0x51, 0xa0},
- {0x52, 0x78},
- {0x53, 0x00},
- {0x54, 0x00},
- {0x55, 0x00},
- {0x57, 0x00},
- {0x5c, 0x00},
- {0x5a, 0x50},
- {0x5b, 0x3c},
- {0x35, 0x02},
- {0xd9, 0x10},
- {0x94, 0x11},
-};
-
-static const u8 bridge_start_ov965x_vga[][2] = {
- {0x94, 0xaa},
- {0xf1, 0x60},
- {0xe5, 0x04},
- {0xc0, 0x50},
- {0xc1, 0x3c},
- {0x8c, 0x00},
- {0x8d, 0x1c},
- {0x34, 0x05},
- {0xc2, 0x0c},
- {0xc3, 0xf9},
- {0xda, 0x01},
- {0x50, 0x00},
- {0x51, 0xa0},
- {0x52, 0x3c},
- {0x53, 0x00},
- {0x54, 0x00},
- {0x55, 0x00},
- {0x57, 0x00},
- {0x5c, 0x00},
- {0x5a, 0xa0},
- {0x5b, 0x78},
- {0x35, 0x02},
- {0xd9, 0x10},
- {0x94, 0x11},
-};
-
-static const u8 bridge_start_ov965x_svga[][2] = {
- {0x94, 0xaa},
- {0xf1, 0x60},
- {0xe5, 0x04},
- {0xc0, 0xa0},
- {0xc1, 0x80},
- {0x8c, 0x00},
- {0x8d, 0x1c},
- {0x34, 0x05},
- {0xc2, 0x4c},
- {0xc3, 0xf9},
- {0x50, 0x00},
- {0x51, 0x40},
- {0x52, 0x00},
- {0x53, 0x00},
- {0x54, 0x00},
- {0x55, 0x88},
- {0x57, 0x00},
- {0x5c, 0x00},
- {0x5a, 0xc8},
- {0x5b, 0x96},
- {0x35, 0x02},
- {0xd9, 0x10},
- {0xda, 0x00},
- {0x94, 0x11},
-};
-
-static const u8 bridge_start_ov965x_xga[][2] = {
- {0x94, 0xaa},
- {0xf1, 0x60},
- {0xe5, 0x04},
- {0xc0, 0xa0},
- {0xc1, 0x80},
- {0x8c, 0x00},
- {0x8d, 0x1c},
- {0x34, 0x05},
- {0xc2, 0x4c},
- {0xc3, 0xf9},
- {0x50, 0x00},
- {0x51, 0x40},
- {0x52, 0x00},
- {0x53, 0x00},
- {0x54, 0x00},
- {0x55, 0x88},
- {0x57, 0x00},
- {0x5c, 0x01},
- {0x5a, 0x00},
- {0x5b, 0xc0},
- {0x35, 0x02},
- {0xd9, 0x10},
- {0xda, 0x01},
- {0x94, 0x11},
-};
-
-static const u8 bridge_start_ov965x_sxga[][2] = {
- {0x94, 0xaa},
- {0xf1, 0x60},
- {0xe5, 0x04},
- {0xc0, 0xa0},
- {0xc1, 0x80},
- {0x8c, 0x00},
- {0x8d, 0x1c},
- {0x34, 0x05},
- {0xc2, 0x0c},
- {0xc3, 0xf9},
- {0xda, 0x00},
- {0x35, 0x02},
- {0xd9, 0x10},
- {0x94, 0x11},
-};
-
-static const u8 sensor_start_ov965x_2_qvga[][2] = {
- {0x3b, 0xe4}, /* com11 - night mode 1/4 frame rate */
- {0x1e, 0x04}, /* mvfp */
- {0x13, 0xe0}, /* com8 */
- {0x00, 0x00},
- {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
- {0x11, 0x01}, /* clkrc */
- {0x6b, 0x5a}, /* dblv */
- {0x6a, 0x02}, /* 50 Hz banding filter */
- {0xc5, 0x03}, /* 60 Hz banding filter */
- {0xa2, 0x96}, /* bd50 */
- {0xa3, 0x7d}, /* bd60 */
-
- {0xff, 0x13}, /* read 13, write ff 00 */
- {0x13, 0xe7},
- {0x3a, 0x80}, /* tslb - yuyv */
-};
-
-static const u8 sensor_start_ov965x_2_vga[][2] = {
- {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */
- {0x1e, 0x04}, /* mvfp */
- {0x13, 0xe0}, /* com8 */
- {0x00, 0x00},
- {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
- {0x11, 0x03}, /* clkrc */
- {0x6b, 0x5a}, /* dblv */
- {0x6a, 0x05}, /* 50 Hz banding filter */
- {0xc5, 0x07}, /* 60 Hz banding filter */
- {0xa2, 0x4b}, /* bd50 */
- {0xa3, 0x3e}, /* bd60 */
-
- {0x2d, 0x00}, /* advfl */
-};
-
-static const u8 sensor_start_ov965x_2_svga[][2] = { /* same for xga */
- {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */
- {0x1e, 0x04}, /* mvfp */
- {0x13, 0xe0}, /* com8 */
- {0x00, 0x00},
- {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
- {0x11, 0x01}, /* clkrc */
- {0x6b, 0x5a}, /* dblv */
- {0x6a, 0x0c}, /* 50 Hz banding filter */
- {0xc5, 0x0f}, /* 60 Hz banding filter */
- {0xa2, 0x4e}, /* bd50 */
- {0xa3, 0x41}, /* bd60 */
-};
-
-static const u8 sensor_start_ov965x_2_sxga[][2] = {
- {0x13, 0xe0}, /* com8 */
- {0x00, 0x00},
- {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
- {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */
- {0x1e, 0x04}, /* mvfp */
- {0x11, 0x01}, /* clkrc */
- {0x6b, 0x5a}, /* dblv */
- {0x6a, 0x0c}, /* 50 Hz banding filter */
- {0xc5, 0x0f}, /* 60 Hz banding filter */
- {0xa2, 0x4e}, /* bd50 */
- {0xa3, 0x41}, /* bd60 */
-};
-
static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
{
struct usb_device *udev = gspca_dev->dev;
@@ -1360,14 +671,14 @@ static void set_frame_rate(struct gspca_dev *gspca_dev)
PDEBUG(D_PROBE, "frame_rate: %d", r->fps);
}
-static void setbrightness_77(struct gspca_dev *gspca_dev)
+static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
sccb_reg_write(gspca_dev, 0x9B, sd->brightness);
}
-static void setcontrast_77(struct gspca_dev *gspca_dev)
+static void setcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1401,7 +712,7 @@ static void setgain(struct gspca_dev *gspca_dev)
sccb_reg_write(gspca_dev, 0x00, val);
}
-static void setexposure_77(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 val;
@@ -1432,7 +743,7 @@ static void sethue(struct gspca_dev *gspca_dev)
sccb_reg_write(gspca_dev, 0x01, sd->hue);
}
-static void setautogain_77(struct gspca_dev *gspca_dev)
+static void setautogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1457,7 +768,7 @@ static void setawb(struct gspca_dev *gspca_dev)
sccb_reg_write(gspca_dev, 0x63, 0xaa); /* AWB off */
}
-static void setsharpness_77(struct gspca_dev *gspca_dev)
+static void setsharpness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 val;
@@ -1491,132 +802,6 @@ static void setvflip(struct gspca_dev *gspca_dev)
sccb_reg_read(gspca_dev, 0x0c) & 0x7f);
}
-/* ov965x specific controls */
-static void setbrightness_96(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 val;
-
- val = sd->brightness;
- if (val < 8)
- val = 15 - val; /* f .. 8 */
- else
- val = val - 8; /* 0 .. 7 */
- sccb_reg_write(gspca_dev, 0x55, /* brtn - brightness adjustment */
- 0x0f | (val << 4));
-}
-
-static void setcontrast_96(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sccb_reg_write(gspca_dev, 0x56, /* cnst1 - contrast 1 ctrl coeff */
- sd->contrast << 4);
-}
-
-static void setexposure_96(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 val;
- static const u8 expo[4] = {0x00, 0x25, 0x38, 0x5e};
-
- sccb_reg_write(gspca_dev, 0x10, /* aec[9:2] */
- expo[sd->exposure]);
- val = sccb_reg_read(gspca_dev, 0x13); /* com8 */
- sccb_reg_write(gspca_dev, 0xff, 0x00);
- sccb_reg_write(gspca_dev, 0x13, val);
- val = sccb_reg_read(gspca_dev, 0xa1); /* aech */
- sccb_reg_write(gspca_dev, 0xff, 0x00);
- sccb_reg_write(gspca_dev, 0xa1, val & 0xe0); /* aec[15:10] = 0 */
-}
-
-static void setsharpness_96(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 val;
-
- val = sd->sharpness;
- if (val < 0) { /* auto */
- val = sccb_reg_read(gspca_dev, 0x42); /* com17 */
- sccb_reg_write(gspca_dev, 0xff, 0x00);
- sccb_reg_write(gspca_dev, 0x42, val | 0x40);
- /* Edge enhancement strength auto adjust */
- return;
- }
- if (val != 0)
- val = 1 << (val - 1);
- sccb_reg_write(gspca_dev, 0x3f, /* edge - edge enhance. factor */
- val);
- val = sccb_reg_read(gspca_dev, 0x42); /* com17 */
- sccb_reg_write(gspca_dev, 0xff, 0x00);
- sccb_reg_write(gspca_dev, 0x42, val & 0xbf);
-}
-
-static void setautogain_96(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 val;
-
-/*fixme: should adjust agc/awb/aec by different controls */
- val = sd->autogain;
- val = sccb_reg_read(gspca_dev, 0x13); /* com8 */
- sccb_reg_write(gspca_dev, 0xff, 0x00);
- if (sd->autogain)
- val |= 0x05; /* agc & aec */
- else
- val &= 0xfa;
- sccb_reg_write(gspca_dev, 0x13, val);
-}
-
-static void setsatur(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 val1, val2, val3;
- static const u8 matrix[5][2] = {
- {0x14, 0x38},
- {0x1e, 0x54},
- {0x28, 0x70},
- {0x32, 0x8c},
- {0x48, 0x90}
- };
-
- val1 = matrix[sd->satur][0];
- val2 = matrix[sd->satur][1];
- val3 = val1 + val2;
- sccb_reg_write(gspca_dev, 0x4f, val3); /* matrix coeff */
- sccb_reg_write(gspca_dev, 0x50, val3);
- sccb_reg_write(gspca_dev, 0x51, 0x00);
- sccb_reg_write(gspca_dev, 0x52, val1);
- sccb_reg_write(gspca_dev, 0x53, val2);
- sccb_reg_write(gspca_dev, 0x54, val3);
- sccb_reg_write(gspca_dev, 0x58, 0x1a); /* mtxs - coeff signs */
- val1 = sccb_reg_read(gspca_dev, 0x41); /* com16 */
- sccb_reg_write(gspca_dev, 0xff, 0x00);
- sccb_reg_write(gspca_dev, 0x41, val1);
-}
-
-static void setfreq(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 val;
-
- val = sccb_reg_read(gspca_dev, 0x13); /* com8 */
- sccb_reg_write(gspca_dev, 0xff, 0x00);
- if (sd->lightfreq == 0) {
- sccb_reg_write(gspca_dev, 0x13, val & 0xdf);
- return;
- }
- sccb_reg_write(gspca_dev, 0x13, val | 0x20);
-
- val = sccb_reg_read(gspca_dev, 0x42); /* com17 */
- sccb_reg_write(gspca_dev, 0xff, 0x00);
- if (sd->lightfreq == 1)
- val |= 0x01;
- else
- val &= 0xfe;
- sccb_reg_write(gspca_dev, 0x42, val);
-}
-
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
@@ -1624,77 +809,50 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
- sd->sensor = id->driver_info;
-
cam = &gspca_dev->cam;
- if (sd->sensor == SENSOR_OV772X) {
- cam->cam_mode = ov772x_mode;
- cam->nmodes = ARRAY_SIZE(ov772x_mode);
+ cam->cam_mode = ov772x_mode;
+ cam->nmodes = ARRAY_SIZE(ov772x_mode);
+ cam->mode_framerates = ov772x_framerates;
- cam->bulk = 1;
- cam->bulk_size = 16384;
- cam->bulk_nurbs = 2;
- } else { /* ov965x */
- cam->cam_mode = ov965x_mode;
- cam->nmodes = ARRAY_SIZE(ov965x_mode);
- }
+ cam->bulk = 1;
+ cam->bulk_size = 16384;
+ cam->bulk_nurbs = 2;
sd->frame_rate = 30;
- if (sd->sensor == SENSOR_OV772X) {
- sd->brightness = BRIGHTNESS_77_DEF;
- sd->contrast = CONTRAST_77_DEF;
- sd->gain = GAIN_DEF;
- sd->exposure = EXPO_77_DEF;
- sd->redblc = RED_BALANCE_DEF;
- sd->blueblc = BLUE_BALANCE_DEF;
- sd->hue = HUE_DEF;
-#if AUTOGAIN_77_DEF != 0
- sd->autogain = AUTOGAIN_77_DEF;
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->gain = GAIN_DEF;
+ sd->exposure = EXPO_DEF;
+ sd->redblc = RED_BALANCE_DEF;
+ sd->blueblc = BLUE_BALANCE_DEF;
+ sd->hue = HUE_DEF;
+#if AUTOGAIN_DEF != 0
+ sd->autogain = AUTOGAIN_DEF;
#else
- gspca_dev->ctrl_inac |= (1 << AWB_77_IDX);
+ gspca_dev->ctrl_inac |= (1 << AWB_IDX);
#endif
#if AWB_DEF != 0
- sd->awb = AWB_DEF
+ sd->awb = AWB_DEF
#endif
-#if SHARPNESS_77_DEF != 0
- sd->sharpness = SHARPNESS_77_DEF;
+#if SHARPNESS_DEF != 0
+ sd->sharpness = SHARPNESS_DEF;
#endif
#if HFLIP_DEF != 0
- sd->hflip = HFLIP_DEF;
+ sd->hflip = HFLIP_DEF;
#endif
#if VFLIP_DEF != 0
- sd->vflip = VFLIP_DEF;
-#endif
- } else {
- sd->brightness = BRIGHTNESS_96_DEF;
- sd->contrast = CONTRAST_96_DEF;
-#if AUTOGAIN_96_DEF != 0
- sd->autogain = AUTOGAIN_96_DEF;
- gspca_dev->ctrl_inac |= (1 << EXPO_96_IDX);
+ sd->vflip = VFLIP_DEF;
#endif
-#if EXPO_96_DEF != 0
- sd->exposure = EXPO_96_DEF;
-#endif
-#if SHARPNESS_96_DEF != 0
- sd->sharpness = SHARPNESS_96_DEF;
-#endif
- sd->satur = SATUR_DEF;
- sd->lightfreq = FREQ_DEF;
- }
+
return 0;
}
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
- struct sd *sd = (struct sd *) gspca_dev;
u16 sensor_id;
- static const u8 sensor_addr[2] = {
- 0x42, /* 0 SENSOR_OV772X */
- 0x60, /* 1 SENSOR_OV965X */
- };
/* reset bridge */
ov534_reg_write(gspca_dev, 0xe7, 0x3a);
@@ -1702,8 +860,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
msleep(100);
/* initialize the sensor address */
- ov534_reg_write(gspca_dev, OV534_REG_ADDRESS,
- sensor_addr[sd->sensor]);
+ ov534_reg_write(gspca_dev, OV534_REG_ADDRESS, 0x42);
/* reset sensor */
sccb_reg_write(gspca_dev, 0x12, 0x80);
@@ -1717,64 +874,46 @@ static int sd_init(struct gspca_dev *gspca_dev)
PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id);
/* initialize */
- switch (sd->sensor) {
- case SENSOR_OV772X:
- reg_w_array(gspca_dev, bridge_init_ov772x,
- ARRAY_SIZE(bridge_init_ov772x));
- ov534_set_led(gspca_dev, 1);
- sccb_w_array(gspca_dev, sensor_init_ov772x,
- ARRAY_SIZE(sensor_init_ov772x));
- ov534_reg_write(gspca_dev, 0xe0, 0x09);
- ov534_set_led(gspca_dev, 0);
- set_frame_rate(gspca_dev);
- break;
- default:
-/* case SENSOR_OV965X: */
- reg_w_array(gspca_dev, bridge_init_ov965x,
- ARRAY_SIZE(bridge_init_ov965x));
- sccb_w_array(gspca_dev, sensor_init_ov965x,
- ARRAY_SIZE(sensor_init_ov965x));
- reg_w_array(gspca_dev, bridge_init_ov965x_2,
- ARRAY_SIZE(bridge_init_ov965x_2));
- sccb_w_array(gspca_dev, sensor_init_ov965x_2,
- ARRAY_SIZE(sensor_init_ov965x_2));
- ov534_reg_write(gspca_dev, 0xe0, 0x00);
- ov534_reg_write(gspca_dev, 0xe0, 0x01);
- ov534_set_led(gspca_dev, 0);
- ov534_reg_write(gspca_dev, 0xe0, 0x00);
- }
+ reg_w_array(gspca_dev, bridge_init,
+ ARRAY_SIZE(bridge_init));
+ ov534_set_led(gspca_dev, 1);
+ sccb_w_array(gspca_dev, sensor_init,
+ ARRAY_SIZE(sensor_init));
+ ov534_reg_write(gspca_dev, 0xe0, 0x09);
+ ov534_set_led(gspca_dev, 0);
+ set_frame_rate(gspca_dev);
return 0;
}
-static int sd_start_ov772x(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
{
int mode;
mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
if (mode != 0) { /* 320x240 */
- reg_w_array(gspca_dev, bridge_start_ov772x_qvga,
- ARRAY_SIZE(bridge_start_ov772x_qvga));
- sccb_w_array(gspca_dev, sensor_start_ov772x_qvga,
- ARRAY_SIZE(sensor_start_ov772x_qvga));
+ reg_w_array(gspca_dev, bridge_start_qvga,
+ ARRAY_SIZE(bridge_start_qvga));
+ sccb_w_array(gspca_dev, sensor_start_qvga,
+ ARRAY_SIZE(sensor_start_qvga));
} else { /* 640x480 */
- reg_w_array(gspca_dev, bridge_start_ov772x_vga,
- ARRAY_SIZE(bridge_start_ov772x_vga));
- sccb_w_array(gspca_dev, sensor_start_ov772x_vga,
- ARRAY_SIZE(sensor_start_ov772x_vga));
+ reg_w_array(gspca_dev, bridge_start_vga,
+ ARRAY_SIZE(bridge_start_vga));
+ sccb_w_array(gspca_dev, sensor_start_vga,
+ ARRAY_SIZE(sensor_start_vga));
}
set_frame_rate(gspca_dev);
- setautogain_77(gspca_dev);
+ setautogain(gspca_dev);
setawb(gspca_dev);
setgain(gspca_dev);
setredblc(gspca_dev);
setblueblc(gspca_dev);
sethue(gspca_dev);
- setexposure_77(gspca_dev);
- setbrightness_77(gspca_dev);
- setcontrast_77(gspca_dev);
- setsharpness_77(gspca_dev);
+ setexposure(gspca_dev);
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ setsharpness(gspca_dev);
setvflip(gspca_dev);
sethflip(gspca_dev);
@@ -1783,81 +922,12 @@ static int sd_start_ov772x(struct gspca_dev *gspca_dev)
return 0;
}
-static int sd_start_ov965x(struct gspca_dev *gspca_dev)
-{
- int mode;
-
- mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
- switch (mode) {
- default:
-/* case 4: * 320x240 */
- sccb_w_array(gspca_dev, sensor_start_ov965x_1_vga,
- ARRAY_SIZE(sensor_start_ov965x_1_vga));
- reg_w_array(gspca_dev, bridge_start_ov965x_qvga,
- ARRAY_SIZE(bridge_start_ov965x_qvga));
- sccb_w_array(gspca_dev, sensor_start_ov965x_2_qvga,
- ARRAY_SIZE(sensor_start_ov965x_2_qvga));
- break;
- case 3: /* 640x480 */
- sccb_w_array(gspca_dev, sensor_start_ov965x_1_vga,
- ARRAY_SIZE(sensor_start_ov965x_1_vga));
- reg_w_array(gspca_dev, bridge_start_ov965x_vga,
- ARRAY_SIZE(bridge_start_ov965x_vga));
- sccb_w_array(gspca_dev, sensor_start_ov965x_2_vga,
- ARRAY_SIZE(sensor_start_ov965x_2_vga));
- break;
- case 2: /* 800x600 */
- sccb_w_array(gspca_dev, sensor_start_ov965x_1_svga,
- ARRAY_SIZE(sensor_start_ov965x_1_svga));
- reg_w_array(gspca_dev, bridge_start_ov965x_svga,
- ARRAY_SIZE(bridge_start_ov965x_svga));
- sccb_w_array(gspca_dev, sensor_start_ov965x_2_svga,
- ARRAY_SIZE(sensor_start_ov965x_2_svga));
- break;
- case 1: /* 1024x768 */
- sccb_w_array(gspca_dev, sensor_start_ov965x_1_xga,
- ARRAY_SIZE(sensor_start_ov965x_1_xga));
- reg_w_array(gspca_dev, bridge_start_ov965x_xga,
- ARRAY_SIZE(bridge_start_ov965x_xga));
- sccb_w_array(gspca_dev, sensor_start_ov965x_2_svga,
- ARRAY_SIZE(sensor_start_ov965x_2_svga));
- break;
- case 0: /* 1280x1024 */
- sccb_w_array(gspca_dev, sensor_start_ov965x_1_sxga,
- ARRAY_SIZE(sensor_start_ov965x_1_sxga));
- reg_w_array(gspca_dev, bridge_start_ov965x_sxga,
- ARRAY_SIZE(bridge_start_ov965x_sxga));
- sccb_w_array(gspca_dev, sensor_start_ov965x_2_sxga,
- ARRAY_SIZE(sensor_start_ov965x_2_sxga));
- break;
- }
- setfreq(gspca_dev);
- setautogain_96(gspca_dev);
- setbrightness_96(gspca_dev);
- setcontrast_96(gspca_dev);
- setexposure_96(gspca_dev);
- setsharpness_96(gspca_dev);
- setsatur(gspca_dev);
-
- ov534_reg_write(gspca_dev, 0xe0, 0x00);
- ov534_reg_write(gspca_dev, 0xe0, 0x00);
- ov534_set_led(gspca_dev, 1);
- return 0;
-}
-
-static void sd_stopN_ov772x(struct gspca_dev *gspca_dev)
+static void sd_stopN(struct gspca_dev *gspca_dev)
{
ov534_reg_write(gspca_dev, 0xe0, 0x09);
ov534_set_led(gspca_dev, 0);
}
-static void sd_stopN_ov965x(struct gspca_dev *gspca_dev)
-{
- ov534_reg_write(gspca_dev, 0xe0, 0x01);
- ov534_set_led(gspca_dev, 0);
- ov534_reg_write(gspca_dev, 0xe0, 0x00);
-}
-
/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
#define UVC_STREAM_EOH (1 << 7)
#define UVC_STREAM_ERR (1 << 6)
@@ -1875,11 +945,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
__u32 this_pts;
u16 this_fid;
int remaining_len = len;
- int payload_len;
- payload_len = gspca_dev->cam.bulk ? 2048 : 2040;
do {
- len = min(remaining_len, payload_len);
+ len = min(remaining_len, 2048);
/* Payloads are prefixed with a UVC-style header. We
consider a frame to start when the FID toggles, or the PTS
@@ -1918,7 +986,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data + 12, len - 12);
/* If this packet is marked as EOF, end the frame */
} else if (data[1] & UVC_STREAM_EOF) {
+ struct gspca_frame *frame;
+
sd->last_pts = 0;
+ frame = gspca_get_i_frame(gspca_dev);
+ if (frame == NULL)
+ goto discard;
+ if (frame->data_end - frame->data + (len - 12) !=
+ gspca_dev->width * gspca_dev->height * 2) {
+ PDEBUG(D_PACK, "wrong sized frame");
+ goto discard;
+ }
gspca_frame_add(gspca_dev, LAST_PACKET,
data + 12, len - 12);
} else {
@@ -1965,12 +1043,8 @@ static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
sd->exposure = val;
- if (gspca_dev->streaming) {
- if (sd->sensor == SENSOR_OV772X)
- setexposure_77(gspca_dev);
- else
- setexposure_96(gspca_dev);
- }
+ if (gspca_dev->streaming)
+ setexposure(gspca_dev);
return 0;
}
@@ -1987,12 +1061,8 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
sd->brightness = val;
- if (gspca_dev->streaming) {
- if (sd->sensor == SENSOR_OV772X)
- setbrightness_77(gspca_dev);
- else
- setbrightness_96(gspca_dev);
- }
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
return 0;
}
@@ -2009,12 +1079,8 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
sd->contrast = val;
- if (gspca_dev->streaming) {
- if (sd->sensor == SENSOR_OV772X)
- setcontrast_77(gspca_dev);
- else
- setcontrast_96(gspca_dev);
- }
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
return 0;
}
@@ -2026,41 +1092,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
-static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->satur = val;
- if (gspca_dev->streaming)
- setsatur(gspca_dev);
- return 0;
-}
-
-static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->satur;
- return 0;
-}
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->lightfreq = val;
- if (gspca_dev->streaming)
- setfreq(gspca_dev);
- return 0;
-}
-
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->lightfreq;
- return 0;
-}
-
static int sd_setredblc(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2122,22 +1153,14 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
sd->autogain = val;
if (gspca_dev->streaming) {
- if (sd->sensor == SENSOR_OV772X) {
-
- /* the auto white balance control works only
- * when auto gain is set */
- if (val)
- gspca_dev->ctrl_inac &= ~(1 << AWB_77_IDX);
- else
- gspca_dev->ctrl_inac |= (1 << AWB_77_IDX);
- setautogain_77(gspca_dev);
- } else {
- if (val)
- gspca_dev->ctrl_inac |= (1 << EXPO_96_IDX);
- else
- gspca_dev->ctrl_inac &= ~(1 << EXPO_96_IDX);
- setautogain_96(gspca_dev);
- }
+
+ /* the auto white balance control works only
+ * when auto gain is set */
+ if (val)
+ gspca_dev->ctrl_inac &= ~(1 << AWB_IDX);
+ else
+ gspca_dev->ctrl_inac |= (1 << AWB_IDX);
+ setautogain(gspca_dev);
}
return 0;
}
@@ -2173,12 +1196,8 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
sd->sharpness = val;
- if (gspca_dev->streaming) {
- if (sd->sensor == SENSOR_OV772X)
- setsharpness_77(gspca_dev);
- else
- setsharpness_96(gspca_dev);
- }
+ if (gspca_dev->streaming)
+ setsharpness(gspca_dev);
return 0;
}
@@ -2257,7 +1276,7 @@ static int sd_set_streamparm(struct gspca_dev *gspca_dev,
/* Set requested framerate */
sd->frame_rate = tpf->denominator / tpf->numerator;
- if (gspca_dev->streaming && sd->sensor == SENSOR_OV772X)
+ if (gspca_dev->streaming)
set_frame_rate(gspca_dev);
/* Return the actual framerate */
@@ -2267,57 +1286,23 @@ static int sd_set_streamparm(struct gspca_dev *gspca_dev,
return 0;
}
-static int sd_querymenu(struct gspca_dev *gspca_dev,
- struct v4l2_querymenu *menu)
-{
- switch (menu->id) {
- case V4L2_CID_POWER_LINE_FREQUENCY:
- switch (menu->index) {
- case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
- strcpy((char *) menu->name, "NoFliker");
- return 0;
- case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
- strcpy((char *) menu->name, "50 Hz");
- return 0;
- case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
- strcpy((char *) menu->name, "60 Hz");
- return 0;
- }
- break;
- }
- return -EINVAL;
-}
-
/* sub-driver description */
-static const struct sd_desc sd_desc_ov772x = {
+static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls_ov772x,
- .nctrls = ARRAY_SIZE(sd_ctrls_ov772x),
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
.init = sd_init,
- .start = sd_start_ov772x,
- .stopN = sd_stopN_ov772x,
+ .start = sd_start,
+ .stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
.get_streamparm = sd_get_streamparm,
.set_streamparm = sd_set_streamparm,
};
-static const struct sd_desc sd_desc_ov965x = {
- .name = MODULE_NAME,
- .ctrls = sd_ctrls_ov965x,
- .nctrls = ARRAY_SIZE(sd_ctrls_ov965x),
- .config = sd_config,
- .init = sd_init,
- .start = sd_start_ov965x,
- .stopN = sd_stopN_ov965x,
- .pkt_scan = sd_pkt_scan,
- .querymenu = sd_querymenu,
-};
-
/* -- module initialisation -- */
static const __devinitdata struct usb_device_id device_table[] = {
- {USB_DEVICE(0x06f8, 0x3003), .driver_info = SENSOR_OV965X},
- {USB_DEVICE(0x1415, 0x2000), .driver_info = SENSOR_OV772X},
+ {USB_DEVICE(0x1415, 0x2000)},
{}
};
@@ -2326,11 +1311,7 @@ MODULE_DEVICE_TABLE(usb, device_table);
/* -- device connect -- */
static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
- return gspca_dev_probe(intf, id,
- id->driver_info == SENSOR_OV772X
- ? &sd_desc_ov772x
- : &sd_desc_ov965x,
- sizeof(struct sd),
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
THIS_MODULE);
}
diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c
new file mode 100644
index 000000000000..bbe5a030e3b4
--- /dev/null
+++ b/drivers/media/video/gspca/ov534_9.c
@@ -0,0 +1,1477 @@
+/*
+ * ov534-ov965x gspca driver
+ *
+ * Copyright (C) 2009-2010 Jean-Francois Moine http://moinejf.free.fr
+ * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it>
+ * Copyright (C) 2008 Jim Paris <jim@jtan.com>
+ *
+ * Based on a prototype written by Mark Ferrell <majortrips@gmail.com>
+ * USB protocol reverse engineered by Jim Paris <jim@jtan.com>
+ * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/
+ *
+ * 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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "ov534_9"
+
+#include "gspca.h"
+
+#define OV534_REG_ADDRESS 0xf1 /* sensor address */
+#define OV534_REG_SUBADDR 0xf2
+#define OV534_REG_WRITE 0xf3
+#define OV534_REG_READ 0xf4
+#define OV534_REG_OPERATION 0xf5
+#define OV534_REG_STATUS 0xf6
+
+#define OV534_OP_WRITE_3 0x37
+#define OV534_OP_WRITE_2 0x33
+#define OV534_OP_READ_2 0xf9
+
+#define CTRL_TIMEOUT 500
+
+MODULE_AUTHOR("Jean-Francois Moine <moinejf@free.fr>");
+MODULE_DESCRIPTION("GSPCA/OV534_9 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ __u32 last_pts;
+ u8 last_fid;
+
+ u8 brightness;
+ u8 contrast;
+ u8 autogain;
+ u8 exposure;
+ s8 sharpness;
+ u8 satur;
+ u8 freq;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+
+static const struct ctrl sd_ctrls[] = {
+ { /* 0 */
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 15,
+ .step = 1,
+#define BRIGHTNESS_DEF 7
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ { /* 1 */
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 15,
+ .step = 1,
+#define CONTRAST_DEF 3
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ { /* 2 */
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Autogain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+#define EXPO_IDX 3
+ { /* 3 */
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+#define EXPO_DEF 0
+ .default_value = EXPO_DEF,
+ },
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
+ { /* 4 */
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sharpness",
+ .minimum = -1, /* -1 = auto */
+ .maximum = 4,
+ .step = 1,
+#define SHARPNESS_DEF -1
+ .default_value = SHARPNESS_DEF,
+ },
+ .set = sd_setsharpness,
+ .get = sd_getsharpness,
+ },
+ { /* 5 */
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 4,
+ .step = 1,
+#define SATUR_DEF 2
+ .default_value = SATUR_DEF,
+ },
+ .set = sd_setsatur,
+ .get = sd_getsatur,
+ },
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light frequency filter",
+ .minimum = 0,
+ .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
+ .step = 1,
+#define FREQ_DEF 0
+ .default_value = FREQ_DEF,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq,
+ },
+};
+
+static const struct v4l2_pix_format ov965x_mode[] = {
+#define QVGA_MODE 0
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG},
+#define VGA_MODE 1
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG},
+#define SVGA_MODE 2
+ {800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 800,
+ .sizeimage = 800 * 600 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG},
+#define XGA_MODE 3
+ {1024, 768, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 1024,
+ .sizeimage = 1024 * 768 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG},
+#define SXGA_MODE 4
+ {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 1280,
+ .sizeimage = 1280 * 1024 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG},
+};
+
+static const u8 bridge_init[][2] = {
+ {0x88, 0xf8},
+ {0x89, 0xff},
+ {0x76, 0x03},
+ {0x92, 0x03},
+ {0x95, 0x10},
+ {0xe2, 0x00},
+ {0xe7, 0x3e},
+ {0x8d, 0x1c},
+ {0x8e, 0x00},
+ {0x8f, 0x00},
+ {0x1f, 0x00},
+ {0xc3, 0xf9},
+ {0x89, 0xff},
+ {0x88, 0xf8},
+ {0x76, 0x03},
+ {0x92, 0x01},
+ {0x93, 0x18},
+ {0x1c, 0x0a},
+ {0x1d, 0x48},
+ {0xc0, 0x50},
+ {0xc1, 0x3c},
+ {0x34, 0x05},
+ {0xc2, 0x0c},
+ {0xc3, 0xf9},
+ {0x34, 0x05},
+ {0xe7, 0x2e},
+ {0x31, 0xf9},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0x25, 0x42},
+ {0x94, 0x11},
+};
+
+static const u8 sensor_init[][2] = {
+ {0x12, 0x80}, /* com7 - SSCB reset */
+ {0x00, 0x00}, /* gain */
+ {0x01, 0x80}, /* blue */
+ {0x02, 0x80}, /* red */
+ {0x03, 0x1b}, /* vref */
+ {0x04, 0x03}, /* com1 - exposure low bits */
+ {0x0b, 0x57}, /* ver */
+ {0x0e, 0x61}, /* com5 */
+ {0x0f, 0x42}, /* com6 */
+ {0x11, 0x00}, /* clkrc */
+ {0x12, 0x02}, /* com7 - 15fps VGA YUYV */
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x14, 0x28}, /* com9 */
+ {0x16, 0x24}, /* reg16 */
+ {0x17, 0x1d}, /* hstart*/
+ {0x18, 0xbd}, /* hstop */
+ {0x19, 0x01}, /* vstrt */
+ {0x1a, 0x81}, /* vstop*/
+ {0x1e, 0x04}, /* mvfp */
+ {0x24, 0x3c}, /* aew */
+ {0x25, 0x36}, /* aeb */
+ {0x26, 0x71}, /* vpt */
+ {0x27, 0x08}, /* bbias */
+ {0x28, 0x08}, /* gbbias */
+ {0x29, 0x15}, /* gr com */
+ {0x2a, 0x00}, /* exhch */
+ {0x2b, 0x00}, /* exhcl */
+ {0x2c, 0x08}, /* rbias */
+ {0x32, 0xff}, /* href */
+ {0x33, 0x00}, /* chlf */
+ {0x34, 0x3f}, /* aref1 */
+ {0x35, 0x00}, /* aref2 */
+ {0x36, 0xf8}, /* aref3 */
+ {0x38, 0x72}, /* adc2 */
+ {0x39, 0x57}, /* aref4 */
+ {0x3a, 0x80}, /* tslb - yuyv */
+ {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */
+ {0x3d, 0x99}, /* com13 */
+ {0x3f, 0xc1}, /* edge */
+ {0x40, 0xc0}, /* com15 */
+ {0x41, 0x40}, /* com16 */
+ {0x42, 0xc0}, /* com17 */
+ {0x43, 0x0a}, /* rsvd */
+ {0x44, 0xf0},
+ {0x45, 0x46},
+ {0x46, 0x62},
+ {0x47, 0x2a},
+ {0x48, 0x3c},
+ {0x4a, 0xfc},
+ {0x4b, 0xfc},
+ {0x4c, 0x7f},
+ {0x4d, 0x7f},
+ {0x4e, 0x7f},
+ {0x4f, 0x98}, /* matrix */
+ {0x50, 0x98},
+ {0x51, 0x00},
+ {0x52, 0x28},
+ {0x53, 0x70},
+ {0x54, 0x98},
+ {0x58, 0x1a}, /* matrix coef sign */
+ {0x59, 0x85}, /* AWB control */
+ {0x5a, 0xa9},
+ {0x5b, 0x64},
+ {0x5c, 0x84},
+ {0x5d, 0x53},
+ {0x5e, 0x0e},
+ {0x5f, 0xf0}, /* AWB blue limit */
+ {0x60, 0xf0}, /* AWB red limit */
+ {0x61, 0xf0}, /* AWB green limit */
+ {0x62, 0x00}, /* lcc1 */
+ {0x63, 0x00}, /* lcc2 */
+ {0x64, 0x02}, /* lcc3 */
+ {0x65, 0x16}, /* lcc4 */
+ {0x66, 0x01}, /* lcc5 */
+ {0x69, 0x02}, /* hv */
+ {0x6b, 0x5a}, /* dbvl */
+ {0x6c, 0x04},
+ {0x6d, 0x55},
+ {0x6e, 0x00},
+ {0x6f, 0x9d},
+ {0x70, 0x21}, /* dnsth */
+ {0x71, 0x78},
+ {0x72, 0x00}, /* poidx */
+ {0x73, 0x01}, /* pckdv */
+ {0x74, 0x3a}, /* xindx */
+ {0x75, 0x35}, /* yindx */
+ {0x76, 0x01},
+ {0x77, 0x02},
+ {0x7a, 0x12}, /* gamma curve */
+ {0x7b, 0x08},
+ {0x7c, 0x16},
+ {0x7d, 0x30},
+ {0x7e, 0x5e},
+ {0x7f, 0x72},
+ {0x80, 0x82},
+ {0x81, 0x8e},
+ {0x82, 0x9a},
+ {0x83, 0xa4},
+ {0x84, 0xac},
+ {0x85, 0xb8},
+ {0x86, 0xc3},
+ {0x87, 0xd6},
+ {0x88, 0xe6},
+ {0x89, 0xf2},
+ {0x8a, 0x03},
+ {0x8c, 0x89}, /* com19 */
+ {0x14, 0x28}, /* com9 */
+ {0x90, 0x7d},
+ {0x91, 0x7b},
+ {0x9d, 0x03}, /* lcc6 */
+ {0x9e, 0x04}, /* lcc7 */
+ {0x9f, 0x7a},
+ {0xa0, 0x79},
+ {0xa1, 0x40}, /* aechm */
+ {0xa4, 0x50}, /* com21 */
+ {0xa5, 0x68}, /* com26 */
+ {0xa6, 0x4a}, /* AWB green */
+ {0xa8, 0xc1}, /* refa8 */
+ {0xa9, 0xef}, /* refa9 */
+ {0xaa, 0x92},
+ {0xab, 0x04},
+ {0xac, 0x80}, /* black level control */
+ {0xad, 0x80},
+ {0xae, 0x80},
+ {0xaf, 0x80},
+ {0xb2, 0xf2},
+ {0xb3, 0x20},
+ {0xb4, 0x20}, /* ctrlb4 */
+ {0xb5, 0x00},
+ {0xb6, 0xaf},
+ {0xbb, 0xae},
+ {0xbc, 0x7f}, /* ADC channel offsets */
+ {0xdb, 0x7f},
+ {0xbe, 0x7f},
+ {0xbf, 0x7f},
+ {0xc0, 0xe2},
+ {0xc1, 0xc0},
+ {0xc2, 0x01},
+ {0xc3, 0x4e},
+ {0xc6, 0x85},
+ {0xc7, 0x80}, /* com24 */
+ {0xc9, 0xe0},
+ {0xca, 0xe8},
+ {0xcb, 0xf0},
+ {0xcc, 0xd8},
+ {0xcd, 0xf1},
+ {0x4f, 0x98}, /* matrix */
+ {0x50, 0x98},
+ {0x51, 0x00},
+ {0x52, 0x28},
+ {0x53, 0x70},
+ {0x54, 0x98},
+ {0x58, 0x1a},
+ {0xff, 0x41}, /* read 41, write ff 00 */
+ {0x41, 0x40}, /* com16 */
+
+ {0xc5, 0x03}, /* 60 Hz banding filter */
+ {0x6a, 0x02}, /* 50 Hz banding filter */
+
+ {0x12, 0x62}, /* com7 - 30fps VGA YUV */
+ {0x36, 0xfa}, /* aref3 */
+ {0x69, 0x0a}, /* hv */
+ {0x8c, 0x89}, /* com22 */
+ {0x14, 0x28}, /* com9 */
+ {0x3e, 0x0c},
+ {0x41, 0x40}, /* com16 */
+ {0x72, 0x00},
+ {0x73, 0x00},
+ {0x74, 0x3a},
+ {0x75, 0x35},
+ {0x76, 0x01},
+ {0xc7, 0x80},
+ {0x03, 0x12}, /* vref */
+ {0x17, 0x16}, /* hstart */
+ {0x18, 0x02}, /* hstop */
+ {0x19, 0x01}, /* vstrt */
+ {0x1a, 0x3d}, /* vstop */
+ {0x32, 0xff}, /* href */
+ {0xc0, 0xaa},
+};
+
+static const u8 bridge_init_2[][2] = {
+ {0x94, 0xaa},
+ {0xf1, 0x60},
+ {0xe5, 0x04},
+ {0xc0, 0x50},
+ {0xc1, 0x3c},
+ {0x8c, 0x00},
+ {0x8d, 0x1c},
+ {0x34, 0x05},
+
+ {0xc2, 0x0c},
+ {0xc3, 0xf9},
+ {0xda, 0x01},
+ {0x50, 0x00},
+ {0x51, 0xa0},
+ {0x52, 0x3c},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x00},
+ {0x57, 0x00},
+ {0x5c, 0x00},
+ {0x5a, 0xa0},
+ {0x5b, 0x78},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0x94, 0x11},
+};
+
+static const u8 sensor_init_2[][2] = {
+ {0x3b, 0xc4},
+ {0x1e, 0x04}, /* mvfp */
+ {0x13, 0xe0}, /* com8 */
+ {0x00, 0x00}, /* gain */
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x11, 0x03}, /* clkrc */
+ {0x6b, 0x5a}, /* dblv */
+ {0x6a, 0x05},
+ {0xc5, 0x07},
+ {0xa2, 0x4b},
+ {0xa3, 0x3e},
+ {0x2d, 0x00},
+ {0xff, 0x42}, /* read 42, write ff 00 */
+ {0x42, 0xc0}, /* com17 */
+ {0x2d, 0x00},
+ {0xff, 0x42}, /* read 42, write ff 00 */
+ {0x42, 0xc1}, /* com17 */
+/* sharpness */
+ {0x3f, 0x01},
+ {0xff, 0x42}, /* read 42, write ff 00 */
+ {0x42, 0xc1}, /* com17 */
+/* saturation */
+ {0x4f, 0x98}, /* matrix */
+ {0x50, 0x98},
+ {0x51, 0x00},
+ {0x52, 0x28},
+ {0x53, 0x70},
+ {0x54, 0x98},
+ {0x58, 0x1a},
+ {0xff, 0x41}, /* read 41, write ff 00 */
+ {0x41, 0x40}, /* com16 */
+/* contrast */
+ {0x56, 0x40},
+/* brightness */
+ {0x55, 0x8f},
+/* expo */
+ {0x10, 0x25}, /* aech - exposure high bits */
+ {0xff, 0x13}, /* read 13, write ff 00 */
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+};
+
+static const u8 sensor_start_1_vga[][2] = { /* same for qvga */
+ {0x12, 0x62}, /* com7 - 30fps VGA YUV */
+ {0x36, 0xfa}, /* aref3 */
+ {0x69, 0x0a}, /* hv */
+ {0x8c, 0x89}, /* com22 */
+ {0x14, 0x28}, /* com9 */
+ {0x3e, 0x0c}, /* com14 */
+ {0x41, 0x40}, /* com16 */
+ {0x72, 0x00},
+ {0x73, 0x00},
+ {0x74, 0x3a},
+ {0x75, 0x35},
+ {0x76, 0x01},
+ {0xc7, 0x80}, /* com24 */
+ {0x03, 0x12}, /* vref */
+ {0x17, 0x16}, /* hstart */
+ {0x18, 0x02}, /* hstop */
+ {0x19, 0x01}, /* vstrt */
+ {0x1a, 0x3d}, /* vstop */
+ {0x32, 0xff}, /* href */
+ {0xc0, 0xaa},
+};
+
+static const u8 sensor_start_1_svga[][2] = {
+ {0x12, 0x02}, /* com7 - YUYV - VGA 15 full resolution */
+ {0x36, 0xf8}, /* aref3 */
+ {0x69, 0x02}, /* hv */
+ {0x8c, 0x0d}, /* com22 */
+ {0x3e, 0x0c}, /* com14 */
+ {0x41, 0x40}, /* com16 */
+ {0x72, 0x00},
+ {0x73, 0x01},
+ {0x74, 0x3a},
+ {0x75, 0x35},
+ {0x76, 0x01},
+ {0xc7, 0x80}, /* com24 */
+ {0x03, 0x1b}, /* vref */
+ {0x17, 0x1d}, /* hstart */
+ {0x18, 0xbd}, /* hstop */
+ {0x19, 0x01}, /* vstrt */
+ {0x1a, 0x81}, /* vstop */
+ {0x32, 0xff}, /* href */
+ {0xc0, 0xe2},
+};
+
+static const u8 sensor_start_1_xga[][2] = {
+ {0x12, 0x02}, /* com7 */
+ {0x36, 0xf8}, /* aref3 */
+ {0x69, 0x02}, /* hv */
+ {0x8c, 0x89}, /* com22 */
+ {0x14, 0x28}, /* com9 */
+ {0x3e, 0x0c}, /* com14 */
+ {0x41, 0x40}, /* com16 */
+ {0x72, 0x00},
+ {0x73, 0x01},
+ {0x74, 0x3a},
+ {0x75, 0x35},
+ {0x76, 0x01},
+ {0xc7, 0x80}, /* com24 */
+ {0x03, 0x1b}, /* vref */
+ {0x17, 0x1d}, /* hstart */
+ {0x18, 0xbd}, /* hstop */
+ {0x19, 0x01}, /* vstrt */
+ {0x1a, 0x81}, /* vstop */
+ {0x32, 0xff}, /* href */
+ {0xc0, 0xe2},
+};
+
+static const u8 sensor_start_1_sxga[][2] = {
+ {0x12, 0x02}, /* com7 */
+ {0x36, 0xf8}, /* aref3 */
+ {0x69, 0x02}, /* hv */
+ {0x8c, 0x89}, /* com22 */
+ {0x14, 0x28}, /* com9 */
+ {0x3e, 0x0c}, /* com14 */
+ {0x41, 0x40}, /* com16 */
+ {0x72, 0x00},
+ {0x73, 0x01},
+ {0x74, 0x3a},
+ {0x75, 0x35},
+ {0x76, 0x01},
+ {0xc7, 0x80}, /* com24 */
+ {0x03, 0x1b}, /* vref */
+ {0x17, 0x1d}, /* hstart */
+ {0x18, 0x02}, /* hstop */
+ {0x19, 0x01}, /* vstrt */
+ {0x1a, 0x81}, /* vstop */
+ {0x32, 0xff}, /* href */
+ {0xc0, 0xe2},
+};
+
+static const u8 bridge_start_qvga[][2] = {
+ {0x94, 0xaa},
+ {0xf1, 0x60},
+ {0xe5, 0x04},
+ {0xc0, 0x50},
+ {0xc1, 0x3c},
+ {0x8c, 0x00},
+ {0x8d, 0x1c},
+ {0x34, 0x05},
+
+ {0xc2, 0x4c},
+ {0xc3, 0xf9},
+ {0xda, 0x00},
+ {0x50, 0x00},
+ {0x51, 0xa0},
+ {0x52, 0x78},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x00},
+ {0x57, 0x00},
+ {0x5c, 0x00},
+ {0x5a, 0x50},
+ {0x5b, 0x3c},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0x94, 0x11},
+};
+
+static const u8 bridge_start_vga[][2] = {
+ {0x94, 0xaa},
+ {0xf1, 0x60},
+ {0xe5, 0x04},
+ {0xc0, 0x50},
+ {0xc1, 0x3c},
+ {0x8c, 0x00},
+ {0x8d, 0x1c},
+ {0x34, 0x05},
+ {0xc2, 0x0c},
+ {0xc3, 0xf9},
+ {0xda, 0x01},
+ {0x50, 0x00},
+ {0x51, 0xa0},
+ {0x52, 0x3c},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x00},
+ {0x57, 0x00},
+ {0x5c, 0x00},
+ {0x5a, 0xa0},
+ {0x5b, 0x78},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0x94, 0x11},
+};
+
+static const u8 bridge_start_svga[][2] = {
+ {0x94, 0xaa},
+ {0xf1, 0x60},
+ {0xe5, 0x04},
+ {0xc0, 0xa0},
+ {0xc1, 0x80},
+ {0x8c, 0x00},
+ {0x8d, 0x1c},
+ {0x34, 0x05},
+ {0xc2, 0x4c},
+ {0xc3, 0xf9},
+ {0x50, 0x00},
+ {0x51, 0x40},
+ {0x52, 0x00},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x88},
+ {0x57, 0x00},
+ {0x5c, 0x00},
+ {0x5a, 0xc8},
+ {0x5b, 0x96},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0xda, 0x00},
+ {0x94, 0x11},
+};
+
+static const u8 bridge_start_xga[][2] = {
+ {0x94, 0xaa},
+ {0xf1, 0x60},
+ {0xe5, 0x04},
+ {0xc0, 0xa0},
+ {0xc1, 0x80},
+ {0x8c, 0x00},
+ {0x8d, 0x1c},
+ {0x34, 0x05},
+ {0xc2, 0x4c},
+ {0xc3, 0xf9},
+ {0x50, 0x00},
+ {0x51, 0x40},
+ {0x52, 0x00},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x88},
+ {0x57, 0x00},
+ {0x5c, 0x01},
+ {0x5a, 0x00},
+ {0x5b, 0xc0},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0xda, 0x01},
+ {0x94, 0x11},
+};
+
+static const u8 bridge_start_sxga[][2] = {
+ {0x94, 0xaa},
+ {0xf1, 0x60},
+ {0xe5, 0x04},
+ {0xc0, 0xa0},
+ {0xc1, 0x80},
+ {0x8c, 0x00},
+ {0x8d, 0x1c},
+ {0x34, 0x05},
+ {0xc2, 0x0c},
+ {0xc3, 0xf9},
+ {0xda, 0x00},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0x94, 0x11},
+};
+
+static const u8 sensor_start_2_qvga[][2] = {
+ {0x3b, 0xe4}, /* com11 - night mode 1/4 frame rate */
+ {0x1e, 0x04}, /* mvfp */
+ {0x13, 0xe0}, /* com8 */
+ {0x00, 0x00},
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x11, 0x01}, /* clkrc */
+ {0x6b, 0x5a}, /* dblv */
+ {0x6a, 0x02}, /* 50 Hz banding filter */
+ {0xc5, 0x03}, /* 60 Hz banding filter */
+ {0xa2, 0x96}, /* bd50 */
+ {0xa3, 0x7d}, /* bd60 */
+
+ {0xff, 0x13}, /* read 13, write ff 00 */
+ {0x13, 0xe7},
+ {0x3a, 0x80}, /* tslb - yuyv */
+};
+
+static const u8 sensor_start_2_vga[][2] = {
+ {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */
+ {0x1e, 0x04}, /* mvfp */
+ {0x13, 0xe0}, /* com8 */
+ {0x00, 0x00},
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x11, 0x03}, /* clkrc */
+ {0x6b, 0x5a}, /* dblv */
+ {0x6a, 0x05}, /* 50 Hz banding filter */
+ {0xc5, 0x07}, /* 60 Hz banding filter */
+ {0xa2, 0x4b}, /* bd50 */
+ {0xa3, 0x3e}, /* bd60 */
+
+ {0x2d, 0x00}, /* advfl */
+};
+
+static const u8 sensor_start_2_svga[][2] = { /* same for xga */
+ {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */
+ {0x1e, 0x04}, /* mvfp */
+ {0x13, 0xe0}, /* com8 */
+ {0x00, 0x00},
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x11, 0x01}, /* clkrc */
+ {0x6b, 0x5a}, /* dblv */
+ {0x6a, 0x0c}, /* 50 Hz banding filter */
+ {0xc5, 0x0f}, /* 60 Hz banding filter */
+ {0xa2, 0x4e}, /* bd50 */
+ {0xa3, 0x41}, /* bd60 */
+};
+
+static const u8 sensor_start_2_sxga[][2] = {
+ {0x13, 0xe0}, /* com8 */
+ {0x00, 0x00},
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */
+ {0x1e, 0x04}, /* mvfp */
+ {0x11, 0x01}, /* clkrc */
+ {0x6b, 0x5a}, /* dblv */
+ {0x6a, 0x0c}, /* 50 Hz banding filter */
+ {0xc5, 0x0f}, /* 60 Hz banding filter */
+ {0xa2, 0x4e}, /* bd50 */
+ {0xa3, 0x41}, /* bd60 */
+};
+
+static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ gspca_dev->usb_buf[0] = val;
+ ret = usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ 0x01,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_w failed %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void reg_w(struct gspca_dev *gspca_dev, u16 reg, u8 val)
+{
+ PDEBUG(D_USBO, "reg_w [%04x] = %02x", reg, val);
+ reg_w_i(gspca_dev, reg, val);
+}
+
+static u8 reg_r(struct gspca_dev *gspca_dev, u16 reg)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return 0;
+ ret = usb_control_msg(udev,
+ usb_rcvctrlpipe(udev, 0),
+ 0x01,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
+ PDEBUG(D_USBI, "reg_r [%04x] -> %02x", reg, gspca_dev->usb_buf[0]);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_r err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+ return gspca_dev->usb_buf[0];
+}
+
+static int sccb_check_status(struct gspca_dev *gspca_dev)
+{
+ u8 data;
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ data = reg_r(gspca_dev, OV534_REG_STATUS);
+
+ switch (data) {
+ case 0x00:
+ return 1;
+ case 0x04:
+ return 0;
+ case 0x03:
+ break;
+ default:
+ PDEBUG(D_USBI|D_USBO,
+ "sccb status 0x%02x, attempt %d/5",
+ data, i + 1);
+ }
+ }
+ return 0;
+}
+
+static void sccb_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+{
+ PDEBUG(D_USBO, "sccb_write [%02x] = %02x", reg, val);
+ reg_w_i(gspca_dev, OV534_REG_SUBADDR, reg);
+ reg_w_i(gspca_dev, OV534_REG_WRITE, val);
+ reg_w_i(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
+
+ if (!sccb_check_status(gspca_dev))
+ PDEBUG(D_ERR, "sccb_write failed");
+}
+
+static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg)
+{
+ reg_w(gspca_dev, OV534_REG_SUBADDR, reg);
+ reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
+ if (!sccb_check_status(gspca_dev))
+ PDEBUG(D_ERR, "sccb_read failed 1");
+
+ reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
+ if (!sccb_check_status(gspca_dev))
+ PDEBUG(D_ERR, "sccb_read failed 2");
+
+ return reg_r(gspca_dev, OV534_REG_READ);
+}
+
+/* output a bridge sequence (reg - val) */
+static void reg_w_array(struct gspca_dev *gspca_dev,
+ const u8 (*data)[2], int len)
+{
+ while (--len >= 0) {
+ reg_w(gspca_dev, (*data)[0], (*data)[1]);
+ data++;
+ }
+}
+
+/* output a sensor sequence (reg - val) */
+static void sccb_w_array(struct gspca_dev *gspca_dev,
+ const u8 (*data)[2], int len)
+{
+ while (--len >= 0) {
+ if ((*data)[0] != 0xff) {
+ sccb_write(gspca_dev, (*data)[0], (*data)[1]);
+ } else {
+ sccb_read(gspca_dev, (*data)[1]);
+ sccb_write(gspca_dev, 0xff, 0x00);
+ }
+ data++;
+ }
+}
+
+/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.
+ * (direction and output)? */
+static void set_led(struct gspca_dev *gspca_dev, int status)
+{
+ u8 data;
+
+ PDEBUG(D_CONF, "led status: %d", status);
+
+ data = reg_r(gspca_dev, 0x21);
+ data |= 0x80;
+ reg_w(gspca_dev, 0x21, data);
+
+ data = reg_r(gspca_dev, 0x23);
+ if (status)
+ data |= 0x80;
+ else
+ data &= ~0x80;
+
+ reg_w(gspca_dev, 0x23, data);
+
+ if (!status) {
+ data = reg_r(gspca_dev, 0x21);
+ data &= ~0x80;
+ reg_w(gspca_dev, 0x21, data);
+ }
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 val;
+
+ val = sd->brightness;
+ if (val < 8)
+ val = 15 - val; /* f .. 8 */
+ else
+ val = val - 8; /* 0 .. 7 */
+ sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */
+ 0x0f | (val << 4));
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sccb_write(gspca_dev, 0x56, /* cnst1 - contrast 1 ctrl coeff */
+ sd->contrast << 4);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 val;
+
+/*fixme: should adjust agc/awb/aec by different controls */
+ val = sd->autogain;
+ val = sccb_read(gspca_dev, 0x13); /* com8 */
+ sccb_write(gspca_dev, 0xff, 0x00);
+ if (sd->autogain)
+ val |= 0x05; /* agc & aec */
+ else
+ val &= 0xfa;
+ sccb_write(gspca_dev, 0x13, val);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 val;
+ static const u8 expo[4] = {0x00, 0x25, 0x38, 0x5e};
+
+ sccb_write(gspca_dev, 0x10, /* aec[9:2] */
+ expo[sd->exposure]);
+
+ val = sccb_read(gspca_dev, 0x13); /* com8 */
+ sccb_write(gspca_dev, 0xff, 0x00);
+ sccb_write(gspca_dev, 0x13, val);
+
+ val = sccb_read(gspca_dev, 0xa1); /* aech */
+ sccb_write(gspca_dev, 0xff, 0x00);
+ sccb_write(gspca_dev, 0xa1, val & 0xe0); /* aec[15:10] = 0 */
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s8 val;
+
+ val = sd->sharpness;
+ if (val < 0) { /* auto */
+ val = sccb_read(gspca_dev, 0x42); /* com17 */
+ sccb_write(gspca_dev, 0xff, 0x00);
+ sccb_write(gspca_dev, 0x42, val | 0x40);
+ /* Edge enhancement strength auto adjust */
+ return;
+ }
+ if (val != 0)
+ val = 1 << (val - 1);
+ sccb_write(gspca_dev, 0x3f, /* edge - edge enhance. factor */
+ val);
+ val = sccb_read(gspca_dev, 0x42); /* com17 */
+ sccb_write(gspca_dev, 0xff, 0x00);
+ sccb_write(gspca_dev, 0x42, val & 0xbf);
+}
+
+static void setsatur(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 val1, val2, val3;
+ static const u8 matrix[5][2] = {
+ {0x14, 0x38},
+ {0x1e, 0x54},
+ {0x28, 0x70},
+ {0x32, 0x8c},
+ {0x48, 0x90}
+ };
+
+ val1 = matrix[sd->satur][0];
+ val2 = matrix[sd->satur][1];
+ val3 = val1 + val2;
+ sccb_write(gspca_dev, 0x4f, val3); /* matrix coeff */
+ sccb_write(gspca_dev, 0x50, val3);
+ sccb_write(gspca_dev, 0x51, 0x00);
+ sccb_write(gspca_dev, 0x52, val1);
+ sccb_write(gspca_dev, 0x53, val2);
+ sccb_write(gspca_dev, 0x54, val3);
+ sccb_write(gspca_dev, 0x58, 0x1a); /* mtxs - coeff signs */
+
+ val1 = sccb_read(gspca_dev, 0x41); /* com16 */
+ sccb_write(gspca_dev, 0xff, 0x00);
+ sccb_write(gspca_dev, 0x41, val1);
+}
+
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 val;
+
+ val = sccb_read(gspca_dev, 0x13); /* com8 */
+ sccb_write(gspca_dev, 0xff, 0x00);
+ if (sd->freq == 0) {
+ sccb_write(gspca_dev, 0x13, val & 0xdf);
+ return;
+ }
+ sccb_write(gspca_dev, 0x13, val | 0x20);
+
+ val = sccb_read(gspca_dev, 0x42); /* com17 */
+ sccb_write(gspca_dev, 0xff, 0x00);
+ if (sd->freq == 1)
+ val |= 0x01;
+ else
+ val &= 0xfe;
+ sccb_write(gspca_dev, 0x42, val);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+
+ cam->cam_mode = ov965x_mode;
+ cam->nmodes = ARRAY_SIZE(ov965x_mode);
+
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+#if AUTOGAIN_DEF != 0
+ sd->autogain = AUTOGAIN_DEF;
+ gspca_dev->ctrl_inac |= (1 << EXPO_IDX);
+#endif
+#if EXPO_DEF != 0
+ sd->exposure = EXPO_DEF;
+#endif
+#if SHARPNESS_DEF != 0
+ sd->sharpness = SHARPNESS_DEF;
+#endif
+ sd->satur = SATUR_DEF;
+ sd->freq = FREQ_DEF;
+
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ u16 sensor_id;
+
+ /* reset bridge */
+ reg_w(gspca_dev, 0xe7, 0x3a);
+ reg_w(gspca_dev, 0xe0, 0x08);
+ msleep(100);
+
+ /* initialize the sensor address */
+ reg_w(gspca_dev, OV534_REG_ADDRESS, 0x60);
+
+ /* reset sensor */
+ sccb_write(gspca_dev, 0x12, 0x80);
+ msleep(10);
+
+ /* probe the sensor */
+ sccb_read(gspca_dev, 0x0a);
+ sensor_id = sccb_read(gspca_dev, 0x0a) << 8;
+ sccb_read(gspca_dev, 0x0b);
+ sensor_id |= sccb_read(gspca_dev, 0x0b);
+ PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id);
+
+ /* initialize */
+ reg_w_array(gspca_dev, bridge_init,
+ ARRAY_SIZE(bridge_init));
+ sccb_w_array(gspca_dev, sensor_init,
+ ARRAY_SIZE(sensor_init));
+ reg_w_array(gspca_dev, bridge_init_2,
+ ARRAY_SIZE(bridge_init_2));
+ sccb_w_array(gspca_dev, sensor_init_2,
+ ARRAY_SIZE(sensor_init_2));
+ reg_w(gspca_dev, 0xe0, 0x00);
+ reg_w(gspca_dev, 0xe0, 0x01);
+ set_led(gspca_dev, 0);
+ reg_w(gspca_dev, 0xe0, 0x00);
+
+ return gspca_dev->usb_err;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ switch (gspca_dev->curr_mode) {
+ case QVGA_MODE: /* 320x240 */
+ sccb_w_array(gspca_dev, sensor_start_1_vga,
+ ARRAY_SIZE(sensor_start_1_vga));
+ reg_w_array(gspca_dev, bridge_start_qvga,
+ ARRAY_SIZE(bridge_start_qvga));
+ sccb_w_array(gspca_dev, sensor_start_2_qvga,
+ ARRAY_SIZE(sensor_start_2_qvga));
+ break;
+ case VGA_MODE: /* 640x480 */
+ sccb_w_array(gspca_dev, sensor_start_1_vga,
+ ARRAY_SIZE(sensor_start_1_vga));
+ reg_w_array(gspca_dev, bridge_start_vga,
+ ARRAY_SIZE(bridge_start_vga));
+ sccb_w_array(gspca_dev, sensor_start_2_vga,
+ ARRAY_SIZE(sensor_start_2_vga));
+ break;
+ case SVGA_MODE: /* 800x600 */
+ sccb_w_array(gspca_dev, sensor_start_1_svga,
+ ARRAY_SIZE(sensor_start_1_svga));
+ reg_w_array(gspca_dev, bridge_start_svga,
+ ARRAY_SIZE(bridge_start_svga));
+ sccb_w_array(gspca_dev, sensor_start_2_svga,
+ ARRAY_SIZE(sensor_start_2_svga));
+ break;
+ case XGA_MODE: /* 1024x768 */
+ sccb_w_array(gspca_dev, sensor_start_1_xga,
+ ARRAY_SIZE(sensor_start_1_xga));
+ reg_w_array(gspca_dev, bridge_start_xga,
+ ARRAY_SIZE(bridge_start_xga));
+ sccb_w_array(gspca_dev, sensor_start_2_svga,
+ ARRAY_SIZE(sensor_start_2_svga));
+ break;
+ default:
+/* case SXGA_MODE: * 1280x1024 */
+ sccb_w_array(gspca_dev, sensor_start_1_sxga,
+ ARRAY_SIZE(sensor_start_1_sxga));
+ reg_w_array(gspca_dev, bridge_start_sxga,
+ ARRAY_SIZE(bridge_start_sxga));
+ sccb_w_array(gspca_dev, sensor_start_2_sxga,
+ ARRAY_SIZE(sensor_start_2_sxga));
+ break;
+ }
+ setfreq(gspca_dev);
+ setautogain(gspca_dev);
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ setexposure(gspca_dev);
+ setsharpness(gspca_dev);
+ setsatur(gspca_dev);
+
+ reg_w(gspca_dev, 0xe0, 0x00);
+ reg_w(gspca_dev, 0xe0, 0x00);
+ set_led(gspca_dev, 1);
+ return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev, 0xe0, 0x01);
+ set_led(gspca_dev, 0);
+ reg_w(gspca_dev, 0xe0, 0x00);
+}
+
+/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
+#define UVC_STREAM_EOH (1 << 7)
+#define UVC_STREAM_ERR (1 << 6)
+#define UVC_STREAM_STI (1 << 5)
+#define UVC_STREAM_RES (1 << 4)
+#define UVC_STREAM_SCR (1 << 3)
+#define UVC_STREAM_PTS (1 << 2)
+#define UVC_STREAM_EOF (1 << 1)
+#define UVC_STREAM_FID (1 << 0)
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, int len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u32 this_pts;
+ u8 this_fid;
+ int remaining_len = len;
+
+ do {
+ len = min(remaining_len, 2040);
+
+ /* Payloads are prefixed with a UVC-style header. We
+ consider a frame to start when the FID toggles, or the PTS
+ changes. A frame ends when EOF is set, and we've received
+ the correct number of bytes. */
+
+ /* Verify UVC header. Header length is always 12 */
+ if (data[0] != 12 || len < 12) {
+ PDEBUG(D_PACK, "bad header");
+ goto discard;
+ }
+
+ /* Check errors */
+ if (data[1] & UVC_STREAM_ERR) {
+ PDEBUG(D_PACK, "payload error");
+ goto discard;
+ }
+
+ /* Extract PTS and FID */
+ if (!(data[1] & UVC_STREAM_PTS)) {
+ PDEBUG(D_PACK, "PTS not present");
+ goto discard;
+ }
+ this_pts = (data[5] << 24) | (data[4] << 16)
+ | (data[3] << 8) | data[2];
+ this_fid = data[1] & UVC_STREAM_FID;
+
+ /* If PTS or FID has changed, start a new frame. */
+ if (this_pts != sd->last_pts || this_fid != sd->last_fid) {
+ if (gspca_dev->last_packet_type == INTER_PACKET)
+ gspca_frame_add(gspca_dev, LAST_PACKET,
+ NULL, 0);
+ sd->last_pts = this_pts;
+ sd->last_fid = this_fid;
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ data + 12, len - 12);
+ /* If this packet is marked as EOF, end the frame */
+ } else if (data[1] & UVC_STREAM_EOF) {
+ sd->last_pts = 0;
+ gspca_frame_add(gspca_dev, LAST_PACKET,
+ data + 12, len - 12);
+ } else {
+
+ /* Add the data from this payload */
+ gspca_frame_add(gspca_dev, INTER_PACKET,
+ data + 12, len - 12);
+ }
+
+ /* Done this payload */
+ goto scan_next;
+
+discard:
+ /* Discard data until a new frame starts. */
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+
+scan_next:
+ remaining_len -= len;
+ data += len;
+ } while (remaining_len > 0);
+}
+
+/* controls */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+
+ if (gspca_dev->streaming) {
+ if (val)
+ gspca_dev->ctrl_inac |= (1 << EXPO_IDX);
+ else
+ gspca_dev->ctrl_inac &= ~(1 << EXPO_IDX);
+ setautogain(gspca_dev);
+ }
+ return gspca_dev->usb_err;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->exposure = val;
+ if (gspca_dev->streaming)
+ setexposure(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->exposure;
+ return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->sharpness = val;
+ if (gspca_dev->streaming)
+ setsharpness(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->sharpness;
+ return 0;
+}
+
+static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->satur = val;
+ if (gspca_dev->streaming)
+ setsatur(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->satur;
+ return 0;
+}
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->freq = val;
+ if (gspca_dev->streaming)
+ setfreq(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->freq;
+ return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ switch (menu->id) {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (menu->index) {
+ case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+ strcpy((char *) menu->name, "NoFliker");
+ return 0;
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x06f8, 0x3003)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ int ret;
+
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index 4706a823add0..0c87c3490b1e 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -25,6 +25,7 @@
#define MODULE_NAME "pac207"
+#include <linux/input.h>
#include "gspca.h"
MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>");
@@ -77,7 +78,7 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
#define SD_BRIGHTNESS 0
{
{
@@ -495,6 +496,25 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+#ifdef CONFIG_INPUT
+static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* interrupt packet data */
+ int len) /* interrput packet length */
+{
+ int ret = -EINVAL;
+
+ if (len == 2 && data[0] == 0x5a && data[1] == 0x5a) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+ input_sync(gspca_dev->input_dev);
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ ret = 0;
+ }
+
+ return ret;
+}
+#endif
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -506,6 +526,9 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.dq_callback = pac207_do_auto_gain,
.pkt_scan = sd_pkt_scan,
+#ifdef CONFIG_INPUT
+ .int_pkt_scan = sd_int_pkt_scan,
+#endif
};
/* -- module initialisation -- */
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c
index de0b66c4b56e..2a68220d1ada 100644
--- a/drivers/media/video/gspca/pac7302.c
+++ b/drivers/media/video/gspca/pac7302.c
@@ -4,7 +4,9 @@
*
* V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
*
- * Separated from Pixart PAC7311 library by Márton Németh <nm127@freemail.hu>
+ * Separated from Pixart PAC7311 library by Márton Németh
+ * Camera button input handling by Márton Németh <nm127@freemail.hu>
+ * Copyright (C) 2009-2010 Márton Németh <nm127@freemail.hu>
*
* 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
@@ -22,33 +24,26 @@
*/
/* Some documentation about various registers as determined by trial and error.
- When the register addresses differ between the 7202 and the 7311 the 2
- different addresses are written as 7302addr/7311addr, when one of the 2
- addresses is a - sign that register description is not valid for the
- matching IC.
Register page 1:
Address Description
- -/0x08 Unknown compressor related, must always be 8 except when not
- in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
- -/0x1b Auto white balance related, bit 0 is AWB enable (inverted)
- bits 345 seem to toggle per color gains on/off (inverted)
0x78 Global control, bit 6 controls the LED (inverted)
- -/0x80 JPEG compression ratio ? Best not touched
- Register page 3/4:
+ Register page 3:
Address Description
- 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
+ 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
- -/0x0f Master gain 1-245, low value = high gain
- 0x10/- Master gain 0-31
- -/0x10 Another gain 0-15, limited influence (1-2x gain I guess)
+ 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
+ 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
+ 63 -> ~27 fps, the 2 msb's must always be 1 !!
+ 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
+ 1 -> ~30 fps, 2 -> ~20 fps
+ 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time
+ 0x0f Exposure bit 8, 0-448, 448 = no exposure at all
+ 0x10 Master gain 0-31
0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
- -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to
- completely disable the analog amplification block. Set to 0x68
- for max gain, 0x14 for minimal gain.
The registers are accessed in the following functions:
@@ -68,6 +63,7 @@
#define MODULE_NAME "pac7302"
+#include <linux/input.h>
#include <media/v4l2-chip-ident.h>
#include "gspca.h"
@@ -86,8 +82,8 @@ struct sd {
unsigned char red_balance;
unsigned char blue_balance;
unsigned char gain;
- unsigned char exposure;
unsigned char autogain;
+ unsigned short exposure;
__u8 hflip;
__u8 vflip;
u8 flags;
@@ -124,8 +120,7 @@ static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
-/* This control is pac7302 only */
+static const struct ctrl sd_ctrls[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
@@ -141,7 +136,6 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setbrightness,
.get = sd_getbrightness,
},
-/* This control is for both the 7302 and the 7311 */
{
{
.id = V4L2_CID_CONTRAST,
@@ -157,7 +151,6 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setcontrast,
.get = sd_getcontrast,
},
-/* This control is pac7302 only */
{
{
.id = V4L2_CID_SATURATION,
@@ -215,7 +208,6 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setbluebalance,
.get = sd_getbluebalance,
},
-/* All controls below are for both the 7302 and the 7311 */
{
{
.id = V4L2_CID_GAIN,
@@ -238,11 +230,10 @@ static struct ctrl sd_ctrls[] = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Exposure",
.minimum = 0,
-#define EXPOSURE_MAX 255
- .maximum = EXPOSURE_MAX,
+ .maximum = 1023,
.step = 1,
-#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
-#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
+#define EXPOSURE_DEF 66 /* 33 ms / 30 fps */
+#define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */
.default_value = EXPOSURE_DEF,
},
.set = sd_setexposure,
@@ -301,7 +292,6 @@ static const struct v4l2_pix_format vga_mode[] = {
};
#define LOAD_PAGE3 255
-#define LOAD_PAGE4 254
#define END_OF_SEQUENCE 0
/* pac 7302 */
@@ -379,7 +369,7 @@ static const __u8 start_7302[] = {
#define SKIP 0xaa
/* page 3 - the value SKIP says skip the index - see reg_w_page() */
static const __u8 page3_7302[] = {
- 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
+ 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
@@ -388,7 +378,7 @@ static const __u8 page3_7302[] = {
0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
+ SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -401,12 +391,14 @@ static const __u8 page3_7302[] = {
0x00
};
-static int reg_w_buf(struct gspca_dev *gspca_dev,
+static void reg_w_buf(struct gspca_dev *gspca_dev,
__u8 index,
const char *buffer, int len)
{
int ret;
+ if (gspca_dev->usb_err < 0)
+ return;
memcpy(gspca_dev->usb_buf, buffer, len);
ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
@@ -415,20 +407,23 @@ static int reg_w_buf(struct gspca_dev *gspca_dev,
0, /* value */
index, gspca_dev->usb_buf, len,
500);
- if (ret < 0)
+ if (ret < 0) {
PDEBUG(D_ERR, "reg_w_buf(): "
"Failed to write registers to index 0x%x, error %i",
index, ret);
- return ret;
+ gspca_dev->usb_err = ret;
+ }
}
-static int reg_w(struct gspca_dev *gspca_dev,
+static void reg_w(struct gspca_dev *gspca_dev,
__u8 index,
__u8 value)
{
int ret;
+ if (gspca_dev->usb_err < 0)
+ return;
gspca_dev->usb_buf[0] = value;
ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
@@ -436,32 +431,32 @@ static int reg_w(struct gspca_dev *gspca_dev,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, index, gspca_dev->usb_buf, 1,
500);
- if (ret < 0)
+ if (ret < 0) {
PDEBUG(D_ERR, "reg_w(): "
"Failed to write register to index 0x%x, value 0x%x, error %i",
index, value, ret);
- return ret;
+ gspca_dev->usb_err = ret;
+ }
}
-static int reg_w_seq(struct gspca_dev *gspca_dev,
+static void reg_w_seq(struct gspca_dev *gspca_dev,
const __u8 *seq, int len)
{
- int ret = 0;
while (--len >= 0) {
- if (0 <= ret)
- ret = reg_w(gspca_dev, seq[0], seq[1]);
+ reg_w(gspca_dev, seq[0], seq[1]);
seq += 2;
}
- return ret;
}
/* load the beginning of a page */
-static int reg_w_page(struct gspca_dev *gspca_dev,
+static void reg_w_page(struct gspca_dev *gspca_dev,
const __u8 *page, int len)
{
int index;
int ret = 0;
+ if (gspca_dev->usb_err < 0)
+ return;
for (index = 0; index < len; index++) {
if (page[index] == SKIP) /* skip this index */
continue;
@@ -477,56 +472,47 @@ static int reg_w_page(struct gspca_dev *gspca_dev,
"Failed to write register to index 0x%x, "
"value 0x%x, error %i",
index, page[index], ret);
+ gspca_dev->usb_err = ret;
break;
}
}
- return ret;
}
/* output a variable sequence */
-static int reg_w_var(struct gspca_dev *gspca_dev,
+static void reg_w_var(struct gspca_dev *gspca_dev,
const __u8 *seq,
- const __u8 *page3, unsigned int page3_len,
- const __u8 *page4, unsigned int page4_len)
+ const __u8 *page3, unsigned int page3_len)
{
int index, len;
- int ret = 0;
for (;;) {
index = *seq++;
len = *seq++;
switch (len) {
case END_OF_SEQUENCE:
- return ret;
- case LOAD_PAGE4:
- ret = reg_w_page(gspca_dev, page4, page4_len);
- break;
+ return;
case LOAD_PAGE3:
- ret = reg_w_page(gspca_dev, page3, page3_len);
+ reg_w_page(gspca_dev, page3, page3_len);
break;
default:
if (len > USB_BUF_SZ) {
PDEBUG(D_ERR|D_STREAM,
"Incorrect variable sequence");
- return -EINVAL;
+ return;
}
while (len > 0) {
if (len < 8) {
- ret = reg_w_buf(gspca_dev,
+ reg_w_buf(gspca_dev,
index, seq, len);
- if (ret < 0)
- return ret;
seq += len;
break;
}
- ret = reg_w_buf(gspca_dev, index, seq, 8);
+ reg_w_buf(gspca_dev, index, seq, 8);
seq += 8;
index += 8;
len -= 8;
}
}
- if (ret < 0)
- return ret;
}
/* not reached */
}
@@ -560,11 +546,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
/* This function is used by pac7302 only */
-static int setbrightcont(struct gspca_dev *gspca_dev)
+static void setbrightcont(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i, v;
- int ret;
static const __u8 max[10] =
{0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
0xd4, 0xec};
@@ -572,7 +557,7 @@ static int setbrightcont(struct gspca_dev *gspca_dev)
{0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
0x11, 0x0b};
- ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
+ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
for (i = 0; i < 10; i++) {
v = max[i];
v += (sd->brightness - BRIGHTNESS_MAX)
@@ -582,136 +567,121 @@ static int setbrightcont(struct gspca_dev *gspca_dev)
v = 0;
else if (v > 0xff)
v = 0xff;
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xa2 + i, v);
+ reg_w(gspca_dev, 0xa2 + i, v);
}
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xdc, 0x01);
- return ret;
+ reg_w(gspca_dev, 0xdc, 0x01);
}
/* This function is used by pac7302 only */
-static int setcolors(struct gspca_dev *gspca_dev)
+static void setcolors(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i, v;
- int ret;
static const int a[9] =
{217, -212, 0, -101, 170, -67, -38, -315, 355};
static const int b[9] =
{19, 106, 0, 19, 106, 1, 19, 106, 1};
- ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x11, 0x01);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
+ reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
+ reg_w(gspca_dev, 0x11, 0x01);
+ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
for (i = 0; i < 9; i++) {
v = a[i] * sd->colors / COLOR_MAX + b[i];
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
+ reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
+ reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
}
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xdc, 0x01);
+ reg_w(gspca_dev, 0xdc, 0x01);
PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
- return ret;
}
-static int setwhitebalance(struct gspca_dev *gspca_dev)
+static void setwhitebalance(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret;
- ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xc6, sd->white_balance);
+ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
+ reg_w(gspca_dev, 0xc6, sd->white_balance);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xdc, 0x01);
+ reg_w(gspca_dev, 0xdc, 0x01);
PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance);
- return ret;
}
-static int setredbalance(struct gspca_dev *gspca_dev)
+static void setredbalance(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret;
- ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xc5, sd->red_balance);
+ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
+ reg_w(gspca_dev, 0xc5, sd->red_balance);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xdc, 0x01);
+ reg_w(gspca_dev, 0xdc, 0x01);
PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance);
- return ret;
}
-static int setbluebalance(struct gspca_dev *gspca_dev)
+static void setbluebalance(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret;
- ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xc7, sd->blue_balance);
+ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
+ reg_w(gspca_dev, 0xc7, sd->blue_balance);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xdc, 0x01);
+ reg_w(gspca_dev, 0xdc, 0x01);
PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance);
- return ret;
}
-static int setgain(struct gspca_dev *gspca_dev)
+static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret;
- ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x10, sd->gain >> 3);
+ reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
+ reg_w(gspca_dev, 0x10, sd->gain >> 3);
/* load registers to sensor (Bit 0, auto clear) */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x11, 0x01);
- return ret;
+ reg_w(gspca_dev, 0x11, 0x01);
}
-static int setexposure(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret;
- __u8 reg;
-
- /* register 2 of frame 3/4 contains the clock divider configuring the
- no fps according to the formula: 60 / reg. sd->exposure is the
- desired exposure time in ms. */
- reg = 120 * sd->exposure / 1000;
- if (reg < 2)
- reg = 2;
- else if (reg > 63)
- reg = 63;
-
- /* On the pac7302 reg2 MUST be a multiple of 3, so round it to
- the nearest multiple of 3, except when between 6 and 12? */
- if (reg < 6 || reg > 12)
- reg = ((reg + 1) / 3) * 3;
- ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x02, reg);
+ __u8 clockdiv;
+ __u16 exposure;
+
+ /* register 2 of frame 3 contains the clock divider configuring the
+ no fps according to the formula: 90 / reg. sd->exposure is the
+ desired exposure time in 0.5 ms. */
+ clockdiv = (90 * sd->exposure + 1999) / 2000;
+
+ /* Note clockdiv = 3 also works, but when running at 30 fps, depending
+ on the scene being recorded, the camera switches to another
+ quantization table for certain JPEG blocks, and we don't know how
+ to decompress these blocks. So we cap the framerate at 15 fps */
+ if (clockdiv < 6)
+ clockdiv = 6;
+ else if (clockdiv > 63)
+ clockdiv = 63;
+
+ /* reg2 MUST be a multiple of 3, except when between 6 and 12?
+ Always round up, otherwise we cannot get the desired frametime
+ using the partial frame time exposure control */
+ if (clockdiv < 6 || clockdiv > 12)
+ clockdiv = ((clockdiv + 2) / 3) * 3;
+
+ /* frame exposure time in ms = 1000 * clockdiv / 90 ->
+ exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */
+ exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv);
+ /* 0 = use full frametime, 448 = no exposure, reverse it */
+ exposure = 448 - exposure;
+
+ reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
+ reg_w(gspca_dev, 0x02, clockdiv);
+ reg_w(gspca_dev, 0x0e, exposure & 0xff);
+ reg_w(gspca_dev, 0x0f, exposure >> 8);
/* load registers to sensor (Bit 0, auto clear) */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x11, 0x01);
- return ret;
+ reg_w(gspca_dev, 0x11, 0x01);
}
-static int sethvflip(struct gspca_dev *gspca_dev)
+static void sethvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret;
u8 data, hflip, vflip;
hflip = sd->hflip;
@@ -721,48 +691,37 @@ static int sethvflip(struct gspca_dev *gspca_dev)
if (sd->flags & FL_VFLIP)
vflip = !vflip;
- ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
+ reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x21, data);
+ reg_w(gspca_dev, 0x21, data);
+
/* load registers to sensor (Bit 0, auto clear) */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x11, 0x01);
- return ret;
+ reg_w(gspca_dev, 0x11, 0x01);
}
/* this function is called at probe and resume time for pac7302 */
static int sd_init(struct gspca_dev *gspca_dev)
{
- return reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
+ reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
+ return gspca_dev->usb_err;
}
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret = 0;
sd->sof_read = 0;
- ret = reg_w_var(gspca_dev, start_7302,
- page3_7302, sizeof(page3_7302),
- NULL, 0);
- if (0 <= ret)
- ret = setbrightcont(gspca_dev);
- if (0 <= ret)
- ret = setcolors(gspca_dev);
- if (0 <= ret)
- ret = setwhitebalance(gspca_dev);
- if (0 <= ret)
- ret = setredbalance(gspca_dev);
- if (0 <= ret)
- ret = setbluebalance(gspca_dev);
- if (0 <= ret)
- ret = setgain(gspca_dev);
- if (0 <= ret)
- ret = setexposure(gspca_dev);
- if (0 <= ret)
- ret = sethvflip(gspca_dev);
+ reg_w_var(gspca_dev, start_7302,
+ page3_7302, sizeof(page3_7302));
+ setbrightcont(gspca_dev);
+ setcolors(gspca_dev);
+ setwhitebalance(gspca_dev);
+ setredbalance(gspca_dev);
+ setbluebalance(gspca_dev);
+ setgain(gspca_dev);
+ setexposure(gspca_dev);
+ sethvflip(gspca_dev);
/* only resolution 640x480 is supported for pac7302 */
@@ -771,34 +730,27 @@ static int sd_start(struct gspca_dev *gspca_dev)
atomic_set(&sd->avg_lum, -1);
/* start stream */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xff, 0x01);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x78, 0x01);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x78, 0x01);
- return ret;
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
- int ret;
/* stop stream */
- ret = reg_w(gspca_dev, 0xff, 0x01);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x78, 0x00);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x78, 0x00);
}
/* called on streamoff with alt 0 and on disconnect for pac7302 */
static void sd_stop0(struct gspca_dev *gspca_dev)
{
- int ret;
-
if (!gspca_dev->present)
return;
- ret = reg_w(gspca_dev, 0xff, 0x01);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x78, 0x40);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x78, 0x40);
}
/* Include pac common sof detection functions */
@@ -808,22 +760,13 @@ static void do_autogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int avg_lum = atomic_read(&sd->avg_lum);
- int desired_lum, deadzone;
+ int desired_lum;
+ const int deadzone = 30;
if (avg_lum == -1)
return;
- desired_lum = 270 + sd->brightness * 4;
- /* Hack hack, with the 7202 the first exposure step is
- pretty large, so if we're about to make the first
- exposure increase make the deadzone large to avoid
- oscilating */
- if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
- sd->exposure > EXPOSURE_DEF &&
- sd->exposure < 42)
- deadzone = 90;
- else
- deadzone = 30;
+ desired_lum = 270 + sd->brightness;
if (sd->autogain_ignore_frames > 0)
sd->autogain_ignore_frames--;
@@ -947,7 +890,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
sd->brightness = val;
if (gspca_dev->streaming)
setbrightcont(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
@@ -966,7 +909,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
if (gspca_dev->streaming) {
setbrightcont(gspca_dev);
}
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
@@ -984,7 +927,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
sd->colors = val;
if (gspca_dev->streaming)
setcolors(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
@@ -998,14 +941,11 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret = 0;
sd->white_balance = val;
if (gspca_dev->streaming)
- ret = setwhitebalance(gspca_dev);
- if (0 <= ret)
- ret = 0;
- return ret;
+ setwhitebalance(gspca_dev);
+ return gspca_dev->usb_err;
}
static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
@@ -1019,14 +959,11 @@ static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret = 0;
sd->red_balance = val;
if (gspca_dev->streaming)
- ret = setredbalance(gspca_dev);
- if (0 <= ret)
- ret = 0;
- return ret;
+ setredbalance(gspca_dev);
+ return gspca_dev->usb_err;
}
static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
@@ -1040,14 +977,11 @@ static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret = 0;
sd->blue_balance = val;
if (gspca_dev->streaming)
- ret = setbluebalance(gspca_dev);
- if (0 <= ret)
- ret = 0;
- return ret;
+ setbluebalance(gspca_dev);
+ return gspca_dev->usb_err;
}
static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val)
@@ -1065,7 +999,7 @@ static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
sd->gain = val;
if (gspca_dev->streaming)
setgain(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -1083,7 +1017,7 @@ static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
sd->exposure = val;
if (gspca_dev->streaming)
setexposure(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
@@ -1114,7 +1048,7 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
}
}
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -1132,7 +1066,7 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
sd->hflip = val;
if (gspca_dev->streaming)
sethvflip(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -1150,7 +1084,7 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
sd->vflip = val;
if (gspca_dev->streaming)
sethvflip(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -1165,7 +1099,6 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
struct v4l2_dbg_register *reg)
{
- int ret = -EINVAL;
__u8 index;
__u8 value;
@@ -1185,14 +1118,12 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
/* Note that there shall be no access to other page
by any other function between the page swith and
the actual register write */
- ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
- if (0 <= ret)
- ret = reg_w(gspca_dev, index, value);
+ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
+ reg_w(gspca_dev, index, value);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xdc, 0x01);
+ reg_w(gspca_dev, 0xdc, 0x01);
}
- return ret;
+ return gspca_dev->usb_err;
}
static int sd_chip_ident(struct gspca_dev *gspca_dev,
@@ -1210,8 +1141,39 @@ static int sd_chip_ident(struct gspca_dev *gspca_dev,
}
#endif
+#ifdef CONFIG_INPUT
+static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* interrupt packet data */
+ int len) /* interrput packet length */
+{
+ int ret = -EINVAL;
+ u8 data0, data1;
+
+ if (len == 2) {
+ data0 = data[0];
+ data1 = data[1];
+ if ((data0 == 0x00 && data1 == 0x11) ||
+ (data0 == 0x22 && data1 == 0x33) ||
+ (data0 == 0x44 && data1 == 0x55) ||
+ (data0 == 0x66 && data1 == 0x77) ||
+ (data0 == 0x88 && data1 == 0x99) ||
+ (data0 == 0xaa && data1 == 0xbb) ||
+ (data0 == 0xcc && data1 == 0xdd) ||
+ (data0 == 0xee && data1 == 0xff)) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+ input_sync(gspca_dev->input_dev);
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+#endif
+
/* sub-driver description for pac7302 */
-static struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
@@ -1226,6 +1188,9 @@ static struct sd_desc sd_desc = {
.set_register = sd_dbg_s_register,
.get_chip_ident = sd_chip_ident,
#endif
+#ifdef CONFIG_INPUT
+ .int_pkt_scan = sd_int_pkt_scan,
+#endif
};
/* -- module initialisation -- */
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 42cfcdfd8f4f..44fed9686729 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -51,6 +51,7 @@
#define MODULE_NAME "pac7311"
+#include <linux/input.h>
#include "gspca.h"
MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
@@ -88,7 +89,7 @@ static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
/* This control is for both the 7302 and the 7311 */
{
{
@@ -200,7 +201,6 @@ static const struct v4l2_pix_format vga_mode[] = {
.priv = 0},
};
-#define LOAD_PAGE3 255
#define LOAD_PAGE4 254
#define END_OF_SEQUENCE 0
@@ -259,12 +259,14 @@ static const __u8 page4_7311[] = {
0x23, 0x28, 0x04, 0x11, 0x00, 0x00
};
-static int reg_w_buf(struct gspca_dev *gspca_dev,
+static void reg_w_buf(struct gspca_dev *gspca_dev,
__u8 index,
const char *buffer, int len)
{
int ret;
+ if (gspca_dev->usb_err < 0)
+ return;
memcpy(gspca_dev->usb_buf, buffer, len);
ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
@@ -273,20 +275,23 @@ static int reg_w_buf(struct gspca_dev *gspca_dev,
0, /* value */
index, gspca_dev->usb_buf, len,
500);
- if (ret < 0)
+ if (ret < 0) {
PDEBUG(D_ERR, "reg_w_buf(): "
"Failed to write registers to index 0x%x, error %i",
index, ret);
- return ret;
+ gspca_dev->usb_err = ret;
+ }
}
-static int reg_w(struct gspca_dev *gspca_dev,
+static void reg_w(struct gspca_dev *gspca_dev,
__u8 index,
__u8 value)
{
int ret;
+ if (gspca_dev->usb_err < 0)
+ return;
gspca_dev->usb_buf[0] = value;
ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
@@ -294,32 +299,32 @@ static int reg_w(struct gspca_dev *gspca_dev,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, index, gspca_dev->usb_buf, 1,
500);
- if (ret < 0)
+ if (ret < 0) {
PDEBUG(D_ERR, "reg_w(): "
"Failed to write register to index 0x%x, value 0x%x, error %i",
index, value, ret);
- return ret;
+ gspca_dev->usb_err = ret;
+ }
}
-static int reg_w_seq(struct gspca_dev *gspca_dev,
+static void reg_w_seq(struct gspca_dev *gspca_dev,
const __u8 *seq, int len)
{
- int ret = 0;
while (--len >= 0) {
- if (0 <= ret)
- ret = reg_w(gspca_dev, seq[0], seq[1]);
+ reg_w(gspca_dev, seq[0], seq[1]);
seq += 2;
}
- return ret;
}
/* load the beginning of a page */
-static int reg_w_page(struct gspca_dev *gspca_dev,
+static void reg_w_page(struct gspca_dev *gspca_dev,
const __u8 *page, int len)
{
int index;
int ret = 0;
+ if (gspca_dev->usb_err < 0)
+ return;
for (index = 0; index < len; index++) {
if (page[index] == SKIP) /* skip this index */
continue;
@@ -335,56 +340,47 @@ static int reg_w_page(struct gspca_dev *gspca_dev,
"Failed to write register to index 0x%x, "
"value 0x%x, error %i",
index, page[index], ret);
+ gspca_dev->usb_err = ret;
break;
}
}
- return ret;
}
/* output a variable sequence */
-static int reg_w_var(struct gspca_dev *gspca_dev,
+static void reg_w_var(struct gspca_dev *gspca_dev,
const __u8 *seq,
- const __u8 *page3, unsigned int page3_len,
const __u8 *page4, unsigned int page4_len)
{
int index, len;
- int ret = 0;
for (;;) {
index = *seq++;
len = *seq++;
switch (len) {
case END_OF_SEQUENCE:
- return ret;
+ return;
case LOAD_PAGE4:
- ret = reg_w_page(gspca_dev, page4, page4_len);
- break;
- case LOAD_PAGE3:
- ret = reg_w_page(gspca_dev, page3, page3_len);
+ reg_w_page(gspca_dev, page4, page4_len);
break;
default:
if (len > USB_BUF_SZ) {
PDEBUG(D_ERR|D_STREAM,
"Incorrect variable sequence");
- return -EINVAL;
+ return;
}
while (len > 0) {
if (len < 8) {
- ret = reg_w_buf(gspca_dev,
+ reg_w_buf(gspca_dev,
index, seq, len);
- if (ret < 0)
- return ret;
seq += len;
break;
}
- ret = reg_w_buf(gspca_dev, index, seq, 8);
+ reg_w_buf(gspca_dev, index, seq, 8);
seq += 8;
index += 8;
len -= 8;
}
}
- if (ret < 0)
- return ret;
}
/* not reached */
}
@@ -412,46 +408,36 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
/* This function is used by pac7311 only */
-static int setcontrast(struct gspca_dev *gspca_dev)
+static void setcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret;
- ret = reg_w(gspca_dev, 0xff, 0x04);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x10, sd->contrast >> 4);
+ reg_w(gspca_dev, 0xff, 0x04);
+ reg_w(gspca_dev, 0x10, sd->contrast >> 4);
/* load registers to sensor (Bit 0, auto clear) */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x11, 0x01);
- return ret;
+ reg_w(gspca_dev, 0x11, 0x01);
}
-static int setgain(struct gspca_dev *gspca_dev)
+static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int gain = GAIN_MAX - sd->gain;
- int ret;
if (gain < 1)
gain = 1;
else if (gain > 245)
gain = 245;
- ret = reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x0e, 0x00);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x0f, gain);
+ reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
+ reg_w(gspca_dev, 0x0e, 0x00);
+ reg_w(gspca_dev, 0x0f, gain);
/* load registers to sensor (Bit 0, auto clear) */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x11, 0x01);
- return ret;
+ reg_w(gspca_dev, 0x11, 0x01);
}
-static int setexposure(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret;
__u8 reg;
/* register 2 of frame 3/4 contains the clock divider configuring the
@@ -463,94 +449,72 @@ static int setexposure(struct gspca_dev *gspca_dev)
else if (reg > 63)
reg = 63;
- ret = reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x02, reg);
+ reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
+ reg_w(gspca_dev, 0x02, reg);
+
/* Page 1 register 8 must always be 0x08 except when not in
640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0xff, 0x01);
if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
reg <= 3) {
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x08, 0x09);
+ reg_w(gspca_dev, 0x08, 0x09);
} else {
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x08, 0x08);
+ reg_w(gspca_dev, 0x08, 0x08);
}
/* load registers to sensor (Bit 0, auto clear) */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x11, 0x01);
- return ret;
+ reg_w(gspca_dev, 0x11, 0x01);
}
-static int sethvflip(struct gspca_dev *gspca_dev)
+static void sethvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret;
__u8 data;
- ret = reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
+ reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x21, data);
+ reg_w(gspca_dev, 0x21, data);
+
/* load registers to sensor (Bit 0, auto clear) */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x11, 0x01);
- return ret;
+ reg_w(gspca_dev, 0x11, 0x01);
}
/* this function is called at probe and resume time for pac7311 */
static int sd_init(struct gspca_dev *gspca_dev)
{
- return reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
+ reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
+ return gspca_dev->usb_err;
}
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret;
sd->sof_read = 0;
- ret = reg_w_var(gspca_dev, start_7311,
- NULL, 0,
+ reg_w_var(gspca_dev, start_7311,
page4_7311, sizeof(page4_7311));
- if (0 <= ret)
- ret = setcontrast(gspca_dev);
- if (0 <= ret)
- ret = setgain(gspca_dev);
- if (0 <= ret)
- ret = setexposure(gspca_dev);
- if (0 <= ret)
- ret = sethvflip(gspca_dev);
+ setcontrast(gspca_dev);
+ setgain(gspca_dev);
+ setexposure(gspca_dev);
+ sethvflip(gspca_dev);
/* set correct resolution */
switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
case 2: /* 160x120 pac7311 */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xff, 0x01);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x17, 0x20);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x87, 0x10);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x17, 0x20);
+ reg_w(gspca_dev, 0x87, 0x10);
break;
case 1: /* 320x240 pac7311 */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xff, 0x01);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x17, 0x30);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x87, 0x11);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x17, 0x30);
+ reg_w(gspca_dev, 0x87, 0x11);
break;
case 0: /* 640x480 */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xff, 0x01);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x17, 0x00);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x87, 0x12);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x17, 0x00);
+ reg_w(gspca_dev, 0x87, 0x12);
break;
}
@@ -559,37 +523,24 @@ static int sd_start(struct gspca_dev *gspca_dev)
atomic_set(&sd->avg_lum, -1);
/* start stream */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xff, 0x01);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x78, 0x05);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x78, 0x05);
- return ret;
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
- int ret;
-
- ret = reg_w(gspca_dev, 0xff, 0x04);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x27, 0x80);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x28, 0xca);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x29, 0x53);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x2a, 0x0e);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0xff, 0x01);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x3e, 0x20);
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
- if (0 <= ret)
- ret = reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
+ reg_w(gspca_dev, 0xff, 0x04);
+ reg_w(gspca_dev, 0x27, 0x80);
+ reg_w(gspca_dev, 0x28, 0xca);
+ reg_w(gspca_dev, 0x29, 0x53);
+ reg_w(gspca_dev, 0x2a, 0x0e);
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x3e, 0x20);
+ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
+ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
+ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
}
/* called on streamoff with alt 0 and on disconnect for 7311 */
@@ -734,7 +685,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
if (gspca_dev->streaming) {
setcontrast(gspca_dev);
}
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
@@ -752,7 +703,7 @@ static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
sd->gain = val;
if (gspca_dev->streaming)
setgain(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -770,7 +721,7 @@ static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
sd->exposure = val;
if (gspca_dev->streaming)
setexposure(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
@@ -801,7 +752,7 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
}
}
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -819,7 +770,7 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
sd->hflip = val;
if (gspca_dev->streaming)
sethvflip(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -837,7 +788,7 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
sd->vflip = val;
if (gspca_dev->streaming)
sethvflip(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -848,8 +799,39 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+#ifdef CONFIG_INPUT
+static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* interrupt packet data */
+ int len) /* interrupt packet length */
+{
+ int ret = -EINVAL;
+ u8 data0, data1;
+
+ if (len == 2) {
+ data0 = data[0];
+ data1 = data[1];
+ if ((data0 == 0x00 && data1 == 0x11) ||
+ (data0 == 0x22 && data1 == 0x33) ||
+ (data0 == 0x44 && data1 == 0x55) ||
+ (data0 == 0x66 && data1 == 0x77) ||
+ (data0 == 0x88 && data1 == 0x99) ||
+ (data0 == 0xaa && data1 == 0xbb) ||
+ (data0 == 0xcc && data1 == 0xdd) ||
+ (data0 == 0xee && data1 == 0xff)) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+ input_sync(gspca_dev->input_dev);
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+#endif
+
/* sub-driver description for pac7311 */
-static struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
@@ -860,6 +842,9 @@ static struct sd_desc sd_desc = {
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
+#ifdef CONFIG_INPUT
+ .int_pkt_scan = sd_int_pkt_scan,
+#endif
};
/* -- module initialisation -- */
diff --git a/drivers/media/video/gspca/pac_common.h b/drivers/media/video/gspca/pac_common.h
index 20f67d9b8c06..8462a7c1a338 100644
--- a/drivers/media/video/gspca/pac_common.h
+++ b/drivers/media/video/gspca/pac_common.h
@@ -24,11 +24,10 @@
*/
/* We calculate the autogain at the end of the transfer of a frame, at this
- moment a frame with the old settings is being transmitted, and a frame is
- being captured with the old settings. So if we adjust the autogain we must
- ignore atleast the 2 next frames for the new settings to come into effect
- before doing any other adjustments */
-#define PAC_AUTOGAIN_IGNORE_FRAMES 3
+ moment a frame with the old settings is being captured and transmitted. So
+ if we adjust the gain or exposure we must ignore atleast the next frame for
+ the new settings to come into effect before doing any other adjustments. */
+#define PAC_AUTOGAIN_IGNORE_FRAMES 2
static const unsigned char pac_sof_marker[5] =
{ 0xff, 0xff, 0x00, 0xff, 0x96 };
diff --git a/drivers/media/video/gspca/sn9c2028.c b/drivers/media/video/gspca/sn9c2028.c
new file mode 100644
index 000000000000..dda5fd4aa69e
--- /dev/null
+++ b/drivers/media/video/gspca/sn9c2028.c
@@ -0,0 +1,757 @@
+/*
+ * SN9C2028 library
+ *
+ * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sn9c2028"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Theodore Kilgore");
+MODULE_DESCRIPTION("Sonix SN9C2028 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ u8 sof_read;
+ u16 model;
+};
+
+struct init_command {
+ unsigned char instruction[6];
+ unsigned char to_read; /* length to read. 0 means no reply requested */
+};
+
+/* V4L2 controls supported by the driver */
+static struct ctrl sd_ctrls[] = {
+};
+
+/* How to change the resolution of any of the VGA cams is unknown */
+static const struct v4l2_pix_format vga_mode[] = {
+ {640, 480, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 4,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+/* No way to change the resolution of the CIF cams is known */
+static const struct v4l2_pix_format cif_mode[] = {
+ {352, 288, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 4,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+/* the bytes to write are in gspca_dev->usb_buf */
+static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command)
+{
+ int rc;
+
+ PDEBUG(D_USBO, "sending command %02x%02x%02x%02x%02x%02x", command[0],
+ command[1], command[2], command[3], command[4], command[5]);
+
+ memcpy(gspca_dev->usb_buf, command, 6);
+ rc = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ USB_REQ_GET_CONFIGURATION,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 2, 0, gspca_dev->usb_buf, 6, 500);
+ if (rc < 0) {
+ PDEBUG(D_ERR, "command write [%02x] error %d",
+ gspca_dev->usb_buf[0], rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int sn9c2028_read1(struct gspca_dev *gspca_dev)
+{
+ int rc;
+
+ rc = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ USB_REQ_GET_STATUS,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 1, 0, gspca_dev->usb_buf, 1, 500);
+ if (rc != 1) {
+ PDEBUG(D_ERR, "read1 error %d", rc);
+ return (rc < 0) ? rc : -EIO;
+ }
+ PDEBUG(D_USBI, "read1 response %02x", gspca_dev->usb_buf[0]);
+ return gspca_dev->usb_buf[0];
+}
+
+static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading)
+{
+ int rc;
+ rc = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ USB_REQ_GET_STATUS,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 4, 0, gspca_dev->usb_buf, 4, 500);
+ if (rc != 4) {
+ PDEBUG(D_ERR, "read4 error %d", rc);
+ return (rc < 0) ? rc : -EIO;
+ }
+ memcpy(reading, gspca_dev->usb_buf, 4);
+ PDEBUG(D_USBI, "read4 response %02x%02x%02x%02x", reading[0],
+ reading[1], reading[2], reading[3]);
+ return rc;
+}
+
+static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command)
+{
+ int i, status;
+ __u8 reading[4];
+
+ status = sn9c2028_command(gspca_dev, command);
+ if (status < 0)
+ return status;
+
+ status = -1;
+ for (i = 0; i < 256 && status < 2; i++)
+ status = sn9c2028_read1(gspca_dev);
+ if (status != 2) {
+ PDEBUG(D_ERR, "long command status read error %d", status);
+ return (status < 0) ? status : -EIO;
+ }
+
+ memset(reading, 0, 4);
+ status = sn9c2028_read4(gspca_dev, reading);
+ if (status < 0)
+ return status;
+
+ /* in general, the first byte of the response is the first byte of
+ * the command, or'ed with 8 */
+ status = sn9c2028_read1(gspca_dev);
+ if (status < 0)
+ return status;
+
+ return 0;
+}
+
+static int sn9c2028_short_command(struct gspca_dev *gspca_dev, u8 *command)
+{
+ int err_code;
+
+ err_code = sn9c2028_command(gspca_dev, command);
+ if (err_code < 0)
+ return err_code;
+
+ err_code = sn9c2028_read1(gspca_dev);
+ if (err_code < 0)
+ return err_code;
+
+ return 0;
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam = &gspca_dev->cam;
+
+ PDEBUG(D_PROBE, "SN9C2028 camera detected (vid/pid 0x%04X:0x%04X)",
+ id->idVendor, id->idProduct);
+
+ sd->model = id->idProduct;
+
+ switch (sd->model) {
+ case 0x7005:
+ PDEBUG(D_PROBE, "Genius Smart 300 camera");
+ break;
+ case 0x8000:
+ PDEBUG(D_PROBE, "DC31VC");
+ break;
+ case 0x8001:
+ PDEBUG(D_PROBE, "Spy camera");
+ break;
+ case 0x8003:
+ PDEBUG(D_PROBE, "CIF camera");
+ break;
+ case 0x8008:
+ PDEBUG(D_PROBE, "Mini-Shotz ms-350 camera");
+ break;
+ case 0x800a:
+ PDEBUG(D_PROBE, "Vivitar 3350b type camera");
+ cam->input_flags = V4L2_IN_ST_VFLIP | V4L2_IN_ST_HFLIP;
+ break;
+ }
+
+ switch (sd->model) {
+ case 0x8000:
+ case 0x8001:
+ case 0x8003:
+ cam->cam_mode = cif_mode;
+ cam->nmodes = ARRAY_SIZE(cif_mode);
+ break;
+ default:
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+ }
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ int status = -1;
+
+ sn9c2028_read1(gspca_dev);
+ sn9c2028_read1(gspca_dev);
+ status = sn9c2028_read1(gspca_dev);
+
+ return (status < 0) ? status : 0;
+}
+
+static int run_start_commands(struct gspca_dev *gspca_dev,
+ struct init_command *cam_commands, int n)
+{
+ int i, err_code = -1;
+
+ for (i = 0; i < n; i++) {
+ switch (cam_commands[i].to_read) {
+ case 4:
+ err_code = sn9c2028_long_command(gspca_dev,
+ cam_commands[i].instruction);
+ break;
+ case 1:
+ err_code = sn9c2028_short_command(gspca_dev,
+ cam_commands[i].instruction);
+ break;
+ case 0:
+ err_code = sn9c2028_command(gspca_dev,
+ cam_commands[i].instruction);
+ break;
+ }
+ if (err_code < 0)
+ return err_code;
+ }
+ return 0;
+}
+
+static int start_spy_cam(struct gspca_dev *gspca_dev)
+{
+ struct init_command spy_start_commands[] = {
+ {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},
+ {{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},
+ {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, /* width 352 */
+ {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, /* height 288 */
+ /* {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, */
+ {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4},
+ {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* red gain ?*/
+ /* {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, */
+ {{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},
+ /* {{0x13, 0x29, 0x01, 0x0c, 0x00, 0x00}, 4}, */
+ {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
+ /* {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, */
+ {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
+ {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
+ /* {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, */
+ {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
+ {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
+ {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
+ {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x02, 0x06, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x03, 0x13, 0x00, 0x00, 0x00}, 4}, /*don't mess with*/
+ /*{{0x11, 0x04, 0x06, 0x00, 0x00, 0x00}, 4}, observed */
+ {{0x11, 0x04, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */
+ /*{{0x11, 0x05, 0x65, 0x00, 0x00, 0x00}, 4}, observed */
+ {{0x11, 0x05, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */
+ {{0x11, 0x06, 0xb1, 0x00, 0x00, 0x00}, 4}, /* observed */
+ {{0x11, 0x07, 0x00, 0x00, 0x00, 0x00}, 4},
+ /*{{0x11, 0x08, 0x06, 0x00, 0x00, 0x00}, 4}, observed */
+ {{0x11, 0x08, 0x0b, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x09, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x0a, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x0c, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x0d, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x0e, 0x04, 0x00, 0x00, 0x00}, 4},
+ /* {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4}, */
+ /* brightness or gain. 0 is default. 4 is good
+ * indoors at night with incandescent lighting */
+ {{0x11, 0x0f, 0x04, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x10, 0x06, 0x00, 0x00, 0x00}, 4}, /*hstart or hoffs*/
+ {{0x11, 0x11, 0x06, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x14, 0x02, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x13, 0x01, 0x00, 0x00, 0x00}, 4},
+ /* {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, observed */
+ {{0x1b, 0x02, 0x11, 0x00, 0x00, 0x00}, 1}, /* brighter */
+ /* {{0x1b, 0x13, 0x01, 0x00, 0x00, 0x00}, 1}, observed */
+ {{0x1b, 0x13, 0x11, 0x00, 0x00, 0x00}, 1},
+ {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}, /* compresses */
+ /* Camera should start to capture now. */
+ };
+
+ return run_start_commands(gspca_dev, spy_start_commands,
+ ARRAY_SIZE(spy_start_commands));
+}
+
+static int start_cif_cam(struct gspca_dev *gspca_dev)
+{
+ struct init_command cif_start_commands[] = {
+ {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
+ /* The entire sequence below seems redundant */
+ /* {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x22, 0x01, 0x06, 0x00, 0x00}, 4},
+ {{0x13, 0x23, 0x01, 0x02, 0x00, 0x00}, 4},
+ {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, width?
+ {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, height?
+ {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?
+ {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},
+ {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
+ {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
+ {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
+ {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
+ {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
+ {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},*/
+ {{0x1b, 0x21, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x17, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x19, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x03, 0x5a, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x04, 0x27, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x05, 0x01, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x12, 0x14, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x14, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x15, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x16, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x77, 0xa2, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x06, 0x0f, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x07, 0x14, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x08, 0x0f, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x09, 0x10, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x12, 0x07, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x10, 0x1f, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},
+ {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 1}, /* width/8 */
+ {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 1}, /* height/8 */
+ /* {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?
+ * {{0x13, 0x28, 0x01, 0x1e, 0x00, 0x00}, 4}, does nothing
+ * {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, */
+ /* {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
+ * causes subsampling
+ * but not a change in the resolution setting! */
+ {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
+ {{0x13, 0x2d, 0x01, 0x01, 0x00, 0x00}, 4},
+ {{0x13, 0x2e, 0x01, 0x08, 0x00, 0x00}, 4},
+ {{0x13, 0x2f, 0x01, 0x06, 0x00, 0x00}, 4},
+ {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x1b, 0x04, 0x6d, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x05, 0x03, 0x00, 0x00, 0x00}, 1},
+ {{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x0e, 0x01, 0x00, 0x00, 0x00}, 1},
+ {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x10, 0x0f, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},
+ {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1},/* use compression */
+ /* Camera should start to capture now. */
+ };
+
+ return run_start_commands(gspca_dev, cif_start_commands,
+ ARRAY_SIZE(cif_start_commands));
+}
+
+static int start_ms350_cam(struct gspca_dev *gspca_dev)
+{
+ struct init_command ms350_start_commands[] = {
+ {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},
+ {{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},
+ {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
+ {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
+ {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},
+ {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4},
+ {{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
+ {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
+ {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
+ {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
+ {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
+ {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x00, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x01, 0x70, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x02, 0x05, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x03, 0x5d, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x04, 0x07, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x05, 0x25, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x06, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x07, 0x09, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x08, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x09, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x0c, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x0d, 0x0c, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x0e, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x11, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x13, 0x63, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x15, 0x70, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x18, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x11, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* width */
+ {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* height */
+ {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* vstart? */
+ {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},
+ {{0x13, 0x29, 0x01, 0x40, 0x00, 0x00}, 4}, /* hstart? */
+ {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
+ {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
+ {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
+ {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
+ {{0x1b, 0x02, 0x05, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},
+ {{0x20, 0x18, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x02, 0x0a, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 0},
+ /* Camera should start to capture now. */
+ };
+
+ return run_start_commands(gspca_dev, ms350_start_commands,
+ ARRAY_SIZE(ms350_start_commands));
+}
+
+static int start_genius_cam(struct gspca_dev *gspca_dev)
+{
+ struct init_command genius_start_commands[] = {
+ {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
+ {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
+ /* "preliminary" width and height settings */
+ {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
+ {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
+ {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
+ {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
+ {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
+ {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
+ {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
+ {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* real width */
+ {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* real height */
+ {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
+ {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
+ {{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4},
+ {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
+ {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
+ {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
+ {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
+ {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4},
+ {{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4},
+ {{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},
+ {{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},
+ {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0}
+ /* Camera should start to capture now. */
+ };
+
+ return run_start_commands(gspca_dev, genius_start_commands,
+ ARRAY_SIZE(genius_start_commands));
+}
+
+static int start_vivitar_cam(struct gspca_dev *gspca_dev)
+{
+ struct init_command vivitar_start_commands[] = {
+ {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x22, 0x01, 0x01, 0x00, 0x00}, 4},
+ {{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4},
+ {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},
+ {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},
+ {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
+ {{0x13, 0x28, 0x01, 0x0a, 0x00, 0x00}, 4},
+ /*
+ * Above is changed from OEM 0x0b. Fixes Bayer tiling.
+ * Presumably gives a vertical shift of one row.
+ */
+ {{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},
+ /* Above seems to do horizontal shift. */
+ {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
+ {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
+ {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
+ {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
+ /* Above three commands seem to relate to brightness. */
+ {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
+ {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x1b, 0x12, 0x80, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x01, 0x77, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x02, 0x3a, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x12, 0x78, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x14, 0x80, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x15, 0x34, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x1b, 0x04, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x20, 0x44, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x23, 0xee, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x26, 0xa0, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x27, 0x9a, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x28, 0xa0, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x2a, 0x80, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x2b, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x2f, 0x3d, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x30, 0x24, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x32, 0x86, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x60, 0xa9, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x61, 0x42, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x65, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x69, 0x38, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x6f, 0x88, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x70, 0x0b, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x71, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x74, 0x21, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x75, 0x86, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x76, 0x00, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x7d, 0xf3, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x17, 0x1c, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x18, 0xc0, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x19, 0x05, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x1a, 0xf6, 0x00, 0x00, 0x00}, 1},
+ /* {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},
+ {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},
+ {{0x13, 0x28, 0x01, 0x0b, 0x00, 0x00}, 4}, */
+ {{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x10, 0x26, 0x00, 0x00, 0x00}, 1},
+ {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x1b, 0x76, 0x03, 0x00, 0x00, 0x00}, 1},
+ {{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},
+ {{0x1b, 0x00, 0x3f, 0x00, 0x00, 0x00}, 1},
+ /* Above is brightness; OEM driver setting is 0x10 */
+ {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},
+ {{0x20, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},
+ {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}
+ };
+
+ return run_start_commands(gspca_dev, vivitar_start_commands,
+ ARRAY_SIZE(vivitar_start_commands));
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int err_code;
+
+ sd->sof_read = 0;
+
+ switch (sd->model) {
+ case 0x7005:
+ err_code = start_genius_cam(gspca_dev);
+ break;
+ case 0x8001:
+ err_code = start_spy_cam(gspca_dev);
+ break;
+ case 0x8003:
+ err_code = start_cif_cam(gspca_dev);
+ break;
+ case 0x8008:
+ err_code = start_ms350_cam(gspca_dev);
+ break;
+ case 0x800a:
+ err_code = start_vivitar_cam(gspca_dev);
+ break;
+ default:
+ PDEBUG(D_ERR, "Starting unknown camera, please report this");
+ return -ENXIO;
+ }
+
+ return err_code;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ int result;
+ __u8 data[6];
+
+ result = sn9c2028_read1(gspca_dev);
+ if (result < 0)
+ PDEBUG(D_ERR, "Camera Stop read failed");
+
+ memset(data, 0, 6);
+ data[0] = 0x14;
+ result = sn9c2028_command(gspca_dev, data);
+ if (result < 0)
+ PDEBUG(D_ERR, "Camera Stop command failed");
+}
+
+/* Include sn9c2028 sof detection functions */
+#include "sn9c2028.h"
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ unsigned char *sof;
+
+ sof = sn9c2028_find_sof(gspca_dev, data, len);
+ if (sof) {
+ int n;
+
+ /* finish decoding current frame */
+ n = sof - data;
+ if (n > sizeof sn9c2028_sof_marker)
+ n -= sizeof sn9c2028_sof_marker;
+ else
+ n = 0;
+ gspca_frame_add(gspca_dev, LAST_PACKET, data, n);
+ /* Start next frame. */
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ sn9c2028_sof_marker, sizeof sn9c2028_sof_marker);
+ len -= sof - data;
+ data = sof;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */
+ /* The Genius Smart is untested. I can't find an owner ! */
+ /* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */
+ {USB_DEVICE(0x0c45, 0x8001)}, /* Wild Planet digital spy cam */
+ {USB_DEVICE(0x0c45, 0x8003)}, /* Several small CIF cameras */
+ /* {USB_DEVICE(0x0c45, 0x8006)}, Unknown VGA camera */
+ {USB_DEVICE(0x0c45, 0x8008)}, /* Mini-Shotz ms-350 */
+ {USB_DEVICE(0x0c45, 0x800a)}, /* Vivicam 3350B */
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ int ret;
+
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
+ PDEBUG(D_PROBE, "registered");
+ return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/sn9c2028.h b/drivers/media/video/gspca/sn9c2028.h
new file mode 100644
index 000000000000..8fd1d3e05665
--- /dev/null
+++ b/drivers/media/video/gspca/sn9c2028.h
@@ -0,0 +1,51 @@
+/*
+ * SN9C2028 common functions
+ *
+ * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn,edu>
+ *
+ * Based closely upon the file gspca/pac_common.h
+ *
+ * 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
+ *
+ */
+
+static const unsigned char sn9c2028_sof_marker[5] =
+ { 0xff, 0xff, 0x00, 0xc4, 0xc4 };
+
+static unsigned char *sn9c2028_find_sof(struct gspca_dev *gspca_dev,
+ unsigned char *m, int len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+
+ /* Search for the SOF marker (fixed part) in the header */
+ for (i = 0; i < len; i++) {
+ if (m[i] == sn9c2028_sof_marker[sd->sof_read]) {
+ sd->sof_read++;
+ if (sd->sof_read == sizeof(sn9c2028_sof_marker)) {
+ PDEBUG(D_FRAM,
+ "SOF found, bytes to analyze: %u."
+ " Frame starts at byte #%u",
+ len, i + 1);
+ sd->sof_read = 0;
+ return m + i + 1;
+ }
+ } else {
+ sd->sof_read = 0;
+ }
+ }
+
+ return NULL;
+}
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 4cff8035614f..4a1bc08f82b9 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -129,7 +129,7 @@ static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val);
static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val);
static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
{
#define BRIGHTNESS_IDX 0
{
@@ -1506,36 +1506,36 @@ static int set_cmatrix(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
s32 hue_coord, hue_index = 180 + sd->hue;
u8 cmatrix[21];
- memset(cmatrix, 0, 21);
+ memset(cmatrix, 0, sizeof cmatrix);
cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
cmatrix[18] = sd->brightness - 0x80;
hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
- cmatrix[6] = (unsigned char)(hue_coord & 0xff);
- cmatrix[7] = (unsigned char)((hue_coord >> 8) & 0x0f);
+ cmatrix[6] = hue_coord;
+ cmatrix[7] = (hue_coord >> 8) & 0x0f;
hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
- cmatrix[8] = (unsigned char)(hue_coord & 0xff);
- cmatrix[9] = (unsigned char)((hue_coord >> 8) & 0x0f);
+ cmatrix[8] = hue_coord;
+ cmatrix[9] = (hue_coord >> 8) & 0x0f;
hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
- cmatrix[10] = (unsigned char)(hue_coord & 0xff);
- cmatrix[11] = (unsigned char)((hue_coord >> 8) & 0x0f);
+ cmatrix[10] = hue_coord;
+ cmatrix[11] = (hue_coord >> 8) & 0x0f;
hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
- cmatrix[12] = (unsigned char)(hue_coord & 0xff);
- cmatrix[13] = (unsigned char)((hue_coord >> 8) & 0x0f);
+ cmatrix[12] = hue_coord;
+ cmatrix[13] = (hue_coord >> 8) & 0x0f;
hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
- cmatrix[14] = (unsigned char)(hue_coord & 0xff);
- cmatrix[15] = (unsigned char)((hue_coord >> 8) & 0x0f);
+ cmatrix[14] = hue_coord;
+ cmatrix[15] = (hue_coord >> 8) & 0x0f;
hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
- cmatrix[16] = (unsigned char)(hue_coord & 0xff);
- cmatrix[17] = (unsigned char)((hue_coord >> 8) & 0x0f);
+ cmatrix[16] = hue_coord;
+ cmatrix[17] = (hue_coord >> 8) & 0x0f;
return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
}
@@ -2015,6 +2015,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
default:
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
+ break;
}
sd->old_step = 0;
@@ -2319,7 +2320,7 @@ static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
}
}
if (avg_lum > MAX_AVG_LUM) {
- if (sd->gain - 1 >= 0) {
+ if (sd->gain > 0) {
sd->gain--;
set_gain(gspca_dev);
}
@@ -2347,7 +2348,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
int avg_lum;
- static unsigned char frame_header[] =
+ static u8 frame_header[] =
{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
if (len == 64 && memcmp(data, frame_header, 6) == 0) {
avg_lum = ((data[35] >> 2) & 3) |
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index ddff2b5ee5c2..785eeb4c2014 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -42,6 +42,7 @@ Reg Use
#define MODULE_NAME "sonixb"
+#include <linux/input.h>
#include "gspca.h"
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
@@ -53,9 +54,11 @@ struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
atomic_t avg_lum;
int prev_avg_lum;
+ int exp_too_low_cnt;
+ int exp_too_high_cnt;
+ unsigned short exposure;
unsigned char gain;
- unsigned char exposure;
unsigned char brightness;
unsigned char autogain;
unsigned char autogain_ignore_frames;
@@ -73,8 +76,9 @@ struct sd {
#define SENSOR_OV7630 2
#define SENSOR_PAS106 3
#define SENSOR_PAS202 4
-#define SENSOR_TAS5110 5
-#define SENSOR_TAS5130CXX 6
+#define SENSOR_TAS5110C 5
+#define SENSOR_TAS5110D 6
+#define SENSOR_TAS5130CXX 7
__u8 reg11;
};
@@ -95,13 +99,15 @@ struct sensor_data {
/* sensor_data flags */
#define F_GAIN 0x01 /* has gain */
#define F_SIF 0x02 /* sif or vga */
+#define F_COARSE_EXPO 0x04 /* exposure control is coarse */
/* priv field of struct v4l2_pix_format flags (do not use low nibble!) */
#define MODE_RAW 0x10 /* raw bayer mode */
#define MODE_REDUCED_SIF 0x20 /* vga mode (320x240 / 160x120) on sif cam */
/* ctrl_dis helper macros */
-#define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX))
+#define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << COARSE_EXPOSURE_IDX) | \
+ (1 << AUTOGAIN_IDX))
#define NO_FREQ (1 << FREQ_IDX)
#define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX)
@@ -127,11 +133,10 @@ struct sensor_data {
}
/* We calculate the autogain at the end of the transfer of a frame, at this
- moment a frame with the old settings is being transmitted, and a frame is
- being captured with the old settings. So if we adjust the autogain we must
- ignore atleast the 2 next frames for the new settings to come into effect
- before doing any other adjustments */
-#define AUTOGAIN_IGNORE_FRAMES 3
+ moment a frame with the old settings is being captured and transmitted. So
+ if we adjust the gain or exposure we must ignore atleast the next frame for
+ the new settings to come into effect before doing any other adjustments. */
+#define AUTOGAIN_IGNORE_FRAMES 1
/* V4L2 controls supported by the driver */
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
@@ -145,7 +150,7 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
#define BRIGHTNESS_IDX 0
{
{
@@ -171,7 +176,7 @@ static struct ctrl sd_ctrls[] = {
.maximum = 255,
.step = 1,
#define GAIN_DEF 127
-#define GAIN_KNEE 200
+#define GAIN_KNEE 230
.default_value = GAIN_DEF,
},
.set = sd_setgain,
@@ -183,10 +188,10 @@ static struct ctrl sd_ctrls[] = {
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Exposure",
-#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
-#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
+#define EXPOSURE_DEF 66 /* 33 ms / 30 fps (except on PASXXX) */
+#define EXPOSURE_KNEE 200 /* 100 ms / 10 fps (except on PASXXX) */
.minimum = 0,
- .maximum = 255,
+ .maximum = 1023,
.step = 1,
.default_value = EXPOSURE_DEF,
.flags = 0,
@@ -194,7 +199,23 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setexposure,
.get = sd_getexposure,
},
-#define AUTOGAIN_IDX 3
+#define COARSE_EXPOSURE_IDX 3
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+#define COARSE_EXPOSURE_DEF 2 /* 30 fps */
+ .minimum = 2,
+ .maximum = 15,
+ .step = 1,
+ .default_value = COARSE_EXPOSURE_DEF,
+ .flags = 0,
+ },
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
+#define AUTOGAIN_IDX 4
{
{
.id = V4L2_CID_AUTOGAIN,
@@ -210,7 +231,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setautogain,
.get = sd_getautogain,
},
-#define FREQ_IDX 4
+#define FREQ_IDX 5
{
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -219,7 +240,7 @@ static struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
.step = 1,
-#define FREQ_DEF 1
+#define FREQ_DEF 0
.default_value = FREQ_DEF,
},
.set = sd_setfreq,
@@ -345,7 +366,7 @@ static const __u8 initOv7630[] = {
};
static const __u8 initOv7630_3[] = {
0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
- 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
+ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
0x28, 0x1e, /* H & V sizes r15 .. r16 */
0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
@@ -387,6 +408,30 @@ static const __u8 initPas106[] = {
0x18, 0x10, 0x02, 0x02, 0x09, 0x07
};
/* compression 0x86 mckinit1 0x2b */
+
+/* "Known" PAS106B registers:
+ 0x02 clock divider
+ 0x03 Variable framerate bits 4-11
+ 0x04 Var framerate bits 0-3, one must leave the 4 msb's at 0 !!
+ The variable framerate control must never be set lower then 300,
+ which sets the framerate at 90 / reg02, otherwise vsync is lost.
+ 0x05 Shutter Time Line Offset, this can be used as an exposure control:
+ 0 = use full frame time, 255 = no exposure at all
+ Note this may never be larger then "var-framerate control" / 2 - 2.
+ When var-framerate control is < 514, no exposure is reached at the max
+ allowed value for the framerate control value, rather then at 255.
+ 0x06 Shutter Time Pixel Offset, like reg05 this influences exposure, but
+ only a very little bit, leave at 0xcd
+ 0x07 offset sign bit (bit0 1 > negative offset)
+ 0x08 offset
+ 0x09 Blue Gain
+ 0x0a Green1 Gain
+ 0x0b Green2 Gain
+ 0x0c Red Gain
+ 0x0e Global gain
+ 0x13 Write 1 to commit settings to sensor
+*/
+
static const __u8 pas106_sensor_init[][8] = {
/* Pixel Clock Divider 6 */
{ 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 },
@@ -433,37 +478,55 @@ static const __u8 initPas202[] = {
0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x03, 0x0a,
- 0x28, 0x1e, 0x28, 0x89, 0x20,
+ 0x28, 0x1e, 0x20, 0x89, 0x20,
0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
};
+
+/* "Known" PAS202BCB registers:
+ 0x02 clock divider
+ 0x04 Variable framerate bits 6-11 (*)
+ 0x05 Var framerate bits 0-5, one must leave the 2 msb's at 0 !!
+ 0x07 Blue Gain
+ 0x08 Green Gain
+ 0x09 Red Gain
+ 0x0b offset sign bit (bit0 1 > negative offset)
+ 0x0c offset
+ 0x0e Unknown image is slightly brighter when bit 0 is 0, if reg0f is 0 too,
+ leave at 1 otherwise we get a jump in our exposure control
+ 0x0f Exposure 0-255, 0 = use full frame time, 255 = no exposure at all
+ 0x10 Master gain 0 - 31
+ 0x11 write 1 to apply changes
+ (*) The variable framerate control must never be set lower then 500
+ which sets the framerate at 30 / reg02, otherwise vsync is lost.
+*/
static const __u8 pas202_sensor_init[][8] = {
- {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
+ /* Set the clock divider to 4 -> 30 / 4 = 7.5 fps, we would like
+ to set it lower, but for some reason the bridge starts missing
+ vsync's then */
+ {0xa0, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x10},
{0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
{0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
- {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
+ {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x01, 0x32, 0x10},
{0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
{0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
{0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
{0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
{0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
{0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
- {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
- {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
-
- {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
- {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
- {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
- {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
- {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
- {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
- {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
- {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
};
-static const __u8 initTas5110[] = {
+static const __u8 initTas5110c[] = {
0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00,
- 0x00, 0x01, 0x00, 0x45, 0x09, 0x0a,
+ 0x00, 0x00, 0x00, 0x45, 0x09, 0x0a,
+ 0x16, 0x12, 0x60, 0x86, 0x2b,
+ 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
+};
+/* Same as above, except a different hstart */
+static const __u8 initTas5110d[] = {
+ 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x41, 0x09, 0x0a,
0x16, 0x12, 0x60, 0x86, 0x2b,
0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
};
@@ -476,7 +539,7 @@ static const __u8 tas5110_sensor_init[][8] = {
static const __u8 initTas5130[] = {
0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00,
- 0x00, 0x01, 0x00, 0x68, 0x0c, 0x0a,
+ 0x00, 0x00, 0x00, 0x68, 0x0c, 0x0a,
0x28, 0x1e, 0x60, COMP, MCK_INIT,
0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
};
@@ -493,12 +556,14 @@ SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0),
SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
F_GAIN, 0, 0x21),
-SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ,
+SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_GAIN|F_SIF, NO_FREQ,
0),
-SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, 0,
- NO_EXPO|NO_FREQ, 0),
-SENS(initTas5110, NULL, tas5110_sensor_init, NULL, NULL, F_GAIN|F_SIF,
- NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, F_GAIN,
+ NO_FREQ, 0),
+SENS(initTas5110c, NULL, tas5110_sensor_init, NULL, NULL,
+ F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initTas5110d, NULL, tas5110_sensor_init, NULL, NULL,
+ F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0),
SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ,
0),
};
@@ -587,42 +652,28 @@ static void setbrightness(struct gspca_dev *gspca_dev)
goto err;
break;
}
- case SENSOR_PAS106: {
- __u8 i2c1[] =
- {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
-
- i2c1[3] = sd->brightness >> 3;
- i2c1[2] = 0x0e;
- if (i2c_w(gspca_dev, i2c1) < 0)
- goto err;
- i2c1[3] = 0x01;
- i2c1[2] = 0x13;
- if (i2c_w(gspca_dev, i2c1) < 0)
- goto err;
- break;
- }
+ case SENSOR_PAS106:
case SENSOR_PAS202: {
- /* __u8 i2cpexpo1[] =
- {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
- __u8 i2cpexpo[] =
- {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
- __u8 i2cp202[] =
- {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
- static __u8 i2cpdoit[] =
- {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
-
- /* change reg 0x10 */
- i2cpexpo[4] = 0xff - sd->brightness;
-/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
- goto err; */
-/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
- goto err; */
- if (i2c_w(gspca_dev, i2cpexpo) < 0)
- goto err;
- if (i2c_w(gspca_dev, i2cpdoit) < 0)
- goto err;
- i2cp202[3] = sd->brightness >> 3;
- if (i2c_w(gspca_dev, i2cp202) < 0)
+ __u8 i2cpbright[] =
+ {0xb0, 0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x16};
+ __u8 i2cpdoit[] =
+ {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16};
+
+ /* PAS106 uses reg 7 and 8 instead of b and c */
+ if (sd->sensor == SENSOR_PAS106) {
+ i2cpbright[2] = 7;
+ i2cpdoit[2] = 0x13;
+ }
+
+ if (sd->brightness < 127) {
+ /* change reg 0x0b, signreg */
+ i2cpbright[3] = 0x01;
+ /* set reg 0x0c, offset */
+ i2cpbright[4] = 127 - sd->brightness;
+ } else
+ i2cpbright[4] = sd->brightness - 127;
+
+ if (i2c_w(gspca_dev, i2cpbright) < 0)
goto err;
if (i2c_w(gspca_dev, i2cpdoit) < 0)
goto err;
@@ -652,7 +703,8 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
switch (sd->sensor) {
- case SENSOR_TAS5110: {
+ case SENSOR_TAS5110C:
+ case SENSOR_TAS5110D: {
__u8 i2c[] =
{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
@@ -674,6 +726,37 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
goto err;
break;
}
+ case SENSOR_PAS106:
+ case SENSOR_PAS202: {
+ __u8 i2cpgain[] =
+ {0xa0, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x15};
+ __u8 i2cpcolorgain[] =
+ {0xc0, 0x40, 0x07, 0x00, 0x00, 0x00, 0x00, 0x15};
+ __u8 i2cpdoit[] =
+ {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16};
+
+ /* PAS106 uses different regs (and has split green gains) */
+ if (sd->sensor == SENSOR_PAS106) {
+ i2cpgain[2] = 0x0e;
+ i2cpcolorgain[0] = 0xd0;
+ i2cpcolorgain[2] = 0x09;
+ i2cpdoit[2] = 0x13;
+ }
+
+ i2cpgain[3] = sd->gain >> 3;
+ i2cpcolorgain[3] = sd->gain >> 4;
+ i2cpcolorgain[4] = sd->gain >> 4;
+ i2cpcolorgain[5] = sd->gain >> 4;
+ i2cpcolorgain[6] = sd->gain >> 4;
+
+ if (i2c_w(gspca_dev, i2cpgain) < 0)
+ goto err;
+ if (i2c_w(gspca_dev, i2cpcolorgain) < 0)
+ goto err;
+ if (i2c_w(gspca_dev, i2cpdoit) < 0)
+ goto err;
+ break;
+ }
}
return;
err:
@@ -684,19 +767,21 @@ static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u8 gain;
- __u8 rgb_value;
+ __u8 buf[2] = { 0, 0 };
+
+ if (sensor_data[sd->sensor].flags & F_GAIN) {
+ /* Use the sensor gain to do the actual gain */
+ setsensorgain(gspca_dev);
+ return;
+ }
gain = sd->gain >> 4;
/* red and blue gain */
- rgb_value = gain << 4 | gain;
- reg_w(gspca_dev, 0x10, &rgb_value, 1);
+ buf[0] = gain << 4 | gain;
/* green gain */
- rgb_value = gain;
- reg_w(gspca_dev, 0x11, &rgb_value, 1);
-
- if (sensor_data[sd->sensor].flags & F_GAIN)
- setsensorgain(gspca_dev);
+ buf[1] = gain;
+ reg_w(gspca_dev, 0x10, buf, 2);
}
static void setexposure(struct gspca_dev *gspca_dev)
@@ -704,17 +789,12 @@ static void setexposure(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
switch (sd->sensor) {
- case SENSOR_TAS5110: {
- __u8 reg;
-
+ case SENSOR_TAS5110C:
+ case SENSOR_TAS5110D: {
/* register 19's high nibble contains the sn9c10x clock divider
The high nibble configures the no fps according to the
formula: 60 / high_nibble. With a maximum of 30 fps */
- reg = 120 * sd->exposure / 1000;
- if (reg < 2)
- reg = 2;
- else if (reg > 15)
- reg = 15;
+ __u8 reg = sd->exposure;
reg = (reg << 4) | 0x0b;
reg_w(gspca_dev, 0x19, &reg, 1);
break;
@@ -750,20 +830,21 @@ static void setexposure(struct gspca_dev *gspca_dev)
} else
reg10_max = 0x41;
- reg11 = (60 * sd->exposure + 999) / 1000;
+ reg11 = (15 * sd->exposure + 999) / 1000;
if (reg11 < 1)
reg11 = 1;
else if (reg11 > 16)
reg11 = 16;
- /* In 640x480, if the reg11 has less than 3, the image is
- unstable (not enough bandwidth). */
- if (gspca_dev->width == 640 && reg11 < 3)
- reg11 = 3;
+ /* In 640x480, if the reg11 has less than 4, the image is
+ unstable (the bridge goes into a higher compression mode
+ which we have not reverse engineered yet). */
+ if (gspca_dev->width == 640 && reg11 < 4)
+ reg11 = 4;
/* frame exposure time in ms = 1000 * reg11 / 30 ->
- reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
- reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
+ reg10 = (sd->exposure / 2) * reg10_max / (1000 * reg11 / 30) */
+ reg10 = (sd->exposure * 15 * reg10_max) / (1000 * reg11);
/* Don't allow this to get below 10 when using autogain, the
steps become very large (relatively) when below 10 causing
@@ -786,10 +867,85 @@ static void setexposure(struct gspca_dev *gspca_dev)
if (i2c_w(gspca_dev, i2c) == 0)
sd->reg11 = reg11;
else
- PDEBUG(D_ERR, "i2c error exposure");
+ goto err;
+ break;
+ }
+ case SENSOR_PAS202: {
+ __u8 i2cpframerate[] =
+ {0xb0, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x16};
+ __u8 i2cpexpo[] =
+ {0xa0, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x16};
+ const __u8 i2cpdoit[] =
+ {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16};
+ int framerate_ctrl;
+
+ /* The exposure knee for the autogain algorithm is 200
+ (100 ms / 10 fps on other sensors), for values below this
+ use the control for setting the partial frame expose time,
+ above that use variable framerate. This way we run at max
+ framerate (640x480@7.5 fps, 320x240@10fps) until the knee
+ is reached. Using the variable framerate control above 200
+ is better then playing around with both clockdiv + partial
+ frame exposure times (like we are doing with the ov chips),
+ as that sometimes leads to jumps in the exposure control,
+ which are bad for auto exposure. */
+ if (sd->exposure < 200) {
+ i2cpexpo[3] = 255 - (sd->exposure * 255) / 200;
+ framerate_ctrl = 500;
+ } else {
+ /* The PAS202's exposure control goes from 0 - 4095,
+ but anything below 500 causes vsync issues, so scale
+ our 200-1023 to 500-4095 */
+ framerate_ctrl = (sd->exposure - 200) * 1000 / 229 +
+ 500;
+ }
+
+ i2cpframerate[3] = framerate_ctrl >> 6;
+ i2cpframerate[4] = framerate_ctrl & 0x3f;
+ if (i2c_w(gspca_dev, i2cpframerate) < 0)
+ goto err;
+ if (i2c_w(gspca_dev, i2cpexpo) < 0)
+ goto err;
+ if (i2c_w(gspca_dev, i2cpdoit) < 0)
+ goto err;
+ break;
+ }
+ case SENSOR_PAS106: {
+ __u8 i2cpframerate[] =
+ {0xb1, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 0x14};
+ __u8 i2cpexpo[] =
+ {0xa1, 0x40, 0x05, 0x00, 0x00, 0x00, 0x00, 0x14};
+ const __u8 i2cpdoit[] =
+ {0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14};
+ int framerate_ctrl;
+
+ /* For values below 150 use partial frame exposure, above
+ that use framerate ctrl */
+ if (sd->exposure < 150) {
+ i2cpexpo[3] = 150 - sd->exposure;
+ framerate_ctrl = 300;
+ } else {
+ /* The PAS106's exposure control goes from 0 - 4095,
+ but anything below 300 causes vsync issues, so scale
+ our 150-1023 to 300-4095 */
+ framerate_ctrl = (sd->exposure - 150) * 1000 / 230 +
+ 300;
+ }
+
+ i2cpframerate[3] = framerate_ctrl >> 4;
+ i2cpframerate[4] = framerate_ctrl & 0x0f;
+ if (i2c_w(gspca_dev, i2cpframerate) < 0)
+ goto err;
+ if (i2c_w(gspca_dev, i2cpexpo) < 0)
+ goto err;
+ if (i2c_w(gspca_dev, i2cpdoit) < 0)
+ goto err;
break;
}
}
+ return;
+err:
+ PDEBUG(D_ERR, "i2c error exposure");
}
static void setfreq(struct gspca_dev *gspca_dev)
@@ -823,30 +979,43 @@ static void setfreq(struct gspca_dev *gspca_dev)
}
}
+#include "coarse_expo_autogain.h"
+
static void do_autogain(struct gspca_dev *gspca_dev)
{
- int deadzone, desired_avg_lum;
+ int deadzone, desired_avg_lum, result;
struct sd *sd = (struct sd *) gspca_dev;
int avg_lum = atomic_read(&sd->avg_lum);
- if (avg_lum == -1)
+ if (avg_lum == -1 || !sd->autogain)
return;
+ if (sd->autogain_ignore_frames > 0) {
+ sd->autogain_ignore_frames--;
+ return;
+ }
+
/* SIF / VGA sensors have a different autoexposure area and thus
different avg_lum values for the same picture brightness */
if (sensor_data[sd->sensor].flags & F_SIF) {
- deadzone = 1000;
- desired_avg_lum = 7000;
+ deadzone = 500;
+ /* SIF sensors tend to overexpose, so keep this small */
+ desired_avg_lum = 5000;
} else {
- deadzone = 3000;
- desired_avg_lum = 23000;
+ deadzone = 1500;
+ desired_avg_lum = 18000;
}
- if (sd->autogain_ignore_frames > 0)
- sd->autogain_ignore_frames--;
- else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
- sd->brightness * desired_avg_lum / 127,
- deadzone, GAIN_KNEE, EXPOSURE_KNEE)) {
+ if (sensor_data[sd->sensor].flags & F_COARSE_EXPO)
+ result = gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
+ sd->brightness * desired_avg_lum / 127,
+ deadzone);
+ else
+ result = gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
+ sd->brightness * desired_avg_lum / 127,
+ deadzone, GAIN_KNEE, EXPOSURE_KNEE);
+
+ if (result) {
PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d",
(int)sd->gain, (int)sd->exposure);
sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
@@ -881,7 +1050,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->brightness = BRIGHTNESS_DEF;
sd->gain = GAIN_DEF;
- sd->exposure = EXPOSURE_DEF;
+ if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) {
+ sd->exposure = COARSE_EXPOSURE_DEF;
+ gspca_dev->ctrl_dis |= (1 << EXPOSURE_IDX);
+ } else {
+ sd->exposure = EXPOSURE_DEF;
+ gspca_dev->ctrl_dis |= (1 << COARSE_EXPOSURE_IDX);
+ }
if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
sd->autogain = 0; /* Disable do_autogain callback */
else
@@ -917,9 +1092,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg12_19[6] = sn9c10x[0x18 - 1] | (mode << 4);
/* Special cases where reg 17 and or 19 value depends on mode */
switch (sd->sensor) {
- case SENSOR_PAS202:
- reg12_19[5] = mode ? 0x24 : 0x20;
- break;
case SENSOR_TAS5130CXX:
/* probably not mode specific at all most likely the upper
nibble of 0x19 is exposure (clock divider) just as with
@@ -955,6 +1127,16 @@ static int sd_start(struct gspca_dev *gspca_dev)
sensor_data[sd->sensor].sensor_bridge_init_size[
sd->bridge]);
+ /* Mode specific sensor setup */
+ switch (sd->sensor) {
+ case SENSOR_PAS202: {
+ const __u8 i2cpclockdiv[] =
+ {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10};
+ /* clockdiv from 4 to 3 (7.5 -> 10 fps) when in low res mode */
+ if (mode)
+ i2c_w(gspca_dev, i2cpclockdiv);
+ }
+ }
/* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
reg_w(gspca_dev, 0x15, &reg12_19[3], 2);
/* compression register */
@@ -985,6 +1167,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
sd->frames_to_drop = 0;
sd->autogain_ignore_frames = 0;
+ sd->exp_too_high_cnt = 0;
+ sd->exp_too_low_cnt = 0;
atomic_set(&sd->avg_lum, -1);
return 0;
}
@@ -1143,11 +1327,14 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
sd->autogain = val;
+ sd->exp_too_high_cnt = 0;
+ sd->exp_too_low_cnt = 0;
+
/* when switching to autogain set defaults to make sure
we are on a valid point of the autogain gain /
exposure knee graph, and give this change time to
take effect before doing autogain. */
- if (sd->autogain) {
+ if (sd->autogain && !(sensor_data[sd->sensor].flags & F_COARSE_EXPO)) {
sd->exposure = EXPOSURE_DEF;
sd->gain = GAIN_DEF;
if (gspca_dev->streaming) {
@@ -1207,6 +1394,25 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
return -EINVAL;
}
+#ifdef CONFIG_INPUT
+static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* interrupt packet data */
+ int len) /* interrupt packet length */
+{
+ int ret = -EINVAL;
+
+ if (len == 1 && data[0] == 1) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+ input_sync(gspca_dev->input_dev);
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ ret = 0;
+ }
+
+ return ret;
+}
+#endif
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -1219,6 +1425,9 @@ static const struct sd_desc sd_desc = {
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
.dq_callback = do_autogain,
+#ifdef CONFIG_INPUT
+ .int_pkt_scan = sd_int_pkt_scan,
+#endif
};
/* -- module initialisation -- */
@@ -1227,21 +1436,21 @@ static const struct sd_desc sd_desc = {
static const struct usb_device_id device_table[] __devinitconst = {
- {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110, 102)}, /* TAS5110C1B */
- {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110, 101)}, /* TAS5110C1B */
+ {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110C, 102)}, /* TAS5110C1B */
+ {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110C, 101)}, /* TAS5110C1B */
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
- {USB_DEVICE(0x0c45, 0x6007), SB(TAS5110, 101)}, /* TAS5110D */
+ {USB_DEVICE(0x0c45, 0x6007), SB(TAS5110D, 101)}, /* TAS5110D */
+#endif
{USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)},
{USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
-#endif
{USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
{USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
{USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
+#endif
{USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)},
{USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
-#endif
{USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
{USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 0bd36a00dd2a..83d5773d4629 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -21,6 +21,7 @@
#define MODULE_NAME "sonixj"
+#include <linux/input.h>
#include "gspca.h"
#include "jpeg.h"
@@ -45,6 +46,7 @@ struct sd {
u8 red;
u8 gamma;
u8 vflip; /* ov7630/ov7648 only */
+ u8 sharpness;
u8 infrared; /* mt9v111 only */
u8 freq; /* ov76xx only */
u8 quality; /* image quality */
@@ -64,16 +66,17 @@ struct sd {
#define BRIDGE_SN9C110 2
#define BRIDGE_SN9C120 3
u8 sensor; /* Type of image sensor chip */
-#define SENSOR_HV7131R 0
-#define SENSOR_MI0360 1
-#define SENSOR_MO4000 2
-#define SENSOR_MT9V111 3
-#define SENSOR_OM6802 4
-#define SENSOR_OV7630 5
-#define SENSOR_OV7648 6
-#define SENSOR_OV7660 7
-#define SENSOR_PO1030 8
-#define SENSOR_SP80708 9
+#define SENSOR_ADCM1700 0
+#define SENSOR_HV7131R 1
+#define SENSOR_MI0360 2
+#define SENSOR_MO4000 3
+#define SENSOR_MT9V111 4
+#define SENSOR_OM6802 5
+#define SENSOR_OV7630 6
+#define SENSOR_OV7648 7
+#define SENSOR_OV7660 8
+#define SENSOR_PO1030 9
+#define SENSOR_SP80708 10
u8 i2c_addr;
u8 *jpeg_hdr;
@@ -96,12 +99,14 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
#define BRIGHTNESS_IDX 0
{
{
@@ -225,8 +230,23 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setvflip,
.get = sd_getvflip,
},
+#define SHARPNESS_IDX 8
+ {
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sharpness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define SHARPNESS_DEF 90
+ .default_value = SHARPNESS_DEF,
+ },
+ .set = sd_setsharpness,
+ .get = sd_getsharpness,
+ },
/* mt9v111 only */
-#define INFRARED_IDX 8
+#define INFRARED_IDX 9
{
{
.id = V4L2_CID_INFRARED,
@@ -242,7 +262,7 @@ static struct ctrl sd_ctrls[] = {
.get = sd_getinfrared,
},
/* ov7630/ov7648/ov7660 only */
-#define FREQ_IDX 9
+#define FREQ_IDX 10
{
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -261,28 +281,37 @@ static struct ctrl sd_ctrls[] = {
/* table of the disabled controls */
static __u32 ctrl_dis[] = {
+ (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX) |
+ (1 << AUTOGAIN_IDX), /* SENSOR_ADCM1700 0 */
+ (1 << INFRARED_IDX) | (1 << FREQ_IDX),
+ /* SENSOR_HV7131R 1 */
(1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
- /* SENSOR_HV7131R 0 */
+ /* SENSOR_MI0360 2 */
(1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
- /* SENSOR_MI0360 1 */
- (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
- /* SENSOR_MO4000 2 */
+ /* SENSOR_MO4000 3 */
(1 << VFLIP_IDX) | (1 << FREQ_IDX),
- /* SENSOR_MT9V111 3 */
+ /* SENSOR_MT9V111 4 */
(1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
- /* SENSOR_OM6802 4 */
+ /* SENSOR_OM6802 5 */
(1 << INFRARED_IDX),
- /* SENSOR_OV7630 5 */
+ /* SENSOR_OV7630 6 */
(1 << INFRARED_IDX),
- /* SENSOR_OV7648 6 */
+ /* SENSOR_OV7648 7 */
(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
- /* SENSOR_OV7660 7 */
+ /* SENSOR_OV7660 8 */
(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX) |
- (1 << FREQ_IDX), /* SENSOR_PO1030 8 */
+ (1 << FREQ_IDX), /* SENSOR_PO1030 9 */
(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX) |
- (1 << FREQ_IDX), /* SENSOR_SP80708 9 */
+ (1 << FREQ_IDX), /* SENSOR_SP80708 10 */
};
+static const struct v4l2_pix_format cif_mode[] = {
+ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 4 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
static const struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 160,
@@ -302,6 +331,17 @@ static const struct v4l2_pix_format vga_mode[] = {
.priv = 0},
};
+static const u8 sn_adcm1700[0x1c] = {
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
+ 0x00, 0x43, 0x60, 0x00, 0x1a, 0x00, 0x00, 0x00,
+/* reg8 reg9 rega regb regc regd rege regf */
+ 0x80, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
+ 0x03, 0x00, 0x05, 0x01, 0x05, 0x16, 0x12, 0x42,
+/* reg18 reg19 reg1a reg1b */
+ 0x06, 0x00, 0x00, 0x00
+};
+
/*Data from sn9c102p+hv7131r */
static const u8 sn_hv7131[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
@@ -415,6 +455,7 @@ static const u8 sn_sp80708[0x1c] = {
/* sequence specific to the sensors - !! index = SENSOR_xxx */
static const u8 *sn_tb[] = {
+ sn_adcm1700,
sn_hv7131,
sn_mi0360,
sn_mo4000,
@@ -432,6 +473,11 @@ static const u8 gamma_def[17] = {
0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
};
+/* gamma for sensor ADCM1700 */
+static const u8 gamma_spec_0[17] = {
+ 0x0f, 0x39, 0x5a, 0x74, 0x86, 0x95, 0xa6, 0xb4,
+ 0xbd, 0xc4, 0xcc, 0xd4, 0xd5, 0xde, 0xe4, 0xed, 0xf5
+};
/* gamma for sensors HV7131R and MT9V111 */
static const u8 gamma_spec_1[17] = {
0x08, 0x3a, 0x52, 0x65, 0x75, 0x83, 0x91, 0x9d,
@@ -450,6 +496,42 @@ static const u8 reg84[] = {
0x3e, 0x00, 0xcd, 0x0f, 0xf7, 0x0f, /* VR VG VB */
0x00, 0x00, 0x00 /* YUV offsets */
};
+static const u8 adcm1700_sensor_init[][8] = {
+ {0xa0, 0x51, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xb0, 0x51, 0x04, 0x08, 0x00, 0x00, 0x00, 0x10}, /* reset */
+ {0xdd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xb0, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xdd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xb0, 0x51, 0x0c, 0xe0, 0x2e, 0x00, 0x00, 0x10},
+ {0xb0, 0x51, 0x10, 0x02, 0x02, 0x00, 0x00, 0x10},
+ {0xb0, 0x51, 0x14, 0x0e, 0x0e, 0x00, 0x00, 0x10},
+ {0xb0, 0x51, 0x1c, 0x00, 0x80, 0x00, 0x00, 0x10},
+ {0xb0, 0x51, 0x20, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xdd, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xb0, 0x51, 0x04, 0x04, 0x00, 0x00, 0x00, 0x10},
+ {0xdd, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xb0, 0x51, 0x04, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xa0, 0x51, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x10},
+ {0xb0, 0x51, 0x14, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xb0, 0x51, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {}
+};
+static const u8 adcm1700_sensor_param1[][8] = {
+ {0xb0, 0x51, 0x26, 0xf9, 0x01, 0x00, 0x00, 0x10}, /* exposure? */
+ {0xd0, 0x51, 0x1e, 0x8e, 0x8e, 0x8e, 0x8e, 0x10},
+
+ {0xa0, 0x51, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xb0, 0x51, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10},
+ {0xa0, 0x51, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x10},
+ {0xb0, 0x51, 0x32, 0x00, 0x72, 0x00, 0x00, 0x10},
+ {0xd0, 0x51, 0x1e, 0xbe, 0xd7, 0xe8, 0xbe, 0x10}, /* exposure? */
+
+ {0xa0, 0x51, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xb0, 0x51, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10},
+ {0xa0, 0x51, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x10},
+ {0xb0, 0x51, 0x32, 0x00, 0xa2, 0x00, 0x00, 0x10},
+ {}
+};
static const u8 hv7131r_sensor_init[][8] = {
{0xc1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
{0xb1, 0x11, 0x34, 0x17, 0x7f, 0x00, 0x00, 0x10},
@@ -986,17 +1068,18 @@ static const u8 sp80708_sensor_param1[][8] = {
{}
};
-static const u8 (*sensor_init[10])[8] = {
- hv7131r_sensor_init, /* HV7131R 0 */
- mi0360_sensor_init, /* MI0360 1 */
- mo4000_sensor_init, /* MO4000 2 */
- mt9v111_sensor_init, /* MT9V111 3 */
- om6802_sensor_init, /* OM6802 4 */
- ov7630_sensor_init, /* OV7630 5 */
- ov7648_sensor_init, /* OV7648 6 */
- ov7660_sensor_init, /* OV7660 7 */
- po1030_sensor_init, /* PO1030 8 */
- sp80708_sensor_init, /* SP80708 9 */
+static const u8 (*sensor_init[11])[8] = {
+ adcm1700_sensor_init, /* ADCM1700 0 */
+ hv7131r_sensor_init, /* HV7131R 1 */
+ mi0360_sensor_init, /* MI0360 2 */
+ mo4000_sensor_init, /* MO4000 3 */
+ mt9v111_sensor_init, /* MT9V111 4 */
+ om6802_sensor_init, /* OM6802 5 */
+ ov7630_sensor_init, /* OV7630 6 */
+ ov7648_sensor_init, /* OV7648 7 */
+ ov7660_sensor_init, /* OV7660 8 */
+ po1030_sensor_init, /* PO1030 9 */
+ sp80708_sensor_init, /* SP80708 10 */
};
/* read <len> bytes to gspca_dev->usb_buf */
@@ -1064,6 +1147,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
PDEBUG(D_USBO, "i2c_w2 [%02x] = %02x", reg, val);
switch (sd->sensor) {
+ case SENSOR_ADCM1700:
case SENSOR_OM6802: /* i2c command = a0 (100 kHz) */
gspca_dev->usb_buf[0] = 0x80 | (2 << 4);
break;
@@ -1110,6 +1194,7 @@ static void i2c_r(struct gspca_dev *gspca_dev, u8 reg, int len)
u8 mode[8];
switch (sd->sensor) {
+ case SENSOR_ADCM1700:
case SENSOR_OM6802: /* i2c command = 90 (100 kHz) */
mode[0] = 0x80 | 0x10;
break;
@@ -1260,7 +1345,8 @@ static void bridge_init(struct gspca_dev *gspca_dev,
{0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
static const u8 regd4[] = {0x60, 0x00, 0x00};
- reg_w1(gspca_dev, 0xf1, 0x00);
+ /* sensor clock already enabled in sd_init */
+ /* reg_w1(gspca_dev, 0xf1, 0x00); */
reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
/* configure gpio */
@@ -1284,6 +1370,12 @@ static void bridge_init(struct gspca_dev *gspca_dev,
reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
switch (sd->sensor) {
+ case SENSOR_ADCM1700:
+ reg_w1(gspca_dev, 0x01, 0x43);
+ reg_w1(gspca_dev, 0x17, 0x62);
+ reg_w1(gspca_dev, 0x01, 0x42);
+ reg_w1(gspca_dev, 0x01, 0x42);
+ break;
case SENSOR_MT9V111:
reg_w1(gspca_dev, 0x01, 0x61);
reg_w1(gspca_dev, 0x17, 0x61);
@@ -1357,14 +1449,19 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
- cam = &gspca_dev->cam;
- cam->cam_mode = vga_mode;
- cam->nmodes = ARRAY_SIZE(vga_mode);
- cam->npkt = 24; /* 24 packets per ISOC message */
-
sd->bridge = id->driver_info >> 16;
sd->sensor = id->driver_info;
+ cam = &gspca_dev->cam;
+ if (sd->sensor == SENSOR_ADCM1700) {
+ cam->cam_mode = cif_mode;
+ cam->nmodes = ARRAY_SIZE(cif_mode);
+ } else {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+ }
+ cam->npkt = 24; /* 24 packets per ISOC message */
+
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
@@ -1374,6 +1471,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->autogain = AUTOGAIN_DEF;
sd->ag_cnt = -1;
sd->vflip = VFLIP_DEF;
+ switch (sd->sensor) {
+ case SENSOR_OM6802:
+ sd->sharpness = 0x10;
+ break;
+ default:
+ sd->sharpness = SHARPNESS_DEF;
+ break;
+ }
sd->infrared = INFRARED_DEF;
sd->freq = FREQ_DEF;
sd->quality = QUALITY_DEF;
@@ -1433,7 +1538,9 @@ static int sd_init(struct gspca_dev *gspca_dev)
break;
}
- reg_w1(gspca_dev, 0xf1, 0x01);
+ /* Note we do not disable the sensor clock here (power saving mode),
+ as that also disables the button on the cam. */
+ reg_w1(gspca_dev, 0xf1, 0x00);
/* set the i2c address */
sn9c1xx = sn_tb[sd->sensor];
@@ -1543,6 +1650,10 @@ static void setbrightness(struct gspca_dev *gspca_dev)
k2 = ((int) sd->brightness - 0x8000) >> 10;
switch (sd->sensor) {
+ case SENSOR_ADCM1700:
+ if (k2 > 0x1f)
+ k2 = 0; /* only positive Y offset */
+ break;
case SENSOR_HV7131R:
expo = sd->brightness << 4;
if (expo > 0x002dc6c0)
@@ -1625,6 +1736,9 @@ static void setgamma(struct gspca_dev *gspca_dev)
};
switch (sd->sensor) {
+ case SENSOR_ADCM1700:
+ gamma_base = gamma_spec_0;
+ break;
case SENSOR_HV7131R:
case SENSOR_MT9V111:
gamma_base = gamma_spec_1;
@@ -1670,23 +1784,39 @@ static void setautogain(struct gspca_dev *gspca_dev)
sd->ag_cnt = -1;
}
-/* ov7630/ov7648 only */
+/* hv7131r/ov7630/ov7648 only */
static void setvflip(struct sd *sd)
{
u8 comn;
if (sd->gspca_dev.ctrl_dis & (1 << VFLIP_IDX))
return;
- if (sd->sensor == SENSOR_OV7630) {
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ comn = 0x18; /* clkdiv = 1, ablcen = 1 */
+ if (sd->vflip)
+ comn |= 0x01;
+ i2c_w1(&sd->gspca_dev, 0x01, comn); /* sctra */
+ break;
+ case SENSOR_OV7630:
comn = 0x02;
if (!sd->vflip)
comn |= 0x80;
- } else {
+ i2c_w1(&sd->gspca_dev, 0x75, comn);
+ break;
+ default:
+/* case SENSOR_OV7648: */
comn = 0x06;
if (sd->vflip)
comn |= 0x80;
+ i2c_w1(&sd->gspca_dev, 0x75, comn);
+ break;
}
- i2c_w1(&sd->gspca_dev, 0x75, comn);
+}
+
+static void setsharpness(struct sd *sd)
+{
+ reg_w1(&sd->gspca_dev, 0x99, sd->sharpness);
}
static void setinfrared(struct sd *sd)
@@ -1804,6 +1934,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
int mode;
static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
+ static const u8 CA_adcm1700[] =
+ { 0x14, 0xec, 0x0a, 0xf6 };
static const u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */
static const u8 CE_ov76xx[] =
{ 0x32, 0xdd, 0x32, 0xdd };
@@ -1824,6 +1956,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
i2c_w_seq(gspca_dev, sensor_init[sd->sensor]);
switch (sd->sensor) {
+ case SENSOR_ADCM1700:
+ reg2 = 0x60;
+ break;
case SENSOR_OM6802:
reg2 = 0x71;
break;
@@ -1842,17 +1977,28 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]);
reg_w1(gspca_dev, 0x13, sn9c1xx[0x13]);
reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
- reg_w1(gspca_dev, 0xd2, 0x6a); /* DC29 */
- reg_w1(gspca_dev, 0xd3, 0x50);
+ if (sd->sensor == SENSOR_ADCM1700) {
+ reg_w1(gspca_dev, 0xd2, 0x3a); /* AE_H_SIZE = 116 */
+ reg_w1(gspca_dev, 0xd3, 0x30); /* AE_V_SIZE = 96 */
+ } else {
+ reg_w1(gspca_dev, 0xd2, 0x6a); /* AE_H_SIZE = 212 */
+ reg_w1(gspca_dev, 0xd3, 0x50); /* AE_V_SIZE = 160 */
+ }
reg_w1(gspca_dev, 0xc6, 0x00);
reg_w1(gspca_dev, 0xc7, 0x00);
- reg_w1(gspca_dev, 0xc8, 0x50);
- reg_w1(gspca_dev, 0xc9, 0x3c);
+ if (sd->sensor == SENSOR_ADCM1700) {
+ reg_w1(gspca_dev, 0xc8, 0x2c); /* AW_H_STOP = 352 */
+ reg_w1(gspca_dev, 0xc9, 0x24); /* AW_V_STOP = 288 */
+ } else {
+ reg_w1(gspca_dev, 0xc8, 0x50); /* AW_H_STOP = 640 */
+ reg_w1(gspca_dev, 0xc9, 0x3c); /* AW_V_STOP = 480 */
+ }
reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
switch (sd->sensor) {
case SENSOR_MT9V111:
reg17 = 0xe0;
break;
+ case SENSOR_ADCM1700:
case SENSOR_OV7630:
reg17 = 0xe2;
break;
@@ -1870,44 +2016,39 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
}
reg_w1(gspca_dev, 0x17, reg17);
-/* set reg1 was here */
- reg_w1(gspca_dev, 0x05, sn9c1xx[5]); /* red */
- reg_w1(gspca_dev, 0x07, sn9c1xx[7]); /* green */
- reg_w1(gspca_dev, 0x06, sn9c1xx[6]); /* blue */
+
+ reg_w1(gspca_dev, 0x05, 0x00); /* red */
+ reg_w1(gspca_dev, 0x07, 0x00); /* green */
+ reg_w1(gspca_dev, 0x06, 0x00); /* blue */
reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]);
setgamma(gspca_dev);
+/*fixme: 8 times with all zeroes and 1 or 2 times with normal values */
for (i = 0; i < 8; i++)
reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
switch (sd->sensor) {
+ case SENSOR_ADCM1700:
+ case SENSOR_OV7660:
+ case SENSOR_SP80708:
+ reg_w1(gspca_dev, 0x9a, 0x05);
+ break;
case SENSOR_MT9V111:
reg_w1(gspca_dev, 0x9a, 0x07);
- reg_w1(gspca_dev, 0x99, 0x59);
- break;
- case SENSOR_OM6802:
- reg_w1(gspca_dev, 0x9a, 0x08);
- reg_w1(gspca_dev, 0x99, 0x10);
break;
case SENSOR_OV7648:
reg_w1(gspca_dev, 0x9a, 0x0a);
- reg_w1(gspca_dev, 0x99, 0x60);
- break;
- case SENSOR_OV7660:
- case SENSOR_SP80708:
- reg_w1(gspca_dev, 0x9a, 0x05);
- reg_w1(gspca_dev, 0x99, 0x59);
break;
default:
reg_w1(gspca_dev, 0x9a, 0x08);
- reg_w1(gspca_dev, 0x99, 0x59);
break;
}
+ setsharpness(sd);
reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
- reg_w1(gspca_dev, 0x05, sn9c1xx[5]); /* red */
- reg_w1(gspca_dev, 0x07, sn9c1xx[7]); /* green */
- reg_w1(gspca_dev, 0x06, sn9c1xx[6]); /* blue */
+ reg_w1(gspca_dev, 0x05, 0x20); /* red */
+ reg_w1(gspca_dev, 0x07, 0x20); /* green */
+ reg_w1(gspca_dev, 0x06, 0x20); /* blue */
init = NULL;
mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
@@ -1917,6 +2058,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg1 = 0x06; /* 640x480: clk 24Mhz, video trf enable */
reg17 = 0x61; /* 0x:20: enable sensor clock */
switch (sd->sensor) {
+ case SENSOR_ADCM1700:
+ init = adcm1700_sensor_param1;
+ reg1 = 0x46;
+ reg17 = 0xe2;
+ break;
case SENSOR_MO4000:
if (mode) {
/* reg1 = 0x46; * 320 clk 48Mhz 60fp/s */
@@ -1940,7 +2086,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg17 = 0x64; /* 640 MCKSIZE */
break;
case SENSOR_OV7630:
- setvflip(sd);
reg17 = 0xe2;
reg1 = 0x44;
break;
@@ -1986,8 +2131,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
reg_w(gspca_dev, 0xc0, C0, 6);
- reg_w(gspca_dev, 0xca, CA, 4);
+ if (sd->sensor == SENSOR_ADCM1700)
+ reg_w(gspca_dev, 0xca, CA_adcm1700, 4);
+ else
+ reg_w(gspca_dev, 0xca, CA, 4);
switch (sd->sensor) {
+ case SENSOR_ADCM1700:
case SENSOR_OV7630:
case SENSOR_OV7648:
case SENSOR_OV7660:
@@ -2008,11 +2157,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x17, reg17);
reg_w1(gspca_dev, 0x01, reg1);
- switch (sd->sensor) {
- case SENSOR_OV7630:
- setvflip(sd);
- break;
- }
+ setvflip(sd);
setbrightness(gspca_dev);
setcontrast(gspca_dev);
setautogain(gspca_dev);
@@ -2056,7 +2201,8 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]);
reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
reg_w1(gspca_dev, 0x01, data);
- reg_w1(gspca_dev, 0xf1, 0x00);
+ /* Don't disable sensor clock as that disables the button on the cam */
+ /* reg_w1(gspca_dev, 0xf1, 0x01); */
}
static void sd_stop0(struct gspca_dev *gspca_dev)
@@ -2288,6 +2434,24 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->sharpness = val;
+ if (gspca_dev->streaming)
+ setsharpness(sd);
+ return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->sharpness;
+ return 0;
+}
+
static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2391,6 +2555,25 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
return -EINVAL;
}
+#ifdef CONFIG_INPUT
+static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* interrupt packet data */
+ int len) /* interrupt packet length */
+{
+ int ret = -EINVAL;
+
+ if (len == 1 && data[0] == 1) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+ input_sync(gspca_dev->input_dev);
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ ret = 0;
+ }
+
+ return ret;
+}
+#endif
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -2406,6 +2589,9 @@ static const struct sd_desc sd_desc = {
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
.querymenu = sd_querymenu,
+#ifdef CONFIG_INPUT
+ .int_pkt_scan = sd_int_pkt_scan,
+#endif
};
/* -- module initialisation -- */
@@ -2472,6 +2658,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
/* {USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)}, *sn9c120b*/
{USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)}, /*sn9c120b*/
{USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)}, /*sn9c120b*/
+ {USB_DEVICE(0x0c45, 0x614a), BS(SN9C120, ADCM1700)}, /*sn9c120b*/
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
index fe46868a87f2..b866c73c97db 100644
--- a/drivers/media/video/gspca/spca500.c
+++ b/drivers/media/video/gspca/spca500.c
@@ -68,7 +68,7 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
@@ -1047,7 +1047,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
}
/* sub-driver description */
-static struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
index 6761a3048a98..c99333933e32 100644
--- a/drivers/media/video/gspca/spca501.c
+++ b/drivers/media/video/gspca/spca501.c
@@ -59,7 +59,7 @@ static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
#define MY_BRIGHTNESS 0
{
{
diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c
index 0f9232ff1281..c576eed73abe 100644
--- a/drivers/media/video/gspca/spca505.c
+++ b/drivers/media/video/gspca/spca505.c
@@ -42,7 +42,7 @@ struct sd {
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c
index 39257e4e074f..89fec4c500af 100644
--- a/drivers/media/video/gspca/spca506.c
+++ b/drivers/media/video/gspca/spca506.c
@@ -51,7 +51,7 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
#define SD_BRIGHTNESS 0
{
{
@@ -673,7 +673,7 @@ static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
}
/* sub-driver description */
-static struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
index 4d8e6cf75d55..15b2eef8a3f6 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/video/gspca/spca508.c
@@ -45,7 +45,7 @@ struct sd {
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index 58c2f0039af1..dc7f2b0fbc79 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -922,7 +922,7 @@ static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
}
/* control tables */
-static struct ctrl sd_ctrls_12a[] = {
+static const struct ctrl sd_ctrls_12a[] = {
{
{
.id = V4L2_CID_HUE,
@@ -964,7 +964,7 @@ static struct ctrl sd_ctrls_12a[] = {
},
};
-static struct ctrl sd_ctrls_72a[] = {
+static const struct ctrl sd_ctrls_72a[] = {
{
{
.id = V4L2_CID_HUE,
diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c
index d70b156872d6..e64662052992 100644
--- a/drivers/media/video/gspca/sq905c.c
+++ b/drivers/media/video/gspca/sq905c.c
@@ -47,6 +47,7 @@ MODULE_LICENSE("GPL");
/* Commands. These go in the "value" slot. */
#define SQ905C_CLEAR 0xa0 /* clear everything */
+#define SQ905C_GET_ID 0x14f4 /* Read version number */
#define SQ905C_CAPTURE_LOW 0xa040 /* Starts capture at 160x120 */
#define SQ905C_CAPTURE_MED 0x1440 /* Starts capture at 320x240 */
#define SQ905C_CAPTURE_HI 0x2840 /* Starts capture at 320x240 */
@@ -101,6 +102,26 @@ static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index)
return 0;
}
+static int sq905c_read(struct gspca_dev *gspca_dev, u16 command, u16 index,
+ int size)
+{
+ int ret;
+
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ USB_REQ_SYNCH_FRAME, /* request */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ command, index, gspca_dev->usb_buf, size,
+ SQ905C_CMD_TIMEOUT);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/* This function is called as a workqueue function and runs whenever the camera
* is streaming data. Because it is a workqueue function it is allowed to sleep
* so we can use synchronous USB calls. To avoid possible collisions with other
@@ -183,13 +204,34 @@ static int sd_config(struct gspca_dev *gspca_dev,
{
struct cam *cam = &gspca_dev->cam;
struct sd *dev = (struct sd *) gspca_dev;
+ int ret;
PDEBUG(D_PROBE,
"SQ9050 camera detected"
" (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+
+ ret = sq905c_command(gspca_dev, SQ905C_GET_ID, 0);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "Get version command failed");
+ return ret;
+ }
+
+ ret = sq905c_read(gspca_dev, 0xf5, 0, 20);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "Reading version command failed");
+ return ret;
+ }
+ /* Note we leave out the usb id and the manufacturing date */
+ PDEBUG(D_PROBE,
+ "SQ9050 ID string: %02x - %02x %02x %02x %02x %02x %02x",
+ gspca_dev->usb_buf[3],
+ gspca_dev->usb_buf[14], gspca_dev->usb_buf[15],
+ gspca_dev->usb_buf[16], gspca_dev->usb_buf[17],
+ gspca_dev->usb_buf[18], gspca_dev->usb_buf[19]);
+
cam->cam_mode = sq905c_mode;
cam->nmodes = 2;
- if (id->idProduct == 0x9050)
+ if (gspca_dev->usb_buf[15] == 0)
cam->nmodes = 1;
/* We don't use the buffer gspca allocates so make it small. */
cam->bulk_size = 32;
@@ -258,6 +300,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x2770, 0x905c)},
{USB_DEVICE(0x2770, 0x9050)},
+ {USB_DEVICE(0x2770, 0x9052)},
{USB_DEVICE(0x2770, 0x913d)},
{}
};
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
index 2e2935532d99..0fb534210a2c 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/video/gspca/stk014.c
@@ -53,7 +53,7 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
diff --git a/drivers/media/video/gspca/stv0680.c b/drivers/media/video/gspca/stv0680.c
index 2a69d7ccb50d..e50dd7693f74 100644
--- a/drivers/media/video/gspca/stv0680.c
+++ b/drivers/media/video/gspca/stv0680.c
@@ -45,7 +45,7 @@ struct sd {
};
/* V4L2 controls supported by the driver */
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
};
static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val,
@@ -53,24 +53,28 @@ static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val,
{
int ret = -1;
u8 req_type = 0;
+ unsigned int pipe = 0;
switch (set) {
case 0: /* 0xc1 */
req_type = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
+ pipe = usb_rcvctrlpipe(gspca_dev->dev, 0);
break;
case 1: /* 0x41 */
req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
+ pipe = usb_sndctrlpipe(gspca_dev->dev, 0);
break;
case 2: /* 0x80 */
req_type = USB_DIR_IN | USB_RECIP_DEVICE;
+ pipe = usb_rcvctrlpipe(gspca_dev->dev, 0);
break;
case 3: /* 0x40 */
req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ pipe = usb_sndctrlpipe(gspca_dev->dev, 0);
break;
}
- ret = usb_control_msg(gspca_dev->dev,
- usb_rcvctrlpipe(gspca_dev->dev, 0),
+ ret = usb_control_msg(gspca_dev->dev, pipe,
req, req_type,
val, 0, gspca_dev->usb_buf, size, 500);
@@ -138,6 +142,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam = &gspca_dev->cam;
+ /* Give the camera some time to settle, otherwise initalization will
+ fail on hotplug, and yes it really needs a full second. */
+ msleep(1000);
+
/* ping camera to be sure STV0680 is present */
if (stv_sndctrl(gspca_dev, 0, 0x88, 0x5678, 0x02) != 0x02 ||
gspca_dev->usb_buf[0] != 0x56 || gspca_dev->usb_buf[1] != 0x78) {
@@ -169,6 +177,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
PDEBUG(D_PROBE, "Camera supports CIF mode");
if (gspca_dev->usb_buf[7] & 0x02)
PDEBUG(D_PROBE, "Camera supports VGA mode");
+ if (gspca_dev->usb_buf[7] & 0x04)
+ PDEBUG(D_PROBE, "Camera supports QCIF mode");
if (gspca_dev->usb_buf[7] & 0x08)
PDEBUG(D_PROBE, "Camera supports QVGA mode");
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
index 5d0241bb1611..af73da34c83f 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -27,6 +27,7 @@
* P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web
*/
+#include <linux/input.h>
#include "stv06xx_sensor.h"
MODULE_AUTHOR("Erik Andrén");
@@ -219,6 +220,7 @@ static void stv06xx_dump_bridge(struct sd *sd)
info("Read 0x%x from address 0x%x", data, i);
}
+ info("Testing stv06xx bridge registers for writability");
for (i = 0x1400; i < 0x160f; i++) {
stv06xx_read_bridge(sd, i, &data);
buf = data;
@@ -229,7 +231,7 @@ static void stv06xx_dump_bridge(struct sd *sd)
info("Register 0x%x is read/write", i);
else if (data != buf)
info("Register 0x%x is read/write,"
- "but only partially", i);
+ " but only partially", i);
else
info("Register 0x%x is read-only", i);
@@ -426,6 +428,29 @@ frame_data:
}
}
+#ifdef CONFIG_INPUT
+static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* interrupt packet data */
+ int len) /* interrupt packet length */
+{
+ int ret = -EINVAL;
+
+ if (len == 1 && data[0] == 0x80) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+ input_sync(gspca_dev->input_dev);
+ ret = 0;
+ }
+
+ if (len == 1 && data[0] == 0x88) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ ret = 0;
+ }
+
+ return ret;
+}
+#endif
+
static int stv06xx_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id);
@@ -436,7 +461,10 @@ static const struct sd_desc sd_desc = {
.init = stv06xx_init,
.start = stv06xx_start,
.stopN = stv06xx_stopN,
- .pkt_scan = stv06xx_pkt_scan
+ .pkt_scan = stv06xx_pkt_scan,
+#ifdef CONFIG_INPUT
+ .int_pkt_scan = sd_int_pkt_scan,
+#endif
};
/* This function is called at probe time */
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
index 487d40555343..96c61926d372 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
@@ -228,6 +228,7 @@ static const struct stv_init stv_bridge_init[] = {
/* This reg is written twice. Some kind of reset? */
{NULL, 0x1620, 0x80},
{NULL, 0x1620, 0x00},
+ {NULL, 0x1443, 0x00},
{NULL, 0x1423, 0x04},
{x1500, 0x1500, ARRAY_SIZE(x1500)},
{x1536, 0x1536, ARRAY_SIZE(x1536)},
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index 716df6b15fc5..0c786e00ebcf 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -67,7 +67,7 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
@@ -267,142 +267,6 @@ static const struct cmd spca504A_clicksmart420_open_data[] = {
{0x06, 0x0000, 0x0000},
{0x00, 0x0004, 0x2880},
{0x00, 0x0001, 0x2881},
-/* look like setting a qTable */
- {0x00, 0x0006, 0x2800},
- {0x00, 0x0004, 0x2801},
- {0x00, 0x0004, 0x2802},
- {0x00, 0x0006, 0x2803},
- {0x00, 0x000a, 0x2804},
- {0x00, 0x0010, 0x2805},
- {0x00, 0x0014, 0x2806},
- {0x00, 0x0018, 0x2807},
- {0x00, 0x0005, 0x2808},
- {0x00, 0x0005, 0x2809},
- {0x00, 0x0006, 0x280a},
- {0x00, 0x0008, 0x280b},
- {0x00, 0x000a, 0x280c},
- {0x00, 0x0017, 0x280d},
- {0x00, 0x0018, 0x280e},
- {0x00, 0x0016, 0x280f},
-
- {0x00, 0x0006, 0x2810},
- {0x00, 0x0005, 0x2811},
- {0x00, 0x0006, 0x2812},
- {0x00, 0x000a, 0x2813},
- {0x00, 0x0010, 0x2814},
- {0x00, 0x0017, 0x2815},
- {0x00, 0x001c, 0x2816},
- {0x00, 0x0016, 0x2817},
- {0x00, 0x0006, 0x2818},
- {0x00, 0x0007, 0x2819},
- {0x00, 0x0009, 0x281a},
- {0x00, 0x000c, 0x281b},
- {0x00, 0x0014, 0x281c},
- {0x00, 0x0023, 0x281d},
- {0x00, 0x0020, 0x281e},
- {0x00, 0x0019, 0x281f},
-
- {0x00, 0x0007, 0x2820},
- {0x00, 0x0009, 0x2821},
- {0x00, 0x000f, 0x2822},
- {0x00, 0x0016, 0x2823},
- {0x00, 0x001b, 0x2824},
- {0x00, 0x002c, 0x2825},
- {0x00, 0x0029, 0x2826},
- {0x00, 0x001f, 0x2827},
- {0x00, 0x000a, 0x2828},
- {0x00, 0x000e, 0x2829},
- {0x00, 0x0016, 0x282a},
- {0x00, 0x001a, 0x282b},
- {0x00, 0x0020, 0x282c},
- {0x00, 0x002a, 0x282d},
- {0x00, 0x002d, 0x282e},
- {0x00, 0x0025, 0x282f},
-
- {0x00, 0x0014, 0x2830},
- {0x00, 0x001a, 0x2831},
- {0x00, 0x001f, 0x2832},
- {0x00, 0x0023, 0x2833},
- {0x00, 0x0029, 0x2834},
- {0x00, 0x0030, 0x2835},
- {0x00, 0x0030, 0x2836},
- {0x00, 0x0028, 0x2837},
- {0x00, 0x001d, 0x2838},
- {0x00, 0x0025, 0x2839},
- {0x00, 0x0026, 0x283a},
- {0x00, 0x0027, 0x283b},
- {0x00, 0x002d, 0x283c},
- {0x00, 0x0028, 0x283d},
- {0x00, 0x0029, 0x283e},
- {0x00, 0x0028, 0x283f},
-
- {0x00, 0x0007, 0x2840},
- {0x00, 0x0007, 0x2841},
- {0x00, 0x000a, 0x2842},
- {0x00, 0x0013, 0x2843},
- {0x00, 0x0028, 0x2844},
- {0x00, 0x0028, 0x2845},
- {0x00, 0x0028, 0x2846},
- {0x00, 0x0028, 0x2847},
- {0x00, 0x0007, 0x2848},
- {0x00, 0x0008, 0x2849},
- {0x00, 0x000a, 0x284a},
- {0x00, 0x001a, 0x284b},
- {0x00, 0x0028, 0x284c},
- {0x00, 0x0028, 0x284d},
- {0x00, 0x0028, 0x284e},
- {0x00, 0x0028, 0x284f},
-
- {0x00, 0x000a, 0x2850},
- {0x00, 0x000a, 0x2851},
- {0x00, 0x0016, 0x2852},
- {0x00, 0x0028, 0x2853},
- {0x00, 0x0028, 0x2854},
- {0x00, 0x0028, 0x2855},
- {0x00, 0x0028, 0x2856},
- {0x00, 0x0028, 0x2857},
- {0x00, 0x0013, 0x2858},
- {0x00, 0x001a, 0x2859},
- {0x00, 0x0028, 0x285a},
- {0x00, 0x0028, 0x285b},
- {0x00, 0x0028, 0x285c},
- {0x00, 0x0028, 0x285d},
- {0x00, 0x0028, 0x285e},
- {0x00, 0x0028, 0x285f},
-
- {0x00, 0x0028, 0x2860},
- {0x00, 0x0028, 0x2861},
- {0x00, 0x0028, 0x2862},
- {0x00, 0x0028, 0x2863},
- {0x00, 0x0028, 0x2864},
- {0x00, 0x0028, 0x2865},
- {0x00, 0x0028, 0x2866},
- {0x00, 0x0028, 0x2867},
- {0x00, 0x0028, 0x2868},
- {0x00, 0x0028, 0x2869},
- {0x00, 0x0028, 0x286a},
- {0x00, 0x0028, 0x286b},
- {0x00, 0x0028, 0x286c},
- {0x00, 0x0028, 0x286d},
- {0x00, 0x0028, 0x286e},
- {0x00, 0x0028, 0x286f},
-
- {0x00, 0x0028, 0x2870},
- {0x00, 0x0028, 0x2871},
- {0x00, 0x0028, 0x2872},
- {0x00, 0x0028, 0x2873},
- {0x00, 0x0028, 0x2874},
- {0x00, 0x0028, 0x2875},
- {0x00, 0x0028, 0x2876},
- {0x00, 0x0028, 0x2877},
- {0x00, 0x0028, 0x2878},
- {0x00, 0x0028, 0x2879},
- {0x00, 0x0028, 0x287a},
- {0x00, 0x0028, 0x287b},
- {0x00, 0x0028, 0x287c},
- {0x00, 0x0028, 0x287d},
- {0x00, 0x0028, 0x287e},
- {0x00, 0x0028, 0x287f},
{0xa0, 0x0000, 0x0503},
};
@@ -622,6 +486,20 @@ static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
PDEBUG(D_FRAM, "after wait 0x%04x", notdone);
}
+static void spca504_read_info(struct gspca_dev *gspca_dev)
+{
+ int i;
+ u8 info[6];
+
+ for (i = 0; i < 6; i++)
+ info[i] = reg_r_1(gspca_dev, i);
+ PDEBUG(D_STREAM,
+ "Read info: %d %d %d %d %d %d."
+ " Should be 1,0,2,2,0,0",
+ info[0], info[1], info[2],
+ info[3], info[4], info[5]);
+}
+
static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
u8 req,
u16 idx, u16 val, u16 endcode, u8 count)
@@ -709,7 +587,7 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
spca504B_PollingDataReady(gspca_dev);
/* Init the cam width height with some values get on init ? */
- reg_w_riv(gspca_dev, 0x31, 0, 0x04);
+ reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
spca504B_WaitCmdStatus(gspca_dev);
spca504B_PollingDataReady(gspca_dev);
break;
@@ -807,14 +685,14 @@ static void init_ctl_reg(struct gspca_dev *gspca_dev)
default:
/* case BRIDGE_SPCA533: */
/* case BRIDGE_SPCA504B: */
- reg_w_riv(gspca_dev, 0, 0x00, 0x21ad); /* hue */
- reg_w_riv(gspca_dev, 0, 0x01, 0x21ac); /* sat/hue */
- reg_w_riv(gspca_dev, 0, 0x00, 0x21a3); /* gamma */
+ reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */
+ reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */
+ reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */
break;
case BRIDGE_SPCA536:
- reg_w_riv(gspca_dev, 0, 0x40, 0x20f5);
- reg_w_riv(gspca_dev, 0, 0x01, 0x20f4);
- reg_w_riv(gspca_dev, 0, 0x00, 0x2089);
+ reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
+ reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
+ reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
break;
}
if (pollreg)
@@ -881,17 +759,15 @@ static int sd_config(struct gspca_dev *gspca_dev,
static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
- u8 info[6];
switch (sd->bridge) {
case BRIDGE_SPCA504B:
reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
- reg_w_riv(gspca_dev, 0, 0x01, 0x2306);
- reg_w_riv(gspca_dev, 0, 0x00, 0x0d04);
- reg_w_riv(gspca_dev, 0, 0x00, 0x2000);
- reg_w_riv(gspca_dev, 0, 0x13, 0x2301);
- reg_w_riv(gspca_dev, 0, 0x00, 0x2306);
+ reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
+ reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
+ reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
+ reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
+ reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
/* fall thru */
case BRIDGE_SPCA533:
spca504B_PollingDataReady(gspca_dev);
@@ -924,15 +800,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* case BRIDGE_SPCA504: */
PDEBUG(D_STREAM, "Opening SPCA504");
if (sd->subtype == AiptekMiniPenCam13) {
- /*****************************/
- for (i = 0; i < 6; i++)
- info[i] = reg_r_1(gspca_dev, i);
- PDEBUG(D_STREAM,
- "Read info: %d %d %d %d %d %d."
- " Should be 1,0,2,2,0,0",
- info[0], info[1], info[2],
- info[3], info[4], info[5]);
- /* spca504a aiptek */
+ spca504_read_info(gspca_dev);
+
/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
spca504A_acknowledged_command(gspca_dev, 0x24,
8, 3, 0x9e, 1);
@@ -971,8 +840,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int enable;
- int i;
- u8 info[6];
/* create the JPEG header */
sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
@@ -1000,7 +867,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
spca504B_WaitCmdStatus(gspca_dev);
break;
default:
- reg_w_riv(gspca_dev, 0x31, 0, 0x04);
+ reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
spca504B_WaitCmdStatus(gspca_dev);
spca504B_PollingDataReady(gspca_dev);
break;
@@ -1008,14 +875,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
case BRIDGE_SPCA504:
if (sd->subtype == AiptekMiniPenCam13) {
- for (i = 0; i < 6; i++)
- info[i] = reg_r_1(gspca_dev, i);
- PDEBUG(D_STREAM,
- "Read info: %d %d %d %d %d %d."
- " Should be 1,0,2,2,0,0",
- info[0], info[1], info[2],
- info[3], info[4], info[5]);
- /* spca504a aiptek */
+ spca504_read_info(gspca_dev);
+
/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
spca504A_acknowledged_command(gspca_dev, 0x24,
8, 3, 0x9e, 1);
@@ -1026,13 +887,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
0, 0, 0x9d, 1);
} else {
spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
- for (i = 0; i < 6; i++)
- info[i] = reg_r_1(gspca_dev, i);
- PDEBUG(D_STREAM,
- "Read info: %d %d %d %d %d %d."
- " Should be 1,0,2,2,0,0",
- info[0], info[1], info[2],
- info[3], info[4], info[5]);
+ spca504_read_info(gspca_dev);
spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
}
@@ -1336,6 +1191,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
{USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
{USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
+ {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
{USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
{USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
{USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index 55ef6a744427..668a7536af90 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -52,6 +52,7 @@ struct sd {
#define SENSOR_OM6802 0
#define SENSOR_OTHER 1
#define SENSOR_TAS5130A 2
+#define SENSOR_LT168G 3 /* must verify if this is the actual model */
};
/* V4L2 controls supported by the driver */
@@ -78,7 +79,7 @@ static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
@@ -306,6 +307,17 @@ static const u8 n4_tas5130a[] = {
0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
0xc6, 0xda
};
+static const u8 n4_lt168g[] = {
+ 0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,
+ 0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,
+ 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,
+ 0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,
+ 0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,
+ 0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,
+ 0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,
+ 0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,
+ 0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80
+};
static const struct additional_sensor_data sensor_data[] = {
{ /* 0: OM6802 */
@@ -380,6 +392,23 @@ static const struct additional_sensor_data sensor_data[] = {
.stream =
{0x0b, 0x04, 0x0a, 0x40},
},
+ { /* 3: LT168G */
+ .n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
+ .n4 = n4_lt168g,
+ .n4sz = sizeof n4_lt168g,
+ .reg80 = 0x7c,
+ .reg8e = 0xb3,
+ .nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},
+ .data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,
+ 0xb0, 0xf4},
+ .data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
+ 0xff},
+ .data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
+ 0xff},
+ .data4 = {0x66, 0x41, 0xa8, 0xf0},
+ .data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
+ .stream = {0x0b, 0x04, 0x0a, 0x28},
+ },
};
#define MAX_EFFECTS 7
@@ -716,6 +745,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
PDEBUG(D_PROBE, "sensor tas5130a");
sd->sensor = SENSOR_TAS5130A;
break;
+ case 0x0802:
+ PDEBUG(D_PROBE, "sensor lt168g");
+ sd->sensor = SENSOR_LT168G;
+ break;
case 0x0803:
PDEBUG(D_PROBE, "sensor 'other'");
sd->sensor = SENSOR_OTHER;
@@ -758,6 +791,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
+ if (sd->sensor == SENSOR_LT168G) {
+ test_byte = reg_r(gspca_dev, 0x80);
+ PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
+ test_byte);
+ reg_w(gspca_dev, 0x6c80);
+ }
+
reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
@@ -782,6 +822,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
+ if (sd->sensor == SENSOR_LT168G) {
+ test_byte = reg_r(gspca_dev, 0x80);
+ PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80,
+ test_byte);
+ reg_w(gspca_dev, 0x6c80);
+ }
+
reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
@@ -888,6 +935,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_OM6802:
om6802_sensor_init(gspca_dev);
break;
+ case SENSOR_LT168G:
+ break;
case SENSOR_OTHER:
break;
default:
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
index b74a3b6489c7..c7b6eb1e04d5 100644
--- a/drivers/media/video/gspca/tv8532.c
+++ b/drivers/media/video/gspca/tv8532.c
@@ -39,7 +39,7 @@ struct sd {
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index c090efcd8045..4989f9afb46e 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -32,10 +32,13 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
+ u8 brightness;
+ u8 contrast;
+ u8 colors;
u8 hflip;
u8 vflip;
u8 lightfreq;
- u8 sharpness;
+ s8 sharpness;
u8 image_offset;
@@ -52,6 +55,7 @@ struct sd {
#define SENSOR_OV7670 6
#define SENSOR_PO1200 7
#define SENSOR_PO3130NC 8
+#define SENSOR_POxxxx 9
u8 flags;
#define FL_SAMSUNG 0x01 /* SamsungQ1 (2 sensors) */
#define FL_HFLIP 0x02 /* mirrored by default */
@@ -59,6 +63,12 @@ struct sd {
};
/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
@@ -68,9 +78,54 @@ static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
+#define BRIGHTNESS_IDX 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define BRIGHTNESS_DEF 128
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define CONTRAST_IDX 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define CONTRAST_DEF 127
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define COLORS_IDX 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 1,
+ .maximum = 127,
+ .step = 1,
+#define COLOR_DEF 63
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
/* next 2 controls work with some sensors only */
-#define HFLIP_IDX 0
+#define HFLIP_IDX 3
{
{
.id = V4L2_CID_HFLIP,
@@ -85,7 +140,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_sethflip,
.get = sd_gethflip,
},
-#define VFLIP_IDX 1
+#define VFLIP_IDX 4
{
{
.id = V4L2_CID_VFLIP,
@@ -100,7 +155,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setvflip,
.get = sd_getvflip,
},
-#define LIGHTFREQ_IDX 2
+#define LIGHTFREQ_IDX 5
{
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -115,17 +170,16 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setfreq,
.get = sd_getfreq,
},
-/* po1200 only */
-#define SHARPNESS_IDX 3
+#define SHARPNESS_IDX 6
{
{
.id = V4L2_CID_SHARPNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Sharpness",
- .minimum = 0,
+ .minimum = -1,
.maximum = 2,
.step = 1,
-#define SHARPNESS_DEF 1
+#define SHARPNESS_DEF -1
.default_value = SHARPNESS_DEF,
},
.set = sd_setsharpness,
@@ -133,6 +187,42 @@ static struct ctrl sd_ctrls[] = {
},
};
+/* table of the disabled controls */
+static u32 ctrl_dis[] = {
+/* SENSOR_HV7131R 0 */
+ (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
+ | (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX)
+ | (1 << SHARPNESS_IDX),
+/* SENSOR_MI0360 1 */
+ (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
+ | (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX)
+ | (1 << SHARPNESS_IDX),
+/* SENSOR_MI1310_SOC 2 */
+ (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
+ | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX),
+/* SENSOR_MI1320 3 */
+ (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
+ | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX),
+/* SENSOR_MI1320_SOC 4 */
+ (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
+ | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX),
+/* SENSOR_OV7660 5 */
+ (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
+ | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX),
+/* SENSOR_OV7670 6 */
+ (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
+ | (1 << SHARPNESS_IDX),
+/* SENSOR_PO1200 7 */
+ (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
+ | (1 << LIGHTFREQ_IDX),
+/* SENSOR_PO3130NC 8 */
+ (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
+ | (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX)
+ | (1 << SHARPNESS_IDX),
+/* SENSOR_POxxxx 9 */
+ (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX),
+};
+
static const struct v4l2_pix_format vc0321_mode[] = {
{320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
.bytesperline = 320,
@@ -215,7 +305,7 @@ static const u8 mi0360_initVGA_JPG[][4] = {
{0xb3, 0x15, 0x00, 0xcc},
{0xb3, 0x16, 0x02, 0xcc},
{0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x35, 0xdd, 0xcc}, /* i2c add: 5d */
{0xb3, 0x34, 0x02, 0xcc},
{0xb3, 0x00, 0x25, 0xcc},
{0xbc, 0x00, 0x71, 0xcc},
@@ -435,7 +525,7 @@ static const u8 mi1310_socinitVGA_JPG[][4] = {
{0xb3, 0x08, 0x01, 0xcc},
{0xb3, 0x09, 0x0c, 0xcc},
{0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x35, 0xdd, 0xcc}, /* i2c add: 5d */
{0xb3, 0x02, 0x00, 0xcc},
{0xb3, 0x03, 0x0a, 0xcc},
{0xb3, 0x04, 0x05, 0xcc},
@@ -860,7 +950,8 @@ static const u8 mi1320_initVGA_data[][4] = {
{0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
{0xb3, 0x06, 0x00, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
{0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x35, 0xc8, 0xcc}, {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc}, /* i2c add: 48 */
+ {0xb3, 0x02, 0x00, 0xcc},
{0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
{0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
{0xb3, 0x22, 0x03, 0xcc}, {0xb3, 0x23, 0xc0, 0xcc},
@@ -901,7 +992,8 @@ static const u8 mi1320_initVGA_data[][4] = {
{0xc3, 0x01, 0x03, 0xbb}, {0xc4, 0x00, 0x04, 0xbb},
{0xf0, 0x00, 0x00, 0xbb}, {0x05, 0x01, 0x13, 0xbb},
{0x06, 0x00, 0x11, 0xbb}, {0x07, 0x00, 0x85, 0xbb},
- {0x08, 0x00, 0x27, 0xbb}, {0x20, 0x01, 0x03, 0xbb},
+ {0x08, 0x00, 0x27, 0xbb},
+ {0x20, 0x01, 0x00, 0xbb}, /* h/v flips - was 03 */
{0x21, 0x80, 0x00, 0xbb}, {0x22, 0x0d, 0x0f, 0xbb},
{0x24, 0x80, 0x00, 0xbb}, {0x59, 0x00, 0xff, 0xbb},
{0xf0, 0x00, 0x02, 0xbb}, {0x39, 0x03, 0x0d, 0xbb},
@@ -1012,7 +1104,7 @@ static const u8 mi1320_soc_InitVGA[][4] = {
{0xb3, 0x08, 0x01, 0xcc},
{0xb3, 0x09, 0x0c, 0xcc},
{0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc}, /* i2c add: 48 */
{0xb3, 0x02, 0x00, 0xcc},
{0xb3, 0x03, 0x0a, 0xcc},
{0xb3, 0x04, 0x05, 0xcc},
@@ -1359,7 +1451,8 @@ static const u8 po3130_initVGA_data[][4] = {
{0xb3, 0x23, 0xe8, 0xcc}, {0xb8, 0x08, 0xe8, 0xcc},
{0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
{0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
- {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0xf6, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0xf6, 0xcc}, /* i2c add: 76 */
{0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0x71, 0xcc},
{0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc},
{0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
@@ -1561,7 +1654,7 @@ static const u8 hv7131r_initVGA_data[][4] = {
{0xb3, 0x16, 0x02, 0xcc},
{0xb3, 0x17, 0x7f, 0xcc},
{0xb3, 0x34, 0x01, 0xcc},
- {0xb3, 0x35, 0x91, 0xcc},
+ {0xb3, 0x35, 0x91, 0xcc}, /* i2c add: 11 */
{0xb3, 0x00, 0x27, 0xcc},
{0xbc, 0x00, 0x73, 0xcc},
{0xb8, 0x00, 0x23, 0xcc},
@@ -1747,7 +1840,8 @@ static const u8 ov7660_initVGA_data[][4] = {
{0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc},
{0xb3, 0x1f, 0x02, 0xcc},
{0xb3, 0x34, 0x01, 0xcc},
- {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */
+ {0xb3, 0x00, 0x26, 0xcc},
{0xb8, 0x00, 0x33, 0xcc}, /* 13 */
{0xb8, 0x01, 0x7d, 0xcc},
{0xbc, 0x00, 0x73, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
@@ -1883,7 +1977,8 @@ static const u8 ov7670_initVGA_JPG[][4] = {
{0x00, 0x00, 0x10, 0xdd},
{0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x10, 0xdd},
{0xb3, 0x00, 0x66, 0xcc}, {0xb3, 0x00, 0x67, 0xcc},
- {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */
+ {0xb3, 0x34, 0x01, 0xcc},
{0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x01, 0xcc},
{0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc},
{0xb3, 0x02, 0x02, 0xcc}, {0xb3, 0x03, 0x1f, 0xcc},
@@ -2181,7 +2276,7 @@ static const u8 po1200_initVGA_data[][4] = {
{0xb0, 0x54, 0x13, 0xcc},
{0xb3, 0x00, 0x67, 0xcc},
{0xb3, 0x34, 0x01, 0xcc},
- {0xb3, 0x35, 0xdc, 0xcc},
+ {0xb3, 0x35, 0xdc, 0xcc}, /* i2c add: 5c */
{0x00, 0x03, 0x00, 0xaa},
{0x00, 0x12, 0x05, 0xaa},
{0x00, 0x13, 0x02, 0xaa},
@@ -2408,6 +2503,251 @@ static const u8 po1200_initVGA_data[][4] = {
{0x00, 0xb6, 0x39, 0xaa},
{0x00, 0xb7, 0x24, 0xaa},
/*write 89 0400 1415*/
+ {}
+};
+
+static const u8 poxxxx_init_common[][4] = {
+ {0xb3, 0x00, 0x04, 0xcc},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb0, 0x03, 0x09, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0xf6, 0xcc}, /* i2c add: 76 */
+ {0xb3, 0x02, 0xb0, 0xcc},
+ {0xb3, 0x03, 0x18, 0xcc},
+ {0xb3, 0x04, 0x15, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x04, 0xcc},
+ {0xb3, 0x23, 0x00, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x2c, 0x03, 0xcc},
+ {0xb3, 0x2d, 0x56, 0xcc},
+ {0xb3, 0x2e, 0x02, 0xcc},
+ {0xb3, 0x2f, 0x0a, 0xcc},
+ {0xb3, 0x40, 0x00, 0xcc},
+ {0xb3, 0x41, 0x34, 0xcc},
+ {0xb3, 0x42, 0x01, 0xcc},
+ {0xb3, 0x43, 0xe0, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xb3, 0x4d, 0x00, 0xcc},
+ {0x00, 0x0b, 0x2a, 0xaa},
+ {0x00, 0x0e, 0x03, 0xaa},
+ {0x00, 0x0f, 0xea, 0xaa},
+ {0x00, 0x12, 0x08, 0xaa},
+ {0x00, 0x1e, 0x06, 0xaa},
+ {0x00, 0x21, 0x00, 0xaa},
+ {0x00, 0x31, 0x1f, 0xaa},
+ {0x00, 0x33, 0x38, 0xaa},
+ {0x00, 0x36, 0xc0, 0xaa},
+ {0x00, 0x37, 0xc8, 0xaa},
+ {0x00, 0x3b, 0x36, 0xaa},
+ {0x00, 0x4b, 0xfe, 0xaa},
+ {0x00, 0x4d, 0x2e, 0xaa},
+ {0x00, 0x51, 0x1c, 0xaa},
+ {0x00, 0x52, 0x01, 0xaa},
+ {0x00, 0x55, 0x0a, 0xaa},
+ {0x00, 0x56, 0x0a, 0xaa},
+ {0x00, 0x57, 0x07, 0xaa},
+ {0x00, 0x58, 0x07, 0xaa},
+ {0x00, 0x59, 0x04, 0xaa},
+ {0x00, 0x70, 0x68, 0xaa},
+ {0x00, 0x71, 0x04, 0xaa},
+ {0x00, 0x72, 0x10, 0xaa},
+ {0x00, 0x80, 0x71, 0xaa},
+ {0x00, 0x81, 0x08, 0xaa},
+ {0x00, 0x82, 0x00, 0xaa},
+ {0x00, 0x83, 0x55, 0xaa},
+ {0x00, 0x84, 0x06, 0xaa},
+ {0x00, 0x85, 0x06, 0xaa},
+ {0x00, 0x8b, 0x25, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa},
+ {0x00, 0x8d, 0x86, 0xaa},
+ {0x00, 0x8e, 0x82, 0xaa},
+ {0x00, 0x8f, 0x2d, 0xaa},
+ {0x00, 0x90, 0x8b, 0xaa},
+ {0x00, 0x91, 0x81, 0xaa},
+ {0x00, 0x92, 0x81, 0xaa},
+ {0x00, 0x93, 0x23, 0xaa},
+ {0x00, 0xa3, 0x2a, 0xaa},
+ {0x00, 0xa4, 0x03, 0xaa},
+ {0x00, 0xa5, 0xea, 0xaa},
+ {0x00, 0xb0, 0x68, 0xaa},
+ {0x00, 0xbc, 0x04, 0xaa},
+ {0x00, 0xbe, 0x3b, 0xaa},
+ {0x00, 0x4e, 0x40, 0xaa},
+ {0x00, 0x06, 0x04, 0xaa},
+ {0x00, 0x07, 0x03, 0xaa},
+ {0x00, 0xcd, 0x18, 0xaa},
+ {0x00, 0x28, 0x03, 0xaa},
+ {0x00, 0x29, 0xef, 0xaa},
+/* reinit on alt 2 (qvga) or alt7 (vga) */
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0xb8, 0x00, 0x01, 0xcc},
+
+ {0x00, 0x1d, 0x85, 0xaa},
+ {0x00, 0x1e, 0xc6, 0xaa},
+ {0x00, 0x00, 0x40, 0xdd},
+ {0x00, 0x1d, 0x05, 0xaa},
+
+ {0x00, 0xd6, 0x22, 0xaa}, /* gamma 0 */
+ {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x0a, 0xaa},
+ {0x00, 0x75, 0x16, 0xaa},
+ {0x00, 0x76, 0x25, 0xaa},
+ {0x00, 0x77, 0x34, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa},
+ {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa},
+ {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa},
+ {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa},
+
+ {0x00, 0xd6, 0x62, 0xaa}, /* gamma 1 */
+ {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x0a, 0xaa},
+ {0x00, 0x75, 0x16, 0xaa},
+ {0x00, 0x76, 0x25, 0xaa},
+ {0x00, 0x77, 0x34, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa},
+ {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa},
+ {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa},
+ {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa},
+
+ {0x00, 0xd6, 0xa2, 0xaa}, /* gamma 2 */
+ {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x0a, 0xaa},
+ {0x00, 0x75, 0x16, 0xaa},
+ {0x00, 0x76, 0x25, 0xaa},
+ {0x00, 0x77, 0x34, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa},
+ {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa},
+ {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa},
+ {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa},
+
+ {0x00, 0xaa, 0xff, 0xaa}, /* back light comp */
+ {0x00, 0xc4, 0x03, 0xaa},
+ {0x00, 0xc5, 0x19, 0xaa},
+ {0x00, 0xc6, 0x03, 0xaa},
+ {0x00, 0xc7, 0x91, 0xaa},
+ {0x00, 0xc8, 0x01, 0xaa},
+ {0x00, 0xc9, 0xdd, 0xaa},
+ {0x00, 0xca, 0x02, 0xaa},
+ {0x00, 0xcb, 0x37, 0xaa},
+
+/* read d1 */
+ {0x00, 0xd1, 0x3c, 0xaa},
+ {0x00, 0xb8, 0x28, 0xaa},
+ {0x00, 0xb9, 0x1e, 0xaa},
+ {0x00, 0xb6, 0x14, 0xaa},
+ {0x00, 0xb7, 0x0f, 0xaa},
+ {0x00, 0x5c, 0x10, 0xaa},
+ {0x00, 0x5d, 0x18, 0xaa},
+ {0x00, 0x5e, 0x24, 0xaa},
+ {0x00, 0x5f, 0x24, 0xaa},
+ {0x00, 0x86, 0x1a, 0xaa},
+ {0x00, 0x60, 0x00, 0xaa},
+ {0x00, 0x61, 0x1b, 0xaa},
+ {0x00, 0x62, 0x30, 0xaa},
+ {0x00, 0x63, 0x40, 0xaa},
+ {0x00, 0x87, 0x1a, 0xaa},
+ {0x00, 0x64, 0x00, 0xaa},
+ {0x00, 0x65, 0x08, 0xaa},
+ {0x00, 0x66, 0x10, 0xaa},
+ {0x00, 0x67, 0x20, 0xaa},
+ {0x00, 0x88, 0x10, 0xaa},
+ {0x00, 0x68, 0x00, 0xaa},
+ {0x00, 0x69, 0x08, 0xaa},
+ {0x00, 0x6a, 0x0f, 0xaa},
+ {0x00, 0x6b, 0x0f, 0xaa},
+ {0x00, 0x89, 0x07, 0xaa},
+ {0x00, 0xd5, 0x4c, 0xaa},
+ {0x00, 0x0a, 0x00, 0xaa},
+ {0x00, 0x0b, 0x2a, 0xaa},
+ {0x00, 0x0e, 0x03, 0xaa},
+ {0x00, 0x0f, 0xea, 0xaa},
+ {0x00, 0xa2, 0x00, 0xaa},
+ {0x00, 0xa3, 0x2a, 0xaa},
+ {0x00, 0xa4, 0x03, 0xaa},
+ {0x00, 0xa5, 0xea, 0xaa},
+ {}
+};
+static const u8 poxxxx_initVGA[][4] = {
+ {0x00, 0x20, 0x11, 0xaa},
+ {0x00, 0x33, 0x38, 0xaa},
+ {0x00, 0xbb, 0x0d, 0xaa},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x02, 0xb0, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0x00, 0x04, 0x06, 0xaa},
+ {0x00, 0x05, 0x3f, 0xaa},
+ {0x00, 0x04, 0x00, 0xdd}, /* delay 1s */
+ {}
+};
+static const u8 poxxxx_initQVGA[][4] = {
+ {0x00, 0x20, 0x33, 0xaa},
+ {0x00, 0x33, 0x38, 0xaa},
+ {0x00, 0xbb, 0x0d, 0xaa},
+ {0xb3, 0x22, 0x00, 0xcc},
+ {0xb3, 0x23, 0xf0, 0xcc},
+ {0xb3, 0x16, 0x01, 0xcc},
+ {0xb3, 0x17, 0x3f, 0xcc},
+ {0xb3, 0x02, 0xb0, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x00, 0xcc},
+ {0x00, 0x04, 0x06, 0xaa},
+ {0x00, 0x05, 0x3f, 0xaa},
+ {0x00, 0x04, 0x00, 0xdd}, /* delay 1s */
+ {}
+};
+static const u8 poxxxx_init_end_1[][4] = {
+ {0x00, 0x47, 0x25, 0xaa},
+ {0x00, 0x48, 0x80, 0xaa},
+ {0x00, 0x49, 0x1f, 0xaa},
+ {0x00, 0x4a, 0x40, 0xaa},
+ {0x00, 0x44, 0x40, 0xaa},
+ {0x00, 0xab, 0x4a, 0xaa},
+ {0x00, 0xb1, 0x00, 0xaa},
+ {0x00, 0xb2, 0x04, 0xaa},
+ {0x00, 0xb3, 0x08, 0xaa},
+ {0x00, 0xb4, 0x0b, 0xaa},
+ {0x00, 0xb5, 0x0d, 0xaa},
+ {0x00, 0x59, 0x7e, 0xaa}, /* sharpness */
+ {0x00, 0x16, 0x00, 0xaa}, /* white balance */
+ {0x00, 0x18, 0x00, 0xaa},
+ {}
+};
+static const u8 poxxxx_init_end_2[][4] = {
+ {0x00, 0x1d, 0x85, 0xaa},
+ {0x00, 0x1e, 0x06, 0xaa},
+ {0x00, 0x1d, 0x05, 0xaa},
+ {}
};
struct sensor_info {
@@ -2420,33 +2760,89 @@ struct sensor_info {
u8 op;
};
-static const struct sensor_info sensor_info_data[] = {
-/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */
+/* probe values */
+static const struct sensor_info vc0321_probe_data[] = {
+/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */
+/* 0 OV9640 */
{-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
+/* 1 ICM108T (may respond on IdAdd == 0x83 - tested in vc032x_probe_sensor) */
{-1, 0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01},
-/* (tested in vc032x_probe_sensor) */
-/* {-1, 0x80 | 0x20, 0x83, 0x0000, 0x24, 0x25, 0x01}, */
- {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01},
+/* 2 PO2130 (may detect PO3130NC - tested in vc032x_probe_sensor)*/
+ {-1, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* 3 MI1310 */
+ {-1, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* 4 MI360 - tested in vc032x_probe_sensor */
+/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */
+/* 5 7131R */
+ {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
+/* 6 OV7649 */
+ {-1, 0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05},
+/* 7 PAS302BCW */
+ {-1, 0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05},
+/* 8 OV7660 */
+ {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
+/* 9 PO3130NC - (tested in vc032x_probe_sensor) */
+/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01}, */
+/* 10 PO1030KC */
+ {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* 11 MI1310_SOC */
{SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
-/* (tested in vc032x_probe_sensor) */
+/* 12 OV9650 */
+ {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
+/* 13 S5K532 */
+ {-1, 0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01},
+/* 14 MI360_SOC - ??? */
+/* 15 PO1200N */
+ {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
+/* 16 PO3030K */
+ {-1, 0x80 | 0x18, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* 17 PO2030 */
+ {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* ?? */
+ {-1, 0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01},
+ {SENSOR_MI1320, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x65, 0x01},
+};
+static const struct sensor_info vc0323_probe_data[] = {
+/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */
+/* 0 OV9640 */
+ {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
+/* 1 ICM108T (may respond on IdAdd == 0x83 - tested in vc032x_probe_sensor) */
+ {-1, 0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01},
+/* 2 PO2130 (may detect PO3130NC - tested in vc032x_probe_sensor)*/
+ {-1, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* 3 MI1310 */
+ {-1, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* 4 MI360 - tested in vc032x_probe_sensor */
/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */
+/* 5 7131R */
{SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
+/* 6 OV7649 */
{-1, 0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05},
+/* 7 PAS302BCW */
{-1, 0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05},
+/* 8 OV7660 */
{SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
-/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01}, */
+/* 9 PO3130NC - (tested in vc032x_probe_sensor) */
+/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01}, */
+/* 10 PO1030KC */
{-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
-/* {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01}, */
-/* {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05}, */
+/* 11 MI1310_SOC */
+ {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
+/* 12 OV9650 */
+ {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
+/* 13 S5K532 */
{-1, 0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01},
+/* 14 MI360_SOC - ??? */
+/* 15 PO1200N */
{SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
+/* 16 ?? */
{-1, 0x80 | 0x2d, 0x00, 0x0000, 0x65, 0x67, 0x01},
+/* 17 PO2030 */
{-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* ?? */
{-1, 0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01},
{SENSOR_MI1320_SOC, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x67, 0x01},
-/*fixme: previously detected?*/
- {SENSOR_MI1320, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x65, 0x01},
-/*fixme: not in the ms-win probe - may be found before?*/
+/*fixme: not in the ms-win probe - may be found before? */
{SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
};
@@ -2520,7 +2916,7 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
- int i;
+ int i, n;
u16 value;
const struct sensor_info *ptsensor_info;
@@ -2531,9 +2927,16 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
}
reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
- PDEBUG(D_PROBE, "check sensor header %02x", gspca_dev->usb_buf[0]);
- for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) {
- ptsensor_info = &sensor_info_data[i];
+ PDEBUG(D_PROBE, "vc032%d check sensor header %02x",
+ sd->bridge == BRIDGE_VC0321 ? 1 : 3, gspca_dev->usb_buf[0]);
+ if (sd->bridge == BRIDGE_VC0321) {
+ ptsensor_info = vc0321_probe_data;
+ n = ARRAY_SIZE(vc0321_probe_data);
+ } else {
+ ptsensor_info = vc0323_probe_data;
+ n = ARRAY_SIZE(vc0323_probe_data);
+ }
+ for (i = 0; i < n; i++) {
reg_w(dev, 0xa0, 0x02, 0xb334);
reg_w(dev, 0xa0, ptsensor_info->m1, 0xb300);
reg_w(dev, 0xa0, ptsensor_info->m2, 0xb300);
@@ -2551,13 +2954,15 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
return ptsensor_info->sensorId;
switch (value) {
+ case 0x3130:
+ return SENSOR_PO3130NC;
case 0x7673:
return SENSOR_OV7670;
case 0x8243:
return SENSOR_MI0360;
}
-/*fixme: should return here*/
}
+ ptsensor_info++;
}
return -1;
}
@@ -2619,7 +3024,7 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
i2c_write(gspca_dev, data[i][0], &data[i][1], 2);
break;
case 0xdd:
- msleep(data[i][2] + 10);
+ msleep(data[i][1] * 256 + data[i][2] + 10);
break;
}
i++;
@@ -2646,12 +3051,17 @@ static int sd_config(struct gspca_dev *gspca_dev,
64, /* OV7670 6 */
128, /* PO1200 7 */
128, /* PO3130NC 8 */
+ 128, /* POxxxx 9 */
};
cam = &gspca_dev->cam;
sd->bridge = id->driver_info >> 8;
sd->flags = id->driver_info & 0xff;
- sensor = vc032x_probe_sensor(gspca_dev);
+ if (id->idVendor == 0x046d &&
+ (id->idProduct == 0x0892 || id->idProduct == 0x0896))
+ sensor = SENSOR_POxxxx;
+ else
+ sensor = vc032x_probe_sensor(gspca_dev);
switch (sensor) {
case -1:
PDEBUG(D_PROBE, "Unknown sensor...");
@@ -2684,6 +3094,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
case SENSOR_PO3130NC:
PDEBUG(D_PROBE, "Find Sensor PO3130NC");
break;
+ case SENSOR_POxxxx:
+ PDEBUG(D_PROBE, "Sensor POxxxx");
+ break;
}
sd->sensor = sensor;
@@ -2712,28 +3125,19 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
cam->npkt = npkt[sd->sensor];
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
sd->hflip = HFLIP_DEF;
sd->vflip = VFLIP_DEF;
- if (sd->sensor == SENSOR_OV7670)
- sd->flags |= FL_HFLIP | FL_VFLIP;
sd->lightfreq = FREQ_DEF;
- if (sd->sensor != SENSOR_OV7670)
- gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
- switch (sd->sensor) {
- case SENSOR_MI1310_SOC:
- case SENSOR_MI1320_SOC:
- case SENSOR_OV7660:
- case SENSOR_OV7670:
- case SENSOR_PO1200:
- break;
- default:
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX)
- | (1 << VFLIP_IDX);
- break;
- }
-
sd->sharpness = SHARPNESS_DEF;
+ gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
+
+ if (sd->sensor == SENSOR_OV7670)
+ sd->flags |= FL_HFLIP | FL_VFLIP;
+
if (sd->bridge == BRIDGE_VC0321) {
reg_r(gspca_dev, 0x8a, 0, 3);
reg_w(dev, 0x87, 0x00, 0x0f0f);
@@ -2747,10 +3151,55 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_POxxxx) {
+ reg_r(gspca_dev, 0xa1, 0xb300, 1);
+ if (gspca_dev->usb_buf[0] != 0) {
+ reg_w(gspca_dev->dev, 0xa0, 0x26, 0xb300);
+ reg_w(gspca_dev->dev, 0xa0, 0x04, 0xb300);
+ reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb300);
+ }
+ }
return 0;
}
-/* some sensors only */
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 data;
+
+ if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS_IDX))
+ return;
+ data = sd->brightness;
+ if (data >= 0x80)
+ data &= 0x7f;
+ else
+ data = 0xff ^ data;
+ i2c_write(gspca_dev, 0x98, &data, 1);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (gspca_dev->ctrl_dis & (1 << CONTRAST_IDX))
+ return;
+ i2c_write(gspca_dev, 0x99, &sd->contrast, 1);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 data;
+
+ if (gspca_dev->ctrl_dis & (1 << COLORS_IDX))
+ return;
+ data = sd->colors - (sd->colors >> 3) - 1;
+ i2c_write(gspca_dev, 0x94, &data, 1);
+ i2c_write(gspca_dev, 0x95, &sd->colors, 1);
+}
+
static void sethvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2764,6 +3213,7 @@ static void sethvflip(struct gspca_dev *gspca_dev)
vflip = !vflip;
switch (sd->sensor) {
case SENSOR_MI1310_SOC:
+ case SENSOR_MI1320:
case SENSOR_MI1320_SOC:
data[0] = data[1] = 0; /* select page 0 */
i2c_write(gspca_dev, 0xf0, data, 2);
@@ -2801,18 +3251,29 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]);
}
-/* po1200 only */
static void setsharpness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 data;
- if (sd->sensor != SENSOR_PO1200)
- return;
- data = 0;
- i2c_write(gspca_dev, 0x03, &data, 1);
- data = 0xb5 + sd->sharpness * 3;
- i2c_write(gspca_dev, 0x61, &data, 1);
+ switch (sd->sensor) {
+ case SENSOR_PO1200:
+ data = 0;
+ i2c_write(gspca_dev, 0x03, &data, 1);
+ if (sd->sharpness < 0)
+ data = 0x6a;
+ else
+ data = 0xb5 + sd->sharpness * 3;
+ i2c_write(gspca_dev, 0x61, &data, 1);
+ break;
+ case SENSOR_POxxxx:
+ if (sd->sharpness < 0)
+ data = 0x7e; /* def = max */
+ else
+ data = 0x60 + sd->sharpness * 0x0f;
+ i2c_write(gspca_dev, 0x59, &data, 1);
+ break;
+ }
}
static int sd_start(struct gspca_dev *gspca_dev)
@@ -2922,12 +3383,27 @@ static int sd_start(struct gspca_dev *gspca_dev)
usb_exchange(gspca_dev, init);
init = po3130_rundata;
break;
- default:
-/* case SENSOR_PO1200: */
+ case SENSOR_PO1200:
GammaT = po1200_gamma;
MatrixT = po1200_matrix;
init = po1200_initVGA_data;
break;
+ default:
+/* case SENSOR_POxxxx: */
+ usb_exchange(gspca_dev, poxxxx_init_common);
+ if (mode)
+ init = poxxxx_initQVGA;
+ else
+ init = poxxxx_initVGA;
+ usb_exchange(gspca_dev, init);
+ reg_r(gspca_dev, 0x8c, 0x0000, 3);
+ reg_w(gspca_dev->dev, 0xa0,
+ gspca_dev->usb_buf[2] & 1 ? 0 : 1,
+ 0xb35c);
+ msleep(300);
+/*fixme: i2c read 04 and 05*/
+ init = poxxxx_init_end_1;
+ break;
}
usb_exchange(gspca_dev, init);
if (GammaT && MatrixT) {
@@ -2936,7 +3412,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
put_tab_to_reg(gspca_dev, GammaT, 17, 0xb86c);
put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
- /* set the led on 0x0892 0x0896 */
switch (sd->sensor) {
case SENSOR_PO1200:
case SENSOR_HV7131R:
@@ -2945,16 +3420,22 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_MI1310_SOC:
reg_w(gspca_dev->dev, 0x89, 0x058c, 0x0000);
break;
- default:
- if (!(sd->flags & FL_SAMSUNG))
- reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
- break;
}
msleep(100);
setsharpness(gspca_dev);
sethvflip(gspca_dev);
setlightfreq(gspca_dev);
}
+ if (sd->sensor == SENSOR_POxxxx) {
+ setcolors(gspca_dev);
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+
+ /* led on */
+ msleep(80);
+ reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+ usb_exchange(gspca_dev, poxxxx_init_end_2);
+ }
return 0;
}
@@ -2963,10 +3444,17 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
struct usb_device *dev = gspca_dev->dev;
struct sd *sd = (struct sd *) gspca_dev;
- if (sd->sensor == SENSOR_MI1310_SOC)
+ switch (sd->sensor) {
+ case SENSOR_MI1310_SOC:
reg_w(dev, 0x89, 0x058c, 0x00ff);
- else if (!(sd->flags & FL_SAMSUNG))
- reg_w(dev, 0x89, 0xffff, 0xffff);
+ break;
+ case SENSOR_POxxxx:
+ return;
+ default:
+ if (!(sd->flags & FL_SAMSUNG))
+ reg_w(dev, 0x89, 0xffff, 0xffff);
+ break;
+ }
reg_w(dev, 0xa0, 0x01, 0xb301);
reg_w(dev, 0xa0, 0x09, 0xb003);
}
@@ -2984,6 +3472,12 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
reg_w(dev, 0x89, 0x058c, 0x00ff);
else if (!(sd->flags & FL_SAMSUNG))
reg_w(dev, 0x89, 0xffff, 0xffff);
+
+ if (sd->sensor == SENSOR_POxxxx) {
+ reg_w(dev, 0xa0, 0x26, 0xb300);
+ reg_w(dev, 0xa0, 0x04, 0xb300);
+ reg_w(dev, 0xa0, 0x00, 0xb300);
+ }
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -3009,6 +3503,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
int l;
frame = gspca_get_i_frame(gspca_dev);
+ if (frame == NULL) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ }
l = frame->data_end - frame->data;
if (len > frame->v4l2_buf.length - l)
len = frame->v4l2_buf.length - l;
@@ -3016,6 +3514,60 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->colors;
+ return 0;
+}
+
static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 1a800fc1c00e..50986da3d912 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -1,9 +1,8 @@
/*
- * Z-Star/Vimicro zc301/zc302p/vc30x library
- * Copyright (C) 2004 2005 2006 Michel Xhaard
- * mxhaard@magic.fr
+ * Z-Star/Vimicro zc301/zc302p/vc30x library
*
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009-2010 Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr
*
* 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
@@ -22,10 +21,11 @@
#define MODULE_NAME "zc3xx"
+#include <linux/input.h>
#include "gspca.h"
#include "jpeg.h"
-MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>, "
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, "
"Serge A. Suchkov <Serge.A.S@tochka.ru>");
MODULE_DESCRIPTION("GSPCA ZC03xx/VC3xx USB Camera Driver");
MODULE_LICENSE("GPL");
@@ -39,18 +39,18 @@ static int force_sensor = -1;
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- __u8 brightness;
- __u8 contrast;
- __u8 gamma;
- __u8 autogain;
- __u8 lightfreq;
- __u8 sharpness;
+ u8 brightness;
+ u8 contrast;
+ u8 gamma;
+ u8 autogain;
+ u8 lightfreq;
+ u8 sharpness;
u8 quality; /* image quality */
#define QUALITY_MIN 40
#define QUALITY_MAX 60
#define QUALITY_DEF 50
- signed char sensor; /* Type of image sensor chip */
+ u8 sensor; /* Type of image sensor chip */
/* !! values used in different tables */
#define SENSOR_ADCM2700 0
#define SENSOR_CS2102 1
@@ -92,9 +92,8 @@ static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
#define BRIGHTNESS_IDX 0
-#define SD_BRIGHTNESS 0
{
{
.id = V4L2_CID_BRIGHTNESS,
@@ -103,26 +102,26 @@ static struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
- .default_value = 128,
+#define BRIGHTNESS_DEF 128
+ .default_value = BRIGHTNESS_DEF,
},
.set = sd_setbrightness,
.get = sd_getbrightness,
},
-#define SD_CONTRAST 1
{
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Contrast",
.minimum = 0,
- .maximum = 256,
+ .maximum = 255,
.step = 1,
- .default_value = 128,
+#define CONTRAST_DEF 128
+ .default_value = CONTRAST_DEF,
},
.set = sd_setcontrast,
.get = sd_getcontrast,
},
-#define SD_GAMMA 2
{
{
.id = V4L2_CID_GAMMA,
@@ -136,7 +135,6 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setgamma,
.get = sd_getgamma,
},
-#define SD_AUTOGAIN 3
{
{
.id = V4L2_CID_AUTOGAIN,
@@ -145,13 +143,13 @@ static struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
- .default_value = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
},
.set = sd_setautogain,
.get = sd_getautogain,
},
#define LIGHTFREQ_IDX 4
-#define SD_FREQ 4
{
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -160,12 +158,12 @@ static struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
.step = 1,
- .default_value = 1,
+#define FREQ_DEF 0
+ .default_value = FREQ_DEF,
},
.set = sd_setfreq,
.get = sd_getfreq,
},
-#define SD_SHARPNESS 5
{
{
.id = V4L2_CID_SHARPNESS,
@@ -174,7 +172,8 @@ static struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 3,
.step = 1,
- .default_value = 2,
+#define SHARPNESS_DEF 2
+ .default_value = SHARPNESS_DEF,
},
.set = sd_setsharpness,
.get = sd_getsharpness,
@@ -194,6 +193,19 @@ static const struct v4l2_pix_format vga_mode[] = {
.priv = 0},
};
+static const struct v4l2_pix_format broken_vga_mode[] = {
+ {320, 232, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 232 * 4 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 472, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 472 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
static const struct v4l2_pix_format sif_mode[] = {
{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 176,
@@ -209,9 +221,9 @@ static const struct v4l2_pix_format sif_mode[] = {
/* usb exchanges */
struct usb_action {
- __u8 req;
- __u8 val;
- __u16 idx;
+ u8 req;
+ u8 val;
+ u16 idx;
};
static const struct usb_action adcm2700_Initial[] = {
@@ -421,7 +433,7 @@ static const struct usb_action adcm2700_NoFliker[] = {
{0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */
{}
};
-static const struct usb_action cs2102_Initial[] = { /* 320x240 */
+static const struct usb_action cs2102_InitialScale[] = { /* 320x240 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
@@ -473,7 +485,7 @@ static const struct usb_action cs2102_Initial[] = { /* 320x240 */
{}
};
-static const struct usb_action cs2102_InitialScale[] = { /* 640x480 */
+static const struct usb_action cs2102_Initial[] = { /* 640x480 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
@@ -524,7 +536,7 @@ static const struct usb_action cs2102_InitialScale[] = { /* 640x480 */
{0xa0, 0x00, 0x01ad},
{}
};
-static const struct usb_action cs2102_50HZ[] = {
+static const struct usb_action cs2102_50HZScale[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
{0xaa, 0x23, 0x0001},
{0xaa, 0x24, 0x005f},
@@ -546,7 +558,7 @@ static const struct usb_action cs2102_50HZ[] = {
{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
{}
};
-static const struct usb_action cs2102_50HZScale[] = {
+static const struct usb_action cs2102_50HZ[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
{0xaa, 0x23, 0x0000},
{0xaa, 0x24, 0x00af},
@@ -568,7 +580,7 @@ static const struct usb_action cs2102_50HZScale[] = {
{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
{}
};
-static const struct usb_action cs2102_60HZ[] = {
+static const struct usb_action cs2102_60HZScale[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
{0xaa, 0x23, 0x0001},
{0xaa, 0x24, 0x0055},
@@ -590,7 +602,7 @@ static const struct usb_action cs2102_60HZ[] = {
{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
{}
};
-static const struct usb_action cs2102_60HZScale[] = {
+static const struct usb_action cs2102_60HZ[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
{0xaa, 0x23, 0x0000},
{0xaa, 0x24, 0x00aa},
@@ -612,7 +624,7 @@ static const struct usb_action cs2102_60HZScale[] = {
{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
{}
};
-static const struct usb_action cs2102_NoFliker[] = {
+static const struct usb_action cs2102_NoFlikerScale[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
{0xaa, 0x23, 0x0001},
{0xaa, 0x24, 0x005f},
@@ -634,7 +646,7 @@ static const struct usb_action cs2102_NoFliker[] = {
{0xa0, 0xff, ZC3XX_R020_HSYNC_3},
{}
};
-static const struct usb_action cs2102_NoFlikerScale[] = {
+static const struct usb_action cs2102_NoFliker[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
{0xaa, 0x23, 0x0000},
{0xaa, 0x24, 0x00af},
@@ -658,7 +670,7 @@ static const struct usb_action cs2102_NoFlikerScale[] = {
};
/* CS2102_KOCOM */
-static const struct usb_action cs2102K_Initial[] = {
+static const struct usb_action cs2102K_InitialScale[] = {
{0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
{0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT},
@@ -917,7 +929,7 @@ static const struct usb_action cs2102K_Initial[] = {
{}
};
-static const struct usb_action cs2102K_InitialScale[] = {
+static const struct usb_action cs2102K_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
@@ -1495,7 +1507,7 @@ static const struct usb_action gc0305_NoFliker[] = {
{}
};
-static const struct usb_action hdcs2020xb_Initial[] = {
+static const struct usb_action hdcs2020b_InitialScale[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* qtable 0x05 */
@@ -1627,7 +1639,7 @@ static const struct usb_action hdcs2020xb_Initial[] = {
{0xa0, 0x40, ZC3XX_R118_BGAIN},
{}
};
-static const struct usb_action hdcs2020xb_InitialScale[] = {
+static const struct usb_action hdcs2020b_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
@@ -1819,7 +1831,7 @@ static const struct usb_action hdcs2020b_NoFliker[] = {
{}
};
-static const struct usb_action hv7131bxx_Initial[] = { /* 320x240 */
+static const struct usb_action hv7131b_InitialScale[] = { /* 320x240 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
@@ -1866,7 +1878,7 @@ static const struct usb_action hv7131bxx_Initial[] = { /* 320x240 */
{}
};
-static const struct usb_action hv7131bxx_InitialScale[] = { /* 640x480*/
+static const struct usb_action hv7131b_Initial[] = { /* 640x480*/
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT},
@@ -2063,7 +2075,7 @@ static const struct usb_action hv7131b_NoFlikerScale[] = { /* 320x240 */
{}
};
-static const struct usb_action hv7131cxx_Initial[] = {
+static const struct usb_action hv7131r_InitialScale[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},
@@ -2157,7 +2169,7 @@ static const struct usb_action hv7131cxx_Initial[] = {
{}
};
-static const struct usb_action hv7131cxx_InitialScale[] = {
+static const struct usb_action hv7131r_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* diff */
@@ -2259,7 +2271,7 @@ static const struct usb_action hv7131cxx_InitialScale[] = {
{}
};
-static const struct usb_action icm105axx_Initial[] = {
+static const struct usb_action icm105a_InitialScale[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
@@ -2436,7 +2448,7 @@ static const struct usb_action icm105axx_Initial[] = {
{}
};
-static const struct usb_action icm105axx_InitialScale[] = {
+static const struct usb_action icm105a_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
@@ -2615,7 +2627,7 @@ static const struct usb_action icm105axx_InitialScale[] = {
{0xa0, 0x40, ZC3XX_R118_BGAIN},
{}
};
-static const struct usb_action icm105a_50HZ[] = {
+static const struct usb_action icm105a_50HZScale[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
{0xaa, 0x0c, 0x0020}, /* 00,0c,20,aa */
@@ -2646,7 +2658,7 @@ static const struct usb_action icm105a_50HZ[] = {
{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
{}
};
-static const struct usb_action icm105a_50HZScale[] = {
+static const struct usb_action icm105a_50HZ[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
{0xaa, 0x0c, 0x008c}, /* 00,0c,8c,aa */
@@ -2679,7 +2691,7 @@ static const struct usb_action icm105a_50HZScale[] = {
{0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */
{}
};
-static const struct usb_action icm105a_60HZ[] = {
+static const struct usb_action icm105a_60HZScale[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
{0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */
@@ -2710,7 +2722,7 @@ static const struct usb_action icm105a_60HZ[] = {
{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
{}
};
-static const struct usb_action icm105a_60HZScale[] = {
+static const struct usb_action icm105a_60HZ[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
{0xaa, 0x0c, 0x0008}, /* 00,0c,08,aa */
@@ -2743,7 +2755,7 @@ static const struct usb_action icm105a_60HZScale[] = {
{0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */
{}
};
-static const struct usb_action icm105a_NoFliker[] = {
+static const struct usb_action icm105a_NoFlikerScale[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
{0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */
@@ -2774,7 +2786,7 @@ static const struct usb_action icm105a_NoFliker[] = {
{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */
{}
};
-static const struct usb_action icm105a_NoFlikerScale[] = {
+static const struct usb_action icm105a_NoFliker[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
{0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */
@@ -2808,7 +2820,7 @@ static const struct usb_action icm105a_NoFlikerScale[] = {
{}
};
-static const struct usb_action MC501CB_InitialScale[] = {
+static const struct usb_action mc501cb_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
@@ -2928,7 +2940,7 @@ static const struct usb_action MC501CB_InitialScale[] = {
{}
};
-static const struct usb_action MC501CB_Initial[] = { /* 320x240 */
+static const struct usb_action mc501cb_InitialScale[] = { /* 320x240 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
@@ -3047,7 +3059,7 @@ static const struct usb_action MC501CB_Initial[] = { /* 320x240 */
{}
};
-static const struct usb_action MC501CB_50HZ[] = {
+static const struct usb_action mc501cb_50HZScale[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
@@ -3064,7 +3076,7 @@ static const struct usb_action MC501CB_50HZ[] = {
{}
};
-static const struct usb_action MC501CB_50HZScale[] = {
+static const struct usb_action mc501cb_50HZ[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
@@ -3081,7 +3093,7 @@ static const struct usb_action MC501CB_50HZScale[] = {
{}
};
-static const struct usb_action MC501CB_60HZ[] = {
+static const struct usb_action mc501cb_60HZScale[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
@@ -3098,7 +3110,7 @@ static const struct usb_action MC501CB_60HZ[] = {
{}
};
-static const struct usb_action MC501CB_60HZScale[] = {
+static const struct usb_action mc501cb_60HZ[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
@@ -3115,7 +3127,7 @@ static const struct usb_action MC501CB_60HZScale[] = {
{}
};
-static const struct usb_action MC501CB_NoFliker[] = {
+static const struct usb_action mc501cb_NoFlikerScale[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
@@ -3132,7 +3144,7 @@ static const struct usb_action MC501CB_NoFliker[] = {
{}
};
-static const struct usb_action MC501CB_NoFlikerScale[] = {
+static const struct usb_action mc501cb_NoFliker[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
@@ -3144,8 +3156,8 @@ static const struct usb_action MC501CB_NoFlikerScale[] = {
{}
};
-/* from zs211.inf - HKR,%OV7620%,Initial - 640x480 */
-static const struct usb_action OV7620_mode0[] = {
+/* from zs211.inf */
+static const struct usb_action ov7620_Initial[] = { /* 640x480 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
{0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, /* 00,02,40,cc */
{0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */
@@ -3214,9 +3226,7 @@ static const struct usb_action OV7620_mode0[] = {
{0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,50,cc */
{}
};
-
-/* from zs211.inf - HKR,%OV7620%,InitialScale - 320x240 */
-static const struct usb_action OV7620_mode1[] = {
+static const struct usb_action ov7620_InitialScale[] = { /* 320x240 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
{0xa0, 0x50, ZC3XX_R002_CLOCKSELECT}, /* 00,02,50,cc */
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */
@@ -3287,9 +3297,7 @@ static const struct usb_action OV7620_mode1[] = {
{0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,50,cc */
{}
};
-
-/* from zs211.inf - HKR,%OV7620%\AE,50HZ */
-static const struct usb_action OV7620_50HZ[] = {
+static const struct usb_action ov7620_50HZ[] = {
{0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */
{0xdd, 0x00, 0x0100}, /* 00,01,00,dd */
{0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */
@@ -3307,9 +3315,7 @@ static const struct usb_action OV7620_50HZ[] = {
if mode0 (640x480) */
{}
};
-
-/* from zs211.inf - HKR,%OV7620%\AE,60HZ */
-static const struct usb_action OV7620_60HZ[] = {
+static const struct usb_action ov7620_60HZ[] = {
{0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */
/* (bug in zs211.inf) */
{0xdd, 0x00, 0x0100}, /* 00,01,00,dd */
@@ -3331,9 +3337,7 @@ static const struct usb_action OV7620_60HZ[] = {
{0xa1, 0x01, 0x0037}, */
{}
};
-
-/* from zs211.inf - HKR,%OV7620%\AE,NoFliker */
-static const struct usb_action OV7620_NoFliker[] = {
+static const struct usb_action ov7620_NoFliker[] = {
{0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */
/* (bug in zs211.inf) */
{0xdd, 0x00, 0x0100}, /* 00,01,00,dd */
@@ -3354,7 +3358,7 @@ static const struct usb_action OV7620_NoFliker[] = {
{}
};
-static const struct usb_action ov7630c_Initial[] = {
+static const struct usb_action ov7630c_InitialScale[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
@@ -3511,7 +3515,7 @@ static const struct usb_action ov7630c_Initial[] = {
{}
};
-static const struct usb_action ov7630c_InitialScale[] = {
+static const struct usb_action ov7630c_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
@@ -3682,7 +3686,7 @@ static const struct usb_action pas106b_Initial_com[] = {
{}
};
-static const struct usb_action pas106b_Initial[] = { /* 176x144 */
+static const struct usb_action pas106b_InitialScale[] = { /* 176x144 */
/* JPEG control */
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
/* Sream and Sensor specific */
@@ -3800,7 +3804,7 @@ static const struct usb_action pas106b_Initial[] = { /* 176x144 */
{}
};
-static const struct usb_action pas106b_InitialScale[] = { /* 352x288 */
+static const struct usb_action pas106b_Initial[] = { /* 352x288 */
/* JPEG control */
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
/* Sream and Sensor specific */
@@ -3972,10 +3976,10 @@ static const struct usb_action pas106b_NoFliker[] = {
{}
};
-/* from usbvm31b.inf */
+/* from lvWIMv.inf 046d:08a2/:08aa 2007/06/03 */
static const struct usb_action pas202b_Initial[] = { /* 640x480 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
- {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
{0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0e,cc */
{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc */
{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
@@ -4000,7 +4004,7 @@ static const struct usb_action pas202b_Initial[] = { /* 640x480 */
{0xaa, 0x09, 0x0006}, /* 00,09,06,aa */
{0xaa, 0x0a, 0x0001}, /* 00,0a,01,aa */
{0xaa, 0x0b, 0x0001}, /* 00,0b,01,aa */
- {0xaa, 0x0c, 0x0008}, /* 00,0c,08,aa */
+ {0xaa, 0x0c, 0x0006},
{0xaa, 0x0d, 0x0000}, /* 00,0d,00,aa */
{0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
{0xaa, 0x12, 0x0005}, /* 00,12,05,aa */
@@ -4019,13 +4023,13 @@ static const struct usb_action pas202b_Initial[] = { /* 640x480 */
};
static const struct usb_action pas202b_InitialScale[] = { /* 320x240 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
- {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
{0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0e,cc */
{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */
{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */
{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */
{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */
- {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */
{0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */
{0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */
@@ -4035,7 +4039,7 @@ static const struct usb_action pas202b_InitialScale[] = { /* 320x240 */
{0xa0, 0x08, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,08,cc */
{0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,02,cc */
{0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */
- {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d8,cc */
+ {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
{0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */
{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */
{0xaa, 0x02, 0x0002}, /* 00,02,02,aa */
@@ -4044,7 +4048,7 @@ static const struct usb_action pas202b_InitialScale[] = { /* 320x240 */
{0xaa, 0x09, 0x0006}, /* 00,09,06,aa */
{0xaa, 0x0a, 0x0001}, /* 00,0a,01,aa */
{0xaa, 0x0b, 0x0001}, /* 00,0b,01,aa */
- {0xaa, 0x0c, 0x0008}, /* 00,0c,08,aa */
+ {0xaa, 0x0c, 0x0006},
{0xaa, 0x0d, 0x0000}, /* 00,0d,00,aa */
{0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
{0xaa, 0x12, 0x0005}, /* 00,12,05,aa */
@@ -4059,6 +4063,8 @@ static const struct usb_action pas202b_InitialScale[] = { /* 320x240 */
{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */
{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */
{0xa0, 0x70, ZC3XX_R18D_YTARGET}, /* 01,8d,70,cc */
+ {0xa0, 0xff, ZC3XX_R097_WINYSTARTHIGH},
+ {0xa0, 0xfe, ZC3XX_R098_WINYSTARTLOW},
{}
};
static const struct usb_action pas202b_50HZ[] = {
@@ -4066,22 +4072,22 @@ static const struct usb_action pas202b_50HZ[] = {
{0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */
{0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */
{0xaa, 0x20, 0x0002}, /* 00,20,02,aa */
- {0xaa, 0x21, 0x0068}, /* 00,21,68,aa */
+ {0xaa, 0x21, 0x001b},
{0xaa, 0x03, 0x0044}, /* 00,03,44,aa */
- {0xaa, 0x04, 0x0009}, /* 00,04,09,aa */
- {0xaa, 0x05, 0x0028}, /* 00,05,28,aa */
+ {0xaa, 0x04, 0x0008},
+ {0xaa, 0x05, 0x001b},
{0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */
{0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */
- {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,14,cc */
+ {0xa0, 0x1c, ZC3XX_R1A9_DIGITALLIMITDIFF},
{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
- {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
- {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,d2,cc */
+ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW},
{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
{0xa0, 0x4d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,4d,cc */
- {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
- {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1b, ZC3XX_R18F_AEUNFREEZE},
{0xa0, 0x44, ZC3XX_R01D_HSYNC_0}, /* 00,1d,44,cc */
{0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */
{0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ad,cc */
@@ -4094,23 +4100,23 @@ static const struct usb_action pas202b_50HZScale[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */
{0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */
- {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */
- {0xaa, 0x21, 0x006c}, /* 00,21,6c,aa */
+ {0xaa, 0x20, 0x0004},
+ {0xaa, 0x21, 0x003d},
{0xaa, 0x03, 0x0041}, /* 00,03,41,aa */
- {0xaa, 0x04, 0x0009}, /* 00,04,09,aa */
- {0xaa, 0x05, 0x002c}, /* 00,05,2c,aa */
+ {0xaa, 0x04, 0x0010},
+ {0xaa, 0x05, 0x003d},
{0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */
{0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */
- {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,14,cc */
+ {0xa0, 0x1c, ZC3XX_R1A9_DIGITALLIMITDIFF},
{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
- {0xa0, 0x0f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0f,cc */
- {0xa0, 0xbe, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,be,cc */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW},
{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
{0xa0, 0x9b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,9b,cc */
- {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
- {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1b, ZC3XX_R18F_AEUNFREEZE},
{0xa0, 0x41, ZC3XX_R01D_HSYNC_0}, /* 00,1d,41,cc */
{0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */
{0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ad,cc */
@@ -4130,16 +4136,16 @@ static const struct usb_action pas202b_60HZ[] = {
{0xaa, 0x05, 0x0000}, /* 00,05,00,aa */
{0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */
{0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */
- {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,14,cc */
+ {0xa0, 0x1c, ZC3XX_R1A9_DIGITALLIMITDIFF},
{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
- {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
- {0xa0, 0xc0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,c0,cc */
+ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW},
{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
{0xa0, 0x40, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,40,cc */
- {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
- {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1b, ZC3XX_R18F_AEUNFREEZE},
{0xa0, 0x45, ZC3XX_R01D_HSYNC_0}, /* 00,1d,45,cc */
{0xa0, 0x8e, ZC3XX_R01E_HSYNC_1}, /* 00,1e,8e,cc */
{0xa0, 0xc1, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c1,cc */
@@ -4152,23 +4158,23 @@ static const struct usb_action pas202b_60HZScale[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */
{0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */
- {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */
- {0xaa, 0x21, 0x0004}, /* 00,21,04,aa */
+ {0xaa, 0x20, 0x0004},
+ {0xaa, 0x21, 0x0008},
{0xaa, 0x03, 0x0042}, /* 00,03,42,aa */
- {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */
- {0xaa, 0x05, 0x0004}, /* 00,05,04,aa */
+ {0xaa, 0x04, 0x0010},
+ {0xaa, 0x05, 0x0008},
{0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */
{0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */
- {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,14,cc */
+ {0xa0, 0x1c, ZC3XX_R1A9_DIGITALLIMITDIFF},
{0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
- {0xa0, 0x0f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0f,cc */
- {0xa0, 0x9f, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,9f,cc */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x08, ZC3XX_R192_EXPOSURELIMITLOW},
{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
{0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,81,cc */
- {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
- {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1b, ZC3XX_R18F_AEUNFREEZE},
{0xa0, 0x42, ZC3XX_R01D_HSYNC_0}, /* 00,1d,42,cc */
{0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */
{0xa0, 0xaf, ZC3XX_R01F_HSYNC_2}, /* 00,1f,af,cc */
@@ -4182,22 +4188,22 @@ static const struct usb_action pas202b_NoFliker[] = {
{0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */
{0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */
{0xaa, 0x20, 0x0002}, /* 00,20,02,aa */
- {0xaa, 0x21, 0x0020}, /* 00,21,20,aa */
+ {0xaa, 0x21, 0x0006},
{0xaa, 0x03, 0x0040}, /* 00,03,40,aa */
{0xaa, 0x04, 0x0008}, /* 00,04,08,aa */
- {0xaa, 0x05, 0x0020}, /* 00,05,20,aa */
+ {0xaa, 0x05, 0x0006},
{0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */
{0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
- {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */
- {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x06, ZC3XX_R192_EXPOSURELIMITLOW},
{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
- {0xa0, 0x02, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,02,cc */
+ {0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW},
{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
- {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
{0xa0, 0x40, ZC3XX_R01D_HSYNC_0}, /* 00,1d,40,cc */
{0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, /* 00,1e,60,cc */
{0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
@@ -4210,23 +4216,23 @@ static const struct usb_action pas202b_NoFlikerScale[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */
{0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */
- {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */
- {0xaa, 0x21, 0x0010}, /* 00,21,10,aa */
+ {0xaa, 0x20, 0x0004},
+ {0xaa, 0x21, 0x000c},
{0xaa, 0x03, 0x0040}, /* 00,03,40,aa */
- {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */
- {0xaa, 0x05, 0x0010}, /* 00,05,10,aa */
+ {0xaa, 0x04, 0x0010},
+ {0xaa, 0x05, 0x000c},
{0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */
{0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */
- {0xa0, 0x0f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0f,cc */
- {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */
+ {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x0c, ZC3XX_R192_EXPOSURELIMITLOW},
{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */
{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
{0xa0, 0x02, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,02,cc */
{0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */
{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */
{0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */
- {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
{0xa0, 0x40, ZC3XX_R01D_HSYNC_0}, /* 00,1d,40,cc */
{0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, /* 00,1e,60,cc */
{0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */
@@ -4713,8 +4719,8 @@ static const struct usb_action pb0330_NoFlikerScale[] = {
{}
};
-/* from oem9.inf - HKR,%PO2030%,Initial - 640x480 - (close to CS2102) */
-static const struct usb_action PO2030_mode0[] = {
+/* from oem9.inf */
+static const struct usb_action po2030_Initial[] = { /* 640x480 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
{0xa0, 0x04, ZC3XX_R002_CLOCKSELECT}, /* 00,02,04,cc */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
@@ -4790,8 +4796,8 @@ static const struct usb_action PO2030_mode0[] = {
{}
};
-/* from oem9.inf - HKR,%PO2030%,InitialScale - 320x240 */
-static const struct usb_action PO2030_mode1[] = {
+/* from oem9.inf */
+static const struct usb_action po2030_InitialScale[] = { /* 320x240 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
@@ -4867,7 +4873,7 @@ static const struct usb_action PO2030_mode1[] = {
{}
};
-static const struct usb_action PO2030_50HZ[] = {
+static const struct usb_action po2030_50HZ[] = {
{0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */
{0xaa, 0x1a, 0x0001}, /* 00,1a,01,aa */
{0xaa, 0x1b, 0x000a}, /* 00,1b,0a,aa */
@@ -4889,7 +4895,7 @@ static const struct usb_action PO2030_50HZ[] = {
{}
};
-static const struct usb_action PO2030_60HZ[] = {
+static const struct usb_action po2030_60HZ[] = {
{0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */
{0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */
{0xaa, 0x1b, 0x00de}, /* 00,1b,de,aa */
@@ -4912,7 +4918,7 @@ static const struct usb_action PO2030_60HZ[] = {
{}
};
-static const struct usb_action PO2030_NoFliker[] = {
+static const struct usb_action po2030_NoFliker[] = {
{0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */
{0xaa, 0x8d, 0x000d}, /* 00,8d,0d,aa */
{0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */
@@ -4924,7 +4930,7 @@ static const struct usb_action PO2030_NoFliker[] = {
};
/* TEST */
-static const struct usb_action tas5130CK_Initial[] = {
+static const struct usb_action tas5130cK_InitialScale[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x01, 0x003b},
{0xa0, 0x0e, 0x003a},
@@ -5127,7 +5133,7 @@ static const struct usb_action tas5130CK_Initial[] = {
{}
};
-static const struct usb_action tas5130CK_InitialScale[] = {
+static const struct usb_action tas5130cK_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x01, 0x003b},
{0xa0, 0x0e, 0x003a},
@@ -5560,7 +5566,7 @@ static const struct usb_action tas5130cxx_NoFlikerScale[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_Initial[] = {
+static const struct usb_action tas5130c_vf0250_InitialScale[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */
{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */
@@ -5627,7 +5633,7 @@ static const struct usb_action tas5130c_vf0250_Initial[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_InitialScale[] = {
+static const struct usb_action tas5130c_vf0250_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */
{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */
@@ -5692,8 +5698,7 @@ static const struct usb_action tas5130c_vf0250_InitialScale[] = {
{0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */
{}
};
-/* "50HZ" light frequency banding filter */
-static const struct usb_action tas5130c_vf0250_50HZ[] = {
+static const struct usb_action tas5130c_vf0250_50HZScale[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
{0xaa, 0x84, 0x00aa}, /* 00,84,aa,aa */
@@ -5717,8 +5722,7 @@ static const struct usb_action tas5130c_vf0250_50HZ[] = {
{}
};
-/* "50HZScale" light frequency banding filter */
-static const struct usb_action tas5130c_vf0250_50HZScale[] = {
+static const struct usb_action tas5130c_vf0250_50HZ[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0003}, /* 00,83,03,aa */
{0xaa, 0x84, 0x0054}, /* 00,84,54,aa */
@@ -5742,8 +5746,7 @@ static const struct usb_action tas5130c_vf0250_50HZScale[] = {
{}
};
-/* "60HZ" light frequency banding filter */
-static const struct usb_action tas5130c_vf0250_60HZ[] = {
+static const struct usb_action tas5130c_vf0250_60HZScale[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
{0xaa, 0x84, 0x0062}, /* 00,84,62,aa */
@@ -5767,8 +5770,7 @@ static const struct usb_action tas5130c_vf0250_60HZ[] = {
{}
};
-/* "60HZScale" light frequency banding ilter */
-static const struct usb_action tas5130c_vf0250_60HZScale[] = {
+static const struct usb_action tas5130c_vf0250_60HZ[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0002}, /* 00,83,02,aa */
{0xaa, 0x84, 0x00c4}, /* 00,84,c4,aa */
@@ -5792,8 +5794,7 @@ static const struct usb_action tas5130c_vf0250_60HZScale[] = {
{}
};
-/* "NoFliker" light frequency banding flter */
-static const struct usb_action tas5130c_vf0250_NoFliker[] = {
+static const struct usb_action tas5130c_vf0250_NoFlikerScale[] = {
{0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
@@ -5815,8 +5816,7 @@ static const struct usb_action tas5130c_vf0250_NoFliker[] = {
{}
};
-/* "NoFlikerScale" light frequency banding filter */
-static const struct usb_action tas5130c_vf0250_NoFlikerScale[] = {
+static const struct usb_action tas5130c_vf0250_NoFliker[] = {
{0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
@@ -5839,7 +5839,7 @@ static const struct usb_action tas5130c_vf0250_NoFlikerScale[] = {
};
static u8 reg_r_i(struct gspca_dev *gspca_dev,
- __u16 index)
+ u16 index)
{
usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0),
@@ -5852,7 +5852,7 @@ static u8 reg_r_i(struct gspca_dev *gspca_dev,
}
static u8 reg_r(struct gspca_dev *gspca_dev,
- __u16 index)
+ u16 index)
{
u8 ret;
@@ -5862,8 +5862,8 @@ static u8 reg_r(struct gspca_dev *gspca_dev,
}
static void reg_w_i(struct usb_device *dev,
- __u8 value,
- __u16 index)
+ u8 value,
+ u16 index)
{
usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
@@ -5874,18 +5874,18 @@ static void reg_w_i(struct usb_device *dev,
}
static void reg_w(struct usb_device *dev,
- __u8 value,
- __u16 index)
+ u8 value,
+ u16 index)
{
PDEBUG(D_USBO, "reg w [%04x] = %02x", index, value);
reg_w_i(dev, value, index);
}
-static __u16 i2c_read(struct gspca_dev *gspca_dev,
- __u8 reg)
+static u16 i2c_read(struct gspca_dev *gspca_dev,
+ u8 reg)
{
- __u8 retbyte;
- __u16 retval;
+ u8 retbyte;
+ u16 retval;
reg_w_i(gspca_dev->dev, reg, 0x0092);
reg_w_i(gspca_dev->dev, 0x02, 0x0090); /* <- read command */
@@ -5900,12 +5900,12 @@ static __u16 i2c_read(struct gspca_dev *gspca_dev,
return retval;
}
-static __u8 i2c_write(struct gspca_dev *gspca_dev,
- __u8 reg,
- __u8 valL,
- __u8 valH)
+static u8 i2c_write(struct gspca_dev *gspca_dev,
+ u8 reg,
+ u8 valL,
+ u8 valH)
{
- __u8 retbyte;
+ u8 retbyte;
reg_w_i(gspca_dev->dev, reg, 0x92);
reg_w_i(gspca_dev->dev, valL, 0x93);
@@ -5957,24 +5957,24 @@ static void setmatrix(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
- const __u8 *matrix;
+ const u8 *matrix;
static const u8 adcm2700_matrix[9] =
/* {0x66, 0xed, 0xed, 0xed, 0x66, 0xed, 0xed, 0xed, 0x66}; */
/*ms-win*/
{0x74, 0xed, 0xed, 0xed, 0x74, 0xed, 0xed, 0xed, 0x74};
- static const __u8 gc0305_matrix[9] =
+ static const u8 gc0305_matrix[9] =
{0x50, 0xf8, 0xf8, 0xf8, 0x50, 0xf8, 0xf8, 0xf8, 0x50};
- static const __u8 ov7620_matrix[9] =
+ static const u8 ov7620_matrix[9] =
{0x58, 0xf4, 0xf4, 0xf4, 0x58, 0xf4, 0xf4, 0xf4, 0x58};
- static const __u8 pas202b_matrix[9] =
+ static const u8 pas202b_matrix[9] =
{0x4c, 0xf5, 0xff, 0xf9, 0x51, 0xf5, 0xfb, 0xed, 0x5f};
- static const __u8 po2030_matrix[9] =
+ static const u8 po2030_matrix[9] =
{0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60};
static const u8 tas5130c_matrix[9] =
{0x68, 0xec, 0xec, 0xec, 0x68, 0xec, 0xec, 0xec, 0x68};
- static const __u8 vf0250_matrix[9] =
+ static const u8 vf0250_matrix[9] =
{0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b};
- static const __u8 *matrix_tb[SENSOR_MAX] = {
+ static const u8 *matrix_tb[SENSOR_MAX] = {
adcm2700_matrix, /* SENSOR_ADCM2700 0 */
ov7620_matrix, /* SENSOR_CS2102 1 */
NULL, /* SENSOR_CS2102K 2 */
@@ -6006,11 +6006,12 @@ static void setmatrix(struct gspca_dev *gspca_dev)
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 brightness;
+ u8 brightness;
switch (sd->sensor) {
case SENSOR_GC0305:
case SENSOR_OV7620:
+ case SENSOR_PAS202B:
case SENSOR_PO2030:
return;
}
@@ -6034,7 +6035,7 @@ static void setsharpness(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
int sharpness;
- static const __u8 sharpness_tb[][2] = {
+ static const u8 sharpness_tb[][2] = {
{0x02, 0x03},
{0x04, 0x07},
{0x08, 0x0f},
@@ -6053,118 +6054,69 @@ static void setcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
- const __u8 *Tgamma, *Tgradient;
- int g, i, k;
- static const __u8 kgamma_tb[16] = /* delta for contrast */
+ const u8 *Tgamma;
+ int g, i, k, adj, gp;
+ u8 gr[16];
+ static const u8 delta_tb[16] = /* delta for contrast */
{0x15, 0x0d, 0x0a, 0x09, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
- static const __u8 kgrad_tb[16] =
- {0x1b, 0x06, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x04};
- static const __u8 Tgamma_1[16] =
+ static const u8 gamma_tb[6][16] = {
{0x00, 0x00, 0x03, 0x0d, 0x1b, 0x2e, 0x45, 0x5f,
- 0x79, 0x93, 0xab, 0xc1, 0xd4, 0xe5, 0xf3, 0xff};
- static const __u8 Tgradient_1[16] =
- {0x00, 0x01, 0x05, 0x0b, 0x10, 0x15, 0x18, 0x1a,
- 0x1a, 0x18, 0x16, 0x14, 0x12, 0x0f, 0x0d, 0x06};
- static const __u8 Tgamma_2[16] =
+ 0x79, 0x93, 0xab, 0xc1, 0xd4, 0xe5, 0xf3, 0xff},
{0x01, 0x0c, 0x1f, 0x3a, 0x53, 0x6d, 0x85, 0x9c,
- 0xb0, 0xc2, 0xd1, 0xde, 0xe9, 0xf2, 0xf9, 0xff};
- static const __u8 Tgradient_2[16] =
- {0x05, 0x0f, 0x16, 0x1a, 0x19, 0x19, 0x17, 0x15,
- 0x12, 0x10, 0x0e, 0x0b, 0x09, 0x08, 0x06, 0x03};
- static const __u8 Tgamma_3[16] =
+ 0xb0, 0xc2, 0xd1, 0xde, 0xe9, 0xf2, 0xf9, 0xff},
{0x04, 0x16, 0x30, 0x4e, 0x68, 0x81, 0x98, 0xac,
- 0xbe, 0xcd, 0xda, 0xe4, 0xed, 0xf5, 0xfb, 0xff};
- static const __u8 Tgradient_3[16] =
- {0x0c, 0x16, 0x1b, 0x1c, 0x19, 0x18, 0x15, 0x12,
- 0x10, 0x0d, 0x0b, 0x09, 0x08, 0x06, 0x05, 0x03};
- static const __u8 Tgamma_4[16] =
+ 0xbe, 0xcd, 0xda, 0xe4, 0xed, 0xf5, 0xfb, 0xff},
{0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
- 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff};
- static const __u8 Tgradient_4[16] =
- {0x26, 0x22, 0x20, 0x1c, 0x16, 0x13, 0x10, 0x0d,
- 0x0b, 0x09, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02};
- static const __u8 Tgamma_5[16] =
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff},
{0x20, 0x4b, 0x6e, 0x8d, 0xa3, 0xb5, 0xc5, 0xd2,
- 0xdc, 0xe5, 0xec, 0xf2, 0xf6, 0xfa, 0xfd, 0xff};
- static const __u8 Tgradient_5[16] =
- {0x37, 0x26, 0x20, 0x1a, 0x14, 0x10, 0x0e, 0x0b,
- 0x09, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02};
- static const __u8 Tgamma_6[16] = /* ?? was gamma 5 */
+ 0xdc, 0xe5, 0xec, 0xf2, 0xf6, 0xfa, 0xfd, 0xff},
{0x24, 0x44, 0x64, 0x84, 0x9d, 0xb2, 0xc4, 0xd3,
- 0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff};
- static const __u8 Tgradient_6[16] =
- {0x18, 0x20, 0x20, 0x1c, 0x16, 0x13, 0x10, 0x0e,
- 0x0b, 0x09, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01};
- static const __u8 *gamma_tb[] = {
- NULL, Tgamma_1, Tgamma_2,
- Tgamma_3, Tgamma_4, Tgamma_5, Tgamma_6
+ 0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff},
};
- static const __u8 *gradient_tb[] = {
- NULL, Tgradient_1, Tgradient_2,
- Tgradient_3, Tgradient_4, Tgradient_5, Tgradient_6
- };
-#ifdef GSPCA_DEBUG
- __u8 v[16];
-#endif
- Tgamma = gamma_tb[sd->gamma];
- Tgradient = gradient_tb[sd->gamma];
+ Tgamma = gamma_tb[sd->gamma - 1];
- k = (sd->contrast - 128) /* -128 / 128 */
- * Tgamma[0];
- PDEBUG(D_CONF, "gamma:%d contrast:%d gamma coeff: %d/128",
- sd->gamma, sd->contrast, k);
+ k = ((int) sd->contrast - 128); /* -128 / 128 */
+ adj = 0;
+ gp = 0;
for (i = 0; i < 16; i++) {
- g = Tgamma[i] + kgamma_tb[i] * k / 128;
+ g = Tgamma[i] - delta_tb[i] * k / 128 - adj / 2;
if (g > 0xff)
g = 0xff;
else if (g <= 0)
g = 1;
reg_w(dev, g, 0x0120 + i); /* gamma */
-#ifdef GSPCA_DEBUG
- if (gspca_debug & D_CONF)
- v[i] = g;
-#endif
- }
- PDEBUG(D_CONF, "tb: %02x %02x %02x %02x %02x %02x %02x %02x",
- v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
- PDEBUG(D_CONF, " %02x %02x %02x %02x %02x %02x %02x %02x",
- v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]);
- for (i = 0; i < 16; i++) {
- g = Tgradient[i] - kgrad_tb[i] * k / 128;
- if (g > 0xff)
- g = 0xff;
- else if (g <= 0) {
- if (i != 15)
- g = 0;
+ if (k > 0)
+ adj--;
+ else
+ adj++;
+
+ if (i != 0) {
+ if (gp == 0)
+ gr[i - 1] = 0;
else
- g = 1;
+ gr[i - 1] = g - gp;
}
- reg_w(dev, g, 0x0130 + i); /* gradient */
-#ifdef GSPCA_DEBUG
- if (gspca_debug & D_CONF)
- v[i] = g;
-#endif
+ gp = g;
}
- PDEBUG(D_CONF, " %02x %02x %02x %02x %02x %02x %02x %02x",
- v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
- PDEBUG(D_CONF, " %02x %02x %02x %02x %02x %02x %02x %02x",
- v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]);
+ gr[15] = gr[14] / 2;
+ for (i = 0; i < 16; i++)
+ reg_w(dev, gr[i], 0x0130 + i); /* gradient */
}
static void setquality(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
- __u8 frxt;
+ u8 frxt;
switch (sd->sensor) {
case SENSOR_ADCM2700:
case SENSOR_GC0305:
case SENSOR_HV7131B:
case SENSOR_OV7620:
+ case SENSOR_PAS202B:
case SENSOR_PO2030:
return;
}
@@ -6218,9 +6170,9 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
hdcs2020b_50HZ, hdcs2020b_50HZ,
hdcs2020b_60HZ, hdcs2020b_60HZ},
/* SENSOR_HV7131B 5 */
- {hv7131b_NoFlikerScale, hv7131b_NoFliker,
- hv7131b_50HZScale, hv7131b_50HZ,
- hv7131b_60HZScale, hv7131b_60HZ},
+ {hv7131b_NoFliker, hv7131b_NoFlikerScale,
+ hv7131b_50HZ, hv7131b_50HZScale,
+ hv7131b_60HZ, hv7131b_60HZScale},
/* SENSOR_HV7131C 6 */
{NULL, NULL,
NULL, NULL,
@@ -6230,17 +6182,17 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
icm105a_50HZ, icm105a_50HZScale,
icm105a_60HZ, icm105a_60HZScale},
/* SENSOR_MC501CB 8 */
- {MC501CB_NoFliker, MC501CB_NoFlikerScale,
- MC501CB_50HZ, MC501CB_50HZScale,
- MC501CB_60HZ, MC501CB_60HZScale},
+ {mc501cb_NoFliker, mc501cb_NoFlikerScale,
+ mc501cb_50HZ, mc501cb_50HZScale,
+ mc501cb_60HZ, mc501cb_60HZScale},
/* SENSOR_MI0360SOC 9 */
- {mi360soc_AENoFlikerScale, mi360soc_AENoFliker,
- mi360soc_AE50HZScale, mi360soc_AE50HZ,
- mi360soc_AE60HZScale, mi360soc_AE60HZ},
+ {mi360soc_AENoFliker, mi360soc_AENoFlikerScale,
+ mi360soc_AE50HZ, mi360soc_AE50HZScale,
+ mi360soc_AE60HZ, mi360soc_AE60HZScale},
/* SENSOR_OV7620 10 */
- {OV7620_NoFliker, OV7620_NoFliker,
- OV7620_50HZ, OV7620_50HZ,
- OV7620_60HZ, OV7620_60HZ},
+ {ov7620_NoFliker, ov7620_NoFliker,
+ ov7620_50HZ, ov7620_50HZ,
+ ov7620_60HZ, ov7620_60HZ},
/* SENSOR_OV7630C 11 */
{NULL, NULL,
NULL, NULL,
@@ -6258,17 +6210,17 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
pb0330_50HZScale, pb0330_50HZ,
pb0330_60HZScale, pb0330_60HZ},
/* SENSOR_PO2030 15 */
- {PO2030_NoFliker, PO2030_NoFliker,
- PO2030_50HZ, PO2030_50HZ,
- PO2030_60HZ, PO2030_60HZ},
+ {po2030_NoFliker, po2030_NoFliker,
+ po2030_50HZ, po2030_50HZ,
+ po2030_60HZ, po2030_60HZ},
/* SENSOR_TAS5130CK 16 */
- {tas5130cxx_NoFlikerScale, tas5130cxx_NoFliker,
- tas5130cxx_50HZScale, tas5130cxx_50HZ,
- tas5130cxx_60HZScale, tas5130cxx_60HZ},
+ {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+ tas5130cxx_50HZ, tas5130cxx_50HZScale,
+ tas5130cxx_60HZ, tas5130cxx_60HZScale},
/* SENSOR_TAS5130CXX 17 */
- {tas5130cxx_NoFlikerScale, tas5130cxx_NoFliker,
- tas5130cxx_50HZScale, tas5130cxx_50HZ,
- tas5130cxx_60HZScale, tas5130cxx_60HZ},
+ {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+ tas5130cxx_50HZ, tas5130cxx_50HZScale,
+ tas5130cxx_60HZ, tas5130cxx_60HZScale},
/* SENSOR_TAS5130C_VF0250 18 */
{tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale,
tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale,
@@ -6277,9 +6229,9 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
i = sd->lightfreq * 2;
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
- if (!mode)
- i++; /* 640x480 */
- zc3_freq = freq_tb[(int) sd->sensor][i];
+ if (mode)
+ i++; /* 320x240 */
+ zc3_freq = freq_tb[sd->sensor][i];
if (zc3_freq != NULL) {
usb_exchange(gspca_dev, zc3_freq);
switch (sd->sensor) {
@@ -6297,6 +6249,9 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
reg_w(gspca_dev->dev, 0x44, 0x0002);
}
break;
+ case SENSOR_PAS202B:
+ reg_w(gspca_dev->dev, 0x00, 0x01a7);
+ break;
}
}
return 0;
@@ -6305,7 +6260,7 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
static void setautogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 autoval;
+ u8 autoval;
if (sd->autogain)
autoval = 0x42;
@@ -6333,6 +6288,12 @@ static void send_unknown(struct usb_device *dev, int sensor)
reg_w(dev, 0x02, 0x003b);
reg_w(dev, 0x00, 0x0038);
break;
+ case SENSOR_PAS202B:
+ reg_w(dev, 0x03, 0x003b);
+ reg_w(dev, 0x0c, 0x003a);
+ reg_w(dev, 0x0b, 0x0039);
+ reg_w(dev, 0x0b, 0x0038);
+ break;
}
}
@@ -6349,7 +6310,7 @@ static void start_2wr_probe(struct usb_device *dev, int sensor)
static int sif_probe(struct gspca_dev *gspca_dev)
{
- __u16 checkword;
+ u16 checkword;
start_2wr_probe(gspca_dev->dev, 0x0f); /* PAS106 */
reg_w(gspca_dev->dev, 0x08, 0x008d);
@@ -6392,6 +6353,7 @@ static int vga_2wr_probe(struct gspca_dev *gspca_dev)
}
start_2wr_probe(dev, 0x08); /* HDCS2020 */
+ i2c_write(gspca_dev, 0x1c, 0x00, 0x00);
i2c_write(gspca_dev, 0x15, 0xaa, 0x00);
retword = i2c_read(gspca_dev, 0x15);
if (retword != 0)
@@ -6420,8 +6382,10 @@ static int vga_2wr_probe(struct gspca_dev *gspca_dev)
i2c_write(gspca_dev, 0x03, 0xaa, 0x00);
msleep(50);
retword = i2c_read(gspca_dev, 0x03);
- if (retword != 0)
+ if (retword != 0) {
+ send_unknown(dev, SENSOR_PAS202B);
return 0x0e; /* PAS202BCB */
+ }
start_2wr_probe(dev, 0x02); /* TAS5130C */
i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
@@ -6457,8 +6421,8 @@ ov_check:
}
struct sensor_by_chipset_revision {
- __u16 revision;
- __u8 internal_sensor_id;
+ u16 revision;
+ u8 internal_sensor_id;
};
static const struct sensor_by_chipset_revision chipset_revision_sensor[] = {
{0xc000, 0x12}, /* TAS5130C */
@@ -6467,6 +6431,7 @@ static const struct sensor_by_chipset_revision chipset_revision_sensor[] = {
{0x8001, 0x13},
{0x8000, 0x14}, /* CS2102K */
{0x8400, 0x15}, /* TAS5130K */
+ {0xe400, 0x15},
};
static int vga_3wr_probe(struct gspca_dev *gspca_dev)
@@ -6474,7 +6439,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
int i;
- __u8 retbyte;
+ u8 retbyte;
u16 retword;
/*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/
@@ -6622,8 +6587,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
int sensor;
- int vga = 1; /* 1: vga, 0: sif */
- static const __u8 gamma[SENSOR_MAX] = {
+ static const u8 gamma[SENSOR_MAX] = {
4, /* SENSOR_ADCM2700 0 */
4, /* SENSOR_CS2102 1 */
5, /* SENSOR_CS2102K 2 */
@@ -6644,9 +6608,30 @@ static int sd_config(struct gspca_dev *gspca_dev,
3, /* SENSOR_TAS5130CXX 17 */
3, /* SENSOR_TAS5130C_VF0250 18 */
};
+ static const u8 mode_tb[SENSOR_MAX] = {
+ 2, /* SENSOR_ADCM2700 0 */
+ 1, /* SENSOR_CS2102 1 */
+ 1, /* SENSOR_CS2102K 2 */
+ 1, /* SENSOR_GC0305 3 */
+ 1, /* SENSOR_HDCS2020b 4 */
+ 1, /* SENSOR_HV7131B 5 */
+ 1, /* SENSOR_HV7131C 6 */
+ 1, /* SENSOR_ICM105A 7 */
+ 2, /* SENSOR_MC501CB 8 */
+ 1, /* SENSOR_MI0360SOC 9 */
+ 2, /* SENSOR_OV7620 10 */
+ 1, /* SENSOR_OV7630C 11 */
+ 0, /* SENSOR_PAS106 12 */
+ 1, /* SENSOR_PAS202B 13 */
+ 1, /* SENSOR_PB0330 14 */
+ 1, /* SENSOR_PO2030 15 */
+ 1, /* SENSOR_TAS5130CK 16 */
+ 1, /* SENSOR_TAS5130CXX 17 */
+ 1, /* SENSOR_TAS5130C_VF0250 18 */
+ };
/* define some sensors from the vendor/product */
- sd->sharpness = 2;
+ sd->sharpness = SHARPNESS_DEF;
sd->sensor = id->driver_info;
sensor = zcxx_probeSensor(gspca_dev);
if (sensor >= 0)
@@ -6671,8 +6656,21 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
break;
case 0:
- PDEBUG(D_PROBE, "Find Sensor HV7131B");
- sd->sensor = SENSOR_HV7131B;
+ /* check the sensor type */
+ sensor = i2c_read(gspca_dev, 0x00);
+ PDEBUG(D_PROBE, "Sensor hv7131 type %d", sensor);
+ switch (sensor) {
+ case 0: /* hv7131b */
+ case 1: /* hv7131e */
+ PDEBUG(D_PROBE, "Find Sensor HV7131B");
+ sd->sensor = SENSOR_HV7131B;
+ break;
+ default:
+/* case 2: * hv7131r */
+ PDEBUG(D_PROBE, "Find Sensor HV7131R(c)");
+ sd->sensor = SENSOR_HV7131C;
+ break;
+ }
break;
case 0x02:
PDEBUG(D_PROBE, "Sensor TAS5130C");
@@ -6699,12 +6697,11 @@ static int sd_config(struct gspca_dev *gspca_dev,
case 0x0e:
PDEBUG(D_PROBE, "Find Sensor PAS202B");
sd->sensor = SENSOR_PAS202B;
- sd->sharpness = 1;
+/* sd->sharpness = 1; */
break;
case 0x0f:
PDEBUG(D_PROBE, "Find Sensor PAS106");
sd->sensor = SENSOR_PAS106;
- vga = 0; /* SIF */
break;
case 0x10:
case 0x12:
@@ -6770,31 +6767,38 @@ static int sd_config(struct gspca_dev *gspca_dev,
if (sensor < 0x20) {
if (sensor == -1 || sensor == 0x10 || sensor == 0x12)
reg_w(gspca_dev->dev, 0x02, 0x0010);
- else
- reg_w(gspca_dev->dev, sensor & 0x0f, 0x0010);
reg_r(gspca_dev, 0x0010);
}
cam = &gspca_dev->cam;
/*fixme:test*/
gspca_dev->nbalt--;
- if (vga) {
- cam->cam_mode = vga_mode;
- cam->nmodes = ARRAY_SIZE(vga_mode);
- } else {
+ switch (mode_tb[sd->sensor]) {
+ case 0:
cam->cam_mode = sif_mode;
cam->nmodes = ARRAY_SIZE(sif_mode);
+ break;
+ case 1:
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+ break;
+ default:
+/* case 2: */
+ cam->cam_mode = broken_vga_mode;
+ cam->nmodes = ARRAY_SIZE(broken_vga_mode);
+ break;
}
- sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
- sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
- sd->gamma = gamma[(int) sd->sensor];
- sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
- sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->gamma = gamma[sd->sensor];
+ sd->autogain = AUTOGAIN_DEF;
+ sd->lightfreq = FREQ_DEF;
sd->quality = QUALITY_DEF;
switch (sd->sensor) {
case SENSOR_GC0305:
case SENSOR_OV7620:
+ case SENSOR_PAS202B:
case SENSOR_PO2030:
gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX);
break;
@@ -6805,14 +6809,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
break;
}
- /* switch the led off */
- reg_w(gspca_dev->dev, 0x01, 0x0000);
return 0;
}
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
+ /* switch off the led */
reg_w(gspca_dev->dev, 0x01, 0x0000);
return 0;
}
@@ -6821,28 +6824,27 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
- const struct usb_action *zc3_init;
int mode;
static const struct usb_action *init_tb[SENSOR_MAX][2] = {
{adcm2700_Initial, adcm2700_InitialScale}, /* 0 */
- {cs2102_InitialScale, cs2102_Initial}, /* 1 */
- {cs2102K_InitialScale, cs2102K_Initial}, /* 2 */
+ {cs2102_Initial, cs2102_InitialScale}, /* 1 */
+ {cs2102K_Initial, cs2102K_InitialScale}, /* 2 */
{gc0305_Initial, gc0305_InitialScale}, /* 3 */
- {hdcs2020xb_InitialScale, hdcs2020xb_Initial}, /* 4 */
- {hv7131bxx_InitialScale, hv7131bxx_Initial}, /* 5 */
- {hv7131cxx_InitialScale, hv7131cxx_Initial}, /* 6 */
- {icm105axx_InitialScale, icm105axx_Initial}, /* 7 */
- {MC501CB_InitialScale, MC501CB_Initial}, /* 8 */
+ {hdcs2020b_Initial, hdcs2020b_InitialScale}, /* 4 */
+ {hv7131b_Initial, hv7131b_InitialScale}, /* 5 */
+ {hv7131r_Initial, hv7131r_InitialScale}, /* 6 */
+ {icm105a_Initial, icm105a_InitialScale}, /* 7 */
+ {mc501cb_Initial, mc501cb_InitialScale}, /* 8 */
{mi0360soc_Initial, mi0360soc_InitialScale}, /* 9 */
- {OV7620_mode0, OV7620_mode1}, /* 10 */
- {ov7630c_InitialScale, ov7630c_Initial}, /* 11 */
- {pas106b_InitialScale, pas106b_Initial}, /* 12 */
+ {ov7620_Initial, ov7620_InitialScale}, /* 10 */
+ {ov7630c_Initial, ov7630c_InitialScale}, /* 11 */
+ {pas106b_Initial, pas106b_InitialScale}, /* 12 */
{pas202b_Initial, pas202b_InitialScale}, /* 13 */
{pb0330_Initial, pb0330_InitialScale}, /* 14 */
- {PO2030_mode0, PO2030_mode1}, /* 15 */
- {tas5130CK_InitialScale, tas5130CK_Initial}, /* 16 */
+ {po2030_Initial, po2030_InitialScale}, /* 15 */
+ {tas5130cK_Initial, tas5130cK_InitialScale}, /* 16 */
{tas5130cxx_Initial, tas5130cxx_InitialScale}, /* 17 */
- {tas5130c_vf0250_InitialScale, tas5130c_vf0250_Initial},
+ {tas5130c_vf0250_Initial, tas5130c_vf0250_InitialScale},
/* 18 */
};
@@ -6854,8 +6856,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
0x21); /* JPEG 422 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
- mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
- zc3_init = init_tb[(int) sd->sensor][mode];
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
switch (sd->sensor) {
case SENSOR_HV7131C:
zcxx_probeSensor(gspca_dev);
@@ -6864,7 +6865,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
usb_exchange(gspca_dev, pas106b_Initial_com);
break;
}
- usb_exchange(gspca_dev, zc3_init);
+ usb_exchange(gspca_dev, init_tb[sd->sensor][mode]);
switch (sd->sensor) {
case SENSOR_ADCM2700:
@@ -6883,6 +6884,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(dev, 0x02, 0x003b);
reg_w(dev, 0x00, 0x0038);
break;
+ case SENSOR_PAS202B:
+ reg_w(dev, 0x03, 0x003b);
+ reg_w(dev, 0x0c, 0x003a);
+ reg_w(dev, 0x0b, 0x0039);
+ break;
}
setmatrix(gspca_dev);
@@ -6961,13 +6967,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
switch (sd->sensor) {
case SENSOR_PO2030:
msleep(50);
- reg_r(gspca_dev, 0x0008);
- reg_r(gspca_dev, 0x0007);
- /*fall thru*/
- case SENSOR_PAS202B:
reg_w(dev, 0x00, 0x0007); /* (from win traces) */
reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
break;
+ case SENSOR_PAS202B:
+ reg_w(dev, 0x32, 0x0007); /* (from win traces) */
+ reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
+ break;
}
return 0;
}
@@ -7165,6 +7171,22 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
return 0;
}
+#ifdef CONFIG_INPUT
+static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* interrupt packet data */
+ int len) /* interrput packet length */
+{
+ if (len == 8 && data[4] == 1) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+ input_sync(gspca_dev->input_dev);
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ }
+
+ return 0;
+}
+#endif
+
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
@@ -7177,6 +7199,9 @@ static const struct sd_desc sd_desc = {
.querymenu = sd_querymenu,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
+#ifdef CONFIG_INPUT
+ .int_pkt_scan = sd_int_pkt_scan,
+#endif
};
static const __devinitdata struct usb_device_id device_table[] = {
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index 51f393d03a46..2fc9865fd486 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -39,12 +39,12 @@ int hdpvr_debug;
module_param(hdpvr_debug, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(hdpvr_debug, "enable debugging output");
-uint default_video_input = HDPVR_VIDEO_INPUTS;
+static uint default_video_input = HDPVR_VIDEO_INPUTS;
module_param(default_video_input, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(default_video_input, "default video input: 0=Component / "
"1=S-Video / 2=Composite");
-uint default_audio_input = HDPVR_AUDIO_INPUTS;
+static uint default_audio_input = HDPVR_AUDIO_INPUTS;
module_param(default_audio_input, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(default_audio_input, "default audio input: 0=RCA back / "
"1=RCA front / 2=S/PDIF");
@@ -59,6 +59,7 @@ static struct usb_device_id hdpvr_table[] = {
{ USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID) },
{ USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID1) },
{ USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID2) },
+ { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID3) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, hdpvr_table);
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index fdd782039e9d..196f82de48f0 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -302,7 +302,8 @@ static int hdpvr_start_streaming(struct hdpvr_device *dev)
/* function expects dev->io_mutex to be hold by caller */
static int hdpvr_stop_streaming(struct hdpvr_device *dev)
{
- uint actual_length, c = 0;
+ int actual_length;
+ uint c = 0;
u8 *buf;
if (dev->status == STATUS_IDLE)
@@ -572,7 +573,7 @@ static int vidioc_querycap(struct file *file, void *priv,
struct hdpvr_device *dev = video_drvdata(file);
strcpy(cap->driver, "hdpvr");
- strcpy(cap->card, "Haupauge HD PVR");
+ strcpy(cap->card, "Hauppauge HD PVR");
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
cap->version = HDPVR_VERSION;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h
index 1edd8759121e..49ae25d83d10 100644
--- a/drivers/media/video/hdpvr/hdpvr.h
+++ b/drivers/media/video/hdpvr/hdpvr.h
@@ -30,6 +30,7 @@
#define HD_PVR_PRODUCT_ID 0x4900
#define HD_PVR_PRODUCT_ID1 0x4901
#define HD_PVR_PRODUCT_ID2 0x4902
+#define HD_PVR_PRODUCT_ID3 0x4982
#define UNSET (-1U)
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
index 60d992ee2589..e620a3a92f25 100644
--- a/drivers/media/video/hexium_gemini.c
+++ b/drivers/media/video/hexium_gemini.c
@@ -352,9 +352,13 @@ static struct saa7146_ext_vv vv_data;
static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
{
struct hexium *hexium = (struct hexium *) dev->ext_priv;
+ int ret;
DEB_EE((".\n"));
+ ret = saa7146_vv_devinit(dev);
+ if (ret)
+ return ret;
hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
if (NULL == hexium) {
printk("hexium_gemini: not enough kernel memory in hexium_attach().\n");
@@ -400,9 +404,10 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
vv_data.ops.vidioc_g_input = vidioc_g_input;
vv_data.ops.vidioc_s_input = vidioc_s_input;
- if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) {
+ ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
+ if (ret < 0) {
printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
- return -1;
+ return ret;
}
printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num);
diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c
index 938a1f8f880a..fe596a1c12a8 100644
--- a/drivers/media/video/hexium_orion.c
+++ b/drivers/media/video/hexium_orion.c
@@ -216,6 +216,10 @@ static int hexium_probe(struct saa7146_dev *dev)
return -EFAULT;
}
+ err = saa7146_vv_devinit(dev);
+ if (err)
+ return err;
+
hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
if (NULL == hexium) {
printk("hexium_orion: hexium_probe: not enough kernel memory.\n");
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index b86e35386cee..da18d698e7f2 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -299,7 +299,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct ir_scancode_table *ir_codes = NULL;
const char *name = NULL;
- int ir_type = 0;
+ u64 ir_type = 0;
struct IR_i2c *ir;
struct input_dev *input_dev;
struct i2c_adapter *adap = client->adapter;
@@ -331,6 +331,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
ir_codes = &ir_codes_pv951_table;
break;
case 0x18:
+ case 0x1f:
case 0x1a:
name = "Hauppauge";
ir->get_key = get_key_haup;
@@ -446,7 +447,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
input_dev->name = ir->name;
input_dev->phys = ir->phys;
- err = ir_input_register(ir->input, ir->ir_codes);
+ err = ir_input_register(ir->input, ir->ir_codes, NULL);
if (err)
goto err_out_free;
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index 79d0fe4990d6..ca1fd3227a93 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -1210,6 +1210,53 @@ static const struct ivtv_card ivtv_card_buffalo = {
.i2c = &ivtv_i2c_std,
};
+/* ------------------------------------------------------------------------- */
+/* Sony Kikyou */
+
+static const struct ivtv_card_pci_info ivtv_pci_kikyou[] = {
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_SONY, 0x813d },
+ { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_kikyou = {
+ .type = IVTV_CARD_KIKYOU,
+ .name = "Sony VAIO Giga Pocket (ENX Kikyou)",
+ .v4l2_capabilities = IVTV_CAP_ENCODER,
+ .hw_video = IVTV_HW_SAA7115,
+ .hw_audio = IVTV_HW_GPIO,
+ .hw_audio_ctrl = IVTV_HW_GPIO,
+ .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER,
+ .video_inputs = {
+ { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE1 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE1 },
+ { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO1 },
+ },
+ .audio_inputs = {
+ { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER },
+ { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN },
+ { IVTV_CARD_INPUT_LINE_IN2, IVTV_GPIO_LINE_IN },
+ },
+ .gpio_init = { .direction = 0x03e1, .initial_value = 0x0320 },
+ .gpio_audio_input = { .mask = 0x0060,
+ .tuner = 0x0020,
+ .linein = 0x0000,
+ .radio = 0x0060 },
+ .gpio_audio_mute = { .mask = 0x0000,
+ .mute = 0x0000 }, /* 0x200? Disable for now. */
+ .gpio_audio_mode = { .mask = 0x0080,
+ .mono = 0x0000,
+ .stereo = 0x0000, /* SAP */
+ .lang1 = 0x0080,
+ .lang2 = 0x0000,
+ .both = 0x0080 },
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_SONY_BTF_PXN01Z },
+ },
+ .pci_list = ivtv_pci_kikyou,
+ .i2c = &ivtv_i2c_std,
+};
+
+
static const struct ivtv_card *ivtv_card_list[] = {
&ivtv_card_pvr250,
&ivtv_card_pvr350,
@@ -1238,6 +1285,7 @@ static const struct ivtv_card *ivtv_card_list[] = {
&ivtv_card_aver_m104,
&ivtv_card_buffalo,
&ivtv_card_aver_ultra1500mce,
+ &ivtv_card_kikyou,
/* Variations of standard cards but with the same PCI IDs.
These cards must come last in this list. */
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 6148827ec885..78eca992e1fd 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -51,7 +51,8 @@
#define IVTV_CARD_AVER_M104 24 /* AverMedia M104 miniPCI card */
#define IVTV_CARD_BUFFALO_MV5L 25 /* Buffalo PC-MV5L/PCI card */
#define IVTV_CARD_AVER_ULTRA1500MCE 26 /* AVerMedia UltraTV 1500 MCE */
-#define IVTV_CARD_LAST 26
+#define IVTV_CARD_KIKYOU 27 /* Sony VAIO Giga Pocket (ENX Kikyou) */
+#define IVTV_CARD_LAST 27
/* Variants of existing cards but with the same PCI IDs. The driver
detects these based on other device information.
@@ -86,6 +87,7 @@
#define IVTV_PCI_ID_MELCO 0x1154
#define IVTV_PCI_ID_GOTVIEW1 0xffac
#define IVTV_PCI_ID_GOTVIEW2 0xffad
+#define IVTV_PCI_ID_SONY 0x104d
/* hardware flags, no gaps allowed */
#define IVTV_HW_CX25840 (1 << 0)
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 347c3344f56d..9a250548be4d 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -193,6 +193,7 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t25 = AverMedia M104 (not yet working)\n"
"\t\t\t26 = Buffalo PC-MV5L/PCI\n"
"\t\t\t27 = AVerMedia UltraTV 1500 MCE\n"
+ "\t\t\t28 = Sony VAIO Giga Pocket (ENX Kikyou)\n"
"\t\t\t 0 = Autodetect (default)\n"
"\t\t\t-1 = Ignore this card\n\t\t");
MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60");
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index c1b7ec475c27..a71e8ba306b0 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -258,7 +258,7 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
IVTV_ERR("ivtv_init_mpeg_decoder failed to start playback\n");
return;
}
- ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data);
+ ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data);
mem_offset = itv->dec_mem + data[1];
if ((readbytes = load_fw_direct(IVTV_DECODE_INIT_MPEG_FILENAME,
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index cd9db0bf33bf..12d36ca91d53 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -562,7 +562,7 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv)
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv_stream *s;
- ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
+ ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data);
IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream);
del_timer(&itv->dma_timer);
@@ -638,7 +638,7 @@ static void ivtv_irq_dma_err(struct ivtv *itv)
u32 data[CX2341X_MBOX_MAX_DATA];
del_timer(&itv->dma_timer);
- ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
+ ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data);
IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1],
read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
@@ -669,7 +669,7 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv)
struct ivtv_stream *s;
/* Get DMA destination and size arguments from card */
- ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, data);
+ ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, 7, data);
IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
if (data[0] > 2 || data[1] == 0 || data[2] == 0) {
@@ -713,9 +713,9 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
struct ivtv_stream *s;
/* YUV or MPG */
- ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data);
if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
+ ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data);
itv->dma_data_req_size =
1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
itv->dma_data_req_offset = data[1];
@@ -724,6 +724,7 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
}
else {
+ ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 3, data);
itv->dma_data_req_size = min_t(u32, data[2], 0x10000);
itv->dma_data_req_offset = data[1];
s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
@@ -940,9 +941,10 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
ivtv_dma_enc_start(s);
break;
}
- if (i == IVTV_MAX_STREAMS && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) {
+
+ if (i == IVTV_MAX_STREAMS &&
+ test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
ivtv_udma_start(itv);
- }
}
if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) {
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index 1b5c0ac09a85..84577f6f41a2 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -369,10 +369,11 @@ int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...)
}
/* This one is for stuff that can't sleep.. irq handlers, etc.. */
-void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb, u32 data[])
+void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb,
+ int argc, u32 data[])
{
+ volatile u32 __iomem *p = mbdata->mbox[mb].data;
int i;
-
- for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
- data[i] = readl(&mbdata->mbox[mb].data[i]);
+ for (i = 0; i < argc; i++, p++)
+ data[i] = readl(p);
}
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h
index 6ef12091e3f3..8247662c928e 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.h
+++ b/drivers/media/video/ivtv/ivtv-mailbox.h
@@ -24,7 +24,8 @@
#define IVTV_MBOX_DMA_END 8
#define IVTV_MBOX_DMA 9
-void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]);
+void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb,
+ int argc, u32 data[]);
int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index e12c6022373e..1f9387f6ca24 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -577,10 +577,14 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
clear_bit(IVTV_F_I_EOS, &itv->i_flags);
/* Initialize Digitizer for Capture */
+ /* Avoid tinny audio problem - ensure audio clocks are going */
+ v4l2_subdev_call(itv->sd_audio, audio, s_stream, 1);
+ /* Avoid unpredictable PCI bus hang - disable video clocks */
v4l2_subdev_call(itv->sd_video, video, s_stream, 0);
- ivtv_msleep_timeout(300, 1);
+ ivtv_msleep_timeout(150, 1);
ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
v4l2_subdev_call(itv->sd_video, video, s_stream, 1);
+ ivtv_msleep_timeout(150, 1);
}
/* begin_capture */
diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c
index d07ad6c39024..1daf1dd65bf7 100644
--- a/drivers/media/video/ivtv/ivtv-udma.c
+++ b/drivers/media/video/ivtv/ivtv-udma.c
@@ -213,6 +213,7 @@ void ivtv_udma_start(struct ivtv *itv)
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
set_bit(IVTV_F_I_DMA, &itv->i_flags);
set_bit(IVTV_F_I_UDMA, &itv->i_flags);
+ clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags);
}
void ivtv_udma_prepare(struct ivtv *itv)
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c
index fc4dd6045720..7438f8d775ba 100644
--- a/drivers/media/video/mt9t112.c
+++ b/drivers/media/video/mt9t112.c
@@ -514,7 +514,7 @@ static int mt9t112_init_pll(const struct i2c_client *client)
/* poll to verify out of standby. Must Poll this bit */
for (i = 0; i < 100; i++) {
mt9t112_reg_read(data, client, 0x0018);
- if (0x4000 & data)
+ if (!(0x4000 & data))
break;
mdelay(10);
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index 91df7ec91fb6..1a34d2993e94 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -257,19 +257,18 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
{
struct soc_camera_link *icl = to_soc_camera_link(icd);
- unsigned int width_flag;
+ unsigned int flags = SOCAM_MASTER | SOCAM_SLAVE |
+ SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
+ SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
+ SOCAM_DATA_ACTIVE_HIGH;
if (icl->query_bus_param)
- width_flag = icl->query_bus_param(icl) &
- SOCAM_DATAWIDTH_MASK;
+ flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK;
else
- width_flag = SOCAM_DATAWIDTH_10;
+ flags |= SOCAM_DATAWIDTH_10;
- return SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
- SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
- SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
- SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_SLAVE |
- width_flag;
+ return soc_camera_apply_sensor_flags(icl, flags);
}
static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c
index 2ba14fb5b031..c167cc3de492 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/video/mx1_camera.c
@@ -718,7 +718,7 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
- if (!res || !irq) {
+ if (!res || (int)irq <= 0) {
err = -ENODEV;
goto exit;
}
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index c1fc6dc776f5..9f01f14e4aa2 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -169,7 +169,11 @@ static struct saa7146_extension extension;
static int mxb_probe(struct saa7146_dev *dev)
{
struct mxb *mxb = NULL;
+ int err;
+ err = saa7146_vv_devinit(dev);
+ if (err)
+ return err;
mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
if (mxb == NULL) {
DEB_D(("not enough kernel memory.\n"));
@@ -294,7 +298,7 @@ static int mxb_init_done(struct saa7146_dev* dev)
/* select tuner-output on saa7111a */
i = 0;
saa7111a_call(mxb, video, s_routing, SAA7115_COMPOSITE0,
- SAA7111_FMT_CCIR | SAA7111_VBI_BYPASS, 0);
+ SAA7111_FMT_CCIR, 0);
/* select a tuner type */
tun_setup.mode_mask = T_ANALOG_TV;
@@ -518,8 +522,8 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
return err;
/* switch video in saa7111a */
- if (saa7111a_call(mxb, video, s_routing, i, 0, 0))
- printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a #1.\n");
+ if (saa7111a_call(mxb, video, s_routing, i, SAA7111_FMT_CCIR, 0))
+ printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a.\n");
/* switch the audio-source only if necessary */
if (0 == mxb->cur_mute)
diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c
index 7400eacb4d64..142c327afb32 100644
--- a/drivers/media/video/omap24xxcam.c
+++ b/drivers/media/video/omap24xxcam.c
@@ -1735,7 +1735,7 @@ static struct v4l2_int_device omap24xxcam = {
*
*/
-static int __init omap24xxcam_probe(struct platform_device *pdev)
+static int __devinit omap24xxcam_probe(struct platform_device *pdev)
{
struct omap24xxcam_device *cam;
struct resource *mem;
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index 3a45e945a528..7f8ece30c77b 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -547,7 +547,6 @@ static const struct v4l2_queryctrl ov772x_controls[] = {
},
};
-
/*
* general function
*/
@@ -634,7 +633,12 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
- SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
+ SOCAM_DATA_ACTIVE_HIGH;
+
+ if (priv->info->flags & OV772X_FLAG_8BIT)
+ flags |= SOCAM_DATAWIDTH_8;
+ else
+ flags |= SOCAM_DATAWIDTH_10;
return soc_camera_apply_sensor_flags(icl, flags);
}
@@ -1040,15 +1044,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd,
return -ENODEV;
/*
- * ov772x only use 8 or 10 bit bus width
- */
- if (SOCAM_DATAWIDTH_10 != priv->info->buswidth &&
- SOCAM_DATAWIDTH_8 != priv->info->buswidth) {
- dev_err(&client->dev, "bus width error\n");
- return -ENODEV;
- }
-
- /*
* check and show product ID and manufacturer ID
*/
pid = i2c_smbus_read_byte_data(client, PID);
@@ -1130,7 +1125,6 @@ static int ov772x_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct ov772x_priv *priv;
- struct ov772x_camera_info *info;
struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct soc_camera_link *icl;
@@ -1145,8 +1139,6 @@ static int ov772x_probe(struct i2c_client *client,
if (!icl || !icl->priv)
return -EINVAL;
- info = icl->priv;
-
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&adapter->dev,
"I2C-Adapter doesn't support "
@@ -1158,7 +1150,7 @@ static int ov772x_probe(struct i2c_client *client,
if (!priv)
return -ENOMEM;
- priv->info = info;
+ priv->info = icl->priv;
v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index de5485f506b1..cb4057bb07a0 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -233,8 +233,9 @@ struct pvr2_hdw {
int state_encoder_waitok; /* Encoder pre-wait done */
int state_encoder_runok; /* Encoder has run for >= .25 sec */
int state_decoder_run; /* Decoder is running */
+ int state_decoder_ready; /* Decoder is stabilized & streamable */
int state_usbstream_run; /* FX2 is streaming */
- int state_decoder_quiescent; /* Decoder idle for > 50msec */
+ int state_decoder_quiescent; /* Decoder idle for minimal interval */
int state_pipeline_config; /* Pipeline is configured */
int state_pipeline_req; /* Somebody wants to stream */
int state_pipeline_pause; /* Pipeline must be paused */
@@ -255,9 +256,16 @@ struct pvr2_hdw {
void (*state_func)(void *);
void *state_data;
- /* Timer for measuring decoder settling time */
+ /* Timer for measuring required decoder settling time before we're
+ allowed to fire it up again. */
struct timer_list quiescent_timer;
+ /* Timer for measuring decoder stabilization time, which is the
+ amount of time we need to let the decoder run before we can
+ trust its output (otherwise the encoder might see garbage and
+ then fail to start correctly). */
+ struct timer_list decoder_stabilization_timer;
+
/* Timer for measuring encoder pre-wait time */
struct timer_list encoder_wait_timer;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 1bbdab08fe0e..712b300f723f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -48,11 +48,13 @@
before we are allowed to start it running. */
#define TIME_MSEC_DECODER_WAIT 50
+/* This defines a minimum interval that the decoder must be allowed to run
+ before we can safely begin using its streaming output. */
+#define TIME_MSEC_DECODER_STABILIZATION_WAIT 300
+
/* This defines a minimum interval that the encoder must remain quiet
- before we are allowed to configure it. I had this originally set to
- 50msec, but Martin Dauskardt <martin.dauskardt@gmx.de> reports that
- things work better when it's set to 100msec. */
-#define TIME_MSEC_ENCODER_WAIT 100
+ before we are allowed to configure it. */
+#define TIME_MSEC_ENCODER_WAIT 50
/* This defines the minimum interval that the encoder must successfully run
before we consider that the encoder has run at least once since its
@@ -334,6 +336,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
static void pvr2_hdw_quiescent_timeout(unsigned long);
+static void pvr2_hdw_decoder_stabilization_timeout(unsigned long);
static void pvr2_hdw_encoder_wait_timeout(unsigned long);
static void pvr2_hdw_encoder_run_timeout(unsigned long);
static int pvr2_issue_simple_cmd(struct pvr2_hdw *,u32);
@@ -1705,6 +1708,7 @@ static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 stream=%s",
(enablefl ? "on" : "off"));
v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_stream, enablefl);
+ v4l2_device_call_all(&hdw->v4l2_dev, 0, audio, s_stream, enablefl);
if (hdw->decoder_client_id) {
/* We get here if the encoder has been noticed. Otherwise
we'll issue a warning to the user (which should
@@ -2461,6 +2465,11 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw->quiescent_timer.data = (unsigned long)hdw;
hdw->quiescent_timer.function = pvr2_hdw_quiescent_timeout;
+ init_timer(&hdw->decoder_stabilization_timer);
+ hdw->decoder_stabilization_timer.data = (unsigned long)hdw;
+ hdw->decoder_stabilization_timer.function =
+ pvr2_hdw_decoder_stabilization_timeout;
+
init_timer(&hdw->encoder_wait_timer);
hdw->encoder_wait_timer.data = (unsigned long)hdw;
hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout;
@@ -2674,6 +2683,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
fail:
if (hdw) {
del_timer_sync(&hdw->quiescent_timer);
+ del_timer_sync(&hdw->decoder_stabilization_timer);
del_timer_sync(&hdw->encoder_run_timer);
del_timer_sync(&hdw->encoder_wait_timer);
if (hdw->workqueue) {
@@ -2741,6 +2751,7 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
hdw->workqueue = NULL;
}
del_timer_sync(&hdw->quiescent_timer);
+ del_timer_sync(&hdw->decoder_stabilization_timer);
del_timer_sync(&hdw->encoder_run_timer);
del_timer_sync(&hdw->encoder_wait_timer);
if (hdw->fw_buffer) {
@@ -4452,7 +4463,7 @@ static int state_check_enable_encoder_run(struct pvr2_hdw *hdw)
switch (hdw->pathway_state) {
case PVR2_PATHWAY_ANALOG:
- if (hdw->state_decoder_run) {
+ if (hdw->state_decoder_run && hdw->state_decoder_ready) {
/* In analog mode, if the decoder is running, then
run the encoder. */
return !0;
@@ -4519,6 +4530,17 @@ static void pvr2_hdw_quiescent_timeout(unsigned long data)
}
+/* Timeout function for decoder stabilization timer. */
+static void pvr2_hdw_decoder_stabilization_timeout(unsigned long data)
+{
+ struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+ hdw->state_decoder_ready = !0;
+ trace_stbit("state_decoder_ready", hdw->state_decoder_ready);
+ hdw->state_stale = !0;
+ queue_work(hdw->workqueue, &hdw->workpoll);
+}
+
+
/* Timeout function for encoder wait timer. */
static void pvr2_hdw_encoder_wait_timeout(unsigned long data)
{
@@ -4557,8 +4579,13 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw)
}
hdw->state_decoder_quiescent = 0;
hdw->state_decoder_run = 0;
- /* paranoia - solve race if timer just completed */
+ /* paranoia - solve race if timer(s) just completed */
del_timer_sync(&hdw->quiescent_timer);
+ /* Kill the stabilization timer, in case we're killing the
+ encoder before the previous stabilization interval has
+ been properly timed. */
+ del_timer_sync(&hdw->decoder_stabilization_timer);
+ hdw->state_decoder_ready = 0;
} else {
if (!hdw->state_decoder_quiescent) {
if (!timer_pending(&hdw->quiescent_timer)) {
@@ -4596,10 +4623,21 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw)
if (hdw->flag_decoder_missed) return 0;
if (pvr2_decoder_enable(hdw,!0) < 0) return 0;
hdw->state_decoder_quiescent = 0;
+ hdw->state_decoder_ready = 0;
hdw->state_decoder_run = !0;
+ if (hdw->decoder_client_id == PVR2_CLIENT_ID_SAA7115) {
+ hdw->decoder_stabilization_timer.expires =
+ jiffies +
+ (HZ * TIME_MSEC_DECODER_STABILIZATION_WAIT /
+ 1000);
+ add_timer(&hdw->decoder_stabilization_timer);
+ } else {
+ hdw->state_decoder_ready = !0;
+ }
}
trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent);
trace_stbit("state_decoder_run",hdw->state_decoder_run);
+ trace_stbit("state_decoder_ready", hdw->state_decoder_ready);
return !0;
}
@@ -4797,7 +4835,8 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
buf,acnt,
"worker:%s%s%s%s%s%s%s",
(hdw->state_decoder_run ?
- " <decode:run>" :
+ (hdw->state_decoder_ready ?
+ "<decode:run>" : " <decode:start>") :
(hdw->state_decoder_quiescent ?
"" : " <decode:stop>")),
(hdw->state_decoder_quiescent ?
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 56e70eae20c1..51d3009ab57f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -306,6 +306,7 @@ struct pvr2_hdw_debug_info {
int state_encoder_ok;
int state_encoder_run;
int state_decoder_run;
+ int state_decoder_ready;
int state_usbstream_run;
int state_decoder_quiescent;
int state_pipeline_config;
diff --git a/drivers/media/video/pwc/philips.txt b/drivers/media/video/pwc/philips.txt
index f9f3584281d8..d38dd791511e 100644
--- a/drivers/media/video/pwc/philips.txt
+++ b/drivers/media/video/pwc/philips.txt
@@ -33,7 +33,7 @@ a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin
contains decompression routines that allow you to use higher image sizes and
framerates; in addition the webcam uses less bandwidth on the USB bus (handy
if you want to run more than 1 camera simultaneously). These routines fall
-under a NDA, and may therefor not be distributed as source; however, its use
+under a NDA, and may therefore not be distributed as source; however, its use
is completely optional.
You can build this code either into your kernel, or as a module. I recommend
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 50b415e07eda..f7f7e04cf485 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -753,7 +753,7 @@ int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
buf[0] = 0xff; /* fixed */
ret = send_control_msg(pdev,
- SET_LUM_CTL, SHUTTER_MODE_FORMATTER, &buf, sizeof(buf));
+ SET_LUM_CTL, SHUTTER_MODE_FORMATTER, &buf, 1);
if (!mode && ret >= 0) {
if (value < 0)
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 294f860ce2b0..322ac4eecf0a 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -898,18 +898,8 @@ static void recalculate_fifo_timeout(struct pxa_camera_dev *pcdev,
static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
{
- struct pxacamera_platform_data *pdata = pcdev->pdata;
- struct device *dev = pcdev->soc_host.v4l2_dev.dev;
u32 cicr4 = 0;
- dev_dbg(dev, "Registered platform device at %p data %p\n",
- pcdev, pdata);
-
- if (pdata && pdata->init) {
- dev_dbg(dev, "%s: Init gpios\n", __func__);
- pdata->init(dev);
- }
-
/* disable all interrupts */
__raw_writel(0x3ff, pcdev->base + CICR0);
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
index 7e42989ce0e4..9277194cd821 100644
--- a/drivers/media/video/rj54n1cb0c.c
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -165,7 +165,7 @@ struct rj54n1_reg_val {
u8 val;
};
-const static struct rj54n1_reg_val bank_4[] = {
+static const struct rj54n1_reg_val bank_4[] = {
{0x417, 0},
{0x42c, 0},
{0x42d, 0xf0},
@@ -186,7 +186,7 @@ const static struct rj54n1_reg_val bank_4[] = {
{0x4fe, 2},
};
-const static struct rj54n1_reg_val bank_5[] = {
+static const struct rj54n1_reg_val bank_5[] = {
{0x514, 0},
{0x516, 0},
{0x518, 0},
@@ -207,7 +207,7 @@ const static struct rj54n1_reg_val bank_5[] = {
{0x5fe, 2},
};
-const static struct rj54n1_reg_val bank_7[] = {
+static const struct rj54n1_reg_val bank_7[] = {
{0x70a, 0},
{0x714, 0xff},
{0x715, 0xff},
@@ -215,7 +215,7 @@ const static struct rj54n1_reg_val bank_7[] = {
{0x7FE, 2},
};
-const static struct rj54n1_reg_val bank_8[] = {
+static const struct rj54n1_reg_val bank_8[] = {
{0x800, 0x00},
{0x801, 0x01},
{0x802, 0x61},
@@ -403,12 +403,12 @@ const static struct rj54n1_reg_val bank_8[] = {
{0x8FE, 2},
};
-const static struct rj54n1_reg_val bank_10[] = {
+static const struct rj54n1_reg_val bank_10[] = {
{0x10bf, 0x69}
};
/* Clock dividers - these are default register values, divider = register + 1 */
-const static struct rj54n1_clock_div clk_div = {
+static const struct rj54n1_clock_div clk_div = {
.ratio_tg = 3 /* default: 5 */,
.ratio_t = 4 /* default: 1 */,
.ratio_r = 4 /* default: 0 */,
@@ -563,7 +563,7 @@ static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
struct i2c_client *client = sd->priv;
struct rj54n1 *rj54n1 = to_rj54n1(client);
struct v4l2_rect *rect = &a->c;
- unsigned int dummy, output_w, output_h,
+ unsigned int dummy = 0, output_w, output_h,
input_w = rect->width, input_h = rect->height;
int ret;
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 44873a016c2c..c0a7f8a369f4 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -104,6 +104,10 @@ static int saa711x_has_reg(const int id, const u8 reg)
if (id == V4L2_IDENT_SAA7111)
return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
(reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e;
+ if (id == V4L2_IDENT_SAA7111A)
+ return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
+ reg != 0x14 && reg != 0x18 && reg != 0x19 &&
+ reg != 0x1d && reg != 0x1e;
/* common for saa7113/4/5/8 */
if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f ||
@@ -954,8 +958,7 @@ static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
011 NTSC N (3.58MHz) PAL M (3.58MHz)
100 reserved NTSC-Japan (3.58MHz)
*/
- if (state->ident == V4L2_IDENT_SAA7111 ||
- state->ident == V4L2_IDENT_SAA7113) {
+ if (state->ident <= V4L2_IDENT_SAA7113) {
u8 reg = saa711x_read(sd, R_0E_CHROMA_CNTL_1) & 0x8f;
if (std == V4L2_STD_PAL_M) {
@@ -1232,22 +1235,19 @@ static int saa711x_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
struct saa711x_state *state = to_state(sd);
- u8 mask = (state->ident == V4L2_IDENT_SAA7111) ? 0xf8 : 0xf0;
+ u8 mask = (state->ident <= V4L2_IDENT_SAA7111A) ? 0xf8 : 0xf0;
v4l2_dbg(1, debug, sd, "decoder set input %d output %d\n",
input, output);
/* saa7111/3 does not have these inputs */
- if ((state->ident == V4L2_IDENT_SAA7113 ||
- state->ident == V4L2_IDENT_SAA7111) &&
+ if (state->ident <= V4L2_IDENT_SAA7113 &&
(input == SAA7115_COMPOSITE4 ||
input == SAA7115_COMPOSITE5)) {
return -EINVAL;
}
if (input > SAA7115_SVIDEO3)
return -EINVAL;
- if (output > SAA7115_IPORT_ON)
- return -EINVAL;
if (state->input == input && state->output == output)
return 0;
v4l2_dbg(1, debug, sd, "now setting %s input %s output\n",
@@ -1256,7 +1256,7 @@ static int saa711x_s_routing(struct v4l2_subdev *sd,
state->input = input;
/* saa7111 has slightly different input numbering */
- if (state->ident == V4L2_IDENT_SAA7111) {
+ if (state->ident <= V4L2_IDENT_SAA7111A) {
if (input >= SAA7115_COMPOSITE4)
input -= 2;
/* saa7111 specific */
@@ -1292,7 +1292,7 @@ static int saa711x_s_gpio(struct v4l2_subdev *sd, u32 val)
{
struct saa711x_state *state = to_state(sd);
- if (state->ident != V4L2_IDENT_SAA7111)
+ if (state->ident > V4L2_IDENT_SAA7111A)
return -EINVAL;
saa711x_write(sd, 0x11, (saa711x_read(sd, 0x11) & 0x7f) |
(val ? 0x80 : 0));
@@ -1596,6 +1596,10 @@ static int saa711x_probe(struct i2c_client *client,
switch (chip_id) {
case '1':
state->ident = V4L2_IDENT_SAA7111;
+ if (saa711x_read(sd, R_00_CHIP_VERSION) & 0xf0) {
+ v4l_info(client, "saa7111a variant found\n");
+ state->ident = V4L2_IDENT_SAA7111A;
+ }
break;
case '3':
state->ident = V4L2_IDENT_SAA7113;
@@ -1612,7 +1616,7 @@ static int saa711x_probe(struct i2c_client *client,
default:
state->ident = V4L2_IDENT_SAA7111;
v4l2_info(sd, "WARNING: Chip is not known - Falling back to saa7111\n");
-
+ break;
}
state->audclk_freq = 48000;
@@ -1623,6 +1627,7 @@ static int saa711x_probe(struct i2c_client *client,
state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
switch (state->ident) {
case V4L2_IDENT_SAA7111:
+ case V4L2_IDENT_SAA7111A:
saa711x_writeregs(sd, saa7111_init);
break;
case V4L2_IDENT_SAA7113:
@@ -1632,7 +1637,7 @@ static int saa711x_probe(struct i2c_client *client,
state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
saa711x_writeregs(sd, saa7115_init_auto_input);
}
- if (state->ident != V4L2_IDENT_SAA7111)
+ if (state->ident > V4L2_IDENT_SAA7111A)
saa711x_writeregs(sd, saa7115_init_misc);
saa711x_set_v4lstd(sd, V4L2_STD_NTSC);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index 2fe7a701b954..250ef84cf5ca 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -181,7 +181,7 @@ static const struct i2c_reg_value saa7127_init_config_common[] = {
#define SAA7127_60HZ_DAC_CONTROL 0x15
static const struct i2c_reg_value saa7127_init_config_60hz[] = {
{ SAA7127_REG_BURST_START, 0x19 },
- /* BURST_END is also used as a chip ID in saa7127_detect_client */
+ /* BURST_END is also used as a chip ID in saa7127_probe */
{ SAA7127_REG_BURST_END, 0x1d },
{ SAA7127_REG_CHROMA_PHASE, 0xa3 },
{ SAA7127_REG_GAINU, 0x98 },
@@ -200,10 +200,10 @@ static const struct i2c_reg_value saa7127_init_config_60hz[] = {
{ 0, 0 }
};
-#define SAA7127_50HZ_DAC_CONTROL 0x02
-static struct i2c_reg_value saa7127_init_config_50hz[] = {
+#define SAA7127_50HZ_PAL_DAC_CONTROL 0x02
+static struct i2c_reg_value saa7127_init_config_50hz_pal[] = {
{ SAA7127_REG_BURST_START, 0x21 },
- /* BURST_END is also used as a chip ID in saa7127_detect_client */
+ /* BURST_END is also used as a chip ID in saa7127_probe */
{ SAA7127_REG_BURST_END, 0x1d },
{ SAA7127_REG_CHROMA_PHASE, 0x3f },
{ SAA7127_REG_GAINU, 0x7d },
@@ -222,6 +222,28 @@ static struct i2c_reg_value saa7127_init_config_50hz[] = {
{ 0, 0 }
};
+#define SAA7127_50HZ_SECAM_DAC_CONTROL 0x08
+static struct i2c_reg_value saa7127_init_config_50hz_secam[] = {
+ { SAA7127_REG_BURST_START, 0x21 },
+ /* BURST_END is also used as a chip ID in saa7127_probe */
+ { SAA7127_REG_BURST_END, 0x1d },
+ { SAA7127_REG_CHROMA_PHASE, 0x3f },
+ { SAA7127_REG_GAINU, 0x6a },
+ { SAA7127_REG_GAINV, 0x81 },
+ { SAA7127_REG_BLACK_LEVEL, 0x33 },
+ { SAA7127_REG_BLANKING_LEVEL, 0x35 },
+ { SAA7127_REG_VBI_BLANKING, 0x35 },
+ { SAA7127_REG_DAC_CONTROL, 0x08 },
+ { SAA7127_REG_BURST_AMP, 0x2f },
+ { SAA7127_REG_SUBC3, 0xb2 },
+ { SAA7127_REG_SUBC2, 0x3b },
+ { SAA7127_REG_SUBC1, 0xa3 },
+ { SAA7127_REG_SUBC0, 0x28 },
+ { SAA7127_REG_MULTI, 0x90 },
+ { SAA7127_REG_CLOSED_CAPTION, 0x00 },
+ { 0, 0 }
+};
+
/*
**********************************************************************
*
@@ -463,10 +485,21 @@ static int saa7127_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
v4l2_dbg(1, debug, sd, "Selecting 60 Hz video Standard\n");
inittab = saa7127_init_config_60hz;
state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
+
+ } else if (state->ident == V4L2_IDENT_SAA7129 &&
+ (std & V4L2_STD_SECAM) &&
+ !(std & (V4L2_STD_625_50 & ~V4L2_STD_SECAM))) {
+
+ /* If and only if SECAM, with a SAA712[89] */
+ v4l2_dbg(1, debug, sd,
+ "Selecting 50 Hz SECAM video Standard\n");
+ inittab = saa7127_init_config_50hz_secam;
+ state->reg_61 = SAA7127_50HZ_SECAM_DAC_CONTROL;
+
} else {
- v4l2_dbg(1, debug, sd, "Selecting 50 Hz video Standard\n");
- inittab = saa7127_init_config_50hz;
- state->reg_61 = SAA7127_50HZ_DAC_CONTROL;
+ v4l2_dbg(1, debug, sd, "Selecting 50 Hz PAL video Standard\n");
+ inittab = saa7127_init_config_50hz_pal;
+ state->reg_61 = SAA7127_50HZ_PAL_DAC_CONTROL;
}
/* Write Table */
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 03f572708b85..297833fb3b4a 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -4160,7 +4160,7 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE2,
},
},
- [SAA7134_BOARD_BEHOLD_505RDS] = {
+ [SAA7134_BOARD_BEHOLD_505RDS_MK5] = {
/* Beholder Intl. Ltd. 2008 */
/*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 505 RDS",
@@ -5320,6 +5320,41 @@ struct saa7134_board saa7134_boards[] = {
.vmux = 8,
} },
},
+ [SAA7134_BOARD_BEHOLD_505RDS_MK3] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 505 RDS",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = LINE2,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .mute = {
+ .name = name_mute,
+ .amux = LINE1,
+ },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ },
};
@@ -6235,7 +6270,13 @@ struct pci_device_id saa7134_pci_tbl[] = {
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
.subvendor = 0x0000,
.subdevice = 0x505B,
- .driver_data = SAA7134_BOARD_BEHOLD_505RDS,
+ .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK5,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x0000,
+ .subdevice = 0x5051,
+ .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK3,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
@@ -6792,7 +6833,8 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_407FM:
case SAA7134_BOARD_BEHOLD_409:
case SAA7134_BOARD_BEHOLD_505FM:
- case SAA7134_BOARD_BEHOLD_505RDS:
+ case SAA7134_BOARD_BEHOLD_505RDS_MK5:
+ case SAA7134_BOARD_BEHOLD_505RDS_MK3:
case SAA7134_BOARD_BEHOLD_507_9FM:
case SAA7134_BOARD_BEHOLD_507RDS_MK3:
case SAA7134_BOARD_BEHOLD_507RDS_MK5:
@@ -6953,8 +6995,8 @@ int saa7134_board_init1(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_VIDEOMATE_S350:
dev->has_remote = SAA7134_REMOTE_GPIO;
- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00008000, 0x00008000);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0000C000, 0x0000C000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0000C000, 0x0000C000);
break;
}
return 0;
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 9f85e917f9f3..a7ad7810fddc 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -420,19 +420,6 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
ctrl |= SAA7134_MAIN_CTRL_TE5;
irq |= SAA7134_IRQ1_INTE_RA2_1 |
SAA7134_IRQ1_INTE_RA2_0;
-
- /* dma: setup channel 5 (= TS) */
-
- saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff);
- saa_writeb(SAA7134_TS_DMA1,
- ((dev->ts.nr_packets - 1) >> 8) & 0xff);
- /* TSNOPIT=0, TSCOLAP=0 */
- saa_writeb(SAA7134_TS_DMA2,
- (((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00);
- saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
- saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 |
- SAA7134_RS_CONTROL_ME |
- (dev->ts.pt_ts.dma >> 12));
}
/* set task conditions + field handling */
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 7dfecfc6017c..ee5bff02a92c 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -93,9 +93,9 @@ static int ts_open(struct file *file)
dprintk("open dev=%s\n", video_device_node_name(vdev));
err = -EBUSY;
if (!mutex_trylock(&dev->empress_tsq.vb_lock))
- goto done;
+ return err;
if (atomic_read(&dev->empress_users))
- goto done_up;
+ goto done;
/* Unmute audio */
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
@@ -105,10 +105,8 @@ static int ts_open(struct file *file)
file->private_data = dev;
err = 0;
-done_up:
- mutex_unlock(&dev->empress_tsq.vb_lock);
done:
- unlock_kernel();
+ mutex_unlock(&dev->empress_tsq.vb_lock);
return err;
}
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index f8e985989ca0..9499000f66b6 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -460,7 +460,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
int polling = 0;
int rc5_gpio = 0;
int nec_gpio = 0;
- int ir_type = IR_TYPE_OTHER;
+ u64 ir_type = IR_TYPE_OTHER;
int err;
if (dev->has_remote != SAA7134_REMOTE_GPIO)
@@ -568,7 +568,8 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_407FM:
case SAA7134_BOARD_BEHOLD_409:
case SAA7134_BOARD_BEHOLD_505FM:
- case SAA7134_BOARD_BEHOLD_505RDS:
+ case SAA7134_BOARD_BEHOLD_505RDS_MK5:
+ case SAA7134_BOARD_BEHOLD_505RDS_MK3:
case SAA7134_BOARD_BEHOLD_507_9FM:
case SAA7134_BOARD_BEHOLD_507RDS_MK3:
case SAA7134_BOARD_BEHOLD_507RDS_MK5:
@@ -728,7 +729,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
dev->remote = ir;
saa7134_ir_start(dev, ir);
- err = ir_input_register(ir->dev, ir_codes);
+ err = ir_input_register(ir->dev, ir_codes, NULL);
if (err)
goto err_out_stop;
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
index 03488ba4c99c..b9817d74943f 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -250,6 +250,19 @@ int saa7134_ts_start(struct saa7134_dev *dev)
BUG_ON(dev->ts_started);
+ /* dma: setup channel 5 (= TS) */
+ saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff);
+ saa_writeb(SAA7134_TS_DMA1,
+ ((dev->ts.nr_packets - 1) >> 8) & 0xff);
+ /* TSNOPIT=0, TSCOLAP=0 */
+ saa_writeb(SAA7134_TS_DMA2,
+ (((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00);
+ saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
+ saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 |
+ SAA7134_RS_CONTROL_ME |
+ (dev->ts.pt_ts.dma >> 12));
+
+ /* reset hardware TS buffers */
saa_writeb(SAA7134_TS_SERIAL1, 0x00);
saa_writeb(SAA7134_TS_SERIAL1, 0x03);
saa_writeb(SAA7134_TS_SERIAL1, 0x00);
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index cb732640ac4a..31138d3e51bb 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -205,7 +205,7 @@ static struct saa7134_format formats[] = {
#define NORM_525_60 \
.h_start = 0, \
- .h_stop = 703, \
+ .h_stop = 719, \
.video_v_start = 23, \
.video_v_stop = 262, \
.vbi_v_start_0 = 10, \
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 53b7e0b8a2fb..bf130967ed17 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -282,7 +282,7 @@ struct saa7134_format {
#define SAA7134_BOARD_HAUPPAUGE_HVR1120 156
#define SAA7134_BOARD_AVERMEDIA_STUDIO_507UA 157
#define SAA7134_BOARD_AVERMEDIA_CARDBUS_501 158
-#define SAA7134_BOARD_BEHOLD_505RDS 159
+#define SAA7134_BOARD_BEHOLD_505RDS_MK5 159
#define SAA7134_BOARD_BEHOLD_507RDS_MK3 160
#define SAA7134_BOARD_BEHOLD_507RDS_MK5 161
#define SAA7134_BOARD_BEHOLD_607FM_MK5 162
@@ -299,6 +299,7 @@ struct saa7134_format {
#define SAA7134_BOARD_ZOLID_HYBRID_PCI 173
#define SAA7134_BOARD_ASUS_EUROPA_HYBRID 174
#define SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S 175
+#define SAA7134_BOARD_BEHOLD_505RDS_MK3 176
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
diff --git a/drivers/media/video/saa7164/saa7164-api.c b/drivers/media/video/saa7164/saa7164-api.c
index 6f094a96ac81..1d487c150340 100644
--- a/drivers/media/video/saa7164/saa7164-api.c
+++ b/drivers/media/video/saa7164/saa7164-api.c
@@ -523,7 +523,7 @@ int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen,
}
reglen = saa7164_i2caddr_to_reglen(bus, addr);
- if (unitid < 0) {
+ if (reglen < 0) {
printk(KERN_ERR
"%s() error, cannot translate regaddr to reglen\n",
__func__);
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index d69363f0d8c9..fb88c63188f3 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -1748,6 +1748,22 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
icd);
}
+static int sh_mobile_ceu_get_parm(struct soc_camera_device *icd,
+ struct v4l2_streamparm *parm)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+ return v4l2_subdev_call(sd, video, g_parm, parm);
+}
+
+static int sh_mobile_ceu_set_parm(struct soc_camera_device *icd,
+ struct v4l2_streamparm *parm)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+
+ return v4l2_subdev_call(sd, video, s_parm, parm);
+}
+
static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd,
struct v4l2_control *ctrl)
{
@@ -1808,6 +1824,8 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.try_fmt = sh_mobile_ceu_try_fmt,
.set_ctrl = sh_mobile_ceu_set_ctrl,
.get_ctrl = sh_mobile_ceu_get_ctrl,
+ .set_parm = sh_mobile_ceu_set_parm,
+ .get_parm = sh_mobile_ceu_get_parm,
.reqbufs = sh_mobile_ceu_reqbufs,
.poll = sh_mobile_ceu_poll,
.querycap = sh_mobile_ceu_querycap,
@@ -1827,7 +1845,7 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
- if (!res || !irq) {
+ if (!res || (int)irq <= 0) {
dev_err(&pdev->dev, "Not enough CEU platform resources.\n");
err = -ENODEV;
goto exit;
diff --git a/drivers/media/video/sn9c102/Kconfig b/drivers/media/video/sn9c102/Kconfig
index f71f272776de..6ebaf2940d06 100644
--- a/drivers/media/video/sn9c102/Kconfig
+++ b/drivers/media/video/sn9c102/Kconfig
@@ -1,7 +1,10 @@
config USB_SN9C102
- tristate "USB SN9C1xx PC Camera Controller support"
+ tristate "USB SN9C1xx PC Camera Controller support (DEPRECATED)"
depends on VIDEO_V4L2
---help---
+ This driver is DEPRECATED please use the gspca sonixb and
+ sonixj modules instead.
+
Say Y here if you want support for cameras based on SONiX SN9C101,
SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers.
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
index 36ee43a9ee95..cc40d6ba9f22 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -45,20 +45,24 @@ static const struct usb_device_id sn9c102_id_table[] = {
{ SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
/* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */
+#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
+#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), },
#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
-#endif
/* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */
+#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), },
/* SN9C103 */
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h
index 4af7382da5c5..494957b10bac 100644
--- a/drivers/media/video/sn9c102/sn9c102_sensor.h
+++ b/drivers/media/video/sn9c102/sn9c102_sensor.h
@@ -120,7 +120,7 @@ extern int sn9c102_write_regs(struct sn9c102_device*, const u8 valreg[][2],
/*
Write multiple registers with constant values. For example:
sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17}, {0x0f, 0x18});
- Register adresses must be < 256.
+ Register addresses must be < 256.
*/
#define sn9c102_write_const_regs(sn9c102_device, data...) \
({ static const u8 _valreg[][2] = {data}; \
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 6b3fbcca7747..80f6bfa2632b 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -781,6 +781,32 @@ static int soc_camera_s_crop(struct file *file, void *fh,
return ret;
}
+static int soc_camera_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+
+ if (ici->ops->get_parm)
+ return ici->ops->get_parm(icd, a);
+
+ return -ENOIOCTLCMD;
+}
+
+static int soc_camera_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+
+ if (ici->ops->set_parm)
+ return ici->ops->set_parm(icd, a);
+
+ return -ENOIOCTLCMD;
+}
+
static int soc_camera_g_chip_ident(struct file *file, void *fh,
struct v4l2_dbg_chip_ident *id)
{
@@ -846,10 +872,8 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
struct v4l2_subdev *subdev;
- int ret;
if (!adap) {
- ret = -ENODEV;
dev_err(&icd->dev, "Cannot get I2C adapter #%d. No driver?\n",
icl->i2c_adapter_id);
goto ei2cga;
@@ -859,10 +883,8 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
icl->module_name, icl->board_info, NULL);
- if (!subdev) {
- ret = -ENOMEM;
+ if (!subdev)
goto ei2cnd;
- }
client = subdev->priv;
@@ -873,7 +895,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
ei2cnd:
i2c_put_adapter(adap);
ei2cga:
- return ret;
+ return -ENODEV;
}
static void soc_camera_free_i2c(struct soc_camera_device *icd)
@@ -1260,6 +1282,8 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
.vidioc_cropcap = soc_camera_cropcap,
.vidioc_g_crop = soc_camera_g_crop,
.vidioc_s_crop = soc_camera_s_crop,
+ .vidioc_g_parm = soc_camera_g_parm,
+ .vidioc_s_parm = soc_camera_s_parm,
.vidioc_g_chip_ident = soc_camera_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = soc_camera_g_register,
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c
index f8d5c87dc2aa..8b63b6545e76 100644
--- a/drivers/media/video/soc_mediabus.c
+++ b/drivers/media/video/soc_mediabus.c
@@ -24,91 +24,106 @@ static const struct soc_mbus_pixelfmt mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(YVYU8_2X8_LE)] = {
+ },
+ [MBUS_IDX(YVYU8_2X8_LE)] = {
.fourcc = V4L2_PIX_FMT_YVYU,
.name = "YVYU",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(YUYV8_2X8_BE)] = {
+ },
+ [MBUS_IDX(YUYV8_2X8_BE)] = {
.fourcc = V4L2_PIX_FMT_UYVY,
.name = "UYVY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(YVYU8_2X8_BE)] = {
+ },
+ [MBUS_IDX(YVYU8_2X8_BE)] = {
.fourcc = V4L2_PIX_FMT_VYUY,
.name = "VYUY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(RGB555_2X8_PADHI_LE)] = {
+ },
+ [MBUS_IDX(RGB555_2X8_PADHI_LE)] = {
.fourcc = V4L2_PIX_FMT_RGB555,
.name = "RGB555",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(RGB555_2X8_PADHI_BE)] = {
+ },
+ [MBUS_IDX(RGB555_2X8_PADHI_BE)] = {
.fourcc = V4L2_PIX_FMT_RGB555X,
.name = "RGB555X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(RGB565_2X8_LE)] = {
+ },
+ [MBUS_IDX(RGB565_2X8_LE)] = {
.fourcc = V4L2_PIX_FMT_RGB565,
.name = "RGB565",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(RGB565_2X8_BE)] = {
+ },
+ [MBUS_IDX(RGB565_2X8_BE)] = {
.fourcc = V4L2_PIX_FMT_RGB565X,
.name = "RGB565X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(SBGGR8_1X8)] = {
+ },
+ [MBUS_IDX(SBGGR8_1X8)] = {
.fourcc = V4L2_PIX_FMT_SBGGR8,
.name = "Bayer 8 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(SBGGR10_1X10)] = {
+ },
+ [MBUS_IDX(SBGGR10_1X10)] = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 10,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(GREY8_1X8)] = {
+ },
+ [MBUS_IDX(GREY8_1X8)] = {
.fourcc = V4L2_PIX_FMT_GREY,
.name = "Grey",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(Y10_1X10)] = {
+ },
+ [MBUS_IDX(Y10_1X10)] = {
.fourcc = V4L2_PIX_FMT_Y10,
.name = "Grey 10bit",
.bits_per_sample = 10,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(SBGGR10_2X8_PADHI_LE)] = {
+ },
+ [MBUS_IDX(SBGGR10_2X8_PADHI_LE)] = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(SBGGR10_2X8_PADLO_LE)] = {
+ },
+ [MBUS_IDX(SBGGR10_2X8_PADLO_LE)] = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADLO,
.order = SOC_MBUS_ORDER_LE,
- }, [MBUS_IDX(SBGGR10_2X8_PADHI_BE)] = {
+ },
+ [MBUS_IDX(SBGGR10_2X8_PADHI_BE)] = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
- }, [MBUS_IDX(SBGGR10_2X8_PADLO_BE)] = {
+ },
+ [MBUS_IDX(SBGGR10_2X8_PADLO_BE)] = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 8,
@@ -134,7 +149,8 @@ EXPORT_SYMBOL(soc_mbus_bytes_per_line);
const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
enum v4l2_mbus_pixelcode code)
{
- if ((unsigned int)(code - V4L2_MBUS_FMT_FIXED) > ARRAY_SIZE(mbus_fmt))
+ if (code - V4L2_MBUS_FMT_FIXED > ARRAY_SIZE(mbus_fmt) ||
+ code <= V4L2_MBUS_FMT_FIXED)
return NULL;
return mbus_fmt + code - V4L2_MBUS_FMT_FIXED - 1;
}
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index 0446524d3543..6bf6bc7dbc7f 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -6,7 +6,7 @@
The tea6420 is a bus controlled audio-matrix with 5 stereo inputs,
4 stereo outputs and gain control for each output.
- It is cascadable, i.e. it can be found at the adresses 0x98
+ It is cascadable, i.e. it can be found at the addresses 0x98
and 0x9a on the i2c-bus.
For detailed informations download the specifications directly
diff --git a/drivers/media/video/tlg2300/Kconfig b/drivers/media/video/tlg2300/Kconfig
new file mode 100644
index 000000000000..2c29ec659b4e
--- /dev/null
+++ b/drivers/media/video/tlg2300/Kconfig
@@ -0,0 +1,16 @@
+config VIDEO_TLG2300
+ tristate "Telegent TLG2300 USB video capture support"
+ depends on VIDEO_DEV && I2C && INPUT && SND && DVB_CORE
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_IR
+ select VIDEOBUF_VMALLOC
+ select SND_PCM
+ select VIDEOBUF_DVB
+
+ ---help---
+ This is a video4linux driver for Telegent tlg2300 based TV cards.
+ The driver supports V4L2, DVB-T and radio.
+
+ To compile this driver as a module, choose M here: the
+ module will be called poseidon
diff --git a/drivers/media/video/tlg2300/Makefile b/drivers/media/video/tlg2300/Makefile
new file mode 100644
index 000000000000..81bb7fdd1e3d
--- /dev/null
+++ b/drivers/media/video/tlg2300/Makefile
@@ -0,0 +1,9 @@
+poseidon-objs := pd-video.o pd-alsa.o pd-dvb.o pd-radio.o pd-main.o
+
+obj-$(CONFIG_VIDEO_TLG2300) += poseidon.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
diff --git a/drivers/media/video/tlg2300/pd-alsa.c b/drivers/media/video/tlg2300/pd-alsa.c
new file mode 100644
index 000000000000..6f42621ad478
--- /dev/null
+++ b/drivers/media/video/tlg2300/pd-alsa.c
@@ -0,0 +1,332 @@
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/init.h>
+#include <linux/sound.h>
+#include <linux/spinlock.h>
+#include <linux/soundcard.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <media/v4l2-common.h>
+#include "pd-common.h"
+#include "vendorcmds.h"
+
+static void complete_handler_audio(struct urb *urb);
+#define AUDIO_EP (0x83)
+#define AUDIO_BUF_SIZE (512)
+#define PERIOD_SIZE (1024 * 8)
+#define PERIOD_MIN (4)
+#define PERIOD_MAX PERIOD_MIN
+
+static struct snd_pcm_hardware snd_pd_hw_capture = {
+ .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID,
+
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_48000,
+
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = PERIOD_SIZE * PERIOD_MIN,
+ .period_bytes_min = PERIOD_SIZE,
+ .period_bytes_max = PERIOD_SIZE,
+ .periods_min = PERIOD_MIN,
+ .periods_max = PERIOD_MAX,
+ /*
+ .buffer_bytes_max = 62720 * 8,
+ .period_bytes_min = 64,
+ .period_bytes_max = 12544,
+ .periods_min = 2,
+ .periods_max = 98
+ */
+};
+
+static int snd_pd_capture_open(struct snd_pcm_substream *substream)
+{
+ struct poseidon *p = snd_pcm_substream_chip(substream);
+ struct poseidon_audio *pa = &p->audio;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ if (!p)
+ return -ENODEV;
+ pa->users++;
+ pa->card_close = 0;
+ pa->capture_pcm_substream = substream;
+ runtime->private_data = p;
+
+ runtime->hw = snd_pd_hw_capture;
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ usb_autopm_get_interface(p->interface);
+ kref_get(&p->kref);
+ return 0;
+}
+
+static int snd_pd_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct poseidon *p = snd_pcm_substream_chip(substream);
+ struct poseidon_audio *pa = &p->audio;
+
+ pa->users--;
+ pa->card_close = 1;
+ usb_autopm_put_interface(p->interface);
+ kref_put(&p->kref, poseidon_delete);
+ return 0;
+}
+
+static int snd_pd_hw_capture_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned int size;
+
+ size = params_buffer_bytes(hw_params);
+ if (runtime->dma_area) {
+ if (runtime->dma_bytes > size)
+ return 0;
+ vfree(runtime->dma_area);
+ }
+ runtime->dma_area = vmalloc(size);
+ if (!runtime->dma_area)
+ return -ENOMEM;
+ else
+ runtime->dma_bytes = size;
+ return 0;
+}
+
+static int audio_buf_free(struct poseidon *p)
+{
+ struct poseidon_audio *pa = &p->audio;
+ int i;
+
+ for (i = 0; i < AUDIO_BUFS; i++)
+ if (pa->urb_array[i])
+ usb_kill_urb(pa->urb_array[i]);
+ free_all_urb_generic(pa->urb_array, AUDIO_BUFS);
+ logpm();
+ return 0;
+}
+
+static int snd_pd_hw_capture_free(struct snd_pcm_substream *substream)
+{
+ struct poseidon *p = snd_pcm_substream_chip(substream);
+
+ logpm();
+ audio_buf_free(p);
+ return 0;
+}
+
+static int snd_pd_prepare(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+#define AUDIO_TRAILER_SIZE (16)
+static inline void handle_audio_data(struct urb *urb, int *period_elapsed)
+{
+ struct poseidon_audio *pa = urb->context;
+ struct snd_pcm_runtime *runtime = pa->capture_pcm_substream->runtime;
+
+ int stride = runtime->frame_bits >> 3;
+ int len = urb->actual_length / stride;
+ unsigned char *cp = urb->transfer_buffer;
+ unsigned int oldptr = pa->rcv_position;
+
+ if (urb->actual_length == AUDIO_BUF_SIZE - 4)
+ len -= (AUDIO_TRAILER_SIZE / stride);
+
+ /* do the copy */
+ if (oldptr + len >= runtime->buffer_size) {
+ unsigned int cnt = runtime->buffer_size - oldptr;
+
+ memcpy(runtime->dma_area + oldptr * stride, cp, cnt * stride);
+ memcpy(runtime->dma_area, (cp + cnt * stride),
+ (len * stride - cnt * stride));
+ } else
+ memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);
+
+ /* update the statas */
+ snd_pcm_stream_lock(pa->capture_pcm_substream);
+ pa->rcv_position += len;
+ if (pa->rcv_position >= runtime->buffer_size)
+ pa->rcv_position -= runtime->buffer_size;
+
+ pa->copied_position += (len);
+ if (pa->copied_position >= runtime->period_size) {
+ pa->copied_position -= runtime->period_size;
+ *period_elapsed = 1;
+ }
+ snd_pcm_stream_unlock(pa->capture_pcm_substream);
+}
+
+static void complete_handler_audio(struct urb *urb)
+{
+ struct poseidon_audio *pa = urb->context;
+ struct snd_pcm_substream *substream = pa->capture_pcm_substream;
+ int period_elapsed = 0;
+ int ret;
+
+ if (1 == pa->card_close || pa->capture_stream != STREAM_ON)
+ return;
+
+ if (urb->status != 0) {
+ /*if (urb->status == -ESHUTDOWN)*/
+ return;
+ }
+
+ if (substream) {
+ if (urb->actual_length) {
+ handle_audio_data(urb, &period_elapsed);
+ if (period_elapsed)
+ snd_pcm_period_elapsed(substream);
+ }
+ }
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret < 0)
+ log("audio urb failed (errcod = %i)", ret);
+ return;
+}
+
+static int fire_audio_urb(struct poseidon *p)
+{
+ int i, ret = 0;
+ struct poseidon_audio *pa = &p->audio;
+
+ alloc_bulk_urbs_generic(pa->urb_array, AUDIO_BUFS,
+ p->udev, AUDIO_EP,
+ AUDIO_BUF_SIZE, GFP_ATOMIC,
+ complete_handler_audio, pa);
+
+ for (i = 0; i < AUDIO_BUFS; i++) {
+ ret = usb_submit_urb(pa->urb_array[i], GFP_KERNEL);
+ if (ret)
+ log("urb err : %d", ret);
+ }
+ log();
+ return ret;
+}
+
+static int snd_pd_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct poseidon *p = snd_pcm_substream_chip(substream);
+ struct poseidon_audio *pa = &p->audio;
+
+ if (debug_mode)
+ log("cmd %d, audio stat : %d\n", cmd, pa->capture_stream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_START:
+ if (pa->capture_stream == STREAM_ON)
+ return 0;
+
+ pa->rcv_position = pa->copied_position = 0;
+ pa->capture_stream = STREAM_ON;
+
+ if (in_hibernation(p))
+ return 0;
+ fire_audio_urb(p);
+ return 0;
+
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ pa->capture_stream = STREAM_SUSPEND;
+ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pa->capture_stream = STREAM_OFF;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static snd_pcm_uframes_t
+snd_pd_capture_pointer(struct snd_pcm_substream *substream)
+{
+ struct poseidon *p = snd_pcm_substream_chip(substream);
+ struct poseidon_audio *pa = &p->audio;
+ return pa->rcv_position;
+}
+
+static struct page *snd_pcm_pd_get_page(struct snd_pcm_substream *subs,
+ unsigned long offset)
+{
+ void *pageptr = subs->runtime->dma_area + offset;
+ return vmalloc_to_page(pageptr);
+}
+
+static struct snd_pcm_ops pcm_capture_ops = {
+ .open = snd_pd_capture_open,
+ .close = snd_pd_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_pd_hw_capture_params,
+ .hw_free = snd_pd_hw_capture_free,
+ .prepare = snd_pd_prepare,
+ .trigger = snd_pd_capture_trigger,
+ .pointer = snd_pd_capture_pointer,
+ .page = snd_pcm_pd_get_page,
+};
+
+#ifdef CONFIG_PM
+int pm_alsa_suspend(struct poseidon *p)
+{
+ logpm(p);
+ audio_buf_free(p);
+ return 0;
+}
+
+int pm_alsa_resume(struct poseidon *p)
+{
+ logpm(p);
+ fire_audio_urb(p);
+ return 0;
+}
+#endif
+
+int poseidon_audio_init(struct poseidon *p)
+{
+ struct poseidon_audio *pa = &p->audio;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ int ret;
+
+ ret = snd_card_create(-1, "Telegent", THIS_MODULE, 0, &card);
+ if (ret != 0)
+ return ret;
+
+ ret = snd_pcm_new(card, "poseidon audio", 0, 0, 1, &pcm);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+ pcm->info_flags = 0;
+ pcm->private_data = p;
+ strcpy(pcm->name, "poseidon audio capture");
+
+ strcpy(card->driver, "ALSA driver");
+ strcpy(card->shortname, "poseidon Audio");
+ strcpy(card->longname, "poseidon ALSA Audio");
+
+ if (snd_card_register(card)) {
+ snd_card_free(card);
+ return -ENOMEM;
+ }
+ pa->card = card;
+ return 0;
+}
+
+int poseidon_audio_free(struct poseidon *p)
+{
+ struct poseidon_audio *pa = &p->audio;
+
+ if (pa->card)
+ snd_card_free(pa->card);
+ return 0;
+}
diff --git a/drivers/media/video/tlg2300/pd-common.h b/drivers/media/video/tlg2300/pd-common.h
new file mode 100644
index 000000000000..46066bdc73f9
--- /dev/null
+++ b/drivers/media/video/tlg2300/pd-common.h
@@ -0,0 +1,282 @@
+#ifndef PD_COMMON_H
+#define PD_COMMON_H
+
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/videodev2.h>
+#include <linux/semaphore.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-device.h>
+
+#include "dvb_frontend.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dmxdev.h"
+
+#define SBUF_NUM 8
+#define MAX_BUFFER_NUM 6
+#define PK_PER_URB 32
+#define ISO_PKT_SIZE 3072
+
+#define POSEIDON_STATE_NONE (0x0000)
+#define POSEIDON_STATE_ANALOG (0x0001)
+#define POSEIDON_STATE_FM (0x0002)
+#define POSEIDON_STATE_DVBT (0x0004)
+#define POSEIDON_STATE_VBI (0x0008)
+#define POSEIDON_STATE_DISCONNECT (0x0080)
+
+#define PM_SUSPEND_DELAY 3
+
+#define V4L_PAL_VBI_LINES 18
+#define V4L_NTSC_VBI_LINES 12
+#define V4L_PAL_VBI_FRAMESIZE (V4L_PAL_VBI_LINES * 1440 * 2)
+#define V4L_NTSC_VBI_FRAMESIZE (V4L_NTSC_VBI_LINES * 1440 * 2)
+
+#define TUNER_FREQ_MIN (45000000)
+#define TUNER_FREQ_MAX (862000000)
+
+struct vbi_data {
+ struct video_device *v_dev;
+ struct video_data *video;
+ struct front_face *front;
+
+ unsigned int copied;
+ unsigned int vbi_size; /* the whole size of two fields */
+ int users;
+};
+
+/*
+ * This is the running context of the video, it is useful for
+ * resume()
+ */
+struct running_context {
+ u32 freq; /* VIDIOC_S_FREQUENCY */
+ int audio_idx; /* VIDIOC_S_TUNER */
+ v4l2_std_id tvnormid; /* VIDIOC_S_STD */
+ int sig_index; /* VIDIOC_S_INPUT */
+ struct v4l2_pix_format pix; /* VIDIOC_S_FMT */
+};
+
+struct video_data {
+ /* v4l2 video device */
+ struct video_device *v_dev;
+
+ /* the working context */
+ struct running_context context;
+
+ /* for data copy */
+ int field_count;
+
+ char *dst;
+ int lines_copied;
+ int prev_left;
+
+ int lines_per_field;
+ int lines_size;
+
+ /* for communication */
+ u8 endpoint_addr;
+ struct urb *urb_array[SBUF_NUM];
+ struct vbi_data *vbi;
+ struct poseidon *pd;
+ struct front_face *front;
+
+ int is_streaming;
+ int users;
+
+ /* for bubble handler */
+ struct work_struct bubble_work;
+};
+
+enum pcm_stream_state {
+ STREAM_OFF,
+ STREAM_ON,
+ STREAM_SUSPEND,
+};
+
+#define AUDIO_BUFS (3)
+#define CAPTURE_STREAM_EN 1
+struct poseidon_audio {
+ struct urb *urb_array[AUDIO_BUFS];
+ unsigned int copied_position;
+ struct snd_pcm_substream *capture_pcm_substream;
+
+ unsigned int rcv_position;
+ struct snd_card *card;
+ int card_close;
+
+ int users;
+ int pm_state;
+ enum pcm_stream_state capture_stream;
+};
+
+struct radio_data {
+ __u32 fm_freq;
+ int users;
+ unsigned int is_radio_streaming;
+ int pre_emphasis;
+ struct video_device *fm_dev;
+};
+
+#define DVB_SBUF_NUM 4
+#define DVB_URB_BUF_SIZE 0x2000
+struct pd_dvb_adapter {
+ struct dvb_adapter dvb_adap;
+ struct dvb_frontend dvb_fe;
+ struct dmxdev dmxdev;
+ struct dvb_demux demux;
+
+ atomic_t users;
+ atomic_t active_feed;
+
+ /* data transfer */
+ s32 is_streaming;
+ struct urb *urb_array[DVB_SBUF_NUM];
+ struct poseidon *pd_device;
+ u8 ep_addr;
+ u8 reserved[3];
+
+ /* data for power resume*/
+ struct dvb_frontend_parameters fe_param;
+
+ /* for channel scanning */
+ int prev_freq;
+ int bandwidth;
+ unsigned long last_jiffies;
+};
+
+struct front_face {
+ /* use this field to distinguish VIDEO and VBI */
+ enum v4l2_buf_type type;
+
+ /* for host */
+ struct videobuf_queue q;
+
+ /* the bridge for host and device */
+ struct videobuf_buffer *curr_frame;
+
+ /* for device */
+ spinlock_t queue_lock;
+ struct list_head active;
+ struct poseidon *pd;
+};
+
+struct poseidon {
+ struct list_head device_list;
+
+ struct mutex lock;
+ struct kref kref;
+
+ /* for V4L2 */
+ struct v4l2_device v4l2_dev;
+
+ /* hardware info */
+ struct usb_device *udev;
+ struct usb_interface *interface;
+ int cur_transfer_mode;
+
+ struct video_data video_data; /* video */
+ struct vbi_data vbi_data; /* vbi */
+ struct poseidon_audio audio; /* audio (alsa) */
+ struct radio_data radio_data; /* FM */
+ struct pd_dvb_adapter dvb_data; /* DVB */
+
+ u32 state;
+ struct file *file_for_stream; /* the active stream*/
+
+#ifdef CONFIG_PM
+ int (*pm_suspend)(struct poseidon *);
+ int (*pm_resume)(struct poseidon *);
+ pm_message_t msg;
+
+ struct work_struct pm_work;
+ u8 portnum;
+#endif
+};
+
+struct poseidon_format {
+ char *name;
+ int fourcc; /* video4linux 2 */
+ int depth; /* bit/pixel */
+ int flags;
+};
+
+struct poseidon_tvnorm {
+ v4l2_std_id v4l2_id;
+ char name[12];
+ u32 tlg_tvnorm;
+};
+
+/* video */
+int pd_video_init(struct poseidon *);
+void pd_video_exit(struct poseidon *);
+int stop_all_video_stream(struct poseidon *);
+
+/* alsa audio */
+int poseidon_audio_init(struct poseidon *);
+int poseidon_audio_free(struct poseidon *);
+#ifdef CONFIG_PM
+int pm_alsa_suspend(struct poseidon *);
+int pm_alsa_resume(struct poseidon *);
+#endif
+
+/* dvb */
+int pd_dvb_usb_device_init(struct poseidon *);
+void pd_dvb_usb_device_exit(struct poseidon *);
+void pd_dvb_usb_device_cleanup(struct poseidon *);
+int pd_dvb_get_adapter_num(struct pd_dvb_adapter *);
+void dvb_stop_streaming(struct pd_dvb_adapter *);
+
+/* FM */
+int poseidon_fm_init(struct poseidon *);
+int poseidon_fm_exit(struct poseidon *);
+struct video_device *vdev_init(struct poseidon *, struct video_device *);
+
+/* vendor command ops */
+int send_set_req(struct poseidon*, u8, s32, s32*);
+int send_get_req(struct poseidon*, u8, s32, void*, s32*, s32);
+s32 set_tuner_mode(struct poseidon*, unsigned char);
+
+/* bulk urb alloc/free */
+int alloc_bulk_urbs_generic(struct urb **urb_array, int num,
+ struct usb_device *udev, u8 ep_addr,
+ int buf_size, gfp_t gfp_flags,
+ usb_complete_t complete_fn, void *context);
+void free_all_urb_generic(struct urb **urb_array, int num);
+
+/* misc */
+void poseidon_delete(struct kref *kref);
+void destroy_video_device(struct video_device **v_dev);
+extern int debug_mode;
+void set_debug_mode(struct video_device *vfd, int debug_mode);
+
+#ifdef CONFIG_PM
+#define in_hibernation(pd) (pd->msg.event == PM_EVENT_FREEZE)
+#else
+#define in_hibernation(pd) (0)
+#endif
+#define get_pm_count(p) (atomic_read(&(p)->interface->pm_usage_cnt))
+
+#define log(a, ...) printk(KERN_DEBUG "\t[ %s : %.3d ] "a"\n", \
+ __func__, __LINE__, ## __VA_ARGS__)
+
+/* for power management */
+#define logpm(pd) do {\
+ if (debug_mode & 0x10)\
+ log();\
+ } while (0)
+
+#define logs(f) do { \
+ if ((debug_mode & 0x4) && \
+ (f)->type == V4L2_BUF_TYPE_VBI_CAPTURE) \
+ log("type : VBI");\
+ \
+ if ((debug_mode & 0x8) && \
+ (f)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) \
+ log("type : VIDEO");\
+ } while (0)
+#endif
diff --git a/drivers/media/video/tlg2300/pd-dvb.c b/drivers/media/video/tlg2300/pd-dvb.c
new file mode 100644
index 000000000000..4133aee568bf
--- /dev/null
+++ b/drivers/media/video/tlg2300/pd-dvb.c
@@ -0,0 +1,593 @@
+#include "pd-common.h"
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/dvb/dmx.h>
+#include <linux/delay.h>
+
+#include "vendorcmds.h"
+#include <linux/sched.h>
+#include <asm/atomic.h>
+
+static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb);
+
+static int dvb_bandwidth[][2] = {
+ { TLG_BW_8, BANDWIDTH_8_MHZ },
+ { TLG_BW_7, BANDWIDTH_7_MHZ },
+ { TLG_BW_6, BANDWIDTH_6_MHZ }
+};
+static int dvb_bandwidth_length = ARRAY_SIZE(dvb_bandwidth);
+
+static s32 dvb_start_streaming(struct pd_dvb_adapter *pd_dvb);
+static int poseidon_check_mode_dvbt(struct poseidon *pd)
+{
+ s32 ret = 0, cmd_status = 0;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ/4);
+
+ ret = usb_set_interface(pd->udev, 0, BULK_ALTERNATE_IFACE);
+ if (ret != 0)
+ return ret;
+
+ ret = set_tuner_mode(pd, TLG_MODE_CAPS_DVB_T);
+ if (ret)
+ return ret;
+
+ /* signal source */
+ ret = send_set_req(pd, SGNL_SRC_SEL, TLG_SIG_SRC_ANTENNA, &cmd_status);
+ if (ret|cmd_status)
+ return ret;
+
+ return 0;
+}
+
+/* acquire :
+ * 1 == open
+ * 0 == release
+ */
+static int poseidon_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+ struct poseidon *pd = fe->demodulator_priv;
+ struct pd_dvb_adapter *pd_dvb;
+ int ret = 0;
+
+ if (!pd)
+ return -ENODEV;
+
+ pd_dvb = container_of(fe, struct pd_dvb_adapter, dvb_fe);
+ if (acquire) {
+ mutex_lock(&pd->lock);
+ if (pd->state & POSEIDON_STATE_DISCONNECT) {
+ ret = -ENODEV;
+ goto open_out;
+ }
+
+ if (pd->state && !(pd->state & POSEIDON_STATE_DVBT)) {
+ ret = -EBUSY;
+ goto open_out;
+ }
+
+ usb_autopm_get_interface(pd->interface);
+ if (0 == pd->state) {
+ ret = poseidon_check_mode_dvbt(pd);
+ if (ret < 0) {
+ usb_autopm_put_interface(pd->interface);
+ goto open_out;
+ }
+ pd->state |= POSEIDON_STATE_DVBT;
+ pd_dvb->bandwidth = 0;
+ pd_dvb->prev_freq = 0;
+ }
+ atomic_inc(&pd_dvb->users);
+ kref_get(&pd->kref);
+open_out:
+ mutex_unlock(&pd->lock);
+ } else {
+ dvb_stop_streaming(pd_dvb);
+
+ if (atomic_dec_and_test(&pd_dvb->users)) {
+ mutex_lock(&pd->lock);
+ pd->state &= ~POSEIDON_STATE_DVBT;
+ mutex_unlock(&pd->lock);
+ }
+ kref_put(&pd->kref, poseidon_delete);
+ usb_autopm_put_interface(pd->interface);
+ }
+ return ret;
+}
+
+static void poseidon_fe_release(struct dvb_frontend *fe)
+{
+ struct poseidon *pd = fe->demodulator_priv;
+
+#ifdef CONFIG_PM
+ pd->pm_suspend = NULL;
+ pd->pm_resume = NULL;
+#endif
+}
+
+static s32 poseidon_fe_sleep(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+/*
+ * return true if we can satisfy the conditions, else return false.
+ */
+static bool check_scan_ok(__u32 freq, int bandwidth,
+ struct pd_dvb_adapter *adapter)
+{
+ if (bandwidth < 0)
+ return false;
+
+ if (adapter->prev_freq == freq
+ && adapter->bandwidth == bandwidth) {
+ long nl = jiffies - adapter->last_jiffies;
+ unsigned int msec ;
+
+ msec = jiffies_to_msecs(abs(nl));
+ return msec > 15000 ? true : false;
+ }
+ return true;
+}
+
+/*
+ * Check if the firmware delays too long for an invalid frequency.
+ */
+static int fw_delay_overflow(struct pd_dvb_adapter *adapter)
+{
+ long nl = jiffies - adapter->last_jiffies;
+ unsigned int msec ;
+
+ msec = jiffies_to_msecs(abs(nl));
+ return msec > 800 ? true : false;
+}
+
+static int poseidon_set_fe(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ s32 ret = 0, cmd_status = 0;
+ s32 i, bandwidth = -1;
+ struct poseidon *pd = fe->demodulator_priv;
+ struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
+
+ if (in_hibernation(pd))
+ return -EBUSY;
+
+ mutex_lock(&pd->lock);
+ for (i = 0; i < dvb_bandwidth_length; i++)
+ if (fep->u.ofdm.bandwidth == dvb_bandwidth[i][1])
+ bandwidth = dvb_bandwidth[i][0];
+
+ if (check_scan_ok(fep->frequency, bandwidth, pd_dvb)) {
+ ret = send_set_req(pd, TUNE_FREQ_SELECT,
+ fep->frequency / 1000, &cmd_status);
+ if (ret | cmd_status) {
+ log("error line");
+ goto front_out;
+ }
+
+ ret = send_set_req(pd, DVBT_BANDW_SEL,
+ bandwidth, &cmd_status);
+ if (ret | cmd_status) {
+ log("error line");
+ goto front_out;
+ }
+
+ ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
+ if (ret | cmd_status) {
+ log("error line");
+ goto front_out;
+ }
+
+ /* save the context for future */
+ memcpy(&pd_dvb->fe_param, fep, sizeof(*fep));
+ pd_dvb->bandwidth = bandwidth;
+ pd_dvb->prev_freq = fep->frequency;
+ pd_dvb->last_jiffies = jiffies;
+ }
+front_out:
+ mutex_unlock(&pd->lock);
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int pm_dvb_suspend(struct poseidon *pd)
+{
+ struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
+ dvb_stop_streaming(pd_dvb);
+ dvb_urb_cleanup(pd_dvb);
+ msleep(500);
+ return 0;
+}
+
+static int pm_dvb_resume(struct poseidon *pd)
+{
+ struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
+
+ poseidon_check_mode_dvbt(pd);
+ msleep(300);
+ poseidon_set_fe(&pd_dvb->dvb_fe, &pd_dvb->fe_param);
+
+ dvb_start_streaming(pd_dvb);
+ return 0;
+}
+#endif
+
+static s32 poseidon_fe_init(struct dvb_frontend *fe)
+{
+ struct poseidon *pd = fe->demodulator_priv;
+ struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
+
+#ifdef CONFIG_PM
+ pd->pm_suspend = pm_dvb_suspend;
+ pd->pm_resume = pm_dvb_resume;
+#endif
+ memset(&pd_dvb->fe_param, 0,
+ sizeof(struct dvb_frontend_parameters));
+ return 0;
+}
+
+static int poseidon_get_fe(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct poseidon *pd = fe->demodulator_priv;
+ struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
+
+ memcpy(fep, &pd_dvb->fe_param, sizeof(*fep));
+ return 0;
+}
+
+static int poseidon_fe_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 1000;
+ return 0;
+}
+
+static int poseidon_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+ struct poseidon *pd = fe->demodulator_priv;
+ s32 ret = -1, cmd_status;
+ struct tuner_dtv_sig_stat_s status = {};
+
+ if (in_hibernation(pd))
+ return -EBUSY;
+ mutex_lock(&pd->lock);
+
+ ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_DVB_T,
+ &status, &cmd_status, sizeof(status));
+ if (ret | cmd_status) {
+ log("get tuner status error");
+ goto out;
+ }
+
+ if (debug_mode)
+ log("P : %d, L %d, LB :%d", status.sig_present,
+ status.sig_locked, status.sig_lock_busy);
+
+ if (status.sig_lock_busy) {
+ goto out;
+ } else if (status.sig_present || status.sig_locked) {
+ *stat |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER
+ | FE_HAS_SYNC | FE_HAS_VITERBI;
+ } else {
+ if (fw_delay_overflow(&pd->dvb_data))
+ *stat |= FE_TIMEDOUT;
+ }
+out:
+ mutex_unlock(&pd->lock);
+ return ret;
+}
+
+static int poseidon_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct poseidon *pd = fe->demodulator_priv;
+ struct tuner_ber_rate_s tlg_ber = {};
+ s32 ret = -1, cmd_status;
+
+ mutex_lock(&pd->lock);
+ ret = send_get_req(pd, TUNER_BER_RATE, 0,
+ &tlg_ber, &cmd_status, sizeof(tlg_ber));
+ if (ret | cmd_status)
+ goto out;
+ *ber = tlg_ber.ber_rate;
+out:
+ mutex_unlock(&pd->lock);
+ return ret;
+}
+
+static s32 poseidon_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct poseidon *pd = fe->demodulator_priv;
+ struct tuner_dtv_sig_stat_s status = {};
+ s32 ret = 0, cmd_status;
+
+ mutex_lock(&pd->lock);
+ ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_DVB_T,
+ &status, &cmd_status, sizeof(status));
+ if (ret | cmd_status)
+ goto out;
+ if ((status.sig_present || status.sig_locked) && !status.sig_strength)
+ *strength = 0xFFFF;
+ else
+ *strength = status.sig_strength;
+out:
+ mutex_unlock(&pd->lock);
+ return ret;
+}
+
+static int poseidon_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ return 0;
+}
+
+static int poseidon_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
+{
+ *unc = 0;
+ return 0;
+}
+
+static struct dvb_frontend_ops poseidon_frontend_ops = {
+ .info = {
+ .name = "Poseidon DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 174000000,
+ .frequency_max = 862000000,
+ .frequency_stepsize = 62500,/* FIXME */
+ .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_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+ FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_RECOVER |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = poseidon_fe_release,
+
+ .init = poseidon_fe_init,
+ .sleep = poseidon_fe_sleep,
+
+ .set_frontend = poseidon_set_fe,
+ .get_frontend = poseidon_get_fe,
+ .get_tune_settings = poseidon_fe_get_tune_settings,
+
+ .read_status = poseidon_read_status,
+ .read_ber = poseidon_read_ber,
+ .read_signal_strength = poseidon_read_signal_strength,
+ .read_snr = poseidon_read_snr,
+ .read_ucblocks = poseidon_read_unc_blocks,
+
+ .ts_bus_ctrl = poseidon_ts_bus_ctrl,
+};
+
+static void dvb_urb_irq(struct urb *urb)
+{
+ struct pd_dvb_adapter *pd_dvb = urb->context;
+ int len = urb->transfer_buffer_length;
+ struct dvb_demux *demux = &pd_dvb->demux;
+ s32 ret;
+
+ if (!pd_dvb->is_streaming || urb->status) {
+ if (urb->status == -EPROTO)
+ goto resend;
+ return;
+ }
+
+ if (urb->actual_length == len)
+ dvb_dmx_swfilter(demux, urb->transfer_buffer, len);
+ else if (urb->actual_length == len - 4) {
+ int offset;
+ u8 *buf = urb->transfer_buffer;
+
+ /*
+ * The packet size is 512,
+ * last packet contains 456 bytes tsp data
+ */
+ for (offset = 456; offset < len; offset += 512) {
+ if (!strncmp(buf + offset, "DVHS", 4)) {
+ dvb_dmx_swfilter(demux, buf, offset);
+ if (len > offset + 52 + 4) {
+ /*16 bytes trailer + 36 bytes padding */
+ buf += offset + 52;
+ len -= offset + 52 + 4;
+ dvb_dmx_swfilter(demux, buf, len);
+ }
+ break;
+ }
+ }
+ }
+
+resend:
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret)
+ log(" usb_submit_urb failed: error %d", ret);
+}
+
+static int dvb_urb_init(struct pd_dvb_adapter *pd_dvb)
+{
+ if (pd_dvb->urb_array[0])
+ return 0;
+
+ alloc_bulk_urbs_generic(pd_dvb->urb_array, DVB_SBUF_NUM,
+ pd_dvb->pd_device->udev, pd_dvb->ep_addr,
+ DVB_URB_BUF_SIZE, GFP_KERNEL,
+ dvb_urb_irq, pd_dvb);
+ return 0;
+}
+
+static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb)
+{
+ free_all_urb_generic(pd_dvb->urb_array, DVB_SBUF_NUM);
+}
+
+static s32 dvb_start_streaming(struct pd_dvb_adapter *pd_dvb)
+{
+ struct poseidon *pd = pd_dvb->pd_device;
+ int ret = 0;
+
+ if (pd->state & POSEIDON_STATE_DISCONNECT)
+ return -ENODEV;
+
+ mutex_lock(&pd->lock);
+ if (!pd_dvb->is_streaming) {
+ s32 i, cmd_status = 0;
+ /*
+ * Once upon a time, there was a difficult bug lying here.
+ * ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
+ */
+
+ ret = send_set_req(pd, PLAY_SERVICE, 1, &cmd_status);
+ if (ret | cmd_status)
+ goto out;
+
+ ret = dvb_urb_init(pd_dvb);
+ if (ret < 0)
+ goto out;
+
+ pd_dvb->is_streaming = 1;
+ for (i = 0; i < DVB_SBUF_NUM; i++) {
+ ret = usb_submit_urb(pd_dvb->urb_array[i],
+ GFP_KERNEL);
+ if (ret) {
+ log(" submit urb error %d", ret);
+ goto out;
+ }
+ }
+ }
+out:
+ mutex_unlock(&pd->lock);
+ return ret;
+}
+
+void dvb_stop_streaming(struct pd_dvb_adapter *pd_dvb)
+{
+ struct poseidon *pd = pd_dvb->pd_device;
+
+ mutex_lock(&pd->lock);
+ if (pd_dvb->is_streaming) {
+ s32 i, ret, cmd_status = 0;
+
+ pd_dvb->is_streaming = 0;
+
+ for (i = 0; i < DVB_SBUF_NUM; i++)
+ if (pd_dvb->urb_array[i])
+ usb_kill_urb(pd_dvb->urb_array[i]);
+
+ ret = send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP,
+ &cmd_status);
+ if (ret | cmd_status)
+ log("error");
+ }
+ mutex_unlock(&pd->lock);
+}
+
+static int pd_start_feed(struct dvb_demux_feed *feed)
+{
+ struct pd_dvb_adapter *pd_dvb = feed->demux->priv;
+ int ret = 0;
+
+ if (!pd_dvb)
+ return -1;
+ if (atomic_inc_return(&pd_dvb->active_feed) == 1)
+ ret = dvb_start_streaming(pd_dvb);
+ return ret;
+}
+
+static int pd_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct pd_dvb_adapter *pd_dvb = feed->demux->priv;
+
+ if (!pd_dvb)
+ return -1;
+ if (atomic_dec_and_test(&pd_dvb->active_feed))
+ dvb_stop_streaming(pd_dvb);
+ return 0;
+}
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+int pd_dvb_usb_device_init(struct poseidon *pd)
+{
+ struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
+ struct dvb_demux *dvbdemux;
+ int ret = 0;
+
+ pd_dvb->ep_addr = 0x82;
+ atomic_set(&pd_dvb->users, 0);
+ atomic_set(&pd_dvb->active_feed, 0);
+ pd_dvb->pd_device = pd;
+
+ ret = dvb_register_adapter(&pd_dvb->dvb_adap,
+ "Poseidon dvbt adapter",
+ THIS_MODULE,
+ NULL /* for hibernation correctly*/,
+ adapter_nr);
+ if (ret < 0)
+ goto error1;
+
+ /* register frontend */
+ pd_dvb->dvb_fe.demodulator_priv = pd;
+ memcpy(&pd_dvb->dvb_fe.ops, &poseidon_frontend_ops,
+ sizeof(struct dvb_frontend_ops));
+ ret = dvb_register_frontend(&pd_dvb->dvb_adap, &pd_dvb->dvb_fe);
+ if (ret < 0)
+ goto error2;
+
+ /* register demux device */
+ dvbdemux = &pd_dvb->demux;
+ dvbdemux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+ dvbdemux->priv = pd_dvb;
+ dvbdemux->feednum = dvbdemux->filternum = 64;
+ dvbdemux->start_feed = pd_start_feed;
+ dvbdemux->stop_feed = pd_stop_feed;
+ dvbdemux->write_to_decoder = NULL;
+
+ ret = dvb_dmx_init(dvbdemux);
+ if (ret < 0)
+ goto error3;
+
+ pd_dvb->dmxdev.filternum = pd_dvb->demux.filternum;
+ pd_dvb->dmxdev.demux = &pd_dvb->demux.dmx;
+ pd_dvb->dmxdev.capabilities = 0;
+
+ ret = dvb_dmxdev_init(&pd_dvb->dmxdev, &pd_dvb->dvb_adap);
+ if (ret < 0)
+ goto error3;
+ return 0;
+
+error3:
+ dvb_unregister_frontend(&pd_dvb->dvb_fe);
+error2:
+ dvb_unregister_adapter(&pd_dvb->dvb_adap);
+error1:
+ return ret;
+}
+
+void pd_dvb_usb_device_exit(struct poseidon *pd)
+{
+ struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
+
+ while (atomic_read(&pd_dvb->users) != 0
+ || atomic_read(&pd_dvb->active_feed) != 0) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ);
+ }
+ dvb_dmxdev_release(&pd_dvb->dmxdev);
+ dvb_unregister_frontend(&pd_dvb->dvb_fe);
+ dvb_unregister_adapter(&pd_dvb->dvb_adap);
+ pd_dvb_usb_device_cleanup(pd);
+}
+
+void pd_dvb_usb_device_cleanup(struct poseidon *pd)
+{
+ struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
+
+ dvb_urb_cleanup(pd_dvb);
+}
+
+int pd_dvb_get_adapter_num(struct pd_dvb_adapter *pd_dvb)
+{
+ return pd_dvb->dvb_adap.num;
+}
diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/video/tlg2300/pd-main.c
new file mode 100644
index 000000000000..2cf0ebf9f28b
--- /dev/null
+++ b/drivers/media/video/tlg2300/pd-main.c
@@ -0,0 +1,539 @@
+/*
+ * device driver for Telegent tlg2300 based TV cards
+ *
+ * Author :
+ * Kang Yong <kangyong@telegent.com>
+ * Zhang Xiaobing <xbzhang@telegent.com>
+ * Huang Shijie <zyziii@telegent.com> or <shijie8@gmail.com>
+ *
+ * (c) 2009 Telegent Systems
+ * (c) 2010 Telegent Systems
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/version.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/suspend.h>
+#include <linux/usb/quirks.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/firmware.h>
+#include <linux/smp_lock.h>
+
+#include "vendorcmds.h"
+#include "pd-common.h"
+
+#define VENDOR_ID 0x1B24
+#define PRODUCT_ID 0x4001
+static struct usb_device_id id_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID, PRODUCT_ID, 255, 1, 0) },
+ { USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID, PRODUCT_ID, 255, 1, 1) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+int debug_mode;
+module_param(debug_mode, int, 0644);
+MODULE_PARM_DESC(debug_mode, "0 = disable, 1 = enable, 2 = verbose");
+
+const char *firmware_name = "tlg2300_firmware.bin";
+struct usb_driver poseidon_driver;
+static LIST_HEAD(pd_device_list);
+
+/*
+ * send set request to USB firmware.
+ */
+s32 send_set_req(struct poseidon *pd, u8 cmdid, s32 param, s32 *cmd_status)
+{
+ s32 ret;
+ s8 data[32] = {};
+ u16 lower_16, upper_16;
+
+ if (pd->state & POSEIDON_STATE_DISCONNECT)
+ return -ENODEV;
+
+ mdelay(30);
+
+ if (param == 0) {
+ upper_16 = lower_16 = 0;
+ } else {
+ /* send 32 bit param as two 16 bit param,little endian */
+ lower_16 = (unsigned short)(param & 0xffff);
+ upper_16 = (unsigned short)((param >> 16) & 0xffff);
+ }
+ ret = usb_control_msg(pd->udev,
+ usb_rcvctrlpipe(pd->udev, 0),
+ REQ_SET_CMD | cmdid,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ lower_16,
+ upper_16,
+ &data,
+ sizeof(*cmd_status),
+ USB_CTRL_GET_TIMEOUT);
+
+ if (!ret) {
+ return -ENXIO;
+ } else {
+ /* 1st 4 bytes into cmd_status */
+ memcpy((char *)cmd_status, &(data[0]), sizeof(*cmd_status));
+ }
+ return 0;
+}
+
+/*
+ * send get request to Poseidon firmware.
+ */
+s32 send_get_req(struct poseidon *pd, u8 cmdid, s32 param,
+ void *buf, s32 *cmd_status, s32 datalen)
+{
+ s32 ret;
+ s8 data[128] = {};
+ u16 lower_16, upper_16;
+
+ if (pd->state & POSEIDON_STATE_DISCONNECT)
+ return -ENODEV;
+
+ mdelay(30);
+ if (param == 0) {
+ upper_16 = lower_16 = 0;
+ } else {
+ /*send 32 bit param as two 16 bit param, little endian */
+ lower_16 = (unsigned short)(param & 0xffff);
+ upper_16 = (unsigned short)((param >> 16) & 0xffff);
+ }
+ ret = usb_control_msg(pd->udev,
+ usb_rcvctrlpipe(pd->udev, 0),
+ REQ_GET_CMD | cmdid,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ lower_16,
+ upper_16,
+ &data,
+ (datalen + sizeof(*cmd_status)),
+ USB_CTRL_GET_TIMEOUT);
+
+ if (ret < 0) {
+ return -ENXIO;
+ } else {
+ /* 1st 4 bytes into cmd_status, remaining data into cmd_data */
+ memcpy((char *)cmd_status, &data[0], sizeof(*cmd_status));
+ memcpy((char *)buf, &data[sizeof(*cmd_status)], datalen);
+ }
+ return 0;
+}
+
+static int pm_notifier_block(struct notifier_block *nb,
+ unsigned long event, void *dummy)
+{
+ struct poseidon *pd = NULL;
+ struct list_head *node, *next;
+
+ switch (event) {
+ case PM_POST_HIBERNATION:
+ list_for_each_safe(node, next, &pd_device_list) {
+ struct usb_device *udev;
+ struct usb_interface *iface;
+ int rc = 0;
+
+ pd = container_of(node, struct poseidon, device_list);
+ udev = pd->udev;
+ iface = pd->interface;
+
+ /* It will cause the system to reload the firmware */
+ rc = usb_lock_device_for_reset(udev, iface);
+ if (rc >= 0) {
+ usb_reset_device(udev);
+ usb_unlock_device(udev);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ log("event :%ld\n", event);
+ return 0;
+}
+
+static struct notifier_block pm_notifer = {
+ .notifier_call = pm_notifier_block,
+};
+
+int set_tuner_mode(struct poseidon *pd, unsigned char mode)
+{
+ s32 ret, cmd_status;
+
+ if (pd->state & POSEIDON_STATE_DISCONNECT)
+ return -ENODEV;
+
+ ret = send_set_req(pd, TUNE_MODE_SELECT, mode, &cmd_status);
+ if (ret || cmd_status)
+ return -ENXIO;
+ return 0;
+}
+
+void poseidon_delete(struct kref *kref)
+{
+ struct poseidon *pd = container_of(kref, struct poseidon, kref);
+
+ if (!pd)
+ return;
+ list_del_init(&pd->device_list);
+
+ pd_dvb_usb_device_cleanup(pd);
+ /* clean_audio_data(&pd->audio_data);*/
+
+ if (pd->udev) {
+ usb_put_dev(pd->udev);
+ pd->udev = NULL;
+ }
+ if (pd->interface) {
+ usb_put_intf(pd->interface);
+ pd->interface = NULL;
+ }
+ kfree(pd);
+ log();
+}
+
+static int firmware_download(struct usb_device *udev)
+{
+ int ret = 0, actual_length;
+ const struct firmware *fw = NULL;
+ void *fwbuf = NULL;
+ size_t fwlength = 0, offset;
+ size_t max_packet_size;
+
+ ret = request_firmware(&fw, firmware_name, &udev->dev);
+ if (ret) {
+ log("download err : %d", ret);
+ return ret;
+ }
+
+ fwlength = fw->size;
+
+ fwbuf = kzalloc(fwlength, GFP_KERNEL);
+ if (!fwbuf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ memcpy(fwbuf, fw->data, fwlength);
+
+ max_packet_size = udev->ep_out[0x1]->desc.wMaxPacketSize;
+ log("\t\t download size : %d", (int)max_packet_size);
+
+ for (offset = 0; offset < fwlength; offset += max_packet_size) {
+ actual_length = 0;
+ ret = usb_bulk_msg(udev,
+ usb_sndbulkpipe(udev, 0x01), /* ep 1 */
+ fwbuf + offset,
+ min(max_packet_size, fwlength - offset),
+ &actual_length,
+ HZ * 10);
+ if (ret)
+ break;
+ }
+ kfree(fwbuf);
+out:
+ release_firmware(fw);
+ return ret;
+}
+
+static inline struct poseidon *get_pd(struct usb_interface *intf)
+{
+ return usb_get_intfdata(intf);
+}
+
+#ifdef CONFIG_PM
+/* one-to-one map : poseidon{} <----> usb_device{}'s port */
+static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev)
+{
+ pd->portnum = udev->portnum;
+}
+
+static inline int get_autopm_ref(struct poseidon *pd)
+{
+ return pd->video_data.users + pd->vbi_data.users + pd->audio.users
+ + atomic_read(&pd->dvb_data.users) + pd->radio_data.users;
+}
+
+/* fixup something for poseidon */
+static inline struct poseidon *fixup(struct poseidon *pd)
+{
+ int count;
+
+ /* old udev and interface have gone, so put back reference . */
+ count = get_autopm_ref(pd);
+ log("count : %d, ref count : %d", count, get_pm_count(pd));
+ while (count--)
+ usb_autopm_put_interface(pd->interface);
+ /*usb_autopm_set_interface(pd->interface); */
+
+ usb_put_dev(pd->udev);
+ usb_put_intf(pd->interface);
+ log("event : %d\n", pd->msg.event);
+ return pd;
+}
+
+static struct poseidon *find_old_poseidon(struct usb_device *udev)
+{
+ struct poseidon *pd;
+
+ list_for_each_entry(pd, &pd_device_list, device_list) {
+ if (pd->portnum == udev->portnum && in_hibernation(pd))
+ return fixup(pd);
+ }
+ return NULL;
+}
+
+/* Is the card working now ? */
+static inline int is_working(struct poseidon *pd)
+{
+ return get_pm_count(pd) > 0;
+}
+
+static int poseidon_suspend(struct usb_interface *intf, pm_message_t msg)
+{
+ struct poseidon *pd = get_pd(intf);
+
+ if (!pd)
+ return 0;
+ if (!is_working(pd)) {
+ if (get_pm_count(pd) <= 0 && !in_hibernation(pd)) {
+ pd->msg.event = PM_EVENT_AUTO_SUSPEND;
+ pd->pm_resume = NULL; /* a good guard */
+ printk(KERN_DEBUG "\n\t+ TLG2300 auto suspend +\n\n");
+ }
+ return 0;
+ }
+ pd->msg = msg; /* save it here */
+ logpm(pd);
+ return pd->pm_suspend ? pd->pm_suspend(pd) : 0;
+}
+
+static int poseidon_resume(struct usb_interface *intf)
+{
+ struct poseidon *pd = get_pd(intf);
+
+ if (!pd)
+ return 0;
+ printk(KERN_DEBUG "\n\t ++ TLG2300 resume ++\n\n");
+
+ if (!is_working(pd)) {
+ if (PM_EVENT_AUTO_SUSPEND == pd->msg.event)
+ pd->msg = PMSG_ON;
+ return 0;
+ }
+ if (in_hibernation(pd)) {
+ logpm(pd);
+ return 0;
+ }
+ logpm(pd);
+ return pd->pm_resume ? pd->pm_resume(pd) : 0;
+}
+
+static void hibernation_resume(struct work_struct *w)
+{
+ struct poseidon *pd = container_of(w, struct poseidon, pm_work);
+ int count;
+
+ pd->msg.event = 0; /* clear it here */
+ pd->state &= ~POSEIDON_STATE_DISCONNECT;
+
+ /* set the new interface's reference */
+ count = get_autopm_ref(pd);
+ while (count--)
+ usb_autopm_get_interface(pd->interface);
+
+ /* resume the context */
+ logpm(pd);
+ if (pd->pm_resume)
+ pd->pm_resume(pd);
+}
+#else /* CONFIG_PM is not enabled: */
+static inline struct poseidon *find_old_poseidon(struct usb_device *udev)
+{
+ return NULL;
+}
+
+static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev)
+{
+}
+#endif
+
+static bool check_firmware(struct usb_device *udev, int *down_firmware)
+{
+ void *buf;
+ int ret;
+ struct cmd_firmware_vers_s *cmd_firm;
+
+ buf = kzalloc(sizeof(*cmd_firm) + sizeof(u32), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ ret = usb_control_msg(udev,
+ usb_rcvctrlpipe(udev, 0),
+ REQ_GET_CMD | GET_FW_ID,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0,
+ 0,
+ buf,
+ sizeof(*cmd_firm) + sizeof(u32),
+ USB_CTRL_GET_TIMEOUT);
+ kfree(buf);
+
+ if (ret < 0) {
+ *down_firmware = 1;
+ return firmware_download(udev);
+ }
+ return ret;
+}
+
+static int poseidon_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct poseidon *pd = NULL;
+ int ret = 0;
+ int new_one = 0;
+
+ /* download firmware */
+ check_firmware(udev, &ret);
+ if (ret)
+ return 0;
+
+ /* Do I recovery from the hibernate ? */
+ pd = find_old_poseidon(udev);
+ if (!pd) {
+ pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return -ENOMEM;
+ kref_init(&pd->kref);
+ set_map_flags(pd, udev);
+ new_one = 1;
+ }
+
+ pd->udev = usb_get_dev(udev);
+ pd->interface = usb_get_intf(interface);
+ usb_set_intfdata(interface, pd);
+
+ if (new_one) {
+ struct device *dev = &interface->dev;
+
+ logpm(pd);
+ mutex_init(&pd->lock);
+
+ /* register v4l2 device */
+ snprintf(pd->v4l2_dev.name, sizeof(pd->v4l2_dev.name), "%s %s",
+ dev->driver->name, dev_name(dev));
+ ret = v4l2_device_register(NULL, &pd->v4l2_dev);
+
+ /* register devices in directory /dev */
+ ret = pd_video_init(pd);
+ poseidon_audio_init(pd);
+ poseidon_fm_init(pd);
+ pd_dvb_usb_device_init(pd);
+
+ INIT_LIST_HEAD(&pd->device_list);
+ list_add_tail(&pd->device_list, &pd_device_list);
+ }
+
+ device_init_wakeup(&udev->dev, 1);
+#ifdef CONFIG_PM
+ pd->udev->autosuspend_disabled = 0;
+ pd->udev->autosuspend_delay = HZ * PM_SUSPEND_DELAY;
+
+ if (in_hibernation(pd)) {
+ INIT_WORK(&pd->pm_work, hibernation_resume);
+ schedule_work(&pd->pm_work);
+ }
+#endif
+ return 0;
+}
+
+static void poseidon_disconnect(struct usb_interface *interface)
+{
+ struct poseidon *pd = get_pd(interface);
+
+ if (!pd)
+ return;
+ logpm(pd);
+ if (in_hibernation(pd))
+ return;
+
+ mutex_lock(&pd->lock);
+ pd->state |= POSEIDON_STATE_DISCONNECT;
+ mutex_unlock(&pd->lock);
+
+ /* stop urb transferring */
+ stop_all_video_stream(pd);
+ dvb_stop_streaming(&pd->dvb_data);
+
+ /*unregister v4l2 device */
+ v4l2_device_unregister(&pd->v4l2_dev);
+
+ lock_kernel();
+ {
+ pd_dvb_usb_device_exit(pd);
+ poseidon_fm_exit(pd);
+
+ poseidon_audio_free(pd);
+ pd_video_exit(pd);
+ }
+ unlock_kernel();
+
+ usb_set_intfdata(interface, NULL);
+ kref_put(&pd->kref, poseidon_delete);
+}
+
+struct usb_driver poseidon_driver = {
+ .name = "poseidon",
+ .probe = poseidon_probe,
+ .disconnect = poseidon_disconnect,
+ .id_table = id_table,
+#ifdef CONFIG_PM
+ .suspend = poseidon_suspend,
+ .resume = poseidon_resume,
+#endif
+ .supports_autosuspend = 1,
+};
+
+static int __init poseidon_init(void)
+{
+ int ret;
+
+ ret = usb_register(&poseidon_driver);
+ if (ret)
+ return ret;
+ register_pm_notifier(&pm_notifer);
+ return ret;
+}
+
+static void __exit poseidon_exit(void)
+{
+ log();
+ unregister_pm_notifier(&pm_notifer);
+ usb_deregister(&poseidon_driver);
+}
+
+module_init(poseidon_init);
+module_exit(poseidon_exit);
+
+MODULE_AUTHOR("Telegent Systems");
+MODULE_DESCRIPTION("For tlg2300-based USB device ");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tlg2300/pd-radio.c b/drivers/media/video/tlg2300/pd-radio.c
new file mode 100644
index 000000000000..755766b15157
--- /dev/null
+++ b/drivers/media/video/tlg2300/pd-radio.c
@@ -0,0 +1,420 @@
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <media/v4l2-dev.h>
+#include <linux/version.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/sched.h>
+
+#include "pd-common.h"
+#include "vendorcmds.h"
+
+static int set_frequency(struct poseidon *p, __u32 frequency);
+static int poseidon_fm_close(struct file *filp);
+static int poseidon_fm_open(struct file *filp);
+
+#define TUNER_FREQ_MIN_FM 76000000
+#define TUNER_FREQ_MAX_FM 108000000
+
+#define MAX_PREEMPHASIS (V4L2_PREEMPHASIS_75_uS + 1)
+static int preemphasis[MAX_PREEMPHASIS] = {
+ TLG_TUNE_ASTD_NONE, /* V4L2_PREEMPHASIS_DISABLED */
+ TLG_TUNE_ASTD_FM_EUR, /* V4L2_PREEMPHASIS_50_uS */
+ TLG_TUNE_ASTD_FM_US, /* V4L2_PREEMPHASIS_75_uS */
+};
+
+static int poseidon_check_mode_radio(struct poseidon *p)
+{
+ int ret;
+ u32 status;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ/2);
+ ret = usb_set_interface(p->udev, 0, BULK_ALTERNATE_IFACE);
+ if (ret < 0)
+ goto out;
+
+ ret = set_tuner_mode(p, TLG_MODE_FM_RADIO);
+ if (ret != 0)
+ goto out;
+
+ ret = send_set_req(p, SGNL_SRC_SEL, TLG_SIG_SRC_ANTENNA, &status);
+ ret = send_set_req(p, TUNER_AUD_ANA_STD,
+ p->radio_data.pre_emphasis, &status);
+ ret |= send_set_req(p, TUNER_AUD_MODE,
+ TLG_TUNE_TVAUDIO_MODE_STEREO, &status);
+ ret |= send_set_req(p, AUDIO_SAMPLE_RATE_SEL,
+ ATV_AUDIO_RATE_48K, &status);
+ ret |= send_set_req(p, TUNE_FREQ_SELECT, TUNER_FREQ_MIN_FM, &status);
+out:
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int pm_fm_suspend(struct poseidon *p)
+{
+ logpm(p);
+ pm_alsa_suspend(p);
+ usb_set_interface(p->udev, 0, 0);
+ msleep(300);
+ return 0;
+}
+
+static int pm_fm_resume(struct poseidon *p)
+{
+ logpm(p);
+ poseidon_check_mode_radio(p);
+ set_frequency(p, p->radio_data.fm_freq);
+ pm_alsa_resume(p);
+ return 0;
+}
+#endif
+
+static int poseidon_fm_open(struct file *filp)
+{
+ struct video_device *vfd = video_devdata(filp);
+ struct poseidon *p = video_get_drvdata(vfd);
+ int ret = 0;
+
+ if (!p)
+ return -1;
+
+ mutex_lock(&p->lock);
+ if (p->state & POSEIDON_STATE_DISCONNECT) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (p->state && !(p->state & POSEIDON_STATE_FM)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ usb_autopm_get_interface(p->interface);
+ if (0 == p->state) {
+ /* default pre-emphasis */
+ if (p->radio_data.pre_emphasis == 0)
+ p->radio_data.pre_emphasis = TLG_TUNE_ASTD_FM_EUR;
+ set_debug_mode(vfd, debug_mode);
+
+ ret = poseidon_check_mode_radio(p);
+ if (ret < 0) {
+ usb_autopm_put_interface(p->interface);
+ goto out;
+ }
+ p->state |= POSEIDON_STATE_FM;
+ }
+ p->radio_data.users++;
+ kref_get(&p->kref);
+ filp->private_data = p;
+out:
+ mutex_unlock(&p->lock);
+ return ret;
+}
+
+static int poseidon_fm_close(struct file *filp)
+{
+ struct poseidon *p = filp->private_data;
+ struct radio_data *fm = &p->radio_data;
+ uint32_t status;
+
+ mutex_lock(&p->lock);
+ fm->users--;
+ if (0 == fm->users)
+ p->state &= ~POSEIDON_STATE_FM;
+
+ if (fm->is_radio_streaming && filp == p->file_for_stream) {
+ fm->is_radio_streaming = 0;
+ send_set_req(p, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP, &status);
+ }
+ usb_autopm_put_interface(p->interface);
+ mutex_unlock(&p->lock);
+
+ kref_put(&p->kref, poseidon_delete);
+ filp->private_data = NULL;
+ return 0;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+{
+ struct poseidon *p = file->private_data;
+
+ strlcpy(v->driver, "tele-radio", sizeof(v->driver));
+ strlcpy(v->card, "Telegent Poseidon", sizeof(v->card));
+ usb_make_path(p->udev, v->bus_info, sizeof(v->bus_info));
+ v->version = KERNEL_VERSION(0, 0, 1);
+ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ return 0;
+}
+
+static const struct v4l2_file_operations poseidon_fm_fops = {
+ .owner = THIS_MODULE,
+ .open = poseidon_fm_open,
+ .release = poseidon_fm_close,
+ .ioctl = video_ioctl2,
+};
+
+int tlg_fm_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
+{
+ struct tuner_fm_sig_stat_s fm_stat = {};
+ int ret, status, count = 5;
+ struct poseidon *p = file->private_data;
+
+ if (vt->index != 0)
+ return -EINVAL;
+
+ vt->type = V4L2_TUNER_RADIO;
+ vt->capability = V4L2_TUNER_CAP_STEREO;
+ vt->rangelow = TUNER_FREQ_MIN_FM / 62500;
+ vt->rangehigh = TUNER_FREQ_MAX_FM / 62500;
+ vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ vt->audmode = V4L2_TUNER_MODE_STEREO;
+ vt->signal = 0;
+ vt->afc = 0;
+
+ mutex_lock(&p->lock);
+ ret = send_get_req(p, TUNER_STATUS, TLG_MODE_FM_RADIO,
+ &fm_stat, &status, sizeof(fm_stat));
+
+ while (fm_stat.sig_lock_busy && count-- && !ret) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ);
+
+ ret = send_get_req(p, TUNER_STATUS, TLG_MODE_FM_RADIO,
+ &fm_stat, &status, sizeof(fm_stat));
+ }
+ mutex_unlock(&p->lock);
+
+ if (ret || status) {
+ vt->signal = 0;
+ } else if ((fm_stat.sig_present || fm_stat.sig_locked)
+ && fm_stat.sig_strength == 0) {
+ vt->signal = 0xffff;
+ } else
+ vt->signal = (fm_stat.sig_strength * 255 / 10) << 8;
+
+ return 0;
+}
+
+int fm_get_freq(struct file *file, void *priv, struct v4l2_frequency *argp)
+{
+ struct poseidon *p = file->private_data;
+
+ argp->frequency = p->radio_data.fm_freq;
+ return 0;
+}
+
+static int set_frequency(struct poseidon *p, __u32 frequency)
+{
+ __u32 freq ;
+ int ret, status;
+
+ mutex_lock(&p->lock);
+
+ ret = send_set_req(p, TUNER_AUD_ANA_STD,
+ p->radio_data.pre_emphasis, &status);
+
+ freq = (frequency * 125) * 500 / 1000;/* kHZ */
+ if (freq < TUNER_FREQ_MIN_FM/1000 || freq > TUNER_FREQ_MAX_FM/1000) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = send_set_req(p, TUNE_FREQ_SELECT, freq, &status);
+ if (ret < 0)
+ goto error ;
+ ret = send_set_req(p, TAKE_REQUEST, 0, &status);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ/4);
+ if (!p->radio_data.is_radio_streaming) {
+ ret = send_set_req(p, TAKE_REQUEST, 0, &status);
+ ret = send_set_req(p, PLAY_SERVICE,
+ TLG_TUNE_PLAY_SVC_START, &status);
+ p->radio_data.is_radio_streaming = 1;
+ }
+ p->radio_data.fm_freq = frequency;
+error:
+ mutex_unlock(&p->lock);
+ return ret;
+}
+
+int fm_set_freq(struct file *file, void *priv, struct v4l2_frequency *argp)
+{
+ struct poseidon *p = file->private_data;
+
+ p->file_for_stream = file;
+#ifdef CONFIG_PM
+ p->pm_suspend = pm_fm_suspend;
+ p->pm_resume = pm_fm_resume;
+#endif
+ return set_frequency(p, argp->frequency);
+}
+
+int tlg_fm_vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *arg)
+{
+ return 0;
+}
+
+int tlg_fm_vidioc_g_exts_ctrl(struct file *file, void *fh,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct poseidon *p = file->private_data;
+ int i;
+
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX)
+ return -EINVAL;
+
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS)
+ continue;
+
+ if (i < MAX_PREEMPHASIS)
+ ctrl->value = p->radio_data.pre_emphasis;
+ }
+ return 0;
+}
+
+int tlg_fm_vidioc_s_exts_ctrl(struct file *file, void *fh,
+ struct v4l2_ext_controls *ctrls)
+{
+ int i;
+
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX)
+ return -EINVAL;
+
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS)
+ continue;
+
+ if (ctrl->value >= 0 && ctrl->value < MAX_PREEMPHASIS) {
+ struct poseidon *p = file->private_data;
+ int pre_emphasis = preemphasis[ctrl->value];
+ u32 status;
+
+ send_set_req(p, TUNER_AUD_ANA_STD,
+ pre_emphasis, &status);
+ p->radio_data.pre_emphasis = pre_emphasis;
+ }
+ }
+ return 0;
+}
+
+int tlg_fm_vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ return 0;
+}
+
+int tlg_fm_vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *ctrl)
+{
+ if (!(ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL))
+ return -EINVAL;
+
+ ctrl->id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
+ if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) {
+ /* return the next supported control */
+ ctrl->id = V4L2_CID_TUNE_PREEMPHASIS;
+ v4l2_ctrl_query_fill(ctrl, V4L2_PREEMPHASIS_DISABLED,
+ V4L2_PREEMPHASIS_75_uS, 1,
+ V4L2_PREEMPHASIS_50_uS);
+ ctrl->flags = V4L2_CTRL_FLAG_UPDATE;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+int tlg_fm_vidioc_querymenu(struct file *file, void *fh,
+ struct v4l2_querymenu *qmenu)
+{
+ return v4l2_ctrl_query_menu(qmenu, NULL, NULL);
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
+{
+ return vt->index > 0 ? -EINVAL : 0;
+}
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *va)
+{
+ return (va->index != 0) ? -EINVAL : 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ a->index = 0;
+ a->mode = 0;
+ a->capability = V4L2_AUDCAP_STEREO;
+ strcpy(a->name, "Radio");
+ return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, u32 i)
+{
+ return (i != 0) ? -EINVAL : 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, u32 *i)
+{
+ return (*i != 0) ? -EINVAL : 0;
+}
+
+static const struct v4l2_ioctl_ops poseidon_fm_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = tlg_fm_vidioc_queryctrl,
+ .vidioc_querymenu = tlg_fm_vidioc_querymenu,
+ .vidioc_g_ctrl = tlg_fm_vidioc_g_ctrl,
+ .vidioc_s_ctrl = tlg_fm_vidioc_s_ctrl,
+ .vidioc_s_ext_ctrls = tlg_fm_vidioc_s_exts_ctrl,
+ .vidioc_g_ext_ctrls = tlg_fm_vidioc_g_exts_ctrl,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_tuner = tlg_fm_vidioc_g_tuner,
+ .vidioc_g_frequency = fm_get_freq,
+ .vidioc_s_frequency = fm_set_freq,
+};
+
+static struct video_device poseidon_fm_template = {
+ .name = "Telegent-Radio",
+ .fops = &poseidon_fm_fops,
+ .minor = -1,
+ .release = video_device_release,
+ .ioctl_ops = &poseidon_fm_ioctl_ops,
+};
+
+int poseidon_fm_init(struct poseidon *p)
+{
+ struct video_device *fm_dev;
+
+ fm_dev = vdev_init(p, &poseidon_fm_template);
+ if (fm_dev == NULL)
+ return -1;
+
+ if (video_register_device(fm_dev, VFL_TYPE_RADIO, -1) < 0) {
+ video_device_release(fm_dev);
+ return -1;
+ }
+ p->radio_data.fm_dev = fm_dev;
+ return 0;
+}
+
+int poseidon_fm_exit(struct poseidon *p)
+{
+ destroy_video_device(&p->radio_data.fm_dev);
+ return 0;
+}
diff --git a/drivers/media/video/tlg2300/pd-video.c b/drivers/media/video/tlg2300/pd-video.c
new file mode 100644
index 000000000000..becfba6a3041
--- /dev/null
+++ b/drivers/media/video/tlg2300/pd-video.c
@@ -0,0 +1,1667 @@
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <linux/usb.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-dev.h>
+
+#include "pd-common.h"
+#include "vendorcmds.h"
+
+static int pm_video_suspend(struct poseidon *pd);
+static int pm_video_resume(struct poseidon *pd);
+static void iso_bubble_handler(struct work_struct *w);
+
+int usb_transfer_mode;
+module_param(usb_transfer_mode, int, 0644);
+MODULE_PARM_DESC(usb_transfer_mode, "0 = Bulk, 1 = Isochronous");
+
+static const struct poseidon_format poseidon_formats[] = {
+ { "YUV 422", V4L2_PIX_FMT_YUYV, 16, 0},
+ { "RGB565", V4L2_PIX_FMT_RGB565, 16, 0},
+};
+
+static const struct poseidon_tvnorm poseidon_tvnorms[] = {
+ { V4L2_STD_PAL_D, "PAL-D", TLG_TUNE_VSTD_PAL_D },
+ { V4L2_STD_PAL_B, "PAL-B", TLG_TUNE_VSTD_PAL_B },
+ { V4L2_STD_PAL_G, "PAL-G", TLG_TUNE_VSTD_PAL_G },
+ { V4L2_STD_PAL_H, "PAL-H", TLG_TUNE_VSTD_PAL_H },
+ { V4L2_STD_PAL_I, "PAL-I", TLG_TUNE_VSTD_PAL_I },
+ { V4L2_STD_PAL_M, "PAL-M", TLG_TUNE_VSTD_PAL_M },
+ { V4L2_STD_PAL_N, "PAL-N", TLG_TUNE_VSTD_PAL_N_COMBO },
+ { V4L2_STD_PAL_Nc, "PAL-Nc", TLG_TUNE_VSTD_PAL_N_COMBO },
+ { V4L2_STD_NTSC_M, "NTSC-M", TLG_TUNE_VSTD_NTSC_M },
+ { V4L2_STD_NTSC_M_JP, "NTSC-JP", TLG_TUNE_VSTD_NTSC_M_J },
+ { V4L2_STD_SECAM_B, "SECAM-B", TLG_TUNE_VSTD_SECAM_B },
+ { V4L2_STD_SECAM_D, "SECAM-D", TLG_TUNE_VSTD_SECAM_D },
+ { V4L2_STD_SECAM_G, "SECAM-G", TLG_TUNE_VSTD_SECAM_G },
+ { V4L2_STD_SECAM_H, "SECAM-H", TLG_TUNE_VSTD_SECAM_H },
+ { V4L2_STD_SECAM_K, "SECAM-K", TLG_TUNE_VSTD_SECAM_K },
+ { V4L2_STD_SECAM_K1, "SECAM-K1", TLG_TUNE_VSTD_SECAM_K1 },
+ { V4L2_STD_SECAM_L, "SECAM-L", TLG_TUNE_VSTD_SECAM_L },
+ { V4L2_STD_SECAM_LC, "SECAM-LC", TLG_TUNE_VSTD_SECAM_L1 },
+};
+static const unsigned int POSEIDON_TVNORMS = ARRAY_SIZE(poseidon_tvnorms);
+
+struct pd_audio_mode {
+ u32 tlg_audio_mode;
+ u32 v4l2_audio_sub;
+ u32 v4l2_audio_mode;
+};
+
+static const struct pd_audio_mode pd_audio_modes[] = {
+ { TLG_TUNE_TVAUDIO_MODE_MONO, V4L2_TUNER_SUB_MONO,
+ V4L2_TUNER_MODE_MONO },
+ { TLG_TUNE_TVAUDIO_MODE_STEREO, V4L2_TUNER_SUB_STEREO,
+ V4L2_TUNER_MODE_STEREO },
+ { TLG_TUNE_TVAUDIO_MODE_LANG_A, V4L2_TUNER_SUB_LANG1,
+ V4L2_TUNER_MODE_LANG1 },
+ { TLG_TUNE_TVAUDIO_MODE_LANG_B, V4L2_TUNER_SUB_LANG2,
+ V4L2_TUNER_MODE_LANG2 },
+ { TLG_TUNE_TVAUDIO_MODE_LANG_C, V4L2_TUNER_SUB_LANG1,
+ V4L2_TUNER_MODE_LANG1_LANG2 }
+};
+static const unsigned int POSEIDON_AUDIOMODS = ARRAY_SIZE(pd_audio_modes);
+
+struct pd_input {
+ char *name;
+ uint32_t tlg_src;
+};
+
+static const struct pd_input pd_inputs[] = {
+ { "TV Antenna", TLG_SIG_SRC_ANTENNA },
+ { "TV Cable", TLG_SIG_SRC_CABLE },
+ { "TV SVideo", TLG_SIG_SRC_SVIDEO },
+ { "TV Composite", TLG_SIG_SRC_COMPOSITE }
+};
+static const unsigned int POSEIDON_INPUTS = ARRAY_SIZE(pd_inputs);
+
+struct poseidon_control {
+ struct v4l2_queryctrl v4l2_ctrl;
+ enum cmd_custom_param_id vc_id;
+};
+
+static struct poseidon_control controls[] = {
+ {
+ { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
+ "brightness", 0, 10000, 1, 100, 0, },
+ CUST_PARM_ID_BRIGHTNESS_CTRL
+ }, {
+ { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
+ "contrast", 0, 10000, 1, 100, 0, },
+ CUST_PARM_ID_CONTRAST_CTRL,
+ }, {
+ { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
+ "hue", 0, 10000, 1, 100, 0, },
+ CUST_PARM_ID_HUE_CTRL,
+ }, {
+ { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
+ "saturation", 0, 10000, 1, 100, 0, },
+ CUST_PARM_ID_SATURATION_CTRL,
+ },
+};
+
+struct video_std_to_audio_std {
+ v4l2_std_id video_std;
+ int audio_std;
+};
+
+static const struct video_std_to_audio_std video_to_audio_map[] = {
+ /* country : { 27, 32, 33, 34, 36, 44, 45, 46, 47, 48, 64,
+ 65, 86, 351, 352, 353, 354, 358, 372, 852, 972 } */
+ { (V4L2_STD_PAL_I | V4L2_STD_PAL_B | V4L2_STD_PAL_D |
+ V4L2_STD_SECAM_L | V4L2_STD_SECAM_D), TLG_TUNE_ASTD_NICAM },
+
+ /* country : { 1, 52, 54, 55, 886 } */
+ {V4L2_STD_NTSC_M | V4L2_STD_PAL_N | V4L2_STD_PAL_M, TLG_TUNE_ASTD_BTSC},
+
+ /* country : { 81 } */
+ { V4L2_STD_NTSC_M_JP, TLG_TUNE_ASTD_EIAJ },
+
+ /* other country : TLG_TUNE_ASTD_A2 */
+};
+static const unsigned int map_size = ARRAY_SIZE(video_to_audio_map);
+
+static int get_audio_std(v4l2_std_id v4l2_std)
+{
+ int i = 0;
+
+ for (; i < map_size; i++) {
+ if (v4l2_std & video_to_audio_map[i].video_std)
+ return video_to_audio_map[i].audio_std;
+ }
+ return TLG_TUNE_ASTD_A2;
+}
+
+static int vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct front_face *front = fh;
+ struct poseidon *p = front->pd;
+
+ logs(front);
+
+ strcpy(cap->driver, "tele-video");
+ strcpy(cap->card, "Telegent Poseidon");
+ usb_make_path(p->udev, cap->bus_info, sizeof(cap->bus_info));
+ cap->version = KERNEL_VERSION(0, 0, 1);
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
+ V4L2_CAP_AUDIO | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
+ return 0;
+}
+
+/*====================================================================*/
+static void init_copy(struct video_data *video, bool index)
+{
+ struct front_face *front = video->front;
+
+ video->field_count = index;
+ video->lines_copied = 0;
+ video->prev_left = 0 ;
+ video->dst = (char *)videobuf_to_vmalloc(front->curr_frame)
+ + index * video->lines_size;
+ video->vbi->copied = 0; /* set it here */
+}
+
+static bool get_frame(struct front_face *front, int *need_init)
+{
+ struct videobuf_buffer *vb = front->curr_frame;
+
+ if (vb)
+ return true;
+
+ spin_lock(&front->queue_lock);
+ if (!list_empty(&front->active)) {
+ vb = list_entry(front->active.next,
+ struct videobuf_buffer, queue);
+ if (need_init)
+ *need_init = 1;
+ front->curr_frame = vb;
+ list_del_init(&vb->queue);
+ }
+ spin_unlock(&front->queue_lock);
+
+ return !!vb;
+}
+
+/* check if the video's buffer is ready */
+static bool get_video_frame(struct front_face *front, struct video_data *video)
+{
+ int need_init = 0;
+ bool ret = true;
+
+ ret = get_frame(front, &need_init);
+ if (ret && need_init)
+ init_copy(video, 0);
+ return ret;
+}
+
+static void submit_frame(struct front_face *front)
+{
+ struct videobuf_buffer *vb = front->curr_frame;
+
+ if (vb == NULL)
+ return;
+
+ front->curr_frame = NULL;
+ vb->state = VIDEOBUF_DONE;
+ vb->field_count++;
+ do_gettimeofday(&vb->ts);
+
+ wake_up(&vb->done);
+}
+
+/*
+ * A frame is composed of two fields. If we receive all the two fields,
+ * call the submit_frame() to submit the whole frame to applications.
+ */
+static void end_field(struct video_data *video)
+{
+ /* logs(video->front); */
+ if (1 == video->field_count)
+ submit_frame(video->front);
+ else
+ init_copy(video, 1);
+}
+
+static void copy_video_data(struct video_data *video, char *src,
+ unsigned int count)
+{
+#define copy_data(len) \
+ do { \
+ if (++video->lines_copied > video->lines_per_field) \
+ goto overflow; \
+ memcpy(video->dst, src, len);\
+ video->dst += len + video->lines_size; \
+ src += len; \
+ count -= len; \
+ } while (0)
+
+ while (count && count >= video->lines_size) {
+ if (video->prev_left) {
+ copy_data(video->prev_left);
+ video->prev_left = 0;
+ continue;
+ }
+ copy_data(video->lines_size);
+ }
+ if (count && count < video->lines_size) {
+ memcpy(video->dst, src, count);
+
+ video->prev_left = video->lines_size - count;
+ video->dst += count;
+ }
+ return;
+
+overflow:
+ end_field(video);
+}
+
+static void check_trailer(struct video_data *video, char *src, int count)
+{
+ struct vbi_data *vbi = video->vbi;
+ int offset; /* trailer's offset */
+ char *buf;
+
+ offset = (video->context.pix.sizeimage / 2 + vbi->vbi_size / 2)
+ - (vbi->copied + video->lines_size * video->lines_copied);
+ if (video->prev_left)
+ offset -= (video->lines_size - video->prev_left);
+
+ if (offset > count || offset <= 0)
+ goto short_package;
+
+ buf = src + offset;
+
+ /* trailer : (VFHS) + U32 + U32 + field_num */
+ if (!strncmp(buf, "VFHS", 4)) {
+ int field_num = *((u32 *)(buf + 12));
+
+ if ((field_num & 1) ^ video->field_count) {
+ init_copy(video, video->field_count);
+ return;
+ }
+ copy_video_data(video, src, offset);
+ }
+short_package:
+ end_field(video);
+}
+
+/* ========== Check this more carefully! =========== */
+static inline void copy_vbi_data(struct vbi_data *vbi,
+ char *src, unsigned int count)
+{
+ struct front_face *front = vbi->front;
+
+ if (front && get_frame(front, NULL)) {
+ char *buf = videobuf_to_vmalloc(front->curr_frame);
+
+ if (vbi->video->field_count)
+ buf += (vbi->vbi_size / 2);
+ memcpy(buf + vbi->copied, src, count);
+ }
+ vbi->copied += count;
+}
+
+/*
+ * Copy the normal data (VBI or VIDEO) without the trailer.
+ * VBI is not interlaced, while VIDEO is interlaced.
+ */
+static inline void copy_vbi_video_data(struct video_data *video,
+ char *src, unsigned int count)
+{
+ struct vbi_data *vbi = video->vbi;
+ unsigned int vbi_delta = (vbi->vbi_size / 2) - vbi->copied;
+
+ if (vbi_delta >= count) {
+ copy_vbi_data(vbi, src, count);
+ } else {
+ if (vbi_delta) {
+ copy_vbi_data(vbi, src, vbi_delta);
+
+ /* we receive the two fields of the VBI*/
+ if (vbi->front && video->field_count)
+ submit_frame(vbi->front);
+ }
+ copy_video_data(video, src + vbi_delta, count - vbi_delta);
+ }
+}
+
+static void urb_complete_bulk(struct urb *urb)
+{
+ struct front_face *front = urb->context;
+ struct video_data *video = &front->pd->video_data;
+ char *src = (char *)urb->transfer_buffer;
+ int count = urb->actual_length;
+ int ret = 0;
+
+ if (!video->is_streaming || urb->status) {
+ if (urb->status == -EPROTO)
+ goto resend_it;
+ return;
+ }
+ if (!get_video_frame(front, video))
+ goto resend_it;
+
+ if (count == urb->transfer_buffer_length)
+ copy_vbi_video_data(video, src, count);
+ else
+ check_trailer(video, src, count);
+
+resend_it:
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret)
+ log(" submit failed: error %d", ret);
+}
+
+/************************* for ISO *********************/
+#define GET_SUCCESS (0)
+#define GET_TRAILER (1)
+#define GET_TOO_MUCH_BUBBLE (2)
+#define GET_NONE (3)
+static int get_chunk(int start, struct urb *urb,
+ int *head, int *tail, int *bubble_err)
+{
+ struct usb_iso_packet_descriptor *pkt = NULL;
+ int ret = GET_SUCCESS;
+
+ for (*head = *tail = -1; start < urb->number_of_packets; start++) {
+ pkt = &urb->iso_frame_desc[start];
+
+ /* handle the bubble of the Hub */
+ if (-EOVERFLOW == pkt->status) {
+ if (++*bubble_err > urb->number_of_packets / 3)
+ return GET_TOO_MUCH_BUBBLE;
+ continue;
+ }
+
+ /* This is the gap */
+ if (pkt->status || pkt->actual_length <= 0
+ || pkt->actual_length > ISO_PKT_SIZE) {
+ if (*head != -1)
+ break;
+ continue;
+ }
+
+ /* a good isochronous packet */
+ if (pkt->actual_length == ISO_PKT_SIZE) {
+ if (*head == -1)
+ *head = start;
+ *tail = start;
+ continue;
+ }
+
+ /* trailer is here */
+ if (pkt->actual_length < ISO_PKT_SIZE) {
+ if (*head == -1) {
+ *head = start;
+ *tail = start;
+ return GET_TRAILER;
+ }
+ break;
+ }
+ }
+
+ if (*head == -1 && *tail == -1)
+ ret = GET_NONE;
+ return ret;
+}
+
+/*
+ * |__|------|___|-----|_______|
+ * ^ ^
+ * | |
+ * gap gap
+ */
+static void urb_complete_iso(struct urb *urb)
+{
+ struct front_face *front = urb->context;
+ struct video_data *video = &front->pd->video_data;
+ int bubble_err = 0, head = 0, tail = 0;
+ char *src = (char *)urb->transfer_buffer;
+ int ret = 0;
+
+ if (!video->is_streaming)
+ return;
+
+ do {
+ if (!get_video_frame(front, video))
+ goto out;
+
+ switch (get_chunk(head, urb, &head, &tail, &bubble_err)) {
+ case GET_SUCCESS:
+ copy_vbi_video_data(video, src + (head * ISO_PKT_SIZE),
+ (tail - head + 1) * ISO_PKT_SIZE);
+ break;
+ case GET_TRAILER:
+ check_trailer(video, src + (head * ISO_PKT_SIZE),
+ ISO_PKT_SIZE);
+ break;
+ case GET_NONE:
+ goto out;
+ case GET_TOO_MUCH_BUBBLE:
+ log("\t We got too much bubble");
+ schedule_work(&video->bubble_work);
+ return;
+ }
+ } while (head = tail + 1, head < urb->number_of_packets);
+
+out:
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret)
+ log("usb_submit_urb err : %d", ret);
+}
+/*============================= [ end ] =====================*/
+
+static int prepare_iso_urb(struct video_data *video)
+{
+ struct usb_device *udev = video->pd->udev;
+ int i;
+
+ if (video->urb_array[0])
+ return 0;
+
+ for (i = 0; i < SBUF_NUM; i++) {
+ struct urb *urb;
+ void *mem;
+ int j;
+
+ urb = usb_alloc_urb(PK_PER_URB, GFP_KERNEL);
+ if (urb == NULL)
+ goto out;
+
+ video->urb_array[i] = urb;
+ mem = usb_buffer_alloc(udev,
+ ISO_PKT_SIZE * PK_PER_URB,
+ GFP_KERNEL,
+ &urb->transfer_dma);
+
+ urb->complete = urb_complete_iso; /* handler */
+ urb->dev = udev;
+ urb->context = video->front;
+ urb->pipe = usb_rcvisocpipe(udev,
+ video->endpoint_addr);
+ urb->interval = 1;
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ urb->number_of_packets = PK_PER_URB;
+ urb->transfer_buffer = mem;
+ urb->transfer_buffer_length = PK_PER_URB * ISO_PKT_SIZE;
+
+ for (j = 0; j < PK_PER_URB; j++) {
+ urb->iso_frame_desc[j].offset = ISO_PKT_SIZE * j;
+ urb->iso_frame_desc[j].length = ISO_PKT_SIZE;
+ }
+ }
+ return 0;
+out:
+ for (; i > 0; i--)
+ ;
+ return -ENOMEM;
+}
+
+/* return the succeeded number of the allocation */
+int alloc_bulk_urbs_generic(struct urb **urb_array, int num,
+ struct usb_device *udev, u8 ep_addr,
+ int buf_size, gfp_t gfp_flags,
+ usb_complete_t complete_fn, void *context)
+{
+ struct urb *urb;
+ void *mem;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ urb = usb_alloc_urb(0, gfp_flags);
+ if (urb == NULL)
+ return i;
+
+ mem = usb_buffer_alloc(udev, buf_size, gfp_flags,
+ &urb->transfer_dma);
+ if (mem == NULL)
+ return i;
+
+ usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, ep_addr),
+ mem, buf_size, complete_fn, context);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ urb_array[i] = urb;
+ }
+ return i;
+}
+
+void free_all_urb_generic(struct urb **urb_array, int num)
+{
+ int i;
+ struct urb *urb;
+
+ for (i = 0; i < num; i++) {
+ urb = urb_array[i];
+ if (urb) {
+ usb_buffer_free(urb->dev,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer,
+ urb->transfer_dma);
+ usb_free_urb(urb);
+ urb_array[i] = NULL;
+ }
+ }
+}
+
+static int prepare_bulk_urb(struct video_data *video)
+{
+ if (video->urb_array[0])
+ return 0;
+
+ alloc_bulk_urbs_generic(video->urb_array, SBUF_NUM,
+ video->pd->udev, video->endpoint_addr,
+ 0x2000, GFP_KERNEL,
+ urb_complete_bulk, video->front);
+ return 0;
+}
+
+/* free the URBs */
+static void free_all_urb(struct video_data *video)
+{
+ free_all_urb_generic(video->urb_array, SBUF_NUM);
+}
+
+static void pd_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ videobuf_vmalloc_free(vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static void pd_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ struct front_face *front = q->priv_data;
+ vb->state = VIDEOBUF_QUEUED;
+ list_add_tail(&vb->queue, &front->active);
+}
+
+static int pd_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct front_face *front = q->priv_data;
+ int rc;
+
+ switch (front->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (VIDEOBUF_NEEDS_INIT == vb->state) {
+ struct v4l2_pix_format *pix;
+
+ pix = &front->pd->video_data.context.pix;
+ vb->size = pix->sizeimage; /* real frame size */
+ vb->width = pix->width;
+ vb->height = pix->height;
+ rc = videobuf_iolock(q, vb, NULL);
+ if (rc < 0)
+ return rc;
+ }
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (VIDEOBUF_NEEDS_INIT == vb->state) {
+ vb->size = front->pd->vbi_data.vbi_size;
+ rc = videobuf_iolock(q, vb, NULL);
+ if (rc < 0)
+ return rc;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ vb->field = field;
+ vb->state = VIDEOBUF_PREPARED;
+ return 0;
+}
+
+int fire_all_urb(struct video_data *video)
+{
+ int i, ret;
+
+ video->is_streaming = 1;
+
+ for (i = 0; i < SBUF_NUM; i++) {
+ ret = usb_submit_urb(video->urb_array[i], GFP_KERNEL);
+ if (ret)
+ log("(%d) failed: error %d", i, ret);
+ }
+ return ret;
+}
+
+static int start_video_stream(struct poseidon *pd)
+{
+ struct video_data *video = &pd->video_data;
+ s32 cmd_status;
+
+ send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
+ send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_START, &cmd_status);
+
+ if (pd->cur_transfer_mode) {
+ prepare_iso_urb(video);
+ INIT_WORK(&video->bubble_work, iso_bubble_handler);
+ } else {
+ /* The bulk mode does not need a bubble handler */
+ prepare_bulk_urb(video);
+ }
+ fire_all_urb(video);
+ return 0;
+}
+
+static int pd_buf_setup(struct videobuf_queue *q, unsigned int *count,
+ unsigned int *size)
+{
+ struct front_face *front = q->priv_data;
+ struct poseidon *pd = front->pd;
+
+ switch (front->type) {
+ default:
+ return -EINVAL;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ struct video_data *video = &pd->video_data;
+ struct v4l2_pix_format *pix = &video->context.pix;
+
+ *size = PAGE_ALIGN(pix->sizeimage);/* page aligned frame size */
+ if (*count < 4)
+ *count = 4;
+ if (1) {
+ /* same in different altersetting */
+ video->endpoint_addr = 0x82;
+ video->vbi = &pd->vbi_data;
+ video->vbi->video = video;
+ video->pd = pd;
+ video->lines_per_field = pix->height / 2;
+ video->lines_size = pix->width * 2;
+ video->front = front;
+ }
+ return start_video_stream(pd);
+ }
+
+ case V4L2_BUF_TYPE_VBI_CAPTURE: {
+ struct vbi_data *vbi = &pd->vbi_data;
+
+ *size = PAGE_ALIGN(vbi->vbi_size);
+ log("size : %d", *size);
+ if (*count == 0)
+ *count = 4;
+ }
+ break;
+ }
+ return 0;
+}
+
+static struct videobuf_queue_ops pd_video_qops = {
+ .buf_setup = pd_buf_setup,
+ .buf_prepare = pd_buf_prepare,
+ .buf_queue = pd_buf_queue,
+ .buf_release = pd_buf_release,
+};
+
+static int vidioc_enum_fmt(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ if (ARRAY_SIZE(poseidon_formats) <= f->index)
+ return -EINVAL;
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->flags = 0;
+ f->pixelformat = poseidon_formats[f->index].fourcc;
+ strcpy(f->description, poseidon_formats[f->index].name);
+ return 0;
+}
+
+static int vidioc_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct front_face *front = fh;
+ struct poseidon *pd = front->pd;
+
+ logs(front);
+ f->fmt.pix = pd->video_data.context.pix;
+ return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ return 0;
+}
+
+/*
+ * VLC calls VIDIOC_S_STD before VIDIOC_S_FMT, while
+ * Mplayer calls them in the reverse order.
+ */
+static int pd_vidioc_s_fmt(struct poseidon *pd, struct v4l2_pix_format *pix)
+{
+ struct video_data *video = &pd->video_data;
+ struct running_context *context = &video->context;
+ struct v4l2_pix_format *pix_def = &context->pix;
+ s32 ret = 0, cmd_status = 0, vid_resol;
+
+ /* set the pixel format to firmware */
+ if (pix->pixelformat == V4L2_PIX_FMT_RGB565) {
+ vid_resol = TLG_TUNER_VID_FORMAT_RGB_565;
+ } else {
+ pix->pixelformat = V4L2_PIX_FMT_YUYV;
+ vid_resol = TLG_TUNER_VID_FORMAT_YUV;
+ }
+ ret = send_set_req(pd, VIDEO_STREAM_FMT_SEL,
+ vid_resol, &cmd_status);
+
+ /* set the resolution to firmware */
+ vid_resol = TLG_TUNE_VID_RES_720;
+ switch (pix->width) {
+ case 704:
+ vid_resol = TLG_TUNE_VID_RES_704;
+ break;
+ default:
+ pix->width = 720;
+ case 720:
+ break;
+ }
+ ret |= send_set_req(pd, VIDEO_ROSOLU_SEL,
+ vid_resol, &cmd_status);
+ if (ret || cmd_status) {
+ mutex_unlock(&pd->lock);
+ return -EBUSY;
+ }
+
+ pix_def->pixelformat = pix->pixelformat; /* save it */
+ pix->height = (context->tvnormid & V4L2_STD_525_60) ? 480 : 576;
+
+ /* Compare with the default setting */
+ if ((pix_def->width != pix->width)
+ || (pix_def->height != pix->height)) {
+ pix_def->width = pix->width;
+ pix_def->height = pix->height;
+ pix_def->bytesperline = pix->width * 2;
+ pix_def->sizeimage = pix->width * pix->height * 2;
+ }
+ *pix = *pix_def;
+
+ return 0;
+}
+
+static int vidioc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct front_face *front = fh;
+ struct poseidon *pd = front->pd;
+
+ logs(front);
+ /* stop VBI here */
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)
+ return -EINVAL;
+
+ mutex_lock(&pd->lock);
+ if (pd->file_for_stream == NULL)
+ pd->file_for_stream = file;
+ else if (file != pd->file_for_stream) {
+ mutex_unlock(&pd->lock);
+ return -EINVAL;
+ }
+
+ pd_vidioc_s_fmt(pd, &f->fmt.pix);
+ mutex_unlock(&pd->lock);
+ return 0;
+}
+
+static int vidioc_g_fmt_vbi(struct file *file, void *fh,
+ struct v4l2_format *v4l2_f)
+{
+ struct front_face *front = fh;
+ struct poseidon *pd = front->pd;
+ struct v4l2_vbi_format *vbi_fmt = &v4l2_f->fmt.vbi;
+
+ vbi_fmt->samples_per_line = 720 * 2;
+ vbi_fmt->sampling_rate = 6750000 * 4;
+ vbi_fmt->sample_format = V4L2_PIX_FMT_GREY;
+ vbi_fmt->offset = 64 * 4; /*FIXME: why offset */
+ if (pd->video_data.context.tvnormid & V4L2_STD_525_60) {
+ vbi_fmt->start[0] = 10;
+ vbi_fmt->start[1] = 264;
+ vbi_fmt->count[0] = V4L_NTSC_VBI_LINES;
+ vbi_fmt->count[1] = V4L_NTSC_VBI_LINES;
+ } else {
+ vbi_fmt->start[0] = 6;
+ vbi_fmt->start[1] = 314;
+ vbi_fmt->count[0] = V4L_PAL_VBI_LINES;
+ vbi_fmt->count[1] = V4L_PAL_VBI_LINES;
+ }
+ vbi_fmt->flags = V4L2_VBI_UNSYNC;
+ logs(front);
+ return 0;
+}
+
+static int set_std(struct poseidon *pd, v4l2_std_id *norm)
+{
+ struct video_data *video = &pd->video_data;
+ struct vbi_data *vbi = &pd->vbi_data;
+ struct running_context *context;
+ struct v4l2_pix_format *pix;
+ s32 i, ret = 0, cmd_status, param;
+ int height;
+
+ for (i = 0; i < POSEIDON_TVNORMS; i++) {
+ if (*norm & poseidon_tvnorms[i].v4l2_id) {
+ param = poseidon_tvnorms[i].tlg_tvnorm;
+ log("name : %s", poseidon_tvnorms[i].name);
+ goto found;
+ }
+ }
+ return -EINVAL;
+found:
+ mutex_lock(&pd->lock);
+ ret = send_set_req(pd, VIDEO_STD_SEL, param, &cmd_status);
+ if (ret || cmd_status)
+ goto out;
+
+ /* Set vbi size and check the height of the frame */
+ context = &video->context;
+ context->tvnormid = poseidon_tvnorms[i].v4l2_id;
+ if (context->tvnormid & V4L2_STD_525_60) {
+ vbi->vbi_size = V4L_NTSC_VBI_FRAMESIZE;
+ height = 480;
+ } else {
+ vbi->vbi_size = V4L_PAL_VBI_FRAMESIZE;
+ height = 576;
+ }
+
+ pix = &context->pix;
+ if (pix->height != height) {
+ pix->height = height;
+ pix->sizeimage = pix->width * pix->height * 2;
+ }
+
+out:
+ mutex_unlock(&pd->lock);
+ return ret;
+}
+
+int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+ struct front_face *front = fh;
+ logs(front);
+ return set_std(front->pd, norm);
+}
+
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in)
+{
+ struct front_face *front = fh;
+
+ if (in->index < 0 || in->index >= POSEIDON_INPUTS)
+ return -EINVAL;
+ strcpy(in->name, pd_inputs[in->index].name);
+ in->type = V4L2_INPUT_TYPE_TUNER;
+
+ /*
+ * the audio input index mixed with this video input,
+ * Poseidon only have one audio/video, set to "0"
+ */
+ in->audioset = 0;
+ in->tuner = 0;
+ in->std = V4L2_STD_ALL;
+ in->status = 0;
+ logs(front);
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ struct front_face *front = fh;
+ struct poseidon *pd = front->pd;
+ struct running_context *context = &pd->video_data.context;
+
+ logs(front);
+ *i = context->sig_index;
+ return 0;
+}
+
+/* We can support several inputs */
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+ struct front_face *front = fh;
+ struct poseidon *pd = front->pd;
+ s32 ret, cmd_status;
+
+ if (i < 0 || i >= POSEIDON_INPUTS)
+ return -EINVAL;
+ ret = send_set_req(pd, SGNL_SRC_SEL,
+ pd_inputs[i].tlg_src, &cmd_status);
+ if (ret)
+ return ret;
+
+ pd->video_data.context.sig_index = i;
+ return 0;
+}
+
+static struct poseidon_control *check_control_id(__u32 id)
+{
+ struct poseidon_control *control = &controls[0];
+ int array_size = ARRAY_SIZE(controls);
+
+ for (; control < &controls[array_size]; control++)
+ if (control->v4l2_ctrl.id == id)
+ return control;
+ return NULL;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *a)
+{
+ struct poseidon_control *control = NULL;
+
+ control = check_control_id(a->id);
+ if (!control)
+ return -EINVAL;
+
+ *a = control->v4l2_ctrl;
+ return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
+{
+ struct front_face *front = fh;
+ struct poseidon *pd = front->pd;
+ struct poseidon_control *control = NULL;
+ struct tuner_custom_parameter_s tuner_param;
+ s32 ret = 0, cmd_status;
+
+ control = check_control_id(ctrl->id);
+ if (!control)
+ return -EINVAL;
+
+ mutex_lock(&pd->lock);
+ ret = send_get_req(pd, TUNER_CUSTOM_PARAMETER, control->vc_id,
+ &tuner_param, &cmd_status, sizeof(tuner_param));
+ mutex_unlock(&pd->lock);
+
+ if (ret || cmd_status)
+ return -1;
+
+ ctrl->value = tuner_param.param_value;
+ return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+ struct tuner_custom_parameter_s param = {0};
+ struct poseidon_control *control = NULL;
+ struct front_face *front = fh;
+ struct poseidon *pd = front->pd;
+ s32 ret = 0, cmd_status, params;
+
+ control = check_control_id(a->id);
+ if (!control)
+ return -EINVAL;
+
+ param.param_value = a->value;
+ param.param_id = control->vc_id;
+ params = *(s32 *)&param; /* temp code */
+
+ mutex_lock(&pd->lock);
+ ret = send_set_req(pd, TUNER_CUSTOM_PARAMETER, params, &cmd_status);
+ ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
+ mutex_unlock(&pd->lock);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ/4);
+ return ret;
+}
+
+/* Audio ioctls */
+static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+ if (0 != a->index)
+ return -EINVAL;
+ a->capability = V4L2_AUDCAP_STEREO;
+ strcpy(a->name, "USB audio in");
+ /*Poseidon have no AVL function.*/
+ a->mode = 0;
+ return 0;
+}
+
+int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+ a->index = 0;
+ a->capability = V4L2_AUDCAP_STEREO;
+ strcpy(a->name, "USB audio in");
+ a->mode = 0;
+ return 0;
+}
+
+int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+ return (0 == a->index) ? 0 : -EINVAL;
+}
+
+/* Tuner ioctls */
+static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *tuner)
+{
+ struct front_face *front = fh;
+ struct poseidon *pd = front->pd;
+ struct tuner_atv_sig_stat_s atv_stat;
+ s32 count = 5, ret, cmd_status;
+ int index;
+
+ if (0 != tuner->index)
+ return -EINVAL;
+
+ mutex_lock(&pd->lock);
+ ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_ANALOG_TV,
+ &atv_stat, &cmd_status, sizeof(atv_stat));
+
+ while (atv_stat.sig_lock_busy && count-- && !ret) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ);
+
+ ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_ANALOG_TV,
+ &atv_stat, &cmd_status, sizeof(atv_stat));
+ }
+ mutex_unlock(&pd->lock);
+
+ if (debug_mode)
+ log("P:%d,S:%d", atv_stat.sig_present, atv_stat.sig_strength);
+
+ if (ret || cmd_status)
+ tuner->signal = 0;
+ else if (atv_stat.sig_present && !atv_stat.sig_strength)
+ tuner->signal = 0xFFFF;
+ else
+ tuner->signal = (atv_stat.sig_strength * 255 / 10) << 8;
+
+ strcpy(tuner->name, "Telegent Systems");
+ tuner->type = V4L2_TUNER_ANALOG_TV;
+ tuner->rangelow = TUNER_FREQ_MIN / 62500;
+ tuner->rangehigh = TUNER_FREQ_MAX / 62500;
+ tuner->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+ index = pd->video_data.context.audio_idx;
+ tuner->rxsubchans = pd_audio_modes[index].v4l2_audio_sub;
+ tuner->audmode = pd_audio_modes[index].v4l2_audio_mode;
+ tuner->afc = 0;
+ logs(front);
+ return 0;
+}
+
+static int pd_vidioc_s_tuner(struct poseidon *pd, int index)
+{
+ s32 ret = 0, cmd_status, param, audiomode;
+
+ mutex_lock(&pd->lock);
+ param = pd_audio_modes[index].tlg_audio_mode;
+ ret = send_set_req(pd, TUNER_AUD_MODE, param, &cmd_status);
+ audiomode = get_audio_std(pd->video_data.context.tvnormid);
+ ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode,
+ &cmd_status);
+ if (!ret)
+ pd->video_data.context.audio_idx = index;
+ mutex_unlock(&pd->lock);
+ return ret;
+}
+
+static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *a)
+{
+ struct front_face *front = fh;
+ struct poseidon *pd = front->pd;
+ int index;
+
+ if (0 != a->index)
+ return -EINVAL;
+ logs(front);
+ for (index = 0; index < POSEIDON_AUDIOMODS; index++)
+ if (a->audmode == pd_audio_modes[index].v4l2_audio_mode)
+ return pd_vidioc_s_tuner(pd, index);
+ return -EINVAL;
+}
+
+static int vidioc_g_frequency(struct file *file, void *fh,
+ struct v4l2_frequency *freq)
+{
+ struct front_face *front = fh;
+ struct poseidon *pd = front->pd;
+ struct running_context *context = &pd->video_data.context;
+
+ if (0 != freq->tuner)
+ return -EINVAL;
+ freq->frequency = context->freq;
+ freq->type = V4L2_TUNER_ANALOG_TV;
+ return 0;
+}
+
+static int set_frequency(struct poseidon *pd, __u32 frequency)
+{
+ s32 ret = 0, param, cmd_status;
+ struct running_context *context = &pd->video_data.context;
+
+ param = frequency * 62500 / 1000;
+ if (param < TUNER_FREQ_MIN/1000 || param > TUNER_FREQ_MAX / 1000)
+ return -EINVAL;
+
+ mutex_lock(&pd->lock);
+ ret = send_set_req(pd, TUNE_FREQ_SELECT, param, &cmd_status);
+ ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
+
+ msleep(250); /* wait for a while until the hardware is ready. */
+ context->freq = frequency;
+ mutex_unlock(&pd->lock);
+ return ret;
+}
+
+static int vidioc_s_frequency(struct file *file, void *fh,
+ struct v4l2_frequency *freq)
+{
+ struct front_face *front = fh;
+ struct poseidon *pd = front->pd;
+
+ logs(front);
+#ifdef CONFIG_PM
+ pd->pm_suspend = pm_video_suspend;
+ pd->pm_resume = pm_video_resume;
+#endif
+ return set_frequency(pd, freq->frequency);
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *b)
+{
+ struct front_face *front = file->private_data;
+ logs(front);
+ return videobuf_reqbufs(&front->q, b);
+}
+
+static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct front_face *front = file->private_data;
+ logs(front);
+ return videobuf_querybuf(&front->q, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct front_face *front = file->private_data;
+ return videobuf_qbuf(&front->q, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct front_face *front = file->private_data;
+ return videobuf_dqbuf(&front->q, b, file->f_flags & O_NONBLOCK);
+}
+
+/* Just stop the URBs, do not free the URBs */
+int usb_transfer_stop(struct video_data *video)
+{
+ if (video->is_streaming) {
+ int i;
+ s32 cmd_status;
+ struct poseidon *pd = video->pd;
+
+ video->is_streaming = 0;
+ for (i = 0; i < SBUF_NUM; ++i) {
+ if (video->urb_array[i])
+ usb_kill_urb(video->urb_array[i]);
+ }
+
+ send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP,
+ &cmd_status);
+ }
+ return 0;
+}
+
+int stop_all_video_stream(struct poseidon *pd)
+{
+ struct video_data *video = &pd->video_data;
+ struct vbi_data *vbi = &pd->vbi_data;
+
+ mutex_lock(&pd->lock);
+ if (video->is_streaming) {
+ struct front_face *front = video->front;
+
+ /* stop the URBs */
+ usb_transfer_stop(video);
+ free_all_urb(video);
+
+ /* stop the host side of VIDEO */
+ videobuf_stop(&front->q);
+ videobuf_mmap_free(&front->q);
+
+ /* stop the host side of VBI */
+ front = vbi->front;
+ if (front) {
+ videobuf_stop(&front->q);
+ videobuf_mmap_free(&front->q);
+ }
+ }
+ mutex_unlock(&pd->lock);
+ return 0;
+}
+
+/*
+ * The bubbles can seriously damage the video's quality,
+ * though it occurs in very rare situation.
+ */
+static void iso_bubble_handler(struct work_struct *w)
+{
+ struct video_data *video;
+ struct poseidon *pd;
+
+ video = container_of(w, struct video_data, bubble_work);
+ pd = video->pd;
+
+ mutex_lock(&pd->lock);
+ usb_transfer_stop(video);
+ msleep(500);
+ start_video_stream(pd);
+ mutex_unlock(&pd->lock);
+}
+
+
+static int vidioc_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct front_face *front = fh;
+
+ logs(front);
+ if (unlikely(type != front->type))
+ return -EINVAL;
+ return videobuf_streamon(&front->q);
+}
+
+static int vidioc_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct front_face *front = file->private_data;
+
+ logs(front);
+ if (unlikely(type != front->type))
+ return -EINVAL;
+ return videobuf_streamoff(&front->q);
+}
+
+/* Set the firmware's default values : need altersetting */
+static int pd_video_checkmode(struct poseidon *pd)
+{
+ s32 ret = 0, cmd_status, audiomode;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ/2);
+
+ /* choose the altersetting */
+ ret = usb_set_interface(pd->udev, 0,
+ (pd->cur_transfer_mode ?
+ ISO_3K_BULK_ALTERNATE_IFACE :
+ BULK_ALTERNATE_IFACE));
+ if (ret < 0)
+ goto error;
+
+ /* set default parameters for PAL-D , with the VBI enabled*/
+ ret = set_tuner_mode(pd, TLG_MODE_ANALOG_TV);
+ ret |= send_set_req(pd, SGNL_SRC_SEL,
+ TLG_SIG_SRC_ANTENNA, &cmd_status);
+ ret |= send_set_req(pd, VIDEO_STD_SEL,
+ TLG_TUNE_VSTD_PAL_D, &cmd_status);
+ ret |= send_set_req(pd, VIDEO_STREAM_FMT_SEL,
+ TLG_TUNER_VID_FORMAT_YUV, &cmd_status);
+ ret |= send_set_req(pd, VIDEO_ROSOLU_SEL,
+ TLG_TUNE_VID_RES_720, &cmd_status);
+ ret |= send_set_req(pd, TUNE_FREQ_SELECT, TUNER_FREQ_MIN, &cmd_status);
+ ret |= send_set_req(pd, VBI_DATA_SEL, 1, &cmd_status);/* enable vbi */
+
+ /* set the audio */
+ audiomode = get_audio_std(pd->video_data.context.tvnormid);
+ ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode, &cmd_status);
+ ret |= send_set_req(pd, TUNER_AUD_MODE,
+ TLG_TUNE_TVAUDIO_MODE_STEREO, &cmd_status);
+ ret |= send_set_req(pd, AUDIO_SAMPLE_RATE_SEL,
+ ATV_AUDIO_RATE_48K, &cmd_status);
+error:
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int pm_video_suspend(struct poseidon *pd)
+{
+ /* stop audio */
+ pm_alsa_suspend(pd);
+
+ /* stop and free all the URBs */
+ usb_transfer_stop(&pd->video_data);
+ free_all_urb(&pd->video_data);
+
+ /* reset the interface */
+ usb_set_interface(pd->udev, 0, 0);
+ msleep(300);
+ return 0;
+}
+
+static int restore_v4l2_context(struct poseidon *pd,
+ struct running_context *context)
+{
+ struct front_face *front = pd->video_data.front;
+
+ pd_video_checkmode(pd);
+
+ set_std(pd, &context->tvnormid);
+ vidioc_s_input(NULL, front, context->sig_index);
+ pd_vidioc_s_tuner(pd, context->audio_idx);
+ pd_vidioc_s_fmt(pd, &context->pix);
+ set_frequency(pd, context->freq);
+ return 0;
+}
+
+static int pm_video_resume(struct poseidon *pd)
+{
+ struct video_data *video = &pd->video_data;
+
+ /* resume the video */
+ /* [1] restore the origin V4L2 parameters */
+ restore_v4l2_context(pd, &video->context);
+
+ /* [2] initiate video copy variables */
+ if (video->front->curr_frame)
+ init_copy(video, 0);
+
+ /* [3] fire urbs */
+ start_video_stream(pd);
+
+ /* resume the audio */
+ pm_alsa_resume(pd);
+ return 0;
+}
+#endif
+
+void set_debug_mode(struct video_device *vfd, int debug_mode)
+{
+ vfd->debug = 0;
+ if (debug_mode & 0x1)
+ vfd->debug = V4L2_DEBUG_IOCTL;
+ if (debug_mode & 0x2)
+ vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
+}
+
+static void init_video_context(struct running_context *context)
+{
+ context->sig_index = 0;
+ context->audio_idx = 1; /* stereo */
+ context->tvnormid = V4L2_STD_PAL_D;
+ context->pix = (struct v4l2_pix_format) {
+ .width = 720,
+ .height = 576,
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .field = V4L2_FIELD_INTERLACED,
+ .bytesperline = 720 * 2,
+ .sizeimage = 720 * 576 * 2,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ .priv = 0
+ };
+}
+
+static int pd_video_open(struct file *file)
+{
+ struct video_device *vfd = video_devdata(file);
+ struct poseidon *pd = video_get_drvdata(vfd);
+ struct front_face *front = NULL;
+ int ret = -ENOMEM;
+
+ mutex_lock(&pd->lock);
+ usb_autopm_get_interface(pd->interface);
+
+ if (vfd->vfl_type == VFL_TYPE_GRABBER
+ && !(pd->state & POSEIDON_STATE_ANALOG)) {
+ front = kzalloc(sizeof(struct front_face), GFP_KERNEL);
+ if (!front)
+ goto out;
+
+ pd->cur_transfer_mode = usb_transfer_mode;/* bulk or iso */
+ init_video_context(&pd->video_data.context);
+
+ ret = pd_video_checkmode(pd);
+ if (ret < 0) {
+ kfree(front);
+ ret = -1;
+ goto out;
+ }
+
+ pd->state |= POSEIDON_STATE_ANALOG;
+ front->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ pd->video_data.users++;
+ set_debug_mode(vfd, debug_mode);
+
+ videobuf_queue_vmalloc_init(&front->q, &pd_video_qops,
+ NULL, &front->queue_lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,/* video is interlacd */
+ sizeof(struct videobuf_buffer),/*it's enough*/
+ front);
+ } else if (vfd->vfl_type == VFL_TYPE_VBI
+ && !(pd->state & POSEIDON_STATE_VBI)) {
+ front = kzalloc(sizeof(struct front_face), GFP_KERNEL);
+ if (!front)
+ goto out;
+
+ pd->state |= POSEIDON_STATE_VBI;
+ front->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ pd->vbi_data.front = front;
+ pd->vbi_data.users++;
+
+ videobuf_queue_vmalloc_init(&front->q, &pd_video_qops,
+ NULL, &front->queue_lock,
+ V4L2_BUF_TYPE_VBI_CAPTURE,
+ V4L2_FIELD_NONE, /* vbi is NONE mode */
+ sizeof(struct videobuf_buffer),
+ front);
+ } else {
+ /* maybe add FM support here */
+ log("other ");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ front->pd = pd;
+ front->curr_frame = NULL;
+ INIT_LIST_HEAD(&front->active);
+ spin_lock_init(&front->queue_lock);
+
+ file->private_data = front;
+ kref_get(&pd->kref);
+
+ mutex_unlock(&pd->lock);
+ return 0;
+out:
+ usb_autopm_put_interface(pd->interface);
+ mutex_unlock(&pd->lock);
+ return ret;
+}
+
+static int pd_video_release(struct file *file)
+{
+ struct front_face *front = file->private_data;
+ struct poseidon *pd = front->pd;
+ s32 cmd_status = 0;
+
+ logs(front);
+ mutex_lock(&pd->lock);
+
+ if (front->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ pd->state &= ~POSEIDON_STATE_ANALOG;
+
+ /* stop the device, and free the URBs */
+ usb_transfer_stop(&pd->video_data);
+ free_all_urb(&pd->video_data);
+
+ /* stop the firmware */
+ send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP,
+ &cmd_status);
+
+ pd->file_for_stream = NULL;
+ pd->video_data.users--;
+ } else if (front->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ pd->state &= ~POSEIDON_STATE_VBI;
+ pd->vbi_data.front = NULL;
+ pd->vbi_data.users--;
+ }
+ videobuf_stop(&front->q);
+ videobuf_mmap_free(&front->q);
+
+ usb_autopm_put_interface(pd->interface);
+ mutex_unlock(&pd->lock);
+
+ kfree(front);
+ file->private_data = NULL;
+ kref_put(&pd->kref, poseidon_delete);
+ return 0;
+}
+
+static int pd_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct front_face *front = file->private_data;
+ return videobuf_mmap_mapper(&front->q, vma);
+}
+
+unsigned int pd_video_poll(struct file *file, poll_table *table)
+{
+ struct front_face *front = file->private_data;
+ return videobuf_poll_stream(file, &front->q, table);
+}
+
+ssize_t pd_video_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct front_face *front = file->private_data;
+ return videobuf_read_stream(&front->q, buffer, count, ppos,
+ 0, file->f_flags & O_NONBLOCK);
+}
+
+/* This struct works for both VIDEO and VBI */
+static const struct v4l2_file_operations pd_video_fops = {
+ .owner = THIS_MODULE,
+ .open = pd_video_open,
+ .release = pd_video_release,
+ .read = pd_video_read,
+ .poll = pd_video_poll,
+ .mmap = pd_video_mmap,
+ .ioctl = video_ioctl2, /* maybe changed in future */
+};
+
+static const struct v4l2_ioctl_ops pd_video_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+
+ /* Video format */
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt,
+ .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi, /* VBI */
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt,
+
+ /* Input */
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_enum_input = vidioc_enum_input,
+
+ /* Audio ioctls */
+ .vidioc_enumaudio = vidioc_enumaudio,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+
+ /* Tuner ioctls */
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+
+ /* Buffer handlers */
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+
+ /* Stream on/off */
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+
+ /* Control handling */
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+};
+
+static struct video_device pd_video_template = {
+ .name = "Telegent-Video",
+ .fops = &pd_video_fops,
+ .minor = -1,
+ .release = video_device_release,
+ .tvnorms = V4L2_STD_ALL,
+ .ioctl_ops = &pd_video_ioctl_ops,
+};
+
+struct video_device *vdev_init(struct poseidon *pd, struct video_device *tmp)
+{
+ struct video_device *vfd;
+
+ vfd = video_device_alloc();
+ if (vfd == NULL)
+ return NULL;
+ *vfd = *tmp;
+ vfd->minor = -1;
+ vfd->v4l2_dev = &pd->v4l2_dev;
+ /*vfd->parent = &(pd->udev->dev); */
+ vfd->release = video_device_release;
+ video_set_drvdata(vfd, pd);
+ return vfd;
+}
+
+void destroy_video_device(struct video_device **v_dev)
+{
+ struct video_device *dev = *v_dev;
+
+ if (dev == NULL)
+ return;
+
+ if (video_is_registered(dev))
+ video_unregister_device(dev);
+ else
+ video_device_release(dev);
+ *v_dev = NULL;
+}
+
+void pd_video_exit(struct poseidon *pd)
+{
+ struct video_data *video = &pd->video_data;
+ struct vbi_data *vbi = &pd->vbi_data;
+
+ destroy_video_device(&video->v_dev);
+ destroy_video_device(&vbi->v_dev);
+ log();
+}
+
+int pd_video_init(struct poseidon *pd)
+{
+ struct video_data *video = &pd->video_data;
+ struct vbi_data *vbi = &pd->vbi_data;
+ int ret = -ENOMEM;
+
+ video->v_dev = vdev_init(pd, &pd_video_template);
+ if (video->v_dev == NULL)
+ goto out;
+
+ ret = video_register_device(video->v_dev, VFL_TYPE_GRABBER, -1);
+ if (ret != 0)
+ goto out;
+
+ /* VBI uses the same template as video */
+ vbi->v_dev = vdev_init(pd, &pd_video_template);
+ if (vbi->v_dev == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = video_register_device(vbi->v_dev, VFL_TYPE_VBI, -1);
+ if (ret != 0)
+ goto out;
+ log("register VIDEO/VBI devices");
+ return 0;
+out:
+ log("VIDEO/VBI devices register failed, : %d", ret);
+ pd_video_exit(pd);
+ return ret;
+}
+
diff --git a/drivers/media/video/tlg2300/vendorcmds.h b/drivers/media/video/tlg2300/vendorcmds.h
new file mode 100644
index 000000000000..ba6f4ae3b2c2
--- /dev/null
+++ b/drivers/media/video/tlg2300/vendorcmds.h
@@ -0,0 +1,243 @@
+#ifndef VENDOR_CMD_H_
+#define VENDOR_CMD_H_
+
+#define BULK_ALTERNATE_IFACE (2)
+#define ISO_3K_BULK_ALTERNATE_IFACE (1)
+#define REQ_SET_CMD (0X00)
+#define REQ_GET_CMD (0X80)
+
+enum tlg__analog_audio_standard {
+ TLG_TUNE_ASTD_NONE = 0x00000000,
+ TLG_TUNE_ASTD_A2 = 0x00000001,
+ TLG_TUNE_ASTD_NICAM = 0x00000002,
+ TLG_TUNE_ASTD_EIAJ = 0x00000004,
+ TLG_TUNE_ASTD_BTSC = 0x00000008,
+ TLG_TUNE_ASTD_FM_US = 0x00000010,
+ TLG_TUNE_ASTD_FM_EUR = 0x00000020,
+ TLG_TUNE_ASTD_ALL = 0x0000003f
+};
+
+/*
+ * identifiers for Custom Parameter messages.
+ * @typedef cmd_custom_param_id_t
+ */
+enum cmd_custom_param_id {
+ CUST_PARM_ID_NONE = 0x00,
+ CUST_PARM_ID_BRIGHTNESS_CTRL = 0x01,
+ CUST_PARM_ID_CONTRAST_CTRL = 0x02,
+ CUST_PARM_ID_HUE_CTRL = 0x03,
+ CUST_PARM_ID_SATURATION_CTRL = 0x04,
+ CUST_PARM_ID_AUDIO_SNR_THRESHOLD = 0x10,
+ CUST_PARM_ID_AUDIO_AGC_THRESHOLD = 0x11,
+ CUST_PARM_ID_MAX
+};
+
+struct tuner_custom_parameter_s {
+ uint16_t param_id; /* Parameter identifier */
+ uint16_t param_value; /* Parameter value */
+};
+
+struct tuner_ber_rate_s {
+ uint32_t ber_rate; /* BER sample rate in seconds */
+};
+
+struct tuner_atv_sig_stat_s {
+ uint32_t sig_present;
+ uint32_t sig_locked;
+ uint32_t sig_lock_busy;
+ uint32_t sig_strength; /* milliDb */
+ uint32_t tv_audio_chan; /* mono/stereo/sap*/
+ uint32_t mvision_stat; /* macrovision status */
+};
+
+struct tuner_dtv_sig_stat_s {
+ uint32_t sig_present; /* Boolean*/
+ uint32_t sig_locked; /* Boolean */
+ uint32_t sig_lock_busy; /* Boolean (Can this time-out?) */
+ uint32_t sig_strength; /* milliDb*/
+};
+
+struct tuner_fm_sig_stat_s {
+ uint32_t sig_present; /* Boolean*/
+ uint32_t sig_locked; /* Boolean */
+ uint32_t sig_lock_busy; /* Boolean */
+ uint32_t sig_stereo_mono;/* TBD*/
+ uint32_t sig_strength; /* milliDb*/
+};
+
+enum _tag_tlg_tune_srv_cmd {
+ TLG_TUNE_PLAY_SVC_START = 1,
+ TLG_TUNE_PLAY_SVC_STOP
+};
+
+enum _tag_tune_atv_audio_mode_caps {
+ TLG_TUNE_TVAUDIO_MODE_MONO = 0x00000001,
+ TLG_TUNE_TVAUDIO_MODE_STEREO = 0x00000002,
+ TLG_TUNE_TVAUDIO_MODE_LANG_A = 0x00000010,/* Primary language*/
+ TLG_TUNE_TVAUDIO_MODE_LANG_B = 0x00000020,/* 2nd avail language*/
+ TLG_TUNE_TVAUDIO_MODE_LANG_C = 0x00000040
+};
+
+
+enum _tag_tuner_atv_audio_rates {
+ ATV_AUDIO_RATE_NONE = 0x00,/* Audio not supported*/
+ ATV_AUDIO_RATE_32K = 0x01,/* Audio rate = 32 KHz*/
+ ATV_AUDIO_RATE_48K = 0x02, /* Audio rate = 48 KHz*/
+ ATV_AUDIO_RATE_31_25K = 0x04 /* Audio rate = 31.25KHz */
+};
+
+enum _tag_tune_atv_vid_res_caps {
+ TLG_TUNE_VID_RES_NONE = 0x00000000,
+ TLG_TUNE_VID_RES_720 = 0x00000001,
+ TLG_TUNE_VID_RES_704 = 0x00000002,
+ TLG_TUNE_VID_RES_360 = 0x00000004
+};
+
+enum _tag_tuner_analog_video_format {
+ TLG_TUNER_VID_FORMAT_YUV = 0x00000001,
+ TLG_TUNER_VID_FORMAT_YCRCB = 0x00000002,
+ TLG_TUNER_VID_FORMAT_RGB_565 = 0x00000004,
+};
+
+enum tlg_ext_audio_support {
+ TLG_EXT_AUDIO_NONE = 0x00,/* No external audio input supported */
+ TLG_EXT_AUDIO_LR = 0x01/* LR external audio inputs supported*/
+};
+
+enum {
+ TLG_MODE_NONE = 0x00, /* No Mode specified*/
+ TLG_MODE_ANALOG_TV = 0x01, /* Analog Television mode*/
+ TLG_MODE_ANALOG_TV_UNCOMP = 0x01, /* Analog Television mode*/
+ TLG_MODE_ANALOG_TV_COMP = 0x02, /* Analog TV mode (compressed)*/
+ TLG_MODE_FM_RADIO = 0x04, /* FM Radio mode*/
+ TLG_MODE_DVB_T = 0x08, /* Digital TV (DVB-T)*/
+};
+
+enum tlg_signal_sources_t {
+ TLG_SIG_SRC_NONE = 0x00,/* Signal source not specified */
+ TLG_SIG_SRC_ANTENNA = 0x01,/* Signal src is: Antenna */
+ TLG_SIG_SRC_CABLE = 0x02,/* Signal src is: Coax Cable*/
+ TLG_SIG_SRC_SVIDEO = 0x04,/* Signal src is: S_VIDEO */
+ TLG_SIG_SRC_COMPOSITE = 0x08 /* Signal src is: Composite Video */
+};
+
+enum tuner_analog_video_standard {
+ TLG_TUNE_VSTD_NONE = 0x00000000,
+ TLG_TUNE_VSTD_NTSC_M = 0x00000001,
+ TLG_TUNE_VSTD_NTSC_M_J = 0x00000002,/* Japan */
+ TLG_TUNE_VSTD_PAL_B = 0x00000010,
+ TLG_TUNE_VSTD_PAL_D = 0x00000020,
+ TLG_TUNE_VSTD_PAL_G = 0x00000040,
+ TLG_TUNE_VSTD_PAL_H = 0x00000080,
+ TLG_TUNE_VSTD_PAL_I = 0x00000100,
+ TLG_TUNE_VSTD_PAL_M = 0x00000200,
+ TLG_TUNE_VSTD_PAL_N = 0x00000400,
+ TLG_TUNE_VSTD_SECAM_B = 0x00001000,
+ TLG_TUNE_VSTD_SECAM_D = 0x00002000,
+ TLG_TUNE_VSTD_SECAM_G = 0x00004000,
+ TLG_TUNE_VSTD_SECAM_H = 0x00008000,
+ TLG_TUNE_VSTD_SECAM_K = 0x00010000,
+ TLG_TUNE_VSTD_SECAM_K1 = 0x00020000,
+ TLG_TUNE_VSTD_SECAM_L = 0x00040000,
+ TLG_TUNE_VSTD_SECAM_L1 = 0x00080000,
+ TLG_TUNE_VSTD_PAL_N_COMBO = 0x00100000
+};
+
+enum tlg_mode_caps {
+ TLG_MODE_CAPS_NONE = 0x00, /* No Mode specified */
+ TLG_MODE_CAPS_ANALOG_TV_UNCOMP = 0x01, /* Analog TV mode */
+ TLG_MODE_CAPS_ANALOG_TV_COMP = 0x02, /* Analog TV (compressed)*/
+ TLG_MODE_CAPS_FM_RADIO = 0x04, /* FM Radio mode */
+ TLG_MODE_CAPS_DVB_T = 0x08, /* Digital TV (DVB-T) */
+};
+
+enum poseidon_vendor_cmds {
+ LAST_CMD_STAT = 0x00,
+ GET_CHIP_ID = 0x01,
+ GET_FW_ID = 0x02,
+ PRODUCT_CAPS = 0x03,
+
+ TUNE_MODE_CAP_ATV = 0x10,
+ TUNE_MODE_CAP_ATVCOMP = 0X10,
+ TUNE_MODE_CAP_DVBT = 0x10,
+ TUNE_MODE_CAP_FM = 0x10,
+ TUNE_MODE_SELECT = 0x11,
+ TUNE_FREQ_SELECT = 0x12,
+ SGNL_SRC_SEL = 0x13,
+
+ VIDEO_STD_SEL = 0x14,
+ VIDEO_STREAM_FMT_SEL = 0x15,
+ VIDEO_ROSOLU_AVAIL = 0x16,
+ VIDEO_ROSOLU_SEL = 0x17,
+ VIDEO_CONT_PROTECT = 0x20,
+
+ VCR_TIMING_MODSEL = 0x21,
+ EXT_AUDIO_CAP = 0x22,
+ EXT_AUDIO_SEL = 0x23,
+ TEST_PATTERN_SEL = 0x24,
+ VBI_DATA_SEL = 0x25,
+ AUDIO_SAMPLE_RATE_CAP = 0x28,
+ AUDIO_SAMPLE_RATE_SEL = 0x29,
+ TUNER_AUD_MODE = 0x2a,
+ TUNER_AUD_MODE_AVAIL = 0x2b,
+ TUNER_AUD_ANA_STD = 0x2c,
+ TUNER_CUSTOM_PARAMETER = 0x2f,
+
+ DVBT_TUNE_MODE_SEL = 0x30,
+ DVBT_BANDW_CAP = 0x31,
+ DVBT_BANDW_SEL = 0x32,
+ DVBT_GUARD_INTERV_CAP = 0x33,
+ DVBT_GUARD_INTERV_SEL = 0x34,
+ DVBT_MODULATION_CAP = 0x35,
+ DVBT_MODULATION_SEL = 0x36,
+ DVBT_INNER_FEC_RATE_CAP = 0x37,
+ DVBT_INNER_FEC_RATE_SEL = 0x38,
+ DVBT_TRANS_MODE_CAP = 0x39,
+ DVBT_TRANS_MODE_SEL = 0x3a,
+ DVBT_SEARCH_RANG = 0x3c,
+
+ TUNER_SETUP_ANALOG = 0x40,
+ TUNER_SETUP_DIGITAL = 0x41,
+ TUNER_SETUP_FM_RADIO = 0x42,
+ TAKE_REQUEST = 0x43, /* Take effect of the command */
+ PLAY_SERVICE = 0x44, /* Play start or Play stop */
+ TUNER_STATUS = 0x45,
+ TUNE_PROP_DVBT = 0x46,
+ ERR_RATE_STATS = 0x47,
+ TUNER_BER_RATE = 0x48,
+
+ SCAN_CAPS = 0x50,
+ SCAN_SETUP = 0x51,
+ SCAN_SERVICE = 0x52,
+ SCAN_STATS = 0x53,
+
+ PID_SET = 0x58,
+ PID_UNSET = 0x59,
+ PID_LIST = 0x5a,
+
+ IRD_CAP = 0x60,
+ IRD_MODE_SEL = 0x61,
+ IRD_SETUP = 0x62,
+
+ PTM_MODE_CAP = 0x70,
+ PTM_MODE_SEL = 0x71,
+ PTM_SERVICE = 0x72,
+ TUNER_REG_SCRIPT = 0x73,
+ CMD_CHIP_RST = 0x74,
+};
+
+enum tlg_bw {
+ TLG_BW_5 = 5,
+ TLG_BW_6 = 6,
+ TLG_BW_7 = 7,
+ TLG_BW_8 = 8,
+ TLG_BW_12 = 12,
+ TLG_BW_15 = 15
+};
+
+struct cmd_firmware_vers_s {
+ uint8_t fw_rev_major;
+ uint8_t fw_rev_minor;
+ uint16_t fw_patch;
+};
+#endif /* VENDOR_CMD_H_ */
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 5b3eaa16afd2..c4dab6cfd948 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -1078,6 +1078,7 @@ static int tuner_probe(struct i2c_client *client,
goto register_client;
}
+ kfree(t);
return -ENODEV;
case 0x42:
case 0x43:
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index d533ea57e7b1..0a877497b93f 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -680,10 +680,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n",
tvee->model, tvee->rev_str, tvee->serial_number);
if (tvee->has_MAC_address == 1)
- tveeprom_info("MAC address is %02X-%02X-%02X-%02X-%02X-%02X\n",
- tvee->MAC_address[0], tvee->MAC_address[1],
- tvee->MAC_address[2], tvee->MAC_address[3],
- tvee->MAC_address[4], tvee->MAC_address[5]);
+ tveeprom_info("MAC address is %pM\n", tvee->MAC_address);
tveeprom_info("tuner model is %s (idx %d, type %d)\n",
t_name1, tuner1, tvee->tuner_type);
tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c
new file mode 100644
index 000000000000..5a878bca02d4
--- /dev/null
+++ b/drivers/media/video/tvp7002.c
@@ -0,0 +1,1187 @@
+/* Texas Instruments Triple 8-/10-BIT 165-/110-MSPS Video and Graphics
+ * Digitizer with Horizontal PLL registers
+ *
+ * Copyright (C) 2009 Texas Instruments Inc
+ * Author: Santiago Nunez-Corrales <santiago.nunez@ridgerun.com>
+ *
+ * This code is partially based upon the TVP5150 driver
+ * written by Mauro Carvalho Chehab (mchehab@infradead.org),
+ * the TVP514x driver written by Vaibhav Hiremath <hvaibhav@ti.com>
+ * and the TVP7002 driver in the TI LSP 2.10.00.14. Revisions by
+ * Muralidharan Karicheri and Snehaprabha Narnakaje (TI).
+ *
+ * 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/tvp7002.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include "tvp7002_reg.h"
+
+MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer driver");
+MODULE_AUTHOR("Santiago Nunez-Corrales <santiago.nunez@ridgerun.com>");
+MODULE_LICENSE("GPL");
+
+/* Module Name */
+#define TVP7002_MODULE_NAME "tvp7002"
+
+/* I2C retry attempts */
+#define I2C_RETRY_COUNT (5)
+
+/* End of registers */
+#define TVP7002_EOR 0x5c
+
+/* Read write definition for registers */
+#define TVP7002_READ 0
+#define TVP7002_WRITE 1
+#define TVP7002_RESERVED 2
+
+/* Interlaced vs progressive mask and shift */
+#define TVP7002_IP_SHIFT 5
+#define TVP7002_INPR_MASK (0x01 << TVP7002_IP_SHIFT)
+
+/* Shift for CPL and LPF registers */
+#define TVP7002_CL_SHIFT 8
+#define TVP7002_CL_MASK 0x0f
+
+/* Debug functions */
+static int debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+/* Structure for register values */
+struct i2c_reg_value {
+ u8 reg;
+ u8 value;
+ u8 type;
+};
+
+/*
+ * Register default values (according to tvp7002 datasheet)
+ * In the case of read-only registers, the value (0xff) is
+ * never written. R/W functionality is controlled by the
+ * writable bit in the register struct definition.
+ */
+static const struct i2c_reg_value tvp7002_init_default[] = {
+ { TVP7002_CHIP_REV, 0xff, TVP7002_READ },
+ { TVP7002_HPLL_FDBK_DIV_MSBS, 0x67, TVP7002_WRITE },
+ { TVP7002_HPLL_FDBK_DIV_LSBS, 0x20, TVP7002_WRITE },
+ { TVP7002_HPLL_CRTL, 0xa0, TVP7002_WRITE },
+ { TVP7002_HPLL_PHASE_SEL, 0x80, TVP7002_WRITE },
+ { TVP7002_CLAMP_START, 0x32, TVP7002_WRITE },
+ { TVP7002_CLAMP_W, 0x20, TVP7002_WRITE },
+ { TVP7002_HSYNC_OUT_W, 0x60, TVP7002_WRITE },
+ { TVP7002_B_FINE_GAIN, 0x00, TVP7002_WRITE },
+ { TVP7002_G_FINE_GAIN, 0x00, TVP7002_WRITE },
+ { TVP7002_R_FINE_GAIN, 0x00, TVP7002_WRITE },
+ { TVP7002_B_FINE_OFF_MSBS, 0x80, TVP7002_WRITE },
+ { TVP7002_G_FINE_OFF_MSBS, 0x80, TVP7002_WRITE },
+ { TVP7002_R_FINE_OFF_MSBS, 0x80, TVP7002_WRITE },
+ { TVP7002_SYNC_CTL_1, 0x20, TVP7002_WRITE },
+ { TVP7002_HPLL_AND_CLAMP_CTL, 0x2e, TVP7002_WRITE },
+ { TVP7002_SYNC_ON_G_THRS, 0x5d, TVP7002_WRITE },
+ { TVP7002_SYNC_SEPARATOR_THRS, 0x47, TVP7002_WRITE },
+ { TVP7002_HPLL_PRE_COAST, 0x00, TVP7002_WRITE },
+ { TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE },
+ { TVP7002_SYNC_DETECT_STAT, 0xff, TVP7002_READ },
+ { TVP7002_OUT_FORMATTER, 0x47, TVP7002_WRITE },
+ { TVP7002_MISC_CTL_1, 0x01, TVP7002_WRITE },
+ { TVP7002_MISC_CTL_2, 0x00, TVP7002_WRITE },
+ { TVP7002_MISC_CTL_3, 0x01, TVP7002_WRITE },
+ { TVP7002_IN_MUX_SEL_1, 0x00, TVP7002_WRITE },
+ { TVP7002_IN_MUX_SEL_2, 0x67, TVP7002_WRITE },
+ { TVP7002_B_AND_G_COARSE_GAIN, 0x77, TVP7002_WRITE },
+ { TVP7002_R_COARSE_GAIN, 0x07, TVP7002_WRITE },
+ { TVP7002_FINE_OFF_LSBS, 0x00, TVP7002_WRITE },
+ { TVP7002_B_COARSE_OFF, 0x10, TVP7002_WRITE },
+ { TVP7002_G_COARSE_OFF, 0x10, TVP7002_WRITE },
+ { TVP7002_R_COARSE_OFF, 0x10, TVP7002_WRITE },
+ { TVP7002_HSOUT_OUT_START, 0x08, TVP7002_WRITE },
+ { TVP7002_MISC_CTL_4, 0x00, TVP7002_WRITE },
+ { TVP7002_B_DGTL_ALC_OUT_LSBS, 0xff, TVP7002_READ },
+ { TVP7002_G_DGTL_ALC_OUT_LSBS, 0xff, TVP7002_READ },
+ { TVP7002_R_DGTL_ALC_OUT_LSBS, 0xff, TVP7002_READ },
+ { TVP7002_AUTO_LVL_CTL_ENABLE, 0x80, TVP7002_WRITE },
+ { TVP7002_DGTL_ALC_OUT_MSBS, 0xff, TVP7002_READ },
+ { TVP7002_AUTO_LVL_CTL_FILTER, 0x53, TVP7002_WRITE },
+ { 0x29, 0x08, TVP7002_RESERVED },
+ { TVP7002_FINE_CLAMP_CTL, 0x07, TVP7002_WRITE },
+ /* PWR_CTL is controlled only by the probe and reset functions */
+ { TVP7002_PWR_CTL, 0x00, TVP7002_RESERVED },
+ { TVP7002_ADC_SETUP, 0x50, TVP7002_WRITE },
+ { TVP7002_COARSE_CLAMP_CTL, 0x00, TVP7002_WRITE },
+ { TVP7002_SOG_CLAMP, 0x80, TVP7002_WRITE },
+ { TVP7002_RGB_COARSE_CLAMP_CTL, 0x00, TVP7002_WRITE },
+ { TVP7002_SOG_COARSE_CLAMP_CTL, 0x04, TVP7002_WRITE },
+ { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
+ { 0x32, 0x18, TVP7002_RESERVED },
+ { 0x33, 0x60, TVP7002_RESERVED },
+ { TVP7002_MVIS_STRIPPER_W, 0xff, TVP7002_RESERVED },
+ { TVP7002_VSYNC_ALGN, 0x10, TVP7002_WRITE },
+ { TVP7002_SYNC_BYPASS, 0x00, TVP7002_WRITE },
+ { TVP7002_L_FRAME_STAT_LSBS, 0xff, TVP7002_READ },
+ { TVP7002_L_FRAME_STAT_MSBS, 0xff, TVP7002_READ },
+ { TVP7002_CLK_L_STAT_LSBS, 0xff, TVP7002_READ },
+ { TVP7002_CLK_L_STAT_MSBS, 0xff, TVP7002_READ },
+ { TVP7002_HSYNC_W, 0xff, TVP7002_READ },
+ { TVP7002_VSYNC_W, 0xff, TVP7002_READ },
+ { TVP7002_L_LENGTH_TOL, 0x03, TVP7002_WRITE },
+ { 0x3e, 0x60, TVP7002_RESERVED },
+ { TVP7002_VIDEO_BWTH_CTL, 0x01, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_LSBS, 0x01, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_MSBS, 0x2c, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_LSBS, 0x06, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_MSBS, 0x2c, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_START_L_OFF, 0x05, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_START_L_OFF, 0x00, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_DURATION, 0x1e, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_DURATION, 0x00, TVP7002_WRITE },
+ { TVP7002_FBIT_F_0_START_L_OFF, 0x00, TVP7002_WRITE },
+ { TVP7002_FBIT_F_1_START_L_OFF, 0x00, TVP7002_WRITE },
+ { TVP7002_YUV_Y_G_COEF_LSBS, 0xe3, TVP7002_WRITE },
+ { TVP7002_YUV_Y_G_COEF_MSBS, 0x16, TVP7002_WRITE },
+ { TVP7002_YUV_Y_B_COEF_LSBS, 0x4f, TVP7002_WRITE },
+ { TVP7002_YUV_Y_B_COEF_MSBS, 0x02, TVP7002_WRITE },
+ { TVP7002_YUV_Y_R_COEF_LSBS, 0xce, TVP7002_WRITE },
+ { TVP7002_YUV_Y_R_COEF_MSBS, 0x06, TVP7002_WRITE },
+ { TVP7002_YUV_U_G_COEF_LSBS, 0xab, TVP7002_WRITE },
+ { TVP7002_YUV_U_G_COEF_MSBS, 0xf3, TVP7002_WRITE },
+ { TVP7002_YUV_U_B_COEF_LSBS, 0x00, TVP7002_WRITE },
+ { TVP7002_YUV_U_B_COEF_MSBS, 0x10, TVP7002_WRITE },
+ { TVP7002_YUV_U_R_COEF_LSBS, 0x55, TVP7002_WRITE },
+ { TVP7002_YUV_U_R_COEF_MSBS, 0xfc, TVP7002_WRITE },
+ { TVP7002_YUV_V_G_COEF_LSBS, 0x78, TVP7002_WRITE },
+ { TVP7002_YUV_V_G_COEF_MSBS, 0xf1, TVP7002_WRITE },
+ { TVP7002_YUV_V_B_COEF_LSBS, 0x88, TVP7002_WRITE },
+ { TVP7002_YUV_V_B_COEF_MSBS, 0xfe, TVP7002_WRITE },
+ { TVP7002_YUV_V_R_COEF_LSBS, 0x00, TVP7002_WRITE },
+ { TVP7002_YUV_V_R_COEF_MSBS, 0x10, TVP7002_WRITE },
+ /* This signals end of register values */
+ { TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 480P */
+static const struct i2c_reg_value tvp7002_parms_480P[] = {
+ { TVP7002_HPLL_FDBK_DIV_MSBS, 0x35, TVP7002_WRITE },
+ { TVP7002_HPLL_FDBK_DIV_LSBS, 0x0a, TVP7002_WRITE },
+ { TVP7002_HPLL_CRTL, 0x02, TVP7002_WRITE },
+ { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_LSBS, 0x91, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_MSBS, 0x00, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_LSBS, 0x0B, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_MSBS, 0x00, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_START_L_OFF, 0x03, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_START_L_OFF, 0x01, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_DURATION, 0x13, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_DURATION, 0x13, TVP7002_WRITE },
+ { TVP7002_ALC_PLACEMENT, 0x18, TVP7002_WRITE },
+ { TVP7002_CLAMP_START, 0x06, TVP7002_WRITE },
+ { TVP7002_CLAMP_W, 0x10, TVP7002_WRITE },
+ { TVP7002_HPLL_PRE_COAST, 0x03, TVP7002_WRITE },
+ { TVP7002_HPLL_POST_COAST, 0x03, TVP7002_WRITE },
+ { TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 576P */
+static const struct i2c_reg_value tvp7002_parms_576P[] = {
+ { TVP7002_HPLL_FDBK_DIV_MSBS, 0x36, TVP7002_WRITE },
+ { TVP7002_HPLL_FDBK_DIV_LSBS, 0x00, TVP7002_WRITE },
+ { TVP7002_HPLL_CRTL, 0x18, TVP7002_WRITE },
+ { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_LSBS, 0x9B, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_MSBS, 0x00, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_LSBS, 0x0F, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_MSBS, 0x00, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_START_L_OFF, 0x00, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_START_L_OFF, 0x00, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_DURATION, 0x2D, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_DURATION, 0x00, TVP7002_WRITE },
+ { TVP7002_ALC_PLACEMENT, 0x18, TVP7002_WRITE },
+ { TVP7002_CLAMP_START, 0x06, TVP7002_WRITE },
+ { TVP7002_CLAMP_W, 0x10, TVP7002_WRITE },
+ { TVP7002_HPLL_PRE_COAST, 0x03, TVP7002_WRITE },
+ { TVP7002_HPLL_POST_COAST, 0x03, TVP7002_WRITE },
+ { TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 1080I60 */
+static const struct i2c_reg_value tvp7002_parms_1080I60[] = {
+ { TVP7002_HPLL_FDBK_DIV_MSBS, 0x89, TVP7002_WRITE },
+ { TVP7002_HPLL_FDBK_DIV_LSBS, 0x08, TVP7002_WRITE },
+ { TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE },
+ { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_MSBS, 0x08, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_START_L_OFF, 0x02, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_START_L_OFF, 0x02, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_DURATION, 0x16, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_DURATION, 0x17, TVP7002_WRITE },
+ { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
+ { TVP7002_CLAMP_START, 0x32, TVP7002_WRITE },
+ { TVP7002_CLAMP_W, 0x20, TVP7002_WRITE },
+ { TVP7002_HPLL_PRE_COAST, 0x01, TVP7002_WRITE },
+ { TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE },
+ { TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 1080P60 */
+static const struct i2c_reg_value tvp7002_parms_1080P60[] = {
+ { TVP7002_HPLL_FDBK_DIV_MSBS, 0x89, TVP7002_WRITE },
+ { TVP7002_HPLL_FDBK_DIV_LSBS, 0x08, TVP7002_WRITE },
+ { TVP7002_HPLL_CRTL, 0xE0, TVP7002_WRITE },
+ { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_MSBS, 0x08, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_START_L_OFF, 0x02, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_START_L_OFF, 0x02, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_DURATION, 0x16, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_DURATION, 0x17, TVP7002_WRITE },
+ { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
+ { TVP7002_CLAMP_START, 0x32, TVP7002_WRITE },
+ { TVP7002_CLAMP_W, 0x20, TVP7002_WRITE },
+ { TVP7002_HPLL_PRE_COAST, 0x01, TVP7002_WRITE },
+ { TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE },
+ { TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 1080I50 */
+static const struct i2c_reg_value tvp7002_parms_1080I50[] = {
+ { TVP7002_HPLL_FDBK_DIV_MSBS, 0xa5, TVP7002_WRITE },
+ { TVP7002_HPLL_FDBK_DIV_LSBS, 0x00, TVP7002_WRITE },
+ { TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE },
+ { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_MSBS, 0x08, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_START_L_OFF, 0x02, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_START_L_OFF, 0x02, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_DURATION, 0x16, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_DURATION, 0x17, TVP7002_WRITE },
+ { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
+ { TVP7002_CLAMP_START, 0x32, TVP7002_WRITE },
+ { TVP7002_CLAMP_W, 0x20, TVP7002_WRITE },
+ { TVP7002_HPLL_PRE_COAST, 0x01, TVP7002_WRITE },
+ { TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE },
+ { TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 720P60 */
+static const struct i2c_reg_value tvp7002_parms_720P60[] = {
+ { TVP7002_HPLL_FDBK_DIV_MSBS, 0x67, TVP7002_WRITE },
+ { TVP7002_HPLL_FDBK_DIV_LSBS, 0x02, TVP7002_WRITE },
+ { TVP7002_HPLL_CRTL, 0xa0, TVP7002_WRITE },
+ { TVP7002_HPLL_PHASE_SEL, 0x16, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_LSBS, 0x47, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_LSBS, 0x4B, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_MSBS, 0x06, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_START_L_OFF, 0x05, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_START_L_OFF, 0x00, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_DURATION, 0x2D, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_DURATION, 0x00, TVP7002_WRITE },
+ { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
+ { TVP7002_CLAMP_START, 0x32, TVP7002_WRITE },
+ { TVP7002_CLAMP_W, 0x20, TVP7002_WRITE },
+ { TVP7002_HPLL_PRE_COAST, 0x00, TVP7002_WRITE },
+ { TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE },
+ { TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Register parameters for 720P50 */
+static const struct i2c_reg_value tvp7002_parms_720P50[] = {
+ { TVP7002_HPLL_FDBK_DIV_MSBS, 0x7b, TVP7002_WRITE },
+ { TVP7002_HPLL_FDBK_DIV_LSBS, 0x0c, TVP7002_WRITE },
+ { TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE },
+ { TVP7002_HPLL_PHASE_SEL, 0x16, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_LSBS, 0x47, TVP7002_WRITE },
+ { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_LSBS, 0x4B, TVP7002_WRITE },
+ { TVP7002_AVID_STOP_PIXEL_MSBS, 0x06, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_START_L_OFF, 0x05, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_START_L_OFF, 0x00, TVP7002_WRITE },
+ { TVP7002_VBLK_F_0_DURATION, 0x2D, TVP7002_WRITE },
+ { TVP7002_VBLK_F_1_DURATION, 0x00, TVP7002_WRITE },
+ { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
+ { TVP7002_CLAMP_START, 0x32, TVP7002_WRITE },
+ { TVP7002_CLAMP_W, 0x20, TVP7002_WRITE },
+ { TVP7002_HPLL_PRE_COAST, 0x01, TVP7002_WRITE },
+ { TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE },
+ { TVP7002_EOR, 0xff, TVP7002_RESERVED }
+};
+
+/* Struct list for available formats */
+static const struct v4l2_fmtdesc tvp7002_fmt_list[] = {
+ {
+ .index = 0,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .flags = 0,
+ .description = "8-bit UYVY 4:2:2 Format",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(tvp7002_fmt_list)
+
+/* Preset definition for handling device operation */
+struct tvp7002_preset_definition {
+ u32 preset;
+ const struct i2c_reg_value *p_settings;
+ enum v4l2_colorspace color_space;
+ enum v4l2_field scanmode;
+ u16 progressive;
+ u16 lines_per_frame;
+ u16 cpl_min;
+ u16 cpl_max;
+};
+
+/* Struct list for digital video presets */
+static const struct tvp7002_preset_definition tvp7002_presets[] = {
+ {
+ V4L2_DV_720P60,
+ tvp7002_parms_720P60,
+ V4L2_COLORSPACE_REC709,
+ V4L2_FIELD_NONE,
+ 1,
+ 0x2EE,
+ 135,
+ 153
+ },
+ {
+ V4L2_DV_1080I60,
+ tvp7002_parms_1080I60,
+ V4L2_COLORSPACE_REC709,
+ V4L2_FIELD_INTERLACED,
+ 0,
+ 0x465,
+ 181,
+ 205
+ },
+ {
+ V4L2_DV_1080I50,
+ tvp7002_parms_1080I50,
+ V4L2_COLORSPACE_REC709,
+ V4L2_FIELD_INTERLACED,
+ 0,
+ 0x465,
+ 217,
+ 245
+ },
+ {
+ V4L2_DV_720P50,
+ tvp7002_parms_720P50,
+ V4L2_COLORSPACE_REC709,
+ V4L2_FIELD_NONE,
+ 1,
+ 0x2EE,
+ 163,
+ 183
+ },
+ {
+ V4L2_DV_1080P60,
+ tvp7002_parms_1080P60,
+ V4L2_COLORSPACE_REC709,
+ V4L2_FIELD_NONE,
+ 1,
+ 0x465,
+ 90,
+ 102
+ },
+ {
+ V4L2_DV_480P59_94,
+ tvp7002_parms_480P,
+ V4L2_COLORSPACE_SMPTE170M,
+ V4L2_FIELD_NONE,
+ 1,
+ 0x20D,
+ 0xffff,
+ 0xffff
+ },
+ {
+ V4L2_DV_576P50,
+ tvp7002_parms_576P,
+ V4L2_COLORSPACE_SMPTE170M,
+ V4L2_FIELD_NONE,
+ 1,
+ 0x271,
+ 0xffff,
+ 0xffff
+ }
+};
+
+#define NUM_PRESETS ARRAY_SIZE(tvp7002_presets)
+
+/* Device definition */
+struct tvp7002 {
+ struct v4l2_subdev sd;
+ const struct tvp7002_config *pdata;
+
+ int ver;
+ int streaming;
+
+ struct v4l2_pix_format pix;
+ const struct tvp7002_preset_definition *current_preset;
+ u8 gain;
+};
+
+/*
+ * to_tvp7002 - Obtain device handler TVP7002
+ * @sd: ptr to v4l2_subdev struct
+ *
+ * Returns device handler tvp7002.
+ */
+static inline struct tvp7002 *to_tvp7002(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct tvp7002, sd);
+}
+
+/*
+ * tvp7002_read - Read a value from a register in an TVP7002
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: TVP7002 register address
+ * @dst: pointer to 8-bit destination
+ *
+ * Returns value read if successful, or non-zero (-1) otherwise.
+ */
+static int tvp7002_read(struct v4l2_subdev *sd, u8 addr, u8 *dst)
+{
+ struct i2c_client *c = v4l2_get_subdevdata(sd);
+ int retry;
+ int error;
+
+ for (retry = 0; retry < I2C_RETRY_COUNT; retry++) {
+ error = i2c_smbus_read_byte_data(c, addr);
+
+ if (error >= 0) {
+ *dst = (u8)error;
+ return 0;
+ }
+
+ msleep_interruptible(10);
+ }
+ v4l2_err(sd, "TVP7002 read error %d\n", error);
+ return error;
+}
+
+/*
+ * tvp7002_read_err() - Read a register value with error code
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @reg: destination register
+ * @val: value to be read
+ * @error: pointer to error value
+ *
+ * Read a value in a register and save error value in pointer.
+ * Also update the register table if successful
+ */
+static inline void tvp7002_read_err(struct v4l2_subdev *sd, u8 reg,
+ u8 *dst, int *err)
+{
+ if (!*err)
+ *err = tvp7002_read(sd, reg, dst);
+}
+
+/*
+ * tvp7002_write() - Write a value to a register in TVP7002
+ * @sd: ptr to v4l2_subdev struct
+ * @addr: TVP7002 register address
+ * @value: value to be written to the register
+ *
+ * Write a value to a register in an TVP7002 decoder device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp7002_write(struct v4l2_subdev *sd, u8 addr, u8 value)
+{
+ struct i2c_client *c;
+ int retry;
+ int error;
+
+ c = v4l2_get_subdevdata(sd);
+
+ for (retry = 0; retry < I2C_RETRY_COUNT; retry++) {
+ error = i2c_smbus_write_byte_data(c, addr, value);
+
+ if (error >= 0)
+ return 0;
+
+ v4l2_warn(sd, "Write: retry ... %d\n", retry);
+ msleep_interruptible(10);
+ }
+ v4l2_err(sd, "TVP7002 write error %d\n", error);
+ return error;
+}
+
+/*
+ * tvp7002_write_err() - Write a register value with error code
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @reg: destination register
+ * @val: value to be written
+ * @error: pointer to error value
+ *
+ * Write a value in a register and save error value in pointer.
+ * Also update the register table if successful
+ */
+static inline void tvp7002_write_err(struct v4l2_subdev *sd, u8 reg,
+ u8 val, int *err)
+{
+ if (!*err)
+ *err = tvp7002_write(sd, reg, val);
+}
+
+/*
+ * tvp7002_g_chip_ident() - Get chip identification number
+ * @sd: ptr to v4l2_subdev struct
+ * @chip: ptr to v4l2_dbg_chip_ident struct
+ *
+ * Obtains the chip's identification number.
+ * Returns zero or -EINVAL if read operation fails.
+ */
+static int tvp7002_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ u8 rev;
+ int error;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ error = tvp7002_read(sd, TVP7002_CHIP_REV, &rev);
+
+ if (error < 0)
+ return error;
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP7002, rev);
+}
+
+/*
+ * tvp7002_write_inittab() - Write initialization values
+ * @sd: ptr to v4l2_subdev struct
+ * @regs: ptr to i2c_reg_value struct
+ *
+ * Write initialization values.
+ * Returns zero or -EINVAL if read operation fails.
+ */
+static int tvp7002_write_inittab(struct v4l2_subdev *sd,
+ const struct i2c_reg_value *regs)
+{
+ int error = 0;
+
+ /* Initialize the first (defined) registers */
+ while (TVP7002_EOR != regs->reg) {
+ if (TVP7002_WRITE == regs->type)
+ tvp7002_write_err(sd, regs->reg, regs->value, &error);
+ regs++;
+ }
+
+ return error;
+}
+
+/*
+ * tvp7002_s_dv_preset() - Set digital video preset
+ * @sd: ptr to v4l2_subdev struct
+ * @std: ptr to v4l2_dv_preset struct
+ *
+ * Set the digital video preset for a TVP7002 decoder device.
+ * Returns zero when successful or -EINVAL if register access fails.
+ */
+static int tvp7002_s_dv_preset(struct v4l2_subdev *sd,
+ struct v4l2_dv_preset *dv_preset)
+{
+ struct tvp7002 *device = to_tvp7002(sd);
+ u32 preset;
+ int i;
+
+ for (i = 0; i < NUM_PRESETS; i++) {
+ preset = tvp7002_presets[i].preset;
+ if (preset == dv_preset->preset) {
+ device->current_preset = &tvp7002_presets[i];
+ return tvp7002_write_inittab(sd, tvp7002_presets[i].p_settings);
+ }
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * tvp7002_g_ctrl() - Get a control
+ * @sd: ptr to v4l2_subdev struct
+ * @ctrl: ptr to v4l2_control struct
+ *
+ * Get a control for a TVP7002 decoder device.
+ * Returns zero when successful or -EINVAL if register access fails.
+ */
+static int tvp7002_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct tvp7002 *device = to_tvp7002(sd);
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ ctrl->value = device->gain;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * tvp7002_s_ctrl() - Set a control
+ * @sd: ptr to v4l2_subdev struct
+ * @ctrl: ptr to v4l2_control struct
+ *
+ * Set a control in TVP7002 decoder device.
+ * Returns zero when successful or -EINVAL if register access fails.
+ */
+static int tvp7002_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct tvp7002 *device = to_tvp7002(sd);
+ int error = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ tvp7002_write_err(sd, TVP7002_R_FINE_GAIN,
+ ctrl->value & 0xff, &error);
+ tvp7002_write_err(sd, TVP7002_G_FINE_GAIN,
+ ctrl->value & 0xff, &error);
+ tvp7002_write_err(sd, TVP7002_B_FINE_GAIN,
+ ctrl->value & 0xff, &error);
+
+ if (error < 0)
+ return error;
+
+ /* Set only after knowing there is no error */
+ device->gain = ctrl->value & 0xff;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * tvp7002_queryctrl() - Query a control
+ * @sd: ptr to v4l2_subdev struct
+ * @ctrl: ptr to v4l2_queryctrl struct
+ *
+ * Query a control of a TVP7002 decoder device.
+ * Returns zero when successful or -EINVAL if register read fails.
+ */
+static int tvp7002_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ switch (qc->id) {
+ case V4L2_CID_GAIN:
+ /*
+ * Gain is supported [0-255, default=0, step=1]
+ */
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 0);
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * tvp7002_try_fmt_cap() - V4L2 decoder interface handler for try_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
+ *
+ * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This
+ * ioctl is used to negotiate the image capture size and pixel format
+ * without actually making it take effect.
+ */
+static int tvp7002_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct tvp7002 *device = to_tvp7002(sd);
+ struct v4l2_dv_enum_preset e_preset;
+ struct v4l2_pix_format *pix;
+ int error = 0;
+
+ pix = &f->fmt.pix;
+
+ /* Calculate height and width based on current standard */
+ error = v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset);
+ if (error)
+ return -EINVAL;
+
+ pix->width = e_preset.width;
+ pix->height = e_preset.height;
+ pix->pixelformat = V4L2_PIX_FMT_UYVY;
+ pix->field = device->current_preset->scanmode;
+ pix->bytesperline = pix->width * 2;
+ pix->sizeimage = pix->bytesperline * pix->height;
+ pix->colorspace = device->current_preset->color_space;
+ pix->priv = 0;
+
+ v4l2_dbg(1, debug, sd, "Try FMT: pixelformat - %s, bytesperline - %d"
+ "Width - %d, Height - %d", "8-bit UYVY 4:2:2 Format",
+ pix->bytesperline, pix->width, pix->height);
+ return error;
+}
+
+/*
+ * tvp7002_s_fmt() - V4L2 decoder interface handler for s_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure
+ *
+ * If the requested format is supported, configures the HW to use that
+ * format, returns error code if format not supported or HW can't be
+ * correctly configured.
+ */
+static int tvp7002_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct tvp7002 *decoder = to_tvp7002(sd);
+ int rval;
+
+ rval = tvp7002_try_fmt_cap(sd, f);
+ if (!rval)
+ decoder->pix = f->fmt.pix;
+ return rval;
+}
+
+/*
+ * tvp7002_g_fmt() - V4L2 decoder interface handler for tvp7002_g_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @f: pointer to standard V4L2 v4l2_format structure
+ *
+ * Returns the decoder's current pixel format in the v4l2_format
+ * parameter.
+ */
+static int tvp7002_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+{
+ struct tvp7002 *decoder = to_tvp7002(sd);
+
+ f->fmt.pix = decoder->pix;
+
+ v4l2_dbg(1, debug, sd, "Current FMT: bytesperline - %d"
+ "Width - %d, Height - %d",
+ decoder->pix.bytesperline,
+ decoder->pix.width, decoder->pix.height);
+ return 0;
+}
+
+/*
+ * tvp7002_query_dv_preset() - query DV preset
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @std_id: standard V4L2 v4l2_dv_preset
+ *
+ * Returns the current DV preset by TVP7002. If no active input is
+ * detected, returns -EINVAL
+ */
+static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
+ struct v4l2_dv_preset *qpreset)
+{
+ const struct tvp7002_preset_definition *presets = tvp7002_presets;
+ struct v4l2_dv_enum_preset e_preset;
+ struct tvp7002 *device;
+ u8 progressive;
+ u32 lpfr;
+ u32 cpln;
+ int error = 0;
+ u8 lpf_lsb;
+ u8 lpf_msb;
+ u8 cpl_lsb;
+ u8 cpl_msb;
+ int index;
+
+ device = to_tvp7002(sd);
+
+ /* Read standards from device registers */
+ tvp7002_read_err(sd, TVP7002_L_FRAME_STAT_LSBS, &lpf_lsb, &error);
+ tvp7002_read_err(sd, TVP7002_L_FRAME_STAT_MSBS, &lpf_msb, &error);
+
+ if (error < 0)
+ return error;
+
+ tvp7002_read_err(sd, TVP7002_CLK_L_STAT_LSBS, &cpl_lsb, &error);
+ tvp7002_read_err(sd, TVP7002_CLK_L_STAT_MSBS, &cpl_msb, &error);
+
+ if (error < 0)
+ return error;
+
+ /* Get lines per frame, clocks per line and interlaced/progresive */
+ lpfr = lpf_lsb | ((TVP7002_CL_MASK & lpf_msb) << TVP7002_CL_SHIFT);
+ cpln = cpl_lsb | ((TVP7002_CL_MASK & cpl_msb) << TVP7002_CL_SHIFT);
+ progressive = (lpf_msb & TVP7002_INPR_MASK) >> TVP7002_IP_SHIFT;
+
+ /* Do checking of video modes */
+ for (index = 0; index < NUM_PRESETS; index++, presets++)
+ if (lpfr == presets->lines_per_frame &&
+ progressive == presets->progressive) {
+ if (presets->cpl_min == 0xffff)
+ break;
+ if (cpln >= presets->cpl_min && cpln <= presets->cpl_max)
+ break;
+ }
+
+ if (index == NUM_PRESETS) {
+ v4l2_err(sd, "querystd error, lpf = %x, cpl = %x\n",
+ lpfr, cpln);
+ return -EINVAL;
+ }
+
+ if (v4l_fill_dv_preset_info(presets->preset, &e_preset))
+ return -EINVAL;
+
+ /* Set values in found preset */
+ qpreset->preset = presets->preset;
+
+ /* Update lines per frame and clocks per line info */
+ v4l2_dbg(1, debug, sd, "Current preset: %d %d",
+ e_preset.width, e_preset.height);
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * tvp7002_g_register() - Get the value of a register
+ * @sd: ptr to v4l2_subdev struct
+ * @vreg: ptr to v4l2_dbg_register struct
+ *
+ * Get the value of a TVP7002 decoder device register.
+ * Returns zero when successful, -EINVAL if register read fails or
+ * access to I2C client fails, -EPERM if the call is not allowed
+ * by diabled CAP_SYS_ADMIN.
+ */
+static int tvp7002_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 val;
+ int ret;
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ ret = tvp7002_read(sd, reg->reg & 0xff, &val);
+ reg->val = val;
+ return ret;
+}
+
+/*
+ * tvp7002_s_register() - set a control
+ * @sd: ptr to v4l2_subdev struct
+ * @ctrl: ptr to v4l2_control struct
+ *
+ * Get the value of a TVP7002 decoder device register.
+ * Returns zero when successful, -EINVAL if register read fails or
+ * -EPERM if call not allowed.
+ */
+static int tvp7002_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ return tvp7002_write(sd, reg->reg & 0xff, reg->val & 0xff);
+}
+#endif
+
+/*
+ * tvp7002_enum_fmt() - Enum supported formats
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @enable: pointer to format struct
+ *
+ * Enumerate supported formats.
+ */
+
+static int tvp7002_enum_fmt(struct v4l2_subdev *sd,
+ struct v4l2_fmtdesc *fmtdesc)
+{
+ /* Check requested format index is within range */
+ if (fmtdesc->index < 0 || fmtdesc->index >= NUM_FORMATS)
+ return -EINVAL;
+ *fmtdesc = tvp7002_fmt_list[fmtdesc->index];
+
+ return 0;
+}
+
+/*
+ * tvp7002_s_stream() - V4L2 decoder i/f handler for s_stream
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @enable: streaming enable or disable
+ *
+ * Sets streaming to enable or disable, if possible.
+ */
+static int tvp7002_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct tvp7002 *device = to_tvp7002(sd);
+ int error = 0;
+
+ if (device->streaming == enable)
+ return 0;
+
+ if (enable) {
+ /* Set output state on (low impedance means stream on) */
+ error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00);
+ device->streaming = enable;
+ } else {
+ /* Set output state off (high impedance means stream off) */
+ error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x03);
+ if (error)
+ v4l2_dbg(1, debug, sd, "Unable to stop streaming\n");
+
+ device->streaming = enable;
+ }
+
+ return error;
+}
+
+/*
+ * tvp7002_log_status() - Print information about register settings
+ * @sd: ptr to v4l2_subdev struct
+ *
+ * Log register values of a TVP7002 decoder device.
+ * Returns zero or -EINVAL if read operation fails.
+ */
+static int tvp7002_log_status(struct v4l2_subdev *sd)
+{
+ const struct tvp7002_preset_definition *presets = tvp7002_presets;
+ struct tvp7002 *device = to_tvp7002(sd);
+ struct v4l2_dv_enum_preset e_preset;
+ struct v4l2_dv_preset detected;
+ int i;
+
+ detected.preset = V4L2_DV_INVALID;
+ /* Find my current standard*/
+ tvp7002_query_dv_preset(sd, &detected);
+
+ /* Print standard related code values */
+ for (i = 0; i < NUM_PRESETS; i++, presets++)
+ if (presets->preset == detected.preset)
+ break;
+
+ if (v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset))
+ return -EINVAL;
+
+ v4l2_info(sd, "Selected DV Preset: %s\n", e_preset.name);
+ v4l2_info(sd, " Pixels per line: %u\n", e_preset.width);
+ v4l2_info(sd, " Lines per frame: %u\n\n", e_preset.height);
+ if (i == NUM_PRESETS) {
+ v4l2_info(sd, "Detected DV Preset: None\n");
+ } else {
+ if (v4l_fill_dv_preset_info(presets->preset, &e_preset))
+ return -EINVAL;
+ v4l2_info(sd, "Detected DV Preset: %s\n", e_preset.name);
+ v4l2_info(sd, " Pixels per line: %u\n", e_preset.width);
+ v4l2_info(sd, " Lines per frame: %u\n\n", e_preset.height);
+ }
+ v4l2_info(sd, "Streaming enabled: %s\n",
+ device->streaming ? "yes" : "no");
+
+ /* Print the current value of the gain control */
+ v4l2_info(sd, "Gain: %u\n", device->gain);
+
+ return 0;
+}
+
+/* V4L2 core operation handlers */
+static const struct v4l2_subdev_core_ops tvp7002_core_ops = {
+ .g_chip_ident = tvp7002_g_chip_ident,
+ .log_status = tvp7002_log_status,
+ .g_ctrl = tvp7002_g_ctrl,
+ .s_ctrl = tvp7002_s_ctrl,
+ .queryctrl = tvp7002_queryctrl,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = tvp7002_g_register,
+ .s_register = tvp7002_s_register,
+#endif
+};
+
+/* Specific video subsystem operation handlers */
+static const struct v4l2_subdev_video_ops tvp7002_video_ops = {
+ .s_dv_preset = tvp7002_s_dv_preset,
+ .query_dv_preset = tvp7002_query_dv_preset,
+ .s_stream = tvp7002_s_stream,
+ .g_fmt = tvp7002_g_fmt,
+ .s_fmt = tvp7002_s_fmt,
+ .enum_fmt = tvp7002_enum_fmt,
+};
+
+/* V4L2 top level operation handlers */
+static const struct v4l2_subdev_ops tvp7002_ops = {
+ .core = &tvp7002_core_ops,
+ .video = &tvp7002_video_ops,
+};
+
+static struct tvp7002 tvp7002_dev = {
+ .streaming = 0,
+
+ .pix = {
+ .width = 1280,
+ .height = 720,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .field = V4L2_FIELD_NONE,
+ .bytesperline = 1280 * 2,
+ .sizeimage = 1280 * 2 * 720,
+ .colorspace = V4L2_COLORSPACE_REC709,
+ },
+
+ .current_preset = tvp7002_presets,
+ .gain = 0,
+};
+
+/*
+ * tvp7002_probe - Probe a TVP7002 device
+ * @sd: ptr to v4l2_subdev struct
+ * @ctrl: ptr to i2c_device_id struct
+ *
+ * Initialize the TVP7002 device
+ * Returns zero when successful, -EINVAL if register read fails or
+ * -EIO if i2c access is not available.
+ */
+static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
+{
+ struct v4l2_subdev *sd;
+ struct tvp7002 *device;
+ struct v4l2_dv_preset preset;
+ int polarity_a;
+ int polarity_b;
+ u8 revision;
+
+ int error;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(c->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+ return -EIO;
+
+ if (!c->dev.platform_data) {
+ v4l_err(c, "No platform data!!\n");
+ return -ENODEV;
+ }
+
+ device = kmalloc(sizeof(struct tvp7002), GFP_KERNEL);
+
+ if (!device)
+ return -ENOMEM;
+
+ *device = tvp7002_dev;
+ sd = &device->sd;
+ device->pdata = c->dev.platform_data;
+
+ /* Tell v4l2 the device is ready */
+ v4l2_i2c_subdev_init(sd, c, &tvp7002_ops);
+ v4l_info(c, "tvp7002 found @ 0x%02x (%s)\n",
+ c->addr, c->adapter->name);
+
+ error = tvp7002_read(sd, TVP7002_CHIP_REV, &revision);
+ if (error < 0)
+ goto found_error;
+
+ /* Get revision number */
+ v4l2_info(sd, "Rev. %02x detected.\n", revision);
+ if (revision != 0x02)
+ v4l2_info(sd, "Unknown revision detected.\n");
+
+ /* Initializes TVP7002 to its default values */
+ error = tvp7002_write_inittab(sd, tvp7002_init_default);
+
+ if (error < 0)
+ goto found_error;
+
+ /* Set polarity information after registers have been set */
+ polarity_a = 0x20 | device->pdata->hs_polarity << 5
+ | device->pdata->vs_polarity << 2;
+ error = tvp7002_write(sd, TVP7002_SYNC_CTL_1, polarity_a);
+ if (error < 0)
+ goto found_error;
+
+ polarity_b = 0x01 | device->pdata->fid_polarity << 2
+ | device->pdata->sog_polarity << 1
+ | device->pdata->clk_polarity;
+ error = tvp7002_write(sd, TVP7002_MISC_CTL_3, polarity_b);
+ if (error < 0)
+ goto found_error;
+
+ /* Set registers according to default video mode */
+ preset.preset = device->current_preset->preset;
+ error = tvp7002_s_dv_preset(sd, &preset);
+
+found_error:
+ if (error < 0)
+ kfree(device);
+
+ return error;
+}
+
+/*
+ * tvp7002_remove - Remove TVP7002 device support
+ * @c: ptr to i2c_client struct
+ *
+ * Reset the TVP7002 device
+ * Returns zero.
+ */
+static int tvp7002_remove(struct i2c_client *c)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(c);
+ struct tvp7002 *device = to_tvp7002(sd);
+
+ v4l2_dbg(1, debug, sd, "Removing tvp7002 adapter"
+ "on address 0x%x\n", c->addr);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(device);
+ return 0;
+}
+
+/* I2C Device ID table */
+static const struct i2c_device_id tvp7002_id[] = {
+ { "tvp7002", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tvp7002_id);
+
+/* I2C driver data */
+static struct i2c_driver tvp7002_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = TVP7002_MODULE_NAME,
+ },
+ .probe = tvp7002_probe,
+ .remove = tvp7002_remove,
+ .id_table = tvp7002_id,
+};
+
+/*
+ * tvp7002_init - Initialize driver via I2C interface
+ *
+ * Register the TVP7002 driver.
+ * Return 0 on success or error code on failure.
+ */
+static int __init tvp7002_init(void)
+{
+ return i2c_add_driver(&tvp7002_driver);
+}
+
+/*
+ * tvp7002_exit - Remove driver via I2C interface
+ *
+ * Unregister the TVP7002 driver.
+ * Returns nothing.
+ */
+static void __exit tvp7002_exit(void)
+{
+ i2c_del_driver(&tvp7002_driver);
+}
+
+module_init(tvp7002_init);
+module_exit(tvp7002_exit);
diff --git a/drivers/media/video/tvp7002_reg.h b/drivers/media/video/tvp7002_reg.h
new file mode 100644
index 000000000000..0e34ca9bccf3
--- /dev/null
+++ b/drivers/media/video/tvp7002_reg.h
@@ -0,0 +1,150 @@
+/* Texas Instruments Triple 8-/10-BIT 165-/110-MSPS Video and Graphics
+ * Digitizer with Horizontal PLL registers
+ *
+ * Copyright (C) 2009 Texas Instruments Inc
+ * Author: Santiago Nunez-Corrales <santiago.nunez@ridgerun.com>
+ *
+ * This code is partially based upon the TVP5150 driver
+ * written by Mauro Carvalho Chehab (mchehab@infradead.org),
+ * the TVP514x driver written by Vaibhav Hiremath <hvaibhav@ti.com>
+ * and the TVP7002 driver in the TI LSP 2.10.00.14
+ *
+ * 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.
+ */
+
+/* Naming conventions
+ * ------------------
+ *
+ * FDBK: Feedback
+ * DIV: Divider
+ * CTL: Control
+ * SEL: Select
+ * IN: Input
+ * OUT: Output
+ * R: Red
+ * G: Green
+ * B: Blue
+ * OFF: Offset
+ * THRS: Threshold
+ * DGTL: Digital
+ * LVL: Level
+ * PWR: Power
+ * MVIS: Macrovision
+ * W: Width
+ * H: Height
+ * ALGN: Alignment
+ * CLK: Clocks
+ * TOL: Tolerance
+ * BWTH: Bandwidth
+ * COEF: Coefficient
+ * STAT: Status
+ * AUTO: Automatic
+ * FLD: Field
+ * L: Line
+ */
+
+#define TVP7002_CHIP_REV 0x00
+#define TVP7002_HPLL_FDBK_DIV_MSBS 0x01
+#define TVP7002_HPLL_FDBK_DIV_LSBS 0x02
+#define TVP7002_HPLL_CRTL 0x03
+#define TVP7002_HPLL_PHASE_SEL 0x04
+#define TVP7002_CLAMP_START 0x05
+#define TVP7002_CLAMP_W 0x06
+#define TVP7002_HSYNC_OUT_W 0x07
+#define TVP7002_B_FINE_GAIN 0x08
+#define TVP7002_G_FINE_GAIN 0x09
+#define TVP7002_R_FINE_GAIN 0x0a
+#define TVP7002_B_FINE_OFF_MSBS 0x0b
+#define TVP7002_G_FINE_OFF_MSBS 0x0c
+#define TVP7002_R_FINE_OFF_MSBS 0x0d
+#define TVP7002_SYNC_CTL_1 0x0e
+#define TVP7002_HPLL_AND_CLAMP_CTL 0x0f
+#define TVP7002_SYNC_ON_G_THRS 0x10
+#define TVP7002_SYNC_SEPARATOR_THRS 0x11
+#define TVP7002_HPLL_PRE_COAST 0x12
+#define TVP7002_HPLL_POST_COAST 0x13
+#define TVP7002_SYNC_DETECT_STAT 0x14
+#define TVP7002_OUT_FORMATTER 0x15
+#define TVP7002_MISC_CTL_1 0x16
+#define TVP7002_MISC_CTL_2 0x17
+#define TVP7002_MISC_CTL_3 0x18
+#define TVP7002_IN_MUX_SEL_1 0x19
+#define TVP7002_IN_MUX_SEL_2 0x1a
+#define TVP7002_B_AND_G_COARSE_GAIN 0x1b
+#define TVP7002_R_COARSE_GAIN 0x1c
+#define TVP7002_FINE_OFF_LSBS 0x1d
+#define TVP7002_B_COARSE_OFF 0x1e
+#define TVP7002_G_COARSE_OFF 0x1f
+#define TVP7002_R_COARSE_OFF 0x20
+#define TVP7002_HSOUT_OUT_START 0x21
+#define TVP7002_MISC_CTL_4 0x22
+#define TVP7002_B_DGTL_ALC_OUT_LSBS 0x23
+#define TVP7002_G_DGTL_ALC_OUT_LSBS 0x24
+#define TVP7002_R_DGTL_ALC_OUT_LSBS 0x25
+#define TVP7002_AUTO_LVL_CTL_ENABLE 0x26
+#define TVP7002_DGTL_ALC_OUT_MSBS 0x27
+#define TVP7002_AUTO_LVL_CTL_FILTER 0x28
+/* Reserved 0x29*/
+#define TVP7002_FINE_CLAMP_CTL 0x2a
+#define TVP7002_PWR_CTL 0x2b
+#define TVP7002_ADC_SETUP 0x2c
+#define TVP7002_COARSE_CLAMP_CTL 0x2d
+#define TVP7002_SOG_CLAMP 0x2e
+#define TVP7002_RGB_COARSE_CLAMP_CTL 0x2f
+#define TVP7002_SOG_COARSE_CLAMP_CTL 0x30
+#define TVP7002_ALC_PLACEMENT 0x31
+/* Reserved 0x32 */
+/* Reserved 0x33 */
+#define TVP7002_MVIS_STRIPPER_W 0x34
+#define TVP7002_VSYNC_ALGN 0x35
+#define TVP7002_SYNC_BYPASS 0x36
+#define TVP7002_L_FRAME_STAT_LSBS 0x37
+#define TVP7002_L_FRAME_STAT_MSBS 0x38
+#define TVP7002_CLK_L_STAT_LSBS 0x39
+#define TVP7002_CLK_L_STAT_MSBS 0x3a
+#define TVP7002_HSYNC_W 0x3b
+#define TVP7002_VSYNC_W 0x3c
+#define TVP7002_L_LENGTH_TOL 0x3d
+/* Reserved 0x3e */
+#define TVP7002_VIDEO_BWTH_CTL 0x3f
+#define TVP7002_AVID_START_PIXEL_LSBS 0x40
+#define TVP7002_AVID_START_PIXEL_MSBS 0x41
+#define TVP7002_AVID_STOP_PIXEL_LSBS 0x42
+#define TVP7002_AVID_STOP_PIXEL_MSBS 0x43
+#define TVP7002_VBLK_F_0_START_L_OFF 0x44
+#define TVP7002_VBLK_F_1_START_L_OFF 0x45
+#define TVP7002_VBLK_F_0_DURATION 0x46
+#define TVP7002_VBLK_F_1_DURATION 0x47
+#define TVP7002_FBIT_F_0_START_L_OFF 0x48
+#define TVP7002_FBIT_F_1_START_L_OFF 0x49
+#define TVP7002_YUV_Y_G_COEF_LSBS 0x4a
+#define TVP7002_YUV_Y_G_COEF_MSBS 0x4b
+#define TVP7002_YUV_Y_B_COEF_LSBS 0x4c
+#define TVP7002_YUV_Y_B_COEF_MSBS 0x4d
+#define TVP7002_YUV_Y_R_COEF_LSBS 0x4e
+#define TVP7002_YUV_Y_R_COEF_MSBS 0x4f
+#define TVP7002_YUV_U_G_COEF_LSBS 0x50
+#define TVP7002_YUV_U_G_COEF_MSBS 0x51
+#define TVP7002_YUV_U_B_COEF_LSBS 0x52
+#define TVP7002_YUV_U_B_COEF_MSBS 0x53
+#define TVP7002_YUV_U_R_COEF_LSBS 0x54
+#define TVP7002_YUV_U_R_COEF_MSBS 0x55
+#define TVP7002_YUV_V_G_COEF_LSBS 0x56
+#define TVP7002_YUV_V_G_COEF_MSBS 0x57
+#define TVP7002_YUV_V_B_COEF_LSBS 0x58
+#define TVP7002_YUV_V_B_COEF_MSBS 0x59
+#define TVP7002_YUV_V_R_COEF_LSBS 0x5a
+#define TVP7002_YUV_V_R_COEF_MSBS 0x5b
+
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index 5b801a6e1eea..76be733eabfd 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -233,10 +233,10 @@ struct tw9910_hsync_ctrl {
};
struct tw9910_priv {
- struct v4l2_subdev subdev;
- struct tw9910_video_info *info;
- const struct tw9910_scale_ctrl *scale;
- u32 revision;
+ struct v4l2_subdev subdev;
+ struct tw9910_video_info *info;
+ const struct tw9910_scale_ctrl *scale;
+ u32 revision;
};
static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = {
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 1054546db908..7c17ec63c5da 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -1487,7 +1487,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
usbvision->vbi = usbvision_vdev_init(usbvision,
&usbvision_vbi_template,
"USBVision VBI");
- if (usbvision->vdev == NULL) {
+ if (usbvision->vbi == NULL) {
goto err_exit;
}
if (video_register_device(usbvision->vbi,
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 0469d7a876a8..3b2e7800d56f 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -23,9 +23,13 @@
#include "uvcvideo.h"
-#define UVC_CTRL_NDATA 2
#define UVC_CTRL_DATA_CURRENT 0
#define UVC_CTRL_DATA_BACKUP 1
+#define UVC_CTRL_DATA_MIN 2
+#define UVC_CTRL_DATA_MAX 3
+#define UVC_CTRL_DATA_RES 4
+#define UVC_CTRL_DATA_DEF 5
+#define UVC_CTRL_DATA_LAST 6
/* ------------------------------------------------------------------------
* Controls
@@ -755,6 +759,49 @@ struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
return ctrl;
}
+static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
+ struct uvc_control *ctrl)
+{
+ int ret;
+
+ if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
+ ctrl->info->size);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
+ ctrl->info->size);
+ if (ret < 0)
+ return ret;
+ }
+ if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
+ ctrl->info->size);
+ if (ret < 0)
+ return ret;
+ }
+ if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
+ ctrl->info->size);
+ if (ret < 0)
+ return ret;
+ }
+
+ ctrl->cached = 1;
+ return 0;
+}
+
int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct v4l2_queryctrl *v4l2_ctrl)
{
@@ -762,17 +809,12 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct uvc_control_mapping *mapping;
struct uvc_menu_info *menu;
unsigned int i;
- __u8 *data;
int ret;
ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
if (ctrl == NULL)
return -EINVAL;
- data = kmalloc(ctrl->info->size, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
v4l2_ctrl->id = mapping->id;
v4l2_ctrl->type = mapping->v4l2_type;
@@ -782,14 +824,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
- if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size);
+ if (!ctrl->cached) {
+ ret = uvc_ctrl_populate_cache(chain, ctrl);
if (ret < 0)
- goto out;
- v4l2_ctrl->default_value =
- mapping->get(mapping, UVC_GET_DEF, data);
+ return ret;
+ }
+
+ if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+ v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
}
switch (mapping->v4l2_type) {
@@ -806,56 +849,37 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
}
}
- ret = 0;
- goto out;
+ return 0;
case V4L2_CTRL_TYPE_BOOLEAN:
v4l2_ctrl->minimum = 0;
v4l2_ctrl->maximum = 1;
v4l2_ctrl->step = 1;
- ret = 0;
- goto out;
+ return 0;
case V4L2_CTRL_TYPE_BUTTON:
v4l2_ctrl->minimum = 0;
v4l2_ctrl->maximum = 0;
v4l2_ctrl->step = 0;
- ret = 0;
- goto out;
+ return 0;
default:
break;
}
- if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size);
- if (ret < 0)
- goto out;
- v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data);
- }
- if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size);
- if (ret < 0)
- goto out;
- v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data);
- }
- if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size);
- if (ret < 0)
- goto out;
- v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data);
- }
+ if (ctrl->info->flags & UVC_CONTROL_GET_MIN)
+ v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
- ret = 0;
-out:
- kfree(data);
- return ret;
+ if (ctrl->info->flags & UVC_CONTROL_GET_MAX)
+ v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+
+ if (ctrl->info->flags & UVC_CONTROL_GET_RES)
+ v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+
+ return 0;
}
@@ -997,19 +1021,57 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
{
struct uvc_control *ctrl;
struct uvc_control_mapping *mapping;
- s32 value = xctrl->value;
+ s32 value;
+ u32 step;
+ s32 min;
+ s32 max;
int ret;
ctrl = uvc_find_control(chain, xctrl->id, &mapping);
if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)
return -EINVAL;
- if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
- if (value < 0 || value >= mapping->menu_count)
- return -EINVAL;
- value = mapping->menu_info[value].value;
+ /* Clamp out of range values. */
+ switch (mapping->v4l2_type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ if (!ctrl->cached) {
+ ret = uvc_ctrl_populate_cache(chain, ctrl);
+ if (ret < 0)
+ return ret;
+ }
+
+ min = mapping->get(mapping, UVC_GET_MIN,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
+ max = mapping->get(mapping, UVC_GET_MAX,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+ step = mapping->get(mapping, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+
+ xctrl->value = min + (xctrl->value - min + step/2) / step * step;
+ xctrl->value = clamp(xctrl->value, min, max);
+ value = xctrl->value;
+ break;
+
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ xctrl->value = clamp(xctrl->value, 0, 1);
+ value = xctrl->value;
+ break;
+
+ case V4L2_CTRL_TYPE_MENU:
+ if (xctrl->value < 0 || xctrl->value >= mapping->menu_count)
+ return -ERANGE;
+ value = mapping->menu_info[xctrl->value].value;
+ break;
+
+ default:
+ value = xctrl->value;
+ break;
}
+ /* If the mapping doesn't span the whole UVC control, the current value
+ * needs to be loaded from the device to perform the read-modify-write
+ * operation.
+ */
if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) {
if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) {
memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
@@ -1027,6 +1089,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
ctrl->loaded = 1;
}
+ /* Backup the current value in case we need to rollback later. */
if (!ctrl->dirty) {
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
@@ -1080,10 +1143,8 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
}
if (!found) {
- uvc_trace(UVC_TRACE_CONTROL,
- "Control " UVC_GUID_FORMAT "/%u not found.\n",
- UVC_GUID_ARGS(entity->extension.guidExtensionCode),
- xctrl->selector);
+ uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u not found.\n",
+ entity->extension.guidExtensionCode, xctrl->selector);
return -EINVAL;
}
@@ -1159,9 +1220,9 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
(ctrl->info->flags & UVC_CONTROL_RESTORE) == 0)
continue;
- printk(KERN_INFO "restoring control " UVC_GUID_FORMAT
- "/%u/%u\n", UVC_GUID_ARGS(ctrl->info->entity),
- ctrl->info->index, ctrl->info->selector);
+ printk(KERN_INFO "restoring control %pUl/%u/%u\n",
+ ctrl->info->entity, ctrl->info->index,
+ ctrl->info->selector);
ctrl->dirty = 1;
}
@@ -1215,47 +1276,43 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id,
dev->intfnum, info->selector, (__u8 *)&size, 2);
if (ret < 0) {
- uvc_trace(UVC_TRACE_CONTROL, "GET_LEN failed on "
- "control " UVC_GUID_FORMAT "/%u (%d).\n",
- UVC_GUID_ARGS(info->entity), info->selector,
- ret);
+ uvc_trace(UVC_TRACE_CONTROL,
+ "GET_LEN failed on control %pUl/%u (%d).\n",
+ info->entity, info->selector, ret);
return;
}
if (info->size != le16_to_cpu(size)) {
- uvc_trace(UVC_TRACE_CONTROL, "Control " UVC_GUID_FORMAT
- "/%u size doesn't match user supplied "
- "value.\n", UVC_GUID_ARGS(info->entity),
- info->selector);
+ uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u size "
+ "doesn't match user supplied value.\n",
+ info->entity, info->selector);
return;
}
ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
dev->intfnum, info->selector, &inf, 1);
if (ret < 0) {
- uvc_trace(UVC_TRACE_CONTROL, "GET_INFO failed on "
- "control " UVC_GUID_FORMAT "/%u (%d).\n",
- UVC_GUID_ARGS(info->entity), info->selector,
- ret);
+ uvc_trace(UVC_TRACE_CONTROL,
+ "GET_INFO failed on control %pUl/%u (%d).\n",
+ info->entity, info->selector, ret);
return;
}
flags = info->flags;
if (((flags & UVC_CONTROL_GET_CUR) && !(inf & (1 << 0))) ||
((flags & UVC_CONTROL_SET_CUR) && !(inf & (1 << 1)))) {
- uvc_trace(UVC_TRACE_CONTROL, "Control "
- UVC_GUID_FORMAT "/%u flags don't match "
- "supported operations.\n",
- UVC_GUID_ARGS(info->entity), info->selector);
+ uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u flags "
+ "don't match supported operations.\n",
+ info->entity, info->selector);
return;
}
}
ctrl->info = info;
- ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_NDATA, GFP_KERNEL);
- uvc_trace(UVC_TRACE_CONTROL, "Added control " UVC_GUID_FORMAT "/%u "
- "to device %s entity %u\n", UVC_GUID_ARGS(ctrl->info->entity),
- ctrl->info->selector, dev->udev->devpath, entity->id);
+ ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_DATA_LAST, GFP_KERNEL);
+ uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
+ "entity %u\n", ctrl->info->entity, ctrl->info->selector,
+ dev->udev->devpath, entity->id);
}
/*
@@ -1281,17 +1338,16 @@ int uvc_ctrl_add_info(struct uvc_control_info *info)
continue;
if (ctrl->selector == info->selector) {
- uvc_trace(UVC_TRACE_CONTROL, "Control "
- UVC_GUID_FORMAT "/%u is already defined.\n",
- UVC_GUID_ARGS(info->entity), info->selector);
+ uvc_trace(UVC_TRACE_CONTROL,
+ "Control %pUl/%u is already defined.\n",
+ info->entity, info->selector);
ret = -EEXIST;
goto end;
}
if (ctrl->index == info->index) {
- uvc_trace(UVC_TRACE_CONTROL, "Control "
- UVC_GUID_FORMAT "/%u would overwrite index "
- "%d.\n", UVC_GUID_ARGS(info->entity),
- info->selector, info->index);
+ uvc_trace(UVC_TRACE_CONTROL,
+ "Control %pUl/%u would overwrite index %d.\n",
+ info->entity, info->selector, info->index);
ret = -EEXIST;
goto end;
}
@@ -1332,10 +1388,9 @@ int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
continue;
if (info->size * 8 < mapping->size + mapping->offset) {
- uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' would "
- "overflow control " UVC_GUID_FORMAT "/%u\n",
- mapping->name, UVC_GUID_ARGS(info->entity),
- info->selector);
+ uvc_trace(UVC_TRACE_CONTROL,
+ "Mapping '%s' would overflow control %pUl/%u\n",
+ mapping->name, info->entity, info->selector);
ret = -EOVERFLOW;
goto end;
}
@@ -1354,9 +1409,9 @@ int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
mapping->ctrl = info;
list_add_tail(&mapping->list, &info->mappings);
- uvc_trace(UVC_TRACE_CONTROL, "Adding mapping %s to control "
- UVC_GUID_FORMAT "/%u.\n", mapping->name,
- UVC_GUID_ARGS(info->entity), info->selector);
+ uvc_trace(UVC_TRACE_CONTROL,
+ "Adding mapping %s to control %pUl/%u.\n",
+ mapping->name, info->entity, info->selector);
ret = 0;
break;
@@ -1378,6 +1433,7 @@ uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
struct usb_device_id id;
u8 index;
} blacklist[] = {
+ { { USB_DEVICE(0x13d3, 0x509b) }, 9 }, /* Gain */
{ { USB_DEVICE(0x1c4f, 0x3000) }, 6 }, /* WB Temperature */
{ { USB_DEVICE(0x5986, 0x0241) }, 2 }, /* Hue */
};
@@ -1393,7 +1449,7 @@ uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
size = entity->processing.bControlSize;
for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
- if (!usb_match_id(dev->intf, &blacklist[i].id))
+ if (!usb_match_one_id(dev->intf, &blacklist[i].id))
continue;
if (blacklist[i].index >= 8 * size ||
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 391cccca7ffc..a814820a3f6e 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -43,8 +43,9 @@
#define DRIVER_VERSION "v0.1.0"
#endif
+unsigned int uvc_clock_param = CLOCK_MONOTONIC;
unsigned int uvc_no_drop_param;
-static unsigned int uvc_quirks_param;
+static unsigned int uvc_quirks_param = -1;
unsigned int uvc_trace_param;
unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
@@ -59,6 +60,11 @@ static struct uvc_format_desc uvc_fmts[] = {
.fcc = V4L2_PIX_FMT_YUYV,
},
{
+ .name = "YUV 4:2:2 (YUYV)",
+ .guid = UVC_GUID_FORMAT_YUY2_ISIGHT,
+ .fcc = V4L2_PIX_FMT_YUYV,
+ },
+ {
.name = "YUV 4:2:0 (NV12)",
.guid = UVC_GUID_FORMAT_NV12,
.fcc = V4L2_PIX_FMT_NV12,
@@ -309,11 +315,10 @@ static int uvc_parse_format(struct uvc_device *dev,
sizeof format->name);
format->fcc = fmtdesc->fcc;
} else {
- uvc_printk(KERN_INFO, "Unknown video format "
- UVC_GUID_FORMAT "\n",
- UVC_GUID_ARGS(&buffer[5]));
- snprintf(format->name, sizeof format->name,
- UVC_GUID_FORMAT, UVC_GUID_ARGS(&buffer[5]));
+ uvc_printk(KERN_INFO, "Unknown video format %pUl\n",
+ &buffer[5]);
+ snprintf(format->name, sizeof(format->name), "%pUl\n",
+ &buffer[5]);
format->fcc = 0;
}
@@ -1750,7 +1755,8 @@ static int uvc_probe(struct usb_interface *intf,
dev->udev = usb_get_dev(udev);
dev->intf = usb_get_intf(intf);
dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
- dev->quirks = id->driver_info | uvc_quirks_param;
+ dev->quirks = (uvc_quirks_param == -1)
+ ? id->driver_info : uvc_quirks_param;
if (udev->product != NULL)
strlcpy(dev->name, udev->product, sizeof dev->name);
@@ -1773,9 +1779,9 @@ static int uvc_probe(struct usb_interface *intf,
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
- if (uvc_quirks_param != 0) {
- uvc_printk(KERN_INFO, "Forcing device quirks 0x%x by module "
- "parameter for testing purpose.\n", uvc_quirks_param);
+ if (dev->quirks != id->driver_info) {
+ uvc_printk(KERN_INFO, "Forcing device quirks to 0x%x by module "
+ "parameter for testing purpose.\n", dev->quirks);
uvc_printk(KERN_INFO, "Please report required quirks to the "
"linux-uvc-devel mailing list.\n");
}
@@ -1892,6 +1898,45 @@ static int uvc_reset_resume(struct usb_interface *intf)
}
/* ------------------------------------------------------------------------
+ * Module parameters
+ */
+
+static int uvc_clock_param_get(char *buffer, struct kernel_param *kp)
+{
+ if (uvc_clock_param == CLOCK_MONOTONIC)
+ return sprintf(buffer, "CLOCK_MONOTONIC");
+ else
+ return sprintf(buffer, "CLOCK_REALTIME");
+}
+
+static int uvc_clock_param_set(const char *val, struct kernel_param *kp)
+{
+ if (strncasecmp(val, "clock_", strlen("clock_")) == 0)
+ val += strlen("clock_");
+
+ if (strcasecmp(val, "monotonic") == 0)
+ uvc_clock_param = CLOCK_MONOTONIC;
+ else if (strcasecmp(val, "realtime") == 0)
+ uvc_clock_param = CLOCK_REALTIME;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+module_param_call(clock, uvc_clock_param_set, uvc_clock_param_get,
+ &uvc_clock_param, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(clock, "Video buffers timestamp clock");
+module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
+module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(quirks, "Forced device quirks");
+module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(trace, "Trace level bitmask");
+module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
+
+/* ------------------------------------------------------------------------
* Driver initialization and cleanup
*/
@@ -2197,15 +2242,6 @@ static void __exit uvc_cleanup(void)
module_init(uvc_init);
module_exit(uvc_cleanup);
-module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
-module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(quirks, "Forced device quirks");
-module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(trace, "Trace level bitmask");
-module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
-
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index f854698c4061..4a925a31b0e0 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -59,9 +59,9 @@
* returns immediately.
*
* When the buffer is full, the completion handler removes it from the irq
- * queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue.
+ * queue, marks it as done (UVC_BUF_STATE_DONE) and wakes its wait queue.
* At that point, any process waiting on the buffer will be woken up. If a
- * process tries to dequeue a buffer after it has been marked ready, the
+ * process tries to dequeue a buffer after it has been marked done, the
* dequeing will succeed immediately.
*
* 2. Buffers are queued, user is waiting on a buffer and the device gets
@@ -201,6 +201,7 @@ static void __uvc_query_buffer(struct uvc_buffer *buf,
break;
case UVC_BUF_STATE_QUEUED:
case UVC_BUF_STATE_ACTIVE:
+ case UVC_BUF_STATE_READY:
v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
break;
case UVC_BUF_STATE_IDLE:
@@ -295,13 +296,15 @@ static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
{
if (nonblocking) {
return (buf->state != UVC_BUF_STATE_QUEUED &&
- buf->state != UVC_BUF_STATE_ACTIVE)
+ buf->state != UVC_BUF_STATE_ACTIVE &&
+ buf->state != UVC_BUF_STATE_READY)
? 0 : -EAGAIN;
}
return wait_event_interruptible(buf->wait,
buf->state != UVC_BUF_STATE_QUEUED &&
- buf->state != UVC_BUF_STATE_ACTIVE);
+ buf->state != UVC_BUF_STATE_ACTIVE &&
+ buf->state != UVC_BUF_STATE_READY);
}
/*
@@ -348,6 +351,7 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue,
case UVC_BUF_STATE_IDLE:
case UVC_BUF_STATE_QUEUED:
case UVC_BUF_STATE_ACTIVE:
+ case UVC_BUF_STATE_READY:
default:
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
"(driver bug?).\n", buf->state);
@@ -489,6 +493,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
spin_lock_irqsave(&queue->irqlock, flags);
list_del(&buf->queue);
+ buf->state = UVC_BUF_STATE_DONE;
if (!list_empty(&queue->irqqueue))
nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
queue);
@@ -497,7 +502,6 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
spin_unlock_irqrestore(&queue->irqlock, flags);
buf->buf.sequence = queue->sequence++;
- do_gettimeofday(&buf->buf.timestamp);
wake_up(&buf->wait);
return nextbuf;
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 23239a4adefe..43152aa52227 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -539,7 +539,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
xctrl.id = ctrl->id;
xctrl.value = ctrl->value;
- uvc_ctrl_begin(chain);
+ ret = uvc_ctrl_begin(chain);
if (ret < 0)
return ret;
@@ -549,6 +549,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return ret;
}
ret = uvc_ctrl_commit(chain);
+ if (ret == 0)
+ ctrl->value = xctrl.value;
break;
}
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 9a9802830d41..6b0666be370f 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -410,6 +410,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
* when the EOF bit is set to force synchronisation on the next packet.
*/
if (buf->state != UVC_BUF_STATE_ACTIVE) {
+ struct timespec ts;
+
if (fid == stream->last_fid) {
uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
"sync).\n");
@@ -419,6 +421,14 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
return -ENODATA;
}
+ if (uvc_clock_param == CLOCK_MONOTONIC)
+ ktime_get_ts(&ts);
+ else
+ ktime_get_real_ts(&ts);
+
+ buf->buf.timestamp.tv_sec = ts.tv_sec;
+ buf->buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+
/* TODO: Handle PTS and SCR. */
buf->state = UVC_BUF_STATE_ACTIVE;
}
@@ -441,7 +451,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
if (fid != stream->last_fid && buf->buf.bytesused != 0) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
"toggled).\n");
- buf->state = UVC_BUF_STATE_DONE;
+ buf->state = UVC_BUF_STATE_READY;
return -EAGAIN;
}
@@ -470,7 +480,7 @@ static void uvc_video_decode_data(struct uvc_streaming *stream,
/* Complete the current frame if the buffer size was exceeded. */
if (len > maxlen) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
- buf->state = UVC_BUF_STATE_DONE;
+ buf->state = UVC_BUF_STATE_READY;
}
}
@@ -482,7 +492,7 @@ static void uvc_video_decode_end(struct uvc_streaming *stream,
uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
if (data[0] == len)
uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
- buf->state = UVC_BUF_STATE_DONE;
+ buf->state = UVC_BUF_STATE_READY;
if (stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
stream->last_fid ^= UVC_STREAM_FID;
}
@@ -568,8 +578,7 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
uvc_video_decode_end(stream, buf, mem,
urb->iso_frame_desc[i].actual_length);
- if (buf->state == UVC_BUF_STATE_DONE ||
- buf->state == UVC_BUF_STATE_ERROR)
+ if (buf->state == UVC_BUF_STATE_READY)
buf = uvc_queue_next_buffer(&stream->queue, buf);
}
}
@@ -627,8 +636,7 @@ static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
if (!stream->bulk.skip_payload && buf != NULL) {
uvc_video_decode_end(stream, buf, stream->bulk.header,
stream->bulk.payload_size);
- if (buf->state == UVC_BUF_STATE_DONE ||
- buf->state == UVC_BUF_STATE_ERROR)
+ if (buf->state == UVC_BUF_STATE_READY)
buf = uvc_queue_next_buffer(&stream->queue,
buf);
}
@@ -669,7 +677,7 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
stream->bulk.payload_size == stream->bulk.max_payload_size) {
if (buf->buf.bytesused == stream->queue.buf_used) {
stream->queue.buf_used = 0;
- buf->state = UVC_BUF_STATE_DONE;
+ buf->state = UVC_BUF_STATE_READY;
uvc_queue_next_buffer(&stream->queue, buf);
stream->last_fid ^= UVC_STREAM_FID;
}
@@ -924,10 +932,8 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream,
static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
{
struct usb_interface *intf = stream->intf;
- struct usb_host_interface *alts;
- struct usb_host_endpoint *ep = NULL;
- int intfnum = stream->intfnum;
- unsigned int bandwidth, psize, i;
+ struct usb_host_endpoint *ep;
+ unsigned int i;
int ret;
stream->last_fid = -1;
@@ -936,6 +942,12 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
stream->bulk.payload_size = 0;
if (intf->num_altsetting > 1) {
+ struct usb_host_endpoint *best_ep = NULL;
+ unsigned int best_psize = 3 * 1024;
+ unsigned int bandwidth;
+ unsigned int uninitialized_var(altsetting);
+ int intfnum = stream->intfnum;
+
/* Isochronous endpoint, select the alternate setting. */
bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
@@ -949,6 +961,9 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
}
for (i = 0; i < intf->num_altsetting; ++i) {
+ struct usb_host_interface *alts;
+ unsigned int psize;
+
alts = &intf->altsetting[i];
ep = uvc_find_endpoint(alts,
stream->header.bEndpointAddress);
@@ -958,21 +973,27 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
/* Check if the bandwidth is high enough. */
psize = le16_to_cpu(ep->desc.wMaxPacketSize);
psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
- if (psize >= bandwidth)
- break;
+ if (psize >= bandwidth && psize <= best_psize) {
+ altsetting = i;
+ best_psize = psize;
+ best_ep = ep;
+ }
}
- if (i >= intf->num_altsetting) {
+ if (best_ep == NULL) {
uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting "
"for requested bandwidth.\n");
return -EIO;
}
- ret = usb_set_interface(stream->dev->udev, intfnum, i);
+ uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u "
+ "(%u B/frame bandwidth).\n", altsetting, best_psize);
+
+ ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
if (ret < 0)
return ret;
- ret = uvc_init_video_isoc(stream, ep, gfp_flags);
+ ret = uvc_init_video_isoc(stream, best_ep, gfp_flags);
} else {
/* Bulk endpoint, proceed to URB initialization. */
ep = uvc_find_endpoint(&intf->altsetting[0],
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 7ec9a04ced50..2bba059259e6 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -113,6 +113,9 @@ struct uvc_xu_control {
#define UVC_GUID_FORMAT_YUY2 \
{ 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2_ISIGHT \
+ { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9b, 0x71}
#define UVC_GUID_FORMAT_NV12 \
{ 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
@@ -149,7 +152,7 @@ struct uvc_xu_control {
#define UVC_MAX_STATUS_SIZE 16
#define UVC_CTRL_CONTROL_TIMEOUT 300
-#define UVC_CTRL_STREAMING_TIMEOUT 3000
+#define UVC_CTRL_STREAMING_TIMEOUT 5000
/* Devices quirks */
#define UVC_QUIRK_STATUS_INTERVAL 0x00000001
@@ -242,7 +245,8 @@ struct uvc_control {
uvc_control_info. */
__u8 dirty : 1,
loaded : 1,
- modified : 1;
+ modified : 1,
+ cached : 1;
__u8 *data;
};
@@ -365,8 +369,9 @@ enum uvc_buffer_state {
UVC_BUF_STATE_IDLE = 0,
UVC_BUF_STATE_QUEUED = 1,
UVC_BUF_STATE_ACTIVE = 2,
- UVC_BUF_STATE_DONE = 3,
- UVC_BUF_STATE_ERROR = 4,
+ UVC_BUF_STATE_READY = 3,
+ UVC_BUF_STATE_DONE = 4,
+ UVC_BUF_STATE_ERROR = 5,
};
struct uvc_buffer {
@@ -532,6 +537,7 @@ struct uvc_driver {
#define UVC_WARN_MINMAX 0
#define UVC_WARN_PROBE_DEF 1
+extern unsigned int uvc_clock_param;
extern unsigned int uvc_no_drop_param;
extern unsigned int uvc_trace_param;
extern unsigned int uvc_timeout_param;
@@ -551,16 +557,6 @@ extern unsigned int uvc_timeout_param;
#define uvc_printk(level, msg...) \
printk(level "uvcvideo: " msg)
-#define UVC_GUID_FORMAT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" \
- "%02x%02x%02x%02x%02x%02x"
-#define UVC_GUID_ARGS(guid) \
- (guid)[3], (guid)[2], (guid)[1], (guid)[0], \
- (guid)[5], (guid)[4], \
- (guid)[7], (guid)[6], \
- (guid)[8], (guid)[9], \
- (guid)[10], (guid)[11], (guid)[12], \
- (guid)[13], (guid)[14], (guid)[15]
-
/* --------------------------------------------------------------------------
* Internal functions.
*/
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index c4150bd26337..f77f84bfe714 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -288,7 +288,7 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user
static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
{
- if (copy_to_user(&up->w, &kp->w, sizeof(up->w)) ||
+ if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
put_user(kp->field, &up->field) ||
put_user(kp->chromakey, &up->chromakey) ||
put_user(kp->clipcount, &up->clipcount))
@@ -475,6 +475,9 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
return -EFAULT;
switch (kp->memory) {
case V4L2_MEMORY_MMAP:
+ if (get_user(kp->length, &up->length) ||
+ get_user(kp->m.offset, &up->m.offset))
+ return -EFAULT;
break;
case V4L2_MEMORY_USERPTR:
{
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index fa78555b118b..fcd045e7a1c1 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -418,6 +418,8 @@ static void *__videobuf_alloc(size_t size)
struct videobuf_buffer *vb;
vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
+ if (!vb)
+ return vb;
mem = vb->priv = ((char *)vb)+size;
mem->magic=MAGIC_SG_MEM;
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index d6e6a28fb6b8..136e09383c06 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -138,6 +138,8 @@ static void *__videobuf_alloc(size_t size)
struct videobuf_buffer *vb;
vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
+ if (!vb)
+ return vb;
mem = vb->priv = ((char *)vb)+size;
mem->magic=MAGIC_VMAL_MEM;
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 37632a064966..cdbe70385c12 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -1371,7 +1371,7 @@ static int __init vivi_create_instance(int inst)
/* Now that everything is fine, let's add it to device list */
list_add_tail(&dev->vivi_devlist, &vivi_devlist);
- if (video_nr >= 0)
+ if (video_nr != -1)
video_nr++;
dev->vfd = vfd;
diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig
index edb00293cd59..a7e610e0be9e 100644
--- a/drivers/media/video/zc0301/Kconfig
+++ b/drivers/media/video/zc0301/Kconfig
@@ -1,7 +1,11 @@
config USB_ZC0301
- tristate "USB ZC0301[P] Image Processor and Control Chip support"
+ tristate "USB ZC0301[P] webcam support (DEPRECATED)"
depends on VIDEO_V4L2
+ default n
---help---
+ This driver is DEPRECATED please use the gspca zc3xx module
+ instead.
+
Say Y here if you want support for cameras based on the ZC0301 or
ZC0301P Image Processors and Control Chips.
diff --git a/drivers/media/video/zoran/zoran_device.c b/drivers/media/video/zoran/zoran_device.c
index f6c2fb4fc3b4..e6ad4b205611 100644
--- a/drivers/media/video/zoran/zoran_device.c
+++ b/drivers/media/video/zoran/zoran_device.c
@@ -1196,7 +1196,8 @@ zoran_reap_stat_com (struct zoran *zr)
static void zoran_restart(struct zoran *zr)
{
/* Now the stat_comm buffer is ready for restart */
- int status = 0, mode;
+ unsigned int status = 0;
+ int mode;
if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
decoder_call(zr, video, g_input_status, &status);
@@ -1228,7 +1229,7 @@ error_handler (struct zoran *zr,
u32 astat,
u32 stat)
{
- int i, j;
+ int i;
/* This is JPEG error handling part */
if (zr->codec_mode != BUZ_MODE_MOTION_COMPRESS &&
@@ -1279,6 +1280,7 @@ error_handler (struct zoran *zr,
/* Report error */
if (zr36067_debug > 1 && zr->num_errors <= 8) {
long frame;
+ int j;
frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
printk(KERN_ERR
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
index 2ddffed019ee..ec41303544e5 100644
--- a/drivers/media/video/zoran/zoran_driver.c
+++ b/drivers/media/video/zoran/zoran_driver.c
@@ -324,7 +324,7 @@ static int jpg_fbuffer_alloc(struct zoran_fh *fh)
/* Allocate fragment table for this buffer */
mem = (void *)get_zeroed_page(GFP_KERNEL);
- if (mem == 0) {
+ if (!mem) {
dprintk(1,
KERN_ERR
"%s: %s - get_zeroed_page (frag_tab) failed for buffer %d\n",
@@ -1444,7 +1444,7 @@ zoran_set_norm (struct zoran *zr,
}
if (norm == V4L2_STD_ALL) {
- int status = 0;
+ unsigned int status = 0;
v4l2_std_id std = 0;
decoder_call(zr, video, querystd, &std);
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index f0eae83e3d89..3d4bac252902 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -78,6 +78,7 @@
#define METHOD0 0
#define METHOD1 1
#define METHOD2 2
+#define METHOD3 3
/* Module parameters */
@@ -114,7 +115,7 @@ static struct usb_device_id device_table[] = {
{USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 },
{USB_DEVICE(0x0a17, 0x004e), .driver_info = METHOD2 },
{USB_DEVICE(0x041e, 0x405d), .driver_info = METHOD2 },
- {USB_DEVICE(0x08ca, 0x2102), .driver_info = METHOD2 },
+ {USB_DEVICE(0x08ca, 0x2102), .driver_info = METHOD3 },
{USB_DEVICE(0x06d6, 0x003d), .driver_info = METHOD0 },
{} /* Terminating entry */
};
@@ -302,7 +303,7 @@ static message m2[] = {
};
/* init table */
-static message *init[3] = { m0, m1, m2 };
+static message *init[4] = { m0, m1, m2, m2 };
/* JPEG static data in header (Huffman table, etc) */
@@ -967,6 +968,22 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
m0d1[0] = mode;
m1[2].value = 0xf000 + mode;
m2[1].value = 0xf000 + mode;
+
+ /* special case for METHOD3, the modes are different */
+ if (cam->method == METHOD3) {
+ switch (mode) {
+ case 1:
+ m2[1].value = 0xf000 + 4;
+ break;
+ case 2:
+ m2[1].value = 0xf000 + 0;
+ break;
+ default:
+ m2[1].value = 0xf000 + 1;
+ break;
+ }
+ }
+
header2[437] = cam->height / 256;
header2[438] = cam->height % 256;
header2[439] = cam->width / 256;
@@ -1582,6 +1599,22 @@ static int zr364xx_probe(struct usb_interface *intf,
m0d1[0] = mode;
m1[2].value = 0xf000 + mode;
m2[1].value = 0xf000 + mode;
+
+ /* special case for METHOD3, the modes are different */
+ if (cam->method == METHOD3) {
+ switch (mode) {
+ case 1:
+ m2[1].value = 0xf000 + 4;
+ break;
+ case 2:
+ m2[1].value = 0xf000 + 0;
+ break;
+ default:
+ m2[1].value = 0xf000 + 1;
+ break;
+ }
+ }
+
header2[437] = cam->height / 256;
header2[438] = cam->height % 256;
header2[439] = cam->width / 256;
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index bd83fa0a4970..972b87069d55 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -1226,9 +1226,8 @@ static int mspro_block_init_disk(struct memstick_dev *card)
blk_queue_prep_rq(msb->queue, mspro_block_prepare_req);
blk_queue_bounce_limit(msb->queue, limit);
- blk_queue_max_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES);
- blk_queue_max_phys_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS);
- blk_queue_max_hw_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS);
+ blk_queue_max_hw_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES);
+ blk_queue_max_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS);
blk_queue_max_segment_size(msb->queue,
MSPRO_BLOCK_MAX_PAGES * msb->page_size);
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 85bc6a685e36..5382b5a44aff 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -126,8 +126,6 @@ static int mfcounter = 0;
* Public data...
*/
-static struct proc_dir_entry *mpt_proc_root_dir;
-
#define WHOINIT_UNKNOWN 0xAA
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -146,6 +144,9 @@ static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *mpt_proc_root_dir;
+#endif
/*
* Driver Callback Index's
@@ -4330,6 +4331,8 @@ initChainBuffers(MPT_ADAPTER *ioc)
if (ioc->bus_type == SPI)
num_chain *= MPT_SCSI_CAN_QUEUE;
+ else if (ioc->bus_type == SAS)
+ num_chain *= MPT_SAS_CAN_QUEUE;
else
num_chain *= MPT_FC_CAN_QUEUE;
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index b4948671eb92..9718c8f2e959 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -76,8 +76,8 @@
#define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.04.13"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.13"
+#define MPT_LINUX_VERSION_COMMON "3.04.14"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.14"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 352acd05c46b..caa8f568a41c 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -360,8 +360,8 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
u16 iocstatus;
/* bus reset is only good for SCSI IO, RAID PASSTHRU */
- if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) ||
- (function == MPI_FUNCTION_SCSI_IO_REQUEST)) {
+ if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
+ function == MPI_FUNCTION_SCSI_IO_REQUEST)) {
dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
"TaskMgmt, not SCSI_IO!!\n", ioc->name));
return -EPERM;
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index ebf6ae024da4..612ab3c51a6b 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -195,29 +195,34 @@ mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
unsigned long flags;
int ready;
MPT_ADAPTER *ioc;
+ int loops = 40; /* seconds */
hd = shost_priv(SCpnt->device->host);
ioc = hd->ioc;
spin_lock_irqsave(shost->host_lock, flags);
- while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
+ while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY
+ || (loops > 0 && ioc->active == 0)) {
spin_unlock_irqrestore(shost->host_lock, flags);
dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
"mptfc_block_error_handler.%d: %d:%d, port status is "
- "DID_IMM_RETRY, deferring %s recovery.\n",
+ "%x, active flag %d, deferring %s recovery.\n",
ioc->name, ioc->sh->host_no,
- SCpnt->device->id, SCpnt->device->lun, caller));
+ SCpnt->device->id, SCpnt->device->lun,
+ ready, ioc->active, caller));
msleep(1000);
spin_lock_irqsave(shost->host_lock, flags);
+ loops --;
}
spin_unlock_irqrestore(shost->host_lock, flags);
- if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
+ if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata
+ || ioc->active == 0) {
dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
"%s.%d: %d:%d, failing recovery, "
- "port state %d, vdevice %p.\n", caller,
+ "port state %x, active %d, vdevice %p.\n", caller,
ioc->name, ioc->sh->host_no,
SCpnt->device->id, SCpnt->device->lun, ready,
- SCpnt->device->hostdata));
+ ioc->active, SCpnt->device->hostdata));
return FAILED;
}
dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 83873e3d0ce7..c20bbe45da82 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -1075,6 +1075,19 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
return 0;
}
+static void
+mptsas_block_io_sdev(struct scsi_device *sdev, void *data)
+{
+ scsi_device_set_state(sdev, SDEV_BLOCK);
+}
+
+static void
+mptsas_block_io_starget(struct scsi_target *starget)
+{
+ if (starget)
+ starget_for_each_device(starget, NULL, mptsas_block_io_sdev);
+}
+
/**
* mptsas_target_reset_queue
*
@@ -1098,10 +1111,11 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
id = sas_event_data->TargetID;
channel = sas_event_data->Bus;
- if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
- return;
-
- vtarget->deleted = 1; /* block IO */
+ vtarget = mptsas_find_vtarget(ioc, channel, id);
+ if (vtarget) {
+ mptsas_block_io_starget(vtarget->starget);
+ vtarget->deleted = 1; /* block IO */
+ }
target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
GFP_ATOMIC);
@@ -1868,7 +1882,8 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
if (ioc->sas_discovery_quiesce_io)
return SCSI_MLQUEUE_HOST_BUSY;
-// scsi_print_command(SCpnt);
+ if (ioc->debug_level & MPT_DEBUG_SCSI)
+ scsi_print_command(SCpnt);
return mptscsih_qcmd(SCpnt,done);
}
@@ -2686,6 +2701,187 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
return error;
}
+struct rep_manu_request{
+ u8 smp_frame_type;
+ u8 function;
+ u8 reserved;
+ u8 request_length;
+};
+
+struct rep_manu_reply{
+ u8 smp_frame_type; /* 0x41 */
+ u8 function; /* 0x01 */
+ u8 function_result;
+ u8 response_length;
+ u16 expander_change_count;
+ u8 reserved0[2];
+ u8 sas_format:1;
+ u8 reserved1:7;
+ u8 reserved2[3];
+ u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
+ u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
+ u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
+ u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
+ u16 component_id;
+ u8 component_revision_id;
+ u8 reserved3;
+ u8 vendor_specific[8];
+};
+
+/**
+ * mptsas_exp_repmanufacture_info -
+ * @ioc: per adapter object
+ * @sas_address: expander sas address
+ * @edev: the sas_expander_device object
+ *
+ * Fills in the sas_expander_device object when SMP port is created.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
+ u64 sas_address, struct sas_expander_device *edev)
+{
+ MPT_FRAME_HDR *mf;
+ SmpPassthroughRequest_t *smpreq;
+ SmpPassthroughReply_t *smprep;
+ struct rep_manu_reply *manufacture_reply;
+ struct rep_manu_request *manufacture_request;
+ int ret;
+ int flagsLength;
+ unsigned long timeleft;
+ char *psge;
+ unsigned long flags;
+ void *data_out = NULL;
+ dma_addr_t data_out_dma = 0;
+ u32 sz;
+
+ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+ if (ioc->ioc_reset_in_progress) {
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+ printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
+ __func__, ioc->name);
+ return -EFAULT;
+ }
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+ ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
+ if (ret)
+ goto out;
+
+ mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
+ if (!mf) {
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+
+ smpreq = (SmpPassthroughRequest_t *)mf;
+ memset(smpreq, 0, sizeof(*smpreq));
+
+ sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
+
+ data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma);
+ if (!data_out) {
+ printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
+ ret = -ENOMEM;
+ goto put_mf;
+ }
+
+ manufacture_request = data_out;
+ manufacture_request->smp_frame_type = 0x40;
+ manufacture_request->function = 1;
+ manufacture_request->reserved = 0;
+ manufacture_request->request_length = 0;
+
+ smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
+ smpreq->PhysicalPort = 0xFF;
+ *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
+ smpreq->RequestDataLength = sizeof(struct rep_manu_request);
+
+ psge = (char *)
+ (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
+
+ flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+ MPI_SGE_FLAGS_HOST_TO_IOC |
+ MPI_SGE_FLAGS_END_OF_BUFFER;
+ flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
+ flagsLength |= sizeof(struct rep_manu_request);
+
+ ioc->add_sge(psge, flagsLength, data_out_dma);
+ psge += ioc->SGE_size;
+
+ flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+ MPI_SGE_FLAGS_IOC_TO_HOST |
+ MPI_SGE_FLAGS_END_OF_BUFFER;
+ flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
+ flagsLength |= sizeof(struct rep_manu_reply);
+ ioc->add_sge(psge, flagsLength, data_out_dma +
+ sizeof(struct rep_manu_request));
+
+ INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
+ mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
+
+ timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
+ if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+ ret = -ETIME;
+ mpt_free_msg_frame(ioc, mf);
+ mf = NULL;
+ if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
+ goto out_free;
+ if (!timeleft)
+ mpt_HardResetHandler(ioc, CAN_SLEEP);
+ goto out_free;
+ }
+
+ mf = NULL;
+
+ if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
+ u8 *tmp;
+
+ smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
+ if (le16_to_cpu(smprep->ResponseDataLength) !=
+ sizeof(struct rep_manu_reply))
+ goto out_free;
+
+ manufacture_reply = data_out + sizeof(struct rep_manu_request);
+ strncpy(edev->vendor_id, manufacture_reply->vendor_id,
+ SAS_EXPANDER_VENDOR_ID_LEN);
+ strncpy(edev->product_id, manufacture_reply->product_id,
+ SAS_EXPANDER_PRODUCT_ID_LEN);
+ strncpy(edev->product_rev, manufacture_reply->product_rev,
+ SAS_EXPANDER_PRODUCT_REV_LEN);
+ edev->level = manufacture_reply->sas_format;
+ if (manufacture_reply->sas_format) {
+ strncpy(edev->component_vendor_id,
+ manufacture_reply->component_vendor_id,
+ SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
+ tmp = (u8 *)&manufacture_reply->component_id;
+ edev->component_id = tmp[0] << 8 | tmp[1];
+ edev->component_revision_id =
+ manufacture_reply->component_revision_id;
+ }
+ } else {
+ printk(MYIOC_s_ERR_FMT
+ "%s: smp passthru reply failed to be returned\n",
+ ioc->name, __func__);
+ ret = -ENXIO;
+ }
+out_free:
+ if (data_out_dma)
+ pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma);
+put_mf:
+ if (mf)
+ mpt_free_msg_frame(ioc, mf);
+out_unlock:
+ CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
+ mutex_unlock(&ioc->sas_mgmt.mutex);
+out:
+ return ret;
+ }
+
static void
mptsas_parse_device_info(struct sas_identify *identify,
struct mptsas_devinfo *device_info)
@@ -2967,6 +3163,11 @@ static int mptsas_probe_one_phy(struct device *dev,
goto out;
}
mptsas_set_rphy(ioc, phy_info, rphy);
+ if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
+ identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
+ mptsas_exp_repmanufacture_info(ioc,
+ identify.sas_address,
+ rphy_to_expander_device(rphy));
}
out:
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 57752751712b..4a7d1afcb666 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -1438,9 +1438,14 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
&& (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
&& (SCpnt->device->tagged_supported)) {
scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
- } else {
+ if (SCpnt->request && SCpnt->request->ioprio) {
+ if (((SCpnt->request->ioprio & 0x7) == 1) ||
+ !(SCpnt->request->ioprio & 0x7))
+ scsictl |= MPI_SCSIIO_CONTROL_HEADOFQ;
+ }
+ } else
scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
- }
+
/* Use the above information to set up the message frame
*/
@@ -1796,7 +1801,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
"Command not in the active list! (sc=%p)\n", ioc->name,
SCpnt));
- retval = 0;
+ retval = SUCCESS;
goto out;
}
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index e39986a78273..2658b1484a2c 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -1065,9 +1065,8 @@ static int i2o_block_probe(struct device *dev)
queue = gd->queue;
queue->queuedata = i2o_blk_dev;
- blk_queue_max_phys_segments(queue, I2O_MAX_PHYS_SEGMENTS);
- blk_queue_max_sectors(queue, max_sectors);
- blk_queue_max_hw_segments(queue, i2o_sg_tablesize(c, body_size));
+ blk_queue_max_hw_sectors(queue, max_sectors);
+ blk_queue_max_segments(queue, i2o_sg_tablesize(c, body_size));
osm_debug("max sectors = %d\n", queue->max_sectors);
osm_debug("phys segments = %d\n", queue->max_phys_segments);
diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c
index 7045c45da9b1..949a648f8e2e 100644
--- a/drivers/message/i2o/i2o_proc.c
+++ b/drivers/message/i2o/i2o_proc.c
@@ -111,10 +111,7 @@ static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len)
break;
case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */
- seq_printf(seq,
- "LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X",
- serialno[2], serialno[3],
- serialno[4], serialno[5], serialno[6], serialno[7]);
+ seq_printf(seq, "LAN-48 MAC address @ %pM", &serialno[2]);
break;
case I2O_SNFORMAT_WAN: /* WAN MAC Address */
@@ -126,10 +123,8 @@ static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len)
case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */
/* FIXME: Figure out what a LAN-64 address really looks like?? */
seq_printf(seq,
- "LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X",
- serialno[8], serialno[9],
- serialno[2], serialno[3],
- serialno[4], serialno[5], serialno[6], serialno[7]);
+ "LAN-64 MAC address @ [?:%02X:%02X:?] %pM",
+ serialno[8], serialno[9], &serialno[2]);
break;
case I2O_SNFORMAT_DDM: /* I2O DDM */
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
index e5ab62141503..ef5ce2676f05 100644
--- a/drivers/message/i2o/iop.c
+++ b/drivers/message/i2o/iop.c
@@ -539,7 +539,7 @@ static int i2o_iop_reset(struct i2o_controller *c)
* which is indeterminate. We need to wait until the IOP has
* rebooted before we can let the system talk to it. We read
* the inbound Free_List until a message is available. If we
- * can't read one in the given ammount of time, we assume the
+ * can't read one in the given amount of time, we assume the
* IOP could not reboot properly.
*/
osm_debug("%s: Reset in progress, waiting for reboot...\n",
diff --git a/drivers/mfd/88pm8607.c b/drivers/mfd/88pm8607.c
deleted file mode 100644
index 7e3f65907993..000000000000
--- a/drivers/mfd/88pm8607.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Base driver for Marvell 88PM8607
- *
- * Copyright (C) 2009 Marvell International Ltd.
- * Haojian Zhuang <haojian.zhuang@marvell.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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/88pm8607.h>
-
-
-#define PM8607_REG_RESOURCE(_start, _end) \
-{ \
- .start = PM8607_##_start, \
- .end = PM8607_##_end, \
- .flags = IORESOURCE_IO, \
-}
-
-static struct resource pm8607_regulator_resources[] = {
- PM8607_REG_RESOURCE(BUCK1, BUCK1),
- PM8607_REG_RESOURCE(BUCK2, BUCK2),
- PM8607_REG_RESOURCE(BUCK3, BUCK3),
- PM8607_REG_RESOURCE(LDO1, LDO1),
- PM8607_REG_RESOURCE(LDO2, LDO2),
- PM8607_REG_RESOURCE(LDO3, LDO3),
- PM8607_REG_RESOURCE(LDO4, LDO4),
- PM8607_REG_RESOURCE(LDO5, LDO5),
- PM8607_REG_RESOURCE(LDO6, LDO6),
- PM8607_REG_RESOURCE(LDO7, LDO7),
- PM8607_REG_RESOURCE(LDO8, LDO8),
- PM8607_REG_RESOURCE(LDO9, LDO9),
- PM8607_REG_RESOURCE(LDO10, LDO10),
- PM8607_REG_RESOURCE(LDO12, LDO12),
- PM8607_REG_RESOURCE(LDO14, LDO14),
-};
-
-#define PM8607_REG_DEVS(_name, _id) \
-{ \
- .name = "88pm8607-" #_name, \
- .num_resources = 1, \
- .resources = &pm8607_regulator_resources[PM8607_ID_##_id], \
-}
-
-static struct mfd_cell pm8607_devs[] = {
- PM8607_REG_DEVS(buck1, BUCK1),
- PM8607_REG_DEVS(buck2, BUCK2),
- PM8607_REG_DEVS(buck3, BUCK3),
- PM8607_REG_DEVS(ldo1, LDO1),
- PM8607_REG_DEVS(ldo2, LDO2),
- PM8607_REG_DEVS(ldo3, LDO3),
- PM8607_REG_DEVS(ldo4, LDO4),
- PM8607_REG_DEVS(ldo5, LDO5),
- PM8607_REG_DEVS(ldo6, LDO6),
- PM8607_REG_DEVS(ldo7, LDO7),
- PM8607_REG_DEVS(ldo8, LDO8),
- PM8607_REG_DEVS(ldo9, LDO9),
- PM8607_REG_DEVS(ldo10, LDO10),
- PM8607_REG_DEVS(ldo12, LDO12),
- PM8607_REG_DEVS(ldo14, LDO14),
-};
-
-static inline int pm8607_read_device(struct pm8607_chip *chip,
- int reg, int bytes, void *dest)
-{
- struct i2c_client *i2c = chip->client;
- unsigned char data;
- int ret;
-
- data = (unsigned char)reg;
- ret = i2c_master_send(i2c, &data, 1);
- if (ret < 0)
- return ret;
-
- ret = i2c_master_recv(i2c, dest, bytes);
- if (ret < 0)
- return ret;
- return 0;
-}
-
-static inline int pm8607_write_device(struct pm8607_chip *chip,
- int reg, int bytes, void *src)
-{
- struct i2c_client *i2c = chip->client;
- unsigned char buf[bytes + 1];
- int ret;
-
- buf[0] = (unsigned char)reg;
- memcpy(&buf[1], src, bytes);
-
- ret = i2c_master_send(i2c, buf, bytes + 1);
- if (ret < 0)
- return ret;
- return 0;
-}
-
-int pm8607_reg_read(struct pm8607_chip *chip, int reg)
-{
- unsigned char data;
- int ret;
-
- mutex_lock(&chip->io_lock);
- ret = chip->read(chip, reg, 1, &data);
- mutex_unlock(&chip->io_lock);
-
- if (ret < 0)
- return ret;
- else
- return (int)data;
-}
-EXPORT_SYMBOL(pm8607_reg_read);
-
-int pm8607_reg_write(struct pm8607_chip *chip, int reg,
- unsigned char data)
-{
- int ret;
-
- mutex_lock(&chip->io_lock);
- ret = chip->write(chip, reg, 1, &data);
- mutex_unlock(&chip->io_lock);
-
- return ret;
-}
-EXPORT_SYMBOL(pm8607_reg_write);
-
-int pm8607_bulk_read(struct pm8607_chip *chip, int reg,
- int count, unsigned char *buf)
-{
- int ret;
-
- mutex_lock(&chip->io_lock);
- ret = chip->read(chip, reg, count, buf);
- mutex_unlock(&chip->io_lock);
-
- return ret;
-}
-EXPORT_SYMBOL(pm8607_bulk_read);
-
-int pm8607_bulk_write(struct pm8607_chip *chip, int reg,
- int count, unsigned char *buf)
-{
- int ret;
-
- mutex_lock(&chip->io_lock);
- ret = chip->write(chip, reg, count, buf);
- mutex_unlock(&chip->io_lock);
-
- return ret;
-}
-EXPORT_SYMBOL(pm8607_bulk_write);
-
-int pm8607_set_bits(struct pm8607_chip *chip, int reg,
- unsigned char mask, unsigned char data)
-{
- unsigned char value;
- int ret;
-
- mutex_lock(&chip->io_lock);
- ret = chip->read(chip, reg, 1, &value);
- if (ret < 0)
- goto out;
- value &= ~mask;
- value |= data;
- ret = chip->write(chip, reg, 1, &value);
-out:
- mutex_unlock(&chip->io_lock);
- return ret;
-}
-EXPORT_SYMBOL(pm8607_set_bits);
-
-
-static const struct i2c_device_id pm8607_id_table[] = {
- { "88PM8607", 0 },
- {}
-};
-MODULE_DEVICE_TABLE(i2c, pm8607_id_table);
-
-
-static int __devinit pm8607_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct pm8607_platform_data *pdata = client->dev.platform_data;
- struct pm8607_chip *chip;
- int i, count;
- int ret;
-
- chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL);
- if (chip == NULL)
- return -ENOMEM;
-
- chip->client = client;
- chip->dev = &client->dev;
- chip->read = pm8607_read_device;
- chip->write = pm8607_write_device;
- i2c_set_clientdata(client, chip);
-
- mutex_init(&chip->io_lock);
- dev_set_drvdata(chip->dev, chip);
-
- ret = pm8607_reg_read(chip, PM8607_CHIP_ID);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
- goto out;
- }
- if ((ret & CHIP_ID_MASK) == CHIP_ID)
- dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
- ret);
- else {
- dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
- "Chip ID: %02x\n", ret);
- goto out;
- }
- chip->chip_id = ret;
-
- ret = pm8607_reg_read(chip, PM8607_BUCK3);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
- goto out;
- }
- if (ret & PM8607_BUCK3_DOUBLE)
- chip->buck3_double = 1;
-
- ret = pm8607_reg_read(chip, PM8607_MISC1);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
- goto out;
- }
- if (pdata->i2c_port == PI2C_PORT)
- ret |= PM8607_MISC1_PI2C;
- else
- ret &= ~PM8607_MISC1_PI2C;
- ret = pm8607_reg_write(chip, PM8607_MISC1, ret);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret);
- goto out;
- }
-
-
- count = ARRAY_SIZE(pm8607_devs);
- for (i = 0; i < count; i++) {
- ret = mfd_add_devices(chip->dev, i, &pm8607_devs[i],
- 1, NULL, 0);
- if (ret != 0) {
- dev_err(chip->dev, "Failed to add subdevs\n");
- goto out;
- }
- }
-
- return 0;
-
-out:
- i2c_set_clientdata(client, NULL);
- kfree(chip);
- return ret;
-}
-
-static int __devexit pm8607_remove(struct i2c_client *client)
-{
- struct pm8607_chip *chip = i2c_get_clientdata(client);
-
- mfd_remove_devices(chip->dev);
- kfree(chip);
- return 0;
-}
-
-static struct i2c_driver pm8607_driver = {
- .driver = {
- .name = "88PM8607",
- .owner = THIS_MODULE,
- },
- .probe = pm8607_probe,
- .remove = __devexit_p(pm8607_remove),
- .id_table = pm8607_id_table,
-};
-
-static int __init pm8607_init(void)
-{
- int ret;
- ret = i2c_add_driver(&pm8607_driver);
- if (ret != 0)
- pr_err("Failed to register 88PM8607 I2C driver: %d\n", ret);
- return ret;
-}
-subsys_initcall(pm8607_init);
-
-static void __exit pm8607_exit(void)
-{
- i2c_del_driver(&pm8607_driver);
-}
-module_exit(pm8607_exit);
-
-MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM8607");
-MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
new file mode 100644
index 000000000000..6a14d2b1ccf0
--- /dev/null
+++ b/drivers/mfd/88pm860x-core.c
@@ -0,0 +1,740 @@
+/*
+ * Base driver for Marvell 88PM8607
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/88pm860x.h>
+
+#define INT_STATUS_NUM 3
+
+char pm860x_backlight_name[][MFD_NAME_SIZE] = {
+ "backlight-0",
+ "backlight-1",
+ "backlight-2",
+};
+EXPORT_SYMBOL(pm860x_backlight_name);
+
+char pm860x_led_name[][MFD_NAME_SIZE] = {
+ "led0-red",
+ "led0-green",
+ "led0-blue",
+ "led1-red",
+ "led1-green",
+ "led1-blue",
+};
+EXPORT_SYMBOL(pm860x_led_name);
+
+#define PM8606_BACKLIGHT_RESOURCE(_i, _x) \
+{ \
+ .name = pm860x_backlight_name[_i], \
+ .start = PM8606_##_x, \
+ .end = PM8606_##_x, \
+ .flags = IORESOURCE_IO, \
+}
+
+static struct resource backlight_resources[] = {
+ PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT1, WLED1A),
+ PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT2, WLED2A),
+ PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT3, WLED3A),
+};
+
+#define PM8606_BACKLIGHT_DEVS(_i) \
+{ \
+ .name = "88pm860x-backlight", \
+ .num_resources = 1, \
+ .resources = &backlight_resources[_i], \
+ .id = _i, \
+}
+
+static struct mfd_cell backlight_devs[] = {
+ PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT1),
+ PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT2),
+ PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT3),
+};
+
+#define PM8606_LED_RESOURCE(_i, _x) \
+{ \
+ .name = pm860x_led_name[_i], \
+ .start = PM8606_##_x, \
+ .end = PM8606_##_x, \
+ .flags = IORESOURCE_IO, \
+}
+
+static struct resource led_resources[] = {
+ PM8606_LED_RESOURCE(PM8606_LED1_RED, RGB2B),
+ PM8606_LED_RESOURCE(PM8606_LED1_GREEN, RGB2C),
+ PM8606_LED_RESOURCE(PM8606_LED1_BLUE, RGB2D),
+ PM8606_LED_RESOURCE(PM8606_LED2_RED, RGB1B),
+ PM8606_LED_RESOURCE(PM8606_LED2_GREEN, RGB1C),
+ PM8606_LED_RESOURCE(PM8606_LED2_BLUE, RGB1D),
+};
+
+#define PM8606_LED_DEVS(_i) \
+{ \
+ .name = "88pm860x-led", \
+ .num_resources = 1, \
+ .resources = &led_resources[_i], \
+ .id = _i, \
+}
+
+static struct mfd_cell led_devs[] = {
+ PM8606_LED_DEVS(PM8606_LED1_RED),
+ PM8606_LED_DEVS(PM8606_LED1_GREEN),
+ PM8606_LED_DEVS(PM8606_LED1_BLUE),
+ PM8606_LED_DEVS(PM8606_LED2_RED),
+ PM8606_LED_DEVS(PM8606_LED2_GREEN),
+ PM8606_LED_DEVS(PM8606_LED2_BLUE),
+};
+
+static struct resource touch_resources[] = {
+ {
+ .start = PM8607_IRQ_PEN,
+ .end = PM8607_IRQ_PEN,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell touch_devs[] = {
+ {
+ .name = "88pm860x-touch",
+ .num_resources = 1,
+ .resources = &touch_resources[0],
+ },
+};
+
+#define PM8607_REG_RESOURCE(_start, _end) \
+{ \
+ .start = PM8607_##_start, \
+ .end = PM8607_##_end, \
+ .flags = IORESOURCE_IO, \
+}
+
+static struct resource power_supply_resources[] = {
+ {
+ .name = "88pm860x-power",
+ .start = PM8607_IRQ_CHG,
+ .end = PM8607_IRQ_CHG,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell power_devs[] = {
+ {
+ .name = "88pm860x-power",
+ .num_resources = 1,
+ .resources = &power_supply_resources[0],
+ .id = -1,
+ },
+};
+
+static struct resource onkey_resources[] = {
+ {
+ .name = "88pm860x-onkey",
+ .start = PM8607_IRQ_ONKEY,
+ .end = PM8607_IRQ_ONKEY,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell onkey_devs[] = {
+ {
+ .name = "88pm860x-onkey",
+ .num_resources = 1,
+ .resources = &onkey_resources[0],
+ .id = -1,
+ },
+};
+
+static struct resource regulator_resources[] = {
+ PM8607_REG_RESOURCE(BUCK1, BUCK1),
+ PM8607_REG_RESOURCE(BUCK2, BUCK2),
+ PM8607_REG_RESOURCE(BUCK3, BUCK3),
+ PM8607_REG_RESOURCE(LDO1, LDO1),
+ PM8607_REG_RESOURCE(LDO2, LDO2),
+ PM8607_REG_RESOURCE(LDO3, LDO3),
+ PM8607_REG_RESOURCE(LDO4, LDO4),
+ PM8607_REG_RESOURCE(LDO5, LDO5),
+ PM8607_REG_RESOURCE(LDO6, LDO6),
+ PM8607_REG_RESOURCE(LDO7, LDO7),
+ PM8607_REG_RESOURCE(LDO8, LDO8),
+ PM8607_REG_RESOURCE(LDO9, LDO9),
+ PM8607_REG_RESOURCE(LDO10, LDO10),
+ PM8607_REG_RESOURCE(LDO12, LDO12),
+ PM8607_REG_RESOURCE(LDO14, LDO14),
+};
+
+#define PM8607_REG_DEVS(_name, _id) \
+{ \
+ .name = "88pm8607-" #_name, \
+ .num_resources = 1, \
+ .resources = &regulator_resources[PM8607_ID_##_id], \
+ .id = PM8607_ID_##_id, \
+}
+
+static struct mfd_cell regulator_devs[] = {
+ PM8607_REG_DEVS(buck1, BUCK1),
+ PM8607_REG_DEVS(buck2, BUCK2),
+ PM8607_REG_DEVS(buck3, BUCK3),
+ PM8607_REG_DEVS(ldo1, LDO1),
+ PM8607_REG_DEVS(ldo2, LDO2),
+ PM8607_REG_DEVS(ldo3, LDO3),
+ PM8607_REG_DEVS(ldo4, LDO4),
+ PM8607_REG_DEVS(ldo5, LDO5),
+ PM8607_REG_DEVS(ldo6, LDO6),
+ PM8607_REG_DEVS(ldo7, LDO7),
+ PM8607_REG_DEVS(ldo8, LDO8),
+ PM8607_REG_DEVS(ldo9, LDO9),
+ PM8607_REG_DEVS(ldo10, LDO10),
+ PM8607_REG_DEVS(ldo12, LDO12),
+ PM8607_REG_DEVS(ldo14, LDO14),
+};
+
+struct pm860x_irq_data {
+ int reg;
+ int mask_reg;
+ int enable; /* enable or not */
+ int offs; /* bit offset in mask register */
+};
+
+static struct pm860x_irq_data pm860x_irqs[] = {
+ [PM8607_IRQ_ONKEY] = {
+ .reg = PM8607_INT_STATUS1,
+ .mask_reg = PM8607_INT_MASK_1,
+ .offs = 1 << 0,
+ },
+ [PM8607_IRQ_EXTON] = {
+ .reg = PM8607_INT_STATUS1,
+ .mask_reg = PM8607_INT_MASK_1,
+ .offs = 1 << 1,
+ },
+ [PM8607_IRQ_CHG] = {
+ .reg = PM8607_INT_STATUS1,
+ .mask_reg = PM8607_INT_MASK_1,
+ .offs = 1 << 2,
+ },
+ [PM8607_IRQ_BAT] = {
+ .reg = PM8607_INT_STATUS1,
+ .mask_reg = PM8607_INT_MASK_1,
+ .offs = 1 << 3,
+ },
+ [PM8607_IRQ_RTC] = {
+ .reg = PM8607_INT_STATUS1,
+ .mask_reg = PM8607_INT_MASK_1,
+ .offs = 1 << 4,
+ },
+ [PM8607_IRQ_CC] = {
+ .reg = PM8607_INT_STATUS1,
+ .mask_reg = PM8607_INT_MASK_1,
+ .offs = 1 << 5,
+ },
+ [PM8607_IRQ_VBAT] = {
+ .reg = PM8607_INT_STATUS2,
+ .mask_reg = PM8607_INT_MASK_2,
+ .offs = 1 << 0,
+ },
+ [PM8607_IRQ_VCHG] = {
+ .reg = PM8607_INT_STATUS2,
+ .mask_reg = PM8607_INT_MASK_2,
+ .offs = 1 << 1,
+ },
+ [PM8607_IRQ_VSYS] = {
+ .reg = PM8607_INT_STATUS2,
+ .mask_reg = PM8607_INT_MASK_2,
+ .offs = 1 << 2,
+ },
+ [PM8607_IRQ_TINT] = {
+ .reg = PM8607_INT_STATUS2,
+ .mask_reg = PM8607_INT_MASK_2,
+ .offs = 1 << 3,
+ },
+ [PM8607_IRQ_GPADC0] = {
+ .reg = PM8607_INT_STATUS2,
+ .mask_reg = PM8607_INT_MASK_2,
+ .offs = 1 << 4,
+ },
+ [PM8607_IRQ_GPADC1] = {
+ .reg = PM8607_INT_STATUS2,
+ .mask_reg = PM8607_INT_MASK_2,
+ .offs = 1 << 5,
+ },
+ [PM8607_IRQ_GPADC2] = {
+ .reg = PM8607_INT_STATUS2,
+ .mask_reg = PM8607_INT_MASK_2,
+ .offs = 1 << 6,
+ },
+ [PM8607_IRQ_GPADC3] = {
+ .reg = PM8607_INT_STATUS2,
+ .mask_reg = PM8607_INT_MASK_2,
+ .offs = 1 << 7,
+ },
+ [PM8607_IRQ_AUDIO_SHORT] = {
+ .reg = PM8607_INT_STATUS3,
+ .mask_reg = PM8607_INT_MASK_3,
+ .offs = 1 << 0,
+ },
+ [PM8607_IRQ_PEN] = {
+ .reg = PM8607_INT_STATUS3,
+ .mask_reg = PM8607_INT_MASK_3,
+ .offs = 1 << 1,
+ },
+ [PM8607_IRQ_HEADSET] = {
+ .reg = PM8607_INT_STATUS3,
+ .mask_reg = PM8607_INT_MASK_3,
+ .offs = 1 << 2,
+ },
+ [PM8607_IRQ_HOOK] = {
+ .reg = PM8607_INT_STATUS3,
+ .mask_reg = PM8607_INT_MASK_3,
+ .offs = 1 << 3,
+ },
+ [PM8607_IRQ_MICIN] = {
+ .reg = PM8607_INT_STATUS3,
+ .mask_reg = PM8607_INT_MASK_3,
+ .offs = 1 << 4,
+ },
+ [PM8607_IRQ_CHG_FAIL] = {
+ .reg = PM8607_INT_STATUS3,
+ .mask_reg = PM8607_INT_MASK_3,
+ .offs = 1 << 5,
+ },
+ [PM8607_IRQ_CHG_DONE] = {
+ .reg = PM8607_INT_STATUS3,
+ .mask_reg = PM8607_INT_MASK_3,
+ .offs = 1 << 6,
+ },
+ [PM8607_IRQ_CHG_FAULT] = {
+ .reg = PM8607_INT_STATUS3,
+ .mask_reg = PM8607_INT_MASK_3,
+ .offs = 1 << 7,
+ },
+};
+
+static inline struct pm860x_irq_data *irq_to_pm860x(struct pm860x_chip *chip,
+ int irq)
+{
+ return &pm860x_irqs[irq - chip->irq_base];
+}
+
+static irqreturn_t pm860x_irq(int irq, void *data)
+{
+ struct pm860x_chip *chip = data;
+ struct pm860x_irq_data *irq_data;
+ struct i2c_client *i2c;
+ int read_reg = -1, value = 0;
+ int i;
+
+ i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
+ for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
+ irq_data = &pm860x_irqs[i];
+ if (read_reg != irq_data->reg) {
+ read_reg = irq_data->reg;
+ value = pm860x_reg_read(i2c, irq_data->reg);
+ }
+ if (value & irq_data->enable)
+ handle_nested_irq(chip->irq_base + i);
+ }
+ return IRQ_HANDLED;
+}
+
+static void pm860x_irq_lock(unsigned int irq)
+{
+ struct pm860x_chip *chip = get_irq_chip_data(irq);
+
+ mutex_lock(&chip->irq_lock);
+}
+
+static void pm860x_irq_sync_unlock(unsigned int irq)
+{
+ struct pm860x_chip *chip = get_irq_chip_data(irq);
+ struct pm860x_irq_data *irq_data;
+ struct i2c_client *i2c;
+ static unsigned char cached[3] = {0x0, 0x0, 0x0};
+ unsigned char mask[3];
+ int i;
+
+ i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
+ /* Load cached value. In initial, all IRQs are masked */
+ for (i = 0; i < 3; i++)
+ mask[i] = cached[i];
+ for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
+ irq_data = &pm860x_irqs[i];
+ switch (irq_data->mask_reg) {
+ case PM8607_INT_MASK_1:
+ mask[0] &= ~irq_data->offs;
+ mask[0] |= irq_data->enable;
+ break;
+ case PM8607_INT_MASK_2:
+ mask[1] &= ~irq_data->offs;
+ mask[1] |= irq_data->enable;
+ break;
+ case PM8607_INT_MASK_3:
+ mask[2] &= ~irq_data->offs;
+ mask[2] |= irq_data->enable;
+ break;
+ default:
+ dev_err(chip->dev, "wrong IRQ\n");
+ break;
+ }
+ }
+ /* update mask into registers */
+ for (i = 0; i < 3; i++) {
+ if (mask[i] != cached[i]) {
+ cached[i] = mask[i];
+ pm860x_reg_write(i2c, PM8607_INT_MASK_1 + i, mask[i]);
+ }
+ }
+
+ mutex_unlock(&chip->irq_lock);
+}
+
+static void pm860x_irq_enable(unsigned int irq)
+{
+ struct pm860x_chip *chip = get_irq_chip_data(irq);
+ pm860x_irqs[irq - chip->irq_base].enable
+ = pm860x_irqs[irq - chip->irq_base].offs;
+}
+
+static void pm860x_irq_disable(unsigned int irq)
+{
+ struct pm860x_chip *chip = get_irq_chip_data(irq);
+ pm860x_irqs[irq - chip->irq_base].enable = 0;
+}
+
+static struct irq_chip pm860x_irq_chip = {
+ .name = "88pm860x",
+ .bus_lock = pm860x_irq_lock,
+ .bus_sync_unlock = pm860x_irq_sync_unlock,
+ .enable = pm860x_irq_enable,
+ .disable = pm860x_irq_disable,
+};
+
+static int __devinit device_gpadc_init(struct pm860x_chip *chip,
+ struct pm860x_platform_data *pdata)
+{
+ struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
+ : chip->companion;
+ int use_gpadc = 0, data, ret;
+
+ /* initialize GPADC without activating it */
+
+ if (pdata && pdata->touch) {
+ /* set GPADC MISC1 register */
+ data = 0;
+ data |= (pdata->touch->gpadc_prebias << 1)
+ & PM8607_GPADC_PREBIAS_MASK;
+ data |= (pdata->touch->slot_cycle << 3)
+ & PM8607_GPADC_SLOT_CYCLE_MASK;
+ data |= (pdata->touch->off_scale << 5)
+ & PM8607_GPADC_OFF_SCALE_MASK;
+ data |= (pdata->touch->sw_cal << 7)
+ & PM8607_GPADC_SW_CAL_MASK;
+ if (data) {
+ ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
+ if (ret < 0)
+ goto out;
+ }
+ /* set tsi prebias time */
+ if (pdata->touch->tsi_prebias) {
+ data = pdata->touch->tsi_prebias;
+ ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
+ if (ret < 0)
+ goto out;
+ }
+ /* set prebias & prechg time of pen detect */
+ data = 0;
+ data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK;
+ data |= (pdata->touch->pen_prechg << 5)
+ & PM8607_PD_PRECHG_MASK;
+ if (data) {
+ ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
+ if (ret < 0)
+ goto out;
+ }
+
+ use_gpadc = 1;
+ }
+
+ /* turn on GPADC */
+ if (use_gpadc) {
+ ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
+ PM8607_GPADC_EN, PM8607_GPADC_EN);
+ }
+out:
+ return ret;
+}
+
+static int __devinit device_irq_init(struct pm860x_chip *chip,
+ struct pm860x_platform_data *pdata)
+{
+ struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
+ : chip->companion;
+ unsigned char status_buf[INT_STATUS_NUM];
+ unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+ struct irq_desc *desc;
+ int i, data, mask, ret = -EINVAL;
+ int __irq;
+
+ if (!pdata || !pdata->irq_base) {
+ dev_warn(chip->dev, "No interrupt support on IRQ base\n");
+ return -EINVAL;
+ }
+
+ mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR
+ | PM8607_B0_MISC1_INT_MASK;
+ data = 0;
+ chip->irq_mode = 0;
+ if (pdata && pdata->irq_mode) {
+ /*
+ * irq_mode defines the way of clearing interrupt. If it's 1,
+ * clear IRQ by write. Otherwise, clear it by read.
+ * This control bit is valid from 88PM8607 B0 steping.
+ */
+ data |= PM8607_B0_MISC1_INT_CLEAR;
+ chip->irq_mode = 1;
+ }
+ ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, mask, data);
+ if (ret < 0)
+ goto out;
+
+ /* mask all IRQs */
+ memset(status_buf, 0, INT_STATUS_NUM);
+ ret = pm860x_bulk_write(i2c, PM8607_INT_MASK_1,
+ INT_STATUS_NUM, status_buf);
+ if (ret < 0)
+ goto out;
+
+ if (chip->irq_mode) {
+ /* clear interrupt status by write */
+ memset(status_buf, 0xFF, INT_STATUS_NUM);
+ ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1,
+ INT_STATUS_NUM, status_buf);
+ } else {
+ /* clear interrupt status by read */
+ ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1,
+ INT_STATUS_NUM, status_buf);
+ }
+ if (ret < 0)
+ goto out;
+
+ mutex_init(&chip->irq_lock);
+ chip->irq_base = pdata->irq_base;
+ chip->core_irq = i2c->irq;
+ if (!chip->core_irq)
+ goto out;
+
+ desc = irq_to_desc(chip->core_irq);
+
+ /* register IRQ by genirq */
+ for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
+ __irq = i + chip->irq_base;
+ set_irq_chip_data(__irq, chip);
+ set_irq_chip_and_handler(__irq, &pm860x_irq_chip,
+ handle_edge_irq);
+ set_irq_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(__irq, IRQF_VALID);
+#else
+ set_irq_noprobe(__irq);
+#endif
+ }
+
+ ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags,
+ "88pm860x", chip);
+ if (ret) {
+ dev_err(chip->dev, "Failed to request IRQ: %d\n", ret);
+ chip->core_irq = 0;
+ }
+
+ return 0;
+out:
+ chip->core_irq = 0;
+ return ret;
+}
+
+static void __devexit device_irq_exit(struct pm860x_chip *chip)
+{
+ if (chip->core_irq)
+ free_irq(chip->core_irq, chip);
+}
+
+static void __devinit device_8606_init(struct pm860x_chip *chip,
+ struct i2c_client *i2c,
+ struct pm860x_platform_data *pdata)
+{
+ int ret;
+
+ if (pdata && pdata->backlight) {
+ ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0],
+ ARRAY_SIZE(backlight_devs),
+ &backlight_resources[0], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add backlight "
+ "subdev\n");
+ goto out_dev;
+ }
+ }
+
+ if (pdata && pdata->led) {
+ ret = mfd_add_devices(chip->dev, 0, &led_devs[0],
+ ARRAY_SIZE(led_devs),
+ &led_resources[0], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add led "
+ "subdev\n");
+ goto out_dev;
+ }
+ }
+ return;
+out_dev:
+ mfd_remove_devices(chip->dev);
+ device_irq_exit(chip);
+}
+
+static void __devinit device_8607_init(struct pm860x_chip *chip,
+ struct i2c_client *i2c,
+ struct pm860x_platform_data *pdata)
+{
+ int data, ret;
+
+ ret = pm860x_reg_read(i2c, PM8607_CHIP_ID);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
+ goto out;
+ }
+ if ((ret & PM8607_VERSION_MASK) == PM8607_VERSION)
+ dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
+ ret);
+ else {
+ dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
+ "Chip ID: %02x\n", ret);
+ goto out;
+ }
+
+ ret = pm860x_reg_read(i2c, PM8607_BUCK3);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
+ goto out;
+ }
+ if (ret & PM8607_BUCK3_DOUBLE)
+ chip->buck3_double = 1;
+
+ ret = pm860x_reg_read(i2c, PM8607_B0_MISC1);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
+ goto out;
+ }
+
+ if (pdata && (pdata->i2c_port == PI2C_PORT))
+ data = PM8607_B0_MISC1_PI2C;
+ else
+ data = 0;
+ ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, PM8607_B0_MISC1_PI2C, data);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to access MISC1:%d\n", ret);
+ goto out;
+ }
+
+ ret = device_gpadc_init(chip, pdata);
+ if (ret < 0)
+ goto out;
+
+ ret = device_irq_init(chip, pdata);
+ if (ret < 0)
+ goto out;
+
+ ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
+ ARRAY_SIZE(regulator_devs),
+ &regulator_resources[0], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add regulator subdev\n");
+ goto out_dev;
+ }
+
+ if (pdata && pdata->touch) {
+ ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
+ ARRAY_SIZE(touch_devs),
+ &touch_resources[0], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add touch "
+ "subdev\n");
+ goto out_dev;
+ }
+ }
+
+ if (pdata && pdata->power) {
+ ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
+ ARRAY_SIZE(power_devs),
+ &power_supply_resources[0], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add power supply "
+ "subdev\n");
+ goto out_dev;
+ }
+ }
+
+ ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
+ ARRAY_SIZE(onkey_devs),
+ &onkey_resources[0], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add onkey subdev\n");
+ goto out_dev;
+ }
+
+ return;
+out_dev:
+ mfd_remove_devices(chip->dev);
+ device_irq_exit(chip);
+out:
+ return;
+}
+
+int pm860x_device_init(struct pm860x_chip *chip,
+ struct pm860x_platform_data *pdata)
+{
+ chip->core_irq = 0;
+
+ switch (chip->id) {
+ case CHIP_PM8606:
+ device_8606_init(chip, chip->client, pdata);
+ break;
+ case CHIP_PM8607:
+ device_8607_init(chip, chip->client, pdata);
+ break;
+ }
+
+ if (chip->companion) {
+ switch (chip->id) {
+ case CHIP_PM8607:
+ device_8606_init(chip, chip->companion, pdata);
+ break;
+ case CHIP_PM8606:
+ device_8607_init(chip, chip->companion, pdata);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void pm860x_device_exit(struct pm860x_chip *chip)
+{
+ device_irq_exit(chip);
+ mfd_remove_devices(chip->dev);
+}
+
+MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
new file mode 100644
index 000000000000..c37e12bf3004
--- /dev/null
+++ b/drivers/mfd/88pm860x-i2c.c
@@ -0,0 +1,236 @@
+/*
+ * I2C driver for Marvell 88PM860x
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/mfd/88pm860x.h>
+
+static inline int pm860x_read_device(struct i2c_client *i2c,
+ int reg, int bytes, void *dest)
+{
+ unsigned char data;
+ int ret;
+
+ data = (unsigned char)reg;
+ ret = i2c_master_send(i2c, &data, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_master_recv(i2c, dest, bytes);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static inline int pm860x_write_device(struct i2c_client *i2c,
+ int reg, int bytes, void *src)
+{
+ unsigned char buf[bytes + 1];
+ int ret;
+
+ buf[0] = (unsigned char)reg;
+ memcpy(&buf[1], src, bytes);
+
+ ret = i2c_master_send(i2c, buf, bytes + 1);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+int pm860x_reg_read(struct i2c_client *i2c, int reg)
+{
+ struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+ unsigned char data;
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = pm860x_read_device(i2c, reg, 1, &data);
+ mutex_unlock(&chip->io_lock);
+
+ if (ret < 0)
+ return ret;
+ else
+ return (int)data;
+}
+EXPORT_SYMBOL(pm860x_reg_read);
+
+int pm860x_reg_write(struct i2c_client *i2c, int reg,
+ unsigned char data)
+{
+ struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = pm860x_write_device(i2c, reg, 1, &data);
+ mutex_unlock(&chip->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(pm860x_reg_write);
+
+int pm860x_bulk_read(struct i2c_client *i2c, int reg,
+ int count, unsigned char *buf)
+{
+ struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = pm860x_read_device(i2c, reg, count, buf);
+ mutex_unlock(&chip->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(pm860x_bulk_read);
+
+int pm860x_bulk_write(struct i2c_client *i2c, int reg,
+ int count, unsigned char *buf)
+{
+ struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = pm860x_write_device(i2c, reg, count, buf);
+ mutex_unlock(&chip->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(pm860x_bulk_write);
+
+int pm860x_set_bits(struct i2c_client *i2c, int reg,
+ unsigned char mask, unsigned char data)
+{
+ struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+ unsigned char value;
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = pm860x_read_device(i2c, reg, 1, &value);
+ if (ret < 0)
+ goto out;
+ value &= ~mask;
+ value |= data;
+ ret = pm860x_write_device(i2c, reg, 1, &value);
+out:
+ mutex_unlock(&chip->io_lock);
+ return ret;
+}
+EXPORT_SYMBOL(pm860x_set_bits);
+
+
+static const struct i2c_device_id pm860x_id_table[] = {
+ { "88PM860x", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
+
+static int verify_addr(struct i2c_client *i2c)
+{
+ unsigned short addr_8607[] = {0x30, 0x34};
+ unsigned short addr_8606[] = {0x10, 0x11};
+ int size, i;
+
+ if (i2c == NULL)
+ return 0;
+ size = ARRAY_SIZE(addr_8606);
+ for (i = 0; i < size; i++) {
+ if (i2c->addr == *(addr_8606 + i))
+ return CHIP_PM8606;
+ }
+ size = ARRAY_SIZE(addr_8607);
+ for (i = 0; i < size; i++) {
+ if (i2c->addr == *(addr_8607 + i))
+ return CHIP_PM8607;
+ }
+ return 0;
+}
+
+static int __devinit pm860x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pm860x_platform_data *pdata = client->dev.platform_data;
+ struct pm860x_chip *chip;
+
+ if (!pdata) {
+ pr_info("No platform data in %s!\n", __func__);
+ return -EINVAL;
+ }
+
+ chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
+ if (chip == NULL)
+ return -ENOMEM;
+
+ chip->id = verify_addr(client);
+ chip->client = client;
+ i2c_set_clientdata(client, chip);
+ chip->dev = &client->dev;
+ mutex_init(&chip->io_lock);
+ dev_set_drvdata(chip->dev, chip);
+
+ /*
+ * Both client and companion client shares same platform driver.
+ * Driver distinguishes them by pdata->companion_addr.
+ * pdata->companion_addr is only assigned if companion chip exists.
+ * At the same time, the companion_addr shouldn't equal to client
+ * address.
+ */
+ if (pdata->companion_addr && (pdata->companion_addr != client->addr)) {
+ chip->companion_addr = pdata->companion_addr;
+ chip->companion = i2c_new_dummy(chip->client->adapter,
+ chip->companion_addr);
+ i2c_set_clientdata(chip->companion, chip);
+ }
+
+ pm860x_device_init(chip, pdata);
+ return 0;
+}
+
+static int __devexit pm860x_remove(struct i2c_client *client)
+{
+ struct pm860x_chip *chip = i2c_get_clientdata(client);
+
+ pm860x_device_exit(chip);
+ i2c_unregister_device(chip->companion);
+ i2c_set_clientdata(chip->companion, NULL);
+ i2c_set_clientdata(chip->client, NULL);
+ kfree(chip);
+ return 0;
+}
+
+static struct i2c_driver pm860x_driver = {
+ .driver = {
+ .name = "88PM860x",
+ .owner = THIS_MODULE,
+ },
+ .probe = pm860x_probe,
+ .remove = __devexit_p(pm860x_remove),
+ .id_table = pm860x_id_table,
+};
+
+static int __init pm860x_i2c_init(void)
+{
+ int ret;
+ ret = i2c_add_driver(&pm860x_driver);
+ if (ret != 0)
+ pr_err("Failed to register 88PM860x I2C driver: %d\n", ret);
+ return ret;
+}
+subsys_initcall(pm860x_i2c_init);
+
+static void __exit pm860x_i2c_exit(void)
+{
+ i2c_del_driver(&pm860x_driver);
+}
+module_exit(pm860x_i2c_exit);
+
+MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 87829789243e..2a5a0b78f84e 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -9,6 +9,16 @@ config MFD_CORE
tristate
default n
+config MFD_88PM860X
+ bool "Support Marvell 88PM8606/88PM8607"
+ depends on I2C=y && GENERIC_HARDIRQS
+ select MFD_CORE
+ help
+ This supports for Marvell 88PM8606/88PM8607 Power Management IC.
+ This includes the I2C driver and the core APIs _only_, you have to
+ select individual components like voltage regulators, RTC and
+ battery-charger under the corresponding menus.
+
config MFD_SM501
tristate "Support for Silicon Motion SM501"
---help---
@@ -37,7 +47,7 @@ config MFD_ASIC3
config MFD_SH_MOBILE_SDHI
bool "Support for SuperH Mobile SDHI"
- depends on SUPERH
+ depends on SUPERH || ARCH_SHMOBILE
select MFD_CORE
---help---
This driver supports the SDHI hardware block found in many
@@ -68,6 +78,15 @@ config HTC_PASIC3
HTC Magician devices, respectively. Actual functionality is
handled by the leds-pasic3 and ds1wm drivers.
+config HTC_I2CPLD
+ bool "HTC I2C PLD chip support"
+ depends on I2C=y && GPIOLIB
+ help
+ If you say yes here you get support for the supposed CPLD
+ found on omap850 HTC devices like the HTC Wizard and HTC Herald.
+ This device provides input and output GPIOs through an I2C
+ interface to one or more sub-chips.
+
config UCB1400_CORE
tristate "Philips UCB1400 Core driver"
depends on AC97_BUS
@@ -94,7 +113,7 @@ config TPS65010
config MENELAUS
bool "Texas Instruments TWL92330/Menelaus PM chip"
- depends on I2C=y && ARCH_OMAP24XX
+ depends on I2C=y && ARCH_OMAP2
help
If you say yes here you get support for the Texas Instruments
TWL92330/Menelaus Power Management chip. This include voltage
@@ -184,6 +203,16 @@ config PMIC_ADP5520
individual components like LCD backlight, LEDs, GPIOs and Kepad
under the corresponding menus.
+config MFD_MAX8925
+ bool "Maxim Semiconductor MAX8925 PMIC Support"
+ depends on I2C=y && GENERIC_HARDIRQS
+ select MFD_CORE
+ help
+ Say yes here to support for Maxim Semiconductor MAX8925. This is
+ a Power Management IC. This driver provies common support for
+ accessing the device, additional drivers must be enabled in order
+ to use the functionality of the device.
+
config MFD_WM8400
tristate "Support Wolfson Microelectronics WM8400"
select MFD_CORE
@@ -197,7 +226,7 @@ config MFD_WM8400
config MFD_WM831X
bool "Support Wolfson Microelectronics WM831x/2x PMICs"
select MFD_CORE
- depends on I2C=y
+ depends on I2C=y && GENERIC_HARDIRQS
help
Support for the Wolfson Microelecronics WM831x and WM832x PMICs.
This driver provides common support for accessing the device,
@@ -205,7 +234,8 @@ config MFD_WM831X
functionality of the device.
config MFD_WM8350
- tristate
+ bool
+ depends on GENERIC_HARDIRQS
config MFD_WM8350_CONFIG_MODE_0
bool
@@ -256,9 +286,9 @@ config MFD_WM8352_CONFIG_MODE_3
depends on MFD_WM8350
config MFD_WM8350_I2C
- tristate "Support Wolfson Microelectronics WM8350 with I2C"
+ bool "Support Wolfson Microelectronics WM8350 with I2C"
select MFD_WM8350
- depends on I2C
+ depends on I2C=y && GENERIC_HARDIRQS
help
The WM8350 is an integrated audio and power management
subsystem with watchdog and RTC functionality for embedded
@@ -266,6 +296,18 @@ config MFD_WM8350_I2C
I2C as the control interface. Additional options must be
selected to enable support for the functionality of the chip.
+config MFD_WM8994
+ tristate "Support Wolfson Microelectronics WM8994"
+ select MFD_CORE
+ depends on I2C
+ help
+ The WM8994 is a highly integrated hi-fi CODEC designed for
+ smartphone applicatiosn. As well as audio functionality it
+ has on board GPIO and regulator functionality which is
+ supported via the relevant subsystems. This driver provides
+ core support for the WM8994, in order to use the actual
+ functionaltiy of the device other drivers must be enabled.
+
config MFD_PCF50633
tristate "Support for NXP PCF50633"
depends on I2C
@@ -300,8 +342,8 @@ config PCF50633_GPIO
the PCF50633 chip.
config AB3100_CORE
- tristate "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
- depends on I2C
+ bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
+ depends on I2C=y
default y if ARCH_U300
help
Select this to enable the AB3100 Mixed Signal IC core
@@ -329,16 +371,6 @@ config EZX_PCAP
This enables the PCAP ASIC present on EZX Phones. This is
needed for MMC, TouchScreen, Sound, USB, etc..
-config MFD_88PM8607
- bool "Support Marvell 88PM8607"
- depends on I2C=y
- select MFD_CORE
- help
- This supports for Marvell 88PM8607 Power Management IC. This includes
- the I2C driver and the core APIs _only_, you have to select
- individual components like voltage regulators, RTC and
- battery-charger under the corresponding menus.
-
config AB4500_CORE
tristate "ST-Ericsson's AB4500 Mixed Signal Power management chip"
depends on SPI
@@ -348,6 +380,25 @@ config AB4500_CORE
read/write functions for the devices to get access to this chip.
This chip embeds various other multimedia funtionalities as well.
+config MFD_TIMBERDALE
+ tristate "Support for the Timberdale FPGA"
+ select MFD_CORE
+ depends on PCI && GPIOLIB
+ ---help---
+ This is the core driver for the timberdale FPGA. This device is a
+ multifunction device which exposes numerous platform devices.
+
+ The timberdale FPGA can be found on the Intel Atom development board
+ for in-vehicle infontainment, called Russellville.
+
+config LPC_SCH
+ tristate "Intel SCH LPC"
+ depends on PCI
+ select MFD_CORE
+ help
+ LPC bridge function of the Intel SCH provides support for
+ System Management Bus and General Purpose I/O.
+
endmenu
menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index ca2f2c4ff05e..22715add99a7 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -2,18 +2,21 @@
# Makefile for multifunction miscellaneous devices
#
+88pm860x-objs := 88pm860x-core.o 88pm860x-i2c.o
+obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o
obj-$(CONFIG_MFD_SM501) += sm501.o
-obj-$(CONFIG_MFD_ASIC3) += asic3.o
+obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o
obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
+obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
-obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o
-obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o
-obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o
+obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
+obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o
+obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o
obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o
@@ -22,6 +25,7 @@ wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
wm8350-objs += wm8350-irq.o
obj-$(CONFIG_MFD_WM8350) += wm8350.o
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
+obj-$(CONFIG_MFD_WM8994) += wm8994-core.o
obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_MENELAUS) += menelaus.o
@@ -47,6 +51,8 @@ endif
obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o
obj-$(CONFIG_PMIC_DA903X) += da903x.o
+max8925-objs := max8925-core.o max8925-i2c.o
+obj-$(CONFIG_MFD_MAX8925) += max8925.o
obj-$(CONFIG_MFD_PCF50633) += pcf50633-core.o
obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
@@ -54,5 +60,6 @@ obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
obj-$(CONFIG_AB4500_CORE) += ab4500-core.o
-obj-$(CONFIG_MFD_88PM8607) += 88pm8607.o
-obj-$(CONFIG_PMIC_ADP5520) += adp5520.o \ No newline at end of file
+obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
+obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
+obj-$(CONFIG_LPC_SCH) += lpc_sch.o \ No newline at end of file
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
index fd42a80e7bf9..a2ce3b6af4a2 100644
--- a/drivers/mfd/ab3100-core.c
+++ b/drivers/mfd/ab3100-core.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007-2009 ST-Ericsson
+ * Copyright (C) 2007-2010 ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
* Low-level core for exclusive access to the AB3100 IC on the I2C bus
* and some basic chip-configuration.
@@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/interrupt.h>
+#include <linux/random.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
@@ -365,18 +366,23 @@ int ab3100_event_registers_startup_state_get(struct ab3100 *ab3100,
}
EXPORT_SYMBOL(ab3100_event_registers_startup_state_get);
-/* Interrupt handling worker */
-static void ab3100_work(struct work_struct *work)
+/*
+ * This is a threaded interrupt handler so we can make some
+ * I2C calls etc.
+ */
+static irqreturn_t ab3100_irq_handler(int irq, void *data)
{
- struct ab3100 *ab3100 = container_of(work, struct ab3100, work);
+ struct ab3100 *ab3100 = data;
u8 event_regs[3];
u32 fatevent;
int err;
+ add_interrupt_randomness(irq);
+
err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1,
event_regs, 3);
if (err)
- goto err_event_wq;
+ goto err_event;
fatevent = (event_regs[0] << 16) |
(event_regs[1] << 8) |
@@ -398,29 +404,11 @@ static void ab3100_work(struct work_struct *work)
dev_dbg(ab3100->dev,
"IRQ Event: 0x%08x\n", fatevent);
- /* By now the IRQ should be acked and deasserted so enable it again */
- enable_irq(ab3100->i2c_client->irq);
- return;
+ return IRQ_HANDLED;
- err_event_wq:
+ err_event:
dev_dbg(ab3100->dev,
- "error in event workqueue\n");
- /* Enable the IRQ anyway, what choice do we have? */
- enable_irq(ab3100->i2c_client->irq);
- return;
-}
-
-static irqreturn_t ab3100_irq_handler(int irq, void *data)
-{
- struct ab3100 *ab3100 = data;
- /*
- * Disable the IRQ and dispatch a worker to handle the
- * event. Since the chip resides on I2C this is slow
- * stuff and we will re-enable the interrupts once th
- * worker has finished.
- */
- disable_irq_nosync(irq);
- schedule_work(&ab3100->work);
+ "error reading event status\n");
return IRQ_HANDLED;
}
@@ -735,10 +723,7 @@ static struct platform_device ab3100_##devname##_device = { \
.id = -1, \
}
-/*
- * This lists all the subdevices and corresponding register
- * ranges.
- */
+/* This lists all the subdevices */
AB3100_DEVICE(dac, "ab3100-dac");
AB3100_DEVICE(leds, "ab3100-leds");
AB3100_DEVICE(power, "ab3100-power");
@@ -904,12 +889,11 @@ static int __init ab3100_probe(struct i2c_client *client,
if (err)
goto exit_no_setup;
- INIT_WORK(&ab3100->work, ab3100_work);
-
+ err = request_threaded_irq(client->irq, NULL, ab3100_irq_handler,
+ IRQF_ONESHOT, "ab3100-core", ab3100);
/* This real unpredictable IRQ is of course sampled for entropy */
- err = request_irq(client->irq, ab3100_irq_handler,
- IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
- "AB3100 IRQ", ab3100);
+ rand_initialize_irq(client->irq);
+
if (err)
goto exit_no_irq;
diff --git a/drivers/mfd/ab3100-otp.c b/drivers/mfd/ab3100-otp.c
index 0499b2031a2c..b603469dff69 100644
--- a/drivers/mfd/ab3100-otp.c
+++ b/drivers/mfd/ab3100-otp.c
@@ -13,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/mfd/ab3100.h>
#include <linux/debugfs.h>
+#include <linux/seq_file.h>
/* The OTP registers */
#define AB3100_OTP0 0xb0
@@ -95,11 +96,10 @@ static int __init ab3100_otp_read(struct ab3100_otp *otp)
* This is a simple debugfs human-readable file that dumps out
* the contents of the OTP.
*/
-#ifdef CONFIG_DEBUGFS
-static int show_otp(struct seq_file *s, void *v)
+#ifdef CONFIG_DEBUG_FS
+static int ab3100_show_otp(struct seq_file *s, void *v)
{
struct ab3100_otp *otp = s->private;
- int err;
seq_printf(s, "OTP is %s\n", otp->locked ? "LOCKED" : "UNLOCKED");
seq_printf(s, "OTP clock switch startup is %uHz\n", otp->freq);
@@ -113,7 +113,7 @@ static int show_otp(struct seq_file *s, void *v)
static int ab3100_otp_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab3100_otp_show, inode->i_private);
+ return single_open(file, ab3100_show_otp, inode->i_private);
}
static const struct file_operations ab3100_otp_operations = {
@@ -131,13 +131,14 @@ static int __init ab3100_otp_init_debugfs(struct device *dev,
&ab3100_otp_operations);
if (!otp->debugfs) {
dev_err(dev, "AB3100 debugfs OTP file registration failed!\n");
- return err;
+ return -ENOENT;
}
+ return 0;
}
static void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp)
{
- debugfs_remove_file(otp->debugfs);
+ debugfs_remove(otp->debugfs);
}
#else
/* Compile this out if debugfs not selected */
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index e22128c3e9a8..95c1e6bd1729 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -80,6 +80,7 @@ struct asic3 {
u16 irq_bothedge[4];
struct gpio_chip gpio;
struct device *dev;
+ void __iomem *tmio_cnf;
struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)];
};
@@ -685,8 +686,24 @@ static struct mfd_cell asic3_cell_ds1wm = {
.resources = ds1wm_resources,
};
+static void asic3_mmc_pwr(struct platform_device *pdev, int state)
+{
+ struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+
+ tmio_core_mmc_pwr(asic->tmio_cnf, 1 - asic->bus_shift, state);
+}
+
+static void asic3_mmc_clk_div(struct platform_device *pdev, int state)
+{
+ struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+
+ tmio_core_mmc_clk_div(asic->tmio_cnf, 1 - asic->bus_shift, state);
+}
+
static struct tmio_mmc_data asic3_mmc_data = {
- .hclk = 24576000,
+ .hclk = 24576000,
+ .set_pwr = asic3_mmc_pwr,
+ .set_clk_div = asic3_mmc_clk_div,
};
static struct resource asic3_mmc_resources[] = {
@@ -696,11 +713,6 @@ static struct resource asic3_mmc_resources[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = ASIC3_SD_CONFIG_BASE,
- .end = ASIC3_SD_CONFIG_BASE + 0x1ff,
- .flags = IORESOURCE_MEM,
- },
- {
.start = 0,
.end = 0,
.flags = IORESOURCE_IRQ,
@@ -743,6 +755,10 @@ static int asic3_mmc_enable(struct platform_device *pdev)
asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF),
ASIC3_SDHWCTRL_SDPWR, 1);
+ /* ASIC3_SD_CTRL_BASE assumes 32-bit addressing, TMIO is 16-bit */
+ tmio_core_mmc_enable(asic->tmio_cnf, 1 - asic->bus_shift,
+ ASIC3_SD_CTRL_BASE >> 1);
+
return 0;
}
@@ -797,10 +813,15 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm);
/* MMC */
+ asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) +
+ mem_sdio->start, 0x400 >> asic->bus_shift);
+ if (!asic->tmio_cnf) {
+ ret = -ENOMEM;
+ dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n");
+ goto out;
+ }
asic3_mmc_resources[0].start >>= asic->bus_shift;
asic3_mmc_resources[0].end >>= asic->bus_shift;
- asic3_mmc_resources[1].start >>= asic->bus_shift;
- asic3_mmc_resources[1].end >>= asic->bus_shift;
asic3_cell_mmc.platform_data = &asic3_cell_mmc;
asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc);
@@ -820,7 +841,10 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
static void asic3_mfd_remove(struct platform_device *pdev)
{
+ struct asic3 *asic = platform_get_drvdata(pdev);
+
mfd_remove_devices(&pdev->dev);
+ iounmap(asic->tmio_cnf);
}
/* Core */
diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c
index aa266e1f69b2..addb846c1e34 100644
--- a/drivers/mfd/htc-egpio.c
+++ b/drivers/mfd/htc-egpio.c
@@ -108,7 +108,7 @@ static void egpio_handler(unsigned int irq, struct irq_desc *desc)
ack_irqs(ei);
/* Process all set pins. */
readval &= ei->irqs_enabled;
- for_each_bit(irqpin, &readval, ei->nirqs) {
+ for_each_set_bit(irqpin, &readval, ei->nirqs) {
/* Run irq handler */
pr_debug("got IRQ %d\n", irqpin);
irq = ei->irq_start + irqpin;
diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c
new file mode 100644
index 000000000000..37b9fdab4f36
--- /dev/null
+++ b/drivers/mfd/htc-i2cpld.c
@@ -0,0 +1,710 @@
+/*
+ * htc-i2cpld.c
+ * Chip driver for an unknown CPLD chip found on omap850 HTC devices like
+ * the HTC Wizard and HTC Herald.
+ * The cpld is located on the i2c bus and acts as an input/output GPIO
+ * extender.
+ *
+ * Copyright (C) 2009 Cory Maccarrone <darkstar6262@gmail.com>
+ *
+ * Based on work done in the linwizard project
+ * Copyright (C) 2008-2009 Angelo Arrifano <miknix@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include <linux/htcpld.h>
+#include <linux/gpio.h>
+
+struct htcpld_chip {
+ spinlock_t lock;
+
+ /* chip info */
+ u8 reset;
+ u8 addr;
+ struct device *dev;
+ struct i2c_client *client;
+
+ /* Output details */
+ u8 cache_out;
+ struct gpio_chip chip_out;
+
+ /* Input details */
+ u8 cache_in;
+ struct gpio_chip chip_in;
+
+ u16 irqs_enabled;
+ uint irq_start;
+ int nirqs;
+
+ /*
+ * Work structure to allow for setting values outside of any
+ * possible interrupt context
+ */
+ struct work_struct set_val_work;
+};
+
+struct htcpld_data {
+ /* irq info */
+ u16 irqs_enabled;
+ uint irq_start;
+ int nirqs;
+ uint chained_irq;
+ unsigned int int_reset_gpio_hi;
+ unsigned int int_reset_gpio_lo;
+
+ /* htcpld info */
+ struct htcpld_chip *chip;
+ unsigned int nchips;
+};
+
+/* There does not appear to be a way to proactively mask interrupts
+ * on the htcpld chip itself. So, we simply ignore interrupts that
+ * aren't desired. */
+static void htcpld_mask(unsigned int irq)
+{
+ struct htcpld_chip *chip = get_irq_chip_data(irq);
+ chip->irqs_enabled &= ~(1 << (irq - chip->irq_start));
+ pr_debug("HTCPLD mask %d %04x\n", irq, chip->irqs_enabled);
+}
+static void htcpld_unmask(unsigned int irq)
+{
+ struct htcpld_chip *chip = get_irq_chip_data(irq);
+ chip->irqs_enabled |= 1 << (irq - chip->irq_start);
+ pr_debug("HTCPLD unmask %d %04x\n", irq, chip->irqs_enabled);
+}
+
+static int htcpld_set_type(unsigned int irq, unsigned int flags)
+{
+ struct irq_desc *d = irq_to_desc(irq);
+
+ if (!d) {
+ pr_err("HTCPLD invalid IRQ: %d\n", irq);
+ return -EINVAL;
+ }
+
+ if (flags & ~IRQ_TYPE_SENSE_MASK)
+ return -EINVAL;
+
+ /* We only allow edge triggering */
+ if (flags & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))
+ return -EINVAL;
+
+ d->status &= ~IRQ_TYPE_SENSE_MASK;
+ d->status |= flags;
+
+ return 0;
+}
+
+static struct irq_chip htcpld_muxed_chip = {
+ .name = "htcpld",
+ .mask = htcpld_mask,
+ .unmask = htcpld_unmask,
+ .set_type = htcpld_set_type,
+};
+
+/* To properly dispatch IRQ events, we need to read from the
+ * chip. This is an I2C action that could possibly sleep
+ * (which is bad in interrupt context) -- so we use a threaded
+ * interrupt handler to get around that.
+ */
+static irqreturn_t htcpld_handler(int irq, void *dev)
+{
+ struct htcpld_data *htcpld = dev;
+ unsigned int i;
+ unsigned long flags;
+ int irqpin;
+ struct irq_desc *desc;
+
+ if (!htcpld) {
+ pr_debug("htcpld is null in ISR\n");
+ return IRQ_HANDLED;
+ }
+
+ /*
+ * For each chip, do a read of the chip and trigger any interrupts
+ * desired. The interrupts will be triggered from LSB to MSB (i.e.
+ * bit 0 first, then bit 1, etc.)
+ *
+ * For chips that have no interrupt range specified, just skip 'em.
+ */
+ for (i = 0; i < htcpld->nchips; i++) {
+ struct htcpld_chip *chip = &htcpld->chip[i];
+ struct i2c_client *client;
+ int val;
+ unsigned long uval, old_val;
+
+ if (!chip) {
+ pr_debug("chip %d is null in ISR\n", i);
+ continue;
+ }
+
+ if (chip->nirqs == 0)
+ continue;
+
+ client = chip->client;
+ if (!client) {
+ pr_debug("client %d is null in ISR\n", i);
+ continue;
+ }
+
+ /* Scan the chip */
+ val = i2c_smbus_read_byte_data(client, chip->cache_out);
+ if (val < 0) {
+ /* Throw a warning and skip this chip */
+ dev_warn(chip->dev, "Unable to read from chip: %d\n",
+ val);
+ continue;
+ }
+
+ uval = (unsigned long)val;
+
+ spin_lock_irqsave(&chip->lock, flags);
+
+ /* Save away the old value so we can compare it */
+ old_val = chip->cache_in;
+
+ /* Write the new value */
+ chip->cache_in = uval;
+
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ /*
+ * For each bit in the data (starting at bit 0), trigger
+ * associated interrupts.
+ */
+ for (irqpin = 0; irqpin < chip->nirqs; irqpin++) {
+ unsigned oldb, newb;
+ int flags;
+
+ irq = chip->irq_start + irqpin;
+ desc = irq_to_desc(irq);
+ flags = desc->status;
+
+ /* Run the IRQ handler, but only if the bit value
+ * changed, and the proper flags are set */
+ oldb = (old_val >> irqpin) & 1;
+ newb = (uval >> irqpin) & 1;
+
+ if ((!oldb && newb && (flags & IRQ_TYPE_EDGE_RISING)) ||
+ (oldb && !newb &&
+ (flags & IRQ_TYPE_EDGE_FALLING))) {
+ pr_debug("fire IRQ %d\n", irqpin);
+ desc->handle_irq(irq, desc);
+ }
+ }
+ }
+
+ /*
+ * In order to continue receiving interrupts, the int_reset_gpio must
+ * be asserted.
+ */
+ if (htcpld->int_reset_gpio_hi)
+ gpio_set_value(htcpld->int_reset_gpio_hi, 1);
+ if (htcpld->int_reset_gpio_lo)
+ gpio_set_value(htcpld->int_reset_gpio_lo, 0);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * The GPIO set routines can be called from interrupt context, especially if,
+ * for example they're attached to the led-gpio framework and a trigger is
+ * enabled. As such, we declared work above in the htcpld_chip structure,
+ * and that work is scheduled in the set routine. The kernel can then run
+ * the I2C functions, which will sleep, in process context.
+ */
+void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+ struct i2c_client *client;
+ struct htcpld_chip *chip_data;
+ unsigned long flags;
+
+ chip_data = container_of(chip, struct htcpld_chip, chip_out);
+ if (!chip_data)
+ return;
+
+ client = chip_data->client;
+ if (client == NULL)
+ return;
+
+ spin_lock_irqsave(&chip_data->lock, flags);
+ if (val)
+ chip_data->cache_out |= (1 << offset);
+ else
+ chip_data->cache_out &= ~(1 << offset);
+ spin_unlock_irqrestore(&chip_data->lock, flags);
+
+ schedule_work(&(chip_data->set_val_work));
+}
+
+void htcpld_chip_set_ni(struct work_struct *work)
+{
+ struct htcpld_chip *chip_data;
+ struct i2c_client *client;
+
+ chip_data = container_of(work, struct htcpld_chip, set_val_work);
+ client = chip_data->client;
+ i2c_smbus_read_byte_data(client, chip_data->cache_out);
+}
+
+int htcpld_chip_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct htcpld_chip *chip_data;
+ int val = 0;
+ int is_input = 0;
+
+ /* Try out first */
+ chip_data = container_of(chip, struct htcpld_chip, chip_out);
+ if (!chip_data) {
+ /* Try in */
+ is_input = 1;
+ chip_data = container_of(chip, struct htcpld_chip, chip_in);
+ if (!chip_data)
+ return -EINVAL;
+ }
+
+ /* Determine if this is an input or output GPIO */
+ if (!is_input)
+ /* Use the output cache */
+ val = (chip_data->cache_out >> offset) & 1;
+ else
+ /* Use the input cache */
+ val = (chip_data->cache_in >> offset) & 1;
+
+ if (val)
+ return 1;
+ else
+ return 0;
+}
+
+static int htcpld_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ htcpld_chip_set(chip, offset, value);
+ return 0;
+}
+
+static int htcpld_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ /*
+ * No-op: this function can only be called on the input chip.
+ * We do however make sure the offset is within range.
+ */
+ return (offset < chip->ngpio) ? 0 : -EINVAL;
+}
+
+int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct htcpld_chip *chip_data;
+
+ chip_data = container_of(chip, struct htcpld_chip, chip_in);
+
+ if (offset < chip_data->nirqs)
+ return chip_data->irq_start + offset;
+ else
+ return -EINVAL;
+}
+
+void htcpld_chip_reset(struct i2c_client *client)
+{
+ struct htcpld_chip *chip_data = i2c_get_clientdata(client);
+ if (!chip_data)
+ return;
+
+ i2c_smbus_read_byte_data(
+ client, (chip_data->cache_out = chip_data->reset));
+}
+
+static int __devinit htcpld_setup_chip_irq(
+ struct platform_device *pdev,
+ int chip_index)
+{
+ struct htcpld_data *htcpld;
+ struct device *dev = &pdev->dev;
+ struct htcpld_core_platform_data *pdata;
+ struct htcpld_chip *chip;
+ struct htcpld_chip_platform_data *plat_chip_data;
+ unsigned int irq, irq_end;
+ int ret = 0;
+
+ /* Get the platform and driver data */
+ pdata = dev->platform_data;
+ htcpld = platform_get_drvdata(pdev);
+ chip = &htcpld->chip[chip_index];
+ plat_chip_data = &pdata->chip[chip_index];
+
+ /* Setup irq handlers */
+ irq_end = chip->irq_start + chip->nirqs;
+ for (irq = chip->irq_start; irq < irq_end; irq++) {
+ set_irq_chip(irq, &htcpld_muxed_chip);
+ set_irq_chip_data(irq, chip);
+ set_irq_handler(irq, handle_simple_irq);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+#else
+ set_irq_probe(irq);
+#endif
+ }
+
+ return ret;
+}
+
+static int __devinit htcpld_register_chip_i2c(
+ struct platform_device *pdev,
+ int chip_index)
+{
+ struct htcpld_data *htcpld;
+ struct device *dev = &pdev->dev;
+ struct htcpld_core_platform_data *pdata;
+ struct htcpld_chip *chip;
+ struct htcpld_chip_platform_data *plat_chip_data;
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+ struct i2c_board_info info;
+
+ /* Get the platform and driver data */
+ pdata = dev->platform_data;
+ htcpld = platform_get_drvdata(pdev);
+ chip = &htcpld->chip[chip_index];
+ plat_chip_data = &pdata->chip[chip_index];
+
+ adapter = i2c_get_adapter(pdata->i2c_adapter_id);
+ if (adapter == NULL) {
+ /* Eek, no such I2C adapter! Bail out. */
+ dev_warn(dev, "Chip at i2c address 0x%x: Invalid i2c adapter %d\n",
+ plat_chip_data->addr, pdata->i2c_adapter_id);
+ return -ENODEV;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
+ dev_warn(dev, "i2c adapter %d non-functional\n",
+ pdata->i2c_adapter_id);
+ return -EINVAL;
+ }
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = plat_chip_data->addr;
+ strlcpy(info.type, "htcpld-chip", I2C_NAME_SIZE);
+ info.platform_data = chip;
+
+ /* Add the I2C device. This calls the probe() function. */
+ client = i2c_new_device(adapter, &info);
+ if (!client) {
+ /* I2C device registration failed, contineu with the next */
+ dev_warn(dev, "Unable to add I2C device for 0x%x\n",
+ plat_chip_data->addr);
+ return -ENODEV;
+ }
+
+ i2c_set_clientdata(client, chip);
+ snprintf(client->name, I2C_NAME_SIZE, "Chip_0x%d", client->addr);
+ chip->client = client;
+
+ /* Reset the chip */
+ htcpld_chip_reset(client);
+ chip->cache_in = i2c_smbus_read_byte_data(client, chip->cache_out);
+
+ return 0;
+}
+
+static void __devinit htcpld_unregister_chip_i2c(
+ struct platform_device *pdev,
+ int chip_index)
+{
+ struct htcpld_data *htcpld;
+ struct htcpld_chip *chip;
+
+ /* Get the platform and driver data */
+ htcpld = platform_get_drvdata(pdev);
+ chip = &htcpld->chip[chip_index];
+
+ if (chip->client)
+ i2c_unregister_device(chip->client);
+}
+
+static int __devinit htcpld_register_chip_gpio(
+ struct platform_device *pdev,
+ int chip_index)
+{
+ struct htcpld_data *htcpld;
+ struct device *dev = &pdev->dev;
+ struct htcpld_core_platform_data *pdata;
+ struct htcpld_chip *chip;
+ struct htcpld_chip_platform_data *plat_chip_data;
+ struct gpio_chip *gpio_chip;
+ int ret = 0;
+
+ /* Get the platform and driver data */
+ pdata = dev->platform_data;
+ htcpld = platform_get_drvdata(pdev);
+ chip = &htcpld->chip[chip_index];
+ plat_chip_data = &pdata->chip[chip_index];
+
+ /* Setup the GPIO chips */
+ gpio_chip = &(chip->chip_out);
+ gpio_chip->label = "htcpld-out";
+ gpio_chip->dev = dev;
+ gpio_chip->owner = THIS_MODULE;
+ gpio_chip->get = htcpld_chip_get;
+ gpio_chip->set = htcpld_chip_set;
+ gpio_chip->direction_input = NULL;
+ gpio_chip->direction_output = htcpld_direction_output;
+ gpio_chip->base = plat_chip_data->gpio_out_base;
+ gpio_chip->ngpio = plat_chip_data->num_gpios;
+
+ gpio_chip = &(chip->chip_in);
+ gpio_chip->label = "htcpld-in";
+ gpio_chip->dev = dev;
+ gpio_chip->owner = THIS_MODULE;
+ gpio_chip->get = htcpld_chip_get;
+ gpio_chip->set = NULL;
+ gpio_chip->direction_input = htcpld_direction_input;
+ gpio_chip->direction_output = NULL;
+ gpio_chip->to_irq = htcpld_chip_to_irq;
+ gpio_chip->base = plat_chip_data->gpio_in_base;
+ gpio_chip->ngpio = plat_chip_data->num_gpios;
+
+ /* Add the GPIO chips */
+ ret = gpiochip_add(&(chip->chip_out));
+ if (ret) {
+ dev_warn(dev, "Unable to register output GPIOs for 0x%x: %d\n",
+ plat_chip_data->addr, ret);
+ return ret;
+ }
+
+ ret = gpiochip_add(&(chip->chip_in));
+ if (ret) {
+ int error;
+
+ dev_warn(dev, "Unable to register input GPIOs for 0x%x: %d\n",
+ plat_chip_data->addr, ret);
+
+ error = gpiochip_remove(&(chip->chip_out));
+ if (error)
+ dev_warn(dev, "Error while trying to unregister gpio chip: %d\n", error);
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __devinit htcpld_setup_chips(struct platform_device *pdev)
+{
+ struct htcpld_data *htcpld;
+ struct device *dev = &pdev->dev;
+ struct htcpld_core_platform_data *pdata;
+ int i;
+
+ /* Get the platform and driver data */
+ pdata = dev->platform_data;
+ htcpld = platform_get_drvdata(pdev);
+
+ /* Setup each chip's output GPIOs */
+ htcpld->nchips = pdata->num_chip;
+ htcpld->chip = kzalloc(sizeof(struct htcpld_chip) * htcpld->nchips,
+ GFP_KERNEL);
+ if (!htcpld->chip) {
+ dev_warn(dev, "Unable to allocate memory for chips\n");
+ return -ENOMEM;
+ }
+
+ /* Add the chips as best we can */
+ for (i = 0; i < htcpld->nchips; i++) {
+ int ret;
+
+ /* Setup the HTCPLD chips */
+ htcpld->chip[i].reset = pdata->chip[i].reset;
+ htcpld->chip[i].cache_out = pdata->chip[i].reset;
+ htcpld->chip[i].cache_in = 0;
+ htcpld->chip[i].dev = dev;
+ htcpld->chip[i].irq_start = pdata->chip[i].irq_base;
+ htcpld->chip[i].nirqs = pdata->chip[i].num_irqs;
+
+ INIT_WORK(&(htcpld->chip[i].set_val_work), &htcpld_chip_set_ni);
+ spin_lock_init(&(htcpld->chip[i].lock));
+
+ /* Setup the interrupts for the chip */
+ if (htcpld->chained_irq) {
+ ret = htcpld_setup_chip_irq(pdev, i);
+ if (ret)
+ continue;
+ }
+
+ /* Register the chip with I2C */
+ ret = htcpld_register_chip_i2c(pdev, i);
+ if (ret)
+ continue;
+
+
+ /* Register the chips with the GPIO subsystem */
+ ret = htcpld_register_chip_gpio(pdev, i);
+ if (ret) {
+ /* Unregister the chip from i2c and continue */
+ htcpld_unregister_chip_i2c(pdev, i);
+ continue;
+ }
+
+ dev_info(dev, "Registered chip at 0x%x\n", pdata->chip[i].addr);
+ }
+
+ return 0;
+}
+
+static int __devinit htcpld_core_probe(struct platform_device *pdev)
+{
+ struct htcpld_data *htcpld;
+ struct device *dev = &pdev->dev;
+ struct htcpld_core_platform_data *pdata;
+ struct resource *res;
+ int ret = 0;
+
+ if (!dev)
+ return -ENODEV;
+
+ pdata = dev->platform_data;
+ if (!pdata) {
+ dev_warn(dev, "Platform data not found for htcpld core!\n");
+ return -ENXIO;
+ }
+
+ htcpld = kzalloc(sizeof(struct htcpld_data), GFP_KERNEL);
+ if (!htcpld)
+ return -ENOMEM;
+
+ /* Find chained irq */
+ ret = -EINVAL;
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res) {
+ int flags;
+ htcpld->chained_irq = res->start;
+
+ /* Setup the chained interrupt handler */
+ flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
+ ret = request_threaded_irq(htcpld->chained_irq,
+ NULL, htcpld_handler,
+ flags, pdev->name, htcpld);
+ if (ret) {
+ dev_warn(dev, "Unable to setup chained irq handler: %d\n", ret);
+ goto fail;
+ } else
+ device_init_wakeup(dev, 0);
+ }
+
+ /* Set the driver data */
+ platform_set_drvdata(pdev, htcpld);
+
+ /* Setup the htcpld chips */
+ ret = htcpld_setup_chips(pdev);
+ if (ret)
+ goto fail;
+
+ /* Request the GPIO(s) for the int reset and set them up */
+ if (pdata->int_reset_gpio_hi) {
+ ret = gpio_request(pdata->int_reset_gpio_hi, "htcpld-core");
+ if (ret) {
+ /*
+ * If it failed, that sucks, but we can probably
+ * continue on without it.
+ */
+ dev_warn(dev, "Unable to request int_reset_gpio_hi -- interrupts may not work\n");
+ htcpld->int_reset_gpio_hi = 0;
+ } else {
+ htcpld->int_reset_gpio_hi = pdata->int_reset_gpio_hi;
+ gpio_set_value(htcpld->int_reset_gpio_hi, 1);
+ }
+ }
+
+ if (pdata->int_reset_gpio_lo) {
+ ret = gpio_request(pdata->int_reset_gpio_lo, "htcpld-core");
+ if (ret) {
+ /*
+ * If it failed, that sucks, but we can probably
+ * continue on without it.
+ */
+ dev_warn(dev, "Unable to request int_reset_gpio_lo -- interrupts may not work\n");
+ htcpld->int_reset_gpio_lo = 0;
+ } else {
+ htcpld->int_reset_gpio_lo = pdata->int_reset_gpio_lo;
+ gpio_set_value(htcpld->int_reset_gpio_lo, 0);
+ }
+ }
+
+ dev_info(dev, "Initialized successfully\n");
+ return 0;
+
+fail:
+ kfree(htcpld);
+ return ret;
+}
+
+/* The I2C Driver -- used internally */
+static const struct i2c_device_id htcpld_chip_id[] = {
+ { "htcpld-chip", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, htcpld_chip_id);
+
+
+static struct i2c_driver htcpld_chip_driver = {
+ .driver = {
+ .name = "htcpld-chip",
+ },
+ .id_table = htcpld_chip_id,
+};
+
+/* The Core Driver */
+static struct platform_driver htcpld_core_driver = {
+ .driver = {
+ .name = "i2c-htcpld",
+ },
+};
+
+static int __init htcpld_core_init(void)
+{
+ int ret;
+
+ /* Register the I2C Chip driver */
+ ret = i2c_add_driver(&htcpld_chip_driver);
+ if (ret)
+ return ret;
+
+ /* Probe for our chips */
+ return platform_driver_probe(&htcpld_core_driver, htcpld_core_probe);
+}
+
+static void __exit htcpld_core_exit(void)
+{
+ i2c_del_driver(&htcpld_chip_driver);
+ platform_driver_unregister(&htcpld_core_driver);
+}
+
+module_init(htcpld_core_init);
+module_exit(htcpld_core_exit);
+
+MODULE_AUTHOR("Cory Maccarrone <darkstar6262@gmail.com>");
+MODULE_DESCRIPTION("I2C HTC PLD Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c
new file mode 100644
index 000000000000..51b2f6065a0b
--- /dev/null
+++ b/drivers/mfd/lpc_sch.c
@@ -0,0 +1,133 @@
+/*
+ * lpc_sch.c - LPC interface for Intel Poulsbo SCH
+ *
+ * LPC bridge function of the Intel SCH contains many other
+ * functional units, such as Interrupt controllers, Timers,
+ * Power Management, System Management, GPIO, RTC, and LPC
+ * Configuration Registers.
+ *
+ * Copyright (c) 2010 CompuLab Ltd
+ * Author: Denis Turischev <denis@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include <linux/mfd/core.h>
+
+#define SMBASE 0x40
+#define SMBUS_IO_SIZE 64
+
+#define GPIOBASE 0x44
+#define GPIO_IO_SIZE 64
+
+static struct resource smbus_sch_resource = {
+ .flags = IORESOURCE_IO,
+};
+
+
+static struct resource gpio_sch_resource = {
+ .flags = IORESOURCE_IO,
+};
+
+static struct mfd_cell lpc_sch_cells[] = {
+ {
+ .name = "isch_smbus",
+ .num_resources = 1,
+ .resources = &smbus_sch_resource,
+ },
+ {
+ .name = "sch_gpio",
+ .num_resources = 1,
+ .resources = &gpio_sch_resource,
+ },
+};
+
+static struct pci_device_id lpc_sch_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, lpc_sch_ids);
+
+static int __devinit lpc_sch_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ unsigned int base_addr_cfg;
+ unsigned short base_addr;
+
+ pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
+ if (!(base_addr_cfg & (1 << 31))) {
+ dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n");
+ return -ENODEV;
+ }
+ base_addr = (unsigned short)base_addr_cfg;
+ if (base_addr == 0) {
+ dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
+ return -ENODEV;
+ }
+
+ smbus_sch_resource.start = base_addr;
+ smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
+
+ pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
+ if (!(base_addr_cfg & (1 << 31))) {
+ dev_err(&dev->dev, "Decode of the GPIO I/O range disabled\n");
+ return -ENODEV;
+ }
+ base_addr = (unsigned short)base_addr_cfg;
+ if (base_addr == 0) {
+ dev_err(&dev->dev, "I/O space for GPIO uninitialized\n");
+ return -ENODEV;
+ }
+
+ gpio_sch_resource.start = base_addr;
+ gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
+
+ return mfd_add_devices(&dev->dev, -1,
+ lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0);
+}
+
+static void __devexit lpc_sch_remove(struct pci_dev *dev)
+{
+ mfd_remove_devices(&dev->dev);
+}
+
+static struct pci_driver lpc_sch_driver = {
+ .name = "lpc_sch",
+ .id_table = lpc_sch_ids,
+ .probe = lpc_sch_probe,
+ .remove = __devexit_p(lpc_sch_remove),
+};
+
+static int __init lpc_sch_init(void)
+{
+ return pci_register_driver(&lpc_sch_driver);
+}
+
+static void __exit lpc_sch_exit(void)
+{
+ pci_unregister_driver(&lpc_sch_driver);
+}
+
+module_init(lpc_sch_init);
+module_exit(lpc_sch_exit);
+
+MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
+MODULE_DESCRIPTION("LPC interface for Intel Poulsbo SCH");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c
new file mode 100644
index 000000000000..85d63c04749b
--- /dev/null
+++ b/drivers/mfd/max8925-core.c
@@ -0,0 +1,656 @@
+/*
+ * Base driver for Maxim MAX8925
+ *
+ * Copyright (C) 2009-2010 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max8925.h>
+
+static struct resource backlight_resources[] = {
+ {
+ .name = "max8925-backlight",
+ .start = MAX8925_WLED_MODE_CNTL,
+ .end = MAX8925_WLED_CNTL,
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static struct mfd_cell backlight_devs[] = {
+ {
+ .name = "max8925-backlight",
+ .num_resources = 1,
+ .resources = &backlight_resources[0],
+ .id = -1,
+ },
+};
+
+static struct resource touch_resources[] = {
+ {
+ .name = "max8925-tsc",
+ .start = MAX8925_TSC_IRQ,
+ .end = MAX8925_ADC_RES_END,
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static struct mfd_cell touch_devs[] = {
+ {
+ .name = "max8925-touch",
+ .num_resources = 1,
+ .resources = &touch_resources[0],
+ .id = -1,
+ },
+};
+
+static struct resource power_supply_resources[] = {
+ {
+ .name = "max8925-power",
+ .start = MAX8925_CHG_IRQ1,
+ .end = MAX8925_CHG_IRQ1_MASK,
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static struct mfd_cell power_devs[] = {
+ {
+ .name = "max8925-power",
+ .num_resources = 1,
+ .resources = &power_supply_resources[0],
+ .id = -1,
+ },
+};
+
+static struct resource rtc_resources[] = {
+ {
+ .name = "max8925-rtc",
+ .start = MAX8925_RTC_IRQ,
+ .end = MAX8925_RTC_IRQ_MASK,
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static struct mfd_cell rtc_devs[] = {
+ {
+ .name = "max8925-rtc",
+ .num_resources = 1,
+ .resources = &rtc_resources[0],
+ .id = -1,
+ },
+};
+
+#define MAX8925_REG_RESOURCE(_start, _end) \
+{ \
+ .start = MAX8925_##_start, \
+ .end = MAX8925_##_end, \
+ .flags = IORESOURCE_IO, \
+}
+
+static struct resource regulator_resources[] = {
+ MAX8925_REG_RESOURCE(SDCTL1, SDCTL1),
+ MAX8925_REG_RESOURCE(SDCTL2, SDCTL2),
+ MAX8925_REG_RESOURCE(SDCTL3, SDCTL3),
+ MAX8925_REG_RESOURCE(LDOCTL1, LDOCTL1),
+ MAX8925_REG_RESOURCE(LDOCTL2, LDOCTL2),
+ MAX8925_REG_RESOURCE(LDOCTL3, LDOCTL3),
+ MAX8925_REG_RESOURCE(LDOCTL4, LDOCTL4),
+ MAX8925_REG_RESOURCE(LDOCTL5, LDOCTL5),
+ MAX8925_REG_RESOURCE(LDOCTL6, LDOCTL6),
+ MAX8925_REG_RESOURCE(LDOCTL7, LDOCTL7),
+ MAX8925_REG_RESOURCE(LDOCTL8, LDOCTL8),
+ MAX8925_REG_RESOURCE(LDOCTL9, LDOCTL9),
+ MAX8925_REG_RESOURCE(LDOCTL10, LDOCTL10),
+ MAX8925_REG_RESOURCE(LDOCTL11, LDOCTL11),
+ MAX8925_REG_RESOURCE(LDOCTL12, LDOCTL12),
+ MAX8925_REG_RESOURCE(LDOCTL13, LDOCTL13),
+ MAX8925_REG_RESOURCE(LDOCTL14, LDOCTL14),
+ MAX8925_REG_RESOURCE(LDOCTL15, LDOCTL15),
+ MAX8925_REG_RESOURCE(LDOCTL16, LDOCTL16),
+ MAX8925_REG_RESOURCE(LDOCTL17, LDOCTL17),
+ MAX8925_REG_RESOURCE(LDOCTL18, LDOCTL18),
+ MAX8925_REG_RESOURCE(LDOCTL19, LDOCTL19),
+ MAX8925_REG_RESOURCE(LDOCTL20, LDOCTL20),
+};
+
+#define MAX8925_REG_DEVS(_id) \
+{ \
+ .name = "max8925-regulator", \
+ .num_resources = 1, \
+ .resources = &regulator_resources[MAX8925_ID_##_id], \
+ .id = MAX8925_ID_##_id, \
+}
+
+static struct mfd_cell regulator_devs[] = {
+ MAX8925_REG_DEVS(SD1),
+ MAX8925_REG_DEVS(SD2),
+ MAX8925_REG_DEVS(SD3),
+ MAX8925_REG_DEVS(LDO1),
+ MAX8925_REG_DEVS(LDO2),
+ MAX8925_REG_DEVS(LDO3),
+ MAX8925_REG_DEVS(LDO4),
+ MAX8925_REG_DEVS(LDO5),
+ MAX8925_REG_DEVS(LDO6),
+ MAX8925_REG_DEVS(LDO7),
+ MAX8925_REG_DEVS(LDO8),
+ MAX8925_REG_DEVS(LDO9),
+ MAX8925_REG_DEVS(LDO10),
+ MAX8925_REG_DEVS(LDO11),
+ MAX8925_REG_DEVS(LDO12),
+ MAX8925_REG_DEVS(LDO13),
+ MAX8925_REG_DEVS(LDO14),
+ MAX8925_REG_DEVS(LDO15),
+ MAX8925_REG_DEVS(LDO16),
+ MAX8925_REG_DEVS(LDO17),
+ MAX8925_REG_DEVS(LDO18),
+ MAX8925_REG_DEVS(LDO19),
+ MAX8925_REG_DEVS(LDO20),
+};
+
+enum {
+ FLAGS_ADC = 1, /* register in ADC component */
+ FLAGS_RTC, /* register in RTC component */
+};
+
+struct max8925_irq_data {
+ int reg;
+ int mask_reg;
+ int enable; /* enable or not */
+ int offs; /* bit offset in mask register */
+ int flags;
+ int tsc_irq;
+};
+
+static struct max8925_irq_data max8925_irqs[] = {
+ [MAX8925_IRQ_VCHG_DC_OVP] = {
+ .reg = MAX8925_CHG_IRQ1,
+ .mask_reg = MAX8925_CHG_IRQ1_MASK,
+ .offs = 1 << 0,
+ },
+ [MAX8925_IRQ_VCHG_DC_F] = {
+ .reg = MAX8925_CHG_IRQ1,
+ .mask_reg = MAX8925_CHG_IRQ1_MASK,
+ .offs = 1 << 1,
+ },
+ [MAX8925_IRQ_VCHG_DC_R] = {
+ .reg = MAX8925_CHG_IRQ1,
+ .mask_reg = MAX8925_CHG_IRQ1_MASK,
+ .offs = 1 << 2,
+ },
+ [MAX8925_IRQ_VCHG_USB_OVP] = {
+ .reg = MAX8925_CHG_IRQ1,
+ .mask_reg = MAX8925_CHG_IRQ1_MASK,
+ .offs = 1 << 3,
+ },
+ [MAX8925_IRQ_VCHG_USB_F] = {
+ .reg = MAX8925_CHG_IRQ1,
+ .mask_reg = MAX8925_CHG_IRQ1_MASK,
+ .offs = 1 << 4,
+ },
+ [MAX8925_IRQ_VCHG_USB_R] = {
+ .reg = MAX8925_CHG_IRQ1,
+ .mask_reg = MAX8925_CHG_IRQ1_MASK,
+ .offs = 1 << 5,
+ },
+ [MAX8925_IRQ_VCHG_THM_OK_R] = {
+ .reg = MAX8925_CHG_IRQ2,
+ .mask_reg = MAX8925_CHG_IRQ2_MASK,
+ .offs = 1 << 0,
+ },
+ [MAX8925_IRQ_VCHG_THM_OK_F] = {
+ .reg = MAX8925_CHG_IRQ2,
+ .mask_reg = MAX8925_CHG_IRQ2_MASK,
+ .offs = 1 << 1,
+ },
+ [MAX8925_IRQ_VCHG_SYSLOW_F] = {
+ .reg = MAX8925_CHG_IRQ2,
+ .mask_reg = MAX8925_CHG_IRQ2_MASK,
+ .offs = 1 << 2,
+ },
+ [MAX8925_IRQ_VCHG_SYSLOW_R] = {
+ .reg = MAX8925_CHG_IRQ2,
+ .mask_reg = MAX8925_CHG_IRQ2_MASK,
+ .offs = 1 << 3,
+ },
+ [MAX8925_IRQ_VCHG_RST] = {
+ .reg = MAX8925_CHG_IRQ2,
+ .mask_reg = MAX8925_CHG_IRQ2_MASK,
+ .offs = 1 << 4,
+ },
+ [MAX8925_IRQ_VCHG_DONE] = {
+ .reg = MAX8925_CHG_IRQ2,
+ .mask_reg = MAX8925_CHG_IRQ2_MASK,
+ .offs = 1 << 5,
+ },
+ [MAX8925_IRQ_VCHG_TOPOFF] = {
+ .reg = MAX8925_CHG_IRQ2,
+ .mask_reg = MAX8925_CHG_IRQ2_MASK,
+ .offs = 1 << 6,
+ },
+ [MAX8925_IRQ_VCHG_TMR_FAULT] = {
+ .reg = MAX8925_CHG_IRQ2,
+ .mask_reg = MAX8925_CHG_IRQ2_MASK,
+ .offs = 1 << 7,
+ },
+ [MAX8925_IRQ_GPM_RSTIN] = {
+ .reg = MAX8925_ON_OFF_IRQ1,
+ .mask_reg = MAX8925_ON_OFF_IRQ1_MASK,
+ .offs = 1 << 0,
+ },
+ [MAX8925_IRQ_GPM_MPL] = {
+ .reg = MAX8925_ON_OFF_IRQ1,
+ .mask_reg = MAX8925_ON_OFF_IRQ1_MASK,
+ .offs = 1 << 1,
+ },
+ [MAX8925_IRQ_GPM_SW_3SEC] = {
+ .reg = MAX8925_ON_OFF_IRQ1,
+ .mask_reg = MAX8925_ON_OFF_IRQ1_MASK,
+ .offs = 1 << 2,
+ },
+ [MAX8925_IRQ_GPM_EXTON_F] = {
+ .reg = MAX8925_ON_OFF_IRQ1,
+ .mask_reg = MAX8925_ON_OFF_IRQ1_MASK,
+ .offs = 1 << 3,
+ },
+ [MAX8925_IRQ_GPM_EXTON_R] = {
+ .reg = MAX8925_ON_OFF_IRQ1,
+ .mask_reg = MAX8925_ON_OFF_IRQ1_MASK,
+ .offs = 1 << 4,
+ },
+ [MAX8925_IRQ_GPM_SW_1SEC] = {
+ .reg = MAX8925_ON_OFF_IRQ1,
+ .mask_reg = MAX8925_ON_OFF_IRQ1_MASK,
+ .offs = 1 << 5,
+ },
+ [MAX8925_IRQ_GPM_SW_F] = {
+ .reg = MAX8925_ON_OFF_IRQ1,
+ .mask_reg = MAX8925_ON_OFF_IRQ1_MASK,
+ .offs = 1 << 6,
+ },
+ [MAX8925_IRQ_GPM_SW_R] = {
+ .reg = MAX8925_ON_OFF_IRQ1,
+ .mask_reg = MAX8925_ON_OFF_IRQ1_MASK,
+ .offs = 1 << 7,
+ },
+ [MAX8925_IRQ_GPM_SYSCKEN_F] = {
+ .reg = MAX8925_ON_OFF_IRQ2,
+ .mask_reg = MAX8925_ON_OFF_IRQ2_MASK,
+ .offs = 1 << 0,
+ },
+ [MAX8925_IRQ_GPM_SYSCKEN_R] = {
+ .reg = MAX8925_ON_OFF_IRQ2,
+ .mask_reg = MAX8925_ON_OFF_IRQ2_MASK,
+ .offs = 1 << 1,
+ },
+ [MAX8925_IRQ_RTC_ALARM1] = {
+ .reg = MAX8925_RTC_IRQ,
+ .mask_reg = MAX8925_RTC_IRQ_MASK,
+ .offs = 1 << 2,
+ .flags = FLAGS_RTC,
+ },
+ [MAX8925_IRQ_RTC_ALARM0] = {
+ .reg = MAX8925_RTC_IRQ,
+ .mask_reg = MAX8925_RTC_IRQ_MASK,
+ .offs = 1 << 3,
+ .flags = FLAGS_RTC,
+ },
+ [MAX8925_IRQ_TSC_STICK] = {
+ .reg = MAX8925_TSC_IRQ,
+ .mask_reg = MAX8925_TSC_IRQ_MASK,
+ .offs = 1 << 0,
+ .flags = FLAGS_ADC,
+ .tsc_irq = 1,
+ },
+ [MAX8925_IRQ_TSC_NSTICK] = {
+ .reg = MAX8925_TSC_IRQ,
+ .mask_reg = MAX8925_TSC_IRQ_MASK,
+ .offs = 1 << 1,
+ .flags = FLAGS_ADC,
+ .tsc_irq = 1,
+ },
+};
+
+static inline struct max8925_irq_data *irq_to_max8925(struct max8925_chip *chip,
+ int irq)
+{
+ return &max8925_irqs[irq - chip->irq_base];
+}
+
+static irqreturn_t max8925_irq(int irq, void *data)
+{
+ struct max8925_chip *chip = data;
+ struct max8925_irq_data *irq_data;
+ struct i2c_client *i2c;
+ int read_reg = -1, value = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) {
+ irq_data = &max8925_irqs[i];
+ /* TSC IRQ should be serviced in max8925_tsc_irq() */
+ if (irq_data->tsc_irq)
+ continue;
+ if (irq_data->flags == FLAGS_RTC)
+ i2c = chip->rtc;
+ else if (irq_data->flags == FLAGS_ADC)
+ i2c = chip->adc;
+ else
+ i2c = chip->i2c;
+ if (read_reg != irq_data->reg) {
+ read_reg = irq_data->reg;
+ value = max8925_reg_read(i2c, irq_data->reg);
+ }
+ if (value & irq_data->enable)
+ handle_nested_irq(chip->irq_base + i);
+ }
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t max8925_tsc_irq(int irq, void *data)
+{
+ struct max8925_chip *chip = data;
+ struct max8925_irq_data *irq_data;
+ struct i2c_client *i2c;
+ int read_reg = -1, value = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) {
+ irq_data = &max8925_irqs[i];
+ /* non TSC IRQ should be serviced in max8925_irq() */
+ if (!irq_data->tsc_irq)
+ continue;
+ if (irq_data->flags == FLAGS_RTC)
+ i2c = chip->rtc;
+ else if (irq_data->flags == FLAGS_ADC)
+ i2c = chip->adc;
+ else
+ i2c = chip->i2c;
+ if (read_reg != irq_data->reg) {
+ read_reg = irq_data->reg;
+ value = max8925_reg_read(i2c, irq_data->reg);
+ }
+ if (value & irq_data->enable)
+ handle_nested_irq(chip->irq_base + i);
+ }
+ return IRQ_HANDLED;
+}
+
+static void max8925_irq_lock(unsigned int irq)
+{
+ struct max8925_chip *chip = get_irq_chip_data(irq);
+
+ mutex_lock(&chip->irq_lock);
+}
+
+static void max8925_irq_sync_unlock(unsigned int irq)
+{
+ struct max8925_chip *chip = get_irq_chip_data(irq);
+ struct max8925_irq_data *irq_data;
+ static unsigned char cache_chg[2] = {0xff, 0xff};
+ static unsigned char cache_on[2] = {0xff, 0xff};
+ static unsigned char cache_rtc = 0xff, cache_tsc = 0xff;
+ unsigned char irq_chg[2], irq_on[2];
+ unsigned char irq_rtc, irq_tsc;
+ int i;
+
+ /* Load cached value. In initial, all IRQs are masked */
+ irq_chg[0] = cache_chg[0];
+ irq_chg[1] = cache_chg[1];
+ irq_on[0] = cache_on[0];
+ irq_on[1] = cache_on[1];
+ irq_rtc = cache_rtc;
+ irq_tsc = cache_tsc;
+ for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) {
+ irq_data = &max8925_irqs[i];
+ switch (irq_data->mask_reg) {
+ case MAX8925_CHG_IRQ1_MASK:
+ irq_chg[0] &= irq_data->enable;
+ break;
+ case MAX8925_CHG_IRQ2_MASK:
+ irq_chg[1] &= irq_data->enable;
+ break;
+ case MAX8925_ON_OFF_IRQ1_MASK:
+ irq_on[0] &= irq_data->enable;
+ break;
+ case MAX8925_ON_OFF_IRQ2_MASK:
+ irq_on[1] &= irq_data->enable;
+ break;
+ case MAX8925_RTC_IRQ_MASK:
+ irq_rtc &= irq_data->enable;
+ break;
+ case MAX8925_TSC_IRQ_MASK:
+ irq_tsc &= irq_data->enable;
+ break;
+ default:
+ dev_err(chip->dev, "wrong IRQ\n");
+ break;
+ }
+ }
+ /* update mask into registers */
+ if (cache_chg[0] != irq_chg[0]) {
+ cache_chg[0] = irq_chg[0];
+ max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ1_MASK,
+ irq_chg[0]);
+ }
+ if (cache_chg[1] != irq_chg[1]) {
+ cache_chg[1] = irq_chg[1];
+ max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ2_MASK,
+ irq_chg[1]);
+ }
+ if (cache_on[0] != irq_on[0]) {
+ cache_on[0] = irq_on[0];
+ max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ1_MASK,
+ irq_on[0]);
+ }
+ if (cache_on[1] != irq_on[1]) {
+ cache_on[1] = irq_on[1];
+ max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ2_MASK,
+ irq_on[1]);
+ }
+ if (cache_rtc != irq_rtc) {
+ cache_rtc = irq_rtc;
+ max8925_reg_write(chip->rtc, MAX8925_RTC_IRQ_MASK, irq_rtc);
+ }
+ if (cache_tsc != irq_tsc) {
+ cache_tsc = irq_tsc;
+ max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, irq_tsc);
+ }
+
+ mutex_unlock(&chip->irq_lock);
+}
+
+static void max8925_irq_enable(unsigned int irq)
+{
+ struct max8925_chip *chip = get_irq_chip_data(irq);
+ max8925_irqs[irq - chip->irq_base].enable
+ = max8925_irqs[irq - chip->irq_base].offs;
+}
+
+static void max8925_irq_disable(unsigned int irq)
+{
+ struct max8925_chip *chip = get_irq_chip_data(irq);
+ max8925_irqs[irq - chip->irq_base].enable = 0;
+}
+
+static struct irq_chip max8925_irq_chip = {
+ .name = "max8925",
+ .bus_lock = max8925_irq_lock,
+ .bus_sync_unlock = max8925_irq_sync_unlock,
+ .enable = max8925_irq_enable,
+ .disable = max8925_irq_disable,
+};
+
+static int max8925_irq_init(struct max8925_chip *chip, int irq,
+ struct max8925_platform_data *pdata)
+{
+ unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+ struct irq_desc *desc;
+ int i, ret;
+ int __irq;
+
+ if (!pdata || !pdata->irq_base) {
+ dev_warn(chip->dev, "No interrupt support on IRQ base\n");
+ return -EINVAL;
+ }
+ /* clear all interrupts */
+ max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ1);
+ max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ2);
+ max8925_reg_read(chip->i2c, MAX8925_ON_OFF_IRQ1);
+ max8925_reg_read(chip->i2c, MAX8925_ON_OFF_IRQ2);
+ max8925_reg_read(chip->rtc, MAX8925_RTC_IRQ);
+ max8925_reg_read(chip->adc, MAX8925_TSC_IRQ);
+ /* mask all interrupts */
+ max8925_reg_write(chip->rtc, MAX8925_ALARM0_CNTL, 0);
+ max8925_reg_write(chip->rtc, MAX8925_ALARM1_CNTL, 0);
+ max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ1_MASK, 0xff);
+ max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ2_MASK, 0xff);
+ max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ1_MASK, 0xff);
+ max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ2_MASK, 0xff);
+ max8925_reg_write(chip->rtc, MAX8925_RTC_IRQ_MASK, 0xff);
+ max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, 0xff);
+
+ mutex_init(&chip->irq_lock);
+ chip->core_irq = irq;
+ chip->irq_base = pdata->irq_base;
+ desc = irq_to_desc(chip->core_irq);
+
+ /* register with genirq */
+ for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) {
+ __irq = i + chip->irq_base;
+ set_irq_chip_data(__irq, chip);
+ set_irq_chip_and_handler(__irq, &max8925_irq_chip,
+ handle_edge_irq);
+ set_irq_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(__irq, IRQF_VALID);
+#else
+ set_irq_noprobe(__irq);
+#endif
+ }
+ if (!irq) {
+ dev_warn(chip->dev, "No interrupt support on core IRQ\n");
+ goto tsc_irq;
+ }
+
+ ret = request_threaded_irq(irq, NULL, max8925_irq, flags,
+ "max8925", chip);
+ if (ret) {
+ dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret);
+ chip->core_irq = 0;
+ }
+tsc_irq:
+ if (!pdata->tsc_irq) {
+ dev_warn(chip->dev, "No interrupt support on TSC IRQ\n");
+ return 0;
+ }
+ chip->tsc_irq = pdata->tsc_irq;
+
+ ret = request_threaded_irq(chip->tsc_irq, NULL, max8925_tsc_irq,
+ flags, "max8925-tsc", chip);
+ if (ret) {
+ dev_err(chip->dev, "Failed to request TSC IRQ: %d\n", ret);
+ chip->tsc_irq = 0;
+ }
+ return 0;
+}
+
+int __devinit max8925_device_init(struct max8925_chip *chip,
+ struct max8925_platform_data *pdata)
+{
+ int ret;
+
+ max8925_irq_init(chip, chip->i2c->irq, pdata);
+
+ if (pdata && (pdata->power || pdata->touch)) {
+ /* enable ADC to control internal reference */
+ max8925_set_bits(chip->i2c, MAX8925_RESET_CNFG, 1, 1);
+ /* enable internal reference for ADC */
+ max8925_set_bits(chip->adc, MAX8925_TSC_CNFG1, 3, 2);
+ /* check for internal reference IRQ */
+ do {
+ ret = max8925_reg_read(chip->adc, MAX8925_TSC_IRQ);
+ } while (ret & MAX8925_NREF_OK);
+ /* enaable ADC scheduler, interval is 1 second */
+ max8925_set_bits(chip->adc, MAX8925_ADC_SCHED, 3, 2);
+ }
+
+ /* enable Momentary Power Loss */
+ max8925_set_bits(chip->rtc, MAX8925_MPL_CNTL, 1 << 4, 1 << 4);
+
+ ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
+ ARRAY_SIZE(rtc_devs),
+ &rtc_resources[0], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add rtc subdev\n");
+ goto out;
+ }
+ if (pdata && pdata->regulator[0]) {
+ ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
+ ARRAY_SIZE(regulator_devs),
+ &regulator_resources[0], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add regulator subdev\n");
+ goto out_dev;
+ }
+ }
+
+ if (pdata && pdata->backlight) {
+ ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0],
+ ARRAY_SIZE(backlight_devs),
+ &backlight_resources[0], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add backlight subdev\n");
+ goto out_dev;
+ }
+ }
+
+ if (pdata && pdata->power) {
+ ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
+ ARRAY_SIZE(power_devs),
+ &power_supply_resources[0], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add power supply "
+ "subdev\n");
+ goto out_dev;
+ }
+ }
+
+ if (pdata && pdata->touch) {
+ ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
+ ARRAY_SIZE(touch_devs),
+ &touch_resources[0], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add touch subdev\n");
+ goto out_dev;
+ }
+ }
+
+ return 0;
+out_dev:
+ mfd_remove_devices(chip->dev);
+out:
+ return ret;
+}
+
+void __devexit max8925_device_exit(struct max8925_chip *chip)
+{
+ if (chip->core_irq)
+ free_irq(chip->core_irq, chip);
+ if (chip->tsc_irq)
+ free_irq(chip->tsc_irq, chip);
+ mfd_remove_devices(chip->dev);
+}
+
+
+MODULE_DESCRIPTION("PMIC Driver for Maxim MAX8925");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
new file mode 100644
index 000000000000..c0b883c14f41
--- /dev/null
+++ b/drivers/mfd/max8925-i2c.c
@@ -0,0 +1,211 @@
+/*
+ * I2C driver for Maxim MAX8925
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/mfd/max8925.h>
+
+#define RTC_I2C_ADDR 0x68
+#define ADC_I2C_ADDR 0x47
+
+static inline int max8925_read_device(struct i2c_client *i2c,
+ int reg, int bytes, void *dest)
+{
+ int ret;
+
+ if (bytes > 1)
+ ret = i2c_smbus_read_i2c_block_data(i2c, reg, bytes, dest);
+ else {
+ ret = i2c_smbus_read_byte_data(i2c, reg);
+ if (ret < 0)
+ return ret;
+ *(unsigned char *)dest = (unsigned char)ret;
+ }
+ return ret;
+}
+
+static inline int max8925_write_device(struct i2c_client *i2c,
+ int reg, int bytes, void *src)
+{
+ unsigned char buf[bytes + 1];
+ int ret;
+
+ buf[0] = (unsigned char)reg;
+ memcpy(&buf[1], src, bytes);
+
+ ret = i2c_master_send(i2c, buf, bytes + 1);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+int max8925_reg_read(struct i2c_client *i2c, int reg)
+{
+ struct max8925_chip *chip = i2c_get_clientdata(i2c);
+ unsigned char data = 0;
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = max8925_read_device(i2c, reg, 1, &data);
+ mutex_unlock(&chip->io_lock);
+
+ if (ret < 0)
+ return ret;
+ else
+ return (int)data;
+}
+EXPORT_SYMBOL(max8925_reg_read);
+
+int max8925_reg_write(struct i2c_client *i2c, int reg,
+ unsigned char data)
+{
+ struct max8925_chip *chip = i2c_get_clientdata(i2c);
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = max8925_write_device(i2c, reg, 1, &data);
+ mutex_unlock(&chip->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(max8925_reg_write);
+
+int max8925_bulk_read(struct i2c_client *i2c, int reg,
+ int count, unsigned char *buf)
+{
+ struct max8925_chip *chip = i2c_get_clientdata(i2c);
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = max8925_read_device(i2c, reg, count, buf);
+ mutex_unlock(&chip->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(max8925_bulk_read);
+
+int max8925_bulk_write(struct i2c_client *i2c, int reg,
+ int count, unsigned char *buf)
+{
+ struct max8925_chip *chip = i2c_get_clientdata(i2c);
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = max8925_write_device(i2c, reg, count, buf);
+ mutex_unlock(&chip->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(max8925_bulk_write);
+
+int max8925_set_bits(struct i2c_client *i2c, int reg,
+ unsigned char mask, unsigned char data)
+{
+ struct max8925_chip *chip = i2c_get_clientdata(i2c);
+ unsigned char value;
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = max8925_read_device(i2c, reg, 1, &value);
+ if (ret < 0)
+ goto out;
+ value &= ~mask;
+ value |= data;
+ ret = max8925_write_device(i2c, reg, 1, &value);
+out:
+ mutex_unlock(&chip->io_lock);
+ return ret;
+}
+EXPORT_SYMBOL(max8925_set_bits);
+
+
+static const struct i2c_device_id max8925_id_table[] = {
+ { "max8925", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, max8925_id_table);
+
+static int __devinit max8925_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max8925_platform_data *pdata = client->dev.platform_data;
+ static struct max8925_chip *chip;
+
+ if (!pdata) {
+ pr_info("%s: platform data is missing\n", __func__);
+ return -EINVAL;
+ }
+
+ chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL);
+ if (chip == NULL)
+ return -ENOMEM;
+ chip->i2c = client;
+ chip->dev = &client->dev;
+ i2c_set_clientdata(client, chip);
+ dev_set_drvdata(chip->dev, chip);
+ mutex_init(&chip->io_lock);
+
+ chip->rtc = i2c_new_dummy(chip->i2c->adapter, RTC_I2C_ADDR);
+ i2c_set_clientdata(chip->rtc, chip);
+
+ chip->adc = i2c_new_dummy(chip->i2c->adapter, ADC_I2C_ADDR);
+ i2c_set_clientdata(chip->adc, chip);
+
+ max8925_device_init(chip, pdata);
+
+ return 0;
+}
+
+static int __devexit max8925_remove(struct i2c_client *client)
+{
+ struct max8925_chip *chip = i2c_get_clientdata(client);
+
+ max8925_device_exit(chip);
+ i2c_unregister_device(chip->adc);
+ i2c_unregister_device(chip->rtc);
+ i2c_set_clientdata(chip->adc, NULL);
+ i2c_set_clientdata(chip->rtc, NULL);
+ i2c_set_clientdata(chip->i2c, NULL);
+ kfree(chip);
+ return 0;
+}
+
+static struct i2c_driver max8925_driver = {
+ .driver = {
+ .name = "max8925",
+ .owner = THIS_MODULE,
+ },
+ .probe = max8925_probe,
+ .remove = __devexit_p(max8925_remove),
+ .id_table = max8925_id_table,
+};
+
+static int __init max8925_i2c_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&max8925_driver);
+ if (ret != 0)
+ pr_err("Failed to register MAX8925 I2C driver: %d\n", ret);
+ return ret;
+}
+subsys_initcall(max8925_i2c_init);
+
+static void __exit max8925_i2c_exit(void)
+{
+ i2c_del_driver(&max8925_driver);
+}
+module_exit(max8925_i2c_exit);
+
+MODULE_DESCRIPTION("I2C Driver for Maxim 8925");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/mc13783-core.c b/drivers/mfd/mc13783-core.c
index a1ade2324ea9..62a847e4c2d8 100644
--- a/drivers/mfd/mc13783-core.c
+++ b/drivers/mfd/mc13783-core.c
@@ -225,7 +225,7 @@ int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset,
}
EXPORT_SYMBOL(mc13783_reg_rmw);
-int mc13783_mask(struct mc13783 *mc13783, int irq)
+int mc13783_irq_mask(struct mc13783 *mc13783, int irq)
{
int ret;
unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1;
@@ -245,9 +245,9 @@ int mc13783_mask(struct mc13783 *mc13783, int irq)
return mc13783_reg_write(mc13783, offmask, mask | irqbit);
}
-EXPORT_SYMBOL(mc13783_mask);
+EXPORT_SYMBOL(mc13783_irq_mask);
-int mc13783_unmask(struct mc13783 *mc13783, int irq)
+int mc13783_irq_unmask(struct mc13783 *mc13783, int irq)
{
int ret;
unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1;
@@ -267,7 +267,53 @@ int mc13783_unmask(struct mc13783 *mc13783, int irq)
return mc13783_reg_write(mc13783, offmask, mask & ~irqbit);
}
-EXPORT_SYMBOL(mc13783_unmask);
+EXPORT_SYMBOL(mc13783_irq_unmask);
+
+int mc13783_irq_status(struct mc13783 *mc13783, int irq,
+ int *enabled, int *pending)
+{
+ int ret;
+ unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1;
+ unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1;
+ u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
+
+ if (irq < 0 || irq >= MC13783_NUM_IRQ)
+ return -EINVAL;
+
+ if (enabled) {
+ u32 mask;
+
+ ret = mc13783_reg_read(mc13783, offmask, &mask);
+ if (ret)
+ return ret;
+
+ *enabled = mask & irqbit;
+ }
+
+ if (pending) {
+ u32 stat;
+
+ ret = mc13783_reg_read(mc13783, offstat, &stat);
+ if (ret)
+ return ret;
+
+ *pending = stat & irqbit;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(mc13783_irq_status);
+
+int mc13783_irq_ack(struct mc13783 *mc13783, int irq)
+{
+ unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1;
+ unsigned int val = 1 << (irq < 24 ? irq : irq - 24);
+
+ BUG_ON(irq < 0 || irq >= MC13783_NUM_IRQ);
+
+ return mc13783_reg_write(mc13783, offstat, val);
+}
+EXPORT_SYMBOL(mc13783_irq_ack);
int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq,
irq_handler_t handler, const char *name, void *dev)
@@ -297,7 +343,7 @@ int mc13783_irq_request(struct mc13783 *mc13783, int irq,
if (ret)
return ret;
- ret = mc13783_unmask(mc13783, irq);
+ ret = mc13783_irq_unmask(mc13783, irq);
if (ret) {
mc13783->irqhandler[irq] = NULL;
mc13783->irqdata[irq] = NULL;
@@ -317,7 +363,7 @@ int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev)
mc13783->irqdata[irq] != dev)
return -EINVAL;
- ret = mc13783_mask(mc13783, irq);
+ ret = mc13783_irq_mask(mc13783, irq);
if (ret)
return ret;
@@ -333,17 +379,6 @@ static inline irqreturn_t mc13783_irqhandler(struct mc13783 *mc13783, int irq)
return mc13783->irqhandler[irq](irq, mc13783->irqdata[irq]);
}
-int mc13783_ackirq(struct mc13783 *mc13783, int irq)
-{
- unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1;
- unsigned int val = 1 << (irq < 24 ? irq : irq - 24);
-
- BUG_ON(irq < 0 || irq >= MC13783_NUM_IRQ);
-
- return mc13783_reg_write(mc13783, offstat, val);
-}
-EXPORT_SYMBOL(mc13783_ackirq);
-
/*
* returns: number of handled irqs or negative error
* locking: holds mc13783->lock
@@ -422,7 +457,7 @@ static irqreturn_t mc13783_handler_adcdone(int irq, void *data)
{
struct mc13783_adcdone_data *adcdone_data = data;
- mc13783_ackirq(adcdone_data->mc13783, irq);
+ mc13783_irq_ack(adcdone_data->mc13783, irq);
complete_all(&adcdone_data->done);
@@ -486,7 +521,7 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
dev_dbg(&mc13783->spidev->dev, "%s: request irq\n", __func__);
mc13783_irq_request(mc13783, MC13783_IRQ_ADCDONE,
mc13783_handler_adcdone, __func__, &adcdone_data);
- mc13783_ackirq(mc13783, MC13783_IRQ_ADCDONE);
+ mc13783_irq_ack(mc13783, MC13783_IRQ_ADCDONE);
mc13783_reg_write(mc13783, MC13783_REG_ADC_0, adc0);
mc13783_reg_write(mc13783, MC13783_REG_ADC_1, adc1);
@@ -619,6 +654,8 @@ err_revision:
}
/* This should go away (END) */
+ mc13783_unlock(mc13783);
+
if (pdata->flags & MC13783_USE_ADC)
mc13783_add_subdevice(mc13783, "mc13783-adc");
@@ -641,8 +678,6 @@ err_revision:
if (pdata->flags & MC13783_USE_TOUCHSCREEN)
mc13783_add_subdevice(mc13783, "mc13783-ts");
- mc13783_unlock(mc13783);
-
return 0;
}
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index ae15e495e20e..aa17f4bddc56 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/acpi.h>
#include <linux/mfd/core.h>
static int mfd_add_device(struct device *parent, int id,
@@ -62,6 +63,10 @@ static int mfd_add_device(struct device *parent, int id,
res[r].start = cell->resources[r].start;
res[r].end = cell->resources[r].end;
}
+
+ ret = acpi_check_resource_conflict(res);
+ if (ret)
+ goto fail_res;
}
platform_device_add_resources(pdev, res, cell->num_resources);
diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c
index 03efae8041ab..468fd366d4da 100644
--- a/drivers/mfd/sh_mobile_sdhi.c
+++ b/drivers/mfd/sh_mobile_sdhi.c
@@ -21,7 +21,7 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
-
+#include <linux/mmc/host.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tmio.h>
#include <linux/mfd/sh_mobile_sdhi.h>
@@ -95,9 +95,9 @@ static int __init sh_mobile_sdhi_probe(struct platform_device *pdev)
clk_enable(priv->clk);
- /* FIXME: silly const unsigned int hclk */
- *(unsigned int *)&priv->mmc_data.hclk = clk_get_rate(priv->clk);
+ priv->mmc_data.hclk = clk_get_rate(priv->clk);
priv->mmc_data.set_pwr = sh_mobile_sdhi_set_pwr;
+ priv->mmc_data.capabilities = MMC_CAP_MMC_HIGHSPEED;
memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc));
priv->cell_mmc.driver_data = &priv->mmc_data;
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 0cc5eeff5ee8..7b6652f60117 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -523,7 +523,7 @@ unsigned long sm501_set_clock(struct device *dev,
unsigned long clock = readl(sm->regs + SM501_CURRENT_CLOCK);
unsigned char reg;
unsigned int pll_reg = 0;
- unsigned long sm501_freq; /* the actual frequency acheived */
+ unsigned long sm501_freq; /* the actual frequency achieved */
struct sm501_clock to;
@@ -533,7 +533,7 @@ unsigned long sm501_set_clock(struct device *dev,
switch (clksrc) {
case SM501_CLOCK_P2XCLK:
- /* This clock is divided in half so to achive the
+ /* This clock is divided in half so to achieve the
* requested frequency the value must be multiplied by
* 2. This clock also has an additional pre divisor */
@@ -562,7 +562,7 @@ unsigned long sm501_set_clock(struct device *dev,
break;
case SM501_CLOCK_V2XCLK:
- /* This clock is divided in half so to achive the
+ /* This clock is divided in half so to achieve the
* requested frequency the value must be multiplied by 2. */
sm501_freq = (sm501_select_clock(2 * req_freq, &to, 3) / 2);
@@ -648,7 +648,7 @@ unsigned long sm501_find_clock(struct device *dev,
unsigned long req_freq)
{
struct sm501_devdata *sm = dev_get_drvdata(dev);
- unsigned long sm501_freq; /* the frequency achiveable by the 501 */
+ unsigned long sm501_freq; /* the frequency achieveable by the 501 */
struct sm501_clock to;
switch (clksrc) {
@@ -1440,8 +1440,7 @@ static int __devinit sm501_plat_probe(struct platform_device *dev)
platform_set_drvdata(dev, sm);
- sm->regs = ioremap(sm->io_res->start,
- (sm->io_res->end - sm->io_res->start) - 1);
+ sm->regs = ioremap(sm->io_res->start, resource_size(sm->io_res));
if (sm->regs == NULL) {
dev_err(&dev->dev, "cannot remap registers\n");
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 0a255c1f1ce7..26d9176fca91 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -38,6 +38,19 @@ enum {
T7L66XB_CELL_MMC,
};
+static const struct resource t7l66xb_mmc_resources[] = {
+ {
+ .start = 0x800,
+ .end = 0x9ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_T7L66XB_MMC,
+ .end = IRQ_T7L66XB_MMC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
#define SCR_REVID 0x08 /* b Revision ID */
#define SCR_IMR 0x42 /* b Interrupt Mask */
#define SCR_DEV_CTL 0xe0 /* b Device control */
@@ -83,6 +96,9 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc)
spin_unlock_irqrestore(&t7l66xb->lock, flags);
+ tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
+ t7l66xb_mmc_resources[0].start & 0xfffe);
+
return 0;
}
@@ -106,28 +122,28 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
return 0;
}
+static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state);
+}
+
+static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state);
+}
+
/*--------------------------------------------------------------------------*/
static struct tmio_mmc_data t7166xb_mmc_data = {
.hclk = 24000000,
-};
-
-static const struct resource t7l66xb_mmc_resources[] = {
- {
- .start = 0x800,
- .end = 0x9ff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = 0x200,
- .end = 0x2ff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = IRQ_T7L66XB_MMC,
- .end = IRQ_T7L66XB_MMC,
- .flags = IORESOURCE_IRQ,
- },
+ .set_pwr = t7l66xb_mmc_pwr,
+ .set_clk_div = t7l66xb_mmc_clk_div,
};
static const struct resource t7l66xb_nand_resources[] = {
@@ -282,6 +298,9 @@ static int t7l66xb_resume(struct platform_device *dev)
if (pdata && pdata->resume)
pdata->resume(dev);
+ tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
+ t7l66xb_mmc_resources[0].start & 0xfffe);
+
return 0;
}
#else
@@ -341,7 +360,7 @@ static int t7l66xb_probe(struct platform_device *dev)
if (ret)
goto err_request_scr;
- t7l66xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1);
+ t7l66xb->scr = ioremap(rscr->start, resource_size(rscr));
if (!t7l66xb->scr) {
ret = -ENOMEM;
goto err_ioremap;
@@ -384,12 +403,12 @@ static int t7l66xb_probe(struct platform_device *dev)
err_ioremap:
release_resource(&t7l66xb->rscr);
err_request_scr:
- kfree(t7l66xb);
clk_put(t7l66xb->clk48m);
err_clk48m_get:
clk_put(t7l66xb->clk32k);
err_clk32k_get:
err_noirq:
+ kfree(t7l66xb);
return ret;
}
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c
index 3280ab33f88a..5c7f04343d5c 100644
--- a/drivers/mfd/tc6387xb.c
+++ b/drivers/mfd/tc6387xb.c
@@ -22,28 +22,52 @@ enum {
TC6387XB_CELL_MMC,
};
+struct tc6387xb {
+ void __iomem *scr;
+ struct clk *clk32k;
+ struct resource rscr;
+};
+
+static struct resource tc6387xb_mmc_resources[] = {
+ {
+ .start = 0x800,
+ .end = 0x9ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/*--------------------------------------------------------------------------*/
+
#ifdef CONFIG_PM
static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
{
- struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
if (pdata && pdata->suspend)
pdata->suspend(dev);
- clk_disable(clk32k);
+ clk_disable(tc6387xb->clk32k);
return 0;
}
static int tc6387xb_resume(struct platform_device *dev)
{
- struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
- clk_enable(clk32k);
+ clk_enable(tc6387xb->clk32k);
if (pdata && pdata->resume)
pdata->resume(dev);
+ tmio_core_mmc_resume(tc6387xb->scr + 0x200, 0,
+ tc6387xb_mmc_resources[0].start & 0xfffe);
+
return 0;
}
#else
@@ -53,12 +77,32 @@ static int tc6387xb_resume(struct platform_device *dev)
/*--------------------------------------------------------------------------*/
+static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_pwr(tc6387xb->scr + 0x200, 0, state);
+}
+
+static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, 0, state);
+}
+
+
static int tc6387xb_mmc_enable(struct platform_device *mmc)
{
struct platform_device *dev = to_platform_device(mmc->dev.parent);
- struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
- clk_enable(clk32k);
+ clk_enable(tc6387xb->clk32k);
+
+ tmio_core_mmc_enable(tc6387xb->scr + 0x200, 0,
+ tc6387xb_mmc_resources[0].start & 0xfffe);
return 0;
}
@@ -66,36 +110,20 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc)
static int tc6387xb_mmc_disable(struct platform_device *mmc)
{
struct platform_device *dev = to_platform_device(mmc->dev.parent);
- struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
- clk_disable(clk32k);
+ clk_disable(tc6387xb->clk32k);
return 0;
}
-/*--------------------------------------------------------------------------*/
-
static struct tmio_mmc_data tc6387xb_mmc_data = {
.hclk = 24000000,
+ .set_pwr = tc6387xb_mmc_pwr,
+ .set_clk_div = tc6387xb_mmc_clk_div,
};
-static struct resource tc6387xb_mmc_resources[] = {
- {
- .start = 0x800,
- .end = 0x9ff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = 0x200,
- .end = 0x2ff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = 0,
- .end = 0,
- .flags = IORESOURCE_IRQ,
- },
-};
+/*--------------------------------------------------------------------------*/
static struct mfd_cell tc6387xb_cells[] = {
[TC6387XB_CELL_MMC] = {
@@ -111,8 +139,9 @@ static struct mfd_cell tc6387xb_cells[] = {
static int tc6387xb_probe(struct platform_device *dev)
{
struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
- struct resource *iomem;
+ struct resource *iomem, *rscr;
struct clk *clk32k;
+ struct tc6387xb *tc6387xb;
int irq, ret;
iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
@@ -120,18 +149,40 @@ static int tc6387xb_probe(struct platform_device *dev)
return -EINVAL;
}
+ tc6387xb = kzalloc(sizeof *tc6387xb, GFP_KERNEL);
+ if (!tc6387xb)
+ return -ENOMEM;
+
ret = platform_get_irq(dev, 0);
if (ret >= 0)
irq = ret;
else
- goto err_resource;
+ goto err_no_irq;
clk32k = clk_get(&dev->dev, "CLK_CK32K");
if (IS_ERR(clk32k)) {
ret = PTR_ERR(clk32k);
+ goto err_no_clk;
+ }
+
+ rscr = &tc6387xb->rscr;
+ rscr->name = "tc6387xb-core";
+ rscr->start = iomem->start;
+ rscr->end = iomem->start + 0xff;
+ rscr->flags = IORESOURCE_MEM;
+
+ ret = request_resource(iomem, rscr);
+ if (ret)
goto err_resource;
+
+ tc6387xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1);
+ if (!tc6387xb->scr) {
+ ret = -ENOMEM;
+ goto err_ioremap;
}
- platform_set_drvdata(dev, clk32k);
+
+ tc6387xb->clk32k = clk32k;
+ platform_set_drvdata(dev, tc6387xb);
if (pdata && pdata->enable)
pdata->enable(dev);
@@ -149,8 +200,13 @@ static int tc6387xb_probe(struct platform_device *dev)
if (!ret)
return 0;
- clk_put(clk32k);
+err_ioremap:
+ release_resource(&tc6387xb->rscr);
err_resource:
+ clk_put(clk32k);
+err_no_clk:
+err_no_irq:
+ kfree(tc6387xb);
return ret;
}
@@ -195,3 +251,4 @@ MODULE_DESCRIPTION("Toshiba TC6387XB core driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Ian Molton");
MODULE_ALIAS("platform:tc6387xb");
+
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index 1429a7341a9a..c59e5c5737d0 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -136,10 +136,6 @@ static int tc6393xb_nand_enable(struct platform_device *nand)
return 0;
}
-static struct tmio_mmc_data tc6393xb_mmc_data = {
- .hclk = 24000000,
-};
-
static struct resource __devinitdata tc6393xb_nand_resources[] = {
{
.start = 0x1000,
@@ -165,11 +161,6 @@ static struct resource __devinitdata tc6393xb_mmc_resources[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = 0x200,
- .end = 0x2ff,
- .flags = IORESOURCE_MEM,
- },
- {
.start = IRQ_TC6393_MMC,
.end = IRQ_TC6393_MMC,
.flags = IORESOURCE_IRQ,
@@ -346,6 +337,50 @@ int tc6393xb_lcd_mode(struct platform_device *fb,
}
EXPORT_SYMBOL(tc6393xb_lcd_mode);
+static int tc6393xb_mmc_enable(struct platform_device *mmc)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_enable(tc6393xb->scr + 0x200, 0,
+ tc6393xb_mmc_resources[0].start & 0xfffe);
+
+ return 0;
+}
+
+static int tc6393xb_mmc_resume(struct platform_device *mmc)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_resume(tc6393xb->scr + 0x200, 0,
+ tc6393xb_mmc_resources[0].start & 0xfffe);
+
+ return 0;
+}
+
+static void tc6393xb_mmc_pwr(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_pwr(tc6393xb->scr + 0x200, 0, state);
+}
+
+static void tc6393xb_mmc_clk_div(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_clk_div(tc6393xb->scr + 0x200, 0, state);
+}
+
+static struct tmio_mmc_data tc6393xb_mmc_data = {
+ .hclk = 24000000,
+ .set_pwr = tc6393xb_mmc_pwr,
+ .set_clk_div = tc6393xb_mmc_clk_div,
+};
+
static struct mfd_cell __devinitdata tc6393xb_cells[] = {
[TC6393XB_CELL_NAND] = {
.name = "tmio-nand",
@@ -355,6 +390,8 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = {
},
[TC6393XB_CELL_MMC] = {
.name = "tmio-mmc",
+ .enable = tc6393xb_mmc_enable,
+ .resume = tc6393xb_mmc_resume,
.driver_data = &tc6393xb_mmc_data,
.num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
.resources = tc6393xb_mmc_resources,
@@ -610,7 +647,7 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
if (ret)
goto err_request_scr;
- tc6393xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1);
+ tc6393xb->scr = ioremap(rscr->start, resource_size(rscr));
if (!tc6393xb->scr) {
ret = -ENOMEM;
goto err_ioremap;
@@ -836,3 +873,4 @@ MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer");
MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller");
MODULE_ALIAS("platform:tc6393xb");
+
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c
new file mode 100644
index 000000000000..1ed44d283803
--- /dev/null
+++ b/drivers/mfd/timberdale.c
@@ -0,0 +1,727 @@
+/*
+ * timberdale.c timberdale FPGA MFD driver
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/* Supports:
+ * Timberdale FPGA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/mfd/core.h>
+
+#include <linux/timb_gpio.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-ocores.h>
+#include <linux/i2c/tsc2007.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/xilinx_spi.h>
+#include <linux/spi/max7301.h>
+#include <linux/spi/mc33880.h>
+
+#include <media/timb_radio.h>
+
+#include "timberdale.h"
+
+#define DRIVER_NAME "timberdale"
+
+struct timberdale_device {
+ resource_size_t ctl_mapbase;
+ unsigned char __iomem *ctl_membase;
+ struct {
+ u32 major;
+ u32 minor;
+ u32 config;
+ } fw;
+};
+
+/*--------------------------------------------------------------------------*/
+
+static struct tsc2007_platform_data timberdale_tsc2007_platform_data = {
+ .model = 2003,
+ .x_plate_ohms = 100
+};
+
+static struct i2c_board_info timberdale_i2c_board_info[] = {
+ {
+ I2C_BOARD_INFO("tsc2007", 0x48),
+ .platform_data = &timberdale_tsc2007_platform_data,
+ .irq = IRQ_TIMBERDALE_TSC_INT
+ },
+};
+
+static __devinitdata struct ocores_i2c_platform_data
+timberdale_ocores_platform_data = {
+ .regstep = 4,
+ .clock_khz = 62500,
+ .devices = timberdale_i2c_board_info,
+ .num_devices = ARRAY_SIZE(timberdale_i2c_board_info)
+};
+
+const static __devinitconst struct resource timberdale_ocores_resources[] = {
+ {
+ .start = OCORESOFFSET,
+ .end = OCORESEND,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TIMBERDALE_I2C,
+ .end = IRQ_TIMBERDALE_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+const struct max7301_platform_data timberdale_max7301_platform_data = {
+ .base = 200
+};
+
+const struct mc33880_platform_data timberdale_mc33880_platform_data = {
+ .base = 100
+};
+
+static struct spi_board_info timberdale_spi_16bit_board_info[] = {
+ {
+ .modalias = "max7301",
+ .max_speed_hz = 26000,
+ .chip_select = 2,
+ .mode = SPI_MODE_0,
+ .platform_data = &timberdale_max7301_platform_data
+ },
+};
+
+static struct spi_board_info timberdale_spi_8bit_board_info[] = {
+ {
+ .modalias = "mc33880",
+ .max_speed_hz = 4000,
+ .chip_select = 1,
+ .mode = SPI_MODE_1,
+ .platform_data = &timberdale_mc33880_platform_data
+ },
+};
+
+static __devinitdata struct xspi_platform_data timberdale_xspi_platform_data = {
+ .num_chipselect = 3,
+ .little_endian = true,
+ /* bits per word and devices will be filled in runtime depending
+ * on the HW config
+ */
+};
+
+const static __devinitconst struct resource timberdale_spi_resources[] = {
+ {
+ .start = SPIOFFSET,
+ .end = SPIEND,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TIMBERDALE_SPI,
+ .end = IRQ_TIMBERDALE_SPI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+const static __devinitconst struct resource timberdale_eth_resources[] = {
+ {
+ .start = ETHOFFSET,
+ .end = ETHEND,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TIMBERDALE_ETHSW_IF,
+ .end = IRQ_TIMBERDALE_ETHSW_IF,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static __devinitdata struct timbgpio_platform_data
+ timberdale_gpio_platform_data = {
+ .gpio_base = 0,
+ .nr_pins = GPIO_NR_PINS,
+ .irq_base = 200,
+};
+
+const static __devinitconst struct resource timberdale_gpio_resources[] = {
+ {
+ .start = GPIOOFFSET,
+ .end = GPIOEND,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TIMBERDALE_GPIO,
+ .end = IRQ_TIMBERDALE_GPIO,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+const static __devinitconst struct resource timberdale_mlogicore_resources[] = {
+ {
+ .start = MLCOREOFFSET,
+ .end = MLCOREEND,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TIMBERDALE_MLCORE,
+ .end = IRQ_TIMBERDALE_MLCORE,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = IRQ_TIMBERDALE_MLCORE_BUF,
+ .end = IRQ_TIMBERDALE_MLCORE_BUF,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+const static __devinitconst struct resource timberdale_uart_resources[] = {
+ {
+ .start = UARTOFFSET,
+ .end = UARTEND,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TIMBERDALE_UART,
+ .end = IRQ_TIMBERDALE_UART,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+const static __devinitconst struct resource timberdale_uartlite_resources[] = {
+ {
+ .start = UARTLITEOFFSET,
+ .end = UARTLITEEND,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TIMBERDALE_UARTLITE,
+ .end = IRQ_TIMBERDALE_UARTLITE,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+const static __devinitconst struct resource timberdale_radio_resources[] = {
+ {
+ .start = RDSOFFSET,
+ .end = RDSEND,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TIMBERDALE_RDS,
+ .end = IRQ_TIMBERDALE_RDS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static __devinitdata struct i2c_board_info timberdale_tef6868_i2c_board_info = {
+ I2C_BOARD_INFO("tef6862", 0x60)
+};
+
+static __devinitdata struct i2c_board_info timberdale_saa7706_i2c_board_info = {
+ I2C_BOARD_INFO("saa7706h", 0x1C)
+};
+
+static __devinitdata struct timb_radio_platform_data
+ timberdale_radio_platform_data = {
+ .i2c_adapter = 0,
+ .tuner = {
+ .module_name = "tef6862",
+ .info = &timberdale_tef6868_i2c_board_info
+ },
+ .dsp = {
+ .module_name = "saa7706h",
+ .info = &timberdale_saa7706_i2c_board_info
+ }
+};
+
+const static __devinitconst struct resource timberdale_dma_resources[] = {
+ {
+ .start = DMAOFFSET,
+ .end = DMAEND,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TIMBERDALE_DMA,
+ .end = IRQ_TIMBERDALE_DMA,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
+ {
+ .name = "timb-uart",
+ .num_resources = ARRAY_SIZE(timberdale_uart_resources),
+ .resources = timberdale_uart_resources,
+ },
+ {
+ .name = "timb-gpio",
+ .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
+ .resources = timberdale_gpio_resources,
+ .platform_data = &timberdale_gpio_platform_data,
+ .data_size = sizeof(timberdale_gpio_platform_data),
+ },
+ {
+ .name = "timb-radio",
+ .num_resources = ARRAY_SIZE(timberdale_radio_resources),
+ .resources = timberdale_radio_resources,
+ .platform_data = &timberdale_radio_platform_data,
+ .data_size = sizeof(timberdale_radio_platform_data),
+ },
+ {
+ .name = "xilinx_spi",
+ .num_resources = ARRAY_SIZE(timberdale_spi_resources),
+ .resources = timberdale_spi_resources,
+ .platform_data = &timberdale_xspi_platform_data,
+ .data_size = sizeof(timberdale_xspi_platform_data),
+ },
+ {
+ .name = "ks8842",
+ .num_resources = ARRAY_SIZE(timberdale_eth_resources),
+ .resources = timberdale_eth_resources,
+ },
+ {
+ .name = "timb-dma",
+ .num_resources = ARRAY_SIZE(timberdale_dma_resources),
+ .resources = timberdale_dma_resources,
+ },
+};
+
+static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
+ {
+ .name = "timb-uart",
+ .num_resources = ARRAY_SIZE(timberdale_uart_resources),
+ .resources = timberdale_uart_resources,
+ },
+ {
+ .name = "uartlite",
+ .num_resources = ARRAY_SIZE(timberdale_uartlite_resources),
+ .resources = timberdale_uartlite_resources,
+ },
+ {
+ .name = "timb-gpio",
+ .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
+ .resources = timberdale_gpio_resources,
+ .platform_data = &timberdale_gpio_platform_data,
+ .data_size = sizeof(timberdale_gpio_platform_data),
+ },
+ {
+ .name = "timb-mlogicore",
+ .num_resources = ARRAY_SIZE(timberdale_mlogicore_resources),
+ .resources = timberdale_mlogicore_resources,
+ },
+ {
+ .name = "timb-radio",
+ .num_resources = ARRAY_SIZE(timberdale_radio_resources),
+ .resources = timberdale_radio_resources,
+ .platform_data = &timberdale_radio_platform_data,
+ .data_size = sizeof(timberdale_radio_platform_data),
+ },
+ {
+ .name = "xilinx_spi",
+ .num_resources = ARRAY_SIZE(timberdale_spi_resources),
+ .resources = timberdale_spi_resources,
+ .platform_data = &timberdale_xspi_platform_data,
+ .data_size = sizeof(timberdale_xspi_platform_data),
+ },
+ {
+ .name = "ks8842",
+ .num_resources = ARRAY_SIZE(timberdale_eth_resources),
+ .resources = timberdale_eth_resources,
+ },
+ {
+ .name = "timb-dma",
+ .num_resources = ARRAY_SIZE(timberdale_dma_resources),
+ .resources = timberdale_dma_resources,
+ },
+};
+
+static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
+ {
+ .name = "timb-uart",
+ .num_resources = ARRAY_SIZE(timberdale_uart_resources),
+ .resources = timberdale_uart_resources,
+ },
+ {
+ .name = "timb-gpio",
+ .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
+ .resources = timberdale_gpio_resources,
+ .platform_data = &timberdale_gpio_platform_data,
+ .data_size = sizeof(timberdale_gpio_platform_data),
+ },
+ {
+ .name = "timb-radio",
+ .num_resources = ARRAY_SIZE(timberdale_radio_resources),
+ .resources = timberdale_radio_resources,
+ .platform_data = &timberdale_radio_platform_data,
+ .data_size = sizeof(timberdale_radio_platform_data),
+ },
+ {
+ .name = "xilinx_spi",
+ .num_resources = ARRAY_SIZE(timberdale_spi_resources),
+ .resources = timberdale_spi_resources,
+ .platform_data = &timberdale_xspi_platform_data,
+ .data_size = sizeof(timberdale_xspi_platform_data),
+ },
+ {
+ .name = "timb-dma",
+ .num_resources = ARRAY_SIZE(timberdale_dma_resources),
+ .resources = timberdale_dma_resources,
+ },
+};
+
+static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
+ {
+ .name = "timb-uart",
+ .num_resources = ARRAY_SIZE(timberdale_uart_resources),
+ .resources = timberdale_uart_resources,
+ },
+ {
+ .name = "ocores-i2c",
+ .num_resources = ARRAY_SIZE(timberdale_ocores_resources),
+ .resources = timberdale_ocores_resources,
+ .platform_data = &timberdale_ocores_platform_data,
+ .data_size = sizeof(timberdale_ocores_platform_data),
+ },
+ {
+ .name = "timb-gpio",
+ .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
+ .resources = timberdale_gpio_resources,
+ .platform_data = &timberdale_gpio_platform_data,
+ .data_size = sizeof(timberdale_gpio_platform_data),
+ },
+ {
+ .name = "timb-radio",
+ .num_resources = ARRAY_SIZE(timberdale_radio_resources),
+ .resources = timberdale_radio_resources,
+ .platform_data = &timberdale_radio_platform_data,
+ .data_size = sizeof(timberdale_radio_platform_data),
+ },
+ {
+ .name = "xilinx_spi",
+ .num_resources = ARRAY_SIZE(timberdale_spi_resources),
+ .resources = timberdale_spi_resources,
+ .platform_data = &timberdale_xspi_platform_data,
+ .data_size = sizeof(timberdale_xspi_platform_data),
+ },
+ {
+ .name = "ks8842",
+ .num_resources = ARRAY_SIZE(timberdale_eth_resources),
+ .resources = timberdale_eth_resources,
+ },
+ {
+ .name = "timb-dma",
+ .num_resources = ARRAY_SIZE(timberdale_dma_resources),
+ .resources = timberdale_dma_resources,
+ },
+};
+
+static const __devinitconst struct resource timberdale_sdhc_resources[] = {
+ /* located in bar 1 and bar 2 */
+ {
+ .start = SDHC0OFFSET,
+ .end = SDHC0END,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TIMBERDALE_SDHC,
+ .end = IRQ_TIMBERDALE_SDHC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static __devinitdata struct mfd_cell timberdale_cells_bar1[] = {
+ {
+ .name = "sdhci",
+ .num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
+ .resources = timberdale_sdhc_resources,
+ },
+};
+
+static __devinitdata struct mfd_cell timberdale_cells_bar2[] = {
+ {
+ .name = "sdhci",
+ .num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
+ .resources = timberdale_sdhc_resources,
+ },
+};
+
+static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct timberdale_device *priv = pci_get_drvdata(pdev);
+
+ return sprintf(buf, "%d.%d.%d\n", priv->fw.major, priv->fw.minor,
+ priv->fw.config);
+}
+
+static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
+
+/*--------------------------------------------------------------------------*/
+
+static int __devinit timb_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct timberdale_device *priv;
+ int err, i;
+ resource_size_t mapbase;
+ struct msix_entry *msix_entries = NULL;
+ u8 ip_setup;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ pci_set_drvdata(dev, priv);
+
+ err = pci_enable_device(dev);
+ if (err)
+ goto err_enable;
+
+ mapbase = pci_resource_start(dev, 0);
+ if (!mapbase) {
+ dev_err(&dev->dev, "No resource\n");
+ goto err_start;
+ }
+
+ /* create a resource for the PCI master register */
+ priv->ctl_mapbase = mapbase + CHIPCTLOFFSET;
+ if (!request_mem_region(priv->ctl_mapbase, CHIPCTLSIZE, "timb-ctl")) {
+ dev_err(&dev->dev, "Failed to request ctl mem\n");
+ goto err_request;
+ }
+
+ priv->ctl_membase = ioremap(priv->ctl_mapbase, CHIPCTLSIZE);
+ if (!priv->ctl_membase) {
+ dev_err(&dev->dev, "ioremap failed for ctl mem\n");
+ goto err_ioremap;
+ }
+
+ /* read the HW config */
+ priv->fw.major = ioread32(priv->ctl_membase + TIMB_REV_MAJOR);
+ priv->fw.minor = ioread32(priv->ctl_membase + TIMB_REV_MINOR);
+ priv->fw.config = ioread32(priv->ctl_membase + TIMB_HW_CONFIG);
+
+ if (priv->fw.major > TIMB_SUPPORTED_MAJOR) {
+ dev_err(&dev->dev, "The driver supports an older "
+ "version of the FPGA, please update the driver to "
+ "support %d.%d\n", priv->fw.major, priv->fw.minor);
+ goto err_ioremap;
+ }
+ if (priv->fw.major < TIMB_SUPPORTED_MAJOR ||
+ priv->fw.minor < TIMB_REQUIRED_MINOR) {
+ dev_err(&dev->dev, "The FPGA image is too old (%d.%d), "
+ "please upgrade the FPGA to at least: %d.%d\n",
+ priv->fw.major, priv->fw.minor,
+ TIMB_SUPPORTED_MAJOR, TIMB_REQUIRED_MINOR);
+ goto err_ioremap;
+ }
+
+ msix_entries = kzalloc(TIMBERDALE_NR_IRQS * sizeof(*msix_entries),
+ GFP_KERNEL);
+ if (!msix_entries)
+ goto err_ioremap;
+
+ for (i = 0; i < TIMBERDALE_NR_IRQS; i++)
+ msix_entries[i].entry = i;
+
+ err = pci_enable_msix(dev, msix_entries, TIMBERDALE_NR_IRQS);
+ if (err) {
+ dev_err(&dev->dev,
+ "MSI-X init failed: %d, expected entries: %d\n",
+ err, TIMBERDALE_NR_IRQS);
+ goto err_msix;
+ }
+
+ err = device_create_file(&dev->dev, &dev_attr_fw_ver);
+ if (err)
+ goto err_create_file;
+
+ /* Reset all FPGA PLB peripherals */
+ iowrite32(0x1, priv->ctl_membase + TIMB_SW_RST);
+
+ /* update IRQ offsets in I2C board info */
+ for (i = 0; i < ARRAY_SIZE(timberdale_i2c_board_info); i++)
+ timberdale_i2c_board_info[i].irq =
+ msix_entries[timberdale_i2c_board_info[i].irq].vector;
+
+ /* Update the SPI configuration depending on the HW (8 or 16 bit) */
+ if (priv->fw.config & TIMB_HW_CONFIG_SPI_8BIT) {
+ timberdale_xspi_platform_data.bits_per_word = 8;
+ timberdale_xspi_platform_data.devices =
+ timberdale_spi_8bit_board_info;
+ timberdale_xspi_platform_data.num_devices =
+ ARRAY_SIZE(timberdale_spi_8bit_board_info);
+ } else {
+ timberdale_xspi_platform_data.bits_per_word = 16;
+ timberdale_xspi_platform_data.devices =
+ timberdale_spi_16bit_board_info;
+ timberdale_xspi_platform_data.num_devices =
+ ARRAY_SIZE(timberdale_spi_16bit_board_info);
+ }
+
+ ip_setup = priv->fw.config & TIMB_HW_VER_MASK;
+ switch (ip_setup) {
+ case TIMB_HW_VER0:
+ err = mfd_add_devices(&dev->dev, -1,
+ timberdale_cells_bar0_cfg0,
+ ARRAY_SIZE(timberdale_cells_bar0_cfg0),
+ &dev->resource[0], msix_entries[0].vector);
+ break;
+ case TIMB_HW_VER1:
+ err = mfd_add_devices(&dev->dev, -1,
+ timberdale_cells_bar0_cfg1,
+ ARRAY_SIZE(timberdale_cells_bar0_cfg1),
+ &dev->resource[0], msix_entries[0].vector);
+ break;
+ case TIMB_HW_VER2:
+ err = mfd_add_devices(&dev->dev, -1,
+ timberdale_cells_bar0_cfg2,
+ ARRAY_SIZE(timberdale_cells_bar0_cfg2),
+ &dev->resource[0], msix_entries[0].vector);
+ break;
+ case TIMB_HW_VER3:
+ err = mfd_add_devices(&dev->dev, -1,
+ timberdale_cells_bar0_cfg3,
+ ARRAY_SIZE(timberdale_cells_bar0_cfg3),
+ &dev->resource[0], msix_entries[0].vector);
+ break;
+ default:
+ dev_err(&dev->dev, "Uknown IP setup: %d.%d.%d\n",
+ priv->fw.major, priv->fw.minor, ip_setup);
+ err = -ENODEV;
+ goto err_mfd;
+ break;
+ }
+
+ if (err) {
+ dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
+ goto err_mfd;
+ }
+
+ err = mfd_add_devices(&dev->dev, 0,
+ timberdale_cells_bar1, ARRAY_SIZE(timberdale_cells_bar1),
+ &dev->resource[1], msix_entries[0].vector);
+ if (err) {
+ dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
+ goto err_mfd2;
+ }
+
+ /* only version 0 and 3 have the iNand routed to SDHCI */
+ if (((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER0) ||
+ ((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER3)) {
+ err = mfd_add_devices(&dev->dev, 1, timberdale_cells_bar2,
+ ARRAY_SIZE(timberdale_cells_bar2),
+ &dev->resource[2], msix_entries[0].vector);
+ if (err) {
+ dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
+ goto err_mfd2;
+ }
+ }
+
+ kfree(msix_entries);
+
+ dev_info(&dev->dev,
+ "Found Timberdale Card. Rev: %d.%d, HW config: 0x%02x\n",
+ priv->fw.major, priv->fw.minor, priv->fw.config);
+
+ return 0;
+
+err_mfd2:
+ mfd_remove_devices(&dev->dev);
+err_mfd:
+ device_remove_file(&dev->dev, &dev_attr_fw_ver);
+err_create_file:
+ pci_disable_msix(dev);
+err_msix:
+ iounmap(priv->ctl_membase);
+err_ioremap:
+ release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
+err_request:
+ pci_set_drvdata(dev, NULL);
+err_start:
+ pci_disable_device(dev);
+err_enable:
+ kfree(msix_entries);
+ kfree(priv);
+ pci_set_drvdata(dev, NULL);
+ return -ENODEV;
+}
+
+static void __devexit timb_remove(struct pci_dev *dev)
+{
+ struct timberdale_device *priv = pci_get_drvdata(dev);
+
+ mfd_remove_devices(&dev->dev);
+
+ device_remove_file(&dev->dev, &dev_attr_fw_ver);
+
+ iounmap(priv->ctl_membase);
+ release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
+
+ pci_disable_msix(dev);
+ pci_disable_device(dev);
+ pci_set_drvdata(dev, NULL);
+ kfree(priv);
+}
+
+static struct pci_device_id timberdale_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, timberdale_pci_tbl);
+
+static struct pci_driver timberdale_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = timberdale_pci_tbl,
+ .probe = timb_probe,
+ .remove = __devexit_p(timb_remove),
+};
+
+static int __init timberdale_init(void)
+{
+ int err;
+
+ err = pci_register_driver(&timberdale_pci_driver);
+ if (err < 0) {
+ printk(KERN_ERR
+ "Failed to register PCI driver for %s device.\n",
+ timberdale_pci_driver.name);
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "Driver for %s has been successfully registered.\n",
+ timberdale_pci_driver.name);
+
+ return 0;
+}
+
+static void __exit timberdale_exit(void)
+{
+ pci_unregister_driver(&timberdale_pci_driver);
+
+ printk(KERN_INFO "Driver for %s has been successfully unregistered.\n",
+ timberdale_pci_driver.name);
+}
+
+module_init(timberdale_init);
+module_exit(timberdale_exit);
+
+MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/timberdale.h b/drivers/mfd/timberdale.h
new file mode 100644
index 000000000000..8d27ffabc25d
--- /dev/null
+++ b/drivers/mfd/timberdale.h
@@ -0,0 +1,130 @@
+/*
+ * timberdale.h timberdale FPGA MFD driver defines
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/* Supports:
+ * Timberdale FPGA
+ */
+
+#ifndef MFD_TIMBERDALE_H
+#define MFD_TIMBERDALE_H
+
+#define DRV_VERSION "0.1"
+
+/* This driver only support versions >= 3.8 and < 4.0 */
+#define TIMB_SUPPORTED_MAJOR 3
+
+/* This driver only support minor >= 8 */
+#define TIMB_REQUIRED_MINOR 8
+
+/* Registers of the control area */
+#define TIMB_REV_MAJOR 0x00
+#define TIMB_REV_MINOR 0x04
+#define TIMB_HW_CONFIG 0x08
+#define TIMB_SW_RST 0x40
+
+/* bits in the TIMB_HW_CONFIG register */
+#define TIMB_HW_CONFIG_SPI_8BIT 0x80
+
+#define TIMB_HW_VER_MASK 0x0f
+#define TIMB_HW_VER0 0x00
+#define TIMB_HW_VER1 0x01
+#define TIMB_HW_VER2 0x02
+#define TIMB_HW_VER3 0x03
+
+#define OCORESOFFSET 0x0
+#define OCORESEND 0x1f
+
+#define SPIOFFSET 0x80
+#define SPIEND 0xff
+
+#define UARTLITEOFFSET 0x100
+#define UARTLITEEND 0x10f
+
+#define RDSOFFSET 0x180
+#define RDSEND 0x183
+
+#define ETHOFFSET 0x300
+#define ETHEND 0x3ff
+
+#define GPIOOFFSET 0x400
+#define GPIOEND 0x7ff
+
+#define CHIPCTLOFFSET 0x800
+#define CHIPCTLEND 0x8ff
+#define CHIPCTLSIZE (CHIPCTLEND - CHIPCTLOFFSET)
+
+#define INTCOFFSET 0xc00
+#define INTCEND 0xfff
+#define INTCSIZE (INTCEND - INTCOFFSET)
+
+#define MOSTOFFSET 0x1000
+#define MOSTEND 0x13ff
+
+#define UARTOFFSET 0x1400
+#define UARTEND 0x17ff
+
+#define XIICOFFSET 0x1800
+#define XIICEND 0x19ff
+
+#define I2SOFFSET 0x1C00
+#define I2SEND 0x1fff
+
+#define LOGIWOFFSET 0x30000
+#define LOGIWEND 0x37fff
+
+#define MLCOREOFFSET 0x40000
+#define MLCOREEND 0x43fff
+
+#define DMAOFFSET 0x01000000
+#define DMAEND 0x013fffff
+
+/* SDHC0 is placed in PCI bar 1 */
+#define SDHC0OFFSET 0x00
+#define SDHC0END 0xff
+
+/* SDHC1 is placed in PCI bar 2 */
+#define SDHC1OFFSET 0x00
+#define SDHC1END 0xff
+
+#define PCI_VENDOR_ID_TIMB 0x10ee
+#define PCI_DEVICE_ID_TIMB 0xa123
+
+#define IRQ_TIMBERDALE_INIC 0
+#define IRQ_TIMBERDALE_MLB 1
+#define IRQ_TIMBERDALE_GPIO 2
+#define IRQ_TIMBERDALE_I2C 3
+#define IRQ_TIMBERDALE_UART 4
+#define IRQ_TIMBERDALE_DMA 5
+#define IRQ_TIMBERDALE_I2S 6
+#define IRQ_TIMBERDALE_TSC_INT 7
+#define IRQ_TIMBERDALE_SDHC 8
+#define IRQ_TIMBERDALE_ADV7180 9
+#define IRQ_TIMBERDALE_ETHSW_IF 10
+#define IRQ_TIMBERDALE_SPI 11
+#define IRQ_TIMBERDALE_UARTLITE 12
+#define IRQ_TIMBERDALE_MLCORE 13
+#define IRQ_TIMBERDALE_MLCORE_BUF 14
+#define IRQ_TIMBERDALE_RDS 15
+#define TIMBERDALE_NR_IRQS 16
+
+#define GPIO_PIN_ASCB 8
+#define GPIO_PIN_INIC_RST 14
+#define GPIO_PIN_BT_RST 15
+#define GPIO_NR_PINS 16
+
+#endif
diff --git a/drivers/mfd/tmio_core.c b/drivers/mfd/tmio_core.c
new file mode 100644
index 000000000000..eddc19ae464b
--- /dev/null
+++ b/drivers/mfd/tmio_core.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright(c) 2009 Ian Molton <spyro@f2s.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.
+ */
+
+#include <linux/mfd/tmio.h>
+
+int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base)
+{
+ /* Enable the MMC/SD Control registers */
+ sd_config_write16(cnf, shift, CNF_CMD, SDCREN);
+ sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe);
+
+ /* Disable SD power during suspend */
+ sd_config_write8(cnf, shift, CNF_PWR_CTL_3, 0x01);
+
+ /* The below is required but why? FIXME */
+ sd_config_write8(cnf, shift, CNF_STOP_CLK_CTL, 0x1f);
+
+ /* Power down SD bus */
+ sd_config_write8(cnf, shift, CNF_PWR_CTL_2, 0x00);
+
+ return 0;
+}
+EXPORT_SYMBOL(tmio_core_mmc_enable);
+
+int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base)
+{
+
+ /* Enable the MMC/SD Control registers */
+ sd_config_write16(cnf, shift, CNF_CMD, SDCREN);
+ sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe);
+
+ return 0;
+}
+EXPORT_SYMBOL(tmio_core_mmc_resume);
+
+void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state)
+{
+ sd_config_write8(cnf, shift, CNF_PWR_CTL_2, state ? 0x02 : 0x00);
+}
+EXPORT_SYMBOL(tmio_core_mmc_pwr);
+
+void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state)
+{
+ sd_config_write8(cnf, shift, CNF_SD_CLK_MODE, state ? 1 : 0);
+}
+EXPORT_SYMBOL(tmio_core_mmc_clk_div);
+
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 2a7606534196..562cd4935e17 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -58,13 +58,6 @@
#define DRIVER_NAME "twl"
-#if defined(CONFIG_TWL4030_BCI_BATTERY) || \
- defined(CONFIG_TWL4030_BCI_BATTERY_MODULE)
-#define twl_has_bci() true
-#else
-#define twl_has_bci() false
-#endif
-
#if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE)
#define twl_has_keypad() true
#else
@@ -115,7 +108,8 @@
#define twl_has_watchdog() false
#endif
-#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE)
+#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) ||\
+ defined(CONFIG_SND_SOC_TWL6030) || defined(CONFIG_SND_SOC_TWL6030_MODULE)
#define twl_has_codec() true
#else
#define twl_has_codec() false
@@ -129,7 +123,7 @@
#define TWL_NUM_SLAVES 4
#if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \
- || defined(CONFIG_INPUT_TWL4030_PWBUTTON_MODULE)
+ || defined(CONFIG_INPUT_TWL4030_PWRBUTTON_MODULE)
#define twl_has_pwrbutton() true
#else
#define twl_has_pwrbutton() false
@@ -204,6 +198,7 @@
/* subchip/slave 3 0x4B - AUDIO */
#define TWL6030_BASEADD_AUDIO 0x0000
#define TWL6030_BASEADD_RSV 0x0000
+#define TWL6030_BASEADD_ZERO 0x0000
/* Few power values */
#define R_CFG_BOOT 0x05
@@ -319,9 +314,11 @@ static struct twl_mapping twl6030_map[] = {
{ SUB_CHIP_ID1, TWL6030_BASEADD_CHARGER },
{ SUB_CHIP_ID1, TWL6030_BASEADD_GASGAUGE },
{ SUB_CHIP_ID1, TWL6030_BASEADD_PWM },
- { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
- { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
+ { SUB_CHIP_ID0, TWL6030_BASEADD_ZERO },
+ { SUB_CHIP_ID1, TWL6030_BASEADD_ZERO },
+ { SUB_CHIP_ID2, TWL6030_BASEADD_ZERO },
+ { SUB_CHIP_ID2, TWL6030_BASEADD_ZERO },
{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
@@ -587,18 +584,6 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
struct device *child;
unsigned sub_chip_id;
- if (twl_has_bci() && pdata->bci &&
- !(features & (TPS_SUBSET | TWL5031))) {
- child = add_child(3, "twl4030_bci",
- pdata->bci, sizeof(*pdata->bci),
- false,
- /* irq0 = CHG_PRES, irq1 = BCI */
- pdata->irq_base + BCI_PRES_INTR_OFFSET,
- pdata->irq_base + BCI_INTR_OFFSET);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
if (twl_has_gpio() && pdata->gpio) {
child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
pdata->gpio, sizeof(*pdata->gpio),
@@ -711,8 +696,19 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
return PTR_ERR(child);
}
- if (twl_has_codec() && pdata->codec) {
- child = add_child(1, "twl4030_codec",
+ if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
+ sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
+ child = add_child(sub_chip_id, "twl4030_codec",
+ pdata->codec, sizeof(*pdata->codec),
+ false, 0, 0);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+
+ /* Phoenix*/
+ if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
+ sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
+ child = add_child(sub_chip_id, "twl6030_codec",
pdata->codec, sizeof(*pdata->codec),
false, 0, 0);
if (IS_ERR(child))
@@ -965,6 +961,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
int status;
unsigned i;
struct twl4030_platform_data *pdata = client->dev.platform_data;
+ u8 temp;
if (!pdata) {
dev_dbg(&client->dev, "no platform data?\n");
@@ -1032,6 +1029,18 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
goto fail;
}
+ /* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
+ * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
+ * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
+ */
+
+ if (twl_class_is_4030()) {
+ twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);
+ temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
+ I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
+ twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
+ }
+
status = add_children(pdata, id->driver_data);
fail:
if (status < 0)
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 0815292fdafc..7efa8789a3a2 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -405,7 +405,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) {
remap &= ~SLEEP_STATE_MASK;
- remap |= rconfig->remap_off << SLEEP_STATE_SHIFT;
+ remap |= rconfig->remap_sleep << SLEEP_STATE_SHIFT;
}
err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
@@ -461,6 +461,56 @@ out:
return err;
}
+int twl4030_remove_script(u8 flags)
+{
+ int err = 0;
+
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1,
+ R_PROTECT_KEY);
+ if (err) {
+ pr_err("twl4030: unable to unlock PROTECT_KEY\n");
+ return err;
+ }
+
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2,
+ R_PROTECT_KEY);
+ if (err) {
+ pr_err("twl4030: unable to unlock PROTECT_KEY\n");
+ return err;
+ }
+
+ if (flags & TWL4030_WRST_SCRIPT) {
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
+ R_SEQ_ADD_WARM);
+ if (err)
+ return err;
+ }
+ if (flags & TWL4030_WAKEUP12_SCRIPT) {
+ if (err)
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
+ R_SEQ_ADD_S2A12);
+ return err;
+ }
+ if (flags & TWL4030_WAKEUP3_SCRIPT) {
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
+ R_SEQ_ADD_S2A3);
+ if (err)
+ return err;
+ }
+ if (flags & TWL4030_SLEEP_SCRIPT) {
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
+ R_SEQ_ADD_A2S);
+ if (err)
+ return err;
+ }
+
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
+ if (err)
+ pr_err("TWL4030 Unable to relock registers\n");
+
+ return err;
+}
+
void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
{
int err = 0;
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 252b74188ec2..b281217334eb 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -27,6 +27,7 @@
#include <linux/mutex.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/gpio.h>
+#include <linux/semaphore.h>
#include <mach/dma.h>
#include <mach/hardware.h>
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 4b2021af1d96..07101e9e1cba 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -321,7 +321,6 @@ EXPORT_SYMBOL_GPL(wm831x_set_bits);
*/
int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
{
- int tries = 10;
int ret, src;
mutex_lock(&wm831x->auxadc_lock);
@@ -349,13 +348,14 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
goto disable;
}
- do {
- msleep(1);
+ /* Ignore the result to allow us to soldier on without IRQ hookup */
+ wait_for_completion_timeout(&wm831x->auxadc_done, msecs_to_jiffies(5));
- ret = wm831x_reg_read(wm831x, WM831X_AUXADC_CONTROL);
- if (ret < 0)
- ret = WM831X_AUX_CVT_ENA;
- } while ((ret & WM831X_AUX_CVT_ENA) && --tries);
+ ret = wm831x_reg_read(wm831x, WM831X_AUXADC_CONTROL);
+ if (ret < 0) {
+ dev_err(wm831x->dev, "AUXADC status read failed: %d\n", ret);
+ goto disable;
+ }
if (ret & WM831X_AUX_CVT_ENA) {
dev_err(wm831x->dev, "Timed out reading AUXADC\n");
@@ -390,6 +390,15 @@ out:
}
EXPORT_SYMBOL_GPL(wm831x_auxadc_read);
+static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data)
+{
+ struct wm831x *wm831x = irq_data;
+
+ complete(&wm831x->auxadc_done);
+
+ return IRQ_HANDLED;
+}
+
/**
* wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC
*
@@ -1411,6 +1420,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
mutex_init(&wm831x->io_lock);
mutex_init(&wm831x->key_lock);
mutex_init(&wm831x->auxadc_lock);
+ init_completion(&wm831x->auxadc_done);
dev_set_drvdata(wm831x->dev, wm831x);
ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
@@ -1449,18 +1459,33 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
case WM8310:
parent = WM8310;
wm831x->num_gpio = 16;
+ if (rev > 0) {
+ wm831x->has_gpio_ena = 1;
+ wm831x->has_cs_sts = 1;
+ }
+
dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
break;
case WM8311:
parent = WM8311;
wm831x->num_gpio = 16;
+ if (rev > 0) {
+ wm831x->has_gpio_ena = 1;
+ wm831x->has_cs_sts = 1;
+ }
+
dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
break;
case WM8312:
parent = WM8312;
wm831x->num_gpio = 16;
+ if (rev > 0) {
+ wm831x->has_gpio_ena = 1;
+ wm831x->has_cs_sts = 1;
+ }
+
dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
break;
@@ -1508,6 +1533,16 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
if (ret != 0)
goto err;
+ if (wm831x->irq_base) {
+ ret = request_threaded_irq(wm831x->irq_base +
+ WM831X_IRQ_AUXADC_DATA,
+ NULL, wm831x_auxadc_irq, 0,
+ "auxadc", wm831x);
+ if (ret < 0)
+ dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n",
+ ret);
+ }
+
/* The core device is up, instantiate the subdevices. */
switch (parent) {
case WM8310:
@@ -1578,6 +1613,8 @@ static void wm831x_device_exit(struct wm831x *wm831x)
{
wm831x_otp_exit(wm831x);
mfd_remove_devices(wm831x->dev);
+ if (wm831x->irq_base)
+ free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x);
wm831x_irq_exit(wm831x);
kfree(wm831x);
}
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
index 8485a7018060..bd75807d5302 100644
--- a/drivers/mfd/wm8350-core.c
+++ b/drivers/mfd/wm8350-core.c
@@ -134,8 +134,7 @@ static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg)
wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY)
return 0;
- if ((reg == WM8350_GPIO_CONFIGURATION_I_O) ||
- (reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
+ if ((reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
reg <= WM8350_GPIO_FUNCTION_SELECT_4) ||
(reg >= WM8350_BATTERY_CHARGER_CONTROL_1 &&
reg <= WM8350_BATTERY_CHARGER_CONTROL_3))
@@ -340,7 +339,6 @@ EXPORT_SYMBOL_GPL(wm8350_reg_unlock);
int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
{
u16 reg, result = 0;
- int tries = 5;
if (channel < WM8350_AUXADC_AUX1 || channel > WM8350_AUXADC_TEMP)
return -EINVAL;
@@ -364,12 +362,13 @@ int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
reg |= 1 << channel | WM8350_AUXADC_POLL;
wm8350_reg_write(wm8350, WM8350_DIGITISER_CONTROL_1, reg);
- do {
- schedule_timeout_interruptible(1);
- reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
- } while ((reg & WM8350_AUXADC_POLL) && --tries);
+ /* We ignore the result of the completion and just check for a
+ * conversion result, allowing us to soldier on if the IRQ
+ * infrastructure is not set up for the chip. */
+ wait_for_completion_timeout(&wm8350->auxadc_done, msecs_to_jiffies(5));
- if (!tries)
+ reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
+ if (reg & WM8350_AUXADC_POLL)
dev_err(wm8350->dev, "adc chn %d read timeout\n", channel);
else
result = wm8350_reg_read(wm8350,
@@ -386,6 +385,15 @@ int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
}
EXPORT_SYMBOL_GPL(wm8350_read_auxadc);
+static irqreturn_t wm8350_auxadc_irq(int irq, void *irq_data)
+{
+ struct wm8350 *wm8350 = irq_data;
+
+ complete(&wm8350->auxadc_done);
+
+ return IRQ_HANDLED;
+}
+
/*
* Cache is always host endian.
*/
@@ -683,11 +691,22 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
}
mutex_init(&wm8350->auxadc_mutex);
+ init_completion(&wm8350->auxadc_done);
ret = wm8350_irq_init(wm8350, irq, pdata);
if (ret < 0)
goto err;
+ if (wm8350->irq_base) {
+ ret = request_threaded_irq(wm8350->irq_base +
+ WM8350_IRQ_AUXADC_DATARDY,
+ NULL, wm8350_auxadc_irq, 0,
+ "auxadc", wm8350);
+ if (ret < 0)
+ dev_warn(wm8350->dev,
+ "Failed to request AUXADC IRQ: %d\n", ret);
+ }
+
if (pdata && pdata->init) {
ret = pdata->init(wm8350);
if (ret != 0) {
@@ -737,6 +756,9 @@ void wm8350_device_exit(struct wm8350 *wm8350)
platform_device_unregister(wm8350->gpio.pdev);
platform_device_unregister(wm8350->codec.pdev);
+ if (wm8350->irq_base)
+ free_irq(wm8350->irq_base + WM8350_IRQ_AUXADC_DATARDY, wm8350);
+
wm8350_irq_exit(wm8350);
kfree(wm8350->reg_cache);
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c
index c8df547c4747..f56c9adf9493 100644
--- a/drivers/mfd/wm8350-irq.c
+++ b/drivers/mfd/wm8350-irq.c
@@ -18,7 +18,7 @@
#include <linux/bug.h>
#include <linux/device.h>
#include <linux/interrupt.h>
-#include <linux/workqueue.h>
+#include <linux/irq.h>
#include <linux/mfd/wm8350/core.h>
#include <linux/mfd/wm8350/audio.h>
@@ -29,8 +29,6 @@
#include <linux/mfd/wm8350/supply.h>
#include <linux/mfd/wm8350/wdt.h>
-#define WM8350_NUM_IRQ_REGS 7
-
#define WM8350_INT_OFFSET_1 0
#define WM8350_INT_OFFSET_2 1
#define WM8350_POWER_UP_INT_OFFSET 2
@@ -366,19 +364,10 @@ static struct wm8350_irq_data wm8350_irqs[] = {
},
};
-static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
+static inline struct wm8350_irq_data *irq_to_wm8350_irq(struct wm8350 *wm8350,
+ int irq)
{
- mutex_lock(&wm8350->irq_mutex);
-
- if (wm8350->irq[irq].handler)
- wm8350->irq[irq].handler(irq, wm8350->irq[irq].data);
- else {
- dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n",
- irq);
- wm8350_mask_irq(wm8350, irq);
- }
-
- mutex_unlock(&wm8350->irq_mutex);
+ return &wm8350_irqs[irq - wm8350->irq_base];
}
/*
@@ -386,7 +375,9 @@ static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
* interrupts are clear on read the IRQ line will be reasserted and
* the physical IRQ will be handled again if another interrupt is
* asserted while we run - in the normal course of events this is a
- * rare occurrence so we save I2C/SPI reads.
+ * rare occurrence so we save I2C/SPI reads. We're also assuming that
+ * it's rare to get lots of interrupts firing simultaneously so try to
+ * minimise I/O.
*/
static irqreturn_t wm8350_irq(int irq, void *irq_data)
{
@@ -397,7 +388,6 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data)
struct wm8350_irq_data *data;
int i;
- /* TODO: Use block reads to improve performance? */
level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
& ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
@@ -416,93 +406,101 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data)
sub_reg[data->reg] =
wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 +
data->reg);
- sub_reg[data->reg] &=
- ~wm8350_reg_read(wm8350,
- WM8350_INT_STATUS_1_MASK +
- data->reg);
+ sub_reg[data->reg] &= ~wm8350->irq_masks[data->reg];
read_done[data->reg] = 1;
}
if (sub_reg[data->reg] & data->mask)
- wm8350_irq_call_handler(wm8350, i);
+ handle_nested_irq(wm8350->irq_base + i);
}
return IRQ_HANDLED;
}
-int wm8350_register_irq(struct wm8350 *wm8350, int irq,
- irq_handler_t handler, unsigned long flags,
- const char *name, void *data)
+static void wm8350_irq_lock(unsigned int irq)
{
- if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
- return -EINVAL;
-
- if (wm8350->irq[irq].handler)
- return -EBUSY;
-
- mutex_lock(&wm8350->irq_mutex);
- wm8350->irq[irq].handler = handler;
- wm8350->irq[irq].data = data;
- mutex_unlock(&wm8350->irq_mutex);
-
- wm8350_unmask_irq(wm8350, irq);
+ struct wm8350 *wm8350 = get_irq_chip_data(irq);
- return 0;
+ mutex_lock(&wm8350->irq_lock);
}
-EXPORT_SYMBOL_GPL(wm8350_register_irq);
-int wm8350_free_irq(struct wm8350 *wm8350, int irq)
+static void wm8350_irq_sync_unlock(unsigned int irq)
{
- if (irq < 0 || irq > WM8350_NUM_IRQ)
- return -EINVAL;
+ struct wm8350 *wm8350 = get_irq_chip_data(irq);
+ int i;
- wm8350_mask_irq(wm8350, irq);
+ for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
+ /* If there's been a change in the mask write it back
+ * to the hardware. */
+ if (wm8350->irq_masks[i] !=
+ wm8350->reg_cache[WM8350_INT_STATUS_1_MASK + i])
+ WARN_ON(wm8350_reg_write(wm8350,
+ WM8350_INT_STATUS_1_MASK + i,
+ wm8350->irq_masks[i]));
+ }
- mutex_lock(&wm8350->irq_mutex);
- wm8350->irq[irq].handler = NULL;
- mutex_unlock(&wm8350->irq_mutex);
- return 0;
+ mutex_unlock(&wm8350->irq_lock);
}
-EXPORT_SYMBOL_GPL(wm8350_free_irq);
-int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
+static void wm8350_irq_enable(unsigned int irq)
{
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK +
- wm8350_irqs[irq].reg,
- wm8350_irqs[irq].mask);
+ struct wm8350 *wm8350 = get_irq_chip_data(irq);
+ struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
+
+ wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask;
}
-EXPORT_SYMBOL_GPL(wm8350_mask_irq);
-int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
+static void wm8350_irq_disable(unsigned int irq)
{
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK +
- wm8350_irqs[irq].reg,
- wm8350_irqs[irq].mask);
+ struct wm8350 *wm8350 = get_irq_chip_data(irq);
+ struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
+
+ wm8350->irq_masks[irq_data->reg] |= irq_data->mask;
}
-EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
+
+static struct irq_chip wm8350_irq_chip = {
+ .name = "wm8350",
+ .bus_lock = wm8350_irq_lock,
+ .bus_sync_unlock = wm8350_irq_sync_unlock,
+ .disable = wm8350_irq_disable,
+ .enable = wm8350_irq_enable,
+};
int wm8350_irq_init(struct wm8350 *wm8350, int irq,
struct wm8350_platform_data *pdata)
{
- int ret;
+ int ret, cur_irq, i;
int flags = IRQF_ONESHOT;
if (!irq) {
- dev_err(wm8350->dev, "No IRQ configured\n");
- return -EINVAL;
+ dev_warn(wm8350->dev, "No interrupt support, no core IRQ\n");
+ return 0;
+ }
+
+ if (!pdata || !pdata->irq_base) {
+ dev_warn(wm8350->dev, "No interrupt support, no IRQ base\n");
+ return 0;
}
+ /* Mask top level interrupts */
wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
- wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF);
- wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF);
- wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF);
- wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF);
- wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF);
- mutex_init(&wm8350->irq_mutex);
+ /* Mask all individual interrupts by default and cache the
+ * masks. We read the masks back since there are unwritable
+ * bits in the mask registers. */
+ for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
+ wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK + i,
+ 0xFFFF);
+ wm8350->irq_masks[i] =
+ wm8350_reg_read(wm8350,
+ WM8350_INT_STATUS_1_MASK + i);
+ }
+
+ mutex_init(&wm8350->irq_lock);
wm8350->chip_irq = irq;
+ wm8350->irq_base = pdata->irq_base;
- if (pdata && pdata->irq_high) {
+ if (pdata->irq_high) {
flags |= IRQF_TRIGGER_HIGH;
wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
@@ -514,11 +512,32 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq,
WM8350_IRQ_POL);
}
+ /* Register with genirq */
+ for (cur_irq = wm8350->irq_base;
+ cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base;
+ cur_irq++) {
+ set_irq_chip_data(cur_irq, wm8350);
+ set_irq_chip_and_handler(cur_irq, &wm8350_irq_chip,
+ handle_edge_irq);
+ set_irq_nested_thread(cur_irq, 1);
+
+ /* ARM needs us to explicitly flag the IRQ as valid
+ * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+ set_irq_flags(cur_irq, IRQF_VALID);
+#else
+ set_irq_noprobe(cur_irq);
+#endif
+ }
+
ret = request_threaded_irq(irq, NULL, wm8350_irq, flags,
"wm8350", wm8350);
if (ret != 0)
dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret);
+ /* Allow interrupts to fire */
+ wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0);
+
return ret;
}
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
new file mode 100644
index 000000000000..844e1c1b7d90
--- /dev/null
+++ b/drivers/mfd/wm8994-core.c
@@ -0,0 +1,537 @@
+/*
+ * wm8994-core.c -- Device access for Wolfson WM8994
+ *
+ * Copyright 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/mfd/wm8994/registers.h>
+
+static int wm8994_read(struct wm8994 *wm8994, unsigned short reg,
+ int bytes, void *dest)
+{
+ int ret, i;
+ u16 *buf = dest;
+
+ BUG_ON(bytes % 2);
+ BUG_ON(bytes <= 0);
+
+ ret = wm8994->read_dev(wm8994, reg, bytes, dest);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < bytes / 2; i++) {
+ buf[i] = be16_to_cpu(buf[i]);
+
+ dev_vdbg(wm8994->dev, "Read %04x from R%d(0x%x)\n",
+ buf[i], reg + i, reg + i);
+ }
+
+ return 0;
+}
+
+/**
+ * wm8994_reg_read: Read a single WM8994 register.
+ *
+ * @wm8994: Device to read from.
+ * @reg: Register to read.
+ */
+int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg)
+{
+ unsigned short val;
+ int ret;
+
+ mutex_lock(&wm8994->io_lock);
+
+ ret = wm8994_read(wm8994, reg, 2, &val);
+
+ mutex_unlock(&wm8994->io_lock);
+
+ if (ret < 0)
+ return ret;
+ else
+ return val;
+}
+EXPORT_SYMBOL_GPL(wm8994_reg_read);
+
+/**
+ * wm8994_bulk_read: Read multiple WM8994 registers
+ *
+ * @wm8994: Device to read from
+ * @reg: First register
+ * @count: Number of registers
+ * @buf: Buffer to fill.
+ */
+int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
+ int count, u16 *buf)
+{
+ int ret;
+
+ mutex_lock(&wm8994->io_lock);
+
+ ret = wm8994_read(wm8994, reg, count * 2, buf);
+
+ mutex_unlock(&wm8994->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8994_bulk_read);
+
+static int wm8994_write(struct wm8994 *wm8994, unsigned short reg,
+ int bytes, void *src)
+{
+ u16 *buf = src;
+ int i;
+
+ BUG_ON(bytes % 2);
+ BUG_ON(bytes <= 0);
+
+ for (i = 0; i < bytes / 2; i++) {
+ dev_vdbg(wm8994->dev, "Write %04x to R%d(0x%x)\n",
+ buf[i], reg + i, reg + i);
+
+ buf[i] = cpu_to_be16(buf[i]);
+ }
+
+ return wm8994->write_dev(wm8994, reg, bytes, src);
+}
+
+/**
+ * wm8994_reg_write: Write a single WM8994 register.
+ *
+ * @wm8994: Device to write to.
+ * @reg: Register to write to.
+ * @val: Value to write.
+ */
+int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg,
+ unsigned short val)
+{
+ int ret;
+
+ mutex_lock(&wm8994->io_lock);
+
+ ret = wm8994_write(wm8994, reg, 2, &val);
+
+ mutex_unlock(&wm8994->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8994_reg_write);
+
+/**
+ * wm8994_set_bits: Set the value of a bitfield in a WM8994 register
+ *
+ * @wm8994: Device to write to.
+ * @reg: Register to write to.
+ * @mask: Mask of bits to set.
+ * @val: Value to set (unshifted)
+ */
+int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg,
+ unsigned short mask, unsigned short val)
+{
+ int ret;
+ u16 r;
+
+ mutex_lock(&wm8994->io_lock);
+
+ ret = wm8994_read(wm8994, reg, 2, &r);
+ if (ret < 0)
+ goto out;
+
+ r &= ~mask;
+ r |= val;
+
+ ret = wm8994_write(wm8994, reg, 2, &r);
+
+out:
+ mutex_unlock(&wm8994->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8994_set_bits);
+
+static struct mfd_cell wm8994_regulator_devs[] = {
+ { .name = "wm8994-ldo", .id = 1 },
+ { .name = "wm8994-ldo", .id = 2 },
+};
+
+static struct mfd_cell wm8994_devs[] = {
+ { .name = "wm8994-codec" },
+ { .name = "wm8994-gpio" },
+};
+
+/*
+ * Supplies for the main bulk of CODEC; the LDO supplies are ignored
+ * and should be handled via the standard regulator API supply
+ * management.
+ */
+static const char *wm8994_main_supplies[] = {
+ "DBVDD",
+ "DCVDD",
+ "AVDD1",
+ "AVDD2",
+ "CPVDD",
+ "SPKVDD1",
+ "SPKVDD2",
+};
+
+#ifdef CONFIG_PM
+static int wm8994_device_suspend(struct device *dev)
+{
+ struct wm8994 *wm8994 = dev_get_drvdata(dev);
+ int ret;
+
+ /* GPIO configuration state is saved here since we may be configuring
+ * the GPIO alternate functions even if we're not using the gpiolib
+ * driver for them.
+ */
+ ret = wm8994_read(wm8994, WM8994_GPIO_1, WM8994_NUM_GPIO_REGS * 2,
+ &wm8994->gpio_regs);
+ if (ret < 0)
+ dev_err(dev, "Failed to save GPIO registers: %d\n", ret);
+
+ /* For similar reasons we also stash the regulator states */
+ ret = wm8994_read(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2,
+ &wm8994->ldo_regs);
+ if (ret < 0)
+ dev_err(dev, "Failed to save LDO registers: %d\n", ret);
+
+ ret = regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
+ wm8994->supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to disable supplies: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int wm8994_device_resume(struct device *dev)
+{
+ struct wm8994 *wm8994 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies),
+ wm8994->supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = wm8994_write(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2,
+ &wm8994->ldo_regs);
+ if (ret < 0)
+ dev_err(dev, "Failed to restore LDO registers: %d\n", ret);
+
+ ret = wm8994_write(wm8994, WM8994_GPIO_1, WM8994_NUM_GPIO_REGS * 2,
+ &wm8994->gpio_regs);
+ if (ret < 0)
+ dev_err(dev, "Failed to restore GPIO registers: %d\n", ret);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_REGULATOR
+static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
+{
+ struct wm8994_ldo_pdata *ldo_pdata;
+
+ if (!pdata)
+ return 0;
+
+ ldo_pdata = &pdata->ldo[ldo];
+
+ if (!ldo_pdata->init_data)
+ return 0;
+
+ return ldo_pdata->init_data->num_consumer_supplies != 0;
+}
+#else
+static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
+{
+ return 0;
+}
+#endif
+
+/*
+ * Instantiate the generic non-control parts of the device.
+ */
+static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
+{
+ struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+ int ret, i;
+
+ mutex_init(&wm8994->io_lock);
+ dev_set_drvdata(wm8994->dev, wm8994);
+
+ /* Add the on-chip regulators first for bootstrapping */
+ ret = mfd_add_devices(wm8994->dev, -1,
+ wm8994_regulator_devs,
+ ARRAY_SIZE(wm8994_regulator_devs),
+ NULL, 0);
+ if (ret != 0) {
+ dev_err(wm8994->dev, "Failed to add children: %d\n", ret);
+ goto err;
+ }
+
+ wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
+ ARRAY_SIZE(wm8994_main_supplies),
+ GFP_KERNEL);
+ if (!wm8994->supplies)
+ goto err;
+
+ for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
+ wm8994->supplies[i].supply = wm8994_main_supplies[i];
+
+ ret = regulator_bulk_get(wm8994->dev, ARRAY_SIZE(wm8994_main_supplies),
+ wm8994->supplies);
+ if (ret != 0) {
+ dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
+ goto err_supplies;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies),
+ wm8994->supplies);
+ if (ret != 0) {
+ dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_get;
+ }
+
+ ret = wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET);
+ if (ret < 0) {
+ dev_err(wm8994->dev, "Failed to read ID register\n");
+ goto err_enable;
+ }
+ if (ret != 0x8994) {
+ dev_err(wm8994->dev, "Device is not a WM8994, ID is %x\n",
+ ret);
+ ret = -EINVAL;
+ goto err_enable;
+ }
+
+ ret = wm8994_reg_read(wm8994, WM8994_CHIP_REVISION);
+ if (ret < 0) {
+ dev_err(wm8994->dev, "Failed to read revision register: %d\n",
+ ret);
+ goto err_enable;
+ }
+
+ switch (ret) {
+ case 0:
+ case 1:
+ dev_warn(wm8994->dev, "revision %c not fully supported\n",
+ 'A' + ret);
+ break;
+ default:
+ dev_info(wm8994->dev, "revision %c\n", 'A' + ret);
+ break;
+ }
+
+
+ if (pdata) {
+ wm8994->gpio_base = pdata->gpio_base;
+
+ /* GPIO configuration is only applied if it's non-zero */
+ for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
+ if (pdata->gpio_defaults[i]) {
+ wm8994_set_bits(wm8994, WM8994_GPIO_1 + i,
+ 0xffff,
+ pdata->gpio_defaults[i]);
+ }
+ }
+ }
+
+ /* In some system designs where the regulators are not in use,
+ * we can achieve a small reduction in leakage currents by
+ * floating LDO outputs. This bit makes no difference if the
+ * LDOs are enabled, it only affects cases where the LDOs were
+ * in operation and are then disabled.
+ */
+ for (i = 0; i < WM8994_NUM_LDO_REGS; i++) {
+ if (wm8994_ldo_in_use(pdata, i))
+ wm8994_set_bits(wm8994, WM8994_LDO_1 + i,
+ WM8994_LDO1_DISCH, WM8994_LDO1_DISCH);
+ else
+ wm8994_set_bits(wm8994, WM8994_LDO_1 + i,
+ WM8994_LDO1_DISCH, 0);
+ }
+
+ ret = mfd_add_devices(wm8994->dev, -1,
+ wm8994_devs, ARRAY_SIZE(wm8994_devs),
+ NULL, 0);
+ if (ret != 0) {
+ dev_err(wm8994->dev, "Failed to add children: %d\n", ret);
+ goto err_enable;
+ }
+
+ return 0;
+
+err_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
+ wm8994->supplies);
+err_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies);
+err_supplies:
+ kfree(wm8994->supplies);
+err:
+ mfd_remove_devices(wm8994->dev);
+ kfree(wm8994);
+ return ret;
+}
+
+static void wm8994_device_exit(struct wm8994 *wm8994)
+{
+ mfd_remove_devices(wm8994->dev);
+ regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
+ wm8994->supplies);
+ regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies);
+ kfree(wm8994->supplies);
+ kfree(wm8994);
+}
+
+static int wm8994_i2c_read_device(struct wm8994 *wm8994, unsigned short reg,
+ int bytes, void *dest)
+{
+ struct i2c_client *i2c = wm8994->control_data;
+ int ret;
+ u16 r = cpu_to_be16(reg);
+
+ ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
+ if (ret < 0)
+ return ret;
+ if (ret != 2)
+ return -EIO;
+
+ ret = i2c_master_recv(i2c, dest, bytes);
+ if (ret < 0)
+ return ret;
+ if (ret != bytes)
+ return -EIO;
+ return 0;
+}
+
+/* Currently we allocate the write buffer on the stack; this is OK for
+ * small writes - if we need to do large writes this will need to be
+ * revised.
+ */
+static int wm8994_i2c_write_device(struct wm8994 *wm8994, unsigned short reg,
+ int bytes, void *src)
+{
+ struct i2c_client *i2c = wm8994->control_data;
+ unsigned char msg[bytes + 2];
+ int ret;
+
+ reg = cpu_to_be16(reg);
+ memcpy(&msg[0], &reg, 2);
+ memcpy(&msg[2], src, bytes);
+
+ ret = i2c_master_send(i2c, msg, bytes + 2);
+ if (ret < 0)
+ return ret;
+ if (ret < bytes + 2)
+ return -EIO;
+
+ return 0;
+}
+
+static int wm8994_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8994 *wm8994;
+
+ wm8994 = kzalloc(sizeof(struct wm8994), GFP_KERNEL);
+ if (wm8994 == NULL) {
+ kfree(i2c);
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(i2c, wm8994);
+ wm8994->dev = &i2c->dev;
+ wm8994->control_data = i2c;
+ wm8994->read_dev = wm8994_i2c_read_device;
+ wm8994->write_dev = wm8994_i2c_write_device;
+
+ return wm8994_device_init(wm8994, id->driver_data, i2c->irq);
+}
+
+static int wm8994_i2c_remove(struct i2c_client *i2c)
+{
+ struct wm8994 *wm8994 = i2c_get_clientdata(i2c);
+
+ wm8994_device_exit(wm8994);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8994_i2c_suspend(struct i2c_client *i2c, pm_message_t state)
+{
+ return wm8994_device_suspend(&i2c->dev);
+}
+
+static int wm8994_i2c_resume(struct i2c_client *i2c)
+{
+ return wm8994_device_resume(&i2c->dev);
+}
+#else
+#define wm8994_i2c_suspend NULL
+#define wm8994_i2c_resume NULL
+#endif
+
+static const struct i2c_device_id wm8994_i2c_id[] = {
+ { "wm8994", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id);
+
+static struct i2c_driver wm8994_i2c_driver = {
+ .driver = {
+ .name = "wm8994",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8994_i2c_probe,
+ .remove = wm8994_i2c_remove,
+ .suspend = wm8994_i2c_suspend,
+ .resume = wm8994_i2c_resume,
+ .id_table = wm8994_i2c_id,
+};
+
+static int __init wm8994_i2c_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&wm8994_i2c_driver);
+ if (ret != 0)
+ pr_err("Failed to register wm8994 I2C driver: %d\n", ret);
+
+ return ret;
+}
+module_init(wm8994_i2c_init);
+
+static void __exit wm8994_i2c_exit(void)
+{
+ i2c_del_driver(&wm8994_i2c_driver);
+}
+module_exit(wm8994_i2c_exit);
+
+MODULE_DESCRIPTION("Core support for the WM8994 audio CODEC");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index e3551d20464f..2191c8d896a0 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -212,6 +212,15 @@ config CS5535_MFGPT_DEFAULT_IRQ
want to use a different IRQ by default. This is here for
architectures to set as necessary.
+config CS5535_CLOCK_EVENT_SRC
+ tristate "CS5535/CS5536 high-res timer (MFGPT) events"
+ depends on GENERIC_TIME && GENERIC_CLOCKEVENTS && CS5535_MFGPT
+ help
+ This driver provides a clock event source based on the MFGPT
+ timer(s) in the CS5535 and CS5536 companion chips.
+ MFGPTs have a better resolution and max interval than the
+ generic PIT, and are suitable for use as high-res timers.
+
config HP_ILO
tristate "Channel interface driver for HP iLO/iLO2 processor"
depends on PCI
@@ -259,6 +268,16 @@ config ISL29003
This driver can also be built as a module. If so, the module
will be called isl29003.
+config SENSORS_TSL2550
+ tristate "Taos TSL2550 ambient light sensor"
+ depends on I2C && SYSFS
+ help
+ If you say yes here you get support for the Taos TSL2550
+ ambient light sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called tsl2550.
+
config EP93XX_PWM
tristate "EP93xx PWM support"
depends on ARCH_EP93XX
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 049ff2482f30..27c484355414 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_SGI_GRU) += sgi-gru/
obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfgpt.o
obj-$(CONFIG_HP_ILO) += hpilo.o
obj-$(CONFIG_ISL29003) += isl29003.o
+obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o
obj-$(CONFIG_DS1682) += ds1682.o
obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 2cb2736d65aa..db7d0f21b65d 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -505,6 +505,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
* Export the EEPROM bytes through sysfs, since that's convenient.
* By default, only root should see the data (maybe passwords etc)
*/
+ sysfs_bin_attr_init(&at24->bin);
at24->bin.attr.name = "eeprom";
at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR;
at24->bin.read = at24_bin_read;
diff --git a/drivers/misc/iwmc3200top/fw-download.c b/drivers/misc/iwmc3200top/fw-download.c
index 50d431e469f5..9dbaeb574e63 100644
--- a/drivers/misc/iwmc3200top/fw-download.c
+++ b/drivers/misc/iwmc3200top/fw-download.c
@@ -43,15 +43,14 @@ static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file,
struct iwmct_parser *parser = &priv->parser;
struct iwmct_fw_hdr *fw_hdr = &parser->versions;
- LOG_INFOEX(priv, INIT, "-->\n");
+ LOG_TRACE(priv, FW_DOWNLOAD, "-->\n");
LOG_INFO(priv, FW_DOWNLOAD, "file_size=%zd\n", file_size);
parser->file = file;
parser->file_size = file_size;
parser->cur_pos = 0;
- parser->buf = NULL;
-
+ parser->entry_point = 0;
parser->buf = kzalloc(block_size, GFP_KERNEL);
if (!parser->buf) {
LOG_ERROR(priv, FW_DOWNLOAD, "kzalloc error\n");
@@ -70,7 +69,7 @@ static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file,
parser->cur_pos += sizeof(struct iwmct_fw_hdr);
- LOG_INFOEX(priv, INIT, "<--\n");
+ LOG_TRACE(priv, FW_DOWNLOAD, "<--\n");
return 0;
}
@@ -113,7 +112,7 @@ static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec,
struct iwmct_dbg *dbg = &priv->dbg;
struct iwmct_fw_sec_hdr *sec_hdr;
- LOG_INFOEX(priv, INIT, "-->\n");
+ LOG_TRACE(priv, FW_DOWNLOAD, "-->\n");
while (parser->cur_pos + sizeof(struct iwmct_fw_sec_hdr)
<= parser->file_size) {
@@ -152,7 +151,7 @@ static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec,
"finished with section cur_pos=%zd\n", parser->cur_pos);
}
- LOG_INFOEX(priv, INIT, "<--\n");
+ LOG_TRACE(priv, INIT, "<--\n");
return 0;
}
@@ -167,7 +166,7 @@ static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec,
int ret = 0;
u32 cmd = 0;
- LOG_INFOEX(priv, INIT, "-->\n");
+ LOG_TRACE(priv, FW_DOWNLOAD, "-->\n");
LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n",
addr, sec_size);
@@ -229,7 +228,7 @@ static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec,
hdr->cmd = cpu_to_le32(cmd);
/* send it down */
/* TODO: add more proper sending and error checking */
- ret = iwmct_tx(priv, 0, parser->buf, trans_size);
+ ret = iwmct_tx(priv, parser->buf, trans_size);
if (ret != 0) {
LOG_INFO(priv, FW_DOWNLOAD,
"iwmct_tx returned %d\n", ret);
@@ -251,7 +250,7 @@ static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec,
if (sent < sec_size)
ret = -EINVAL;
exit:
- LOG_INFOEX(priv, INIT, "<--\n");
+ LOG_TRACE(priv, FW_DOWNLOAD, "<--\n");
return ret;
}
@@ -262,7 +261,7 @@ static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump)
int ret;
u32 cmd;
- LOG_INFOEX(priv, INIT, "-->\n");
+ LOG_TRACE(priv, FW_DOWNLOAD, "-->\n");
memset(parser->buf, 0, parser->buf_size);
cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
@@ -281,11 +280,11 @@ static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump)
LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr));
/* send it down */
/* TODO: add more proper sending and error checking */
- ret = iwmct_tx(priv, 0, parser->buf, IWMC_SDIO_BLK_SIZE);
+ ret = iwmct_tx(priv, parser->buf, IWMC_SDIO_BLK_SIZE);
if (ret)
LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret);
- LOG_INFOEX(priv, INIT, "<--\n");
+ LOG_TRACE(priv, FW_DOWNLOAD, "<--\n");
return 0;
}
@@ -298,8 +297,16 @@ int iwmct_fw_load(struct iwmct_priv *priv)
__le32 addr;
int ret;
- /* clear parser struct */
- memset(&priv->parser, 0, sizeof(struct iwmct_parser));
+
+ LOG_INFO(priv, FW_DOWNLOAD, "barker download request 0x%x is:\n",
+ priv->barker);
+ LOG_INFO(priv, FW_DOWNLOAD, "******* Top FW %s requested ********\n",
+ (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not");
+ LOG_INFO(priv, FW_DOWNLOAD, "******* GPS FW %s requested ********\n",
+ (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not");
+ LOG_INFO(priv, FW_DOWNLOAD, "******* BT FW %s requested ********\n",
+ (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not");
+
/* get the firmware */
ret = request_firmware(&raw, fw_name, &priv->func->dev);
@@ -317,6 +324,7 @@ int iwmct_fw_load(struct iwmct_priv *priv)
LOG_INFO(priv, FW_DOWNLOAD, "Read firmware '%s'\n", fw_name);
+ /* clear parser struct */
ret = iwmct_fw_parser_init(priv, raw->data, raw->size, priv->trans_len);
if (ret < 0) {
LOG_ERROR(priv, FW_DOWNLOAD,
@@ -324,7 +332,6 @@ int iwmct_fw_load(struct iwmct_priv *priv)
goto exit;
}
- /* checksum */
if (!iwmct_checksum(priv)) {
LOG_ERROR(priv, FW_DOWNLOAD, "checksum error\n");
ret = -EINVAL;
@@ -333,23 +340,18 @@ int iwmct_fw_load(struct iwmct_priv *priv)
/* download firmware to device */
while (iwmct_parse_next_section(priv, &pdata, &len, &addr)) {
- if (iwmct_download_section(priv, pdata, len, addr)) {
+ ret = iwmct_download_section(priv, pdata, len, addr);
+ if (ret) {
LOG_ERROR(priv, FW_DOWNLOAD,
"%s download section failed\n", fw_name);
- ret = -EIO;
goto exit;
}
}
- iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK));
+ ret = iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK));
exit:
kfree(priv->parser.buf);
-
- if (raw)
- release_firmware(raw);
-
- raw = NULL;
-
+ release_firmware(raw);
return ret;
}
diff --git a/drivers/misc/iwmc3200top/iwmc3200top.h b/drivers/misc/iwmc3200top/iwmc3200top.h
index 43bd510e1872..740ff0738ea8 100644
--- a/drivers/misc/iwmc3200top/iwmc3200top.h
+++ b/drivers/misc/iwmc3200top/iwmc3200top.h
@@ -196,9 +196,7 @@ struct iwmct_priv {
struct list_head read_req_list;
};
-extern int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
- void *src, int count);
-
+extern int iwmct_tx(struct iwmct_priv *priv, void *src, int count);
extern int iwmct_fw_load(struct iwmct_priv *priv);
extern void iwmct_dbg_init_params(struct iwmct_priv *drv);
diff --git a/drivers/misc/iwmc3200top/log.h b/drivers/misc/iwmc3200top/log.h
index aba8121f978c..4434bb16cea7 100644
--- a/drivers/misc/iwmc3200top/log.h
+++ b/drivers/misc/iwmc3200top/log.h
@@ -37,13 +37,26 @@
#define LOG_SEV_INFO 3
#define LOG_SEV_INFOEX 4
-#define LOG_SEV_FILTER_ALL \
- (BIT(LOG_SEV_CRITICAL) | \
- BIT(LOG_SEV_ERROR) | \
- BIT(LOG_SEV_WARNING) | \
- BIT(LOG_SEV_INFO) | \
+/* Log levels not defined for FW */
+#define LOG_SEV_TRACE 5
+#define LOG_SEV_DUMP 6
+
+#define LOG_SEV_FW_FILTER_ALL \
+ (BIT(LOG_SEV_CRITICAL) | \
+ BIT(LOG_SEV_ERROR) | \
+ BIT(LOG_SEV_WARNING) | \
+ BIT(LOG_SEV_INFO) | \
BIT(LOG_SEV_INFOEX))
+#define LOG_SEV_FILTER_ALL \
+ (BIT(LOG_SEV_CRITICAL) | \
+ BIT(LOG_SEV_ERROR) | \
+ BIT(LOG_SEV_WARNING) | \
+ BIT(LOG_SEV_INFO) | \
+ BIT(LOG_SEV_INFOEX) | \
+ BIT(LOG_SEV_TRACE) | \
+ BIT(LOG_SEV_DUMP))
+
/* log source */
#define LOG_SRC_INIT 0
#define LOG_SRC_DEBUGFS 1
@@ -104,16 +117,16 @@ do { \
__func__, __LINE__, ##args); \
} while (0)
-#define LOG_INFOEX(priv, src, fmt, args...) \
+#define LOG_TRACE(priv, src, fmt, args...) \
do { \
- if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_TRACE)) \
dev_dbg(priv2dev(priv), "%s %d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#define LOG_HEXDUMP(src, ptr, len) \
do { \
- if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_DUMP)) \
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, \
16, 1, ptr, len, false); \
} while (0)
@@ -142,7 +155,7 @@ ssize_t store_iwmct_log_level_fw(struct device *d,
#define LOG_ERROR(priv, src, fmt, args...)
#define LOG_WARNING(priv, src, fmt, args...)
#define LOG_INFO(priv, src, fmt, args...)
-#define LOG_INFOEX(priv, src, fmt, args...)
+#define LOG_TRACE(priv, src, fmt, args...)
#define LOG_HEXDUMP(src, ptr, len)
static inline void iwmct_log_top_message(struct iwmct_priv *priv,
diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c
index fafcaa481d74..3b7292a5cea9 100644
--- a/drivers/misc/iwmc3200top/main.c
+++ b/drivers/misc/iwmc3200top/main.c
@@ -49,6 +49,20 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_COPYRIGHT);
MODULE_FIRMWARE(FW_NAME(FW_API_VER));
+
+static inline int __iwmct_tx(struct iwmct_priv *priv, void *src, int count)
+{
+ return sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, src, count);
+
+}
+int iwmct_tx(struct iwmct_priv *priv, void *src, int count)
+{
+ int ret;
+ sdio_claim_host(priv->func);
+ ret = __iwmct_tx(priv, src, count);
+ sdio_release_host(priv->func);
+ return ret;
+}
/*
* This workers main task is to wait for OP_OPR_ALIVE
* from TOP FW until ALIVE_MSG_TIMOUT timeout is elapsed.
@@ -66,7 +80,7 @@ static void iwmct_rescan_worker(struct work_struct *ws)
ret = bus_rescan_devices(priv->func->dev.bus);
if (ret < 0)
- LOG_INFO(priv, FW_DOWNLOAD, "bus_rescan_devices FAILED!!!\n");
+ LOG_INFO(priv, INIT, "bus_rescan_devices FAILED!!!\n");
}
static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg)
@@ -137,7 +151,7 @@ int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len)
int ret;
u8 *buf;
- LOG_INFOEX(priv, FW_MSG, "Sending hcmd:\n");
+ LOG_TRACE(priv, FW_MSG, "Sending hcmd:\n");
/* add padding to 256 for IWMC */
((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256;
@@ -158,27 +172,12 @@ int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len)
}
memcpy(buf, cmd, len);
-
- sdio_claim_host(priv->func);
- ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, buf,
- FW_HCMD_BLOCK_SIZE);
- sdio_release_host(priv->func);
+ ret = iwmct_tx(priv, buf, FW_HCMD_BLOCK_SIZE);
kfree(buf);
return ret;
}
-int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
- void *src, int count)
-{
- int ret;
-
- sdio_claim_host(priv->func);
- ret = sdio_memcpy_toio(priv->func, addr, src, count);
- sdio_release_host(priv->func);
-
- return ret;
-}
static void iwmct_irq_read_worker(struct work_struct *ws)
{
@@ -192,7 +191,7 @@ static void iwmct_irq_read_worker(struct work_struct *ws)
priv = container_of(ws, struct iwmct_priv, isr_worker);
- LOG_INFO(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws);
+ LOG_TRACE(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws);
/* --------------------- Handshake with device -------------------- */
sdio_claim_host(priv->func);
@@ -273,8 +272,7 @@ static void iwmct_irq_read_worker(struct work_struct *ws)
if (barker & BARKER_DNLOAD_SYNC_MSK) {
/* Send the same barker back */
- ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR,
- buf, iosize);
+ ret = __iwmct_tx(priv, buf, iosize);
if (ret) {
LOG_ERROR(priv, IRQ,
"error %d echoing barker\n", ret);
@@ -292,15 +290,6 @@ static void iwmct_irq_read_worker(struct work_struct *ws)
sdio_release_host(priv->func);
-
- LOG_INFO(priv, IRQ, "barker download request 0x%x is:\n", priv->barker);
- LOG_INFO(priv, IRQ, "******* Top FW %s requested ********\n",
- (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not");
- LOG_INFO(priv, IRQ, "******* GPS FW %s requested ********\n",
- (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not");
- LOG_INFO(priv, IRQ, "******* BT FW %s requested ********\n",
- (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not");
-
if (priv->dbg.fw_download)
iwmct_fw_load(priv);
else
@@ -312,7 +301,7 @@ exit_release:
sdio_release_host(priv->func);
exit:
kfree(buf);
- LOG_INFO(priv, IRQ, "exit iwmct_irq_read_worker\n");
+ LOG_TRACE(priv, IRQ, "exit iwmct_irq_read_worker\n");
}
static void iwmct_irq(struct sdio_func *func)
@@ -325,12 +314,12 @@ static void iwmct_irq(struct sdio_func *func)
priv = sdio_get_drvdata(func);
- LOG_INFO(priv, IRQ, "enter iwmct_irq\n");
+ LOG_TRACE(priv, IRQ, "enter iwmct_irq\n");
/* read the function's status register */
val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret);
- LOG_INFO(priv, IRQ, "iir value = %d, ret=%d\n", val, ret);
+ LOG_TRACE(priv, IRQ, "iir value = %d, ret=%d\n", val, ret);
if (!val) {
LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n");
@@ -372,7 +361,7 @@ static void iwmct_irq(struct sdio_func *func)
queue_work(priv->wq, &priv->isr_worker);
- LOG_INFO(priv, IRQ, "exit iwmct_irq\n");
+ LOG_TRACE(priv, IRQ, "exit iwmct_irq\n");
return;
@@ -608,8 +597,6 @@ static void iwmct_remove(struct sdio_func *func)
struct iwmct_work_struct *read_req;
struct iwmct_priv *priv = sdio_get_drvdata(func);
- priv = sdio_get_drvdata(func);
-
LOG_INFO(priv, INIT, "enter\n");
sdio_claim_host(func);
@@ -660,7 +647,7 @@ static int __init iwmct_init(void)
/* Default log filter settings */
iwmct_log_set_filter(LOG_SRC_ALL, LOG_SEV_FILTER_RUNTIME);
- iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FILTER_ALL);
+ iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FW_FILTER_ALL);
iwmct_log_set_fw_filter(LOG_SRC_ALL, FW_LOG_SEV_FILTER_RUNTIME);
rc = sdio_register_driver(&iwmct_driver);
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index 3648b23d5c92..4a0648301fdf 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -26,21 +26,9 @@
* It is adapted from the Linux Kernel Dump Test Tool by
* Fernando Luis Vazquez Cao <http://lkdtt.sourceforge.net>
*
- * Usage : insmod lkdtm.ko [recur_count={>0}] cpoint_name=<> cpoint_type=<>
- * [cpoint_count={>0}]
+ * Debugfs support added by Simon Kagstrom <simon.kagstrom@netinsight.net>
*
- * recur_count : Recursion level for the stack overflow test. Default is 10.
- *
- * cpoint_name : Crash point where the kernel is to be crashed. It can be
- * one of INT_HARDWARE_ENTRY, INT_HW_IRQ_EN, INT_TASKLET_ENTRY,
- * FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_DISPATCH_CMD,
- * IDE_CORE_CP
- *
- * cpoint_type : Indicates the action to be taken on hitting the crash point.
- * It can be one of PANIC, BUG, EXCEPTION, LOOP, OVERFLOW
- *
- * cpoint_count : Indicates the number of times the crash point is to be hit
- * to trigger an action. The default is 10.
+ * See Documentation/fault-injection/provoke-crashes.txt for instructions
*/
#include <linux/kernel.h>
@@ -53,13 +41,12 @@
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <scsi/scsi_cmnd.h>
+#include <linux/debugfs.h>
#ifdef CONFIG_IDE
#include <linux/ide.h>
#endif
-#define NUM_CPOINTS 8
-#define NUM_CPOINT_TYPES 5
#define DEFAULT_COUNT 10
#define REC_NUM_DEFAULT 10
@@ -72,7 +59,8 @@ enum cname {
MEM_SWAPOUT,
TIMERADD,
SCSI_DISPATCH_CMD,
- IDE_CORE_CP
+ IDE_CORE_CP,
+ DIRECT,
};
enum ctype {
@@ -81,7 +69,11 @@ enum ctype {
BUG,
EXCEPTION,
LOOP,
- OVERFLOW
+ OVERFLOW,
+ CORRUPT_STACK,
+ UNALIGNED_LOAD_STORE_WRITE,
+ OVERWRITE_ALLOCATION,
+ WRITE_AFTER_FREE,
};
static char* cp_name[] = {
@@ -92,7 +84,8 @@ static char* cp_name[] = {
"MEM_SWAPOUT",
"TIMERADD",
"SCSI_DISPATCH_CMD",
- "IDE_CORE_CP"
+ "IDE_CORE_CP",
+ "DIRECT",
};
static char* cp_type[] = {
@@ -100,7 +93,11 @@ static char* cp_type[] = {
"BUG",
"EXCEPTION",
"LOOP",
- "OVERFLOW"
+ "OVERFLOW",
+ "CORRUPT_STACK",
+ "UNALIGNED_LOAD_STORE_WRITE",
+ "OVERWRITE_ALLOCATION",
+ "WRITE_AFTER_FREE",
};
static struct jprobe lkdtm;
@@ -193,34 +190,66 @@ int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file,
}
#endif
+/* Return the crashpoint number or NONE if the name is invalid */
+static enum ctype parse_cp_type(const char *what, size_t count)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cp_type); i++) {
+ if (!strcmp(what, cp_type[i]))
+ return i + 1;
+ }
+
+ return NONE;
+}
+
+static const char *cp_type_to_str(enum ctype type)
+{
+ if (type == NONE || type < 0 || type > ARRAY_SIZE(cp_type))
+ return "None";
+
+ return cp_type[type - 1];
+}
+
+static const char *cp_name_to_str(enum cname name)
+{
+ if (name == INVALID || name < 0 || name > ARRAY_SIZE(cp_name))
+ return "INVALID";
+
+ return cp_name[name - 1];
+}
+
+
static int lkdtm_parse_commandline(void)
{
int i;
- if (cpoint_name == NULL || cpoint_type == NULL ||
- cpoint_count < 1 || recur_count < 1)
+ if (cpoint_count < 1 || recur_count < 1)
return -EINVAL;
- for (i = 0; i < NUM_CPOINTS; ++i) {
+ count = cpoint_count;
+
+ /* No special parameters */
+ if (!cpoint_type && !cpoint_name)
+ return 0;
+
+ /* Neither or both of these need to be set */
+ if (!cpoint_type || !cpoint_name)
+ return -EINVAL;
+
+ cptype = parse_cp_type(cpoint_type, strlen(cpoint_type));
+ if (cptype == NONE)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(cp_name); i++) {
if (!strcmp(cpoint_name, cp_name[i])) {
cpoint = i + 1;
- break;
- }
- }
-
- for (i = 0; i < NUM_CPOINT_TYPES; ++i) {
- if (!strcmp(cpoint_type, cp_type[i])) {
- cptype = i + 1;
- break;
+ return 0;
}
}
- if (cpoint == INVALID || cptype == NONE)
- return -EINVAL;
-
- count = cpoint_count;
-
- return 0;
+ /* Could not find a valid crash point */
+ return -EINVAL;
}
static int recursive_loop(int a)
@@ -235,53 +264,92 @@ static int recursive_loop(int a)
return recursive_loop(a);
}
-void lkdtm_handler(void)
+static void lkdtm_do_action(enum ctype which)
{
- printk(KERN_INFO "lkdtm : Crash point %s of type %s hit\n",
- cpoint_name, cpoint_type);
- --count;
+ switch (which) {
+ case PANIC:
+ panic("dumptest");
+ break;
+ case BUG:
+ BUG();
+ break;
+ case EXCEPTION:
+ *((int *) 0) = 0;
+ break;
+ case LOOP:
+ for (;;)
+ ;
+ break;
+ case OVERFLOW:
+ (void) recursive_loop(0);
+ break;
+ case CORRUPT_STACK: {
+ volatile u32 data[8];
+ volatile u32 *p = data;
+
+ p[12] = 0x12345678;
+ break;
+ }
+ case UNALIGNED_LOAD_STORE_WRITE: {
+ static u8 data[5] __attribute__((aligned(4))) = {1, 2,
+ 3, 4, 5};
+ u32 *p;
+ u32 val = 0x12345678;
+
+ p = (u32 *)(data + 1);
+ if (*p == 0)
+ val = 0x87654321;
+ *p = val;
+ break;
+ }
+ case OVERWRITE_ALLOCATION: {
+ size_t len = 1020;
+ u32 *data = kmalloc(len, GFP_KERNEL);
+
+ data[1024 / sizeof(u32)] = 0x12345678;
+ kfree(data);
+ break;
+ }
+ case WRITE_AFTER_FREE: {
+ size_t len = 1024;
+ u32 *data = kmalloc(len, GFP_KERNEL);
+
+ kfree(data);
+ schedule();
+ memset(data, 0x78, len);
+ break;
+ }
+ case NONE:
+ default:
+ break;
+ }
+
+}
+
+static void lkdtm_handler(void)
+{
+ count--;
+ printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds\n",
+ cp_name_to_str(cpoint), cp_type_to_str(cptype), count);
if (count == 0) {
- switch (cptype) {
- case NONE:
- break;
- case PANIC:
- printk(KERN_INFO "lkdtm : PANIC\n");
- panic("dumptest");
- break;
- case BUG:
- printk(KERN_INFO "lkdtm : BUG\n");
- BUG();
- break;
- case EXCEPTION:
- printk(KERN_INFO "lkdtm : EXCEPTION\n");
- *((int *) 0) = 0;
- break;
- case LOOP:
- printk(KERN_INFO "lkdtm : LOOP\n");
- for (;;);
- break;
- case OVERFLOW:
- printk(KERN_INFO "lkdtm : OVERFLOW\n");
- (void) recursive_loop(0);
- break;
- default:
- break;
- }
+ lkdtm_do_action(cptype);
count = cpoint_count;
}
}
-static int __init lkdtm_module_init(void)
+static int lkdtm_register_cpoint(enum cname which)
{
int ret;
- if (lkdtm_parse_commandline() == -EINVAL) {
- printk(KERN_INFO "lkdtm : Invalid command\n");
- return -EINVAL;
- }
+ cpoint = INVALID;
+ if (lkdtm.entry != NULL)
+ unregister_jprobe(&lkdtm);
- switch (cpoint) {
+ switch (which) {
+ case DIRECT:
+ lkdtm_do_action(cptype);
+ return 0;
case INT_HARDWARE_ENTRY:
lkdtm.kp.symbol_name = "do_IRQ";
lkdtm.entry = (kprobe_opcode_t*) jp_do_irq;
@@ -315,28 +383,268 @@ static int __init lkdtm_module_init(void)
lkdtm.kp.symbol_name = "generic_ide_ioctl";
lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl;
#else
- printk(KERN_INFO "lkdtm : Crash point not available\n");
+ printk(KERN_INFO "lkdtm: Crash point not available\n");
+ return -EINVAL;
#endif
break;
default:
- printk(KERN_INFO "lkdtm : Invalid Crash Point\n");
- break;
+ printk(KERN_INFO "lkdtm: Invalid Crash Point\n");
+ return -EINVAL;
}
+ cpoint = which;
if ((ret = register_jprobe(&lkdtm)) < 0) {
- printk(KERN_INFO "lkdtm : Couldn't register jprobe\n");
- return ret;
+ printk(KERN_INFO "lkdtm: Couldn't register jprobe\n");
+ cpoint = INVALID;
+ }
+
+ return ret;
+}
+
+static ssize_t do_register_entry(enum cname which, struct file *f,
+ const char __user *user_buf, size_t count, loff_t *off)
+{
+ char *buf;
+ int err;
+
+ if (count >= PAGE_SIZE)
+ return -EINVAL;
+
+ buf = (char *)__get_free_page(GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ if (copy_from_user(buf, user_buf, count)) {
+ free_page((unsigned long) buf);
+ return -EFAULT;
+ }
+ /* NULL-terminate and remove enter */
+ buf[count] = '\0';
+ strim(buf);
+
+ cptype = parse_cp_type(buf, count);
+ free_page((unsigned long) buf);
+
+ if (cptype == NONE)
+ return -EINVAL;
+
+ err = lkdtm_register_cpoint(which);
+ if (err < 0)
+ return err;
+
+ *off += count;
+
+ return count;
+}
+
+/* Generic read callback that just prints out the available crash types */
+static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf,
+ size_t count, loff_t *off)
+{
+ char *buf;
+ int i, n, out;
+
+ buf = (char *)__get_free_page(GFP_KERNEL);
+
+ n = snprintf(buf, PAGE_SIZE, "Available crash types:\n");
+ for (i = 0; i < ARRAY_SIZE(cp_type); i++)
+ n += snprintf(buf + n, PAGE_SIZE - n, "%s\n", cp_type[i]);
+ buf[n] = '\0';
+
+ out = simple_read_from_buffer(user_buf, count, off,
+ buf, n);
+ free_page((unsigned long) buf);
+
+ return out;
+}
+
+static int lkdtm_debugfs_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+
+static ssize_t int_hardware_entry(struct file *f, const char __user *buf,
+ size_t count, loff_t *off)
+{
+ return do_register_entry(INT_HARDWARE_ENTRY, f, buf, count, off);
+}
+
+static ssize_t int_hw_irq_en(struct file *f, const char __user *buf,
+ size_t count, loff_t *off)
+{
+ return do_register_entry(INT_HW_IRQ_EN, f, buf, count, off);
+}
+
+static ssize_t int_tasklet_entry(struct file *f, const char __user *buf,
+ size_t count, loff_t *off)
+{
+ return do_register_entry(INT_TASKLET_ENTRY, f, buf, count, off);
+}
+
+static ssize_t fs_devrw_entry(struct file *f, const char __user *buf,
+ size_t count, loff_t *off)
+{
+ return do_register_entry(FS_DEVRW, f, buf, count, off);
+}
+
+static ssize_t mem_swapout_entry(struct file *f, const char __user *buf,
+ size_t count, loff_t *off)
+{
+ return do_register_entry(MEM_SWAPOUT, f, buf, count, off);
+}
+
+static ssize_t timeradd_entry(struct file *f, const char __user *buf,
+ size_t count, loff_t *off)
+{
+ return do_register_entry(TIMERADD, f, buf, count, off);
+}
+
+static ssize_t scsi_dispatch_cmd_entry(struct file *f,
+ const char __user *buf, size_t count, loff_t *off)
+{
+ return do_register_entry(SCSI_DISPATCH_CMD, f, buf, count, off);
+}
+
+static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf,
+ size_t count, loff_t *off)
+{
+ return do_register_entry(IDE_CORE_CP, f, buf, count, off);
+}
+
+/* Special entry to just crash directly. Available without KPROBEs */
+static ssize_t direct_entry(struct file *f, const char __user *user_buf,
+ size_t count, loff_t *off)
+{
+ enum ctype type;
+ char *buf;
+
+ if (count >= PAGE_SIZE)
+ return -EINVAL;
+ if (count < 1)
+ return -EINVAL;
+
+ buf = (char *)__get_free_page(GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ if (copy_from_user(buf, user_buf, count)) {
+ free_page((unsigned long) buf);
+ return -EFAULT;
+ }
+ /* NULL-terminate and remove enter */
+ buf[count] = '\0';
+ strim(buf);
+
+ type = parse_cp_type(buf, count);
+ free_page((unsigned long) buf);
+ if (type == NONE)
+ return -EINVAL;
+
+ printk(KERN_INFO "lkdtm: Performing direct entry %s\n",
+ cp_type_to_str(type));
+ lkdtm_do_action(type);
+ *off += count;
+
+ return count;
+}
+
+struct crash_entry {
+ const char *name;
+ const struct file_operations fops;
+};
+
+static const struct crash_entry crash_entries[] = {
+ {"DIRECT", {.read = lkdtm_debugfs_read,
+ .open = lkdtm_debugfs_open,
+ .write = direct_entry} },
+ {"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read,
+ .open = lkdtm_debugfs_open,
+ .write = int_hardware_entry} },
+ {"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read,
+ .open = lkdtm_debugfs_open,
+ .write = int_hw_irq_en} },
+ {"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read,
+ .open = lkdtm_debugfs_open,
+ .write = int_tasklet_entry} },
+ {"FS_DEVRW", {.read = lkdtm_debugfs_read,
+ .open = lkdtm_debugfs_open,
+ .write = fs_devrw_entry} },
+ {"MEM_SWAPOUT", {.read = lkdtm_debugfs_read,
+ .open = lkdtm_debugfs_open,
+ .write = mem_swapout_entry} },
+ {"TIMERADD", {.read = lkdtm_debugfs_read,
+ .open = lkdtm_debugfs_open,
+ .write = timeradd_entry} },
+ {"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read,
+ .open = lkdtm_debugfs_open,
+ .write = scsi_dispatch_cmd_entry} },
+ {"IDE_CORE_CP", {.read = lkdtm_debugfs_read,
+ .open = lkdtm_debugfs_open,
+ .write = ide_core_cp_entry} },
+};
+
+static struct dentry *lkdtm_debugfs_root;
+
+static int __init lkdtm_module_init(void)
+{
+ int ret = -EINVAL;
+ int n_debugfs_entries = 1; /* Assume only the direct entry */
+ int i;
+
+ /* Register debugfs interface */
+ lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL);
+ if (!lkdtm_debugfs_root) {
+ printk(KERN_ERR "lkdtm: creating root dir failed\n");
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_KPROBES
+ n_debugfs_entries = ARRAY_SIZE(crash_entries);
+#endif
+
+ for (i = 0; i < n_debugfs_entries; i++) {
+ const struct crash_entry *cur = &crash_entries[i];
+ struct dentry *de;
+
+ de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root,
+ NULL, &cur->fops);
+ if (de == NULL) {
+ printk(KERN_ERR "lkdtm: could not create %s\n",
+ cur->name);
+ goto out_err;
+ }
+ }
+
+ if (lkdtm_parse_commandline() == -EINVAL) {
+ printk(KERN_INFO "lkdtm: Invalid command\n");
+ goto out_err;
+ }
+
+ if (cpoint != INVALID && cptype != NONE) {
+ ret = lkdtm_register_cpoint(cpoint);
+ if (ret < 0) {
+ printk(KERN_INFO "lkdtm: Invalid crash point %d\n",
+ cpoint);
+ goto out_err;
+ }
+ printk(KERN_INFO "lkdtm: Crash point %s of type %s registered\n",
+ cpoint_name, cpoint_type);
+ } else {
+ printk(KERN_INFO "lkdtm: No crash points registered, enable through debugfs\n");
}
- printk(KERN_INFO "lkdtm : Crash point %s of type %s registered\n",
- cpoint_name, cpoint_type);
return 0;
+
+out_err:
+ debugfs_remove_recursive(lkdtm_debugfs_root);
+ return ret;
}
static void __exit lkdtm_module_exit(void)
{
- unregister_jprobe(&lkdtm);
- printk(KERN_INFO "lkdtm : Crash point unregistered\n");
+ debugfs_remove_recursive(lkdtm_debugfs_root);
+
+ unregister_jprobe(&lkdtm);
+ printk(KERN_INFO "lkdtm: Crash point unregistered\n");
}
module_init(lkdtm_module_init);
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
index 04c27266f567..779aa8ebe4cf 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -497,12 +497,7 @@ static struct pci_driver phantom_pci_driver = {
.resume = phantom_resume
};
-static ssize_t phantom_show_version(struct class *cls, char *buf)
-{
- return sprintf(buf, PHANTOM_VERSION "\n");
-}
-
-static CLASS_ATTR(version, 0444, phantom_show_version, NULL);
+static CLASS_ATTR_STRING(version, 0444, PHANTOM_VERSION);
static int __init phantom_init(void)
{
@@ -515,7 +510,7 @@ static int __init phantom_init(void)
printk(KERN_ERR "phantom: can't register phantom class\n");
goto err;
}
- retval = class_create_file(phantom_class, &class_attr_version);
+ retval = class_create_file(phantom_class, &class_attr_version.attr);
if (retval) {
printk(KERN_ERR "phantom: can't create sysfs version file\n");
goto err_class;
@@ -541,7 +536,7 @@ static int __init phantom_init(void)
err_unchr:
unregister_chrdev_region(dev, PHANTOM_MAX_MINORS);
err_attr:
- class_remove_file(phantom_class, &class_attr_version);
+ class_remove_file(phantom_class, &class_attr_version.attr);
err_class:
class_destroy(phantom_class);
err:
@@ -554,7 +549,7 @@ static void __exit phantom_exit(void)
unregister_chrdev_region(MKDEV(phantom_major, 0), PHANTOM_MAX_MINORS);
- class_remove_file(phantom_class, &class_attr_version);
+ class_remove_file(phantom_class, &class_attr_version.attr);
class_destroy(phantom_class);
pr_debug("phantom: module successfully removed\n");
diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h
index 02a77b8b8eef..7a8b9068ea03 100644
--- a/drivers/misc/sgi-gru/grutables.h
+++ b/drivers/misc/sgi-gru/grutables.h
@@ -516,8 +516,7 @@ struct gru_blade_state {
/* Scan all active GRUs in a GRU bitmap */
#define for_each_gru_in_bitmap(gid, map) \
- for ((gid) = find_first_bit((map), GRU_MAX_GRUS); (gid) < GRU_MAX_GRUS;\
- (gid)++, (gid) = find_next_bit((map), GRU_MAX_GRUS, (gid)))
+ for_each_set_bit((gid), (map), GRU_MAX_GRUS)
/* Scan all active GRUs on a specific blade */
#define for_each_gru_on_blade(gru, nid, i) \
@@ -536,23 +535,17 @@ struct gru_blade_state {
/* Scan each CBR whose bit is set in a TFM (or copy of) */
#define for_each_cbr_in_tfm(i, map) \
- for ((i) = find_first_bit(map, GRU_NUM_CBE); \
- (i) < GRU_NUM_CBE; \
- (i)++, (i) = find_next_bit(map, GRU_NUM_CBE, i))
+ for_each_set_bit((i), (map), GRU_NUM_CBE)
/* Scan each CBR in a CBR bitmap. Note: multiple CBRs in an allocation unit */
#define for_each_cbr_in_allocation_map(i, map, k) \
- for ((k) = find_first_bit(map, GRU_CBR_AU); (k) < GRU_CBR_AU; \
- (k) = find_next_bit(map, GRU_CBR_AU, (k) + 1)) \
+ for_each_set_bit((k), (map), GRU_CBR_AU) \
for ((i) = (k)*GRU_CBR_AU_SIZE; \
(i) < ((k) + 1) * GRU_CBR_AU_SIZE; (i)++)
/* Scan each DSR in a DSR bitmap. Note: multiple DSRs in an allocation unit */
#define for_each_dsr_in_allocation_map(i, map, k) \
- for ((k) = find_first_bit((const unsigned long *)map, GRU_DSR_AU);\
- (k) < GRU_DSR_AU; \
- (k) = find_next_bit((const unsigned long *)map, \
- GRU_DSR_AU, (k) + 1)) \
+ for_each_set_bit((k), (const unsigned long *)(map), GRU_DSR_AU) \
for ((i) = (k) * GRU_DSR_AU_CL; \
(i) < ((k) + 1) * GRU_DSR_AU_CL; (i)++)
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c
index 16f0abda1423..57b152f8d1b9 100644
--- a/drivers/misc/sgi-xp/xpnet.c
+++ b/drivers/misc/sgi-xp/xpnet.c
@@ -475,7 +475,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->data[0] == 0xff) {
/* we are being asked to broadcast to all partitions */
- for_each_bit(dest_partid, xpnet_broadcast_partitions,
+ for_each_set_bit(dest_partid, xpnet_broadcast_partitions,
xp_max_npartitions) {
xpnet_send(skb, queued_msg, start_addr, end_addr,
diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/misc/tsl2550.c
index a0702f36a72f..483ae5f7f68e 100644
--- a/drivers/i2c/chips/tsl2550.c
+++ b/drivers/misc/tsl2550.c
@@ -47,8 +47,8 @@ struct tsl2550_data {
struct i2c_client *client;
struct mutex update_lock;
- unsigned int power_state : 1;
- unsigned int operating_mode : 1;
+ unsigned int power_state:1;
+ unsigned int operating_mode:1;
};
/*
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index b9f1e84897cc..e7f8027165e6 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -74,6 +74,9 @@ static void mmc_test_prepare_mrq(struct mmc_test_card *test,
}
mrq->cmd->arg = dev_addr;
+ if (!mmc_card_blockaddr(test->card))
+ mrq->cmd->arg <<= 9;
+
mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC;
if (blocks == 1)
@@ -190,7 +193,7 @@ static int __mmc_test_prepare(struct mmc_test_card *test, int write)
}
for (i = 0;i < BUFFER_SIZE / 512;i++) {
- ret = mmc_test_buffer_transfer(test, test->buffer, i * 512, 512, 1);
+ ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
if (ret)
return ret;
}
@@ -219,7 +222,7 @@ static int mmc_test_cleanup(struct mmc_test_card *test)
memset(test->buffer, 0, 512);
for (i = 0;i < BUFFER_SIZE / 512;i++) {
- ret = mmc_test_buffer_transfer(test, test->buffer, i * 512, 512, 1);
+ ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
if (ret)
return ret;
}
@@ -426,7 +429,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
for (i = 0;i < sectors;i++) {
ret = mmc_test_buffer_transfer(test,
test->buffer + i * 512,
- dev_addr + i * 512, 512, 0);
+ dev_addr + i, 512, 0);
if (ret)
return ret;
}
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index c5a7a855f4b1..381fe032caa1 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -154,9 +154,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
if (mq->bounce_buf) {
blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
- blk_queue_max_sectors(mq->queue, bouncesz / 512);
- blk_queue_max_phys_segments(mq->queue, bouncesz / 512);
- blk_queue_max_hw_segments(mq->queue, bouncesz / 512);
+ blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
+ blk_queue_max_segments(mq->queue, bouncesz / 512);
blk_queue_max_segment_size(mq->queue, bouncesz);
mq->sg = kmalloc(sizeof(struct scatterlist),
@@ -180,10 +179,9 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
if (!mq->bounce_buf) {
blk_queue_bounce_limit(mq->queue, limit);
- blk_queue_max_sectors(mq->queue,
+ blk_queue_max_hw_sectors(mq->queue,
min(host->max_blk_count, host->max_req_size / 512));
- blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
- blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
+ blk_queue_max_segments(mq->queue, host->max_hw_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
mq->sg = kmalloc(sizeof(struct scatterlist) *
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index f53755533e7e..723e50894db9 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -37,6 +37,7 @@
#include <linux/gfp.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/kfifo.h>
#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
@@ -47,19 +48,9 @@
#define UART_NR 8 /* Number of UARTs this driver can handle */
-#define UART_XMIT_SIZE PAGE_SIZE
+#define FIFO_SIZE PAGE_SIZE
#define WAKEUP_CHARS 256
-#define circ_empty(circ) ((circ)->head == (circ)->tail)
-#define circ_clear(circ) ((circ)->head = (circ)->tail = 0)
-
-#define circ_chars_pending(circ) \
- (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE))
-
-#define circ_chars_free(circ) \
- (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))
-
-
struct uart_icount {
__u32 cts;
__u32 dsr;
@@ -82,7 +73,7 @@ struct sdio_uart_port {
struct mutex func_lock;
struct task_struct *in_sdio_uart_irq;
unsigned int regs_offset;
- struct circ_buf xmit;
+ struct kfifo xmit_fifo;
spinlock_t write_lock;
struct uart_icount icount;
unsigned int uartclk;
@@ -105,6 +96,8 @@ static int sdio_uart_add_port(struct sdio_uart_port *port)
kref_init(&port->kref);
mutex_init(&port->func_lock);
spin_lock_init(&port->write_lock);
+ if (kfifo_alloc(&port->xmit_fifo, FIFO_SIZE, GFP_KERNEL))
+ return -ENOMEM;
spin_lock(&sdio_uart_table_lock);
for (index = 0; index < UART_NR; index++) {
@@ -140,6 +133,7 @@ static void sdio_uart_port_destroy(struct kref *kref)
{
struct sdio_uart_port *port =
container_of(kref, struct sdio_uart_port, kref);
+ kfifo_free(&port->xmit_fifo);
kfree(port);
}
@@ -456,9 +450,11 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port,
static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
{
- struct circ_buf *xmit = &port->xmit;
+ struct kfifo *xmit = &port->xmit_fifo;
int count;
struct tty_struct *tty;
+ u8 iobuf[16];
+ int len;
if (port->x_char) {
sdio_out(port, UART_TX, port->x_char);
@@ -469,27 +465,25 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
tty = tty_port_tty_get(&port->port);
- if (tty == NULL || circ_empty(xmit) ||
+ if (tty == NULL || !kfifo_len(xmit) ||
tty->stopped || tty->hw_stopped) {
sdio_uart_stop_tx(port);
tty_kref_put(tty);
return;
}
- count = 16;
- do {
- sdio_out(port, UART_TX, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ len = kfifo_out_locked(xmit, iobuf, 16, &port->write_lock);
+ for (count = 0; count < len; count++) {
+ sdio_out(port, UART_TX, iobuf[count]);
port->icount.tx++;
- if (circ_empty(xmit))
- break;
- } while (--count > 0);
+ }
- if (circ_chars_pending(xmit) < WAKEUP_CHARS)
+ len = kfifo_len(xmit);
+ if (len < WAKEUP_CHARS) {
tty_wakeup(tty);
-
- if (circ_empty(xmit))
- sdio_uart_stop_tx(port);
+ if (len == 0)
+ sdio_uart_stop_tx(port);
+ }
tty_kref_put(tty);
}
@@ -581,7 +575,7 @@ static int uart_carrier_raised(struct tty_port *tport)
struct sdio_uart_port *port =
container_of(tport, struct sdio_uart_port, port);
unsigned int ret = sdio_uart_claim_func(port);
- if (ret) /* Missing hardware shoudn't block for carrier */
+ if (ret) /* Missing hardware shouldn't block for carrier */
return 1;
ret = sdio_uart_get_mctrl(port);
sdio_uart_release_func(port);
@@ -632,7 +626,6 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
{
struct sdio_uart_port *port =
container_of(tport, struct sdio_uart_port, port);
- unsigned long page;
int ret;
/*
@@ -641,22 +634,17 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
*/
set_bit(TTY_IO_ERROR, &tty->flags);
- /* Initialise and allocate the transmit buffer. */
- page = __get_free_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
- port->xmit.buf = (unsigned char *)page;
- circ_clear(&port->xmit);
+ kfifo_reset(&port->xmit_fifo);
ret = sdio_uart_claim_func(port);
if (ret)
- goto err1;
+ return ret;
ret = sdio_enable_func(port->func);
if (ret)
- goto err2;
+ goto err1;
ret = sdio_claim_irq(port->func, sdio_uart_irq);
if (ret)
- goto err3;
+ goto err2;
/*
* Clear the FIFO buffers and disable them.
@@ -700,12 +688,10 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
sdio_uart_release_func(port);
return 0;
-err3:
- sdio_disable_func(port->func);
err2:
- sdio_uart_release_func(port);
+ sdio_disable_func(port->func);
err1:
- free_page((unsigned long)port->xmit.buf);
+ sdio_uart_release_func(port);
return ret;
}
@@ -727,7 +713,7 @@ static void sdio_uart_shutdown(struct tty_port *tport)
ret = sdio_uart_claim_func(port);
if (ret)
- goto skip;
+ return;
sdio_uart_stop_rx(port);
@@ -749,10 +735,6 @@ static void sdio_uart_shutdown(struct tty_port *tport)
sdio_disable_func(port->func);
sdio_uart_release_func(port);
-
-skip:
- /* Free the transmit buffer page. */
- free_page((unsigned long)port->xmit.buf);
}
/**
@@ -822,27 +804,12 @@ static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf,
int count)
{
struct sdio_uart_port *port = tty->driver_data;
- struct circ_buf *circ = &port->xmit;
- int c, ret = 0;
+ int ret;
if (!port->func)
return -ENODEV;
- spin_lock(&port->write_lock);
- while (1) {
- c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
- if (count < c)
- c = count;
- if (c <= 0)
- break;
- memcpy(circ->buf + circ->head, buf, c);
- circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
- buf += c;
- count -= c;
- ret += c;
- }
- spin_unlock(&port->write_lock);
-
+ ret = kfifo_in_locked(&port->xmit_fifo, buf, count, &port->write_lock);
if (!(port->ier & UART_IER_THRI)) {
int err = sdio_uart_claim_func(port);
if (!err) {
@@ -859,13 +826,13 @@ static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf,
static int sdio_uart_write_room(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
- return port ? circ_chars_free(&port->xmit) : 0;
+ return FIFO_SIZE - kfifo_len(&port->xmit_fifo);
}
static int sdio_uart_chars_in_buffer(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
- return port ? circ_chars_pending(&port->xmit) : 0;
+ return kfifo_len(&port->xmit_fifo);
}
static void sdio_uart_send_xchar(struct tty_struct *tty, char ch)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 30acd5265821..3168ebd616b2 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1089,6 +1089,7 @@ void mmc_rescan(struct work_struct *work)
mmc_claim_host(host);
mmc_power_up(host);
+ sdio_reset(host);
mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail);
@@ -1151,6 +1152,9 @@ void mmc_stop_host(struct mmc_host *host)
cancel_delayed_work(&host->detect);
mmc_flush_scheduled_work();
+ /* clear pm flags now and let card drivers set them as needed */
+ host->pm_flags = 0;
+
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
if (host->bus_ops->remove)
@@ -1273,12 +1277,13 @@ int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_release_host(host);
+ host->pm_flags = 0;
err = 0;
}
}
mmc_bus_put(host);
- if (!err)
+ if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER))
mmc_power_off(host);
return err;
@@ -1296,8 +1301,10 @@ int mmc_resume_host(struct mmc_host *host)
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
- mmc_power_up(host);
- mmc_select_voltage(host, host->ocr);
+ if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
+ mmc_power_up(host);
+ mmc_select_voltage(host, host->ocr);
+ }
BUG_ON(!host->bus_ops->resume);
err = host->bus_ops->resume(host);
if (err) {
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 06b64085a355..2dd4cfe7ca17 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -188,6 +188,40 @@ static int sdio_disable_cd(struct mmc_card *card)
}
/*
+ * Devices that remain active during a system suspend are
+ * put back into 1-bit mode.
+ */
+static int sdio_disable_wide(struct mmc_card *card)
+{
+ int ret;
+ u8 ctrl;
+
+ if (!(card->host->caps & MMC_CAP_4_BIT_DATA))
+ return 0;
+
+ if (card->cccr.low_speed && !card->cccr.wide_bus)
+ return 0;
+
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
+ if (ret)
+ return ret;
+
+ if (!(ctrl & SDIO_BUS_WIDTH_4BIT))
+ return 0;
+
+ ctrl &= ~SDIO_BUS_WIDTH_4BIT;
+ ctrl |= SDIO_BUS_ASYNC_INT;
+
+ ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
+ if (ret)
+ return ret;
+
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_1);
+
+ return 0;
+}
+
+/*
* Test if the card supports high-speed mode and, if so, switch to it.
*/
static int sdio_enable_hs(struct mmc_card *card)
@@ -224,7 +258,7 @@ static int sdio_enable_hs(struct mmc_card *card)
* we're trying to reinitialise.
*/
static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
- struct mmc_card *oldcard)
+ struct mmc_card *oldcard, int powered_resume)
{
struct mmc_card *card;
int err;
@@ -235,9 +269,11 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
/*
* Inform the card of the voltage
*/
- err = mmc_send_io_op_cond(host, host->ocr, &ocr);
- if (err)
- goto err;
+ if (!powered_resume) {
+ err = mmc_send_io_op_cond(host, host->ocr, &ocr);
+ if (err)
+ goto err;
+ }
/*
* For SPI, enable CRC as appropriate.
@@ -262,7 +298,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
/*
* For native busses: set card RCA and quit open drain mode.
*/
- if (!mmc_host_is_spi(host)) {
+ if (!powered_resume && !mmc_host_is_spi(host)) {
err = mmc_send_relative_addr(host, &card->rca);
if (err)
goto remove;
@@ -273,7 +309,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
/*
* Select card, as all following commands rely on that.
*/
- if (!mmc_host_is_spi(host)) {
+ if (!powered_resume && !mmc_host_is_spi(host)) {
err = mmc_select_card(card);
if (err)
goto remove;
@@ -425,6 +461,12 @@ static int mmc_sdio_suspend(struct mmc_host *host)
}
}
+ if (!err && host->pm_flags & MMC_PM_KEEP_POWER) {
+ mmc_claim_host(host);
+ sdio_disable_wide(host->card);
+ mmc_release_host(host);
+ }
+
return err;
}
@@ -437,7 +479,13 @@ static int mmc_sdio_resume(struct mmc_host *host)
/* Basic card reinitialization. */
mmc_claim_host(host);
- err = mmc_sdio_init_card(host, host->ocr, host->card);
+ err = mmc_sdio_init_card(host, host->ocr, host->card,
+ (host->pm_flags & MMC_PM_KEEP_POWER));
+ if (!err)
+ /* We may have switched to 1-bit mode during suspend. */
+ err = sdio_enable_wide(host->card);
+ if (!err && host->sdio_irqs)
+ mmc_signal_sdio_irq(host);
mmc_release_host(host);
/*
@@ -507,7 +555,7 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
/*
* Detect and init the card.
*/
- err = mmc_sdio_init_card(host, host->ocr, NULL);
+ err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
if (err)
goto err;
card = host->card;
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
index f9aa8a7deffa..ff27c8c71355 100644
--- a/drivers/mmc/core/sdio_io.c
+++ b/drivers/mmc/core/sdio_io.c
@@ -189,7 +189,12 @@ static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
{
unsigned mval = min(func->card->host->max_seg_size,
func->card->host->max_blk_size);
- mval = min(mval, func->max_blksize);
+
+ if (mmc_blksz_for_byte_mode(func->card))
+ mval = min(mval, func->cur_blksize);
+ else
+ mval = min(mval, func->max_blksize);
+
return min(mval, 512u); /* maximum size for byte mode */
}
@@ -635,3 +640,52 @@ void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
*err_ret = ret;
}
EXPORT_SYMBOL_GPL(sdio_f0_writeb);
+
+/**
+ * sdio_get_host_pm_caps - get host power management capabilities
+ * @func: SDIO function attached to host
+ *
+ * Returns a capability bitmask corresponding to power management
+ * features supported by the host controller that the card function
+ * might rely upon during a system suspend. The host doesn't need
+ * to be claimed, nor the function active, for this information to be
+ * obtained.
+ */
+mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func)
+{
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ return func->card->host->pm_caps;
+}
+EXPORT_SYMBOL_GPL(sdio_get_host_pm_caps);
+
+/**
+ * sdio_set_host_pm_flags - set wanted host power management capabilities
+ * @func: SDIO function attached to host
+ *
+ * Set a capability bitmask corresponding to wanted host controller
+ * power management features for the upcoming suspend state.
+ * This must be called, if needed, each time the suspend method of
+ * the function driver is called, and must contain only bits that
+ * were returned by sdio_get_host_pm_caps().
+ * The host doesn't need to be claimed, nor the function active,
+ * for this information to be set.
+ */
+int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags)
+{
+ struct mmc_host *host;
+
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ host = func->card->host;
+
+ if (flags & ~host->pm_caps)
+ return -EINVAL;
+
+ /* function suspend methods are serialized, hence no lock needed */
+ host->pm_flags |= flags;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sdio_set_host_pm_flags);
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index 4eb7825fd1a7..dea36d9c22e6 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -67,13 +67,13 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
return err;
}
-int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
- unsigned addr, u8 in, u8* out)
+static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
+ unsigned addr, u8 in, u8 *out)
{
struct mmc_command cmd;
int err;
- BUG_ON(!card);
+ BUG_ON(!host);
BUG_ON(fn > 7);
/* sanity check */
@@ -90,11 +90,11 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
cmd.arg |= in;
cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ err = mmc_wait_for_cmd(host, &cmd, 0);
if (err)
return err;
- if (mmc_host_is_spi(card->host)) {
+ if (mmc_host_is_spi(host)) {
/* host driver already reported errors */
} else {
if (cmd.resp[0] & R5_ERROR)
@@ -106,7 +106,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
}
if (out) {
- if (mmc_host_is_spi(card->host))
+ if (mmc_host_is_spi(host))
*out = (cmd.resp[0] >> 8) & 0xFF;
else
*out = cmd.resp[0] & 0xFF;
@@ -115,6 +115,13 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
return 0;
}
+int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
+ unsigned addr, u8 in, u8 *out)
+{
+ BUG_ON(!card);
+ return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out);
+}
+
int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
{
@@ -182,3 +189,20 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
return 0;
}
+int sdio_reset(struct mmc_host *host)
+{
+ int ret;
+ u8 abort;
+
+ /* SDIO Simplified Specification V2.0, 4.4 Reset for SDIO */
+
+ ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort);
+ if (ret)
+ abort = 0x08;
+ else
+ abort |= 0x08;
+
+ ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL);
+ return ret;
+}
+
diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h
index e2e74b0d17d8..12a4d3ab174c 100644
--- a/drivers/mmc/core/sdio_ops.h
+++ b/drivers/mmc/core/sdio_ops.h
@@ -17,6 +17,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
unsigned addr, u8 in, u8* out);
int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
+int sdio_reset(struct mmc_host *host);
#endif
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index ce1d28884e29..2e13b94769fd 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -69,20 +69,16 @@ config MMC_SDHCI_PCI
If unsure, say N.
config MMC_RICOH_MMC
- tristate "Ricoh MMC Controller Disabler (EXPERIMENTAL)"
+ bool "Ricoh MMC Controller Disabler (EXPERIMENTAL)"
depends on MMC_SDHCI_PCI
help
- This selects the disabler for the Ricoh MMC Controller. This
+ This adds a pci quirk to disable Ricoh MMC Controller. This
proprietary controller is unnecessary because the SDHCI driver
supports MMC cards on the SD controller, but if it is not
disabled, it will steal the MMC cards away - rendering them
- useless. It is safe to select this driver even if you don't
+ useless. It is safe to select this even if you don't
have a Ricoh based card reader.
-
- To compile this driver as a module, choose M here:
- the module will be called ricoh_mmc.
-
If unsure, say Y.
config MMC_SDHCI_OF
@@ -193,6 +189,7 @@ config MMC_AU1X
choice
prompt "Atmel SD/MMC Driver"
+ depends on AVR32 || ARCH_AT91
default MMC_ATMELMCI if AVR32
help
Choose which driver to use for the Atmel MCI Silicon
@@ -368,7 +365,7 @@ config MMC_SDRICOH_CS
config MMC_TMIO
tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support"
- depends on MFD_TMIO || MFD_ASIC3 || SUPERH
+ depends on MFD_TMIO || MFD_ASIC3 || MFD_SH_MOBILE_SDHI
help
This provides support for the SD/MMC cell found in TC6393XB,
T7L66XB and also HTC ASIC3
@@ -399,7 +396,7 @@ config MMC_VIA_SDMMC
config SDH_BFIN
tristate "Blackfin Secure Digital Host support"
- depends on MMC && ((BF54x && !BF544) || (BF51x && !BF512))
+ depends on (BF54x && !BF544) || (BF51x && !BF512)
help
If you say yes here you will get support for the Blackfin on-chip
Secure Digital Host interface. This includes support for MMC and
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 3d253dd4240f..f4803977dfce 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -12,7 +12,6 @@ obj-$(CONFIG_MMC_IMX) += imxmmc.o
obj-$(CONFIG_MMC_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
-obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o
obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 63924e0c7ea9..91dc60cd032b 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -78,6 +78,17 @@
#define DRIVER_NAME "at91_mci"
+static inline int at91mci_is_mci1rev2xx(void)
+{
+ return ( cpu_is_at91sam9260()
+ || cpu_is_at91sam9263()
+ || cpu_is_at91cap9()
+ || cpu_is_at91sam9rl()
+ || cpu_is_at91sam9g10()
+ || cpu_is_at91sam9g20()
+ );
+}
+
#define FL_SENT_COMMAND (1 << 0)
#define FL_SENT_STOP (1 << 1)
@@ -88,6 +99,10 @@
#define at91_mci_read(host, reg) __raw_readl((host)->baseaddr + (reg))
#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg))
+#define MCI_BLKSIZE 512
+#define MCI_MAXBLKSIZE 4095
+#define MCI_BLKATONCE 256
+#define MCI_BUFSIZE (MCI_BLKSIZE * MCI_BLKATONCE)
/*
* Low level type for this driver
@@ -200,8 +215,8 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
size = data->blksz * data->blocks;
len = data->sg_len;
- /* AT91SAM926[0/3] Data Write Operation and number of bytes erratum */
- if (cpu_is_at91sam9260() || cpu_is_at91sam9263())
+ /* MCI1 rev2xx Data Write Operation and number of bytes erratum */
+ if (at91mci_is_mci1rev2xx())
if (host->total_length == 12)
memset(dmabuf, 0, 12);
@@ -227,8 +242,10 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
for (index = 0; index < (amount / 4); index++)
*dmabuf++ = swab32(sgbuffer[index]);
} else {
- memcpy(dmabuf, sgbuffer, amount);
- dmabuf += amount;
+ char *tmpv = (char *)dmabuf;
+ memcpy(tmpv, sgbuffer, amount);
+ tmpv += amount;
+ dmabuf = (unsigned *)tmpv;
}
kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
@@ -245,80 +262,14 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
}
/*
- * Prepare a dma read
- */
-static void at91_mci_pre_dma_read(struct at91mci_host *host)
-{
- int i;
- struct scatterlist *sg;
- struct mmc_command *cmd;
- struct mmc_data *data;
-
- pr_debug("pre dma read\n");
-
- cmd = host->cmd;
- if (!cmd) {
- pr_debug("no command\n");
- return;
- }
-
- data = cmd->data;
- if (!data) {
- pr_debug("no data\n");
- return;
- }
-
- for (i = 0; i < 2; i++) {
- /* nothing left to transfer */
- if (host->transfer_index >= data->sg_len) {
- pr_debug("Nothing left to transfer (index = %d)\n", host->transfer_index);
- break;
- }
-
- /* Check to see if this needs filling */
- if (i == 0) {
- if (at91_mci_read(host, ATMEL_PDC_RCR) != 0) {
- pr_debug("Transfer active in current\n");
- continue;
- }
- }
- else {
- if (at91_mci_read(host, ATMEL_PDC_RNCR) != 0) {
- pr_debug("Transfer active in next\n");
- continue;
- }
- }
-
- /* Setup the next transfer */
- pr_debug("Using transfer index %d\n", host->transfer_index);
-
- sg = &data->sg[host->transfer_index++];
- pr_debug("sg = %p\n", sg);
-
- sg->dma_address = dma_map_page(NULL, sg_page(sg), sg->offset, sg->length, DMA_FROM_DEVICE);
-
- pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
-
- if (i == 0) {
- at91_mci_write(host, ATMEL_PDC_RPR, sg->dma_address);
- at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ? sg->length : sg->length / 4);
- }
- else {
- at91_mci_write(host, ATMEL_PDC_RNPR, sg->dma_address);
- at91_mci_write(host, ATMEL_PDC_RNCR, (data->blksz & 0x3) ? sg->length : sg->length / 4);
- }
- }
-
- pr_debug("pre dma read done\n");
-}
-
-/*
* Handle after a dma read
*/
static void at91_mci_post_dma_read(struct at91mci_host *host)
{
struct mmc_command *cmd;
struct mmc_data *data;
+ unsigned int len, i, size;
+ unsigned *dmabuf = host->buffer;
pr_debug("post dma read\n");
@@ -334,42 +285,39 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
return;
}
- while (host->in_use_index < host->transfer_index) {
- struct scatterlist *sg;
+ size = data->blksz * data->blocks;
+ len = data->sg_len;
- pr_debug("finishing index %d\n", host->in_use_index);
+ at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX);
+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
- sg = &data->sg[host->in_use_index++];
+ for (i = 0; i < len; i++) {
+ struct scatterlist *sg;
+ int amount;
+ unsigned int *sgbuffer;
- pr_debug("Unmapping page %08X\n", sg->dma_address);
+ sg = &data->sg[i];
- dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE);
+ sgbuffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
+ amount = min(size, sg->length);
+ size -= amount;
if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
- unsigned int *buffer;
int index;
-
- /* Swap the contents of the buffer */
- buffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
- pr_debug("buffer = %p, length = %d\n", buffer, sg->length);
-
- for (index = 0; index < (sg->length / 4); index++)
- buffer[index] = swab32(buffer[index]);
-
- kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
+ for (index = 0; index < (amount / 4); index++)
+ sgbuffer[index] = swab32(*dmabuf++);
+ } else {
+ char *tmpv = (char *)dmabuf;
+ memcpy(sgbuffer, tmpv, amount);
+ tmpv += amount;
+ dmabuf = (unsigned *)tmpv;
}
- flush_dcache_page(sg_page(sg));
-
- data->bytes_xfered += sg->length;
- }
-
- /* Is there another transfer to trigger? */
- if (host->transfer_index < data->sg_len)
- at91_mci_pre_dma_read(host);
- else {
- at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX);
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
+ kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
+ dmac_flush_range((void *)sgbuffer, ((void *)sgbuffer) + amount);
+ data->bytes_xfered += amount;
+ if (size == 0)
+ break;
}
pr_debug("post dma read done\n");
@@ -461,7 +409,7 @@ static void at91_mci_enable(struct at91mci_host *host)
at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
mr = AT91_MCI_PDCMODE | 0x34a;
- if (cpu_is_at91sam9260() || cpu_is_at91sam9263())
+ if (at91mci_is_mci1rev2xx())
mr |= AT91_MCI_RDPROOF | AT91_MCI_WRPROOF;
at91_mci_write(host, AT91_MCI_MR, mr);
@@ -602,10 +550,14 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command
/*
* Handle a read
*/
- host->buffer = NULL;
host->total_length = 0;
- at91_mci_pre_dma_read(host);
+ at91_mci_write(host, ATMEL_PDC_RPR, host->physical_address);
+ at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ?
+ (blocks * block_length) : (blocks * block_length) / 4);
+ at91_mci_write(host, ATMEL_PDC_RNPR, 0);
+ at91_mci_write(host, ATMEL_PDC_RNCR, 0);
+
ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;
}
else {
@@ -614,27 +566,15 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command
*/
host->total_length = block_length * blocks;
/*
- * AT91SAM926[0/3] Data Write Operation and
+ * MCI1 rev2xx Data Write Operation and
* number of bytes erratum
*/
- if (cpu_is_at91sam9260 () || cpu_is_at91sam9263())
+ if (at91mci_is_mci1rev2xx())
if (host->total_length < 12)
host->total_length = 12;
- host->buffer = kmalloc(host->total_length, GFP_KERNEL);
- if (!host->buffer) {
- pr_debug("Can't alloc tx buffer\n");
- cmd->error = -ENOMEM;
- mmc_request_done(host->mmc, host->request);
- return;
- }
-
at91_mci_sg_to_dma(host, data);
- host->physical_address = dma_map_single(NULL,
- host->buffer, host->total_length,
- DMA_TO_DEVICE);
-
pr_debug("Transmitting %d bytes\n", host->total_length);
at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
@@ -701,14 +641,6 @@ static void at91_mci_completed_command(struct at91mci_host *host, unsigned int s
cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));
cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
- if (host->buffer) {
- dma_unmap_single(NULL,
- host->physical_address, host->total_length,
- DMA_TO_DEVICE);
- kfree(host->buffer);
- host->buffer = NULL;
- }
-
pr_debug("Status = %08X/%08x [%08X %08X %08X %08X]\n",
status, at91_mci_read(host, AT91_MCI_SR),
cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
@@ -754,7 +686,8 @@ static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->request = mrq;
host->flags = 0;
- mod_timer(&host->timer, jiffies + HZ);
+ /* more than 1s timeout needed with slow SD cards */
+ mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000));
at91_mci_process_next(host);
}
@@ -942,7 +875,8 @@ static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
pr_debug("****** Resetting SD-card bus width ******\n");
at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
}
- mmc_detect_change(host->mmc, msecs_to_jiffies(100));
+ /* 0.5s needed because of early card detect switch firing */
+ mmc_detect_change(host->mmc, msecs_to_jiffies(500));
}
return IRQ_HANDLED;
}
@@ -1006,24 +940,42 @@ static int __init at91_mci_probe(struct platform_device *pdev)
mmc->f_min = 375000;
mmc->f_max = 25000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = MMC_CAP_SDIO_IRQ;
+ mmc->caps = 0;
- mmc->max_blk_size = 4095;
- mmc->max_blk_count = mmc->max_req_size;
+ mmc->max_blk_size = MCI_MAXBLKSIZE;
+ mmc->max_blk_count = MCI_BLKATONCE;
+ mmc->max_req_size = MCI_BUFSIZE;
+ mmc->max_phys_segs = MCI_BLKATONCE;
+ mmc->max_hw_segs = MCI_BLKATONCE;
+ mmc->max_seg_size = MCI_BUFSIZE;
host = mmc_priv(mmc);
host->mmc = mmc;
- host->buffer = NULL;
host->bus_mode = 0;
host->board = pdev->dev.platform_data;
if (host->board->wire4) {
- if (cpu_is_at91sam9260() || cpu_is_at91sam9263())
+ if (at91mci_is_mci1rev2xx())
mmc->caps |= MMC_CAP_4_BIT_DATA;
else
dev_warn(&pdev->dev, "4 wire bus mode not supported"
" - using 1 wire\n");
}
+ host->buffer = dma_alloc_coherent(&pdev->dev, MCI_BUFSIZE,
+ &host->physical_address, GFP_KERNEL);
+ if (!host->buffer) {
+ ret = -ENOMEM;
+ dev_err(&pdev->dev, "Can't allocate transmit buffer\n");
+ goto fail5;
+ }
+
+ /* Add SDIO capability when available */
+ if (at91mci_is_mci1rev2xx()) {
+ /* at91mci MCI1 rev2xx sdio interrupt erratum */
+ if (host->board->wire4 || !host->board->slot_b)
+ mmc->caps |= MMC_CAP_SDIO_IRQ;
+ }
+
/*
* Reserve GPIOs ... board init code makes sure these pins are set
* up as GPIOs with the right direction (input, except for vcc)
@@ -1032,7 +984,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
ret = gpio_request(host->board->det_pin, "mmc_detect");
if (ret < 0) {
dev_dbg(&pdev->dev, "couldn't claim card detect pin\n");
- goto fail5;
+ goto fail4b;
}
}
if (host->board->wp_pin) {
@@ -1132,6 +1084,10 @@ fail3:
fail4:
if (host->board->det_pin)
gpio_free(host->board->det_pin);
+fail4b:
+ if (host->buffer)
+ dma_free_coherent(&pdev->dev, MCI_BUFSIZE,
+ host->buffer, host->physical_address);
fail5:
mmc_free_host(mmc);
fail6:
@@ -1154,6 +1110,10 @@ static int __exit at91_mci_remove(struct platform_device *pdev)
host = mmc_priv(mmc);
+ if (host->buffer)
+ dma_free_coherent(&pdev->dev, MCI_BUFSIZE,
+ host->buffer, host->physical_address);
+
if (host->board->det_pin) {
if (device_can_wakeup(&pdev->dev))
free_irq(gpio_to_irq(host->board->det_pin), host);
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index d3f55615c099..57b21198828f 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -650,11 +650,11 @@ static int au1xmmc_prepare_data(struct au1xmmc_host *host,
flags = DDMA_FLAGS_IE;
if (host->flags & HOST_F_XMIT) {
- ret = au1xxx_dbdma_put_source_flags(channel,
- (void *)sg_virt(sg), len, flags);
+ ret = au1xxx_dbdma_put_source(channel,
+ sg_phys(sg), len, flags);
} else {
- ret = au1xxx_dbdma_put_dest_flags(channel,
- (void *)sg_virt(sg), len, flags);
+ ret = au1xxx_dbdma_put_dest(channel,
+ sg_phys(sg), len, flags);
}
if (!ret)
@@ -1017,6 +1017,10 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
} else
mmc->caps |= MMC_CAP_NEEDS_POLL;
+ /* platform may not be able to use all advertised caps */
+ if (host->platdata)
+ mmc->caps &= ~(host->platdata->mask_host_caps);
+
tasklet_init(&host->data_task, au1xmmc_tasklet_data,
(unsigned long)host);
diff --git a/drivers/mmc/host/bfin_sdh.c b/drivers/mmc/host/bfin_sdh.c
index 3343a57355cc..56f7b448b911 100644
--- a/drivers/mmc/host/bfin_sdh.c
+++ b/drivers/mmc/host/bfin_sdh.c
@@ -115,7 +115,7 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
unsigned int length;
unsigned int data_ctl;
unsigned int dma_cfg;
- struct scatterlist *sg;
+ unsigned int cycle_ns, timeout;
dev_dbg(mmc_dev(host->mmc), "%s enter flags: 0x%x\n", __func__, data->flags);
host->data = data;
@@ -136,8 +136,11 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
data_ctl |= ((ffs(data->blksz) - 1) << 4);
bfin_write_SDH_DATA_CTL(data_ctl);
-
- bfin_write_SDH_DATA_TIMER(0xFFFF);
+ /* the time of a host clock period in ns */
+ cycle_ns = 1000000000 / (get_sclk() / (2 * (host->clk_div + 1)));
+ timeout = data->timeout_ns / cycle_ns;
+ timeout += data->timeout_clks;
+ bfin_write_SDH_DATA_TIMER(timeout);
SSYNC();
if (data->flags & MMC_DATA_READ) {
@@ -151,6 +154,7 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
#if defined(CONFIG_BF54x)
dma_cfg |= DMAFLOW_ARRAY | NDSIZE_5 | RESTART | WDSIZE_32 | DMAEN;
{
+ struct scatterlist *sg;
int i;
for_each_sg(data->sg, sg, host->dma_len, i) {
host->sg_cpu[i].start_addr = sg_dma_address(sg);
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index dd45e7c3517e..3bd0ba294e9d 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -73,6 +73,7 @@
/* DAVINCI_MMCCTL definitions */
#define MMCCTL_DATRST (1 << 0)
#define MMCCTL_CMDRST (1 << 1)
+#define MMCCTL_WIDTH_8_BIT (1 << 8)
#define MMCCTL_WIDTH_4_BIT (1 << 2)
#define MMCCTL_DATEG_DISABLED (0 << 6)
#define MMCCTL_DATEG_RISING (1 << 6)
@@ -791,22 +792,42 @@ static void calculate_clk_divider(struct mmc_host *mmc, struct mmc_ios *ios)
static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
- unsigned int mmc_pclk = 0;
struct mmc_davinci_host *host = mmc_priv(mmc);
- mmc_pclk = host->mmc_input_clk;
dev_dbg(mmc_dev(host->mmc),
"clock %dHz busmode %d powermode %d Vdd %04x\n",
ios->clock, ios->bus_mode, ios->power_mode,
ios->vdd);
- if (ios->bus_width == MMC_BUS_WIDTH_4) {
- dev_dbg(mmc_dev(host->mmc), "Enabling 4 bit mode\n");
- writel(readl(host->base + DAVINCI_MMCCTL) | MMCCTL_WIDTH_4_BIT,
- host->base + DAVINCI_MMCCTL);
- } else {
- dev_dbg(mmc_dev(host->mmc), "Disabling 4 bit mode\n");
- writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_WIDTH_4_BIT,
+
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_8:
+ dev_dbg(mmc_dev(host->mmc), "Enabling 8 bit mode\n");
+ writel((readl(host->base + DAVINCI_MMCCTL) &
+ ~MMCCTL_WIDTH_4_BIT) | MMCCTL_WIDTH_8_BIT,
host->base + DAVINCI_MMCCTL);
+ break;
+ case MMC_BUS_WIDTH_4:
+ dev_dbg(mmc_dev(host->mmc), "Enabling 4 bit mode\n");
+ if (host->version == MMC_CTLR_VERSION_2)
+ writel((readl(host->base + DAVINCI_MMCCTL) &
+ ~MMCCTL_WIDTH_8_BIT) | MMCCTL_WIDTH_4_BIT,
+ host->base + DAVINCI_MMCCTL);
+ else
+ writel(readl(host->base + DAVINCI_MMCCTL) |
+ MMCCTL_WIDTH_4_BIT,
+ host->base + DAVINCI_MMCCTL);
+ break;
+ case MMC_BUS_WIDTH_1:
+ dev_dbg(mmc_dev(host->mmc), "Enabling 1 bit mode\n");
+ if (host->version == MMC_CTLR_VERSION_2)
+ writel(readl(host->base + DAVINCI_MMCCTL) &
+ ~(MMCCTL_WIDTH_8_BIT | MMCCTL_WIDTH_4_BIT),
+ host->base + DAVINCI_MMCCTL);
+ else
+ writel(readl(host->base + DAVINCI_MMCCTL) &
+ ~MMCCTL_WIDTH_4_BIT,
+ host->base + DAVINCI_MMCCTL);
+ break;
}
calculate_clk_divider(mmc, ios);
@@ -1189,10 +1210,14 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
/* REVISIT: someday, support IRQ-driven card detection. */
mmc->caps |= MMC_CAP_NEEDS_POLL;
+ mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
- if (!pdata || pdata->wires == 4 || pdata->wires == 0)
+ if (pdata && (pdata->wires == 4 || pdata->wires == 0))
mmc->caps |= MMC_CAP_4_BIT_DATA;
+ if (pdata && (pdata->wires == 8))
+ mmc->caps |= (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA);
+
host->version = pdata->version;
mmc->ops = &mmc_davinci_ops;
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 90d168ad03b6..84c103a7ee13 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -2,6 +2,7 @@
* linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver
*
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
+ * Copyright (C) 2010 ST-Ericsson AB.
*
* 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
@@ -34,9 +35,6 @@
#define DRIVER_NAME "mmci-pl18x"
-#define DBG(host,fmt,args...) \
- pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
-
static unsigned int fmax = 515633;
/*
@@ -105,8 +103,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
void __iomem *base;
int blksz_bits;
- DBG(host, "blksz %04x blks %04x flags %08x\n",
- data->blksz, data->blocks, data->flags);
+ dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n",
+ data->blksz, data->blocks, data->flags);
host->data = data;
host->size = data->blksz;
@@ -155,7 +153,7 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
{
void __iomem *base = host->base;
- DBG(host, "op %02x arg %08x flags %08x\n",
+ dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n",
cmd->opcode, cmd->arg, cmd->flags);
if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
@@ -184,8 +182,20 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
{
if (status & MCI_DATABLOCKEND) {
host->data_xfered += data->blksz;
+#ifdef CONFIG_ARCH_U300
+ /*
+ * On the U300 some signal or other is
+ * badly routed so that a data write does
+ * not properly terminate with a MCI_DATAEND
+ * status flag. This quirk will make writes
+ * work again.
+ */
+ if (data->flags & MMC_DATA_WRITE)
+ status |= MCI_DATAEND;
+#endif
}
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
+ dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status);
if (status & MCI_DATACRCFAIL)
data->error = -EILSEQ;
else if (status & MCI_DATATIMEOUT)
@@ -307,7 +317,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
status = readl(base + MMCISTATUS);
- DBG(host, "irq1 %08x\n", status);
+ dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status);
do {
unsigned long flags;
@@ -401,7 +411,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
status &= readl(host->base + MMCIMASK0);
writel(status, host->base + MMCICLEAR);
- DBG(host, "irq0 %08x\n", status);
+ dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status);
data = host->data;
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
@@ -428,8 +438,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
WARN_ON(host->mrq != NULL);
if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
- printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n",
- mmc_hostname(mmc), mrq->data->blksz);
+ dev_err(mmc_dev(mmc), "unsupported block size (%d bytes)\n",
+ mrq->data->blksz);
mrq->cmd->error = -EINVAL;
mmc_request_done(mmc, mrq);
return;
@@ -582,8 +592,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
host->hw_designer = amba_manf(dev);
host->hw_revision = amba_rev(dev);
- DBG(host, "designer ID = 0x%02x\n", host->hw_designer);
- DBG(host, "revision = 0x%01x\n", host->hw_revision);
+ dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer);
+ dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision);
host->clk = clk_get(&dev->dev, NULL);
if (IS_ERR(host->clk)) {
@@ -608,7 +618,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
if (ret < 0)
goto clk_disable;
host->mclk = clk_get_rate(host->clk);
- DBG(host, "eventual mclk rate: %u Hz\n", host->mclk);
+ dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n",
+ host->mclk);
}
host->base = ioremap(dev->res.start, resource_size(&dev->res));
if (!host->base) {
@@ -619,6 +630,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
mmc->ops = &mmci_ops;
mmc->f_min = (host->mclk + 511) / 512;
mmc->f_max = min(host->mclk, fmax);
+ dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
+
#ifdef CONFIG_REGULATOR
/* If we're using the regulator framework, try to fetch a regulator */
host->vcc = regulator_get(&dev->dev, "vmmc");
@@ -712,7 +725,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
mmc_add_host(mmc);
- printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
+ dev_info(&dev->dev, "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
(unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index b31946e0b4ca..4c068e5fe6b2 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1250,9 +1250,7 @@ msmsdcc_resume(struct platform_device *dev)
if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
mmc_resume_host(mmc);
- if (host->stat_irq)
- enable_irq(host->stat_irq);
- else if (host->stat_irq)
+ if (host->stat_irq)
enable_irq(host->stat_irq);
}
return 0;
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 60a2b69e54f5..2df90412abb5 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -4,7 +4,7 @@
* This is a driver for the SDHC controller found in Freescale MX2/MX3
* SoCs. It is basically the same hardware as found on MX1 (imxmmc.c).
* Unlike the hardware found on MX1, this hardware just works and does
- * not need all the quirks found in imxmmc.c, hence the seperate driver.
+ * not need all the quirks found in imxmmc.c, hence the separate driver.
*
* Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
* Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
@@ -708,7 +708,7 @@ static int mxcmci_probe(struct platform_device *pdev)
mmc->max_blk_size = 2048;
mmc->max_blk_count = 65535;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
- mmc->max_seg_size = mmc->max_seg_size;
+ mmc->max_seg_size = mmc->max_req_size;
host = mmc_priv(mmc);
host->base = ioremap(r->start, resource_size(r));
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 4b2322518909..83f0affadcae 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -30,6 +30,8 @@
#include <linux/mmc/core.h>
#include <linux/io.h>
#include <linux/semaphore.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
#include <plat/dma.h>
#include <mach/hardware.h>
#include <plat/board.h>
@@ -146,6 +148,15 @@ struct omap_hsmmc_host {
struct clk *fclk;
struct clk *iclk;
struct clk *dbclk;
+ /*
+ * vcc == configured supply
+ * vcc_aux == optional
+ * - MMC1, supply for DAT4..DAT7
+ * - MMC2/MMC2, external level shifter voltage supply, for
+ * chip (SDIO, eMMC, etc) or transceiver (MMC2 only)
+ */
+ struct regulator *vcc;
+ struct regulator *vcc_aux;
struct semaphore sem;
struct work_struct mmc_carddetect_work;
void __iomem *base;
@@ -171,10 +182,337 @@ struct omap_hsmmc_host {
int vdd;
int protect_card;
int reqs_blocked;
+ int use_reg;
struct omap_mmc_platform_data *pdata;
};
+static int omap_hsmmc_card_detect(struct device *dev, int slot)
+{
+ struct omap_mmc_platform_data *mmc = dev->platform_data;
+
+ /* NOTE: assumes card detect signal is active-low */
+ return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
+}
+
+static int omap_hsmmc_get_wp(struct device *dev, int slot)
+{
+ struct omap_mmc_platform_data *mmc = dev->platform_data;
+
+ /* NOTE: assumes write protect signal is active-high */
+ return gpio_get_value_cansleep(mmc->slots[0].gpio_wp);
+}
+
+static int omap_hsmmc_get_cover_state(struct device *dev, int slot)
+{
+ struct omap_mmc_platform_data *mmc = dev->platform_data;
+
+ /* NOTE: assumes card detect signal is active-low */
+ return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
+}
+
+#ifdef CONFIG_PM
+
+static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot)
+{
+ struct omap_mmc_platform_data *mmc = dev->platform_data;
+
+ disable_irq(mmc->slots[0].card_detect_irq);
+ return 0;
+}
+
+static int omap_hsmmc_resume_cdirq(struct device *dev, int slot)
+{
+ struct omap_mmc_platform_data *mmc = dev->platform_data;
+
+ enable_irq(mmc->slots[0].card_detect_irq);
+ return 0;
+}
+
+#else
+
+#define omap_hsmmc_suspend_cdirq NULL
+#define omap_hsmmc_resume_cdirq NULL
+
+#endif
+
+#ifdef CONFIG_REGULATOR
+
+static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
+ int vdd)
+{
+ struct omap_hsmmc_host *host =
+ platform_get_drvdata(to_platform_device(dev));
+ int ret;
+
+ if (mmc_slot(host).before_set_reg)
+ mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
+
+ if (power_on)
+ ret = mmc_regulator_set_ocr(host->vcc, vdd);
+ else
+ ret = mmc_regulator_set_ocr(host->vcc, 0);
+
+ if (mmc_slot(host).after_set_reg)
+ mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
+
+ return ret;
+}
+
+static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on,
+ int vdd)
+{
+ struct omap_hsmmc_host *host =
+ platform_get_drvdata(to_platform_device(dev));
+ int ret = 0;
+
+ /*
+ * If we don't see a Vcc regulator, assume it's a fixed
+ * voltage always-on regulator.
+ */
+ if (!host->vcc)
+ return 0;
+
+ if (mmc_slot(host).before_set_reg)
+ mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
+
+ /*
+ * Assume Vcc regulator is used only to power the card ... OMAP
+ * VDDS is used to power the pins, optionally with a transceiver to
+ * support cards using voltages other than VDDS (1.8V nominal). When a
+ * transceiver is used, DAT3..7 are muxed as transceiver control pins.
+ *
+ * In some cases this regulator won't support enable/disable;
+ * e.g. it's a fixed rail for a WLAN chip.
+ *
+ * In other cases vcc_aux switches interface power. Example, for
+ * eMMC cards it represents VccQ. Sometimes transceivers or SDIO
+ * chips/cards need an interface voltage rail too.
+ */
+ if (power_on) {
+ ret = mmc_regulator_set_ocr(host->vcc, vdd);
+ /* Enable interface voltage rail, if needed */
+ if (ret == 0 && host->vcc_aux) {
+ ret = regulator_enable(host->vcc_aux);
+ if (ret < 0)
+ ret = mmc_regulator_set_ocr(host->vcc, 0);
+ }
+ } else {
+ if (host->vcc_aux)
+ ret = regulator_disable(host->vcc_aux);
+ if (ret == 0)
+ ret = mmc_regulator_set_ocr(host->vcc, 0);
+ }
+
+ if (mmc_slot(host).after_set_reg)
+ mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
+
+ return ret;
+}
+
+static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep,
+ int vdd, int cardsleep)
+{
+ struct omap_hsmmc_host *host =
+ platform_get_drvdata(to_platform_device(dev));
+ int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
+
+ return regulator_set_mode(host->vcc, mode);
+}
+
+static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep,
+ int vdd, int cardsleep)
+{
+ struct omap_hsmmc_host *host =
+ platform_get_drvdata(to_platform_device(dev));
+ int err, mode;
+
+ /*
+ * If we don't see a Vcc regulator, assume it's a fixed
+ * voltage always-on regulator.
+ */
+ if (!host->vcc)
+ return 0;
+
+ mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
+
+ if (!host->vcc_aux)
+ return regulator_set_mode(host->vcc, mode);
+
+ if (cardsleep) {
+ /* VCC can be turned off if card is asleep */
+ if (sleep)
+ err = mmc_regulator_set_ocr(host->vcc, 0);
+ else
+ err = mmc_regulator_set_ocr(host->vcc, vdd);
+ } else
+ err = regulator_set_mode(host->vcc, mode);
+ if (err)
+ return err;
+
+ if (!mmc_slot(host).vcc_aux_disable_is_sleep)
+ return regulator_set_mode(host->vcc_aux, mode);
+
+ if (sleep)
+ return regulator_disable(host->vcc_aux);
+ else
+ return regulator_enable(host->vcc_aux);
+}
+
+static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
+{
+ struct regulator *reg;
+ int ret = 0;
+
+ switch (host->id) {
+ case OMAP_MMC1_DEVID:
+ /* On-chip level shifting via PBIAS0/PBIAS1 */
+ mmc_slot(host).set_power = omap_hsmmc_1_set_power;
+ mmc_slot(host).set_sleep = omap_hsmmc_1_set_sleep;
+ break;
+ case OMAP_MMC2_DEVID:
+ case OMAP_MMC3_DEVID:
+ /* Off-chip level shifting, or none */
+ mmc_slot(host).set_power = omap_hsmmc_23_set_power;
+ mmc_slot(host).set_sleep = omap_hsmmc_23_set_sleep;
+ break;
+ default:
+ pr_err("MMC%d configuration not supported!\n", host->id);
+ return -EINVAL;
+ }
+
+ reg = regulator_get(host->dev, "vmmc");
+ if (IS_ERR(reg)) {
+ dev_dbg(host->dev, "vmmc regulator missing\n");
+ /*
+ * HACK: until fixed.c regulator is usable,
+ * we don't require a main regulator
+ * for MMC2 or MMC3
+ */
+ if (host->id == OMAP_MMC1_DEVID) {
+ ret = PTR_ERR(reg);
+ goto err;
+ }
+ } else {
+ host->vcc = reg;
+ mmc_slot(host).ocr_mask = mmc_regulator_get_ocrmask(reg);
+
+ /* Allow an aux regulator */
+ reg = regulator_get(host->dev, "vmmc_aux");
+ host->vcc_aux = IS_ERR(reg) ? NULL : reg;
+
+ /*
+ * UGLY HACK: workaround regulator framework bugs.
+ * When the bootloader leaves a supply active, it's
+ * initialized with zero usecount ... and we can't
+ * disable it without first enabling it. Until the
+ * framework is fixed, we need a workaround like this
+ * (which is safe for MMC, but not in general).
+ */
+ if (regulator_is_enabled(host->vcc) > 0) {
+ regulator_enable(host->vcc);
+ regulator_disable(host->vcc);
+ }
+ if (host->vcc_aux) {
+ if (regulator_is_enabled(reg) > 0) {
+ regulator_enable(reg);
+ regulator_disable(reg);
+ }
+ }
+ }
+
+ return 0;
+
+err:
+ mmc_slot(host).set_power = NULL;
+ mmc_slot(host).set_sleep = NULL;
+ return ret;
+}
+
+static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
+{
+ regulator_put(host->vcc);
+ regulator_put(host->vcc_aux);
+ mmc_slot(host).set_power = NULL;
+ mmc_slot(host).set_sleep = NULL;
+}
+
+static inline int omap_hsmmc_have_reg(void)
+{
+ return 1;
+}
+
+#else
+
+static inline int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
+{
+ return -EINVAL;
+}
+
+static inline void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
+{
+}
+
+static inline int omap_hsmmc_have_reg(void)
+{
+ return 0;
+}
+
+#endif
+
+static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)
+{
+ int ret;
+
+ if (gpio_is_valid(pdata->slots[0].switch_pin)) {
+ pdata->suspend = omap_hsmmc_suspend_cdirq;
+ pdata->resume = omap_hsmmc_resume_cdirq;
+ if (pdata->slots[0].cover)
+ pdata->slots[0].get_cover_state =
+ omap_hsmmc_get_cover_state;
+ else
+ pdata->slots[0].card_detect = omap_hsmmc_card_detect;
+ pdata->slots[0].card_detect_irq =
+ gpio_to_irq(pdata->slots[0].switch_pin);
+ ret = gpio_request(pdata->slots[0].switch_pin, "mmc_cd");
+ if (ret)
+ return ret;
+ ret = gpio_direction_input(pdata->slots[0].switch_pin);
+ if (ret)
+ goto err_free_sp;
+ } else
+ pdata->slots[0].switch_pin = -EINVAL;
+
+ if (gpio_is_valid(pdata->slots[0].gpio_wp)) {
+ pdata->slots[0].get_ro = omap_hsmmc_get_wp;
+ ret = gpio_request(pdata->slots[0].gpio_wp, "mmc_wp");
+ if (ret)
+ goto err_free_cd;
+ ret = gpio_direction_input(pdata->slots[0].gpio_wp);
+ if (ret)
+ goto err_free_wp;
+ } else
+ pdata->slots[0].gpio_wp = -EINVAL;
+
+ return 0;
+
+err_free_wp:
+ gpio_free(pdata->slots[0].gpio_wp);
+err_free_cd:
+ if (gpio_is_valid(pdata->slots[0].switch_pin))
+err_free_sp:
+ gpio_free(pdata->slots[0].switch_pin);
+ return ret;
+}
+
+static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata)
+{
+ if (gpio_is_valid(pdata->slots[0].gpio_wp))
+ gpio_free(pdata->slots[0].gpio_wp);
+ if (gpio_is_valid(pdata->slots[0].switch_pin))
+ gpio_free(pdata->slots[0].switch_pin);
+}
+
/*
* Stop clock to the card
*/
@@ -835,7 +1173,7 @@ static void omap_hsmmc_detect(struct work_struct *work)
sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
if (slot->card_detect)
- carddetect = slot->card_detect(slot->card_detect_irq);
+ carddetect = slot->card_detect(host->dev, host->slot_id);
else {
omap_hsmmc_protect_card(host);
carddetect = -ENOSYS;
@@ -1242,7 +1580,7 @@ static int omap_hsmmc_get_cd(struct mmc_host *mmc)
if (!mmc_slot(host).card_detect)
return -ENOSYS;
- return mmc_slot(host).card_detect(mmc_slot(host).card_detect_irq);
+ return mmc_slot(host).card_detect(host->dev, host->slot_id);
}
static int omap_hsmmc_get_ro(struct mmc_host *mmc)
@@ -1311,7 +1649,7 @@ static int omap_hsmmc_enabled_to_disabled(struct omap_hsmmc_host *host)
if (host->power_mode == MMC_POWER_OFF)
return 0;
- return msecs_to_jiffies(OMAP_MMC_SLEEP_TIMEOUT);
+ return OMAP_MMC_SLEEP_TIMEOUT;
}
/* Handler for [DISABLED -> REGSLEEP / CARDSLEEP] transition */
@@ -1347,11 +1685,14 @@ static int omap_hsmmc_disabled_to_sleep(struct omap_hsmmc_host *host)
dev_dbg(mmc_dev(host->mmc), "DISABLED -> %s\n",
host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP");
+ if (mmc_slot(host).no_off)
+ return 0;
+
if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
mmc_slot(host).card_detect ||
(mmc_slot(host).get_cover_state &&
mmc_slot(host).get_cover_state(host->dev, host->slot_id)))
- return msecs_to_jiffies(OMAP_MMC_OFF_TIMEOUT);
+ return OMAP_MMC_OFF_TIMEOUT;
return 0;
}
@@ -1362,6 +1703,9 @@ static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host)
if (!mmc_try_claim_host(host->mmc))
return 0;
+ if (mmc_slot(host).no_off)
+ return 0;
+
if (!((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
mmc_slot(host).card_detect ||
(mmc_slot(host).get_cover_state &&
@@ -1616,7 +1960,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
struct mmc_host *mmc;
struct omap_hsmmc_host *host = NULL;
struct resource *res;
- int ret = 0, irq;
+ int ret, irq;
if (pdata == NULL) {
dev_err(&pdev->dev, "Platform Data is missing\n");
@@ -1638,10 +1982,14 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
if (res == NULL)
return -EBUSY;
+ ret = omap_hsmmc_gpio_init(pdata);
+ if (ret)
+ goto err;
+
mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev);
if (!mmc) {
ret = -ENOMEM;
- goto err;
+ goto err_alloc;
}
host = mmc_priv(mmc);
@@ -1656,7 +2004,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
host->slot_id = 0;
host->mapbase = res->start;
host->base = ioremap(host->mapbase, SZ_4K);
- host->power_mode = -1;
+ host->power_mode = MMC_POWER_OFF;
platform_set_drvdata(pdev, host);
INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect);
@@ -1666,6 +2014,13 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
else
mmc->ops = &omap_hsmmc_ops;
+ /*
+ * If regulator_disable can only put vcc_aux to sleep then there is
+ * no off state.
+ */
+ if (mmc_slot(host).vcc_aux_disable_is_sleep)
+ mmc_slot(host).no_off = 1;
+
mmc->f_min = 400000;
mmc->f_max = 52000000;
@@ -1781,7 +2136,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
goto err_irq;
}
- /* initialize power supplies, gpios, etc */
if (pdata->init != NULL) {
if (pdata->init(&pdev->dev) != 0) {
dev_dbg(mmc_dev(host->mmc),
@@ -1789,6 +2143,14 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
goto err_irq_cd_init;
}
}
+
+ if (omap_hsmmc_have_reg() && !mmc_slot(host).set_power) {
+ ret = omap_hsmmc_reg_get(host);
+ if (ret)
+ goto err_reg;
+ host->use_reg = 1;
+ }
+
mmc->ocr_avail = mmc_slot(host).ocr_mask;
/* Request IRQ for card detect */
@@ -1823,19 +2185,22 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
ret = device_create_file(&mmc->class_dev,
&dev_attr_cover_switch);
if (ret < 0)
- goto err_cover_switch;
+ goto err_slot_name;
}
omap_hsmmc_debugfs(mmc);
return 0;
-err_cover_switch:
- device_remove_file(&mmc->class_dev, &dev_attr_cover_switch);
err_slot_name:
mmc_remove_host(mmc);
-err_irq_cd:
free_irq(mmc_slot(host).card_detect_irq, host);
+err_irq_cd:
+ if (host->use_reg)
+ omap_hsmmc_reg_put(host);
+err_reg:
+ if (host->pdata->cleanup)
+ host->pdata->cleanup(&pdev->dev);
err_irq_cd_init:
free_irq(host->irq, host);
err_irq:
@@ -1847,14 +2212,14 @@ err_irq:
clk_disable(host->dbclk);
clk_put(host->dbclk);
}
-
err1:
iounmap(host->base);
+ platform_set_drvdata(pdev, NULL);
+ mmc_free_host(mmc);
+err_alloc:
+ omap_hsmmc_gpio_free(pdata);
err:
- dev_dbg(mmc_dev(host->mmc), "Probe Failed\n");
release_mem_region(res->start, res->end - res->start + 1);
- if (host)
- mmc_free_host(mmc);
return ret;
}
@@ -1866,6 +2231,8 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
if (host) {
mmc_host_enable(host->mmc);
mmc_remove_host(host->mmc);
+ if (host->use_reg)
+ omap_hsmmc_reg_put(host);
if (host->pdata->cleanup)
host->pdata->cleanup(&pdev->dev);
free_irq(host->irq, host);
@@ -1884,6 +2251,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
mmc_free_host(host->mmc);
iounmap(host->base);
+ omap_hsmmc_gpio_free(pdev->dev.platform_data);
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/mmc/host/ricoh_mmc.c b/drivers/mmc/host/ricoh_mmc.c
deleted file mode 100644
index f62790513322..000000000000
--- a/drivers/mmc/host/ricoh_mmc.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * ricoh_mmc.c - Dummy driver to disable the Rioch MMC controller.
- *
- * Copyright (C) 2007 Philip Langdale, 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 is a conceptually ridiculous driver, but it is required by the way
- * the Ricoh multi-function chips (R5CXXX) work. These chips implement
- * the four main memory card controllers (SD, MMC, MS, xD) and one or both
- * of cardbus or firewire. It happens that they implement SD and MMC
- * support as separate controllers (and PCI functions). The linux SDHCI
- * driver supports MMC cards but the chip detects MMC cards in hardware
- * and directs them to the MMC controller - so the SDHCI driver never sees
- * them. To get around this, we must disable the useless MMC controller.
- * At that point, the SDHCI controller will start seeing them. As a bonus,
- * a detection event occurs immediately, even if the MMC card is already
- * in the reader.
- *
- * It seems to be the case that the relevant PCI registers to deactivate the
- * MMC controller live on PCI function 0, which might be the cardbus controller
- * or the firewire controller, depending on the particular chip in question. As
- * such, it makes what this driver has to do unavoidably ugly. Such is life.
- */
-
-#include <linux/pci.h>
-
-#define DRIVER_NAME "ricoh-mmc"
-
-static const struct pci_device_id pci_ids[] __devinitdata = {
- {
- .vendor = PCI_VENDOR_ID_RICOH,
- .device = PCI_DEVICE_ID_RICOH_R5C843,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { /* end: all zeroes */ },
-};
-
-MODULE_DEVICE_TABLE(pci, pci_ids);
-
-static int ricoh_mmc_disable(struct pci_dev *fw_dev)
-{
- u8 write_enable;
- u8 write_target;
- u8 disable;
-
- if (fw_dev->device == PCI_DEVICE_ID_RICOH_RL5C476) {
- /* via RL5C476 */
-
- pci_read_config_byte(fw_dev, 0xB7, &disable);
- if (disable & 0x02) {
- printk(KERN_INFO DRIVER_NAME
- ": Controller already disabled. " \
- "Nothing to do.\n");
- return -ENODEV;
- }
-
- pci_read_config_byte(fw_dev, 0x8E, &write_enable);
- pci_write_config_byte(fw_dev, 0x8E, 0xAA);
- pci_read_config_byte(fw_dev, 0x8D, &write_target);
- pci_write_config_byte(fw_dev, 0x8D, 0xB7);
- pci_write_config_byte(fw_dev, 0xB7, disable | 0x02);
- pci_write_config_byte(fw_dev, 0x8E, write_enable);
- pci_write_config_byte(fw_dev, 0x8D, write_target);
- } else {
- /* via R5C832 */
-
- pci_read_config_byte(fw_dev, 0xCB, &disable);
- if (disable & 0x02) {
- printk(KERN_INFO DRIVER_NAME
- ": Controller already disabled. " \
- "Nothing to do.\n");
- return -ENODEV;
- }
-
- pci_read_config_byte(fw_dev, 0xCA, &write_enable);
- pci_write_config_byte(fw_dev, 0xCA, 0x57);
- pci_write_config_byte(fw_dev, 0xCB, disable | 0x02);
- pci_write_config_byte(fw_dev, 0xCA, write_enable);
- }
-
- printk(KERN_INFO DRIVER_NAME
- ": Controller is now disabled.\n");
-
- return 0;
-}
-
-static int ricoh_mmc_enable(struct pci_dev *fw_dev)
-{
- u8 write_enable;
- u8 write_target;
- u8 disable;
-
- if (fw_dev->device == PCI_DEVICE_ID_RICOH_RL5C476) {
- /* via RL5C476 */
-
- pci_read_config_byte(fw_dev, 0x8E, &write_enable);
- pci_write_config_byte(fw_dev, 0x8E, 0xAA);
- pci_read_config_byte(fw_dev, 0x8D, &write_target);
- pci_write_config_byte(fw_dev, 0x8D, 0xB7);
- pci_read_config_byte(fw_dev, 0xB7, &disable);
- pci_write_config_byte(fw_dev, 0xB7, disable & ~0x02);
- pci_write_config_byte(fw_dev, 0x8E, write_enable);
- pci_write_config_byte(fw_dev, 0x8D, write_target);
- } else {
- /* via R5C832 */
-
- pci_read_config_byte(fw_dev, 0xCA, &write_enable);
- pci_read_config_byte(fw_dev, 0xCB, &disable);
- pci_write_config_byte(fw_dev, 0xCA, 0x57);
- pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02);
- pci_write_config_byte(fw_dev, 0xCA, write_enable);
- }
-
- printk(KERN_INFO DRIVER_NAME
- ": Controller is now re-enabled.\n");
-
- return 0;
-}
-
-static int __devinit ricoh_mmc_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- u8 rev;
- u8 ctrlfound = 0;
-
- struct pci_dev *fw_dev = NULL;
-
- BUG_ON(pdev == NULL);
- BUG_ON(ent == NULL);
-
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
-
- printk(KERN_INFO DRIVER_NAME
- ": Ricoh MMC controller found at %s [%04x:%04x] (rev %x)\n",
- pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
- (int)rev);
-
- while ((fw_dev =
- pci_get_device(PCI_VENDOR_ID_RICOH,
- PCI_DEVICE_ID_RICOH_RL5C476, fw_dev))) {
- if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) &&
- PCI_FUNC(fw_dev->devfn) == 0 &&
- pdev->bus == fw_dev->bus) {
- if (ricoh_mmc_disable(fw_dev) != 0)
- return -ENODEV;
-
- pci_set_drvdata(pdev, fw_dev);
-
- ++ctrlfound;
- break;
- }
- }
-
- fw_dev = NULL;
-
- while (!ctrlfound &&
- (fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH,
- PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) {
- if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) &&
- PCI_FUNC(fw_dev->devfn) == 0 &&
- pdev->bus == fw_dev->bus) {
- if (ricoh_mmc_disable(fw_dev) != 0)
- return -ENODEV;
-
- pci_set_drvdata(pdev, fw_dev);
-
- ++ctrlfound;
- }
- }
-
- if (!ctrlfound) {
- printk(KERN_WARNING DRIVER_NAME
- ": Main Ricoh function not found. Cannot disable controller.\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void __devexit ricoh_mmc_remove(struct pci_dev *pdev)
-{
- struct pci_dev *fw_dev = NULL;
-
- fw_dev = pci_get_drvdata(pdev);
- BUG_ON(fw_dev == NULL);
-
- ricoh_mmc_enable(fw_dev);
-
- pci_set_drvdata(pdev, NULL);
-}
-
-static int ricoh_mmc_suspend_late(struct pci_dev *pdev, pm_message_t state)
-{
- struct pci_dev *fw_dev = NULL;
-
- fw_dev = pci_get_drvdata(pdev);
- BUG_ON(fw_dev == NULL);
-
- printk(KERN_INFO DRIVER_NAME ": Suspending.\n");
-
- ricoh_mmc_enable(fw_dev);
-
- return 0;
-}
-
-static int ricoh_mmc_resume_early(struct pci_dev *pdev)
-{
- struct pci_dev *fw_dev = NULL;
-
- fw_dev = pci_get_drvdata(pdev);
- BUG_ON(fw_dev == NULL);
-
- printk(KERN_INFO DRIVER_NAME ": Resuming.\n");
-
- ricoh_mmc_disable(fw_dev);
-
- return 0;
-}
-
-static struct pci_driver ricoh_mmc_driver = {
- .name = DRIVER_NAME,
- .id_table = pci_ids,
- .probe = ricoh_mmc_probe,
- .remove = __devexit_p(ricoh_mmc_remove),
- .suspend_late = ricoh_mmc_suspend_late,
- .resume_early = ricoh_mmc_resume_early,
-};
-
-/*****************************************************************************\
- * *
- * Driver init/exit *
- * *
-\*****************************************************************************/
-
-static int __init ricoh_mmc_drv_init(void)
-{
- printk(KERN_INFO DRIVER_NAME
- ": Ricoh MMC Controller disabling driver\n");
- printk(KERN_INFO DRIVER_NAME ": Copyright(c) Philip Langdale\n");
-
- return pci_register_driver(&ricoh_mmc_driver);
-}
-
-static void __exit ricoh_mmc_drv_exit(void)
-{
- pci_unregister_driver(&ricoh_mmc_driver);
-}
-
-module_init(ricoh_mmc_drv_init);
-module_exit(ricoh_mmc_drv_exit);
-
-MODULE_AUTHOR("Philip Langdale <philipl@alumni.utexas.net>");
-MODULE_DESCRIPTION("Ricoh MMC Controller disabling driver");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index d96e1abf2d64..2fdf7689ae6c 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -1179,7 +1179,7 @@ static int s3cmci_card_present(struct mmc_host *mmc)
struct s3c24xx_mci_pdata *pdata = host->pdata;
int ret;
- if (pdata->gpio_detect == 0)
+ if (pdata->no_detect)
return -ENOSYS;
ret = gpio_get_value(pdata->gpio_detect) ? 0 : 1;
@@ -1360,6 +1360,8 @@ static struct mmc_host_ops s3cmci_ops = {
static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
/* This is currently here to avoid a number of if (host->pdata)
* checks. Any zero fields to ensure reasonable defaults are picked. */
+ .no_wprotect = 1,
+ .no_detect = 1,
};
#ifdef CONFIG_CPU_FREQ
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 5c3a1767770a..8e1020cf73f4 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -80,9 +80,6 @@ struct sdhci_pci_chip {
static int ricoh_probe(struct sdhci_pci_chip *chip)
{
- if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM)
- chip->quirks |= SDHCI_QUIRK_CLOCK_BEFORE_RESET;
-
if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG ||
chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY)
chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET;
@@ -92,7 +89,9 @@ static int ricoh_probe(struct sdhci_pci_chip *chip)
static const struct sdhci_pci_fixes sdhci_ricoh = {
.probe = ricoh_probe,
- .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR,
+ .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
+ SDHCI_QUIRK_FORCE_DMA |
+ SDHCI_QUIRK_CLOCK_BEFORE_RESET,
};
static const struct sdhci_pci_fixes sdhci_ene_712 = {
@@ -501,6 +500,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
{
struct sdhci_pci_chip *chip;
struct sdhci_pci_slot *slot;
+ mmc_pm_flag_t pm_flags = 0;
int i, ret;
chip = pci_get_drvdata(pdev);
@@ -519,6 +519,8 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
sdhci_resume_host(chip->slots[i]->host);
return ret;
}
+
+ pm_flags |= slot->host->mmc->pm_flags;
}
if (chip->fixes && chip->fixes->suspend) {
@@ -531,9 +533,15 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
}
pci_save_state(pdev);
- pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ if (pm_flags & MMC_PM_KEEP_POWER) {
+ if (pm_flags & MMC_PM_WAKE_SDIO_IRQ)
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_set_power_state(pdev, PCI_D3hot);
+ } else {
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ }
return 0;
}
@@ -653,6 +661,8 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
goto unmap;
}
+ host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
+
ret = sdhci_add_host(host);
if (ret)
goto remove;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c279fbc4c2e5..d6ab62d539fb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -174,20 +174,31 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
}
-static void sdhci_init(struct sdhci_host *host)
+static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
+
+static void sdhci_init(struct sdhci_host *host, int soft)
{
- sdhci_reset(host, SDHCI_RESET_ALL);
+ if (soft)
+ sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
+ else
+ sdhci_reset(host, SDHCI_RESET_ALL);
sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
+
+ if (soft) {
+ /* force clock reconfiguration */
+ host->clock = 0;
+ sdhci_set_ios(host->mmc, &host->mmc->ios);
+ }
}
static void sdhci_reinit(struct sdhci_host *host)
{
- sdhci_init(host);
+ sdhci_init(host, 0);
sdhci_enable_card_detection(host);
}
@@ -376,6 +387,20 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
local_irq_restore(*flags);
}
+static void sdhci_set_adma_desc(u8 *desc, u32 addr, int len, unsigned cmd)
+{
+ __le32 *dataddr = (__le32 __force *)(desc + 4);
+ __le16 *cmdlen = (__le16 __force *)desc;
+
+ /* SDHCI specification says ADMA descriptors should be 4 byte
+ * aligned, so using 16 or 32bit operations should be safe. */
+
+ cmdlen[0] = cpu_to_le16(cmd);
+ cmdlen[1] = cpu_to_le16(len);
+
+ dataddr[0] = cpu_to_le32(addr);
+}
+
static int sdhci_adma_table_pre(struct sdhci_host *host,
struct mmc_data *data)
{
@@ -443,19 +468,11 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
sdhci_kunmap_atomic(buffer, &flags);
}
- desc[7] = (align_addr >> 24) & 0xff;
- desc[6] = (align_addr >> 16) & 0xff;
- desc[5] = (align_addr >> 8) & 0xff;
- desc[4] = (align_addr >> 0) & 0xff;
+ /* tran, valid */
+ sdhci_set_adma_desc(desc, align_addr, offset, 0x21);
BUG_ON(offset > 65536);
- desc[3] = (offset >> 8) & 0xff;
- desc[2] = (offset >> 0) & 0xff;
-
- desc[1] = 0x00;
- desc[0] = 0x21; /* tran, valid */
-
align += 4;
align_addr += 4;
@@ -465,19 +482,10 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
len -= offset;
}
- desc[7] = (addr >> 24) & 0xff;
- desc[6] = (addr >> 16) & 0xff;
- desc[5] = (addr >> 8) & 0xff;
- desc[4] = (addr >> 0) & 0xff;
-
BUG_ON(len > 65536);
- desc[3] = (len >> 8) & 0xff;
- desc[2] = (len >> 0) & 0xff;
-
- desc[1] = 0x00;
- desc[0] = 0x21; /* tran, valid */
-
+ /* tran, valid */
+ sdhci_set_adma_desc(desc, addr, len, 0x21);
desc += 8;
/*
@@ -490,16 +498,9 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
/*
* Add a terminating entry.
*/
- desc[7] = 0;
- desc[6] = 0;
- desc[5] = 0;
- desc[4] = 0;
- desc[3] = 0;
- desc[2] = 0;
-
- desc[1] = 0x00;
- desc[0] = 0x03; /* nop, end, valid */
+ /* nop, end, valid */
+ sdhci_set_adma_desc(desc, 0, 0, 0x3);
/*
* Resync align buffer as we might have changed it.
@@ -1610,16 +1611,13 @@ int sdhci_resume_host(struct sdhci_host *host)
if (ret)
return ret;
- sdhci_init(host);
+ sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
mmiowb();
ret = mmc_resume_host(host->mmc);
- if (ret)
- return ret;
-
sdhci_enable_card_detection(host);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(sdhci_resume_host);
@@ -1874,7 +1872,7 @@ int sdhci_add_host(struct sdhci_host *host)
if (ret)
goto untasklet;
- sdhci_init(host);
+ sdhci_init(host, 0);
#ifdef CONFIG_MMC_DEBUG
sdhci_dumpregs(host);
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index 7cccc8523747..b2b577f6afd4 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -46,7 +46,9 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
clk |= 0x100;
}
- sd_config_write8(host, CNF_SD_CLK_MODE, clk >> 22);
+ if (host->set_clk_div)
+ host->set_clk_div(host->pdev, (clk>>22) & 1);
+
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff);
}
@@ -321,7 +323,7 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid)
if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) {
ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT |
TMIO_STAT_CARD_REMOVE);
- mmc_detect_change(host->mmc, 0);
+ mmc_detect_change(host->mmc, msecs_to_jiffies(100));
}
/* CRC and other errors */
@@ -427,12 +429,13 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/* Power sequence - OFF -> ON -> UP */
switch (ios->power_mode) {
case MMC_POWER_OFF: /* power down SD bus */
- sd_config_write8(host, CNF_PWR_CTL_2, 0x00);
+ if (host->set_pwr)
+ host->set_pwr(host->pdev, 0);
tmio_mmc_clk_stop(host);
break;
case MMC_POWER_ON: /* power up SD bus */
-
- sd_config_write8(host, CNF_PWR_CTL_2, 0x02);
+ if (host->set_pwr)
+ host->set_pwr(host->pdev, 1);
break;
case MMC_POWER_UP: /* start bus clock */
tmio_mmc_clk_start(host);
@@ -485,21 +488,15 @@ static int tmio_mmc_resume(struct platform_device *dev)
{
struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
struct mmc_host *mmc = platform_get_drvdata(dev);
- struct tmio_mmc_host *host = mmc_priv(mmc);
int ret = 0;
/* Tell the MFD core we are ready to be enabled */
- if (cell->enable) {
- ret = cell->enable(dev);
+ if (cell->resume) {
+ ret = cell->resume(dev);
if (ret)
goto out;
}
- /* Enable the MMC/SD Control registers */
- sd_config_write16(host, CNF_CMD, SDCREN);
- sd_config_write32(host, CNF_CTL_BASE,
- (dev->resource[0].start >> host->bus_shift) & 0xfffe);
-
mmc_resume_host(mmc);
out:
@@ -514,17 +511,16 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
{
struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
struct tmio_mmc_data *pdata;
- struct resource *res_ctl, *res_cnf;
+ struct resource *res_ctl;
struct tmio_mmc_host *host;
struct mmc_host *mmc;
int ret = -EINVAL;
- if (dev->num_resources != 3)
+ if (dev->num_resources != 2)
goto out;
res_ctl = platform_get_resource(dev, IORESOURCE_MEM, 0);
- res_cnf = platform_get_resource(dev, IORESOURCE_MEM, 1);
- if (!res_ctl || !res_cnf)
+ if (!res_ctl)
goto out;
pdata = cell->driver_data;
@@ -539,8 +535,12 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
host = mmc_priv(mmc);
host->mmc = mmc;
+ host->pdev = dev;
platform_set_drvdata(dev, mmc);
+ host->set_pwr = pdata->set_pwr;
+ host->set_clk_div = pdata->set_clk_div;
+
/* SD control register space size is 0x200, 0x400 for bus_shift=1 */
host->bus_shift = resource_size(res_ctl) >> 10;
@@ -548,12 +548,9 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
if (!host->ctl)
goto host_free;
- host->cnf = ioremap(res_cnf->start, resource_size(res_cnf));
- if (!host->cnf)
- goto unmap_ctl;
-
mmc->ops = &tmio_mmc_ops;
mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->caps |= pdata->capabilities;
mmc->f_max = pdata->hclk;
mmc->f_min = mmc->f_max / 512;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
@@ -562,23 +559,9 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
if (cell->enable) {
ret = cell->enable(dev);
if (ret)
- goto unmap_cnf;
+ goto unmap_ctl;
}
- /* Enable the MMC/SD Control registers */
- sd_config_write16(host, CNF_CMD, SDCREN);
- sd_config_write32(host, CNF_CTL_BASE,
- (dev->resource[0].start >> host->bus_shift) & 0xfffe);
-
- /* Disable SD power during suspend */
- sd_config_write8(host, CNF_PWR_CTL_3, 0x01);
-
- /* The below is required but why? FIXME */
- sd_config_write8(host, CNF_STOP_CLK_CTL, 0x1f);
-
- /* Power down SD bus*/
- sd_config_write8(host, CNF_PWR_CTL_2, 0x00);
-
tmio_mmc_clk_stop(host);
reset(host);
@@ -586,14 +569,14 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
if (ret >= 0)
host->irq = ret;
else
- goto unmap_cnf;
+ goto cell_disable;
disable_mmc_irqs(host, TMIO_MASK_ALL);
ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED |
IRQF_TRIGGER_FALLING, dev_name(&dev->dev), host);
if (ret)
- goto unmap_cnf;
+ goto cell_disable;
mmc_add_host(mmc);
@@ -605,8 +588,9 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
return 0;
-unmap_cnf:
- iounmap(host->cnf);
+cell_disable:
+ if (cell->disable)
+ cell->disable(dev);
unmap_ctl:
iounmap(host->ctl);
host_free:
@@ -617,6 +601,7 @@ out:
static int __devexit tmio_mmc_remove(struct platform_device *dev)
{
+ struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
struct mmc_host *mmc = platform_get_drvdata(dev);
platform_set_drvdata(dev, NULL);
@@ -625,8 +610,9 @@ static int __devexit tmio_mmc_remove(struct platform_device *dev)
struct tmio_mmc_host *host = mmc_priv(mmc);
mmc_remove_host(mmc);
free_irq(host->irq, host);
+ if (cell->disable)
+ cell->disable(dev);
iounmap(host->ctl);
- iounmap(host->cnf);
mmc_free_host(mmc);
}
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 9fa998594974..dafecfbcd91a 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -11,26 +11,6 @@
#include <linux/highmem.h>
-#define CNF_CMD 0x04
-#define CNF_CTL_BASE 0x10
-#define CNF_INT_PIN 0x3d
-#define CNF_STOP_CLK_CTL 0x40
-#define CNF_GCLK_CTL 0x41
-#define CNF_SD_CLK_MODE 0x42
-#define CNF_PIN_STATUS 0x44
-#define CNF_PWR_CTL_1 0x48
-#define CNF_PWR_CTL_2 0x49
-#define CNF_PWR_CTL_3 0x4a
-#define CNF_CARD_DETECT_MODE 0x4c
-#define CNF_SD_SLOT 0x50
-#define CNF_EXT_GCLK_CTL_1 0xf0
-#define CNF_EXT_GCLK_CTL_2 0xf1
-#define CNF_EXT_GCLK_CTL_3 0xf9
-#define CNF_SD_LED_EN_1 0xfa
-#define CNF_SD_LED_EN_2 0xfe
-
-#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/
-
#define CTL_SD_CMD 0x00
#define CTL_ARG_REG 0x04
#define CTL_STOP_INTERNAL_ACTION 0x08
@@ -75,10 +55,8 @@
/* Define some IRQ masks */
/* This is the mask used at reset by the chip */
#define TMIO_MASK_ALL 0x837f031d
-#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND | \
- TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
-#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND | \
- TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
+#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND)
+#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND)
#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \
TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
@@ -110,7 +88,6 @@
struct tmio_mmc_host {
- void __iomem *cnf;
void __iomem *ctl;
unsigned long bus_shift;
struct mmc_command *cmd;
@@ -119,10 +96,16 @@ struct tmio_mmc_host {
struct mmc_host *mmc;
int irq;
+ /* Callbacks for clock / power control */
+ void (*set_pwr)(struct platform_device *host, int state);
+ void (*set_clk_div)(struct platform_device *host, int state);
+
/* pio related stuff */
struct scatterlist *sg_ptr;
unsigned int sg_len;
unsigned int sg_off;
+
+ struct platform_device *pdev;
};
#include <linux/io.h>
@@ -163,25 +146,6 @@ static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr,
writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
}
-static inline void sd_config_write8(struct tmio_mmc_host *host, int addr,
- u8 val)
-{
- writeb(val, host->cnf + (addr << host->bus_shift));
-}
-
-static inline void sd_config_write16(struct tmio_mmc_host *host, int addr,
- u16 val)
-{
- writew(val, host->cnf + (addr << host->bus_shift));
-}
-
-static inline void sd_config_write32(struct tmio_mmc_host *host, int addr,
- u32 val)
-{
- writew(val, host->cnf + (addr << host->bus_shift));
- writew(val >> 16, host->cnf + ((addr + 2) << host->bus_shift));
-}
-
#include <linux/scatterlist.h>
#include <linux/blkdev.h>
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c
index ca584d0380b4..ca584d0380b4 100755..100644
--- a/drivers/mtd/chips/cfi_util.c
+++ b/drivers/mtd/chips/cfi_util.c
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index 1bec5e1ce6ac..8db1148dfa47 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -226,7 +226,7 @@ struct unlock_addr {
* exists, but is for MTD_UADDR_NOT_SUPPORTED - and, therefore,
* should not be used. The problem is that structures with
* initializers have extra fields initialized to 0. It is _very_
- * desireable to have the unlock address entries for unsupported
+ * desirable to have the unlock address entries for unsupported
* data widths automatically initialized - that means that
* MTD_UADDR_NOT_SUPPORTED must be 0 and the first entry here
* must go unused.
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index 8aca5523a337..8aca5523a337 100755..100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 4c364d44ad59..aa2807d0ce72 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -251,12 +251,6 @@ config MTD_NETtel
help
Support for flash chips on NETtel/SecureEdge/SnapGear boards.
-config MTD_ALCHEMY
- tristate "AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support"
- depends on SOC_AU1X00 && MTD_PARTITIONS && MTD_CFI
- help
- Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
-
config MTD_DILNETPC
tristate "CFI Flash device mapped on DIL/Net PC"
depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
@@ -428,15 +422,6 @@ config MTD_H720X
This enables access to the flash chips on the Hynix evaluation boards.
If you have such a board, say 'Y'.
-config MTD_OMAP_NOR
- tristate "TI OMAP board mappings"
- depends on MTD_CFI && ARCH_OMAP
- help
- This enables access to the NOR flash chips on TI OMAP-based
- boards defining flash platform devices and flash platform data.
- These boards include the Innovator, H2, H3, OSK, Perseus2, and
- more. If you have such a board, say 'Y'.
-
# This needs CFI or JEDEC, depending on the cards found.
config MTD_PCI
tristate "PCI MTD driver"
@@ -549,4 +534,21 @@ config MTD_VMU
To build this as a module select M here, the module will be called
vmu-flash.
+config MTD_PISMO
+ tristate "MTD discovery driver for PISMO modules"
+ depends on I2C
+ depends on ARCH_VERSATILE
+ help
+ This driver allows for discovery of PISMO modules - see
+ <http://www.pismoworld.org/>. These are small modules containing
+ up to five memory devices (eg, SRAM, flash, DOC) described by an
+ I2C EEPROM.
+
+ This driver does not create any MTD maps itself; instead it
+ creates MTD physmap and MTD SRAM platform devices. If you
+ enable this option, you should consider enabling MTD_PHYSMAP
+ and/or MTD_PLATRAM according to the devices on your module.
+
+ When built as a module, it will be called pismo.ko
+
endmenu
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index ce315214ff2b..bb035cd54c72 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -40,7 +40,6 @@ obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o
obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
obj-$(CONFIG_MTD_PCI) += pci.o
-obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o
obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
obj-$(CONFIG_MTD_EDB7312) += edb7312.o
obj-$(CONFIG_MTD_IMPA7) += impa7.o
@@ -55,7 +54,6 @@ obj-$(CONFIG_MTD_IXP2000) += ixp2000.o
obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o
obj-$(CONFIG_MTD_DMV182) += dmv182.o
obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o
-obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o
obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
obj-$(CONFIG_MTD_BFIN_ASYNC) += bfin-async-flash.o
obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c
deleted file mode 100644
index 845ad4f2a542..000000000000
--- a/drivers/mtd/maps/alchemy-flash.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Flash memory access on AMD Alchemy evaluation boards
- *
- * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#ifdef CONFIG_MIPS_PB1000
-#define BOARD_MAP_NAME "Pb1000 Flash"
-#define BOARD_FLASH_SIZE 0x00800000 /* 8MB */
-#define BOARD_FLASH_WIDTH 4 /* 32-bits */
-#endif
-
-#ifdef CONFIG_MIPS_PB1500
-#define BOARD_MAP_NAME "Pb1500 Flash"
-#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
-#define BOARD_FLASH_WIDTH 4 /* 32-bits */
-#endif
-
-#ifdef CONFIG_MIPS_PB1100
-#define BOARD_MAP_NAME "Pb1100 Flash"
-#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
-#define BOARD_FLASH_WIDTH 4 /* 32-bits */
-#endif
-
-#ifdef CONFIG_MIPS_PB1550
-#define BOARD_MAP_NAME "Pb1550 Flash"
-#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
-#define BOARD_FLASH_WIDTH 4 /* 32-bits */
-#endif
-
-#ifdef CONFIG_MIPS_PB1200
-#define BOARD_MAP_NAME "Pb1200 Flash"
-#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
-#define BOARD_FLASH_WIDTH 2 /* 16-bits */
-#endif
-
-#ifdef CONFIG_MIPS_DB1000
-#define BOARD_MAP_NAME "Db1000 Flash"
-#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
-#define BOARD_FLASH_WIDTH 4 /* 32-bits */
-#endif
-
-#ifdef CONFIG_MIPS_DB1500
-#define BOARD_MAP_NAME "Db1500 Flash"
-#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
-#define BOARD_FLASH_WIDTH 4 /* 32-bits */
-#endif
-
-#ifdef CONFIG_MIPS_DB1100
-#define BOARD_MAP_NAME "Db1100 Flash"
-#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
-#define BOARD_FLASH_WIDTH 4 /* 32-bits */
-#endif
-
-#ifdef CONFIG_MIPS_DB1550
-#define BOARD_MAP_NAME "Db1550 Flash"
-#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
-#define BOARD_FLASH_WIDTH 4 /* 32-bits */
-#endif
-
-#ifdef CONFIG_MIPS_DB1200
-#define BOARD_MAP_NAME "Db1200 Flash"
-#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
-#define BOARD_FLASH_WIDTH 2 /* 16-bits */
-#endif
-
-#ifdef CONFIG_MIPS_BOSPORUS
-#define BOARD_MAP_NAME "Bosporus Flash"
-#define BOARD_FLASH_SIZE 0x01000000 /* 16MB */
-#define BOARD_FLASH_WIDTH 2 /* 16-bits */
-#endif
-
-#ifdef CONFIG_MIPS_MIRAGE
-#define BOARD_MAP_NAME "Mirage Flash"
-#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
-#define BOARD_FLASH_WIDTH 4 /* 32-bits */
-#define USE_LOCAL_ACCESSORS /* why? */
-#endif
-
-static struct map_info alchemy_map = {
- .name = BOARD_MAP_NAME,
-};
-
-static struct mtd_partition alchemy_partitions[] = {
- {
- .name = "User FS",
- .size = BOARD_FLASH_SIZE - 0x00400000,
- .offset = 0x0000000
- },{
- .name = "YAMON",
- .size = 0x0100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = (0x300000 - 0x40000), /* last 256KB is yamon env */
- .offset = MTDPART_OFS_APPEND,
- }
-};
-
-static struct mtd_info *mymtd;
-
-static int __init alchemy_mtd_init(void)
-{
- struct mtd_partition *parts;
- int nb_parts = 0;
- unsigned long window_addr;
- unsigned long window_size;
-
- /* Default flash buswidth */
- alchemy_map.bankwidth = BOARD_FLASH_WIDTH;
-
- window_addr = 0x20000000 - BOARD_FLASH_SIZE;
- window_size = BOARD_FLASH_SIZE;
-
- /*
- * Static partition definition selection
- */
- parts = alchemy_partitions;
- nb_parts = ARRAY_SIZE(alchemy_partitions);
- alchemy_map.size = window_size;
-
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
- printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n",
- alchemy_map.bankwidth*8);
- alchemy_map.virt = ioremap(window_addr, window_size);
- mymtd = do_map_probe("cfi_probe", &alchemy_map);
- if (!mymtd) {
- iounmap(alchemy_map.virt);
- return -ENXIO;
- }
- mymtd->owner = THIS_MODULE;
-
- add_mtd_partitions(mymtd, parts, nb_parts);
- return 0;
-}
-
-static void __exit alchemy_mtd_cleanup(void)
-{
- if (mymtd) {
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- iounmap(alchemy_map.virt);
- }
-}
-
-module_init(alchemy_mtd_init);
-module_exit(alchemy_mtd_cleanup);
-
-MODULE_AUTHOR("Embedded Alley Solutions, Inc");
-MODULE_DESCRIPTION(BOARD_MAP_NAME " MTD driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c
index ead0b2fab670..e69de29bb2d1 100644
--- a/drivers/mtd/maps/omap_nor.c
+++ b/drivers/mtd/maps/omap_nor.c
@@ -1,188 +0,0 @@
-/*
- * Flash memory support for various TI OMAP boards
- *
- * Copyright (C) 2001-2002 MontaVista Software Inc.
- * Copyright (C) 2003-2004 Texas Instruments
- * Copyright (C) 2004 Nokia Corporation
- *
- * Assembled using driver code copyright the companies above
- * and written by David Brownell, Jian Zhang <jzhang@ti.com>,
- * Tony Lindgren <tony@atomide.com> and others.
- *
- * 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/platform_device.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <mach/hardware.h>
-#include <asm/mach/flash.h>
-#include <plat/tc.h>
-
-#ifdef CONFIG_MTD_PARTITIONS
-static const char *part_probes[] = { /* "RedBoot", */ "cmdlinepart", NULL };
-#endif
-
-struct omapflash_info {
- struct mtd_partition *parts;
- struct mtd_info *mtd;
- struct map_info map;
-};
-
-static void omap_set_vpp(struct map_info *map, int enable)
-{
- static int count;
- u32 l;
-
- if (cpu_class_is_omap1()) {
- if (enable) {
- if (count++ == 0) {
- l = omap_readl(EMIFS_CONFIG);
- l |= OMAP_EMIFS_CONFIG_WP;
- omap_writel(l, EMIFS_CONFIG);
- }
- } else {
- if (count && (--count == 0)) {
- l = omap_readl(EMIFS_CONFIG);
- l &= ~OMAP_EMIFS_CONFIG_WP;
- omap_writel(l, EMIFS_CONFIG);
- }
- }
- }
-}
-
-static int __init omapflash_probe(struct platform_device *pdev)
-{
- int err;
- struct omapflash_info *info;
- struct flash_platform_data *pdata = pdev->dev.platform_data;
- struct resource *res = pdev->resource;
- unsigned long size = res->end - res->start + 1;
-
- info = kzalloc(sizeof(struct omapflash_info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- if (!request_mem_region(res->start, size, "flash")) {
- err = -EBUSY;
- goto out_free_info;
- }
-
- info->map.virt = ioremap(res->start, size);
- if (!info->map.virt) {
- err = -ENOMEM;
- goto out_release_mem_region;
- }
- info->map.name = dev_name(&pdev->dev);
- info->map.phys = res->start;
- info->map.size = size;
- info->map.bankwidth = pdata->width;
- info->map.set_vpp = omap_set_vpp;
-
- simple_map_init(&info->map);
- info->mtd = do_map_probe(pdata->map_name, &info->map);
- if (!info->mtd) {
- err = -EIO;
- goto out_iounmap;
- }
- info->mtd->owner = THIS_MODULE;
-
- info->mtd->dev.parent = &pdev->dev;
-
-#ifdef CONFIG_MTD_PARTITIONS
- err = parse_mtd_partitions(info->mtd, part_probes, &info->parts, 0);
- if (err > 0)
- add_mtd_partitions(info->mtd, info->parts, err);
- else if (err <= 0 && pdata->parts)
- add_mtd_partitions(info->mtd, pdata->parts, pdata->nr_parts);
- else
-#endif
- add_mtd_device(info->mtd);
-
- platform_set_drvdata(pdev, info);
-
- return 0;
-
-out_iounmap:
- iounmap(info->map.virt);
-out_release_mem_region:
- release_mem_region(res->start, size);
-out_free_info:
- kfree(info);
-
- return err;
-}
-
-static int __exit omapflash_remove(struct platform_device *pdev)
-{
- struct omapflash_info *info = platform_get_drvdata(pdev);
-
- platform_set_drvdata(pdev, NULL);
-
- if (info) {
- if (info->parts) {
- del_mtd_partitions(info->mtd);
- kfree(info->parts);
- } else
- del_mtd_device(info->mtd);
- map_destroy(info->mtd);
- release_mem_region(info->map.phys, info->map.size);
- iounmap((void __iomem *) info->map.virt);
- kfree(info);
- }
-
- return 0;
-}
-
-static struct platform_driver omapflash_driver = {
- .remove = __exit_p(omapflash_remove),
- .driver = {
- .name = "omapflash",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init omapflash_init(void)
-{
- return platform_driver_probe(&omapflash_driver, omapflash_probe);
-}
-
-static void __exit omapflash_exit(void)
-{
- platform_driver_unregister(&omapflash_driver);
-}
-
-module_init(omapflash_init);
-module_exit(omapflash_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("MTD NOR map driver for TI OMAP boards");
-MODULE_ALIAS("platform:omapflash");
diff --git a/drivers/mtd/maps/pismo.c b/drivers/mtd/maps/pismo.c
new file mode 100644
index 000000000000..30e12c88d1da
--- /dev/null
+++ b/drivers/mtd/maps/pismo.c
@@ -0,0 +1,320 @@
+/*
+ * PISMO memory driver - http://www.pismoworld.org/
+ *
+ * For ARM Realview and Versatile platforms
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/plat-ram.h>
+#include <linux/mtd/pismo.h>
+
+#define PISMO_NUM_CS 5
+
+struct pismo_cs_block {
+ u8 type;
+ u8 width;
+ __le16 access;
+ __le32 size;
+ u32 reserved[2];
+ char device[32];
+} __packed;
+
+struct pismo_eeprom {
+ struct pismo_cs_block cs[PISMO_NUM_CS];
+ char board[15];
+ u8 sum;
+} __packed;
+
+struct pismo_mem {
+ phys_addr_t base;
+ u32 size;
+ u16 access;
+ u8 width;
+ u8 type;
+};
+
+struct pismo_data {
+ struct i2c_client *client;
+ void (*vpp)(void *, int);
+ void *vpp_data;
+ struct platform_device *dev[PISMO_NUM_CS];
+};
+
+/* FIXME: set_vpp could do with a better calling convention */
+static struct pismo_data *vpp_pismo;
+static DEFINE_MUTEX(pismo_mutex);
+
+static int pismo_setvpp_probe_fix(struct pismo_data *pismo)
+{
+ mutex_lock(&pismo_mutex);
+ if (vpp_pismo) {
+ mutex_unlock(&pismo_mutex);
+ kfree(pismo);
+ return -EBUSY;
+ }
+ vpp_pismo = pismo;
+ mutex_unlock(&pismo_mutex);
+ return 0;
+}
+
+static void pismo_setvpp_remove_fix(struct pismo_data *pismo)
+{
+ mutex_lock(&pismo_mutex);
+ if (vpp_pismo == pismo)
+ vpp_pismo = NULL;
+ mutex_unlock(&pismo_mutex);
+}
+
+static void pismo_set_vpp(struct map_info *map, int on)
+{
+ struct pismo_data *pismo = vpp_pismo;
+
+ pismo->vpp(pismo->vpp_data, on);
+}
+/* end of hack */
+
+
+static unsigned int __devinit pismo_width_to_bytes(unsigned int width)
+{
+ width &= 15;
+ if (width > 2)
+ return 0;
+ return 1 << width;
+}
+
+static int __devinit pismo_eeprom_read(struct i2c_client *client, void *buf,
+ u8 addr, size_t size)
+{
+ int ret;
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .len = sizeof(addr),
+ .buf = &addr,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = size,
+ .buf = buf,
+ },
+ };
+
+ ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+
+ return ret == ARRAY_SIZE(msg) ? size : -EIO;
+}
+
+static int __devinit pismo_add_device(struct pismo_data *pismo, int i,
+ struct pismo_mem *region, const char *name, void *pdata, size_t psize)
+{
+ struct platform_device *dev;
+ struct resource res = { };
+ phys_addr_t base = region->base;
+ int ret;
+
+ if (base == ~0)
+ return -ENXIO;
+
+ res.start = base;
+ res.end = base + region->size - 1;
+ res.flags = IORESOURCE_MEM;
+
+ dev = platform_device_alloc(name, i);
+ if (!dev)
+ return -ENOMEM;
+ dev->dev.parent = &pismo->client->dev;
+
+ do {
+ ret = platform_device_add_resources(dev, &res, 1);
+ if (ret)
+ break;
+
+ ret = platform_device_add_data(dev, pdata, psize);
+ if (ret)
+ break;
+
+ ret = platform_device_add(dev);
+ if (ret)
+ break;
+
+ pismo->dev[i] = dev;
+ return 0;
+ } while (0);
+
+ platform_device_put(dev);
+ return ret;
+}
+
+static int __devinit pismo_add_nor(struct pismo_data *pismo, int i,
+ struct pismo_mem *region)
+{
+ struct physmap_flash_data data = {
+ .width = region->width,
+ };
+
+ if (pismo->vpp)
+ data.set_vpp = pismo_set_vpp;
+
+ return pismo_add_device(pismo, i, region, "physmap-flash",
+ &data, sizeof(data));
+}
+
+static int __devinit pismo_add_sram(struct pismo_data *pismo, int i,
+ struct pismo_mem *region)
+{
+ struct platdata_mtd_ram data = {
+ .bankwidth = region->width,
+ };
+
+ return pismo_add_device(pismo, i, region, "mtd-ram",
+ &data, sizeof(data));
+}
+
+static void __devinit pismo_add_one(struct pismo_data *pismo, int i,
+ const struct pismo_cs_block *cs, phys_addr_t base)
+{
+ struct device *dev = &pismo->client->dev;
+ struct pismo_mem region;
+
+ region.base = base;
+ region.type = cs->type;
+ region.width = pismo_width_to_bytes(cs->width);
+ region.access = le16_to_cpu(cs->access);
+ region.size = le32_to_cpu(cs->size);
+
+ if (region.width == 0) {
+ dev_err(dev, "cs%u: bad width: %02x, ignoring\n", i, cs->width);
+ return;
+ }
+
+ /*
+ * FIXME: may need to the platforms memory controller here, but at
+ * the moment we assume that it has already been correctly setup.
+ * The memory controller can also tell us the base address as well.
+ */
+
+ dev_info(dev, "cs%u: %.32s: type %02x access %u00ps size %uK\n",
+ i, cs->device, region.type, region.access, region.size / 1024);
+
+ switch (region.type) {
+ case 0:
+ break;
+ case 1:
+ /* static DOC */
+ break;
+ case 2:
+ /* static NOR */
+ pismo_add_nor(pismo, i, &region);
+ break;
+ case 3:
+ /* static RAM */
+ pismo_add_sram(pismo, i, &region);
+ break;
+ }
+}
+
+static int __devexit pismo_remove(struct i2c_client *client)
+{
+ struct pismo_data *pismo = i2c_get_clientdata(client);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pismo->dev); i++)
+ platform_device_unregister(pismo->dev[i]);
+
+ /* FIXME: set_vpp needs saner arguments */
+ pismo_setvpp_remove_fix(pismo);
+
+ kfree(pismo);
+
+ return 0;
+}
+
+static int __devinit pismo_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct pismo_pdata *pdata = client->dev.platform_data;
+ struct pismo_eeprom eeprom;
+ struct pismo_data *pismo;
+ int ret, i;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "functionality mismatch\n");
+ return -EIO;
+ }
+
+ pismo = kzalloc(sizeof(*pismo), GFP_KERNEL);
+ if (!pismo)
+ return -ENOMEM;
+
+ /* FIXME: set_vpp needs saner arguments */
+ ret = pismo_setvpp_probe_fix(pismo);
+ if (ret)
+ return ret;
+
+ pismo->client = client;
+ if (pdata) {
+ pismo->vpp = pdata->set_vpp;
+ pismo->vpp_data = pdata->vpp_data;
+ }
+ i2c_set_clientdata(client, pismo);
+
+ ret = pismo_eeprom_read(client, &eeprom, 0, sizeof(eeprom));
+ if (ret < 0) {
+ dev_err(&client->dev, "error reading EEPROM: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(&client->dev, "%.15s board found\n", eeprom.board);
+
+ for (i = 0; i < ARRAY_SIZE(eeprom.cs); i++)
+ if (eeprom.cs[i].type != 0xff)
+ pismo_add_one(pismo, i, &eeprom.cs[i],
+ pdata->cs_addrs[i]);
+
+ return 0;
+}
+
+static const struct i2c_device_id pismo_id[] = {
+ { "pismo" },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, pismo_id);
+
+static struct i2c_driver pismo_driver = {
+ .driver = {
+ .name = "pismo",
+ .owner = THIS_MODULE,
+ },
+ .probe = pismo_probe,
+ .remove = __devexit_p(pismo_remove),
+ .id_table = pismo_id,
+};
+
+static int __init pismo_init(void)
+{
+ BUILD_BUG_ON(sizeof(struct pismo_cs_block) != 48);
+ BUILD_BUG_ON(sizeof(struct pismo_eeprom) != 256);
+
+ return i2c_add_driver(&pismo_driver);
+}
+module_init(pismo_init);
+
+static void __exit pismo_exit(void)
+{
+ i2c_del_driver(&pismo_driver);
+}
+module_exit(pismo_exit);
+
+MODULE_AUTHOR("Russell King <linux@arm.linux.org.uk>");
+MODULE_DESCRIPTION("PISMO memory driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c
index dafb91944e70..76a76be5a7bd 100644
--- a/drivers/mtd/maps/plat-ram.c
+++ b/drivers/mtd/maps/plat-ram.c
@@ -4,7 +4,7 @@
* http://www.simtec.co.uk/products/SWLINUX/
* Ben Dooks <ben@simtec.co.uk>
*
- * Generic platfrom device based RAM map
+ * Generic platform device based RAM map
*
* 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
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index a714ec482761..92e12df0917f 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -322,7 +322,7 @@ static void mtdoops_do_dump(struct kmsg_dumper *dumper,
memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
/* Panics must be written immediately */
- if (reason == KMSG_DUMP_PANIC) {
+ if (reason != KMSG_DUMP_OOPS) {
if (!cxt->mtd->panic_write)
printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n");
else
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 677cd53f18c3..1157d5679e66 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -444,7 +444,7 @@ config MTD_NAND_FSL_UPM
config MTD_NAND_MXC
tristate "MXC NAND support"
- depends on ARCH_MX2 || ARCH_MX3
+ depends on ARCH_MX2 || ARCH_MX25 || ARCH_MX3
help
This enables the driver for the NAND flash controller on the
MXC processors.
@@ -457,10 +457,10 @@ config MTD_NAND_NOMADIK
config MTD_NAND_SH_FLCTL
tristate "Support for NAND on Renesas SuperH FLCTL"
- depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723
+ depends on MTD_NAND && SUPERH
help
Several Renesas SuperH CPU has FLCTL. This option enables support
- for NAND Flash using FLCTL. This driver support SH7723.
+ for NAND Flash using FLCTL.
config MTD_NAND_DAVINCI
tristate "Support NAND on DaVinci SoC"
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
index 92c334ff4508..43d46e424040 100644
--- a/drivers/mtd/nand/au1550nd.c
+++ b/drivers/mtd/nand/au1550nd.c
@@ -19,6 +19,7 @@
#include <asm/io.h>
#include <asm/mach-au1x00/au1xxx.h>
+#include <asm/mach-db1x00/bcsr.h>
/*
* MTD structure for NAND controller
@@ -475,7 +476,8 @@ static int __init au1xxx_nand_init(void)
/* set gpio206 high */
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_read(BCSR_STATUS) >> 6) & 0x1);
+
switch (boot_swapboot) {
case 0:
case 2:
diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c
index 087bcd745bb7..7d1cca7a31a9 100644
--- a/drivers/mtd/nand/bcm_umi_nand.c
+++ b/drivers/mtd/nand/bcm_umi_nand.c
@@ -381,7 +381,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev)
if (!r)
return -ENXIO;
- /* map physical adress */
+ /* map physical address */
bcm_umi_io_base = ioremap(r->start, r->end - r->start + 1);
if (!bcm_umi_io_base) {
@@ -525,7 +525,7 @@ static int bcm_umi_nand_remove(struct platform_device *pdev)
/* Release resources, unregister device */
nand_release(board_mtd);
- /* unmap physical adress */
+ /* unmap physical address */
iounmap(bcm_umi_io_base);
/* Free the MTD device structure */
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 45dec5770da0..b2900d8406d3 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -507,7 +507,7 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
* MXC NANDFC can only perform full page+spare or
* spare-only read/write. When the upper layers
* layers perform a read/write buf operation,
- * we will used the saved column adress to index into
+ * we will used the saved column address to index into
* the full page.
*/
send_addr(host, 0, page_addr == -1);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 1bb799f0125c..26aec0080184 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -30,12 +30,8 @@
#define DRIVER_NAME "omap2-nand"
-/* size (4 KiB) for IO mapping */
-#define NAND_IO_SIZE SZ_4K
-
#define NAND_WP_OFF 0
#define NAND_WP_BIT 0x00000010
-#define WR_RD_PIN_MONITORING 0x00600000
#define GPMC_BUF_FULL 0x00000001
#define GPMC_BUF_EMPTY 0x00000000
@@ -882,8 +878,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
struct omap_nand_info *info;
struct omap_nand_platform_data *pdata;
int err;
- unsigned long val;
-
pdata = pdev->dev.platform_data;
if (pdata == NULL) {
@@ -905,28 +899,14 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
info->gpmc_cs = pdata->cs;
info->gpmc_baseaddr = pdata->gpmc_baseaddr;
info->gpmc_cs_baseaddr = pdata->gpmc_cs_baseaddr;
+ info->phys_base = pdata->phys_base;
info->mtd.priv = &info->nand;
info->mtd.name = dev_name(&pdev->dev);
info->mtd.owner = THIS_MODULE;
- err = gpmc_cs_request(info->gpmc_cs, NAND_IO_SIZE, &info->phys_base);
- if (err < 0) {
- dev_err(&pdev->dev, "Cannot request GPMC CS\n");
- goto out_free_info;
- }
-
- /* Enable RD PIN Monitoring Reg */
- if (pdata->dev_ready) {
- val = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1);
- val |= WR_RD_PIN_MONITORING;
- gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG1, val);
- }
-
- val = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG7);
- val &= ~(0xf << 8);
- val |= (0xc & 0xf) << 8;
- gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG7, val);
+ info->nand.options |= pdata->devsize ? NAND_BUSWIDTH_16 : 0;
+ info->nand.options |= NAND_SKIP_BBTSCAN;
/* NAND write protect off */
omap_nand_wp(&info->mtd, NAND_WP_OFF);
@@ -934,7 +914,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
if (!request_mem_region(info->phys_base, NAND_IO_SIZE,
pdev->dev.driver->name)) {
err = -EBUSY;
- goto out_free_cs;
+ goto out_free_info;
}
info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE);
@@ -963,11 +943,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
info->nand.chip_delay = 50;
}
- info->nand.options |= NAND_SKIP_BBTSCAN;
- if ((gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1) & 0x3000)
- == 0x1000)
- info->nand.options |= NAND_BUSWIDTH_16;
-
if (use_prefetch) {
/* copy the virtual address of nand base for fifo access */
info->nand_pref_fifo_add = info->nand.IO_ADDR_R;
@@ -1043,8 +1018,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
out_release_mem_region:
release_mem_region(info->phys_base, NAND_IO_SIZE);
-out_free_cs:
- gpmc_cs_free(info->gpmc_cs);
out_free_info:
kfree(info);
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
index 02bef21f2e4b..1842df8bdd93 100644
--- a/drivers/mtd/nand/sh_flctl.c
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -1,10 +1,10 @@
/*
* SuperH FLCTL nand controller
*
- * Copyright © 2008 Renesas Solutions Corp.
- * Copyright © 2008 Atom Create Engineering Co., Ltd.
+ * Copyright (c) 2008 Renesas Solutions Corp.
+ * Copyright (c) 2008 Atom Create Engineering Co., Ltd.
*
- * Based on fsl_elbc_nand.c, Copyright © 2006-2007 Freescale Semiconductor
+ * Based on fsl_elbc_nand.c, Copyright (c) 2006-2007 Freescale Semiconductor
*
* 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
@@ -75,6 +75,11 @@ static void start_translation(struct sh_flctl *flctl)
writeb(TRSTRT, FLTRCR(flctl));
}
+static void timeout_error(struct sh_flctl *flctl, const char *str)
+{
+ dev_err(&flctl->pdev->dev, "Timeout occured in %s\n", str);
+}
+
static void wait_completion(struct sh_flctl *flctl)
{
uint32_t timeout = LOOP_TIMEOUT_MAX;
@@ -87,7 +92,7 @@ static void wait_completion(struct sh_flctl *flctl)
udelay(1);
}
- printk(KERN_ERR "wait_completion(): Timeout occured \n");
+ timeout_error(flctl, __func__);
writeb(0x0, FLTRCR(flctl));
}
@@ -100,6 +105,8 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr)
addr = page_addr; /* ERASE1 */
} else if (page_addr != -1) {
/* SEQIN, READ0, etc.. */
+ if (flctl->chip.options & NAND_BUSWIDTH_16)
+ column >>= 1;
if (flctl->page_size) {
addr = column & 0x0FFF;
addr |= (page_addr & 0xff) << 16;
@@ -132,7 +139,7 @@ static void wait_rfifo_ready(struct sh_flctl *flctl)
return;
udelay(1);
}
- printk(KERN_ERR "wait_rfifo_ready(): Timeout occured \n");
+ timeout_error(flctl, __func__);
}
static void wait_wfifo_ready(struct sh_flctl *flctl)
@@ -146,7 +153,7 @@ static void wait_wfifo_ready(struct sh_flctl *flctl)
return;
udelay(1);
}
- printk(KERN_ERR "wait_wfifo_ready(): Timeout occured \n");
+ timeout_error(flctl, __func__);
}
static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number)
@@ -198,7 +205,7 @@ static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number)
writel(0, FL4ECCCR(flctl));
}
- printk(KERN_ERR "wait_recfifo_ready(): Timeout occured \n");
+ timeout_error(flctl, __func__);
return 1; /* timeout */
}
@@ -214,7 +221,7 @@ static void wait_wecfifo_ready(struct sh_flctl *flctl)
return;
udelay(1);
}
- printk(KERN_ERR "wait_wecfifo_ready(): Timeout occured \n");
+ timeout_error(flctl, __func__);
}
static void read_datareg(struct sh_flctl *flctl, int offset)
@@ -275,7 +282,7 @@ static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
- uint32_t flcmncr_val = readl(FLCMNCR(flctl));
+ uint32_t flcmncr_val = readl(FLCMNCR(flctl)) & ~SEL_16BIT;
uint32_t flcmdcr_val, addr_len_bytes = 0;
/* Set SNAND bit if page size is 2048byte */
@@ -297,6 +304,8 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va
case NAND_CMD_READOOB:
addr_len_bytes = flctl->rw_ADRCNT;
flcmdcr_val |= CDSRC_E;
+ if (flctl->chip.options & NAND_BUSWIDTH_16)
+ flcmncr_val |= SEL_16BIT;
break;
case NAND_CMD_SEQIN:
/* This case is that cmd is READ0 or READ1 or READ00 */
@@ -305,6 +314,8 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va
case NAND_CMD_PAGEPROG:
addr_len_bytes = flctl->rw_ADRCNT;
flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW;
+ if (flctl->chip.options & NAND_BUSWIDTH_16)
+ flcmncr_val |= SEL_16BIT;
break;
case NAND_CMD_READID:
flcmncr_val &= ~SNAND_E;
@@ -523,6 +534,8 @@ static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
set_addr(mtd, 0, page_addr);
flctl->read_bytes = mtd->writesize + mtd->oobsize;
+ if (flctl->chip.options & NAND_BUSWIDTH_16)
+ column >>= 1;
flctl->index += column;
goto read_normal_exit;
@@ -686,6 +699,18 @@ static uint8_t flctl_read_byte(struct mtd_info *mtd)
return data;
}
+static uint16_t flctl_read_word(struct mtd_info *mtd)
+{
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ int index = flctl->index;
+ uint16_t data;
+ uint16_t *buf = (uint16_t *)&flctl->done_buff[index];
+
+ data = *buf;
+ flctl->index += 2;
+ return data;
+}
+
static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
int i;
@@ -769,38 +794,36 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
return 0;
}
-static int __init flctl_probe(struct platform_device *pdev)
+static int __devinit flctl_probe(struct platform_device *pdev)
{
struct resource *res;
struct sh_flctl *flctl;
struct mtd_info *flctl_mtd;
struct nand_chip *nand;
struct sh_flctl_platform_data *pdata;
- int ret;
+ int ret = -ENXIO;
pdata = pdev->dev.platform_data;
if (pdata == NULL) {
- printk(KERN_ERR "sh_flctl platform_data not found.\n");
- return -ENODEV;
+ dev_err(&pdev->dev, "no platform data defined\n");
+ return -EINVAL;
}
flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
if (!flctl) {
- printk(KERN_ERR "Unable to allocate NAND MTD dev structure.\n");
+ dev_err(&pdev->dev, "failed to allocate driver data\n");
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
- printk(KERN_ERR "%s: resource not found.\n", __func__);
- ret = -ENODEV;
+ dev_err(&pdev->dev, "failed to get I/O memory\n");
goto err;
}
- flctl->reg = ioremap(res->start, res->end - res->start + 1);
+ flctl->reg = ioremap(res->start, resource_size(res));
if (flctl->reg == NULL) {
- printk(KERN_ERR "%s: ioremap error.\n", __func__);
- ret = -ENOMEM;
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
goto err;
}
@@ -808,6 +831,7 @@ static int __init flctl_probe(struct platform_device *pdev)
flctl_mtd = &flctl->mtd;
nand = &flctl->chip;
flctl_mtd->priv = nand;
+ flctl->pdev = pdev;
flctl->hwecc = pdata->has_hwecc;
flctl_register_init(flctl, pdata->flcmncr_val);
@@ -825,6 +849,11 @@ static int __init flctl_probe(struct platform_device *pdev)
nand->select_chip = flctl_select_chip;
nand->cmdfunc = flctl_cmdfunc;
+ if (pdata->flcmncr_val & SEL_16BIT) {
+ nand->options |= NAND_BUSWIDTH_16;
+ nand->read_word = flctl_read_word;
+ }
+
ret = nand_scan_ident(flctl_mtd, 1);
if (ret)
goto err;
@@ -846,7 +875,7 @@ err:
return ret;
}
-static int __exit flctl_remove(struct platform_device *pdev)
+static int __devexit flctl_remove(struct platform_device *pdev)
{
struct sh_flctl *flctl = platform_get_drvdata(pdev);
diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c
index 79fc4530987b..25c5dd03a837 100644
--- a/drivers/mtd/tests/mtd_readtest.c
+++ b/drivers/mtd/tests/mtd_readtest.c
@@ -147,6 +147,10 @@ static int scan_for_bad_eraseblocks(void)
}
memset(bbt, 0 , ebcnt);
+ /* NOR flash does not implement block_isbad */
+ if (mtd->block_isbad == NULL)
+ return 0;
+
printk(PRINT_PREF "scanning for bad eraseblocks\n");
for (i = 0; i < ebcnt; ++i) {
bbt[i] = is_block_bad(i) ? 1 : 0;
@@ -184,7 +188,7 @@ static int __init mtd_readtest_init(void)
tmp = mtd->size;
do_div(tmp, mtd->erasesize);
ebcnt = tmp;
- pgcnt = mtd->erasesize / mtd->writesize;
+ pgcnt = mtd->erasesize / pgsize;
printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
"page size %u, count of eraseblocks %u, pages per "
diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c
index 141363a7e805..7fbb51d4eabe 100644
--- a/drivers/mtd/tests/mtd_speedtest.c
+++ b/drivers/mtd/tests/mtd_speedtest.c
@@ -301,6 +301,10 @@ static int scan_for_bad_eraseblocks(void)
}
memset(bbt, 0 , ebcnt);
+ /* NOR flash does not implement block_isbad */
+ if (mtd->block_isbad == NULL)
+ goto out;
+
printk(PRINT_PREF "scanning for bad eraseblocks\n");
for (i = 0; i < ebcnt; ++i) {
bbt[i] = is_block_bad(i) ? 1 : 0;
@@ -309,6 +313,7 @@ static int scan_for_bad_eraseblocks(void)
cond_resched();
}
printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+out:
goodebcnt = ebcnt - bad;
return 0;
}
@@ -340,7 +345,7 @@ static int __init mtd_speedtest_init(void)
tmp = mtd->size;
do_div(tmp, mtd->erasesize);
ebcnt = tmp;
- pgcnt = mtd->erasesize / mtd->writesize;
+ pgcnt = mtd->erasesize / pgsize;
printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
"page size %u, count of eraseblocks %u, pages per "
diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c
index 63920476b57a..a99d3cd737d8 100644
--- a/drivers/mtd/tests/mtd_stresstest.c
+++ b/drivers/mtd/tests/mtd_stresstest.c
@@ -227,6 +227,10 @@ static int scan_for_bad_eraseblocks(void)
}
memset(bbt, 0 , ebcnt);
+ /* NOR flash does not implement block_isbad */
+ if (mtd->block_isbad == NULL)
+ return 0;
+
printk(PRINT_PREF "scanning for bad eraseblocks\n");
for (i = 0; i < ebcnt; ++i) {
bbt[i] = is_block_bad(i) ? 1 : 0;
@@ -265,7 +269,7 @@ static int __init mtd_stresstest_init(void)
tmp = mtd->size;
do_div(tmp, mtd->erasesize);
ebcnt = tmp;
- pgcnt = mtd->erasesize / mtd->writesize;
+ pgcnt = mtd->erasesize / pgsize;
printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
"page size %u, count of eraseblocks %u, pages per "
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 14cec04c34f9..fad40aa6f099 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -37,6 +37,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/stringify.h>
+#include <linux/namei.h>
#include <linux/stat.h>
#include <linux/miscdevice.h>
#include <linux/log2.h>
@@ -50,7 +51,8 @@
/**
* struct mtd_dev_param - MTD device parameter description data structure.
- * @name: MTD device name or number string
+ * @name: MTD character device node path, MTD device name, or MTD device number
+ * string
* @vid_hdr_offs: VID header offset
*/
struct mtd_dev_param {
@@ -59,10 +61,10 @@ struct mtd_dev_param {
};
/* Numbers of elements set in the @mtd_dev_param array */
-static int mtd_devs;
+static int __initdata mtd_devs;
/* MTD devices specification parameters */
-static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];
+static struct mtd_dev_param __initdata mtd_dev_param[UBI_MAX_DEVICES];
/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
struct class *ubi_class;
@@ -87,7 +89,8 @@ DEFINE_MUTEX(ubi_devices_mutex);
static DEFINE_SPINLOCK(ubi_devices_lock);
/* "Show" method for files in '/<sysfs>/class/ubi/' */
-static ssize_t ubi_version_show(struct class *class, char *buf)
+static ssize_t ubi_version_show(struct class *class, struct class_attribute *attr,
+ char *buf)
{
return sprintf(buf, "%d\n", UBI_VERSION);
}
@@ -363,11 +366,13 @@ static void dev_release(struct device *dev)
/**
* ubi_sysfs_init - initialize sysfs for an UBI device.
* @ubi: UBI device description object
+ * @ref: set to %1 on exit in case of failure if a reference to @ubi->dev was
+ * taken
*
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
-static int ubi_sysfs_init(struct ubi_device *ubi)
+static int ubi_sysfs_init(struct ubi_device *ubi, int *ref)
{
int err;
@@ -379,6 +384,7 @@ static int ubi_sysfs_init(struct ubi_device *ubi)
if (err)
return err;
+ *ref = 1;
err = device_create_file(&ubi->dev, &dev_eraseblock_size);
if (err)
return err;
@@ -434,7 +440,7 @@ static void ubi_sysfs_close(struct ubi_device *ubi)
}
/**
- * kill_volumes - destroy all volumes.
+ * kill_volumes - destroy all user volumes.
* @ubi: UBI device description object
*/
static void kill_volumes(struct ubi_device *ubi)
@@ -447,36 +453,29 @@ static void kill_volumes(struct ubi_device *ubi)
}
/**
- * free_user_volumes - free all user volumes.
- * @ubi: UBI device description object
- *
- * Normally the volumes are freed at the release function of the volume device
- * objects. However, on error paths the volumes have to be freed before the
- * device objects have been initialized.
- */
-static void free_user_volumes(struct ubi_device *ubi)
-{
- int i;
-
- for (i = 0; i < ubi->vtbl_slots; i++)
- if (ubi->volumes[i]) {
- kfree(ubi->volumes[i]->eba_tbl);
- kfree(ubi->volumes[i]);
- }
-}
-
-/**
* uif_init - initialize user interfaces for an UBI device.
* @ubi: UBI device description object
+ * @ref: set to %1 on exit in case of failure if a reference to @ubi->dev was
+ * taken, otherwise set to %0
+ *
+ * This function initializes various user interfaces for an UBI device. If the
+ * initialization fails at an early stage, this function frees all the
+ * resources it allocated, returns an error, and @ref is set to %0. However,
+ * if the initialization fails after the UBI device was registered in the
+ * driver core subsystem, this function takes a reference to @ubi->dev, because
+ * otherwise the release function ('dev_release()') would free whole @ubi
+ * object. The @ref argument is set to %1 in this case. The caller has to put
+ * this reference.
*
* This function returns zero in case of success and a negative error code in
- * case of failure. Note, this function destroys all volumes if it fails.
+ * case of failure.
*/
-static int uif_init(struct ubi_device *ubi)
+static int uif_init(struct ubi_device *ubi, int *ref)
{
int i, err;
dev_t dev;
+ *ref = 0;
sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
/*
@@ -504,7 +503,7 @@ static int uif_init(struct ubi_device *ubi)
goto out_unreg;
}
- err = ubi_sysfs_init(ubi);
+ err = ubi_sysfs_init(ubi, ref);
if (err)
goto out_sysfs;
@@ -522,6 +521,8 @@ static int uif_init(struct ubi_device *ubi)
out_volumes:
kill_volumes(ubi);
out_sysfs:
+ if (*ref)
+ get_device(&ubi->dev);
ubi_sysfs_close(ubi);
cdev_del(&ubi->cdev);
out_unreg:
@@ -875,7 +876,7 @@ static int ubi_reboot_notifier(struct notifier_block *n, unsigned long state,
int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
{
struct ubi_device *ubi;
- int i, err, do_free = 1;
+ int i, err, ref = 0;
/*
* Check if we already have the same MTD device attached.
@@ -975,9 +976,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
goto out_detach;
}
- err = uif_init(ubi);
+ err = uif_init(ubi, &ref);
if (err)
- goto out_nofree;
+ goto out_detach;
ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
if (IS_ERR(ubi->bgt_thread)) {
@@ -1025,12 +1026,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
out_uif:
uif_close(ubi);
-out_nofree:
- do_free = 0;
out_detach:
ubi_wl_close(ubi);
- if (do_free)
- free_user_volumes(ubi);
free_internal_volumes(ubi);
vfree(ubi->vtbl);
out_free:
@@ -1039,7 +1036,10 @@ out_free:
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
vfree(ubi->dbg_peb_buf);
#endif
- kfree(ubi);
+ if (ref)
+ put_device(&ubi->dev);
+ else
+ kfree(ubi);
return err;
}
@@ -1096,7 +1096,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
/*
* Get a reference to the device in order to prevent 'dev_release()'
- * from freeing @ubi object.
+ * from freeing the @ubi object.
*/
get_device(&ubi->dev);
@@ -1116,13 +1116,50 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
}
/**
- * find_mtd_device - open an MTD device by its name or number.
- * @mtd_dev: name or number of the device
+ * open_mtd_by_chdev - open an MTD device by its character device node path.
+ * @mtd_dev: MTD character device node path
+ *
+ * This helper function opens an MTD device by its character node device path.
+ * Returns MTD device description object in case of success and a negative
+ * error code in case of failure.
+ */
+static struct mtd_info * __init open_mtd_by_chdev(const char *mtd_dev)
+{
+ int err, major, minor, mode;
+ struct path path;
+
+ /* Probably this is an MTD character device node path */
+ err = kern_path(mtd_dev, LOOKUP_FOLLOW, &path);
+ if (err)
+ return ERR_PTR(err);
+
+ /* MTD device number is defined by the major / minor numbers */
+ major = imajor(path.dentry->d_inode);
+ minor = iminor(path.dentry->d_inode);
+ mode = path.dentry->d_inode->i_mode;
+ path_put(&path);
+ if (major != MTD_CHAR_MAJOR || !S_ISCHR(mode))
+ return ERR_PTR(-EINVAL);
+
+ if (minor & 1)
+ /*
+ * Just do not think the "/dev/mtdrX" devices support is need,
+ * so do not support them to avoid doing extra work.
+ */
+ return ERR_PTR(-EINVAL);
+
+ return get_mtd_device(NULL, minor / 2);
+}
+
+/**
+ * open_mtd_device - open MTD device by name, character device path, or number.
+ * @mtd_dev: name, character device node path, or MTD device device number
*
* This function tries to open and MTD device described by @mtd_dev string,
- * which is first treated as an ASCII number, and if it is not true, it is
- * treated as MTD device name. Returns MTD device description object in case of
- * success and a negative error code in case of failure.
+ * which is first treated as ASCII MTD device number, and if it is not true, it
+ * is treated as MTD device name, and if that is also not true, it is treated
+ * as MTD character device node path. Returns MTD device description object in
+ * case of success and a negative error code in case of failure.
*/
static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
{
@@ -1137,6 +1174,9 @@ static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
* MTD device name.
*/
mtd = get_mtd_device_nm(mtd_dev);
+ if (IS_ERR(mtd) && PTR_ERR(mtd) == -ENODEV)
+ /* Probably this is an MTD character device node path */
+ mtd = open_mtd_by_chdev(mtd_dev);
} else
mtd = get_mtd_device(NULL, mtd_num);
@@ -1352,13 +1392,15 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000);
MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: "
- "mtd=<name|num>[,<vid_hdr_offs>].\n"
+ "mtd=<name|num|path>[,<vid_hdr_offs>].\n"
"Multiple \"mtd\" parameters may be specified.\n"
- "MTD devices may be specified by their number or name.\n"
+ "MTD devices may be specified by their number, name, or "
+ "path to the MTD character device node.\n"
"Optional \"vid_hdr_offs\" parameter specifies UBI VID "
- "header position and data starting position to be used "
- "by UBI.\n"
- "Example: mtd=content,1984 mtd=4 - attach MTD device"
+ "header position to be used by UBI.\n"
+ "Example 1: mtd=/dev/mtd0 - attach MTD device "
+ "/dev/mtd0.\n"
+ "Example 2: mtd=content,1984 mtd=4 - attach MTD device "
"with name \"content\" using VID header offset 1984, and "
"MTD device number 4 with default VID header offset.");
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index f237ddbb2713..111ea41c4ecd 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -853,7 +853,6 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd,
break;
}
- req.name[req.name_len] = '\0';
err = verify_mkvol_req(ubi, &req);
if (err)
break;
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index f30bcb372c05..17a107129726 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -96,8 +96,11 @@ void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len);
+int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
+ int offset, int len);
#else
#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
+#define ubi_dbg_check_write(ubi, buf, pnum, offset, len) 0
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT
@@ -176,6 +179,7 @@ static inline int ubi_dbg_is_erase_failure(void)
#define ubi_dbg_is_write_failure() 0
#define ubi_dbg_is_erase_failure() 0
#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
+#define ubi_dbg_check_write(ubi, buf, pnum, offset, len) 0
#endif /* !CONFIG_MTD_UBI_DEBUG */
#endif /* !__UBI_DEBUG_H__ */
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 8aa51e7a6a7d..b4ecc84c7549 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -143,7 +143,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
err = paranoid_check_not_bad(ubi, pnum);
if (err)
- return err > 0 ? -EINVAL : err;
+ return err;
addr = (loff_t)pnum * ubi->peb_size + offset;
retry:
@@ -236,12 +236,12 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
err = paranoid_check_not_bad(ubi, pnum);
if (err)
- return err > 0 ? -EINVAL : err;
+ return err;
/* The area we are writing to has to contain all 0xFF bytes */
err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
if (err)
- return err > 0 ? -EINVAL : err;
+ return err;
if (offset >= ubi->leb_start) {
/*
@@ -250,10 +250,10 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
*/
err = paranoid_check_peb_ec_hdr(ubi, pnum);
if (err)
- return err > 0 ? -EINVAL : err;
+ return err;
err = paranoid_check_peb_vid_hdr(ubi, pnum);
if (err)
- return err > 0 ? -EINVAL : err;
+ return err;
}
if (ubi_dbg_is_write_failure()) {
@@ -273,6 +273,21 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
} else
ubi_assert(written == len);
+ if (!err) {
+ err = ubi_dbg_check_write(ubi, buf, pnum, offset, len);
+ if (err)
+ return err;
+
+ /*
+ * Since we always write sequentially, the rest of the PEB has
+ * to contain only 0xFF bytes.
+ */
+ offset += len;
+ len = ubi->peb_size - offset;
+ if (len)
+ err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
+ }
+
return err;
}
@@ -348,7 +363,7 @@ retry:
err = ubi_dbg_check_all_ff(ubi, pnum, 0, ubi->peb_size);
if (err)
- return err > 0 ? -EINVAL : err;
+ return err;
if (ubi_dbg_is_erase_failure() && !err) {
dbg_err("cannot erase PEB %d (emulated)", pnum);
@@ -542,7 +557,7 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
err = paranoid_check_not_bad(ubi, pnum);
if (err != 0)
- return err > 0 ? -EINVAL : err;
+ return err;
if (ubi->ro_mode) {
ubi_err("read-only mode");
@@ -819,7 +834,7 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
if (err)
- return -EINVAL;
+ return err;
err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize);
return err;
@@ -1083,7 +1098,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
err = paranoid_check_peb_ec_hdr(ubi, pnum);
if (err)
- return err > 0 ? -EINVAL : err;
+ return err;
vid_hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
vid_hdr->version = UBI_VERSION;
@@ -1092,7 +1107,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
if (err)
- return -EINVAL;
+ return err;
p = (char *)vid_hdr - ubi->vid_hdr_shift;
err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset,
@@ -1107,8 +1122,8 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
* @ubi: UBI device description object
* @pnum: physical eraseblock number to check
*
- * This function returns zero if the physical eraseblock is good, a positive
- * number if it is bad and a negative error code if an error occurred.
+ * This function returns zero if the physical eraseblock is good, %-EINVAL if
+ * it is bad and a negative error code if an error occurred.
*/
static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
{
@@ -1120,7 +1135,7 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
ubi_err("paranoid check failed for PEB %d", pnum);
ubi_dbg_dump_stack();
- return err;
+ return err > 0 ? -EINVAL : err;
}
/**
@@ -1130,7 +1145,7 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
* @ec_hdr: the erase counter header to check
*
* This function returns zero if the erase counter header contains valid
- * values, and %1 if not.
+ * values, and %-EINVAL if not.
*/
static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
const struct ubi_ec_hdr *ec_hdr)
@@ -1156,7 +1171,7 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
fail:
ubi_dbg_dump_ec_hdr(ec_hdr);
ubi_dbg_dump_stack();
- return 1;
+ return -EINVAL;
}
/**
@@ -1164,8 +1179,8 @@ fail:
* @ubi: UBI device description object
* @pnum: the physical eraseblock number to check
*
- * This function returns zero if the erase counter header is all right, %1 if
- * not, and a negative error code if an error occurred.
+ * This function returns zero if the erase counter header is all right and and
+ * a negative error code if not or if an error occurred.
*/
static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
{
@@ -1188,7 +1203,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
ubi_err("paranoid check failed for PEB %d", pnum);
ubi_dbg_dump_ec_hdr(ec_hdr);
ubi_dbg_dump_stack();
- err = 1;
+ err = -EINVAL;
goto exit;
}
@@ -1206,7 +1221,7 @@ exit:
* @vid_hdr: the volume identifier header to check
*
* This function returns zero if the volume identifier header is all right, and
- * %1 if not.
+ * %-EINVAL if not.
*/
static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
const struct ubi_vid_hdr *vid_hdr)
@@ -1233,7 +1248,7 @@ fail:
ubi_err("paranoid check failed for PEB %d", pnum);
ubi_dbg_dump_vid_hdr(vid_hdr);
ubi_dbg_dump_stack();
- return 1;
+ return -EINVAL;
}
@@ -1243,7 +1258,7 @@ fail:
* @pnum: the physical eraseblock number to check
*
* This function returns zero if the volume identifier header is all right,
- * %1 if not, and a negative error code if an error occurred.
+ * and a negative error code if not or if an error occurred.
*/
static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
{
@@ -1270,7 +1285,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
ubi_err("paranoid check failed for PEB %d", pnum);
ubi_dbg_dump_vid_hdr(vid_hdr);
ubi_dbg_dump_stack();
- err = 1;
+ err = -EINVAL;
goto exit;
}
@@ -1282,6 +1297,61 @@ exit:
}
/**
+ * ubi_dbg_check_write - make sure write succeeded.
+ * @ubi: UBI device description object
+ * @buf: buffer with data which were written
+ * @pnum: physical eraseblock number the data were written to
+ * @offset: offset within the physical eraseblock the data were written to
+ * @len: how many bytes were written
+ *
+ * This functions reads data which were recently written and compares it with
+ * the original data buffer - the data have to match. Returns zero if the data
+ * match and a negative error code if not or in case of failure.
+ */
+int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
+ int offset, int len)
+{
+ int err, i;
+
+ mutex_lock(&ubi->dbg_buf_mutex);
+ err = ubi_io_read(ubi, ubi->dbg_peb_buf, pnum, offset, len);
+ if (err)
+ goto out_unlock;
+
+ for (i = 0; i < len; i++) {
+ uint8_t c = ((uint8_t *)buf)[i];
+ uint8_t c1 = ((uint8_t *)ubi->dbg_peb_buf)[i];
+ int dump_len;
+
+ if (c == c1)
+ continue;
+
+ ubi_err("paranoid check failed for PEB %d:%d, len %d",
+ pnum, offset, len);
+ ubi_msg("data differ at position %d", i);
+ dump_len = max_t(int, 128, len - i);
+ ubi_msg("hex dump of the original buffer from %d to %d",
+ i, i + dump_len);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+ buf + i, dump_len, 1);
+ ubi_msg("hex dump of the read buffer from %d to %d",
+ i, i + dump_len);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+ ubi->dbg_peb_buf + i, dump_len, 1);
+ ubi_dbg_dump_stack();
+ err = -EINVAL;
+ goto out_unlock;
+ }
+ mutex_unlock(&ubi->dbg_buf_mutex);
+
+ return 0;
+
+out_unlock:
+ mutex_unlock(&ubi->dbg_buf_mutex);
+ return err;
+}
+
+/**
* ubi_dbg_check_all_ff - check that a region of flash is empty.
* @ubi: UBI device description object
* @pnum: the physical eraseblock number to check
@@ -1289,8 +1359,8 @@ exit:
* @len: the length of the region to check
*
* This function returns zero if only 0xFF bytes are present at offset
- * @offset of the physical eraseblock @pnum, %1 if not, and a negative error
- * code if an error occurred.
+ * @offset of the physical eraseblock @pnum, and a negative error code if not
+ * or if an error occurred.
*/
int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
{
@@ -1321,7 +1391,7 @@ fail:
ubi_msg("hex dump of the %d-%d region", offset, offset + len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
ubi->dbg_peb_buf, len, 1);
- err = 1;
+ err = -EINVAL;
error:
ubi_dbg_dump_stack();
mutex_unlock(&ubi->dbg_buf_mutex);
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 277786ebaa2c..1361574e2b00 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -291,8 +291,7 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
*/
struct ubi_volume_desc *ubi_open_volume_path(const char *pathname, int mode)
{
- int error, ubi_num, vol_id;
- struct ubi_volume_desc *ret;
+ int error, ubi_num, vol_id, mod;
struct inode *inode;
struct path path;
@@ -306,16 +305,16 @@ struct ubi_volume_desc *ubi_open_volume_path(const char *pathname, int mode)
return ERR_PTR(error);
inode = path.dentry->d_inode;
+ mod = inode->i_mode;
ubi_num = ubi_major2num(imajor(inode));
vol_id = iminor(inode) - 1;
+ path_put(&path);
+ if (!S_ISCHR(mod))
+ return ERR_PTR(-EINVAL);
if (vol_id >= 0 && ubi_num >= 0)
- ret = ubi_open_volume(ubi_num, vol_id, mode);
- else
- ret = ERR_PTR(-ENODEV);
-
- path_put(&path);
- return ret;
+ return ubi_open_volume(ubi_num, vol_id, mode);
+ return ERR_PTR(-ENODEV);
}
EXPORT_SYMBOL_GPL(ubi_open_volume_path);
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 90af61a2c3e4..594184bbd56a 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -974,11 +974,8 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
seb->ec = si->mean_ec;
err = paranoid_check_si(ubi, si);
- if (err) {
- if (err > 0)
- err = -EINVAL;
+ if (err)
goto out_vidh;
- }
ubi_free_vid_hdr(ubi, vidh);
kfree(ech);
@@ -1086,8 +1083,8 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
* @ubi: UBI device description object
* @si: scanning information
*
- * This function returns zero if the scanning information is all right, %1 if
- * not and a negative error code if an error occurred.
+ * This function returns zero if the scanning information is all right, and a
+ * negative error code if not or if an error occurred.
*/
static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
{
@@ -1346,7 +1343,7 @@ bad_vid_hdr:
out:
ubi_dbg_dump_stack();
- return 1;
+ return -EINVAL;
}
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index c1d7b880c795..425bf5a3edd4 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -155,6 +155,7 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
if (err)
return err;
vol->updating = 0;
+ return 0;
}
vol->upd_buf = vmalloc(ubi->leb_size);
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index 1afc61e7455d..40044028d682 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -566,6 +566,7 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
vol->alignment = be32_to_cpu(vtbl[i].alignment);
vol->data_pad = be32_to_cpu(vtbl[i].data_pad);
+ vol->upd_marker = vtbl[i].upd_marker;
vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ?
UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
vol->name_len = be16_to_cpu(vtbl[i].name_len);
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 600c7229d5cf..f64ddabd4ac8 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -464,7 +464,7 @@ retry:
ubi->peb_size - ubi->vid_hdr_aloffset);
if (err) {
ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum);
- return err > 0 ? -EINVAL : err;
+ return err;
}
return e->pnum;
@@ -513,7 +513,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
dbg_wl("erase PEB %d, old EC %llu", e->pnum, ec);
err = paranoid_check_ec(ubi, e->pnum, e->ec);
- if (err > 0)
+ if (err)
return -EINVAL;
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
@@ -1572,8 +1572,7 @@ void ubi_wl_close(struct ubi_device *ubi)
* @ec: the erase counter to check
*
* This function returns zero if the erase counter of physical eraseblock @pnum
- * is equivalent to @ec, %1 if not, and a negative error code if an error
- * occurred.
+ * is equivalent to @ec, and a negative error code if not or if an error occurred.
*/
static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
{
@@ -1611,8 +1610,8 @@ out_free:
* @e: the wear-leveling entry to check
* @root: the root of the tree
*
- * This function returns zero if @e is in the @root RB-tree and %1 if it is
- * not.
+ * This function returns zero if @e is in the @root RB-tree and %-EINVAL if it
+ * is not.
*/
static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
struct rb_root *root)
@@ -1623,7 +1622,7 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
ubi_err("paranoid check failed for PEB %d, EC %d, RB-tree %p ",
e->pnum, e->ec, root);
ubi_dbg_dump_stack();
- return 1;
+ return -EINVAL;
}
/**
@@ -1632,7 +1631,7 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
* @ubi: UBI device description object
* @e: the wear-leveling entry to check
*
- * This function returns zero if @e is in @ubi->pq and %1 if it is not.
+ * This function returns zero if @e is in @ubi->pq and %-EINVAL if it is not.
*/
static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e)
{
@@ -1647,6 +1646,6 @@ static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e)
ubi_err("paranoid check failed for PEB %d, EC %d, Protect queue",
e->pnum, e->ec);
ubi_dbg_dump_stack();
- return 1;
+ return -EINVAL;
}
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 4d4cad393dce..b6de7b1e2a5c 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -812,7 +812,7 @@ static void set_multicast_list(struct net_device *dev)
if (dev->flags & IFF_PROMISC) {
outb(RX_PROM, RX_CMD);
inb(RX_STATUS);
- } else if (dev->mc_list || dev->flags & IFF_ALLMULTI) {
+ } else if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) {
/* Multicast or all multicast is the same */
outb(RX_MULT, RX_CMD);
inb(RX_STATUS); /* Clear status. */
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 9257d7ce0378..04b5bba19021 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -1216,7 +1216,7 @@ static int elp_close(struct net_device *dev)
static void elp_set_mc_list(struct net_device *dev)
{
elp_device *adapter = netdev_priv(dev);
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
int i;
unsigned long flags;
@@ -1229,11 +1229,10 @@ static void elp_set_mc_list(struct net_device *dev)
/* send a "load multicast list" command to the board, max 10 addrs/cmd */
/* if num_addrs==0 the list will be cleared */
adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST;
- adapter->tx_pcb.length = 6 * dev->mc_count;
- for (i = 0; i < dev->mc_count; i++) {
- memcpy(adapter->tx_pcb.data.multicast[i], dmi->dmi_addr, 6);
- dmi = dmi->next;
- }
+ adapter->tx_pcb.length = 6 * netdev_mc_count(dev);
+ i = 0;
+ netdev_for_each_mc_addr(dmi, dev)
+ memcpy(adapter->tx_pcb.data.multicast[i++], dmi->dmi_addr, 6);
adapter->got[CMD_LOAD_MULTICAST_LIST] = 0;
if (!send_pcb(dev, &adapter->tx_pcb))
pr_err("%s: couldn't send set_multicast command\n", dev->name);
@@ -1244,7 +1243,7 @@ static void elp_set_mc_list(struct net_device *dev)
TIMEOUT_MSG(__LINE__);
}
}
- if (dev->mc_count)
+ if (!netdev_mc_empty(dev))
adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI;
else /* num_addrs == 0 */
adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 9d85efce5916..902435a76466 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -1111,12 +1111,14 @@ set_multicast_list(struct net_device *dev)
unsigned long flags;
struct el3_private *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
+ int mc_count = netdev_mc_count(dev);
if (el3_debug > 1) {
static int old;
- if (old != dev->mc_count) {
- old = dev->mc_count;
- pr_debug("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count);
+ if (old != mc_count) {
+ old = mc_count;
+ pr_debug("%s: Setting Rx mode to %d addresses.\n",
+ dev->name, mc_count);
}
}
spin_lock_irqsave(&lp->lock, flags);
@@ -1124,7 +1126,7 @@ set_multicast_list(struct net_device *dev)
outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
ioaddr + EL3_CMD);
}
- else if (dev->mc_count || (dev->flags&IFF_ALLMULTI)) {
+ else if (mc_count || (dev->flags&IFF_ALLMULTI)) {
outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD);
}
else
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 063b049ffe55..1e898b1c8068 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -1536,7 +1536,7 @@ static void set_rx_mode(struct net_device *dev)
pr_debug("%s: Setting promiscuous mode.\n",
dev->name);
new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm;
- } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {
+ } else if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) {
new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast;
} else
new_mode = SetRxFilter | RxStation | RxBroadcast;
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index 27d80ca5e4c0..beed4fa10c6e 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -625,8 +625,8 @@ static int init586(struct net_device *dev)
volatile struct iasetup_cmd_struct *ias_cmd;
volatile struct tdr_cmd_struct *tdr_cmd;
volatile struct mcsetup_cmd_struct *mc_cmd;
- struct dev_mc_list *dmi = dev->mc_list;
- int num_addrs = dev->mc_count;
+ struct dev_mc_list *dmi;
+ int num_addrs = netdev_mc_count(dev);
ptr = (void *) ((char *) p->scb + sizeof(struct scb_struct));
@@ -771,7 +771,7 @@ static int init586(struct net_device *dev)
* Multicast setup
*/
- if (dev->mc_count) {
+ if (num_addrs) {
/* I don't understand this: do we really need memory after the init? */
int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
if (len <= 0) {
@@ -787,10 +787,9 @@ static int init586(struct net_device *dev)
mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST;
mc_cmd->cmd_link = 0xffff;
mc_cmd->mc_cnt = num_addrs * 6;
- for (i = 0; i < num_addrs; i++) {
- memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr, 6);
- dmi = dmi->next;
- }
+ i = 0;
+ netdev_for_each_mc_addr(dmi, dev)
+ memcpy((char *) mc_cmd->mc_list[i++], dmi->dmi_addr, 6);
p->scb->cbl_offset = make16(mc_cmd);
p->scb->cmd = CUC_START;
elmc_id_attn586();
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index 36c4191e7bca..5c07b147ec99 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -1526,32 +1526,29 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
if ((dev->flags&IFF_PROMISC) ||
(dev->flags&IFF_ALLMULTI) ||
- dev->mc_count > 10)
+ netdev_mc_count(dev) > 10)
/* Enable promiscuous mode */
filt |= 1;
- else if(dev->mc_count)
+ else if (!netdev_mc_empty(dev))
{
unsigned char block[62];
unsigned char *bp;
- struct dev_mc_list *dmc=dev->mc_list;
-
- int i;
+ struct dev_mc_list *dmc;
if(retry==0)
lp->mc_list_valid = 0;
if(!lp->mc_list_valid)
{
block[1]=0;
- block[0]=dev->mc_count;
+ block[0]=netdev_mc_count(dev);
bp=block+2;
- for(i=0;i<dev->mc_count;i++)
- {
+ netdev_for_each_mc_addr(dmc, dev) {
memcpy(bp, dmc->dmi_addr, 6);
bp+=6;
- dmc=dmc->next;
}
- if(mc32_command_nowait(dev, 2, block, 2+6*dev->mc_count)==-1)
+ if(mc32_command_nowait(dev, 2, block,
+ 2+6*netdev_mc_count(dev))==-1)
{
lp->mc_reload_wait = 1;
return;
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 39db0e96815d..f965431f4924 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -375,7 +375,7 @@ static struct vortex_chip_info {
};
-static struct pci_device_id vortex_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(vortex_pci_tbl) = {
{ 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 },
{ 0x10B7, 0x5920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C592 },
{ 0x10B7, 0x5970, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C597 },
@@ -2970,7 +2970,7 @@ static void set_rx_mode(struct net_device *dev)
if (vortex_debug > 3)
pr_notice("%s: Setting promiscuous mode.\n", dev->name);
new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
- } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {
+ } else if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) {
new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
} else
new_mode = SetRxFilter | RxStation | RxBroadcast;
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index b1e5764628c6..4e9a5a20b6a6 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -595,9 +595,8 @@ static void lance_load_multicast (struct net_device *dev)
struct lance_private *lp = netdev_priv(dev);
volatile struct lance_init_block *ib = lp->init_block;
volatile u16 *mcast_table = (u16 *)&ib->filter;
- struct dev_mc_list *dmi=dev->mc_list;
+ struct dev_mc_list *dmi;
char *addrs;
- int i;
u32 crc;
/* set all multicast bits */
@@ -611,9 +610,8 @@ static void lance_load_multicast (struct net_device *dev)
ib->filter [1] = 0;
/* Add addresses */
- for (i = 0; i < dev->mc_count; i++){
+ netdev_for_each_mc_addr(dmi, dev) {
addrs = dmi->dmi_addr;
- dmi = dmi->next;
/* multicast address? */
if (!(*addrs & 1))
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 3f452bcbfb9e..3d4406b16658 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -46,6 +46,8 @@
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define DRV_NAME "8139cp"
#define DRV_VERSION "1.3"
#define DRV_RELDATE "Mar 22, 2004"
@@ -104,8 +106,6 @@ static int multicast_filter_limit = 32;
module_param(multicast_filter_limit, int, 0);
MODULE_PARM_DESC (multicast_filter_limit, "8139cp: maximum number of filtered multicast addresses");
-#define PFX DRV_NAME ": "
-
#define CP_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
NETIF_MSG_PROBE | \
NETIF_MSG_LINK)
@@ -394,7 +394,7 @@ static int cp_get_eeprom(struct net_device *dev,
static int cp_set_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom, u8 *data);
-static struct pci_device_id cp_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(cp_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139), },
{ PCI_DEVICE(PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322), },
{ },
@@ -470,9 +470,8 @@ static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb,
static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail,
u32 status, u32 len)
{
- if (netif_msg_rx_err (cp))
- pr_debug("%s: rx err, slot %d status 0x%x len %d\n",
- cp->dev->name, rx_tail, status, len);
+ netif_dbg(cp, rx_err, cp->dev, "rx err, slot %d status 0x%x len %d\n",
+ rx_tail, status, len);
cp->dev->stats.rx_errors++;
if (status & RxErrFrame)
cp->dev->stats.rx_frame_errors++;
@@ -545,9 +544,8 @@ rx_status_loop:
goto rx_next;
}
- if (netif_msg_rx_status(cp))
- pr_debug("%s: rx slot %d status 0x%x len %d\n",
- dev->name, rx_tail, status, len);
+ netif_dbg(cp, rx_status, dev, "rx slot %d status 0x%x len %d\n",
+ rx_tail, status, len);
new_skb = netdev_alloc_skb_ip_align(dev, buflen);
if (!new_skb) {
@@ -621,9 +619,8 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
if (!status || (status == 0xFFFF))
return IRQ_NONE;
- if (netif_msg_intr(cp))
- pr_debug("%s: intr, status %04x cmd %02x cpcmd %04x\n",
- dev->name, status, cpr8(Cmd), cpr16(CpCmd));
+ netif_dbg(cp, intr, dev, "intr, status %04x cmd %02x cpcmd %04x\n",
+ status, cpr8(Cmd), cpr16(CpCmd));
cpw16(IntrStatus, status & ~cp_rx_intr_mask);
@@ -654,8 +651,8 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
pci_read_config_word(cp->pdev, PCI_STATUS, &pci_status);
pci_write_config_word(cp->pdev, PCI_STATUS, pci_status);
- pr_err("%s: PCI bus error, status=%04x, PCI status=%04x\n",
- dev->name, status, pci_status);
+ netdev_err(dev, "PCI bus error, status=%04x, PCI status=%04x\n",
+ status, pci_status);
/* TODO: reset hardware */
}
@@ -700,9 +697,8 @@ static void cp_tx (struct cp_private *cp)
if (status & LastFrag) {
if (status & (TxError | TxFIFOUnder)) {
- if (netif_msg_tx_err(cp))
- pr_debug("%s: tx err, status 0x%x\n",
- cp->dev->name, status);
+ netif_dbg(cp, tx_err, cp->dev,
+ "tx err, status 0x%x\n", status);
cp->dev->stats.tx_errors++;
if (status & TxOWC)
cp->dev->stats.tx_window_errors++;
@@ -717,8 +713,8 @@ static void cp_tx (struct cp_private *cp)
((status >> TxColCntShift) & TxColCntMask);
cp->dev->stats.tx_packets++;
cp->dev->stats.tx_bytes += skb->len;
- if (netif_msg_tx_done(cp))
- pr_debug("%s: tx done, slot %d\n", cp->dev->name, tx_tail);
+ netif_dbg(cp, tx_done, cp->dev,
+ "tx done, slot %d\n", tx_tail);
}
dev_kfree_skb_irq(skb);
}
@@ -752,8 +748,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
if (TX_BUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev);
spin_unlock_irqrestore(&cp->lock, intr_flags);
- pr_err(PFX "%s: BUG! Tx Ring full when queue awake!\n",
- dev->name);
+ netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
return NETDEV_TX_BUSY;
}
@@ -878,9 +873,8 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
wmb();
}
cp->tx_head = entry;
- if (netif_msg_tx_queued(cp))
- pr_debug("%s: tx queued, slot %d, skblen %d\n",
- dev->name, entry, skb->len);
+ netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen %d\n",
+ entry, skb->len);
if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
netif_stop_queue(dev);
@@ -899,7 +893,7 @@ static void __cp_set_rx_mode (struct net_device *dev)
{
struct cp_private *cp = netdev_priv(dev);
u32 mc_filter[2]; /* Multicast hash filter */
- int i, rx_mode;
+ int rx_mode;
u32 tmp;
/* Note: do not reorder, GCC is clever about common statements. */
@@ -909,7 +903,7 @@ static void __cp_set_rx_mode (struct net_device *dev)
AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
AcceptAllPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
- } else if ((dev->mc_count > multicast_filter_limit) ||
+ } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
(dev->flags & IFF_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
@@ -918,8 +912,7 @@ static void __cp_set_rx_mode (struct net_device *dev)
struct dev_mc_list *mclist;
rx_mode = AcceptBroadcast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
@@ -993,7 +986,7 @@ static void cp_reset_hw (struct cp_private *cp)
schedule_timeout_uninterruptible(10);
}
- pr_err("%s: hardware reset timeout\n", cp->dev->name);
+ netdev_err(cp->dev, "hardware reset timeout\n");
}
static inline void cp_start_hw (struct cp_private *cp)
@@ -1160,8 +1153,7 @@ static int cp_open (struct net_device *dev)
struct cp_private *cp = netdev_priv(dev);
int rc;
- if (netif_msg_ifup(cp))
- pr_debug("%s: enabling interface\n", dev->name);
+ netif_dbg(cp, ifup, dev, "enabling interface\n");
rc = cp_alloc_rings(cp);
if (rc)
@@ -1195,8 +1187,7 @@ static int cp_close (struct net_device *dev)
napi_disable(&cp->napi);
- if (netif_msg_ifdown(cp))
- pr_debug("%s: disabling interface\n", dev->name);
+ netif_dbg(cp, ifdown, dev, "disabling interface\n");
spin_lock_irqsave(&cp->lock, flags);
@@ -1219,9 +1210,9 @@ static void cp_tx_timeout(struct net_device *dev)
unsigned long flags;
int rc;
- pr_warning("%s: Transmit timeout, status %2x %4x %4x %4x\n",
- dev->name, cpr8(Cmd), cpr16(CpCmd),
- cpr16(IntrStatus), cpr16(IntrMask));
+ netdev_warn(dev, "Transmit timeout, status %2x %4x %4x %4x\n",
+ cpr8(Cmd), cpr16(CpCmd),
+ cpr16(IntrStatus), cpr16(IntrMask));
spin_lock_irqsave(&cp->lock, flags);
@@ -1874,8 +1865,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pdev->revision < 0x20) {
dev_info(&pdev->dev,
- "This (id %04x:%04x rev %02x) is not an 8139C+ compatible chip, use 8139too\n",
- pdev->vendor, pdev->device, pdev->revision);
+ "This (id %04x:%04x rev %02x) is not an 8139C+ compatible chip, use 8139too\n",
+ pdev->vendor, pdev->device, pdev->revision);
return -ENODEV;
}
@@ -1933,14 +1924,13 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
dev_err(&pdev->dev,
- "No usable DMA configuration, aborting.\n");
+ "No usable DMA configuration, aborting\n");
goto err_out_res;
}
rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
dev_err(&pdev->dev,
- "No usable consistent DMA configuration, "
- "aborting.\n");
+ "No usable consistent DMA configuration, aborting\n");
goto err_out_res;
}
}
@@ -1952,7 +1942,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!regs) {
rc = -EIO;
dev_err(&pdev->dev, "Cannot map PCI MMIO (%Lx@%Lx)\n",
- (unsigned long long)pci_resource_len(pdev, 1),
+ (unsigned long long)pci_resource_len(pdev, 1),
(unsigned long long)pciaddr);
goto err_out_res;
}
@@ -1990,11 +1980,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
goto err_out_iomap;
- pr_info("%s: RTL-8139C+ at 0x%lx, %pM, IRQ %d\n",
- dev->name,
- dev->base_addr,
- dev->dev_addr,
- dev->irq);
+ netdev_info(dev, "RTL-8139C+ at 0x%lx, %pM, IRQ %d\n",
+ dev->base_addr, dev->dev_addr, dev->irq);
pci_set_drvdata(pdev, dev);
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 25f7339daabd..b4efc913978b 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -89,6 +89,8 @@
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define DRV_NAME "8139too"
#define DRV_VERSION "0.9.28"
@@ -111,7 +113,6 @@
#include <asm/irq.h>
#define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION
-#define PFX DRV_NAME ": "
/* Default Message level */
#define RTL8139_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
@@ -130,9 +131,9 @@
# define assert(expr) do {} while (0)
#else
# define assert(expr) \
- if(unlikely(!(expr))) { \
- pr_err("Assertion failed! %s,%s,%s,line=%d\n", \
- #expr, __FILE__, __func__, __LINE__); \
+ if (unlikely(!(expr))) { \
+ pr_err("Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr, __FILE__, __func__, __LINE__); \
}
#endif
@@ -231,7 +232,7 @@ static const struct {
};
-static struct pci_device_id rtl8139_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(rtl8139_pci_tbl) = {
{0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
@@ -957,7 +958,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
pdev->device == PCI_DEVICE_ID_REALTEK_8139 &&
pdev->subsystem_vendor == PCI_VENDOR_ID_ATHEROS &&
pdev->subsystem_device == PCI_DEVICE_ID_REALTEK_8139) {
- pr_info("8139too: OQO Model 2 detected. Forcing PIO\n");
+ pr_info("OQO Model 2 detected. Forcing PIO\n");
use_io = 1;
}
@@ -1010,21 +1011,19 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
tp->mii.reg_num_mask = 0x1f;
/* dev is fully set up and ready to use now */
- pr_debug("about to register device named %s (%p)...\n", dev->name, dev);
+ pr_debug("about to register device named %s (%p)...\n",
+ dev->name, dev);
i = register_netdev (dev);
if (i) goto err_out;
pci_set_drvdata (pdev, dev);
- pr_info("%s: %s at 0x%lx, %pM, IRQ %d\n",
- dev->name,
- board_info[ent->driver_data].name,
- dev->base_addr,
- dev->dev_addr,
- dev->irq);
+ netdev_info(dev, "%s at 0x%lx, %pM, IRQ %d\n",
+ board_info[ent->driver_data].name,
+ dev->base_addr, dev->dev_addr, dev->irq);
- pr_debug("%s: Identified 8139 chip type '%s'\n",
- dev->name, rtl_chip_info[tp->chipset].name);
+ netdev_dbg(dev, "Identified 8139 chip type '%s'\n",
+ rtl_chip_info[tp->chipset].name);
/* Find the connected MII xcvrs.
Doing this in open() would allow detecting external xcvrs later, but
@@ -1037,13 +1036,12 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
if (mii_status != 0xffff && mii_status != 0x0000) {
u16 advertising = mdio_read(dev, phy, 4);
tp->phys[phy_idx++] = phy;
- pr_info("%s: MII transceiver %d status 0x%4.4x advertising %4.4x.\n",
- dev->name, phy, mii_status, advertising);
+ netdev_info(dev, "MII transceiver %d status 0x%04x advertising %04x\n",
+ phy, mii_status, advertising);
}
}
if (phy_idx == 0) {
- pr_info("%s: No MII transceivers found! Assuming SYM transceiver.\n",
- dev->name);
+ netdev_info(dev, "No MII transceivers found! Assuming SYM transceiver\n");
tp->phys[0] = 32;
}
} else
@@ -1062,15 +1060,15 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0)
tp->mii.full_duplex = full_duplex[board_idx];
if (tp->mii.full_duplex) {
- pr_info("%s: Media type forced to Full Duplex.\n", dev->name);
+ netdev_info(dev, "Media type forced to Full Duplex\n");
/* Changing the MII-advertised media because might prevent
re-connection. */
tp->mii.force_media = 1;
}
if (tp->default_port) {
- pr_info(" Forcing %dMbps %s-duplex operation.\n",
- (option & 0x20 ? 100 : 10),
- (option & 0x10 ? "full" : "half"));
+ netdev_info(dev, " Forcing %dMbps %s-duplex operation\n",
+ (option & 0x20 ? 100 : 10),
+ (option & 0x10 ? "full" : "half"));
mdio_write(dev, tp->phys[0], 0,
((option & 0x20) ? 0x2000 : 0) | /* 100Mbps? */
((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
@@ -1330,12 +1328,12 @@ static int rtl8139_open (struct net_device *dev)
rtl8139_hw_start (dev);
netif_start_queue (dev);
- if (netif_msg_ifup(tp))
- pr_debug("%s: rtl8139_open() ioaddr %#llx IRQ %d"
- " GP Pins %2.2x %s-duplex.\n", dev->name,
- (unsigned long long)pci_resource_start (tp->pci_dev, 1),
- dev->irq, RTL_R8 (MediaStatus),
- tp->mii.full_duplex ? "full" : "half");
+ netif_dbg(tp, ifup, dev,
+ "%s() ioaddr %#llx IRQ %d GP Pins %02x %s-duplex\n",
+ __func__,
+ (unsigned long long)pci_resource_start (tp->pci_dev, 1),
+ dev->irq, RTL_R8 (MediaStatus),
+ tp->mii.full_duplex ? "full" : "half");
rtl8139_start_thread(tp);
@@ -1393,7 +1391,7 @@ static void rtl8139_hw_start (struct net_device *dev)
RTL_W8 (Config3, RTL_R8 (Config3) & ~Cfg3_Magic);
}
- pr_debug("init buffer addresses\n");
+ netdev_dbg(dev, "init buffer addresses\n");
/* Lock Config[01234] and BMCR register writes */
RTL_W8 (Cfg9346, Cfg9346_Lock);
@@ -1555,14 +1553,11 @@ static inline void rtl8139_thread_iter (struct net_device *dev,
tp->mii.full_duplex = duplex;
if (mii_lpa) {
- pr_info("%s: Setting %s-duplex based on MII #%d link"
- " partner ability of %4.4x.\n",
- dev->name,
- tp->mii.full_duplex ? "full" : "half",
- tp->phys[0], mii_lpa);
+ netdev_info(dev, "Setting %s-duplex based on MII #%d link partner ability of %04x\n",
+ tp->mii.full_duplex ? "full" : "half",
+ tp->phys[0], mii_lpa);
} else {
- pr_info("%s: media is unconnected, link down, or incompatible connection\n",
- dev->name);
+ netdev_info(dev, "media is unconnected, link down, or incompatible connection\n");
}
#if 0
RTL_W8 (Cfg9346, Cfg9346_Unlock);
@@ -1576,13 +1571,12 @@ static inline void rtl8139_thread_iter (struct net_device *dev,
rtl8139_tune_twister (dev, tp);
- pr_debug("%s: Media selection tick, Link partner %4.4x.\n",
- dev->name, RTL_R16 (NWayLPAR));
- pr_debug("%s: Other registers are IntMask %4.4x IntStatus %4.4x\n",
- dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus));
- pr_debug("%s: Chip config %2.2x %2.2x.\n",
- dev->name, RTL_R8 (Config0),
- RTL_R8 (Config1));
+ netdev_dbg(dev, "Media selection tick, Link partner %04x\n",
+ RTL_R16(NWayLPAR));
+ netdev_dbg(dev, "Other registers are IntMask %04x IntStatus %04x\n",
+ RTL_R16(IntrMask), RTL_R16(IntrStatus));
+ netdev_dbg(dev, "Chip config %02x %02x\n",
+ RTL_R8(Config0), RTL_R8(Config1));
}
static void rtl8139_thread (struct work_struct *work)
@@ -1640,17 +1634,17 @@ static void rtl8139_tx_timeout_task (struct work_struct *work)
int i;
u8 tmp8;
- pr_debug("%s: Transmit timeout, status %2.2x %4.4x %4.4x media %2.2x.\n",
- dev->name, RTL_R8 (ChipCmd),
- RTL_R16(IntrStatus), RTL_R16(IntrMask), RTL_R8(MediaStatus));
+ netdev_dbg(dev, "Transmit timeout, status %02x %04x %04x media %02x\n",
+ RTL_R8(ChipCmd), RTL_R16(IntrStatus),
+ RTL_R16(IntrMask), RTL_R8(MediaStatus));
/* Emit info to figure out what went wrong. */
- pr_debug("%s: Tx queue start entry %ld dirty entry %ld.\n",
- dev->name, tp->cur_tx, tp->dirty_tx);
+ netdev_dbg(dev, "Tx queue start entry %ld dirty entry %ld\n",
+ tp->cur_tx, tp->dirty_tx);
for (i = 0; i < NUM_TX_DESC; i++)
- pr_debug("%s: Tx descriptor %d is %8.8lx.%s\n",
- dev->name, i, RTL_R32 (TxStatus0 + (i * 4)),
- i == tp->dirty_tx % NUM_TX_DESC ?
- " (queue head)" : "");
+ netdev_dbg(dev, "Tx descriptor %d is %08lx%s\n",
+ i, RTL_R32(TxStatus0 + (i * 4)),
+ i == tp->dirty_tx % NUM_TX_DESC ?
+ " (queue head)" : "");
tp->xstats.tx_timeouts++;
@@ -1729,9 +1723,8 @@ static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb,
netif_stop_queue (dev);
spin_unlock_irqrestore(&tp->lock, flags);
- if (netif_msg_tx_queued(tp))
- pr_debug("%s: Queued Tx packet size %u to slot %d.\n",
- dev->name, len, entry);
+ netif_dbg(tp, tx_queued, dev, "Queued Tx packet size %u to slot %d\n",
+ len, entry);
return NETDEV_TX_OK;
}
@@ -1760,9 +1753,8 @@ static void rtl8139_tx_interrupt (struct net_device *dev,
/* Note: TxCarrierLost is always asserted at 100mbps. */
if (txstatus & (TxOutOfWindow | TxAborted)) {
/* There was an major error, log it. */
- if (netif_msg_tx_err(tp))
- pr_debug("%s: Transmit error, Tx status %8.8x.\n",
- dev->name, txstatus);
+ netif_dbg(tp, tx_err, dev, "Transmit error, Tx status %08x\n",
+ txstatus);
dev->stats.tx_errors++;
if (txstatus & TxAborted) {
dev->stats.tx_aborted_errors++;
@@ -1792,8 +1784,8 @@ static void rtl8139_tx_interrupt (struct net_device *dev,
#ifndef RTL8139_NDEBUG
if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
- pr_err("%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
- dev->name, dirty_tx, tp->cur_tx);
+ netdev_err(dev, "Out-of-sync dirty pointer, %ld vs. %ld\n",
+ dirty_tx, tp->cur_tx);
dirty_tx += NUM_TX_DESC;
}
#endif /* RTL8139_NDEBUG */
@@ -1816,14 +1808,13 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
int tmp_work;
#endif
- if (netif_msg_rx_err (tp))
- pr_debug("%s: Ethernet frame had errors, status %8.8x.\n",
- dev->name, rx_status);
+ netif_dbg(tp, rx_err, dev, "Ethernet frame had errors, status %08x\n",
+ rx_status);
dev->stats.rx_errors++;
if (!(rx_status & RxStatusOK)) {
if (rx_status & RxTooLong) {
- pr_debug("%s: Oversized Ethernet frame, status %4.4x!\n",
- dev->name, rx_status);
+ netdev_dbg(dev, "Oversized Ethernet frame, status %04x!\n",
+ rx_status);
/* A.C.: The chip hangs here. */
}
if (rx_status & (RxBadSymbol | RxBadAlign))
@@ -1855,7 +1846,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
break;
}
if (tmp_work <= 0)
- pr_warning(PFX "rx stop wait too long\n");
+ netdev_warn(dev, "rx stop wait too long\n");
/* restart receive */
tmp_work = 200;
while (--tmp_work > 0) {
@@ -1866,7 +1857,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
break;
}
if (tmp_work <= 0)
- pr_warning(PFX "tx/rx enable wait too long\n");
+ netdev_warn(dev, "tx/rx enable wait too long\n");
/* and reinitialize all rx related registers */
RTL_W8_F (Cfg9346, Cfg9346_Unlock);
@@ -1877,7 +1868,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
RTL_W32 (RxConfig, tp->rx_config);
tp->cur_rx = 0;
- pr_debug("init buffer addresses\n");
+ netdev_dbg(dev, "init buffer addresses\n");
/* Lock Config[01234] and BMCR register writes */
RTL_W8 (Cfg9346, Cfg9346_Lock);
@@ -1931,10 +1922,9 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
unsigned int cur_rx = tp->cur_rx;
unsigned int rx_size = 0;
- pr_debug("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
- " free to %4.4x, Cmd %2.2x.\n", dev->name, (u16)cur_rx,
- RTL_R16 (RxBufAddr),
- RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
+ netdev_dbg(dev, "In %s(), current %04x BufAddr %04x, free to %04x, Cmd %02x\n",
+ __func__, (u16)cur_rx,
+ RTL_R16(RxBufAddr), RTL_R16(RxBufPtr), RTL_R8(ChipCmd));
while (netif_running(dev) && received < budget &&
(RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
@@ -1950,19 +1940,12 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
rx_size = rx_status >> 16;
pkt_size = rx_size - 4;
- if (netif_msg_rx_status(tp))
- pr_debug("%s: rtl8139_rx() status %4.4x, size %4.4x,"
- " cur %4.4x.\n", dev->name, rx_status,
- rx_size, cur_rx);
+ netif_dbg(tp, rx_status, dev, "%s() status %04x, size %04x, cur %04x\n",
+ __func__, rx_status, rx_size, cur_rx);
#if RTL8139_DEBUG > 2
- {
- int i;
- pr_debug("%s: Frame contents ", dev->name);
- for (i = 0; i < 70; i++)
- pr_cont(" %2.2x",
- rx_ring[ring_offset + i]);
- pr_cont(".\n");
- }
+ print_dump_hex(KERN_DEBUG, "Frame contents: ",
+ DUMP_PREFIX_OFFSET, 16, 1,
+ &rx_ring[ring_offset], 70, true);
#endif
/* Packet copy from FIFO still in progress.
@@ -1973,14 +1956,11 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
if (!tp->fifo_copy_timeout)
tp->fifo_copy_timeout = jiffies + 2;
else if (time_after(jiffies, tp->fifo_copy_timeout)) {
- pr_debug("%s: hung FIFO. Reset.", dev->name);
+ netdev_dbg(dev, "hung FIFO. Reset\n");
rx_size = 0;
goto no_early_rx;
}
- if (netif_msg_intr(tp)) {
- pr_debug("%s: fifo copy in progress.",
- dev->name);
- }
+ netif_dbg(tp, intr, dev, "fifo copy in progress\n");
tp->xstats.early_rx++;
break;
}
@@ -2021,8 +2001,7 @@ no_early_rx:
netif_receive_skb (skb);
} else {
if (net_ratelimit())
- pr_warning("%s: Memory squeeze, dropping packet.\n",
- dev->name);
+ netdev_warn(dev, "Memory squeeze, dropping packet\n");
dev->stats.rx_dropped++;
}
received++;
@@ -2036,10 +2015,9 @@ no_early_rx:
if (unlikely(!received || rx_size == 0xfff0))
rtl8139_isr_ack(tp);
- pr_debug("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
- " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
- RTL_R16 (RxBufAddr),
- RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
+ netdev_dbg(dev, "Done %s(), current %04x BufAddr %04x, free to %04x, Cmd %02x\n",
+ __func__, cur_rx,
+ RTL_R16(RxBufAddr), RTL_R16(RxBufPtr), RTL_R8(ChipCmd));
tp->cur_rx = cur_rx;
@@ -2060,8 +2038,7 @@ static void rtl8139_weird_interrupt (struct net_device *dev,
void __iomem *ioaddr,
int status, int link_changed)
{
- pr_debug("%s: Abnormal interrupt, status %8.8x.\n",
- dev->name, status);
+ netdev_dbg(dev, "Abnormal interrupt, status %08x\n", status);
assert (dev != NULL);
assert (tp != NULL);
@@ -2089,8 +2066,7 @@ static void rtl8139_weird_interrupt (struct net_device *dev,
pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status);
pci_write_config_word (tp->pci_dev, PCI_STATUS, pci_cmd_status);
- pr_err("%s: PCI Bus error %4.4x.\n",
- dev->name, pci_cmd_status);
+ netdev_err(dev, "PCI Bus error %04x\n", pci_cmd_status);
}
}
@@ -2183,8 +2159,8 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance)
out:
spin_unlock (&tp->lock);
- pr_debug("%s: exiting interrupt, intr_status=%#4.4x.\n",
- dev->name, RTL_R16 (IntrStatus));
+ netdev_dbg(dev, "exiting interrupt, intr_status=%#4.4x\n",
+ RTL_R16(IntrStatus));
return IRQ_RETVAL(handled);
}
@@ -2233,9 +2209,8 @@ static int rtl8139_close (struct net_device *dev)
netif_stop_queue(dev);
napi_disable(&tp->napi);
- if (netif_msg_ifdown(tp))
- pr_debug("%s: Shutting down ethercard, status was 0x%4.4x.\n",
- dev->name, RTL_R16 (IntrStatus));
+ netif_dbg(tp, ifdown, dev, "Shutting down ethercard, status was 0x%04x\n",
+ RTL_R16(IntrStatus));
spin_lock_irqsave (&tp->lock, flags);
@@ -2509,11 +2484,11 @@ static void __set_rx_mode (struct net_device *dev)
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
u32 mc_filter[2]; /* Multicast hash filter */
- int i, rx_mode;
+ int rx_mode;
u32 tmp;
- pr_debug("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n",
- dev->name, dev->flags, RTL_R32 (RxConfig));
+ netdev_dbg(dev, "rtl8139_set_rx_mode(%04x) done -- Rx config %08lx\n",
+ dev->flags, RTL_R32(RxConfig));
/* Note: do not reorder, GCC is clever about common statements. */
if (dev->flags & IFF_PROMISC) {
@@ -2521,7 +2496,7 @@ static void __set_rx_mode (struct net_device *dev)
AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
AcceptAllPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
- } else if ((dev->mc_count > multicast_filter_limit) ||
+ } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
(dev->flags & IFF_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
@@ -2530,8 +2505,7 @@ static void __set_rx_mode (struct net_device *dev)
struct dev_mc_list *mclist;
rx_mode = AcceptBroadcast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 1663bc9e45de..f94d17d78bb0 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -1505,7 +1505,7 @@ static void set_multicast_list(struct net_device *dev)
int config = 0, cnt;
DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
- dev->name, dev->mc_count,
+ dev->name, netdev_mc_count(dev),
dev->flags & IFF_PROMISC ? "ON" : "OFF",
dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
@@ -1533,7 +1533,7 @@ static void set_multicast_list(struct net_device *dev)
i596_add_cmd(dev, &lp->cf_cmd.cmd);
}
- cnt = dev->mc_count;
+ cnt = netdev_mc_count(dev);
if (cnt > MAX_MC_CNT)
{
cnt = MAX_MC_CNT;
@@ -1541,7 +1541,7 @@ static void set_multicast_list(struct net_device *dev)
dev->name, cnt);
}
- if (dev->mc_count > 0) {
+ if (!netdev_mc_empty(dev)) {
struct dev_mc_list *dmi;
unsigned char *cp;
struct mc_cmd *cmd;
@@ -1550,13 +1550,16 @@ static void set_multicast_list(struct net_device *dev)
return;
cmd = &lp->mc_cmd;
cmd->cmd.command = CmdMulticastList;
- cmd->mc_cnt = dev->mc_count * 6;
+ cmd->mc_cnt = cnt * ETH_ALEN;
cp = cmd->mc_addrs;
- for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) {
- memcpy(cp, dmi->dmi_addr, 6);
+ netdev_for_each_mc_addr(dmi, dev) {
+ if (!cnt--)
+ break;
+ memcpy(cp, dmi->dmi_addr, ETH_ALEN);
if (i596_debug > 1)
DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %pM\n",
dev->name, cp));
+ cp += ETH_ALEN;
}
i596_add_cmd(dev, &cmd->cmd);
}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index dd9a09c72dff..0ba5b8e50a7c 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -90,6 +90,18 @@ config MACVLAN
To compile this driver as a module, choose M here: the module
will be called macvlan.
+config MACVTAP
+ tristate "MAC-VLAN based tap driver (EXPERIMENTAL)"
+ depends on MACVLAN
+ help
+ This adds a specialized tap character device driver that is based
+ on the MAC-VLAN network interface, called macvtap. A macvtap device
+ can be added in the same way as a macvlan device, using 'type
+ macvlan', and then be accessed through the tap user space interface.
+
+ To compile this driver as a module, choose M here: the module
+ will be called macvtap.
+
config EQUALIZER
tristate "EQL (serial line load balancing) support"
---help---
@@ -868,8 +880,8 @@ config BFIN_RX_DESC_NUM
Set the number of buffer packets used in driver.
config BFIN_MAC_RMII
- bool "RMII PHY Interface (EXPERIMENTAL)"
- depends on BFIN_MAC && EXPERIMENTAL
+ bool "RMII PHY Interface"
+ depends on BFIN_MAC
default y if BFIN527_EZKIT
default n if BFIN537_STAMP
help
@@ -895,7 +907,7 @@ config SMC91X
select CRC32
select MII
depends on ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || \
- MIPS || BLACKFIN || MN10300
+ MIPS || BLACKFIN || MN10300 || COLDFIRE
help
This is a driver for SMC's 91x series of Ethernet chipsets,
including the SMC91C94 and the SMC91C111. Say Y if you want it
@@ -920,7 +932,7 @@ config NET_NETX
config TI_DAVINCI_EMAC
tristate "TI DaVinci EMAC Support"
- depends on ARM && ARCH_DAVINCI
+ depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
select PHYLIB
help
This driver supports TI's DaVinci Ethernet .
@@ -983,6 +995,14 @@ config ETHOC
help
Say Y here if you want to use the OpenCores 10/100 Mbps Ethernet MAC.
+config GRETH
+ tristate "Aeroflex Gaisler GRETH Ethernet MAC support"
+ depends on SPARC
+ select PHYLIB
+ select CRC32
+ help
+ Say Y here if you want to use the Aeroflex Gaisler GRETH Ethernet MAC.
+
config SMC911X
tristate "SMSC LAN911[5678] support"
select CRC32
@@ -1368,6 +1388,17 @@ config AC3200
To compile this driver as a module, choose M here. The module
will be called ac3200.
+config KSZ884X_PCI
+ tristate "Micrel KSZ8841/2 PCI"
+ depends on NET_PCI && PCI
+ select MII
+ select CRC32
+ help
+ This PCI driver is for Micrel KSZ8841/KSZ8842 PCI Ethernet chip.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ksz884x.
+
config APRICOT
tristate "Apricot Xen-II on board Ethernet"
depends on NET_PCI && ISA
@@ -1883,7 +1914,8 @@ config 68360_ENET
config FEC
bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
- depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27 || ARCH_MX35 || ARCH_MX25
+ depends on M523x || M527x || M5272 || M528x || M520x || M532x || \
+ MACH_MX27 || ARCH_MX35 || ARCH_MX25 || ARCH_MX5
help
Say Y here if you want to use the built-in 10/100 Fast ethernet
controller on some Motorola ColdFire and Freescale i.MX processors.
@@ -1939,6 +1971,7 @@ config ATL2
config XILINX_EMACLITE
tristate "Xilinx 10/100 Ethernet Lite support"
depends on PPC32 || MICROBLAZE
+ select PHYLIB
help
This driver supports the 10/100 Ethernet Lite from Xilinx.
@@ -2356,20 +2389,6 @@ config GELIC_WIRELESS
the driver automatically distinguishes the models, you can
safely enable this option even if you have a wireless-less model.
-config GELIC_WIRELESS_OLD_PSK_INTERFACE
- bool "PS3 Wireless private PSK interface (OBSOLETE)"
- depends on GELIC_WIRELESS
- select WEXT_PRIV
- help
- This option retains the obsolete private interface to pass
- the PSK from user space programs to the driver. The PSK
- stands for 'Pre Shared Key' and is used for WPA[2]-PSK
- (WPA-Personal) environment.
- If WPA[2]-PSK is used and you need to use old programs that
- support only this old interface, say Y. Otherwise N.
-
- If unsure, say N.
-
config FSL_PQ_MDIO
tristate "Freescale PQ MDIO"
depends on FSL_SOC
@@ -2618,6 +2637,28 @@ config IXGBE_DCB
If unsure, say N.
+config IXGBEVF
+ tristate "Intel(R) 82599 Virtual Function Ethernet support"
+ depends on PCI_MSI
+ ---help---
+ This driver supports Intel(R) 82599 virtual functions. For more
+ information on how to identify your adapter, go to the Adapter &
+ Driver ID Guide at:
+
+ <http://support.intel.com/support/network/sb/CS-008441.htm>
+
+ For general information and support, go to the Intel support
+ website at:
+
+ <http://support.intel.com>
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/ixgbevf.txt>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ixgbevf. MSI-X interrupt support is required
+ for this driver to work correctly.
+
config IXGB
tristate "Intel(R) PRO/10GbE support"
depends on PCI
@@ -2756,6 +2797,13 @@ config BNX2X
To compile this driver as a module, choose M here: the module
will be called bnx2x. This is recommended.
+config QLCNIC
+ tristate "QLOGIC QLCNIC 1/10Gb Converged Ethernet NIC Support"
+ depends on PCI
+ help
+ This driver supports QLogic QLE8240 and QLE8242 Converged Ethernet
+ devices.
+
config QLGE
tristate "QLogic QLGE 10Gb Ethernet Driver Support"
depends on PCI
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index ad1346dd9da9..478886234c28 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/
obj-$(CONFIG_IGB) += igb/
obj-$(CONFIG_IGBVF) += igbvf/
obj-$(CONFIG_IXGBE) += ixgbe/
+obj-$(CONFIG_IXGBEVF) += ixgbevf/
obj-$(CONFIG_IXGB) += ixgb/
obj-$(CONFIG_IP1000) += ipg.o
obj-$(CONFIG_CHELSIO_T1) += chelsio/
@@ -95,6 +96,7 @@ obj-$(CONFIG_SKFP) += skfp/
obj-$(CONFIG_KS8842) += ks8842.o
obj-$(CONFIG_KS8851) += ks8851.o
obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
+obj-$(CONFIG_KSZ884X_PCI) += ksz884x.o
obj-$(CONFIG_VIA_RHINE) += via-rhine.o
obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
@@ -148,6 +150,7 @@ ll_temac-objs := ll_temac_main.o ll_temac_mdio.o
obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o
obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o
obj-$(CONFIG_QLA3XXX) += qla3xxx.o
+obj-$(CONFIG_QLCNIC) += qlcnic/
obj-$(CONFIG_QLGE) += qlge/
obj-$(CONFIG_PPP) += ppp_generic.o
@@ -167,6 +170,7 @@ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
obj-$(CONFIG_DUMMY) += dummy.o
obj-$(CONFIG_IFB) += ifb.o
obj-$(CONFIG_MACVLAN) += macvlan.o
+obj-$(CONFIG_MACVTAP) += macvtap.o
obj-$(CONFIG_DE600) += de600.o
obj-$(CONFIG_DE620) += de620.o
obj-$(CONFIG_LANCE) += lance.o
@@ -246,6 +250,7 @@ pasemi_mac_driver-objs := pasemi_mac.o pasemi_mac_ethtool.o
obj-$(CONFIG_MLX4_CORE) += mlx4/
obj-$(CONFIG_ENC28J60) += enc28j60.o
obj-$(CONFIG_ETHOC) += ethoc.o
+obj-$(CONFIG_GRETH) += greth.o
obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index b7ec0368d7e8..bd4d829eca12 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -603,9 +603,8 @@ static void lance_load_multicast (struct net_device *dev)
struct lance_private *lp = netdev_priv(dev);
volatile struct lance_init_block *ib = lp->init_block;
volatile u16 *mcast_table = (u16 *)&ib->filter;
- struct dev_mc_list *dmi=dev->mc_list;
+ struct dev_mc_list *dmi;
char *addrs;
- int i;
u32 crc;
/* set all multicast bits */
@@ -619,9 +618,8 @@ static void lance_load_multicast (struct net_device *dev)
ib->filter [1] = 0;
/* Add addresses */
- for (i = 0; i < dev->mc_count; i++){
+ netdev_for_each_mc_addr(dmi, dev) {
addrs = dmi->dmi_addr;
- dmi = dmi->next;
/* multicast address? */
if (!(*addrs & 1))
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index d82a9a994753..4ae750ef1e10 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -134,7 +134,7 @@
#define PCI_DEVICE_ID_SGI_ACENIC 0x0009
#endif
-static struct pci_device_id acenic_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(acenic_pci_tbl) = {
{ PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE,
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
{ PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_COPPER,
@@ -2845,7 +2845,7 @@ static void ace_set_multicast_list(struct net_device *dev)
* set the entire multicast list at a time and keeping track of
* it here is going to be messy.
*/
- if ((dev->mc_count) && !(ap->mcast_all)) {
+ if (!netdev_mc_empty(dev) && !ap->mcast_all) {
cmd.evt = C_SET_MULTICAST_MODE;
cmd.code = C_C_MCAST_ENABLE;
cmd.idx = 0;
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 766aabfdfc75..b8a59d255b49 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -113,7 +113,7 @@ MODULE_PARM_DESC(coalesce, "Enable or Disable interrupt coalescing, 1: Enable, 0
module_param_array(dynamic_ipg, bool, NULL, 0);
MODULE_PARM_DESC(dynamic_ipg, "Enable or Disable dynamic IPG, 1: Enable, 0: Disable");
-static struct pci_device_id amd8111e_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(amd8111e_pci_tbl) = {
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD8111E_7462,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
@@ -1176,8 +1176,7 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id)
/* Schedule a polling routine */
__napi_schedule(&lp->napi);
} else if (intren0 & RINTEN0) {
- printk("************Driver bug! \
- interrupt while in poll\n");
+ printk("************Driver bug! interrupt while in poll\n");
/* Fix by disable receive interrupts */
writel(RINTEN0, mmio + INTEN0);
}
@@ -1378,28 +1377,28 @@ list to the device.
*/
static void amd8111e_set_multicast_list(struct net_device *dev)
{
- struct dev_mc_list* mc_ptr;
+ struct dev_mc_list *mc_ptr;
struct amd8111e_priv *lp = netdev_priv(dev);
u32 mc_filter[2] ;
- int i,bit_num;
+ int bit_num;
+
if(dev->flags & IFF_PROMISC){
writel( VAL2 | PROM, lp->mmio + CMD2);
return;
}
else
writel( PROM, lp->mmio + CMD2);
- if(dev->flags & IFF_ALLMULTI || dev->mc_count > MAX_FILTER_SIZE){
+ if (dev->flags & IFF_ALLMULTI ||
+ netdev_mc_count(dev) > MAX_FILTER_SIZE) {
/* get all multicast packet */
mc_filter[1] = mc_filter[0] = 0xffffffff;
- lp->mc_list = dev->mc_list;
lp->options |= OPTION_MULTICAST_ENABLE;
amd8111e_writeq(*(u64*)mc_filter,lp->mmio + LADRF);
return;
}
- if( dev->mc_count == 0 ){
+ if (netdev_mc_empty(dev)) {
/* get only own packets */
mc_filter[1] = mc_filter[0] = 0;
- lp->mc_list = NULL;
lp->options &= ~OPTION_MULTICAST_ENABLE;
amd8111e_writeq(*(u64*)mc_filter,lp->mmio + LADRF);
/* disable promiscous mode */
@@ -1408,10 +1407,8 @@ static void amd8111e_set_multicast_list(struct net_device *dev)
}
/* load all the multicast addresses in the logic filter */
lp->options |= OPTION_MULTICAST_ENABLE;
- lp->mc_list = dev->mc_list;
mc_filter[1] = mc_filter[0] = 0;
- for (i = 0, mc_ptr = dev->mc_list; mc_ptr && i < dev->mc_count;
- i++, mc_ptr = mc_ptr->next) {
+ netdev_for_each_mc_addr(mc_ptr, dev) {
bit_num = (ether_crc_le(ETH_ALEN, mc_ptr->dmi_addr) >> 26) & 0x3f;
mc_filter[bit_num >> 5] |= 1 << (bit_num & 31);
}
diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h
index 28c60a71ed50..ac36eb6981e3 100644
--- a/drivers/net/amd8111e.h
+++ b/drivers/net/amd8111e.h
@@ -789,7 +789,6 @@ struct amd8111e_priv{
char opened;
struct net_device_stats stats;
unsigned int drv_rx_errors;
- struct dev_mc_list* mc_list;
struct amd8111e_coalesce_conf coal_conf;
struct ipg_info ipg_data;
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index dbfbd3b7ff86..8ea4ec705bef 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -1125,7 +1125,6 @@ struct net_device * __init ltpc_probe(void)
printk(KERN_INFO "Apple/Farallon LocalTalk-PC card at %03x, DMA%d. Using polled mode.\n",io,dma);
dev->netdev_ops = &ltpc_netdev;
- dev->mc_list = NULL;
dev->base_addr = io;
dev->irq = irq;
dev->dma = dma;
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c
index dbf4de39754d..b68e1eb405ff 100644
--- a/drivers/net/arcnet/com20020-pci.c
+++ b/drivers/net/arcnet/com20020-pci.c
@@ -144,7 +144,7 @@ static void __devexit com20020pci_remove(struct pci_dev *pdev)
free_netdev(dev);
}
-static struct pci_device_id com20020pci_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(com20020pci_id_table) = {
{ 0x1571, 0xa001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x1571, 0xa002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x1571, 0xa003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index c35af3e106b1..08d8be47dae0 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -123,9 +123,7 @@ static void ariadne_reset(struct net_device *dev);
static irqreturn_t ariadne_interrupt(int irq, void *data);
static int ariadne_close(struct net_device *dev);
static struct net_device_stats *ariadne_get_stats(struct net_device *dev);
-#ifdef HAVE_MULTICAST
static void set_multicast_list(struct net_device *dev);
-#endif
static void memcpyw(volatile u_short *dest, u_short *src, int len)
@@ -821,7 +819,7 @@ static void set_multicast_list(struct net_device *dev)
lance->RDP = PROM; /* Set promiscuous mode */
} else {
short multicast_table[4];
- int num_addrs = dev->mc_count;
+ int num_addrs = netdev_mc_count(dev);
int i;
/* We don't use the multicast table, but rely on upper-layer filtering. */
memset(multicast_table, (num_addrs == 0) ? 0 : -1,
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 164b37e85eea..f1f58c5e27bf 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -351,13 +351,13 @@ static struct net_device_stats *am79c961_getstats (struct net_device *dev)
return &priv->stats;
}
-static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash)
+static void am79c961_mc_hash(char *addr, unsigned short *hash)
{
- if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) {
+ if (addr[0] & 0x01) {
int idx, bit;
u32 crc;
- crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr);
+ crc = ether_crc_le(ETH_ALEN, addr);
idx = crc >> 30;
bit = (crc >> 26) & 15;
@@ -387,8 +387,8 @@ static void am79c961_setmulticastlist (struct net_device *dev)
memset(multi_hash, 0x00, sizeof(multi_hash));
- for (dmi = dev->mc_list; dmi; dmi = dmi->next)
- am79c961_mc_hash(dmi, multi_hash);
+ netdev_for_each_mc_addr(dmi, dev)
+ am79c961_mc_hash(dmi->dmi_addr, multi_hash);
}
spin_lock_irqsave(&priv->chip_lock, flags);
@@ -680,7 +680,7 @@ static const struct net_device_ops am79c961_netdev_ops = {
#endif
};
-static int __init am79c961_probe(struct platform_device *pdev)
+static int __devinit am79c961_probe(struct platform_device *pdev)
{
struct resource *res;
struct net_device *dev;
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index c8bc60a7040c..8b23d5a175bf 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -558,14 +558,11 @@ static void at91ether_sethashtable(struct net_device *dev)
{
struct dev_mc_list *curr;
unsigned long mc_filter[2];
- unsigned int i, bitnr;
+ unsigned int bitnr;
mc_filter[0] = mc_filter[1] = 0;
- curr = dev->mc_list;
- for (i = 0; i < dev->mc_count; i++, curr = curr->next) {
- if (!curr) break; /* unexpected end of list */
-
+ netdev_for_each_mc_addr(curr, dev) {
bitnr = hash_get_index(curr->dmi_addr);
mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
}
@@ -592,7 +589,7 @@ static void at91ether_set_multicast_list(struct net_device *dev)
at91_emac_write(AT91_EMAC_HSH, -1);
at91_emac_write(AT91_EMAC_HSL, -1);
cfg |= AT91_EMAC_MTI;
- } else if (dev->mc_count > 0) { /* Enable specific multicasts */
+ } else if (!netdev_mc_empty(dev)) { /* Enable specific multicasts */
at91ether_sethashtable(dev);
cfg |= AT91_EMAC_MTI;
} else if (dev->flags & (~IFF_ALLMULTI)) { /* Disable all multicast mode */
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index b25467ac895c..bf72d57a0afd 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -9,6 +9,8 @@
* (at your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -20,9 +22,9 @@
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
-#include <mach/ep93xx-regs.h>
-#include <mach/platform.h>
-#include <asm/io.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
#define DRV_MODULE_NAME "ep93xx-eth"
#define DRV_MODULE_VERSION "0.1"
@@ -185,7 +187,47 @@ struct ep93xx_priv
#define wrw(ep, off, val) __raw_writew((val), (ep)->base_addr + (off))
#define wrl(ep, off, val) __raw_writel((val), (ep)->base_addr + (off))
-static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg);
+static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ int data;
+ int i;
+
+ wrl(ep, REG_MIICMD, REG_MIICMD_READ | (phy_id << 5) | reg);
+
+ for (i = 0; i < 10; i++) {
+ if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0)
+ break;
+ msleep(1);
+ }
+
+ if (i == 10) {
+ pr_info("mdio read timed out\n");
+ data = 0xffff;
+ } else {
+ data = rdl(ep, REG_MIIDATA);
+ }
+
+ return data;
+}
+
+static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ int i;
+
+ wrl(ep, REG_MIIDATA, data);
+ wrl(ep, REG_MIICMD, REG_MIICMD_WRITE | (phy_id << 5) | reg);
+
+ for (i = 0; i < 10; i++) {
+ if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0)
+ break;
+ msleep(1);
+ }
+
+ if (i == 10)
+ pr_info("mdio write timed out\n");
+}
static struct net_device_stats *ep93xx_get_stats(struct net_device *dev)
{
@@ -217,14 +259,11 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget)
rstat->rstat1 = 0;
if (!(rstat0 & RSTAT0_EOF))
- printk(KERN_CRIT "ep93xx_rx: not end-of-frame "
- " %.8x %.8x\n", rstat0, rstat1);
+ pr_crit("not end-of-frame %.8x %.8x\n", rstat0, rstat1);
if (!(rstat0 & RSTAT0_EOB))
- printk(KERN_CRIT "ep93xx_rx: not end-of-buffer "
- " %.8x %.8x\n", rstat0, rstat1);
+ pr_crit("not end-of-buffer %.8x %.8x\n", rstat0, rstat1);
if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry)
- printk(KERN_CRIT "ep93xx_rx: entry mismatch "
- " %.8x %.8x\n", rstat0, rstat1);
+ pr_crit("entry mismatch %.8x %.8x\n", rstat0, rstat1);
if (!(rstat0 & RSTAT0_RWE)) {
ep->stats.rx_errors++;
@@ -241,8 +280,7 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget)
length = rstat1 & RSTAT1_FRAME_LENGTH;
if (length > MAX_PKT_SIZE) {
- printk(KERN_NOTICE "ep93xx_rx: invalid length "
- " %.8x %.8x\n", rstat0, rstat1);
+ pr_notice("invalid length %.8x %.8x\n", rstat0, rstat1);
goto err;
}
@@ -371,11 +409,9 @@ static void ep93xx_tx_complete(struct net_device *dev)
tstat->tstat0 = 0;
if (tstat0 & TSTAT0_FA)
- printk(KERN_CRIT "ep93xx_tx_complete: frame aborted "
- " %.8x\n", tstat0);
+ pr_crit("frame aborted %.8x\n", tstat0);
if ((tstat0 & TSTAT0_BUFFER_INDEX) != entry)
- printk(KERN_CRIT "ep93xx_tx_complete: entry mismatch "
- " %.8x\n", tstat0);
+ pr_crit("entry mismatch %.8x\n", tstat0);
if (tstat0 & TSTAT0_TXWE) {
int length = ep->descs->tdesc[entry].tdesc1 & 0xfff;
@@ -536,7 +572,7 @@ static int ep93xx_start_hw(struct net_device *dev)
}
if (i == 10) {
- printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n");
+ pr_crit("hw failed to reset\n");
return 1;
}
@@ -581,7 +617,7 @@ static int ep93xx_start_hw(struct net_device *dev)
}
if (i == 10) {
- printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to start\n");
+ pr_crit("hw failed to start\n");
return 1;
}
@@ -617,7 +653,7 @@ static void ep93xx_stop_hw(struct net_device *dev)
}
if (i == 10)
- printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n");
+ pr_crit("hw failed to reset\n");
}
static int ep93xx_open(struct net_device *dev)
@@ -681,48 +717,6 @@ static int ep93xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return generic_mii_ioctl(&ep->mii, data, cmd, NULL);
}
-static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg)
-{
- struct ep93xx_priv *ep = netdev_priv(dev);
- int data;
- int i;
-
- wrl(ep, REG_MIICMD, REG_MIICMD_READ | (phy_id << 5) | reg);
-
- for (i = 0; i < 10; i++) {
- if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0)
- break;
- msleep(1);
- }
-
- if (i == 10) {
- printk(KERN_INFO DRV_MODULE_NAME ": mdio read timed out\n");
- data = 0xffff;
- } else {
- data = rdl(ep, REG_MIIDATA);
- }
-
- return data;
-}
-
-static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data)
-{
- struct ep93xx_priv *ep = netdev_priv(dev);
- int i;
-
- wrl(ep, REG_MIIDATA, data);
- wrl(ep, REG_MIICMD, REG_MIICMD_WRITE | (phy_id << 5) | reg);
-
- for (i = 0; i < 10; i++) {
- if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0)
- break;
- msleep(1);
- }
-
- if (i == 10)
- printk(KERN_INFO DRV_MODULE_NAME ": mdio write timed out\n");
-}
-
static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
strcpy(info->driver, DRV_MODULE_NAME);
@@ -825,12 +819,19 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
struct ep93xx_eth_data *data;
struct net_device *dev;
struct ep93xx_priv *ep;
+ struct resource *mem;
+ int irq;
int err;
if (pdev == NULL)
return -ENODEV;
data = pdev->dev.platform_data;
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!mem || irq < 0)
+ return -ENXIO;
+
dev = ep93xx_dev_alloc(data);
if (dev == NULL) {
err = -ENOMEM;
@@ -842,23 +843,21 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
- ep->res = request_mem_region(pdev->resource[0].start,
- pdev->resource[0].end - pdev->resource[0].start + 1,
- dev_name(&pdev->dev));
+ ep->res = request_mem_region(mem->start, resource_size(mem),
+ dev_name(&pdev->dev));
if (ep->res == NULL) {
dev_err(&pdev->dev, "Could not reserve memory region\n");
err = -ENOMEM;
goto err_out;
}
- ep->base_addr = ioremap(pdev->resource[0].start,
- pdev->resource[0].end - pdev->resource[0].start);
+ ep->base_addr = ioremap(mem->start, resource_size(mem));
if (ep->base_addr == NULL) {
dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
err = -EIO;
goto err_out;
}
- ep->irq = pdev->resource[1].start;
+ ep->irq = irq;
ep->mii.phy_id = data->phy_id;
ep->mii.phy_id_mask = 0x1f;
@@ -877,11 +876,8 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
goto err_out;
}
- printk(KERN_INFO "%s: ep93xx on-chip ethernet, IRQ %d, "
- "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", dev->name,
- ep->irq, data->dev_addr[0], data->dev_addr[1],
- data->dev_addr[2], data->dev_addr[3],
- data->dev_addr[4], data->dev_addr[5]);
+ printk(KERN_INFO "%s: ep93xx on-chip ethernet, IRQ %d, %pM\n",
+ dev->name, ep->irq, dev->dev_addr);
return 0;
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index 1f7a69c929a6..d9de9bce2395 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -463,7 +463,7 @@ static void ether3_setmulticastlist(struct net_device *dev)
if (dev->flags & IFF_PROMISC) {
/* promiscuous mode */
priv(dev)->regs.config1 |= CFG1_RECVPROMISC;
- } else if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
+ } else if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev)) {
priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI;
} else
priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD;
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
index c3dfbdd2cdcf..6e2ae1d06df1 100644
--- a/drivers/net/arm/ixp4xx_eth.c
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -735,22 +735,25 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
static void eth_set_mcast_list(struct net_device *dev)
{
struct port *port = netdev_priv(dev);
- struct dev_mc_list *mclist = dev->mc_list;
+ struct dev_mc_list *mclist;
u8 diffs[ETH_ALEN], *addr;
- int cnt = dev->mc_count, i;
+ int i;
- if ((dev->flags & IFF_PROMISC) || !mclist || !cnt) {
+ if ((dev->flags & IFF_PROMISC) || netdev_mc_empty(dev)) {
__raw_writel(DEFAULT_RX_CNTRL0 & ~RX_CNTRL0_ADDR_FLTR_EN,
&port->regs->rx_control[0]);
return;
}
memset(diffs, 0, ETH_ALEN);
- addr = mclist->dmi_addr; /* first MAC address */
- while (--cnt && (mclist = mclist->next))
+ addr = NULL;
+ netdev_for_each_mc_addr(mclist, dev) {
+ if (!addr)
+ addr = mclist->dmi_addr; /* first MAC address */
for (i = 0; i < ETH_ALEN; i++)
diffs[i] |= addr[i] ^ mclist->dmi_addr[i];
+ }
for (i = 0; i < ETH_ALEN; i++) {
__raw_writel(addr[i], &port->regs->mcast_addr[i]);
diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c
index be256b34cea8..a1d4188c430b 100644
--- a/drivers/net/arm/ks8695net.c
+++ b/drivers/net/arm/ks8695net.c
@@ -327,25 +327,24 @@ ks8695_refill_rxbuffers(struct ks8695_priv *ksp)
*/
static void
ks8695_init_partial_multicast(struct ks8695_priv *ksp,
- struct dev_mc_list *addr,
- int nr_addr)
+ struct net_device *ndev)
{
u32 low, high;
int i;
+ struct dev_mc_list *dmi;
- for (i = 0; i < nr_addr; i++, addr = addr->next) {
- /* Ran out of addresses? */
- if (!addr)
- break;
+ i = 0;
+ netdev_for_each_mc_addr(dmi, ndev) {
/* Ran out of space in chip? */
BUG_ON(i == KS8695_NR_ADDRESSES);
- low = (addr->dmi_addr[2] << 24) | (addr->dmi_addr[3] << 16) |
- (addr->dmi_addr[4] << 8) | (addr->dmi_addr[5]);
- high = (addr->dmi_addr[0] << 8) | (addr->dmi_addr[1]);
+ low = (dmi->dmi_addr[2] << 24) | (dmi->dmi_addr[3] << 16) |
+ (dmi->dmi_addr[4] << 8) | (dmi->dmi_addr[5]);
+ high = (dmi->dmi_addr[0] << 8) | (dmi->dmi_addr[1]);
ks8695_writereg(ksp, KS8695_AAL_(i), low);
ks8695_writereg(ksp, KS8695_AAH_(i), AAH_E | high);
+ i++;
}
/* Clear the remaining Additional Station Addresses */
@@ -576,9 +575,9 @@ static int ks8695_poll(struct napi_struct *napi, int budget)
if (work_done < budget) {
unsigned long flags;
spin_lock_irqsave(&ksp->rx_lock, flags);
+ __napi_complete(napi);
/*enable rx interrupt*/
writel(isr | mask_bit, KS8695_IRQ_VA + KS8695_INTEN);
- __napi_complete(napi);
spin_unlock_irqrestore(&ksp->rx_lock, flags);
}
return work_done;
@@ -1207,7 +1206,7 @@ ks8695_set_multicast(struct net_device *ndev)
if (ndev->flags & IFF_ALLMULTI) {
/* enable all multicast mode */
ctrl |= DRXC_RM;
- } else if (ndev->mc_count > KS8695_NR_ADDRESSES) {
+ } else if (netdev_mc_count(ndev) > KS8695_NR_ADDRESSES) {
/* more specific multicast addresses than can be
* handled in hardware
*/
@@ -1215,8 +1214,7 @@ ks8695_set_multicast(struct net_device *ndev)
} else {
/* enable specific multicasts */
ctrl &= ~DRXC_RM;
- ks8695_init_partial_multicast(ksp, ndev->mc_list,
- ndev->mc_count);
+ ks8695_init_partial_multicast(ksp, ndev);
}
ks8695_writereg(ksp, KS8695_DRXC, ctrl);
@@ -1335,7 +1333,6 @@ ks8695_stop(struct net_device *ndev)
netif_stop_queue(ndev);
napi_disable(&ksp->napi);
- netif_carrier_off(ndev);
ks8695_shutdown(ksp);
diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c
index b7f3866d546f..febd813c916d 100644
--- a/drivers/net/arm/w90p910_ether.c
+++ b/drivers/net/arm/w90p910_ether.c
@@ -858,10 +858,10 @@ static void w90p910_ether_set_multicast_list(struct net_device *dev)
if (dev->flags & IFF_PROMISC)
rx_mode = CAMCMR_AUP | CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP;
- else if ((dev->flags & IFF_ALLMULTI) || dev->mc_list)
- rx_mode = CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP;
- else
- rx_mode = CAMCMR_ECMP | CAMCMR_ABP;
+ else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev))
+ rx_mode = CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP;
+ else
+ rx_mode = CAMCMR_ECMP | CAMCMR_ABP;
__raw_writel(rx_mode, ether->reg + REG_CAMCMR);
}
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index b14f4799d5d1..309843ab8869 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -839,21 +839,19 @@ set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC) {
memset(mc_filter, 0xff, sizeof(mc_filter));
outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */
- } else if (dev->mc_count > MC_FILTERBREAK ||
+ } else if (netdev_mc_count(dev) > MC_FILTERBREAK ||
(dev->flags & IFF_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */
memset(mc_filter, 0xff, sizeof(mc_filter));
outb(2, ioaddr + RX_MODE); /* Use normal mode. */
- } else if (dev->mc_count == 0) {
+ } else if (netdev_mc_empty(dev)) {
memset(mc_filter, 0x00, sizeof(mc_filter));
outb(1, ioaddr + RX_MODE); /* Ignore almost all multicasts. */
} else {
struct dev_mc_list *mclist;
- int i;
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
unsigned int bit =
ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26;
mc_filter[bit >> 3] |= (1 << bit);
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index cc9ed8643910..280cfff48b49 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -1097,7 +1097,7 @@ static void set_multicast_list( struct net_device *dev )
REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
} else {
short multicast_table[4];
- int num_addrs = dev->mc_count;
+ int num_addrs = netdev_mc_count(dev);
int i;
/* We don't use the multicast table, but rely on upper-layer
* filtering. */
diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h
index efe5435bc3d3..84ae905bf732 100644
--- a/drivers/net/atl1c/atl1c.h
+++ b/drivers/net/atl1c/atl1c.h
@@ -313,6 +313,9 @@ enum atl1c_rss_type {
enum atl1c_nic_type {
athr_l1c = 0,
athr_l2c = 1,
+ athr_l2c_b,
+ athr_l2c_b2,
+ athr_l1d,
};
enum atl1c_trans_queue {
@@ -426,8 +429,12 @@ struct atl1c_hw {
#define ATL1C_ASPM_L1_SUPPORT 0x0100
#define ATL1C_ASPM_CTRL_MON 0x0200
#define ATL1C_HIB_DISABLE 0x0400
-#define ATL1C_LINK_CAP_1000M 0x0800
-#define ATL1C_FPGA_VERSION 0x8000
+#define ATL1C_APS_MODE_ENABLE 0x0800
+#define ATL1C_LINK_EXT_SYNC 0x1000
+#define ATL1C_CLK_GATING_EN 0x2000
+#define ATL1C_FPGA_VERSION 0x8000
+ u16 link_cap_flags;
+#define ATL1C_LINK_CAP_1000M 0x0001
u16 cmb_tpd;
u16 cmb_rrd;
u16 cmb_rx_timer; /* 2us resolution */
diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c
index 9b1e0eaebb5c..61a0f2ff11e9 100644
--- a/drivers/net/atl1c/atl1c_ethtool.c
+++ b/drivers/net/atl1c/atl1c_ethtool.c
@@ -37,7 +37,7 @@ static int atl1c_get_settings(struct net_device *netdev,
SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_TP);
- if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M)
+ if (hw->link_cap_flags & ATL1C_LINK_CAP_1000M)
ecmd->supported |= SUPPORTED_1000baseT_Full;
ecmd->advertising = ADVERTISED_TP;
diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c
index 3e69b940b8f7..f1389d664a21 100644
--- a/drivers/net/atl1c/atl1c_hw.c
+++ b/drivers/net/atl1c/atl1c_hw.c
@@ -70,17 +70,39 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
u32 otp_ctrl_data;
u32 twsi_ctrl_data;
u8 eth_addr[ETH_ALEN];
+ u16 phy_data;
+ bool raise_vol = false;
/* init */
addr[0] = addr[1] = 0;
AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
if (atl1c_check_eeprom_exist(hw)) {
- /* Enable OTP CLK */
- if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
- otp_ctrl_data |= OTP_CTRL_CLK_EN;
- AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
- AT_WRITE_FLUSH(hw);
- msleep(1);
+ if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b) {
+ /* Enable OTP CLK */
+ if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
+ otp_ctrl_data |= OTP_CTRL_CLK_EN;
+ AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+ AT_WRITE_FLUSH(hw);
+ msleep(1);
+ }
+ }
+
+ if (hw->nic_type == athr_l2c_b ||
+ hw->nic_type == athr_l2c_b2 ||
+ hw->nic_type == athr_l1d) {
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
+ if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
+ goto out;
+ phy_data &= 0xFF7F;
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
+
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
+ if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
+ goto out;
+ phy_data |= 0x8;
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
+ udelay(20);
+ raise_vol = true;
}
AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
@@ -96,11 +118,31 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
return -1;
}
/* Disable OTP_CLK */
- if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
- otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
- AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
- AT_WRITE_FLUSH(hw);
- msleep(1);
+ if ((hw->nic_type == athr_l1c || hw->nic_type == athr_l2c)) {
+ if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
+ otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
+ AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+ AT_WRITE_FLUSH(hw);
+ msleep(1);
+ }
+ }
+ if (raise_vol) {
+ if (hw->nic_type == athr_l2c_b ||
+ hw->nic_type == athr_l2c_b2 ||
+ hw->nic_type == athr_l1d) {
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
+ if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
+ goto out;
+ phy_data |= 0x80;
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
+
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
+ if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
+ goto out;
+ phy_data &= 0xFFF7;
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
+ udelay(20);
+ }
}
/* maybe MAC-address is from BIOS */
@@ -114,6 +156,7 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
return 0;
}
+out:
return -1;
}
@@ -307,7 +350,7 @@ static int atl1c_phy_setup_adv(struct atl1c_hw *hw)
mii_adv_data |= ADVERTISE_10HALF | ADVERTISE_10FULL |
ADVERTISE_100HALF | ADVERTISE_100FULL;
- if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M) {
+ if (hw->link_cap_flags & ATL1C_LINK_CAP_1000M) {
if (hw->autoneg_advertised & ADVERTISED_1000baseT_Half)
mii_giga_ctrl_data |= ADVERTISE_1000HALF;
if (hw->autoneg_advertised & ADVERTISED_1000baseT_Full)
@@ -389,6 +432,7 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
{
struct atl1c_adapter *adapter = hw->adapter;
struct pci_dev *pdev = adapter->pdev;
+ u16 phy_data;
u32 phy_ctrl_data = GPHY_CTRL_DEFAULT;
u32 mii_ier_data = IER_LINK_UP | IER_LINK_DOWN;
int err;
@@ -404,6 +448,21 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
AT_WRITE_FLUSH(hw);
msleep(10);
+ if (hw->nic_type == athr_l2c_b) {
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x0A);
+ atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data);
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xDFFF);
+ }
+
+ if (hw->nic_type == athr_l2c_b ||
+ hw->nic_type == athr_l2c_b2 ||
+ hw->nic_type == athr_l1d) {
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
+ atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data);
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xFFF7);
+ msleep(20);
+ }
+
/*Enable PHY LinkChange Interrupt */
err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data);
if (err) {
diff --git a/drivers/net/atl1c/atl1c_hw.h b/drivers/net/atl1c/atl1c_hw.h
index c2c738df5c63..1eeb3ed9f0cb 100644
--- a/drivers/net/atl1c/atl1c_hw.h
+++ b/drivers/net/atl1c/atl1c_hw.h
@@ -57,6 +57,7 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define REG_LINK_CTRL 0x68
#define LINK_CTRL_L0S_EN 0x01
#define LINK_CTRL_L1_EN 0x02
+#define LINK_CTRL_EXT_SYNC 0x80
#define REG_VPD_CAP 0x6C
#define VPD_CAP_ID_MASK 0xff
@@ -156,6 +157,8 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define PM_CTRL_PM_REQ_TIMER_SHIFT 20
#define PM_CTRL_LCKDET_TIMER_MASK 0x3F
#define PM_CTRL_LCKDET_TIMER_SHIFT 24
+#define PM_CTRL_EN_BUFS_RX_L0S 0x10000000
+#define PM_CTRL_SA_DLY_EN 0x20000000
#define PM_CTRL_MAC_ASPM_CHK 0x40000000
#define PM_CTRL_HOTRST 0x80000000
@@ -314,6 +317,8 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define MAC_CTRL_BC_EN 0x4000000
#define MAC_CTRL_DBG 0x8000000
#define MAC_CTRL_SINGLE_PAUSE_EN 0x10000000
+#define MAC_CTRL_HASH_ALG_CRC32 0x20000000
+#define MAC_CTRL_SPEED_MODE_SW 0x40000000
/* MAC IPG/IFG Control Register */
#define REG_MAC_IPG_IFG 0x1484
diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
index 2f4be59b9c0b..50dc531a02d8 100644
--- a/drivers/net/atl1c/atl1c_main.c
+++ b/drivers/net/atl1c/atl1c_main.c
@@ -21,11 +21,18 @@
#include "atl1c.h"
-#define ATL1C_DRV_VERSION "1.0.0.1-NAPI"
+#define ATL1C_DRV_VERSION "1.0.0.2-NAPI"
char atl1c_driver_name[] = "atl1c";
char atl1c_driver_version[] = ATL1C_DRV_VERSION;
#define PCI_DEVICE_ID_ATTANSIC_L2C 0x1062
#define PCI_DEVICE_ID_ATTANSIC_L1C 0x1063
+#define PCI_DEVICE_ID_ATHEROS_L2C_B 0x2060 /* AR8152 v1.1 Fast 10/100 */
+#define PCI_DEVICE_ID_ATHEROS_L2C_B2 0x2062 /* AR8152 v2.0 Fast 10/100 */
+#define PCI_DEVICE_ID_ATHEROS_L1D 0x1073 /* AR8151 v1.0 Gigabit 1000 */
+
+#define L2CB_V10 0xc0
+#define L2CB_V11 0xc1
+
/*
* atl1c_pci_tbl - PCI Device ID Table
*
@@ -35,9 +42,12 @@ char atl1c_driver_version[] = ATL1C_DRV_VERSION;
* { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
* Class, Class Mask, private data (not used) }
*/
-static struct pci_device_id atl1c_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(atl1c_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1C)},
{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2C)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L1D)},
/* required last entry */
{ 0 }
};
@@ -367,7 +377,7 @@ static void atl1c_set_multi(struct net_device *netdev)
AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
/* comoute mc addresses' hash value ,and put it into hash table */
- for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+ netdev_for_each_mc_addr(mc_ptr, netdev) {
hash_value = atl1c_hash_mc_addr(hw, mc_ptr->dmi_addr);
atl1c_hash_set(hw, hash_value);
}
@@ -593,11 +603,18 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw)
case PCI_DEVICE_ID_ATTANSIC_L2C:
hw->nic_type = athr_l2c;
break;
-
case PCI_DEVICE_ID_ATTANSIC_L1C:
hw->nic_type = athr_l1c;
break;
-
+ case PCI_DEVICE_ID_ATHEROS_L2C_B:
+ hw->nic_type = athr_l2c_b;
+ break;
+ case PCI_DEVICE_ID_ATHEROS_L2C_B2:
+ hw->nic_type = athr_l2c_b2;
+ break;
+ case PCI_DEVICE_ID_ATHEROS_L1D:
+ hw->nic_type = athr_l1d;
+ break;
default:
break;
}
@@ -620,10 +637,13 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT;
if (link_ctrl_data & LINK_CTRL_L1_EN)
hw->ctrl_flags |= ATL1C_ASPM_L1_SUPPORT;
+ if (link_ctrl_data & LINK_CTRL_EXT_SYNC)
+ hw->ctrl_flags |= ATL1C_LINK_EXT_SYNC;
- if (hw->nic_type == athr_l1c) {
+ if (hw->nic_type == athr_l1c ||
+ hw->nic_type == athr_l1d) {
hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
- hw->ctrl_flags |= ATL1C_LINK_CAP_1000M;
+ hw->link_cap_flags |= ATL1C_LINK_CAP_1000M;
}
return 0;
}
@@ -1234,21 +1254,92 @@ static void atl1c_disable_l0s_l1(struct atl1c_hw *hw)
static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
{
u32 pm_ctrl_data;
+ u32 link_ctrl_data;
AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data);
-
+ AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1;
+
pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+ pm_ctrl_data &= ~(PM_CTRL_LCKDET_TIMER_MASK <<
+ PM_CTRL_LCKDET_TIMER_SHIFT);
pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
+ pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+ pm_ctrl_data |= PM_CTRL_RBER_EN;
+ pm_ctrl_data |= PM_CTRL_SDES_EN;
+
+ if (hw->nic_type == athr_l2c_b ||
+ hw->nic_type == athr_l1d ||
+ hw->nic_type == athr_l2c_b2) {
+ link_ctrl_data &= ~LINK_CTRL_EXT_SYNC;
+ if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE)) {
+ if (hw->nic_type == athr_l2c_b &&
+ hw->revision_id == L2CB_V10)
+ link_ctrl_data |= LINK_CTRL_EXT_SYNC;
+ }
+
+ AT_WRITE_REG(hw, REG_LINK_CTRL, link_ctrl_data);
+
+ pm_ctrl_data |= PM_CTRL_PCIE_RECV;
+ pm_ctrl_data |= AT_ASPM_L1_TIMER << PM_CTRL_PM_REQ_TIMER_SHIFT;
+ pm_ctrl_data &= ~PM_CTRL_EN_BUFS_RX_L0S;
+ pm_ctrl_data &= ~PM_CTRL_SA_DLY_EN;
+ pm_ctrl_data &= ~PM_CTRL_HOTRST;
+ pm_ctrl_data |= 1 << PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+ pm_ctrl_data |= PM_CTRL_SERDES_PD_EX_L1;
+ }
if (linkup) {
- pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN;
- pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
+ pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+ pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+ if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT)
+ pm_ctrl_data |= PM_CTRL_ASPM_L1_EN;
+ if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT)
+ pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN;
+
+ if (hw->nic_type == athr_l2c_b ||
+ hw->nic_type == athr_l1d ||
+ hw->nic_type == athr_l2c_b2) {
+ if (hw->nic_type == athr_l2c_b)
+ if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE))
+ pm_ctrl_data &= PM_CTRL_ASPM_L0S_EN;
+ pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
+ pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
+ pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
+ pm_ctrl_data |= PM_CTRL_CLK_SWH_L1;
+ if (hw->adapter->link_speed == SPEED_100 ||
+ hw->adapter->link_speed == SPEED_1000) {
+ pm_ctrl_data &=
+ ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
+ PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+ if (hw->nic_type == athr_l1d)
+ pm_ctrl_data |= 0xF <<
+ PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+ else
+ pm_ctrl_data |= 7 <<
+ PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+ }
+ } else {
+ pm_ctrl_data |= PM_CTRL_SERDES_L1_EN;
+ pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN;
+ pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN;
+ pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
+ pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+ pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+ }
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
+ if (hw->adapter->link_speed == SPEED_10)
+ if (hw->nic_type == athr_l1d)
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0xB69D);
+ else
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
+ else if (hw->adapter->link_speed == SPEED_100)
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB2DD);
+ else
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x96DD);
- pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN;
- pm_ctrl_data |= PM_CTRL_SERDES_L1_EN;
} else {
pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
@@ -1302,6 +1393,10 @@ static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter)
mac_ctrl_data |= MAC_CTRL_MC_ALL_EN;
mac_ctrl_data |= MAC_CTRL_SINGLE_PAUSE_EN;
+ if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2) {
+ mac_ctrl_data |= MAC_CTRL_SPEED_MODE_SW;
+ mac_ctrl_data |= MAC_CTRL_HASH_ALG_CRC32;
+ }
AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
}
@@ -2596,11 +2691,8 @@ static int __devinit atl1c_probe(struct pci_dev *pdev,
memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
if (netif_msg_probe(adapter))
- dev_dbg(&pdev->dev,
- "mac address : %02x-%02x-%02x-%02x-%02x-%02x\n",
- adapter->hw.mac_addr[0], adapter->hw.mac_addr[1],
- adapter->hw.mac_addr[2], adapter->hw.mac_addr[3],
- adapter->hw.mac_addr[4], adapter->hw.mac_addr[5]);
+ dev_dbg(&pdev->dev, "mac address : %pM\n",
+ adapter->hw.mac_addr);
atl1c_hw_set_mac_addr(&adapter->hw);
INIT_WORK(&adapter->common_task, atl1c_common_task);
diff --git a/drivers/net/atl1e/atl1e_hw.c b/drivers/net/atl1e/atl1e_hw.c
index 4a7700620119..76cc043def8c 100644
--- a/drivers/net/atl1e/atl1e_hw.c
+++ b/drivers/net/atl1e/atl1e_hw.c
@@ -394,7 +394,6 @@ static int atl1e_phy_setup_autoneg_adv(struct atl1e_hw *hw)
int atl1e_phy_commit(struct atl1e_hw *hw)
{
struct atl1e_adapter *adapter = hw->adapter;
- struct pci_dev *pdev = adapter->pdev;
int ret_val;
u16 phy_data;
@@ -415,12 +414,12 @@ int atl1e_phy_commit(struct atl1e_hw *hw)
}
if (0 != (val & (MDIO_START | MDIO_BUSY))) {
- dev_err(&pdev->dev,
- "pcie linkdown at least for 25ms\n");
+ netdev_err(adapter->netdev,
+ "pcie linkdown at least for 25ms\n");
return ret_val;
}
- dev_err(&pdev->dev, "pcie linkup after %d ms\n", i);
+ netdev_err(adapter->netdev, "pcie linkup after %d ms\n", i);
}
return 0;
}
@@ -428,7 +427,6 @@ int atl1e_phy_commit(struct atl1e_hw *hw)
int atl1e_phy_init(struct atl1e_hw *hw)
{
struct atl1e_adapter *adapter = hw->adapter;
- struct pci_dev *pdev = adapter->pdev;
s32 ret_val;
u16 phy_val;
@@ -492,20 +490,22 @@ int atl1e_phy_init(struct atl1e_hw *hw)
/*Enable PHY LinkChange Interrupt */
ret_val = atl1e_write_phy_reg(hw, MII_INT_CTRL, 0xC00);
if (ret_val) {
- dev_err(&pdev->dev, "Error enable PHY linkChange Interrupt\n");
+ netdev_err(adapter->netdev,
+ "Error enable PHY linkChange Interrupt\n");
return ret_val;
}
/* setup AutoNeg parameters */
ret_val = atl1e_phy_setup_autoneg_adv(hw);
if (ret_val) {
- dev_err(&pdev->dev, "Error Setting up Auto-Negotiation\n");
+ netdev_err(adapter->netdev,
+ "Error Setting up Auto-Negotiation\n");
return ret_val;
}
/* SW.Reset & En-Auto-Neg to restart Auto-Neg*/
- dev_dbg(&pdev->dev, "Restarting Auto-Neg");
+ netdev_dbg(adapter->netdev, "Restarting Auto-Negotiation\n");
ret_val = atl1e_phy_commit(hw);
if (ret_val) {
- dev_err(&pdev->dev, "Error Resetting the phy");
+ netdev_err(adapter->netdev, "Error resetting the phy\n");
return ret_val;
}
@@ -559,9 +559,8 @@ int atl1e_reset_hw(struct atl1e_hw *hw)
}
if (timeout >= AT_HW_MAX_IDLE_DELAY) {
- dev_err(&pdev->dev,
- "MAC state machine cann't be idle since"
- " disabled for 10ms second\n");
+ netdev_err(adapter->netdev,
+ "MAC state machine can't be idle since disabled for 10ms second\n");
return AT_ERR_TIMEOUT;
}
diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c
index 08f8c0969e9b..73302ae468aa 100644
--- a/drivers/net/atl1e/atl1e_main.c
+++ b/drivers/net/atl1e/atl1e_main.c
@@ -35,7 +35,7 @@ char atl1e_driver_version[] = DRV_VERSION;
* { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
* Class, Class Mask, private data (not used) }
*/
-static struct pci_device_id atl1e_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(atl1e_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1E)},
{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1066)},
/* required last entry */
@@ -164,11 +164,10 @@ static int atl1e_check_link(struct atl1e_adapter *adapter)
{
struct atl1e_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
- struct pci_dev *pdev = adapter->pdev;
int err = 0;
u16 speed, duplex, phy_data;
- /* MII_BMSR must read twise */
+ /* MII_BMSR must read twice */
atl1e_read_phy_reg(hw, MII_BMSR, &phy_data);
atl1e_read_phy_reg(hw, MII_BMSR, &phy_data);
if ((phy_data & BMSR_LSTATUS) == 0) {
@@ -195,12 +194,11 @@ static int atl1e_check_link(struct atl1e_adapter *adapter)
adapter->link_speed = speed;
adapter->link_duplex = duplex;
atl1e_setup_mac_ctrl(adapter);
- dev_info(&pdev->dev,
- "%s: %s NIC Link is Up<%d Mbps %s>\n",
- atl1e_driver_name, netdev->name,
- adapter->link_speed,
- adapter->link_duplex == FULL_DUPLEX ?
- "Full Duplex" : "Half Duplex");
+ netdev_info(netdev,
+ "NIC Link is Up <%d Mbps %s Duplex>\n",
+ adapter->link_speed,
+ adapter->link_duplex == FULL_DUPLEX ?
+ "Full" : "Half");
}
if (!netif_carrier_ok(netdev)) {
@@ -230,7 +228,6 @@ static void atl1e_link_chg_task(struct work_struct *work)
static void atl1e_link_chg_event(struct atl1e_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- struct pci_dev *pdev = adapter->pdev;
u16 phy_data = 0;
u16 link_up = 0;
@@ -243,8 +240,7 @@ static void atl1e_link_chg_event(struct atl1e_adapter *adapter)
if (!link_up) {
if (netif_carrier_ok(netdev)) {
/* old link state: Up */
- dev_info(&pdev->dev, "%s: %s NIC Link is Down\n",
- atl1e_driver_name, netdev->name);
+ netdev_info(netdev, "NIC Link is Down\n");
adapter->link_speed = SPEED_0;
netif_stop_queue(netdev);
}
@@ -311,7 +307,7 @@ static void atl1e_set_multi(struct net_device *netdev)
AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
/* comoute mc addresses' hash value ,and put it into hash table */
- for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+ netdev_for_each_mc_addr(mc_ptr, netdev) {
hash_value = atl1e_hash_mc_addr(hw, mc_ptr->dmi_addr);
atl1e_hash_set(hw, hash_value);
}
@@ -321,10 +317,9 @@ static void atl1e_vlan_rx_register(struct net_device *netdev,
struct vlan_group *grp)
{
struct atl1e_adapter *adapter = netdev_priv(netdev);
- struct pci_dev *pdev = adapter->pdev;
u32 mac_ctrl_data = 0;
- dev_dbg(&pdev->dev, "atl1e_vlan_rx_register\n");
+ netdev_dbg(adapter->netdev, "%s\n", __func__);
atl1e_irq_disable(adapter);
@@ -345,9 +340,7 @@ static void atl1e_vlan_rx_register(struct net_device *netdev,
static void atl1e_restore_vlan(struct atl1e_adapter *adapter)
{
- struct pci_dev *pdev = adapter->pdev;
-
- dev_dbg(&pdev->dev, "atl1e_restore_vlan !");
+ netdev_dbg(adapter->netdev, "%s\n", __func__);
atl1e_vlan_rx_register(adapter->netdev, adapter->vlgrp);
}
/*
@@ -391,7 +384,7 @@ static int atl1e_change_mtu(struct net_device *netdev, int new_mtu)
if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
(max_frame > MAX_JUMBO_FRAME_SIZE)) {
- dev_warn(&adapter->pdev->dev, "invalid MTU setting\n");
+ netdev_warn(adapter->netdev, "invalid MTU setting\n");
return -EINVAL;
}
/* set MTU */
@@ -438,7 +431,6 @@ static int atl1e_mii_ioctl(struct net_device *netdev,
struct ifreq *ifr, int cmd)
{
struct atl1e_adapter *adapter = netdev_priv(netdev);
- struct pci_dev *pdev = adapter->pdev;
struct mii_ioctl_data *data = if_mii(ifr);
unsigned long flags;
int retval = 0;
@@ -466,8 +458,8 @@ static int atl1e_mii_ioctl(struct net_device *netdev,
goto out;
}
- dev_dbg(&pdev->dev, "<atl1e_mii_ioctl> write %x %x",
- data->reg_num, data->val_in);
+ netdev_dbg(adapter->netdev, "<atl1e_mii_ioctl> write %x %x\n",
+ data->reg_num, data->val_in);
if (atl1e_write_phy_reg(&adapter->hw,
data->reg_num, data->val_in)) {
retval = -EIO;
@@ -602,7 +594,7 @@ static int __devinit atl1e_sw_init(struct atl1e_adapter *adapter)
hw->dmaw_dly_cnt = 4;
if (atl1e_alloc_queues(adapter)) {
- dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
+ netdev_err(adapter->netdev, "Unable to allocate memory for queues\n");
return -ENOMEM;
}
@@ -800,8 +792,8 @@ static int atl1e_setup_ring_resources(struct atl1e_adapter *adapter)
adapter->ring_size, &adapter->ring_dma);
if (adapter->ring_vir_addr == NULL) {
- dev_err(&pdev->dev, "pci_alloc_consistent failed, "
- "size = D%d", size);
+ netdev_err(adapter->netdev,
+ "pci_alloc_consistent failed, size = D%d\n", size);
return -ENOMEM;
}
@@ -817,7 +809,8 @@ static int atl1e_setup_ring_resources(struct atl1e_adapter *adapter)
size = sizeof(struct atl1e_tx_buffer) * (tx_ring->count);
tx_ring->tx_buffer = kzalloc(size, GFP_KERNEL);
if (tx_ring->tx_buffer == NULL) {
- dev_err(&pdev->dev, "kzalloc failed , size = D%d", size);
+ netdev_err(adapter->netdev, "kzalloc failed, size = D%d\n",
+ size);
err = -ENOMEM;
goto failed;
}
@@ -852,8 +845,8 @@ static int atl1e_setup_ring_resources(struct atl1e_adapter *adapter)
}
if (unlikely(offset > adapter->ring_size)) {
- dev_err(&pdev->dev, "offset(%d) > ring size(%d) !!\n",
- offset, adapter->ring_size);
+ netdev_err(adapter->netdev, "offset(%d) > ring size(%d) !!\n",
+ offset, adapter->ring_size);
err = -1;
goto failed;
}
@@ -1077,7 +1070,6 @@ static void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter)
static int atl1e_configure(struct atl1e_adapter *adapter)
{
struct atl1e_hw *hw = &adapter->hw;
- struct pci_dev *pdev = adapter->pdev;
u32 intr_status_data = 0;
@@ -1130,8 +1122,8 @@ static int atl1e_configure(struct atl1e_adapter *adapter)
intr_status_data = AT_READ_REG(hw, REG_ISR);
if (unlikely((intr_status_data & ISR_PHY_LINKDOWN) != 0)) {
- dev_err(&pdev->dev, "atl1e_configure failed,"
- "PCIE phy link down\n");
+ netdev_err(adapter->netdev,
+ "atl1e_configure failed, PCIE phy link down\n");
return -1;
}
@@ -1262,7 +1254,6 @@ static irqreturn_t atl1e_intr(int irq, void *data)
{
struct net_device *netdev = data;
struct atl1e_adapter *adapter = netdev_priv(netdev);
- struct pci_dev *pdev = adapter->pdev;
struct atl1e_hw *hw = &adapter->hw;
int max_ints = AT_MAX_INT_WORK;
int handled = IRQ_NONE;
@@ -1285,8 +1276,8 @@ static irqreturn_t atl1e_intr(int irq, void *data)
handled = IRQ_HANDLED;
/* check if PCIE PHY Link down */
if (status & ISR_PHY_LINKDOWN) {
- dev_err(&pdev->dev,
- "pcie phy linkdown %x\n", status);
+ netdev_err(adapter->netdev,
+ "pcie phy linkdown %x\n", status);
if (netif_running(adapter->netdev)) {
/* reset MAC */
atl1e_irq_reset(adapter);
@@ -1297,9 +1288,9 @@ static irqreturn_t atl1e_intr(int irq, void *data)
/* check if DMA read/write error */
if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
- dev_err(&pdev->dev,
- "PCIE DMA RW error (status = 0x%x)\n",
- status);
+ netdev_err(adapter->netdev,
+ "PCIE DMA RW error (status = 0x%x)\n",
+ status);
atl1e_irq_reset(adapter);
schedule_work(&adapter->reset_task);
break;
@@ -1382,7 +1373,6 @@ static struct atl1e_rx_page *atl1e_get_rx_page(struct atl1e_adapter *adapter,
static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que,
int *work_done, int work_to_do)
{
- struct pci_dev *pdev = adapter->pdev;
struct net_device *netdev = adapter->netdev;
struct atl1e_rx_ring *rx_ring = (struct atl1e_rx_ring *)
&adapter->rx_ring;
@@ -1404,11 +1394,10 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que,
rx_page->read_offset);
/* check sequence number */
if (prrs->seq_num != rx_page_desc[que].rx_nxseq) {
- dev_err(&pdev->dev,
- "rx sequence number"
- " error (rx=%d) (expect=%d)\n",
- prrs->seq_num,
- rx_page_desc[que].rx_nxseq);
+ netdev_err(netdev,
+ "rx sequence number error (rx=%d) (expect=%d)\n",
+ prrs->seq_num,
+ rx_page_desc[que].rx_nxseq);
rx_page_desc[que].rx_nxseq++;
/* just for debug use */
AT_WRITE_REG(&adapter->hw, REG_DEBUG_DATA0,
@@ -1424,9 +1413,9 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que,
RRS_ERR_DRIBBLE | RRS_ERR_CODE |
RRS_ERR_TRUNC)) {
/* hardware error, discard this packet*/
- dev_err(&pdev->dev,
- "rx packet desc error %x\n",
- *((u32 *)prrs + 1));
+ netdev_err(netdev,
+ "rx packet desc error %x\n",
+ *((u32 *)prrs + 1));
goto skip_pkt;
}
}
@@ -1435,8 +1424,8 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que,
RRS_PKT_SIZE_MASK) - 4; /* CRC */
skb = netdev_alloc_skb_ip_align(netdev, packet_size);
if (skb == NULL) {
- dev_warn(&pdev->dev, "%s: Memory squeeze,"
- "deferring packet.\n", netdev->name);
+ netdev_warn(netdev,
+ "Memory squeeze, deferring packet\n");
goto skip_pkt;
}
skb->dev = netdev;
@@ -1450,9 +1439,9 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que,
u16 vlan_tag = (prrs->vtag >> 4) |
((prrs->vtag & 7) << 13) |
((prrs->vtag & 8) << 9);
- dev_dbg(&pdev->dev,
- "RXD VLAN TAG<RRD>=0x%04x\n",
- prrs->vtag);
+ netdev_dbg(netdev,
+ "RXD VLAN TAG<RRD>=0x%04x\n",
+ prrs->vtag);
vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
vlan_tag);
} else {
@@ -1500,7 +1489,6 @@ static int atl1e_clean(struct napi_struct *napi, int budget)
{
struct atl1e_adapter *adapter =
container_of(napi, struct atl1e_adapter, napi);
- struct pci_dev *pdev = adapter->pdev;
u32 imr_data;
int work_done = 0;
@@ -1519,8 +1507,8 @@ quit_polling:
/* test debug */
if (test_bit(__AT_DOWN, &adapter->flags)) {
atomic_dec(&adapter->irq_sem);
- dev_err(&pdev->dev,
- "atl1e_clean is called when AT_DOWN\n");
+ netdev_err(adapter->netdev,
+ "atl1e_clean is called when AT_DOWN\n");
}
/* reenable RX intr */
/*atl1e_irq_enable(adapter); */
@@ -1618,7 +1606,6 @@ static u16 atl1e_cal_tdp_req(const struct sk_buff *skb)
static int atl1e_tso_csum(struct atl1e_adapter *adapter,
struct sk_buff *skb, struct atl1e_tpd_desc *tpd)
{
- struct pci_dev *pdev = adapter->pdev;
u8 hdr_len;
u32 real_len;
unsigned short offload_type;
@@ -1642,8 +1629,8 @@ static int atl1e_tso_csum(struct atl1e_adapter *adapter,
hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
if (unlikely(skb->len == hdr_len)) {
/* only xsum need */
- dev_warn(&pdev->dev,
- "IPV4 tso with zero data??\n");
+ netdev_warn(adapter->netdev,
+ "IPV4 tso with zero data??\n");
goto check_sum;
} else {
ip_hdr(skb)->check = 0;
@@ -1672,8 +1659,8 @@ check_sum:
cso = skb_transport_offset(skb);
if (unlikely(cso & 0x1)) {
- dev_err(&adapter->pdev->dev,
- "pay load offset should not ant event number\n");
+ netdev_err(adapter->netdev,
+ "payload offset should not ant event number\n");
return -1;
} else {
css = cso + skb->csum_offset;
@@ -1886,8 +1873,8 @@ static int atl1e_request_irq(struct atl1e_adapter *adapter)
adapter->have_msi = true;
err = pci_enable_msi(adapter->pdev);
if (err) {
- dev_dbg(&pdev->dev,
- "Unable to allocate MSI interrupt Error: %d\n", err);
+ netdev_dbg(adapter->netdev,
+ "Unable to allocate MSI interrupt Error: %d\n", err);
adapter->have_msi = false;
} else
netdev->irq = pdev->irq;
@@ -1898,13 +1885,13 @@ static int atl1e_request_irq(struct atl1e_adapter *adapter)
err = request_irq(adapter->pdev->irq, atl1e_intr, flags,
netdev->name, netdev);
if (err) {
- dev_dbg(&pdev->dev,
- "Unable to allocate interrupt Error: %d\n", err);
+ netdev_dbg(adapter->netdev,
+ "Unable to allocate interrupt Error: %d\n", err);
if (adapter->have_msi)
pci_disable_msi(adapter->pdev);
return err;
}
- dev_dbg(&pdev->dev, "atl1e_request_irq OK\n");
+ netdev_dbg(adapter->netdev, "atl1e_request_irq OK\n");
return err;
}
@@ -2078,7 +2065,7 @@ static int atl1e_suspend(struct pci_dev *pdev, pm_message_t state)
(atl1e_write_phy_reg(hw,
MII_ADVERTISE, mii_advertise_data) != 0) ||
(atl1e_phy_commit(hw)) != 0) {
- dev_dbg(&pdev->dev, "set phy register failed\n");
+ netdev_dbg(adapter->netdev, "set phy register failed\n");
goto wol_dis;
}
@@ -2100,17 +2087,14 @@ static int atl1e_suspend(struct pci_dev *pdev, pm_message_t state)
}
if ((mii_bmsr_data & BMSR_LSTATUS) == 0)
- dev_dbg(&pdev->dev,
- "%s: Link may change"
- "when suspend\n",
- atl1e_driver_name);
+ netdev_dbg(adapter->netdev,
+ "Link may change when suspend\n");
}
wol_ctrl_data |= WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN;
/* only link up can wake up */
if (atl1e_write_phy_reg(hw, MII_INT_CTRL, 0x400) != 0) {
- dev_dbg(&pdev->dev, "%s: read write phy "
- "register failed.\n",
- atl1e_driver_name);
+ netdev_dbg(adapter->netdev,
+ "read write phy register failed\n");
goto wol_dis;
}
}
@@ -2131,9 +2115,8 @@ static int atl1e_suspend(struct pci_dev *pdev, pm_message_t state)
if (wufc & AT_WUFC_MAG)
mac_ctrl_data |= MAC_CTRL_BC_EN;
- dev_dbg(&pdev->dev,
- "%s: suspend MAC=0x%x\n",
- atl1e_driver_name, mac_ctrl_data);
+ netdev_dbg(adapter->netdev, "suspend MAC=0x%x\n",
+ mac_ctrl_data);
AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data);
AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
@@ -2183,8 +2166,8 @@ static int atl1e_resume(struct pci_dev *pdev)
err = pci_enable_device(pdev);
if (err) {
- dev_err(&pdev->dev, "ATL1e: Cannot enable PCI"
- " device from suspend\n");
+ netdev_err(adapter->netdev,
+ "Cannot enable PCI device from suspend\n");
return err;
}
@@ -2315,7 +2298,7 @@ static int __devinit atl1e_probe(struct pci_dev *pdev,
err = atl1e_init_netdev(netdev, pdev);
if (err) {
- dev_err(&pdev->dev, "init netdevice failed\n");
+ netdev_err(netdev, "init netdevice failed\n");
goto err_init_netdev;
}
adapter = netdev_priv(netdev);
@@ -2326,7 +2309,7 @@ static int __devinit atl1e_probe(struct pci_dev *pdev,
adapter->hw.hw_addr = pci_iomap(pdev, BAR_0, 0);
if (!adapter->hw.hw_addr) {
err = -EIO;
- dev_err(&pdev->dev, "cannot map device registers\n");
+ netdev_err(netdev, "cannot map device registers\n");
goto err_ioremap;
}
netdev->base_addr = (unsigned long)adapter->hw.hw_addr;
@@ -2356,7 +2339,7 @@ static int __devinit atl1e_probe(struct pci_dev *pdev,
/* setup the private structure */
err = atl1e_sw_init(adapter);
if (err) {
- dev_err(&pdev->dev, "net device private data init failed\n");
+ netdev_err(netdev, "net device private data init failed\n");
goto err_sw_init;
}
@@ -2372,22 +2355,19 @@ static int __devinit atl1e_probe(struct pci_dev *pdev,
if (atl1e_read_mac_addr(&adapter->hw) != 0) {
err = -EIO;
- dev_err(&pdev->dev, "get mac address failed\n");
+ netdev_err(netdev, "get mac address failed\n");
goto err_eeprom;
}
memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
- dev_dbg(&pdev->dev, "mac address : %02x-%02x-%02x-%02x-%02x-%02x\n",
- adapter->hw.mac_addr[0], adapter->hw.mac_addr[1],
- adapter->hw.mac_addr[2], adapter->hw.mac_addr[3],
- adapter->hw.mac_addr[4], adapter->hw.mac_addr[5]);
+ netdev_dbg(netdev, "mac address : %pM\n", adapter->hw.mac_addr);
INIT_WORK(&adapter->reset_task, atl1e_reset_task);
INIT_WORK(&adapter->link_chg_task, atl1e_link_chg_task);
err = register_netdev(netdev);
if (err) {
- dev_err(&pdev->dev, "register netdevice failed\n");
+ netdev_err(netdev, "register netdevice failed\n");
goto err_register;
}
@@ -2488,8 +2468,8 @@ static pci_ers_result_t atl1e_io_slot_reset(struct pci_dev *pdev)
struct atl1e_adapter *adapter = netdev_priv(netdev);
if (pci_enable_device(pdev)) {
- dev_err(&pdev->dev,
- "ATL1e: Cannot re-enable PCI device after reset.\n");
+ netdev_err(adapter->netdev,
+ "Cannot re-enable PCI device after reset\n");
return PCI_ERS_RESULT_DISCONNECT;
}
pci_set_master(pdev);
@@ -2517,8 +2497,8 @@ static void atl1e_io_resume(struct pci_dev *pdev)
if (netif_running(netdev)) {
if (atl1e_up(adapter)) {
- dev_err(&pdev->dev,
- "ATL1e: can't bring device back up after reset\n");
+ netdev_err(adapter->netdev,
+ "can't bring device back up after reset\n");
return;
}
}
diff --git a/drivers/net/atl1e/atl1e_param.c b/drivers/net/atl1e/atl1e_param.c
index b3be59fd3fb5..0ce60b6e7ef0 100644
--- a/drivers/net/atl1e/atl1e_param.c
+++ b/drivers/net/atl1e/atl1e_param.c
@@ -116,7 +116,7 @@ struct atl1e_option {
} arg;
};
-static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt, struct pci_dev *pdev)
+static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt, struct atl1e_adapter *adapter)
{
if (*value == OPTION_UNSET) {
*value = opt->def;
@@ -127,16 +127,19 @@ static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt,
case enable_option:
switch (*value) {
case OPTION_ENABLED:
- dev_info(&pdev->dev, "%s Enabled\n", opt->name);
+ netdev_info(adapter->netdev,
+ "%s Enabled\n", opt->name);
return 0;
case OPTION_DISABLED:
- dev_info(&pdev->dev, "%s Disabled\n", opt->name);
+ netdev_info(adapter->netdev,
+ "%s Disabled\n", opt->name);
return 0;
}
break;
case range_option:
if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
- dev_info(&pdev->dev, "%s set to %i\n", opt->name, *value);
+ netdev_info(adapter->netdev, "%s set to %i\n",
+ opt->name, *value);
return 0;
}
break;
@@ -148,8 +151,8 @@ static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt,
ent = &opt->arg.l.p[i];
if (*value == ent->i) {
if (ent->str[0] != '\0')
- dev_info(&pdev->dev, "%s\n",
- ent->str);
+ netdev_info(adapter->netdev,
+ "%s\n", ent->str);
return 0;
}
}
@@ -159,8 +162,8 @@ static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt,
BUG();
}
- dev_info(&pdev->dev, "Invalid %s specified (%i) %s\n",
- opt->name, *value, opt->err);
+ netdev_info(adapter->netdev, "Invalid %s specified (%i) %s\n",
+ opt->name, *value, opt->err);
*value = opt->def;
return -1;
}
@@ -176,11 +179,13 @@ static int __devinit atl1e_validate_option(int *value, struct atl1e_option *opt,
*/
void __devinit atl1e_check_options(struct atl1e_adapter *adapter)
{
- struct pci_dev *pdev = adapter->pdev;
int bd = adapter->bd_number;
+
if (bd >= ATL1E_MAX_NIC) {
- dev_notice(&pdev->dev, "no configuration for board #%i\n", bd);
- dev_notice(&pdev->dev, "Using defaults for all values\n");
+ netdev_notice(adapter->netdev,
+ "no configuration for board #%i\n", bd);
+ netdev_notice(adapter->netdev,
+ "Using defaults for all values\n");
}
{ /* Transmit Ring Size */
@@ -196,7 +201,7 @@ void __devinit atl1e_check_options(struct atl1e_adapter *adapter)
int val;
if (num_tx_desc_cnt > bd) {
val = tx_desc_cnt[bd];
- atl1e_validate_option(&val, &opt, pdev);
+ atl1e_validate_option(&val, &opt, adapter);
adapter->tx_ring.count = (u16) val & 0xFFFC;
} else
adapter->tx_ring.count = (u16)opt.def;
@@ -215,7 +220,7 @@ void __devinit atl1e_check_options(struct atl1e_adapter *adapter)
int val;
if (num_rx_mem_size > bd) {
val = rx_mem_size[bd];
- atl1e_validate_option(&val, &opt, pdev);
+ atl1e_validate_option(&val, &opt, adapter);
adapter->rx_ring.page_size = (u32)val * 1024;
} else {
adapter->rx_ring.page_size = (u32)opt.def * 1024;
@@ -235,7 +240,7 @@ void __devinit atl1e_check_options(struct atl1e_adapter *adapter)
int val;
if (num_int_mod_timer > bd) {
val = int_mod_timer[bd];
- atl1e_validate_option(&val, &opt, pdev);
+ atl1e_validate_option(&val, &opt, adapter);
adapter->hw.imt = (u16) val;
} else
adapter->hw.imt = (u16)(opt.def);
@@ -254,7 +259,7 @@ void __devinit atl1e_check_options(struct atl1e_adapter *adapter)
int val;
if (num_media_type > bd) {
val = media_type[bd];
- atl1e_validate_option(&val, &opt, pdev);
+ atl1e_validate_option(&val, &opt, adapter);
adapter->hw.media_type = (u16) val;
} else
adapter->hw.media_type = (u16)(opt.def);
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index b6cf3263127c..9ba547069db3 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -232,7 +232,7 @@ static void __devinit atl1_check_options(struct atl1_adapter *adapter)
/*
* atl1_pci_tbl - PCI Device ID Table
*/
-static const struct pci_device_id atl1_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(atl1_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1)},
/* required last entry */
{0,}
diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c
index ec52529394ad..7061d7108f08 100644
--- a/drivers/net/atlx/atl2.c
+++ b/drivers/net/atlx/atl2.c
@@ -63,7 +63,7 @@ MODULE_VERSION(ATL2_DRV_VERSION);
/*
* atl2_pci_tbl - PCI Device ID Table
*/
-static struct pci_device_id atl2_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(atl2_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2)},
/* required last entry */
{0,}
@@ -157,7 +157,7 @@ static void atl2_set_multi(struct net_device *netdev)
ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
/* comoute mc addresses' hash value ,and put it into hash table */
- for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+ netdev_for_each_mc_addr(mc_ptr, netdev) {
hash_value = atl2_hash_mc_addr(hw, mc_ptr->dmi_addr);
atl2_hash_set(hw, hash_value);
}
diff --git a/drivers/net/atlx/atl2.h b/drivers/net/atlx/atl2.h
index d918bbe621ea..927e4de6474d 100644
--- a/drivers/net/atlx/atl2.h
+++ b/drivers/net/atlx/atl2.h
@@ -442,7 +442,7 @@ struct atl2_hw {
struct atl2_ring_header {
/* pointer to the descriptor ring memory */
void *desc;
- /* physical adress of the descriptor ring */
+ /* physical address of the descriptor ring */
dma_addr_t dma;
/* length of descriptor ring in bytes */
unsigned int size;
diff --git a/drivers/net/atlx/atlx.c b/drivers/net/atlx/atlx.c
index 3dc014215679..72f3306352e2 100644
--- a/drivers/net/atlx/atlx.c
+++ b/drivers/net/atlx/atlx.c
@@ -144,7 +144,7 @@ static void atlx_set_multi(struct net_device *netdev)
iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2));
/* compute mc addresses' hash value ,and put it into hash table */
- for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+ netdev_for_each_mc_addr(mc_ptr, netdev) {
hash_value = atlx_hash_mc_addr(hw, mc_ptr->dmi_addr);
atlx_hash_set(hw, hash_value);
}
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 2f8261c9614a..6ad16205dc17 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -861,7 +861,7 @@ static void set_rx_mode_8002(struct net_device *dev)
struct net_local *lp = netdev_priv(dev);
long ioaddr = dev->base_addr;
- if (dev->mc_count > 0 || (dev->flags & (IFF_ALLMULTI|IFF_PROMISC)))
+ if (!netdev_mc_empty(dev) || (dev->flags & (IFF_ALLMULTI|IFF_PROMISC)))
lp->addr_mode = CMR2h_PROMISC;
else
lp->addr_mode = CMR2h_Normal;
@@ -877,7 +877,8 @@ static void set_rx_mode_8012(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
new_mode = CMR2h_PROMISC;
- } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
+ } else if ((netdev_mc_count(dev) > 1000) ||
+ (dev->flags & IFF_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */
memset(mc_filter, 0xff, sizeof(mc_filter));
new_mode = CMR2h_Normal;
@@ -885,9 +886,7 @@ static void set_rx_mode_8012(struct net_device *dev)
struct dev_mc_list *mclist;
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next)
- {
+ netdev_for_each_mc_addr(mclist, dev) {
int filterbit = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f;
mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
}
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 6bac04603a88..4da191b87b0d 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -55,6 +55,7 @@
#include <linux/delay.h>
#include <linux/crc32.h>
#include <linux/phy.h>
+#include <linux/platform_device.h>
#include <asm/cpu.h>
#include <asm/mipsregs.h>
@@ -63,6 +64,7 @@
#include <asm/processor.h>
#include <au1000.h>
+#include <au1xxx_eth.h>
#include <prom.h>
#include "au1000_eth.h"
@@ -112,15 +114,15 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES];
*
* PHY detection algorithm
*
- * If AU1XXX_PHY_STATIC_CONFIG is undefined, the PHY setup is
+ * If 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
+ * selecting the first (or last, if 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
+ * controller's PHY and phy1_search_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.
@@ -129,9 +131,7 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES];
* controller is not registered to the network subsystem.
*/
-/* autodetection defaults */
-#undef AU1XXX_PHY_SEARCH_HIGHEST_ADDR
-#define AU1XXX_PHY1_SEARCH_ON_MAC0
+/* autodetection defaults: phy1_search_mac0 */
/* static PHY setup
*
@@ -148,29 +148,6 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES];
* specific irq-map
*/
-#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
-
-# define AU1XXX_PHY0_ADDR 5
-# define AU1XXX_PHY0_BUSID 0
-# undef AU1XXX_PHY0_IRQ
-
-# undef AU1XXX_PHY1_ADDR
-# undef AU1XXX_PHY1_BUSID
-# undef AU1XXX_PHY1_IRQ
-#endif
-
-#if defined(AU1XXX_PHY0_BUSID) && (AU1XXX_PHY0_BUSID > 0)
-# error MAC0-associated PHY attached 2nd MACs MII bus not supported yet
-#endif
-
static void enable_mac(struct net_device *dev, int force_reset)
{
unsigned long flags;
@@ -390,67 +367,55 @@ static int mii_probe (struct net_device *dev)
struct au1000_private *const aup = netdev_priv(dev);
struct phy_device *phydev = NULL;
-#if defined(AU1XXX_PHY_STATIC_CONFIG)
- BUG_ON(aup->mac_id < 0 || aup->mac_id > 1);
+ if (aup->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);
+ if (aup->phy_addr)
+ phydev = aup->mii_bus->phy_map[aup->phy_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
- }
+ } else {
+ 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 (!aup->phy_search_highest_addr)
+ break; /* break out with first one found */
+ }
-# 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");
+ if (aup->phy1_search_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 =
+ aup->mii_bus->phy_map[phy_addr];
- /* 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 (aup->mac_id == 1)
+ break;
- if (!tmp_phydev)
- continue; /* no PHY here... */
+ if (!tmp_phydev)
+ continue; /* no PHY here... */
- if (tmp_phydev->attached_dev)
- continue; /* already claimed by MAC0 */
+ if (tmp_phydev->attached_dev)
+ continue; /* already claimed by MAC0 */
- phydev = tmp_phydev;
- break; /* found it */
+ phydev = tmp_phydev;
+ break; /* found it */
+ }
+ }
}
}
-# endif /* defined(AU1XXX_PHY1_SEARCH_OTHER_BUS) */
-#endif /* defined(AU1XXX_PHY_STATIC_CONFIG) */
if (!phydev) {
printk (KERN_ERR DRV_NAME ":%s: no PHY found\n", dev->name);
return -1;
@@ -578,31 +543,6 @@ setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
}
}
-static struct {
- u32 base_addr;
- u32 macen_addr;
- int irq;
- struct net_device *dev;
-} 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;
-
/*
* ethtool operations
*/
@@ -711,7 +651,6 @@ static int au1000_init(struct net_device *dev)
static inline void update_rx_stats(struct net_device *dev, u32 status)
{
- struct au1000_private *aup = netdev_priv(dev);
struct net_device_stats *ps = &dev->stats;
ps->rx_packets++;
@@ -969,7 +908,7 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
}
pDB = aup->tx_db_inuse[aup->tx_head];
- skb_copy_from_linear_data(skb, pDB->vaddr, skb->len);
+ skb_copy_from_linear_data(skb, (void *)pDB->vaddr, skb->len);
if (skb->len < ETH_ZLEN) {
for (i=skb->len; i<ETH_ZLEN; i++) {
((char *)pDB->vaddr)[i] = 0;
@@ -1013,21 +952,18 @@ static void au1000_multicast_list(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
aup->mac->control |= MAC_PROMISCUOUS;
} else if ((dev->flags & IFF_ALLMULTI) ||
- dev->mc_count > MULTICAST_FILTER_LIMIT) {
+ netdev_mc_count(dev) > MULTICAST_FILTER_LIMIT) {
aup->mac->control |= MAC_PASS_ALL_MULTI;
aup->mac->control &= ~MAC_PROMISCUOUS;
printk(KERN_INFO "%s: Pass all multicast\n", dev->name);
} else {
- int i;
struct dev_mc_list *mclist;
u32 mc_filter[2]; /* Multicast hash filter */
mc_filter[1] = mc_filter[0] = 0;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev)
set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26,
(long *)mc_filter);
- }
aup->mac->multi_hash_high = mc_filter[1];
aup->mac->multi_hash_low = mc_filter[0];
aup->mac->control &= ~MAC_PROMISCUOUS;
@@ -1058,53 +994,59 @@ static const struct net_device_ops au1000_netdev_ops = {
.ndo_change_mtu = eth_change_mtu,
};
-static struct net_device * au1000_probe(int port_num)
+static int __devinit au1000_probe(struct platform_device *pdev)
{
static unsigned version_printed = 0;
struct au1000_private *aup = NULL;
+ struct au1000_eth_platform_data *pd;
struct net_device *dev = NULL;
db_dest_t *pDB, *pDBfree;
+ int irq, i, err = 0;
+ struct resource *base, *macen;
char ethaddr[6];
- int irq, i, err;
- u32 base, macen;
- if (port_num >= NUM_ETH_INTERFACES)
- return NULL;
+ base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!base) {
+ printk(KERN_ERR DRV_NAME ": failed to retrieve base register\n");
+ err = -ENODEV;
+ goto out;
+ }
- base = CPHYSADDR(iflist[port_num].base_addr );
- macen = CPHYSADDR(iflist[port_num].macen_addr);
- irq = iflist[port_num].irq;
+ macen = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!macen) {
+ printk(KERN_ERR DRV_NAME ": failed to retrieve MAC Enable register\n");
+ err = -ENODEV;
+ goto out;
+ }
- if (!request_mem_region( base, MAC_IOSIZE, "Au1x00 ENET") ||
- !request_mem_region(macen, 4, "Au1x00 ENET"))
- return NULL;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ printk(KERN_ERR DRV_NAME ": failed to retrieve IRQ\n");
+ err = -ENODEV;
+ goto out;
+ }
- if (version_printed++ == 0)
- printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
+ if (!request_mem_region(base->start, resource_size(base), pdev->name)) {
+ printk(KERN_ERR DRV_NAME ": failed to request memory region for base registers\n");
+ err = -ENXIO;
+ goto out;
+ }
+
+ if (!request_mem_region(macen->start, resource_size(macen), pdev->name)) {
+ printk(KERN_ERR DRV_NAME ": failed to request memory region for MAC enable register\n");
+ err = -ENXIO;
+ goto err_request;
+ }
dev = alloc_etherdev(sizeof(struct au1000_private));
if (!dev) {
printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME);
- return NULL;
+ err = -ENOMEM;
+ goto err_alloc;
}
- dev->base_addr = base;
- dev->irq = irq;
- dev->netdev_ops = &au1000_netdev_ops;
- SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
- dev->watchdog_timeo = ETH_TX_TIMEOUT;
-
- err = register_netdev(dev);
- if (err != 0) {
- printk(KERN_ERR "%s: Cannot register net device, error %d\n",
- DRV_NAME, err);
- free_netdev(dev);
- return NULL;
- }
-
- printk("%s: Au1xx0 Ethernet found at 0x%x, irq %d\n",
- dev->name, base, irq);
-
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ platform_set_drvdata(pdev, dev);
aup = netdev_priv(dev);
spin_lock_init(&aup->lock);
@@ -1115,21 +1057,29 @@ static struct net_device * au1000_probe(int port_num)
(NUM_TX_BUFFS + NUM_RX_BUFFS),
&aup->dma_addr, 0);
if (!aup->vaddr) {
- free_netdev(dev);
- release_mem_region( base, MAC_IOSIZE);
- release_mem_region(macen, 4);
- return NULL;
+ printk(KERN_ERR DRV_NAME ": failed to allocate data buffers\n");
+ err = -ENOMEM;
+ goto err_vaddr;
}
/* aup->mac is the base address of the MAC's registers */
- aup->mac = (volatile mac_reg_t *)iflist[port_num].base_addr;
+ aup->mac = (volatile mac_reg_t *)ioremap_nocache(base->start, resource_size(base));
+ if (!aup->mac) {
+ printk(KERN_ERR DRV_NAME ": failed to ioremap MAC registers\n");
+ err = -ENXIO;
+ goto err_remap1;
+ }
- /* Setup some variables for quick register address access */
- aup->enable = (volatile u32 *)iflist[port_num].macen_addr;
- aup->mac_id = port_num;
- au_macs[port_num] = aup;
+ /* Setup some variables for quick register address access */
+ aup->enable = (volatile u32 *)ioremap_nocache(macen->start, resource_size(macen));
+ if (!aup->enable) {
+ printk(KERN_ERR DRV_NAME ": failed to ioremap MAC enable register\n");
+ err = -ENXIO;
+ goto err_remap2;
+ }
+ aup->mac_id = pdev->id;
- if (port_num == 0) {
+ if (pdev->id == 0) {
if (prom_get_ethernet_addr(ethaddr) == 0)
memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
else {
@@ -1139,7 +1089,7 @@ static struct net_device * au1000_probe(int port_num)
}
setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
- } else if (port_num == 1)
+ } else if (pdev->id == 1)
setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
/*
@@ -1147,14 +1097,37 @@ static struct net_device * au1000_probe(int port_num)
* 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;
+ dev->dev_addr[5] += pdev->id;
*aup->enable = 0;
aup->mac_enabled = 0;
+ pd = pdev->dev.platform_data;
+ if (!pd) {
+ printk(KERN_INFO DRV_NAME ": no platform_data passed, PHY search on MAC0\n");
+ aup->phy1_search_mac0 = 1;
+ } else {
+ aup->phy_static_config = pd->phy_static_config;
+ aup->phy_search_highest_addr = pd->phy_search_highest_addr;
+ aup->phy1_search_mac0 = pd->phy1_search_mac0;
+ aup->phy_addr = pd->phy_addr;
+ aup->phy_busid = pd->phy_busid;
+ aup->phy_irq = pd->phy_irq;
+ }
+
+ if (aup->phy_busid && aup->phy_busid > 0) {
+ printk(KERN_ERR DRV_NAME ": MAC0-associated PHY attached 2nd MACs MII"
+ "bus not supported yet\n");
+ err = -ENODEV;
+ goto err_mdiobus_alloc;
+ }
+
aup->mii_bus = mdiobus_alloc();
- if (aup->mii_bus == NULL)
- goto err_out;
+ if (aup->mii_bus == NULL) {
+ printk(KERN_ERR DRV_NAME ": failed to allocate mdiobus structure\n");
+ err = -ENOMEM;
+ goto err_mdiobus_alloc;
+ }
aup->mii_bus->priv = dev;
aup->mii_bus->read = au1000_mdiobus_read;
@@ -1168,23 +1141,19 @@ static struct net_device * au1000_probe(int port_num)
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->mac_id)
- aup->mii_bus->irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ;
-# endif
-# if defined(AU1XXX_PHY1_IRQ)
- if (AU1XXX_PHY1_BUSID == aup->mac_id)
- aup->mii_bus->irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ;
-# endif
-#endif
- mdiobus_register(aup->mii_bus);
+ if (aup->phy_static_config)
+ if (aup->phy_irq && aup->phy_busid == aup->mac_id)
+ aup->mii_bus->irq[aup->phy_addr] = aup->phy_irq;
+
+ err = mdiobus_register(aup->mii_bus);
+ if (err) {
+ printk(KERN_ERR DRV_NAME " failed to register MDIO bus\n");
+ goto err_mdiobus_reg;
+ }
- if (mii_probe(dev) != 0) {
+ if (mii_probe(dev) != 0)
goto err_out;
- }
pDBfree = NULL;
/* setup the data buffer descriptors and attach a buffer to each one */
@@ -1216,19 +1185,35 @@ static struct net_device * au1000_probe(int port_num)
aup->tx_db_inuse[i] = pDB;
}
+ dev->base_addr = base->start;
+ dev->irq = irq;
+ dev->netdev_ops = &au1000_netdev_ops;
+ SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
+ dev->watchdog_timeo = ETH_TX_TIMEOUT;
+
/*
* The boot code uses the ethernet controller, so reset it to start
* fresh. au1000_init() expects that the device is in reset state.
*/
reset_mac(dev);
- return dev;
+ err = register_netdev(dev);
+ if (err) {
+ printk(KERN_ERR DRV_NAME "%s: Cannot register net device, aborting.\n",
+ dev->name);
+ goto err_out;
+ }
+
+ printk("%s: Au1xx0 Ethernet found at 0x%lx, irq %d\n",
+ dev->name, (unsigned long)base->start, irq);
+ if (version_printed++ == 0)
+ printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
+
+ return 0;
err_out:
- if (aup->mii_bus != NULL) {
+ if (aup->mii_bus != NULL)
mdiobus_unregister(aup->mii_bus);
- mdiobus_free(aup->mii_bus);
- }
/* here we should have a valid dev plus aup-> register addresses
* so we can reset the mac properly.*/
@@ -1242,67 +1227,84 @@ err_out:
if (aup->tx_db_inuse[i])
ReleaseDB(aup, aup->tx_db_inuse[i]);
}
+err_mdiobus_reg:
+ mdiobus_free(aup->mii_bus);
+err_mdiobus_alloc:
+ iounmap(aup->enable);
+err_remap2:
+ iounmap(aup->mac);
+err_remap1:
dma_free_noncoherent(NULL, MAX_BUF_SIZE * (NUM_TX_BUFFS + NUM_RX_BUFFS),
(void *)aup->vaddr, aup->dma_addr);
- unregister_netdev(dev);
+err_vaddr:
free_netdev(dev);
- release_mem_region( base, MAC_IOSIZE);
- release_mem_region(macen, 4);
- return NULL;
+err_alloc:
+ release_mem_region(macen->start, resource_size(macen));
+err_request:
+ release_mem_region(base->start, resource_size(base));
+out:
+ return err;
}
-/*
- * Setup the base address and interrupt of the Au1xxx ethernet macs
- * based on cpu type and whether the interface is enabled in sys_pinfunc
- * register. The last interface is enabled if SYS_PF_NI2 (bit 4) is 0.
- */
-static int __init au1000_init_module(void)
+static int __devexit au1000_remove(struct platform_device *pdev)
{
- int ni = (int)((au_readl(SYS_PINFUNC) & (u32)(SYS_PF_NI2)) >> 4);
- struct net_device *dev;
- int i, found_one = 0;
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct au1000_private *aup = netdev_priv(dev);
+ int i;
+ struct resource *base, *macen;
- num_ifs = NUM_ETH_INTERFACES - ni;
+ platform_set_drvdata(pdev, NULL);
+
+ unregister_netdev(dev);
+ mdiobus_unregister(aup->mii_bus);
+ mdiobus_free(aup->mii_bus);
+
+ for (i = 0; i < NUM_RX_DMA; i++)
+ if (aup->rx_db_inuse[i])
+ ReleaseDB(aup, aup->rx_db_inuse[i]);
+
+ for (i = 0; i < NUM_TX_DMA; i++)
+ 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);
+
+ iounmap(aup->mac);
+ iounmap(aup->enable);
+
+ base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(base->start, resource_size(base));
+
+ macen = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ release_mem_region(macen->start, resource_size(macen));
+
+ free_netdev(dev);
- for(i = 0; i < num_ifs; i++) {
- dev = au1000_probe(i);
- iflist[i].dev = dev;
- if (dev)
- found_one++;
- }
- if (!found_one)
- return -ENODEV;
return 0;
}
-static void __exit au1000_cleanup_module(void)
+static struct platform_driver au1000_eth_driver = {
+ .probe = au1000_probe,
+ .remove = __devexit_p(au1000_remove),
+ .driver = {
+ .name = "au1000-eth",
+ .owner = THIS_MODULE,
+ },
+};
+MODULE_ALIAS("platform:au1000-eth");
+
+
+static int __init au1000_init_module(void)
+{
+ return platform_driver_register(&au1000_eth_driver);
+}
+
+static void __exit au1000_exit_module(void)
{
- int i, j;
- struct net_device *dev;
- struct au1000_private *aup;
-
- for (i = 0; i < num_ifs; i++) {
- dev = iflist[i].dev;
- if (dev) {
- aup = netdev_priv(dev);
- unregister_netdev(dev);
- mdiobus_unregister(aup->mii_bus);
- mdiobus_free(aup->mii_bus);
- 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++)
- 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);
- release_mem_region(dev->base_addr, MAC_IOSIZE);
- release_mem_region(CPHYSADDR(iflist[i].macen_addr), 4);
- free_netdev(dev);
- }
- }
+ platform_driver_unregister(&au1000_eth_driver);
}
module_init(au1000_init_module);
-module_exit(au1000_cleanup_module);
+module_exit(au1000_exit_module);
diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h
index 824ecd5ff3a8..f9d29a29b8fd 100644
--- a/drivers/net/au1000_eth.h
+++ b/drivers/net/au1000_eth.h
@@ -108,6 +108,15 @@ struct au1000_private {
struct phy_device *phy_dev;
struct mii_bus *mii_bus;
+ /* PHY configuration */
+ int phy_static_config;
+ int phy_search_highest_addr;
+ int phy1_search_mac0;
+
+ int phy_addr;
+ int phy_busid;
+ int phy_irq;
+
/* These variables are just for quick access to certain regs addresses. */
volatile mac_reg_t *mac; /* mac registers */
volatile u32 *enable; /* address of MAC Enable Register */
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index 62d9c9cc5671..1dd4403247ca 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -921,7 +921,7 @@ static int ax_probe(struct platform_device *pdev)
size = (res->end - res->start) + 1;
ax->mem2 = request_mem_region(res->start, size, pdev->name);
- if (ax->mem == NULL) {
+ if (ax->mem2 == NULL) {
dev_err(&pdev->dev, "cannot reserve registers\n");
ret = -ENXIO;
goto exit_mem1;
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 4869adb69586..332c60356285 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -10,6 +10,8 @@
* Distribute under GPL.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -34,7 +36,6 @@
#include "b44.h"
#define DRV_MODULE_NAME "b44"
-#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "2.0"
#define B44_DEF_MSG_ENABLE \
@@ -102,7 +103,7 @@ MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
#ifdef CONFIG_B44_PCI
-static const struct pci_device_id b44_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(b44_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1) },
@@ -189,11 +190,10 @@ static int b44_wait_bit(struct b44 *bp, unsigned long reg,
udelay(10);
}
if (i == timeout) {
- printk(KERN_ERR PFX "%s: BUG! Timeout waiting for bit %08x of register "
- "%lx to %s.\n",
- bp->dev->name,
- bit, reg,
- (clear ? "clear" : "set"));
+ if (net_ratelimit())
+ netdev_err(bp->dev, "BUG! Timeout waiting for bit %08x of register %lx to %s\n",
+ bit, reg, clear ? "clear" : "set");
+
return -ENODEV;
}
return 0;
@@ -333,13 +333,12 @@ static int b44_phy_reset(struct b44 *bp)
err = b44_readphy(bp, MII_BMCR, &val);
if (!err) {
if (val & BMCR_RESET) {
- printk(KERN_ERR PFX "%s: PHY Reset would not complete.\n",
- bp->dev->name);
+ netdev_err(bp->dev, "PHY Reset would not complete\n");
err = -ENODEV;
}
}
- return 0;
+ return err;
}
static void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags)
@@ -413,7 +412,7 @@ static void b44_wap54g10_workaround(struct b44 *bp)
}
return;
error:
- printk(KERN_WARNING PFX "PHY: cannot reset MII transceiver isolate bit.\n");
+ pr_warning("PHY: cannot reset MII transceiver isolate bit\n");
}
#else
static inline void b44_wap54g10_workaround(struct b44 *bp)
@@ -506,18 +505,15 @@ static void b44_stats_update(struct b44 *bp)
static void b44_link_report(struct b44 *bp)
{
if (!netif_carrier_ok(bp->dev)) {
- printk(KERN_INFO PFX "%s: Link is down.\n", bp->dev->name);
+ netdev_info(bp->dev, "Link is down\n");
} else {
- printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
- bp->dev->name,
- (bp->flags & B44_FLAG_100_BASE_T) ? 100 : 10,
- (bp->flags & B44_FLAG_FULL_DUPLEX) ? "full" : "half");
-
- printk(KERN_INFO PFX "%s: Flow control is %s for TX and "
- "%s for RX.\n",
- bp->dev->name,
- (bp->flags & B44_FLAG_TX_PAUSE) ? "on" : "off",
- (bp->flags & B44_FLAG_RX_PAUSE) ? "on" : "off");
+ netdev_info(bp->dev, "Link is up at %d Mbps, %s duplex\n",
+ (bp->flags & B44_FLAG_100_BASE_T) ? 100 : 10,
+ (bp->flags & B44_FLAG_FULL_DUPLEX) ? "full" : "half");
+
+ netdev_info(bp->dev, "Flow control is %s for TX and %s for RX\n",
+ (bp->flags & B44_FLAG_TX_PAUSE) ? "on" : "off",
+ (bp->flags & B44_FLAG_RX_PAUSE) ? "on" : "off");
}
}
@@ -576,11 +572,9 @@ static void b44_check_phy(struct b44 *bp)
}
if (bmsr & BMSR_RFAULT)
- printk(KERN_WARNING PFX "%s: Remote fault detected in PHY\n",
- bp->dev->name);
+ netdev_warn(bp->dev, "Remote fault detected in PHY\n");
if (bmsr & BMSR_JCD)
- printk(KERN_WARNING PFX "%s: Jabber detected in PHY\n",
- bp->dev->name);
+ netdev_warn(bp->dev, "Jabber detected in PHY\n");
}
}
@@ -815,7 +809,7 @@ static int b44_rx(struct b44 *bp, int budget)
struct sk_buff *copy_skb;
b44_recycle_rx(bp, cons, bp->rx_prod);
- copy_skb = dev_alloc_skb(len + 2);
+ copy_skb = netdev_alloc_skb(bp->dev, len + 2);
if (copy_skb == NULL)
goto drop_it_no_recycle;
@@ -901,7 +895,7 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id)
handled = 1;
if (unlikely(!netif_running(dev))) {
- printk(KERN_INFO "%s: late interrupt.\n", dev->name);
+ netdev_info(dev, "late interrupt\n");
goto irq_ack;
}
@@ -926,8 +920,7 @@ static void b44_tx_timeout(struct net_device *dev)
{
struct b44 *bp = netdev_priv(dev);
- printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
- dev->name);
+ netdev_err(dev, "transmit timed out, resetting\n");
spin_lock_irq(&bp->lock);
@@ -956,8 +949,7 @@ static netdev_tx_t b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* This is a hard error, log it. */
if (unlikely(TX_BUFFS_AVAIL(bp) < 1)) {
netif_stop_queue(dev);
- printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
- dev->name);
+ netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
goto err_out;
}
@@ -1333,7 +1325,7 @@ static void b44_halt(struct b44 *bp)
/* reset PHY */
b44_phy_reset(bp);
/* power down PHY */
- printk(KERN_INFO PFX "%s: powering down PHY\n", bp->dev->name);
+ netdev_info(bp->dev, "powering down PHY\n");
bw32(bp, B44_MAC_CTRL, MAC_CTRL_PHY_PDOWN);
/* now reset the chip, but without enabling the MAC&PHY
* part of it. This has to be done _after_ we shut down the PHY */
@@ -1524,7 +1516,7 @@ static void b44_setup_pseudo_magicp(struct b44 *bp)
pwol_pattern = kzalloc(B44_PATTERN_SIZE, GFP_KERNEL);
if (!pwol_pattern) {
- printk(KERN_ERR PFX "Memory not available for WOL\n");
+ pr_err("Memory not available for WOL\n");
return;
}
@@ -1691,10 +1683,12 @@ static int __b44_load_mcast(struct b44 *bp, struct net_device *dev)
struct dev_mc_list *mclist;
int i, num_ents;
- num_ents = min_t(int, dev->mc_count, B44_MCAST_TABLE_SIZE);
- mclist = dev->mc_list;
- for (i = 0; mclist && i < num_ents; i++, mclist = mclist->next) {
- __b44_cam_write(bp, mclist->dmi_addr, i + 1);
+ num_ents = min_t(int, netdev_mc_count(dev), B44_MCAST_TABLE_SIZE);
+ i = 0;
+ netdev_for_each_mc_addr(mclist, dev) {
+ if (i == num_ents)
+ break;
+ __b44_cam_write(bp, mclist->dmi_addr, i++ + 1);
}
return i+1;
}
@@ -1716,7 +1710,7 @@ static void __b44_set_rx_mode(struct net_device *dev)
__b44_set_mac_addr(bp);
if ((dev->flags & IFF_ALLMULTI) ||
- (dev->mc_count > B44_MCAST_TABLE_SIZE))
+ (netdev_mc_count(dev) > B44_MCAST_TABLE_SIZE))
val |= RXCONFIG_ALLMULTI;
else
i = __b44_load_mcast(bp, dev);
@@ -2097,7 +2091,7 @@ static int __devinit b44_get_invariants(struct b44 *bp)
memcpy(bp->dev->dev_addr, addr, 6);
if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){
- printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n");
+ pr_err("Invalid MAC address found in EEPROM\n");
return -EINVAL;
}
@@ -2142,12 +2136,12 @@ static int __devinit b44_init_one(struct ssb_device *sdev,
instance++;
if (b44_version_printed++ == 0)
- printk(KERN_INFO "%s", version);
+ pr_info("%s", version);
dev = alloc_etherdev(sizeof(*bp));
if (!dev) {
- dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n");
+ dev_err(sdev->dev, "Etherdev alloc failed, aborting\n");
err = -ENOMEM;
goto out;
}
@@ -2186,13 +2180,13 @@ static int __devinit b44_init_one(struct ssb_device *sdev,
err = ssb_dma_set_mask(sdev, DMA_BIT_MASK(30));
if (err) {
dev_err(sdev->dev,
- "Required 30BIT DMA mask unsupported by the system.\n");
+ "Required 30BIT DMA mask unsupported by the system\n");
goto err_out_powerdown;
}
err = b44_get_invariants(bp);
if (err) {
dev_err(sdev->dev,
- "Problem fetching invariants of chip, aborting.\n");
+ "Problem fetching invariants of chip, aborting\n");
goto err_out_powerdown;
}
@@ -2212,7 +2206,7 @@ static int __devinit b44_init_one(struct ssb_device *sdev,
err = register_netdev(dev);
if (err) {
- dev_err(sdev->dev, "Cannot register net device, aborting.\n");
+ dev_err(sdev->dev, "Cannot register net device, aborting\n");
goto err_out_powerdown;
}
@@ -2223,8 +2217,12 @@ static int __devinit b44_init_one(struct ssb_device *sdev,
*/
b44_chip_reset(bp, B44_CHIP_RESET_FULL);
- printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %pM\n",
- dev->name, dev->dev_addr);
+ /* do a phy reset to test if there is an active phy */
+ if (b44_phy_reset(bp) < 0)
+ bp->phy_addr = B44_PHY_ADDR_NO_PHY;
+
+ netdev_info(dev, "Broadcom 44xx/47xx 10/100BaseT Ethernet %pM\n",
+ dev->dev_addr);
return 0;
@@ -2297,7 +2295,7 @@ static int b44_resume(struct ssb_device *sdev)
rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
if (rc) {
- printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name);
+ netdev_err(dev, "request_irq failed\n");
return rc;
}
diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c
index 0bd47d32ec42..8cdcab7655c0 100644
--- a/drivers/net/bcm63xx_enet.c
+++ b/drivers/net/bcm63xx_enet.c
@@ -619,7 +619,7 @@ static void bcm_enet_set_multicast_list(struct net_device *dev)
/* only 3 perfect match registers left, first one is used for
* own mac address */
- if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > 3)
+ if ((dev->flags & IFF_ALLMULTI) || netdev_mc_count(dev) > 3)
val |= ENET_RXCFG_ALLMCAST_MASK;
else
val &= ~ENET_RXCFG_ALLMCAST_MASK;
@@ -631,16 +631,13 @@ static void bcm_enet_set_multicast_list(struct net_device *dev)
return;
}
- for (i = 0, mc_list = dev->mc_list;
- (mc_list != NULL) && (i < dev->mc_count) && (i < 3);
- i++, mc_list = mc_list->next) {
+ i = 0;
+ netdev_for_each_mc_addr(mc_list, dev) {
u8 *dmi_addr;
u32 tmp;
- /* filter non ethernet address */
- if (mc_list->dmi_addrlen != 6)
- continue;
-
+ if (i == 3)
+ break;
/* update perfect match registers */
dmi_addr = mc_list->dmi_addr;
tmp = (dmi_addr[2] << 24) | (dmi_addr[3] << 16) |
@@ -649,7 +646,7 @@ static void bcm_enet_set_multicast_list(struct net_device *dev)
tmp = (dmi_addr[0] << 8 | dmi_addr[1]);
tmp |= ENET_PMH_DATAVALID_MASK;
- enet_writel(priv, tmp, ENET_PMH_REG(i + 1));
+ enet_writel(priv, tmp, ENET_PMH_REG(i++ + 1));
}
for (; i < 3; i++) {
diff --git a/drivers/net/benet/Kconfig b/drivers/net/benet/Kconfig
index fdb6e81a4374..1a41a49bb619 100644
--- a/drivers/net/benet/Kconfig
+++ b/drivers/net/benet/Kconfig
@@ -1,6 +1,6 @@
config BE2NET
- tristate "ServerEngines' 10Gbps NIC - BladeEngine 2"
+ tristate "ServerEngines' 10Gbps NIC - BladeEngine"
depends on PCI && INET
help
This driver implements the NIC functionality for ServerEngines'
- 10Gbps network adapter - BladeEngine 2.
+ 10Gbps network adapter - BladeEngine.
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index 9fd8e5ecd5d7..8f0752553681 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -32,28 +32,26 @@
#include "be_hw.h"
-#define DRV_VER "2.101.346u"
+#define DRV_VER "2.102.147u"
#define DRV_NAME "be2net"
#define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC"
#define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC"
#define OC_NAME "Emulex OneConnect 10Gbps NIC"
#define OC_NAME1 "Emulex OneConnect 10Gbps NIC (be3)"
-#define DRV_DESC BE_NAME "Driver"
+#define DRV_DESC "ServerEngines BladeEngine 10Gbps NIC Driver"
#define BE_VENDOR_ID 0x19a2
#define BE_DEVICE_ID1 0x211
#define BE_DEVICE_ID2 0x221
#define OC_DEVICE_ID1 0x700
-#define OC_DEVICE_ID2 0x701
-#define OC_DEVICE_ID3 0x710
+#define OC_DEVICE_ID2 0x710
static inline char *nic_name(struct pci_dev *pdev)
{
switch (pdev->device) {
case OC_DEVICE_ID1:
- case OC_DEVICE_ID2:
return OC_NAME;
- case OC_DEVICE_ID3:
+ case OC_DEVICE_ID2:
return OC_NAME1;
case BE_DEVICE_ID2:
return BE3_NAME;
@@ -153,6 +151,7 @@ struct be_eq_obj {
struct be_mcc_obj {
struct be_queue_info q;
struct be_queue_info cq;
+ bool rearm_cq;
};
struct be_drvr_stats {
@@ -165,6 +164,7 @@ struct be_drvr_stats {
ulong be_tx_jiffies;
u64 be_tx_bytes;
u64 be_tx_bytes_prev;
+ u64 be_tx_pkts;
u32 be_tx_rate;
u32 cache_barrier[16];
@@ -176,6 +176,7 @@ struct be_drvr_stats {
ulong be_rx_jiffies;
u64 be_rx_bytes;
u64 be_rx_bytes_prev;
+ u64 be_rx_pkts;
u32 be_rx_rate;
/* number of non ether type II frames dropped where
* frame len > length field of Mac Hdr */
@@ -252,7 +253,8 @@ struct be_adapter {
bool rx_post_starved; /* Zero rx frags have been posted to BE */
struct vlan_group *vlan_grp;
- u16 num_vlans;
+ u16 vlans_added;
+ u16 max_vlans; /* Number of vlans supported */
u8 vlan_tag[VLAN_GROUP_ARRAY_LEN];
struct be_dma_mem mc_cmd_mem;
@@ -266,6 +268,7 @@ struct be_adapter {
u32 if_handle; /* Used to configure filtering */
u32 pmac_id; /* MAC addr handle used by BE card */
+ bool eeh_err;
bool link_up;
u32 port_num;
bool promiscuous;
@@ -276,17 +279,17 @@ struct be_adapter {
int link_speed;
u8 port_type;
u8 transceiver;
+ u8 generation; /* BladeEngine ASIC generation */
};
+/* BladeEngine Generation numbers */
+#define BE_GEN2 2
+#define BE_GEN3 3
+
extern const struct ethtool_ops be_ethtool_ops;
#define drvr_stats(adapter) (&adapter->stats.drvr_stats)
-static inline unsigned int be_pci_func(struct be_adapter *adapter)
-{
- return PCI_FUNC(adapter->pdev->devfn);
-}
-
#define BE_SET_NETDEV_OPS(netdev, ops) (netdev->netdev_ops = ops)
#define PAGE_SHIFT_4K 12
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index 102ade134165..c59215361f4e 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -104,10 +104,26 @@ static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter)
return NULL;
}
-int be_process_mcc(struct be_adapter *adapter)
+void be_async_mcc_enable(struct be_adapter *adapter)
+{
+ spin_lock_bh(&adapter->mcc_cq_lock);
+
+ be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, 0);
+ adapter->mcc_obj.rearm_cq = true;
+
+ spin_unlock_bh(&adapter->mcc_cq_lock);
+}
+
+void be_async_mcc_disable(struct be_adapter *adapter)
+{
+ adapter->mcc_obj.rearm_cq = false;
+}
+
+int be_process_mcc(struct be_adapter *adapter, int *status)
{
struct be_mcc_compl *compl;
- int num = 0, status = 0;
+ int num = 0;
+ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
spin_lock_bh(&adapter->mcc_cq_lock);
while ((compl = be_mcc_compl_get(adapter))) {
@@ -119,31 +135,31 @@ int be_process_mcc(struct be_adapter *adapter)
be_async_link_state_process(adapter,
(struct be_async_event_link_state *) compl);
} else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
- status = be_mcc_compl_process(adapter, compl);
- atomic_dec(&adapter->mcc_obj.q.used);
+ *status = be_mcc_compl_process(adapter, compl);
+ atomic_dec(&mcc_obj->q.used);
}
be_mcc_compl_use(compl);
num++;
}
- if (num)
- be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, num);
-
spin_unlock_bh(&adapter->mcc_cq_lock);
- return status;
+ return num;
}
/* Wait till no more pending mcc requests are present */
static int be_mcc_wait_compl(struct be_adapter *adapter)
{
#define mcc_timeout 120000 /* 12s timeout */
- int i, status;
+ int i, num, status = 0;
+ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
+
for (i = 0; i < mcc_timeout; i++) {
- status = be_process_mcc(adapter);
- if (status)
- return status;
+ num = be_process_mcc(adapter, &status);
+ if (num)
+ be_cq_notify(adapter, mcc_obj->cq.id,
+ mcc_obj->rearm_cq, num);
- if (atomic_read(&adapter->mcc_obj.q.used) == 0)
+ if (atomic_read(&mcc_obj->q.used) == 0)
break;
udelay(100);
}
@@ -151,7 +167,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
dev_err(&adapter->pdev->dev, "mccq poll timed out\n");
return -1;
}
- return 0;
+ return status;
}
/* Notify MCC requests and wait for completion */
@@ -167,7 +183,14 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
u32 ready;
do {
- ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
+ ready = ioread32(db);
+ if (ready == 0xffffffff) {
+ dev_err(&adapter->pdev->dev,
+ "pci slot disconnected\n");
+ return -1;
+ }
+
+ ready &= MPU_MAILBOX_DB_RDY_MASK;
if (ready)
break;
@@ -198,6 +221,11 @@ static int be_mbox_notify_wait(struct be_adapter *adapter)
struct be_mcc_mailbox *mbox = mbox_mem->va;
struct be_mcc_compl *compl = &mbox->compl;
+ /* wait for ready to be set */
+ status = be_mbox_db_ready_wait(adapter, db);
+ if (status != 0)
+ return status;
+
val |= MPU_MAILBOX_DB_HI_MASK;
/* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */
val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
@@ -286,7 +314,7 @@ static void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
MCC_WRB_SGE_CNT_SHIFT;
wrb->payload_length = payload_len;
wrb->tag0 = opcode;
- be_dws_cpu_to_le(wrb, 20);
+ be_dws_cpu_to_le(wrb, 8);
}
/* Don't touch the hdr after it's prepared */
@@ -296,6 +324,7 @@ static void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
req_hdr->opcode = opcode;
req_hdr->subsystem = subsystem;
req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr));
+ req_hdr->version = 0;
}
static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages,
@@ -396,6 +425,9 @@ int be_cmd_fw_clean(struct be_adapter *adapter)
u8 *wrb;
int status;
+ if (adapter->eeh_err)
+ return -EIO;
+
spin_lock(&adapter->mbox_lock);
wrb = (u8 *)wrb_from_mbox(adapter);
@@ -433,8 +465,6 @@ int be_cmd_eq_create(struct be_adapter *adapter,
req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
- AMAP_SET_BITS(struct amap_eq_context, func, req->context,
- be_pci_func(adapter));
AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1);
/* 4byte eqe*/
AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0);
@@ -597,7 +627,6 @@ int be_cmd_cq_create(struct be_adapter *adapter,
AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1);
AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id);
AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1);
- AMAP_SET_BITS(struct amap_cq_context, func, ctxt, be_pci_func(adapter));
be_dws_cpu_to_le(ctxt, sizeof(req->context));
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
@@ -646,7 +675,6 @@ int be_cmd_mccq_create(struct be_adapter *adapter,
req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
- AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, be_pci_func(adapter));
AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1);
AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt,
be_encoded_q_len(mccq->len));
@@ -695,8 +723,6 @@ int be_cmd_txq_create(struct be_adapter *adapter,
AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt,
be_encoded_q_len(txq->len));
- AMAP_SET_BITS(struct amap_tx_context, pci_func_id, ctxt,
- be_pci_func(adapter));
AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1);
AMAP_SET_BITS(struct amap_tx_context, cq_id_send, ctxt, cq->id);
@@ -768,6 +794,9 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
u8 subsys = 0, opcode = 0;
int status;
+ if (adapter->eeh_err)
+ return -EIO;
+
spin_lock(&adapter->mbox_lock);
wrb = wrb_from_mbox(adapter);
@@ -856,6 +885,9 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id)
struct be_cmd_req_if_destroy *req;
int status;
+ if (adapter->eeh_err)
+ return -EIO;
+
spin_lock(&adapter->mbox_lock);
wrb = wrb_from_mbox(adapter);
@@ -1096,8 +1128,7 @@ err:
* (mc == NULL) => multicast promiscous
*/
int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
- struct dev_mc_list *mc_list, u32 mc_count,
- struct be_dma_mem *mem)
+ struct net_device *netdev, struct be_dma_mem *mem)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_mcast_mac_config *req = mem->va;
@@ -1124,13 +1155,14 @@ int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
OPCODE_COMMON_NTWK_MULTICAST_SET, sizeof(*req));
req->interface_id = if_id;
- if (mc_list) {
+ if (netdev) {
int i;
struct dev_mc_list *mc;
- req->num_mac = cpu_to_le16(mc_count);
+ req->num_mac = cpu_to_le16(netdev_mc_count(netdev));
- for (mc = mc_list, i = 0; mc; mc = mc->next, i++)
+ i = 0;
+ netdev_for_each_mc_addr(mc, netdev)
memcpy(req->mac[i].byte, mc->dmi_addr, ETH_ALEN);
} else {
req->promiscuous = 1;
@@ -1374,7 +1406,7 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
u32 flash_type, u32 flash_opcode, u32 buf_size)
{
struct be_mcc_wrb *wrb;
- struct be_cmd_write_flashrom *req = cmd->va;
+ struct be_cmd_write_flashrom *req;
struct be_sge *sge;
int status;
@@ -1408,7 +1440,8 @@ err:
return status;
}
-int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc)
+int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
+ int offset)
{
struct be_mcc_wrb *wrb;
struct be_cmd_write_flashrom *req;
@@ -1429,9 +1462,9 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc)
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_READ_FLASHROM, sizeof(*req)+4);
- req->params.op_type = cpu_to_le32(FLASHROM_TYPE_REDBOOT);
+ req->params.op_type = cpu_to_le32(IMG_TYPE_REDBOOT);
req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT);
- req->params.offset = 0x3FFFC;
+ req->params.offset = offset;
req->params.data_buf_size = 0x4;
status = be_mcc_notify_wait(adapter);
@@ -1607,3 +1640,33 @@ err:
spin_unlock_bh(&adapter->mcc_lock);
return status;
}
+
+extern int be_cmd_get_seeprom_data(struct be_adapter *adapter,
+ struct be_dma_mem *nonemb_cmd)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_seeprom_read *req;
+ struct be_sge *sge;
+ int status;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+ req = nonemb_cmd->va;
+ sge = nonembedded_sgl(wrb);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
+ OPCODE_COMMON_SEEPROM_READ);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_SEEPROM_READ, sizeof(*req));
+
+ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+ sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(nonemb_cmd->size);
+
+ status = be_mcc_notify_wait(adapter);
+
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
index c002b8391b4d..cce61f9a3714 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -124,6 +124,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_CQ_CREATE 12
#define OPCODE_COMMON_EQ_CREATE 13
#define OPCODE_COMMON_MCC_CREATE 21
+#define OPCODE_COMMON_SEEPROM_READ 30
#define OPCODE_COMMON_NTWK_RX_FILTER 34
#define OPCODE_COMMON_GET_FW_VERSION 35
#define OPCODE_COMMON_SET_FLOW_CONTROL 36
@@ -164,7 +165,8 @@ struct be_cmd_req_hdr {
u8 domain; /* dword 0 */
u32 timeout; /* dword 1 */
u32 request_length; /* dword 2 */
- u32 rsvd; /* dword 3 */
+ u8 version; /* dword 3 */
+ u8 rsvd[3]; /* dword 3 */
};
#define RESP_HDR_INFO_OPCODE_SHIFT 0 /* bits 0 - 7 */
@@ -854,6 +856,19 @@ struct be_cmd_resp_ddrdma_test {
u8 rcv_buff[4096];
};
+/*********************** SEEPROM Read ***********************/
+
+#define BE_READ_SEEPROM_LEN 1024
+struct be_cmd_req_seeprom_read {
+ struct be_cmd_req_hdr hdr;
+ u8 rsvd0[BE_READ_SEEPROM_LEN];
+};
+
+struct be_cmd_resp_seeprom_read {
+ struct be_cmd_req_hdr hdr;
+ u8 seeprom_data[BE_READ_SEEPROM_LEN];
+};
+
extern int be_pci_fnum_get(struct be_adapter *adapter);
extern int be_cmd_POST(struct be_adapter *adapter);
extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
@@ -897,8 +912,7 @@ extern int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id,
extern int be_cmd_promiscuous_config(struct be_adapter *adapter,
u8 port_num, bool en);
extern int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
- struct dev_mc_list *mc_list, u32 mc_count,
- struct be_dma_mem *mem);
+ struct net_device *netdev, struct be_dma_mem *mem);
extern int be_cmd_set_flow_control(struct be_adapter *adapter,
u32 tx_fc, u32 rx_fc);
extern int be_cmd_get_flow_control(struct be_adapter *adapter,
@@ -906,7 +920,7 @@ extern int be_cmd_get_flow_control(struct be_adapter *adapter,
extern int be_cmd_query_fw_cfg(struct be_adapter *adapter,
u32 *port_num, u32 *cap);
extern int be_cmd_reset_function(struct be_adapter *adapter);
-extern int be_process_mcc(struct be_adapter *adapter);
+extern int be_process_mcc(struct be_adapter *adapter, int *status);
extern int be_cmd_set_beacon_state(struct be_adapter *adapter,
u8 port_num, u8 beacon, u8 status, u8 state);
extern int be_cmd_get_beacon_state(struct be_adapter *adapter,
@@ -916,15 +930,21 @@ extern int be_cmd_read_port_type(struct be_adapter *adapter, u32 port,
extern int be_cmd_write_flashrom(struct be_adapter *adapter,
struct be_dma_mem *cmd, u32 flash_oper,
u32 flash_opcode, u32 buf_size);
-extern int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc);
+int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
+ int offset);
extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
struct be_dma_mem *nonemb_cmd);
extern int be_cmd_fw_init(struct be_adapter *adapter);
extern int be_cmd_fw_clean(struct be_adapter *adapter);
+extern void be_async_mcc_enable(struct be_adapter *adapter);
+extern void be_async_mcc_disable(struct be_adapter *adapter);
extern int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num,
u32 loopback_type, u32 pkt_size,
u32 num_pkts, u64 pattern);
extern int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern,
u32 byte_cnt, struct be_dma_mem *cmd);
+extern int be_cmd_get_seeprom_data(struct be_adapter *adapter,
+ struct be_dma_mem *nonemb_cmd);
extern int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
u8 loopback_type, u8 enable);
+
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index 5d001c4deac1..9560d48944ab 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -112,6 +112,7 @@ static const char et_self_tests[][ETH_GSTRING_LEN] = {
"PHY Loopback test",
"External Loopback test",
"DDR DMA test"
+ "Link test"
};
#define ETHTOOL_TESTS_NUM ARRAY_SIZE(et_self_tests)
@@ -529,6 +530,9 @@ static void
be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
{
struct be_adapter *adapter = netdev_priv(netdev);
+ bool link_up;
+ u8 mac_speed = 0;
+ u16 qos_link_speed = 0;
memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);
@@ -545,12 +549,20 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
&data[2]) != 0) {
test->flags |= ETH_TEST_FL_FAILED;
}
+ }
- data[3] = be_test_ddr_dma(adapter);
- if (data[3] != 0)
- test->flags |= ETH_TEST_FL_FAILED;
+ if (be_test_ddr_dma(adapter) != 0) {
+ data[3] = 1;
+ test->flags |= ETH_TEST_FL_FAILED;
}
+ if (be_cmd_link_status_query(adapter, &link_up, &mac_speed,
+ &qos_link_speed) != 0) {
+ test->flags |= ETH_TEST_FL_FAILED;
+ data[4] = -1;
+ } else if (mac_speed) {
+ data[4] = 1;
+ }
}
static int
@@ -567,12 +579,57 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)
return be_load_fw(adapter, file_name);
}
+static int
+be_get_eeprom_len(struct net_device *netdev)
+{
+ return BE_READ_SEEPROM_LEN;
+}
+
+static int
+be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
+ uint8_t *data)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ struct be_dma_mem eeprom_cmd;
+ struct be_cmd_resp_seeprom_read *resp;
+ int status;
+
+ if (!eeprom->len)
+ return -EINVAL;
+
+ eeprom->magic = BE_VENDOR_ID | (adapter->pdev->device<<16);
+
+ memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem));
+ eeprom_cmd.size = sizeof(struct be_cmd_req_seeprom_read);
+ eeprom_cmd.va = pci_alloc_consistent(adapter->pdev, eeprom_cmd.size,
+ &eeprom_cmd.dma);
+
+ if (!eeprom_cmd.va) {
+ dev_err(&adapter->pdev->dev,
+ "Memory allocation failure. Could not read eeprom\n");
+ return -ENOMEM;
+ }
+
+ status = be_cmd_get_seeprom_data(adapter, &eeprom_cmd);
+
+ if (!status) {
+ resp = (struct be_cmd_resp_seeprom_read *) eeprom_cmd.va;
+ memcpy(data, resp->seeprom_data + eeprom->offset, eeprom->len);
+ }
+ pci_free_consistent(adapter->pdev, eeprom_cmd.size, eeprom_cmd.va,
+ eeprom_cmd.dma);
+
+ return status;
+}
+
const struct ethtool_ops be_ethtool_ops = {
.get_settings = be_get_settings,
.get_drvinfo = be_get_drvinfo,
.get_wol = be_get_wol,
.set_wol = be_set_wol,
.get_link = ethtool_op_get_link,
+ .get_eeprom_len = be_get_eeprom_len,
+ .get_eeprom = be_read_eeprom,
.get_coalesce = be_get_coalesce,
.set_coalesce = be_set_coalesce,
.get_ringparam = be_get_ringparam,
diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h
index e2b3beffd49d..2d4a4b827637 100644
--- a/drivers/net/benet/be_hw.h
+++ b/drivers/net/benet/be_hw.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -99,6 +99,64 @@
/* Number of entries posted */
#define DB_MCCQ_NUM_POSTED_SHIFT (16) /* bits 16 - 29 */
+/* Flashrom related descriptors */
+#define IMAGE_TYPE_FIRMWARE 160
+#define IMAGE_TYPE_BOOTCODE 224
+#define IMAGE_TYPE_OPTIONROM 32
+
+#define NUM_FLASHDIR_ENTRIES 32
+
+#define IMG_TYPE_ISCSI_ACTIVE 0
+#define IMG_TYPE_REDBOOT 1
+#define IMG_TYPE_BIOS 2
+#define IMG_TYPE_PXE_BIOS 3
+#define IMG_TYPE_FCOE_BIOS 8
+#define IMG_TYPE_ISCSI_BACKUP 9
+#define IMG_TYPE_FCOE_FW_ACTIVE 10
+#define IMG_TYPE_FCOE_FW_BACKUP 11
+#define IMG_TYPE_NCSI_FW 13
+
+#define FLASHROM_OPER_FLASH 1
+#define FLASHROM_OPER_SAVE 2
+#define FLASHROM_OPER_REPORT 4
+
+#define FLASH_IMAGE_MAX_SIZE_g2 (1310720) /* Max firmware image sz */
+#define FLASH_BIOS_IMAGE_MAX_SIZE_g2 (262144) /* Max OPTION ROM img sz */
+#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g2 (262144) /* Max Redboot image sz */
+#define FLASH_IMAGE_MAX_SIZE_g3 (2097152) /* Max fw image size */
+#define FLASH_BIOS_IMAGE_MAX_SIZE_g3 (524288) /* Max OPTION ROM img sz */
+#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 (1048576) /* Max Redboot image sz */
+#define FLASH_NCSI_IMAGE_MAX_SIZE_g3 (262144) /* Max NSCI image sz */
+
+#define FLASH_NCSI_MAGIC (0x16032009)
+#define FLASH_NCSI_DISABLED (0)
+#define FLASH_NCSI_ENABLED (1)
+
+#define FLASH_NCSI_BITFILE_HDR_OFFSET (0x600000)
+
+/* Offsets for components on Flash. */
+#define FLASH_iSCSI_PRIMARY_IMAGE_START_g2 (1048576)
+#define FLASH_iSCSI_BACKUP_IMAGE_START_g2 (2359296)
+#define FLASH_FCoE_PRIMARY_IMAGE_START_g2 (3670016)
+#define FLASH_FCoE_BACKUP_IMAGE_START_g2 (4980736)
+#define FLASH_iSCSI_BIOS_START_g2 (7340032)
+#define FLASH_PXE_BIOS_START_g2 (7864320)
+#define FLASH_FCoE_BIOS_START_g2 (524288)
+#define FLASH_REDBOOT_START_g2 (0)
+
+#define FLASH_NCSI_START_g3 (15990784)
+#define FLASH_iSCSI_PRIMARY_IMAGE_START_g3 (2097152)
+#define FLASH_iSCSI_BACKUP_IMAGE_START_g3 (4194304)
+#define FLASH_FCoE_PRIMARY_IMAGE_START_g3 (6291456)
+#define FLASH_FCoE_BACKUP_IMAGE_START_g3 (8388608)
+#define FLASH_iSCSI_BIOS_START_g3 (12582912)
+#define FLASH_PXE_BIOS_START_g3 (13107200)
+#define FLASH_FCoE_BIOS_START_g3 (13631488)
+#define FLASH_REDBOOT_START_g3 (262144)
+
+
+
+
/*
* BE descriptors: host memory data structures whose formats
* are hardwired in BE silicon.
@@ -107,6 +165,7 @@
#define EQ_ENTRY_VALID_MASK 0x1 /* bit 0 */
#define EQ_ENTRY_RES_ID_MASK 0xFFFF /* bits 16 - 31 */
#define EQ_ENTRY_RES_ID_SHIFT 16
+
struct be_eq_entry {
u32 evt;
};
@@ -221,41 +280,6 @@ struct be_eth_rx_compl {
u32 dw[4];
};
-/* Flashrom related descriptors */
-#define IMAGE_TYPE_FIRMWARE 160
-#define IMAGE_TYPE_BOOTCODE 224
-#define IMAGE_TYPE_OPTIONROM 32
-
-#define NUM_FLASHDIR_ENTRIES 32
-
-#define FLASHROM_TYPE_ISCSI_ACTIVE 0
-#define FLASHROM_TYPE_REDBOOT 1
-#define FLASHROM_TYPE_BIOS 2
-#define FLASHROM_TYPE_PXE_BIOS 3
-#define FLASHROM_TYPE_FCOE_BIOS 8
-#define FLASHROM_TYPE_ISCSI_BACKUP 9
-#define FLASHROM_TYPE_FCOE_FW_ACTIVE 10
-#define FLASHROM_TYPE_FCOE_FW_BACKUP 11
-
-#define FLASHROM_OPER_FLASH 1
-#define FLASHROM_OPER_SAVE 2
-#define FLASHROM_OPER_REPORT 4
-
-#define FLASH_IMAGE_MAX_SIZE (1310720) /* Max firmware image size */
-#define FLASH_BIOS_IMAGE_MAX_SIZE (262144) /* Max OPTION ROM image sz */
-#define FLASH_REDBOOT_IMAGE_MAX_SIZE (262144) /* Max redboot image sz */
-
-/* Offsets for components on Flash. */
-#define FLASH_iSCSI_PRIMARY_IMAGE_START (1048576)
-#define FLASH_iSCSI_BACKUP_IMAGE_START (2359296)
-#define FLASH_FCoE_PRIMARY_IMAGE_START (3670016)
-#define FLASH_FCoE_BACKUP_IMAGE_START (4980736)
-#define FLASH_iSCSI_BIOS_START (7340032)
-#define FLASH_PXE_BIOS_START (7864320)
-#define FLASH_FCoE_BIOS_START (524288)
-#define FLASH_REDBOOT_START (32768)
-#define FLASH_REDBOOT_ISM_START (0)
-
struct controller_id {
u32 vendor;
u32 device;
@@ -263,7 +287,20 @@ struct controller_id {
u32 subdevice;
};
-struct flash_file_hdr {
+struct flash_comp {
+ unsigned long offset;
+ int optype;
+ int size;
+};
+
+struct image_hdr {
+ u32 imageid;
+ u32 imageoffset;
+ u32 imagelength;
+ u32 image_checksum;
+ u8 image_version[32];
+};
+struct flash_file_hdr_g2 {
u8 sign[32];
u32 cksum;
u32 antidote;
@@ -275,6 +312,17 @@ struct flash_file_hdr {
u8 build[24];
};
+struct flash_file_hdr_g3 {
+ u8 sign[52];
+ u8 ufi_version[4];
+ u32 file_len;
+ u32 cksum;
+ u32 antidote;
+ u32 num_imgs;
+ u8 build[24];
+ u8 rsvd[32];
+};
+
struct flash_section_hdr {
u32 format_rev;
u32 cksum;
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 3a1f7902c16d..43e8032f9236 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -34,7 +34,6 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
{ PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) },
{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },
{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
- { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID3) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, be_dev_ids);
@@ -69,6 +68,9 @@ static void be_intr_set(struct be_adapter *adapter, bool enable)
u32 reg = ioread32(addr);
u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+ if (adapter->eeh_err)
+ return;
+
if (!enabled && enable)
reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
else if (enabled && !enable)
@@ -100,6 +102,10 @@ static void be_eq_notify(struct be_adapter *adapter, u16 qid,
{
u32 val = 0;
val |= qid & DB_EQ_RING_ID_MASK;
+
+ if (adapter->eeh_err)
+ return;
+
if (arm)
val |= 1 << DB_EQ_REARM_SHIFT;
if (clear_int)
@@ -113,6 +119,10 @@ void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped)
{
u32 val = 0;
val |= qid & DB_CQ_RING_ID_MASK;
+
+ if (adapter->eeh_err)
+ return;
+
if (arm)
val |= 1 << DB_CQ_REARM_SHIFT;
val |= num_popped << DB_CQ_NUM_POPPED_SHIFT;
@@ -149,13 +159,10 @@ void netdev_stats_update(struct be_adapter *adapter)
struct net_device_stats *dev_stats = &adapter->netdev->stats;
struct be_erx_stats *erx_stats = &hw_stats->erx;
- dev_stats->rx_packets = port_stats->rx_total_frames;
- dev_stats->tx_packets = port_stats->tx_unicastframes +
- port_stats->tx_multicastframes + port_stats->tx_broadcastframes;
- dev_stats->rx_bytes = (u64) port_stats->rx_bytes_msd << 32 |
- (u64) port_stats->rx_bytes_lsd;
- dev_stats->tx_bytes = (u64) port_stats->tx_bytes_msd << 32 |
- (u64) port_stats->tx_bytes_lsd;
+ dev_stats->rx_packets = drvr_stats(adapter)->be_rx_pkts;
+ dev_stats->tx_packets = drvr_stats(adapter)->be_tx_pkts;
+ dev_stats->rx_bytes = drvr_stats(adapter)->be_rx_bytes;
+ dev_stats->tx_bytes = drvr_stats(adapter)->be_tx_bytes;
/* bad pkts received */
dev_stats->rx_errors = port_stats->rx_crc_errors +
@@ -312,12 +319,13 @@ static void be_tx_rate_update(struct be_adapter *adapter)
}
static void be_tx_stats_update(struct be_adapter *adapter,
- u32 wrb_cnt, u32 copied, bool stopped)
+ u32 wrb_cnt, u32 copied, u32 gso_segs, bool stopped)
{
struct be_drvr_stats *stats = drvr_stats(adapter);
stats->be_tx_reqs++;
stats->be_tx_wrbs += wrb_cnt;
stats->be_tx_bytes += copied;
+ stats->be_tx_pkts += (gso_segs ? gso_segs : 1);
if (stopped)
stats->be_tx_stops++;
}
@@ -462,7 +470,8 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
be_txq_notify(adapter, txq->id, wrb_cnt);
- be_tx_stats_update(adapter, wrb_cnt, copied, stopped);
+ be_tx_stats_update(adapter, wrb_cnt, copied,
+ skb_shinfo(skb)->gso_segs, stopped);
} else {
txq->head = start;
dev_kfree_skb_any(skb);
@@ -474,10 +483,12 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu)
{
struct be_adapter *adapter = netdev_priv(netdev);
if (new_mtu < BE_MIN_MTU ||
- new_mtu > BE_MAX_JUMBO_FRAME_SIZE) {
+ new_mtu > (BE_MAX_JUMBO_FRAME_SIZE -
+ (ETH_HLEN + ETH_FCS_LEN))) {
dev_info(&adapter->pdev->dev,
"MTU must be between %d and %d bytes\n",
- BE_MIN_MTU, BE_MAX_JUMBO_FRAME_SIZE);
+ BE_MIN_MTU,
+ (BE_MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN)));
return -EINVAL;
}
dev_info(&adapter->pdev->dev, "MTU changed from %d to %d bytes\n",
@@ -487,17 +498,16 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu)
}
/*
- * if there are BE_NUM_VLANS_SUPPORTED or lesser number of VLANS configured,
- * program them in BE. If more than BE_NUM_VLANS_SUPPORTED are configured,
- * set the BE in promiscuous VLAN mode.
+ * A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE.
+ * If the user configures more, place BE in vlan promiscuous mode.
*/
static int be_vid_config(struct be_adapter *adapter)
{
u16 vtag[BE_NUM_VLANS_SUPPORTED];
u16 ntags = 0, i;
- int status;
+ int status = 0;
- if (adapter->num_vlans <= BE_NUM_VLANS_SUPPORTED) {
+ if (adapter->vlans_added <= adapter->max_vlans) {
/* Construct VLAN Table to give to HW */
for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
if (adapter->vlan_tag[i]) {
@@ -531,21 +541,21 @@ static void be_vlan_add_vid(struct net_device *netdev, u16 vid)
{
struct be_adapter *adapter = netdev_priv(netdev);
- adapter->num_vlans++;
adapter->vlan_tag[vid] = 1;
-
- be_vid_config(adapter);
+ adapter->vlans_added++;
+ if (adapter->vlans_added <= (adapter->max_vlans + 1))
+ be_vid_config(adapter);
}
static void be_vlan_rem_vid(struct net_device *netdev, u16 vid)
{
struct be_adapter *adapter = netdev_priv(netdev);
- adapter->num_vlans--;
adapter->vlan_tag[vid] = 0;
-
vlan_group_set_device(adapter->vlan_grp, vid, NULL);
- be_vid_config(adapter);
+ adapter->vlans_added--;
+ if (adapter->vlans_added <= adapter->max_vlans)
+ be_vid_config(adapter);
}
static void be_set_multicast_list(struct net_device *netdev)
@@ -565,14 +575,15 @@ static void be_set_multicast_list(struct net_device *netdev)
}
/* Enable multicast promisc if num configured exceeds what we support */
- if (netdev->flags & IFF_ALLMULTI || netdev->mc_count > BE_MAX_MC) {
- be_cmd_multicast_set(adapter, adapter->if_handle, NULL, 0,
+ if (netdev->flags & IFF_ALLMULTI ||
+ netdev_mc_count(netdev) > BE_MAX_MC) {
+ be_cmd_multicast_set(adapter, adapter->if_handle, NULL,
&adapter->mc_cmd_mem);
goto done;
}
- be_cmd_multicast_set(adapter, adapter->if_handle, netdev->mc_list,
- netdev->mc_count, &adapter->mc_cmd_mem);
+ be_cmd_multicast_set(adapter, adapter->if_handle, netdev,
+ &adapter->mc_cmd_mem);
done:
return;
}
@@ -607,6 +618,7 @@ static void be_rx_stats_update(struct be_adapter *adapter,
stats->be_rx_compl++;
stats->be_rx_frags += numfrags;
stats->be_rx_bytes += pktsize;
+ stats->be_rx_pkts++;
}
static inline bool do_pkt_csum(struct be_eth_rx_compl *rxcp, bool cso)
@@ -634,9 +646,11 @@ get_rx_page_info(struct be_adapter *adapter, u16 frag_idx)
rx_page_info = &adapter->rx_obj.page_info_tbl[frag_idx];
BUG_ON(!rx_page_info->page);
- if (rx_page_info->last_page_user)
+ if (rx_page_info->last_page_user) {
pci_unmap_page(adapter->pdev, pci_unmap_addr(rx_page_info, bus),
adapter->big_page_size, PCI_DMA_FROMDEVICE);
+ rx_page_info->last_page_user = false;
+ }
atomic_dec(&rxq->used);
return rx_page_info;
@@ -666,17 +680,17 @@ static void be_rx_compl_discard(struct be_adapter *adapter,
* indicated by rxcp.
*/
static void skb_fill_rx_data(struct be_adapter *adapter,
- struct sk_buff *skb, struct be_eth_rx_compl *rxcp)
+ struct sk_buff *skb, struct be_eth_rx_compl *rxcp,
+ u16 num_rcvd)
{
struct be_queue_info *rxq = &adapter->rx_obj.q;
struct be_rx_page_info *page_info;
- u16 rxq_idx, i, num_rcvd, j;
+ u16 rxq_idx, i, j;
u32 pktsize, hdr_len, curr_frag_len, size;
u8 *start;
rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
pktsize = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
- num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
page_info = get_rx_page_info(adapter, rxq_idx);
@@ -704,7 +718,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
skb->data_len = curr_frag_len - hdr_len;
skb->tail += hdr_len;
}
- memset(page_info, 0, sizeof(*page_info));
+ page_info->page = NULL;
if (pktsize <= rx_frag_size) {
BUG_ON(num_rcvd != 1);
@@ -737,7 +751,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
skb->len += curr_frag_len;
skb->data_len += curr_frag_len;
- memset(page_info, 0, sizeof(*page_info));
+ page_info->page = NULL;
}
BUG_ON(j > MAX_SKB_FRAGS);
@@ -752,25 +766,23 @@ static void be_rx_compl_process(struct be_adapter *adapter,
{
struct sk_buff *skb;
u32 vlanf, vid;
+ u16 num_rcvd;
u8 vtm;
- vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
- vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp);
-
- /* vlanf could be wrongly set in some cards.
- * ignore if vtm is not set */
- if ((adapter->cap & 0x400) && !vtm)
- vlanf = 0;
+ num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
+ /* Is it a flush compl that has no data */
+ if (unlikely(num_rcvd == 0))
+ return;
skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN);
- if (!skb) {
+ if (unlikely(!skb)) {
if (net_ratelimit())
dev_warn(&adapter->pdev->dev, "skb alloc failed\n");
be_rx_compl_discard(adapter, rxcp);
return;
}
- skb_fill_rx_data(adapter, skb, rxcp);
+ skb_fill_rx_data(adapter, skb, rxcp, num_rcvd);
if (do_pkt_csum(rxcp, adapter->rx_csum))
skb->ip_summed = CHECKSUM_NONE;
@@ -781,8 +793,16 @@ static void be_rx_compl_process(struct be_adapter *adapter,
skb->protocol = eth_type_trans(skb, adapter->netdev);
skb->dev = adapter->netdev;
- if (vlanf) {
- if (!adapter->vlan_grp || adapter->num_vlans == 0) {
+ vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
+ vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp);
+
+ /* vlanf could be wrongly set in some cards.
+ * ignore if vtm is not set */
+ if ((adapter->cap & 0x400) && !vtm)
+ vlanf = 0;
+
+ if (unlikely(vlanf)) {
+ if (!adapter->vlan_grp || adapter->vlans_added == 0) {
kfree_skb(skb);
return;
}
@@ -809,6 +829,10 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
u8 vtm;
num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
+ /* Is it a flush compl that has no data */
+ if (unlikely(num_rcvd == 0))
+ return;
+
pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
@@ -862,7 +886,7 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
vid = be16_to_cpu(vid);
- if (!adapter->vlan_grp || adapter->num_vlans == 0)
+ if (!adapter->vlan_grp || adapter->vlans_added == 0)
return;
vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid);
@@ -910,7 +934,7 @@ static inline struct page *be_alloc_pages(u32 size)
static void be_post_rx_frags(struct be_adapter *adapter)
{
struct be_rx_page_info *page_info_tbl = adapter->rx_obj.page_info_tbl;
- struct be_rx_page_info *page_info = NULL;
+ struct be_rx_page_info *page_info = NULL, *prev_page_info = NULL;
struct be_queue_info *rxq = &adapter->rx_obj.q;
struct page *pagep = NULL;
struct be_eth_rx_d *rxd;
@@ -941,7 +965,6 @@ static void be_post_rx_frags(struct be_adapter *adapter)
rxd = queue_head_node(rxq);
rxd->fragpa_lo = cpu_to_le32(frag_dmaaddr & 0xFFFFFFFF);
rxd->fragpa_hi = cpu_to_le32(upper_32_bits(frag_dmaaddr));
- queue_head_inc(rxq);
/* Any space left in the current big page for another frag? */
if ((page_offset + rx_frag_size + rx_frag_size) >
@@ -949,10 +972,13 @@ static void be_post_rx_frags(struct be_adapter *adapter)
pagep = NULL;
page_info->last_page_user = true;
}
+
+ prev_page_info = page_info;
+ queue_head_inc(rxq);
page_info = &page_info_tbl[rxq->head];
}
if (pagep)
- page_info->last_page_user = true;
+ prev_page_info->last_page_user = true;
if (posted) {
atomic_add(posted, &rxq->used);
@@ -1102,6 +1128,9 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
struct be_queue_info *txq = &adapter->tx_obj.q;
struct be_eth_tx_compl *txcp;
u16 end_idx, cmpl = 0, timeo = 0;
+ struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list;
+ struct sk_buff *sent_skb;
+ bool dummy_wrb;
/* Wait for a max of 200ms for all the tx-completions to arrive. */
do {
@@ -1125,6 +1154,15 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
if (atomic_read(&txq->used))
dev_err(&adapter->pdev->dev, "%d pending tx-completions\n",
atomic_read(&txq->used));
+
+ /* free posted tx for which compls will never arrive */
+ while (atomic_read(&txq->used)) {
+ sent_skb = sent_skbs[txq->tail];
+ end_idx = txq->tail;
+ index_adv(&end_idx,
+ wrb_cnt_for_skb(sent_skb, &dummy_wrb) - 1, txq->len);
+ be_tx_compl_process(adapter, end_idx);
+ }
}
static void be_mcc_queues_destroy(struct be_adapter *adapter)
@@ -1257,6 +1295,11 @@ static void be_rx_queues_destroy(struct be_adapter *adapter)
q = &adapter->rx_obj.q;
if (q->created) {
be_cmd_q_destroy(adapter, q, QTYPE_RXQ);
+
+ /* After the rxq is invalidated, wait for a grace time
+ * of 1ms for all dma to end and the flush compl to arrive
+ */
+ mdelay(1);
be_rx_q_clean(adapter);
}
be_queue_free(adapter, q);
@@ -1339,7 +1382,7 @@ rx_eq_free:
/* There are 8 evt ids per func. Retruns the evt id's bit number */
static inline int be_evt_bit_get(struct be_adapter *adapter, u32 eq_id)
{
- return eq_id - 8 * be_pci_func(adapter);
+ return eq_id % 8;
}
static irqreturn_t be_intx(int irq, void *dev)
@@ -1348,7 +1391,7 @@ static irqreturn_t be_intx(int irq, void *dev)
int isr;
isr = ioread32(adapter->csr + CEV_ISR0_OFFSET +
- be_pci_func(adapter) * CEV_ISR_SIZE);
+ (adapter->tx_eq.q.id/ 8) * CEV_ISR_SIZE);
if (!isr)
return IRQ_NONE;
@@ -1426,23 +1469,38 @@ int be_poll_rx(struct napi_struct *napi, int budget)
return work_done;
}
-void be_process_tx(struct be_adapter *adapter)
+/* As TX and MCC share the same EQ check for both TX and MCC completions.
+ * For TX/MCC we don't honour budget; consume everything
+ */
+static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
{
+ struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi);
+ struct be_adapter *adapter =
+ container_of(tx_eq, struct be_adapter, tx_eq);
struct be_queue_info *txq = &adapter->tx_obj.q;
struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
struct be_eth_tx_compl *txcp;
- u32 num_cmpl = 0;
+ int tx_compl = 0, mcc_compl, status = 0;
u16 end_idx;
while ((txcp = be_tx_compl_get(tx_cq))) {
end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
- wrb_index, txcp);
+ wrb_index, txcp);
be_tx_compl_process(adapter, end_idx);
- num_cmpl++;
+ tx_compl++;
+ }
+
+ mcc_compl = be_process_mcc(adapter, &status);
+
+ napi_complete(napi);
+
+ if (mcc_compl) {
+ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
+ be_cq_notify(adapter, mcc_obj->cq.id, true, mcc_compl);
}
- if (num_cmpl) {
- be_cq_notify(adapter, tx_cq->id, true, num_cmpl);
+ if (tx_compl) {
+ be_cq_notify(adapter, adapter->tx_obj.cq.id, true, tx_compl);
/* As Tx wrbs have been freed up, wake up netdev queue if
* it was stopped due to lack of tx wrbs.
@@ -1453,24 +1511,8 @@ void be_process_tx(struct be_adapter *adapter)
}
drvr_stats(adapter)->be_tx_events++;
- drvr_stats(adapter)->be_tx_compl += num_cmpl;
+ drvr_stats(adapter)->be_tx_compl += tx_compl;
}
-}
-
-/* As TX and MCC share the same EQ check for both TX and MCC completions.
- * For TX/MCC we don't honour budget; consume everything
- */
-static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
-{
- struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi);
- struct be_adapter *adapter =
- container_of(tx_eq, struct be_adapter, tx_eq);
-
- napi_complete(napi);
-
- be_process_tx(adapter);
-
- be_process_mcc(adapter);
return 1;
}
@@ -1639,6 +1681,9 @@ static int be_open(struct net_device *netdev)
/* Rx compl queue may be in unarmed state; rearm it */
be_cq_notify(adapter, adapter->rx_obj.cq.id, true, 0);
+ /* Now that interrupts are on we can process async mcc */
+ be_async_mcc_enable(adapter);
+
status = be_cmd_link_status_query(adapter, &link_up, &mac_speed,
&link_speed);
if (status)
@@ -1764,6 +1809,8 @@ static int be_close(struct net_device *netdev)
cancel_delayed_work_sync(&adapter->work);
+ be_async_mcc_disable(adapter);
+
netif_stop_queue(netdev);
netif_carrier_off(netdev);
adapter->link_up = false;
@@ -1796,15 +1843,19 @@ char flash_cookie[2][16] = {"*** SE FLAS",
"H DIRECTORY *** "};
static bool be_flash_redboot(struct be_adapter *adapter,
- const u8 *p)
+ const u8 *p, u32 img_start, int image_size,
+ int hdr_size)
{
u32 crc_offset;
u8 flashed_crc[4];
int status;
- crc_offset = FLASH_REDBOOT_START + FLASH_REDBOOT_IMAGE_MAX_SIZE - 4
- + sizeof(struct flash_file_hdr) - 32*1024;
+
+ crc_offset = hdr_size + img_start + image_size - 4;
+
p += crc_offset;
- status = be_cmd_get_flash_crc(adapter, flashed_crc);
+
+ status = be_cmd_get_flash_crc(adapter, flashed_crc,
+ (img_start + image_size - 4));
if (status) {
dev_err(&adapter->pdev->dev,
"could not get crc from flash, not flashing redboot\n");
@@ -1816,112 +1867,133 @@ static bool be_flash_redboot(struct be_adapter *adapter,
return false;
else
return true;
-
}
-static int be_flash_image(struct be_adapter *adapter,
+static int be_flash_data(struct be_adapter *adapter,
const struct firmware *fw,
- struct be_dma_mem *flash_cmd, u32 flash_type)
+ struct be_dma_mem *flash_cmd, int num_of_images)
+
{
- int status;
- u32 flash_op, image_offset = 0, total_bytes, image_size = 0;
+ int status = 0, i, filehdr_size = 0;
+ u32 total_bytes = 0, flash_op;
int num_bytes;
const u8 *p = fw->data;
struct be_cmd_write_flashrom *req = flash_cmd->va;
-
- switch (flash_type) {
- case FLASHROM_TYPE_ISCSI_ACTIVE:
- image_offset = FLASH_iSCSI_PRIMARY_IMAGE_START;
- image_size = FLASH_IMAGE_MAX_SIZE;
- break;
- case FLASHROM_TYPE_ISCSI_BACKUP:
- image_offset = FLASH_iSCSI_BACKUP_IMAGE_START;
- image_size = FLASH_IMAGE_MAX_SIZE;
- break;
- case FLASHROM_TYPE_FCOE_FW_ACTIVE:
- image_offset = FLASH_FCoE_PRIMARY_IMAGE_START;
- image_size = FLASH_IMAGE_MAX_SIZE;
- break;
- case FLASHROM_TYPE_FCOE_FW_BACKUP:
- image_offset = FLASH_FCoE_BACKUP_IMAGE_START;
- image_size = FLASH_IMAGE_MAX_SIZE;
- break;
- case FLASHROM_TYPE_BIOS:
- image_offset = FLASH_iSCSI_BIOS_START;
- image_size = FLASH_BIOS_IMAGE_MAX_SIZE;
- break;
- case FLASHROM_TYPE_FCOE_BIOS:
- image_offset = FLASH_FCoE_BIOS_START;
- image_size = FLASH_BIOS_IMAGE_MAX_SIZE;
- break;
- case FLASHROM_TYPE_PXE_BIOS:
- image_offset = FLASH_PXE_BIOS_START;
- image_size = FLASH_BIOS_IMAGE_MAX_SIZE;
- break;
- case FLASHROM_TYPE_REDBOOT:
- if (!be_flash_redboot(adapter, fw->data))
- return 0;
- image_offset = FLASH_REDBOOT_ISM_START;
- image_size = FLASH_REDBOOT_IMAGE_MAX_SIZE;
- break;
- default:
- return 0;
+ struct flash_comp *pflashcomp;
+ int num_comp;
+
+ struct flash_comp gen3_flash_types[9] = {
+ { FLASH_iSCSI_PRIMARY_IMAGE_START_g3, IMG_TYPE_ISCSI_ACTIVE,
+ FLASH_IMAGE_MAX_SIZE_g3},
+ { FLASH_REDBOOT_START_g3, IMG_TYPE_REDBOOT,
+ FLASH_REDBOOT_IMAGE_MAX_SIZE_g3},
+ { FLASH_iSCSI_BIOS_START_g3, IMG_TYPE_BIOS,
+ FLASH_BIOS_IMAGE_MAX_SIZE_g3},
+ { FLASH_PXE_BIOS_START_g3, IMG_TYPE_PXE_BIOS,
+ FLASH_BIOS_IMAGE_MAX_SIZE_g3},
+ { FLASH_FCoE_BIOS_START_g3, IMG_TYPE_FCOE_BIOS,
+ FLASH_BIOS_IMAGE_MAX_SIZE_g3},
+ { FLASH_iSCSI_BACKUP_IMAGE_START_g3, IMG_TYPE_ISCSI_BACKUP,
+ FLASH_IMAGE_MAX_SIZE_g3},
+ { FLASH_FCoE_PRIMARY_IMAGE_START_g3, IMG_TYPE_FCOE_FW_ACTIVE,
+ FLASH_IMAGE_MAX_SIZE_g3},
+ { FLASH_FCoE_BACKUP_IMAGE_START_g3, IMG_TYPE_FCOE_FW_BACKUP,
+ FLASH_IMAGE_MAX_SIZE_g3},
+ { FLASH_NCSI_START_g3, IMG_TYPE_NCSI_FW,
+ FLASH_NCSI_IMAGE_MAX_SIZE_g3}
+ };
+ struct flash_comp gen2_flash_types[8] = {
+ { FLASH_iSCSI_PRIMARY_IMAGE_START_g2, IMG_TYPE_ISCSI_ACTIVE,
+ FLASH_IMAGE_MAX_SIZE_g2},
+ { FLASH_REDBOOT_START_g2, IMG_TYPE_REDBOOT,
+ FLASH_REDBOOT_IMAGE_MAX_SIZE_g2},
+ { FLASH_iSCSI_BIOS_START_g2, IMG_TYPE_BIOS,
+ FLASH_BIOS_IMAGE_MAX_SIZE_g2},
+ { FLASH_PXE_BIOS_START_g2, IMG_TYPE_PXE_BIOS,
+ FLASH_BIOS_IMAGE_MAX_SIZE_g2},
+ { FLASH_FCoE_BIOS_START_g2, IMG_TYPE_FCOE_BIOS,
+ FLASH_BIOS_IMAGE_MAX_SIZE_g2},
+ { FLASH_iSCSI_BACKUP_IMAGE_START_g2, IMG_TYPE_ISCSI_BACKUP,
+ FLASH_IMAGE_MAX_SIZE_g2},
+ { FLASH_FCoE_PRIMARY_IMAGE_START_g2, IMG_TYPE_FCOE_FW_ACTIVE,
+ FLASH_IMAGE_MAX_SIZE_g2},
+ { FLASH_FCoE_BACKUP_IMAGE_START_g2, IMG_TYPE_FCOE_FW_BACKUP,
+ FLASH_IMAGE_MAX_SIZE_g2}
+ };
+
+ if (adapter->generation == BE_GEN3) {
+ pflashcomp = gen3_flash_types;
+ filehdr_size = sizeof(struct flash_file_hdr_g3);
+ num_comp = 9;
+ } else {
+ pflashcomp = gen2_flash_types;
+ filehdr_size = sizeof(struct flash_file_hdr_g2);
+ num_comp = 8;
}
-
- p += sizeof(struct flash_file_hdr) + image_offset;
- if (p + image_size > fw->data + fw->size)
+ for (i = 0; i < num_comp; i++) {
+ if ((pflashcomp[i].optype == IMG_TYPE_NCSI_FW) &&
+ memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0)
+ continue;
+ if ((pflashcomp[i].optype == IMG_TYPE_REDBOOT) &&
+ (!be_flash_redboot(adapter, fw->data,
+ pflashcomp[i].offset, pflashcomp[i].size,
+ filehdr_size)))
+ continue;
+ p = fw->data;
+ p += filehdr_size + pflashcomp[i].offset
+ + (num_of_images * sizeof(struct image_hdr));
+ if (p + pflashcomp[i].size > fw->data + fw->size)
return -1;
-
- total_bytes = image_size;
-
- while (total_bytes) {
- if (total_bytes > 32*1024)
- num_bytes = 32*1024;
- else
- num_bytes = total_bytes;
- total_bytes -= num_bytes;
-
- if (!total_bytes)
- flash_op = FLASHROM_OPER_FLASH;
- else
- flash_op = FLASHROM_OPER_SAVE;
- memcpy(req->params.data_buf, p, num_bytes);
- p += num_bytes;
- status = be_cmd_write_flashrom(adapter, flash_cmd,
- flash_type, flash_op, num_bytes);
- if (status) {
- dev_err(&adapter->pdev->dev,
- "cmd to write to flash rom failed. type/op %d/%d\n",
- flash_type, flash_op);
- return -1;
+ total_bytes = pflashcomp[i].size;
+ while (total_bytes) {
+ if (total_bytes > 32*1024)
+ num_bytes = 32*1024;
+ else
+ num_bytes = total_bytes;
+ total_bytes -= num_bytes;
+
+ if (!total_bytes)
+ flash_op = FLASHROM_OPER_FLASH;
+ else
+ flash_op = FLASHROM_OPER_SAVE;
+ memcpy(req->params.data_buf, p, num_bytes);
+ p += num_bytes;
+ status = be_cmd_write_flashrom(adapter, flash_cmd,
+ pflashcomp[i].optype, flash_op, num_bytes);
+ if (status) {
+ dev_err(&adapter->pdev->dev,
+ "cmd to write to flash rom failed.\n");
+ return -1;
+ }
+ yield();
}
- yield();
}
-
return 0;
}
+static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr)
+{
+ if (fhdr == NULL)
+ return 0;
+ if (fhdr->build[0] == '3')
+ return BE_GEN3;
+ else if (fhdr->build[0] == '2')
+ return BE_GEN2;
+ else
+ return 0;
+}
+
int be_load_fw(struct be_adapter *adapter, u8 *func)
{
char fw_file[ETHTOOL_FLASH_MAX_FILENAME];
const struct firmware *fw;
- struct flash_file_hdr *fhdr;
- struct flash_section_info *fsec = NULL;
+ struct flash_file_hdr_g2 *fhdr;
+ struct flash_file_hdr_g3 *fhdr3;
+ struct image_hdr *img_hdr_ptr = NULL;
struct be_dma_mem flash_cmd;
- int status;
+ int status, i = 0;
const u8 *p;
- bool entry_found = false;
- int flash_type;
- char fw_ver[FW_VER_LEN];
- char fw_cfg;
- status = be_cmd_get_fw_ver(adapter, fw_ver);
- if (status)
- return status;
-
- fw_cfg = *(fw_ver + 2);
- if (fw_cfg == '0')
- fw_cfg = '1';
strcpy(fw_file, func);
status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
@@ -1929,34 +2001,9 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
goto fw_exit;
p = fw->data;
- fhdr = (struct flash_file_hdr *) p;
- if (memcmp(fhdr->sign, FW_FILE_HDR_SIGN, strlen(FW_FILE_HDR_SIGN))) {
- dev_err(&adapter->pdev->dev,
- "Firmware(%s) load error (signature did not match)\n",
- fw_file);
- status = -1;
- goto fw_exit;
- }
-
+ fhdr = (struct flash_file_hdr_g2 *) p;
dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file);
- p += sizeof(struct flash_file_hdr);
- while (p < (fw->data + fw->size)) {
- fsec = (struct flash_section_info *)p;
- if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) {
- entry_found = true;
- break;
- }
- p += 32;
- }
-
- if (!entry_found) {
- status = -1;
- dev_err(&adapter->pdev->dev,
- "Flash cookie not found in firmware image\n");
- goto fw_exit;
- }
-
flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024;
flash_cmd.va = pci_alloc_consistent(adapter->pdev, flash_cmd.size,
&flash_cmd.dma);
@@ -1967,12 +2014,26 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
goto fw_exit;
}
- for (flash_type = FLASHROM_TYPE_ISCSI_ACTIVE;
- flash_type <= FLASHROM_TYPE_FCOE_FW_BACKUP; flash_type++) {
- status = be_flash_image(adapter, fw, &flash_cmd,
- flash_type);
- if (status)
- break;
+ if ((adapter->generation == BE_GEN3) &&
+ (get_ufigen_type(fhdr) == BE_GEN3)) {
+ fhdr3 = (struct flash_file_hdr_g3 *) fw->data;
+ for (i = 0; i < fhdr3->num_imgs; i++) {
+ img_hdr_ptr = (struct image_hdr *) (fw->data +
+ (sizeof(struct flash_file_hdr_g3) +
+ i * sizeof(struct image_hdr)));
+ if (img_hdr_ptr->imageid == 1) {
+ status = be_flash_data(adapter, fw,
+ &flash_cmd, fhdr3->num_imgs);
+ }
+
+ }
+ } else if ((adapter->generation == BE_GEN2) &&
+ (get_ufigen_type(fhdr) == BE_GEN2)) {
+ status = be_flash_data(adapter, fw, &flash_cmd, 0);
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "UFI and Interface are not compatible for flashing\n");
+ status = -1;
}
pci_free_consistent(adapter->pdev, flash_cmd.size, flash_cmd.va,
@@ -2049,6 +2110,7 @@ static void be_unmap_pci_bars(struct be_adapter *adapter)
static int be_map_pci_bars(struct be_adapter *adapter)
{
u8 __iomem *addr;
+ int pcicfg_reg;
addr = ioremap_nocache(pci_resource_start(adapter->pdev, 2),
pci_resource_len(adapter->pdev, 2));
@@ -2062,8 +2124,13 @@ static int be_map_pci_bars(struct be_adapter *adapter)
goto pci_map_err;
adapter->db = addr;
- addr = ioremap_nocache(pci_resource_start(adapter->pdev, 1),
- pci_resource_len(adapter->pdev, 1));
+ if (adapter->generation == BE_GEN2)
+ pcicfg_reg = 1;
+ else
+ pcicfg_reg = 0;
+
+ addr = ioremap_nocache(pci_resource_start(adapter->pdev, pcicfg_reg),
+ pci_resource_len(adapter->pdev, pcicfg_reg));
if (addr == NULL)
goto pci_map_err;
adapter->pcicfg = addr;
@@ -2128,6 +2195,7 @@ static int be_ctrl_init(struct be_adapter *adapter)
spin_lock_init(&adapter->mcc_lock);
spin_lock_init(&adapter->mcc_cq_lock);
+ pci_save_state(adapter->pdev);
return 0;
free_mbox:
@@ -2160,6 +2228,7 @@ static int be_stats_init(struct be_adapter *adapter)
cmd->va = pci_alloc_consistent(adapter->pdev, cmd->size, &cmd->dma);
if (cmd->va == NULL)
return -1;
+ memset(cmd->va, 0, cmd->size);
return 0;
}
@@ -2213,6 +2282,11 @@ static int be_get_config(struct be_adapter *adapter)
memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
+ if (adapter->cap & 0x400)
+ adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/4;
+ else
+ adapter->max_vlans = BE_NUM_VLANS_SUPPORTED;
+
return 0;
}
@@ -2238,6 +2312,20 @@ static int __devinit be_probe(struct pci_dev *pdev,
goto rel_reg;
}
adapter = netdev_priv(netdev);
+
+ switch (pdev->device) {
+ case BE_DEVICE_ID1:
+ case OC_DEVICE_ID1:
+ adapter->generation = BE_GEN2;
+ break;
+ case BE_DEVICE_ID2:
+ case OC_DEVICE_ID2:
+ adapter->generation = BE_GEN3;
+ break;
+ default:
+ adapter->generation = 0;
+ }
+
adapter->pdev = pdev;
pci_set_drvdata(pdev, adapter);
adapter->netdev = netdev;
@@ -2371,13 +2459,123 @@ static int be_resume(struct pci_dev *pdev)
return 0;
}
+/*
+ * An FLR will stop BE from DMAing any data.
+ */
+static void be_shutdown(struct pci_dev *pdev)
+{
+ struct be_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
+
+ netif_device_detach(netdev);
+
+ be_cmd_reset_function(adapter);
+
+ if (adapter->wol)
+ be_setup_wol(adapter, true);
+
+ pci_disable_device(pdev);
+
+ return;
+}
+
+static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct be_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
+
+ dev_err(&adapter->pdev->dev, "EEH error detected\n");
+
+ adapter->eeh_err = true;
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev)) {
+ rtnl_lock();
+ be_close(netdev);
+ rtnl_unlock();
+ }
+ be_clear(adapter);
+
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ pci_disable_device(pdev);
+
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev)
+{
+ struct be_adapter *adapter = pci_get_drvdata(pdev);
+ int status;
+
+ dev_info(&adapter->pdev->dev, "EEH reset\n");
+ adapter->eeh_err = false;
+
+ status = pci_enable_device(pdev);
+ if (status)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ pci_set_master(pdev);
+ pci_set_power_state(pdev, 0);
+ pci_restore_state(pdev);
+
+ /* Check if card is ok and fw is ready */
+ status = be_cmd_POST(adapter);
+ if (status)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void be_eeh_resume(struct pci_dev *pdev)
+{
+ int status = 0;
+ struct be_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
+
+ dev_info(&adapter->pdev->dev, "EEH resume\n");
+
+ pci_save_state(pdev);
+
+ /* tell fw we're ready to fire cmds */
+ status = be_cmd_fw_init(adapter);
+ if (status)
+ goto err;
+
+ status = be_setup(adapter);
+ if (status)
+ goto err;
+
+ if (netif_running(netdev)) {
+ status = be_open(netdev);
+ if (status)
+ goto err;
+ }
+ netif_device_attach(netdev);
+ return;
+err:
+ dev_err(&adapter->pdev->dev, "EEH resume failed\n");
+ return;
+}
+
+static struct pci_error_handlers be_eeh_handlers = {
+ .error_detected = be_eeh_err_detected,
+ .slot_reset = be_eeh_reset,
+ .resume = be_eeh_resume,
+};
+
static struct pci_driver be_driver = {
.name = DRV_NAME,
.id_table = be_dev_ids,
.probe = be_probe,
.remove = be_remove,
.suspend = be_suspend,
- .resume = be_resume
+ .resume = be_resume,
+ .shutdown = be_shutdown,
+ .err_handler = &be_eeh_handlers
};
static int __init be_init_module(void)
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 8ffea3990d07..587f93cf03f6 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -33,6 +33,7 @@
#include <asm/dma.h>
#include <linux/dma-mapping.h>
+#include <asm/dpmc.h>
#include <asm/blackfin.h>
#include <asm/cacheflush.h>
#include <asm/portmux.h>
@@ -386,8 +387,8 @@ static int mii_probe(struct net_device *dev)
u32 sclk, mdc_div;
/* Enable PHY output early */
- if (!(bfin_read_VR_CTL() & PHYCLKOE))
- bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE);
+ if (!(bfin_read_VR_CTL() & CLKBUFOE))
+ bfin_write_VR_CTL(bfin_read_VR_CTL() | CLKBUFOE);
sclk = get_sclk();
mdc_div = ((sclk / MDC_CLK) / 2) - 1;
@@ -811,16 +812,14 @@ static void bfin_mac_timeout(struct net_device *dev)
static void bfin_mac_multicast_hash(struct net_device *dev)
{
u32 emac_hashhi, emac_hashlo;
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
char *addrs;
- int i;
u32 crc;
emac_hashhi = emac_hashlo = 0;
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
addrs = dmi->dmi_addr;
- dmi = dmi->next;
/* skip non-multicast addresses */
if (!(*addrs & 1))
@@ -861,7 +860,7 @@ static void bfin_mac_set_multicast_list(struct net_device *dev)
sysctl = bfin_read_EMAC_OPMODE();
sysctl |= PAM;
bfin_write_EMAC_OPMODE(sysctl);
- } else if (dev->mc_count) {
+ } else if (!netdev_mc_empty(dev)) {
/* set up multicast hash table */
sysctl = bfin_read_EMAC_OPMODE();
sysctl |= HM;
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 9b587c344194..119468e76323 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -973,7 +973,7 @@ static void bmac_set_multicast(struct net_device *dev)
{
struct dev_mc_list *dmi;
struct bmac_data *bp = netdev_priv(dev);
- int num_addrs = dev->mc_count;
+ int num_addrs = netdev_mc_count(dev);
unsigned short rx_cfg;
int i;
@@ -982,7 +982,7 @@ static void bmac_set_multicast(struct net_device *dev)
XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs));
- if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+ if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) {
for (i=0; i<4; i++) bp->hash_table_mask[i] = 0xffff;
bmac_update_hash_table_mask(dev, bp);
rx_cfg = bmac_rx_on(dev, 1, 0);
@@ -1000,7 +1000,7 @@ static void bmac_set_multicast(struct net_device *dev)
rx_cfg = bmac_rx_on(dev, 0, 0);
XXDEBUG(("bmac: multi disabled, rx_cfg=%#08x\n", rx_cfg));
} else {
- for (dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next)
+ netdev_for_each_mc_addr(dmi, dev)
bmac_addhash(bp, dmi->dmi_addr);
bmac_update_hash_table_mask(dev, bp);
rx_cfg = bmac_rx_on(dev, 1, 0);
@@ -1015,13 +1015,13 @@ static void bmac_set_multicast(struct net_device *dev)
static void bmac_set_multicast(struct net_device *dev)
{
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
char *addrs;
int i;
unsigned short rx_cfg;
u32 crc;
- if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+ if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) {
bmwrite(dev, BHASH0, 0xffff);
bmwrite(dev, BHASH1, 0xffff);
bmwrite(dev, BHASH2, 0xffff);
@@ -1039,9 +1039,8 @@ static void bmac_set_multicast(struct net_device *dev)
for(i = 0; i < 4; i++) hash_table[i] = 0;
- for(i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
addrs = dmi->dmi_addr;
- dmi = dmi->next;
if(!(*addrs & 1))
continue;
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 65df1de447e4..381887ba677c 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -1,6 +1,6 @@
/* bnx2.c: Broadcom NX2 network driver.
*
- * Copyright (c) 2004-2009 Broadcom Corporation
+ * Copyright (c) 2004-2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -9,6 +9,7 @@
* Written by: Michael Chan (mchan@broadcom.com)
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -48,7 +49,6 @@
#include <linux/cache.h>
#include <linux/firmware.h>
#include <linux/log2.h>
-#include <linux/list.h>
#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
#define BCM_CNIC 1
@@ -58,14 +58,13 @@
#include "bnx2_fw.h"
#define DRV_MODULE_NAME "bnx2"
-#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "2.0.3"
-#define DRV_MODULE_RELDATE "Dec 03, 2009"
-#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-5.0.0.j3.fw"
+#define DRV_MODULE_VERSION "2.0.8"
+#define DRV_MODULE_RELDATE "Feb 15, 2010"
+#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-5.0.0.j6.fw"
#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-5.0.0.j3.fw"
-#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-5.0.0.j3.fw"
-#define FW_RV2P_FILE_09_Ax "bnx2/bnx2-rv2p-09ax-5.0.0.j3.fw"
-#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-5.0.0.j3.fw"
+#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-5.0.0.j9.fw"
+#define FW_RV2P_FILE_09_Ax "bnx2/bnx2-rv2p-09ax-5.0.0.j10.fw"
+#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-5.0.0.j10.fw"
#define RUN_AT(x) (jiffies + (x))
@@ -980,33 +979,27 @@ bnx2_report_link(struct bnx2 *bp)
{
if (bp->link_up) {
netif_carrier_on(bp->dev);
- printk(KERN_INFO PFX "%s NIC %s Link is Up, ", bp->dev->name,
- bnx2_xceiver_str(bp));
-
- printk("%d Mbps ", bp->line_speed);
-
- if (bp->duplex == DUPLEX_FULL)
- printk("full duplex");
- else
- printk("half duplex");
+ netdev_info(bp->dev, "NIC %s Link is Up, %d Mbps %s duplex",
+ bnx2_xceiver_str(bp),
+ bp->line_speed,
+ bp->duplex == DUPLEX_FULL ? "full" : "half");
if (bp->flow_ctrl) {
if (bp->flow_ctrl & FLOW_CTRL_RX) {
- printk(", receive ");
+ pr_cont(", receive ");
if (bp->flow_ctrl & FLOW_CTRL_TX)
- printk("& transmit ");
+ pr_cont("& transmit ");
}
else {
- printk(", transmit ");
+ pr_cont(", transmit ");
}
- printk("flow control ON");
+ pr_cont("flow control ON");
}
- printk("\n");
- }
- else {
+ pr_cont("\n");
+ } else {
netif_carrier_off(bp->dev);
- printk(KERN_ERR PFX "%s NIC %s Link is Down\n", bp->dev->name,
- bnx2_xceiver_str(bp));
+ netdev_err(bp->dev, "NIC %s Link is Down\n",
+ bnx2_xceiver_str(bp));
}
bnx2_report_fw_link(bp);
@@ -1278,7 +1271,7 @@ bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
if (lo_water >= bp->rx_ring_size)
lo_water = 0;
- hi_water = bp->rx_ring_size / 4;
+ hi_water = min_t(int, bp->rx_ring_size / 4, lo_water + 16);
if (hi_water <= lo_water)
lo_water = 0;
@@ -2483,8 +2476,7 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
/* If we timed out, inform the firmware that this is the case. */
if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
if (!silent)
- printk(KERN_ERR PFX "fw sync timeout, reset code = "
- "%x\n", msg_data);
+ pr_err("fw sync timeout, reset code = %x\n", msg_data);
msg_data &= ~BNX2_DRV_MSG_CODE;
msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
@@ -2600,8 +2592,7 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp)
good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
if (good_mbuf == NULL) {
- printk(KERN_ERR PFX "Failed to allocate memory in "
- "bnx2_alloc_bad_rbuf\n");
+ pr_err("Failed to allocate memory in %s\n", __func__);
return -ENOMEM;
}
@@ -3561,9 +3552,7 @@ bnx2_set_rx_mode(struct net_device *dev)
memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
-
+ netdev_for_each_mc_addr(mclist, dev) {
crc = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
bit = crc & 0xff;
regidx = (bit & 0xe0) >> 5;
@@ -3579,14 +3568,14 @@ bnx2_set_rx_mode(struct net_device *dev)
sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
}
- if (dev->uc.count > BNX2_MAX_UNICAST_ADDRESSES) {
+ if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) {
rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
BNX2_RPM_SORT_USER0_PROM_VLAN;
} else if (!(dev->flags & IFF_PROMISC)) {
/* Add all entries into to the match filter list */
i = 0;
- list_for_each_entry(ha, &dev->uc.list, list) {
+ netdev_for_each_uc_addr(ha, dev) {
bnx2_set_mac_addr(bp, ha->addr,
i + BNX2_START_UNICAST_ADDRESS_INDEX);
sort_mode |= (1 <<
@@ -3657,15 +3646,13 @@ bnx2_request_firmware(struct bnx2 *bp)
rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
if (rc) {
- printk(KERN_ERR PFX "Can't load firmware file \"%s\"\n",
- mips_fw_file);
+ pr_err("Can't load firmware file \"%s\"\n", mips_fw_file);
return rc;
}
rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
if (rc) {
- printk(KERN_ERR PFX "Can't load firmware file \"%s\"\n",
- rv2p_fw_file);
+ pr_err("Can't load firmware file \"%s\"\n", rv2p_fw_file);
return rc;
}
mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
@@ -3676,15 +3663,13 @@ bnx2_request_firmware(struct bnx2 *bp)
check_mips_fw_entry(bp->mips_firmware, &mips_fw->rxp) ||
check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) ||
check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) {
- printk(KERN_ERR PFX "Firmware file \"%s\" is invalid\n",
- mips_fw_file);
+ pr_err("Firmware file \"%s\" is invalid\n", mips_fw_file);
return -EINVAL;
}
if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) ||
check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) ||
check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) {
- printk(KERN_ERR PFX "Firmware file \"%s\" is invalid\n",
- rv2p_fw_file);
+ pr_err("Firmware file \"%s\" is invalid\n", rv2p_fw_file);
return -EINVAL;
}
@@ -4318,7 +4303,7 @@ bnx2_init_nvram(struct bnx2 *bp)
if (j == entry_count) {
bp->flash_info = NULL;
- printk(KERN_ALERT PFX "Unknown flash/EEPROM type.\n");
+ pr_alert("Unknown flash/EEPROM type\n");
return -ENODEV;
}
@@ -4738,7 +4723,7 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
- printk(KERN_ERR PFX "Chip reset did not complete\n");
+ pr_err("Chip reset did not complete\n");
return -EBUSY;
}
}
@@ -4746,7 +4731,7 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
/* Make sure byte swapping is properly configured. */
val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
if (val != 0x01020304) {
- printk(KERN_ERR PFX "Chip not in correct endian mode\n");
+ pr_err("Chip not in correct endian mode\n");
return -ENODEV;
}
@@ -4941,7 +4926,7 @@ bnx2_init_chip(struct bnx2 *bp)
BNX2_HC_CONFIG_COLLECT_STATS;
}
- if (bp->irq_nvecs > 1) {
+ if (bp->flags & BNX2_FLAG_USING_MSIX) {
REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
BNX2_HC_MSIX_BIT_VECTOR_VAL);
@@ -5167,9 +5152,8 @@ bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
ring_prod = prod = rxr->rx_pg_prod;
for (i = 0; i < bp->rx_pg_ring_size; i++) {
if (bnx2_alloc_rx_page(bp, rxr, ring_prod) < 0) {
- printk(KERN_WARNING PFX "%s: init'ed rx page ring %d "
- "with %d/%d pages only\n",
- bp->dev->name, ring_num, i, bp->rx_pg_ring_size);
+ netdev_warn(bp->dev, "init'ed rx page ring %d with %d/%d pages only\n",
+ ring_num, i, bp->rx_pg_ring_size);
break;
}
prod = NEXT_RX_BD(prod);
@@ -5180,9 +5164,8 @@ bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
ring_prod = prod = rxr->rx_prod;
for (i = 0; i < bp->rx_ring_size; i++) {
if (bnx2_alloc_rx_skb(bp, rxr, ring_prod) < 0) {
- printk(KERN_WARNING PFX "%s: init'ed rx ring %d with "
- "%d/%d skbs only\n",
- bp->dev->name, ring_num, i, bp->rx_ring_size);
+ netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
+ ring_num, i, bp->rx_ring_size);
break;
}
prod = NEXT_RX_BD(prod);
@@ -6145,6 +6128,10 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
+ /* Need to flush the previous three writes to ensure MSI-X
+ * is setup properly */
+ REG_RD(bp, BNX2_PCI_MSIX_CONTROL);
+
for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
msix_ent[i].entry = i;
msix_ent[i].vector = 0;
@@ -6227,6 +6214,8 @@ bnx2_open(struct net_device *dev)
atomic_set(&bp->intr_sem, 0);
+ memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block));
+
bnx2_enable_int(bp);
if (bp->flags & BNX2_FLAG_USING_MSI) {
@@ -6234,11 +6223,7 @@ bnx2_open(struct net_device *dev)
* If MSI test fails, go back to INTx mode
*/
if (bnx2_test_intr(bp) != 0) {
- printk(KERN_WARNING PFX "%s: No interrupt was generated"
- " using MSI, switching to INTx mode. Please"
- " report this failure to the PCI maintainer"
- " and include system chipset information.\n",
- bp->dev->name);
+ netdev_warn(bp->dev, "No interrupt was generated using MSI, switching to INTx mode. Please report this failure to the PCI maintainer and include system chipset information.\n");
bnx2_disable_int(bp);
bnx2_free_irq(bp);
@@ -6258,9 +6243,9 @@ bnx2_open(struct net_device *dev)
}
}
if (bp->flags & BNX2_FLAG_USING_MSI)
- printk(KERN_INFO PFX "%s: using MSI\n", dev->name);
+ netdev_info(dev, "using MSI\n");
else if (bp->flags & BNX2_FLAG_USING_MSIX)
- printk(KERN_INFO PFX "%s: using MSIX\n", dev->name);
+ netdev_info(dev, "using MSIX\n");
netif_tx_start_all_queues(dev);
@@ -6299,20 +6284,18 @@ bnx2_dump_state(struct bnx2 *bp)
{
struct net_device *dev = bp->dev;
- printk(KERN_ERR PFX "%s DEBUG: intr_sem[%x]\n", dev->name,
- atomic_read(&bp->intr_sem));
- printk(KERN_ERR PFX "%s DEBUG: EMAC_TX_STATUS[%08x] "
- "RPM_MGMT_PKT_CTRL[%08x]\n", dev->name,
- REG_RD(bp, BNX2_EMAC_TX_STATUS),
- REG_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
- printk(KERN_ERR PFX "%s DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
- dev->name, bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P0),
- bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P1));
- printk(KERN_ERR PFX "%s DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
- dev->name, REG_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
+ netdev_err(dev, "DEBUG: intr_sem[%x]\n", atomic_read(&bp->intr_sem));
+ netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] RPM_MGMT_PKT_CTRL[%08x]\n",
+ REG_RD(bp, BNX2_EMAC_TX_STATUS),
+ REG_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
+ netdev_err(dev, "DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
+ bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P0),
+ bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P1));
+ netdev_err(dev, "DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
+ REG_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
if (bp->flags & BNX2_FLAG_USING_MSIX)
- printk(KERN_ERR PFX "%s DEBUG: PBA[%08x]\n", dev->name,
- REG_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE));
+ netdev_err(dev, "DEBUG: PBA[%08x]\n",
+ REG_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE));
}
static void
@@ -6376,8 +6359,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(bnx2_tx_avail(bp, txr) <
(skb_shinfo(skb)->nr_frags + 1))) {
netif_tx_stop_queue(txq);
- printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
- dev->name);
+ netdev_err(dev, "BUG! Tx ring full when queue awake!\n");
return NETDEV_TX_BUSY;
}
@@ -6538,92 +6520,121 @@ bnx2_close(struct net_device *dev)
return 0;
}
-#define GET_NET_STATS64(ctr) \
+static void
+bnx2_save_stats(struct bnx2 *bp)
+{
+ u32 *hw_stats = (u32 *) bp->stats_blk;
+ u32 *temp_stats = (u32 *) bp->temp_stats_blk;
+ int i;
+
+ /* The 1st 10 counters are 64-bit counters */
+ for (i = 0; i < 20; i += 2) {
+ u32 hi;
+ u64 lo;
+
+ hi = temp_stats[i] + hw_stats[i];
+ lo = (u64) temp_stats[i + 1] + (u64) hw_stats[i + 1];
+ if (lo > 0xffffffff)
+ hi++;
+ temp_stats[i] = hi;
+ temp_stats[i + 1] = lo & 0xffffffff;
+ }
+
+ for ( ; i < sizeof(struct statistics_block) / 4; i++)
+ temp_stats[i] += hw_stats[i];
+}
+
+#define GET_64BIT_NET_STATS64(ctr) \
(unsigned long) ((unsigned long) (ctr##_hi) << 32) + \
(unsigned long) (ctr##_lo)
-#define GET_NET_STATS32(ctr) \
+#define GET_64BIT_NET_STATS32(ctr) \
(ctr##_lo)
#if (BITS_PER_LONG == 64)
-#define GET_NET_STATS GET_NET_STATS64
+#define GET_64BIT_NET_STATS(ctr) \
+ GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + \
+ GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
#else
-#define GET_NET_STATS GET_NET_STATS32
+#define GET_64BIT_NET_STATS(ctr) \
+ GET_64BIT_NET_STATS32(bp->stats_blk->ctr) + \
+ GET_64BIT_NET_STATS32(bp->temp_stats_blk->ctr)
#endif
+#define GET_32BIT_NET_STATS(ctr) \
+ (unsigned long) (bp->stats_blk->ctr + \
+ bp->temp_stats_blk->ctr)
+
static struct net_device_stats *
bnx2_get_stats(struct net_device *dev)
{
struct bnx2 *bp = netdev_priv(dev);
- struct statistics_block *stats_blk = bp->stats_blk;
struct net_device_stats *net_stats = &dev->stats;
if (bp->stats_blk == NULL) {
return net_stats;
}
net_stats->rx_packets =
- GET_NET_STATS(stats_blk->stat_IfHCInUcastPkts) +
- GET_NET_STATS(stats_blk->stat_IfHCInMulticastPkts) +
- GET_NET_STATS(stats_blk->stat_IfHCInBroadcastPkts);
+ GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
+ GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
+ GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts);
net_stats->tx_packets =
- GET_NET_STATS(stats_blk->stat_IfHCOutUcastPkts) +
- GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts) +
- GET_NET_STATS(stats_blk->stat_IfHCOutBroadcastPkts);
+ GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) +
+ GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) +
+ GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts);
net_stats->rx_bytes =
- GET_NET_STATS(stats_blk->stat_IfHCInOctets);
+ GET_64BIT_NET_STATS(stat_IfHCInOctets);
net_stats->tx_bytes =
- GET_NET_STATS(stats_blk->stat_IfHCOutOctets);
+ GET_64BIT_NET_STATS(stat_IfHCOutOctets);
net_stats->multicast =
- GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts);
+ GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts);
net_stats->collisions =
- (unsigned long) stats_blk->stat_EtherStatsCollisions;
+ GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
net_stats->rx_length_errors =
- (unsigned long) (stats_blk->stat_EtherStatsUndersizePkts +
- stats_blk->stat_EtherStatsOverrsizePkts);
+ GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) +
+ GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts);
net_stats->rx_over_errors =
- (unsigned long) (stats_blk->stat_IfInFTQDiscards +
- stats_blk->stat_IfInMBUFDiscards);
+ GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
+ GET_32BIT_NET_STATS(stat_IfInMBUFDiscards);
net_stats->rx_frame_errors =
- (unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors;
+ GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors);
net_stats->rx_crc_errors =
- (unsigned long) stats_blk->stat_Dot3StatsFCSErrors;
+ GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors);
net_stats->rx_errors = net_stats->rx_length_errors +
net_stats->rx_over_errors + net_stats->rx_frame_errors +
net_stats->rx_crc_errors;
net_stats->tx_aborted_errors =
- (unsigned long) (stats_blk->stat_Dot3StatsExcessiveCollisions +
- stats_blk->stat_Dot3StatsLateCollisions);
+ GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) +
+ GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions);
if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
(CHIP_ID(bp) == CHIP_ID_5708_A0))
net_stats->tx_carrier_errors = 0;
else {
net_stats->tx_carrier_errors =
- (unsigned long)
- stats_blk->stat_Dot3StatsCarrierSenseErrors;
+ GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors);
}
net_stats->tx_errors =
- (unsigned long)
- stats_blk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors
- +
+ GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) +
net_stats->tx_aborted_errors +
net_stats->tx_carrier_errors;
net_stats->rx_missed_errors =
- (unsigned long) (stats_blk->stat_IfInFTQDiscards +
- stats_blk->stat_IfInMBUFDiscards + stats_blk->stat_FwRxDrop);
+ GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
+ GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) +
+ GET_32BIT_NET_STATS(stat_FwRxDrop);
return net_stats;
}
@@ -6717,32 +6728,15 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (cmd->autoneg == AUTONEG_ENABLE) {
autoneg |= AUTONEG_SPEED;
- cmd->advertising &= ETHTOOL_ALL_COPPER_SPEED;
-
- /* allow advertising 1 speed */
- if ((cmd->advertising == ADVERTISED_10baseT_Half) ||
- (cmd->advertising == ADVERTISED_10baseT_Full) ||
- (cmd->advertising == ADVERTISED_100baseT_Half) ||
- (cmd->advertising == ADVERTISED_100baseT_Full)) {
-
- if (cmd->port == PORT_FIBRE)
- goto err_out_unlock;
-
- advertising = cmd->advertising;
-
- } else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
- if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ||
- (cmd->port == PORT_TP))
- goto err_out_unlock;
- } else if (cmd->advertising == ADVERTISED_1000baseT_Full)
- advertising = cmd->advertising;
- else if (cmd->advertising == ADVERTISED_1000baseT_Half)
- goto err_out_unlock;
- else {
- if (cmd->port == PORT_FIBRE)
- advertising = ETHTOOL_ALL_FIBRE_SPEED;
- else
+ advertising = cmd->advertising;
+ if (cmd->port == PORT_TP) {
+ advertising &= ETHTOOL_ALL_COPPER_SPEED;
+ if (!advertising)
advertising = ETHTOOL_ALL_COPPER_SPEED;
+ } else {
+ advertising &= ETHTOOL_ALL_FIBRE_SPEED;
+ if (!advertising)
+ advertising = ETHTOOL_ALL_FIBRE_SPEED;
}
advertising |= ADVERTISED_Autoneg;
}
@@ -7083,6 +7077,9 @@ static int
bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
{
if (netif_running(bp->dev)) {
+ /* Reset will erase chipset stats; save them */
+ bnx2_save_stats(bp);
+
bnx2_netif_stop(bp);
bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
bnx2_free_skbs(bp);
@@ -7104,6 +7101,13 @@ bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
dev_close(bp->dev);
return rc;
}
+#ifdef BCM_CNIC
+ mutex_lock(&bp->cnic_lock);
+ /* Let cnic know about the new status block. */
+ if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD)
+ bnx2_setup_cnic_irq_info(bp);
+ mutex_unlock(&bp->cnic_lock);
+#endif
bnx2_netif_start(bp);
}
return 0;
@@ -7427,6 +7431,7 @@ bnx2_get_ethtool_stats(struct net_device *dev,
struct bnx2 *bp = netdev_priv(dev);
int i;
u32 *hw_stats = (u32 *) bp->stats_blk;
+ u32 *temp_stats = (u32 *) bp->temp_stats_blk;
u8 *stats_len_arr = NULL;
if (hw_stats == NULL) {
@@ -7443,21 +7448,26 @@ bnx2_get_ethtool_stats(struct net_device *dev,
stats_len_arr = bnx2_5708_stats_len_arr;
for (i = 0; i < BNX2_NUM_STATS; i++) {
+ unsigned long offset;
+
if (stats_len_arr[i] == 0) {
/* skip this counter */
buf[i] = 0;
continue;
}
+
+ offset = bnx2_stats_offset_arr[i];
if (stats_len_arr[i] == 4) {
/* 4-byte counter */
- buf[i] = (u64)
- *(hw_stats + bnx2_stats_offset_arr[i]);
+ buf[i] = (u64) *(hw_stats + offset) +
+ *(temp_stats + offset);
continue;
}
/* 8-byte counter */
- buf[i] = (((u64) *(hw_stats +
- bnx2_stats_offset_arr[i])) << 32) +
- *(hw_stats + bnx2_stats_offset_arr[i] + 1);
+ buf[i] = (((u64) *(hw_stats + offset)) << 32) +
+ *(hw_stats + offset + 1) +
+ (((u64) *(temp_stats + offset)) << 32) +
+ *(temp_stats + offset + 1);
}
}
@@ -7625,7 +7635,7 @@ bnx2_change_mtu(struct net_device *dev, int new_mtu)
return (bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size));
}
-#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+#ifdef CONFIG_NET_POLL_CONTROLLER
static void
poll_bnx2(struct net_device *dev)
{
@@ -7733,10 +7743,9 @@ bnx2_get_pci_speed(struct bnx2 *bp)
static void __devinit
bnx2_read_vpd_fw_ver(struct bnx2 *bp)
{
- int rc, i, v0_len = 0;
+ int rc, i, j;
u8 *data;
- u8 *v0_str = NULL;
- bool mn_match = false;
+ unsigned int block_end, rosize, len;
#define BNX2_VPD_NVRAM_OFFSET 0x300
#define BNX2_VPD_LEN 128
@@ -7758,53 +7767,42 @@ bnx2_read_vpd_fw_ver(struct bnx2 *bp)
data[i + 3] = data[i + BNX2_VPD_LEN];
}
- for (i = 0; i <= BNX2_VPD_LEN - 3; ) {
- unsigned char val = data[i];
- unsigned int block_end;
-
- if (val == 0x82 || val == 0x91) {
- i = (i + 3 + (data[i + 1] + (data[i + 2] << 8)));
- continue;
- }
-
- if (val != 0x90)
- goto vpd_done;
+ i = pci_vpd_find_tag(data, 0, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA);
+ if (i < 0)
+ goto vpd_done;
- block_end = (i + 3 + (data[i + 1] + (data[i + 2] << 8)));
- i += 3;
+ rosize = pci_vpd_lrdt_size(&data[i]);
+ i += PCI_VPD_LRDT_TAG_SIZE;
+ block_end = i + rosize;
- if (block_end > BNX2_VPD_LEN)
- goto vpd_done;
+ if (block_end > BNX2_VPD_LEN)
+ goto vpd_done;
- while (i < (block_end - 2)) {
- int len = data[i + 2];
+ j = pci_vpd_find_info_keyword(data, i, rosize,
+ PCI_VPD_RO_KEYWORD_MFR_ID);
+ if (j < 0)
+ goto vpd_done;
- if (i + 3 + len > block_end)
- goto vpd_done;
+ len = pci_vpd_info_field_size(&data[j]);
- if (data[i] == 'M' && data[i + 1] == 'N') {
- if (len != 4 ||
- memcmp(&data[i + 3], "1028", 4))
- goto vpd_done;
- mn_match = true;
+ j += PCI_VPD_INFO_FLD_HDR_SIZE;
+ if (j + len > block_end || len != 4 ||
+ memcmp(&data[j], "1028", 4))
+ goto vpd_done;
- } else if (data[i] == 'V' && data[i + 1] == '0') {
- if (len > BNX2_MAX_VER_SLEN)
- goto vpd_done;
+ j = pci_vpd_find_info_keyword(data, i, rosize,
+ PCI_VPD_RO_KEYWORD_VENDOR0);
+ if (j < 0)
+ goto vpd_done;
- v0_len = len;
- v0_str = &data[i + 3];
- }
- i += 3 + len;
+ len = pci_vpd_info_field_size(&data[j]);
- if (mn_match && v0_str) {
- memcpy(bp->fw_version, v0_str, v0_len);
- bp->fw_version[v0_len] = ' ';
- goto vpd_done;
- }
- }
+ j += PCI_VPD_INFO_FLD_HDR_SIZE;
+ if (j + len > block_end || len > BNX2_MAX_VER_SLEN)
goto vpd_done;
- }
+
+ memcpy(bp->fw_version, &data[j], len);
+ bp->fw_version[len] = ' ';
vpd_done:
kfree(data);
@@ -7825,23 +7823,31 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->flags = 0;
bp->phy_flags = 0;
+ bp->temp_stats_blk =
+ kzalloc(sizeof(struct statistics_block), GFP_KERNEL);
+
+ if (bp->temp_stats_blk == NULL) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
/* enable device (incl. PCI PM wakeup), and bus-mastering */
rc = pci_enable_device(pdev);
if (rc) {
- dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
+ dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
goto err_out;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
dev_err(&pdev->dev,
- "Cannot find PCI device base address, aborting.\n");
+ "Cannot find PCI device base address, aborting\n");
rc = -ENODEV;
goto err_out_disable;
}
rc = pci_request_regions(pdev, DRV_MODULE_NAME);
if (rc) {
- dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
+ dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
goto err_out_disable;
}
@@ -7851,7 +7857,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
if (bp->pm_cap == 0) {
dev_err(&pdev->dev,
- "Cannot find power management capability, aborting.\n");
+ "Cannot find power management capability, aborting\n");
rc = -EIO;
goto err_out_release;
}
@@ -7874,7 +7880,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->regview = ioremap_nocache(dev->base_addr, mem_len);
if (!bp->regview) {
- dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
+ dev_err(&pdev->dev, "Cannot map register space, aborting\n");
rc = -ENOMEM;
goto err_out_release;
}
@@ -7894,7 +7900,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
if (CHIP_NUM(bp) == CHIP_NUM_5709) {
if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) {
dev_err(&pdev->dev,
- "Cannot find PCIE capability, aborting.\n");
+ "Cannot find PCIE capability, aborting\n");
rc = -EIO;
goto err_out_unmap;
}
@@ -7905,7 +7911,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
if (bp->pcix_cap == 0) {
dev_err(&pdev->dev,
- "Cannot find PCIX capability, aborting.\n");
+ "Cannot find PCIX capability, aborting\n");
rc = -EIO;
goto err_out_unmap;
}
@@ -7934,11 +7940,11 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
if (rc) {
dev_err(&pdev->dev,
- "pci_set_consistent_dma_mask failed, aborting.\n");
+ "pci_set_consistent_dma_mask failed, aborting\n");
goto err_out_unmap;
}
} else if ((rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
- dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
+ dev_err(&pdev->dev, "System does not support DMA, aborting\n");
goto err_out_unmap;
}
@@ -7955,7 +7961,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
!(bp->flags & BNX2_FLAG_PCIX)) {
dev_err(&pdev->dev,
- "5706 A1 can only be used in a PCIX bus, aborting.\n");
+ "5706 A1 can only be used in a PCIX bus, aborting\n");
goto err_out_unmap;
}
@@ -7978,7 +7984,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
BNX2_DEV_INFO_SIGNATURE_MAGIC) {
- dev_err(&pdev->dev, "Firmware not running, aborting.\n");
+ dev_err(&pdev->dev, "Firmware not running, aborting\n");
rc = -ENODEV;
goto err_out_unmap;
}
@@ -8229,7 +8235,7 @@ static const struct net_device_ops bnx2_netdev_ops = {
#ifdef BCM_VLAN
.ndo_vlan_rx_register = bnx2_vlan_rx_register,
#endif
-#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = poll_bnx2,
#endif
};
@@ -8251,7 +8257,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
char str[40];
if (version_printed++ == 0)
- printk(KERN_INFO "%s", version);
+ pr_info("%s", version);
/* dev zeroed in init_etherdev */
dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
@@ -8301,15 +8307,13 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto error;
}
- printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
- "IRQ %d, node addr %pM\n",
- dev->name,
- board_info[ent->driver_data].name,
- ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
- ((CHIP_ID(bp) & 0x0ff0) >> 4),
- bnx2_bus_string(bp, str),
- dev->base_addr,
- bp->pdev->irq, dev->dev_addr);
+ netdev_info(dev, "%s (%c%d) %s found at mem %lx, IRQ %d, node addr %pM\n",
+ board_info[ent->driver_data].name,
+ ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
+ ((CHIP_ID(bp) & 0x0ff0) >> 4),
+ bnx2_bus_string(bp, str),
+ dev->base_addr,
+ bp->pdev->irq, dev->dev_addr);
return 0;
@@ -8346,6 +8350,8 @@ bnx2_remove_one(struct pci_dev *pdev)
if (bp->regview)
iounmap(bp->regview);
+ kfree(bp->temp_stats_blk);
+
free_netdev(dev);
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -8442,7 +8448,7 @@ static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
rtnl_lock();
if (pci_enable_device(pdev)) {
dev_err(&pdev->dev,
- "Cannot re-enable PCI device after reset.\n");
+ "Cannot re-enable PCI device after reset\n");
rtnl_unlock();
return PCI_ERS_RESULT_DISCONNECT;
}
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 939dc44d50a0..cd4b0e4637ab 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -349,7 +349,7 @@ struct l2_fhdr {
#define BNX2_L2CTX_BD_PRE_READ 0x00000000
#define BNX2_L2CTX_CTX_SIZE 0x00000000
#define BNX2_L2CTX_CTX_TYPE 0x00000000
-#define BNX2_L2CTX_LO_WATER_MARK_DEFAULT 32
+#define BNX2_L2CTX_LO_WATER_MARK_DEFAULT 4
#define BNX2_L2CTX_LO_WATER_MARK_SCALE 4
#define BNX2_L2CTX_LO_WATER_MARK_DIS 0
#define BNX2_L2CTX_HI_WATER_MARK_SHIFT 4
@@ -6851,6 +6851,7 @@ struct bnx2 {
dma_addr_t status_blk_mapping;
struct statistics_block *stats_blk;
+ struct statistics_block *temp_stats_blk;
dma_addr_t stats_blk_mapping;
int ctx_pages;
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index 602ab86b6392..3c48a7a68308 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -1,6 +1,6 @@
/* bnx2x.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2009 Broadcom Corporation
+ * Copyright (c) 2007-2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,7 +44,6 @@
/* error/debug prints */
#define DRV_MODULE_NAME "bnx2x"
-#define PFX DRV_MODULE_NAME ": "
/* for messages that are currently off */
#define BNX2X_MSG_OFF 0
@@ -58,30 +57,40 @@
#define DP_LEVEL KERN_NOTICE /* was: KERN_DEBUG */
/* regular debug print */
-#define DP(__mask, __fmt, __args...) do { \
- if (bp->msglevel & (__mask)) \
- printk(DP_LEVEL "[%s:%d(%s)]" __fmt, __func__, __LINE__, \
- bp->dev ? (bp->dev->name) : "?", ##__args); \
- } while (0)
+#define DP(__mask, __fmt, __args...) \
+do { \
+ if (bp->msg_enable & (__mask)) \
+ printk(DP_LEVEL "[%s:%d(%s)]" __fmt, \
+ __func__, __LINE__, \
+ bp->dev ? (bp->dev->name) : "?", \
+ ##__args); \
+} while (0)
/* errors debug print */
-#define BNX2X_DBG_ERR(__fmt, __args...) do { \
- if (bp->msglevel & NETIF_MSG_PROBE) \
- printk(KERN_ERR "[%s:%d(%s)]" __fmt, __func__, __LINE__, \
- bp->dev ? (bp->dev->name) : "?", ##__args); \
- } while (0)
+#define BNX2X_DBG_ERR(__fmt, __args...) \
+do { \
+ if (netif_msg_probe(bp)) \
+ pr_err("[%s:%d(%s)]" __fmt, \
+ __func__, __LINE__, \
+ bp->dev ? (bp->dev->name) : "?", \
+ ##__args); \
+} while (0)
/* for errors (never masked) */
-#define BNX2X_ERR(__fmt, __args...) do { \
- printk(KERN_ERR "[%s:%d(%s)]" __fmt, __func__, __LINE__, \
- bp->dev ? (bp->dev->name) : "?", ##__args); \
- } while (0)
+#define BNX2X_ERR(__fmt, __args...) \
+do { \
+ pr_err("[%s:%d(%s)]" __fmt, \
+ __func__, __LINE__, \
+ bp->dev ? (bp->dev->name) : "?", \
+ ##__args); \
+} while (0)
/* before we have a dev->name use dev_info() */
-#define BNX2X_DEV_INFO(__fmt, __args...) do { \
- if (bp->msglevel & NETIF_MSG_PROBE) \
- dev_info(&bp->pdev->dev, __fmt, ##__args); \
- } while (0)
+#define BNX2X_DEV_INFO(__fmt, __args...) \
+do { \
+ if (netif_msg_probe(bp)) \
+ dev_info(&bp->pdev->dev, __fmt, ##__args); \
+} while (0)
#ifdef BNX2X_STOP_ON_ERROR
@@ -130,7 +139,7 @@
offset, len32); \
} while (0)
-#define VIRT_WR_DMAE_LEN(bp, data, addr, len32) \
+#define VIRT_WR_DMAE_LEN(bp, data, addr, len32, le32_swap) \
do { \
memcpy(GUNZIP_BUF(bp), data, (len32) * 4); \
bnx2x_write_big_buf_wb(bp, addr, len32); \
@@ -882,7 +891,7 @@ struct bnx2x {
/* End of fields used in the performance code paths */
int panic;
- int msglevel;
+ int msg_enable;
u32 flags;
#define PCIX_FLAG 1
diff --git a/drivers/net/bnx2x_fw_defs.h b/drivers/net/bnx2x_fw_defs.h
index 931dcace5628..08d71bf438d6 100644
--- a/drivers/net/bnx2x_fw_defs.h
+++ b/drivers/net/bnx2x_fw_defs.h
@@ -1,6 +1,6 @@
/* bnx2x_fw_defs.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2009 Broadcom Corporation
+ * Copyright (c) 2007-2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -471,6 +471,11 @@
/* Host coalescing constants */
+#define HC_IGU_BC_MODE 0
+#define HC_IGU_NBC_MODE 1
+
+#define HC_REGULAR_SEGMENT 0
+#define HC_DEFAULT_SEGMENT 1
/* index numbers */
#define HC_USTORM_DEF_SB_NUM_INDICES 8
diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h
index 52585338ada8..760069345b11 100644
--- a/drivers/net/bnx2x_hsi.h
+++ b/drivers/net/bnx2x_hsi.h
@@ -1,6 +1,6 @@
/* bnx2x_hsi.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2009 Broadcom Corporation
+ * Copyright (c) 2007-2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -1261,7 +1261,7 @@ struct host_func_stats {
#define BCM_5710_FW_MAJOR_VERSION 5
#define BCM_5710_FW_MINOR_VERSION 2
-#define BCM_5710_FW_REVISION_VERSION 7
+#define BCM_5710_FW_REVISION_VERSION 13
#define BCM_5710_FW_ENGINEERING_VERSION 0
#define BCM_5710_FW_COMPILE_FLAGS 1
@@ -2433,8 +2433,10 @@ struct common_ramrod_eth_rx_cqe {
u8 ramrod_type;
#define COMMON_RAMROD_ETH_RX_CQE_TYPE (0x1<<0)
#define COMMON_RAMROD_ETH_RX_CQE_TYPE_SHIFT 0
-#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0 (0x7F<<1)
-#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0_SHIFT 1
+#define COMMON_RAMROD_ETH_RX_CQE_ERROR (0x1<<1)
+#define COMMON_RAMROD_ETH_RX_CQE_ERROR_SHIFT 1
+#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0 (0x3F<<2)
+#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0_SHIFT 2
u8 conn_type;
__le16 reserved1;
__le32 conn_and_cmd_data;
diff --git a/drivers/net/bnx2x_init_ops.h b/drivers/net/bnx2x_init_ops.h
index 38b970a14fd7..2b1363a6fe78 100644
--- a/drivers/net/bnx2x_init_ops.h
+++ b/drivers/net/bnx2x_init_ops.h
@@ -2,7 +2,7 @@
* Static functions needed during the initialization.
* This file is "included" in bnx2x_main.c.
*
- * Copyright (c) 2007-2009 Broadcom Corporation
+ * Copyright (c) 2007-2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -138,11 +138,16 @@ static void bnx2x_write_big_buf_wb(struct bnx2x *bp, u32 addr, u32 len)
static void bnx2x_init_wr_wb(struct bnx2x *bp, u32 addr, const u32 *data,
u32 len)
{
+ const u32 *old_data = data;
+
data = (const u32 *)bnx2x_sel_blob(bp, addr, (const u8 *)data);
- if (bp->dmae_ready)
- VIRT_WR_DMAE_LEN(bp, data, addr, len);
- else
+ if (bp->dmae_ready) {
+ if (old_data != data)
+ VIRT_WR_DMAE_LEN(bp, data, addr, len, 1);
+ else
+ VIRT_WR_DMAE_LEN(bp, data, addr, len, 0);
+ } else
bnx2x_init_ind_wr(bp, addr, data, len);
}
diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c
index cf5778919b4b..32e79c359e89 100644
--- a/drivers/net/bnx2x_link.c
+++ b/drivers/net/bnx2x_link.c
@@ -14,6 +14,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/pci.h>
@@ -2987,11 +2989,8 @@ static u8 bnx2x_verify_sfp_module(struct link_params *params)
else
vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
- printk(KERN_INFO PFX "Warning: "
- "Unqualified SFP+ module "
- "detected on %s, Port %d from %s part number %s\n"
- , bp->dev->name, params->port,
- vendor_name, vendor_pn);
+ netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected, Port %d from %s part number %s\n",
+ params->port, vendor_name, vendor_pn);
return -EINVAL;
}
@@ -4846,16 +4845,8 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
" has been detected on "
"port %d\n",
params->port);
- printk(KERN_ERR PFX "Error: Power"
- " fault on %s Port %d has"
- " been detected and the"
- " power to that SFP+ module"
- " has been removed to prevent"
- " failure of the card. Please"
- " remove the SFP+ module and"
- " restart the system to clear"
- " this error.\n"
- , bp->dev->name, params->port);
+ netdev_err(bp->dev, "Error: Power fault on Port %d has been detected and the power to that SFP+ module has been removed to prevent failure of the card. Please remove the SFP+ module and restart the system to clear this error.\n",
+ params->port);
/*
* Disable all RX_ALARMs except for
* mod_abs
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index 306c2b8165e2..ed785a30e98b 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -1,6 +1,6 @@
/* bnx2x_main.c: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2009 Broadcom Corporation
+ * Copyright (c) 2007-2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -57,8 +57,8 @@
#include "bnx2x_init_ops.h"
#include "bnx2x_dump.h"
-#define DRV_MODULE_VERSION "1.52.1-5"
-#define DRV_MODULE_RELDATE "2009/11/09"
+#define DRV_MODULE_VERSION "1.52.1-7"
+#define DRV_MODULE_RELDATE "2010/02/28"
#define BNX2X_BC_VER 0x040200
#include <linux/firmware.h>
@@ -140,7 +140,7 @@ static struct {
};
-static const struct pci_device_id bnx2x_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = {
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E },
@@ -514,24 +514,24 @@ static void bnx2x_fw_dump(struct bnx2x *bp)
mark = REG_RD(bp, MCP_REG_MCPR_SCRATCH + 0xf104);
mark = ((mark + 0x3) & ~0x3);
- printk(KERN_ERR PFX "begin fw dump (mark 0x%x)\n", mark);
+ pr_err("begin fw dump (mark 0x%x)\n", mark);
- printk(KERN_ERR PFX);
+ pr_err("");
for (offset = mark - 0x08000000; offset <= 0xF900; offset += 0x8*4) {
for (word = 0; word < 8; word++)
data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH +
offset + 4*word));
data[8] = 0x0;
- printk(KERN_CONT "%s", (char *)data);
+ pr_cont("%s", (char *)data);
}
for (offset = 0xF108; offset <= mark - 0x08000000; offset += 0x8*4) {
for (word = 0; word < 8; word++)
data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH +
offset + 4*word));
data[8] = 0x0;
- printk(KERN_CONT "%s", (char *)data);
+ pr_cont("%s", (char *)data);
}
- printk(KERN_ERR PFX "end of fw dump\n");
+ pr_err("end of fw dump\n");
}
static void bnx2x_panic_dump(struct bnx2x *bp)
@@ -957,21 +957,34 @@ static int bnx2x_tx_int(struct bnx2x_fastpath *fp)
fp->tx_pkt_cons = sw_cons;
fp->tx_bd_cons = bd_cons;
+ /* Need to make the tx_bd_cons update visible to start_xmit()
+ * before checking for netif_tx_queue_stopped(). Without the
+ * memory barrier, there is a small possibility that
+ * start_xmit() will miss it and cause the queue to be stopped
+ * forever.
+ */
+ smp_wmb();
+
/* TBD need a thresh? */
if (unlikely(netif_tx_queue_stopped(txq))) {
-
- /* Need to make the tx_bd_cons update visible to start_xmit()
- * before checking for netif_tx_queue_stopped(). Without the
- * memory barrier, there is a small possibility that
- * start_xmit() will miss it and cause the queue to be stopped
- * forever.
+ /* Taking tx_lock() is needed to prevent reenabling the queue
+ * while it's empty. This could have happen if rx_action() gets
+ * suspended in bnx2x_tx_int() after the condition before
+ * netif_tx_wake_queue(), while tx_action (bnx2x_start_xmit()):
+ *
+ * stops the queue->sees fresh tx_bd_cons->releases the queue->
+ * sends some packets consuming the whole queue again->
+ * stops the queue
*/
- smp_mb();
+
+ __netif_tx_lock(txq, smp_processor_id());
if ((netif_tx_queue_stopped(txq)) &&
(bp->state == BNX2X_STATE_OPEN) &&
(bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3))
netif_tx_wake_queue(txq);
+
+ __netif_tx_unlock(txq);
}
return 0;
}
@@ -2136,7 +2149,7 @@ static void bnx2x_link_report(struct bnx2x *bp)
{
if (bp->flags & MF_FUNC_DIS) {
netif_carrier_off(bp->dev);
- printk(KERN_ERR PFX "%s NIC Link is Down\n", bp->dev->name);
+ netdev_err(bp->dev, "NIC Link is Down\n");
return;
}
@@ -2145,7 +2158,7 @@ static void bnx2x_link_report(struct bnx2x *bp)
if (bp->state == BNX2X_STATE_OPEN)
netif_carrier_on(bp->dev);
- printk(KERN_INFO PFX "%s NIC Link is Up, ", bp->dev->name);
+ netdev_info(bp->dev, "NIC Link is Up, ");
line_speed = bp->link_vars.line_speed;
if (IS_E1HMF(bp)) {
@@ -2157,29 +2170,29 @@ static void bnx2x_link_report(struct bnx2x *bp)
if (vn_max_rate < line_speed)
line_speed = vn_max_rate;
}
- printk("%d Mbps ", line_speed);
+ pr_cont("%d Mbps ", line_speed);
if (bp->link_vars.duplex == DUPLEX_FULL)
- printk("full duplex");
+ pr_cont("full duplex");
else
- printk("half duplex");
+ pr_cont("half duplex");
if (bp->link_vars.flow_ctrl != BNX2X_FLOW_CTRL_NONE) {
if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) {
- printk(", receive ");
+ pr_cont(", receive ");
if (bp->link_vars.flow_ctrl &
BNX2X_FLOW_CTRL_TX)
- printk("& transmit ");
+ pr_cont("& transmit ");
} else {
- printk(", transmit ");
+ pr_cont(", transmit ");
}
- printk("flow control ON");
+ pr_cont("flow control ON");
}
- printk("\n");
+ pr_cont("\n");
} else { /* link_down */
netif_carrier_off(bp->dev);
- printk(KERN_ERR PFX "%s NIC Link is Down\n", bp->dev->name);
+ netdev_err(bp->dev, "NIC Link is Down\n");
}
}
@@ -2898,10 +2911,8 @@ static inline void bnx2x_fan_failure(struct bnx2x *bp)
bp->link_params.ext_phy_config);
/* log the failure */
- printk(KERN_ERR PFX "Fan Failure on Network Controller %s has caused"
- " the driver to shutdown the card to prevent permanent"
- " damage. Please contact Dell Support for assistance\n",
- bp->dev->name);
+ netdev_err(bp->dev, "Fan Failure on Network Controller has caused the driver to shutdown the card to prevent permanent damage.\n"
+ "Please contact Dell Support for assistance.\n");
}
static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
@@ -4296,7 +4307,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
bnx2x_net_stats_update(bp);
bnx2x_drv_stats_update(bp);
- if (bp->msglevel & NETIF_MSG_TIMER) {
+ if (netif_msg_timer(bp)) {
struct bnx2x_fastpath *fp0_rx = bp->fp;
struct bnx2x_fastpath *fp0_tx = bp->fp;
struct tstorm_per_client_stats *old_tclient =
@@ -4306,7 +4317,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
struct net_device_stats *nstats = &bp->dev->stats;
int i;
- printk(KERN_DEBUG "%s:\n", bp->dev->name);
+ netdev_printk(KERN_DEBUG, bp->dev, "\n");
printk(KERN_DEBUG " tx avail (%4x) tx hc idx (%x)"
" tx pkt (%lx)\n",
bnx2x_tx_avail(fp0_tx),
@@ -4464,7 +4475,7 @@ static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
/* Make sure the state has been "changed" */
smp_wmb();
- if ((event != STATS_EVENT_UPDATE) || (bp->msglevel & NETIF_MSG_TIMER))
+ if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
state, event, bp->stats_state);
}
@@ -5674,8 +5685,7 @@ gunzip_nomem2:
bp->gunzip_buf = NULL;
gunzip_nomem1:
- printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for"
- " un-compression\n", bp->dev->name);
+ netdev_err(bp->dev, "Cannot allocate firmware buffer for un-compression\n");
return -ENOMEM;
}
@@ -5721,14 +5731,13 @@ static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len)
rc = zlib_inflate(bp->strm, Z_FINISH);
if ((rc != Z_OK) && (rc != Z_STREAM_END))
- printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n",
- bp->dev->name, bp->strm->msg);
+ netdev_err(bp->dev, "Firmware decompression error: %s\n",
+ bp->strm->msg);
bp->gunzip_outlen = (FW_BUF_SIZE - bp->strm->avail_out);
if (bp->gunzip_outlen & 0x3)
- printk(KERN_ERR PFX "%s: Firmware decompression error:"
- " gunzip_outlen (%d) not aligned\n",
- bp->dev->name, bp->gunzip_outlen);
+ netdev_err(bp->dev, "Firmware decompression error: gunzip_outlen (%d) not aligned\n",
+ bp->gunzip_outlen);
bp->gunzip_outlen >>= 2;
zlib_inflateEnd(bp->strm);
@@ -6213,8 +6222,8 @@ static int bnx2x_init_common(struct bnx2x *bp)
if (sizeof(union cdu_context) != 1024)
/* we currently assume that a context is 1024 bytes */
- printk(KERN_ALERT PFX "please adjust the size of"
- " cdu_context(%ld)\n", (long)sizeof(union cdu_context));
+ pr_alert("please adjust the size of cdu_context(%ld)\n",
+ (long)sizeof(union cdu_context));
bnx2x_init_block(bp, CDU_BLOCK, COMMON_STAGE);
val = (4 << 24) + (0 << 12) + 1024;
@@ -6938,19 +6947,21 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp)
}
}
-static void bnx2x_free_irq(struct bnx2x *bp)
+static void bnx2x_free_irq(struct bnx2x *bp, bool disable_only)
{
if (bp->flags & USING_MSIX_FLAG) {
- bnx2x_free_msix_irqs(bp);
+ if (!disable_only)
+ bnx2x_free_msix_irqs(bp);
pci_disable_msix(bp->pdev);
bp->flags &= ~USING_MSIX_FLAG;
} else if (bp->flags & USING_MSI_FLAG) {
- free_irq(bp->pdev->irq, bp->dev);
+ if (!disable_only)
+ free_irq(bp->pdev->irq, bp->dev);
pci_disable_msi(bp->pdev);
bp->flags &= ~USING_MSI_FLAG;
- } else
+ } else if (!disable_only)
free_irq(bp->pdev->irq, bp->dev);
}
@@ -7018,11 +7029,10 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
}
i = BNX2X_NUM_QUEUES(bp);
- printk(KERN_INFO PFX "%s: using MSI-X IRQs: sp %d fp[%d] %d"
- " ... fp[%d] %d\n",
- bp->dev->name, bp->msix_table[0].vector,
- 0, bp->msix_table[offset].vector,
- i - 1, bp->msix_table[offset + i - 1].vector);
+ netdev_info(bp->dev, "using MSI-X IRQs: sp %d fp[%d] %d ... fp[%d] %d\n",
+ bp->msix_table[0].vector,
+ 0, bp->msix_table[offset].vector,
+ i - 1, bp->msix_table[offset + i - 1].vector);
return 0;
}
@@ -7443,8 +7453,10 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
rc = bnx2x_set_num_queues(bp);
- if (bnx2x_alloc_mem(bp))
+ if (bnx2x_alloc_mem(bp)) {
+ bnx2x_free_irq(bp, true);
return -ENOMEM;
+ }
for_each_queue(bp, i)
bnx2x_fp(bp, i, disable_tpa) =
@@ -7459,7 +7471,7 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
if (bp->flags & USING_MSIX_FLAG) {
rc = bnx2x_req_msix_irqs(bp);
if (rc) {
- pci_disable_msix(bp->pdev);
+ bnx2x_free_irq(bp, true);
goto load_error1;
}
} else {
@@ -7471,14 +7483,13 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
rc = bnx2x_req_irq(bp);
if (rc) {
BNX2X_ERR("IRQ request failed rc %d, aborting\n", rc);
- if (bp->flags & USING_MSI_FLAG)
- pci_disable_msi(bp->pdev);
+ bnx2x_free_irq(bp, true);
goto load_error1;
}
if (bp->flags & USING_MSI_FLAG) {
bp->dev->irq = bp->pdev->irq;
- printk(KERN_INFO PFX "%s: using MSI IRQ %d\n",
- bp->dev->name, bp->pdev->irq);
+ netdev_info(bp->dev, "using MSI IRQ %d\n",
+ bp->pdev->irq);
}
}
@@ -7527,6 +7538,9 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
rc = bnx2x_init_hw(bp, load_code);
if (rc) {
BNX2X_ERR("HW init failed, aborting\n");
+ bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
+ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
+ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
goto load_error2;
}
@@ -7664,7 +7678,7 @@ load_error3:
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
load_error2:
/* Release IRQs */
- bnx2x_free_irq(bp);
+ bnx2x_free_irq(bp, false);
load_error1:
bnx2x_napi_disable(bp);
for_each_queue(bp, i)
@@ -7855,7 +7869,7 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
/* Release IRQs */
- bnx2x_free_irq(bp);
+ bnx2x_free_irq(bp, false);
/* Wait until tx fastpath tasks complete */
for_each_queue(bp, i) {
@@ -8297,8 +8311,7 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
val3 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[8]);
val4 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[12]);
- printk(KERN_INFO PFX "part number %X-%X-%X-%X\n",
- val, val2, val3, val4);
+ pr_info("part number %X-%X-%X-%X\n", val, val2, val3, val4);
}
static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
@@ -8909,17 +8922,15 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
bnx2x_undi_unload(bp);
if (CHIP_REV_IS_FPGA(bp))
- printk(KERN_ERR PFX "FPGA detected\n");
+ pr_err("FPGA detected\n");
if (BP_NOMCP(bp) && (func == 0))
- printk(KERN_ERR PFX
- "MCP disabled, must load devices in order!\n");
+ pr_err("MCP disabled, must load devices in order!\n");
/* Set multi queue mode */
if ((multi_mode != ETH_RSS_MODE_DISABLED) &&
((int_mode == INT_MODE_INTx) || (int_mode == INT_MODE_MSI))) {
- printk(KERN_ERR PFX
- "Multi disabled since int_mode requested is not MSI-X\n");
+ pr_err("Multi disabled since int_mode requested is not MSI-X\n");
multi_mode = ETH_RSS_MODE_DISABLED;
}
bp->multi_mode = multi_mode;
@@ -9345,7 +9356,7 @@ static u32 bnx2x_get_msglevel(struct net_device *dev)
{
struct bnx2x *bp = netdev_priv(dev);
- return bp->msglevel;
+ return bp->msg_enable;
}
static void bnx2x_set_msglevel(struct net_device *dev, u32 level)
@@ -9353,7 +9364,7 @@ static void bnx2x_set_msglevel(struct net_device *dev, u32 level)
struct bnx2x *bp = netdev_priv(dev);
if (capable(CAP_NET_ADMIN))
- bp->msglevel = level;
+ bp->msg_enable = level;
}
static int bnx2x_nway_reset(struct net_device *dev)
@@ -9962,12 +9973,14 @@ static int bnx2x_set_flags(struct net_device *dev, u32 data)
/* TPA requires Rx CSUM offloading */
if ((data & ETH_FLAG_LRO) && bp->rx_csum) {
- if (!(dev->features & NETIF_F_LRO)) {
- dev->features |= NETIF_F_LRO;
- bp->flags |= TPA_ENABLE_FLAG;
- changed = 1;
- }
-
+ if (!disable_tpa) {
+ if (!(dev->features & NETIF_F_LRO)) {
+ dev->features |= NETIF_F_LRO;
+ bp->flags |= TPA_ENABLE_FLAG;
+ changed = 1;
+ }
+ } else
+ rc = -EINVAL;
} else if (dev->features & NETIF_F_LRO) {
dev->features &= ~NETIF_F_LRO;
bp->flags &= ~TPA_ENABLE_FLAG;
@@ -10425,7 +10438,8 @@ static int bnx2x_test_intr(struct bnx2x *bp)
config->hdr.length = 0;
if (CHIP_IS_E1(bp))
- config->hdr.offset = (BP_PORT(bp) ? 32 : 0);
+ /* use last unicast entries */
+ config->hdr.offset = (BP_PORT(bp) ? 63 : 31);
else
config->hdr.offset = BP_FUNC(bp);
config->hdr.client_id = bp->fp->cl_id;
@@ -10644,7 +10658,7 @@ static const struct {
((bnx2x_stats_arr[i].flags & STATS_FLAGS_BOTH) == STATS_FLAGS_PORT)
#define IS_FUNC_STAT(i) (bnx2x_stats_arr[i].flags & STATS_FLAGS_FUNC)
#define IS_E1HMF_MODE_STAT(bp) \
- (IS_E1HMF(bp) && !(bp->msglevel & BNX2X_MSG_STATS))
+ (IS_E1HMF(bp) && !(bp->msg_enable & BNX2X_MSG_STATS))
static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
{
@@ -11471,7 +11485,8 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
rx_mode = BNX2X_RX_MODE_PROMISC;
else if ((dev->flags & IFF_ALLMULTI) ||
- ((dev->mc_count > BNX2X_MAX_MULTICAST) && CHIP_IS_E1(bp)))
+ ((netdev_mc_count(dev) > BNX2X_MAX_MULTICAST) &&
+ CHIP_IS_E1(bp)))
rx_mode = BNX2X_RX_MODE_ALLMULTI;
else { /* some multicasts */
@@ -11481,10 +11496,8 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
struct mac_configuration_cmd *config =
bnx2x_sp(bp, mcast_config);
- for (i = 0, mclist = dev->mc_list;
- mclist && (i < dev->mc_count);
- i++, mclist = mclist->next) {
-
+ i = 0;
+ netdev_for_each_mc_addr(mclist, dev) {
config->config_table[i].
cam_entry.msb_mac_addr =
swab16(*(u16 *)&mclist->dmi_addr[0]);
@@ -11512,6 +11525,7 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
cam_entry.middle_mac_addr,
config->config_table[i].
cam_entry.lsb_mac_addr);
+ i++;
}
old = config->hdr.length;
if (old > i) {
@@ -11553,10 +11567,7 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
memset(mc_filter, 0, 4 * MC_HASH_SIZE);
- for (i = 0, mclist = dev->mc_list;
- mclist && (i < dev->mc_count);
- i++, mclist = mclist->next) {
-
+ netdev_for_each_mc_addr(mclist, dev) {
DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n",
mclist->dmi_addr);
@@ -11731,7 +11742,7 @@ static void bnx2x_vlan_rx_register(struct net_device *dev,
#endif
-#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+#ifdef CONFIG_NET_POLL_CONTROLLER
static void poll_bnx2x(struct net_device *dev)
{
struct bnx2x *bp = netdev_priv(dev);
@@ -11755,7 +11766,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
#ifdef BCM_VLAN
.ndo_vlan_rx_register = bnx2x_vlan_rx_register,
#endif
-#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = poll_bnx2x,
#endif
};
@@ -11776,20 +11787,18 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
rc = pci_enable_device(pdev);
if (rc) {
- printk(KERN_ERR PFX "Cannot enable PCI device, aborting\n");
+ pr_err("Cannot enable PCI device, aborting\n");
goto err_out;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- printk(KERN_ERR PFX "Cannot find PCI device base address,"
- " aborting\n");
+ pr_err("Cannot find PCI device base address, aborting\n");
rc = -ENODEV;
goto err_out_disable;
}
if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
- printk(KERN_ERR PFX "Cannot find second PCI device"
- " base address, aborting\n");
+ pr_err("Cannot find second PCI device base address, aborting\n");
rc = -ENODEV;
goto err_out_disable;
}
@@ -11797,8 +11806,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
if (atomic_read(&pdev->enable_cnt) == 1) {
rc = pci_request_regions(pdev, DRV_MODULE_NAME);
if (rc) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources,"
- " aborting\n");
+ pr_err("Cannot obtain PCI resources, aborting\n");
goto err_out_disable;
}
@@ -11808,16 +11816,14 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
if (bp->pm_cap == 0) {
- printk(KERN_ERR PFX "Cannot find power management"
- " capability, aborting\n");
+ pr_err("Cannot find power management capability, aborting\n");
rc = -EIO;
goto err_out_release;
}
bp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
if (bp->pcie_cap == 0) {
- printk(KERN_ERR PFX "Cannot find PCI Express capability,"
- " aborting\n");
+ pr_err("Cannot find PCI Express capability, aborting\n");
rc = -EIO;
goto err_out_release;
}
@@ -11825,15 +11831,13 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
bp->flags |= USING_DAC_FLAG;
if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
- printk(KERN_ERR PFX "pci_set_consistent_dma_mask"
- " failed, aborting\n");
+ pr_err("pci_set_consistent_dma_mask failed, aborting\n");
rc = -EIO;
goto err_out_release;
}
} else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
- printk(KERN_ERR PFX "System does not support DMA,"
- " aborting\n");
+ pr_err("System does not support DMA, aborting\n");
rc = -EIO;
goto err_out_release;
}
@@ -11846,7 +11850,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
bp->regview = pci_ioremap_bar(pdev, 0);
if (!bp->regview) {
- printk(KERN_ERR PFX "Cannot map register space, aborting\n");
+ pr_err("Cannot map register space, aborting\n");
rc = -ENOMEM;
goto err_out_release;
}
@@ -11855,7 +11859,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
min_t(u64, BNX2X_DB_SIZE,
pci_resource_len(pdev, 2)));
if (!bp->doorbells) {
- printk(KERN_ERR PFX "Cannot map doorbell space, aborting\n");
+ pr_err("Cannot map doorbell space, aborting\n");
rc = -ENOMEM;
goto err_out_unmap;
}
@@ -11957,8 +11961,7 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
offset = be32_to_cpu(sections[i].offset);
len = be32_to_cpu(sections[i].len);
if (offset + len > firmware->size) {
- printk(KERN_ERR PFX "Section %d length is out of "
- "bounds\n", i);
+ pr_err("Section %d length is out of bounds\n", i);
return -EINVAL;
}
}
@@ -11970,8 +11973,7 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
for (i = 0; i < be32_to_cpu(fw_hdr->init_ops_offsets.len) / 2; i++) {
if (be16_to_cpu(ops_offsets[i]) > num_ops) {
- printk(KERN_ERR PFX "Section offset %d is out of "
- "bounds\n", i);
+ pr_err("Section offset %d is out of bounds\n", i);
return -EINVAL;
}
}
@@ -11983,8 +11985,7 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
(fw_ver[1] != BCM_5710_FW_MINOR_VERSION) ||
(fw_ver[2] != BCM_5710_FW_REVISION_VERSION) ||
(fw_ver[3] != BCM_5710_FW_ENGINEERING_VERSION)) {
- printk(KERN_ERR PFX "Bad FW version:%d.%d.%d.%d."
- " Should be %d.%d.%d.%d\n",
+ pr_err("Bad FW version:%d.%d.%d.%d. Should be %d.%d.%d.%d\n",
fw_ver[0], fw_ver[1], fw_ver[2],
fw_ver[3], BCM_5710_FW_MAJOR_VERSION,
BCM_5710_FW_MINOR_VERSION,
@@ -12034,18 +12035,17 @@ static inline void be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n)
target[i] = be16_to_cpu(source[i]);
}
-#define BNX2X_ALLOC_AND_SET(arr, lbl, func) \
- do { \
- u32 len = be32_to_cpu(fw_hdr->arr.len); \
- bp->arr = kmalloc(len, GFP_KERNEL); \
- if (!bp->arr) { \
- printk(KERN_ERR PFX "Failed to allocate %d bytes " \
- "for "#arr"\n", len); \
- goto lbl; \
- } \
- func(bp->firmware->data + be32_to_cpu(fw_hdr->arr.offset), \
- (u8 *)bp->arr, len); \
- } while (0)
+#define BNX2X_ALLOC_AND_SET(arr, lbl, func) \
+do { \
+ u32 len = be32_to_cpu(fw_hdr->arr.len); \
+ bp->arr = kmalloc(len, GFP_KERNEL); \
+ if (!bp->arr) { \
+ pr_err("Failed to allocate %d bytes for "#arr"\n", len); \
+ goto lbl; \
+ } \
+ func(bp->firmware->data + be32_to_cpu(fw_hdr->arr.offset), \
+ (u8 *)bp->arr, len); \
+} while (0)
static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev)
{
@@ -12058,18 +12058,17 @@ static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev)
else
fw_file_name = FW_FILE_NAME_E1H;
- printk(KERN_INFO PFX "Loading %s\n", fw_file_name);
+ pr_info("Loading %s\n", fw_file_name);
rc = request_firmware(&bp->firmware, fw_file_name, dev);
if (rc) {
- printk(KERN_ERR PFX "Can't load firmware file %s\n",
- fw_file_name);
+ pr_err("Can't load firmware file %s\n", fw_file_name);
goto request_firmware_exit;
}
rc = bnx2x_check_firmware(bp);
if (rc) {
- printk(KERN_ERR PFX "Corrupt firmware file %s\n", fw_file_name);
+ pr_err("Corrupt firmware file %s\n", fw_file_name);
goto request_firmware_exit;
}
@@ -12128,12 +12127,12 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
/* dev zeroed in init_etherdev */
dev = alloc_etherdev_mq(sizeof(*bp), MAX_CONTEXT);
if (!dev) {
- printk(KERN_ERR PFX "Cannot allocate net device\n");
+ pr_err("Cannot allocate net device\n");
return -ENOMEM;
}
bp = netdev_priv(dev);
- bp->msglevel = debug;
+ bp->msg_enable = debug;
pci_set_drvdata(pdev, dev);
@@ -12150,7 +12149,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
/* Set init arrays */
rc = bnx2x_init_firmware(bp, &pdev->dev);
if (rc) {
- printk(KERN_ERR PFX "Error loading firmware\n");
+ pr_err("Error loading firmware\n");
goto init_one_exit;
}
@@ -12161,12 +12160,11 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
}
bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed);
- printk(KERN_INFO "%s: %s (%c%d) PCI-E x%d %s found at mem %lx,"
- " IRQ %d, ", dev->name, board_info[ent->driver_data].name,
- (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4),
- pcie_width, (pcie_speed == 2) ? "5GHz (Gen2)" : "2.5GHz",
- dev->base_addr, bp->pdev->irq);
- printk(KERN_CONT "node addr %pM\n", dev->dev_addr);
+ netdev_info(dev, "%s (%c%d) PCI-E x%d %s found at mem %lx, IRQ %d, node addr %pM\n",
+ board_info[ent->driver_data].name,
+ (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4),
+ pcie_width, (pcie_speed == 2) ? "5GHz (Gen2)" : "2.5GHz",
+ dev->base_addr, bp->pdev->irq, dev->dev_addr);
return 0;
@@ -12194,7 +12192,7 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
struct bnx2x *bp;
if (!dev) {
- printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n");
+ pr_err("BAD net device from bnx2x_init_one\n");
return;
}
bp = netdev_priv(dev);
@@ -12227,7 +12225,7 @@ static int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state)
struct bnx2x *bp;
if (!dev) {
- printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n");
+ pr_err("BAD net device from bnx2x_init_one\n");
return -ENODEV;
}
bp = netdev_priv(dev);
@@ -12259,7 +12257,7 @@ static int bnx2x_resume(struct pci_dev *pdev)
int rc;
if (!dev) {
- printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n");
+ pr_err("BAD net device from bnx2x_init_one\n");
return -ENODEV;
}
bp = netdev_priv(dev);
@@ -12298,7 +12296,7 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");
/* Release IRQs */
- bnx2x_free_irq(bp);
+ bnx2x_free_irq(bp, false);
if (CHIP_IS_E1(bp)) {
struct mac_configuration_cmd *config =
@@ -12462,17 +12460,17 @@ static int __init bnx2x_init(void)
{
int ret;
- printk(KERN_INFO "%s", version);
+ pr_info("%s", version);
bnx2x_wq = create_singlethread_workqueue("bnx2x");
if (bnx2x_wq == NULL) {
- printk(KERN_ERR PFX "Cannot create workqueue\n");
+ pr_err("Cannot create workqueue\n");
return -ENOMEM;
}
ret = pci_register_driver(&bnx2x_pci_driver);
if (ret) {
- printk(KERN_ERR PFX "Cannot register driver\n");
+ pr_err("Cannot register driver\n");
destroy_workqueue(bnx2x_wq);
}
return ret;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 3f0071cfe56b..430c02267d7e 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2615,6 +2615,17 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
unsigned char *arp_ptr;
__be32 sip, tip;
+ if (dev->priv_flags & IFF_802_1Q_VLAN) {
+ /*
+ * When using VLANS and bonding, dev and oriv_dev may be
+ * incorrect if the physical interface supports VLAN
+ * acceleration. With this change ARP validation now
+ * works for hosts only reachable on the VLAN interface.
+ */
+ dev = vlan_dev_real_dev(dev);
+ orig_dev = dev_get_by_index_rcu(dev_net(skb->dev),skb->skb_iif);
+ }
+
if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
goto out;
@@ -3296,7 +3307,7 @@ static void bond_remove_proc_entry(struct bonding *bond)
/* Create the bonding directory under /proc/net, if doesn't exist yet.
* Caller must hold rtnl_lock.
*/
-static void bond_create_proc_dir(struct bond_net *bn)
+static void __net_init bond_create_proc_dir(struct bond_net *bn)
{
if (!bn->proc_dir) {
bn->proc_dir = proc_mkdir(DRV_NAME, bn->net->proc_net);
@@ -3309,7 +3320,7 @@ static void bond_create_proc_dir(struct bond_net *bn)
/* Destroy the bonding directory under /proc/net, if empty.
* Caller must hold rtnl_lock.
*/
-static void bond_destroy_proc_dir(struct bond_net *bn)
+static void __net_exit bond_destroy_proc_dir(struct bond_net *bn)
{
if (bn->proc_dir) {
remove_proc_entry(DRV_NAME, bn->net->proc_net);
@@ -3327,11 +3338,11 @@ static void bond_remove_proc_entry(struct bonding *bond)
{
}
-static void bond_create_proc_dir(struct bond_net *bn)
+static inline void bond_create_proc_dir(struct bond_net *bn)
{
}
-static void bond_destroy_proc_dir(struct bond_net *bn)
+static inline void bond_destroy_proc_dir(struct bond_net *bn)
{
}
@@ -3639,7 +3650,7 @@ static int bond_open(struct net_device *bond_dev)
*/
if (bond_alb_initialize(bond, (bond->params.mode == BOND_MODE_ALB))) {
/* something went wrong - fail the open operation */
- return -1;
+ return -ENOMEM;
}
INIT_DELAYED_WORK(&bond->alb_work, bond_alb_monitor);
@@ -3731,7 +3742,7 @@ static int bond_close(struct net_device *bond_dev)
static struct net_device_stats *bond_get_stats(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct net_device_stats *stats = &bond->stats;
+ struct net_device_stats *stats = &bond_dev->stats;
struct net_device_stats local_stats;
struct slave *slave;
int i;
@@ -4935,6 +4946,8 @@ int bond_create(struct net *net, const char *name)
}
res = register_netdevice(bond_dev);
+ if (res < 0)
+ goto out_netdev;
out:
rtnl_unlock();
@@ -4944,7 +4957,7 @@ out_netdev:
goto out;
}
-static int bond_net_init(struct net *net)
+static int __net_init bond_net_init(struct net *net)
{
struct bond_net *bn = net_generic(net, bond_net_id);
@@ -4956,7 +4969,7 @@ static int bond_net_init(struct net *net)
return 0;
}
-static void bond_net_exit(struct net *net)
+static void __net_exit bond_net_exit(struct net *net)
{
struct bond_net *bn = net_generic(net, bond_net_id);
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 5acd557cea9b..b8bec086daa1 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -51,7 +51,9 @@
* "show" function for the bond_masters attribute.
* The class parameter is ignored.
*/
-static ssize_t bonding_show_bonds(struct class *cls, char *buf)
+static ssize_t bonding_show_bonds(struct class *cls,
+ struct class_attribute *attr,
+ char *buf)
{
struct net *net = current->nsproxy->net_ns;
struct bond_net *bn = net_generic(net, bond_net_id);
@@ -98,6 +100,7 @@ static struct net_device *bond_get_by_name(struct net *net, const char *ifname)
*/
static ssize_t bonding_store_bonds(struct class *cls,
+ struct class_attribute *attr,
const char *buffer, size_t count)
{
struct net *net = current->nsproxy->net_ns;
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 558ec1352527..257a7a4dfce9 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -197,7 +197,6 @@ struct bonding {
s8 send_grat_arp;
s8 send_unsol_na;
s8 setup_by_slave;
- struct net_device_stats stats;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_entry;
char proc_file_name[IFNAMSIZ];
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index 166cc7e579c0..a2f29a38798a 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -342,6 +342,9 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned int mb, prio;
u32 reg_mid, reg_mcr;
+ if (can_dropped_invalid_skb(dev, skb))
+ return NETDEV_TX_OK;
+
mb = get_tx_next_mb(priv);
prio = get_tx_next_prio(priv);
@@ -1070,6 +1073,7 @@ static int __init at91_can_probe(struct platform_device *pdev)
priv->can.bittiming_const = &at91_bittiming_const;
priv->can.do_set_bittiming = at91_set_bittiming;
priv->can.do_set_mode = at91_set_mode;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
priv->reg_base = addr;
priv->dev = dev;
priv->clk = clk;
diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c
index 0ec1524523cc..866905fa4119 100644
--- a/drivers/net/can/bfin_can.c
+++ b/drivers/net/can/bfin_can.c
@@ -26,6 +26,7 @@
#define DRV_NAME "bfin_can"
#define BFIN_CAN_TIMEOUT 100
+#define TX_ECHO_SKB_MAX 1
/*
* transmit and receive channels
@@ -318,6 +319,9 @@ static int bfin_can_start_xmit(struct sk_buff *skb, struct net_device *dev)
u16 val;
int i;
+ if (can_dropped_invalid_skb(dev, skb))
+ return NETDEV_TX_OK;
+
netif_stop_queue(dev);
/* fill id */
@@ -590,7 +594,7 @@ struct net_device *alloc_bfin_candev(void)
struct net_device *dev;
struct bfin_can_priv *priv;
- dev = alloc_candev(sizeof(*priv));
+ dev = alloc_candev(sizeof(*priv), TX_ECHO_SKB_MAX);
if (!dev)
return NULL;
@@ -600,6 +604,7 @@ struct net_device *alloc_bfin_candev(void)
priv->can.bittiming_const = &bfin_can_bittiming_const;
priv->can.do_set_bittiming = bfin_can_set_bittiming;
priv->can.do_set_mode = bfin_can_set_mode;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
return dev;
}
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index c1bb29f0322b..904aa369f80e 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -574,6 +574,7 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
[IFLA_CAN_BITTIMING_CONST]
= { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) },
+ [IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
};
static int can_changelink(struct net_device *dev,
@@ -592,6 +593,8 @@ static int can_changelink(struct net_device *dev,
if (dev->flags & IFF_UP)
return -EBUSY;
cm = nla_data(data[IFLA_CAN_CTRLMODE]);
+ if (cm->flags & ~priv->ctrlmode_supported)
+ return -EOPNOTSUPP;
priv->ctrlmode &= ~cm->mask;
priv->ctrlmode |= cm->flags;
}
@@ -647,6 +650,8 @@ static size_t can_get_size(const struct net_device *dev)
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */
size += sizeof(struct can_bittiming); /* IFLA_CAN_BITTIMING */
size += sizeof(struct can_clock); /* IFLA_CAN_CLOCK */
+ if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */
+ size += sizeof(struct can_berr_counter);
if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */
size += sizeof(struct can_bittiming_const);
@@ -657,6 +662,7 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
struct can_ctrlmode cm = {.flags = priv->ctrlmode};
+ struct can_berr_counter bec;
enum can_state state = priv->state;
if (priv->do_get_state)
@@ -667,6 +673,8 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
NLA_PUT(skb, IFLA_CAN_BITTIMING,
sizeof(priv->bittiming), &priv->bittiming);
NLA_PUT(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock);
+ if (priv->do_get_berr_counter && !priv->do_get_berr_counter(dev, &bec))
+ NLA_PUT(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec);
if (priv->bittiming_const)
NLA_PUT(skb, IFLA_CAN_BITTIMING_CONST,
sizeof(*priv->bittiming_const), priv->bittiming_const);
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
index 1a72ca066a17..f8cc168ec76c 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/mcp251x.c
@@ -180,6 +180,14 @@
#define RXBEID0_OFF 4
#define RXBDLC_OFF 5
#define RXBDAT_OFF 6
+#define RXFSIDH(n) ((n) * 4)
+#define RXFSIDL(n) ((n) * 4 + 1)
+#define RXFEID8(n) ((n) * 4 + 2)
+#define RXFEID0(n) ((n) * 4 + 3)
+#define RXMSIDH(n) ((n) * 4 + 0x20)
+#define RXMSIDL(n) ((n) * 4 + 0x21)
+#define RXMEID8(n) ((n) * 4 + 0x22)
+#define RXMEID0(n) ((n) * 4 + 0x23)
#define GET_BYTE(val, byte) \
(((val) >> ((byte) * 8)) & 0xff)
@@ -219,7 +227,8 @@ struct mcp251x_priv {
struct net_device *net;
struct spi_device *spi;
- struct mutex spi_lock; /* SPI buffer lock */
+ struct mutex mcp_lock; /* SPI device lock */
+
u8 *spi_tx_buf;
u8 *spi_rx_buf;
dma_addr_t spi_tx_dma;
@@ -227,11 +236,11 @@ struct mcp251x_priv {
struct sk_buff *tx_skb;
int tx_len;
+
struct workqueue_struct *wq;
struct work_struct tx_work;
- struct work_struct irq_work;
- struct completion awake;
- int wake;
+ struct work_struct restart_work;
+
int force_quit;
int after_suspend;
#define AFTER_SUSPEND_UP 1
@@ -245,7 +254,8 @@ static void mcp251x_clean(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
- net->stats.tx_errors++;
+ if (priv->tx_skb || priv->tx_len)
+ net->stats.tx_errors++;
if (priv->tx_skb)
dev_kfree_skb(priv->tx_skb);
if (priv->tx_len)
@@ -300,16 +310,12 @@ static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
u8 val = 0;
- mutex_lock(&priv->spi_lock);
-
priv->spi_tx_buf[0] = INSTRUCTION_READ;
priv->spi_tx_buf[1] = reg;
mcp251x_spi_trans(spi, 3);
val = priv->spi_rx_buf[2];
- mutex_unlock(&priv->spi_lock);
-
return val;
}
@@ -317,15 +323,11 @@ static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
- mutex_lock(&priv->spi_lock);
-
priv->spi_tx_buf[0] = INSTRUCTION_WRITE;
priv->spi_tx_buf[1] = reg;
priv->spi_tx_buf[2] = val;
mcp251x_spi_trans(spi, 3);
-
- mutex_unlock(&priv->spi_lock);
}
static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
@@ -333,16 +335,12 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
- mutex_lock(&priv->spi_lock);
-
priv->spi_tx_buf[0] = INSTRUCTION_BIT_MODIFY;
priv->spi_tx_buf[1] = reg;
priv->spi_tx_buf[2] = mask;
priv->spi_tx_buf[3] = val;
mcp251x_spi_trans(spi, 4);
-
- mutex_unlock(&priv->spi_lock);
}
static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
@@ -358,10 +356,8 @@ static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + i,
buf[i]);
} else {
- mutex_lock(&priv->spi_lock);
memcpy(priv->spi_tx_buf, buf, TXBDAT_OFF + len);
mcp251x_spi_trans(spi, TXBDAT_OFF + len);
- mutex_unlock(&priv->spi_lock);
}
}
@@ -408,13 +404,9 @@ static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,
for (; i < (RXBDAT_OFF + len); i++)
buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);
} else {
- mutex_lock(&priv->spi_lock);
-
priv->spi_tx_buf[RXBCTRL_OFF] = INSTRUCTION_READ_RXB(buf_idx);
mcp251x_spi_trans(spi, SPI_TRANSFER_BUF_LEN);
memcpy(buf, priv->spi_rx_buf, SPI_TRANSFER_BUF_LEN);
-
- mutex_unlock(&priv->spi_lock);
}
}
@@ -467,21 +459,6 @@ static void mcp251x_hw_sleep(struct spi_device *spi)
mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP);
}
-static void mcp251x_hw_wakeup(struct spi_device *spi)
-{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-
- priv->wake = 1;
-
- /* Can only wake up by generating a wake-up interrupt. */
- mcp251x_write_bits(spi, CANINTE, CANINTE_WAKIE, CANINTE_WAKIE);
- mcp251x_write_bits(spi, CANINTF, CANINTF_WAKIF, CANINTF_WAKIF);
-
- /* Wait until the device is awake */
- if (!wait_for_completion_timeout(&priv->awake, HZ))
- dev_err(&spi->dev, "MCP251x didn't wake-up\n");
-}
-
static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
struct net_device *net)
{
@@ -490,16 +467,11 @@ static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
if (priv->tx_skb || priv->tx_len) {
dev_warn(&spi->dev, "hard_xmit called while tx busy\n");
- netif_stop_queue(net);
return NETDEV_TX_BUSY;
}
- if (skb->len != sizeof(struct can_frame)) {
- dev_err(&spi->dev, "dropping packet - bad length\n");
- dev_kfree_skb(skb);
- net->stats.tx_dropped++;
+ if (can_dropped_invalid_skb(net, skb))
return NETDEV_TX_OK;
- }
netif_stop_queue(net);
priv->tx_skb = skb;
@@ -515,12 +487,13 @@ static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode)
switch (mode) {
case CAN_MODE_START:
+ mcp251x_clean(net);
/* We have to delay work since SPI I/O may sleep */
priv->can.state = CAN_STATE_ERROR_ACTIVE;
priv->restart_tx = 1;
if (priv->can.restart_ms == 0)
priv->after_suspend = AFTER_SUSPEND_RESTART;
- queue_work(priv->wq, &priv->irq_work);
+ queue_work(priv->wq, &priv->restart_work);
break;
default:
return -EOPNOTSUPP;
@@ -529,7 +502,7 @@ static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode)
return 0;
}
-static void mcp251x_set_normal_mode(struct spi_device *spi)
+static int mcp251x_set_normal_mode(struct spi_device *spi)
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
unsigned long timeout;
@@ -537,12 +510,14 @@ static void mcp251x_set_normal_mode(struct spi_device *spi)
/* Enable interrupts */
mcp251x_write_reg(spi, CANINTE,
CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE |
- CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE |
- CANINTF_MERRF);
+ CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE);
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
/* Put device into loopback mode */
mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LOOPBACK);
+ } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
+ /* Put device into listen-only mode */
+ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LISTEN_ONLY);
} else {
/* Put device into normal mode */
mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL);
@@ -554,11 +529,12 @@ static void mcp251x_set_normal_mode(struct spi_device *spi)
if (time_after(jiffies, timeout)) {
dev_err(&spi->dev, "MCP251x didn't"
" enter in normal mode\n");
- return;
+ return -EBUSY;
}
}
}
priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ return 0;
}
static int mcp251x_do_set_bittiming(struct net_device *net)
@@ -589,33 +565,39 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
{
mcp251x_do_set_bittiming(net);
- /* Enable RX0->RX1 buffer roll over and disable filters */
- mcp251x_write_bits(spi, RXBCTRL(0),
- RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1,
- RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1);
- mcp251x_write_bits(spi, RXBCTRL(1),
- RXBCTRL_RXM0 | RXBCTRL_RXM1,
- RXBCTRL_RXM0 | RXBCTRL_RXM1);
+ mcp251x_write_reg(spi, RXBCTRL(0),
+ RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1);
+ mcp251x_write_reg(spi, RXBCTRL(1),
+ RXBCTRL_RXM0 | RXBCTRL_RXM1);
return 0;
}
-static void mcp251x_hw_reset(struct spi_device *spi)
+static int mcp251x_hw_reset(struct spi_device *spi)
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
int ret;
-
- mutex_lock(&priv->spi_lock);
+ unsigned long timeout;
priv->spi_tx_buf[0] = INSTRUCTION_RESET;
-
ret = spi_write(spi, priv->spi_tx_buf, 1);
-
- mutex_unlock(&priv->spi_lock);
-
- if (ret)
+ if (ret) {
dev_err(&spi->dev, "reset failed: ret = %d\n", ret);
+ return -EIO;
+ }
+
/* Wait for reset to finish */
+ timeout = jiffies + HZ;
mdelay(10);
+ while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK)
+ != CANCTRL_REQOP_CONF) {
+ schedule();
+ if (time_after(jiffies, timeout)) {
+ dev_err(&spi->dev, "MCP251x didn't"
+ " enter in conf mode after reset\n");
+ return -EBUSY;
+ }
+ }
+ return 0;
}
static int mcp251x_hw_probe(struct spi_device *spi)
@@ -639,63 +621,17 @@ static int mcp251x_hw_probe(struct spi_device *spi)
return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;
}
-static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
-{
- struct net_device *net = (struct net_device *)dev_id;
- struct mcp251x_priv *priv = netdev_priv(net);
-
- /* Schedule bottom half */
- if (!work_pending(&priv->irq_work))
- queue_work(priv->wq, &priv->irq_work);
-
- return IRQ_HANDLED;
-}
-
-static int mcp251x_open(struct net_device *net)
+static void mcp251x_open_clean(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
struct spi_device *spi = priv->spi;
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- int ret;
-
- ret = open_candev(net);
- if (ret) {
- dev_err(&spi->dev, "unable to set initial baudrate!\n");
- return ret;
- }
+ free_irq(spi->irq, priv);
+ mcp251x_hw_sleep(spi);
if (pdata->transceiver_enable)
- pdata->transceiver_enable(1);
-
- priv->force_quit = 0;
- priv->tx_skb = NULL;
- priv->tx_len = 0;
-
- ret = request_irq(spi->irq, mcp251x_can_isr,
- IRQF_TRIGGER_FALLING, DEVICE_NAME, net);
- if (ret) {
- dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
- if (pdata->transceiver_enable)
- pdata->transceiver_enable(0);
- close_candev(net);
- return ret;
- }
-
- mcp251x_hw_wakeup(spi);
- mcp251x_hw_reset(spi);
- ret = mcp251x_setup(net, priv, spi);
- if (ret) {
- free_irq(spi->irq, net);
- mcp251x_hw_sleep(spi);
- if (pdata->transceiver_enable)
- pdata->transceiver_enable(0);
- close_candev(net);
- return ret;
- }
- mcp251x_set_normal_mode(spi);
- netif_wake_queue(net);
-
- return 0;
+ pdata->transceiver_enable(0);
+ close_candev(net);
}
static int mcp251x_stop(struct net_device *net)
@@ -706,17 +642,19 @@ static int mcp251x_stop(struct net_device *net)
close_candev(net);
+ priv->force_quit = 1;
+ free_irq(spi->irq, priv);
+ destroy_workqueue(priv->wq);
+ priv->wq = NULL;
+
+ mutex_lock(&priv->mcp_lock);
+
/* Disable and clear pending interrupts */
mcp251x_write_reg(spi, CANINTE, 0x00);
mcp251x_write_reg(spi, CANINTF, 0x00);
- priv->force_quit = 1;
- free_irq(spi->irq, net);
- flush_workqueue(priv->wq);
-
mcp251x_write_reg(spi, TXBCTRL(0), 0);
- if (priv->tx_skb || priv->tx_len)
- mcp251x_clean(net);
+ mcp251x_clean(net);
mcp251x_hw_sleep(spi);
@@ -725,9 +663,27 @@ static int mcp251x_stop(struct net_device *net)
priv->can.state = CAN_STATE_STOPPED;
+ mutex_unlock(&priv->mcp_lock);
+
return 0;
}
+static void mcp251x_error_skb(struct net_device *net, int can_id, int data1)
+{
+ struct sk_buff *skb;
+ struct can_frame *frame;
+
+ skb = alloc_can_err_skb(net, &frame);
+ if (skb) {
+ frame->can_id = can_id;
+ frame->data[1] = data1;
+ netif_rx(skb);
+ } else {
+ dev_err(&net->dev,
+ "cannot allocate error skb\n");
+ }
+}
+
static void mcp251x_tx_work_handler(struct work_struct *ws)
{
struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,
@@ -736,33 +692,32 @@ static void mcp251x_tx_work_handler(struct work_struct *ws)
struct net_device *net = priv->net;
struct can_frame *frame;
+ mutex_lock(&priv->mcp_lock);
if (priv->tx_skb) {
- frame = (struct can_frame *)priv->tx_skb->data;
-
if (priv->can.state == CAN_STATE_BUS_OFF) {
mcp251x_clean(net);
- netif_wake_queue(net);
- return;
+ } else {
+ frame = (struct can_frame *)priv->tx_skb->data;
+
+ if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)
+ frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;
+ mcp251x_hw_tx(spi, frame, 0);
+ priv->tx_len = 1 + frame->can_dlc;
+ can_put_echo_skb(priv->tx_skb, net, 0);
+ priv->tx_skb = NULL;
}
- if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)
- frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;
- mcp251x_hw_tx(spi, frame, 0);
- priv->tx_len = 1 + frame->can_dlc;
- can_put_echo_skb(priv->tx_skb, net, 0);
- priv->tx_skb = NULL;
}
+ mutex_unlock(&priv->mcp_lock);
}
-static void mcp251x_irq_work_handler(struct work_struct *ws)
+static void mcp251x_restart_work_handler(struct work_struct *ws)
{
struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,
- irq_work);
+ restart_work);
struct spi_device *spi = priv->spi;
struct net_device *net = priv->net;
- u8 txbnctrl;
- u8 intf;
- enum can_state new_state;
+ mutex_lock(&priv->mcp_lock);
if (priv->after_suspend) {
mdelay(10);
mcp251x_hw_reset(spi);
@@ -771,45 +726,54 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
mcp251x_set_normal_mode(spi);
} else if (priv->after_suspend & AFTER_SUSPEND_UP) {
netif_device_attach(net);
- /* Clean since we lost tx buffer */
- if (priv->tx_skb || priv->tx_len) {
- mcp251x_clean(net);
- netif_wake_queue(net);
- }
+ mcp251x_clean(net);
mcp251x_set_normal_mode(spi);
+ netif_wake_queue(net);
} else {
mcp251x_hw_sleep(spi);
}
priv->after_suspend = 0;
+ priv->force_quit = 0;
}
- if (priv->can.restart_ms == 0 && priv->can.state == CAN_STATE_BUS_OFF)
- return;
+ if (priv->restart_tx) {
+ priv->restart_tx = 0;
+ mcp251x_write_reg(spi, TXBCTRL(0), 0);
+ mcp251x_clean(net);
+ netif_wake_queue(net);
+ mcp251x_error_skb(net, CAN_ERR_RESTARTED, 0);
+ }
+ mutex_unlock(&priv->mcp_lock);
+}
- while (!priv->force_quit && !freezing(current)) {
- u8 eflag = mcp251x_read_reg(spi, EFLG);
- int can_id = 0, data1 = 0;
+static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
+{
+ struct mcp251x_priv *priv = dev_id;
+ struct spi_device *spi = priv->spi;
+ struct net_device *net = priv->net;
- mcp251x_write_reg(spi, EFLG, 0x00);
+ mutex_lock(&priv->mcp_lock);
+ while (!priv->force_quit) {
+ enum can_state new_state;
+ u8 intf = mcp251x_read_reg(spi, CANINTF);
+ u8 eflag;
+ int can_id = 0, data1 = 0;
- if (priv->restart_tx) {
- priv->restart_tx = 0;
- mcp251x_write_reg(spi, TXBCTRL(0), 0);
- if (priv->tx_skb || priv->tx_len)
- mcp251x_clean(net);
- netif_wake_queue(net);
- can_id |= CAN_ERR_RESTARTED;
+ if (intf & CANINTF_RX0IF) {
+ mcp251x_hw_rx(spi, 0);
+ /* Free one buffer ASAP */
+ mcp251x_write_bits(spi, CANINTF, intf & CANINTF_RX0IF,
+ 0x00);
}
- if (priv->wake) {
- /* Wait whilst the device wakes up */
- mdelay(10);
- priv->wake = 0;
- }
+ if (intf & CANINTF_RX1IF)
+ mcp251x_hw_rx(spi, 1);
- intf = mcp251x_read_reg(spi, CANINTF);
mcp251x_write_bits(spi, CANINTF, intf, 0x00);
+ eflag = mcp251x_read_reg(spi, EFLG);
+ mcp251x_write_reg(spi, EFLG, 0x00);
+
/* Update can state */
if (eflag & EFLG_TXBO) {
new_state = CAN_STATE_BUS_OFF;
@@ -850,59 +814,31 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
}
priv->can.state = new_state;
- if ((intf & CANINTF_ERRIF) || (can_id & CAN_ERR_RESTARTED)) {
- struct sk_buff *skb;
- struct can_frame *frame;
-
- /* Create error frame */
- skb = alloc_can_err_skb(net, &frame);
- if (skb) {
- /* Set error frame flags based on bus state */
- frame->can_id = can_id;
- frame->data[1] = data1;
-
- /* Update net stats for overflows */
- if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
- if (eflag & EFLG_RX0OVR)
- net->stats.rx_over_errors++;
- if (eflag & EFLG_RX1OVR)
- net->stats.rx_over_errors++;
- frame->can_id |= CAN_ERR_CRTL;
- frame->data[1] |=
- CAN_ERR_CRTL_RX_OVERFLOW;
- }
-
- netif_rx(skb);
- } else {
- dev_info(&spi->dev,
- "cannot allocate error skb\n");
+ if (intf & CANINTF_ERRIF) {
+ /* Handle overflow counters */
+ if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
+ if (eflag & EFLG_RX0OVR)
+ net->stats.rx_over_errors++;
+ if (eflag & EFLG_RX1OVR)
+ net->stats.rx_over_errors++;
+ can_id |= CAN_ERR_CRTL;
+ data1 |= CAN_ERR_CRTL_RX_OVERFLOW;
}
+ mcp251x_error_skb(net, can_id, data1);
}
if (priv->can.state == CAN_STATE_BUS_OFF) {
if (priv->can.restart_ms == 0) {
+ priv->force_quit = 1;
can_bus_off(net);
mcp251x_hw_sleep(spi);
- return;
+ break;
}
}
if (intf == 0)
break;
- if (intf & CANINTF_WAKIF)
- complete(&priv->awake);
-
- if (intf & CANINTF_MERRF) {
- /* If there are pending Tx buffers, restart queue */
- txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0));
- if (!(txbnctrl & TXBCTRL_TXREQ)) {
- if (priv->tx_skb || priv->tx_len)
- mcp251x_clean(net);
- netif_wake_queue(net);
- }
- }
-
if (intf & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) {
net->stats.tx_packets++;
net->stats.tx_bytes += priv->tx_len - 1;
@@ -913,12 +849,66 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
netif_wake_queue(net);
}
- if (intf & CANINTF_RX0IF)
- mcp251x_hw_rx(spi, 0);
+ }
+ mutex_unlock(&priv->mcp_lock);
+ return IRQ_HANDLED;
+}
- if (intf & CANINTF_RX1IF)
- mcp251x_hw_rx(spi, 1);
+static int mcp251x_open(struct net_device *net)
+{
+ struct mcp251x_priv *priv = netdev_priv(net);
+ struct spi_device *spi = priv->spi;
+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+ int ret;
+
+ ret = open_candev(net);
+ if (ret) {
+ dev_err(&spi->dev, "unable to set initial baudrate!\n");
+ return ret;
+ }
+
+ mutex_lock(&priv->mcp_lock);
+ if (pdata->transceiver_enable)
+ pdata->transceiver_enable(1);
+
+ priv->force_quit = 0;
+ priv->tx_skb = NULL;
+ priv->tx_len = 0;
+
+ ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
+ IRQF_TRIGGER_FALLING, DEVICE_NAME, priv);
+ if (ret) {
+ dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
+ if (pdata->transceiver_enable)
+ pdata->transceiver_enable(0);
+ close_candev(net);
+ goto open_unlock;
+ }
+
+ priv->wq = create_freezeable_workqueue("mcp251x_wq");
+ INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
+ INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);
+
+ ret = mcp251x_hw_reset(spi);
+ if (ret) {
+ mcp251x_open_clean(net);
+ goto open_unlock;
+ }
+ ret = mcp251x_setup(net, priv, spi);
+ if (ret) {
+ mcp251x_open_clean(net);
+ goto open_unlock;
}
+ ret = mcp251x_set_normal_mode(spi);
+ if (ret) {
+ mcp251x_open_clean(net);
+ goto open_unlock;
+ }
+ netif_wake_queue(net);
+
+open_unlock:
+ mutex_unlock(&priv->mcp_lock);
+ return ret;
}
static const struct net_device_ops mcp251x_netdev_ops = {
@@ -952,11 +942,13 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
priv->can.bittiming_const = &mcp251x_bittiming_const;
priv->can.do_set_mode = mcp251x_do_set_mode;
priv->can.clock.freq = pdata->oscillator_frequency / 2;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
+ CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
priv->net = net;
dev_set_drvdata(&spi->dev, priv);
priv->spi = spi;
- mutex_init(&priv->spi_lock);
+ mutex_init(&priv->mcp_lock);
/* If requested, allocate DMA buffers */
if (mcp251x_enable_dma) {
@@ -1005,18 +997,12 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
SET_NETDEV_DEV(net, &spi->dev);
- priv->wq = create_freezeable_workqueue("mcp251x_wq");
-
- INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
- INIT_WORK(&priv->irq_work, mcp251x_irq_work_handler);
-
- init_completion(&priv->awake);
-
/* Configure the SPI bus */
spi->mode = SPI_MODE_0;
spi->bits_per_word = 8;
spi_setup(spi);
+ /* Here is OK to not lock the MCP, no one knows about it yet */
if (!mcp251x_hw_probe(spi)) {
dev_info(&spi->dev, "Probe failed\n");
goto error_probe;
@@ -1059,10 +1045,6 @@ static int __devexit mcp251x_can_remove(struct spi_device *spi)
unregister_candev(net);
free_candev(net);
- priv->force_quit = 1;
- flush_workqueue(priv->wq);
- destroy_workqueue(priv->wq);
-
if (mcp251x_enable_dma) {
dma_free_coherent(&spi->dev, PAGE_SIZE,
priv->spi_tx_buf, priv->spi_tx_dma);
@@ -1084,6 +1066,12 @@ static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state)
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
struct net_device *net = priv->net;
+ priv->force_quit = 1;
+ disable_irq(spi->irq);
+ /*
+ * Note: at this point neither IST nor workqueues are running.
+ * open/stop cannot be called anyway so locking is not needed
+ */
if (netif_running(net)) {
netif_device_detach(net);
@@ -1110,16 +1098,18 @@ static int mcp251x_can_resume(struct spi_device *spi)
if (priv->after_suspend & AFTER_SUSPEND_POWER) {
pdata->power_enable(1);
- queue_work(priv->wq, &priv->irq_work);
+ queue_work(priv->wq, &priv->restart_work);
} else {
if (priv->after_suspend & AFTER_SUSPEND_UP) {
if (pdata->transceiver_enable)
pdata->transceiver_enable(1);
- queue_work(priv->wq, &priv->irq_work);
+ queue_work(priv->wq, &priv->restart_work);
} else {
priv->after_suspend = 0;
}
}
+ priv->force_quit = 0;
+ enable_irq(spi->irq);
return 0;
}
#else
diff --git a/drivers/net/can/mscan/Kconfig b/drivers/net/can/mscan/Kconfig
index cd0f2d6f375d..27d1d398e25e 100644
--- a/drivers/net/can/mscan/Kconfig
+++ b/drivers/net/can/mscan/Kconfig
@@ -11,12 +11,13 @@ if CAN_MSCAN
config CAN_MPC5XXX
tristate "Freescale MPC5xxx onboard CAN controller"
- depends on PPC_MPC52xx
+ depends on (PPC_MPC52xx || PPC_MPC512x)
---help---
If you say yes here you get support for Freescale's MPC5xxx
- onboard CAN controller.
+ onboard CAN controller. Currently, the MPC5200, MPC5200B and
+ MPC5121 (Rev. 2 and later) are supported.
- This driver can also be built as a module. If so, the module
+ This driver can also be built as a module. If so, the module
will be called mscan-mpc5xxx.ko.
endif
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index 1de6f6349b16..03e7c48465a2 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -29,6 +29,7 @@
#include <linux/can/dev.h>
#include <linux/of_platform.h>
#include <sysdev/fsl_soc.h>
+#include <linux/clk.h>
#include <linux/io.h>
#include <asm/mpc52xx.h>
@@ -36,22 +37,21 @@
#define DRV_NAME "mpc5xxx_can"
-static struct of_device_id mpc52xx_cdm_ids[] __devinitdata = {
+struct mpc5xxx_can_data {
+ unsigned int type;
+ u32 (*get_clock)(struct of_device *ofdev, const char *clock_name,
+ int *mscan_clksrc);
+};
+
+#ifdef CONFIG_PPC_MPC52xx
+static struct of_device_id __devinitdata mpc52xx_cdm_ids[] = {
{ .compatible = "fsl,mpc5200-cdm", },
{}
};
-/*
- * Get frequency of the MSCAN clock source
- *
- * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock (IP_CLK)
- * can be selected. According to the MPC5200 user's manual, the oscillator
- * clock is the better choice as it has less jitter but due to a hardware
- * bug, it can not be selected for the old MPC5200 Rev. A chips.
- */
-
-static unsigned int __devinit mpc52xx_can_clock_freq(struct of_device *of,
- int clock_src)
+static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev,
+ const char *clock_name,
+ int *mscan_clksrc)
{
unsigned int pvr;
struct mpc52xx_cdm __iomem *cdm;
@@ -61,21 +61,33 @@ static unsigned int __devinit mpc52xx_can_clock_freq(struct of_device *of,
pvr = mfspr(SPRN_PVR);
- freq = mpc5xxx_get_bus_frequency(of->node);
+ /*
+ * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock
+ * (IP_CLK) can be selected as MSCAN clock source. According to
+ * the MPC5200 user's manual, the oscillator clock is the better
+ * choice as it has less jitter. For this reason, it is selected
+ * by default. Unfortunately, it can not be selected for the old
+ * MPC5200 Rev. A chips due to a hardware bug (check errata).
+ */
+ if (clock_name && strcmp(clock_name, "ip") == 0)
+ *mscan_clksrc = MSCAN_CLKSRC_BUS;
+ else
+ *mscan_clksrc = MSCAN_CLKSRC_XTAL;
+
+ freq = mpc5xxx_get_bus_frequency(ofdev->node);
if (!freq)
return 0;
- if (clock_src == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
+ if (*mscan_clksrc == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
return freq;
/* Determine SYS_XTAL_IN frequency from the clock domain settings */
np_cdm = of_find_matching_node(NULL, mpc52xx_cdm_ids);
if (!np_cdm) {
- dev_err(&of->dev, "can't get clock node!\n");
+ dev_err(&ofdev->dev, "can't get clock node!\n");
return 0;
}
cdm = of_iomap(np_cdm, 0);
- of_node_put(np_cdm);
if (in_8(&cdm->ipb_clk_sel) & 0x1)
freq *= 2;
@@ -84,26 +96,174 @@ static unsigned int __devinit mpc52xx_can_clock_freq(struct of_device *of,
freq *= (val & (1 << 5)) ? 8 : 4;
freq /= (val & (1 << 6)) ? 12 : 16;
+ of_node_put(np_cdm);
iounmap(cdm);
return freq;
}
+#else /* !CONFIG_PPC_MPC52xx */
+static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev,
+ const char *clock_name,
+ int *mscan_clksrc)
+{
+ return 0;
+}
+#endif /* CONFIG_PPC_MPC52xx */
+
+#ifdef CONFIG_PPC_MPC512x
+struct mpc512x_clockctl {
+ u32 spmr; /* System PLL Mode Reg */
+ u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */
+ u32 scfr1; /* System Clk Freq Reg 1 */
+ u32 scfr2; /* System Clk Freq Reg 2 */
+ u32 reserved;
+ u32 bcr; /* Bread Crumb Reg */
+ u32 pccr[12]; /* PSC Clk Ctrl Reg 0-11 */
+ u32 spccr; /* SPDIF Clk Ctrl Reg */
+ u32 cccr; /* CFM Clk Ctrl Reg */
+ u32 dccr; /* DIU Clk Cnfg Reg */
+ u32 mccr[4]; /* MSCAN Clk Ctrl Reg 1-3 */
+};
+
+static struct of_device_id __devinitdata mpc512x_clock_ids[] = {
+ { .compatible = "fsl,mpc5121-clock", },
+ {}
+};
+
+static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev,
+ const char *clock_name,
+ int *mscan_clksrc)
+{
+ struct mpc512x_clockctl __iomem *clockctl;
+ struct device_node *np_clock;
+ struct clk *sys_clk, *ref_clk;
+ int plen, clockidx, clocksrc = -1;
+ u32 sys_freq, val, clockdiv = 1, freq = 0;
+ const u32 *pval;
+
+ np_clock = of_find_matching_node(NULL, mpc512x_clock_ids);
+ if (!np_clock) {
+ dev_err(&ofdev->dev, "couldn't find clock node\n");
+ return -ENODEV;
+ }
+ clockctl = of_iomap(np_clock, 0);
+ if (!clockctl) {
+ dev_err(&ofdev->dev, "couldn't map clock registers\n");
+ return 0;
+ }
+
+ /* Determine the MSCAN device index from the physical address */
+ pval = of_get_property(ofdev->node, "reg", &plen);
+ BUG_ON(!pval || plen < sizeof(*pval));
+ clockidx = (*pval & 0x80) ? 1 : 0;
+ if (*pval & 0x2000)
+ clockidx += 2;
+
+ /*
+ * Clock source and divider selection: 3 different clock sources
+ * can be selected: "ip", "ref" or "sys". For the latter two, a
+ * clock divider can be defined as well. If the clock source is
+ * not specified by the device tree, we first try to find an
+ * optimal CAN source clock based on the system clock. If that
+ * is not posslible, the reference clock will be used.
+ */
+ if (clock_name && !strcmp(clock_name, "ip")) {
+ *mscan_clksrc = MSCAN_CLKSRC_IPS;
+ freq = mpc5xxx_get_bus_frequency(ofdev->node);
+ } else {
+ *mscan_clksrc = MSCAN_CLKSRC_BUS;
+
+ pval = of_get_property(ofdev->node,
+ "fsl,mscan-clock-divider", &plen);
+ if (pval && plen == sizeof(*pval))
+ clockdiv = *pval;
+ if (!clockdiv)
+ clockdiv = 1;
+
+ if (!clock_name || !strcmp(clock_name, "sys")) {
+ sys_clk = clk_get(&ofdev->dev, "sys_clk");
+ if (!sys_clk) {
+ dev_err(&ofdev->dev, "couldn't get sys_clk\n");
+ goto exit_unmap;
+ }
+ /* Get and round up/down sys clock rate */
+ sys_freq = 1000000 *
+ ((clk_get_rate(sys_clk) + 499999) / 1000000);
+
+ if (!clock_name) {
+ /* A multiple of 16 MHz would be optimal */
+ if ((sys_freq % 16000000) == 0) {
+ clocksrc = 0;
+ clockdiv = sys_freq / 16000000;
+ freq = sys_freq / clockdiv;
+ }
+ } else {
+ clocksrc = 0;
+ freq = sys_freq / clockdiv;
+ }
+ }
+
+ if (clocksrc < 0) {
+ ref_clk = clk_get(&ofdev->dev, "ref_clk");
+ if (!ref_clk) {
+ dev_err(&ofdev->dev, "couldn't get ref_clk\n");
+ goto exit_unmap;
+ }
+ clocksrc = 1;
+ freq = clk_get_rate(ref_clk) / clockdiv;
+ }
+ }
+
+ /* Disable clock */
+ out_be32(&clockctl->mccr[clockidx], 0x0);
+ if (clocksrc >= 0) {
+ /* Set source and divider */
+ val = (clocksrc << 14) | ((clockdiv - 1) << 17);
+ out_be32(&clockctl->mccr[clockidx], val);
+ /* Enable clock */
+ out_be32(&clockctl->mccr[clockidx], val | 0x10000);
+ }
+
+ /* Enable MSCAN clock domain */
+ val = in_be32(&clockctl->sccr[1]);
+ if (!(val & (1 << 25)))
+ out_be32(&clockctl->sccr[1], val | (1 << 25));
+
+ dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n",
+ *mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" :
+ clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv);
+
+exit_unmap:
+ of_node_put(np_clock);
+ iounmap(clockctl);
+
+ return freq;
+}
+#else /* !CONFIG_PPC_MPC512x */
+static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev,
+ const char *clock_name,
+ int *mscan_clksrc)
+{
+ return 0;
+}
+#endif /* CONFIG_PPC_MPC512x */
static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
const struct of_device_id *id)
{
+ struct mpc5xxx_can_data *data = (struct mpc5xxx_can_data *)id->data;
struct device_node *np = ofdev->node;
struct net_device *dev;
struct mscan_priv *priv;
void __iomem *base;
- const char *clk_src;
- int err, irq, clock_src;
+ const char *clock_name = NULL;
+ int irq, mscan_clksrc = 0;
+ int err = -ENOMEM;
- base = of_iomap(ofdev->node, 0);
+ base = of_iomap(np, 0);
if (!base) {
dev_err(&ofdev->dev, "couldn't ioremap\n");
- err = -ENOMEM;
- goto exit_release_mem;
+ return err;
}
irq = irq_of_parse_and_map(np, 0);
@@ -114,37 +274,27 @@ static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
}
dev = alloc_mscandev();
- if (!dev) {
- err = -ENOMEM;
+ if (!dev)
goto exit_dispose_irq;
- }
priv = netdev_priv(dev);
priv->reg_base = base;
dev->irq = irq;
- /*
- * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock
- * (IP_CLK) can be selected as MSCAN clock source. According to
- * the MPC5200 user's manual, the oscillator clock is the better
- * choice as it has less jitter. For this reason, it is selected
- * by default.
- */
- clk_src = of_get_property(np, "fsl,mscan-clock-source", NULL);
- if (clk_src && strcmp(clk_src, "ip") == 0)
- clock_src = MSCAN_CLKSRC_BUS;
- else
- clock_src = MSCAN_CLKSRC_XTAL;
- priv->can.clock.freq = mpc52xx_can_clock_freq(ofdev, clock_src);
+ clock_name = of_get_property(np, "fsl,mscan-clock-source", NULL);
+
+ BUG_ON(!data);
+ priv->type = data->type;
+ priv->can.clock.freq = data->get_clock(ofdev, clock_name,
+ &mscan_clksrc);
if (!priv->can.clock.freq) {
- dev_err(&ofdev->dev, "couldn't get MSCAN clock frequency\n");
- err = -ENODEV;
+ dev_err(&ofdev->dev, "couldn't get MSCAN clock properties\n");
goto exit_free_mscan;
}
SET_NETDEV_DEV(dev, &ofdev->dev);
- err = register_mscandev(dev, clock_src);
+ err = register_mscandev(dev, mscan_clksrc);
if (err) {
dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
DRV_NAME, err);
@@ -164,7 +314,7 @@ exit_dispose_irq:
irq_dispose_mapping(irq);
exit_unmap_mem:
iounmap(base);
-exit_release_mem:
+
return err;
}
@@ -225,8 +375,20 @@ static int mpc5xxx_can_resume(struct of_device *ofdev)
}
#endif
+static struct mpc5xxx_can_data __devinitdata mpc5200_can_data = {
+ .type = MSCAN_TYPE_MPC5200,
+ .get_clock = mpc52xx_can_get_clock,
+};
+
+static struct mpc5xxx_can_data __devinitdata mpc5121_can_data = {
+ .type = MSCAN_TYPE_MPC5121,
+ .get_clock = mpc512x_can_get_clock,
+};
+
static struct of_device_id __devinitdata mpc5xxx_can_table[] = {
- {.compatible = "fsl,mpc5200-mscan"},
+ { .compatible = "fsl,mpc5200-mscan", .data = &mpc5200_can_data, },
+ /* Note that only MPC5121 Rev. 2 (and later) is supported */
+ { .compatible = "fsl,mpc5121-mscan", .data = &mpc5121_can_data, },
{},
};
@@ -255,5 +417,5 @@ static void __exit mpc5xxx_can_exit(void)
module_exit(mpc5xxx_can_exit);
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
-MODULE_DESCRIPTION("Freescale MPC5200 CAN driver");
+MODULE_DESCRIPTION("Freescale MPC5xxx CAN driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
index 07346f880ca6..6b7dd578d417 100644
--- a/drivers/net/can/mscan/mscan.c
+++ b/drivers/net/can/mscan/mscan.c
@@ -4,7 +4,7 @@
* Copyright (C) 2005-2006 Andrey Volkov <avolkov@varma-el.com>,
* Varma Electronics Oy
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
- * Copytight (C) 2008-2009 Pengutronix <kernel@pengutronix.de>
+ * Copyright (C) 2008-2009 Pengutronix <kernel@pengutronix.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the version 2 of the GNU General Public License
@@ -152,6 +152,12 @@ static int mscan_start(struct net_device *dev)
priv->shadow_canrier = 0;
priv->flags = 0;
+ if (priv->type == MSCAN_TYPE_MPC5121) {
+ /* Clear pending bus-off condition */
+ if (in_8(&regs->canmisc) & MSCAN_BOHOLD)
+ out_8(&regs->canmisc, MSCAN_BOHOLD);
+ }
+
err = mscan_set_mode(dev, MSCAN_NORMAL_MODE);
if (err)
return err;
@@ -163,8 +169,29 @@ static int mscan_start(struct net_device *dev)
out_8(&regs->cantier, 0);
/* Enable receive interrupts. */
- out_8(&regs->canrier, MSCAN_OVRIE | MSCAN_RXFIE | MSCAN_CSCIE |
- MSCAN_RSTATE1 | MSCAN_RSTATE0 | MSCAN_TSTATE1 | MSCAN_TSTATE0);
+ out_8(&regs->canrier, MSCAN_RX_INTS_ENABLE);
+
+ return 0;
+}
+
+static int mscan_restart(struct net_device *dev)
+{
+ struct mscan_priv *priv = netdev_priv(dev);
+
+ if (priv->type == MSCAN_TYPE_MPC5121) {
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ WARN(!(in_8(&regs->canmisc) & MSCAN_BOHOLD),
+ "bus-off state expected");
+ out_8(&regs->canmisc, MSCAN_BOHOLD);
+ /* Re-enable receive interrupts. */
+ out_8(&regs->canrier, MSCAN_RX_INTS_ENABLE);
+ } else {
+ if (priv->can.state <= CAN_STATE_BUS_OFF)
+ mscan_set_mode(dev, MSCAN_INIT_MODE);
+ return mscan_start(dev);
+ }
return 0;
}
@@ -177,8 +204,8 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
int i, rtr, buf_id;
u32 can_id;
- if (frame->can_dlc > 8)
- return -EINVAL;
+ if (can_dropped_invalid_skb(dev, skb))
+ return NETDEV_TX_OK;
out_8(&regs->cantier, 0);
@@ -359,9 +386,12 @@ static void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame,
* automatically. To avoid that we stop the chip doing
* a light-weight stop (we are in irq-context).
*/
- out_8(&regs->cantier, 0);
- out_8(&regs->canrier, 0);
- setbits8(&regs->canctl0, MSCAN_SLPRQ | MSCAN_INITRQ);
+ if (priv->type != MSCAN_TYPE_MPC5121) {
+ out_8(&regs->cantier, 0);
+ out_8(&regs->canrier, 0);
+ setbits8(&regs->canctl0,
+ MSCAN_SLPRQ | MSCAN_INITRQ);
+ }
can_bus_off(dev);
break;
default:
@@ -491,9 +521,7 @@ static int mscan_do_set_mode(struct net_device *dev, enum can_mode mode)
switch (mode) {
case CAN_MODE_START:
- if (priv->can.state <= CAN_STATE_BUS_OFF)
- mscan_set_mode(dev, MSCAN_INIT_MODE);
- ret = mscan_start(dev);
+ ret = mscan_restart(dev);
if (ret)
break;
if (netif_queue_stopped(dev))
@@ -592,18 +620,21 @@ static const struct net_device_ops mscan_netdev_ops = {
.ndo_start_xmit = mscan_start_xmit,
};
-int register_mscandev(struct net_device *dev, int clock_src)
+int register_mscandev(struct net_device *dev, int mscan_clksrc)
{
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
u8 ctl1;
ctl1 = in_8(&regs->canctl1);
- if (clock_src)
+ if (mscan_clksrc)
ctl1 |= MSCAN_CLKSRC;
else
ctl1 &= ~MSCAN_CLKSRC;
+ if (priv->type == MSCAN_TYPE_MPC5121)
+ ctl1 |= MSCAN_BORM; /* bus-off recovery upon request */
+
ctl1 |= MSCAN_CANE;
out_8(&regs->canctl1, ctl1);
udelay(100);
@@ -655,6 +686,7 @@ struct net_device *alloc_mscandev(void)
priv->can.bittiming_const = &mscan_bittiming_const;
priv->can.do_set_bittiming = mscan_do_set_bittiming;
priv->can.do_set_mode = mscan_do_set_mode;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
for (i = 0; i < TX_QUEUE_SIZE; i++) {
priv->tx_queue[i].id = i;
diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h
index 00fc4aaf1ed8..4ff966473bc9 100644
--- a/drivers/net/can/mscan/mscan.h
+++ b/drivers/net/can/mscan/mscan.h
@@ -38,18 +38,20 @@
#define MSCAN_CLKSRC 0x40
#define MSCAN_LOOPB 0x20
#define MSCAN_LISTEN 0x10
+#define MSCAN_BORM 0x08
#define MSCAN_WUPM 0x04
#define MSCAN_SLPAK 0x02
#define MSCAN_INITAK 0x01
-/* Use the MPC5200 MSCAN variant? */
+/* Use the MPC5XXX MSCAN variant? */
#ifdef CONFIG_PPC
-#define MSCAN_FOR_MPC5200
+#define MSCAN_FOR_MPC5XXX
#endif
-#ifdef MSCAN_FOR_MPC5200
+#ifdef MSCAN_FOR_MPC5XXX
#define MSCAN_CLKSRC_BUS 0
#define MSCAN_CLKSRC_XTAL MSCAN_CLKSRC
+#define MSCAN_CLKSRC_IPS MSCAN_CLKSRC
#else
#define MSCAN_CLKSRC_BUS MSCAN_CLKSRC
#define MSCAN_CLKSRC_XTAL 0
@@ -136,7 +138,7 @@
#define MSCAN_EFF_RTR_SHIFT 0
#define MSCAN_EFF_FLAGS 0x18 /* IDE + SRR */
-#ifdef MSCAN_FOR_MPC5200
+#ifdef MSCAN_FOR_MPC5XXX
#define _MSCAN_RESERVED_(n, num) u8 _res##n[num]
#define _MSCAN_RESERVED_DSR_SIZE 2
#else
@@ -165,67 +167,66 @@ struct mscan_regs {
u8 cantbsel; /* + 0x14 0x0a */
u8 canidac; /* + 0x15 0x0b */
u8 reserved; /* + 0x16 0x0c */
- _MSCAN_RESERVED_(6, 5); /* + 0x17 */
-#ifndef MSCAN_FOR_MPC5200
- u8 canmisc; /* 0x0d */
-#endif
+ _MSCAN_RESERVED_(6, 2); /* + 0x17 */
+ u8 canmisc; /* + 0x19 0x0d */
+ _MSCAN_RESERVED_(7, 2); /* + 0x1a */
u8 canrxerr; /* + 0x1c 0x0e */
u8 cantxerr; /* + 0x1d 0x0f */
- _MSCAN_RESERVED_(7, 2); /* + 0x1e */
+ _MSCAN_RESERVED_(8, 2); /* + 0x1e */
u16 canidar1_0; /* + 0x20 0x10 */
- _MSCAN_RESERVED_(8, 2); /* + 0x22 */
+ _MSCAN_RESERVED_(9, 2); /* + 0x22 */
u16 canidar3_2; /* + 0x24 0x12 */
- _MSCAN_RESERVED_(9, 2); /* + 0x26 */
+ _MSCAN_RESERVED_(10, 2); /* + 0x26 */
u16 canidmr1_0; /* + 0x28 0x14 */
- _MSCAN_RESERVED_(10, 2); /* + 0x2a */
+ _MSCAN_RESERVED_(11, 2); /* + 0x2a */
u16 canidmr3_2; /* + 0x2c 0x16 */
- _MSCAN_RESERVED_(11, 2); /* + 0x2e */
+ _MSCAN_RESERVED_(12, 2); /* + 0x2e */
u16 canidar5_4; /* + 0x30 0x18 */
- _MSCAN_RESERVED_(12, 2); /* + 0x32 */
+ _MSCAN_RESERVED_(13, 2); /* + 0x32 */
u16 canidar7_6; /* + 0x34 0x1a */
- _MSCAN_RESERVED_(13, 2); /* + 0x36 */
+ _MSCAN_RESERVED_(14, 2); /* + 0x36 */
u16 canidmr5_4; /* + 0x38 0x1c */
- _MSCAN_RESERVED_(14, 2); /* + 0x3a */
+ _MSCAN_RESERVED_(15, 2); /* + 0x3a */
u16 canidmr7_6; /* + 0x3c 0x1e */
- _MSCAN_RESERVED_(15, 2); /* + 0x3e */
+ _MSCAN_RESERVED_(16, 2); /* + 0x3e */
struct {
u16 idr1_0; /* + 0x40 0x20 */
- _MSCAN_RESERVED_(16, 2); /* + 0x42 */
+ _MSCAN_RESERVED_(17, 2); /* + 0x42 */
u16 idr3_2; /* + 0x44 0x22 */
- _MSCAN_RESERVED_(17, 2); /* + 0x46 */
+ _MSCAN_RESERVED_(18, 2); /* + 0x46 */
u16 dsr1_0; /* + 0x48 0x24 */
- _MSCAN_RESERVED_(18, 2); /* + 0x4a */
+ _MSCAN_RESERVED_(19, 2); /* + 0x4a */
u16 dsr3_2; /* + 0x4c 0x26 */
- _MSCAN_RESERVED_(19, 2); /* + 0x4e */
+ _MSCAN_RESERVED_(20, 2); /* + 0x4e */
u16 dsr5_4; /* + 0x50 0x28 */
- _MSCAN_RESERVED_(20, 2); /* + 0x52 */
+ _MSCAN_RESERVED_(21, 2); /* + 0x52 */
u16 dsr7_6; /* + 0x54 0x2a */
- _MSCAN_RESERVED_(21, 2); /* + 0x56 */
+ _MSCAN_RESERVED_(22, 2); /* + 0x56 */
u8 dlr; /* + 0x58 0x2c */
- u8:8; /* + 0x59 0x2d */
- _MSCAN_RESERVED_(22, 2); /* + 0x5a */
+ u8 reserved; /* + 0x59 0x2d */
+ _MSCAN_RESERVED_(23, 2); /* + 0x5a */
u16 time; /* + 0x5c 0x2e */
} rx;
- _MSCAN_RESERVED_(23, 2); /* + 0x5e */
+ _MSCAN_RESERVED_(24, 2); /* + 0x5e */
struct {
u16 idr1_0; /* + 0x60 0x30 */
- _MSCAN_RESERVED_(24, 2); /* + 0x62 */
+ _MSCAN_RESERVED_(25, 2); /* + 0x62 */
u16 idr3_2; /* + 0x64 0x32 */
- _MSCAN_RESERVED_(25, 2); /* + 0x66 */
+ _MSCAN_RESERVED_(26, 2); /* + 0x66 */
u16 dsr1_0; /* + 0x68 0x34 */
- _MSCAN_RESERVED_(26, 2); /* + 0x6a */
+ _MSCAN_RESERVED_(27, 2); /* + 0x6a */
u16 dsr3_2; /* + 0x6c 0x36 */
- _MSCAN_RESERVED_(27, 2); /* + 0x6e */
+ _MSCAN_RESERVED_(28, 2); /* + 0x6e */
u16 dsr5_4; /* + 0x70 0x38 */
- _MSCAN_RESERVED_(28, 2); /* + 0x72 */
+ _MSCAN_RESERVED_(29, 2); /* + 0x72 */
u16 dsr7_6; /* + 0x74 0x3a */
- _MSCAN_RESERVED_(29, 2); /* + 0x76 */
+ _MSCAN_RESERVED_(30, 2); /* + 0x76 */
u8 dlr; /* + 0x78 0x3c */
u8 tbpr; /* + 0x79 0x3d */
- _MSCAN_RESERVED_(30, 2); /* + 0x7a */
+ _MSCAN_RESERVED_(31, 2); /* + 0x7a */
u16 time; /* + 0x7c 0x3e */
} tx;
- _MSCAN_RESERVED_(31, 2); /* + 0x7e */
+ _MSCAN_RESERVED_(32, 2); /* + 0x7e */
} __attribute__ ((packed));
#undef _MSCAN_RESERVED_
@@ -237,6 +238,15 @@ struct mscan_regs {
#define MSCAN_POWEROFF_MODE (MSCAN_CSWAI | MSCAN_SLPRQ)
#define MSCAN_SET_MODE_RETRIES 255
#define MSCAN_ECHO_SKB_MAX 3
+#define MSCAN_RX_INTS_ENABLE (MSCAN_OVRIE | MSCAN_RXFIE | MSCAN_CSCIE | \
+ MSCAN_RSTATE1 | MSCAN_RSTATE0 | \
+ MSCAN_TSTATE1 | MSCAN_TSTATE0)
+
+/* MSCAN type variants */
+enum {
+ MSCAN_TYPE_MPC5200,
+ MSCAN_TYPE_MPC5121
+};
#define BTR0_BRP_MASK 0x3f
#define BTR0_SJW_SHIFT 6
@@ -270,6 +280,7 @@ struct tx_queue_entry {
struct mscan_priv {
struct can_priv can; /* must be the first member */
+ unsigned int type; /* MSCAN type variants */
long open_time;
unsigned long flags;
void __iomem *reg_base; /* ioremap'ed address to registers */
@@ -285,12 +296,7 @@ struct mscan_priv {
};
extern struct net_device *alloc_mscandev(void);
-/*
- * clock_src:
- * 1 = The MSCAN clock source is the onchip Bus Clock.
- * 0 = The MSCAN clock source is the chip Oscillator Clock.
- */
-extern int register_mscandev(struct net_device *dev, int clock_src);
+extern int register_mscandev(struct net_device *dev, int mscan_clksrc);
extern void unregister_mscandev(struct net_device *dev);
#endif /* __MSCAN_H__ */
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index 4c674927f247..9e277d64a318 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -44,4 +44,16 @@ config CAN_KVASER_PCI
This driver is for the the PCIcanx and PCIcan cards (1, 2 or
4 channel) from Kvaser (http://www.kvaser.com).
+config CAN_PLX_PCI
+ tristate "PLX90xx PCI-bridge based Cards"
+ depends on PCI
+ ---help---
+ This driver is for CAN interface cards based on
+ the PLX90xx PCI bridge.
+ Driver supports now:
+ - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
+ - Adlink PCI-7841/cPCI-7841 SE card
+ - Marathon CAN-bus-PCI card (http://www.marathon.ru/)
+ - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
+
endif
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
index 9d245ac03965..ce924553995d 100644
--- a/drivers/net/can/sja1000/Makefile
+++ b/drivers/net/can/sja1000/Makefile
@@ -8,5 +8,6 @@ obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
+obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c
index fd04789d3370..87300606abb9 100644
--- a/drivers/net/can/sja1000/ems_pci.c
+++ b/drivers/net/can/sja1000/ems_pci.c
@@ -102,7 +102,7 @@ struct ems_pci_card {
#define EMS_PCI_BASE_SIZE 4096 /* size of controller area */
-static struct pci_device_id ems_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(ems_pci_tbl) = {
/* CPC-PCI v1 */
{PCI_VENDOR_ID_SIEMENS, 0x2104, PCI_ANY_ID, PCI_ANY_ID,},
/* CPC-PCI v2 */
diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c
index 7dd7769b9713..441e776a7f59 100644
--- a/drivers/net/can/sja1000/kvaser_pci.c
+++ b/drivers/net/can/sja1000/kvaser_pci.c
@@ -109,7 +109,7 @@ struct kvaser_pci {
#define KVASER_PCI_VENDOR_ID2 0x1a07 /* the PCI device and vendor IDs */
#define KVASER_PCI_DEVICE_ID2 0x0008
-static struct pci_device_id kvaser_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(kvaser_pci_tbl) = {
{KVASER_PCI_VENDOR_ID1, KVASER_PCI_DEVICE_ID1, PCI_ANY_ID, PCI_ANY_ID,},
{KVASER_PCI_VENDOR_ID2, KVASER_PCI_DEVICE_ID2, PCI_ANY_ID, PCI_ANY_ID,},
{ 0,}
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
new file mode 100644
index 000000000000..6b46a6395f80
--- /dev/null
+++ b/drivers/net/can/sja1000/plx_pci.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2008-2010 Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>
+ *
+ * Derived from the ems_pci.c driver:
+ * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
+ * Copyright (C) 2008 Markus Plessing <plessing@ems-wuensche.com>
+ * Copyright (C) 2008 Sebastian Haas <haas@ems-wuensche.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/io.h>
+
+#include "sja1000.h"
+
+#define DRV_NAME "sja1000_plx_pci"
+
+MODULE_AUTHOR("Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>");
+MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with "
+ "the SJA1000 chips");
+MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
+ "Adlink PCI-7841/cPCI-7841 SE, "
+ "Marathon CAN-bus-PCI, "
+ "TEWS TECHNOLOGIES TPMC810");
+MODULE_LICENSE("GPL v2");
+
+#define PLX_PCI_MAX_CHAN 2
+
+struct plx_pci_card {
+ int channels; /* detected channels count */
+ struct net_device *net_dev[PLX_PCI_MAX_CHAN];
+ void __iomem *conf_addr;
+};
+
+#define PLX_PCI_CAN_CLOCK (16000000 / 2)
+
+/* PLX90xx registers */
+#define PLX_INTCSR 0x4c /* Interrupt Control/Status */
+#define PLX_CNTRL 0x50 /* User I/O, Direct Slave Response,
+ * Serial EEPROM, and Initialization
+ * Control register
+ */
+
+#define PLX_LINT1_EN 0x1 /* Local interrupt 1 enable */
+#define PLX_LINT2_EN (1 << 3) /* Local interrupt 2 enable */
+#define PLX_PCI_INT_EN (1 << 6) /* PCI Interrupt Enable */
+#define PLX_PCI_RESET (1 << 30) /* PCI Adapter Software Reset */
+
+/*
+ * The board configuration is probably following:
+ * RX1 is connected to ground.
+ * TX1 is not connected.
+ * CLKO is not connected.
+ * Setting the OCR register to 0xDA is a good idea.
+ * This means normal output mode, push-pull and the correct polarity.
+ */
+#define PLX_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
+
+/*
+ * In the CDR register, you should set CBP to 1.
+ * You will probably also want to set the clock divider value to 7
+ * (meaning direct oscillator output) because the second SJA1000 chip
+ * is driven by the first one CLKOUT output.
+ */
+#define PLX_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK)
+
+/* SJA1000 Control Register in the BasicCAN Mode */
+#define REG_CR 0x00
+
+/* States of some SJA1000 registers after hardware reset in the BasicCAN mode*/
+#define REG_CR_BASICCAN_INITIAL 0x21
+#define REG_CR_BASICCAN_INITIAL_MASK 0xa1
+#define REG_SR_BASICCAN_INITIAL 0x0c
+#define REG_IR_BASICCAN_INITIAL 0xe0
+
+/* States of some SJA1000 registers after hardware reset in the PeliCAN mode*/
+#define REG_MOD_PELICAN_INITIAL 0x01
+#define REG_SR_PELICAN_INITIAL 0x3c
+#define REG_IR_PELICAN_INITIAL 0x00
+
+#define ADLINK_PCI_VENDOR_ID 0x144A
+#define ADLINK_PCI_DEVICE_ID 0x7841
+
+#define MARATHON_PCI_DEVICE_ID 0x2715
+
+#define TEWS_PCI_VENDOR_ID 0x1498
+#define TEWS_PCI_DEVICE_ID_TMPC810 0x032A
+
+static void plx_pci_reset_common(struct pci_dev *pdev);
+static void plx_pci_reset_marathon(struct pci_dev *pdev);
+
+struct plx_pci_channel_map {
+ u32 bar;
+ u32 offset;
+ u32 size; /* 0x00 - auto, e.g. length of entire bar */
+};
+
+struct plx_pci_card_info {
+ const char *name;
+ int channel_count;
+ u32 can_clock;
+ u8 ocr; /* output control register */
+ u8 cdr; /* clock divider register */
+
+ /* Parameters for mapping local configuration space */
+ struct plx_pci_channel_map conf_map;
+
+ /* Parameters for mapping the SJA1000 chips */
+ struct plx_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CHAN];
+
+ /* Pointer to device-dependent reset function */
+ void (*reset_func)(struct pci_dev *pdev);
+};
+
+static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = {
+ "Adlink PCI-7841/cPCI-7841", 2,
+ PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+ {1, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
+ &plx_pci_reset_common
+ /* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = {
+ "Adlink PCI-7841/cPCI-7841 SE", 2,
+ PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+ {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
+ &plx_pci_reset_common
+ /* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = {
+ "Marathon CAN-bus-PCI", 2,
+ PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+ {0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} },
+ &plx_pci_reset_marathon
+ /* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = {
+ "TEWS TECHNOLOGIES TPMC810", 2,
+ PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+ {0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} },
+ &plx_pci_reset_common
+ /* based on PLX9030 */
+};
+
+static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
+ {
+ /* Adlink PCI-7841/cPCI-7841 */
+ ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_NETWORK_OTHER << 8, ~0,
+ (kernel_ulong_t)&plx_pci_card_info_adlink
+ },
+ {
+ /* Adlink PCI-7841/cPCI-7841 SE */
+ ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_OTHER << 8, ~0,
+ (kernel_ulong_t)&plx_pci_card_info_adlink_se
+ },
+ {
+ /* Marathon CAN-bus-PCI card */
+ PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ (kernel_ulong_t)&plx_pci_card_info_marathon
+ },
+ {
+ /* TEWS TECHNOLOGIES TPMC810 card */
+ TEWS_PCI_VENDOR_ID, TEWS_PCI_DEVICE_ID_TMPC810,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ (kernel_ulong_t)&plx_pci_card_info_tews
+ },
+ { 0,}
+};
+MODULE_DEVICE_TABLE(pci, plx_pci_tbl);
+
+static u8 plx_pci_read_reg(const struct sja1000_priv *priv, int port)
+{
+ return ioread8(priv->reg_base + port);
+}
+
+static void plx_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
+{
+ iowrite8(val, priv->reg_base + port);
+}
+
+/*
+ * Check if a CAN controller is present at the specified location
+ * by trying to switch 'em from the Basic mode into the PeliCAN mode.
+ * Also check states of some registers in reset mode.
+ */
+static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
+{
+ int flag = 0;
+
+ /*
+ * Check registers after hardware reset (the Basic mode)
+ * See states on p. 10 of the Datasheet.
+ */
+ if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) ==
+ REG_CR_BASICCAN_INITIAL &&
+ (priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) &&
+ (priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL))
+ flag = 1;
+
+ /* Bring the SJA1000 into the PeliCAN mode*/
+ priv->write_reg(priv, REG_CDR, CDR_PELICAN);
+
+ /*
+ * Check registers after reset in the PeliCAN mode.
+ * See states on p. 23 of the Datasheet.
+ */
+ if (priv->read_reg(priv, REG_MOD) == REG_MOD_PELICAN_INITIAL &&
+ priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL &&
+ priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL)
+ return flag;
+
+ return 0;
+}
+
+/*
+ * PLX90xx software reset
+ * Also LRESET# asserts and brings to reset device on the Local Bus (if wired).
+ * For most cards it's enough for reset the SJA1000 chips.
+ */
+static void plx_pci_reset_common(struct pci_dev *pdev)
+{
+ struct plx_pci_card *card = pci_get_drvdata(pdev);
+ u32 cntrl;
+
+ cntrl = ioread32(card->conf_addr + PLX_CNTRL);
+ cntrl |= PLX_PCI_RESET;
+ iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
+ udelay(100);
+ cntrl ^= PLX_PCI_RESET;
+ iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
+};
+
+/* Special reset function for Marathon card */
+static void plx_pci_reset_marathon(struct pci_dev *pdev)
+{
+ void __iomem *reset_addr;
+ int i;
+ int reset_bar[2] = {3, 5};
+
+ plx_pci_reset_common(pdev);
+
+ for (i = 0; i < 2; i++) {
+ reset_addr = pci_iomap(pdev, reset_bar[i], 0);
+ if (!reset_addr) {
+ dev_err(&pdev->dev, "Failed to remap reset "
+ "space %d (BAR%d)\n", i, reset_bar[i]);
+ } else {
+ /* reset the SJA1000 chip */
+ iowrite8(0x1, reset_addr);
+ udelay(100);
+ pci_iounmap(pdev, reset_addr);
+ }
+ }
+}
+
+static void plx_pci_del_card(struct pci_dev *pdev)
+{
+ struct plx_pci_card *card = pci_get_drvdata(pdev);
+ struct net_device *dev;
+ struct sja1000_priv *priv;
+ int i = 0;
+
+ for (i = 0; i < card->channels; i++) {
+ dev = card->net_dev[i];
+ if (!dev)
+ continue;
+
+ dev_info(&pdev->dev, "Removing %s\n", dev->name);
+ unregister_sja1000dev(dev);
+ priv = netdev_priv(dev);
+ if (priv->reg_base)
+ pci_iounmap(pdev, priv->reg_base);
+ free_sja1000dev(dev);
+ }
+
+ plx_pci_reset_common(pdev);
+
+ /*
+ * Disable interrupts from PCI-card (PLX90xx) and disable Local_1,
+ * Local_2 interrupts
+ */
+ iowrite32(0x0, card->conf_addr + PLX_INTCSR);
+
+ if (card->conf_addr)
+ pci_iounmap(pdev, card->conf_addr);
+
+ kfree(card);
+
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+/*
+ * Probe PLX90xx based device for the SJA1000 chips and register each
+ * available CAN channel to SJA1000 Socket-CAN subsystem.
+ */
+static int __devinit plx_pci_add_card(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct sja1000_priv *priv;
+ struct net_device *dev;
+ struct plx_pci_card *card;
+ struct plx_pci_card_info *ci;
+ int err, i;
+ u32 val;
+ void __iomem *addr;
+
+ ci = (struct plx_pci_card_info *)ent->driver_data;
+
+ if (pci_enable_device(pdev) < 0) {
+ dev_err(&pdev->dev, "Failed to enable PCI device\n");
+ return -ENODEV;
+ }
+
+ dev_info(&pdev->dev, "Detected \"%s\" card at slot #%i\n",
+ ci->name, PCI_SLOT(pdev->devfn));
+
+ /* Allocate card structures to hold addresses, ... */
+ card = kzalloc(sizeof(*card), GFP_KERNEL);
+ if (!card) {
+ dev_err(&pdev->dev, "Unable to allocate memory\n");
+ pci_disable_device(pdev);
+ return -ENOMEM;
+ }
+
+ pci_set_drvdata(pdev, card);
+
+ card->channels = 0;
+
+ /* Remap PLX90xx configuration space */
+ addr = pci_iomap(pdev, ci->conf_map.bar, ci->conf_map.size);
+ if (!addr) {
+ err = -ENOMEM;
+ dev_err(&pdev->dev, "Failed to remap configuration space "
+ "(BAR%d)\n", ci->conf_map.bar);
+ goto failure_cleanup;
+ }
+ card->conf_addr = addr + ci->conf_map.offset;
+
+ ci->reset_func(pdev);
+
+ /* Detect available channels */
+ for (i = 0; i < ci->channel_count; i++) {
+ struct plx_pci_channel_map *cm = &ci->chan_map_tbl[i];
+
+ dev = alloc_sja1000dev(0);
+ if (!dev) {
+ err = -ENOMEM;
+ goto failure_cleanup;
+ }
+
+ card->net_dev[i] = dev;
+ priv = netdev_priv(dev);
+ priv->priv = card;
+ priv->irq_flags = IRQF_SHARED;
+
+ dev->irq = pdev->irq;
+
+ /*
+ * Remap IO space of the SJA1000 chips
+ * This is device-dependent mapping
+ */
+ addr = pci_iomap(pdev, cm->bar, cm->size);
+ if (!addr) {
+ err = -ENOMEM;
+ dev_err(&pdev->dev, "Failed to remap BAR%d\n", cm->bar);
+ goto failure_cleanup;
+ }
+
+ priv->reg_base = addr + cm->offset;
+ priv->read_reg = plx_pci_read_reg;
+ priv->write_reg = plx_pci_write_reg;
+
+ /* Check if channel is present */
+ if (plx_pci_check_sja1000(priv)) {
+ priv->can.clock.freq = ci->can_clock;
+ priv->ocr = ci->ocr;
+ priv->cdr = ci->cdr;
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ /* Register SJA1000 device */
+ err = register_sja1000dev(dev);
+ if (err) {
+ dev_err(&pdev->dev, "Registering device failed "
+ "(err=%d)\n", err);
+ free_sja1000dev(dev);
+ goto failure_cleanup;
+ }
+
+ card->channels++;
+
+ dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d "
+ "registered as %s\n", i + 1, priv->reg_base,
+ dev->irq, dev->name);
+ } else {
+ dev_err(&pdev->dev, "Channel #%d not detected\n",
+ i + 1);
+ free_sja1000dev(dev);
+ }
+ }
+
+ if (!card->channels) {
+ err = -ENODEV;
+ goto failure_cleanup;
+ }
+
+ /*
+ * Enable interrupts from PCI-card (PLX90xx) and enable Local_1,
+ * Local_2 interrupts from the SJA1000 chips
+ */
+ val = ioread32(card->conf_addr + PLX_INTCSR);
+ val |= PLX_LINT1_EN | PLX_LINT2_EN | PLX_PCI_INT_EN;
+ iowrite32(val, card->conf_addr + PLX_INTCSR);
+
+ return 0;
+
+failure_cleanup:
+ dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err);
+
+ plx_pci_del_card(pdev);
+
+ return err;
+}
+
+static struct pci_driver plx_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = plx_pci_tbl,
+ .probe = plx_pci_add_card,
+ .remove = plx_pci_del_card,
+};
+
+static int __init plx_pci_init(void)
+{
+ return pci_register_driver(&plx_pci_driver);
+}
+
+static void __exit plx_pci_exit(void)
+{
+ pci_unregister_driver(&plx_pci_driver);
+}
+
+module_init(plx_pci_init);
+module_exit(plx_pci_exit);
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 542a4f7255b4..145b1a731a53 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -130,8 +130,12 @@ static void set_normal_mode(struct net_device *dev)
/* check reset bit */
if ((status & MOD_RM) == 0) {
priv->can.state = CAN_STATE_ERROR_ACTIVE;
- /* enable all interrupts */
- priv->write_reg(priv, REG_IER, IRQ_ALL);
+ /* enable interrupts */
+ if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
+ priv->write_reg(priv, REG_IER, IRQ_ALL);
+ else
+ priv->write_reg(priv, REG_IER,
+ IRQ_ALL & ~IRQ_BEI);
return;
}
@@ -203,6 +207,17 @@ static int sja1000_set_bittiming(struct net_device *dev)
return 0;
}
+static int sja1000_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
+{
+ struct sja1000_priv *priv = netdev_priv(dev);
+
+ bec->txerr = priv->read_reg(priv, REG_TXERR);
+ bec->rxerr = priv->read_reg(priv, REG_RXERR);
+
+ return 0;
+}
+
/*
* initialize SJA1000 chip:
* - reset chip
@@ -249,6 +264,9 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
uint8_t dreg;
int i;
+ if (can_dropped_invalid_skb(dev, skb))
+ return NETDEV_TX_OK;
+
netif_stop_queue(dev);
fi = dlc = cf->can_dlc;
@@ -434,6 +452,8 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
CAN_ERR_CRTL_TX_PASSIVE :
CAN_ERR_CRTL_RX_PASSIVE;
}
+ cf->data[6] = txerr;
+ cf->data[7] = rxerr;
}
priv->can.state = state;
@@ -564,6 +584,9 @@ struct net_device *alloc_sja1000dev(int sizeof_priv)
priv->can.bittiming_const = &sja1000_bittiming_const;
priv->can.do_set_bittiming = sja1000_set_bittiming;
priv->can.do_set_mode = sja1000_set_mode;
+ priv->can.do_get_berr_counter = sja1000_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
+ CAN_CTRLMODE_BERR_REPORTING;
if (sizeof_priv)
priv->priv = (void *)priv + sizeof(struct sja1000_priv);
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index 5c993c2da528..0c3d2ba0d178 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -28,9 +28,11 @@
* .mbx_offset = 0x2000,
* .int_line = 0,
* .revision = 1,
+ * .transceiver_switch = hecc_phy_control,
* };
*
- * Please see include/can/platform/ti_hecc.h for description of above fields
+ * Please see include/linux/can/platform/ti_hecc.h for description of
+ * above fields.
*
*/
@@ -220,6 +222,7 @@ struct ti_hecc_priv {
u32 tx_head;
u32 tx_tail;
u32 rx_next;
+ void (*transceiver_switch)(int);
};
static inline int get_tx_head_mb(struct ti_hecc_priv *priv)
@@ -317,6 +320,13 @@ static int ti_hecc_set_btc(struct ti_hecc_priv *priv)
return 0;
}
+static void ti_hecc_transceiver_switch(const struct ti_hecc_priv *priv,
+ int on)
+{
+ if (priv->transceiver_switch)
+ priv->transceiver_switch(on);
+}
+
static void ti_hecc_reset(struct net_device *ndev)
{
u32 cnt;
@@ -477,6 +487,9 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
u32 mbxno, mbx_mask, data;
unsigned long flags;
+ if (can_dropped_invalid_skb(ndev, skb))
+ return NETDEV_TX_OK;
+
mbxno = get_tx_head_mb(priv);
mbx_mask = BIT(mbxno);
spin_lock_irqsave(&priv->mbx_lock, flags);
@@ -491,7 +504,6 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_unlock_irqrestore(&priv->mbx_lock, flags);
/* Prepare mailbox for transmission */
- data = min_t(u8, cf->can_dlc, 8);
if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */
data |= HECC_CANMCF_RTR;
data |= get_tx_head_prio(priv) << 8;
@@ -816,15 +828,17 @@ static int ti_hecc_open(struct net_device *ndev)
return err;
}
+ ti_hecc_transceiver_switch(priv, 1);
+
/* Open common can device */
err = open_candev(ndev);
if (err) {
dev_err(ndev->dev.parent, "open_candev() failed %d\n", err);
+ ti_hecc_transceiver_switch(priv, 0);
free_irq(ndev->irq, ndev);
return err;
}
- clk_enable(priv->clk);
ti_hecc_start(ndev);
napi_enable(&priv->napi);
netif_start_queue(ndev);
@@ -840,8 +854,8 @@ static int ti_hecc_close(struct net_device *ndev)
napi_disable(&priv->napi);
ti_hecc_stop(ndev);
free_irq(ndev->irq, ndev);
- clk_disable(priv->clk);
close_candev(ndev);
+ ti_hecc_transceiver_switch(priv, 0);
return 0;
}
@@ -903,10 +917,12 @@ static int ti_hecc_probe(struct platform_device *pdev)
priv->hecc_ram_offset = pdata->hecc_ram_offset;
priv->mbx_offset = pdata->mbx_offset;
priv->int_line = pdata->int_line;
+ priv->transceiver_switch = pdata->transceiver_switch;
priv->can.bittiming_const = &ti_hecc_bittiming_const;
priv->can.do_set_mode = ti_hecc_do_set_mode;
priv->can.do_get_state = ti_hecc_get_state;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
ndev->irq = irq->start;
ndev->flags |= IFF_ECHO;
@@ -925,6 +941,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
netif_napi_add(ndev, &priv->napi, ti_hecc_rx_poll,
HECC_DEF_NAPI_WEIGHT);
+ clk_enable(priv->clk);
err = register_candev(ndev);
if (err) {
dev_err(&pdev->dev, "register_candev() failed\n");
@@ -953,6 +970,7 @@ static int __devexit ti_hecc_remove(struct platform_device *pdev)
struct net_device *ndev = platform_get_drvdata(pdev);
struct ti_hecc_priv *priv = netdev_priv(ndev);
+ clk_disable(priv->clk);
clk_put(priv->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
iounmap(priv->base);
@@ -964,6 +982,48 @@ static int __devexit ti_hecc_remove(struct platform_device *pdev)
return 0;
}
+
+#ifdef CONFIG_PM
+static int ti_hecc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct ti_hecc_priv *priv = netdev_priv(dev);
+
+ if (netif_running(dev)) {
+ netif_stop_queue(dev);
+ netif_device_detach(dev);
+ }
+
+ hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_PDR);
+ priv->can.state = CAN_STATE_SLEEPING;
+
+ clk_disable(priv->clk);
+
+ return 0;
+}
+
+static int ti_hecc_resume(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct ti_hecc_priv *priv = netdev_priv(dev);
+
+ clk_enable(priv->clk);
+
+ hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_PDR);
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ if (netif_running(dev)) {
+ netif_device_attach(dev);
+ netif_start_queue(dev);
+ }
+
+ return 0;
+}
+#else
+#define ti_hecc_suspend NULL
+#define ti_hecc_resume NULL
+#endif
+
/* TI HECC netdevice driver: platform driver structure */
static struct platform_driver ti_hecc_driver = {
.driver = {
@@ -972,6 +1032,8 @@ static struct platform_driver ti_hecc_driver = {
},
.probe = ti_hecc_probe,
.remove = __devexit_p(ti_hecc_remove),
+ .suspend = ti_hecc_suspend,
+ .resume = ti_hecc_resume,
};
static int __init ti_hecc_init_driver(void)
@@ -979,14 +1041,15 @@ static int __init ti_hecc_init_driver(void)
printk(KERN_INFO DRV_DESC "\n");
return platform_driver_register(&ti_hecc_driver);
}
-module_init(ti_hecc_init_driver);
static void __exit ti_hecc_exit_driver(void)
{
printk(KERN_INFO DRV_DESC " unloaded\n");
platform_driver_unregister(&ti_hecc_driver);
}
+
module_exit(ti_hecc_exit_driver);
+module_init(ti_hecc_init_driver);
MODULE_AUTHOR("Anant Gole <anantgole@ti.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index bbc78e0b8a15..97ff6febad63 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -5,6 +5,6 @@ config CAN_EMS_USB
tristate "EMS CPC-USB/ARM7 CAN/USB interface"
---help---
This driver is for the one channel CPC-USB/ARM7 CAN/USB interface
- from from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
+ from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
endmenu
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index efbb05c71bf4..33451092b8e8 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -767,6 +767,9 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
size_t size = CPC_HEADER_SIZE + CPC_MSG_HEADER_LEN
+ sizeof(struct cpc_can_msg);
+ if (can_dropped_invalid_skb(netdev, skb))
+ return NETDEV_TX_OK;
+
/* create a URB, and a buffer for it, and copy the data to the URB */
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
@@ -873,9 +876,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
return NETDEV_TX_OK;
nomem:
- if (skb)
- dev_kfree_skb(skb);
-
+ dev_kfree_skb(skb);
stats->tx_dropped++;
return NETDEV_TX_OK;
@@ -1019,8 +1020,7 @@ static int ems_usb_probe(struct usb_interface *intf,
dev->can.bittiming_const = &ems_usb_bittiming_const;
dev->can.do_set_bittiming = ems_usb_set_bittiming;
dev->can.do_set_mode = ems_usb_set_mode;
-
- netdev->flags |= IFF_ECHO; /* we support local echo */
+ dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
netdev->netdev_ops = &ems_usb_netdev_ops;
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index 80ac56313981..d124d837ae58 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -47,6 +47,7 @@
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/can.h>
+#include <linux/can/dev.h>
#include <net/rtnetlink.h>
static __initdata const char banner[] =
@@ -70,10 +71,11 @@ MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");
static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
{
+ struct can_frame *cf = (struct can_frame *)skb->data;
struct net_device_stats *stats = &dev->stats;
stats->rx_packets++;
- stats->rx_bytes += skb->len;
+ stats->rx_bytes += cf->can_dlc;
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
@@ -85,11 +87,15 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
{
+ struct can_frame *cf = (struct can_frame *)skb->data;
struct net_device_stats *stats = &dev->stats;
int loop;
+ if (can_dropped_invalid_skb(dev, skb))
+ return NETDEV_TX_OK;
+
stats->tx_packets++;
- stats->tx_bytes += skb->len;
+ stats->tx_bytes += cf->can_dlc;
/* set flag whether this packet has to be looped back */
loop = skb->pkt_type == PACKET_LOOPBACK;
@@ -103,7 +109,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
* CAN core already did the echo for us
*/
stats->rx_packets++;
- stats->rx_bytes += skb->len;
+ stats->rx_bytes += cf->can_dlc;
}
kfree_skb(skb);
return NETDEV_TX_OK;
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index f857afe8e488..9bd155e4111c 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -66,6 +66,7 @@
* by default, the selective clear mask is set up to process rx packets.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/kernel.h>
@@ -106,7 +107,7 @@
#define cas_page_unmap(x) kunmap_atomic((x), KM_SKB_DATA_SOFTIRQ)
#define CAS_NCPUS num_online_cpus()
-#if defined(CONFIG_CASSINI_NAPI) && defined(HAVE_NETDEV_POLL)
+#ifdef CONFIG_CASSINI_NAPI
#define USE_NAPI
#define cas_skb_release(x) netif_receive_skb(x)
#else
@@ -143,7 +144,6 @@
#undef RX_COUNT_BUFFERS /* define to calculate RX buffer stats */
#define DRV_MODULE_NAME "cassini"
-#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "1.6"
#define DRV_MODULE_RELDATE "21 May 2008"
@@ -236,7 +236,7 @@ static u16 link_modes[] __devinitdata = {
CAS_BMCR_SPEED1000|BMCR_FULLDPLX /* 5 : 1000bt full duplex */
};
-static struct pci_device_id cas_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(cas_pci_tbl) = {
{ PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_CASSINI,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SATURN,
@@ -649,9 +649,8 @@ static cas_page_t *cas_page_dequeue(struct cas *cp)
cas_spare_recover(cp, GFP_ATOMIC);
spin_lock(&cp->rx_spare_lock);
if (list_empty(&cp->rx_spare_list)) {
- if (netif_msg_rx_err(cp))
- printk(KERN_ERR "%s: no spare buffers "
- "available.\n", cp->dev->name);
+ netif_err(cp, rx_err, cp->dev,
+ "no spare buffers available\n");
spin_unlock(&cp->rx_spare_lock);
return NULL;
}
@@ -728,12 +727,10 @@ static void cas_begin_auto_negotiation(struct cas *cp, struct ethtool_cmd *ep)
#endif
start_aneg:
if (cp->lstate == link_up) {
- printk(KERN_INFO "%s: PCS link down.\n",
- cp->dev->name);
+ netdev_info(cp->dev, "PCS link down\n");
} else {
if (changed) {
- printk(KERN_INFO "%s: link configuration changed\n",
- cp->dev->name);
+ netdev_info(cp->dev, "link configuration changed\n");
}
}
cp->lstate = link_down;
@@ -826,12 +823,12 @@ static int cas_saturn_firmware_init(struct cas *cp)
err = request_firmware(&fw, fw_name, &cp->pdev->dev);
if (err) {
- printk(KERN_ERR "cassini: Failed to load firmware \"%s\"\n",
+ pr_err("Failed to load firmware \"%s\"\n",
fw_name);
return err;
}
if (fw->size < 2) {
- printk(KERN_ERR "cassini: bogus length %zu in \"%s\"\n",
+ pr_err("bogus length %zu in \"%s\"\n",
fw->size, fw_name);
err = -EINVAL;
goto out;
@@ -841,7 +838,7 @@ static int cas_saturn_firmware_init(struct cas *cp)
cp->fw_data = vmalloc(cp->fw_size);
if (!cp->fw_data) {
err = -ENOMEM;
- printk(KERN_ERR "cassini: \"%s\" Failed %d\n", fw_name, err);
+ pr_err("\"%s\" Failed %d\n", fw_name, err);
goto out;
}
memcpy(cp->fw_data, &fw->data[2], cp->fw_size);
@@ -986,9 +983,8 @@ static void cas_phy_init(struct cas *cp)
break;
}
if (limit <= 0)
- printk(KERN_WARNING "%s: PCS reset bit would not "
- "clear [%08x].\n", cp->dev->name,
- readl(cp->regs + REG_PCS_STATE_MACHINE));
+ netdev_warn(cp->dev, "PCS reset bit would not clear [%08x]\n",
+ readl(cp->regs + REG_PCS_STATE_MACHINE));
/* Make sure PCS is disabled while changing advertisement
* configuration.
@@ -1030,11 +1026,8 @@ static int cas_pcs_link_check(struct cas *cp)
*/
if ((stat & (PCS_MII_STATUS_AUTONEG_COMP |
PCS_MII_STATUS_REMOTE_FAULT)) ==
- (PCS_MII_STATUS_AUTONEG_COMP | PCS_MII_STATUS_REMOTE_FAULT)) {
- if (netif_msg_link(cp))
- printk(KERN_INFO "%s: PCS RemoteFault\n",
- cp->dev->name);
- }
+ (PCS_MII_STATUS_AUTONEG_COMP | PCS_MII_STATUS_REMOTE_FAULT))
+ netif_info(cp, link, cp->dev, "PCS RemoteFault\n");
/* work around link detection issue by querying the PCS state
* machine directly.
@@ -1081,10 +1074,8 @@ static int cas_pcs_link_check(struct cas *cp)
cp->link_transition = LINK_TRANSITION_ON_FAILURE;
}
netif_carrier_off(cp->dev);
- if (cp->opened && netif_msg_link(cp)) {
- printk(KERN_INFO "%s: PCS link down.\n",
- cp->dev->name);
- }
+ if (cp->opened)
+ netif_info(cp, link, cp->dev, "PCS link down\n");
/* Cassini only: if you force a mode, there can be
* sync problems on link down. to fix that, the following
@@ -1139,9 +1130,8 @@ static int cas_txmac_interrupt(struct net_device *dev,
if (!txmac_stat)
return 0;
- if (netif_msg_intr(cp))
- printk(KERN_DEBUG "%s: txmac interrupt, txmac_stat: 0x%x\n",
- cp->dev->name, txmac_stat);
+ netif_printk(cp, intr, KERN_DEBUG, cp->dev,
+ "txmac interrupt, txmac_stat: 0x%x\n", txmac_stat);
/* Defer timer expiration is quite normal,
* don't even log the event.
@@ -1152,14 +1142,12 @@ static int cas_txmac_interrupt(struct net_device *dev,
spin_lock(&cp->stat_lock[0]);
if (txmac_stat & MAC_TX_UNDERRUN) {
- printk(KERN_ERR "%s: TX MAC xmit underrun.\n",
- dev->name);
+ netdev_err(dev, "TX MAC xmit underrun\n");
cp->net_stats[0].tx_fifo_errors++;
}
if (txmac_stat & MAC_TX_MAX_PACKET_ERR) {
- printk(KERN_ERR "%s: TX MAC max packet size error.\n",
- dev->name);
+ netdev_err(dev, "TX MAC max packet size error\n");
cp->net_stats[0].tx_errors++;
}
@@ -1487,8 +1475,7 @@ static int cas_rxmac_reset(struct cas *cp)
udelay(10);
}
if (limit == STOP_TRIES) {
- printk(KERN_ERR "%s: RX MAC will not disable, resetting whole "
- "chip.\n", dev->name);
+ netdev_err(dev, "RX MAC will not disable, resetting whole chip\n");
return 1;
}
@@ -1500,8 +1487,7 @@ static int cas_rxmac_reset(struct cas *cp)
udelay(10);
}
if (limit == STOP_TRIES) {
- printk(KERN_ERR "%s: RX DMA will not disable, resetting whole "
- "chip.\n", dev->name);
+ netdev_err(dev, "RX DMA will not disable, resetting whole chip\n");
return 1;
}
@@ -1515,8 +1501,7 @@ static int cas_rxmac_reset(struct cas *cp)
udelay(10);
}
if (limit == STOP_TRIES) {
- printk(KERN_ERR "%s: RX reset command will not execute, "
- "resetting whole chip.\n", dev->name);
+ netdev_err(dev, "RX reset command will not execute, resetting whole chip\n");
return 1;
}
@@ -1545,9 +1530,7 @@ static int cas_rxmac_interrupt(struct net_device *dev, struct cas *cp,
if (!stat)
return 0;
- if (netif_msg_intr(cp))
- printk(KERN_DEBUG "%s: rxmac interrupt, stat: 0x%x\n",
- cp->dev->name, stat);
+ netif_dbg(cp, intr, cp->dev, "rxmac interrupt, stat: 0x%x\n", stat);
/* these are all rollovers */
spin_lock(&cp->stat_lock[0]);
@@ -1580,9 +1563,8 @@ static int cas_mac_interrupt(struct net_device *dev, struct cas *cp,
if (!stat)
return 0;
- if (netif_msg_intr(cp))
- printk(KERN_DEBUG "%s: mac interrupt, stat: 0x%x\n",
- cp->dev->name, stat);
+ netif_printk(cp, intr, KERN_DEBUG, cp->dev,
+ "mac interrupt, stat: 0x%x\n", stat);
/* This interrupt is just for pause frame and pause
* tracking. It is useful for diagnostics and debug
@@ -1605,9 +1587,7 @@ static inline int cas_mdio_link_not_up(struct cas *cp)
switch (cp->lstate) {
case link_force_ret:
- if (netif_msg_link(cp))
- printk(KERN_INFO "%s: Autoneg failed again, keeping"
- " forced mode\n", cp->dev->name);
+ netif_info(cp, link, cp->dev, "Autoneg failed again, keeping forced mode\n");
cas_phy_write(cp, MII_BMCR, cp->link_fcntl);
cp->timer_ticks = 5;
cp->lstate = link_force_ok;
@@ -1675,9 +1655,9 @@ static int cas_mii_link_check(struct cas *cp, const u16 bmsr)
cas_mif_poll(cp, 0);
cp->link_fcntl = cas_phy_read(cp, MII_BMCR);
cp->timer_ticks = 5;
- if (cp->opened && netif_msg_link(cp))
- printk(KERN_INFO "%s: Got link after fallback, retrying"
- " autoneg once...\n", cp->dev->name);
+ if (cp->opened)
+ netif_info(cp, link, cp->dev,
+ "Got link after fallback, retrying autoneg once...\n");
cas_phy_write(cp, MII_BMCR,
cp->link_fcntl | BMCR_ANENABLE |
BMCR_ANRESTART);
@@ -1704,9 +1684,8 @@ static int cas_mii_link_check(struct cas *cp, const u16 bmsr)
cp->link_transition = LINK_TRANSITION_LINK_DOWN;
netif_carrier_off(cp->dev);
- if (cp->opened && netif_msg_link(cp))
- printk(KERN_INFO "%s: Link down\n",
- cp->dev->name);
+ if (cp->opened)
+ netif_info(cp, link, cp->dev, "Link down\n");
restart = 1;
} else if (++cp->timer_ticks > 10)
@@ -1737,23 +1716,23 @@ static int cas_pci_interrupt(struct net_device *dev, struct cas *cp,
if (!stat)
return 0;
- printk(KERN_ERR "%s: PCI error [%04x:%04x] ", dev->name, stat,
- readl(cp->regs + REG_BIM_DIAG));
+ netdev_err(dev, "PCI error [%04x:%04x]",
+ stat, readl(cp->regs + REG_BIM_DIAG));
/* cassini+ has this reserved */
if ((stat & PCI_ERR_BADACK) &&
((cp->cas_flags & CAS_FLAG_REG_PLUS) == 0))
- printk("<No ACK64# during ABS64 cycle> ");
+ pr_cont(" <No ACK64# during ABS64 cycle>");
if (stat & PCI_ERR_DTRTO)
- printk("<Delayed transaction timeout> ");
+ pr_cont(" <Delayed transaction timeout>");
if (stat & PCI_ERR_OTHER)
- printk("<other> ");
+ pr_cont(" <other>");
if (stat & PCI_ERR_BIM_DMA_WRITE)
- printk("<BIM DMA 0 write req> ");
+ pr_cont(" <BIM DMA 0 write req>");
if (stat & PCI_ERR_BIM_DMA_READ)
- printk("<BIM DMA 0 read req> ");
- printk("\n");
+ pr_cont(" <BIM DMA 0 read req>");
+ pr_cont("\n");
if (stat & PCI_ERR_OTHER) {
u16 cfg;
@@ -1762,25 +1741,19 @@ static int cas_pci_interrupt(struct net_device *dev, struct cas *cp,
* true cause.
*/
pci_read_config_word(cp->pdev, PCI_STATUS, &cfg);
- printk(KERN_ERR "%s: Read PCI cfg space status [%04x]\n",
- dev->name, cfg);
+ netdev_err(dev, "Read PCI cfg space status [%04x]\n", cfg);
if (cfg & PCI_STATUS_PARITY)
- printk(KERN_ERR "%s: PCI parity error detected.\n",
- dev->name);
+ netdev_err(dev, "PCI parity error detected\n");
if (cfg & PCI_STATUS_SIG_TARGET_ABORT)
- printk(KERN_ERR "%s: PCI target abort.\n",
- dev->name);
+ netdev_err(dev, "PCI target abort\n");
if (cfg & PCI_STATUS_REC_TARGET_ABORT)
- printk(KERN_ERR "%s: PCI master acks target abort.\n",
- dev->name);
+ netdev_err(dev, "PCI master acks target abort\n");
if (cfg & PCI_STATUS_REC_MASTER_ABORT)
- printk(KERN_ERR "%s: PCI master abort.\n", dev->name);
+ netdev_err(dev, "PCI master abort\n");
if (cfg & PCI_STATUS_SIG_SYSTEM_ERROR)
- printk(KERN_ERR "%s: PCI system error SERR#.\n",
- dev->name);
+ netdev_err(dev, "PCI system error SERR#\n");
if (cfg & PCI_STATUS_DETECTED_PARITY)
- printk(KERN_ERR "%s: PCI parity error.\n",
- dev->name);
+ netdev_err(dev, "PCI parity error\n");
/* Write the error bits back to clear them. */
cfg &= (PCI_STATUS_PARITY |
@@ -1806,9 +1779,8 @@ static int cas_abnormal_irq(struct net_device *dev, struct cas *cp,
{
if (status & INTR_RX_TAG_ERROR) {
/* corrupt RX tag framing */
- if (netif_msg_rx_err(cp))
- printk(KERN_DEBUG "%s: corrupt rx tag framing\n",
- cp->dev->name);
+ netif_printk(cp, rx_err, KERN_DEBUG, cp->dev,
+ "corrupt rx tag framing\n");
spin_lock(&cp->stat_lock[0]);
cp->net_stats[0].rx_errors++;
spin_unlock(&cp->stat_lock[0]);
@@ -1817,9 +1789,8 @@ static int cas_abnormal_irq(struct net_device *dev, struct cas *cp,
if (status & INTR_RX_LEN_MISMATCH) {
/* length mismatch. */
- if (netif_msg_rx_err(cp))
- printk(KERN_DEBUG "%s: length mismatch for rx frame\n",
- cp->dev->name);
+ netif_printk(cp, rx_err, KERN_DEBUG, cp->dev,
+ "length mismatch for rx frame\n");
spin_lock(&cp->stat_lock[0]);
cp->net_stats[0].rx_errors++;
spin_unlock(&cp->stat_lock[0]);
@@ -1861,12 +1832,11 @@ do_reset:
#if 1
atomic_inc(&cp->reset_task_pending);
atomic_inc(&cp->reset_task_pending_all);
- printk(KERN_ERR "%s:reset called in cas_abnormal_irq [0x%x]\n",
- dev->name, status);
+ netdev_err(dev, "reset called in cas_abnormal_irq [0x%x]\n", status);
schedule_work(&cp->reset_task);
#else
atomic_set(&cp->reset_task_pending, CAS_RESET_ALL);
- printk(KERN_ERR "reset called in cas_abnormal_irq\n");
+ netdev_err(dev, "reset called in cas_abnormal_irq\n");
schedule_work(&cp->reset_task);
#endif
return 1;
@@ -1920,9 +1890,8 @@ static inline void cas_tx_ringN(struct cas *cp, int ring, int limit)
if (count < 0)
break;
- if (netif_msg_tx_done(cp))
- printk(KERN_DEBUG "%s: tx[%d] done, slot %d\n",
- cp->dev->name, ring, entry);
+ netif_printk(cp, tx_done, KERN_DEBUG, cp->dev,
+ "tx[%d] done, slot %d\n", ring, entry);
skbs[entry] = NULL;
cp->tx_tiny_use[ring][entry].nbufs = 0;
@@ -1969,9 +1938,9 @@ static void cas_tx(struct net_device *dev, struct cas *cp,
#ifdef USE_TX_COMPWB
u64 compwb = le64_to_cpu(cp->init_block->tx_compwb);
#endif
- if (netif_msg_intr(cp))
- printk(KERN_DEBUG "%s: tx interrupt, status: 0x%x, %llx\n",
- cp->dev->name, status, (unsigned long long)compwb);
+ netif_printk(cp, intr, KERN_DEBUG, cp->dev,
+ "tx interrupt, status: 0x%x, %llx\n",
+ status, (unsigned long long)compwb);
/* process all the rings */
for (ring = 0; ring < N_TX_RINGS; ring++) {
#ifdef USE_TX_COMPWB
@@ -2050,10 +2019,8 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
hlen = min(cp->page_size - off, dlen);
if (hlen < 0) {
- if (netif_msg_rx_err(cp)) {
- printk(KERN_DEBUG "%s: rx page overflow: "
- "%d\n", cp->dev->name, hlen);
- }
+ netif_printk(cp, rx_err, KERN_DEBUG, cp->dev,
+ "rx page overflow: %d\n", hlen);
dev_kfree_skb_irq(skb);
return -1;
}
@@ -2130,10 +2097,8 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
off = CAS_VAL(RX_COMP1_DATA_OFF, words[0]) + swivel;
hlen = min(cp->page_size - off, dlen);
if (hlen < 0) {
- if (netif_msg_rx_err(cp)) {
- printk(KERN_DEBUG "%s: rx page overflow: "
- "%d\n", cp->dev->name, hlen);
- }
+ netif_printk(cp, rx_err, KERN_DEBUG, cp->dev,
+ "rx page overflow: %d\n", hlen);
dev_kfree_skb_irq(skb);
return -1;
}
@@ -2265,9 +2230,8 @@ static int cas_post_rxds_ringN(struct cas *cp, int ring, int num)
entry = cp->rx_old[ring];
- if (netif_msg_intr(cp))
- printk(KERN_DEBUG "%s: rxd[%d] interrupt, done: %d\n",
- cp->dev->name, ring, entry);
+ netif_printk(cp, intr, KERN_DEBUG, cp->dev,
+ "rxd[%d] interrupt, done: %d\n", ring, entry);
cluster = -1;
count = entry & 0x3;
@@ -2337,11 +2301,10 @@ static int cas_rx_ringN(struct cas *cp, int ring, int budget)
int entry, drops;
int npackets = 0;
- if (netif_msg_intr(cp))
- printk(KERN_DEBUG "%s: rx[%d] interrupt, done: %d/%d\n",
- cp->dev->name, ring,
- readl(cp->regs + REG_RX_COMP_HEAD),
- cp->rx_new[ring]);
+ netif_printk(cp, intr, KERN_DEBUG, cp->dev,
+ "rx[%d] interrupt, done: %d/%d\n",
+ ring,
+ readl(cp->regs + REG_RX_COMP_HEAD), cp->rx_new[ring]);
entry = cp->rx_new[ring];
drops = 0;
@@ -2442,8 +2405,7 @@ static int cas_rx_ringN(struct cas *cp, int ring, int budget)
cp->rx_new[ring] = entry;
if (drops)
- printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n",
- cp->dev->name);
+ netdev_info(cp->dev, "Memory squeeze, deferring packet\n");
return npackets;
}
@@ -2457,10 +2419,9 @@ static void cas_post_rxcs_ringN(struct net_device *dev,
last = cp->rx_cur[ring];
entry = cp->rx_new[ring];
- if (netif_msg_intr(cp))
- printk(KERN_DEBUG "%s: rxc[%d] interrupt, done: %d/%d\n",
- dev->name, ring, readl(cp->regs + REG_RX_COMP_HEAD),
- entry);
+ netif_printk(cp, intr, KERN_DEBUG, dev,
+ "rxc[%d] interrupt, done: %d/%d\n",
+ ring, readl(cp->regs + REG_RX_COMP_HEAD), entry);
/* zero and re-mark descriptors */
while (last != entry) {
@@ -2729,42 +2690,38 @@ static void cas_tx_timeout(struct net_device *dev)
{
struct cas *cp = netdev_priv(dev);
- printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
+ netdev_err(dev, "transmit timed out, resetting\n");
if (!cp->hw_running) {
- printk("%s: hrm.. hw not running!\n", dev->name);
+ netdev_err(dev, "hrm.. hw not running!\n");
return;
}
- printk(KERN_ERR "%s: MIF_STATE[%08x]\n",
- dev->name, readl(cp->regs + REG_MIF_STATE_MACHINE));
-
- printk(KERN_ERR "%s: MAC_STATE[%08x]\n",
- dev->name, readl(cp->regs + REG_MAC_STATE_MACHINE));
-
- printk(KERN_ERR "%s: TX_STATE[%08x:%08x:%08x] "
- "FIFO[%08x:%08x:%08x] SM1[%08x] SM2[%08x]\n",
- dev->name,
- readl(cp->regs + REG_TX_CFG),
- readl(cp->regs + REG_MAC_TX_STATUS),
- readl(cp->regs + REG_MAC_TX_CFG),
- readl(cp->regs + REG_TX_FIFO_PKT_CNT),
- readl(cp->regs + REG_TX_FIFO_WRITE_PTR),
- readl(cp->regs + REG_TX_FIFO_READ_PTR),
- readl(cp->regs + REG_TX_SM_1),
- readl(cp->regs + REG_TX_SM_2));
-
- printk(KERN_ERR "%s: RX_STATE[%08x:%08x:%08x]\n",
- dev->name,
- readl(cp->regs + REG_RX_CFG),
- readl(cp->regs + REG_MAC_RX_STATUS),
- readl(cp->regs + REG_MAC_RX_CFG));
-
- printk(KERN_ERR "%s: HP_STATE[%08x:%08x:%08x:%08x]\n",
- dev->name,
- readl(cp->regs + REG_HP_STATE_MACHINE),
- readl(cp->regs + REG_HP_STATUS0),
- readl(cp->regs + REG_HP_STATUS1),
- readl(cp->regs + REG_HP_STATUS2));
+ netdev_err(dev, "MIF_STATE[%08x]\n",
+ readl(cp->regs + REG_MIF_STATE_MACHINE));
+
+ netdev_err(dev, "MAC_STATE[%08x]\n",
+ readl(cp->regs + REG_MAC_STATE_MACHINE));
+
+ netdev_err(dev, "TX_STATE[%08x:%08x:%08x] FIFO[%08x:%08x:%08x] SM1[%08x] SM2[%08x]\n",
+ readl(cp->regs + REG_TX_CFG),
+ readl(cp->regs + REG_MAC_TX_STATUS),
+ readl(cp->regs + REG_MAC_TX_CFG),
+ readl(cp->regs + REG_TX_FIFO_PKT_CNT),
+ readl(cp->regs + REG_TX_FIFO_WRITE_PTR),
+ readl(cp->regs + REG_TX_FIFO_READ_PTR),
+ readl(cp->regs + REG_TX_SM_1),
+ readl(cp->regs + REG_TX_SM_2));
+
+ netdev_err(dev, "RX_STATE[%08x:%08x:%08x]\n",
+ readl(cp->regs + REG_RX_CFG),
+ readl(cp->regs + REG_MAC_RX_STATUS),
+ readl(cp->regs + REG_MAC_RX_CFG));
+
+ netdev_err(dev, "HP_STATE[%08x:%08x:%08x:%08x]\n",
+ readl(cp->regs + REG_HP_STATE_MACHINE),
+ readl(cp->regs + REG_HP_STATUS0),
+ readl(cp->regs + REG_HP_STATUS1),
+ readl(cp->regs + REG_HP_STATUS2));
#if 1
atomic_inc(&cp->reset_task_pending);
@@ -2830,8 +2787,7 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
CAS_TABORT(cp)*(skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev);
spin_unlock_irqrestore(&cp->tx_lock[ring], flags);
- printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
- "queue awake!\n", dev->name);
+ netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
return 1;
}
@@ -2908,11 +2864,9 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
if (TX_BUFFS_AVAIL(cp, ring) <= CAS_TABORT(cp)*(MAX_SKB_FRAGS + 1))
netif_stop_queue(dev);
- if (netif_msg_tx_queued(cp))
- printk(KERN_DEBUG "%s: tx[%d] queued, slot %d, skblen %d, "
- "avail %d\n",
- dev->name, ring, entry, skb->len,
- TX_BUFFS_AVAIL(cp, ring));
+ netif_printk(cp, tx_queued, KERN_DEBUG, dev,
+ "tx[%d] queued, slot %d, skblen %d, avail %d\n",
+ ring, entry, skb->len, TX_BUFFS_AVAIL(cp, ring));
writel(entry, cp->regs + REG_TX_KICKN(ring));
spin_unlock_irqrestore(&cp->tx_lock[ring], flags);
return 0;
@@ -2999,6 +2953,40 @@ static inline void cas_init_dma(struct cas *cp)
cas_init_rx_dma(cp);
}
+static void cas_process_mc_list(struct cas *cp)
+{
+ u16 hash_table[16];
+ u32 crc;
+ struct dev_mc_list *dmi;
+ int i = 1;
+
+ memset(hash_table, 0, sizeof(hash_table));
+ netdev_for_each_mc_addr(dmi, cp->dev) {
+ if (i <= CAS_MC_EXACT_MATCH_SIZE) {
+ /* use the alternate mac address registers for the
+ * first 15 multicast addresses
+ */
+ writel((dmi->dmi_addr[4] << 8) | dmi->dmi_addr[5],
+ cp->regs + REG_MAC_ADDRN(i*3 + 0));
+ writel((dmi->dmi_addr[2] << 8) | dmi->dmi_addr[3],
+ cp->regs + REG_MAC_ADDRN(i*3 + 1));
+ writel((dmi->dmi_addr[0] << 8) | dmi->dmi_addr[1],
+ cp->regs + REG_MAC_ADDRN(i*3 + 2));
+ i++;
+ }
+ else {
+ /* use hw hash table for the next series of
+ * multicast addresses
+ */
+ crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr);
+ crc >>= 24;
+ hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
+ }
+ }
+ for (i = 0; i < 16; i++)
+ writel(hash_table[i], cp->regs + REG_MAC_HASH_TABLEN(i));
+}
+
/* Must be invoked under cp->lock. */
static u32 cas_setup_multicast(struct cas *cp)
{
@@ -3014,43 +3002,7 @@ static u32 cas_setup_multicast(struct cas *cp)
rxcfg |= MAC_RX_CFG_HASH_FILTER_EN;
} else {
- u16 hash_table[16];
- u32 crc;
- struct dev_mc_list *dmi = cp->dev->mc_list;
- int i;
-
- /* use the alternate mac address registers for the
- * first 15 multicast addresses
- */
- for (i = 1; i <= CAS_MC_EXACT_MATCH_SIZE; i++) {
- if (!dmi) {
- writel(0x0, cp->regs + REG_MAC_ADDRN(i*3 + 0));
- writel(0x0, cp->regs + REG_MAC_ADDRN(i*3 + 1));
- writel(0x0, cp->regs + REG_MAC_ADDRN(i*3 + 2));
- continue;
- }
- writel((dmi->dmi_addr[4] << 8) | dmi->dmi_addr[5],
- cp->regs + REG_MAC_ADDRN(i*3 + 0));
- writel((dmi->dmi_addr[2] << 8) | dmi->dmi_addr[3],
- cp->regs + REG_MAC_ADDRN(i*3 + 1));
- writel((dmi->dmi_addr[0] << 8) | dmi->dmi_addr[1],
- cp->regs + REG_MAC_ADDRN(i*3 + 2));
- dmi = dmi->next;
- }
-
- /* use hw hash table for the next series of
- * multicast addresses
- */
- memset(hash_table, 0, sizeof(hash_table));
- while (dmi) {
- crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr);
- crc >>= 24;
- hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
- dmi = dmi->next;
- }
- for (i=0; i < 16; i++)
- writel(hash_table[i], cp->regs +
- REG_MAC_HASH_TABLEN(i));
+ cas_process_mc_list(cp);
rxcfg |= MAC_RX_CFG_HASH_FILTER_EN;
}
@@ -3100,10 +3052,10 @@ static void cas_mac_reset(struct cas *cp)
if (readl(cp->regs + REG_MAC_TX_RESET) |
readl(cp->regs + REG_MAC_RX_RESET))
- printk(KERN_ERR "%s: mac tx[%d]/rx[%d] reset failed [%08x]\n",
- cp->dev->name, readl(cp->regs + REG_MAC_TX_RESET),
- readl(cp->regs + REG_MAC_RX_RESET),
- readl(cp->regs + REG_MAC_STATE_MACHINE));
+ netdev_err(cp->dev, "mac tx[%d]/rx[%d] reset failed [%08x]\n",
+ readl(cp->regs + REG_MAC_TX_RESET),
+ readl(cp->regs + REG_MAC_RX_RESET),
+ readl(cp->regs + REG_MAC_STATE_MACHINE));
}
@@ -3423,7 +3375,7 @@ use_random_mac_addr:
goto done;
/* Sun MAC prefix then 3 random bytes. */
- printk(PFX "MAC address not found in ROM VPD\n");
+ pr_info("MAC address not found in ROM VPD\n");
dev_addr[0] = 0x08;
dev_addr[1] = 0x00;
dev_addr[2] = 0x20;
@@ -3484,7 +3436,7 @@ static int cas_check_invariants(struct cas *cp)
__free_pages(page, CAS_JUMBO_PAGE_SHIFT - PAGE_SHIFT);
cp->page_order = CAS_JUMBO_PAGE_SHIFT - PAGE_SHIFT;
} else {
- printk(PFX "MTU limited to %d bytes\n", CAS_MAX_MTU);
+ printk("MTU limited to %d bytes\n", CAS_MAX_MTU);
}
}
#endif
@@ -3529,7 +3481,7 @@ static int cas_check_invariants(struct cas *cp)
}
}
}
- printk(KERN_ERR PFX "MII phy did not respond [%08x]\n",
+ pr_err("MII phy did not respond [%08x]\n",
readl(cp->regs + REG_MIF_STATE_MACHINE));
return -1;
@@ -3574,21 +3526,19 @@ static inline void cas_start_dma(struct cas *cp)
val = readl(cp->regs + REG_MAC_RX_CFG);
if ((val & MAC_RX_CFG_EN)) {
if (txfailed) {
- printk(KERN_ERR
- "%s: enabling mac failed [tx:%08x:%08x].\n",
- cp->dev->name,
- readl(cp->regs + REG_MIF_STATE_MACHINE),
- readl(cp->regs + REG_MAC_STATE_MACHINE));
+ netdev_err(cp->dev,
+ "enabling mac failed [tx:%08x:%08x]\n",
+ readl(cp->regs + REG_MIF_STATE_MACHINE),
+ readl(cp->regs + REG_MAC_STATE_MACHINE));
}
goto enable_rx_done;
}
udelay(10);
}
- printk(KERN_ERR "%s: enabling mac failed [%s:%08x:%08x].\n",
- cp->dev->name,
- (txfailed? "tx,rx":"rx"),
- readl(cp->regs + REG_MIF_STATE_MACHINE),
- readl(cp->regs + REG_MAC_STATE_MACHINE));
+ netdev_err(cp->dev, "enabling mac failed [%s:%08x:%08x]\n",
+ (txfailed ? "tx,rx" : "rx"),
+ readl(cp->regs + REG_MIF_STATE_MACHINE),
+ readl(cp->regs + REG_MAC_STATE_MACHINE));
enable_rx_done:
cas_unmask_intr(cp); /* enable interrupts */
@@ -3690,9 +3640,8 @@ static void cas_set_link_modes(struct cas *cp)
}
}
- if (netif_msg_link(cp))
- printk(KERN_INFO "%s: Link up at %d Mbps, %s-duplex.\n",
- cp->dev->name, speed, (full_duplex ? "full" : "half"));
+ netif_info(cp, link, cp->dev, "Link up at %d Mbps, %s-duplex\n",
+ speed, full_duplex ? "full" : "half");
val = MAC_XIF_TX_MII_OUTPUT_EN | MAC_XIF_LINK_LED;
if (CAS_PHY_MII(cp->phy_type)) {
@@ -3762,18 +3711,14 @@ static void cas_set_link_modes(struct cas *cp)
if (netif_msg_link(cp)) {
if (pause & 0x01) {
- printk(KERN_INFO "%s: Pause is enabled "
- "(rxfifo: %d off: %d on: %d)\n",
- cp->dev->name,
- cp->rx_fifo_size,
- cp->rx_pause_off,
- cp->rx_pause_on);
+ netdev_info(cp->dev, "Pause is enabled (rxfifo: %d off: %d on: %d)\n",
+ cp->rx_fifo_size,
+ cp->rx_pause_off,
+ cp->rx_pause_on);
} else if (pause & 0x10) {
- printk(KERN_INFO "%s: TX pause enabled\n",
- cp->dev->name);
+ netdev_info(cp->dev, "TX pause enabled\n");
} else {
- printk(KERN_INFO "%s: Pause is disabled\n",
- cp->dev->name);
+ netdev_info(cp->dev, "Pause is disabled\n");
}
}
@@ -3849,7 +3794,7 @@ static void cas_global_reset(struct cas *cp, int blkflag)
goto done;
udelay(10);
}
- printk(KERN_ERR "%s: sw reset failed.\n", cp->dev->name);
+ netdev_err(cp->dev, "sw reset failed\n");
done:
/* enable various BIM interrupts */
@@ -3955,7 +3900,7 @@ static int cas_change_mtu(struct net_device *dev, int new_mtu)
#else
atomic_set(&cp->reset_task_pending, (cp->phy_type & CAS_PHY_SERDES) ?
CAS_RESET_ALL : CAS_RESET_MTU);
- printk(KERN_ERR "reset called in cas_change_mtu\n");
+ pr_err("reset called in cas_change_mtu\n");
schedule_work(&cp->reset_task);
#endif
@@ -4237,10 +4182,8 @@ static void cas_link_timer(unsigned long data)
if (((tlm == 0x5) || (tlm == 0x3)) &&
(CAS_VAL(MAC_SM_ENCAP_SM, val) == 0)) {
- if (netif_msg_tx_err(cp))
- printk(KERN_DEBUG "%s: tx err: "
- "MAC_STATE[%08x]\n",
- cp->dev->name, val);
+ netif_printk(cp, tx_err, KERN_DEBUG, cp->dev,
+ "tx err: MAC_STATE[%08x]\n", val);
reset = 1;
goto done;
}
@@ -4249,10 +4192,9 @@ static void cas_link_timer(unsigned long data)
wptr = readl(cp->regs + REG_TX_FIFO_WRITE_PTR);
rptr = readl(cp->regs + REG_TX_FIFO_READ_PTR);
if ((val == 0) && (wptr != rptr)) {
- if (netif_msg_tx_err(cp))
- printk(KERN_DEBUG "%s: tx err: "
- "TX_FIFO[%08x:%08x:%08x]\n",
- cp->dev->name, val, wptr, rptr);
+ netif_printk(cp, tx_err, KERN_DEBUG, cp->dev,
+ "tx err: TX_FIFO[%08x:%08x:%08x]\n",
+ val, wptr, rptr);
reset = 1;
}
@@ -4268,7 +4210,7 @@ done:
schedule_work(&cp->reset_task);
#else
atomic_set(&cp->reset_task_pending, CAS_RESET_ALL);
- printk(KERN_ERR "reset called in cas_link_timer\n");
+ pr_err("reset called in cas_link_timer\n");
schedule_work(&cp->reset_task);
#endif
}
@@ -4361,8 +4303,7 @@ static int cas_open(struct net_device *dev)
*/
if (request_irq(cp->pdev->irq, cas_interrupt,
IRQF_SHARED, dev->name, (void *) dev)) {
- printk(KERN_ERR "%s: failed to request irq !\n",
- cp->dev->name);
+ netdev_err(cp->dev, "failed to request irq !\n");
err = -EAGAIN;
goto err_spare;
}
@@ -5002,24 +4943,24 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
u8 orig_cacheline_size = 0, cas_cacheline_size = 0;
if (cas_version_printed++ == 0)
- printk(KERN_INFO "%s", version);
+ pr_info("%s", version);
err = pci_enable_device(pdev);
if (err) {
- dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
+ dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
return err;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
dev_err(&pdev->dev, "Cannot find proper PCI device "
- "base address, aborting.\n");
+ "base address, aborting\n");
err = -ENODEV;
goto err_out_disable_pdev;
}
dev = alloc_etherdev(sizeof(*cp));
if (!dev) {
- dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
+ dev_err(&pdev->dev, "Etherdev alloc failed, aborting\n");
err = -ENOMEM;
goto err_out_disable_pdev;
}
@@ -5027,7 +4968,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
err = pci_request_regions(pdev, dev->name);
if (err) {
- dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
+ dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
goto err_out_free_netdev;
}
pci_set_master(pdev);
@@ -5041,8 +4982,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
pci_cmd |= PCI_COMMAND_PARITY;
pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
if (pci_try_set_mwi(pdev))
- printk(KERN_WARNING PFX "Could not enable MWI for %s\n",
- pci_name(pdev));
+ pr_warning("Could not enable MWI for %s\n", pci_name(pdev));
cas_program_bridge(pdev);
@@ -5085,7 +5025,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (err) {
dev_err(&pdev->dev, "No usable DMA configuration, "
- "aborting.\n");
+ "aborting\n");
goto err_out_free_res;
}
pci_using_dac = 0;
@@ -5132,7 +5072,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
INIT_WORK(&cp->reset_task, cas_reset_task);
/* Default link parameters */
- if (link_mode >= 0 && link_mode <= 6)
+ if (link_mode >= 0 && link_mode < 6)
cp->link_cntl = link_modes[link_mode];
else
cp->link_cntl = BMCR_ANENABLE;
@@ -5144,7 +5084,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
/* give us access to cassini registers */
cp->regs = pci_iomap(pdev, 0, casreg_len);
if (!cp->regs) {
- dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
+ dev_err(&pdev->dev, "Cannot map device registers, aborting\n");
goto err_out_free_res;
}
cp->casreg_len = casreg_len;
@@ -5163,7 +5103,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
pci_alloc_consistent(pdev, sizeof(struct cas_init_block),
&cp->block_dvma);
if (!cp->init_block) {
- dev_err(&pdev->dev, "Cannot allocate init block, aborting.\n");
+ dev_err(&pdev->dev, "Cannot allocate init block, aborting\n");
goto err_out_iounmap;
}
@@ -5197,18 +5137,17 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
dev->features |= NETIF_F_HIGHDMA;
if (register_netdev(dev)) {
- dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
+ dev_err(&pdev->dev, "Cannot register net device, aborting\n");
goto err_out_free_consistent;
}
i = readl(cp->regs + REG_BIM_CFG);
- printk(KERN_INFO "%s: Sun Cassini%s (%sbit/%sMHz PCI/%s) "
- "Ethernet[%d] %pM\n", dev->name,
- (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "",
- (i & BIM_CFG_32BIT) ? "32" : "64",
- (i & BIM_CFG_66MHZ) ? "66" : "33",
- (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq,
- dev->dev_addr);
+ netdev_info(dev, "Sun Cassini%s (%sbit/%sMHz PCI/%s) Ethernet[%d] %pM\n",
+ (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "",
+ (i & BIM_CFG_32BIT) ? "32" : "64",
+ (i & BIM_CFG_66MHZ) ? "66" : "33",
+ (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq,
+ dev->dev_addr);
pci_set_drvdata(pdev, dev);
cp->hw_running = 1;
@@ -5322,7 +5261,7 @@ static int cas_resume(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct cas *cp = netdev_priv(dev);
- printk(KERN_INFO "%s: resuming\n", dev->name);
+ netdev_info(dev, "resuming\n");
mutex_lock(&cp->pm_mutex);
cas_hard_reset(cp);
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 699d22c5fe09..2d11afe45310 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -36,6 +36,8 @@
* *
****************************************************************************/
+#define pr_fmt(fmt) "cxgb: " fmt
+
#ifndef _CXGB_COMMON_H_
#define _CXGB_COMMON_H_
@@ -55,28 +57,6 @@
#define DRV_DESCRIPTION "Chelsio 10Gb Ethernet Driver"
#define DRV_NAME "cxgb"
#define DRV_VERSION "2.2"
-#define PFX DRV_NAME ": "
-
-#define CH_ERR(fmt, ...) printk(KERN_ERR PFX fmt, ## __VA_ARGS__)
-#define CH_WARN(fmt, ...) printk(KERN_WARNING PFX fmt, ## __VA_ARGS__)
-#define CH_ALERT(fmt, ...) printk(KERN_ALERT PFX fmt, ## __VA_ARGS__)
-
-/*
- * More powerful macro that selectively prints messages based on msg_enable.
- * For info and debugging messages.
- */
-#define CH_MSG(adapter, level, category, fmt, ...) do { \
- if ((adapter)->msg_enable & NETIF_MSG_##category) \
- printk(KERN_##level PFX "%s: " fmt, (adapter)->name, \
- ## __VA_ARGS__); \
-} while (0)
-
-#ifdef DEBUG
-# define CH_DBG(adapter, category, fmt, ...) \
- CH_MSG(adapter, DEBUG, category, fmt, ## __VA_ARGS__)
-#else
-# define CH_DBG(fmt, ...)
-#endif
#define CH_DEVICE(devid, ssid, idx) \
{ PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx }
@@ -90,25 +70,13 @@
typedef struct adapter adapter_t;
struct t1_rx_mode {
- struct net_device *dev;
- u32 idx;
- struct dev_mc_list *list;
+ struct net_device *dev;
};
#define t1_rx_mode_promisc(rm) (rm->dev->flags & IFF_PROMISC)
#define t1_rx_mode_allmulti(rm) (rm->dev->flags & IFF_ALLMULTI)
-#define t1_rx_mode_mc_cnt(rm) (rm->dev->mc_count)
-
-static inline u8 *t1_get_next_mcaddr(struct t1_rx_mode *rm)
-{
- u8 *addr = NULL;
-
- if (rm->idx++ < rm->dev->mc_count) {
- addr = rm->list->dmi_addr;
- rm->list = rm->list->next;
- }
- return addr;
-}
+#define t1_rx_mode_mc_cnt(rm) (netdev_mc_count(rm->dev))
+#define t1_get_netdev(rm) (rm->dev)
#define MAX_NPORTS 4
#define PORT_MASK ((1 << MAX_NPORTS) - 1)
@@ -334,7 +302,7 @@ static inline int t1_is_asic(const adapter_t *adapter)
return adapter->params.is_asic;
}
-extern struct pci_device_id t1_pci_tbl[];
+extern const struct pci_device_id t1_pci_tbl[];
static inline int adapter_matches_type(const adapter_t *adapter,
int version, int revision)
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index 082cdb28b510..0f71304e0542 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -125,8 +125,6 @@ static void t1_set_rxmode(struct net_device *dev)
struct t1_rx_mode rm;
rm.dev = dev;
- rm.idx = 0;
- rm.list = dev->mc_list;
mac->ops->set_rx_mode(mac, &rm);
}
@@ -976,7 +974,7 @@ void t1_fatal_err(struct adapter *adapter)
t1_sge_stop(adapter->sge);
t1_interrupts_disable(adapter);
}
- CH_ALERT("%s: encountered fatal error, operation suspended\n",
+ pr_alert("%s: encountered fatal error, operation suspended\n",
adapter->name);
}
@@ -1020,7 +1018,7 @@ static int __devinit init_one(struct pci_dev *pdev,
return err;
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- CH_ERR("%s: cannot find PCI device memory base address\n",
+ pr_err("%s: cannot find PCI device memory base address\n",
pci_name(pdev));
err = -ENODEV;
goto out_disable_pdev;
@@ -1030,20 +1028,20 @@ static int __devinit init_one(struct pci_dev *pdev,
pci_using_dac = 1;
if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
- CH_ERR("%s: unable to obtain 64-bit DMA for "
+ pr_err("%s: unable to obtain 64-bit DMA for "
"consistent allocations\n", pci_name(pdev));
err = -ENODEV;
goto out_disable_pdev;
}
} else if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
- CH_ERR("%s: no usable DMA configuration\n", pci_name(pdev));
+ pr_err("%s: no usable DMA configuration\n", pci_name(pdev));
goto out_disable_pdev;
}
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
- CH_ERR("%s: cannot obtain PCI resources\n", pci_name(pdev));
+ pr_err("%s: cannot obtain PCI resources\n", pci_name(pdev));
goto out_disable_pdev;
}
@@ -1071,7 +1069,7 @@ static int __devinit init_one(struct pci_dev *pdev,
adapter->regs = ioremap(mmio_start, mmio_len);
if (!adapter->regs) {
- CH_ERR("%s: cannot map device registers\n",
+ pr_err("%s: cannot map device registers\n",
pci_name(pdev));
err = -ENOMEM;
goto out_free_dev;
@@ -1150,8 +1148,8 @@ static int __devinit init_one(struct pci_dev *pdev,
for (i = 0; i < bi->port_number; ++i) {
err = register_netdev(adapter->port[i].dev);
if (err)
- CH_WARN("%s: cannot register net device %s, skipping\n",
- pci_name(pdev), adapter->port[i].dev->name);
+ pr_warning("%s: cannot register net device %s, skipping\n",
+ pci_name(pdev), adapter->port[i].dev->name);
else {
/*
* Change the name we use for messages to the name of
@@ -1164,7 +1162,7 @@ static int __devinit init_one(struct pci_dev *pdev,
}
}
if (!adapter->registered_device_map) {
- CH_ERR("%s: could not register any net devices\n",
+ pr_err("%s: could not register any net devices\n",
pci_name(pdev));
goto out_release_adapter_res;
}
diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c
index 1e0749e000b0..639ff1955739 100644
--- a/drivers/net/chelsio/espi.c
+++ b/drivers/net/chelsio/espi.c
@@ -76,7 +76,7 @@ static int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr,
} while (busy && --attempts);
if (busy)
- CH_ERR("%s: TRICN write timed out\n", adapter->name);
+ pr_err("%s: TRICN write timed out\n", adapter->name);
return busy;
}
@@ -86,7 +86,7 @@ static int tricn_init(adapter_t *adapter)
int i, sme = 1;
if (!(readl(adapter->regs + A_ESPI_RX_RESET) & F_RX_CLK_STATUS)) {
- CH_ERR("%s: ESPI clock not ready\n", adapter->name);
+ pr_err("%s: ESPI clock not ready\n", adapter->name);
return -1;
}
diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c
index 2117c4fbb107..a6eb30a6e2b9 100644
--- a/drivers/net/chelsio/pm3393.c
+++ b/drivers/net/chelsio/pm3393.c
@@ -251,8 +251,9 @@ static int pm3393_interrupt_handler(struct cmac *cmac)
/* Read the master interrupt status register. */
pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS,
&master_intr_status);
- CH_DBG(cmac->adapter, INTR, "PM3393 intr cause 0x%x\n",
- master_intr_status);
+ if (netif_msg_intr(cmac->adapter))
+ dev_dbg(&cmac->adapter->pdev->dev, "PM3393 intr cause 0x%x\n",
+ master_intr_status);
/* TBD XXX Lets just clear everything for now */
pm3393_interrupt_clear(cmac);
@@ -375,12 +376,12 @@ static int pm3393_set_rx_mode(struct cmac *cmac, struct t1_rx_mode *rm)
rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN;
} else if (t1_rx_mode_mc_cnt(rm)) {
/* Accept one or more multicast(s). */
- u8 *addr;
+ struct dev_mc_list *dmi;
int bit;
u16 mc_filter[4] = { 0, };
- while ((addr = t1_get_next_mcaddr(rm))) {
- bit = (ether_crc(ETH_ALEN, addr) >> 23) & 0x3f; /* bit[23:28] */
+ netdev_for_each_mc_addr(dmi, t1_get_netdev(rm)) {
+ bit = (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 23) & 0x3f; /* bit[23:28] */
mc_filter[bit >> 4] |= 1 << (bit & 0xf);
}
pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, mc_filter[0]);
@@ -776,11 +777,12 @@ static int pm3393_mac_reset(adapter_t * adapter)
successful_reset = (is_pl4_reset_finished && !is_pl4_outof_lock
&& is_xaui_mabc_pll_locked);
- CH_DBG(adapter, HW,
- "PM3393 HW reset %d: pl4_reset 0x%x, val 0x%x, "
- "is_pl4_outof_lock 0x%x, xaui_locked 0x%x\n",
- i, is_pl4_reset_finished, val, is_pl4_outof_lock,
- is_xaui_mabc_pll_locked);
+ if (netif_msg_hw(adapter))
+ dev_dbg(&adapter->pdev->dev,
+ "PM3393 HW reset %d: pl4_reset 0x%x, val 0x%x, "
+ "is_pl4_outof_lock 0x%x, xaui_locked 0x%x\n",
+ i, is_pl4_reset_finished, val,
+ is_pl4_outof_lock, is_xaui_mabc_pll_locked);
}
return successful_reset ? 0 : 1;
}
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 109d2783e4d8..55d99ca82f8a 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -248,7 +248,7 @@ static void restart_sched(unsigned long);
*
* Interrupts are handled by a single CPU and it is likely that on a MP system
* the application is migrated to another CPU. In that scenario, we try to
- * seperate the RX(in irq context) and TX state in order to decrease memory
+ * separate the RX(in irq context) and TX state in order to decrease memory
* contention.
*/
struct sge {
@@ -267,7 +267,7 @@ struct sge {
struct sk_buff *espibug_skb[MAX_NPORTS];
u32 sge_control; /* shadow value of sge control reg */
struct sge_intr_counts stats;
- struct sge_port_stats *port_stats[MAX_NPORTS];
+ struct sge_port_stats __percpu *port_stats[MAX_NPORTS];
struct sched *tx_sched;
struct cmdQ cmdQ[SGE_CMDQ_N] ____cacheline_aligned_in_smp;
};
@@ -953,7 +953,7 @@ int t1_sge_intr_error_handler(struct sge *sge)
sge->stats.respQ_empty++;
if (cause & F_RESPQ_OVERFLOW) {
sge->stats.respQ_overflow++;
- CH_ALERT("%s: SGE response queue overflow\n",
+ pr_alert("%s: SGE response queue overflow\n",
adapter->name);
}
if (cause & F_FL_EXHAUSTED) {
@@ -962,12 +962,12 @@ int t1_sge_intr_error_handler(struct sge *sge)
}
if (cause & F_PACKET_TOO_BIG) {
sge->stats.pkt_too_big++;
- CH_ALERT("%s: SGE max packet size exceeded\n",
+ pr_alert("%s: SGE max packet size exceeded\n",
adapter->name);
}
if (cause & F_PACKET_MISMATCH) {
sge->stats.pkt_mismatch++;
- CH_ALERT("%s: SGE packet mismatch\n", adapter->name);
+ pr_alert("%s: SGE packet mismatch\n", adapter->name);
}
if (cause & SGE_INT_FATAL)
t1_fatal_err(adapter);
@@ -1101,7 +1101,7 @@ static void unexpected_offload(struct adapter *adapter, struct freelQ *fl)
pci_dma_sync_single_for_cpu(adapter->pdev, pci_unmap_addr(ce, dma_addr),
pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE);
- CH_ERR("%s: unexpected offload packet, cmd %u\n",
+ pr_err("%s: unexpected offload packet, cmd %u\n",
adapter->name, *skb->data);
recycle_fl_buf(fl, fl->cidx);
}
@@ -1687,7 +1687,7 @@ static int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter,
netif_stop_queue(dev);
set_bit(dev->if_port, &sge->stopped_tx_queues);
sge->stats.cmdQ_full[2]++;
- CH_ERR("%s: Tx ring full while queue awake!\n",
+ pr_err("%s: Tx ring full while queue awake!\n",
adapter->name);
}
spin_unlock(&q->lock);
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index 17720c6e5bfe..53bde15fc94d 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -90,7 +90,7 @@ int __t1_tpi_write(adapter_t *adapter, u32 addr, u32 value)
tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1,
TPI_ATTEMPTS, 3);
if (tpi_busy)
- CH_ALERT("%s: TPI write to 0x%x failed\n",
+ pr_alert("%s: TPI write to 0x%x failed\n",
adapter->name, addr);
return tpi_busy;
}
@@ -118,7 +118,7 @@ int __t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp)
tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1,
TPI_ATTEMPTS, 3);
if (tpi_busy)
- CH_ALERT("%s: TPI read from 0x%x failed\n",
+ pr_alert("%s: TPI read from 0x%x failed\n",
adapter->name, addr);
else
*valp = readl(adapter->regs + A_TPI_RD_DATA);
@@ -262,7 +262,7 @@ static int mi1_wait_until_ready(adapter_t *adapter, int mi1_reg)
udelay(10);
} while (busy && --attempts);
if (busy)
- CH_ALERT("%s: MDIO operation timed out\n", adapter->name);
+ pr_alert("%s: MDIO operation timed out\n", adapter->name);
return busy;
}
@@ -528,7 +528,7 @@ static const struct board_info t1_board[] = {
};
-struct pci_device_id t1_pci_tbl[] = {
+DEFINE_PCI_DEVICE_TABLE(t1_pci_tbl) = {
CH_DEVICE(8, 0, CH_BRD_T110_1CU),
CH_DEVICE(8, 1, CH_BRD_T110_1CU),
CH_DEVICE(7, 0, CH_BRD_N110_1F),
@@ -581,7 +581,7 @@ int t1_seeprom_read(adapter_t *adapter, u32 addr, __le32 *data)
} while (!(val & F_VPD_OP_FLAG) && --i);
if (!(val & F_VPD_OP_FLAG)) {
- CH_ERR("%s: reading EEPROM address 0x%x failed\n",
+ pr_err("%s: reading EEPROM address 0x%x failed\n",
adapter->name, addr);
return -EIO;
}
@@ -734,8 +734,9 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
break;
case CHBT_BOARD_8000:
case CHBT_BOARD_CHT110:
- CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n",
- cause);
+ if (netif_msg_intr(adapter))
+ dev_dbg(&adapter->pdev->dev,
+ "External interrupt cause 0x%x\n", cause);
if (cause & ELMER0_GP_BIT1) { /* PMC3393 INTB */
struct cmac *mac = adapter->port[0].mac;
@@ -746,8 +747,9 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
t1_tpi_read(adapter,
A_ELMER0_GPI_STAT, &mod_detect);
- CH_MSG(adapter, INFO, LINK, "XPAK %s\n",
- mod_detect ? "removed" : "inserted");
+ if (netif_msg_link(adapter))
+ dev_info(&adapter->pdev->dev, "XPAK %s\n",
+ mod_detect ? "removed" : "inserted");
}
break;
#ifdef CONFIG_CHELSIO_T1_COUGAR
@@ -1084,7 +1086,7 @@ static void __devinit init_link_config(struct link_config *lc,
#ifdef CONFIG_CHELSIO_T1_COUGAR
if (bi->clock_cspi && !(adapter->cspi = t1_cspi_create(adapter))) {
- CH_ERR("%s: CSPI initialization failed\n",
+ pr_err("%s: CSPI initialization failed\n",
adapter->name);
goto error;
}
@@ -1105,20 +1107,20 @@ int __devinit t1_init_sw_modules(adapter_t *adapter,
adapter->sge = t1_sge_create(adapter, &adapter->params.sge);
if (!adapter->sge) {
- CH_ERR("%s: SGE initialization failed\n",
+ pr_err("%s: SGE initialization failed\n",
adapter->name);
goto error;
}
if (bi->espi_nports && !(adapter->espi = t1_espi_create(adapter))) {
- CH_ERR("%s: ESPI initialization failed\n",
+ pr_err("%s: ESPI initialization failed\n",
adapter->name);
goto error;
}
adapter->tp = t1_tp_create(adapter, &adapter->params.tp);
if (!adapter->tp) {
- CH_ERR("%s: TP initialization failed\n",
+ pr_err("%s: TP initialization failed\n",
adapter->name);
goto error;
}
@@ -1138,14 +1140,14 @@ int __devinit t1_init_sw_modules(adapter_t *adapter,
adapter->port[i].phy = bi->gphy->create(adapter->port[i].dev,
phy_addr, bi->mdio_ops);
if (!adapter->port[i].phy) {
- CH_ERR("%s: PHY %d initialization failed\n",
+ pr_err("%s: PHY %d initialization failed\n",
adapter->name, i);
goto error;
}
adapter->port[i].mac = mac = bi->gmac->create(adapter, i);
if (!mac) {
- CH_ERR("%s: MAC %d initialization failed\n",
+ pr_err("%s: MAC %d initialization failed\n",
adapter->name, i);
goto error;
}
@@ -1157,7 +1159,7 @@ int __devinit t1_init_sw_modules(adapter_t *adapter,
if (!t1_is_asic(adapter) || bi->chip_mac == CHBT_MAC_DUMMY)
mac->ops->macaddress_get(mac, hw_addr);
else if (vpd_macaddress_get(adapter, i, hw_addr)) {
- CH_ERR("%s: could not read MAC address from VPD ROM\n",
+ pr_err("%s: could not read MAC address from VPD ROM\n",
adapter->port[i].dev->name);
goto error;
}
diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c
index 99b51f61fe77..c844111cffeb 100644
--- a/drivers/net/chelsio/vsc7326.c
+++ b/drivers/net/chelsio/vsc7326.c
@@ -48,14 +48,14 @@ static void vsc_read(adapter_t *adapter, u32 addr, u32 *val)
i++;
} while (((status & 1) == 0) && (i < 50));
if (i == 50)
- CH_ERR("Invalid tpi read from MAC, breaking loop.\n");
+ pr_err("Invalid tpi read from MAC, breaking loop.\n");
t1_tpi_read(adapter, (REG_LOCAL_DATA << 2) + 4, &vlo);
t1_tpi_read(adapter, REG_LOCAL_DATA << 2, &vhi);
*val = (vhi << 16) | vlo;
- /* CH_ERR("rd: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n",
+ /* pr_err("rd: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n",
((addr&0xe000)>>13), ((addr&0x1e00)>>9),
((addr&0x01fe)>>1), *val); */
spin_unlock_bh(&adapter->mac_lock);
@@ -66,7 +66,7 @@ static void vsc_write(adapter_t *adapter, u32 addr, u32 data)
spin_lock_bh(&adapter->mac_lock);
t1_tpi_write(adapter, (addr << 2) + 4, data & 0xFFFF);
t1_tpi_write(adapter, addr << 2, (data >> 16) & 0xFFFF);
- /* CH_ERR("wr: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n",
+ /* pr_err("wr: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n",
((addr&0xe000)>>13), ((addr&0x1e00)>>9),
((addr&0x01fe)>>1), data); */
spin_unlock_bh(&adapter->mac_lock);
@@ -225,7 +225,7 @@ static void run_table(adapter_t *adapter, struct init_table *ib, int len)
for (i = 0; i < len; i++) {
if (ib[i].addr == INITBLOCK_SLEEP) {
udelay( ib[i].data );
- CH_ERR("sleep %d us\n",ib[i].data);
+ pr_err("sleep %d us\n",ib[i].data);
} else
vsc_write( adapter, ib[i].addr, ib[i].data );
}
@@ -241,7 +241,7 @@ static int bist_rd(adapter_t *adapter, int moduleid, int address)
(address != 0x2) &&
(address != 0xd) &&
(address != 0xe))
- CH_ERR("No bist address: 0x%x\n", address);
+ pr_err("No bist address: 0x%x\n", address);
data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) |
((moduleid & 0xff) << 0));
@@ -251,9 +251,9 @@ static int bist_rd(adapter_t *adapter, int moduleid, int address)
vsc_read(adapter, REG_RAM_BIST_RESULT, &result);
if ((result & (1 << 9)) != 0x0)
- CH_ERR("Still in bist read: 0x%x\n", result);
+ pr_err("Still in bist read: 0x%x\n", result);
else if ((result & (1 << 8)) != 0x0)
- CH_ERR("bist read error: 0x%x\n", result);
+ pr_err("bist read error: 0x%x\n", result);
return (result & 0xff);
}
@@ -268,10 +268,10 @@ static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
(address != 0x2) &&
(address != 0xd) &&
(address != 0xe))
- CH_ERR("No bist address: 0x%x\n", address);
+ pr_err("No bist address: 0x%x\n", address);
if (value > 255)
- CH_ERR("Suspicious write out of range value: 0x%x\n", value);
+ pr_err("Suspicious write out of range value: 0x%x\n", value);
data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) |
((moduleid & 0xff) << 0));
@@ -281,9 +281,9 @@ static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
vsc_read(adapter, REG_RAM_BIST_CMD, &result);
if ((result & (1 << 27)) != 0x0)
- CH_ERR("Still in bist write: 0x%x\n", result);
+ pr_err("Still in bist write: 0x%x\n", result);
else if ((result & (1 << 26)) != 0x0)
- CH_ERR("bist write error: 0x%x\n", result);
+ pr_err("bist write error: 0x%x\n", result);
return 0;
}
@@ -306,7 +306,7 @@ static int check_bist(adapter_t *adapter, int moduleid)
column = ((bist_rd(adapter,moduleid, 0x0e)<<8) +
(bist_rd(adapter,moduleid, 0x0d)));
if ((result & 3) != 0x3)
- CH_ERR("Result: 0x%x BIST error in ram %d, column: 0x%04x\n",
+ pr_err("Result: 0x%x BIST error in ram %d, column: 0x%04x\n",
result, moduleid, column);
return 0;
}
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 4332b3a2fafb..9781942992e9 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -1,6 +1,6 @@
/* cnic.c: Broadcom CNIC core network driver.
*
- * Copyright (c) 2006-2009 Broadcom Corporation
+ * Copyright (c) 2006-2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -10,6 +10,8 @@
* Modified and maintained by: Michael Chan <mchan@broadcom.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
@@ -47,7 +49,6 @@
#include "cnic_defs.h"
#define DRV_MODULE_NAME "cnic"
-#define PFX DRV_MODULE_NAME ": "
static char version[] __devinitdata =
"Broadcom NetXtreme II CNIC Driver " DRV_MODULE_NAME " v" CNIC_MODULE_VERSION " (" CNIC_MODULE_RELDATE ")\n";
@@ -326,6 +327,12 @@ static int cnic_iscsi_nl_msg_recv(struct cnic_dev *dev, u32 msg_type,
if (l5_cid >= MAX_CM_SK_TBL_SZ)
break;
+ rcu_read_lock();
+ if (!rcu_dereference(cp->ulp_ops[CNIC_ULP_L4])) {
+ rc = -ENODEV;
+ rcu_read_unlock();
+ break;
+ }
csk = &cp->csk_tbl[l5_cid];
csk_hold(csk);
if (cnic_in_use(csk)) {
@@ -340,6 +347,7 @@ static int cnic_iscsi_nl_msg_recv(struct cnic_dev *dev, u32 msg_type,
cnic_cm_set_pg(csk);
}
csk_put(csk);
+ rcu_read_unlock();
rc = 0;
}
}
@@ -409,14 +417,13 @@ int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops)
struct cnic_dev *dev;
if (ulp_type < 0 || ulp_type >= MAX_CNIC_ULP_TYPE) {
- printk(KERN_ERR PFX "cnic_register_driver: Bad type %d\n",
- ulp_type);
+ pr_err("%s: Bad type %d\n", __func__, ulp_type);
return -EINVAL;
}
mutex_lock(&cnic_lock);
if (cnic_ulp_tbl[ulp_type]) {
- printk(KERN_ERR PFX "cnic_register_driver: Type %d has already "
- "been registered\n", ulp_type);
+ pr_err("%s: Type %d has already been registered\n",
+ __func__, ulp_type);
mutex_unlock(&cnic_lock);
return -EBUSY;
}
@@ -455,15 +462,14 @@ int cnic_unregister_driver(int ulp_type)
int i = 0;
if (ulp_type < 0 || ulp_type >= MAX_CNIC_ULP_TYPE) {
- printk(KERN_ERR PFX "cnic_unregister_driver: Bad type %d\n",
- ulp_type);
+ pr_err("%s: Bad type %d\n", __func__, ulp_type);
return -EINVAL;
}
mutex_lock(&cnic_lock);
ulp_ops = cnic_ulp_tbl[ulp_type];
if (!ulp_ops) {
- printk(KERN_ERR PFX "cnic_unregister_driver: Type %d has not "
- "been registered\n", ulp_type);
+ pr_err("%s: Type %d has not been registered\n",
+ __func__, ulp_type);
goto out_unlock;
}
read_lock(&cnic_dev_lock);
@@ -471,8 +477,8 @@ int cnic_unregister_driver(int ulp_type)
struct cnic_local *cp = dev->cnic_priv;
if (rcu_dereference(cp->ulp_ops[ulp_type])) {
- printk(KERN_ERR PFX "cnic_unregister_driver: Type %d "
- "still has devices registered\n", ulp_type);
+ pr_err("%s: Type %d still has devices registered\n",
+ __func__, ulp_type);
read_unlock(&cnic_dev_lock);
goto out_unlock;
}
@@ -492,8 +498,7 @@ int cnic_unregister_driver(int ulp_type)
}
if (atomic_read(&ulp_ops->ref_count) != 0)
- printk(KERN_WARNING PFX "%s: Failed waiting for ref count to go"
- " to zero.\n", dev->netdev->name);
+ netdev_warn(dev->netdev, "Failed waiting for ref count to go to zero\n");
return 0;
out_unlock:
@@ -511,20 +516,19 @@ static int cnic_register_device(struct cnic_dev *dev, int ulp_type,
struct cnic_ulp_ops *ulp_ops;
if (ulp_type < 0 || ulp_type >= MAX_CNIC_ULP_TYPE) {
- printk(KERN_ERR PFX "cnic_register_device: Bad type %d\n",
- ulp_type);
+ pr_err("%s: Bad type %d\n", __func__, ulp_type);
return -EINVAL;
}
mutex_lock(&cnic_lock);
if (cnic_ulp_tbl[ulp_type] == NULL) {
- printk(KERN_ERR PFX "cnic_register_device: Driver with type %d "
- "has not been registered\n", ulp_type);
+ pr_err("%s: Driver with type %d has not been registered\n",
+ __func__, ulp_type);
mutex_unlock(&cnic_lock);
return -EAGAIN;
}
if (rcu_dereference(cp->ulp_ops[ulp_type])) {
- printk(KERN_ERR PFX "cnic_register_device: Type %d has already "
- "been registered to this device\n", ulp_type);
+ pr_err("%s: Type %d has already been registered to this device\n",
+ __func__, ulp_type);
mutex_unlock(&cnic_lock);
return -EBUSY;
}
@@ -552,8 +556,7 @@ static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
int i = 0;
if (ulp_type < 0 || ulp_type >= MAX_CNIC_ULP_TYPE) {
- printk(KERN_ERR PFX "cnic_unregister_device: Bad type %d\n",
- ulp_type);
+ pr_err("%s: Bad type %d\n", __func__, ulp_type);
return -EINVAL;
}
mutex_lock(&cnic_lock);
@@ -561,8 +564,8 @@ static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
rcu_assign_pointer(cp->ulp_ops[ulp_type], NULL);
cnic_put(dev);
} else {
- printk(KERN_ERR PFX "cnic_unregister_device: device not "
- "registered to this ulp type %d\n", ulp_type);
+ pr_err("%s: device not registered to this ulp type %d\n",
+ __func__, ulp_type);
mutex_unlock(&cnic_lock);
return -EINVAL;
}
@@ -576,8 +579,7 @@ static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
i++;
}
if (test_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[ulp_type]))
- printk(KERN_WARNING PFX "%s: Failed waiting for ULP up call"
- " to complete.\n", dev->netdev->name);
+ netdev_warn(dev->netdev, "Failed waiting for ULP up call to complete\n");
return 0;
}
@@ -898,7 +900,8 @@ static int cnic_alloc_uio(struct cnic_dev *dev) {
uinfo->mem[0].memtype = UIO_MEM_PHYS;
if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
- uinfo->mem[1].addr = (unsigned long) cp->status_blk & PAGE_MASK;
+ uinfo->mem[1].addr = (unsigned long) cp->status_blk.gen &
+ PAGE_MASK;
if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9;
else
@@ -1101,10 +1104,9 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
if (ret)
goto error;
- cp->bnx2x_status_blk = cp->status_blk;
cp->bnx2x_def_status_blk = cp->ethdev->irq_arr[1].status_blk;
- memset(cp->bnx2x_status_blk, 0, sizeof(struct host_status_block));
+ memset(cp->status_blk.bnx2x, 0, sizeof(*cp->status_blk.bnx2x));
cp->l2_rx_ring_size = 15;
@@ -1865,8 +1867,7 @@ static int cnic_bnx2x_connect(struct cnic_dev *dev, struct kwqe *wqes[],
}
if (sizeof(*conn_buf) > CNIC_KWQ16_DATA_SIZE) {
- printk(KERN_ERR PFX "%s: conn_buf size too big\n",
- dev->netdev->name);
+ netdev_err(dev->netdev, "conn_buf size too big\n");
return -ENOMEM;
}
conn_buf = cnic_get_kwqe_16_data(cp, l5_cid, &l5_data);
@@ -2026,13 +2027,13 @@ static int cnic_submit_bnx2x_kwqes(struct cnic_dev *dev, struct kwqe *wqes[],
break;
default:
ret = 0;
- printk(KERN_ERR PFX "%s: Unknown type of KWQE(0x%x)\n",
- dev->netdev->name, opcode);
+ netdev_err(dev->netdev, "Unknown type of KWQE(0x%x)\n",
+ opcode);
break;
}
if (ret < 0)
- printk(KERN_ERR PFX "%s: KWQE(0x%x) failed\n",
- dev->netdev->name, opcode);
+ netdev_err(dev->netdev, "KWQE(0x%x) failed\n",
+ opcode);
i += work;
}
return 0;
@@ -2074,8 +2075,8 @@ static void service_kcqes(struct cnic_dev *dev, int num_cqes)
else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L2)
goto end;
else {
- printk(KERN_ERR PFX "%s: Unknown type of KCQE(0x%x)\n",
- dev->netdev->name, kcqe_op_flag);
+ netdev_err(dev->netdev, "Unknown type of KCQE(0x%x)\n",
+ kcqe_op_flag);
goto end;
}
@@ -2204,7 +2205,7 @@ static void cnic_service_bnx2_msix(unsigned long data)
{
struct cnic_dev *dev = (struct cnic_dev *) data;
struct cnic_local *cp = dev->cnic_priv;
- struct status_block_msix *status_blk = cp->bnx2_status_blk;
+ struct status_block_msix *status_blk = cp->status_blk.bnx2;
u32 status_idx = status_blk->status_idx;
u16 hw_prod, sw_prod;
int kcqe_cnt;
@@ -2250,7 +2251,7 @@ static irqreturn_t cnic_irq(int irq, void *dev_instance)
if (cp->ack_int)
cp->ack_int(dev);
- prefetch(cp->status_blk);
+ prefetch(cp->status_blk.gen);
prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags)))
@@ -2291,7 +2292,7 @@ static void cnic_service_bnx2x_bh(unsigned long data)
struct cnic_local *cp = dev->cnic_priv;
u16 hw_prod, sw_prod;
struct cstorm_status_block_c *sblk =
- &cp->bnx2x_status_blk->c_status_block;
+ &cp->status_blk.bnx2x->c_status_block;
u32 status_idx = sblk->status_block_index;
int kcqe_cnt;
@@ -2333,7 +2334,7 @@ static int cnic_service_bnx2x(void *data, void *status_blk)
struct cnic_local *cp = dev->cnic_priv;
u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX;
- prefetch(cp->status_blk);
+ prefetch(cp->status_blk.bnx2x);
prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags)))
@@ -2513,7 +2514,7 @@ static int cnic_cm_offload_pg(struct cnic_sock *csk)
l4kwqe->sa5 = dev->mac_addr[5];
l4kwqe->etype = ETH_P_IP;
- l4kwqe->ipid_count = DEF_IPID_COUNT;
+ l4kwqe->ipid_start = DEF_IPID_START;
l4kwqe->host_opaque = csk->l5_cid;
if (csk->vlan_id) {
@@ -2859,8 +2860,8 @@ static int cnic_get_route(struct cnic_sock *csk, struct cnic_sockaddr *saddr)
{
struct cnic_dev *dev = csk->dev;
struct cnic_local *cp = dev->cnic_priv;
- int is_v6, err, rc = -ENETUNREACH;
- struct dst_entry *dst;
+ int is_v6, rc = 0;
+ struct dst_entry *dst = NULL;
struct net_device *realdev;
u32 local_port;
@@ -2876,39 +2877,31 @@ static int cnic_get_route(struct cnic_sock *csk, struct cnic_sockaddr *saddr)
clear_bit(SK_F_IPV6, &csk->flags);
if (is_v6) {
-#if defined(CONFIG_IPV6) || (defined(CONFIG_IPV6_MODULE) && defined(MODULE))
set_bit(SK_F_IPV6, &csk->flags);
- err = cnic_get_v6_route(&saddr->remote.v6, &dst);
- if (err)
- return err;
-
- if (!dst || dst->error || !dst->dev)
- goto err_out;
+ cnic_get_v6_route(&saddr->remote.v6, &dst);
memcpy(&csk->dst_ip[0], &saddr->remote.v6.sin6_addr,
sizeof(struct in6_addr));
csk->dst_port = saddr->remote.v6.sin6_port;
local_port = saddr->local.v6.sin6_port;
-#else
- return rc;
-#endif
} else {
- err = cnic_get_v4_route(&saddr->remote.v4, &dst);
- if (err)
- return err;
-
- if (!dst || dst->error || !dst->dev)
- goto err_out;
+ cnic_get_v4_route(&saddr->remote.v4, &dst);
csk->dst_ip[0] = saddr->remote.v4.sin_addr.s_addr;
csk->dst_port = saddr->remote.v4.sin_port;
local_port = saddr->local.v4.sin_port;
}
- csk->vlan_id = cnic_get_vlan(dst->dev, &realdev);
- if (realdev != dev->netdev)
- goto err_out;
+ csk->vlan_id = 0;
+ csk->mtu = dev->netdev->mtu;
+ if (dst && dst->dev) {
+ u16 vlan = cnic_get_vlan(dst->dev, &realdev);
+ if (realdev == dev->netdev) {
+ csk->vlan_id = vlan;
+ csk->mtu = dst_mtu(dst);
+ }
+ }
if (local_port >= CNIC_LOCAL_PORT_MIN &&
local_port < CNIC_LOCAL_PORT_MAX) {
@@ -2926,9 +2919,6 @@ static int cnic_get_route(struct cnic_sock *csk, struct cnic_sockaddr *saddr)
}
csk->src_port = local_port;
- csk->mtu = dst_mtu(dst);
- rc = 0;
-
err_out:
dst_release(dst);
return rc;
@@ -3052,6 +3042,14 @@ static void cnic_cm_process_offld_pg(struct cnic_dev *dev, struct l4_kcq *kcqe)
clear_bit(SK_F_OFFLD_SCHED, &csk->flags);
goto done;
}
+ /* Possible PG kcqe status: SUCCESS, OFFLOADED_PG, or CTX_ALLOC_FAIL */
+ if (kcqe->status == L4_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAIL) {
+ clear_bit(SK_F_OFFLD_SCHED, &csk->flags);
+ cnic_cm_upcall(cp, csk,
+ L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE);
+ goto done;
+ }
+
csk->pg_cid = kcqe->pg_cid;
set_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags);
cnic_cm_conn_req(csk);
@@ -3089,6 +3087,13 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
}
switch (opcode) {
+ case L5CM_RAMROD_CMD_ID_TCP_CONNECT:
+ if (l4kcqe->status != 0) {
+ clear_bit(SK_F_OFFLD_SCHED, &csk->flags);
+ cnic_cm_upcall(cp, csk,
+ L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE);
+ }
+ break;
case L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE:
if (l4kcqe->status == 0)
set_bit(SK_F_OFFLD_COMPLETE, &csk->flags);
@@ -3099,7 +3104,10 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
break;
case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
- if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags))
+ if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
+ cnic_cm_upcall(cp, csk, opcode);
+ break;
+ } else if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags))
csk->state = opcode;
/* fall through */
case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
@@ -3163,6 +3171,16 @@ static int cnic_ready_to_close(struct cnic_sock *csk, u32 opcode)
if (!test_and_set_bit(SK_F_CLOSING, &csk->flags))
return 1;
}
+ /* 57710+ only workaround to handle unsolicited RESET_COMP
+ * which will be treated like a RESET RCVD notification
+ * which triggers the clean up procedure
+ */
+ else if (opcode == L4_KCQE_OPCODE_VALUE_RESET_COMP) {
+ if (!test_and_set_bit(SK_F_CLOSING, &csk->flags)) {
+ csk->state = L4_KCQE_OPCODE_VALUE_RESET_RECEIVED;
+ return 1;
+ }
+ }
return 0;
}
@@ -3172,10 +3190,8 @@ static void cnic_close_bnx2_conn(struct cnic_sock *csk, u32 opcode)
struct cnic_local *cp = dev->cnic_priv;
clear_bit(SK_F_CONNECT_START, &csk->flags);
- if (cnic_ready_to_close(csk, opcode)) {
- cnic_close_conn(csk);
- cnic_cm_upcall(cp, csk, opcode);
- }
+ cnic_close_conn(csk);
+ cnic_cm_upcall(cp, csk, opcode);
}
static void cnic_cm_stop_bnx2_hw(struct cnic_dev *dev)
@@ -3393,8 +3409,7 @@ static int cnic_init_bnx2_irq(struct cnic_dev *dev)
CNIC_WR(dev, base + BNX2_HC_COM_TICKS_OFF, (64 << 16) | 220);
CNIC_WR(dev, base + BNX2_HC_CMD_TICKS_OFF, (64 << 16) | 220);
- cp->bnx2_status_blk = cp->status_blk;
- cp->last_status_idx = cp->bnx2_status_blk->status_idx;
+ cp->last_status_idx = cp->status_blk.bnx2->status_idx;
tasklet_init(&cp->cnic_irq_task, cnic_service_bnx2_msix,
(unsigned long) dev);
err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0,
@@ -3403,7 +3418,7 @@ static int cnic_init_bnx2_irq(struct cnic_dev *dev)
tasklet_disable(&cp->cnic_irq_task);
return err;
}
- while (cp->bnx2_status_blk->status_completion_producer_index &&
+ while (cp->status_blk.bnx2->status_completion_producer_index &&
i < 10) {
CNIC_WR(dev, BNX2_HC_COALESCE_NOW,
1 << (11 + sblk_num));
@@ -3411,13 +3426,13 @@ static int cnic_init_bnx2_irq(struct cnic_dev *dev)
i++;
barrier();
}
- if (cp->bnx2_status_blk->status_completion_producer_index) {
+ if (cp->status_blk.bnx2->status_completion_producer_index) {
cnic_free_irq(dev);
goto failed;
}
} else {
- struct status_block *sblk = cp->status_blk;
+ struct status_block *sblk = cp->status_blk.gen;
u32 hc_cmd = CNIC_RD(dev, BNX2_HC_COMMAND);
int i = 0;
@@ -3435,8 +3450,7 @@ static int cnic_init_bnx2_irq(struct cnic_dev *dev)
return 0;
failed:
- printk(KERN_ERR PFX "%s: " "KCQ index not resetting to 0.\n",
- dev->netdev->name);
+ netdev_err(dev->netdev, "KCQ index not resetting to 0\n");
return -EBUSY;
}
@@ -3475,7 +3489,7 @@ static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev)
int i;
struct tx_bd *txbd;
dma_addr_t buf_map;
- struct status_block *s_blk = cp->status_blk;
+ struct status_block *s_blk = cp->status_blk.gen;
sb_id = cp->status_blk_num;
tx_cid = 20;
@@ -3483,7 +3497,7 @@ static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev)
cnic_init_context(dev, tx_cid + 1);
cp->tx_cons_ptr = &s_blk->status_tx_quick_consumer_index2;
if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
- struct status_block_msix *sblk = cp->status_blk;
+ struct status_block_msix *sblk = cp->status_blk.bnx2;
tx_cid = TX_TSS_CID + sb_id - 1;
cnic_init_context(dev, tx_cid);
@@ -3539,7 +3553,7 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
u32 cid_addr, sb_id, val, coal_reg, coal_val;
int i;
struct rx_bd *rxbd;
- struct status_block *s_blk = cp->status_blk;
+ struct status_block *s_blk = cp->status_blk.gen;
sb_id = cp->status_blk_num;
cnic_init_context(dev, 2);
@@ -3547,7 +3561,7 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
coal_reg = BNX2_HC_COMMAND;
coal_val = CNIC_RD(dev, coal_reg);
if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
- struct status_block_msix *sblk = cp->status_blk;
+ struct status_block_msix *sblk = cp->status_blk.bnx2;
cp->rx_cons_ptr = &sblk->status_rx_quick_consumer_index;
coal_reg = BNX2_HC_COALESCE_NOW;
@@ -3646,7 +3660,7 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
struct cnic_eth_dev *ethdev = cp->ethdev;
- struct status_block *sblk = cp->status_blk;
+ struct status_block *sblk = cp->status_blk.gen;
u32 val;
int err;
@@ -3758,8 +3772,7 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
err = cnic_init_bnx2_irq(dev);
if (err) {
- printk(KERN_ERR PFX "%s: cnic_init_irq failed\n",
- dev->netdev->name);
+ netdev_err(dev->netdev, "cnic_init_irq failed\n");
cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 0);
cnic_reg_wr_ind(dev, BNX2_COM_SCRATCH + 0x20, 0);
return err;
@@ -4122,8 +4135,7 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
offsetof(struct cstorm_status_block_c,
index_values[HC_INDEX_C_ISCSI_EQ_CONS]));
if (eq_idx != 0) {
- printk(KERN_ERR PFX "%s: EQ cons index %x != 0\n",
- dev->netdev->name, eq_idx);
+ netdev_err(dev->netdev, "EQ cons index %x != 0\n", eq_idx);
return -EBUSY;
}
ret = cnic_init_bnx2x_irq(dev);
@@ -4208,8 +4220,7 @@ static int cnic_register_netdev(struct cnic_dev *dev)
err = ethdev->drv_register_cnic(dev->netdev, cp->cnic_ops, dev);
if (err)
- printk(KERN_ERR PFX "%s: register_cnic failed\n",
- dev->netdev->name);
+ netdev_err(dev->netdev, "register_cnic failed\n");
return err;
}
@@ -4238,13 +4249,12 @@ static int cnic_start_hw(struct cnic_dev *dev)
cp->chip_id = ethdev->chip_id;
pci_dev_get(dev->pcidev);
cp->func = PCI_FUNC(dev->pcidev->devfn);
- cp->status_blk = ethdev->irq_arr[0].status_blk;
+ cp->status_blk.gen = ethdev->irq_arr[0].status_blk;
cp->status_blk_num = ethdev->irq_arr[0].status_blk_num;
err = cp->alloc_resc(dev);
if (err) {
- printk(KERN_ERR PFX "%s: allocate resource failure\n",
- dev->netdev->name);
+ netdev_err(dev->netdev, "allocate resource failure\n");
goto err1;
}
@@ -4326,10 +4336,9 @@ static void cnic_free_dev(struct cnic_dev *dev)
i++;
}
if (atomic_read(&dev->ref_count) != 0)
- printk(KERN_ERR PFX "%s: Failed waiting for ref count to go"
- " to zero.\n", dev->netdev->name);
+ netdev_err(dev->netdev, "Failed waiting for ref count to go to zero\n");
- printk(KERN_INFO PFX "Removed CNIC device: %s\n", dev->netdev->name);
+ netdev_info(dev->netdev, "Removed CNIC device\n");
dev_put(dev->netdev);
kfree(dev);
}
@@ -4345,8 +4354,7 @@ static struct cnic_dev *cnic_alloc_dev(struct net_device *dev,
cdev = kzalloc(alloc_size , GFP_KERNEL);
if (cdev == NULL) {
- printk(KERN_ERR PFX "%s: allocate dev struct failure\n",
- dev->name);
+ netdev_err(dev, "allocate dev struct failure\n");
return NULL;
}
@@ -4364,7 +4372,7 @@ static struct cnic_dev *cnic_alloc_dev(struct net_device *dev,
spin_lock_init(&cp->cnic_ulp_lock);
- printk(KERN_INFO PFX "Added CNIC device: %s\n", dev->name);
+ netdev_info(dev, "Added CNIC device\n");
return cdev;
}
@@ -4605,7 +4613,7 @@ static int __init cnic_init(void)
{
int rc = 0;
- printk(KERN_INFO "%s", version);
+ pr_info("%s", version);
rc = register_netdevice_notifier(&cnic_netdev_notifier);
if (rc) {
diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h
index 241d09acc0d4..a0d853dff983 100644
--- a/drivers/net/cnic.h
+++ b/drivers/net/cnic.h
@@ -1,6 +1,6 @@
/* cnic.h: Broadcom CNIC core network driver.
*
- * Copyright (c) 2006-2009 Broadcom Corporation
+ * Copyright (c) 2006-2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -101,7 +101,7 @@ struct cnic_redirect_entry {
#define BNX2X_KWQ_DATA(cp, x) \
&(cp)->kwq_16_data[BNX2X_KWQ_DATA_PG(cp, x)][BNX2X_KWQ_DATA_IDX(cp, x)]
-#define DEF_IPID_COUNT 0xc001
+#define DEF_IPID_START 0x8000
#define DEF_KA_TIMEOUT 10000
#define DEF_KA_INTERVAL 300000
@@ -224,9 +224,12 @@ struct cnic_local {
u16 kcq_prod_idx;
u32 kcq_io_addr;
- void *status_blk;
- struct status_block_msix *bnx2_status_blk;
- struct host_status_block *bnx2x_status_blk;
+ union {
+ void *gen;
+ struct status_block_msix *bnx2;
+ struct host_status_block *bnx2x;
+ } status_blk;
+
struct host_def_status_block *bnx2x_def_status_blk;
u32 status_blk_num;
diff --git a/drivers/net/cnic_defs.h b/drivers/net/cnic_defs.h
index 9827b278dc7c..7ce694d41b6b 100644
--- a/drivers/net/cnic_defs.h
+++ b/drivers/net/cnic_defs.h
@@ -1,7 +1,7 @@
/* cnic.c: Broadcom CNIC core network driver.
*
- * Copyright (c) 2006-2009 Broadcom Corporation
+ * Copyright (c) 2006-2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h
index 8aaf98bdd4f7..110c62072e6f 100644
--- a/drivers/net/cnic_if.h
+++ b/drivers/net/cnic_if.h
@@ -1,6 +1,6 @@
/* cnic_if.h: Broadcom CNIC core network driver.
*
- * Copyright (c) 2006 Broadcom Corporation
+ * Copyright (c) 2006-2010 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -12,8 +12,8 @@
#ifndef CNIC_IF_H
#define CNIC_IF_H
-#define CNIC_MODULE_VERSION "2.1.0"
-#define CNIC_MODULE_RELDATE "Oct 10, 2009"
+#define CNIC_MODULE_VERSION "2.1.1"
+#define CNIC_MODULE_RELDATE "Feb 22, 2010"
#define CNIC_ULP_RDMA 0
#define CNIC_ULP_ISCSI 1
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
index 8d0be26f94e3..60777fd90b33 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/cpmac.c
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/netdevice.h>
+#include <linux/if_vlan.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/skbuff.h>
@@ -36,6 +37,7 @@
#include <linux/phy_fixed.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/clk.h>
#include <asm/gpio.h>
#include <asm/atomic.h>
@@ -54,9 +56,9 @@ module_param(dumb_switch, int, 0444);
MODULE_PARM_DESC(debug_level, "Number of NETIF_MSG bits to enable");
MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus");
-#define CPMAC_VERSION "0.5.1"
-/* frame size + 802.1q tag */
-#define CPMAC_SKB_SIZE (ETH_FRAME_LEN + 4)
+#define CPMAC_VERSION "0.5.2"
+/* frame size + 802.1q tag + FCS size */
+#define CPMAC_SKB_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
#define CPMAC_QUEUES 8
/* Ethernet registers */
@@ -294,9 +296,16 @@ static int cpmac_mdio_write(struct mii_bus *bus, int phy_id,
static int cpmac_mdio_reset(struct mii_bus *bus)
{
+ struct clk *cpmac_clk;
+
+ cpmac_clk = clk_get(&bus->dev, "cpmac");
+ if (IS_ERR(cpmac_clk)) {
+ printk(KERN_ERR "unable to get cpmac clock\n");
+ return -1;
+ }
ar7_device_reset(AR7_RESET_BIT_MDIO);
cpmac_write(bus->priv, CPMAC_MDIO_CONTROL, MDIOC_ENABLE |
- MDIOC_CLKDIV(ar7_cpmac_freq() / 2200000 - 1));
+ MDIOC_CLKDIV(clk_get_rate(cpmac_clk) / 2200000 - 1));
return 0;
}
@@ -320,7 +329,6 @@ static int cpmac_config(struct net_device *dev, struct ifmap *map)
static void cpmac_set_multicast_list(struct net_device *dev)
{
struct dev_mc_list *iter;
- int i;
u8 tmp;
u32 mbp, bit, hash[2] = { 0, };
struct cpmac_priv *priv = netdev_priv(dev);
@@ -340,8 +348,7 @@ static void cpmac_set_multicast_list(struct net_device *dev)
* cpmac uses some strange mac address hashing
* (not crc32)
*/
- for (i = 0, iter = dev->mc_list; i < dev->mc_count;
- i++, iter = iter->next) {
+ netdev_for_each_mc_addr(iter, dev) {
bit = 0;
tmp = iter->dmi_addr[0];
bit ^= (tmp >> 2) ^ (tmp << 4);
@@ -1130,8 +1137,9 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
}
if (phy_id == PHY_MAX_ADDR) {
- dev_err(&pdev->dev, "no PHY present\n");
- return -ENODEV;
+ dev_err(&pdev->dev, "no PHY present, falling back to switch on MDIO bus 0\n");
+ strncpy(mdio_bus_id, "0", MII_BUS_ID_SIZE); /* fixed phys bus */
+ phy_id = pdev->id;
}
dev = alloc_etherdev_mq(sizeof(*priv), CPMAC_QUEUES);
@@ -1284,8 +1292,8 @@ void __devexit cpmac_exit(void)
{
platform_driver_unregister(&cpmac_driver);
mdiobus_unregister(cpmac_mii);
- mdiobus_free(cpmac_mii);
iounmap(cpmac_mii->priv);
+ mdiobus_free(cpmac_mii);
}
module_init(cpmac_init);
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index a24be34a3f7a..dd24aadb778c 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -1564,7 +1564,7 @@ static void
set_multicast_list(struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
- int num_addr = dev->mc_count;
+ int num_addr = netdev_mc_count(dev);
unsigned long int lo_bits;
unsigned long int hi_bits;
@@ -1596,13 +1596,12 @@ set_multicast_list(struct net_device *dev)
} else {
/* MC mode, receive normal and MC packets */
char hash_ix;
- struct dev_mc_list *dmi = dev->mc_list;
- int i;
+ struct dev_mc_list *dmi;
char *baddr;
lo_bits = 0x00000000ul;
hi_bits = 0x00000000ul;
- for (i = 0; i < num_addr; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
/* Calculate the hash index for the GA registers */
hash_ix = 0;
@@ -1632,7 +1631,6 @@ set_multicast_list(struct net_device *dev)
} else {
lo_bits |= (1 << hash_ix);
}
- dmi = dmi->next;
}
/* Disable individual receive */
SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 0e79cef95c0a..b0208e474f7e 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -580,7 +580,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
}
#ifdef CONFIG_SH_HICOSH4
- /* truely reset the chip */
+ /* truly reset the chip */
writeword(ioaddr, ADD_PORT, 0x0114);
writeword(ioaddr, DATA_PORT, 0x0040);
#endif
@@ -1785,7 +1785,7 @@ static void set_multicast_list(struct net_device *dev)
{
lp->rx_mode = RX_ALL_ACCEPT;
}
- else if((dev->flags&IFF_ALLMULTI)||dev->mc_list)
+ else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev))
{
/* The multicast-accept list is initialized to accept-all, and we
rely on higher-level filtering for now. */
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 3e8618b4efbc..4cd7f420766a 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -264,6 +264,10 @@ struct adapter {
struct work_struct fatal_error_handler_task;
struct work_struct link_fault_handler_task;
+ struct work_struct db_full_task;
+ struct work_struct db_empty_task;
+ struct work_struct db_drop_task;
+
struct dentry *debugfs_root;
struct mutex mdio_lock;
@@ -335,6 +339,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
unsigned char *data);
irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
+extern struct workqueue_struct *cxgb3_wq;
int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size);
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 6ff356d4c7ab..fe08a004b0dd 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -67,32 +67,6 @@
/* Additional NETIF_MSG_* categories */
#define NETIF_MSG_MMIO 0x8000000
-struct t3_rx_mode {
- struct net_device *dev;
- struct dev_mc_list *mclist;
- unsigned int idx;
-};
-
-static inline void init_rx_mode(struct t3_rx_mode *p, struct net_device *dev,
- struct dev_mc_list *mclist)
-{
- p->dev = dev;
- p->mclist = mclist;
- p->idx = 0;
-}
-
-static inline u8 *t3_get_next_mcaddr(struct t3_rx_mode *rm)
-{
- u8 *addr = NULL;
-
- if (rm->mclist && rm->idx < rm->dev->mc_count) {
- addr = rm->mclist->dmi_addr;
- rm->mclist = rm->mclist->next;
- rm->idx++;
- }
- return addr;
-}
-
enum {
MAX_NPORTS = 2, /* max # of ports */
MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */
@@ -746,7 +720,7 @@ void t3_mac_enable_exact_filters(struct cmac *mac);
int t3_mac_enable(struct cmac *mac, int which);
int t3_mac_disable(struct cmac *mac, int which);
int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu);
-int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm);
+int t3_mac_set_rx_mode(struct cmac *mac, struct net_device *dev);
int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]);
int t3_mac_set_num_ucast(struct cmac *mac, int n);
const struct mac_stats *t3_mac_update_stats(struct cmac *mac);
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 89bec9c3c141..9e3e8750b46a 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -45,6 +45,7 @@
#include <linux/firmware.h>
#include <linux/log2.h>
#include <linux/stringify.h>
+#include <linux/sched.h>
#include <asm/uaccess.h>
#include "common.h"
@@ -80,7 +81,7 @@ enum {
#define CH_DEVICE(devid, idx) \
{ PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx }
-static const struct pci_device_id cxgb3_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(cxgb3_pci_tbl) = {
CH_DEVICE(0x20, 0), /* PE9000 */
CH_DEVICE(0x21, 1), /* T302E */
CH_DEVICE(0x22, 2), /* T310E */
@@ -140,7 +141,7 @@ MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not");
* will block keventd as it needs the rtnl lock, and we'll deadlock waiting
* for our work to complete. Get our own work queue to solve this.
*/
-static struct workqueue_struct *cxgb3_wq;
+struct workqueue_struct *cxgb3_wq;
/**
* link_report - show link status and link speed/duplex
@@ -324,11 +325,9 @@ void t3_os_phymod_changed(struct adapter *adap, int port_id)
static void cxgb_set_rxmode(struct net_device *dev)
{
- struct t3_rx_mode rm;
struct port_info *pi = netdev_priv(dev);
- init_rx_mode(&rm, dev, dev->mc_list);
- t3_mac_set_rx_mode(&pi->mac, &rm);
+ t3_mac_set_rx_mode(&pi->mac, dev);
}
/**
@@ -339,17 +338,15 @@ static void cxgb_set_rxmode(struct net_device *dev)
*/
static void link_start(struct net_device *dev)
{
- struct t3_rx_mode rm;
struct port_info *pi = netdev_priv(dev);
struct cmac *mac = &pi->mac;
- init_rx_mode(&rm, dev, dev->mc_list);
t3_mac_reset(mac);
t3_mac_set_num_ucast(mac, MAX_MAC_IDX);
t3_mac_set_mtu(mac, dev->mtu);
t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr);
t3_mac_set_address(mac, SAN_MAC_IDX, pi->iscsic.mac_addr);
- t3_mac_set_rx_mode(mac, &rm);
+ t3_mac_set_rx_mode(mac, dev);
t3_link_start(&pi->phy, mac, &pi->link_config);
t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
}
@@ -590,6 +587,19 @@ static void setup_rss(struct adapter *adap)
V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map);
}
+static void ring_dbs(struct adapter *adap)
+{
+ int i, j;
+
+ for (i = 0; i < SGE_QSETS; i++) {
+ struct sge_qset *qs = &adap->sge.qs[i];
+
+ if (qs->adap)
+ for (j = 0; j < SGE_TXQ_PER_SET; j++)
+ t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | V_EGRCNTX(qs->txq[j].cntxt_id));
+ }
+}
+
static void init_napi(struct adapter *adap)
{
int i;
@@ -1284,6 +1294,7 @@ static void cxgb_down(struct adapter *adapter)
free_irq_resources(adapter);
quiesce_rx(adapter);
+ t3_sge_stop(adapter);
flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */
}
@@ -2754,6 +2765,42 @@ static void t3_adap_check_task(struct work_struct *work)
spin_unlock_irq(&adapter->work_lock);
}
+static void db_full_task(struct work_struct *work)
+{
+ struct adapter *adapter = container_of(work, struct adapter,
+ db_full_task);
+
+ cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_FULL, 0);
+}
+
+static void db_empty_task(struct work_struct *work)
+{
+ struct adapter *adapter = container_of(work, struct adapter,
+ db_empty_task);
+
+ cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_EMPTY, 0);
+}
+
+static void db_drop_task(struct work_struct *work)
+{
+ struct adapter *adapter = container_of(work, struct adapter,
+ db_drop_task);
+ unsigned long delay = 1000;
+ unsigned short r;
+
+ cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_DROP, 0);
+
+ /*
+ * Sleep a while before ringing the driver qset dbs.
+ * The delay is between 1000-2023 usecs.
+ */
+ get_random_bytes(&r, 2);
+ delay += r & 1023;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(delay));
+ ring_dbs(adapter);
+}
+
/*
* Processes external (PHY) interrupts in process context.
*/
@@ -3222,6 +3269,11 @@ static int __devinit init_one(struct pci_dev *pdev,
INIT_LIST_HEAD(&adapter->adapter_list);
INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task);
+
+ INIT_WORK(&adapter->db_full_task, db_full_task);
+ INIT_WORK(&adapter->db_empty_task, db_empty_task);
+ INIT_WORK(&adapter->db_drop_task, db_drop_task);
+
INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
for (i = 0; i < ai->nports0 + ai->nports1; ++i) {
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index 75064eea1d87..9498361119d6 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -1252,7 +1252,7 @@ int cxgb3_offload_activate(struct adapter *adapter)
struct mtutab mtutab;
unsigned int l2t_capacity;
- t = kcalloc(1, sizeof(*t), GFP_KERNEL);
+ t = kzalloc(sizeof(*t), GFP_KERNEL);
if (!t)
return -ENOMEM;
diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h
index 670aa62042da..929c298115ca 100644
--- a/drivers/net/cxgb3/cxgb3_offload.h
+++ b/drivers/net/cxgb3/cxgb3_offload.h
@@ -73,7 +73,10 @@ enum {
OFFLOAD_STATUS_UP,
OFFLOAD_STATUS_DOWN,
OFFLOAD_PORT_DOWN,
- OFFLOAD_PORT_UP
+ OFFLOAD_PORT_UP,
+ OFFLOAD_DB_FULL,
+ OFFLOAD_DB_EMPTY,
+ OFFLOAD_DB_DROP
};
struct cxgb3_client {
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
index 1b5327b5a965..cb42353c9fdd 100644
--- a/drivers/net/cxgb3/regs.h
+++ b/drivers/net/cxgb3/regs.h
@@ -254,6 +254,22 @@
#define V_LOPIODRBDROPERR(x) ((x) << S_LOPIODRBDROPERR)
#define F_LOPIODRBDROPERR V_LOPIODRBDROPERR(1U)
+#define S_HIPRIORITYDBFULL 7
+#define V_HIPRIORITYDBFULL(x) ((x) << S_HIPRIORITYDBFULL)
+#define F_HIPRIORITYDBFULL V_HIPRIORITYDBFULL(1U)
+
+#define S_HIPRIORITYDBEMPTY 6
+#define V_HIPRIORITYDBEMPTY(x) ((x) << S_HIPRIORITYDBEMPTY)
+#define F_HIPRIORITYDBEMPTY V_HIPRIORITYDBEMPTY(1U)
+
+#define S_LOPRIORITYDBFULL 5
+#define V_LOPRIORITYDBFULL(x) ((x) << S_LOPRIORITYDBFULL)
+#define F_LOPRIORITYDBFULL V_LOPRIORITYDBFULL(1U)
+
+#define S_LOPRIORITYDBEMPTY 4
+#define V_LOPRIORITYDBEMPTY(x) ((x) << S_LOPRIORITYDBEMPTY)
+#define F_LOPRIORITYDBEMPTY V_LOPRIORITYDBEMPTY(1U)
+
#define S_RSPQDISABLED 3
#define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED)
#define F_RSPQDISABLED V_RSPQDISABLED(1U)
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index bdbd14727e4b..67e61b2a8c42 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -42,6 +42,7 @@
#include "sge_defs.h"
#include "t3_cpl.h"
#include "firmware_exports.h"
+#include "cxgb3_offload.h"
#define USE_GTS 0
@@ -196,13 +197,13 @@ static inline void refill_rspq(struct adapter *adapter,
/**
* need_skb_unmap - does the platform need unmapping of sk_buffs?
*
- * Returns true if the platfrom needs sk_buff unmapping. The compiler
+ * Returns true if the platform needs sk_buff unmapping. The compiler
* optimizes away unecessary code if this returns true.
*/
static inline int need_skb_unmap(void)
{
/*
- * This structure is used to tell if the platfrom needs buffer
+ * This structure is used to tell if the platform needs buffer
* unmapping by checking if DECLARE_PCI_UNMAP_ADDR defines anything.
*/
struct dummy {
@@ -480,6 +481,7 @@ static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q)
{
if (q->pend_cred >= q->credits / 4) {
q->pend_cred = 0;
+ wmb();
t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
}
}
@@ -2079,6 +2081,7 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
struct sge_fl *fl, int len, int complete)
{
struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+ struct port_info *pi = netdev_priv(qs->netdev);
struct sk_buff *skb = NULL;
struct cpl_rx_pkt *cpl;
struct skb_frag_struct *rx_frag;
@@ -2116,11 +2119,18 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
if (!nr_frags) {
offset = 2 + sizeof(struct cpl_rx_pkt);
- qs->lro_va = sd->pg_chunk.va + 2;
- }
- len -= offset;
+ cpl = qs->lro_va = sd->pg_chunk.va + 2;
+
+ if ((pi->rx_offload & T3_RX_CSUM) &&
+ cpl->csum_valid && cpl->csum == htons(0xffff)) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
+ } else
+ skb->ip_summed = CHECKSUM_NONE;
+ } else
+ cpl = qs->lro_va;
- prefetch(qs->lro_va);
+ len -= offset;
rx_frag += nr_frags;
rx_frag->page = sd->pg_chunk.page;
@@ -2136,12 +2146,8 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
return;
skb_record_rx_queue(skb, qs - &adap->sge.qs[0]);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- cpl = qs->lro_va;
if (unlikely(cpl->vlan_valid)) {
- struct net_device *dev = qs->netdev;
- struct port_info *pi = netdev_priv(dev);
struct vlan_group *grp = pi->vlan_grp;
if (likely(grp != NULL)) {
@@ -2282,11 +2288,14 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
while (likely(budget_left && is_new_response(r, q))) {
int packet_complete, eth, ethpad = 2, lro = qs->lro_enabled;
struct sk_buff *skb = NULL;
- u32 len, flags = ntohl(r->flags);
- __be32 rss_hi = *(const __be32 *)r,
- rss_lo = r->rss_hdr.rss_hash_val;
+ u32 len, flags;
+ __be32 rss_hi, rss_lo;
+ rmb();
eth = r->rss_hdr.opcode == CPL_RX_PKT;
+ rss_hi = *(const __be32 *)r;
+ rss_lo = r->rss_hdr.rss_hash_val;
+ flags = ntohl(r->flags);
if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) {
skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC);
@@ -2497,7 +2506,10 @@ static int process_pure_responses(struct adapter *adap, struct sge_qset *qs,
refill_rspq(adap, q, q->credits);
q->credits = 0;
}
- } while (is_new_response(r, q) && is_pure_response(r));
+ if (!is_new_response(r, q))
+ break;
+ rmb();
+ } while (is_pure_response(r));
if (sleeping)
check_ring_db(adap, qs, sleeping);
@@ -2531,6 +2543,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q)
if (!is_new_response(r, q))
return -1;
+ rmb();
if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) {
t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx));
@@ -2829,8 +2842,13 @@ void t3_sge_err_intr_handler(struct adapter *adapter)
}
if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR))
- CH_ALERT(adapter, "SGE dropped %s priority doorbell\n",
- status & F_HIPIODRBDROPERR ? "high" : "lo");
+ queue_work(cxgb3_wq, &adapter->db_drop_task);
+
+ if (status & (F_HIPRIORITYDBFULL | F_LOPRIORITYDBFULL))
+ queue_work(cxgb3_wq, &adapter->db_full_task);
+
+ if (status & (F_HIPRIORITYDBEMPTY | F_LOPRIORITYDBEMPTY))
+ queue_work(cxgb3_wq, &adapter->db_empty_task);
t3_write_reg(adapter, A_SG_INT_CAUSE, status);
if (status & SGE_FATALERR)
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 032cfe065570..95a8ba0759f1 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -1262,7 +1262,8 @@ void t3_link_changed(struct adapter *adapter, int port_id)
lc->fc = fc;
}
- t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
+ t3_os_link_changed(adapter, port_id, link_ok && !pi->link_fault,
+ speed, duplex, fc);
}
void t3_link_fault(struct adapter *adapter, int port_id)
@@ -1432,7 +1433,10 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \
V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \
F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \
- F_HIRCQPARITYERROR)
+ F_HIRCQPARITYERROR | F_LOPRIORITYDBFULL | \
+ F_HIPRIORITYDBFULL | F_LOPRIORITYDBEMPTY | \
+ F_HIPRIORITYDBEMPTY | F_HIPIODRBDROPERR | \
+ F_LOPIODRBDROPERR)
#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
F_NFASRCHFAIL)
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index 0109ee4f2f91..c142a2132e9f 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -297,29 +297,30 @@ static int hash_hw_addr(const u8 * addr)
return hash;
}
-int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
+int t3_mac_set_rx_mode(struct cmac *mac, struct net_device *dev)
{
u32 val, hash_lo, hash_hi;
struct adapter *adap = mac->adapter;
unsigned int oft = mac->offset;
val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES;
- if (rm->dev->flags & IFF_PROMISC)
+ if (dev->flags & IFF_PROMISC)
val |= F_COPYALLFRAMES;
t3_write_reg(adap, A_XGM_RX_CFG + oft, val);
- if (rm->dev->flags & IFF_ALLMULTI)
+ if (dev->flags & IFF_ALLMULTI)
hash_lo = hash_hi = 0xffffffff;
else {
- u8 *addr;
+ struct dev_mc_list *dmi;
int exact_addr_idx = mac->nucast;
hash_lo = hash_hi = 0;
- while ((addr = t3_get_next_mcaddr(rm)))
+ netdev_for_each_mc_addr(dmi, dev)
if (exact_addr_idx < EXACT_ADDR_FILTERS)
- set_addr_filter(mac, exact_addr_idx++, addr);
+ set_addr_filter(mac, exact_addr_idx++,
+ dmi->dmi_addr);
else {
- int hash = hash_hw_addr(addr);
+ int hash = hash_hw_addr(dmi->dmi_addr);
if (hash < 32)
hash_lo |= (1 << hash);
@@ -353,6 +354,9 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
* packet size register includes header, but not FCS.
*/
mtu += 14;
+ if (mtu > 1536)
+ mtu += 4;
+
if (mtu > MAX_FRAME_SIZE - 4)
return -EINVAL;
t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index 33c4fe26178c..8bd086aee56d 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -62,12 +62,11 @@
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/uaccess.h>
+#include <linux/davinci_emac.h>
#include <asm/irq.h>
#include <asm/page.h>
-#include <mach/emac.h>
-
static int debug_level;
module_param(debug_level, int, 0);
MODULE_PARM_DESC(debug_level, "DaVinci EMAC debug level (NETIF_MSG bits)");
@@ -465,6 +464,7 @@ struct emac_priv {
void __iomem *ctrl_base;
void __iomem *emac_ctrl_ram;
u32 ctrl_ram_size;
+ u32 hw_ram_addr;
struct emac_txch *txch[EMAC_DEF_MAX_TX_CH];
struct emac_rxch *rxch[EMAC_DEF_MAX_RX_CH];
u32 link; /* 1=link on, 0=link off */
@@ -488,6 +488,9 @@ struct emac_priv {
struct mii_bus *mii_bus;
struct phy_device *phydev;
spinlock_t lock;
+ /*platform specific members*/
+ void (*int_enable) (void);
+ void (*int_disable) (void);
};
/* clock frequency for EMAC */
@@ -495,11 +498,9 @@ static struct clk *emac_clk;
static unsigned long emac_bus_frequency;
static unsigned long mdio_max_freq;
-/* EMAC internal utility function */
-static inline u32 emac_virt_to_phys(void __iomem *addr)
-{
- return (u32 __force) io_v2p(addr);
-}
+#define emac_virt_to_phys(addr, priv) \
+ (((u32 __force)(addr) - (u32 __force)(priv->emac_ctrl_ram)) \
+ + priv->hw_ram_addr)
/* Cache macros - Packet buffers would be from skb pool which is cached */
#define EMAC_VIRT_NOCACHE(addr) (addr)
@@ -956,19 +957,18 @@ static void emac_dev_mcast_set(struct net_device *ndev)
} else {
mbp_enable = (mbp_enable & ~EMAC_MBP_RXPROMISC);
if ((ndev->flags & IFF_ALLMULTI) ||
- (ndev->mc_count > EMAC_DEF_MAX_MULTICAST_ADDRESSES)) {
+ netdev_mc_count(ndev) > EMAC_DEF_MAX_MULTICAST_ADDRESSES) {
mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST);
emac_add_mcast(priv, EMAC_ALL_MULTI_SET, NULL);
}
- if (ndev->mc_count > 0) {
+ if (!netdev_mc_empty(ndev)) {
struct dev_mc_list *mc_ptr;
mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST);
emac_add_mcast(priv, EMAC_ALL_MULTI_CLR, NULL);
/* program multicast address list into EMAC hardware */
- for (mc_ptr = ndev->mc_list; mc_ptr;
- mc_ptr = mc_ptr->next) {
+ netdev_for_each_mc_addr(mc_ptr, ndev) {
emac_add_mcast(priv, EMAC_MULTICAST_ADD,
- (u8 *)mc_ptr->dmi_addr);
+ (u8 *) mc_ptr->dmi_addr);
}
} else {
mbp_enable = (mbp_enable & ~EMAC_MBP_RXMCAST);
@@ -1002,6 +1002,8 @@ static void emac_int_disable(struct emac_priv *priv)
emac_ctrl_write(EMAC_DM646X_CMRXINTEN, 0x0);
emac_ctrl_write(EMAC_DM646X_CMTXINTEN, 0x0);
/* NOTE: Rx Threshold and Misc interrupts are not disabled */
+ if (priv->int_disable)
+ priv->int_disable();
local_irq_restore(flags);
@@ -1021,6 +1023,9 @@ static void emac_int_disable(struct emac_priv *priv)
static void emac_int_enable(struct emac_priv *priv)
{
if (priv->version == EMAC_VERSION_2) {
+ if (priv->int_enable)
+ priv->int_enable();
+
emac_ctrl_write(EMAC_DM646X_CMRXINTEN, 0xff);
emac_ctrl_write(EMAC_DM646X_CMTXINTEN, 0xff);
@@ -1302,7 +1307,7 @@ static int emac_tx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
curr_bd = txch->active_queue_head;
if (NULL == curr_bd) {
emac_write(EMAC_TXCP(ch),
- emac_virt_to_phys(txch->last_hw_bdprocessed));
+ emac_virt_to_phys(txch->last_hw_bdprocessed, priv));
txch->no_active_pkts++;
spin_unlock_irqrestore(&priv->tx_lock, flags);
return 0;
@@ -1312,7 +1317,7 @@ static int emac_tx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
while ((curr_bd) &&
((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) &&
(pkts_processed < budget)) {
- emac_write(EMAC_TXCP(ch), emac_virt_to_phys(curr_bd));
+ emac_write(EMAC_TXCP(ch), emac_virt_to_phys(curr_bd, priv));
txch->active_queue_head = curr_bd->next;
if (frame_status & EMAC_CPPI_EOQ_BIT) {
if (curr_bd->next) { /* misqueued packet */
@@ -1399,7 +1404,7 @@ static int emac_send(struct emac_priv *priv, struct emac_netpktobj *pkt, u32 ch)
txch->active_queue_tail = curr_bd;
if (1 != txch->queue_active) {
emac_write(EMAC_TXHDP(ch),
- emac_virt_to_phys(curr_bd));
+ emac_virt_to_phys(curr_bd, priv));
txch->queue_active = 1;
}
++txch->queue_reinit;
@@ -1411,10 +1416,11 @@ static int emac_send(struct emac_priv *priv, struct emac_netpktobj *pkt, u32 ch)
tail_bd->next = curr_bd;
txch->active_queue_tail = curr_bd;
tail_bd = EMAC_VIRT_NOCACHE(tail_bd);
- tail_bd->h_next = (int)emac_virt_to_phys(curr_bd);
+ tail_bd->h_next = (int)emac_virt_to_phys(curr_bd, priv);
frame_status = tail_bd->mode;
if (frame_status & EMAC_CPPI_EOQ_BIT) {
- emac_write(EMAC_TXHDP(ch), emac_virt_to_phys(curr_bd));
+ emac_write(EMAC_TXHDP(ch),
+ emac_virt_to_phys(curr_bd, priv));
frame_status &= ~(EMAC_CPPI_EOQ_BIT);
tail_bd->mode = frame_status;
++txch->end_of_queue_add;
@@ -1604,7 +1610,8 @@ static int emac_init_rxch(struct emac_priv *priv, u32 ch, char *param)
}
/* populate the hardware descriptor */
- curr_bd->h_next = emac_virt_to_phys(rxch->active_queue_head);
+ curr_bd->h_next = emac_virt_to_phys(rxch->active_queue_head,
+ priv);
/* FIXME buff_ptr = dma_map_single(... data_ptr ...) */
curr_bd->buff_ptr = virt_to_phys(curr_bd->data_ptr);
curr_bd->off_b_len = rxch->buf_size;
@@ -1879,7 +1886,7 @@ static void emac_addbd_to_rx_queue(struct emac_priv *priv, u32 ch,
rxch->active_queue_tail = curr_bd;
if (0 != rxch->queue_active) {
emac_write(EMAC_RXHDP(ch),
- emac_virt_to_phys(rxch->active_queue_head));
+ emac_virt_to_phys(rxch->active_queue_head, priv));
rxch->queue_active = 1;
}
} else {
@@ -1890,11 +1897,11 @@ static void emac_addbd_to_rx_queue(struct emac_priv *priv, u32 ch,
rxch->active_queue_tail = curr_bd;
tail_bd->next = curr_bd;
tail_bd = EMAC_VIRT_NOCACHE(tail_bd);
- tail_bd->h_next = emac_virt_to_phys(curr_bd);
+ tail_bd->h_next = emac_virt_to_phys(curr_bd, priv);
frame_status = tail_bd->mode;
if (frame_status & EMAC_CPPI_EOQ_BIT) {
emac_write(EMAC_RXHDP(ch),
- emac_virt_to_phys(curr_bd));
+ emac_virt_to_phys(curr_bd, priv));
frame_status &= ~(EMAC_CPPI_EOQ_BIT);
tail_bd->mode = frame_status;
++rxch->end_of_queue_add;
@@ -1987,7 +1994,7 @@ static int emac_rx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
curr_pkt->num_bufs = 1;
curr_pkt->pkt_length =
(frame_status & EMAC_RX_BD_PKT_LENGTH_MASK);
- emac_write(EMAC_RXCP(ch), emac_virt_to_phys(curr_bd));
+ emac_write(EMAC_RXCP(ch), emac_virt_to_phys(curr_bd, priv));
++rxch->processed_bd;
last_bd = curr_bd;
curr_bd = last_bd->next;
@@ -1998,7 +2005,7 @@ static int emac_rx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
if (curr_bd) {
++rxch->mis_queued_packets;
emac_write(EMAC_RXHDP(ch),
- emac_virt_to_phys(curr_bd));
+ emac_virt_to_phys(curr_bd, priv));
} else {
++rxch->end_of_queue;
rxch->queue_active = 0;
@@ -2099,7 +2106,7 @@ static int emac_hw_enable(struct emac_priv *priv)
emac_write(EMAC_RXINTMASKSET, BIT(ch));
rxch->queue_active = 1;
emac_write(EMAC_RXHDP(ch),
- emac_virt_to_phys(rxch->active_queue_head));
+ emac_virt_to_phys(rxch->active_queue_head, priv));
}
/* Enable MII */
@@ -2378,7 +2385,7 @@ static int emac_dev_open(struct net_device *ndev)
struct emac_priv *priv = netdev_priv(ndev);
netif_carrier_off(ndev);
- for (cnt = 0; cnt <= ETH_ALEN; cnt++)
+ for (cnt = 0; cnt < ETH_ALEN; cnt++)
ndev->dev_addr[cnt] = priv->mac_addr[cnt];
/* Configuration items */
@@ -2651,7 +2658,7 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
pdata = pdev->dev.platform_data;
if (!pdata) {
- printk(KERN_ERR "DaVinci EMAC: No platfrom data\n");
+ printk(KERN_ERR "DaVinci EMAC: No platform data\n");
return -ENODEV;
}
@@ -2660,6 +2667,9 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
priv->phy_mask = pdata->phy_mask;
priv->rmii_en = pdata->rmii_en;
priv->version = pdata->version;
+ priv->int_enable = pdata->interrupt_enable;
+ priv->int_disable = pdata->interrupt_disable;
+
emac_dev = &ndev->dev;
/* Get EMAC platform data */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -2672,8 +2682,7 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
priv->emac_base_phys = res->start + pdata->ctrl_reg_offset;
size = res->end - res->start + 1;
if (!request_mem_region(res->start, size, ndev->name)) {
- dev_err(emac_dev, "DaVinci EMAC: failed request_mem_region() \
- for regs\n");
+ dev_err(emac_dev, "DaVinci EMAC: failed request_mem_region() for regs\n");
rc = -ENXIO;
goto probe_quit;
}
@@ -2692,6 +2701,12 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
priv->ctrl_ram_size = pdata->ctrl_ram_size;
priv->emac_ctrl_ram = priv->remap_addr + pdata->ctrl_ram_offset;
+ if (pdata->hw_ram_addr)
+ priv->hw_ram_addr = pdata->hw_ram_addr;
+ else
+ priv->hw_ram_addr = (u32 __force)res->start +
+ pdata->ctrl_ram_offset;
+
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(emac_dev, "DaVinci EMAC: Error getting irq res\n");
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index 45794f6cb0f6..a0a6830b5e6d 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -464,7 +464,7 @@ static int de620_close(struct net_device *dev)
static void de620_set_multicast_list(struct net_device *dev)
{
- if (dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
+ if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
{ /* Enable promiscuous mode */
de620_set_register(dev, W_TCR, (TCR_DEF & ~RXPBM) | RXALL);
}
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index be9590253aa1..8cf3cc6f20e2 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -940,9 +940,8 @@ static void lance_load_multicast(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
volatile u16 *ib = (volatile u16 *)dev->mem_start;
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
char *addrs;
- int i;
u32 crc;
/* set all multicast bits */
@@ -960,9 +959,8 @@ static void lance_load_multicast(struct net_device *dev)
*lib_ptr(ib, filter[3], lp->type) = 0;
/* Add addresses */
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
addrs = dmi->dmi_addr;
- dmi = dmi->next;
/* multicast address? */
if (!(*addrs & 1))
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 6a6ea038d7a3..ed53a8d45f4e 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -1052,12 +1052,9 @@ static int __devinit dfx_driver_init(struct net_device *dev,
board_name = "DEFEA";
if (dfx_bus_pci)
board_name = "DEFPA";
- pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, "
- "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
+ pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, Hardware addr = %pMF\n",
print_name, board_name, dfx_use_mmio ? "" : "I/O ",
- (long long)bar_start, dev->irq,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ (long long)bar_start, dev->irq, dev->dev_addr);
/*
* Get memory for descriptor block, consumer block, and other buffers
@@ -2230,7 +2227,7 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev)
* perfect filtering will be used.
*/
- if (dev->mc_count > (PI_CMD_ADDR_FILTER_K_SIZE - bp->uc_count))
+ if (netdev_mc_count(dev) > (PI_CMD_ADDR_FILTER_K_SIZE - bp->uc_count))
{
bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */
bp->mc_count = 0; /* Don't add mc addrs to CAM */
@@ -2238,17 +2235,16 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev)
else
{
bp->group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC group prom mode */
- bp->mc_count = dev->mc_count; /* Add mc addrs to CAM */
+ bp->mc_count = netdev_mc_count(dev); /* Add mc addrs to CAM */
}
/* Copy addresses to multicast address table, then update adapter CAM */
- dmi = dev->mc_list; /* point to first multicast addr */
- for (i=0; i < bp->mc_count; i++)
- {
- memcpy(&bp->mc_table[i*FDDI_K_ALEN], dmi->dmi_addr, FDDI_K_ALEN);
- dmi = dmi->next; /* point to next multicast addr */
- }
+ i = 0;
+ netdev_for_each_mc_addr(dmi, dev)
+ memcpy(&bp->mc_table[i++ * FDDI_K_ALEN],
+ dmi->dmi_addr, FDDI_K_ALEN);
+
if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS)
{
DBG_printk("%s: Could not update multicast address table!\n", dev->name);
@@ -3631,7 +3627,7 @@ static int __devinit dfx_pci_register(struct pci_dev *,
const struct pci_device_id *);
static void __devexit dfx_pci_unregister(struct pci_dev *);
-static struct pci_device_id dfx_pci_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(dfx_pci_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) },
{ }
};
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 0c1f491d20bf..744c1928dfca 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -1272,7 +1272,7 @@ static void set_multicast_list(struct net_device *dev)
static void SetMulticastFilter(struct net_device *dev)
{
struct depca_private *lp = netdev_priv(dev);
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
char *addrs;
int i, j, bit, byte;
u16 hashcode;
@@ -1287,9 +1287,8 @@ static void SetMulticastFilter(struct net_device *dev)
lp->init_block.mcast_table[i] = 0;
}
/* Add multicast addresses */
- for (i = 0; i < dev->mc_count; i++) { /* for each address in the list */
+ netdev_for_each_mc_addr(dmi, dev) {
addrs = dmi->dmi_addr;
- dmi = dmi->next;
if ((*addrs & 0x01) == 1) { /* multicast address? */
crc = ether_crc(ETH_ALEN, addrs);
hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 2a8b6a7c0b87..b05bad829827 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -1128,19 +1128,16 @@ set_multicast (struct net_device *dev)
/* Receive all frames promiscuously. */
rx_mode = ReceiveAllFrames;
} else if ((dev->flags & IFF_ALLMULTI) ||
- (dev->mc_count > multicast_filter_limit)) {
+ (netdev_mc_count(dev) > multicast_filter_limit)) {
/* Receive broadcast and multicast frames */
rx_mode = ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast;
- } else if (dev->mc_count > 0) {
- int i;
+ } else if (!netdev_mc_empty(dev)) {
struct dev_mc_list *mclist;
/* Receive broadcast frames and multicast frames filtering
by Hashtable */
rx_mode =
ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
- for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist=mclist->next)
- {
+ netdev_for_each_mc_addr(mclist, dev) {
int bit, index = 0;
int crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
/* The inverted high significant 6 bits of CRC are
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
index 266ec8777ca8..7caab3d26a9e 100644
--- a/drivers/net/dl2k.h
+++ b/drivers/net/dl2k.h
@@ -537,7 +537,7 @@ struct netdev_private {
driver_data Data private to the driver.
*/
-static const struct pci_device_id rio_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(rio_pci_tbl) = {
{0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, },
{0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, },
{ }
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index b37730065688..1c67f1138ca7 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -724,8 +724,7 @@ static void
dm9000_hash_table(struct net_device *dev)
{
board_info_t *db = netdev_priv(dev);
- struct dev_mc_list *mcptr = dev->mc_list;
- int mc_cnt = dev->mc_count;
+ struct dev_mc_list *mcptr;
int i, oft;
u32 hash_val;
u16 hash_table[4];
@@ -753,7 +752,7 @@ dm9000_hash_table(struct net_device *dev)
rcr |= RCR_ALL;
/* the multicast address in Hash Table : 64 bits */
- for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
+ netdev_for_each_mc_addr(mcptr, dev) {
hash_val = ether_crc_le(6, mcptr->dmi_addr) & 0x3f;
hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
}
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 839fb2b136d3..a26ccab057d5 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -208,7 +208,7 @@ MODULE_PARM_DESC(use_io, "Force use of i/o access mode");
#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\
PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \
PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich }
-static struct pci_device_id e100_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(e100_id_table) = {
INTEL_8255X_ETHERNET_DEVICE(0x1029, 0),
INTEL_8255X_ETHERNET_DEVICE(0x1030, 0),
INTEL_8255X_ETHERNET_DEVICE(0x1031, 3),
@@ -1537,14 +1537,18 @@ static int e100_hw_init(struct nic *nic)
static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb)
{
struct net_device *netdev = nic->netdev;
- struct dev_mc_list *list = netdev->mc_list;
- u16 i, count = min(netdev->mc_count, E100_MAX_MULTICAST_ADDRS);
+ struct dev_mc_list *list;
+ u16 i, count = min(netdev_mc_count(netdev), E100_MAX_MULTICAST_ADDRS);
cb->command = cpu_to_le16(cb_multi);
cb->u.multi.count = cpu_to_le16(count * ETH_ALEN);
- for (i = 0; list && i < count; i++, list = list->next)
- memcpy(&cb->u.multi.addr[i*ETH_ALEN], &list->dmi_addr,
+ i = 0;
+ netdev_for_each_mc_addr(list, netdev) {
+ if (i == count)
+ break;
+ memcpy(&cb->u.multi.addr[i++ * ETH_ALEN], &list->dmi_addr,
ETH_ALEN);
+ }
}
static void e100_set_multicast_list(struct net_device *netdev)
@@ -1552,7 +1556,7 @@ static void e100_set_multicast_list(struct net_device *netdev)
struct nic *nic = netdev_priv(netdev);
DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n",
- netdev->mc_count, netdev->flags);
+ netdev_mc_count(netdev), netdev->flags);
if (netdev->flags & IFF_PROMISC)
nic->flags |= promiscuous;
@@ -1560,7 +1564,7 @@ static void e100_set_multicast_list(struct net_device *netdev)
nic->flags &= ~promiscuous;
if (netdev->flags & IFF_ALLMULTI ||
- netdev->mc_count > E100_MAX_MULTICAST_ADDRS)
+ netdev_mc_count(netdev) > E100_MAX_MULTICAST_ADDRS)
nic->flags |= multicast_all;
else
nic->flags &= ~multicast_all;
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 2a567df3ea71..9902b33b7160 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -326,6 +326,8 @@ struct e1000_adapter {
/* for ioport free */
int bars;
int need_ioport;
+
+ bool discarding;
};
enum e1000_state_t {
@@ -347,6 +349,7 @@ extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
extern void e1000_update_stats(struct e1000_adapter *adapter);
+extern bool e1000_has_link(struct e1000_adapter *adapter);
extern void e1000_power_up_phy(struct e1000_adapter *);
extern void e1000_set_ethtool_ops(struct net_device *netdev);
extern void e1000_check_options(struct e1000_adapter *adapter);
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 13e9ece16889..c67e93117271 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -215,6 +215,23 @@ static int e1000_set_settings(struct net_device *netdev,
return 0;
}
+static u32 e1000_get_link(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ /*
+ * If the link is not reported up to netdev, interrupts are disabled,
+ * and so the physical link state may have changed since we last
+ * looked. Set get_link_status to make sure that the true link
+ * state is interrogated, rather than pulling a cached and possibly
+ * stale link state from the driver.
+ */
+ if (!netif_carrier_ok(netdev))
+ adapter->hw.get_link_status = 1;
+
+ return e1000_has_link(adapter);
+}
+
static void e1000_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
@@ -1892,7 +1909,7 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.get_msglevel = e1000_get_msglevel,
.set_msglevel = e1000_set_msglevel,
.nway_reset = e1000_nway_reset,
- .get_link = ethtool_op_get_link,
+ .get_link = e1000_get_link,
.get_eeprom_len = e1000_get_eeprom_len,
.get_eeprom = e1000_get_eeprom,
.set_eeprom = e1000_set_eeprom,
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 7e855f9bbd97..8be6faee43e6 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -42,7 +42,7 @@ static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation
* Macro expands to...
* {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
*/
-static struct pci_device_id e1000_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
INTEL_E1000_ETHERNET_DEVICE(0x1000),
INTEL_E1000_ETHERNET_DEVICE(0x1001),
INTEL_E1000_ETHERNET_DEVICE(0x1004),
@@ -847,6 +847,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
goto err_pci_reg;
pci_set_master(pdev);
+ err = pci_save_state(pdev);
+ if (err)
+ goto err_alloc_etherdev;
err = -ENOMEM;
netdev = alloc_etherdev(sizeof(struct e1000_adapter));
@@ -1698,18 +1701,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
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;
@@ -2139,7 +2130,7 @@ static void e1000_set_rx_mode(struct net_device *netdev)
rctl |= E1000_RCTL_VFE;
}
- if (netdev->uc.count > rar_entries - 1) {
+ if (netdev_uc_count(netdev) > rar_entries - 1) {
rctl |= E1000_RCTL_UPE;
} else if (!(netdev->flags & IFF_PROMISC)) {
rctl &= ~E1000_RCTL_UPE;
@@ -2162,7 +2153,7 @@ static void e1000_set_rx_mode(struct net_device *netdev)
*/
i = 1;
if (use_uc)
- list_for_each_entry(ha, &netdev->uc.list, list) {
+ netdev_for_each_uc_addr(ha, netdev) {
if (i == rar_entries)
break;
e1000_rar_set(hw, ha->addr, i++);
@@ -2170,29 +2161,25 @@ static void e1000_set_rx_mode(struct net_device *netdev)
WARN_ON(i == rar_entries);
- mc_ptr = netdev->mc_list;
-
- for (; i < rar_entries; i++) {
- if (mc_ptr) {
- e1000_rar_set(hw, mc_ptr->da_addr, i);
- mc_ptr = mc_ptr->next;
+ netdev_for_each_mc_addr(mc_ptr, netdev) {
+ if (i == rar_entries) {
+ /* load any remaining addresses into the hash table */
+ u32 hash_reg, hash_bit, mta;
+ hash_value = e1000_hash_mc_addr(hw, mc_ptr->da_addr);
+ hash_reg = (hash_value >> 5) & 0x7F;
+ hash_bit = hash_value & 0x1F;
+ mta = (1 << hash_bit);
+ mcarray[hash_reg] |= mta;
} else {
- E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0);
- E1000_WRITE_FLUSH();
- E1000_WRITE_REG_ARRAY(hw, RA, (i << 1) + 1, 0);
- E1000_WRITE_FLUSH();
+ e1000_rar_set(hw, mc_ptr->da_addr, i++);
}
}
- /* load any remaining addresses into the hash table */
-
- for (; mc_ptr; mc_ptr = mc_ptr->next) {
- u32 hash_reg, hash_bit, mta;
- hash_value = e1000_hash_mc_addr(hw, mc_ptr->da_addr);
- hash_reg = (hash_value >> 5) & 0x7F;
- hash_bit = hash_value & 0x1F;
- mta = (1 << hash_bit);
- mcarray[hash_reg] |= mta;
+ for (; i < rar_entries; i++) {
+ E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0);
+ E1000_WRITE_FLUSH();
+ E1000_WRITE_REG_ARRAY(hw, RA, (i << 1) + 1, 0);
+ E1000_WRITE_FLUSH();
}
/* write the hash table completely, write from bottom to avoid
@@ -2258,7 +2245,7 @@ static void e1000_82547_tx_fifo_stall(unsigned long data)
}
}
-static bool e1000_has_link(struct e1000_adapter *adapter)
+bool e1000_has_link(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
bool link_active = false;
@@ -2802,13 +2789,13 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
dma_error:
dev_err(&pdev->dev, "TX DMA map failed\n");
buffer_info->dma = 0;
- count--;
-
- while (count >= 0) {
+ if (count)
count--;
- i--;
- if (i < 0)
+
+ while (count--) {
+ if (i==0)
i += tx_ring->count;
+ i--;
buffer_info = &tx_ring->buffer_info[i];
e1000_unmap_and_free_tx_resource(adapter, buffer_info);
}
@@ -3176,13 +3163,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
* however with the new *_jumbo_rx* routines, jumbo receives will use
* fragmented skbs */
- 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)
+ if (max_frame <= E1000_RXBUFFER_2048)
adapter->rx_buffer_len = E1000_RXBUFFER_2048;
else
#if (PAGE_SIZE >= E1000_RXBUFFER_16384)
@@ -3850,13 +3831,22 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
length = le16_to_cpu(rx_desc->length);
/* !EOP means multiple descriptors were used to store a single
- * packet, also make sure the frame isn't just CRC only */
- if (unlikely(!(status & E1000_RXD_STAT_EOP) || (length <= 4))) {
+ * packet, if thats the case we need to toss it. In fact, we
+ * to toss every packet with the EOP bit clear and the next
+ * frame that _does_ have the EOP bit set, as it is by
+ * definition only a frame fragment
+ */
+ if (unlikely(!(status & E1000_RXD_STAT_EOP)))
+ adapter->discarding = true;
+
+ if (adapter->discarding) {
/* All receives must fit into a single buffer */
E1000_DBG("%s: Receive packet consumed multiple"
" buffers\n", netdev->name);
/* recycle */
buffer_info->skb = skb;
+ if (status & E1000_RXD_STAT_EOP)
+ adapter->discarding = false;
goto next_desc;
}
@@ -4015,11 +4005,21 @@ check_page:
}
}
- if (!buffer_info->dma)
+ if (!buffer_info->dma) {
buffer_info->dma = pci_map_page(pdev,
buffer_info->page, 0,
buffer_info->length,
PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(pdev, buffer_info->dma)) {
+ put_page(buffer_info->page);
+ dev_kfree_skb(skb);
+ buffer_info->page = NULL;
+ buffer_info->skb = NULL;
+ buffer_info->dma = 0;
+ adapter->alloc_rx_buff_failed++;
+ break; /* while !buffer_info->skb */
+ }
+ }
rx_desc = E1000_RX_DESC(*rx_ring, i);
rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
@@ -4110,6 +4110,13 @@ map_skb:
skb->data,
buffer_info->length,
PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(pdev, buffer_info->dma)) {
+ dev_kfree_skb(skb);
+ buffer_info->skb = NULL;
+ buffer_info->dma = 0;
+ adapter->alloc_rx_buff_failed++;
+ break; /* while !buffer_info->skb */
+ }
/*
* XXX if it was allocated cleanly it will never map to a
@@ -4605,6 +4612,7 @@ static int e1000_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
+ pci_save_state(pdev);
if (adapter->need_ioport)
err = pci_enable_device(pdev);
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index 02d67d047d96..712ccc66ba25 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -267,8 +267,14 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
}
switch (hw->mac.type) {
+ case e1000_82573:
+ func->set_lan_id = e1000_set_lan_id_single_port;
+ func->check_mng_mode = e1000e_check_mng_mode_generic;
+ func->led_on = e1000e_led_on_generic;
+ break;
case e1000_82574:
case e1000_82583:
+ func->set_lan_id = e1000_set_lan_id_single_port;
func->check_mng_mode = e1000_check_mng_mode_82574;
func->led_on = e1000_led_on_82574;
break;
@@ -922,9 +928,12 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
ew32(IMC, 0xffffffff);
icr = er32(ICR);
- if (hw->mac.type == e1000_82571 &&
- hw->dev_spec.e82571.alt_mac_addr_is_present)
- e1000e_set_laa_state_82571(hw, true);
+ /* Install any alternate MAC address into RAR0 */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+ if (ret_val)
+ return ret_val;
+
+ e1000e_set_laa_state_82571(hw, true);
/* Reinitialize the 82571 serdes link state machine */
if (hw->phy.media_type == e1000_media_type_internal_serdes)
@@ -1225,32 +1234,6 @@ static s32 e1000_led_on_82574(struct e1000_hw *hw)
}
/**
- * e1000_update_mc_addr_list_82571 - Update Multicast addresses
- * @hw: pointer to the HW structure
- * @mc_addr_list: array of multicast addresses to program
- * @mc_addr_count: number of multicast addresses to program
- * @rar_used_count: the first RAR register free to program
- * @rar_count: total number of supported Receive Address Registers
- *
- * Updates the Receive Address Registers and Multicast Table Array.
- * The caller must have a packed mc_addr_list of multicast addresses.
- * The parameter rar_count will usually be hw->mac.rar_entry_count
- * unless there are workarounds that change this.
- **/
-static void e1000_update_mc_addr_list_82571(struct e1000_hw *hw,
- u8 *mc_addr_list,
- u32 mc_addr_count,
- u32 rar_used_count,
- u32 rar_count)
-{
- if (e1000e_get_laa_state_82571(hw))
- rar_count--;
-
- e1000e_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count,
- rar_used_count, rar_count);
-}
-
-/**
* e1000_setup_link_82571 - Setup flow control and link settings
* @hw: pointer to the HW structure
*
@@ -1363,7 +1346,7 @@ static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw)
*
* 1) down
* 2) autoneg_progress
- * 3) autoneg_complete (the link sucessfully autonegotiated)
+ * 3) autoneg_complete (the link successfully autonegotiated)
* 4) forced_up (the link has been forced up, it did not autonegotiate)
*
**/
@@ -1621,6 +1604,29 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
}
/**
+ * e1000_read_mac_addr_82571 - Read device MAC address
+ * @hw: pointer to the HW structure
+ **/
+static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw)
+{
+ s32 ret_val = 0;
+
+ /*
+ * If there's an alternate MAC address place it in RAR0
+ * so that it will override the Si installed default perm
+ * address.
+ */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
* e1000_power_down_phy_copper_82571 - Remove link during PHY power down
* @hw: pointer to the HW structure
*
@@ -1695,10 +1701,11 @@ static struct e1000_mac_operations e82571_mac_ops = {
.cleanup_led = e1000e_cleanup_led_generic,
.clear_hw_cntrs = e1000_clear_hw_cntrs_82571,
.get_bus_info = e1000e_get_bus_info_pcie,
+ .set_lan_id = e1000_set_lan_id_multi_port_pcie,
/* .get_link_up_info: media type dependent */
/* .led_on: mac type dependent */
.led_off = e1000e_led_off_generic,
- .update_mc_addr_list = e1000_update_mc_addr_list_82571,
+ .update_mc_addr_list = e1000e_update_mc_addr_list_generic,
.write_vfta = e1000_write_vfta_generic,
.clear_vfta = e1000_clear_vfta_82571,
.reset_hw = e1000_reset_hw_82571,
@@ -1706,6 +1713,7 @@ static struct e1000_mac_operations e82571_mac_ops = {
.setup_link = e1000_setup_link_82571,
/* .setup_physical_interface: media type dependent */
.setup_led = e1000e_setup_led_generic,
+ .read_mac_addr = e1000_read_mac_addr_82571,
};
static struct e1000_phy_operations e82_phy_ops_igp = {
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index e02e38221ed4..e301e26d6897 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -320,6 +320,8 @@
#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */
/* Header split receive */
+#define E1000_RFCTL_NFSW_DIS 0x00000040
+#define E1000_RFCTL_NFSR_DIS 0x00000080
#define E1000_RFCTL_ACK_DIS 0x00001000
#define E1000_RFCTL_EXTEN 0x00008000
#define E1000_RFCTL_IPV6_EX_DIS 0x00010000
@@ -460,6 +462,8 @@
*/
#define E1000_RAR_ENTRIES 15
#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */
+#define E1000_RAL_MAC_ADDR_LEN 4
+#define E1000_RAH_MAC_ADDR_LEN 2
/* Error Codes */
#define E1000_ERR_NVM 1
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index d6ee28f6ea08..c2ec095d2163 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -421,6 +421,7 @@ struct e1000_info {
/* CRC Stripping defines */
#define FLAG2_CRC_STRIPPING (1 << 0)
#define FLAG2_HAS_PHY_WAKEUP (1 << 1)
+#define FLAG2_IS_DISCARDING (1 << 2)
#define E1000_RX_DESC_PS(R, i) \
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
@@ -458,7 +459,7 @@ extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter);
extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
extern void e1000e_update_stats(struct e1000_adapter *adapter);
-extern bool e1000_has_link(struct e1000_adapter *adapter);
+extern bool e1000e_has_link(struct e1000_adapter *adapter);
extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
@@ -502,6 +503,8 @@ extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
extern s32 e1000e_led_on_generic(struct e1000_hw *hw);
extern s32 e1000e_led_off_generic(struct e1000_hw *hw);
extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw);
+extern void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
+extern void e1000_set_lan_id_single_port(struct e1000_hw *hw);
extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex);
extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex);
extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw);
@@ -516,9 +519,7 @@ extern void e1000_clear_vfta_generic(struct e1000_hw *hw);
extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
extern void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
u8 *mc_addr_list,
- u32 mc_addr_count,
- u32 rar_used_count,
- u32 rar_count);
+ u32 mc_addr_count);
extern void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
@@ -529,6 +530,7 @@ extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw);
extern s32 e1000e_force_mac_fc(struct e1000_hw *hw);
extern s32 e1000e_blink_led(struct e1000_hw *hw);
extern void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
+extern s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw);
extern void e1000e_reset_adaptive(struct e1000_hw *hw);
extern void e1000e_update_adaptive(struct e1000_hw *hw);
@@ -628,7 +630,15 @@ extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16
extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
extern void e1000e_release_nvm(struct e1000_hw *hw);
extern void e1000e_reload_nvm(struct e1000_hw *hw);
-extern s32 e1000e_read_mac_addr(struct e1000_hw *hw);
+extern s32 e1000_read_mac_addr_generic(struct e1000_hw *hw);
+
+static inline s32 e1000e_read_mac_addr(struct e1000_hw *hw)
+{
+ if (hw->mac.ops.read_mac_addr)
+ return hw->mac.ops.read_mac_addr(hw);
+
+ return e1000_read_mac_addr_generic(hw);
+}
static inline s32 e1000_validate_nvm_checksum(struct e1000_hw *hw)
{
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
index e2aa3b788564..27d21589a69a 100644
--- a/drivers/net/e1000e/es2lan.c
+++ b/drivers/net/e1000e/es2lan.c
@@ -246,6 +246,9 @@ static s32 e1000_init_mac_params_80003es2lan(struct e1000_adapter *adapter)
break;
}
+ /* set lan id for port to determine which phy lock to use */
+ hw->mac.ops.set_lan_id(hw);
+
return 0;
}
@@ -814,7 +817,9 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
ew32(IMC, 0xffffffff);
icr = er32(ICR);
- return 0;
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+
+ return ret_val;
}
/**
@@ -1340,6 +1345,29 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
}
/**
+ * e1000_read_mac_addr_80003es2lan - Read device MAC address
+ * @hw: pointer to the HW structure
+ **/
+static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw)
+{
+ s32 ret_val = 0;
+
+ /*
+ * If there's an alternate MAC address place it in RAR0
+ * so that it will override the Si installed default perm
+ * address.
+ */
+ ret_val = e1000_check_alt_mac_addr_generic(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
+ return ret_val;
+}
+
+/**
* e1000_power_down_phy_copper_80003es2lan - Remove link during PHY power down
* @hw: pointer to the HW structure
*
@@ -1403,12 +1431,14 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
}
static struct e1000_mac_operations es2_mac_ops = {
+ .read_mac_addr = e1000_read_mac_addr_80003es2lan,
.id_led_init = e1000e_id_led_init,
.check_mng_mode = e1000e_check_mng_mode_generic,
/* check_for_link dependent on media type */
.cleanup_led = e1000e_cleanup_led_generic,
.clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan,
.get_bus_info = e1000e_get_bus_info_pcie,
+ .set_lan_id = e1000_set_lan_id_multi_port_pcie,
.get_link_up_info = e1000_get_link_up_info_80003es2lan,
.led_on = e1000e_led_on_generic,
.led_off = e1000e_led_off_generic,
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 0aa50c229c79..b33e3cbe9ab0 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -202,7 +202,7 @@ static u32 e1000_get_link(struct net_device *netdev)
if (!netif_carrier_ok(netdev))
mac->get_link_status = 1;
- return e1000_has_link(adapter);
+ return e1000e_has_link(adapter);
}
static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index eccf29b75c41..8bdcd5f24eff 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -389,6 +389,9 @@ enum e1e_registers {
#define E1000_FUNC_1 1
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0 0
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1 3
+
enum e1000_mac_type {
e1000_82571,
e1000_82572,
@@ -746,16 +749,18 @@ struct e1000_mac_operations {
void (*clear_hw_cntrs)(struct e1000_hw *);
void (*clear_vfta)(struct e1000_hw *);
s32 (*get_bus_info)(struct e1000_hw *);
+ void (*set_lan_id)(struct e1000_hw *);
s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
s32 (*led_on)(struct e1000_hw *);
s32 (*led_off)(struct e1000_hw *);
- void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32, u32, u32);
+ void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32);
s32 (*reset_hw)(struct e1000_hw *);
s32 (*init_hw)(struct e1000_hw *);
s32 (*setup_link)(struct e1000_hw *);
s32 (*setup_physical_interface)(struct e1000_hw *);
s32 (*setup_led)(struct e1000_hw *);
void (*write_vfta)(struct e1000_hw *, u32, u32);
+ s32 (*read_mac_addr)(struct e1000_hw *);
};
/* Function pointers for the PHY. */
@@ -814,6 +819,10 @@ struct e1000_mac_info {
u16 ifs_ratio;
u16 ifs_step_size;
u16 mta_reg_count;
+
+ /* Maximum size of the MTA register table in all supported adapters */
+ #define MAX_MTA_REG 128
+ u32 mta_shadow[MAX_MTA_REG];
u16 rar_entry_count;
u8 forced_speed_duplex;
@@ -897,7 +906,6 @@ struct e1000_fc_info {
struct e1000_dev_spec_82571 {
bool laa_is_present;
- bool alt_mac_addr_is_present;
u32 smb_counter;
};
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index 8b6ecd127889..8b5e157e9c87 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -2740,6 +2740,16 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
reg &= ~(1 << 31);
ew32(STATUS, reg);
}
+
+ /*
+ * work-around descriptor data corruption issue during nfs v2 udp
+ * traffic, just disable the nfs filtering capability
+ */
+ reg = er32(RFCTL);
+ reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
+ ew32(RFCTL, reg);
+
+ return;
}
/**
@@ -3368,6 +3378,7 @@ static struct e1000_mac_operations ich8_mac_ops = {
/* cleanup_led dependent on mac type */
.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan,
.get_bus_info = e1000_get_bus_info_ich8lan,
+ .set_lan_id = e1000_set_lan_id_single_port,
.get_link_up_info = e1000_get_link_up_info_ich8lan,
/* led_on dependent on mac type */
/* led_off dependent on mac type */
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
index 2fa9b36a2c5a..a8b2c0de27c4 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/e1000e/lib.c
@@ -51,10 +51,10 @@ enum e1000_mng_mode {
**/
s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw)
{
+ struct e1000_mac_info *mac = &hw->mac;
struct e1000_bus_info *bus = &hw->bus;
struct e1000_adapter *adapter = hw->adapter;
- u32 status;
- u16 pcie_link_status, pci_header_type, cap_offset;
+ u16 pcie_link_status, cap_offset;
cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
if (!cap_offset) {
@@ -68,20 +68,46 @@ s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw)
PCIE_LINK_WIDTH_SHIFT);
}
- pci_read_config_word(adapter->pdev, PCI_HEADER_TYPE_REGISTER,
- &pci_header_type);
- if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
- status = er32(STATUS);
- bus->func = (status & E1000_STATUS_FUNC_MASK)
- >> E1000_STATUS_FUNC_SHIFT;
- } else {
- bus->func = 0;
- }
+ mac->ops.set_lan_id(hw);
return 0;
}
/**
+ * e1000_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices
+ *
+ * @hw: pointer to the HW structure
+ *
+ * Determines the LAN function id by reading memory-mapped registers
+ * and swaps the port value if requested.
+ **/
+void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+ u32 reg;
+
+ /*
+ * The status register reports the correct function number
+ * for the device regardless of function swap state.
+ */
+ reg = er32(STATUS);
+ bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
+}
+
+/**
+ * e1000_set_lan_id_single_port - Set LAN id for a single port device
+ * @hw: pointer to the HW structure
+ *
+ * Sets the LAN function id to zero for a single port device.
+ **/
+void e1000_set_lan_id_single_port(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+
+ bus->func = 0;
+}
+
+/**
* e1000_clear_vfta_generic - Clear VLAN filter table
* @hw: pointer to the HW structure
*
@@ -139,6 +165,68 @@ void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
}
/**
+ * e1000_check_alt_mac_addr_generic - Check for alternate MAC addr
+ * @hw: pointer to the HW structure
+ *
+ * Checks the nvm for an alternate MAC address. An alternate MAC address
+ * can be setup by pre-boot software and must be treated like a permanent
+ * address and must override the actual permanent MAC address. If an
+ * alternate MAC address is found it is programmed into RAR0, replacing
+ * the permanent address that was installed into RAR0 by the Si on reset.
+ * This function will return SUCCESS unless it encounters an error while
+ * reading the EEPROM.
+ **/
+s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
+{
+ u32 i;
+ s32 ret_val = 0;
+ u16 offset, nvm_alt_mac_addr_offset, nvm_data;
+ u8 alt_mac_addr[ETH_ALEN];
+
+ ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
+ &nvm_alt_mac_addr_offset);
+ if (ret_val) {
+ e_dbg("NVM Read Error\n");
+ goto out;
+ }
+
+ if (nvm_alt_mac_addr_offset == 0xFFFF) {
+ /* There is no Alternate MAC Address */
+ goto out;
+ }
+
+ if (hw->bus.func == E1000_FUNC_1)
+ nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
+ for (i = 0; i < ETH_ALEN; i += 2) {
+ offset = nvm_alt_mac_addr_offset + (i >> 1);
+ ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data);
+ if (ret_val) {
+ e_dbg("NVM Read Error\n");
+ goto out;
+ }
+
+ alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
+ alt_mac_addr[i + 1] = (u8)(nvm_data >> 8);
+ }
+
+ /* if multicast bit is set, the alternate address will not be used */
+ if (alt_mac_addr[0] & 0x01) {
+ e_dbg("Ignoring Alternate Mac Address with MC bit set\n");
+ goto out;
+ }
+
+ /*
+ * We have a valid alternate MAC address, and we want to treat it the
+ * same as the normal permanent MAC address stored by the HW into the
+ * RAR. Do this by mapping this address into RAR0.
+ */
+ e1000e_rar_set(hw, alt_mac_addr, 0);
+
+out:
+ return ret_val;
+}
+
+/**
* e1000e_rar_set - Set receive address register
* @hw: pointer to the HW structure
* @addr: pointer to the receive address
@@ -252,62 +340,34 @@ static u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
* @hw: pointer to the HW structure
* @mc_addr_list: array of multicast addresses to program
* @mc_addr_count: number of multicast addresses to program
- * @rar_used_count: the first RAR register free to program
- * @rar_count: total number of supported Receive Address Registers
*
- * Updates the Receive Address Registers and Multicast Table Array.
+ * Updates entire Multicast Table Array.
* The caller must have a packed mc_addr_list of multicast addresses.
- * The parameter rar_count will usually be hw->mac.rar_entry_count
- * unless there are workarounds that change this.
**/
void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
- u8 *mc_addr_list, u32 mc_addr_count,
- u32 rar_used_count, u32 rar_count)
+ u8 *mc_addr_list, u32 mc_addr_count)
{
- u32 i;
- u32 *mcarray = kzalloc(hw->mac.mta_reg_count * sizeof(u32), GFP_ATOMIC);
+ u32 hash_value, hash_bit, hash_reg;
+ int i;
- if (!mcarray) {
- printk(KERN_ERR "multicast array memory allocation failed\n");
- return;
- }
+ /* clear mta_shadow */
+ memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
- /*
- * Load the first set of multicast addresses into the exact
- * filters (RAR). If there are not enough to fill the RAR
- * array, clear the filters.
- */
- for (i = rar_used_count; i < rar_count; i++) {
- if (mc_addr_count) {
- e1000e_rar_set(hw, mc_addr_list, i);
- mc_addr_count--;
- mc_addr_list += ETH_ALEN;
- } else {
- E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0);
- e1e_flush();
- E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0);
- e1e_flush();
- }
- }
-
- /* Load any remaining multicast addresses into the hash table. */
- for (; mc_addr_count > 0; mc_addr_count--) {
- u32 hash_value, hash_reg, hash_bit, mta;
+ /* update mta_shadow from mc_addr_list */
+ for (i = 0; (u32) i < mc_addr_count; i++) {
hash_value = e1000_hash_mc_addr(hw, mc_addr_list);
- e_dbg("Hash value = 0x%03X\n", hash_value);
+
hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
hash_bit = hash_value & 0x1F;
- mta = (1 << hash_bit);
- mcarray[hash_reg] |= mta;
- mc_addr_list += ETH_ALEN;
- }
- /* write the hash table completely */
- for (i = 0; i < hw->mac.mta_reg_count; i++)
- E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, mcarray[i]);
+ hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
+ mc_addr_list += (ETH_ALEN);
+ }
+ /* replace the entire MTA table */
+ for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
e1e_flush();
- kfree(mcarray);
}
/**
@@ -587,7 +647,7 @@ s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
if (!(rxcw & E1000_RXCW_IV)) {
mac->serdes_has_link = true;
e_dbg("SERDES: Link up - autoneg "
- "completed sucessfully.\n");
+ "completed successfully.\n");
} else {
mac->serdes_has_link = false;
e_dbg("SERDES: Link down - invalid"
@@ -2072,67 +2132,27 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
}
/**
- * e1000e_read_mac_addr - Read device MAC address
+ * e1000_read_mac_addr_generic - Read device MAC address
* @hw: pointer to the HW structure
*
* Reads the device MAC address from the EEPROM and stores the value.
* Since devices with two ports use the same EEPROM, we increment the
* last bit in the MAC address for the second port.
**/
-s32 e1000e_read_mac_addr(struct e1000_hw *hw)
+s32 e1000_read_mac_addr_generic(struct e1000_hw *hw)
{
- s32 ret_val;
- u16 offset, nvm_data, i;
- u16 mac_addr_offset = 0;
-
- if (hw->mac.type == e1000_82571) {
- /* Check for an alternate MAC address. An alternate MAC
- * address can be setup by pre-boot software and must be
- * treated like a permanent address and must override the
- * actual permanent MAC address.*/
- ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
- &mac_addr_offset);
- if (ret_val) {
- e_dbg("NVM Read Error\n");
- return ret_val;
- }
- if (mac_addr_offset == 0xFFFF)
- mac_addr_offset = 0;
-
- if (mac_addr_offset) {
- if (hw->bus.func == E1000_FUNC_1)
- mac_addr_offset += ETH_ALEN/sizeof(u16);
-
- /* make sure we have a valid mac address here
- * before using it */
- ret_val = e1000_read_nvm(hw, mac_addr_offset, 1,
- &nvm_data);
- if (ret_val) {
- e_dbg("NVM Read Error\n");
- return ret_val;
- }
- if (nvm_data & 0x0001)
- mac_addr_offset = 0;
- }
+ u32 rar_high;
+ u32 rar_low;
+ u16 i;
- if (mac_addr_offset)
- hw->dev_spec.e82571.alt_mac_addr_is_present = 1;
- }
+ rar_high = er32(RAH(0));
+ rar_low = er32(RAL(0));
- for (i = 0; i < ETH_ALEN; i += 2) {
- offset = mac_addr_offset + (i >> 1);
- ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data);
- if (ret_val) {
- e_dbg("NVM Read Error\n");
- return ret_val;
- }
- hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
- hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
- }
+ for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
+ hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
- /* Flip last bit of mac address if we're on second port */
- if (!mac_addr_offset && hw->bus.func == E1000_FUNC_1)
- hw->mac.perm_addr[5] ^= 1;
+ for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
+ hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
for (i = 0; i < ETH_ALEN; i++)
hw->mac.addr[i] = hw->mac.perm_addr[i];
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index c45965a256b6..88d54d3efcef 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -450,13 +450,23 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
length = le16_to_cpu(rx_desc->length);
- /* !EOP means multiple descriptors were used to store a single
- * packet, also make sure the frame isn't just CRC only */
- if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) {
+ /*
+ * !EOP means multiple descriptors were used to store a single
+ * packet, if that's the case we need to toss it. In fact, we
+ * need to toss every packet with the EOP bit clear and the
+ * next frame that _does_ have the EOP bit set, as it is by
+ * definition only a frame fragment
+ */
+ if (unlikely(!(status & E1000_RXD_STAT_EOP)))
+ adapter->flags2 |= FLAG2_IS_DISCARDING;
+
+ if (adapter->flags2 & FLAG2_IS_DISCARDING) {
/* All receives must fit into a single buffer */
e_dbg("Receive packet consumed multiple buffers\n");
/* recycle */
buffer_info->skb = skb;
+ if (status & E1000_RXD_STAT_EOP)
+ adapter->flags2 &= ~FLAG2_IS_DISCARDING;
goto next_desc;
}
@@ -745,10 +755,16 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
PCI_DMA_FROMDEVICE);
buffer_info->dma = 0;
- if (!(staterr & E1000_RXD_STAT_EOP)) {
+ /* see !EOP comment in other rx routine */
+ if (!(staterr & E1000_RXD_STAT_EOP))
+ adapter->flags2 |= FLAG2_IS_DISCARDING;
+
+ if (adapter->flags2 & FLAG2_IS_DISCARDING) {
e_dbg("Packet Split buffers didn't pick up the full "
"packet\n");
dev_kfree_skb_irq(skb);
+ if (staterr & E1000_RXD_STAT_EOP)
+ adapter->flags2 &= ~FLAG2_IS_DISCARDING;
goto next_desc;
}
@@ -1118,6 +1134,7 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter)
rx_ring->next_to_clean = 0;
rx_ring->next_to_use = 0;
+ adapter->flags2 &= ~FLAG2_IS_DISCARDING;
writel(0, adapter->hw.hw_addr + rx_ring->head);
writel(0, adapter->hw.hw_addr + rx_ring->tail);
@@ -2333,18 +2350,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
rctl &= ~E1000_RCTL_SZ_4096;
rctl |= E1000_RCTL_BSEX;
switch (adapter->rx_buffer_len) {
- case 256:
- rctl |= E1000_RCTL_SZ_256;
- rctl &= ~E1000_RCTL_BSEX;
- break;
- case 512:
- rctl |= E1000_RCTL_SZ_512;
- rctl &= ~E1000_RCTL_BSEX;
- break;
- case 1024:
- rctl |= E1000_RCTL_SZ_1024;
- rctl &= ~E1000_RCTL_BSEX;
- break;
case 2048:
default:
rctl |= E1000_RCTL_SZ_2048;
@@ -2536,22 +2541,14 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
* @hw: pointer to the HW structure
* @mc_addr_list: array of multicast addresses to program
* @mc_addr_count: number of multicast addresses to program
- * @rar_used_count: the first RAR register free to program
- * @rar_count: total number of supported Receive Address Registers
*
- * Updates the Receive Address Registers and Multicast Table Array.
+ * Updates the Multicast Table Array.
* The caller must have a packed mc_addr_list of multicast addresses.
- * The parameter rar_count will usually be hw->mac.rar_entry_count
- * unless there are workarounds that change this. Currently no func pointer
- * exists and all implementations are handled in the generic version of this
- * function.
**/
static void e1000_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list,
- u32 mc_addr_count, u32 rar_used_count,
- u32 rar_count)
+ u32 mc_addr_count)
{
- hw->mac.ops.update_mc_addr_list(hw, mc_addr_list, mc_addr_count,
- rar_used_count, rar_count);
+ hw->mac.ops.update_mc_addr_list(hw, mc_addr_list, mc_addr_count);
}
/**
@@ -2567,7 +2564,6 @@ static void e1000_set_multi(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- struct e1000_mac_info *mac = &hw->mac;
struct dev_mc_list *mc_ptr;
u8 *mta_list;
u32 rctl;
@@ -2593,31 +2589,25 @@ static void e1000_set_multi(struct net_device *netdev)
ew32(RCTL, rctl);
- if (netdev->mc_count) {
- mta_list = kmalloc(netdev->mc_count * 6, GFP_ATOMIC);
+ if (!netdev_mc_empty(netdev)) {
+ mta_list = kmalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC);
if (!mta_list)
return;
/* prepare a packed array of only addresses. */
- mc_ptr = netdev->mc_list;
-
- for (i = 0; i < netdev->mc_count; i++) {
- if (!mc_ptr)
- break;
- memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr,
- ETH_ALEN);
- mc_ptr = mc_ptr->next;
- }
+ i = 0;
+ netdev_for_each_mc_addr(mc_ptr, netdev)
+ memcpy(mta_list + (i++ * ETH_ALEN),
+ mc_ptr->dmi_addr, ETH_ALEN);
- e1000_update_mc_addr_list(hw, mta_list, i, 1,
- mac->rar_entry_count);
+ e1000_update_mc_addr_list(hw, mta_list, i);
kfree(mta_list);
} else {
/*
* if we're called from probe, we might not have
* anything to do here, so clear out the list
*/
- e1000_update_mc_addr_list(hw, NULL, 0, 1, mac->rar_entry_count);
+ e1000_update_mc_addr_list(hw, NULL, 0);
}
}
@@ -3477,7 +3467,7 @@ static void e1000_print_link_info(struct e1000_adapter *adapter)
((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" )));
}
-bool e1000_has_link(struct e1000_adapter *adapter)
+bool e1000e_has_link(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
bool link_active = 0;
@@ -3558,7 +3548,7 @@ static void e1000_watchdog_task(struct work_struct *work)
u32 link, tctl;
int tx_pending = 0;
- link = e1000_has_link(adapter);
+ link = e1000e_has_link(adapter);
if ((netif_carrier_ok(netdev)) && link) {
e1000e_enable_receives(adapter);
goto link_up;
@@ -3781,7 +3771,7 @@ static int e1000_tso(struct e1000_adapter *adapter,
0, IPPROTO_TCP, 0);
cmd_length = E1000_TXD_CMD_IP;
ipcse = skb_transport_offset(skb) - 1;
- } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+ } else if (skb_is_gso_v6(skb)) {
ipv6_hdr(skb)->payload_len = 0;
tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr,
@@ -3962,13 +3952,13 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
dma_error:
dev_err(&pdev->dev, "TX DMA map failed\n");
buffer_info->dma = 0;
- count--;
-
- while (count >= 0) {
+ if (count)
count--;
- i--;
- if (i < 0)
+
+ while (count--) {
+ if (i==0)
i += tx_ring->count;
+ i--;
buffer_info = &tx_ring->buffer_info[i];
e1000_put_txbuf(adapter, buffer_info);;
}
@@ -4317,13 +4307,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
* fragmented skbs
*/
- if (max_frame <= 256)
- adapter->rx_buffer_len = 256;
- else if (max_frame <= 512)
- adapter->rx_buffer_len = 512;
- else if (max_frame <= 1024)
- adapter->rx_buffer_len = 1024;
- else if (max_frame <= 2048)
+ if (max_frame <= 2048)
adapter->rx_buffer_len = 2048;
else
adapter->rx_buffer_len = 4096;
@@ -5135,7 +5119,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
e1000_eeprom_checks(adapter);
- /* copy the MAC address out of the NVM */
+ /* copy the MAC address */
if (e1000e_read_mac_addr(&adapter->hw))
e_err("NVM Read Error while reading MAC address\n");
@@ -5327,7 +5311,7 @@ static struct pci_error_handlers e1000_err_handler = {
.resume = e1000_io_resume,
};
-static struct pci_device_id e1000_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 },
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 94c59498cdb6..1b05bdf62c3c 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1287,9 +1287,10 @@ set_multicast_list(struct net_device *dev)
struct eepro_local *lp = netdev_priv(dev);
short ioaddr = dev->base_addr;
unsigned short mode;
- struct dev_mc_list *dmi=dev->mc_list;
+ struct dev_mc_list *dmi;
+ int mc_count = netdev_mc_count(dev);
- if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || dev->mc_count > 63)
+ if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || mc_count > 63)
{
eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
mode = inb(ioaddr + REG2);
@@ -1299,7 +1300,7 @@ set_multicast_list(struct net_device *dev)
eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
}
- else if (dev->mc_count==0 )
+ else if (mc_count == 0)
{
eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
mode = inb(ioaddr + REG2);
@@ -1329,12 +1330,10 @@ set_multicast_list(struct net_device *dev)
outw(MC_SETUP, ioaddr + IO_PORT);
outw(0, ioaddr + IO_PORT);
outw(0, ioaddr + IO_PORT);
- outw(6*(dev->mc_count + 1), ioaddr + IO_PORT);
+ outw(6 * (mc_count + 1), ioaddr + IO_PORT);
- for (i = 0; i < dev->mc_count; i++)
- {
- eaddrs=(unsigned short *)dmi->dmi_addr;
- dmi=dmi->next;
+ netdev_for_each_mc_addr(dmi, dev) {
+ eaddrs = (unsigned short *) dmi->dmi_addr;
outw(*eaddrs++, ioaddr + IO_PORT);
outw(*eaddrs++, ioaddr + IO_PORT);
outw(*eaddrs++, ioaddr + IO_PORT);
@@ -1348,7 +1347,7 @@ set_multicast_list(struct net_device *dev)
outb(MC_SETUP, ioaddr);
/* Update the transmit queue */
- i = lp->tx_end + XMT_HEADER + 6*(dev->mc_count + 1);
+ i = lp->tx_end + XMT_HEADER + 6 * (mc_count + 1);
if (lp->tx_start != lp->tx_end)
{
@@ -1380,8 +1379,8 @@ set_multicast_list(struct net_device *dev)
break;
} else if ((i & 0x0f) == 0x03) { /* MC-Done */
printk(KERN_DEBUG "%s: set Rx mode to %d address%s.\n",
- dev->name, dev->mc_count,
- dev->mc_count > 1 ? "es":"");
+ dev->name, mc_count,
+ mc_count > 1 ? "es":"");
break;
}
}
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 6fbfc8eee632..7013dc8a6cbc 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -1578,7 +1578,7 @@ static void eexp_setup_filter(struct net_device *dev)
{
struct dev_mc_list *dmi;
unsigned short ioaddr = dev->base_addr;
- int count = dev->mc_count;
+ int count = netdev_mc_count(dev);
int i;
if (count > 8) {
printk(KERN_INFO "%s: too many multicast addresses (%d)\n",
@@ -1588,23 +1588,19 @@ static void eexp_setup_filter(struct net_device *dev)
outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR);
outw(6*count, ioaddr+SHADOW(CONF_NR_MULTICAST));
- for (i = 0, dmi = dev->mc_list; i < count; i++, dmi = dmi->next) {
- unsigned short *data;
- if (!dmi) {
- printk(KERN_INFO "%s: too few multicast addresses\n", dev->name);
+ i = 0;
+ netdev_for_each_mc_addr(dmi, dev) {
+ unsigned short *data = (unsigned short *) dmi->dmi_addr;
+
+ if (i == count)
break;
- }
- if (dmi->dmi_addrlen != ETH_ALEN) {
- printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
- continue;
- }
- data = (unsigned short *)dmi->dmi_addr;
outw((CONF_MULTICAST+(6*i)) & ~31, ioaddr+SM_PTR);
outw(data[0], ioaddr+SHADOW(CONF_MULTICAST+(6*i)));
outw((CONF_MULTICAST+(6*i)+2) & ~31, ioaddr+SM_PTR);
outw(data[1], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+2));
outw((CONF_MULTICAST+(6*i)+4) & ~31, ioaddr+SM_PTR);
outw(data[2], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+4));
+ i++;
}
}
@@ -1627,9 +1623,9 @@ eexp_set_multicast(struct net_device *dev)
}
if (!(dev->flags & IFF_PROMISC)) {
eexp_setup_filter(dev);
- if (lp->old_mc_count != dev->mc_count) {
+ if (lp->old_mc_count != netdev_mc_count(dev)) {
kick = 1;
- lp->old_mc_count = dev->mc_count;
+ lp->old_mc_count = netdev_mc_count(dev);
}
}
if (kick) {
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 7b62336e6736..b004eaba3d7b 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -1967,7 +1967,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
{
struct ehea_port *port = netdev_priv(dev);
struct dev_mc_list *k_mcl_entry;
- int ret, i;
+ int ret;
if (dev->flags & IFF_PROMISC) {
ehea_promiscuous(dev, 1);
@@ -1981,7 +1981,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
}
ehea_allmulti(dev, 0);
- if (dev->mc_count) {
+ if (!netdev_mc_empty(dev)) {
ret = ehea_drop_multicast_list(dev);
if (ret) {
/* Dropping the current multicast list failed.
@@ -1990,15 +1990,14 @@ static void ehea_set_multicast_list(struct net_device *dev)
ehea_allmulti(dev, 1);
}
- if (dev->mc_count > port->adapter->max_mc_mac) {
+ if (netdev_mc_count(dev) > port->adapter->max_mc_mac) {
ehea_info("Mcast registration limit reached (0x%llx). "
"Use ALLMULTI!",
port->adapter->max_mc_mac);
goto out;
}
- for (i = 0, k_mcl_entry = dev->mc_list; i < dev->mc_count; i++,
- k_mcl_entry = k_mcl_entry->next)
+ netdev_for_each_mc_addr(k_mcl_entry, dev)
ehea_add_multicast_entry(port, k_mcl_entry->dmi_addr);
}
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index 66813c91a720..3ee32e58c7ec 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -1413,7 +1413,7 @@ static void enc28j60_set_multicast_list(struct net_device *dev)
if (netif_msg_link(priv))
dev_info(&dev->dev, "promiscuous mode\n");
priv->rxfilter = RXFILTER_PROMISC;
- } else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count) {
+ } else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) {
if (netif_msg_link(priv))
dev_info(&dev->dev, "%smulticast mode\n",
(dev->flags & IFF_ALLMULTI) ? "all-" : "");
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index e1c2076228ba..ee01f5a6d0d4 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -34,7 +34,7 @@
#define DRV_NAME "enic"
#define DRV_DESCRIPTION "Cisco 10G Ethernet Driver"
-#define DRV_VERSION "1.1.0.100"
+#define DRV_VERSION "1.1.0.241a"
#define DRV_COPYRIGHT "Copyright 2008-2009 Cisco Systems, Inc"
#define PFX DRV_NAME ": "
@@ -89,9 +89,12 @@ struct enic {
spinlock_t devcmd_lock;
u8 mac_addr[ETH_ALEN];
u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
+ unsigned int flags;
unsigned int mc_count;
int csum_rx_enabled;
u32 port_mtu;
+ u32 rx_coalesce_usecs;
+ u32 tx_coalesce_usecs;
/* work queue cache line section */
____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX];
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index f875751af15e..cf098bb636b8 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -51,7 +51,7 @@
#define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */
/* Supported devices */
-static struct pci_device_id enic_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(enic_id_table) = {
{ PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) },
{ 0, } /* end of table */
};
@@ -261,6 +261,62 @@ static void enic_set_msglevel(struct net_device *netdev, u32 value)
enic->msg_enable = value;
}
+static int enic_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ecmd)
+{
+ struct enic *enic = netdev_priv(netdev);
+
+ ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;
+ ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;
+
+ return 0;
+}
+
+static int enic_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ecmd)
+{
+ struct enic *enic = netdev_priv(netdev);
+ u32 tx_coalesce_usecs;
+ u32 rx_coalesce_usecs;
+
+ tx_coalesce_usecs = min_t(u32,
+ INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
+ ecmd->tx_coalesce_usecs);
+ rx_coalesce_usecs = min_t(u32,
+ INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
+ ecmd->rx_coalesce_usecs);
+
+ switch (vnic_dev_get_intr_mode(enic->vdev)) {
+ case VNIC_DEV_INTR_MODE_INTX:
+ if (tx_coalesce_usecs != rx_coalesce_usecs)
+ return -EINVAL;
+
+ vnic_intr_coalescing_timer_set(&enic->intr[ENIC_INTX_WQ_RQ],
+ INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
+ break;
+ case VNIC_DEV_INTR_MODE_MSI:
+ if (tx_coalesce_usecs != rx_coalesce_usecs)
+ return -EINVAL;
+
+ vnic_intr_coalescing_timer_set(&enic->intr[0],
+ INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
+ break;
+ case VNIC_DEV_INTR_MODE_MSIX:
+ vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_WQ],
+ INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
+ vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_RQ],
+ INTR_COALESCE_USEC_TO_HW(rx_coalesce_usecs));
+ break;
+ default:
+ break;
+ }
+
+ enic->tx_coalesce_usecs = tx_coalesce_usecs;
+ enic->rx_coalesce_usecs = rx_coalesce_usecs;
+
+ return 0;
+}
+
static const struct ethtool_ops enic_ethtool_ops = {
.get_settings = enic_get_settings,
.get_drvinfo = enic_get_drvinfo,
@@ -278,6 +334,8 @@ static const struct ethtool_ops enic_ethtool_ops = {
.set_sg = ethtool_op_set_sg,
.get_tso = ethtool_op_get_tso,
.set_tso = enic_set_tso,
+ .get_coalesce = enic_get_coalesce,
+ .set_coalesce = enic_set_coalesce,
.get_flags = ethtool_op_get_flags,
.set_flags = ethtool_op_set_flags,
};
@@ -363,12 +421,12 @@ static void enic_mtu_check(struct enic *enic)
u32 mtu = vnic_dev_mtu(enic->vdev);
if (mtu && mtu != enic->port_mtu) {
+ enic->port_mtu = mtu;
if (mtu < enic->netdev->mtu)
printk(KERN_WARNING PFX
"%s: interface MTU (%d) set higher "
"than switch port MTU (%d)\n",
enic->netdev->name, enic->netdev->mtu, mtu);
- enic->port_mtu = mtu;
}
}
@@ -673,7 +731,7 @@ static inline void enic_queue_wq_skb(struct enic *enic,
/* netif_tx_lock held, process context with BHs disabled, or BH */
static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,
- struct net_device *netdev)
+ struct net_device *netdev)
{
struct enic *enic = netdev_priv(netdev);
struct vnic_wq *wq = &enic->wq[0];
@@ -764,15 +822,16 @@ static int enic_set_mac_addr(struct net_device *netdev, char *addr)
static void enic_set_multicast_list(struct net_device *netdev)
{
struct enic *enic = netdev_priv(netdev);
- struct dev_mc_list *list = netdev->mc_list;
+ struct dev_mc_list *list;
int directed = 1;
int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0;
int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0;
int promisc = (netdev->flags & IFF_PROMISC) ? 1 : 0;
+ unsigned int mc_count = netdev_mc_count(netdev);
int allmulti = (netdev->flags & IFF_ALLMULTI) ||
- (netdev->mc_count > ENIC_MULTICAST_PERFECT_FILTERS);
+ mc_count > ENIC_MULTICAST_PERFECT_FILTERS;
+ unsigned int flags = netdev->flags | (allmulti ? IFF_ALLMULTI : 0);
u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
- unsigned int mc_count = netdev->mc_count;
unsigned int i, j;
if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS)
@@ -780,8 +839,11 @@ static void enic_set_multicast_list(struct net_device *netdev)
spin_lock(&enic->devcmd_lock);
- vnic_dev_packet_filter(enic->vdev, directed,
- multicast, broadcast, promisc, allmulti);
+ if (enic->flags != flags) {
+ enic->flags = flags;
+ vnic_dev_packet_filter(enic->vdev, directed,
+ multicast, broadcast, promisc, allmulti);
+ }
/* Is there an easier way? Trying to minimize to
* calls to add/del multicast addrs. We keep the
@@ -789,9 +851,11 @@ static void enic_set_multicast_list(struct net_device *netdev)
* look for changes to add/del.
*/
- for (i = 0; list && i < mc_count; i++) {
- memcpy(mc_addr[i], list->dmi_addr, ETH_ALEN);
- list = list->next;
+ i = 0;
+ netdev_for_each_mc_addr(list, netdev) {
+ if (i == mc_count)
+ break;
+ memcpy(mc_addr[i++], list->dmi_addr, ETH_ALEN);
}
for (i = 0; i < enic->mc_count; i++) {
@@ -1084,34 +1148,6 @@ static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
return 0;
}
-static void enic_rq_drop_buf(struct vnic_rq *rq,
- struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
- int skipped, void *opaque)
-{
- struct enic *enic = vnic_dev_priv(rq->vdev);
- struct sk_buff *skb = buf->os_buf;
-
- if (skipped)
- return;
-
- pci_unmap_single(enic->pdev, buf->dma_addr,
- buf->len, PCI_DMA_FROMDEVICE);
-
- dev_kfree_skb_any(skb);
-}
-
-static int enic_rq_service_drop(struct vnic_dev *vdev, struct cq_desc *cq_desc,
- u8 type, u16 q_number, u16 completed_index, void *opaque)
-{
- struct enic *enic = vnic_dev_priv(vdev);
-
- vnic_rq_service(&enic->rq[q_number], cq_desc,
- completed_index, VNIC_RQ_RETURN_DESC,
- enic_rq_drop_buf, opaque);
-
- return 0;
-}
-
static int enic_poll(struct napi_struct *napi, int budget)
{
struct enic *enic = container_of(napi, struct enic, napi);
@@ -1119,6 +1155,7 @@ static int enic_poll(struct napi_struct *napi, int budget)
unsigned int rq_work_to_do = budget;
unsigned int wq_work_to_do = -1; /* no limit */
unsigned int work_done, rq_work_done, wq_work_done;
+ int err;
/* Service RQ (first) and WQ
*/
@@ -1142,16 +1179,19 @@ static int enic_poll(struct napi_struct *napi, int budget)
0 /* don't unmask intr */,
0 /* don't reset intr timer */);
- if (rq_work_done > 0) {
+ err = vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
- /* Replenish RQ
- */
+ /* Buffer allocation failed. Stay in polling
+ * mode so we can try to fill the ring again.
+ */
- vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
+ if (err)
+ rq_work_done = rq_work_to_do;
- } else {
+ if (rq_work_done < rq_work_to_do) {
- /* If no work done, flush all LROs and exit polling
+ /* Some work done, but not enough to stay in polling,
+ * flush all LROs and exit polling
*/
if (netdev->features & NETIF_F_LRO)
@@ -1170,6 +1210,7 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
struct net_device *netdev = enic->netdev;
unsigned int work_to_do = budget;
unsigned int work_done;
+ int err;
/* Service RQ
*/
@@ -1177,25 +1218,30 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
work_done = vnic_cq_service(&enic->cq[ENIC_CQ_RQ],
work_to_do, enic_rq_service, NULL);
- if (work_done > 0) {
-
- /* Replenish RQ
- */
-
- vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
-
- /* Return intr event credits for this polling
- * cycle. An intr event is the completion of a
- * RQ packet.
- */
+ /* Return intr event credits for this polling
+ * cycle. An intr event is the completion of a
+ * RQ packet.
+ */
+ if (work_done > 0)
vnic_intr_return_credits(&enic->intr[ENIC_MSIX_RQ],
work_done,
0 /* don't unmask intr */,
0 /* don't reset intr timer */);
- } else {
- /* If no work done, flush all LROs and exit polling
+ err = vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
+
+ /* Buffer allocation failed. Stay in polling mode
+ * so we can try to fill the ring again.
+ */
+
+ if (err)
+ work_done = work_to_do;
+
+ if (work_done < work_to_do) {
+
+ /* Some work done, but not enough to stay in polling,
+ * flush all LROs and exit polling
*/
if (netdev->features & NETIF_F_LRO)
@@ -1304,6 +1350,24 @@ static int enic_request_intr(struct enic *enic)
return err;
}
+static void enic_synchronize_irqs(struct enic *enic)
+{
+ unsigned int i;
+
+ switch (vnic_dev_get_intr_mode(enic->vdev)) {
+ case VNIC_DEV_INTR_MODE_INTX:
+ case VNIC_DEV_INTR_MODE_MSI:
+ synchronize_irq(enic->pdev->irq);
+ break;
+ case VNIC_DEV_INTR_MODE_MSIX:
+ for (i = 0; i < enic->intr_count; i++)
+ synchronize_irq(enic->msix_entry[i].vector);
+ break;
+ default:
+ break;
+ }
+}
+
static int enic_notify_set(struct enic *enic)
{
int err;
@@ -1360,11 +1424,13 @@ static int enic_open(struct net_device *netdev)
}
for (i = 0; i < enic->rq_count; i++) {
- err = vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf);
- if (err) {
+ vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf);
+ /* Need at least one buffer on ring to get going */
+ if (vnic_rq_desc_used(&enic->rq[i]) == 0) {
printk(KERN_ERR PFX
"%s: Unable to alloc receive buffers.\n",
netdev->name);
+ err = -ENOMEM;
goto err_out_notify_unset;
}
}
@@ -1409,16 +1475,19 @@ static int enic_stop(struct net_device *netdev)
unsigned int i;
int err;
+ for (i = 0; i < enic->intr_count; i++)
+ vnic_intr_mask(&enic->intr[i]);
+
+ enic_synchronize_irqs(enic);
+
del_timer_sync(&enic->notify_timer);
spin_lock(&enic->devcmd_lock);
vnic_dev_disable(enic->vdev);
spin_unlock(&enic->devcmd_lock);
napi_disable(&enic->napi);
- netif_stop_queue(netdev);
-
- for (i = 0; i < enic->intr_count; i++)
- vnic_intr_mask(&enic->intr[i]);
+ netif_carrier_off(netdev);
+ netif_tx_disable(netdev);
for (i = 0; i < enic->wq_count; i++) {
err = vnic_wq_disable(&enic->wq[i]);
@@ -1436,11 +1505,6 @@ static int enic_stop(struct net_device *netdev)
spin_unlock(&enic->devcmd_lock);
enic_free_intr(enic);
- (void)vnic_cq_service(&enic->cq[ENIC_CQ_RQ],
- -1, enic_rq_service_drop, NULL);
- (void)vnic_cq_service(&enic->cq[ENIC_CQ_WQ],
- -1, enic_wq_service, NULL);
-
for (i = 0; i < enic->wq_count; i++)
vnic_wq_clean(&enic->wq[i], enic_free_wq_buf);
for (i = 0; i < enic->rq_count; i++)
@@ -1762,7 +1826,8 @@ int enic_dev_init(struct enic *enic)
err = enic_set_intr_mode(enic);
if (err) {
printk(KERN_ERR PFX
- "Failed to set intr mode, aborting.\n");
+ "Failed to set intr mode based on resource "
+ "counts and system capabilities, aborting.\n");
return err;
}
@@ -1986,6 +2051,9 @@ static int __devinit enic_probe(struct pci_dev *pdev,
goto err_out_dev_deinit;
}
+ enic->tx_coalesce_usecs = enic->config.intr_timer_usec;
+ enic->rx_coalesce_usecs = enic->tx_coalesce_usecs;
+
netdev->netdev_ops = &enic_netdev_ops;
netdev->watchdog_timeo = 2 * HZ;
netdev->ethtool_ops = &enic_ethtool_ops;
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index 32111144efc9..02839bf0fe8b 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -66,21 +66,21 @@ int enic_get_vnic_config(struct enic *enic)
GET_CONFIG(wq_desc_count);
GET_CONFIG(rq_desc_count);
GET_CONFIG(mtu);
- GET_CONFIG(intr_timer);
GET_CONFIG(intr_timer_type);
GET_CONFIG(intr_mode);
+ GET_CONFIG(intr_timer_usec);
c->wq_desc_count =
min_t(u32, ENIC_MAX_WQ_DESCS,
max_t(u32, ENIC_MIN_WQ_DESCS,
c->wq_desc_count));
- c->wq_desc_count &= 0xfffffff0; /* must be aligned to groups of 16 */
+ c->wq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
c->rq_desc_count =
min_t(u32, ENIC_MAX_RQ_DESCS,
max_t(u32, ENIC_MIN_RQ_DESCS,
c->rq_desc_count));
- c->rq_desc_count &= 0xfffffff0; /* must be aligned to groups of 16 */
+ c->rq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
if (c->mtu == 0)
c->mtu = 1500;
@@ -88,15 +88,17 @@ int enic_get_vnic_config(struct enic *enic)
max_t(u16, ENIC_MIN_MTU,
c->mtu));
- c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer);
+ c->intr_timer_usec = min_t(u32,
+ INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
+ c->intr_timer_usec);
printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n",
enic->mac_addr, c->wq_desc_count, c->rq_desc_count);
printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d "
- "intr timer %d\n",
+ "intr timer %d usec\n",
c->mtu, ENIC_SETTING(enic, TXCSUM),
ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO),
- ENIC_SETTING(enic, LRO), c->intr_timer);
+ ENIC_SETTING(enic, LRO), c->intr_timer_usec);
return 0;
}
@@ -303,7 +305,7 @@ void enic_init_vnic_resources(struct enic *enic)
for (i = 0; i < enic->intr_count; i++) {
vnic_intr_init(&enic->intr[i],
- enic->config.intr_timer,
+ INTR_COALESCE_USEC_TO_HW(enic->config.intr_timer_usec),
enic->config.intr_timer_type,
mask_on_assertion);
}
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c
index 29a48e8b59d3..69b9b70c7da0 100644
--- a/drivers/net/enic/vnic_dev.c
+++ b/drivers/net/enic/vnic_dev.c
@@ -36,7 +36,6 @@ struct vnic_res {
};
#define VNIC_DEV_CAP_INIT 0x0001
-#define VNIC_DEV_CAP_PERBI 0x0002
struct vnic_dev {
void *priv;
diff --git a/drivers/net/enic/vnic_enet.h b/drivers/net/enic/vnic_enet.h
index 6332ac9391b8..8eeb6758491b 100644
--- a/drivers/net/enic/vnic_enet.h
+++ b/drivers/net/enic/vnic_enet.h
@@ -20,6 +20,10 @@
#ifndef _VNIC_ENIC_H_
#define _VNIC_ENIC_H_
+/* Hardware intr coalesce timer is in units of 1.5us */
+#define INTR_COALESCE_USEC_TO_HW(usec) ((usec) * 2/3)
+#define INTR_COALESCE_HW_TO_USEC(usec) ((usec) * 3/2)
+
/* Device-specific region: enet configuration */
struct vnic_enet_config {
u32 flags;
@@ -30,6 +34,7 @@ struct vnic_enet_config {
u8 intr_timer_type;
u8 intr_mode;
char devname[16];
+ u32 intr_timer_usec;
};
#define VENETF_TSO 0x1 /* TSO enabled */
diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/enic/vnic_intr.c
index 1f8786d7195e..3934309a9498 100644
--- a/drivers/net/enic/vnic_intr.c
+++ b/drivers/net/enic/vnic_intr.c
@@ -50,12 +50,18 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
unsigned int coalescing_type, unsigned int mask_on_assertion)
{
- iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer);
+ vnic_intr_coalescing_timer_set(intr, coalescing_timer);
iowrite32(coalescing_type, &intr->ctrl->coalescing_type);
iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion);
iowrite32(0, &intr->ctrl->int_credits);
}
+void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
+ unsigned int coalescing_timer)
+{
+ iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer);
+}
+
void vnic_intr_clean(struct vnic_intr *intr)
{
iowrite32(0, &intr->ctrl->int_credits);
diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h
index 9a53604edce6..2fe6c6339e3c 100644
--- a/drivers/net/enic/vnic_intr.h
+++ b/drivers/net/enic/vnic_intr.h
@@ -61,6 +61,7 @@ static inline void vnic_intr_unmask(struct vnic_intr *intr)
static inline void vnic_intr_mask(struct vnic_intr *intr)
{
iowrite32(1, &intr->ctrl->mask);
+ (void)ioread32(&intr->ctrl->mask);
}
static inline void vnic_intr_return_credits(struct vnic_intr *intr,
@@ -101,6 +102,8 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
unsigned int index);
void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
unsigned int coalescing_type, unsigned int mask_on_assertion);
+void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
+ unsigned int coalescing_timer);
void vnic_intr_clean(struct vnic_intr *intr);
#endif /* _VNIC_INTR_H_ */
diff --git a/drivers/net/enic/vnic_nic.h b/drivers/net/enic/vnic_nic.h
index eeaf329945d8..cf80ab46d582 100644
--- a/drivers/net/enic/vnic_nic.h
+++ b/drivers/net/enic/vnic_nic.h
@@ -41,12 +41,12 @@
#define NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD 1UL
#define NIC_CFG_IG_VLAN_STRIP_EN_SHIFT 24
-#define NIC_CFG_RSS_HASH_TYPE_IPV4 (1 << 0)
-#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 (1 << 1)
-#define NIC_CFG_RSS_HASH_TYPE_IPV6 (1 << 2)
-#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6 (1 << 3)
-#define NIC_CFG_RSS_HASH_TYPE_IPV6_EX (1 << 4)
-#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX (1 << 5)
+#define NIC_CFG_RSS_HASH_TYPE_IPV4 (1 << 1)
+#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 (1 << 2)
+#define NIC_CFG_RSS_HASH_TYPE_IPV6 (1 << 3)
+#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6 (1 << 4)
+#define NIC_CFG_RSS_HASH_TYPE_IPV6_EX (1 << 5)
+#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX (1 << 6)
static inline void vnic_set_nic_cfg(u32 *nic_cfg,
u8 rss_default_cpu, u8 rss_hash_type,
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 41494f7b2ec8..39c271b6be44 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -167,7 +167,7 @@ static const struct epic_chip_info pci_id_tbl[] = {
};
-static struct pci_device_id epic_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(epic_pci_tbl) = {
{ 0x10B8, 0x0005, 0x1092, 0x0AB4, 0, 0, SMSC_83C170_0 },
{ 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170 },
{ 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID,
@@ -1390,21 +1390,20 @@ static void set_rx_mode(struct net_device *dev)
outl(0x002C, ioaddr + RxCtrl);
/* Unconditionally log net taps. */
memset(mc_filter, 0xff, sizeof(mc_filter));
- } else if ((dev->mc_count > 0) || (dev->flags & IFF_ALLMULTI)) {
+ } else if ((!netdev_mc_empty(dev)) || (dev->flags & IFF_ALLMULTI)) {
/* There is apparently a chip bug, so the multicast filter
is never enabled. */
/* Too many to filter perfectly -- accept all multicasts. */
memset(mc_filter, 0xff, sizeof(mc_filter));
outl(0x000C, ioaddr + RxCtrl);
- } else if (dev->mc_count == 0) {
+ } else if (netdev_mc_empty(dev)) {
outl(0x0004, ioaddr + RxCtrl);
return;
} else { /* Never executed, for now. */
struct dev_mc_list *mclist;
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
unsigned int bit_nr =
ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f;
mc_filter[bit_nr >> 3] |= (1 << bit_nr);
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 71bfeec33a0b..d3abeee3f110 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -1359,7 +1359,7 @@ static void eth16i_multicast(struct net_device *dev)
{
int ioaddr = dev->base_addr;
- if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
+ if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
{
outb(3, ioaddr + RECEIVE_MODE_REG);
} else {
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index bd1db92aec1b..209742304e20 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -755,7 +755,7 @@ static void ethoc_set_multicast_list(struct net_device *dev)
{
struct ethoc *priv = netdev_priv(dev);
u32 mode = ethoc_read(priv, MODER);
- struct dev_mc_list *mc = NULL;
+ struct dev_mc_list *mc;
u32 hash[2] = { 0, 0 };
/* set loopback mode if requested */
@@ -783,8 +783,8 @@ static void ethoc_set_multicast_list(struct net_device *dev)
hash[0] = 0xffffffff;
hash[1] = 0xffffffff;
} else {
- for (mc = dev->mc_list; mc; mc = mc->next) {
- u32 crc = ether_crc(mc->dmi_addrlen, mc->dmi_addr);
+ netdev_for_each_mc_addr(mc, dev) {
+ u32 crc = ether_crc(ETH_ALEN, mc->dmi_addr);
int bit = (crc >> 26) & 0x3f;
hash[bit >> 5] |= 1 << (bit & 0x1f);
}
@@ -904,7 +904,7 @@ static int ethoc_probe(struct platform_device *pdev)
}
mmio = devm_request_mem_region(&pdev->dev, res->start,
- res->end - res->start + 1, res->name);
+ resource_size(res), res->name);
if (!mmio) {
dev_err(&pdev->dev, "cannot request I/O memory space\n");
ret = -ENXIO;
@@ -917,7 +917,7 @@ static int ethoc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (res) {
mem = devm_request_mem_region(&pdev->dev, res->start,
- res->end - res->start + 1, res->name);
+ resource_size(res), res->name);
if (!mem) {
dev_err(&pdev->dev, "cannot request memory space\n");
ret = -ENXIO;
@@ -945,7 +945,7 @@ static int ethoc_probe(struct platform_device *pdev)
priv->dma_alloc = 0;
priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr,
- mmio->end - mmio->start + 1);
+ resource_size(mmio));
if (!priv->iobase) {
dev_err(&pdev->dev, "cannot remap I/O memory space\n");
ret = -ENXIO;
@@ -954,7 +954,7 @@ static int ethoc_probe(struct platform_device *pdev)
if (netdev->mem_end) {
priv->membase = devm_ioremap_nocache(&pdev->dev,
- netdev->mem_start, mem->end - mem->start + 1);
+ netdev->mem_start, resource_size(mem));
if (!priv->membase) {
dev_err(&pdev->dev, "cannot remap memory space\n");
ret = -ENXIO;
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index dd4ba01fd92d..91e59f3a9d6d 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -1169,7 +1169,7 @@ static void set_multicast_list(struct net_device *dev)
static void SetMulticastFilter(struct net_device *dev)
{
struct ewrk3_private *lp = netdev_priv(dev);
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
u_long iobase = dev->base_addr;
int i;
char *addrs, bit, byte;
@@ -1213,9 +1213,8 @@ static void SetMulticastFilter(struct net_device *dev)
}
/* Update table */
- for (i = 0; i < dev->mc_count; i++) { /* for each address in the list */
+ netdev_for_each_mc_addr(dmi, dev) {
addrs = dmi->dmi_addr;
- dmi = dmi->next;
if ((*addrs & 0x01) == 1) { /* multicast address? */
crc = ether_crc_le(ETH_ALEN, addrs);
hashcode = crc & ((1 << 9) - 1); /* hashcode is 9 LSb of CRC */
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index dac4e595589e..9d5ad08a119f 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -1786,18 +1786,16 @@ static void __set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
memset(mc_filter, 0xff, sizeof(mc_filter));
rx_mode = CR_W_PROM | CR_W_AB | CR_W_AM;
- } else if ((dev->mc_count > multicast_filter_limit) ||
+ } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
(dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
memset(mc_filter, 0xff, sizeof(mc_filter));
rx_mode = CR_W_AB | CR_W_AM;
} else {
struct dev_mc_list *mclist;
- int i;
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
unsigned int bit;
bit = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F;
mc_filter[bit >> 5] |= (1 << bit);
@@ -1941,7 +1939,7 @@ static int netdev_close(struct net_device *dev)
return 0;
}
-static struct pci_device_id fealnx_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(fealnx_pci_tbl) = {
{0x1516, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x1516, 0x0803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
{0x1516, 0x0891, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 16a1d58419d9..9f98c1c4a344 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -1128,6 +1128,26 @@ static phy_info_t phy_info_dp83848= {
},
};
+static phy_info_t phy_info_lan8700 = {
+ 0x0007C0C,
+ "LAN8700",
+ (const phy_cmd_t []) { /* config */
+ { mk_mii_read(MII_REG_CR), mii_parse_cr },
+ { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
+ { mk_mii_end, }
+ },
+ (const phy_cmd_t []) { /* startup */
+ { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
+ { mk_mii_read(MII_REG_SR), mii_parse_sr },
+ { mk_mii_end, }
+ },
+ (const phy_cmd_t []) { /* act_int */
+ { mk_mii_end, }
+ },
+ (const phy_cmd_t []) { /* shutdown */
+ { mk_mii_end, }
+ },
+};
/* ------------------------------------------------------------------------- */
static phy_info_t const * const phy_info[] = {
@@ -1137,6 +1157,7 @@ static phy_info_t const * const phy_info[] = {
&phy_info_am79c874,
&phy_info_ks8721bl,
&phy_info_dp83848,
+ &phy_info_lan8700,
NULL
};
@@ -1554,7 +1575,7 @@ static void set_multicast_list(struct net_device *dev)
{
struct fec_enet_private *fep = netdev_priv(dev);
struct dev_mc_list *dmi;
- unsigned int i, j, bit, data, crc, tmp;
+ unsigned int i, bit, data, crc, tmp;
unsigned char hash;
if (dev->flags & IFF_PROMISC) {
@@ -1583,9 +1604,7 @@ static void set_multicast_list(struct net_device *dev)
writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
- dmi = dev->mc_list;
-
- for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) {
+ netdev_for_each_mc_addr(dmi, dev) {
/* Only support group multicast for now */
if (!(dmi->dmi_addr[0] & 1))
continue;
@@ -1658,6 +1677,7 @@ static int fec_enet_init(struct net_device *dev, int index)
{
struct fec_enet_private *fep = netdev_priv(dev);
struct bufdesc *cbd_base;
+ struct bufdesc *bdp;
int i;
/* Allocate memory for buffer descriptors. */
@@ -1710,6 +1730,34 @@ static int fec_enet_init(struct net_device *dev, int index)
/* Set MII speed to 2.5 MHz */
fep->phy_speed = ((((clk_get_rate(fep->clk) / 2 + 4999999)
/ 2500000) / 2) & 0x3F) << 1;
+
+ /* Initialize the receive buffer descriptors. */
+ bdp = fep->rx_bd_base;
+ for (i = 0; i < RX_RING_SIZE; i++) {
+
+ /* Initialize the BD for every fragment in the page. */
+ bdp->cbd_sc = 0;
+ bdp++;
+ }
+
+ /* Set the last buffer to wrap */
+ bdp--;
+ bdp->cbd_sc |= BD_SC_WRAP;
+
+ /* ...and the same for transmit */
+ bdp = fep->tx_bd_base;
+ for (i = 0; i < TX_RING_SIZE; i++) {
+
+ /* Initialize the BD for every fragment in the page. */
+ bdp->cbd_sc = 0;
+ bdp->cbd_bufaddr = 0;
+ bdp++;
+ }
+
+ /* Set the last buffer to wrap */
+ bdp--;
+ bdp->cbd_sc |= BD_SC_WRAP;
+
fec_restart(dev, 0);
/* Queue up command to detect the PHY and initialize the
@@ -1730,7 +1778,6 @@ static void
fec_restart(struct net_device *dev, int duplex)
{
struct fec_enet_private *fep = netdev_priv(dev);
- struct bufdesc *bdp;
int i;
/* Whack a reset. We should wait for this. */
@@ -1768,33 +1815,6 @@ fec_restart(struct net_device *dev, int duplex)
}
}
- /* Initialize the receive buffer descriptors. */
- bdp = fep->rx_bd_base;
- for (i = 0; i < RX_RING_SIZE; i++) {
-
- /* Initialize the BD for every fragment in the page. */
- bdp->cbd_sc = BD_ENET_RX_EMPTY;
- bdp++;
- }
-
- /* Set the last buffer to wrap */
- bdp--;
- bdp->cbd_sc |= BD_SC_WRAP;
-
- /* ...and the same for transmit */
- bdp = fep->tx_bd_base;
- for (i = 0; i < TX_RING_SIZE; i++) {
-
- /* Initialize the BD for every fragment in the page. */
- bdp->cbd_sc = 0;
- bdp->cbd_bufaddr = 0;
- bdp++;
- }
-
- /* Set the last buffer to wrap */
- bdp--;
- bdp->cbd_sc |= BD_SC_WRAP;
-
/* Enable MII mode */
if (duplex) {
/* MII enable / FD enable */
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index 848e8407ea8f..0dbd7219bbde 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -575,19 +575,16 @@ static void mpc52xx_fec_set_multicast_list(struct net_device *dev)
out_be32(&fec->gaddr2, 0xffffffff);
} else {
u32 crc;
- int i;
struct dev_mc_list *dmi;
u32 gaddr1 = 0x00000000;
u32 gaddr2 = 0x00000000;
- dmi = dev->mc_list;
- for (i=0; i<dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
crc = ether_crc_le(6, dmi->dmi_addr) >> 26;
if (crc >= 32)
gaddr1 |= 1 << (crc-32);
else
gaddr2 |= 1 << crc;
- dmi = dmi->next;
}
out_be32(&fec->gaddr1, gaddr1);
out_be32(&fec->gaddr2, gaddr2);
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 3c340489804a..ca05e5662029 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -3095,7 +3095,7 @@ static void nv_set_multicast(struct net_device *dev)
} else {
pff |= NVREG_PFF_MYADDR;
- if (dev->flags & IFF_ALLMULTI || dev->mc_list) {
+ if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev)) {
u32 alwaysOff[2];
u32 alwaysOn[2];
@@ -3105,8 +3105,7 @@ static void nv_set_multicast(struct net_device *dev)
} else {
struct dev_mc_list *walk;
- walk = dev->mc_list;
- while (walk != NULL) {
+ netdev_for_each_mc_addr(walk, dev) {
u32 a, b;
a = le32_to_cpu(*(__le32 *) walk->dmi_addr);
b = le16_to_cpu(*(__le16 *) (&walk->dmi_addr[4]));
@@ -3114,7 +3113,6 @@ static void nv_set_multicast(struct net_device *dev)
alwaysOff[0] &= ~a;
alwaysOn[1] &= b;
alwaysOff[1] &= ~b;
- walk = walk->next;
}
}
addr[0] = alwaysOn[0];
@@ -6198,7 +6196,7 @@ static void nv_shutdown(struct pci_dev *pdev)
#define nv_resume NULL
#endif /* CONFIG_PM */
-static struct pci_device_id pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(pci_tbl) = {
{ /* nForce Ethernet Controller */
PCI_DEVICE(0x10DE, 0x01C3),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig
index 562ea68ed99b..fc073b5a38c7 100644
--- a/drivers/net/fs_enet/Kconfig
+++ b/drivers/net/fs_enet/Kconfig
@@ -1,9 +1,13 @@
config FS_ENET
tristate "Freescale Ethernet Driver"
- depends on CPM1 || CPM2
+ depends on CPM1 || CPM2 || PPC_MPC512x
select MII
select PHYLIB
+config FS_ENET_MPC5121_FEC
+ def_bool y if (FS_ENET && PPC_MPC512x)
+ select FS_ENET_HAS_FEC
+
config FS_ENET_HAS_SCC
bool "Chip has an SCC usable for ethernet"
depends on FS_ENET && (CPM1 || CPM2)
@@ -16,13 +20,13 @@ config FS_ENET_HAS_FCC
config FS_ENET_HAS_FEC
bool "Chip has an FEC usable for ethernet"
- depends on FS_ENET && CPM1
+ depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC)
select FS_ENET_MDIO_FEC
default y
config FS_ENET_MDIO_FEC
tristate "MDIO driver for FEC"
- depends on FS_ENET && CPM1
+ depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC)
config FS_ENET_MDIO_FCC
tristate "MDIO driver for FCC"
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index ec2f5034457f..0770e2f6da6b 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -108,9 +108,7 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
* the last indicator should be set.
*/
if ((sc & BD_ENET_RX_LAST) == 0)
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s rcv is not +last\n",
- dev->name);
+ dev_warn(fep->dev, "rcv is not +last\n");
/*
* Check for errors.
@@ -178,9 +176,8 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
received++;
netif_receive_skb(skb);
} else {
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s Memory squeeze, dropping packet.\n",
- dev->name);
+ dev_warn(fep->dev,
+ "Memory squeeze, dropping packet.\n");
fep->stats.rx_dropped++;
skbn = skb;
}
@@ -242,9 +239,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
* the last indicator should be set.
*/
if ((sc & BD_ENET_RX_LAST) == 0)
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s rcv is not +last\n",
- dev->name);
+ dev_warn(fep->dev, "rcv is not +last\n");
/*
* Check for errors.
@@ -313,9 +308,8 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
received++;
netif_rx(skb);
} else {
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s Memory squeeze, dropping packet.\n",
- dev->name);
+ dev_warn(fep->dev,
+ "Memory squeeze, dropping packet.\n");
fep->stats.rx_dropped++;
skbn = skb;
}
@@ -388,10 +382,10 @@ static void fs_enet_tx(struct net_device *dev)
} else
fep->stats.tx_packets++;
- if (sc & BD_ENET_TX_READY)
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s HEY! Enet xmit interrupt and TX_READY.\n",
- dev->name);
+ if (sc & BD_ENET_TX_READY) {
+ dev_warn(fep->dev,
+ "HEY! Enet xmit interrupt and TX_READY.\n");
+ }
/*
* Deferred means some collisions occurred during transmit,
@@ -511,9 +505,8 @@ void fs_init_bds(struct net_device *dev)
for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) {
skb = dev_alloc_skb(ENET_RX_FRSIZE);
if (skb == NULL) {
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s Memory squeeze, unable to allocate skb\n",
- dev->name);
+ dev_warn(fep->dev,
+ "Memory squeeze, unable to allocate skb\n");
break;
}
skb_align(skb, ENET_RX_ALIGN);
@@ -587,6 +580,40 @@ void fs_cleanup_bds(struct net_device *dev)
/**********************************************************************************/
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+/*
+ * MPC5121 FEC requeries 4-byte alignment for TX data buffer!
+ */
+static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
+ struct sk_buff *skb)
+{
+ struct sk_buff *new_skb;
+ struct fs_enet_private *fep = netdev_priv(dev);
+
+ /* Alloc new skb */
+ new_skb = dev_alloc_skb(skb->len + 4);
+ if (!new_skb) {
+ if (net_ratelimit()) {
+ dev_warn(fep->dev,
+ "Memory squeeze, dropping tx packet.\n");
+ }
+ return NULL;
+ }
+
+ /* Make sure new skb is properly aligned */
+ skb_align(new_skb, 4);
+
+ /* Copy data to new skb ... */
+ skb_copy_from_linear_data(skb, new_skb->data, skb->len);
+ skb_put(new_skb, skb->len);
+
+ /* ... and free an old one */
+ dev_kfree_skb_any(skb);
+
+ return new_skb;
+}
+#endif
+
static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
@@ -595,6 +622,19 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
u16 sc;
unsigned long flags;
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ if (((unsigned long)skb->data) & 0x3) {
+ skb = tx_skb_align_workaround(dev, skb);
+ if (!skb) {
+ /*
+ * We have lost packet due to memory allocation error
+ * in tx_skb_align_workaround(). Hopefully original
+ * skb is still valid, so try transmit it later.
+ */
+ return NETDEV_TX_BUSY;
+ }
+ }
+#endif
spin_lock_irqsave(&fep->tx_lock, flags);
/*
@@ -610,8 +650,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
* Ooops. All transmit buffers are full. Bail out.
* This should not happen, since the tx queue should be stopped.
*/
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s tx queue full!.\n", dev->name);
+ dev_warn(fep->dev, "tx queue full!.\n");
return NETDEV_TX_BUSY;
}
@@ -788,8 +827,7 @@ static int fs_enet_open(struct net_device *dev)
r = request_irq(fep->interrupt, fs_enet_interrupt, IRQF_SHARED,
"fs_enet-mac", dev);
if (r != 0) {
- printk(KERN_ERR DRV_MODULE_NAME
- ": %s Could not allocate FS_ENET IRQ!", dev->name);
+ dev_err(fep->dev, "Could not allocate FS_ENET IRQ!");
if (fep->fpi->use_napi)
napi_disable(&fep->napi);
return -EINVAL;
@@ -1053,7 +1091,7 @@ static int __devinit fs_enet_probe(struct of_device *ofdev,
if (ret)
goto out_free_bd;
- printk(KERN_INFO "%s: fs_enet: %pM\n", ndev->name, ndev->dev_addr);
+ pr_info("%s: fs_enet: %pM\n", ndev->name, ndev->dev_addr);
return 0;
@@ -1103,11 +1141,18 @@ static struct of_device_id fs_enet_match[] = {
},
#endif
#ifdef CONFIG_FS_ENET_HAS_FEC
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ {
+ .compatible = "fsl,mpc5121-fec",
+ .data = (void *)&fs_fec_ops,
+ },
+#else
{
.compatible = "fsl,pq1-fec-enet",
.data = (void *)&fs_fec_ops,
},
#endif
+#endif
{}
};
MODULE_DEVICE_TABLE(of, fs_enet_match);
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index ef01e09781a5..1ece4b1a689e 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -13,9 +13,56 @@
#ifdef CONFIG_CPM1
#include <asm/cpm1.h>
+#endif
+
+#if defined(CONFIG_FS_ENET_HAS_FEC)
+#include <asm/cpm.h>
+
+#if defined(CONFIG_FS_ENET_MPC5121_FEC)
+/* MPC5121 FEC has different register layout */
+struct fec {
+ u32 fec_reserved0;
+ u32 fec_ievent; /* Interrupt event reg */
+ u32 fec_imask; /* Interrupt mask reg */
+ u32 fec_reserved1;
+ u32 fec_r_des_active; /* Receive descriptor reg */
+ u32 fec_x_des_active; /* Transmit descriptor reg */
+ u32 fec_reserved2[3];
+ u32 fec_ecntrl; /* Ethernet control reg */
+ u32 fec_reserved3[6];
+ u32 fec_mii_data; /* MII manage frame reg */
+ u32 fec_mii_speed; /* MII speed control reg */
+ u32 fec_reserved4[7];
+ u32 fec_mib_ctrlstat; /* MIB control/status reg */
+ u32 fec_reserved5[7];
+ u32 fec_r_cntrl; /* Receive control reg */
+ u32 fec_reserved6[15];
+ u32 fec_x_cntrl; /* Transmit Control reg */
+ u32 fec_reserved7[7];
+ u32 fec_addr_low; /* Low 32bits MAC address */
+ u32 fec_addr_high; /* High 16bits MAC address */
+ u32 fec_opd; /* Opcode + Pause duration */
+ u32 fec_reserved8[10];
+ u32 fec_hash_table_high; /* High 32bits hash table */
+ u32 fec_hash_table_low; /* Low 32bits hash table */
+ u32 fec_grp_hash_table_high; /* High 32bits hash table */
+ u32 fec_grp_hash_table_low; /* Low 32bits hash table */
+ u32 fec_reserved9[7];
+ u32 fec_x_wmrk; /* FIFO transmit water mark */
+ u32 fec_reserved10;
+ u32 fec_r_bound; /* FIFO receive bound reg */
+ u32 fec_r_fstart; /* FIFO receive start reg */
+ u32 fec_reserved11[11];
+ u32 fec_r_des_start; /* Receive descriptor ring */
+ u32 fec_x_des_start; /* Transmit descriptor ring */
+ u32 fec_r_buff_size; /* Maximum receive buff size */
+ u32 fec_reserved12[26];
+ u32 fec_dma_control; /* DMA Endian and other ctrl */
+};
+#endif
struct fec_info {
- fec_t __iomem *fecp;
+ struct fec __iomem *fecp;
u32 mii_speed;
};
#endif
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 22e5a847a588..cf4f674f9e2e 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -218,7 +218,7 @@ static void set_multicast_finish(struct net_device *dev)
/* if all multi or too many multicasts; just enable all */
if ((dev->flags & IFF_ALLMULTI) != 0 ||
- dev->mc_count > FCC_MAX_MULTICAST_ADDRS) {
+ netdev_mc_count(dev) > FCC_MAX_MULTICAST_ADDRS) {
W32(ep, fen_gaddrh, 0xffffffff);
W32(ep, fen_gaddrl, 0xffffffff);
@@ -235,7 +235,7 @@ static void set_multicast_list(struct net_device *dev)
if ((dev->flags & IFF_PROMISC) == 0) {
set_multicast_start(dev);
- for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next)
+ netdev_for_each_mc_addr(pmc, dev)
set_multicast_one(dev, pmc->dmi_addr);
set_multicast_finish(dev);
} else
@@ -476,8 +476,9 @@ static void clear_int_events(struct net_device *dev, u32 int_events)
static void ev_error(struct net_device *dev, u32 int_events)
{
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events);
+ struct fs_enet_private *fep = netdev_priv(dev);
+
+ dev_warn(fep->dev, "FS_ENET ERROR(s) 0x%x\n", int_events);
}
static int get_regs(struct net_device *dev, void *p, int *sizep)
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index ca7bcb8ab3a1..cd2c6cca5f24 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -80,7 +80,7 @@
*/
#define FEC_RESET_DELAY 50
-static int whack_reset(fec_t __iomem *fecp)
+static int whack_reset(struct fec __iomem *fecp)
{
int i;
@@ -168,7 +168,7 @@ static void cleanup_data(struct net_device *dev)
static void set_promiscuous_mode(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FS(fecp, r_cntrl, FEC_RCNTRL_PROM);
}
@@ -216,11 +216,11 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac)
static void set_multicast_finish(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
/* if all multi or too many multicasts; just enable all */
if ((dev->flags & IFF_ALLMULTI) != 0 ||
- dev->mc_count > FEC_MAX_MULTICAST_ADDRS) {
+ netdev_mc_count(dev) > FEC_MAX_MULTICAST_ADDRS) {
fep->fec.hthi = 0xffffffffU;
fep->fec.htlo = 0xffffffffU;
}
@@ -236,7 +236,7 @@ static void set_multicast_list(struct net_device *dev)
if ((dev->flags & IFF_PROMISC) == 0) {
set_multicast_start(dev);
- for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next)
+ netdev_for_each_mc_addr(pmc, dev)
set_multicast_one(dev, pmc->dmi_addr);
set_multicast_finish(dev);
} else
@@ -246,7 +246,7 @@ static void set_multicast_list(struct net_device *dev)
static void restart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
const struct fs_platform_info *fpi = fep->fpi;
dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
int r;
@@ -257,8 +257,7 @@ static void restart(struct net_device *dev)
r = whack_reset(fep->fec.fecp);
if (r != 0)
- printk(KERN_ERR DRV_MODULE_NAME
- ": %s FEC Reset FAILED!\n", dev->name);
+ dev_err(fep->dev, "FEC Reset FAILED!\n");
/*
* Set station address.
*/
@@ -281,7 +280,11 @@ static void restart(struct net_device *dev)
* Set maximum receive buffer size.
*/
FW(fecp, r_buff_size, PKT_MAXBLR_SIZE);
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ FW(fecp, r_cntrl, PKT_MAXBUF_SIZE << 16);
+#else
FW(fecp, r_hash, PKT_MAXBUF_SIZE);
+#endif
/* get physical address */
rx_bd_base_phys = fep->ring_mem_addr;
@@ -298,7 +301,11 @@ static void restart(struct net_device *dev)
/*
* Enable big endian and don't care about SDMA FC.
*/
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ FS(fecp, dma_control, 0xC0000000);
+#else
FW(fecp, fun_code, 0x78000000);
+#endif
/*
* Set MII speed.
@@ -309,9 +316,17 @@ static void restart(struct net_device *dev)
* Clear any outstanding interrupt.
*/
FW(fecp, ievent, 0xffc0);
+#ifndef CONFIG_FS_ENET_MPC5121_FEC
FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29);
FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
+#else
+ /*
+ * Only set MII mode - do not touch maximum frame length
+ * configured before.
+ */
+ FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);
+#endif
/*
* adjust to duplex mode
*/
@@ -340,7 +355,7 @@ static void stop(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
struct fec_info* feci= fep->phydev->bus->priv;
@@ -355,9 +370,7 @@ static void stop(struct net_device *dev)
udelay(1);
if (i == FEC_RESET_DELAY)
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s FEC timeout on graceful transmit stop\n",
- dev->name);
+ dev_warn(fep->dev, "FEC timeout on graceful transmit stop\n");
/*
* Disable FEC. Let only MII interrupts.
*/
@@ -378,7 +391,7 @@ static void stop(struct net_device *dev)
static void napi_clear_rx_event(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK);
}
@@ -386,7 +399,7 @@ static void napi_clear_rx_event(struct net_device *dev)
static void napi_enable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
}
@@ -394,7 +407,7 @@ static void napi_enable_rx(struct net_device *dev)
static void napi_disable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
}
@@ -402,7 +415,7 @@ static void napi_disable_rx(struct net_device *dev)
static void rx_bd_done(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FW(fecp, r_des_active, 0x01000000);
}
@@ -410,7 +423,7 @@ static void rx_bd_done(struct net_device *dev)
static void tx_kickstart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FW(fecp, x_des_active, 0x01000000);
}
@@ -418,7 +431,7 @@ static void tx_kickstart(struct net_device *dev)
static u32 get_int_events(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
return FR(fecp, ievent) & FR(fecp, imask);
}
@@ -426,32 +439,33 @@ static u32 get_int_events(struct net_device *dev)
static void clear_int_events(struct net_device *dev, u32 int_events)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t __iomem *fecp = fep->fec.fecp;
+ struct fec __iomem *fecp = fep->fec.fecp;
FW(fecp, ievent, int_events);
}
static void ev_error(struct net_device *dev, u32 int_events)
{
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s FEC ERROR(s) 0x%x\n", dev->name, int_events);
+ struct fs_enet_private *fep = netdev_priv(dev);
+
+ dev_warn(fep->dev, "FEC ERROR(s) 0x%x\n", int_events);
}
static int get_regs(struct net_device *dev, void *p, int *sizep)
{
struct fs_enet_private *fep = netdev_priv(dev);
- if (*sizep < sizeof(fec_t))
+ if (*sizep < sizeof(struct fec))
return -EINVAL;
- memcpy_fromio(p, fep->fec.fecp, sizeof(fec_t));
+ memcpy_fromio(p, fep->fec.fecp, sizeof(struct fec));
return 0;
}
static int get_regs_len(struct net_device *dev)
{
- return sizeof(fec_t);
+ return sizeof(struct fec);
}
static void tx_restart(struct net_device *dev)
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index 008cdd9cc536..c490a466cae1 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -213,7 +213,7 @@ static void set_multicast_finish(struct net_device *dev)
/* if all multi or too many multicasts; just enable all */
if ((dev->flags & IFF_ALLMULTI) != 0 ||
- dev->mc_count > SCC_MAX_MULTICAST_ADDRS) {
+ netdev_mc_count(dev) > SCC_MAX_MULTICAST_ADDRS) {
W16(ep, sen_gaddr1, 0xffff);
W16(ep, sen_gaddr2, 0xffff);
@@ -228,7 +228,7 @@ static void set_multicast_list(struct net_device *dev)
if ((dev->flags & IFF_PROMISC) == 0) {
set_multicast_start(dev);
- for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next)
+ netdev_for_each_mc_addr(pmc, dev)
set_multicast_one(dev, pmc->dmi_addr);
set_multicast_finish(dev);
} else
@@ -367,9 +367,7 @@ static void stop(struct net_device *dev)
udelay(1);
if (i == SCC_RESET_DELAY)
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s SCC timeout on graceful transmit stop\n",
- dev->name);
+ dev_warn(fep->dev, "SCC timeout on graceful transmit stop\n");
W16(sccp, scc_sccm, 0);
C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
@@ -429,8 +427,9 @@ static void clear_int_events(struct net_device *dev, u32 int_events)
static void ev_error(struct net_device *dev, u32 int_events)
{
- printk(KERN_WARNING DRV_MODULE_NAME
- ": %s SCC ERROR(s) 0x%x\n", dev->name, int_events);
+ struct fs_enet_private *fep = netdev_priv(dev);
+
+ dev_warn(fep->dev, "SCC ERROR(s) 0x%x\n", int_events);
}
static int get_regs(struct net_device *dev, void *p, int *sizep)
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 96eba4280c5c..5944b65082cb 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -52,7 +52,7 @@
static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
{
struct fec_info* fec = bus->priv;
- fec_t __iomem *fecp = fec->fecp;
+ struct fec __iomem *fecp = fec->fecp;
int i, ret = -1;
BUG_ON((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0);
@@ -75,7 +75,7 @@ static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val)
{
struct fec_info* fec = bus->priv;
- fec_t __iomem *fecp = fec->fecp;
+ struct fec __iomem *fecp = fec->fecp;
int i;
/* this must never happen */
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 8bd3c9f17532..b6715553cf17 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -998,7 +998,7 @@ static int gfar_probe(struct of_device *ofdev,
}
/* Need to reverse the bit maps as bit_map's MSB is q0
- * but, for_each_bit parses from right to left, which
+ * but, for_each_set_bit parses from right to left, which
* basically reverses the queue numbers */
for (i = 0; i< priv->num_grps; i++) {
priv->gfargrp[i].tx_bit_map = reverse_bitmap(
@@ -1011,7 +1011,7 @@ static int gfar_probe(struct of_device *ofdev,
* also assign queues to groups */
for (grp_idx = 0; grp_idx < priv->num_grps; grp_idx++) {
priv->gfargrp[grp_idx].num_rx_queues = 0x0;
- for_each_bit(i, &priv->gfargrp[grp_idx].rx_bit_map,
+ for_each_set_bit(i, &priv->gfargrp[grp_idx].rx_bit_map,
priv->num_rx_queues) {
priv->gfargrp[grp_idx].num_rx_queues++;
priv->rx_queue[i]->grp = &priv->gfargrp[grp_idx];
@@ -1019,7 +1019,7 @@ static int gfar_probe(struct of_device *ofdev,
rqueue = rqueue | ((RQUEUE_EN0 | RQUEUE_EX0) >> i);
}
priv->gfargrp[grp_idx].num_tx_queues = 0x0;
- for_each_bit (i, &priv->gfargrp[grp_idx].tx_bit_map,
+ for_each_set_bit(i, &priv->gfargrp[grp_idx].tx_bit_map,
priv->num_tx_queues) {
priv->gfargrp[grp_idx].num_tx_queues++;
priv->tx_queue[i]->grp = &priv->gfargrp[grp_idx];
@@ -1709,7 +1709,7 @@ void gfar_configure_coalescing(struct gfar_private *priv,
if (priv->mode == MQ_MG_MODE) {
baddr = &regs->txic0;
- for_each_bit (i, &tx_mask, priv->num_tx_queues) {
+ for_each_set_bit(i, &tx_mask, priv->num_tx_queues) {
if (likely(priv->tx_queue[i]->txcoalescing)) {
gfar_write(baddr + i, 0);
gfar_write(baddr + i, priv->tx_queue[i]->txic);
@@ -1717,7 +1717,7 @@ void gfar_configure_coalescing(struct gfar_private *priv,
}
baddr = &regs->rxic0;
- for_each_bit (i, &rx_mask, priv->num_rx_queues) {
+ for_each_set_bit(i, &rx_mask, priv->num_rx_queues) {
if (likely(priv->rx_queue[i]->rxcoalescing)) {
gfar_write(baddr + i, 0);
gfar_write(baddr + i, priv->rx_queue[i]->rxic);
@@ -2021,7 +2021,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* setup the TxBD length and buffer pointer for the first BD */
- tx_queue->tx_skbuff[tx_queue->skb_curtx] = skb;
txbdp_start->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data,
skb_headlen(skb), DMA_TO_DEVICE);
@@ -2053,6 +2052,10 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
txbdp_start->lstatus = lstatus;
+ eieio(); /* force lstatus write before tx_skbuff */
+
+ tx_queue->tx_skbuff[tx_queue->skb_curtx] = skb;
+
/* Update the current skb pointer to the next entry we will use
* (wrapping if necessary) */
tx_queue->skb_curtx = (tx_queue->skb_curtx + 1) &
@@ -2607,7 +2610,7 @@ static int gfar_poll(struct napi_struct *napi, int budget)
budget_per_queue = left_over_budget/num_queues;
left_over_budget = 0;
- for_each_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) {
+ for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) {
if (test_bit(i, &serviced_queues))
continue;
rx_queue = priv->rx_queue[i];
@@ -2863,11 +2866,11 @@ static void gfar_set_multi(struct net_device *dev)
em_num = 0;
}
- if (dev->mc_count == 0)
+ if (netdev_mc_empty(dev))
return;
/* Parse the list, and set the appropriate bits */
- for(mc_ptr = dev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+ netdev_for_each_mc_addr(mc_ptr, dev) {
if (idx < em_num) {
gfar_set_mac_for_addr(dev, idx,
mc_ptr->dmi_addr);
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
new file mode 100644
index 000000000000..2b9c1cbc9ec1
--- /dev/null
+++ b/drivers/net/greth.c
@@ -0,0 +1,1634 @@
+/*
+ * Aeroflex Gaisler GRETH 10/100/1G Ethernet MAC.
+ *
+ * 2005-2009 (c) Aeroflex Gaisler AB
+ *
+ * This driver supports GRETH 10/100 and GRETH 10/100/1G Ethernet MACs
+ * available in the GRLIB VHDL IP core library.
+ *
+ * Full documentation of both cores can be found here:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ *
+ * The Gigabit version supports scatter/gather DMA, any alignment of
+ * buffers and checksum offloading.
+ *
+ * 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.
+ *
+ * Contributors: Kristoffer Glembo
+ * Daniel Hellstrom
+ * Marko Isomaki
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/io.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <asm/cacheflush.h>
+#include <asm/byteorder.h>
+
+#ifdef CONFIG_SPARC
+#include <asm/idprom.h>
+#endif
+
+#include "greth.h"
+
+#define GRETH_DEF_MSG_ENABLE \
+ (NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK | \
+ NETIF_MSG_IFDOWN | \
+ NETIF_MSG_IFUP | \
+ NETIF_MSG_RX_ERR | \
+ NETIF_MSG_TX_ERR)
+
+static int greth_debug = -1; /* -1 == use GRETH_DEF_MSG_ENABLE as value */
+module_param(greth_debug, int, 0);
+MODULE_PARM_DESC(greth_debug, "GRETH bitmapped debugging message enable value");
+
+/* Accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */
+static int macaddr[6];
+module_param_array(macaddr, int, NULL, 0);
+MODULE_PARM_DESC(macaddr, "GRETH Ethernet MAC address");
+
+static int greth_edcl = 1;
+module_param(greth_edcl, int, 0);
+MODULE_PARM_DESC(greth_edcl, "GRETH EDCL usage indicator. Set to 1 if EDCL is used.");
+
+static int greth_open(struct net_device *dev);
+static netdev_tx_t greth_start_xmit(struct sk_buff *skb,
+ struct net_device *dev);
+static netdev_tx_t greth_start_xmit_gbit(struct sk_buff *skb,
+ struct net_device *dev);
+static int greth_rx(struct net_device *dev, int limit);
+static int greth_rx_gbit(struct net_device *dev, int limit);
+static void greth_clean_tx(struct net_device *dev);
+static void greth_clean_tx_gbit(struct net_device *dev);
+static irqreturn_t greth_interrupt(int irq, void *dev_id);
+static int greth_close(struct net_device *dev);
+static int greth_set_mac_add(struct net_device *dev, void *p);
+static void greth_set_multicast_list(struct net_device *dev);
+
+#define GRETH_REGLOAD(a) (be32_to_cpu(__raw_readl(&(a))))
+#define GRETH_REGSAVE(a, v) (__raw_writel(cpu_to_be32(v), &(a)))
+#define GRETH_REGORIN(a, v) (GRETH_REGSAVE(a, (GRETH_REGLOAD(a) | (v))))
+#define GRETH_REGANDIN(a, v) (GRETH_REGSAVE(a, (GRETH_REGLOAD(a) & (v))))
+
+#define NEXT_TX(N) (((N) + 1) & GRETH_TXBD_NUM_MASK)
+#define SKIP_TX(N, C) (((N) + C) & GRETH_TXBD_NUM_MASK)
+#define NEXT_RX(N) (((N) + 1) & GRETH_RXBD_NUM_MASK)
+
+static void greth_print_rx_packet(void *addr, int len)
+{
+ print_hex_dump(KERN_DEBUG, "RX: ", DUMP_PREFIX_OFFSET, 16, 1,
+ addr, len, true);
+}
+
+static void greth_print_tx_packet(struct sk_buff *skb)
+{
+ int i;
+ int length;
+
+ if (skb_shinfo(skb)->nr_frags == 0)
+ length = skb->len;
+ else
+ length = skb_headlen(skb);
+
+ print_hex_dump(KERN_DEBUG, "TX: ", DUMP_PREFIX_OFFSET, 16, 1,
+ skb->data, length, true);
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+
+ print_hex_dump(KERN_DEBUG, "TX: ", DUMP_PREFIX_OFFSET, 16, 1,
+ phys_to_virt(page_to_phys(skb_shinfo(skb)->frags[i].page)) +
+ skb_shinfo(skb)->frags[i].page_offset,
+ length, true);
+ }
+}
+
+static inline void greth_enable_tx(struct greth_private *greth)
+{
+ wmb();
+ GRETH_REGORIN(greth->regs->control, GRETH_TXEN);
+}
+
+static inline void greth_disable_tx(struct greth_private *greth)
+{
+ GRETH_REGANDIN(greth->regs->control, ~GRETH_TXEN);
+}
+
+static inline void greth_enable_rx(struct greth_private *greth)
+{
+ wmb();
+ GRETH_REGORIN(greth->regs->control, GRETH_RXEN);
+}
+
+static inline void greth_disable_rx(struct greth_private *greth)
+{
+ GRETH_REGANDIN(greth->regs->control, ~GRETH_RXEN);
+}
+
+static inline void greth_enable_irqs(struct greth_private *greth)
+{
+ GRETH_REGORIN(greth->regs->control, GRETH_RXI | GRETH_TXI);
+}
+
+static inline void greth_disable_irqs(struct greth_private *greth)
+{
+ GRETH_REGANDIN(greth->regs->control, ~(GRETH_RXI|GRETH_TXI));
+}
+
+static inline void greth_write_bd(u32 *bd, u32 val)
+{
+ __raw_writel(cpu_to_be32(val), bd);
+}
+
+static inline u32 greth_read_bd(u32 *bd)
+{
+ return be32_to_cpu(__raw_readl(bd));
+}
+
+static void greth_clean_rings(struct greth_private *greth)
+{
+ int i;
+ struct greth_bd *rx_bdp = greth->rx_bd_base;
+ struct greth_bd *tx_bdp = greth->tx_bd_base;
+
+ if (greth->gbit_mac) {
+
+ /* Free and unmap RX buffers */
+ for (i = 0; i < GRETH_RXBD_NUM; i++, rx_bdp++) {
+ if (greth->rx_skbuff[i] != NULL) {
+ dev_kfree_skb(greth->rx_skbuff[i]);
+ dma_unmap_single(greth->dev,
+ greth_read_bd(&rx_bdp->addr),
+ MAX_FRAME_SIZE+NET_IP_ALIGN,
+ DMA_FROM_DEVICE);
+ }
+ }
+
+ /* TX buffers */
+ while (greth->tx_free < GRETH_TXBD_NUM) {
+
+ struct sk_buff *skb = greth->tx_skbuff[greth->tx_last];
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ tx_bdp = greth->tx_bd_base + greth->tx_last;
+ greth->tx_last = NEXT_TX(greth->tx_last);
+
+ dma_unmap_single(greth->dev,
+ greth_read_bd(&tx_bdp->addr),
+ skb_headlen(skb),
+ DMA_TO_DEVICE);
+
+ for (i = 0; i < nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ tx_bdp = greth->tx_bd_base + greth->tx_last;
+
+ dma_unmap_page(greth->dev,
+ greth_read_bd(&tx_bdp->addr),
+ frag->size,
+ DMA_TO_DEVICE);
+
+ greth->tx_last = NEXT_TX(greth->tx_last);
+ }
+ greth->tx_free += nr_frags+1;
+ dev_kfree_skb(skb);
+ }
+
+
+ } else { /* 10/100 Mbps MAC */
+
+ for (i = 0; i < GRETH_RXBD_NUM; i++, rx_bdp++) {
+ kfree(greth->rx_bufs[i]);
+ dma_unmap_single(greth->dev,
+ greth_read_bd(&rx_bdp->addr),
+ MAX_FRAME_SIZE,
+ DMA_FROM_DEVICE);
+ }
+ for (i = 0; i < GRETH_TXBD_NUM; i++, tx_bdp++) {
+ kfree(greth->tx_bufs[i]);
+ dma_unmap_single(greth->dev,
+ greth_read_bd(&tx_bdp->addr),
+ MAX_FRAME_SIZE,
+ DMA_TO_DEVICE);
+ }
+ }
+}
+
+static int greth_init_rings(struct greth_private *greth)
+{
+ struct sk_buff *skb;
+ struct greth_bd *rx_bd, *tx_bd;
+ u32 dma_addr;
+ int i;
+
+ rx_bd = greth->rx_bd_base;
+ tx_bd = greth->tx_bd_base;
+
+ /* Initialize descriptor rings and buffers */
+ if (greth->gbit_mac) {
+
+ for (i = 0; i < GRETH_RXBD_NUM; i++) {
+ skb = netdev_alloc_skb(greth->netdev, MAX_FRAME_SIZE+NET_IP_ALIGN);
+ if (skb == NULL) {
+ if (netif_msg_ifup(greth))
+ dev_err(greth->dev, "Error allocating DMA ring.\n");
+ goto cleanup;
+ }
+ skb_reserve(skb, NET_IP_ALIGN);
+ dma_addr = dma_map_single(greth->dev,
+ skb->data,
+ MAX_FRAME_SIZE+NET_IP_ALIGN,
+ DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(greth->dev, dma_addr)) {
+ if (netif_msg_ifup(greth))
+ dev_err(greth->dev, "Could not create initial DMA mapping\n");
+ goto cleanup;
+ }
+ greth->rx_skbuff[i] = skb;
+ greth_write_bd(&rx_bd[i].addr, dma_addr);
+ greth_write_bd(&rx_bd[i].stat, GRETH_BD_EN | GRETH_BD_IE);
+ }
+
+ } else {
+
+ /* 10/100 MAC uses a fixed set of buffers and copy to/from SKBs */
+ for (i = 0; i < GRETH_RXBD_NUM; i++) {
+
+ greth->rx_bufs[i] = kmalloc(MAX_FRAME_SIZE, GFP_KERNEL);
+
+ if (greth->rx_bufs[i] == NULL) {
+ if (netif_msg_ifup(greth))
+ dev_err(greth->dev, "Error allocating DMA ring.\n");
+ goto cleanup;
+ }
+
+ dma_addr = dma_map_single(greth->dev,
+ greth->rx_bufs[i],
+ MAX_FRAME_SIZE,
+ DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(greth->dev, dma_addr)) {
+ if (netif_msg_ifup(greth))
+ dev_err(greth->dev, "Could not create initial DMA mapping\n");
+ goto cleanup;
+ }
+ greth_write_bd(&rx_bd[i].addr, dma_addr);
+ greth_write_bd(&rx_bd[i].stat, GRETH_BD_EN | GRETH_BD_IE);
+ }
+ for (i = 0; i < GRETH_TXBD_NUM; i++) {
+
+ greth->tx_bufs[i] = kmalloc(MAX_FRAME_SIZE, GFP_KERNEL);
+
+ if (greth->tx_bufs[i] == NULL) {
+ if (netif_msg_ifup(greth))
+ dev_err(greth->dev, "Error allocating DMA ring.\n");
+ goto cleanup;
+ }
+
+ dma_addr = dma_map_single(greth->dev,
+ greth->tx_bufs[i],
+ MAX_FRAME_SIZE,
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(greth->dev, dma_addr)) {
+ if (netif_msg_ifup(greth))
+ dev_err(greth->dev, "Could not create initial DMA mapping\n");
+ goto cleanup;
+ }
+ greth_write_bd(&tx_bd[i].addr, dma_addr);
+ greth_write_bd(&tx_bd[i].stat, 0);
+ }
+ }
+ greth_write_bd(&rx_bd[GRETH_RXBD_NUM - 1].stat,
+ greth_read_bd(&rx_bd[GRETH_RXBD_NUM - 1].stat) | GRETH_BD_WR);
+
+ /* Initialize pointers. */
+ greth->rx_cur = 0;
+ greth->tx_next = 0;
+ greth->tx_last = 0;
+ greth->tx_free = GRETH_TXBD_NUM;
+
+ /* Initialize descriptor base address */
+ GRETH_REGSAVE(greth->regs->tx_desc_p, greth->tx_bd_base_phys);
+ GRETH_REGSAVE(greth->regs->rx_desc_p, greth->rx_bd_base_phys);
+
+ return 0;
+
+cleanup:
+ greth_clean_rings(greth);
+ return -ENOMEM;
+}
+
+static int greth_open(struct net_device *dev)
+{
+ struct greth_private *greth = netdev_priv(dev);
+ int err;
+
+ err = greth_init_rings(greth);
+ if (err) {
+ if (netif_msg_ifup(greth))
+ dev_err(&dev->dev, "Could not allocate memory for DMA rings\n");
+ return err;
+ }
+
+ err = request_irq(greth->irq, greth_interrupt, 0, "eth", (void *) dev);
+ if (err) {
+ if (netif_msg_ifup(greth))
+ dev_err(&dev->dev, "Could not allocate interrupt %d\n", dev->irq);
+ greth_clean_rings(greth);
+ return err;
+ }
+
+ if (netif_msg_ifup(greth))
+ dev_dbg(&dev->dev, " starting queue\n");
+ netif_start_queue(dev);
+
+ napi_enable(&greth->napi);
+
+ greth_enable_irqs(greth);
+ greth_enable_tx(greth);
+ greth_enable_rx(greth);
+ return 0;
+
+}
+
+static int greth_close(struct net_device *dev)
+{
+ struct greth_private *greth = netdev_priv(dev);
+
+ napi_disable(&greth->napi);
+
+ greth_disable_tx(greth);
+
+ netif_stop_queue(dev);
+
+ free_irq(greth->irq, (void *) dev);
+
+ greth_clean_rings(greth);
+
+ return 0;
+}
+
+static netdev_tx_t
+greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct greth_private *greth = netdev_priv(dev);
+ struct greth_bd *bdp;
+ int err = NETDEV_TX_OK;
+ u32 status, dma_addr;
+
+ bdp = greth->tx_bd_base + greth->tx_next;
+
+ if (unlikely(greth->tx_free <= 0)) {
+ netif_stop_queue(dev);
+ return NETDEV_TX_BUSY;
+ }
+
+ if (netif_msg_pktdata(greth))
+ greth_print_tx_packet(skb);
+
+
+ if (unlikely(skb->len > MAX_FRAME_SIZE)) {
+ dev->stats.tx_errors++;
+ goto out;
+ }
+
+ dma_addr = greth_read_bd(&bdp->addr);
+
+ memcpy((unsigned char *) phys_to_virt(dma_addr), skb->data, skb->len);
+
+ dma_sync_single_for_device(greth->dev, dma_addr, skb->len, DMA_TO_DEVICE);
+
+ status = GRETH_BD_EN | (skb->len & GRETH_BD_LEN);
+
+ /* Wrap around descriptor ring */
+ if (greth->tx_next == GRETH_TXBD_NUM_MASK) {
+ status |= GRETH_BD_WR;
+ }
+
+ greth->tx_next = NEXT_TX(greth->tx_next);
+ greth->tx_free--;
+
+ /* No more descriptors */
+ if (unlikely(greth->tx_free == 0)) {
+
+ /* Free transmitted descriptors */
+ greth_clean_tx(dev);
+
+ /* If nothing was cleaned, stop queue & wait for irq */
+ if (unlikely(greth->tx_free == 0)) {
+ status |= GRETH_BD_IE;
+ netif_stop_queue(dev);
+ }
+ }
+
+ /* Write descriptor control word and enable transmission */
+ greth_write_bd(&bdp->stat, status);
+ greth_enable_tx(greth);
+
+out:
+ dev_kfree_skb(skb);
+ return err;
+}
+
+
+static netdev_tx_t
+greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct greth_private *greth = netdev_priv(dev);
+ struct greth_bd *bdp;
+ u32 status = 0, dma_addr;
+ int curr_tx, nr_frags, i, err = NETDEV_TX_OK;
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+
+ if (greth->tx_free < nr_frags + 1) {
+ netif_stop_queue(dev);
+ err = NETDEV_TX_BUSY;
+ goto out;
+ }
+
+ if (netif_msg_pktdata(greth))
+ greth_print_tx_packet(skb);
+
+ if (unlikely(skb->len > MAX_FRAME_SIZE)) {
+ dev->stats.tx_errors++;
+ goto out;
+ }
+
+ /* Save skb pointer. */
+ greth->tx_skbuff[greth->tx_next] = skb;
+
+ /* Linear buf */
+ if (nr_frags != 0)
+ status = GRETH_TXBD_MORE;
+
+ status |= GRETH_TXBD_CSALL;
+ status |= skb_headlen(skb) & GRETH_BD_LEN;
+ if (greth->tx_next == GRETH_TXBD_NUM_MASK)
+ status |= GRETH_BD_WR;
+
+
+ bdp = greth->tx_bd_base + greth->tx_next;
+ greth_write_bd(&bdp->stat, status);
+ dma_addr = dma_map_single(greth->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
+
+ if (unlikely(dma_mapping_error(greth->dev, dma_addr)))
+ goto map_error;
+
+ greth_write_bd(&bdp->addr, dma_addr);
+
+ curr_tx = NEXT_TX(greth->tx_next);
+
+ /* Frags */
+ for (i = 0; i < nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ greth->tx_skbuff[curr_tx] = NULL;
+ bdp = greth->tx_bd_base + curr_tx;
+
+ status = GRETH_TXBD_CSALL;
+ status |= frag->size & GRETH_BD_LEN;
+
+ /* Wrap around descriptor ring */
+ if (curr_tx == GRETH_TXBD_NUM_MASK)
+ status |= GRETH_BD_WR;
+
+ /* More fragments left */
+ if (i < nr_frags - 1)
+ status |= GRETH_TXBD_MORE;
+
+ /* ... last fragment, check if out of descriptors */
+ else if (greth->tx_free - nr_frags - 1 < (MAX_SKB_FRAGS + 1)) {
+
+ /* Enable interrupts and stop queue */
+ status |= GRETH_BD_IE;
+ netif_stop_queue(dev);
+ }
+
+ greth_write_bd(&bdp->stat, status);
+
+ dma_addr = dma_map_page(greth->dev,
+ frag->page,
+ frag->page_offset,
+ frag->size,
+ DMA_TO_DEVICE);
+
+ if (unlikely(dma_mapping_error(greth->dev, dma_addr)))
+ goto frag_map_error;
+
+ greth_write_bd(&bdp->addr, dma_addr);
+
+ curr_tx = NEXT_TX(curr_tx);
+ }
+
+ wmb();
+
+ /* Enable the descriptors that we configured ... */
+ for (i = 0; i < nr_frags + 1; i++) {
+ bdp = greth->tx_bd_base + greth->tx_next;
+ greth_write_bd(&bdp->stat, greth_read_bd(&bdp->stat) | GRETH_BD_EN);
+ greth->tx_next = NEXT_TX(greth->tx_next);
+ greth->tx_free--;
+ }
+
+ greth_enable_tx(greth);
+
+ return NETDEV_TX_OK;
+
+frag_map_error:
+ /* Unmap SKB mappings that succeeded */
+ for (i = 0; greth->tx_next + i != curr_tx; i++) {
+ bdp = greth->tx_bd_base + greth->tx_next + i;
+ dma_unmap_single(greth->dev,
+ greth_read_bd(&bdp->addr),
+ greth_read_bd(&bdp->stat) & GRETH_BD_LEN,
+ DMA_TO_DEVICE);
+ }
+map_error:
+ if (net_ratelimit())
+ dev_warn(greth->dev, "Could not create TX DMA mapping\n");
+ dev_kfree_skb(skb);
+out:
+ return err;
+}
+
+
+static irqreturn_t greth_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct greth_private *greth;
+ u32 status;
+ irqreturn_t retval = IRQ_NONE;
+
+ greth = netdev_priv(dev);
+
+ spin_lock(&greth->devlock);
+
+ /* Get the interrupt events that caused us to be here. */
+ status = GRETH_REGLOAD(greth->regs->status);
+
+ /* Handle rx and tx interrupts through poll */
+ if (status & (GRETH_INT_RX | GRETH_INT_TX)) {
+
+ /* Clear interrupt status */
+ GRETH_REGORIN(greth->regs->status,
+ status & (GRETH_INT_RX | GRETH_INT_TX));
+
+ retval = IRQ_HANDLED;
+
+ /* Disable interrupts and schedule poll() */
+ greth_disable_irqs(greth);
+ napi_schedule(&greth->napi);
+ }
+
+ mmiowb();
+ spin_unlock(&greth->devlock);
+
+ return retval;
+}
+
+static void greth_clean_tx(struct net_device *dev)
+{
+ struct greth_private *greth;
+ struct greth_bd *bdp;
+ u32 stat;
+
+ greth = netdev_priv(dev);
+
+ while (1) {
+ bdp = greth->tx_bd_base + greth->tx_last;
+ stat = greth_read_bd(&bdp->stat);
+
+ if (unlikely(stat & GRETH_BD_EN))
+ break;
+
+ if (greth->tx_free == GRETH_TXBD_NUM)
+ break;
+
+ /* Check status for errors */
+ if (unlikely(stat & GRETH_TXBD_STATUS)) {
+ dev->stats.tx_errors++;
+ if (stat & GRETH_TXBD_ERR_AL)
+ dev->stats.tx_aborted_errors++;
+ if (stat & GRETH_TXBD_ERR_UE)
+ dev->stats.tx_fifo_errors++;
+ }
+ dev->stats.tx_packets++;
+ greth->tx_last = NEXT_TX(greth->tx_last);
+ greth->tx_free++;
+ }
+
+ if (greth->tx_free > 0) {
+ netif_wake_queue(dev);
+ }
+
+}
+
+static inline void greth_update_tx_stats(struct net_device *dev, u32 stat)
+{
+ /* Check status for errors */
+ if (unlikely(stat & GRETH_TXBD_STATUS)) {
+ dev->stats.tx_errors++;
+ if (stat & GRETH_TXBD_ERR_AL)
+ dev->stats.tx_aborted_errors++;
+ if (stat & GRETH_TXBD_ERR_UE)
+ dev->stats.tx_fifo_errors++;
+ if (stat & GRETH_TXBD_ERR_LC)
+ dev->stats.tx_aborted_errors++;
+ }
+ dev->stats.tx_packets++;
+}
+
+static void greth_clean_tx_gbit(struct net_device *dev)
+{
+ struct greth_private *greth;
+ struct greth_bd *bdp, *bdp_last_frag;
+ struct sk_buff *skb;
+ u32 stat;
+ int nr_frags, i;
+
+ greth = netdev_priv(dev);
+
+ while (greth->tx_free < GRETH_TXBD_NUM) {
+
+ skb = greth->tx_skbuff[greth->tx_last];
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+
+ /* We only clean fully completed SKBs */
+ bdp_last_frag = greth->tx_bd_base + SKIP_TX(greth->tx_last, nr_frags);
+ stat = bdp_last_frag->stat;
+
+ if (stat & GRETH_BD_EN)
+ break;
+
+ greth->tx_skbuff[greth->tx_last] = NULL;
+
+ greth_update_tx_stats(dev, stat);
+
+ bdp = greth->tx_bd_base + greth->tx_last;
+
+ greth->tx_last = NEXT_TX(greth->tx_last);
+
+ dma_unmap_single(greth->dev,
+ greth_read_bd(&bdp->addr),
+ skb_headlen(skb),
+ DMA_TO_DEVICE);
+
+ for (i = 0; i < nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ bdp = greth->tx_bd_base + greth->tx_last;
+
+ dma_unmap_page(greth->dev,
+ greth_read_bd(&bdp->addr),
+ frag->size,
+ DMA_TO_DEVICE);
+
+ greth->tx_last = NEXT_TX(greth->tx_last);
+ }
+ greth->tx_free += nr_frags+1;
+ dev_kfree_skb(skb);
+ }
+ if (greth->tx_free > (MAX_SKB_FRAGS + 1)) {
+ netif_wake_queue(dev);
+ }
+}
+
+static int greth_pending_packets(struct greth_private *greth)
+{
+ struct greth_bd *bdp;
+ u32 status;
+ bdp = greth->rx_bd_base + greth->rx_cur;
+ status = greth_read_bd(&bdp->stat);
+ if (status & GRETH_BD_EN)
+ return 0;
+ else
+ return 1;
+}
+
+static int greth_rx(struct net_device *dev, int limit)
+{
+ struct greth_private *greth;
+ struct greth_bd *bdp;
+ struct sk_buff *skb;
+ int pkt_len;
+ int bad, count;
+ u32 status, dma_addr;
+
+ greth = netdev_priv(dev);
+
+ for (count = 0; count < limit; ++count) {
+
+ bdp = greth->rx_bd_base + greth->rx_cur;
+ status = greth_read_bd(&bdp->stat);
+ dma_addr = greth_read_bd(&bdp->addr);
+ bad = 0;
+
+ if (unlikely(status & GRETH_BD_EN)) {
+ break;
+ }
+
+ /* Check status for errors. */
+ if (unlikely(status & GRETH_RXBD_STATUS)) {
+ if (status & GRETH_RXBD_ERR_FT) {
+ dev->stats.rx_length_errors++;
+ bad = 1;
+ }
+ if (status & (GRETH_RXBD_ERR_AE | GRETH_RXBD_ERR_OE)) {
+ dev->stats.rx_frame_errors++;
+ bad = 1;
+ }
+ if (status & GRETH_RXBD_ERR_CRC) {
+ dev->stats.rx_crc_errors++;
+ bad = 1;
+ }
+ }
+ if (unlikely(bad)) {
+ dev->stats.rx_errors++;
+
+ } else {
+
+ pkt_len = status & GRETH_BD_LEN;
+
+ skb = netdev_alloc_skb(dev, pkt_len + NET_IP_ALIGN);
+
+ if (unlikely(skb == NULL)) {
+
+ if (net_ratelimit())
+ dev_warn(&dev->dev, "low on memory - " "packet dropped\n");
+
+ dev->stats.rx_dropped++;
+
+ } else {
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb->dev = dev;
+
+ dma_sync_single_for_cpu(greth->dev,
+ dma_addr,
+ pkt_len,
+ DMA_FROM_DEVICE);
+
+ if (netif_msg_pktdata(greth))
+ greth_print_rx_packet(phys_to_virt(dma_addr), pkt_len);
+
+ memcpy(skb_put(skb, pkt_len), phys_to_virt(dma_addr), pkt_len);
+
+ skb->protocol = eth_type_trans(skb, dev);
+ dev->stats.rx_packets++;
+ netif_receive_skb(skb);
+ }
+ }
+
+ status = GRETH_BD_EN | GRETH_BD_IE;
+ if (greth->rx_cur == GRETH_RXBD_NUM_MASK) {
+ status |= GRETH_BD_WR;
+ }
+
+ wmb();
+ greth_write_bd(&bdp->stat, status);
+
+ dma_sync_single_for_device(greth->dev, dma_addr, MAX_FRAME_SIZE, DMA_FROM_DEVICE);
+
+ greth_enable_rx(greth);
+
+ greth->rx_cur = NEXT_RX(greth->rx_cur);
+ }
+
+ return count;
+}
+
+static inline int hw_checksummed(u32 status)
+{
+
+ if (status & GRETH_RXBD_IP_FRAG)
+ return 0;
+
+ if (status & GRETH_RXBD_IP && status & GRETH_RXBD_IP_CSERR)
+ return 0;
+
+ if (status & GRETH_RXBD_UDP && status & GRETH_RXBD_UDP_CSERR)
+ return 0;
+
+ if (status & GRETH_RXBD_TCP && status & GRETH_RXBD_TCP_CSERR)
+ return 0;
+
+ return 1;
+}
+
+static int greth_rx_gbit(struct net_device *dev, int limit)
+{
+ struct greth_private *greth;
+ struct greth_bd *bdp;
+ struct sk_buff *skb, *newskb;
+ int pkt_len;
+ int bad, count = 0;
+ u32 status, dma_addr;
+
+ greth = netdev_priv(dev);
+
+ for (count = 0; count < limit; ++count) {
+
+ bdp = greth->rx_bd_base + greth->rx_cur;
+ skb = greth->rx_skbuff[greth->rx_cur];
+ status = greth_read_bd(&bdp->stat);
+ bad = 0;
+
+ if (status & GRETH_BD_EN)
+ break;
+
+ /* Check status for errors. */
+ if (unlikely(status & GRETH_RXBD_STATUS)) {
+
+ if (status & GRETH_RXBD_ERR_FT) {
+ dev->stats.rx_length_errors++;
+ bad = 1;
+ } else if (status &
+ (GRETH_RXBD_ERR_AE | GRETH_RXBD_ERR_OE | GRETH_RXBD_ERR_LE)) {
+ dev->stats.rx_frame_errors++;
+ bad = 1;
+ } else if (status & GRETH_RXBD_ERR_CRC) {
+ dev->stats.rx_crc_errors++;
+ bad = 1;
+ }
+ }
+
+ /* Allocate new skb to replace current */
+ newskb = netdev_alloc_skb(dev, MAX_FRAME_SIZE + NET_IP_ALIGN);
+
+ if (!bad && newskb) {
+ skb_reserve(newskb, NET_IP_ALIGN);
+
+ dma_addr = dma_map_single(greth->dev,
+ newskb->data,
+ MAX_FRAME_SIZE + NET_IP_ALIGN,
+ DMA_FROM_DEVICE);
+
+ if (!dma_mapping_error(greth->dev, dma_addr)) {
+ /* Process the incoming frame. */
+ pkt_len = status & GRETH_BD_LEN;
+
+ dma_unmap_single(greth->dev,
+ greth_read_bd(&bdp->addr),
+ MAX_FRAME_SIZE + NET_IP_ALIGN,
+ DMA_FROM_DEVICE);
+
+ if (netif_msg_pktdata(greth))
+ greth_print_rx_packet(phys_to_virt(greth_read_bd(&bdp->addr)), pkt_len);
+
+ skb_put(skb, pkt_len);
+
+ if (greth->flags & GRETH_FLAG_RX_CSUM && hw_checksummed(status))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ dev->stats.rx_packets++;
+ netif_receive_skb(skb);
+
+ greth->rx_skbuff[greth->rx_cur] = newskb;
+ greth_write_bd(&bdp->addr, dma_addr);
+ } else {
+ if (net_ratelimit())
+ dev_warn(greth->dev, "Could not create DMA mapping, dropping packet\n");
+ dev_kfree_skb(newskb);
+ dev->stats.rx_dropped++;
+ }
+ } else {
+ if (net_ratelimit())
+ dev_warn(greth->dev, "Could not allocate SKB, dropping packet\n");
+ dev->stats.rx_dropped++;
+ }
+
+ status = GRETH_BD_EN | GRETH_BD_IE;
+ if (greth->rx_cur == GRETH_RXBD_NUM_MASK) {
+ status |= GRETH_BD_WR;
+ }
+
+ wmb();
+ greth_write_bd(&bdp->stat, status);
+ greth_enable_rx(greth);
+ greth->rx_cur = NEXT_RX(greth->rx_cur);
+ }
+
+ return count;
+
+}
+
+static int greth_poll(struct napi_struct *napi, int budget)
+{
+ struct greth_private *greth;
+ int work_done = 0;
+ greth = container_of(napi, struct greth_private, napi);
+
+ if (greth->gbit_mac) {
+ greth_clean_tx_gbit(greth->netdev);
+ } else {
+ greth_clean_tx(greth->netdev);
+ }
+
+restart_poll:
+ if (greth->gbit_mac) {
+ work_done += greth_rx_gbit(greth->netdev, budget - work_done);
+ } else {
+ work_done += greth_rx(greth->netdev, budget - work_done);
+ }
+
+ if (work_done < budget) {
+
+ napi_complete(napi);
+
+ if (greth_pending_packets(greth)) {
+ napi_reschedule(napi);
+ goto restart_poll;
+ }
+ }
+
+ greth_enable_irqs(greth);
+ return work_done;
+}
+
+static int greth_set_mac_add(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+ struct greth_private *greth;
+ struct greth_regs *regs;
+
+ greth = netdev_priv(dev);
+ regs = (struct greth_regs *) greth->regs;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ GRETH_REGSAVE(regs->esa_msb, addr->sa_data[0] << 8 | addr->sa_data[1]);
+ GRETH_REGSAVE(regs->esa_lsb,
+ addr->sa_data[2] << 24 | addr->
+ sa_data[3] << 16 | addr->sa_data[4] << 8 | addr->sa_data[5]);
+ return 0;
+}
+
+static u32 greth_hash_get_index(__u8 *addr)
+{
+ return (ether_crc(6, addr)) & 0x3F;
+}
+
+static void greth_set_hash_filter(struct net_device *dev)
+{
+ struct dev_mc_list *curr;
+ struct greth_private *greth = netdev_priv(dev);
+ struct greth_regs *regs = (struct greth_regs *) greth->regs;
+ u32 mc_filter[2];
+ unsigned int bitnr;
+
+ mc_filter[0] = mc_filter[1] = 0;
+
+ netdev_for_each_mc_addr(curr, dev) {
+ bitnr = greth_hash_get_index(curr->dmi_addr);
+ mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
+ }
+
+ GRETH_REGSAVE(regs->hash_msb, mc_filter[1]);
+ GRETH_REGSAVE(regs->hash_lsb, mc_filter[0]);
+}
+
+static void greth_set_multicast_list(struct net_device *dev)
+{
+ int cfg;
+ struct greth_private *greth = netdev_priv(dev);
+ struct greth_regs *regs = (struct greth_regs *) greth->regs;
+
+ cfg = GRETH_REGLOAD(regs->control);
+ if (dev->flags & IFF_PROMISC)
+ cfg |= GRETH_CTRL_PR;
+ else
+ cfg &= ~GRETH_CTRL_PR;
+
+ if (greth->multicast) {
+ if (dev->flags & IFF_ALLMULTI) {
+ GRETH_REGSAVE(regs->hash_msb, -1);
+ GRETH_REGSAVE(regs->hash_lsb, -1);
+ cfg |= GRETH_CTRL_MCEN;
+ GRETH_REGSAVE(regs->control, cfg);
+ return;
+ }
+
+ if (netdev_mc_empty(dev)) {
+ cfg &= ~GRETH_CTRL_MCEN;
+ GRETH_REGSAVE(regs->control, cfg);
+ return;
+ }
+
+ /* Setup multicast filter */
+ greth_set_hash_filter(dev);
+ cfg |= GRETH_CTRL_MCEN;
+ }
+ GRETH_REGSAVE(regs->control, cfg);
+}
+
+static u32 greth_get_msglevel(struct net_device *dev)
+{
+ struct greth_private *greth = netdev_priv(dev);
+ return greth->msg_enable;
+}
+
+static void greth_set_msglevel(struct net_device *dev, u32 value)
+{
+ struct greth_private *greth = netdev_priv(dev);
+ greth->msg_enable = value;
+}
+static int greth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct greth_private *greth = netdev_priv(dev);
+ struct phy_device *phy = greth->phy;
+
+ if (!phy)
+ return -ENODEV;
+
+ return phy_ethtool_gset(phy, cmd);
+}
+
+static int greth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct greth_private *greth = netdev_priv(dev);
+ struct phy_device *phy = greth->phy;
+
+ if (!phy)
+ return -ENODEV;
+
+ return phy_ethtool_sset(phy, cmd);
+}
+
+static int greth_get_regs_len(struct net_device *dev)
+{
+ return sizeof(struct greth_regs);
+}
+
+static void greth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ struct greth_private *greth = netdev_priv(dev);
+
+ strncpy(info->driver, dev_driver_string(greth->dev), 32);
+ strncpy(info->version, "revision: 1.0", 32);
+ strncpy(info->bus_info, greth->dev->bus->name, 32);
+ strncpy(info->fw_version, "N/A", 32);
+ info->eedump_len = 0;
+ info->regdump_len = sizeof(struct greth_regs);
+}
+
+static void greth_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
+{
+ int i;
+ struct greth_private *greth = netdev_priv(dev);
+ u32 __iomem *greth_regs = (u32 __iomem *) greth->regs;
+ u32 *buff = p;
+
+ for (i = 0; i < sizeof(struct greth_regs) / sizeof(u32); i++)
+ buff[i] = greth_read_bd(&greth_regs[i]);
+}
+
+static u32 greth_get_rx_csum(struct net_device *dev)
+{
+ struct greth_private *greth = netdev_priv(dev);
+ return (greth->flags & GRETH_FLAG_RX_CSUM) != 0;
+}
+
+static int greth_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct greth_private *greth = netdev_priv(dev);
+
+ spin_lock_bh(&greth->devlock);
+
+ if (data)
+ greth->flags |= GRETH_FLAG_RX_CSUM;
+ else
+ greth->flags &= ~GRETH_FLAG_RX_CSUM;
+
+ spin_unlock_bh(&greth->devlock);
+
+ return 0;
+}
+
+static u32 greth_get_tx_csum(struct net_device *dev)
+{
+ return (dev->features & NETIF_F_IP_CSUM) != 0;
+}
+
+static int greth_set_tx_csum(struct net_device *dev, u32 data)
+{
+ netif_tx_lock_bh(dev);
+ ethtool_op_set_tx_csum(dev, data);
+ netif_tx_unlock_bh(dev);
+ return 0;
+}
+
+static const struct ethtool_ops greth_ethtool_ops = {
+ .get_msglevel = greth_get_msglevel,
+ .set_msglevel = greth_set_msglevel,
+ .get_settings = greth_get_settings,
+ .set_settings = greth_set_settings,
+ .get_drvinfo = greth_get_drvinfo,
+ .get_regs_len = greth_get_regs_len,
+ .get_regs = greth_get_regs,
+ .get_rx_csum = greth_get_rx_csum,
+ .set_rx_csum = greth_set_rx_csum,
+ .get_tx_csum = greth_get_tx_csum,
+ .set_tx_csum = greth_set_tx_csum,
+ .get_link = ethtool_op_get_link,
+};
+
+static struct net_device_ops greth_netdev_ops = {
+ .ndo_open = greth_open,
+ .ndo_stop = greth_close,
+ .ndo_start_xmit = greth_start_xmit,
+ .ndo_set_mac_address = greth_set_mac_add,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+static inline int wait_for_mdio(struct greth_private *greth)
+{
+ unsigned long timeout = jiffies + 4*HZ/100;
+ while (GRETH_REGLOAD(greth->regs->mdio) & GRETH_MII_BUSY) {
+ if (time_after(jiffies, timeout))
+ return 0;
+ }
+ return 1;
+}
+
+static int greth_mdio_read(struct mii_bus *bus, int phy, int reg)
+{
+ struct greth_private *greth = bus->priv;
+ int data;
+
+ if (!wait_for_mdio(greth))
+ return -EBUSY;
+
+ GRETH_REGSAVE(greth->regs->mdio, ((phy & 0x1F) << 11) | ((reg & 0x1F) << 6) | 2);
+
+ if (!wait_for_mdio(greth))
+ return -EBUSY;
+
+ if (!(GRETH_REGLOAD(greth->regs->mdio) & GRETH_MII_NVALID)) {
+ data = (GRETH_REGLOAD(greth->regs->mdio) >> 16) & 0xFFFF;
+ return data;
+
+ } else {
+ return -1;
+ }
+}
+
+static int greth_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
+{
+ struct greth_private *greth = bus->priv;
+
+ if (!wait_for_mdio(greth))
+ return -EBUSY;
+
+ GRETH_REGSAVE(greth->regs->mdio,
+ ((val & 0xFFFF) << 16) | ((phy & 0x1F) << 11) | ((reg & 0x1F) << 6) | 1);
+
+ if (!wait_for_mdio(greth))
+ return -EBUSY;
+
+ return 0;
+}
+
+static int greth_mdio_reset(struct mii_bus *bus)
+{
+ return 0;
+}
+
+static void greth_link_change(struct net_device *dev)
+{
+ struct greth_private *greth = netdev_priv(dev);
+ struct phy_device *phydev = greth->phy;
+ unsigned long flags;
+
+ int status_change = 0;
+
+ spin_lock_irqsave(&greth->devlock, flags);
+
+ if (phydev->link) {
+
+ if ((greth->speed != phydev->speed) || (greth->duplex != phydev->duplex)) {
+
+ GRETH_REGANDIN(greth->regs->control,
+ ~(GRETH_CTRL_FD | GRETH_CTRL_SP | GRETH_CTRL_GB));
+
+ if (phydev->duplex)
+ GRETH_REGORIN(greth->regs->control, GRETH_CTRL_FD);
+
+ if (phydev->speed == SPEED_100) {
+
+ GRETH_REGORIN(greth->regs->control, GRETH_CTRL_SP);
+ }
+
+ else if (phydev->speed == SPEED_1000)
+ GRETH_REGORIN(greth->regs->control, GRETH_CTRL_GB);
+
+ greth->speed = phydev->speed;
+ greth->duplex = phydev->duplex;
+ status_change = 1;
+ }
+ }
+
+ if (phydev->link != greth->link) {
+ if (!phydev->link) {
+ greth->speed = 0;
+ greth->duplex = -1;
+ }
+ greth->link = phydev->link;
+
+ status_change = 1;
+ }
+
+ spin_unlock_irqrestore(&greth->devlock, flags);
+
+ if (status_change) {
+ if (phydev->link)
+ pr_debug("%s: link up (%d/%s)\n",
+ dev->name, phydev->speed,
+ DUPLEX_FULL == phydev->duplex ? "Full" : "Half");
+ else
+ pr_debug("%s: link down\n", dev->name);
+ }
+}
+
+static int greth_mdio_probe(struct net_device *dev)
+{
+ struct greth_private *greth = netdev_priv(dev);
+ struct phy_device *phy = NULL;
+ int ret;
+
+ /* Find the first PHY */
+ phy = phy_find_first(greth->mdio);
+
+ if (!phy) {
+ if (netif_msg_probe(greth))
+ dev_err(&dev->dev, "no PHY found\n");
+ return -ENXIO;
+ }
+
+ ret = phy_connect_direct(dev, phy, &greth_link_change,
+ 0, greth->gbit_mac ?
+ PHY_INTERFACE_MODE_GMII :
+ PHY_INTERFACE_MODE_MII);
+ if (ret) {
+ if (netif_msg_ifup(greth))
+ dev_err(&dev->dev, "could not attach to PHY\n");
+ return ret;
+ }
+
+ if (greth->gbit_mac)
+ phy->supported &= PHY_GBIT_FEATURES;
+ else
+ phy->supported &= PHY_BASIC_FEATURES;
+
+ phy->advertising = phy->supported;
+
+ greth->link = 0;
+ greth->speed = 0;
+ greth->duplex = -1;
+ greth->phy = phy;
+
+ return 0;
+}
+
+static inline int phy_aneg_done(struct phy_device *phydev)
+{
+ int retval;
+
+ retval = phy_read(phydev, MII_BMSR);
+
+ return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE);
+}
+
+static int greth_mdio_init(struct greth_private *greth)
+{
+ int ret, phy;
+ unsigned long timeout;
+
+ greth->mdio = mdiobus_alloc();
+ if (!greth->mdio) {
+ return -ENOMEM;
+ }
+
+ greth->mdio->name = "greth-mdio";
+ snprintf(greth->mdio->id, MII_BUS_ID_SIZE, "%s-%d", greth->mdio->name, greth->irq);
+ greth->mdio->read = greth_mdio_read;
+ greth->mdio->write = greth_mdio_write;
+ greth->mdio->reset = greth_mdio_reset;
+ greth->mdio->priv = greth;
+
+ greth->mdio->irq = greth->mdio_irqs;
+
+ for (phy = 0; phy < PHY_MAX_ADDR; phy++)
+ greth->mdio->irq[phy] = PHY_POLL;
+
+ ret = mdiobus_register(greth->mdio);
+ if (ret) {
+ goto error;
+ }
+
+ ret = greth_mdio_probe(greth->netdev);
+ if (ret) {
+ if (netif_msg_probe(greth))
+ dev_err(&greth->netdev->dev, "failed to probe MDIO bus\n");
+ goto unreg_mdio;
+ }
+
+ phy_start(greth->phy);
+
+ /* If Ethernet debug link is used make autoneg happen right away */
+ if (greth->edcl && greth_edcl == 1) {
+ phy_start_aneg(greth->phy);
+ timeout = jiffies + 6*HZ;
+ while (!phy_aneg_done(greth->phy) && time_before(jiffies, timeout)) {
+ }
+ genphy_read_status(greth->phy);
+ greth_link_change(greth->netdev);
+ }
+
+ return 0;
+
+unreg_mdio:
+ mdiobus_unregister(greth->mdio);
+error:
+ mdiobus_free(greth->mdio);
+ return ret;
+}
+
+/* Initialize the GRETH MAC */
+static int __devinit greth_of_probe(struct of_device *ofdev, const struct of_device_id *match)
+{
+ struct net_device *dev;
+ struct greth_private *greth;
+ struct greth_regs *regs;
+
+ int i;
+ int err;
+ int tmp;
+ unsigned long timeout;
+
+ dev = alloc_etherdev(sizeof(struct greth_private));
+
+ if (dev == NULL)
+ return -ENOMEM;
+
+ greth = netdev_priv(dev);
+ greth->netdev = dev;
+ greth->dev = &ofdev->dev;
+
+ if (greth_debug > 0)
+ greth->msg_enable = greth_debug;
+ else
+ greth->msg_enable = GRETH_DEF_MSG_ENABLE;
+
+ spin_lock_init(&greth->devlock);
+
+ greth->regs = of_ioremap(&ofdev->resource[0], 0,
+ resource_size(&ofdev->resource[0]),
+ "grlib-greth regs");
+
+ if (greth->regs == NULL) {
+ if (netif_msg_probe(greth))
+ dev_err(greth->dev, "ioremap failure.\n");
+ err = -EIO;
+ goto error1;
+ }
+
+ regs = (struct greth_regs *) greth->regs;
+ greth->irq = ofdev->irqs[0];
+
+ dev_set_drvdata(greth->dev, dev);
+ SET_NETDEV_DEV(dev, greth->dev);
+
+ if (netif_msg_probe(greth))
+ dev_dbg(greth->dev, "reseting controller.\n");
+
+ /* Reset the controller. */
+ GRETH_REGSAVE(regs->control, GRETH_RESET);
+
+ /* Wait for MAC to reset itself */
+ timeout = jiffies + HZ/100;
+ while (GRETH_REGLOAD(regs->control) & GRETH_RESET) {
+ if (time_after(jiffies, timeout)) {
+ err = -EIO;
+ if (netif_msg_probe(greth))
+ dev_err(greth->dev, "timeout when waiting for reset.\n");
+ goto error2;
+ }
+ }
+
+ /* Get default PHY address */
+ greth->phyaddr = (GRETH_REGLOAD(regs->mdio) >> 11) & 0x1F;
+
+ /* Check if we have GBIT capable MAC */
+ tmp = GRETH_REGLOAD(regs->control);
+ greth->gbit_mac = (tmp >> 27) & 1;
+
+ /* Check for multicast capability */
+ greth->multicast = (tmp >> 25) & 1;
+
+ greth->edcl = (tmp >> 31) & 1;
+
+ /* If we have EDCL we disable the EDCL speed-duplex FSM so
+ * it doesn't interfere with the software */
+ if (greth->edcl != 0)
+ GRETH_REGORIN(regs->control, GRETH_CTRL_DISDUPLEX);
+
+ /* Check if MAC can handle MDIO interrupts */
+ greth->mdio_int_en = (tmp >> 26) & 1;
+
+ err = greth_mdio_init(greth);
+ if (err) {
+ if (netif_msg_probe(greth))
+ dev_err(greth->dev, "failed to register MDIO bus\n");
+ goto error2;
+ }
+
+ /* Allocate TX descriptor ring in coherent memory */
+ greth->tx_bd_base = (struct greth_bd *) dma_alloc_coherent(greth->dev,
+ 1024,
+ &greth->tx_bd_base_phys,
+ GFP_KERNEL);
+
+ if (!greth->tx_bd_base) {
+ if (netif_msg_probe(greth))
+ dev_err(&dev->dev, "could not allocate descriptor memory.\n");
+ err = -ENOMEM;
+ goto error3;
+ }
+
+ memset(greth->tx_bd_base, 0, 1024);
+
+ /* Allocate RX descriptor ring in coherent memory */
+ greth->rx_bd_base = (struct greth_bd *) dma_alloc_coherent(greth->dev,
+ 1024,
+ &greth->rx_bd_base_phys,
+ GFP_KERNEL);
+
+ if (!greth->rx_bd_base) {
+ if (netif_msg_probe(greth))
+ dev_err(greth->dev, "could not allocate descriptor memory.\n");
+ err = -ENOMEM;
+ goto error4;
+ }
+
+ memset(greth->rx_bd_base, 0, 1024);
+
+ /* Get MAC address from: module param, OF property or ID prom */
+ for (i = 0; i < 6; i++) {
+ if (macaddr[i] != 0)
+ break;
+ }
+ if (i == 6) {
+ const unsigned char *addr;
+ int len;
+ addr = of_get_property(ofdev->node, "local-mac-address", &len);
+ if (addr != NULL && len == 6) {
+ for (i = 0; i < 6; i++)
+ macaddr[i] = (unsigned int) addr[i];
+ } else {
+#ifdef CONFIG_SPARC
+ for (i = 0; i < 6; i++)
+ macaddr[i] = (unsigned int) idprom->id_ethaddr[i];
+#endif
+ }
+ }
+
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = macaddr[i];
+
+ macaddr[5]++;
+
+ if (!is_valid_ether_addr(&dev->dev_addr[0])) {
+ if (netif_msg_probe(greth))
+ dev_err(greth->dev, "no valid ethernet address, aborting.\n");
+ err = -EINVAL;
+ goto error5;
+ }
+
+ GRETH_REGSAVE(regs->esa_msb, dev->dev_addr[0] << 8 | dev->dev_addr[1]);
+ GRETH_REGSAVE(regs->esa_lsb, dev->dev_addr[2] << 24 | dev->dev_addr[3] << 16 |
+ dev->dev_addr[4] << 8 | dev->dev_addr[5]);
+
+ /* Clear all pending interrupts except PHY irq */
+ GRETH_REGSAVE(regs->status, 0xFF);
+
+ if (greth->gbit_mac) {
+ dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA;
+ greth_netdev_ops.ndo_start_xmit = greth_start_xmit_gbit;
+ greth->flags = GRETH_FLAG_RX_CSUM;
+ }
+
+ if (greth->multicast) {
+ greth_netdev_ops.ndo_set_multicast_list = greth_set_multicast_list;
+ dev->flags |= IFF_MULTICAST;
+ } else {
+ dev->flags &= ~IFF_MULTICAST;
+ }
+
+ dev->netdev_ops = &greth_netdev_ops;
+ dev->ethtool_ops = &greth_ethtool_ops;
+
+ if (register_netdev(dev)) {
+ if (netif_msg_probe(greth))
+ dev_err(greth->dev, "netdevice registration failed.\n");
+ err = -ENOMEM;
+ goto error5;
+ }
+
+ /* setup NAPI */
+ memset(&greth->napi, 0, sizeof(greth->napi));
+ netif_napi_add(dev, &greth->napi, greth_poll, 64);
+
+ return 0;
+
+error5:
+ dma_free_coherent(greth->dev, 1024, greth->rx_bd_base, greth->rx_bd_base_phys);
+error4:
+ dma_free_coherent(greth->dev, 1024, greth->tx_bd_base, greth->tx_bd_base_phys);
+error3:
+ mdiobus_unregister(greth->mdio);
+error2:
+ of_iounmap(&ofdev->resource[0], greth->regs, resource_size(&ofdev->resource[0]));
+error1:
+ free_netdev(dev);
+ return err;
+}
+
+static int __devexit greth_of_remove(struct of_device *of_dev)
+{
+ struct net_device *ndev = dev_get_drvdata(&of_dev->dev);
+ struct greth_private *greth = netdev_priv(ndev);
+
+ /* Free descriptor areas */
+ dma_free_coherent(&of_dev->dev, 1024, greth->rx_bd_base, greth->rx_bd_base_phys);
+
+ dma_free_coherent(&of_dev->dev, 1024, greth->tx_bd_base, greth->tx_bd_base_phys);
+
+ dev_set_drvdata(&of_dev->dev, NULL);
+
+ if (greth->phy)
+ phy_stop(greth->phy);
+ mdiobus_unregister(greth->mdio);
+
+ unregister_netdev(ndev);
+ free_netdev(ndev);
+
+ of_iounmap(&of_dev->resource[0], greth->regs, resource_size(&of_dev->resource[0]));
+
+ return 0;
+}
+
+static struct of_device_id greth_of_match[] = {
+ {
+ .name = "GAISLER_ETHMAC",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, greth_of_match);
+
+static struct of_platform_driver greth_of_driver = {
+ .name = "grlib-greth",
+ .match_table = greth_of_match,
+ .probe = greth_of_probe,
+ .remove = __devexit_p(greth_of_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "grlib-greth",
+ },
+};
+
+static int __init greth_init(void)
+{
+ return of_register_platform_driver(&greth_of_driver);
+}
+
+static void __exit greth_cleanup(void)
+{
+ of_unregister_platform_driver(&greth_of_driver);
+}
+
+module_init(greth_init);
+module_exit(greth_cleanup);
+
+MODULE_AUTHOR("Aeroflex Gaisler AB.");
+MODULE_DESCRIPTION("Aeroflex Gaisler Ethernet MAC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/greth.h b/drivers/net/greth.h
new file mode 100644
index 000000000000..973388d6abca
--- /dev/null
+++ b/drivers/net/greth.h
@@ -0,0 +1,143 @@
+#ifndef GRETH_H
+#define GRETH_H
+
+#include <linux/phy.h>
+
+/* Register bits and masks */
+#define GRETH_RESET 0x40
+#define GRETH_MII_BUSY 0x8
+#define GRETH_MII_NVALID 0x10
+
+#define GRETH_CTRL_FD 0x10
+#define GRETH_CTRL_PR 0x20
+#define GRETH_CTRL_SP 0x80
+#define GRETH_CTRL_GB 0x100
+#define GRETH_CTRL_PSTATIEN 0x400
+#define GRETH_CTRL_MCEN 0x800
+#define GRETH_CTRL_DISDUPLEX 0x1000
+#define GRETH_STATUS_PHYSTAT 0x100
+
+#define GRETH_BD_EN 0x800
+#define GRETH_BD_WR 0x1000
+#define GRETH_BD_IE 0x2000
+#define GRETH_BD_LEN 0x7FF
+
+#define GRETH_TXEN 0x1
+#define GRETH_INT_TX 0x8
+#define GRETH_TXI 0x4
+#define GRETH_TXBD_STATUS 0x0001C000
+#define GRETH_TXBD_MORE 0x20000
+#define GRETH_TXBD_IPCS 0x40000
+#define GRETH_TXBD_TCPCS 0x80000
+#define GRETH_TXBD_UDPCS 0x100000
+#define GRETH_TXBD_CSALL (GRETH_TXBD_IPCS | GRETH_TXBD_TCPCS | GRETH_TXBD_UDPCS)
+#define GRETH_TXBD_ERR_LC 0x10000
+#define GRETH_TXBD_ERR_UE 0x4000
+#define GRETH_TXBD_ERR_AL 0x8000
+
+#define GRETH_INT_RX 0x4
+#define GRETH_RXEN 0x2
+#define GRETH_RXI 0x8
+#define GRETH_RXBD_STATUS 0xFFFFC000
+#define GRETH_RXBD_ERR_AE 0x4000
+#define GRETH_RXBD_ERR_FT 0x8000
+#define GRETH_RXBD_ERR_CRC 0x10000
+#define GRETH_RXBD_ERR_OE 0x20000
+#define GRETH_RXBD_ERR_LE 0x40000
+#define GRETH_RXBD_IP 0x80000
+#define GRETH_RXBD_IP_CSERR 0x100000
+#define GRETH_RXBD_UDP 0x200000
+#define GRETH_RXBD_UDP_CSERR 0x400000
+#define GRETH_RXBD_TCP 0x800000
+#define GRETH_RXBD_TCP_CSERR 0x1000000
+#define GRETH_RXBD_IP_FRAG 0x2000000
+#define GRETH_RXBD_MCAST 0x4000000
+
+/* Descriptor parameters */
+#define GRETH_TXBD_NUM 128
+#define GRETH_TXBD_NUM_MASK (GRETH_TXBD_NUM-1)
+#define GRETH_TX_BUF_SIZE 2048
+#define GRETH_RXBD_NUM 128
+#define GRETH_RXBD_NUM_MASK (GRETH_RXBD_NUM-1)
+#define GRETH_RX_BUF_SIZE 2048
+
+/* Buffers per page */
+#define GRETH_RX_BUF_PPGAE (PAGE_SIZE/GRETH_RX_BUF_SIZE)
+#define GRETH_TX_BUF_PPGAE (PAGE_SIZE/GRETH_TX_BUF_SIZE)
+
+/* How many pages are needed for buffers */
+#define GRETH_RX_BUF_PAGE_NUM (GRETH_RXBD_NUM/GRETH_RX_BUF_PPGAE)
+#define GRETH_TX_BUF_PAGE_NUM (GRETH_TXBD_NUM/GRETH_TX_BUF_PPGAE)
+
+/* Buffer size.
+ * Gbit MAC uses tagged maximum frame size which is 1518 excluding CRC.
+ * Set to 1520 to make all buffers word aligned for non-gbit MAC.
+ */
+#define MAX_FRAME_SIZE 1520
+
+/* Flags */
+#define GRETH_FLAG_RX_CSUM 0x1
+
+/* GRETH APB registers */
+struct greth_regs {
+ u32 control;
+ u32 status;
+ u32 esa_msb;
+ u32 esa_lsb;
+ u32 mdio;
+ u32 tx_desc_p;
+ u32 rx_desc_p;
+ u32 edclip;
+ u32 hash_msb;
+ u32 hash_lsb;
+};
+
+/* GRETH buffer descriptor */
+struct greth_bd {
+ u32 stat;
+ u32 addr;
+};
+
+struct greth_private {
+ struct sk_buff *rx_skbuff[GRETH_RXBD_NUM];
+ struct sk_buff *tx_skbuff[GRETH_TXBD_NUM];
+
+ unsigned char *tx_bufs[GRETH_TXBD_NUM];
+ unsigned char *rx_bufs[GRETH_RXBD_NUM];
+
+ u16 tx_next;
+ u16 tx_last;
+ u16 tx_free;
+ u16 rx_cur;
+
+ struct greth_regs *regs; /* Address of controller registers. */
+ struct greth_bd *rx_bd_base; /* Address of Rx BDs. */
+ struct greth_bd *tx_bd_base; /* Address of Tx BDs. */
+ dma_addr_t rx_bd_base_phys;
+ dma_addr_t tx_bd_base_phys;
+
+ int irq;
+
+ struct device *dev; /* Pointer to of_device->dev */
+ struct net_device *netdev;
+ struct napi_struct napi;
+ spinlock_t devlock;
+
+ struct phy_device *phy;
+ struct mii_bus *mdio;
+ int mdio_irqs[PHY_MAX_ADDR];
+ unsigned int link;
+ unsigned int speed;
+ unsigned int duplex;
+
+ u32 msg_enable;
+ u32 flags;
+
+ u8 phyaddr;
+ u8 multicast;
+ u8 gbit_mac;
+ u8 mdio_int_en;
+ u8 edcl;
+};
+
+#endif
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index ea85075a89a2..373546dd0831 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -1854,17 +1854,18 @@ static void set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
writew(0x000F, ioaddr + AddrMode);
- } else if ((dev->mc_count > 63) || (dev->flags & IFF_ALLMULTI)) {
+ } else if ((netdev_mc_count(dev) > 63) || (dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
writew(0x000B, ioaddr + AddrMode);
- } else if (dev->mc_count > 0) { /* Must use the CAM filter. */
+ } else if (!netdev_mc_empty(dev)) { /* Must use the CAM filter. */
struct dev_mc_list *mclist;
- int i;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ int i = 0;
+
+ netdev_for_each_mc_addr(mclist, dev) {
writel(*(u32*)(mclist->dmi_addr), ioaddr + 0x100 + i*8);
writel(0x20000 | (*(u16*)&mclist->dmi_addr[4]),
ioaddr + 0x104 + i*8);
+ i++;
}
/* Clear remaining entries. */
for (; i < 64; i++)
@@ -1990,7 +1991,7 @@ static void __devexit hamachi_remove_one (struct pci_dev *pdev)
}
}
-static struct pci_device_id hamachi_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(hamachi_pci_tbl) = {
{ 0x1318, 0x0911, PCI_ANY_ID, PCI_ANY_ID, },
{ 0, }
};
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 90f890e7c5e1..b766a69bf0ca 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -210,7 +210,7 @@ MODULE_DEVICE_TABLE(eisa, hp100_eisa_tbl);
#endif
#ifdef CONFIG_PCI
-static struct pci_device_id hp100_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(hp100_pci_tbl) = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID,},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID,},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2970A, PCI_ANY_ID, PCI_ANY_ID,},
@@ -2090,7 +2090,7 @@ static void hp100_set_multicast_list(struct net_device *dev)
lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */
lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */
memset(&lp->hash_bytes, 0xff, 8);
- } else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) {
+ } else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) {
lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */
lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */
#ifdef HP100_MULTICAST_FILTER /* doesn't work!!! */
@@ -2098,22 +2098,23 @@ static void hp100_set_multicast_list(struct net_device *dev)
/* set hash filter to receive all multicast packets */
memset(&lp->hash_bytes, 0xff, 8);
} else {
- int i, j, idx;
+ int i, idx;
u_char *addrs;
struct dev_mc_list *dmi;
memset(&lp->hash_bytes, 0x00, 8);
#ifdef HP100_DEBUG
- printk("hp100: %s: computing hash filter - mc_count = %i\n", dev->name, dev->mc_count);
+ printk("hp100: %s: computing hash filter - mc_count = %i\n",
+ dev->name, netdev_mc_count(dev));
#endif
- for (i = 0, dmi = dev->mc_list; i < dev->mc_count; i++, dmi = dmi->next) {
+ netdev_for_each_mc_addr(dmi, dev) {
addrs = dmi->dmi_addr;
if ((*addrs & 0x01) == 0x01) { /* multicast address? */
#ifdef HP100_DEBUG
printk("hp100: %s: multicast = %pM, ",
dev->name, addrs);
#endif
- for (j = idx = 0; j < 6; j++) {
+ for (i = idx = 0; i < 6; i++) {
idx ^= *addrs++ & 0x3f;
printk(":%02x:", idx);
}
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index fb5e019169ee..fb0ac6d7c040 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -391,11 +391,11 @@ static void emac_hash_mc(struct emac_instance *dev)
struct dev_mc_list *dmi;
int i;
- DBG(dev, "hash_mc %d" NL, dev->ndev->mc_count);
+ DBG(dev, "hash_mc %d" NL, netdev_mc_count(dev->ndev));
memset(gaht_temp, 0, sizeof (gaht_temp));
- for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) {
+ netdev_for_each_mc_addr(dmi, dev->ndev) {
int slot, reg, mask;
DBG2(dev, "mc %pM" NL, dmi->dmi_addr);
@@ -425,9 +425,9 @@ static inline u32 emac_iff2rmr(struct net_device *ndev)
if (ndev->flags & IFF_PROMISC)
r |= EMAC_RMR_PME;
else if (ndev->flags & IFF_ALLMULTI ||
- (ndev->mc_count > EMAC_XAHT_SLOTS(dev)))
+ (netdev_mc_count(ndev) > EMAC_XAHT_SLOTS(dev)))
r |= EMAC_RMR_PMME;
- else if (ndev->mc_count > 0)
+ else if (!netdev_mc_empty(ndev))
r |= EMAC_RMR_MAE;
return r;
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 052c74091d91..b5d0f4e973f7 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -420,7 +420,7 @@ static void InitBoard(struct net_device *dev)
/* start putting the multicast addresses into the CAM list. Stop if
it is full. */
- for (mcptr = dev->mc_list; mcptr != NULL; mcptr = mcptr->next) {
+ netdev_for_each_mc_addr(mcptr, dev) {
putcam(cams, &camcnt, mcptr->dmi_addr);
if (camcnt == 16)
break;
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index a86693906ac8..0bc777bac9b4 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -1062,7 +1062,8 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
struct ibmveth_adapter *adapter = netdev_priv(netdev);
unsigned long lpar_rc;
- if((netdev->flags & IFF_PROMISC) || (netdev->mc_count > adapter->mcastFilterSize)) {
+ if ((netdev->flags & IFF_PROMISC) ||
+ (netdev_mc_count(netdev) > adapter->mcastFilterSize)) {
lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
IbmVethMcastEnableRecv |
IbmVethMcastDisableFiltering,
@@ -1071,8 +1072,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
ibmveth_error_printk("h_multicast_ctrl rc=%ld when entering promisc mode\n", lpar_rc);
}
} else {
- struct dev_mc_list *mclist = netdev->mc_list;
- int i;
+ struct dev_mc_list *mclist;
/* clear the filter table & disable filtering */
lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
IbmVethMcastEnableRecv |
@@ -1083,7 +1083,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
ibmveth_error_printk("h_multicast_ctrl rc=%ld when attempting to clear filter table\n", lpar_rc);
}
/* add the addresses to the filter table */
- for(i = 0; i < netdev->mc_count; ++i, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, netdev) {
// add the multicast address to the filter table
unsigned long mcast_addr = 0;
memcpy(((char *)&mcast_addr)+2, mclist->dmi_addr, 6);
@@ -1577,7 +1577,7 @@ static struct attribute * veth_pool_attrs[] = {
NULL,
};
-static struct sysfs_ops veth_pool_ops = {
+static const struct sysfs_ops veth_pool_ops = {
.show = veth_pool_show,
.store = veth_pool_store,
};
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index c505b50d1fa3..9d7fa2fb85ea 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -727,6 +727,34 @@ static s32 igb_check_for_link_82575(struct e1000_hw *hw)
}
/**
+ * igb_power_up_serdes_link_82575 - Power up the serdes link after shutdown
+ * @hw: pointer to the HW structure
+ **/
+void igb_power_up_serdes_link_82575(struct e1000_hw *hw)
+{
+ u32 reg;
+
+
+ if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
+ !igb_sgmii_active_82575(hw))
+ return;
+
+ /* Enable PCS to turn on link */
+ reg = rd32(E1000_PCS_CFG0);
+ reg |= E1000_PCS_CFG_PCS_EN;
+ wr32(E1000_PCS_CFG0, reg);
+
+ /* Power up the laser */
+ reg = rd32(E1000_CTRL_EXT);
+ reg &= ~E1000_CTRL_EXT_SDP3_DATA;
+ wr32(E1000_CTRL_EXT, reg);
+
+ /* flush the write to verify completion */
+ wrfl();
+ msleep(1);
+}
+
+/**
* igb_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex
* @hw: pointer to the HW structure
* @speed: stores the current speed
@@ -791,27 +819,12 @@ static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed,
void igb_shutdown_serdes_link_82575(struct e1000_hw *hw)
{
u32 reg;
- u16 eeprom_data = 0;
- if (hw->phy.media_type != e1000_media_type_internal_serdes ||
+ if (hw->phy.media_type != e1000_media_type_internal_serdes &&
igb_sgmii_active_82575(hw))
return;
- if (hw->bus.func == E1000_FUNC_0)
- hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
- else if (hw->mac.type == e1000_82580)
- hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A +
- NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1,
- &eeprom_data);
- else if (hw->bus.func == E1000_FUNC_1)
- hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
-
- /*
- * If APM is not enabled in the EEPROM and management interface is
- * not enabled, then power down.
- */
- if (!(eeprom_data & E1000_NVM_APME_82575) &&
- !igb_enable_mng_pass_thru(hw)) {
+ if (!igb_enable_mng_pass_thru(hw)) {
/* Disable PCS to turn off link */
reg = rd32(E1000_PCS_CFG0);
reg &= ~E1000_PCS_CFG_PCS_EN;
@@ -826,8 +839,6 @@ void igb_shutdown_serdes_link_82575(struct e1000_hw *hw)
wrfl();
msleep(1);
}
-
- return;
}
/**
@@ -1183,6 +1194,22 @@ out:
}
/**
+ * igb_power_down_phy_copper_82575 - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+void igb_power_down_phy_copper_82575(struct e1000_hw *hw)
+{
+ /* If the management interface is not enabled, then power down */
+ if (!(igb_enable_mng_pass_thru(hw) || igb_check_reset_block(hw)))
+ igb_power_down_phy_copper(hw);
+
+ return;
+}
+
+/**
* igb_clear_hw_cntrs_82575 - Clear device specific hardware counters
* @hw: pointer to the HW structure
*
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h
index d51c9927c819..fbe1c99c193c 100644
--- a/drivers/net/igb/e1000_82575.h
+++ b/drivers/net/igb/e1000_82575.h
@@ -29,6 +29,8 @@
#define _E1000_82575_H_
extern void igb_shutdown_serdes_link_82575(struct e1000_hw *hw);
+extern void igb_power_up_serdes_link_82575(struct e1000_hw *hw);
+extern void igb_power_down_phy_copper_82575(struct e1000_hw *hw);
extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
@@ -219,6 +221,9 @@ struct e1000_adv_tx_context_desc {
#define E1000_VLVF_LVLAN 0x00100000
#define E1000_VLVF_VLANID_ENABLE 0x80000000
+#define E1000_VMVIR_VLANA_DEFAULT 0x40000000 /* Always use default VLAN */
+#define E1000_VMVIR_VLANA_NEVER 0x80000000 /* Never insert VLAN tag */
+
#define E1000_IOVCTL 0x05BBC
#define E1000_IOVCTL_REUSE_VFQ 0x00000001
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
index 6e036ae3138f..fe6cf1b696c7 100644
--- a/drivers/net/igb/e1000_defines.h
+++ b/drivers/net/igb/e1000_defines.h
@@ -313,12 +313,6 @@
#define E1000_PBA_34K 0x0022
#define E1000_PBA_64K 0x0040 /* 64KB */
-#define IFS_MAX 80
-#define IFS_MIN 40
-#define IFS_RATIO 4
-#define IFS_STEP 10
-#define MIN_NUM_XMITS 1000
-
/* SW Semaphore Register */
#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
@@ -481,6 +475,7 @@
/* PHY Control Register */
#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h
index dbaeb5f5e0c7..448005276b26 100644
--- a/drivers/net/igb/e1000_hw.h
+++ b/drivers/net/igb/e1000_hw.h
@@ -339,19 +339,12 @@ struct e1000_mac_info {
enum e1000_mac_type type;
- u32 collision_delta;
u32 ledctl_default;
u32 ledctl_mode1;
u32 ledctl_mode2;
u32 mc_filter_type;
- u32 tx_packet_delta;
u32 txcw;
- u16 current_ifs_val;
- u16 ifs_max_val;
- u16 ifs_min_val;
- u16 ifs_ratio;
- u16 ifs_step_size;
u16 mta_reg_count;
u16 uta_reg_count;
diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c
index 2ad358a240bf..2a8a886b37eb 100644
--- a/drivers/net/igb/e1000_mac.c
+++ b/drivers/net/igb/e1000_mac.c
@@ -1304,76 +1304,6 @@ out:
}
/**
- * igb_reset_adaptive - Reset Adaptive Interframe Spacing
- * @hw: pointer to the HW structure
- *
- * Reset the Adaptive Interframe Spacing throttle to default values.
- **/
-void igb_reset_adaptive(struct e1000_hw *hw)
-{
- struct e1000_mac_info *mac = &hw->mac;
-
- if (!mac->adaptive_ifs) {
- hw_dbg("Not in Adaptive IFS mode!\n");
- goto out;
- }
-
- if (!mac->ifs_params_forced) {
- mac->current_ifs_val = 0;
- mac->ifs_min_val = IFS_MIN;
- mac->ifs_max_val = IFS_MAX;
- mac->ifs_step_size = IFS_STEP;
- mac->ifs_ratio = IFS_RATIO;
- }
-
- mac->in_ifs_mode = false;
- wr32(E1000_AIT, 0);
-out:
- return;
-}
-
-/**
- * igb_update_adaptive - Update Adaptive Interframe Spacing
- * @hw: pointer to the HW structure
- *
- * Update the Adaptive Interframe Spacing Throttle value based on the
- * time between transmitted packets and time between collisions.
- **/
-void igb_update_adaptive(struct e1000_hw *hw)
-{
- struct e1000_mac_info *mac = &hw->mac;
-
- if (!mac->adaptive_ifs) {
- hw_dbg("Not in Adaptive IFS mode!\n");
- goto out;
- }
-
- if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
- if (mac->tx_packet_delta > MIN_NUM_XMITS) {
- mac->in_ifs_mode = true;
- if (mac->current_ifs_val < mac->ifs_max_val) {
- if (!mac->current_ifs_val)
- mac->current_ifs_val = mac->ifs_min_val;
- else
- mac->current_ifs_val +=
- mac->ifs_step_size;
- wr32(E1000_AIT,
- mac->current_ifs_val);
- }
- }
- } else {
- if (mac->in_ifs_mode &&
- (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
- mac->current_ifs_val = 0;
- mac->in_ifs_mode = false;
- wr32(E1000_AIT, 0);
- }
- }
-out:
- return;
-}
-
-/**
* igb_validate_mdi_setting - Verify MDI/MDIx settings
* @hw: pointer to the HW structure
*
diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/igb/e1000_mac.h
index bca17d882417..601be99711c2 100644
--- a/drivers/net/igb/e1000_mac.h
+++ b/drivers/net/igb/e1000_mac.h
@@ -67,8 +67,6 @@ void igb_mta_set(struct e1000_hw *hw, u32 hash_value);
void igb_put_hw_semaphore(struct e1000_hw *hw);
void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
s32 igb_check_alt_mac_addr(struct e1000_hw *hw);
-void igb_reset_adaptive(struct e1000_hw *hw);
-void igb_update_adaptive(struct e1000_hw *hw);
bool igb_enable_mng_pass_thru(struct e1000_hw *hw);
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c
index 3670a66401b8..cf1f32300923 100644
--- a/drivers/net/igb/e1000_phy.c
+++ b/drivers/net/igb/e1000_phy.c
@@ -1931,6 +1931,41 @@ s32 igb_phy_init_script_igp3(struct e1000_hw *hw)
}
/**
+ * igb_power_up_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, restore the link to previous settings.
+ **/
+void igb_power_up_phy_copper(struct e1000_hw *hw)
+{
+ u16 mii_reg = 0;
+
+ /* The PHY will retain its settings across a power down/up cycle */
+ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+ mii_reg &= ~MII_CR_POWER_DOWN;
+ hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+}
+
+/**
+ * igb_power_down_phy_copper - Power down copper PHY
+ * @hw: pointer to the HW structure
+ *
+ * Power down PHY to save power when interface is down and wake on lan
+ * is not enabled.
+ **/
+void igb_power_down_phy_copper(struct e1000_hw *hw)
+{
+ u16 mii_reg = 0;
+
+ /* The PHY will retain its settings across a power down/up cycle */
+ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+ mii_reg |= MII_CR_POWER_DOWN;
+ hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+ msleep(1);
+}
+
+/**
* igb_check_polarity_82580 - Checks the polarity.
* @hw: pointer to the HW structure
*
diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h
index 555eb54bb6ed..565a6dbb3714 100644
--- a/drivers/net/igb/e1000_phy.h
+++ b/drivers/net/igb/e1000_phy.h
@@ -60,6 +60,8 @@ s32 igb_setup_copper_link(struct e1000_hw *hw);
s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
u32 usec_interval, bool *success);
+void igb_power_up_phy_copper(struct e1000_hw *hw);
+void igb_power_down_phy_copper(struct e1000_hw *hw);
s32 igb_phy_init_script_igp3(struct e1000_hw *hw);
s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h
index dd4e6ffd29f5..abb7333a1fbf 100644
--- a/drivers/net/igb/e1000_regs.h
+++ b/drivers/net/igb/e1000_regs.h
@@ -310,6 +310,7 @@
#define E1000_VMOLR(_n) (0x05AD0 + (4 * (_n)))
#define E1000_VLVF(_n) (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine
* Filter - RW */
+#define E1000_VMVIR(_n) (0x03700 + (4 * (_n)))
#define wr32(reg, value) (writel(value, hw->hw_addr + reg))
#define rd32(reg) (readl(hw->hw_addr + reg))
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
index b1c1eb88893f..a1775705b24c 100644
--- a/drivers/net/igb/igb.h
+++ b/drivers/net/igb/igb.h
@@ -75,11 +75,14 @@ struct vf_data_storage {
u16 vlans_enabled;
u32 flags;
unsigned long last_nack;
+ u16 pf_vlan; /* When set, guest VLAN config not allowed. */
+ u16 pf_qos;
};
#define IGB_VF_FLAG_CTS 0x00000001 /* VF is clear to send data */
#define IGB_VF_FLAG_UNI_PROMISC 0x00000002 /* VF has unicast promisc */
#define IGB_VF_FLAG_MULTI_PROMISC 0x00000004 /* VF has multicast promisc */
+#define IGB_VF_FLAG_PF_SET_MAC 0x00000008 /* PF has set MAC address */
/* RX descriptor control thresholds.
* PTHRESH - MAC will consider prefetch if it has fewer than this number of
@@ -92,13 +95,13 @@ struct vf_data_storage {
* descriptors until either it has this many to write back, or the
* ITR timer expires.
*/
-#define IGB_RX_PTHRESH (hw->mac.type <= e1000_82576 ? 16 : 8)
+#define IGB_RX_PTHRESH 8
#define IGB_RX_HTHRESH 8
#define IGB_RX_WTHRESH 1
#define IGB_TX_PTHRESH 8
#define IGB_TX_HTHRESH 1
#define IGB_TX_WTHRESH ((hw->mac.type == e1000_82576 && \
- adapter->msix_entries) ? 0 : 16)
+ adapter->msix_entries) ? 1 : 16)
/* this is the size past which hardware will drop packets when setting LPE=0 */
#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
@@ -138,6 +141,7 @@ struct igb_buffer {
u16 length;
u16 next_to_watch;
u16 mapped_as_page;
+ u16 gso_segs;
};
/* RX */
struct {
@@ -173,7 +177,6 @@ struct igb_q_vector {
u16 itr_val;
u8 set_itr;
- u8 itr_shift;
void __iomem *itr_register;
char name[IFNAMSIZ + 9];
@@ -238,7 +241,6 @@ static inline int igb_desc_unused(struct igb_ring *ring)
}
/* board specific private data structure */
-
struct igb_adapter {
struct timer_list watchdog_timer;
struct timer_list phy_info_timer;
@@ -264,12 +266,12 @@ struct igb_adapter {
unsigned long led_status;
/* TX */
- struct igb_ring *tx_ring; /* One per active queue */
+ struct igb_ring *tx_ring[16];
unsigned long tx_queue_len;
u32 tx_timeout_count;
/* RX */
- struct igb_ring *rx_ring; /* One per active queue */
+ struct igb_ring *rx_ring[16];
int num_tx_queues;
int num_rx_queues;
@@ -354,7 +356,9 @@ extern void igb_unmap_and_free_tx_resource(struct igb_ring *,
struct igb_buffer *);
extern void igb_alloc_rx_buffers_adv(struct igb_ring *, int);
extern void igb_update_stats(struct igb_adapter *);
+extern bool igb_has_link(struct igb_adapter *adapter);
extern void igb_set_ethtool_ops(struct net_device *);
+extern void igb_power_up_link(struct igb_adapter *);
static inline s32 igb_reset_phy(struct e1000_hw *hw)
{
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index f771a6c08777..a4cead12fd98 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -234,6 +234,24 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
return 0;
}
+static u32 igb_get_link(struct net_device *netdev)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ struct e1000_mac_info *mac = &adapter->hw.mac;
+
+ /*
+ * If the link is not reported up to netdev, interrupts are disabled,
+ * and so the physical link state may have changed since we last
+ * looked. Set get_link_status to make sure that the true link
+ * state is interrogated, rather than pulling a cached and possibly
+ * stale link state from the driver.
+ */
+ if (!netif_carrier_ok(netdev))
+ mac->get_link_status = 1;
+
+ return igb_has_link(adapter);
+}
+
static void igb_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
@@ -296,7 +314,7 @@ static int igb_set_pauseparam(struct net_device *netdev,
static u32 igb_get_rx_csum(struct net_device *netdev)
{
struct igb_adapter *adapter = netdev_priv(netdev);
- return !!(adapter->rx_ring[0].flags & IGB_RING_FLAG_RX_CSUM);
+ return !!(adapter->rx_ring[0]->flags & IGB_RING_FLAG_RX_CSUM);
}
static int igb_set_rx_csum(struct net_device *netdev, u32 data)
@@ -306,9 +324,9 @@ static int igb_set_rx_csum(struct net_device *netdev, u32 data)
for (i = 0; i < adapter->num_rx_queues; i++) {
if (data)
- adapter->rx_ring[i].flags |= IGB_RING_FLAG_RX_CSUM;
+ adapter->rx_ring[i]->flags |= IGB_RING_FLAG_RX_CSUM;
else
- adapter->rx_ring[i].flags &= ~IGB_RING_FLAG_RX_CSUM;
+ adapter->rx_ring[i]->flags &= ~IGB_RING_FLAG_RX_CSUM;
}
return 0;
@@ -771,9 +789,9 @@ static int igb_set_ringparam(struct net_device *netdev,
if (!netif_running(adapter->netdev)) {
for (i = 0; i < adapter->num_tx_queues; i++)
- adapter->tx_ring[i].count = new_tx_count;
+ adapter->tx_ring[i]->count = new_tx_count;
for (i = 0; i < adapter->num_rx_queues; i++)
- adapter->rx_ring[i].count = new_rx_count;
+ adapter->rx_ring[i]->count = new_rx_count;
adapter->tx_ring_count = new_tx_count;
adapter->rx_ring_count = new_rx_count;
goto clear_reset;
@@ -797,10 +815,10 @@ static int igb_set_ringparam(struct net_device *netdev,
* to the tx and rx ring structs.
*/
if (new_tx_count != adapter->tx_ring_count) {
- memcpy(temp_ring, adapter->tx_ring,
- adapter->num_tx_queues * sizeof(struct igb_ring));
-
for (i = 0; i < adapter->num_tx_queues; i++) {
+ memcpy(&temp_ring[i], adapter->tx_ring[i],
+ sizeof(struct igb_ring));
+
temp_ring[i].count = new_tx_count;
err = igb_setup_tx_resources(&temp_ring[i]);
if (err) {
@@ -812,20 +830,21 @@ static int igb_set_ringparam(struct net_device *netdev,
}
}
- for (i = 0; i < adapter->num_tx_queues; i++)
- igb_free_tx_resources(&adapter->tx_ring[i]);
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ igb_free_tx_resources(adapter->tx_ring[i]);
- memcpy(adapter->tx_ring, temp_ring,
- adapter->num_tx_queues * sizeof(struct igb_ring));
+ memcpy(adapter->tx_ring[i], &temp_ring[i],
+ sizeof(struct igb_ring));
+ }
adapter->tx_ring_count = new_tx_count;
}
- if (new_rx_count != adapter->rx_ring->count) {
- memcpy(temp_ring, adapter->rx_ring,
- adapter->num_rx_queues * sizeof(struct igb_ring));
-
+ if (new_rx_count != adapter->rx_ring_count) {
for (i = 0; i < adapter->num_rx_queues; i++) {
+ memcpy(&temp_ring[i], adapter->rx_ring[i],
+ sizeof(struct igb_ring));
+
temp_ring[i].count = new_rx_count;
err = igb_setup_rx_resources(&temp_ring[i]);
if (err) {
@@ -838,11 +857,12 @@ static int igb_set_ringparam(struct net_device *netdev,
}
- for (i = 0; i < adapter->num_rx_queues; i++)
- igb_free_rx_resources(&adapter->rx_ring[i]);
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ igb_free_rx_resources(adapter->rx_ring[i]);
- memcpy(adapter->rx_ring, temp_ring,
- adapter->num_rx_queues * sizeof(struct igb_ring));
+ memcpy(adapter->rx_ring[i], &temp_ring[i],
+ sizeof(struct igb_ring));
+ }
adapter->rx_ring_count = new_rx_count;
}
@@ -1704,6 +1724,9 @@ static void igb_diag_test(struct net_device *netdev,
dev_info(&adapter->pdev->dev, "offline testing starting\n");
+ /* power up link for link test */
+ igb_power_up_link(adapter);
+
/* Link test performed before hardware reset so autoneg doesn't
* interfere with test result */
if (igb_link_test(adapter, &data[4]))
@@ -1727,6 +1750,8 @@ static void igb_diag_test(struct net_device *netdev,
eth_test->flags |= ETH_TEST_FL_FAILED;
igb_reset(adapter);
+ /* power up link for loopback test */
+ igb_power_up_link(adapter);
if (igb_loopback_test(adapter, &data[3]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1745,9 +1770,14 @@ static void igb_diag_test(struct net_device *netdev,
dev_open(netdev);
} else {
dev_info(&adapter->pdev->dev, "online testing starting\n");
- /* Online tests */
- if (igb_link_test(adapter, &data[4]))
- eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ /* PHY is powered down when interface is down */
+ if (!netif_carrier_ok(netdev)) {
+ data[4] = 0;
+ } else {
+ if (igb_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+ }
/* Online tests aren't run; pass by default */
data[0] = 0;
@@ -1812,7 +1842,8 @@ static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
struct igb_adapter *adapter = netdev_priv(netdev);
wol->supported = WAKE_UCAST | WAKE_MCAST |
- WAKE_BCAST | WAKE_MAGIC;
+ WAKE_BCAST | WAKE_MAGIC |
+ WAKE_PHY;
wol->wolopts = 0;
/* this function will set ->supported = 0 and return 1 if wol is not
@@ -1835,15 +1866,15 @@ static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
wol->wolopts |= WAKE_BCAST;
if (adapter->wol & E1000_WUFC_MAG)
wol->wolopts |= WAKE_MAGIC;
-
- return;
+ if (adapter->wol & E1000_WUFC_LNKC)
+ wol->wolopts |= WAKE_PHY;
}
static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
struct igb_adapter *adapter = netdev_priv(netdev);
- if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+ if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE))
return -EOPNOTSUPP;
if (igb_wol_exclusion(adapter, wol) ||
@@ -1861,6 +1892,8 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
adapter->wol |= E1000_WUFC_BC;
if (wol->wolopts & WAKE_MAGIC)
adapter->wol |= E1000_WUFC_MAG;
+ if (wol->wolopts & WAKE_PHY)
+ adapter->wol |= E1000_WUFC_LNKC;
device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
return 0;
@@ -2005,12 +2038,12 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
for (j = 0; j < adapter->num_tx_queues; j++) {
- queue_stat = (u64 *)&adapter->tx_ring[j].tx_stats;
+ queue_stat = (u64 *)&adapter->tx_ring[j]->tx_stats;
for (k = 0; k < IGB_TX_QUEUE_STATS_LEN; k++, i++)
data[i] = queue_stat[k];
}
for (j = 0; j < adapter->num_rx_queues; j++) {
- queue_stat = (u64 *)&adapter->rx_ring[j].rx_stats;
+ queue_stat = (u64 *)&adapter->rx_ring[j]->rx_stats;
for (k = 0; k < IGB_RX_QUEUE_STATS_LEN; k++, i++)
data[i] = queue_stat[k];
}
@@ -2074,7 +2107,7 @@ static const struct ethtool_ops igb_ethtool_ops = {
.get_msglevel = igb_get_msglevel,
.set_msglevel = igb_set_msglevel,
.nway_reset = igb_nway_reset,
- .get_link = ethtool_op_get_link,
+ .get_link = igb_get_link,
.get_eeprom_len = igb_get_eeprom_len,
.get_eeprom = igb_get_eeprom,
.set_eeprom = igb_set_eeprom,
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 933c64ff2465..0ed25f059a00 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -60,7 +60,7 @@ static const struct e1000_info *igb_info_tbl[] = {
[board_82575] = &e1000_82575_info,
};
-static struct pci_device_id igb_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_FIBER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), board_82575 },
@@ -133,6 +133,12 @@ static void igb_msg_task(struct igb_adapter *);
static void igb_vmm_control(struct igb_adapter *);
static int igb_set_vf_mac(struct igb_adapter *, int, unsigned char *);
static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
+static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac);
+static int igb_ndo_set_vf_vlan(struct net_device *netdev,
+ int vf, u16 vlan, u8 qos);
+static int igb_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate);
+static int igb_ndo_get_vf_config(struct net_device *netdev, int vf,
+ struct ifla_vf_info *ivi);
#ifdef CONFIG_PM
static int igb_suspend(struct pci_dev *, pm_message_t);
@@ -312,31 +318,35 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
*/
if (adapter->vfs_allocated_count) {
for (; i < adapter->rss_queues; i++)
- adapter->rx_ring[i].reg_idx = rbase_offset +
- Q_IDX_82576(i);
+ adapter->rx_ring[i]->reg_idx = rbase_offset +
+ Q_IDX_82576(i);
for (; j < adapter->rss_queues; j++)
- adapter->tx_ring[j].reg_idx = rbase_offset +
- Q_IDX_82576(j);
+ adapter->tx_ring[j]->reg_idx = rbase_offset +
+ Q_IDX_82576(j);
}
case e1000_82575:
case e1000_82580:
default:
for (; i < adapter->num_rx_queues; i++)
- adapter->rx_ring[i].reg_idx = rbase_offset + i;
+ adapter->rx_ring[i]->reg_idx = rbase_offset + i;
for (; j < adapter->num_tx_queues; j++)
- adapter->tx_ring[j].reg_idx = rbase_offset + j;
+ adapter->tx_ring[j]->reg_idx = rbase_offset + j;
break;
}
}
static void igb_free_queues(struct igb_adapter *adapter)
{
- kfree(adapter->tx_ring);
- kfree(adapter->rx_ring);
-
- adapter->tx_ring = NULL;
- adapter->rx_ring = NULL;
+ int i;
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ kfree(adapter->tx_ring[i]);
+ adapter->tx_ring[i] = NULL;
+ }
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ kfree(adapter->rx_ring[i]);
+ adapter->rx_ring[i] = NULL;
+ }
adapter->num_rx_queues = 0;
adapter->num_tx_queues = 0;
}
@@ -350,20 +360,13 @@ static void igb_free_queues(struct igb_adapter *adapter)
**/
static int igb_alloc_queues(struct igb_adapter *adapter)
{
+ struct igb_ring *ring;
int i;
- adapter->tx_ring = kcalloc(adapter->num_tx_queues,
- sizeof(struct igb_ring), GFP_KERNEL);
- if (!adapter->tx_ring)
- goto err;
-
- adapter->rx_ring = kcalloc(adapter->num_rx_queues,
- sizeof(struct igb_ring), GFP_KERNEL);
- if (!adapter->rx_ring)
- goto err;
-
for (i = 0; i < adapter->num_tx_queues; i++) {
- struct igb_ring *ring = &(adapter->tx_ring[i]);
+ ring = kzalloc(sizeof(struct igb_ring), GFP_KERNEL);
+ if (!ring)
+ goto err;
ring->count = adapter->tx_ring_count;
ring->queue_index = i;
ring->pdev = adapter->pdev;
@@ -371,10 +374,13 @@ static int igb_alloc_queues(struct igb_adapter *adapter)
/* For 82575, context index must be unique per ring. */
if (adapter->hw.mac.type == e1000_82575)
ring->flags = IGB_RING_FLAG_TX_CTX_IDX;
+ adapter->tx_ring[i] = ring;
}
for (i = 0; i < adapter->num_rx_queues; i++) {
- struct igb_ring *ring = &(adapter->rx_ring[i]);
+ ring = kzalloc(sizeof(struct igb_ring), GFP_KERNEL);
+ if (!ring)
+ goto err;
ring->count = adapter->rx_ring_count;
ring->queue_index = i;
ring->pdev = adapter->pdev;
@@ -384,6 +390,7 @@ static int igb_alloc_queues(struct igb_adapter *adapter)
/* set flag indicating ring supports SCTP checksum offload */
if (adapter->hw.mac.type >= e1000_82576)
ring->flags |= IGB_RING_FLAG_RX_SCTP_CSUM;
+ adapter->rx_ring[i] = ring;
}
igb_cache_ring_register(adapter);
@@ -421,6 +428,8 @@ static void igb_assign_vector(struct igb_q_vector *q_vector, int msix_vector)
msixbm = E1000_EICR_RX_QUEUE0 << rx_queue;
if (tx_queue > IGB_N0_QUEUE)
msixbm |= E1000_EICR_TX_QUEUE0 << tx_queue;
+ if (!adapter->msix_entries && msix_vector == 0)
+ msixbm |= E1000_EIMS_OTHER;
array_wr32(E1000_MSIXBM(0), msix_vector, msixbm);
q_vector->eims_value = msixbm;
break;
@@ -496,6 +505,12 @@ static void igb_assign_vector(struct igb_q_vector *q_vector, int msix_vector)
BUG();
break;
}
+
+ /* add q_vector eims value to global eims_enable_mask */
+ adapter->eims_enable_mask |= q_vector->eims_value;
+
+ /* configure q_vector to set itr on first interrupt */
+ q_vector->set_itr = 1;
}
/**
@@ -553,11 +568,8 @@ static void igb_configure_msix(struct igb_adapter *adapter)
adapter->eims_enable_mask |= adapter->eims_other;
- for (i = 0; i < adapter->num_q_vectors; i++) {
- struct igb_q_vector *q_vector = adapter->q_vector[i];
- igb_assign_vector(q_vector, vector++);
- adapter->eims_enable_mask |= q_vector->eims_value;
- }
+ for (i = 0; i < adapter->num_q_vectors; i++)
+ igb_assign_vector(adapter->q_vector[i], vector++);
wrfl();
}
@@ -637,6 +649,8 @@ static void igb_free_q_vectors(struct igb_adapter *adapter)
for (v_idx = 0; v_idx < adapter->num_q_vectors; v_idx++) {
struct igb_q_vector *q_vector = adapter->q_vector[v_idx];
adapter->q_vector[v_idx] = NULL;
+ if (!q_vector)
+ continue;
netif_napi_del(&q_vector->napi);
kfree(q_vector);
}
@@ -674,7 +688,7 @@ static void igb_set_interrupt_capability(struct igb_adapter *adapter)
/* start with one vector for every rx queue */
numvecs = adapter->num_rx_queues;
- /* if tx handler is seperate add 1 for every tx queue */
+ /* if tx handler is separate add 1 for every tx queue */
if (!(adapter->flags & IGB_FLAG_QUEUE_PAIRS))
numvecs += adapter->num_tx_queues;
@@ -748,33 +762,24 @@ static int igb_alloc_q_vectors(struct igb_adapter *adapter)
if (!q_vector)
goto err_out;
q_vector->adapter = adapter;
- q_vector->itr_shift = (hw->mac.type == e1000_82575) ? 16 : 0;
q_vector->itr_register = hw->hw_addr + E1000_EITR(0);
q_vector->itr_val = IGB_START_ITR;
- q_vector->set_itr = 1;
netif_napi_add(adapter->netdev, &q_vector->napi, igb_poll, 64);
adapter->q_vector[v_idx] = q_vector;
}
return 0;
err_out:
- while (v_idx) {
- v_idx--;
- q_vector = adapter->q_vector[v_idx];
- netif_napi_del(&q_vector->napi);
- kfree(q_vector);
- adapter->q_vector[v_idx] = NULL;
- }
+ igb_free_q_vectors(adapter);
return -ENOMEM;
}
static void igb_map_rx_ring_to_vector(struct igb_adapter *adapter,
int ring_idx, int v_idx)
{
- struct igb_q_vector *q_vector;
+ struct igb_q_vector *q_vector = adapter->q_vector[v_idx];
- q_vector = adapter->q_vector[v_idx];
- q_vector->rx_ring = &adapter->rx_ring[ring_idx];
+ q_vector->rx_ring = adapter->rx_ring[ring_idx];
q_vector->rx_ring->q_vector = q_vector;
q_vector->itr_val = adapter->rx_itr_setting;
if (q_vector->itr_val && q_vector->itr_val <= 3)
@@ -784,10 +789,9 @@ static void igb_map_rx_ring_to_vector(struct igb_adapter *adapter,
static void igb_map_tx_ring_to_vector(struct igb_adapter *adapter,
int ring_idx, int v_idx)
{
- struct igb_q_vector *q_vector;
+ struct igb_q_vector *q_vector = adapter->q_vector[v_idx];
- q_vector = adapter->q_vector[v_idx];
- q_vector->tx_ring = &adapter->tx_ring[ring_idx];
+ q_vector->tx_ring = adapter->tx_ring[ring_idx];
q_vector->tx_ring->q_vector = q_vector;
q_vector->itr_val = adapter->tx_itr_setting;
if (q_vector->itr_val && q_vector->itr_val <= 3)
@@ -877,7 +881,6 @@ static int igb_request_irq(struct igb_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
- struct e1000_hw *hw = &adapter->hw;
int err = 0;
if (adapter->msix_entries) {
@@ -909,20 +912,7 @@ static int igb_request_irq(struct igb_adapter *adapter)
igb_setup_all_tx_resources(adapter);
igb_setup_all_rx_resources(adapter);
} else {
- switch (hw->mac.type) {
- case e1000_82575:
- wr32(E1000_MSIXBM(0),
- (E1000_EICR_RX_QUEUE0 |
- E1000_EICR_TX_QUEUE0 |
- E1000_EIMS_OTHER));
- break;
- case e1000_82580:
- case e1000_82576:
- wr32(E1000_IVAR0, E1000_IVAR_VALID);
- break;
- default:
- break;
- }
+ igb_assign_vector(adapter->q_vector[0], 0);
}
if (adapter->flags & IGB_FLAG_HAS_MSI) {
@@ -1111,7 +1101,7 @@ static void igb_configure(struct igb_adapter *adapter)
* at least 1 descriptor unused to make sure
* next_to_use != next_to_clean */
for (i = 0; i < adapter->num_rx_queues; i++) {
- struct igb_ring *ring = &adapter->rx_ring[i];
+ struct igb_ring *ring = adapter->rx_ring[i];
igb_alloc_rx_buffers_adv(ring, igb_desc_unused(ring));
}
@@ -1119,6 +1109,29 @@ static void igb_configure(struct igb_adapter *adapter)
adapter->tx_queue_len = netdev->tx_queue_len;
}
+/**
+ * igb_power_up_link - Power up the phy/serdes link
+ * @adapter: address of board private structure
+ **/
+void igb_power_up_link(struct igb_adapter *adapter)
+{
+ if (adapter->hw.phy.media_type == e1000_media_type_copper)
+ igb_power_up_phy_copper(&adapter->hw);
+ else
+ igb_power_up_serdes_link_82575(&adapter->hw);
+}
+
+/**
+ * igb_power_down_link - Power down the phy/serdes link
+ * @adapter: address of board private structure
+ */
+static void igb_power_down_link(struct igb_adapter *adapter)
+{
+ if (adapter->hw.phy.media_type == e1000_media_type_copper)
+ igb_power_down_phy_copper_82575(&adapter->hw);
+ else
+ igb_shutdown_serdes_link_82575(&adapter->hw);
+}
/**
* igb_up - Open the interface and prepare it to handle traffic
@@ -1140,6 +1153,8 @@ int igb_up(struct igb_adapter *adapter)
}
if (adapter->msix_entries)
igb_configure_msix(adapter);
+ else
+ igb_assign_vector(adapter->q_vector[0], 0);
/* Clear any pending interrupts. */
rd32(E1000_ICR);
@@ -1338,12 +1353,14 @@ void igb_reset(struct igb_adapter *adapter)
wr32(E1000_PCIEMISC,
reg & ~E1000_PCIEMISC_LX_DECISION);
}
+ if (!netif_running(adapter->netdev))
+ igb_power_down_link(adapter);
+
igb_update_mng_vlan(adapter);
/* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE);
- igb_reset_adaptive(hw);
igb_get_phy_info(hw);
}
@@ -1362,6 +1379,10 @@ static const struct net_device_ops igb_netdev_ops = {
.ndo_vlan_rx_register = igb_vlan_rx_register,
.ndo_vlan_rx_add_vid = igb_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = igb_vlan_rx_kill_vid,
+ .ndo_set_vf_mac = igb_ndo_set_vf_mac,
+ .ndo_set_vf_vlan = igb_ndo_set_vf_vlan,
+ .ndo_set_vf_tx_rate = igb_ndo_set_vf_bw,
+ .ndo_get_vf_config = igb_ndo_get_vf_config,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = igb_netpoll,
#endif
@@ -1482,7 +1503,6 @@ static int __devinit igb_probe(struct pci_dev *pdev,
igb_get_bus_info_pcie(hw);
hw->phy.autoneg_wait_to_complete = false;
- hw->mac.adaptive_ifs = true;
/* Copper options */
if (hw->phy.media_type == e1000_media_type_copper) {
@@ -1716,9 +1736,6 @@ static void __devexit igb_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
- if (!igb_check_reset_block(hw))
- igb_reset_phy(hw);
-
igb_clear_interrupt_scheme(adapter);
#ifdef CONFIG_PCI_IOV
@@ -1994,7 +2011,7 @@ static int igb_open(struct net_device *netdev)
if (err)
goto err_setup_rx;
- /* e1000_power_up_phy(adapter); */
+ igb_power_up_link(adapter);
/* before we allocate an interrupt, we must be ready to handle it.
* Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
@@ -2036,7 +2053,7 @@ static int igb_open(struct net_device *netdev)
err_req_irq:
igb_release_hw_control(adapter);
- /* e1000_power_down_phy(adapter); */
+ igb_power_down_link(adapter);
igb_free_all_rx_resources(adapter);
err_setup_rx:
igb_free_all_tx_resources(adapter);
@@ -2124,19 +2141,19 @@ static int igb_setup_all_tx_resources(struct igb_adapter *adapter)
int i, err = 0;
for (i = 0; i < adapter->num_tx_queues; i++) {
- err = igb_setup_tx_resources(&adapter->tx_ring[i]);
+ err = igb_setup_tx_resources(adapter->tx_ring[i]);
if (err) {
dev_err(&pdev->dev,
"Allocation for Tx Queue %u failed\n", i);
for (i--; i >= 0; i--)
- igb_free_tx_resources(&adapter->tx_ring[i]);
+ igb_free_tx_resources(adapter->tx_ring[i]);
break;
}
}
for (i = 0; i < IGB_ABS_MAX_TX_QUEUES; i++) {
int r_idx = i % adapter->num_tx_queues;
- adapter->multi_tx_table[i] = &adapter->tx_ring[r_idx];
+ adapter->multi_tx_table[i] = adapter->tx_ring[r_idx];
}
return err;
}
@@ -2219,7 +2236,7 @@ static void igb_configure_tx(struct igb_adapter *adapter)
int i;
for (i = 0; i < adapter->num_tx_queues; i++)
- igb_configure_tx_ring(adapter, &adapter->tx_ring[i]);
+ igb_configure_tx_ring(adapter, adapter->tx_ring[i]);
}
/**
@@ -2277,12 +2294,12 @@ static int igb_setup_all_rx_resources(struct igb_adapter *adapter)
int i, err = 0;
for (i = 0; i < adapter->num_rx_queues; i++) {
- err = igb_setup_rx_resources(&adapter->rx_ring[i]);
+ err = igb_setup_rx_resources(adapter->rx_ring[i]);
if (err) {
dev_err(&pdev->dev,
"Allocation for Rx Queue %u failed\n", i);
for (i--; i >= 0; i--)
- igb_free_rx_resources(&adapter->rx_ring[i]);
+ igb_free_rx_resources(adapter->rx_ring[i]);
break;
}
}
@@ -2489,7 +2506,8 @@ static void igb_rlpml_set(struct igb_adapter *adapter)
wr32(E1000_RLPML, max_frame_size);
}
-static inline void igb_set_vmolr(struct igb_adapter *adapter, int vfn)
+static inline void igb_set_vmolr(struct igb_adapter *adapter,
+ int vfn, bool aupe)
{
struct e1000_hw *hw = &adapter->hw;
u32 vmolr;
@@ -2502,8 +2520,11 @@ static inline void igb_set_vmolr(struct igb_adapter *adapter, int vfn)
return;
vmolr = rd32(E1000_VMOLR(vfn));
- vmolr |= E1000_VMOLR_AUPE | /* Accept untagged packets */
- E1000_VMOLR_STRVLAN; /* Strip vlan tags */
+ vmolr |= E1000_VMOLR_STRVLAN; /* Strip vlan tags */
+ if (aupe)
+ vmolr |= E1000_VMOLR_AUPE; /* Accept untagged packets */
+ else
+ vmolr &= ~(E1000_VMOLR_AUPE); /* Tagged packets ONLY */
/* clear all bits that might not be set */
vmolr &= ~(E1000_VMOLR_BAM | E1000_VMOLR_RSSE);
@@ -2570,11 +2591,14 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
E1000_SRRCTL_BSIZEPKT_SHIFT;
srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
}
+ /* Only set Drop Enable if we are supporting multiple queues */
+ if (adapter->vfs_allocated_count || adapter->num_rx_queues > 1)
+ srrctl |= E1000_SRRCTL_DROP_EN;
wr32(E1000_SRRCTL(reg_idx), srrctl);
/* set filtering for VMDQ pools */
- igb_set_vmolr(adapter, reg_idx & 0x7);
+ igb_set_vmolr(adapter, reg_idx & 0x7, true);
/* enable receive descriptor fetching */
rxdctl = rd32(E1000_RXDCTL(reg_idx));
@@ -2606,7 +2630,7 @@ static void igb_configure_rx(struct igb_adapter *adapter)
/* Setup the HW Rx Head and Tail Descriptor Pointers and
* the Base and Length of the Rx Descriptor Ring */
for (i = 0; i < adapter->num_rx_queues; i++)
- igb_configure_rx_ring(adapter, &adapter->rx_ring[i]);
+ igb_configure_rx_ring(adapter, adapter->rx_ring[i]);
}
/**
@@ -2643,7 +2667,7 @@ static void igb_free_all_tx_resources(struct igb_adapter *adapter)
int i;
for (i = 0; i < adapter->num_tx_queues; i++)
- igb_free_tx_resources(&adapter->tx_ring[i]);
+ igb_free_tx_resources(adapter->tx_ring[i]);
}
void igb_unmap_and_free_tx_resource(struct igb_ring *tx_ring,
@@ -2710,7 +2734,7 @@ static void igb_clean_all_tx_rings(struct igb_adapter *adapter)
int i;
for (i = 0; i < adapter->num_tx_queues; i++)
- igb_clean_tx_ring(&adapter->tx_ring[i]);
+ igb_clean_tx_ring(adapter->tx_ring[i]);
}
/**
@@ -2747,7 +2771,7 @@ static void igb_free_all_rx_resources(struct igb_adapter *adapter)
int i;
for (i = 0; i < adapter->num_rx_queues; i++)
- igb_free_rx_resources(&adapter->rx_ring[i]);
+ igb_free_rx_resources(adapter->rx_ring[i]);
}
/**
@@ -2811,7 +2835,7 @@ static void igb_clean_all_rx_rings(struct igb_adapter *adapter)
int i;
for (i = 0; i < adapter->num_rx_queues; i++)
- igb_clean_rx_ring(&adapter->rx_ring[i]);
+ igb_clean_rx_ring(adapter->rx_ring[i]);
}
/**
@@ -2853,38 +2877,30 @@ static int igb_write_mc_addr_list(struct net_device *netdev)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- struct dev_mc_list *mc_ptr = netdev->mc_list;
+ struct dev_mc_list *mc_ptr;
u8 *mta_list;
- u32 vmolr = 0;
int i;
- if (!netdev->mc_count) {
+ if (netdev_mc_empty(netdev)) {
/* nothing to program, so clear mc list */
igb_update_mc_addr_list(hw, NULL, 0);
igb_restore_vf_multicasts(adapter);
return 0;
}
- mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC);
+ mta_list = kzalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC);
if (!mta_list)
return -ENOMEM;
- /* set vmolr receive overflow multicast bit */
- vmolr |= E1000_VMOLR_ROMPE;
-
/* The shared function expects a packed array of only addresses. */
- mc_ptr = netdev->mc_list;
+ i = 0;
+ netdev_for_each_mc_addr(mc_ptr, netdev)
+ memcpy(mta_list + (i++ * ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
- for (i = 0; i < netdev->mc_count; i++) {
- if (!mc_ptr)
- break;
- memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
- mc_ptr = mc_ptr->next;
- }
igb_update_mc_addr_list(hw, mta_list, i);
kfree(mta_list);
- return netdev->mc_count;
+ return netdev_mc_count(netdev);
}
/**
@@ -2905,12 +2921,13 @@ static int igb_write_uc_addr_list(struct net_device *netdev)
int count = 0;
/* return ENOMEM indicating insufficient memory for addresses */
- if (netdev->uc.count > rar_entries)
+ if (netdev_uc_count(netdev) > rar_entries)
return -ENOMEM;
- if (netdev->uc.count && rar_entries) {
+ if (!netdev_uc_empty(netdev) && rar_entries) {
struct netdev_hw_addr *ha;
- list_for_each_entry(ha, &netdev->uc.list, list) {
+
+ netdev_for_each_uc_addr(ha, netdev) {
if (!rar_entries)
break;
igb_rar_set_qsel(adapter, ha->addr,
@@ -3014,7 +3031,7 @@ static void igb_update_phy_info(unsigned long data)
* igb_has_link - check shared code for link and determine up/down
* @adapter: pointer to driver private info
**/
-static bool igb_has_link(struct igb_adapter *adapter)
+bool igb_has_link(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
bool link_active = false;
@@ -3131,10 +3148,9 @@ static void igb_watchdog_task(struct work_struct *work)
}
igb_update_stats(adapter);
- igb_update_adaptive(hw);
for (i = 0; i < adapter->num_tx_queues; i++) {
- struct igb_ring *tx_ring = &adapter->tx_ring[i];
+ struct igb_ring *tx_ring = adapter->tx_ring[i];
if (!netif_carrier_ok(netdev)) {
/* We've lost link, so the controller stops DMA,
* but we've got queued Tx work that's never going
@@ -3235,6 +3251,10 @@ static void igb_update_ring_itr(struct igb_q_vector *q_vector)
else
new_val = avg_wire_size / 2;
+ /* when in itr mode 3 do not exceed 20K ints/sec */
+ if (adapter->rx_itr_setting == 3 && new_val < 196)
+ new_val = 196;
+
set_itr_val:
if (new_val != q_vector->itr_val) {
q_vector->itr_val = new_val;
@@ -3330,13 +3350,13 @@ static void igb_set_itr(struct igb_adapter *adapter)
adapter->rx_itr = igb_update_itr(adapter,
adapter->rx_itr,
- adapter->rx_ring->total_packets,
- adapter->rx_ring->total_bytes);
+ q_vector->rx_ring->total_packets,
+ q_vector->rx_ring->total_bytes);
adapter->tx_itr = igb_update_itr(adapter,
adapter->tx_itr,
- adapter->tx_ring->total_packets,
- adapter->tx_ring->total_bytes);
+ q_vector->tx_ring->total_packets,
+ q_vector->tx_ring->total_bytes);
current_itr = max(adapter->rx_itr, adapter->tx_itr);
/* conservative mode (itr 3) eliminates the lowest_latency setting */
@@ -3359,10 +3379,10 @@ static void igb_set_itr(struct igb_adapter *adapter)
}
set_itr_now:
- adapter->rx_ring->total_bytes = 0;
- adapter->rx_ring->total_packets = 0;
- adapter->tx_ring->total_bytes = 0;
- adapter->tx_ring->total_packets = 0;
+ q_vector->rx_ring->total_bytes = 0;
+ q_vector->rx_ring->total_packets = 0;
+ q_vector->tx_ring->total_bytes = 0;
+ q_vector->tx_ring->total_packets = 0;
if (new_itr != q_vector->itr_val) {
/* this attempts to bias the interrupt rate towards Bulk
@@ -3402,8 +3422,8 @@ static inline int igb_tso_adv(struct igb_ring *tx_ring,
int err;
struct igb_buffer *buffer_info;
u32 info = 0, tu_cmd = 0;
- u32 mss_l4len_idx, l4len;
- *hdr_len = 0;
+ u32 mss_l4len_idx;
+ u8 l4len;
if (skb_header_cloned(skb)) {
err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
@@ -3422,7 +3442,7 @@ static inline int igb_tso_adv(struct igb_ring *tx_ring,
iph->daddr, 0,
IPPROTO_TCP,
0);
- } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+ } else if (skb_is_gso_v6(skb)) {
ipv6_hdr(skb)->payload_len = 0;
tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr,
@@ -3584,6 +3604,7 @@ static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb,
for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
struct skb_frag_struct *frag;
+ count++;
i++;
if (i == tx_ring->count)
i = 0;
@@ -3605,10 +3626,10 @@ static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb,
if (pci_dma_mapping_error(pdev, buffer_info->dma))
goto dma_error;
- count++;
}
tx_ring->buffer_info[i].skb = skb;
+ tx_ring->buffer_info[i].gso_segs = skb_shinfo(skb)->gso_segs ?: 1;
tx_ring->buffer_info[first].next_to_watch = i;
return ++count;
@@ -3622,14 +3643,12 @@ dma_error:
buffer_info->length = 0;
buffer_info->next_to_watch = 0;
buffer_info->mapped_as_page = false;
- count--;
/* clear timestamp and dma mappings for remaining portion of packet */
- while (count >= 0) {
- count--;
+ while (count--) {
+ if (i == 0)
+ i = tx_ring->count;
i--;
- if (i < 0)
- i += tx_ring->count;
buffer_info = &tx_ring->buffer_info[i];
igb_unmap_and_free_tx_resource(tx_ring, buffer_info);
}
@@ -3638,7 +3657,7 @@ dma_error:
}
static inline void igb_tx_queue_adv(struct igb_ring *tx_ring,
- int tx_flags, int count, u32 paylen,
+ u32 tx_flags, int count, u32 paylen,
u8 hdr_len)
{
union e1000_adv_tx_desc *tx_desc;
@@ -3726,7 +3745,7 @@ static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, int size)
return 0;
}
-static int igb_maybe_stop_tx(struct igb_ring *tx_ring, int size)
+static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, int size)
{
if (igb_desc_unused(tx_ring) >= size)
return 0;
@@ -3737,10 +3756,10 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb,
struct igb_ring *tx_ring)
{
struct igb_adapter *adapter = netdev_priv(tx_ring->netdev);
- unsigned int first;
- unsigned int tx_flags = 0;
- u8 hdr_len = 0;
int tso = 0, count;
+ u32 tx_flags = 0;
+ u16 first;
+ u8 hdr_len = 0;
union skb_shared_tx *shtx = skb_tx(skb);
/* need: 1 descriptor per page,
@@ -3921,7 +3940,7 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
netdev->mtu = new_mtu;
for (i = 0; i < adapter->num_rx_queues; i++)
- adapter->rx_ring[i].rx_buffer_len = rx_buffer_len;
+ adapter->rx_ring[i]->rx_buffer_len = rx_buffer_len;
if (netif_running(netdev))
igb_up(adapter);
@@ -3943,7 +3962,7 @@ void igb_update_stats(struct igb_adapter *adapter)
struct net_device_stats *net_stats = igb_get_stats(adapter->netdev);
struct e1000_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
- u32 rnbc;
+ u32 rnbc, reg;
u16 phy_tmp;
int i;
u64 bytes, packets;
@@ -3963,10 +3982,11 @@ void igb_update_stats(struct igb_adapter *adapter)
packets = 0;
for (i = 0; i < adapter->num_rx_queues; i++) {
u32 rqdpc_tmp = rd32(E1000_RQDPC(i)) & 0x0FFF;
- adapter->rx_ring[i].rx_stats.drops += rqdpc_tmp;
+ struct igb_ring *ring = adapter->rx_ring[i];
+ ring->rx_stats.drops += rqdpc_tmp;
net_stats->rx_fifo_errors += rqdpc_tmp;
- bytes += adapter->rx_ring[i].rx_stats.bytes;
- packets += adapter->rx_ring[i].rx_stats.packets;
+ bytes += ring->rx_stats.bytes;
+ packets += ring->rx_stats.packets;
}
net_stats->rx_bytes = bytes;
@@ -3975,8 +3995,9 @@ void igb_update_stats(struct igb_adapter *adapter)
bytes = 0;
packets = 0;
for (i = 0; i < adapter->num_tx_queues; i++) {
- bytes += adapter->tx_ring[i].tx_stats.bytes;
- packets += adapter->tx_ring[i].tx_stats.packets;
+ struct igb_ring *ring = adapter->tx_ring[i];
+ bytes += ring->tx_stats.bytes;
+ packets += ring->tx_stats.packets;
}
net_stats->tx_bytes = bytes;
net_stats->tx_packets = packets;
@@ -4034,15 +4055,17 @@ void igb_update_stats(struct igb_adapter *adapter)
adapter->stats.mptc += rd32(E1000_MPTC);
adapter->stats.bptc += rd32(E1000_BPTC);
- /* used for adaptive IFS */
- hw->mac.tx_packet_delta = rd32(E1000_TPT);
- adapter->stats.tpt += hw->mac.tx_packet_delta;
- hw->mac.collision_delta = rd32(E1000_COLC);
- adapter->stats.colc += hw->mac.collision_delta;
+ adapter->stats.tpt += rd32(E1000_TPT);
+ adapter->stats.colc += rd32(E1000_COLC);
adapter->stats.algnerrc += rd32(E1000_ALGNERRC);
- adapter->stats.rxerrc += rd32(E1000_RXERRC);
- adapter->stats.tncrs += rd32(E1000_TNCRS);
+ /* read internal phy specific stats */
+ reg = rd32(E1000_CTRL_EXT);
+ if (!(reg & E1000_CTRL_EXT_LINK_MODE_MASK)) {
+ adapter->stats.rxerrc += rd32(E1000_RXERRC);
+ adapter->stats.tncrs += rd32(E1000_TNCRS);
+ }
+
adapter->stats.tsctc += rd32(E1000_TSCTC);
adapter->stats.tsctfc += rd32(E1000_TSCTFC);
@@ -4105,6 +4128,9 @@ static irqreturn_t igb_msix_other(int irq, void *data)
u32 icr = rd32(E1000_ICR);
/* reading ICR causes bit 31 of EICR to be cleared */
+ if (icr & E1000_ICR_DRSTA)
+ schedule_work(&adapter->reset_task);
+
if (icr & E1000_ICR_DOUTSYNC) {
/* HW is reporting DMA is out of sync */
adapter->stats.doosync++;
@@ -4134,6 +4160,7 @@ static irqreturn_t igb_msix_other(int irq, void *data)
static void igb_write_itr(struct igb_q_vector *q_vector)
{
+ struct igb_adapter *adapter = q_vector->adapter;
u32 itr_val = q_vector->itr_val & 0x7FFC;
if (!q_vector->set_itr)
@@ -4142,8 +4169,8 @@ static void igb_write_itr(struct igb_q_vector *q_vector)
if (!itr_val)
itr_val = 0x4;
- if (q_vector->itr_shift)
- itr_val |= itr_val << q_vector->itr_shift;
+ if (adapter->hw.mac.type == e1000_82575)
+ itr_val |= itr_val << 16;
else
itr_val |= 0x8000000;
@@ -4220,9 +4247,8 @@ static void igb_setup_dca(struct igb_adapter *adapter)
wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_CB2);
for (i = 0; i < adapter->num_q_vectors; i++) {
- struct igb_q_vector *q_vector = adapter->q_vector[i];
- q_vector->cpu = -1;
- igb_update_dca(q_vector);
+ adapter->q_vector[i]->cpu = -1;
+ igb_update_dca(adapter->q_vector[i]);
}
}
@@ -4496,10 +4522,57 @@ static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf)
reg |= size;
wr32(E1000_VMOLR(vf), reg);
}
- return 0;
}
}
- return -1;
+ return 0;
+}
+
+static void igb_set_vmvir(struct igb_adapter *adapter, u32 vid, u32 vf)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (vid)
+ wr32(E1000_VMVIR(vf), (vid | E1000_VMVIR_VLANA_DEFAULT));
+ else
+ wr32(E1000_VMVIR(vf), 0);
+}
+
+static int igb_ndo_set_vf_vlan(struct net_device *netdev,
+ int vf, u16 vlan, u8 qos)
+{
+ int err = 0;
+ struct igb_adapter *adapter = netdev_priv(netdev);
+
+ if ((vf >= adapter->vfs_allocated_count) || (vlan > 4095) || (qos > 7))
+ return -EINVAL;
+ if (vlan || qos) {
+ err = igb_vlvf_set(adapter, vlan, !!vlan, vf);
+ if (err)
+ goto out;
+ igb_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
+ igb_set_vmolr(adapter, vf, !vlan);
+ adapter->vf_data[vf].pf_vlan = vlan;
+ adapter->vf_data[vf].pf_qos = qos;
+ dev_info(&adapter->pdev->dev,
+ "Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
+ if (test_bit(__IGB_DOWN, &adapter->state)) {
+ dev_warn(&adapter->pdev->dev,
+ "The VF VLAN has been set,"
+ " but the PF device is not up.\n");
+ dev_warn(&adapter->pdev->dev,
+ "Bring the PF device up before"
+ " attempting to use the VF device.\n");
+ }
+ } else {
+ igb_vlvf_set(adapter, adapter->vf_data[vf].pf_vlan,
+ false, vf);
+ igb_set_vmvir(adapter, vlan, vf);
+ igb_set_vmolr(adapter, vf, true);
+ adapter->vf_data[vf].pf_vlan = 0;
+ adapter->vf_data[vf].pf_qos = 0;
+ }
+out:
+ return err;
}
static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
@@ -4512,15 +4585,21 @@ static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
{
- /* clear all flags */
- adapter->vf_data[vf].flags = 0;
+ /* clear flags */
+ adapter->vf_data[vf].flags &= ~(IGB_VF_FLAG_PF_SET_MAC);
adapter->vf_data[vf].last_nack = jiffies;
/* reset offloads to defaults */
- igb_set_vmolr(adapter, vf);
+ igb_set_vmolr(adapter, vf, true);
/* reset vlans for device */
igb_clear_vf_vfta(adapter, vf);
+ if (adapter->vf_data[vf].pf_vlan)
+ igb_ndo_set_vf_vlan(adapter->netdev, vf,
+ adapter->vf_data[vf].pf_vlan,
+ adapter->vf_data[vf].pf_qos);
+ else
+ igb_clear_vf_vfta(adapter, vf);
/* reset multicast table array for vf */
adapter->vf_data[vf].num_vf_mc_hashes = 0;
@@ -4534,7 +4613,8 @@ static void igb_vf_reset_event(struct igb_adapter *adapter, u32 vf)
unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses;
/* generate a new mac address as we were hotplug removed/added */
- random_ether_addr(vf_mac);
+ if (!(adapter->vf_data[vf].flags & IGB_VF_FLAG_PF_SET_MAC))
+ random_ether_addr(vf_mac);
/* process remaining reset events */
igb_vf_reset(adapter, vf);
@@ -4647,7 +4727,10 @@ static void igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
retval = igb_set_vf_rlpml(adapter, msgbuf[1], vf);
break;
case E1000_VF_SET_VLAN:
- retval = igb_set_vf_vlan(adapter, msgbuf, vf);
+ if (adapter->vf_data[vf].pf_vlan)
+ retval = -1;
+ else
+ retval = igb_set_vf_vlan(adapter, msgbuf, vf);
break;
default:
dev_err(&pdev->dev, "Unhandled Msg %08x\n", msgbuf[0]);
@@ -4728,6 +4811,9 @@ static irqreturn_t igb_intr_msi(int irq, void *data)
igb_write_itr(q_vector);
+ if (icr & E1000_ICR_DRSTA)
+ schedule_work(&adapter->reset_task);
+
if (icr & E1000_ICR_DOUTSYNC) {
/* HW is reporting DMA is out of sync */
adapter->stats.doosync++;
@@ -4767,6 +4853,9 @@ static irqreturn_t igb_intr(int irq, void *data)
if (!(icr & E1000_ICR_INT_ASSERTED))
return IRQ_NONE;
+ if (icr & E1000_ICR_DRSTA)
+ schedule_work(&adapter->reset_task);
+
if (icr & E1000_ICR_DOUTSYNC) {
/* HW is reporting DMA is out of sync */
adapter->stats.doosync++;
@@ -4930,7 +5019,7 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
if (skb) {
unsigned int segs, bytecount;
/* gso_segs is currently only valid for tcp */
- segs = skb_shinfo(skb)->gso_segs ?: 1;
+ segs = buffer_info->gso_segs;
/* multiply data chunks by size of headers */
bytecount = ((segs - 1) * skb_headlen(skb)) +
skb->len;
@@ -5748,7 +5837,9 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake)
*enable_wake = wufc || adapter->en_mng_pt;
if (!*enable_wake)
- igb_shutdown_serdes_link_82575(hw);
+ igb_power_down_link(adapter);
+ else
+ igb_power_up_link(adapter);
/* Release control of h/w to f/w. If f/w is AMT enabled, this
* would have already happened in close and is redundant. */
@@ -5788,6 +5879,7 @@ static int igb_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
+ pci_save_state(pdev);
err = pci_enable_device_mem(pdev);
if (err) {
@@ -5805,8 +5897,6 @@ static int igb_resume(struct pci_dev *pdev)
return -ENOMEM;
}
- /* e1000_power_up_phy(adapter); */
-
igb_reset(adapter);
/* let the f/w know that the h/w is now under the control of the
@@ -5915,6 +6005,7 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev)
} else {
pci_set_master(pdev);
pci_restore_state(pdev);
+ pci_save_state(pdev);
pci_enable_wake(pdev, PCI_D3hot, 0);
pci_enable_wake(pdev, PCI_D3cold, 0);
@@ -6003,6 +6094,43 @@ static int igb_set_vf_mac(struct igb_adapter *adapter,
return 0;
}
+static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ if (!is_valid_ether_addr(mac) || (vf >= adapter->vfs_allocated_count))
+ return -EINVAL;
+ adapter->vf_data[vf].flags |= IGB_VF_FLAG_PF_SET_MAC;
+ dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n", mac, vf);
+ dev_info(&adapter->pdev->dev, "Reload the VF driver to make this"
+ " change effective.");
+ if (test_bit(__IGB_DOWN, &adapter->state)) {
+ dev_warn(&adapter->pdev->dev, "The VF MAC address has been set,"
+ " but the PF device is not up.\n");
+ dev_warn(&adapter->pdev->dev, "Bring the PF device up before"
+ " attempting to use the VF device.\n");
+ }
+ return igb_set_vf_mac(adapter, vf, mac);
+}
+
+static int igb_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate)
+{
+ return -EOPNOTSUPP;
+}
+
+static int igb_ndo_get_vf_config(struct net_device *netdev,
+ int vf, struct ifla_vf_info *ivi)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ if (vf >= adapter->vfs_allocated_count)
+ return -EINVAL;
+ ivi->vf = vf;
+ memcpy(&ivi->mac, adapter->vf_data[vf].vf_mac_addresses, ETH_ALEN);
+ ivi->tx_rate = 0;
+ ivi->vlan = adapter->vf_data[vf].pf_vlan;
+ ivi->qos = adapter->vf_data[vf].pf_qos;
+ return 0;
+}
+
static void igb_vmm_control(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
index 0dbd0320023a..a77afd8a14bb 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/igbvf/netdev.c
@@ -1403,8 +1403,8 @@ static void igbvf_set_multi(struct net_device *netdev)
u8 *mta_list = NULL;
int i;
- if (netdev->mc_count) {
- mta_list = kmalloc(netdev->mc_count * 6, GFP_ATOMIC);
+ if (!netdev_mc_empty(netdev)) {
+ mta_list = kmalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC);
if (!mta_list) {
dev_err(&adapter->pdev->dev,
"failed to allocate multicast filter list\n");
@@ -1413,15 +1413,9 @@ static void igbvf_set_multi(struct net_device *netdev)
}
/* prepare a packed array of only addresses. */
- mc_ptr = netdev->mc_list;
-
- for (i = 0; i < netdev->mc_count; i++) {
- if (!mc_ptr)
- break;
- memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr,
- ETH_ALEN);
- mc_ptr = mc_ptr->next;
- }
+ i = 0;
+ netdev_for_each_mc_addr(mc_ptr, netdev)
+ memcpy(mta_list + (i++ * ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
hw->mac.ops.update_mc_addr_list(hw, mta_list, i, 0, 0);
kfree(mta_list);
@@ -1963,7 +1957,7 @@ static int igbvf_tso(struct igbvf_adapter *adapter,
iph->daddr, 0,
IPPROTO_TCP,
0);
- } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+ } else if (skb_is_gso_v6(skb)) {
ipv6_hdr(skb)->payload_len = 0;
tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr,
@@ -2117,6 +2111,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
/* set time_stamp *before* dma to help avoid a possible race */
buffer_info->time_stamp = jiffies;
buffer_info->next_to_watch = i;
+ buffer_info->mapped_as_page = false;
buffer_info->dma = pci_map_single(pdev, skb->data, len,
PCI_DMA_TODEVICE);
if (pci_dma_mapping_error(pdev, buffer_info->dma))
@@ -2126,6 +2121,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
struct skb_frag_struct *frag;
+ count++;
i++;
if (i == tx_ring->count)
i = 0;
@@ -2146,7 +2142,6 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
PCI_DMA_TODEVICE);
if (pci_dma_mapping_error(pdev, buffer_info->dma))
goto dma_error;
- count++;
}
tx_ring->buffer_info[i].skb = skb;
@@ -2163,14 +2158,14 @@ dma_error:
buffer_info->length = 0;
buffer_info->next_to_watch = 0;
buffer_info->mapped_as_page = false;
- count--;
+ if (count)
+ count--;
/* clear timestamp and dma mappings for remaining portion of packet */
- while (count >= 0) {
- count--;
- i--;
- if (i < 0)
+ while (count--) {
+ if (i==0)
i += tx_ring->count;
+ i--;
buffer_info = &tx_ring->buffer_info[i];
igbvf_put_txbuf(adapter, buffer_info);
}
@@ -2608,11 +2603,7 @@ static void igbvf_print_device_info(struct igbvf_adapter *adapter)
struct pci_dev *pdev = adapter->pdev;
dev_info(&pdev->dev, "Intel(R) 82576 Virtual Function\n");
- dev_info(&pdev->dev, "Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
- /* MAC address */
- netdev->dev_addr[0], netdev->dev_addr[1],
- netdev->dev_addr[2], netdev->dev_addr[3],
- netdev->dev_addr[4], netdev->dev_addr[5]);
+ dev_info(&pdev->dev, "Address: %pM\n", netdev->dev_addr);
dev_info(&pdev->dev, "MAC: %d\n", hw->mac.type);
}
@@ -2778,11 +2769,8 @@ static int __devinit igbvf_probe(struct pci_dev *pdev,
memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
if (!is_valid_ether_addr(netdev->perm_addr)) {
- dev_err(&pdev->dev, "Invalid MAC Address: "
- "%02x:%02x:%02x:%02x:%02x:%02x\n",
- netdev->dev_addr[0], netdev->dev_addr[1],
- netdev->dev_addr[2], netdev->dev_addr[3],
- netdev->dev_addr[4], netdev->dev_addr[5]);
+ dev_err(&pdev->dev, "Invalid MAC Address: %pM\n",
+ netdev->dev_addr);
err = -EIO;
goto err_hw_init;
}
@@ -2884,7 +2872,7 @@ static struct pci_error_handlers igbvf_err_handler = {
.resume = igbvf_io_resume,
};
-static struct pci_device_id igbvf_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(igbvf_pci_tbl) = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_VF), board_vf },
{ } /* terminate list */
};
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index 8ec15ab8c8c2..70871b9b045a 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -1383,7 +1383,7 @@ static void __devexit ioc3_remove_one (struct pci_dev *pdev)
*/
}
-static struct pci_device_id ioc3_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(ioc3_pci_tbl) = {
{ PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID },
{ 0 }
};
@@ -1664,11 +1664,10 @@ static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static void ioc3_set_multicast_list(struct net_device *dev)
{
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
struct ioc3_private *ip = netdev_priv(dev);
struct ioc3 *ioc3 = ip->regs;
u64 ehar = 0;
- int i;
netif_stop_queue(dev); /* Lock out others. */
@@ -1681,16 +1680,16 @@ static void ioc3_set_multicast_list(struct net_device *dev)
ioc3_w_emcr(ip->emcr); /* Clear promiscuous. */
(void) ioc3_r_emcr();
- if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+ if ((dev->flags & IFF_ALLMULTI) ||
+ (netdev_mc_count(dev) > 64)) {
/* Too many for hashing to make sense or we want all
multicast packets anyway, so skip computing all the
hashes and just accept all packets. */
ip->ehar_h = 0xffffffff;
ip->ehar_l = 0xffffffff;
} else {
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
char *addr = dmi->dmi_addr;
- dmi = dmi->next;
if (!(*addr & 1))
continue;
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
index ba8d246d05a0..150415e83f61 100644
--- a/drivers/net/ipg.c
+++ b/drivers/net/ipg.c
@@ -88,17 +88,15 @@ static const char *ipg_brand_name[] = {
"Sundance Technology ST2021 based NIC",
"Tamarack Microelectronics TC9020/9021 based NIC",
"Tamarack Microelectronics TC9020/9021 based NIC",
- "D-Link NIC",
"D-Link NIC IP1000A"
};
-static struct pci_device_id ipg_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(ipg_pci_tbl) = {
{ PCI_VDEVICE(SUNDANCE, 0x1023), 0 },
{ PCI_VDEVICE(SUNDANCE, 0x2021), 1 },
{ PCI_VDEVICE(SUNDANCE, 0x1021), 2 },
{ PCI_VDEVICE(DLINK, 0x9021), 3 },
- { PCI_VDEVICE(DLINK, 0x4000), 4 },
- { PCI_VDEVICE(DLINK, 0x4020), 5 },
+ { PCI_VDEVICE(DLINK, 0x4020), 4 },
{ 0, }
};
@@ -585,11 +583,11 @@ static void ipg_nic_set_multicast_list(struct net_device *dev)
receivemode = IPG_RM_RECEIVEALLFRAMES;
} else if ((dev->flags & IFF_ALLMULTI) ||
((dev->flags & IFF_MULTICAST) &&
- (dev->mc_count > IPG_MULTICAST_HASHTABLE_SIZE))) {
+ (netdev_mc_count(dev) > IPG_MULTICAST_HASHTABLE_SIZE))) {
/* NIC to be configured to receive all multicast
* frames. */
receivemode |= IPG_RM_RECEIVEMULTICAST;
- } else if ((dev->flags & IFF_MULTICAST) && (dev->mc_count > 0)) {
+ } else if ((dev->flags & IFF_MULTICAST) && !netdev_mc_empty(dev)) {
/* NIC to be configured to receive selected
* multicast addresses. */
receivemode |= IPG_RM_RECEIVEMULTICASTHASH;
@@ -610,8 +608,7 @@ static void ipg_nic_set_multicast_list(struct net_device *dev)
hashtable[1] = 0x00000000;
/* Cycle through all multicast addresses to filter. */
- for (mc_list_ptr = dev->mc_list;
- mc_list_ptr != NULL; mc_list_ptr = mc_list_ptr->next) {
+ netdev_for_each_mc_addr(mc_list_ptr, dev) {
/* Calculate CRC result for each multicast address. */
hashindex = crc32_le(0xffffffff, mc_list_ptr->dmi_addr,
ETH_ALEN);
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index f76384221422..af10e97345ce 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -64,6 +64,16 @@ endchoice
comment "Dongle support"
+config SH_SIR
+ tristate "SuperH SIR on UART"
+ depends on IRDA && SUPERH && \
+ (CPU_SUBTYPE_SH7722 || CPU_SUBTYPE_SH7723 || \
+ CPU_SUBTYPE_SH7724)
+ default n
+ help
+ Say Y here if your want to enable SIR function on SuperH UART
+ devices.
+
config DONGLE
bool "Serial dongle support"
depends on IRTTY_SIR
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index d82e1e3bd8c8..e030d47e2793 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_AU1000_FIR) += au1k_ir.o
# SIR drivers
obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o
obj-$(CONFIG_BFIN_SIR) += bfin_sir.o
+obj-$(CONFIG_SH_SIR) += sh_sir.o
# dongle drivers for SIR drivers
obj-$(CONFIG_ESI_DONGLE) += esi-sir.o
obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index 9b2eebdbb25b..b5cbd39d0685 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -36,6 +36,7 @@
#include <asm/pb1000.h>
#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
#include <asm/db1x00.h>
+#include <asm/mach-db1x00/bcsr.h>
#else
#error au1k_ir: unsupported board
#endif
@@ -66,10 +67,6 @@ static char version[] __devinitdata =
#define RUN_AT(x) (jiffies + (x))
-#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
-static BCSR * const bcsr = (BCSR *)0xAE000000;
-#endif
-
static DEFINE_SPINLOCK(ir_lock);
/*
@@ -282,9 +279,8 @@ static int au1k_irda_net_init(struct net_device *dev)
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
/* power on */
- bcsr->resets &= ~BCSR_RESETS_IRDA_MODE_MASK;
- bcsr->resets |= BCSR_RESETS_IRDA_MODE_FULL;
- au_sync();
+ bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK,
+ BCSR_RESETS_IRDA_MODE_FULL);
#endif
return 0;
@@ -720,14 +716,14 @@ au1k_irda_set_speed(struct net_device *dev, int speed)
if (speed == 4000000) {
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
- bcsr->resets |= BCSR_RESETS_FIR_SEL;
+ bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_FIR_SEL);
#else /* Pb1000 and Pb1100 */
writel(1<<13, CPLD_AUX1);
#endif
}
else {
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
- bcsr->resets &= ~BCSR_RESETS_FIR_SEL;
+ bcsr_mod(BCSR_RESETS, BCSR_RESETS_FIR_SEL, 0);
#else /* Pb1000 and Pb1100 */
writel(readl(CPLD_AUX1) & ~(1<<13), CPLD_AUX1);
#endif
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 2d7b5c1d5572..b7e6625ca75e 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -184,7 +184,7 @@
#define CONFIG0H_DMA_ON_NORX CONFIG0H_DMA_OFF| OBOE_CONFIG0H_ENDMAC
#define CONFIG0H_DMA_ON CONFIG0H_DMA_ON_NORX | OBOE_CONFIG0H_ENRX
-static struct pci_device_id toshoboe_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(toshoboe_pci_tbl) = {
{ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIRD01, PCI_ANY_ID, PCI_ANY_ID, },
{ } /* Terminating entry */
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index e8e33bb9d876..2c9b3af16612 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1651,6 +1651,8 @@ static int irda_usb_probe(struct usb_interface *intf,
self->rx_urb = kcalloc(self->max_rx_urb, sizeof(struct urb *),
GFP_KERNEL);
+ if (!self->rx_urb)
+ goto err_free_net;
for (i = 0; i < self->max_rx_urb; i++) {
self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
@@ -1783,6 +1785,8 @@ err_out_2:
err_out_1:
for (i = 0; i < self->max_rx_urb; i++)
usb_free_urb(self->rx_urb[i]);
+ kfree(self->rx_urb);
+err_free_net:
free_netdev(net);
err_out:
return ret;
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index c412e8026173..1dcdce0631aa 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -331,7 +331,7 @@ static int sa1100_irda_resume(struct platform_device *pdev)
* If we missed a speed change, initialise at the new speed
* directly. It is debatable whether this is actually
* required, but in the interests of continuing from where
- * we left off it is desireable. The converse argument is
+ * we left off it is desirable. The converse argument is
* that we should re-negotiate at 9600 baud again.
*/
if (si->newspeed) {
diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c
new file mode 100644
index 000000000000..d7c983dc91ad
--- /dev/null
+++ b/drivers/net/irda/sh_sir.c
@@ -0,0 +1,823 @@
+/*
+ * SuperH IrDA Driver
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on bfin_sir.c
+ * Copyright 2006-2009 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/irda_device.h>
+#include <asm/clock.h>
+
+#define DRIVER_NAME "sh_sir"
+
+#define RX_PHASE (1 << 0)
+#define TX_PHASE (1 << 1)
+#define TX_COMP_PHASE (1 << 2) /* tx complete */
+#define NONE_PHASE (1 << 31)
+
+#define IRIF_RINTCLR 0x0016 /* DMA rx interrupt source clear */
+#define IRIF_TINTCLR 0x0018 /* DMA tx interrupt source clear */
+#define IRIF_SIR0 0x0020 /* IrDA-SIR10 control */
+#define IRIF_SIR1 0x0022 /* IrDA-SIR10 baudrate error correction */
+#define IRIF_SIR2 0x0024 /* IrDA-SIR10 baudrate count */
+#define IRIF_SIR3 0x0026 /* IrDA-SIR10 status */
+#define IRIF_SIR_FRM 0x0028 /* Hardware frame processing set */
+#define IRIF_SIR_EOF 0x002A /* EOF value */
+#define IRIF_SIR_FLG 0x002C /* Flag clear */
+#define IRIF_UART_STS2 0x002E /* UART status 2 */
+#define IRIF_UART0 0x0030 /* UART control */
+#define IRIF_UART1 0x0032 /* UART status */
+#define IRIF_UART2 0x0034 /* UART mode */
+#define IRIF_UART3 0x0036 /* UART transmit data */
+#define IRIF_UART4 0x0038 /* UART receive data */
+#define IRIF_UART5 0x003A /* UART interrupt mask */
+#define IRIF_UART6 0x003C /* UART baud rate error correction */
+#define IRIF_UART7 0x003E /* UART baud rate count set */
+#define IRIF_CRC0 0x0040 /* CRC engine control */
+#define IRIF_CRC1 0x0042 /* CRC engine input data */
+#define IRIF_CRC2 0x0044 /* CRC engine calculation */
+#define IRIF_CRC3 0x0046 /* CRC engine output data 1 */
+#define IRIF_CRC4 0x0048 /* CRC engine output data 2 */
+
+/* IRIF_SIR0 */
+#define IRTPW (1 << 1) /* transmit pulse width select */
+#define IRERRC (1 << 0) /* Clear receive pulse width error */
+
+/* IRIF_SIR3 */
+#define IRERR (1 << 0) /* received pulse width Error */
+
+/* IRIF_SIR_FRM */
+#define EOFD (1 << 9) /* EOF detection flag */
+#define FRER (1 << 8) /* Frame Error bit */
+#define FRP (1 << 0) /* Frame processing set */
+
+/* IRIF_UART_STS2 */
+#define IRSME (1 << 6) /* Receive Sum Error flag */
+#define IROVE (1 << 5) /* Receive Overrun Error flag */
+#define IRFRE (1 << 4) /* Receive Framing Error flag */
+#define IRPRE (1 << 3) /* Receive Parity Error flag */
+
+/* IRIF_UART0_*/
+#define TBEC (1 << 2) /* Transmit Data Clear */
+#define RIE (1 << 1) /* Receive Enable */
+#define TIE (1 << 0) /* Transmit Enable */
+
+/* IRIF_UART1 */
+#define URSME (1 << 6) /* Receive Sum Error Flag */
+#define UROVE (1 << 5) /* Receive Overrun Error Flag */
+#define URFRE (1 << 4) /* Receive Framing Error Flag */
+#define URPRE (1 << 3) /* Receive Parity Error Flag */
+#define RBF (1 << 2) /* Receive Buffer Full Flag */
+#define TSBE (1 << 1) /* Transmit Shift Buffer Empty Flag */
+#define TBE (1 << 0) /* Transmit Buffer Empty flag */
+#define TBCOMP (TSBE | TBE)
+
+/* IRIF_UART5 */
+#define RSEIM (1 << 6) /* Receive Sum Error Flag IRQ Mask */
+#define RBFIM (1 << 2) /* Receive Buffer Full Flag IRQ Mask */
+#define TSBEIM (1 << 1) /* Transmit Shift Buffer Empty Flag IRQ Mask */
+#define TBEIM (1 << 0) /* Transmit Buffer Empty Flag IRQ Mask */
+#define RX_MASK (RSEIM | RBFIM)
+
+/* IRIF_CRC0 */
+#define CRC_RST (1 << 15) /* CRC Engine Reset */
+#define CRC_CT_MASK 0x0FFF
+
+/************************************************************************
+
+
+ structure
+
+
+************************************************************************/
+struct sh_sir_self {
+ void __iomem *membase;
+ unsigned int irq;
+ struct clk *clk;
+
+ struct net_device *ndev;
+
+ struct irlap_cb *irlap;
+ struct qos_info qos;
+
+ iobuff_t tx_buff;
+ iobuff_t rx_buff;
+};
+
+/************************************************************************
+
+
+ common function
+
+
+************************************************************************/
+static void sh_sir_write(struct sh_sir_self *self, u32 offset, u16 data)
+{
+ iowrite16(data, self->membase + offset);
+}
+
+static u16 sh_sir_read(struct sh_sir_self *self, u32 offset)
+{
+ return ioread16(self->membase + offset);
+}
+
+static void sh_sir_update_bits(struct sh_sir_self *self, u32 offset,
+ u16 mask, u16 data)
+{
+ u16 old, new;
+
+ old = sh_sir_read(self, offset);
+ new = (old & ~mask) | data;
+ if (old != new)
+ sh_sir_write(self, offset, new);
+}
+
+/************************************************************************
+
+
+ CRC function
+
+
+************************************************************************/
+static void sh_sir_crc_reset(struct sh_sir_self *self)
+{
+ sh_sir_write(self, IRIF_CRC0, CRC_RST);
+}
+
+static void sh_sir_crc_add(struct sh_sir_self *self, u8 data)
+{
+ sh_sir_write(self, IRIF_CRC1, (u16)data);
+}
+
+static u16 sh_sir_crc_cnt(struct sh_sir_self *self)
+{
+ return CRC_CT_MASK & sh_sir_read(self, IRIF_CRC0);
+}
+
+static u16 sh_sir_crc_out(struct sh_sir_self *self)
+{
+ return sh_sir_read(self, IRIF_CRC4);
+}
+
+static int sh_sir_crc_init(struct sh_sir_self *self)
+{
+ struct device *dev = &self->ndev->dev;
+ int ret = -EIO;
+ u16 val;
+
+ sh_sir_crc_reset(self);
+
+ sh_sir_crc_add(self, 0xCC);
+ sh_sir_crc_add(self, 0xF5);
+ sh_sir_crc_add(self, 0xF1);
+ sh_sir_crc_add(self, 0xA7);
+
+ val = sh_sir_crc_cnt(self);
+ if (4 != val) {
+ dev_err(dev, "CRC count error %x\n", val);
+ goto crc_init_out;
+ }
+
+ val = sh_sir_crc_out(self);
+ if (0x51DF != val) {
+ dev_err(dev, "CRC result error%x\n", val);
+ goto crc_init_out;
+ }
+
+ ret = 0;
+
+crc_init_out:
+
+ sh_sir_crc_reset(self);
+ return ret;
+}
+
+/************************************************************************
+
+
+ baud rate functions
+
+
+************************************************************************/
+#define SCLK_BASE 1843200 /* 1.8432MHz */
+
+static u32 sh_sir_find_sclk(struct clk *irda_clk)
+{
+ struct cpufreq_frequency_table *freq_table = irda_clk->freq_table;
+ struct clk *pclk = clk_get(NULL, "peripheral_clk");
+ u32 limit, min = 0xffffffff, tmp;
+ int i, index = 0;
+
+ limit = clk_get_rate(pclk);
+ clk_put(pclk);
+
+ /* IrDA can not set over peripheral_clk */
+ for (i = 0;
+ freq_table[i].frequency != CPUFREQ_TABLE_END;
+ i++) {
+ u32 freq = freq_table[i].frequency;
+
+ if (freq == CPUFREQ_ENTRY_INVALID)
+ continue;
+
+ /* IrDA should not over peripheral_clk */
+ if (freq > limit)
+ continue;
+
+ tmp = freq % SCLK_BASE;
+ if (tmp < min) {
+ min = tmp;
+ index = i;
+ }
+ }
+
+ return freq_table[index].frequency;
+}
+
+#define ERR_ROUNDING(a) ((a + 5000) / 10000)
+static int sh_sir_set_baudrate(struct sh_sir_self *self, u32 baudrate)
+{
+ struct clk *clk;
+ struct device *dev = &self->ndev->dev;
+ u32 rate;
+ u16 uabca, uabc;
+ u16 irbca, irbc;
+ u32 min, rerr, tmp;
+ int i;
+
+ /* Baud Rate Error Correction x 10000 */
+ u32 rate_err_array[] = {
+ 0000, 0625, 1250, 1875,
+ 2500, 3125, 3750, 4375,
+ 5000, 5625, 6250, 6875,
+ 7500, 8125, 8750, 9375,
+ };
+
+ /*
+ * FIXME
+ *
+ * it support 9600 only now
+ */
+ switch (baudrate) {
+ case 9600:
+ break;
+ default:
+ dev_err(dev, "un-supported baudrate %d\n", baudrate);
+ return -EIO;
+ }
+
+ clk = clk_get(NULL, "irda_clk");
+ if (!clk) {
+ dev_err(dev, "can not get irda_clk\n");
+ return -EIO;
+ }
+
+ clk_set_rate(clk, sh_sir_find_sclk(clk));
+ rate = clk_get_rate(clk);
+ clk_put(clk);
+
+ dev_dbg(dev, "selected sclk = %d\n", rate);
+
+ /*
+ * CALCULATION
+ *
+ * 1843200 = system rate / (irbca + (irbc + 1))
+ */
+
+ irbc = rate / SCLK_BASE;
+
+ tmp = rate - (SCLK_BASE * irbc);
+ tmp *= 10000;
+
+ rerr = tmp / SCLK_BASE;
+
+ min = 0xffffffff;
+ irbca = 0;
+ for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) {
+ tmp = abs(rate_err_array[i] - rerr);
+ if (min > tmp) {
+ min = tmp;
+ irbca = i;
+ }
+ }
+
+ tmp = rate / (irbc + ERR_ROUNDING(rate_err_array[irbca]));
+ if ((SCLK_BASE / 100) < abs(tmp - SCLK_BASE))
+ dev_warn(dev, "IrDA freq error margin over %d\n", tmp);
+
+ dev_dbg(dev, "target = %d, result = %d, infrared = %d.%d\n",
+ SCLK_BASE, tmp, irbc, rate_err_array[irbca]);
+
+ irbca = (irbca & 0xF) << 4;
+ irbc = (irbc - 1) & 0xF;
+
+ if (!irbc) {
+ dev_err(dev, "sh_sir can not set 0 in IRIF_SIR2\n");
+ return -EIO;
+ }
+
+ sh_sir_write(self, IRIF_SIR0, IRTPW | IRERRC);
+ sh_sir_write(self, IRIF_SIR1, irbca);
+ sh_sir_write(self, IRIF_SIR2, irbc);
+
+ /*
+ * CALCULATION
+ *
+ * BaudRate[bps] = system rate / (uabca + (uabc + 1) x 16)
+ */
+
+ uabc = rate / baudrate;
+ uabc = (uabc / 16) - 1;
+ uabc = (uabc + 1) * 16;
+
+ tmp = rate - (uabc * baudrate);
+ tmp *= 10000;
+
+ rerr = tmp / baudrate;
+
+ min = 0xffffffff;
+ uabca = 0;
+ for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) {
+ tmp = abs(rate_err_array[i] - rerr);
+ if (min > tmp) {
+ min = tmp;
+ uabca = i;
+ }
+ }
+
+ tmp = rate / (uabc + ERR_ROUNDING(rate_err_array[uabca]));
+ if ((baudrate / 100) < abs(tmp - baudrate))
+ dev_warn(dev, "UART freq error margin over %d\n", tmp);
+
+ dev_dbg(dev, "target = %d, result = %d, uart = %d.%d\n",
+ baudrate, tmp,
+ uabc, rate_err_array[uabca]);
+
+ uabca = (uabca & 0xF) << 4;
+ uabc = (uabc / 16) - 1;
+
+ sh_sir_write(self, IRIF_UART6, uabca);
+ sh_sir_write(self, IRIF_UART7, uabc);
+
+ return 0;
+}
+
+/************************************************************************
+
+
+ iobuf function
+
+
+************************************************************************/
+static int __sh_sir_init_iobuf(iobuff_t *io, int size)
+{
+ io->head = kmalloc(size, GFP_KERNEL);
+ if (!io->head)
+ return -ENOMEM;
+
+ io->truesize = size;
+ io->in_frame = FALSE;
+ io->state = OUTSIDE_FRAME;
+ io->data = io->head;
+
+ return 0;
+}
+
+static void sh_sir_remove_iobuf(struct sh_sir_self *self)
+{
+ kfree(self->rx_buff.head);
+ kfree(self->tx_buff.head);
+
+ self->rx_buff.head = NULL;
+ self->tx_buff.head = NULL;
+}
+
+static int sh_sir_init_iobuf(struct sh_sir_self *self, int rxsize, int txsize)
+{
+ int err = -ENOMEM;
+
+ if (self->rx_buff.head ||
+ self->tx_buff.head) {
+ dev_err(&self->ndev->dev, "iobuff has already existed.");
+ return err;
+ }
+
+ err = __sh_sir_init_iobuf(&self->rx_buff, rxsize);
+ if (err)
+ goto iobuf_err;
+
+ err = __sh_sir_init_iobuf(&self->tx_buff, txsize);
+
+iobuf_err:
+ if (err)
+ sh_sir_remove_iobuf(self);
+
+ return err;
+}
+
+/************************************************************************
+
+
+ status function
+
+
+************************************************************************/
+static void sh_sir_clear_all_err(struct sh_sir_self *self)
+{
+ /* Clear error flag for receive pulse width */
+ sh_sir_update_bits(self, IRIF_SIR0, IRERRC, IRERRC);
+
+ /* Clear frame / EOF error flag */
+ sh_sir_write(self, IRIF_SIR_FLG, 0xffff);
+
+ /* Clear all status error */
+ sh_sir_write(self, IRIF_UART_STS2, 0);
+}
+
+static void sh_sir_set_phase(struct sh_sir_self *self, int phase)
+{
+ u16 uart5 = 0;
+ u16 uart0 = 0;
+
+ switch (phase) {
+ case TX_PHASE:
+ uart5 = TBEIM;
+ uart0 = TBEC | TIE;
+ break;
+ case TX_COMP_PHASE:
+ uart5 = TSBEIM;
+ uart0 = TIE;
+ break;
+ case RX_PHASE:
+ uart5 = RX_MASK;
+ uart0 = RIE;
+ break;
+ default:
+ break;
+ }
+
+ sh_sir_write(self, IRIF_UART5, uart5);
+ sh_sir_write(self, IRIF_UART0, uart0);
+}
+
+static int sh_sir_is_which_phase(struct sh_sir_self *self)
+{
+ u16 val = sh_sir_read(self, IRIF_UART5);
+
+ if (val & TBEIM)
+ return TX_PHASE;
+
+ if (val & TSBEIM)
+ return TX_COMP_PHASE;
+
+ if (val & RX_MASK)
+ return RX_PHASE;
+
+ return NONE_PHASE;
+}
+
+static void sh_sir_tx(struct sh_sir_self *self, int phase)
+{
+ switch (phase) {
+ case TX_PHASE:
+ if (0 >= self->tx_buff.len) {
+ sh_sir_set_phase(self, TX_COMP_PHASE);
+ } else {
+ sh_sir_write(self, IRIF_UART3, self->tx_buff.data[0]);
+ self->tx_buff.len--;
+ self->tx_buff.data++;
+ }
+ break;
+ case TX_COMP_PHASE:
+ sh_sir_set_phase(self, RX_PHASE);
+ netif_wake_queue(self->ndev);
+ break;
+ default:
+ dev_err(&self->ndev->dev, "should not happen\n");
+ break;
+ }
+}
+
+static int sh_sir_read_data(struct sh_sir_self *self)
+{
+ u16 val;
+ int timeout = 1024;
+
+ while (timeout--) {
+ val = sh_sir_read(self, IRIF_UART1);
+
+ /* data get */
+ if (val & RBF) {
+ if (val & (URSME | UROVE | URFRE | URPRE))
+ break;
+
+ return (int)sh_sir_read(self, IRIF_UART4);
+ }
+
+ udelay(1);
+ }
+
+ dev_err(&self->ndev->dev, "UART1 %04x : STATUS %04x\n",
+ val, sh_sir_read(self, IRIF_UART_STS2));
+
+ /* read data register for clear error */
+ sh_sir_read(self, IRIF_UART4);
+
+ return -1;
+}
+
+static void sh_sir_rx(struct sh_sir_self *self)
+{
+ int timeout = 1024;
+ int data;
+
+ while (timeout--) {
+ data = sh_sir_read_data(self);
+ if (data < 0)
+ break;
+
+ async_unwrap_char(self->ndev, &self->ndev->stats,
+ &self->rx_buff, (u8)data);
+ self->ndev->last_rx = jiffies;
+
+ if (EOFD & sh_sir_read(self, IRIF_SIR_FRM))
+ continue;
+
+ break;
+ }
+}
+
+static irqreturn_t sh_sir_irq(int irq, void *dev_id)
+{
+ struct sh_sir_self *self = dev_id;
+ struct device *dev = &self->ndev->dev;
+ int phase = sh_sir_is_which_phase(self);
+
+ switch (phase) {
+ case TX_COMP_PHASE:
+ case TX_PHASE:
+ sh_sir_tx(self, phase);
+ break;
+ case RX_PHASE:
+ if (sh_sir_read(self, IRIF_SIR3))
+ dev_err(dev, "rcv pulse width error occurred\n");
+
+ sh_sir_rx(self);
+ sh_sir_clear_all_err(self);
+ break;
+ default:
+ dev_err(dev, "unknown interrupt\n");
+ }
+
+ return IRQ_HANDLED;
+}
+
+/************************************************************************
+
+
+ net_device_ops function
+
+
+************************************************************************/
+static int sh_sir_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct sh_sir_self *self = netdev_priv(ndev);
+ int speed = irda_get_next_speed(skb);
+
+ if ((0 < speed) &&
+ (9600 != speed)) {
+ dev_err(&ndev->dev, "support 9600 only (%d)\n", speed);
+ return -EIO;
+ }
+
+ netif_stop_queue(ndev);
+
+ self->tx_buff.data = self->tx_buff.head;
+ self->tx_buff.len = 0;
+ if (skb->len)
+ self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
+ self->tx_buff.truesize);
+
+ sh_sir_set_phase(self, TX_PHASE);
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+
+static int sh_sir_ioctl(struct net_device *ndev, struct ifreq *ifreq, int cmd)
+{
+ /*
+ * FIXME
+ *
+ * This function is needed for irda framework.
+ * But nothing to do now
+ */
+ return 0;
+}
+
+static struct net_device_stats *sh_sir_stats(struct net_device *ndev)
+{
+ struct sh_sir_self *self = netdev_priv(ndev);
+
+ return &self->ndev->stats;
+}
+
+static int sh_sir_open(struct net_device *ndev)
+{
+ struct sh_sir_self *self = netdev_priv(ndev);
+ int err;
+
+ clk_enable(self->clk);
+ err = sh_sir_crc_init(self);
+ if (err)
+ goto open_err;
+
+ sh_sir_set_baudrate(self, 9600);
+
+ self->irlap = irlap_open(ndev, &self->qos, DRIVER_NAME);
+ if (!self->irlap)
+ goto open_err;
+
+ /*
+ * Now enable the interrupt then start the queue
+ */
+ sh_sir_update_bits(self, IRIF_SIR_FRM, FRP, FRP);
+ sh_sir_read(self, IRIF_UART1); /* flag clear */
+ sh_sir_read(self, IRIF_UART4); /* flag clear */
+ sh_sir_set_phase(self, RX_PHASE);
+
+ netif_start_queue(ndev);
+
+ dev_info(&self->ndev->dev, "opened\n");
+
+ return 0;
+
+open_err:
+ clk_disable(self->clk);
+
+ return err;
+}
+
+static int sh_sir_stop(struct net_device *ndev)
+{
+ struct sh_sir_self *self = netdev_priv(ndev);
+
+ /* Stop IrLAP */
+ if (self->irlap) {
+ irlap_close(self->irlap);
+ self->irlap = NULL;
+ }
+
+ netif_stop_queue(ndev);
+
+ dev_info(&ndev->dev, "stoped\n");
+
+ return 0;
+}
+
+static const struct net_device_ops sh_sir_ndo = {
+ .ndo_open = sh_sir_open,
+ .ndo_stop = sh_sir_stop,
+ .ndo_start_xmit = sh_sir_hard_xmit,
+ .ndo_do_ioctl = sh_sir_ioctl,
+ .ndo_get_stats = sh_sir_stats,
+};
+
+/************************************************************************
+
+
+ platform_driver function
+
+
+************************************************************************/
+static int __devinit sh_sir_probe(struct platform_device *pdev)
+{
+ struct net_device *ndev;
+ struct sh_sir_self *self;
+ struct resource *res;
+ char clk_name[8];
+ void __iomem *base;
+ unsigned int irq;
+ int err = -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!res || irq < 0) {
+ dev_err(&pdev->dev, "Not enough platform resources.\n");
+ goto exit;
+ }
+
+ ndev = alloc_irdadev(sizeof(*self));
+ if (!ndev)
+ goto exit;
+
+ base = ioremap_nocache(res->start, resource_size(res));
+ if (!base) {
+ err = -ENXIO;
+ dev_err(&pdev->dev, "Unable to ioremap.\n");
+ goto err_mem_1;
+ }
+
+ self = netdev_priv(ndev);
+ err = sh_sir_init_iobuf(self, IRDA_SKB_MAX_MTU, IRDA_SIR_MAX_FRAME);
+ if (err)
+ goto err_mem_2;
+
+ snprintf(clk_name, sizeof(clk_name), "irda%d", pdev->id);
+ self->clk = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(self->clk)) {
+ dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+ goto err_mem_3;
+ }
+
+ irda_init_max_qos_capabilies(&self->qos);
+
+ ndev->netdev_ops = &sh_sir_ndo;
+ ndev->irq = irq;
+
+ self->membase = base;
+ self->ndev = ndev;
+ self->qos.baud_rate.bits &= IR_9600; /* FIXME */
+ self->qos.min_turn_time.bits = 1; /* 10 ms or more */
+
+ irda_qos_bits_to_value(&self->qos);
+
+ err = register_netdev(ndev);
+ if (err)
+ goto err_mem_4;
+
+ platform_set_drvdata(pdev, ndev);
+
+ if (request_irq(irq, sh_sir_irq, IRQF_DISABLED, "sh_sir", self)) {
+ dev_warn(&pdev->dev, "Unable to attach sh_sir interrupt\n");
+ goto err_mem_4;
+ }
+
+ dev_info(&pdev->dev, "SuperH IrDA probed\n");
+
+ goto exit;
+
+err_mem_4:
+ clk_put(self->clk);
+err_mem_3:
+ sh_sir_remove_iobuf(self);
+err_mem_2:
+ iounmap(self->membase);
+err_mem_1:
+ free_netdev(ndev);
+exit:
+ return err;
+}
+
+static int __devexit sh_sir_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct sh_sir_self *self = netdev_priv(ndev);
+
+ if (!self)
+ return 0;
+
+ unregister_netdev(ndev);
+ clk_put(self->clk);
+ sh_sir_remove_iobuf(self);
+ iounmap(self->membase);
+ free_netdev(ndev);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver sh_sir_driver = {
+ .probe = sh_sir_probe,
+ .remove = __devexit_p(sh_sir_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init sh_sir_init(void)
+{
+ return platform_driver_register(&sh_sir_driver);
+}
+
+static void __exit sh_sir_exit(void)
+{
+ platform_driver_unregister(&sh_sir_driver);
+}
+
+module_init(sh_sir_init);
+module_exit(sh_sir_exit);
+
+MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
+MODULE_DESCRIPTION("SuperH IrDA driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index fddb4efd5453..6533c010cf5c 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -121,7 +121,7 @@ static void iodelay(int udelay)
}
}
-static struct pci_device_id via_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(via_pci_tbl) = {
{ PCI_VENDOR_ID_VIA, 0x8231, PCI_ANY_ID, PCI_ANY_ID,0,0,0 },
{ PCI_VENDOR_ID_VIA, 0x3109, PCI_ANY_ID, PCI_ANY_ID,0,0,1 },
{ PCI_VENDOR_ID_VIA, 0x3074, PCI_ANY_ID, PCI_ANY_ID,0,0,2 },
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index bd3c6b5ee76a..209d4bcfaced 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -59,7 +59,7 @@ MODULE_LICENSE("GPL");
static /* const */ char drivername[] = DRIVER_NAME;
-static struct pci_device_id vlsi_irda_table [] = {
+static DEFINE_PCI_DEVICE_TABLE(vlsi_irda_table) = {
{
.class = PCI_CLASS_WIRELESS_IRDA << 8,
.class_mask = PCI_CLASS_SUBCLASS_MASK << 8,
diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
deleted file mode 100644
index 04d0502726c0..000000000000
--- a/drivers/net/isa-skeleton.c
+++ /dev/null
@@ -1,718 +0,0 @@
-/* isa-skeleton.c: A network driver outline for linux.
- *
- * Written 1993-94 by Donald Becker.
- *
- * Copyright 1993 United States Government as represented by the
- * Director, National Security Agency.
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * The author may be reached as becker@scyld.com, or C/O
- * Scyld Computing Corporation
- * 410 Severn Ave., Suite 210
- * Annapolis MD 21403
- *
- * This file is an outline for writing a network device driver for the
- * the Linux operating system.
- *
- * To write (or understand) a driver, have a look at the "loopback.c" file to
- * get a feel of what is going on, and then use the code below as a skeleton
- * for the new driver.
- *
- */
-
-static const char *version =
- "isa-skeleton.c:v1.51 9/24/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-/*
- * Sources:
- * List your sources of programming information to document that
- * the driver is your own creation, and give due credit to others
- * that contributed to the work. Remember that GNU project code
- * cannot use proprietary or trade secret information. Interface
- * definitions are generally considered non-copyrightable to the
- * extent that the same names and structures must be used to be
- * compatible.
- *
- * Finally, keep in mind that the Linux kernel is has an API, not
- * ABI. Proprietary object-code-only distributions are not permitted
- * under the GPL.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-/*
- * The name of the card. Is used for messages and in the requests for
- * io regions, irqs and dma channels
- */
-static const char* cardname = "netcard";
-
-/* First, a few definitions that the brave might change. */
-
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int netcard_portlist[] __initdata =
- { 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0};
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 2
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-/* The number of low I/O ports used by the ethercard. */
-#define NETCARD_IO_EXTENT 32
-
-#define MY_TX_TIMEOUT ((400*HZ)/1000)
-
-/* Information that need to be kept for each board. */
-struct net_local {
- struct net_device_stats stats;
- long open_time; /* Useless example local info. */
-
- /* Tx control lock. This protects the transmit buffer ring
- * state along with the "tx full" state of the driver. This
- * means all netif_queue flow control actions are protected
- * by this lock as well.
- */
- spinlock_t lock;
-};
-
-/* The station (ethernet) address prefix, used for IDing the board. */
-#define SA_ADDR0 0x00
-#define SA_ADDR1 0x42
-#define SA_ADDR2 0x65
-
-/* Index to functions, as function prototypes. */
-
-static int netcard_probe1(struct net_device *dev, int ioaddr);
-static int net_open(struct net_device *dev);
-static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t net_interrupt(int irq, void *dev_id);
-static void net_rx(struct net_device *dev);
-static int net_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void net_tx_timeout(struct net_device *dev);
-
-
-/* Example routines you must write ;->. */
-#define tx_done(dev) 1
-static void hardware_send_packet(short ioaddr, char *buf, int length);
-static void chipset_init(struct net_device *dev, int startp);
-
-/*
- * Check for a network adaptor of this type, and return '0' iff one exists.
- * If dev->base_addr == 0, probe all likely locations.
- * If dev->base_addr == 1, always return failure.
- * If dev->base_addr == 2, allocate space for the device and return success
- * (detachable devices only).
- */
-static int __init do_netcard_probe(struct net_device *dev)
-{
- int i;
- int base_addr = dev->base_addr;
- int irq = dev->irq;
-
- if (base_addr > 0x1ff) /* Check a single specified location. */
- return netcard_probe1(dev, base_addr);
- else if (base_addr != 0) /* Don't probe at all. */
- return -ENXIO;
-
- for (i = 0; netcard_portlist[i]; i++) {
- int ioaddr = netcard_portlist[i];
- if (netcard_probe1(dev, ioaddr) == 0)
- return 0;
- dev->irq = irq;
- }
-
- return -ENODEV;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-#ifdef jumpered_dma
- free_dma(dev->dma);
-#endif
-#ifdef jumpered_interrupts
- free_irq(dev->irq, dev);
-#endif
- release_region(dev->base_addr, NETCARD_IO_EXTENT);
-}
-
-#ifndef MODULE
-struct net_device * __init netcard_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_netcard_probe(dev);
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops netcard_netdev_ops = {
- .ndo_open = net_open,
- .ndo_stop = net_close,
- .ndo_start_xmit = net_send_packet,
- .ndo_get_stats = net_get_stats,
- .ndo_set_multicast_list = set_multicast_list,
- .ndo_tx_timeout = net_tx_timeout,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_change_mtu = eth_change_mtu,
-};
-
-/*
- * This is the real probe routine. Linux has a history of friendly device
- * probes on the ISA bus. A good device probes avoids doing writes, and
- * verifies that the correct device exists and functions.
- */
-static int __init netcard_probe1(struct net_device *dev, int ioaddr)
-{
- struct net_local *np;
- static unsigned version_printed;
- int i;
- int err = -ENODEV;
-
- /* Grab the region so that no one else tries to probe our ioports. */
- if (!request_region(ioaddr, NETCARD_IO_EXTENT, cardname))
- return -EBUSY;
-
- /*
- * For ethernet adaptors the first three octets of the station address
- * contains the manufacturer's unique code. That might be a good probe
- * method. Ideally you would add additional checks.
- */
- if (inb(ioaddr + 0) != SA_ADDR0 ||
- inb(ioaddr + 1) != SA_ADDR1 ||
- inb(ioaddr + 2) != SA_ADDR2)
- goto out;
-
- if (net_debug && version_printed++ == 0)
- printk(KERN_DEBUG "%s", version);
-
- printk(KERN_INFO "%s: %s found at %#3x, ", dev->name, cardname, ioaddr);
-
- /* Fill in the 'dev' fields. */
- dev->base_addr = ioaddr;
-
- /* Retrieve and print the ethernet address. */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = inb(ioaddr + i);
-
- printk("%pM", dev->dev_addr);
-
- err = -EAGAIN;
-#ifdef jumpered_interrupts
- /*
- * If this board has jumpered interrupts, allocate the interrupt
- * vector now. There is no point in waiting since no other device
- * can use the interrupt, and this marks the irq as busy. Jumpered
- * interrupts are typically not reported by the boards, and we must
- * used autoIRQ to find them.
- */
-
- if (dev->irq == -1)
- ; /* Do nothing: a user-level program will set it. */
- else if (dev->irq < 2) { /* "Auto-IRQ" */
- unsigned long irq_mask = probe_irq_on();
- /* Trigger an interrupt here. */
-
- dev->irq = probe_irq_off(irq_mask);
- if (net_debug >= 2)
- printk(" autoirq is %d", dev->irq);
- } else if (dev->irq == 2)
- /*
- * Fixup for users that don't know that IRQ 2 is really
- * IRQ9, or don't know which one to set.
- */
- dev->irq = 9;
-
- {
- int irqval = request_irq(dev->irq, net_interrupt, 0, cardname, dev);
- if (irqval) {
- printk("%s: unable to get IRQ %d (irqval=%d).\n",
- dev->name, dev->irq, irqval);
- goto out;
- }
- }
-#endif /* jumpered interrupt */
-#ifdef jumpered_dma
- /*
- * If we use a jumpered DMA channel, that should be probed for and
- * allocated here as well. See lance.c for an example.
- */
- if (dev->dma == 0) {
- if (request_dma(dev->dma, cardname)) {
- printk("DMA %d allocation failed.\n", dev->dma);
- goto out1;
- } else
- printk(", assigned DMA %d.\n", dev->dma);
- } else {
- short dma_status, new_dma_status;
-
- /* Read the DMA channel status registers. */
- dma_status = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) |
- (inb(DMA2_STAT_REG) & 0xf0);
- /* Trigger a DMA request, perhaps pause a bit. */
- outw(0x1234, ioaddr + 8);
- /* Re-read the DMA status registers. */
- new_dma_status = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) |
- (inb(DMA2_STAT_REG) & 0xf0);
- /*
- * Eliminate the old and floating requests,
- * and DMA4 the cascade.
- */
- new_dma_status ^= dma_status;
- new_dma_status &= ~0x10;
- for (i = 7; i > 0; i--)
- if (test_bit(i, &new_dma_status)) {
- dev->dma = i;
- break;
- }
- if (i <= 0) {
- printk("DMA probe failed.\n");
- goto out1;
- }
- if (request_dma(dev->dma, cardname)) {
- printk("probed DMA %d allocation failed.\n", dev->dma);
- goto out1;
- }
- }
-#endif /* jumpered DMA */
-
- np = netdev_priv(dev);
- spin_lock_init(&np->lock);
-
- dev->netdev_ops = &netcard_netdev_ops;
- dev->watchdog_timeo = MY_TX_TIMEOUT;
-
- err = register_netdev(dev);
- if (err)
- goto out2;
- return 0;
-out2:
-#ifdef jumpered_dma
- free_dma(dev->dma);
-#endif
-out1:
-#ifdef jumpered_interrupts
- free_irq(dev->irq, dev);
-#endif
-out:
- release_region(base_addr, NETCARD_IO_EXTENT);
- return err;
-}
-
-static void net_tx_timeout(struct net_device *dev)
-{
- struct net_local *np = netdev_priv(dev);
-
- printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
- tx_done(dev) ? "IRQ conflict" : "network cable problem");
-
- /* Try to restart the adaptor. */
- chipset_init(dev, 1);
-
- np->stats.tx_errors++;
-
- /* If we have space available to accept new transmit
- * requests, wake up the queueing layer. This would
- * be the case if the chipset_init() call above just
- * flushes out the tx queue and empties it.
- *
- * If instead, the tx queue is retained then the
- * netif_wake_queue() call should be placed in the
- * TX completion interrupt handler of the driver instead
- * of here.
- */
- if (!tx_full(dev))
- netif_wake_queue(dev);
-}
-
-/*
- * Open/initialize the board. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
- */
-static int
-net_open(struct net_device *dev)
-{
- struct net_local *np = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- /*
- * This is used if the interrupt line can turned off (shared).
- * See 3c503.c for an example of selecting the IRQ at config-time.
- */
- if (request_irq(dev->irq, net_interrupt, 0, cardname, dev)) {
- return -EAGAIN;
- }
- /*
- * Always allocate the DMA channel after the IRQ,
- * and clean up on failure.
- */
- if (request_dma(dev->dma, cardname)) {
- free_irq(dev->irq, dev);
- return -EAGAIN;
- }
-
- /* Reset the hardware here. Don't forget to set the station address. */
- chipset_init(dev, 1);
- outb(0x00, ioaddr);
- np->open_time = jiffies;
-
- /* We are now ready to accept transmit requeusts from
- * the queueing layer of the networking.
- */
- netif_start_queue(dev);
-
- return 0;
-}
-
-/* This will only be invoked if your driver is _not_ in XOFF state.
- * What this means is that you need not check it, and that this
- * invariant will hold if you make sure that the netif_*_queue()
- * calls are done at the proper times.
- */
-static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
- struct net_local *np = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
-
- /* If some error occurs while trying to transmit this
- * packet, you should return '1' from this function.
- * In such a case you _may not_ do anything to the
- * SKB, it is still owned by the network queueing
- * layer when an error is returned. This means you
- * may not modify any SKB fields, you may not free
- * the SKB, etc.
- */
-
-#if TX_RING
- /* This is the most common case for modern hardware.
- * The spinlock protects this code from the TX complete
- * hardware interrupt handler. Queue flow control is
- * thus managed under this lock as well.
- */
- unsigned long flags;
- spin_lock_irqsave(&np->lock, flags);
-
- add_to_tx_ring(np, skb, length);
- dev->trans_start = jiffies;
-
- /* If we just used up the very last entry in the
- * TX ring on this device, tell the queueing
- * layer to send no more.
- */
- if (tx_full(dev))
- netif_stop_queue(dev);
-
- /* When the TX completion hw interrupt arrives, this
- * is when the transmit statistics are updated.
- */
-
- spin_unlock_irqrestore(&np->lock, flags);
-#else
- /* This is the case for older hardware which takes
- * a single transmit buffer at a time, and it is
- * just written to the device via PIO.
- *
- * No spin locking is needed since there is no TX complete
- * event. If by chance your card does have a TX complete
- * hardware IRQ then you may need to utilize np->lock here.
- */
- hardware_send_packet(ioaddr, buf, length);
- np->stats.tx_bytes += skb->len;
-
- dev->trans_start = jiffies;
-
- /* You might need to clean up and record Tx statistics here. */
- if (inw(ioaddr) == /*RU*/81)
- np->stats.tx_aborted_errors++;
- dev_kfree_skb (skb);
-#endif
-
- return NETDEV_TX_OK;
-}
-
-#if TX_RING
-/* This handles TX complete events posted by the device
- * via interrupts.
- */
-void net_tx(struct net_device *dev)
-{
- struct net_local *np = netdev_priv(dev);
- int entry;
-
- /* This protects us from concurrent execution of
- * our dev->hard_start_xmit function above.
- */
- spin_lock(&np->lock);
-
- entry = np->tx_old;
- while (tx_entry_is_sent(np, entry)) {
- struct sk_buff *skb = np->skbs[entry];
-
- np->stats.tx_bytes += skb->len;
- dev_kfree_skb_irq (skb);
-
- entry = next_tx_entry(np, entry);
- }
- np->tx_old = entry;
-
- /* If we had stopped the queue due to a "tx full"
- * condition, and space has now been made available,
- * wake up the queue.
- */
- if (netif_queue_stopped(dev) && ! tx_full(dev))
- netif_wake_queue(dev);
-
- spin_unlock(&np->lock);
-}
-#endif
-
-/*
- * The typical workload of the driver:
- * Handle the network interface interrupts.
- */
-static irqreturn_t net_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct net_local *np;
- int ioaddr, status;
- int handled = 0;
-
- ioaddr = dev->base_addr;
-
- np = netdev_priv(dev);
- status = inw(ioaddr + 0);
-
- if (status == 0)
- goto out;
- handled = 1;
-
- if (status & RX_INTR) {
- /* Got a packet(s). */
- net_rx(dev);
- }
-#if TX_RING
- if (status & TX_INTR) {
- /* Transmit complete. */
- net_tx(dev);
- np->stats.tx_packets++;
- netif_wake_queue(dev);
- }
-#endif
- if (status & COUNTERS_INTR) {
- /* Increment the appropriate 'localstats' field. */
- np->stats.tx_window_errors++;
- }
-out:
- return IRQ_RETVAL(handled);
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void
-net_rx(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- int boguscount = 10;
-
- do {
- int status = inw(ioaddr);
- int pkt_len = inw(ioaddr);
-
- if (pkt_len == 0) /* Read all the frames? */
- break; /* Done for now */
-
- if (status & 0x40) { /* There was an error. */
- lp->stats.rx_errors++;
- if (status & 0x20) lp->stats.rx_frame_errors++;
- if (status & 0x10) lp->stats.rx_over_errors++;
- if (status & 0x08) lp->stats.rx_crc_errors++;
- if (status & 0x04) lp->stats.rx_fifo_errors++;
- } else {
- /* Malloc up new buffer. */
- struct sk_buff *skb;
-
- lp->stats.rx_bytes+=pkt_len;
-
- skb = dev_alloc_skb(pkt_len);
- if (skb == NULL) {
- printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
- dev->name);
- lp->stats.rx_dropped++;
- break;
- }
- skb->dev = dev;
-
- /* 'skb->data' points to the start of sk_buff data area. */
- memcpy(skb_put(skb,pkt_len), (void*)dev->rmem_start,
- pkt_len);
- /* or */
- insw(ioaddr, skb->data, (pkt_len + 1) >> 1);
-
- netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
- }
- } while (--boguscount);
-
- return;
-}
-
-/* The inverse routine to net_open(). */
-static int
-net_close(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- lp->open_time = 0;
-
- netif_stop_queue(dev);
-
- /* Flush the Tx and disable Rx here. */
-
- disable_dma(dev->dma);
-
- /* If not IRQ or DMA jumpered, free up the line. */
- outw(0x00, ioaddr+0); /* Release the physical interrupt line. */
-
- free_irq(dev->irq, dev);
- free_dma(dev->dma);
-
- /* Update the statistics here. */
-
- return 0;
-
-}
-
-/*
- * Get the current statistics.
- * This may be called with the card open or closed.
- */
-static struct net_device_stats *net_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- short ioaddr = dev->base_addr;
-
- /* Update the statistics from the device registers. */
- lp->stats.rx_missed_errors = inw(ioaddr+1);
- return &lp->stats;
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- * num_addrs == -1 Promiscuous mode, receive all packets
- * num_addrs == 0 Normal mode, clear multicast list
- * num_addrs > 0 Multicast mode, receive normal and MC packets,
- * and do best-effort filtering.
- */
-static void
-set_multicast_list(struct net_device *dev)
-{
- short ioaddr = dev->base_addr;
- if (dev->flags&IFF_PROMISC)
- {
- /* Enable promiscuous mode */
- outw(MULTICAST|PROMISC, ioaddr);
- }
- else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS)
- {
- /* Disable promiscuous mode, use normal mode. */
- hardware_set_filter(NULL);
-
- outw(MULTICAST, ioaddr);
- }
- else if(dev->mc_count)
- {
- /* Walk the address list, and load the filter */
- hardware_set_filter(dev->mc_list);
-
- outw(MULTICAST, ioaddr);
- }
- else
- outw(0, ioaddr);
-}
-
-#ifdef MODULE
-
-static struct net_device *this_device;
-static int io = 0x300;
-static int irq;
-static int dma;
-static int mem;
-MODULE_LICENSE("GPL");
-
-int init_module(void)
-{
- struct net_device *dev;
- int result;
-
- if (io == 0)
- printk(KERN_WARNING "%s: You shouldn't use auto-probing with insmod!\n",
- cardname);
- dev = alloc_etherdev(sizeof(struct net_local));
- if (!dev)
- return -ENOMEM;
-
- /* Copy the parameters from insmod into the device structure. */
- dev->base_addr = io;
- dev->irq = irq;
- dev->dma = dma;
- dev->mem_start = mem;
- if (do_netcard_probe(dev) == 0) {
- this_device = dev;
- return 0;
- }
- free_netdev(dev);
- return -ENXIO;
-}
-
-void
-cleanup_module(void)
-{
- unregister_netdev(this_device);
- cleanup_card(this_device);
- free_netdev(this_device);
-}
-
-#endif /* MODULE */
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 16c91910d6c1..e6e972d9b7ca 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -384,7 +384,7 @@ static struct attribute *veth_cnx_default_attrs[] = {
NULL
};
-static struct sysfs_ops veth_cnx_sysfs_ops = {
+static const struct sysfs_ops veth_cnx_sysfs_ops = {
.show = veth_cnx_attribute_show
};
@@ -441,7 +441,7 @@ static struct attribute *veth_port_default_attrs[] = {
NULL
};
-static struct sysfs_ops veth_port_sysfs_ops = {
+static const struct sysfs_ops veth_port_sysfs_ops = {
.show = veth_port_attribute_show
};
@@ -958,18 +958,17 @@ static void veth_set_multicast_list(struct net_device *dev)
write_lock_irqsave(&port->mcast_gate, flags);
if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
- (dev->mc_count > VETH_MAX_MCAST)) {
+ (netdev_mc_count(dev) > VETH_MAX_MCAST)) {
port->promiscuous = 1;
} else {
- struct dev_mc_list *dmi = dev->mc_list;
- int i;
+ struct dev_mc_list *dmi;
port->promiscuous = 0;
/* Update table */
port->num_mcast = 0;
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
u8 *addr = dmi->dmi_addr;
u64 xaddr = 0;
@@ -978,7 +977,6 @@ static void veth_set_multicast_list(struct net_device *dev)
port->mcast_addr[port->num_mcast] = xaddr;
port->num_mcast++;
}
- dmi = dmi->next;
}
}
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index 5257ae08b9f9..92d2e71d0c8b 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -75,19 +75,14 @@ struct ixgb_adapter;
#include "ixgb_ee.h"
#include "ixgb_ids.h"
+#define PFX "ixgb: "
+
#ifdef _DEBUG_DRIVER_
-#define IXGB_DBG(args...) printk(KERN_DEBUG "ixgb: " args)
+#define IXGB_DBG(args...) printk(KERN_DEBUG PFX args)
#else
#define IXGB_DBG(args...)
#endif
-#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, \
- __func__ , ## args))
-
-
/* TX/RX descriptor defines */
#define DEFAULT_TXD 256
#define MAX_TXD 4096
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index bcd0f01d5feb..c9fef65cb98b 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -50,7 +50,7 @@ MODULE_PARM_DESC(copybreak,
* { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
* Class, Class Mask, private data (not used) }
*/
-static struct pci_device_id ixgb_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(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,
@@ -238,8 +238,8 @@ ixgb_up(struct ixgb_adapter *adapter)
if (err) {
if (adapter->have_msi)
pci_disable_msi(adapter->pdev);
- DPRINTK(PROBE, ERR,
- "Unable to allocate interrupt Error: %d\n", err);
+ netif_err(adapter, probe, adapter->netdev,
+ "Unable to allocate interrupt Error: %d\n", err);
return err;
}
@@ -310,7 +310,7 @@ ixgb_reset(struct ixgb_adapter *adapter)
ixgb_adapter_stop(hw);
if (!ixgb_init_hw(hw))
- DPRINTK(PROBE, ERR, "ixgb_init_hw failed.\n");
+ netif_err(adapter, probe, adapter->netdev, "ixgb_init_hw failed\n");
/* restore frame size information */
IXGB_WRITE_REG(hw, MFS, hw->max_frame_size << IXGB_MFS_SHIFT);
@@ -447,7 +447,8 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* make sure the EEPROM is good */
if (!ixgb_validate_eeprom_checksum(&adapter->hw)) {
- DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n");
+ netif_err(adapter, probe, adapter->netdev,
+ "The EEPROM Checksum Is Not Valid\n");
err = -EIO;
goto err_eeprom;
}
@@ -456,7 +457,7 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
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");
+ netif_err(adapter, probe, adapter->netdev, "Invalid MAC Address\n");
err = -EIO;
goto err_eeprom;
}
@@ -477,7 +478,8 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
- DPRINTK(PROBE, INFO, "Intel(R) PRO/10GbE Network Connection\n");
+ netif_info(adapter, probe, adapter->netdev,
+ "Intel(R) PRO/10GbE Network Connection\n");
ixgb_check_options(adapter);
/* reset the hardware with the new settings */
@@ -552,14 +554,14 @@ ixgb_sw_init(struct ixgb_adapter *adapter)
hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH;
adapter->rx_buffer_len = hw->max_frame_size + 8; /* + 8 for errata */
- if ((hw->device_id == IXGB_DEVICE_ID_82597EX)
- || (hw->device_id == IXGB_DEVICE_ID_82597EX_CX4)
- || (hw->device_id == IXGB_DEVICE_ID_82597EX_LR)
- || (hw->device_id == IXGB_DEVICE_ID_82597EX_SR))
+ if ((hw->device_id == IXGB_DEVICE_ID_82597EX) ||
+ (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 */
- DPRINTK(PROBE, ERR, "unsupported device id\n");
+ netif_err(adapter, probe, adapter->netdev, "unsupported device id\n");
}
/* enable flow control to be programmed */
@@ -661,8 +663,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");
+ netif_err(adapter, probe, adapter->netdev,
+ "Unable to allocate transmit descriptor ring memory\n");
return -ENOMEM;
}
memset(txdr->buffer_info, 0, size);
@@ -675,8 +677,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");
+ netif_err(adapter, probe, adapter->netdev,
+ "Unable to allocate transmit descriptor memory\n");
return -ENOMEM;
}
memset(txdr->desc, 0, txdr->size);
@@ -750,8 +752,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");
+ netif_err(adapter, probe, adapter->netdev,
+ "Unable to allocate receive descriptor ring\n");
return -ENOMEM;
}
memset(rxdr->buffer_info, 0, size);
@@ -765,8 +767,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");
+ netif_err(adapter, probe, adapter->netdev,
+ "Unable to allocate receive descriptors\n");
return -ENOMEM;
}
memset(rxdr->desc, 0, rxdr->size);
@@ -1077,7 +1079,7 @@ ixgb_set_multi(struct net_device *netdev)
rctl |= IXGB_RCTL_VFE;
}
- if (netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES) {
+ if (netdev_mc_count(netdev) > IXGB_MAX_NUM_MULTICAST_ADDRESSES) {
rctl |= IXGB_RCTL_MPE;
IXGB_WRITE_REG(hw, RCTL, rctl);
} else {
@@ -1086,13 +1088,12 @@ ixgb_set_multi(struct net_device *netdev)
IXGB_WRITE_REG(hw, RCTL, rctl);
- for (i = 0, mc_ptr = netdev->mc_list;
- mc_ptr;
- i++, mc_ptr = mc_ptr->next)
- memcpy(&mta[i * IXGB_ETH_LENGTH_OF_ADDRESS],
+ i = 0;
+ netdev_for_each_mc_addr(mc_ptr, netdev)
+ memcpy(&mta[i++ * IXGB_ETH_LENGTH_OF_ADDRESS],
mc_ptr->dmi_addr, IXGB_ETH_LENGTH_OF_ADDRESS);
- ixgb_mc_addr_list_update(hw, mta, netdev->mc_count, 0);
+ ixgb_mc_addr_list_update(hw, mta, netdev_mc_count(netdev), 0);
}
}
@@ -1363,13 +1364,13 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
dma_error:
dev_err(&pdev->dev, "TX DMA map failed\n");
buffer_info->dma = 0;
- count--;
-
- while (count >= 0) {
+ if (count)
count--;
- i--;
- if (i < 0)
+
+ while (count--) {
+ if (i==0)
i += tx_ring->count;
+ i--;
buffer_info = &tx_ring->buffer_info[i];
ixgb_unmap_and_free_tx_resource(adapter, buffer_info);
}
@@ -1580,7 +1581,8 @@ ixgb_change_mtu(struct net_device *netdev, int new_mtu)
/* MTU < 68 is an error for IPv4 traffic, just don't allow it */
if ((new_mtu < 68) ||
(max_frame > IXGB_MAX_JUMBO_FRAME_SIZE + ENET_FCS_LENGTH)) {
- DPRINTK(PROBE, ERR, "Invalid MTU setting %d\n", new_mtu);
+ netif_err(adapter, probe, adapter->netdev,
+ "Invalid MTU setting %d\n", new_mtu);
return -EINVAL;
}
@@ -1616,7 +1618,7 @@ ixgb_update_stats(struct ixgb_adapter *adapter)
return;
if ((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) ||
- (netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) {
+ (netdev_mc_count(netdev) > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) {
u64 multi = IXGB_READ_REG(&adapter->hw, MPRCL);
u32 bcast_l = IXGB_READ_REG(&adapter->hw, BPRCL);
u32 bcast_h = IXGB_READ_REG(&adapter->hw, BPRCH);
@@ -1854,24 +1856,25 @@ ixgb_clean_tx_irq(struct ixgb_adapter *adapter)
&& !(IXGB_READ_REG(&adapter->hw, STATUS) &
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_err(adapter, drv, adapter->netdev,
+ "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);
}
}
@@ -2269,7 +2272,8 @@ static pci_ers_result_t ixgb_io_slot_reset(struct pci_dev *pdev)
struct ixgb_adapter *adapter = netdev_priv(netdev);
if (pci_enable_device(pdev)) {
- DPRINTK(PROBE, ERR, "Cannot re-enable PCI device after reset.\n");
+ netif_err(adapter, probe, adapter->netdev,
+ "Cannot re-enable PCI device after reset\n");
return PCI_ERS_RESULT_DISCONNECT;
}
@@ -2285,14 +2289,16 @@ static pci_ers_result_t ixgb_io_slot_reset(struct pci_dev *pdev)
/* Make sure the EEPROM is good */
if (!ixgb_validate_eeprom_checksum(&adapter->hw)) {
- DPRINTK(PROBE, ERR, "After reset, the EEPROM checksum is not valid.\n");
+ netif_err(adapter, probe, adapter->netdev,
+ "After reset, the EEPROM checksum is not valid\n");
return PCI_ERS_RESULT_DISCONNECT;
}
ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr);
memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
if (!is_valid_ether_addr(netdev->perm_addr)) {
- DPRINTK(PROBE, ERR, "After reset, invalid MAC address.\n");
+ netif_err(adapter, probe, adapter->netdev,
+ "After reset, invalid MAC address\n");
return PCI_ERS_RESULT_DISCONNECT;
}
diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile
index bfef0ebcba9a..8f81efb49169 100644
--- a/drivers/net/ixgbe/Makefile
+++ b/drivers/net/ixgbe/Makefile
@@ -33,7 +33,8 @@
obj-$(CONFIG_IXGBE) += ixgbe.o
ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
- ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o
+ ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \
+ ixgbe_mbx.o
ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \
ixgbe_dcb_82599.o ixgbe_dcb_nl.o
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index 303e7bd39b67..19e94ee155a2 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -98,6 +98,22 @@
#define IXGBE_MAX_RSC_INT_RATE 162760
+#define IXGBE_MAX_VF_MC_ENTRIES 30
+#define IXGBE_MAX_VF_FUNCTIONS 64
+#define IXGBE_MAX_VFTA_ENTRIES 128
+#define MAX_EMULATION_MAC_ADDRS 16
+#define VMDQ_P(p) ((p) + adapter->num_vfs)
+
+struct vf_data_storage {
+ unsigned char vf_mac_addresses[ETH_ALEN];
+ u16 vf_mc_hashes[IXGBE_MAX_VF_MC_ENTRIES];
+ u16 num_vf_mc_hashes;
+ u16 default_vf_vlan_id;
+ u16 vlans_enabled;
+ bool clear_to_send;
+ int rar;
+};
+
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct ixgbe_tx_buffer {
@@ -159,6 +175,7 @@ struct ixgbe_ring {
struct ixgbe_queue_stats stats;
unsigned long reinit_state;
+ int numa_node;
u64 rsc_count; /* stat for coalesced packets */
u64 rsc_flush; /* stats for flushed packets */
u32 restart_queue; /* track tx queue restarts */
@@ -171,7 +188,7 @@ struct ixgbe_ring {
enum ixgbe_ring_f_enum {
RING_F_NONE = 0,
RING_F_DCB,
- RING_F_VMDQ,
+ RING_F_VMDQ, /* SR-IOV uses the same ring feature */
RING_F_RSS,
RING_F_FDIR,
#ifdef IXGBE_FCOE
@@ -183,7 +200,7 @@ enum ixgbe_ring_f_enum {
#define IXGBE_MAX_DCB_INDICES 8
#define IXGBE_MAX_RSS_INDICES 16
-#define IXGBE_MAX_VMDQ_INDICES 16
+#define IXGBE_MAX_VMDQ_INDICES 64
#define IXGBE_MAX_FDIR_INDICES 64
#ifdef IXGBE_FCOE
#define IXGBE_MAX_FCOE_INDICES 8
@@ -277,7 +294,7 @@ struct ixgbe_adapter {
u16 eitr_high;
/* TX */
- struct ixgbe_ring *tx_ring ____cacheline_aligned_in_smp; /* One per active queue */
+ struct ixgbe_ring *tx_ring[MAX_TX_QUEUES] ____cacheline_aligned_in_smp;
int num_tx_queues;
u32 tx_timeout_count;
bool detect_tx_hung;
@@ -286,8 +303,10 @@ struct ixgbe_adapter {
u64 lsc_int;
/* RX */
- struct ixgbe_ring *rx_ring ____cacheline_aligned_in_smp; /* One per active queue */
+ struct ixgbe_ring *rx_ring[MAX_RX_QUEUES] ____cacheline_aligned_in_smp;
int num_rx_queues;
+ int num_rx_pools; /* == num_rx_queues in 82598 */
+ int num_rx_queues_per_pool; /* 1 if 82598, can be many if 82599 */
u64 hw_csum_rx_error;
u64 hw_rx_no_dma_resources;
u64 non_eop_descs;
@@ -323,13 +342,14 @@ struct ixgbe_adapter {
#define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19)
#define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20)
#define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22)
-#define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23)
-#define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 24)
-#define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 25)
-#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 26)
-#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 27)
-#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 28)
-#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 29)
+#define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 23)
+#define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 24)
+#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 25)
+#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 26)
+#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 27)
+#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 28)
+#define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 29)
+#define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 30)
u32 flags2;
#define IXGBE_FLAG2_RSC_CAPABLE (u32)(1)
@@ -379,6 +399,13 @@ struct ixgbe_adapter {
u64 rsc_total_flush;
u32 wol;
u16 eeprom_version;
+
+ int node;
+
+ /* SR-IOV */
+ DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS);
+ unsigned int num_vfs;
+ struct vf_data_storage *vfinfo;
};
enum ixbge_state_t {
@@ -426,6 +453,10 @@ extern s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc);
extern s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
struct ixgbe_atr_input *input,
u8 queue);
+extern s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
+ struct ixgbe_atr_input *input,
+ struct ixgbe_atr_input_masks *input_masks,
+ u16 soft_id, u8 queue);
extern s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input,
u16 vlan_id);
extern s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input,
@@ -440,6 +471,7 @@ extern s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input,
u16 flex_byte);
extern s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input,
u8 l4type);
+extern void ixgbe_set_rx_mode(struct net_device *netdev);
#ifdef IXGBE_FCOE
extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter);
extern int ixgbe_fso(struct ixgbe_adapter *adapter,
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
index 3103f4165311..35a06b47587b 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -357,12 +357,34 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
u32 fctrl_reg;
u32 rmcs_reg;
u32 reg;
+ u32 link_speed = 0;
+ bool link_up;
#ifdef CONFIG_DCB
if (hw->fc.requested_mode == ixgbe_fc_pfc)
goto out;
#endif /* CONFIG_DCB */
+ /*
+ * On 82598 having Rx FC on causes resets while doing 1G
+ * so if it's on turn it off once we know link_speed. For
+ * more details see 82598 Specification update.
+ */
+ hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
+ if (link_up && link_speed == IXGBE_LINK_SPEED_1GB_FULL) {
+ switch (hw->fc.requested_mode) {
+ case ixgbe_fc_full:
+ hw->fc.requested_mode = ixgbe_fc_tx_pause;
+ break;
+ case ixgbe_fc_rx_pause:
+ hw->fc.requested_mode = ixgbe_fc_none;
+ break;
+ default:
+ /* no change */
+ break;
+ }
+ }
+
/* Negotiate the fc mode to use */
ret_val = ixgbe_fc_autoneg(hw);
if (ret_val)
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
index b49bd6b9feb7..1f30e163bd9c 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ixgbe/ixgbe_82599.c
@@ -31,6 +31,7 @@
#include "ixgbe.h"
#include "ixgbe_phy.h"
+#include "ixgbe_mbx.h"
#define IXGBE_82599_MAX_TX_QUEUES 128
#define IXGBE_82599_MAX_RX_QUEUES 128
@@ -889,7 +890,7 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
{
s32 status = 0;
- u32 ctrl, ctrl_ext;
+ u32 ctrl;
u32 i;
u32 autoc;
u32 autoc2;
@@ -944,15 +945,9 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
status = IXGBE_ERR_RESET_FAILED;
hw_dbg(hw, "Reset polling failed to complete.\n");
}
- /* Clear PF Reset Done bit so PF/VF Mail Ops can work */
- ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
- ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
- IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
msleep(50);
-
-
/*
* Store the original AUTOC/AUTOC2 values if they have not been
* stored off yet. Otherwise restore the stored original
@@ -1095,9 +1090,11 @@ static s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, u32 vind,
bool vlan_on)
{
u32 regindex;
+ u32 vlvf_index;
u32 bitindex;
u32 bits;
u32 first_empty_slot;
+ u32 vt_ctl;
if (vlan > 4095)
return IXGBE_ERR_PARAM;
@@ -1124,76 +1121,84 @@ static s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, u32 vind,
/* Part 2
- * If the vind is set
+ * If VT mode is set
* Either vlan_on
* make sure the vlan is in VLVF
* set the vind bit in the matching VLVFB
* Or !vlan_on
* clear the pool bit and possibly the vind
*/
- if (vind) {
- /* find the vlanid or the first empty slot */
- first_empty_slot = 0;
-
- for (regindex = 1; regindex < IXGBE_VLVF_ENTRIES; regindex++) {
- bits = IXGBE_READ_REG(hw, IXGBE_VLVF(regindex));
- if (!bits && !first_empty_slot)
- first_empty_slot = regindex;
- else if ((bits & 0x0FFF) == vlan)
- break;
- }
+ vt_ctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
+ if (!(vt_ctl & IXGBE_VT_CTL_VT_ENABLE))
+ goto out;
- if (regindex >= IXGBE_VLVF_ENTRIES) {
- if (first_empty_slot)
- regindex = first_empty_slot;
- else {
- hw_dbg(hw, "No space in VLVF.\n");
- goto out;
- }
+ /* find the vlanid or the first empty slot */
+ first_empty_slot = 0;
+
+ for (vlvf_index = 1; vlvf_index < IXGBE_VLVF_ENTRIES; vlvf_index++) {
+ bits = IXGBE_READ_REG(hw, IXGBE_VLVF(vlvf_index));
+ if (!bits && !first_empty_slot)
+ first_empty_slot = vlvf_index;
+ else if ((bits & 0x0FFF) == vlan)
+ break;
+ }
+
+ if (vlvf_index >= IXGBE_VLVF_ENTRIES) {
+ if (first_empty_slot)
+ vlvf_index = first_empty_slot;
+ else {
+ hw_dbg(hw, "No space in VLVF.\n");
+ goto out;
}
+ }
- if (vlan_on) {
- /* set the pool bit */
- if (vind < 32) {
- bits = IXGBE_READ_REG(hw,
- IXGBE_VLVFB(regindex * 2));
- bits |= (1 << vind);
- IXGBE_WRITE_REG(hw,
- IXGBE_VLVFB(regindex * 2), bits);
- } else {
- bits = IXGBE_READ_REG(hw,
- IXGBE_VLVFB((regindex * 2) + 1));
- bits |= (1 << vind);
- IXGBE_WRITE_REG(hw,
- IXGBE_VLVFB((regindex * 2) + 1), bits);
- }
+ if (vlan_on) {
+ /* set the pool bit */
+ if (vind < 32) {
+ bits = IXGBE_READ_REG(hw,
+ IXGBE_VLVFB(vlvf_index * 2));
+ bits |= (1 << vind);
+ IXGBE_WRITE_REG(hw,
+ IXGBE_VLVFB(vlvf_index * 2), bits);
} else {
- /* clear the pool bit */
- if (vind < 32) {
- bits = IXGBE_READ_REG(hw,
- IXGBE_VLVFB(regindex * 2));
+ bits = IXGBE_READ_REG(hw,
+ IXGBE_VLVFB((vlvf_index * 2) + 1));
+ bits |= (1 << (vind - 32));
+ IXGBE_WRITE_REG(hw,
+ IXGBE_VLVFB((vlvf_index * 2) + 1), bits);
+ }
+ } else {
+ /* clear the pool bit */
+ if (vind < 32) {
+ bits = IXGBE_READ_REG(hw,
+ IXGBE_VLVFB(vlvf_index * 2));
bits &= ~(1 << vind);
- IXGBE_WRITE_REG(hw,
- IXGBE_VLVFB(regindex * 2), bits);
- bits |= IXGBE_READ_REG(hw,
- IXGBE_VLVFB((regindex * 2) + 1));
- } else {
- bits = IXGBE_READ_REG(hw,
- IXGBE_VLVFB((regindex * 2) + 1));
- bits &= ~(1 << vind);
- IXGBE_WRITE_REG(hw,
- IXGBE_VLVFB((regindex * 2) + 1), bits);
- bits |= IXGBE_READ_REG(hw,
- IXGBE_VLVFB(regindex * 2));
- }
+ IXGBE_WRITE_REG(hw,
+ IXGBE_VLVFB(vlvf_index * 2), bits);
+ bits |= IXGBE_READ_REG(hw,
+ IXGBE_VLVFB((vlvf_index * 2) + 1));
+ } else {
+ bits = IXGBE_READ_REG(hw,
+ IXGBE_VLVFB((vlvf_index * 2) + 1));
+ bits &= ~(1 << (vind - 32));
+ IXGBE_WRITE_REG(hw,
+ IXGBE_VLVFB((vlvf_index * 2) + 1), bits);
+ bits |= IXGBE_READ_REG(hw,
+ IXGBE_VLVFB(vlvf_index * 2));
}
+ }
- if (bits)
- IXGBE_WRITE_REG(hw, IXGBE_VLVF(regindex),
- (IXGBE_VLVF_VIEN | vlan));
- else
- IXGBE_WRITE_REG(hw, IXGBE_VLVF(regindex), 0);
+ if (bits) {
+ IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index),
+ (IXGBE_VLVF_VIEN | vlan));
+ /* if bits is non-zero then some pools/VFs are still
+ * using this VLAN ID. Force the VFTA entry to on */
+ bits = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex));
+ bits |= (1 << bitindex);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), bits);
}
+ else
+ IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), 0);
out:
return 0;
@@ -1434,6 +1439,9 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc)
/* Send interrupt when 64 filters are left */
fdirctrl |= 4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT;
+ /* Initialize the drop queue to Rx queue 127 */
+ fdirctrl |= (127 << IXGBE_FDIRCTRL_DROP_Q_SHIFT);
+
switch (pballoc) {
case IXGBE_FDIR_PBALLOC_64K:
/* 2k - 1 perfect filters */
@@ -1675,8 +1683,8 @@ s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr)
* @src_addr_4: the fourth 4 bytes of the IP address to load
**/
s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input,
- u32 src_addr_1, u32 src_addr_2,
- u32 src_addr_3, u32 src_addr_4)
+ u32 src_addr_1, u32 src_addr_2,
+ u32 src_addr_3, u32 src_addr_4)
{
input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET] = src_addr_4 & 0xff;
input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] =
@@ -1718,8 +1726,8 @@ s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input,
* @dst_addr_4: the fourth 4 bytes of the IP address to load
**/
s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input,
- u32 dst_addr_1, u32 dst_addr_2,
- u32 dst_addr_3, u32 dst_addr_4)
+ u32 dst_addr_1, u32 dst_addr_2,
+ u32 dst_addr_3, u32 dst_addr_4)
{
input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET] = dst_addr_4 & 0xff;
input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] =
@@ -1797,7 +1805,7 @@ s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte)
* @vm_pool: the Virtual Machine pool to load
**/
s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input,
- u8 vm_pool)
+ u8 vm_pool)
{
input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET] = vm_pool;
@@ -1821,8 +1829,7 @@ s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type)
* @input: input stream to search
* @vlan: the VLAN id to load
**/
-static s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input,
- u16 *vlan)
+static s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, u16 *vlan)
{
*vlan = input->byte_stream[IXGBE_ATR_VLAN_OFFSET];
*vlan |= input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] << 8;
@@ -2078,23 +2085,26 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
* ixgbe_fdir_add_perfect_filter_82599 - Adds a perfect filter
* @hw: pointer to hardware structure
* @input: input bitstream
+ * @input_masks: bitwise masks for relevant fields
+ * @soft_id: software index into the silicon hash tables for filter storage
* @queue: queue index to direct traffic to
*
* Note that the caller to this function must lock before calling, since the
* hardware writes must be protected from one another.
**/
s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
- struct ixgbe_atr_input *input,
- u16 soft_id,
- u8 queue)
+ struct ixgbe_atr_input *input,
+ struct ixgbe_atr_input_masks *input_masks,
+ u16 soft_id, u8 queue)
{
u32 fdircmd = 0;
u32 fdirhash;
- u32 src_ipv4, dst_ipv4;
+ u32 src_ipv4 = 0, dst_ipv4 = 0;
u32 src_ipv6_1, src_ipv6_2, src_ipv6_3, src_ipv6_4;
u16 src_port, dst_port, vlan_id, flex_bytes;
u16 bucket_hash;
u8 l4type;
+ u8 fdirm = 0;
/* Get our input values */
ixgbe_atr_get_l4type_82599(input, &l4type);
@@ -2149,7 +2159,6 @@ s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
/* IPv4 */
ixgbe_atr_get_src_ipv4_82599(input, &src_ipv4);
IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv4);
-
}
ixgbe_atr_get_dst_ipv4_82599(input, &dst_ipv4);
@@ -2158,7 +2167,78 @@ s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
IXGBE_WRITE_REG(hw, IXGBE_FDIRVLAN, (vlan_id |
(flex_bytes << IXGBE_FDIRVLAN_FLEX_SHIFT)));
IXGBE_WRITE_REG(hw, IXGBE_FDIRPORT, (src_port |
- (dst_port << IXGBE_FDIRPORT_DESTINATION_SHIFT)));
+ (dst_port << IXGBE_FDIRPORT_DESTINATION_SHIFT)));
+
+ /*
+ * Program the relevant mask registers. If src/dst_port or src/dst_addr
+ * are zero, then assume a full mask for that field. Also assume that
+ * a VLAN of 0 is unspecified, so mask that out as well. L4type
+ * cannot be masked out in this implementation.
+ *
+ * This also assumes IPv4 only. IPv6 masking isn't supported at this
+ * point in time.
+ */
+ if (src_ipv4 == 0)
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRSIP4M, 0xffffffff);
+ else
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRSIP4M, input_masks->src_ip_mask);
+
+ if (dst_ipv4 == 0)
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRDIP4M, 0xffffffff);
+ else
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRDIP4M, input_masks->dst_ip_mask);
+
+ switch (l4type & IXGBE_ATR_L4TYPE_MASK) {
+ case IXGBE_ATR_L4TYPE_TCP:
+ if (src_port == 0)
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, 0xffff);
+ else
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM,
+ input_masks->src_port_mask);
+
+ if (dst_port == 0)
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM,
+ (IXGBE_READ_REG(hw, IXGBE_FDIRTCPM) |
+ (0xffff << 16)));
+ else
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM,
+ (IXGBE_READ_REG(hw, IXGBE_FDIRTCPM) |
+ (input_masks->dst_port_mask << 16)));
+ break;
+ case IXGBE_ATR_L4TYPE_UDP:
+ if (src_port == 0)
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, 0xffff);
+ else
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM,
+ input_masks->src_port_mask);
+
+ if (dst_port == 0)
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM,
+ (IXGBE_READ_REG(hw, IXGBE_FDIRUDPM) |
+ (0xffff << 16)));
+ else
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM,
+ (IXGBE_READ_REG(hw, IXGBE_FDIRUDPM) |
+ (input_masks->src_port_mask << 16)));
+ break;
+ default:
+ /* this already would have failed above */
+ break;
+ }
+
+ /* Program the last mask register, FDIRM */
+ if (input_masks->vlan_id_mask || !vlan_id)
+ /* Mask both VLAN and VLANP - bits 0 and 1 */
+ fdirm |= 0x3;
+
+ if (input_masks->data_mask || !flex_bytes)
+ /* Flex bytes need masking, so mask the whole thing - bit 4 */
+ fdirm |= 0x10;
+
+ /* Now mask VM pool and destination IPv6 - bits 5 and 2 */
+ fdirm |= 0x24;
+
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRM, fdirm);
fdircmd |= IXGBE_FDIRCMD_CMD_ADD_FLOW;
fdircmd |= IXGBE_FDIRCMD_FILTER_UPDATE;
@@ -2655,4 +2735,5 @@ struct ixgbe_info ixgbe_82599_info = {
.mac_ops = &mac_ops_82599,
.eeprom_ops = &eeprom_ops_82599,
.phy_ops = &phy_ops_82599,
+ .mbx_ops = &mbx_ops_82599,
};
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
index 21f158f79dd0..eb49020903c1 100644
--- a/drivers/net/ixgbe/ixgbe_common.c
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -28,7 +28,6 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/sched.h>
-#include <linux/list.h>
#include <linux/netdevice.h>
#include "ixgbe.h"
@@ -1278,19 +1277,11 @@ s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw)
/* Get the MAC address from the RAR0 for later reference */
hw->mac.ops.get_mac_addr(hw, hw->mac.addr);
- hw_dbg(hw, " Keeping Current RAR0 Addr =%.2X %.2X %.2X ",
- hw->mac.addr[0], hw->mac.addr[1],
- hw->mac.addr[2]);
- hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3],
- hw->mac.addr[4], hw->mac.addr[5]);
+ hw_dbg(hw, " Keeping Current RAR0 Addr =%pM\n", hw->mac.addr);
} else {
/* Setup the receive address. */
hw_dbg(hw, "Overriding MAC Address in RAR[0]\n");
- hw_dbg(hw, " New MAC Addr =%.2X %.2X %.2X ",
- hw->mac.addr[0], hw->mac.addr[1],
- hw->mac.addr[2]);
- hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3],
- hw->mac.addr[4], hw->mac.addr[5]);
+ hw_dbg(hw, " New MAC Addr =%pM\n", hw->mac.addr);
hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
}
@@ -1355,7 +1346,7 @@ static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq)
/**
* ixgbe_update_uc_addr_list_generic - Updates MAC list of secondary addresses
* @hw: pointer to hardware structure
- * @uc_list: the list of new addresses
+ * @netdev: pointer to net device structure
*
* The given list replaces any existing list. Clears the secondary addrs from
* receive address registers. Uses unused receive address registers for the
@@ -1365,7 +1356,7 @@ static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq)
* manually putting the device into promiscuous mode.
**/
s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw,
- struct list_head *uc_list)
+ struct net_device *netdev)
{
u32 i;
u32 old_promisc_setting = hw->addr_ctrl.overflow_promisc;
@@ -1389,7 +1380,7 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw,
}
/* Add the new addresses */
- list_for_each_entry(ha, uc_list, list) {
+ netdev_for_each_uc_addr(ha, netdev) {
hw_dbg(hw, " Adding the secondary addresses:\n");
ixgbe_add_uc_addr(hw, ha->addr, 0);
}
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
index dfff0ffaa502..13606d4809c9 100644
--- a/drivers/net/ixgbe/ixgbe_common.h
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -60,7 +60,7 @@ s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list,
u32 mc_addr_count,
ixgbe_mc_addr_itr func);
s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw,
- struct list_head *uc_list);
+ struct net_device *netdev);
s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw);
s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw);
s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval);
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index 56f37f66b696..dd4883f642be 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -223,7 +223,7 @@ static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id,
if (adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] !=
adapter->dcb_cfg.bw_percentage[0][bwg_id]) {
- adapter->dcb_set_bitmap |= BIT_PG_RX;
+ adapter->dcb_set_bitmap |= BIT_PG_TX;
adapter->dcb_set_bitmap |= BIT_RESETLINK;
}
}
@@ -341,6 +341,12 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
if (!adapter->dcb_set_bitmap)
return DCB_NO_HW_CHG;
+ ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg,
+ adapter->ring_feature[RING_F_DCB].indices);
+
+ if (ret)
+ return DCB_NO_HW_CHG;
+
/*
* Only take down the adapter if the configuration change
* requires a reset.
@@ -359,14 +365,6 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
}
}
- ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg,
- adapter->ring_feature[RING_F_DCB].indices);
- if (ret) {
- if (adapter->dcb_set_bitmap & BIT_RESETLINK)
- clear_bit(__IXGBE_RESETTING, &adapter->state);
- return DCB_NO_HW_CHG;
- }
-
if (adapter->dcb_cfg.pfc_mode_enable) {
if ((adapter->hw.mac.type != ixgbe_mac_82598EB) &&
(adapter->hw.fc.current_mode != ixgbe_fc_pfc))
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index d77961fc75f9..7949a446e4c7 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -441,10 +441,8 @@ static int ixgbe_set_tso(struct net_device *netdev, u32 data)
netdev->features |= NETIF_F_TSO;
netdev->features |= NETIF_F_TSO6;
} else {
- netif_tx_stop_all_queues(netdev);
netdev->features &= ~NETIF_F_TSO;
netdev->features &= ~NETIF_F_TSO6;
- netif_tx_start_all_queues(netdev);
}
return 0;
}
@@ -834,8 +832,8 @@ static void ixgbe_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
- struct ixgbe_ring *tx_ring = adapter->tx_ring;
- struct ixgbe_ring *rx_ring = adapter->rx_ring;
+ struct ixgbe_ring *tx_ring = adapter->tx_ring[0];
+ struct ixgbe_ring *rx_ring = adapter->rx_ring[0];
ring->rx_max_pending = IXGBE_MAX_RXD;
ring->tx_max_pending = IXGBE_MAX_TXD;
@@ -867,8 +865,8 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
new_tx_count = min(new_tx_count, (u32)IXGBE_MAX_TXD);
new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE);
- if ((new_tx_count == adapter->tx_ring->count) &&
- (new_rx_count == adapter->rx_ring->count)) {
+ if ((new_tx_count == adapter->tx_ring[0]->count) &&
+ (new_rx_count == adapter->rx_ring[0]->count)) {
/* nothing to do */
return 0;
}
@@ -878,25 +876,24 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
if (!netif_running(adapter->netdev)) {
for (i = 0; i < adapter->num_tx_queues; i++)
- adapter->tx_ring[i].count = new_tx_count;
+ adapter->tx_ring[i]->count = new_tx_count;
for (i = 0; i < adapter->num_rx_queues; i++)
- adapter->rx_ring[i].count = new_rx_count;
+ adapter->rx_ring[i]->count = new_rx_count;
adapter->tx_ring_count = new_tx_count;
adapter->rx_ring_count = new_rx_count;
- goto err_setup;
+ goto clear_reset;
}
- temp_tx_ring = kcalloc(adapter->num_tx_queues,
- sizeof(struct ixgbe_ring), GFP_KERNEL);
+ temp_tx_ring = vmalloc(adapter->num_tx_queues * sizeof(struct ixgbe_ring));
if (!temp_tx_ring) {
err = -ENOMEM;
- goto err_setup;
+ goto clear_reset;
}
if (new_tx_count != adapter->tx_ring_count) {
- memcpy(temp_tx_ring, adapter->tx_ring,
- adapter->num_tx_queues * sizeof(struct ixgbe_ring));
for (i = 0; i < adapter->num_tx_queues; i++) {
+ memcpy(&temp_tx_ring[i], adapter->tx_ring[i],
+ sizeof(struct ixgbe_ring));
temp_tx_ring[i].count = new_tx_count;
err = ixgbe_setup_tx_resources(adapter,
&temp_tx_ring[i]);
@@ -904,28 +901,24 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
while (i) {
i--;
ixgbe_free_tx_resources(adapter,
- &temp_tx_ring[i]);
+ &temp_tx_ring[i]);
}
- goto err_setup;
+ goto clear_reset;
}
}
need_update = true;
}
- temp_rx_ring = kcalloc(adapter->num_rx_queues,
- sizeof(struct ixgbe_ring), GFP_KERNEL);
- if ((!temp_rx_ring) && (need_update)) {
- for (i = 0; i < adapter->num_tx_queues; i++)
- ixgbe_free_tx_resources(adapter, &temp_tx_ring[i]);
- kfree(temp_tx_ring);
+ temp_rx_ring = vmalloc(adapter->num_rx_queues * sizeof(struct ixgbe_ring));
+ if (!temp_rx_ring) {
err = -ENOMEM;
goto err_setup;
}
if (new_rx_count != adapter->rx_ring_count) {
- memcpy(temp_rx_ring, adapter->rx_ring,
- adapter->num_rx_queues * sizeof(struct ixgbe_ring));
for (i = 0; i < adapter->num_rx_queues; i++) {
+ memcpy(&temp_rx_ring[i], adapter->rx_ring[i],
+ sizeof(struct ixgbe_ring));
temp_rx_ring[i].count = new_rx_count;
err = ixgbe_setup_rx_resources(adapter,
&temp_rx_ring[i]);
@@ -947,22 +940,32 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
/* tx */
if (new_tx_count != adapter->tx_ring_count) {
- kfree(adapter->tx_ring);
- adapter->tx_ring = temp_tx_ring;
- temp_tx_ring = NULL;
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ ixgbe_free_tx_resources(adapter,
+ adapter->tx_ring[i]);
+ memcpy(adapter->tx_ring[i], &temp_tx_ring[i],
+ sizeof(struct ixgbe_ring));
+ }
adapter->tx_ring_count = new_tx_count;
}
/* rx */
if (new_rx_count != adapter->rx_ring_count) {
- kfree(adapter->rx_ring);
- adapter->rx_ring = temp_rx_ring;
- temp_rx_ring = NULL;
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ ixgbe_free_rx_resources(adapter,
+ adapter->rx_ring[i]);
+ memcpy(adapter->rx_ring[i], &temp_rx_ring[i],
+ sizeof(struct ixgbe_ring));
+ }
adapter->rx_ring_count = new_rx_count;
}
ixgbe_up(adapter);
}
+
+ vfree(temp_rx_ring);
err_setup:
+ vfree(temp_tx_ring);
+clear_reset:
clear_bit(__IXGBE_RESETTING, &adapter->state);
return err;
}
@@ -974,6 +977,9 @@ static int ixgbe_get_sset_count(struct net_device *netdev, int sset)
return IXGBE_TEST_LEN;
case ETH_SS_STATS:
return IXGBE_STATS_LEN;
+ case ETH_SS_NTUPLE_FILTERS:
+ return (ETHTOOL_MAX_NTUPLE_LIST_ENTRY *
+ ETHTOOL_MAX_NTUPLE_STRING_PER_ENTRY);
default:
return -EOPNOTSUPP;
}
@@ -1007,13 +1013,13 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
for (j = 0; j < adapter->num_tx_queues; j++) {
- queue_stat = (u64 *)&adapter->tx_ring[j].stats;
+ queue_stat = (u64 *)&adapter->tx_ring[j]->stats;
for (k = 0; k < stat_count; k++)
data[i + k] = queue_stat[k];
i += k;
}
for (j = 0; j < adapter->num_rx_queues; j++) {
- queue_stat = (u64 *)&adapter->rx_ring[j].stats;
+ queue_stat = (u64 *)&adapter->rx_ring[j]->stats;
for (k = 0; k < stat_count; k++)
data[i + k] = queue_stat[k];
i += k;
@@ -1627,7 +1633,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
reg_data |= IXGBE_RXDCTL_ENABLE;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(0), reg_data);
if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
- int j = adapter->rx_ring[0].reg_idx;
+ int j = adapter->rx_ring[0]->reg_idx;
u32 k;
for (k = 0; k < 10; k++) {
if (IXGBE_READ_REG(&adapter->hw,
@@ -1867,11 +1873,22 @@ static void ixgbe_diag_test(struct net_device *netdev,
if (ixgbe_intr_test(adapter, &data[2]))
eth_test->flags |= ETH_TEST_FL_FAILED;
+ /* If SRIOV or VMDq is enabled then skip MAC
+ * loopback diagnostic. */
+ if (adapter->flags & (IXGBE_FLAG_SRIOV_ENABLED |
+ IXGBE_FLAG_VMDQ_ENABLED)) {
+ DPRINTK(HW, INFO, "Skip MAC loopback diagnostic in VT "
+ "mode\n");
+ data[3] = 0;
+ goto skip_loopback;
+ }
+
ixgbe_reset(adapter);
DPRINTK(HW, INFO, "loopback testing starting\n");
if (ixgbe_loopback_test(adapter, &data[3]))
eth_test->flags |= ETH_TEST_FL_FAILED;
+skip_loopback:
ixgbe_reset(adapter);
clear_bit(__IXGBE_TESTING, &adapter->state);
@@ -2000,7 +2017,7 @@ static int ixgbe_get_coalesce(struct net_device *netdev,
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
- ec->tx_max_coalesced_frames_irq = adapter->tx_ring[0].work_limit;
+ ec->tx_max_coalesced_frames_irq = adapter->tx_ring[0]->work_limit;
/* only valid if in constant ITR mode */
switch (adapter->rx_itr_setting) {
@@ -2053,7 +2070,7 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
return -EINVAL;
if (ec->tx_max_coalesced_frames_irq)
- adapter->tx_ring[0].work_limit = ec->tx_max_coalesced_frames_irq;
+ adapter->tx_ring[0]->work_limit = ec->tx_max_coalesced_frames_irq;
if (ec->rx_coalesce_usecs > 1) {
/* check the limits */
@@ -2134,23 +2151,124 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
static int ixgbe_set_flags(struct net_device *netdev, u32 data)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ bool need_reset = false;
ethtool_op_set_flags(netdev, data);
- if (!(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE))
- return 0;
-
/* if state changes we need to update adapter->flags and reset */
if ((!!(data & ETH_FLAG_LRO)) !=
(!!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))) {
adapter->flags2 ^= IXGBE_FLAG2_RSC_ENABLED;
+ need_reset = true;
+ }
+
+ /*
+ * Check if Flow Director n-tuple support was enabled or disabled. If
+ * the state changed, we need to reset.
+ */
+ if ((adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) &&
+ (!(data & ETH_FLAG_NTUPLE))) {
+ /* turn off Flow Director perfect, set hash and reset */
+ adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
+ adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
+ need_reset = true;
+ } else if ((!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)) &&
+ (data & ETH_FLAG_NTUPLE)) {
+ /* turn off Flow Director hash, enable perfect and reset */
+ adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
+ adapter->flags |= IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
+ need_reset = true;
+ } else {
+ /* no state change */
+ }
+
+ if (need_reset) {
if (netif_running(netdev))
ixgbe_reinit_locked(adapter);
else
ixgbe_reset(adapter);
}
+
return 0;
+}
+static int ixgbe_set_rx_ntuple(struct net_device *dev,
+ struct ethtool_rx_ntuple *cmd)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(dev);
+ struct ethtool_rx_ntuple_flow_spec fs = cmd->fs;
+ struct ixgbe_atr_input input_struct;
+ struct ixgbe_atr_input_masks input_masks;
+ int target_queue;
+
+ if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+ return -EOPNOTSUPP;
+
+ /*
+ * Don't allow programming if the action is a queue greater than
+ * the number of online Tx queues.
+ */
+ if ((fs.action >= adapter->num_tx_queues) ||
+ (fs.action < ETHTOOL_RXNTUPLE_ACTION_DROP))
+ return -EINVAL;
+
+ memset(&input_struct, 0, sizeof(struct ixgbe_atr_input));
+ memset(&input_masks, 0, sizeof(struct ixgbe_atr_input_masks));
+
+ input_masks.src_ip_mask = fs.m_u.tcp_ip4_spec.ip4src;
+ input_masks.dst_ip_mask = fs.m_u.tcp_ip4_spec.ip4dst;
+ input_masks.src_port_mask = fs.m_u.tcp_ip4_spec.psrc;
+ input_masks.dst_port_mask = fs.m_u.tcp_ip4_spec.pdst;
+ input_masks.vlan_id_mask = fs.vlan_tag_mask;
+ /* only use the lowest 2 bytes for flex bytes */
+ input_masks.data_mask = (fs.data_mask & 0xffff);
+
+ switch (fs.flow_type) {
+ case TCP_V4_FLOW:
+ ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_TCP);
+ break;
+ case UDP_V4_FLOW:
+ ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_UDP);
+ break;
+ case SCTP_V4_FLOW:
+ ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_SCTP);
+ break;
+ default:
+ return -1;
+ }
+
+ /* Mask bits from the inputs based on user-supplied mask */
+ ixgbe_atr_set_src_ipv4_82599(&input_struct,
+ (fs.h_u.tcp_ip4_spec.ip4src & ~fs.m_u.tcp_ip4_spec.ip4src));
+ ixgbe_atr_set_dst_ipv4_82599(&input_struct,
+ (fs.h_u.tcp_ip4_spec.ip4dst & ~fs.m_u.tcp_ip4_spec.ip4dst));
+ /* 82599 expects these to be byte-swapped for perfect filtering */
+ ixgbe_atr_set_src_port_82599(&input_struct,
+ ((ntohs(fs.h_u.tcp_ip4_spec.psrc)) & ~fs.m_u.tcp_ip4_spec.psrc));
+ ixgbe_atr_set_dst_port_82599(&input_struct,
+ ((ntohs(fs.h_u.tcp_ip4_spec.pdst)) & ~fs.m_u.tcp_ip4_spec.pdst));
+
+ /* VLAN and Flex bytes are either completely masked or not */
+ if (!fs.vlan_tag_mask)
+ ixgbe_atr_set_vlan_id_82599(&input_struct, fs.vlan_tag);
+
+ if (!input_masks.data_mask)
+ /* make sure we only use the first 2 bytes of user data */
+ ixgbe_atr_set_flex_byte_82599(&input_struct,
+ (fs.data & 0xffff));
+
+ /* determine if we need to drop or route the packet */
+ if (fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP)
+ target_queue = MAX_RX_QUEUES - 1;
+ else
+ target_queue = fs.action;
+
+ spin_lock(&adapter->fdir_perfect_lock);
+ ixgbe_fdir_add_perfect_filter_82599(&adapter->hw, &input_struct,
+ &input_masks, 0, target_queue);
+ spin_unlock(&adapter->fdir_perfect_lock);
+
+ return 0;
}
static const struct ethtool_ops ixgbe_ethtool_ops = {
@@ -2188,6 +2306,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
.set_coalesce = ixgbe_set_coalesce,
.get_flags = ethtool_op_get_flags,
.set_flags = ixgbe_set_flags,
+ .set_rx_ntuple = ixgbe_set_rx_ntuple,
};
void ixgbe_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c
index e9a20c88c155..4123dec0dfb7 100644
--- a/drivers/net/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ixgbe/ixgbe_fcoe.c
@@ -525,7 +525,7 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
for (i = 0; i < IXGBE_FCRETA_SIZE; i++) {
fcoe_i = f->mask + i % f->indices;
fcoe_i &= IXGBE_FCRETA_ENTRY_MASK;
- fcoe_q = adapter->rx_ring[fcoe_i].reg_idx;
+ fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx;
IXGBE_WRITE_REG(hw, IXGBE_FCRETA(i), fcoe_q);
}
IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, IXGBE_FCRECTL_ENA);
@@ -533,7 +533,7 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
} else {
/* Use single rx queue for FCoE */
fcoe_i = f->mask;
- fcoe_q = adapter->rx_ring[fcoe_i].reg_idx;
+ fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx;
IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, 0);
IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE),
IXGBE_ETQS_QUEUE_EN |
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 9c9202f40b10..684af371462d 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -45,12 +45,13 @@
#include "ixgbe.h"
#include "ixgbe_common.h"
#include "ixgbe_dcb_82599.h"
+#include "ixgbe_sriov.h"
char ixgbe_driver_name[] = "ixgbe";
static const char ixgbe_driver_string[] =
"Intel(R) 10 Gigabit PCI Express Network Driver";
-#define DRV_VERSION "2.0.44-k2"
+#define DRV_VERSION "2.0.62-k2"
const char ixgbe_driver_version[] = DRV_VERSION;
static char ixgbe_copyright[] = "Copyright (c) 1999-2010 Intel Corporation.";
@@ -67,7 +68,7 @@ static const struct ixgbe_info *ixgbe_info_tbl[] = {
* { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
* Class, Class Mask, private data (not used) }
*/
-static struct pci_device_id ixgbe_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = {
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598),
board_82598 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT),
@@ -124,6 +125,13 @@ static struct notifier_block dca_notifier = {
};
#endif
+#ifdef CONFIG_PCI_IOV
+static unsigned int max_vfs;
+module_param(max_vfs, uint, 0);
+MODULE_PARM_DESC(max_vfs, "Maximum number of virtual functions to allocate "
+ "per physical function");
+#endif /* CONFIG_PCI_IOV */
+
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
MODULE_LICENSE("GPL");
@@ -131,6 +139,41 @@ MODULE_VERSION(DRV_VERSION);
#define DEFAULT_DEBUG_LEVEL_SHIFT 3
+static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 gcr;
+ u32 gpie;
+ u32 vmdctl;
+
+#ifdef CONFIG_PCI_IOV
+ /* disable iov and allow time for transactions to clear */
+ pci_disable_sriov(adapter->pdev);
+#endif
+
+ /* turn off device IOV mode */
+ gcr = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
+ gcr &= ~(IXGBE_GCR_EXT_SRIOV);
+ IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr);
+ gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
+ gpie &= ~IXGBE_GPIE_VTMODE_MASK;
+ IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
+
+ /* set default pool back to 0 */
+ vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
+ vmdctl &= ~IXGBE_VT_CTL_POOL_MASK;
+ IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl);
+
+ /* take a breather then clean up driver data */
+ msleep(100);
+ if (adapter->vfinfo)
+ kfree(adapter->vfinfo);
+ adapter->vfinfo = NULL;
+
+ adapter->num_vfs = 0;
+ adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
+}
+
static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter)
{
u32 ctrl_ext;
@@ -451,7 +494,7 @@ static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
{
u32 rxctrl;
int cpu = get_cpu();
- int q = rx_ring - adapter->rx_ring;
+ int q = rx_ring->reg_idx;
if (rx_ring->cpu != cpu) {
rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q));
@@ -479,7 +522,7 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
{
u32 txctrl;
int cpu = get_cpu();
- int q = tx_ring - adapter->tx_ring;
+ int q = tx_ring->reg_idx;
struct ixgbe_hw *hw = &adapter->hw;
if (tx_ring->cpu != cpu) {
@@ -513,12 +556,12 @@ static void ixgbe_setup_dca(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL, 2);
for (i = 0; i < adapter->num_tx_queues; i++) {
- adapter->tx_ring[i].cpu = -1;
- ixgbe_update_tx_dca(adapter, &adapter->tx_ring[i]);
+ adapter->tx_ring[i]->cpu = -1;
+ ixgbe_update_tx_dca(adapter, adapter->tx_ring[i]);
}
for (i = 0; i < adapter->num_rx_queues; i++) {
- adapter->rx_ring[i].cpu = -1;
- ixgbe_update_rx_dca(adapter, &adapter->rx_ring[i]);
+ adapter->rx_ring[i]->cpu = -1;
+ ixgbe_update_rx_dca(adapter, adapter->rx_ring[i]);
}
}
@@ -775,6 +818,12 @@ static inline struct sk_buff *ixgbe_transform_rsc_queue(struct sk_buff *skb,
return skb;
}
+struct ixgbe_rsc_cb {
+ dma_addr_t dma;
+};
+
+#define IXGBE_RSC_CB(skb) ((struct ixgbe_rsc_cb *)(skb)->cb)
+
static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
struct ixgbe_ring *rx_ring,
int *work_done, int work_to_do)
@@ -806,6 +855,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
break;
(*work_done)++;
+ rmb(); /* read descriptor and rx_buffer_info after status DD */
if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED) {
hdr_info = le16_to_cpu(ixgbe_get_hdr_info(rx_desc));
len = (hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >>
@@ -823,9 +873,21 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
rx_buffer_info->skb = NULL;
if (rx_buffer_info->dma) {
- pci_unmap_single(pdev, rx_buffer_info->dma,
- rx_ring->rx_buf_len,
- PCI_DMA_FROMDEVICE);
+ if ((adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) &&
+ (!(staterr & IXGBE_RXD_STAT_EOP)) &&
+ (!(skb->prev)))
+ /*
+ * When HWRSC is enabled, delay unmapping
+ * of the first packet. It carries the
+ * header information, HW may still
+ * access the header after the writeback.
+ * Only unmap it when EOP is reached
+ */
+ IXGBE_RSC_CB(skb)->dma = rx_buffer_info->dma;
+ else
+ pci_unmap_single(pdev, rx_buffer_info->dma,
+ rx_ring->rx_buf_len,
+ PCI_DMA_FROMDEVICE);
rx_buffer_info->dma = 0;
skb_put(skb, len);
}
@@ -873,6 +935,10 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
if (skb->prev)
skb = ixgbe_transform_rsc_queue(skb, &(rx_ring->rsc_count));
if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
+ if (IXGBE_RSC_CB(skb)->dma)
+ pci_unmap_single(pdev, IXGBE_RSC_CB(skb)->dma,
+ rx_ring->rx_buf_len,
+ PCI_DMA_FROMDEVICE);
if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED)
rx_ring->rsc_count += skb_shinfo(skb)->nr_frags;
else
@@ -984,12 +1050,12 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
*/
for (v_idx = 0; v_idx < q_vectors; v_idx++) {
q_vector = adapter->q_vector[v_idx];
- /* XXX for_each_bit(...) */
+ /* XXX for_each_set_bit(...) */
r_idx = find_first_bit(q_vector->rxr_idx,
adapter->num_rx_queues);
for (i = 0; i < q_vector->rxr_count; i++) {
- j = adapter->rx_ring[r_idx].reg_idx;
+ j = adapter->rx_ring[r_idx]->reg_idx;
ixgbe_set_ivar(adapter, 0, j, v_idx);
r_idx = find_next_bit(q_vector->rxr_idx,
adapter->num_rx_queues,
@@ -999,7 +1065,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
adapter->num_tx_queues);
for (i = 0; i < q_vector->txr_count; i++) {
- j = adapter->tx_ring[r_idx].reg_idx;
+ j = adapter->tx_ring[r_idx]->reg_idx;
ixgbe_set_ivar(adapter, 1, j, v_idx);
r_idx = find_next_bit(q_vector->txr_idx,
adapter->num_tx_queues,
@@ -1025,7 +1091,12 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
/* set up to autoclear timer, and the vectors */
mask = IXGBE_EIMS_ENABLE_MASK;
- mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC);
+ if (adapter->num_vfs)
+ mask &= ~(IXGBE_EIMS_OTHER |
+ IXGBE_EIMS_MAILBOX |
+ IXGBE_EIMS_LSC);
+ else
+ mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, mask);
}
@@ -1134,7 +1205,7 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
for (i = 0; i < q_vector->txr_count; i++) {
- tx_ring = &(adapter->tx_ring[r_idx]);
+ tx_ring = adapter->tx_ring[r_idx];
ret_itr = ixgbe_update_itr(adapter, q_vector->eitr,
q_vector->tx_itr,
tx_ring->total_packets,
@@ -1149,7 +1220,7 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
for (i = 0; i < q_vector->rxr_count; i++) {
- rx_ring = &(adapter->rx_ring[r_idx]);
+ rx_ring = adapter->rx_ring[r_idx];
ret_itr = ixgbe_update_itr(adapter, q_vector->eitr,
q_vector->rx_itr,
rx_ring->total_packets,
@@ -1254,6 +1325,9 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
if (eicr & IXGBE_EICR_LSC)
ixgbe_check_lsc(adapter);
+ if (eicr & IXGBE_EICR_MAILBOX)
+ ixgbe_msg_task(adapter);
+
if (hw->mac.type == ixgbe_mac_82598EB)
ixgbe_check_fan_failure(adapter, eicr);
@@ -1268,7 +1342,7 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
netif_tx_stop_all_queues(netdev);
for (i = 0; i < adapter->num_tx_queues; i++) {
struct ixgbe_ring *tx_ring =
- &adapter->tx_ring[i];
+ adapter->tx_ring[i];
if (test_and_clear_bit(__IXGBE_FDIR_INIT_DONE,
&tx_ring->reinit_state))
schedule_work(&adapter->fdir_reinit_task);
@@ -1327,7 +1401,7 @@ static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data)
r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
for (i = 0; i < q_vector->txr_count; i++) {
- tx_ring = &(adapter->tx_ring[r_idx]);
+ tx_ring = adapter->tx_ring[r_idx];
tx_ring->total_bytes = 0;
tx_ring->total_packets = 0;
r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
@@ -1355,7 +1429,7 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data)
r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
for (i = 0; i < q_vector->rxr_count; i++) {
- rx_ring = &(adapter->rx_ring[r_idx]);
+ rx_ring = adapter->rx_ring[r_idx];
rx_ring->total_bytes = 0;
rx_ring->total_packets = 0;
r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
@@ -1385,7 +1459,7 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data)
r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
for (i = 0; i < q_vector->txr_count; i++) {
- ring = &(adapter->tx_ring[r_idx]);
+ ring = adapter->tx_ring[r_idx];
ring->total_bytes = 0;
ring->total_packets = 0;
r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
@@ -1394,7 +1468,7 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data)
r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
for (i = 0; i < q_vector->rxr_count; i++) {
- ring = &(adapter->rx_ring[r_idx]);
+ ring = adapter->rx_ring[r_idx];
ring->total_bytes = 0;
ring->total_packets = 0;
r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
@@ -1425,7 +1499,7 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
long r_idx;
r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
- rx_ring = &(adapter->rx_ring[r_idx]);
+ rx_ring = adapter->rx_ring[r_idx];
#ifdef CONFIG_IXGBE_DCA
if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
ixgbe_update_rx_dca(adapter, rx_ring);
@@ -1466,7 +1540,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
for (i = 0; i < q_vector->txr_count; i++) {
- ring = &(adapter->tx_ring[r_idx]);
+ ring = adapter->tx_ring[r_idx];
#ifdef CONFIG_IXGBE_DCA
if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
ixgbe_update_tx_dca(adapter, ring);
@@ -1482,7 +1556,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
budget = max(budget, 1);
r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
for (i = 0; i < q_vector->rxr_count; i++) {
- ring = &(adapter->rx_ring[r_idx]);
+ ring = adapter->rx_ring[r_idx];
#ifdef CONFIG_IXGBE_DCA
if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
ixgbe_update_rx_dca(adapter, ring);
@@ -1493,7 +1567,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
}
r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
- ring = &(adapter->rx_ring[r_idx]);
+ ring = adapter->rx_ring[r_idx];
/* If all Rx work done, exit the polling mode */
if (work_done < budget) {
napi_complete(napi);
@@ -1526,7 +1600,7 @@ static int ixgbe_clean_txonly(struct napi_struct *napi, int budget)
long r_idx;
r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
- tx_ring = &(adapter->tx_ring[r_idx]);
+ tx_ring = adapter->tx_ring[r_idx];
#ifdef CONFIG_IXGBE_DCA
if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
ixgbe_update_tx_dca(adapter, tx_ring);
@@ -1711,8 +1785,8 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter)
struct ixgbe_q_vector *q_vector = adapter->q_vector[0];
u8 current_itr;
u32 new_itr = q_vector->eitr;
- struct ixgbe_ring *rx_ring = &adapter->rx_ring[0];
- struct ixgbe_ring *tx_ring = &adapter->tx_ring[0];
+ struct ixgbe_ring *rx_ring = adapter->rx_ring[0];
+ struct ixgbe_ring *tx_ring = adapter->tx_ring[0];
q_vector->tx_itr = ixgbe_update_itr(adapter, new_itr,
q_vector->tx_itr,
@@ -1768,6 +1842,8 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
mask |= IXGBE_EIMS_ECC;
mask |= IXGBE_EIMS_GPI_SDP1;
mask |= IXGBE_EIMS_GPI_SDP2;
+ if (adapter->num_vfs)
+ mask |= IXGBE_EIMS_MAILBOX;
}
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
@@ -1776,6 +1852,11 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
ixgbe_irq_enable_queues(adapter, ~0);
IXGBE_WRITE_FLUSH(&adapter->hw);
+
+ if (adapter->num_vfs > 32) {
+ u32 eitrsel = (1 << (adapter->num_vfs - 32)) - 1;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITRSEL, eitrsel);
+ }
}
/**
@@ -1817,10 +1898,10 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
ixgbe_check_fan_failure(adapter, eicr);
if (napi_schedule_prep(&(q_vector->napi))) {
- adapter->tx_ring[0].total_packets = 0;
- adapter->tx_ring[0].total_bytes = 0;
- adapter->rx_ring[0].total_packets = 0;
- adapter->rx_ring[0].total_bytes = 0;
+ adapter->tx_ring[0]->total_packets = 0;
+ adapter->tx_ring[0]->total_bytes = 0;
+ adapter->rx_ring[0]->total_packets = 0;
+ adapter->rx_ring[0]->total_bytes = 0;
/* would disable interrupts here but EIAM disabled it */
__napi_schedule(&(q_vector->napi));
}
@@ -1905,6 +1986,8 @@ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0);
+ if (adapter->num_vfs > 32)
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITRSEL, 0);
}
IXGBE_WRITE_FLUSH(&adapter->hw);
if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
@@ -1950,7 +2033,7 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
/* Setup the HW Tx Head and Tail descriptor pointers */
for (i = 0; i < adapter->num_tx_queues; i++) {
- struct ixgbe_ring *ring = &adapter->tx_ring[i];
+ struct ixgbe_ring *ring = adapter->tx_ring[i];
j = ring->reg_idx;
tdba = ring->dma;
tdlen = ring->count * sizeof(union ixgbe_adv_tx_desc);
@@ -1960,8 +2043,8 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), tdlen);
IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0);
IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0);
- adapter->tx_ring[i].head = IXGBE_TDH(j);
- adapter->tx_ring[i].tail = IXGBE_TDT(j);
+ adapter->tx_ring[i]->head = IXGBE_TDH(j);
+ adapter->tx_ring[i]->tail = IXGBE_TDT(j);
/*
* Disable Tx Head Writeback RO bit, since this hoses
* bookkeeping if things aren't delivered in order.
@@ -1989,18 +2072,32 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
if (hw->mac.type == ixgbe_mac_82599EB) {
u32 rttdcs;
+ u32 mask;
/* disable the arbiter while setting MTQC */
rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
rttdcs |= IXGBE_RTTDCS_ARBDIS;
IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
- /* We enable 8 traffic classes, DCB only */
- if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
- IXGBE_WRITE_REG(hw, IXGBE_MTQC, (IXGBE_MTQC_RT_ENA |
- IXGBE_MTQC_8TC_8TQ));
- else
+ /* set transmit pool layout */
+ mask = (IXGBE_FLAG_SRIOV_ENABLED | IXGBE_FLAG_DCB_ENABLED);
+ switch (adapter->flags & mask) {
+
+ case (IXGBE_FLAG_SRIOV_ENABLED):
+ IXGBE_WRITE_REG(hw, IXGBE_MTQC,
+ (IXGBE_MTQC_VT_ENA | IXGBE_MTQC_64VF));
+ break;
+
+ case (IXGBE_FLAG_DCB_ENABLED):
+ /* We enable 8 traffic classes, DCB only */
+ IXGBE_WRITE_REG(hw, IXGBE_MTQC,
+ (IXGBE_MTQC_RT_ENA | IXGBE_MTQC_8TC_8TQ));
+ break;
+
+ default:
IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB);
+ break;
+ }
/* re-eable the arbiter */
rttdcs &= ~IXGBE_RTTDCS_ARBDIS;
@@ -2059,12 +2156,16 @@ static u32 ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
#ifdef CONFIG_IXGBE_DCB
| IXGBE_FLAG_DCB_ENABLED
#endif
+ | IXGBE_FLAG_SRIOV_ENABLED
);
switch (mask) {
case (IXGBE_FLAG_RSS_ENABLED):
mrqc = IXGBE_MRQC_RSSEN;
break;
+ case (IXGBE_FLAG_SRIOV_ENABLED):
+ mrqc = IXGBE_MRQC_VMDQEN;
+ break;
#ifdef CONFIG_IXGBE_DCB
case (IXGBE_FLAG_DCB_ENABLED):
mrqc = IXGBE_MRQC_RT8TCEN;
@@ -2090,7 +2191,7 @@ static void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter, int index)
u32 rscctrl;
int rx_buf_len;
- rx_ring = &adapter->rx_ring[index];
+ rx_ring = adapter->rx_ring[index];
j = rx_ring->reg_idx;
rx_buf_len = rx_ring->rx_buf_len;
rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(j));
@@ -2145,7 +2246,9 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
int rx_buf_len;
/* Decide whether to use packet split mode or not */
- adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
+ /* Do not use packet split if we're in SR-IOV Mode */
+ if (!adapter->num_vfs)
+ adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
/* Set the RX buffer length according to the mode */
if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
@@ -2157,7 +2260,9 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
IXGBE_PSRTYPE_IPV4HDR |
IXGBE_PSRTYPE_IPV6HDR |
IXGBE_PSRTYPE_L2HDR;
- IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype);
+ IXGBE_WRITE_REG(hw,
+ IXGBE_PSRTYPE(adapter->num_vfs),
+ psrtype);
}
} else {
if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) &&
@@ -2184,7 +2289,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
#endif
IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
- rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc);
+ rdlen = adapter->rx_ring[0]->count * sizeof(union ixgbe_adv_rx_desc);
/* disable receives while setting up the descriptors */
rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
@@ -2194,7 +2299,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
* the Base and Length of the Rx Descriptor Ring
*/
for (i = 0; i < adapter->num_rx_queues; i++) {
- rx_ring = &adapter->rx_ring[i];
+ rx_ring = adapter->rx_ring[i];
rdba = rx_ring->dma;
j = rx_ring->reg_idx;
IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), (rdba & DMA_BIT_MASK(32)));
@@ -2243,6 +2348,30 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
}
+ if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
+ u32 vt_reg_bits;
+ u32 reg_offset, vf_shift;
+ u32 vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
+ vt_reg_bits = IXGBE_VMD_CTL_VMDQ_EN
+ | IXGBE_VT_CTL_REPLEN;
+ vt_reg_bits |= (adapter->num_vfs <<
+ IXGBE_VT_CTL_POOL_SHIFT);
+ IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl | vt_reg_bits);
+ IXGBE_WRITE_REG(hw, IXGBE_MRQC, 0);
+
+ vf_shift = adapter->num_vfs % 32;
+ reg_offset = adapter->num_vfs / 32;
+ IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTE(0), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTE(1), 0);
+ /* Enable only the PF's pool for Tx/Rx */
+ IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset), (1 << vf_shift));
+ IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), (1 << vf_shift));
+ IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
+ ixgbe_set_vmolr(hw, adapter->num_vfs);
+ }
+
/* Program MRQC for the distribution of queues */
mrqc = ixgbe_setup_mrqc(adapter);
@@ -2274,6 +2403,20 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
}
IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
+ if (adapter->num_vfs) {
+ u32 reg;
+
+ /* Map PF MAC address in RAR Entry 0 to first pool
+ * following VFs */
+ hw->mac.ops.set_vmdq(hw, 0, adapter->num_vfs);
+
+ /* Set up VF register offsets for selected VT Mode, i.e.
+ * 64 VFs for SR-IOV */
+ reg = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
+ reg |= IXGBE_GCR_EXT_SRIOV;
+ IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, reg);
+ }
+
rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
if (adapter->flags & IXGBE_FLAG_RSS_ENABLED ||
@@ -2312,15 +2455,17 @@ static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
+ int pool_ndx = adapter->num_vfs;
/* add VID to filter table */
- hw->mac.ops.set_vfta(&adapter->hw, vid, 0, true);
+ hw->mac.ops.set_vfta(&adapter->hw, vid, pool_ndx, true);
}
static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
+ int pool_ndx = adapter->num_vfs;
if (!test_bit(__IXGBE_DOWN, &adapter->state))
ixgbe_irq_disable(adapter);
@@ -2331,7 +2476,7 @@ static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
ixgbe_irq_enable(adapter);
/* remove VID from filter table */
- hw->mac.ops.set_vfta(&adapter->hw, vid, 0, false);
+ hw->mac.ops.set_vfta(&adapter->hw, vid, pool_ndx, false);
}
static void ixgbe_vlan_rx_register(struct net_device *netdev,
@@ -2361,7 +2506,7 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev,
} else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
for (i = 0; i < adapter->num_rx_queues; i++) {
u32 ctrl;
- j = adapter->rx_ring[i].reg_idx;
+ j = adapter->rx_ring[i]->reg_idx;
ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(j));
ctrl |= IXGBE_RXDCTL_VME;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(j), ctrl);
@@ -2414,7 +2559,7 @@ static u8 *ixgbe_addr_list_itr(struct ixgbe_hw *hw, u8 **mc_addr_ptr, u32 *vmdq)
* responsible for configuring the hardware for proper unicast, multicast and
* promiscuous mode.
**/
-static void ixgbe_set_rx_mode(struct net_device *netdev)
+void ixgbe_set_rx_mode(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
@@ -2446,14 +2591,16 @@ static void ixgbe_set_rx_mode(struct net_device *netdev)
IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
/* reprogram secondary unicast list */
- hw->mac.ops.update_uc_addr_list(hw, &netdev->uc.list);
+ hw->mac.ops.update_uc_addr_list(hw, netdev);
/* reprogram multicast list */
- addr_count = netdev->mc_count;
+ addr_count = netdev_mc_count(netdev);
if (addr_count)
addr_list = netdev->mc_list->dmi_addr;
hw->mac.ops.update_mc_addr_list(hw, addr_list, addr_count,
ixgbe_addr_list_itr);
+ if (adapter->num_vfs)
+ ixgbe_restore_vf_multicasts(adapter);
}
static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter)
@@ -2522,7 +2669,7 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
ixgbe_dcb_hw_config(&adapter->hw, &adapter->dcb_cfg);
for (i = 0; i < adapter->num_tx_queues; i++) {
- j = adapter->tx_ring[i].reg_idx;
+ j = adapter->tx_ring[i]->reg_idx;
txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
/* PThresh workaround for Tx hang with DFP enabled. */
txdctl |= 32;
@@ -2539,7 +2686,7 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
for (i = 0; i < adapter->num_rx_queues; i++) {
- j = adapter->rx_ring[i].reg_idx;
+ j = adapter->rx_ring[i]->reg_idx;
vlnctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
vlnctrl |= IXGBE_RXDCTL_VME;
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(j), vlnctrl);
@@ -2579,7 +2726,7 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
#endif /* IXGBE_FCOE */
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
for (i = 0; i < adapter->num_tx_queues; i++)
- adapter->tx_ring[i].atr_sample_rate =
+ adapter->tx_ring[i]->atr_sample_rate =
adapter->atr_sample_rate;
ixgbe_init_fdir_signature_82599(hw, adapter->fdir_pballoc);
} else if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) {
@@ -2589,8 +2736,8 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
ixgbe_configure_tx(adapter);
ixgbe_configure_rx(adapter);
for (i = 0; i < adapter->num_rx_queues; i++)
- ixgbe_alloc_rx_buffers(adapter, &adapter->rx_ring[i],
- (adapter->rx_ring[i].count - 1));
+ ixgbe_alloc_rx_buffers(adapter, adapter->rx_ring[i],
+ (adapter->rx_ring[i]->count - 1));
}
static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw)
@@ -2673,7 +2820,7 @@ link_cfg_out:
static inline void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
int rxr)
{
- int j = adapter->rx_ring[rxr].reg_idx;
+ int j = adapter->rx_ring[rxr]->reg_idx;
int k;
for (k = 0; k < IXGBE_MAX_RX_DESC_POLL; k++) {
@@ -2687,8 +2834,8 @@ static inline void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
DPRINTK(DRV, ERR, "RXDCTL.ENABLE on Rx queue %d "
"not set within the polling period\n", rxr);
}
- ixgbe_release_rx_desc(&adapter->hw, &adapter->rx_ring[rxr],
- (adapter->rx_ring[rxr].count - 1));
+ ixgbe_release_rx_desc(&adapter->hw, adapter->rx_ring[rxr],
+ (adapter->rx_ring[rxr]->count - 1));
}
static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
@@ -2702,6 +2849,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
u32 txdctl, rxdctl, mhadd;
u32 dmatxctl;
u32 gpie;
+ u32 ctrl_ext;
ixgbe_get_hw_control(adapter);
@@ -2714,6 +2862,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
/* MSI only */
gpie = 0;
}
+ if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
+ gpie &= ~IXGBE_GPIE_VTMODE_MASK;
+ gpie |= IXGBE_GPIE_VTMODE_64;
+ }
/* XXX: to interrupt immediately for EICS writes, enable this */
/* gpie |= IXGBE_GPIE_EIMEN; */
IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
@@ -2770,7 +2922,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
}
for (i = 0; i < adapter->num_tx_queues; i++) {
- j = adapter->tx_ring[i].reg_idx;
+ j = adapter->tx_ring[i]->reg_idx;
txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
/* enable WTHRESH=8 descriptors, to encourage burst writeback */
txdctl |= (8 << 16);
@@ -2784,14 +2936,26 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl);
}
for (i = 0; i < adapter->num_tx_queues; i++) {
- j = adapter->tx_ring[i].reg_idx;
+ j = adapter->tx_ring[i]->reg_idx;
txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
txdctl |= IXGBE_TXDCTL_ENABLE;
IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
+ if (hw->mac.type == ixgbe_mac_82599EB) {
+ int wait_loop = 10;
+ /* poll for Tx Enable ready */
+ do {
+ msleep(1);
+ txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
+ } while (--wait_loop &&
+ !(txdctl & IXGBE_TXDCTL_ENABLE));
+ if (!wait_loop)
+ DPRINTK(DRV, ERR, "Could not enable "
+ "Tx Queue %d\n", j);
+ }
}
for (i = 0; i < num_rx_rings; i++) {
- j = adapter->rx_ring[i].reg_idx;
+ j = adapter->rx_ring[i]->reg_idx;
rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
/* enable PTHRESH=32 descriptors (half the internal cache)
* and HTHRESH=0 descriptors (to minimize latency on fetch),
@@ -2865,7 +3029,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
for (i = 0; i < adapter->num_tx_queues; i++)
set_bit(__IXGBE_FDIR_INIT_DONE,
- &(adapter->tx_ring[i].reinit_state));
+ &(adapter->tx_ring[i]->reinit_state));
/* enable transmits */
netif_tx_start_all_queues(netdev);
@@ -2875,6 +3039,12 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
adapter->link_check_timeout = jiffies;
mod_timer(&adapter->watchdog_timer, jiffies);
+
+ /* Set PF Reset Done bit so PF/VF Mail Ops can work */
+ ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+ ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
+ IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
+
return 0;
}
@@ -2923,7 +3093,8 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
}
/* reprogram the RAR[0] in case user changed it. */
- hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
+ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs,
+ IXGBE_RAH_AV);
}
/**
@@ -2955,6 +3126,10 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
rx_buffer_info->skb = NULL;
do {
struct sk_buff *this = skb;
+ if (IXGBE_RSC_CB(this)->dma)
+ pci_unmap_single(pdev, IXGBE_RSC_CB(this)->dma,
+ rx_ring->rx_buf_len,
+ PCI_DMA_FROMDEVICE);
skb = skb->prev;
dev_kfree_skb(this);
} while (skb);
@@ -3029,7 +3204,7 @@ static void ixgbe_clean_all_rx_rings(struct ixgbe_adapter *adapter)
int i;
for (i = 0; i < adapter->num_rx_queues; i++)
- ixgbe_clean_rx_ring(adapter, &adapter->rx_ring[i]);
+ ixgbe_clean_rx_ring(adapter, adapter->rx_ring[i]);
}
/**
@@ -3041,7 +3216,7 @@ static void ixgbe_clean_all_tx_rings(struct ixgbe_adapter *adapter)
int i;
for (i = 0; i < adapter->num_tx_queues; i++)
- ixgbe_clean_tx_ring(adapter, &adapter->tx_ring[i]);
+ ixgbe_clean_tx_ring(adapter, adapter->tx_ring[i]);
}
void ixgbe_down(struct ixgbe_adapter *adapter)
@@ -3055,6 +3230,17 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
/* signal that we are down to the interrupt handler */
set_bit(__IXGBE_DOWN, &adapter->state);
+ /* disable receive for all VFs and wait one second */
+ if (adapter->num_vfs) {
+ for (i = 0 ; i < adapter->num_vfs; i++)
+ adapter->vfinfo[i].clear_to_send = 0;
+
+ /* ping all the active vfs to let them know we are going down */
+ ixgbe_ping_all_vfs(adapter);
+ /* Disable all VFTE/VFRE TX/RX */
+ ixgbe_disable_tx_rx(adapter);
+ }
+
/* disable receives */
rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
@@ -3081,7 +3267,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
/* disable transmits in the hardware now that interrupts are off */
for (i = 0; i < adapter->num_tx_queues; i++) {
- j = adapter->tx_ring[i].reg_idx;
+ j = adapter->tx_ring[i]->reg_idx;
txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j),
(txdctl & ~IXGBE_TXDCTL_ENABLE));
@@ -3094,6 +3280,9 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
netif_carrier_off(netdev);
+ /* clear n-tuple filters that are cached */
+ ethtool_ntuple_flush(netdev);
+
if (!pci_channel_offline(adapter->pdev))
ixgbe_reset(adapter);
ixgbe_clean_all_tx_rings(adapter);
@@ -3121,13 +3310,13 @@ static int ixgbe_poll(struct napi_struct *napi, int budget)
#ifdef CONFIG_IXGBE_DCA
if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
- ixgbe_update_tx_dca(adapter, adapter->tx_ring);
- ixgbe_update_rx_dca(adapter, adapter->rx_ring);
+ ixgbe_update_tx_dca(adapter, adapter->tx_ring[0]);
+ ixgbe_update_rx_dca(adapter, adapter->rx_ring[0]);
}
#endif
- tx_clean_complete = ixgbe_clean_tx_irq(q_vector, adapter->tx_ring);
- ixgbe_clean_rx_irq(q_vector, adapter->rx_ring, &work_done, budget);
+ tx_clean_complete = ixgbe_clean_tx_irq(q_vector, adapter->tx_ring[0]);
+ ixgbe_clean_rx_irq(q_vector, adapter->rx_ring[0], &work_done, budget);
if (!tx_clean_complete)
work_done = budget;
@@ -3291,6 +3480,19 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter)
}
#endif /* IXGBE_FCOE */
+/**
+ * ixgbe_set_sriov_queues: Allocate queues for IOV use
+ * @adapter: board private structure to initialize
+ *
+ * IOV doesn't actually use anything, so just NAK the
+ * request for now and let the other queue routines
+ * figure out what to do.
+ */
+static inline bool ixgbe_set_sriov_queues(struct ixgbe_adapter *adapter)
+{
+ return false;
+}
+
/*
* ixgbe_set_num_queues: Allocate queues for device, feature dependant
* @adapter: board private structure to initialize
@@ -3304,6 +3506,15 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter)
**/
static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
{
+ /* Start with base case */
+ adapter->num_rx_queues = 1;
+ adapter->num_tx_queues = 1;
+ adapter->num_rx_pools = adapter->num_rx_queues;
+ adapter->num_rx_queues_per_pool = 1;
+
+ if (ixgbe_set_sriov_queues(adapter))
+ return;
+
#ifdef IXGBE_FCOE
if (ixgbe_set_fcoe_queues(adapter))
goto done;
@@ -3393,9 +3604,9 @@ static inline bool ixgbe_cache_ring_rss(struct ixgbe_adapter *adapter)
if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
for (i = 0; i < adapter->num_rx_queues; i++)
- adapter->rx_ring[i].reg_idx = i;
+ adapter->rx_ring[i]->reg_idx = i;
for (i = 0; i < adapter->num_tx_queues; i++)
- adapter->tx_ring[i].reg_idx = i;
+ adapter->tx_ring[i]->reg_idx = i;
ret = true;
} else {
ret = false;
@@ -3422,8 +3633,8 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter)
if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
/* the number of queues is assumed to be symmetric */
for (i = 0; i < dcb_i; i++) {
- adapter->rx_ring[i].reg_idx = i << 3;
- adapter->tx_ring[i].reg_idx = i << 2;
+ adapter->rx_ring[i]->reg_idx = i << 3;
+ adapter->tx_ring[i]->reg_idx = i << 2;
}
ret = true;
} else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
@@ -3441,18 +3652,18 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter)
* Rx TC0-TC7 are offset by 16 queues each
*/
for (i = 0; i < 3; i++) {
- adapter->tx_ring[i].reg_idx = i << 5;
- adapter->rx_ring[i].reg_idx = i << 4;
+ adapter->tx_ring[i]->reg_idx = i << 5;
+ adapter->rx_ring[i]->reg_idx = i << 4;
}
for ( ; i < 5; i++) {
- adapter->tx_ring[i].reg_idx =
+ adapter->tx_ring[i]->reg_idx =
((i + 2) << 4);
- adapter->rx_ring[i].reg_idx = i << 4;
+ adapter->rx_ring[i]->reg_idx = i << 4;
}
for ( ; i < dcb_i; i++) {
- adapter->tx_ring[i].reg_idx =
+ adapter->tx_ring[i]->reg_idx =
((i + 8) << 3);
- adapter->rx_ring[i].reg_idx = i << 4;
+ adapter->rx_ring[i]->reg_idx = i << 4;
}
ret = true;
@@ -3465,12 +3676,12 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter)
*
* Rx TC0-TC3 are offset by 32 queues each
*/
- adapter->tx_ring[0].reg_idx = 0;
- adapter->tx_ring[1].reg_idx = 64;
- adapter->tx_ring[2].reg_idx = 96;
- adapter->tx_ring[3].reg_idx = 112;
+ adapter->tx_ring[0]->reg_idx = 0;
+ adapter->tx_ring[1]->reg_idx = 64;
+ adapter->tx_ring[2]->reg_idx = 96;
+ adapter->tx_ring[3]->reg_idx = 112;
for (i = 0 ; i < dcb_i; i++)
- adapter->rx_ring[i].reg_idx = i << 5;
+ adapter->rx_ring[i]->reg_idx = i << 5;
ret = true;
} else {
@@ -3503,9 +3714,9 @@ static bool inline ixgbe_cache_ring_fdir(struct ixgbe_adapter *adapter)
((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) ||
(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))) {
for (i = 0; i < adapter->num_rx_queues; i++)
- adapter->rx_ring[i].reg_idx = i;
+ adapter->rx_ring[i]->reg_idx = i;
for (i = 0; i < adapter->num_tx_queues; i++)
- adapter->tx_ring[i].reg_idx = i;
+ adapter->tx_ring[i]->reg_idx = i;
ret = true;
}
@@ -3533,8 +3744,8 @@ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter)
ixgbe_cache_ring_dcb(adapter);
/* find out queues in TC for FCoE */
- fcoe_rx_i = adapter->rx_ring[fcoe->tc].reg_idx + 1;
- fcoe_tx_i = adapter->tx_ring[fcoe->tc].reg_idx + 1;
+ fcoe_rx_i = adapter->rx_ring[fcoe->tc]->reg_idx + 1;
+ fcoe_tx_i = adapter->tx_ring[fcoe->tc]->reg_idx + 1;
/*
* In 82599, the number of Tx queues for each traffic
* class for both 8-TC and 4-TC modes are:
@@ -3565,8 +3776,8 @@ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter)
fcoe_tx_i = f->mask;
}
for (i = 0; i < f->indices; i++, fcoe_rx_i++, fcoe_tx_i++) {
- adapter->rx_ring[f->mask + i].reg_idx = fcoe_rx_i;
- adapter->tx_ring[f->mask + i].reg_idx = fcoe_tx_i;
+ adapter->rx_ring[f->mask + i]->reg_idx = fcoe_rx_i;
+ adapter->tx_ring[f->mask + i]->reg_idx = fcoe_tx_i;
}
ret = true;
}
@@ -3575,6 +3786,24 @@ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter)
#endif /* IXGBE_FCOE */
/**
+ * ixgbe_cache_ring_sriov - Descriptor ring to register mapping for sriov
+ * @adapter: board private structure to initialize
+ *
+ * SR-IOV doesn't use any descriptor rings but changes the default if
+ * no other mapping is used.
+ *
+ */
+static inline bool ixgbe_cache_ring_sriov(struct ixgbe_adapter *adapter)
+{
+ adapter->rx_ring[0]->reg_idx = adapter->num_vfs * 2;
+ adapter->tx_ring[0]->reg_idx = adapter->num_vfs * 2;
+ if (adapter->num_vfs)
+ return true;
+ else
+ return false;
+}
+
+/**
* ixgbe_cache_ring_register - Descriptor ring to register mapping
* @adapter: board private structure to initialize
*
@@ -3588,8 +3817,11 @@ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter)
static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter)
{
/* start with default case */
- adapter->rx_ring[0].reg_idx = 0;
- adapter->tx_ring[0].reg_idx = 0;
+ adapter->rx_ring[0]->reg_idx = 0;
+ adapter->tx_ring[0]->reg_idx = 0;
+
+ if (ixgbe_cache_ring_sriov(adapter))
+ return;
#ifdef IXGBE_FCOE
if (ixgbe_cache_ring_fcoe(adapter))
@@ -3619,33 +3851,63 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter)
static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter)
{
int i;
-
- adapter->tx_ring = kcalloc(adapter->num_tx_queues,
- sizeof(struct ixgbe_ring), GFP_KERNEL);
- if (!adapter->tx_ring)
- goto err_tx_ring_allocation;
-
- adapter->rx_ring = kcalloc(adapter->num_rx_queues,
- sizeof(struct ixgbe_ring), GFP_KERNEL);
- if (!adapter->rx_ring)
- goto err_rx_ring_allocation;
+ int orig_node = adapter->node;
for (i = 0; i < adapter->num_tx_queues; i++) {
- adapter->tx_ring[i].count = adapter->tx_ring_count;
- adapter->tx_ring[i].queue_index = i;
+ struct ixgbe_ring *ring = adapter->tx_ring[i];
+ if (orig_node == -1) {
+ int cur_node = next_online_node(adapter->node);
+ if (cur_node == MAX_NUMNODES)
+ cur_node = first_online_node;
+ adapter->node = cur_node;
+ }
+ ring = kzalloc_node(sizeof(struct ixgbe_ring), GFP_KERNEL,
+ adapter->node);
+ if (!ring)
+ ring = kzalloc(sizeof(struct ixgbe_ring), GFP_KERNEL);
+ if (!ring)
+ goto err_tx_ring_allocation;
+ ring->count = adapter->tx_ring_count;
+ ring->queue_index = i;
+ ring->numa_node = adapter->node;
+
+ adapter->tx_ring[i] = ring;
}
+ /* Restore the adapter's original node */
+ adapter->node = orig_node;
+
for (i = 0; i < adapter->num_rx_queues; i++) {
- adapter->rx_ring[i].count = adapter->rx_ring_count;
- adapter->rx_ring[i].queue_index = i;
+ struct ixgbe_ring *ring = adapter->rx_ring[i];
+ if (orig_node == -1) {
+ int cur_node = next_online_node(adapter->node);
+ if (cur_node == MAX_NUMNODES)
+ cur_node = first_online_node;
+ adapter->node = cur_node;
+ }
+ ring = kzalloc_node(sizeof(struct ixgbe_ring), GFP_KERNEL,
+ adapter->node);
+ if (!ring)
+ ring = kzalloc(sizeof(struct ixgbe_ring), GFP_KERNEL);
+ if (!ring)
+ goto err_rx_ring_allocation;
+ ring->count = adapter->rx_ring_count;
+ ring->queue_index = i;
+ ring->numa_node = adapter->node;
+
+ adapter->rx_ring[i] = ring;
}
+ /* Restore the adapter's original node */
+ adapter->node = orig_node;
+
ixgbe_cache_ring_register(adapter);
return 0;
err_rx_ring_allocation:
- kfree(adapter->tx_ring);
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ kfree(adapter->tx_ring[i]);
err_tx_ring_allocation:
return -ENOMEM;
}
@@ -3700,6 +3962,9 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
adapter->atr_sample_rate = 0;
+ if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
+ ixgbe_disable_sriov(adapter);
+
ixgbe_set_num_queues(adapter);
err = pci_enable_msi(adapter->pdev);
@@ -3741,7 +4006,11 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter)
}
for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
- q_vector = kzalloc(sizeof(struct ixgbe_q_vector), GFP_KERNEL);
+ q_vector = kzalloc_node(sizeof(struct ixgbe_q_vector),
+ GFP_KERNEL, adapter->node);
+ if (!q_vector)
+ q_vector = kzalloc(sizeof(struct ixgbe_q_vector),
+ GFP_KERNEL);
if (!q_vector)
goto err_out;
q_vector->adapter = adapter;
@@ -3868,10 +4137,16 @@ err_set_interrupt:
**/
void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter)
{
- kfree(adapter->tx_ring);
- kfree(adapter->rx_ring);
- adapter->tx_ring = NULL;
- adapter->rx_ring = NULL;
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ kfree(adapter->tx_ring[i]);
+ adapter->tx_ring[i] = NULL;
+ }
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ kfree(adapter->rx_ring[i]);
+ adapter->rx_ring[i] = NULL;
+ }
ixgbe_free_q_vectors(adapter);
ixgbe_reset_interrupt_capability(adapter);
@@ -3942,6 +4217,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
+ struct net_device *dev = adapter->netdev;
unsigned int rss;
#ifdef CONFIG_IXGBE_DCB
int j;
@@ -3969,10 +4245,18 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599;
adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE;
adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
- adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
+ if (dev->features & NETIF_F_NTUPLE) {
+ /* Flow Director perfect filter enabled */
+ adapter->flags |= IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
+ adapter->atr_sample_rate = 0;
+ spin_lock_init(&adapter->fdir_perfect_lock);
+ } else {
+ /* Flow Director hash filters enabled */
+ adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
+ adapter->atr_sample_rate = 20;
+ }
adapter->ring_feature[RING_F_FDIR].indices =
IXGBE_MAX_FDIR_INDICES;
- adapter->atr_sample_rate = 20;
adapter->fdir_pballoc = 0;
#ifdef IXGBE_FCOE
adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE;
@@ -4041,6 +4325,9 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
/* enable rx csum by default */
adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
+ /* get assigned NUMA node */
+ adapter->node = dev_to_node(&pdev->dev);
+
set_bit(__IXGBE_DOWN, &adapter->state);
return 0;
@@ -4060,7 +4347,9 @@ int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
int size;
size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count;
- tx_ring->tx_buffer_info = vmalloc(size);
+ tx_ring->tx_buffer_info = vmalloc_node(size, tx_ring->numa_node);
+ if (!tx_ring->tx_buffer_info)
+ tx_ring->tx_buffer_info = vmalloc(size);
if (!tx_ring->tx_buffer_info)
goto err;
memset(tx_ring->tx_buffer_info, 0, size);
@@ -4102,7 +4391,7 @@ static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter)
int i, err = 0;
for (i = 0; i < adapter->num_tx_queues; i++) {
- err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]);
+ err = ixgbe_setup_tx_resources(adapter, adapter->tx_ring[i]);
if (!err)
continue;
DPRINTK(PROBE, ERR, "Allocation for Tx Queue %u failed\n", i);
@@ -4126,7 +4415,9 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
int size;
size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
- rx_ring->rx_buffer_info = vmalloc(size);
+ rx_ring->rx_buffer_info = vmalloc_node(size, adapter->node);
+ if (!rx_ring->rx_buffer_info)
+ rx_ring->rx_buffer_info = vmalloc(size);
if (!rx_ring->rx_buffer_info) {
DPRINTK(PROBE, ERR,
"vmalloc allocation failed for the rx desc ring\n");
@@ -4172,7 +4463,7 @@ static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter)
int i, err = 0;
for (i = 0; i < adapter->num_rx_queues; i++) {
- err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]);
+ err = ixgbe_setup_rx_resources(adapter, adapter->rx_ring[i]);
if (!err)
continue;
DPRINTK(PROBE, ERR, "Allocation for Rx Queue %u failed\n", i);
@@ -4215,8 +4506,8 @@ static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter)
int i;
for (i = 0; i < adapter->num_tx_queues; i++)
- if (adapter->tx_ring[i].desc)
- ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]);
+ if (adapter->tx_ring[i]->desc)
+ ixgbe_free_tx_resources(adapter, adapter->tx_ring[i]);
}
/**
@@ -4252,8 +4543,8 @@ static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter)
int i;
for (i = 0; i < adapter->num_rx_queues; i++)
- if (adapter->rx_ring[i].desc)
- ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]);
+ if (adapter->rx_ring[i]->desc)
+ ixgbe_free_rx_resources(adapter, adapter->rx_ring[i]);
}
/**
@@ -4530,8 +4821,8 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
adapter->hw_rx_no_dma_resources +=
IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
for (i = 0; i < adapter->num_rx_queues; i++) {
- rsc_count += adapter->rx_ring[i].rsc_count;
- rsc_flush += adapter->rx_ring[i].rsc_flush;
+ rsc_count += adapter->rx_ring[i]->rsc_count;
+ rsc_flush += adapter->rx_ring[i]->rsc_flush;
}
adapter->rsc_total_count = rsc_count;
adapter->rsc_total_flush = rsc_flush;
@@ -4539,11 +4830,11 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
/* gather some stats to the adapter struct that are per queue */
for (i = 0; i < adapter->num_tx_queues; i++)
- restart_queue += adapter->tx_ring[i].restart_queue;
+ restart_queue += adapter->tx_ring[i]->restart_queue;
adapter->restart_queue = restart_queue;
for (i = 0; i < adapter->num_rx_queues; i++)
- non_eop_descs += adapter->rx_ring[i].non_eop_descs;
+ non_eop_descs += adapter->rx_ring[i]->non_eop_descs;
adapter->non_eop_descs = non_eop_descs;
adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
@@ -4782,7 +5073,7 @@ static void ixgbe_fdir_reinit_task(struct work_struct *work)
if (ixgbe_reinit_fdir_tables_82599(hw) == 0) {
for (i = 0; i < adapter->num_tx_queues; i++)
set_bit(__IXGBE_FDIR_INIT_DONE,
- &(adapter->tx_ring[i].reinit_state));
+ &(adapter->tx_ring[i]->reinit_state));
} else {
DPRINTK(PROBE, ERR, "failed to finish FDIR re-initialization, "
"ignored adding FDIR ATR filters \n");
@@ -4791,6 +5082,8 @@ static void ixgbe_fdir_reinit_task(struct work_struct *work)
netif_tx_start_all_queues(adapter->netdev);
}
+static DEFINE_MUTEX(ixgbe_watchdog_lock);
+
/**
* ixgbe_watchdog_task - worker thread to bring link up
* @work: pointer to work_struct containing our data
@@ -4802,13 +5095,16 @@ static void ixgbe_watchdog_task(struct work_struct *work)
watchdog_task);
struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
- u32 link_speed = adapter->link_speed;
- bool link_up = adapter->link_up;
+ u32 link_speed;
+ bool link_up;
int i;
struct ixgbe_ring *tx_ring;
int some_tx_pending = 0;
- adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK;
+ mutex_lock(&ixgbe_watchdog_lock);
+
+ link_up = adapter->link_up;
+ link_speed = adapter->link_speed;
if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) {
hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
@@ -4879,7 +5175,7 @@ static void ixgbe_watchdog_task(struct work_struct *work)
if (!netif_carrier_ok(netdev)) {
for (i = 0; i < adapter->num_tx_queues; i++) {
- tx_ring = &adapter->tx_ring[i];
+ tx_ring = adapter->tx_ring[i];
if (tx_ring->next_to_use != tx_ring->next_to_clean) {
some_tx_pending = 1;
break;
@@ -4897,7 +5193,7 @@ static void ixgbe_watchdog_task(struct work_struct *work)
}
ixgbe_update_stats(adapter);
- adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK;
+ mutex_unlock(&ixgbe_watchdog_lock);
}
static int ixgbe_tso(struct ixgbe_adapter *adapter,
@@ -4928,7 +5224,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
iph->daddr, 0,
IPPROTO_TCP,
0);
- } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+ } else if (skb_is_gso_v6(skb)) {
ipv6_hdr(skb)->payload_len = 0;
tcp_hdr(skb)->check =
~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
@@ -5167,19 +5463,19 @@ dma_error:
tx_buffer_info->dma = 0;
tx_buffer_info->time_stamp = 0;
tx_buffer_info->next_to_watch = 0;
- count--;
+ if (count)
+ count--;
/* clear timestamp and dma mappings for remaining portion of packet */
- while (count >= 0) {
- count--;
- i--;
- if (i < 0)
+ while (count--) {
+ if (i==0)
i += tx_ring->count;
+ i--;
tx_buffer_info = &tx_ring->tx_buffer_info[i];
ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info);
}
- return count;
+ return 0;
}
static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
@@ -5329,8 +5625,11 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
struct ixgbe_adapter *adapter = netdev_priv(dev);
int txq = smp_processor_id();
- if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE)
+ if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
+ while (unlikely(txq >= dev->real_num_tx_queues))
+ txq -= dev->real_num_tx_queues;
return txq;
+ }
#ifdef IXGBE_FCOE
if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) &&
@@ -5340,8 +5639,14 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
return txq;
}
#endif
- if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
- return (skb->vlan_tci & IXGBE_TX_FLAGS_VLAN_PRIO_MASK) >> 13;
+ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+ if (skb->priority == TC_PRIO_CONTROL)
+ txq = adapter->ring_feature[RING_F_DCB].indices-1;
+ else
+ txq = (skb->vlan_tci & IXGBE_TX_FLAGS_VLAN_PRIO_MASK)
+ >> 13;
+ return txq;
+ }
return skb_tx_hash(dev, skb);
}
@@ -5368,17 +5673,12 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
tx_flags |= IXGBE_TX_FLAGS_VLAN;
} else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
- if (skb->priority != TC_PRIO_CONTROL) {
- tx_flags |= ((skb->queue_mapping & 0x7) << 13);
- tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
- tx_flags |= IXGBE_TX_FLAGS_VLAN;
- } else {
- skb->queue_mapping =
- adapter->ring_feature[RING_F_DCB].indices-1;
- }
+ tx_flags |= ((skb->queue_mapping & 0x7) << 13);
+ tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
+ tx_flags |= IXGBE_TX_FLAGS_VLAN;
}
- tx_ring = &adapter->tx_ring[skb->queue_mapping];
+ tx_ring = adapter->tx_ring[skb->queue_mapping];
if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) &&
(skb->protocol == htons(ETH_P_FCOE))) {
@@ -5484,7 +5784,8 @@ static int ixgbe_set_mac(struct net_device *netdev, void *p)
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
- hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
+ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs,
+ IXGBE_RAH_AV);
return 0;
}
@@ -5621,6 +5922,61 @@ static const struct net_device_ops ixgbe_netdev_ops = {
#endif /* IXGBE_FCOE */
};
+static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter,
+ const struct ixgbe_info *ii)
+{
+#ifdef CONFIG_PCI_IOV
+ struct ixgbe_hw *hw = &adapter->hw;
+ int err;
+
+ if (hw->mac.type != ixgbe_mac_82599EB || !max_vfs)
+ return;
+
+ /* The 82599 supports up to 64 VFs per physical function
+ * but this implementation limits allocation to 63 so that
+ * basic networking resources are still available to the
+ * physical function
+ */
+ adapter->num_vfs = (max_vfs > 63) ? 63 : max_vfs;
+ adapter->flags |= IXGBE_FLAG_SRIOV_ENABLED;
+ err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "Failed to enable PCI sriov: %d\n", err);
+ goto err_novfs;
+ }
+ /* If call to enable VFs succeeded then allocate memory
+ * for per VF control structures.
+ */
+ adapter->vfinfo =
+ kcalloc(adapter->num_vfs,
+ sizeof(struct vf_data_storage), GFP_KERNEL);
+ if (adapter->vfinfo) {
+ /* Now that we're sure SR-IOV is enabled
+ * and memory allocated set up the mailbox parameters
+ */
+ ixgbe_init_mbx_params_pf(hw);
+ memcpy(&hw->mbx.ops, ii->mbx_ops,
+ sizeof(hw->mbx.ops));
+
+ /* Disable RSC when in SR-IOV mode */
+ adapter->flags2 &= ~(IXGBE_FLAG2_RSC_CAPABLE |
+ IXGBE_FLAG2_RSC_ENABLED);
+ return;
+ }
+
+ /* Oh oh */
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate memory for VF "
+ "Data Storage - SRIOV disabled\n");
+ pci_disable_sriov(adapter->pdev);
+
+err_novfs:
+ adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
+ adapter->num_vfs = 0;
+#endif /* CONFIG_PCI_IOV */
+}
+
/**
* ixgbe_probe - Device Initialization Routine
* @pdev: PCI device information struct
@@ -5641,6 +5997,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
static int cards_found;
int i, err, pci_using_dac;
+ unsigned int indices = num_possible_cpus();
#ifdef IXGBE_FCOE
u16 device_caps;
#endif
@@ -5679,7 +6036,18 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
pci_set_master(pdev);
pci_save_state(pdev);
- netdev = alloc_etherdev_mq(sizeof(struct ixgbe_adapter), MAX_TX_QUEUES);
+ if (ii->mac == ixgbe_mac_82598EB)
+ indices = min_t(unsigned int, indices, IXGBE_MAX_RSS_INDICES);
+ else
+ indices = min_t(unsigned int, indices, IXGBE_MAX_FDIR_INDICES);
+
+ indices = max_t(unsigned int, indices, IXGBE_MAX_DCB_INDICES);
+#ifdef IXGBE_FCOE
+ indices += min_t(unsigned int, num_possible_cpus(),
+ IXGBE_MAX_FCOE_INDICES);
+#endif
+ indices = min_t(unsigned int, indices, MAX_TX_QUEUES);
+ netdev = alloc_etherdev_mq(sizeof(struct ixgbe_adapter), indices);
if (!netdev) {
err = -ENOMEM;
goto err_alloc_etherdev;
@@ -5760,6 +6128,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
if (err)
goto err_sw_init;
+ /* Make it possible the adapter to be woken up via WOL */
+ if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0);
+
/*
* If there is a fan on this device and it has failed log the
* failure.
@@ -5795,6 +6167,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
goto err_sw_init;
}
+ ixgbe_probe_vf(adapter, ii);
+
netdev->features = NETIF_F_SG |
NETIF_F_IP_CSUM |
NETIF_F_HW_VLAN_TX |
@@ -5815,6 +6189,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
netdev->vlan_features |= NETIF_F_IPV6_CSUM;
netdev->vlan_features |= NETIF_F_SG;
+ if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
+ adapter->flags &= ~(IXGBE_FLAG_RSS_ENABLED |
+ IXGBE_FLAG_DCB_ENABLED);
if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
@@ -5941,6 +6318,13 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
ixgbe_setup_dca(adapter);
}
#endif
+ if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
+ DPRINTK(PROBE, INFO, "IOV is enabled with %d VFs\n",
+ adapter->num_vfs);
+ for (i = 0; i < adapter->num_vfs; i++)
+ ixgbe_vf_configuration(pdev, (i | 0x10000000));
+ }
+
/* add san mac addr to netdev */
ixgbe_add_sanmac_netdev(netdev);
@@ -5953,6 +6337,8 @@ err_register:
ixgbe_clear_interrupt_scheme(adapter);
err_sw_init:
err_eeprom:
+ if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
+ ixgbe_disable_sriov(adapter);
clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
del_timer_sync(&adapter->sfp_timer);
cancel_work_sync(&adapter->sfp_task);
@@ -6021,6 +6407,9 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
if (netdev->reg_state == NETREG_REGISTERED)
unregister_netdev(netdev);
+ if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
+ ixgbe_disable_sriov(adapter);
+
ixgbe_clear_interrupt_scheme(adapter);
ixgbe_release_hw_control(adapter);
diff --git a/drivers/net/ixgbe/ixgbe_mbx.c b/drivers/net/ixgbe/ixgbe_mbx.c
new file mode 100644
index 000000000000..d75f9148eb1f
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_mbx.c
@@ -0,0 +1,479 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2009 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include "ixgbe_type.h"
+#include "ixgbe_common.h"
+#include "ixgbe_mbx.h"
+
+/**
+ * ixgbe_read_mbx - Reads a message from the mailbox
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ * @mbx_id: id of mailbox to read
+ *
+ * returns SUCCESS if it successfuly read message from buffer
+ **/
+s32 ixgbe_read_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ /* limit read to size of mailbox */
+ if (size > mbx->size)
+ size = mbx->size;
+
+ if (mbx->ops.read)
+ ret_val = mbx->ops.read(hw, msg, size, mbx_id);
+
+ return ret_val;
+}
+
+/**
+ * ixgbe_write_mbx - Write a message to the mailbox
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ * @mbx_id: id of mailbox to write
+ *
+ * returns SUCCESS if it successfully copied message into the buffer
+ **/
+s32 ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ s32 ret_val = 0;
+
+ if (size > mbx->size)
+ ret_val = IXGBE_ERR_MBX;
+
+ else if (mbx->ops.write)
+ ret_val = mbx->ops.write(hw, msg, size, mbx_id);
+
+ return ret_val;
+}
+
+/**
+ * ixgbe_check_for_msg - checks to see if someone sent us mail
+ * @hw: pointer to the HW structure
+ * @mbx_id: id of mailbox to check
+ *
+ * returns SUCCESS if the Status bit was found or else ERR_MBX
+ **/
+s32 ixgbe_check_for_msg(struct ixgbe_hw *hw, u16 mbx_id)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ if (mbx->ops.check_for_msg)
+ ret_val = mbx->ops.check_for_msg(hw, mbx_id);
+
+ return ret_val;
+}
+
+/**
+ * ixgbe_check_for_ack - checks to see if someone sent us ACK
+ * @hw: pointer to the HW structure
+ * @mbx_id: id of mailbox to check
+ *
+ * returns SUCCESS if the Status bit was found or else ERR_MBX
+ **/
+s32 ixgbe_check_for_ack(struct ixgbe_hw *hw, u16 mbx_id)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ if (mbx->ops.check_for_ack)
+ ret_val = mbx->ops.check_for_ack(hw, mbx_id);
+
+ return ret_val;
+}
+
+/**
+ * ixgbe_check_for_rst - checks to see if other side has reset
+ * @hw: pointer to the HW structure
+ * @mbx_id: id of mailbox to check
+ *
+ * returns SUCCESS if the Status bit was found or else ERR_MBX
+ **/
+s32 ixgbe_check_for_rst(struct ixgbe_hw *hw, u16 mbx_id)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ if (mbx->ops.check_for_rst)
+ ret_val = mbx->ops.check_for_rst(hw, mbx_id);
+
+ return ret_val;
+}
+
+/**
+ * ixgbe_poll_for_msg - Wait for message notification
+ * @hw: pointer to the HW structure
+ * @mbx_id: id of mailbox to write
+ *
+ * returns SUCCESS if it successfully received a message notification
+ **/
+static s32 ixgbe_poll_for_msg(struct ixgbe_hw *hw, u16 mbx_id)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ int countdown = mbx->timeout;
+
+ if (!countdown || !mbx->ops.check_for_msg)
+ goto out;
+
+ while (countdown && mbx->ops.check_for_msg(hw, mbx_id)) {
+ countdown--;
+ if (!countdown)
+ break;
+ udelay(mbx->usec_delay);
+ }
+
+ /* if we failed, all future posted messages fail until reset */
+ if (!countdown)
+ mbx->timeout = 0;
+out:
+ return countdown ? 0 : IXGBE_ERR_MBX;
+}
+
+/**
+ * ixgbe_poll_for_ack - Wait for message acknowledgement
+ * @hw: pointer to the HW structure
+ * @mbx_id: id of mailbox to write
+ *
+ * returns SUCCESS if it successfully received a message acknowledgement
+ **/
+static s32 ixgbe_poll_for_ack(struct ixgbe_hw *hw, u16 mbx_id)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ int countdown = mbx->timeout;
+
+ if (!countdown || !mbx->ops.check_for_ack)
+ goto out;
+
+ while (countdown && mbx->ops.check_for_ack(hw, mbx_id)) {
+ countdown--;
+ if (!countdown)
+ break;
+ udelay(mbx->usec_delay);
+ }
+
+ /* if we failed, all future posted messages fail until reset */
+ if (!countdown)
+ mbx->timeout = 0;
+out:
+ return countdown ? 0 : IXGBE_ERR_MBX;
+}
+
+/**
+ * ixgbe_read_posted_mbx - Wait for message notification and receive message
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ * @mbx_id: id of mailbox to write
+ *
+ * returns SUCCESS if it successfully received a message notification and
+ * copied it into the receive buffer.
+ **/
+s32 ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ if (!mbx->ops.read)
+ goto out;
+
+ ret_val = ixgbe_poll_for_msg(hw, mbx_id);
+
+ /* if ack received read message, otherwise we timed out */
+ if (!ret_val)
+ ret_val = mbx->ops.read(hw, msg, size, mbx_id);
+out:
+ return ret_val;
+}
+
+/**
+ * ixgbe_write_posted_mbx - Write a message to the mailbox, wait for ack
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ * @mbx_id: id of mailbox to write
+ *
+ * returns SUCCESS if it successfully copied message into the buffer and
+ * received an ack to that message within delay * timeout period
+ **/
+s32 ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size,
+ u16 mbx_id)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ /* exit if either we can't write or there isn't a defined timeout */
+ if (!mbx->ops.write || !mbx->timeout)
+ goto out;
+
+ /* send msg */
+ ret_val = mbx->ops.write(hw, msg, size, mbx_id);
+
+ /* if msg sent wait until we receive an ack */
+ if (!ret_val)
+ ret_val = ixgbe_poll_for_ack(hw, mbx_id);
+out:
+ return ret_val;
+}
+
+/**
+ * ixgbe_init_mbx_ops_generic - Initialize MB function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Setup the mailbox read and write message function pointers
+ **/
+void ixgbe_init_mbx_ops_generic(struct ixgbe_hw *hw)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+
+ mbx->ops.read_posted = ixgbe_read_posted_mbx;
+ mbx->ops.write_posted = ixgbe_write_posted_mbx;
+}
+
+static s32 ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, u32 mask, s32 index)
+{
+ u32 mbvficr = IXGBE_READ_REG(hw, IXGBE_MBVFICR(index));
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ if (mbvficr & mask) {
+ ret_val = 0;
+ IXGBE_WRITE_REG(hw, IXGBE_MBVFICR(index), mask);
+ }
+
+ return ret_val;
+}
+
+/**
+ * ixgbe_check_for_msg_pf - checks to see if the VF has sent mail
+ * @hw: pointer to the HW structure
+ * @vf_number: the VF index
+ *
+ * returns SUCCESS if the VF has set the Status bit or else ERR_MBX
+ **/
+static s32 ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, u16 vf_number)
+{
+ s32 ret_val = IXGBE_ERR_MBX;
+ s32 index = IXGBE_MBVFICR_INDEX(vf_number);
+ u32 vf_bit = vf_number % 16;
+
+ if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFREQ_VF1 << vf_bit,
+ index)) {
+ ret_val = 0;
+ hw->mbx.stats.reqs++;
+ }
+
+ return ret_val;
+}
+
+/**
+ * ixgbe_check_for_ack_pf - checks to see if the VF has ACKed
+ * @hw: pointer to the HW structure
+ * @vf_number: the VF index
+ *
+ * returns SUCCESS if the VF has set the Status bit or else ERR_MBX
+ **/
+static s32 ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, u16 vf_number)
+{
+ s32 ret_val = IXGBE_ERR_MBX;
+ s32 index = IXGBE_MBVFICR_INDEX(vf_number);
+ u32 vf_bit = vf_number % 16;
+
+ if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFACK_VF1 << vf_bit,
+ index)) {
+ ret_val = 0;
+ hw->mbx.stats.acks++;
+ }
+
+ return ret_val;
+}
+
+/**
+ * ixgbe_check_for_rst_pf - checks to see if the VF has reset
+ * @hw: pointer to the HW structure
+ * @vf_number: the VF index
+ *
+ * returns SUCCESS if the VF has set the Status bit or else ERR_MBX
+ **/
+static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number)
+{
+ u32 reg_offset = (vf_number < 32) ? 0 : 1;
+ u32 vf_shift = vf_number % 32;
+ u32 vflre = 0;
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ if (hw->mac.type == ixgbe_mac_82599EB)
+ vflre = IXGBE_READ_REG(hw, IXGBE_VFLRE(reg_offset));
+
+ if (vflre & (1 << vf_shift)) {
+ ret_val = 0;
+ IXGBE_WRITE_REG(hw, IXGBE_VFLREC(reg_offset), (1 << vf_shift));
+ hw->mbx.stats.rsts++;
+ }
+
+ return ret_val;
+}
+
+/**
+ * ixgbe_obtain_mbx_lock_pf - obtain mailbox lock
+ * @hw: pointer to the HW structure
+ * @vf_number: the VF index
+ *
+ * return SUCCESS if we obtained the mailbox lock
+ **/
+static s32 ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, u16 vf_number)
+{
+ s32 ret_val = IXGBE_ERR_MBX;
+ u32 p2v_mailbox;
+
+ /* Take ownership of the buffer */
+ IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_PFU);
+
+ /* reserve mailbox for vf use */
+ p2v_mailbox = IXGBE_READ_REG(hw, IXGBE_PFMAILBOX(vf_number));
+ if (p2v_mailbox & IXGBE_PFMAILBOX_PFU)
+ ret_val = 0;
+
+ return ret_val;
+}
+
+/**
+ * ixgbe_write_mbx_pf - Places a message in the mailbox
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ * @vf_number: the VF index
+ *
+ * returns SUCCESS if it successfully copied message into the buffer
+ **/
+static s32 ixgbe_write_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size,
+ u16 vf_number)
+{
+ s32 ret_val;
+ u16 i;
+
+ /* lock the mailbox to prevent pf/vf race condition */
+ ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_number);
+ if (ret_val)
+ goto out_no_write;
+
+ /* flush msg and acks as we are overwriting the message buffer */
+ ixgbe_check_for_msg_pf(hw, vf_number);
+ ixgbe_check_for_ack_pf(hw, vf_number);
+
+ /* copy the caller specified message to the mailbox memory buffer */
+ for (i = 0; i < size; i++)
+ IXGBE_WRITE_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_number), i, msg[i]);
+
+ /* Interrupt VF to tell it a message has been sent and release buffer*/
+ IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_STS);
+
+ /* update stats */
+ hw->mbx.stats.msgs_tx++;
+
+out_no_write:
+ return ret_val;
+
+}
+
+/**
+ * ixgbe_read_mbx_pf - Read a message from the mailbox
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ * @vf_number: the VF index
+ *
+ * This function copies a message from the mailbox buffer to the caller's
+ * memory buffer. The presumption is that the caller knows that there was
+ * a message due to a VF request so no polling for message is needed.
+ **/
+static s32 ixgbe_read_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size,
+ u16 vf_number)
+{
+ s32 ret_val;
+ u16 i;
+
+ /* lock the mailbox to prevent pf/vf race condition */
+ ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_number);
+ if (ret_val)
+ goto out_no_read;
+
+ /* copy the message to the mailbox memory buffer */
+ for (i = 0; i < size; i++)
+ msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_number), i);
+
+ /* Acknowledge the message and release buffer */
+ IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_ACK);
+
+ /* update stats */
+ hw->mbx.stats.msgs_rx++;
+
+out_no_read:
+ return ret_val;
+}
+
+/**
+ * ixgbe_init_mbx_params_pf - set initial values for pf mailbox
+ * @hw: pointer to the HW structure
+ *
+ * Initializes the hw->mbx struct to correct values for pf mailbox
+ */
+void ixgbe_init_mbx_params_pf(struct ixgbe_hw *hw)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+
+ if (hw->mac.type != ixgbe_mac_82599EB)
+ return;
+
+ mbx->timeout = 0;
+ mbx->usec_delay = 0;
+
+ mbx->size = IXGBE_VFMAILBOX_SIZE;
+
+ mbx->stats.msgs_tx = 0;
+ mbx->stats.msgs_rx = 0;
+ mbx->stats.reqs = 0;
+ mbx->stats.acks = 0;
+ mbx->stats.rsts = 0;
+}
+
+struct ixgbe_mbx_operations mbx_ops_82599 = {
+ .read = ixgbe_read_mbx_pf,
+ .write = ixgbe_write_mbx_pf,
+ .read_posted = ixgbe_read_posted_mbx,
+ .write_posted = ixgbe_write_posted_mbx,
+ .check_for_msg = ixgbe_check_for_msg_pf,
+ .check_for_ack = ixgbe_check_for_ack_pf,
+ .check_for_rst = ixgbe_check_for_rst_pf,
+};
+
diff --git a/drivers/net/ixgbe/ixgbe_mbx.h b/drivers/net/ixgbe/ixgbe_mbx.h
new file mode 100644
index 000000000000..be7ab3309ab7
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_mbx.h
@@ -0,0 +1,96 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2009 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_MBX_H_
+#define _IXGBE_MBX_H_
+
+#include "ixgbe_type.h"
+
+#define IXGBE_VFMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */
+#define IXGBE_ERR_MBX -100
+
+#define IXGBE_VFMAILBOX 0x002FC
+#define IXGBE_VFMBMEM 0x00200
+
+#define IXGBE_PFMAILBOX(x) (0x04B00 + (4 * x))
+#define IXGBE_PFMBMEM(vfn) (0x13000 + (64 * vfn))
+
+#define IXGBE_PFMAILBOX_STS 0x00000001 /* Initiate message send to VF */
+#define IXGBE_PFMAILBOX_ACK 0x00000002 /* Ack message recv'd from VF */
+#define IXGBE_PFMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */
+#define IXGBE_PFMAILBOX_PFU 0x00000008 /* PF owns the mailbox buffer */
+#define IXGBE_PFMAILBOX_RVFU 0x00000010 /* Reset VFU - used when VF stuck */
+
+#define IXGBE_MBVFICR_VFREQ_MASK 0x0000FFFF /* bits for VF messages */
+#define IXGBE_MBVFICR_VFREQ_VF1 0x00000001 /* bit for VF 1 message */
+#define IXGBE_MBVFICR_VFACK_MASK 0xFFFF0000 /* bits for VF acks */
+#define IXGBE_MBVFICR_VFACK_VF1 0x00010000 /* bit for VF 1 ack */
+
+
+/* If it's a IXGBE_VF_* msg then it originates in the VF and is sent to the
+ * PF. The reverse is true if it is IXGBE_PF_*.
+ * Message ACK's are the value or'd with 0xF0000000
+ */
+#define IXGBE_VT_MSGTYPE_ACK 0x80000000 /* Messages below or'd with
+ * this are the ACK */
+#define IXGBE_VT_MSGTYPE_NACK 0x40000000 /* Messages below or'd with
+ * this are the NACK */
+#define IXGBE_VT_MSGTYPE_CTS 0x20000000 /* Indicates that VF is still
+ clear to send requests */
+#define IXGBE_VT_MSGINFO_SHIFT 16
+/* bits 23:16 are used for exra info for certain messages */
+#define IXGBE_VT_MSGINFO_MASK (0xFF << IXGBE_VT_MSGINFO_SHIFT)
+
+#define IXGBE_VF_RESET 0x01 /* VF requests reset */
+#define IXGBE_VF_SET_MAC_ADDR 0x02 /* VF requests PF to set MAC addr */
+#define IXGBE_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */
+#define IXGBE_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */
+#define IXGBE_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */
+
+/* length of permanent address message returned from PF */
+#define IXGBE_VF_PERMADDR_MSG_LEN 4
+/* word in permanent address message with the current multicast type */
+#define IXGBE_VF_MC_TYPE_WORD 3
+
+#define IXGBE_PF_CONTROL_MSG 0x0100 /* PF control message */
+
+#define IXGBE_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */
+#define IXGBE_VF_MBX_INIT_DELAY 500 /* microseconds between retries */
+
+s32 ixgbe_read_mbx(struct ixgbe_hw *, u32 *, u16, u16);
+s32 ixgbe_write_mbx(struct ixgbe_hw *, u32 *, u16, u16);
+s32 ixgbe_read_posted_mbx(struct ixgbe_hw *, u32 *, u16, u16);
+s32 ixgbe_write_posted_mbx(struct ixgbe_hw *, u32 *, u16, u16);
+s32 ixgbe_check_for_msg(struct ixgbe_hw *, u16);
+s32 ixgbe_check_for_ack(struct ixgbe_hw *, u16);
+s32 ixgbe_check_for_rst(struct ixgbe_hw *, u16);
+void ixgbe_init_mbx_ops_generic(struct ixgbe_hw *hw);
+void ixgbe_init_mbx_params_pf(struct ixgbe_hw *);
+
+extern struct ixgbe_mbx_operations mbx_ops_82599;
+
+#endif /* _IXGBE_MBX_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c
new file mode 100644
index 000000000000..d4cd20f30199
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_sriov.c
@@ -0,0 +1,362 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2009 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+#ifdef NETIF_F_HW_VLAN_TX
+#include <linux/if_vlan.h>
+#endif
+
+#include "ixgbe.h"
+
+#include "ixgbe_sriov.h"
+
+int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
+ int entries, u16 *hash_list, u32 vf)
+{
+ struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
+ int i;
+
+ /* only so many hash values supported */
+ entries = min(entries, IXGBE_MAX_VF_MC_ENTRIES);
+
+ /*
+ * salt away the number of multi cast addresses assigned
+ * to this VF for later use to restore when the PF multi cast
+ * list changes
+ */
+ vfinfo->num_vf_mc_hashes = entries;
+
+ /*
+ * VFs are limited to using the MTA hash table for their multicast
+ * addresses
+ */
+ for (i = 0; i < entries; i++) {
+ vfinfo->vf_mc_hashes[i] = hash_list[i];;
+ }
+
+ /* Flush and reset the mta with the new values */
+ ixgbe_set_rx_mode(adapter->netdev);
+
+ return 0;
+}
+
+void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct vf_data_storage *vfinfo;
+ int i, j;
+ u32 vector_bit;
+ u32 vector_reg;
+ u32 mta_reg;
+
+ for (i = 0; i < adapter->num_vfs; i++) {
+ vfinfo = &adapter->vfinfo[i];
+ for (j = 0; j < vfinfo->num_vf_mc_hashes; j++) {
+ hw->addr_ctrl.mta_in_use++;
+ vector_reg = (vfinfo->vf_mc_hashes[j] >> 5) & 0x7F;
+ vector_bit = vfinfo->vf_mc_hashes[j] & 0x1F;
+ mta_reg = IXGBE_READ_REG(hw, IXGBE_MTA(vector_reg));
+ mta_reg |= (1 << vector_bit);
+ IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg);
+ }
+ }
+}
+
+int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, u32 vf)
+{
+ u32 ctrl;
+
+ /* Check if global VLAN already set, if not set it */
+ ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL);
+ if (!(ctrl & IXGBE_VLNCTRL_VFE)) {
+ /* enable VLAN tag insert/strip */
+ ctrl |= IXGBE_VLNCTRL_VFE;
+ ctrl &= ~IXGBE_VLNCTRL_CFIEN;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
+ }
+
+ return adapter->hw.mac.ops.set_vfta(&adapter->hw, vid, vf, (bool)add);
+}
+
+
+void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf)
+{
+ u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf));
+ vmolr |= (IXGBE_VMOLR_AUPE |
+ IXGBE_VMOLR_ROMPE |
+ IXGBE_VMOLR_ROPE |
+ IXGBE_VMOLR_BAM);
+ IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf), vmolr);
+}
+
+inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ /* reset offloads to defaults */
+ ixgbe_set_vmolr(hw, vf);
+
+
+ /* reset multicast table array for vf */
+ adapter->vfinfo[vf].num_vf_mc_hashes = 0;
+
+ /* Flush and reset the mta with the new values */
+ ixgbe_set_rx_mode(adapter->netdev);
+
+ if (adapter->vfinfo[vf].rar > 0) {
+ adapter->hw.mac.ops.clear_rar(&adapter->hw,
+ adapter->vfinfo[vf].rar);
+ adapter->vfinfo[vf].rar = -1;
+ }
+}
+
+int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
+ int vf, unsigned char *mac_addr)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ adapter->vfinfo[vf].rar = hw->mac.ops.set_rar(hw, vf + 1, mac_addr,
+ vf, IXGBE_RAH_AV);
+ if (adapter->vfinfo[vf].rar < 0) {
+ DPRINTK(DRV, ERR, "Could not set MAC Filter for VF %d\n", vf);
+ return -1;
+ }
+
+ memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, 6);
+
+ return 0;
+}
+
+int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
+{
+ unsigned char vf_mac_addr[6];
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ unsigned int vfn = (event_mask & 0x3f);
+
+ bool enable = ((event_mask & 0x10000000U) != 0);
+
+ if (enable) {
+ random_ether_addr(vf_mac_addr);
+ DPRINTK(PROBE, INFO, "IOV: VF %d is enabled "
+ "mac %02X:%02X:%02X:%02X:%02X:%02X\n",
+ vfn,
+ vf_mac_addr[0], vf_mac_addr[1], vf_mac_addr[2],
+ vf_mac_addr[3], vf_mac_addr[4], vf_mac_addr[5]);
+ /*
+ * Store away the VF "permananet" MAC address, it will ask
+ * for it later.
+ */
+ memcpy(adapter->vfinfo[vfn].vf_mac_addresses, vf_mac_addr, 6);
+ }
+
+ return 0;
+}
+
+inline void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 reg;
+ u32 reg_offset, vf_shift;
+
+ vf_shift = vf % 32;
+ reg_offset = vf / 32;
+
+ /* enable transmit and receive for vf */
+ reg = IXGBE_READ_REG(hw, IXGBE_VFTE(reg_offset));
+ reg |= (reg | (1 << vf_shift));
+ IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), reg);
+
+ reg = IXGBE_READ_REG(hw, IXGBE_VFRE(reg_offset));
+ reg |= (reg | (1 << vf_shift));
+ IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset), reg);
+
+ ixgbe_vf_reset_event(adapter, vf);
+}
+
+static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
+{
+ u32 mbx_size = IXGBE_VFMAILBOX_SIZE;
+ u32 msgbuf[mbx_size];
+ struct ixgbe_hw *hw = &adapter->hw;
+ s32 retval;
+ int entries;
+ u16 *hash_list;
+ int add, vid;
+
+ retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf);
+
+ if (retval)
+ printk(KERN_ERR "Error receiving message from VF\n");
+
+ /* this is a message we already processed, do nothing */
+ if (msgbuf[0] & (IXGBE_VT_MSGTYPE_ACK | IXGBE_VT_MSGTYPE_NACK))
+ return retval;
+
+ /*
+ * until the vf completes a virtual function reset it should not be
+ * allowed to start any configuration.
+ */
+
+ if (msgbuf[0] == IXGBE_VF_RESET) {
+ unsigned char *vf_mac = adapter->vfinfo[vf].vf_mac_addresses;
+ u8 *addr = (u8 *)(&msgbuf[1]);
+ DPRINTK(PROBE, INFO, "VF Reset msg received from vf %d\n", vf);
+ adapter->vfinfo[vf].clear_to_send = false;
+ ixgbe_vf_reset_msg(adapter, vf);
+ adapter->vfinfo[vf].clear_to_send = true;
+
+ /* reply to reset with ack and vf mac address */
+ msgbuf[0] = IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK;
+ memcpy(addr, vf_mac, IXGBE_ETH_LENGTH_OF_ADDRESS);
+ /*
+ * Piggyback the multicast filter type so VF can compute the
+ * correct vectors
+ */
+ msgbuf[3] = hw->mac.mc_filter_type;
+ ixgbe_write_mbx(hw, msgbuf, IXGBE_VF_PERMADDR_MSG_LEN, vf);
+
+ return retval;
+ }
+
+ if (!adapter->vfinfo[vf].clear_to_send) {
+ msgbuf[0] |= IXGBE_VT_MSGTYPE_NACK;
+ ixgbe_write_mbx(hw, msgbuf, 1, vf);
+ return retval;
+ }
+
+ switch ((msgbuf[0] & 0xFFFF)) {
+ case IXGBE_VF_SET_MAC_ADDR:
+ {
+ u8 *new_mac = ((u8 *)(&msgbuf[1]));
+ if (is_valid_ether_addr(new_mac))
+ ixgbe_set_vf_mac(adapter, vf, new_mac);
+ else
+ retval = -1;
+ }
+ break;
+ case IXGBE_VF_SET_MULTICAST:
+ entries = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK)
+ >> IXGBE_VT_MSGINFO_SHIFT;
+ hash_list = (u16 *)&msgbuf[1];
+ retval = ixgbe_set_vf_multicasts(adapter, entries,
+ hash_list, vf);
+ break;
+ case IXGBE_VF_SET_LPE:
+ WARN_ON((msgbuf[0] & 0xFFFF) == IXGBE_VF_SET_LPE);
+ break;
+ case IXGBE_VF_SET_VLAN:
+ add = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK)
+ >> IXGBE_VT_MSGINFO_SHIFT;
+ vid = (msgbuf[1] & IXGBE_VLVF_VLANID_MASK);
+ retval = ixgbe_set_vf_vlan(adapter, add, vid, vf);
+ break;
+ default:
+ DPRINTK(DRV, ERR, "Unhandled Msg %8.8x\n", msgbuf[0]);
+ retval = IXGBE_ERR_MBX;
+ break;
+ }
+
+ /* notify the VF of the results of what it sent us */
+ if (retval)
+ msgbuf[0] |= IXGBE_VT_MSGTYPE_NACK;
+ else
+ msgbuf[0] |= IXGBE_VT_MSGTYPE_ACK;
+
+ msgbuf[0] |= IXGBE_VT_MSGTYPE_CTS;
+
+ ixgbe_write_mbx(hw, msgbuf, 1, vf);
+
+ return retval;
+}
+
+static void ixgbe_rcv_ack_from_vf(struct ixgbe_adapter *adapter, u32 vf)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 msg = IXGBE_VT_MSGTYPE_NACK;
+
+ /* if device isn't clear to send it shouldn't be reading either */
+ if (!adapter->vfinfo[vf].clear_to_send)
+ ixgbe_write_mbx(hw, &msg, 1, vf);
+}
+
+void ixgbe_msg_task(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 vf;
+
+ for (vf = 0; vf < adapter->num_vfs; vf++) {
+ /* process any reset requests */
+ if (!ixgbe_check_for_rst(hw, vf))
+ ixgbe_vf_reset_event(adapter, vf);
+
+ /* process any messages pending */
+ if (!ixgbe_check_for_msg(hw, vf))
+ ixgbe_rcv_msg_from_vf(adapter, vf);
+
+ /* process any acks */
+ if (!ixgbe_check_for_ack(hw, vf))
+ ixgbe_rcv_ack_from_vf(adapter, vf);
+ }
+}
+
+void ixgbe_disable_tx_rx(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ /* disable transmit and receive for all vfs */
+ IXGBE_WRITE_REG(hw, IXGBE_VFTE(0), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTE(1), 0);
+
+ IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), 0);
+}
+
+void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 ping;
+ int i;
+
+ for (i = 0 ; i < adapter->num_vfs; i++) {
+ ping = IXGBE_PF_CONTROL_MSG;
+ if (adapter->vfinfo[i].clear_to_send)
+ ping |= IXGBE_VT_MSGTYPE_CTS;
+ ixgbe_write_mbx(hw, &ping, 1, i);
+ }
+}
+
diff --git a/drivers/net/ixgbe/ixgbe_sriov.h b/drivers/net/ixgbe/ixgbe_sriov.h
new file mode 100644
index 000000000000..51d1106c45a1
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_sriov.h
@@ -0,0 +1,47 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2009 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_SRIOV_H_
+#define _IXGBE_SRIOV_H_
+
+int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
+ int entries, u16 *hash_list, u32 vf);
+void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter);
+int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, u32 vf);
+void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf);
+void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf);
+void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf);
+void ixgbe_msg_task(struct ixgbe_adapter *adapter);
+int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
+ int vf, unsigned char *mac_addr);
+int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask);
+void ixgbe_disable_tx_rx(struct ixgbe_adapter *adapter);
+void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter);
+void ixgbe_dump_registers(struct ixgbe_adapter *adapter);
+
+#endif /* _IXGBE_SRIOV_H_ */
+
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index 9eafddfa1b97..2be907466593 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -30,7 +30,7 @@
#include <linux/types.h>
#include <linux/mdio.h>
-#include <linux/list.h>
+#include <linux/netdevice.h>
/* Vendor ID */
#define IXGBE_INTEL_VENDOR_ID 0x8086
@@ -277,6 +277,7 @@
#define IXGBE_DTXCTL 0x07E00
#define IXGBE_DMATXCTL 0x04A80
+#define IXGBE_PFDTXGSWC 0x08220
#define IXGBE_DTXMXSZRQ 0x08100
#define IXGBE_DTXTCPFLGL 0x04A88
#define IXGBE_DTXTCPFLGH 0x04A8C
@@ -287,6 +288,8 @@
#define IXGBE_DMATXCTL_NS 0x2 /* No Snoop LSO hdr buffer */
#define IXGBE_DMATXCTL_GDV 0x8 /* Global Double VLAN */
#define IXGBE_DMATXCTL_VT_SHIFT 16 /* VLAN EtherType */
+
+#define IXGBE_PFDTXGSWC_VT_LBEN 0x1 /* Local L2 VT switch enable */
#define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4)) /* 16 of these (0-15) */
/* Tx DCA Control register : 128 of these (0-127) */
#define IXGBE_DCA_TXCTRL_82599(_i) (0x0600C + ((_i) * 0x40))
@@ -497,6 +500,7 @@
/* DCB registers */
#define IXGBE_RTRPCS 0x02430
#define IXGBE_RTTDCS 0x04900
+#define IXGBE_RTTDCS_ARBDIS 0x00000040 /* DCB arbiter disable */
#define IXGBE_RTTPCS 0x0CD00
#define IXGBE_RTRUP2TC 0x03020
#define IXGBE_RTTUP2TC 0x0C800
@@ -730,6 +734,13 @@
#define IXGBE_GCR_CMPL_TMOUT_RESEND 0x00010000
#define IXGBE_GCR_CAP_VER2 0x00040000
+#define IXGBE_GCR_EXT_MSIX_EN 0x80000000
+#define IXGBE_GCR_EXT_VT_MODE_16 0x00000001
+#define IXGBE_GCR_EXT_VT_MODE_32 0x00000002
+#define IXGBE_GCR_EXT_VT_MODE_64 0x00000003
+#define IXGBE_GCR_EXT_SRIOV (IXGBE_GCR_EXT_MSIX_EN | \
+ IXGBE_GCR_EXT_VT_MODE_64)
+
/* Time Sync Registers */
#define IXGBE_TSYNCRXCTL 0x05188 /* Rx Time Sync Control register - RW */
#define IXGBE_TSYNCTXCTL 0x08C00 /* Tx Time Sync Control register - RW */
@@ -1065,6 +1076,8 @@
/* VFRE bitmask */
#define IXGBE_VFRE_ENABLE_ALL 0xFFFFFFFF
+#define IXGBE_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */
+
/* RDHMPN and TDHMPN bitmasks */
#define IXGBE_RDHMPN_RDICADDR 0x007FF800
#define IXGBE_RDHMPN_RDICRDREQ 0x00800000
@@ -1295,6 +1308,7 @@
/* VLAN pool filtering masks */
#define IXGBE_VLVF_VIEN 0x80000000 /* filter is valid */
#define IXGBE_VLVF_ENTRIES 64
+#define IXGBE_VLVF_VLANID_MASK 0x00000FFF
#define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.1q protocol */
@@ -1843,6 +1857,12 @@
#define IXGBE_RX_DESC_SPECIAL_PRI_SHIFT 0x000D /* Priority in upper 3 of 16 */
#define IXGBE_TX_DESC_SPECIAL_PRI_SHIFT IXGBE_RX_DESC_SPECIAL_PRI_SHIFT
+/* SR-IOV specific macros */
+#define IXGBE_MBVFICR_INDEX(vf_number) (vf_number >> 4)
+#define IXGBE_MBVFICR(_i) (0x00710 + (_i * 4))
+#define IXGBE_VFLRE(_i) (((_i & 1) ? 0x001C0 : 0x00600))
+#define IXGBE_VFLREC(_i) (0x00700 + (_i * 4))
+
/* Little Endian defines */
#ifndef __le32
#define __le32 u32
@@ -2109,6 +2129,15 @@ struct ixgbe_atr_input {
u8 byte_stream[42];
};
+struct ixgbe_atr_input_masks {
+ u32 src_ip_mask;
+ u32 dst_ip_mask;
+ u16 src_port_mask;
+ u16 dst_port_mask;
+ u16 vlan_id_mask;
+ u16 data_mask;
+};
+
enum ixgbe_eeprom_type {
ixgbe_eeprom_uninitialized = 0,
ixgbe_eeprom_spi,
@@ -2385,7 +2414,7 @@ struct ixgbe_mac_operations {
s32 (*set_vmdq)(struct ixgbe_hw *, u32, u32);
s32 (*clear_vmdq)(struct ixgbe_hw *, u32, u32);
s32 (*init_rx_addrs)(struct ixgbe_hw *);
- s32 (*update_uc_addr_list)(struct ixgbe_hw *, struct list_head *);
+ s32 (*update_uc_addr_list)(struct ixgbe_hw *, struct net_device *);
s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32,
ixgbe_mc_addr_itr);
s32 (*enable_mc)(struct ixgbe_hw *);
@@ -2463,6 +2492,37 @@ struct ixgbe_phy_info {
bool multispeed_fiber;
};
+#include "ixgbe_mbx.h"
+
+struct ixgbe_mbx_operations {
+ s32 (*init_params)(struct ixgbe_hw *hw);
+ s32 (*read)(struct ixgbe_hw *, u32 *, u16, u16);
+ s32 (*write)(struct ixgbe_hw *, u32 *, u16, u16);
+ s32 (*read_posted)(struct ixgbe_hw *, u32 *, u16, u16);
+ s32 (*write_posted)(struct ixgbe_hw *, u32 *, u16, u16);
+ s32 (*check_for_msg)(struct ixgbe_hw *, u16);
+ s32 (*check_for_ack)(struct ixgbe_hw *, u16);
+ s32 (*check_for_rst)(struct ixgbe_hw *, u16);
+};
+
+struct ixgbe_mbx_stats {
+ u32 msgs_tx;
+ u32 msgs_rx;
+
+ u32 acks;
+ u32 reqs;
+ u32 rsts;
+};
+
+struct ixgbe_mbx_info {
+ struct ixgbe_mbx_operations ops;
+ struct ixgbe_mbx_stats stats;
+ u32 timeout;
+ u32 usec_delay;
+ u32 v2p_mailbox;
+ u16 size;
+};
+
struct ixgbe_hw {
u8 __iomem *hw_addr;
void *back;
@@ -2472,6 +2532,7 @@ struct ixgbe_hw {
struct ixgbe_phy_info phy;
struct ixgbe_eeprom_info eeprom;
struct ixgbe_bus_info bus;
+ struct ixgbe_mbx_info mbx;
u16 device_id;
u16 vendor_id;
u16 subsystem_device_id;
@@ -2486,6 +2547,7 @@ struct ixgbe_info {
struct ixgbe_mac_operations *mac_ops;
struct ixgbe_eeprom_operations *eeprom_ops;
struct ixgbe_phy_operations *phy_ops;
+ struct ixgbe_mbx_operations *mbx_ops;
};
diff --git a/drivers/net/ixgbevf/Makefile b/drivers/net/ixgbevf/Makefile
new file mode 100644
index 000000000000..dd4e0d27e8cc
--- /dev/null
+++ b/drivers/net/ixgbevf/Makefile
@@ -0,0 +1,38 @@
+################################################################################
+#
+# Intel 82599 Virtual Function driver
+# Copyright(c) 1999 - 2009 Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) 82599 VF ethernet driver
+#
+
+obj-$(CONFIG_IXGBEVF) += ixgbevf.o
+
+ixgbevf-objs := vf.o \
+ mbx.o \
+ ethtool.o \
+ ixgbevf_main.o
+
diff --git a/drivers/net/ixgbevf/defines.h b/drivers/net/ixgbevf/defines.h
new file mode 100644
index 000000000000..c44fdb05447a
--- /dev/null
+++ b/drivers/net/ixgbevf/defines.h
@@ -0,0 +1,292 @@
+/*******************************************************************************
+
+ Intel 82599 Virtual Function driver
+ Copyright(c) 1999 - 2009 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBEVF_DEFINES_H_
+#define _IXGBEVF_DEFINES_H_
+
+/* Device IDs */
+#define IXGBE_DEV_ID_82599_VF 0x10ED
+
+#define IXGBE_VF_IRQ_CLEAR_MASK 7
+#define IXGBE_VF_MAX_TX_QUEUES 1
+#define IXGBE_VF_MAX_RX_QUEUES 1
+#define IXGBE_ETH_LENGTH_OF_ADDRESS 6
+
+/* Link speed */
+typedef u32 ixgbe_link_speed;
+#define IXGBE_LINK_SPEED_1GB_FULL 0x0020
+#define IXGBE_LINK_SPEED_10GB_FULL 0x0080
+
+#define IXGBE_CTRL_RST 0x04000000 /* Reset (SW) */
+#define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */
+#define IXGBE_TXDCTL_ENABLE 0x02000000 /* Enable specific Tx Queue */
+#define IXGBE_LINKS_UP 0x40000000
+#define IXGBE_LINKS_SPEED 0x20000000
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE 8
+#define IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE 8
+#define IXGBE_REQ_TX_BUFFER_GRANULARITY 1024
+
+/* Interrupt Vector Allocation Registers */
+#define IXGBE_IVAR_ALLOC_VAL 0x80 /* Interrupt Allocation valid */
+
+#define IXGBE_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */
+
+/* Receive Config masks */
+#define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */
+#define IXGBE_RXCTRL_DMBYPS 0x00000002 /* Descriptor Monitor Bypass */
+#define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */
+#define IXGBE_RXDCTL_VME 0x40000000 /* VLAN mode enable */
+
+/* DCA Control */
+#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */
+
+/* PSRTYPE bit definitions */
+#define IXGBE_PSRTYPE_TCPHDR 0x00000010
+#define IXGBE_PSRTYPE_UDPHDR 0x00000020
+#define IXGBE_PSRTYPE_IPV4HDR 0x00000100
+#define IXGBE_PSRTYPE_IPV6HDR 0x00000200
+#define IXGBE_PSRTYPE_L2HDR 0x00001000
+
+/* SRRCTL bit definitions */
+#define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10 /* so many KBs */
+#define IXGBE_SRRCTL_RDMTS_SHIFT 22
+#define IXGBE_SRRCTL_RDMTS_MASK 0x01C00000
+#define IXGBE_SRRCTL_DROP_EN 0x10000000
+#define IXGBE_SRRCTL_BSIZEPKT_MASK 0x0000007F
+#define IXGBE_SRRCTL_BSIZEHDR_MASK 0x00003F00
+#define IXGBE_SRRCTL_DESCTYPE_LEGACY 0x00000000
+#define IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
+#define IXGBE_SRRCTL_DESCTYPE_MASK 0x0E000000
+
+/* Receive Descriptor bit definitions */
+#define IXGBE_RXD_STAT_DD 0x01 /* Descriptor Done */
+#define IXGBE_RXD_STAT_EOP 0x02 /* End of Packet */
+#define IXGBE_RXD_STAT_FLM 0x04 /* FDir Match */
+#define IXGBE_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
+#define IXGBE_RXDADV_NEXTP_MASK 0x000FFFF0 /* Next Descriptor Index */
+#define IXGBE_RXDADV_NEXTP_SHIFT 0x00000004
+#define IXGBE_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */
+#define IXGBE_RXD_STAT_L4CS 0x20 /* L4 xsum calculated */
+#define IXGBE_RXD_STAT_IPCS 0x40 /* IP xsum calculated */
+#define IXGBE_RXD_STAT_PIF 0x80 /* passed in-exact filter */
+#define IXGBE_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */
+#define IXGBE_RXD_STAT_VEXT 0x200 /* 1st VLAN found */
+#define IXGBE_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */
+#define IXGBE_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */
+#define IXGBE_RXD_STAT_TS 0x10000 /* Time Stamp */
+#define IXGBE_RXD_STAT_SECP 0x20000 /* Security Processing */
+#define IXGBE_RXD_STAT_LB 0x40000 /* Loopback Status */
+#define IXGBE_RXD_STAT_ACK 0x8000 /* ACK Packet indication */
+#define IXGBE_RXD_ERR_CE 0x01 /* CRC Error */
+#define IXGBE_RXD_ERR_LE 0x02 /* Length Error */
+#define IXGBE_RXD_ERR_PE 0x08 /* Packet Error */
+#define IXGBE_RXD_ERR_OSE 0x10 /* Oversize Error */
+#define IXGBE_RXD_ERR_USE 0x20 /* Undersize Error */
+#define IXGBE_RXD_ERR_TCPE 0x40 /* TCP/UDP Checksum Error */
+#define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */
+#define IXGBE_RXDADV_ERR_MASK 0xFFF00000 /* RDESC.ERRORS mask */
+#define IXGBE_RXDADV_ERR_SHIFT 20 /* RDESC.ERRORS shift */
+#define IXGBE_RXDADV_ERR_HBO 0x00800000 /*Header Buffer Overflow */
+#define IXGBE_RXDADV_ERR_CE 0x01000000 /* CRC Error */
+#define IXGBE_RXDADV_ERR_LE 0x02000000 /* Length Error */
+#define IXGBE_RXDADV_ERR_PE 0x08000000 /* Packet Error */
+#define IXGBE_RXDADV_ERR_OSE 0x10000000 /* Oversize Error */
+#define IXGBE_RXDADV_ERR_USE 0x20000000 /* Undersize Error */
+#define IXGBE_RXDADV_ERR_TCPE 0x40000000 /* TCP/UDP Checksum Error */
+#define IXGBE_RXDADV_ERR_IPE 0x80000000 /* IP Checksum Error */
+#define IXGBE_RXD_VLAN_ID_MASK 0x0FFF /* VLAN ID is in lower 12 bits */
+#define IXGBE_RXD_PRI_MASK 0xE000 /* Priority is in upper 3 bits */
+#define IXGBE_RXD_PRI_SHIFT 13
+#define IXGBE_RXD_CFI_MASK 0x1000 /* CFI is bit 12 */
+#define IXGBE_RXD_CFI_SHIFT 12
+
+#define IXGBE_RXDADV_STAT_DD IXGBE_RXD_STAT_DD /* Done */
+#define IXGBE_RXDADV_STAT_EOP IXGBE_RXD_STAT_EOP /* End of Packet */
+#define IXGBE_RXDADV_STAT_FLM IXGBE_RXD_STAT_FLM /* FDir Match */
+#define IXGBE_RXDADV_STAT_VP IXGBE_RXD_STAT_VP /* IEEE VLAN Pkt */
+#define IXGBE_RXDADV_STAT_MASK 0x000FFFFF /* Stat/NEXTP: bit 0-19 */
+#define IXGBE_RXDADV_STAT_FCEOFS 0x00000040 /* FCoE EOF/SOF Stat */
+#define IXGBE_RXDADV_STAT_FCSTAT 0x00000030 /* FCoE Pkt Stat */
+#define IXGBE_RXDADV_STAT_FCSTAT_NOMTCH 0x00000000 /* 00: No Ctxt Match */
+#define IXGBE_RXDADV_STAT_FCSTAT_NODDP 0x00000010 /* 01: Ctxt w/o DDP */
+#define IXGBE_RXDADV_STAT_FCSTAT_FCPRSP 0x00000020 /* 10: Recv. FCP_RSP */
+#define IXGBE_RXDADV_STAT_FCSTAT_DDP 0x00000030 /* 11: Ctxt w/ DDP */
+
+#define IXGBE_RXDADV_RSSTYPE_MASK 0x0000000F
+#define IXGBE_RXDADV_PKTTYPE_MASK 0x0000FFF0
+#define IXGBE_RXDADV_PKTTYPE_MASK_EX 0x0001FFF0
+#define IXGBE_RXDADV_HDRBUFLEN_MASK 0x00007FE0
+#define IXGBE_RXDADV_RSCCNT_MASK 0x001E0000
+#define IXGBE_RXDADV_RSCCNT_SHIFT 17
+#define IXGBE_RXDADV_HDRBUFLEN_SHIFT 5
+#define IXGBE_RXDADV_SPLITHEADER_EN 0x00001000
+#define IXGBE_RXDADV_SPH 0x8000
+
+#define IXGBE_RXD_ERR_FRAME_ERR_MASK ( \
+ IXGBE_RXD_ERR_CE | \
+ IXGBE_RXD_ERR_LE | \
+ IXGBE_RXD_ERR_PE | \
+ IXGBE_RXD_ERR_OSE | \
+ IXGBE_RXD_ERR_USE)
+
+#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK ( \
+ IXGBE_RXDADV_ERR_CE | \
+ IXGBE_RXDADV_ERR_LE | \
+ IXGBE_RXDADV_ERR_PE | \
+ IXGBE_RXDADV_ERR_OSE | \
+ IXGBE_RXDADV_ERR_USE)
+
+#define IXGBE_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
+#define IXGBE_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
+#define IXGBE_TXD_CMD_EOP 0x01000000 /* End of Packet */
+#define IXGBE_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define IXGBE_TXD_CMD_IC 0x04000000 /* Insert Checksum */
+#define IXGBE_TXD_CMD_RS 0x08000000 /* Report Status */
+#define IXGBE_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
+#define IXGBE_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
+#define IXGBE_TXD_STAT_DD 0x00000001 /* Descriptor Done */
+
+/* Transmit Descriptor - Advanced */
+union ixgbe_adv_tx_desc {
+ struct {
+ __le64 buffer_addr; /* Address of descriptor's data buf */
+ __le32 cmd_type_len;
+ __le32 olinfo_status;
+ } read;
+ struct {
+ __le64 rsvd; /* Reserved */
+ __le32 nxtseq_seed;
+ __le32 status;
+ } wb;
+};
+
+/* Receive Descriptor - Advanced */
+union ixgbe_adv_rx_desc {
+ struct {
+ __le64 pkt_addr; /* Packet buffer address */
+ __le64 hdr_addr; /* Header buffer address */
+ } read;
+ struct {
+ struct {
+ union {
+ __le32 data;
+ struct {
+ __le16 pkt_info; /* RSS, Pkt type */
+ __le16 hdr_info; /* Splithdr, hdrlen */
+ } hs_rss;
+ } lo_dword;
+ union {
+ __le32 rss; /* RSS Hash */
+ struct {
+ __le16 ip_id; /* IP id */
+ __le16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ __le32 status_error; /* ext status/error */
+ __le16 length; /* Packet length */
+ __le16 vlan; /* VLAN tag */
+ } upper;
+ } wb; /* writeback */
+};
+
+/* Context descriptors */
+struct ixgbe_adv_tx_context_desc {
+ __le32 vlan_macip_lens;
+ __le32 seqnum_seed;
+ __le32 type_tucmd_mlhl;
+ __le32 mss_l4len_idx;
+};
+
+/* Adv Transmit Descriptor Config Masks */
+#define IXGBE_ADVTXD_DTYP_MASK 0x00F00000 /* DTYP mask */
+#define IXGBE_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Desc */
+#define IXGBE_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
+#define IXGBE_ADVTXD_DCMD_EOP IXGBE_TXD_CMD_EOP /* End of Packet */
+#define IXGBE_ADVTXD_DCMD_IFCS IXGBE_TXD_CMD_IFCS /* Insert FCS */
+#define IXGBE_ADVTXD_DCMD_RS IXGBE_TXD_CMD_RS /* Report Status */
+#define IXGBE_ADVTXD_DCMD_DEXT IXGBE_TXD_CMD_DEXT /* Desc ext (1=Adv) */
+#define IXGBE_ADVTXD_DCMD_VLE IXGBE_TXD_CMD_VLE /* VLAN pkt enable */
+#define IXGBE_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */
+#define IXGBE_ADVTXD_STAT_DD IXGBE_TXD_STAT_DD /* Descriptor Done */
+#define IXGBE_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */
+#define IXGBE_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */
+#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */
+#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */
+#define IXGBE_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 Packet TYPE of SCTP */
+#define IXGBE_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */
+#define IXGBE_ADVTXD_POPTS_SHIFT 8 /* Adv desc POPTS shift */
+#define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \
+ IXGBE_ADVTXD_POPTS_SHIFT)
+#define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \
+ IXGBE_ADVTXD_POPTS_SHIFT)
+#define IXGBE_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
+#define IXGBE_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
+#define IXGBE_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */
+#define IXGBE_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
+#define IXGBE_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
+
+/* Interrupt register bitmasks */
+
+/* Extended Interrupt Cause Read */
+#define IXGBE_EICR_RTX_QUEUE 0x0000FFFF /* RTx Queue Interrupt */
+#define IXGBE_EICR_MAILBOX 0x00080000 /* VF to PF Mailbox Interrupt */
+#define IXGBE_EICR_OTHER 0x80000000 /* Interrupt Cause Active */
+
+/* Extended Interrupt Cause Set */
+#define IXGBE_EICS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EICS_MAILBOX IXGBE_EICR_MAILBOX /* VF to PF Mailbox Int */
+#define IXGBE_EICS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */
+
+/* Extended Interrupt Mask Set */
+#define IXGBE_EIMS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EIMS_MAILBOX IXGBE_EICR_MAILBOX /* VF to PF Mailbox Int */
+#define IXGBE_EIMS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */
+
+/* Extended Interrupt Mask Clear */
+#define IXGBE_EIMC_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EIMC_MAILBOX IXGBE_EICR_MAILBOX /* VF to PF Mailbox Int */
+#define IXGBE_EIMC_OTHER IXGBE_EICR_OTHER /* INT Cause Active */
+
+#define IXGBE_EIMS_ENABLE_MASK ( \
+ IXGBE_EIMS_RTX_QUEUE | \
+ IXGBE_EIMS_MAILBOX | \
+ IXGBE_EIMS_OTHER)
+
+#define IXGBE_EITR_CNT_WDIS 0x80000000
+
+/* Error Codes */
+#define IXGBE_ERR_INVALID_MAC_ADDR -1
+#define IXGBE_ERR_RESET_FAILED -2
+
+#endif /* _IXGBEVF_DEFINES_H_ */
diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c
new file mode 100644
index 000000000000..399be0c34c36
--- /dev/null
+++ b/drivers/net/ixgbevf/ethtool.c
@@ -0,0 +1,716 @@
+/*******************************************************************************
+
+ Intel 82599 Virtual Function driver
+ Copyright(c) 1999 - 2009 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for ixgbevf */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/vmalloc.h>
+#include <linux/if_vlan.h>
+#include <linux/uaccess.h>
+
+#include "ixgbevf.h"
+
+#define IXGBE_ALL_RAR_ENTRIES 16
+
+#ifdef ETHTOOL_GSTATS
+struct ixgbe_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+ int base_stat_offset;
+};
+
+#define IXGBEVF_STAT(m, b) sizeof(((struct ixgbevf_adapter *)0)->m), \
+ offsetof(struct ixgbevf_adapter, m), \
+ offsetof(struct ixgbevf_adapter, b)
+static struct ixgbe_stats ixgbe_gstrings_stats[] = {
+ {"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc)},
+ {"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc)},
+ {"rx_bytes", IXGBEVF_STAT(stats.vfgorc, stats.base_vfgorc)},
+ {"tx_bytes", IXGBEVF_STAT(stats.vfgotc, stats.base_vfgotc)},
+ {"tx_busy", IXGBEVF_STAT(tx_busy, zero_base)},
+ {"multicast", IXGBEVF_STAT(stats.vfmprc, stats.base_vfmprc)},
+ {"rx_csum_offload_good", IXGBEVF_STAT(hw_csum_rx_good, zero_base)},
+ {"rx_csum_offload_errors", IXGBEVF_STAT(hw_csum_rx_error, zero_base)},
+ {"tx_csum_offload_ctxt", IXGBEVF_STAT(hw_csum_tx_good, zero_base)},
+ {"rx_header_split", IXGBEVF_STAT(rx_hdr_split, zero_base)},
+};
+
+#define IXGBE_QUEUE_STATS_LEN 0
+#define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats)
+
+#define IXGBEVF_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN)
+#endif /* ETHTOOL_GSTATS */
+#ifdef ETHTOOL_TEST
+static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = {
+ "Register test (offline)",
+ "Link test (on/offline)"
+};
+#define IXGBE_TEST_LEN (sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN)
+#endif /* ETHTOOL_TEST */
+
+static int ixgbevf_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 link_speed = 0;
+ bool link_up;
+
+ ecmd->supported = SUPPORTED_10000baseT_Full;
+ ecmd->autoneg = AUTONEG_DISABLE;
+ ecmd->transceiver = XCVR_DUMMY1;
+ ecmd->port = -1;
+
+ hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
+
+ if (link_up) {
+ ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
+ SPEED_10000 : SPEED_1000;
+ ecmd->duplex = DUPLEX_FULL;
+ } else {
+ ecmd->speed = -1;
+ ecmd->duplex = -1;
+ }
+
+ return 0;
+}
+
+static u32 ixgbevf_get_rx_csum(struct net_device *netdev)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ return adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED;
+}
+
+static int ixgbevf_set_rx_csum(struct net_device *netdev, u32 data)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ if (data)
+ adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
+ else
+ adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED;
+
+ if (netif_running(netdev)) {
+ if (!adapter->dev_closed)
+ ixgbevf_reinit_locked(adapter);
+ } else {
+ ixgbevf_reset(adapter);
+ }
+
+ return 0;
+}
+
+static int ixgbevf_set_tso(struct net_device *netdev, u32 data)
+{
+ if (data) {
+ netdev->features |= NETIF_F_TSO;
+ netdev->features |= NETIF_F_TSO6;
+ } else {
+ netif_tx_stop_all_queues(netdev);
+ netdev->features &= ~NETIF_F_TSO;
+ netdev->features &= ~NETIF_F_TSO6;
+ netif_tx_start_all_queues(netdev);
+ }
+ return 0;
+}
+
+static u32 ixgbevf_get_msglevel(struct net_device *netdev)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ return adapter->msg_enable;
+}
+
+static void ixgbevf_set_msglevel(struct net_device *netdev, u32 data)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ adapter->msg_enable = data;
+}
+
+#define IXGBE_GET_STAT(_A_, _R_) (_A_->stats._R_)
+
+static char *ixgbevf_reg_names[] = {
+ "IXGBE_VFCTRL",
+ "IXGBE_VFSTATUS",
+ "IXGBE_VFLINKS",
+ "IXGBE_VFRXMEMWRAP",
+ "IXGBE_VFRTIMER",
+ "IXGBE_VTEICR",
+ "IXGBE_VTEICS",
+ "IXGBE_VTEIMS",
+ "IXGBE_VTEIMC",
+ "IXGBE_VTEIAC",
+ "IXGBE_VTEIAM",
+ "IXGBE_VTEITR",
+ "IXGBE_VTIVAR",
+ "IXGBE_VTIVAR_MISC",
+ "IXGBE_VFRDBAL0",
+ "IXGBE_VFRDBAL1",
+ "IXGBE_VFRDBAH0",
+ "IXGBE_VFRDBAH1",
+ "IXGBE_VFRDLEN0",
+ "IXGBE_VFRDLEN1",
+ "IXGBE_VFRDH0",
+ "IXGBE_VFRDH1",
+ "IXGBE_VFRDT0",
+ "IXGBE_VFRDT1",
+ "IXGBE_VFRXDCTL0",
+ "IXGBE_VFRXDCTL1",
+ "IXGBE_VFSRRCTL0",
+ "IXGBE_VFSRRCTL1",
+ "IXGBE_VFPSRTYPE",
+ "IXGBE_VFTDBAL0",
+ "IXGBE_VFTDBAL1",
+ "IXGBE_VFTDBAH0",
+ "IXGBE_VFTDBAH1",
+ "IXGBE_VFTDLEN0",
+ "IXGBE_VFTDLEN1",
+ "IXGBE_VFTDH0",
+ "IXGBE_VFTDH1",
+ "IXGBE_VFTDT0",
+ "IXGBE_VFTDT1",
+ "IXGBE_VFTXDCTL0",
+ "IXGBE_VFTXDCTL1",
+ "IXGBE_VFTDWBAL0",
+ "IXGBE_VFTDWBAL1",
+ "IXGBE_VFTDWBAH0",
+ "IXGBE_VFTDWBAH1"
+};
+
+
+static int ixgbevf_get_regs_len(struct net_device *netdev)
+{
+ return (ARRAY_SIZE(ixgbevf_reg_names)) * sizeof(u32);
+}
+
+static void ixgbevf_get_regs(struct net_device *netdev,
+ struct ethtool_regs *regs,
+ void *p)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 *regs_buff = p;
+ u32 regs_len = ixgbevf_get_regs_len(netdev);
+ u8 i;
+
+ memset(p, 0, regs_len);
+
+ regs->version = (1 << 24) | hw->revision_id << 16 | hw->device_id;
+
+ /* General Registers */
+ regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_VFCTRL);
+ regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_VFSTATUS);
+ regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_VFLINKS);
+ regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_VFRXMEMWRAP);
+ regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_VFRTIMER);
+
+ /* Interrupt */
+ /* don't read EICR because it can clear interrupt causes, instead
+ * read EICS which is a shadow but doesn't clear EICR */
+ regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_VTEICS);
+ regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_VTEICS);
+ regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_VTEIMS);
+ regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_VTEIMC);
+ regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_VTEIAC);
+ regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_VTEIAM);
+ regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_VTEITR(0));
+ regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_VTIVAR(0));
+ regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_VTIVAR_MISC);
+
+ /* Receive DMA */
+ for (i = 0; i < 2; i++)
+ regs_buff[14 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDBAL(i));
+ for (i = 0; i < 2; i++)
+ regs_buff[16 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDBAH(i));
+ for (i = 0; i < 2; i++)
+ regs_buff[18 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDLEN(i));
+ for (i = 0; i < 2; i++)
+ regs_buff[20 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDH(i));
+ for (i = 0; i < 2; i++)
+ regs_buff[22 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDT(i));
+ for (i = 0; i < 2; i++)
+ regs_buff[24 + i] = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i));
+ for (i = 0; i < 2; i++)
+ regs_buff[26 + i] = IXGBE_READ_REG(hw, IXGBE_VFSRRCTL(i));
+
+ /* Receive */
+ regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_VFPSRTYPE);
+
+ /* Transmit */
+ for (i = 0; i < 2; i++)
+ regs_buff[29 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDBAL(i));
+ for (i = 0; i < 2; i++)
+ regs_buff[31 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDBAH(i));
+ for (i = 0; i < 2; i++)
+ regs_buff[33 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDLEN(i));
+ for (i = 0; i < 2; i++)
+ regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDH(i));
+ for (i = 0; i < 2; i++)
+ regs_buff[37 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDT(i));
+ for (i = 0; i < 2; i++)
+ regs_buff[39 + i] = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i));
+ for (i = 0; i < 2; i++)
+ regs_buff[41 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDWBAL(i));
+ for (i = 0; i < 2; i++)
+ regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDWBAH(i));
+
+ for (i = 0; i < ARRAY_SIZE(ixgbevf_reg_names); i++)
+ hw_dbg(hw, "%s\t%8.8x\n", ixgbevf_reg_names[i], regs_buff[i]);
+}
+
+static void ixgbevf_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+ strlcpy(drvinfo->driver, ixgbevf_driver_name, 32);
+ strlcpy(drvinfo->version, ixgbevf_driver_version, 32);
+
+ strlcpy(drvinfo->fw_version, "N/A", 4);
+ strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+}
+
+static void ixgbevf_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct ixgbevf_ring *tx_ring = adapter->tx_ring;
+ struct ixgbevf_ring *rx_ring = adapter->rx_ring;
+
+ ring->rx_max_pending = IXGBEVF_MAX_RXD;
+ ring->tx_max_pending = IXGBEVF_MAX_TXD;
+ ring->rx_mini_max_pending = 0;
+ ring->rx_jumbo_max_pending = 0;
+ ring->rx_pending = rx_ring->count;
+ ring->tx_pending = tx_ring->count;
+ ring->rx_mini_pending = 0;
+ ring->rx_jumbo_pending = 0;
+}
+
+static int ixgbevf_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct ixgbevf_ring *tx_ring = NULL, *rx_ring = NULL;
+ int i, err;
+ u32 new_rx_count, new_tx_count;
+ bool need_tx_update = false;
+ bool need_rx_update = false;
+
+ if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+ return -EINVAL;
+
+ new_rx_count = max(ring->rx_pending, (u32)IXGBEVF_MIN_RXD);
+ new_rx_count = min(new_rx_count, (u32)IXGBEVF_MAX_RXD);
+ new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE);
+
+ new_tx_count = max(ring->tx_pending, (u32)IXGBEVF_MIN_TXD);
+ new_tx_count = min(new_tx_count, (u32)IXGBEVF_MAX_TXD);
+ new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE);
+
+ if ((new_tx_count == adapter->tx_ring->count) &&
+ (new_rx_count == adapter->rx_ring->count)) {
+ /* nothing to do */
+ return 0;
+ }
+
+ while (test_and_set_bit(__IXGBEVF_RESETTING, &adapter->state))
+ msleep(1);
+
+ if (new_tx_count != adapter->tx_ring_count) {
+ tx_ring = kcalloc(adapter->num_tx_queues,
+ sizeof(struct ixgbevf_ring), GFP_KERNEL);
+ if (!tx_ring) {
+ err = -ENOMEM;
+ goto err_setup;
+ }
+ memcpy(tx_ring, adapter->tx_ring,
+ adapter->num_tx_queues * sizeof(struct ixgbevf_ring));
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ tx_ring[i].count = new_tx_count;
+ err = ixgbevf_setup_tx_resources(adapter,
+ &tx_ring[i]);
+ if (err) {
+ while (i) {
+ i--;
+ ixgbevf_free_tx_resources(adapter,
+ &tx_ring[i]);
+ }
+ kfree(tx_ring);
+ goto err_setup;
+ }
+ tx_ring[i].v_idx = adapter->tx_ring[i].v_idx;
+ }
+ need_tx_update = true;
+ }
+
+ if (new_rx_count != adapter->rx_ring_count) {
+ rx_ring = kcalloc(adapter->num_rx_queues,
+ sizeof(struct ixgbevf_ring), GFP_KERNEL);
+ if ((!rx_ring) && (need_tx_update)) {
+ err = -ENOMEM;
+ goto err_rx_setup;
+ }
+ memcpy(rx_ring, adapter->rx_ring,
+ adapter->num_rx_queues * sizeof(struct ixgbevf_ring));
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ rx_ring[i].count = new_rx_count;
+ err = ixgbevf_setup_rx_resources(adapter,
+ &rx_ring[i]);
+ if (err) {
+ while (i) {
+ i--;
+ ixgbevf_free_rx_resources(adapter,
+ &rx_ring[i]);
+ }
+ kfree(rx_ring);
+ goto err_rx_setup;
+ }
+ rx_ring[i].v_idx = adapter->rx_ring[i].v_idx;
+ }
+ need_rx_update = true;
+ }
+
+err_rx_setup:
+ /* if rings need to be updated, here's the place to do it in one shot */
+ if (need_tx_update || need_rx_update) {
+ if (netif_running(netdev))
+ ixgbevf_down(adapter);
+ }
+
+ /* tx */
+ if (need_tx_update) {
+ kfree(adapter->tx_ring);
+ adapter->tx_ring = tx_ring;
+ tx_ring = NULL;
+ adapter->tx_ring_count = new_tx_count;
+ }
+
+ /* rx */
+ if (need_rx_update) {
+ kfree(adapter->rx_ring);
+ adapter->rx_ring = rx_ring;
+ rx_ring = NULL;
+ adapter->rx_ring_count = new_rx_count;
+ }
+
+ /* success! */
+ err = 0;
+ if (netif_running(netdev))
+ ixgbevf_up(adapter);
+
+err_setup:
+ clear_bit(__IXGBEVF_RESETTING, &adapter->state);
+ return err;
+}
+
+static int ixgbevf_get_sset_count(struct net_device *dev, int stringset)
+{
+ switch (stringset) {
+ case ETH_SS_TEST:
+ return IXGBE_TEST_LEN;
+ case ETH_SS_STATS:
+ return IXGBE_GLOBAL_STATS_LEN;
+ default:
+ return -EINVAL;
+ }
+}
+
+static void ixgbevf_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ int i;
+
+ ixgbevf_update_stats(adapter);
+ for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
+ char *p = (char *)adapter +
+ ixgbe_gstrings_stats[i].stat_offset;
+ char *b = (char *)adapter +
+ ixgbe_gstrings_stats[i].base_stat_offset;
+ data[i] = ((ixgbe_gstrings_stats[i].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p) -
+ ((ixgbe_gstrings_stats[i].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)b : *(u32 *)b);
+ }
+}
+
+static void ixgbevf_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *data)
+{
+ char *p = (char *)data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_TEST:
+ memcpy(data, *ixgbe_gstrings_test,
+ IXGBE_TEST_LEN * ETH_GSTRING_LEN);
+ break;
+ case ETH_SS_STATS:
+ for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
+ memcpy(p, ixgbe_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ }
+}
+
+static int ixgbevf_link_test(struct ixgbevf_adapter *adapter, u64 *data)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ bool link_up;
+ u32 link_speed = 0;
+ *data = 0;
+
+ hw->mac.ops.check_link(hw, &link_speed, &link_up, true);
+ if (!link_up)
+ *data = 1;
+
+ return *data;
+}
+
+/* ethtool register test data */
+struct ixgbevf_reg_test {
+ u16 reg;
+ u8 array_len;
+ u8 test_type;
+ u32 mask;
+ u32 write;
+};
+
+/* In the hardware, registers are laid out either singly, in arrays
+ * spaced 0x40 bytes apart, or in contiguous tables. We assume
+ * most tests take place on arrays or single registers (handled
+ * as a single-element array) and special-case the tables.
+ * Table tests are always pattern tests.
+ *
+ * We also make provision for some required setup steps by specifying
+ * registers to be written without any read-back testing.
+ */
+
+#define PATTERN_TEST 1
+#define SET_READ_TEST 2
+#define WRITE_NO_TEST 3
+#define TABLE32_TEST 4
+#define TABLE64_TEST_LO 5
+#define TABLE64_TEST_HI 6
+
+/* default VF register test */
+static struct ixgbevf_reg_test reg_test_vf[] = {
+ { IXGBE_VFRDBAL(0), 2, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
+ { IXGBE_VFRDBAH(0), 2, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+ { IXGBE_VFRDLEN(0), 2, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+ { IXGBE_VFRXDCTL(0), 2, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE },
+ { IXGBE_VFRDT(0), 2, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+ { IXGBE_VFRXDCTL(0), 2, WRITE_NO_TEST, 0, 0 },
+ { IXGBE_VFTDBAL(0), 2, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+ { IXGBE_VFTDBAH(0), 2, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+ { IXGBE_VFTDLEN(0), 2, PATTERN_TEST, 0x000FFF80, 0x000FFF80 },
+ { 0, 0, 0, 0 }
+};
+
+#define REG_PATTERN_TEST(R, M, W) \
+{ \
+ u32 pat, val, before; \
+ const u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \
+ for (pat = 0; pat < ARRAY_SIZE(_test); pat++) { \
+ before = readl(adapter->hw.hw_addr + R); \
+ writel((_test[pat] & W), (adapter->hw.hw_addr + R)); \
+ val = readl(adapter->hw.hw_addr + R); \
+ if (val != (_test[pat] & W & M)) { \
+ hw_dbg(&adapter->hw, \
+ "pattern test reg %04X failed: got " \
+ "0x%08X expected 0x%08X\n", \
+ R, val, (_test[pat] & W & M)); \
+ *data = R; \
+ writel(before, adapter->hw.hw_addr + R); \
+ return 1; \
+ } \
+ writel(before, adapter->hw.hw_addr + R); \
+ } \
+}
+
+#define REG_SET_AND_CHECK(R, M, W) \
+{ \
+ u32 val, before; \
+ before = readl(adapter->hw.hw_addr + R); \
+ writel((W & M), (adapter->hw.hw_addr + R)); \
+ val = readl(adapter->hw.hw_addr + R); \
+ if ((W & M) != (val & M)) { \
+ printk(KERN_ERR "set/check reg %04X test failed: got 0x%08X " \
+ "expected 0x%08X\n", R, (val & M), (W & M)); \
+ *data = R; \
+ writel(before, (adapter->hw.hw_addr + R)); \
+ return 1; \
+ } \
+ writel(before, (adapter->hw.hw_addr + R)); \
+}
+
+static int ixgbevf_reg_test(struct ixgbevf_adapter *adapter, u64 *data)
+{
+ struct ixgbevf_reg_test *test;
+ u32 i;
+
+ test = reg_test_vf;
+
+ /*
+ * Perform the register test, looping through the test table
+ * until we either fail or reach the null entry.
+ */
+ while (test->reg) {
+ for (i = 0; i < test->array_len; i++) {
+ switch (test->test_type) {
+ case PATTERN_TEST:
+ REG_PATTERN_TEST(test->reg + (i * 0x40),
+ test->mask,
+ test->write);
+ break;
+ case SET_READ_TEST:
+ REG_SET_AND_CHECK(test->reg + (i * 0x40),
+ test->mask,
+ test->write);
+ break;
+ case WRITE_NO_TEST:
+ writel(test->write,
+ (adapter->hw.hw_addr + test->reg)
+ + (i * 0x40));
+ break;
+ case TABLE32_TEST:
+ REG_PATTERN_TEST(test->reg + (i * 4),
+ test->mask,
+ test->write);
+ break;
+ case TABLE64_TEST_LO:
+ REG_PATTERN_TEST(test->reg + (i * 8),
+ test->mask,
+ test->write);
+ break;
+ case TABLE64_TEST_HI:
+ REG_PATTERN_TEST((test->reg + 4) + (i * 8),
+ test->mask,
+ test->write);
+ break;
+ }
+ }
+ test++;
+ }
+
+ *data = 0;
+ return *data;
+}
+
+static void ixgbevf_diag_test(struct net_device *netdev,
+ struct ethtool_test *eth_test, u64 *data)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ bool if_running = netif_running(netdev);
+
+ set_bit(__IXGBEVF_TESTING, &adapter->state);
+ if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+ /* Offline tests */
+
+ hw_dbg(&adapter->hw, "offline testing starting\n");
+
+ /* Link test performed before hardware reset so autoneg doesn't
+ * interfere with test result */
+ if (ixgbevf_link_test(adapter, &data[1]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ if (if_running)
+ /* indicate we're in test mode */
+ dev_close(netdev);
+ else
+ ixgbevf_reset(adapter);
+
+ hw_dbg(&adapter->hw, "register testing starting\n");
+ if (ixgbevf_reg_test(adapter, &data[0]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ ixgbevf_reset(adapter);
+
+ clear_bit(__IXGBEVF_TESTING, &adapter->state);
+ if (if_running)
+ dev_open(netdev);
+ } else {
+ hw_dbg(&adapter->hw, "online testing starting\n");
+ /* Online tests */
+ if (ixgbevf_link_test(adapter, &data[1]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ /* Online tests aren't run; pass by default */
+ data[0] = 0;
+
+ clear_bit(__IXGBEVF_TESTING, &adapter->state);
+ }
+ msleep_interruptible(4 * 1000);
+}
+
+static int ixgbevf_nway_reset(struct net_device *netdev)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+ if (netif_running(netdev)) {
+ if (!adapter->dev_closed)
+ ixgbevf_reinit_locked(adapter);
+ }
+
+ return 0;
+}
+
+static struct ethtool_ops ixgbevf_ethtool_ops = {
+ .get_settings = ixgbevf_get_settings,
+ .get_drvinfo = ixgbevf_get_drvinfo,
+ .get_regs_len = ixgbevf_get_regs_len,
+ .get_regs = ixgbevf_get_regs,
+ .nway_reset = ixgbevf_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_ringparam = ixgbevf_get_ringparam,
+ .set_ringparam = ixgbevf_set_ringparam,
+ .get_rx_csum = ixgbevf_get_rx_csum,
+ .set_rx_csum = ixgbevf_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_ipv6_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_msglevel = ixgbevf_get_msglevel,
+ .set_msglevel = ixgbevf_set_msglevel,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ixgbevf_set_tso,
+ .self_test = ixgbevf_diag_test,
+ .get_sset_count = ixgbevf_get_sset_count,
+ .get_strings = ixgbevf_get_strings,
+ .get_ethtool_stats = ixgbevf_get_ethtool_stats,
+};
+
+void ixgbevf_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &ixgbevf_ethtool_ops);
+}
diff --git a/drivers/net/ixgbevf/ixgbevf.h b/drivers/net/ixgbevf/ixgbevf.h
new file mode 100644
index 000000000000..f7015efbff05
--- /dev/null
+++ b/drivers/net/ixgbevf/ixgbevf.h
@@ -0,0 +1,318 @@
+/*******************************************************************************
+
+ Intel 82599 Virtual Function driver
+ Copyright(c) 1999 - 2009 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBEVF_H_
+#define _IXGBEVF_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+
+#include "vf.h"
+
+/* wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer */
+struct ixgbevf_tx_buffer {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ unsigned long time_stamp;
+ u16 length;
+ u16 next_to_watch;
+ u16 mapped_as_page;
+};
+
+struct ixgbevf_rx_buffer {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ struct page *page;
+ dma_addr_t page_dma;
+ unsigned int page_offset;
+};
+
+struct ixgbevf_ring {
+ struct ixgbevf_adapter *adapter; /* backlink */
+ void *desc; /* descriptor ring memory */
+ dma_addr_t dma; /* phys. address of descriptor ring */
+ unsigned int size; /* length in bytes */
+ unsigned int count; /* amount of descriptors */
+ unsigned int next_to_use;
+ unsigned int next_to_clean;
+
+ int queue_index; /* needed for multiqueue queue management */
+ union {
+ struct ixgbevf_tx_buffer *tx_buffer_info;
+ struct ixgbevf_rx_buffer *rx_buffer_info;
+ };
+
+ u16 head;
+ u16 tail;
+
+ unsigned int total_bytes;
+ unsigned int total_packets;
+
+ u16 reg_idx; /* holds the special value that gets the hardware register
+ * offset associated with this ring, which is different
+ * for DCB and RSS modes */
+
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
+ /* cpu for tx queue */
+ int cpu;
+#endif
+
+ u64 v_idx; /* maps directly to the index for this ring in the hardware
+ * vector array, can also be used for finding the bit in EICR
+ * and friends that represents the vector for this ring */
+
+ u16 work_limit; /* max work per interrupt */
+ u16 rx_buf_len;
+};
+
+enum ixgbevf_ring_f_enum {
+ RING_F_NONE = 0,
+ RING_F_ARRAY_SIZE /* must be last in enum set */
+};
+
+struct ixgbevf_ring_feature {
+ int indices;
+ int mask;
+};
+
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define IXGBEVF_RX_BUFFER_WRITE 16 /* Must be power of 2 */
+
+#define MAX_RX_QUEUES 1
+#define MAX_TX_QUEUES 1
+
+#define IXGBEVF_DEFAULT_TXD 1024
+#define IXGBEVF_DEFAULT_RXD 512
+#define IXGBEVF_MAX_TXD 4096
+#define IXGBEVF_MIN_TXD 64
+#define IXGBEVF_MAX_RXD 4096
+#define IXGBEVF_MIN_RXD 64
+
+/* Supported Rx Buffer Sizes */
+#define IXGBEVF_RXBUFFER_64 64 /* Used for packet split */
+#define IXGBEVF_RXBUFFER_128 128 /* Used for packet split */
+#define IXGBEVF_RXBUFFER_256 256 /* Used for packet split */
+#define IXGBEVF_RXBUFFER_2048 2048
+#define IXGBEVF_MAX_RXBUFFER 16384 /* largest size for single descriptor */
+
+#define IXGBEVF_RX_HDR_SIZE IXGBEVF_RXBUFFER_256
+
+#define MAXIMUM_ETHERNET_VLAN_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
+
+#define IXGBE_TX_FLAGS_CSUM (u32)(1)
+#define IXGBE_TX_FLAGS_VLAN (u32)(1 << 1)
+#define IXGBE_TX_FLAGS_TSO (u32)(1 << 2)
+#define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3)
+#define IXGBE_TX_FLAGS_FCOE (u32)(1 << 4)
+#define IXGBE_TX_FLAGS_FSO (u32)(1 << 5)
+#define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000
+#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000
+#define IXGBE_TX_FLAGS_VLAN_SHIFT 16
+
+/* MAX_MSIX_Q_VECTORS of these are allocated,
+ * but we only use one per queue-specific vector.
+ */
+struct ixgbevf_q_vector {
+ struct ixgbevf_adapter *adapter;
+ struct napi_struct napi;
+ DECLARE_BITMAP(rxr_idx, MAX_RX_QUEUES); /* Rx ring indices */
+ DECLARE_BITMAP(txr_idx, MAX_TX_QUEUES); /* Tx ring indices */
+ u8 rxr_count; /* Rx ring count assigned to this vector */
+ u8 txr_count; /* Tx ring count assigned to this vector */
+ u8 tx_itr;
+ u8 rx_itr;
+ u32 eitr;
+ int v_idx; /* vector index in list */
+};
+
+/* Helper macros to switch between ints/sec and what the register uses.
+ * And yes, it's the same math going both ways. The lowest value
+ * supported by all of the ixgbe hardware is 8.
+ */
+#define EITR_INTS_PER_SEC_TO_REG(_eitr) \
+ ((_eitr) ? (1000000000 / ((_eitr) * 256)) : 8)
+#define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG
+
+#define IXGBE_DESC_UNUSED(R) \
+ ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+ (R)->next_to_clean - (R)->next_to_use - 1)
+
+#define IXGBE_RX_DESC_ADV(R, i) \
+ (&(((union ixgbe_adv_rx_desc *)((R).desc))[i]))
+#define IXGBE_TX_DESC_ADV(R, i) \
+ (&(((union ixgbe_adv_tx_desc *)((R).desc))[i]))
+#define IXGBE_TX_CTXTDESC_ADV(R, i) \
+ (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i]))
+
+#define IXGBE_MAX_JUMBO_FRAME_SIZE 16128
+
+#define OTHER_VECTOR 1
+#define NON_Q_VECTORS (OTHER_VECTOR)
+
+#define MAX_MSIX_Q_VECTORS 2
+#define MAX_MSIX_COUNT 2
+
+#define MIN_MSIX_Q_VECTORS 2
+#define MIN_MSIX_COUNT (MIN_MSIX_Q_VECTORS + NON_Q_VECTORS)
+
+/* board specific private data structure */
+struct ixgbevf_adapter {
+ struct timer_list watchdog_timer;
+#ifdef NETIF_F_HW_VLAN_TX
+ struct vlan_group *vlgrp;
+#endif
+ u16 bd_number;
+ struct work_struct reset_task;
+ struct ixgbevf_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
+ char name[MAX_MSIX_COUNT][IFNAMSIZ + 9];
+
+ /* Interrupt Throttle Rate */
+ u32 itr_setting;
+ u16 eitr_low;
+ u16 eitr_high;
+
+ /* TX */
+ struct ixgbevf_ring *tx_ring; /* One per active queue */
+ int num_tx_queues;
+ u64 restart_queue;
+ u64 hw_csum_tx_good;
+ u64 lsc_int;
+ u64 hw_tso_ctxt;
+ u64 hw_tso6_ctxt;
+ u32 tx_timeout_count;
+ bool detect_tx_hung;
+
+ /* RX */
+ struct ixgbevf_ring *rx_ring; /* One per active queue */
+ int num_rx_queues;
+ int num_rx_pools; /* == num_rx_queues in 82598 */
+ int num_rx_queues_per_pool; /* 1 if 82598, can be many if 82599 */
+ u64 hw_csum_rx_error;
+ u64 hw_rx_no_dma_resources;
+ u64 hw_csum_rx_good;
+ u64 non_eop_descs;
+ int num_msix_vectors;
+ int max_msix_q_vectors; /* true count of q_vectors for device */
+ struct ixgbevf_ring_feature ring_feature[RING_F_ARRAY_SIZE];
+ struct msix_entry *msix_entries;
+
+ u64 rx_hdr_split;
+ u32 alloc_rx_page_failed;
+ u32 alloc_rx_buff_failed;
+
+ /* Some features need tri-state capability,
+ * thus the additional *_CAPABLE flags.
+ */
+ u32 flags;
+#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1)
+#define IXGBE_FLAG_RX_1BUF_CAPABLE (u32)(1 << 1)
+#define IXGBE_FLAG_RX_PS_CAPABLE (u32)(1 << 2)
+#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 3)
+#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 4)
+#define IXGBE_FLAG_IMIR_ENABLED (u32)(1 << 5)
+#define IXGBE_FLAG_MQ_CAPABLE (u32)(1 << 6)
+#define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 7)
+#define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 8)
+ /* OS defined structs */
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct net_device_stats net_stats;
+
+ /* structs defined in ixgbe_vf.h */
+ struct ixgbe_hw hw;
+ u16 msg_enable;
+ struct ixgbevf_hw_stats stats;
+ u64 zero_base;
+ /* Interrupt Throttle Rate */
+ u32 eitr_param;
+
+ unsigned long state;
+ u32 *config_space;
+ u64 tx_busy;
+ unsigned int tx_ring_count;
+ unsigned int rx_ring_count;
+
+ u32 link_speed;
+ bool link_up;
+ unsigned long link_check_timeout;
+
+ struct work_struct watchdog_task;
+ bool netdev_registered;
+ bool dev_closed;
+};
+
+enum ixbgevf_state_t {
+ __IXGBEVF_TESTING,
+ __IXGBEVF_RESETTING,
+ __IXGBEVF_DOWN
+};
+
+enum ixgbevf_boards {
+ board_82599_vf,
+};
+
+extern struct ixgbevf_info ixgbevf_vf_info;
+extern struct ixgbe_mac_operations ixgbevf_mbx_ops;
+
+/* needed by ethtool.c */
+extern char ixgbevf_driver_name[];
+extern const char ixgbevf_driver_version[];
+
+extern int ixgbevf_up(struct ixgbevf_adapter *adapter);
+extern void ixgbevf_down(struct ixgbevf_adapter *adapter);
+extern void ixgbevf_reinit_locked(struct ixgbevf_adapter *adapter);
+extern void ixgbevf_reset(struct ixgbevf_adapter *adapter);
+extern void ixgbevf_set_ethtool_ops(struct net_device *netdev);
+extern int ixgbevf_setup_rx_resources(struct ixgbevf_adapter *,
+ struct ixgbevf_ring *);
+extern int ixgbevf_setup_tx_resources(struct ixgbevf_adapter *,
+ struct ixgbevf_ring *);
+extern void ixgbevf_free_rx_resources(struct ixgbevf_adapter *,
+ struct ixgbevf_ring *);
+extern void ixgbevf_free_tx_resources(struct ixgbevf_adapter *,
+ struct ixgbevf_ring *);
+extern void ixgbevf_update_stats(struct ixgbevf_adapter *adapter);
+
+#ifdef ETHTOOL_OPS_COMPAT
+extern int ethtool_ioctl(struct ifreq *ifr);
+
+#endif
+extern void ixgbe_napi_add_all(struct ixgbevf_adapter *adapter);
+extern void ixgbe_napi_del_all(struct ixgbevf_adapter *adapter);
+
+#ifdef DEBUG
+extern char *ixgbevf_get_hw_dev_name(struct ixgbe_hw *hw);
+#define hw_dbg(hw, format, arg...) \
+ printk(KERN_DEBUG "%s: " format, ixgbevf_get_hw_dev_name(hw), ##arg)
+#else
+#define hw_dbg(hw, format, arg...) do {} while (0)
+#endif
+
+#endif /* _IXGBEVF_H_ */
diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c
new file mode 100644
index 000000000000..ca653c49b765
--- /dev/null
+++ b/drivers/net/ixgbevf/ixgbevf_main.c
@@ -0,0 +1,3578 @@
+/*******************************************************************************
+
+ Intel 82599 Virtual Function driver
+ Copyright(c) 1999 - 2009 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+/******************************************************************************
+ Copyright (c)2006 - 2007 Myricom, Inc. for some LRO specific code
+******************************************************************************/
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+
+#include "ixgbevf.h"
+
+char ixgbevf_driver_name[] = "ixgbevf";
+static const char ixgbevf_driver_string[] =
+ "Intel(R) 82599 Virtual Function";
+
+#define DRV_VERSION "1.0.0-k0"
+const char ixgbevf_driver_version[] = DRV_VERSION;
+static char ixgbevf_copyright[] = "Copyright (c) 2009 Intel Corporation.";
+
+static const struct ixgbevf_info *ixgbevf_info_tbl[] = {
+ [board_82599_vf] = &ixgbevf_vf_info,
+};
+
+/* ixgbevf_pci_tbl - PCI Device ID Table
+ *
+ * Wildcard entries (PCI_ANY_ID) should come last
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ * Class, Class Mask, private data (not used) }
+ */
+static struct pci_device_id ixgbevf_pci_tbl[] = {
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF),
+ board_82599_vf},
+
+ /* required last entry */
+ {0, }
+};
+MODULE_DEVICE_TABLE(pci, ixgbevf_pci_tbl);
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION("Intel(R) 82599 Virtual Function Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+#define DEFAULT_DEBUG_LEVEL_SHIFT 3
+
+/* forward decls */
+static void ixgbevf_set_itr_msix(struct ixgbevf_q_vector *q_vector);
+static void ixgbevf_write_eitr(struct ixgbevf_adapter *adapter, int v_idx,
+ u32 itr_reg);
+
+static inline void ixgbevf_release_rx_desc(struct ixgbe_hw *hw,
+ struct ixgbevf_ring *rx_ring,
+ u32 val)
+{
+ /*
+ * 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();
+ IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rx_ring->reg_idx), val);
+}
+
+/*
+ * ixgbe_set_ivar - set the IVAR registers, mapping interrupt causes to vectors
+ * @adapter: pointer to adapter struct
+ * @direction: 0 for Rx, 1 for Tx, -1 for other causes
+ * @queue: queue to map the corresponding interrupt to
+ * @msix_vector: the vector to map to the corresponding queue
+ *
+ */
+static void ixgbevf_set_ivar(struct ixgbevf_adapter *adapter, s8 direction,
+ u8 queue, u8 msix_vector)
+{
+ u32 ivar, index;
+ struct ixgbe_hw *hw = &adapter->hw;
+ if (direction == -1) {
+ /* other causes */
+ msix_vector |= IXGBE_IVAR_ALLOC_VAL;
+ ivar = IXGBE_READ_REG(hw, IXGBE_VTIVAR_MISC);
+ ivar &= ~0xFF;
+ ivar |= msix_vector;
+ IXGBE_WRITE_REG(hw, IXGBE_VTIVAR_MISC, ivar);
+ } else {
+ /* tx or rx causes */
+ msix_vector |= IXGBE_IVAR_ALLOC_VAL;
+ index = ((16 * (queue & 1)) + (8 * direction));
+ ivar = IXGBE_READ_REG(hw, IXGBE_VTIVAR(queue >> 1));
+ ivar &= ~(0xFF << index);
+ ivar |= (msix_vector << index);
+ IXGBE_WRITE_REG(hw, IXGBE_VTIVAR(queue >> 1), ivar);
+ }
+}
+
+static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_tx_buffer
+ *tx_buffer_info)
+{
+ if (tx_buffer_info->dma) {
+ if (tx_buffer_info->mapped_as_page)
+ pci_unmap_page(adapter->pdev,
+ tx_buffer_info->dma,
+ tx_buffer_info->length,
+ PCI_DMA_TODEVICE);
+ else
+ pci_unmap_single(adapter->pdev,
+ tx_buffer_info->dma,
+ tx_buffer_info->length,
+ PCI_DMA_TODEVICE);
+ tx_buffer_info->dma = 0;
+ }
+ if (tx_buffer_info->skb) {
+ dev_kfree_skb_any(tx_buffer_info->skb);
+ tx_buffer_info->skb = NULL;
+ }
+ tx_buffer_info->time_stamp = 0;
+ /* tx_buffer_info must be completely set up in the transmit path */
+}
+
+static inline bool ixgbevf_check_tx_hang(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_ring *tx_ring,
+ unsigned int eop)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 head, tail;
+
+ /* Detect a transmit hang in hardware, this serializes the
+ * check with the clearing of time_stamp and movement of eop */
+ head = readl(hw->hw_addr + tx_ring->head);
+ tail = readl(hw->hw_addr + tx_ring->tail);
+ adapter->detect_tx_hung = false;
+ if ((head != tail) &&
+ tx_ring->tx_buffer_info[eop].time_stamp &&
+ time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ)) {
+ /* detected Tx unit hang */
+ union ixgbe_adv_tx_desc *tx_desc;
+ tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+ printk(KERN_ERR "Detected Tx Unit Hang\n"
+ " Tx Queue <%d>\n"
+ " TDH, TDT <%x>, <%x>\n"
+ " next_to_use <%x>\n"
+ " next_to_clean <%x>\n"
+ "tx_buffer_info[next_to_clean]\n"
+ " time_stamp <%lx>\n"
+ " jiffies <%lx>\n",
+ tx_ring->queue_index,
+ head, tail,
+ tx_ring->next_to_use, eop,
+ tx_ring->tx_buffer_info[eop].time_stamp, jiffies);
+ return true;
+ }
+
+ return false;
+}
+
+#define IXGBE_MAX_TXD_PWR 14
+#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR)
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \
+ (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
+#ifdef MAX_SKB_FRAGS
+#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
+ MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */
+#else
+#define DESC_NEEDED TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD)
+#endif
+
+static void ixgbevf_tx_timeout(struct net_device *netdev);
+
+/**
+ * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+ * @adapter: board private structure
+ * @tx_ring: tx ring to clean
+ **/
+static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_ring *tx_ring)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct ixgbe_hw *hw = &adapter->hw;
+ union ixgbe_adv_tx_desc *tx_desc, *eop_desc;
+ struct ixgbevf_tx_buffer *tx_buffer_info;
+ unsigned int i, eop, count = 0;
+ unsigned int total_bytes = 0, total_packets = 0;
+
+ i = tx_ring->next_to_clean;
+ eop = tx_ring->tx_buffer_info[i].next_to_watch;
+ eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+
+ while ((eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) &&
+ (count < tx_ring->work_limit)) {
+ bool cleaned = false;
+ for ( ; !cleaned; count++) {
+ struct sk_buff *skb;
+ tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ cleaned = (i == eop);
+ skb = tx_buffer_info->skb;
+
+ if (cleaned && skb) {
+ unsigned int segs, bytecount;
+
+ /* gso_segs is currently only valid for tcp */
+ segs = skb_shinfo(skb)->gso_segs ?: 1;
+ /* multiply data chunks by size of headers */
+ bytecount = ((segs - 1) * skb_headlen(skb)) +
+ skb->len;
+ total_packets += segs;
+ total_bytes += bytecount;
+ }
+
+ ixgbevf_unmap_and_free_tx_resource(adapter,
+ tx_buffer_info);
+
+ tx_desc->wb.status = 0;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ eop = tx_ring->tx_buffer_info[i].next_to_watch;
+ eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+ }
+
+ tx_ring->next_to_clean = i;
+
+#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
+ if (unlikely(count && netif_carrier_ok(netdev) &&
+ (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) {
+ /* Make sure that anybody stopping the queue after this
+ * sees the new next_to_clean.
+ */
+ smp_mb();
+#ifdef HAVE_TX_MQ
+ if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) &&
+ !test_bit(__IXGBEVF_DOWN, &adapter->state)) {
+ netif_wake_subqueue(netdev, tx_ring->queue_index);
+ ++adapter->restart_queue;
+ }
+#else
+ if (netif_queue_stopped(netdev) &&
+ !test_bit(__IXGBEVF_DOWN, &adapter->state)) {
+ netif_wake_queue(netdev);
+ ++adapter->restart_queue;
+ }
+#endif
+ }
+
+ if (adapter->detect_tx_hung) {
+ if (ixgbevf_check_tx_hang(adapter, tx_ring, i)) {
+ /* schedule immediate reset if we believe we hung */
+ printk(KERN_INFO
+ "tx hang %d detected, resetting adapter\n",
+ adapter->tx_timeout_count + 1);
+ ixgbevf_tx_timeout(adapter->netdev);
+ }
+ }
+
+ /* re-arm the interrupt */
+ if ((count >= tx_ring->work_limit) &&
+ (!test_bit(__IXGBEVF_DOWN, &adapter->state))) {
+ IXGBE_WRITE_REG(hw, IXGBE_VTEICS, tx_ring->v_idx);
+ }
+
+ tx_ring->total_bytes += total_bytes;
+ tx_ring->total_packets += total_packets;
+
+ adapter->net_stats.tx_bytes += total_bytes;
+ adapter->net_stats.tx_packets += total_packets;
+
+ return (count < tx_ring->work_limit);
+}
+
+/**
+ * ixgbevf_receive_skb - Send a completed packet up the stack
+ * @q_vector: structure containing interrupt and ring information
+ * @skb: packet to send up
+ * @status: hardware indication of status of receive
+ * @rx_ring: rx descriptor ring (for a specific queue) to setup
+ * @rx_desc: rx descriptor
+ **/
+static void ixgbevf_receive_skb(struct ixgbevf_q_vector *q_vector,
+ struct sk_buff *skb, u8 status,
+ struct ixgbevf_ring *ring,
+ union ixgbe_adv_rx_desc *rx_desc)
+{
+ struct ixgbevf_adapter *adapter = q_vector->adapter;
+ bool is_vlan = (status & IXGBE_RXD_STAT_VP);
+ u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan);
+ int ret;
+
+ if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
+ if (adapter->vlgrp && is_vlan)
+ vlan_gro_receive(&q_vector->napi,
+ adapter->vlgrp,
+ tag, skb);
+ else
+ napi_gro_receive(&q_vector->napi, skb);
+ } else {
+ if (adapter->vlgrp && is_vlan)
+ ret = vlan_hwaccel_rx(skb, adapter->vlgrp, tag);
+ else
+ ret = netif_rx(skb);
+ }
+}
+
+/**
+ * ixgbevf_rx_checksum - indicate in skb if hw indicated a good cksum
+ * @adapter: address of board private structure
+ * @status_err: hardware indication of status of receive
+ * @skb: skb currently being received and modified
+ **/
+static inline void ixgbevf_rx_checksum(struct ixgbevf_adapter *adapter,
+ u32 status_err, struct sk_buff *skb)
+{
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* Rx csum disabled */
+ if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
+ return;
+
+ /* if IP and error */
+ if ((status_err & IXGBE_RXD_STAT_IPCS) &&
+ (status_err & IXGBE_RXDADV_ERR_IPE)) {
+ adapter->hw_csum_rx_error++;
+ return;
+ }
+
+ if (!(status_err & IXGBE_RXD_STAT_L4CS))
+ return;
+
+ if (status_err & IXGBE_RXDADV_ERR_TCPE) {
+ adapter->hw_csum_rx_error++;
+ return;
+ }
+
+ /* It must be a TCP or UDP packet with a valid checksum */
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ adapter->hw_csum_rx_good++;
+}
+
+/**
+ * ixgbevf_alloc_rx_buffers - Replace used receive buffers; packet split
+ * @adapter: address of board private structure
+ **/
+static void ixgbevf_alloc_rx_buffers(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_ring *rx_ring,
+ int cleaned_count)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ union ixgbe_adv_rx_desc *rx_desc;
+ struct ixgbevf_rx_buffer *bi;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned int bufsz = rx_ring->rx_buf_len + NET_IP_ALIGN;
+
+ i = rx_ring->next_to_use;
+ bi = &rx_ring->rx_buffer_info[i];
+
+ while (cleaned_count--) {
+ rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+
+ if (!bi->page_dma &&
+ (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) {
+ if (!bi->page) {
+ bi->page = netdev_alloc_page(adapter->netdev);
+ if (!bi->page) {
+ adapter->alloc_rx_page_failed++;
+ goto no_buffers;
+ }
+ bi->page_offset = 0;
+ } else {
+ /* use a half page if we're re-using */
+ bi->page_offset ^= (PAGE_SIZE / 2);
+ }
+
+ bi->page_dma = pci_map_page(pdev, bi->page,
+ bi->page_offset,
+ (PAGE_SIZE / 2),
+ PCI_DMA_FROMDEVICE);
+ }
+
+ skb = bi->skb;
+ if (!skb) {
+ skb = netdev_alloc_skb(adapter->netdev,
+ bufsz);
+
+ if (!skb) {
+ adapter->alloc_rx_buff_failed++;
+ goto no_buffers;
+ }
+
+ /*
+ * Make buffer alignment 2 beyond a 16 byte boundary
+ * this will result in a 16 byte aligned IP header after
+ * the 14 byte MAC header is removed
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ bi->skb = skb;
+ }
+ if (!bi->dma) {
+ bi->dma = pci_map_single(pdev, skb->data,
+ rx_ring->rx_buf_len,
+ PCI_DMA_FROMDEVICE);
+ }
+ /* Refresh the desc even if buffer_addrs didn't change because
+ * each write-back erases this info. */
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma);
+ rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
+ } else {
+ rx_desc->read.pkt_addr = cpu_to_le64(bi->dma);
+ }
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ bi = &rx_ring->rx_buffer_info[i];
+ }
+
+no_buffers:
+ if (rx_ring->next_to_use != i) {
+ rx_ring->next_to_use = i;
+ if (i-- == 0)
+ i = (rx_ring->count - 1);
+
+ ixgbevf_release_rx_desc(&adapter->hw, rx_ring, i);
+ }
+}
+
+static inline void ixgbevf_irq_enable_queues(struct ixgbevf_adapter *adapter,
+ u64 qmask)
+{
+ u32 mask;
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ mask = (qmask & 0xFFFFFFFF);
+ IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);
+}
+
+static inline u16 ixgbevf_get_hdr_info(union ixgbe_adv_rx_desc *rx_desc)
+{
+ return rx_desc->wb.lower.lo_dword.hs_rss.hdr_info;
+}
+
+static inline u16 ixgbevf_get_pkt_info(union ixgbe_adv_rx_desc *rx_desc)
+{
+ return rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
+}
+
+static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ struct ixgbevf_ring *rx_ring,
+ int *work_done, int work_to_do)
+{
+ struct ixgbevf_adapter *adapter = q_vector->adapter;
+ struct pci_dev *pdev = adapter->pdev;
+ union ixgbe_adv_rx_desc *rx_desc, *next_rxd;
+ struct ixgbevf_rx_buffer *rx_buffer_info, *next_buffer;
+ struct sk_buff *skb;
+ unsigned int i;
+ u32 len, staterr;
+ u16 hdr_info;
+ bool cleaned = false;
+ int cleaned_count = 0;
+ unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+
+ i = rx_ring->next_to_clean;
+ rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+ staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+ rx_buffer_info = &rx_ring->rx_buffer_info[i];
+
+ while (staterr & IXGBE_RXD_STAT_DD) {
+ u32 upper_len = 0;
+ if (*work_done >= work_to_do)
+ break;
+ (*work_done)++;
+
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ hdr_info = le16_to_cpu(ixgbevf_get_hdr_info(rx_desc));
+ len = (hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >>
+ IXGBE_RXDADV_HDRBUFLEN_SHIFT;
+ if (hdr_info & IXGBE_RXDADV_SPH)
+ adapter->rx_hdr_split++;
+ if (len > IXGBEVF_RX_HDR_SIZE)
+ len = IXGBEVF_RX_HDR_SIZE;
+ upper_len = le16_to_cpu(rx_desc->wb.upper.length);
+ } else {
+ len = le16_to_cpu(rx_desc->wb.upper.length);
+ }
+ cleaned = true;
+ skb = rx_buffer_info->skb;
+ prefetch(skb->data - NET_IP_ALIGN);
+ rx_buffer_info->skb = NULL;
+
+ if (rx_buffer_info->dma) {
+ pci_unmap_single(pdev, rx_buffer_info->dma,
+ rx_ring->rx_buf_len,
+ PCI_DMA_FROMDEVICE);
+ rx_buffer_info->dma = 0;
+ skb_put(skb, len);
+ }
+
+ if (upper_len) {
+ pci_unmap_page(pdev, rx_buffer_info->page_dma,
+ PAGE_SIZE / 2, PCI_DMA_FROMDEVICE);
+ rx_buffer_info->page_dma = 0;
+ skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
+ rx_buffer_info->page,
+ rx_buffer_info->page_offset,
+ upper_len);
+
+ if ((rx_ring->rx_buf_len > (PAGE_SIZE / 2)) ||
+ (page_count(rx_buffer_info->page) != 1))
+ rx_buffer_info->page = NULL;
+ else
+ get_page(rx_buffer_info->page);
+
+ skb->len += upper_len;
+ skb->data_len += upper_len;
+ skb->truesize += upper_len;
+ }
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+
+ next_rxd = IXGBE_RX_DESC_ADV(*rx_ring, i);
+ prefetch(next_rxd);
+ cleaned_count++;
+
+ next_buffer = &rx_ring->rx_buffer_info[i];
+
+ if (!(staterr & IXGBE_RXD_STAT_EOP)) {
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ rx_buffer_info->skb = next_buffer->skb;
+ rx_buffer_info->dma = next_buffer->dma;
+ next_buffer->skb = skb;
+ next_buffer->dma = 0;
+ } else {
+ skb->next = next_buffer->skb;
+ skb->next->prev = skb;
+ }
+ adapter->non_eop_descs++;
+ goto next_desc;
+ }
+
+ /* ERR_MASK will only have valid bits if EOP set */
+ if (unlikely(staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK)) {
+ dev_kfree_skb_irq(skb);
+ goto next_desc;
+ }
+
+ ixgbevf_rx_checksum(adapter, staterr, skb);
+
+ /* probably a little skewed due to removing CRC */
+ total_rx_bytes += skb->len;
+ total_rx_packets++;
+
+ /*
+ * Work around issue of some types of VM to VM loop back
+ * packets not getting split correctly
+ */
+ if (staterr & IXGBE_RXD_STAT_LB) {
+ u32 header_fixup_len = skb->len - skb->data_len;
+ if (header_fixup_len < 14)
+ skb_push(skb, header_fixup_len);
+ }
+ skb->protocol = eth_type_trans(skb, adapter->netdev);
+
+ ixgbevf_receive_skb(q_vector, skb, staterr, rx_ring, rx_desc);
+ adapter->netdev->last_rx = jiffies;
+
+next_desc:
+ rx_desc->wb.upper.status_error = 0;
+
+ /* return some buffers to hardware, one at a time is too slow */
+ if (cleaned_count >= IXGBEVF_RX_BUFFER_WRITE) {
+ ixgbevf_alloc_rx_buffers(adapter, rx_ring,
+ cleaned_count);
+ cleaned_count = 0;
+ }
+
+ /* use prefetched values */
+ rx_desc = next_rxd;
+ rx_buffer_info = &rx_ring->rx_buffer_info[i];
+
+ staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+ }
+
+ rx_ring->next_to_clean = i;
+ cleaned_count = IXGBE_DESC_UNUSED(rx_ring);
+
+ if (cleaned_count)
+ ixgbevf_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
+
+ rx_ring->total_packets += total_rx_packets;
+ rx_ring->total_bytes += total_rx_bytes;
+ adapter->net_stats.rx_bytes += total_rx_bytes;
+ adapter->net_stats.rx_packets += total_rx_packets;
+
+ return cleaned;
+}
+
+/**
+ * ixgbevf_clean_rxonly - msix (aka one shot) rx clean routine
+ * @napi: napi struct with our devices info in it
+ * @budget: amount of work driver is allowed to do this pass, in packets
+ *
+ * This function is optimized for cleaning one queue only on a single
+ * q_vector!!!
+ **/
+static int ixgbevf_clean_rxonly(struct napi_struct *napi, int budget)
+{
+ struct ixgbevf_q_vector *q_vector =
+ container_of(napi, struct ixgbevf_q_vector, napi);
+ struct ixgbevf_adapter *adapter = q_vector->adapter;
+ struct ixgbevf_ring *rx_ring = NULL;
+ int work_done = 0;
+ long r_idx;
+
+ r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+ rx_ring = &(adapter->rx_ring[r_idx]);
+
+ ixgbevf_clean_rx_irq(q_vector, rx_ring, &work_done, budget);
+
+ /* If all Rx work done, exit the polling mode */
+ if (work_done < budget) {
+ napi_complete(napi);
+ if (adapter->itr_setting & 1)
+ ixgbevf_set_itr_msix(q_vector);
+ if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+ ixgbevf_irq_enable_queues(adapter, rx_ring->v_idx);
+ }
+
+ return work_done;
+}
+
+/**
+ * ixgbevf_clean_rxonly_many - msix (aka one shot) rx clean routine
+ * @napi: napi struct with our devices info in it
+ * @budget: amount of work driver is allowed to do this pass, in packets
+ *
+ * This function will clean more than one rx queue associated with a
+ * q_vector.
+ **/
+static int ixgbevf_clean_rxonly_many(struct napi_struct *napi, int budget)
+{
+ struct ixgbevf_q_vector *q_vector =
+ container_of(napi, struct ixgbevf_q_vector, napi);
+ struct ixgbevf_adapter *adapter = q_vector->adapter;
+ struct ixgbevf_ring *rx_ring = NULL;
+ int work_done = 0, i;
+ long r_idx;
+ u64 enable_mask = 0;
+
+ /* attempt to distribute budget to each queue fairly, but don't allow
+ * the budget to go below 1 because we'll exit polling */
+ budget /= (q_vector->rxr_count ?: 1);
+ budget = max(budget, 1);
+ r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+ for (i = 0; i < q_vector->rxr_count; i++) {
+ rx_ring = &(adapter->rx_ring[r_idx]);
+ ixgbevf_clean_rx_irq(q_vector, rx_ring, &work_done, budget);
+ enable_mask |= rx_ring->v_idx;
+ r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
+ r_idx + 1);
+ }
+
+#ifndef HAVE_NETDEV_NAPI_LIST
+ if (!netif_running(adapter->netdev))
+ work_done = 0;
+
+#endif
+ r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+ rx_ring = &(adapter->rx_ring[r_idx]);
+
+ /* If all Rx work done, exit the polling mode */
+ if (work_done < budget) {
+ napi_complete(napi);
+ if (adapter->itr_setting & 1)
+ ixgbevf_set_itr_msix(q_vector);
+ if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+ ixgbevf_irq_enable_queues(adapter, enable_mask);
+ }
+
+ return work_done;
+}
+
+
+/**
+ * ixgbevf_configure_msix - Configure MSI-X hardware
+ * @adapter: board private structure
+ *
+ * ixgbevf_configure_msix sets up the hardware to properly generate MSI-X
+ * interrupts.
+ **/
+static void ixgbevf_configure_msix(struct ixgbevf_adapter *adapter)
+{
+ struct ixgbevf_q_vector *q_vector;
+ struct ixgbe_hw *hw = &adapter->hw;
+ int i, j, q_vectors, v_idx, r_idx;
+ u32 mask;
+
+ q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
+ /*
+ * Populate the IVAR table and set the ITR values to the
+ * corresponding register.
+ */
+ for (v_idx = 0; v_idx < q_vectors; v_idx++) {
+ q_vector = adapter->q_vector[v_idx];
+ /* XXX for_each_set_bit(...) */
+ r_idx = find_first_bit(q_vector->rxr_idx,
+ adapter->num_rx_queues);
+
+ for (i = 0; i < q_vector->rxr_count; i++) {
+ j = adapter->rx_ring[r_idx].reg_idx;
+ ixgbevf_set_ivar(adapter, 0, j, v_idx);
+ r_idx = find_next_bit(q_vector->rxr_idx,
+ adapter->num_rx_queues,
+ r_idx + 1);
+ }
+ r_idx = find_first_bit(q_vector->txr_idx,
+ adapter->num_tx_queues);
+
+ for (i = 0; i < q_vector->txr_count; i++) {
+ j = adapter->tx_ring[r_idx].reg_idx;
+ ixgbevf_set_ivar(adapter, 1, j, v_idx);
+ r_idx = find_next_bit(q_vector->txr_idx,
+ adapter->num_tx_queues,
+ r_idx + 1);
+ }
+
+ /* if this is a tx only vector halve the interrupt rate */
+ if (q_vector->txr_count && !q_vector->rxr_count)
+ q_vector->eitr = (adapter->eitr_param >> 1);
+ else if (q_vector->rxr_count)
+ /* rx only */
+ q_vector->eitr = adapter->eitr_param;
+
+ ixgbevf_write_eitr(adapter, v_idx, q_vector->eitr);
+ }
+
+ ixgbevf_set_ivar(adapter, -1, 1, v_idx);
+
+ /* set up to autoclear timer, and the vectors */
+ mask = IXGBE_EIMS_ENABLE_MASK;
+ mask &= ~IXGBE_EIMS_OTHER;
+ IXGBE_WRITE_REG(hw, IXGBE_VTEIAC, mask);
+}
+
+enum latency_range {
+ lowest_latency = 0,
+ low_latency = 1,
+ bulk_latency = 2,
+ latency_invalid = 255
+};
+
+/**
+ * ixgbevf_update_itr - update the dynamic ITR value based on statistics
+ * @adapter: pointer to adapter
+ * @eitr: eitr setting (ints per sec) to give last timeslice
+ * @itr_setting: current throttle rate in ints/second
+ * @packets: the number of packets during this measurement interval
+ * @bytes: the number of bytes during this measurement interval
+ *
+ * Stores a new ITR value based on packets and byte
+ * counts during the last interrupt. The advantage of per interrupt
+ * computation is faster updates and more accurate ITR for the current
+ * traffic pattern. Constants in this function were computed
+ * based on theoretical maximum wire speed and thresholds were set based
+ * on testing data as well as attempting to minimize response time
+ * while increasing bulk throughput.
+ **/
+static u8 ixgbevf_update_itr(struct ixgbevf_adapter *adapter,
+ u32 eitr, u8 itr_setting,
+ int packets, int bytes)
+{
+ unsigned int retval = itr_setting;
+ u32 timepassed_us;
+ u64 bytes_perint;
+
+ if (packets == 0)
+ goto update_itr_done;
+
+
+ /* simple throttlerate management
+ * 0-20MB/s lowest (100000 ints/s)
+ * 20-100MB/s low (20000 ints/s)
+ * 100-1249MB/s bulk (8000 ints/s)
+ */
+ /* what was last interrupt timeslice? */
+ timepassed_us = 1000000/eitr;
+ bytes_perint = bytes / timepassed_us; /* bytes/usec */
+
+ switch (itr_setting) {
+ case lowest_latency:
+ if (bytes_perint > adapter->eitr_low)
+ retval = low_latency;
+ break;
+ case low_latency:
+ if (bytes_perint > adapter->eitr_high)
+ retval = bulk_latency;
+ else if (bytes_perint <= adapter->eitr_low)
+ retval = lowest_latency;
+ break;
+ case bulk_latency:
+ if (bytes_perint <= adapter->eitr_high)
+ retval = low_latency;
+ break;
+ }
+
+update_itr_done:
+ return retval;
+}
+
+/**
+ * ixgbevf_write_eitr - write VTEITR register in hardware specific way
+ * @adapter: pointer to adapter struct
+ * @v_idx: vector index into q_vector array
+ * @itr_reg: new value to be written in *register* format, not ints/s
+ *
+ * This function is made to be called by ethtool and by the driver
+ * when it needs to update VTEITR registers at runtime. Hardware
+ * specific quirks/differences are taken care of here.
+ */
+static void ixgbevf_write_eitr(struct ixgbevf_adapter *adapter, int v_idx,
+ u32 itr_reg)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ itr_reg = EITR_INTS_PER_SEC_TO_REG(itr_reg);
+
+ /*
+ * set the WDIS bit to not clear the timer bits and cause an
+ * immediate assertion of the interrupt
+ */
+ itr_reg |= IXGBE_EITR_CNT_WDIS;
+
+ IXGBE_WRITE_REG(hw, IXGBE_VTEITR(v_idx), itr_reg);
+}
+
+static void ixgbevf_set_itr_msix(struct ixgbevf_q_vector *q_vector)
+{
+ struct ixgbevf_adapter *adapter = q_vector->adapter;
+ u32 new_itr;
+ u8 current_itr, ret_itr;
+ int i, r_idx, v_idx = q_vector->v_idx;
+ struct ixgbevf_ring *rx_ring, *tx_ring;
+
+ r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
+ for (i = 0; i < q_vector->txr_count; i++) {
+ tx_ring = &(adapter->tx_ring[r_idx]);
+ ret_itr = ixgbevf_update_itr(adapter, q_vector->eitr,
+ q_vector->tx_itr,
+ tx_ring->total_packets,
+ tx_ring->total_bytes);
+ /* if the result for this queue would decrease interrupt
+ * rate for this vector then use that result */
+ q_vector->tx_itr = ((q_vector->tx_itr > ret_itr) ?
+ q_vector->tx_itr - 1 : ret_itr);
+ r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
+ r_idx + 1);
+ }
+
+ r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+ for (i = 0; i < q_vector->rxr_count; i++) {
+ rx_ring = &(adapter->rx_ring[r_idx]);
+ ret_itr = ixgbevf_update_itr(adapter, q_vector->eitr,
+ q_vector->rx_itr,
+ rx_ring->total_packets,
+ rx_ring->total_bytes);
+ /* if the result for this queue would decrease interrupt
+ * rate for this vector then use that result */
+ q_vector->rx_itr = ((q_vector->rx_itr > ret_itr) ?
+ q_vector->rx_itr - 1 : ret_itr);
+ r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
+ r_idx + 1);
+ }
+
+ current_itr = max(q_vector->rx_itr, q_vector->tx_itr);
+
+ switch (current_itr) {
+ /* counts and packets in update_itr are dependent on these numbers */
+ case lowest_latency:
+ new_itr = 100000;
+ break;
+ case low_latency:
+ new_itr = 20000; /* aka hwitr = ~200 */
+ break;
+ case bulk_latency:
+ default:
+ new_itr = 8000;
+ break;
+ }
+
+ if (new_itr != q_vector->eitr) {
+ u32 itr_reg;
+
+ /* save the algorithm value here, not the smoothed one */
+ q_vector->eitr = new_itr;
+ /* do an exponential smoothing */
+ new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100);
+ itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr);
+ ixgbevf_write_eitr(adapter, v_idx, itr_reg);
+ }
+
+ return;
+}
+
+static irqreturn_t ixgbevf_msix_mbx(int irq, void *data)
+{
+ struct net_device *netdev = data;
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 eicr;
+ u32 msg;
+
+ eicr = IXGBE_READ_REG(hw, IXGBE_VTEICS);
+ IXGBE_WRITE_REG(hw, IXGBE_VTEICR, eicr);
+
+ hw->mbx.ops.read(hw, &msg, 1);
+
+ if ((msg & IXGBE_MBVFICR_VFREQ_MASK) == IXGBE_PF_CONTROL_MSG)
+ mod_timer(&adapter->watchdog_timer,
+ round_jiffies(jiffies + 10));
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ixgbevf_msix_clean_tx(int irq, void *data)
+{
+ struct ixgbevf_q_vector *q_vector = data;
+ struct ixgbevf_adapter *adapter = q_vector->adapter;
+ struct ixgbevf_ring *tx_ring;
+ int i, r_idx;
+
+ if (!q_vector->txr_count)
+ return IRQ_HANDLED;
+
+ r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
+ for (i = 0; i < q_vector->txr_count; i++) {
+ tx_ring = &(adapter->tx_ring[r_idx]);
+ tx_ring->total_bytes = 0;
+ tx_ring->total_packets = 0;
+ ixgbevf_clean_tx_irq(adapter, tx_ring);
+ r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
+ r_idx + 1);
+ }
+
+ if (adapter->itr_setting & 1)
+ ixgbevf_set_itr_msix(q_vector);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ixgbe_msix_clean_rx - single unshared vector rx clean (all queues)
+ * @irq: unused
+ * @data: pointer to our q_vector struct for this interrupt vector
+ **/
+static irqreturn_t ixgbevf_msix_clean_rx(int irq, void *data)
+{
+ struct ixgbevf_q_vector *q_vector = data;
+ struct ixgbevf_adapter *adapter = q_vector->adapter;
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct ixgbevf_ring *rx_ring;
+ int r_idx;
+ int i;
+
+ r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+ for (i = 0; i < q_vector->rxr_count; i++) {
+ rx_ring = &(adapter->rx_ring[r_idx]);
+ rx_ring->total_bytes = 0;
+ rx_ring->total_packets = 0;
+ r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
+ r_idx + 1);
+ }
+
+ if (!q_vector->rxr_count)
+ return IRQ_HANDLED;
+
+ r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+ rx_ring = &(adapter->rx_ring[r_idx]);
+ /* disable interrupts on this vector only */
+ IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, rx_ring->v_idx);
+ napi_schedule(&q_vector->napi);
+
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ixgbevf_msix_clean_many(int irq, void *data)
+{
+ ixgbevf_msix_clean_rx(irq, data);
+ ixgbevf_msix_clean_tx(irq, data);
+
+ return IRQ_HANDLED;
+}
+
+static inline void map_vector_to_rxq(struct ixgbevf_adapter *a, int v_idx,
+ int r_idx)
+{
+ struct ixgbevf_q_vector *q_vector = a->q_vector[v_idx];
+
+ set_bit(r_idx, q_vector->rxr_idx);
+ q_vector->rxr_count++;
+ a->rx_ring[r_idx].v_idx = 1 << v_idx;
+}
+
+static inline void map_vector_to_txq(struct ixgbevf_adapter *a, int v_idx,
+ int t_idx)
+{
+ struct ixgbevf_q_vector *q_vector = a->q_vector[v_idx];
+
+ set_bit(t_idx, q_vector->txr_idx);
+ q_vector->txr_count++;
+ a->tx_ring[t_idx].v_idx = 1 << v_idx;
+}
+
+/**
+ * ixgbevf_map_rings_to_vectors - Maps descriptor rings to vectors
+ * @adapter: board private structure to initialize
+ *
+ * This function maps descriptor rings to the queue-specific vectors
+ * we were allotted through the MSI-X enabling code. Ideally, we'd have
+ * one vector per ring/queue, but on a constrained vector budget, we
+ * group the rings as "efficiently" as possible. You would add new
+ * mapping configurations in here.
+ **/
+static int ixgbevf_map_rings_to_vectors(struct ixgbevf_adapter *adapter)
+{
+ int q_vectors;
+ int v_start = 0;
+ int rxr_idx = 0, txr_idx = 0;
+ int rxr_remaining = adapter->num_rx_queues;
+ int txr_remaining = adapter->num_tx_queues;
+ int i, j;
+ int rqpv, tqpv;
+ int err = 0;
+
+ q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
+ /*
+ * The ideal configuration...
+ * We have enough vectors to map one per queue.
+ */
+ if (q_vectors == adapter->num_rx_queues + adapter->num_tx_queues) {
+ for (; rxr_idx < rxr_remaining; v_start++, rxr_idx++)
+ map_vector_to_rxq(adapter, v_start, rxr_idx);
+
+ for (; txr_idx < txr_remaining; v_start++, txr_idx++)
+ map_vector_to_txq(adapter, v_start, txr_idx);
+ goto out;
+ }
+
+ /*
+ * If we don't have enough vectors for a 1-to-1
+ * mapping, we'll have to group them so there are
+ * multiple queues per vector.
+ */
+ /* Re-adjusting *qpv takes care of the remainder. */
+ for (i = v_start; i < q_vectors; i++) {
+ rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - i);
+ for (j = 0; j < rqpv; j++) {
+ map_vector_to_rxq(adapter, i, rxr_idx);
+ rxr_idx++;
+ rxr_remaining--;
+ }
+ }
+ for (i = v_start; i < q_vectors; i++) {
+ tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - i);
+ for (j = 0; j < tqpv; j++) {
+ map_vector_to_txq(adapter, i, txr_idx);
+ txr_idx++;
+ txr_remaining--;
+ }
+ }
+
+out:
+ return err;
+}
+
+/**
+ * ixgbevf_request_msix_irqs - Initialize MSI-X interrupts
+ * @adapter: board private structure
+ *
+ * ixgbevf_request_msix_irqs allocates MSI-X vectors and requests
+ * interrupts from the kernel.
+ **/
+static int ixgbevf_request_msix_irqs(struct ixgbevf_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ irqreturn_t (*handler)(int, void *);
+ int i, vector, q_vectors, err;
+ int ri = 0, ti = 0;
+
+ /* Decrement for Other and TCP Timer vectors */
+ q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
+#define SET_HANDLER(_v) (((_v)->rxr_count && (_v)->txr_count) \
+ ? &ixgbevf_msix_clean_many : \
+ (_v)->rxr_count ? &ixgbevf_msix_clean_rx : \
+ (_v)->txr_count ? &ixgbevf_msix_clean_tx : \
+ NULL)
+ for (vector = 0; vector < q_vectors; vector++) {
+ handler = SET_HANDLER(adapter->q_vector[vector]);
+
+ if (handler == &ixgbevf_msix_clean_rx) {
+ sprintf(adapter->name[vector], "%s-%s-%d",
+ netdev->name, "rx", ri++);
+ } else if (handler == &ixgbevf_msix_clean_tx) {
+ sprintf(adapter->name[vector], "%s-%s-%d",
+ netdev->name, "tx", ti++);
+ } else if (handler == &ixgbevf_msix_clean_many) {
+ sprintf(adapter->name[vector], "%s-%s-%d",
+ netdev->name, "TxRx", vector);
+ } else {
+ /* skip this unused q_vector */
+ continue;
+ }
+ err = request_irq(adapter->msix_entries[vector].vector,
+ handler, 0, adapter->name[vector],
+ adapter->q_vector[vector]);
+ if (err) {
+ hw_dbg(&adapter->hw,
+ "request_irq failed for MSIX interrupt "
+ "Error: %d\n", err);
+ goto free_queue_irqs;
+ }
+ }
+
+ sprintf(adapter->name[vector], "%s:mbx", netdev->name);
+ err = request_irq(adapter->msix_entries[vector].vector,
+ &ixgbevf_msix_mbx, 0, adapter->name[vector], netdev);
+ if (err) {
+ hw_dbg(&adapter->hw,
+ "request_irq for msix_mbx failed: %d\n", err);
+ goto free_queue_irqs;
+ }
+
+ return 0;
+
+free_queue_irqs:
+ for (i = vector - 1; i >= 0; i--)
+ free_irq(adapter->msix_entries[--vector].vector,
+ &(adapter->q_vector[i]));
+ pci_disable_msix(adapter->pdev);
+ kfree(adapter->msix_entries);
+ adapter->msix_entries = NULL;
+ return err;
+}
+
+static inline void ixgbevf_reset_q_vectors(struct ixgbevf_adapter *adapter)
+{
+ int i, q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
+ for (i = 0; i < q_vectors; i++) {
+ struct ixgbevf_q_vector *q_vector = adapter->q_vector[i];
+ bitmap_zero(q_vector->rxr_idx, MAX_RX_QUEUES);
+ bitmap_zero(q_vector->txr_idx, MAX_TX_QUEUES);
+ q_vector->rxr_count = 0;
+ q_vector->txr_count = 0;
+ q_vector->eitr = adapter->eitr_param;
+ }
+}
+
+/**
+ * ixgbevf_request_irq - initialize interrupts
+ * @adapter: board private structure
+ *
+ * Attempts to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ **/
+static int ixgbevf_request_irq(struct ixgbevf_adapter *adapter)
+{
+ int err = 0;
+
+ err = ixgbevf_request_msix_irqs(adapter);
+
+ if (err)
+ hw_dbg(&adapter->hw,
+ "request_irq failed, Error %d\n", err);
+
+ return err;
+}
+
+static void ixgbevf_free_irq(struct ixgbevf_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int i, q_vectors;
+
+ q_vectors = adapter->num_msix_vectors;
+
+ i = q_vectors - 1;
+
+ free_irq(adapter->msix_entries[i].vector, netdev);
+ i--;
+
+ for (; i >= 0; i--) {
+ free_irq(adapter->msix_entries[i].vector,
+ adapter->q_vector[i]);
+ }
+
+ ixgbevf_reset_q_vectors(adapter);
+}
+
+/**
+ * ixgbevf_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+static inline void ixgbevf_irq_disable(struct ixgbevf_adapter *adapter)
+{
+ int i;
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, ~0);
+
+ IXGBE_WRITE_FLUSH(hw);
+
+ for (i = 0; i < adapter->num_msix_vectors; i++)
+ synchronize_irq(adapter->msix_entries[i].vector);
+}
+
+/**
+ * ixgbevf_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter,
+ bool queues, bool flush)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 mask;
+ u64 qmask;
+
+ mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
+ qmask = ~0;
+
+ IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);
+
+ if (queues)
+ ixgbevf_irq_enable_queues(adapter, qmask);
+
+ if (flush)
+ IXGBE_WRITE_FLUSH(hw);
+}
+
+/**
+ * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+{
+ u64 tdba;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 i, j, tdlen, txctrl;
+
+ /* Setup the HW Tx Head and Tail descriptor pointers */
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct ixgbevf_ring *ring = &adapter->tx_ring[i];
+ j = ring->reg_idx;
+ tdba = ring->dma;
+ tdlen = ring->count * sizeof(union ixgbe_adv_tx_desc);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTDBAL(j),
+ (tdba & DMA_BIT_MASK(32)));
+ IXGBE_WRITE_REG(hw, IXGBE_VFTDBAH(j), (tdba >> 32));
+ IXGBE_WRITE_REG(hw, IXGBE_VFTDLEN(j), tdlen);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTDH(j), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTDT(j), 0);
+ adapter->tx_ring[i].head = IXGBE_VFTDH(j);
+ adapter->tx_ring[i].tail = IXGBE_VFTDT(j);
+ /* Disable Tx Head Writeback RO bit, since this hoses
+ * bookkeeping if things aren't delivered in order.
+ */
+ txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
+ txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
+ IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
+ }
+}
+
+#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2
+
+static void ixgbevf_configure_srrctl(struct ixgbevf_adapter *adapter, int index)
+{
+ struct ixgbevf_ring *rx_ring;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 srrctl;
+
+ rx_ring = &adapter->rx_ring[index];
+
+ srrctl = IXGBE_SRRCTL_DROP_EN;
+
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ u16 bufsz = IXGBEVF_RXBUFFER_2048;
+ /* grow the amount we can receive on large page machines */
+ if (bufsz < (PAGE_SIZE / 2))
+ bufsz = (PAGE_SIZE / 2);
+ /* cap the bufsz at our largest descriptor size */
+ bufsz = min((u16)IXGBEVF_MAX_RXBUFFER, bufsz);
+
+ srrctl |= bufsz >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+ srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
+ srrctl |= ((IXGBEVF_RX_HDR_SIZE <<
+ IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
+ IXGBE_SRRCTL_BSIZEHDR_MASK);
+ } else {
+ srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
+
+ if (rx_ring->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE)
+ srrctl |= IXGBEVF_RXBUFFER_2048 >>
+ IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+ else
+ srrctl |= rx_ring->rx_buf_len >>
+ IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+ }
+ IXGBE_WRITE_REG(hw, IXGBE_VFSRRCTL(index), srrctl);
+}
+
+/**
+ * ixgbevf_configure_rx - Configure 82599 VF Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void ixgbevf_configure_rx(struct ixgbevf_adapter *adapter)
+{
+ u64 rdba;
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+ int i, j;
+ u32 rdlen;
+ int rx_buf_len;
+
+ /* Decide whether to use packet split mode or not */
+ if (netdev->mtu > ETH_DATA_LEN) {
+ if (adapter->flags & IXGBE_FLAG_RX_PS_CAPABLE)
+ adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
+ else
+ adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
+ } else {
+ if (adapter->flags & IXGBE_FLAG_RX_1BUF_CAPABLE)
+ adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
+ else
+ adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
+ }
+
+ /* Set the RX buffer length according to the mode */
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ /* PSRTYPE must be initialized in 82599 */
+ u32 psrtype = IXGBE_PSRTYPE_TCPHDR |
+ IXGBE_PSRTYPE_UDPHDR |
+ IXGBE_PSRTYPE_IPV4HDR |
+ IXGBE_PSRTYPE_IPV6HDR |
+ IXGBE_PSRTYPE_L2HDR;
+ IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, psrtype);
+ rx_buf_len = IXGBEVF_RX_HDR_SIZE;
+ } else {
+ IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, 0);
+ if (netdev->mtu <= ETH_DATA_LEN)
+ rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+ else
+ rx_buf_len = ALIGN(max_frame, 1024);
+ }
+
+ rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc);
+ /* Setup the HW Rx Head and Tail Descriptor Pointers and
+ * the Base and Length of the Rx Descriptor Ring */
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ rdba = adapter->rx_ring[i].dma;
+ j = adapter->rx_ring[i].reg_idx;
+ IXGBE_WRITE_REG(hw, IXGBE_VFRDBAL(j),
+ (rdba & DMA_BIT_MASK(32)));
+ IXGBE_WRITE_REG(hw, IXGBE_VFRDBAH(j), (rdba >> 32));
+ IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(j), rdlen);
+ IXGBE_WRITE_REG(hw, IXGBE_VFRDH(j), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_VFRDT(j), 0);
+ adapter->rx_ring[i].head = IXGBE_VFRDH(j);
+ adapter->rx_ring[i].tail = IXGBE_VFRDT(j);
+ adapter->rx_ring[i].rx_buf_len = rx_buf_len;
+
+ ixgbevf_configure_srrctl(adapter, j);
+ }
+}
+
+static void ixgbevf_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *grp)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ int i, j;
+ u32 ctrl;
+
+ adapter->vlgrp = grp;
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ j = adapter->rx_ring[i].reg_idx;
+ ctrl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(j));
+ ctrl |= IXGBE_RXDCTL_VME;
+ IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(j), ctrl);
+ }
+}
+
+static void ixgbevf_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct net_device *v_netdev;
+
+ /* add VID to filter table */
+ if (hw->mac.ops.set_vfta)
+ hw->mac.ops.set_vfta(hw, vid, 0, true);
+ /*
+ * Copy feature flags from netdev to the vlan netdev for this vid.
+ * This allows things like TSO to bubble down to our vlan device.
+ */
+ v_netdev = vlan_group_get_device(adapter->vlgrp, vid);
+ v_netdev->features |= adapter->netdev->features;
+ vlan_group_set_device(adapter->vlgrp, vid, v_netdev);
+}
+
+static void ixgbevf_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+ ixgbevf_irq_disable(adapter);
+
+ vlan_group_set_device(adapter->vlgrp, vid, NULL);
+
+ if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+ ixgbevf_irq_enable(adapter, true, true);
+
+ /* remove VID from filter table */
+ if (hw->mac.ops.set_vfta)
+ hw->mac.ops.set_vfta(hw, vid, 0, false);
+}
+
+static void ixgbevf_restore_vlan(struct ixgbevf_adapter *adapter)
+{
+ ixgbevf_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+
+ if (adapter->vlgrp) {
+ u16 vid;
+ for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ if (!vlan_group_get_device(adapter->vlgrp, vid))
+ continue;
+ ixgbevf_vlan_rx_add_vid(adapter->netdev, vid);
+ }
+ }
+}
+
+static u8 *ixgbevf_addr_list_itr(struct ixgbe_hw *hw, u8 **mc_addr_ptr,
+ u32 *vmdq)
+{
+ struct dev_mc_list *mc_ptr;
+ u8 *addr = *mc_addr_ptr;
+ *vmdq = 0;
+
+ mc_ptr = container_of(addr, struct dev_mc_list, dmi_addr[0]);
+ if (mc_ptr->next)
+ *mc_addr_ptr = mc_ptr->next->dmi_addr;
+ else
+ *mc_addr_ptr = NULL;
+
+ return addr;
+}
+
+/**
+ * ixgbevf_set_rx_mode - Multicast set
+ * @netdev: network interface device structure
+ *
+ * The set_rx_method entry point is called whenever the multicast address
+ * list or the network interface flags are updated. This routine is
+ * responsible for configuring the hardware for proper multicast mode.
+ **/
+static void ixgbevf_set_rx_mode(struct net_device *netdev)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u8 *addr_list = NULL;
+ int addr_count = 0;
+
+ /* reprogram multicast list */
+ addr_count = netdev_mc_count(netdev);
+ if (addr_count)
+ addr_list = netdev->mc_list->dmi_addr;
+ if (hw->mac.ops.update_mc_addr_list)
+ hw->mac.ops.update_mc_addr_list(hw, addr_list, addr_count,
+ ixgbevf_addr_list_itr);
+}
+
+static void ixgbevf_napi_enable_all(struct ixgbevf_adapter *adapter)
+{
+ int q_idx;
+ struct ixgbevf_q_vector *q_vector;
+ int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
+ for (q_idx = 0; q_idx < q_vectors; q_idx++) {
+ struct napi_struct *napi;
+ q_vector = adapter->q_vector[q_idx];
+ if (!q_vector->rxr_count)
+ continue;
+ napi = &q_vector->napi;
+ if (q_vector->rxr_count > 1)
+ napi->poll = &ixgbevf_clean_rxonly_many;
+
+ napi_enable(napi);
+ }
+}
+
+static void ixgbevf_napi_disable_all(struct ixgbevf_adapter *adapter)
+{
+ int q_idx;
+ struct ixgbevf_q_vector *q_vector;
+ int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
+ for (q_idx = 0; q_idx < q_vectors; q_idx++) {
+ q_vector = adapter->q_vector[q_idx];
+ if (!q_vector->rxr_count)
+ continue;
+ napi_disable(&q_vector->napi);
+ }
+}
+
+static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int i;
+
+ ixgbevf_set_rx_mode(netdev);
+
+ ixgbevf_restore_vlan(adapter);
+
+ ixgbevf_configure_tx(adapter);
+ ixgbevf_configure_rx(adapter);
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ struct ixgbevf_ring *ring = &adapter->rx_ring[i];
+ ixgbevf_alloc_rx_buffers(adapter, ring, ring->count);
+ ring->next_to_use = ring->count - 1;
+ writel(ring->next_to_use, adapter->hw.hw_addr + ring->tail);
+ }
+}
+
+#define IXGBE_MAX_RX_DESC_POLL 10
+static inline void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter,
+ int rxr)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ int j = adapter->rx_ring[rxr].reg_idx;
+ int k;
+
+ for (k = 0; k < IXGBE_MAX_RX_DESC_POLL; k++) {
+ if (IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(j)) & IXGBE_RXDCTL_ENABLE)
+ break;
+ else
+ msleep(1);
+ }
+ if (k >= IXGBE_MAX_RX_DESC_POLL) {
+ hw_dbg(hw, "RXDCTL.ENABLE on Rx queue %d "
+ "not set within the polling period\n", rxr);
+ }
+
+ ixgbevf_release_rx_desc(&adapter->hw, &adapter->rx_ring[rxr],
+ (adapter->rx_ring[rxr].count - 1));
+}
+
+static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct ixgbe_hw *hw = &adapter->hw;
+ int i, j = 0;
+ int num_rx_rings = adapter->num_rx_queues;
+ u32 txdctl, rxdctl;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ j = adapter->tx_ring[i].reg_idx;
+ txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(j));
+ /* enable WTHRESH=8 descriptors, to encourage burst writeback */
+ txdctl |= (8 << 16);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(j), txdctl);
+ }
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ j = adapter->tx_ring[i].reg_idx;
+ txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(j));
+ txdctl |= IXGBE_TXDCTL_ENABLE;
+ IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(j), txdctl);
+ }
+
+ for (i = 0; i < num_rx_rings; i++) {
+ j = adapter->rx_ring[i].reg_idx;
+ rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(j));
+ rxdctl |= IXGBE_RXDCTL_ENABLE;
+ IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(j), rxdctl);
+ ixgbevf_rx_desc_queue_enable(adapter, i);
+ }
+
+ ixgbevf_configure_msix(adapter);
+
+ if (hw->mac.ops.set_rar) {
+ if (is_valid_ether_addr(hw->mac.addr))
+ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0);
+ else
+ hw->mac.ops.set_rar(hw, 0, hw->mac.perm_addr, 0);
+ }
+
+ clear_bit(__IXGBEVF_DOWN, &adapter->state);
+ ixgbevf_napi_enable_all(adapter);
+
+ /* enable transmits */
+ netif_tx_start_all_queues(netdev);
+
+ /* bring the link up in the watchdog, this could race with our first
+ * link up interrupt but shouldn't be a problem */
+ adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+ adapter->link_check_timeout = jiffies;
+ mod_timer(&adapter->watchdog_timer, jiffies);
+ return 0;
+}
+
+int ixgbevf_up(struct ixgbevf_adapter *adapter)
+{
+ int err;
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ ixgbevf_configure(adapter);
+
+ err = ixgbevf_up_complete(adapter);
+
+ /* clear any pending interrupts, may auto mask */
+ IXGBE_READ_REG(hw, IXGBE_VTEICR);
+
+ ixgbevf_irq_enable(adapter, true, true);
+
+ return err;
+}
+
+/**
+ * ixgbevf_clean_rx_ring - Free Rx Buffers per Queue
+ * @adapter: board private structure
+ * @rx_ring: ring to free buffers from
+ **/
+static void ixgbevf_clean_rx_ring(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_ring *rx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long size;
+ unsigned int i;
+
+ if (!rx_ring->rx_buffer_info)
+ return;
+
+ /* Free all the Rx ring sk_buffs */
+ for (i = 0; i < rx_ring->count; i++) {
+ struct ixgbevf_rx_buffer *rx_buffer_info;
+
+ rx_buffer_info = &rx_ring->rx_buffer_info[i];
+ if (rx_buffer_info->dma) {
+ pci_unmap_single(pdev, rx_buffer_info->dma,
+ rx_ring->rx_buf_len,
+ PCI_DMA_FROMDEVICE);
+ rx_buffer_info->dma = 0;
+ }
+ if (rx_buffer_info->skb) {
+ struct sk_buff *skb = rx_buffer_info->skb;
+ rx_buffer_info->skb = NULL;
+ do {
+ struct sk_buff *this = skb;
+ skb = skb->prev;
+ dev_kfree_skb(this);
+ } while (skb);
+ }
+ if (!rx_buffer_info->page)
+ continue;
+ pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE / 2,
+ PCI_DMA_FROMDEVICE);
+ rx_buffer_info->page_dma = 0;
+ put_page(rx_buffer_info->page);
+ rx_buffer_info->page = NULL;
+ rx_buffer_info->page_offset = 0;
+ }
+
+ size = sizeof(struct ixgbevf_rx_buffer) * rx_ring->count;
+ memset(rx_ring->rx_buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(rx_ring->desc, 0, rx_ring->size);
+
+ rx_ring->next_to_clean = 0;
+ rx_ring->next_to_use = 0;
+
+ if (rx_ring->head)
+ writel(0, adapter->hw.hw_addr + rx_ring->head);
+ if (rx_ring->tail)
+ writel(0, adapter->hw.hw_addr + rx_ring->tail);
+}
+
+/**
+ * ixgbevf_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ * @tx_ring: ring to be cleaned
+ **/
+static void ixgbevf_clean_tx_ring(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_ring *tx_ring)
+{
+ struct ixgbevf_tx_buffer *tx_buffer_info;
+ unsigned long size;
+ unsigned int i;
+
+ if (!tx_ring->tx_buffer_info)
+ return;
+
+ /* Free all the Tx ring sk_buffs */
+
+ for (i = 0; i < tx_ring->count; i++) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ ixgbevf_unmap_and_free_tx_resource(adapter, tx_buffer_info);
+ }
+
+ size = sizeof(struct ixgbevf_tx_buffer) * tx_ring->count;
+ memset(tx_ring->tx_buffer_info, 0, size);
+
+ memset(tx_ring->desc, 0, tx_ring->size);
+
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+
+ if (tx_ring->head)
+ writel(0, adapter->hw.hw_addr + tx_ring->head);
+ if (tx_ring->tail)
+ writel(0, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+/**
+ * ixgbevf_clean_all_rx_rings - Free Rx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void ixgbevf_clean_all_rx_rings(struct ixgbevf_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ ixgbevf_clean_rx_ring(adapter, &adapter->rx_ring[i]);
+}
+
+/**
+ * ixgbevf_clean_all_tx_rings - Free Tx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void ixgbevf_clean_all_tx_rings(struct ixgbevf_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ ixgbevf_clean_tx_ring(adapter, &adapter->tx_ring[i]);
+}
+
+void ixgbevf_down(struct ixgbevf_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 txdctl;
+ int i, j;
+
+ /* signal that we are down to the interrupt handler */
+ set_bit(__IXGBEVF_DOWN, &adapter->state);
+ /* disable receives */
+
+ netif_tx_disable(netdev);
+
+ msleep(10);
+
+ netif_tx_stop_all_queues(netdev);
+
+ ixgbevf_irq_disable(adapter);
+
+ ixgbevf_napi_disable_all(adapter);
+
+ del_timer_sync(&adapter->watchdog_timer);
+ /* can't call flush scheduled work here because it can deadlock
+ * if linkwatch_event tries to acquire the rtnl_lock which we are
+ * holding */
+ while (adapter->flags & IXGBE_FLAG_IN_WATCHDOG_TASK)
+ msleep(1);
+
+ /* disable transmits in the hardware now that interrupts are off */
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ j = adapter->tx_ring[i].reg_idx;
+ txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(j));
+ IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(j),
+ (txdctl & ~IXGBE_TXDCTL_ENABLE));
+ }
+
+ netif_carrier_off(netdev);
+
+ if (!pci_channel_offline(adapter->pdev))
+ ixgbevf_reset(adapter);
+
+ ixgbevf_clean_all_tx_rings(adapter);
+ ixgbevf_clean_all_rx_rings(adapter);
+}
+
+void ixgbevf_reinit_locked(struct ixgbevf_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ WARN_ON(in_interrupt());
+
+ while (test_and_set_bit(__IXGBEVF_RESETTING, &adapter->state))
+ msleep(1);
+
+ /*
+ * Check if PF is up before re-init. If not then skip until
+ * later when the PF is up and ready to service requests from
+ * the VF via mailbox. If the VF is up and running then the
+ * watchdog task will continue to schedule reset tasks until
+ * the PF is up and running.
+ */
+ if (!hw->mac.ops.reset_hw(hw)) {
+ ixgbevf_down(adapter);
+ ixgbevf_up(adapter);
+ }
+
+ clear_bit(__IXGBEVF_RESETTING, &adapter->state);
+}
+
+void ixgbevf_reset(struct ixgbevf_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+
+ if (hw->mac.ops.reset_hw(hw))
+ hw_dbg(hw, "PF still resetting\n");
+ else
+ hw->mac.ops.init_hw(hw);
+
+ if (is_valid_ether_addr(adapter->hw.mac.addr)) {
+ memcpy(netdev->dev_addr, adapter->hw.mac.addr,
+ netdev->addr_len);
+ memcpy(netdev->perm_addr, adapter->hw.mac.addr,
+ netdev->addr_len);
+ }
+}
+
+static void ixgbevf_acquire_msix_vectors(struct ixgbevf_adapter *adapter,
+ int vectors)
+{
+ int err, vector_threshold;
+
+ /* We'll want at least 3 (vector_threshold):
+ * 1) TxQ[0] Cleanup
+ * 2) RxQ[0] Cleanup
+ * 3) Other (Link Status Change, etc.)
+ */
+ vector_threshold = MIN_MSIX_COUNT;
+
+ /* The more we get, the more we will assign to Tx/Rx Cleanup
+ * for the separate queues...where Rx Cleanup >= Tx Cleanup.
+ * Right now, we simply care about how many we'll get; we'll
+ * set them up later while requesting irq's.
+ */
+ while (vectors >= vector_threshold) {
+ err = pci_enable_msix(adapter->pdev, adapter->msix_entries,
+ vectors);
+ if (!err) /* Success in acquiring all requested vectors. */
+ break;
+ else if (err < 0)
+ vectors = 0; /* Nasty failure, quit now */
+ else /* err == number of vectors we should try again with */
+ vectors = err;
+ }
+
+ if (vectors < vector_threshold) {
+ /* Can't allocate enough MSI-X interrupts? Oh well.
+ * This just means we'll go with either a single MSI
+ * vector or fall back to legacy interrupts.
+ */
+ hw_dbg(&adapter->hw,
+ "Unable to allocate MSI-X interrupts\n");
+ kfree(adapter->msix_entries);
+ adapter->msix_entries = NULL;
+ } else {
+ /*
+ * Adjust for only the vectors we'll use, which is minimum
+ * of max_msix_q_vectors + NON_Q_VECTORS, or the number of
+ * vectors we were allocated.
+ */
+ adapter->num_msix_vectors = vectors;
+ }
+}
+
+/*
+ * ixgbe_set_num_queues: Allocate queues for device, feature dependant
+ * @adapter: board private structure to initialize
+ *
+ * This is the top level queue allocation routine. The order here is very
+ * important, starting with the "most" number of features turned on at once,
+ * and ending with the smallest set of features. This way large combinations
+ * can be allocated if they're turned on, and smaller combinations are the
+ * fallthrough conditions.
+ *
+ **/
+static void ixgbevf_set_num_queues(struct ixgbevf_adapter *adapter)
+{
+ /* Start with base case */
+ adapter->num_rx_queues = 1;
+ adapter->num_tx_queues = 1;
+ adapter->num_rx_pools = adapter->num_rx_queues;
+ adapter->num_rx_queues_per_pool = 1;
+}
+
+/**
+ * ixgbevf_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ *
+ * We allocate one ring per queue at run-time since we don't know the
+ * number of queues at compile-time. The polling_netdev array is
+ * intended for Multiqueue, but should work fine with a single queue.
+ **/
+static int ixgbevf_alloc_queues(struct ixgbevf_adapter *adapter)
+{
+ int i;
+
+ adapter->tx_ring = kcalloc(adapter->num_tx_queues,
+ sizeof(struct ixgbevf_ring), GFP_KERNEL);
+ if (!adapter->tx_ring)
+ goto err_tx_ring_allocation;
+
+ adapter->rx_ring = kcalloc(adapter->num_rx_queues,
+ sizeof(struct ixgbevf_ring), GFP_KERNEL);
+ if (!adapter->rx_ring)
+ goto err_rx_ring_allocation;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ adapter->tx_ring[i].count = adapter->tx_ring_count;
+ adapter->tx_ring[i].queue_index = i;
+ adapter->tx_ring[i].reg_idx = i;
+ }
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ adapter->rx_ring[i].count = adapter->rx_ring_count;
+ adapter->rx_ring[i].queue_index = i;
+ adapter->rx_ring[i].reg_idx = i;
+ }
+
+ return 0;
+
+err_rx_ring_allocation:
+ kfree(adapter->tx_ring);
+err_tx_ring_allocation:
+ return -ENOMEM;
+}
+
+/**
+ * ixgbevf_set_interrupt_capability - set MSI-X or FAIL if not supported
+ * @adapter: board private structure to initialize
+ *
+ * Attempt to configure the interrupts using the best available
+ * capabilities of the hardware and the kernel.
+ **/
+static int ixgbevf_set_interrupt_capability(struct ixgbevf_adapter *adapter)
+{
+ int err = 0;
+ int vector, v_budget;
+
+ /*
+ * It's easy to be greedy for MSI-X vectors, but it really
+ * doesn't do us much good if we have a lot more vectors
+ * than CPU's. So let's be conservative and only ask for
+ * (roughly) twice the number of vectors as there are CPU's.
+ */
+ v_budget = min(adapter->num_rx_queues + adapter->num_tx_queues,
+ (int)(num_online_cpus() * 2)) + NON_Q_VECTORS;
+
+ /* A failure in MSI-X entry allocation isn't fatal, but it does
+ * mean we disable MSI-X capabilities of the adapter. */
+ adapter->msix_entries = kcalloc(v_budget,
+ sizeof(struct msix_entry), GFP_KERNEL);
+ if (!adapter->msix_entries) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ for (vector = 0; vector < v_budget; vector++)
+ adapter->msix_entries[vector].entry = vector;
+
+ ixgbevf_acquire_msix_vectors(adapter, v_budget);
+
+out:
+ return err;
+}
+
+/**
+ * ixgbevf_alloc_q_vectors - Allocate memory for interrupt vectors
+ * @adapter: board private structure to initialize
+ *
+ * We allocate one q_vector per queue interrupt. If allocation fails we
+ * return -ENOMEM.
+ **/
+static int ixgbevf_alloc_q_vectors(struct ixgbevf_adapter *adapter)
+{
+ int q_idx, num_q_vectors;
+ struct ixgbevf_q_vector *q_vector;
+ int napi_vectors;
+ int (*poll)(struct napi_struct *, int);
+
+ num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+ napi_vectors = adapter->num_rx_queues;
+ poll = &ixgbevf_clean_rxonly;
+
+ for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
+ q_vector = kzalloc(sizeof(struct ixgbevf_q_vector), GFP_KERNEL);
+ if (!q_vector)
+ goto err_out;
+ q_vector->adapter = adapter;
+ q_vector->v_idx = q_idx;
+ q_vector->eitr = adapter->eitr_param;
+ if (q_idx < napi_vectors)
+ netif_napi_add(adapter->netdev, &q_vector->napi,
+ (*poll), 64);
+ adapter->q_vector[q_idx] = q_vector;
+ }
+
+ return 0;
+
+err_out:
+ while (q_idx) {
+ q_idx--;
+ q_vector = adapter->q_vector[q_idx];
+ netif_napi_del(&q_vector->napi);
+ kfree(q_vector);
+ adapter->q_vector[q_idx] = NULL;
+ }
+ return -ENOMEM;
+}
+
+/**
+ * ixgbevf_free_q_vectors - Free memory allocated for interrupt vectors
+ * @adapter: board private structure to initialize
+ *
+ * This function frees the memory allocated to the q_vectors. In addition if
+ * NAPI is enabled it will delete any references to the NAPI struct prior
+ * to freeing the q_vector.
+ **/
+static void ixgbevf_free_q_vectors(struct ixgbevf_adapter *adapter)
+{
+ int q_idx, num_q_vectors;
+ int napi_vectors;
+
+ num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+ napi_vectors = adapter->num_rx_queues;
+
+ for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
+ struct ixgbevf_q_vector *q_vector = adapter->q_vector[q_idx];
+
+ adapter->q_vector[q_idx] = NULL;
+ if (q_idx < napi_vectors)
+ netif_napi_del(&q_vector->napi);
+ kfree(q_vector);
+ }
+}
+
+/**
+ * ixgbevf_reset_interrupt_capability - Reset MSIX setup
+ * @adapter: board private structure
+ *
+ **/
+static void ixgbevf_reset_interrupt_capability(struct ixgbevf_adapter *adapter)
+{
+ pci_disable_msix(adapter->pdev);
+ kfree(adapter->msix_entries);
+ adapter->msix_entries = NULL;
+
+ return;
+}
+
+/**
+ * ixgbevf_init_interrupt_scheme - Determine if MSIX is supported and init
+ * @adapter: board private structure to initialize
+ *
+ **/
+static int ixgbevf_init_interrupt_scheme(struct ixgbevf_adapter *adapter)
+{
+ int err;
+
+ /* Number of supported queues */
+ ixgbevf_set_num_queues(adapter);
+
+ err = ixgbevf_set_interrupt_capability(adapter);
+ if (err) {
+ hw_dbg(&adapter->hw,
+ "Unable to setup interrupt capabilities\n");
+ goto err_set_interrupt;
+ }
+
+ err = ixgbevf_alloc_q_vectors(adapter);
+ if (err) {
+ hw_dbg(&adapter->hw, "Unable to allocate memory for queue "
+ "vectors\n");
+ goto err_alloc_q_vectors;
+ }
+
+ err = ixgbevf_alloc_queues(adapter);
+ if (err) {
+ printk(KERN_ERR "Unable to allocate memory for queues\n");
+ goto err_alloc_queues;
+ }
+
+ hw_dbg(&adapter->hw, "Multiqueue %s: Rx Queue count = %u, "
+ "Tx Queue count = %u\n",
+ (adapter->num_rx_queues > 1) ? "Enabled" :
+ "Disabled", adapter->num_rx_queues, adapter->num_tx_queues);
+
+ set_bit(__IXGBEVF_DOWN, &adapter->state);
+
+ return 0;
+err_alloc_queues:
+ ixgbevf_free_q_vectors(adapter);
+err_alloc_q_vectors:
+ ixgbevf_reset_interrupt_capability(adapter);
+err_set_interrupt:
+ return err;
+}
+
+/**
+ * ixgbevf_sw_init - Initialize general software structures
+ * (struct ixgbevf_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * ixgbevf_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int __devinit ixgbevf_sw_init(struct ixgbevf_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct pci_dev *pdev = adapter->pdev;
+ int err;
+
+ /* PCI config space info */
+
+ hw->vendor_id = pdev->vendor;
+ hw->device_id = pdev->device;
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+ hw->subsystem_vendor_id = pdev->subsystem_vendor;
+ hw->subsystem_device_id = pdev->subsystem_device;
+
+ hw->mbx.ops.init_params(hw);
+ hw->mac.max_tx_queues = MAX_TX_QUEUES;
+ hw->mac.max_rx_queues = MAX_RX_QUEUES;
+ err = hw->mac.ops.reset_hw(hw);
+ if (err) {
+ dev_info(&pdev->dev,
+ "PF still in reset state, assigning new address\n");
+ random_ether_addr(hw->mac.addr);
+ } else {
+ err = hw->mac.ops.init_hw(hw);
+ if (err) {
+ printk(KERN_ERR "init_shared_code failed: %d\n", err);
+ goto out;
+ }
+ }
+
+ /* Enable dynamic interrupt throttling rates */
+ adapter->eitr_param = 20000;
+ adapter->itr_setting = 1;
+
+ /* set defaults for eitr in MegaBytes */
+ adapter->eitr_low = 10;
+ adapter->eitr_high = 20;
+
+ /* set default ring sizes */
+ adapter->tx_ring_count = IXGBEVF_DEFAULT_TXD;
+ adapter->rx_ring_count = IXGBEVF_DEFAULT_RXD;
+
+ /* enable rx csum by default */
+ adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
+
+ set_bit(__IXGBEVF_DOWN, &adapter->state);
+
+out:
+ return err;
+}
+
+static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ adapter->stats.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC);
+ adapter->stats.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB);
+ adapter->stats.last_vfgorc |=
+ (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32);
+ adapter->stats.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC);
+ adapter->stats.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB);
+ adapter->stats.last_vfgotc |=
+ (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGOTC_MSB))) << 32);
+ adapter->stats.last_vfmprc = IXGBE_READ_REG(hw, IXGBE_VFMPRC);
+
+ adapter->stats.base_vfgprc = adapter->stats.last_vfgprc;
+ adapter->stats.base_vfgorc = adapter->stats.last_vfgorc;
+ adapter->stats.base_vfgptc = adapter->stats.last_vfgptc;
+ adapter->stats.base_vfgotc = adapter->stats.last_vfgotc;
+ adapter->stats.base_vfmprc = adapter->stats.last_vfmprc;
+}
+
+#define UPDATE_VF_COUNTER_32bit(reg, last_counter, counter) \
+ { \
+ u32 current_counter = IXGBE_READ_REG(hw, reg); \
+ if (current_counter < last_counter) \
+ counter += 0x100000000LL; \
+ last_counter = current_counter; \
+ counter &= 0xFFFFFFFF00000000LL; \
+ counter |= current_counter; \
+ }
+
+#define UPDATE_VF_COUNTER_36bit(reg_lsb, reg_msb, last_counter, counter) \
+ { \
+ u64 current_counter_lsb = IXGBE_READ_REG(hw, reg_lsb); \
+ u64 current_counter_msb = IXGBE_READ_REG(hw, reg_msb); \
+ u64 current_counter = (current_counter_msb << 32) | \
+ current_counter_lsb; \
+ if (current_counter < last_counter) \
+ counter += 0x1000000000LL; \
+ last_counter = current_counter; \
+ counter &= 0xFFFFFFF000000000LL; \
+ counter |= current_counter; \
+ }
+/**
+ * ixgbevf_update_stats - Update the board statistics counters.
+ * @adapter: board private structure
+ **/
+void ixgbevf_update_stats(struct ixgbevf_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ UPDATE_VF_COUNTER_32bit(IXGBE_VFGPRC, adapter->stats.last_vfgprc,
+ adapter->stats.vfgprc);
+ UPDATE_VF_COUNTER_32bit(IXGBE_VFGPTC, adapter->stats.last_vfgptc,
+ adapter->stats.vfgptc);
+ UPDATE_VF_COUNTER_36bit(IXGBE_VFGORC_LSB, IXGBE_VFGORC_MSB,
+ adapter->stats.last_vfgorc,
+ adapter->stats.vfgorc);
+ UPDATE_VF_COUNTER_36bit(IXGBE_VFGOTC_LSB, IXGBE_VFGOTC_MSB,
+ adapter->stats.last_vfgotc,
+ adapter->stats.vfgotc);
+ UPDATE_VF_COUNTER_32bit(IXGBE_VFMPRC, adapter->stats.last_vfmprc,
+ adapter->stats.vfmprc);
+
+ /* Fill out the OS statistics structure */
+ adapter->net_stats.multicast = adapter->stats.vfmprc -
+ adapter->stats.base_vfmprc;
+}
+
+/**
+ * ixgbevf_watchdog - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void ixgbevf_watchdog(unsigned long data)
+{
+ struct ixgbevf_adapter *adapter = (struct ixgbevf_adapter *)data;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u64 eics = 0;
+ int i;
+
+ /*
+ * Do the watchdog outside of interrupt context due to the lovely
+ * delays that some of the newer hardware requires
+ */
+
+ if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ goto watchdog_short_circuit;
+
+ /* get one bit for every active tx/rx interrupt vector */
+ for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
+ struct ixgbevf_q_vector *qv = adapter->q_vector[i];
+ if (qv->rxr_count || qv->txr_count)
+ eics |= (1 << i);
+ }
+
+ IXGBE_WRITE_REG(hw, IXGBE_VTEICS, (u32)eics);
+
+watchdog_short_circuit:
+ schedule_work(&adapter->watchdog_task);
+}
+
+/**
+ * ixgbevf_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+static void ixgbevf_tx_timeout(struct net_device *netdev)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+ /* Do the reset outside of interrupt context */
+ schedule_work(&adapter->reset_task);
+}
+
+static void ixgbevf_reset_task(struct work_struct *work)
+{
+ struct ixgbevf_adapter *adapter;
+ adapter = container_of(work, struct ixgbevf_adapter, reset_task);
+
+ /* If we're already down or resetting, just bail */
+ if (test_bit(__IXGBEVF_DOWN, &adapter->state) ||
+ test_bit(__IXGBEVF_RESETTING, &adapter->state))
+ return;
+
+ adapter->tx_timeout_count++;
+
+ ixgbevf_reinit_locked(adapter);
+}
+
+/**
+ * ixgbevf_watchdog_task - worker thread to bring link up
+ * @work: pointer to work_struct containing our data
+ **/
+static void ixgbevf_watchdog_task(struct work_struct *work)
+{
+ struct ixgbevf_adapter *adapter = container_of(work,
+ struct ixgbevf_adapter,
+ watchdog_task);
+ struct net_device *netdev = adapter->netdev;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 link_speed = adapter->link_speed;
+ bool link_up = adapter->link_up;
+
+ adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK;
+
+ /*
+ * Always check the link on the watchdog because we have
+ * no LSC interrupt
+ */
+ if (hw->mac.ops.check_link) {
+ if ((hw->mac.ops.check_link(hw, &link_speed,
+ &link_up, false)) != 0) {
+ adapter->link_up = link_up;
+ adapter->link_speed = link_speed;
+ netif_carrier_off(netdev);
+ netif_tx_stop_all_queues(netdev);
+ schedule_work(&adapter->reset_task);
+ goto pf_has_reset;
+ }
+ } else {
+ /* always assume link is up, if no check link
+ * function */
+ link_speed = IXGBE_LINK_SPEED_10GB_FULL;
+ link_up = true;
+ }
+ adapter->link_up = link_up;
+ adapter->link_speed = link_speed;
+
+ if (link_up) {
+ if (!netif_carrier_ok(netdev)) {
+ hw_dbg(&adapter->hw, "NIC Link is Up %s, ",
+ ((link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
+ "10 Gbps" : "1 Gbps"));
+ netif_carrier_on(netdev);
+ netif_tx_wake_all_queues(netdev);
+ } else {
+ /* Force detection of hung controller */
+ adapter->detect_tx_hung = true;
+ }
+ } else {
+ adapter->link_up = false;
+ adapter->link_speed = 0;
+ if (netif_carrier_ok(netdev)) {
+ hw_dbg(&adapter->hw, "NIC Link is Down\n");
+ netif_carrier_off(netdev);
+ netif_tx_stop_all_queues(netdev);
+ }
+ }
+
+pf_has_reset:
+ ixgbevf_update_stats(adapter);
+
+ /* Force detection of hung controller every watchdog period */
+ adapter->detect_tx_hung = true;
+
+ /* Reset the timer */
+ if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer,
+ round_jiffies(jiffies + (2 * HZ)));
+
+ adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK;
+}
+
+/**
+ * ixgbevf_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ * @tx_ring: Tx descriptor ring for a specific queue
+ *
+ * Free all transmit software resources
+ **/
+void ixgbevf_free_tx_resources(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_ring *tx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ ixgbevf_clean_tx_ring(adapter, tx_ring);
+
+ vfree(tx_ring->tx_buffer_info);
+ tx_ring->tx_buffer_info = NULL;
+
+ pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma);
+
+ tx_ring->desc = NULL;
+}
+
+/**
+ * ixgbevf_free_all_tx_resources - Free Tx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+static void ixgbevf_free_all_tx_resources(struct ixgbevf_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ if (adapter->tx_ring[i].desc)
+ ixgbevf_free_tx_resources(adapter,
+ &adapter->tx_ring[i]);
+
+}
+
+/**
+ * ixgbevf_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: board private structure
+ * @tx_ring: tx descriptor ring (for a specific queue) to setup
+ *
+ * Return 0 on success, negative on failure
+ **/
+int ixgbevf_setup_tx_resources(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_ring *tx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ int size;
+
+ size = sizeof(struct ixgbevf_tx_buffer) * tx_ring->count;
+ tx_ring->tx_buffer_info = vmalloc(size);
+ if (!tx_ring->tx_buffer_info)
+ goto err;
+ memset(tx_ring->tx_buffer_info, 0, size);
+
+ /* round up to nearest 4K */
+ tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc);
+ tx_ring->size = ALIGN(tx_ring->size, 4096);
+
+ tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
+ &tx_ring->dma);
+ if (!tx_ring->desc)
+ goto err;
+
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+ tx_ring->work_limit = tx_ring->count;
+ return 0;
+
+err:
+ vfree(tx_ring->tx_buffer_info);
+ tx_ring->tx_buffer_info = NULL;
+ hw_dbg(&adapter->hw, "Unable to allocate memory for the transmit "
+ "descriptor ring\n");
+ return -ENOMEM;
+}
+
+/**
+ * ixgbevf_setup_all_tx_resources - allocate all queues Tx resources
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not). It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int ixgbevf_setup_all_tx_resources(struct ixgbevf_adapter *adapter)
+{
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ err = ixgbevf_setup_tx_resources(adapter, &adapter->tx_ring[i]);
+ if (!err)
+ continue;
+ hw_dbg(&adapter->hw,
+ "Allocation for Tx Queue %u failed\n", i);
+ break;
+ }
+
+ return err;
+}
+
+/**
+ * ixgbevf_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ * @rx_ring: rx descriptor ring (for a specific queue) to setup
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int ixgbevf_setup_rx_resources(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_ring *rx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ int size;
+
+ size = sizeof(struct ixgbevf_rx_buffer) * rx_ring->count;
+ rx_ring->rx_buffer_info = vmalloc(size);
+ if (!rx_ring->rx_buffer_info) {
+ hw_dbg(&adapter->hw,
+ "Unable to vmalloc buffer memory for "
+ "the receive descriptor ring\n");
+ goto alloc_failed;
+ }
+ memset(rx_ring->rx_buffer_info, 0, size);
+
+ /* Round up to nearest 4K */
+ rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc);
+ rx_ring->size = ALIGN(rx_ring->size, 4096);
+
+ rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
+ &rx_ring->dma);
+
+ if (!rx_ring->desc) {
+ hw_dbg(&adapter->hw,
+ "Unable to allocate memory for "
+ "the receive descriptor ring\n");
+ vfree(rx_ring->rx_buffer_info);
+ rx_ring->rx_buffer_info = NULL;
+ goto alloc_failed;
+ }
+
+ rx_ring->next_to_clean = 0;
+ rx_ring->next_to_use = 0;
+
+ return 0;
+alloc_failed:
+ return -ENOMEM;
+}
+
+/**
+ * ixgbevf_setup_all_rx_resources - allocate all queues Rx resources
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not). It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int ixgbevf_setup_all_rx_resources(struct ixgbevf_adapter *adapter)
+{
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ err = ixgbevf_setup_rx_resources(adapter, &adapter->rx_ring[i]);
+ if (!err)
+ continue;
+ hw_dbg(&adapter->hw,
+ "Allocation for Rx Queue %u failed\n", i);
+ break;
+ }
+ return err;
+}
+
+/**
+ * ixgbevf_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ * @rx_ring: ring to clean the resources from
+ *
+ * Free all receive software resources
+ **/
+void ixgbevf_free_rx_resources(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_ring *rx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ ixgbevf_clean_rx_ring(adapter, rx_ring);
+
+ vfree(rx_ring->rx_buffer_info);
+ rx_ring->rx_buffer_info = NULL;
+
+ pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
+
+ rx_ring->desc = NULL;
+}
+
+/**
+ * ixgbevf_free_all_rx_resources - Free Rx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+static void ixgbevf_free_all_rx_resources(struct ixgbevf_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ if (adapter->rx_ring[i].desc)
+ ixgbevf_free_rx_resources(adapter,
+ &adapter->rx_ring[i]);
+}
+
+/**
+ * ixgbevf_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP). At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int ixgbevf_open(struct net_device *netdev)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ int err;
+
+ /* disallow open during test */
+ if (test_bit(__IXGBEVF_TESTING, &adapter->state))
+ return -EBUSY;
+
+ if (hw->adapter_stopped) {
+ ixgbevf_reset(adapter);
+ /* if adapter is still stopped then PF isn't up and
+ * the vf can't start. */
+ if (hw->adapter_stopped) {
+ err = IXGBE_ERR_MBX;
+ printk(KERN_ERR "Unable to start - perhaps the PF"
+ "Driver isn't up yet\n");
+ goto err_setup_reset;
+ }
+ }
+
+ /* allocate transmit descriptors */
+ err = ixgbevf_setup_all_tx_resources(adapter);
+ if (err)
+ goto err_setup_tx;
+
+ /* allocate receive descriptors */
+ err = ixgbevf_setup_all_rx_resources(adapter);
+ if (err)
+ goto err_setup_rx;
+
+ ixgbevf_configure(adapter);
+
+ /*
+ * Map the Tx/Rx rings to the vectors we were allotted.
+ * if request_irq will be called in this function map_rings
+ * must be called *before* up_complete
+ */
+ ixgbevf_map_rings_to_vectors(adapter);
+
+ err = ixgbevf_up_complete(adapter);
+ if (err)
+ goto err_up;
+
+ /* clear any pending interrupts, may auto mask */
+ IXGBE_READ_REG(hw, IXGBE_VTEICR);
+ err = ixgbevf_request_irq(adapter);
+ if (err)
+ goto err_req_irq;
+
+ ixgbevf_irq_enable(adapter, true, true);
+
+ return 0;
+
+err_req_irq:
+ ixgbevf_down(adapter);
+err_up:
+ ixgbevf_free_irq(adapter);
+err_setup_rx:
+ ixgbevf_free_all_rx_resources(adapter);
+err_setup_tx:
+ ixgbevf_free_all_tx_resources(adapter);
+ ixgbevf_reset(adapter);
+
+err_setup_reset:
+
+ return err;
+}
+
+/**
+ * ixgbevf_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS. The hardware is still under the drivers control, but
+ * needs to be disabled. A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static int ixgbevf_close(struct net_device *netdev)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+ ixgbevf_down(adapter);
+ ixgbevf_free_irq(adapter);
+
+ ixgbevf_free_all_tx_resources(adapter);
+ ixgbevf_free_all_rx_resources(adapter);
+
+ return 0;
+}
+
+static int ixgbevf_tso(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_ring *tx_ring,
+ struct sk_buff *skb, u32 tx_flags, u8 *hdr_len)
+{
+ struct ixgbe_adv_tx_context_desc *context_desc;
+ unsigned int i;
+ int err;
+ struct ixgbevf_tx_buffer *tx_buffer_info;
+ u32 vlan_macip_lens = 0, type_tucmd_mlhl;
+ u32 mss_l4len_idx, l4len;
+
+ if (skb_is_gso(skb)) {
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (err)
+ return err;
+ }
+ l4len = tcp_hdrlen(skb);
+ *hdr_len += l4len;
+
+ if (skb->protocol == htons(ETH_P_IP)) {
+ struct iphdr *iph = ip_hdr(skb);
+ iph->tot_len = 0;
+ iph->check = 0;
+ tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+ iph->daddr, 0,
+ IPPROTO_TCP,
+ 0);
+ adapter->hw_tso_ctxt++;
+ } else if (skb_is_gso_v6(skb)) {
+ ipv6_hdr(skb)->payload_len = 0;
+ tcp_hdr(skb)->check =
+ ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0);
+ adapter->hw_tso6_ctxt++;
+ }
+
+ i = tx_ring->next_to_use;
+
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+
+ /* VLAN MACLEN IPLEN */
+ if (tx_flags & IXGBE_TX_FLAGS_VLAN)
+ vlan_macip_lens |=
+ (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
+ vlan_macip_lens |= ((skb_network_offset(skb)) <<
+ IXGBE_ADVTXD_MACLEN_SHIFT);
+ *hdr_len += skb_network_offset(skb);
+ vlan_macip_lens |=
+ (skb_transport_header(skb) - skb_network_header(skb));
+ *hdr_len +=
+ (skb_transport_header(skb) - skb_network_header(skb));
+ context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
+ context_desc->seqnum_seed = 0;
+
+ /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
+ type_tucmd_mlhl = (IXGBE_TXD_CMD_DEXT |
+ IXGBE_ADVTXD_DTYP_CTXT);
+
+ if (skb->protocol == htons(ETH_P_IP))
+ type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
+ type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
+
+ /* MSS L4LEN IDX */
+ mss_l4len_idx =
+ (skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT);
+ mss_l4len_idx |= (l4len << IXGBE_ADVTXD_L4LEN_SHIFT);
+ /* use index 1 for TSO */
+ mss_l4len_idx |= (1 << IXGBE_ADVTXD_IDX_SHIFT);
+ context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
+
+ tx_buffer_info->time_stamp = jiffies;
+ tx_buffer_info->next_to_watch = i;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ tx_ring->next_to_use = i;
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool ixgbevf_tx_csum(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_ring *tx_ring,
+ struct sk_buff *skb, u32 tx_flags)
+{
+ struct ixgbe_adv_tx_context_desc *context_desc;
+ unsigned int i;
+ struct ixgbevf_tx_buffer *tx_buffer_info;
+ u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL ||
+ (tx_flags & IXGBE_TX_FLAGS_VLAN)) {
+ i = tx_ring->next_to_use;
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+
+ if (tx_flags & IXGBE_TX_FLAGS_VLAN)
+ vlan_macip_lens |= (tx_flags &
+ IXGBE_TX_FLAGS_VLAN_MASK);
+ vlan_macip_lens |= (skb_network_offset(skb) <<
+ IXGBE_ADVTXD_MACLEN_SHIFT);
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ vlan_macip_lens |= (skb_transport_header(skb) -
+ skb_network_header(skb));
+
+ context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
+ context_desc->seqnum_seed = 0;
+
+ type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT |
+ IXGBE_ADVTXD_DTYP_CTXT);
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ switch (skb->protocol) {
+ case __constant_htons(ETH_P_IP):
+ type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
+ if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+ type_tucmd_mlhl |=
+ IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ break;
+ case __constant_htons(ETH_P_IPV6):
+ /* XXX what about other V6 headers?? */
+ if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+ type_tucmd_mlhl |=
+ IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ break;
+ default:
+ if (unlikely(net_ratelimit())) {
+ printk(KERN_WARNING
+ "partial checksum but "
+ "proto=%x!\n",
+ skb->protocol);
+ }
+ break;
+ }
+ }
+
+ context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
+ /* use index zero for tx checksum offload */
+ context_desc->mss_l4len_idx = 0;
+
+ tx_buffer_info->time_stamp = jiffies;
+ tx_buffer_info->next_to_watch = i;
+
+ adapter->hw_csum_tx_good++;
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ tx_ring->next_to_use = i;
+
+ return true;
+ }
+
+ return false;
+}
+
+static int ixgbevf_tx_map(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_ring *tx_ring,
+ struct sk_buff *skb, u32 tx_flags,
+ unsigned int first)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct ixgbevf_tx_buffer *tx_buffer_info;
+ unsigned int len;
+ unsigned int total = skb->len;
+ unsigned int offset = 0, size, count = 0, i;
+ unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+ unsigned int f;
+
+ i = tx_ring->next_to_use;
+
+ len = min(skb_headlen(skb), total);
+ while (len) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ size = min(len, (unsigned int)IXGBE_MAX_DATA_PER_TXD);
+
+ tx_buffer_info->length = size;
+ tx_buffer_info->mapped_as_page = false;
+ tx_buffer_info->dma = pci_map_single(adapter->pdev,
+ skb->data + offset,
+ size, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(pdev, tx_buffer_info->dma))
+ goto dma_error;
+ tx_buffer_info->time_stamp = jiffies;
+ tx_buffer_info->next_to_watch = i;
+
+ len -= size;
+ total -= size;
+ offset += size;
+ count++;
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ for (f = 0; f < nr_frags; f++) {
+ struct skb_frag_struct *frag;
+
+ frag = &skb_shinfo(skb)->frags[f];
+ len = min((unsigned int)frag->size, total);
+ offset = frag->page_offset;
+
+ while (len) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ size = min(len, (unsigned int)IXGBE_MAX_DATA_PER_TXD);
+
+ tx_buffer_info->length = size;
+ tx_buffer_info->dma = pci_map_page(adapter->pdev,
+ frag->page,
+ offset,
+ size,
+ PCI_DMA_TODEVICE);
+ tx_buffer_info->mapped_as_page = true;
+ if (pci_dma_mapping_error(pdev, tx_buffer_info->dma))
+ goto dma_error;
+ tx_buffer_info->time_stamp = jiffies;
+ tx_buffer_info->next_to_watch = i;
+
+ len -= size;
+ total -= size;
+ offset += size;
+ count++;
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+ if (total == 0)
+ break;
+ }
+
+ if (i == 0)
+ i = tx_ring->count - 1;
+ else
+ i = i - 1;
+ tx_ring->tx_buffer_info[i].skb = skb;
+ tx_ring->tx_buffer_info[first].next_to_watch = i;
+
+ return count;
+
+dma_error:
+ dev_err(&pdev->dev, "TX DMA map failed\n");
+
+ /* clear timestamp and dma mappings for failed tx_buffer_info map */
+ tx_buffer_info->dma = 0;
+ tx_buffer_info->time_stamp = 0;
+ tx_buffer_info->next_to_watch = 0;
+ count--;
+
+ /* clear timestamp and dma mappings for remaining portion of packet */
+ while (count >= 0) {
+ count--;
+ i--;
+ if (i < 0)
+ i += tx_ring->count;
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ ixgbevf_unmap_and_free_tx_resource(adapter, tx_buffer_info);
+ }
+
+ return count;
+}
+
+static void ixgbevf_tx_queue(struct ixgbevf_adapter *adapter,
+ struct ixgbevf_ring *tx_ring, int tx_flags,
+ int count, u32 paylen, u8 hdr_len)
+{
+ union ixgbe_adv_tx_desc *tx_desc = NULL;
+ struct ixgbevf_tx_buffer *tx_buffer_info;
+ u32 olinfo_status = 0, cmd_type_len = 0;
+ unsigned int i;
+
+ u32 txd_cmd = IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS | IXGBE_TXD_CMD_IFCS;
+
+ cmd_type_len |= IXGBE_ADVTXD_DTYP_DATA;
+
+ cmd_type_len |= IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT;
+
+ if (tx_flags & IXGBE_TX_FLAGS_VLAN)
+ cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE;
+
+ if (tx_flags & IXGBE_TX_FLAGS_TSO) {
+ cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE;
+
+ olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
+ IXGBE_ADVTXD_POPTS_SHIFT;
+
+ /* use index 1 context for tso */
+ olinfo_status |= (1 << IXGBE_ADVTXD_IDX_SHIFT);
+ if (tx_flags & IXGBE_TX_FLAGS_IPV4)
+ olinfo_status |= IXGBE_TXD_POPTS_IXSM <<
+ IXGBE_ADVTXD_POPTS_SHIFT;
+
+ } else if (tx_flags & IXGBE_TX_FLAGS_CSUM)
+ olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
+ IXGBE_ADVTXD_POPTS_SHIFT;
+
+ olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT);
+
+ i = tx_ring->next_to_use;
+ while (count--) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+ tx_desc->read.buffer_addr = cpu_to_le64(tx_buffer_info->dma);
+ tx_desc->read.cmd_type_len =
+ cpu_to_le32(cmd_type_len | tx_buffer_info->length);
+ tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ tx_desc->read.cmd_type_len |= cpu_to_le32(txd_cmd);
+
+ /*
+ * 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();
+
+ tx_ring->next_to_use = i;
+ writel(i, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+static int __ixgbevf_maybe_stop_tx(struct net_device *netdev,
+ struct ixgbevf_ring *tx_ring, int size)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+ netif_stop_subqueue(netdev, tx_ring->queue_index);
+ /* Herbert's original patch had:
+ * smp_mb__after_netif_stop_queue();
+ * but since that doesn't exist yet, just open code it. */
+ smp_mb();
+
+ /* We need to check again in a case another CPU has just
+ * made room available. */
+ if (likely(IXGBE_DESC_UNUSED(tx_ring) < size))
+ return -EBUSY;
+
+ /* A reprieve! - use start_queue because it doesn't call schedule */
+ netif_start_subqueue(netdev, tx_ring->queue_index);
+ ++adapter->restart_queue;
+ return 0;
+}
+
+static int ixgbevf_maybe_stop_tx(struct net_device *netdev,
+ struct ixgbevf_ring *tx_ring, int size)
+{
+ if (likely(IXGBE_DESC_UNUSED(tx_ring) >= size))
+ return 0;
+ return __ixgbevf_maybe_stop_tx(netdev, tx_ring, size);
+}
+
+static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct ixgbevf_ring *tx_ring;
+ unsigned int first;
+ unsigned int tx_flags = 0;
+ u8 hdr_len = 0;
+ int r_idx = 0, tso;
+ int count = 0;
+
+ unsigned int f;
+
+ tx_ring = &adapter->tx_ring[r_idx];
+
+ if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ tx_flags |= vlan_tx_tag_get(skb);
+ tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
+ tx_flags |= IXGBE_TX_FLAGS_VLAN;
+ }
+
+ /* four things can cause us to need a context descriptor */
+ if (skb_is_gso(skb) ||
+ (skb->ip_summed == CHECKSUM_PARTIAL) ||
+ (tx_flags & IXGBE_TX_FLAGS_VLAN))
+ count++;
+
+ count += TXD_USE_COUNT(skb_headlen(skb));
+ for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+ count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
+
+ if (ixgbevf_maybe_stop_tx(netdev, tx_ring, count)) {
+ adapter->tx_busy++;
+ return NETDEV_TX_BUSY;
+ }
+
+ first = tx_ring->next_to_use;
+
+ if (skb->protocol == htons(ETH_P_IP))
+ tx_flags |= IXGBE_TX_FLAGS_IPV4;
+ tso = ixgbevf_tso(adapter, tx_ring, skb, tx_flags, &hdr_len);
+ if (tso < 0) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ if (tso)
+ tx_flags |= IXGBE_TX_FLAGS_TSO;
+ else if (ixgbevf_tx_csum(adapter, tx_ring, skb, tx_flags) &&
+ (skb->ip_summed == CHECKSUM_PARTIAL))
+ tx_flags |= IXGBE_TX_FLAGS_CSUM;
+
+ ixgbevf_tx_queue(adapter, tx_ring, tx_flags,
+ ixgbevf_tx_map(adapter, tx_ring, skb, tx_flags, first),
+ skb->len, hdr_len);
+
+ netdev->trans_start = jiffies;
+
+ ixgbevf_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED);
+
+ return NETDEV_TX_OK;
+}
+
+/**
+ * ixgbevf_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ **/
+static struct net_device_stats *ixgbevf_get_stats(struct net_device *netdev)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+ /* only return the current stats */
+ return &adapter->net_stats;
+}
+
+/**
+ * ixgbevf_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int ixgbevf_set_mac(struct net_device *netdev, void *p)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
+
+ if (hw->mac.ops.set_rar)
+ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0);
+
+ return 0;
+}
+
+/**
+ * ixgbevf_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int ixgbevf_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+
+ /* MTU < 68 is an error and causes problems on some kernels */
+ if ((new_mtu < 68) || (max_frame > MAXIMUM_ETHERNET_VLAN_SIZE))
+ return -EINVAL;
+
+ hw_dbg(&adapter->hw, "changing MTU from %d to %d\n",
+ netdev->mtu, new_mtu);
+ /* must set new MTU before calling down or up */
+ netdev->mtu = new_mtu;
+
+ if (netif_running(netdev))
+ ixgbevf_reinit_locked(adapter);
+
+ return 0;
+}
+
+static void ixgbevf_shutdown(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev)) {
+ ixgbevf_down(adapter);
+ ixgbevf_free_irq(adapter);
+ ixgbevf_free_all_tx_resources(adapter);
+ ixgbevf_free_all_rx_resources(adapter);
+ }
+
+#ifdef CONFIG_PM
+ pci_save_state(pdev);
+#endif
+
+ pci_disable_device(pdev);
+}
+
+static const struct net_device_ops ixgbe_netdev_ops = {
+ .ndo_open = &ixgbevf_open,
+ .ndo_stop = &ixgbevf_close,
+ .ndo_start_xmit = &ixgbevf_xmit_frame,
+ .ndo_get_stats = &ixgbevf_get_stats,
+ .ndo_set_rx_mode = &ixgbevf_set_rx_mode,
+ .ndo_set_multicast_list = &ixgbevf_set_rx_mode,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = &ixgbevf_set_mac,
+ .ndo_change_mtu = &ixgbevf_change_mtu,
+ .ndo_tx_timeout = &ixgbevf_tx_timeout,
+ .ndo_vlan_rx_register = &ixgbevf_vlan_rx_register,
+ .ndo_vlan_rx_add_vid = &ixgbevf_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = &ixgbevf_vlan_rx_kill_vid,
+};
+
+static void ixgbevf_assign_netdev_ops(struct net_device *dev)
+{
+ struct ixgbevf_adapter *adapter;
+ adapter = netdev_priv(dev);
+ dev->netdev_ops = &ixgbe_netdev_ops;
+ ixgbevf_set_ethtool_ops(dev);
+ dev->watchdog_timeo = 5 * HZ;
+}
+
+/**
+ * ixgbevf_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in ixgbevf_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * ixgbevf_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *netdev;
+ struct ixgbevf_adapter *adapter = NULL;
+ struct ixgbe_hw *hw = NULL;
+ const struct ixgbevf_info *ii = ixgbevf_info_tbl[ent->driver_data];
+ static int cards_found;
+ int err, pci_using_dac;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
+ !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ pci_using_dac = 1;
+ } else {
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err) {
+ err = pci_set_consistent_dma_mask(pdev,
+ DMA_BIT_MASK(32));
+ if (err) {
+ dev_err(&pdev->dev, "No usable DMA "
+ "configuration, aborting\n");
+ goto err_dma;
+ }
+ }
+ pci_using_dac = 0;
+ }
+
+ err = pci_request_regions(pdev, ixgbevf_driver_name);
+ if (err) {
+ dev_err(&pdev->dev, "pci_request_regions failed 0x%x\n", err);
+ goto err_pci_reg;
+ }
+
+ pci_set_master(pdev);
+
+#ifdef HAVE_TX_MQ
+ netdev = alloc_etherdev_mq(sizeof(struct ixgbevf_adapter),
+ MAX_TX_QUEUES);
+#else
+ netdev = alloc_etherdev(sizeof(struct ixgbevf_adapter));
+#endif
+ if (!netdev) {
+ err = -ENOMEM;
+ goto err_alloc_etherdev;
+ }
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ pci_set_drvdata(pdev, netdev);
+ adapter = netdev_priv(netdev);
+
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ hw = &adapter->hw;
+ hw->back = adapter;
+ adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
+
+ /*
+ * call save state here in standalone driver because it relies on
+ * adapter struct to exist, and needs to call netdev_priv
+ */
+ pci_save_state(pdev);
+
+ hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (!hw->hw_addr) {
+ err = -EIO;
+ goto err_ioremap;
+ }
+
+ ixgbevf_assign_netdev_ops(netdev);
+
+ adapter->bd_number = cards_found;
+
+ /* Setup hw api */
+ memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops));
+ hw->mac.type = ii->mac;
+
+ memcpy(&hw->mbx.ops, &ixgbevf_mbx_ops,
+ sizeof(struct ixgbe_mac_operations));
+
+ adapter->flags &= ~IXGBE_FLAG_RX_PS_CAPABLE;
+ adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
+ adapter->flags |= IXGBE_FLAG_RX_1BUF_CAPABLE;
+
+ /* setup the private structure */
+ err = ixgbevf_sw_init(adapter);
+
+ ixgbevf_init_last_counter_stats(adapter);
+
+#ifdef MAX_SKB_FRAGS
+ netdev->features = NETIF_F_SG |
+ NETIF_F_IP_CSUM |
+ NETIF_F_HW_VLAN_TX |
+ NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER;
+
+ netdev->features |= NETIF_F_IPV6_CSUM;
+ netdev->features |= NETIF_F_TSO;
+ netdev->features |= NETIF_F_TSO6;
+ netdev->vlan_features |= NETIF_F_TSO;
+ netdev->vlan_features |= NETIF_F_TSO6;
+ netdev->vlan_features |= NETIF_F_IP_CSUM;
+ netdev->vlan_features |= NETIF_F_SG;
+
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+#endif /* MAX_SKB_FRAGS */
+
+ /* The HW MAC address was set and/or determined in sw_init */
+ memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
+ memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
+
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ printk(KERN_ERR "invalid MAC address\n");
+ err = -EIO;
+ goto err_sw_init;
+ }
+
+ init_timer(&adapter->watchdog_timer);
+ adapter->watchdog_timer.function = &ixgbevf_watchdog;
+ adapter->watchdog_timer.data = (unsigned long)adapter;
+
+ INIT_WORK(&adapter->reset_task, ixgbevf_reset_task);
+ INIT_WORK(&adapter->watchdog_task, ixgbevf_watchdog_task);
+
+ err = ixgbevf_init_interrupt_scheme(adapter);
+ if (err)
+ goto err_sw_init;
+
+ /* pick up the PCI bus settings for reporting later */
+ if (hw->mac.ops.get_bus_info)
+ hw->mac.ops.get_bus_info(hw);
+
+
+ netif_carrier_off(netdev);
+ netif_tx_stop_all_queues(netdev);
+
+ strcpy(netdev->name, "eth%d");
+
+ err = register_netdev(netdev);
+ if (err)
+ goto err_register;
+
+ adapter->netdev_registered = true;
+
+ /* print the MAC address */
+ hw_dbg(hw, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
+ netdev->dev_addr[0],
+ netdev->dev_addr[1],
+ netdev->dev_addr[2],
+ netdev->dev_addr[3],
+ netdev->dev_addr[4],
+ netdev->dev_addr[5]);
+
+ hw_dbg(hw, "MAC: %d\n", hw->mac.type);
+
+ hw_dbg(hw, "LRO is disabled \n");
+
+ hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
+ cards_found++;
+ return 0;
+
+err_register:
+err_sw_init:
+ ixgbevf_reset_interrupt_capability(adapter);
+ iounmap(hw->hw_addr);
+err_ioremap:
+ free_netdev(netdev);
+err_alloc_etherdev:
+ pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+ pci_disable_device(pdev);
+ return err;
+}
+
+/**
+ * ixgbevf_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * ixgbevf_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+ set_bit(__IXGBEVF_DOWN, &adapter->state);
+
+ del_timer_sync(&adapter->watchdog_timer);
+
+ cancel_work_sync(&adapter->watchdog_task);
+
+ flush_scheduled_work();
+
+ if (adapter->netdev_registered) {
+ unregister_netdev(netdev);
+ adapter->netdev_registered = false;
+ }
+
+ ixgbevf_reset_interrupt_capability(adapter);
+
+ iounmap(adapter->hw.hw_addr);
+ pci_release_regions(pdev);
+
+ hw_dbg(&adapter->hw, "Remove complete\n");
+
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+
+ free_netdev(netdev);
+
+ pci_disable_device(pdev);
+}
+
+static struct pci_driver ixgbevf_driver = {
+ .name = ixgbevf_driver_name,
+ .id_table = ixgbevf_pci_tbl,
+ .probe = ixgbevf_probe,
+ .remove = __devexit_p(ixgbevf_remove),
+ .shutdown = ixgbevf_shutdown,
+};
+
+/**
+ * ixgbe_init_module - Driver Registration Routine
+ *
+ * ixgbe_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+static int __init ixgbevf_init_module(void)
+{
+ int ret;
+ printk(KERN_INFO "ixgbevf: %s - version %s\n", ixgbevf_driver_string,
+ ixgbevf_driver_version);
+
+ printk(KERN_INFO "%s\n", ixgbevf_copyright);
+
+ ret = pci_register_driver(&ixgbevf_driver);
+ return ret;
+}
+
+module_init(ixgbevf_init_module);
+
+/**
+ * ixgbe_exit_module - Driver Exit Cleanup Routine
+ *
+ * ixgbe_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+static void __exit ixgbevf_exit_module(void)
+{
+ pci_unregister_driver(&ixgbevf_driver);
+}
+
+#ifdef DEBUG
+/**
+ * ixgbe_get_hw_dev_name - return device name string
+ * used by hardware layer to print debugging information
+ **/
+char *ixgbevf_get_hw_dev_name(struct ixgbe_hw *hw)
+{
+ struct ixgbevf_adapter *adapter = hw->back;
+ return adapter->netdev->name;
+}
+
+#endif
+module_exit(ixgbevf_exit_module);
+
+/* ixgbevf_main.c */
diff --git a/drivers/net/ixgbevf/mbx.c b/drivers/net/ixgbevf/mbx.c
new file mode 100644
index 000000000000..b8143501e6fc
--- /dev/null
+++ b/drivers/net/ixgbevf/mbx.c
@@ -0,0 +1,341 @@
+/*******************************************************************************
+
+ Intel 82599 Virtual Function driver
+ Copyright(c) 1999 - 2009 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "mbx.h"
+
+/**
+ * ixgbevf_poll_for_msg - Wait for message notification
+ * @hw: pointer to the HW structure
+ *
+ * returns 0 if it successfully received a message notification
+ **/
+static s32 ixgbevf_poll_for_msg(struct ixgbe_hw *hw)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ int countdown = mbx->timeout;
+
+ while (countdown && mbx->ops.check_for_msg(hw)) {
+ countdown--;
+ udelay(mbx->udelay);
+ }
+
+ /* if we failed, all future posted messages fail until reset */
+ if (!countdown)
+ mbx->timeout = 0;
+
+ return countdown ? 0 : IXGBE_ERR_MBX;
+}
+
+/**
+ * ixgbevf_poll_for_ack - Wait for message acknowledgement
+ * @hw: pointer to the HW structure
+ *
+ * returns 0 if it successfully received a message acknowledgement
+ **/
+static s32 ixgbevf_poll_for_ack(struct ixgbe_hw *hw)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ int countdown = mbx->timeout;
+
+ while (countdown && mbx->ops.check_for_ack(hw)) {
+ countdown--;
+ udelay(mbx->udelay);
+ }
+
+ /* if we failed, all future posted messages fail until reset */
+ if (!countdown)
+ mbx->timeout = 0;
+
+ return countdown ? 0 : IXGBE_ERR_MBX;
+}
+
+/**
+ * ixgbevf_read_posted_mbx - Wait for message notification and receive message
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ *
+ * returns 0 if it successfully received a message notification and
+ * copied it into the receive buffer.
+ **/
+static s32 ixgbevf_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ ret_val = ixgbevf_poll_for_msg(hw);
+
+ /* if ack received read message, otherwise we timed out */
+ if (!ret_val)
+ ret_val = mbx->ops.read(hw, msg, size);
+
+ return ret_val;
+}
+
+/**
+ * ixgbevf_write_posted_mbx - Write a message to the mailbox, wait for ack
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ *
+ * returns 0 if it successfully copied message into the buffer and
+ * received an ack to that message within delay * timeout period
+ **/
+static s32 ixgbevf_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ s32 ret_val;
+
+ /* send msg */
+ ret_val = mbx->ops.write(hw, msg, size);
+
+ /* if msg sent wait until we receive an ack */
+ if (!ret_val)
+ ret_val = ixgbevf_poll_for_ack(hw);
+
+ return ret_val;
+}
+
+/**
+ * ixgbevf_read_v2p_mailbox - read v2p mailbox
+ * @hw: pointer to the HW structure
+ *
+ * This function is used to read the v2p mailbox without losing the read to
+ * clear status bits.
+ **/
+static u32 ixgbevf_read_v2p_mailbox(struct ixgbe_hw *hw)
+{
+ u32 v2p_mailbox = IXGBE_READ_REG(hw, IXGBE_VFMAILBOX);
+
+ v2p_mailbox |= hw->mbx.v2p_mailbox;
+ hw->mbx.v2p_mailbox |= v2p_mailbox & IXGBE_VFMAILBOX_R2C_BITS;
+
+ return v2p_mailbox;
+}
+
+/**
+ * ixgbevf_check_for_bit_vf - Determine if a status bit was set
+ * @hw: pointer to the HW structure
+ * @mask: bitmask for bits to be tested and cleared
+ *
+ * This function is used to check for the read to clear bits within
+ * the V2P mailbox.
+ **/
+static s32 ixgbevf_check_for_bit_vf(struct ixgbe_hw *hw, u32 mask)
+{
+ u32 v2p_mailbox = ixgbevf_read_v2p_mailbox(hw);
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ if (v2p_mailbox & mask)
+ ret_val = 0;
+
+ hw->mbx.v2p_mailbox &= ~mask;
+
+ return ret_val;
+}
+
+/**
+ * ixgbevf_check_for_msg_vf - checks to see if the PF has sent mail
+ * @hw: pointer to the HW structure
+ *
+ * returns 0 if the PF has set the Status bit or else ERR_MBX
+ **/
+static s32 ixgbevf_check_for_msg_vf(struct ixgbe_hw *hw)
+{
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ if (!ixgbevf_check_for_bit_vf(hw, IXGBE_VFMAILBOX_PFSTS)) {
+ ret_val = 0;
+ hw->mbx.stats.reqs++;
+ }
+
+ return ret_val;
+}
+
+/**
+ * ixgbevf_check_for_ack_vf - checks to see if the PF has ACK'd
+ * @hw: pointer to the HW structure
+ *
+ * returns 0 if the PF has set the ACK bit or else ERR_MBX
+ **/
+static s32 ixgbevf_check_for_ack_vf(struct ixgbe_hw *hw)
+{
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ if (!ixgbevf_check_for_bit_vf(hw, IXGBE_VFMAILBOX_PFACK)) {
+ ret_val = 0;
+ hw->mbx.stats.acks++;
+ }
+
+ return ret_val;
+}
+
+/**
+ * ixgbevf_check_for_rst_vf - checks to see if the PF has reset
+ * @hw: pointer to the HW structure
+ *
+ * returns true if the PF has set the reset done bit or else false
+ **/
+static s32 ixgbevf_check_for_rst_vf(struct ixgbe_hw *hw)
+{
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ if (!ixgbevf_check_for_bit_vf(hw, (IXGBE_VFMAILBOX_RSTD |
+ IXGBE_VFMAILBOX_RSTI))) {
+ ret_val = 0;
+ hw->mbx.stats.rsts++;
+ }
+
+ return ret_val;
+}
+
+/**
+ * ixgbevf_obtain_mbx_lock_vf - obtain mailbox lock
+ * @hw: pointer to the HW structure
+ *
+ * return 0 if we obtained the mailbox lock
+ **/
+static s32 ixgbevf_obtain_mbx_lock_vf(struct ixgbe_hw *hw)
+{
+ s32 ret_val = IXGBE_ERR_MBX;
+
+ /* Take ownership of the buffer */
+ IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_VFU);
+
+ /* reserve mailbox for vf use */
+ if (ixgbevf_read_v2p_mailbox(hw) & IXGBE_VFMAILBOX_VFU)
+ ret_val = 0;
+
+ return ret_val;
+}
+
+/**
+ * ixgbevf_write_mbx_vf - Write a message to the mailbox
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ *
+ * returns 0 if it successfully copied message into the buffer
+ **/
+static s32 ixgbevf_write_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size)
+{
+ s32 ret_val;
+ u16 i;
+
+
+ /* lock the mailbox to prevent pf/vf race condition */
+ ret_val = ixgbevf_obtain_mbx_lock_vf(hw);
+ if (ret_val)
+ goto out_no_write;
+
+ /* flush msg and acks as we are overwriting the message buffer */
+ ixgbevf_check_for_msg_vf(hw);
+ ixgbevf_check_for_ack_vf(hw);
+
+ /* copy the caller specified message to the mailbox memory buffer */
+ for (i = 0; i < size; i++)
+ IXGBE_WRITE_REG_ARRAY(hw, IXGBE_VFMBMEM, i, msg[i]);
+
+ /* update stats */
+ hw->mbx.stats.msgs_tx++;
+
+ /* Drop VFU and interrupt the PF to tell it a message has been sent */
+ IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_REQ);
+
+out_no_write:
+ return ret_val;
+}
+
+/**
+ * ixgbevf_read_mbx_vf - Reads a message from the inbox intended for vf
+ * @hw: pointer to the HW structure
+ * @msg: The message buffer
+ * @size: Length of buffer
+ *
+ * returns 0 if it successfuly read message from buffer
+ **/
+static s32 ixgbevf_read_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size)
+{
+ s32 ret_val = 0;
+ u16 i;
+
+ /* lock the mailbox to prevent pf/vf race condition */
+ ret_val = ixgbevf_obtain_mbx_lock_vf(hw);
+ if (ret_val)
+ goto out_no_read;
+
+ /* copy the message from the mailbox memory buffer */
+ for (i = 0; i < size; i++)
+ msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_VFMBMEM, i);
+
+ /* Acknowledge receipt and release mailbox, then we're done */
+ IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_ACK);
+
+ /* update stats */
+ hw->mbx.stats.msgs_rx++;
+
+out_no_read:
+ return ret_val;
+}
+
+/**
+ * ixgbevf_init_mbx_params_vf - set initial values for vf mailbox
+ * @hw: pointer to the HW structure
+ *
+ * Initializes the hw->mbx struct to correct values for vf mailbox
+ */
+s32 ixgbevf_init_mbx_params_vf(struct ixgbe_hw *hw)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+
+ /* start mailbox as timed out and let the reset_hw call set the timeout
+ * value to begin communications */
+ mbx->timeout = 0;
+ mbx->udelay = IXGBE_VF_MBX_INIT_DELAY;
+
+ mbx->size = IXGBE_VFMAILBOX_SIZE;
+
+ mbx->stats.msgs_tx = 0;
+ mbx->stats.msgs_rx = 0;
+ mbx->stats.reqs = 0;
+ mbx->stats.acks = 0;
+ mbx->stats.rsts = 0;
+
+ return 0;
+}
+
+struct ixgbe_mbx_operations ixgbevf_mbx_ops = {
+ .init_params = ixgbevf_init_mbx_params_vf,
+ .read = ixgbevf_read_mbx_vf,
+ .write = ixgbevf_write_mbx_vf,
+ .read_posted = ixgbevf_read_posted_mbx,
+ .write_posted = ixgbevf_write_posted_mbx,
+ .check_for_msg = ixgbevf_check_for_msg_vf,
+ .check_for_ack = ixgbevf_check_for_ack_vf,
+ .check_for_rst = ixgbevf_check_for_rst_vf,
+};
+
diff --git a/drivers/net/ixgbevf/mbx.h b/drivers/net/ixgbevf/mbx.h
new file mode 100644
index 000000000000..1b0e0bf4c0f5
--- /dev/null
+++ b/drivers/net/ixgbevf/mbx.h
@@ -0,0 +1,100 @@
+/*******************************************************************************
+
+ Intel 82599 Virtual Function driver
+ Copyright(c) 1999 - 2009 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_MBX_H_
+#define _IXGBE_MBX_H_
+
+#include "vf.h"
+
+#define IXGBE_VFMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */
+#define IXGBE_ERR_MBX -100
+
+#define IXGBE_VFMAILBOX 0x002FC
+#define IXGBE_VFMBMEM 0x00200
+
+/* Define mailbox register bits */
+#define IXGBE_VFMAILBOX_REQ 0x00000001 /* Request for PF Ready bit */
+#define IXGBE_VFMAILBOX_ACK 0x00000002 /* Ack PF message received */
+#define IXGBE_VFMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */
+#define IXGBE_VFMAILBOX_PFU 0x00000008 /* PF owns the mailbox buffer */
+#define IXGBE_VFMAILBOX_PFSTS 0x00000010 /* PF wrote a message in the MB */
+#define IXGBE_VFMAILBOX_PFACK 0x00000020 /* PF ack the previous VF msg */
+#define IXGBE_VFMAILBOX_RSTI 0x00000040 /* PF has reset indication */
+#define IXGBE_VFMAILBOX_RSTD 0x00000080 /* PF has indicated reset done */
+#define IXGBE_VFMAILBOX_R2C_BITS 0x000000B0 /* All read to clear bits */
+
+#define IXGBE_PFMAILBOX(x) (0x04B00 + (4 * x))
+#define IXGBE_PFMBMEM(vfn) (0x13000 + (64 * vfn))
+
+#define IXGBE_PFMAILBOX_STS 0x00000001 /* Initiate message send to VF */
+#define IXGBE_PFMAILBOX_ACK 0x00000002 /* Ack message recv'd from VF */
+#define IXGBE_PFMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */
+#define IXGBE_PFMAILBOX_PFU 0x00000008 /* PF owns the mailbox buffer */
+#define IXGBE_PFMAILBOX_RVFU 0x00000010 /* Reset VFU - used when VF stuck */
+
+#define IXGBE_MBVFICR_VFREQ_MASK 0x0000FFFF /* bits for VF messages */
+#define IXGBE_MBVFICR_VFREQ_VF1 0x00000001 /* bit for VF 1 message */
+#define IXGBE_MBVFICR_VFACK_MASK 0xFFFF0000 /* bits for VF acks */
+#define IXGBE_MBVFICR_VFACK_VF1 0x00010000 /* bit for VF 1 ack */
+
+
+/* If it's a IXGBE_VF_* msg then it originates in the VF and is sent to the
+ * PF. The reverse is true if it is IXGBE_PF_*.
+ * Message ACK's are the value or'd with 0xF0000000
+ */
+#define IXGBE_VT_MSGTYPE_ACK 0x80000000 /* Messages below or'd with
+ * this are the ACK */
+#define IXGBE_VT_MSGTYPE_NACK 0x40000000 /* Messages below or'd with
+ * this are the NACK */
+#define IXGBE_VT_MSGTYPE_CTS 0x20000000 /* Indicates that VF is still
+ * clear to send requests */
+#define IXGBE_VT_MSGINFO_SHIFT 16
+/* bits 23:16 are used for exra info for certain messages */
+#define IXGBE_VT_MSGINFO_MASK (0xFF << IXGBE_VT_MSGINFO_SHIFT)
+
+#define IXGBE_VF_RESET 0x01 /* VF requests reset */
+#define IXGBE_VF_SET_MAC_ADDR 0x02 /* VF requests PF to set MAC addr */
+#define IXGBE_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */
+#define IXGBE_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */
+#define IXGBE_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */
+
+/* length of permanent address message returned from PF */
+#define IXGBE_VF_PERMADDR_MSG_LEN 4
+/* word in permanent address message with the current multicast type */
+#define IXGBE_VF_MC_TYPE_WORD 3
+
+#define IXGBE_PF_CONTROL_MSG 0x0100 /* PF control message */
+
+#define IXGBE_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */
+#define IXGBE_VF_MBX_INIT_DELAY 500 /* microseconds between retries */
+
+/* forward declaration of the HW struct */
+struct ixgbe_hw;
+
+s32 ixgbevf_init_mbx_params_vf(struct ixgbe_hw *);
+
+#endif /* _IXGBE_MBX_H_ */
diff --git a/drivers/net/ixgbevf/regs.h b/drivers/net/ixgbevf/regs.h
new file mode 100644
index 000000000000..12f75960aec1
--- /dev/null
+++ b/drivers/net/ixgbevf/regs.h
@@ -0,0 +1,85 @@
+/*******************************************************************************
+
+ Intel 82599 Virtual Function driver
+ Copyright(c) 1999 - 2009 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBEVF_REGS_H_
+#define _IXGBEVF_REGS_H_
+
+#define IXGBE_VFCTRL 0x00000
+#define IXGBE_VFSTATUS 0x00008
+#define IXGBE_VFLINKS 0x00010
+#define IXGBE_VFRTIMER 0x00048
+#define IXGBE_VFRXMEMWRAP 0x03190
+#define IXGBE_VTEICR 0x00100
+#define IXGBE_VTEICS 0x00104
+#define IXGBE_VTEIMS 0x00108
+#define IXGBE_VTEIMC 0x0010C
+#define IXGBE_VTEIAC 0x00110
+#define IXGBE_VTEIAM 0x00114
+#define IXGBE_VTEITR(x) (0x00820 + (4 * x))
+#define IXGBE_VTIVAR(x) (0x00120 + (4 * x))
+#define IXGBE_VTIVAR_MISC 0x00140
+#define IXGBE_VTRSCINT(x) (0x00180 + (4 * x))
+#define IXGBE_VFRDBAL(x) (0x01000 + (0x40 * x))
+#define IXGBE_VFRDBAH(x) (0x01004 + (0x40 * x))
+#define IXGBE_VFRDLEN(x) (0x01008 + (0x40 * x))
+#define IXGBE_VFRDH(x) (0x01010 + (0x40 * x))
+#define IXGBE_VFRDT(x) (0x01018 + (0x40 * x))
+#define IXGBE_VFRXDCTL(x) (0x01028 + (0x40 * x))
+#define IXGBE_VFSRRCTL(x) (0x01014 + (0x40 * x))
+#define IXGBE_VFRSCCTL(x) (0x0102C + (0x40 * x))
+#define IXGBE_VFPSRTYPE 0x00300
+#define IXGBE_VFTDBAL(x) (0x02000 + (0x40 * x))
+#define IXGBE_VFTDBAH(x) (0x02004 + (0x40 * x))
+#define IXGBE_VFTDLEN(x) (0x02008 + (0x40 * x))
+#define IXGBE_VFTDH(x) (0x02010 + (0x40 * x))
+#define IXGBE_VFTDT(x) (0x02018 + (0x40 * x))
+#define IXGBE_VFTXDCTL(x) (0x02028 + (0x40 * x))
+#define IXGBE_VFTDWBAL(x) (0x02038 + (0x40 * x))
+#define IXGBE_VFTDWBAH(x) (0x0203C + (0x40 * x))
+#define IXGBE_VFDCA_RXCTRL(x) (0x0100C + (0x40 * x))
+#define IXGBE_VFDCA_TXCTRL(x) (0x0200c + (0x40 * x))
+#define IXGBE_VFGPRC 0x0101C
+#define IXGBE_VFGPTC 0x0201C
+#define IXGBE_VFGORC_LSB 0x01020
+#define IXGBE_VFGORC_MSB 0x01024
+#define IXGBE_VFGOTC_LSB 0x02020
+#define IXGBE_VFGOTC_MSB 0x02024
+#define IXGBE_VFMPRC 0x01034
+
+#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
+
+#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg))
+
+#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) ( \
+ writel((value), ((a)->hw_addr + (reg) + ((offset) << 2))))
+
+#define IXGBE_READ_REG_ARRAY(a, reg, offset) ( \
+ readl((a)->hw_addr + (reg) + ((offset) << 2)))
+
+#define IXGBE_WRITE_FLUSH(a) (IXGBE_READ_REG(a, IXGBE_VFSTATUS))
+
+#endif /* _IXGBEVF_REGS_H_ */
diff --git a/drivers/net/ixgbevf/vf.c b/drivers/net/ixgbevf/vf.c
new file mode 100644
index 000000000000..4b5dec0ec140
--- /dev/null
+++ b/drivers/net/ixgbevf/vf.c
@@ -0,0 +1,387 @@
+/*******************************************************************************
+
+ Intel 82599 Virtual Function driver
+ Copyright(c) 1999 - 2009 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "vf.h"
+
+/**
+ * ixgbevf_start_hw_vf - Prepare hardware for Tx/Rx
+ * @hw: pointer to hardware structure
+ *
+ * Starts the hardware by filling the bus info structure and media type, clears
+ * all on chip counters, initializes receive address registers, multicast
+ * table, VLAN filter table, calls routine to set up link and flow control
+ * settings, and leaves transmit and receive units disabled and uninitialized
+ **/
+static s32 ixgbevf_start_hw_vf(struct ixgbe_hw *hw)
+{
+ /* Clear adapter stopped flag */
+ hw->adapter_stopped = false;
+
+ return 0;
+}
+
+/**
+ * ixgbevf_init_hw_vf - virtual function hardware initialization
+ * @hw: pointer to hardware structure
+ *
+ * Initialize the hardware by resetting the hardware and then starting
+ * the hardware
+ **/
+static s32 ixgbevf_init_hw_vf(struct ixgbe_hw *hw)
+{
+ s32 status = hw->mac.ops.start_hw(hw);
+
+ hw->mac.ops.get_mac_addr(hw, hw->mac.addr);
+
+ return status;
+}
+
+/**
+ * ixgbevf_reset_hw_vf - Performs hardware reset
+ * @hw: pointer to hardware structure
+ *
+ * Resets the hardware by reseting the transmit and receive units, masks and
+ * clears all interrupts.
+ **/
+static s32 ixgbevf_reset_hw_vf(struct ixgbe_hw *hw)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ u32 timeout = IXGBE_VF_INIT_TIMEOUT;
+ s32 ret_val = IXGBE_ERR_INVALID_MAC_ADDR;
+ u32 msgbuf[IXGBE_VF_PERMADDR_MSG_LEN];
+ u8 *addr = (u8 *)(&msgbuf[1]);
+
+ /* Call adapter stop to disable tx/rx and clear interrupts */
+ hw->mac.ops.stop_adapter(hw);
+
+ IXGBE_WRITE_REG(hw, IXGBE_VFCTRL, IXGBE_CTRL_RST);
+ IXGBE_WRITE_FLUSH(hw);
+
+ /* we cannot reset while the RSTI / RSTD bits are asserted */
+ while (!mbx->ops.check_for_rst(hw) && timeout) {
+ timeout--;
+ udelay(5);
+ }
+
+ if (!timeout)
+ return IXGBE_ERR_RESET_FAILED;
+
+ /* mailbox timeout can now become active */
+ mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT;
+
+ msgbuf[0] = IXGBE_VF_RESET;
+ mbx->ops.write_posted(hw, msgbuf, 1);
+
+ msleep(10);
+
+ /* set our "perm_addr" based on info provided by PF */
+ /* also set up the mc_filter_type which is piggy backed
+ * on the mac address in word 3 */
+ ret_val = mbx->ops.read_posted(hw, msgbuf, IXGBE_VF_PERMADDR_MSG_LEN);
+ if (ret_val)
+ return ret_val;
+
+ if (msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK))
+ return IXGBE_ERR_INVALID_MAC_ADDR;
+
+ memcpy(hw->mac.perm_addr, addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
+ hw->mac.mc_filter_type = msgbuf[IXGBE_VF_MC_TYPE_WORD];
+
+ return 0;
+}
+
+/**
+ * ixgbevf_stop_hw_vf - Generic stop Tx/Rx units
+ * @hw: pointer to hardware structure
+ *
+ * Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts,
+ * disables transmit and receive units. The adapter_stopped flag is used by
+ * the shared code and drivers to determine if the adapter is in a stopped
+ * state and should not touch the hardware.
+ **/
+static s32 ixgbevf_stop_hw_vf(struct ixgbe_hw *hw)
+{
+ u32 number_of_queues;
+ u32 reg_val;
+ u16 i;
+
+ /*
+ * Set the adapter_stopped flag so other driver functions stop touching
+ * the hardware
+ */
+ hw->adapter_stopped = true;
+
+ /* Disable the receive unit by stopped each queue */
+ number_of_queues = hw->mac.max_rx_queues;
+ for (i = 0; i < number_of_queues; i++) {
+ reg_val = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i));
+ if (reg_val & IXGBE_RXDCTL_ENABLE) {
+ reg_val &= ~IXGBE_RXDCTL_ENABLE;
+ IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), reg_val);
+ }
+ }
+
+ IXGBE_WRITE_FLUSH(hw);
+
+ /* Clear interrupt mask to stop from interrupts being generated */
+ IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, IXGBE_VF_IRQ_CLEAR_MASK);
+
+ /* Clear any pending interrupts */
+ IXGBE_READ_REG(hw, IXGBE_VTEICR);
+
+ /* Disable the transmit unit. Each queue must be disabled. */
+ number_of_queues = hw->mac.max_tx_queues;
+ for (i = 0; i < number_of_queues; i++) {
+ reg_val = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i));
+ if (reg_val & IXGBE_TXDCTL_ENABLE) {
+ reg_val &= ~IXGBE_TXDCTL_ENABLE;
+ IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(i), reg_val);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ixgbevf_mta_vector - Determines bit-vector in multicast table to set
+ * @hw: pointer to hardware structure
+ * @mc_addr: the multicast address
+ *
+ * Extracts the 12 bits, from a multicast address, to determine which
+ * bit-vector to set in the multicast table. The hardware uses 12 bits, from
+ * incoming rx multicast addresses, to determine the bit-vector to check in
+ * the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set
+ * by the MO field of the MCSTCTRL. The MO field is set during initialization
+ * to mc_filter_type.
+ **/
+static s32 ixgbevf_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr)
+{
+ u32 vector = 0;
+
+ switch (hw->mac.mc_filter_type) {
+ case 0: /* use bits [47:36] of the address */
+ vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4));
+ break;
+ case 1: /* use bits [46:35] of the address */
+ vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5));
+ break;
+ case 2: /* use bits [45:34] of the address */
+ vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6));
+ break;
+ case 3: /* use bits [43:32] of the address */
+ vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8));
+ break;
+ default: /* Invalid mc_filter_type */
+ break;
+ }
+
+ /* vector can only be 12-bits or boundary will be exceeded */
+ vector &= 0xFFF;
+ return vector;
+}
+
+/**
+ * ixgbevf_get_mac_addr_vf - Read device MAC address
+ * @hw: pointer to the HW structure
+ * @mac_addr: pointer to storage for retrieved MAC address
+ **/
+static s32 ixgbevf_get_mac_addr_vf(struct ixgbe_hw *hw, u8 *mac_addr)
+{
+ memcpy(mac_addr, hw->mac.perm_addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
+
+ return 0;
+}
+
+/**
+ * ixgbevf_set_rar_vf - set device MAC address
+ * @hw: pointer to hardware structure
+ * @index: Receive address register to write
+ * @addr: Address to put into receive address register
+ * @vmdq: Unused in this implementation
+ **/
+static s32 ixgbevf_set_rar_vf(struct ixgbe_hw *hw, u32 index, u8 *addr,
+ u32 vmdq)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ u32 msgbuf[3];
+ u8 *msg_addr = (u8 *)(&msgbuf[1]);
+ s32 ret_val;
+
+ memset(msgbuf, 0, sizeof(msgbuf));
+ msgbuf[0] = IXGBE_VF_SET_MAC_ADDR;
+ memcpy(msg_addr, addr, 6);
+ ret_val = mbx->ops.write_posted(hw, msgbuf, 3);
+
+ if (!ret_val)
+ ret_val = mbx->ops.read_posted(hw, msgbuf, 3);
+
+ msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS;
+
+ /* if nacked the address was rejected, use "perm_addr" */
+ if (!ret_val &&
+ (msgbuf[0] == (IXGBE_VF_SET_MAC_ADDR | IXGBE_VT_MSGTYPE_NACK)))
+ ixgbevf_get_mac_addr_vf(hw, hw->mac.addr);
+
+ return ret_val;
+}
+
+/**
+ * ixgbevf_update_mc_addr_list_vf - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ * @next: caller supplied function to return next address in list
+ *
+ * Updates the Multicast Table Array.
+ **/
+static s32 ixgbevf_update_mc_addr_list_vf(struct ixgbe_hw *hw, u8 *mc_addr_list,
+ u32 mc_addr_count,
+ ixgbe_mc_addr_itr next)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ u32 msgbuf[IXGBE_VFMAILBOX_SIZE];
+ u16 *vector_list = (u16 *)&msgbuf[1];
+ u32 vector;
+ u32 cnt, i;
+ u32 vmdq;
+
+ /* Each entry in the list uses 1 16 bit word. We have 30
+ * 16 bit words available in our HW msg buffer (minus 1 for the
+ * msg type). That's 30 hash values if we pack 'em right. If
+ * there are more than 30 MC addresses to add then punt the
+ * extras for now and then add code to handle more than 30 later.
+ * It would be unusual for a server to request that many multi-cast
+ * addresses except for in large enterprise network environments.
+ */
+
+ cnt = (mc_addr_count > 30) ? 30 : mc_addr_count;
+ msgbuf[0] = IXGBE_VF_SET_MULTICAST;
+ msgbuf[0] |= cnt << IXGBE_VT_MSGINFO_SHIFT;
+
+ for (i = 0; i < cnt; i++) {
+ vector = ixgbevf_mta_vector(hw, next(hw, &mc_addr_list, &vmdq));
+ vector_list[i] = vector;
+ }
+
+ mbx->ops.write_posted(hw, msgbuf, IXGBE_VFMAILBOX_SIZE);
+
+ return 0;
+}
+
+/**
+ * ixgbevf_set_vfta_vf - Set/Unset vlan filter table address
+ * @hw: pointer to the HW structure
+ * @vlan: 12 bit VLAN ID
+ * @vind: unused by VF drivers
+ * @vlan_on: if true then set bit, else clear bit
+ **/
+static s32 ixgbevf_set_vfta_vf(struct ixgbe_hw *hw, u32 vlan, u32 vind,
+ bool vlan_on)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ u32 msgbuf[2];
+
+ msgbuf[0] = IXGBE_VF_SET_VLAN;
+ msgbuf[1] = vlan;
+ /* Setting the 8 bit field MSG INFO to TRUE indicates "add" */
+ msgbuf[0] |= vlan_on << IXGBE_VT_MSGINFO_SHIFT;
+
+ return mbx->ops.write_posted(hw, msgbuf, 2);
+}
+
+/**
+ * ixgbevf_setup_mac_link_vf - Setup MAC link settings
+ * @hw: pointer to hardware structure
+ * @speed: Unused in this implementation
+ * @autoneg: Unused in this implementation
+ * @autoneg_wait_to_complete: Unused in this implementation
+ *
+ * Do nothing and return success. VF drivers are not allowed to change
+ * global settings. Maintained for driver compatibility.
+ **/
+static s32 ixgbevf_setup_mac_link_vf(struct ixgbe_hw *hw,
+ ixgbe_link_speed speed, bool autoneg,
+ bool autoneg_wait_to_complete)
+{
+ return 0;
+}
+
+/**
+ * ixgbevf_check_mac_link_vf - Get link/speed status
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @link_up: true is link is up, false otherwise
+ * @autoneg_wait_to_complete: true when waiting for completion is needed
+ *
+ * Reads the links register to determine if link is up and the current speed
+ **/
+static s32 ixgbevf_check_mac_link_vf(struct ixgbe_hw *hw,
+ ixgbe_link_speed *speed,
+ bool *link_up,
+ bool autoneg_wait_to_complete)
+{
+ u32 links_reg;
+
+ if (!(hw->mbx.ops.check_for_rst(hw))) {
+ *link_up = false;
+ *speed = 0;
+ return -1;
+ }
+
+ links_reg = IXGBE_READ_REG(hw, IXGBE_VFLINKS);
+
+ if (links_reg & IXGBE_LINKS_UP)
+ *link_up = true;
+ else
+ *link_up = false;
+
+ if (links_reg & IXGBE_LINKS_SPEED)
+ *speed = IXGBE_LINK_SPEED_10GB_FULL;
+ else
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
+
+ return 0;
+}
+
+struct ixgbe_mac_operations ixgbevf_mac_ops = {
+ .init_hw = ixgbevf_init_hw_vf,
+ .reset_hw = ixgbevf_reset_hw_vf,
+ .start_hw = ixgbevf_start_hw_vf,
+ .get_mac_addr = ixgbevf_get_mac_addr_vf,
+ .stop_adapter = ixgbevf_stop_hw_vf,
+ .setup_link = ixgbevf_setup_mac_link_vf,
+ .check_link = ixgbevf_check_mac_link_vf,
+ .set_rar = ixgbevf_set_rar_vf,
+ .update_mc_addr_list = ixgbevf_update_mc_addr_list_vf,
+ .set_vfta = ixgbevf_set_vfta_vf,
+};
+
+struct ixgbevf_info ixgbevf_vf_info = {
+ .mac = ixgbe_mac_82599_vf,
+ .mac_ops = &ixgbevf_mac_ops,
+};
+
diff --git a/drivers/net/ixgbevf/vf.h b/drivers/net/ixgbevf/vf.h
new file mode 100644
index 000000000000..799600e92700
--- /dev/null
+++ b/drivers/net/ixgbevf/vf.h
@@ -0,0 +1,168 @@
+/*******************************************************************************
+
+ Intel 82599 Virtual Function driver
+ Copyright(c) 1999 - 2009 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef __IXGBE_VF_H__
+#define __IXGBE_VF_H__
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+
+#include "defines.h"
+#include "regs.h"
+#include "mbx.h"
+
+struct ixgbe_hw;
+
+/* iterator type for walking multicast address lists */
+typedef u8* (*ixgbe_mc_addr_itr) (struct ixgbe_hw *hw, u8 **mc_addr_ptr,
+ u32 *vmdq);
+struct ixgbe_mac_operations {
+ s32 (*init_hw)(struct ixgbe_hw *);
+ s32 (*reset_hw)(struct ixgbe_hw *);
+ s32 (*start_hw)(struct ixgbe_hw *);
+ s32 (*clear_hw_cntrs)(struct ixgbe_hw *);
+ enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *);
+ u32 (*get_supported_physical_layer)(struct ixgbe_hw *);
+ s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *);
+ s32 (*stop_adapter)(struct ixgbe_hw *);
+ s32 (*get_bus_info)(struct ixgbe_hw *);
+
+ /* Link */
+ s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool);
+ s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool);
+ s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *,
+ bool *);
+
+ /* RAR, Multicast, VLAN */
+ s32 (*set_rar)(struct ixgbe_hw *, u32, u8 *, u32);
+ s32 (*init_rx_addrs)(struct ixgbe_hw *);
+ s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32,
+ ixgbe_mc_addr_itr);
+ s32 (*enable_mc)(struct ixgbe_hw *);
+ s32 (*disable_mc)(struct ixgbe_hw *);
+ s32 (*clear_vfta)(struct ixgbe_hw *);
+ s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool);
+};
+
+enum ixgbe_mac_type {
+ ixgbe_mac_unknown = 0,
+ ixgbe_mac_82599_vf,
+ ixgbe_num_macs
+};
+
+struct ixgbe_mac_info {
+ struct ixgbe_mac_operations ops;
+ u8 addr[6];
+ u8 perm_addr[6];
+
+ enum ixgbe_mac_type type;
+
+ s32 mc_filter_type;
+
+ bool get_link_status;
+ u32 max_tx_queues;
+ u32 max_rx_queues;
+ u32 max_msix_vectors;
+};
+
+struct ixgbe_mbx_operations {
+ s32 (*init_params)(struct ixgbe_hw *hw);
+ s32 (*read)(struct ixgbe_hw *, u32 *, u16);
+ s32 (*write)(struct ixgbe_hw *, u32 *, u16);
+ s32 (*read_posted)(struct ixgbe_hw *, u32 *, u16);
+ s32 (*write_posted)(struct ixgbe_hw *, u32 *, u16);
+ s32 (*check_for_msg)(struct ixgbe_hw *);
+ s32 (*check_for_ack)(struct ixgbe_hw *);
+ s32 (*check_for_rst)(struct ixgbe_hw *);
+};
+
+struct ixgbe_mbx_stats {
+ u32 msgs_tx;
+ u32 msgs_rx;
+
+ u32 acks;
+ u32 reqs;
+ u32 rsts;
+};
+
+struct ixgbe_mbx_info {
+ struct ixgbe_mbx_operations ops;
+ struct ixgbe_mbx_stats stats;
+ u32 timeout;
+ u32 udelay;
+ u32 v2p_mailbox;
+ u16 size;
+};
+
+struct ixgbe_hw {
+ void *back;
+
+ u8 __iomem *hw_addr;
+ u8 *flash_address;
+ unsigned long io_base;
+
+ struct ixgbe_mac_info mac;
+ struct ixgbe_mbx_info mbx;
+
+ u16 device_id;
+ u16 subsystem_vendor_id;
+ u16 subsystem_device_id;
+ u16 vendor_id;
+
+ u8 revision_id;
+ bool adapter_stopped;
+};
+
+struct ixgbevf_hw_stats {
+ u64 base_vfgprc;
+ u64 base_vfgptc;
+ u64 base_vfgorc;
+ u64 base_vfgotc;
+ u64 base_vfmprc;
+
+ u64 last_vfgprc;
+ u64 last_vfgptc;
+ u64 last_vfgorc;
+ u64 last_vfgotc;
+ u64 last_vfmprc;
+
+ u64 vfgprc;
+ u64 vfgptc;
+ u64 vfgorc;
+ u64 vfgotc;
+ u64 vfmprc;
+};
+
+struct ixgbevf_info {
+ enum ixgbe_mac_type mac;
+ struct ixgbe_mac_operations *mac_ops;
+};
+
+#endif /* __IXGBE_VF_H__ */
+
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 792b88fc3574..0f31497833df 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -288,7 +288,7 @@ jme_set_rx_pcc(struct jme_adapter *jme, int p)
wmb();
if (!(test_bit(JME_FLAG_POLL, &jme->flags)))
- msg_rx_status(jme, "Switched to PCC_P%d\n", p);
+ netif_info(jme, rx_status, jme->dev, "Switched to PCC_P%d\n", p);
}
static void
@@ -483,13 +483,13 @@ jme_check_link(struct net_device *netdev, int testonly)
strcat(linkmsg, (phylink & PHY_LINK_MDI_STAT) ?
"MDI-X" :
"MDI");
- msg_link(jme, "Link is up at %s.\n", linkmsg);
+ netif_info(jme, link, jme->dev, "Link is up at %s.\n", linkmsg);
netif_carrier_on(netdev);
} else {
if (testonly)
goto out;
- msg_link(jme, "Link is down.\n");
+ netif_info(jme, link, jme->dev, "Link is down.\n");
jme->phylink = 0;
netif_carrier_off(netdev);
}
@@ -883,20 +883,20 @@ jme_rxsum_ok(struct jme_adapter *jme, u16 flags)
if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_TCPON | RXWBFLAG_TCPCS))
== RXWBFLAG_TCPON)) {
if (flags & RXWBFLAG_IPV4)
- msg_rx_err(jme, "TCP Checksum error\n");
+ netif_err(jme, rx_err, jme->dev, "TCP Checksum error\n");
return false;
}
if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS))
== RXWBFLAG_UDPON)) {
if (flags & RXWBFLAG_IPV4)
- msg_rx_err(jme, "UDP Checksum error.\n");
+ netif_err(jme, rx_err, jme->dev, "UDP Checksum error.\n");
return false;
}
if (unlikely((flags & (RXWBFLAG_IPV4 | RXWBFLAG_IPCS))
== RXWBFLAG_IPV4)) {
- msg_rx_err(jme, "IPv4 Checksum error.\n");
+ netif_err(jme, rx_err, jme->dev, "IPv4 Checksum error.\n");
return false;
}
@@ -1186,9 +1186,9 @@ jme_link_change_tasklet(unsigned long arg)
while (!atomic_dec_and_test(&jme->link_changing)) {
atomic_inc(&jme->link_changing);
- msg_intr(jme, "Get link change lock failed.\n");
+ netif_info(jme, intr, jme->dev, "Get link change lock failed.\n");
while (atomic_read(&jme->link_changing) != 1)
- msg_intr(jme, "Waiting link change lock.\n");
+ netif_info(jme, intr, jme->dev, "Waiting link change lock.\n");
}
if (jme_check_link(netdev, 1) && jme->old_mtu == netdev->mtu)
@@ -1305,7 +1305,7 @@ jme_rx_empty_tasklet(unsigned long arg)
if (unlikely(!netif_carrier_ok(jme->dev)))
return;
- msg_rx_status(jme, "RX Queue Full!\n");
+ netif_info(jme, rx_status, jme->dev, "RX Queue Full!\n");
jme_rx_clean_tasklet(arg);
@@ -1325,7 +1325,7 @@ jme_wake_queue_if_stopped(struct jme_adapter *jme)
smp_wmb();
if (unlikely(netif_queue_stopped(jme->dev) &&
atomic_read(&txring->nr_free) >= (jme->tx_wake_threshold))) {
- msg_tx_done(jme, "TX Queue Waked.\n");
+ netif_info(jme, tx_done, jme->dev, "TX Queue Waked.\n");
netif_wake_queue(jme->dev);
}
@@ -1835,7 +1835,7 @@ jme_tx_csum(struct jme_adapter *jme, struct sk_buff *skb, u8 *flags)
*flags |= TXFLAG_UDPCS;
break;
default:
- msg_tx_err(jme, "Error upper layer protocol.\n");
+ netif_err(jme, tx_err, jme->dev, "Error upper layer protocol.\n");
break;
}
}
@@ -1910,12 +1910,12 @@ jme_stop_queue_if_full(struct jme_adapter *jme)
smp_wmb();
if (unlikely(atomic_read(&txring->nr_free) < (MAX_SKB_FRAGS+2))) {
netif_stop_queue(jme->dev);
- msg_tx_queued(jme, "TX Queue Paused.\n");
+ netif_info(jme, tx_queued, jme->dev, "TX Queue Paused.\n");
smp_wmb();
if (atomic_read(&txring->nr_free)
>= (jme->tx_wake_threshold)) {
netif_wake_queue(jme->dev);
- msg_tx_queued(jme, "TX Queue Fast Waked.\n");
+ netif_info(jme, tx_queued, jme->dev, "TX Queue Fast Waked.\n");
}
}
@@ -1923,7 +1923,7 @@ jme_stop_queue_if_full(struct jme_adapter *jme)
(jiffies - txbi->start_xmit) >= TX_TIMEOUT &&
txbi->skb)) {
netif_stop_queue(jme->dev);
- msg_tx_queued(jme, "TX Queue Stopped %d@%lu.\n", idx, jiffies);
+ netif_info(jme, tx_queued, jme->dev, "TX Queue Stopped %d@%lu.\n", idx, jiffies);
}
}
@@ -1946,7 +1946,7 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev)
if (unlikely(idx < 0)) {
netif_stop_queue(netdev);
- msg_tx_err(jme, "BUG! Tx ring full when queue awake!\n");
+ netif_err(jme, tx_err, jme->dev, "BUG! Tx ring full when queue awake!\n");
return NETDEV_TX_BUSY;
}
@@ -1997,7 +1997,6 @@ jme_set_multi(struct net_device *netdev)
{
struct jme_adapter *jme = netdev_priv(netdev);
u32 mc_hash[2] = {};
- int i;
spin_lock_bh(&jme->rxmcs_lock);
@@ -2012,10 +2011,7 @@ jme_set_multi(struct net_device *netdev)
int bit_nr;
jme->reg_rxmcs |= RXMCS_MULFRAME | RXMCS_MULFILTERED;
- for (i = 0, mclist = netdev->mc_list;
- mclist && i < netdev->mc_count;
- ++i, mclist = mclist->next) {
-
+ netdev_for_each_mc_addr(mclist, netdev) {
bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3F;
mc_hash[bit_nr >> 5] |= 1 << (bit_nr & 0x1F);
}
@@ -2473,7 +2469,7 @@ jme_smb_read(struct jme_adapter *jme, unsigned int addr)
val = jread32(jme, JME_SMBCSR);
}
if (!to) {
- msg_hw(jme, "SMB Bus Busy.\n");
+ netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n");
return 0xFF;
}
@@ -2489,7 +2485,7 @@ jme_smb_read(struct jme_adapter *jme, unsigned int addr)
val = jread32(jme, JME_SMBINTF);
}
if (!to) {
- msg_hw(jme, "SMB Bus Busy.\n");
+ netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n");
return 0xFF;
}
@@ -2509,7 +2505,7 @@ jme_smb_write(struct jme_adapter *jme, unsigned int addr, u8 data)
val = jread32(jme, JME_SMBCSR);
}
if (!to) {
- msg_hw(jme, "SMB Bus Busy.\n");
+ netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n");
return;
}
@@ -2526,7 +2522,7 @@ jme_smb_write(struct jme_adapter *jme, unsigned int addr, u8 data)
val = jread32(jme, JME_SMBINTF);
}
if (!to) {
- msg_hw(jme, "SMB Bus Busy.\n");
+ netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n");
return;
}
@@ -2876,14 +2872,14 @@ jme_init_one(struct pci_dev *pdev,
goto err_out_unmap;
}
- msg_probe(jme, "%s%s ver:%x rev:%x macaddr:%pM\n",
- (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) ?
- "JMC250 Gigabit Ethernet" :
- (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC260) ?
- "JMC260 Fast Ethernet" : "Unknown",
- (jme->fpgaver != 0) ? " (FPGA)" : "",
- (jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev,
- jme->rev, netdev->dev_addr);
+ netif_info(jme, probe, jme->dev, "%s%s ver:%x rev:%x macaddr:%pM\n",
+ (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) ?
+ "JMC250 Gigabit Ethernet" :
+ (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC260) ?
+ "JMC260 Fast Ethernet" : "Unknown",
+ (jme->fpgaver != 0) ? " (FPGA)" : "",
+ (jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev,
+ jme->rev, netdev->dev_addr);
return 0;
@@ -2994,7 +2990,7 @@ jme_resume(struct pci_dev *pdev)
}
#endif
-static struct pci_device_id jme_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(jme_pci_tbl) = {
{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC250) },
{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC260) },
{ }
diff --git a/drivers/net/jme.h b/drivers/net/jme.h
index 251abed3817e..c19db9146a2f 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/jme.h
@@ -45,43 +45,16 @@
printk(KERN_ERR PFX fmt, ## args)
#ifdef TX_DEBUG
-#define tx_dbg(priv, fmt, args...) \
- printk(KERN_DEBUG "%s: " fmt, (priv)->dev->name, ## args)
+#define tx_dbg(priv, fmt, args...) \
+ printk(KERN_DEBUG "%s: " fmt, (priv)->dev->name, ##args)
#else
-#define tx_dbg(priv, fmt, args...)
+#define tx_dbg(priv, fmt, args...) \
+do { \
+ if (0) \
+ printk(KERN_DEBUG "%s: " fmt, (priv)->dev->name, ##args); \
+} while (0)
#endif
-#define jme_msg(msglvl, type, priv, fmt, args...) \
- if (netif_msg_##type(priv)) \
- printk(msglvl "%s: " fmt, (priv)->dev->name, ## args)
-
-#define msg_probe(priv, fmt, args...) \
- jme_msg(KERN_INFO, probe, priv, fmt, ## args)
-
-#define msg_link(priv, fmt, args...) \
- jme_msg(KERN_INFO, link, priv, fmt, ## args)
-
-#define msg_intr(priv, fmt, args...) \
- jme_msg(KERN_INFO, intr, priv, fmt, ## args)
-
-#define msg_rx_err(priv, fmt, args...) \
- jme_msg(KERN_ERR, rx_err, priv, fmt, ## args)
-
-#define msg_rx_status(priv, fmt, args...) \
- jme_msg(KERN_INFO, rx_status, priv, fmt, ## args)
-
-#define msg_tx_err(priv, fmt, args...) \
- jme_msg(KERN_ERR, tx_err, priv, fmt, ## args)
-
-#define msg_tx_done(priv, fmt, args...) \
- jme_msg(KERN_INFO, tx_done, priv, fmt, ## args)
-
-#define msg_tx_queued(priv, fmt, args...) \
- jme_msg(KERN_INFO, tx_queued, priv, fmt, ## args)
-
-#define msg_hw(priv, fmt, args...) \
- jme_msg(KERN_ERR, hw, priv, fmt, ## args)
-
/*
* Extra PCI Configuration space interface
*/
diff --git a/drivers/net/korina.c b/drivers/net/korina.c
index 25e2af6997e4..300c2249812d 100644
--- a/drivers/net/korina.c
+++ b/drivers/net/korina.c
@@ -482,7 +482,7 @@ static void korina_multicast_list(struct net_device *dev)
{
struct korina_private *lp = netdev_priv(dev);
unsigned long flags;
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
u32 recognise = ETH_ARC_AB; /* always accept broadcasts */
int i;
@@ -490,23 +490,21 @@ static void korina_multicast_list(struct net_device *dev)
if (dev->flags & IFF_PROMISC)
recognise |= ETH_ARC_PRO;
- else if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 4))
+ else if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 4))
/* All multicast and broadcast */
recognise |= ETH_ARC_AM;
/* Build the hash table */
- if (dev->mc_count > 4) {
+ if (netdev_mc_count(dev) > 4) {
u16 hash_table[4];
u32 crc;
for (i = 0; i < 4; i++)
hash_table[i] = 0;
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
char *addrs = dmi->dmi_addr;
- dmi = dmi->next;
-
if (!(*addrs & 1))
continue;
diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c
index 6d3ac65bc35c..0573e0bb4444 100644
--- a/drivers/net/ks8851.c
+++ b/drivers/net/ks8851.c
@@ -407,7 +407,7 @@ static irqreturn_t ks8851_irq(int irq, void *pw)
* @buff: The buffer address
* @len: The length of the data to read
*
- * Issue an RXQ FIFO read command and read the @len ammount of data from
+ * Issue an RXQ FIFO read command and read the @len amount of data from
* the FIFO into the buffer specified by @buff.
*/
static void ks8851_rdfifo(struct ks8851_net *ks, u8 *buff, unsigned len)
@@ -965,14 +965,13 @@ static void ks8851_set_rx_mode(struct net_device *dev)
rxctrl.rxcr1 = (RXCR1_RXME | RXCR1_RXAE |
RXCR1_RXPAFMA | RXCR1_RXMAFMA);
- } else if (dev->flags & IFF_MULTICAST && dev->mc_count > 0) {
- struct dev_mc_list *mcptr = dev->mc_list;
+ } else if (dev->flags & IFF_MULTICAST && !netdev_mc_empty(dev)) {
+ struct dev_mc_list *mcptr;
u32 crc;
- int i;
/* accept some multicast */
- for (i = dev->mc_count; i > 0; i--) {
+ netdev_for_each_mc_addr(mcptr, dev) {
crc = ether_crc(ETH_ALEN, mcptr->dmi_addr);
crc >>= (32 - 6); /* get top six bits */
diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c
index c146304d8d6c..84b0e15831f9 100644
--- a/drivers/net/ks8851_mll.c
+++ b/drivers/net/ks8851_mll.c
@@ -854,8 +854,8 @@ static void ks_update_link_status(struct net_device *netdev, struct ks_net *ks)
static irqreturn_t ks_irq(int irq, void *pw)
{
- struct ks_net *ks = pw;
- struct net_device *netdev = ks->netdev;
+ struct net_device *netdev = pw;
+ struct ks_net *ks = netdev_priv(netdev);
u16 status;
/*this should be the first in IRQ handler */
@@ -1193,10 +1193,11 @@ static void ks_set_rx_mode(struct net_device *netdev)
else
ks_set_promis(ks, false);
- if ((netdev->flags & IFF_MULTICAST) && netdev->mc_count) {
- if (netdev->mc_count <= MAX_MCAST_LST) {
+ if ((netdev->flags & IFF_MULTICAST) && netdev_mc_count(netdev)) {
+ if (netdev_mc_count(netdev) <= MAX_MCAST_LST) {
int i = 0;
- for (ptr = netdev->mc_list; ptr; ptr = ptr->next) {
+
+ netdev_for_each_mc_addr(ptr, netdev) {
if (!(*ptr->dmi_addr & 1))
continue;
if (i >= MAX_MCAST_LST)
diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c
new file mode 100644
index 000000000000..7264a3e5c2c0
--- /dev/null
+++ b/drivers/net/ksz884x.c
@@ -0,0 +1,7335 @@
+/**
+ * drivers/net/ksx884x.c - Micrel KSZ8841/2 PCI Ethernet driver
+ *
+ * Copyright (c) 2009-2010 Micrel, Inc.
+ * Tristram Ha <Tristram.Ha@micrel.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/mii.h>
+#include <linux/platform_device.h>
+#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <linux/sched.h>
+
+
+/* DMA Registers */
+
+#define KS_DMA_TX_CTRL 0x0000
+#define DMA_TX_ENABLE 0x00000001
+#define DMA_TX_CRC_ENABLE 0x00000002
+#define DMA_TX_PAD_ENABLE 0x00000004
+#define DMA_TX_LOOPBACK 0x00000100
+#define DMA_TX_FLOW_ENABLE 0x00000200
+#define DMA_TX_CSUM_IP 0x00010000
+#define DMA_TX_CSUM_TCP 0x00020000
+#define DMA_TX_CSUM_UDP 0x00040000
+#define DMA_TX_BURST_SIZE 0x3F000000
+
+#define KS_DMA_RX_CTRL 0x0004
+#define DMA_RX_ENABLE 0x00000001
+#define KS884X_DMA_RX_MULTICAST 0x00000002
+#define DMA_RX_PROMISCUOUS 0x00000004
+#define DMA_RX_ERROR 0x00000008
+#define DMA_RX_UNICAST 0x00000010
+#define DMA_RX_ALL_MULTICAST 0x00000020
+#define DMA_RX_BROADCAST 0x00000040
+#define DMA_RX_FLOW_ENABLE 0x00000200
+#define DMA_RX_CSUM_IP 0x00010000
+#define DMA_RX_CSUM_TCP 0x00020000
+#define DMA_RX_CSUM_UDP 0x00040000
+#define DMA_RX_BURST_SIZE 0x3F000000
+
+#define DMA_BURST_SHIFT 24
+#define DMA_BURST_DEFAULT 8
+
+#define KS_DMA_TX_START 0x0008
+#define KS_DMA_RX_START 0x000C
+#define DMA_START 0x00000001
+
+#define KS_DMA_TX_ADDR 0x0010
+#define KS_DMA_RX_ADDR 0x0014
+
+#define DMA_ADDR_LIST_MASK 0xFFFFFFFC
+#define DMA_ADDR_LIST_SHIFT 2
+
+/* MTR0 */
+#define KS884X_MULTICAST_0_OFFSET 0x0020
+#define KS884X_MULTICAST_1_OFFSET 0x0021
+#define KS884X_MULTICAST_2_OFFSET 0x0022
+#define KS884x_MULTICAST_3_OFFSET 0x0023
+/* MTR1 */
+#define KS884X_MULTICAST_4_OFFSET 0x0024
+#define KS884X_MULTICAST_5_OFFSET 0x0025
+#define KS884X_MULTICAST_6_OFFSET 0x0026
+#define KS884X_MULTICAST_7_OFFSET 0x0027
+
+/* Interrupt Registers */
+
+/* INTEN */
+#define KS884X_INTERRUPTS_ENABLE 0x0028
+/* INTST */
+#define KS884X_INTERRUPTS_STATUS 0x002C
+
+#define KS884X_INT_RX_STOPPED 0x02000000
+#define KS884X_INT_TX_STOPPED 0x04000000
+#define KS884X_INT_RX_OVERRUN 0x08000000
+#define KS884X_INT_TX_EMPTY 0x10000000
+#define KS884X_INT_RX 0x20000000
+#define KS884X_INT_TX 0x40000000
+#define KS884X_INT_PHY 0x80000000
+
+#define KS884X_INT_RX_MASK \
+ (KS884X_INT_RX | KS884X_INT_RX_OVERRUN)
+#define KS884X_INT_TX_MASK \
+ (KS884X_INT_TX | KS884X_INT_TX_EMPTY)
+#define KS884X_INT_MASK (KS884X_INT_RX | KS884X_INT_TX | KS884X_INT_PHY)
+
+/* MAC Additional Station Address */
+
+/* MAAL0 */
+#define KS_ADD_ADDR_0_LO 0x0080
+/* MAAH0 */
+#define KS_ADD_ADDR_0_HI 0x0084
+/* MAAL1 */
+#define KS_ADD_ADDR_1_LO 0x0088
+/* MAAH1 */
+#define KS_ADD_ADDR_1_HI 0x008C
+/* MAAL2 */
+#define KS_ADD_ADDR_2_LO 0x0090
+/* MAAH2 */
+#define KS_ADD_ADDR_2_HI 0x0094
+/* MAAL3 */
+#define KS_ADD_ADDR_3_LO 0x0098
+/* MAAH3 */
+#define KS_ADD_ADDR_3_HI 0x009C
+/* MAAL4 */
+#define KS_ADD_ADDR_4_LO 0x00A0
+/* MAAH4 */
+#define KS_ADD_ADDR_4_HI 0x00A4
+/* MAAL5 */
+#define KS_ADD_ADDR_5_LO 0x00A8
+/* MAAH5 */
+#define KS_ADD_ADDR_5_HI 0x00AC
+/* MAAL6 */
+#define KS_ADD_ADDR_6_LO 0x00B0
+/* MAAH6 */
+#define KS_ADD_ADDR_6_HI 0x00B4
+/* MAAL7 */
+#define KS_ADD_ADDR_7_LO 0x00B8
+/* MAAH7 */
+#define KS_ADD_ADDR_7_HI 0x00BC
+/* MAAL8 */
+#define KS_ADD_ADDR_8_LO 0x00C0
+/* MAAH8 */
+#define KS_ADD_ADDR_8_HI 0x00C4
+/* MAAL9 */
+#define KS_ADD_ADDR_9_LO 0x00C8
+/* MAAH9 */
+#define KS_ADD_ADDR_9_HI 0x00CC
+/* MAAL10 */
+#define KS_ADD_ADDR_A_LO 0x00D0
+/* MAAH10 */
+#define KS_ADD_ADDR_A_HI 0x00D4
+/* MAAL11 */
+#define KS_ADD_ADDR_B_LO 0x00D8
+/* MAAH11 */
+#define KS_ADD_ADDR_B_HI 0x00DC
+/* MAAL12 */
+#define KS_ADD_ADDR_C_LO 0x00E0
+/* MAAH12 */
+#define KS_ADD_ADDR_C_HI 0x00E4
+/* MAAL13 */
+#define KS_ADD_ADDR_D_LO 0x00E8
+/* MAAH13 */
+#define KS_ADD_ADDR_D_HI 0x00EC
+/* MAAL14 */
+#define KS_ADD_ADDR_E_LO 0x00F0
+/* MAAH14 */
+#define KS_ADD_ADDR_E_HI 0x00F4
+/* MAAL15 */
+#define KS_ADD_ADDR_F_LO 0x00F8
+/* MAAH15 */
+#define KS_ADD_ADDR_F_HI 0x00FC
+
+#define ADD_ADDR_HI_MASK 0x0000FFFF
+#define ADD_ADDR_ENABLE 0x80000000
+#define ADD_ADDR_INCR 8
+
+/* Miscellaneous Registers */
+
+/* MARL */
+#define KS884X_ADDR_0_OFFSET 0x0200
+#define KS884X_ADDR_1_OFFSET 0x0201
+/* MARM */
+#define KS884X_ADDR_2_OFFSET 0x0202
+#define KS884X_ADDR_3_OFFSET 0x0203
+/* MARH */
+#define KS884X_ADDR_4_OFFSET 0x0204
+#define KS884X_ADDR_5_OFFSET 0x0205
+
+/* OBCR */
+#define KS884X_BUS_CTRL_OFFSET 0x0210
+
+#define BUS_SPEED_125_MHZ 0x0000
+#define BUS_SPEED_62_5_MHZ 0x0001
+#define BUS_SPEED_41_66_MHZ 0x0002
+#define BUS_SPEED_25_MHZ 0x0003
+
+/* EEPCR */
+#define KS884X_EEPROM_CTRL_OFFSET 0x0212
+
+#define EEPROM_CHIP_SELECT 0x0001
+#define EEPROM_SERIAL_CLOCK 0x0002
+#define EEPROM_DATA_OUT 0x0004
+#define EEPROM_DATA_IN 0x0008
+#define EEPROM_ACCESS_ENABLE 0x0010
+
+/* MBIR */
+#define KS884X_MEM_INFO_OFFSET 0x0214
+
+#define RX_MEM_TEST_FAILED 0x0008
+#define RX_MEM_TEST_FINISHED 0x0010
+#define TX_MEM_TEST_FAILED 0x0800
+#define TX_MEM_TEST_FINISHED 0x1000
+
+/* GCR */
+#define KS884X_GLOBAL_CTRL_OFFSET 0x0216
+#define GLOBAL_SOFTWARE_RESET 0x0001
+
+#define KS8841_POWER_MANAGE_OFFSET 0x0218
+
+/* WFCR */
+#define KS8841_WOL_CTRL_OFFSET 0x021A
+#define KS8841_WOL_MAGIC_ENABLE 0x0080
+#define KS8841_WOL_FRAME3_ENABLE 0x0008
+#define KS8841_WOL_FRAME2_ENABLE 0x0004
+#define KS8841_WOL_FRAME1_ENABLE 0x0002
+#define KS8841_WOL_FRAME0_ENABLE 0x0001
+
+/* WF0 */
+#define KS8841_WOL_FRAME_CRC_OFFSET 0x0220
+#define KS8841_WOL_FRAME_BYTE0_OFFSET 0x0224
+#define KS8841_WOL_FRAME_BYTE2_OFFSET 0x0228
+
+/* IACR */
+#define KS884X_IACR_P 0x04A0
+#define KS884X_IACR_OFFSET KS884X_IACR_P
+
+/* IADR1 */
+#define KS884X_IADR1_P 0x04A2
+#define KS884X_IADR2_P 0x04A4
+#define KS884X_IADR3_P 0x04A6
+#define KS884X_IADR4_P 0x04A8
+#define KS884X_IADR5_P 0x04AA
+
+#define KS884X_ACC_CTRL_SEL_OFFSET KS884X_IACR_P
+#define KS884X_ACC_CTRL_INDEX_OFFSET (KS884X_ACC_CTRL_SEL_OFFSET + 1)
+
+#define KS884X_ACC_DATA_0_OFFSET KS884X_IADR4_P
+#define KS884X_ACC_DATA_1_OFFSET (KS884X_ACC_DATA_0_OFFSET + 1)
+#define KS884X_ACC_DATA_2_OFFSET KS884X_IADR5_P
+#define KS884X_ACC_DATA_3_OFFSET (KS884X_ACC_DATA_2_OFFSET + 1)
+#define KS884X_ACC_DATA_4_OFFSET KS884X_IADR2_P
+#define KS884X_ACC_DATA_5_OFFSET (KS884X_ACC_DATA_4_OFFSET + 1)
+#define KS884X_ACC_DATA_6_OFFSET KS884X_IADR3_P
+#define KS884X_ACC_DATA_7_OFFSET (KS884X_ACC_DATA_6_OFFSET + 1)
+#define KS884X_ACC_DATA_8_OFFSET KS884X_IADR1_P
+
+/* P1MBCR */
+#define KS884X_P1MBCR_P 0x04D0
+#define KS884X_P1MBSR_P 0x04D2
+#define KS884X_PHY1ILR_P 0x04D4
+#define KS884X_PHY1IHR_P 0x04D6
+#define KS884X_P1ANAR_P 0x04D8
+#define KS884X_P1ANLPR_P 0x04DA
+
+/* P2MBCR */
+#define KS884X_P2MBCR_P 0x04E0
+#define KS884X_P2MBSR_P 0x04E2
+#define KS884X_PHY2ILR_P 0x04E4
+#define KS884X_PHY2IHR_P 0x04E6
+#define KS884X_P2ANAR_P 0x04E8
+#define KS884X_P2ANLPR_P 0x04EA
+
+#define KS884X_PHY_1_CTRL_OFFSET KS884X_P1MBCR_P
+#define PHY_CTRL_INTERVAL (KS884X_P2MBCR_P - KS884X_P1MBCR_P)
+
+#define KS884X_PHY_CTRL_OFFSET 0x00
+
+/* Mode Control Register */
+#define PHY_REG_CTRL 0
+
+#define PHY_RESET 0x8000
+#define PHY_LOOPBACK 0x4000
+#define PHY_SPEED_100MBIT 0x2000
+#define PHY_AUTO_NEG_ENABLE 0x1000
+#define PHY_POWER_DOWN 0x0800
+#define PHY_MII_DISABLE 0x0400
+#define PHY_AUTO_NEG_RESTART 0x0200
+#define PHY_FULL_DUPLEX 0x0100
+#define PHY_COLLISION_TEST 0x0080
+#define PHY_HP_MDIX 0x0020
+#define PHY_FORCE_MDIX 0x0010
+#define PHY_AUTO_MDIX_DISABLE 0x0008
+#define PHY_REMOTE_FAULT_DISABLE 0x0004
+#define PHY_TRANSMIT_DISABLE 0x0002
+#define PHY_LED_DISABLE 0x0001
+
+#define KS884X_PHY_STATUS_OFFSET 0x02
+
+/* Mode Status Register */
+#define PHY_REG_STATUS 1
+
+#define PHY_100BT4_CAPABLE 0x8000
+#define PHY_100BTX_FD_CAPABLE 0x4000
+#define PHY_100BTX_CAPABLE 0x2000
+#define PHY_10BT_FD_CAPABLE 0x1000
+#define PHY_10BT_CAPABLE 0x0800
+#define PHY_MII_SUPPRESS_CAPABLE 0x0040
+#define PHY_AUTO_NEG_ACKNOWLEDGE 0x0020
+#define PHY_REMOTE_FAULT 0x0010
+#define PHY_AUTO_NEG_CAPABLE 0x0008
+#define PHY_LINK_STATUS 0x0004
+#define PHY_JABBER_DETECT 0x0002
+#define PHY_EXTENDED_CAPABILITY 0x0001
+
+#define KS884X_PHY_ID_1_OFFSET 0x04
+#define KS884X_PHY_ID_2_OFFSET 0x06
+
+/* PHY Identifier Registers */
+#define PHY_REG_ID_1 2
+#define PHY_REG_ID_2 3
+
+#define KS884X_PHY_AUTO_NEG_OFFSET 0x08
+
+/* Auto-Negotiation Advertisement Register */
+#define PHY_REG_AUTO_NEGOTIATION 4
+
+#define PHY_AUTO_NEG_NEXT_PAGE 0x8000
+#define PHY_AUTO_NEG_REMOTE_FAULT 0x2000
+/* Not supported. */
+#define PHY_AUTO_NEG_ASYM_PAUSE 0x0800
+#define PHY_AUTO_NEG_SYM_PAUSE 0x0400
+#define PHY_AUTO_NEG_100BT4 0x0200
+#define PHY_AUTO_NEG_100BTX_FD 0x0100
+#define PHY_AUTO_NEG_100BTX 0x0080
+#define PHY_AUTO_NEG_10BT_FD 0x0040
+#define PHY_AUTO_NEG_10BT 0x0020
+#define PHY_AUTO_NEG_SELECTOR 0x001F
+#define PHY_AUTO_NEG_802_3 0x0001
+
+#define PHY_AUTO_NEG_PAUSE (PHY_AUTO_NEG_SYM_PAUSE | PHY_AUTO_NEG_ASYM_PAUSE)
+
+#define KS884X_PHY_REMOTE_CAP_OFFSET 0x0A
+
+/* Auto-Negotiation Link Partner Ability Register */
+#define PHY_REG_REMOTE_CAPABILITY 5
+
+#define PHY_REMOTE_NEXT_PAGE 0x8000
+#define PHY_REMOTE_ACKNOWLEDGE 0x4000
+#define PHY_REMOTE_REMOTE_FAULT 0x2000
+#define PHY_REMOTE_SYM_PAUSE 0x0400
+#define PHY_REMOTE_100BTX_FD 0x0100
+#define PHY_REMOTE_100BTX 0x0080
+#define PHY_REMOTE_10BT_FD 0x0040
+#define PHY_REMOTE_10BT 0x0020
+
+/* P1VCT */
+#define KS884X_P1VCT_P 0x04F0
+#define KS884X_P1PHYCTRL_P 0x04F2
+
+/* P2VCT */
+#define KS884X_P2VCT_P 0x04F4
+#define KS884X_P2PHYCTRL_P 0x04F6
+
+#define KS884X_PHY_SPECIAL_OFFSET KS884X_P1VCT_P
+#define PHY_SPECIAL_INTERVAL (KS884X_P2VCT_P - KS884X_P1VCT_P)
+
+#define KS884X_PHY_LINK_MD_OFFSET 0x00
+
+#define PHY_START_CABLE_DIAG 0x8000
+#define PHY_CABLE_DIAG_RESULT 0x6000
+#define PHY_CABLE_STAT_NORMAL 0x0000
+#define PHY_CABLE_STAT_OPEN 0x2000
+#define PHY_CABLE_STAT_SHORT 0x4000
+#define PHY_CABLE_STAT_FAILED 0x6000
+#define PHY_CABLE_10M_SHORT 0x1000
+#define PHY_CABLE_FAULT_COUNTER 0x01FF
+
+#define KS884X_PHY_PHY_CTRL_OFFSET 0x02
+
+#define PHY_STAT_REVERSED_POLARITY 0x0020
+#define PHY_STAT_MDIX 0x0010
+#define PHY_FORCE_LINK 0x0008
+#define PHY_POWER_SAVING_DISABLE 0x0004
+#define PHY_REMOTE_LOOPBACK 0x0002
+
+/* SIDER */
+#define KS884X_SIDER_P 0x0400
+#define KS884X_CHIP_ID_OFFSET KS884X_SIDER_P
+#define KS884X_FAMILY_ID_OFFSET (KS884X_CHIP_ID_OFFSET + 1)
+
+#define REG_FAMILY_ID 0x88
+
+#define REG_CHIP_ID_41 0x8810
+#define REG_CHIP_ID_42 0x8800
+
+#define KS884X_CHIP_ID_MASK_41 0xFF10
+#define KS884X_CHIP_ID_MASK 0xFFF0
+#define KS884X_CHIP_ID_SHIFT 4
+#define KS884X_REVISION_MASK 0x000E
+#define KS884X_REVISION_SHIFT 1
+#define KS8842_START 0x0001
+
+#define CHIP_IP_41_M 0x8810
+#define CHIP_IP_42_M 0x8800
+#define CHIP_IP_61_M 0x8890
+#define CHIP_IP_62_M 0x8880
+
+#define CHIP_IP_41_P 0x8850
+#define CHIP_IP_42_P 0x8840
+#define CHIP_IP_61_P 0x88D0
+#define CHIP_IP_62_P 0x88C0
+
+/* SGCR1 */
+#define KS8842_SGCR1_P 0x0402
+#define KS8842_SWITCH_CTRL_1_OFFSET KS8842_SGCR1_P
+
+#define SWITCH_PASS_ALL 0x8000
+#define SWITCH_TX_FLOW_CTRL 0x2000
+#define SWITCH_RX_FLOW_CTRL 0x1000
+#define SWITCH_CHECK_LENGTH 0x0800
+#define SWITCH_AGING_ENABLE 0x0400
+#define SWITCH_FAST_AGING 0x0200
+#define SWITCH_AGGR_BACKOFF 0x0100
+#define SWITCH_PASS_PAUSE 0x0008
+#define SWITCH_LINK_AUTO_AGING 0x0001
+
+/* SGCR2 */
+#define KS8842_SGCR2_P 0x0404
+#define KS8842_SWITCH_CTRL_2_OFFSET KS8842_SGCR2_P
+
+#define SWITCH_VLAN_ENABLE 0x8000
+#define SWITCH_IGMP_SNOOP 0x4000
+#define IPV6_MLD_SNOOP_ENABLE 0x2000
+#define IPV6_MLD_SNOOP_OPTION 0x1000
+#define PRIORITY_SCHEME_SELECT 0x0800
+#define SWITCH_MIRROR_RX_TX 0x0100
+#define UNICAST_VLAN_BOUNDARY 0x0080
+#define MULTICAST_STORM_DISABLE 0x0040
+#define SWITCH_BACK_PRESSURE 0x0020
+#define FAIR_FLOW_CTRL 0x0010
+#define NO_EXC_COLLISION_DROP 0x0008
+#define SWITCH_HUGE_PACKET 0x0004
+#define SWITCH_LEGAL_PACKET 0x0002
+#define SWITCH_BUF_RESERVE 0x0001
+
+/* SGCR3 */
+#define KS8842_SGCR3_P 0x0406
+#define KS8842_SWITCH_CTRL_3_OFFSET KS8842_SGCR3_P
+
+#define BROADCAST_STORM_RATE_LO 0xFF00
+#define SWITCH_REPEATER 0x0080
+#define SWITCH_HALF_DUPLEX 0x0040
+#define SWITCH_FLOW_CTRL 0x0020
+#define SWITCH_10_MBIT 0x0010
+#define SWITCH_REPLACE_NULL_VID 0x0008
+#define BROADCAST_STORM_RATE_HI 0x0007
+
+#define BROADCAST_STORM_RATE 0x07FF
+
+/* SGCR4 */
+#define KS8842_SGCR4_P 0x0408
+
+/* SGCR5 */
+#define KS8842_SGCR5_P 0x040A
+#define KS8842_SWITCH_CTRL_5_OFFSET KS8842_SGCR5_P
+
+#define LED_MODE 0x8200
+#define LED_SPEED_DUPLEX_ACT 0x0000
+#define LED_SPEED_DUPLEX_LINK_ACT 0x8000
+#define LED_DUPLEX_10_100 0x0200
+
+/* SGCR6 */
+#define KS8842_SGCR6_P 0x0410
+#define KS8842_SWITCH_CTRL_6_OFFSET KS8842_SGCR6_P
+
+#define KS8842_PRIORITY_MASK 3
+#define KS8842_PRIORITY_SHIFT 2
+
+/* SGCR7 */
+#define KS8842_SGCR7_P 0x0412
+#define KS8842_SWITCH_CTRL_7_OFFSET KS8842_SGCR7_P
+
+#define SWITCH_UNK_DEF_PORT_ENABLE 0x0008
+#define SWITCH_UNK_DEF_PORT_3 0x0004
+#define SWITCH_UNK_DEF_PORT_2 0x0002
+#define SWITCH_UNK_DEF_PORT_1 0x0001
+
+/* MACAR1 */
+#define KS8842_MACAR1_P 0x0470
+#define KS8842_MACAR2_P 0x0472
+#define KS8842_MACAR3_P 0x0474
+#define KS8842_MAC_ADDR_1_OFFSET KS8842_MACAR1_P
+#define KS8842_MAC_ADDR_0_OFFSET (KS8842_MAC_ADDR_1_OFFSET + 1)
+#define KS8842_MAC_ADDR_3_OFFSET KS8842_MACAR2_P
+#define KS8842_MAC_ADDR_2_OFFSET (KS8842_MAC_ADDR_3_OFFSET + 1)
+#define KS8842_MAC_ADDR_5_OFFSET KS8842_MACAR3_P
+#define KS8842_MAC_ADDR_4_OFFSET (KS8842_MAC_ADDR_5_OFFSET + 1)
+
+/* TOSR1 */
+#define KS8842_TOSR1_P 0x0480
+#define KS8842_TOSR2_P 0x0482
+#define KS8842_TOSR3_P 0x0484
+#define KS8842_TOSR4_P 0x0486
+#define KS8842_TOSR5_P 0x0488
+#define KS8842_TOSR6_P 0x048A
+#define KS8842_TOSR7_P 0x0490
+#define KS8842_TOSR8_P 0x0492
+#define KS8842_TOS_1_OFFSET KS8842_TOSR1_P
+#define KS8842_TOS_2_OFFSET KS8842_TOSR2_P
+#define KS8842_TOS_3_OFFSET KS8842_TOSR3_P
+#define KS8842_TOS_4_OFFSET KS8842_TOSR4_P
+#define KS8842_TOS_5_OFFSET KS8842_TOSR5_P
+#define KS8842_TOS_6_OFFSET KS8842_TOSR6_P
+
+#define KS8842_TOS_7_OFFSET KS8842_TOSR7_P
+#define KS8842_TOS_8_OFFSET KS8842_TOSR8_P
+
+/* P1CR1 */
+#define KS8842_P1CR1_P 0x0500
+#define KS8842_P1CR2_P 0x0502
+#define KS8842_P1VIDR_P 0x0504
+#define KS8842_P1CR3_P 0x0506
+#define KS8842_P1IRCR_P 0x0508
+#define KS8842_P1ERCR_P 0x050A
+#define KS884X_P1SCSLMD_P 0x0510
+#define KS884X_P1CR4_P 0x0512
+#define KS884X_P1SR_P 0x0514
+
+/* P2CR1 */
+#define KS8842_P2CR1_P 0x0520
+#define KS8842_P2CR2_P 0x0522
+#define KS8842_P2VIDR_P 0x0524
+#define KS8842_P2CR3_P 0x0526
+#define KS8842_P2IRCR_P 0x0528
+#define KS8842_P2ERCR_P 0x052A
+#define KS884X_P2SCSLMD_P 0x0530
+#define KS884X_P2CR4_P 0x0532
+#define KS884X_P2SR_P 0x0534
+
+/* P3CR1 */
+#define KS8842_P3CR1_P 0x0540
+#define KS8842_P3CR2_P 0x0542
+#define KS8842_P3VIDR_P 0x0544
+#define KS8842_P3CR3_P 0x0546
+#define KS8842_P3IRCR_P 0x0548
+#define KS8842_P3ERCR_P 0x054A
+
+#define KS8842_PORT_1_CTRL_1 KS8842_P1CR1_P
+#define KS8842_PORT_2_CTRL_1 KS8842_P2CR1_P
+#define KS8842_PORT_3_CTRL_1 KS8842_P3CR1_P
+
+#define PORT_CTRL_ADDR(port, addr) \
+ (addr = KS8842_PORT_1_CTRL_1 + (port) * \
+ (KS8842_PORT_2_CTRL_1 - KS8842_PORT_1_CTRL_1))
+
+#define KS8842_PORT_CTRL_1_OFFSET 0x00
+
+#define PORT_BROADCAST_STORM 0x0080
+#define PORT_DIFFSERV_ENABLE 0x0040
+#define PORT_802_1P_ENABLE 0x0020
+#define PORT_BASED_PRIORITY_MASK 0x0018
+#define PORT_BASED_PRIORITY_BASE 0x0003
+#define PORT_BASED_PRIORITY_SHIFT 3
+#define PORT_BASED_PRIORITY_0 0x0000
+#define PORT_BASED_PRIORITY_1 0x0008
+#define PORT_BASED_PRIORITY_2 0x0010
+#define PORT_BASED_PRIORITY_3 0x0018
+#define PORT_INSERT_TAG 0x0004
+#define PORT_REMOVE_TAG 0x0002
+#define PORT_PRIO_QUEUE_ENABLE 0x0001
+
+#define KS8842_PORT_CTRL_2_OFFSET 0x02
+
+#define PORT_INGRESS_VLAN_FILTER 0x4000
+#define PORT_DISCARD_NON_VID 0x2000
+#define PORT_FORCE_FLOW_CTRL 0x1000
+#define PORT_BACK_PRESSURE 0x0800
+#define PORT_TX_ENABLE 0x0400
+#define PORT_RX_ENABLE 0x0200
+#define PORT_LEARN_DISABLE 0x0100
+#define PORT_MIRROR_SNIFFER 0x0080
+#define PORT_MIRROR_RX 0x0040
+#define PORT_MIRROR_TX 0x0020
+#define PORT_USER_PRIORITY_CEILING 0x0008
+#define PORT_VLAN_MEMBERSHIP 0x0007
+
+#define KS8842_PORT_CTRL_VID_OFFSET 0x04
+
+#define PORT_DEFAULT_VID 0x0001
+
+#define KS8842_PORT_CTRL_3_OFFSET 0x06
+
+#define PORT_INGRESS_LIMIT_MODE 0x000C
+#define PORT_INGRESS_ALL 0x0000
+#define PORT_INGRESS_UNICAST 0x0004
+#define PORT_INGRESS_MULTICAST 0x0008
+#define PORT_INGRESS_BROADCAST 0x000C
+#define PORT_COUNT_IFG 0x0002
+#define PORT_COUNT_PREAMBLE 0x0001
+
+#define KS8842_PORT_IN_RATE_OFFSET 0x08
+#define KS8842_PORT_OUT_RATE_OFFSET 0x0A
+
+#define PORT_PRIORITY_RATE 0x0F
+#define PORT_PRIORITY_RATE_SHIFT 4
+
+#define KS884X_PORT_LINK_MD 0x10
+
+#define PORT_CABLE_10M_SHORT 0x8000
+#define PORT_CABLE_DIAG_RESULT 0x6000
+#define PORT_CABLE_STAT_NORMAL 0x0000
+#define PORT_CABLE_STAT_OPEN 0x2000
+#define PORT_CABLE_STAT_SHORT 0x4000
+#define PORT_CABLE_STAT_FAILED 0x6000
+#define PORT_START_CABLE_DIAG 0x1000
+#define PORT_FORCE_LINK 0x0800
+#define PORT_POWER_SAVING_DISABLE 0x0400
+#define PORT_PHY_REMOTE_LOOPBACK 0x0200
+#define PORT_CABLE_FAULT_COUNTER 0x01FF
+
+#define KS884X_PORT_CTRL_4_OFFSET 0x12
+
+#define PORT_LED_OFF 0x8000
+#define PORT_TX_DISABLE 0x4000
+#define PORT_AUTO_NEG_RESTART 0x2000
+#define PORT_REMOTE_FAULT_DISABLE 0x1000
+#define PORT_POWER_DOWN 0x0800
+#define PORT_AUTO_MDIX_DISABLE 0x0400
+#define PORT_FORCE_MDIX 0x0200
+#define PORT_LOOPBACK 0x0100
+#define PORT_AUTO_NEG_ENABLE 0x0080
+#define PORT_FORCE_100_MBIT 0x0040
+#define PORT_FORCE_FULL_DUPLEX 0x0020
+#define PORT_AUTO_NEG_SYM_PAUSE 0x0010
+#define PORT_AUTO_NEG_100BTX_FD 0x0008
+#define PORT_AUTO_NEG_100BTX 0x0004
+#define PORT_AUTO_NEG_10BT_FD 0x0002
+#define PORT_AUTO_NEG_10BT 0x0001
+
+#define KS884X_PORT_STATUS_OFFSET 0x14
+
+#define PORT_HP_MDIX 0x8000
+#define PORT_REVERSED_POLARITY 0x2000
+#define PORT_RX_FLOW_CTRL 0x0800
+#define PORT_TX_FLOW_CTRL 0x1000
+#define PORT_STATUS_SPEED_100MBIT 0x0400
+#define PORT_STATUS_FULL_DUPLEX 0x0200
+#define PORT_REMOTE_FAULT 0x0100
+#define PORT_MDIX_STATUS 0x0080
+#define PORT_AUTO_NEG_COMPLETE 0x0040
+#define PORT_STATUS_LINK_GOOD 0x0020
+#define PORT_REMOTE_SYM_PAUSE 0x0010
+#define PORT_REMOTE_100BTX_FD 0x0008
+#define PORT_REMOTE_100BTX 0x0004
+#define PORT_REMOTE_10BT_FD 0x0002
+#define PORT_REMOTE_10BT 0x0001
+
+/*
+#define STATIC_MAC_TABLE_ADDR 00-0000FFFF-FFFFFFFF
+#define STATIC_MAC_TABLE_FWD_PORTS 00-00070000-00000000
+#define STATIC_MAC_TABLE_VALID 00-00080000-00000000
+#define STATIC_MAC_TABLE_OVERRIDE 00-00100000-00000000
+#define STATIC_MAC_TABLE_USE_FID 00-00200000-00000000
+#define STATIC_MAC_TABLE_FID 00-03C00000-00000000
+*/
+
+#define STATIC_MAC_TABLE_ADDR 0x0000FFFF
+#define STATIC_MAC_TABLE_FWD_PORTS 0x00070000
+#define STATIC_MAC_TABLE_VALID 0x00080000
+#define STATIC_MAC_TABLE_OVERRIDE 0x00100000
+#define STATIC_MAC_TABLE_USE_FID 0x00200000
+#define STATIC_MAC_TABLE_FID 0x03C00000
+
+#define STATIC_MAC_FWD_PORTS_SHIFT 16
+#define STATIC_MAC_FID_SHIFT 22
+
+/*
+#define VLAN_TABLE_VID 00-00000000-00000FFF
+#define VLAN_TABLE_FID 00-00000000-0000F000
+#define VLAN_TABLE_MEMBERSHIP 00-00000000-00070000
+#define VLAN_TABLE_VALID 00-00000000-00080000
+*/
+
+#define VLAN_TABLE_VID 0x00000FFF
+#define VLAN_TABLE_FID 0x0000F000
+#define VLAN_TABLE_MEMBERSHIP 0x00070000
+#define VLAN_TABLE_VALID 0x00080000
+
+#define VLAN_TABLE_FID_SHIFT 12
+#define VLAN_TABLE_MEMBERSHIP_SHIFT 16
+
+/*
+#define DYNAMIC_MAC_TABLE_ADDR 00-0000FFFF-FFFFFFFF
+#define DYNAMIC_MAC_TABLE_FID 00-000F0000-00000000
+#define DYNAMIC_MAC_TABLE_SRC_PORT 00-00300000-00000000
+#define DYNAMIC_MAC_TABLE_TIMESTAMP 00-00C00000-00000000
+#define DYNAMIC_MAC_TABLE_ENTRIES 03-FF000000-00000000
+#define DYNAMIC_MAC_TABLE_MAC_EMPTY 04-00000000-00000000
+#define DYNAMIC_MAC_TABLE_RESERVED 78-00000000-00000000
+#define DYNAMIC_MAC_TABLE_NOT_READY 80-00000000-00000000
+*/
+
+#define DYNAMIC_MAC_TABLE_ADDR 0x0000FFFF
+#define DYNAMIC_MAC_TABLE_FID 0x000F0000
+#define DYNAMIC_MAC_TABLE_SRC_PORT 0x00300000
+#define DYNAMIC_MAC_TABLE_TIMESTAMP 0x00C00000
+#define DYNAMIC_MAC_TABLE_ENTRIES 0xFF000000
+
+#define DYNAMIC_MAC_TABLE_ENTRIES_H 0x03
+#define DYNAMIC_MAC_TABLE_MAC_EMPTY 0x04
+#define DYNAMIC_MAC_TABLE_RESERVED 0x78
+#define DYNAMIC_MAC_TABLE_NOT_READY 0x80
+
+#define DYNAMIC_MAC_FID_SHIFT 16
+#define DYNAMIC_MAC_SRC_PORT_SHIFT 20
+#define DYNAMIC_MAC_TIMESTAMP_SHIFT 22
+#define DYNAMIC_MAC_ENTRIES_SHIFT 24
+#define DYNAMIC_MAC_ENTRIES_H_SHIFT 8
+
+/*
+#define MIB_COUNTER_VALUE 00-00000000-3FFFFFFF
+#define MIB_COUNTER_VALID 00-00000000-40000000
+#define MIB_COUNTER_OVERFLOW 00-00000000-80000000
+*/
+
+#define MIB_COUNTER_VALUE 0x3FFFFFFF
+#define MIB_COUNTER_VALID 0x40000000
+#define MIB_COUNTER_OVERFLOW 0x80000000
+
+#define MIB_PACKET_DROPPED 0x0000FFFF
+
+#define KS_MIB_PACKET_DROPPED_TX_0 0x100
+#define KS_MIB_PACKET_DROPPED_TX_1 0x101
+#define KS_MIB_PACKET_DROPPED_TX 0x102
+#define KS_MIB_PACKET_DROPPED_RX_0 0x103
+#define KS_MIB_PACKET_DROPPED_RX_1 0x104
+#define KS_MIB_PACKET_DROPPED_RX 0x105
+
+/* Change default LED mode. */
+#define SET_DEFAULT_LED LED_SPEED_DUPLEX_ACT
+
+#define MAC_ADDR_LEN 6
+#define MAC_ADDR_ORDER(i) (MAC_ADDR_LEN - 1 - (i))
+
+#define MAX_ETHERNET_BODY_SIZE 1500
+#define ETHERNET_HEADER_SIZE 14
+
+#define MAX_ETHERNET_PACKET_SIZE \
+ (MAX_ETHERNET_BODY_SIZE + ETHERNET_HEADER_SIZE)
+
+#define REGULAR_RX_BUF_SIZE (MAX_ETHERNET_PACKET_SIZE + 4)
+#define MAX_RX_BUF_SIZE (1912 + 4)
+
+#define ADDITIONAL_ENTRIES 16
+#define MAX_MULTICAST_LIST 32
+
+#define HW_MULTICAST_SIZE 8
+
+#define HW_TO_DEV_PORT(port) (port - 1)
+
+enum {
+ media_connected,
+ media_disconnected
+};
+
+enum {
+ OID_COUNTER_UNKOWN,
+
+ OID_COUNTER_FIRST,
+
+ /* total transmit errors */
+ OID_COUNTER_XMIT_ERROR,
+
+ /* total receive errors */
+ OID_COUNTER_RCV_ERROR,
+
+ OID_COUNTER_LAST
+};
+
+/*
+ * Hardware descriptor definitions
+ */
+
+#define DESC_ALIGNMENT 16
+#define BUFFER_ALIGNMENT 8
+
+#define NUM_OF_RX_DESC 64
+#define NUM_OF_TX_DESC 64
+
+#define KS_DESC_RX_FRAME_LEN 0x000007FF
+#define KS_DESC_RX_FRAME_TYPE 0x00008000
+#define KS_DESC_RX_ERROR_CRC 0x00010000
+#define KS_DESC_RX_ERROR_RUNT 0x00020000
+#define KS_DESC_RX_ERROR_TOO_LONG 0x00040000
+#define KS_DESC_RX_ERROR_PHY 0x00080000
+#define KS884X_DESC_RX_PORT_MASK 0x00300000
+#define KS_DESC_RX_MULTICAST 0x01000000
+#define KS_DESC_RX_ERROR 0x02000000
+#define KS_DESC_RX_ERROR_CSUM_UDP 0x04000000
+#define KS_DESC_RX_ERROR_CSUM_TCP 0x08000000
+#define KS_DESC_RX_ERROR_CSUM_IP 0x10000000
+#define KS_DESC_RX_LAST 0x20000000
+#define KS_DESC_RX_FIRST 0x40000000
+#define KS_DESC_RX_ERROR_COND \
+ (KS_DESC_RX_ERROR_CRC | \
+ KS_DESC_RX_ERROR_RUNT | \
+ KS_DESC_RX_ERROR_PHY | \
+ KS_DESC_RX_ERROR_TOO_LONG)
+
+#define KS_DESC_HW_OWNED 0x80000000
+
+#define KS_DESC_BUF_SIZE 0x000007FF
+#define KS884X_DESC_TX_PORT_MASK 0x00300000
+#define KS_DESC_END_OF_RING 0x02000000
+#define KS_DESC_TX_CSUM_GEN_UDP 0x04000000
+#define KS_DESC_TX_CSUM_GEN_TCP 0x08000000
+#define KS_DESC_TX_CSUM_GEN_IP 0x10000000
+#define KS_DESC_TX_LAST 0x20000000
+#define KS_DESC_TX_FIRST 0x40000000
+#define KS_DESC_TX_INTERRUPT 0x80000000
+
+#define KS_DESC_PORT_SHIFT 20
+
+#define KS_DESC_RX_MASK (KS_DESC_BUF_SIZE)
+
+#define KS_DESC_TX_MASK \
+ (KS_DESC_TX_INTERRUPT | \
+ KS_DESC_TX_FIRST | \
+ KS_DESC_TX_LAST | \
+ KS_DESC_TX_CSUM_GEN_IP | \
+ KS_DESC_TX_CSUM_GEN_TCP | \
+ KS_DESC_TX_CSUM_GEN_UDP | \
+ KS_DESC_BUF_SIZE)
+
+struct ksz_desc_rx_stat {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u32 hw_owned:1;
+ u32 first_desc:1;
+ u32 last_desc:1;
+ u32 csum_err_ip:1;
+ u32 csum_err_tcp:1;
+ u32 csum_err_udp:1;
+ u32 error:1;
+ u32 multicast:1;
+ u32 src_port:4;
+ u32 err_phy:1;
+ u32 err_too_long:1;
+ u32 err_runt:1;
+ u32 err_crc:1;
+ u32 frame_type:1;
+ u32 reserved1:4;
+ u32 frame_len:11;
+#else
+ u32 frame_len:11;
+ u32 reserved1:4;
+ u32 frame_type:1;
+ u32 err_crc:1;
+ u32 err_runt:1;
+ u32 err_too_long:1;
+ u32 err_phy:1;
+ u32 src_port:4;
+ u32 multicast:1;
+ u32 error:1;
+ u32 csum_err_udp:1;
+ u32 csum_err_tcp:1;
+ u32 csum_err_ip:1;
+ u32 last_desc:1;
+ u32 first_desc:1;
+ u32 hw_owned:1;
+#endif
+};
+
+struct ksz_desc_tx_stat {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u32 hw_owned:1;
+ u32 reserved1:31;
+#else
+ u32 reserved1:31;
+ u32 hw_owned:1;
+#endif
+};
+
+struct ksz_desc_rx_buf {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u32 reserved4:6;
+ u32 end_of_ring:1;
+ u32 reserved3:14;
+ u32 buf_size:11;
+#else
+ u32 buf_size:11;
+ u32 reserved3:14;
+ u32 end_of_ring:1;
+ u32 reserved4:6;
+#endif
+};
+
+struct ksz_desc_tx_buf {
+#ifdef __BIG_ENDIAN_BITFIELD
+ u32 intr:1;
+ u32 first_seg:1;
+ u32 last_seg:1;
+ u32 csum_gen_ip:1;
+ u32 csum_gen_tcp:1;
+ u32 csum_gen_udp:1;
+ u32 end_of_ring:1;
+ u32 reserved4:1;
+ u32 dest_port:4;
+ u32 reserved3:9;
+ u32 buf_size:11;
+#else
+ u32 buf_size:11;
+ u32 reserved3:9;
+ u32 dest_port:4;
+ u32 reserved4:1;
+ u32 end_of_ring:1;
+ u32 csum_gen_udp:1;
+ u32 csum_gen_tcp:1;
+ u32 csum_gen_ip:1;
+ u32 last_seg:1;
+ u32 first_seg:1;
+ u32 intr:1;
+#endif
+};
+
+union desc_stat {
+ struct ksz_desc_rx_stat rx;
+ struct ksz_desc_tx_stat tx;
+ u32 data;
+};
+
+union desc_buf {
+ struct ksz_desc_rx_buf rx;
+ struct ksz_desc_tx_buf tx;
+ u32 data;
+};
+
+/**
+ * struct ksz_hw_desc - Hardware descriptor data structure
+ * @ctrl: Descriptor control value.
+ * @buf: Descriptor buffer value.
+ * @addr: Physical address of memory buffer.
+ * @next: Pointer to next hardware descriptor.
+ */
+struct ksz_hw_desc {
+ union desc_stat ctrl;
+ union desc_buf buf;
+ u32 addr;
+ u32 next;
+};
+
+/**
+ * struct ksz_sw_desc - Software descriptor data structure
+ * @ctrl: Descriptor control value.
+ * @buf: Descriptor buffer value.
+ * @buf_size: Current buffers size value in hardware descriptor.
+ */
+struct ksz_sw_desc {
+ union desc_stat ctrl;
+ union desc_buf buf;
+ u32 buf_size;
+};
+
+/**
+ * struct ksz_dma_buf - OS dependent DMA buffer data structure
+ * @skb: Associated socket buffer.
+ * @dma: Associated physical DMA address.
+ * len: Actual len used.
+ */
+struct ksz_dma_buf {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ int len;
+};
+
+/**
+ * struct ksz_desc - Descriptor structure
+ * @phw: Hardware descriptor pointer to uncached physical memory.
+ * @sw: Cached memory to hold hardware descriptor values for
+ * manipulation.
+ * @dma_buf: Operating system dependent data structure to hold physical
+ * memory buffer allocation information.
+ */
+struct ksz_desc {
+ struct ksz_hw_desc *phw;
+ struct ksz_sw_desc sw;
+ struct ksz_dma_buf dma_buf;
+};
+
+#define DMA_BUFFER(desc) ((struct ksz_dma_buf *)(&(desc)->dma_buf))
+
+/**
+ * struct ksz_desc_info - Descriptor information data structure
+ * @ring: First descriptor in the ring.
+ * @cur: Current descriptor being manipulated.
+ * @ring_virt: First hardware descriptor in the ring.
+ * @ring_phys: The physical address of the first descriptor of the ring.
+ * @size: Size of hardware descriptor.
+ * @alloc: Number of descriptors allocated.
+ * @avail: Number of descriptors available for use.
+ * @last: Index for last descriptor released to hardware.
+ * @next: Index for next descriptor available for use.
+ * @mask: Mask for index wrapping.
+ */
+struct ksz_desc_info {
+ struct ksz_desc *ring;
+ struct ksz_desc *cur;
+ struct ksz_hw_desc *ring_virt;
+ u32 ring_phys;
+ int size;
+ int alloc;
+ int avail;
+ int last;
+ int next;
+ int mask;
+};
+
+/*
+ * KSZ8842 switch definitions
+ */
+
+enum {
+ TABLE_STATIC_MAC = 0,
+ TABLE_VLAN,
+ TABLE_DYNAMIC_MAC,
+ TABLE_MIB
+};
+
+#define LEARNED_MAC_TABLE_ENTRIES 1024
+#define STATIC_MAC_TABLE_ENTRIES 8
+
+/**
+ * struct ksz_mac_table - Static MAC table data structure
+ * @mac_addr: MAC address to filter.
+ * @vid: VID value.
+ * @fid: FID value.
+ * @ports: Port membership.
+ * @override: Override setting.
+ * @use_fid: FID use setting.
+ * @valid: Valid setting indicating the entry is being used.
+ */
+struct ksz_mac_table {
+ u8 mac_addr[MAC_ADDR_LEN];
+ u16 vid;
+ u8 fid;
+ u8 ports;
+ u8 override:1;
+ u8 use_fid:1;
+ u8 valid:1;
+};
+
+#define VLAN_TABLE_ENTRIES 16
+
+/**
+ * struct ksz_vlan_table - VLAN table data structure
+ * @vid: VID value.
+ * @fid: FID value.
+ * @member: Port membership.
+ */
+struct ksz_vlan_table {
+ u16 vid;
+ u8 fid;
+ u8 member;
+};
+
+#define DIFFSERV_ENTRIES 64
+#define PRIO_802_1P_ENTRIES 8
+#define PRIO_QUEUES 4
+
+#define SWITCH_PORT_NUM 2
+#define TOTAL_PORT_NUM (SWITCH_PORT_NUM + 1)
+#define HOST_MASK (1 << SWITCH_PORT_NUM)
+#define PORT_MASK 7
+
+#define MAIN_PORT 0
+#define OTHER_PORT 1
+#define HOST_PORT SWITCH_PORT_NUM
+
+#define PORT_COUNTER_NUM 0x20
+#define TOTAL_PORT_COUNTER_NUM (PORT_COUNTER_NUM + 2)
+
+#define MIB_COUNTER_RX_LO_PRIORITY 0x00
+#define MIB_COUNTER_RX_HI_PRIORITY 0x01
+#define MIB_COUNTER_RX_UNDERSIZE 0x02
+#define MIB_COUNTER_RX_FRAGMENT 0x03
+#define MIB_COUNTER_RX_OVERSIZE 0x04
+#define MIB_COUNTER_RX_JABBER 0x05
+#define MIB_COUNTER_RX_SYMBOL_ERR 0x06
+#define MIB_COUNTER_RX_CRC_ERR 0x07
+#define MIB_COUNTER_RX_ALIGNMENT_ERR 0x08
+#define MIB_COUNTER_RX_CTRL_8808 0x09
+#define MIB_COUNTER_RX_PAUSE 0x0A
+#define MIB_COUNTER_RX_BROADCAST 0x0B
+#define MIB_COUNTER_RX_MULTICAST 0x0C
+#define MIB_COUNTER_RX_UNICAST 0x0D
+#define MIB_COUNTER_RX_OCTET_64 0x0E
+#define MIB_COUNTER_RX_OCTET_65_127 0x0F
+#define MIB_COUNTER_RX_OCTET_128_255 0x10
+#define MIB_COUNTER_RX_OCTET_256_511 0x11
+#define MIB_COUNTER_RX_OCTET_512_1023 0x12
+#define MIB_COUNTER_RX_OCTET_1024_1522 0x13
+#define MIB_COUNTER_TX_LO_PRIORITY 0x14
+#define MIB_COUNTER_TX_HI_PRIORITY 0x15
+#define MIB_COUNTER_TX_LATE_COLLISION 0x16
+#define MIB_COUNTER_TX_PAUSE 0x17
+#define MIB_COUNTER_TX_BROADCAST 0x18
+#define MIB_COUNTER_TX_MULTICAST 0x19
+#define MIB_COUNTER_TX_UNICAST 0x1A
+#define MIB_COUNTER_TX_DEFERRED 0x1B
+#define MIB_COUNTER_TX_TOTAL_COLLISION 0x1C
+#define MIB_COUNTER_TX_EXCESS_COLLISION 0x1D
+#define MIB_COUNTER_TX_SINGLE_COLLISION 0x1E
+#define MIB_COUNTER_TX_MULTI_COLLISION 0x1F
+
+#define MIB_COUNTER_RX_DROPPED_PACKET 0x20
+#define MIB_COUNTER_TX_DROPPED_PACKET 0x21
+
+/**
+ * struct ksz_port_mib - Port MIB data structure
+ * @cnt_ptr: Current pointer to MIB counter index.
+ * @link_down: Indication the link has just gone down.
+ * @state: Connection status of the port.
+ * @mib_start: The starting counter index. Some ports do not start at 0.
+ * @counter: 64-bit MIB counter value.
+ * @dropped: Temporary buffer to remember last read packet dropped values.
+ *
+ * MIB counters needs to be read periodically so that counters do not get
+ * overflowed and give incorrect values. A right balance is needed to
+ * satisfy this condition and not waste too much CPU time.
+ *
+ * It is pointless to read MIB counters when the port is disconnected. The
+ * @state provides the connection status so that MIB counters are read only
+ * when the port is connected. The @link_down indicates the port is just
+ * disconnected so that all MIB counters are read one last time to update the
+ * information.
+ */
+struct ksz_port_mib {
+ u8 cnt_ptr;
+ u8 link_down;
+ u8 state;
+ u8 mib_start;
+
+ u64 counter[TOTAL_PORT_COUNTER_NUM];
+ u32 dropped[2];
+};
+
+/**
+ * struct ksz_port_cfg - Port configuration data structure
+ * @vid: VID value.
+ * @member: Port membership.
+ * @port_prio: Port priority.
+ * @rx_rate: Receive priority rate.
+ * @tx_rate: Transmit priority rate.
+ * @stp_state: Current Spanning Tree Protocol state.
+ */
+struct ksz_port_cfg {
+ u16 vid;
+ u8 member;
+ u8 port_prio;
+ u32 rx_rate[PRIO_QUEUES];
+ u32 tx_rate[PRIO_QUEUES];
+ int stp_state;
+};
+
+/**
+ * struct ksz_switch - KSZ8842 switch data structure
+ * @mac_table: MAC table entries information.
+ * @vlan_table: VLAN table entries information.
+ * @port_cfg: Port configuration information.
+ * @diffserv: DiffServ priority settings. Possible values from 6-bit of ToS
+ * (bit7 ~ bit2) field.
+ * @p_802_1p: 802.1P priority settings. Possible values from 3-bit of 802.1p
+ * Tag priority field.
+ * @br_addr: Bridge address. Used for STP.
+ * @other_addr: Other MAC address. Used for multiple network device mode.
+ * @broad_per: Broadcast storm percentage.
+ * @member: Current port membership. Used for STP.
+ */
+struct ksz_switch {
+ struct ksz_mac_table mac_table[STATIC_MAC_TABLE_ENTRIES];
+ struct ksz_vlan_table vlan_table[VLAN_TABLE_ENTRIES];
+ struct ksz_port_cfg port_cfg[TOTAL_PORT_NUM];
+
+ u8 diffserv[DIFFSERV_ENTRIES];
+ u8 p_802_1p[PRIO_802_1P_ENTRIES];
+
+ u8 br_addr[MAC_ADDR_LEN];
+ u8 other_addr[MAC_ADDR_LEN];
+
+ u8 broad_per;
+ u8 member;
+};
+
+#define TX_RATE_UNIT 10000
+
+/**
+ * struct ksz_port_info - Port information data structure
+ * @state: Connection status of the port.
+ * @tx_rate: Transmit rate divided by 10000 to get Mbit.
+ * @duplex: Duplex mode.
+ * @advertised: Advertised auto-negotiation setting. Used to determine link.
+ * @partner: Auto-negotiation partner setting. Used to determine link.
+ * @port_id: Port index to access actual hardware register.
+ * @pdev: Pointer to OS dependent network device.
+ */
+struct ksz_port_info {
+ uint state;
+ uint tx_rate;
+ u8 duplex;
+ u8 advertised;
+ u8 partner;
+ u8 port_id;
+ void *pdev;
+};
+
+#define MAX_TX_HELD_SIZE 52000
+
+/* Hardware features and bug fixes. */
+#define LINK_INT_WORKING (1 << 0)
+#define SMALL_PACKET_TX_BUG (1 << 1)
+#define HALF_DUPLEX_SIGNAL_BUG (1 << 2)
+#define IPV6_CSUM_GEN_HACK (1 << 3)
+#define RX_HUGE_FRAME (1 << 4)
+#define STP_SUPPORT (1 << 8)
+
+/* Software overrides. */
+#define PAUSE_FLOW_CTRL (1 << 0)
+#define FAST_AGING (1 << 1)
+
+/**
+ * struct ksz_hw - KSZ884X hardware data structure
+ * @io: Virtual address assigned.
+ * @ksz_switch: Pointer to KSZ8842 switch.
+ * @port_info: Port information.
+ * @port_mib: Port MIB information.
+ * @dev_count: Number of network devices this hardware supports.
+ * @dst_ports: Destination ports in switch for transmission.
+ * @id: Hardware ID. Used for display only.
+ * @mib_cnt: Number of MIB counters this hardware has.
+ * @mib_port_cnt: Number of ports with MIB counters.
+ * @tx_cfg: Cached transmit control settings.
+ * @rx_cfg: Cached receive control settings.
+ * @intr_mask: Current interrupt mask.
+ * @intr_set: Current interrup set.
+ * @intr_blocked: Interrupt blocked.
+ * @rx_desc_info: Receive descriptor information.
+ * @tx_desc_info: Transmit descriptor information.
+ * @tx_int_cnt: Transmit interrupt count. Used for TX optimization.
+ * @tx_int_mask: Transmit interrupt mask. Used for TX optimization.
+ * @tx_size: Transmit data size. Used for TX optimization.
+ * The maximum is defined by MAX_TX_HELD_SIZE.
+ * @perm_addr: Permanent MAC address.
+ * @override_addr: Overrided MAC address.
+ * @address: Additional MAC address entries.
+ * @addr_list_size: Additional MAC address list size.
+ * @mac_override: Indication of MAC address overrided.
+ * @promiscuous: Counter to keep track of promiscuous mode set.
+ * @all_multi: Counter to keep track of all multicast mode set.
+ * @multi_list: Multicast address entries.
+ * @multi_bits: Cached multicast hash table settings.
+ * @multi_list_size: Multicast address list size.
+ * @enabled: Indication of hardware enabled.
+ * @rx_stop: Indication of receive process stop.
+ * @features: Hardware features to enable.
+ * @overrides: Hardware features to override.
+ * @parent: Pointer to parent, network device private structure.
+ */
+struct ksz_hw {
+ void __iomem *io;
+
+ struct ksz_switch *ksz_switch;
+ struct ksz_port_info port_info[SWITCH_PORT_NUM];
+ struct ksz_port_mib port_mib[TOTAL_PORT_NUM];
+ int dev_count;
+ int dst_ports;
+ int id;
+ int mib_cnt;
+ int mib_port_cnt;
+
+ u32 tx_cfg;
+ u32 rx_cfg;
+ u32 intr_mask;
+ u32 intr_set;
+ uint intr_blocked;
+
+ struct ksz_desc_info rx_desc_info;
+ struct ksz_desc_info tx_desc_info;
+
+ int tx_int_cnt;
+ int tx_int_mask;
+ int tx_size;
+
+ u8 perm_addr[MAC_ADDR_LEN];
+ u8 override_addr[MAC_ADDR_LEN];
+ u8 address[ADDITIONAL_ENTRIES][MAC_ADDR_LEN];
+ u8 addr_list_size;
+ u8 mac_override;
+ u8 promiscuous;
+ u8 all_multi;
+ u8 multi_list[MAX_MULTICAST_LIST][MAC_ADDR_LEN];
+ u8 multi_bits[HW_MULTICAST_SIZE];
+ u8 multi_list_size;
+
+ u8 enabled;
+ u8 rx_stop;
+ u8 reserved2[1];
+
+ uint features;
+ uint overrides;
+
+ void *parent;
+};
+
+enum {
+ PHY_NO_FLOW_CTRL,
+ PHY_FLOW_CTRL,
+ PHY_TX_ONLY,
+ PHY_RX_ONLY
+};
+
+/**
+ * struct ksz_port - Virtual port data structure
+ * @duplex: Duplex mode setting. 1 for half duplex, 2 for full
+ * duplex, and 0 for auto, which normally results in full
+ * duplex.
+ * @speed: Speed setting. 10 for 10 Mbit, 100 for 100 Mbit, and
+ * 0 for auto, which normally results in 100 Mbit.
+ * @force_link: Force link setting. 0 for auto-negotiation, and 1 for
+ * force.
+ * @flow_ctrl: Flow control setting. PHY_NO_FLOW_CTRL for no flow
+ * control, and PHY_FLOW_CTRL for flow control.
+ * PHY_TX_ONLY and PHY_RX_ONLY are not supported for 100
+ * Mbit PHY.
+ * @first_port: Index of first port this port supports.
+ * @mib_port_cnt: Number of ports with MIB counters.
+ * @port_cnt: Number of ports this port supports.
+ * @counter: Port statistics counter.
+ * @hw: Pointer to hardware structure.
+ * @linked: Pointer to port information linked to this port.
+ */
+struct ksz_port {
+ u8 duplex;
+ u8 speed;
+ u8 force_link;
+ u8 flow_ctrl;
+
+ int first_port;
+ int mib_port_cnt;
+ int port_cnt;
+ u64 counter[OID_COUNTER_LAST];
+
+ struct ksz_hw *hw;
+ struct ksz_port_info *linked;
+};
+
+/**
+ * struct ksz_timer_info - Timer information data structure
+ * @timer: Kernel timer.
+ * @cnt: Running timer counter.
+ * @max: Number of times to run timer; -1 for infinity.
+ * @period: Timer period in jiffies.
+ */
+struct ksz_timer_info {
+ struct timer_list timer;
+ int cnt;
+ int max;
+ int period;
+};
+
+/**
+ * struct ksz_shared_mem - OS dependent shared memory data structure
+ * @dma_addr: Physical DMA address allocated.
+ * @alloc_size: Allocation size.
+ * @phys: Actual physical address used.
+ * @alloc_virt: Virtual address allocated.
+ * @virt: Actual virtual address used.
+ */
+struct ksz_shared_mem {
+ dma_addr_t dma_addr;
+ uint alloc_size;
+ uint phys;
+ u8 *alloc_virt;
+ u8 *virt;
+};
+
+/**
+ * struct ksz_counter_info - OS dependent counter information data structure
+ * @counter: Wait queue to wakeup after counters are read.
+ * @time: Next time in jiffies to read counter.
+ * @read: Indication of counters read in full or not.
+ */
+struct ksz_counter_info {
+ wait_queue_head_t counter;
+ unsigned long time;
+ int read;
+};
+
+/**
+ * struct dev_info - Network device information data structure
+ * @dev: Pointer to network device.
+ * @pdev: Pointer to PCI device.
+ * @hw: Hardware structure.
+ * @desc_pool: Physical memory used for descriptor pool.
+ * @hwlock: Spinlock to prevent hardware from accessing.
+ * @lock: Mutex lock to prevent device from accessing.
+ * @dev_rcv: Receive process function used.
+ * @last_skb: Socket buffer allocated for descriptor rx fragments.
+ * @skb_index: Buffer index for receiving fragments.
+ * @skb_len: Buffer length for receiving fragments.
+ * @mib_read: Workqueue to read MIB counters.
+ * @mib_timer_info: Timer to read MIB counters.
+ * @counter: Used for MIB reading.
+ * @mtu: Current MTU used. The default is REGULAR_RX_BUF_SIZE;
+ * the maximum is MAX_RX_BUF_SIZE.
+ * @opened: Counter to keep track of device open.
+ * @rx_tasklet: Receive processing tasklet.
+ * @tx_tasklet: Transmit processing tasklet.
+ * @wol_enable: Wake-on-LAN enable set by ethtool.
+ * @wol_support: Wake-on-LAN support used by ethtool.
+ * @pme_wait: Used for KSZ8841 power management.
+ */
+struct dev_info {
+ struct net_device *dev;
+ struct pci_dev *pdev;
+
+ struct ksz_hw hw;
+ struct ksz_shared_mem desc_pool;
+
+ spinlock_t hwlock;
+ struct mutex lock;
+
+ int (*dev_rcv)(struct dev_info *);
+
+ struct sk_buff *last_skb;
+ int skb_index;
+ int skb_len;
+
+ struct work_struct mib_read;
+ struct ksz_timer_info mib_timer_info;
+ struct ksz_counter_info counter[TOTAL_PORT_NUM];
+
+ int mtu;
+ int opened;
+
+ struct tasklet_struct rx_tasklet;
+ struct tasklet_struct tx_tasklet;
+
+ int wol_enable;
+ int wol_support;
+ unsigned long pme_wait;
+};
+
+/**
+ * struct dev_priv - Network device private data structure
+ * @adapter: Adapter device information.
+ * @port: Port information.
+ * @monitor_time_info: Timer to monitor ports.
+ * @stats: Network statistics.
+ * @proc_sem: Semaphore for proc accessing.
+ * @id: Device ID.
+ * @mii_if: MII interface information.
+ * @advertising: Temporary variable to store advertised settings.
+ * @msg_enable: The message flags controlling driver output.
+ * @media_state: The connection status of the device.
+ * @multicast: The all multicast state of the device.
+ * @promiscuous: The promiscuous state of the device.
+ */
+struct dev_priv {
+ struct dev_info *adapter;
+ struct ksz_port port;
+ struct ksz_timer_info monitor_timer_info;
+ struct net_device_stats stats;
+
+ struct semaphore proc_sem;
+ int id;
+
+ struct mii_if_info mii_if;
+ u32 advertising;
+
+ u32 msg_enable;
+ int media_state;
+ int multicast;
+ int promiscuous;
+};
+
+#define ks_info(_ks, _msg...) dev_info(&(_ks)->pdev->dev, _msg)
+#define ks_warn(_ks, _msg...) dev_warn(&(_ks)->pdev->dev, _msg)
+#define ks_dbg(_ks, _msg...) dev_dbg(&(_ks)->pdev->dev, _msg)
+#define ks_err(_ks, _msg...) dev_err(&(_ks)->pdev->dev, _msg)
+
+#define DRV_NAME "KSZ884X PCI"
+#define DEVICE_NAME "KSZ884x PCI"
+#define DRV_VERSION "1.0.0"
+#define DRV_RELDATE "Feb 8, 2010"
+
+static char version[] __devinitdata =
+ "Micrel " DEVICE_NAME " " DRV_VERSION " (" DRV_RELDATE ")";
+
+static u8 DEFAULT_MAC_ADDRESS[] = { 0x00, 0x10, 0xA1, 0x88, 0x42, 0x01 };
+
+/*
+ * Interrupt processing primary routines
+ */
+
+static inline void hw_ack_intr(struct ksz_hw *hw, uint interrupt)
+{
+ writel(interrupt, hw->io + KS884X_INTERRUPTS_STATUS);
+}
+
+static inline void hw_dis_intr(struct ksz_hw *hw)
+{
+ hw->intr_blocked = hw->intr_mask;
+ writel(0, hw->io + KS884X_INTERRUPTS_ENABLE);
+ hw->intr_set = readl(hw->io + KS884X_INTERRUPTS_ENABLE);
+}
+
+static inline void hw_set_intr(struct ksz_hw *hw, uint interrupt)
+{
+ hw->intr_set = interrupt;
+ writel(interrupt, hw->io + KS884X_INTERRUPTS_ENABLE);
+}
+
+static inline void hw_ena_intr(struct ksz_hw *hw)
+{
+ hw->intr_blocked = 0;
+ hw_set_intr(hw, hw->intr_mask);
+}
+
+static inline void hw_dis_intr_bit(struct ksz_hw *hw, uint bit)
+{
+ hw->intr_mask &= ~(bit);
+}
+
+static inline void hw_turn_off_intr(struct ksz_hw *hw, uint interrupt)
+{
+ u32 read_intr;
+
+ read_intr = readl(hw->io + KS884X_INTERRUPTS_ENABLE);
+ hw->intr_set = read_intr & ~interrupt;
+ writel(hw->intr_set, hw->io + KS884X_INTERRUPTS_ENABLE);
+ hw_dis_intr_bit(hw, interrupt);
+}
+
+/**
+ * hw_turn_on_intr - turn on specified interrupts
+ * @hw: The hardware instance.
+ * @bit: The interrupt bits to be on.
+ *
+ * This routine turns on the specified interrupts in the interrupt mask so that
+ * those interrupts will be enabled.
+ */
+static void hw_turn_on_intr(struct ksz_hw *hw, u32 bit)
+{
+ hw->intr_mask |= bit;
+
+ if (!hw->intr_blocked)
+ hw_set_intr(hw, hw->intr_mask);
+}
+
+static inline void hw_ena_intr_bit(struct ksz_hw *hw, uint interrupt)
+{
+ u32 read_intr;
+
+ read_intr = readl(hw->io + KS884X_INTERRUPTS_ENABLE);
+ hw->intr_set = read_intr | interrupt;
+ writel(hw->intr_set, hw->io + KS884X_INTERRUPTS_ENABLE);
+}
+
+static inline void hw_read_intr(struct ksz_hw *hw, uint *status)
+{
+ *status = readl(hw->io + KS884X_INTERRUPTS_STATUS);
+ *status = *status & hw->intr_set;
+}
+
+static inline void hw_restore_intr(struct ksz_hw *hw, uint interrupt)
+{
+ if (interrupt)
+ hw_ena_intr(hw);
+}
+
+/**
+ * hw_block_intr - block hardware interrupts
+ *
+ * This function blocks all interrupts of the hardware and returns the current
+ * interrupt enable mask so that interrupts can be restored later.
+ *
+ * Return the current interrupt enable mask.
+ */
+static uint hw_block_intr(struct ksz_hw *hw)
+{
+ uint interrupt = 0;
+
+ if (!hw->intr_blocked) {
+ hw_dis_intr(hw);
+ interrupt = hw->intr_blocked;
+ }
+ return interrupt;
+}
+
+/*
+ * Hardware descriptor routines
+ */
+
+static inline void reset_desc(struct ksz_desc *desc, union desc_stat status)
+{
+ status.rx.hw_owned = 0;
+ desc->phw->ctrl.data = cpu_to_le32(status.data);
+}
+
+static inline void release_desc(struct ksz_desc *desc)
+{
+ desc->sw.ctrl.tx.hw_owned = 1;
+ if (desc->sw.buf_size != desc->sw.buf.data) {
+ desc->sw.buf_size = desc->sw.buf.data;
+ desc->phw->buf.data = cpu_to_le32(desc->sw.buf.data);
+ }
+ desc->phw->ctrl.data = cpu_to_le32(desc->sw.ctrl.data);
+}
+
+static void get_rx_pkt(struct ksz_desc_info *info, struct ksz_desc **desc)
+{
+ *desc = &info->ring[info->last];
+ info->last++;
+ info->last &= info->mask;
+ info->avail--;
+ (*desc)->sw.buf.data &= ~KS_DESC_RX_MASK;
+}
+
+static inline void set_rx_buf(struct ksz_desc *desc, u32 addr)
+{
+ desc->phw->addr = cpu_to_le32(addr);
+}
+
+static inline void set_rx_len(struct ksz_desc *desc, u32 len)
+{
+ desc->sw.buf.rx.buf_size = len;
+}
+
+static inline void get_tx_pkt(struct ksz_desc_info *info,
+ struct ksz_desc **desc)
+{
+ *desc = &info->ring[info->next];
+ info->next++;
+ info->next &= info->mask;
+ info->avail--;
+ (*desc)->sw.buf.data &= ~KS_DESC_TX_MASK;
+}
+
+static inline void set_tx_buf(struct ksz_desc *desc, u32 addr)
+{
+ desc->phw->addr = cpu_to_le32(addr);
+}
+
+static inline void set_tx_len(struct ksz_desc *desc, u32 len)
+{
+ desc->sw.buf.tx.buf_size = len;
+}
+
+/* Switch functions */
+
+#define TABLE_READ 0x10
+#define TABLE_SEL_SHIFT 2
+
+#define HW_DELAY(hw, reg) \
+ do { \
+ u16 dummy; \
+ dummy = readw(hw->io + reg); \
+ } while (0)
+
+/**
+ * sw_r_table - read 4 bytes of data from switch table
+ * @hw: The hardware instance.
+ * @table: The table selector.
+ * @addr: The address of the table entry.
+ * @data: Buffer to store the read data.
+ *
+ * This routine reads 4 bytes of data from the table of the switch.
+ * Hardware interrupts are disabled to minimize corruption of read data.
+ */
+static void sw_r_table(struct ksz_hw *hw, int table, u16 addr, u32 *data)
+{
+ u16 ctrl_addr;
+ uint interrupt;
+
+ ctrl_addr = (((table << TABLE_SEL_SHIFT) | TABLE_READ) << 8) | addr;
+
+ interrupt = hw_block_intr(hw);
+
+ writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET);
+ HW_DELAY(hw, KS884X_IACR_OFFSET);
+ *data = readl(hw->io + KS884X_ACC_DATA_0_OFFSET);
+
+ hw_restore_intr(hw, interrupt);
+}
+
+/**
+ * sw_w_table_64 - write 8 bytes of data to the switch table
+ * @hw: The hardware instance.
+ * @table: The table selector.
+ * @addr: The address of the table entry.
+ * @data_hi: The high part of data to be written (bit63 ~ bit32).
+ * @data_lo: The low part of data to be written (bit31 ~ bit0).
+ *
+ * This routine writes 8 bytes of data to the table of the switch.
+ * Hardware interrupts are disabled to minimize corruption of written data.
+ */
+static void sw_w_table_64(struct ksz_hw *hw, int table, u16 addr, u32 data_hi,
+ u32 data_lo)
+{
+ u16 ctrl_addr;
+ uint interrupt;
+
+ ctrl_addr = ((table << TABLE_SEL_SHIFT) << 8) | addr;
+
+ interrupt = hw_block_intr(hw);
+
+ writel(data_hi, hw->io + KS884X_ACC_DATA_4_OFFSET);
+ writel(data_lo, hw->io + KS884X_ACC_DATA_0_OFFSET);
+
+ writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET);
+ HW_DELAY(hw, KS884X_IACR_OFFSET);
+
+ hw_restore_intr(hw, interrupt);
+}
+
+/**
+ * sw_w_sta_mac_table - write to the static MAC table
+ * @hw: The hardware instance.
+ * @addr: The address of the table entry.
+ * @mac_addr: The MAC address.
+ * @ports: The port members.
+ * @override: The flag to override the port receive/transmit settings.
+ * @valid: The flag to indicate entry is valid.
+ * @use_fid: The flag to indicate the FID is valid.
+ * @fid: The FID value.
+ *
+ * This routine writes an entry of the static MAC table of the switch. It
+ * calls sw_w_table_64() to write the data.
+ */
+static void sw_w_sta_mac_table(struct ksz_hw *hw, u16 addr, u8 *mac_addr,
+ u8 ports, int override, int valid, int use_fid, u8 fid)
+{
+ u32 data_hi;
+ u32 data_lo;
+
+ data_lo = ((u32) mac_addr[2] << 24) |
+ ((u32) mac_addr[3] << 16) |
+ ((u32) mac_addr[4] << 8) | mac_addr[5];
+ data_hi = ((u32) mac_addr[0] << 8) | mac_addr[1];
+ data_hi |= (u32) ports << STATIC_MAC_FWD_PORTS_SHIFT;
+
+ if (override)
+ data_hi |= STATIC_MAC_TABLE_OVERRIDE;
+ if (use_fid) {
+ data_hi |= STATIC_MAC_TABLE_USE_FID;
+ data_hi |= (u32) fid << STATIC_MAC_FID_SHIFT;
+ }
+ if (valid)
+ data_hi |= STATIC_MAC_TABLE_VALID;
+
+ sw_w_table_64(hw, TABLE_STATIC_MAC, addr, data_hi, data_lo);
+}
+
+/**
+ * sw_r_vlan_table - read from the VLAN table
+ * @hw: The hardware instance.
+ * @addr: The address of the table entry.
+ * @vid: Buffer to store the VID.
+ * @fid: Buffer to store the VID.
+ * @member: Buffer to store the port membership.
+ *
+ * This function reads an entry of the VLAN table of the switch. It calls
+ * sw_r_table() to get the data.
+ *
+ * Return 0 if the entry is valid; otherwise -1.
+ */
+static int sw_r_vlan_table(struct ksz_hw *hw, u16 addr, u16 *vid, u8 *fid,
+ u8 *member)
+{
+ u32 data;
+
+ sw_r_table(hw, TABLE_VLAN, addr, &data);
+ if (data & VLAN_TABLE_VALID) {
+ *vid = (u16)(data & VLAN_TABLE_VID);
+ *fid = (u8)((data & VLAN_TABLE_FID) >> VLAN_TABLE_FID_SHIFT);
+ *member = (u8)((data & VLAN_TABLE_MEMBERSHIP) >>
+ VLAN_TABLE_MEMBERSHIP_SHIFT);
+ return 0;
+ }
+ return -1;
+}
+
+/**
+ * port_r_mib_cnt - read MIB counter
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @addr: The address of the counter.
+ * @cnt: Buffer to store the counter.
+ *
+ * This routine reads a MIB counter of the port.
+ * Hardware interrupts are disabled to minimize corruption of read data.
+ */
+static void port_r_mib_cnt(struct ksz_hw *hw, int port, u16 addr, u64 *cnt)
+{
+ u32 data;
+ u16 ctrl_addr;
+ uint interrupt;
+ int timeout;
+
+ ctrl_addr = addr + PORT_COUNTER_NUM * port;
+
+ interrupt = hw_block_intr(hw);
+
+ ctrl_addr |= (((TABLE_MIB << TABLE_SEL_SHIFT) | TABLE_READ) << 8);
+ writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET);
+ HW_DELAY(hw, KS884X_IACR_OFFSET);
+
+ for (timeout = 100; timeout > 0; timeout--) {
+ data = readl(hw->io + KS884X_ACC_DATA_0_OFFSET);
+
+ if (data & MIB_COUNTER_VALID) {
+ if (data & MIB_COUNTER_OVERFLOW)
+ *cnt += MIB_COUNTER_VALUE + 1;
+ *cnt += data & MIB_COUNTER_VALUE;
+ break;
+ }
+ }
+
+ hw_restore_intr(hw, interrupt);
+}
+
+/**
+ * port_r_mib_pkt - read dropped packet counts
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @cnt: Buffer to store the receive and transmit dropped packet counts.
+ *
+ * This routine reads the dropped packet counts of the port.
+ * Hardware interrupts are disabled to minimize corruption of read data.
+ */
+static void port_r_mib_pkt(struct ksz_hw *hw, int port, u32 *last, u64 *cnt)
+{
+ u32 cur;
+ u32 data;
+ u16 ctrl_addr;
+ uint interrupt;
+ int index;
+
+ index = KS_MIB_PACKET_DROPPED_RX_0 + port;
+ do {
+ interrupt = hw_block_intr(hw);
+
+ ctrl_addr = (u16) index;
+ ctrl_addr |= (((TABLE_MIB << TABLE_SEL_SHIFT) | TABLE_READ)
+ << 8);
+ writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET);
+ HW_DELAY(hw, KS884X_IACR_OFFSET);
+ data = readl(hw->io + KS884X_ACC_DATA_0_OFFSET);
+
+ hw_restore_intr(hw, interrupt);
+
+ data &= MIB_PACKET_DROPPED;
+ cur = *last;
+ if (data != cur) {
+ *last = data;
+ if (data < cur)
+ data += MIB_PACKET_DROPPED + 1;
+ data -= cur;
+ *cnt += data;
+ }
+ ++last;
+ ++cnt;
+ index -= KS_MIB_PACKET_DROPPED_TX -
+ KS_MIB_PACKET_DROPPED_TX_0 + 1;
+ } while (index >= KS_MIB_PACKET_DROPPED_TX_0 + port);
+}
+
+/**
+ * port_r_cnt - read MIB counters periodically
+ * @hw: The hardware instance.
+ * @port: The port index.
+ *
+ * This routine is used to read the counters of the port periodically to avoid
+ * counter overflow. The hardware should be acquired first before calling this
+ * routine.
+ *
+ * Return non-zero when not all counters not read.
+ */
+static int port_r_cnt(struct ksz_hw *hw, int port)
+{
+ struct ksz_port_mib *mib = &hw->port_mib[port];
+
+ if (mib->mib_start < PORT_COUNTER_NUM)
+ while (mib->cnt_ptr < PORT_COUNTER_NUM) {
+ port_r_mib_cnt(hw, port, mib->cnt_ptr,
+ &mib->counter[mib->cnt_ptr]);
+ ++mib->cnt_ptr;
+ }
+ if (hw->mib_cnt > PORT_COUNTER_NUM)
+ port_r_mib_pkt(hw, port, mib->dropped,
+ &mib->counter[PORT_COUNTER_NUM]);
+ mib->cnt_ptr = 0;
+ return 0;
+}
+
+/**
+ * port_init_cnt - initialize MIB counter values
+ * @hw: The hardware instance.
+ * @port: The port index.
+ *
+ * This routine is used to initialize all counters to zero if the hardware
+ * cannot do it after reset.
+ */
+static void port_init_cnt(struct ksz_hw *hw, int port)
+{
+ struct ksz_port_mib *mib = &hw->port_mib[port];
+
+ mib->cnt_ptr = 0;
+ if (mib->mib_start < PORT_COUNTER_NUM)
+ do {
+ port_r_mib_cnt(hw, port, mib->cnt_ptr,
+ &mib->counter[mib->cnt_ptr]);
+ ++mib->cnt_ptr;
+ } while (mib->cnt_ptr < PORT_COUNTER_NUM);
+ if (hw->mib_cnt > PORT_COUNTER_NUM)
+ port_r_mib_pkt(hw, port, mib->dropped,
+ &mib->counter[PORT_COUNTER_NUM]);
+ memset((void *) mib->counter, 0, sizeof(u64) * TOTAL_PORT_COUNTER_NUM);
+ mib->cnt_ptr = 0;
+}
+
+/*
+ * Port functions
+ */
+
+/**
+ * port_chk - check port register bits
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @offset: The offset of the port register.
+ * @bits: The data bits to check.
+ *
+ * This function checks whether the specified bits of the port register are set
+ * or not.
+ *
+ * Return 0 if the bits are not set.
+ */
+static int port_chk(struct ksz_hw *hw, int port, int offset, u16 bits)
+{
+ u32 addr;
+ u16 data;
+
+ PORT_CTRL_ADDR(port, addr);
+ addr += offset;
+ data = readw(hw->io + addr);
+ return (data & bits) == bits;
+}
+
+/**
+ * port_cfg - set port register bits
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @offset: The offset of the port register.
+ * @bits: The data bits to set.
+ * @set: The flag indicating whether the bits are to be set or not.
+ *
+ * This routine sets or resets the specified bits of the port register.
+ */
+static void port_cfg(struct ksz_hw *hw, int port, int offset, u16 bits,
+ int set)
+{
+ u32 addr;
+ u16 data;
+
+ PORT_CTRL_ADDR(port, addr);
+ addr += offset;
+ data = readw(hw->io + addr);
+ if (set)
+ data |= bits;
+ else
+ data &= ~bits;
+ writew(data, hw->io + addr);
+}
+
+/**
+ * port_chk_shift - check port bit
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @offset: The offset of the register.
+ * @shift: Number of bits to shift.
+ *
+ * This function checks whether the specified port is set in the register or
+ * not.
+ *
+ * Return 0 if the port is not set.
+ */
+static int port_chk_shift(struct ksz_hw *hw, int port, u32 addr, int shift)
+{
+ u16 data;
+ u16 bit = 1 << port;
+
+ data = readw(hw->io + addr);
+ data >>= shift;
+ return (data & bit) == bit;
+}
+
+/**
+ * port_cfg_shift - set port bit
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @offset: The offset of the register.
+ * @shift: Number of bits to shift.
+ * @set: The flag indicating whether the port is to be set or not.
+ *
+ * This routine sets or resets the specified port in the register.
+ */
+static void port_cfg_shift(struct ksz_hw *hw, int port, u32 addr, int shift,
+ int set)
+{
+ u16 data;
+ u16 bits = 1 << port;
+
+ data = readw(hw->io + addr);
+ bits <<= shift;
+ if (set)
+ data |= bits;
+ else
+ data &= ~bits;
+ writew(data, hw->io + addr);
+}
+
+/**
+ * port_r8 - read byte from port register
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @offset: The offset of the port register.
+ * @data: Buffer to store the data.
+ *
+ * This routine reads a byte from the port register.
+ */
+static void port_r8(struct ksz_hw *hw, int port, int offset, u8 *data)
+{
+ u32 addr;
+
+ PORT_CTRL_ADDR(port, addr);
+ addr += offset;
+ *data = readb(hw->io + addr);
+}
+
+/**
+ * port_r16 - read word from port register.
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @offset: The offset of the port register.
+ * @data: Buffer to store the data.
+ *
+ * This routine reads a word from the port register.
+ */
+static void port_r16(struct ksz_hw *hw, int port, int offset, u16 *data)
+{
+ u32 addr;
+
+ PORT_CTRL_ADDR(port, addr);
+ addr += offset;
+ *data = readw(hw->io + addr);
+}
+
+/**
+ * port_w16 - write word to port register.
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @offset: The offset of the port register.
+ * @data: Data to write.
+ *
+ * This routine writes a word to the port register.
+ */
+static void port_w16(struct ksz_hw *hw, int port, int offset, u16 data)
+{
+ u32 addr;
+
+ PORT_CTRL_ADDR(port, addr);
+ addr += offset;
+ writew(data, hw->io + addr);
+}
+
+/**
+ * sw_chk - check switch register bits
+ * @hw: The hardware instance.
+ * @addr: The address of the switch register.
+ * @bits: The data bits to check.
+ *
+ * This function checks whether the specified bits of the switch register are
+ * set or not.
+ *
+ * Return 0 if the bits are not set.
+ */
+static int sw_chk(struct ksz_hw *hw, u32 addr, u16 bits)
+{
+ u16 data;
+
+ data = readw(hw->io + addr);
+ return (data & bits) == bits;
+}
+
+/**
+ * sw_cfg - set switch register bits
+ * @hw: The hardware instance.
+ * @addr: The address of the switch register.
+ * @bits: The data bits to set.
+ * @set: The flag indicating whether the bits are to be set or not.
+ *
+ * This function sets or resets the specified bits of the switch register.
+ */
+static void sw_cfg(struct ksz_hw *hw, u32 addr, u16 bits, int set)
+{
+ u16 data;
+
+ data = readw(hw->io + addr);
+ if (set)
+ data |= bits;
+ else
+ data &= ~bits;
+ writew(data, hw->io + addr);
+}
+
+/* Bandwidth */
+
+static inline void port_cfg_broad_storm(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_1_OFFSET, PORT_BROADCAST_STORM, set);
+}
+
+static inline int port_chk_broad_storm(struct ksz_hw *hw, int p)
+{
+ return port_chk(hw, p,
+ KS8842_PORT_CTRL_1_OFFSET, PORT_BROADCAST_STORM);
+}
+
+/* Driver set switch broadcast storm protection at 10% rate. */
+#define BROADCAST_STORM_PROTECTION_RATE 10
+
+/* 148,800 frames * 67 ms / 100 */
+#define BROADCAST_STORM_VALUE 9969
+
+/**
+ * sw_cfg_broad_storm - configure broadcast storm threshold
+ * @hw: The hardware instance.
+ * @percent: Broadcast storm threshold in percent of transmit rate.
+ *
+ * This routine configures the broadcast storm threshold of the switch.
+ */
+static void sw_cfg_broad_storm(struct ksz_hw *hw, u8 percent)
+{
+ u16 data;
+ u32 value = ((u32) BROADCAST_STORM_VALUE * (u32) percent / 100);
+
+ if (value > BROADCAST_STORM_RATE)
+ value = BROADCAST_STORM_RATE;
+
+ data = readw(hw->io + KS8842_SWITCH_CTRL_3_OFFSET);
+ data &= ~(BROADCAST_STORM_RATE_LO | BROADCAST_STORM_RATE_HI);
+ data |= ((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8);
+ writew(data, hw->io + KS8842_SWITCH_CTRL_3_OFFSET);
+}
+
+/**
+ * sw_get_board_storm - get broadcast storm threshold
+ * @hw: The hardware instance.
+ * @percent: Buffer to store the broadcast storm threshold percentage.
+ *
+ * This routine retrieves the broadcast storm threshold of the switch.
+ */
+static void sw_get_broad_storm(struct ksz_hw *hw, u8 *percent)
+{
+ int num;
+ u16 data;
+
+ data = readw(hw->io + KS8842_SWITCH_CTRL_3_OFFSET);
+ num = (data & BROADCAST_STORM_RATE_HI);
+ num <<= 8;
+ num |= (data & BROADCAST_STORM_RATE_LO) >> 8;
+ num = (num * 100 + BROADCAST_STORM_VALUE / 2) / BROADCAST_STORM_VALUE;
+ *percent = (u8) num;
+}
+
+/**
+ * sw_dis_broad_storm - disable broadstorm
+ * @hw: The hardware instance.
+ * @port: The port index.
+ *
+ * This routine disables the broadcast storm limit function of the switch.
+ */
+static void sw_dis_broad_storm(struct ksz_hw *hw, int port)
+{
+ port_cfg_broad_storm(hw, port, 0);
+}
+
+/**
+ * sw_ena_broad_storm - enable broadcast storm
+ * @hw: The hardware instance.
+ * @port: The port index.
+ *
+ * This routine enables the broadcast storm limit function of the switch.
+ */
+static void sw_ena_broad_storm(struct ksz_hw *hw, int port)
+{
+ sw_cfg_broad_storm(hw, hw->ksz_switch->broad_per);
+ port_cfg_broad_storm(hw, port, 1);
+}
+
+/**
+ * sw_init_broad_storm - initialize broadcast storm
+ * @hw: The hardware instance.
+ *
+ * This routine initializes the broadcast storm limit function of the switch.
+ */
+static void sw_init_broad_storm(struct ksz_hw *hw)
+{
+ int port;
+
+ hw->ksz_switch->broad_per = 1;
+ sw_cfg_broad_storm(hw, hw->ksz_switch->broad_per);
+ for (port = 0; port < TOTAL_PORT_NUM; port++)
+ sw_dis_broad_storm(hw, port);
+ sw_cfg(hw, KS8842_SWITCH_CTRL_2_OFFSET, MULTICAST_STORM_DISABLE, 1);
+}
+
+/**
+ * hw_cfg_broad_storm - configure broadcast storm
+ * @hw: The hardware instance.
+ * @percent: Broadcast storm threshold in percent of transmit rate.
+ *
+ * This routine configures the broadcast storm threshold of the switch.
+ * It is called by user functions. The hardware should be acquired first.
+ */
+static void hw_cfg_broad_storm(struct ksz_hw *hw, u8 percent)
+{
+ if (percent > 100)
+ percent = 100;
+
+ sw_cfg_broad_storm(hw, percent);
+ sw_get_broad_storm(hw, &percent);
+ hw->ksz_switch->broad_per = percent;
+}
+
+/**
+ * sw_dis_prio_rate - disable switch priority rate
+ * @hw: The hardware instance.
+ * @port: The port index.
+ *
+ * This routine disables the priority rate function of the switch.
+ */
+static void sw_dis_prio_rate(struct ksz_hw *hw, int port)
+{
+ u32 addr;
+
+ PORT_CTRL_ADDR(port, addr);
+ addr += KS8842_PORT_IN_RATE_OFFSET;
+ writel(0, hw->io + addr);
+}
+
+/**
+ * sw_init_prio_rate - initialize switch prioirty rate
+ * @hw: The hardware instance.
+ *
+ * This routine initializes the priority rate function of the switch.
+ */
+static void sw_init_prio_rate(struct ksz_hw *hw)
+{
+ int port;
+ int prio;
+ struct ksz_switch *sw = hw->ksz_switch;
+
+ for (port = 0; port < TOTAL_PORT_NUM; port++) {
+ for (prio = 0; prio < PRIO_QUEUES; prio++) {
+ sw->port_cfg[port].rx_rate[prio] =
+ sw->port_cfg[port].tx_rate[prio] = 0;
+ }
+ sw_dis_prio_rate(hw, port);
+ }
+}
+
+/* Communication */
+
+static inline void port_cfg_back_pressure(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_BACK_PRESSURE, set);
+}
+
+static inline void port_cfg_force_flow_ctrl(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_FORCE_FLOW_CTRL, set);
+}
+
+static inline int port_chk_back_pressure(struct ksz_hw *hw, int p)
+{
+ return port_chk(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_BACK_PRESSURE);
+}
+
+static inline int port_chk_force_flow_ctrl(struct ksz_hw *hw, int p)
+{
+ return port_chk(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_FORCE_FLOW_CTRL);
+}
+
+/* Spanning Tree */
+
+static inline void port_cfg_dis_learn(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_LEARN_DISABLE, set);
+}
+
+static inline void port_cfg_rx(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_RX_ENABLE, set);
+}
+
+static inline void port_cfg_tx(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_TX_ENABLE, set);
+}
+
+static inline void sw_cfg_fast_aging(struct ksz_hw *hw, int set)
+{
+ sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET, SWITCH_FAST_AGING, set);
+}
+
+static inline void sw_flush_dyn_mac_table(struct ksz_hw *hw)
+{
+ if (!(hw->overrides & FAST_AGING)) {
+ sw_cfg_fast_aging(hw, 1);
+ mdelay(1);
+ sw_cfg_fast_aging(hw, 0);
+ }
+}
+
+/* VLAN */
+
+static inline void port_cfg_ins_tag(struct ksz_hw *hw, int p, int insert)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_1_OFFSET, PORT_INSERT_TAG, insert);
+}
+
+static inline void port_cfg_rmv_tag(struct ksz_hw *hw, int p, int remove)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_1_OFFSET, PORT_REMOVE_TAG, remove);
+}
+
+static inline int port_chk_ins_tag(struct ksz_hw *hw, int p)
+{
+ return port_chk(hw, p,
+ KS8842_PORT_CTRL_1_OFFSET, PORT_INSERT_TAG);
+}
+
+static inline int port_chk_rmv_tag(struct ksz_hw *hw, int p)
+{
+ return port_chk(hw, p,
+ KS8842_PORT_CTRL_1_OFFSET, PORT_REMOVE_TAG);
+}
+
+static inline void port_cfg_dis_non_vid(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_DISCARD_NON_VID, set);
+}
+
+static inline void port_cfg_in_filter(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_INGRESS_VLAN_FILTER, set);
+}
+
+static inline int port_chk_dis_non_vid(struct ksz_hw *hw, int p)
+{
+ return port_chk(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_DISCARD_NON_VID);
+}
+
+static inline int port_chk_in_filter(struct ksz_hw *hw, int p)
+{
+ return port_chk(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_INGRESS_VLAN_FILTER);
+}
+
+/* Mirroring */
+
+static inline void port_cfg_mirror_sniffer(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_MIRROR_SNIFFER, set);
+}
+
+static inline void port_cfg_mirror_rx(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_MIRROR_RX, set);
+}
+
+static inline void port_cfg_mirror_tx(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_MIRROR_TX, set);
+}
+
+static inline void sw_cfg_mirror_rx_tx(struct ksz_hw *hw, int set)
+{
+ sw_cfg(hw, KS8842_SWITCH_CTRL_2_OFFSET, SWITCH_MIRROR_RX_TX, set);
+}
+
+static void sw_init_mirror(struct ksz_hw *hw)
+{
+ int port;
+
+ for (port = 0; port < TOTAL_PORT_NUM; port++) {
+ port_cfg_mirror_sniffer(hw, port, 0);
+ port_cfg_mirror_rx(hw, port, 0);
+ port_cfg_mirror_tx(hw, port, 0);
+ }
+ sw_cfg_mirror_rx_tx(hw, 0);
+}
+
+static inline void sw_cfg_unk_def_deliver(struct ksz_hw *hw, int set)
+{
+ sw_cfg(hw, KS8842_SWITCH_CTRL_7_OFFSET,
+ SWITCH_UNK_DEF_PORT_ENABLE, set);
+}
+
+static inline int sw_cfg_chk_unk_def_deliver(struct ksz_hw *hw)
+{
+ return sw_chk(hw, KS8842_SWITCH_CTRL_7_OFFSET,
+ SWITCH_UNK_DEF_PORT_ENABLE);
+}
+
+static inline void sw_cfg_unk_def_port(struct ksz_hw *hw, int port, int set)
+{
+ port_cfg_shift(hw, port, KS8842_SWITCH_CTRL_7_OFFSET, 0, set);
+}
+
+static inline int sw_chk_unk_def_port(struct ksz_hw *hw, int port)
+{
+ return port_chk_shift(hw, port, KS8842_SWITCH_CTRL_7_OFFSET, 0);
+}
+
+/* Priority */
+
+static inline void port_cfg_diffserv(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_1_OFFSET, PORT_DIFFSERV_ENABLE, set);
+}
+
+static inline void port_cfg_802_1p(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_1_OFFSET, PORT_802_1P_ENABLE, set);
+}
+
+static inline void port_cfg_replace_vid(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_USER_PRIORITY_CEILING, set);
+}
+
+static inline void port_cfg_prio(struct ksz_hw *hw, int p, int set)
+{
+ port_cfg(hw, p,
+ KS8842_PORT_CTRL_1_OFFSET, PORT_PRIO_QUEUE_ENABLE, set);
+}
+
+static inline int port_chk_diffserv(struct ksz_hw *hw, int p)
+{
+ return port_chk(hw, p,
+ KS8842_PORT_CTRL_1_OFFSET, PORT_DIFFSERV_ENABLE);
+}
+
+static inline int port_chk_802_1p(struct ksz_hw *hw, int p)
+{
+ return port_chk(hw, p,
+ KS8842_PORT_CTRL_1_OFFSET, PORT_802_1P_ENABLE);
+}
+
+static inline int port_chk_replace_vid(struct ksz_hw *hw, int p)
+{
+ return port_chk(hw, p,
+ KS8842_PORT_CTRL_2_OFFSET, PORT_USER_PRIORITY_CEILING);
+}
+
+static inline int port_chk_prio(struct ksz_hw *hw, int p)
+{
+ return port_chk(hw, p,
+ KS8842_PORT_CTRL_1_OFFSET, PORT_PRIO_QUEUE_ENABLE);
+}
+
+/**
+ * sw_dis_diffserv - disable switch DiffServ priority
+ * @hw: The hardware instance.
+ * @port: The port index.
+ *
+ * This routine disables the DiffServ priority function of the switch.
+ */
+static void sw_dis_diffserv(struct ksz_hw *hw, int port)
+{
+ port_cfg_diffserv(hw, port, 0);
+}
+
+/**
+ * sw_dis_802_1p - disable switch 802.1p priority
+ * @hw: The hardware instance.
+ * @port: The port index.
+ *
+ * This routine disables the 802.1p priority function of the switch.
+ */
+static void sw_dis_802_1p(struct ksz_hw *hw, int port)
+{
+ port_cfg_802_1p(hw, port, 0);
+}
+
+/**
+ * sw_cfg_replace_null_vid -
+ * @hw: The hardware instance.
+ * @set: The flag to disable or enable.
+ *
+ */
+static void sw_cfg_replace_null_vid(struct ksz_hw *hw, int set)
+{
+ sw_cfg(hw, KS8842_SWITCH_CTRL_3_OFFSET, SWITCH_REPLACE_NULL_VID, set);
+}
+
+/**
+ * sw_cfg_replace_vid - enable switch 802.10 priority re-mapping
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @set: The flag to disable or enable.
+ *
+ * This routine enables the 802.1p priority re-mapping function of the switch.
+ * That allows 802.1p priority field to be replaced with the port's default
+ * tag's priority value if the ingress packet's 802.1p priority has a higher
+ * priority than port's default tag's priority.
+ */
+static void sw_cfg_replace_vid(struct ksz_hw *hw, int port, int set)
+{
+ port_cfg_replace_vid(hw, port, set);
+}
+
+/**
+ * sw_cfg_port_based - configure switch port based priority
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @prio: The priority to set.
+ *
+ * This routine configures the port based priority of the switch.
+ */
+static void sw_cfg_port_based(struct ksz_hw *hw, int port, u8 prio)
+{
+ u16 data;
+
+ if (prio > PORT_BASED_PRIORITY_BASE)
+ prio = PORT_BASED_PRIORITY_BASE;
+
+ hw->ksz_switch->port_cfg[port].port_prio = prio;
+
+ port_r16(hw, port, KS8842_PORT_CTRL_1_OFFSET, &data);
+ data &= ~PORT_BASED_PRIORITY_MASK;
+ data |= prio << PORT_BASED_PRIORITY_SHIFT;
+ port_w16(hw, port, KS8842_PORT_CTRL_1_OFFSET, data);
+}
+
+/**
+ * sw_dis_multi_queue - disable transmit multiple queues
+ * @hw: The hardware instance.
+ * @port: The port index.
+ *
+ * This routine disables the transmit multiple queues selection of the switch
+ * port. Only single transmit queue on the port.
+ */
+static void sw_dis_multi_queue(struct ksz_hw *hw, int port)
+{
+ port_cfg_prio(hw, port, 0);
+}
+
+/**
+ * sw_init_prio - initialize switch priority
+ * @hw: The hardware instance.
+ *
+ * This routine initializes the switch QoS priority functions.
+ */
+static void sw_init_prio(struct ksz_hw *hw)
+{
+ int port;
+ int tos;
+ struct ksz_switch *sw = hw->ksz_switch;
+
+ /*
+ * Init all the 802.1p tag priority value to be assigned to different
+ * priority queue.
+ */
+ sw->p_802_1p[0] = 0;
+ sw->p_802_1p[1] = 0;
+ sw->p_802_1p[2] = 1;
+ sw->p_802_1p[3] = 1;
+ sw->p_802_1p[4] = 2;
+ sw->p_802_1p[5] = 2;
+ sw->p_802_1p[6] = 3;
+ sw->p_802_1p[7] = 3;
+
+ /*
+ * Init all the DiffServ priority value to be assigned to priority
+ * queue 0.
+ */
+ for (tos = 0; tos < DIFFSERV_ENTRIES; tos++)
+ sw->diffserv[tos] = 0;
+
+ /* All QoS functions disabled. */
+ for (port = 0; port < TOTAL_PORT_NUM; port++) {
+ sw_dis_multi_queue(hw, port);
+ sw_dis_diffserv(hw, port);
+ sw_dis_802_1p(hw, port);
+ sw_cfg_replace_vid(hw, port, 0);
+
+ sw->port_cfg[port].port_prio = 0;
+ sw_cfg_port_based(hw, port, sw->port_cfg[port].port_prio);
+ }
+ sw_cfg_replace_null_vid(hw, 0);
+}
+
+/**
+ * port_get_def_vid - get port default VID.
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @vid: Buffer to store the VID.
+ *
+ * This routine retrieves the default VID of the port.
+ */
+static void port_get_def_vid(struct ksz_hw *hw, int port, u16 *vid)
+{
+ u32 addr;
+
+ PORT_CTRL_ADDR(port, addr);
+ addr += KS8842_PORT_CTRL_VID_OFFSET;
+ *vid = readw(hw->io + addr);
+}
+
+/**
+ * sw_init_vlan - initialize switch VLAN
+ * @hw: The hardware instance.
+ *
+ * This routine initializes the VLAN function of the switch.
+ */
+static void sw_init_vlan(struct ksz_hw *hw)
+{
+ int port;
+ int entry;
+ struct ksz_switch *sw = hw->ksz_switch;
+
+ /* Read 16 VLAN entries from device's VLAN table. */
+ for (entry = 0; entry < VLAN_TABLE_ENTRIES; entry++) {
+ sw_r_vlan_table(hw, entry,
+ &sw->vlan_table[entry].vid,
+ &sw->vlan_table[entry].fid,
+ &sw->vlan_table[entry].member);
+ }
+
+ for (port = 0; port < TOTAL_PORT_NUM; port++) {
+ port_get_def_vid(hw, port, &sw->port_cfg[port].vid);
+ sw->port_cfg[port].member = PORT_MASK;
+ }
+}
+
+/**
+ * sw_cfg_port_base_vlan - configure port-based VLAN membership
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @member: The port-based VLAN membership.
+ *
+ * This routine configures the port-based VLAN membership of the port.
+ */
+static void sw_cfg_port_base_vlan(struct ksz_hw *hw, int port, u8 member)
+{
+ u32 addr;
+ u8 data;
+
+ PORT_CTRL_ADDR(port, addr);
+ addr += KS8842_PORT_CTRL_2_OFFSET;
+
+ data = readb(hw->io + addr);
+ data &= ~PORT_VLAN_MEMBERSHIP;
+ data |= (member & PORT_MASK);
+ writeb(data, hw->io + addr);
+
+ hw->ksz_switch->port_cfg[port].member = member;
+}
+
+/**
+ * sw_get_addr - get the switch MAC address.
+ * @hw: The hardware instance.
+ * @mac_addr: Buffer to store the MAC address.
+ *
+ * This function retrieves the MAC address of the switch.
+ */
+static inline void sw_get_addr(struct ksz_hw *hw, u8 *mac_addr)
+{
+ int i;
+
+ for (i = 0; i < 6; i += 2) {
+ mac_addr[i] = readb(hw->io + KS8842_MAC_ADDR_0_OFFSET + i);
+ mac_addr[1 + i] = readb(hw->io + KS8842_MAC_ADDR_1_OFFSET + i);
+ }
+}
+
+/**
+ * sw_set_addr - configure switch MAC address
+ * @hw: The hardware instance.
+ * @mac_addr: The MAC address.
+ *
+ * This function configures the MAC address of the switch.
+ */
+static void sw_set_addr(struct ksz_hw *hw, u8 *mac_addr)
+{
+ int i;
+
+ for (i = 0; i < 6; i += 2) {
+ writeb(mac_addr[i], hw->io + KS8842_MAC_ADDR_0_OFFSET + i);
+ writeb(mac_addr[1 + i], hw->io + KS8842_MAC_ADDR_1_OFFSET + i);
+ }
+}
+
+/**
+ * sw_set_global_ctrl - set switch global control
+ * @hw: The hardware instance.
+ *
+ * This routine sets the global control of the switch function.
+ */
+static void sw_set_global_ctrl(struct ksz_hw *hw)
+{
+ u16 data;
+
+ /* Enable switch MII flow control. */
+ data = readw(hw->io + KS8842_SWITCH_CTRL_3_OFFSET);
+ data |= SWITCH_FLOW_CTRL;
+ writew(data, hw->io + KS8842_SWITCH_CTRL_3_OFFSET);
+
+ data = readw(hw->io + KS8842_SWITCH_CTRL_1_OFFSET);
+
+ /* Enable aggressive back off algorithm in half duplex mode. */
+ data |= SWITCH_AGGR_BACKOFF;
+
+ /* Enable automatic fast aging when link changed detected. */
+ data |= SWITCH_AGING_ENABLE;
+ data |= SWITCH_LINK_AUTO_AGING;
+
+ if (hw->overrides & FAST_AGING)
+ data |= SWITCH_FAST_AGING;
+ else
+ data &= ~SWITCH_FAST_AGING;
+ writew(data, hw->io + KS8842_SWITCH_CTRL_1_OFFSET);
+
+ data = readw(hw->io + KS8842_SWITCH_CTRL_2_OFFSET);
+
+ /* Enable no excessive collision drop. */
+ data |= NO_EXC_COLLISION_DROP;
+ writew(data, hw->io + KS8842_SWITCH_CTRL_2_OFFSET);
+}
+
+enum {
+ STP_STATE_DISABLED = 0,
+ STP_STATE_LISTENING,
+ STP_STATE_LEARNING,
+ STP_STATE_FORWARDING,
+ STP_STATE_BLOCKED,
+ STP_STATE_SIMPLE
+};
+
+/**
+ * port_set_stp_state - configure port spanning tree state
+ * @hw: The hardware instance.
+ * @port: The port index.
+ * @state: The spanning tree state.
+ *
+ * This routine configures the spanning tree state of the port.
+ */
+static void port_set_stp_state(struct ksz_hw *hw, int port, int state)
+{
+ u16 data;
+
+ port_r16(hw, port, KS8842_PORT_CTRL_2_OFFSET, &data);
+ switch (state) {
+ case STP_STATE_DISABLED:
+ data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE);
+ data |= PORT_LEARN_DISABLE;
+ break;
+ case STP_STATE_LISTENING:
+/*
+ * No need to turn on transmit because of port direct mode.
+ * Turning on receive is required if static MAC table is not setup.
+ */
+ data &= ~PORT_TX_ENABLE;
+ data |= PORT_RX_ENABLE;
+ data |= PORT_LEARN_DISABLE;
+ break;
+ case STP_STATE_LEARNING:
+ data &= ~PORT_TX_ENABLE;
+ data |= PORT_RX_ENABLE;
+ data &= ~PORT_LEARN_DISABLE;
+ break;
+ case STP_STATE_FORWARDING:
+ data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
+ data &= ~PORT_LEARN_DISABLE;
+ break;
+ case STP_STATE_BLOCKED:
+/*
+ * Need to setup static MAC table with override to keep receiving BPDU
+ * messages. See sw_init_stp routine.
+ */
+ data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE);
+ data |= PORT_LEARN_DISABLE;
+ break;
+ case STP_STATE_SIMPLE:
+ data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
+ data |= PORT_LEARN_DISABLE;
+ break;
+ }
+ port_w16(hw, port, KS8842_PORT_CTRL_2_OFFSET, data);
+ hw->ksz_switch->port_cfg[port].stp_state = state;
+}
+
+#define STP_ENTRY 0
+#define BROADCAST_ENTRY 1
+#define BRIDGE_ADDR_ENTRY 2
+#define IPV6_ADDR_ENTRY 3
+
+/**
+ * sw_clr_sta_mac_table - clear static MAC table
+ * @hw: The hardware instance.
+ *
+ * This routine clears the static MAC table.
+ */
+static void sw_clr_sta_mac_table(struct ksz_hw *hw)
+{
+ struct ksz_mac_table *entry;
+ int i;
+
+ for (i = 0; i < STATIC_MAC_TABLE_ENTRIES; i++) {
+ entry = &hw->ksz_switch->mac_table[i];
+ sw_w_sta_mac_table(hw, i,
+ entry->mac_addr, entry->ports,
+ entry->override, 0,
+ entry->use_fid, entry->fid);
+ }
+}
+
+/**
+ * sw_init_stp - initialize switch spanning tree support
+ * @hw: The hardware instance.
+ *
+ * This routine initializes the spanning tree support of the switch.
+ */
+static void sw_init_stp(struct ksz_hw *hw)
+{
+ struct ksz_mac_table *entry;
+
+ entry = &hw->ksz_switch->mac_table[STP_ENTRY];
+ entry->mac_addr[0] = 0x01;
+ entry->mac_addr[1] = 0x80;
+ entry->mac_addr[2] = 0xC2;
+ entry->mac_addr[3] = 0x00;
+ entry->mac_addr[4] = 0x00;
+ entry->mac_addr[5] = 0x00;
+ entry->ports = HOST_MASK;
+ entry->override = 1;
+ entry->valid = 1;
+ sw_w_sta_mac_table(hw, STP_ENTRY,
+ entry->mac_addr, entry->ports,
+ entry->override, entry->valid,
+ entry->use_fid, entry->fid);
+}
+
+/**
+ * sw_block_addr - block certain packets from the host port
+ * @hw: The hardware instance.
+ *
+ * This routine blocks certain packets from reaching to the host port.
+ */
+static void sw_block_addr(struct ksz_hw *hw)
+{
+ struct ksz_mac_table *entry;
+ int i;
+
+ for (i = BROADCAST_ENTRY; i <= IPV6_ADDR_ENTRY; i++) {
+ entry = &hw->ksz_switch->mac_table[i];
+ entry->valid = 0;
+ sw_w_sta_mac_table(hw, i,
+ entry->mac_addr, entry->ports,
+ entry->override, entry->valid,
+ entry->use_fid, entry->fid);
+ }
+}
+
+#define PHY_LINK_SUPPORT \
+ (PHY_AUTO_NEG_ASYM_PAUSE | \
+ PHY_AUTO_NEG_SYM_PAUSE | \
+ PHY_AUTO_NEG_100BT4 | \
+ PHY_AUTO_NEG_100BTX_FD | \
+ PHY_AUTO_NEG_100BTX | \
+ PHY_AUTO_NEG_10BT_FD | \
+ PHY_AUTO_NEG_10BT)
+
+static inline void hw_r_phy_ctrl(struct ksz_hw *hw, int phy, u16 *data)
+{
+ *data = readw(hw->io + phy + KS884X_PHY_CTRL_OFFSET);
+}
+
+static inline void hw_w_phy_ctrl(struct ksz_hw *hw, int phy, u16 data)
+{
+ writew(data, hw->io + phy + KS884X_PHY_CTRL_OFFSET);
+}
+
+static inline void hw_r_phy_link_stat(struct ksz_hw *hw, int phy, u16 *data)
+{
+ *data = readw(hw->io + phy + KS884X_PHY_STATUS_OFFSET);
+}
+
+static inline void hw_r_phy_auto_neg(struct ksz_hw *hw, int phy, u16 *data)
+{
+ *data = readw(hw->io + phy + KS884X_PHY_AUTO_NEG_OFFSET);
+}
+
+static inline void hw_w_phy_auto_neg(struct ksz_hw *hw, int phy, u16 data)
+{
+ writew(data, hw->io + phy + KS884X_PHY_AUTO_NEG_OFFSET);
+}
+
+static inline void hw_r_phy_rem_cap(struct ksz_hw *hw, int phy, u16 *data)
+{
+ *data = readw(hw->io + phy + KS884X_PHY_REMOTE_CAP_OFFSET);
+}
+
+static inline void hw_r_phy_crossover(struct ksz_hw *hw, int phy, u16 *data)
+{
+ *data = readw(hw->io + phy + KS884X_PHY_CTRL_OFFSET);
+}
+
+static inline void hw_w_phy_crossover(struct ksz_hw *hw, int phy, u16 data)
+{
+ writew(data, hw->io + phy + KS884X_PHY_CTRL_OFFSET);
+}
+
+static inline void hw_r_phy_polarity(struct ksz_hw *hw, int phy, u16 *data)
+{
+ *data = readw(hw->io + phy + KS884X_PHY_PHY_CTRL_OFFSET);
+}
+
+static inline void hw_w_phy_polarity(struct ksz_hw *hw, int phy, u16 data)
+{
+ writew(data, hw->io + phy + KS884X_PHY_PHY_CTRL_OFFSET);
+}
+
+static inline void hw_r_phy_link_md(struct ksz_hw *hw, int phy, u16 *data)
+{
+ *data = readw(hw->io + phy + KS884X_PHY_LINK_MD_OFFSET);
+}
+
+static inline void hw_w_phy_link_md(struct ksz_hw *hw, int phy, u16 data)
+{
+ writew(data, hw->io + phy + KS884X_PHY_LINK_MD_OFFSET);
+}
+
+/**
+ * hw_r_phy - read data from PHY register
+ * @hw: The hardware instance.
+ * @port: Port to read.
+ * @reg: PHY register to read.
+ * @val: Buffer to store the read data.
+ *
+ * This routine reads data from the PHY register.
+ */
+static void hw_r_phy(struct ksz_hw *hw, int port, u16 reg, u16 *val)
+{
+ int phy;
+
+ phy = KS884X_PHY_1_CTRL_OFFSET + port * PHY_CTRL_INTERVAL + reg;
+ *val = readw(hw->io + phy);
+}
+
+/**
+ * port_w_phy - write data to PHY register
+ * @hw: The hardware instance.
+ * @port: Port to write.
+ * @reg: PHY register to write.
+ * @val: Word data to write.
+ *
+ * This routine writes data to the PHY register.
+ */
+static void hw_w_phy(struct ksz_hw *hw, int port, u16 reg, u16 val)
+{
+ int phy;
+
+ phy = KS884X_PHY_1_CTRL_OFFSET + port * PHY_CTRL_INTERVAL + reg;
+ writew(val, hw->io + phy);
+}
+
+/*
+ * EEPROM access functions
+ */
+
+#define AT93C_CODE 0
+#define AT93C_WR_OFF 0x00
+#define AT93C_WR_ALL 0x10
+#define AT93C_ER_ALL 0x20
+#define AT93C_WR_ON 0x30
+
+#define AT93C_WRITE 1
+#define AT93C_READ 2
+#define AT93C_ERASE 3
+
+#define EEPROM_DELAY 4
+
+static inline void drop_gpio(struct ksz_hw *hw, u8 gpio)
+{
+ u16 data;
+
+ data = readw(hw->io + KS884X_EEPROM_CTRL_OFFSET);
+ data &= ~gpio;
+ writew(data, hw->io + KS884X_EEPROM_CTRL_OFFSET);
+}
+
+static inline void raise_gpio(struct ksz_hw *hw, u8 gpio)
+{
+ u16 data;
+
+ data = readw(hw->io + KS884X_EEPROM_CTRL_OFFSET);
+ data |= gpio;
+ writew(data, hw->io + KS884X_EEPROM_CTRL_OFFSET);
+}
+
+static inline u8 state_gpio(struct ksz_hw *hw, u8 gpio)
+{
+ u16 data;
+
+ data = readw(hw->io + KS884X_EEPROM_CTRL_OFFSET);
+ return (u8)(data & gpio);
+}
+
+static void eeprom_clk(struct ksz_hw *hw)
+{
+ raise_gpio(hw, EEPROM_SERIAL_CLOCK);
+ udelay(EEPROM_DELAY);
+ drop_gpio(hw, EEPROM_SERIAL_CLOCK);
+ udelay(EEPROM_DELAY);
+}
+
+static u16 spi_r(struct ksz_hw *hw)
+{
+ int i;
+ u16 temp = 0;
+
+ for (i = 15; i >= 0; i--) {
+ raise_gpio(hw, EEPROM_SERIAL_CLOCK);
+ udelay(EEPROM_DELAY);
+
+ temp |= (state_gpio(hw, EEPROM_DATA_IN)) ? 1 << i : 0;
+
+ drop_gpio(hw, EEPROM_SERIAL_CLOCK);
+ udelay(EEPROM_DELAY);
+ }
+ return temp;
+}
+
+static void spi_w(struct ksz_hw *hw, u16 data)
+{
+ int i;
+
+ for (i = 15; i >= 0; i--) {
+ (data & (0x01 << i)) ? raise_gpio(hw, EEPROM_DATA_OUT) :
+ drop_gpio(hw, EEPROM_DATA_OUT);
+ eeprom_clk(hw);
+ }
+}
+
+static void spi_reg(struct ksz_hw *hw, u8 data, u8 reg)
+{
+ int i;
+
+ /* Initial start bit */
+ raise_gpio(hw, EEPROM_DATA_OUT);
+ eeprom_clk(hw);
+
+ /* AT93C operation */
+ for (i = 1; i >= 0; i--) {
+ (data & (0x01 << i)) ? raise_gpio(hw, EEPROM_DATA_OUT) :
+ drop_gpio(hw, EEPROM_DATA_OUT);
+ eeprom_clk(hw);
+ }
+
+ /* Address location */
+ for (i = 5; i >= 0; i--) {
+ (reg & (0x01 << i)) ? raise_gpio(hw, EEPROM_DATA_OUT) :
+ drop_gpio(hw, EEPROM_DATA_OUT);
+ eeprom_clk(hw);
+ }
+}
+
+#define EEPROM_DATA_RESERVED 0
+#define EEPROM_DATA_MAC_ADDR_0 1
+#define EEPROM_DATA_MAC_ADDR_1 2
+#define EEPROM_DATA_MAC_ADDR_2 3
+#define EEPROM_DATA_SUBSYS_ID 4
+#define EEPROM_DATA_SUBSYS_VEN_ID 5
+#define EEPROM_DATA_PM_CAP 6
+
+/* User defined EEPROM data */
+#define EEPROM_DATA_OTHER_MAC_ADDR 9
+
+/**
+ * eeprom_read - read from AT93C46 EEPROM
+ * @hw: The hardware instance.
+ * @reg: The register offset.
+ *
+ * This function reads a word from the AT93C46 EEPROM.
+ *
+ * Return the data value.
+ */
+static u16 eeprom_read(struct ksz_hw *hw, u8 reg)
+{
+ u16 data;
+
+ raise_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT);
+
+ spi_reg(hw, AT93C_READ, reg);
+ data = spi_r(hw);
+
+ drop_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT);
+
+ return data;
+}
+
+/**
+ * eeprom_write - write to AT93C46 EEPROM
+ * @hw: The hardware instance.
+ * @reg: The register offset.
+ * @data: The data value.
+ *
+ * This procedure writes a word to the AT93C46 EEPROM.
+ */
+static void eeprom_write(struct ksz_hw *hw, u8 reg, u16 data)
+{
+ int timeout;
+
+ raise_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT);
+
+ /* Enable write. */
+ spi_reg(hw, AT93C_CODE, AT93C_WR_ON);
+ drop_gpio(hw, EEPROM_CHIP_SELECT);
+ udelay(1);
+
+ /* Erase the register. */
+ raise_gpio(hw, EEPROM_CHIP_SELECT);
+ spi_reg(hw, AT93C_ERASE, reg);
+ drop_gpio(hw, EEPROM_CHIP_SELECT);
+ udelay(1);
+
+ /* Check operation complete. */
+ raise_gpio(hw, EEPROM_CHIP_SELECT);
+ timeout = 8;
+ mdelay(2);
+ do {
+ mdelay(1);
+ } while (!state_gpio(hw, EEPROM_DATA_IN) && --timeout);
+ drop_gpio(hw, EEPROM_CHIP_SELECT);
+ udelay(1);
+
+ /* Write the register. */
+ raise_gpio(hw, EEPROM_CHIP_SELECT);
+ spi_reg(hw, AT93C_WRITE, reg);
+ spi_w(hw, data);
+ drop_gpio(hw, EEPROM_CHIP_SELECT);
+ udelay(1);
+
+ /* Check operation complete. */
+ raise_gpio(hw, EEPROM_CHIP_SELECT);
+ timeout = 8;
+ mdelay(2);
+ do {
+ mdelay(1);
+ } while (!state_gpio(hw, EEPROM_DATA_IN) && --timeout);
+ drop_gpio(hw, EEPROM_CHIP_SELECT);
+ udelay(1);
+
+ /* Disable write. */
+ raise_gpio(hw, EEPROM_CHIP_SELECT);
+ spi_reg(hw, AT93C_CODE, AT93C_WR_OFF);
+
+ drop_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT);
+}
+
+/*
+ * Link detection routines
+ */
+
+static u16 advertised_flow_ctrl(struct ksz_port *port, u16 ctrl)
+{
+ ctrl &= ~PORT_AUTO_NEG_SYM_PAUSE;
+ switch (port->flow_ctrl) {
+ case PHY_FLOW_CTRL:
+ ctrl |= PORT_AUTO_NEG_SYM_PAUSE;
+ break;
+ /* Not supported. */
+ case PHY_TX_ONLY:
+ case PHY_RX_ONLY:
+ default:
+ break;
+ }
+ return ctrl;
+}
+
+static void set_flow_ctrl(struct ksz_hw *hw, int rx, int tx)
+{
+ u32 rx_cfg;
+ u32 tx_cfg;
+
+ rx_cfg = hw->rx_cfg;
+ tx_cfg = hw->tx_cfg;
+ if (rx)
+ hw->rx_cfg |= DMA_RX_FLOW_ENABLE;
+ else
+ hw->rx_cfg &= ~DMA_RX_FLOW_ENABLE;
+ if (tx)
+ hw->tx_cfg |= DMA_TX_FLOW_ENABLE;
+ else
+ hw->tx_cfg &= ~DMA_TX_FLOW_ENABLE;
+ if (hw->enabled) {
+ if (rx_cfg != hw->rx_cfg)
+ writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL);
+ if (tx_cfg != hw->tx_cfg)
+ writel(hw->tx_cfg, hw->io + KS_DMA_TX_CTRL);
+ }
+}
+
+static void determine_flow_ctrl(struct ksz_hw *hw, struct ksz_port *port,
+ u16 local, u16 remote)
+{
+ int rx;
+ int tx;
+
+ if (hw->overrides & PAUSE_FLOW_CTRL)
+ return;
+
+ rx = tx = 0;
+ if (port->force_link)
+ rx = tx = 1;
+ if (remote & PHY_AUTO_NEG_SYM_PAUSE) {
+ if (local & PHY_AUTO_NEG_SYM_PAUSE) {
+ rx = tx = 1;
+ } else if ((remote & PHY_AUTO_NEG_ASYM_PAUSE) &&
+ (local & PHY_AUTO_NEG_PAUSE) ==
+ PHY_AUTO_NEG_ASYM_PAUSE) {
+ tx = 1;
+ }
+ } else if (remote & PHY_AUTO_NEG_ASYM_PAUSE) {
+ if ((local & PHY_AUTO_NEG_PAUSE) == PHY_AUTO_NEG_PAUSE)
+ rx = 1;
+ }
+ if (!hw->ksz_switch)
+ set_flow_ctrl(hw, rx, tx);
+}
+
+static inline void port_cfg_change(struct ksz_hw *hw, struct ksz_port *port,
+ struct ksz_port_info *info, u16 link_status)
+{
+ if ((hw->features & HALF_DUPLEX_SIGNAL_BUG) &&
+ !(hw->overrides & PAUSE_FLOW_CTRL)) {
+ u32 cfg = hw->tx_cfg;
+
+ /* Disable flow control in the half duplex mode. */
+ if (1 == info->duplex)
+ hw->tx_cfg &= ~DMA_TX_FLOW_ENABLE;
+ if (hw->enabled && cfg != hw->tx_cfg)
+ writel(hw->tx_cfg, hw->io + KS_DMA_TX_CTRL);
+ }
+}
+
+/**
+ * port_get_link_speed - get current link status
+ * @port: The port instance.
+ *
+ * This routine reads PHY registers to determine the current link status of the
+ * switch ports.
+ */
+static void port_get_link_speed(struct ksz_port *port)
+{
+ uint interrupt;
+ struct ksz_port_info *info;
+ struct ksz_port_info *linked = NULL;
+ struct ksz_hw *hw = port->hw;
+ u16 data;
+ u16 status;
+ u8 local;
+ u8 remote;
+ int i;
+ int p;
+ int change = 0;
+
+ interrupt = hw_block_intr(hw);
+
+ for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) {
+ info = &hw->port_info[p];
+ port_r16(hw, p, KS884X_PORT_CTRL_4_OFFSET, &data);
+ port_r16(hw, p, KS884X_PORT_STATUS_OFFSET, &status);
+
+ /*
+ * Link status is changing all the time even when there is no
+ * cable connection!
+ */
+ remote = status & (PORT_AUTO_NEG_COMPLETE |
+ PORT_STATUS_LINK_GOOD);
+ local = (u8) data;
+
+ /* No change to status. */
+ if (local == info->advertised && remote == info->partner)
+ continue;
+
+ info->advertised = local;
+ info->partner = remote;
+ if (status & PORT_STATUS_LINK_GOOD) {
+
+ /* Remember the first linked port. */
+ if (!linked)
+ linked = info;
+
+ info->tx_rate = 10 * TX_RATE_UNIT;
+ if (status & PORT_STATUS_SPEED_100MBIT)
+ info->tx_rate = 100 * TX_RATE_UNIT;
+
+ info->duplex = 1;
+ if (status & PORT_STATUS_FULL_DUPLEX)
+ info->duplex = 2;
+
+ if (media_connected != info->state) {
+ hw_r_phy(hw, p, KS884X_PHY_AUTO_NEG_OFFSET,
+ &data);
+ hw_r_phy(hw, p, KS884X_PHY_REMOTE_CAP_OFFSET,
+ &status);
+ determine_flow_ctrl(hw, port, data, status);
+ if (hw->ksz_switch) {
+ port_cfg_back_pressure(hw, p,
+ (1 == info->duplex));
+ }
+ change |= 1 << i;
+ port_cfg_change(hw, port, info, status);
+ }
+ info->state = media_connected;
+ } else {
+ if (media_disconnected != info->state) {
+ change |= 1 << i;
+
+ /* Indicate the link just goes down. */
+ hw->port_mib[p].link_down = 1;
+ }
+ info->state = media_disconnected;
+ }
+ hw->port_mib[p].state = (u8) info->state;
+ }
+
+ if (linked && media_disconnected == port->linked->state)
+ port->linked = linked;
+
+ hw_restore_intr(hw, interrupt);
+}
+
+#define PHY_RESET_TIMEOUT 10
+
+/**
+ * port_set_link_speed - set port speed
+ * @port: The port instance.
+ *
+ * This routine sets the link speed of the switch ports.
+ */
+static void port_set_link_speed(struct ksz_port *port)
+{
+ struct ksz_port_info *info;
+ struct ksz_hw *hw = port->hw;
+ u16 data;
+ u16 cfg;
+ u8 status;
+ int i;
+ int p;
+
+ for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) {
+ info = &hw->port_info[p];
+
+ port_r16(hw, p, KS884X_PORT_CTRL_4_OFFSET, &data);
+ port_r8(hw, p, KS884X_PORT_STATUS_OFFSET, &status);
+
+ cfg = 0;
+ if (status & PORT_STATUS_LINK_GOOD)
+ cfg = data;
+
+ data |= PORT_AUTO_NEG_ENABLE;
+ data = advertised_flow_ctrl(port, data);
+
+ data |= PORT_AUTO_NEG_100BTX_FD | PORT_AUTO_NEG_100BTX |
+ PORT_AUTO_NEG_10BT_FD | PORT_AUTO_NEG_10BT;
+
+ /* Check if manual configuration is specified by the user. */
+ if (port->speed || port->duplex) {
+ if (10 == port->speed)
+ data &= ~(PORT_AUTO_NEG_100BTX_FD |
+ PORT_AUTO_NEG_100BTX);
+ else if (100 == port->speed)
+ data &= ~(PORT_AUTO_NEG_10BT_FD |
+ PORT_AUTO_NEG_10BT);
+ if (1 == port->duplex)
+ data &= ~(PORT_AUTO_NEG_100BTX_FD |
+ PORT_AUTO_NEG_10BT_FD);
+ else if (2 == port->duplex)
+ data &= ~(PORT_AUTO_NEG_100BTX |
+ PORT_AUTO_NEG_10BT);
+ }
+ if (data != cfg) {
+ data |= PORT_AUTO_NEG_RESTART;
+ port_w16(hw, p, KS884X_PORT_CTRL_4_OFFSET, data);
+ }
+ }
+}
+
+/**
+ * port_force_link_speed - force port speed
+ * @port: The port instance.
+ *
+ * This routine forces the link speed of the switch ports.
+ */
+static void port_force_link_speed(struct ksz_port *port)
+{
+ struct ksz_hw *hw = port->hw;
+ u16 data;
+ int i;
+ int phy;
+ int p;
+
+ for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) {
+ phy = KS884X_PHY_1_CTRL_OFFSET + p * PHY_CTRL_INTERVAL;
+ hw_r_phy_ctrl(hw, phy, &data);
+
+ data &= ~PHY_AUTO_NEG_ENABLE;
+
+ if (10 == port->speed)
+ data &= ~PHY_SPEED_100MBIT;
+ else if (100 == port->speed)
+ data |= PHY_SPEED_100MBIT;
+ if (1 == port->duplex)
+ data &= ~PHY_FULL_DUPLEX;
+ else if (2 == port->duplex)
+ data |= PHY_FULL_DUPLEX;
+ hw_w_phy_ctrl(hw, phy, data);
+ }
+}
+
+static void port_set_power_saving(struct ksz_port *port, int enable)
+{
+ struct ksz_hw *hw = port->hw;
+ int i;
+ int p;
+
+ for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++)
+ port_cfg(hw, p,
+ KS884X_PORT_CTRL_4_OFFSET, PORT_POWER_DOWN, enable);
+}
+
+/*
+ * KSZ8841 power management functions
+ */
+
+/**
+ * hw_chk_wol_pme_status - check PMEN pin
+ * @hw: The hardware instance.
+ *
+ * This function is used to check PMEN pin is asserted.
+ *
+ * Return 1 if PMEN pin is asserted; otherwise, 0.
+ */
+static int hw_chk_wol_pme_status(struct ksz_hw *hw)
+{
+ struct dev_info *hw_priv = container_of(hw, struct dev_info, hw);
+ struct pci_dev *pdev = hw_priv->pdev;
+ u16 data;
+
+ if (!pdev->pm_cap)
+ return 0;
+ pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &data);
+ return (data & PCI_PM_CTRL_PME_STATUS) == PCI_PM_CTRL_PME_STATUS;
+}
+
+/**
+ * hw_clr_wol_pme_status - clear PMEN pin
+ * @hw: The hardware instance.
+ *
+ * This routine is used to clear PME_Status to deassert PMEN pin.
+ */
+static void hw_clr_wol_pme_status(struct ksz_hw *hw)
+{
+ struct dev_info *hw_priv = container_of(hw, struct dev_info, hw);
+ struct pci_dev *pdev = hw_priv->pdev;
+ u16 data;
+
+ if (!pdev->pm_cap)
+ return;
+
+ /* Clear PME_Status to deassert PMEN pin. */
+ pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &data);
+ data |= PCI_PM_CTRL_PME_STATUS;
+ pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, data);
+}
+
+/**
+ * hw_cfg_wol_pme - enable or disable Wake-on-LAN
+ * @hw: The hardware instance.
+ * @set: The flag indicating whether to enable or disable.
+ *
+ * This routine is used to enable or disable Wake-on-LAN.
+ */
+static void hw_cfg_wol_pme(struct ksz_hw *hw, int set)
+{
+ struct dev_info *hw_priv = container_of(hw, struct dev_info, hw);
+ struct pci_dev *pdev = hw_priv->pdev;
+ u16 data;
+
+ if (!pdev->pm_cap)
+ return;
+ pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &data);
+ data &= ~PCI_PM_CTRL_STATE_MASK;
+ if (set)
+ data |= PCI_PM_CTRL_PME_ENABLE | PCI_D3hot;
+ else
+ data &= ~PCI_PM_CTRL_PME_ENABLE;
+ pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, data);
+}
+
+/**
+ * hw_cfg_wol - configure Wake-on-LAN features
+ * @hw: The hardware instance.
+ * @frame: The pattern frame bit.
+ * @set: The flag indicating whether to enable or disable.
+ *
+ * This routine is used to enable or disable certain Wake-on-LAN features.
+ */
+static void hw_cfg_wol(struct ksz_hw *hw, u16 frame, int set)
+{
+ u16 data;
+
+ data = readw(hw->io + KS8841_WOL_CTRL_OFFSET);
+ if (set)
+ data |= frame;
+ else
+ data &= ~frame;
+ writew(data, hw->io + KS8841_WOL_CTRL_OFFSET);
+}
+
+/**
+ * hw_set_wol_frame - program Wake-on-LAN pattern
+ * @hw: The hardware instance.
+ * @i: The frame index.
+ * @mask_size: The size of the mask.
+ * @mask: Mask to ignore certain bytes in the pattern.
+ * @frame_size: The size of the frame.
+ * @pattern: The frame data.
+ *
+ * This routine is used to program Wake-on-LAN pattern.
+ */
+static void hw_set_wol_frame(struct ksz_hw *hw, int i, uint mask_size,
+ u8 *mask, uint frame_size, u8 *pattern)
+{
+ int bits;
+ int from;
+ int len;
+ int to;
+ u32 crc;
+ u8 data[64];
+ u8 val = 0;
+
+ if (frame_size > mask_size * 8)
+ frame_size = mask_size * 8;
+ if (frame_size > 64)
+ frame_size = 64;
+
+ i *= 0x10;
+ writel(0, hw->io + KS8841_WOL_FRAME_BYTE0_OFFSET + i);
+ writel(0, hw->io + KS8841_WOL_FRAME_BYTE2_OFFSET + i);
+
+ bits = len = from = to = 0;
+ do {
+ if (bits) {
+ if ((val & 1))
+ data[to++] = pattern[from];
+ val >>= 1;
+ ++from;
+ --bits;
+ } else {
+ val = mask[len];
+ writeb(val, hw->io + KS8841_WOL_FRAME_BYTE0_OFFSET + i
+ + len);
+ ++len;
+ if (val)
+ bits = 8;
+ else
+ from += 8;
+ }
+ } while (from < (int) frame_size);
+ if (val) {
+ bits = mask[len - 1];
+ val <<= (from % 8);
+ bits &= ~val;
+ writeb(bits, hw->io + KS8841_WOL_FRAME_BYTE0_OFFSET + i + len -
+ 1);
+ }
+ crc = ether_crc(to, data);
+ writel(crc, hw->io + KS8841_WOL_FRAME_CRC_OFFSET + i);
+}
+
+/**
+ * hw_add_wol_arp - add ARP pattern
+ * @hw: The hardware instance.
+ * @ip_addr: The IPv4 address assigned to the device.
+ *
+ * This routine is used to add ARP pattern for waking up the host.
+ */
+static void hw_add_wol_arp(struct ksz_hw *hw, u8 *ip_addr)
+{
+ u8 mask[6] = { 0x3F, 0xF0, 0x3F, 0x00, 0xC0, 0x03 };
+ u8 pattern[42] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x06,
+ 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+
+ memcpy(&pattern[38], ip_addr, 4);
+ hw_set_wol_frame(hw, 3, 6, mask, 42, pattern);
+}
+
+/**
+ * hw_add_wol_bcast - add broadcast pattern
+ * @hw: The hardware instance.
+ *
+ * This routine is used to add broadcast pattern for waking up the host.
+ */
+static void hw_add_wol_bcast(struct ksz_hw *hw)
+{
+ u8 mask[] = { 0x3F };
+ u8 pattern[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+ hw_set_wol_frame(hw, 2, 1, mask, MAC_ADDR_LEN, pattern);
+}
+
+/**
+ * hw_add_wol_mcast - add multicast pattern
+ * @hw: The hardware instance.
+ *
+ * This routine is used to add multicast pattern for waking up the host.
+ *
+ * It is assumed the multicast packet is the ICMPv6 neighbor solicitation used
+ * by IPv6 ping command. Note that multicast packets are filtred through the
+ * multicast hash table, so not all multicast packets can wake up the host.
+ */
+static void hw_add_wol_mcast(struct ksz_hw *hw)
+{
+ u8 mask[] = { 0x3F };
+ u8 pattern[] = { 0x33, 0x33, 0xFF, 0x00, 0x00, 0x00 };
+
+ memcpy(&pattern[3], &hw->override_addr[3], 3);
+ hw_set_wol_frame(hw, 1, 1, mask, 6, pattern);
+}
+
+/**
+ * hw_add_wol_ucast - add unicast pattern
+ * @hw: The hardware instance.
+ *
+ * This routine is used to add unicast pattern to wakeup the host.
+ *
+ * It is assumed the unicast packet is directed to the device, as the hardware
+ * can only receive them in normal case.
+ */
+static void hw_add_wol_ucast(struct ksz_hw *hw)
+{
+ u8 mask[] = { 0x3F };
+
+ hw_set_wol_frame(hw, 0, 1, mask, MAC_ADDR_LEN, hw->override_addr);
+}
+
+/**
+ * hw_enable_wol - enable Wake-on-LAN
+ * @hw: The hardware instance.
+ * @wol_enable: The Wake-on-LAN settings.
+ * @net_addr: The IPv4 address assigned to the device.
+ *
+ * This routine is used to enable Wake-on-LAN depending on driver settings.
+ */
+static void hw_enable_wol(struct ksz_hw *hw, u32 wol_enable, u8 *net_addr)
+{
+ hw_cfg_wol(hw, KS8841_WOL_MAGIC_ENABLE, (wol_enable & WAKE_MAGIC));
+ hw_cfg_wol(hw, KS8841_WOL_FRAME0_ENABLE, (wol_enable & WAKE_UCAST));
+ hw_add_wol_ucast(hw);
+ hw_cfg_wol(hw, KS8841_WOL_FRAME1_ENABLE, (wol_enable & WAKE_MCAST));
+ hw_add_wol_mcast(hw);
+ hw_cfg_wol(hw, KS8841_WOL_FRAME2_ENABLE, (wol_enable & WAKE_BCAST));
+ hw_cfg_wol(hw, KS8841_WOL_FRAME3_ENABLE, (wol_enable & WAKE_ARP));
+ hw_add_wol_arp(hw, net_addr);
+}
+
+/**
+ * hw_init - check driver is correct for the hardware
+ * @hw: The hardware instance.
+ *
+ * This function checks the hardware is correct for this driver and sets the
+ * hardware up for proper initialization.
+ *
+ * Return number of ports or 0 if not right.
+ */
+static int hw_init(struct ksz_hw *hw)
+{
+ int rc = 0;
+ u16 data;
+ u16 revision;
+
+ /* Set bus speed to 125MHz. */
+ writew(BUS_SPEED_125_MHZ, hw->io + KS884X_BUS_CTRL_OFFSET);
+
+ /* Check KSZ884x chip ID. */
+ data = readw(hw->io + KS884X_CHIP_ID_OFFSET);
+
+ revision = (data & KS884X_REVISION_MASK) >> KS884X_REVISION_SHIFT;
+ data &= KS884X_CHIP_ID_MASK_41;
+ if (REG_CHIP_ID_41 == data)
+ rc = 1;
+ else if (REG_CHIP_ID_42 == data)
+ rc = 2;
+ else
+ return 0;
+
+ /* Setup hardware features or bug workarounds. */
+ if (revision <= 1) {
+ hw->features |= SMALL_PACKET_TX_BUG;
+ if (1 == rc)
+ hw->features |= HALF_DUPLEX_SIGNAL_BUG;
+ }
+ hw->features |= IPV6_CSUM_GEN_HACK;
+ return rc;
+}
+
+/**
+ * hw_reset - reset the hardware
+ * @hw: The hardware instance.
+ *
+ * This routine resets the hardware.
+ */
+static void hw_reset(struct ksz_hw *hw)
+{
+ writew(GLOBAL_SOFTWARE_RESET, hw->io + KS884X_GLOBAL_CTRL_OFFSET);
+
+ /* Wait for device to reset. */
+ mdelay(10);
+
+ /* Write 0 to clear device reset. */
+ writew(0, hw->io + KS884X_GLOBAL_CTRL_OFFSET);
+}
+
+/**
+ * hw_setup - setup the hardware
+ * @hw: The hardware instance.
+ *
+ * This routine setup the hardware for proper operation.
+ */
+static void hw_setup(struct ksz_hw *hw)
+{
+#if SET_DEFAULT_LED
+ u16 data;
+
+ /* Change default LED mode. */
+ data = readw(hw->io + KS8842_SWITCH_CTRL_5_OFFSET);
+ data &= ~LED_MODE;
+ data |= SET_DEFAULT_LED;
+ writew(data, hw->io + KS8842_SWITCH_CTRL_5_OFFSET);
+#endif
+
+ /* Setup transmit control. */
+ hw->tx_cfg = (DMA_TX_PAD_ENABLE | DMA_TX_CRC_ENABLE |
+ (DMA_BURST_DEFAULT << DMA_BURST_SHIFT) | DMA_TX_ENABLE);
+
+ /* Setup receive control. */
+ hw->rx_cfg = (DMA_RX_BROADCAST | DMA_RX_UNICAST |
+ (DMA_BURST_DEFAULT << DMA_BURST_SHIFT) | DMA_RX_ENABLE);
+ hw->rx_cfg |= KS884X_DMA_RX_MULTICAST;
+
+ /* Hardware cannot handle UDP packet in IP fragments. */
+ hw->rx_cfg |= (DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP);
+
+ if (hw->all_multi)
+ hw->rx_cfg |= DMA_RX_ALL_MULTICAST;
+ if (hw->promiscuous)
+ hw->rx_cfg |= DMA_RX_PROMISCUOUS;
+}
+
+/**
+ * hw_setup_intr - setup interrupt mask
+ * @hw: The hardware instance.
+ *
+ * This routine setup the interrupt mask for proper operation.
+ */
+static void hw_setup_intr(struct ksz_hw *hw)
+{
+ hw->intr_mask = KS884X_INT_MASK | KS884X_INT_RX_OVERRUN;
+}
+
+static void ksz_check_desc_num(struct ksz_desc_info *info)
+{
+#define MIN_DESC_SHIFT 2
+
+ int alloc = info->alloc;
+ int shift;
+
+ shift = 0;
+ while (!(alloc & 1)) {
+ shift++;
+ alloc >>= 1;
+ }
+ if (alloc != 1 || shift < MIN_DESC_SHIFT) {
+ printk(KERN_ALERT "Hardware descriptor numbers not right!\n");
+ while (alloc) {
+ shift++;
+ alloc >>= 1;
+ }
+ if (shift < MIN_DESC_SHIFT)
+ shift = MIN_DESC_SHIFT;
+ alloc = 1 << shift;
+ info->alloc = alloc;
+ }
+ info->mask = info->alloc - 1;
+}
+
+static void hw_init_desc(struct ksz_desc_info *desc_info, int transmit)
+{
+ int i;
+ u32 phys = desc_info->ring_phys;
+ struct ksz_hw_desc *desc = desc_info->ring_virt;
+ struct ksz_desc *cur = desc_info->ring;
+ struct ksz_desc *previous = NULL;
+
+ for (i = 0; i < desc_info->alloc; i++) {
+ cur->phw = desc++;
+ phys += desc_info->size;
+ previous = cur++;
+ previous->phw->next = cpu_to_le32(phys);
+ }
+ previous->phw->next = cpu_to_le32(desc_info->ring_phys);
+ previous->sw.buf.rx.end_of_ring = 1;
+ previous->phw->buf.data = cpu_to_le32(previous->sw.buf.data);
+
+ desc_info->avail = desc_info->alloc;
+ desc_info->last = desc_info->next = 0;
+
+ desc_info->cur = desc_info->ring;
+}
+
+/**
+ * hw_set_desc_base - set descriptor base addresses
+ * @hw: The hardware instance.
+ * @tx_addr: The transmit descriptor base.
+ * @rx_addr: The receive descriptor base.
+ *
+ * This routine programs the descriptor base addresses after reset.
+ */
+static void hw_set_desc_base(struct ksz_hw *hw, u32 tx_addr, u32 rx_addr)
+{
+ /* Set base address of Tx/Rx descriptors. */
+ writel(tx_addr, hw->io + KS_DMA_TX_ADDR);
+ writel(rx_addr, hw->io + KS_DMA_RX_ADDR);
+}
+
+static void hw_reset_pkts(struct ksz_desc_info *info)
+{
+ info->cur = info->ring;
+ info->avail = info->alloc;
+ info->last = info->next = 0;
+}
+
+static inline void hw_resume_rx(struct ksz_hw *hw)
+{
+ writel(DMA_START, hw->io + KS_DMA_RX_START);
+}
+
+/**
+ * hw_start_rx - start receiving
+ * @hw: The hardware instance.
+ *
+ * This routine starts the receive function of the hardware.
+ */
+static void hw_start_rx(struct ksz_hw *hw)
+{
+ writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL);
+
+ /* Notify when the receive stops. */
+ hw->intr_mask |= KS884X_INT_RX_STOPPED;
+
+ writel(DMA_START, hw->io + KS_DMA_RX_START);
+ hw_ack_intr(hw, KS884X_INT_RX_STOPPED);
+ hw->rx_stop++;
+
+ /* Variable overflows. */
+ if (0 == hw->rx_stop)
+ hw->rx_stop = 2;
+}
+
+/*
+ * hw_stop_rx - stop receiving
+ * @hw: The hardware instance.
+ *
+ * This routine stops the receive function of the hardware.
+ */
+static void hw_stop_rx(struct ksz_hw *hw)
+{
+ hw->rx_stop = 0;
+ hw_turn_off_intr(hw, KS884X_INT_RX_STOPPED);
+ writel((hw->rx_cfg & ~DMA_RX_ENABLE), hw->io + KS_DMA_RX_CTRL);
+}
+
+/**
+ * hw_start_tx - start transmitting
+ * @hw: The hardware instance.
+ *
+ * This routine starts the transmit function of the hardware.
+ */
+static void hw_start_tx(struct ksz_hw *hw)
+{
+ writel(hw->tx_cfg, hw->io + KS_DMA_TX_CTRL);
+}
+
+/**
+ * hw_stop_tx - stop transmitting
+ * @hw: The hardware instance.
+ *
+ * This routine stops the transmit function of the hardware.
+ */
+static void hw_stop_tx(struct ksz_hw *hw)
+{
+ writel((hw->tx_cfg & ~DMA_TX_ENABLE), hw->io + KS_DMA_TX_CTRL);
+}
+
+/**
+ * hw_disable - disable hardware
+ * @hw: The hardware instance.
+ *
+ * This routine disables the hardware.
+ */
+static void hw_disable(struct ksz_hw *hw)
+{
+ hw_stop_rx(hw);
+ hw_stop_tx(hw);
+ hw->enabled = 0;
+}
+
+/**
+ * hw_enable - enable hardware
+ * @hw: The hardware instance.
+ *
+ * This routine enables the hardware.
+ */
+static void hw_enable(struct ksz_hw *hw)
+{
+ hw_start_tx(hw);
+ hw_start_rx(hw);
+ hw->enabled = 1;
+}
+
+/**
+ * hw_alloc_pkt - allocate enough descriptors for transmission
+ * @hw: The hardware instance.
+ * @length: The length of the packet.
+ * @physical: Number of descriptors required.
+ *
+ * This function allocates descriptors for transmission.
+ *
+ * Return 0 if not successful; 1 for buffer copy; or number of descriptors.
+ */
+static int hw_alloc_pkt(struct ksz_hw *hw, int length, int physical)
+{
+ /* Always leave one descriptor free. */
+ if (hw->tx_desc_info.avail <= 1)
+ return 0;
+
+ /* Allocate a descriptor for transmission and mark it current. */
+ get_tx_pkt(&hw->tx_desc_info, &hw->tx_desc_info.cur);
+ hw->tx_desc_info.cur->sw.buf.tx.first_seg = 1;
+
+ /* Keep track of number of transmit descriptors used so far. */
+ ++hw->tx_int_cnt;
+ hw->tx_size += length;
+
+ /* Cannot hold on too much data. */
+ if (hw->tx_size >= MAX_TX_HELD_SIZE)
+ hw->tx_int_cnt = hw->tx_int_mask + 1;
+
+ if (physical > hw->tx_desc_info.avail)
+ return 1;
+
+ return hw->tx_desc_info.avail;
+}
+
+/**
+ * hw_send_pkt - mark packet for transmission
+ * @hw: The hardware instance.
+ *
+ * This routine marks the packet for transmission in PCI version.
+ */
+static void hw_send_pkt(struct ksz_hw *hw)
+{
+ struct ksz_desc *cur = hw->tx_desc_info.cur;
+
+ cur->sw.buf.tx.last_seg = 1;
+
+ /* Interrupt only after specified number of descriptors used. */
+ if (hw->tx_int_cnt > hw->tx_int_mask) {
+ cur->sw.buf.tx.intr = 1;
+ hw->tx_int_cnt = 0;
+ hw->tx_size = 0;
+ }
+
+ /* KSZ8842 supports port directed transmission. */
+ cur->sw.buf.tx.dest_port = hw->dst_ports;
+
+ release_desc(cur);
+
+ writel(0, hw->io + KS_DMA_TX_START);
+}
+
+static int empty_addr(u8 *addr)
+{
+ u32 *addr1 = (u32 *) addr;
+ u16 *addr2 = (u16 *) &addr[4];
+
+ return 0 == *addr1 && 0 == *addr2;
+}
+
+/**
+ * hw_set_addr - set MAC address
+ * @hw: The hardware instance.
+ *
+ * This routine programs the MAC address of the hardware when the address is
+ * overrided.
+ */
+static void hw_set_addr(struct ksz_hw *hw)
+{
+ int i;
+
+ for (i = 0; i < MAC_ADDR_LEN; i++)
+ writeb(hw->override_addr[MAC_ADDR_ORDER(i)],
+ hw->io + KS884X_ADDR_0_OFFSET + i);
+
+ sw_set_addr(hw, hw->override_addr);
+}
+
+/**
+ * hw_read_addr - read MAC address
+ * @hw: The hardware instance.
+ *
+ * This routine retrieves the MAC address of the hardware.
+ */
+static void hw_read_addr(struct ksz_hw *hw)
+{
+ int i;
+
+ for (i = 0; i < MAC_ADDR_LEN; i++)
+ hw->perm_addr[MAC_ADDR_ORDER(i)] = readb(hw->io +
+ KS884X_ADDR_0_OFFSET + i);
+
+ if (!hw->mac_override) {
+ memcpy(hw->override_addr, hw->perm_addr, MAC_ADDR_LEN);
+ if (empty_addr(hw->override_addr)) {
+ memcpy(hw->perm_addr, DEFAULT_MAC_ADDRESS,
+ MAC_ADDR_LEN);
+ memcpy(hw->override_addr, DEFAULT_MAC_ADDRESS,
+ MAC_ADDR_LEN);
+ hw->override_addr[5] += hw->id;
+ hw_set_addr(hw);
+ }
+ }
+}
+
+static void hw_ena_add_addr(struct ksz_hw *hw, int index, u8 *mac_addr)
+{
+ int i;
+ u32 mac_addr_lo;
+ u32 mac_addr_hi;
+
+ mac_addr_hi = 0;
+ for (i = 0; i < 2; i++) {
+ mac_addr_hi <<= 8;
+ mac_addr_hi |= mac_addr[i];
+ }
+ mac_addr_hi |= ADD_ADDR_ENABLE;
+ mac_addr_lo = 0;
+ for (i = 2; i < 6; i++) {
+ mac_addr_lo <<= 8;
+ mac_addr_lo |= mac_addr[i];
+ }
+ index *= ADD_ADDR_INCR;
+
+ writel(mac_addr_lo, hw->io + index + KS_ADD_ADDR_0_LO);
+ writel(mac_addr_hi, hw->io + index + KS_ADD_ADDR_0_HI);
+}
+
+static void hw_set_add_addr(struct ksz_hw *hw)
+{
+ int i;
+
+ for (i = 0; i < ADDITIONAL_ENTRIES; i++) {
+ if (empty_addr(hw->address[i]))
+ writel(0, hw->io + ADD_ADDR_INCR * i +
+ KS_ADD_ADDR_0_HI);
+ else
+ hw_ena_add_addr(hw, i, hw->address[i]);
+ }
+}
+
+static int hw_add_addr(struct ksz_hw *hw, u8 *mac_addr)
+{
+ int i;
+ int j = ADDITIONAL_ENTRIES;
+
+ if (!memcmp(hw->override_addr, mac_addr, MAC_ADDR_LEN))
+ return 0;
+ for (i = 0; i < hw->addr_list_size; i++) {
+ if (!memcmp(hw->address[i], mac_addr, MAC_ADDR_LEN))
+ return 0;
+ if (ADDITIONAL_ENTRIES == j && empty_addr(hw->address[i]))
+ j = i;
+ }
+ if (j < ADDITIONAL_ENTRIES) {
+ memcpy(hw->address[j], mac_addr, MAC_ADDR_LEN);
+ hw_ena_add_addr(hw, j, hw->address[j]);
+ return 0;
+ }
+ return -1;
+}
+
+static int hw_del_addr(struct ksz_hw *hw, u8 *mac_addr)
+{
+ int i;
+
+ for (i = 0; i < hw->addr_list_size; i++) {
+ if (!memcmp(hw->address[i], mac_addr, MAC_ADDR_LEN)) {
+ memset(hw->address[i], 0, MAC_ADDR_LEN);
+ writel(0, hw->io + ADD_ADDR_INCR * i +
+ KS_ADD_ADDR_0_HI);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/**
+ * hw_clr_multicast - clear multicast addresses
+ * @hw: The hardware instance.
+ *
+ * This routine removes all multicast addresses set in the hardware.
+ */
+static void hw_clr_multicast(struct ksz_hw *hw)
+{
+ int i;
+
+ for (i = 0; i < HW_MULTICAST_SIZE; i++) {
+ hw->multi_bits[i] = 0;
+
+ writeb(0, hw->io + KS884X_MULTICAST_0_OFFSET + i);
+ }
+}
+
+/**
+ * hw_set_grp_addr - set multicast addresses
+ * @hw: The hardware instance.
+ *
+ * This routine programs multicast addresses for the hardware to accept those
+ * addresses.
+ */
+static void hw_set_grp_addr(struct ksz_hw *hw)
+{
+ int i;
+ int index;
+ int position;
+ int value;
+
+ memset(hw->multi_bits, 0, sizeof(u8) * HW_MULTICAST_SIZE);
+
+ for (i = 0; i < hw->multi_list_size; i++) {
+ position = (ether_crc(6, hw->multi_list[i]) >> 26) & 0x3f;
+ index = position >> 3;
+ value = 1 << (position & 7);
+ hw->multi_bits[index] |= (u8) value;
+ }
+
+ for (i = 0; i < HW_MULTICAST_SIZE; i++)
+ writeb(hw->multi_bits[i], hw->io + KS884X_MULTICAST_0_OFFSET +
+ i);
+}
+
+/**
+ * hw_set_multicast - enable or disable all multicast receiving
+ * @hw: The hardware instance.
+ * @multicast: To turn on or off the all multicast feature.
+ *
+ * This routine enables/disables the hardware to accept all multicast packets.
+ */
+static void hw_set_multicast(struct ksz_hw *hw, u8 multicast)
+{
+ /* Stop receiving for reconfiguration. */
+ hw_stop_rx(hw);
+
+ if (multicast)
+ hw->rx_cfg |= DMA_RX_ALL_MULTICAST;
+ else
+ hw->rx_cfg &= ~DMA_RX_ALL_MULTICAST;
+
+ if (hw->enabled)
+ hw_start_rx(hw);
+}
+
+/**
+ * hw_set_promiscuous - enable or disable promiscuous receiving
+ * @hw: The hardware instance.
+ * @prom: To turn on or off the promiscuous feature.
+ *
+ * This routine enables/disables the hardware to accept all packets.
+ */
+static void hw_set_promiscuous(struct ksz_hw *hw, u8 prom)
+{
+ /* Stop receiving for reconfiguration. */
+ hw_stop_rx(hw);
+
+ if (prom)
+ hw->rx_cfg |= DMA_RX_PROMISCUOUS;
+ else
+ hw->rx_cfg &= ~DMA_RX_PROMISCUOUS;
+
+ if (hw->enabled)
+ hw_start_rx(hw);
+}
+
+/**
+ * sw_enable - enable the switch
+ * @hw: The hardware instance.
+ * @enable: The flag to enable or disable the switch
+ *
+ * This routine is used to enable/disable the switch in KSZ8842.
+ */
+static void sw_enable(struct ksz_hw *hw, int enable)
+{
+ int port;
+
+ for (port = 0; port < SWITCH_PORT_NUM; port++) {
+ if (hw->dev_count > 1) {
+ /* Set port-base vlan membership with host port. */
+ sw_cfg_port_base_vlan(hw, port,
+ HOST_MASK | (1 << port));
+ port_set_stp_state(hw, port, STP_STATE_DISABLED);
+ } else {
+ sw_cfg_port_base_vlan(hw, port, PORT_MASK);
+ port_set_stp_state(hw, port, STP_STATE_FORWARDING);
+ }
+ }
+ if (hw->dev_count > 1)
+ port_set_stp_state(hw, SWITCH_PORT_NUM, STP_STATE_SIMPLE);
+ else
+ port_set_stp_state(hw, SWITCH_PORT_NUM, STP_STATE_FORWARDING);
+
+ if (enable)
+ enable = KS8842_START;
+ writew(enable, hw->io + KS884X_CHIP_ID_OFFSET);
+}
+
+/**
+ * sw_setup - setup the switch
+ * @hw: The hardware instance.
+ *
+ * This routine setup the hardware switch engine for default operation.
+ */
+static void sw_setup(struct ksz_hw *hw)
+{
+ int port;
+
+ sw_set_global_ctrl(hw);
+
+ /* Enable switch broadcast storm protection at 10% percent rate. */
+ sw_init_broad_storm(hw);
+ hw_cfg_broad_storm(hw, BROADCAST_STORM_PROTECTION_RATE);
+ for (port = 0; port < SWITCH_PORT_NUM; port++)
+ sw_ena_broad_storm(hw, port);
+
+ sw_init_prio(hw);
+
+ sw_init_mirror(hw);
+
+ sw_init_prio_rate(hw);
+
+ sw_init_vlan(hw);
+
+ if (hw->features & STP_SUPPORT)
+ sw_init_stp(hw);
+ if (!sw_chk(hw, KS8842_SWITCH_CTRL_1_OFFSET,
+ SWITCH_TX_FLOW_CTRL | SWITCH_RX_FLOW_CTRL))
+ hw->overrides |= PAUSE_FLOW_CTRL;
+ sw_enable(hw, 1);
+}
+
+/**
+ * ksz_start_timer - start kernel timer
+ * @info: Kernel timer information.
+ * @time: The time tick.
+ *
+ * This routine starts the kernel timer after the specified time tick.
+ */
+static void ksz_start_timer(struct ksz_timer_info *info, int time)
+{
+ info->cnt = 0;
+ info->timer.expires = jiffies + time;
+ add_timer(&info->timer);
+
+ /* infinity */
+ info->max = -1;
+}
+
+/**
+ * ksz_stop_timer - stop kernel timer
+ * @info: Kernel timer information.
+ *
+ * This routine stops the kernel timer.
+ */
+static void ksz_stop_timer(struct ksz_timer_info *info)
+{
+ if (info->max) {
+ info->max = 0;
+ del_timer_sync(&info->timer);
+ }
+}
+
+static void ksz_init_timer(struct ksz_timer_info *info, int period,
+ void (*function)(unsigned long), void *data)
+{
+ info->max = 0;
+ info->period = period;
+ init_timer(&info->timer);
+ info->timer.function = function;
+ info->timer.data = (unsigned long) data;
+}
+
+static void ksz_update_timer(struct ksz_timer_info *info)
+{
+ ++info->cnt;
+ if (info->max > 0) {
+ if (info->cnt < info->max) {
+ info->timer.expires = jiffies + info->period;
+ add_timer(&info->timer);
+ } else
+ info->max = 0;
+ } else if (info->max < 0) {
+ info->timer.expires = jiffies + info->period;
+ add_timer(&info->timer);
+ }
+}
+
+/**
+ * ksz_alloc_soft_desc - allocate software descriptors
+ * @desc_info: Descriptor information structure.
+ * @transmit: Indication that descriptors are for transmit.
+ *
+ * This local function allocates software descriptors for manipulation in
+ * memory.
+ *
+ * Return 0 if successful.
+ */
+static int ksz_alloc_soft_desc(struct ksz_desc_info *desc_info, int transmit)
+{
+ desc_info->ring = kmalloc(sizeof(struct ksz_desc) * desc_info->alloc,
+ GFP_KERNEL);
+ if (!desc_info->ring)
+ return 1;
+ memset((void *) desc_info->ring, 0,
+ sizeof(struct ksz_desc) * desc_info->alloc);
+ hw_init_desc(desc_info, transmit);
+ return 0;
+}
+
+/**
+ * ksz_alloc_desc - allocate hardware descriptors
+ * @adapter: Adapter information structure.
+ *
+ * This local function allocates hardware descriptors for receiving and
+ * transmitting.
+ *
+ * Return 0 if successful.
+ */
+static int ksz_alloc_desc(struct dev_info *adapter)
+{
+ struct ksz_hw *hw = &adapter->hw;
+ int offset;
+
+ /* Allocate memory for RX & TX descriptors. */
+ adapter->desc_pool.alloc_size =
+ hw->rx_desc_info.size * hw->rx_desc_info.alloc +
+ hw->tx_desc_info.size * hw->tx_desc_info.alloc +
+ DESC_ALIGNMENT;
+
+ adapter->desc_pool.alloc_virt =
+ pci_alloc_consistent(
+ adapter->pdev, adapter->desc_pool.alloc_size,
+ &adapter->desc_pool.dma_addr);
+ if (adapter->desc_pool.alloc_virt == NULL) {
+ adapter->desc_pool.alloc_size = 0;
+ return 1;
+ }
+ memset(adapter->desc_pool.alloc_virt, 0, adapter->desc_pool.alloc_size);
+
+ /* Align to the next cache line boundary. */
+ offset = (((ulong) adapter->desc_pool.alloc_virt % DESC_ALIGNMENT) ?
+ (DESC_ALIGNMENT -
+ ((ulong) adapter->desc_pool.alloc_virt % DESC_ALIGNMENT)) : 0);
+ adapter->desc_pool.virt = adapter->desc_pool.alloc_virt + offset;
+ adapter->desc_pool.phys = adapter->desc_pool.dma_addr + offset;
+
+ /* Allocate receive/transmit descriptors. */
+ hw->rx_desc_info.ring_virt = (struct ksz_hw_desc *)
+ adapter->desc_pool.virt;
+ hw->rx_desc_info.ring_phys = adapter->desc_pool.phys;
+ offset = hw->rx_desc_info.alloc * hw->rx_desc_info.size;
+ hw->tx_desc_info.ring_virt = (struct ksz_hw_desc *)
+ (adapter->desc_pool.virt + offset);
+ hw->tx_desc_info.ring_phys = adapter->desc_pool.phys + offset;
+
+ if (ksz_alloc_soft_desc(&hw->rx_desc_info, 0))
+ return 1;
+ if (ksz_alloc_soft_desc(&hw->tx_desc_info, 1))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * free_dma_buf - release DMA buffer resources
+ * @adapter: Adapter information structure.
+ *
+ * This routine is just a helper function to release the DMA buffer resources.
+ */
+static void free_dma_buf(struct dev_info *adapter, struct ksz_dma_buf *dma_buf,
+ int direction)
+{
+ pci_unmap_single(adapter->pdev, dma_buf->dma, dma_buf->len, direction);
+ dev_kfree_skb(dma_buf->skb);
+ dma_buf->skb = NULL;
+ dma_buf->dma = 0;
+}
+
+/**
+ * ksz_init_rx_buffers - initialize receive descriptors
+ * @adapter: Adapter information structure.
+ *
+ * This routine initializes DMA buffers for receiving.
+ */
+static void ksz_init_rx_buffers(struct dev_info *adapter)
+{
+ int i;
+ struct ksz_desc *desc;
+ struct ksz_dma_buf *dma_buf;
+ struct ksz_hw *hw = &adapter->hw;
+ struct ksz_desc_info *info = &hw->rx_desc_info;
+
+ for (i = 0; i < hw->rx_desc_info.alloc; i++) {
+ get_rx_pkt(info, &desc);
+
+ dma_buf = DMA_BUFFER(desc);
+ if (dma_buf->skb && dma_buf->len != adapter->mtu)
+ free_dma_buf(adapter, dma_buf, PCI_DMA_FROMDEVICE);
+ dma_buf->len = adapter->mtu;
+ if (!dma_buf->skb)
+ dma_buf->skb = alloc_skb(dma_buf->len, GFP_ATOMIC);
+ if (dma_buf->skb && !dma_buf->dma) {
+ dma_buf->skb->dev = adapter->dev;
+ dma_buf->dma = pci_map_single(
+ adapter->pdev,
+ skb_tail_pointer(dma_buf->skb),
+ dma_buf->len,
+ PCI_DMA_FROMDEVICE);
+ }
+
+ /* Set descriptor. */
+ set_rx_buf(desc, dma_buf->dma);
+ set_rx_len(desc, dma_buf->len);
+ release_desc(desc);
+ }
+}
+
+/**
+ * ksz_alloc_mem - allocate memory for hardware descriptors
+ * @adapter: Adapter information structure.
+ *
+ * This function allocates memory for use by hardware descriptors for receiving
+ * and transmitting.
+ *
+ * Return 0 if successful.
+ */
+static int ksz_alloc_mem(struct dev_info *adapter)
+{
+ struct ksz_hw *hw = &adapter->hw;
+
+ /* Determine the number of receive and transmit descriptors. */
+ hw->rx_desc_info.alloc = NUM_OF_RX_DESC;
+ hw->tx_desc_info.alloc = NUM_OF_TX_DESC;
+
+ /* Determine how many descriptors to skip transmit interrupt. */
+ hw->tx_int_cnt = 0;
+ hw->tx_int_mask = NUM_OF_TX_DESC / 4;
+ if (hw->tx_int_mask > 8)
+ hw->tx_int_mask = 8;
+ while (hw->tx_int_mask) {
+ hw->tx_int_cnt++;
+ hw->tx_int_mask >>= 1;
+ }
+ if (hw->tx_int_cnt) {
+ hw->tx_int_mask = (1 << (hw->tx_int_cnt - 1)) - 1;
+ hw->tx_int_cnt = 0;
+ }
+
+ /* Determine the descriptor size. */
+ hw->rx_desc_info.size =
+ (((sizeof(struct ksz_hw_desc) + DESC_ALIGNMENT - 1) /
+ DESC_ALIGNMENT) * DESC_ALIGNMENT);
+ hw->tx_desc_info.size =
+ (((sizeof(struct ksz_hw_desc) + DESC_ALIGNMENT - 1) /
+ DESC_ALIGNMENT) * DESC_ALIGNMENT);
+ if (hw->rx_desc_info.size != sizeof(struct ksz_hw_desc))
+ printk(KERN_ALERT
+ "Hardware descriptor size not right!\n");
+ ksz_check_desc_num(&hw->rx_desc_info);
+ ksz_check_desc_num(&hw->tx_desc_info);
+
+ /* Allocate descriptors. */
+ if (ksz_alloc_desc(adapter))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * ksz_free_desc - free software and hardware descriptors
+ * @adapter: Adapter information structure.
+ *
+ * This local routine frees the software and hardware descriptors allocated by
+ * ksz_alloc_desc().
+ */
+static void ksz_free_desc(struct dev_info *adapter)
+{
+ struct ksz_hw *hw = &adapter->hw;
+
+ /* Reset descriptor. */
+ hw->rx_desc_info.ring_virt = NULL;
+ hw->tx_desc_info.ring_virt = NULL;
+ hw->rx_desc_info.ring_phys = 0;
+ hw->tx_desc_info.ring_phys = 0;
+
+ /* Free memory. */
+ if (adapter->desc_pool.alloc_virt)
+ pci_free_consistent(
+ adapter->pdev,
+ adapter->desc_pool.alloc_size,
+ adapter->desc_pool.alloc_virt,
+ adapter->desc_pool.dma_addr);
+
+ /* Reset resource pool. */
+ adapter->desc_pool.alloc_size = 0;
+ adapter->desc_pool.alloc_virt = NULL;
+
+ kfree(hw->rx_desc_info.ring);
+ hw->rx_desc_info.ring = NULL;
+ kfree(hw->tx_desc_info.ring);
+ hw->tx_desc_info.ring = NULL;
+}
+
+/**
+ * ksz_free_buffers - free buffers used in the descriptors
+ * @adapter: Adapter information structure.
+ * @desc_info: Descriptor information structure.
+ *
+ * This local routine frees buffers used in the DMA buffers.
+ */
+static void ksz_free_buffers(struct dev_info *adapter,
+ struct ksz_desc_info *desc_info, int direction)
+{
+ int i;
+ struct ksz_dma_buf *dma_buf;
+ struct ksz_desc *desc = desc_info->ring;
+
+ for (i = 0; i < desc_info->alloc; i++) {
+ dma_buf = DMA_BUFFER(desc);
+ if (dma_buf->skb)
+ free_dma_buf(adapter, dma_buf, direction);
+ desc++;
+ }
+}
+
+/**
+ * ksz_free_mem - free all resources used by descriptors
+ * @adapter: Adapter information structure.
+ *
+ * This local routine frees all the resources allocated by ksz_alloc_mem().
+ */
+static void ksz_free_mem(struct dev_info *adapter)
+{
+ /* Free transmit buffers. */
+ ksz_free_buffers(adapter, &adapter->hw.tx_desc_info,
+ PCI_DMA_TODEVICE);
+
+ /* Free receive buffers. */
+ ksz_free_buffers(adapter, &adapter->hw.rx_desc_info,
+ PCI_DMA_FROMDEVICE);
+
+ /* Free descriptors. */
+ ksz_free_desc(adapter);
+}
+
+static void get_mib_counters(struct ksz_hw *hw, int first, int cnt,
+ u64 *counter)
+{
+ int i;
+ int mib;
+ int port;
+ struct ksz_port_mib *port_mib;
+
+ memset(counter, 0, sizeof(u64) * TOTAL_PORT_COUNTER_NUM);
+ for (i = 0, port = first; i < cnt; i++, port++) {
+ port_mib = &hw->port_mib[port];
+ for (mib = port_mib->mib_start; mib < hw->mib_cnt; mib++)
+ counter[mib] += port_mib->counter[mib];
+ }
+}
+
+/**
+ * send_packet - send packet
+ * @skb: Socket buffer.
+ * @dev: Network device.
+ *
+ * This routine is used to send a packet out to the network.
+ */
+static void send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ksz_desc *desc;
+ struct ksz_desc *first;
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ struct ksz_desc_info *info = &hw->tx_desc_info;
+ struct ksz_dma_buf *dma_buf;
+ int len;
+ int last_frag = skb_shinfo(skb)->nr_frags;
+
+ /*
+ * KSZ8842 with multiple device interfaces needs to be told which port
+ * to send.
+ */
+ if (hw->dev_count > 1)
+ hw->dst_ports = 1 << priv->port.first_port;
+
+ /* Hardware will pad the length to 60. */
+ len = skb->len;
+
+ /* Remember the very first descriptor. */
+ first = info->cur;
+ desc = first;
+
+ dma_buf = DMA_BUFFER(desc);
+ if (last_frag) {
+ int frag;
+ skb_frag_t *this_frag;
+
+ dma_buf->len = skb->len - skb->data_len;
+
+ dma_buf->dma = pci_map_single(
+ hw_priv->pdev, skb->data, dma_buf->len,
+ PCI_DMA_TODEVICE);
+ set_tx_buf(desc, dma_buf->dma);
+ set_tx_len(desc, dma_buf->len);
+
+ frag = 0;
+ do {
+ this_frag = &skb_shinfo(skb)->frags[frag];
+
+ /* Get a new descriptor. */
+ get_tx_pkt(info, &desc);
+
+ /* Keep track of descriptors used so far. */
+ ++hw->tx_int_cnt;
+
+ dma_buf = DMA_BUFFER(desc);
+ dma_buf->len = this_frag->size;
+
+ dma_buf->dma = pci_map_single(
+ hw_priv->pdev,
+ page_address(this_frag->page) +
+ this_frag->page_offset,
+ dma_buf->len,
+ PCI_DMA_TODEVICE);
+ set_tx_buf(desc, dma_buf->dma);
+ set_tx_len(desc, dma_buf->len);
+
+ frag++;
+ if (frag == last_frag)
+ break;
+
+ /* Do not release the last descriptor here. */
+ release_desc(desc);
+ } while (1);
+
+ /* current points to the last descriptor. */
+ info->cur = desc;
+
+ /* Release the first descriptor. */
+ release_desc(first);
+ } else {
+ dma_buf->len = len;
+
+ dma_buf->dma = pci_map_single(
+ hw_priv->pdev, skb->data, dma_buf->len,
+ PCI_DMA_TODEVICE);
+ set_tx_buf(desc, dma_buf->dma);
+ set_tx_len(desc, dma_buf->len);
+ }
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ (desc)->sw.buf.tx.csum_gen_tcp = 1;
+ (desc)->sw.buf.tx.csum_gen_udp = 1;
+ }
+
+ /*
+ * The last descriptor holds the packet so that it can be returned to
+ * network subsystem after all descriptors are transmitted.
+ */
+ dma_buf->skb = skb;
+
+ hw_send_pkt(hw);
+
+ /* Update transmit statistics. */
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += len;
+}
+
+/**
+ * transmit_cleanup - clean up transmit descriptors
+ * @dev: Network device.
+ *
+ * This routine is called to clean up the transmitted buffers.
+ */
+static void transmit_cleanup(struct dev_info *hw_priv, int normal)
+{
+ int last;
+ union desc_stat status;
+ struct ksz_hw *hw = &hw_priv->hw;
+ struct ksz_desc_info *info = &hw->tx_desc_info;
+ struct ksz_desc *desc;
+ struct ksz_dma_buf *dma_buf;
+ struct net_device *dev = NULL;
+
+ spin_lock(&hw_priv->hwlock);
+ last = info->last;
+
+ while (info->avail < info->alloc) {
+ /* Get next descriptor which is not hardware owned. */
+ desc = &info->ring[last];
+ status.data = le32_to_cpu(desc->phw->ctrl.data);
+ if (status.tx.hw_owned) {
+ if (normal)
+ break;
+ else
+ reset_desc(desc, status);
+ }
+
+ dma_buf = DMA_BUFFER(desc);
+ pci_unmap_single(
+ hw_priv->pdev, dma_buf->dma, dma_buf->len,
+ PCI_DMA_TODEVICE);
+
+ /* This descriptor contains the last buffer in the packet. */
+ if (dma_buf->skb) {
+ dev = dma_buf->skb->dev;
+
+ /* Release the packet back to network subsystem. */
+ dev_kfree_skb_irq(dma_buf->skb);
+ dma_buf->skb = NULL;
+ }
+
+ /* Free the transmitted descriptor. */
+ last++;
+ last &= info->mask;
+ info->avail++;
+ }
+ info->last = last;
+ spin_unlock(&hw_priv->hwlock);
+
+ /* Notify the network subsystem that the packet has been sent. */
+ if (dev)
+ dev->trans_start = jiffies;
+}
+
+/**
+ * transmit_done - transmit done processing
+ * @dev: Network device.
+ *
+ * This routine is called when the transmit interrupt is triggered, indicating
+ * either a packet is sent successfully or there are transmit errors.
+ */
+static void tx_done(struct dev_info *hw_priv)
+{
+ struct ksz_hw *hw = &hw_priv->hw;
+ int port;
+
+ transmit_cleanup(hw_priv, 1);
+
+ for (port = 0; port < hw->dev_count; port++) {
+ struct net_device *dev = hw->port_info[port].pdev;
+
+ if (netif_running(dev) && netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+ }
+}
+
+static inline void copy_old_skb(struct sk_buff *old, struct sk_buff *skb)
+{
+ skb->dev = old->dev;
+ skb->protocol = old->protocol;
+ skb->ip_summed = old->ip_summed;
+ skb->csum = old->csum;
+ skb_set_network_header(skb, ETH_HLEN);
+
+ dev_kfree_skb(old);
+}
+
+/**
+ * netdev_tx - send out packet
+ * @skb: Socket buffer.
+ * @dev: Network device.
+ *
+ * This function is used by the upper network layer to send out a packet.
+ *
+ * Return 0 if successful; otherwise an error code indicating failure.
+ */
+static int netdev_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ int left;
+ int num = 1;
+ int rc = 0;
+
+ if (hw->features & SMALL_PACKET_TX_BUG) {
+ struct sk_buff *org_skb = skb;
+
+ if (skb->len <= 48) {
+ if (skb_end_pointer(skb) - skb->data >= 50) {
+ memset(&skb->data[skb->len], 0, 50 - skb->len);
+ skb->len = 50;
+ } else {
+ skb = dev_alloc_skb(50);
+ if (!skb)
+ return NETDEV_TX_BUSY;
+ memcpy(skb->data, org_skb->data, org_skb->len);
+ memset(&skb->data[org_skb->len], 0,
+ 50 - org_skb->len);
+ skb->len = 50;
+ copy_old_skb(org_skb, skb);
+ }
+ }
+ }
+
+ spin_lock_irq(&hw_priv->hwlock);
+
+ num = skb_shinfo(skb)->nr_frags + 1;
+ left = hw_alloc_pkt(hw, skb->len, num);
+ if (left) {
+ if (left < num ||
+ ((hw->features & IPV6_CSUM_GEN_HACK) &&
+ (CHECKSUM_PARTIAL == skb->ip_summed) &&
+ (ETH_P_IPV6 == htons(skb->protocol)))) {
+ struct sk_buff *org_skb = skb;
+
+ skb = dev_alloc_skb(org_skb->len);
+ if (!skb)
+ return NETDEV_TX_BUSY;
+ skb_copy_and_csum_dev(org_skb, skb->data);
+ org_skb->ip_summed = 0;
+ skb->len = org_skb->len;
+ copy_old_skb(org_skb, skb);
+ }
+ send_packet(skb, dev);
+ if (left <= num)
+ netif_stop_queue(dev);
+ } else {
+ /* Stop the transmit queue until packet is allocated. */
+ netif_stop_queue(dev);
+ rc = NETDEV_TX_BUSY;
+ }
+
+ spin_unlock_irq(&hw_priv->hwlock);
+
+ return rc;
+}
+
+/**
+ * netdev_tx_timeout - transmit timeout processing
+ * @dev: Network device.
+ *
+ * This routine is called when the transmit timer expires. That indicates the
+ * hardware is not running correctly because transmit interrupts are not
+ * triggered to free up resources so that the transmit routine can continue
+ * sending out packets. The hardware is reset to correct the problem.
+ */
+static void netdev_tx_timeout(struct net_device *dev)
+{
+ static unsigned long last_reset;
+
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ int port;
+
+ if (hw->dev_count > 1) {
+ /*
+ * Only reset the hardware if time between calls is long
+ * enough.
+ */
+ if (jiffies - last_reset <= dev->watchdog_timeo)
+ hw_priv = NULL;
+ }
+
+ last_reset = jiffies;
+ if (hw_priv) {
+ hw_dis_intr(hw);
+ hw_disable(hw);
+
+ transmit_cleanup(hw_priv, 0);
+ hw_reset_pkts(&hw->rx_desc_info);
+ hw_reset_pkts(&hw->tx_desc_info);
+ ksz_init_rx_buffers(hw_priv);
+
+ hw_reset(hw);
+
+ hw_set_desc_base(hw,
+ hw->tx_desc_info.ring_phys,
+ hw->rx_desc_info.ring_phys);
+ hw_set_addr(hw);
+ if (hw->all_multi)
+ hw_set_multicast(hw, hw->all_multi);
+ else if (hw->multi_list_size)
+ hw_set_grp_addr(hw);
+
+ if (hw->dev_count > 1) {
+ hw_set_add_addr(hw);
+ for (port = 0; port < SWITCH_PORT_NUM; port++) {
+ struct net_device *port_dev;
+
+ port_set_stp_state(hw, port,
+ STP_STATE_DISABLED);
+
+ port_dev = hw->port_info[port].pdev;
+ if (netif_running(port_dev))
+ port_set_stp_state(hw, port,
+ STP_STATE_SIMPLE);
+ }
+ }
+
+ hw_enable(hw);
+ hw_ena_intr(hw);
+ }
+
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
+
+static inline void csum_verified(struct sk_buff *skb)
+{
+ unsigned short protocol;
+ struct iphdr *iph;
+
+ protocol = skb->protocol;
+ skb_reset_network_header(skb);
+ iph = (struct iphdr *) skb_network_header(skb);
+ if (protocol == htons(ETH_P_8021Q)) {
+ protocol = iph->tot_len;
+ skb_set_network_header(skb, VLAN_HLEN);
+ iph = (struct iphdr *) skb_network_header(skb);
+ }
+ if (protocol == htons(ETH_P_IP)) {
+ if (iph->protocol == IPPROTO_TCP)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+}
+
+static inline int rx_proc(struct net_device *dev, struct ksz_hw* hw,
+ struct ksz_desc *desc, union desc_stat status)
+{
+ int packet_len;
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_dma_buf *dma_buf;
+ struct sk_buff *skb;
+ int rx_status;
+
+ /* Received length includes 4-byte CRC. */
+ packet_len = status.rx.frame_len - 4;
+
+ dma_buf = DMA_BUFFER(desc);
+ pci_dma_sync_single_for_cpu(
+ hw_priv->pdev, dma_buf->dma, packet_len + 4,
+ PCI_DMA_FROMDEVICE);
+
+ do {
+ /* skb->data != skb->head */
+ skb = dev_alloc_skb(packet_len + 2);
+ if (!skb) {
+ priv->stats.rx_dropped++;
+ return -ENOMEM;
+ }
+
+ /*
+ * Align socket buffer in 4-byte boundary for better
+ * performance.
+ */
+ skb_reserve(skb, 2);
+
+ memcpy(skb_put(skb, packet_len),
+ dma_buf->skb->data, packet_len);
+ } while (0);
+
+ skb->dev = dev;
+
+ skb->protocol = eth_type_trans(skb, dev);
+
+ if (hw->rx_cfg & (DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP))
+ csum_verified(skb);
+
+ /* Update receive statistics. */
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += packet_len;
+
+ /* Notify upper layer for received packet. */
+ dev->last_rx = jiffies;
+
+ rx_status = netif_rx(skb);
+
+ return 0;
+}
+
+static int dev_rcv_packets(struct dev_info *hw_priv)
+{
+ int next;
+ union desc_stat status;
+ struct ksz_hw *hw = &hw_priv->hw;
+ struct net_device *dev = hw->port_info[0].pdev;
+ struct ksz_desc_info *info = &hw->rx_desc_info;
+ int left = info->alloc;
+ struct ksz_desc *desc;
+ int received = 0;
+
+ next = info->next;
+ while (left--) {
+ /* Get next descriptor which is not hardware owned. */
+ desc = &info->ring[next];
+ status.data = le32_to_cpu(desc->phw->ctrl.data);
+ if (status.rx.hw_owned)
+ break;
+
+ /* Status valid only when last descriptor bit is set. */
+ if (status.rx.last_desc && status.rx.first_desc) {
+ if (rx_proc(dev, hw, desc, status))
+ goto release_packet;
+ received++;
+ }
+
+release_packet:
+ release_desc(desc);
+ next++;
+ next &= info->mask;
+ }
+ info->next = next;
+
+ return received;
+}
+
+static int port_rcv_packets(struct dev_info *hw_priv)
+{
+ int next;
+ union desc_stat status;
+ struct ksz_hw *hw = &hw_priv->hw;
+ struct net_device *dev = hw->port_info[0].pdev;
+ struct ksz_desc_info *info = &hw->rx_desc_info;
+ int left = info->alloc;
+ struct ksz_desc *desc;
+ int received = 0;
+
+ next = info->next;
+ while (left--) {
+ /* Get next descriptor which is not hardware owned. */
+ desc = &info->ring[next];
+ status.data = le32_to_cpu(desc->phw->ctrl.data);
+ if (status.rx.hw_owned)
+ break;
+
+ if (hw->dev_count > 1) {
+ /* Get received port number. */
+ int p = HW_TO_DEV_PORT(status.rx.src_port);
+
+ dev = hw->port_info[p].pdev;
+ if (!netif_running(dev))
+ goto release_packet;
+ }
+
+ /* Status valid only when last descriptor bit is set. */
+ if (status.rx.last_desc && status.rx.first_desc) {
+ if (rx_proc(dev, hw, desc, status))
+ goto release_packet;
+ received++;
+ }
+
+release_packet:
+ release_desc(desc);
+ next++;
+ next &= info->mask;
+ }
+ info->next = next;
+
+ return received;
+}
+
+static int dev_rcv_special(struct dev_info *hw_priv)
+{
+ int next;
+ union desc_stat status;
+ struct ksz_hw *hw = &hw_priv->hw;
+ struct net_device *dev = hw->port_info[0].pdev;
+ struct ksz_desc_info *info = &hw->rx_desc_info;
+ int left = info->alloc;
+ struct ksz_desc *desc;
+ int received = 0;
+
+ next = info->next;
+ while (left--) {
+ /* Get next descriptor which is not hardware owned. */
+ desc = &info->ring[next];
+ status.data = le32_to_cpu(desc->phw->ctrl.data);
+ if (status.rx.hw_owned)
+ break;
+
+ if (hw->dev_count > 1) {
+ /* Get received port number. */
+ int p = HW_TO_DEV_PORT(status.rx.src_port);
+
+ dev = hw->port_info[p].pdev;
+ if (!netif_running(dev))
+ goto release_packet;
+ }
+
+ /* Status valid only when last descriptor bit is set. */
+ if (status.rx.last_desc && status.rx.first_desc) {
+ /*
+ * Receive without error. With receive errors
+ * disabled, packets with receive errors will be
+ * dropped, so no need to check the error bit.
+ */
+ if (!status.rx.error || (status.data &
+ KS_DESC_RX_ERROR_COND) ==
+ KS_DESC_RX_ERROR_TOO_LONG) {
+ if (rx_proc(dev, hw, desc, status))
+ goto release_packet;
+ received++;
+ } else {
+ struct dev_priv *priv = netdev_priv(dev);
+
+ /* Update receive error statistics. */
+ priv->port.counter[OID_COUNTER_RCV_ERROR]++;
+ }
+ }
+
+release_packet:
+ release_desc(desc);
+ next++;
+ next &= info->mask;
+ }
+ info->next = next;
+
+ return received;
+}
+
+static void rx_proc_task(unsigned long data)
+{
+ struct dev_info *hw_priv = (struct dev_info *) data;
+ struct ksz_hw *hw = &hw_priv->hw;
+
+ if (!hw->enabled)
+ return;
+ if (unlikely(!hw_priv->dev_rcv(hw_priv))) {
+
+ /* In case receive process is suspended because of overrun. */
+ hw_resume_rx(hw);
+
+ /* tasklets are interruptible. */
+ spin_lock_irq(&hw_priv->hwlock);
+ hw_turn_on_intr(hw, KS884X_INT_RX_MASK);
+ spin_unlock_irq(&hw_priv->hwlock);
+ } else {
+ hw_ack_intr(hw, KS884X_INT_RX);
+ tasklet_schedule(&hw_priv->rx_tasklet);
+ }
+}
+
+static void tx_proc_task(unsigned long data)
+{
+ struct dev_info *hw_priv = (struct dev_info *) data;
+ struct ksz_hw *hw = &hw_priv->hw;
+
+ hw_ack_intr(hw, KS884X_INT_TX_MASK);
+
+ tx_done(hw_priv);
+
+ /* tasklets are interruptible. */
+ spin_lock_irq(&hw_priv->hwlock);
+ hw_turn_on_intr(hw, KS884X_INT_TX);
+ spin_unlock_irq(&hw_priv->hwlock);
+}
+
+static inline void handle_rx_stop(struct ksz_hw *hw)
+{
+ /* Receive just has been stopped. */
+ if (0 == hw->rx_stop)
+ hw->intr_mask &= ~KS884X_INT_RX_STOPPED;
+ else if (hw->rx_stop > 1) {
+ if (hw->enabled && (hw->rx_cfg & DMA_RX_ENABLE)) {
+ hw_start_rx(hw);
+ } else {
+ hw->intr_mask &= ~KS884X_INT_RX_STOPPED;
+ hw->rx_stop = 0;
+ }
+ } else
+ /* Receive just has been started. */
+ hw->rx_stop++;
+}
+
+/**
+ * netdev_intr - interrupt handling
+ * @irq: Interrupt number.
+ * @dev_id: Network device.
+ *
+ * This function is called by upper network layer to signal interrupt.
+ *
+ * Return IRQ_HANDLED if interrupt is handled.
+ */
+static irqreturn_t netdev_intr(int irq, void *dev_id)
+{
+ uint int_enable = 0;
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+
+ hw_read_intr(hw, &int_enable);
+
+ /* Not our interrupt! */
+ if (!int_enable)
+ return IRQ_NONE;
+
+ do {
+ hw_ack_intr(hw, int_enable);
+ int_enable &= hw->intr_mask;
+
+ if (unlikely(int_enable & KS884X_INT_TX_MASK)) {
+ hw_dis_intr_bit(hw, KS884X_INT_TX_MASK);
+ tasklet_schedule(&hw_priv->tx_tasklet);
+ }
+
+ if (likely(int_enable & KS884X_INT_RX)) {
+ hw_dis_intr_bit(hw, KS884X_INT_RX);
+ tasklet_schedule(&hw_priv->rx_tasklet);
+ }
+
+ if (unlikely(int_enable & KS884X_INT_RX_OVERRUN)) {
+ priv->stats.rx_fifo_errors++;
+ hw_resume_rx(hw);
+ }
+
+ if (unlikely(int_enable & KS884X_INT_PHY)) {
+ struct ksz_port *port = &priv->port;
+
+ hw->features |= LINK_INT_WORKING;
+ port_get_link_speed(port);
+ }
+
+ if (unlikely(int_enable & KS884X_INT_RX_STOPPED)) {
+ handle_rx_stop(hw);
+ break;
+ }
+
+ if (unlikely(int_enable & KS884X_INT_TX_STOPPED)) {
+ u32 data;
+
+ hw->intr_mask &= ~KS884X_INT_TX_STOPPED;
+ printk(KERN_INFO "Tx stopped\n");
+ data = readl(hw->io + KS_DMA_TX_CTRL);
+ if (!(data & DMA_TX_ENABLE))
+ printk(KERN_INFO "Tx disabled\n");
+ break;
+ }
+ } while (0);
+
+ hw_ena_intr(hw);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Linux network device functions
+ */
+
+static unsigned long next_jiffies;
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void netdev_netpoll(struct net_device *dev)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+
+ hw_dis_intr(&hw_priv->hw);
+ netdev_intr(dev->irq, dev);
+}
+#endif
+
+static void bridge_change(struct ksz_hw *hw)
+{
+ int port;
+ u8 member;
+ struct ksz_switch *sw = hw->ksz_switch;
+
+ /* No ports in forwarding state. */
+ if (!sw->member) {
+ port_set_stp_state(hw, SWITCH_PORT_NUM, STP_STATE_SIMPLE);
+ sw_block_addr(hw);
+ }
+ for (port = 0; port < SWITCH_PORT_NUM; port++) {
+ if (STP_STATE_FORWARDING == sw->port_cfg[port].stp_state)
+ member = HOST_MASK | sw->member;
+ else
+ member = HOST_MASK | (1 << port);
+ if (member != sw->port_cfg[port].member)
+ sw_cfg_port_base_vlan(hw, port, member);
+ }
+}
+
+/**
+ * netdev_close - close network device
+ * @dev: Network device.
+ *
+ * This function process the close operation of network device. This is caused
+ * by the user command "ifconfig ethX down."
+ *
+ * Return 0 if successful; otherwise an error code indicating failure.
+ */
+static int netdev_close(struct net_device *dev)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_port *port = &priv->port;
+ struct ksz_hw *hw = &hw_priv->hw;
+ int pi;
+
+ netif_stop_queue(dev);
+
+ ksz_stop_timer(&priv->monitor_timer_info);
+
+ /* Need to shut the port manually in multiple device interfaces mode. */
+ if (hw->dev_count > 1) {
+ port_set_stp_state(hw, port->first_port, STP_STATE_DISABLED);
+
+ /* Port is closed. Need to change bridge setting. */
+ if (hw->features & STP_SUPPORT) {
+ pi = 1 << port->first_port;
+ if (hw->ksz_switch->member & pi) {
+ hw->ksz_switch->member &= ~pi;
+ bridge_change(hw);
+ }
+ }
+ }
+ if (port->first_port > 0)
+ hw_del_addr(hw, dev->dev_addr);
+ if (!hw_priv->wol_enable)
+ port_set_power_saving(port, true);
+
+ if (priv->multicast)
+ --hw->all_multi;
+ if (priv->promiscuous)
+ --hw->promiscuous;
+
+ hw_priv->opened--;
+ if (!(hw_priv->opened)) {
+ ksz_stop_timer(&hw_priv->mib_timer_info);
+ flush_work(&hw_priv->mib_read);
+
+ hw_dis_intr(hw);
+ hw_disable(hw);
+ hw_clr_multicast(hw);
+
+ /* Delay for receive task to stop scheduling itself. */
+ msleep(2000 / HZ);
+
+ tasklet_disable(&hw_priv->rx_tasklet);
+ tasklet_disable(&hw_priv->tx_tasklet);
+ free_irq(dev->irq, hw_priv->dev);
+
+ transmit_cleanup(hw_priv, 0);
+ hw_reset_pkts(&hw->rx_desc_info);
+ hw_reset_pkts(&hw->tx_desc_info);
+
+ /* Clean out static MAC table when the switch is shutdown. */
+ if (hw->features & STP_SUPPORT)
+ sw_clr_sta_mac_table(hw);
+ }
+
+ return 0;
+}
+
+static void hw_cfg_huge_frame(struct dev_info *hw_priv, struct ksz_hw *hw)
+{
+ if (hw->ksz_switch) {
+ u32 data;
+
+ data = readw(hw->io + KS8842_SWITCH_CTRL_2_OFFSET);
+ if (hw->features & RX_HUGE_FRAME)
+ data |= SWITCH_HUGE_PACKET;
+ else
+ data &= ~SWITCH_HUGE_PACKET;
+ writew(data, hw->io + KS8842_SWITCH_CTRL_2_OFFSET);
+ }
+ if (hw->features & RX_HUGE_FRAME) {
+ hw->rx_cfg |= DMA_RX_ERROR;
+ hw_priv->dev_rcv = dev_rcv_special;
+ } else {
+ hw->rx_cfg &= ~DMA_RX_ERROR;
+ if (hw->dev_count > 1)
+ hw_priv->dev_rcv = port_rcv_packets;
+ else
+ hw_priv->dev_rcv = dev_rcv_packets;
+ }
+}
+
+static int prepare_hardware(struct net_device *dev)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ int rc = 0;
+
+ /* Remember the network device that requests interrupts. */
+ hw_priv->dev = dev;
+ rc = request_irq(dev->irq, netdev_intr, IRQF_SHARED, dev->name, dev);
+ if (rc)
+ return rc;
+ tasklet_enable(&hw_priv->rx_tasklet);
+ tasklet_enable(&hw_priv->tx_tasklet);
+
+ hw->promiscuous = 0;
+ hw->all_multi = 0;
+ hw->multi_list_size = 0;
+
+ hw_reset(hw);
+
+ hw_set_desc_base(hw,
+ hw->tx_desc_info.ring_phys, hw->rx_desc_info.ring_phys);
+ hw_set_addr(hw);
+ hw_cfg_huge_frame(hw_priv, hw);
+ ksz_init_rx_buffers(hw_priv);
+ return 0;
+}
+
+/**
+ * netdev_open - open network device
+ * @dev: Network device.
+ *
+ * This function process the open operation of network device. This is caused
+ * by the user command "ifconfig ethX up."
+ *
+ * Return 0 if successful; otherwise an error code indicating failure.
+ */
+static int netdev_open(struct net_device *dev)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ struct ksz_port *port = &priv->port;
+ int i;
+ int p;
+ int rc = 0;
+
+ priv->multicast = 0;
+ priv->promiscuous = 0;
+
+ /* Reset device statistics. */
+ memset(&priv->stats, 0, sizeof(struct net_device_stats));
+ memset((void *) port->counter, 0,
+ (sizeof(u64) * OID_COUNTER_LAST));
+
+ if (!(hw_priv->opened)) {
+ rc = prepare_hardware(dev);
+ if (rc)
+ return rc;
+ for (i = 0; i < hw->mib_port_cnt; i++) {
+ if (next_jiffies < jiffies)
+ next_jiffies = jiffies + HZ * 2;
+ else
+ next_jiffies += HZ * 1;
+ hw_priv->counter[i].time = next_jiffies;
+ hw->port_mib[i].state = media_disconnected;
+ port_init_cnt(hw, i);
+ }
+ if (hw->ksz_switch)
+ hw->port_mib[HOST_PORT].state = media_connected;
+ else {
+ hw_add_wol_bcast(hw);
+ hw_cfg_wol_pme(hw, 0);
+ hw_clr_wol_pme_status(&hw_priv->hw);
+ }
+ }
+ port_set_power_saving(port, false);
+
+ for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) {
+ /*
+ * Initialize to invalid value so that link detection
+ * is done.
+ */
+ hw->port_info[p].partner = 0xFF;
+ hw->port_info[p].state = media_disconnected;
+ }
+
+ /* Need to open the port in multiple device interfaces mode. */
+ if (hw->dev_count > 1) {
+ port_set_stp_state(hw, port->first_port, STP_STATE_SIMPLE);
+ if (port->first_port > 0)
+ hw_add_addr(hw, dev->dev_addr);
+ }
+
+ port_get_link_speed(port);
+ if (port->force_link)
+ port_force_link_speed(port);
+ else
+ port_set_link_speed(port);
+
+ if (!(hw_priv->opened)) {
+ hw_setup_intr(hw);
+ hw_enable(hw);
+ hw_ena_intr(hw);
+
+ if (hw->mib_port_cnt)
+ ksz_start_timer(&hw_priv->mib_timer_info,
+ hw_priv->mib_timer_info.period);
+ }
+
+ hw_priv->opened++;
+
+ ksz_start_timer(&priv->monitor_timer_info,
+ priv->monitor_timer_info.period);
+
+ priv->media_state = port->linked->state;
+
+ if (media_connected == priv->media_state)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s link %s\n", dev->name,
+ (media_connected == priv->media_state ?
+ "on" : "off"));
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+/* RX errors = rx_errors */
+/* RX dropped = rx_dropped */
+/* RX overruns = rx_fifo_errors */
+/* RX frame = rx_crc_errors + rx_frame_errors + rx_length_errors */
+/* TX errors = tx_errors */
+/* TX dropped = tx_dropped */
+/* TX overruns = tx_fifo_errors */
+/* TX carrier = tx_aborted_errors + tx_carrier_errors + tx_window_errors */
+/* collisions = collisions */
+
+/**
+ * netdev_query_statistics - query network device statistics
+ * @dev: Network device.
+ *
+ * This function returns the statistics of the network device. The device
+ * needs not be opened.
+ *
+ * Return network device statistics.
+ */
+static struct net_device_stats *netdev_query_statistics(struct net_device *dev)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct ksz_port *port = &priv->port;
+ struct ksz_hw *hw = &priv->adapter->hw;
+ struct ksz_port_mib *mib;
+ int i;
+ int p;
+
+ priv->stats.rx_errors = port->counter[OID_COUNTER_RCV_ERROR];
+ priv->stats.tx_errors = port->counter[OID_COUNTER_XMIT_ERROR];
+
+ /* Reset to zero to add count later. */
+ priv->stats.multicast = 0;
+ priv->stats.collisions = 0;
+ priv->stats.rx_length_errors = 0;
+ priv->stats.rx_crc_errors = 0;
+ priv->stats.rx_frame_errors = 0;
+ priv->stats.tx_window_errors = 0;
+
+ for (i = 0, p = port->first_port; i < port->mib_port_cnt; i++, p++) {
+ mib = &hw->port_mib[p];
+
+ priv->stats.multicast += (unsigned long)
+ mib->counter[MIB_COUNTER_RX_MULTICAST];
+
+ priv->stats.collisions += (unsigned long)
+ mib->counter[MIB_COUNTER_TX_TOTAL_COLLISION];
+
+ priv->stats.rx_length_errors += (unsigned long)(
+ mib->counter[MIB_COUNTER_RX_UNDERSIZE] +
+ mib->counter[MIB_COUNTER_RX_FRAGMENT] +
+ mib->counter[MIB_COUNTER_RX_OVERSIZE] +
+ mib->counter[MIB_COUNTER_RX_JABBER]);
+ priv->stats.rx_crc_errors += (unsigned long)
+ mib->counter[MIB_COUNTER_RX_CRC_ERR];
+ priv->stats.rx_frame_errors += (unsigned long)(
+ mib->counter[MIB_COUNTER_RX_ALIGNMENT_ERR] +
+ mib->counter[MIB_COUNTER_RX_SYMBOL_ERR]);
+
+ priv->stats.tx_window_errors += (unsigned long)
+ mib->counter[MIB_COUNTER_TX_LATE_COLLISION];
+ }
+
+ return &priv->stats;
+}
+
+/**
+ * netdev_set_mac_address - set network device MAC address
+ * @dev: Network device.
+ * @addr: Buffer of MAC address.
+ *
+ * This function is used to set the MAC address of the network device.
+ *
+ * Return 0 to indicate success.
+ */
+static int netdev_set_mac_address(struct net_device *dev, void *addr)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ struct sockaddr *mac = addr;
+ uint interrupt;
+
+ if (priv->port.first_port > 0)
+ hw_del_addr(hw, dev->dev_addr);
+ else {
+ hw->mac_override = 1;
+ memcpy(hw->override_addr, mac->sa_data, MAC_ADDR_LEN);
+ }
+
+ memcpy(dev->dev_addr, mac->sa_data, MAX_ADDR_LEN);
+
+ interrupt = hw_block_intr(hw);
+
+ if (priv->port.first_port > 0)
+ hw_add_addr(hw, dev->dev_addr);
+ else
+ hw_set_addr(hw);
+ hw_restore_intr(hw, interrupt);
+
+ return 0;
+}
+
+static void dev_set_promiscuous(struct net_device *dev, struct dev_priv *priv,
+ struct ksz_hw *hw, int promiscuous)
+{
+ if (promiscuous != priv->promiscuous) {
+ u8 prev_state = hw->promiscuous;
+
+ if (promiscuous)
+ ++hw->promiscuous;
+ else
+ --hw->promiscuous;
+ priv->promiscuous = promiscuous;
+
+ /* Turn on/off promiscuous mode. */
+ if (hw->promiscuous <= 1 && prev_state <= 1)
+ hw_set_promiscuous(hw, hw->promiscuous);
+
+ /*
+ * Port is not in promiscuous mode, meaning it is released
+ * from the bridge.
+ */
+ if ((hw->features & STP_SUPPORT) && !promiscuous &&
+ dev->br_port) {
+ struct ksz_switch *sw = hw->ksz_switch;
+ int port = priv->port.first_port;
+
+ port_set_stp_state(hw, port, STP_STATE_DISABLED);
+ port = 1 << port;
+ if (sw->member & port) {
+ sw->member &= ~port;
+ bridge_change(hw);
+ }
+ }
+ }
+}
+
+static void dev_set_multicast(struct dev_priv *priv, struct ksz_hw *hw,
+ int multicast)
+{
+ if (multicast != priv->multicast) {
+ u8 all_multi = hw->all_multi;
+
+ if (multicast)
+ ++hw->all_multi;
+ else
+ --hw->all_multi;
+ priv->multicast = multicast;
+
+ /* Turn on/off all multicast mode. */
+ if (hw->all_multi <= 1 && all_multi <= 1)
+ hw_set_multicast(hw, hw->all_multi);
+ }
+}
+
+/**
+ * netdev_set_rx_mode
+ * @dev: Network device.
+ *
+ * This routine is used to set multicast addresses or put the network device
+ * into promiscuous mode.
+ */
+static void netdev_set_rx_mode(struct net_device *dev)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ struct dev_mc_list *mc_ptr;
+ int multicast = (dev->flags & IFF_ALLMULTI);
+
+ dev_set_promiscuous(dev, priv, hw, (dev->flags & IFF_PROMISC));
+
+ if (hw_priv->hw.dev_count > 1)
+ multicast |= (dev->flags & IFF_MULTICAST);
+ dev_set_multicast(priv, hw, multicast);
+
+ /* Cannot use different hashes in multiple device interfaces mode. */
+ if (hw_priv->hw.dev_count > 1)
+ return;
+
+ if ((dev->flags & IFF_MULTICAST) && !netdev_mc_empty(dev)) {
+ int i = 0;
+
+ /* List too big to support so turn on all multicast mode. */
+ if (dev->mc_count > MAX_MULTICAST_LIST) {
+ if (MAX_MULTICAST_LIST != hw->multi_list_size) {
+ hw->multi_list_size = MAX_MULTICAST_LIST;
+ ++hw->all_multi;
+ hw_set_multicast(hw, hw->all_multi);
+ }
+ return;
+ }
+
+ netdev_for_each_mc_addr(mc_ptr, dev) {
+ if (!(*mc_ptr->dmi_addr & 1))
+ continue;
+ if (i >= MAX_MULTICAST_LIST)
+ break;
+ memcpy(hw->multi_list[i++], mc_ptr->dmi_addr,
+ MAC_ADDR_LEN);
+ }
+ hw->multi_list_size = (u8) i;
+ hw_set_grp_addr(hw);
+ } else {
+ if (MAX_MULTICAST_LIST == hw->multi_list_size) {
+ --hw->all_multi;
+ hw_set_multicast(hw, hw->all_multi);
+ }
+ hw->multi_list_size = 0;
+ hw_clr_multicast(hw);
+ }
+}
+
+static int netdev_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ int hw_mtu;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ /* Cannot use different MTU in multiple device interfaces mode. */
+ if (hw->dev_count > 1)
+ if (dev != hw_priv->dev)
+ return 0;
+ if (new_mtu < 60)
+ return -EINVAL;
+
+ if (dev->mtu != new_mtu) {
+ hw_mtu = new_mtu + ETHERNET_HEADER_SIZE + 4;
+ if (hw_mtu > MAX_RX_BUF_SIZE)
+ return -EINVAL;
+ if (hw_mtu > REGULAR_RX_BUF_SIZE) {
+ hw->features |= RX_HUGE_FRAME;
+ hw_mtu = MAX_RX_BUF_SIZE;
+ } else {
+ hw->features &= ~RX_HUGE_FRAME;
+ hw_mtu = REGULAR_RX_BUF_SIZE;
+ }
+ hw_mtu = (hw_mtu + 3) & ~3;
+ hw_priv->mtu = hw_mtu;
+ dev->mtu = new_mtu;
+ }
+ return 0;
+}
+
+/**
+ * netdev_ioctl - I/O control processing
+ * @dev: Network device.
+ * @ifr: Interface request structure.
+ * @cmd: I/O control code.
+ *
+ * This function is used to process I/O control calls.
+ *
+ * Return 0 to indicate success.
+ */
+static int netdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ struct ksz_port *port = &priv->port;
+ int rc;
+ int result = 0;
+ struct mii_ioctl_data *data = if_mii(ifr);
+
+ if (down_interruptible(&priv->proc_sem))
+ return -ERESTARTSYS;
+
+ /* assume success */
+ rc = 0;
+ switch (cmd) {
+ /* Get address of MII PHY in use. */
+ case SIOCGMIIPHY:
+ data->phy_id = priv->id;
+
+ /* Fallthrough... */
+
+ /* Read MII PHY register. */
+ case SIOCGMIIREG:
+ if (data->phy_id != priv->id || data->reg_num >= 6)
+ result = -EIO;
+ else
+ hw_r_phy(hw, port->linked->port_id, data->reg_num,
+ &data->val_out);
+ break;
+
+ /* Write MII PHY register. */
+ case SIOCSMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ result = -EPERM;
+ else if (data->phy_id != priv->id || data->reg_num >= 6)
+ result = -EIO;
+ else
+ hw_w_phy(hw, port->linked->port_id, data->reg_num,
+ data->val_in);
+ break;
+
+ default:
+ result = -EOPNOTSUPP;
+ }
+
+ up(&priv->proc_sem);
+
+ return result;
+}
+
+/*
+ * MII support
+ */
+
+/**
+ * mdio_read - read PHY register
+ * @dev: Network device.
+ * @phy_id: The PHY id.
+ * @reg_num: The register number.
+ *
+ * This function returns the PHY register value.
+ *
+ * Return the register value.
+ */
+static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct ksz_port *port = &priv->port;
+ struct ksz_hw *hw = port->hw;
+ u16 val_out;
+
+ hw_r_phy(hw, port->linked->port_id, reg_num << 1, &val_out);
+ return val_out;
+}
+
+/**
+ * mdio_write - set PHY register
+ * @dev: Network device.
+ * @phy_id: The PHY id.
+ * @reg_num: The register number.
+ * @val: The register value.
+ *
+ * This procedure sets the PHY register value.
+ */
+static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct ksz_port *port = &priv->port;
+ struct ksz_hw *hw = port->hw;
+ int i;
+ int pi;
+
+ for (i = 0, pi = port->first_port; i < port->port_cnt; i++, pi++)
+ hw_w_phy(hw, pi, reg_num << 1, val);
+}
+
+/*
+ * ethtool support
+ */
+
+#define EEPROM_SIZE 0x40
+
+static u16 eeprom_data[EEPROM_SIZE] = { 0 };
+
+#define ADVERTISED_ALL \
+ (ADVERTISED_10baseT_Half | \
+ ADVERTISED_10baseT_Full | \
+ ADVERTISED_100baseT_Half | \
+ ADVERTISED_100baseT_Full)
+
+/* These functions use the MII functions in mii.c. */
+
+/**
+ * netdev_get_settings - get network device settings
+ * @dev: Network device.
+ * @cmd: Ethtool command.
+ *
+ * This function queries the PHY and returns its state in the ethtool command.
+ *
+ * Return 0 if successful; otherwise an error code.
+ */
+static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+
+ mutex_lock(&hw_priv->lock);
+ mii_ethtool_gset(&priv->mii_if, cmd);
+ cmd->advertising |= SUPPORTED_TP;
+ mutex_unlock(&hw_priv->lock);
+
+ /* Save advertised settings for workaround in next function. */
+ priv->advertising = cmd->advertising;
+ return 0;
+}
+
+/**
+ * netdev_set_settings - set network device settings
+ * @dev: Network device.
+ * @cmd: Ethtool command.
+ *
+ * This function sets the PHY according to the ethtool command.
+ *
+ * Return 0 if successful; otherwise an error code.
+ */
+static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_port *port = &priv->port;
+ int rc;
+
+ /*
+ * ethtool utility does not change advertised setting if auto
+ * negotiation is not specified explicitly.
+ */
+ if (cmd->autoneg && priv->advertising == cmd->advertising) {
+ cmd->advertising |= ADVERTISED_ALL;
+ if (10 == cmd->speed)
+ cmd->advertising &=
+ ~(ADVERTISED_100baseT_Full |
+ ADVERTISED_100baseT_Half);
+ else if (100 == cmd->speed)
+ cmd->advertising &=
+ ~(ADVERTISED_10baseT_Full |
+ ADVERTISED_10baseT_Half);
+ if (0 == cmd->duplex)
+ cmd->advertising &=
+ ~(ADVERTISED_100baseT_Full |
+ ADVERTISED_10baseT_Full);
+ else if (1 == cmd->duplex)
+ cmd->advertising &=
+ ~(ADVERTISED_100baseT_Half |
+ ADVERTISED_10baseT_Half);
+ }
+ mutex_lock(&hw_priv->lock);
+ if (cmd->autoneg &&
+ (cmd->advertising & ADVERTISED_ALL) ==
+ ADVERTISED_ALL) {
+ port->duplex = 0;
+ port->speed = 0;
+ port->force_link = 0;
+ } else {
+ port->duplex = cmd->duplex + 1;
+ if (cmd->speed != 1000)
+ port->speed = cmd->speed;
+ if (cmd->autoneg)
+ port->force_link = 0;
+ else
+ port->force_link = 1;
+ }
+ rc = mii_ethtool_sset(&priv->mii_if, cmd);
+ mutex_unlock(&hw_priv->lock);
+ return rc;
+}
+
+/**
+ * netdev_nway_reset - restart auto-negotiation
+ * @dev: Network device.
+ *
+ * This function restarts the PHY for auto-negotiation.
+ *
+ * Return 0 if successful; otherwise an error code.
+ */
+static int netdev_nway_reset(struct net_device *dev)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ int rc;
+
+ mutex_lock(&hw_priv->lock);
+ rc = mii_nway_restart(&priv->mii_if);
+ mutex_unlock(&hw_priv->lock);
+ return rc;
+}
+
+/**
+ * netdev_get_link - get network device link status
+ * @dev: Network device.
+ *
+ * This function gets the link status from the PHY.
+ *
+ * Return true if PHY is linked and false otherwise.
+ */
+static u32 netdev_get_link(struct net_device *dev)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ int rc;
+
+ rc = mii_link_ok(&priv->mii_if);
+ return rc;
+}
+
+/**
+ * netdev_get_drvinfo - get network driver information
+ * @dev: Network device.
+ * @info: Ethtool driver info data structure.
+ *
+ * This procedure returns the driver information.
+ */
+static void netdev_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, pci_name(hw_priv->pdev));
+}
+
+/**
+ * netdev_get_regs_len - get length of register dump
+ * @dev: Network device.
+ *
+ * This function returns the length of the register dump.
+ *
+ * Return length of the register dump.
+ */
+static struct hw_regs {
+ int start;
+ int end;
+} hw_regs_range[] = {
+ { KS_DMA_TX_CTRL, KS884X_INTERRUPTS_STATUS },
+ { KS_ADD_ADDR_0_LO, KS_ADD_ADDR_F_HI },
+ { KS884X_ADDR_0_OFFSET, KS8841_WOL_FRAME_BYTE2_OFFSET },
+ { KS884X_SIDER_P, KS8842_SGCR7_P },
+ { KS8842_MACAR1_P, KS8842_TOSR8_P },
+ { KS884X_P1MBCR_P, KS8842_P3ERCR_P },
+ { 0, 0 }
+};
+
+static int netdev_get_regs_len(struct net_device *dev)
+{
+ struct hw_regs *range = hw_regs_range;
+ int regs_len = 0x10 * sizeof(u32);
+
+ while (range->end > range->start) {
+ regs_len += (range->end - range->start + 3) / 4 * 4;
+ range++;
+ }
+ return regs_len;
+}
+
+/**
+ * netdev_get_regs - get register dump
+ * @dev: Network device.
+ * @regs: Ethtool registers data structure.
+ * @ptr: Buffer to store the register values.
+ *
+ * This procedure dumps the register values in the provided buffer.
+ */
+static void netdev_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+ void *ptr)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ int *buf = (int *) ptr;
+ struct hw_regs *range = hw_regs_range;
+ int len;
+
+ mutex_lock(&hw_priv->lock);
+ regs->version = 0;
+ for (len = 0; len < 0x40; len += 4) {
+ pci_read_config_dword(hw_priv->pdev, len, buf);
+ buf++;
+ }
+ while (range->end > range->start) {
+ for (len = range->start; len < range->end; len += 4) {
+ *buf = readl(hw->io + len);
+ buf++;
+ }
+ range++;
+ }
+ mutex_unlock(&hw_priv->lock);
+}
+
+#define WOL_SUPPORT \
+ (WAKE_PHY | WAKE_MAGIC | \
+ WAKE_UCAST | WAKE_MCAST | \
+ WAKE_BCAST | WAKE_ARP)
+
+/**
+ * netdev_get_wol - get Wake-on-LAN support
+ * @dev: Network device.
+ * @wol: Ethtool Wake-on-LAN data structure.
+ *
+ * This procedure returns Wake-on-LAN support.
+ */
+static void netdev_get_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wol)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+
+ wol->supported = hw_priv->wol_support;
+ wol->wolopts = hw_priv->wol_enable;
+ memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+/**
+ * netdev_set_wol - set Wake-on-LAN support
+ * @dev: Network device.
+ * @wol: Ethtool Wake-on-LAN data structure.
+ *
+ * This function sets Wake-on-LAN support.
+ *
+ * Return 0 if successful; otherwise an error code.
+ */
+static int netdev_set_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wol)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+
+ /* Need to find a way to retrieve the device IP address. */
+ u8 net_addr[] = { 192, 168, 1, 1 };
+
+ if (wol->wolopts & ~hw_priv->wol_support)
+ return -EINVAL;
+
+ hw_priv->wol_enable = wol->wolopts;
+
+ /* Link wakeup cannot really be disabled. */
+ if (wol->wolopts)
+ hw_priv->wol_enable |= WAKE_PHY;
+ hw_enable_wol(&hw_priv->hw, hw_priv->wol_enable, net_addr);
+ return 0;
+}
+
+/**
+ * netdev_get_msglevel - get debug message level
+ * @dev: Network device.
+ *
+ * This function returns current debug message level.
+ *
+ * Return current debug message flags.
+ */
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+
+ return priv->msg_enable;
+}
+
+/**
+ * netdev_set_msglevel - set debug message level
+ * @dev: Network device.
+ * @value: Debug message flags.
+ *
+ * This procedure sets debug message level.
+ */
+static void netdev_set_msglevel(struct net_device *dev, u32 value)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+
+ priv->msg_enable = value;
+}
+
+/**
+ * netdev_get_eeprom_len - get EEPROM length
+ * @dev: Network device.
+ *
+ * This function returns the length of the EEPROM.
+ *
+ * Return length of the EEPROM.
+ */
+static int netdev_get_eeprom_len(struct net_device *dev)
+{
+ return EEPROM_SIZE * 2;
+}
+
+/**
+ * netdev_get_eeprom - get EEPROM data
+ * @dev: Network device.
+ * @eeprom: Ethtool EEPROM data structure.
+ * @data: Buffer to store the EEPROM data.
+ *
+ * This function dumps the EEPROM data in the provided buffer.
+ *
+ * Return 0 if successful; otherwise an error code.
+ */
+#define EEPROM_MAGIC 0x10A18842
+
+static int netdev_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ u8 *eeprom_byte = (u8 *) eeprom_data;
+ int i;
+ int len;
+
+ len = (eeprom->offset + eeprom->len + 1) / 2;
+ for (i = eeprom->offset / 2; i < len; i++)
+ eeprom_data[i] = eeprom_read(&hw_priv->hw, i);
+ eeprom->magic = EEPROM_MAGIC;
+ memcpy(data, &eeprom_byte[eeprom->offset], eeprom->len);
+
+ return 0;
+}
+
+/**
+ * netdev_set_eeprom - write EEPROM data
+ * @dev: Network device.
+ * @eeprom: Ethtool EEPROM data structure.
+ * @data: Data buffer.
+ *
+ * This function modifies the EEPROM data one byte at a time.
+ *
+ * Return 0 if successful; otherwise an error code.
+ */
+static int netdev_set_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ u16 eeprom_word[EEPROM_SIZE];
+ u8 *eeprom_byte = (u8 *) eeprom_word;
+ int i;
+ int len;
+
+ if (eeprom->magic != EEPROM_MAGIC)
+ return 1;
+
+ len = (eeprom->offset + eeprom->len + 1) / 2;
+ for (i = eeprom->offset / 2; i < len; i++)
+ eeprom_data[i] = eeprom_read(&hw_priv->hw, i);
+ memcpy(eeprom_word, eeprom_data, EEPROM_SIZE * 2);
+ memcpy(&eeprom_byte[eeprom->offset], data, eeprom->len);
+ for (i = 0; i < EEPROM_SIZE; i++)
+ if (eeprom_word[i] != eeprom_data[i]) {
+ eeprom_data[i] = eeprom_word[i];
+ eeprom_write(&hw_priv->hw, i, eeprom_data[i]);
+ }
+
+ return 0;
+}
+
+/**
+ * netdev_get_pauseparam - get flow control parameters
+ * @dev: Network device.
+ * @pause: Ethtool PAUSE settings data structure.
+ *
+ * This procedure returns the PAUSE control flow settings.
+ */
+static void netdev_get_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *pause)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+
+ pause->autoneg = (hw->overrides & PAUSE_FLOW_CTRL) ? 0 : 1;
+ if (!hw->ksz_switch) {
+ pause->rx_pause =
+ (hw->rx_cfg & DMA_RX_FLOW_ENABLE) ? 1 : 0;
+ pause->tx_pause =
+ (hw->tx_cfg & DMA_TX_FLOW_ENABLE) ? 1 : 0;
+ } else {
+ pause->rx_pause =
+ (sw_chk(hw, KS8842_SWITCH_CTRL_1_OFFSET,
+ SWITCH_RX_FLOW_CTRL)) ? 1 : 0;
+ pause->tx_pause =
+ (sw_chk(hw, KS8842_SWITCH_CTRL_1_OFFSET,
+ SWITCH_TX_FLOW_CTRL)) ? 1 : 0;
+ }
+}
+
+/**
+ * netdev_set_pauseparam - set flow control parameters
+ * @dev: Network device.
+ * @pause: Ethtool PAUSE settings data structure.
+ *
+ * This function sets the PAUSE control flow settings.
+ * Not implemented yet.
+ *
+ * Return 0 if successful; otherwise an error code.
+ */
+static int netdev_set_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *pause)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ struct ksz_port *port = &priv->port;
+
+ mutex_lock(&hw_priv->lock);
+ if (pause->autoneg) {
+ if (!pause->rx_pause && !pause->tx_pause)
+ port->flow_ctrl = PHY_NO_FLOW_CTRL;
+ else
+ port->flow_ctrl = PHY_FLOW_CTRL;
+ hw->overrides &= ~PAUSE_FLOW_CTRL;
+ port->force_link = 0;
+ if (hw->ksz_switch) {
+ sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET,
+ SWITCH_RX_FLOW_CTRL, 1);
+ sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET,
+ SWITCH_TX_FLOW_CTRL, 1);
+ }
+ port_set_link_speed(port);
+ } else {
+ hw->overrides |= PAUSE_FLOW_CTRL;
+ if (hw->ksz_switch) {
+ sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET,
+ SWITCH_RX_FLOW_CTRL, pause->rx_pause);
+ sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET,
+ SWITCH_TX_FLOW_CTRL, pause->tx_pause);
+ } else
+ set_flow_ctrl(hw, pause->rx_pause, pause->tx_pause);
+ }
+ mutex_unlock(&hw_priv->lock);
+
+ return 0;
+}
+
+/**
+ * netdev_get_ringparam - get tx/rx ring parameters
+ * @dev: Network device.
+ * @pause: Ethtool RING settings data structure.
+ *
+ * This procedure returns the TX/RX ring settings.
+ */
+static void netdev_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+
+ ring->tx_max_pending = (1 << 9);
+ ring->tx_pending = hw->tx_desc_info.alloc;
+ ring->rx_max_pending = (1 << 9);
+ ring->rx_pending = hw->rx_desc_info.alloc;
+}
+
+#define STATS_LEN (TOTAL_PORT_COUNTER_NUM)
+
+static struct {
+ char string[ETH_GSTRING_LEN];
+} ethtool_stats_keys[STATS_LEN] = {
+ { "rx_lo_priority_octets" },
+ { "rx_hi_priority_octets" },
+ { "rx_undersize_packets" },
+ { "rx_fragments" },
+ { "rx_oversize_packets" },
+ { "rx_jabbers" },
+ { "rx_symbol_errors" },
+ { "rx_crc_errors" },
+ { "rx_align_errors" },
+ { "rx_mac_ctrl_packets" },
+ { "rx_pause_packets" },
+ { "rx_bcast_packets" },
+ { "rx_mcast_packets" },
+ { "rx_ucast_packets" },
+ { "rx_64_or_less_octet_packets" },
+ { "rx_65_to_127_octet_packets" },
+ { "rx_128_to_255_octet_packets" },
+ { "rx_256_to_511_octet_packets" },
+ { "rx_512_to_1023_octet_packets" },
+ { "rx_1024_to_1522_octet_packets" },
+
+ { "tx_lo_priority_octets" },
+ { "tx_hi_priority_octets" },
+ { "tx_late_collisions" },
+ { "tx_pause_packets" },
+ { "tx_bcast_packets" },
+ { "tx_mcast_packets" },
+ { "tx_ucast_packets" },
+ { "tx_deferred" },
+ { "tx_total_collisions" },
+ { "tx_excessive_collisions" },
+ { "tx_single_collisions" },
+ { "tx_mult_collisions" },
+
+ { "rx_discards" },
+ { "tx_discards" },
+};
+
+/**
+ * netdev_get_strings - get statistics identity strings
+ * @dev: Network device.
+ * @stringset: String set identifier.
+ * @buf: Buffer to store the strings.
+ *
+ * This procedure returns the strings used to identify the statistics.
+ */
+static void netdev_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+
+ if (ETH_SS_STATS == stringset)
+ memcpy(buf, &ethtool_stats_keys,
+ ETH_GSTRING_LEN * hw->mib_cnt);
+}
+
+/**
+ * netdev_get_sset_count - get statistics size
+ * @dev: Network device.
+ * @sset: The statistics set number.
+ *
+ * This function returns the size of the statistics to be reported.
+ *
+ * Return size of the statistics to be reported.
+ */
+static int netdev_get_sset_count(struct net_device *dev, int sset)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+
+ switch (sset) {
+ case ETH_SS_STATS:
+ return hw->mib_cnt;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+/**
+ * netdev_get_ethtool_stats - get network device statistics
+ * @dev: Network device.
+ * @stats: Ethtool statistics data structure.
+ * @data: Buffer to store the statistics.
+ *
+ * This procedure returns the statistics.
+ */
+static void netdev_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ struct ksz_port *port = &priv->port;
+ int n_stats = stats->n_stats;
+ int i;
+ int n;
+ int p;
+ int rc;
+ u64 counter[TOTAL_PORT_COUNTER_NUM];
+
+ mutex_lock(&hw_priv->lock);
+ n = SWITCH_PORT_NUM;
+ for (i = 0, p = port->first_port; i < port->mib_port_cnt; i++, p++) {
+ if (media_connected == hw->port_mib[p].state) {
+ hw_priv->counter[p].read = 1;
+
+ /* Remember first port that requests read. */
+ if (n == SWITCH_PORT_NUM)
+ n = p;
+ }
+ }
+ mutex_unlock(&hw_priv->lock);
+
+ if (n < SWITCH_PORT_NUM)
+ schedule_work(&hw_priv->mib_read);
+
+ if (1 == port->mib_port_cnt && n < SWITCH_PORT_NUM) {
+ p = n;
+ rc = wait_event_interruptible_timeout(
+ hw_priv->counter[p].counter,
+ 2 == hw_priv->counter[p].read,
+ HZ * 1);
+ } else
+ for (i = 0, p = n; i < port->mib_port_cnt - n; i++, p++) {
+ if (0 == i) {
+ rc = wait_event_interruptible_timeout(
+ hw_priv->counter[p].counter,
+ 2 == hw_priv->counter[p].read,
+ HZ * 2);
+ } else if (hw->port_mib[p].cnt_ptr) {
+ rc = wait_event_interruptible_timeout(
+ hw_priv->counter[p].counter,
+ 2 == hw_priv->counter[p].read,
+ HZ * 1);
+ }
+ }
+
+ get_mib_counters(hw, port->first_port, port->mib_port_cnt, counter);
+ n = hw->mib_cnt;
+ if (n > n_stats)
+ n = n_stats;
+ n_stats -= n;
+ for (i = 0; i < n; i++)
+ *data++ = counter[i];
+}
+
+/**
+ * netdev_get_rx_csum - get receive checksum support
+ * @dev: Network device.
+ *
+ * This function gets receive checksum support setting.
+ *
+ * Return true if receive checksum is enabled; false otherwise.
+ */
+static u32 netdev_get_rx_csum(struct net_device *dev)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+
+ return hw->rx_cfg &
+ (DMA_RX_CSUM_UDP |
+ DMA_RX_CSUM_TCP |
+ DMA_RX_CSUM_IP);
+}
+
+/**
+ * netdev_set_rx_csum - set receive checksum support
+ * @dev: Network device.
+ * @data: Zero to disable receive checksum support.
+ *
+ * This function sets receive checksum support setting.
+ *
+ * Return 0 if successful; otherwise an error code.
+ */
+static int netdev_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ u32 new_setting = hw->rx_cfg;
+
+ if (data)
+ new_setting |=
+ (DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP |
+ DMA_RX_CSUM_IP);
+ else
+ new_setting &=
+ ~(DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP |
+ DMA_RX_CSUM_IP);
+ new_setting &= ~DMA_RX_CSUM_UDP;
+ mutex_lock(&hw_priv->lock);
+ if (new_setting != hw->rx_cfg) {
+ hw->rx_cfg = new_setting;
+ if (hw->enabled)
+ writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL);
+ }
+ mutex_unlock(&hw_priv->lock);
+ return 0;
+}
+
+static struct ethtool_ops netdev_ethtool_ops = {
+ .get_settings = netdev_get_settings,
+ .set_settings = netdev_set_settings,
+ .nway_reset = netdev_nway_reset,
+ .get_link = netdev_get_link,
+ .get_drvinfo = netdev_get_drvinfo,
+ .get_regs_len = netdev_get_regs_len,
+ .get_regs = netdev_get_regs,
+ .get_wol = netdev_get_wol,
+ .set_wol = netdev_set_wol,
+ .get_msglevel = netdev_get_msglevel,
+ .set_msglevel = netdev_set_msglevel,
+ .get_eeprom_len = netdev_get_eeprom_len,
+ .get_eeprom = netdev_get_eeprom,
+ .set_eeprom = netdev_set_eeprom,
+ .get_pauseparam = netdev_get_pauseparam,
+ .set_pauseparam = netdev_set_pauseparam,
+ .get_ringparam = netdev_get_ringparam,
+ .get_strings = netdev_get_strings,
+ .get_sset_count = netdev_get_sset_count,
+ .get_ethtool_stats = netdev_get_ethtool_stats,
+ .get_rx_csum = netdev_get_rx_csum,
+ .set_rx_csum = netdev_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+};
+
+/*
+ * Hardware monitoring
+ */
+
+static void update_link(struct net_device *dev, struct dev_priv *priv,
+ struct ksz_port *port)
+{
+ if (priv->media_state != port->linked->state) {
+ priv->media_state = port->linked->state;
+ if (netif_running(dev)) {
+ if (media_connected == priv->media_state)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s link %s\n", dev->name,
+ (media_connected == priv->media_state ?
+ "on" : "off"));
+ }
+ }
+}
+
+static void mib_read_work(struct work_struct *work)
+{
+ struct dev_info *hw_priv =
+ container_of(work, struct dev_info, mib_read);
+ struct ksz_hw *hw = &hw_priv->hw;
+ struct ksz_port_mib *mib;
+ int i;
+
+ next_jiffies = jiffies;
+ for (i = 0; i < hw->mib_port_cnt; i++) {
+ mib = &hw->port_mib[i];
+
+ /* Reading MIB counters or requested to read. */
+ if (mib->cnt_ptr || 1 == hw_priv->counter[i].read) {
+
+ /* Need to process receive interrupt. */
+ if (port_r_cnt(hw, i))
+ break;
+ hw_priv->counter[i].read = 0;
+
+ /* Finish reading counters. */
+ if (0 == mib->cnt_ptr) {
+ hw_priv->counter[i].read = 2;
+ wake_up_interruptible(
+ &hw_priv->counter[i].counter);
+ }
+ } else if (jiffies >= hw_priv->counter[i].time) {
+ /* Only read MIB counters when the port is connected. */
+ if (media_connected == mib->state)
+ hw_priv->counter[i].read = 1;
+ next_jiffies += HZ * 1 * hw->mib_port_cnt;
+ hw_priv->counter[i].time = next_jiffies;
+
+ /* Port is just disconnected. */
+ } else if (mib->link_down) {
+ mib->link_down = 0;
+
+ /* Read counters one last time after link is lost. */
+ hw_priv->counter[i].read = 1;
+ }
+ }
+}
+
+static void mib_monitor(unsigned long ptr)
+{
+ struct dev_info *hw_priv = (struct dev_info *) ptr;
+
+ mib_read_work(&hw_priv->mib_read);
+
+ /* This is used to verify Wake-on-LAN is working. */
+ if (hw_priv->pme_wait) {
+ if (hw_priv->pme_wait <= jiffies) {
+ hw_clr_wol_pme_status(&hw_priv->hw);
+ hw_priv->pme_wait = 0;
+ }
+ } else if (hw_chk_wol_pme_status(&hw_priv->hw)) {
+
+ /* PME is asserted. Wait 2 seconds to clear it. */
+ hw_priv->pme_wait = jiffies + HZ * 2;
+ }
+
+ ksz_update_timer(&hw_priv->mib_timer_info);
+}
+
+/**
+ * dev_monitor - periodic monitoring
+ * @ptr: Network device pointer.
+ *
+ * This routine is run in a kernel timer to monitor the network device.
+ */
+static void dev_monitor(unsigned long ptr)
+{
+ struct net_device *dev = (struct net_device *) ptr;
+ struct dev_priv *priv = netdev_priv(dev);
+ struct dev_info *hw_priv = priv->adapter;
+ struct ksz_hw *hw = &hw_priv->hw;
+ struct ksz_port *port = &priv->port;
+
+ if (!(hw->features & LINK_INT_WORKING))
+ port_get_link_speed(port);
+ update_link(dev, priv, port);
+
+ ksz_update_timer(&priv->monitor_timer_info);
+}
+
+/*
+ * Linux network device interface functions
+ */
+
+/* Driver exported variables */
+
+static int msg_enable;
+
+static char *macaddr = ":";
+static char *mac1addr = ":";
+
+/*
+ * This enables multiple network device mode for KSZ8842, which contains a
+ * switch with two physical ports. Some users like to take control of the
+ * ports for running Spanning Tree Protocol. The driver will create an
+ * additional eth? device for the other port.
+ *
+ * Some limitations are the network devices cannot have different MTU and
+ * multicast hash tables.
+ */
+static int multi_dev;
+
+/*
+ * As most users select multiple network device mode to use Spanning Tree
+ * Protocol, this enables a feature in which most unicast and multicast packets
+ * are forwarded inside the switch and not passed to the host. Only packets
+ * that need the host's attention are passed to it. This prevents the host
+ * wasting CPU time to examine each and every incoming packets and do the
+ * forwarding itself.
+ *
+ * As the hack requires the private bridge header, the driver cannot compile
+ * with just the kernel headers.
+ *
+ * Enabling STP support also turns on multiple network device mode.
+ */
+static int stp;
+
+/*
+ * This enables fast aging in the KSZ8842 switch. Not sure what situation
+ * needs that. However, fast aging is used to flush the dynamic MAC table when
+ * STP suport is enabled.
+ */
+static int fast_aging;
+
+/**
+ * netdev_init - initalize network device.
+ * @dev: Network device.
+ *
+ * This function initializes the network device.
+ *
+ * Return 0 if successful; otherwise an error code indicating failure.
+ */
+static int __init netdev_init(struct net_device *dev)
+{
+ struct dev_priv *priv = netdev_priv(dev);
+
+ /* 500 ms timeout */
+ ksz_init_timer(&priv->monitor_timer_info, 500 * HZ / 1000,
+ dev_monitor, dev);
+
+ /* 500 ms timeout */
+ dev->watchdog_timeo = HZ / 2;
+
+ dev->features |= NETIF_F_IP_CSUM;
+
+ /*
+ * Hardware does not really support IPv6 checksum generation, but
+ * driver actually runs faster with this on. Refer IPV6_CSUM_GEN_HACK.
+ */
+ dev->features |= NETIF_F_IPV6_CSUM;
+ dev->features |= NETIF_F_SG;
+
+ sema_init(&priv->proc_sem, 1);
+
+ priv->mii_if.phy_id_mask = 0x1;
+ priv->mii_if.reg_num_mask = 0x7;
+ priv->mii_if.dev = dev;
+ priv->mii_if.mdio_read = mdio_read;
+ priv->mii_if.mdio_write = mdio_write;
+ priv->mii_if.phy_id = priv->port.first_port + 1;
+
+ priv->msg_enable = netif_msg_init(msg_enable,
+ (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK));
+
+ return 0;
+}
+
+static const struct net_device_ops netdev_ops = {
+ .ndo_init = netdev_init,
+ .ndo_open = netdev_open,
+ .ndo_stop = netdev_close,
+ .ndo_get_stats = netdev_query_statistics,
+ .ndo_start_xmit = netdev_tx,
+ .ndo_tx_timeout = netdev_tx_timeout,
+ .ndo_change_mtu = netdev_change_mtu,
+ .ndo_set_mac_address = netdev_set_mac_address,
+ .ndo_do_ioctl = netdev_ioctl,
+ .ndo_set_rx_mode = netdev_set_rx_mode,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = netdev_netpoll,
+#endif
+};
+
+static void netdev_free(struct net_device *dev)
+{
+ if (dev->watchdog_timeo)
+ unregister_netdev(dev);
+
+ free_netdev(dev);
+}
+
+struct platform_info {
+ struct dev_info dev_info;
+ struct net_device *netdev[SWITCH_PORT_NUM];
+};
+
+static int net_device_present;
+
+static void get_mac_addr(struct dev_info *hw_priv, u8 *macaddr, int port)
+{
+ int i;
+ int j;
+ int got_num;
+ int num;
+
+ i = j = num = got_num = 0;
+ while (j < MAC_ADDR_LEN) {
+ if (macaddr[i]) {
+ got_num = 1;
+ if ('0' <= macaddr[i] && macaddr[i] <= '9')
+ num = num * 16 + macaddr[i] - '0';
+ else if ('A' <= macaddr[i] && macaddr[i] <= 'F')
+ num = num * 16 + 10 + macaddr[i] - 'A';
+ else if ('a' <= macaddr[i] && macaddr[i] <= 'f')
+ num = num * 16 + 10 + macaddr[i] - 'a';
+ else if (':' == macaddr[i])
+ got_num = 2;
+ else
+ break;
+ } else if (got_num)
+ got_num = 2;
+ else
+ break;
+ if (2 == got_num) {
+ if (MAIN_PORT == port) {
+ hw_priv->hw.override_addr[j++] = (u8) num;
+ hw_priv->hw.override_addr[5] +=
+ hw_priv->hw.id;
+ } else {
+ hw_priv->hw.ksz_switch->other_addr[j++] =
+ (u8) num;
+ hw_priv->hw.ksz_switch->other_addr[5] +=
+ hw_priv->hw.id;
+ }
+ num = got_num = 0;
+ }
+ i++;
+ }
+ if (MAC_ADDR_LEN == j) {
+ if (MAIN_PORT == port)
+ hw_priv->hw.mac_override = 1;
+ }
+}
+
+#define KS884X_DMA_MASK (~0x0UL)
+
+static void read_other_addr(struct ksz_hw *hw)
+{
+ int i;
+ u16 data[3];
+ struct ksz_switch *sw = hw->ksz_switch;
+
+ for (i = 0; i < 3; i++)
+ data[i] = eeprom_read(hw, i + EEPROM_DATA_OTHER_MAC_ADDR);
+ if ((data[0] || data[1] || data[2]) && data[0] != 0xffff) {
+ sw->other_addr[5] = (u8) data[0];
+ sw->other_addr[4] = (u8)(data[0] >> 8);
+ sw->other_addr[3] = (u8) data[1];
+ sw->other_addr[2] = (u8)(data[1] >> 8);
+ sw->other_addr[1] = (u8) data[2];
+ sw->other_addr[0] = (u8)(data[2] >> 8);
+ }
+}
+
+#ifndef PCI_VENDOR_ID_MICREL_KS
+#define PCI_VENDOR_ID_MICREL_KS 0x16c6
+#endif
+
+static int __init pcidev_init(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct net_device *dev;
+ struct dev_priv *priv;
+ struct dev_info *hw_priv;
+ struct ksz_hw *hw;
+ struct platform_info *info;
+ struct ksz_port *port;
+ unsigned long reg_base;
+ unsigned long reg_len;
+ int cnt;
+ int i;
+ int mib_port_count;
+ int pi;
+ int port_count;
+ int result;
+ char banner[80];
+ struct ksz_switch *sw = NULL;
+
+ result = pci_enable_device(pdev);
+ if (result)
+ return result;
+
+ result = -ENODEV;
+
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) ||
+ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
+ return result;
+
+ reg_base = pci_resource_start(pdev, 0);
+ reg_len = pci_resource_len(pdev, 0);
+ if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0)
+ return result;
+
+ if (!request_mem_region(reg_base, reg_len, DRV_NAME))
+ return result;
+ pci_set_master(pdev);
+
+ result = -ENOMEM;
+
+ info = kmalloc(sizeof(struct platform_info), GFP_KERNEL);
+ if (!info)
+ goto pcidev_init_dev_err;
+ memset(info, 0, sizeof(struct platform_info));
+
+ hw_priv = &info->dev_info;
+ hw_priv->pdev = pdev;
+
+ hw = &hw_priv->hw;
+
+ hw->io = ioremap(reg_base, reg_len);
+ if (!hw->io)
+ goto pcidev_init_io_err;
+
+ cnt = hw_init(hw);
+ if (!cnt) {
+ if (msg_enable & NETIF_MSG_PROBE)
+ printk(KERN_ALERT "chip not detected\n");
+ result = -ENODEV;
+ goto pcidev_init_alloc_err;
+ }
+
+ sprintf(banner, "%s\n", version);
+ banner[13] = cnt + '0';
+ ks_info(hw_priv, "%s", banner);
+ ks_dbg(hw_priv, "Mem = %p; IRQ = %d\n", hw->io, pdev->irq);
+
+ /* Assume device is KSZ8841. */
+ hw->dev_count = 1;
+ port_count = 1;
+ mib_port_count = 1;
+ hw->addr_list_size = 0;
+ hw->mib_cnt = PORT_COUNTER_NUM;
+ hw->mib_port_cnt = 1;
+
+ /* KSZ8842 has a switch with multiple ports. */
+ if (2 == cnt) {
+ if (fast_aging)
+ hw->overrides |= FAST_AGING;
+
+ hw->mib_cnt = TOTAL_PORT_COUNTER_NUM;
+
+ /* Multiple network device interfaces are required. */
+ if (multi_dev) {
+ hw->dev_count = SWITCH_PORT_NUM;
+ hw->addr_list_size = SWITCH_PORT_NUM - 1;
+ }
+
+ /* Single network device has multiple ports. */
+ if (1 == hw->dev_count) {
+ port_count = SWITCH_PORT_NUM;
+ mib_port_count = SWITCH_PORT_NUM;
+ }
+ hw->mib_port_cnt = TOTAL_PORT_NUM;
+ hw->ksz_switch = kmalloc(sizeof(struct ksz_switch), GFP_KERNEL);
+ if (!hw->ksz_switch)
+ goto pcidev_init_alloc_err;
+ memset(hw->ksz_switch, 0, sizeof(struct ksz_switch));
+
+ sw = hw->ksz_switch;
+ }
+ for (i = 0; i < hw->mib_port_cnt; i++)
+ hw->port_mib[i].mib_start = 0;
+
+ hw->parent = hw_priv;
+
+ /* Default MTU is 1500. */
+ hw_priv->mtu = (REGULAR_RX_BUF_SIZE + 3) & ~3;
+
+ if (ksz_alloc_mem(hw_priv))
+ goto pcidev_init_mem_err;
+
+ hw_priv->hw.id = net_device_present;
+
+ spin_lock_init(&hw_priv->hwlock);
+ mutex_init(&hw_priv->lock);
+
+ /* tasklet is enabled. */
+ tasklet_init(&hw_priv->rx_tasklet, rx_proc_task,
+ (unsigned long) hw_priv);
+ tasklet_init(&hw_priv->tx_tasklet, tx_proc_task,
+ (unsigned long) hw_priv);
+
+ /* tasklet_enable will decrement the atomic counter. */
+ tasklet_disable(&hw_priv->rx_tasklet);
+ tasklet_disable(&hw_priv->tx_tasklet);
+
+ for (i = 0; i < TOTAL_PORT_NUM; i++)
+ init_waitqueue_head(&hw_priv->counter[i].counter);
+
+ if (macaddr[0] != ':')
+ get_mac_addr(hw_priv, macaddr, MAIN_PORT);
+
+ /* Read MAC address and initialize override address if not overrided. */
+ hw_read_addr(hw);
+
+ /* Multiple device interfaces mode requires a second MAC address. */
+ if (hw->dev_count > 1) {
+ memcpy(sw->other_addr, hw->override_addr, MAC_ADDR_LEN);
+ read_other_addr(hw);
+ if (mac1addr[0] != ':')
+ get_mac_addr(hw_priv, mac1addr, OTHER_PORT);
+ }
+
+ hw_setup(hw);
+ if (hw->ksz_switch)
+ sw_setup(hw);
+ else {
+ hw_priv->wol_support = WOL_SUPPORT;
+ hw_priv->wol_enable = 0;
+ }
+
+ INIT_WORK(&hw_priv->mib_read, mib_read_work);
+
+ /* 500 ms timeout */
+ ksz_init_timer(&hw_priv->mib_timer_info, 500 * HZ / 1000,
+ mib_monitor, hw_priv);
+
+ for (i = 0; i < hw->dev_count; i++) {
+ dev = alloc_etherdev(sizeof(struct dev_priv));
+ if (!dev)
+ goto pcidev_init_reg_err;
+ info->netdev[i] = dev;
+
+ priv = netdev_priv(dev);
+ priv->adapter = hw_priv;
+ priv->id = net_device_present++;
+
+ port = &priv->port;
+ port->port_cnt = port_count;
+ port->mib_port_cnt = mib_port_count;
+ port->first_port = i;
+ port->flow_ctrl = PHY_FLOW_CTRL;
+
+ port->hw = hw;
+ port->linked = &hw->port_info[port->first_port];
+
+ for (cnt = 0, pi = i; cnt < port_count; cnt++, pi++) {
+ hw->port_info[pi].port_id = pi;
+ hw->port_info[pi].pdev = dev;
+ hw->port_info[pi].state = media_disconnected;
+ }
+
+ dev->mem_start = (unsigned long) hw->io;
+ dev->mem_end = dev->mem_start + reg_len - 1;
+ dev->irq = pdev->irq;
+ if (MAIN_PORT == i)
+ memcpy(dev->dev_addr, hw_priv->hw.override_addr,
+ MAC_ADDR_LEN);
+ else {
+ memcpy(dev->dev_addr, sw->other_addr,
+ MAC_ADDR_LEN);
+ if (!memcmp(sw->other_addr, hw->override_addr,
+ MAC_ADDR_LEN))
+ dev->dev_addr[5] += port->first_port;
+ }
+
+ dev->netdev_ops = &netdev_ops;
+ SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
+ if (register_netdev(dev))
+ goto pcidev_init_reg_err;
+ port_set_power_saving(port, true);
+ }
+
+ pci_dev_get(hw_priv->pdev);
+ pci_set_drvdata(pdev, info);
+ return 0;
+
+pcidev_init_reg_err:
+ for (i = 0; i < hw->dev_count; i++) {
+ if (info->netdev[i]) {
+ netdev_free(info->netdev[i]);
+ info->netdev[i] = NULL;
+ }
+ }
+
+pcidev_init_mem_err:
+ ksz_free_mem(hw_priv);
+ kfree(hw->ksz_switch);
+
+pcidev_init_alloc_err:
+ iounmap(hw->io);
+
+pcidev_init_io_err:
+ kfree(info);
+
+pcidev_init_dev_err:
+ release_mem_region(reg_base, reg_len);
+
+ return result;
+}
+
+static void pcidev_exit(struct pci_dev *pdev)
+{
+ int i;
+ struct platform_info *info = pci_get_drvdata(pdev);
+ struct dev_info *hw_priv = &info->dev_info;
+
+ pci_set_drvdata(pdev, NULL);
+
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ for (i = 0; i < hw_priv->hw.dev_count; i++) {
+ if (info->netdev[i])
+ netdev_free(info->netdev[i]);
+ }
+ if (hw_priv->hw.io)
+ iounmap(hw_priv->hw.io);
+ ksz_free_mem(hw_priv);
+ kfree(hw_priv->hw.ksz_switch);
+ pci_dev_put(hw_priv->pdev);
+ kfree(info);
+}
+
+#ifdef CONFIG_PM
+static int pcidev_resume(struct pci_dev *pdev)
+{
+ int i;
+ struct platform_info *info = pci_get_drvdata(pdev);
+ struct dev_info *hw_priv = &info->dev_info;
+ struct ksz_hw *hw = &hw_priv->hw;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ pci_enable_wake(pdev, PCI_D0, 0);
+
+ if (hw_priv->wol_enable)
+ hw_cfg_wol_pme(hw, 0);
+ for (i = 0; i < hw->dev_count; i++) {
+ if (info->netdev[i]) {
+ struct net_device *dev = info->netdev[i];
+
+ if (netif_running(dev)) {
+ netdev_open(dev);
+ netif_device_attach(dev);
+ }
+ }
+ }
+ return 0;
+}
+
+static int pcidev_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ int i;
+ struct platform_info *info = pci_get_drvdata(pdev);
+ struct dev_info *hw_priv = &info->dev_info;
+ struct ksz_hw *hw = &hw_priv->hw;
+
+ /* Need to find a way to retrieve the device IP address. */
+ u8 net_addr[] = { 192, 168, 1, 1 };
+
+ for (i = 0; i < hw->dev_count; i++) {
+ if (info->netdev[i]) {
+ struct net_device *dev = info->netdev[i];
+
+ if (netif_running(dev)) {
+ netif_device_detach(dev);
+ netdev_close(dev);
+ }
+ }
+ }
+ if (hw_priv->wol_enable) {
+ hw_enable_wol(hw, hw_priv->wol_enable, net_addr);
+ hw_cfg_wol_pme(hw, 1);
+ }
+
+ pci_save_state(pdev);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
+}
+#endif
+
+static char pcidev_name[] = "ksz884xp";
+
+static struct pci_device_id pcidev_table[] = {
+ { PCI_VENDOR_ID_MICREL_KS, 0x8841,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_MICREL_KS, 0x8842,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, pcidev_table);
+
+static struct pci_driver pci_device_driver = {
+#ifdef CONFIG_PM
+ .suspend = pcidev_suspend,
+ .resume = pcidev_resume,
+#endif
+ .name = pcidev_name,
+ .id_table = pcidev_table,
+ .probe = pcidev_init,
+ .remove = pcidev_exit
+};
+
+static int __init ksz884x_init_module(void)
+{
+ return pci_register_driver(&pci_device_driver);
+}
+
+static void __exit ksz884x_cleanup_module(void)
+{
+ pci_unregister_driver(&pci_device_driver);
+}
+
+module_init(ksz884x_init_module);
+module_exit(ksz884x_cleanup_module);
+
+MODULE_DESCRIPTION("KSZ8841/2 PCI network driver");
+MODULE_AUTHOR("Tristram Ha <Tristram.Ha@micrel.com>");
+MODULE_LICENSE("GPL");
+
+module_param_named(message, msg_enable, int, 0);
+MODULE_PARM_DESC(message, "Message verbosity level (0=none, 31=all)");
+
+module_param(macaddr, charp, 0);
+module_param(mac1addr, charp, 0);
+module_param(fast_aging, int, 0);
+module_param(multi_dev, int, 0);
+module_param(stp, int, 0);
+MODULE_PARM_DESC(macaddr, "MAC address");
+MODULE_PARM_DESC(mac1addr, "Second MAC address");
+MODULE_PARM_DESC(fast_aging, "Fast aging");
+MODULE_PARM_DESC(multi_dev, "Multiple device interfaces");
+MODULE_PARM_DESC(stp, "STP support");
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 8d7d3d4625f6..7b9447646f8a 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -1288,7 +1288,7 @@ static void set_multicast_list(struct net_device *dev)
} else {
short multicast_table[4];
int i;
- int num_addrs=dev->mc_count;
+ int num_addrs=netdev_mc_count(dev);
if(dev->flags&IFF_ALLMULTI)
num_addrs=1;
/* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
index b117f7f8b194..443c39a3732f 100644
--- a/drivers/net/lib82596.c
+++ b/drivers/net/lib82596.c
@@ -1094,11 +1094,9 @@ static int __devinit i82596_probe(struct net_device *dev)
return i;
};
- DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx,",
- dev->name, dev->base_addr));
- for (i = 0; i < 6; i++)
- DEB(DEB_PROBE, printk(" %2.2X", dev->dev_addr[i]));
- DEB(DEB_PROBE, printk(" IRQ %d.\n", dev->irq));
+ DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx, %pM IRQ %d.\n",
+ dev->name, dev->base_addr, dev->dev_addr,
+ dev->irq));
DEB(DEB_INIT, printk(KERN_INFO
"%s: dma at 0x%p (%d bytes), lp->scb at 0x%p\n",
dev->name, dma, (int)sizeof(struct i596_dma),
@@ -1382,31 +1380,32 @@ static void set_multicast_list(struct net_device *dev)
}
}
- cnt = dev->mc_count;
+ cnt = netdev_mc_count(dev);
if (cnt > MAX_MC_CNT) {
cnt = MAX_MC_CNT;
printk(KERN_NOTICE "%s: Only %d multicast addresses supported",
dev->name, cnt);
}
- if (dev->mc_count > 0) {
+ if (!netdev_mc_empty(dev)) {
struct dev_mc_list *dmi;
unsigned char *cp;
struct mc_cmd *cmd;
cmd = &dma->mc_cmd;
cmd->cmd.command = SWAP16(CmdMulticastList);
- cmd->mc_cnt = SWAP16(dev->mc_count * 6);
+ cmd->mc_cnt = SWAP16(netdev_mc_count(dev) * 6);
cp = cmd->mc_addrs;
- for (dmi = dev->mc_list;
- cnt && dmi != NULL;
- dmi = dmi->next, cnt--, cp += 6) {
+ netdev_for_each_mc_addr(dmi, dev) {
+ if (!cnt--)
+ break;
memcpy(cp, dmi->dmi_addr, 6);
if (i596_debug > 1)
DEB(DEB_MULTI,
printk(KERN_DEBUG
"%s: Adding address %pM\n",
dev->name, cp));
+ cp += 6;
}
DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd));
i596_add_cmd(dev, &cmd->cmd);
diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c
index 57f25848fe80..56f66f485400 100644
--- a/drivers/net/lib8390.c
+++ b/drivers/net/lib8390.c
@@ -907,15 +907,8 @@ static inline void make_mc_bits(u8 *bits, struct net_device *dev)
{
struct dev_mc_list *dmi;
- for (dmi=dev->mc_list; dmi; dmi=dmi->next)
- {
- u32 crc;
- if (dmi->dmi_addrlen != ETH_ALEN)
- {
- printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
- continue;
- }
- crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
+ netdev_for_each_mc_addr(dmi, dev) {
+ u32 crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
/*
* The 8390 uses the 6 most significant bits of the
* CRC to index the multicast table.
@@ -941,7 +934,7 @@ static void do_set_multicast_list(struct net_device *dev)
if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
{
memset(ei_local->mcfilter, 0, 8);
- if (dev->mc_list)
+ if (!netdev_mc_empty(dev))
make_mc_bits(ei_local->mcfilter, dev);
}
else
@@ -975,7 +968,7 @@ static void do_set_multicast_list(struct net_device *dev)
if(dev->flags&IFF_PROMISC)
ei_outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
- else if(dev->flags&IFF_ALLMULTI || dev->mc_list)
+ else if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev))
ei_outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
else
ei_outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c
index a8522bd73ae7..a18e3485476e 100644
--- a/drivers/net/ll_temac_main.c
+++ b/drivers/net/ll_temac_main.c
@@ -224,6 +224,13 @@ static int temac_set_mac_address(struct net_device *ndev, void *address)
return 0;
}
+static int netdev_set_mac_address(struct net_device *ndev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ return temac_set_mac_address(ndev, addr->sa_data);
+}
+
static void temac_set_multicast_list(struct net_device *ndev)
{
struct temac_local *lp = netdev_priv(ndev);
@@ -232,7 +239,7 @@ static void temac_set_multicast_list(struct net_device *ndev)
mutex_lock(&lp->indirect_mutex);
if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) ||
- ndev->mc_count > MULTICAST_CAM_TABLE_NUM) {
+ netdev_mc_count(ndev) > MULTICAST_CAM_TABLE_NUM) {
/*
* We must make the kernel realise we had to move
* into promisc mode or we start all out war on
@@ -242,10 +249,11 @@ static void temac_set_multicast_list(struct net_device *ndev)
ndev->flags |= IFF_PROMISC;
temac_indirect_out32(lp, XTE_AFM_OFFSET, XTE_AFM_EPPRM_MASK);
dev_info(&ndev->dev, "Promiscuous mode enabled.\n");
- } else if (ndev->mc_count) {
- struct dev_mc_list *mclist = ndev->mc_list;
- for (i = 0; mclist && i < ndev->mc_count; i++) {
+ } else if (!netdev_mc_empty(ndev)) {
+ struct dev_mc_list *mclist;
+ i = 0;
+ netdev_for_each_mc_addr(mclist, ndev) {
if (i >= MULTICAST_CAM_TABLE_NUM)
break;
multi_addr_msw = ((mclist->dmi_addr[3] << 24) |
@@ -258,7 +266,7 @@ static void temac_set_multicast_list(struct net_device *ndev)
(mclist->dmi_addr[4]) | (i << 16));
temac_indirect_out32(lp, XTE_MAW1_OFFSET,
multi_addr_lsw);
- mclist = mclist->next;
+ i++;
}
} else {
val = temac_indirect_in32(lp, XTE_AFM_OFFSET);
@@ -615,7 +623,7 @@ static void ll_temac_recv(struct net_device *ndev)
while ((bdstat & STS_CTRL_APP0_CMPLT)) {
skb = lp->rx_skb[lp->rx_bd_ci];
- length = cur_p->app4;
+ length = cur_p->app4 & 0x3FFF;
skb_vaddr = virt_to_bus(skb->data);
dma_unmap_single(ndev->dev.parent, skb_vaddr, length,
@@ -768,7 +776,7 @@ static const struct net_device_ops temac_netdev_ops = {
.ndo_open = temac_open,
.ndo_stop = temac_stop,
.ndo_start_xmit = temac_start_xmit,
- .ndo_set_mac_address = temac_set_mac_address,
+ .ndo_set_mac_address = netdev_set_mac_address,
//.ndo_set_multicast_list = temac_set_multicast_list,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = temac_poll_controller,
@@ -938,6 +946,9 @@ static int __devexit temac_of_remove(struct of_device *op)
static struct of_device_id temac_of_match[] __devinitdata = {
{ .compatible = "xlnx,xps-ll-temac-1.01.b", },
+ { .compatible = "xlnx,xps-ll-temac-2.00.a", },
+ { .compatible = "xlnx,xps-ll-temac-2.02.a", },
+ { .compatible = "xlnx,xps-ll-temac-2.03.a", },
{},
};
MODULE_DEVICE_TABLE(of, temac_of_match);
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index b9fcc9819837..72b7949c91b1 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -72,7 +72,8 @@ struct pcpu_lstats {
static netdev_tx_t loopback_xmit(struct sk_buff *skb,
struct net_device *dev)
{
- struct pcpu_lstats *pcpu_lstats, *lb_stats;
+ struct pcpu_lstats __percpu *pcpu_lstats;
+ struct pcpu_lstats *lb_stats;
int len;
skb_orphan(skb);
@@ -80,7 +81,7 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
skb->protocol = eth_type_trans(skb, dev);
/* it's OK to use per_cpu_ptr() because BHs are off */
- pcpu_lstats = dev->ml_priv;
+ pcpu_lstats = (void __percpu __force *)dev->ml_priv;
lb_stats = this_cpu_ptr(pcpu_lstats);
len = skb->len;
@@ -95,14 +96,14 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
static struct net_device_stats *loopback_get_stats(struct net_device *dev)
{
- const struct pcpu_lstats *pcpu_lstats;
+ const struct pcpu_lstats __percpu *pcpu_lstats;
struct net_device_stats *stats = &dev->stats;
unsigned long bytes = 0;
unsigned long packets = 0;
unsigned long drops = 0;
int i;
- pcpu_lstats = dev->ml_priv;
+ pcpu_lstats = (void __percpu __force *)dev->ml_priv;
for_each_possible_cpu(i) {
const struct pcpu_lstats *lb_stats;
@@ -135,19 +136,20 @@ static const struct ethtool_ops loopback_ethtool_ops = {
static int loopback_dev_init(struct net_device *dev)
{
- struct pcpu_lstats *lstats;
+ struct pcpu_lstats __percpu *lstats;
lstats = alloc_percpu(struct pcpu_lstats);
if (!lstats)
return -ENOMEM;
- dev->ml_priv = lstats;
+ dev->ml_priv = (void __force *)lstats;
return 0;
}
static void loopback_dev_free(struct net_device *dev)
{
- struct pcpu_lstats *lstats = dev->ml_priv;
+ struct pcpu_lstats __percpu *lstats =
+ (void __percpu __force *)dev->ml_priv;
free_percpu(lstats);
free_netdev(dev);
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index e20fefc73c8b..3e3cc04defd0 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -1253,21 +1253,22 @@ static void set_multicast_list(struct net_device *dev) {
if (i596_debug > 1)
printk ("%s: set multicast list %d\n",
- dev->name, dev->mc_count);
+ dev->name, netdev_mc_count(dev));
- if (dev->mc_count > 0) {
+ if (!netdev_mc_empty(dev)) {
struct dev_mc_list *dmi;
char *cp;
- cmd = kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6, GFP_ATOMIC);
+ cmd = kmalloc(sizeof(struct i596_cmd) + 2 +
+ netdev_mc_count(dev) * 6, GFP_ATOMIC);
if (cmd == NULL) {
printk (KERN_ERR "%s: set_multicast Memory squeeze.\n", dev->name);
return;
}
cmd->command = CmdMulticastList;
- *((unsigned short *) (cmd + 1)) = dev->mc_count * 6;
+ *((unsigned short *) (cmd + 1)) = netdev_mc_count(dev) * 6;
cp = ((char *)(cmd + 1))+2;
- for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
- memcpy(cp, dmi,6);
+ netdev_for_each_mc_addr(dmi, dev) {
+ memcpy(cp, dmi->dmi_addr, 6);
cp += 6;
}
if (i596_debug & LOG_SRCDST)
@@ -1277,7 +1278,8 @@ static void set_multicast_list(struct net_device *dev) {
if (lp->set_conf.pa_next != I596_NULL) {
return;
}
- if (dev->mc_count == 0 && !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
+ if (netdev_mc_empty(dev) &&
+ !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
lp->i596_config[8] &= ~0x01;
} else {
lp->i596_config[8] |= 0x01;
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index f8fa0c3f0f64..a8768672dc5a 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -17,6 +17,8 @@
/* 2002-12-30: Try to support more cards, some clues from NetBSD driver */
/* 2003-12-26: Make sure Asante cards always work. */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -34,31 +36,36 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
+#include <linux/io.h>
#include <asm/system.h>
-#include <asm/io.h>
#include <asm/dma.h>
#include <asm/hwtest.h>
#include <asm/macints.h>
static char version[] =
- "mac8390.c: v0.4 2001-05-15 David Huggins-Daines <dhd@debian.org> and others\n";
+ "v0.4 2001-05-15 David Huggins-Daines <dhd@debian.org> and others\n";
#define EI_SHIFT(x) (ei_local->reg_offset[x])
-#define ei_inb(port) in_8(port)
-#define ei_outb(val,port) out_8(port,val)
-#define ei_inb_p(port) in_8(port)
-#define ei_outb_p(val,port) out_8(port,val)
+#define ei_inb(port) in_8(port)
+#define ei_outb(val, port) out_8(port, val)
+#define ei_inb_p(port) in_8(port)
+#define ei_outb_p(val, port) out_8(port, val)
#include "lib8390.c"
#define WD_START_PG 0x00 /* First page of TX buffer */
#define CABLETRON_RX_START_PG 0x00 /* First page of RX buffer */
#define CABLETRON_RX_STOP_PG 0x30 /* Last page +1 of RX ring */
-#define CABLETRON_TX_START_PG CABLETRON_RX_STOP_PG /* First page of TX buffer */
+#define CABLETRON_TX_START_PG CABLETRON_RX_STOP_PG
+ /* First page of TX buffer */
-/* Unfortunately it seems we have to hardcode these for the moment */
-/* Shouldn't the card know about this? Does anyone know where to read it off the card? Do we trust the data provided by the card? */
+/*
+ * Unfortunately it seems we have to hardcode these for the moment
+ * Shouldn't the card know about this?
+ * Does anyone know where to read it off the card?
+ * Do we trust the data provided by the card?
+ */
#define DAYNA_8390_BASE 0x80000
#define DAYNA_8390_MEM 0x00000
@@ -80,7 +87,7 @@ enum mac8390_type {
MAC8390_KINETICS,
};
-static const char * cardname[] = {
+static const char *cardname[] = {
"apple",
"asante",
"farallon",
@@ -90,7 +97,7 @@ static const char * cardname[] = {
"kinetics",
};
-static int word16[] = {
+static const int word16[] = {
1, /* apple */
1, /* asante */
1, /* farallon */
@@ -101,7 +108,7 @@ static int word16[] = {
};
/* on which cards do we use NuBus resources? */
-static int useresources[] = {
+static const int useresources[] = {
1, /* apple */
1, /* asante */
1, /* farallon */
@@ -117,22 +124,22 @@ enum mac8390_access {
ACCESS_16,
};
-extern int mac8390_memtest(struct net_device * dev);
-static int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev,
+extern int mac8390_memtest(struct net_device *dev);
+static int mac8390_initdev(struct net_device *dev, struct nubus_dev *ndev,
enum mac8390_type type);
-static int mac8390_open(struct net_device * dev);
-static int mac8390_close(struct net_device * dev);
+static int mac8390_open(struct net_device *dev);
+static int mac8390_close(struct net_device *dev);
static void mac8390_no_reset(struct net_device *dev);
static void interlan_reset(struct net_device *dev);
/* Sane (32-bit chunk memory read/write) - Some Farallon and Apple do this*/
static void sane_get_8390_hdr(struct net_device *dev,
struct e8390_pkt_hdr *hdr, int ring_page);
-static void sane_block_input(struct net_device * dev, int count,
- struct sk_buff * skb, int ring_offset);
-static void sane_block_output(struct net_device * dev, int count,
- const unsigned char * buf, const int start_page);
+static void sane_block_input(struct net_device *dev, int count,
+ struct sk_buff *skb, int ring_offset);
+static void sane_block_output(struct net_device *dev, int count,
+ const unsigned char *buf, const int start_page);
/* dayna_memcpy to and from card */
static void dayna_memcpy_fromcard(struct net_device *dev, void *to,
@@ -148,8 +155,8 @@ static void dayna_block_input(struct net_device *dev, int count,
static void dayna_block_output(struct net_device *dev, int count,
const unsigned char *buf, int start_page);
-#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
-#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
+#define memcpy_fromio(a, b, c) memcpy((a), (void *)(b), (c))
+#define memcpy_toio(a, b, c) memcpy((void *)(a), (b), (c))
/* Slow Sane (16-bit chunk memory read/write) Cabletron uses this */
static void slow_sane_get_8390_hdr(struct net_device *dev,
@@ -164,70 +171,72 @@ static void word_memcpy_fromcard(void *tp, const void *fp, int count);
static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev)
{
switch (dev->dr_sw) {
- case NUBUS_DRSW_3COM:
- switch (dev->dr_hw) {
- case NUBUS_DRHW_APPLE_SONIC_NB:
- case NUBUS_DRHW_APPLE_SONIC_LC:
- case NUBUS_DRHW_SONNET:
- return MAC8390_NONE;
- break;
- default:
- return MAC8390_APPLE;
- break;
- }
+ case NUBUS_DRSW_3COM:
+ switch (dev->dr_hw) {
+ case NUBUS_DRHW_APPLE_SONIC_NB:
+ case NUBUS_DRHW_APPLE_SONIC_LC:
+ case NUBUS_DRHW_SONNET:
+ return MAC8390_NONE;
break;
-
- case NUBUS_DRSW_APPLE:
- switch (dev->dr_hw) {
- case NUBUS_DRHW_ASANTE_LC:
- return MAC8390_NONE;
- break;
- case NUBUS_DRHW_CABLETRON:
- return MAC8390_CABLETRON;
- break;
- default:
- return MAC8390_APPLE;
- break;
- }
+ default:
+ return MAC8390_APPLE;
break;
+ }
+ break;
- case NUBUS_DRSW_ASANTE:
- return MAC8390_ASANTE;
+ case NUBUS_DRSW_APPLE:
+ switch (dev->dr_hw) {
+ case NUBUS_DRHW_ASANTE_LC:
+ return MAC8390_NONE;
break;
-
- case NUBUS_DRSW_TECHWORKS:
- case NUBUS_DRSW_DAYNA2:
- case NUBUS_DRSW_DAYNA_LC:
- if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
- return MAC8390_CABLETRON;
- else
- return MAC8390_APPLE;
+ case NUBUS_DRHW_CABLETRON:
+ return MAC8390_CABLETRON;
break;
-
- case NUBUS_DRSW_FARALLON:
- return MAC8390_FARALLON;
+ default:
+ return MAC8390_APPLE;
break;
+ }
+ break;
- case NUBUS_DRSW_KINETICS:
- switch (dev->dr_hw) {
- case NUBUS_DRHW_INTERLAN:
- return MAC8390_INTERLAN;
- break;
- default:
- return MAC8390_KINETICS;
- break;
- }
- break;
+ case NUBUS_DRSW_ASANTE:
+ return MAC8390_ASANTE;
+ break;
- case NUBUS_DRSW_DAYNA:
- // These correspond to Dayna Sonic cards
- // which use the macsonic driver
- if (dev->dr_hw == NUBUS_DRHW_SMC9194 ||
- dev->dr_hw == NUBUS_DRHW_INTERLAN )
- return MAC8390_NONE;
- else
- return MAC8390_DAYNA;
+ case NUBUS_DRSW_TECHWORKS:
+ case NUBUS_DRSW_DAYNA2:
+ case NUBUS_DRSW_DAYNA_LC:
+ if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
+ return MAC8390_CABLETRON;
+ else
+ return MAC8390_APPLE;
+ break;
+
+ case NUBUS_DRSW_FARALLON:
+ return MAC8390_FARALLON;
+ break;
+
+ case NUBUS_DRSW_KINETICS:
+ switch (dev->dr_hw) {
+ case NUBUS_DRHW_INTERLAN:
+ return MAC8390_INTERLAN;
+ break;
+ default:
+ return MAC8390_KINETICS;
break;
+ }
+ break;
+
+ case NUBUS_DRSW_DAYNA:
+ /*
+ * These correspond to Dayna Sonic cards
+ * which use the macsonic driver
+ */
+ if (dev->dr_hw == NUBUS_DRHW_SMC9194 ||
+ dev->dr_hw == NUBUS_DRHW_INTERLAN)
+ return MAC8390_NONE;
+ else
+ return MAC8390_DAYNA;
+ break;
}
return MAC8390_NONE;
}
@@ -237,14 +246,14 @@ static enum mac8390_access __init mac8390_testio(volatile unsigned long membase)
unsigned long outdata = 0xA5A0B5B0;
unsigned long indata = 0x00000000;
/* Try writing 32 bits */
- memcpy((char *)membase, (char *)&outdata, 4);
+ memcpy(membase, &outdata, 4);
/* Now compare them */
if (memcmp((char *)&outdata, (char *)membase, 4) == 0)
return ACCESS_32;
/* Write 16 bit output */
- word_memcpy_tocard((char *)membase, (char *)&outdata, 4);
+ word_memcpy_tocard(membase, &outdata, 4);
/* Now read it back */
- word_memcpy_fromcard((char *)&indata, (char *)membase, 4);
+ word_memcpy_fromcard(&indata, membase, 4);
if (outdata == indata)
return ACCESS_16;
return ACCESS_UNKNOWN;
@@ -258,7 +267,7 @@ static int __init mac8390_memsize(unsigned long membase)
local_irq_save(flags);
/* Check up to 32K in 4K increments */
for (i = 0; i < 8; i++) {
- volatile unsigned short *m = (unsigned short *) (membase + (i * 0x1000));
+ volatile unsigned short *m = (unsigned short *)(membase + (i * 0x1000));
/* Unwriteable - we have a fully decoded card and the
RAM end located */
@@ -273,28 +282,127 @@ static int __init mac8390_memsize(unsigned long membase)
/* check for partial decode and wrap */
for (j = 0; j < i; j++) {
- volatile unsigned short *p = (unsigned short *) (membase + (j * 0x1000));
+ volatile unsigned short *p = (unsigned short *)(membase + (j * 0x1000));
if (*p != (0xA5A0 | j))
break;
- }
- }
+ }
+ }
local_irq_restore(flags);
- /* in any case, we stopped once we tried one block too many,
- or once we reached 32K */
- return i * 0x1000;
+ /*
+ * in any case, we stopped once we tried one block too many,
+ * or once we reached 32K
+ */
+ return i * 0x1000;
+}
+
+static bool __init mac8390_init(struct net_device *dev, struct nubus_dev *ndev,
+ enum mac8390_type cardtype)
+{
+ struct nubus_dir dir;
+ struct nubus_dirent ent;
+ int offset;
+ volatile unsigned short *i;
+
+ printk_once(KERN_INFO pr_fmt("%s"), version);
+
+ dev->irq = SLOT2IRQ(ndev->board->slot);
+ /* This is getting to be a habit */
+ dev->base_addr = (ndev->board->slot_addr |
+ ((ndev->board->slot & 0xf) << 20));
+
+ /*
+ * Get some Nubus info - we will trust the card's idea
+ * of where its memory and registers are.
+ */
+
+ if (nubus_get_func_dir(ndev, &dir) == -1) {
+ pr_err("%s: Unable to get Nubus functional directory for slot %X!\n",
+ dev->name, ndev->board->slot);
+ return false;
+ }
+
+ /* Get the MAC address */
+ if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1) {
+ pr_info("%s: Couldn't get MAC address!\n", dev->name);
+ return false;
+ }
+
+ nubus_get_rsrc_mem(dev->dev_addr, &ent, 6);
+
+ if (useresources[cardtype] == 1) {
+ nubus_rewinddir(&dir);
+ if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS,
+ &ent) == -1) {
+ pr_err("%s: Memory offset resource for slot %X not found!\n",
+ dev->name, ndev->board->slot);
+ return false;
+ }
+ nubus_get_rsrc_mem(&offset, &ent, 4);
+ dev->mem_start = dev->base_addr + offset;
+ /* yes, this is how the Apple driver does it */
+ dev->base_addr = dev->mem_start + 0x10000;
+ nubus_rewinddir(&dir);
+ if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH,
+ &ent) == -1) {
+ pr_info("%s: Memory length resource for slot %X not found, probing\n",
+ dev->name, ndev->board->slot);
+ offset = mac8390_memsize(dev->mem_start);
+ } else {
+ nubus_get_rsrc_mem(&offset, &ent, 4);
+ }
+ dev->mem_end = dev->mem_start + offset;
+ } else {
+ switch (cardtype) {
+ case MAC8390_KINETICS:
+ case MAC8390_DAYNA: /* it's the same */
+ dev->base_addr = (int)(ndev->board->slot_addr +
+ DAYNA_8390_BASE);
+ dev->mem_start = (int)(ndev->board->slot_addr +
+ DAYNA_8390_MEM);
+ dev->mem_end = dev->mem_start +
+ mac8390_memsize(dev->mem_start);
+ break;
+ case MAC8390_INTERLAN:
+ dev->base_addr = (int)(ndev->board->slot_addr +
+ INTERLAN_8390_BASE);
+ dev->mem_start = (int)(ndev->board->slot_addr +
+ INTERLAN_8390_MEM);
+ dev->mem_end = dev->mem_start +
+ mac8390_memsize(dev->mem_start);
+ break;
+ case MAC8390_CABLETRON:
+ dev->base_addr = (int)(ndev->board->slot_addr +
+ CABLETRON_8390_BASE);
+ dev->mem_start = (int)(ndev->board->slot_addr +
+ CABLETRON_8390_MEM);
+ /* The base address is unreadable if 0x00
+ * has been written to the command register
+ * Reset the chip by writing E8390_NODMA +
+ * E8390_PAGE0 + E8390_STOP just to be
+ * sure
+ */
+ i = (void *)dev->base_addr;
+ *i = 0x21;
+ dev->mem_end = dev->mem_start +
+ mac8390_memsize(dev->mem_start);
+ break;
+
+ default:
+ pr_err("Card type %s is unsupported, sorry\n",
+ ndev->board->name);
+ return false;
+ }
+ }
+
+ return true;
}
struct net_device * __init mac8390_probe(int unit)
{
struct net_device *dev;
- volatile unsigned short *i;
- int version_disp = 0;
- struct nubus_dev * ndev = NULL;
+ struct nubus_dev *ndev = NULL;
int err = -ENODEV;
- struct nubus_dir dir;
- struct nubus_dirent ent;
- int offset;
static unsigned int slots;
enum mac8390_type cardtype;
@@ -311,118 +419,19 @@ struct net_device * __init mac8390_probe(int unit)
if (unit >= 0)
sprintf(dev->name, "eth%d", unit);
- while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) {
+ while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET,
+ ndev))) {
/* Have we seen it already? */
- if (slots & (1<<ndev->board->slot))
+ if (slots & (1 << ndev->board->slot))
continue;
- slots |= 1<<ndev->board->slot;
+ slots |= 1 << ndev->board->slot;
- if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE)
+ cardtype = mac8390_ident(ndev);
+ if (cardtype == MAC8390_NONE)
continue;
- if (version_disp == 0) {
- version_disp = 1;
- printk(version);
- }
-
- dev->irq = SLOT2IRQ(ndev->board->slot);
- /* This is getting to be a habit */
- dev->base_addr = ndev->board->slot_addr | ((ndev->board->slot&0xf) << 20);
-
- /* Get some Nubus info - we will trust the card's idea
- of where its memory and registers are. */
-
- if (nubus_get_func_dir(ndev, &dir) == -1) {
- printk(KERN_ERR "%s: Unable to get Nubus functional"
- " directory for slot %X!\n",
- dev->name, ndev->board->slot);
+ if (!mac8390_init(dev, ndev, cardtype))
continue;
- }
-
- /* Get the MAC address */
- if ((nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent)) == -1) {
- printk(KERN_INFO "%s: Couldn't get MAC address!\n",
- dev->name);
- continue;
- } else {
- nubus_get_rsrc_mem(dev->dev_addr, &ent, 6);
- }
-
- if (useresources[cardtype] == 1) {
- nubus_rewinddir(&dir);
- if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, &ent) == -1) {
- printk(KERN_ERR "%s: Memory offset resource"
- " for slot %X not found!\n",
- dev->name, ndev->board->slot);
- continue;
- }
- nubus_get_rsrc_mem(&offset, &ent, 4);
- dev->mem_start = dev->base_addr + offset;
- /* yes, this is how the Apple driver does it */
- dev->base_addr = dev->mem_start + 0x10000;
- nubus_rewinddir(&dir);
- if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH, &ent) == -1) {
- printk(KERN_INFO "%s: Memory length resource"
- " for slot %X not found"
- ", probing\n",
- dev->name, ndev->board->slot);
- offset = mac8390_memsize(dev->mem_start);
- } else {
- nubus_get_rsrc_mem(&offset, &ent, 4);
- }
- dev->mem_end = dev->mem_start + offset;
- } else {
- switch (cardtype) {
- case MAC8390_KINETICS:
- case MAC8390_DAYNA: /* it's the same */
- dev->base_addr =
- (int)(ndev->board->slot_addr +
- DAYNA_8390_BASE);
- dev->mem_start =
- (int)(ndev->board->slot_addr +
- DAYNA_8390_MEM);
- dev->mem_end =
- dev->mem_start +
- mac8390_memsize(dev->mem_start);
- break;
- case MAC8390_INTERLAN:
- dev->base_addr =
- (int)(ndev->board->slot_addr +
- INTERLAN_8390_BASE);
- dev->mem_start =
- (int)(ndev->board->slot_addr +
- INTERLAN_8390_MEM);
- dev->mem_end =
- dev->mem_start +
- mac8390_memsize(dev->mem_start);
- break;
- case MAC8390_CABLETRON:
- dev->base_addr =
- (int)(ndev->board->slot_addr +
- CABLETRON_8390_BASE);
- dev->mem_start =
- (int)(ndev->board->slot_addr +
- CABLETRON_8390_MEM);
- /* The base address is unreadable if 0x00
- * has been written to the command register
- * Reset the chip by writing E8390_NODMA +
- * E8390_PAGE0 + E8390_STOP just to be
- * sure
- */
- i = (void *)dev->base_addr;
- *i = 0x21;
- dev->mem_end =
- dev->mem_start +
- mac8390_memsize(dev->mem_start);
- break;
-
- default:
- printk(KERN_ERR "Card type %s is"
- " unsupported, sorry\n",
- ndev->board->name);
- continue;
- }
- }
/* Do the nasty 8390 stuff */
if (!mac8390_initdev(dev, ndev, cardtype))
@@ -458,7 +467,7 @@ int init_module(void)
dev_mac890[i] = dev;
}
if (!i) {
- printk(KERN_NOTICE "mac8390.c: No useable cards found, driver NOT installed.\n");
+ pr_notice("No useable cards found, driver NOT installed.\n");
return -ENODEV;
}
return 0;
@@ -493,22 +502,23 @@ static const struct net_device_ops mac8390_netdev_ops = {
#endif
};
-static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev,
- enum mac8390_type type)
+static int __init mac8390_initdev(struct net_device *dev,
+ struct nubus_dev *ndev,
+ enum mac8390_type type)
{
- static u32 fwrd4_offsets[16]={
+ static u32 fwrd4_offsets[16] = {
0, 4, 8, 12,
16, 20, 24, 28,
32, 36, 40, 44,
48, 52, 56, 60
};
- static u32 back4_offsets[16]={
+ static u32 back4_offsets[16] = {
60, 56, 52, 48,
44, 40, 36, 32,
28, 24, 20, 16,
12, 8, 4, 0
};
- static u32 fwrd2_offsets[16]={
+ static u32 fwrd2_offsets[16] = {
0, 2, 4, 6,
8, 10, 12, 14,
16, 18, 20, 22,
@@ -526,47 +536,47 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd
/* Cabletron's TX/RX buffers are backwards */
if (type == MAC8390_CABLETRON) {
- ei_status.tx_start_page = CABLETRON_TX_START_PG;
- ei_status.rx_start_page = CABLETRON_RX_START_PG;
- ei_status.stop_page = CABLETRON_RX_STOP_PG;
- ei_status.rmem_start = dev->mem_start;
- ei_status.rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
+ ei_status.tx_start_page = CABLETRON_TX_START_PG;
+ ei_status.rx_start_page = CABLETRON_RX_START_PG;
+ ei_status.stop_page = CABLETRON_RX_STOP_PG;
+ ei_status.rmem_start = dev->mem_start;
+ ei_status.rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
} else {
- ei_status.tx_start_page = WD_START_PG;
- ei_status.rx_start_page = WD_START_PG + TX_PAGES;
- ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
- ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
- ei_status.rmem_end = dev->mem_end;
+ ei_status.tx_start_page = WD_START_PG;
+ ei_status.rx_start_page = WD_START_PG + TX_PAGES;
+ ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.rmem_end = dev->mem_end;
}
/* Fill in model-specific information and functions */
- switch(type) {
+ switch (type) {
case MAC8390_FARALLON:
case MAC8390_APPLE:
- switch(mac8390_testio(dev->mem_start)) {
- case ACCESS_UNKNOWN:
- printk("Don't know how to access card memory!\n");
- return -ENODEV;
- break;
+ switch (mac8390_testio(dev->mem_start)) {
+ case ACCESS_UNKNOWN:
+ pr_info("Don't know how to access card memory!\n");
+ return -ENODEV;
+ break;
- case ACCESS_16:
- /* 16 bit card, register map is reversed */
- ei_status.reset_8390 = &mac8390_no_reset;
- ei_status.block_input = &slow_sane_block_input;
- ei_status.block_output = &slow_sane_block_output;
- ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
- ei_status.reg_offset = back4_offsets;
- break;
+ case ACCESS_16:
+ /* 16 bit card, register map is reversed */
+ ei_status.reset_8390 = &mac8390_no_reset;
+ ei_status.block_input = &slow_sane_block_input;
+ ei_status.block_output = &slow_sane_block_output;
+ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+ ei_status.reg_offset = back4_offsets;
+ break;
- case ACCESS_32:
- /* 32 bit card, register map is reversed */
- ei_status.reset_8390 = &mac8390_no_reset;
- ei_status.block_input = &sane_block_input;
- ei_status.block_output = &sane_block_output;
- ei_status.get_8390_hdr = &sane_get_8390_hdr;
- ei_status.reg_offset = back4_offsets;
- access_bitmode = 1;
- break;
+ case ACCESS_32:
+ /* 32 bit card, register map is reversed */
+ ei_status.reset_8390 = &mac8390_no_reset;
+ ei_status.block_input = &sane_block_input;
+ ei_status.block_output = &sane_block_output;
+ ei_status.get_8390_hdr = &sane_get_8390_hdr;
+ ei_status.reg_offset = back4_offsets;
+ access_bitmode = 1;
+ break;
}
break;
@@ -608,24 +618,25 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd
ei_status.block_input = &slow_sane_block_input;
ei_status.block_output = &slow_sane_block_output;
ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
- ei_status.reg_offset = fwrd4_offsets;
- break;
+ ei_status.reg_offset = fwrd4_offsets;
+ break;
default:
- printk(KERN_ERR "Card type %s is unsupported, sorry\n", ndev->board->name);
+ pr_err("Card type %s is unsupported, sorry\n",
+ ndev->board->name);
return -ENODEV;
}
__NS8390_init(dev, 0);
/* Good, done, now spit out some messages */
- printk(KERN_INFO "%s: %s in slot %X (type %s)\n",
- dev->name, ndev->board->name, ndev->board->slot, cardname[type]);
- printk(KERN_INFO
- "MAC %pM IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n",
- dev->dev_addr, dev->irq,
- (unsigned int)(dev->mem_end - dev->mem_start) >> 10,
- dev->mem_start, access_bitmode ? 32 : 16);
+ pr_info("%s: %s in slot %X (type %s)\n",
+ dev->name, ndev->board->name, ndev->board->slot,
+ cardname[type]);
+ pr_info("MAC %pM IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n",
+ dev->dev_addr, dev->irq,
+ (unsigned int)(dev->mem_end - dev->mem_start) >> 10,
+ dev->mem_start, access_bitmode ? 32 : 16);
return 0;
}
@@ -633,7 +644,7 @@ static int mac8390_open(struct net_device *dev)
{
__ei_open(dev);
if (request_irq(dev->irq, __ei_interrupt, 0, "8390 Ethernet", dev)) {
- printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+ pr_info("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
return -EAGAIN;
}
return 0;
@@ -650,72 +661,71 @@ static void mac8390_no_reset(struct net_device *dev)
{
ei_status.txing = 0;
if (ei_debug > 1)
- printk("reset not supported\n");
+ pr_info("reset not supported\n");
return;
}
static void interlan_reset(struct net_device *dev)
{
- unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq));
+ unsigned char *target = nubus_slot_addr(IRQ2SLOT(dev->irq));
if (ei_debug > 1)
- printk("Need to reset the NS8390 t=%lu...", jiffies);
+ pr_info("Need to reset the NS8390 t=%lu...", jiffies);
ei_status.txing = 0;
target[0xC0000] = 0;
if (ei_debug > 1)
- printk("reset complete\n");
+ pr_cont("reset complete\n");
return;
}
/* dayna_memcpy_fromio/dayna_memcpy_toio */
/* directly from daynaport.c by Alan Cox */
-static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
+static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from,
+ int count)
{
volatile unsigned char *ptr;
- unsigned char *target=to;
- from<<=1; /* word, skip overhead */
- ptr=(unsigned char *)(dev->mem_start+from);
+ unsigned char *target = to;
+ from <<= 1; /* word, skip overhead */
+ ptr = (unsigned char *)(dev->mem_start+from);
/* Leading byte? */
- if (from&2) {
+ if (from & 2) {
*target++ = ptr[-1];
ptr += 2;
count--;
}
- while(count>=2)
- {
+ while (count >= 2) {
*(unsigned short *)target = *(unsigned short volatile *)ptr;
ptr += 4; /* skip cruft */
target += 2;
- count-=2;
+ count -= 2;
}
/* Trailing byte? */
- if(count)
+ if (count)
*target = *ptr;
}
-static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count)
+static void dayna_memcpy_tocard(struct net_device *dev, int to,
+ const void *from, int count)
{
volatile unsigned short *ptr;
- const unsigned char *src=from;
- to<<=1; /* word, skip overhead */
- ptr=(unsigned short *)(dev->mem_start+to);
+ const unsigned char *src = from;
+ to <<= 1; /* word, skip overhead */
+ ptr = (unsigned short *)(dev->mem_start+to);
/* Leading byte? */
- if (to&2) { /* avoid a byte write (stomps on other data) */
+ if (to & 2) { /* avoid a byte write (stomps on other data) */
ptr[-1] = (ptr[-1]&0xFF00)|*src++;
ptr++;
count--;
}
- while(count>=2)
- {
- *ptr++=*(unsigned short *)src; /* Copy and */
+ while (count >= 2) {
+ *ptr++ = *(unsigned short *)src; /* Copy and */
ptr++; /* skip cruft */
src += 2;
- count-=2;
+ count -= 2;
}
/* Trailing byte? */
- if(count)
- {
+ if (count) {
/* card doesn't like byte writes */
- *ptr=(*ptr&0x00FF)|(*src << 8);
+ *ptr = (*ptr & 0x00FF) | (*src << 8);
}
}
@@ -738,11 +748,14 @@ static void sane_block_input(struct net_device *dev, int count,
if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
int semi_count = ei_status.rmem_end - xfer_start;
- memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, semi_count);
+ memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base,
+ semi_count);
count -= semi_count;
- memcpy_toio(skb->data + semi_count, (char *)ei_status.rmem_start, count);
+ memcpy_toio(skb->data + semi_count,
+ (char *)ei_status.rmem_start, count);
} else {
- memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, count);
+ memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base,
+ count);
}
}
@@ -755,16 +768,18 @@ static void sane_block_output(struct net_device *dev, int count,
}
/* dayna block input/output */
-static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+static void dayna_get_8390_hdr(struct net_device *dev,
+ struct e8390_pkt_hdr *hdr, int ring_page)
{
unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
- dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4);
+ dayna_memcpy_fromcard(dev, hdr, hdr_start, 4);
/* Fix endianness */
- hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
+ hdr->count = (hdr->count & 0xFF) << 8 | (hdr->count >> 8);
}
-static void dayna_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+static void dayna_block_input(struct net_device *dev, int count,
+ struct sk_buff *skb, int ring_offset)
{
unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
unsigned long xfer_start = xfer_base+dev->mem_start;
@@ -772,8 +787,7 @@ static void dayna_block_input(struct net_device *dev, int count, struct sk_buff
/* Note the offset math is done in card memory space which is word
per long onto our space. */
- if (xfer_start + count > ei_status.rmem_end)
- {
+ if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
int semi_count = ei_status.rmem_end - xfer_start;
dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
@@ -781,15 +795,14 @@ static void dayna_block_input(struct net_device *dev, int count, struct sk_buff
dayna_memcpy_fromcard(dev, skb->data + semi_count,
ei_status.rmem_start - dev->mem_start,
count);
- }
- else
- {
+ } else {
dayna_memcpy_fromcard(dev, skb->data, xfer_base, count);
}
}
-static void dayna_block_output(struct net_device *dev, int count, const unsigned char *buf,
- int start_page)
+static void dayna_block_output(struct net_device *dev, int count,
+ const unsigned char *buf,
+ int start_page)
{
long shmem = (start_page - WD_START_PG)<<8;
@@ -797,40 +810,39 @@ static void dayna_block_output(struct net_device *dev, int count, const unsigned
}
/* Cabletron block I/O */
-static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
- int ring_page)
+static void slow_sane_get_8390_hdr(struct net_device *dev,
+ struct e8390_pkt_hdr *hdr,
+ int ring_page)
{
unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
- word_memcpy_fromcard((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
+ word_memcpy_fromcard(hdr, (char *)dev->mem_start + hdr_start, 4);
/* Register endianism - fix here rather than 8390.c */
hdr->count = (hdr->count&0xFF)<<8|(hdr->count>>8);
}
-static void slow_sane_block_input(struct net_device *dev, int count, struct sk_buff *skb,
- int ring_offset)
+static void slow_sane_block_input(struct net_device *dev, int count,
+ struct sk_buff *skb, int ring_offset)
{
unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
unsigned long xfer_start = xfer_base+dev->mem_start;
- if (xfer_start + count > ei_status.rmem_end)
- {
+ if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
int semi_count = ei_status.rmem_end - xfer_start;
- word_memcpy_fromcard(skb->data, (char *)dev->mem_start +
- xfer_base, semi_count);
+ word_memcpy_fromcard(skb->data,
+ (char *)dev->mem_start + xfer_base,
+ semi_count);
count -= semi_count;
word_memcpy_fromcard(skb->data + semi_count,
(char *)ei_status.rmem_start, count);
- }
- else
- {
- word_memcpy_fromcard(skb->data, (char *)dev->mem_start +
- xfer_base, count);
+ } else {
+ word_memcpy_fromcard(skb->data,
+ (char *)dev->mem_start + xfer_base, count);
}
}
-static void slow_sane_block_output(struct net_device *dev, int count, const unsigned char *buf,
- int start_page)
+static void slow_sane_block_output(struct net_device *dev, int count,
+ const unsigned char *buf, int start_page)
{
long shmem = (start_page - WD_START_PG)<<8;
@@ -843,10 +855,10 @@ static void word_memcpy_tocard(void *tp, const void *fp, int count)
const unsigned short *from = fp;
count++;
- count/=2;
+ count /= 2;
- while(count--)
- *to++=*from++;
+ while (count--)
+ *to++ = *from++;
}
static void word_memcpy_fromcard(void *tp, const void *fp, int count)
@@ -855,10 +867,10 @@ static void word_memcpy_fromcard(void *tp, const void *fp, int count)
const volatile unsigned short *from = fp;
count++;
- count/=2;
+ count /= 2;
- while(count--)
- *to++=*from++;
+ while (count--)
+ *to++ = *from++;
}
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index 23b633e2ac42..c292a608f9a9 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -568,9 +568,7 @@ static void set_multicast_list(struct net_device *dev)
if(dev->flags&IFF_PROMISC)
{
lp->rx_mode = RX_ALL_ACCEPT;
- }
- else if((dev->flags&IFF_ALLMULTI)||dev->mc_list)
- {
+ } else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) {
/* The multicast-accept list is initialized to accept-all, and we
rely on higher-level filtering for now. */
lp->rx_mode = RX_MULTCAST_ACCEPT;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 1d0d4d9ab623..c8a18a6203c8 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -189,18 +189,11 @@ static void macb_handle_link_change(struct net_device *dev)
static int macb_mii_probe(struct net_device *dev)
{
struct macb *bp = netdev_priv(dev);
- struct phy_device *phydev = NULL;
+ struct phy_device *phydev;
struct eth_platform_data *pdata;
- int phy_addr;
-
- /* find the first phy */
- for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
- if (bp->mii_bus->phy_map[phy_addr]) {
- phydev = bp->mii_bus->phy_map[phy_addr];
- break;
- }
- }
+ int ret;
+ phydev = phy_find_first(bp->mii_bus);
if (!phydev) {
printk (KERN_ERR "%s: no PHY found\n", dev->name);
return -1;
@@ -210,17 +203,13 @@ static int macb_mii_probe(struct net_device *dev)
/* TODO : add pin_irq */
/* attach the mac to the phy */
- if (pdata && pdata->is_rmii) {
- phydev = phy_connect(dev, dev_name(&phydev->dev),
- &macb_handle_link_change, 0, PHY_INTERFACE_MODE_RMII);
- } else {
- phydev = phy_connect(dev, dev_name(&phydev->dev),
- &macb_handle_link_change, 0, PHY_INTERFACE_MODE_MII);
- }
-
- if (IS_ERR(phydev)) {
+ ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, 0,
+ pdata && pdata->is_rmii ?
+ PHY_INTERFACE_MODE_RMII :
+ PHY_INTERFACE_MODE_MII);
+ if (ret) {
printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
- return PTR_ERR(phydev);
+ return ret;
}
/* mask with MAC supported features */
@@ -895,15 +884,12 @@ static void macb_sethashtable(struct net_device *dev)
{
struct dev_mc_list *curr;
unsigned long mc_filter[2];
- unsigned int i, bitnr;
+ unsigned int bitnr;
struct macb *bp = netdev_priv(dev);
mc_filter[0] = mc_filter[1] = 0;
- curr = dev->mc_list;
- for (i = 0; i < dev->mc_count; i++, curr = curr->next) {
- if (!curr) break; /* unexpected end of list */
-
+ netdev_for_each_mc_addr(curr, dev) {
bitnr = hash_get_index(curr->dmi_addr);
mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
}
@@ -934,7 +920,7 @@ static void macb_set_rx_mode(struct net_device *dev)
macb_writel(bp, HRB, -1);
macb_writel(bp, HRT, -1);
cfg |= MACB_BIT(NCFGR_MTI);
- } else if (dev->mc_count > 0) {
+ } else if (!netdev_mc_empty(dev)) {
/* Enable specific multicasts */
macb_sethashtable(dev);
cfg |= MACB_BIT(NCFGR_MTI);
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index d9fbad386389..ab5f0bf6d1ae 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -206,7 +206,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
mp->port_aaui = port_aaui;
else {
/* Apple Network Server uses the AAUI port */
- if (machine_is_compatible("AAPL,ShinerESB"))
+ if (of_machine_is_compatible("AAPL,ShinerESB"))
mp->port_aaui = 1;
else {
#ifdef CONFIG_MACE_AAUI_PORT
@@ -588,7 +588,7 @@ static void mace_set_multicast(struct net_device *dev)
{
struct mace_data *mp = netdev_priv(dev);
volatile struct mace __iomem *mb = mp->mace;
- int i, j;
+ int i;
u32 crc;
unsigned long flags;
@@ -598,7 +598,7 @@ static void mace_set_multicast(struct net_device *dev)
mp->maccc |= PROM;
} else {
unsigned char multicast_filter[8];
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
if (dev->flags & IFF_ALLMULTI) {
for (i = 0; i < 8; i++)
@@ -606,11 +606,10 @@ static void mace_set_multicast(struct net_device *dev)
} else {
for (i = 0; i < 8; i++)
multicast_filter[i] = 0;
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
crc = ether_crc_le(6, dmi->dmi_addr);
- j = crc >> 26; /* bit number in multicast_filter */
- multicast_filter[j >> 3] |= 1 << (j & 7);
- dmi = dmi->next;
+ i = crc >> 26; /* bit number in multicast_filter */
+ multicast_filter[i >> 3] |= 1 << (i & 7);
}
}
#if 0
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 44f3c2896f20..13ba8f4afb7e 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -39,7 +39,6 @@
#include "mace.h"
static char mac_mace_string[] = "macmace";
-static struct platform_device *mac_mace_device;
#define N_TX_BUFF_ORDER 0
#define N_TX_RING (1 << N_TX_BUFF_ORDER)
@@ -496,7 +495,7 @@ static void mace_set_multicast(struct net_device *dev)
{
struct mace_data *mp = netdev_priv(dev);
volatile struct mace *mb = mp->mace;
- int i, j;
+ int i;
u32 crc;
u8 maccc;
unsigned long flags;
@@ -509,7 +508,7 @@ static void mace_set_multicast(struct net_device *dev)
mb->maccc |= PROM;
} else {
unsigned char multicast_filter[8];
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
if (dev->flags & IFF_ALLMULTI) {
for (i = 0; i < 8; i++) {
@@ -518,11 +517,11 @@ static void mace_set_multicast(struct net_device *dev)
} else {
for (i = 0; i < 8; i++)
multicast_filter[i] = 0;
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
crc = ether_crc_le(6, dmi->dmi_addr);
- j = crc >> 26; /* bit number in multicast_filter */
- multicast_filter[j >> 3] |= 1 << (j & 7);
- dmi = dmi->next;
+ /* bit number in multicast_filter */
+ i = crc >> 26;
+ multicast_filter[i >> 3] |= 1 << (i & 7);
}
}
@@ -752,6 +751,7 @@ static irqreturn_t mace_dma_intr(int irq, void *dev_id)
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Macintosh MACE ethernet driver");
+MODULE_ALIAS("platform:macmace");
static int __devexit mac_mace_device_remove (struct platform_device *pdev)
{
@@ -777,47 +777,22 @@ static struct platform_driver mac_mace_driver = {
.probe = mace_probe,
.remove = __devexit_p(mac_mace_device_remove),
.driver = {
- .name = mac_mace_string,
+ .name = mac_mace_string,
+ .owner = THIS_MODULE,
},
};
static int __init mac_mace_init_module(void)
{
- int err;
-
if (!MACH_IS_MAC)
return -ENODEV;
- if ((err = platform_driver_register(&mac_mace_driver))) {
- printk(KERN_ERR "Driver registration failed\n");
- return err;
- }
-
- mac_mace_device = platform_device_alloc(mac_mace_string, 0);
- if (!mac_mace_device)
- goto out_unregister;
-
- if (platform_device_add(mac_mace_device)) {
- platform_device_put(mac_mace_device);
- mac_mace_device = NULL;
- }
-
- return 0;
-
-out_unregister:
- platform_driver_unregister(&mac_mace_driver);
-
- return -ENOMEM;
+ return platform_driver_register(&mac_mace_driver);
}
static void __exit mac_mace_cleanup_module(void)
{
platform_driver_unregister(&mac_mace_driver);
-
- if (mac_mace_device) {
- platform_device_unregister(mac_mace_device);
- mac_mace_device = NULL;
- }
}
module_init(mac_mace_init_module);
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index 875d361fb79d..24109c288108 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -62,7 +62,6 @@
#include <asm/mac_via.h>
static char mac_sonic_string[] = "macsonic";
-static struct platform_device *mac_sonic_device;
#include "sonic.h"
@@ -607,6 +606,7 @@ out:
MODULE_DESCRIPTION("Macintosh SONIC ethernet driver");
module_param(sonic_debug, int, 0);
MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)");
+MODULE_ALIAS("platform:macsonic");
#include "sonic.c"
@@ -627,44 +627,19 @@ static struct platform_driver mac_sonic_driver = {
.probe = mac_sonic_probe,
.remove = __devexit_p(mac_sonic_device_remove),
.driver = {
- .name = mac_sonic_string,
+ .name = mac_sonic_string,
+ .owner = THIS_MODULE,
},
};
static int __init mac_sonic_init_module(void)
{
- int err;
-
- if ((err = platform_driver_register(&mac_sonic_driver))) {
- printk(KERN_ERR "Driver registration failed\n");
- return err;
- }
-
- mac_sonic_device = platform_device_alloc(mac_sonic_string, 0);
- if (!mac_sonic_device)
- goto out_unregister;
-
- if (platform_device_add(mac_sonic_device)) {
- platform_device_put(mac_sonic_device);
- mac_sonic_device = NULL;
- }
-
- return 0;
-
-out_unregister:
- platform_driver_unregister(&mac_sonic_driver);
-
- return -ENOMEM;
+ return platform_driver_register(&mac_sonic_driver);
}
static void __exit mac_sonic_cleanup_module(void)
{
platform_driver_unregister(&mac_sonic_driver);
-
- if (mac_sonic_device) {
- platform_device_unregister(mac_sonic_device);
- mac_sonic_device = NULL;
- }
}
module_init(mac_sonic_init_module);
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 21a9c9ab4b34..40faa368b07a 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -39,31 +39,6 @@ struct macvlan_port {
struct list_head vlans;
};
-/**
- * struct macvlan_rx_stats - MACVLAN percpu rx stats
- * @rx_packets: number of received packets
- * @rx_bytes: number of received bytes
- * @multicast: number of received multicast packets
- * @rx_errors: number of errors
- */
-struct macvlan_rx_stats {
- unsigned long rx_packets;
- unsigned long rx_bytes;
- unsigned long multicast;
- unsigned long rx_errors;
-};
-
-struct macvlan_dev {
- struct net_device *dev;
- struct list_head list;
- struct hlist_node hlist;
- struct macvlan_port *port;
- struct net_device *lowerdev;
- struct macvlan_rx_stats *rx_stats;
- enum macvlan_mode mode;
-};
-
-
static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
const unsigned char *addr)
{
@@ -118,31 +93,17 @@ static int macvlan_addr_busy(const struct macvlan_port *port,
return 0;
}
-static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
- unsigned int len, bool success,
- bool multicast)
-{
- struct macvlan_rx_stats *rx_stats;
-
- rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id());
- if (likely(success)) {
- rx_stats->rx_packets++;;
- rx_stats->rx_bytes += len;
- if (multicast)
- rx_stats->multicast++;
- } else {
- rx_stats->rx_errors++;
- }
-}
-static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev,
+static int macvlan_broadcast_one(struct sk_buff *skb,
+ const struct macvlan_dev *vlan,
const struct ethhdr *eth, bool local)
{
+ struct net_device *dev = vlan->dev;
if (!skb)
return NET_RX_DROP;
if (local)
- return dev_forward_skb(dev, skb);
+ return vlan->forward(dev, skb);
skb->dev = dev;
if (!compare_ether_addr_64bits(eth->h_dest,
@@ -151,7 +112,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev,
else
skb->pkt_type = PACKET_MULTICAST;
- return netif_rx(skb);
+ return vlan->receive(skb);
}
static void macvlan_broadcast(struct sk_buff *skb,
@@ -175,7 +136,7 @@ static void macvlan_broadcast(struct sk_buff *skb,
continue;
nskb = skb_clone(skb, GFP_ATOMIC);
- err = macvlan_broadcast_one(nskb, vlan->dev, eth,
+ err = macvlan_broadcast_one(nskb, vlan, eth,
mode == MACVLAN_MODE_BRIDGE);
macvlan_count_rx(vlan, skb->len + ETH_HLEN,
err == NET_RX_SUCCESS, 1);
@@ -238,7 +199,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
skb->dev = dev;
skb->pkt_type = PACKET_HOST;
- netif_rx(skb);
+ vlan->receive(skb);
return NULL;
}
@@ -260,7 +221,7 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
dest = macvlan_hash_lookup(port, eth->h_dest);
if (dest && dest->mode == MACVLAN_MODE_BRIDGE) {
unsigned int length = skb->len + ETH_HLEN;
- int ret = dev_forward_skb(dest->dev, skb);
+ int ret = dest->forward(dest->dev, skb);
macvlan_count_rx(dest, length,
ret == NET_RX_SUCCESS, 0);
@@ -269,12 +230,12 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
}
xmit_world:
- skb->dev = vlan->lowerdev;
+ skb_set_dev(skb, vlan->lowerdev);
return dev_queue_xmit(skb);
}
-static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
+netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
int i = skb_get_queue_mapping(skb);
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
@@ -290,6 +251,7 @@ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
return ret;
}
+EXPORT_SYMBOL_GPL(macvlan_start_xmit);
static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, const void *daddr,
@@ -418,7 +380,7 @@ static struct lock_class_key macvlan_netdev_addr_lock_key;
#define MACVLAN_FEATURES \
(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
- NETIF_F_TSO_ECN | NETIF_F_TSO6)
+ NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO)
#define MACVLAN_STATE_MASK \
((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
@@ -623,8 +585,11 @@ static int macvlan_get_tx_queues(struct net *net,
return 0;
}
-static int macvlan_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[])
+int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[],
+ int (*receive)(struct sk_buff *skb),
+ int (*forward)(struct net_device *dev,
+ struct sk_buff *skb))
{
struct macvlan_dev *vlan = netdev_priv(dev);
struct macvlan_port *port;
@@ -664,6 +629,8 @@ static int macvlan_newlink(struct net *src_net, struct net_device *dev,
vlan->lowerdev = lowerdev;
vlan->dev = dev;
vlan->port = port;
+ vlan->receive = receive;
+ vlan->forward = forward;
vlan->mode = MACVLAN_MODE_VEPA;
if (data && data[IFLA_MACVLAN_MODE])
@@ -677,8 +644,17 @@ static int macvlan_newlink(struct net *src_net, struct net_device *dev,
netif_stacked_transfer_operstate(lowerdev, dev);
return 0;
}
+EXPORT_SYMBOL_GPL(macvlan_common_newlink);
-static void macvlan_dellink(struct net_device *dev, struct list_head *head)
+static int macvlan_newlink(struct net *src_net, struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
+{
+ return macvlan_common_newlink(src_net, dev, tb, data,
+ netif_rx,
+ dev_forward_skb);
+}
+
+void macvlan_dellink(struct net_device *dev, struct list_head *head)
{
struct macvlan_dev *vlan = netdev_priv(dev);
struct macvlan_port *port = vlan->port;
@@ -689,6 +665,7 @@ static void macvlan_dellink(struct net_device *dev, struct list_head *head)
if (list_empty(&port->vlans))
macvlan_port_destroy(port->dev);
}
+EXPORT_SYMBOL_GPL(macvlan_dellink);
static int macvlan_changelink(struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
@@ -720,19 +697,27 @@ static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = {
[IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
};
-static struct rtnl_link_ops macvlan_link_ops __read_mostly = {
+int macvlan_link_register(struct rtnl_link_ops *ops)
+{
+ /* common fields */
+ ops->priv_size = sizeof(struct macvlan_dev);
+ ops->get_tx_queues = macvlan_get_tx_queues;
+ ops->setup = macvlan_setup;
+ ops->validate = macvlan_validate;
+ ops->maxtype = IFLA_MACVLAN_MAX;
+ ops->policy = macvlan_policy;
+ ops->changelink = macvlan_changelink;
+ ops->get_size = macvlan_get_size;
+ ops->fill_info = macvlan_fill_info;
+
+ return rtnl_link_register(ops);
+};
+EXPORT_SYMBOL_GPL(macvlan_link_register);
+
+static struct rtnl_link_ops macvlan_link_ops = {
.kind = "macvlan",
- .priv_size = sizeof(struct macvlan_dev),
- .get_tx_queues = macvlan_get_tx_queues,
- .setup = macvlan_setup,
- .validate = macvlan_validate,
.newlink = macvlan_newlink,
.dellink = macvlan_dellink,
- .maxtype = IFLA_MACVLAN_MAX,
- .policy = macvlan_policy,
- .changelink = macvlan_changelink,
- .get_size = macvlan_get_size,
- .fill_info = macvlan_fill_info,
};
static int macvlan_device_event(struct notifier_block *unused,
@@ -761,7 +746,7 @@ static int macvlan_device_event(struct notifier_block *unused,
break;
case NETDEV_UNREGISTER:
list_for_each_entry_safe(vlan, next, &port->vlans, list)
- macvlan_dellink(vlan->dev, NULL);
+ vlan->dev->rtnl_link_ops->dellink(vlan->dev, NULL);
break;
}
return NOTIFY_DONE;
@@ -778,7 +763,7 @@ static int __init macvlan_init_module(void)
register_netdevice_notifier(&macvlan_notifier_block);
macvlan_handle_frame_hook = macvlan_handle_frame;
- err = rtnl_link_register(&macvlan_link_ops);
+ err = macvlan_link_register(&macvlan_link_ops);
if (err < 0)
goto err1;
return 0;
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
new file mode 100644
index 000000000000..55ceae09738e
--- /dev/null
+++ b/drivers/net/macvtap.c
@@ -0,0 +1,803 @@
+#include <linux/etherdevice.h>
+#include <linux/if_macvlan.h>
+#include <linux/interrupt.h>
+#include <linux/nsproxy.h>
+#include <linux/compat.h>
+#include <linux/if_tun.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/cache.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+
+#include <net/net_namespace.h>
+#include <net/rtnetlink.h>
+#include <net/sock.h>
+#include <linux/virtio_net.h>
+
+/*
+ * A macvtap queue is the central object of this driver, it connects
+ * an open character device to a macvlan interface. There can be
+ * multiple queues on one interface, which map back to queues
+ * implemented in hardware on the underlying device.
+ *
+ * macvtap_proto is used to allocate queues through the sock allocation
+ * mechanism.
+ *
+ * TODO: multiqueue support is currently not implemented, even though
+ * macvtap is basically prepared for that. We will need to add this
+ * here as well as in virtio-net and qemu to get line rate on 10gbit
+ * adapters from a guest.
+ */
+struct macvtap_queue {
+ struct sock sk;
+ struct socket sock;
+ struct macvlan_dev *vlan;
+ struct file *file;
+ unsigned int flags;
+};
+
+static struct proto macvtap_proto = {
+ .name = "macvtap",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof (struct macvtap_queue),
+};
+
+/*
+ * Minor number matches netdev->ifindex, so need a potentially
+ * large value. This also makes it possible to split the
+ * tap functionality out again in the future by offering it
+ * from other drivers besides macvtap. As long as every device
+ * only has one tap, the interface numbers assure that the
+ * device nodes are unique.
+ */
+static unsigned int macvtap_major;
+#define MACVTAP_NUM_DEVS 65536
+static struct class *macvtap_class;
+static struct cdev macvtap_cdev;
+
+static const struct proto_ops macvtap_socket_ops;
+
+/*
+ * RCU usage:
+ * The macvtap_queue and the macvlan_dev are loosely coupled, the
+ * pointers from one to the other can only be read while rcu_read_lock
+ * or macvtap_lock is held.
+ *
+ * Both the file and the macvlan_dev hold a reference on the macvtap_queue
+ * through sock_hold(&q->sk). When the macvlan_dev goes away first,
+ * q->vlan becomes inaccessible. When the files gets closed,
+ * macvtap_get_queue() fails.
+ *
+ * There may still be references to the struct sock inside of the
+ * queue from outbound SKBs, but these never reference back to the
+ * file or the dev. The data structure is freed through __sk_free
+ * when both our references and any pending SKBs are gone.
+ */
+static DEFINE_SPINLOCK(macvtap_lock);
+
+/*
+ * Choose the next free queue, for now there is only one
+ */
+static int macvtap_set_queue(struct net_device *dev, struct file *file,
+ struct macvtap_queue *q)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ int err = -EBUSY;
+
+ spin_lock(&macvtap_lock);
+ if (rcu_dereference(vlan->tap))
+ goto out;
+
+ err = 0;
+ rcu_assign_pointer(q->vlan, vlan);
+ rcu_assign_pointer(vlan->tap, q);
+ sock_hold(&q->sk);
+
+ q->file = file;
+ file->private_data = q;
+
+out:
+ spin_unlock(&macvtap_lock);
+ return err;
+}
+
+/*
+ * The file owning the queue got closed, give up both
+ * the reference that the files holds as well as the
+ * one from the macvlan_dev if that still exists.
+ *
+ * Using the spinlock makes sure that we don't get
+ * to the queue again after destroying it.
+ */
+static void macvtap_put_queue(struct macvtap_queue *q)
+{
+ struct macvlan_dev *vlan;
+
+ spin_lock(&macvtap_lock);
+ vlan = rcu_dereference(q->vlan);
+ if (vlan) {
+ rcu_assign_pointer(vlan->tap, NULL);
+ rcu_assign_pointer(q->vlan, NULL);
+ sock_put(&q->sk);
+ }
+
+ spin_unlock(&macvtap_lock);
+
+ synchronize_rcu();
+ sock_put(&q->sk);
+}
+
+/*
+ * Since we only support one queue, just dereference the pointer.
+ */
+static struct macvtap_queue *macvtap_get_queue(struct net_device *dev,
+ struct sk_buff *skb)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+
+ return rcu_dereference(vlan->tap);
+}
+
+/*
+ * The net_device is going away, give up the reference
+ * that it holds on the queue (all the queues one day)
+ * and safely set the pointer from the queues to NULL.
+ */
+static void macvtap_del_queues(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ struct macvtap_queue *q;
+
+ spin_lock(&macvtap_lock);
+ q = rcu_dereference(vlan->tap);
+ if (!q) {
+ spin_unlock(&macvtap_lock);
+ return;
+ }
+
+ rcu_assign_pointer(vlan->tap, NULL);
+ rcu_assign_pointer(q->vlan, NULL);
+ spin_unlock(&macvtap_lock);
+
+ synchronize_rcu();
+ sock_put(&q->sk);
+}
+
+/*
+ * Forward happens for data that gets sent from one macvlan
+ * endpoint to another one in bridge mode. We just take
+ * the skb and put it into the receive queue.
+ */
+static int macvtap_forward(struct net_device *dev, struct sk_buff *skb)
+{
+ struct macvtap_queue *q = macvtap_get_queue(dev, skb);
+ if (!q)
+ return -ENOLINK;
+
+ skb_queue_tail(&q->sk.sk_receive_queue, skb);
+ wake_up_interruptible_poll(q->sk.sk_sleep, POLLIN | POLLRDNORM | POLLRDBAND);
+ return 0;
+}
+
+/*
+ * Receive is for data from the external interface (lowerdev),
+ * in case of macvtap, we can treat that the same way as
+ * forward, which macvlan cannot.
+ */
+static int macvtap_receive(struct sk_buff *skb)
+{
+ skb_push(skb, ETH_HLEN);
+ return macvtap_forward(skb->dev, skb);
+}
+
+static int macvtap_newlink(struct net *src_net,
+ struct net_device *dev,
+ struct nlattr *tb[],
+ struct nlattr *data[])
+{
+ struct device *classdev;
+ dev_t devt;
+ int err;
+
+ err = macvlan_common_newlink(src_net, dev, tb, data,
+ macvtap_receive, macvtap_forward);
+ if (err)
+ goto out;
+
+ devt = MKDEV(MAJOR(macvtap_major), dev->ifindex);
+
+ classdev = device_create(macvtap_class, &dev->dev, devt,
+ dev, "tap%d", dev->ifindex);
+ if (IS_ERR(classdev)) {
+ err = PTR_ERR(classdev);
+ macvtap_del_queues(dev);
+ }
+
+out:
+ return err;
+}
+
+static void macvtap_dellink(struct net_device *dev,
+ struct list_head *head)
+{
+ device_destroy(macvtap_class,
+ MKDEV(MAJOR(macvtap_major), dev->ifindex));
+
+ macvtap_del_queues(dev);
+ macvlan_dellink(dev, head);
+}
+
+static struct rtnl_link_ops macvtap_link_ops __read_mostly = {
+ .kind = "macvtap",
+ .newlink = macvtap_newlink,
+ .dellink = macvtap_dellink,
+};
+
+
+static void macvtap_sock_write_space(struct sock *sk)
+{
+ if (!sock_writeable(sk) ||
+ !test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags))
+ return;
+
+ if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+ wake_up_interruptible_poll(sk->sk_sleep, POLLOUT | POLLWRNORM | POLLWRBAND);
+}
+
+static int macvtap_open(struct inode *inode, struct file *file)
+{
+ struct net *net = current->nsproxy->net_ns;
+ struct net_device *dev = dev_get_by_index(net, iminor(inode));
+ struct macvtap_queue *q;
+ int err;
+
+ err = -ENODEV;
+ if (!dev)
+ goto out;
+
+ /* check if this is a macvtap device */
+ err = -EINVAL;
+ if (dev->rtnl_link_ops != &macvtap_link_ops)
+ goto out;
+
+ err = -ENOMEM;
+ q = (struct macvtap_queue *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL,
+ &macvtap_proto);
+ if (!q)
+ goto out;
+
+ init_waitqueue_head(&q->sock.wait);
+ q->sock.type = SOCK_RAW;
+ q->sock.state = SS_CONNECTED;
+ q->sock.file = file;
+ q->sock.ops = &macvtap_socket_ops;
+ sock_init_data(&q->sock, &q->sk);
+ q->sk.sk_write_space = macvtap_sock_write_space;
+ q->flags = IFF_VNET_HDR | IFF_NO_PI | IFF_TAP;
+
+ err = macvtap_set_queue(dev, file, q);
+ if (err)
+ sock_put(&q->sk);
+
+out:
+ if (dev)
+ dev_put(dev);
+
+ return err;
+}
+
+static int macvtap_release(struct inode *inode, struct file *file)
+{
+ struct macvtap_queue *q = file->private_data;
+ macvtap_put_queue(q);
+ return 0;
+}
+
+static unsigned int macvtap_poll(struct file *file, poll_table * wait)
+{
+ struct macvtap_queue *q = file->private_data;
+ unsigned int mask = POLLERR;
+
+ if (!q)
+ goto out;
+
+ mask = 0;
+ poll_wait(file, &q->sock.wait, wait);
+
+ if (!skb_queue_empty(&q->sk.sk_receive_queue))
+ mask |= POLLIN | POLLRDNORM;
+
+ if (sock_writeable(&q->sk) ||
+ (!test_and_set_bit(SOCK_ASYNC_NOSPACE, &q->sock.flags) &&
+ sock_writeable(&q->sk)))
+ mask |= POLLOUT | POLLWRNORM;
+
+out:
+ return mask;
+}
+
+static inline struct sk_buff *macvtap_alloc_skb(struct sock *sk, size_t prepad,
+ size_t len, size_t linear,
+ int noblock, int *err)
+{
+ struct sk_buff *skb;
+
+ /* Under a page? Don't bother with paged skb. */
+ if (prepad + len < PAGE_SIZE || !linear)
+ linear = len;
+
+ skb = sock_alloc_send_pskb(sk, prepad + linear, len - linear, noblock,
+ err);
+ if (!skb)
+ return NULL;
+
+ skb_reserve(skb, prepad);
+ skb_put(skb, linear);
+ skb->data_len = len - linear;
+ skb->len += len - linear;
+
+ return skb;
+}
+
+/*
+ * macvtap_skb_from_vnet_hdr and macvtap_skb_to_vnet_hdr should
+ * be shared with the tun/tap driver.
+ */
+static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb,
+ struct virtio_net_hdr *vnet_hdr)
+{
+ unsigned short gso_type = 0;
+ if (vnet_hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+ switch (vnet_hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
+ case VIRTIO_NET_HDR_GSO_TCPV4:
+ gso_type = SKB_GSO_TCPV4;
+ break;
+ case VIRTIO_NET_HDR_GSO_TCPV6:
+ gso_type = SKB_GSO_TCPV6;
+ break;
+ case VIRTIO_NET_HDR_GSO_UDP:
+ gso_type = SKB_GSO_UDP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (vnet_hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN)
+ gso_type |= SKB_GSO_TCP_ECN;
+
+ if (vnet_hdr->gso_size == 0)
+ return -EINVAL;
+ }
+
+ if (vnet_hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
+ if (!skb_partial_csum_set(skb, vnet_hdr->csum_start,
+ vnet_hdr->csum_offset))
+ return -EINVAL;
+ }
+
+ if (vnet_hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+ skb_shinfo(skb)->gso_size = vnet_hdr->gso_size;
+ skb_shinfo(skb)->gso_type = gso_type;
+
+ /* Header must be checked, and gso_segs computed. */
+ skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+ skb_shinfo(skb)->gso_segs = 0;
+ }
+ return 0;
+}
+
+static int macvtap_skb_to_vnet_hdr(const struct sk_buff *skb,
+ struct virtio_net_hdr *vnet_hdr)
+{
+ memset(vnet_hdr, 0, sizeof(*vnet_hdr));
+
+ if (skb_is_gso(skb)) {
+ struct skb_shared_info *sinfo = skb_shinfo(skb);
+
+ /* This is a hint as to how much should be linear. */
+ vnet_hdr->hdr_len = skb_headlen(skb);
+ vnet_hdr->gso_size = sinfo->gso_size;
+ if (sinfo->gso_type & SKB_GSO_TCPV4)
+ vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+ else if (sinfo->gso_type & SKB_GSO_TCPV6)
+ vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ else if (sinfo->gso_type & SKB_GSO_UDP)
+ vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
+ else
+ BUG();
+ if (sinfo->gso_type & SKB_GSO_TCP_ECN)
+ vnet_hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
+ } else
+ vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
+ vnet_hdr->csum_start = skb->csum_start -
+ skb_headroom(skb);
+ vnet_hdr->csum_offset = skb->csum_offset;
+ } /* else everything is zero */
+
+ return 0;
+}
+
+
+/* Get packet from user space buffer */
+static ssize_t macvtap_get_user(struct macvtap_queue *q,
+ const struct iovec *iv, size_t count,
+ int noblock)
+{
+ struct sk_buff *skb;
+ struct macvlan_dev *vlan;
+ size_t len = count;
+ int err;
+ struct virtio_net_hdr vnet_hdr = { 0 };
+ int vnet_hdr_len = 0;
+
+ if (q->flags & IFF_VNET_HDR) {
+ vnet_hdr_len = sizeof(vnet_hdr);
+
+ err = -EINVAL;
+ if ((len -= vnet_hdr_len) < 0)
+ goto err;
+
+ err = memcpy_fromiovecend((void *)&vnet_hdr, iv, 0,
+ vnet_hdr_len);
+ if (err < 0)
+ goto err;
+ if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
+ vnet_hdr.csum_start + vnet_hdr.csum_offset + 2 >
+ vnet_hdr.hdr_len)
+ vnet_hdr.hdr_len = vnet_hdr.csum_start +
+ vnet_hdr.csum_offset + 2;
+ err = -EINVAL;
+ if (vnet_hdr.hdr_len > len)
+ goto err;
+ }
+
+ err = -EINVAL;
+ if (unlikely(len < ETH_HLEN))
+ goto err;
+
+ skb = macvtap_alloc_skb(&q->sk, NET_IP_ALIGN, len, vnet_hdr.hdr_len,
+ noblock, &err);
+ if (!skb)
+ goto err;
+
+ err = skb_copy_datagram_from_iovec(skb, 0, iv, vnet_hdr_len, len);
+ if (err)
+ goto err_kfree;
+
+ skb_set_network_header(skb, ETH_HLEN);
+ skb_reset_mac_header(skb);
+ skb->protocol = eth_hdr(skb)->h_proto;
+
+ if (vnet_hdr_len) {
+ err = macvtap_skb_from_vnet_hdr(skb, &vnet_hdr);
+ if (err)
+ goto err_kfree;
+ }
+
+ rcu_read_lock_bh();
+ vlan = rcu_dereference(q->vlan);
+ if (vlan)
+ macvlan_start_xmit(skb, vlan->dev);
+ else
+ kfree_skb(skb);
+ rcu_read_unlock_bh();
+
+ return count;
+
+err_kfree:
+ kfree_skb(skb);
+
+err:
+ rcu_read_lock_bh();
+ vlan = rcu_dereference(q->vlan);
+ if (vlan)
+ netdev_get_tx_queue(vlan->dev, 0)->tx_dropped++;
+ rcu_read_unlock_bh();
+
+ return err;
+}
+
+static ssize_t macvtap_aio_write(struct kiocb *iocb, const struct iovec *iv,
+ unsigned long count, loff_t pos)
+{
+ struct file *file = iocb->ki_filp;
+ ssize_t result = -ENOLINK;
+ struct macvtap_queue *q = file->private_data;
+
+ result = macvtap_get_user(q, iv, iov_length(iv, count),
+ file->f_flags & O_NONBLOCK);
+ return result;
+}
+
+/* Put packet to the user space buffer */
+static ssize_t macvtap_put_user(struct macvtap_queue *q,
+ const struct sk_buff *skb,
+ const struct iovec *iv, int len)
+{
+ struct macvlan_dev *vlan;
+ int ret;
+ int vnet_hdr_len = 0;
+
+ if (q->flags & IFF_VNET_HDR) {
+ struct virtio_net_hdr vnet_hdr;
+ vnet_hdr_len = sizeof (vnet_hdr);
+ if ((len -= vnet_hdr_len) < 0)
+ return -EINVAL;
+
+ ret = macvtap_skb_to_vnet_hdr(skb, &vnet_hdr);
+ if (ret)
+ return ret;
+
+ if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, vnet_hdr_len))
+ return -EFAULT;
+ }
+
+ len = min_t(int, skb->len, len);
+
+ ret = skb_copy_datagram_const_iovec(skb, 0, iv, vnet_hdr_len, len);
+
+ rcu_read_lock_bh();
+ vlan = rcu_dereference(q->vlan);
+ if (vlan)
+ macvlan_count_rx(vlan, len, ret == 0, 0);
+ rcu_read_unlock_bh();
+
+ return ret ? ret : (len + vnet_hdr_len);
+}
+
+static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb,
+ const struct iovec *iv, unsigned long len,
+ int noblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct sk_buff *skb;
+ ssize_t ret = 0;
+
+ add_wait_queue(q->sk.sk_sleep, &wait);
+ while (len) {
+ current->state = TASK_INTERRUPTIBLE;
+
+ /* Read frames from the queue */
+ skb = skb_dequeue(&q->sk.sk_receive_queue);
+ if (!skb) {
+ if (noblock) {
+ ret = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ /* Nothing to read, let's sleep */
+ schedule();
+ continue;
+ }
+ ret = macvtap_put_user(q, skb, iv, len);
+ kfree_skb(skb);
+ break;
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(q->sk.sk_sleep, &wait);
+ return ret;
+}
+
+static ssize_t macvtap_aio_read(struct kiocb *iocb, const struct iovec *iv,
+ unsigned long count, loff_t pos)
+{
+ struct file *file = iocb->ki_filp;
+ struct macvtap_queue *q = file->private_data;
+ ssize_t len, ret = 0;
+
+ len = iov_length(iv, count);
+ if (len < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = macvtap_do_read(q, iocb, iv, len, file->f_flags & O_NONBLOCK);
+ ret = min_t(ssize_t, ret, len); /* XXX copied from tun.c. Why? */
+out:
+ return ret;
+}
+
+/*
+ * provide compatibility with generic tun/tap interface
+ */
+static long macvtap_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct macvtap_queue *q = file->private_data;
+ struct macvlan_dev *vlan;
+ void __user *argp = (void __user *)arg;
+ struct ifreq __user *ifr = argp;
+ unsigned int __user *up = argp;
+ unsigned int u;
+ int ret;
+
+ switch (cmd) {
+ case TUNSETIFF:
+ /* ignore the name, just look at flags */
+ if (get_user(u, &ifr->ifr_flags))
+ return -EFAULT;
+
+ ret = 0;
+ if ((u & ~IFF_VNET_HDR) != (IFF_NO_PI | IFF_TAP))
+ ret = -EINVAL;
+ else
+ q->flags = u;
+
+ return ret;
+
+ case TUNGETIFF:
+ rcu_read_lock_bh();
+ vlan = rcu_dereference(q->vlan);
+ if (vlan)
+ dev_hold(vlan->dev);
+ rcu_read_unlock_bh();
+
+ if (!vlan)
+ return -ENOLINK;
+
+ ret = 0;
+ if (copy_to_user(&ifr->ifr_name, q->vlan->dev->name, IFNAMSIZ) ||
+ put_user(q->flags, &ifr->ifr_flags))
+ ret = -EFAULT;
+ dev_put(vlan->dev);
+ return ret;
+
+ case TUNGETFEATURES:
+ if (put_user(IFF_TAP | IFF_NO_PI | IFF_VNET_HDR, up))
+ return -EFAULT;
+ return 0;
+
+ case TUNSETSNDBUF:
+ if (get_user(u, up))
+ return -EFAULT;
+
+ q->sk.sk_sndbuf = u;
+ return 0;
+
+ case TUNSETOFFLOAD:
+ /* let the user check for future flags */
+ if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 |
+ TUN_F_TSO_ECN | TUN_F_UFO))
+ return -EINVAL;
+
+ /* TODO: only accept frames with the features that
+ got enabled for forwarded frames */
+ if (!(q->flags & IFF_VNET_HDR))
+ return -EINVAL;
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static long macvtap_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return macvtap_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static const struct file_operations macvtap_fops = {
+ .owner = THIS_MODULE,
+ .open = macvtap_open,
+ .release = macvtap_release,
+ .aio_read = macvtap_aio_read,
+ .aio_write = macvtap_aio_write,
+ .poll = macvtap_poll,
+ .llseek = no_llseek,
+ .unlocked_ioctl = macvtap_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = macvtap_compat_ioctl,
+#endif
+};
+
+static int macvtap_sendmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *m, size_t total_len)
+{
+ struct macvtap_queue *q = container_of(sock, struct macvtap_queue, sock);
+ return macvtap_get_user(q, m->msg_iov, total_len,
+ m->msg_flags & MSG_DONTWAIT);
+}
+
+static int macvtap_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *m, size_t total_len,
+ int flags)
+{
+ struct macvtap_queue *q = container_of(sock, struct macvtap_queue, sock);
+ int ret;
+ if (flags & ~(MSG_DONTWAIT|MSG_TRUNC))
+ return -EINVAL;
+ ret = macvtap_do_read(q, iocb, m->msg_iov, total_len,
+ flags & MSG_DONTWAIT);
+ if (ret > total_len) {
+ m->msg_flags |= MSG_TRUNC;
+ ret = flags & MSG_TRUNC ? ret : total_len;
+ }
+ return ret;
+}
+
+/* Ops structure to mimic raw sockets with tun */
+static const struct proto_ops macvtap_socket_ops = {
+ .sendmsg = macvtap_sendmsg,
+ .recvmsg = macvtap_recvmsg,
+};
+
+/* Get an underlying socket object from tun file. Returns error unless file is
+ * attached to a device. The returned object works like a packet socket, it
+ * can be used for sock_sendmsg/sock_recvmsg. The caller is responsible for
+ * holding a reference to the file for as long as the socket is in use. */
+struct socket *macvtap_get_socket(struct file *file)
+{
+ struct macvtap_queue *q;
+ if (file->f_op != &macvtap_fops)
+ return ERR_PTR(-EINVAL);
+ q = file->private_data;
+ if (!q)
+ return ERR_PTR(-EBADFD);
+ return &q->sock;
+}
+EXPORT_SYMBOL_GPL(macvtap_get_socket);
+
+static int macvtap_init(void)
+{
+ int err;
+
+ err = alloc_chrdev_region(&macvtap_major, 0,
+ MACVTAP_NUM_DEVS, "macvtap");
+ if (err)
+ goto out1;
+
+ cdev_init(&macvtap_cdev, &macvtap_fops);
+ err = cdev_add(&macvtap_cdev, macvtap_major, MACVTAP_NUM_DEVS);
+ if (err)
+ goto out2;
+
+ macvtap_class = class_create(THIS_MODULE, "macvtap");
+ if (IS_ERR(macvtap_class)) {
+ err = PTR_ERR(macvtap_class);
+ goto out3;
+ }
+
+ err = macvlan_link_register(&macvtap_link_ops);
+ if (err)
+ goto out4;
+
+ return 0;
+
+out4:
+ class_unregister(macvtap_class);
+out3:
+ cdev_del(&macvtap_cdev);
+out2:
+ unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS);
+out1:
+ return err;
+}
+module_init(macvtap_init);
+
+static void macvtap_exit(void)
+{
+ rtnl_link_unregister(&macvtap_link_ops);
+ class_unregister(macvtap_class);
+ cdev_del(&macvtap_cdev);
+ unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS);
+}
+module_exit(macvtap_exit);
+
+MODULE_ALIAS_RTNL_LINK("macvtap");
+MODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index 2af81735386b..9f72cb45f4af 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -51,14 +51,11 @@
static const char *meth_str="SGI O2 Fast Ethernet";
-#define HAVE_TX_TIMEOUT
/* The maximum time waited (in jiffies) before assuming a Tx failed. (400ms) */
#define TX_TIMEOUT (400*HZ/1000)
-#ifdef HAVE_TX_TIMEOUT
static int timeout = TX_TIMEOUT;
module_param(timeout, int, 0);
-#endif
/*
* This structure is private to each device. It is used to pass
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c
index 829b9ec9ff67..64394647dddc 100644
--- a/drivers/net/mlx4/en_rx.c
+++ b/drivers/net/mlx4/en_rx.c
@@ -508,11 +508,11 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
/* We are copying all relevant data to the skb - temporarily
* synch buffers for the copy */
dma = be64_to_cpu(rx_desc->data[0].addr);
- dma_sync_single_range_for_cpu(&mdev->pdev->dev, dma, 0,
- length, DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(&mdev->pdev->dev, dma, length,
+ DMA_FROM_DEVICE);
skb_copy_to_linear_data(skb, va, length);
- dma_sync_single_range_for_device(&mdev->pdev->dev, dma, 0,
- length, DMA_FROM_DEVICE);
+ dma_sync_single_for_device(&mdev->pdev->dev, dma, length,
+ DMA_FROM_DEVICE);
skb->tail += length;
} else {
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 3cf56d90d859..8f6e816a7395 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -1271,7 +1271,7 @@ int mlx4_restart_one(struct pci_dev *pdev)
return __mlx4_init_one(pdev, NULL);
}
-static struct pci_device_id mlx4_pci_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(mlx4_pci_table) = {
{ PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */
{ PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */
{ PCI_VDEVICE(MELLANOX, 0x6354) }, /* MT25408 "Hermon" QDR */
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index af67af55efe7..c97b6e4365a9 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -55,7 +55,6 @@
#include <linux/types.h>
#include <linux/inet_lro.h>
#include <asm/system.h>
-#include <linux/list.h>
static char mv643xx_eth_driver_name[] = "mv643xx_eth";
static char mv643xx_eth_driver_version[] = "1.4";
@@ -1697,7 +1696,7 @@ static u32 uc_addr_filter_mask(struct net_device *dev)
return 0;
nibbles = 1 << (dev->dev_addr[5] & 0x0f);
- list_for_each_entry(ha, &dev->uc.list, list) {
+ netdev_for_each_uc_addr(ha, dev) {
if (memcmp(dev->dev_addr, ha->addr, 5))
return 0;
if ((dev->dev_addr[5] ^ ha->addr[5]) & 0xf0)
@@ -1795,7 +1794,7 @@ oom:
memset(mc_spec, 0, 0x100);
memset(mc_other, 0, 0x100);
- for (addr = dev->mc_list; addr != NULL; addr = addr->next) {
+ netdev_for_each_mc_addr(addr, dev) {
u8 *a = addr->da_addr;
u32 *table;
int entry;
@@ -2847,6 +2846,7 @@ static const struct net_device_ops mv643xx_eth_netdev_ops = {
.ndo_start_xmit = mv643xx_eth_xmit,
.ndo_set_rx_mode = mv643xx_eth_set_rx_mode,
.ndo_set_mac_address = mv643xx_eth_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = mv643xx_eth_ioctl,
.ndo_change_mtu = mv643xx_eth_change_mtu,
.ndo_tx_timeout = mv643xx_eth_tx_timeout,
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 3fcb1c356e0d..676c513e12fc 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -38,6 +38,8 @@
* Myricom, Inc., 325N Santa Anita Avenue, Arcadia, CA 91006
*************************************************************************/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/tcp.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
@@ -75,7 +77,7 @@
#include "myri10ge_mcp.h"
#include "myri10ge_mcp_gen_header.h"
-#define MYRI10GE_VERSION_STR "1.5.1-1.453"
+#define MYRI10GE_VERSION_STR "1.5.2-1.459"
MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -819,9 +821,7 @@ static int myri10ge_change_pause(struct myri10ge_priv *mgp, int pause)
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);
+ netdev_err(mgp->dev, "Failed to set flow control mode\n");
return status;
}
mgp->pause = pause;
@@ -837,8 +837,7 @@ myri10ge_change_promisc(struct myri10ge_priv *mgp, int promisc, int atomic)
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);
+ netdev_err(mgp->dev, "Failed to set promisc mode\n");
}
static int myri10ge_dma_test(struct myri10ge_priv *mgp, int test_type)
@@ -1201,6 +1200,9 @@ myri10ge_alloc_rx_pages(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
{
struct page *page;
int idx;
+#if MYRI10GE_ALLOC_SIZE > 4096
+ int end_offset;
+#endif
if (unlikely(rx->watchdog_needed && !watchdog))
return;
@@ -1242,9 +1244,9 @@ myri10ge_alloc_rx_pages(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
#if MYRI10GE_ALLOC_SIZE > 4096
/* don't cross a 4KB boundary */
- if ((rx->page_offset >> 12) !=
- ((rx->page_offset + bytes - 1) >> 12))
- rx->page_offset = (rx->page_offset + 4096) & ~4095;
+ end_offset = rx->page_offset + bytes - 1;
+ if ((unsigned)(rx->page_offset ^ end_offset) > 4095)
+ rx->page_offset = end_offset & ~4095;
#endif
rx->fill_cnt++;
@@ -1482,19 +1484,15 @@ static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
if (mgp->link_state == MXGEFW_LINK_UP) {
if (netif_msg_link(mgp))
- printk(KERN_INFO
- "myri10ge: %s: link up\n",
- mgp->dev->name);
+ netdev_info(mgp->dev, "link up\n");
netif_carrier_on(mgp->dev);
mgp->link_changes++;
} else {
if (netif_msg_link(mgp))
- printk(KERN_INFO
- "myri10ge: %s: link %s\n",
- mgp->dev->name,
- (link_up == MXGEFW_LINK_MYRINET ?
- "mismatch (Myrinet detected)" :
- "down"));
+ netdev_info(mgp->dev, "link %s\n",
+ link_up == MXGEFW_LINK_MYRINET ?
+ "mismatch (Myrinet detected)" :
+ "down");
netif_carrier_off(mgp->dev);
mgp->link_changes++;
}
@@ -1503,9 +1501,8 @@ static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
ntohl(stats->rdma_tags_available)) {
mgp->rdma_tags_available =
ntohl(stats->rdma_tags_available);
- printk(KERN_WARNING "myri10ge: %s: RDMA timed out! "
- "%d tags left\n", mgp->dev->name,
- mgp->rdma_tags_available);
+ netdev_warn(mgp->dev, "RDMA timed out! %d tags left\n",
+ mgp->rdma_tags_available);
}
mgp->down_cnt += stats->link_down;
if (stats->link_down)
@@ -1576,8 +1573,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg)
if (send_done_count != tx->pkt_done)
myri10ge_tx_done(ss, (int)send_done_count);
if (unlikely(i > myri10ge_max_irq_loops)) {
- printk(KERN_WARNING "myri10ge: %s: irq stuck?\n",
- mgp->dev->name);
+ netdev_err(mgp->dev, "irq stuck?\n");
stats->valid = 0;
schedule_work(&mgp->watchdog_work);
}
@@ -1614,16 +1610,14 @@ myri10ge_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
*/
ptr = mgp->product_code_string;
if (ptr == NULL) {
- printk(KERN_ERR "myri10ge: %s: Missing product code\n",
- netdev->name);
+ netdev_err(netdev, "Missing product code\n");
return 0;
}
for (i = 0; i < 3; i++, ptr++) {
ptr = strchr(ptr, '-');
if (ptr == NULL) {
- printk(KERN_ERR "myri10ge: %s: Invalid product "
- "code %s\n", netdev->name,
- mgp->product_code_string);
+ netdev_err(netdev, "Invalid product code %s\n",
+ mgp->product_code_string);
return 0;
}
}
@@ -2009,17 +2003,15 @@ static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss)
mgp->small_bytes + MXGEFW_PAD, 0);
if (ss->rx_small.fill_cnt < ss->rx_small.mask + 1) {
- printk(KERN_ERR
- "myri10ge: %s:slice-%d: alloced only %d small bufs\n",
- dev->name, slice, ss->rx_small.fill_cnt);
+ netdev_err(dev, "slice-%d: alloced only %d small bufs\n",
+ slice, ss->rx_small.fill_cnt);
goto abort_with_rx_small_ring;
}
myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 0);
if (ss->rx_big.fill_cnt < ss->rx_big.mask + 1) {
- printk(KERN_ERR
- "myri10ge: %s:slice-%d: alloced only %d big bufs\n",
- dev->name, slice, ss->rx_big.fill_cnt);
+ netdev_err(dev, "slice-%d: alloced only %d big bufs\n",
+ slice, ss->rx_big.fill_cnt);
goto abort_with_rx_big_ring;
}
@@ -2358,7 +2350,7 @@ static int myri10ge_open(struct net_device *dev)
mgp->running = MYRI10GE_ETH_STARTING;
status = myri10ge_reset(mgp);
if (status != 0) {
- printk(KERN_ERR "myri10ge: %s: failed reset\n", dev->name);
+ netdev_err(dev, "failed reset\n");
goto abort_with_nothing;
}
@@ -2370,9 +2362,7 @@ static int myri10ge_open(struct net_device *dev)
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES,
&cmd, 0);
if (status != 0) {
- printk(KERN_ERR
- "myri10ge: %s: failed to set number of slices\n",
- dev->name);
+ netdev_err(dev, "failed to set number of slices\n");
goto abort_with_nothing;
}
/* setup the indirection table */
@@ -2384,9 +2374,7 @@ static int myri10ge_open(struct net_device *dev)
MXGEFW_CMD_GET_RSS_TABLE_OFFSET,
&cmd, 0);
if (status != 0) {
- printk(KERN_ERR
- "myri10ge: %s: failed to setup rss tables\n",
- dev->name);
+ netdev_err(dev, "failed to setup rss tables\n");
goto abort_with_nothing;
}
@@ -2400,9 +2388,7 @@ static int myri10ge_open(struct net_device *dev)
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_ENABLE,
&cmd, 0);
if (status != 0) {
- printk(KERN_ERR
- "myri10ge: %s: failed to enable slices\n",
- dev->name);
+ netdev_err(dev, "failed to enable slices\n");
goto abort_with_nothing;
}
}
@@ -2450,9 +2436,7 @@ static int myri10ge_open(struct net_device *dev)
status = myri10ge_get_txrx(mgp, slice);
if (status != 0) {
- printk(KERN_ERR
- "myri10ge: %s: failed to get ring sizes or locations\n",
- dev->name);
+ netdev_err(dev, "failed to get ring sizes or locations\n");
goto abort_with_rings;
}
status = myri10ge_allocate_rings(ss);
@@ -2465,9 +2449,7 @@ static int myri10ge_open(struct net_device *dev)
if (slice == 0 || mgp->dev->real_num_tx_queues > 1)
status = myri10ge_set_stats(mgp, slice);
if (status) {
- printk(KERN_ERR
- "myri10ge: %s: Couldn't set stats DMA\n",
- dev->name);
+ netdev_err(dev, "Couldn't set stats DMA\n");
goto abort_with_rings;
}
@@ -2498,8 +2480,7 @@ static int myri10ge_open(struct net_device *dev)
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);
+ netdev_err(dev, "Couldn't set buffer sizes\n");
goto abort_with_rings;
}
@@ -2511,8 +2492,7 @@ static int myri10ge_open(struct net_device *dev)
cmd.data0 = 0;
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_TSO_MODE, &cmd, 0);
if (status && status != -ENOSYS) {
- printk(KERN_ERR "myri10ge: %s: Couldn't set TSO mode\n",
- dev->name);
+ netdev_err(dev, "Couldn't set TSO mode\n");
goto abort_with_rings;
}
@@ -2521,8 +2501,7 @@ static int myri10ge_open(struct net_device *dev)
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);
+ netdev_err(dev, "Couldn't bring up link\n");
goto abort_with_rings;
}
@@ -2575,15 +2554,12 @@ static int myri10ge_close(struct net_device *dev)
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);
+ netdev_err(dev, "Couldn't bring down link\n");
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);
+ netdev_err(dev, "never got down irq\n");
}
netif_tx_disable(dev);
myri10ge_free_irq(mgp);
@@ -2944,9 +2920,7 @@ abort_linearize:
idx = (idx + 1) & tx->mask;
} while (idx != last_idx);
if (skb_is_gso(skb)) {
- printk(KERN_ERR
- "myri10ge: %s: TSO but wanted to linearize?!?!?\n",
- mgp->dev->name);
+ netdev_err(mgp->dev, "TSO but wanted to linearize?!?!?\n");
goto drop;
}
@@ -3043,8 +3017,8 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
err = myri10ge_send_cmd(mgp, MXGEFW_ENABLE_ALLMULTI, &cmd, 1);
if (err != 0) {
- printk(KERN_ERR "myri10ge: %s: Failed MXGEFW_ENABLE_ALLMULTI,"
- " error status: %d\n", dev->name, err);
+ netdev_err(dev, "Failed MXGEFW_ENABLE_ALLMULTI, error status: %d\n",
+ err);
goto abort;
}
@@ -3058,14 +3032,13 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
err = myri10ge_send_cmd(mgp, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS,
&cmd, 1);
if (err != 0) {
- printk(KERN_ERR
- "myri10ge: %s: Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS"
- ", error status: %d\n", dev->name, err);
+ netdev_err(dev, "Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, error status: %d\n",
+ err);
goto abort;
}
/* Walk the multicast list, and add each address */
- for (mc_list = dev->mc_list; mc_list != NULL; mc_list = mc_list->next) {
+ netdev_for_each_mc_addr(mc_list, dev) {
memcpy(data, &mc_list->dmi_addr, 6);
cmd.data0 = ntohl(data[0]);
cmd.data1 = ntohl(data[1]);
@@ -3073,18 +3046,16 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
&cmd, 1);
if (err != 0) {
- printk(KERN_ERR "myri10ge: %s: Failed "
- "MXGEFW_JOIN_MULTICAST_GROUP, error status:"
- "%d\t", dev->name, err);
- printk(KERN_ERR "MAC %pM\n", mc_list->dmi_addr);
+ netdev_err(dev, "Failed MXGEFW_JOIN_MULTICAST_GROUP, error status:%d %pM\n",
+ err, mc_list->dmi_addr);
goto abort;
}
}
/* Enable multicast filtering */
err = myri10ge_send_cmd(mgp, MXGEFW_DISABLE_ALLMULTI, &cmd, 1);
if (err != 0) {
- printk(KERN_ERR "myri10ge: %s: Failed MXGEFW_DISABLE_ALLMULTI,"
- "error status: %d\n", dev->name, err);
+ netdev_err(dev, "Failed MXGEFW_DISABLE_ALLMULTI, error status: %d\n",
+ err);
goto abort;
}
@@ -3105,9 +3076,8 @@ static int myri10ge_set_mac_address(struct net_device *dev, void *addr)
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);
+ netdev_err(dev, "changing mac address failed with %d\n",
+ status);
return status;
}
@@ -3122,12 +3092,10 @@ static int myri10ge_change_mtu(struct net_device *dev, int new_mtu)
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);
+ netdev_err(dev, "new mtu (%d) is not valid\n", new_mtu);
return -EINVAL;
}
- printk(KERN_INFO "%s: changing mtu from %d to %d\n",
- dev->name, dev->mtu, new_mtu);
+ netdev_info(dev, "changing mtu from %d to %d\n", 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 */
@@ -3356,7 +3324,7 @@ static int myri10ge_suspend(struct pci_dev *pdev, pm_message_t state)
netif_device_detach(netdev);
if (netif_running(netdev)) {
- printk(KERN_INFO "myri10ge: closing %s\n", netdev->name);
+ netdev_info(netdev, "closing\n");
rtnl_lock();
myri10ge_close(netdev);
rtnl_unlock();
@@ -3383,8 +3351,7 @@ static int myri10ge_resume(struct pci_dev *pdev)
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);
+ netdev_err(mgp->dev, "device disappeared!\n");
return -EIO;
}
@@ -3463,10 +3430,9 @@ static void myri10ge_watchdog(struct work_struct *work)
* 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),%s resetting\n",
- mgp->dev->name, reboot,
- myri10ge_reset_recover ? " " : " not");
+ netdev_err(mgp->dev, "NIC rebooted (0x%x),%s resetting\n",
+ reboot,
+ myri10ge_reset_recover ? "" : " not");
if (myri10ge_reset_recover == 0)
return;
rtnl_lock();
@@ -3494,31 +3460,26 @@ static void myri10ge_watchdog(struct work_struct *work)
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);
+ netdev_err(mgp->dev, "device disappeared!\n");
return;
}
}
/* Perhaps it is a software error. Try to reset */
- printk(KERN_ERR "myri10ge: %s: device timeout, resetting\n",
- mgp->dev->name);
+ netdev_err(mgp->dev, "device timeout, resetting\n");
for (i = 0; i < mgp->num_slices; i++) {
tx = &mgp->ss[i].tx;
- printk(KERN_INFO
- "myri10ge: %s: (%d): %d %d %d %d %d %d\n",
- mgp->dev->name, i, tx->queue_active, tx->req,
- tx->done, tx->pkt_start, tx->pkt_done,
- (int)ntohl(mgp->ss[i].fw_stats->
- send_done_count));
+ netdev_err(mgp->dev, "(%d): %d %d %d %d %d %d\n",
+ i, tx->queue_active, tx->req,
+ tx->done, tx->pkt_start, tx->pkt_done,
+ (int)ntohl(mgp->ss[i].fw_stats->
+ send_done_count));
msleep(2000);
- printk(KERN_INFO
- "myri10ge: %s: (%d): %d %d %d %d %d %d\n",
- mgp->dev->name, i, tx->queue_active, tx->req,
- tx->done, tx->pkt_start, tx->pkt_done,
- (int)ntohl(mgp->ss[i].fw_stats->
- send_done_count));
+ netdev_info(mgp->dev, "(%d): %d %d %d %d %d %d\n",
+ i, tx->queue_active, tx->req,
+ tx->done, tx->pkt_start, tx->pkt_done,
+ (int)ntohl(mgp->ss[i].fw_stats->
+ send_done_count));
}
}
@@ -3528,8 +3489,7 @@ static void myri10ge_watchdog(struct work_struct *work)
}
status = myri10ge_load_firmware(mgp, 1);
if (status != 0)
- printk(KERN_ERR "myri10ge: %s: failed to load firmware\n",
- mgp->dev->name);
+ netdev_err(mgp->dev, "failed to load firmware\n");
else
myri10ge_open(mgp->dev);
rtnl_unlock();
@@ -3580,14 +3540,10 @@ static void myri10ge_watchdog_timer(unsigned long arg)
/* nic seems like it might be stuck.. */
if (rx_pause_cnt != mgp->watchdog_pause) {
if (net_ratelimit())
- printk(KERN_WARNING
- "myri10ge %s slice %d:"
- "TX paused, check link partner\n",
- mgp->dev->name, i);
+ netdev_err(mgp->dev, "slice %d: TX paused, check link partner\n",
+ i);
} else {
- printk(KERN_WARNING
- "myri10ge %s slice %d stuck:",
- mgp->dev->name, i);
+ netdev_warn(mgp->dev, "slice %d stuck:", i);
reset_needed = 1;
}
}
@@ -4085,7 +4041,7 @@ static void myri10ge_remove(struct pci_dev *pdev)
#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E 0x0008
#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9 0x0009
-static struct pci_device_id myri10ge_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(myri10ge_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E)},
{PCI_DEVICE
(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9)},
@@ -4127,13 +4083,11 @@ static struct notifier_block myri10ge_dca_notifier = {
static __init int myri10ge_init_module(void)
{
- printk(KERN_INFO "%s: Version %s\n", myri10ge_driver.name,
- MYRI10GE_VERSION_STR);
+ pr_info("Version %s\n", MYRI10GE_VERSION_STR);
if (myri10ge_rss_hash > MXGEFW_RSS_HASH_TYPE_MAX) {
- printk(KERN_ERR
- "%s: Illegal rssh hash type %d, defaulting to source port\n",
- myri10ge_driver.name, myri10ge_rss_hash);
+ pr_err("Illegal rssh hash type %d, defaulting to source port\n",
+ myri10ge_rss_hash);
myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT;
}
#ifdef CONFIG_MYRI10GE_DCA
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index b3513ad3b703..8b4313085359 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -716,10 +716,10 @@ static int myri_header(struct sk_buff *skb, struct net_device *dev,
pad[0] = MYRI_PAD_LEN;
pad[1] = 0xab;
- /* Set the protocol type. For a packet of type ETH_P_802_3 we put the length
- * in here instead. It is up to the 802.2 layer to carry protocol information.
+ /* Set the protocol type. For a packet of type ETH_P_802_3/2 we put the
+ * length in here instead.
*/
- if (type != ETH_P_802_3)
+ if (type != ETH_P_802_3 && type != ETH_P_802_2)
eth->h_proto = htons(type);
else
eth->h_proto = htons(len);
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 797fe164ce27..e52038783245 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -247,7 +247,7 @@ static struct {
{ "NatSemi DP8381[56]", 0, 24 },
};
-static struct pci_device_id natsemi_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(natsemi_pci_tbl) = {
{ PCI_VENDOR_ID_NS, 0x0020, 0x12d9, 0x000c, 0, 0, 0 },
{ PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
{ } /* terminate list */
@@ -2488,16 +2488,16 @@ static void __set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
rx_mode = RxFilterEnable | AcceptBroadcast
| AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys;
- } else if ((dev->mc_count > multicast_filter_limit) ||
+ } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
(dev->flags & IFF_ALLMULTI)) {
rx_mode = RxFilterEnable | AcceptBroadcast
| AcceptAllMulticast | AcceptMyPhys;
} else {
struct dev_mc_list *mclist;
int i;
+
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int b = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff;
mc_filter[b/8] |= (1 << (b & 0x07));
}
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index 3fcebb70151c..85aec4f10131 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -136,7 +136,7 @@ static struct {
};
-static struct pci_device_id ne2k_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(ne2k_pci_tbl) = {
{ 0x10ec, 0x8029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RealTek_RTL_8029 },
{ 0x1050, 0x0940, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940 },
{ 0x11f6, 0x1401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Compex_RL2000 },
diff --git a/drivers/net/netxen/Makefile b/drivers/net/netxen/Makefile
index 11d94e2434e4..861a0590b1f4 100644
--- a/drivers/net/netxen/Makefile
+++ b/drivers/net/netxen/Makefile
@@ -18,7 +18,7 @@
# MA 02111-1307, USA.
#
# The full GNU General Public License is included in this distribution
-# in the file called LICENSE.
+# in the file called "COPYING".
#
#
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index 9bc5bd1d538a..144d2e880422 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -19,7 +19,7 @@
* MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
*
*/
@@ -420,7 +420,7 @@ struct status_desc {
} __attribute__ ((aligned(16)));
/* UNIFIED ROMIMAGE *************************/
-#define NX_UNI_FW_MIN_SIZE 0x3eb000
+#define NX_UNI_FW_MIN_SIZE 0xc8000
#define NX_UNI_DIR_SECT_PRODUCT_TBL 0x0
#define NX_UNI_DIR_SECT_BOOTLD 0x6
#define NX_UNI_DIR_SECT_FW 0x7
@@ -1427,8 +1427,8 @@ static inline u32 netxen_tx_avail(struct nx_host_tx_ring *tx_ring)
}
-int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac);
-int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac);
+int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 *mac);
+int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, u64 *mac);
extern void netxen_change_ringparam(struct netxen_adapter *adapter);
extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr,
int *valp);
diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c
index 9cb8f6878047..2a8ef5fc9663 100644
--- a/drivers/net/netxen/netxen_nic_ctx.c
+++ b/drivers/net/netxen/netxen_nic_ctx.c
@@ -19,7 +19,7 @@
* MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
*
*/
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index 542f408333ff..f8499e56cbee 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -19,7 +19,7 @@
* MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
*
*/
diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h
index d138fc22927a..622e4c8be937 100644
--- a/drivers/net/netxen/netxen_nic_hdr.h
+++ b/drivers/net/netxen/netxen_nic_hdr.h
@@ -19,7 +19,7 @@
* MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
*
*/
@@ -969,7 +969,8 @@ enum {
#define NX_DEV_READY 3
#define NX_DEV_NEED_RESET 4
#define NX_DEV_NEED_QUISCENT 5
-#define NX_DEV_FAILED 6
+#define NX_DEV_NEED_AER 6
+#define NX_DEV_FAILED 7
#define NX_RCODE_DRIVER_INFO 0x20000000
#define NX_RCODE_DRIVER_CAN_RELOAD 0x40000000
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 85e28e60ecf1..a945591298a8 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -19,7 +19,7 @@
* MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
*
*/
@@ -539,7 +539,7 @@ void netxen_p2_nic_set_multi(struct net_device *netdev)
struct netxen_adapter *adapter = netdev_priv(netdev);
struct dev_mc_list *mc_ptr;
u8 null_addr[6];
- int index = 0;
+ int i;
memset(null_addr, 0, 6);
@@ -554,7 +554,7 @@ void netxen_p2_nic_set_multi(struct net_device *netdev)
return;
}
- if (netdev->mc_count == 0) {
+ if (netdev_mc_empty(netdev)) {
adapter->set_promisc(adapter,
NETXEN_NIU_NON_PROMISC_MODE);
netxen_nic_disable_mcast_filter(adapter);
@@ -563,23 +563,20 @@ void netxen_p2_nic_set_multi(struct net_device *netdev)
adapter->set_promisc(adapter, NETXEN_NIU_ALLMULTI_MODE);
if (netdev->flags & IFF_ALLMULTI ||
- netdev->mc_count > adapter->max_mc_count) {
+ netdev_mc_count(netdev) > adapter->max_mc_count) {
netxen_nic_disable_mcast_filter(adapter);
return;
}
netxen_nic_enable_mcast_filter(adapter);
- for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next, index++)
- netxen_nic_set_mcast_addr(adapter, index, mc_ptr->dmi_addr);
-
- if (index != netdev->mc_count)
- printk(KERN_WARNING "%s: %s multicast address count mismatch\n",
- netxen_nic_driver_name, netdev->name);
+ i = 0;
+ netdev_for_each_mc_addr(mc_ptr, netdev)
+ netxen_nic_set_mcast_addr(adapter, i++, mc_ptr->dmi_addr);
/* Clear out remaining addresses */
- for (; index < adapter->max_mc_count; index++)
- netxen_nic_set_mcast_addr(adapter, index, null_addr);
+ while (i < adapter->max_mc_count)
+ netxen_nic_set_mcast_addr(adapter, i++, null_addr);
}
static int
@@ -704,16 +701,14 @@ void netxen_p3_nic_set_multi(struct net_device *netdev)
}
if ((netdev->flags & IFF_ALLMULTI) ||
- (netdev->mc_count > adapter->max_mc_count)) {
+ (netdev_mc_count(netdev) > adapter->max_mc_count)) {
mode = VPORT_MISS_MODE_ACCEPT_MULTI;
goto send_fw_cmd;
}
- if (netdev->mc_count > 0) {
- for (mc_ptr = netdev->mc_list; mc_ptr;
- mc_ptr = mc_ptr->next) {
+ if (!netdev_mc_empty(netdev)) {
+ netdev_for_each_mc_addr(mc_ptr, netdev)
nx_p3_nic_add_mac(adapter, mc_ptr->dmi_addr, &del_list);
- }
}
send_fw_cmd:
@@ -777,17 +772,20 @@ int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr)
int netxen_config_intr_coalesce(struct netxen_adapter *adapter)
{
nx_nic_req_t req;
- u64 word;
- int rv;
+ u64 word[6];
+ int rv, i;
memset(&req, 0, sizeof(nx_nic_req_t));
+ memset(word, 0, sizeof(word));
req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23);
- word = NETXEN_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16);
- req.req_hdr = cpu_to_le64(word);
+ word[0] = NETXEN_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word[0]);
- memcpy(&req.words[0], &adapter->coal, sizeof(adapter->coal));
+ memcpy(&word[0], &adapter->coal, sizeof(adapter->coal));
+ for (i = 0; i < 6; i++)
+ req.words[i] = cpu_to_le64(word[i]);
rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
if (rv != 0) {
@@ -1033,7 +1031,7 @@ static int netxen_get_flash_block(struct netxen_adapter *adapter, int base,
return 0;
}
-int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac)
+int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 *mac)
{
__le32 *pmac = (__le32 *) mac;
u32 offset;
@@ -1058,7 +1056,7 @@ int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac)
return 0;
}
-int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac)
+int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, u64 *mac)
{
uint32_t crbaddr, mac_hi, mac_lo;
int pci_func = adapter->ahw.pci_func;
diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h
index 3fd1dcb3583a..e2c5b6f2df03 100644
--- a/drivers/net/netxen/netxen_nic_hw.h
+++ b/drivers/net/netxen/netxen_nic_hw.h
@@ -19,7 +19,7 @@
* MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
*
*/
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 64cff68d372c..1c63610ead42 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -19,7 +19,7 @@
* MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
*
*/
@@ -780,6 +780,9 @@ netxen_need_fw_reset(struct netxen_adapter *adapter)
if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
return 1;
+ if (adapter->need_fw_reset)
+ return 1;
+
/* last attempt had failed */
if (NXRD32(adapter, CRB_CMDPEG_STATE) == PHAN_INITIALIZE_FAILED)
return 1;
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 9f9d6081959b..08780ef1c1f8 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -19,7 +19,7 @@
* MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
*
*/
@@ -35,6 +35,7 @@
#include <linux/ipv6.h>
#include <linux/inetdevice.h>
#include <linux/sysfs.h>
+#include <linux/aer.h>
MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Converged Ethernet Driver");
MODULE_LICENSE("GPL");
@@ -84,6 +85,7 @@ static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter);
static void netxen_create_diag_entries(struct netxen_adapter *adapter);
static void netxen_remove_diag_entries(struct netxen_adapter *adapter);
+static int nx_dev_request_aer(struct netxen_adapter *adapter);
static int nx_decr_dev_ref_cnt(struct netxen_adapter *adapter);
static int netxen_can_start_firmware(struct netxen_adapter *adapter);
@@ -98,7 +100,7 @@ static void netxen_config_indev_addr(struct net_device *dev, unsigned long);
{PCI_DEVICE(PCI_VENDOR_ID_NETXEN, (device)), \
.class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
-static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(netxen_pci_tbl) = {
ENTRY(PCI_DEVICE_ID_NX2031_10GXSR),
ENTRY(PCI_DEVICE_ID_NX2031_10GCX4),
ENTRY(PCI_DEVICE_ID_NX2031_4GCU),
@@ -430,7 +432,7 @@ netxen_read_mac_addr(struct netxen_adapter *adapter)
{
int i;
unsigned char *p;
- __le64 mac_addr;
+ u64 mac_addr;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
@@ -1262,6 +1264,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if ((err = pci_request_regions(pdev, netxen_nic_driver_name)))
goto err_out_disable_pdev;
+ if (NX_IS_REVISION_P3(pdev->revision))
+ pci_enable_pcie_error_reporting(pdev);
+
pci_set_master(pdev);
netdev = alloc_etherdev(sizeof(struct netxen_adapter));
@@ -1409,17 +1414,19 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
netxen_release_firmware(adapter);
+ if (NX_IS_REVISION_P3(pdev->revision))
+ pci_disable_pcie_error_reporting(pdev);
+
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
free_netdev(netdev);
}
-static int __netxen_nic_shutdown(struct pci_dev *pdev)
+
+static void netxen_nic_detach_func(struct netxen_adapter *adapter)
{
- struct netxen_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev = adapter->netdev;
- int retval;
netif_device_detach(netdev);
@@ -1438,53 +1445,22 @@ static int __netxen_nic_shutdown(struct pci_dev *pdev)
nx_decr_dev_ref_cnt(adapter);
clear_bit(__NX_RESETTING, &adapter->state);
-
- retval = pci_save_state(pdev);
- if (retval)
- return retval;
-
- if (netxen_nic_wol_supported(adapter)) {
- pci_enable_wake(pdev, PCI_D3cold, 1);
- pci_enable_wake(pdev, PCI_D3hot, 1);
- }
-
- pci_disable_device(pdev);
-
- return 0;
-}
-static void netxen_nic_shutdown(struct pci_dev *pdev)
-{
- if (__netxen_nic_shutdown(pdev))
- return;
}
-#ifdef CONFIG_PM
-static int
-netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- int retval;
- retval = __netxen_nic_shutdown(pdev);
- if (retval)
- return retval;
-
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
- return 0;
-}
-
-static int
-netxen_nic_resume(struct pci_dev *pdev)
+static int netxen_nic_attach_func(struct pci_dev *pdev)
{
struct netxen_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev = adapter->netdev;
int err;
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
-
err = pci_enable_device(pdev);
if (err)
return err;
+ pci_set_power_state(pdev, PCI_D0);
+ pci_set_master(pdev);
+ pci_restore_state(pdev);
+
adapter->ahw.crb_win = -1;
adapter->ahw.ocm_win = -1;
@@ -1503,11 +1479,10 @@ netxen_nic_resume(struct pci_dev *pdev)
if (err)
goto err_out_detach;
- netif_device_attach(netdev);
-
netxen_config_indev_addr(netdev, NETDEV_UP);
}
+ netif_device_attach(netdev);
netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY);
return 0;
@@ -1517,6 +1492,85 @@ err_out:
nx_decr_dev_ref_cnt(adapter);
return err;
}
+
+static pci_ers_result_t netxen_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct netxen_adapter *adapter = pci_get_drvdata(pdev);
+
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ if (nx_dev_request_aer(adapter))
+ return PCI_ERS_RESULT_RECOVERED;
+
+ netxen_nic_detach_func(adapter);
+
+ pci_disable_device(pdev);
+
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t netxen_io_slot_reset(struct pci_dev *pdev)
+{
+ int err = 0;
+
+ err = netxen_nic_attach_func(pdev);
+
+ return err ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
+}
+
+static void netxen_io_resume(struct pci_dev *pdev)
+{
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+}
+
+static void netxen_nic_shutdown(struct pci_dev *pdev)
+{
+ struct netxen_adapter *adapter = pci_get_drvdata(pdev);
+
+ netxen_nic_detach_func(adapter);
+
+ if (pci_save_state(pdev))
+ return;
+
+ if (netxen_nic_wol_supported(adapter)) {
+ pci_enable_wake(pdev, PCI_D3cold, 1);
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ }
+
+ pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM
+static int
+netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct netxen_adapter *adapter = pci_get_drvdata(pdev);
+ int retval;
+
+ netxen_nic_detach_func(adapter);
+
+ retval = pci_save_state(pdev);
+ if (retval)
+ return retval;
+
+ if (netxen_nic_wol_supported(adapter)) {
+ pci_enable_wake(pdev, PCI_D3cold, 1);
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ }
+
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int
+netxen_nic_resume(struct pci_dev *pdev)
+{
+ return netxen_nic_attach_func(pdev);
+}
#endif
static int netxen_nic_open(struct net_device *netdev)
@@ -1941,7 +1995,7 @@ static void netxen_tx_timeout_task(struct work_struct *work)
netif_wake_queue(adapter->netdev);
clear_bit(__NX_RESETTING, &adapter->state);
-
+ return;
} else {
clear_bit(__NX_RESETTING, &adapter->state);
if (!netxen_nic_reset_context(adapter)) {
@@ -2104,20 +2158,49 @@ nx_decr_dev_ref_cnt(struct netxen_adapter *adapter)
return count;
}
-static void
+static int
+nx_dev_request_aer(struct netxen_adapter *adapter)
+{
+ u32 state;
+ int ret = -EINVAL;
+
+ if (netxen_api_lock(adapter))
+ return ret;
+
+ state = NXRD32(adapter, NX_CRB_DEV_STATE);
+
+ if (state == NX_DEV_NEED_AER)
+ ret = 0;
+ else if (state == NX_DEV_READY) {
+ NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_AER);
+ ret = 0;
+ }
+
+ netxen_api_unlock(adapter);
+ return ret;
+}
+
+static int
nx_dev_request_reset(struct netxen_adapter *adapter)
{
u32 state;
+ int ret = -EINVAL;
if (netxen_api_lock(adapter))
- return;
+ return ret;
state = NXRD32(adapter, NX_CRB_DEV_STATE);
- if (state != NX_DEV_INITALIZING)
+ if (state == NX_DEV_NEED_RESET)
+ ret = 0;
+ else if (state != NX_DEV_INITALIZING && state != NX_DEV_NEED_AER) {
NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_RESET);
+ ret = 0;
+ }
netxen_api_unlock(adapter);
+
+ return ret;
}
static int
@@ -2240,7 +2323,9 @@ netxen_detach_work(struct work_struct *work)
netxen_nic_down(adapter, netdev);
+ rtnl_lock();
netxen_nic_detach(adapter);
+ rtnl_unlock();
status = NXRD32(adapter, NETXEN_PEG_HALT_STATUS1);
@@ -2269,17 +2354,29 @@ netxen_check_health(struct netxen_adapter *adapter)
u32 state, heartbit;
struct net_device *netdev = adapter->netdev;
+ state = NXRD32(adapter, NX_CRB_DEV_STATE);
+ if (state == NX_DEV_NEED_AER)
+ return 0;
+
if (netxen_nic_check_temp(adapter))
goto detach;
if (adapter->need_fw_reset) {
- nx_dev_request_reset(adapter);
+ if (nx_dev_request_reset(adapter))
+ return 0;
goto detach;
}
- state = NXRD32(adapter, NX_CRB_DEV_STATE);
- if (state == NX_DEV_NEED_RESET)
- goto detach;
+ /* NX_DEV_NEED_RESET, this state can be marked in two cases
+ * 1. Tx timeout 2. Fw hang
+ * Send request to destroy context in case of tx timeout only
+ * and doesn't required in case of Fw hang
+ */
+ if (state == NX_DEV_NEED_RESET) {
+ adapter->need_fw_reset = 1;
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ goto detach;
+ }
if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
return 0;
@@ -2288,12 +2385,17 @@ netxen_check_health(struct netxen_adapter *adapter)
if (heartbit != adapter->heartbit) {
adapter->heartbit = heartbit;
adapter->fw_fail_cnt = 0;
+ if (adapter->need_fw_reset)
+ goto detach;
return 0;
}
if (++adapter->fw_fail_cnt < FW_FAIL_THRESH)
return 0;
+ if (nx_dev_request_reset(adapter))
+ return 0;
+
clear_bit(__NX_FW_ATTACHED, &adapter->state);
dev_info(&netdev->dev, "firmware hang detected\n");
@@ -2496,7 +2598,7 @@ netxen_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr,
return size;
}
-ssize_t netxen_sysfs_write_mem(struct kobject *kobj,
+static ssize_t netxen_sysfs_write_mem(struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t offset, size_t size)
{
@@ -2723,6 +2825,12 @@ netxen_config_indev_addr(struct net_device *dev, unsigned long event)
{ }
#endif
+static struct pci_error_handlers netxen_err_handler = {
+ .error_detected = netxen_io_error_detected,
+ .slot_reset = netxen_io_slot_reset,
+ .resume = netxen_io_resume,
+};
+
static struct pci_driver netxen_driver = {
.name = netxen_nic_driver_name,
.id_table = netxen_pci_tbl,
@@ -2732,7 +2840,8 @@ static struct pci_driver netxen_driver = {
.suspend = netxen_nic_suspend,
.resume = netxen_nic_resume,
#endif
- .shutdown = netxen_nic_shutdown
+ .shutdown = netxen_nic_shutdown,
+ .err_handler = &netxen_err_handler
};
static int __init netxen_init_module(void)
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index 6a87d810e59d..c16cbfb4061b 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -651,7 +651,8 @@ static void ni5010_set_multicast_list(struct net_device *dev)
PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name));
- if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI || dev->mc_list) {
+ if (dev->flags & IFF_PROMISC || dev->flags & IFF_ALLMULTI ||
+ !netdev_mc_empty(dev)) {
outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */
PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name));
} else {
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index b42f5e522f90..05c29c2cef2a 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -596,8 +596,8 @@ static int init586(struct net_device *dev)
struct iasetup_cmd_struct __iomem *ias_cmd;
struct tdr_cmd_struct __iomem *tdr_cmd;
struct mcsetup_cmd_struct __iomem *mc_cmd;
- struct dev_mc_list *dmi = dev->mc_list;
- int num_addrs = dev->mc_count;
+ struct dev_mc_list *dmi;
+ int num_addrs = netdev_mc_count(dev);
ptr = p->scb + 1;
@@ -724,9 +724,9 @@ static int init586(struct net_device *dev)
writew(0xffff, &mc_cmd->cmd_link);
writew(num_addrs * 6, &mc_cmd->mc_cnt);
- for (i = 0; i < num_addrs; i++, dmi = dmi->next)
- memcpy_toio(mc_cmd->mc_list[i],
- dmi->dmi_addr, 6);
+ i = 0;
+ netdev_for_each_mc_addr(dmi, dev)
+ memcpy_toio(mc_cmd->mc_list[i++], dmi->dmi_addr, 6);
writew(make16(mc_cmd), &p->scb->cbl_offset);
writeb(CUC_START, &p->scb->cmd_cuc);
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index ae19aafd2c7e..9225c76cac40 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -849,7 +849,7 @@ static int ni65_lance_reinit(struct net_device *dev)
if(dev->flags & IFF_PROMISC)
ni65_init_lance(p,dev->dev_addr,0x00,M_PROM);
- else if(dev->mc_count || dev->flags & IFF_ALLMULTI)
+ else if (netdev_mc_count(dev) || dev->flags & IFF_ALLMULTI)
ni65_init_lance(p,dev->dev_addr,0xff,0x0);
else
ni65_init_lance(p,dev->dev_addr,0x00,0x00);
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 2aed2b382c40..0678f3106cbc 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -3,6 +3,8 @@
* Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net)
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -33,7 +35,6 @@
#include "niu.h"
#define DRV_MODULE_NAME "niu"
-#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "1.0"
#define DRV_MODULE_RELDATE "Nov 14, 2008"
@@ -58,7 +59,7 @@ static void writeq(u64 val, void __iomem *reg)
}
#endif
-static struct pci_device_id niu_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(niu_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_SUN, 0xabcd)},
{}
};
@@ -89,21 +90,6 @@ static int debug = -1;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "NIU debug level");
-#define niudbg(TYPE, f, a...) \
-do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \
- printk(KERN_DEBUG PFX f, ## a); \
-} while (0)
-
-#define niuinfo(TYPE, f, a...) \
-do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \
- printk(KERN_INFO PFX f, ## a); \
-} while (0)
-
-#define niuwarn(TYPE, f, a...) \
-do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \
- printk(KERN_WARNING PFX f, ## a); \
-} while (0)
-
#define niu_lock_parent(np, flags) \
spin_lock_irqsave(&np->parent->lock, flags)
#define niu_unlock_parent(np, flags) \
@@ -135,10 +121,9 @@ static int __niu_set_and_wait_clear_mac(struct niu *np, unsigned long reg,
nw64_mac(reg, bits);
err = __niu_wait_bits_clear_mac(np, reg, bits, limit, delay);
if (err)
- dev_err(np->device, PFX "%s: bits (%llx) of register %s "
- "would not clear, val[%llx]\n",
- np->dev->name, (unsigned long long) bits, reg_name,
- (unsigned long long) nr64_mac(reg));
+ netdev_err(np->dev, "bits (%llx) of register %s would not clear, val[%llx]\n",
+ (unsigned long long)bits, reg_name,
+ (unsigned long long)nr64_mac(reg));
return err;
}
@@ -175,10 +160,9 @@ static int __niu_set_and_wait_clear_ipp(struct niu *np, unsigned long reg,
err = __niu_wait_bits_clear_ipp(np, reg, bits, limit, delay);
if (err)
- dev_err(np->device, PFX "%s: bits (%llx) of register %s "
- "would not clear, val[%llx]\n",
- np->dev->name, (unsigned long long) bits, reg_name,
- (unsigned long long) nr64_ipp(reg));
+ netdev_err(np->dev, "bits (%llx) of register %s would not clear, val[%llx]\n",
+ (unsigned long long)bits, reg_name,
+ (unsigned long long)nr64_ipp(reg));
return err;
}
@@ -216,10 +200,9 @@ static int __niu_set_and_wait_clear(struct niu *np, unsigned long reg,
nw64(reg, bits);
err = __niu_wait_bits_clear(np, reg, bits, limit, delay);
if (err)
- dev_err(np->device, PFX "%s: bits (%llx) of register %s "
- "would not clear, val[%llx]\n",
- np->dev->name, (unsigned long long) bits, reg_name,
- (unsigned long long) nr64(reg));
+ netdev_err(np->dev, "bits (%llx) of register %s would not clear, val[%llx]\n",
+ (unsigned long long)bits, reg_name,
+ (unsigned long long)nr64(reg));
return err;
}
@@ -475,9 +458,8 @@ static int serdes_init_niu_1g_serdes(struct niu *np)
err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
ESR2_TI_PLL_CFG_L, pll_cfg);
if (err) {
- dev_err(np->device, PFX "NIU Port %d "
- "serdes_init_niu_1g_serdes: "
- "mdio write to ESR2_TI_PLL_CFG_L failed", np->port);
+ netdev_err(np->dev, "NIU Port %d %s() mdio write to ESR2_TI_PLL_CFG_L failed\n",
+ np->port, __func__);
return err;
}
@@ -486,9 +468,8 @@ static int serdes_init_niu_1g_serdes(struct niu *np)
err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
ESR2_TI_PLL_STS_L, pll_sts);
if (err) {
- dev_err(np->device, PFX "NIU Port %d "
- "serdes_init_niu_1g_serdes: "
- "mdio write to ESR2_TI_PLL_STS_L failed", np->port);
+ netdev_err(np->dev, "NIU Port %d %s() mdio write to ESR2_TI_PLL_STS_L failed\n",
+ np->port, __func__);
return err;
}
@@ -531,8 +512,8 @@ static int serdes_init_niu_1g_serdes(struct niu *np)
}
if ((sig & mask) != val) {
- dev_err(np->device, PFX "Port %u signal bits [%08x] are not "
- "[%08x]\n", np->port, (int) (sig & mask), (int) val);
+ netdev_err(np->dev, "Port %u signal bits [%08x] are not [%08x]\n",
+ np->port, (int)(sig & mask), (int)val);
return -ENODEV;
}
@@ -569,9 +550,8 @@ static int serdes_init_niu_10g_serdes(struct niu *np)
err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
ESR2_TI_PLL_CFG_L, pll_cfg & 0xffff);
if (err) {
- dev_err(np->device, PFX "NIU Port %d "
- "serdes_init_niu_10g_serdes: "
- "mdio write to ESR2_TI_PLL_CFG_L failed", np->port);
+ netdev_err(np->dev, "NIU Port %d %s() mdio write to ESR2_TI_PLL_CFG_L failed\n",
+ np->port, __func__);
return err;
}
@@ -580,9 +560,8 @@ static int serdes_init_niu_10g_serdes(struct niu *np)
err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
ESR2_TI_PLL_STS_L, pll_sts & 0xffff);
if (err) {
- dev_err(np->device, PFX "NIU Port %d "
- "serdes_init_niu_10g_serdes: "
- "mdio write to ESR2_TI_PLL_STS_L failed", np->port);
+ netdev_err(np->dev, "NIU Port %d %s() mdio write to ESR2_TI_PLL_STS_L failed\n",
+ np->port, __func__);
return err;
}
@@ -639,9 +618,8 @@ static int serdes_init_niu_10g_serdes(struct niu *np)
}
if ((sig & mask) != val) {
- pr_info(PFX "NIU Port %u signal bits [%08x] are not "
- "[%08x] for 10G...trying 1G\n",
- np->port, (int) (sig & mask), (int) val);
+ pr_info("NIU Port %u signal bits [%08x] are not [%08x] for 10G...trying 1G\n",
+ np->port, (int)(sig & mask), (int)val);
/* 10G failed, try initializing at 1G */
err = serdes_init_niu_1g_serdes(np);
@@ -649,8 +627,8 @@ static int serdes_init_niu_10g_serdes(struct niu *np)
np->flags &= ~NIU_FLAGS_10G;
np->mac_xcvr = MAC_XCVR_PCS;
} else {
- dev_err(np->device, PFX "Port %u 10G/1G SERDES "
- "Link Failed \n", np->port);
+ netdev_err(np->dev, "Port %u 10G/1G SERDES Link Failed\n",
+ np->port);
return -ENODEV;
}
}
@@ -764,9 +742,8 @@ static int esr_reset(struct niu *np)
if (err)
return err;
if (reset != 0) {
- dev_err(np->device, PFX "Port %u ESR_RESET "
- "did not clear [%08x]\n",
- np->port, reset);
+ netdev_err(np->dev, "Port %u ESR_RESET did not clear [%08x]\n",
+ np->port, reset);
return -ENODEV;
}
@@ -890,8 +867,8 @@ static int serdes_init_10g(struct niu *np)
np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT;
return 0;
}
- dev_err(np->device, PFX "Port %u signal bits [%08x] are not "
- "[%08x]\n", np->port, (int) (sig & mask), (int) val);
+ netdev_err(np->dev, "Port %u signal bits [%08x] are not [%08x]\n",
+ np->port, (int)(sig & mask), (int)val);
return -ENODEV;
}
if (np->flags & NIU_FLAGS_HOTPLUG_PHY)
@@ -1039,8 +1016,8 @@ static int serdes_init_1g_serdes(struct niu *np)
}
if ((sig & mask) != val) {
- dev_err(np->device, PFX "Port %u signal bits [%08x] are not "
- "[%08x]\n", np->port, (int) (sig & mask), (int) val);
+ netdev_err(np->dev, "Port %u signal bits [%08x] are not [%08x]\n",
+ np->port, (int)(sig & mask), (int)val);
return -ENODEV;
}
@@ -1332,8 +1309,8 @@ static int bcm8704_reset(struct niu *np)
break;
}
if (limit < 0) {
- dev_err(np->device, PFX "Port %u PHY will not reset "
- "(bmcr=%04x)\n", np->port, (err & 0xffff));
+ netdev_err(np->dev, "Port %u PHY will not reset (bmcr=%04x)\n",
+ np->port, (err & 0xffff));
return -ENODEV;
}
return 0;
@@ -1515,21 +1492,18 @@ static int xcvr_diag_bcm870x(struct niu *np)
MII_STAT1000);
if (err < 0)
return err;
- pr_info(PFX "Port %u PMA_PMD(MII_STAT1000) [%04x]\n",
- np->port, err);
+ pr_info("Port %u PMA_PMD(MII_STAT1000) [%04x]\n", np->port, err);
err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, 0x20);
if (err < 0)
return err;
- pr_info(PFX "Port %u USER_DEV3(0x20) [%04x]\n",
- np->port, err);
+ pr_info("Port %u USER_DEV3(0x20) [%04x]\n", np->port, err);
err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
MII_NWAYTEST);
if (err < 0)
return err;
- pr_info(PFX "Port %u PHYXS(MII_NWAYTEST) [%04x]\n",
- np->port, err);
+ pr_info("Port %u PHYXS(MII_NWAYTEST) [%04x]\n", np->port, err);
#endif
/* XXX dig this out it might not be so useful XXX */
@@ -1555,11 +1529,11 @@ static int xcvr_diag_bcm870x(struct niu *np)
if (analog_stat0 != 0x03fc) {
if ((analog_stat0 == 0x43bc) && (tx_alarm_status != 0)) {
- pr_info(PFX "Port %u cable not connected "
- "or bad cable.\n", np->port);
+ pr_info("Port %u cable not connected or bad cable\n",
+ np->port);
} else if (analog_stat0 == 0x639c) {
- pr_info(PFX "Port %u optical module is bad "
- "or missing.\n", np->port);
+ pr_info("Port %u optical module is bad or missing\n",
+ np->port);
}
}
@@ -1699,8 +1673,8 @@ static int mii_reset(struct niu *np)
break;
}
if (limit < 0) {
- dev_err(np->device, PFX "Port %u MII would not reset, "
- "bmcr[%04x]\n", np->port, err);
+ netdev_err(np->dev, "Port %u MII would not reset, bmcr[%04x]\n",
+ np->port, err);
return -ENODEV;
}
@@ -1895,7 +1869,7 @@ static int mii_init_common(struct niu *np)
return err;
bmsr = err;
- pr_info(PFX "Port %u after MII init bmcr[%04x] bmsr[%04x]\n",
+ pr_info("Port %u after MII init bmcr[%04x] bmsr[%04x]\n",
np->port, bmcr, bmsr);
#endif
@@ -1948,16 +1922,12 @@ static int niu_link_status_common(struct niu *np, int link_up)
unsigned long flags;
if (!netif_carrier_ok(dev) && link_up) {
- niuinfo(LINK, "%s: Link is up at %s, %s duplex\n",
- dev->name,
- (lp->active_speed == SPEED_10000 ?
- "10Gb/sec" :
- (lp->active_speed == SPEED_1000 ?
- "1Gb/sec" :
- (lp->active_speed == SPEED_100 ?
- "100Mbit/sec" : "10Mbit/sec"))),
- (lp->active_duplex == DUPLEX_FULL ?
- "full" : "half"));
+ netif_info(np, link, dev, "Link is up at %s, %s duplex\n",
+ lp->active_speed == SPEED_10000 ? "10Gb/sec" :
+ lp->active_speed == SPEED_1000 ? "1Gb/sec" :
+ lp->active_speed == SPEED_100 ? "100Mbit/sec" :
+ "10Mbit/sec",
+ lp->active_duplex == DUPLEX_FULL ? "full" : "half");
spin_lock_irqsave(&np->lock, flags);
niu_init_xif(np);
@@ -1966,7 +1936,7 @@ static int niu_link_status_common(struct niu *np, int link_up)
netif_carrier_on(dev);
} else if (netif_carrier_ok(dev) && !link_up) {
- niuwarn(LINK, "%s: Link is down\n", dev->name);
+ netif_warn(np, link, dev, "Link is down\n");
spin_lock_irqsave(&np->lock, flags);
niu_handle_led(np, 0);
spin_unlock_irqrestore(&np->lock, flags);
@@ -2232,8 +2202,8 @@ static int link_status_10g_hotplug(struct niu *np, int *link_up_p)
} else {
np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT;
*link_up_p = 0;
- niuwarn(LINK, "%s: Hotplug PHY Removed\n",
- np->dev->name);
+ netif_warn(np, link, np->dev,
+ "Hotplug PHY Removed\n");
}
}
out:
@@ -2531,8 +2501,8 @@ static int serdes_init_10g_serdes(struct niu *np)
np->flags &= ~NIU_FLAGS_10G;
np->mac_xcvr = MAC_XCVR_PCS;
} else {
- dev_err(np->device, PFX "Port %u 10G/1G SERDES Link Failed \n",
- np->port);
+ netdev_err(np->dev, "Port %u 10G/1G SERDES Link Failed\n",
+ np->port);
return -ENODEV;
}
}
@@ -3234,23 +3204,22 @@ static int fflp_early_init(struct niu *np)
parent = np->parent;
err = 0;
if (!(parent->flags & PARENT_FLGS_CLS_HWINIT)) {
- niudbg(PROBE, "fflp_early_init: Initting hw on port %u\n",
- np->port);
if (np->parent->plat_type != PLAT_TYPE_NIU) {
fflp_reset(np);
fflp_set_timings(np);
err = fflp_disable_all_partitions(np);
if (err) {
- niudbg(PROBE, "fflp_disable_all_partitions "
- "failed, err=%d\n", err);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "fflp_disable_all_partitions failed, err=%d\n",
+ err);
goto out;
}
}
err = tcam_early_init(np);
if (err) {
- niudbg(PROBE, "tcam_early_init failed, err=%d\n",
- err);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "tcam_early_init failed, err=%d\n", err);
goto out;
}
fflp_llcsnap_enable(np, 1);
@@ -3260,22 +3229,22 @@ static int fflp_early_init(struct niu *np)
err = tcam_flush_all(np);
if (err) {
- niudbg(PROBE, "tcam_flush_all failed, err=%d\n",
- err);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "tcam_flush_all failed, err=%d\n", err);
goto out;
}
if (np->parent->plat_type != PLAT_TYPE_NIU) {
err = fflp_hash_clear(np);
if (err) {
- niudbg(PROBE, "fflp_hash_clear failed, "
- "err=%d\n", err);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "fflp_hash_clear failed, err=%d\n",
+ err);
goto out;
}
}
vlan_tbl_clear(np);
- niudbg(PROBE, "fflp_early_init: Success\n");
parent->flags |= PARENT_FLGS_CLS_HWINIT;
}
out:
@@ -3665,8 +3634,8 @@ static void niu_tx_work(struct niu *np, struct tx_ring_info *rp)
cons = rp->cons;
- niudbg(TX_DONE, "%s: niu_tx_work() pkt_cnt[%u] cons[%d]\n",
- np->dev->name, pkt_cnt, cons);
+ netif_printk(np, tx_done, KERN_DEBUG, np->dev,
+ "%s() pkt_cnt[%u] cons[%d]\n", __func__, pkt_cnt, cons);
while (pkt_cnt--)
cons = release_tx_packet(np, rp, cons);
@@ -3714,11 +3683,12 @@ static inline void niu_sync_rx_discard_stats(struct niu *np,
rp->rx_errors += misc & RXMISC_COUNT;
if (unlikely(misc & RXMISC_OFLOW))
- dev_err(np->device, "rx-%d: Counter overflow "
- "RXMISC discard\n", rx_channel);
+ dev_err(np->device, "rx-%d: Counter overflow RXMISC discard\n",
+ rx_channel);
- niudbg(RX_ERR, "%s-rx-%d: MISC drop=%u over=%u\n",
- np->dev->name, rx_channel, misc, misc-limit);
+ netif_printk(np, rx_err, KERN_DEBUG, np->dev,
+ "rx-%d: MISC drop=%u over=%u\n",
+ rx_channel, misc, misc-limit);
}
/* WRED (Weighted Random Early Discard) by hardware */
@@ -3728,11 +3698,11 @@ static inline void niu_sync_rx_discard_stats(struct niu *np,
rp->rx_dropped += wred & RED_DIS_CNT_COUNT;
if (unlikely(wred & RED_DIS_CNT_OFLOW))
- dev_err(np->device, "rx-%d: Counter overflow "
- "WRED discard\n", rx_channel);
+ dev_err(np->device, "rx-%d: Counter overflow WRED discard\n", rx_channel);
- niudbg(RX_ERR, "%s-rx-%d: WRED drop=%u over=%u\n",
- np->dev->name, rx_channel, wred, wred-limit);
+ netif_printk(np, rx_err, KERN_DEBUG, np->dev,
+ "rx-%d: WRED drop=%u over=%u\n",
+ rx_channel, wred, wred-limit);
}
}
@@ -3753,8 +3723,9 @@ static int niu_rx_work(struct napi_struct *napi, struct niu *np,
mbox->rx_dma_ctl_stat = 0;
mbox->rcrstat_a = 0;
- niudbg(RX_STATUS, "%s: niu_rx_work(chan[%d]), stat[%llx] qlen=%d\n",
- np->dev->name, rp->rx_channel, (unsigned long long) stat, qlen);
+ netif_printk(np, rx_status, KERN_DEBUG, np->dev,
+ "%s(chan[%d]), stat[%llx] qlen=%d\n",
+ __func__, rp->rx_channel, (unsigned long long)stat, qlen);
rcr_done = work_done = 0;
qlen = min(qlen, budget);
@@ -3791,8 +3762,8 @@ static int niu_poll_core(struct niu *np, struct niu_ldg *lp, int budget)
u32 rx_vec = (v0 & 0xffffffff);
int i, work_done = 0;
- niudbg(INTR, "%s: niu_poll_core() v0[%016llx]\n",
- np->dev->name, (unsigned long long) v0);
+ netif_printk(np, intr, KERN_DEBUG, np->dev,
+ "%s() v0[%016llx]\n", __func__, (unsigned long long)v0);
for (i = 0; i < np->num_tx_rings; i++) {
struct tx_ring_info *rp = &np->tx_rings[i];
@@ -3837,39 +3808,38 @@ static int niu_poll(struct napi_struct *napi, int budget)
static void niu_log_rxchan_errors(struct niu *np, struct rx_ring_info *rp,
u64 stat)
{
- dev_err(np->device, PFX "%s: RX channel %u errors ( ",
- np->dev->name, rp->rx_channel);
+ netdev_err(np->dev, "RX channel %u errors ( ", rp->rx_channel);
if (stat & RX_DMA_CTL_STAT_RBR_TMOUT)
- printk("RBR_TMOUT ");
+ pr_cont("RBR_TMOUT ");
if (stat & RX_DMA_CTL_STAT_RSP_CNT_ERR)
- printk("RSP_CNT ");
+ pr_cont("RSP_CNT ");
if (stat & RX_DMA_CTL_STAT_BYTE_EN_BUS)
- printk("BYTE_EN_BUS ");
+ pr_cont("BYTE_EN_BUS ");
if (stat & RX_DMA_CTL_STAT_RSP_DAT_ERR)
- printk("RSP_DAT ");
+ pr_cont("RSP_DAT ");
if (stat & RX_DMA_CTL_STAT_RCR_ACK_ERR)
- printk("RCR_ACK ");
+ pr_cont("RCR_ACK ");
if (stat & RX_DMA_CTL_STAT_RCR_SHA_PAR)
- printk("RCR_SHA_PAR ");
+ pr_cont("RCR_SHA_PAR ");
if (stat & RX_DMA_CTL_STAT_RBR_PRE_PAR)
- printk("RBR_PRE_PAR ");
+ pr_cont("RBR_PRE_PAR ");
if (stat & RX_DMA_CTL_STAT_CONFIG_ERR)
- printk("CONFIG ");
+ pr_cont("CONFIG ");
if (stat & RX_DMA_CTL_STAT_RCRINCON)
- printk("RCRINCON ");
+ pr_cont("RCRINCON ");
if (stat & RX_DMA_CTL_STAT_RCRFULL)
- printk("RCRFULL ");
+ pr_cont("RCRFULL ");
if (stat & RX_DMA_CTL_STAT_RBRFULL)
- printk("RBRFULL ");
+ pr_cont("RBRFULL ");
if (stat & RX_DMA_CTL_STAT_RBRLOGPAGE)
- printk("RBRLOGPAGE ");
+ pr_cont("RBRLOGPAGE ");
if (stat & RX_DMA_CTL_STAT_CFIGLOGPAGE)
- printk("CFIGLOGPAGE ");
+ pr_cont("CFIGLOGPAGE ");
if (stat & RX_DMA_CTL_STAT_DC_FIFO_ERR)
- printk("DC_FIDO ");
+ pr_cont("DC_FIDO ");
- printk(")\n");
+ pr_cont(")\n");
}
static int niu_rx_error(struct niu *np, struct rx_ring_info *rp)
@@ -3883,9 +3853,9 @@ static int niu_rx_error(struct niu *np, struct rx_ring_info *rp)
err = -EINVAL;
if (err) {
- dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n",
- np->dev->name, rp->rx_channel,
- (unsigned long long) stat);
+ netdev_err(np->dev, "RX channel %u error, stat[%llx]\n",
+ rp->rx_channel,
+ (unsigned long long) stat);
niu_log_rxchan_errors(np, rp, stat);
}
@@ -3899,27 +3869,26 @@ static int niu_rx_error(struct niu *np, struct rx_ring_info *rp)
static void niu_log_txchan_errors(struct niu *np, struct tx_ring_info *rp,
u64 cs)
{
- dev_err(np->device, PFX "%s: TX channel %u errors ( ",
- np->dev->name, rp->tx_channel);
+ netdev_err(np->dev, "TX channel %u errors ( ", rp->tx_channel);
if (cs & TX_CS_MBOX_ERR)
- printk("MBOX ");
+ pr_cont("MBOX ");
if (cs & TX_CS_PKT_SIZE_ERR)
- printk("PKT_SIZE ");
+ pr_cont("PKT_SIZE ");
if (cs & TX_CS_TX_RING_OFLOW)
- printk("TX_RING_OFLOW ");
+ pr_cont("TX_RING_OFLOW ");
if (cs & TX_CS_PREF_BUF_PAR_ERR)
- printk("PREF_BUF_PAR ");
+ pr_cont("PREF_BUF_PAR ");
if (cs & TX_CS_NACK_PREF)
- printk("NACK_PREF ");
+ pr_cont("NACK_PREF ");
if (cs & TX_CS_NACK_PKT_RD)
- printk("NACK_PKT_RD ");
+ pr_cont("NACK_PKT_RD ");
if (cs & TX_CS_CONF_PART_ERR)
- printk("CONF_PART ");
+ pr_cont("CONF_PART ");
if (cs & TX_CS_PKT_PRT_ERR)
- printk("PKT_PTR ");
+ pr_cont("PKT_PTR ");
- printk(")\n");
+ pr_cont(")\n");
}
static int niu_tx_error(struct niu *np, struct tx_ring_info *rp)
@@ -3930,12 +3899,11 @@ static int niu_tx_error(struct niu *np, struct tx_ring_info *rp)
logh = nr64(TX_RNG_ERR_LOGH(rp->tx_channel));
logl = nr64(TX_RNG_ERR_LOGL(rp->tx_channel));
- dev_err(np->device, PFX "%s: TX channel %u error, "
- "cs[%llx] logh[%llx] logl[%llx]\n",
- np->dev->name, rp->tx_channel,
- (unsigned long long) cs,
- (unsigned long long) logh,
- (unsigned long long) logl);
+ netdev_err(np->dev, "TX channel %u error, cs[%llx] logh[%llx] logl[%llx]\n",
+ rp->tx_channel,
+ (unsigned long long)cs,
+ (unsigned long long)logh,
+ (unsigned long long)logl);
niu_log_txchan_errors(np, rp, cs);
@@ -3954,9 +3922,8 @@ static int niu_mif_interrupt(struct niu *np)
phy_mdint = 1;
}
- dev_err(np->device, PFX "%s: MIF interrupt, "
- "stat[%llx] phy_mdint(%d)\n",
- np->dev->name, (unsigned long long) mif_status, phy_mdint);
+ netdev_err(np->dev, "MIF interrupt, stat[%llx] phy_mdint(%d)\n",
+ (unsigned long long)mif_status, phy_mdint);
return -ENODEV;
}
@@ -4081,41 +4048,40 @@ static int niu_mac_interrupt(struct niu *np)
static void niu_log_device_error(struct niu *np, u64 stat)
{
- dev_err(np->device, PFX "%s: Core device errors ( ",
- np->dev->name);
+ netdev_err(np->dev, "Core device errors ( ");
if (stat & SYS_ERR_MASK_META2)
- printk("META2 ");
+ pr_cont("META2 ");
if (stat & SYS_ERR_MASK_META1)
- printk("META1 ");
+ pr_cont("META1 ");
if (stat & SYS_ERR_MASK_PEU)
- printk("PEU ");
+ pr_cont("PEU ");
if (stat & SYS_ERR_MASK_TXC)
- printk("TXC ");
+ pr_cont("TXC ");
if (stat & SYS_ERR_MASK_RDMC)
- printk("RDMC ");
+ pr_cont("RDMC ");
if (stat & SYS_ERR_MASK_TDMC)
- printk("TDMC ");
+ pr_cont("TDMC ");
if (stat & SYS_ERR_MASK_ZCP)
- printk("ZCP ");
+ pr_cont("ZCP ");
if (stat & SYS_ERR_MASK_FFLP)
- printk("FFLP ");
+ pr_cont("FFLP ");
if (stat & SYS_ERR_MASK_IPP)
- printk("IPP ");
+ pr_cont("IPP ");
if (stat & SYS_ERR_MASK_MAC)
- printk("MAC ");
+ pr_cont("MAC ");
if (stat & SYS_ERR_MASK_SMX)
- printk("SMX ");
+ pr_cont("SMX ");
- printk(")\n");
+ pr_cont(")\n");
}
static int niu_device_error(struct niu *np)
{
u64 stat = nr64(SYS_ERR_STAT);
- dev_err(np->device, PFX "%s: Core device error, stat[%llx]\n",
- np->dev->name, (unsigned long long) stat);
+ netdev_err(np->dev, "Core device error, stat[%llx]\n",
+ (unsigned long long)stat);
niu_log_device_error(np, stat);
@@ -4197,8 +4163,8 @@ static void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp,
RX_DMA_CTL_STAT_RCRTO);
nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat_write);
- niudbg(INTR, "%s: rxchan_intr stat[%llx]\n",
- np->dev->name, (unsigned long long) stat);
+ netif_printk(np, intr, KERN_DEBUG, np->dev,
+ "%s() stat[%llx]\n", __func__, (unsigned long long)stat);
}
static void niu_txchan_intr(struct niu *np, struct tx_ring_info *rp,
@@ -4206,8 +4172,8 @@ static void niu_txchan_intr(struct niu *np, struct tx_ring_info *rp,
{
rp->tx_cs = nr64(TX_CS(rp->tx_channel));
- niudbg(INTR, "%s: txchan_intr cs[%llx]\n",
- np->dev->name, (unsigned long long) rp->tx_cs);
+ netif_printk(np, intr, KERN_DEBUG, np->dev,
+ "%s() cs[%llx]\n", __func__, (unsigned long long)rp->tx_cs);
}
static void __niu_fastpath_interrupt(struct niu *np, int ldg, u64 v0)
@@ -4265,8 +4231,8 @@ static irqreturn_t niu_interrupt(int irq, void *dev_id)
u64 v0, v1, v2;
if (netif_msg_intr(np))
- printk(KERN_DEBUG PFX "niu_interrupt() ldg[%p](%d) ",
- lp, ldg);
+ printk(KERN_DEBUG KBUILD_MODNAME ": " "%s() ldg[%p](%d)",
+ __func__, lp, ldg);
spin_lock_irqsave(&np->lock, flags);
@@ -4275,7 +4241,7 @@ static irqreturn_t niu_interrupt(int irq, void *dev_id)
v2 = nr64(LDSV2(ldg));
if (netif_msg_intr(np))
- printk("v0[%llx] v1[%llx] v2[%llx]\n",
+ pr_cont(" v0[%llx] v1[%llx] v2[%llx]\n",
(unsigned long long) v0,
(unsigned long long) v1,
(unsigned long long) v2);
@@ -4400,8 +4366,8 @@ static int niu_alloc_rx_ring_info(struct niu *np,
if (!rp->mbox)
return -ENOMEM;
if ((unsigned long)rp->mbox & (64UL - 1)) {
- dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
- "RXDMA mailbox %p\n", np->dev->name, rp->mbox);
+ netdev_err(np->dev, "Coherent alloc gives misaligned RXDMA mailbox %p\n",
+ rp->mbox);
return -EINVAL;
}
@@ -4411,8 +4377,8 @@ static int niu_alloc_rx_ring_info(struct niu *np,
if (!rp->rcr)
return -ENOMEM;
if ((unsigned long)rp->rcr & (64UL - 1)) {
- dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
- "RXDMA RCR table %p\n", np->dev->name, rp->rcr);
+ netdev_err(np->dev, "Coherent alloc gives misaligned RXDMA RCR table %p\n",
+ rp->rcr);
return -EINVAL;
}
rp->rcr_table_size = MAX_RCR_RING_SIZE;
@@ -4424,8 +4390,8 @@ static int niu_alloc_rx_ring_info(struct niu *np,
if (!rp->rbr)
return -ENOMEM;
if ((unsigned long)rp->rbr & (64UL - 1)) {
- dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
- "RXDMA RBR table %p\n", np->dev->name, rp->rbr);
+ netdev_err(np->dev, "Coherent alloc gives misaligned RXDMA RBR table %p\n",
+ rp->rbr);
return -EINVAL;
}
rp->rbr_table_size = MAX_RBR_RING_SIZE;
@@ -4458,8 +4424,8 @@ static int niu_alloc_tx_ring_info(struct niu *np,
if (!rp->mbox)
return -ENOMEM;
if ((unsigned long)rp->mbox & (64UL - 1)) {
- dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
- "TXDMA mailbox %p\n", np->dev->name, rp->mbox);
+ netdev_err(np->dev, "Coherent alloc gives misaligned TXDMA mailbox %p\n",
+ rp->mbox);
return -EINVAL;
}
@@ -4469,8 +4435,8 @@ static int niu_alloc_tx_ring_info(struct niu *np,
if (!rp->descr)
return -ENOMEM;
if ((unsigned long)rp->descr & (64UL - 1)) {
- dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
- "TXDMA descr table %p\n", np->dev->name, rp->descr);
+ netdev_err(np->dev, "Coherent alloc gives misaligned TXDMA descr table %p\n",
+ rp->descr);
return -EINVAL;
}
@@ -4726,10 +4692,8 @@ static int niu_init_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
if (rp->descr_dma & ~(TX_RNG_CFIG_STADDR_BASE |
TX_RNG_CFIG_STADDR)) {
- dev_err(np->device, PFX "%s: TX ring channel %d "
- "DMA addr (%llx) is not aligned.\n",
- np->dev->name, channel,
- (unsigned long long) rp->descr_dma);
+ netdev_err(np->dev, "TX ring channel %d DMA addr (%llx) is not aligned\n",
+ channel, (unsigned long long)rp->descr_dma);
return -EINVAL;
}
@@ -4746,10 +4710,8 @@ static int niu_init_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
if (((rp->mbox_dma >> 32) & ~TXDMA_MBH_MBADDR) ||
((u32)rp->mbox_dma & ~TXDMA_MBL_MBADDR)) {
- dev_err(np->device, PFX "%s: TX ring channel %d "
- "MBOX addr (%llx) is has illegal bits.\n",
- np->dev->name, channel,
- (unsigned long long) rp->mbox_dma);
+ netdev_err(np->dev, "TX ring channel %d MBOX addr (%llx) has invalid bits\n",
+ channel, (unsigned long long)rp->mbox_dma);
return -EINVAL;
}
nw64(TXDMA_MBH(channel), rp->mbox_dma >> 32);
@@ -5146,9 +5108,8 @@ static int niu_zcp_read(struct niu *np, int index, u64 *data)
err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
1000, 100);
if (err) {
- dev_err(np->device, PFX "%s: ZCP read busy won't clear, "
- "ZCP_RAM_ACC[%llx]\n", np->dev->name,
- (unsigned long long) nr64(ZCP_RAM_ACC));
+ netdev_err(np->dev, "ZCP read busy won't clear, ZCP_RAM_ACC[%llx]\n",
+ (unsigned long long)nr64(ZCP_RAM_ACC));
return err;
}
@@ -5160,9 +5121,8 @@ static int niu_zcp_read(struct niu *np, int index, u64 *data)
err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
1000, 100);
if (err) {
- dev_err(np->device, PFX "%s: ZCP read busy2 won't clear, "
- "ZCP_RAM_ACC[%llx]\n", np->dev->name,
- (unsigned long long) nr64(ZCP_RAM_ACC));
+ netdev_err(np->dev, "ZCP read busy2 won't clear, ZCP_RAM_ACC[%llx]\n",
+ (unsigned long long)nr64(ZCP_RAM_ACC));
return err;
}
@@ -5527,8 +5487,7 @@ static int niu_reset_tx_bmac(struct niu *np)
udelay(100);
}
if (limit < 0) {
- dev_err(np->device, PFX "Port %u TX BMAC would not reset, "
- "BTXMAC_SW_RST[%llx]\n",
+ dev_err(np->device, "Port %u TX BMAC would not reset, BTXMAC_SW_RST[%llx]\n",
np->port,
(unsigned long long) nr64_mac(BTXMAC_SW_RST));
return -ENODEV;
@@ -5629,12 +5588,11 @@ static int niu_reset_rx_xmac(struct niu *np)
while (--limit >= 0) {
if (!(nr64_mac(XRXMAC_SW_RST) & (XRXMAC_SW_RST_REG_RS |
XRXMAC_SW_RST_SOFT_RST)))
- break;
+ break;
udelay(100);
}
if (limit < 0) {
- dev_err(np->device, PFX "Port %u RX XMAC would not reset, "
- "XRXMAC_SW_RST[%llx]\n",
+ dev_err(np->device, "Port %u RX XMAC would not reset, XRXMAC_SW_RST[%llx]\n",
np->port,
(unsigned long long) nr64_mac(XRXMAC_SW_RST));
return -ENODEV;
@@ -5655,8 +5613,7 @@ static int niu_reset_rx_bmac(struct niu *np)
udelay(100);
}
if (limit < 0) {
- dev_err(np->device, PFX "Port %u RX BMAC would not reset, "
- "BRXMAC_SW_RST[%llx]\n",
+ dev_err(np->device, "Port %u RX BMAC would not reset, BRXMAC_SW_RST[%llx]\n",
np->port,
(unsigned long long) nr64_mac(BRXMAC_SW_RST));
return -ENODEV;
@@ -5960,11 +5917,9 @@ static void niu_disable_ipp(struct niu *np)
}
if (limit < 0 &&
(rd != 0 && wr != 1)) {
- dev_err(np->device, PFX "%s: IPP would not quiesce, "
- "rd_ptr[%llx] wr_ptr[%llx]\n",
- np->dev->name,
- (unsigned long long) nr64_ipp(IPP_DFIFO_RD_PTR),
- (unsigned long long) nr64_ipp(IPP_DFIFO_WR_PTR));
+ netdev_err(np->dev, "IPP would not quiesce, rd_ptr[%llx] wr_ptr[%llx]\n",
+ (unsigned long long)nr64_ipp(IPP_DFIFO_RD_PTR),
+ (unsigned long long)nr64_ipp(IPP_DFIFO_WR_PTR));
}
val = nr64_ipp(IPP_CFIG);
@@ -5981,12 +5936,12 @@ static int niu_init_hw(struct niu *np)
{
int i, err;
- niudbg(IFUP, "%s: Initialize TXC\n", np->dev->name);
+ netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize TXC\n");
niu_txc_enable_port(np, 1);
niu_txc_port_dma_enable(np, 1);
niu_txc_set_imask(np, 0);
- niudbg(IFUP, "%s: Initialize TX channels\n", np->dev->name);
+ netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize TX channels\n");
for (i = 0; i < np->num_tx_rings; i++) {
struct tx_ring_info *rp = &np->tx_rings[i];
@@ -5995,27 +5950,27 @@ static int niu_init_hw(struct niu *np)
return err;
}
- niudbg(IFUP, "%s: Initialize RX channels\n", np->dev->name);
+ netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize RX channels\n");
err = niu_init_rx_channels(np);
if (err)
goto out_uninit_tx_channels;
- niudbg(IFUP, "%s: Initialize classifier\n", np->dev->name);
+ netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize classifier\n");
err = niu_init_classifier_hw(np);
if (err)
goto out_uninit_rx_channels;
- niudbg(IFUP, "%s: Initialize ZCP\n", np->dev->name);
+ netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize ZCP\n");
err = niu_init_zcp(np);
if (err)
goto out_uninit_rx_channels;
- niudbg(IFUP, "%s: Initialize IPP\n", np->dev->name);
+ netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize IPP\n");
err = niu_init_ipp(np);
if (err)
goto out_uninit_rx_channels;
- niudbg(IFUP, "%s: Initialize MAC\n", np->dev->name);
+ netif_printk(np, ifup, KERN_DEBUG, np->dev, "Initialize MAC\n");
err = niu_init_mac(np);
if (err)
goto out_uninit_ipp;
@@ -6023,16 +5978,16 @@ static int niu_init_hw(struct niu *np)
return 0;
out_uninit_ipp:
- niudbg(IFUP, "%s: Uninit IPP\n", np->dev->name);
+ netif_printk(np, ifup, KERN_DEBUG, np->dev, "Uninit IPP\n");
niu_disable_ipp(np);
out_uninit_rx_channels:
- niudbg(IFUP, "%s: Uninit RX channels\n", np->dev->name);
+ netif_printk(np, ifup, KERN_DEBUG, np->dev, "Uninit RX channels\n");
niu_stop_rx_channels(np);
niu_reset_rx_channels(np);
out_uninit_tx_channels:
- niudbg(IFUP, "%s: Uninit TX channels\n", np->dev->name);
+ netif_printk(np, ifup, KERN_DEBUG, np->dev, "Uninit TX channels\n");
niu_stop_tx_channels(np);
niu_reset_tx_channels(np);
@@ -6041,25 +5996,25 @@ out_uninit_tx_channels:
static void niu_stop_hw(struct niu *np)
{
- niudbg(IFDOWN, "%s: Disable interrupts\n", np->dev->name);
+ netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Disable interrupts\n");
niu_enable_interrupts(np, 0);
- niudbg(IFDOWN, "%s: Disable RX MAC\n", np->dev->name);
+ netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Disable RX MAC\n");
niu_enable_rx_mac(np, 0);
- niudbg(IFDOWN, "%s: Disable IPP\n", np->dev->name);
+ netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Disable IPP\n");
niu_disable_ipp(np);
- niudbg(IFDOWN, "%s: Stop TX channels\n", np->dev->name);
+ netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Stop TX channels\n");
niu_stop_tx_channels(np);
- niudbg(IFDOWN, "%s: Stop RX channels\n", np->dev->name);
+ netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Stop RX channels\n");
niu_stop_rx_channels(np);
- niudbg(IFDOWN, "%s: Reset TX channels\n", np->dev->name);
+ netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Reset TX channels\n");
niu_reset_tx_channels(np);
- niudbg(IFDOWN, "%s: Reset RX channels\n", np->dev->name);
+ netif_printk(np, ifdown, KERN_DEBUG, np->dev, "Reset RX channels\n");
niu_reset_rx_channels(np);
}
@@ -6369,10 +6324,10 @@ static void niu_set_rx_mode(struct net_device *dev)
np->flags &= ~(NIU_FLAGS_MCAST | NIU_FLAGS_PROMISC);
if (dev->flags & IFF_PROMISC)
np->flags |= NIU_FLAGS_PROMISC;
- if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 0))
+ if ((dev->flags & IFF_ALLMULTI) || (!netdev_mc_empty(dev)))
np->flags |= NIU_FLAGS_MCAST;
- alt_cnt = dev->uc.count;
+ alt_cnt = netdev_uc_count(dev);
if (alt_cnt > niu_num_alt_addr(np)) {
alt_cnt = 0;
np->flags |= NIU_FLAGS_PROMISC;
@@ -6381,17 +6336,15 @@ static void niu_set_rx_mode(struct net_device *dev)
if (alt_cnt) {
int index = 0;
- list_for_each_entry(ha, &dev->uc.list, list) {
+ netdev_for_each_uc_addr(ha, dev) {
err = niu_set_alt_mac(np, index, ha->addr);
if (err)
- printk(KERN_WARNING PFX "%s: Error %d "
- "adding alt mac %d\n",
- dev->name, err, index);
+ netdev_warn(dev, "Error %d adding alt mac %d\n",
+ err, index);
err = niu_enable_alt_mac(np, index, 1);
if (err)
- printk(KERN_WARNING PFX "%s: Error %d "
- "enabling alt mac %d\n",
- dev->name, err, index);
+ netdev_warn(dev, "Error %d enabling alt mac %d\n",
+ err, index);
index++;
}
@@ -6404,16 +6357,15 @@ static void niu_set_rx_mode(struct net_device *dev)
for (i = alt_start; i < niu_num_alt_addr(np); i++) {
err = niu_enable_alt_mac(np, i, 0);
if (err)
- printk(KERN_WARNING PFX "%s: Error %d "
- "disabling alt mac %d\n",
- dev->name, err, i);
+ netdev_warn(dev, "Error %d disabling alt mac %d\n",
+ err, i);
}
}
if (dev->flags & IFF_ALLMULTI) {
for (i = 0; i < 16; i++)
hash[i] = 0xffff;
- } else if (dev->mc_count > 0) {
- for (addr = dev->mc_list; addr; addr = addr->next) {
+ } else if (!netdev_mc_empty(dev)) {
+ netdev_for_each_mc_addr(addr, dev) {
u32 crc = ether_crc_le(ETH_ALEN, addr->da_addr);
crc >>= 24;
@@ -6570,7 +6522,7 @@ static void niu_tx_timeout(struct net_device *dev)
{
struct niu *np = netdev_priv(dev);
- dev_err(np->device, PFX "%s: Transmit timed out, resetting\n",
+ dev_err(np->device, "%s: Transmit timed out, resetting\n",
dev->name);
schedule_work(&np->reset_task);
@@ -6672,8 +6624,7 @@ static netdev_tx_t niu_start_xmit(struct sk_buff *skb,
if (niu_tx_avail(rp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_tx_stop_queue(txq);
- dev_err(np->device, PFX "%s: BUG! Tx ring full when "
- "queue awake!\n", dev->name);
+ dev_err(np->device, "%s: BUG! Tx ring full when queue awake!\n", dev->name);
rp->tx_errors++;
return NETDEV_TX_BUSY;
}
@@ -7237,8 +7188,8 @@ static int niu_get_ethtool_tcam_entry(struct niu *np,
tp = &parent->tcam[idx];
if (!tp->valid) {
- pr_info(PFX "niu%d: %s entry [%d] invalid for idx[%d]\n",
- parent->index, np->dev->name, (u16)nfc->fs.location, idx);
+ netdev_info(np->dev, "niu%d: entry [%d] invalid for idx[%d]\n",
+ parent->index, (u16)nfc->fs.location, idx);
return -EINVAL;
}
@@ -7248,8 +7199,8 @@ static int niu_get_ethtool_tcam_entry(struct niu *np,
ret = niu_class_to_ethflow(class, &fsp->flow_type);
if (ret < 0) {
- pr_info(PFX "niu%d: %s niu_class_to_ethflow failed\n",
- parent->index, np->dev->name);
+ netdev_info(np->dev, "niu%d: niu_class_to_ethflow failed\n",
+ parent->index);
ret = -EINVAL;
goto out;
}
@@ -7332,9 +7283,8 @@ static int niu_get_ethtool_tcam_all(struct niu *np,
if (n_entries != cnt) {
/* print warning, this should not happen */
- pr_info(PFX "niu%d: %s In niu_get_ethtool_tcam_all, "
- "n_entries[%d] != cnt[%d]!!!\n\n",
- np->parent->index, np->dev->name, n_entries, cnt);
+ netdev_info(np->dev, "niu%d: In %s(): n_entries[%d] != cnt[%d]!!!\n",
+ np->parent->index, __func__, n_entries, cnt);
}
return 0;
@@ -7561,9 +7511,8 @@ static int niu_add_ethtool_tcam_entry(struct niu *np,
}
}
if (!add_usr_cls) {
- pr_info(PFX "niu%d: %s niu_add_ethtool_tcam_entry: "
- "Could not find/insert class for pid %d\n",
- parent->index, np->dev->name, uspec->proto);
+ netdev_info(np->dev, "niu%d: %s(): Could not find/insert class for pid %d\n",
+ parent->index, __func__, uspec->proto);
ret = -EINVAL;
goto out;
}
@@ -7596,9 +7545,8 @@ static int niu_add_ethtool_tcam_entry(struct niu *np,
case AH_V6_FLOW:
case ESP_V6_FLOW:
/* Not yet implemented */
- pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: "
- "flow %d for IPv6 not implemented\n\n",
- parent->index, np->dev->name, fsp->flow_type);
+ netdev_info(np->dev, "niu%d: In %s(): flow %d for IPv6 not implemented\n",
+ parent->index, __func__, fsp->flow_type);
ret = -EINVAL;
goto out;
case IP_USER_FLOW:
@@ -7607,17 +7555,15 @@ static int niu_add_ethtool_tcam_entry(struct niu *np,
class);
} else {
/* Not yet implemented */
- pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: "
- "usr flow for IPv6 not implemented\n\n",
- parent->index, np->dev->name);
+ netdev_info(np->dev, "niu%d: In %s(): usr flow for IPv6 not implemented\n",
+ parent->index, __func__);
ret = -EINVAL;
goto out;
}
break;
default:
- pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: "
- "Unknown flow type %d\n\n",
- parent->index, np->dev->name, fsp->flow_type);
+ netdev_info(np->dev, "niu%d: In %s(): Unknown flow type %d\n",
+ parent->index, __func__, fsp->flow_type);
ret = -EINVAL;
goto out;
}
@@ -7627,10 +7573,9 @@ static int niu_add_ethtool_tcam_entry(struct niu *np,
tp->assoc_data = TCAM_ASSOCDATA_DISC;
} else {
if (fsp->ring_cookie >= np->num_rx_rings) {
- pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: "
- "Invalid RX ring %lld\n\n",
- parent->index, np->dev->name,
- (long long) fsp->ring_cookie);
+ netdev_info(np->dev, "niu%d: In %s(): Invalid RX ring %lld\n",
+ parent->index, __func__,
+ (long long)fsp->ring_cookie);
ret = -EINVAL;
goto out;
}
@@ -7699,10 +7644,9 @@ static int niu_del_ethtool_tcam_entry(struct niu *np, u32 loc)
}
}
if (i == NIU_L3_PROG_CLS) {
- pr_info(PFX "niu%d: %s In niu_del_ethtool_tcam_entry,"
- "Usr class 0x%llx not found \n",
- parent->index, np->dev->name,
- (unsigned long long) class);
+ netdev_info(np->dev, "niu%d: In %s(): Usr class 0x%llx not found\n",
+ parent->index, __func__,
+ (unsigned long long)class);
ret = -EINVAL;
goto out;
}
@@ -8001,9 +7945,7 @@ static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent,
* won't get any interrupts and that's painful to debug.
*/
if (nr64(LDG_NUM(ldn)) != ldg) {
- dev_err(np->device, PFX "Port %u, mis-matched "
- "LDG assignment "
- "for ldn %d, should be %d is %llu\n",
+ dev_err(np->device, "Port %u, mis-matched LDG assignment for ldn %d, should be %d is %llu\n",
np->port, ldn, ldg,
(unsigned long long) nr64(LDG_NUM(ldn)));
return -EINVAL;
@@ -8056,7 +7998,7 @@ static int __devinit niu_pci_eeprom_read(struct niu *np, u32 addr)
break;
} while (limit--);
if (!(frame & ESPC_PIO_STAT_READ_END)) {
- dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n",
+ dev_err(np->device, "EEPROM read timeout frame[%llx]\n",
(unsigned long long) frame);
return -ENODEV;
}
@@ -8071,7 +8013,7 @@ static int __devinit niu_pci_eeprom_read(struct niu *np, u32 addr)
break;
} while (limit--);
if (!(frame & ESPC_PIO_STAT_READ_END)) {
- dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n",
+ dev_err(np->device, "EEPROM read timeout frame[%llx]\n",
(unsigned long long) frame);
return -ENODEV;
}
@@ -8152,8 +8094,9 @@ static void __devinit niu_vpd_parse_version(struct niu *np)
s += i + 5;
sscanf(s, "%d.%d", &vpd->fcode_major, &vpd->fcode_minor);
- niudbg(PROBE, "VPD_SCAN: FCODE major(%d) minor(%d)\n",
- vpd->fcode_major, vpd->fcode_minor);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "VPD_SCAN: FCODE major(%d) minor(%d)\n",
+ vpd->fcode_major, vpd->fcode_minor);
if (vpd->fcode_major > NIU_VPD_MIN_MAJOR ||
(vpd->fcode_major == NIU_VPD_MIN_MAJOR &&
vpd->fcode_minor >= NIU_VPD_MIN_MINOR))
@@ -8173,8 +8116,8 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np,
#define FOUND_MASK_PHY 0x00000020
#define FOUND_MASK_ALL 0x0000003f
- niudbg(PROBE, "VPD_SCAN: start[%x] end[%x]\n",
- start, end);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "VPD_SCAN: start[%x] end[%x]\n", start, end);
while (start < end) {
int len, err, instance, type, prop_len;
char namebuf[64];
@@ -8228,8 +8171,7 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np,
}
if (max_len && prop_len > max_len) {
- dev_err(np->device, PFX "Property '%s' length (%d) is "
- "too long.\n", namebuf, prop_len);
+ dev_err(np->device, "Property '%s' length (%d) is too long\n", namebuf, prop_len);
return -EINVAL;
}
@@ -8237,8 +8179,9 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np,
u32 off = start + 5 + err;
int i;
- niudbg(PROBE, "VPD_SCAN: Reading in property [%s] "
- "len[%d]\n", namebuf, prop_len);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "VPD_SCAN: Reading in property [%s] len[%d]\n",
+ namebuf, prop_len);
for (i = 0; i < prop_len; i++)
*prop_buf++ = niu_pci_eeprom_read(np, off + i);
}
@@ -8402,8 +8345,7 @@ static void __devinit niu_pci_vpd_validate(struct niu *np)
u8 val8;
if (!is_valid_ether_addr(&vpd->local_mac[0])) {
- dev_err(np->device, PFX "VPD MAC invalid, "
- "falling back to SPROM.\n");
+ dev_err(np->device, "VPD MAC invalid, falling back to SPROM\n");
np->flags &= ~NIU_FLAGS_VPD_VALID;
return;
@@ -8420,14 +8362,14 @@ static void __devinit niu_pci_vpd_validate(struct niu *np)
np->flags &= ~NIU_FLAGS_10G;
}
if (np->flags & NIU_FLAGS_10G)
- np->mac_xcvr = MAC_XCVR_XPCS;
+ np->mac_xcvr = MAC_XCVR_XPCS;
} else if (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) {
np->flags |= (NIU_FLAGS_10G | NIU_FLAGS_FIBER |
NIU_FLAGS_HOTPLUG_PHY);
} else if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
- dev_err(np->device, PFX "Illegal phy string [%s].\n",
+ dev_err(np->device, "Illegal phy string [%s]\n",
np->vpd.phy_type);
- dev_err(np->device, PFX "Falling back to SPROM.\n");
+ dev_err(np->device, "Falling back to SPROM\n");
np->flags &= ~NIU_FLAGS_VPD_VALID;
return;
}
@@ -8455,7 +8397,8 @@ static int __devinit niu_pci_probe_sprom(struct niu *np)
np->eeprom_len = len;
- niudbg(PROBE, "SPROM: Image size %llu\n", (unsigned long long) val);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "SPROM: Image size %llu\n", (unsigned long long)val);
sum = 0;
for (i = 0; i < len; i++) {
@@ -8465,10 +8408,10 @@ static int __devinit niu_pci_probe_sprom(struct niu *np)
sum += (val >> 16) & 0xff;
sum += (val >> 24) & 0xff;
}
- niudbg(PROBE, "SPROM: Checksum %x\n", (int)(sum & 0xff));
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "SPROM: Checksum %x\n", (int)(sum & 0xff));
if ((sum & 0xff) != 0xab) {
- dev_err(np->device, PFX "Bad SPROM checksum "
- "(%x, should be 0xab)\n", (int) (sum & 0xff));
+ dev_err(np->device, "Bad SPROM checksum (%x, should be 0xab)\n", (int)(sum & 0xff));
return -EINVAL;
}
@@ -8491,11 +8434,12 @@ static int __devinit niu_pci_probe_sprom(struct niu *np)
ESPC_PHY_TYPE_PORT3_SHIFT;
break;
default:
- dev_err(np->device, PFX "Bogus port number %u\n",
+ dev_err(np->device, "Bogus port number %u\n",
np->port);
return -EINVAL;
}
- niudbg(PROBE, "SPROM: PHY type %x\n", val8);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "SPROM: PHY type %x\n", val8);
switch (val8) {
case ESPC_PHY_TYPE_1G_COPPER:
@@ -8527,30 +8471,27 @@ static int __devinit niu_pci_probe_sprom(struct niu *np)
break;
default:
- dev_err(np->device, PFX "Bogus SPROM phy type %u\n", val8);
+ dev_err(np->device, "Bogus SPROM phy type %u\n", val8);
return -EINVAL;
}
val = nr64(ESPC_MAC_ADDR0);
- niudbg(PROBE, "SPROM: MAC_ADDR0[%08llx]\n",
- (unsigned long long) val);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "SPROM: MAC_ADDR0[%08llx]\n", (unsigned long long)val);
dev->perm_addr[0] = (val >> 0) & 0xff;
dev->perm_addr[1] = (val >> 8) & 0xff;
dev->perm_addr[2] = (val >> 16) & 0xff;
dev->perm_addr[3] = (val >> 24) & 0xff;
val = nr64(ESPC_MAC_ADDR1);
- niudbg(PROBE, "SPROM: MAC_ADDR1[%08llx]\n",
- (unsigned long long) val);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "SPROM: MAC_ADDR1[%08llx]\n", (unsigned long long)val);
dev->perm_addr[4] = (val >> 0) & 0xff;
dev->perm_addr[5] = (val >> 8) & 0xff;
if (!is_valid_ether_addr(&dev->perm_addr[0])) {
- dev_err(np->device, PFX "SPROM MAC address invalid\n");
- dev_err(np->device, PFX "[ \n");
- for (i = 0; i < 6; i++)
- printk("%02x ", dev->perm_addr[i]);
- printk("]\n");
+ dev_err(np->device, "SPROM MAC address invalid [ %pM ]\n",
+ dev->perm_addr);
return -EINVAL;
}
@@ -8562,8 +8503,8 @@ static int __devinit niu_pci_probe_sprom(struct niu *np)
memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
val = nr64(ESPC_MOD_STR_LEN);
- niudbg(PROBE, "SPROM: MOD_STR_LEN[%llu]\n",
- (unsigned long long) val);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "SPROM: MOD_STR_LEN[%llu]\n", (unsigned long long)val);
if (val >= 8 * 4)
return -EINVAL;
@@ -8578,8 +8519,8 @@ static int __devinit niu_pci_probe_sprom(struct niu *np)
np->vpd.model[val] = '\0';
val = nr64(ESPC_BD_MOD_STR_LEN);
- niudbg(PROBE, "SPROM: BD_MOD_STR_LEN[%llu]\n",
- (unsigned long long) val);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "SPROM: BD_MOD_STR_LEN[%llu]\n", (unsigned long long)val);
if (val >= 4 * 4)
return -EINVAL;
@@ -8595,8 +8536,8 @@ static int __devinit niu_pci_probe_sprom(struct niu *np)
np->vpd.mac_num =
nr64(ESPC_NUM_PORTS_MACS) & ESPC_NUM_PORTS_MACS_VAL;
- niudbg(PROBE, "SPROM: NUM_PORTS_MACS[%d]\n",
- np->vpd.mac_num);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "SPROM: NUM_PORTS_MACS[%d]\n", np->vpd.mac_num);
return 0;
}
@@ -8629,8 +8570,6 @@ static int __devinit niu_get_and_validate_port(struct niu *np)
}
}
- niudbg(PROBE, "niu_get_and_validate_port: port[%d] num_ports[%d]\n",
- np->port, parent->num_ports);
if (np->port >= parent->num_ports)
return -ENODEV;
@@ -8659,14 +8598,12 @@ static int __devinit phy_record(struct niu_parent *parent,
pr_info("niu%d: Found PHY %08x type %s at phy_port %u\n",
parent->index, id,
- (type == PHY_TYPE_PMA_PMD ?
- "PMA/PMD" :
- (type == PHY_TYPE_PCS ?
- "PCS" : "MII")),
+ type == PHY_TYPE_PMA_PMD ? "PMA/PMD" :
+ type == PHY_TYPE_PCS ? "PCS" : "MII",
phy_port);
if (p->cur[type] >= NIU_MAX_PORTS) {
- printk(KERN_ERR PFX "Too many PHY ports.\n");
+ pr_err("Too many PHY ports\n");
return -EINVAL;
}
idx = p->cur[type];
@@ -8727,8 +8664,7 @@ static void __devinit niu_n2_divide_channels(struct niu_parent *parent)
parent->rxchan_per_port[i] = (16 / num_ports);
parent->txchan_per_port[i] = (16 / num_ports);
- pr_info(PFX "niu%d: Port %u [%u RX chans] "
- "[%u TX chans]\n",
+ pr_info("niu%d: Port %u [%u RX chans] [%u TX chans]\n",
parent->index, i,
parent->rxchan_per_port[i],
parent->txchan_per_port[i]);
@@ -8771,8 +8707,7 @@ static void __devinit niu_divide_channels(struct niu_parent *parent,
parent->rxchan_per_port[i] = rx_chans_per_1g;
parent->txchan_per_port[i] = tx_chans_per_1g;
}
- pr_info(PFX "niu%d: Port %u [%u RX chans] "
- "[%u TX chans]\n",
+ pr_info("niu%d: Port %u [%u RX chans] [%u TX chans]\n",
parent->index, i,
parent->rxchan_per_port[i],
parent->txchan_per_port[i]);
@@ -8781,23 +8716,20 @@ static void __devinit niu_divide_channels(struct niu_parent *parent,
}
if (tot_rx > NIU_NUM_RXCHAN) {
- printk(KERN_ERR PFX "niu%d: Too many RX channels (%d), "
- "resetting to one per port.\n",
+ pr_err("niu%d: Too many RX channels (%d), resetting to one per port\n",
parent->index, tot_rx);
for (i = 0; i < num_ports; i++)
parent->rxchan_per_port[i] = 1;
}
if (tot_tx > NIU_NUM_TXCHAN) {
- printk(KERN_ERR PFX "niu%d: Too many TX channels (%d), "
- "resetting to one per port.\n",
+ pr_err("niu%d: Too many TX channels (%d), resetting to one per port\n",
parent->index, tot_tx);
for (i = 0; i < num_ports; i++)
parent->txchan_per_port[i] = 1;
}
if (tot_rx < NIU_NUM_RXCHAN || tot_tx < NIU_NUM_TXCHAN) {
- printk(KERN_WARNING PFX "niu%d: Driver bug, wasted channels, "
- "RX[%d] TX[%d]\n",
- parent->index, tot_rx, tot_tx);
+ pr_warning("niu%d: Driver bug, wasted channels, RX[%d] TX[%d]\n",
+ parent->index, tot_rx, tot_tx);
}
}
@@ -8825,18 +8757,18 @@ static void __devinit niu_divide_rdc_groups(struct niu_parent *parent,
struct rdc_table *rt = &tp->tables[grp];
int slot;
- pr_info(PFX "niu%d: Port %d RDC tbl(%d) [ ",
+ pr_info("niu%d: Port %d RDC tbl(%d) [ ",
parent->index, i, tp->first_table_num + grp);
for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++) {
rt->rxdma_channel[slot] =
rdc_channel_base + this_channel_offset;
- printk("%d ", rt->rxdma_channel[slot]);
+ pr_cont("%d ", rt->rxdma_channel[slot]);
if (++this_channel_offset == num_channels)
this_channel_offset = 0;
}
- printk("]\n");
+ pr_cont("]\n");
}
parent->rdc_default[i] = rdc_channel_base;
@@ -8996,8 +8928,7 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
break;
default:
- printk(KERN_ERR PFX "Unsupported port config "
- "10G[%d] 1G[%d]\n",
+ pr_err("Unsupported port config 10G[%d] 1G[%d]\n",
num_10g, num_1g);
return -EINVAL;
}
@@ -9015,8 +8946,7 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
return 0;
unknown_vg_1g_port:
- printk(KERN_ERR PFX "Cannot identify platform type, 1gport=%d\n",
- lowest_1g);
+ pr_err("Cannot identify platform type, 1gport=%d\n", lowest_1g);
return -EINVAL;
}
@@ -9025,9 +8955,6 @@ static int __devinit niu_probe_ports(struct niu *np)
struct niu_parent *parent = np->parent;
int err, i;
- niudbg(PROBE, "niu_probe_ports(): port_phy[%08x]\n",
- parent->port_phy);
-
if (parent->port_phy == PORT_PHY_UNKNOWN) {
err = walk_phys(np, parent);
if (err)
@@ -9048,9 +8975,6 @@ static int __devinit niu_classifier_swstate_init(struct niu *np)
{
struct niu_classifier *cp = &np->clas;
- niudbg(PROBE, "niu_classifier_swstate_init: num_tcam(%d)\n",
- np->parent->tcam_num_entries);
-
cp->tcam_top = (u16) np->port;
cp->tcam_sz = np->parent->tcam_num_entries / np->parent->num_ports;
cp->h1_init = 0xffffffff;
@@ -9116,8 +9040,7 @@ static int __devinit niu_init_mac_ipp_pcs_base(struct niu *np)
break;
default:
- dev_err(np->device, PFX "Port %u is invalid, cannot "
- "compute MAC block offset.\n", np->port);
+ dev_err(np->device, "Port %u is invalid, cannot compute MAC block offset\n", np->port);
return -EINVAL;
}
@@ -9327,9 +9250,8 @@ static int __devinit niu_get_of_props(struct niu *np)
phy_type = of_get_property(dp, "phy-type", &prop_len);
if (!phy_type) {
- dev_err(np->device, PFX "%s: OF node lacks "
- "phy-type property\n",
- dp->full_name);
+ netdev_err(dev, "%s: OF node lacks phy-type property\n",
+ dp->full_name);
return -EINVAL;
}
@@ -9339,34 +9261,26 @@ static int __devinit niu_get_of_props(struct niu *np)
strcpy(np->vpd.phy_type, phy_type);
if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
- dev_err(np->device, PFX "%s: Illegal phy string [%s].\n",
- dp->full_name, np->vpd.phy_type);
+ netdev_err(dev, "%s: Illegal phy string [%s]\n",
+ dp->full_name, np->vpd.phy_type);
return -EINVAL;
}
mac_addr = of_get_property(dp, "local-mac-address", &prop_len);
if (!mac_addr) {
- dev_err(np->device, PFX "%s: OF node lacks "
- "local-mac-address property\n",
- dp->full_name);
+ netdev_err(dev, "%s: OF node lacks local-mac-address property\n",
+ dp->full_name);
return -EINVAL;
}
if (prop_len != dev->addr_len) {
- dev_err(np->device, PFX "%s: OF MAC address prop len (%d) "
- "is wrong.\n",
- dp->full_name, prop_len);
+ netdev_err(dev, "%s: OF MAC address prop len (%d) is wrong\n",
+ dp->full_name, prop_len);
}
memcpy(dev->perm_addr, mac_addr, dev->addr_len);
if (!is_valid_ether_addr(&dev->perm_addr[0])) {
- int i;
-
- dev_err(np->device, PFX "%s: OF MAC address is invalid\n",
- dp->full_name);
- dev_err(np->device, PFX "%s: [ \n",
- dp->full_name);
- for (i = 0; i < 6; i++)
- printk("%02x ", dev->perm_addr[i]);
- printk("]\n");
+ netdev_err(dev, "%s: OF MAC address is invalid\n",
+ dp->full_name);
+ netdev_err(dev, "%s: [ %pM ]\n", dp->full_name, dev->perm_addr);
return -EINVAL;
}
@@ -9414,8 +9328,8 @@ static int __devinit niu_get_invariants(struct niu *np)
nw64(ESPC_PIO_EN, ESPC_PIO_EN_ENABLE);
offset = niu_pci_vpd_offset(np);
- niudbg(PROBE, "niu_get_invariants: VPD offset [%08x]\n",
- offset);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "%s() VPD offset [%08x]\n", __func__, offset);
if (offset)
niu_pci_vpd_fetch(np, offset);
nw64(ESPC_PIO_EN, 0);
@@ -9575,8 +9489,6 @@ static struct niu_parent * __devinit niu_new_parent(struct niu *np,
struct niu_parent *p;
int i;
- niudbg(PROBE, "niu_new_parent: Creating new parent.\n");
-
plat_dev = platform_device_register_simple("niu", niu_parent_index,
NULL, 0);
if (IS_ERR(plat_dev))
@@ -9641,9 +9553,6 @@ static struct niu_parent * __devinit niu_get_parent(struct niu *np,
struct niu_parent *p, *tmp;
int port = np->port;
- niudbg(PROBE, "niu_get_parent: platform_type[%u] port[%u]\n",
- ptype, port);
-
mutex_lock(&niu_parent_lock);
p = NULL;
list_for_each_entry(tmp, &niu_parent_list, list) {
@@ -9681,7 +9590,8 @@ static void niu_put_parent(struct niu *np)
BUG_ON(!p || p->ports[port] != np);
- niudbg(PROBE, "niu_put_parent: port[%u]\n", port);
+ netif_printk(np, probe, KERN_DEBUG, np->dev,
+ "%s() port[%u]\n", __func__, port);
sprintf(port_name, "port%d", port);
@@ -9772,7 +9682,7 @@ static struct net_device * __devinit niu_alloc_and_init(
dev = alloc_etherdev_mq(sizeof(struct niu), NIU_NUM_TXCHAN);
if (!dev) {
- dev_err(gen_dev, PFX "Etherdev alloc failed, aborting.\n");
+ dev_err(gen_dev, "Etherdev alloc failed, aborting\n");
return NULL;
}
@@ -9858,30 +9768,26 @@ static int __devinit niu_pci_init_one(struct pci_dev *pdev,
err = pci_enable_device(pdev);
if (err) {
- dev_err(&pdev->dev, PFX "Cannot enable PCI device, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
return err;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
- dev_err(&pdev->dev, PFX "Cannot find proper PCI device "
- "base addresses, aborting.\n");
+ dev_err(&pdev->dev, "Cannot find proper PCI device base addresses, aborting\n");
err = -ENODEV;
goto err_out_disable_pdev;
}
err = pci_request_regions(pdev, DRV_MODULE_NAME);
if (err) {
- dev_err(&pdev->dev, PFX "Cannot obtain PCI resources, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
goto err_out_disable_pdev;
}
pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
if (pos <= 0) {
- dev_err(&pdev->dev, PFX "Cannot find PCI Express capability, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot find PCI Express capability, aborting\n");
goto err_out_free_res;
}
@@ -9920,17 +9826,14 @@ static int __devinit niu_pci_init_one(struct pci_dev *pdev,
dev->features |= NETIF_F_HIGHDMA;
err = pci_set_consistent_dma_mask(pdev, dma_mask);
if (err) {
- dev_err(&pdev->dev, PFX "Unable to obtain 44 bit "
- "DMA for consistent allocations, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Unable to obtain 44 bit DMA for consistent allocations, aborting\n");
goto err_out_release_parent;
}
}
if (err || dma_mask == DMA_BIT_MASK(32)) {
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (err) {
- dev_err(&pdev->dev, PFX "No usable DMA configuration, "
- "aborting.\n");
+ dev_err(&pdev->dev, "No usable DMA configuration, aborting\n");
goto err_out_release_parent;
}
}
@@ -9939,8 +9842,7 @@ static int __devinit niu_pci_init_one(struct pci_dev *pdev,
np->regs = pci_ioremap_bar(pdev, 0);
if (!np->regs) {
- dev_err(&pdev->dev, PFX "Cannot map device registers, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot map device registers, aborting\n");
err = -ENOMEM;
goto err_out_release_parent;
}
@@ -9955,15 +9857,13 @@ static int __devinit niu_pci_init_one(struct pci_dev *pdev,
err = niu_get_invariants(np);
if (err) {
if (err != -ENODEV)
- dev_err(&pdev->dev, PFX "Problem fetching invariants "
- "of chip, aborting.\n");
+ dev_err(&pdev->dev, "Problem fetching invariants of chip, aborting\n");
goto err_out_iounmap;
}
err = register_netdev(dev);
if (err) {
- dev_err(&pdev->dev, PFX "Cannot register net device, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot register net device, aborting\n");
goto err_out_iounmap;
}
@@ -10157,7 +10057,7 @@ static int __devinit niu_of_probe(struct of_device *op,
reg = of_get_property(op->node, "reg", NULL);
if (!reg) {
- dev_err(&op->dev, PFX "%s: No 'reg' property, aborting.\n",
+ dev_err(&op->dev, "%s: No 'reg' property, aborting\n",
op->node->full_name);
return -ENODEV;
}
@@ -10186,8 +10086,7 @@ static int __devinit niu_of_probe(struct of_device *op,
resource_size(&op->resource[1]),
"niu regs");
if (!np->regs) {
- dev_err(&op->dev, PFX "Cannot map device registers, "
- "aborting.\n");
+ dev_err(&op->dev, "Cannot map device registers, aborting\n");
err = -ENOMEM;
goto err_out_release_parent;
}
@@ -10196,8 +10095,7 @@ static int __devinit niu_of_probe(struct of_device *op,
resource_size(&op->resource[2]),
"niu vregs-1");
if (!np->vir_regs_1) {
- dev_err(&op->dev, PFX "Cannot map device vir registers 1, "
- "aborting.\n");
+ dev_err(&op->dev, "Cannot map device vir registers 1, aborting\n");
err = -ENOMEM;
goto err_out_iounmap;
}
@@ -10206,8 +10104,7 @@ static int __devinit niu_of_probe(struct of_device *op,
resource_size(&op->resource[3]),
"niu vregs-2");
if (!np->vir_regs_2) {
- dev_err(&op->dev, PFX "Cannot map device vir registers 2, "
- "aborting.\n");
+ dev_err(&op->dev, "Cannot map device vir registers 2, aborting\n");
err = -ENOMEM;
goto err_out_iounmap;
}
@@ -10217,15 +10114,13 @@ static int __devinit niu_of_probe(struct of_device *op,
err = niu_get_invariants(np);
if (err) {
if (err != -ENODEV)
- dev_err(&op->dev, PFX "Problem fetching invariants "
- "of chip, aborting.\n");
+ dev_err(&op->dev, "Problem fetching invariants of chip, aborting\n");
goto err_out_iounmap;
}
err = register_netdev(dev);
if (err) {
- dev_err(&op->dev, PFX "Cannot register net device, "
- "aborting.\n");
+ dev_err(&op->dev, "Cannot register net device, aborting\n");
goto err_out_iounmap;
}
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 1f6327d41536..8dd509c09bc8 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1719,7 +1719,7 @@ static void ns83820_set_multicast(struct net_device *ndev)
else
and_mask &= ~(RFCR_AAU | RFCR_AAM);
- if (ndev->flags & IFF_ALLMULTI || ndev->mc_count)
+ if (ndev->flags & IFF_ALLMULTI || netdev_mc_count(ndev))
or_mask |= RFCR_AAM;
else
and_mask &= ~RFCR_AAM;
@@ -2292,7 +2292,7 @@ static void __devexit ns83820_remove_one(struct pci_dev *pci_dev)
pci_set_drvdata(pci_dev, NULL);
}
-static struct pci_device_id ns83820_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(ns83820_pci_tbl) = {
{ 0x100b, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, .driver_data = 0, },
{ 0, },
};
diff --git a/drivers/net/octeon/octeon_mgmt.c b/drivers/net/octeon/octeon_mgmt.c
index 050538bf155a..be368e5cbf75 100644
--- a/drivers/net/octeon/octeon_mgmt.c
+++ b/drivers/net/octeon/octeon_mgmt.c
@@ -467,7 +467,6 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
{
struct octeon_mgmt *p = netdev_priv(netdev);
int port = p->port;
- int i;
union cvmx_agl_gmx_rxx_adr_ctl adr_ctl;
union cvmx_agl_gmx_prtx_cfg agl_gmx_prtx;
unsigned long flags;
@@ -493,8 +492,8 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
}
if (netdev->flags & IFF_MULTICAST) {
- if (cam_mode == 0 || (netdev->flags & IFF_ALLMULTI)
- || netdev->mc_count > available_cam_entries)
+ if (cam_mode == 0 || (netdev->flags & IFF_ALLMULTI) ||
+ netdev_mc_count(netdev) > available_cam_entries)
multicast_mode = 2; /* 1 - Accept all multicast. */
else
multicast_mode = 0; /* 0 - Use CAM. */
@@ -511,12 +510,8 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
}
}
if (multicast_mode == 0) {
- i = netdev->mc_count;
- list = netdev->mc_list;
- while (i--) {
+ netdev_for_each_mc_addr(list, netdev)
octeon_mgmt_cam_state_add(&cam_state, list->da_addr);
- list = list->next;
- }
}
@@ -1119,11 +1114,8 @@ static int __init octeon_mgmt_probe(struct platform_device *pdev)
if (p->port >= octeon_bootinfo->mac_addr_count)
dev_err(&pdev->dev,
- "Error %s: Using MAC outside of the assigned range: "
- "%02x:%02x:%02x:%02x:%02x:%02x\n", netdev->name,
- netdev->dev_addr[0], netdev->dev_addr[1],
- netdev->dev_addr[2], netdev->dev_addr[3],
- netdev->dev_addr[4], netdev->dev_addr[5]);
+ "Error %s: Using MAC outside of the assigned range: %pM\n",
+ netdev->name, netdev->dev_addr);
if (register_netdev(netdev))
goto err;
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index 1673eb045e1e..d44d4a208bbf 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -1875,7 +1875,7 @@ static void __devexit pasemi_mac_remove(struct pci_dev *pdev)
free_netdev(netdev);
}
-static struct pci_device_id pasemi_mac_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(pasemi_mac_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa005) },
{ PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa006) },
{ },
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 480af402affd..36785853a149 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -11,7 +11,7 @@
-----<snip>-----
- Written 1997-2000 by Donald Becker.
+ Written 1997-2000 by Donald Becker.
This software may be used and distributed according to the
terms of the GNU General Public License (GPL), incorporated
herein by reference. Drivers based on or derived from this
@@ -85,6 +85,8 @@ IVc. Errata
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -96,16 +98,15 @@ IVc. Errata
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/crc32.h>
-#include <asm/io.h>
+#include <linux/io.h>
#define NETDRV_VERSION "1.0.1"
#define MODNAME "netdrv"
#define NETDRV_DRIVER_LOAD_MSG "MyVendor Fast Ethernet driver " NETDRV_VERSION " loaded"
-#define PFX MODNAME ": "
static char version[] __devinitdata =
-KERN_INFO NETDRV_DRIVER_LOAD_MSG "\n"
-" Support available from http://foo.com/bar/baz.html\n";
+ KERN_INFO NETDRV_DRIVER_LOAD_MSG "\n"
+ " Support available from http://foo.com/bar/baz.html\n";
/* define to 1 to enable PIO instead of MMIO */
#undef USE_IO_OPS
@@ -119,19 +120,24 @@ KERN_INFO NETDRV_DRIVER_LOAD_MSG "\n"
#ifdef NETDRV_DEBUG
/* note: prints function name for you */
-# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
+#define DPRINTK(fmt, args...) \
+ printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
#else
-# define DPRINTK(fmt, args...)
+#define DPRINTK(fmt, args...) \
+do { \
+ if (0) \
+ printk(KERN_DEBUG fmt, ##args); \
+} while (0)
#endif
#ifdef NETDRV_NDEBUG
-# define assert(expr) do {} while (0)
+#define assert(expr) do {} while (0)
#else
-# define assert(expr) \
- if(!(expr)) { \
- printk( "Assertion failed! %s,%s,%s,line=%d\n", \
- #expr,__FILE__,__func__,__LINE__); \
- }
+#define assert(expr) \
+ if (!(expr)) { \
+ printk("Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr, __FILE__, __func__, __LINE__); \
+ }
#endif
@@ -148,10 +154,10 @@ static int multicast_filter_limit = 32;
/* Size of the in-memory receive ring. */
#define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */
-#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
-#define RX_BUF_PAD 16
+#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+#define RX_BUF_PAD 16
#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
-#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
+#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
/* Number of Tx descriptor registers. */
#define NUM_TX_DESC 4
@@ -165,9 +171,11 @@ static int multicast_filter_limit = 32;
/* PCI Tuning Parameters
Threshold is bytes transferred to chip before transmission starts. */
-#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
+#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
-/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */
+/* The following settings are log_2(bytes)-4:
+ 0==16 bytes 1==32 2==64 3==128 4==256 5==512 6==1024 7==end of packet.
+*/
#define RX_FIFO_THRESH 6 /* Rx buffer level before first PCI xfer. */
#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
@@ -175,8 +183,7 @@ static int multicast_filter_limit = 32;
/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (6*HZ)
-
+#define TX_TIMEOUT (6 * HZ)
enum {
HAS_CHIP_XCVR = 0x020000,
@@ -186,7 +193,7 @@ enum {
#define NETDRV_MIN_IO_SIZE 0x80
#define RTL8139B_IO_SIZE 256
-#define NETDRV_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG
+#define NETDRV_CAPS (HAS_CHIP_XCVR | HAS_LNK_CHNG)
typedef enum {
RTL8139 = 0,
@@ -211,7 +218,7 @@ static struct {
};
-static struct pci_device_id netdrv_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(netdrv_pci_tbl) = {
{0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NETDRV_CB },
{0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX },
@@ -220,7 +227,7 @@ static struct pci_device_id netdrv_pci_tbl[] = {
{0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 },
{0,}
};
-MODULE_DEVICE_TABLE (pci, netdrv_pci_tbl);
+MODULE_DEVICE_TABLE(pci, netdrv_pci_tbl);
/* The rest of these values should never change. */
@@ -270,7 +277,7 @@ enum NETDRV_registers {
enum ClearBitMasks {
MultiIntrClear = 0xF000,
ChipCmdClear = 0xE2,
- Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
+ Config1Clear = (1 << 7) | (1 << 6) | (1 << 3) | (1 << 2) | (1 << 1),
};
enum ChipCmdBits {
@@ -329,7 +336,7 @@ enum tx_config_bits {
TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
TxClearAbt = (1 << 0), /* Clear abort (WO) */
- TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
+ TxDMAShift = 8, /* DMA burst value(0-7) is shift this many bits */
TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
};
@@ -481,41 +488,44 @@ struct netdrv_private {
chip_t chipset;
};
-MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
-MODULE_DESCRIPTION ("Skeleton for a PCI Fast Ethernet driver");
+MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
+MODULE_DESCRIPTION("Skeleton for a PCI Fast Ethernet driver");
MODULE_LICENSE("GPL");
module_param(multicast_filter_limit, int, 0);
module_param(max_interrupt_work, int, 0);
module_param_array(media, int, NULL, 0);
-MODULE_PARM_DESC (multicast_filter_limit, "pci-skeleton maximum number of filtered multicast addresses");
-MODULE_PARM_DESC (max_interrupt_work, "pci-skeleton maximum events handled per interrupt");
-MODULE_PARM_DESC (media, "pci-skeleton: Bits 0-3: media type, bit 17: full duplex");
-
-static int read_eeprom (void *ioaddr, int location, int addr_len);
-static int netdrv_open (struct net_device *dev);
-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 val);
-static void netdrv_timer (unsigned long data);
-static void netdrv_tx_timeout (struct net_device *dev);
-static void netdrv_init_ring (struct net_device *dev);
-static int netdrv_start_xmit (struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t netdrv_interrupt (int irq, void *dev_instance);
-static int netdrv_close (struct net_device *dev);
-static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
-static void netdrv_set_rx_mode (struct net_device *dev);
-static void netdrv_hw_start (struct net_device *dev);
+MODULE_PARM_DESC(multicast_filter_limit,
+ MODNAME " maximum number of filtered multicast addresses");
+MODULE_PARM_DESC(max_interrupt_work,
+ MODNAME " maximum events handled per interrupt");
+MODULE_PARM_DESC(media,
+ MODNAME " Bits 0-3: media type, bit 17: full duplex");
+
+static int read_eeprom(void *ioaddr, int location, int addr_len);
+static int netdrv_open(struct net_device *dev);
+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 val);
+static void netdrv_timer(unsigned long data);
+static void netdrv_tx_timeout(struct net_device *dev);
+static void netdrv_init_ring(struct net_device *dev);
+static int netdrv_start_xmit(struct sk_buff *skb,
+ struct net_device *dev);
+static irqreturn_t netdrv_interrupt(int irq, void *dev_instance);
+static int netdrv_close(struct net_device *dev);
+static int netdrv_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void netdrv_set_rx_mode(struct net_device *dev);
+static void netdrv_hw_start(struct net_device *dev);
#ifdef USE_IO_OPS
-#define NETDRV_R8(reg) inb (((unsigned long)ioaddr) + (reg))
-#define NETDRV_R16(reg) inw (((unsigned long)ioaddr) + (reg))
-#define NETDRV_R32(reg) ((unsigned long) inl (((unsigned long)ioaddr) + (reg)))
-#define NETDRV_W8(reg, val8) outb ((val8), ((unsigned long)ioaddr) + (reg))
-#define NETDRV_W16(reg, val16) outw ((val16), ((unsigned long)ioaddr) + (reg))
-#define NETDRV_W32(reg, val32) outl ((val32), ((unsigned long)ioaddr) + (reg))
+#define NETDRV_R8(reg) inb(((unsigned long)ioaddr) + (reg))
+#define NETDRV_R16(reg) inw(((unsigned long)ioaddr) + (reg))
+#define NETDRV_R32(reg) ((unsigned long)inl(((unsigned long)ioaddr) + (reg)))
+#define NETDRV_W8(reg, val8) outb((val8), ((unsigned long)ioaddr) + (reg))
+#define NETDRV_W16(reg, val16) outw((val16), ((unsigned long)ioaddr) + (reg))
+#define NETDRV_W32(reg, val32) outl((val32), ((unsigned long)ioaddr) + (reg))
#define NETDRV_W8_F NETDRV_W8
#define NETDRV_W16_F NETDRV_W16
#define NETDRV_W32_F NETDRV_W32
@@ -528,25 +538,37 @@ static void netdrv_hw_start (struct net_device *dev);
#define readb(addr) inb((unsigned long)(addr))
#define readw(addr) inw((unsigned long)(addr))
#define readl(addr) inl((unsigned long)(addr))
-#define writeb(val,addr) outb((val),(unsigned long)(addr))
-#define writew(val,addr) outw((val),(unsigned long)(addr))
-#define writel(val,addr) outl((val),(unsigned long)(addr))
+#define writeb(val, addr) outb((val), (unsigned long)(addr))
+#define writew(val, addr) outw((val), (unsigned long)(addr))
+#define writel(val, addr) outl((val), (unsigned long)(addr))
#else
/* write MMIO register, with flush */
/* Flush avoids rtl8139 bug w/ posted MMIO writes */
-#define NETDRV_W8_F(reg, val8) do { writeb ((val8), ioaddr + (reg)); readb (ioaddr + (reg)); } while (0)
-#define NETDRV_W16_F(reg, val16) do { writew ((val16), ioaddr + (reg)); readw (ioaddr + (reg)); } while (0)
-#define NETDRV_W32_F(reg, val32) do { writel ((val32), ioaddr + (reg)); readl (ioaddr + (reg)); } while (0)
+#define NETDRV_W8_F(reg, val8) \
+do { \
+ writeb((val8), ioaddr + (reg)); \
+ readb(ioaddr + (reg)); \
+} while (0)
+#define NETDRV_W16_F(reg, val16) \
+do { \
+ writew((val16), ioaddr + (reg)); \
+ readw(ioaddr + (reg)); \
+} while (0)
+#define NETDRV_W32_F(reg, val32) \
+do { \
+ writel((val32), ioaddr + (reg)); \
+ readl(ioaddr + (reg)); \
+} while (0)
#ifdef MMIO_FLUSH_AUDIT_COMPLETE
/* write MMIO register */
-#define NETDRV_W8(reg, val8) writeb ((val8), ioaddr + (reg))
-#define NETDRV_W16(reg, val16) writew ((val16), ioaddr + (reg))
-#define NETDRV_W32(reg, val32) writel ((val32), ioaddr + (reg))
+#define NETDRV_W8(reg, val8) writeb((val8), ioaddr + (reg))
+#define NETDRV_W16(reg, val16) writew((val16), ioaddr + (reg))
+#define NETDRV_W32(reg, val32) writel((val32), ioaddr + (reg))
#else
@@ -558,9 +580,9 @@ static void netdrv_hw_start (struct net_device *dev);
#endif /* MMIO_FLUSH_AUDIT_COMPLETE */
/* read MMIO register */
-#define NETDRV_R8(reg) readb (ioaddr + (reg))
-#define NETDRV_R16(reg) readw (ioaddr + (reg))
-#define NETDRV_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
+#define NETDRV_R8(reg) readb(ioaddr + (reg))
+#define NETDRV_R16(reg) readw(ioaddr + (reg))
+#define NETDRV_R32(reg) ((unsigned long) readl(ioaddr + (reg)))
#endif /* USE_IO_OPS */
@@ -570,14 +592,14 @@ static const u16 netdrv_intr_mask =
TxErr | TxOK | RxErr | RxOK;
static const unsigned int netdrv_rx_config =
- RxCfgEarlyRxNone | RxCfgRcv32K | RxNoWrap |
- (RX_FIFO_THRESH << RxCfgFIFOShift) |
- (RX_DMA_BURST << RxCfgDMAShift);
+ RxCfgEarlyRxNone | RxCfgRcv32K | RxNoWrap |
+ (RX_FIFO_THRESH << RxCfgFIFOShift) |
+ (RX_DMA_BURST << RxCfgDMAShift);
-static int __devinit netdrv_init_board (struct pci_dev *pdev,
- struct net_device **dev_out,
- void **ioaddr_out)
+static int __devinit netdrv_init_board(struct pci_dev *pdev,
+ struct net_device **dev_out,
+ void **ioaddr_out)
{
void *ioaddr = NULL;
struct net_device *dev;
@@ -587,43 +609,43 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
u32 tmp;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- assert (pdev != NULL);
- assert (ioaddr_out != NULL);
+ assert(pdev != NULL);
+ assert(ioaddr_out != NULL);
*ioaddr_out = NULL;
*dev_out = NULL;
/* dev zeroed in alloc_etherdev */
- dev = alloc_etherdev (sizeof (*tp));
+ dev = alloc_etherdev(sizeof(*tp));
if (dev == NULL) {
dev_err(&pdev->dev, "unable to alloc new ethernet\n");
- DPRINTK ("EXIT, returning -ENOMEM\n");
+ DPRINTK("EXIT, returning -ENOMEM\n");
return -ENOMEM;
}
SET_NETDEV_DEV(dev, &pdev->dev);
tp = netdev_priv(dev);
- /* enable device (incl. PCI PM wakeup), and bus-mastering */
- rc = pci_enable_device (pdev);
+ /* enable device(incl. PCI PM wakeup), and bus-mastering */
+ rc = pci_enable_device(pdev);
if (rc)
goto err_out;
- pio_start = pci_resource_start (pdev, 0);
- pio_end = pci_resource_end (pdev, 0);
- pio_flags = pci_resource_flags (pdev, 0);
- pio_len = pci_resource_len (pdev, 0);
+ pio_start = pci_resource_start(pdev, 0);
+ pio_end = pci_resource_end(pdev, 0);
+ pio_flags = pci_resource_flags(pdev, 0);
+ pio_len = pci_resource_len(pdev, 0);
- mmio_start = pci_resource_start (pdev, 1);
- mmio_end = pci_resource_end (pdev, 1);
- mmio_flags = pci_resource_flags (pdev, 1);
- mmio_len = pci_resource_len (pdev, 1);
+ mmio_start = pci_resource_start(pdev, 1);
+ mmio_end = pci_resource_end(pdev, 1);
+ mmio_flags = pci_resource_flags(pdev, 1);
+ mmio_len = pci_resource_len(pdev, 1);
/* set this immediately, we need to know before
* we talk to the chip directly */
- DPRINTK("PIO region size == 0x%02X\n", pio_len);
- DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);
+ DPRINTK("PIO region size == %#02X\n", pio_len);
+ DPRINTK("MMIO region size == %#02lX\n", mmio_len);
/* make sure PCI base addr 0 is PIO */
if (!(pio_flags & IORESOURCE_IO)) {
@@ -647,17 +669,17 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
goto err_out;
}
- rc = pci_request_regions (pdev, MODNAME);
+ rc = pci_request_regions(pdev, MODNAME);
if (rc)
goto err_out;
- pci_set_master (pdev);
+ pci_set_master(pdev);
#ifdef USE_IO_OPS
- ioaddr = (void *) pio_start;
+ ioaddr = (void *)pio_start;
#else
/* ioremap MMIO region */
- ioaddr = ioremap (mmio_start, mmio_len);
+ ioaddr = ioremap(mmio_start, mmio_len);
if (ioaddr == NULL) {
dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
rc = -EIO;
@@ -666,52 +688,50 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
#endif /* USE_IO_OPS */
/* Soft reset the chip. */
- NETDRV_W8 (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear) | CmdReset);
+ NETDRV_W8(ChipCmd, (NETDRV_R8(ChipCmd) & ChipCmdClear) | CmdReset);
/* Check that the chip has finished the reset. */
for (i = 1000; i > 0; i--)
- if ((NETDRV_R8 (ChipCmd) & CmdReset) == 0)
+ if ((NETDRV_R8(ChipCmd) & CmdReset) == 0)
break;
else
- udelay (10);
+ udelay(10);
/* Bring the chip out of low-power mode. */
/* <insert device-specific code here> */
#ifndef USE_IO_OPS
/* sanity checks -- ensure PIO and MMIO registers agree */
- assert (inb (pio_start+Config0) == readb (ioaddr+Config0));
- assert (inb (pio_start+Config1) == readb (ioaddr+Config1));
- assert (inb (pio_start+TxConfig) == readb (ioaddr+TxConfig));
- assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig));
+ assert(inb(pio_start+Config0) == readb(ioaddr+Config0));
+ assert(inb(pio_start+Config1) == readb(ioaddr+Config1));
+ assert(inb(pio_start+TxConfig) == readb(ioaddr+TxConfig));
+ assert(inb(pio_start+RxConfig) == readb(ioaddr+RxConfig));
#endif /* !USE_IO_OPS */
/* identify chip attached to board */
- tmp = NETDRV_R8 (ChipVersion);
- for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--)
+ tmp = NETDRV_R8(ChipVersion);
+ for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--)
if (tmp == rtl_chip_info[i].version) {
tp->chipset = i;
goto match;
}
/* if unknown chip, assume array element #0, original RTL-8139 in this case */
- dev_printk (KERN_DEBUG, &pdev->dev,
- "unknown chip version, assuming RTL-8139\n");
- dev_printk (KERN_DEBUG, &pdev->dev, "TxConfig = 0x%lx\n",
- NETDRV_R32 (TxConfig));
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "unknown chip version, assuming RTL-8139\n");
+ dev_printk(KERN_DEBUG, &pdev->dev, "TxConfig = %#lx\n",
+ NETDRV_R32(TxConfig));
tp->chipset = 0;
match:
- DPRINTK ("chipset id (%d) == index %d, '%s'\n",
- tmp,
- tp->chipset,
- rtl_chip_info[tp->chipset].name);
+ DPRINTK("chipset id(%d) == index %d, '%s'\n",
+ tmp, tp->chipset, rtl_chip_info[tp->chipset].name);
- rc = register_netdev (dev);
+ rc = register_netdev(dev);
if (rc)
goto err_out_unmap;
- DPRINTK ("EXIT, returning 0\n");
+ DPRINTK("EXIT, returning 0\n");
*ioaddr_out = ioaddr;
*dev_out = dev;
return 0;
@@ -721,10 +741,10 @@ err_out_unmap:
iounmap(ioaddr);
err_out_free_res:
#endif
- pci_release_regions (pdev);
+ pci_release_regions(pdev);
err_out:
- free_netdev (dev);
- DPRINTK ("EXIT, returning %d\n", rc);
+ free_netdev(dev);
+ DPRINTK("EXIT, returning %d\n", rc);
return rc;
}
@@ -740,8 +760,8 @@ static const struct net_device_ops netdrv_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
};
-static int __devinit netdrv_init_one (struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit netdrv_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct net_device *dev = NULL;
struct netdrv_private *tp;
@@ -756,29 +776,29 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
printk(version);
#endif
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- assert (pdev != NULL);
- assert (ent != NULL);
+ assert(pdev != NULL);
+ assert(ent != NULL);
board_idx++;
- i = netdrv_init_board (pdev, &dev, &ioaddr);
+ i = netdrv_init_board(pdev, &dev, &ioaddr);
if (i < 0) {
- DPRINTK ("EXIT, returning %d\n", i);
+ DPRINTK("EXIT, returning %d\n", i);
return i;
}
tp = netdev_priv(dev);
- assert (ioaddr != NULL);
- assert (dev != NULL);
- assert (tp != NULL);
+ assert(ioaddr != NULL);
+ assert(dev != NULL);
+ assert(tp != NULL);
- addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;
+ addr_len = read_eeprom(ioaddr, 0, 8) == 0x8129 ? 8 : 6;
for (i = 0; i < 3; i++)
- ((u16 *) (dev->dev_addr))[i] =
- le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len));
+ ((u16 *)(dev->dev_addr))[i] =
+ le16_to_cpu(read_eeprom(ioaddr, i + 7, addr_len));
dev->netdev_ops = &netdrv_netdev_ops;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -791,7 +811,7 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
/* note: tp->chipset set in netdrv_init_board */
tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
- PCI_COMMAND_MASTER | NETDRV_CAPS;
+ PCI_COMMAND_MASTER | NETDRV_CAPS;
tp->pci_dev = pdev;
tp->board = ent->driver_data;
tp->mmio_addr = ioaddr;
@@ -801,18 +821,15 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
tp->phys[0] = 32;
- printk (KERN_INFO "%s: %s at 0x%lx, %pM IRQ %d\n",
- dev->name,
- board_info[ent->driver_data].name,
- dev->base_addr,
- dev->dev_addr,
- dev->irq);
+ netdev_info(dev, "%s at %#lx, %pM IRQ %d\n",
+ board_info[ent->driver_data].name,
+ dev->base_addr, dev->dev_addr, dev->irq);
- printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n",
- dev->name, rtl_chip_info[tp->chipset].name);
+ netdev_printk(KERN_DEBUG, dev, "Identified 8139 chip type '%s'\n",
+ rtl_chip_info[tp->chipset].name);
/* Put the chip into low-power mode. */
- NETDRV_W8_F (Cfg9346, Cfg9346_Unlock);
+ NETDRV_W8_F(Cfg9346, Cfg9346_Unlock);
/* The lower four bits are the media type. */
option = (board_idx > 7) ? 0 : media[board_idx];
@@ -824,45 +841,43 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
}
if (tp->full_duplex) {
- printk (KERN_INFO
- "%s: Media type forced to Full Duplex.\n",
- dev->name);
- mdio_write (dev, tp->phys[0], MII_ADVERTISE, ADVERTISE_FULL);
+ netdev_info(dev, "Media type forced to Full Duplex\n");
+ mdio_write(dev, tp->phys[0], MII_ADVERTISE, ADVERTISE_FULL);
tp->duplex_lock = 1;
}
- DPRINTK ("EXIT - returning 0\n");
+ DPRINTK("EXIT - returning 0\n");
return 0;
}
-static void __devexit netdrv_remove_one (struct pci_dev *pdev)
+static void __devexit netdrv_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata (pdev);
+ struct net_device *dev = pci_get_drvdata(pdev);
struct netdrv_private *np;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- assert (dev != NULL);
+ assert(dev != NULL);
np = netdev_priv(dev);
- assert (np != NULL);
+ assert(np != NULL);
- unregister_netdev (dev);
+ unregister_netdev(dev);
#ifndef USE_IO_OPS
- iounmap (np->mmio_addr);
+ iounmap(np->mmio_addr);
#endif /* !USE_IO_OPS */
- pci_release_regions (pdev);
+ pci_release_regions(pdev);
- free_netdev (dev);
+ free_netdev(dev);
- pci_set_drvdata (pdev, NULL);
+ pci_set_drvdata(pdev, NULL);
- pci_disable_device (pdev);
+ pci_disable_device(pdev);
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
@@ -870,63 +885,63 @@ static void __devexit netdrv_remove_one (struct pci_dev *pdev)
/* EEPROM_Ctrl bits. */
#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
-#define EE_CS 0x08 /* EEPROM chip select. */
+#define EE_CS 0x08 /* EEPROM chip select. */
#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
-#define EE_WRITE_0 0x00
-#define EE_WRITE_1 0x02
+#define EE_WRITE_0 0x00
+#define EE_WRITE_1 0x02
#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
-#define EE_ENB (0x80 | EE_CS)
+#define EE_ENB (0x80 | EE_CS)
/* Delay between EEPROM clock transitions.
No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
- */
+*/
#define eeprom_delay() readl(ee_addr)
/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD (5)
-#define EE_READ_CMD (6)
+#define EE_READ_CMD (6)
#define EE_ERASE_CMD (7)
-static int __devinit read_eeprom (void *ioaddr, int location, int addr_len)
+static int __devinit read_eeprom(void *ioaddr, int location, int addr_len)
{
int i;
unsigned retval = 0;
void *ee_addr = ioaddr + Cfg9346;
int read_cmd = location | (EE_READ_CMD << addr_len);
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- writeb (EE_ENB & ~EE_CS, ee_addr);
- writeb (EE_ENB, ee_addr);
- eeprom_delay ();
+ writeb(EE_ENB & ~EE_CS, ee_addr);
+ writeb(EE_ENB, ee_addr);
+ eeprom_delay();
/* Shift the read command bits out. */
for (i = 4 + addr_len; i >= 0; i--) {
int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
- writeb (EE_ENB | dataval, ee_addr);
- eeprom_delay ();
- writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
- eeprom_delay ();
+ writeb(EE_ENB | dataval, ee_addr);
+ eeprom_delay();
+ writeb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
}
- writeb (EE_ENB, ee_addr);
- eeprom_delay ();
+ writeb(EE_ENB, ee_addr);
+ eeprom_delay();
for (i = 16; i > 0; i--) {
- writeb (EE_ENB | EE_SHIFT_CLK, ee_addr);
- eeprom_delay ();
+ writeb(EE_ENB | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
retval =
- (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 :
- 0);
- writeb (EE_ENB, ee_addr);
- eeprom_delay ();
+ (retval << 1) | ((readb(ee_addr) & EE_DATA_READ) ? 1 :
+ 0);
+ writeb(EE_ENB, ee_addr);
+ eeprom_delay();
}
/* Terminate the EEPROM access. */
- writeb (~EE_CS, ee_addr);
- eeprom_delay ();
+ writeb(~EE_CS, ee_addr);
+ eeprom_delay();
- DPRINTK ("EXIT - returning %d\n", retval);
+ DPRINTK("EXIT - returning %d\n", retval);
return retval;
}
@@ -936,12 +951,12 @@ static int __devinit read_eeprom (void *ioaddr, int location, int addr_len)
The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
met by back-to-back PCI I/O cycles, but we insert a delay to avoid
"overclocking" issues. */
-#define MDIO_DIR 0x80
+#define MDIO_DIR 0x80
#define MDIO_DATA_OUT 0x04
#define MDIO_DATA_IN 0x02
-#define MDIO_CLK 0x01
-#define MDIO_WRITE0 (MDIO_DIR)
-#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
+#define MDIO_CLK 0x01
+#define MDIO_WRITE0 (MDIO_DIR)
+#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
#define mdio_delay() readb(mdio_addr)
@@ -959,24 +974,24 @@ static char mii_2_8139_map[8] = {
/* Syncronize the MII management interface by shifting 32 one bits out. */
-static void mdio_sync (void *mdio_addr)
+static void mdio_sync(void *mdio_addr)
{
int i;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
for (i = 32; i >= 0; i--) {
- writeb (MDIO_WRITE1, mdio_addr);
- mdio_delay ();
- writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr);
- mdio_delay ();
+ writeb(MDIO_WRITE1, mdio_addr);
+ mdio_delay();
+ writeb(MDIO_WRITE1 | MDIO_CLK, mdio_addr);
+ mdio_delay();
}
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
-static int mdio_read (struct net_device *dev, int phy_id, int location)
+static int mdio_read(struct net_device *dev, int phy_id, int location)
{
struct netdrv_private *tp = netdev_priv(dev);
void *mdio_addr = tp->mmio_addr + Config4;
@@ -984,97 +999,94 @@ static int mdio_read (struct net_device *dev, int phy_id, int location)
int retval = 0;
int i;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
if (phy_id > 31) { /* Really a 8139. Use internal registers. */
- DPRINTK ("EXIT after directly using 8139 internal regs\n");
+ DPRINTK("EXIT after directly using 8139 internal regs\n");
return location < 8 && mii_2_8139_map[location] ?
- readw (tp->mmio_addr + mii_2_8139_map[location]) : 0;
+ readw(tp->mmio_addr + mii_2_8139_map[location]) : 0;
}
- mdio_sync (mdio_addr);
+ mdio_sync(mdio_addr);
/* Shift the read command bits out. */
for (i = 15; i >= 0; i--) {
int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
- writeb (MDIO_DIR | dataval, mdio_addr);
- mdio_delay ();
- writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
- mdio_delay ();
+ writeb(MDIO_DIR | dataval, mdio_addr);
+ mdio_delay();
+ writeb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
+ mdio_delay();
}
/* Read the two transition, 16 data, and wire-idle bits. */
for (i = 19; i > 0; i--) {
- writeb (0, mdio_addr);
- mdio_delay ();
- retval =
- (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1
- : 0);
- writeb (MDIO_CLK, mdio_addr);
- mdio_delay ();
+ writeb(0, mdio_addr);
+ mdio_delay();
+ retval = ((retval << 1) | ((readb(mdio_addr) & MDIO_DATA_IN))
+ ? 1 : 0);
+ writeb(MDIO_CLK, mdio_addr);
+ mdio_delay();
}
- DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff);
+ DPRINTK("EXIT, returning %d\n", (retval >> 1) & 0xffff);
return (retval >> 1) & 0xffff;
}
-static void mdio_write (struct net_device *dev, int phy_id, int location,
- int value)
+static void mdio_write(struct net_device *dev, int phy_id, int location,
+ int value)
{
struct netdrv_private *tp = netdev_priv(dev);
void *mdio_addr = tp->mmio_addr + Config4;
int mii_cmd =
- (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
+ (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
int i;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
if (phy_id > 31) { /* Really a 8139. Use internal registers. */
if (location < 8 && mii_2_8139_map[location]) {
- writew (value,
- tp->mmio_addr + mii_2_8139_map[location]);
- readw (tp->mmio_addr + mii_2_8139_map[location]);
+ writew(value,
+ tp->mmio_addr + mii_2_8139_map[location]);
+ readw(tp->mmio_addr + mii_2_8139_map[location]);
}
- DPRINTK ("EXIT after directly using 8139 internal regs\n");
+ DPRINTK("EXIT after directly using 8139 internal regs\n");
return;
}
- mdio_sync (mdio_addr);
+ mdio_sync(mdio_addr);
/* Shift the command bits out. */
for (i = 31; i >= 0; i--) {
int dataval =
- (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
- writeb (dataval, mdio_addr);
- mdio_delay ();
- writeb (dataval | MDIO_CLK, mdio_addr);
- mdio_delay ();
+ (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+ writeb(dataval, mdio_addr);
+ mdio_delay();
+ writeb(dataval | MDIO_CLK, mdio_addr);
+ mdio_delay();
}
/* Clear out extra bits. */
for (i = 2; i > 0; i--) {
- writeb (0, mdio_addr);
- mdio_delay ();
- writeb (MDIO_CLK, mdio_addr);
- mdio_delay ();
+ writeb(0, mdio_addr);
+ mdio_delay();
+ writeb(MDIO_CLK, mdio_addr);
+ mdio_delay();
}
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
-static int netdrv_open (struct net_device *dev)
+static int netdrv_open(struct net_device *dev)
{
struct netdrv_private *tp = netdev_priv(dev);
int retval;
-#ifdef NETDRV_DEBUG
void *ioaddr = tp->mmio_addr;
-#endif
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- retval = request_irq (dev->irq, netdrv_interrupt, IRQF_SHARED, dev->name, dev);
+ retval = request_irq(dev->irq, netdrv_interrupt, IRQF_SHARED, dev->name, dev);
if (retval) {
- DPRINTK ("EXIT, returning %d\n", retval);
+ DPRINTK("EXIT, returning %d\n", retval);
return retval;
}
@@ -1092,7 +1104,7 @@ static int netdrv_open (struct net_device *dev)
pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
tp->rx_ring, tp->rx_ring_dma);
- DPRINTK ("EXIT, returning -ENOMEM\n");
+ DPRINTK("EXIT, returning -ENOMEM\n");
return -ENOMEM;
}
@@ -1100,109 +1112,108 @@ static int netdrv_open (struct net_device *dev)
tp->full_duplex = tp->duplex_lock;
tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
- netdrv_init_ring (dev);
- netdrv_hw_start (dev);
+ netdrv_init_ring(dev);
+ netdrv_hw_start(dev);
- DPRINTK ("%s: netdrv_open() ioaddr %#lx IRQ %d"
- " GP Pins %2.2x %s-duplex.\n",
- dev->name, pci_resource_start (tp->pci_dev, 1),
- dev->irq, NETDRV_R8 (MediaStatus),
- tp->full_duplex ? "full" : "half");
+ netdev_dbg(dev, "ioaddr %#llx IRQ %d GP Pins %02x %s-duplex\n",
+ (unsigned long long)pci_resource_start(tp->pci_dev, 1),
+ dev->irq, NETDRV_R8(MediaStatus),
+ tp->full_duplex ? "full" : "half");
/* Set the timer to switch to check for link beat and perhaps switch
to an alternate media type. */
- init_timer (&tp->timer);
+ init_timer(&tp->timer);
tp->timer.expires = jiffies + 3 * HZ;
tp->timer.data = (unsigned long) dev;
tp->timer.function = &netdrv_timer;
- add_timer (&tp->timer);
+ add_timer(&tp->timer);
- DPRINTK ("EXIT, returning 0\n");
+ DPRINTK("EXIT, returning 0\n");
return 0;
}
/* Start the hardware at open or resume. */
-static void netdrv_hw_start (struct net_device *dev)
+static void netdrv_hw_start(struct net_device *dev)
{
struct netdrv_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
u32 i;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
/* Soft reset the chip. */
- NETDRV_W8 (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear) | CmdReset);
- udelay (100);
+ NETDRV_W8(ChipCmd, (NETDRV_R8(ChipCmd) & ChipCmdClear) | CmdReset);
+ udelay(100);
/* Check that the chip has finished the reset. */
for (i = 1000; i > 0; i--)
- if ((NETDRV_R8 (ChipCmd) & CmdReset) == 0)
+ if ((NETDRV_R8(ChipCmd) & CmdReset) == 0)
break;
/* Restore our idea of the MAC address. */
- NETDRV_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
- NETDRV_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+ NETDRV_W32_F(MAC0 + 0, cpu_to_le32(*(u32 *)(dev->dev_addr + 0)));
+ NETDRV_W32_F(MAC0 + 4, cpu_to_le32(*(u32 *)(dev->dev_addr + 4)));
/* Must enable Tx/Rx before setting transfer thresholds! */
- NETDRV_W8_F (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear) |
- CmdRxEnb | CmdTxEnb);
+ NETDRV_W8_F(ChipCmd, (NETDRV_R8(ChipCmd) & ChipCmdClear) |
+ CmdRxEnb | CmdTxEnb);
i = netdrv_rx_config |
- (NETDRV_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
- NETDRV_W32_F (RxConfig, i);
+ (NETDRV_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+ NETDRV_W32_F(RxConfig, i);
/* Check this value: the documentation for IFG contradicts ifself. */
- NETDRV_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift));
+ NETDRV_W32(TxConfig, (TX_DMA_BURST << TxDMAShift));
/* unlock Config[01234] and BMCR register writes */
- NETDRV_W8_F (Cfg9346, Cfg9346_Unlock);
- udelay (10);
+ NETDRV_W8_F(Cfg9346, Cfg9346_Unlock);
+ udelay(10);
tp->cur_rx = 0;
/* Lock Config[01234] and BMCR register writes */
- NETDRV_W8_F (Cfg9346, Cfg9346_Lock);
- udelay (10);
+ NETDRV_W8_F(Cfg9346, Cfg9346_Lock);
+ udelay(10);
/* init Rx ring buffer DMA address */
- NETDRV_W32_F (RxBuf, tp->rx_ring_dma);
+ NETDRV_W32_F(RxBuf, tp->rx_ring_dma);
/* init Tx buffer DMA addresses */
for (i = 0; i < NUM_TX_DESC; i++)
- NETDRV_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs));
+ NETDRV_W32_F(TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs));
- NETDRV_W32_F (RxMissed, 0);
+ NETDRV_W32_F(RxMissed, 0);
- netdrv_set_rx_mode (dev);
+ netdrv_set_rx_mode(dev);
/* no early-rx interrupts */
- NETDRV_W16 (MultiIntr, NETDRV_R16 (MultiIntr) & MultiIntrClear);
+ NETDRV_W16(MultiIntr, NETDRV_R16(MultiIntr) & MultiIntrClear);
/* make sure RxTx has started */
- NETDRV_W8_F (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear) |
- CmdRxEnb | CmdTxEnb);
+ NETDRV_W8_F(ChipCmd, (NETDRV_R8(ChipCmd) & ChipCmdClear) |
+ CmdRxEnb | CmdTxEnb);
/* Enable all known interrupts by setting the interrupt mask. */
- NETDRV_W16_F (IntrMask, netdrv_intr_mask);
+ NETDRV_W16_F(IntrMask, netdrv_intr_mask);
- netif_start_queue (dev);
+ netif_start_queue(dev);
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void netdrv_init_ring (struct net_device *dev)
+static void netdrv_init_ring(struct net_device *dev)
{
struct netdrv_private *tp = netdev_priv(dev);
int i;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
tp->cur_rx = 0;
- atomic_set (&tp->cur_tx, 0);
- atomic_set (&tp->dirty_tx, 0);
+ atomic_set(&tp->cur_tx, 0);
+ atomic_set(&tp->dirty_tx, 0);
for (i = 0; i < NUM_TX_DESC; i++) {
tp->tx_info[i].skb = NULL;
@@ -1210,11 +1221,11 @@ static void netdrv_init_ring (struct net_device *dev)
tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
}
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
-static void netdrv_timer (unsigned long data)
+static void netdrv_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
struct netdrv_private *tp = netdev_priv(dev);
@@ -1222,58 +1233,54 @@ static void netdrv_timer (unsigned long data)
int next_tick = 60 * HZ;
int mii_lpa;
- mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);
+ mii_lpa = mdio_read(dev, tp->phys[0], MII_LPA);
if (!tp->duplex_lock && mii_lpa != 0xffff) {
int duplex = ((mii_lpa & LPA_100FULL) ||
- (mii_lpa & 0x01C0) == 0x0040);
+ (mii_lpa & 0x01C0) == 0x0040);
if (tp->full_duplex != duplex) {
tp->full_duplex = duplex;
- printk (KERN_INFO
- "%s: Setting %s-duplex based on MII #%d link"
- " partner ability of %4.4x.\n", dev->name,
- tp->full_duplex ? "full" : "half",
- tp->phys[0], mii_lpa);
- NETDRV_W8 (Cfg9346, Cfg9346_Unlock);
- NETDRV_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
- NETDRV_W8 (Cfg9346, Cfg9346_Lock);
+ netdev_info(dev, "Setting %s-duplex based on MII #%d link partner ability of %04x\n",
+ tp->full_duplex ? "full" : "half",
+ tp->phys[0], mii_lpa);
+ NETDRV_W8(Cfg9346, Cfg9346_Unlock);
+ NETDRV_W8(Config1, tp->full_duplex ? 0x60 : 0x20);
+ NETDRV_W8(Cfg9346, Cfg9346_Lock);
}
}
- DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",
- dev->name, NETDRV_R16 (NWayLPAR));
- DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x"
- " RxStatus %4.4x.\n", dev->name,
- NETDRV_R16 (IntrMask),
- NETDRV_R16 (IntrStatus),
- NETDRV_R32 (RxEarlyStatus));
- DPRINTK ("%s: Chip config %2.2x %2.2x.\n",
- dev->name, NETDRV_R8 (Config0),
- NETDRV_R8 (Config1));
+ netdev_dbg(dev, "Media selection tick, Link partner %04x\n",
+ NETDRV_R16(NWayLPAR));
+ netdev_dbg(dev, "Other registers are IntMask %04x IntStatus %04x RxStatus %04lx\n",
+ NETDRV_R16(IntrMask),
+ NETDRV_R16(IntrStatus),
+ NETDRV_R32(RxEarlyStatus));
+ netdev_dbg(dev, "Chip config %02x %02x\n",
+ NETDRV_R8(Config0), NETDRV_R8(Config1));
tp->timer.expires = jiffies + next_tick;
- add_timer (&tp->timer);
+ add_timer(&tp->timer);
}
-static void netdrv_tx_clear (struct net_device *dev)
+static void netdrv_tx_clear(struct net_device *dev)
{
int i;
struct netdrv_private *tp = netdev_priv(dev);
- atomic_set (&tp->cur_tx, 0);
- atomic_set (&tp->dirty_tx, 0);
+ atomic_set(&tp->cur_tx, 0);
+ atomic_set(&tp->dirty_tx, 0);
/* Dump the unsent Tx packets. */
for (i = 0; i < NUM_TX_DESC; i++) {
struct ring_info *rp = &tp->tx_info[i];
if (rp->mapping != 0) {
- pci_unmap_single (tp->pci_dev, rp->mapping,
- rp->skb->len, PCI_DMA_TODEVICE);
+ pci_unmap_single(tp->pci_dev, rp->mapping,
+ rp->skb->len, PCI_DMA_TODEVICE);
rp->mapping = 0;
}
if (rp->skb) {
- dev_kfree_skb (rp->skb);
+ dev_kfree_skb(rp->skb);
rp->skb = NULL;
dev->stats.tx_dropped++;
}
@@ -1281,7 +1288,7 @@ static void netdrv_tx_clear (struct net_device *dev)
}
-static void netdrv_tx_timeout (struct net_device *dev)
+static void netdrv_tx_timeout(struct net_device *dev)
{
struct netdrv_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
@@ -1289,96 +1296,95 @@ static void netdrv_tx_timeout (struct net_device *dev)
u8 tmp8;
unsigned long flags;
- DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x "
- "media %2.2x.\n", dev->name,
- NETDRV_R8 (ChipCmd),
- NETDRV_R16 (IntrStatus),
- NETDRV_R8 (MediaStatus));
+ netdev_dbg(dev, "Transmit timeout, status %02x %04x media %02x\n",
+ NETDRV_R8(ChipCmd),
+ NETDRV_R16(IntrStatus),
+ NETDRV_R8(MediaStatus));
/* disable Tx ASAP, if not already */
- tmp8 = NETDRV_R8 (ChipCmd);
+ tmp8 = NETDRV_R8(ChipCmd);
if (tmp8 & CmdTxEnb)
- NETDRV_W8 (ChipCmd, tmp8 & ~CmdTxEnb);
+ NETDRV_W8(ChipCmd, tmp8 & ~CmdTxEnb);
/* Disable interrupts by clearing the interrupt mask. */
- NETDRV_W16 (IntrMask, 0x0000);
+ NETDRV_W16(IntrMask, 0x0000);
/* Emit info to figure out what went wrong. */
- printk (KERN_DEBUG "%s: Tx queue start entry %d dirty entry %d.\n",
- dev->name, atomic_read (&tp->cur_tx),
- atomic_read (&tp->dirty_tx));
+ netdev_dbg(dev, "Tx queue start entry %d dirty entry %d\n",
+ atomic_read(&tp->cur_tx),
+ atomic_read(&tp->dirty_tx));
for (i = 0; i < NUM_TX_DESC; i++)
- printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n",
- dev->name, i, NETDRV_R32 (TxStatus0 + (i * 4)),
- i == atomic_read (&tp->dirty_tx) % NUM_TX_DESC ?
- " (queue head)" : "");
+ netdev_dbg(dev, "Tx descriptor %d is %08lx%s\n",
+ i, NETDRV_R32(TxStatus0 + (i * 4)),
+ i == atomic_read(&tp->dirty_tx) % NUM_TX_DESC ?
+ "(queue head)" : "");
/* Stop a shared interrupt from scavenging while we are. */
- spin_lock_irqsave (&tp->lock, flags);
+ spin_lock_irqsave(&tp->lock, flags);
- netdrv_tx_clear (dev);
+ netdrv_tx_clear(dev);
- spin_unlock_irqrestore (&tp->lock, flags);
+ spin_unlock_irqrestore(&tp->lock, flags);
/* ...and finally, reset everything */
- netdrv_hw_start (dev);
+ netdrv_hw_start(dev);
- netif_wake_queue (dev);
+ netif_wake_queue(dev);
}
-static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev)
+static int netdrv_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct netdrv_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
int entry;
/* Calculate the next Tx descriptor entry. */
- entry = atomic_read (&tp->cur_tx) % NUM_TX_DESC;
+ entry = atomic_read(&tp->cur_tx) % NUM_TX_DESC;
- assert (tp->tx_info[entry].skb == NULL);
- assert (tp->tx_info[entry].mapping == 0);
+ assert(tp->tx_info[entry].skb == NULL);
+ assert(tp->tx_info[entry].mapping == 0);
tp->tx_info[entry].skb = skb;
/* tp->tx_info[entry].mapping = 0; */
skb_copy_from_linear_data(skb, tp->tx_buf[entry], skb->len);
/* Note: the chip doesn't have auto-pad! */
- NETDRV_W32 (TxStatus0 + (entry * sizeof(u32)),
- tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
+ NETDRV_W32(TxStatus0 + (entry * sizeof(u32)),
+ tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
dev->trans_start = jiffies;
- atomic_inc (&tp->cur_tx);
- if ((atomic_read (&tp->cur_tx) - atomic_read (&tp->dirty_tx)) >= NUM_TX_DESC)
- netif_stop_queue (dev);
+ atomic_inc(&tp->cur_tx);
+ if ((atomic_read(&tp->cur_tx) - atomic_read(&tp->dirty_tx)) >= NUM_TX_DESC)
+ netif_stop_queue(dev);
- DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",
- dev->name, skb->data, skb->len, entry);
+ netdev_dbg(dev, "Queued Tx packet at %p size %u to slot %d\n",
+ skb->data, skb->len, entry);
return NETDEV_TX_OK;
}
-static void netdrv_tx_interrupt (struct net_device *dev,
- struct netdrv_private *tp,
- void *ioaddr)
+static void netdrv_tx_interrupt(struct net_device *dev,
+ struct netdrv_private *tp,
+ void *ioaddr)
{
int cur_tx, dirty_tx, tx_left;
- assert (dev != NULL);
- assert (tp != NULL);
- assert (ioaddr != NULL);
+ assert(dev != NULL);
+ assert(tp != NULL);
+ assert(ioaddr != NULL);
- dirty_tx = atomic_read (&tp->dirty_tx);
+ dirty_tx = atomic_read(&tp->dirty_tx);
- cur_tx = atomic_read (&tp->cur_tx);
+ cur_tx = atomic_read(&tp->cur_tx);
tx_left = cur_tx - dirty_tx;
while (tx_left > 0) {
int entry = dirty_tx % NUM_TX_DESC;
int txstatus;
- txstatus = NETDRV_R32 (TxStatus0 + (entry * sizeof (u32)));
+ txstatus = NETDRV_R32(TxStatus0 + (entry * sizeof(u32)));
if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
break; /* It still hasn't been Txed */
@@ -1386,12 +1392,12 @@ static void netdrv_tx_interrupt (struct net_device *dev,
/* Note: TxCarrierLost is always asserted at 100mbps. */
if (txstatus & (TxOutOfWindow | TxAborted)) {
/* There was an major error, log it. */
- DPRINTK ("%s: Transmit error, Tx status %8.8x.\n",
- dev->name, txstatus);
+ netdev_dbg(dev, "Transmit error, Tx status %#08x\n",
+ txstatus);
dev->stats.tx_errors++;
if (txstatus & TxAborted) {
dev->stats.tx_aborted_errors++;
- NETDRV_W32 (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift));
+ NETDRV_W32(TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift));
}
if (txstatus & TxCarrierLost)
dev->stats.tx_carrier_errors++;
@@ -1417,48 +1423,45 @@ static void netdrv_tx_interrupt (struct net_device *dev,
PCI_DMA_TODEVICE);
tp->tx_info[entry].mapping = 0;
}
- dev_kfree_skb_irq (tp->tx_info[entry].skb);
+ dev_kfree_skb_irq(tp->tx_info[entry].skb);
tp->tx_info[entry].skb = NULL;
dirty_tx++;
if (dirty_tx < 0) { /* handle signed int overflow */
- atomic_sub (cur_tx, &tp->cur_tx); /* XXX racy? */
+ atomic_sub(cur_tx, &tp->cur_tx); /* XXX racy? */
dirty_tx = cur_tx - tx_left + 1;
}
- if (netif_queue_stopped (dev))
- netif_wake_queue (dev);
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
- cur_tx = atomic_read (&tp->cur_tx);
+ cur_tx = atomic_read(&tp->cur_tx);
tx_left = cur_tx - dirty_tx;
}
#ifndef NETDRV_NDEBUG
- if (atomic_read (&tp->cur_tx) - dirty_tx > NUM_TX_DESC) {
- printk (KERN_ERR
- "%s: Out-of-sync dirty pointer, %d vs. %d.\n",
- dev->name, dirty_tx, atomic_read (&tp->cur_tx));
+ if (atomic_read(&tp->cur_tx) - dirty_tx > NUM_TX_DESC) {
+ netdev_err(dev, "Out-of-sync dirty pointer, %d vs. %d\n",
+ dirty_tx, atomic_read(&tp->cur_tx));
dirty_tx += NUM_TX_DESC;
}
#endif /* NETDRV_NDEBUG */
- atomic_set (&tp->dirty_tx, dirty_tx);
+ atomic_set(&tp->dirty_tx, dirty_tx);
}
/* TODO: clean this up! Rx reset need not be this intensive */
-static void netdrv_rx_err (u32 rx_status, struct net_device *dev,
- struct netdrv_private *tp, void *ioaddr)
+static void netdrv_rx_err(u32 rx_status, struct net_device *dev,
+ struct netdrv_private *tp, void *ioaddr)
{
u8 tmp8;
int tmp_work = 1000;
- DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n",
- dev->name, rx_status);
- if (rx_status & RxTooLong) {
- DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",
- dev->name, rx_status);
+ netdev_dbg(dev, "Ethernet frame had errors, status %08x\n", rx_status);
+ if (rx_status & RxTooLong)
+ netdev_dbg(dev, "Oversized Ethernet frame, status %04x!\n",
+ rx_status);
/* A.C.: The chip hangs here. */
- }
dev->stats.rx_errors++;
if (rx_status & (RxBadSymbol | RxBadAlign))
dev->stats.rx_frame_errors++;
@@ -1466,56 +1469,55 @@ static void netdrv_rx_err (u32 rx_status, struct net_device *dev,
dev->stats.rx_length_errors++;
if (rx_status & RxCRCErr)
dev->stats.rx_crc_errors++;
- /* Reset the receiver, based on RealTek recommendation. (Bug?) */
+ /* Reset the receiver, based on RealTek recommendation.(Bug?) */
tp->cur_rx = 0;
/* disable receive */
- tmp8 = NETDRV_R8 (ChipCmd) & ChipCmdClear;
- NETDRV_W8_F (ChipCmd, tmp8 | CmdTxEnb);
+ tmp8 = NETDRV_R8(ChipCmd) & ChipCmdClear;
+ NETDRV_W8_F(ChipCmd, tmp8 | CmdTxEnb);
/* A.C.: Reset the multicast list. */
- netdrv_set_rx_mode (dev);
+ netdrv_set_rx_mode(dev);
/* XXX potentially temporary hack to
* restart hung receiver */
while (--tmp_work > 0) {
- tmp8 = NETDRV_R8 (ChipCmd);
+ tmp8 = NETDRV_R8(ChipCmd);
if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))
break;
- NETDRV_W8_F (ChipCmd,
- (tmp8 & ChipCmdClear) | CmdRxEnb | CmdTxEnb);
+ NETDRV_W8_F(ChipCmd,
+ (tmp8 & ChipCmdClear) | CmdRxEnb | CmdTxEnb);
}
/* G.S.: Re-enable receiver */
/* XXX temporary hack to work around receiver hang */
- netdrv_set_rx_mode (dev);
+ netdrv_set_rx_mode(dev);
if (tmp_work <= 0)
- printk (KERN_WARNING PFX "tx/rx enable wait too long\n");
+ netdev_warn(dev, "tx/rx enable wait too long\n");
}
/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
field alignments and semantics. */
-static void netdrv_rx_interrupt (struct net_device *dev,
- struct netdrv_private *tp, void *ioaddr)
+static void netdrv_rx_interrupt(struct net_device *dev,
+ struct netdrv_private *tp, void *ioaddr)
{
unsigned char *rx_ring;
u16 cur_rx;
- assert (dev != NULL);
- assert (tp != NULL);
- assert (ioaddr != NULL);
+ assert(dev != NULL);
+ assert(tp != NULL);
+ assert(ioaddr != NULL);
rx_ring = tp->rx_ring;
cur_rx = tp->cur_rx;
- DPRINTK ("%s: In netdrv_rx(), current %4.4x BufAddr %4.4x,"
- " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
- NETDRV_R16 (RxBufAddr),
- NETDRV_R16 (RxBufPtr), NETDRV_R8 (ChipCmd));
+ netdev_dbg(dev, "In netdrv_rx(), current %04x BufAddr %04x, free to %04x, Cmd %02x\n",
+ cur_rx, NETDRV_R16(RxBufAddr),
+ NETDRV_R16(RxBufPtr), NETDRV_R8(ChipCmd));
- while ((NETDRV_R8 (ChipCmd) & RxBufEmpty) == 0) {
+ while ((NETDRV_R8(ChipCmd) & RxBufEmpty) == 0) {
int ring_offset = cur_rx % RX_BUF_LEN;
u32 rx_status;
unsigned int rx_size;
@@ -1523,32 +1525,25 @@ static void netdrv_rx_interrupt (struct net_device *dev,
struct sk_buff *skb;
/* read size+status of next frame from DMA ring buffer */
- rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
+ rx_status = le32_to_cpu(*(u32 *)(rx_ring + ring_offset));
rx_size = rx_status >> 16;
pkt_size = rx_size - 4;
- DPRINTK ("%s: netdrv_rx() status %4.4x, size %4.4x,"
- " cur %4.4x.\n", dev->name, rx_status,
- rx_size, cur_rx);
+ netdev_dbg(dev, "netdrv_rx() status %04x, size %04x, cur %04x\n",
+ rx_status, rx_size, cur_rx);
#if defined(NETDRV_DEBUG) && (NETDRV_DEBUG > 2)
- {
- int i;
- DPRINTK ("%s: Frame contents ", dev->name);
- for (i = 0; i < 70; i++)
- printk (" %2.2x",
- rx_ring[ring_offset + i]);
- printk (".\n");
- }
+ print_hex_dump_bytes("Frame contents: ", HEX_DUMP_OFFSET,
+ &rx_ring[ring_offset], 70);
#endif
/* If Rx err or invalid rx_size/rx_status received
- * (which happens if we get lost in the ring),
+ *(which happens if we get lost in the ring),
* Rx process gets reset, so we abort any further
* Rx processing.
*/
if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
(!(rx_status & RxStatusOK))) {
- netdrv_rx_err (rx_status, dev, tp, ioaddr);
+ netdrv_rx_err(rx_status, dev, tp, ioaddr);
return;
}
@@ -1561,71 +1556,67 @@ static void netdrv_rx_interrupt (struct net_device *dev,
* drop packets here under memory pressure.
*/
- skb = dev_alloc_skb (pkt_size + 2);
+ skb = dev_alloc_skb(pkt_size + 2);
if (skb) {
- skb_reserve (skb, 2); /* 16 byte align the IP fields. */
+ skb_reserve(skb, 2); /* 16 byte align the IP fields. */
- skb_copy_to_linear_data (skb, &rx_ring[ring_offset + 4], pkt_size);
- skb_put (skb, pkt_size);
+ skb_copy_to_linear_data(skb, &rx_ring[ring_offset + 4], pkt_size);
+ skb_put(skb, pkt_size);
- skb->protocol = eth_type_trans (skb, dev);
- netif_rx (skb);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
dev->stats.rx_bytes += pkt_size;
dev->stats.rx_packets++;
} else {
- printk (KERN_WARNING
- "%s: Memory squeeze, dropping packet.\n",
- dev->name);
+ netdev_warn(dev, "Memory squeeze, dropping packet\n");
dev->stats.rx_dropped++;
}
cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
- NETDRV_W16_F (RxBufPtr, cur_rx - 16);
+ NETDRV_W16_F(RxBufPtr, cur_rx - 16);
}
- DPRINTK ("%s: Done netdrv_rx(), current %4.4x BufAddr %4.4x,"
- " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
- NETDRV_R16 (RxBufAddr),
- NETDRV_R16 (RxBufPtr), NETDRV_R8 (ChipCmd));
+ netdev_dbg(dev, "Done netdrv_rx(), current %04x BufAddr %04x, free to %04x, Cmd %02x\n",
+ cur_rx, NETDRV_R16(RxBufAddr),
+ NETDRV_R16(RxBufPtr), NETDRV_R8(ChipCmd));
tp->cur_rx = cur_rx;
}
-static void netdrv_weird_interrupt (struct net_device *dev,
- struct netdrv_private *tp,
- void *ioaddr,
- int status, int link_changed)
+static void netdrv_weird_interrupt(struct net_device *dev,
+ struct netdrv_private *tp,
+ void *ioaddr,
+ int status, int link_changed)
{
- printk (KERN_DEBUG "%s: Abnormal interrupt, status %8.8x.\n",
- dev->name, status);
+ netdev_printk(KERN_DEBUG, dev, "Abnormal interrupt, status %08x\n",
+ status);
- assert (dev != NULL);
- assert (tp != NULL);
- assert (ioaddr != NULL);
+ assert(dev != NULL);
+ assert(tp != NULL);
+ assert(ioaddr != NULL);
/* Update the error count. */
- dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
- NETDRV_W32 (RxMissed, 0);
+ dev->stats.rx_missed_errors += NETDRV_R32(RxMissed);
+ NETDRV_W32(RxMissed, 0);
if ((status & RxUnderrun) && link_changed &&
(tp->drv_flags & HAS_LNK_CHNG)) {
/* Really link-change on new chips. */
- int lpar = NETDRV_R16 (NWayLPAR);
+ int lpar = NETDRV_R16(NWayLPAR);
int duplex = ((lpar & 0x0100) || (lpar & 0x01C0) == 0x0040 ||
- tp->duplex_lock);
+ tp->duplex_lock);
if (tp->full_duplex != duplex) {
tp->full_duplex = duplex;
- NETDRV_W8 (Cfg9346, Cfg9346_Unlock);
- NETDRV_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
- NETDRV_W8 (Cfg9346, Cfg9346_Lock);
+ NETDRV_W8(Cfg9346, Cfg9346_Unlock);
+ NETDRV_W8(Config1, tp->full_duplex ? 0x60 : 0x20);
+ NETDRV_W8(Cfg9346, Cfg9346_Lock);
}
status &= ~RxUnderrun;
}
/* XXX along with netdrv_rx_err, are we double-counting errors? */
- if (status &
- (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
+ if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
dev->stats.rx_errors++;
if (status & (PCSTimeout))
@@ -1634,22 +1625,21 @@ static void netdrv_weird_interrupt (struct net_device *dev,
dev->stats.rx_fifo_errors++;
if (status & RxOverflow) {
dev->stats.rx_over_errors++;
- tp->cur_rx = NETDRV_R16 (RxBufAddr) % RX_BUF_LEN;
- NETDRV_W16_F (RxBufPtr, tp->cur_rx - 16);
+ tp->cur_rx = NETDRV_R16(RxBufAddr) % RX_BUF_LEN;
+ NETDRV_W16_F(RxBufPtr, tp->cur_rx - 16);
}
if (status & PCIErr) {
u16 pci_cmd_status;
- pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status);
+ pci_read_config_word(tp->pci_dev, PCI_STATUS, &pci_cmd_status);
- printk (KERN_ERR "%s: PCI Bus error %4.4x.\n",
- dev->name, pci_cmd_status);
+ netdev_err(dev, "PCI Bus error %04x\n", pci_cmd_status);
}
}
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t netdrv_interrupt (int irq, void *dev_instance)
+static irqreturn_t netdrv_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct netdrv_private *tp = netdev_priv(dev);
@@ -1658,22 +1648,21 @@ static irqreturn_t netdrv_interrupt (int irq, void *dev_instance)
int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */
int handled = 0;
- spin_lock (&tp->lock);
+ spin_lock(&tp->lock);
do {
- status = NETDRV_R16 (IntrStatus);
+ status = NETDRV_R16(IntrStatus);
- /* h/w no longer present (hotplug?) or major error, bail */
+ /* h/w no longer present(hotplug?) or major error, bail */
if (status == 0xFFFF)
break;
handled = 1;
/* Acknowledge all of the current interrupt sources ASAP */
- NETDRV_W16_F (IntrStatus, status);
+ NETDRV_W16_F(IntrStatus, status);
- DPRINTK ("%s: interrupt status=%#4.4x new intstat=%#4.4x.\n",
- dev->name, status,
- NETDRV_R16 (IntrStatus));
+ netdev_dbg(dev, "interrupt status=%#04x new intstat=%#04x\n",
+ status, NETDRV_R16(IntrStatus));
if ((status &
(PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
@@ -1682,69 +1671,67 @@ static irqreturn_t netdrv_interrupt (int irq, void *dev_instance)
/* Check uncommon events with one test. */
if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
- RxFIFOOver | TxErr | RxErr))
- netdrv_weird_interrupt (dev, tp, ioaddr,
- status, link_changed);
+ RxFIFOOver | TxErr | RxErr))
+ netdrv_weird_interrupt(dev, tp, ioaddr,
+ status, link_changed);
if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */
- netdrv_rx_interrupt (dev, tp, ioaddr);
+ netdrv_rx_interrupt(dev, tp, ioaddr);
if (status & (TxOK | TxErr))
- netdrv_tx_interrupt (dev, tp, ioaddr);
+ netdrv_tx_interrupt(dev, tp, ioaddr);
boguscnt--;
} while (boguscnt > 0);
if (boguscnt <= 0) {
- printk (KERN_WARNING
- "%s: Too much work at interrupt, "
- "IntrStatus=0x%4.4x.\n", dev->name,
- status);
+ netdev_warn(dev, "Too much work at interrupt, IntrStatus=%#04x\n",
+ status);
/* Clear all interrupt sources. */
- NETDRV_W16 (IntrStatus, 0xffff);
+ NETDRV_W16(IntrStatus, 0xffff);
}
- spin_unlock (&tp->lock);
+ spin_unlock(&tp->lock);
- DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
- dev->name, NETDRV_R16 (IntrStatus));
+ netdev_dbg(dev, "exiting interrupt, intr_status=%#04x\n",
+ NETDRV_R16(IntrStatus));
return IRQ_RETVAL(handled);
}
-static int netdrv_close (struct net_device *dev)
+static int netdrv_close(struct net_device *dev)
{
struct netdrv_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
unsigned long flags;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- netif_stop_queue (dev);
+ netif_stop_queue(dev);
- DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n",
- dev->name, NETDRV_R16 (IntrStatus));
+ netdev_dbg(dev, "Shutting down ethercard, status was %#04x\n",
+ NETDRV_R16(IntrStatus));
- del_timer_sync (&tp->timer);
+ del_timer_sync(&tp->timer);
- spin_lock_irqsave (&tp->lock, flags);
+ spin_lock_irqsave(&tp->lock, flags);
/* Stop the chip's Tx and Rx DMA processes. */
- NETDRV_W8 (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear));
+ NETDRV_W8(ChipCmd, (NETDRV_R8(ChipCmd) & ChipCmdClear));
/* Disable interrupts by clearing the interrupt mask. */
- NETDRV_W16 (IntrMask, 0x0000);
+ NETDRV_W16(IntrMask, 0x0000);
/* Update the error counts. */
- dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
- NETDRV_W32 (RxMissed, 0);
+ dev->stats.rx_missed_errors += NETDRV_R32(RxMissed);
+ NETDRV_W32(RxMissed, 0);
- spin_unlock_irqrestore (&tp->lock, flags);
+ spin_unlock_irqrestore(&tp->lock, flags);
- free_irq (dev->irq, dev);
+ free_irq(dev->irq, dev);
- netdrv_tx_clear (dev);
+ netdrv_tx_clear(dev);
pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
tp->rx_ring, tp->rx_ring_dma);
@@ -1754,23 +1741,23 @@ static int netdrv_close (struct net_device *dev)
tp->tx_bufs = NULL;
/* Green! Put the chip in low-power mode. */
- NETDRV_W8 (Cfg9346, Cfg9346_Unlock);
- NETDRV_W8 (Config1, 0x03);
- NETDRV_W8 (Cfg9346, Cfg9346_Lock);
+ NETDRV_W8(Cfg9346, Cfg9346_Unlock);
+ NETDRV_W8(Config1, 0x03);
+ NETDRV_W8(Cfg9346, Cfg9346_Lock);
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
return 0;
}
-static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+static int netdrv_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct netdrv_private *tp = netdev_priv(dev);
struct mii_ioctl_data *data = if_mii(rq);
unsigned long flags;
int rc = 0;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
switch (cmd) {
case SIOCGMIIPHY: /* Get address of MII PHY in use. */
@@ -1778,15 +1765,15 @@ static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
/* Fall Through */
case SIOCGMIIREG: /* Read MII PHY register. */
- spin_lock_irqsave (&tp->lock, flags);
- data->val_out = mdio_read (dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
- spin_unlock_irqrestore (&tp->lock, flags);
+ spin_lock_irqsave(&tp->lock, flags);
+ data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
+ spin_unlock_irqrestore(&tp->lock, flags);
break;
case SIOCSMIIREG: /* Write MII PHY register. */
- spin_lock_irqsave (&tp->lock, flags);
- mdio_write (dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
- spin_unlock_irqrestore (&tp->lock, flags);
+ spin_lock_irqsave(&tp->lock, flags);
+ mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
+ spin_unlock_irqrestore(&tp->lock, flags);
break;
default:
@@ -1794,43 +1781,43 @@ static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
break;
}
- DPRINTK ("EXIT, returning %d\n", rc);
+ DPRINTK("EXIT, returning %d\n", rc);
return rc;
}
/* Set or clear the multicast filter for this adaptor.
This routine is not state sensitive and need not be SMP locked. */
-static void netdrv_set_rx_mode (struct net_device *dev)
+static void netdrv_set_rx_mode(struct net_device *dev)
{
struct netdrv_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
u32 mc_filter[2]; /* Multicast hash filter */
- int i, rx_mode;
+ int rx_mode;
u32 tmp;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- DPRINTK ("%s: netdrv_set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
- dev->name, dev->flags, NETDRV_R32 (RxConfig));
+ netdev_dbg(dev, "%s(%04x) done -- Rx config %08lx\n",
+ __func__, dev->flags, NETDRV_R32(RxConfig));
/* Note: do not reorder, GCC is clever about common statements. */
if (dev->flags & IFF_PROMISC) {
rx_mode =
- AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
- AcceptAllPhys;
+ AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+ AcceptAllPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
- } else if ((dev->mc_count > multicast_filter_limit) ||
+ } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
(dev->flags & IFF_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
} else {
struct dev_mc_list *mclist;
+
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
@@ -1838,66 +1825,66 @@ static void netdrv_set_rx_mode (struct net_device *dev)
}
/* if called from irq handler, lock already acquired */
- if (!in_irq ())
- spin_lock_irq (&tp->lock);
+ if (!in_irq())
+ spin_lock_irq(&tp->lock);
/* We can safely update without stopping the chip. */
tmp = netdrv_rx_config | rx_mode |
- (NETDRV_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
- NETDRV_W32_F (RxConfig, tmp);
- NETDRV_W32_F (MAR0 + 0, mc_filter[0]);
- NETDRV_W32_F (MAR0 + 4, mc_filter[1]);
+ (NETDRV_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+ NETDRV_W32_F(RxConfig, tmp);
+ NETDRV_W32_F(MAR0 + 0, mc_filter[0]);
+ NETDRV_W32_F(MAR0 + 4, mc_filter[1]);
- if (!in_irq ())
- spin_unlock_irq (&tp->lock);
+ if (!in_irq())
+ spin_unlock_irq(&tp->lock);
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
#ifdef CONFIG_PM
-static int netdrv_suspend (struct pci_dev *pdev, pm_message_t state)
+static int netdrv_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct net_device *dev = pci_get_drvdata (pdev);
+ struct net_device *dev = pci_get_drvdata(pdev);
struct netdrv_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
unsigned long flags;
if (!netif_running(dev))
return 0;
- netif_device_detach (dev);
+ netif_device_detach(dev);
- spin_lock_irqsave (&tp->lock, flags);
+ spin_lock_irqsave(&tp->lock, flags);
/* Disable interrupts, stop Tx and Rx. */
- NETDRV_W16 (IntrMask, 0x0000);
- NETDRV_W8 (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear));
+ NETDRV_W16(IntrMask, 0x0000);
+ NETDRV_W8(ChipCmd, (NETDRV_R8(ChipCmd) & ChipCmdClear));
/* Update the error counts. */
- dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
- NETDRV_W32 (RxMissed, 0);
+ dev->stats.rx_missed_errors += NETDRV_R32(RxMissed);
+ NETDRV_W32(RxMissed, 0);
- spin_unlock_irqrestore (&tp->lock, flags);
+ spin_unlock_irqrestore(&tp->lock, flags);
- pci_save_state (pdev);
- pci_set_power_state (pdev, PCI_D3hot);
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
-static int netdrv_resume (struct pci_dev *pdev)
+static int netdrv_resume(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata (pdev);
+ struct net_device *dev = pci_get_drvdata(pdev);
/*struct netdrv_private *tp = netdev_priv(dev);*/
if (!netif_running(dev))
return 0;
- pci_set_power_state (pdev, PCI_D0);
- pci_restore_state (pdev);
- netif_device_attach (dev);
- netdrv_hw_start (dev);
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ netif_device_attach(dev);
+ netdrv_hw_start(dev);
return 0;
}
@@ -1917,7 +1904,7 @@ static struct pci_driver netdrv_pci_driver = {
};
-static int __init netdrv_init_module (void)
+static int __init netdrv_init_module(void)
{
/* when a module, this is printed whether or not devices are found in probe */
#ifdef MODULE
@@ -1927,9 +1914,9 @@ static int __init netdrv_init_module (void)
}
-static void __exit netdrv_cleanup_module (void)
+static void __exit netdrv_cleanup_module(void)
{
- pci_unregister_driver (&netdrv_pci_driver);
+ pci_unregister_driver(&netdrv_pci_driver);
}
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 98938ea9e0bd..3d1d3a7b7ed3 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -1148,7 +1148,7 @@ static void set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC)
outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
ioaddr + EL3_CMD);
- else if (dev->mc_count || (dev->flags & IFF_ALLMULTI))
+ else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
else
outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 322e11df0097..091e0b00043e 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -886,7 +886,7 @@ static void set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC)
opts |= RxMulticast | RxProm;
- else if (dev->mc_count || (dev->flags & IFF_ALLMULTI))
+ else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
opts |= RxMulticast;
outw(opts, ioaddr + EL3_CMD);
}
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index d431b59e7d11..09291e60d309 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -779,6 +779,7 @@ static struct pcmcia_device_id axnet_ids[] = {
PCMCIA_DEVICE_PROD_ID12("CNet", "CNF301", 0xbc477dde, 0x78c5f40b),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440f, 0x436768c5),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x5261440f, 0x730df72e),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXM", 0x5261440f, 0x3abbd061),
PCMCIA_DEVICE_PROD_ID12("Dynalink", "L100C16", 0x55632fd5, 0x66bc2a90),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "ETXPCM", 0x547e66dc, 0x233adac2),
PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8),
@@ -1065,14 +1066,11 @@ static netdev_tx_t axnet_start_xmit(struct sk_buff *skb,
spin_lock_irqsave(&ei_local->page_lock, flags);
outb_p(0x00, e8390_base + EN0_IMR);
- spin_unlock_irqrestore(&ei_local->page_lock, flags);
/*
* Slow phase with lock held.
*/
- spin_lock_irqsave(&ei_local->page_lock, flags);
-
ei_local->irqlock = 1;
send_length = max(length, ETH_ZLEN);
@@ -1628,8 +1626,7 @@ static inline void make_mc_bits(u8 *bits, struct net_device *dev)
struct dev_mc_list *dmi;
u32 crc;
- for (dmi=dev->mc_list; dmi; dmi=dmi->next) {
-
+ netdev_for_each_mc_addr(dmi, dev) {
crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
/*
* The 8390 uses the 6 most significant bits of the
@@ -1655,7 +1652,7 @@ static void do_set_multicast_list(struct net_device *dev)
if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
memset(ei_local->mcfilter, 0, 8);
- if (dev->mc_list)
+ if (!netdev_mc_empty(dev))
make_mc_bits(ei_local->mcfilter, dev);
} else {
/* set to accept-all */
@@ -1671,7 +1668,7 @@ static void do_set_multicast_list(struct net_device *dev)
if(dev->flags&IFF_PROMISC)
outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
- else if(dev->flags&IFF_ALLMULTI || dev->mc_list)
+ else if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev))
outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
else
outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 813aca3fc433..b9dc80b9d04a 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -717,6 +717,7 @@ static struct pcmcia_device_id fmvj18x_ids[] = {
PCMCIA_PFC_DEVICE_PROD_ID12(0, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0d0a),
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a),
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0e01),
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0a05),
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x1101),
PCMCIA_DEVICE_NULL,
@@ -1186,22 +1187,20 @@ static void set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC) {
memset(mc_filter, 0xff, sizeof(mc_filter));
outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */
- } else if (dev->mc_count > MC_FILTERBREAK ||
+ } else if (netdev_mc_count(dev) > MC_FILTERBREAK ||
(dev->flags & IFF_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */
memset(mc_filter, 0xff, sizeof(mc_filter));
outb(2, ioaddr + RX_MODE); /* Use normal mode. */
- } else if (dev->mc_count == 0) {
+ } else if (netdev_mc_empty(dev)) {
memset(mc_filter, 0x00, sizeof(mc_filter));
outb(1, ioaddr + RX_MODE); /* Ignore almost all multicasts. */
} else {
struct dev_mc_list *mclist;
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
- unsigned int bit =
- ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26;
+ netdev_for_each_mc_addr(mclist, dev) {
+ unsigned int bit = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26;
mc_filter[bit >> 3] |= (1 << (bit & 7));
}
outb(2, ioaddr + RX_MODE); /* Use normal mode. */
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 12e3233868e9..c717b143f11a 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -1475,14 +1475,13 @@ static void set_multicast_list(struct net_device *dev)
{
mace_private *lp = netdev_priv(dev);
int adr[ETHER_ADDR_LEN] = {0}; /* Ethernet address */
- int i;
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
#ifdef PCMCIA_DEBUG
{
static int old;
- if (dev->mc_count != old) {
- old = dev->mc_count;
+ if (netdev_mc_count(dev) != old) {
+ old = netdev_mc_count(dev);
pr_debug("%s: setting Rx mode to %d addresses.\n",
dev->name, old);
}
@@ -1490,15 +1489,14 @@ static void set_multicast_list(struct net_device *dev)
#endif
/* Set multicast_num_addrs. */
- lp->multicast_num_addrs = dev->mc_count;
+ lp->multicast_num_addrs = netdev_mc_count(dev);
/* Set multicast_ladrf. */
if (num_addrs > 0) {
/* Calculate multicast logical address filter */
memset(lp->multicast_ladrf, 0, MACE_LADRF_LEN);
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
memcpy(adr, dmi->dmi_addr, ETHER_ADDR_LEN);
- dmi = dmi->next;
BuildLAF(lp->multicast_ladrf, adr);
}
}
@@ -1537,15 +1535,15 @@ static void set_multicast_list(struct net_device *dev)
#ifdef PCMCIA_DEBUG
{
static int old;
- if (dev->mc_count != old) {
- old = dev->mc_count;
+ if (netdev_mc_count(dev) != old) {
+ old = netdev_mc_count(dev);
pr_debug("%s: setting Rx mode to %d addresses.\n",
dev->name, old);
}
}
#endif
- lp->multicast_num_addrs = dev->mc_count;
+ lp->multicast_num_addrs = netdev_mc_count(dev);
restore_multicast_list(dev);
} /* set_multicast_list */
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 6dd486d2977b..5adc662c4bfb 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -453,8 +453,7 @@ static int mhz_mfc_config(struct pcmcia_device *link)
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
- link->irq.Attributes =
- IRQ_TYPE_DYNAMIC_SHARING;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->io.IOAddrLines = 16;
link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts2 = 8;
@@ -652,8 +651,7 @@ static int osi_config(struct pcmcia_device *link)
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
- link->irq.Attributes =
- IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->io.NumPorts1 = 64;
link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts2 = 8;
@@ -1595,27 +1593,6 @@ static void smc_rx(struct net_device *dev)
/*======================================================================
- Calculate values for the hardware multicast filter hash table.
-
-======================================================================*/
-
-static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
- u_char *multicast_table)
-{
- struct dev_mc_list *mc_addr;
-
- for (mc_addr = addrs; mc_addr && count-- > 0; mc_addr = mc_addr->next) {
- u_int position = ether_crc(6, mc_addr->dmi_addr);
-#ifndef final_version /* Verify multicast address. */
- if ((mc_addr->dmi_addr[0] & 1) == 0)
- continue;
-#endif
- multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
- }
-}
-
-/*======================================================================
-
Set the receive mode.
This routine is used by both the protocol level to notify us of
@@ -1638,9 +1615,17 @@ static void set_rx_mode(struct net_device *dev)
} else if (dev->flags & IFF_ALLMULTI)
rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;
else {
- if (dev->mc_count) {
- fill_multicast_tbl(dev->mc_count, dev->mc_list,
- (u_char *)multicast_table);
+ if (!netdev_mc_empty(dev)) {
+ struct dev_mc_list *mc_addr;
+
+ netdev_for_each_mc_addr(mc_addr, dev) {
+ u_int position = ether_crc(6, mc_addr->dmi_addr);
+#ifndef final_version /* Verify multicast address. */
+ if ((mc_addr->dmi_addr[0] & 1) == 0)
+ continue;
+#endif
+ multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
+ }
}
rx_cfg_setting = RxStripCRC | RxEnable;
}
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 466fc72698c0..4d1802e457be 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1364,47 +1364,63 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
+struct set_address_info {
+ int reg_nr;
+ int page_nr;
+ int mohawk;
+ unsigned int ioaddr;
+};
+
+static void set_address(struct set_address_info *sa_info, char *addr)
+{
+ unsigned int ioaddr = sa_info->ioaddr;
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ if (sa_info->reg_nr > 15) {
+ sa_info->reg_nr = 8;
+ sa_info->page_nr++;
+ SelectPage(sa_info->page_nr);
+ }
+ if (sa_info->mohawk)
+ PutByte(sa_info->reg_nr++, addr[5 - i]);
+ else
+ PutByte(sa_info->reg_nr++, addr[i]);
+ }
+}
+
/****************
* Set all addresses: This first one is the individual address,
* the next 9 addresses are taken from the multicast list and
* the rest is filled with the individual address.
*/
-static void
-set_addresses(struct net_device *dev)
+static void set_addresses(struct net_device *dev)
{
- unsigned int ioaddr = dev->base_addr;
- local_info_t *lp = netdev_priv(dev);
- struct dev_mc_list *dmi = dev->mc_list;
- unsigned char *addr;
- int i,j,k,n;
-
- SelectPage(k=0x50);
- for (i=0,j=8,n=0; ; i++, j++) {
- if (i > 5) {
- if (++n > 9)
- break;
- i = 0;
- if (n > 1 && n <= dev->mc_count && dmi) {
- dmi = dmi->next;
- }
- }
- if (j > 15) {
- j = 8;
- k++;
- SelectPage(k);
- }
-
- if (n && n <= dev->mc_count && dmi)
- addr = dmi->dmi_addr;
- else
- addr = dev->dev_addr;
+ unsigned int ioaddr = dev->base_addr;
+ local_info_t *lp = netdev_priv(dev);
+ struct dev_mc_list *dmi;
+ struct set_address_info sa_info;
+ int i;
- if (lp->mohawk)
- PutByte(j, addr[5-i]);
- else
- PutByte(j, addr[i]);
- }
- SelectPage(0);
+ /*
+ * Setup the info structure so that by first set_address call it will do
+ * SelectPage with the right page number. Hence these ones here.
+ */
+ sa_info.reg_nr = 15 + 1;
+ sa_info.page_nr = 0x50 - 1;
+ sa_info.mohawk = lp->mohawk;
+ sa_info.ioaddr = ioaddr;
+
+ set_address(&sa_info, dev->dev_addr);
+ i = 0;
+ netdev_for_each_mc_addr(dmi, dev) {
+ if (i++ == 9)
+ break;
+ set_address(&sa_info, dmi->dmi_addr);
+ }
+ while (i++ < 9)
+ set_address(&sa_info, dev->dev_addr);
+ SelectPage(0);
}
/****************
@@ -1424,9 +1440,9 @@ set_multicast_list(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* snoop */
PutByte(XIRCREG42_SWC1, value | 0x06); /* set MPE and PME */
- } else if (dev->mc_count > 9 || (dev->flags & IFF_ALLMULTI)) {
+ } else if (netdev_mc_count(dev) > 9 || (dev->flags & IFF_ALLMULTI)) {
PutByte(XIRCREG42_SWC1, value | 0x02); /* set MPE */
- } else if (dev->mc_count) {
+ } else if (!netdev_mc_empty(dev)) {
/* the chip can filter 9 addresses perfectly */
PutByte(XIRCREG42_SWC1, value | 0x01);
SelectPage(0x40);
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index e154677ff706..084d78dd1637 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -21,6 +21,8 @@
*
*************************************************************************/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define DRV_NAME "pcnet32"
#define DRV_VERSION "1.35"
#define DRV_RELDATE "21.Apr.2008"
@@ -50,16 +52,16 @@ static const char *const version =
#include <linux/spinlock.h>
#include <linux/moduleparam.h>
#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
#include <asm/irq.h>
/*
* PCI device identifiers for "new style" Linux PCI Device Drivers
*/
-static struct pci_device_id pcnet32_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(pcnet32_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME), },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE), },
@@ -83,7 +85,7 @@ static int cards_found;
static unsigned int pcnet32_portlist[] __initdata =
{ 0x300, 0x320, 0x340, 0x360, 0 };
-static int pcnet32_debug = 0;
+static int pcnet32_debug;
static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */
static int pcnet32vlb; /* check for VLB cards ? */
@@ -390,7 +392,7 @@ static struct pcnet32_access pcnet32_wio = {
static u16 pcnet32_dwio_read_csr(unsigned long addr, int index)
{
outl(index, addr + PCNET32_DWIO_RAP);
- return (inl(addr + PCNET32_DWIO_RDP) & 0xffff);
+ return inl(addr + PCNET32_DWIO_RDP) & 0xffff;
}
static void pcnet32_dwio_write_csr(unsigned long addr, int index, u16 val)
@@ -402,7 +404,7 @@ static void pcnet32_dwio_write_csr(unsigned long addr, int index, u16 val)
static u16 pcnet32_dwio_read_bcr(unsigned long addr, int index)
{
outl(index, addr + PCNET32_DWIO_RAP);
- return (inl(addr + PCNET32_DWIO_BDP) & 0xffff);
+ return inl(addr + PCNET32_DWIO_BDP) & 0xffff;
}
static void pcnet32_dwio_write_bcr(unsigned long addr, int index, u16 val)
@@ -413,7 +415,7 @@ static void pcnet32_dwio_write_bcr(unsigned long addr, int index, u16 val)
static u16 pcnet32_dwio_read_rap(unsigned long addr)
{
- return (inl(addr + PCNET32_DWIO_RAP) & 0xffff);
+ return inl(addr + PCNET32_DWIO_RAP) & 0xffff;
}
static void pcnet32_dwio_write_rap(unsigned long addr, u16 val)
@@ -487,10 +489,7 @@ static void pcnet32_realloc_tx_ring(struct net_device *dev,
(1 << size),
&new_ring_dma_addr);
if (new_tx_ring == NULL) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Consistent memory allocation failed.\n",
- dev->name);
+ netif_err(lp, drv, dev, "Consistent memory allocation failed\n");
return;
}
memset(new_tx_ring, 0, sizeof(struct pcnet32_tx_head) * (1 << size));
@@ -498,18 +497,14 @@ static void pcnet32_realloc_tx_ring(struct net_device *dev,
new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
GFP_ATOMIC);
if (!new_dma_addr_list) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Memory allocation failed.\n", dev->name);
+ netif_err(lp, drv, dev, "Memory allocation failed\n");
goto free_new_tx_ring;
}
new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
GFP_ATOMIC);
if (!new_skb_list) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Memory allocation failed.\n", dev->name);
+ netif_err(lp, drv, dev, "Memory allocation failed\n");
goto free_new_lists;
}
@@ -529,15 +524,14 @@ static void pcnet32_realloc_tx_ring(struct net_device *dev,
lp->tx_skbuff = new_skb_list;
return;
- free_new_lists:
+free_new_lists:
kfree(new_dma_addr_list);
- free_new_tx_ring:
+free_new_tx_ring:
pci_free_consistent(lp->pci_dev,
sizeof(struct pcnet32_tx_head) *
(1 << size),
new_tx_ring,
new_ring_dma_addr);
- return;
}
/*
@@ -565,10 +559,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
(1 << size),
&new_ring_dma_addr);
if (new_rx_ring == NULL) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Consistent memory allocation failed.\n",
- dev->name);
+ netif_err(lp, drv, dev, "Consistent memory allocation failed\n");
return;
}
memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size));
@@ -576,18 +567,14 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
GFP_ATOMIC);
if (!new_dma_addr_list) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Memory allocation failed.\n", dev->name);
+ netif_err(lp, drv, dev, "Memory allocation failed\n");
goto free_new_rx_ring;
}
new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
GFP_ATOMIC);
if (!new_skb_list) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Memory allocation failed.\n", dev->name);
+ netif_err(lp, drv, dev, "Memory allocation failed\n");
goto free_new_lists;
}
@@ -599,15 +586,14 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
new_skb_list[new] = lp->rx_skbuff[new];
}
/* now allocate any new buffers needed */
- for (; new < size; new++ ) {
+ for (; new < size; new++) {
struct sk_buff *rx_skbuff;
new_skb_list[new] = dev_alloc_skb(PKT_BUF_SKB);
- if (!(rx_skbuff = new_skb_list[new])) {
+ rx_skbuff = new_skb_list[new];
+ if (!rx_skbuff) {
/* keep the original lists and buffers */
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: pcnet32_realloc_rx_ring dev_alloc_skb failed.\n",
- dev->name);
+ netif_err(lp, drv, dev, "%s dev_alloc_skb failed\n",
+ __func__);
goto free_all_new;
}
skb_reserve(rx_skbuff, NET_IP_ALIGN);
@@ -644,8 +630,8 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
lp->rx_skbuff = new_skb_list;
return;
- free_all_new:
- for (; --new >= lp->rx_ring_size; ) {
+free_all_new:
+ while (--new >= lp->rx_ring_size) {
if (new_skb_list[new]) {
pci_unmap_single(lp->pci_dev, new_dma_addr_list[new],
PKT_BUF_SIZE, PCI_DMA_FROMDEVICE);
@@ -653,9 +639,9 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
}
}
kfree(new_skb_list);
- free_new_lists:
+free_new_lists:
kfree(new_dma_addr_list);
- free_new_rx_ring:
+free_new_rx_ring:
pci_free_consistent(lp->pci_dev,
sizeof(struct pcnet32_rx_head) *
(1 << size),
@@ -838,16 +824,14 @@ static int pcnet32_set_ringparam(struct net_device *dev,
spin_unlock_irqrestore(&lp->lock, flags);
- if (netif_msg_drv(lp))
- printk(KERN_INFO
- "%s: Ring Param Settings: RX: %d, TX: %d\n", dev->name,
- lp->rx_ring_size, lp->tx_ring_size);
+ netif_info(lp, drv, dev, "Ring Param Settings: RX: %d, TX: %d\n",
+ lp->rx_ring_size, lp->tx_ring_size);
return 0;
}
static void pcnet32_get_strings(struct net_device *dev, u32 stringset,
- u8 * data)
+ u8 *data)
{
memcpy(data, pcnet32_gstrings_test, sizeof(pcnet32_gstrings_test));
}
@@ -871,17 +855,15 @@ static void pcnet32_ethtool_test(struct net_device *dev,
if (test->flags == ETH_TEST_FL_OFFLINE) {
rc = pcnet32_loopback_test(dev, data);
if (rc) {
- if (netif_msg_hw(lp))
- printk(KERN_DEBUG "%s: Loopback test failed.\n",
- dev->name);
+ netif_printk(lp, hw, KERN_DEBUG, dev,
+ "Loopback test failed\n");
test->flags |= ETH_TEST_FL_FAILED;
- } else if (netif_msg_hw(lp))
- printk(KERN_DEBUG "%s: Loopback test passed.\n",
- dev->name);
- } else if (netif_msg_hw(lp))
- printk(KERN_DEBUG
- "%s: No tests to run (specify 'Offline' on ethtool).",
- dev->name);
+ } else
+ netif_printk(lp, hw, KERN_DEBUG, dev,
+ "Loopback test passed\n");
+ } else
+ netif_printk(lp, hw, KERN_DEBUG, dev,
+ "No tests to run (specify 'Offline' on ethtool)\n");
} /* end pcnet32_ethtool_test */
static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
@@ -926,40 +908,39 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
/* Initialize Transmit buffers. */
size = data_len + 15;
for (x = 0; x < numbuffs; x++) {
- if (!(skb = dev_alloc_skb(size))) {
- if (netif_msg_hw(lp))
- printk(KERN_DEBUG
- "%s: Cannot allocate skb at line: %d!\n",
- dev->name, __LINE__);
+ skb = dev_alloc_skb(size);
+ if (!skb) {
+ netif_printk(lp, hw, KERN_DEBUG, dev,
+ "Cannot allocate skb at line: %d!\n",
+ __LINE__);
goto clean_up;
- } else {
- packet = skb->data;
- skb_put(skb, size); /* create space for data */
- lp->tx_skbuff[x] = skb;
- lp->tx_ring[x].length = cpu_to_le16(-skb->len);
- lp->tx_ring[x].misc = 0;
-
- /* put DA and SA into the skb */
- for (i = 0; i < 6; i++)
- *packet++ = dev->dev_addr[i];
- for (i = 0; i < 6; i++)
- *packet++ = dev->dev_addr[i];
- /* type */
- *packet++ = 0x08;
- *packet++ = 0x06;
- /* packet number */
- *packet++ = x;
- /* fill packet with data */
- for (i = 0; i < data_len; i++)
- *packet++ = i;
-
- lp->tx_dma_addr[x] =
- pci_map_single(lp->pci_dev, skb->data, skb->len,
- PCI_DMA_TODEVICE);
- lp->tx_ring[x].base = cpu_to_le32(lp->tx_dma_addr[x]);
- wmb(); /* Make sure owner changes after all others are visible */
- lp->tx_ring[x].status = cpu_to_le16(status);
}
+ packet = skb->data;
+ skb_put(skb, size); /* create space for data */
+ lp->tx_skbuff[x] = skb;
+ lp->tx_ring[x].length = cpu_to_le16(-skb->len);
+ lp->tx_ring[x].misc = 0;
+
+ /* put DA and SA into the skb */
+ for (i = 0; i < 6; i++)
+ *packet++ = dev->dev_addr[i];
+ for (i = 0; i < 6; i++)
+ *packet++ = dev->dev_addr[i];
+ /* type */
+ *packet++ = 0x08;
+ *packet++ = 0x06;
+ /* packet number */
+ *packet++ = x;
+ /* fill packet with data */
+ for (i = 0; i < data_len; i++)
+ *packet++ = i;
+
+ lp->tx_dma_addr[x] =
+ pci_map_single(lp->pci_dev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+ lp->tx_ring[x].base = cpu_to_le32(lp->tx_dma_addr[x]);
+ wmb(); /* Make sure owner changes after all others are visible */
+ lp->tx_ring[x].status = cpu_to_le16(status);
}
x = a->read_bcr(ioaddr, 32); /* set internal loopback in BCR32 */
@@ -984,9 +965,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
ticks++;
}
if (ticks == 200) {
- if (netif_msg_hw(lp))
- printk("%s: Desc %d failed to reset!\n",
- dev->name, x);
+ netif_err(lp, hw, dev, "Desc %d failed to reset!\n", x);
break;
}
}
@@ -994,15 +973,14 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
wmb();
if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
- printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name);
+ netdev_printk(KERN_DEBUG, dev, "RX loopback packets:\n");
for (x = 0; x < numbuffs; x++) {
- printk(KERN_DEBUG "%s: Packet %d:\n", dev->name, x);
+ netdev_printk(KERN_DEBUG, dev, "Packet %d: ", x);
skb = lp->rx_skbuff[x];
- for (i = 0; i < size; i++) {
- printk("%02x ", *(skb->data + i));
- }
- printk("\n");
+ for (i = 0; i < size; i++)
+ pr_cont(" %02x", *(skb->data + i));
+ pr_cont("\n");
}
}
@@ -1013,11 +991,9 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
packet = lp->tx_skbuff[x]->data;
for (i = 0; i < size; i++) {
if (*(skb->data + i) != packet[i]) {
- if (netif_msg_hw(lp))
- printk(KERN_DEBUG
- "%s: Error in compare! %2x - %02x %02x\n",
- dev->name, i, *(skb->data + i),
- packet[i]);
+ netif_printk(lp, hw, KERN_DEBUG, dev,
+ "Error in compare! %2x - %02x %02x\n",
+ i, *(skb->data + i), packet[i]);
rc = 1;
break;
}
@@ -1025,7 +1001,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
x++;
}
- clean_up:
+clean_up:
*data1 = rc;
pcnet32_purge_tx_ring(dev);
@@ -1044,7 +1020,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
spin_unlock_irqrestore(&lp->lock, flags);
- return (rc);
+ return rc;
} /* end pcnet32_loopback_test */
static void pcnet32_led_blink_callback(struct net_device *dev)
@@ -1056,9 +1032,8 @@ static void pcnet32_led_blink_callback(struct net_device *dev)
int i;
spin_lock_irqsave(&lp->lock, flags);
- for (i = 4; i < 8; i++) {
+ for (i = 4; i < 8; i++)
a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000);
- }
spin_unlock_irqrestore(&lp->lock, flags);
mod_timer(&lp->blink_timer, PCNET32_BLINK_TIMEOUT);
@@ -1080,9 +1055,8 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
/* Save the current value of the bcrs */
spin_lock_irqsave(&lp->lock, flags);
- for (i = 4; i < 8; i++) {
+ for (i = 4; i < 8; i++)
regs[i - 4] = a->read_bcr(ioaddr, i);
- }
spin_unlock_irqrestore(&lp->lock, flags);
mod_timer(&lp->blink_timer, jiffies);
@@ -1097,9 +1071,8 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
/* Restore the original value of the bcrs */
spin_lock_irqsave(&lp->lock, flags);
- for (i = 4; i < 8; i++) {
+ for (i = 4; i < 8; i++)
a->write_bcr(ioaddr, i, regs[i - 4]);
- }
spin_unlock_irqrestore(&lp->lock, flags);
return 0;
@@ -1136,10 +1109,8 @@ static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
spin_lock_irqsave(&lp->lock, *flags);
ticks++;
if (ticks > 200) {
- if (netif_msg_hw(lp))
- printk(KERN_DEBUG
- "%s: Error getting into suspend!\n",
- dev->name);
+ netif_printk(lp, hw, KERN_DEBUG, dev,
+ "Error getting into suspend!\n");
return 0;
}
}
@@ -1184,15 +1155,13 @@ static void pcnet32_rx_entry(struct net_device *dev,
/* Discard oversize frames. */
if (unlikely(pkt_len > PKT_BUF_SIZE)) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR "%s: Impossible packet size %d!\n",
- dev->name, pkt_len);
+ netif_err(lp, drv, dev, "Impossible packet size %d!\n",
+ pkt_len);
dev->stats.rx_errors++;
return;
}
if (pkt_len < 60) {
- if (netif_msg_rx_err(lp))
- printk(KERN_ERR "%s: Runt packet!\n", dev->name);
+ netif_err(lp, rx_err, dev, "Runt packet!\n");
dev->stats.rx_errors++;
return;
}
@@ -1200,7 +1169,8 @@ static void pcnet32_rx_entry(struct net_device *dev,
if (pkt_len > rx_copybreak) {
struct sk_buff *newskb;
- if ((newskb = dev_alloc_skb(PKT_BUF_SKB))) {
+ newskb = dev_alloc_skb(PKT_BUF_SKB);
+ if (newskb) {
skb_reserve(newskb, NET_IP_ALIGN);
skb = lp->rx_skbuff[entry];
pci_unmap_single(lp->pci_dev,
@@ -1218,15 +1188,11 @@ static void pcnet32_rx_entry(struct net_device *dev,
rx_in_place = 1;
} else
skb = NULL;
- } else {
+ } else
skb = dev_alloc_skb(pkt_len + NET_IP_ALIGN);
- }
if (skb == NULL) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Memory squeeze, dropping packet.\n",
- dev->name);
+ netif_err(lp, drv, dev, "Memory squeeze, dropping packet\n");
dev->stats.rx_dropped++;
return;
}
@@ -1297,11 +1263,9 @@ static int pcnet32_tx(struct net_device *dev)
/* There was a major error, log it. */
int err_status = le32_to_cpu(lp->tx_ring[entry].misc);
dev->stats.tx_errors++;
- if (netif_msg_tx_err(lp))
- printk(KERN_ERR
- "%s: Tx error status=%04x err_status=%08x\n",
- dev->name, status,
- err_status);
+ netif_err(lp, tx_err, dev,
+ "Tx error status=%04x err_status=%08x\n",
+ status, err_status);
if (err_status & 0x04000000)
dev->stats.tx_aborted_errors++;
if (err_status & 0x08000000)
@@ -1313,10 +1277,7 @@ static int pcnet32_tx(struct net_device *dev)
dev->stats.tx_fifo_errors++;
/* Ackk! On FIFO errors the Tx unit is turned off! */
/* Remove this verbosity later! */
- if (netif_msg_tx_err(lp))
- printk(KERN_ERR
- "%s: Tx FIFO error!\n",
- dev->name);
+ netif_err(lp, tx_err, dev, "Tx FIFO error!\n");
must_restart = 1;
}
#else
@@ -1325,10 +1286,7 @@ static int pcnet32_tx(struct net_device *dev)
if (!lp->dxsuflo) { /* If controller doesn't recover ... */
/* Ackk! On FIFO errors the Tx unit is turned off! */
/* Remove this verbosity later! */
- if (netif_msg_tx_err(lp))
- printk(KERN_ERR
- "%s: Tx FIFO error!\n",
- dev->name);
+ netif_err(lp, tx_err, dev, "Tx FIFO error!\n");
must_restart = 1;
}
}
@@ -1354,11 +1312,8 @@ static int pcnet32_tx(struct net_device *dev)
delta = (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask + lp->tx_ring_size);
if (delta > lp->tx_ring_size) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
- dev->name, dirty_tx, lp->cur_tx,
- lp->tx_full);
+ netif_err(lp, drv, dev, "out-of-sync dirty pointer, %d vs. %d, full=%d\n",
+ dirty_tx, lp->cur_tx, lp->tx_full);
dirty_tx += lp->tx_ring_size;
delta -= lp->tx_ring_size;
}
@@ -1421,7 +1376,7 @@ static int pcnet32_get_regs_len(struct net_device *dev)
struct pcnet32_private *lp = netdev_priv(dev);
int j = lp->phycount * PCNET32_REGS_PER_PHY;
- return ((PCNET32_NUM_REGS + j) * sizeof(u16));
+ return (PCNET32_NUM_REGS + j) * sizeof(u16);
}
static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
@@ -1445,21 +1400,20 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
*buff++ = inw(ioaddr + i);
/* read control and status registers */
- for (i = 0; i < 90; i++) {
+ for (i = 0; i < 90; i++)
*buff++ = a->read_csr(ioaddr, i);
- }
*buff++ = a->read_csr(ioaddr, 112);
*buff++ = a->read_csr(ioaddr, 114);
/* read bus configuration registers */
- for (i = 0; i < 30; i++) {
+ for (i = 0; i < 30; i++)
*buff++ = a->read_bcr(ioaddr, i);
- }
+
*buff++ = 0; /* skip bcr30 so as not to hang 79C976 */
- for (i = 31; i < 36; i++) {
+
+ for (i = 31; i < 36; i++)
*buff++ = a->read_bcr(ioaddr, i);
- }
/* read mii phy registers */
if (lp->mii) {
@@ -1535,8 +1489,7 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
err = pci_enable_device(pdev);
if (err < 0) {
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_ERR PFX
- "failed to enable device -- err=%d\n", err);
+ pr_err("failed to enable device -- err=%d\n", err);
return err;
}
pci_set_master(pdev);
@@ -1544,29 +1497,25 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
ioaddr = pci_resource_start(pdev, 0);
if (!ioaddr) {
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_ERR PFX
- "card has no PCI IO resources, aborting\n");
+ pr_err("card has no PCI IO resources, aborting\n");
return -ENODEV;
}
if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) {
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_ERR PFX
- "architecture does not support 32bit PCI busmaster DMA\n");
+ pr_err("architecture does not support 32bit PCI busmaster DMA\n");
return -ENODEV;
}
- if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci") ==
- NULL) {
+ if (!request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci")) {
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_ERR PFX
- "io address range already allocated\n");
+ pr_err("io address range already allocated\n");
return -EBUSY;
}
err = pcnet32_probe1(ioaddr, 1, pdev);
- if (err < 0) {
+ if (err < 0)
pci_disable_device(pdev);
- }
+
return err;
}
@@ -1616,7 +1565,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
a = &pcnet32_dwio;
} else {
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_ERR PFX "No access methods\n");
+ pr_err("No access methods\n");
goto err_release_region;
}
}
@@ -1624,11 +1573,10 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
chip_version =
a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr, 89) << 16);
if ((pcnet32_debug & NETIF_MSG_PROBE) && (pcnet32_debug & NETIF_MSG_HW))
- printk(KERN_INFO " PCnet chip version is %#x.\n",
- chip_version);
+ pr_info(" PCnet chip version is %#x\n", chip_version);
if ((chip_version & 0xfff) != 0x003) {
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_INFO PFX "Unsupported chip version.\n");
+ pr_info("Unsupported chip version\n");
goto err_release_region;
}
@@ -1681,7 +1629,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
if (cards_found < MAX_UNITS && homepna[cards_found])
media |= 1; /* switch to home wiring mode */
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_DEBUG PFX "media set to %sMbit mode.\n",
+ printk(KERN_DEBUG PFX "media set to %sMbit mode\n",
(media & 1) ? "1" : "10");
a->write_bcr(ioaddr, 49, media);
break;
@@ -1697,9 +1645,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
break;
default:
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_INFO PFX
- "PCnet version %#x, no PCnet32 chip.\n",
- chip_version);
+ pr_info("PCnet version %#x, no PCnet32 chip\n",
+ chip_version);
goto err_release_region;
}
@@ -1721,7 +1668,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
dev = alloc_etherdev(sizeof(*lp));
if (!dev) {
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_ERR PFX "Memory allocation failed.\n");
+ pr_err("Memory allocation failed\n");
ret = -ENOMEM;
goto err_release_region;
}
@@ -1730,7 +1677,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
SET_NETDEV_DEV(dev, &pdev->dev);
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr);
+ pr_info("%s at %#3lx,", chipname, ioaddr);
/* In most chips, after a chip reset, the ethernet address is read from the
* station address PROM at the base address and programmed into the
@@ -1755,9 +1702,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
!is_valid_ether_addr(dev->dev_addr)) {
if (is_valid_ether_addr(promaddr)) {
if (pcnet32_debug & NETIF_MSG_PROBE) {
- printk(" warning: CSR address invalid,\n");
- printk(KERN_INFO
- " using instead PROM address of");
+ pr_cont(" warning: CSR address invalid,\n");
+ pr_info(" using instead PROM address of");
}
memcpy(dev->dev_addr, promaddr, 6);
}
@@ -1769,54 +1715,54 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
memset(dev->dev_addr, 0, ETH_ALEN);
if (pcnet32_debug & NETIF_MSG_PROBE) {
- printk(" %pM", dev->dev_addr);
+ pr_cont(" %pM", dev->dev_addr);
/* Version 0x2623 and 0x2624 */
if (((chip_version + 1) & 0xfffe) == 0x2624) {
i = a->read_csr(ioaddr, 80) & 0x0C00; /* Check tx_start_pt */
- printk(KERN_INFO " tx_start_pt(0x%04x):", i);
+ pr_info(" tx_start_pt(0x%04x):", i);
switch (i >> 10) {
case 0:
- printk(KERN_CONT " 20 bytes,");
+ pr_cont(" 20 bytes,");
break;
case 1:
- printk(KERN_CONT " 64 bytes,");
+ pr_cont(" 64 bytes,");
break;
case 2:
- printk(KERN_CONT " 128 bytes,");
+ pr_cont(" 128 bytes,");
break;
case 3:
- printk(KERN_CONT "~220 bytes,");
+ pr_cont("~220 bytes,");
break;
}
i = a->read_bcr(ioaddr, 18); /* Check Burst/Bus control */
- printk(KERN_CONT " BCR18(%x):", i & 0xffff);
+ pr_cont(" BCR18(%x):", i & 0xffff);
if (i & (1 << 5))
- printk(KERN_CONT "BurstWrEn ");
+ pr_cont("BurstWrEn ");
if (i & (1 << 6))
- printk(KERN_CONT "BurstRdEn ");
+ pr_cont("BurstRdEn ");
if (i & (1 << 7))
- printk(KERN_CONT "DWordIO ");
+ pr_cont("DWordIO ");
if (i & (1 << 11))
- printk(KERN_CONT "NoUFlow ");
+ pr_cont("NoUFlow ");
i = a->read_bcr(ioaddr, 25);
- printk(KERN_INFO " SRAMSIZE=0x%04x,", i << 8);
+ pr_info(" SRAMSIZE=0x%04x,", i << 8);
i = a->read_bcr(ioaddr, 26);
- printk(KERN_CONT " SRAM_BND=0x%04x,", i << 8);
+ pr_cont(" SRAM_BND=0x%04x,", i << 8);
i = a->read_bcr(ioaddr, 27);
if (i & (1 << 14))
- printk(KERN_CONT "LowLatRx");
+ pr_cont("LowLatRx");
}
}
dev->base_addr = ioaddr;
lp = netdev_priv(dev);
/* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
- if ((lp->init_block =
- pci_alloc_consistent(pdev, sizeof(*lp->init_block), &lp->init_dma_addr)) == NULL) {
+ lp->init_block = pci_alloc_consistent(pdev, sizeof(*lp->init_block),
+ &lp->init_dma_addr);
+ if (!lp->init_block) {
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_ERR PFX
- "Consistent memory allocation failed.\n");
+ pr_err("Consistent memory allocation failed\n");
ret = -ENOMEM;
goto err_free_netdev;
}
@@ -1890,7 +1836,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
if (pdev) { /* use the IRQ provided by PCI */
dev->irq = pdev->irq;
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(" assigned IRQ %d.\n", dev->irq);
+ pr_cont(" assigned IRQ %d\n", dev->irq);
} else {
unsigned long irq_mask = probe_irq_on();
@@ -1906,12 +1852,12 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
dev->irq = probe_irq_off(irq_mask);
if (!dev->irq) {
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(", failed to detect IRQ line.\n");
+ pr_cont(", failed to detect IRQ line\n");
ret = -ENODEV;
goto err_free_ring;
}
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(", probed IRQ %d.\n", dev->irq);
+ pr_cont(", probed IRQ %d\n", dev->irq);
}
/* Set the mii phy_id so that we can query the link state */
@@ -1935,14 +1881,12 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
lp->phymask |= (1 << i);
lp->mii_if.phy_id = i;
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_INFO PFX
- "Found PHY %04x:%04x at address %d.\n",
- id1, id2, i);
+ pr_info("Found PHY %04x:%04x at address %d\n",
+ id1, id2, i);
}
lp->a.write_bcr(ioaddr, 33, (lp->mii_if.phy_id) << 5);
- if (lp->phycount > 1) {
+ if (lp->phycount > 1)
lp->options |= PCNET32_PORT_MII;
- }
}
init_timer(&lp->watchdog_timer);
@@ -1966,7 +1910,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
}
if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_INFO "%s: registered as %s\n", dev->name, lp->name);
+ pr_info("%s: registered as %s\n", dev->name, lp->name);
cards_found++;
/* enable LED writes */
@@ -1995,10 +1939,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, const char *name)
lp->tx_ring_size,
&lp->tx_ring_dma_addr);
if (lp->tx_ring == NULL) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR PFX
- "%s: Consistent memory allocation failed.\n",
- name);
+ netif_err(lp, drv, dev, "Consistent memory allocation failed\n");
return -ENOMEM;
}
@@ -2007,46 +1948,35 @@ static int pcnet32_alloc_ring(struct net_device *dev, const char *name)
lp->rx_ring_size,
&lp->rx_ring_dma_addr);
if (lp->rx_ring == NULL) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR PFX
- "%s: Consistent memory allocation failed.\n",
- name);
+ netif_err(lp, drv, dev, "Consistent memory allocation failed\n");
return -ENOMEM;
}
lp->tx_dma_addr = kcalloc(lp->tx_ring_size, sizeof(dma_addr_t),
GFP_ATOMIC);
if (!lp->tx_dma_addr) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR PFX
- "%s: Memory allocation failed.\n", name);
+ netif_err(lp, drv, dev, "Memory allocation failed\n");
return -ENOMEM;
}
lp->rx_dma_addr = kcalloc(lp->rx_ring_size, sizeof(dma_addr_t),
GFP_ATOMIC);
if (!lp->rx_dma_addr) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR PFX
- "%s: Memory allocation failed.\n", name);
+ netif_err(lp, drv, dev, "Memory allocation failed\n");
return -ENOMEM;
}
lp->tx_skbuff = kcalloc(lp->tx_ring_size, sizeof(struct sk_buff *),
GFP_ATOMIC);
if (!lp->tx_skbuff) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR PFX
- "%s: Memory allocation failed.\n", name);
+ netif_err(lp, drv, dev, "Memory allocation failed\n");
return -ENOMEM;
}
lp->rx_skbuff = kcalloc(lp->rx_ring_size, sizeof(struct sk_buff *),
GFP_ATOMIC);
if (!lp->rx_skbuff) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR PFX
- "%s: Memory allocation failed.\n", name);
+ netif_err(lp, drv, dev, "Memory allocation failed\n");
return -ENOMEM;
}
@@ -2115,12 +2045,11 @@ static int pcnet32_open(struct net_device *dev)
/* switch pcnet32 to 32bit mode */
lp->a.write_bcr(ioaddr, 20, 2);
- if (netif_msg_ifup(lp))
- printk(KERN_DEBUG
- "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
- dev->name, dev->irq, (u32) (lp->tx_ring_dma_addr),
- (u32) (lp->rx_ring_dma_addr),
- (u32) (lp->init_dma_addr));
+ netif_printk(lp, ifup, KERN_DEBUG, dev,
+ "%s() irq %d tx/rx rings %#x/%#x init %#x\n",
+ __func__, dev->irq, (u32) (lp->tx_ring_dma_addr),
+ (u32) (lp->rx_ring_dma_addr),
+ (u32) (lp->init_dma_addr));
/* set/reset autoselect bit */
val = lp->a.read_bcr(ioaddr, 2) & ~2;
@@ -2155,10 +2084,8 @@ static int pcnet32_open(struct net_device *dev)
pdev->subsystem_device == PCI_SUBDEVICE_ID_AT_2701FX)) {
if (lp->options & PCNET32_PORT_ASEL) {
lp->options = PCNET32_PORT_FD | PCNET32_PORT_100;
- if (netif_msg_link(lp))
- printk(KERN_DEBUG
- "%s: Setting 100Mb-Full Duplex.\n",
- dev->name);
+ netif_printk(lp, link, KERN_DEBUG, dev,
+ "Setting 100Mb-Full Duplex\n");
}
}
if (lp->phycount < 2) {
@@ -2246,9 +2173,7 @@ static int pcnet32_open(struct net_device *dev)
}
}
lp->mii_if.phy_id = first_phy;
- if (netif_msg_link(lp))
- printk(KERN_INFO "%s: Using PHY number %d.\n",
- dev->name, first_phy);
+ netif_info(lp, link, dev, "Using PHY number %d\n", first_phy);
}
#ifdef DO_DXSUFLO
@@ -2295,18 +2220,17 @@ static int pcnet32_open(struct net_device *dev)
*/
lp->a.write_csr(ioaddr, CSR0, CSR0_NORMAL);
- if (netif_msg_ifup(lp))
- printk(KERN_DEBUG
- "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n",
- dev->name, i,
- (u32) (lp->init_dma_addr),
- lp->a.read_csr(ioaddr, CSR0));
+ netif_printk(lp, ifup, KERN_DEBUG, dev,
+ "pcnet32 open after %d ticks, init block %#x csr0 %4.4x\n",
+ i,
+ (u32) (lp->init_dma_addr),
+ lp->a.read_csr(ioaddr, CSR0));
spin_unlock_irqrestore(&lp->lock, flags);
return 0; /* Always succeed */
- err_free_ring:
+err_free_ring:
/* free any allocated skbuffs */
pcnet32_purge_rx_ring(dev);
@@ -2316,7 +2240,7 @@ static int pcnet32_open(struct net_device *dev)
*/
lp->a.write_bcr(ioaddr, 20, 4);
- err_free_irq:
+err_free_irq:
spin_unlock_irqrestore(&lp->lock, flags);
free_irq(dev->irq, dev);
return rc;
@@ -2367,14 +2291,12 @@ static int pcnet32_init_ring(struct net_device *dev)
for (i = 0; i < lp->rx_ring_size; i++) {
struct sk_buff *rx_skbuff = lp->rx_skbuff[i];
if (rx_skbuff == NULL) {
- if (!
- (rx_skbuff = lp->rx_skbuff[i] =
- dev_alloc_skb(PKT_BUF_SKB))) {
- /* there is not much, we can do at this point */
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: pcnet32_init_ring dev_alloc_skb failed.\n",
- dev->name);
+ lp->rx_skbuff[i] = dev_alloc_skb(PKT_BUF_SKB);
+ rx_skbuff = lp->rx_skbuff[i];
+ if (!rx_skbuff) {
+ /* there is not much we can do at this point */
+ netif_err(lp, drv, dev, "%s dev_alloc_skb failed\n",
+ __func__);
return -1;
}
skb_reserve(rx_skbuff, NET_IP_ALIGN);
@@ -2424,10 +2346,9 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
if (lp->a.read_csr(ioaddr, CSR0) & CSR0_STOP)
break;
- if (i >= 100 && netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: pcnet32_restart timed out waiting for stop.\n",
- dev->name);
+ if (i >= 100)
+ netif_err(lp, drv, dev, "%s timed out waiting for stop\n",
+ __func__);
pcnet32_purge_tx_ring(dev);
if (pcnet32_init_ring(dev))
@@ -2451,8 +2372,7 @@ static void pcnet32_tx_timeout(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
/* Transmitter timeout, serious problems. */
if (pcnet32_debug & NETIF_MSG_DRV)
- printk(KERN_ERR
- "%s: transmit timed out, status %4.4x, resetting.\n",
+ pr_err("%s: transmit timed out, status %4.4x, resetting\n",
dev->name, lp->a.read_csr(ioaddr, CSR0));
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
dev->stats.tx_errors++;
@@ -2495,11 +2415,9 @@ static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb,
spin_lock_irqsave(&lp->lock, flags);
- if (netif_msg_tx_queued(lp)) {
- printk(KERN_DEBUG
- "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
- dev->name, lp->a.read_csr(ioaddr, CSR0));
- }
+ netif_printk(lp, tx_queued, KERN_DEBUG, dev,
+ "%s() called, csr0 %4.4x\n",
+ __func__, lp->a.read_csr(ioaddr, CSR0));
/* Default status -- will not enable Successful-TxDone
* interrupt when that option is available to us.
@@ -2558,16 +2476,14 @@ pcnet32_interrupt(int irq, void *dev_id)
csr0 = lp->a.read_csr(ioaddr, CSR0);
while ((csr0 & 0x8f00) && --boguscnt >= 0) {
- if (csr0 == 0xffff) {
+ if (csr0 == 0xffff)
break; /* PCMCIA remove happened */
- }
/* Acknowledge all of the current interrupt sources ASAP. */
lp->a.write_csr(ioaddr, CSR0, csr0 & ~0x004f);
- if (netif_msg_intr(lp))
- printk(KERN_DEBUG
- "%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n",
- dev->name, csr0, lp->a.read_csr(ioaddr, CSR0));
+ netif_printk(lp, intr, KERN_DEBUG, dev,
+ "interrupt csr0=%#2.2x new csr=%#2.2x\n",
+ csr0, lp->a.read_csr(ioaddr, CSR0));
/* Log misc errors. */
if (csr0 & 0x4000)
@@ -2587,10 +2503,8 @@ pcnet32_interrupt(int irq, void *dev_id)
dev->stats.rx_errors++; /* Missed a Rx frame. */
}
if (csr0 & 0x0800) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Bus master arbitration failure, status %4.4x.\n",
- dev->name, csr0);
+ netif_err(lp, drv, dev, "Bus master arbitration failure, status %4.4x\n",
+ csr0);
/* unlike for the lance, there is no restart needed */
}
if (napi_schedule_prep(&lp->napi)) {
@@ -2606,9 +2520,9 @@ pcnet32_interrupt(int irq, void *dev_id)
csr0 = lp->a.read_csr(ioaddr, CSR0);
}
- if (netif_msg_intr(lp))
- printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n",
- dev->name, lp->a.read_csr(ioaddr, CSR0));
+ netif_printk(lp, intr, KERN_DEBUG, dev,
+ "exiting interrupt, csr0=%#4.4x\n",
+ lp->a.read_csr(ioaddr, CSR0));
spin_unlock(&lp->lock);
@@ -2630,10 +2544,9 @@ static int pcnet32_close(struct net_device *dev)
dev->stats.rx_missed_errors = lp->a.read_csr(ioaddr, 112);
- if (netif_msg_ifdown(lp))
- printk(KERN_DEBUG
- "%s: Shutting down ethercard, status was %2.2x.\n",
- dev->name, lp->a.read_csr(ioaddr, CSR0));
+ netif_printk(lp, ifdown, KERN_DEBUG, dev,
+ "Shutting down ethercard, status was %2.2x\n",
+ lp->a.read_csr(ioaddr, CSR0));
/* We stop the PCNET32 here -- it occasionally polls memory if we don't. */
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
@@ -2677,7 +2590,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
struct pcnet32_private *lp = netdev_priv(dev);
volatile struct pcnet32_init_block *ib = lp->init_block;
volatile __le16 *mcast_table = (__le16 *)ib->filter;
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
unsigned long ioaddr = dev->base_addr;
char *addrs;
int i;
@@ -2698,9 +2611,8 @@ static void pcnet32_load_multicast(struct net_device *dev)
ib->filter[1] = 0;
/* Add addresses */
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
addrs = dmi->dmi_addr;
- dmi = dmi->next;
/* multicast address? */
if (!(*addrs & 1))
@@ -2730,9 +2642,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
csr15 = lp->a.read_csr(ioaddr, CSR15);
if (dev->flags & IFF_PROMISC) {
/* Log any net taps. */
- if (netif_msg_hw(lp))
- printk(KERN_INFO "%s: Promiscuous mode enabled.\n",
- dev->name);
+ netif_info(lp, hw, dev, "Promiscuous mode enabled\n");
lp->init_block->mode =
cpu_to_le16(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
7);
@@ -2819,10 +2729,8 @@ static int pcnet32_check_otherphy(struct net_device *dev)
mii.phy_id = i;
if (mii_link_ok(&mii)) {
/* found PHY with active link */
- if (netif_msg_link(lp))
- printk(KERN_INFO
- "%s: Using PHY number %d.\n",
- dev->name, i);
+ netif_info(lp, link, dev, "Using PHY number %d\n",
+ i);
/* isolate inactive phy */
bmcr =
@@ -2868,8 +2776,7 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
if (!curr_link) {
if (prev_link || verbose) {
netif_carrier_off(dev);
- if (netif_msg_link(lp))
- printk(KERN_INFO "%s: link down\n", dev->name);
+ netif_info(lp, link, dev, "link down\n");
}
if (lp->phycount > 1) {
curr_link = pcnet32_check_otherphy(dev);
@@ -2881,12 +2788,11 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
if (netif_msg_link(lp)) {
struct ethtool_cmd ecmd;
mii_ethtool_gset(&lp->mii_if, &ecmd);
- printk(KERN_INFO
- "%s: link up, %sMbps, %s-duplex\n",
- dev->name,
- (ecmd.speed == SPEED_100) ? "100" : "10",
- (ecmd.duplex ==
- DUPLEX_FULL) ? "full" : "half");
+ netdev_info(dev, "link up, %sMbps, %s-duplex\n",
+ (ecmd.speed == SPEED_100)
+ ? "100" : "10",
+ (ecmd.duplex == DUPLEX_FULL)
+ ? "full" : "half");
}
bcr9 = lp->a.read_bcr(dev->base_addr, 9);
if ((bcr9 & (1 << 0)) != lp->mii_if.full_duplex) {
@@ -2897,8 +2803,7 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
lp->a.write_bcr(dev->base_addr, 9, bcr9);
}
} else {
- if (netif_msg_link(lp))
- printk(KERN_INFO "%s: link up\n", dev->name);
+ netif_info(lp, link, dev, "link up\n");
}
}
}
@@ -3010,7 +2915,7 @@ MODULE_LICENSE("GPL");
static int __init pcnet32_init_module(void)
{
- printk(KERN_INFO "%s", version);
+ pr_info("%s", version);
pcnet32_debug = netif_msg_init(debug, PCNET32_MSG_DEFAULT);
@@ -3026,7 +2931,7 @@ static int __init pcnet32_init_module(void)
pcnet32_probe_vlbus(pcnet32_portlist);
if (cards_found && (pcnet32_debug & NETIF_MSG_PROBE))
- printk(KERN_INFO PFX "%d cards_found.\n", cards_found);
+ pr_info("%d cards_found\n", cards_found);
return (pcnet32_have_pci + cards_found) ? 0 : -ENODEV;
}
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 33c4b12a63ba..f482fc4f8cf1 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -18,9 +18,6 @@
#include <linux/phy.h>
#include <linux/brcmphy.h>
-#define PHY_ID_BCM50610 0x0143bd60
-#define PHY_ID_BCM50610M 0x0143bd70
-#define PHY_ID_BCM57780 0x03625d90
#define BRCM_PHY_MODEL(phydev) \
((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
@@ -823,7 +820,7 @@ static struct phy_driver bcm57780_driver = {
};
static struct phy_driver bcmac131_driver = {
- .phy_id = 0x0143bc70,
+ .phy_id = PHY_ID_BCMAC131,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCMAC131",
.features = PHY_BASIC_FEATURES |
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 6f69b9ba0df8..65ed385c2ceb 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -63,6 +63,7 @@
#define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb
#define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3
#define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4
+#define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9
#define MII_M1111_HWCFG_FIBER_COPPER_AUTO 0x8000
#define MII_M1111_HWCFG_FIBER_COPPER_RES 0x2000
@@ -269,6 +270,43 @@ static int m88e1111_config_init(struct phy_device *phydev)
return err;
}
+ if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
+ temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
+ if (temp < 0)
+ return temp;
+ temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
+ err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
+ if (err < 0)
+ return err;
+
+ temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+ if (temp < 0)
+ return temp;
+ temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
+ temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
+ err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+ if (err < 0)
+ return err;
+
+ /* soft reset */
+ err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+ if (err < 0)
+ return err;
+ do
+ temp = phy_read(phydev, MII_BMCR);
+ while (temp & BMCR_RESET);
+
+ temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+ if (temp < 0)
+ return temp;
+ temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
+ temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
+ err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+ if (err < 0)
+ return err;
+ }
+
+
err = phy_write(phydev, MII_BMCR, BMCR_RESET);
if (err < 0)
return err;
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index b0e9f9c51721..0295097d6c44 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -410,7 +410,6 @@ EXPORT_SYMBOL(phy_start_aneg);
static void phy_change(struct work_struct *work);
-static void phy_state_machine(struct work_struct *work);
/**
* phy_start_machine - start PHY state machine tracking
@@ -430,7 +429,6 @@ void phy_start_machine(struct phy_device *phydev,
{
phydev->adjust_state = handler;
- INIT_DELAYED_WORK(&phydev->state_queue, phy_state_machine);
schedule_delayed_work(&phydev->state_queue, HZ);
}
@@ -761,7 +759,7 @@ EXPORT_SYMBOL(phy_start);
* phy_state_machine - Handle the state machine
* @work: work_struct that describes the work to be done
*/
-static void phy_state_machine(struct work_struct *work)
+void phy_state_machine(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct phy_device *phydev =
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 8212b2b93422..db1794546c56 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -177,6 +177,7 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
dev->state = PHY_DOWN;
mutex_init(&dev->lock);
+ INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
return dev;
}
@@ -276,6 +277,22 @@ int phy_device_register(struct phy_device *phydev)
EXPORT_SYMBOL(phy_device_register);
/**
+ * phy_find_first - finds the first PHY device on the bus
+ * @bus: the target MII bus
+ */
+struct phy_device *phy_find_first(struct mii_bus *bus)
+{
+ int addr;
+
+ for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
+ if (bus->phy_map[addr])
+ return bus->phy_map[addr];
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(phy_find_first);
+
+/**
* phy_prepare_link - prepares the PHY layer to monitor link status
* @phydev: target phy_device struct
* @handler: callback function for link status change notifications
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index 5123bb954dd7..ed2644a57500 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -25,6 +25,7 @@
#define MII_LAN83C185_ISF 29 /* Interrupt Source Flags */
#define MII_LAN83C185_IM 30 /* Interrupt Mask */
+#define MII_LAN83C185_CTRL_STATUS 17 /* Mode/Status Register */
#define MII_LAN83C185_ISF_INT1 (1<<1) /* Auto-Negotiation Page Received */
#define MII_LAN83C185_ISF_INT2 (1<<2) /* Parallel Detection Fault */
@@ -37,8 +38,10 @@
#define MII_LAN83C185_ISF_INT_ALL (0x0e)
#define MII_LAN83C185_ISF_INT_PHYLIB_EVENTS \
- (MII_LAN83C185_ISF_INT6 | MII_LAN83C185_ISF_INT4)
+ (MII_LAN83C185_ISF_INT6 | MII_LAN83C185_ISF_INT4 | \
+ MII_LAN83C185_ISF_INT7)
+#define MII_LAN83C185_EDPWRDOWN (1 << 13) /* EDPWRDOWN */
static int smsc_phy_config_intr(struct phy_device *phydev)
{
@@ -59,9 +62,23 @@ static int smsc_phy_ack_interrupt(struct phy_device *phydev)
static int smsc_phy_config_init(struct phy_device *phydev)
{
+ int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
+ if (rc < 0)
+ return rc;
+
+ /* Enable energy detect mode for this SMSC Transceivers */
+ rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
+ rc | MII_LAN83C185_EDPWRDOWN);
+ if (rc < 0)
+ return rc;
+
return smsc_phy_ack_interrupt (phydev);
}
+static int lan911x_config_init(struct phy_device *phydev)
+{
+ return smsc_phy_ack_interrupt(phydev);
+}
static struct phy_driver lan83c185_driver = {
.phy_id = 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */
@@ -147,7 +164,7 @@ static struct phy_driver lan911x_int_driver = {
/* basic functions */
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
- .config_init = smsc_phy_config_init,
+ .config_init = lan911x_config_init,
/* IRQ related */
.ack_interrupt = smsc_phy_ack_interrupt,
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 2282e729edbe..6d61602208c1 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -167,7 +167,7 @@ struct channel {
u8 avail; /* flag used in multilink stuff */
u8 had_frag; /* >= 1 fragments have been sent */
u32 lastseq; /* MP: last sequence # received */
- int speed; /* speed of the corresponding ppp channel*/
+ int speed; /* speed of the corresponding ppp channel*/
#endif /* CONFIG_PPP_MULTILINK */
};
@@ -1293,13 +1293,13 @@ ppp_push(struct ppp *ppp)
*/
static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
{
- int len, totlen;
- int i, bits, hdrlen, mtu;
- int flen;
- int navail, nfree, nzero;
- int nbigger;
- int totspeed;
- int totfree;
+ int len, totlen;
+ int i, bits, hdrlen, mtu;
+ int flen;
+ int navail, nfree, nzero;
+ int nbigger;
+ int totspeed;
+ int totfree;
unsigned char *p, *q;
struct list_head *list;
struct channel *pch;
@@ -1307,21 +1307,21 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
struct ppp_channel *chan;
totspeed = 0; /*total bitrate of the bundle*/
- nfree = 0; /* # channels which have no packet already queued */
- navail = 0; /* total # of usable channels (not deregistered) */
- nzero = 0; /* number of channels with zero speed associated*/
- totfree = 0; /*total # of channels available and
+ nfree = 0; /* # channels which have no packet already queued */
+ navail = 0; /* total # of usable channels (not deregistered) */
+ nzero = 0; /* number of channels with zero speed associated*/
+ totfree = 0; /*total # of channels available and
*having no queued packets before
*starting the fragmentation*/
hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
- i = 0;
- list_for_each_entry(pch, &ppp->channels, clist) {
+ i = 0;
+ list_for_each_entry(pch, &ppp->channels, clist) {
navail += pch->avail = (pch->chan != NULL);
pch->speed = pch->chan->speed;
- if (pch->avail) {
+ if (pch->avail) {
if (skb_queue_empty(&pch->file.xq) ||
- !pch->had_frag) {
+ !pch->had_frag) {
if (pch->speed == 0)
nzero++;
else
@@ -1331,60 +1331,60 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
++nfree;
++totfree;
}
- if (!pch->had_frag && i < ppp->nxchan)
- ppp->nxchan = i;
+ if (!pch->had_frag && i < ppp->nxchan)
+ ppp->nxchan = i;
}
++i;
}
/*
- * Don't start sending this packet unless at least half of
- * the channels are free. This gives much better TCP
- * performance if we have a lot of channels.
+ * Don't start sending this packet unless at least half of
+ * the channels are free. This gives much better TCP
+ * performance if we have a lot of channels.
*/
- if (nfree == 0 || nfree < navail / 2)
- return 0; /* can't take now, leave it in xmit_pending */
+ if (nfree == 0 || nfree < navail / 2)
+ return 0; /* can't take now, leave it in xmit_pending */
/* Do protocol field compression (XXX this should be optional) */
- p = skb->data;
- len = skb->len;
+ p = skb->data;
+ len = skb->len;
if (*p == 0) {
++p;
--len;
}
totlen = len;
- nbigger = len % nfree;
+ nbigger = len % nfree;
- /* skip to the channel after the one we last used
- and start at that one */
+ /* skip to the channel after the one we last used
+ and start at that one */
list = &ppp->channels;
- for (i = 0; i < ppp->nxchan; ++i) {
+ for (i = 0; i < ppp->nxchan; ++i) {
list = list->next;
- if (list == &ppp->channels) {
- i = 0;
+ if (list == &ppp->channels) {
+ i = 0;
break;
}
}
- /* create a fragment for each channel */
+ /* create a fragment for each channel */
bits = B;
- while (len > 0) {
+ while (len > 0) {
list = list->next;
- if (list == &ppp->channels) {
- i = 0;
+ if (list == &ppp->channels) {
+ i = 0;
continue;
}
- pch = list_entry(list, struct channel, clist);
+ pch = list_entry(list, struct channel, clist);
++i;
if (!pch->avail)
continue;
/*
- * Skip this channel if it has a fragment pending already and
- * we haven't given a fragment to all of the free channels.
+ * Skip this channel if it has a fragment pending already and
+ * we haven't given a fragment to all of the free channels.
*/
if (pch->avail == 1) {
- if (nfree > 0)
+ if (nfree > 0)
continue;
} else {
pch->avail = 1;
@@ -1393,32 +1393,32 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
/* check the channel's mtu and whether it is still attached. */
spin_lock_bh(&pch->downl);
if (pch->chan == NULL) {
- /* can't use this channel, it's being deregistered */
+ /* can't use this channel, it's being deregistered */
if (pch->speed == 0)
nzero--;
else
- totspeed -= pch->speed;
+ totspeed -= pch->speed;
spin_unlock_bh(&pch->downl);
pch->avail = 0;
totlen = len;
totfree--;
nfree--;
- if (--navail == 0)
+ if (--navail == 0)
break;
continue;
}
/*
*if the channel speed is not set divide
- *the packet evenly among the free channels;
+ *the packet evenly among the free channels;
*otherwise divide it according to the speed
*of the channel we are going to transmit on
*/
flen = len;
if (nfree > 0) {
if (pch->speed == 0) {
- flen = totlen/nfree ;
+ flen = totlen/nfree;
if (nbigger > 0) {
flen++;
nbigger--;
@@ -1436,8 +1436,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
}
/*
- *check if we are on the last channel or
- *we exceded the lenght of the data to
+ *check if we are on the last channel or
+ *we exceded the lenght of the data to
*fragment
*/
if ((nfree <= 0) || (flen > len))
@@ -1448,29 +1448,29 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
*above formula will be equal or less than zero.
*Skip the channel in this case
*/
- if (flen <= 0) {
+ if (flen <= 0) {
pch->avail = 2;
spin_unlock_bh(&pch->downl);
continue;
}
- mtu = pch->chan->mtu - hdrlen;
- if (mtu < 4)
- mtu = 4;
+ mtu = pch->chan->mtu - hdrlen;
+ if (mtu < 4)
+ mtu = 4;
if (flen > mtu)
flen = mtu;
- if (flen == len)
- bits |= E;
- frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC);
+ if (flen == len)
+ bits |= E;
+ frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC);
if (!frag)
goto noskb;
- q = skb_put(frag, flen + hdrlen);
+ q = skb_put(frag, flen + hdrlen);
- /* make the MP header */
+ /* make the MP header */
q[0] = PPP_MP >> 8;
q[1] = PPP_MP;
if (ppp->flags & SC_MP_XSHORTSEQ) {
- q[2] = bits + ((ppp->nxseq >> 8) & 0xf);
+ q[2] = bits + ((ppp->nxseq >> 8) & 0xf);
q[3] = ppp->nxseq;
} else {
q[2] = bits;
@@ -1483,24 +1483,24 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
/* try to send it down the channel */
chan = pch->chan;
- if (!skb_queue_empty(&pch->file.xq) ||
+ if (!skb_queue_empty(&pch->file.xq) ||
!chan->ops->start_xmit(chan, frag))
skb_queue_tail(&pch->file.xq, frag);
- pch->had_frag = 1;
+ pch->had_frag = 1;
p += flen;
- len -= flen;
+ len -= flen;
++ppp->nxseq;
bits = 0;
spin_unlock_bh(&pch->downl);
}
- ppp->nxchan = i;
+ ppp->nxchan = i;
return 1;
noskb:
spin_unlock_bh(&pch->downl);
if (ppp->debug & 1)
- printk(KERN_ERR "PPP: no memory (fragment)\n");
+ printk(KERN_ERR "PPP: no memory (fragment)\n");
++ppp->dev->stats.tx_errors;
++ppp->nxseq;
return 1; /* abandon the frame */
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
index 0c768593aad0..a849f6f23a17 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -568,7 +568,7 @@ void gelic_net_set_multi(struct net_device *netdev)
status);
if ((netdev->flags & IFF_ALLMULTI) ||
- (netdev->mc_count > GELIC_NET_MC_COUNT_MAX)) {
+ (netdev_mc_count(netdev) > GELIC_NET_MC_COUNT_MAX)) {
status = lv1_net_add_multicast_address(bus_id(card),
dev_id(card),
0, 1);
@@ -580,7 +580,7 @@ void gelic_net_set_multi(struct net_device *netdev)
}
/* set multicast addresses */
- for (mc = netdev->mc_list; mc; mc = mc->next) {
+ netdev_for_each_mc_addr(mc, netdev) {
addr = 0;
p = mc->dmi_addr;
for (i = 0; i < ETH_ALEN; i++) {
diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c
index 227b141c4fbd..2663b2fdc0bb 100644
--- a/drivers/net/ps3_gelic_wireless.c
+++ b/drivers/net/ps3_gelic_wireless.c
@@ -1389,113 +1389,6 @@ static int gelic_wl_get_mode(struct net_device *netdev,
return 0;
}
-#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
-/* SIOCIWFIRSTPRIV */
-static int hex2bin(u8 *str, u8 *bin, unsigned int len)
-{
- unsigned int i;
- static unsigned char *hex = "0123456789ABCDEF";
- unsigned char *p, *q;
- u8 tmp;
-
- if (len != WPA_PSK_LEN * 2)
- return -EINVAL;
-
- for (i = 0; i < WPA_PSK_LEN * 2; i += 2) {
- p = strchr(hex, toupper(str[i]));
- q = strchr(hex, toupper(str[i + 1]));
- if (!p || !q) {
- pr_info("%s: unconvertible PSK digit=%d\n",
- __func__, i);
- return -EINVAL;
- }
- tmp = ((p - hex) << 4) + (q - hex);
- *bin++ = tmp;
- }
- return 0;
-};
-
-static int gelic_wl_priv_set_psk(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data, char *extra)
-{
- struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
- unsigned int len;
- unsigned long irqflag;
- int ret = 0;
-
- pr_debug("%s:<- len=%d\n", __func__, data->data.length);
- len = data->data.length - 1;
- if (len <= 2)
- return -EINVAL;
-
- spin_lock_irqsave(&wl->lock, irqflag);
- if (extra[0] == '"' && extra[len - 1] == '"') {
- pr_debug("%s: passphrase mode\n", __func__);
- /* pass phrase */
- if (GELIC_WL_EURUS_PSK_MAX_LEN < (len - 2)) {
- pr_info("%s: passphrase too long\n", __func__);
- ret = -E2BIG;
- goto out;
- }
- memset(wl->psk, 0, sizeof(wl->psk));
- wl->psk_len = len - 2;
- memcpy(wl->psk, &(extra[1]), wl->psk_len);
- wl->psk_type = GELIC_EURUS_WPA_PSK_PASSPHRASE;
- } else {
- ret = hex2bin(extra, wl->psk, len);
- if (ret)
- goto out;
- wl->psk_len = WPA_PSK_LEN;
- wl->psk_type = GELIC_EURUS_WPA_PSK_BIN;
- }
- set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat);
-out:
- spin_unlock_irqrestore(&wl->lock, irqflag);
- pr_debug("%s:->\n", __func__);
- return ret;
-}
-
-static int gelic_wl_priv_get_psk(struct net_device *net_dev,
- struct iw_request_info *info,
- union iwreq_data *data, char *extra)
-{
- struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
- char *p;
- unsigned long irqflag;
- unsigned int i;
-
- pr_debug("%s:<-\n", __func__);
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- spin_lock_irqsave(&wl->lock, irqflag);
- p = extra;
- if (test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat)) {
- if (wl->psk_type == GELIC_EURUS_WPA_PSK_BIN) {
- for (i = 0; i < wl->psk_len; i++) {
- sprintf(p, "%02xu", wl->psk[i]);
- p += 2;
- }
- *p = '\0';
- data->data.length = wl->psk_len * 2;
- } else {
- *p++ = '"';
- memcpy(p, wl->psk, wl->psk_len);
- p += wl->psk_len;
- *p++ = '"';
- *p = '\0';
- data->data.length = wl->psk_len + 2;
- }
- } else
- /* no psk set */
- data->data.length = 0;
- spin_unlock_irqrestore(&wl->lock, irqflag);
- pr_debug("%s:-> %d\n", __func__, data->data.length);
- return 0;
-}
-#endif
-
/* SIOCGIWNICKN */
static int gelic_wl_get_nick(struct net_device *net_dev,
struct iw_request_info *info,
@@ -1571,8 +1464,10 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
init_completion(&wl->scan_done);
/*
* If we have already a bss list, don't try to get new
+ * unless we are doing an ESSID scan
*/
- if (!always_scan && wl->scan_stat == GELIC_WL_SCAN_STAT_GOT_LIST) {
+ if ((!essid_len && !always_scan)
+ && wl->scan_stat == GELIC_WL_SCAN_STAT_GOT_LIST) {
pr_debug("%s: already has the list\n", __func__);
complete(&wl->scan_done);
goto out;
@@ -1673,7 +1568,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
}
}
- /* put them in the newtork_list */
+ /* put them in the network_list */
for (i = 0, scan_info_size = 0, scan_info = buf;
scan_info_size < data_len;
i++, scan_info_size += be16_to_cpu(scan_info->size),
@@ -2009,7 +1904,7 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl)
/* PSK type */
wpa->psk_type = cpu_to_be16(wl->psk_type);
#ifdef DEBUG
- pr_debug("%s: sec=%s psktype=%s\nn", __func__,
+ pr_debug("%s: sec=%s psktype=%s\n", __func__,
wpasecstr(wpa->security),
(wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ?
"BIN" : "passphrase");
@@ -2019,9 +1914,9 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl)
* the debug log because this dumps your precious
* passphrase/key.
*/
- pr_debug("%s: psk=%s\n",
+ pr_debug("%s: psk=%s\n", __func__,
(wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ?
- (char *)"N/A" : (char *)wpa->psk);
+ "N/A" : wpa->psk);
#endif
#endif
/* issue wpa setup */
@@ -2406,40 +2301,10 @@ static const iw_handler gelic_wl_wext_handler[] =
IW_IOCTL(SIOCGIWNICKN) = gelic_wl_get_nick,
};
-#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
-static struct iw_priv_args gelic_wl_private_args[] =
-{
- {
- .cmd = GELIC_WL_PRIV_SET_PSK,
- .set_args = IW_PRIV_TYPE_CHAR |
- (GELIC_WL_EURUS_PSK_MAX_LEN + 2),
- .name = "set_psk"
- },
- {
- .cmd = GELIC_WL_PRIV_GET_PSK,
- .get_args = IW_PRIV_TYPE_CHAR |
- (GELIC_WL_EURUS_PSK_MAX_LEN + 2),
- .name = "get_psk"
- }
-};
-
-static const iw_handler gelic_wl_private_handler[] =
-{
- gelic_wl_priv_set_psk,
- gelic_wl_priv_get_psk,
-};
-#endif
-
static const struct iw_handler_def gelic_wl_wext_handler_def = {
.num_standard = ARRAY_SIZE(gelic_wl_wext_handler),
.standard = gelic_wl_wext_handler,
.get_wireless_stats = gelic_wl_get_wireless_stats,
-#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
- .num_private = ARRAY_SIZE(gelic_wl_private_handler),
- .num_private_args = ARRAY_SIZE(gelic_wl_private_args),
- .private = gelic_wl_private_handler,
- .private_args = gelic_wl_private_args,
-#endif
};
static struct net_device * __devinit gelic_wl_alloc(struct gelic_card *card)
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index dd35066a7f8d..4ef0afbcbe1b 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -61,7 +61,7 @@ static int msi;
module_param(msi, int, 0);
MODULE_PARM_DESC(msi, "Turn on Message Signaled Interrupts.");
-static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(ql3xxx_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3032_DEVICE_ID)},
/* required last entry */
@@ -4087,7 +4087,6 @@ static void __devexit ql3xxx_remove(struct pci_dev *pdev)
struct ql3_adapter *qdev = netdev_priv(ndev);
unregister_netdev(ndev);
- qdev = netdev_priv(ndev);
ql_disable_interrupts(qdev);
diff --git a/drivers/net/qlcnic/Makefile b/drivers/net/qlcnic/Makefile
new file mode 100644
index 000000000000..ddba83ef3f44
--- /dev/null
+++ b/drivers/net/qlcnic/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for Qlogic 1G/10G Ethernet Driver for CNA devices
+#
+
+obj-$(CONFIG_QLCNIC) := qlcnic.o
+
+qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
+ qlcnic_ethtool.o qlcnic_ctx.o
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
new file mode 100644
index 000000000000..0da94b208db1
--- /dev/null
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -0,0 +1,1131 @@
+/*
+ * Copyright (C) 2009 - QLogic 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 _QLCNIC_H_
+#define _QLCNIC_H_
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/timer.h>
+
+#include <linux/vmalloc.h>
+
+#include <linux/io.h>
+#include <asm/byteorder.h>
+
+#include "qlcnic_hdr.h"
+
+#define _QLCNIC_LINUX_MAJOR 5
+#define _QLCNIC_LINUX_MINOR 0
+#define _QLCNIC_LINUX_SUBVERSION 0
+#define QLCNIC_LINUX_VERSIONID "5.0.0"
+
+#define QLCNIC_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c))
+#define _major(v) (((v) >> 24) & 0xff)
+#define _minor(v) (((v) >> 16) & 0xff)
+#define _build(v) ((v) & 0xffff)
+
+/* version in image has weird encoding:
+ * 7:0 - major
+ * 15:8 - minor
+ * 31:16 - build (little endian)
+ */
+#define QLCNIC_DECODE_VERSION(v) \
+ QLCNIC_VERSION_CODE(((v) & 0xff), (((v) >> 8) & 0xff), ((v) >> 16))
+
+#define QLCNIC_NUM_FLASH_SECTORS (64)
+#define QLCNIC_FLASH_SECTOR_SIZE (64 * 1024)
+#define QLCNIC_FLASH_TOTAL_SIZE (QLCNIC_NUM_FLASH_SECTORS \
+ * QLCNIC_FLASH_SECTOR_SIZE)
+
+#define RCV_DESC_RINGSIZE(rds_ring) \
+ (sizeof(struct rcv_desc) * (rds_ring)->num_desc)
+#define RCV_BUFF_RINGSIZE(rds_ring) \
+ (sizeof(struct qlcnic_rx_buffer) * rds_ring->num_desc)
+#define STATUS_DESC_RINGSIZE(sds_ring) \
+ (sizeof(struct status_desc) * (sds_ring)->num_desc)
+#define TX_BUFF_RINGSIZE(tx_ring) \
+ (sizeof(struct qlcnic_cmd_buffer) * tx_ring->num_desc)
+#define TX_DESC_RINGSIZE(tx_ring) \
+ (sizeof(struct cmd_desc_type0) * tx_ring->num_desc)
+
+#define QLCNIC_P3P_A0 0x50
+
+#define QLCNIC_IS_REVISION_P3P(REVISION) (REVISION >= QLCNIC_P3P_A0)
+
+#define FIRST_PAGE_GROUP_START 0
+#define FIRST_PAGE_GROUP_END 0x100000
+
+#define P3_MAX_MTU (9600)
+#define QLCNIC_MAX_ETHERHDR 32 /* This contains some padding */
+
+#define QLCNIC_P3_RX_BUF_MAX_LEN (QLCNIC_MAX_ETHERHDR + ETH_DATA_LEN)
+#define QLCNIC_P3_RX_JUMBO_BUF_MAX_LEN (QLCNIC_MAX_ETHERHDR + P3_MAX_MTU)
+#define QLCNIC_CT_DEFAULT_RX_BUF_LEN 2048
+#define QLCNIC_LRO_BUFFER_EXTRA 2048
+
+#define QLCNIC_RX_LRO_BUFFER_LENGTH (8060)
+
+/* Opcodes to be used with the commands */
+#define TX_ETHER_PKT 0x01
+#define TX_TCP_PKT 0x02
+#define TX_UDP_PKT 0x03
+#define TX_IP_PKT 0x04
+#define TX_TCP_LSO 0x05
+#define TX_TCP_LSO6 0x06
+#define TX_IPSEC 0x07
+#define TX_IPSEC_CMD 0x0a
+#define TX_TCPV6_PKT 0x0b
+#define TX_UDPV6_PKT 0x0c
+
+/* Tx defines */
+#define MAX_BUFFERS_PER_CMD 32
+#define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + 4)
+#define QLCNIC_MAX_TX_TIMEOUTS 2
+
+/*
+ * Following are the states of the Phantom. Phantom will set them and
+ * Host will read to check if the fields are correct.
+ */
+#define PHAN_INITIALIZE_FAILED 0xffff
+#define PHAN_INITIALIZE_COMPLETE 0xff01
+
+/* Host writes the following to notify that it has done the init-handshake */
+#define PHAN_INITIALIZE_ACK 0xf00f
+#define PHAN_PEG_RCV_INITIALIZED 0xff01
+
+#define NUM_RCV_DESC_RINGS 3
+#define NUM_STS_DESC_RINGS 4
+
+#define RCV_RING_NORMAL 0
+#define RCV_RING_JUMBO 1
+#define RCV_RING_LRO 2
+
+#define MIN_CMD_DESCRIPTORS 64
+#define MIN_RCV_DESCRIPTORS 64
+#define MIN_JUMBO_DESCRIPTORS 32
+
+#define MAX_CMD_DESCRIPTORS 1024
+#define MAX_RCV_DESCRIPTORS_1G 4096
+#define MAX_RCV_DESCRIPTORS_10G 8192
+#define MAX_JUMBO_RCV_DESCRIPTORS_1G 512
+#define MAX_JUMBO_RCV_DESCRIPTORS_10G 1024
+#define MAX_LRO_RCV_DESCRIPTORS 8
+
+#define DEFAULT_RCV_DESCRIPTORS_1G 2048
+#define DEFAULT_RCV_DESCRIPTORS_10G 4096
+
+#define get_next_index(index, length) \
+ (((index) + 1) & ((length) - 1))
+
+#define MPORT_MULTI_FUNCTION_MODE 0x2222
+
+/*
+ * Following data structures describe the descriptors that will be used.
+ * Added fileds of tcpHdrSize and ipHdrSize, The driver needs to do it only when
+ * we are doing LSO (above the 1500 size packet) only.
+ */
+
+#define FLAGS_VLAN_TAGGED 0x10
+#define FLAGS_VLAN_OOB 0x40
+
+#define qlcnic_set_tx_vlan_tci(cmd_desc, v) \
+ (cmd_desc)->vlan_TCI = cpu_to_le16(v);
+#define qlcnic_set_cmd_desc_port(cmd_desc, var) \
+ ((cmd_desc)->port_ctxid |= ((var) & 0x0F))
+#define qlcnic_set_cmd_desc_ctxid(cmd_desc, var) \
+ ((cmd_desc)->port_ctxid |= ((var) << 4 & 0xF0))
+
+#define qlcnic_set_tx_port(_desc, _port) \
+ ((_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0))
+
+#define qlcnic_set_tx_flags_opcode(_desc, _flags, _opcode) \
+ ((_desc)->flags_opcode = \
+ cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7)))
+
+#define qlcnic_set_tx_frags_len(_desc, _frags, _len) \
+ ((_desc)->nfrags__length = \
+ cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8)))
+
+struct cmd_desc_type0 {
+ u8 tcp_hdr_offset; /* For LSO only */
+ u8 ip_hdr_offset; /* For LSO only */
+ __le16 flags_opcode; /* 15:13 unused, 12:7 opcode, 6:0 flags */
+ __le32 nfrags__length; /* 31:8 total len, 7:0 frag count */
+
+ __le64 addr_buffer2;
+
+ __le16 reference_handle;
+ __le16 mss;
+ u8 port_ctxid; /* 7:4 ctxid 3:0 port */
+ u8 total_hdr_length; /* LSO only : MAC+IP+TCP Hdr size */
+ __le16 conn_id; /* IPSec offoad only */
+
+ __le64 addr_buffer3;
+ __le64 addr_buffer1;
+
+ __le16 buffer_length[4];
+
+ __le64 addr_buffer4;
+
+ __le32 reserved2;
+ __le16 reserved;
+ __le16 vlan_TCI;
+
+} __attribute__ ((aligned(64)));
+
+/* Note: sizeof(rcv_desc) should always be a mutliple of 2 */
+struct rcv_desc {
+ __le16 reference_handle;
+ __le16 reserved;
+ __le32 buffer_length; /* allocated buffer length (usually 2K) */
+ __le64 addr_buffer;
+};
+
+/* opcode field in status_desc */
+#define QLCNIC_SYN_OFFLOAD 0x03
+#define QLCNIC_RXPKT_DESC 0x04
+#define QLCNIC_OLD_RXPKT_DESC 0x3f
+#define QLCNIC_RESPONSE_DESC 0x05
+#define QLCNIC_LRO_DESC 0x12
+
+/* for status field in status_desc */
+#define STATUS_CKSUM_OK (2)
+
+/* owner bits of status_desc */
+#define STATUS_OWNER_HOST (0x1ULL << 56)
+#define STATUS_OWNER_PHANTOM (0x2ULL << 56)
+
+/* Status descriptor:
+ 0-3 port, 4-7 status, 8-11 type, 12-27 total_length
+ 28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset
+ 53-55 desc_cnt, 56-57 owner, 58-63 opcode
+ */
+#define qlcnic_get_sts_port(sts_data) \
+ ((sts_data) & 0x0F)
+#define qlcnic_get_sts_status(sts_data) \
+ (((sts_data) >> 4) & 0x0F)
+#define qlcnic_get_sts_type(sts_data) \
+ (((sts_data) >> 8) & 0x0F)
+#define qlcnic_get_sts_totallength(sts_data) \
+ (((sts_data) >> 12) & 0xFFFF)
+#define qlcnic_get_sts_refhandle(sts_data) \
+ (((sts_data) >> 28) & 0xFFFF)
+#define qlcnic_get_sts_prot(sts_data) \
+ (((sts_data) >> 44) & 0x0F)
+#define qlcnic_get_sts_pkt_offset(sts_data) \
+ (((sts_data) >> 48) & 0x1F)
+#define qlcnic_get_sts_desc_cnt(sts_data) \
+ (((sts_data) >> 53) & 0x7)
+#define qlcnic_get_sts_opcode(sts_data) \
+ (((sts_data) >> 58) & 0x03F)
+
+#define qlcnic_get_lro_sts_refhandle(sts_data) \
+ ((sts_data) & 0x0FFFF)
+#define qlcnic_get_lro_sts_length(sts_data) \
+ (((sts_data) >> 16) & 0x0FFFF)
+#define qlcnic_get_lro_sts_l2_hdr_offset(sts_data) \
+ (((sts_data) >> 32) & 0x0FF)
+#define qlcnic_get_lro_sts_l4_hdr_offset(sts_data) \
+ (((sts_data) >> 40) & 0x0FF)
+#define qlcnic_get_lro_sts_timestamp(sts_data) \
+ (((sts_data) >> 48) & 0x1)
+#define qlcnic_get_lro_sts_type(sts_data) \
+ (((sts_data) >> 49) & 0x7)
+#define qlcnic_get_lro_sts_push_flag(sts_data) \
+ (((sts_data) >> 52) & 0x1)
+#define qlcnic_get_lro_sts_seq_number(sts_data) \
+ ((sts_data) & 0x0FFFFFFFF)
+
+
+struct status_desc {
+ __le64 status_desc_data[2];
+} __attribute__ ((aligned(16)));
+
+/* UNIFIED ROMIMAGE */
+#define QLCNIC_UNI_FW_MIN_SIZE 0xc8000
+#define QLCNIC_UNI_DIR_SECT_PRODUCT_TBL 0x0
+#define QLCNIC_UNI_DIR_SECT_BOOTLD 0x6
+#define QLCNIC_UNI_DIR_SECT_FW 0x7
+
+/*Offsets */
+#define QLCNIC_UNI_CHIP_REV_OFF 10
+#define QLCNIC_UNI_FLAGS_OFF 11
+#define QLCNIC_UNI_BIOS_VERSION_OFF 12
+#define QLCNIC_UNI_BOOTLD_IDX_OFF 27
+#define QLCNIC_UNI_FIRMWARE_IDX_OFF 29
+
+struct uni_table_desc{
+ u32 findex;
+ u32 num_entries;
+ u32 entry_size;
+ u32 reserved[5];
+};
+
+struct uni_data_desc{
+ u32 findex;
+ u32 size;
+ u32 reserved[5];
+};
+
+/* Magic number to let user know flash is programmed */
+#define QLCNIC_BDINFO_MAGIC 0x12345678
+
+#define QLCNIC_BRDTYPE_P3_REF_QG 0x0021
+#define QLCNIC_BRDTYPE_P3_HMEZ 0x0022
+#define QLCNIC_BRDTYPE_P3_10G_CX4_LP 0x0023
+#define QLCNIC_BRDTYPE_P3_4_GB 0x0024
+#define QLCNIC_BRDTYPE_P3_IMEZ 0x0025
+#define QLCNIC_BRDTYPE_P3_10G_SFP_PLUS 0x0026
+#define QLCNIC_BRDTYPE_P3_10000_BASE_T 0x0027
+#define QLCNIC_BRDTYPE_P3_XG_LOM 0x0028
+#define QLCNIC_BRDTYPE_P3_4_GB_MM 0x0029
+#define QLCNIC_BRDTYPE_P3_10G_SFP_CT 0x002a
+#define QLCNIC_BRDTYPE_P3_10G_SFP_QT 0x002b
+#define QLCNIC_BRDTYPE_P3_10G_CX4 0x0031
+#define QLCNIC_BRDTYPE_P3_10G_XFP 0x0032
+#define QLCNIC_BRDTYPE_P3_10G_TP 0x0080
+
+/* Flash memory map */
+#define QLCNIC_BRDCFG_START 0x4000 /* board config */
+#define QLCNIC_BOOTLD_START 0x10000 /* bootld */
+#define QLCNIC_IMAGE_START 0x43000 /* compressed image */
+#define QLCNIC_USER_START 0x3E8000 /* Firmare info */
+
+#define QLCNIC_FW_VERSION_OFFSET (QLCNIC_USER_START+0x408)
+#define QLCNIC_FW_SIZE_OFFSET (QLCNIC_USER_START+0x40c)
+#define QLCNIC_FW_SERIAL_NUM_OFFSET (QLCNIC_USER_START+0x81c)
+#define QLCNIC_BIOS_VERSION_OFFSET (QLCNIC_USER_START+0x83c)
+
+#define QLCNIC_BRDTYPE_OFFSET (QLCNIC_BRDCFG_START+0x8)
+#define QLCNIC_FW_MAGIC_OFFSET (QLCNIC_BRDCFG_START+0x128)
+
+#define QLCNIC_FW_MIN_SIZE (0x3fffff)
+#define QLCNIC_UNIFIED_ROMIMAGE 0
+#define QLCNIC_FLASH_ROMIMAGE 1
+#define QLCNIC_UNKNOWN_ROMIMAGE 0xff
+
+#define QLCNIC_UNIFIED_ROMIMAGE_NAME "phanfw.bin"
+#define QLCNIC_FLASH_ROMIMAGE_NAME "flash"
+
+extern char qlcnic_driver_name[];
+
+/* Number of status descriptors to handle per interrupt */
+#define MAX_STATUS_HANDLE (64)
+
+/*
+ * qlcnic_skb_frag{} is to contain mapping info for each SG list. This
+ * has to be freed when DMA is complete. This is part of qlcnic_tx_buffer{}.
+ */
+struct qlcnic_skb_frag {
+ u64 dma;
+ u64 length;
+};
+
+struct qlcnic_recv_crb {
+ u32 crb_rcv_producer[NUM_RCV_DESC_RINGS];
+ u32 crb_sts_consumer[NUM_STS_DESC_RINGS];
+ u32 sw_int_mask[NUM_STS_DESC_RINGS];
+};
+
+/* Following defines are for the state of the buffers */
+#define QLCNIC_BUFFER_FREE 0
+#define QLCNIC_BUFFER_BUSY 1
+
+/*
+ * There will be one qlcnic_buffer per skb packet. These will be
+ * used to save the dma info for pci_unmap_page()
+ */
+struct qlcnic_cmd_buffer {
+ struct sk_buff *skb;
+ struct qlcnic_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1];
+ u32 frag_count;
+};
+
+/* In rx_buffer, we do not need multiple fragments as is a single buffer */
+struct qlcnic_rx_buffer {
+ struct list_head list;
+ struct sk_buff *skb;
+ u64 dma;
+ u16 ref_handle;
+ u16 state;
+};
+
+/* Board types */
+#define QLCNIC_GBE 0x01
+#define QLCNIC_XGBE 0x02
+
+/*
+ * One hardware_context{} per adapter
+ * contains interrupt info as well shared hardware info.
+ */
+struct qlcnic_hardware_context {
+ void __iomem *pci_base0;
+ void __iomem *ocm_win_crb;
+
+ unsigned long pci_len0;
+
+ u32 ocm_win;
+ u32 crb_win;
+
+ rwlock_t crb_lock;
+ struct mutex mem_lock;
+
+ u8 cut_through;
+ u8 revision_id;
+ u8 pci_func;
+ u8 linkup;
+ u16 port_type;
+ u16 board_type;
+};
+
+struct qlcnic_adapter_stats {
+ u64 xmitcalled;
+ u64 xmitfinished;
+ u64 rxdropped;
+ u64 txdropped;
+ u64 csummed;
+ u64 rx_pkts;
+ u64 lro_pkts;
+ u64 rxbytes;
+ u64 txbytes;
+ u64 lrobytes;
+ u64 lso_frames;
+ u64 xmit_on;
+ u64 xmit_off;
+ u64 skb_alloc_failure;
+};
+
+/*
+ * Rcv Descriptor Context. One such per Rcv Descriptor. There may
+ * be one Rcv Descriptor for normal packets, one for jumbo and may be others.
+ */
+struct qlcnic_host_rds_ring {
+ u32 producer;
+ u32 num_desc;
+ u32 dma_size;
+ u32 skb_size;
+ u32 flags;
+ void __iomem *crb_rcv_producer;
+ struct rcv_desc *desc_head;
+ struct qlcnic_rx_buffer *rx_buf_arr;
+ struct list_head free_list;
+ spinlock_t lock;
+ dma_addr_t phys_addr;
+};
+
+struct qlcnic_host_sds_ring {
+ u32 consumer;
+ u32 num_desc;
+ void __iomem *crb_sts_consumer;
+ void __iomem *crb_intr_mask;
+
+ struct status_desc *desc_head;
+ struct qlcnic_adapter *adapter;
+ struct napi_struct napi;
+ struct list_head free_list[NUM_RCV_DESC_RINGS];
+
+ int irq;
+
+ dma_addr_t phys_addr;
+ char name[IFNAMSIZ+4];
+};
+
+struct qlcnic_host_tx_ring {
+ u32 producer;
+ __le32 *hw_consumer;
+ u32 sw_consumer;
+ void __iomem *crb_cmd_producer;
+ u32 num_desc;
+
+ struct netdev_queue *txq;
+
+ struct qlcnic_cmd_buffer *cmd_buf_arr;
+ struct cmd_desc_type0 *desc_head;
+ dma_addr_t phys_addr;
+ dma_addr_t hw_cons_phys_addr;
+};
+
+/*
+ * Receive context. There is one such structure per instance of the
+ * receive processing. Any state information that is relevant to
+ * the receive, and is must be in this structure. The global data may be
+ * present elsewhere.
+ */
+struct qlcnic_recv_context {
+ u32 state;
+ u16 context_id;
+ u16 virt_port;
+
+ struct qlcnic_host_rds_ring *rds_rings;
+ struct qlcnic_host_sds_ring *sds_rings;
+};
+
+/* HW context creation */
+
+#define QLCNIC_OS_CRB_RETRY_COUNT 4000
+#define QLCNIC_CDRP_SIGNATURE_MAKE(pcifn, version) \
+ (((pcifn) & 0xff) | (((version) & 0xff) << 8) | (0xcafe << 16))
+
+#define QLCNIC_CDRP_CMD_BIT 0x80000000
+
+/*
+ * All responses must have the QLCNIC_CDRP_CMD_BIT cleared
+ * in the crb QLCNIC_CDRP_CRB_OFFSET.
+ */
+#define QLCNIC_CDRP_FORM_RSP(rsp) (rsp)
+#define QLCNIC_CDRP_IS_RSP(rsp) (((rsp) & QLCNIC_CDRP_CMD_BIT) == 0)
+
+#define QLCNIC_CDRP_RSP_OK 0x00000001
+#define QLCNIC_CDRP_RSP_FAIL 0x00000002
+#define QLCNIC_CDRP_RSP_TIMEOUT 0x00000003
+
+/*
+ * All commands must have the QLCNIC_CDRP_CMD_BIT set in
+ * the crb QLCNIC_CDRP_CRB_OFFSET.
+ */
+#define QLCNIC_CDRP_FORM_CMD(cmd) (QLCNIC_CDRP_CMD_BIT | (cmd))
+#define QLCNIC_CDRP_IS_CMD(cmd) (((cmd) & QLCNIC_CDRP_CMD_BIT) != 0)
+
+#define QLCNIC_CDRP_CMD_SUBMIT_CAPABILITIES 0x00000001
+#define QLCNIC_CDRP_CMD_READ_MAX_RDS_PER_CTX 0x00000002
+#define QLCNIC_CDRP_CMD_READ_MAX_SDS_PER_CTX 0x00000003
+#define QLCNIC_CDRP_CMD_READ_MAX_RULES_PER_CTX 0x00000004
+#define QLCNIC_CDRP_CMD_READ_MAX_RX_CTX 0x00000005
+#define QLCNIC_CDRP_CMD_READ_MAX_TX_CTX 0x00000006
+#define QLCNIC_CDRP_CMD_CREATE_RX_CTX 0x00000007
+#define QLCNIC_CDRP_CMD_DESTROY_RX_CTX 0x00000008
+#define QLCNIC_CDRP_CMD_CREATE_TX_CTX 0x00000009
+#define QLCNIC_CDRP_CMD_DESTROY_TX_CTX 0x0000000a
+#define QLCNIC_CDRP_CMD_SETUP_STATISTICS 0x0000000e
+#define QLCNIC_CDRP_CMD_GET_STATISTICS 0x0000000f
+#define QLCNIC_CDRP_CMD_DELETE_STATISTICS 0x00000010
+#define QLCNIC_CDRP_CMD_SET_MTU 0x00000012
+#define QLCNIC_CDRP_CMD_READ_PHY 0x00000013
+#define QLCNIC_CDRP_CMD_WRITE_PHY 0x00000014
+#define QLCNIC_CDRP_CMD_READ_HW_REG 0x00000015
+#define QLCNIC_CDRP_CMD_GET_FLOW_CTL 0x00000016
+#define QLCNIC_CDRP_CMD_SET_FLOW_CTL 0x00000017
+#define QLCNIC_CDRP_CMD_READ_MAX_MTU 0x00000018
+#define QLCNIC_CDRP_CMD_READ_MAX_LRO 0x00000019
+#define QLCNIC_CDRP_CMD_CONFIGURE_TOE 0x0000001a
+#define QLCNIC_CDRP_CMD_FUNC_ATTRIB 0x0000001b
+#define QLCNIC_CDRP_CMD_READ_PEXQ_PARAMETERS 0x0000001c
+#define QLCNIC_CDRP_CMD_GET_LIC_CAPABILITIES 0x0000001d
+#define QLCNIC_CDRP_CMD_READ_MAX_LRO_PER_BOARD 0x0000001e
+#define QLCNIC_CDRP_CMD_MAX 0x0000001f
+
+#define QLCNIC_RCODE_SUCCESS 0
+#define QLCNIC_RCODE_TIMEOUT 17
+#define QLCNIC_DESTROY_CTX_RESET 0
+
+/*
+ * Capabilities Announced
+ */
+#define QLCNIC_CAP0_LEGACY_CONTEXT (1)
+#define QLCNIC_CAP0_LEGACY_MN (1 << 2)
+#define QLCNIC_CAP0_LSO (1 << 6)
+#define QLCNIC_CAP0_JUMBO_CONTIGUOUS (1 << 7)
+#define QLCNIC_CAP0_LRO_CONTIGUOUS (1 << 8)
+
+/*
+ * Context state
+ */
+#define QLCHAL_VERSION 1
+
+#define QLCNIC_HOST_CTX_STATE_ACTIVE 2
+
+/*
+ * Rx context
+ */
+
+struct qlcnic_hostrq_sds_ring {
+ __le64 host_phys_addr; /* Ring base addr */
+ __le32 ring_size; /* Ring entries */
+ __le16 msi_index;
+ __le16 rsvd; /* Padding */
+};
+
+struct qlcnic_hostrq_rds_ring {
+ __le64 host_phys_addr; /* Ring base addr */
+ __le64 buff_size; /* Packet buffer size */
+ __le32 ring_size; /* Ring entries */
+ __le32 ring_kind; /* Class of ring */
+};
+
+struct qlcnic_hostrq_rx_ctx {
+ __le64 host_rsp_dma_addr; /* Response dma'd here */
+ __le32 capabilities[4]; /* Flag bit vector */
+ __le32 host_int_crb_mode; /* Interrupt crb usage */
+ __le32 host_rds_crb_mode; /* RDS crb usage */
+ /* These ring offsets are relative to data[0] below */
+ __le32 rds_ring_offset; /* Offset to RDS config */
+ __le32 sds_ring_offset; /* Offset to SDS config */
+ __le16 num_rds_rings; /* Count of RDS rings */
+ __le16 num_sds_rings; /* Count of SDS rings */
+ __le16 rsvd1; /* Padding */
+ __le16 rsvd2; /* Padding */
+ u8 reserved[128]; /* reserve space for future expansion*/
+ /* MUST BE 64-bit aligned.
+ The following is packed:
+ - N hostrq_rds_rings
+ - N hostrq_sds_rings */
+ char data[0];
+};
+
+struct qlcnic_cardrsp_rds_ring{
+ __le32 host_producer_crb; /* Crb to use */
+ __le32 rsvd1; /* Padding */
+};
+
+struct qlcnic_cardrsp_sds_ring {
+ __le32 host_consumer_crb; /* Crb to use */
+ __le32 interrupt_crb; /* Crb to use */
+};
+
+struct qlcnic_cardrsp_rx_ctx {
+ /* These ring offsets are relative to data[0] below */
+ __le32 rds_ring_offset; /* Offset to RDS config */
+ __le32 sds_ring_offset; /* Offset to SDS config */
+ __le32 host_ctx_state; /* Starting State */
+ __le32 num_fn_per_port; /* How many PCI fn share the port */
+ __le16 num_rds_rings; /* Count of RDS rings */
+ __le16 num_sds_rings; /* Count of SDS rings */
+ __le16 context_id; /* Handle for context */
+ u8 phys_port; /* Physical id of port */
+ u8 virt_port; /* Virtual/Logical id of port */
+ u8 reserved[128]; /* save space for future expansion */
+ /* MUST BE 64-bit aligned.
+ The following is packed:
+ - N cardrsp_rds_rings
+ - N cardrs_sds_rings */
+ char data[0];
+};
+
+#define SIZEOF_HOSTRQ_RX(HOSTRQ_RX, rds_rings, sds_rings) \
+ (sizeof(HOSTRQ_RX) + \
+ (rds_rings)*(sizeof(struct qlcnic_hostrq_rds_ring)) + \
+ (sds_rings)*(sizeof(struct qlcnic_hostrq_sds_ring)))
+
+#define SIZEOF_CARDRSP_RX(CARDRSP_RX, rds_rings, sds_rings) \
+ (sizeof(CARDRSP_RX) + \
+ (rds_rings)*(sizeof(struct qlcnic_cardrsp_rds_ring)) + \
+ (sds_rings)*(sizeof(struct qlcnic_cardrsp_sds_ring)))
+
+/*
+ * Tx context
+ */
+
+struct qlcnic_hostrq_cds_ring {
+ __le64 host_phys_addr; /* Ring base addr */
+ __le32 ring_size; /* Ring entries */
+ __le32 rsvd; /* Padding */
+};
+
+struct qlcnic_hostrq_tx_ctx {
+ __le64 host_rsp_dma_addr; /* Response dma'd here */
+ __le64 cmd_cons_dma_addr; /* */
+ __le64 dummy_dma_addr; /* */
+ __le32 capabilities[4]; /* Flag bit vector */
+ __le32 host_int_crb_mode; /* Interrupt crb usage */
+ __le32 rsvd1; /* Padding */
+ __le16 rsvd2; /* Padding */
+ __le16 interrupt_ctl;
+ __le16 msi_index;
+ __le16 rsvd3; /* Padding */
+ struct qlcnic_hostrq_cds_ring cds_ring; /* Desc of cds ring */
+ u8 reserved[128]; /* future expansion */
+};
+
+struct qlcnic_cardrsp_cds_ring {
+ __le32 host_producer_crb; /* Crb to use */
+ __le32 interrupt_crb; /* Crb to use */
+};
+
+struct qlcnic_cardrsp_tx_ctx {
+ __le32 host_ctx_state; /* Starting state */
+ __le16 context_id; /* Handle for context */
+ u8 phys_port; /* Physical id of port */
+ u8 virt_port; /* Virtual/Logical id of port */
+ struct qlcnic_cardrsp_cds_ring cds_ring; /* Card cds settings */
+ u8 reserved[128]; /* future expansion */
+};
+
+#define SIZEOF_HOSTRQ_TX(HOSTRQ_TX) (sizeof(HOSTRQ_TX))
+#define SIZEOF_CARDRSP_TX(CARDRSP_TX) (sizeof(CARDRSP_TX))
+
+/* CRB */
+
+#define QLCNIC_HOST_RDS_CRB_MODE_UNIQUE 0
+#define QLCNIC_HOST_RDS_CRB_MODE_SHARED 1
+#define QLCNIC_HOST_RDS_CRB_MODE_CUSTOM 2
+#define QLCNIC_HOST_RDS_CRB_MODE_MAX 3
+
+#define QLCNIC_HOST_INT_CRB_MODE_UNIQUE 0
+#define QLCNIC_HOST_INT_CRB_MODE_SHARED 1
+#define QLCNIC_HOST_INT_CRB_MODE_NORX 2
+#define QLCNIC_HOST_INT_CRB_MODE_NOTX 3
+#define QLCNIC_HOST_INT_CRB_MODE_NORXTX 4
+
+
+/* MAC */
+
+#define MC_COUNT_P3 38
+
+#define QLCNIC_MAC_NOOP 0
+#define QLCNIC_MAC_ADD 1
+#define QLCNIC_MAC_DEL 2
+
+struct qlcnic_mac_list_s {
+ struct list_head list;
+ uint8_t mac_addr[ETH_ALEN+2];
+};
+
+/*
+ * Interrupt coalescing defaults. The defaults are for 1500 MTU. It is
+ * adjusted based on configured MTU.
+ */
+#define QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US 3
+#define QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS 256
+#define QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS 64
+#define QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US 4
+
+#define QLCNIC_INTR_DEFAULT 0x04
+
+union qlcnic_nic_intr_coalesce_data {
+ struct {
+ u16 rx_packets;
+ u16 rx_time_us;
+ u16 tx_packets;
+ u16 tx_time_us;
+ } data;
+ u64 word;
+};
+
+struct qlcnic_nic_intr_coalesce {
+ u16 stats_time_us;
+ u16 rate_sample_time;
+ u16 flags;
+ u16 rsvd_1;
+ u32 low_threshold;
+ u32 high_threshold;
+ union qlcnic_nic_intr_coalesce_data normal;
+ union qlcnic_nic_intr_coalesce_data low;
+ union qlcnic_nic_intr_coalesce_data high;
+ union qlcnic_nic_intr_coalesce_data irq;
+};
+
+#define QLCNIC_HOST_REQUEST 0x13
+#define QLCNIC_REQUEST 0x14
+
+#define QLCNIC_MAC_EVENT 0x1
+
+#define QLCNIC_IP_UP 2
+#define QLCNIC_IP_DOWN 3
+
+/*
+ * Driver --> Firmware
+ */
+#define QLCNIC_H2C_OPCODE_START 0
+#define QLCNIC_H2C_OPCODE_CONFIG_RSS 1
+#define QLCNIC_H2C_OPCODE_CONFIG_RSS_TBL 2
+#define QLCNIC_H2C_OPCODE_CONFIG_INTR_COALESCE 3
+#define QLCNIC_H2C_OPCODE_CONFIG_LED 4
+#define QLCNIC_H2C_OPCODE_CONFIG_PROMISCUOUS 5
+#define QLCNIC_H2C_OPCODE_CONFIG_L2_MAC 6
+#define QLCNIC_H2C_OPCODE_LRO_REQUEST 7
+#define QLCNIC_H2C_OPCODE_GET_SNMP_STATS 8
+#define QLCNIC_H2C_OPCODE_PROXY_START_REQUEST 9
+#define QLCNIC_H2C_OPCODE_PROXY_STOP_REQUEST 10
+#define QLCNIC_H2C_OPCODE_PROXY_SET_MTU 11
+#define QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE 12
+#define QLCNIC_H2C_OPCODE_GET_FINGER_PRINT_REQUEST 13
+#define QLCNIC_H2C_OPCODE_INSTALL_LICENSE_REQUEST 14
+#define QLCNIC_H2C_OPCODE_GET_LICENSE_CAPABILITY_REQUEST 15
+#define QLCNIC_H2C_OPCODE_GET_NET_STATS 16
+#define QLCNIC_H2C_OPCODE_PROXY_UPDATE_P2V 17
+#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR 18
+#define QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK 19
+#define QLCNIC_H2C_OPCODE_PROXY_STOP_DONE 20
+#define QLCNIC_H2C_OPCODE_GET_LINKEVENT 21
+#define QLCNIC_C2C_OPCODE 22
+#define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING 23
+#define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO 24
+#define QLCNIC_H2C_OPCODE_LAST 25
+/*
+ * Firmware --> Driver
+ */
+
+#define QLCNIC_C2H_OPCODE_START 128
+#define QLCNIC_C2H_OPCODE_CONFIG_RSS_RESPONSE 129
+#define QLCNIC_C2H_OPCODE_CONFIG_RSS_TBL_RESPONSE 130
+#define QLCNIC_C2H_OPCODE_CONFIG_MAC_RESPONSE 131
+#define QLCNIC_C2H_OPCODE_CONFIG_PROMISCUOUS_RESPONSE 132
+#define QLCNIC_C2H_OPCODE_CONFIG_L2_MAC_RESPONSE 133
+#define QLCNIC_C2H_OPCODE_LRO_DELETE_RESPONSE 134
+#define QLCNIC_C2H_OPCODE_LRO_ADD_FAILURE_RESPONSE 135
+#define QLCNIC_C2H_OPCODE_GET_SNMP_STATS 136
+#define QLCNIC_C2H_OPCODE_GET_FINGER_PRINT_REPLY 137
+#define QLCNIC_C2H_OPCODE_INSTALL_LICENSE_REPLY 138
+#define QLCNIC_C2H_OPCODE_GET_LICENSE_CAPABILITIES_REPLY 139
+#define QLCNIC_C2H_OPCODE_GET_NET_STATS_RESPONSE 140
+#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE 141
+#define QLCNIC_C2H_OPCODE_LAST 142
+
+#define VPORT_MISS_MODE_DROP 0 /* drop all unmatched */
+#define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */
+#define VPORT_MISS_MODE_ACCEPT_MULTI 2 /* accept unmatched multicast */
+
+#define QLCNIC_LRO_REQUEST_CLEANUP 4
+
+/* Capabilites received */
+#define QLCNIC_FW_CAPABILITY_BDG (1 << 8)
+#define QLCNIC_FW_CAPABILITY_FVLANTX (1 << 9)
+#define QLCNIC_FW_CAPABILITY_HW_LRO (1 << 10)
+
+/* module types */
+#define LINKEVENT_MODULE_NOT_PRESENT 1
+#define LINKEVENT_MODULE_OPTICAL_UNKNOWN 2
+#define LINKEVENT_MODULE_OPTICAL_SRLR 3
+#define LINKEVENT_MODULE_OPTICAL_LRM 4
+#define LINKEVENT_MODULE_OPTICAL_SFP_1G 5
+#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE 6
+#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN 7
+#define LINKEVENT_MODULE_TWINAX 8
+
+#define LINKSPEED_10GBPS 10000
+#define LINKSPEED_1GBPS 1000
+#define LINKSPEED_100MBPS 100
+#define LINKSPEED_10MBPS 10
+
+#define LINKSPEED_ENCODED_10MBPS 0
+#define LINKSPEED_ENCODED_100MBPS 1
+#define LINKSPEED_ENCODED_1GBPS 2
+
+#define LINKEVENT_AUTONEG_DISABLED 0
+#define LINKEVENT_AUTONEG_ENABLED 1
+
+#define LINKEVENT_HALF_DUPLEX 0
+#define LINKEVENT_FULL_DUPLEX 1
+
+#define LINKEVENT_LINKSPEED_MBPS 0
+#define LINKEVENT_LINKSPEED_ENCODED 1
+
+#define AUTO_FW_RESET_ENABLED 0x01
+/* firmware response header:
+ * 63:58 - message type
+ * 57:56 - owner
+ * 55:53 - desc count
+ * 52:48 - reserved
+ * 47:40 - completion id
+ * 39:32 - opcode
+ * 31:16 - error code
+ * 15:00 - reserved
+ */
+#define qlcnic_get_nic_msg_opcode(msg_hdr) \
+ ((msg_hdr >> 32) & 0xFF)
+
+struct qlcnic_fw_msg {
+ union {
+ struct {
+ u64 hdr;
+ u64 body[7];
+ };
+ u64 words[8];
+ };
+};
+
+struct qlcnic_nic_req {
+ __le64 qhdr;
+ __le64 req_hdr;
+ __le64 words[6];
+};
+
+struct qlcnic_mac_req {
+ u8 op;
+ u8 tag;
+ u8 mac_addr[6];
+};
+
+#define QLCNIC_MSI_ENABLED 0x02
+#define QLCNIC_MSIX_ENABLED 0x04
+#define QLCNIC_LRO_ENABLED 0x08
+#define QLCNIC_BRIDGE_ENABLED 0X10
+#define QLCNIC_DIAG_ENABLED 0x20
+#define QLCNIC_IS_MSI_FAMILY(adapter) \
+ ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
+
+#define MSIX_ENTRIES_PER_ADAPTER NUM_STS_DESC_RINGS
+#define QLCNIC_MSIX_TBL_SPACE 8192
+#define QLCNIC_PCI_REG_MSIX_TBL 0x44
+
+#define QLCNIC_NETDEV_WEIGHT 128
+#define QLCNIC_ADAPTER_UP_MAGIC 777
+
+#define __QLCNIC_FW_ATTACHED 0
+#define __QLCNIC_DEV_UP 1
+#define __QLCNIC_RESETTING 2
+#define __QLCNIC_START_FW 4
+
+#define QLCNIC_INTERRUPT_TEST 1
+#define QLCNIC_LOOPBACK_TEST 2
+
+struct qlcnic_adapter {
+ struct qlcnic_hardware_context ahw;
+
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct list_head mac_list;
+
+ spinlock_t tx_clean_lock;
+
+ u16 num_txd;
+ u16 num_rxd;
+ u16 num_jumbo_rxd;
+ u16 num_lro_rxd;
+
+ u8 max_rds_rings;
+ u8 max_sds_rings;
+ u8 driver_mismatch;
+ u8 msix_supported;
+ u8 rx_csum;
+ u8 pci_using_dac;
+ u8 portnum;
+ u8 physical_port;
+
+ u8 mc_enabled;
+ u8 max_mc_count;
+ u8 rss_supported;
+ u8 rsrvd1;
+ u8 fw_wait_cnt;
+ u8 fw_fail_cnt;
+ u8 tx_timeo_cnt;
+ u8 need_fw_reset;
+
+ u8 has_link_events;
+ u8 fw_type;
+ u16 tx_context_id;
+ u16 mtu;
+ u16 is_up;
+
+ u16 link_speed;
+ u16 link_duplex;
+ u16 link_autoneg;
+ u16 module_type;
+
+ u32 capabilities;
+ u32 flags;
+ u32 irq;
+ u32 temp;
+
+ u32 int_vec_bit;
+ u32 heartbit;
+
+ u8 dev_state;
+ u8 diag_test;
+ u8 diag_cnt;
+ u8 rsrd1;
+ u16 rsrd2;
+
+ u8 mac_addr[ETH_ALEN];
+
+ struct qlcnic_adapter_stats stats;
+
+ struct qlcnic_recv_context recv_ctx;
+ struct qlcnic_host_tx_ring *tx_ring;
+
+ void __iomem *tgt_mask_reg;
+ void __iomem *tgt_status_reg;
+ void __iomem *crb_int_state_reg;
+ void __iomem *isr_int_vec;
+
+ struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER];
+
+ struct delayed_work fw_work;
+
+ struct work_struct tx_timeout_task;
+
+ struct qlcnic_nic_intr_coalesce coal;
+
+ unsigned long state;
+ __le32 file_prd_off; /*File fw product offset*/
+ u32 fw_version;
+ const struct firmware *fw;
+};
+
+int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val);
+int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val);
+
+u32 qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off);
+int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *, ulong off, u32 data);
+int qlcnic_pci_mem_write_2M(struct qlcnic_adapter *, u64 off, u64 data);
+int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *, u64 off, u64 *data);
+
+#define QLCRD32(adapter, off) \
+ (qlcnic_hw_read_wx_2M(adapter, off))
+#define QLCWR32(adapter, off, val) \
+ (qlcnic_hw_write_wx_2M(adapter, off, val))
+
+int qlcnic_pcie_sem_lock(struct qlcnic_adapter *, int, u32);
+void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
+
+#define qlcnic_rom_lock(a) \
+ qlcnic_pcie_sem_lock((a), 2, QLCNIC_ROM_LOCK_ID)
+#define qlcnic_rom_unlock(a) \
+ qlcnic_pcie_sem_unlock((a), 2)
+#define qlcnic_phy_lock(a) \
+ qlcnic_pcie_sem_lock((a), 3, QLCNIC_PHY_LOCK_ID)
+#define qlcnic_phy_unlock(a) \
+ qlcnic_pcie_sem_unlock((a), 3)
+#define qlcnic_api_lock(a) \
+ qlcnic_pcie_sem_lock((a), 5, 0)
+#define qlcnic_api_unlock(a) \
+ qlcnic_pcie_sem_unlock((a), 5)
+#define qlcnic_sw_lock(a) \
+ qlcnic_pcie_sem_lock((a), 6, 0)
+#define qlcnic_sw_unlock(a) \
+ qlcnic_pcie_sem_unlock((a), 6)
+#define crb_win_lock(a) \
+ qlcnic_pcie_sem_lock((a), 7, QLCNIC_CRB_WIN_LOCK_ID)
+#define crb_win_unlock(a) \
+ qlcnic_pcie_sem_unlock((a), 7)
+
+int qlcnic_get_board_info(struct qlcnic_adapter *adapter);
+int qlcnic_wol_supported(struct qlcnic_adapter *adapter);
+int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate);
+
+/* Functions from qlcnic_init.c */
+int qlcnic_phantom_init(struct qlcnic_adapter *adapter);
+int qlcnic_load_firmware(struct qlcnic_adapter *adapter);
+int qlcnic_need_fw_reset(struct qlcnic_adapter *adapter);
+void qlcnic_request_firmware(struct qlcnic_adapter *adapter);
+void qlcnic_release_firmware(struct qlcnic_adapter *adapter);
+int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter);
+
+int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp);
+int qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr,
+ u8 *bytes, size_t size);
+int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter);
+void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter);
+
+void __iomem *qlcnic_get_ioaddr(struct qlcnic_adapter *, u32);
+
+int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter);
+void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter);
+
+void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter);
+void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter);
+
+int qlcnic_init_firmware(struct qlcnic_adapter *adapter);
+void qlcnic_watchdog_task(struct work_struct *work);
+void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid,
+ struct qlcnic_host_rds_ring *rds_ring);
+int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max);
+void qlcnic_set_multi(struct net_device *netdev);
+void qlcnic_free_mac_list(struct qlcnic_adapter *adapter);
+int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
+int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter);
+int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable);
+int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, u32 ip, int cmd);
+int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable);
+void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup);
+
+int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
+int qlcnic_change_mtu(struct net_device *netdev, int new_mtu);
+int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable);
+int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable);
+int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
+void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring);
+int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac);
+void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter);
+int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
+
+/* Functions from qlcnic_main.c */
+int qlcnic_reset_context(struct qlcnic_adapter *);
+u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
+ u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd);
+void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
+int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
+int qlcnic_check_loopback_buff(unsigned char *data);
+netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
+
+/*
+ * QLOGIC Board information
+ */
+
+#define QLCNIC_MAX_BOARD_NAME_LEN 100
+struct qlcnic_brdinfo {
+ unsigned short vendor;
+ unsigned short device;
+ unsigned short sub_vendor;
+ unsigned short sub_device;
+ char short_name[QLCNIC_MAX_BOARD_NAME_LEN];
+};
+
+static const struct qlcnic_brdinfo qlcnic_boards[] = {
+ {0x1077, 0x8020, 0x1077, 0x203,
+ "8200 Series Single Port 10GbE Converged Network Adapter "
+ "(TCP/IP Networking)"},
+ {0x1077, 0x8020, 0x1077, 0x207,
+ "8200 Series Dual Port 10GbE Converged Network Adapter "
+ "(TCP/IP Networking)"},
+ {0x1077, 0x8020, 0x1077, 0x20b,
+ "3200 Series Dual Port 10Gb Intelligent Ethernet Adapter"},
+ {0x1077, 0x8020, 0x1077, 0x20c,
+ "3200 Series Quad Port 1Gb Intelligent Ethernet Adapter"},
+ {0x1077, 0x8020, 0x1077, 0x20f,
+ "3200 Series Single Port 10Gb Intelligent Ethernet Adapter"},
+ {0x1077, 0x8020, 0x0, 0x0, "cLOM8214 1/10GbE Controller"},
+};
+
+#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(qlcnic_boards)
+
+static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
+{
+ smp_mb();
+ if (tx_ring->producer < tx_ring->sw_consumer)
+ return tx_ring->sw_consumer - tx_ring->producer;
+ else
+ return tx_ring->sw_consumer + tx_ring->num_desc -
+ tx_ring->producer;
+}
+
+extern const struct ethtool_ops qlcnic_ethtool_ops;
+
+#endif /* __QLCNIC_H_ */
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
new file mode 100644
index 000000000000..0a6a39914aec
--- /dev/null
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2009 - QLogic 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".
+ *
+ */
+
+#include "qlcnic.h"
+
+static u32
+qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
+{
+ u32 rsp;
+ int timeout = 0;
+
+ do {
+ /* give atleast 1ms for firmware to respond */
+ msleep(1);
+
+ if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT)
+ return QLCNIC_CDRP_RSP_TIMEOUT;
+
+ rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET);
+ } while (!QLCNIC_CDRP_IS_RSP(rsp));
+
+ return rsp;
+}
+
+u32
+qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
+ u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd)
+{
+ u32 rsp;
+ u32 signature;
+ u32 rcode = QLCNIC_RCODE_SUCCESS;
+ struct pci_dev *pdev = adapter->pdev;
+
+ signature = QLCNIC_CDRP_SIGNATURE_MAKE(pci_fn, version);
+
+ /* Acquire semaphore before accessing CRB */
+ if (qlcnic_api_lock(adapter))
+ return QLCNIC_RCODE_TIMEOUT;
+
+ QLCWR32(adapter, QLCNIC_SIGN_CRB_OFFSET, signature);
+ QLCWR32(adapter, QLCNIC_ARG1_CRB_OFFSET, arg1);
+ QLCWR32(adapter, QLCNIC_ARG2_CRB_OFFSET, arg2);
+ QLCWR32(adapter, QLCNIC_ARG3_CRB_OFFSET, arg3);
+ QLCWR32(adapter, QLCNIC_CDRP_CRB_OFFSET, QLCNIC_CDRP_FORM_CMD(cmd));
+
+ rsp = qlcnic_poll_rsp(adapter);
+
+ if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) {
+ dev_err(&pdev->dev, "card response timeout.\n");
+ rcode = QLCNIC_RCODE_TIMEOUT;
+ } else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
+ rcode = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+ dev_err(&pdev->dev, "failed card response code:0x%x\n",
+ rcode);
+ }
+
+ /* Release semaphore */
+ qlcnic_api_unlock(adapter);
+
+ return rcode;
+}
+
+int
+qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
+{
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+ if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) {
+ if (qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ QLCHAL_VERSION,
+ recv_ctx->context_id,
+ mtu,
+ 0,
+ QLCNIC_CDRP_CMD_SET_MTU)) {
+
+ dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static int
+qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
+{
+ void *addr;
+ struct qlcnic_hostrq_rx_ctx *prq;
+ struct qlcnic_cardrsp_rx_ctx *prsp;
+ struct qlcnic_hostrq_rds_ring *prq_rds;
+ struct qlcnic_hostrq_sds_ring *prq_sds;
+ struct qlcnic_cardrsp_rds_ring *prsp_rds;
+ struct qlcnic_cardrsp_sds_ring *prsp_sds;
+ struct qlcnic_host_rds_ring *rds_ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+
+ dma_addr_t hostrq_phys_addr, cardrsp_phys_addr;
+ u64 phys_addr;
+
+ int i, nrds_rings, nsds_rings;
+ size_t rq_size, rsp_size;
+ u32 cap, reg, val;
+ int err;
+
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+ nrds_rings = adapter->max_rds_rings;
+ nsds_rings = adapter->max_sds_rings;
+
+ rq_size =
+ SIZEOF_HOSTRQ_RX(struct qlcnic_hostrq_rx_ctx, nrds_rings,
+ nsds_rings);
+ rsp_size =
+ SIZEOF_CARDRSP_RX(struct qlcnic_cardrsp_rx_ctx, nrds_rings,
+ nsds_rings);
+
+ addr = pci_alloc_consistent(adapter->pdev,
+ rq_size, &hostrq_phys_addr);
+ if (addr == NULL)
+ return -ENOMEM;
+ prq = (struct qlcnic_hostrq_rx_ctx *)addr;
+
+ addr = pci_alloc_consistent(adapter->pdev,
+ rsp_size, &cardrsp_phys_addr);
+ if (addr == NULL) {
+ err = -ENOMEM;
+ goto out_free_rq;
+ }
+ prsp = (struct qlcnic_cardrsp_rx_ctx *)addr;
+
+ prq->host_rsp_dma_addr = cpu_to_le64(cardrsp_phys_addr);
+
+ cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN);
+ cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);
+
+ prq->capabilities[0] = cpu_to_le32(cap);
+ prq->host_int_crb_mode =
+ cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
+ prq->host_rds_crb_mode =
+ cpu_to_le32(QLCNIC_HOST_RDS_CRB_MODE_UNIQUE);
+
+ prq->num_rds_rings = cpu_to_le16(nrds_rings);
+ prq->num_sds_rings = cpu_to_le16(nsds_rings);
+ prq->rds_ring_offset = cpu_to_le32(0);
+
+ val = le32_to_cpu(prq->rds_ring_offset) +
+ (sizeof(struct qlcnic_hostrq_rds_ring) * nrds_rings);
+ prq->sds_ring_offset = cpu_to_le32(val);
+
+ prq_rds = (struct qlcnic_hostrq_rds_ring *)(prq->data +
+ le32_to_cpu(prq->rds_ring_offset));
+
+ for (i = 0; i < nrds_rings; i++) {
+
+ rds_ring = &recv_ctx->rds_rings[i];
+
+ prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr);
+ prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc);
+ prq_rds[i].ring_kind = cpu_to_le32(i);
+ prq_rds[i].buff_size = cpu_to_le64(rds_ring->dma_size);
+ }
+
+ prq_sds = (struct qlcnic_hostrq_sds_ring *)(prq->data +
+ le32_to_cpu(prq->sds_ring_offset));
+
+ for (i = 0; i < nsds_rings; i++) {
+
+ sds_ring = &recv_ctx->sds_rings[i];
+
+ prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr);
+ prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc);
+ prq_sds[i].msi_index = cpu_to_le16(i);
+ }
+
+ phys_addr = hostrq_phys_addr;
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ QLCHAL_VERSION,
+ (u32)(phys_addr >> 32),
+ (u32)(phys_addr & 0xffffffff),
+ rq_size,
+ QLCNIC_CDRP_CMD_CREATE_RX_CTX);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to create rx ctx in firmware%d\n", err);
+ goto out_free_rsp;
+ }
+
+
+ prsp_rds = ((struct qlcnic_cardrsp_rds_ring *)
+ &prsp->data[le32_to_cpu(prsp->rds_ring_offset)]);
+
+ for (i = 0; i < le16_to_cpu(prsp->num_rds_rings); i++) {
+ rds_ring = &recv_ctx->rds_rings[i];
+
+ reg = le32_to_cpu(prsp_rds[i].host_producer_crb);
+ rds_ring->crb_rcv_producer = qlcnic_get_ioaddr(adapter,
+ QLCNIC_REG(reg - 0x200));
+ }
+
+ prsp_sds = ((struct qlcnic_cardrsp_sds_ring *)
+ &prsp->data[le32_to_cpu(prsp->sds_ring_offset)]);
+
+ for (i = 0; i < le16_to_cpu(prsp->num_sds_rings); i++) {
+ sds_ring = &recv_ctx->sds_rings[i];
+
+ reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
+ sds_ring->crb_sts_consumer = qlcnic_get_ioaddr(adapter,
+ QLCNIC_REG(reg - 0x200));
+
+ reg = le32_to_cpu(prsp_sds[i].interrupt_crb);
+ sds_ring->crb_intr_mask = qlcnic_get_ioaddr(adapter,
+ QLCNIC_REG(reg - 0x200));
+ }
+
+ recv_ctx->state = le32_to_cpu(prsp->host_ctx_state);
+ recv_ctx->context_id = le16_to_cpu(prsp->context_id);
+ recv_ctx->virt_port = prsp->virt_port;
+
+out_free_rsp:
+ pci_free_consistent(adapter->pdev, rsp_size, prsp, cardrsp_phys_addr);
+out_free_rq:
+ pci_free_consistent(adapter->pdev, rq_size, prq, hostrq_phys_addr);
+ return err;
+}
+
+static void
+qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+ if (qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ QLCHAL_VERSION,
+ recv_ctx->context_id,
+ QLCNIC_DESTROY_CTX_RESET,
+ 0,
+ QLCNIC_CDRP_CMD_DESTROY_RX_CTX)) {
+
+ dev_err(&adapter->pdev->dev,
+ "Failed to destroy rx ctx in firmware\n");
+ }
+}
+
+static int
+qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hostrq_tx_ctx *prq;
+ struct qlcnic_hostrq_cds_ring *prq_cds;
+ struct qlcnic_cardrsp_tx_ctx *prsp;
+ void *rq_addr, *rsp_addr;
+ size_t rq_size, rsp_size;
+ u32 temp;
+ int err;
+ u64 phys_addr;
+ dma_addr_t rq_phys_addr, rsp_phys_addr;
+ struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+
+ rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx);
+ rq_addr = pci_alloc_consistent(adapter->pdev,
+ rq_size, &rq_phys_addr);
+ if (!rq_addr)
+ return -ENOMEM;
+
+ rsp_size = SIZEOF_CARDRSP_TX(struct qlcnic_cardrsp_tx_ctx);
+ rsp_addr = pci_alloc_consistent(adapter->pdev,
+ rsp_size, &rsp_phys_addr);
+ if (!rsp_addr) {
+ err = -ENOMEM;
+ goto out_free_rq;
+ }
+
+ memset(rq_addr, 0, rq_size);
+ prq = (struct qlcnic_hostrq_tx_ctx *)rq_addr;
+
+ memset(rsp_addr, 0, rsp_size);
+ prsp = (struct qlcnic_cardrsp_tx_ctx *)rsp_addr;
+
+ prq->host_rsp_dma_addr = cpu_to_le64(rsp_phys_addr);
+
+ temp = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN |
+ QLCNIC_CAP0_LSO);
+ prq->capabilities[0] = cpu_to_le32(temp);
+
+ prq->host_int_crb_mode =
+ cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
+
+ prq->interrupt_ctl = 0;
+ prq->msi_index = 0;
+ prq->cmd_cons_dma_addr = cpu_to_le64(tx_ring->hw_cons_phys_addr);
+
+ prq_cds = &prq->cds_ring;
+
+ prq_cds->host_phys_addr = cpu_to_le64(tx_ring->phys_addr);
+ prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc);
+
+ phys_addr = rq_phys_addr;
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ QLCHAL_VERSION,
+ (u32)(phys_addr >> 32),
+ ((u32)phys_addr & 0xffffffff),
+ rq_size,
+ QLCNIC_CDRP_CMD_CREATE_TX_CTX);
+
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
+ tx_ring->crb_cmd_producer = qlcnic_get_ioaddr(adapter,
+ QLCNIC_REG(temp - 0x200));
+
+ adapter->tx_context_id =
+ le16_to_cpu(prsp->context_id);
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "Failed to create tx ctx in firmware%d\n", err);
+ err = -EIO;
+ }
+
+ pci_free_consistent(adapter->pdev, rsp_size, rsp_addr, rsp_phys_addr);
+
+out_free_rq:
+ pci_free_consistent(adapter->pdev, rq_size, rq_addr, rq_phys_addr);
+
+ return err;
+}
+
+static void
+qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter)
+{
+ if (qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ QLCHAL_VERSION,
+ adapter->tx_context_id,
+ QLCNIC_DESTROY_CTX_RESET,
+ 0,
+ QLCNIC_CDRP_CMD_DESTROY_TX_CTX)) {
+
+ dev_err(&adapter->pdev->dev,
+ "Failed to destroy tx ctx in firmware\n");
+ }
+}
+
+int
+qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val)
+{
+
+ if (qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ QLCHAL_VERSION,
+ reg,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_READ_PHY)) {
+
+ return -EIO;
+ }
+
+ return QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+}
+
+int
+qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val)
+{
+ return qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ QLCHAL_VERSION,
+ reg,
+ val,
+ 0,
+ QLCNIC_CDRP_CMD_WRITE_PHY);
+}
+
+int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
+{
+ void *addr;
+ int err;
+ int ring;
+ struct qlcnic_recv_context *recv_ctx;
+ struct qlcnic_host_rds_ring *rds_ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_host_tx_ring *tx_ring;
+
+ struct pci_dev *pdev = adapter->pdev;
+
+ recv_ctx = &adapter->recv_ctx;
+ tx_ring = adapter->tx_ring;
+
+ tx_ring->hw_consumer = (__le32 *)pci_alloc_consistent(pdev, sizeof(u32),
+ &tx_ring->hw_cons_phys_addr);
+ if (tx_ring->hw_consumer == NULL) {
+ dev_err(&pdev->dev, "failed to allocate tx consumer\n");
+ return -ENOMEM;
+ }
+ *(tx_ring->hw_consumer) = 0;
+
+ /* cmd desc ring */
+ addr = pci_alloc_consistent(pdev, TX_DESC_RINGSIZE(tx_ring),
+ &tx_ring->phys_addr);
+
+ if (addr == NULL) {
+ dev_err(&pdev->dev, "failed to allocate tx desc ring\n");
+ return -ENOMEM;
+ }
+
+ tx_ring->desc_head = (struct cmd_desc_type0 *)addr;
+
+ for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+ rds_ring = &recv_ctx->rds_rings[ring];
+ addr = pci_alloc_consistent(adapter->pdev,
+ RCV_DESC_RINGSIZE(rds_ring),
+ &rds_ring->phys_addr);
+ if (addr == NULL) {
+ dev_err(&pdev->dev,
+ "failed to allocate rds ring [%d]\n", ring);
+ err = -ENOMEM;
+ goto err_out_free;
+ }
+ rds_ring->desc_head = (struct rcv_desc *)addr;
+
+ }
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+
+ addr = pci_alloc_consistent(adapter->pdev,
+ STATUS_DESC_RINGSIZE(sds_ring),
+ &sds_ring->phys_addr);
+ if (addr == NULL) {
+ dev_err(&pdev->dev,
+ "failed to allocate sds ring [%d]\n", ring);
+ err = -ENOMEM;
+ goto err_out_free;
+ }
+ sds_ring->desc_head = (struct status_desc *)addr;
+ }
+
+
+ err = qlcnic_fw_cmd_create_rx_ctx(adapter);
+ if (err)
+ goto err_out_free;
+ err = qlcnic_fw_cmd_create_tx_ctx(adapter);
+ if (err)
+ goto err_out_free;
+
+ set_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
+ return 0;
+
+err_out_free:
+ qlcnic_free_hw_resources(adapter);
+ return err;
+}
+
+void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_recv_context *recv_ctx;
+ struct qlcnic_host_rds_ring *rds_ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_host_tx_ring *tx_ring;
+ int ring;
+
+
+ if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) {
+ qlcnic_fw_cmd_destroy_rx_ctx(adapter);
+ qlcnic_fw_cmd_destroy_tx_ctx(adapter);
+
+ /* Allow dma queues to drain after context reset */
+ msleep(20);
+ }
+
+ recv_ctx = &adapter->recv_ctx;
+
+ tx_ring = adapter->tx_ring;
+ if (tx_ring->hw_consumer != NULL) {
+ pci_free_consistent(adapter->pdev,
+ sizeof(u32),
+ tx_ring->hw_consumer,
+ tx_ring->hw_cons_phys_addr);
+ tx_ring->hw_consumer = NULL;
+ }
+
+ if (tx_ring->desc_head != NULL) {
+ pci_free_consistent(adapter->pdev,
+ TX_DESC_RINGSIZE(tx_ring),
+ tx_ring->desc_head, tx_ring->phys_addr);
+ tx_ring->desc_head = NULL;
+ }
+
+ for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+ rds_ring = &recv_ctx->rds_rings[ring];
+
+ if (rds_ring->desc_head != NULL) {
+ pci_free_consistent(adapter->pdev,
+ RCV_DESC_RINGSIZE(rds_ring),
+ rds_ring->desc_head,
+ rds_ring->phys_addr);
+ rds_ring->desc_head = NULL;
+ }
+ }
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+
+ if (sds_ring->desc_head != NULL) {
+ pci_free_consistent(adapter->pdev,
+ STATUS_DESC_RINGSIZE(sds_ring),
+ sds_ring->desc_head,
+ sds_ring->phys_addr);
+ sds_ring->desc_head = NULL;
+ }
+ }
+}
+
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
new file mode 100644
index 000000000000..f83e15fe3e1b
--- /dev/null
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -0,0 +1,1032 @@
+/*
+ * Copyright (C) 2009 - QLogic 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".
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+
+#include "qlcnic.h"
+
+struct qlcnic_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+};
+
+#define QLC_SIZEOF(m) FIELD_SIZEOF(struct qlcnic_adapter, m)
+#define QLC_OFF(m) offsetof(struct qlcnic_adapter, m)
+
+static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
+ {"xmit_called",
+ QLC_SIZEOF(stats.xmitcalled), QLC_OFF(stats.xmitcalled)},
+ {"xmit_finished",
+ QLC_SIZEOF(stats.xmitfinished), QLC_OFF(stats.xmitfinished)},
+ {"rx_dropped",
+ QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
+ {"tx_dropped",
+ QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
+ {"csummed",
+ QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
+ {"rx_pkts",
+ QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
+ {"lro_pkts",
+ QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
+ {"rx_bytes",
+ QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
+ {"tx_bytes",
+ QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
+ {"lrobytes",
+ QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
+ {"lso_frames",
+ QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
+ {"xmit_on",
+ QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
+ {"xmit_off",
+ QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
+ {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
+ QLC_OFF(stats.skb_alloc_failure)},
+
+};
+
+#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
+
+static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
+ "Register_Test_on_offline",
+ "Link_Test_on_offline",
+ "Interrupt_Test_offline",
+ "Loopback_Test_offline"
+};
+
+#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
+
+#define QLCNIC_RING_REGS_COUNT 20
+#define QLCNIC_RING_REGS_LEN (QLCNIC_RING_REGS_COUNT * sizeof(u32))
+#define QLCNIC_MAX_EEPROM_LEN 1024
+
+static const u32 diag_registers[] = {
+ CRB_CMDPEG_STATE,
+ CRB_RCVPEG_STATE,
+ CRB_XG_STATE_P3,
+ CRB_FW_CAPABILITIES_1,
+ ISR_INT_STATE_REG,
+ QLCNIC_CRB_DEV_REF_COUNT,
+ QLCNIC_CRB_DEV_STATE,
+ QLCNIC_CRB_DRV_STATE,
+ QLCNIC_CRB_DRV_SCRATCH,
+ QLCNIC_CRB_DEV_PARTITION_INFO,
+ QLCNIC_CRB_DRV_IDC_VER,
+ QLCNIC_PEG_ALIVE_COUNTER,
+ QLCNIC_PEG_HALT_STATUS1,
+ QLCNIC_PEG_HALT_STATUS2,
+ QLCNIC_CRB_PEG_NET_0+0x3c,
+ QLCNIC_CRB_PEG_NET_1+0x3c,
+ QLCNIC_CRB_PEG_NET_2+0x3c,
+ QLCNIC_CRB_PEG_NET_4+0x3c,
+ -1
+};
+
+static int qlcnic_get_regs_len(struct net_device *dev)
+{
+ return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN;
+}
+
+static int qlcnic_get_eeprom_len(struct net_device *dev)
+{
+ return QLCNIC_FLASH_TOTAL_SIZE;
+}
+
+static void
+qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ u32 fw_major, fw_minor, fw_build;
+
+ fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+ fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
+ fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+ sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
+
+ strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+ strlcpy(drvinfo->driver, qlcnic_driver_name, 32);
+ strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 32);
+}
+
+static int
+qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ int check_sfp_module = 0;
+ u16 pcifn = adapter->ahw.pci_func;
+
+ /* read which mode */
+ if (adapter->ahw.port_type == QLCNIC_GBE) {
+ ecmd->supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full);
+
+ ecmd->advertising = (ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full);
+
+ ecmd->speed = adapter->link_speed;
+ ecmd->duplex = adapter->link_duplex;
+ ecmd->autoneg = adapter->link_autoneg;
+
+ } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
+ u32 val;
+
+ val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
+ if (val == QLCNIC_PORT_MODE_802_3_AP) {
+ ecmd->supported = SUPPORTED_1000baseT_Full;
+ ecmd->advertising = ADVERTISED_1000baseT_Full;
+ } else {
+ ecmd->supported = SUPPORTED_10000baseT_Full;
+ ecmd->advertising = ADVERTISED_10000baseT_Full;
+ }
+
+ if (netif_running(dev) && adapter->has_link_events) {
+ ecmd->speed = adapter->link_speed;
+ ecmd->autoneg = adapter->link_autoneg;
+ ecmd->duplex = adapter->link_duplex;
+ goto skip;
+ }
+
+ val = QLCRD32(adapter, P3_LINK_SPEED_REG(pcifn));
+ ecmd->speed = P3_LINK_SPEED_MHZ *
+ P3_LINK_SPEED_VAL(pcifn, val);
+ ecmd->duplex = DUPLEX_FULL;
+ ecmd->autoneg = AUTONEG_DISABLE;
+ } else
+ return -EIO;
+
+skip:
+ ecmd->phy_address = adapter->physical_port;
+ ecmd->transceiver = XCVR_EXTERNAL;
+
+ switch (adapter->ahw.board_type) {
+ case QLCNIC_BRDTYPE_P3_REF_QG:
+ case QLCNIC_BRDTYPE_P3_4_GB:
+ case QLCNIC_BRDTYPE_P3_4_GB_MM:
+
+ ecmd->supported |= SUPPORTED_Autoneg;
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ case QLCNIC_BRDTYPE_P3_10G_CX4:
+ case QLCNIC_BRDTYPE_P3_10G_CX4_LP:
+ case QLCNIC_BRDTYPE_P3_10000_BASE_T:
+ ecmd->supported |= SUPPORTED_TP;
+ ecmd->advertising |= ADVERTISED_TP;
+ ecmd->port = PORT_TP;
+ ecmd->autoneg = adapter->link_autoneg;
+ break;
+ case QLCNIC_BRDTYPE_P3_IMEZ:
+ case QLCNIC_BRDTYPE_P3_XG_LOM:
+ case QLCNIC_BRDTYPE_P3_HMEZ:
+ ecmd->supported |= SUPPORTED_MII;
+ ecmd->advertising |= ADVERTISED_MII;
+ ecmd->port = PORT_MII;
+ ecmd->autoneg = AUTONEG_DISABLE;
+ break;
+ case QLCNIC_BRDTYPE_P3_10G_SFP_PLUS:
+ case QLCNIC_BRDTYPE_P3_10G_SFP_CT:
+ case QLCNIC_BRDTYPE_P3_10G_SFP_QT:
+ ecmd->advertising |= ADVERTISED_TP;
+ ecmd->supported |= SUPPORTED_TP;
+ check_sfp_module = netif_running(dev) &&
+ adapter->has_link_events;
+ case QLCNIC_BRDTYPE_P3_10G_XFP:
+ ecmd->supported |= SUPPORTED_FIBRE;
+ ecmd->advertising |= ADVERTISED_FIBRE;
+ ecmd->port = PORT_FIBRE;
+ ecmd->autoneg = AUTONEG_DISABLE;
+ break;
+ case QLCNIC_BRDTYPE_P3_10G_TP:
+ if (adapter->ahw.port_type == QLCNIC_XGBE) {
+ ecmd->autoneg = AUTONEG_DISABLE;
+ ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
+ ecmd->advertising |=
+ (ADVERTISED_FIBRE | ADVERTISED_TP);
+ ecmd->port = PORT_FIBRE;
+ check_sfp_module = netif_running(dev) &&
+ adapter->has_link_events;
+ } else {
+ ecmd->autoneg = AUTONEG_ENABLE;
+ ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
+ ecmd->advertising |=
+ (ADVERTISED_TP | ADVERTISED_Autoneg);
+ ecmd->port = PORT_TP;
+ }
+ break;
+ default:
+ dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
+ adapter->ahw.board_type);
+ return -EIO;
+ }
+
+ if (check_sfp_module) {
+ switch (adapter->module_type) {
+ case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
+ case LINKEVENT_MODULE_OPTICAL_SRLR:
+ case LINKEVENT_MODULE_OPTICAL_LRM:
+ case LINKEVENT_MODULE_OPTICAL_SFP_1G:
+ ecmd->port = PORT_FIBRE;
+ break;
+ case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
+ case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
+ case LINKEVENT_MODULE_TWINAX:
+ ecmd->port = PORT_TP;
+ break;
+ default:
+ ecmd->port = PORT_OTHER;
+ }
+ }
+
+ return 0;
+}
+
+static int
+qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ __u32 status;
+
+ /* read which mode */
+ if (adapter->ahw.port_type == QLCNIC_GBE) {
+ /* autonegotiation */
+ if (qlcnic_fw_cmd_set_phy(adapter,
+ QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG,
+ ecmd->autoneg) != 0)
+ return -EIO;
+ else
+ adapter->link_autoneg = ecmd->autoneg;
+
+ if (qlcnic_fw_cmd_query_phy(adapter,
+ QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
+ &status) != 0)
+ return -EIO;
+
+ switch (ecmd->speed) {
+ case SPEED_10:
+ qlcnic_set_phy_speed(status, 0);
+ break;
+ case SPEED_100:
+ qlcnic_set_phy_speed(status, 1);
+ break;
+ case SPEED_1000:
+ qlcnic_set_phy_speed(status, 2);
+ break;
+ }
+
+ if (ecmd->duplex == DUPLEX_HALF)
+ qlcnic_clear_phy_duplex(status);
+ if (ecmd->duplex == DUPLEX_FULL)
+ qlcnic_set_phy_duplex(status);
+ if (qlcnic_fw_cmd_set_phy(adapter,
+ QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
+ *((int *)&status)) != 0)
+ return -EIO;
+ else {
+ adapter->link_speed = ecmd->speed;
+ adapter->link_duplex = ecmd->duplex;
+ }
+ } else
+ return -EOPNOTSUPP;
+
+ if (!netif_running(dev))
+ return 0;
+
+ dev->netdev_ops->ndo_stop(dev);
+ return dev->netdev_ops->ndo_open(dev);
+}
+
+static void
+qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_host_sds_ring *sds_ring;
+ u32 *regs_buff = p;
+ int ring, i = 0;
+
+ memset(p, 0, qlcnic_get_regs_len(dev));
+ regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) |
+ (adapter->pdev)->device;
+
+ for (i = 0; diag_registers[i] != -1; i++)
+ regs_buff[i] = QLCRD32(adapter, diag_registers[i]);
+
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ return;
+
+ regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
+
+ regs_buff[i++] = 1; /* No. of tx ring */
+ regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer));
+ regs_buff[i++] = readl(adapter->tx_ring->crb_cmd_producer);
+
+ regs_buff[i++] = 2; /* No. of rx ring */
+ regs_buff[i++] = readl(recv_ctx->rds_rings[0].crb_rcv_producer);
+ regs_buff[i++] = readl(recv_ctx->rds_rings[1].crb_rcv_producer);
+
+ regs_buff[i++] = adapter->max_sds_rings;
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &(recv_ctx->sds_rings[ring]);
+ regs_buff[i++] = readl(sds_ring->crb_sts_consumer);
+ }
+}
+
+static u32 qlcnic_test_link(struct net_device *dev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ u32 val;
+
+ val = QLCRD32(adapter, CRB_XG_STATE_P3);
+ val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val);
+ return (val == XG_LINK_UP_P3) ? 0 : 1;
+}
+
+static int
+qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+ u8 *bytes)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ int offset;
+ int ret;
+
+ if (eeprom->len == 0)
+ return -EINVAL;
+
+ eeprom->magic = (adapter->pdev)->vendor |
+ ((adapter->pdev)->device << 16);
+ offset = eeprom->offset;
+
+ ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
+ eeprom->len);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void
+qlcnic_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+ ring->rx_pending = adapter->num_rxd;
+ ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
+ ring->rx_jumbo_pending += adapter->num_lro_rxd;
+ ring->tx_pending = adapter->num_txd;
+
+ if (adapter->ahw.port_type == QLCNIC_GBE) {
+ ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G;
+ ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+ } else {
+ ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G;
+ ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ }
+
+ ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
+
+ ring->rx_mini_max_pending = 0;
+ ring->rx_mini_pending = 0;
+}
+
+static u32
+qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
+{
+ u32 num_desc;
+ num_desc = max(val, min);
+ num_desc = min(num_desc, max);
+ num_desc = roundup_pow_of_two(num_desc);
+
+ if (val != num_desc) {
+ printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
+ qlcnic_driver_name, r_name, num_desc, val);
+ }
+
+ return num_desc;
+}
+
+static int
+qlcnic_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ u16 max_rcv_desc = MAX_RCV_DESCRIPTORS_10G;
+ u16 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ u16 num_rxd, num_jumbo_rxd, num_txd;
+
+
+ if (ring->rx_mini_pending)
+ return -EOPNOTSUPP;
+
+ if (adapter->ahw.port_type == QLCNIC_GBE) {
+ max_rcv_desc = MAX_RCV_DESCRIPTORS_1G;
+ max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ }
+
+ num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
+ MIN_RCV_DESCRIPTORS, max_rcv_desc, "rx");
+
+ num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
+ MIN_JUMBO_DESCRIPTORS, max_jumbo_desc, "rx jumbo");
+
+ num_txd = qlcnic_validate_ringparam(ring->tx_pending,
+ MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
+
+ if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
+ num_jumbo_rxd == adapter->num_jumbo_rxd)
+ return 0;
+
+ adapter->num_rxd = num_rxd;
+ adapter->num_jumbo_rxd = num_jumbo_rxd;
+ adapter->num_txd = num_txd;
+
+ return qlcnic_reset_context(adapter);
+}
+
+static void
+qlcnic_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ int port = adapter->physical_port;
+ __u32 val;
+
+ if (adapter->ahw.port_type == QLCNIC_GBE) {
+ if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
+ return;
+ /* get flow control settings */
+ val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
+ pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
+ val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
+ switch (port) {
+ case 0:
+ pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
+ break;
+ case 1:
+ pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
+ break;
+ case 2:
+ pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
+ break;
+ case 3:
+ default:
+ pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
+ break;
+ }
+ } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
+ if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
+ return;
+ pause->rx_pause = 1;
+ val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
+ if (port == 0)
+ pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
+ else
+ pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
+ } else {
+ dev_err(&netdev->dev, "Unknown board type: %x\n",
+ adapter->ahw.port_type);
+ }
+}
+
+static int
+qlcnic_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ int port = adapter->physical_port;
+ __u32 val;
+
+ /* read mode */
+ if (adapter->ahw.port_type == QLCNIC_GBE) {
+ if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
+ return -EIO;
+ /* set flow control */
+ val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
+
+ if (pause->rx_pause)
+ qlcnic_gb_rx_flowctl(val);
+ else
+ qlcnic_gb_unset_rx_flowctl(val);
+
+ QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
+ val);
+ /* set autoneg */
+ val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
+ switch (port) {
+ case 0:
+ if (pause->tx_pause)
+ qlcnic_gb_unset_gb0_mask(val);
+ else
+ qlcnic_gb_set_gb0_mask(val);
+ break;
+ case 1:
+ if (pause->tx_pause)
+ qlcnic_gb_unset_gb1_mask(val);
+ else
+ qlcnic_gb_set_gb1_mask(val);
+ break;
+ case 2:
+ if (pause->tx_pause)
+ qlcnic_gb_unset_gb2_mask(val);
+ else
+ qlcnic_gb_set_gb2_mask(val);
+ break;
+ case 3:
+ default:
+ if (pause->tx_pause)
+ qlcnic_gb_unset_gb3_mask(val);
+ else
+ qlcnic_gb_set_gb3_mask(val);
+ break;
+ }
+ QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
+ } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
+ if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
+ return -EIO;
+ val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
+ if (port == 0) {
+ if (pause->tx_pause)
+ qlcnic_xg_unset_xg0_mask(val);
+ else
+ qlcnic_xg_set_xg0_mask(val);
+ } else {
+ if (pause->tx_pause)
+ qlcnic_xg_unset_xg1_mask(val);
+ else
+ qlcnic_xg_set_xg1_mask(val);
+ }
+ QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
+ } else {
+ dev_err(&netdev->dev, "Unknown board type: %x\n",
+ adapter->ahw.port_type);
+ }
+ return 0;
+}
+
+static int qlcnic_reg_test(struct net_device *dev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ u32 data_read, data_written;
+
+ data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
+ if ((data_read & 0xffff) != adapter->pdev->vendor)
+ return 1;
+
+ data_written = (u32)0xa5a5a5a5;
+
+ QLCWR32(adapter, CRB_SCRATCHPAD_TEST, data_written);
+ data_read = QLCRD32(adapter, CRB_SCRATCHPAD_TEST);
+ if (data_written != data_read)
+ return 1;
+
+ return 0;
+}
+
+static int qlcnic_get_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_TEST:
+ return QLCNIC_TEST_LEN;
+ case ETH_SS_STATS:
+ return QLCNIC_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+#define QLC_ILB_PKT_SIZE 64
+
+static void qlcnic_create_loopback_buff(unsigned char *data)
+{
+ unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
+ memset(data, 0x4e, QLC_ILB_PKT_SIZE);
+ memset(data, 0xff, 12);
+ memcpy(data + 12, random_data, sizeof(random_data));
+}
+
+int qlcnic_check_loopback_buff(unsigned char *data)
+{
+ unsigned char buff[QLC_ILB_PKT_SIZE];
+ qlcnic_create_loopback_buff(buff);
+ return memcmp(data, buff, QLC_ILB_PKT_SIZE);
+}
+
+static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
+ struct sk_buff *skb;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ skb = dev_alloc_skb(QLC_ILB_PKT_SIZE);
+ qlcnic_create_loopback_buff(skb->data);
+ skb_put(skb, QLC_ILB_PKT_SIZE);
+
+ adapter->diag_cnt = 0;
+
+ qlcnic_xmit_frame(skb, adapter->netdev);
+
+ msleep(5);
+
+ qlcnic_process_rcv_ring_diag(sds_ring);
+
+ dev_kfree_skb_any(skb);
+ if (!adapter->diag_cnt)
+ return -1;
+ }
+ return 0;
+}
+
+static int qlcnic_loopback_test(struct net_device *netdev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ int max_sds_rings = adapter->max_sds_rings;
+ int ret;
+
+ if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EIO;
+
+ ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
+ if (ret)
+ goto clear_it;
+
+ ret = qlcnic_set_ilb_mode(adapter);
+ if (ret)
+ goto done;
+
+ ret = qlcnic_do_ilb_test(adapter);
+
+ qlcnic_clear_ilb_mode(adapter);
+
+done:
+ qlcnic_diag_free_res(netdev, max_sds_rings);
+
+clear_it:
+ adapter->max_sds_rings = max_sds_rings;
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return ret;
+}
+
+static int qlcnic_irq_test(struct net_device *netdev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ int max_sds_rings = adapter->max_sds_rings;
+ int ret;
+
+ if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EIO;
+
+ ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
+ if (ret)
+ goto clear_it;
+
+ adapter->diag_cnt = 0;
+ ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func,
+ QLCHAL_VERSION, adapter->portnum, 0, 0, 0x00000011);
+ if (ret)
+ goto done;
+
+ msleep(10);
+
+ ret = !adapter->diag_cnt;
+
+done:
+ qlcnic_diag_free_res(netdev, max_sds_rings);
+
+clear_it:
+ adapter->max_sds_rings = max_sds_rings;
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return ret;
+}
+
+static void
+qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
+ u64 *data)
+{
+ memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
+
+ if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+ data[2] = qlcnic_irq_test(dev);
+ if (data[2])
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ data[3] = qlcnic_loopback_test(dev);
+ if (data[3])
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ }
+
+ data[0] = qlcnic_reg_test(dev);
+ if (data[0])
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ /* link test */
+ data[1] = (u64) qlcnic_test_link(dev);
+ if (data[1])
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+}
+
+static void
+qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
+{
+ int index;
+
+ switch (stringset) {
+ case ETH_SS_TEST:
+ memcpy(data, *qlcnic_gstrings_test,
+ QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
+ break;
+ case ETH_SS_STATS:
+ for (index = 0; index < QLCNIC_STATS_LEN; index++) {
+ memcpy(data + index * ETH_GSTRING_LEN,
+ qlcnic_gstrings_stats[index].stat_string,
+ ETH_GSTRING_LEN);
+ }
+ break;
+ }
+}
+
+static void
+qlcnic_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 * data)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ int index;
+
+ for (index = 0; index < QLCNIC_STATS_LEN; index++) {
+ char *p =
+ (char *)adapter +
+ qlcnic_gstrings_stats[index].stat_offset;
+ data[index] =
+ (qlcnic_gstrings_stats[index].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
+ }
+}
+
+static u32 qlcnic_get_tx_csum(struct net_device *dev)
+{
+ return dev->features & NETIF_F_IP_CSUM;
+}
+
+static u32 qlcnic_get_rx_csum(struct net_device *dev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ return adapter->rx_csum;
+}
+
+static int qlcnic_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ adapter->rx_csum = !!data;
+ return 0;
+}
+
+static u32 qlcnic_get_tso(struct net_device *dev)
+{
+ return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0;
+}
+
+static int qlcnic_set_tso(struct net_device *dev, u32 data)
+{
+ if (data)
+ dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
+ else
+ dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+
+ return 0;
+}
+
+static int qlcnic_blink_led(struct net_device *dev, u32 val)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ int ret;
+
+ ret = qlcnic_config_led(adapter, 1, 0xf);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to set LED blink state.\n");
+ return ret;
+ }
+
+ msleep_interruptible(val * 1000);
+
+ ret = qlcnic_config_led(adapter, 0, 0xf);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to reset LED blink state.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void
+qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ u32 wol_cfg;
+
+ wol->supported = 0;
+ wol->wolopts = 0;
+
+ wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+ if (wol_cfg & (1UL << adapter->portnum))
+ wol->supported |= WAKE_MAGIC;
+
+ wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+ if (wol_cfg & (1UL << adapter->portnum))
+ wol->wolopts |= WAKE_MAGIC;
+}
+
+static int
+qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ u32 wol_cfg;
+
+ if (wol->wolopts & ~WAKE_MAGIC)
+ return -EOPNOTSUPP;
+
+ wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+ if (!(wol_cfg & (1 << adapter->portnum)))
+ return -EOPNOTSUPP;
+
+ wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+ if (wol->wolopts & WAKE_MAGIC)
+ wol_cfg |= 1UL << adapter->portnum;
+ else
+ wol_cfg &= ~(1UL << adapter->portnum);
+
+ QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
+
+ return 0;
+}
+
+/*
+ * Set the coalescing parameters. Currently only normal is supported.
+ * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
+ * firmware coalescing to default.
+ */
+static int qlcnic_set_intr_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ethcoal)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ return -EINVAL;
+
+ /*
+ * Return Error if unsupported values or
+ * unsupported parameters are set.
+ */
+ if (ethcoal->rx_coalesce_usecs > 0xffff ||
+ ethcoal->rx_max_coalesced_frames > 0xffff ||
+ ethcoal->tx_coalesce_usecs > 0xffff ||
+ ethcoal->tx_max_coalesced_frames > 0xffff ||
+ ethcoal->rx_coalesce_usecs_irq ||
+ ethcoal->rx_max_coalesced_frames_irq ||
+ ethcoal->tx_coalesce_usecs_irq ||
+ ethcoal->tx_max_coalesced_frames_irq ||
+ ethcoal->stats_block_coalesce_usecs ||
+ ethcoal->use_adaptive_rx_coalesce ||
+ ethcoal->use_adaptive_tx_coalesce ||
+ ethcoal->pkt_rate_low ||
+ ethcoal->rx_coalesce_usecs_low ||
+ ethcoal->rx_max_coalesced_frames_low ||
+ ethcoal->tx_coalesce_usecs_low ||
+ ethcoal->tx_max_coalesced_frames_low ||
+ ethcoal->pkt_rate_high ||
+ ethcoal->rx_coalesce_usecs_high ||
+ ethcoal->rx_max_coalesced_frames_high ||
+ ethcoal->tx_coalesce_usecs_high ||
+ ethcoal->tx_max_coalesced_frames_high)
+ return -EINVAL;
+
+ if (!ethcoal->rx_coalesce_usecs ||
+ !ethcoal->rx_max_coalesced_frames) {
+ adapter->coal.flags = QLCNIC_INTR_DEFAULT;
+ adapter->coal.normal.data.rx_time_us =
+ QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
+ adapter->coal.normal.data.rx_packets =
+ QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
+ } else {
+ adapter->coal.flags = 0;
+ adapter->coal.normal.data.rx_time_us =
+ ethcoal->rx_coalesce_usecs;
+ adapter->coal.normal.data.rx_packets =
+ ethcoal->rx_max_coalesced_frames;
+ }
+ adapter->coal.normal.data.tx_time_us = ethcoal->tx_coalesce_usecs;
+ adapter->coal.normal.data.tx_packets =
+ ethcoal->tx_max_coalesced_frames;
+
+ qlcnic_config_intr_coalesce(adapter);
+
+ return 0;
+}
+
+static int qlcnic_get_intr_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ethcoal)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ return -EINVAL;
+
+ ethcoal->rx_coalesce_usecs = adapter->coal.normal.data.rx_time_us;
+ ethcoal->tx_coalesce_usecs = adapter->coal.normal.data.tx_time_us;
+ ethcoal->rx_max_coalesced_frames =
+ adapter->coal.normal.data.rx_packets;
+ ethcoal->tx_max_coalesced_frames =
+ adapter->coal.normal.data.tx_packets;
+
+ return 0;
+}
+
+static int qlcnic_set_flags(struct net_device *netdev, u32 data)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ int hw_lro;
+
+ if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO))
+ return -EINVAL;
+
+ ethtool_op_set_flags(netdev, data);
+
+ hw_lro = (data & ETH_FLAG_LRO) ? QLCNIC_LRO_ENABLED : 0;
+
+ if (qlcnic_config_hw_lro(adapter, hw_lro))
+ return -EIO;
+
+ if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter))
+ return -EIO;
+
+
+ return 0;
+}
+
+const struct ethtool_ops qlcnic_ethtool_ops = {
+ .get_settings = qlcnic_get_settings,
+ .set_settings = qlcnic_set_settings,
+ .get_drvinfo = qlcnic_get_drvinfo,
+ .get_regs_len = qlcnic_get_regs_len,
+ .get_regs = qlcnic_get_regs,
+ .get_link = ethtool_op_get_link,
+ .get_eeprom_len = qlcnic_get_eeprom_len,
+ .get_eeprom = qlcnic_get_eeprom,
+ .get_ringparam = qlcnic_get_ringparam,
+ .set_ringparam = qlcnic_set_ringparam,
+ .get_pauseparam = qlcnic_get_pauseparam,
+ .set_pauseparam = qlcnic_set_pauseparam,
+ .get_tx_csum = qlcnic_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_csum,
+ .set_sg = ethtool_op_set_sg,
+ .get_tso = qlcnic_get_tso,
+ .set_tso = qlcnic_set_tso,
+ .get_wol = qlcnic_get_wol,
+ .set_wol = qlcnic_set_wol,
+ .self_test = qlcnic_diag_test,
+ .get_strings = qlcnic_get_strings,
+ .get_ethtool_stats = qlcnic_get_ethtool_stats,
+ .get_sset_count = qlcnic_get_sset_count,
+ .get_rx_csum = qlcnic_get_rx_csum,
+ .set_rx_csum = qlcnic_set_rx_csum,
+ .get_coalesce = qlcnic_get_intr_coalesce,
+ .set_coalesce = qlcnic_set_intr_coalesce,
+ .get_flags = ethtool_op_get_flags,
+ .set_flags = qlcnic_set_flags,
+ .phys_id = qlcnic_blink_led,
+};
diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h
new file mode 100644
index 000000000000..0469f84360a4
--- /dev/null
+++ b/drivers/net/qlcnic/qlcnic_hdr.h
@@ -0,0 +1,937 @@
+/*
+ * Copyright (C) 2009 - QLogic 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 __QLCNIC_HDR_H_
+#define __QLCNIC_HDR_H_
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+/*
+ * The basic unit of access when reading/writing control registers.
+ */
+
+enum {
+ QLCNIC_HW_H0_CH_HUB_ADR = 0x05,
+ QLCNIC_HW_H1_CH_HUB_ADR = 0x0E,
+ QLCNIC_HW_H2_CH_HUB_ADR = 0x03,
+ QLCNIC_HW_H3_CH_HUB_ADR = 0x01,
+ QLCNIC_HW_H4_CH_HUB_ADR = 0x06,
+ QLCNIC_HW_H5_CH_HUB_ADR = 0x07,
+ QLCNIC_HW_H6_CH_HUB_ADR = 0x08
+};
+
+/* Hub 0 */
+enum {
+ QLCNIC_HW_MN_CRB_AGT_ADR = 0x15,
+ QLCNIC_HW_MS_CRB_AGT_ADR = 0x25
+};
+
+/* Hub 1 */
+enum {
+ QLCNIC_HW_PS_CRB_AGT_ADR = 0x73,
+ QLCNIC_HW_SS_CRB_AGT_ADR = 0x20,
+ QLCNIC_HW_RPMX3_CRB_AGT_ADR = 0x0b,
+ QLCNIC_HW_QMS_CRB_AGT_ADR = 0x00,
+ QLCNIC_HW_SQGS0_CRB_AGT_ADR = 0x01,
+ QLCNIC_HW_SQGS1_CRB_AGT_ADR = 0x02,
+ QLCNIC_HW_SQGS2_CRB_AGT_ADR = 0x03,
+ QLCNIC_HW_SQGS3_CRB_AGT_ADR = 0x04,
+ QLCNIC_HW_C2C0_CRB_AGT_ADR = 0x58,
+ QLCNIC_HW_C2C1_CRB_AGT_ADR = 0x59,
+ QLCNIC_HW_C2C2_CRB_AGT_ADR = 0x5a,
+ QLCNIC_HW_RPMX2_CRB_AGT_ADR = 0x0a,
+ QLCNIC_HW_RPMX4_CRB_AGT_ADR = 0x0c,
+ QLCNIC_HW_RPMX7_CRB_AGT_ADR = 0x0f,
+ QLCNIC_HW_RPMX9_CRB_AGT_ADR = 0x12,
+ QLCNIC_HW_SMB_CRB_AGT_ADR = 0x18
+};
+
+/* Hub 2 */
+enum {
+ QLCNIC_HW_NIU_CRB_AGT_ADR = 0x31,
+ QLCNIC_HW_I2C0_CRB_AGT_ADR = 0x19,
+ QLCNIC_HW_I2C1_CRB_AGT_ADR = 0x29,
+
+ QLCNIC_HW_SN_CRB_AGT_ADR = 0x10,
+ QLCNIC_HW_I2Q_CRB_AGT_ADR = 0x20,
+ QLCNIC_HW_LPC_CRB_AGT_ADR = 0x22,
+ QLCNIC_HW_ROMUSB_CRB_AGT_ADR = 0x21,
+ QLCNIC_HW_QM_CRB_AGT_ADR = 0x66,
+ QLCNIC_HW_SQG0_CRB_AGT_ADR = 0x60,
+ QLCNIC_HW_SQG1_CRB_AGT_ADR = 0x61,
+ QLCNIC_HW_SQG2_CRB_AGT_ADR = 0x62,
+ QLCNIC_HW_SQG3_CRB_AGT_ADR = 0x63,
+ QLCNIC_HW_RPMX1_CRB_AGT_ADR = 0x09,
+ QLCNIC_HW_RPMX5_CRB_AGT_ADR = 0x0d,
+ QLCNIC_HW_RPMX6_CRB_AGT_ADR = 0x0e,
+ QLCNIC_HW_RPMX8_CRB_AGT_ADR = 0x11
+};
+
+/* Hub 3 */
+enum {
+ QLCNIC_HW_PH_CRB_AGT_ADR = 0x1A,
+ QLCNIC_HW_SRE_CRB_AGT_ADR = 0x50,
+ QLCNIC_HW_EG_CRB_AGT_ADR = 0x51,
+ QLCNIC_HW_RPMX0_CRB_AGT_ADR = 0x08
+};
+
+/* Hub 4 */
+enum {
+ QLCNIC_HW_PEGN0_CRB_AGT_ADR = 0x40,
+ QLCNIC_HW_PEGN1_CRB_AGT_ADR,
+ QLCNIC_HW_PEGN2_CRB_AGT_ADR,
+ QLCNIC_HW_PEGN3_CRB_AGT_ADR,
+ QLCNIC_HW_PEGNI_CRB_AGT_ADR,
+ QLCNIC_HW_PEGND_CRB_AGT_ADR,
+ QLCNIC_HW_PEGNC_CRB_AGT_ADR,
+ QLCNIC_HW_PEGR0_CRB_AGT_ADR,
+ QLCNIC_HW_PEGR1_CRB_AGT_ADR,
+ QLCNIC_HW_PEGR2_CRB_AGT_ADR,
+ QLCNIC_HW_PEGR3_CRB_AGT_ADR,
+ QLCNIC_HW_PEGN4_CRB_AGT_ADR
+};
+
+/* Hub 5 */
+enum {
+ QLCNIC_HW_PEGS0_CRB_AGT_ADR = 0x40,
+ QLCNIC_HW_PEGS1_CRB_AGT_ADR,
+ QLCNIC_HW_PEGS2_CRB_AGT_ADR,
+ QLCNIC_HW_PEGS3_CRB_AGT_ADR,
+ QLCNIC_HW_PEGSI_CRB_AGT_ADR,
+ QLCNIC_HW_PEGSD_CRB_AGT_ADR,
+ QLCNIC_HW_PEGSC_CRB_AGT_ADR
+};
+
+/* Hub 6 */
+enum {
+ QLCNIC_HW_CAS0_CRB_AGT_ADR = 0x46,
+ QLCNIC_HW_CAS1_CRB_AGT_ADR = 0x47,
+ QLCNIC_HW_CAS2_CRB_AGT_ADR = 0x48,
+ QLCNIC_HW_CAS3_CRB_AGT_ADR = 0x49,
+ QLCNIC_HW_NCM_CRB_AGT_ADR = 0x16,
+ QLCNIC_HW_TMR_CRB_AGT_ADR = 0x17,
+ QLCNIC_HW_XDMA_CRB_AGT_ADR = 0x05,
+ QLCNIC_HW_OCM0_CRB_AGT_ADR = 0x06,
+ QLCNIC_HW_OCM1_CRB_AGT_ADR = 0x07
+};
+
+/* Floaters - non existent modules */
+#define QLCNIC_HW_EFC_RPMX0_CRB_AGT_ADR 0x67
+
+/* This field defines PCI/X adr [25:20] of agents on the CRB */
+enum {
+ QLCNIC_HW_PX_MAP_CRB_PH = 0,
+ QLCNIC_HW_PX_MAP_CRB_PS,
+ QLCNIC_HW_PX_MAP_CRB_MN,
+ QLCNIC_HW_PX_MAP_CRB_MS,
+ QLCNIC_HW_PX_MAP_CRB_PGR1,
+ QLCNIC_HW_PX_MAP_CRB_SRE,
+ QLCNIC_HW_PX_MAP_CRB_NIU,
+ QLCNIC_HW_PX_MAP_CRB_QMN,
+ QLCNIC_HW_PX_MAP_CRB_SQN0,
+ QLCNIC_HW_PX_MAP_CRB_SQN1,
+ QLCNIC_HW_PX_MAP_CRB_SQN2,
+ QLCNIC_HW_PX_MAP_CRB_SQN3,
+ QLCNIC_HW_PX_MAP_CRB_QMS,
+ QLCNIC_HW_PX_MAP_CRB_SQS0,
+ QLCNIC_HW_PX_MAP_CRB_SQS1,
+ QLCNIC_HW_PX_MAP_CRB_SQS2,
+ QLCNIC_HW_PX_MAP_CRB_SQS3,
+ QLCNIC_HW_PX_MAP_CRB_PGN0,
+ QLCNIC_HW_PX_MAP_CRB_PGN1,
+ QLCNIC_HW_PX_MAP_CRB_PGN2,
+ QLCNIC_HW_PX_MAP_CRB_PGN3,
+ QLCNIC_HW_PX_MAP_CRB_PGND,
+ QLCNIC_HW_PX_MAP_CRB_PGNI,
+ QLCNIC_HW_PX_MAP_CRB_PGS0,
+ QLCNIC_HW_PX_MAP_CRB_PGS1,
+ QLCNIC_HW_PX_MAP_CRB_PGS2,
+ QLCNIC_HW_PX_MAP_CRB_PGS3,
+ QLCNIC_HW_PX_MAP_CRB_PGSD,
+ QLCNIC_HW_PX_MAP_CRB_PGSI,
+ QLCNIC_HW_PX_MAP_CRB_SN,
+ QLCNIC_HW_PX_MAP_CRB_PGR2,
+ QLCNIC_HW_PX_MAP_CRB_EG,
+ QLCNIC_HW_PX_MAP_CRB_PH2,
+ QLCNIC_HW_PX_MAP_CRB_PS2,
+ QLCNIC_HW_PX_MAP_CRB_CAM,
+ QLCNIC_HW_PX_MAP_CRB_CAS0,
+ QLCNIC_HW_PX_MAP_CRB_CAS1,
+ QLCNIC_HW_PX_MAP_CRB_CAS2,
+ QLCNIC_HW_PX_MAP_CRB_C2C0,
+ QLCNIC_HW_PX_MAP_CRB_C2C1,
+ QLCNIC_HW_PX_MAP_CRB_TIMR,
+ QLCNIC_HW_PX_MAP_CRB_PGR3,
+ QLCNIC_HW_PX_MAP_CRB_RPMX1,
+ QLCNIC_HW_PX_MAP_CRB_RPMX2,
+ QLCNIC_HW_PX_MAP_CRB_RPMX3,
+ QLCNIC_HW_PX_MAP_CRB_RPMX4,
+ QLCNIC_HW_PX_MAP_CRB_RPMX5,
+ QLCNIC_HW_PX_MAP_CRB_RPMX6,
+ QLCNIC_HW_PX_MAP_CRB_RPMX7,
+ QLCNIC_HW_PX_MAP_CRB_XDMA,
+ QLCNIC_HW_PX_MAP_CRB_I2Q,
+ QLCNIC_HW_PX_MAP_CRB_ROMUSB,
+ QLCNIC_HW_PX_MAP_CRB_CAS3,
+ QLCNIC_HW_PX_MAP_CRB_RPMX0,
+ QLCNIC_HW_PX_MAP_CRB_RPMX8,
+ QLCNIC_HW_PX_MAP_CRB_RPMX9,
+ QLCNIC_HW_PX_MAP_CRB_OCM0,
+ QLCNIC_HW_PX_MAP_CRB_OCM1,
+ QLCNIC_HW_PX_MAP_CRB_SMB,
+ QLCNIC_HW_PX_MAP_CRB_I2C0,
+ QLCNIC_HW_PX_MAP_CRB_I2C1,
+ QLCNIC_HW_PX_MAP_CRB_LPC,
+ QLCNIC_HW_PX_MAP_CRB_PGNC,
+ QLCNIC_HW_PX_MAP_CRB_PGR0
+};
+
+/* This field defines CRB adr [31:20] of the agents */
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_MN \
+ ((QLCNIC_HW_H0_CH_HUB_ADR << 7) | QLCNIC_HW_MN_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PH \
+ ((QLCNIC_HW_H0_CH_HUB_ADR << 7) | QLCNIC_HW_PH_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_MS \
+ ((QLCNIC_HW_H0_CH_HUB_ADR << 7) | QLCNIC_HW_MS_CRB_AGT_ADR)
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PS \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_PS_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SS \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SS_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX3 \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX3_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_QMS \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_QMS_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS0 \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS1 \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS2 \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS3 \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS3_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_C2C0 \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_C2C0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_C2C1 \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_C2C1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX2 \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX4 \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX4_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX7 \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX7_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX9 \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX9_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SMB \
+ ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SMB_CRB_AGT_ADR)
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_NIU \
+ ((QLCNIC_HW_H2_CH_HUB_ADR << 7) | QLCNIC_HW_NIU_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_I2C0 \
+ ((QLCNIC_HW_H2_CH_HUB_ADR << 7) | QLCNIC_HW_I2C0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_I2C1 \
+ ((QLCNIC_HW_H2_CH_HUB_ADR << 7) | QLCNIC_HW_I2C1_CRB_AGT_ADR)
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SRE \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SRE_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_EG \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_EG_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX0 \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_QMN \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_QM_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN0 \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN1 \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN2 \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN3 \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG3_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX1 \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX5 \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX5_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX6 \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX6_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX8 \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX8_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS0 \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS1 \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS2 \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS3 \
+ ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS3_CRB_AGT_ADR)
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGNI \
+ ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGNI_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGND \
+ ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGND_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN0 \
+ ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN1 \
+ ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN2 \
+ ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN3 \
+ ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN3_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN4 \
+ ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN4_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGNC \
+ ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGNC_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR0 \
+ ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR1 \
+ ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR2 \
+ ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR3 \
+ ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR3_CRB_AGT_ADR)
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGSI \
+ ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGSI_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGSD \
+ ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGSD_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS0 \
+ ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS1 \
+ ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS2 \
+ ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS3 \
+ ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS3_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGSC \
+ ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGSC_CRB_AGT_ADR)
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAM \
+ ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_NCM_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR \
+ ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_TMR_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA \
+ ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_XDMA_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SN \
+ ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_SN_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q \
+ ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_I2Q_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB \
+ ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_ROMUSB_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_OCM0 \
+ ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_OCM0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_OCM1 \
+ ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_OCM1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_LPC \
+ ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_LPC_CRB_AGT_ADR)
+
+#define QLCNIC_SRE_MISC (QLCNIC_CRB_SRE + 0x0002c)
+
+#define QLCNIC_I2Q_CLR_PCI_HI (QLCNIC_CRB_I2Q + 0x00034)
+
+#define ROMUSB_GLB (QLCNIC_CRB_ROMUSB + 0x00000)
+#define ROMUSB_ROM (QLCNIC_CRB_ROMUSB + 0x10000)
+
+#define QLCNIC_ROMUSB_GLB_STATUS (ROMUSB_GLB + 0x0004)
+#define QLCNIC_ROMUSB_GLB_SW_RESET (ROMUSB_GLB + 0x0008)
+#define QLCNIC_ROMUSB_GLB_PAD_GPIO_I (ROMUSB_GLB + 0x000c)
+#define QLCNIC_ROMUSB_GLB_CAS_RST (ROMUSB_GLB + 0x0038)
+#define QLCNIC_ROMUSB_GLB_TEST_MUX_SEL (ROMUSB_GLB + 0x0044)
+#define QLCNIC_ROMUSB_GLB_PEGTUNE_DONE (ROMUSB_GLB + 0x005c)
+#define QLCNIC_ROMUSB_GLB_CHIP_CLK_CTRL (ROMUSB_GLB + 0x00A8)
+
+#define QLCNIC_ROMUSB_GPIO(n) (ROMUSB_GLB + 0x60 + (4 * (n)))
+
+#define QLCNIC_ROMUSB_ROM_INSTR_OPCODE (ROMUSB_ROM + 0x0004)
+#define QLCNIC_ROMUSB_ROM_ADDRESS (ROMUSB_ROM + 0x0008)
+#define QLCNIC_ROMUSB_ROM_WDATA (ROMUSB_ROM + 0x000c)
+#define QLCNIC_ROMUSB_ROM_ABYTE_CNT (ROMUSB_ROM + 0x0010)
+#define QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT (ROMUSB_ROM + 0x0014)
+#define QLCNIC_ROMUSB_ROM_RDATA (ROMUSB_ROM + 0x0018)
+
+/* Lock IDs for ROM lock */
+#define ROM_LOCK_DRIVER 0x0d417340
+
+/******************************************************************************
+*
+* Definitions specific to M25P flash
+*
+*******************************************************************************
+*/
+
+/* all are 1MB windows */
+
+#define QLCNIC_PCI_CRB_WINDOWSIZE 0x00100000
+#define QLCNIC_PCI_CRB_WINDOW(A) \
+ (QLCNIC_PCI_CRBSPACE + (A)*QLCNIC_PCI_CRB_WINDOWSIZE)
+
+#define QLCNIC_CRB_NIU QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_NIU)
+#define QLCNIC_CRB_SRE QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SRE)
+#define QLCNIC_CRB_ROMUSB \
+ QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_ROMUSB)
+#define QLCNIC_CRB_I2Q QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_I2Q)
+#define QLCNIC_CRB_I2C0 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_I2C0)
+#define QLCNIC_CRB_SMB QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SMB)
+#define QLCNIC_CRB_MAX QLCNIC_PCI_CRB_WINDOW(64)
+
+#define QLCNIC_CRB_PCIX_HOST QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PH)
+#define QLCNIC_CRB_PCIX_HOST2 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PH2)
+#define QLCNIC_CRB_PEG_NET_0 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN0)
+#define QLCNIC_CRB_PEG_NET_1 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN1)
+#define QLCNIC_CRB_PEG_NET_2 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN2)
+#define QLCNIC_CRB_PEG_NET_3 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN3)
+#define QLCNIC_CRB_PEG_NET_4 QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SQS2)
+#define QLCNIC_CRB_PEG_NET_D QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGND)
+#define QLCNIC_CRB_PEG_NET_I QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGNI)
+#define QLCNIC_CRB_DDR_NET QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_MN)
+#define QLCNIC_CRB_QDR_NET QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SN)
+
+#define QLCNIC_CRB_PCIX_MD QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PS)
+#define QLCNIC_CRB_PCIE QLCNIC_CRB_PCIX_MD
+
+#define ISR_INT_VECTOR (QLCNIC_PCIX_PS_REG(PCIX_INT_VECTOR))
+#define ISR_INT_MASK (QLCNIC_PCIX_PS_REG(PCIX_INT_MASK))
+#define ISR_INT_MASK_SLOW (QLCNIC_PCIX_PS_REG(PCIX_INT_MASK))
+#define ISR_INT_TARGET_STATUS (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS))
+#define ISR_INT_TARGET_MASK (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK))
+#define ISR_INT_TARGET_STATUS_F1 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F1))
+#define ISR_INT_TARGET_MASK_F1 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F1))
+#define ISR_INT_TARGET_STATUS_F2 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F2))
+#define ISR_INT_TARGET_MASK_F2 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F2))
+#define ISR_INT_TARGET_STATUS_F3 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F3))
+#define ISR_INT_TARGET_MASK_F3 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F3))
+#define ISR_INT_TARGET_STATUS_F4 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F4))
+#define ISR_INT_TARGET_MASK_F4 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F4))
+#define ISR_INT_TARGET_STATUS_F5 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F5))
+#define ISR_INT_TARGET_MASK_F5 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F5))
+#define ISR_INT_TARGET_STATUS_F6 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F6))
+#define ISR_INT_TARGET_MASK_F6 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F6))
+#define ISR_INT_TARGET_STATUS_F7 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F7))
+#define ISR_INT_TARGET_MASK_F7 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F7))
+
+#define QLCNIC_PCI_MN_2M (0)
+#define QLCNIC_PCI_MS_2M (0x80000)
+#define QLCNIC_PCI_OCM0_2M (0x000c0000UL)
+#define QLCNIC_PCI_CRBSPACE (0x06000000UL)
+#define QLCNIC_PCI_2MB_SIZE (0x00200000UL)
+#define QLCNIC_PCI_CAMQM_2M_BASE (0x000ff800UL)
+#define QLCNIC_PCI_CAMQM_2M_END (0x04800800UL)
+
+#define QLCNIC_CRB_CAM QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_CAM)
+
+#define QLCNIC_ADDR_DDR_NET (0x0000000000000000ULL)
+#define QLCNIC_ADDR_DDR_NET_MAX (0x000000000fffffffULL)
+#define QLCNIC_ADDR_OCM0 (0x0000000200000000ULL)
+#define QLCNIC_ADDR_OCM0_MAX (0x00000002000fffffULL)
+#define QLCNIC_ADDR_OCM1 (0x0000000200400000ULL)
+#define QLCNIC_ADDR_OCM1_MAX (0x00000002004fffffULL)
+#define QLCNIC_ADDR_QDR_NET (0x0000000300000000ULL)
+#define QLCNIC_ADDR_QDR_NET_MAX_P3 (0x0000000303ffffffULL)
+
+/*
+ * Register offsets for MN
+ */
+#define QLCNIC_MIU_CONTROL (0x000)
+#define QLCNIC_MIU_MN_CONTROL (QLCNIC_CRB_DDR_NET+QLCNIC_MIU_CONTROL)
+
+/* 200ms delay in each loop */
+#define QLCNIC_NIU_PHY_WAITLEN 200000
+/* 10 seconds before we give up */
+#define QLCNIC_NIU_PHY_WAITMAX 50
+#define QLCNIC_NIU_MAX_GBE_PORTS 4
+#define QLCNIC_NIU_MAX_XG_PORTS 2
+
+#define QLCNIC_NIU_MODE (QLCNIC_CRB_NIU + 0x00000)
+#define QLCNIC_NIU_GB_PAUSE_CTL (QLCNIC_CRB_NIU + 0x0030c)
+#define QLCNIC_NIU_XG_PAUSE_CTL (QLCNIC_CRB_NIU + 0x00098)
+
+#define QLCNIC_NIU_GB_MAC_CONFIG_0(I) \
+ (QLCNIC_CRB_NIU + 0x30000 + (I)*0x10000)
+#define QLCNIC_NIU_GB_MAC_CONFIG_1(I) \
+ (QLCNIC_CRB_NIU + 0x30004 + (I)*0x10000)
+
+
+#define TEST_AGT_CTRL (0x00)
+
+#define TA_CTL_START 1
+#define TA_CTL_ENABLE 2
+#define TA_CTL_WRITE 4
+#define TA_CTL_BUSY 8
+
+/*
+ * Register offsets for MN
+ */
+#define MIU_TEST_AGT_BASE (0x90)
+
+#define MIU_TEST_AGT_ADDR_LO (0x04)
+#define MIU_TEST_AGT_ADDR_HI (0x08)
+#define MIU_TEST_AGT_WRDATA_LO (0x10)
+#define MIU_TEST_AGT_WRDATA_HI (0x14)
+#define MIU_TEST_AGT_WRDATA_UPPER_LO (0x20)
+#define MIU_TEST_AGT_WRDATA_UPPER_HI (0x24)
+#define MIU_TEST_AGT_WRDATA(i) (0x10+(0x10*((i)>>1))+(4*((i)&1)))
+#define MIU_TEST_AGT_RDDATA_LO (0x18)
+#define MIU_TEST_AGT_RDDATA_HI (0x1c)
+#define MIU_TEST_AGT_RDDATA_UPPER_LO (0x28)
+#define MIU_TEST_AGT_RDDATA_UPPER_HI (0x2c)
+#define MIU_TEST_AGT_RDDATA(i) (0x18+(0x10*((i)>>1))+(4*((i)&1)))
+
+#define MIU_TEST_AGT_ADDR_MASK 0xfffffff8
+#define MIU_TEST_AGT_UPPER_ADDR(off) (0)
+
+/*
+ * Register offsets for MS
+ */
+#define SIU_TEST_AGT_BASE (0x60)
+
+#define SIU_TEST_AGT_ADDR_LO (0x04)
+#define SIU_TEST_AGT_ADDR_HI (0x18)
+#define SIU_TEST_AGT_WRDATA_LO (0x08)
+#define SIU_TEST_AGT_WRDATA_HI (0x0c)
+#define SIU_TEST_AGT_WRDATA(i) (0x08+(4*(i)))
+#define SIU_TEST_AGT_RDDATA_LO (0x10)
+#define SIU_TEST_AGT_RDDATA_HI (0x14)
+#define SIU_TEST_AGT_RDDATA(i) (0x10+(4*(i)))
+
+#define SIU_TEST_AGT_ADDR_MASK 0x3ffff8
+#define SIU_TEST_AGT_UPPER_ADDR(off) ((off)>>22)
+
+/* XG Link status */
+#define XG_LINK_UP 0x10
+#define XG_LINK_DOWN 0x20
+
+#define XG_LINK_UP_P3 0x01
+#define XG_LINK_DOWN_P3 0x02
+#define XG_LINK_STATE_P3_MASK 0xf
+#define XG_LINK_STATE_P3(pcifn, val) \
+ (((val) >> ((pcifn) * 4)) & XG_LINK_STATE_P3_MASK)
+
+#define P3_LINK_SPEED_MHZ 100
+#define P3_LINK_SPEED_MASK 0xff
+#define P3_LINK_SPEED_REG(pcifn) \
+ (CRB_PF_LINK_SPEED_1 + (((pcifn) / 4) * 4))
+#define P3_LINK_SPEED_VAL(pcifn, reg) \
+ (((reg) >> (8 * ((pcifn) & 0x3))) & P3_LINK_SPEED_MASK)
+
+#define QLCNIC_CAM_RAM_BASE (QLCNIC_CRB_CAM + 0x02000)
+#define QLCNIC_CAM_RAM(reg) (QLCNIC_CAM_RAM_BASE + (reg))
+#define QLCNIC_FW_VERSION_MAJOR (QLCNIC_CAM_RAM(0x150))
+#define QLCNIC_FW_VERSION_MINOR (QLCNIC_CAM_RAM(0x154))
+#define QLCNIC_FW_VERSION_SUB (QLCNIC_CAM_RAM(0x158))
+#define QLCNIC_ROM_LOCK_ID (QLCNIC_CAM_RAM(0x100))
+#define QLCNIC_PHY_LOCK_ID (QLCNIC_CAM_RAM(0x120))
+#define QLCNIC_CRB_WIN_LOCK_ID (QLCNIC_CAM_RAM(0x124))
+
+#define NIC_CRB_BASE (QLCNIC_CAM_RAM(0x200))
+#define NIC_CRB_BASE_2 (QLCNIC_CAM_RAM(0x700))
+#define QLCNIC_REG(X) (NIC_CRB_BASE+(X))
+#define QLCNIC_REG_2(X) (NIC_CRB_BASE_2+(X))
+
+#define QLCNIC_CDRP_CRB_OFFSET (QLCNIC_REG(0x18))
+#define QLCNIC_ARG1_CRB_OFFSET (QLCNIC_REG(0x1c))
+#define QLCNIC_ARG2_CRB_OFFSET (QLCNIC_REG(0x20))
+#define QLCNIC_ARG3_CRB_OFFSET (QLCNIC_REG(0x24))
+#define QLCNIC_SIGN_CRB_OFFSET (QLCNIC_REG(0x28))
+
+#define CRB_CMDPEG_STATE (QLCNIC_REG(0x50))
+#define CRB_RCVPEG_STATE (QLCNIC_REG(0x13c))
+
+#define CRB_XG_STATE_P3 (QLCNIC_REG(0x98))
+#define CRB_PF_LINK_SPEED_1 (QLCNIC_REG(0xe8))
+#define CRB_PF_LINK_SPEED_2 (QLCNIC_REG(0xec))
+
+#define CRB_MPORT_MODE (QLCNIC_REG(0xc4))
+#define CRB_DMA_SHIFT (QLCNIC_REG(0xcc))
+
+#define CRB_TEMP_STATE (QLCNIC_REG(0x1b4))
+
+#define CRB_V2P_0 (QLCNIC_REG(0x290))
+#define CRB_V2P(port) (CRB_V2P_0+((port)*4))
+#define CRB_DRIVER_VERSION (QLCNIC_REG(0x2a0))
+
+#define CRB_SW_INT_MASK_0 (QLCNIC_REG(0x1d8))
+#define CRB_SW_INT_MASK_1 (QLCNIC_REG(0x1e0))
+#define CRB_SW_INT_MASK_2 (QLCNIC_REG(0x1e4))
+#define CRB_SW_INT_MASK_3 (QLCNIC_REG(0x1e8))
+
+#define CRB_FW_CAPABILITIES_1 (QLCNIC_CAM_RAM(0x128))
+#define CRB_MAC_BLOCK_START (QLCNIC_CAM_RAM(0x1c0))
+
+/*
+ * capabilities register, can be used to selectively enable/disable features
+ * for backward compability
+ */
+#define CRB_NIC_CAPABILITIES_HOST QLCNIC_REG(0x1a8)
+#define CRB_NIC_CAPABILITIES_FW QLCNIC_REG(0x1dc)
+#define CRB_NIC_MSI_MODE_HOST QLCNIC_REG(0x270)
+#define CRB_NIC_MSI_MODE_FW QLCNIC_REG(0x274)
+
+#define INTR_SCHEME_PERPORT 0x1
+#define MSI_MODE_MULTIFUNC 0x1
+
+/* used for ethtool tests */
+#define CRB_SCRATCHPAD_TEST QLCNIC_REG(0x280)
+
+/*
+ * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address
+ * which can be read by the Phantom host to get producer/consumer indexes from
+ * Phantom/Casper. If it is not HOST_SHARED_MEMORY, then the following
+ * registers will be used for the addresses of the ring's shared memory
+ * on the Phantom.
+ */
+
+#define qlcnic_get_temp_val(x) ((x) >> 16)
+#define qlcnic_get_temp_state(x) ((x) & 0xffff)
+#define qlcnic_encode_temp(val, state) (((val) << 16) | (state))
+
+/*
+ * Temperature control.
+ */
+enum {
+ QLCNIC_TEMP_NORMAL = 0x1, /* Normal operating range */
+ QLCNIC_TEMP_WARN, /* Sound alert, temperature getting high */
+ QLCNIC_TEMP_PANIC /* Fatal error, hardware has shut down. */
+};
+
+/* Lock IDs for PHY lock */
+#define PHY_LOCK_DRIVER 0x44524956
+
+/* Used for PS PCI Memory access */
+#define PCIX_PS_OP_ADDR_LO (0x10000)
+/* via CRB (PS side only) */
+#define PCIX_PS_OP_ADDR_HI (0x10004)
+
+#define PCIX_INT_VECTOR (0x10100)
+#define PCIX_INT_MASK (0x10104)
+
+#define PCIX_OCM_WINDOW (0x10800)
+#define PCIX_OCM_WINDOW_REG(func) (PCIX_OCM_WINDOW + 0x20 * (func))
+
+#define PCIX_TARGET_STATUS (0x10118)
+#define PCIX_TARGET_STATUS_F1 (0x10160)
+#define PCIX_TARGET_STATUS_F2 (0x10164)
+#define PCIX_TARGET_STATUS_F3 (0x10168)
+#define PCIX_TARGET_STATUS_F4 (0x10360)
+#define PCIX_TARGET_STATUS_F5 (0x10364)
+#define PCIX_TARGET_STATUS_F6 (0x10368)
+#define PCIX_TARGET_STATUS_F7 (0x1036c)
+
+#define PCIX_TARGET_MASK (0x10128)
+#define PCIX_TARGET_MASK_F1 (0x10170)
+#define PCIX_TARGET_MASK_F2 (0x10174)
+#define PCIX_TARGET_MASK_F3 (0x10178)
+#define PCIX_TARGET_MASK_F4 (0x10370)
+#define PCIX_TARGET_MASK_F5 (0x10374)
+#define PCIX_TARGET_MASK_F6 (0x10378)
+#define PCIX_TARGET_MASK_F7 (0x1037c)
+
+#define PCIX_MSI_F(i) (0x13000+((i)*4))
+
+#define QLCNIC_PCIX_PH_REG(reg) (QLCNIC_CRB_PCIE + (reg))
+#define QLCNIC_PCIX_PS_REG(reg) (QLCNIC_CRB_PCIX_MD + (reg))
+#define QLCNIC_PCIE_REG(reg) (QLCNIC_CRB_PCIE + (reg))
+
+#define PCIE_SEM0_LOCK (0x1c000)
+#define PCIE_SEM0_UNLOCK (0x1c004)
+#define PCIE_SEM_LOCK(N) (PCIE_SEM0_LOCK + 8*(N))
+#define PCIE_SEM_UNLOCK(N) (PCIE_SEM0_UNLOCK + 8*(N))
+
+#define PCIE_SETUP_FUNCTION (0x12040)
+#define PCIE_SETUP_FUNCTION2 (0x12048)
+#define PCIE_MISCCFG_RC (0x1206c)
+#define PCIE_TGT_SPLIT_CHICKEN (0x12080)
+#define PCIE_CHICKEN3 (0x120c8)
+
+#define ISR_INT_STATE_REG (QLCNIC_PCIX_PS_REG(PCIE_MISCCFG_RC))
+#define PCIE_MAX_MASTER_SPLIT (0x14048)
+
+#define QLCNIC_PORT_MODE_NONE 0
+#define QLCNIC_PORT_MODE_XG 1
+#define QLCNIC_PORT_MODE_GB 2
+#define QLCNIC_PORT_MODE_802_3_AP 3
+#define QLCNIC_PORT_MODE_AUTO_NEG 4
+#define QLCNIC_PORT_MODE_AUTO_NEG_1G 5
+#define QLCNIC_PORT_MODE_AUTO_NEG_XG 6
+#define QLCNIC_PORT_MODE_ADDR (QLCNIC_CAM_RAM(0x24))
+#define QLCNIC_WOL_PORT_MODE (QLCNIC_CAM_RAM(0x198))
+
+#define QLCNIC_WOL_CONFIG_NV (QLCNIC_CAM_RAM(0x184))
+#define QLCNIC_WOL_CONFIG (QLCNIC_CAM_RAM(0x188))
+
+#define QLCNIC_PEG_TUNE_MN_PRESENT 0x1
+#define QLCNIC_PEG_TUNE_CAPABILITY (QLCNIC_CAM_RAM(0x02c))
+
+#define QLCNIC_DMA_WATCHDOG_CTRL (QLCNIC_CAM_RAM(0x14))
+#define QLCNIC_PEG_ALIVE_COUNTER (QLCNIC_CAM_RAM(0xb0))
+#define QLCNIC_PEG_HALT_STATUS1 (QLCNIC_CAM_RAM(0xa8))
+#define QLCNIC_PEG_HALT_STATUS2 (QLCNIC_CAM_RAM(0xac))
+#define QLCNIC_CRB_DEV_REF_COUNT (QLCNIC_CAM_RAM(0x138))
+#define QLCNIC_CRB_DEV_STATE (QLCNIC_CAM_RAM(0x140))
+
+#define QLCNIC_CRB_DRV_STATE (QLCNIC_CAM_RAM(0x144))
+#define QLCNIC_CRB_DRV_SCRATCH (QLCNIC_CAM_RAM(0x148))
+#define QLCNIC_CRB_DEV_PARTITION_INFO (QLCNIC_CAM_RAM(0x14c))
+#define QLCNIC_CRB_DRV_IDC_VER (QLCNIC_CAM_RAM(0x14c))
+
+ /* Device State */
+#define QLCNIC_DEV_COLD 1
+#define QLCNIC_DEV_INITALIZING 2
+#define QLCNIC_DEV_READY 3
+#define QLCNIC_DEV_NEED_RESET 4
+#define QLCNIC_DEV_NEED_QUISCENT 5
+#define QLCNIC_DEV_FAILED 6
+
+#define QLCNIC_RCODE_DRIVER_INFO 0x20000000
+#define QLCNIC_RCODE_DRIVER_CAN_RELOAD 0x40000000
+#define QLCNIC_RCODE_FATAL_ERROR 0x80000000
+#define QLCNIC_FWERROR_PEGNUM(code) ((code) & 0xff)
+#define QLCNIC_FWERROR_CODE(code) ((code >> 8) & 0xfffff)
+
+#define FW_POLL_DELAY (2 * HZ)
+#define FW_FAIL_THRESH 3
+#define FW_POLL_THRESH 10
+
+#define ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
+#define ISR_LEGACY_INT_TRIGGERED(VAL) (((VAL) & 0x300) == 0x200)
+
+/*
+ * PCI Interrupt Vector Values.
+ */
+#define PCIX_INT_VECTOR_BIT_F0 0x0080
+#define PCIX_INT_VECTOR_BIT_F1 0x0100
+#define PCIX_INT_VECTOR_BIT_F2 0x0200
+#define PCIX_INT_VECTOR_BIT_F3 0x0400
+#define PCIX_INT_VECTOR_BIT_F4 0x0800
+#define PCIX_INT_VECTOR_BIT_F5 0x1000
+#define PCIX_INT_VECTOR_BIT_F6 0x2000
+#define PCIX_INT_VECTOR_BIT_F7 0x4000
+
+struct qlcnic_legacy_intr_set {
+ u32 int_vec_bit;
+ u32 tgt_status_reg;
+ u32 tgt_mask_reg;
+ u32 pci_int_reg;
+};
+
+#define QLCNIC_LEGACY_INTR_CONFIG \
+{ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F0, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(0) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F1, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F1, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F1, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(1) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F2, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F2, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F2, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(2) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F3, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F3, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F3, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(3) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F4, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F4, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F4, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(4) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F5, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F5, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F5, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(5) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F6, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F6, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F6, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(6) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F7, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F7, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F7, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(7) }, \
+}
+
+/* NIU REGS */
+
+#define _qlcnic_crb_get_bit(var, bit) ((var >> bit) & 0x1)
+
+/*
+ * NIU GB MAC Config Register 0 (applies to GB0, GB1, GB2, GB3)
+ *
+ * Bit 0 : enable_tx => 1:enable frame xmit, 0:disable
+ * Bit 1 : tx_synced => R/O: xmit enable synched to xmit stream
+ * Bit 2 : enable_rx => 1:enable frame recv, 0:disable
+ * Bit 3 : rx_synced => R/O: recv enable synched to recv stream
+ * Bit 4 : tx_flowctl => 1:enable pause frame generation, 0:disable
+ * Bit 5 : rx_flowctl => 1:act on recv'd pause frames, 0:ignore
+ * Bit 8 : loopback => 1:loop MAC xmits to MAC recvs, 0:normal
+ * Bit 16: tx_reset_pb => 1:reset frame xmit protocol blk, 0:no-op
+ * Bit 17: rx_reset_pb => 1:reset frame recv protocol blk, 0:no-op
+ * Bit 18: tx_reset_mac => 1:reset data/ctl multiplexer blk, 0:no-op
+ * Bit 19: rx_reset_mac => 1:reset ctl frames & timers blk, 0:no-op
+ * Bit 31: soft_reset => 1:reset the MAC and the SERDES, 0:no-op
+ */
+#define qlcnic_gb_rx_flowctl(config_word) \
+ ((config_word) |= 1 << 5)
+#define qlcnic_gb_get_rx_flowctl(config_word) \
+ _qlcnic_crb_get_bit((config_word), 5)
+#define qlcnic_gb_unset_rx_flowctl(config_word) \
+ ((config_word) &= ~(1 << 5))
+
+/*
+ * NIU GB Pause Ctl Register
+ */
+
+#define qlcnic_gb_set_gb0_mask(config_word) \
+ ((config_word) |= 1 << 0)
+#define qlcnic_gb_set_gb1_mask(config_word) \
+ ((config_word) |= 1 << 2)
+#define qlcnic_gb_set_gb2_mask(config_word) \
+ ((config_word) |= 1 << 4)
+#define qlcnic_gb_set_gb3_mask(config_word) \
+ ((config_word) |= 1 << 6)
+
+#define qlcnic_gb_get_gb0_mask(config_word) \
+ _qlcnic_crb_get_bit((config_word), 0)
+#define qlcnic_gb_get_gb1_mask(config_word) \
+ _qlcnic_crb_get_bit((config_word), 2)
+#define qlcnic_gb_get_gb2_mask(config_word) \
+ _qlcnic_crb_get_bit((config_word), 4)
+#define qlcnic_gb_get_gb3_mask(config_word) \
+ _qlcnic_crb_get_bit((config_word), 6)
+
+#define qlcnic_gb_unset_gb0_mask(config_word) \
+ ((config_word) &= ~(1 << 0))
+#define qlcnic_gb_unset_gb1_mask(config_word) \
+ ((config_word) &= ~(1 << 2))
+#define qlcnic_gb_unset_gb2_mask(config_word) \
+ ((config_word) &= ~(1 << 4))
+#define qlcnic_gb_unset_gb3_mask(config_word) \
+ ((config_word) &= ~(1 << 6))
+
+/*
+ * NIU XG Pause Ctl Register
+ *
+ * Bit 0 : xg0_mask => 1:disable tx pause frames
+ * Bit 1 : xg0_request => 1:request single pause frame
+ * Bit 2 : xg0_on_off => 1:request is pause on, 0:off
+ * Bit 3 : xg1_mask => 1:disable tx pause frames
+ * Bit 4 : xg1_request => 1:request single pause frame
+ * Bit 5 : xg1_on_off => 1:request is pause on, 0:off
+ */
+
+#define qlcnic_xg_set_xg0_mask(config_word) \
+ ((config_word) |= 1 << 0)
+#define qlcnic_xg_set_xg1_mask(config_word) \
+ ((config_word) |= 1 << 3)
+
+#define qlcnic_xg_get_xg0_mask(config_word) \
+ _qlcnic_crb_get_bit((config_word), 0)
+#define qlcnic_xg_get_xg1_mask(config_word) \
+ _qlcnic_crb_get_bit((config_word), 3)
+
+#define qlcnic_xg_unset_xg0_mask(config_word) \
+ ((config_word) &= ~(1 << 0))
+#define qlcnic_xg_unset_xg1_mask(config_word) \
+ ((config_word) &= ~(1 << 3))
+
+/*
+ * NIU XG Pause Ctl Register
+ *
+ * Bit 0 : xg0_mask => 1:disable tx pause frames
+ * Bit 1 : xg0_request => 1:request single pause frame
+ * Bit 2 : xg0_on_off => 1:request is pause on, 0:off
+ * Bit 3 : xg1_mask => 1:disable tx pause frames
+ * Bit 4 : xg1_request => 1:request single pause frame
+ * Bit 5 : xg1_on_off => 1:request is pause on, 0:off
+ */
+
+/*
+ * PHY-Specific MII control/status registers.
+ */
+#define QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG 4
+#define QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS 17
+
+/*
+ * PHY-Specific Status Register (reg 17).
+ *
+ * Bit 0 : jabber => 1:jabber detected, 0:not
+ * Bit 1 : polarity => 1:polarity reversed, 0:normal
+ * Bit 2 : recvpause => 1:receive pause enabled, 0:disabled
+ * Bit 3 : xmitpause => 1:transmit pause enabled, 0:disabled
+ * Bit 4 : energydetect => 1:sleep, 0:active
+ * Bit 5 : downshift => 1:downshift, 0:no downshift
+ * Bit 6 : crossover => 1:MDIX (crossover), 0:MDI (no crossover)
+ * Bits 7-9 : cablelen => not valid in 10Mb/s mode
+ * 0:<50m, 1:50-80m, 2:80-110m, 3:110-140m, 4:>140m
+ * Bit 10 : link => 1:link up, 0:link down
+ * Bit 11 : resolved => 1:speed and duplex resolved, 0:not yet
+ * Bit 12 : pagercvd => 1:page received, 0:page not received
+ * Bit 13 : duplex => 1:full duplex, 0:half duplex
+ * Bits 14-15 : speed => 0:10Mb/s, 1:100Mb/s, 2:1000Mb/s, 3:rsvd
+ */
+
+#define qlcnic_get_phy_speed(config_word) (((config_word) >> 14) & 0x03)
+
+#define qlcnic_set_phy_speed(config_word, val) \
+ ((config_word) |= ((val & 0x03) << 14))
+#define qlcnic_set_phy_duplex(config_word) \
+ ((config_word) |= 1 << 13)
+#define qlcnic_clear_phy_duplex(config_word) \
+ ((config_word) &= ~(1 << 13))
+
+#define qlcnic_get_phy_link(config_word) \
+ _qlcnic_crb_get_bit(config_word, 10)
+#define qlcnic_get_phy_duplex(config_word) \
+ _qlcnic_crb_get_bit(config_word, 13)
+
+#define QLCNIC_NIU_NON_PROMISC_MODE 0
+#define QLCNIC_NIU_PROMISC_MODE 1
+#define QLCNIC_NIU_ALLMULTI_MODE 2
+
+struct crb_128M_2M_sub_block_map {
+ unsigned valid;
+ unsigned start_128M;
+ unsigned end_128M;
+ unsigned start_2M;
+};
+
+struct crb_128M_2M_block_map{
+ struct crb_128M_2M_sub_block_map sub_block[16];
+};
+#endif /* __QLCNIC_HDR_H_ */
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
new file mode 100644
index 000000000000..da00e162b6d3
--- /dev/null
+++ b/drivers/net/qlcnic/qlcnic_hw.c
@@ -0,0 +1,1256 @@
+/*
+ * Copyright (C) 2009 - QLogic 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".
+ *
+ */
+
+#include "qlcnic.h"
+
+#include <net/ip.h>
+
+#define MASK(n) ((1ULL<<(n))-1)
+#define OCM_WIN_P3P(addr) (addr & 0xffc0000)
+
+#define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
+
+#define CRB_BLK(off) ((off >> 20) & 0x3f)
+#define CRB_SUBBLK(off) ((off >> 16) & 0xf)
+#define CRB_WINDOW_2M (0x130060)
+#define CRB_HI(off) ((crb_hub_agt[CRB_BLK(off)] << 20) | ((off) & 0xf0000))
+#define CRB_INDIRECT_2M (0x1e0000UL)
+
+
+#ifndef readq
+static inline u64 readq(void __iomem *addr)
+{
+ return readl(addr) | (((u64) readl(addr + 4)) << 32LL);
+}
+#endif
+
+#ifndef writeq
+static inline void writeq(u64 val, void __iomem *addr)
+{
+ writel(((u32) (val)), (addr));
+ writel(((u32) (val >> 32)), (addr + 4));
+}
+#endif
+
+#define ADDR_IN_RANGE(addr, low, high) \
+ (((addr) < (high)) && ((addr) >= (low)))
+
+#define PCI_OFFSET_FIRST_RANGE(adapter, off) \
+ ((adapter)->ahw.pci_base0 + (off))
+
+static void __iomem *pci_base_offset(struct qlcnic_adapter *adapter,
+ unsigned long off)
+{
+ if (ADDR_IN_RANGE(off, FIRST_PAGE_GROUP_START, FIRST_PAGE_GROUP_END))
+ return PCI_OFFSET_FIRST_RANGE(adapter, off);
+
+ return NULL;
+}
+
+static const struct crb_128M_2M_block_map
+crb_128M_2M_map[64] __cacheline_aligned_in_smp = {
+ {{{0, 0, 0, 0} } }, /* 0: PCI */
+ {{{1, 0x0100000, 0x0102000, 0x120000}, /* 1: PCIE */
+ {1, 0x0110000, 0x0120000, 0x130000},
+ {1, 0x0120000, 0x0122000, 0x124000},
+ {1, 0x0130000, 0x0132000, 0x126000},
+ {1, 0x0140000, 0x0142000, 0x128000},
+ {1, 0x0150000, 0x0152000, 0x12a000},
+ {1, 0x0160000, 0x0170000, 0x110000},
+ {1, 0x0170000, 0x0172000, 0x12e000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {1, 0x01e0000, 0x01e0800, 0x122000},
+ {0, 0x0000000, 0x0000000, 0x000000} } },
+ {{{1, 0x0200000, 0x0210000, 0x180000} } },/* 2: MN */
+ {{{0, 0, 0, 0} } }, /* 3: */
+ {{{1, 0x0400000, 0x0401000, 0x169000} } },/* 4: P2NR1 */
+ {{{1, 0x0500000, 0x0510000, 0x140000} } },/* 5: SRE */
+ {{{1, 0x0600000, 0x0610000, 0x1c0000} } },/* 6: NIU */
+ {{{1, 0x0700000, 0x0704000, 0x1b8000} } },/* 7: QM */
+ {{{1, 0x0800000, 0x0802000, 0x170000}, /* 8: SQM0 */
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {1, 0x08f0000, 0x08f2000, 0x172000} } },
+ {{{1, 0x0900000, 0x0902000, 0x174000}, /* 9: SQM1*/
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {1, 0x09f0000, 0x09f2000, 0x176000} } },
+ {{{0, 0x0a00000, 0x0a02000, 0x178000}, /* 10: SQM2*/
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {1, 0x0af0000, 0x0af2000, 0x17a000} } },
+ {{{0, 0x0b00000, 0x0b02000, 0x17c000}, /* 11: SQM3*/
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {1, 0x0bf0000, 0x0bf2000, 0x17e000} } },
+ {{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },/* 12: I2Q */
+ {{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },/* 13: TMR */
+ {{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },/* 14: ROMUSB */
+ {{{1, 0x0f00000, 0x0f01000, 0x164000} } },/* 15: PEG4 */
+ {{{0, 0x1000000, 0x1004000, 0x1a8000} } },/* 16: XDMA */
+ {{{1, 0x1100000, 0x1101000, 0x160000} } },/* 17: PEG0 */
+ {{{1, 0x1200000, 0x1201000, 0x161000} } },/* 18: PEG1 */
+ {{{1, 0x1300000, 0x1301000, 0x162000} } },/* 19: PEG2 */
+ {{{1, 0x1400000, 0x1401000, 0x163000} } },/* 20: PEG3 */
+ {{{1, 0x1500000, 0x1501000, 0x165000} } },/* 21: P2ND */
+ {{{1, 0x1600000, 0x1601000, 0x166000} } },/* 22: P2NI */
+ {{{0, 0, 0, 0} } }, /* 23: */
+ {{{0, 0, 0, 0} } }, /* 24: */
+ {{{0, 0, 0, 0} } }, /* 25: */
+ {{{0, 0, 0, 0} } }, /* 26: */
+ {{{0, 0, 0, 0} } }, /* 27: */
+ {{{0, 0, 0, 0} } }, /* 28: */
+ {{{1, 0x1d00000, 0x1d10000, 0x190000} } },/* 29: MS */
+ {{{1, 0x1e00000, 0x1e01000, 0x16a000} } },/* 30: P2NR2 */
+ {{{1, 0x1f00000, 0x1f10000, 0x150000} } },/* 31: EPG */
+ {{{0} } }, /* 32: PCI */
+ {{{1, 0x2100000, 0x2102000, 0x120000}, /* 33: PCIE */
+ {1, 0x2110000, 0x2120000, 0x130000},
+ {1, 0x2120000, 0x2122000, 0x124000},
+ {1, 0x2130000, 0x2132000, 0x126000},
+ {1, 0x2140000, 0x2142000, 0x128000},
+ {1, 0x2150000, 0x2152000, 0x12a000},
+ {1, 0x2160000, 0x2170000, 0x110000},
+ {1, 0x2170000, 0x2172000, 0x12e000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000} } },
+ {{{1, 0x2200000, 0x2204000, 0x1b0000} } },/* 34: CAM */
+ {{{0} } }, /* 35: */
+ {{{0} } }, /* 36: */
+ {{{0} } }, /* 37: */
+ {{{0} } }, /* 38: */
+ {{{0} } }, /* 39: */
+ {{{1, 0x2800000, 0x2804000, 0x1a4000} } },/* 40: TMR */
+ {{{1, 0x2900000, 0x2901000, 0x16b000} } },/* 41: P2NR3 */
+ {{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },/* 42: RPMX1 */
+ {{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },/* 43: RPMX2 */
+ {{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },/* 44: RPMX3 */
+ {{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },/* 45: RPMX4 */
+ {{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },/* 46: RPMX5 */
+ {{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },/* 47: RPMX6 */
+ {{{1, 0x3000000, 0x3000400, 0x1adc00} } },/* 48: RPMX7 */
+ {{{0, 0x3100000, 0x3104000, 0x1a8000} } },/* 49: XDMA */
+ {{{1, 0x3200000, 0x3204000, 0x1d4000} } },/* 50: I2Q */
+ {{{1, 0x3300000, 0x3304000, 0x1a0000} } },/* 51: ROMUSB */
+ {{{0} } }, /* 52: */
+ {{{1, 0x3500000, 0x3500400, 0x1ac000} } },/* 53: RPMX0 */
+ {{{1, 0x3600000, 0x3600400, 0x1ae000} } },/* 54: RPMX8 */
+ {{{1, 0x3700000, 0x3700400, 0x1ae400} } },/* 55: RPMX9 */
+ {{{1, 0x3800000, 0x3804000, 0x1d0000} } },/* 56: OCM0 */
+ {{{1, 0x3900000, 0x3904000, 0x1b4000} } },/* 57: CRYPTO */
+ {{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },/* 58: SMB */
+ {{{0} } }, /* 59: I2C0 */
+ {{{0} } }, /* 60: I2C1 */
+ {{{1, 0x3d00000, 0x3d04000, 0x1d8000} } },/* 61: LPC */
+ {{{1, 0x3e00000, 0x3e01000, 0x167000} } },/* 62: P2NC */
+ {{{1, 0x3f00000, 0x3f01000, 0x168000} } } /* 63: P2NR0 */
+};
+
+/*
+ * top 12 bits of crb internal address (hub, agent)
+ */
+static const unsigned crb_hub_agt[64] = {
+ 0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PS,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_MN,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_MS,
+ 0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_SRE,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_NIU,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_QMN,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_SQN0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_SQN1,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_SQN2,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_SQN3,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PGN4,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PGN0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PGN1,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PGN2,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PGN3,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PGND,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PGNI,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PGS0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PGS1,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PGS2,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PGS3,
+ 0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PGSI,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_SN,
+ 0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_EG,
+ 0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PS,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_CAM,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR,
+ 0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX1,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX2,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX3,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX4,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX5,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX6,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX7,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB,
+ 0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX8,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX9,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_OCM0,
+ 0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_SMB,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_I2C0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_I2C1,
+ 0,
+ QLCNIC_HW_CRB_HUB_AGT_ADR_PGNC,
+ 0,
+};
+
+/* PCI Windowing for DDR regions. */
+
+#define QLCNIC_PCIE_SEM_TIMEOUT 10000
+
+int
+qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
+{
+ int done = 0, timeout = 0;
+
+ while (!done) {
+ done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)));
+ if (done == 1)
+ break;
+ if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT)
+ return -EIO;
+ msleep(1);
+ }
+
+ if (id_reg)
+ QLCWR32(adapter, id_reg, adapter->portnum);
+
+ return 0;
+}
+
+void
+qlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem)
+{
+ QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)));
+}
+
+static int
+qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
+ struct cmd_desc_type0 *cmd_desc_arr, int nr_desc)
+{
+ u32 i, producer, consumer;
+ struct qlcnic_cmd_buffer *pbuf;
+ struct cmd_desc_type0 *cmd_desc;
+ struct qlcnic_host_tx_ring *tx_ring;
+
+ i = 0;
+
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ return -EIO;
+
+ tx_ring = adapter->tx_ring;
+ __netif_tx_lock_bh(tx_ring->txq);
+
+ producer = tx_ring->producer;
+ consumer = tx_ring->sw_consumer;
+
+ if (nr_desc >= qlcnic_tx_avail(tx_ring)) {
+ netif_tx_stop_queue(tx_ring->txq);
+ __netif_tx_unlock_bh(tx_ring->txq);
+ adapter->stats.xmit_off++;
+ return -EBUSY;
+ }
+
+ do {
+ cmd_desc = &cmd_desc_arr[i];
+
+ pbuf = &tx_ring->cmd_buf_arr[producer];
+ pbuf->skb = NULL;
+ pbuf->frag_count = 0;
+
+ memcpy(&tx_ring->desc_head[producer],
+ &cmd_desc_arr[i], sizeof(struct cmd_desc_type0));
+
+ producer = get_next_index(producer, tx_ring->num_desc);
+ i++;
+
+ } while (i != nr_desc);
+
+ tx_ring->producer = producer;
+
+ qlcnic_update_cmd_producer(adapter, tx_ring);
+
+ __netif_tx_unlock_bh(tx_ring->txq);
+
+ return 0;
+}
+
+static int
+qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
+ unsigned op)
+{
+ struct qlcnic_nic_req req;
+ struct qlcnic_mac_req *mac_req;
+ u64 word;
+
+ memset(&req, 0, sizeof(struct qlcnic_nic_req));
+ req.qhdr = cpu_to_le64(QLCNIC_REQUEST << 23);
+
+ word = QLCNIC_MAC_EVENT | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+
+ mac_req = (struct qlcnic_mac_req *)&req.words[0];
+ mac_req->op = op;
+ memcpy(mac_req->mac_addr, addr, 6);
+
+ return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+}
+
+static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, u8 *addr)
+{
+ struct list_head *head;
+ struct qlcnic_mac_list_s *cur;
+
+ /* look up if already exists */
+ list_for_each(head, &adapter->mac_list) {
+ cur = list_entry(head, struct qlcnic_mac_list_s, list);
+ if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0)
+ return 0;
+ }
+
+ cur = kzalloc(sizeof(struct qlcnic_mac_list_s), GFP_ATOMIC);
+ if (cur == NULL) {
+ dev_err(&adapter->netdev->dev,
+ "failed to add mac address filter\n");
+ return -ENOMEM;
+ }
+ memcpy(cur->mac_addr, addr, ETH_ALEN);
+ list_add_tail(&cur->list, &adapter->mac_list);
+
+ return qlcnic_sre_macaddr_change(adapter,
+ cur->mac_addr, QLCNIC_MAC_ADD);
+}
+
+void qlcnic_set_multi(struct net_device *netdev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct dev_mc_list *mc_ptr;
+ u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ u32 mode = VPORT_MISS_MODE_DROP;
+
+ qlcnic_nic_add_mac(adapter, adapter->mac_addr);
+ qlcnic_nic_add_mac(adapter, bcast_addr);
+
+ if (netdev->flags & IFF_PROMISC) {
+ mode = VPORT_MISS_MODE_ACCEPT_ALL;
+ goto send_fw_cmd;
+ }
+
+ if ((netdev->flags & IFF_ALLMULTI) ||
+ (netdev_mc_count(netdev) > adapter->max_mc_count)) {
+ mode = VPORT_MISS_MODE_ACCEPT_MULTI;
+ goto send_fw_cmd;
+ }
+
+ if (!netdev_mc_empty(netdev)) {
+ netdev_for_each_mc_addr(mc_ptr, netdev) {
+ qlcnic_nic_add_mac(adapter, mc_ptr->dmi_addr);
+ }
+ }
+
+send_fw_cmd:
+ qlcnic_nic_set_promisc(adapter, mode);
+}
+
+int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
+{
+ struct qlcnic_nic_req req;
+ u64 word;
+
+ memset(&req, 0, sizeof(struct qlcnic_nic_req));
+
+ req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+ word = QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE |
+ ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+
+ req.words[0] = cpu_to_le64(mode);
+
+ return qlcnic_send_cmd_descs(adapter,
+ (struct cmd_desc_type0 *)&req, 1);
+}
+
+void qlcnic_free_mac_list(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_mac_list_s *cur;
+ struct list_head *head = &adapter->mac_list;
+
+ while (!list_empty(head)) {
+ cur = list_entry(head->next, struct qlcnic_mac_list_s, list);
+ qlcnic_sre_macaddr_change(adapter,
+ cur->mac_addr, QLCNIC_MAC_DEL);
+ list_del(&cur->list);
+ kfree(cur);
+ }
+}
+
+#define QLCNIC_CONFIG_INTR_COALESCE 3
+
+/*
+ * Send the interrupt coalescing parameter set by ethtool to the card.
+ */
+int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_nic_req req;
+ u64 word[6];
+ int rv, i;
+
+ memset(&req, 0, sizeof(struct qlcnic_nic_req));
+
+ req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+ word[0] = QLCNIC_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word[0]);
+
+ memcpy(&word[0], &adapter->coal, sizeof(adapter->coal));
+ for (i = 0; i < 6; i++)
+ req.words[i] = cpu_to_le64(word[i]);
+
+ rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv != 0)
+ dev_err(&adapter->netdev->dev,
+ "Could not send interrupt coalescing parameters\n");
+
+ return rv;
+}
+
+int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
+{
+ struct qlcnic_nic_req req;
+ u64 word;
+ int rv;
+
+ if ((adapter->flags & QLCNIC_LRO_ENABLED) == enable)
+ return 0;
+
+ memset(&req, 0, sizeof(struct qlcnic_nic_req));
+
+ req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+ word = QLCNIC_H2C_OPCODE_CONFIG_HW_LRO | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+
+ req.words[0] = cpu_to_le64(enable);
+
+ rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv != 0)
+ dev_err(&adapter->netdev->dev,
+ "Could not send configure hw lro request\n");
+
+ adapter->flags ^= QLCNIC_LRO_ENABLED;
+
+ return rv;
+}
+
+int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable)
+{
+ struct qlcnic_nic_req req;
+ u64 word;
+ int rv;
+
+ if (!!(adapter->flags & QLCNIC_BRIDGE_ENABLED) == enable)
+ return 0;
+
+ memset(&req, 0, sizeof(struct qlcnic_nic_req));
+
+ req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+ word = QLCNIC_H2C_OPCODE_CONFIG_BRIDGING |
+ ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+
+ req.words[0] = cpu_to_le64(enable);
+
+ rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv != 0)
+ dev_err(&adapter->netdev->dev,
+ "Could not send configure bridge mode request\n");
+
+ adapter->flags ^= QLCNIC_BRIDGE_ENABLED;
+
+ return rv;
+}
+
+
+#define RSS_HASHTYPE_IP_TCP 0x3
+
+int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
+{
+ struct qlcnic_nic_req req;
+ u64 word;
+ int i, rv;
+
+ const u64 key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
+ 0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
+ 0x255b0ec26d5a56daULL };
+
+
+ memset(&req, 0, sizeof(struct qlcnic_nic_req));
+ req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+ word = QLCNIC_H2C_OPCODE_CONFIG_RSS | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+
+ /*
+ * RSS request:
+ * bits 3-0: hash_method
+ * 5-4: hash_type_ipv4
+ * 7-6: hash_type_ipv6
+ * 8: enable
+ * 9: use indirection table
+ * 47-10: reserved
+ * 63-48: indirection table mask
+ */
+ word = ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
+ ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
+ ((u64)(enable & 0x1) << 8) |
+ ((0x7ULL) << 48);
+ req.words[0] = cpu_to_le64(word);
+ for (i = 0; i < 5; i++)
+ req.words[i+1] = cpu_to_le64(key[i]);
+
+ rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv != 0)
+ dev_err(&adapter->netdev->dev, "could not configure RSS\n");
+
+ return rv;
+}
+
+int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, u32 ip, int cmd)
+{
+ struct qlcnic_nic_req req;
+ u64 word;
+ int rv;
+
+ memset(&req, 0, sizeof(struct qlcnic_nic_req));
+ req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+ word = QLCNIC_H2C_OPCODE_CONFIG_IPADDR | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+
+ req.words[0] = cpu_to_le64(cmd);
+ req.words[1] = cpu_to_le64(ip);
+
+ rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv != 0)
+ dev_err(&adapter->netdev->dev,
+ "could not notify %s IP 0x%x reuqest\n",
+ (cmd == QLCNIC_IP_UP) ? "Add" : "Remove", ip);
+
+ return rv;
+}
+
+int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable)
+{
+ struct qlcnic_nic_req req;
+ u64 word;
+ int rv;
+
+ memset(&req, 0, sizeof(struct qlcnic_nic_req));
+ req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+ word = QLCNIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+ req.words[0] = cpu_to_le64(enable | (enable << 8));
+
+ rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv != 0)
+ dev_err(&adapter->netdev->dev,
+ "could not configure link notification\n");
+
+ return rv;
+}
+
+int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_nic_req req;
+ u64 word;
+ int rv;
+
+ memset(&req, 0, sizeof(struct qlcnic_nic_req));
+ req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+ word = QLCNIC_H2C_OPCODE_LRO_REQUEST |
+ ((u64)adapter->portnum << 16) |
+ ((u64)QLCNIC_LRO_REQUEST_CLEANUP << 56) ;
+
+ req.req_hdr = cpu_to_le64(word);
+
+ rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv != 0)
+ dev_err(&adapter->netdev->dev,
+ "could not cleanup lro flows\n");
+
+ return rv;
+}
+
+/*
+ * qlcnic_change_mtu - Change the Maximum Transfer Unit
+ * @returns 0 on success, negative on failure
+ */
+
+int qlcnic_change_mtu(struct net_device *netdev, int mtu)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ int rc = 0;
+
+ if (mtu > P3_MAX_MTU) {
+ dev_err(&adapter->netdev->dev, "mtu > %d bytes unsupported\n",
+ P3_MAX_MTU);
+ return -EINVAL;
+ }
+
+ rc = qlcnic_fw_cmd_set_mtu(adapter, mtu);
+
+ if (!rc)
+ netdev->mtu = mtu;
+
+ return rc;
+}
+
+int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac)
+{
+ u32 crbaddr, mac_hi, mac_lo;
+ int pci_func = adapter->ahw.pci_func;
+
+ crbaddr = CRB_MAC_BLOCK_START +
+ (4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1));
+
+ mac_lo = QLCRD32(adapter, crbaddr);
+ mac_hi = QLCRD32(adapter, crbaddr+4);
+
+ if (pci_func & 1)
+ *mac = le64_to_cpu((mac_lo >> 16) | ((u64)mac_hi << 16));
+ else
+ *mac = le64_to_cpu((u64)mac_lo | ((u64)mac_hi << 32));
+
+ return 0;
+}
+
+/*
+ * Changes the CRB window to the specified window.
+ */
+ /* Returns < 0 if off is not valid,
+ * 1 if window access is needed. 'off' is set to offset from
+ * CRB space in 128M pci map
+ * 0 if no window access is needed. 'off' is set to 2M addr
+ * In: 'off' is offset from base in 128M pci map
+ */
+static int
+qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter,
+ ulong off, void __iomem **addr)
+{
+ const struct crb_128M_2M_sub_block_map *m;
+
+ if ((off >= QLCNIC_CRB_MAX) || (off < QLCNIC_PCI_CRBSPACE))
+ return -EINVAL;
+
+ off -= QLCNIC_PCI_CRBSPACE;
+
+ /*
+ * Try direct map
+ */
+ m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)];
+
+ if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) {
+ *addr = adapter->ahw.pci_base0 + m->start_2M +
+ (off - m->start_128M);
+ return 0;
+ }
+
+ /*
+ * Not in direct map, use crb window
+ */
+ *addr = adapter->ahw.pci_base0 + CRB_INDIRECT_2M + (off & MASK(16));
+ return 1;
+}
+
+/*
+ * In: 'off' is offset from CRB space in 128M pci map
+ * Out: 'off' is 2M pci map addr
+ * side effect: lock crb window
+ */
+static void
+qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off)
+{
+ u32 window;
+ void __iomem *addr = adapter->ahw.pci_base0 + CRB_WINDOW_2M;
+
+ off -= QLCNIC_PCI_CRBSPACE;
+
+ window = CRB_HI(off);
+
+ if (adapter->ahw.crb_win == window)
+ return;
+
+ writel(window, addr);
+ if (readl(addr) != window) {
+ if (printk_ratelimit())
+ dev_warn(&adapter->pdev->dev,
+ "failed to set CRB window to %d off 0x%lx\n",
+ window, off);
+ }
+ adapter->ahw.crb_win = window;
+}
+
+int
+qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data)
+{
+ unsigned long flags;
+ int rv;
+ void __iomem *addr = NULL;
+
+ rv = qlcnic_pci_get_crb_addr_2M(adapter, off, &addr);
+
+ if (rv == 0) {
+ writel(data, addr);
+ return 0;
+ }
+
+ if (rv > 0) {
+ /* indirect access */
+ write_lock_irqsave(&adapter->ahw.crb_lock, flags);
+ crb_win_lock(adapter);
+ qlcnic_pci_set_crbwindow_2M(adapter, off);
+ writel(data, addr);
+ crb_win_unlock(adapter);
+ write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
+ return 0;
+ }
+
+ dev_err(&adapter->pdev->dev,
+ "%s: invalid offset: 0x%016lx\n", __func__, off);
+ dump_stack();
+ return -EIO;
+}
+
+u32
+qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
+{
+ unsigned long flags;
+ int rv;
+ u32 data;
+ void __iomem *addr = NULL;
+
+ rv = qlcnic_pci_get_crb_addr_2M(adapter, off, &addr);
+
+ if (rv == 0)
+ return readl(addr);
+
+ if (rv > 0) {
+ /* indirect access */
+ write_lock_irqsave(&adapter->ahw.crb_lock, flags);
+ crb_win_lock(adapter);
+ qlcnic_pci_set_crbwindow_2M(adapter, off);
+ data = readl(addr);
+ crb_win_unlock(adapter);
+ write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
+ return data;
+ }
+
+ dev_err(&adapter->pdev->dev,
+ "%s: invalid offset: 0x%016lx\n", __func__, off);
+ dump_stack();
+ return -1;
+}
+
+
+void __iomem *
+qlcnic_get_ioaddr(struct qlcnic_adapter *adapter, u32 offset)
+{
+ void __iomem *addr = NULL;
+
+ WARN_ON(qlcnic_pci_get_crb_addr_2M(adapter, offset, &addr));
+
+ return addr;
+}
+
+
+static int
+qlcnic_pci_set_window_2M(struct qlcnic_adapter *adapter,
+ u64 addr, u32 *start)
+{
+ u32 window;
+ struct pci_dev *pdev = adapter->pdev;
+
+ if ((addr & 0x00ff800) == 0xff800) {
+ if (printk_ratelimit())
+ dev_warn(&pdev->dev, "QM access not handled\n");
+ return -EIO;
+ }
+
+ window = OCM_WIN_P3P(addr);
+
+ writel(window, adapter->ahw.ocm_win_crb);
+ /* read back to flush */
+ readl(adapter->ahw.ocm_win_crb);
+
+ adapter->ahw.ocm_win = window;
+ *start = QLCNIC_PCI_OCM0_2M + GET_MEM_OFFS_2M(addr);
+ return 0;
+}
+
+static int
+qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off,
+ u64 *data, int op)
+{
+ void __iomem *addr, *mem_ptr = NULL;
+ resource_size_t mem_base;
+ int ret;
+ u32 start;
+
+ mutex_lock(&adapter->ahw.mem_lock);
+
+ ret = qlcnic_pci_set_window_2M(adapter, off, &start);
+ if (ret != 0)
+ goto unlock;
+
+ addr = pci_base_offset(adapter, start);
+ if (addr)
+ goto noremap;
+
+ mem_base = pci_resource_start(adapter->pdev, 0) + (start & PAGE_MASK);
+
+ mem_ptr = ioremap(mem_base, PAGE_SIZE);
+ if (mem_ptr == NULL) {
+ ret = -EIO;
+ goto unlock;
+ }
+
+ addr = mem_ptr + (start & (PAGE_SIZE - 1));
+
+noremap:
+ if (op == 0) /* read */
+ *data = readq(addr);
+ else /* write */
+ writeq(*data, addr);
+
+unlock:
+ mutex_unlock(&adapter->ahw.mem_lock);
+
+ if (mem_ptr)
+ iounmap(mem_ptr);
+ return ret;
+}
+
+#define MAX_CTL_CHECK 1000
+
+int
+qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter,
+ u64 off, u64 data)
+{
+ int i, j, ret;
+ u32 temp, off8;
+ u64 stride;
+ void __iomem *mem_crb;
+
+ /* Only 64-bit aligned access */
+ if (off & 7)
+ return -EIO;
+
+ /* P3 onward, test agent base for MIU and SIU is same */
+ if (ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET,
+ QLCNIC_ADDR_QDR_NET_MAX_P3)) {
+ mem_crb = qlcnic_get_ioaddr(adapter,
+ QLCNIC_CRB_QDR_NET+MIU_TEST_AGT_BASE);
+ goto correct;
+ }
+
+ if (ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET, QLCNIC_ADDR_DDR_NET_MAX)) {
+ mem_crb = qlcnic_get_ioaddr(adapter,
+ QLCNIC_CRB_DDR_NET+MIU_TEST_AGT_BASE);
+ goto correct;
+ }
+
+ if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX))
+ return qlcnic_pci_mem_access_direct(adapter, off, &data, 1);
+
+ return -EIO;
+
+correct:
+ stride = QLCNIC_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8;
+
+ off8 = off & ~(stride-1);
+
+ mutex_lock(&adapter->ahw.mem_lock);
+
+ writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO));
+ writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI));
+
+ i = 0;
+ if (stride == 16) {
+ writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL));
+ writel((TA_CTL_START | TA_CTL_ENABLE),
+ (mem_crb + TEST_AGT_CTRL));
+
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ temp = readl(mem_crb + TEST_AGT_CTRL);
+ if ((temp & TA_CTL_BUSY) == 0)
+ break;
+ }
+
+ if (j >= MAX_CTL_CHECK) {
+ ret = -EIO;
+ goto done;
+ }
+
+ i = (off & 0xf) ? 0 : 2;
+ writel(readl(mem_crb + MIU_TEST_AGT_RDDATA(i)),
+ mem_crb + MIU_TEST_AGT_WRDATA(i));
+ writel(readl(mem_crb + MIU_TEST_AGT_RDDATA(i+1)),
+ mem_crb + MIU_TEST_AGT_WRDATA(i+1));
+ i = (off & 0xf) ? 2 : 0;
+ }
+
+ writel(data & 0xffffffff,
+ mem_crb + MIU_TEST_AGT_WRDATA(i));
+ writel((data >> 32) & 0xffffffff,
+ mem_crb + MIU_TEST_AGT_WRDATA(i+1));
+
+ writel((TA_CTL_ENABLE | TA_CTL_WRITE), (mem_crb + TEST_AGT_CTRL));
+ writel((TA_CTL_START | TA_CTL_ENABLE | TA_CTL_WRITE),
+ (mem_crb + TEST_AGT_CTRL));
+
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ temp = readl(mem_crb + TEST_AGT_CTRL);
+ if ((temp & TA_CTL_BUSY) == 0)
+ break;
+ }
+
+ if (j >= MAX_CTL_CHECK) {
+ if (printk_ratelimit())
+ dev_err(&adapter->pdev->dev,
+ "failed to write through agent\n");
+ ret = -EIO;
+ } else
+ ret = 0;
+
+done:
+ mutex_unlock(&adapter->ahw.mem_lock);
+
+ return ret;
+}
+
+int
+qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter,
+ u64 off, u64 *data)
+{
+ int j, ret;
+ u32 temp, off8;
+ u64 val, stride;
+ void __iomem *mem_crb;
+
+ /* Only 64-bit aligned access */
+ if (off & 7)
+ return -EIO;
+
+ /* P3 onward, test agent base for MIU and SIU is same */
+ if (ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET,
+ QLCNIC_ADDR_QDR_NET_MAX_P3)) {
+ mem_crb = qlcnic_get_ioaddr(adapter,
+ QLCNIC_CRB_QDR_NET+MIU_TEST_AGT_BASE);
+ goto correct;
+ }
+
+ if (ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET, QLCNIC_ADDR_DDR_NET_MAX)) {
+ mem_crb = qlcnic_get_ioaddr(adapter,
+ QLCNIC_CRB_DDR_NET+MIU_TEST_AGT_BASE);
+ goto correct;
+ }
+
+ if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX)) {
+ return qlcnic_pci_mem_access_direct(adapter,
+ off, data, 0);
+ }
+
+ return -EIO;
+
+correct:
+ stride = QLCNIC_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8;
+
+ off8 = off & ~(stride-1);
+
+ mutex_lock(&adapter->ahw.mem_lock);
+
+ writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO));
+ writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI));
+ writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL));
+ writel((TA_CTL_START | TA_CTL_ENABLE), (mem_crb + TEST_AGT_CTRL));
+
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ temp = readl(mem_crb + TEST_AGT_CTRL);
+ if ((temp & TA_CTL_BUSY) == 0)
+ break;
+ }
+
+ if (j >= MAX_CTL_CHECK) {
+ if (printk_ratelimit())
+ dev_err(&adapter->pdev->dev,
+ "failed to read through agent\n");
+ ret = -EIO;
+ } else {
+ off8 = MIU_TEST_AGT_RDDATA_LO;
+ if ((stride == 16) && (off & 0xf))
+ off8 = MIU_TEST_AGT_RDDATA_UPPER_LO;
+
+ temp = readl(mem_crb + off8 + 4);
+ val = (u64)temp << 32;
+ val |= readl(mem_crb + off8);
+ *data = val;
+ ret = 0;
+ }
+
+ mutex_unlock(&adapter->ahw.mem_lock);
+
+ return ret;
+}
+
+int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
+{
+ int offset, board_type, magic;
+ struct pci_dev *pdev = adapter->pdev;
+
+ offset = QLCNIC_FW_MAGIC_OFFSET;
+ if (qlcnic_rom_fast_read(adapter, offset, &magic))
+ return -EIO;
+
+ if (magic != QLCNIC_BDINFO_MAGIC) {
+ dev_err(&pdev->dev, "invalid board config, magic=%08x\n",
+ magic);
+ return -EIO;
+ }
+
+ offset = QLCNIC_BRDTYPE_OFFSET;
+ if (qlcnic_rom_fast_read(adapter, offset, &board_type))
+ return -EIO;
+
+ adapter->ahw.board_type = board_type;
+
+ if (board_type == QLCNIC_BRDTYPE_P3_4_GB_MM) {
+ u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I);
+ if ((gpio & 0x8000) == 0)
+ board_type = QLCNIC_BRDTYPE_P3_10G_TP;
+ }
+
+ switch (board_type) {
+ case QLCNIC_BRDTYPE_P3_HMEZ:
+ case QLCNIC_BRDTYPE_P3_XG_LOM:
+ case QLCNIC_BRDTYPE_P3_10G_CX4:
+ case QLCNIC_BRDTYPE_P3_10G_CX4_LP:
+ case QLCNIC_BRDTYPE_P3_IMEZ:
+ case QLCNIC_BRDTYPE_P3_10G_SFP_PLUS:
+ case QLCNIC_BRDTYPE_P3_10G_SFP_CT:
+ case QLCNIC_BRDTYPE_P3_10G_SFP_QT:
+ case QLCNIC_BRDTYPE_P3_10G_XFP:
+ case QLCNIC_BRDTYPE_P3_10000_BASE_T:
+ adapter->ahw.port_type = QLCNIC_XGBE;
+ break;
+ case QLCNIC_BRDTYPE_P3_REF_QG:
+ case QLCNIC_BRDTYPE_P3_4_GB:
+ case QLCNIC_BRDTYPE_P3_4_GB_MM:
+ adapter->ahw.port_type = QLCNIC_GBE;
+ break;
+ case QLCNIC_BRDTYPE_P3_10G_TP:
+ adapter->ahw.port_type = (adapter->portnum < 2) ?
+ QLCNIC_XGBE : QLCNIC_GBE;
+ break;
+ default:
+ dev_err(&pdev->dev, "unknown board type %x\n", board_type);
+ adapter->ahw.port_type = QLCNIC_XGBE;
+ break;
+ }
+
+ return 0;
+}
+
+int
+qlcnic_wol_supported(struct qlcnic_adapter *adapter)
+{
+ u32 wol_cfg;
+
+ wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+ if (wol_cfg & (1UL << adapter->portnum)) {
+ wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+ if (wol_cfg & (1 << adapter->portnum))
+ return 1;
+ }
+
+ return 0;
+}
+
+int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
+{
+ struct qlcnic_nic_req req;
+ int rv;
+ u64 word;
+
+ memset(&req, 0, sizeof(struct qlcnic_nic_req));
+ req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+ word = QLCNIC_H2C_OPCODE_CONFIG_LED | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+
+ req.words[0] = cpu_to_le64((u64)rate << 32);
+ req.words[1] = cpu_to_le64(state);
+
+ rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv)
+ dev_err(&adapter->pdev->dev, "LED configuration failed.\n");
+
+ return rv;
+}
+
+static int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u32 flag)
+{
+ struct qlcnic_nic_req req;
+ int rv;
+ u64 word;
+
+ memset(&req, 0, sizeof(struct qlcnic_nic_req));
+ req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+ word = QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK |
+ ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+ req.words[0] = cpu_to_le64(flag);
+
+ rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv)
+ dev_err(&adapter->pdev->dev,
+ "%sting loopback mode failed.\n",
+ flag ? "Set" : "Reset");
+ return rv;
+}
+
+int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter)
+{
+ if (qlcnic_set_fw_loopback(adapter, 1))
+ return -EIO;
+
+ if (qlcnic_nic_set_promisc(adapter,
+ VPORT_MISS_MODE_ACCEPT_ALL)) {
+ qlcnic_set_fw_loopback(adapter, 0);
+ return -EIO;
+ }
+
+ msleep(1000);
+ return 0;
+}
+
+void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter)
+{
+ int mode = VPORT_MISS_MODE_DROP;
+ struct net_device *netdev = adapter->netdev;
+
+ qlcnic_set_fw_loopback(adapter, 0);
+
+ if (netdev->flags & IFF_PROMISC)
+ mode = VPORT_MISS_MODE_ACCEPT_ALL;
+ else if (netdev->flags & IFF_ALLMULTI)
+ mode = VPORT_MISS_MODE_ACCEPT_MULTI;
+
+ qlcnic_nic_set_promisc(adapter, mode);
+}
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
new file mode 100644
index 000000000000..7c34e4e29b3f
--- /dev/null
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -0,0 +1,1677 @@
+/*
+ * Copyright (C) 2009 - QLogic 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".
+ *
+ */
+
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include "qlcnic.h"
+
+struct crb_addr_pair {
+ u32 addr;
+ u32 data;
+};
+
+#define QLCNIC_MAX_CRB_XFORM 60
+static unsigned int crb_addr_xform[QLCNIC_MAX_CRB_XFORM];
+
+#define crb_addr_transform(name) \
+ (crb_addr_xform[QLCNIC_HW_PX_MAP_CRB_##name] = \
+ QLCNIC_HW_CRB_HUB_AGT_ADR_##name << 20)
+
+#define QLCNIC_ADDR_ERROR (0xffffffff)
+
+static void
+qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_rds_ring *rds_ring);
+
+static void crb_addr_transform_setup(void)
+{
+ crb_addr_transform(XDMA);
+ crb_addr_transform(TIMR);
+ crb_addr_transform(SRE);
+ crb_addr_transform(SQN3);
+ crb_addr_transform(SQN2);
+ crb_addr_transform(SQN1);
+ crb_addr_transform(SQN0);
+ crb_addr_transform(SQS3);
+ crb_addr_transform(SQS2);
+ crb_addr_transform(SQS1);
+ crb_addr_transform(SQS0);
+ crb_addr_transform(RPMX7);
+ crb_addr_transform(RPMX6);
+ crb_addr_transform(RPMX5);
+ crb_addr_transform(RPMX4);
+ crb_addr_transform(RPMX3);
+ crb_addr_transform(RPMX2);
+ crb_addr_transform(RPMX1);
+ crb_addr_transform(RPMX0);
+ crb_addr_transform(ROMUSB);
+ crb_addr_transform(SN);
+ crb_addr_transform(QMN);
+ crb_addr_transform(QMS);
+ crb_addr_transform(PGNI);
+ crb_addr_transform(PGND);
+ crb_addr_transform(PGN3);
+ crb_addr_transform(PGN2);
+ crb_addr_transform(PGN1);
+ crb_addr_transform(PGN0);
+ crb_addr_transform(PGSI);
+ crb_addr_transform(PGSD);
+ crb_addr_transform(PGS3);
+ crb_addr_transform(PGS2);
+ crb_addr_transform(PGS1);
+ crb_addr_transform(PGS0);
+ crb_addr_transform(PS);
+ crb_addr_transform(PH);
+ crb_addr_transform(NIU);
+ crb_addr_transform(I2Q);
+ crb_addr_transform(EG);
+ crb_addr_transform(MN);
+ crb_addr_transform(MS);
+ crb_addr_transform(CAS2);
+ crb_addr_transform(CAS1);
+ crb_addr_transform(CAS0);
+ crb_addr_transform(CAM);
+ crb_addr_transform(C2C1);
+ crb_addr_transform(C2C0);
+ crb_addr_transform(SMB);
+ crb_addr_transform(OCM0);
+ crb_addr_transform(I2C0);
+}
+
+void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_recv_context *recv_ctx;
+ struct qlcnic_host_rds_ring *rds_ring;
+ struct qlcnic_rx_buffer *rx_buf;
+ int i, ring;
+
+ recv_ctx = &adapter->recv_ctx;
+ for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+ rds_ring = &recv_ctx->rds_rings[ring];
+ for (i = 0; i < rds_ring->num_desc; ++i) {
+ rx_buf = &(rds_ring->rx_buf_arr[i]);
+ if (rx_buf->state == QLCNIC_BUFFER_FREE)
+ continue;
+ pci_unmap_single(adapter->pdev,
+ rx_buf->dma,
+ rds_ring->dma_size,
+ PCI_DMA_FROMDEVICE);
+ if (rx_buf->skb != NULL)
+ dev_kfree_skb_any(rx_buf->skb);
+ }
+ }
+}
+
+void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_cmd_buffer *cmd_buf;
+ struct qlcnic_skb_frag *buffrag;
+ int i, j;
+ struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+
+ cmd_buf = tx_ring->cmd_buf_arr;
+ for (i = 0; i < tx_ring->num_desc; i++) {
+ buffrag = cmd_buf->frag_array;
+ if (buffrag->dma) {
+ pci_unmap_single(adapter->pdev, buffrag->dma,
+ buffrag->length, PCI_DMA_TODEVICE);
+ buffrag->dma = 0ULL;
+ }
+ for (j = 0; j < cmd_buf->frag_count; j++) {
+ buffrag++;
+ if (buffrag->dma) {
+ pci_unmap_page(adapter->pdev, buffrag->dma,
+ buffrag->length,
+ PCI_DMA_TODEVICE);
+ buffrag->dma = 0ULL;
+ }
+ }
+ if (cmd_buf->skb) {
+ dev_kfree_skb_any(cmd_buf->skb);
+ cmd_buf->skb = NULL;
+ }
+ cmd_buf++;
+ }
+}
+
+void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_recv_context *recv_ctx;
+ struct qlcnic_host_rds_ring *rds_ring;
+ struct qlcnic_host_tx_ring *tx_ring;
+ int ring;
+
+ recv_ctx = &adapter->recv_ctx;
+
+ if (recv_ctx->rds_rings == NULL)
+ goto skip_rds;
+
+ for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+ rds_ring = &recv_ctx->rds_rings[ring];
+ vfree(rds_ring->rx_buf_arr);
+ rds_ring->rx_buf_arr = NULL;
+ }
+ kfree(recv_ctx->rds_rings);
+
+skip_rds:
+ if (adapter->tx_ring == NULL)
+ return;
+
+ tx_ring = adapter->tx_ring;
+ vfree(tx_ring->cmd_buf_arr);
+ kfree(adapter->tx_ring);
+}
+
+int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_recv_context *recv_ctx;
+ struct qlcnic_host_rds_ring *rds_ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_host_tx_ring *tx_ring;
+ struct qlcnic_rx_buffer *rx_buf;
+ int ring, i, size;
+
+ struct qlcnic_cmd_buffer *cmd_buf_arr;
+ struct net_device *netdev = adapter->netdev;
+
+ size = sizeof(struct qlcnic_host_tx_ring);
+ tx_ring = kzalloc(size, GFP_KERNEL);
+ if (tx_ring == NULL) {
+ dev_err(&netdev->dev, "failed to allocate tx ring struct\n");
+ return -ENOMEM;
+ }
+ adapter->tx_ring = tx_ring;
+
+ tx_ring->num_desc = adapter->num_txd;
+ tx_ring->txq = netdev_get_tx_queue(netdev, 0);
+
+ cmd_buf_arr = vmalloc(TX_BUFF_RINGSIZE(tx_ring));
+ if (cmd_buf_arr == NULL) {
+ dev_err(&netdev->dev, "failed to allocate cmd buffer ring\n");
+ return -ENOMEM;
+ }
+ memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring));
+ tx_ring->cmd_buf_arr = cmd_buf_arr;
+
+ recv_ctx = &adapter->recv_ctx;
+
+ size = adapter->max_rds_rings * sizeof(struct qlcnic_host_rds_ring);
+ rds_ring = kzalloc(size, GFP_KERNEL);
+ if (rds_ring == NULL) {
+ dev_err(&netdev->dev, "failed to allocate rds ring struct\n");
+ return -ENOMEM;
+ }
+ recv_ctx->rds_rings = rds_ring;
+
+ for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+ rds_ring = &recv_ctx->rds_rings[ring];
+ switch (ring) {
+ case RCV_RING_NORMAL:
+ rds_ring->num_desc = adapter->num_rxd;
+ if (adapter->ahw.cut_through) {
+ rds_ring->dma_size =
+ QLCNIC_CT_DEFAULT_RX_BUF_LEN;
+ rds_ring->skb_size =
+ QLCNIC_CT_DEFAULT_RX_BUF_LEN;
+ } else {
+ rds_ring->dma_size =
+ QLCNIC_P3_RX_BUF_MAX_LEN;
+ rds_ring->skb_size =
+ rds_ring->dma_size + NET_IP_ALIGN;
+ }
+ break;
+
+ case RCV_RING_JUMBO:
+ rds_ring->num_desc = adapter->num_jumbo_rxd;
+ rds_ring->dma_size =
+ QLCNIC_P3_RX_JUMBO_BUF_MAX_LEN;
+
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
+ rds_ring->dma_size += QLCNIC_LRO_BUFFER_EXTRA;
+
+ rds_ring->skb_size =
+ rds_ring->dma_size + NET_IP_ALIGN;
+ break;
+
+ case RCV_RING_LRO:
+ rds_ring->num_desc = adapter->num_lro_rxd;
+ rds_ring->dma_size = QLCNIC_RX_LRO_BUFFER_LENGTH;
+ rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN;
+ break;
+
+ }
+ rds_ring->rx_buf_arr = (struct qlcnic_rx_buffer *)
+ vmalloc(RCV_BUFF_RINGSIZE(rds_ring));
+ if (rds_ring->rx_buf_arr == NULL) {
+ dev_err(&netdev->dev, "Failed to allocate "
+ "rx buffer ring %d\n", ring);
+ goto err_out;
+ }
+ memset(rds_ring->rx_buf_arr, 0, RCV_BUFF_RINGSIZE(rds_ring));
+ INIT_LIST_HEAD(&rds_ring->free_list);
+ /*
+ * Now go through all of them, set reference handles
+ * and put them in the queues.
+ */
+ rx_buf = rds_ring->rx_buf_arr;
+ for (i = 0; i < rds_ring->num_desc; i++) {
+ list_add_tail(&rx_buf->list,
+ &rds_ring->free_list);
+ rx_buf->ref_handle = i;
+ rx_buf->state = QLCNIC_BUFFER_FREE;
+ rx_buf++;
+ }
+ spin_lock_init(&rds_ring->lock);
+ }
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ sds_ring->irq = adapter->msix_entries[ring].vector;
+ sds_ring->adapter = adapter;
+ sds_ring->num_desc = adapter->num_rxd;
+
+ for (i = 0; i < NUM_RCV_DESC_RINGS; i++)
+ INIT_LIST_HEAD(&sds_ring->free_list[i]);
+ }
+
+ return 0;
+
+err_out:
+ qlcnic_free_sw_resources(adapter);
+ return -ENOMEM;
+}
+
+/*
+ * Utility to translate from internal Phantom CRB address
+ * to external PCI CRB address.
+ */
+static u32 qlcnic_decode_crb_addr(u32 addr)
+{
+ int i;
+ u32 base_addr, offset, pci_base;
+
+ crb_addr_transform_setup();
+
+ pci_base = QLCNIC_ADDR_ERROR;
+ base_addr = addr & 0xfff00000;
+ offset = addr & 0x000fffff;
+
+ for (i = 0; i < QLCNIC_MAX_CRB_XFORM; i++) {
+ if (crb_addr_xform[i] == base_addr) {
+ pci_base = i << 20;
+ break;
+ }
+ }
+ if (pci_base == QLCNIC_ADDR_ERROR)
+ return pci_base;
+ else
+ return pci_base + offset;
+}
+
+#define QLCNIC_MAX_ROM_WAIT_USEC 100
+
+static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter)
+{
+ long timeout = 0;
+ long done = 0;
+
+ cond_resched();
+
+ while (done == 0) {
+ done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS);
+ done &= 2;
+ if (++timeout >= QLCNIC_MAX_ROM_WAIT_USEC) {
+ dev_err(&adapter->pdev->dev,
+ "Timeout reached waiting for rom done");
+ return -EIO;
+ }
+ udelay(1);
+ }
+ return 0;
+}
+
+static int do_rom_fast_read(struct qlcnic_adapter *adapter,
+ int addr, int *valp)
+{
+ QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr);
+ QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
+ QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 3);
+ QLCWR32(adapter, QLCNIC_ROMUSB_ROM_INSTR_OPCODE, 0xb);
+ if (qlcnic_wait_rom_done(adapter)) {
+ dev_err(&adapter->pdev->dev, "Error waiting for rom done\n");
+ return -EIO;
+ }
+ /* reset abyte_cnt and dummy_byte_cnt */
+ QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 0);
+ udelay(10);
+ QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
+
+ *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA);
+ return 0;
+}
+
+static int do_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr,
+ u8 *bytes, size_t size)
+{
+ int addridx;
+ int ret = 0;
+
+ for (addridx = addr; addridx < (addr + size); addridx += 4) {
+ int v;
+ ret = do_rom_fast_read(adapter, addridx, &v);
+ if (ret != 0)
+ break;
+ *(__le32 *)bytes = cpu_to_le32(v);
+ bytes += 4;
+ }
+
+ return ret;
+}
+
+int
+qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr,
+ u8 *bytes, size_t size)
+{
+ int ret;
+
+ ret = qlcnic_rom_lock(adapter);
+ if (ret < 0)
+ return ret;
+
+ ret = do_rom_fast_read_words(adapter, addr, bytes, size);
+
+ qlcnic_rom_unlock(adapter);
+ return ret;
+}
+
+int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp)
+{
+ int ret;
+
+ if (qlcnic_rom_lock(adapter) != 0)
+ return -EIO;
+
+ ret = do_rom_fast_read(adapter, addr, valp);
+ qlcnic_rom_unlock(adapter);
+ return ret;
+}
+
+int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
+{
+ int addr, val;
+ int i, n, init_delay;
+ struct crb_addr_pair *buf;
+ unsigned offset;
+ u32 off;
+ struct pci_dev *pdev = adapter->pdev;
+
+ /* resetall */
+ qlcnic_rom_lock(adapter);
+ QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xffffffff);
+ qlcnic_rom_unlock(adapter);
+
+ if (qlcnic_rom_fast_read(adapter, 0, &n) != 0 || (n != 0xcafecafe) ||
+ qlcnic_rom_fast_read(adapter, 4, &n) != 0) {
+ dev_err(&pdev->dev, "ERROR Reading crb_init area: val:%x\n", n);
+ return -EIO;
+ }
+ offset = n & 0xffffU;
+ n = (n >> 16) & 0xffffU;
+
+ if (n >= 1024) {
+ dev_err(&pdev->dev, "QLOGIC card flash not initialized.\n");
+ return -EIO;
+ }
+
+ buf = kcalloc(n, sizeof(struct crb_addr_pair), GFP_KERNEL);
+ if (buf == NULL) {
+ dev_err(&pdev->dev, "Unable to calloc memory for rom read.\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (qlcnic_rom_fast_read(adapter, 8*i + 4*offset, &val) != 0 ||
+ qlcnic_rom_fast_read(adapter, 8*i + 4*offset + 4, &addr) != 0) {
+ kfree(buf);
+ return -EIO;
+ }
+
+ buf[i].addr = addr;
+ buf[i].data = val;
+ }
+
+ for (i = 0; i < n; i++) {
+
+ off = qlcnic_decode_crb_addr(buf[i].addr);
+ if (off == QLCNIC_ADDR_ERROR) {
+ dev_err(&pdev->dev, "CRB init value out of range %x\n",
+ buf[i].addr);
+ continue;
+ }
+ off += QLCNIC_PCI_CRBSPACE;
+
+ if (off & 1)
+ continue;
+
+ /* skipping cold reboot MAGIC */
+ if (off == QLCNIC_CAM_RAM(0x1fc))
+ continue;
+ if (off == (QLCNIC_CRB_I2C0 + 0x1c))
+ continue;
+ if (off == (ROMUSB_GLB + 0xbc)) /* do not reset PCI */
+ continue;
+ if (off == (ROMUSB_GLB + 0xa8))
+ continue;
+ if (off == (ROMUSB_GLB + 0xc8)) /* core clock */
+ continue;
+ if (off == (ROMUSB_GLB + 0x24)) /* MN clock */
+ continue;
+ if (off == (ROMUSB_GLB + 0x1c)) /* MS clock */
+ continue;
+ if ((off & 0x0ff00000) == QLCNIC_CRB_DDR_NET)
+ continue;
+ /* skip the function enable register */
+ if (off == QLCNIC_PCIE_REG(PCIE_SETUP_FUNCTION))
+ continue;
+ if (off == QLCNIC_PCIE_REG(PCIE_SETUP_FUNCTION2))
+ continue;
+ if ((off & 0x0ff00000) == QLCNIC_CRB_SMB)
+ continue;
+
+ init_delay = 1;
+ /* After writing this register, HW needs time for CRB */
+ /* to quiet down (else crb_window returns 0xffffffff) */
+ if (off == QLCNIC_ROMUSB_GLB_SW_RESET)
+ init_delay = 1000;
+
+ QLCWR32(adapter, off, buf[i].data);
+
+ msleep(init_delay);
+ }
+ kfree(buf);
+
+ /* p2dn replyCount */
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_D + 0xec, 0x1e);
+ /* disable_peg_cache 0 & 1*/
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_D + 0x4c, 8);
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_I + 0x4c, 8);
+
+ /* peg_clr_all */
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x8, 0);
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0xc, 0);
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x8, 0);
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_1 + 0xc, 0);
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x8, 0);
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_2 + 0xc, 0);
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x8, 0);
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0xc, 0);
+ return 0;
+}
+
+static int
+qlcnic_has_mn(struct qlcnic_adapter *adapter)
+{
+ u32 capability, flashed_ver;
+ capability = 0;
+
+ qlcnic_rom_fast_read(adapter,
+ QLCNIC_FW_VERSION_OFFSET, (int *)&flashed_ver);
+ flashed_ver = QLCNIC_DECODE_VERSION(flashed_ver);
+
+ if (flashed_ver >= QLCNIC_VERSION_CODE(4, 0, 220)) {
+
+ capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY);
+ if (capability & QLCNIC_PEG_TUNE_MN_PRESENT)
+ return 1;
+ }
+ return 0;
+}
+
+static
+struct uni_table_desc *qlcnic_get_table_desc(const u8 *unirom, int section)
+{
+ u32 i;
+ struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0];
+ __le32 entries = cpu_to_le32(directory->num_entries);
+
+ for (i = 0; i < entries; i++) {
+
+ __le32 offs = cpu_to_le32(directory->findex) +
+ (i * cpu_to_le32(directory->entry_size));
+ __le32 tab_type = cpu_to_le32(*((u32 *)&unirom[offs] + 8));
+
+ if (tab_type == section)
+ return (struct uni_table_desc *) &unirom[offs];
+ }
+
+ return NULL;
+}
+
+#define FILEHEADER_SIZE (14 * 4)
+
+static int
+qlcnic_validate_header(struct qlcnic_adapter *adapter)
+{
+ const u8 *unirom = adapter->fw->data;
+ struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0];
+ __le32 fw_file_size = adapter->fw->size;
+ __le32 entries;
+ __le32 entry_size;
+ __le32 tab_size;
+
+ if (fw_file_size < FILEHEADER_SIZE)
+ return -EINVAL;
+
+ entries = cpu_to_le32(directory->num_entries);
+ entry_size = cpu_to_le32(directory->entry_size);
+ tab_size = cpu_to_le32(directory->findex) + (entries * entry_size);
+
+ if (fw_file_size < tab_size)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+qlcnic_validate_bootld(struct qlcnic_adapter *adapter)
+{
+ struct uni_table_desc *tab_desc;
+ struct uni_data_desc *descr;
+ const u8 *unirom = adapter->fw->data;
+ int idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] +
+ QLCNIC_UNI_BOOTLD_IDX_OFF));
+ __le32 offs;
+ __le32 tab_size;
+ __le32 data_size;
+
+ tab_desc = qlcnic_get_table_desc(unirom, QLCNIC_UNI_DIR_SECT_BOOTLD);
+
+ if (!tab_desc)
+ return -EINVAL;
+
+ tab_size = cpu_to_le32(tab_desc->findex) +
+ (cpu_to_le32(tab_desc->entry_size * (idx + 1)));
+
+ if (adapter->fw->size < tab_size)
+ return -EINVAL;
+
+ offs = cpu_to_le32(tab_desc->findex) +
+ (cpu_to_le32(tab_desc->entry_size) * (idx));
+ descr = (struct uni_data_desc *)&unirom[offs];
+
+ data_size = descr->findex + cpu_to_le32(descr->size);
+
+ if (adapter->fw->size < data_size)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+qlcnic_validate_fw(struct qlcnic_adapter *adapter)
+{
+ struct uni_table_desc *tab_desc;
+ struct uni_data_desc *descr;
+ const u8 *unirom = adapter->fw->data;
+ int idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] +
+ QLCNIC_UNI_FIRMWARE_IDX_OFF));
+ __le32 offs;
+ __le32 tab_size;
+ __le32 data_size;
+
+ tab_desc = qlcnic_get_table_desc(unirom, QLCNIC_UNI_DIR_SECT_FW);
+
+ if (!tab_desc)
+ return -EINVAL;
+
+ tab_size = cpu_to_le32(tab_desc->findex) +
+ (cpu_to_le32(tab_desc->entry_size * (idx + 1)));
+
+ if (adapter->fw->size < tab_size)
+ return -EINVAL;
+
+ offs = cpu_to_le32(tab_desc->findex) +
+ (cpu_to_le32(tab_desc->entry_size) * (idx));
+ descr = (struct uni_data_desc *)&unirom[offs];
+ data_size = descr->findex + cpu_to_le32(descr->size);
+
+ if (adapter->fw->size < data_size)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+qlcnic_validate_product_offs(struct qlcnic_adapter *adapter)
+{
+ struct uni_table_desc *ptab_descr;
+ const u8 *unirom = adapter->fw->data;
+ int mn_present = qlcnic_has_mn(adapter);
+ __le32 entries;
+ __le32 entry_size;
+ __le32 tab_size;
+ u32 i;
+
+ ptab_descr = qlcnic_get_table_desc(unirom,
+ QLCNIC_UNI_DIR_SECT_PRODUCT_TBL);
+ if (!ptab_descr)
+ return -EINVAL;
+
+ entries = cpu_to_le32(ptab_descr->num_entries);
+ entry_size = cpu_to_le32(ptab_descr->entry_size);
+ tab_size = cpu_to_le32(ptab_descr->findex) + (entries * entry_size);
+
+ if (adapter->fw->size < tab_size)
+ return -EINVAL;
+
+nomn:
+ for (i = 0; i < entries; i++) {
+
+ __le32 flags, file_chiprev, offs;
+ u8 chiprev = adapter->ahw.revision_id;
+ u32 flagbit;
+
+ offs = cpu_to_le32(ptab_descr->findex) +
+ (i * cpu_to_le32(ptab_descr->entry_size));
+ flags = cpu_to_le32(*((int *)&unirom[offs] +
+ QLCNIC_UNI_FLAGS_OFF));
+ file_chiprev = cpu_to_le32(*((int *)&unirom[offs] +
+ QLCNIC_UNI_CHIP_REV_OFF));
+
+ flagbit = mn_present ? 1 : 2;
+
+ if ((chiprev == file_chiprev) &&
+ ((1ULL << flagbit) & flags)) {
+ adapter->file_prd_off = offs;
+ return 0;
+ }
+ }
+ if (mn_present) {
+ mn_present = 0;
+ goto nomn;
+ }
+ return -EINVAL;
+}
+
+static int
+qlcnic_validate_unified_romimage(struct qlcnic_adapter *adapter)
+{
+ if (qlcnic_validate_header(adapter)) {
+ dev_err(&adapter->pdev->dev,
+ "unified image: header validation failed\n");
+ return -EINVAL;
+ }
+
+ if (qlcnic_validate_product_offs(adapter)) {
+ dev_err(&adapter->pdev->dev,
+ "unified image: product validation failed\n");
+ return -EINVAL;
+ }
+
+ if (qlcnic_validate_bootld(adapter)) {
+ dev_err(&adapter->pdev->dev,
+ "unified image: bootld validation failed\n");
+ return -EINVAL;
+ }
+
+ if (qlcnic_validate_fw(adapter)) {
+ dev_err(&adapter->pdev->dev,
+ "unified image: firmware validation failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static
+struct uni_data_desc *qlcnic_get_data_desc(struct qlcnic_adapter *adapter,
+ u32 section, u32 idx_offset)
+{
+ const u8 *unirom = adapter->fw->data;
+ int idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] +
+ idx_offset));
+ struct uni_table_desc *tab_desc;
+ __le32 offs;
+
+ tab_desc = qlcnic_get_table_desc(unirom, section);
+
+ if (tab_desc == NULL)
+ return NULL;
+
+ offs = cpu_to_le32(tab_desc->findex) +
+ (cpu_to_le32(tab_desc->entry_size) * idx);
+
+ return (struct uni_data_desc *)&unirom[offs];
+}
+
+static u8 *
+qlcnic_get_bootld_offs(struct qlcnic_adapter *adapter)
+{
+ u32 offs = QLCNIC_BOOTLD_START;
+
+ if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE)
+ offs = cpu_to_le32((qlcnic_get_data_desc(adapter,
+ QLCNIC_UNI_DIR_SECT_BOOTLD,
+ QLCNIC_UNI_BOOTLD_IDX_OFF))->findex);
+
+ return (u8 *)&adapter->fw->data[offs];
+}
+
+static u8 *
+qlcnic_get_fw_offs(struct qlcnic_adapter *adapter)
+{
+ u32 offs = QLCNIC_IMAGE_START;
+
+ if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE)
+ offs = cpu_to_le32((qlcnic_get_data_desc(adapter,
+ QLCNIC_UNI_DIR_SECT_FW,
+ QLCNIC_UNI_FIRMWARE_IDX_OFF))->findex);
+
+ return (u8 *)&adapter->fw->data[offs];
+}
+
+static __le32
+qlcnic_get_fw_size(struct qlcnic_adapter *adapter)
+{
+ if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE)
+ return cpu_to_le32((qlcnic_get_data_desc(adapter,
+ QLCNIC_UNI_DIR_SECT_FW,
+ QLCNIC_UNI_FIRMWARE_IDX_OFF))->size);
+ else
+ return cpu_to_le32(
+ *(u32 *)&adapter->fw->data[QLCNIC_FW_SIZE_OFFSET]);
+}
+
+static __le32
+qlcnic_get_fw_version(struct qlcnic_adapter *adapter)
+{
+ struct uni_data_desc *fw_data_desc;
+ const struct firmware *fw = adapter->fw;
+ __le32 major, minor, sub;
+ const u8 *ver_str;
+ int i, ret;
+
+ if (adapter->fw_type != QLCNIC_UNIFIED_ROMIMAGE)
+ return cpu_to_le32(*(u32 *)&fw->data[QLCNIC_FW_VERSION_OFFSET]);
+
+ fw_data_desc = qlcnic_get_data_desc(adapter, QLCNIC_UNI_DIR_SECT_FW,
+ QLCNIC_UNI_FIRMWARE_IDX_OFF);
+ ver_str = fw->data + cpu_to_le32(fw_data_desc->findex) +
+ cpu_to_le32(fw_data_desc->size) - 17;
+
+ for (i = 0; i < 12; i++) {
+ if (!strncmp(&ver_str[i], "REV=", 4)) {
+ ret = sscanf(&ver_str[i+4], "%u.%u.%u ",
+ &major, &minor, &sub);
+ if (ret != 3)
+ return 0;
+ else
+ return major + (minor << 8) + (sub << 16);
+ }
+ }
+
+ return 0;
+}
+
+static __le32
+qlcnic_get_bios_version(struct qlcnic_adapter *adapter)
+{
+ const struct firmware *fw = adapter->fw;
+ __le32 bios_ver, prd_off = adapter->file_prd_off;
+
+ if (adapter->fw_type != QLCNIC_UNIFIED_ROMIMAGE)
+ return cpu_to_le32(
+ *(u32 *)&fw->data[QLCNIC_BIOS_VERSION_OFFSET]);
+
+ bios_ver = cpu_to_le32(*((u32 *) (&fw->data[prd_off])
+ + QLCNIC_UNI_BIOS_VERSION_OFF));
+
+ return (bios_ver << 16) + ((bios_ver >> 8) & 0xff00) + (bios_ver >> 24);
+}
+
+int
+qlcnic_need_fw_reset(struct qlcnic_adapter *adapter)
+{
+ u32 count, old_count;
+ u32 val, version, major, minor, build;
+ int i, timeout;
+
+ if (adapter->need_fw_reset)
+ return 1;
+
+ /* last attempt had failed */
+ if (QLCRD32(adapter, CRB_CMDPEG_STATE) == PHAN_INITIALIZE_FAILED)
+ return 1;
+
+ old_count = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+
+ for (i = 0; i < 10; i++) {
+
+ timeout = msleep_interruptible(200);
+ if (timeout) {
+ QLCWR32(adapter, CRB_CMDPEG_STATE,
+ PHAN_INITIALIZE_FAILED);
+ return -EINTR;
+ }
+
+ count = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+ if (count != old_count)
+ break;
+ }
+
+ /* firmware is dead */
+ if (count == old_count)
+ return 1;
+
+ /* check if we have got newer or different file firmware */
+ if (adapter->fw) {
+
+ val = qlcnic_get_fw_version(adapter);
+
+ version = QLCNIC_DECODE_VERSION(val);
+
+ major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+ minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
+ build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+
+ if (version > QLCNIC_VERSION_CODE(major, minor, build))
+ return 1;
+ }
+
+ return 0;
+}
+
+static const char *fw_name[] = {
+ QLCNIC_UNIFIED_ROMIMAGE_NAME,
+ QLCNIC_FLASH_ROMIMAGE_NAME,
+};
+
+int
+qlcnic_load_firmware(struct qlcnic_adapter *adapter)
+{
+ u64 *ptr64;
+ u32 i, flashaddr, size;
+ const struct firmware *fw = adapter->fw;
+ struct pci_dev *pdev = adapter->pdev;
+
+ dev_info(&pdev->dev, "loading firmware from %s\n",
+ fw_name[adapter->fw_type]);
+
+ if (fw) {
+ __le64 data;
+
+ size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8;
+
+ ptr64 = (u64 *)qlcnic_get_bootld_offs(adapter);
+ flashaddr = QLCNIC_BOOTLD_START;
+
+ for (i = 0; i < size; i++) {
+ data = cpu_to_le64(ptr64[i]);
+
+ if (qlcnic_pci_mem_write_2M(adapter, flashaddr, data))
+ return -EIO;
+
+ flashaddr += 8;
+ }
+
+ size = (__force u32)qlcnic_get_fw_size(adapter) / 8;
+
+ ptr64 = (u64 *)qlcnic_get_fw_offs(adapter);
+ flashaddr = QLCNIC_IMAGE_START;
+
+ for (i = 0; i < size; i++) {
+ data = cpu_to_le64(ptr64[i]);
+
+ if (qlcnic_pci_mem_write_2M(adapter,
+ flashaddr, data))
+ return -EIO;
+
+ flashaddr += 8;
+ }
+ } else {
+ u64 data;
+ u32 hi, lo;
+
+ size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8;
+ flashaddr = QLCNIC_BOOTLD_START;
+
+ for (i = 0; i < size; i++) {
+ if (qlcnic_rom_fast_read(adapter,
+ flashaddr, (int *)&lo) != 0)
+ return -EIO;
+ if (qlcnic_rom_fast_read(adapter,
+ flashaddr + 4, (int *)&hi) != 0)
+ return -EIO;
+
+ data = (((u64)hi << 32) | lo);
+
+ if (qlcnic_pci_mem_write_2M(adapter,
+ flashaddr, data))
+ return -EIO;
+
+ flashaddr += 8;
+ }
+ }
+ msleep(1);
+
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x18, 0x1020);
+ QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0x80001e);
+ return 0;
+}
+
+static int
+qlcnic_validate_firmware(struct qlcnic_adapter *adapter)
+{
+ __le32 val;
+ u32 ver, min_ver, bios, min_size;
+ struct pci_dev *pdev = adapter->pdev;
+ const struct firmware *fw = adapter->fw;
+ u8 fw_type = adapter->fw_type;
+
+ if (fw_type == QLCNIC_UNIFIED_ROMIMAGE) {
+ if (qlcnic_validate_unified_romimage(adapter))
+ return -EINVAL;
+
+ min_size = QLCNIC_UNI_FW_MIN_SIZE;
+ } else {
+ val = cpu_to_le32(*(u32 *)&fw->data[QLCNIC_FW_MAGIC_OFFSET]);
+ if ((__force u32)val != QLCNIC_BDINFO_MAGIC)
+ return -EINVAL;
+
+ min_size = QLCNIC_FW_MIN_SIZE;
+ }
+
+ if (fw->size < min_size)
+ return -EINVAL;
+
+ val = qlcnic_get_fw_version(adapter);
+
+ min_ver = QLCNIC_VERSION_CODE(4, 0, 216);
+
+ ver = QLCNIC_DECODE_VERSION(val);
+
+ if ((_major(ver) > _QLCNIC_LINUX_MAJOR) || (ver < min_ver)) {
+ dev_err(&pdev->dev,
+ "%s: firmware version %d.%d.%d unsupported\n",
+ fw_name[fw_type], _major(ver), _minor(ver), _build(ver));
+ return -EINVAL;
+ }
+
+ val = qlcnic_get_bios_version(adapter);
+ qlcnic_rom_fast_read(adapter, QLCNIC_BIOS_VERSION_OFFSET, (int *)&bios);
+ if ((__force u32)val != bios) {
+ dev_err(&pdev->dev, "%s: firmware bios is incompatible\n",
+ fw_name[fw_type]);
+ return -EINVAL;
+ }
+
+ /* check if flashed firmware is newer */
+ if (qlcnic_rom_fast_read(adapter,
+ QLCNIC_FW_VERSION_OFFSET, (int *)&val))
+ return -EIO;
+
+ val = QLCNIC_DECODE_VERSION(val);
+ if (val > ver) {
+ dev_info(&pdev->dev, "%s: firmware is older than flash\n",
+ fw_name[fw_type]);
+ return -EINVAL;
+ }
+
+ QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC);
+ return 0;
+}
+
+static void
+qlcnic_get_next_fwtype(struct qlcnic_adapter *adapter)
+{
+ u8 fw_type;
+
+ switch (adapter->fw_type) {
+ case QLCNIC_UNKNOWN_ROMIMAGE:
+ fw_type = QLCNIC_UNIFIED_ROMIMAGE;
+ break;
+
+ case QLCNIC_UNIFIED_ROMIMAGE:
+ default:
+ fw_type = QLCNIC_FLASH_ROMIMAGE;
+ break;
+ }
+
+ adapter->fw_type = fw_type;
+}
+
+
+
+void qlcnic_request_firmware(struct qlcnic_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ int rc;
+
+ adapter->fw_type = QLCNIC_UNKNOWN_ROMIMAGE;
+
+next:
+ qlcnic_get_next_fwtype(adapter);
+
+ if (adapter->fw_type == QLCNIC_FLASH_ROMIMAGE) {
+ adapter->fw = NULL;
+ } else {
+ rc = request_firmware(&adapter->fw,
+ fw_name[adapter->fw_type], &pdev->dev);
+ if (rc != 0)
+ goto next;
+
+ rc = qlcnic_validate_firmware(adapter);
+ if (rc != 0) {
+ release_firmware(adapter->fw);
+ msleep(1);
+ goto next;
+ }
+ }
+}
+
+
+void
+qlcnic_release_firmware(struct qlcnic_adapter *adapter)
+{
+ if (adapter->fw)
+ release_firmware(adapter->fw);
+ adapter->fw = NULL;
+}
+
+int qlcnic_phantom_init(struct qlcnic_adapter *adapter)
+{
+ u32 val;
+ int retries = 60;
+
+ do {
+ val = QLCRD32(adapter, CRB_CMDPEG_STATE);
+
+ switch (val) {
+ case PHAN_INITIALIZE_COMPLETE:
+ case PHAN_INITIALIZE_ACK:
+ return 0;
+ case PHAN_INITIALIZE_FAILED:
+ goto out_err;
+ default:
+ break;
+ }
+
+ msleep(500);
+
+ } while (--retries);
+
+ QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
+
+out_err:
+ dev_err(&adapter->pdev->dev, "firmware init failed\n");
+ return -EIO;
+}
+
+static int
+qlcnic_receive_peg_ready(struct qlcnic_adapter *adapter)
+{
+ u32 val;
+ int retries = 2000;
+
+ do {
+ val = QLCRD32(adapter, CRB_RCVPEG_STATE);
+
+ if (val == PHAN_PEG_RCV_INITIALIZED)
+ return 0;
+
+ msleep(10);
+
+ } while (--retries);
+
+ if (!retries) {
+ dev_err(&adapter->pdev->dev, "Receive Peg initialization not "
+ "complete, state: 0x%x.\n", val);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int qlcnic_init_firmware(struct qlcnic_adapter *adapter)
+{
+ int err;
+
+ err = qlcnic_receive_peg_ready(adapter);
+ if (err)
+ return err;
+
+ QLCWR32(adapter, CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT);
+ QLCWR32(adapter, CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC);
+ QLCWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE);
+ QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
+
+ return err;
+}
+
+static void
+qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
+ struct qlcnic_fw_msg *msg)
+{
+ u32 cable_OUI;
+ u16 cable_len;
+ u16 link_speed;
+ u8 link_status, module, duplex, autoneg;
+ struct net_device *netdev = adapter->netdev;
+
+ adapter->has_link_events = 1;
+
+ cable_OUI = msg->body[1] & 0xffffffff;
+ cable_len = (msg->body[1] >> 32) & 0xffff;
+ link_speed = (msg->body[1] >> 48) & 0xffff;
+
+ link_status = msg->body[2] & 0xff;
+ duplex = (msg->body[2] >> 16) & 0xff;
+ autoneg = (msg->body[2] >> 24) & 0xff;
+
+ module = (msg->body[2] >> 8) & 0xff;
+ if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE)
+ dev_info(&netdev->dev, "unsupported cable: OUI 0x%x, "
+ "length %d\n", cable_OUI, cable_len);
+ else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN)
+ dev_info(&netdev->dev, "unsupported cable length %d\n",
+ cable_len);
+
+ qlcnic_advert_link_change(adapter, link_status);
+
+ if (duplex == LINKEVENT_FULL_DUPLEX)
+ adapter->link_duplex = DUPLEX_FULL;
+ else
+ adapter->link_duplex = DUPLEX_HALF;
+
+ adapter->module_type = module;
+ adapter->link_autoneg = autoneg;
+ adapter->link_speed = link_speed;
+}
+
+static void
+qlcnic_handle_fw_message(int desc_cnt, int index,
+ struct qlcnic_host_sds_ring *sds_ring)
+{
+ struct qlcnic_fw_msg msg;
+ struct status_desc *desc;
+ int i = 0, opcode;
+
+ while (desc_cnt > 0 && i < 8) {
+ desc = &sds_ring->desc_head[index];
+ msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]);
+ msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]);
+
+ index = get_next_index(index, sds_ring->num_desc);
+ desc_cnt--;
+ }
+
+ opcode = qlcnic_get_nic_msg_opcode(msg.body[0]);
+ switch (opcode) {
+ case QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE:
+ qlcnic_handle_linkevent(sds_ring->adapter, &msg);
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_rds_ring *rds_ring,
+ struct qlcnic_rx_buffer *buffer)
+{
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ struct pci_dev *pdev = adapter->pdev;
+
+ buffer->skb = dev_alloc_skb(rds_ring->skb_size);
+ if (!buffer->skb) {
+ adapter->stats.skb_alloc_failure++;
+ return -ENOMEM;
+ }
+
+ skb = buffer->skb;
+
+ if (!adapter->ahw.cut_through)
+ skb_reserve(skb, 2);
+
+ dma = pci_map_single(pdev, skb->data,
+ rds_ring->dma_size, PCI_DMA_FROMDEVICE);
+
+ if (pci_dma_mapping_error(pdev, dma)) {
+ dev_kfree_skb_any(skb);
+ buffer->skb = NULL;
+ return -ENOMEM;
+ }
+
+ buffer->skb = skb;
+ buffer->dma = dma;
+ buffer->state = QLCNIC_BUFFER_BUSY;
+
+ return 0;
+}
+
+static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_rds_ring *rds_ring, u16 index, u16 cksum)
+{
+ struct qlcnic_rx_buffer *buffer;
+ struct sk_buff *skb;
+
+ buffer = &rds_ring->rx_buf_arr[index];
+
+ pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
+ PCI_DMA_FROMDEVICE);
+
+ skb = buffer->skb;
+ if (!skb)
+ goto no_skb;
+
+ if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) {
+ adapter->stats.csummed++;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+
+ skb->dev = adapter->netdev;
+
+ buffer->skb = NULL;
+no_skb:
+ buffer->state = QLCNIC_BUFFER_FREE;
+ return skb;
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_process_rcv(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_sds_ring *sds_ring,
+ int ring, u64 sts_data0)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_rx_buffer *buffer;
+ struct sk_buff *skb;
+ struct qlcnic_host_rds_ring *rds_ring;
+ int index, length, cksum, pkt_offset;
+
+ if (unlikely(ring >= adapter->max_rds_rings))
+ return NULL;
+
+ rds_ring = &recv_ctx->rds_rings[ring];
+
+ index = qlcnic_get_sts_refhandle(sts_data0);
+ if (unlikely(index >= rds_ring->num_desc))
+ return NULL;
+
+ buffer = &rds_ring->rx_buf_arr[index];
+
+ length = qlcnic_get_sts_totallength(sts_data0);
+ cksum = qlcnic_get_sts_status(sts_data0);
+ pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
+
+ skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+ if (!skb)
+ return buffer;
+
+ if (length > rds_ring->skb_size)
+ skb_put(skb, rds_ring->skb_size);
+ else
+ skb_put(skb, length);
+
+ if (pkt_offset)
+ skb_pull(skb, pkt_offset);
+
+ skb->truesize = skb->len + sizeof(struct sk_buff);
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ napi_gro_receive(&sds_ring->napi, skb);
+
+ adapter->stats.rx_pkts++;
+ adapter->stats.rxbytes += length;
+
+ return buffer;
+}
+
+#define QLC_TCP_HDR_SIZE 20
+#define QLC_TCP_TS_OPTION_SIZE 12
+#define QLC_TCP_TS_HDR_SIZE (QLC_TCP_HDR_SIZE + QLC_TCP_TS_OPTION_SIZE)
+
+static struct qlcnic_rx_buffer *
+qlcnic_process_lro(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_sds_ring *sds_ring,
+ int ring, u64 sts_data0, u64 sts_data1)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_rx_buffer *buffer;
+ struct sk_buff *skb;
+ struct qlcnic_host_rds_ring *rds_ring;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ bool push, timestamp;
+ int l2_hdr_offset, l4_hdr_offset;
+ int index;
+ u16 lro_length, length, data_offset;
+ u32 seq_number;
+
+ if (unlikely(ring > adapter->max_rds_rings))
+ return NULL;
+
+ rds_ring = &recv_ctx->rds_rings[ring];
+
+ index = qlcnic_get_lro_sts_refhandle(sts_data0);
+ if (unlikely(index > rds_ring->num_desc))
+ return NULL;
+
+ buffer = &rds_ring->rx_buf_arr[index];
+
+ timestamp = qlcnic_get_lro_sts_timestamp(sts_data0);
+ lro_length = qlcnic_get_lro_sts_length(sts_data0);
+ l2_hdr_offset = qlcnic_get_lro_sts_l2_hdr_offset(sts_data0);
+ l4_hdr_offset = qlcnic_get_lro_sts_l4_hdr_offset(sts_data0);
+ push = qlcnic_get_lro_sts_push_flag(sts_data0);
+ seq_number = qlcnic_get_lro_sts_seq_number(sts_data1);
+
+ skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
+ if (!skb)
+ return buffer;
+
+ if (timestamp)
+ data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE;
+ else
+ data_offset = l4_hdr_offset + QLC_TCP_HDR_SIZE;
+
+ skb_put(skb, lro_length + data_offset);
+
+ skb->truesize = skb->len + sizeof(struct sk_buff) + skb_headroom(skb);
+
+ skb_pull(skb, l2_hdr_offset);
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ iph = (struct iphdr *)skb->data;
+ th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
+
+ length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+ iph->tot_len = htons(length);
+ iph->check = 0;
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+ th->psh = push;
+ th->seq = htonl(seq_number);
+
+ length = skb->len;
+
+ netif_receive_skb(skb);
+
+ adapter->stats.lro_pkts++;
+ adapter->stats.lrobytes += length;
+
+ return buffer;
+}
+
+int
+qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
+{
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+ struct list_head *cur;
+ struct status_desc *desc;
+ struct qlcnic_rx_buffer *rxbuf;
+ u64 sts_data0, sts_data1;
+
+ int count = 0;
+ int opcode, ring, desc_cnt;
+ u32 consumer = sds_ring->consumer;
+
+ while (count < max) {
+ desc = &sds_ring->desc_head[consumer];
+ sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
+
+ if (!(sts_data0 & STATUS_OWNER_HOST))
+ break;
+
+ desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
+ opcode = qlcnic_get_sts_opcode(sts_data0);
+
+ switch (opcode) {
+ case QLCNIC_RXPKT_DESC:
+ case QLCNIC_OLD_RXPKT_DESC:
+ case QLCNIC_SYN_OFFLOAD:
+ ring = qlcnic_get_sts_type(sts_data0);
+ rxbuf = qlcnic_process_rcv(adapter, sds_ring,
+ ring, sts_data0);
+ break;
+ case QLCNIC_LRO_DESC:
+ ring = qlcnic_get_lro_sts_type(sts_data0);
+ sts_data1 = le64_to_cpu(desc->status_desc_data[1]);
+ rxbuf = qlcnic_process_lro(adapter, sds_ring,
+ ring, sts_data0, sts_data1);
+ break;
+ case QLCNIC_RESPONSE_DESC:
+ qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
+ default:
+ goto skip;
+ }
+
+ WARN_ON(desc_cnt > 1);
+
+ if (rxbuf)
+ list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
+
+skip:
+ for (; desc_cnt > 0; desc_cnt--) {
+ desc = &sds_ring->desc_head[consumer];
+ desc->status_desc_data[0] =
+ cpu_to_le64(STATUS_OWNER_PHANTOM);
+ consumer = get_next_index(consumer, sds_ring->num_desc);
+ }
+ count++;
+ }
+
+ for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+ struct qlcnic_host_rds_ring *rds_ring =
+ &adapter->recv_ctx.rds_rings[ring];
+
+ if (!list_empty(&sds_ring->free_list[ring])) {
+ list_for_each(cur, &sds_ring->free_list[ring]) {
+ rxbuf = list_entry(cur,
+ struct qlcnic_rx_buffer, list);
+ qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf);
+ }
+ spin_lock(&rds_ring->lock);
+ list_splice_tail_init(&sds_ring->free_list[ring],
+ &rds_ring->free_list);
+ spin_unlock(&rds_ring->lock);
+ }
+
+ qlcnic_post_rx_buffers_nodb(adapter, rds_ring);
+ }
+
+ if (count) {
+ sds_ring->consumer = consumer;
+ writel(consumer, sds_ring->crb_sts_consumer);
+ }
+
+ return count;
+}
+
+void
+qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid,
+ struct qlcnic_host_rds_ring *rds_ring)
+{
+ struct rcv_desc *pdesc;
+ struct qlcnic_rx_buffer *buffer;
+ int producer, count = 0;
+ struct list_head *head;
+
+ producer = rds_ring->producer;
+
+ spin_lock(&rds_ring->lock);
+ head = &rds_ring->free_list;
+ while (!list_empty(head)) {
+
+ buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
+
+ if (!buffer->skb) {
+ if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
+ break;
+ }
+
+ count++;
+ list_del(&buffer->list);
+
+ /* make a rcv descriptor */
+ pdesc = &rds_ring->desc_head[producer];
+ pdesc->addr_buffer = cpu_to_le64(buffer->dma);
+ pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+ pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
+
+ producer = get_next_index(producer, rds_ring->num_desc);
+ }
+ spin_unlock(&rds_ring->lock);
+
+ if (count) {
+ rds_ring->producer = producer;
+ writel((producer-1) & (rds_ring->num_desc-1),
+ rds_ring->crb_rcv_producer);
+ }
+}
+
+static void
+qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_rds_ring *rds_ring)
+{
+ struct rcv_desc *pdesc;
+ struct qlcnic_rx_buffer *buffer;
+ int producer, count = 0;
+ struct list_head *head;
+
+ producer = rds_ring->producer;
+ if (!spin_trylock(&rds_ring->lock))
+ return;
+
+ head = &rds_ring->free_list;
+ while (!list_empty(head)) {
+
+ buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
+
+ if (!buffer->skb) {
+ if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
+ break;
+ }
+
+ count++;
+ list_del(&buffer->list);
+
+ /* make a rcv descriptor */
+ pdesc = &rds_ring->desc_head[producer];
+ pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+ pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
+ pdesc->addr_buffer = cpu_to_le64(buffer->dma);
+
+ producer = get_next_index(producer, rds_ring->num_desc);
+ }
+
+ if (count) {
+ rds_ring->producer = producer;
+ writel((producer - 1) & (rds_ring->num_desc - 1),
+ rds_ring->crb_rcv_producer);
+ }
+ spin_unlock(&rds_ring->lock);
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_sds_ring *sds_ring,
+ int ring, u64 sts_data0)
+{
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_rx_buffer *buffer;
+ struct sk_buff *skb;
+ struct qlcnic_host_rds_ring *rds_ring;
+ int index, length, cksum, pkt_offset;
+
+ if (unlikely(ring >= adapter->max_rds_rings))
+ return NULL;
+
+ rds_ring = &recv_ctx->rds_rings[ring];
+
+ index = qlcnic_get_sts_refhandle(sts_data0);
+ if (unlikely(index >= rds_ring->num_desc))
+ return NULL;
+
+ buffer = &rds_ring->rx_buf_arr[index];
+
+ length = qlcnic_get_sts_totallength(sts_data0);
+ cksum = qlcnic_get_sts_status(sts_data0);
+ pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
+
+ skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+ if (!skb)
+ return buffer;
+
+ skb_put(skb, rds_ring->skb_size);
+
+ if (pkt_offset)
+ skb_pull(skb, pkt_offset);
+
+ skb->truesize = skb->len + sizeof(struct sk_buff);
+
+ if (!qlcnic_check_loopback_buff(skb->data))
+ adapter->diag_cnt++;
+
+ dev_kfree_skb_any(skb);
+ adapter->stats.rx_pkts++;
+ adapter->stats.rxbytes += length;
+
+ return buffer;
+}
+
+void
+qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+ struct status_desc *desc;
+ struct qlcnic_rx_buffer *rxbuf;
+ u64 sts_data0;
+
+ int opcode, ring, desc_cnt;
+ u32 consumer = sds_ring->consumer;
+
+ desc = &sds_ring->desc_head[consumer];
+ sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
+
+ if (!(sts_data0 & STATUS_OWNER_HOST))
+ return;
+
+ desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
+ opcode = qlcnic_get_sts_opcode(sts_data0);
+
+ ring = qlcnic_get_sts_type(sts_data0);
+ rxbuf = qlcnic_process_rcv_diag(adapter, sds_ring,
+ ring, sts_data0);
+
+ desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
+ consumer = get_next_index(consumer, sds_ring->num_desc);
+
+ sds_ring->consumer = consumer;
+ writel(consumer, sds_ring->crb_sts_consumer);
+}
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
new file mode 100644
index 000000000000..fc721564e69e
--- /dev/null
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -0,0 +1,2725 @@
+/*
+ * Copyright (C) 2009 - QLogic 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".
+ *
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+
+#include "qlcnic.h"
+
+#include <linux/dma-mapping.h>
+#include <linux/if_vlan.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+#include <linux/inetdevice.h>
+#include <linux/sysfs.h>
+
+MODULE_DESCRIPTION("QLogic 10 GbE Converged Ethernet Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(QLCNIC_LINUX_VERSIONID);
+MODULE_FIRMWARE(QLCNIC_UNIFIED_ROMIMAGE_NAME);
+
+char qlcnic_driver_name[] = "qlcnic";
+static const char qlcnic_driver_string[] = "QLogic Converged Ethernet Driver v"
+ QLCNIC_LINUX_VERSIONID;
+
+static int port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
+
+/* Default to restricted 1G auto-neg mode */
+static int wol_port_mode = 5;
+
+static int use_msi = 1;
+module_param(use_msi, int, 0644);
+MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled");
+
+static int use_msi_x = 1;
+module_param(use_msi_x, int, 0644);
+MODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled");
+
+static int auto_fw_reset = AUTO_FW_RESET_ENABLED;
+module_param(auto_fw_reset, int, 0644);
+MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled");
+
+static int __devinit qlcnic_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+static void __devexit qlcnic_remove(struct pci_dev *pdev);
+static int qlcnic_open(struct net_device *netdev);
+static int qlcnic_close(struct net_device *netdev);
+static void qlcnic_tx_timeout(struct net_device *netdev);
+static void qlcnic_tx_timeout_task(struct work_struct *work);
+static void qlcnic_attach_work(struct work_struct *work);
+static void qlcnic_fwinit_work(struct work_struct *work);
+static void qlcnic_fw_poll_work(struct work_struct *work);
+static void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
+ work_func_t func, int delay);
+static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter);
+static int qlcnic_poll(struct napi_struct *napi, int budget);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void qlcnic_poll_controller(struct net_device *netdev);
+#endif
+
+static void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter);
+static void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter);
+static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter);
+static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
+
+static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter);
+static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
+
+static irqreturn_t qlcnic_tmp_intr(int irq, void *data);
+static irqreturn_t qlcnic_intr(int irq, void *data);
+static irqreturn_t qlcnic_msi_intr(int irq, void *data);
+static irqreturn_t qlcnic_msix_intr(int irq, void *data);
+
+static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
+static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
+
+/* PCI Device ID Table */
+#define ENTRY(device) \
+ {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
+ .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
+
+#define PCI_DEVICE_ID_QLOGIC_QLE824X 0x8020
+
+static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = {
+ ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X),
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, qlcnic_pci_tbl);
+
+
+void
+qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring)
+{
+ writel(tx_ring->producer, tx_ring->crb_cmd_producer);
+
+ if (qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH) {
+ netif_stop_queue(adapter->netdev);
+ smp_mb();
+ adapter->stats.xmit_off++;
+ }
+}
+
+static const u32 msi_tgt_status[8] = {
+ ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1,
+ ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3,
+ ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5,
+ ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
+};
+
+static const
+struct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG;
+
+static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)
+{
+ writel(0, sds_ring->crb_intr_mask);
+}
+
+static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
+{
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+ writel(0x1, sds_ring->crb_intr_mask);
+
+ if (!QLCNIC_IS_MSI_FAMILY(adapter))
+ writel(0xfbff, adapter->tgt_mask_reg);
+}
+
+static int
+qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count)
+{
+ int size = sizeof(struct qlcnic_host_sds_ring) * count;
+
+ recv_ctx->sds_rings = kzalloc(size, GFP_KERNEL);
+
+ return (recv_ctx->sds_rings == NULL);
+}
+
+static void
+qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
+{
+ if (recv_ctx->sds_rings != NULL)
+ kfree(recv_ctx->sds_rings);
+
+ recv_ctx->sds_rings = NULL;
+}
+
+static int
+qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+ int ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+ if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
+ return -ENOMEM;
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ netif_napi_add(netdev, &sds_ring->napi,
+ qlcnic_poll, QLCNIC_NETDEV_WEIGHT);
+ }
+
+ return 0;
+}
+
+static void
+qlcnic_napi_del(struct qlcnic_adapter *adapter)
+{
+ int ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ netif_napi_del(&sds_ring->napi);
+ }
+
+ qlcnic_free_sds_rings(&adapter->recv_ctx);
+}
+
+static void
+qlcnic_napi_enable(struct qlcnic_adapter *adapter)
+{
+ int ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ napi_enable(&sds_ring->napi);
+ qlcnic_enable_int(sds_ring);
+ }
+}
+
+static void
+qlcnic_napi_disable(struct qlcnic_adapter *adapter)
+{
+ int ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ qlcnic_disable_int(sds_ring);
+ napi_synchronize(&sds_ring->napi);
+ napi_disable(&sds_ring->napi);
+ }
+}
+
+static void qlcnic_clear_stats(struct qlcnic_adapter *adapter)
+{
+ memset(&adapter->stats, 0, sizeof(adapter->stats));
+ return;
+}
+
+static int qlcnic_set_dma_mask(struct qlcnic_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ u64 mask, cmask;
+
+ adapter->pci_using_dac = 0;
+
+ mask = DMA_BIT_MASK(39);
+ cmask = mask;
+
+ if (pci_set_dma_mask(pdev, mask) == 0 &&
+ pci_set_consistent_dma_mask(pdev, cmask) == 0) {
+ adapter->pci_using_dac = 1;
+ return 0;
+ }
+
+ return -EIO;
+}
+
+/* Update addressable range if firmware supports it */
+static int
+qlcnic_update_dma_mask(struct qlcnic_adapter *adapter)
+{
+ int change, shift, err;
+ u64 mask, old_mask, old_cmask;
+ struct pci_dev *pdev = adapter->pdev;
+
+ change = 0;
+
+ shift = QLCRD32(adapter, CRB_DMA_SHIFT);
+ if (shift > 32)
+ return 0;
+
+ if (shift > 9)
+ change = 1;
+
+ if (change) {
+ old_mask = pdev->dma_mask;
+ old_cmask = pdev->dev.coherent_dma_mask;
+
+ mask = DMA_BIT_MASK(32+shift);
+
+ err = pci_set_dma_mask(pdev, mask);
+ if (err)
+ goto err_out;
+
+ err = pci_set_consistent_dma_mask(pdev, mask);
+ if (err)
+ goto err_out;
+ dev_info(&pdev->dev, "using %d-bit dma mask\n", 32+shift);
+ }
+
+ return 0;
+
+err_out:
+ pci_set_dma_mask(pdev, old_mask);
+ pci_set_consistent_dma_mask(pdev, old_cmask);
+ return err;
+}
+
+static void qlcnic_set_port_mode(struct qlcnic_adapter *adapter)
+{
+ u32 val, data;
+
+ val = adapter->ahw.board_type;
+ if ((val == QLCNIC_BRDTYPE_P3_HMEZ) ||
+ (val == QLCNIC_BRDTYPE_P3_XG_LOM)) {
+ if (port_mode == QLCNIC_PORT_MODE_802_3_AP) {
+ data = QLCNIC_PORT_MODE_802_3_AP;
+ QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
+ } else if (port_mode == QLCNIC_PORT_MODE_XG) {
+ data = QLCNIC_PORT_MODE_XG;
+ QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
+ } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_1G) {
+ data = QLCNIC_PORT_MODE_AUTO_NEG_1G;
+ QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
+ } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_XG) {
+ data = QLCNIC_PORT_MODE_AUTO_NEG_XG;
+ QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
+ } else {
+ data = QLCNIC_PORT_MODE_AUTO_NEG;
+ QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
+ }
+
+ if ((wol_port_mode != QLCNIC_PORT_MODE_802_3_AP) &&
+ (wol_port_mode != QLCNIC_PORT_MODE_XG) &&
+ (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_1G) &&
+ (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_XG)) {
+ wol_port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
+ }
+ QLCWR32(adapter, QLCNIC_WOL_PORT_MODE, wol_port_mode);
+ }
+}
+
+static void qlcnic_set_msix_bit(struct pci_dev *pdev, int enable)
+{
+ u32 control;
+ int pos;
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+ if (pos) {
+ pci_read_config_dword(pdev, pos, &control);
+ if (enable)
+ control |= PCI_MSIX_FLAGS_ENABLE;
+ else
+ control = 0;
+ pci_write_config_dword(pdev, pos, control);
+ }
+}
+
+static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ adapter->msix_entries[i].entry = i;
+}
+
+static int
+qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
+{
+ int i;
+ unsigned char *p;
+ u64 mac_addr;
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+
+ if (qlcnic_get_mac_addr(adapter, &mac_addr) != 0)
+ return -EIO;
+
+ p = (unsigned char *)&mac_addr;
+ for (i = 0; i < 6; i++)
+ netdev->dev_addr[i] = *(p + 5 - i);
+
+ memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
+ memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
+
+ /* set station address */
+
+ if (!is_valid_ether_addr(netdev->perm_addr))
+ dev_warn(&pdev->dev, "Bad MAC address %pM.\n",
+ netdev->dev_addr);
+
+ return 0;
+}
+
+static int qlcnic_set_mac(struct net_device *netdev, void *p)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ if (netif_running(netdev)) {
+ netif_device_detach(netdev);
+ qlcnic_napi_disable(adapter);
+ }
+
+ memcpy(adapter->mac_addr, addr->sa_data, netdev->addr_len);
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ qlcnic_set_multi(adapter->netdev);
+
+ if (netif_running(netdev)) {
+ netif_device_attach(netdev);
+ qlcnic_napi_enable(adapter);
+ }
+ return 0;
+}
+
+static const struct net_device_ops qlcnic_netdev_ops = {
+ .ndo_open = qlcnic_open,
+ .ndo_stop = qlcnic_close,
+ .ndo_start_xmit = qlcnic_xmit_frame,
+ .ndo_get_stats = qlcnic_get_stats,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_multicast_list = qlcnic_set_multi,
+ .ndo_set_mac_address = qlcnic_set_mac,
+ .ndo_change_mtu = qlcnic_change_mtu,
+ .ndo_tx_timeout = qlcnic_tx_timeout,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = qlcnic_poll_controller,
+#endif
+};
+
+static void
+qlcnic_setup_intr(struct qlcnic_adapter *adapter)
+{
+ const struct qlcnic_legacy_intr_set *legacy_intrp;
+ struct pci_dev *pdev = adapter->pdev;
+ int err, num_msix;
+
+ if (adapter->rss_supported) {
+ num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ?
+ MSIX_ENTRIES_PER_ADAPTER : 2;
+ } else
+ num_msix = 1;
+
+ adapter->max_sds_rings = 1;
+
+ adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
+
+ legacy_intrp = &legacy_intr[adapter->ahw.pci_func];
+
+ adapter->int_vec_bit = legacy_intrp->int_vec_bit;
+ adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
+ legacy_intrp->tgt_status_reg);
+ adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter,
+ legacy_intrp->tgt_mask_reg);
+ adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR);
+
+ adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter,
+ ISR_INT_STATE_REG);
+
+ qlcnic_set_msix_bit(pdev, 0);
+
+ if (adapter->msix_supported) {
+
+ qlcnic_init_msix_entries(adapter, num_msix);
+ err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
+ if (err == 0) {
+ adapter->flags |= QLCNIC_MSIX_ENABLED;
+ qlcnic_set_msix_bit(pdev, 1);
+
+ if (adapter->rss_supported)
+ adapter->max_sds_rings = num_msix;
+
+ dev_info(&pdev->dev, "using msi-x interrupts\n");
+ return;
+ }
+
+ if (err > 0)
+ pci_disable_msix(pdev);
+
+ /* fall through for msi */
+ }
+
+ if (use_msi && !pci_enable_msi(pdev)) {
+ adapter->flags |= QLCNIC_MSI_ENABLED;
+ adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
+ msi_tgt_status[adapter->ahw.pci_func]);
+ dev_info(&pdev->dev, "using msi interrupts\n");
+ adapter->msix_entries[0].vector = pdev->irq;
+ return;
+ }
+
+ dev_info(&pdev->dev, "using legacy interrupts\n");
+ adapter->msix_entries[0].vector = pdev->irq;
+}
+
+static void
+qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
+{
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ pci_disable_msix(adapter->pdev);
+ if (adapter->flags & QLCNIC_MSI_ENABLED)
+ pci_disable_msi(adapter->pdev);
+}
+
+static void
+qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
+{
+ if (adapter->ahw.pci_base0 != NULL)
+ iounmap(adapter->ahw.pci_base0);
+}
+
+static int
+qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
+{
+ void __iomem *mem_ptr0 = NULL;
+ resource_size_t mem_base;
+ unsigned long mem_len, pci_len0 = 0;
+
+ struct pci_dev *pdev = adapter->pdev;
+ int pci_func = adapter->ahw.pci_func;
+
+ /*
+ * Set the CRB window to invalid. If any register in window 0 is
+ * accessed it should set the window to 0 and then reset it to 1.
+ */
+ adapter->ahw.crb_win = -1;
+ adapter->ahw.ocm_win = -1;
+
+ /* remap phys address */
+ mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
+ mem_len = pci_resource_len(pdev, 0);
+
+ if (mem_len == QLCNIC_PCI_2MB_SIZE) {
+
+ mem_ptr0 = pci_ioremap_bar(pdev, 0);
+ if (mem_ptr0 == NULL) {
+ dev_err(&pdev->dev, "failed to map PCI bar 0\n");
+ return -EIO;
+ }
+ pci_len0 = mem_len;
+ } else {
+ return -EIO;
+ }
+
+ dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
+
+ adapter->ahw.pci_base0 = mem_ptr0;
+ adapter->ahw.pci_len0 = pci_len0;
+
+ adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
+ QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func)));
+
+ return 0;
+}
+
+static void get_brd_name(struct qlcnic_adapter *adapter, char *name)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ int i, found = 0;
+
+ for (i = 0; i < NUM_SUPPORTED_BOARDS; ++i) {
+ if (qlcnic_boards[i].vendor == pdev->vendor &&
+ qlcnic_boards[i].device == pdev->device &&
+ qlcnic_boards[i].sub_vendor == pdev->subsystem_vendor &&
+ qlcnic_boards[i].sub_device == pdev->subsystem_device) {
+ strcpy(name, qlcnic_boards[i].short_name);
+ found = 1;
+ break;
+ }
+
+ }
+
+ if (!found)
+ name = "Unknown";
+}
+
+static void
+qlcnic_check_options(struct qlcnic_adapter *adapter)
+{
+ u32 fw_major, fw_minor, fw_build;
+ char brd_name[QLCNIC_MAX_BOARD_NAME_LEN];
+ char serial_num[32];
+ int i, offset, val;
+ int *ptr32;
+ struct pci_dev *pdev = adapter->pdev;
+
+ adapter->driver_mismatch = 0;
+
+ ptr32 = (int *)&serial_num;
+ offset = QLCNIC_FW_SERIAL_NUM_OFFSET;
+ for (i = 0; i < 8; i++) {
+ if (qlcnic_rom_fast_read(adapter, offset, &val) == -1) {
+ dev_err(&pdev->dev, "error reading board info\n");
+ adapter->driver_mismatch = 1;
+ return;
+ }
+ ptr32[i] = cpu_to_le32(val);
+ offset += sizeof(u32);
+ }
+
+ fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+ fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
+ fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+
+ adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
+
+ if (adapter->portnum == 0) {
+ get_brd_name(adapter, brd_name);
+
+ pr_info("%s: %s Board Chip rev 0x%x\n",
+ module_name(THIS_MODULE),
+ brd_name, adapter->ahw.revision_id);
+ }
+
+ if (adapter->fw_version < QLCNIC_VERSION_CODE(3, 4, 216)) {
+ adapter->driver_mismatch = 1;
+ dev_warn(&pdev->dev, "firmware version %d.%d.%d unsupported\n",
+ fw_major, fw_minor, fw_build);
+ return;
+ }
+
+ i = QLCRD32(adapter, QLCNIC_SRE_MISC);
+ adapter->ahw.cut_through = (i & 0x8000) ? 1 : 0;
+
+ dev_info(&pdev->dev, "firmware v%d.%d.%d [%s]\n",
+ fw_major, fw_minor, fw_build,
+ adapter->ahw.cut_through ? "cut-through" : "legacy");
+
+ if (adapter->fw_version >= QLCNIC_VERSION_CODE(4, 0, 222))
+ adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);
+
+ adapter->flags &= ~QLCNIC_LRO_ENABLED;
+
+ if (adapter->ahw.port_type == QLCNIC_XGBE) {
+ adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
+ adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ } else if (adapter->ahw.port_type == QLCNIC_GBE) {
+ adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
+ adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+ }
+
+ adapter->msix_supported = !!use_msi_x;
+ adapter->rss_supported = !!use_msi_x;
+
+ adapter->num_txd = MAX_CMD_DESCRIPTORS;
+
+ adapter->num_lro_rxd = 0;
+ adapter->max_rds_rings = 2;
+}
+
+static int
+qlcnic_start_firmware(struct qlcnic_adapter *adapter)
+{
+ int val, err, first_boot;
+
+ err = qlcnic_set_dma_mask(adapter);
+ if (err)
+ return err;
+
+ if (!qlcnic_can_start_firmware(adapter))
+ goto wait_init;
+
+ first_boot = QLCRD32(adapter, QLCNIC_CAM_RAM(0x1fc));
+ if (first_boot == 0x55555555)
+ /* This is the first boot after power up */
+ QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC);
+
+ qlcnic_request_firmware(adapter);
+
+ err = qlcnic_need_fw_reset(adapter);
+ if (err < 0)
+ goto err_out;
+ if (err == 0)
+ goto wait_init;
+
+ if (first_boot != 0x55555555) {
+ QLCWR32(adapter, CRB_CMDPEG_STATE, 0);
+ qlcnic_pinit_from_rom(adapter);
+ msleep(1);
+ }
+
+ QLCWR32(adapter, CRB_DMA_SHIFT, 0x55555555);
+ QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
+ QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
+
+ qlcnic_set_port_mode(adapter);
+
+ err = qlcnic_load_firmware(adapter);
+ if (err)
+ goto err_out;
+
+ qlcnic_release_firmware(adapter);
+
+ val = (_QLCNIC_LINUX_MAJOR << 16)
+ | ((_QLCNIC_LINUX_MINOR << 8))
+ | (_QLCNIC_LINUX_SUBVERSION);
+ QLCWR32(adapter, CRB_DRIVER_VERSION, val);
+
+wait_init:
+ /* Handshake with the card before we register the devices. */
+ err = qlcnic_phantom_init(adapter);
+ if (err)
+ goto err_out;
+
+ QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
+
+ qlcnic_update_dma_mask(adapter);
+
+ qlcnic_check_options(adapter);
+
+ adapter->need_fw_reset = 0;
+
+ /* fall through and release firmware */
+
+err_out:
+ qlcnic_release_firmware(adapter);
+ return err;
+}
+
+static int
+qlcnic_request_irq(struct qlcnic_adapter *adapter)
+{
+ irq_handler_t handler;
+ struct qlcnic_host_sds_ring *sds_ring;
+ int err, ring;
+
+ unsigned long flags = 0;
+ struct net_device *netdev = adapter->netdev;
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+ if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
+ handler = qlcnic_tmp_intr;
+ if (!QLCNIC_IS_MSI_FAMILY(adapter))
+ flags |= IRQF_SHARED;
+
+ } else {
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ handler = qlcnic_msix_intr;
+ else if (adapter->flags & QLCNIC_MSI_ENABLED)
+ handler = qlcnic_msi_intr;
+ else {
+ flags |= IRQF_SHARED;
+ handler = qlcnic_intr;
+ }
+ }
+ adapter->irq = netdev->irq;
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ sprintf(sds_ring->name, "%s[%d]", netdev->name, ring);
+ err = request_irq(sds_ring->irq, handler,
+ flags, sds_ring->name, sds_ring);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static void
+qlcnic_free_irq(struct qlcnic_adapter *adapter)
+{
+ int ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+
+ struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ free_irq(sds_ring->irq, sds_ring);
+ }
+}
+
+static void
+qlcnic_init_coalesce_defaults(struct qlcnic_adapter *adapter)
+{
+ adapter->coal.flags = QLCNIC_INTR_DEFAULT;
+ adapter->coal.normal.data.rx_time_us =
+ QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
+ adapter->coal.normal.data.rx_packets =
+ QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
+ adapter->coal.normal.data.tx_time_us =
+ QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US;
+ adapter->coal.normal.data.tx_packets =
+ QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS;
+}
+
+static int
+__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ return -EIO;
+
+ qlcnic_set_multi(netdev);
+ qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu);
+
+ adapter->ahw.linkup = 0;
+
+ if (adapter->max_sds_rings > 1)
+ qlcnic_config_rss(adapter, 1);
+
+ qlcnic_config_intr_coalesce(adapter);
+
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
+ qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
+
+ qlcnic_napi_enable(adapter);
+
+ qlcnic_linkevent_request(adapter, 1);
+
+ set_bit(__QLCNIC_DEV_UP, &adapter->state);
+ return 0;
+}
+
+/* Usage: During resume and firmware recovery module.*/
+
+static int
+qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+ int err = 0;
+
+ rtnl_lock();
+ if (netif_running(netdev))
+ err = __qlcnic_up(adapter, netdev);
+ rtnl_unlock();
+
+ return err;
+}
+
+static void
+__qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ return;
+
+ if (!test_and_clear_bit(__QLCNIC_DEV_UP, &adapter->state))
+ return;
+
+ smp_mb();
+ spin_lock(&adapter->tx_clean_lock);
+ netif_carrier_off(netdev);
+ netif_tx_disable(netdev);
+
+ qlcnic_free_mac_list(adapter);
+
+ qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE);
+
+ qlcnic_napi_disable(adapter);
+
+ qlcnic_release_tx_buffers(adapter);
+ spin_unlock(&adapter->tx_clean_lock);
+}
+
+/* Usage: During suspend and firmware recovery module */
+
+static void
+qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+ rtnl_lock();
+ if (netif_running(netdev))
+ __qlcnic_down(adapter, netdev);
+ rtnl_unlock();
+
+}
+
+static int
+qlcnic_attach(struct qlcnic_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ int err, ring;
+ struct qlcnic_host_rds_ring *rds_ring;
+
+ if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC)
+ return 0;
+
+ err = qlcnic_init_firmware(adapter);
+ if (err)
+ return err;
+
+ err = qlcnic_napi_add(adapter, netdev);
+ if (err)
+ return err;
+
+ err = qlcnic_alloc_sw_resources(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Error in setting sw resources\n");
+ return err;
+ }
+
+ err = qlcnic_alloc_hw_resources(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Error in setting hw resources\n");
+ goto err_out_free_sw;
+ }
+
+
+ for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+ rds_ring = &adapter->recv_ctx.rds_rings[ring];
+ qlcnic_post_rx_buffers(adapter, ring, rds_ring);
+ }
+
+ err = qlcnic_request_irq(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "failed to setup interrupt\n");
+ goto err_out_free_rxbuf;
+ }
+
+ qlcnic_init_coalesce_defaults(adapter);
+
+ qlcnic_create_sysfs_entries(adapter);
+
+ adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC;
+ return 0;
+
+err_out_free_rxbuf:
+ qlcnic_release_rx_buffers(adapter);
+ qlcnic_free_hw_resources(adapter);
+err_out_free_sw:
+ qlcnic_free_sw_resources(adapter);
+ return err;
+}
+
+static void
+qlcnic_detach(struct qlcnic_adapter *adapter)
+{
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ return;
+
+ qlcnic_remove_sysfs_entries(adapter);
+
+ qlcnic_free_hw_resources(adapter);
+ qlcnic_release_rx_buffers(adapter);
+ qlcnic_free_irq(adapter);
+ qlcnic_napi_del(adapter);
+ qlcnic_free_sw_resources(adapter);
+
+ adapter->is_up = 0;
+}
+
+void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_host_sds_ring *sds_ring;
+ int ring;
+
+ if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &adapter->recv_ctx.sds_rings[ring];
+ qlcnic_disable_int(sds_ring);
+ }
+ }
+
+ qlcnic_detach(adapter);
+
+ adapter->diag_test = 0;
+ adapter->max_sds_rings = max_sds_rings;
+
+ if (qlcnic_attach(adapter))
+ return;
+
+ if (netif_running(netdev))
+ __qlcnic_up(adapter, netdev);
+
+ netif_device_attach(netdev);
+}
+
+int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_host_sds_ring *sds_ring;
+ int ring;
+ int ret;
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev))
+ __qlcnic_down(adapter, netdev);
+
+ qlcnic_detach(adapter);
+
+ adapter->max_sds_rings = 1;
+ adapter->diag_test = test;
+
+ ret = qlcnic_attach(adapter);
+ if (ret)
+ return ret;
+
+ if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &adapter->recv_ctx.sds_rings[ring];
+ qlcnic_enable_int(sds_ring);
+ }
+ }
+
+ return 0;
+}
+
+int
+qlcnic_reset_context(struct qlcnic_adapter *adapter)
+{
+ int err = 0;
+ struct net_device *netdev = adapter->netdev;
+
+ if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EBUSY;
+
+ if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) {
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev))
+ __qlcnic_down(adapter, netdev);
+
+ qlcnic_detach(adapter);
+
+ if (netif_running(netdev)) {
+ err = qlcnic_attach(adapter);
+ if (!err)
+ err = __qlcnic_up(adapter, netdev);
+
+ if (err)
+ goto done;
+ }
+
+ netif_device_attach(netdev);
+ }
+
+done:
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return err;
+}
+
+static int
+qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
+ struct net_device *netdev)
+{
+ int err;
+ struct pci_dev *pdev = adapter->pdev;
+
+ adapter->rx_csum = 1;
+ adapter->mc_enabled = 0;
+ adapter->max_mc_count = 38;
+
+ netdev->netdev_ops = &qlcnic_netdev_ops;
+ netdev->watchdog_timeo = 2*HZ;
+
+ qlcnic_change_mtu(netdev, netdev->mtu);
+
+ SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
+
+ netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+ netdev->features |= (NETIF_F_GRO);
+ netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+
+ netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+ netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+
+ if (adapter->pci_using_dac) {
+ netdev->features |= NETIF_F_HIGHDMA;
+ netdev->vlan_features |= NETIF_F_HIGHDMA;
+ }
+
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX)
+ netdev->features |= (NETIF_F_HW_VLAN_TX);
+
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
+ netdev->features |= NETIF_F_LRO;
+
+ netdev->irq = adapter->msix_entries[0].vector;
+
+ INIT_WORK(&adapter->tx_timeout_task, qlcnic_tx_timeout_task);
+
+ if (qlcnic_read_mac_addr(adapter))
+ dev_warn(&pdev->dev, "failed to read mac addr\n");
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ err = register_netdev(netdev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register net device\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int __devinit
+qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct net_device *netdev = NULL;
+ struct qlcnic_adapter *adapter = NULL;
+ int err;
+ int pci_func_id = PCI_FUNC(pdev->devfn);
+ uint8_t revision_id;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+ err = -ENODEV;
+ goto err_out_disable_pdev;
+ }
+
+ err = pci_request_regions(pdev, qlcnic_driver_name);
+ if (err)
+ goto err_out_disable_pdev;
+
+ pci_set_master(pdev);
+
+ netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
+ if (!netdev) {
+ dev_err(&pdev->dev, "failed to allocate net_device\n");
+ err = -ENOMEM;
+ goto err_out_free_res;
+ }
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ adapter = netdev_priv(netdev);
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ adapter->ahw.pci_func = pci_func_id;
+
+ revision_id = pdev->revision;
+ adapter->ahw.revision_id = revision_id;
+
+ rwlock_init(&adapter->ahw.crb_lock);
+ mutex_init(&adapter->ahw.mem_lock);
+
+ spin_lock_init(&adapter->tx_clean_lock);
+ INIT_LIST_HEAD(&adapter->mac_list);
+
+ err = qlcnic_setup_pci_map(adapter);
+ if (err)
+ goto err_out_free_netdev;
+
+ /* This will be reset for mezz cards */
+ adapter->portnum = pci_func_id;
+
+ err = qlcnic_get_board_info(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Error getting board config info.\n");
+ goto err_out_iounmap;
+ }
+
+
+ err = qlcnic_start_firmware(adapter);
+ if (err)
+ goto err_out_decr_ref;
+
+ /*
+ * See if the firmware gave us a virtual-physical port mapping.
+ */
+ adapter->physical_port = adapter->portnum;
+
+ qlcnic_clear_stats(adapter);
+
+ qlcnic_setup_intr(adapter);
+
+ err = qlcnic_setup_netdev(adapter, netdev);
+ if (err)
+ goto err_out_disable_msi;
+
+ pci_set_drvdata(pdev, adapter);
+
+ qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
+
+ switch (adapter->ahw.port_type) {
+ case QLCNIC_GBE:
+ dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n",
+ adapter->netdev->name);
+ break;
+ case QLCNIC_XGBE:
+ dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n",
+ adapter->netdev->name);
+ break;
+ }
+
+ qlcnic_create_diag_entries(adapter);
+
+ return 0;
+
+err_out_disable_msi:
+ qlcnic_teardown_intr(adapter);
+
+err_out_decr_ref:
+ qlcnic_clr_all_drv_state(adapter);
+
+err_out_iounmap:
+ qlcnic_cleanup_pci_map(adapter);
+
+err_out_free_netdev:
+ free_netdev(netdev);
+
+err_out_free_res:
+ pci_release_regions(pdev);
+
+err_out_disable_pdev:
+ pci_set_drvdata(pdev, NULL);
+ pci_disable_device(pdev);
+ return err;
+}
+
+static void __devexit qlcnic_remove(struct pci_dev *pdev)
+{
+ struct qlcnic_adapter *adapter;
+ struct net_device *netdev;
+
+ adapter = pci_get_drvdata(pdev);
+ if (adapter == NULL)
+ return;
+
+ netdev = adapter->netdev;
+
+ qlcnic_cancel_fw_work(adapter);
+
+ unregister_netdev(netdev);
+
+ cancel_work_sync(&adapter->tx_timeout_task);
+
+ qlcnic_detach(adapter);
+
+ qlcnic_clr_all_drv_state(adapter);
+
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
+ qlcnic_teardown_intr(adapter);
+
+ qlcnic_remove_diag_entries(adapter);
+
+ qlcnic_cleanup_pci_map(adapter);
+
+ qlcnic_release_firmware(adapter);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ free_netdev(netdev);
+}
+static int __qlcnic_shutdown(struct pci_dev *pdev)
+{
+ struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
+ int retval;
+
+ netif_device_detach(netdev);
+
+ qlcnic_cancel_fw_work(adapter);
+
+ if (netif_running(netdev))
+ qlcnic_down(adapter, netdev);
+
+ cancel_work_sync(&adapter->tx_timeout_task);
+
+ qlcnic_detach(adapter);
+
+ qlcnic_clr_all_drv_state(adapter);
+
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
+ retval = pci_save_state(pdev);
+ if (retval)
+ return retval;
+
+ if (qlcnic_wol_supported(adapter)) {
+ pci_enable_wake(pdev, PCI_D3cold, 1);
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ }
+
+ return 0;
+}
+
+static void qlcnic_shutdown(struct pci_dev *pdev)
+{
+ if (__qlcnic_shutdown(pdev))
+ return;
+
+ pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM
+static int
+qlcnic_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ int retval;
+
+ retval = __qlcnic_shutdown(pdev);
+ if (retval)
+ return retval;
+
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
+}
+
+static int
+qlcnic_resume(struct pci_dev *pdev)
+{
+ struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_set_master(pdev);
+ pci_restore_state(pdev);
+
+ adapter->ahw.crb_win = -1;
+ adapter->ahw.ocm_win = -1;
+
+ err = qlcnic_start_firmware(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "failed to start firmware\n");
+ return err;
+ }
+
+ if (netif_running(netdev)) {
+ err = qlcnic_attach(adapter);
+ if (err)
+ goto err_out;
+
+ err = qlcnic_up(adapter, netdev);
+ if (err)
+ goto err_out_detach;
+
+
+ qlcnic_config_indev_addr(netdev, NETDEV_UP);
+ }
+
+ netif_device_attach(netdev);
+ qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
+ return 0;
+
+err_out_detach:
+ qlcnic_detach(adapter);
+err_out:
+ qlcnic_clr_all_drv_state(adapter);
+ return err;
+}
+#endif
+
+static int qlcnic_open(struct net_device *netdev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ int err;
+
+ if (adapter->driver_mismatch)
+ return -EIO;
+
+ err = qlcnic_attach(adapter);
+ if (err)
+ return err;
+
+ err = __qlcnic_up(adapter, netdev);
+ if (err)
+ goto err_out;
+
+ netif_start_queue(netdev);
+
+ return 0;
+
+err_out:
+ qlcnic_detach(adapter);
+ return err;
+}
+
+/*
+ * qlcnic_close - Disables a network interface entry point
+ */
+static int qlcnic_close(struct net_device *netdev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+ __qlcnic_down(adapter, netdev);
+ return 0;
+}
+
+static void
+qlcnic_tso_check(struct net_device *netdev,
+ struct qlcnic_host_tx_ring *tx_ring,
+ struct cmd_desc_type0 *first_desc,
+ struct sk_buff *skb)
+{
+ u8 opcode = TX_ETHER_PKT;
+ __be16 protocol = skb->protocol;
+ u16 flags = 0, vid = 0;
+ u32 producer;
+ int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
+ struct cmd_desc_type0 *hwdesc;
+ struct vlan_ethhdr *vh;
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+ if (protocol == cpu_to_be16(ETH_P_8021Q)) {
+
+ vh = (struct vlan_ethhdr *)skb->data;
+ protocol = vh->h_vlan_encapsulated_proto;
+ flags = FLAGS_VLAN_TAGGED;
+
+ } else if (vlan_tx_tag_present(skb)) {
+
+ flags = FLAGS_VLAN_OOB;
+ vid = vlan_tx_tag_get(skb);
+ qlcnic_set_tx_vlan_tci(first_desc, vid);
+ vlan_oob = 1;
+ }
+
+ if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
+ skb_shinfo(skb)->gso_size > 0) {
+
+ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+
+ first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+ first_desc->total_hdr_length = hdr_len;
+ if (vlan_oob) {
+ first_desc->total_hdr_length += VLAN_HLEN;
+ first_desc->tcp_hdr_offset = VLAN_HLEN;
+ first_desc->ip_hdr_offset = VLAN_HLEN;
+ /* Only in case of TSO on vlan device */
+ flags |= FLAGS_VLAN_TAGGED;
+ }
+
+ opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ?
+ TX_TCP_LSO6 : TX_TCP_LSO;
+ tso = 1;
+
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ u8 l4proto;
+
+ if (protocol == cpu_to_be16(ETH_P_IP)) {
+ l4proto = ip_hdr(skb)->protocol;
+
+ if (l4proto == IPPROTO_TCP)
+ opcode = TX_TCP_PKT;
+ else if (l4proto == IPPROTO_UDP)
+ opcode = TX_UDP_PKT;
+ } else if (protocol == cpu_to_be16(ETH_P_IPV6)) {
+ l4proto = ipv6_hdr(skb)->nexthdr;
+
+ if (l4proto == IPPROTO_TCP)
+ opcode = TX_TCPV6_PKT;
+ else if (l4proto == IPPROTO_UDP)
+ opcode = TX_UDPV6_PKT;
+ }
+ }
+
+ first_desc->tcp_hdr_offset += skb_transport_offset(skb);
+ first_desc->ip_hdr_offset += skb_network_offset(skb);
+ qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
+
+ if (!tso)
+ return;
+
+ /* For LSO, we need to copy the MAC/IP/TCP headers into
+ * the descriptor ring
+ */
+ producer = tx_ring->producer;
+ copied = 0;
+ offset = 2;
+
+ if (vlan_oob) {
+ /* Create a TSO vlan header template for firmware */
+
+ hwdesc = &tx_ring->desc_head[producer];
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+ copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
+ hdr_len + VLAN_HLEN);
+
+ vh = (struct vlan_ethhdr *)((char *)hwdesc + 2);
+ skb_copy_from_linear_data(skb, vh, 12);
+ vh->h_vlan_proto = htons(ETH_P_8021Q);
+ vh->h_vlan_TCI = htons(vid);
+ skb_copy_from_linear_data_offset(skb, 12,
+ (char *)vh + 16, copy_len - 16);
+
+ copied = copy_len - VLAN_HLEN;
+ offset = 0;
+
+ producer = get_next_index(producer, tx_ring->num_desc);
+ }
+
+ while (copied < hdr_len) {
+
+ copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
+ (hdr_len - copied));
+
+ hwdesc = &tx_ring->desc_head[producer];
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+ skb_copy_from_linear_data_offset(skb, copied,
+ (char *)hwdesc + offset, copy_len);
+
+ copied += copy_len;
+ offset = 0;
+
+ producer = get_next_index(producer, tx_ring->num_desc);
+ }
+
+ tx_ring->producer = producer;
+ barrier();
+ adapter->stats.lso_frames++;
+}
+
+static int
+qlcnic_map_tx_skb(struct pci_dev *pdev,
+ struct sk_buff *skb, struct qlcnic_cmd_buffer *pbuf)
+{
+ struct qlcnic_skb_frag *nf;
+ struct skb_frag_struct *frag;
+ int i, nr_frags;
+ dma_addr_t map;
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ nf = &pbuf->frag_array[0];
+
+ map = pci_map_single(pdev, skb->data,
+ skb_headlen(skb), PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(pdev, map))
+ goto out_err;
+
+ nf->dma = map;
+ nf->length = skb_headlen(skb);
+
+ for (i = 0; i < nr_frags; i++) {
+ frag = &skb_shinfo(skb)->frags[i];
+ nf = &pbuf->frag_array[i+1];
+
+ map = pci_map_page(pdev, frag->page, frag->page_offset,
+ frag->size, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(pdev, map))
+ goto unwind;
+
+ nf->dma = map;
+ nf->length = frag->size;
+ }
+
+ return 0;
+
+unwind:
+ while (--i >= 0) {
+ nf = &pbuf->frag_array[i+1];
+ pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
+ }
+
+ nf = &pbuf->frag_array[0];
+ pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
+
+out_err:
+ return -ENOMEM;
+}
+
+static inline void
+qlcnic_clear_cmddesc(u64 *desc)
+{
+ desc[0] = 0ULL;
+ desc[2] = 0ULL;
+}
+
+netdev_tx_t
+qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+ struct qlcnic_cmd_buffer *pbuf;
+ struct qlcnic_skb_frag *buffrag;
+ struct cmd_desc_type0 *hwdesc, *first_desc;
+ struct pci_dev *pdev;
+ int i, k;
+
+ u32 producer;
+ int frag_count, no_of_desc;
+ u32 num_txd = tx_ring->num_desc;
+
+ frag_count = skb_shinfo(skb)->nr_frags + 1;
+
+ /* 4 fragments per cmd des */
+ no_of_desc = (frag_count + 3) >> 2;
+
+ if (unlikely(no_of_desc + 2 > qlcnic_tx_avail(tx_ring))) {
+ netif_stop_queue(netdev);
+ adapter->stats.xmit_off++;
+ return NETDEV_TX_BUSY;
+ }
+
+ producer = tx_ring->producer;
+ pbuf = &tx_ring->cmd_buf_arr[producer];
+
+ pdev = adapter->pdev;
+
+ if (qlcnic_map_tx_skb(pdev, skb, pbuf))
+ goto drop_packet;
+
+ pbuf->skb = skb;
+ pbuf->frag_count = frag_count;
+
+ first_desc = hwdesc = &tx_ring->desc_head[producer];
+ qlcnic_clear_cmddesc((u64 *)hwdesc);
+
+ qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len);
+ qlcnic_set_tx_port(first_desc, adapter->portnum);
+
+ for (i = 0; i < frag_count; i++) {
+
+ k = i % 4;
+
+ if ((k == 0) && (i > 0)) {
+ /* move to next desc.*/
+ producer = get_next_index(producer, num_txd);
+ hwdesc = &tx_ring->desc_head[producer];
+ qlcnic_clear_cmddesc((u64 *)hwdesc);
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+ }
+
+ buffrag = &pbuf->frag_array[i];
+
+ hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length);
+ switch (k) {
+ case 0:
+ hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
+ break;
+ case 1:
+ hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma);
+ break;
+ case 2:
+ hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma);
+ break;
+ case 3:
+ hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma);
+ break;
+ }
+ }
+
+ tx_ring->producer = get_next_index(producer, num_txd);
+
+ qlcnic_tso_check(netdev, tx_ring, first_desc, skb);
+
+ qlcnic_update_cmd_producer(adapter, tx_ring);
+
+ adapter->stats.txbytes += skb->len;
+ adapter->stats.xmitcalled++;
+
+ return NETDEV_TX_OK;
+
+drop_packet:
+ adapter->stats.txdropped++;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+}
+
+static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ u32 temp, temp_state, temp_val;
+ int rv = 0;
+
+ temp = QLCRD32(adapter, CRB_TEMP_STATE);
+
+ temp_state = qlcnic_get_temp_state(temp);
+ temp_val = qlcnic_get_temp_val(temp);
+
+ if (temp_state == QLCNIC_TEMP_PANIC) {
+ dev_err(&netdev->dev,
+ "Device temperature %d degrees C exceeds"
+ " maximum allowed. Hardware has been shut down.\n",
+ temp_val);
+ rv = 1;
+ } else if (temp_state == QLCNIC_TEMP_WARN) {
+ if (adapter->temp == QLCNIC_TEMP_NORMAL) {
+ dev_err(&netdev->dev,
+ "Device temperature %d degrees C "
+ "exceeds operating range."
+ " Immediate action needed.\n",
+ temp_val);
+ }
+ } else {
+ if (adapter->temp == QLCNIC_TEMP_WARN) {
+ dev_info(&netdev->dev,
+ "Device temperature is now %d degrees C"
+ " in normal range.\n", temp_val);
+ }
+ }
+ adapter->temp = temp_state;
+ return rv;
+}
+
+void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ if (adapter->ahw.linkup && !linkup) {
+ dev_info(&netdev->dev, "NIC Link is down\n");
+ adapter->ahw.linkup = 0;
+ if (netif_running(netdev)) {
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+ } else if (!adapter->ahw.linkup && linkup) {
+ dev_info(&netdev->dev, "NIC Link is up\n");
+ adapter->ahw.linkup = 1;
+ if (netif_running(netdev)) {
+ netif_carrier_on(netdev);
+ netif_wake_queue(netdev);
+ }
+ }
+}
+
+static void qlcnic_tx_timeout(struct net_device *netdev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state))
+ return;
+
+ dev_err(&netdev->dev, "transmit timeout, resetting.\n");
+ schedule_work(&adapter->tx_timeout_task);
+}
+
+static void qlcnic_tx_timeout_task(struct work_struct *work)
+{
+ struct qlcnic_adapter *adapter =
+ container_of(work, struct qlcnic_adapter, tx_timeout_task);
+
+ if (!netif_running(adapter->netdev))
+ return;
+
+ if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ return;
+
+ if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS)
+ goto request_reset;
+
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ if (!qlcnic_reset_context(adapter)) {
+ adapter->netdev->trans_start = jiffies;
+ return;
+
+ /* context reset failed, fall through for fw reset */
+ }
+
+request_reset:
+ adapter->need_fw_reset = 1;
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+}
+
+static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct net_device_stats *stats = &netdev->stats;
+
+ memset(stats, 0, sizeof(*stats));
+
+ stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts;
+ stats->tx_packets = adapter->stats.xmitfinished;
+ stats->rx_bytes = adapter->stats.rxbytes;
+ stats->tx_bytes = adapter->stats.txbytes;
+ stats->rx_dropped = adapter->stats.rxdropped;
+ stats->tx_dropped = adapter->stats.txdropped;
+
+ return stats;
+}
+
+static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
+{
+ u32 status;
+
+ status = readl(adapter->isr_int_vec);
+
+ if (!(status & adapter->int_vec_bit))
+ return IRQ_NONE;
+
+ /* check interrupt state machine, to be sure */
+ status = readl(adapter->crb_int_state_reg);
+ if (!ISR_LEGACY_INT_TRIGGERED(status))
+ return IRQ_NONE;
+
+ writel(0xffffffff, adapter->tgt_status_reg);
+ /* read twice to ensure write is flushed */
+ readl(adapter->isr_int_vec);
+ readl(adapter->isr_int_vec);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qlcnic_tmp_intr(int irq, void *data)
+{
+ struct qlcnic_host_sds_ring *sds_ring = data;
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ goto done;
+ else if (adapter->flags & QLCNIC_MSI_ENABLED) {
+ writel(0xffffffff, adapter->tgt_status_reg);
+ goto done;
+ }
+
+ if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
+ return IRQ_NONE;
+
+done:
+ adapter->diag_cnt++;
+ qlcnic_enable_int(sds_ring);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qlcnic_intr(int irq, void *data)
+{
+ struct qlcnic_host_sds_ring *sds_ring = data;
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+ if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
+ return IRQ_NONE;
+
+ napi_schedule(&sds_ring->napi);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qlcnic_msi_intr(int irq, void *data)
+{
+ struct qlcnic_host_sds_ring *sds_ring = data;
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+ /* clear interrupt */
+ writel(0xffffffff, adapter->tgt_status_reg);
+
+ napi_schedule(&sds_ring->napi);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qlcnic_msix_intr(int irq, void *data)
+{
+ struct qlcnic_host_sds_ring *sds_ring = data;
+
+ napi_schedule(&sds_ring->napi);
+ return IRQ_HANDLED;
+}
+
+static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
+{
+ u32 sw_consumer, hw_consumer;
+ int count = 0, i;
+ struct qlcnic_cmd_buffer *buffer;
+ struct pci_dev *pdev = adapter->pdev;
+ struct net_device *netdev = adapter->netdev;
+ struct qlcnic_skb_frag *frag;
+ int done;
+ struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+
+ if (!spin_trylock(&adapter->tx_clean_lock))
+ return 1;
+
+ sw_consumer = tx_ring->sw_consumer;
+ hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
+
+ while (sw_consumer != hw_consumer) {
+ buffer = &tx_ring->cmd_buf_arr[sw_consumer];
+ if (buffer->skb) {
+ frag = &buffer->frag_array[0];
+ pci_unmap_single(pdev, frag->dma, frag->length,
+ PCI_DMA_TODEVICE);
+ frag->dma = 0ULL;
+ for (i = 1; i < buffer->frag_count; i++) {
+ frag++;
+ pci_unmap_page(pdev, frag->dma, frag->length,
+ PCI_DMA_TODEVICE);
+ frag->dma = 0ULL;
+ }
+
+ adapter->stats.xmitfinished++;
+ dev_kfree_skb_any(buffer->skb);
+ buffer->skb = NULL;
+ }
+
+ sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
+ if (++count >= MAX_STATUS_HANDLE)
+ break;
+ }
+
+ if (count && netif_running(netdev)) {
+ tx_ring->sw_consumer = sw_consumer;
+
+ smp_mb();
+
+ if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
+ __netif_tx_lock(tx_ring->txq, smp_processor_id());
+ if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
+ netif_wake_queue(netdev);
+ adapter->tx_timeo_cnt = 0;
+ adapter->stats.xmit_on++;
+ }
+ __netif_tx_unlock(tx_ring->txq);
+ }
+ }
+ /*
+ * If everything is freed up to consumer then check if the ring is full
+ * If the ring is full then check if more needs to be freed and
+ * schedule the call back again.
+ *
+ * This happens when there are 2 CPUs. One could be freeing and the
+ * other filling it. If the ring is full when we get out of here and
+ * the card has already interrupted the host then the host can miss the
+ * interrupt.
+ *
+ * There is still a possible race condition and the host could miss an
+ * interrupt. The card has to take care of this.
+ */
+ hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
+ done = (sw_consumer == hw_consumer);
+ spin_unlock(&adapter->tx_clean_lock);
+
+ return done;
+}
+
+static int qlcnic_poll(struct napi_struct *napi, int budget)
+{
+ struct qlcnic_host_sds_ring *sds_ring =
+ container_of(napi, struct qlcnic_host_sds_ring, napi);
+
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+ int tx_complete;
+ int work_done;
+
+ tx_complete = qlcnic_process_cmd_ring(adapter);
+
+ work_done = qlcnic_process_rcv_ring(sds_ring, budget);
+
+ if ((work_done < budget) && tx_complete) {
+ napi_complete(&sds_ring->napi);
+ if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+ qlcnic_enable_int(sds_ring);
+ }
+
+ return work_done;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void qlcnic_poll_controller(struct net_device *netdev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ disable_irq(adapter->irq);
+ qlcnic_intr(adapter->irq, adapter);
+ enable_irq(adapter->irq);
+}
+#endif
+
+static void
+qlcnic_set_drv_state(struct qlcnic_adapter *adapter, int state)
+{
+ u32 val;
+
+ WARN_ON(state != QLCNIC_DEV_NEED_RESET &&
+ state != QLCNIC_DEV_NEED_QUISCENT);
+
+ if (qlcnic_api_lock(adapter))
+ return ;
+
+ val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+
+ if (state == QLCNIC_DEV_NEED_RESET)
+ val |= ((u32)0x1 << (adapter->portnum * 4));
+ else if (state == QLCNIC_DEV_NEED_QUISCENT)
+ val |= ((u32)0x1 << ((adapter->portnum * 4) + 1));
+
+ QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+
+ qlcnic_api_unlock(adapter);
+}
+
+static int
+qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
+{
+ u32 val;
+
+ if (qlcnic_api_lock(adapter))
+ return -EBUSY;
+
+ val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ val &= ~((u32)0x3 << (adapter->portnum * 4));
+ QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+
+ qlcnic_api_unlock(adapter);
+
+ return 0;
+}
+
+static void
+qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter)
+{
+ u32 val;
+
+ if (qlcnic_api_lock(adapter))
+ goto err;
+
+ val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+ val &= ~((u32)0x1 << (adapter->portnum * 4));
+ QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val);
+
+ if (!(val & 0x11111111))
+ QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
+
+ val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ val &= ~((u32)0x3 << (adapter->portnum * 4));
+ QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+
+ qlcnic_api_unlock(adapter);
+err:
+ adapter->fw_fail_cnt = 0;
+ clear_bit(__QLCNIC_START_FW, &adapter->state);
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+}
+
+static int
+qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
+{
+ int act, state;
+
+ state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ act = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+
+ if (((state & 0x11111111) == (act & 0x11111111)) ||
+ ((act & 0x11111111) == ((state >> 1) & 0x11111111)))
+ return 0;
+ else
+ return 1;
+}
+
+static int
+qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
+{
+ u32 val, prev_state;
+ int cnt = 0;
+ int portnum = adapter->portnum;
+
+ if (qlcnic_api_lock(adapter))
+ return -1;
+
+ val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+ if (!(val & ((int)0x1 << (portnum * 4)))) {
+ val |= ((u32)0x1 << (portnum * 4));
+ QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val);
+ } else if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state)) {
+ goto start_fw;
+ }
+
+ prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+
+ switch (prev_state) {
+ case QLCNIC_DEV_COLD:
+start_fw:
+ QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITALIZING);
+ qlcnic_api_unlock(adapter);
+ return 1;
+
+ case QLCNIC_DEV_READY:
+ qlcnic_api_unlock(adapter);
+ return 0;
+
+ case QLCNIC_DEV_NEED_RESET:
+ val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ val |= ((u32)0x1 << (portnum * 4));
+ QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+ break;
+
+ case QLCNIC_DEV_NEED_QUISCENT:
+ val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ val |= ((u32)0x1 << ((portnum * 4) + 1));
+ QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+ break;
+
+ case QLCNIC_DEV_FAILED:
+ qlcnic_api_unlock(adapter);
+ return -1;
+ }
+
+ qlcnic_api_unlock(adapter);
+ msleep(1000);
+ while ((QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) != QLCNIC_DEV_READY) &&
+ ++cnt < 20)
+ msleep(1000);
+
+ if (cnt >= 20)
+ return -1;
+
+ if (qlcnic_api_lock(adapter))
+ return -1;
+
+ val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ val &= ~((u32)0x3 << (portnum * 4));
+ QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+
+ qlcnic_api_unlock(adapter);
+
+ return 0;
+}
+
+static void
+qlcnic_fwinit_work(struct work_struct *work)
+{
+ struct qlcnic_adapter *adapter = container_of(work,
+ struct qlcnic_adapter, fw_work.work);
+ int dev_state;
+
+ if (++adapter->fw_wait_cnt > FW_POLL_THRESH)
+ goto err_ret;
+
+ if (test_bit(__QLCNIC_START_FW, &adapter->state)) {
+
+ if (qlcnic_check_drv_state(adapter)) {
+ qlcnic_schedule_work(adapter,
+ qlcnic_fwinit_work, FW_POLL_DELAY);
+ return;
+ }
+
+ if (!qlcnic_start_firmware(adapter)) {
+ qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
+ return;
+ }
+
+ goto err_ret;
+ }
+
+ dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ switch (dev_state) {
+ case QLCNIC_DEV_READY:
+ if (!qlcnic_start_firmware(adapter)) {
+ qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
+ return;
+ }
+ case QLCNIC_DEV_FAILED:
+ break;
+
+ default:
+ qlcnic_schedule_work(adapter,
+ qlcnic_fwinit_work, 2 * FW_POLL_DELAY);
+ return;
+ }
+
+err_ret:
+ qlcnic_clr_all_drv_state(adapter);
+}
+
+static void
+qlcnic_detach_work(struct work_struct *work)
+{
+ struct qlcnic_adapter *adapter = container_of(work,
+ struct qlcnic_adapter, fw_work.work);
+ struct net_device *netdev = adapter->netdev;
+ u32 status;
+
+ netif_device_detach(netdev);
+
+ qlcnic_down(adapter, netdev);
+
+ rtnl_lock();
+ qlcnic_detach(adapter);
+ rtnl_unlock();
+
+ status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
+
+ if (status & QLCNIC_RCODE_FATAL_ERROR)
+ goto err_ret;
+
+ if (adapter->temp == QLCNIC_TEMP_PANIC)
+ goto err_ret;
+
+ qlcnic_set_drv_state(adapter, adapter->dev_state);
+
+ adapter->fw_wait_cnt = 0;
+
+ qlcnic_schedule_work(adapter, qlcnic_fwinit_work, FW_POLL_DELAY);
+
+ return;
+
+err_ret:
+ qlcnic_clr_all_drv_state(adapter);
+
+}
+
+static void
+qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
+{
+ u32 state;
+
+ if (qlcnic_api_lock(adapter))
+ return;
+
+ state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+
+ if (state != QLCNIC_DEV_INITALIZING && state != QLCNIC_DEV_NEED_RESET) {
+ QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
+ set_bit(__QLCNIC_START_FW, &adapter->state);
+ }
+
+ qlcnic_api_unlock(adapter);
+}
+
+static void
+qlcnic_schedule_work(struct qlcnic_adapter *adapter,
+ work_func_t func, int delay)
+{
+ INIT_DELAYED_WORK(&adapter->fw_work, func);
+ schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay));
+}
+
+static void
+qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
+{
+ while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ msleep(10);
+
+ cancel_delayed_work_sync(&adapter->fw_work);
+}
+
+static void
+qlcnic_attach_work(struct work_struct *work)
+{
+ struct qlcnic_adapter *adapter = container_of(work,
+ struct qlcnic_adapter, fw_work.work);
+ struct net_device *netdev = adapter->netdev;
+ int err;
+
+ if (netif_running(netdev)) {
+ err = qlcnic_attach(adapter);
+ if (err)
+ goto done;
+
+ err = qlcnic_up(adapter, netdev);
+ if (err) {
+ qlcnic_detach(adapter);
+ goto done;
+ }
+
+ qlcnic_config_indev_addr(netdev, NETDEV_UP);
+ }
+
+ netif_device_attach(netdev);
+
+done:
+ adapter->fw_fail_cnt = 0;
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
+ if (!qlcnic_clr_drv_state(adapter))
+ qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
+ FW_POLL_DELAY);
+}
+
+static int
+qlcnic_check_health(struct qlcnic_adapter *adapter)
+{
+ u32 state = 0, heartbit;
+ struct net_device *netdev = adapter->netdev;
+
+ if (qlcnic_check_temp(adapter))
+ goto detach;
+
+ if (adapter->need_fw_reset) {
+ qlcnic_dev_request_reset(adapter);
+ goto detach;
+ }
+
+ state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ if (state == QLCNIC_DEV_NEED_RESET || state == QLCNIC_DEV_NEED_QUISCENT)
+ adapter->need_fw_reset = 1;
+
+ heartbit = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+ if (heartbit != adapter->heartbit) {
+ adapter->heartbit = heartbit;
+ adapter->fw_fail_cnt = 0;
+ if (adapter->need_fw_reset)
+ goto detach;
+ return 0;
+ }
+
+ if (++adapter->fw_fail_cnt < FW_FAIL_THRESH)
+ return 0;
+
+ qlcnic_dev_request_reset(adapter);
+
+ clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
+
+ dev_info(&netdev->dev, "firmware hang detected\n");
+
+detach:
+ adapter->dev_state = (state == QLCNIC_DEV_NEED_QUISCENT) ? state :
+ QLCNIC_DEV_NEED_RESET;
+
+ if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) &&
+ !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ qlcnic_schedule_work(adapter, qlcnic_detach_work, 0);
+
+ return 1;
+}
+
+static void
+qlcnic_fw_poll_work(struct work_struct *work)
+{
+ struct qlcnic_adapter *adapter = container_of(work,
+ struct qlcnic_adapter, fw_work.work);
+
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state))
+ goto reschedule;
+
+
+ if (qlcnic_check_health(adapter))
+ return;
+
+reschedule:
+ qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
+}
+
+static ssize_t
+qlcnic_store_bridged_mode(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ unsigned long new;
+ int ret = -EINVAL;
+
+ if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG))
+ goto err_out;
+
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ goto err_out;
+
+ if (strict_strtoul(buf, 2, &new))
+ goto err_out;
+
+ if (!qlcnic_config_bridged_mode(adapter, !!new))
+ ret = len;
+
+err_out:
+ return ret;
+}
+
+static ssize_t
+qlcnic_show_bridged_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ int bridged_mode = 0;
+
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
+ bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED);
+
+ return sprintf(buf, "%d\n", bridged_mode);
+}
+
+static struct device_attribute dev_attr_bridged_mode = {
+ .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
+ .show = qlcnic_show_bridged_mode,
+ .store = qlcnic_store_bridged_mode,
+};
+
+static ssize_t
+qlcnic_store_diag_mode(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ unsigned long new;
+
+ if (strict_strtoul(buf, 2, &new))
+ return -EINVAL;
+
+ if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
+ adapter->flags ^= QLCNIC_DIAG_ENABLED;
+
+ return len;
+}
+
+static ssize_t
+qlcnic_show_diag_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n",
+ !!(adapter->flags & QLCNIC_DIAG_ENABLED));
+}
+
+static struct device_attribute dev_attr_diag_mode = {
+ .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
+ .show = qlcnic_show_diag_mode,
+ .store = qlcnic_store_diag_mode,
+};
+
+static int
+qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
+ loff_t offset, size_t size)
+{
+ if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
+ return -EIO;
+
+ if ((size != 4) || (offset & 0x3))
+ return -EINVAL;
+
+ if (offset < QLCNIC_PCI_CRBSPACE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_read_crb(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ u32 data;
+ int ret;
+
+ ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
+ if (ret != 0)
+ return ret;
+
+ data = QLCRD32(adapter, offset);
+ memcpy(buf, &data, size);
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_write_crb(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ u32 data;
+ int ret;
+
+ ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
+ if (ret != 0)
+ return ret;
+
+ memcpy(&data, buf, size);
+ QLCWR32(adapter, offset, data);
+ return size;
+}
+
+static int
+qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
+ loff_t offset, size_t size)
+{
+ if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
+ return -EIO;
+
+ if ((size != 8) || (offset & 0x7))
+ return -EIO;
+
+ return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ u64 data;
+ int ret;
+
+ ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
+ if (ret != 0)
+ return ret;
+
+ if (qlcnic_pci_mem_read_2M(adapter, offset, &data))
+ return -EIO;
+
+ memcpy(buf, &data, size);
+
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_write_mem(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ u64 data;
+ int ret;
+
+ ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
+ if (ret != 0)
+ return ret;
+
+ memcpy(&data, buf, size);
+
+ if (qlcnic_pci_mem_write_2M(adapter, offset, data))
+ return -EIO;
+
+ return size;
+}
+
+
+static struct bin_attribute bin_attr_crb = {
+ .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_read_crb,
+ .write = qlcnic_sysfs_write_crb,
+};
+
+static struct bin_attribute bin_attr_mem = {
+ .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_read_mem,
+ .write = qlcnic_sysfs_write_mem,
+};
+
+static void
+qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
+{
+ struct device *dev = &adapter->pdev->dev;
+
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
+ if (device_create_file(dev, &dev_attr_bridged_mode))
+ dev_warn(dev,
+ "failed to create bridged_mode sysfs entry\n");
+}
+
+static void
+qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
+{
+ struct device *dev = &adapter->pdev->dev;
+
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
+ device_remove_file(dev, &dev_attr_bridged_mode);
+}
+
+static void
+qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
+{
+ struct device *dev = &adapter->pdev->dev;
+
+ if (device_create_file(dev, &dev_attr_diag_mode))
+ dev_info(dev, "failed to create diag_mode sysfs entry\n");
+ if (device_create_bin_file(dev, &bin_attr_crb))
+ dev_info(dev, "failed to create crb sysfs entry\n");
+ if (device_create_bin_file(dev, &bin_attr_mem))
+ dev_info(dev, "failed to create mem sysfs entry\n");
+}
+
+
+static void
+qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
+{
+ struct device *dev = &adapter->pdev->dev;
+
+ device_remove_file(dev, &dev_attr_diag_mode);
+ device_remove_bin_file(dev, &bin_attr_crb);
+ device_remove_bin_file(dev, &bin_attr_mem);
+}
+
+#ifdef CONFIG_INET
+
+#define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops)
+
+static int
+qlcnic_destip_supported(struct qlcnic_adapter *adapter)
+{
+ if (adapter->ahw.cut_through)
+ return 0;
+
+ return 1;
+}
+
+static void
+qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
+{
+ struct in_device *indev;
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+ if (!qlcnic_destip_supported(adapter))
+ return;
+
+ indev = in_dev_get(dev);
+ if (!indev)
+ return;
+
+ for_ifa(indev) {
+ switch (event) {
+ case NETDEV_UP:
+ qlcnic_config_ipaddr(adapter,
+ ifa->ifa_address, QLCNIC_IP_UP);
+ break;
+ case NETDEV_DOWN:
+ qlcnic_config_ipaddr(adapter,
+ ifa->ifa_address, QLCNIC_IP_DOWN);
+ break;
+ default:
+ break;
+ }
+ } endfor_ifa(indev);
+
+ in_dev_put(indev);
+ return;
+}
+
+static int qlcnic_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct qlcnic_adapter *adapter;
+ struct net_device *dev = (struct net_device *)ptr;
+
+recheck:
+ if (dev == NULL)
+ goto done;
+
+ if (dev->priv_flags & IFF_802_1Q_VLAN) {
+ dev = vlan_dev_real_dev(dev);
+ goto recheck;
+ }
+
+ if (!is_qlcnic_netdev(dev))
+ goto done;
+
+ adapter = netdev_priv(dev);
+
+ if (!adapter)
+ goto done;
+
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ goto done;
+
+ qlcnic_config_indev_addr(dev, event);
+done:
+ return NOTIFY_DONE;
+}
+
+static int
+qlcnic_inetaddr_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct qlcnic_adapter *adapter;
+ struct net_device *dev;
+
+ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+
+ dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
+
+recheck:
+ if (dev == NULL || !netif_running(dev))
+ goto done;
+
+ if (dev->priv_flags & IFF_802_1Q_VLAN) {
+ dev = vlan_dev_real_dev(dev);
+ goto recheck;
+ }
+
+ if (!is_qlcnic_netdev(dev))
+ goto done;
+
+ adapter = netdev_priv(dev);
+
+ if (!adapter || !qlcnic_destip_supported(adapter))
+ goto done;
+
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ goto done;
+
+ switch (event) {
+ case NETDEV_UP:
+ qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP);
+ break;
+ case NETDEV_DOWN:
+ qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN);
+ break;
+ default:
+ break;
+ }
+
+done:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block qlcnic_netdev_cb = {
+ .notifier_call = qlcnic_netdev_event,
+};
+
+static struct notifier_block qlcnic_inetaddr_cb = {
+ .notifier_call = qlcnic_inetaddr_event,
+};
+#else
+static void
+qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
+{ }
+#endif
+
+static struct pci_driver qlcnic_driver = {
+ .name = qlcnic_driver_name,
+ .id_table = qlcnic_pci_tbl,
+ .probe = qlcnic_probe,
+ .remove = __devexit_p(qlcnic_remove),
+#ifdef CONFIG_PM
+ .suspend = qlcnic_suspend,
+ .resume = qlcnic_resume,
+#endif
+ .shutdown = qlcnic_shutdown
+};
+
+static int __init qlcnic_init_module(void)
+{
+
+ printk(KERN_INFO "%s\n", qlcnic_driver_string);
+
+#ifdef CONFIG_INET
+ register_netdevice_notifier(&qlcnic_netdev_cb);
+ register_inetaddr_notifier(&qlcnic_inetaddr_cb);
+#endif
+
+
+ return pci_register_driver(&qlcnic_driver);
+}
+
+module_init(qlcnic_init_module);
+
+static void __exit qlcnic_exit_module(void)
+{
+
+ pci_unregister_driver(&qlcnic_driver);
+
+#ifdef CONFIG_INET
+ unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
+ unregister_netdevice_notifier(&qlcnic_netdev_cb);
+#endif
+}
+
+module_exit(qlcnic_exit_module);
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 862c1aaf3860..8b742b639ceb 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -19,14 +19,6 @@
#define DRV_VERSION "v1.00.00.23.00.00-01"
#define PFX "qlge: "
-#define QPRINTK(qdev, nlevel, klevel, fmt, args...) \
- do { \
- if (!((qdev)->msg_enable & NETIF_MSG_##nlevel)) \
- ; \
- else \
- dev_printk(KERN_##klevel, &((qdev)->pdev->dev), \
- "%s: " fmt, __func__, ##args); \
- } while (0)
#define WQ_ADDR_ALIGN 0x3 /* 4 byte alignment */
@@ -54,12 +46,8 @@
#define RX_RING_SHADOW_SPACE (sizeof(u64) + \
MAX_DB_PAGES_PER_BQ(NUM_SMALL_BUFFERS) * sizeof(u64) + \
MAX_DB_PAGES_PER_BQ(NUM_LARGE_BUFFERS) * sizeof(u64))
-#define SMALL_BUFFER_SIZE 512
-#define SMALL_BUF_MAP_SIZE (SMALL_BUFFER_SIZE / 2)
#define LARGE_BUFFER_MAX_SIZE 8192
#define LARGE_BUFFER_MIN_SIZE 2048
-#define MAX_SPLIT_SIZE 1023
-#define QLGE_SB_PAD 32
#define MAX_CQ 128
#define DFLT_COALESCE_WAIT 100 /* 100 usec wait for coalescing */
@@ -79,15 +67,43 @@
#define TX_DESC_PER_OAL 0
#endif
+/* Word shifting for converting 64-bit
+ * address to a series of 16-bit words.
+ * This is used for some MPI firmware
+ * mailbox commands.
+ */
+#define LSW(x) ((u16)(x))
+#define MSW(x) ((u16)((u32)(x) >> 16))
+#define LSD(x) ((u32)((u64)(x)))
+#define MSD(x) ((u32)((((u64)(x)) >> 32)))
+
/* MPI test register definitions. This register
* is used for determining alternate NIC function's
* PCI->func number.
*/
enum {
MPI_TEST_FUNC_PORT_CFG = 0x1002,
+ MPI_TEST_FUNC_PRB_CTL = 0x100e,
+ MPI_TEST_FUNC_PRB_EN = 0x18a20000,
+ MPI_TEST_FUNC_RST_STS = 0x100a,
+ MPI_TEST_FUNC_RST_FRC = 0x00000003,
+ MPI_TEST_NIC_FUNC_MASK = 0x00000007,
+ MPI_TEST_NIC1_FUNCTION_ENABLE = (1 << 0),
+ MPI_TEST_NIC1_FUNCTION_MASK = 0x0000000e,
MPI_TEST_NIC1_FUNC_SHIFT = 1,
+ MPI_TEST_NIC2_FUNCTION_ENABLE = (1 << 4),
+ MPI_TEST_NIC2_FUNCTION_MASK = 0x000000e0,
MPI_TEST_NIC2_FUNC_SHIFT = 5,
- MPI_TEST_NIC_FUNC_MASK = 0x00000007,
+ MPI_TEST_FC1_FUNCTION_ENABLE = (1 << 8),
+ MPI_TEST_FC1_FUNCTION_MASK = 0x00000e00,
+ MPI_TEST_FC1_FUNCTION_SHIFT = 9,
+ MPI_TEST_FC2_FUNCTION_ENABLE = (1 << 12),
+ MPI_TEST_FC2_FUNCTION_MASK = 0x0000e000,
+ MPI_TEST_FC2_FUNCTION_SHIFT = 13,
+
+ MPI_NIC_READ = 0x00000000,
+ MPI_NIC_REG_BLOCK = 0x00020000,
+ MPI_NIC_FUNCTION_SHIFT = 6,
};
/*
@@ -468,7 +484,7 @@ enum {
MDIO_PORT = 0x00000440,
MDIO_STATUS = 0x00000450,
- /* XGMAC AUX statistics registers */
+ XGMAC_REGISTER_END = 0x00000740,
};
/*
@@ -509,6 +525,7 @@ enum {
enum {
MAC_ADDR_IDX_SHIFT = 4,
MAC_ADDR_TYPE_SHIFT = 16,
+ MAC_ADDR_TYPE_COUNT = 10,
MAC_ADDR_TYPE_MASK = 0x000f0000,
MAC_ADDR_TYPE_CAM_MAC = 0x00000000,
MAC_ADDR_TYPE_MULTI_MAC = 0x00010000,
@@ -526,6 +543,30 @@ enum {
MAC_ADDR_MR = (1 << 30),
MAC_ADDR_MW = (1 << 31),
MAX_MULTICAST_ENTRIES = 32,
+
+ /* Entry count and words per entry
+ * for each address type in the filter.
+ */
+ MAC_ADDR_MAX_CAM_ENTRIES = 512,
+ MAC_ADDR_MAX_CAM_WCOUNT = 3,
+ MAC_ADDR_MAX_MULTICAST_ENTRIES = 32,
+ MAC_ADDR_MAX_MULTICAST_WCOUNT = 2,
+ MAC_ADDR_MAX_VLAN_ENTRIES = 4096,
+ MAC_ADDR_MAX_VLAN_WCOUNT = 1,
+ MAC_ADDR_MAX_MCAST_FLTR_ENTRIES = 4096,
+ MAC_ADDR_MAX_MCAST_FLTR_WCOUNT = 1,
+ MAC_ADDR_MAX_FC_MAC_ENTRIES = 4,
+ MAC_ADDR_MAX_FC_MAC_WCOUNT = 2,
+ MAC_ADDR_MAX_MGMT_MAC_ENTRIES = 8,
+ MAC_ADDR_MAX_MGMT_MAC_WCOUNT = 2,
+ MAC_ADDR_MAX_MGMT_VLAN_ENTRIES = 16,
+ MAC_ADDR_MAX_MGMT_VLAN_WCOUNT = 1,
+ MAC_ADDR_MAX_MGMT_V4_ENTRIES = 4,
+ MAC_ADDR_MAX_MGMT_V4_WCOUNT = 1,
+ MAC_ADDR_MAX_MGMT_V6_ENTRIES = 4,
+ MAC_ADDR_MAX_MGMT_V6_WCOUNT = 4,
+ MAC_ADDR_MAX_MGMT_TU_DP_ENTRIES = 4,
+ MAC_ADDR_MAX_MGMT_TU_DP_WCOUNT = 1,
};
/*
@@ -596,6 +637,7 @@ enum {
enum {
RT_IDX_IDX_SHIFT = 8,
RT_IDX_TYPE_MASK = 0x000f0000,
+ RT_IDX_TYPE_SHIFT = 16,
RT_IDX_TYPE_RT = 0x00000000,
RT_IDX_TYPE_RT_INV = 0x00010000,
RT_IDX_TYPE_NICQ = 0x00020000,
@@ -664,7 +706,89 @@ enum {
RT_IDX_UNUSED013 = 13,
RT_IDX_UNUSED014 = 14,
RT_IDX_PROMISCUOUS_SLOT = 15,
- RT_IDX_MAX_SLOTS = 16,
+ RT_IDX_MAX_RT_SLOTS = 8,
+ RT_IDX_MAX_NIC_SLOTS = 16,
+};
+
+/*
+ * Serdes Address Register (XG_SERDES_ADDR) bit definitions.
+ */
+enum {
+ XG_SERDES_ADDR_RDY = (1 << 31),
+ XG_SERDES_ADDR_R = (1 << 30),
+
+ XG_SERDES_ADDR_STS = 0x00001E06,
+ XG_SERDES_ADDR_XFI1_PWR_UP = 0x00000005,
+ XG_SERDES_ADDR_XFI2_PWR_UP = 0x0000000a,
+ XG_SERDES_ADDR_XAUI_PWR_DOWN = 0x00000001,
+
+ /* Serdes coredump definitions. */
+ XG_SERDES_XAUI_AN_START = 0x00000000,
+ XG_SERDES_XAUI_AN_END = 0x00000034,
+ XG_SERDES_XAUI_HSS_PCS_START = 0x00000800,
+ XG_SERDES_XAUI_HSS_PCS_END = 0x0000880,
+ XG_SERDES_XFI_AN_START = 0x00001000,
+ XG_SERDES_XFI_AN_END = 0x00001034,
+ XG_SERDES_XFI_TRAIN_START = 0x10001050,
+ XG_SERDES_XFI_TRAIN_END = 0x1000107C,
+ XG_SERDES_XFI_HSS_PCS_START = 0x00001800,
+ XG_SERDES_XFI_HSS_PCS_END = 0x00001838,
+ XG_SERDES_XFI_HSS_TX_START = 0x00001c00,
+ XG_SERDES_XFI_HSS_TX_END = 0x00001c1f,
+ XG_SERDES_XFI_HSS_RX_START = 0x00001c40,
+ XG_SERDES_XFI_HSS_RX_END = 0x00001c5f,
+ XG_SERDES_XFI_HSS_PLL_START = 0x00001e00,
+ XG_SERDES_XFI_HSS_PLL_END = 0x00001e1f,
+};
+
+/*
+ * NIC Probe Mux Address Register (PRB_MX_ADDR) bit definitions.
+ */
+enum {
+ PRB_MX_ADDR_ARE = (1 << 16),
+ PRB_MX_ADDR_UP = (1 << 15),
+ PRB_MX_ADDR_SWP = (1 << 14),
+
+ /* Module select values. */
+ PRB_MX_ADDR_MAX_MODS = 21,
+ PRB_MX_ADDR_MOD_SEL_SHIFT = 9,
+ PRB_MX_ADDR_MOD_SEL_TBD = 0,
+ PRB_MX_ADDR_MOD_SEL_IDE1 = 1,
+ PRB_MX_ADDR_MOD_SEL_IDE2 = 2,
+ PRB_MX_ADDR_MOD_SEL_FRB = 3,
+ PRB_MX_ADDR_MOD_SEL_ODE1 = 4,
+ PRB_MX_ADDR_MOD_SEL_ODE2 = 5,
+ PRB_MX_ADDR_MOD_SEL_DA1 = 6,
+ PRB_MX_ADDR_MOD_SEL_DA2 = 7,
+ PRB_MX_ADDR_MOD_SEL_IMP1 = 8,
+ PRB_MX_ADDR_MOD_SEL_IMP2 = 9,
+ PRB_MX_ADDR_MOD_SEL_OMP1 = 10,
+ PRB_MX_ADDR_MOD_SEL_OMP2 = 11,
+ PRB_MX_ADDR_MOD_SEL_ORS1 = 12,
+ PRB_MX_ADDR_MOD_SEL_ORS2 = 13,
+ PRB_MX_ADDR_MOD_SEL_REG = 14,
+ PRB_MX_ADDR_MOD_SEL_MAC1 = 16,
+ PRB_MX_ADDR_MOD_SEL_MAC2 = 17,
+ PRB_MX_ADDR_MOD_SEL_VQM1 = 18,
+ PRB_MX_ADDR_MOD_SEL_VQM2 = 19,
+ PRB_MX_ADDR_MOD_SEL_MOP = 20,
+ /* Bit fields indicating which modules
+ * are valid for each clock domain.
+ */
+ PRB_MX_ADDR_VALID_SYS_MOD = 0x000f7ff7,
+ PRB_MX_ADDR_VALID_PCI_MOD = 0x000040c1,
+ PRB_MX_ADDR_VALID_XGM_MOD = 0x00037309,
+ PRB_MX_ADDR_VALID_FC_MOD = 0x00003001,
+ PRB_MX_ADDR_VALID_TOTAL = 34,
+
+ /* Clock domain values. */
+ PRB_MX_ADDR_CLOCK_SHIFT = 6,
+ PRB_MX_ADDR_SYS_CLOCK = 0,
+ PRB_MX_ADDR_PCI_CLOCK = 2,
+ PRB_MX_ADDR_FC_CLOCK = 5,
+ PRB_MX_ADDR_XGM_CLOCK = 6,
+
+ PRB_MX_ADDR_MAX_MUX = 64,
};
/*
@@ -737,6 +861,21 @@ enum {
PRB_MX_DATA = 0xfc, /* Use semaphore */
};
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+#define SMALL_BUFFER_SIZE 256
+#define SMALL_BUF_MAP_SIZE SMALL_BUFFER_SIZE
+#define SPLT_SETTING FSC_DBRST_1024
+#define SPLT_LEN 0
+#define QLGE_SB_PAD 0
+#else
+#define SMALL_BUFFER_SIZE 512
+#define SMALL_BUF_MAP_SIZE (SMALL_BUFFER_SIZE / 2)
+#define SPLT_SETTING FSC_SH
+#define SPLT_LEN (SPLT_HDR_EP | \
+ min(SMALL_BUF_MAP_SIZE, 1023))
+#define QLGE_SB_PAD 32
+#endif
+
/*
* CAM output format.
*/
@@ -1421,7 +1560,7 @@ struct nic_stats {
u64 rx_nic_fifo_drop;
};
-/* Address/Length pairs for the coredump. */
+/* Firmware coredump internal register address/length pairs. */
enum {
MPI_CORE_REGS_ADDR = 0x00030000,
MPI_CORE_REGS_CNT = 127,
@@ -1476,7 +1615,7 @@ struct mpi_coredump_segment_header {
u8 description[16];
};
-/* Reg dump segment numbers. */
+/* Firmware coredump header segment numbers. */
enum {
CORE_SEG_NUM = 1,
TEST_LOGIC_SEG_NUM = 2,
@@ -1527,6 +1666,67 @@ enum {
};
+/* There are 64 generic NIC registers. */
+#define NIC_REGS_DUMP_WORD_COUNT 64
+/* XGMAC word count. */
+#define XGMAC_DUMP_WORD_COUNT (XGMAC_REGISTER_END / 4)
+/* Word counts for the SERDES blocks. */
+#define XG_SERDES_XAUI_AN_COUNT 14
+#define XG_SERDES_XAUI_HSS_PCS_COUNT 33
+#define XG_SERDES_XFI_AN_COUNT 14
+#define XG_SERDES_XFI_TRAIN_COUNT 12
+#define XG_SERDES_XFI_HSS_PCS_COUNT 15
+#define XG_SERDES_XFI_HSS_TX_COUNT 32
+#define XG_SERDES_XFI_HSS_RX_COUNT 32
+#define XG_SERDES_XFI_HSS_PLL_COUNT 32
+
+/* There are 2 CNA ETS and 8 NIC ETS registers. */
+#define ETS_REGS_DUMP_WORD_COUNT 10
+
+/* Each probe mux entry stores the probe type plus 64 entries
+ * that are each each 64-bits in length. There are a total of
+ * 34 (PRB_MX_ADDR_VALID_TOTAL) valid probes.
+ */
+#define PRB_MX_ADDR_PRB_WORD_COUNT (1 + (PRB_MX_ADDR_MAX_MUX * 2))
+#define PRB_MX_DUMP_TOT_COUNT (PRB_MX_ADDR_PRB_WORD_COUNT * \
+ PRB_MX_ADDR_VALID_TOTAL)
+/* Each routing entry consists of 4 32-bit words.
+ * They are route type, index, index word, and result.
+ * There are 2 route blocks with 8 entries each and
+ * 2 NIC blocks with 16 entries each.
+ * The totol entries is 48 with 4 words each.
+ */
+#define RT_IDX_DUMP_ENTRIES 48
+#define RT_IDX_DUMP_WORDS_PER_ENTRY 4
+#define RT_IDX_DUMP_TOT_WORDS (RT_IDX_DUMP_ENTRIES * \
+ RT_IDX_DUMP_WORDS_PER_ENTRY)
+/* There are 10 address blocks in filter, each with
+ * different entry counts and different word-count-per-entry.
+ */
+#define MAC_ADDR_DUMP_ENTRIES \
+ ((MAC_ADDR_MAX_CAM_ENTRIES * MAC_ADDR_MAX_CAM_WCOUNT) + \
+ (MAC_ADDR_MAX_MULTICAST_ENTRIES * MAC_ADDR_MAX_MULTICAST_WCOUNT) + \
+ (MAC_ADDR_MAX_VLAN_ENTRIES * MAC_ADDR_MAX_VLAN_WCOUNT) + \
+ (MAC_ADDR_MAX_MCAST_FLTR_ENTRIES * MAC_ADDR_MAX_MCAST_FLTR_WCOUNT) + \
+ (MAC_ADDR_MAX_FC_MAC_ENTRIES * MAC_ADDR_MAX_FC_MAC_WCOUNT) + \
+ (MAC_ADDR_MAX_MGMT_MAC_ENTRIES * MAC_ADDR_MAX_MGMT_MAC_WCOUNT) + \
+ (MAC_ADDR_MAX_MGMT_VLAN_ENTRIES * MAC_ADDR_MAX_MGMT_VLAN_WCOUNT) + \
+ (MAC_ADDR_MAX_MGMT_V4_ENTRIES * MAC_ADDR_MAX_MGMT_V4_WCOUNT) + \
+ (MAC_ADDR_MAX_MGMT_V6_ENTRIES * MAC_ADDR_MAX_MGMT_V6_WCOUNT) + \
+ (MAC_ADDR_MAX_MGMT_TU_DP_ENTRIES * MAC_ADDR_MAX_MGMT_TU_DP_WCOUNT))
+#define MAC_ADDR_DUMP_WORDS_PER_ENTRY 2
+#define MAC_ADDR_DUMP_TOT_WORDS (MAC_ADDR_DUMP_ENTRIES * \
+ MAC_ADDR_DUMP_WORDS_PER_ENTRY)
+/* Maximum of 4 functions whose semaphore registeres are
+ * in the coredump.
+ */
+#define MAX_SEMAPHORE_FUNCTIONS 4
+/* Defines for access the MPI shadow registers. */
+#define RISC_124 0x0003007c
+#define RISC_127 0x0003007f
+#define SHADOW_OFFSET 0xb0000000
+#define SHADOW_REG_SHIFT 20
+
struct ql_nic_misc {
u32 rx_ring_count;
u32 tx_ring_count;
@@ -1568,6 +1768,199 @@ struct ql_reg_dump {
u32 ets[8+2];
};
+struct ql_mpi_coredump {
+ /* segment 0 */
+ struct mpi_coredump_global_header mpi_global_header;
+
+ /* segment 1 */
+ struct mpi_coredump_segment_header core_regs_seg_hdr;
+ u32 mpi_core_regs[MPI_CORE_REGS_CNT];
+ u32 mpi_core_sh_regs[MPI_CORE_SH_REGS_CNT];
+
+ /* segment 2 */
+ struct mpi_coredump_segment_header test_logic_regs_seg_hdr;
+ u32 test_logic_regs[TEST_REGS_CNT];
+
+ /* segment 3 */
+ struct mpi_coredump_segment_header rmii_regs_seg_hdr;
+ u32 rmii_regs[RMII_REGS_CNT];
+
+ /* segment 4 */
+ struct mpi_coredump_segment_header fcmac1_regs_seg_hdr;
+ u32 fcmac1_regs[FCMAC_REGS_CNT];
+
+ /* segment 5 */
+ struct mpi_coredump_segment_header fcmac2_regs_seg_hdr;
+ u32 fcmac2_regs[FCMAC_REGS_CNT];
+
+ /* segment 6 */
+ struct mpi_coredump_segment_header fc1_mbx_regs_seg_hdr;
+ u32 fc1_mbx_regs[FC_MBX_REGS_CNT];
+
+ /* segment 7 */
+ struct mpi_coredump_segment_header ide_regs_seg_hdr;
+ u32 ide_regs[IDE_REGS_CNT];
+
+ /* segment 8 */
+ struct mpi_coredump_segment_header nic1_mbx_regs_seg_hdr;
+ u32 nic1_mbx_regs[NIC_MBX_REGS_CNT];
+
+ /* segment 9 */
+ struct mpi_coredump_segment_header smbus_regs_seg_hdr;
+ u32 smbus_regs[SMBUS_REGS_CNT];
+
+ /* segment 10 */
+ struct mpi_coredump_segment_header fc2_mbx_regs_seg_hdr;
+ u32 fc2_mbx_regs[FC_MBX_REGS_CNT];
+
+ /* segment 11 */
+ struct mpi_coredump_segment_header nic2_mbx_regs_seg_hdr;
+ u32 nic2_mbx_regs[NIC_MBX_REGS_CNT];
+
+ /* segment 12 */
+ struct mpi_coredump_segment_header i2c_regs_seg_hdr;
+ u32 i2c_regs[I2C_REGS_CNT];
+ /* segment 13 */
+ struct mpi_coredump_segment_header memc_regs_seg_hdr;
+ u32 memc_regs[MEMC_REGS_CNT];
+
+ /* segment 14 */
+ struct mpi_coredump_segment_header pbus_regs_seg_hdr;
+ u32 pbus_regs[PBUS_REGS_CNT];
+
+ /* segment 15 */
+ struct mpi_coredump_segment_header mde_regs_seg_hdr;
+ u32 mde_regs[MDE_REGS_CNT];
+
+ /* segment 16 */
+ struct mpi_coredump_segment_header nic_regs_seg_hdr;
+ u32 nic_regs[NIC_REGS_DUMP_WORD_COUNT];
+
+ /* segment 17 */
+ struct mpi_coredump_segment_header nic2_regs_seg_hdr;
+ u32 nic2_regs[NIC_REGS_DUMP_WORD_COUNT];
+
+ /* segment 18 */
+ struct mpi_coredump_segment_header xgmac1_seg_hdr;
+ u32 xgmac1[XGMAC_DUMP_WORD_COUNT];
+
+ /* segment 19 */
+ struct mpi_coredump_segment_header xgmac2_seg_hdr;
+ u32 xgmac2[XGMAC_DUMP_WORD_COUNT];
+
+ /* segment 20 */
+ struct mpi_coredump_segment_header code_ram_seg_hdr;
+ u32 code_ram[CODE_RAM_CNT];
+
+ /* segment 21 */
+ struct mpi_coredump_segment_header memc_ram_seg_hdr;
+ u32 memc_ram[MEMC_RAM_CNT];
+
+ /* segment 22 */
+ struct mpi_coredump_segment_header xaui_an_hdr;
+ u32 serdes_xaui_an[XG_SERDES_XAUI_AN_COUNT];
+
+ /* segment 23 */
+ struct mpi_coredump_segment_header xaui_hss_pcs_hdr;
+ u32 serdes_xaui_hss_pcs[XG_SERDES_XAUI_HSS_PCS_COUNT];
+
+ /* segment 24 */
+ struct mpi_coredump_segment_header xfi_an_hdr;
+ u32 serdes_xfi_an[XG_SERDES_XFI_AN_COUNT];
+
+ /* segment 25 */
+ struct mpi_coredump_segment_header xfi_train_hdr;
+ u32 serdes_xfi_train[XG_SERDES_XFI_TRAIN_COUNT];
+
+ /* segment 26 */
+ struct mpi_coredump_segment_header xfi_hss_pcs_hdr;
+ u32 serdes_xfi_hss_pcs[XG_SERDES_XFI_HSS_PCS_COUNT];
+
+ /* segment 27 */
+ struct mpi_coredump_segment_header xfi_hss_tx_hdr;
+ u32 serdes_xfi_hss_tx[XG_SERDES_XFI_HSS_TX_COUNT];
+
+ /* segment 28 */
+ struct mpi_coredump_segment_header xfi_hss_rx_hdr;
+ u32 serdes_xfi_hss_rx[XG_SERDES_XFI_HSS_RX_COUNT];
+
+ /* segment 29 */
+ struct mpi_coredump_segment_header xfi_hss_pll_hdr;
+ u32 serdes_xfi_hss_pll[XG_SERDES_XFI_HSS_PLL_COUNT];
+
+ /* segment 30 */
+ struct mpi_coredump_segment_header misc_nic_seg_hdr;
+ struct ql_nic_misc misc_nic_info;
+
+ /* segment 31 */
+ /* one interrupt state for each CQ */
+ struct mpi_coredump_segment_header intr_states_seg_hdr;
+ u32 intr_states[MAX_RX_RINGS];
+
+ /* segment 32 */
+ /* 3 cam words each for 16 unicast,
+ * 2 cam words for each of 32 multicast.
+ */
+ struct mpi_coredump_segment_header cam_entries_seg_hdr;
+ u32 cam_entries[(16 * 3) + (32 * 3)];
+
+ /* segment 33 */
+ struct mpi_coredump_segment_header nic_routing_words_seg_hdr;
+ u32 nic_routing_words[16];
+ /* segment 34 */
+ struct mpi_coredump_segment_header ets_seg_hdr;
+ u32 ets[ETS_REGS_DUMP_WORD_COUNT];
+
+ /* segment 35 */
+ struct mpi_coredump_segment_header probe_dump_seg_hdr;
+ u32 probe_dump[PRB_MX_DUMP_TOT_COUNT];
+
+ /* segment 36 */
+ struct mpi_coredump_segment_header routing_reg_seg_hdr;
+ u32 routing_regs[RT_IDX_DUMP_TOT_WORDS];
+
+ /* segment 37 */
+ struct mpi_coredump_segment_header mac_prot_reg_seg_hdr;
+ u32 mac_prot_regs[MAC_ADDR_DUMP_TOT_WORDS];
+
+ /* segment 38 */
+ struct mpi_coredump_segment_header xaui2_an_hdr;
+ u32 serdes2_xaui_an[XG_SERDES_XAUI_AN_COUNT];
+
+ /* segment 39 */
+ struct mpi_coredump_segment_header xaui2_hss_pcs_hdr;
+ u32 serdes2_xaui_hss_pcs[XG_SERDES_XAUI_HSS_PCS_COUNT];
+
+ /* segment 40 */
+ struct mpi_coredump_segment_header xfi2_an_hdr;
+ u32 serdes2_xfi_an[XG_SERDES_XFI_AN_COUNT];
+
+ /* segment 41 */
+ struct mpi_coredump_segment_header xfi2_train_hdr;
+ u32 serdes2_xfi_train[XG_SERDES_XFI_TRAIN_COUNT];
+
+ /* segment 42 */
+ struct mpi_coredump_segment_header xfi2_hss_pcs_hdr;
+ u32 serdes2_xfi_hss_pcs[XG_SERDES_XFI_HSS_PCS_COUNT];
+
+ /* segment 43 */
+ struct mpi_coredump_segment_header xfi2_hss_tx_hdr;
+ u32 serdes2_xfi_hss_tx[XG_SERDES_XFI_HSS_TX_COUNT];
+
+ /* segment 44 */
+ struct mpi_coredump_segment_header xfi2_hss_rx_hdr;
+ u32 serdes2_xfi_hss_rx[XG_SERDES_XFI_HSS_RX_COUNT];
+
+ /* segment 45 */
+ struct mpi_coredump_segment_header xfi2_hss_pll_hdr;
+ u32 serdes2_xfi_hss_pll[XG_SERDES_XFI_HSS_PLL_COUNT];
+
+ /* segment 50 */
+ /* semaphore register for all 5 functions */
+ struct mpi_coredump_segment_header sem_regs_seg_hdr;
+ u32 sem_regs[MAX_SEMAPHORE_FUNCTIONS];
+};
+
/*
* intr_context structure is used during initialization
* to hook the interrupts. It is also used in a single
@@ -1603,6 +1996,8 @@ enum {
QL_CAM_RT_SET = 8,
QL_SELFTEST = 9,
QL_LB_LINK_UP = 10,
+ QL_FRC_COREDUMP = 11,
+ QL_EEH_FATAL = 12,
};
/* link_status bit definitions */
@@ -1724,6 +2119,8 @@ struct ql_adapter {
u32 port_link_up;
u32 port_init;
u32 link_status;
+ struct ql_mpi_coredump *mpi_coredump;
+ u32 core_is_dumped;
u32 link_config;
u32 led_config;
u32 max_frame_size;
@@ -1736,10 +2133,14 @@ struct ql_adapter {
struct delayed_work mpi_work;
struct delayed_work mpi_port_cfg_work;
struct delayed_work mpi_idc_work;
+ struct delayed_work mpi_core_to_log;
struct completion ide_completion;
struct nic_operations *nic_ops;
u16 device_id;
+ struct timer_list timer;
atomic_t lb_count;
+ /* Keep local copy of current mac address. */
+ char current_mac_addr[6];
};
/*
@@ -1807,6 +2208,7 @@ extern int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
void ql_queue_fw_error(struct ql_adapter *qdev);
void ql_mpi_work(struct work_struct *work);
void ql_mpi_reset_work(struct work_struct *work);
+void ql_mpi_core_to_log(struct work_struct *work);
int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 ebit);
void ql_queue_asic_error(struct ql_adapter *qdev);
u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr);
@@ -1817,6 +2219,15 @@ void ql_mpi_port_cfg_work(struct work_struct *work);
int ql_mb_get_fw_state(struct ql_adapter *qdev);
int ql_cam_route_initialize(struct ql_adapter *qdev);
int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
+int ql_write_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 data);
+int ql_unpause_mpi_risc(struct ql_adapter *qdev);
+int ql_pause_mpi_risc(struct ql_adapter *qdev);
+int ql_hard_reset_mpi_risc(struct ql_adapter *qdev);
+int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf,
+ u32 ram_addr, int word_count);
+int ql_core_dump(struct ql_adapter *qdev,
+ struct ql_mpi_coredump *mpi_coredump);
+int ql_mb_sys_err(struct ql_adapter *qdev);
int ql_mb_about_fw(struct ql_adapter *qdev);
int ql_wol(struct ql_adapter *qdev);
int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol);
@@ -1833,6 +2244,7 @@ void ql_gen_reg_dump(struct ql_adapter *qdev,
struct ql_reg_dump *mpi_coredump);
netdev_tx_t ql_lb_send(struct sk_buff *skb, struct net_device *ndev);
void ql_check_lb_frame(struct ql_adapter *, struct sk_buff *);
+int ql_own_firmware(struct ql_adapter *qdev);
int ql_clean_lb_rx_ring(struct rx_ring *rx_ring, int budget);
#if 1
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index 9f58c4710761..ff8550d2ca82 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -1,5 +1,405 @@
#include "qlge.h"
+/* Read a NIC register from the alternate function. */
+static u32 ql_read_other_func_reg(struct ql_adapter *qdev,
+ u32 reg)
+{
+ u32 register_to_read;
+ u32 reg_val;
+ unsigned int status = 0;
+
+ register_to_read = MPI_NIC_REG_BLOCK
+ | MPI_NIC_READ
+ | (qdev->alt_func << MPI_NIC_FUNCTION_SHIFT)
+ | reg;
+ status = ql_read_mpi_reg(qdev, register_to_read, &reg_val);
+ if (status != 0)
+ return 0xffffffff;
+
+ return reg_val;
+}
+
+/* Write a NIC register from the alternate function. */
+static int ql_write_other_func_reg(struct ql_adapter *qdev,
+ u32 reg, u32 reg_val)
+{
+ u32 register_to_read;
+ int status = 0;
+
+ register_to_read = MPI_NIC_REG_BLOCK
+ | MPI_NIC_READ
+ | (qdev->alt_func << MPI_NIC_FUNCTION_SHIFT)
+ | reg;
+ status = ql_write_mpi_reg(qdev, register_to_read, reg_val);
+
+ return status;
+}
+
+static int ql_wait_other_func_reg_rdy(struct ql_adapter *qdev, u32 reg,
+ u32 bit, u32 err_bit)
+{
+ u32 temp;
+ int count = 10;
+
+ while (count) {
+ temp = ql_read_other_func_reg(qdev, reg);
+
+ /* check for errors */
+ if (temp & err_bit)
+ return -1;
+ else if (temp & bit)
+ return 0;
+ mdelay(10);
+ count--;
+ }
+ return -1;
+}
+
+static int ql_read_other_func_serdes_reg(struct ql_adapter *qdev, u32 reg,
+ u32 *data)
+{
+ int status;
+
+ /* wait for reg to come ready */
+ status = ql_wait_other_func_reg_rdy(qdev, XG_SERDES_ADDR / 4,
+ XG_SERDES_ADDR_RDY, 0);
+ if (status)
+ goto exit;
+
+ /* set up for reg read */
+ ql_write_other_func_reg(qdev, XG_SERDES_ADDR/4, reg | PROC_ADDR_R);
+
+ /* wait for reg to come ready */
+ status = ql_wait_other_func_reg_rdy(qdev, XG_SERDES_ADDR / 4,
+ XG_SERDES_ADDR_RDY, 0);
+ if (status)
+ goto exit;
+
+ /* get the data */
+ *data = ql_read_other_func_reg(qdev, (XG_SERDES_DATA / 4));
+exit:
+ return status;
+}
+
+/* Read out the SERDES registers */
+static int ql_read_serdes_reg(struct ql_adapter *qdev, u32 reg, u32 * data)
+{
+ int status;
+
+ /* wait for reg to come ready */
+ status = ql_wait_reg_rdy(qdev, XG_SERDES_ADDR, XG_SERDES_ADDR_RDY, 0);
+ if (status)
+ goto exit;
+
+ /* set up for reg read */
+ ql_write32(qdev, XG_SERDES_ADDR, reg | PROC_ADDR_R);
+
+ /* wait for reg to come ready */
+ status = ql_wait_reg_rdy(qdev, XG_SERDES_ADDR, XG_SERDES_ADDR_RDY, 0);
+ if (status)
+ goto exit;
+
+ /* get the data */
+ *data = ql_read32(qdev, XG_SERDES_DATA);
+exit:
+ return status;
+}
+
+static void ql_get_both_serdes(struct ql_adapter *qdev, u32 addr,
+ u32 *direct_ptr, u32 *indirect_ptr,
+ unsigned int direct_valid, unsigned int indirect_valid)
+{
+ unsigned int status;
+
+ status = 1;
+ if (direct_valid)
+ status = ql_read_serdes_reg(qdev, addr, direct_ptr);
+ /* Dead fill any failures or invalids. */
+ if (status)
+ *direct_ptr = 0xDEADBEEF;
+
+ status = 1;
+ if (indirect_valid)
+ status = ql_read_other_func_serdes_reg(
+ qdev, addr, indirect_ptr);
+ /* Dead fill any failures or invalids. */
+ if (status)
+ *indirect_ptr = 0xDEADBEEF;
+}
+
+static int ql_get_serdes_regs(struct ql_adapter *qdev,
+ struct ql_mpi_coredump *mpi_coredump)
+{
+ int status;
+ unsigned int xfi_direct_valid, xfi_indirect_valid, xaui_direct_valid;
+ unsigned int xaui_indirect_valid, i;
+ u32 *direct_ptr, temp;
+ u32 *indirect_ptr;
+
+ xfi_direct_valid = xfi_indirect_valid = 0;
+ xaui_direct_valid = xaui_indirect_valid = 1;
+
+ /* The XAUI needs to be read out per port */
+ if (qdev->func & 1) {
+ /* We are NIC 2 */
+ status = ql_read_other_func_serdes_reg(qdev,
+ XG_SERDES_XAUI_HSS_PCS_START, &temp);
+ if (status)
+ temp = XG_SERDES_ADDR_XAUI_PWR_DOWN;
+ if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) ==
+ XG_SERDES_ADDR_XAUI_PWR_DOWN)
+ xaui_indirect_valid = 0;
+
+ status = ql_read_serdes_reg(qdev,
+ XG_SERDES_XAUI_HSS_PCS_START, &temp);
+ if (status)
+ temp = XG_SERDES_ADDR_XAUI_PWR_DOWN;
+
+ if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) ==
+ XG_SERDES_ADDR_XAUI_PWR_DOWN)
+ xaui_direct_valid = 0;
+ } else {
+ /* We are NIC 1 */
+ status = ql_read_other_func_serdes_reg(qdev,
+ XG_SERDES_XAUI_HSS_PCS_START, &temp);
+ if (status)
+ temp = XG_SERDES_ADDR_XAUI_PWR_DOWN;
+ if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) ==
+ XG_SERDES_ADDR_XAUI_PWR_DOWN)
+ xaui_indirect_valid = 0;
+
+ status = ql_read_serdes_reg(qdev,
+ XG_SERDES_XAUI_HSS_PCS_START, &temp);
+ if (status)
+ temp = XG_SERDES_ADDR_XAUI_PWR_DOWN;
+ if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) ==
+ XG_SERDES_ADDR_XAUI_PWR_DOWN)
+ xaui_direct_valid = 0;
+ }
+
+ /*
+ * XFI register is shared so only need to read one
+ * functions and then check the bits.
+ */
+ status = ql_read_serdes_reg(qdev, XG_SERDES_ADDR_STS, &temp);
+ if (status)
+ temp = 0;
+
+ if ((temp & XG_SERDES_ADDR_XFI1_PWR_UP) ==
+ XG_SERDES_ADDR_XFI1_PWR_UP) {
+ /* now see if i'm NIC 1 or NIC 2 */
+ if (qdev->func & 1)
+ /* I'm NIC 2, so the indirect (NIC1) xfi is up. */
+ xfi_indirect_valid = 1;
+ else
+ xfi_direct_valid = 1;
+ }
+ if ((temp & XG_SERDES_ADDR_XFI2_PWR_UP) ==
+ XG_SERDES_ADDR_XFI2_PWR_UP) {
+ /* now see if i'm NIC 1 or NIC 2 */
+ if (qdev->func & 1)
+ /* I'm NIC 2, so the indirect (NIC1) xfi is up. */
+ xfi_direct_valid = 1;
+ else
+ xfi_indirect_valid = 1;
+ }
+
+ /* Get XAUI_AN register block. */
+ if (qdev->func & 1) {
+ /* Function 2 is direct */
+ direct_ptr = mpi_coredump->serdes2_xaui_an;
+ indirect_ptr = mpi_coredump->serdes_xaui_an;
+ } else {
+ /* Function 1 is direct */
+ direct_ptr = mpi_coredump->serdes_xaui_an;
+ indirect_ptr = mpi_coredump->serdes2_xaui_an;
+ }
+
+ for (i = 0; i <= 0x000000034; i += 4, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xaui_direct_valid, xaui_indirect_valid);
+
+ /* Get XAUI_HSS_PCS register block. */
+ if (qdev->func & 1) {
+ direct_ptr =
+ mpi_coredump->serdes2_xaui_hss_pcs;
+ indirect_ptr =
+ mpi_coredump->serdes_xaui_hss_pcs;
+ } else {
+ direct_ptr =
+ mpi_coredump->serdes_xaui_hss_pcs;
+ indirect_ptr =
+ mpi_coredump->serdes2_xaui_hss_pcs;
+ }
+
+ for (i = 0x800; i <= 0x880; i += 4, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xaui_direct_valid, xaui_indirect_valid);
+
+ /* Get XAUI_XFI_AN register block. */
+ if (qdev->func & 1) {
+ direct_ptr = mpi_coredump->serdes2_xfi_an;
+ indirect_ptr = mpi_coredump->serdes_xfi_an;
+ } else {
+ direct_ptr = mpi_coredump->serdes_xfi_an;
+ indirect_ptr = mpi_coredump->serdes2_xfi_an;
+ }
+
+ for (i = 0x1000; i <= 0x1034; i += 4, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xfi_direct_valid, xfi_indirect_valid);
+
+ /* Get XAUI_XFI_TRAIN register block. */
+ if (qdev->func & 1) {
+ direct_ptr = mpi_coredump->serdes2_xfi_train;
+ indirect_ptr =
+ mpi_coredump->serdes_xfi_train;
+ } else {
+ direct_ptr = mpi_coredump->serdes_xfi_train;
+ indirect_ptr =
+ mpi_coredump->serdes2_xfi_train;
+ }
+
+ for (i = 0x1050; i <= 0x107c; i += 4, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xfi_direct_valid, xfi_indirect_valid);
+
+ /* Get XAUI_XFI_HSS_PCS register block. */
+ if (qdev->func & 1) {
+ direct_ptr =
+ mpi_coredump->serdes2_xfi_hss_pcs;
+ indirect_ptr =
+ mpi_coredump->serdes_xfi_hss_pcs;
+ } else {
+ direct_ptr =
+ mpi_coredump->serdes_xfi_hss_pcs;
+ indirect_ptr =
+ mpi_coredump->serdes2_xfi_hss_pcs;
+ }
+
+ for (i = 0x1800; i <= 0x1838; i += 4, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xfi_direct_valid, xfi_indirect_valid);
+
+ /* Get XAUI_XFI_HSS_TX register block. */
+ if (qdev->func & 1) {
+ direct_ptr =
+ mpi_coredump->serdes2_xfi_hss_tx;
+ indirect_ptr =
+ mpi_coredump->serdes_xfi_hss_tx;
+ } else {
+ direct_ptr = mpi_coredump->serdes_xfi_hss_tx;
+ indirect_ptr =
+ mpi_coredump->serdes2_xfi_hss_tx;
+ }
+ for (i = 0x1c00; i <= 0x1c1f; i++, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xfi_direct_valid, xfi_indirect_valid);
+
+ /* Get XAUI_XFI_HSS_RX register block. */
+ if (qdev->func & 1) {
+ direct_ptr =
+ mpi_coredump->serdes2_xfi_hss_rx;
+ indirect_ptr =
+ mpi_coredump->serdes_xfi_hss_rx;
+ } else {
+ direct_ptr = mpi_coredump->serdes_xfi_hss_rx;
+ indirect_ptr =
+ mpi_coredump->serdes2_xfi_hss_rx;
+ }
+
+ for (i = 0x1c40; i <= 0x1c5f; i++, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xfi_direct_valid, xfi_indirect_valid);
+
+
+ /* Get XAUI_XFI_HSS_PLL register block. */
+ if (qdev->func & 1) {
+ direct_ptr =
+ mpi_coredump->serdes2_xfi_hss_pll;
+ indirect_ptr =
+ mpi_coredump->serdes_xfi_hss_pll;
+ } else {
+ direct_ptr =
+ mpi_coredump->serdes_xfi_hss_pll;
+ indirect_ptr =
+ mpi_coredump->serdes2_xfi_hss_pll;
+ }
+ for (i = 0x1e00; i <= 0x1e1f; i++, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xfi_direct_valid, xfi_indirect_valid);
+ return 0;
+}
+
+static int ql_read_other_func_xgmac_reg(struct ql_adapter *qdev, u32 reg,
+ u32 *data)
+{
+ int status = 0;
+
+ /* wait for reg to come ready */
+ status = ql_wait_other_func_reg_rdy(qdev, XGMAC_ADDR / 4,
+ XGMAC_ADDR_RDY, XGMAC_ADDR_XME);
+ if (status)
+ goto exit;
+
+ /* set up for reg read */
+ ql_write_other_func_reg(qdev, XGMAC_ADDR / 4, reg | XGMAC_ADDR_R);
+
+ /* wait for reg to come ready */
+ status = ql_wait_other_func_reg_rdy(qdev, XGMAC_ADDR / 4,
+ XGMAC_ADDR_RDY, XGMAC_ADDR_XME);
+ if (status)
+ goto exit;
+
+ /* get the data */
+ *data = ql_read_other_func_reg(qdev, XGMAC_DATA / 4);
+exit:
+ return status;
+}
+
+/* Read the 400 xgmac control/statistics registers
+ * skipping unused locations.
+ */
+static int ql_get_xgmac_regs(struct ql_adapter *qdev, u32 * buf,
+ unsigned int other_function)
+{
+ int status = 0;
+ int i;
+
+ for (i = PAUSE_SRC_LO; i < XGMAC_REGISTER_END; i += 4, buf++) {
+ /* We're reading 400 xgmac registers, but we filter out
+ * serveral locations that are non-responsive to reads.
+ */
+ if ((i == 0x00000114) ||
+ (i == 0x00000118) ||
+ (i == 0x0000013c) ||
+ (i == 0x00000140) ||
+ (i > 0x00000150 && i < 0x000001fc) ||
+ (i > 0x00000278 && i < 0x000002a0) ||
+ (i > 0x000002c0 && i < 0x000002cf) ||
+ (i > 0x000002dc && i < 0x000002f0) ||
+ (i > 0x000003c8 && i < 0x00000400) ||
+ (i > 0x00000400 && i < 0x00000410) ||
+ (i > 0x00000410 && i < 0x00000420) ||
+ (i > 0x00000420 && i < 0x00000430) ||
+ (i > 0x00000430 && i < 0x00000440) ||
+ (i > 0x00000440 && i < 0x00000450) ||
+ (i > 0x00000450 && i < 0x00000500) ||
+ (i > 0x0000054c && i < 0x00000568) ||
+ (i > 0x000005c8 && i < 0x00000600)) {
+ if (other_function)
+ status =
+ ql_read_other_func_xgmac_reg(qdev, i, buf);
+ else
+ status = ql_read_xgmac_reg(qdev, i, buf);
+
+ if (status)
+ *buf = 0xdeadbeef;
+ break;
+ }
+ }
+ return status;
+}
static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf)
{
@@ -43,8 +443,8 @@ static int ql_get_cam_entries(struct ql_adapter *qdev, u32 * buf)
status = ql_get_mac_addr_reg(qdev,
MAC_ADDR_TYPE_CAM_MAC, i, value);
if (status) {
- QPRINTK(qdev, DRV, ERR,
- "Failed read of mac index register.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed read of mac index register.\n");
goto err;
}
*buf++ = value[0]; /* lower MAC address */
@@ -55,8 +455,8 @@ static int ql_get_cam_entries(struct ql_adapter *qdev, u32 * buf)
status = ql_get_mac_addr_reg(qdev,
MAC_ADDR_TYPE_MULTI_MAC, i, value);
if (status) {
- QPRINTK(qdev, DRV, ERR,
- "Failed read of mac index register.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed read of mac index register.\n");
goto err;
}
*buf++ = value[0]; /* lower Mcast address */
@@ -79,8 +479,8 @@ static int ql_get_routing_entries(struct ql_adapter *qdev, u32 * buf)
for (i = 0; i < 16; i++) {
status = ql_get_routing_reg(qdev, i, &value);
if (status) {
- QPRINTK(qdev, DRV, ERR,
- "Failed read of routing index register.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed read of routing index register.\n");
goto err;
} else {
*buf++ = value;
@@ -91,6 +491,226 @@ err:
return status;
}
+/* Read the MPI Processor shadow registers */
+static int ql_get_mpi_shadow_regs(struct ql_adapter *qdev, u32 * buf)
+{
+ u32 i;
+ int status;
+
+ for (i = 0; i < MPI_CORE_SH_REGS_CNT; i++, buf++) {
+ status = ql_write_mpi_reg(qdev, RISC_124,
+ (SHADOW_OFFSET | i << SHADOW_REG_SHIFT));
+ if (status)
+ goto end;
+ status = ql_read_mpi_reg(qdev, RISC_127, buf);
+ if (status)
+ goto end;
+ }
+end:
+ return status;
+}
+
+/* Read the MPI Processor core registers */
+static int ql_get_mpi_regs(struct ql_adapter *qdev, u32 * buf,
+ u32 offset, u32 count)
+{
+ int i, status = 0;
+ for (i = 0; i < count; i++, buf++) {
+ status = ql_read_mpi_reg(qdev, offset + i, buf);
+ if (status)
+ return status;
+ }
+ return status;
+}
+
+/* Read the ASIC probe dump */
+static unsigned int *ql_get_probe(struct ql_adapter *qdev, u32 clock,
+ u32 valid, u32 *buf)
+{
+ u32 module, mux_sel, probe, lo_val, hi_val;
+
+ for (module = 0; module < PRB_MX_ADDR_MAX_MODS; module++) {
+ if (!((valid >> module) & 1))
+ continue;
+ for (mux_sel = 0; mux_sel < PRB_MX_ADDR_MAX_MUX; mux_sel++) {
+ probe = clock
+ | PRB_MX_ADDR_ARE
+ | mux_sel
+ | (module << PRB_MX_ADDR_MOD_SEL_SHIFT);
+ ql_write32(qdev, PRB_MX_ADDR, probe);
+ lo_val = ql_read32(qdev, PRB_MX_DATA);
+ if (mux_sel == 0) {
+ *buf = probe;
+ buf++;
+ }
+ probe |= PRB_MX_ADDR_UP;
+ ql_write32(qdev, PRB_MX_ADDR, probe);
+ hi_val = ql_read32(qdev, PRB_MX_DATA);
+ *buf = lo_val;
+ buf++;
+ *buf = hi_val;
+ buf++;
+ }
+ }
+ return buf;
+}
+
+static int ql_get_probe_dump(struct ql_adapter *qdev, unsigned int *buf)
+{
+ /* First we have to enable the probe mux */
+ ql_write_mpi_reg(qdev, MPI_TEST_FUNC_PRB_CTL, MPI_TEST_FUNC_PRB_EN);
+ buf = ql_get_probe(qdev, PRB_MX_ADDR_SYS_CLOCK,
+ PRB_MX_ADDR_VALID_SYS_MOD, buf);
+ buf = ql_get_probe(qdev, PRB_MX_ADDR_PCI_CLOCK,
+ PRB_MX_ADDR_VALID_PCI_MOD, buf);
+ buf = ql_get_probe(qdev, PRB_MX_ADDR_XGM_CLOCK,
+ PRB_MX_ADDR_VALID_XGM_MOD, buf);
+ buf = ql_get_probe(qdev, PRB_MX_ADDR_FC_CLOCK,
+ PRB_MX_ADDR_VALID_FC_MOD, buf);
+ return 0;
+
+}
+
+/* Read out the routing index registers */
+static int ql_get_routing_index_registers(struct ql_adapter *qdev, u32 *buf)
+{
+ int status;
+ u32 type, index, index_max;
+ u32 result_index;
+ u32 result_data;
+ u32 val;
+
+ status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
+ if (status)
+ return status;
+
+ for (type = 0; type < 4; type++) {
+ if (type < 2)
+ index_max = 8;
+ else
+ index_max = 16;
+ for (index = 0; index < index_max; index++) {
+ val = RT_IDX_RS
+ | (type << RT_IDX_TYPE_SHIFT)
+ | (index << RT_IDX_IDX_SHIFT);
+ ql_write32(qdev, RT_IDX, val);
+ result_index = 0;
+ while ((result_index & RT_IDX_MR) == 0)
+ result_index = ql_read32(qdev, RT_IDX);
+ result_data = ql_read32(qdev, RT_DATA);
+ *buf = type;
+ buf++;
+ *buf = index;
+ buf++;
+ *buf = result_index;
+ buf++;
+ *buf = result_data;
+ buf++;
+ }
+ }
+ ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
+ return status;
+}
+
+/* Read out the MAC protocol registers */
+static void ql_get_mac_protocol_registers(struct ql_adapter *qdev, u32 *buf)
+{
+ u32 result_index, result_data;
+ u32 type;
+ u32 index;
+ u32 offset;
+ u32 val;
+ u32 initial_val = MAC_ADDR_RS;
+ u32 max_index;
+ u32 max_offset;
+
+ for (type = 0; type < MAC_ADDR_TYPE_COUNT; type++) {
+ switch (type) {
+
+ case 0: /* CAM */
+ initial_val |= MAC_ADDR_ADR;
+ max_index = MAC_ADDR_MAX_CAM_ENTRIES;
+ max_offset = MAC_ADDR_MAX_CAM_WCOUNT;
+ break;
+ case 1: /* Multicast MAC Address */
+ max_index = MAC_ADDR_MAX_CAM_WCOUNT;
+ max_offset = MAC_ADDR_MAX_CAM_WCOUNT;
+ break;
+ case 2: /* VLAN filter mask */
+ case 3: /* MC filter mask */
+ max_index = MAC_ADDR_MAX_CAM_WCOUNT;
+ max_offset = MAC_ADDR_MAX_CAM_WCOUNT;
+ break;
+ case 4: /* FC MAC addresses */
+ max_index = MAC_ADDR_MAX_FC_MAC_ENTRIES;
+ max_offset = MAC_ADDR_MAX_FC_MAC_WCOUNT;
+ break;
+ case 5: /* Mgmt MAC addresses */
+ max_index = MAC_ADDR_MAX_MGMT_MAC_ENTRIES;
+ max_offset = MAC_ADDR_MAX_MGMT_MAC_WCOUNT;
+ break;
+ case 6: /* Mgmt VLAN addresses */
+ max_index = MAC_ADDR_MAX_MGMT_VLAN_ENTRIES;
+ max_offset = MAC_ADDR_MAX_MGMT_VLAN_WCOUNT;
+ break;
+ case 7: /* Mgmt IPv4 address */
+ max_index = MAC_ADDR_MAX_MGMT_V4_ENTRIES;
+ max_offset = MAC_ADDR_MAX_MGMT_V4_WCOUNT;
+ break;
+ case 8: /* Mgmt IPv6 address */
+ max_index = MAC_ADDR_MAX_MGMT_V6_ENTRIES;
+ max_offset = MAC_ADDR_MAX_MGMT_V6_WCOUNT;
+ break;
+ case 9: /* Mgmt TCP/UDP Dest port */
+ max_index = MAC_ADDR_MAX_MGMT_TU_DP_ENTRIES;
+ max_offset = MAC_ADDR_MAX_MGMT_TU_DP_WCOUNT;
+ break;
+ default:
+ printk(KERN_ERR"Bad type!!! 0x%08x\n", type);
+ max_index = 0;
+ max_offset = 0;
+ break;
+ }
+ for (index = 0; index < max_index; index++) {
+ for (offset = 0; offset < max_offset; offset++) {
+ val = initial_val
+ | (type << MAC_ADDR_TYPE_SHIFT)
+ | (index << MAC_ADDR_IDX_SHIFT)
+ | (offset);
+ ql_write32(qdev, MAC_ADDR_IDX, val);
+ result_index = 0;
+ while ((result_index & MAC_ADDR_MR) == 0) {
+ result_index = ql_read32(qdev,
+ MAC_ADDR_IDX);
+ }
+ result_data = ql_read32(qdev, MAC_ADDR_DATA);
+ *buf = result_index;
+ buf++;
+ *buf = result_data;
+ buf++;
+ }
+ }
+ }
+}
+
+static void ql_get_sem_registers(struct ql_adapter *qdev, u32 *buf)
+{
+ u32 func_num, reg, reg_val;
+ int status;
+
+ for (func_num = 0; func_num < MAX_SEMAPHORE_FUNCTIONS ; func_num++) {
+ reg = MPI_NIC_REG_BLOCK
+ | (func_num << MPI_NIC_FUNCTION_SHIFT)
+ | (SEM / 4);
+ status = ql_read_mpi_reg(qdev, reg, &reg_val);
+ *buf = reg_val;
+ /* if the read failed then dead fill the element. */
+ if (!status)
+ *buf = 0xdeadbeef;
+ buf++;
+ }
+}
+
/* Create a coredump segment header */
static void ql_build_coredump_seg_header(
struct mpi_coredump_segment_header *seg_hdr,
@@ -103,6 +723,526 @@ static void ql_build_coredump_seg_header(
memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
}
+/*
+ * This function should be called when a coredump / probedump
+ * is to be extracted from the HBA. It is assumed there is a
+ * qdev structure that contains the base address of the register
+ * space for this function as well as a coredump structure that
+ * will contain the dump.
+ */
+int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
+{
+ int status;
+ int i;
+
+ if (!mpi_coredump) {
+ netif_err(qdev, drv, qdev->ndev, "No memory available.\n");
+ return -ENOMEM;
+ }
+
+ /* Try to get the spinlock, but dont worry if
+ * it isn't available. If the firmware died it
+ * might be holding the sem.
+ */
+ ql_sem_spinlock(qdev, SEM_PROC_REG_MASK);
+
+ status = ql_pause_mpi_risc(qdev);
+ if (status) {
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed RISC pause. Status = 0x%.08x\n", status);
+ goto err;
+ }
+
+ /* Insert the global header */
+ memset(&(mpi_coredump->mpi_global_header), 0,
+ sizeof(struct mpi_coredump_global_header));
+ mpi_coredump->mpi_global_header.cookie = MPI_COREDUMP_COOKIE;
+ mpi_coredump->mpi_global_header.headerSize =
+ sizeof(struct mpi_coredump_global_header);
+ mpi_coredump->mpi_global_header.imageSize =
+ sizeof(struct ql_mpi_coredump);
+ memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
+ sizeof(mpi_coredump->mpi_global_header.idString));
+
+ /* Get generic NIC reg dump */
+ ql_build_coredump_seg_header(&mpi_coredump->nic_regs_seg_hdr,
+ NIC1_CONTROL_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->nic_regs), "NIC1 Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->nic2_regs_seg_hdr,
+ NIC2_CONTROL_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->nic2_regs), "NIC2 Registers");
+
+ /* Get XGMac registers. (Segment 18, Rev C. step 21) */
+ ql_build_coredump_seg_header(&mpi_coredump->xgmac1_seg_hdr,
+ NIC1_XGMAC_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->xgmac1), "NIC1 XGMac Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xgmac2_seg_hdr,
+ NIC2_XGMAC_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->xgmac2), "NIC2 XGMac Registers");
+
+ if (qdev->func & 1) {
+ /* Odd means our function is NIC 2 */
+ for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++)
+ mpi_coredump->nic2_regs[i] =
+ ql_read32(qdev, i * sizeof(u32));
+
+ for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++)
+ mpi_coredump->nic_regs[i] =
+ ql_read_other_func_reg(qdev, (i * sizeof(u32)) / 4);
+
+ ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac2[0], 0);
+ ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac1[0], 1);
+ } else {
+ /* Even means our function is NIC 1 */
+ for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++)
+ mpi_coredump->nic_regs[i] =
+ ql_read32(qdev, i * sizeof(u32));
+ for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++)
+ mpi_coredump->nic2_regs[i] =
+ ql_read_other_func_reg(qdev, (i * sizeof(u32)) / 4);
+
+ ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac1[0], 0);
+ ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac2[0], 1);
+ }
+
+ /* Rev C. Step 20a */
+ ql_build_coredump_seg_header(&mpi_coredump->xaui_an_hdr,
+ XAUI_AN_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xaui_an),
+ "XAUI AN Registers");
+
+ /* Rev C. Step 20b */
+ ql_build_coredump_seg_header(&mpi_coredump->xaui_hss_pcs_hdr,
+ XAUI_HSS_PCS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xaui_hss_pcs),
+ "XAUI HSS PCS Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi_an_hdr, XFI_AN_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xfi_an),
+ "XFI AN Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi_train_hdr,
+ XFI_TRAIN_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xfi_train),
+ "XFI TRAIN Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pcs_hdr,
+ XFI_HSS_PCS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xfi_hss_pcs),
+ "XFI HSS PCS Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_tx_hdr,
+ XFI_HSS_TX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xfi_hss_tx),
+ "XFI HSS TX Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_rx_hdr,
+ XFI_HSS_RX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xfi_hss_rx),
+ "XFI HSS RX Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pll_hdr,
+ XFI_HSS_PLL_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xfi_hss_pll),
+ "XFI HSS PLL Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xaui2_an_hdr,
+ XAUI2_AN_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xaui_an),
+ "XAUI2 AN Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xaui2_hss_pcs_hdr,
+ XAUI2_HSS_PCS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xaui_hss_pcs),
+ "XAUI2 HSS PCS Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi2_an_hdr,
+ XFI2_AN_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xfi_an),
+ "XFI2 AN Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi2_train_hdr,
+ XFI2_TRAIN_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xfi_train),
+ "XFI2 TRAIN Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_pcs_hdr,
+ XFI2_HSS_PCS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xfi_hss_pcs),
+ "XFI2 HSS PCS Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_tx_hdr,
+ XFI2_HSS_TX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xfi_hss_tx),
+ "XFI2 HSS TX Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_rx_hdr,
+ XFI2_HSS_RX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xfi_hss_rx),
+ "XFI2 HSS RX Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_pll_hdr,
+ XFI2_HSS_PLL_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xfi_hss_pll),
+ "XFI2 HSS PLL Registers");
+
+ status = ql_get_serdes_regs(qdev, mpi_coredump);
+ if (status) {
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed Dump of Serdes Registers. Status = 0x%.08x\n",
+ status);
+ goto err;
+ }
+
+ ql_build_coredump_seg_header(&mpi_coredump->core_regs_seg_hdr,
+ CORE_SEG_NUM,
+ sizeof(mpi_coredump->core_regs_seg_hdr) +
+ sizeof(mpi_coredump->mpi_core_regs) +
+ sizeof(mpi_coredump->mpi_core_sh_regs),
+ "Core Registers");
+
+ /* Get the MPI Core Registers */
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->mpi_core_regs[0],
+ MPI_CORE_REGS_ADDR, MPI_CORE_REGS_CNT);
+ if (status)
+ goto err;
+ /* Get the 16 MPI shadow registers */
+ status = ql_get_mpi_shadow_regs(qdev,
+ &mpi_coredump->mpi_core_sh_regs[0]);
+ if (status)
+ goto err;
+
+ /* Get the Test Logic Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->test_logic_regs_seg_hdr,
+ TEST_LOGIC_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->test_logic_regs),
+ "Test Logic Regs");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->test_logic_regs[0],
+ TEST_REGS_ADDR, TEST_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the RMII Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->rmii_regs_seg_hdr,
+ RMII_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->rmii_regs),
+ "RMII Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->rmii_regs[0],
+ RMII_REGS_ADDR, RMII_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the FCMAC1 Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->fcmac1_regs_seg_hdr,
+ FCMAC1_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->fcmac1_regs),
+ "FCMAC1 Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->fcmac1_regs[0],
+ FCMAC1_REGS_ADDR, FCMAC_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the FCMAC2 Registers */
+
+ ql_build_coredump_seg_header(&mpi_coredump->fcmac2_regs_seg_hdr,
+ FCMAC2_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->fcmac2_regs),
+ "FCMAC2 Registers");
+
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->fcmac2_regs[0],
+ FCMAC2_REGS_ADDR, FCMAC_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the FC1 MBX Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->fc1_mbx_regs_seg_hdr,
+ FC1_MBOX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->fc1_mbx_regs),
+ "FC1 MBox Regs");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->fc1_mbx_regs[0],
+ FC1_MBX_REGS_ADDR, FC_MBX_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the IDE Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->ide_regs_seg_hdr,
+ IDE_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->ide_regs),
+ "IDE Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->ide_regs[0],
+ IDE_REGS_ADDR, IDE_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the NIC1 MBX Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->nic1_mbx_regs_seg_hdr,
+ NIC1_MBOX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->nic1_mbx_regs),
+ "NIC1 MBox Regs");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->nic1_mbx_regs[0],
+ NIC1_MBX_REGS_ADDR, NIC_MBX_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the SMBus Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->smbus_regs_seg_hdr,
+ SMBUS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->smbus_regs),
+ "SMBus Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->smbus_regs[0],
+ SMBUS_REGS_ADDR, SMBUS_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the FC2 MBX Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->fc2_mbx_regs_seg_hdr,
+ FC2_MBOX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->fc2_mbx_regs),
+ "FC2 MBox Regs");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->fc2_mbx_regs[0],
+ FC2_MBX_REGS_ADDR, FC_MBX_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the NIC2 MBX Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->nic2_mbx_regs_seg_hdr,
+ NIC2_MBOX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->nic2_mbx_regs),
+ "NIC2 MBox Regs");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->nic2_mbx_regs[0],
+ NIC2_MBX_REGS_ADDR, NIC_MBX_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the I2C Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->i2c_regs_seg_hdr,
+ I2C_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->i2c_regs),
+ "I2C Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->i2c_regs[0],
+ I2C_REGS_ADDR, I2C_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the MEMC Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->memc_regs_seg_hdr,
+ MEMC_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->memc_regs),
+ "MEMC Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->memc_regs[0],
+ MEMC_REGS_ADDR, MEMC_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the PBus Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->pbus_regs_seg_hdr,
+ PBUS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->pbus_regs),
+ "PBUS Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->pbus_regs[0],
+ PBUS_REGS_ADDR, PBUS_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the MDE Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->mde_regs_seg_hdr,
+ MDE_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->mde_regs),
+ "MDE Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->mde_regs[0],
+ MDE_REGS_ADDR, MDE_REGS_CNT);
+ if (status)
+ goto err;
+
+ ql_build_coredump_seg_header(&mpi_coredump->misc_nic_seg_hdr,
+ MISC_NIC_INFO_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->misc_nic_info),
+ "MISC NIC INFO");
+ mpi_coredump->misc_nic_info.rx_ring_count = qdev->rx_ring_count;
+ mpi_coredump->misc_nic_info.tx_ring_count = qdev->tx_ring_count;
+ mpi_coredump->misc_nic_info.intr_count = qdev->intr_count;
+ mpi_coredump->misc_nic_info.function = qdev->func;
+
+ /* Segment 31 */
+ /* Get indexed register values. */
+ ql_build_coredump_seg_header(&mpi_coredump->intr_states_seg_hdr,
+ INTR_STATES_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->intr_states),
+ "INTR States");
+ ql_get_intr_states(qdev, &mpi_coredump->intr_states[0]);
+
+ ql_build_coredump_seg_header(&mpi_coredump->cam_entries_seg_hdr,
+ CAM_ENTRIES_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->cam_entries),
+ "CAM Entries");
+ status = ql_get_cam_entries(qdev, &mpi_coredump->cam_entries[0]);
+ if (status)
+ goto err;
+
+ ql_build_coredump_seg_header(&mpi_coredump->nic_routing_words_seg_hdr,
+ ROUTING_WORDS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->nic_routing_words),
+ "Routing Words");
+ status = ql_get_routing_entries(qdev,
+ &mpi_coredump->nic_routing_words[0]);
+ if (status)
+ goto err;
+
+ /* Segment 34 (Rev C. step 23) */
+ ql_build_coredump_seg_header(&mpi_coredump->ets_seg_hdr,
+ ETS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->ets),
+ "ETS Registers");
+ status = ql_get_ets_regs(qdev, &mpi_coredump->ets[0]);
+ if (status)
+ goto err;
+
+ ql_build_coredump_seg_header(&mpi_coredump->probe_dump_seg_hdr,
+ PROBE_DUMP_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->probe_dump),
+ "Probe Dump");
+ ql_get_probe_dump(qdev, &mpi_coredump->probe_dump[0]);
+
+ ql_build_coredump_seg_header(&mpi_coredump->routing_reg_seg_hdr,
+ ROUTING_INDEX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->routing_regs),
+ "Routing Regs");
+ status = ql_get_routing_index_registers(qdev,
+ &mpi_coredump->routing_regs[0]);
+ if (status)
+ goto err;
+
+ ql_build_coredump_seg_header(&mpi_coredump->mac_prot_reg_seg_hdr,
+ MAC_PROTOCOL_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->mac_prot_regs),
+ "MAC Prot Regs");
+ ql_get_mac_protocol_registers(qdev, &mpi_coredump->mac_prot_regs[0]);
+
+ /* Get the semaphore registers for all 5 functions */
+ ql_build_coredump_seg_header(&mpi_coredump->sem_regs_seg_hdr,
+ SEM_REGS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->sem_regs), "Sem Registers");
+
+ ql_get_sem_registers(qdev, &mpi_coredump->sem_regs[0]);
+
+ /* Prevent the mpi restarting while we dump the memory.*/
+ ql_write_mpi_reg(qdev, MPI_TEST_FUNC_RST_STS, MPI_TEST_FUNC_RST_FRC);
+
+ /* clear the pause */
+ status = ql_unpause_mpi_risc(qdev);
+ if (status) {
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed RISC unpause. Status = 0x%.08x\n", status);
+ goto err;
+ }
+
+ /* Reset the RISC so we can dump RAM */
+ status = ql_hard_reset_mpi_risc(qdev);
+ if (status) {
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed RISC reset. Status = 0x%.08x\n", status);
+ goto err;
+ }
+
+ ql_build_coredump_seg_header(&mpi_coredump->code_ram_seg_hdr,
+ WCS_RAM_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->code_ram),
+ "WCS RAM");
+ status = ql_dump_risc_ram_area(qdev, &mpi_coredump->code_ram[0],
+ CODE_RAM_ADDR, CODE_RAM_CNT);
+ if (status) {
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed Dump of CODE RAM. Status = 0x%.08x\n",
+ status);
+ goto err;
+ }
+
+ /* Insert the segment header */
+ ql_build_coredump_seg_header(&mpi_coredump->memc_ram_seg_hdr,
+ MEMC_RAM_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->memc_ram),
+ "MEMC RAM");
+ status = ql_dump_risc_ram_area(qdev, &mpi_coredump->memc_ram[0],
+ MEMC_RAM_ADDR, MEMC_RAM_CNT);
+ if (status) {
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed Dump of MEMC RAM. Status = 0x%.08x\n",
+ status);
+ goto err;
+ }
+err:
+ ql_sem_unlock(qdev, SEM_PROC_REG_MASK); /* does flush too */
+ return status;
+
+}
+
+static void ql_get_core_dump(struct ql_adapter *qdev)
+{
+ if (!ql_own_firmware(qdev)) {
+ netif_err(qdev, drv, qdev->ndev, "Don't own firmware!\n");
+ return;
+ }
+
+ if (!netif_running(qdev->ndev)) {
+ netif_err(qdev, ifup, qdev->ndev,
+ "Force Coredump can only be done from interface that is up.\n");
+ return;
+ }
+
+ if (ql_mb_sys_err(qdev)) {
+ netif_err(qdev, ifup, qdev->ndev,
+ "Fail force coredump with ql_mb_sys_err().\n");
+ return;
+ }
+}
+
void ql_gen_reg_dump(struct ql_adapter *qdev,
struct ql_reg_dump *mpi_coredump)
{
@@ -178,6 +1318,37 @@ void ql_gen_reg_dump(struct ql_adapter *qdev,
status = ql_get_ets_regs(qdev, &mpi_coredump->ets[0]);
if (status)
return;
+
+ if (test_bit(QL_FRC_COREDUMP, &qdev->flags))
+ ql_get_core_dump(qdev);
+}
+
+/* Coredump to messages log file using separate worker thread */
+void ql_mpi_core_to_log(struct work_struct *work)
+{
+ struct ql_adapter *qdev =
+ container_of(work, struct ql_adapter, mpi_core_to_log.work);
+ u32 *tmp, count;
+ int i;
+
+ count = sizeof(struct ql_mpi_coredump) / sizeof(u32);
+ tmp = (u32 *)qdev->mpi_coredump;
+ netif_printk(qdev, drv, KERN_DEBUG, qdev->ndev,
+ "Core is dumping to log file!\n");
+
+ for (i = 0; i < count; i += 8) {
+ printk(KERN_ERR "%.08x: %.08x %.08x %.08x %.08x %.08x "
+ "%.08x %.08x %.08x \n", i,
+ tmp[i + 0],
+ tmp[i + 1],
+ tmp[i + 2],
+ tmp[i + 3],
+ tmp[i + 4],
+ tmp[i + 5],
+ tmp[i + 6],
+ tmp[i + 7]);
+ msleep(5);
+ }
}
#ifdef QL_REG_DUMP
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index 058fa0a48c6f..7dbff87480dc 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -67,8 +67,8 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev)
status = ql_write_cfg(qdev, cqicb, sizeof(*cqicb),
CFG_LCQ, rx_ring->cq_id);
if (status) {
- QPRINTK(qdev, IFUP, ERR,
- "Failed to load CQICB.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to load CQICB.\n");
goto exit;
}
}
@@ -89,8 +89,8 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev)
status = ql_write_cfg(qdev, cqicb, sizeof(*cqicb),
CFG_LCQ, rx_ring->cq_id);
if (status) {
- QPRINTK(qdev, IFUP, ERR,
- "Failed to load CQICB.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to load CQICB.\n");
goto exit;
}
}
@@ -107,8 +107,8 @@ static void ql_update_stats(struct ql_adapter *qdev)
spin_lock(&qdev->stats_lock);
if (ql_sem_spinlock(qdev, qdev->xg_sem_mask)) {
- QPRINTK(qdev, DRV, ERR,
- "Couldn't get xgmac sem.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Couldn't get xgmac sem.\n");
goto quit;
}
/*
@@ -116,8 +116,9 @@ static void ql_update_stats(struct ql_adapter *qdev)
*/
for (i = 0x200; i < 0x280; i += 8) {
if (ql_read_xgmac_reg64(qdev, i, &data)) {
- QPRINTK(qdev, DRV, ERR,
- "Error reading status register 0x%.04x.\n", i);
+ netif_err(qdev, drv, qdev->ndev,
+ "Error reading status register 0x%.04x.\n",
+ i);
goto end;
} else
*iter = data;
@@ -129,8 +130,9 @@ static void ql_update_stats(struct ql_adapter *qdev)
*/
for (i = 0x300; i < 0x3d0; i += 8) {
if (ql_read_xgmac_reg64(qdev, i, &data)) {
- QPRINTK(qdev, DRV, ERR,
- "Error reading status register 0x%.04x.\n", i);
+ netif_err(qdev, drv, qdev->ndev,
+ "Error reading status register 0x%.04x.\n",
+ i);
goto end;
} else
*iter = data;
@@ -142,8 +144,9 @@ static void ql_update_stats(struct ql_adapter *qdev)
*/
for (i = 0x500; i < 0x540; i += 8) {
if (ql_read_xgmac_reg64(qdev, i, &data)) {
- QPRINTK(qdev, DRV, ERR,
- "Error reading status register 0x%.04x.\n", i);
+ netif_err(qdev, drv, qdev->ndev,
+ "Error reading status register 0x%.04x.\n",
+ i);
goto end;
} else
*iter = data;
@@ -155,8 +158,9 @@ static void ql_update_stats(struct ql_adapter *qdev)
*/
for (i = 0x568; i < 0x5a8; i += 8) {
if (ql_read_xgmac_reg64(qdev, i, &data)) {
- QPRINTK(qdev, DRV, ERR,
- "Error reading status register 0x%.04x.\n", i);
+ netif_err(qdev, drv, qdev->ndev,
+ "Error reading status register 0x%.04x.\n",
+ i);
goto end;
} else
*iter = data;
@@ -167,8 +171,8 @@ static void ql_update_stats(struct ql_adapter *qdev)
* Get RX NIC FIFO DROP statistics.
*/
if (ql_read_xgmac_reg64(qdev, 0x5b8, &data)) {
- QPRINTK(qdev, DRV, ERR,
- "Error reading status register 0x%.04x.\n", i);
+ netif_err(qdev, drv, qdev->ndev,
+ "Error reading status register 0x%.04x.\n", i);
goto end;
} else
*iter = data;
@@ -396,14 +400,13 @@ static int ql_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
return -EINVAL;
qdev->wol = wol->wolopts;
- QPRINTK(qdev, DRV, INFO, "Set wol option 0x%x on %s\n",
- qdev->wol, ndev->name);
+ netif_info(qdev, drv, qdev->ndev, "Set wol option 0x%x\n", qdev->wol);
if (!qdev->wol) {
u32 wol = 0;
status = ql_mb_wol_mode(qdev, wol);
- QPRINTK(qdev, DRV, ERR, "WOL %s (wol code 0x%x) on %s\n",
- (status == 0) ? "cleared sucessfully" : "clear failed",
- wol, qdev->ndev->name);
+ netif_err(qdev, drv, qdev->ndev, "WOL %s (wol code 0x%x)\n",
+ status == 0 ? "cleared successfully" : "clear failed",
+ wol);
}
return 0;
@@ -500,7 +503,8 @@ static int ql_run_loopback_test(struct ql_adapter *qdev)
return -EPIPE;
atomic_inc(&qdev->lb_count);
}
-
+ /* Give queue time to settle before testing results. */
+ msleep(2);
ql_clean_lb_rx_ring(&qdev->rx_ring[0], 128);
return atomic_read(&qdev->lb_count) ? -EIO : 0;
}
@@ -533,9 +537,13 @@ static void ql_self_test(struct net_device *ndev,
data[0] = 0;
}
clear_bit(QL_SELFTEST, &qdev->flags);
+ /* Give link time to come up after
+ * port configuration changes.
+ */
+ msleep_interruptible(4 * 1000);
} else {
- QPRINTK(qdev, DRV, ERR,
- "%s: is down, Loopback test will fail.\n", ndev->name);
+ netif_err(qdev, drv, qdev->ndev,
+ "is down, Loopback test will fail.\n");
eth_test->flags |= ETH_TEST_FL_FAILED;
}
}
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 707b391afa02..fd34f266c0a8 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -73,7 +73,19 @@ static int qlge_irq_type = MSIX_IRQ;
module_param(qlge_irq_type, int, MSIX_IRQ);
MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy.");
-static struct pci_device_id qlge_pci_tbl[] __devinitdata = {
+static int qlge_mpi_coredump;
+module_param(qlge_mpi_coredump, int, 0);
+MODULE_PARM_DESC(qlge_mpi_coredump,
+ "Option to enable MPI firmware dump. "
+ "Default is OFF - Do Not allocate memory. ");
+
+static int qlge_force_coredump;
+module_param(qlge_force_coredump, int, 0);
+MODULE_PARM_DESC(qlge_force_coredump,
+ "Option to allow force of firmware core dump. "
+ "Default is OFF - Do not allow.");
+
+static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)},
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)},
/* required last entry */
@@ -116,7 +128,7 @@ static int ql_sem_trylock(struct ql_adapter *qdev, u32 sem_mask)
sem_bits = SEM_SET << SEM_PROC_REG_SHIFT;
break;
default:
- QPRINTK(qdev, PROBE, ALERT, "Bad Semaphore mask!.\n");
+ netif_alert(qdev, probe, qdev->ndev, "bad Semaphore mask!.\n");
return -EINVAL;
}
@@ -156,17 +168,17 @@ int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 err_bit)
/* check for errors */
if (temp & err_bit) {
- QPRINTK(qdev, PROBE, ALERT,
- "register 0x%.08x access error, value = 0x%.08x!.\n",
- reg, temp);
+ netif_alert(qdev, probe, qdev->ndev,
+ "register 0x%.08x access error, value = 0x%.08x!.\n",
+ reg, temp);
return -EIO;
} else if (temp & bit)
return 0;
udelay(UDELAY_DELAY);
count--;
}
- QPRINTK(qdev, PROBE, ALERT,
- "Timed out waiting for reg %x to come ready.\n", reg);
+ netif_alert(qdev, probe, qdev->ndev,
+ "Timed out waiting for reg %x to come ready.\n", reg);
return -ETIMEDOUT;
}
@@ -209,7 +221,7 @@ int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
map = pci_map_single(qdev->pdev, ptr, size, direction);
if (pci_dma_mapping_error(qdev->pdev, map)) {
- QPRINTK(qdev, IFUP, ERR, "Couldn't map DMA area.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Couldn't map DMA area.\n");
return -ENOMEM;
}
@@ -219,8 +231,8 @@ int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
status = ql_wait_cfg(qdev, bit);
if (status) {
- QPRINTK(qdev, IFUP, ERR,
- "Timed out waiting for CFG to come ready.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Timed out waiting for CFG to come ready.\n");
goto exit;
}
@@ -301,8 +313,8 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
case MAC_ADDR_TYPE_VLAN:
case MAC_ADDR_TYPE_MULTI_FLTR:
default:
- QPRINTK(qdev, IFUP, CRIT,
- "Address type %d not yet supported.\n", type);
+ netif_crit(qdev, ifup, qdev->ndev,
+ "Address type %d not yet supported.\n", type);
status = -EPERM;
}
exit:
@@ -359,12 +371,11 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
(addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) |
(addr[5]);
- QPRINTK(qdev, IFUP, DEBUG,
- "Adding %s address %pM"
- " at index %d in the CAM.\n",
- ((type ==
- MAC_ADDR_TYPE_MULTI_MAC) ? "MULTICAST" :
- "UNICAST"), addr, index);
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "Adding %s address %pM at index %d in the CAM.\n",
+ type == MAC_ADDR_TYPE_MULTI_MAC ?
+ "MULTICAST" : "UNICAST",
+ addr, index);
status =
ql_wait_reg_rdy(qdev,
@@ -414,9 +425,11 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
* addressing. It's either MAC_ADDR_E on or off.
* That's bit-27 we're talking about.
*/
- QPRINTK(qdev, IFUP, INFO, "%s VLAN ID %d %s the CAM.\n",
- (enable_bit ? "Adding" : "Removing"),
- index, (enable_bit ? "to" : "from"));
+ netif_info(qdev, ifup, qdev->ndev,
+ "%s VLAN ID %d %s the CAM.\n",
+ enable_bit ? "Adding" : "Removing",
+ index,
+ enable_bit ? "to" : "from");
status =
ql_wait_reg_rdy(qdev,
@@ -431,8 +444,8 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
}
case MAC_ADDR_TYPE_MULTI_FLTR:
default:
- QPRINTK(qdev, IFUP, CRIT,
- "Address type %d not yet supported.\n", type);
+ netif_crit(qdev, ifup, qdev->ndev,
+ "Address type %d not yet supported.\n", type);
status = -EPERM;
}
exit:
@@ -450,17 +463,14 @@ static int ql_set_mac_addr(struct ql_adapter *qdev, int set)
char *addr;
if (set) {
- addr = &qdev->ndev->dev_addr[0];
- QPRINTK(qdev, IFUP, DEBUG,
- "Set Mac addr %02x:%02x:%02x:%02x:%02x:%02x\n",
- addr[0], addr[1], addr[2], addr[3],
- addr[4], addr[5]);
+ addr = &qdev->current_mac_addr[0];
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "Set Mac addr %pM\n", addr);
} else {
memset(zero_mac_addr, 0, ETH_ALEN);
addr = &zero_mac_addr[0];
- QPRINTK(qdev, IFUP, DEBUG,
- "Clearing MAC address on %s\n",
- qdev->ndev->name);
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "Clearing MAC address\n");
}
status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
if (status)
@@ -469,23 +479,21 @@ static int ql_set_mac_addr(struct ql_adapter *qdev, int set)
MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ);
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
if (status)
- QPRINTK(qdev, IFUP, ERR, "Failed to init mac "
- "address.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to init mac address.\n");
return status;
}
void ql_link_on(struct ql_adapter *qdev)
{
- QPRINTK(qdev, LINK, ERR, "%s: Link is up.\n",
- qdev->ndev->name);
+ netif_err(qdev, link, qdev->ndev, "Link is up.\n");
netif_carrier_on(qdev->ndev);
ql_set_mac_addr(qdev, 1);
}
void ql_link_off(struct ql_adapter *qdev)
{
- QPRINTK(qdev, LINK, ERR, "%s: Link is down.\n",
- qdev->ndev->name);
+ netif_err(qdev, link, qdev->ndev, "Link is down.\n");
netif_carrier_off(qdev->ndev);
ql_set_mac_addr(qdev, 0);
}
@@ -522,27 +530,27 @@ static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask,
int status = -EINVAL; /* Return error if no mask match. */
u32 value = 0;
- QPRINTK(qdev, IFUP, DEBUG,
- "%s %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s mask %s the routing reg.\n",
- (enable ? "Adding" : "Removing"),
- ((index == RT_IDX_ALL_ERR_SLOT) ? "MAC ERROR/ALL ERROR" : ""),
- ((index == RT_IDX_IP_CSUM_ERR_SLOT) ? "IP CSUM ERROR" : ""),
- ((index ==
- RT_IDX_TCP_UDP_CSUM_ERR_SLOT) ? "TCP/UDP CSUM ERROR" : ""),
- ((index == RT_IDX_BCAST_SLOT) ? "BROADCAST" : ""),
- ((index == RT_IDX_MCAST_MATCH_SLOT) ? "MULTICAST MATCH" : ""),
- ((index == RT_IDX_ALLMULTI_SLOT) ? "ALL MULTICAST MATCH" : ""),
- ((index == RT_IDX_UNUSED6_SLOT) ? "UNUSED6" : ""),
- ((index == RT_IDX_UNUSED7_SLOT) ? "UNUSED7" : ""),
- ((index == RT_IDX_RSS_MATCH_SLOT) ? "RSS ALL/IPV4 MATCH" : ""),
- ((index == RT_IDX_RSS_IPV6_SLOT) ? "RSS IPV6" : ""),
- ((index == RT_IDX_RSS_TCP4_SLOT) ? "RSS TCP4" : ""),
- ((index == RT_IDX_RSS_TCP6_SLOT) ? "RSS TCP6" : ""),
- ((index == RT_IDX_CAM_HIT_SLOT) ? "CAM HIT" : ""),
- ((index == RT_IDX_UNUSED013) ? "UNUSED13" : ""),
- ((index == RT_IDX_UNUSED014) ? "UNUSED14" : ""),
- ((index == RT_IDX_PROMISCUOUS_SLOT) ? "PROMISCUOUS" : ""),
- (enable ? "to" : "from"));
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "%s %s mask %s the routing reg.\n",
+ enable ? "Adding" : "Removing",
+ index == RT_IDX_ALL_ERR_SLOT ? "MAC ERROR/ALL ERROR" :
+ index == RT_IDX_IP_CSUM_ERR_SLOT ? "IP CSUM ERROR" :
+ index == RT_IDX_TCP_UDP_CSUM_ERR_SLOT ? "TCP/UDP CSUM ERROR" :
+ index == RT_IDX_BCAST_SLOT ? "BROADCAST" :
+ index == RT_IDX_MCAST_MATCH_SLOT ? "MULTICAST MATCH" :
+ index == RT_IDX_ALLMULTI_SLOT ? "ALL MULTICAST MATCH" :
+ index == RT_IDX_UNUSED6_SLOT ? "UNUSED6" :
+ index == RT_IDX_UNUSED7_SLOT ? "UNUSED7" :
+ index == RT_IDX_RSS_MATCH_SLOT ? "RSS ALL/IPV4 MATCH" :
+ index == RT_IDX_RSS_IPV6_SLOT ? "RSS IPV6" :
+ index == RT_IDX_RSS_TCP4_SLOT ? "RSS TCP4" :
+ index == RT_IDX_RSS_TCP6_SLOT ? "RSS TCP6" :
+ index == RT_IDX_CAM_HIT_SLOT ? "CAM HIT" :
+ index == RT_IDX_UNUSED013 ? "UNUSED13" :
+ index == RT_IDX_UNUSED014 ? "UNUSED14" :
+ index == RT_IDX_PROMISCUOUS_SLOT ? "PROMISCUOUS" :
+ "(Bad index != RT_IDX)",
+ enable ? "to" : "from");
switch (mask) {
case RT_IDX_CAM_HIT:
@@ -602,8 +610,8 @@ static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask,
break;
}
default:
- QPRINTK(qdev, IFUP, ERR, "Mask type %d not yet supported.\n",
- mask);
+ netif_err(qdev, ifup, qdev->ndev,
+ "Mask type %d not yet supported.\n", mask);
status = -EPERM;
goto exit;
}
@@ -709,7 +717,7 @@ static int ql_validate_flash(struct ql_adapter *qdev, u32 size, const char *str)
status = strncmp((char *)&qdev->flash, str, 4);
if (status) {
- QPRINTK(qdev, IFUP, ERR, "Invalid flash signature.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Invalid flash signature.\n");
return status;
}
@@ -717,8 +725,8 @@ static int ql_validate_flash(struct ql_adapter *qdev, u32 size, const char *str)
csum += le16_to_cpu(*flash++);
if (csum)
- QPRINTK(qdev, IFUP, ERR,
- "Invalid flash checksum, csum = 0x%.04x.\n", csum);
+ netif_err(qdev, ifup, qdev->ndev,
+ "Invalid flash checksum, csum = 0x%.04x.\n", csum);
return csum;
}
@@ -770,7 +778,8 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev)
for (i = 0; i < size; i++, p++) {
status = ql_read_flash_word(qdev, i+offset, p);
if (status) {
- QPRINTK(qdev, IFUP, ERR, "Error reading flash.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Error reading flash.\n");
goto exit;
}
}
@@ -779,7 +788,7 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev)
sizeof(struct flash_params_8000) / sizeof(u16),
"8000");
if (status) {
- QPRINTK(qdev, IFUP, ERR, "Invalid flash.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Invalid flash.\n");
status = -EINVAL;
goto exit;
}
@@ -797,7 +806,7 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev)
qdev->ndev->addr_len);
if (!is_valid_ether_addr(mac_addr)) {
- QPRINTK(qdev, IFUP, ERR, "Invalid MAC address.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Invalid MAC address.\n");
status = -EINVAL;
goto exit;
}
@@ -831,7 +840,8 @@ static int ql_get_8012_flash_params(struct ql_adapter *qdev)
for (i = 0; i < size; i++, p++) {
status = ql_read_flash_word(qdev, i+offset, p);
if (status) {
- QPRINTK(qdev, IFUP, ERR, "Error reading flash.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Error reading flash.\n");
goto exit;
}
@@ -841,7 +851,7 @@ static int ql_get_8012_flash_params(struct ql_adapter *qdev)
sizeof(struct flash_params_8012) / sizeof(u16),
"8012");
if (status) {
- QPRINTK(qdev, IFUP, ERR, "Invalid flash.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Invalid flash.\n");
status = -EINVAL;
goto exit;
}
@@ -959,17 +969,17 @@ static int ql_8012_port_initialize(struct ql_adapter *qdev)
/* Another function has the semaphore, so
* wait for the port init bit to come ready.
*/
- QPRINTK(qdev, LINK, INFO,
- "Another function has the semaphore, so wait for the port init bit to come ready.\n");
+ netif_info(qdev, link, qdev->ndev,
+ "Another function has the semaphore, so wait for the port init bit to come ready.\n");
status = ql_wait_reg_rdy(qdev, STS, qdev->port_init, 0);
if (status) {
- QPRINTK(qdev, LINK, CRIT,
- "Port initialize timed out.\n");
+ netif_crit(qdev, link, qdev->ndev,
+ "Port initialize timed out.\n");
}
return status;
}
- QPRINTK(qdev, LINK, INFO, "Got xgmac semaphore!.\n");
+ netif_info(qdev, link, qdev->ndev, "Got xgmac semaphore!.\n");
/* Set the core reset. */
status = ql_read_xgmac_reg(qdev, GLOBAL_CFG, &data);
if (status)
@@ -1099,8 +1109,8 @@ static int ql_get_next_chunk(struct ql_adapter *qdev, struct rx_ring *rx_ring,
GFP_ATOMIC,
qdev->lbq_buf_order);
if (unlikely(!rx_ring->pg_chunk.page)) {
- QPRINTK(qdev, DRV, ERR,
- "page allocation failed.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "page allocation failed.\n");
return -ENOMEM;
}
rx_ring->pg_chunk.offset = 0;
@@ -1110,8 +1120,8 @@ static int ql_get_next_chunk(struct ql_adapter *qdev, struct rx_ring *rx_ring,
if (pci_dma_mapping_error(qdev->pdev, map)) {
__free_pages(rx_ring->pg_chunk.page,
qdev->lbq_buf_order);
- QPRINTK(qdev, DRV, ERR,
- "PCI mapping failed.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "PCI mapping failed.\n");
return -ENOMEM;
}
rx_ring->pg_chunk.map = map;
@@ -1148,15 +1158,15 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
while (rx_ring->lbq_free_cnt > 32) {
for (i = 0; i < 16; i++) {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "lbq: try cleaning clean_idx = %d.\n",
- clean_idx);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "lbq: try cleaning clean_idx = %d.\n",
+ clean_idx);
lbq_desc = &rx_ring->lbq[clean_idx];
if (ql_get_next_chunk(qdev, rx_ring, lbq_desc)) {
- QPRINTK(qdev, IFUP, ERR,
- "Could not get a page chunk.\n");
- return;
- }
+ netif_err(qdev, ifup, qdev->ndev,
+ "Could not get a page chunk.\n");
+ return;
+ }
map = lbq_desc->p.pg_chunk.map +
lbq_desc->p.pg_chunk.offset;
@@ -1181,9 +1191,9 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
}
if (start_idx != clean_idx) {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "lbq: updating prod idx = %d.\n",
- rx_ring->lbq_prod_idx);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "lbq: updating prod idx = %d.\n",
+ rx_ring->lbq_prod_idx);
ql_write_db_reg(rx_ring->lbq_prod_idx,
rx_ring->lbq_prod_idx_db_reg);
}
@@ -1201,19 +1211,20 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
while (rx_ring->sbq_free_cnt > 16) {
for (i = 0; i < 16; i++) {
sbq_desc = &rx_ring->sbq[clean_idx];
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "sbq: try cleaning clean_idx = %d.\n",
- clean_idx);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "sbq: try cleaning clean_idx = %d.\n",
+ clean_idx);
if (sbq_desc->p.skb == NULL) {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "sbq: getting new skb for index %d.\n",
- sbq_desc->index);
+ netif_printk(qdev, rx_status, KERN_DEBUG,
+ qdev->ndev,
+ "sbq: getting new skb for index %d.\n",
+ sbq_desc->index);
sbq_desc->p.skb =
netdev_alloc_skb(qdev->ndev,
SMALL_BUFFER_SIZE);
if (sbq_desc->p.skb == NULL) {
- QPRINTK(qdev, PROBE, ERR,
- "Couldn't get an skb.\n");
+ netif_err(qdev, probe, qdev->ndev,
+ "Couldn't get an skb.\n");
rx_ring->sbq_clean_idx = clean_idx;
return;
}
@@ -1223,7 +1234,8 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
rx_ring->sbq_buf_size,
PCI_DMA_FROMDEVICE);
if (pci_dma_mapping_error(qdev->pdev, map)) {
- QPRINTK(qdev, IFUP, ERR, "PCI mapping failed.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "PCI mapping failed.\n");
rx_ring->sbq_clean_idx = clean_idx;
dev_kfree_skb_any(sbq_desc->p.skb);
sbq_desc->p.skb = NULL;
@@ -1247,9 +1259,9 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
}
if (start_idx != clean_idx) {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "sbq: updating prod idx = %d.\n",
- rx_ring->sbq_prod_idx);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "sbq: updating prod idx = %d.\n",
+ rx_ring->sbq_prod_idx);
ql_write_db_reg(rx_ring->sbq_prod_idx,
rx_ring->sbq_prod_idx_db_reg);
}
@@ -1281,8 +1293,9 @@ static void ql_unmap_send(struct ql_adapter *qdev,
* then its an OAL.
*/
if (i == 7) {
- QPRINTK(qdev, TX_DONE, DEBUG,
- "unmapping OAL area.\n");
+ netif_printk(qdev, tx_done, KERN_DEBUG,
+ qdev->ndev,
+ "unmapping OAL area.\n");
}
pci_unmap_single(qdev->pdev,
pci_unmap_addr(&tx_ring_desc->map[i],
@@ -1291,8 +1304,8 @@ static void ql_unmap_send(struct ql_adapter *qdev,
maplen),
PCI_DMA_TODEVICE);
} else {
- QPRINTK(qdev, TX_DONE, DEBUG, "unmapping frag %d.\n",
- i);
+ netif_printk(qdev, tx_done, KERN_DEBUG, qdev->ndev,
+ "unmapping frag %d.\n", i);
pci_unmap_page(qdev->pdev,
pci_unmap_addr(&tx_ring_desc->map[i],
mapaddr),
@@ -1317,7 +1330,8 @@ static int ql_map_send(struct ql_adapter *qdev,
int frag_cnt = skb_shinfo(skb)->nr_frags;
if (frag_cnt) {
- QPRINTK(qdev, TX_QUEUED, DEBUG, "frag_cnt = %d.\n", frag_cnt);
+ netif_printk(qdev, tx_queued, KERN_DEBUG, qdev->ndev,
+ "frag_cnt = %d.\n", frag_cnt);
}
/*
* Map the skb buffer first.
@@ -1326,8 +1340,8 @@ static int ql_map_send(struct ql_adapter *qdev,
err = pci_dma_mapping_error(qdev->pdev, map);
if (err) {
- QPRINTK(qdev, TX_QUEUED, ERR,
- "PCI mapping failed with error: %d\n", err);
+ netif_err(qdev, tx_queued, qdev->ndev,
+ "PCI mapping failed with error: %d\n", err);
return NETDEV_TX_BUSY;
}
@@ -1373,9 +1387,9 @@ static int ql_map_send(struct ql_adapter *qdev,
PCI_DMA_TODEVICE);
err = pci_dma_mapping_error(qdev->pdev, map);
if (err) {
- QPRINTK(qdev, TX_QUEUED, ERR,
- "PCI mapping outbound address list with error: %d\n",
- err);
+ netif_err(qdev, tx_queued, qdev->ndev,
+ "PCI mapping outbound address list with error: %d\n",
+ err);
goto map_error;
}
@@ -1403,9 +1417,9 @@ static int ql_map_send(struct ql_adapter *qdev,
err = pci_dma_mapping_error(qdev->pdev, map);
if (err) {
- QPRINTK(qdev, TX_QUEUED, ERR,
- "PCI mapping frags failed with error: %d.\n",
- err);
+ netif_err(qdev, tx_queued, qdev->ndev,
+ "PCI mapping frags failed with error: %d.\n",
+ err);
goto map_error;
}
@@ -1433,6 +1447,260 @@ map_error:
return NETDEV_TX_BUSY;
}
+/* Process an inbound completion from an rx ring. */
+static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev,
+ struct rx_ring *rx_ring,
+ struct ib_mac_iocb_rsp *ib_mac_rsp,
+ u32 length,
+ u16 vlan_id)
+{
+ struct sk_buff *skb;
+ struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
+ struct skb_frag_struct *rx_frag;
+ int nr_frags;
+ struct napi_struct *napi = &rx_ring->napi;
+
+ napi->dev = qdev->ndev;
+
+ skb = napi_get_frags(napi);
+ if (!skb) {
+ netif_err(qdev, drv, qdev->ndev,
+ "Couldn't get an skb, exiting.\n");
+ rx_ring->rx_dropped++;
+ put_page(lbq_desc->p.pg_chunk.page);
+ return;
+ }
+ prefetch(lbq_desc->p.pg_chunk.va);
+ rx_frag = skb_shinfo(skb)->frags;
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ rx_frag += nr_frags;
+ rx_frag->page = lbq_desc->p.pg_chunk.page;
+ rx_frag->page_offset = lbq_desc->p.pg_chunk.offset;
+ rx_frag->size = length;
+
+ skb->len += length;
+ skb->data_len += length;
+ skb->truesize += length;
+ skb_shinfo(skb)->nr_frags++;
+
+ rx_ring->rx_packets++;
+ rx_ring->rx_bytes += length;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb_record_rx_queue(skb, rx_ring->cq_id);
+ if (qdev->vlgrp && (vlan_id != 0xffff))
+ vlan_gro_frags(&rx_ring->napi, qdev->vlgrp, vlan_id);
+ else
+ napi_gro_frags(napi);
+}
+
+/* Process an inbound completion from an rx ring. */
+static void ql_process_mac_rx_page(struct ql_adapter *qdev,
+ struct rx_ring *rx_ring,
+ struct ib_mac_iocb_rsp *ib_mac_rsp,
+ u32 length,
+ u16 vlan_id)
+{
+ struct net_device *ndev = qdev->ndev;
+ struct sk_buff *skb = NULL;
+ void *addr;
+ struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
+ struct napi_struct *napi = &rx_ring->napi;
+
+ skb = netdev_alloc_skb(ndev, length);
+ if (!skb) {
+ netif_err(qdev, drv, qdev->ndev,
+ "Couldn't get an skb, need to unwind!.\n");
+ rx_ring->rx_dropped++;
+ put_page(lbq_desc->p.pg_chunk.page);
+ return;
+ }
+
+ addr = lbq_desc->p.pg_chunk.va;
+ prefetch(addr);
+
+
+ /* Frame error, so drop the packet. */
+ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
+ netif_err(qdev, drv, qdev->ndev,
+ "Receive error, flags2 = 0x%x\n", ib_mac_rsp->flags2);
+ rx_ring->rx_errors++;
+ goto err_out;
+ }
+
+ /* The max framesize filter on this chip is set higher than
+ * MTU since FCoE uses 2k frames.
+ */
+ if (skb->len > ndev->mtu + ETH_HLEN) {
+ netif_err(qdev, drv, qdev->ndev,
+ "Segment too small, dropping.\n");
+ rx_ring->rx_dropped++;
+ goto err_out;
+ }
+ memcpy(skb_put(skb, ETH_HLEN), addr, ETH_HLEN);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "%d bytes of headers and data in large. Chain page to new skb and pull tail.\n",
+ length);
+ skb_fill_page_desc(skb, 0, lbq_desc->p.pg_chunk.page,
+ lbq_desc->p.pg_chunk.offset+ETH_HLEN,
+ length-ETH_HLEN);
+ skb->len += length-ETH_HLEN;
+ skb->data_len += length-ETH_HLEN;
+ skb->truesize += length-ETH_HLEN;
+
+ rx_ring->rx_packets++;
+ rx_ring->rx_bytes += skb->len;
+ skb->protocol = eth_type_trans(skb, ndev);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (qdev->rx_csum &&
+ !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) {
+ /* TCP frame. */
+ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) {
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "TCP checksum done!\n");
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) &&
+ (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) {
+ /* Unfragmented ipv4 UDP frame. */
+ struct iphdr *iph = (struct iphdr *) skb->data;
+ if (!(iph->frag_off &
+ cpu_to_be16(IP_MF|IP_OFFSET))) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ netif_printk(qdev, rx_status, KERN_DEBUG,
+ qdev->ndev,
+ "TCP checksum done!\n");
+ }
+ }
+ }
+
+ skb_record_rx_queue(skb, rx_ring->cq_id);
+ if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+ if (qdev->vlgrp && (vlan_id != 0xffff))
+ vlan_gro_receive(napi, qdev->vlgrp, vlan_id, skb);
+ else
+ napi_gro_receive(napi, skb);
+ } else {
+ if (qdev->vlgrp && (vlan_id != 0xffff))
+ vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id);
+ else
+ netif_receive_skb(skb);
+ }
+ return;
+err_out:
+ dev_kfree_skb_any(skb);
+ put_page(lbq_desc->p.pg_chunk.page);
+}
+
+/* Process an inbound completion from an rx ring. */
+static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
+ struct rx_ring *rx_ring,
+ struct ib_mac_iocb_rsp *ib_mac_rsp,
+ u32 length,
+ u16 vlan_id)
+{
+ struct net_device *ndev = qdev->ndev;
+ struct sk_buff *skb = NULL;
+ struct sk_buff *new_skb = NULL;
+ struct bq_desc *sbq_desc = ql_get_curr_sbuf(rx_ring);
+
+ skb = sbq_desc->p.skb;
+ /* Allocate new_skb and copy */
+ new_skb = netdev_alloc_skb(qdev->ndev, length + NET_IP_ALIGN);
+ if (new_skb == NULL) {
+ netif_err(qdev, probe, qdev->ndev,
+ "No skb available, drop the packet.\n");
+ rx_ring->rx_dropped++;
+ return;
+ }
+ skb_reserve(new_skb, NET_IP_ALIGN);
+ memcpy(skb_put(new_skb, length), skb->data, length);
+ skb = new_skb;
+
+ /* Frame error, so drop the packet. */
+ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
+ netif_err(qdev, drv, qdev->ndev,
+ "Receive error, flags2 = 0x%x\n", ib_mac_rsp->flags2);
+ dev_kfree_skb_any(skb);
+ rx_ring->rx_errors++;
+ return;
+ }
+
+ /* loopback self test for ethtool */
+ if (test_bit(QL_SELFTEST, &qdev->flags)) {
+ ql_check_lb_frame(qdev, skb);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
+ /* The max framesize filter on this chip is set higher than
+ * MTU since FCoE uses 2k frames.
+ */
+ if (skb->len > ndev->mtu + ETH_HLEN) {
+ dev_kfree_skb_any(skb);
+ rx_ring->rx_dropped++;
+ return;
+ }
+
+ prefetch(skb->data);
+ skb->dev = ndev;
+ if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) {
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "%s Multicast.\n",
+ (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+ IB_MAC_IOCB_RSP_M_HASH ? "Hash" :
+ (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+ IB_MAC_IOCB_RSP_M_REG ? "Registered" :
+ (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+ IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : "");
+ }
+ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P)
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "Promiscuous Packet.\n");
+
+ rx_ring->rx_packets++;
+ rx_ring->rx_bytes += skb->len;
+ skb->protocol = eth_type_trans(skb, ndev);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* If rx checksum is on, and there are no
+ * csum or frame errors.
+ */
+ if (qdev->rx_csum &&
+ !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) {
+ /* TCP frame. */
+ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) {
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "TCP checksum done!\n");
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) &&
+ (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) {
+ /* Unfragmented ipv4 UDP frame. */
+ struct iphdr *iph = (struct iphdr *) skb->data;
+ if (!(iph->frag_off &
+ cpu_to_be16(IP_MF|IP_OFFSET))) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ netif_printk(qdev, rx_status, KERN_DEBUG,
+ qdev->ndev,
+ "TCP checksum done!\n");
+ }
+ }
+ }
+
+ skb_record_rx_queue(skb, rx_ring->cq_id);
+ if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+ if (qdev->vlgrp && (vlan_id != 0xffff))
+ vlan_gro_receive(&rx_ring->napi, qdev->vlgrp,
+ vlan_id, skb);
+ else
+ napi_gro_receive(&rx_ring->napi, skb);
+ } else {
+ if (qdev->vlgrp && (vlan_id != 0xffff))
+ vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id);
+ else
+ netif_receive_skb(skb);
+ }
+}
+
static void ql_realign_skb(struct sk_buff *skb, int len)
{
void *temp_addr = skb->data;
@@ -1467,7 +1735,8 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
*/
if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV &&
ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS) {
- QPRINTK(qdev, RX_STATUS, DEBUG, "Header of %d bytes in small buffer.\n", hdr_len);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "Header of %d bytes in small buffer.\n", hdr_len);
/*
* Headers fit nicely into a small buffer.
*/
@@ -1486,15 +1755,16 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
* Handle the data buffer(s).
*/
if (unlikely(!length)) { /* Is there data too? */
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "No Data buffer in this packet.\n");
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "No Data buffer in this packet.\n");
return skb;
}
if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DS) {
if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS) {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "Headers in small, data of %d bytes in small, combine them.\n", length);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "Headers in small, data of %d bytes in small, combine them.\n",
+ length);
/*
* Data is less than small buffer size so it's
* stuffed in a small buffer.
@@ -1520,8 +1790,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
maplen),
PCI_DMA_FROMDEVICE);
} else {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "%d bytes in a single small buffer.\n", length);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "%d bytes in a single small buffer.\n",
+ length);
sbq_desc = ql_get_curr_sbuf(rx_ring);
skb = sbq_desc->p.skb;
ql_realign_skb(skb, length);
@@ -1536,18 +1807,18 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
}
} else if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL) {
if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS) {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "Header in small, %d bytes in large. Chain large to small!\n", length);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "Header in small, %d bytes in large. Chain large to small!\n",
+ length);
/*
* The data is in a single large buffer. We
* chain it to the header buffer's skb and let
* it rip.
*/
lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "Chaining page at offset = %d,"
- "for %d bytes to skb.\n",
- lbq_desc->p.pg_chunk.offset, length);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "Chaining page at offset = %d, for %d bytes to skb.\n",
+ lbq_desc->p.pg_chunk.offset, length);
skb_fill_page_desc(skb, 0, lbq_desc->p.pg_chunk.page,
lbq_desc->p.pg_chunk.offset,
length);
@@ -1563,8 +1834,8 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
skb = netdev_alloc_skb(qdev->ndev, length);
if (skb == NULL) {
- QPRINTK(qdev, PROBE, DEBUG,
- "No skb available, drop the packet.\n");
+ netif_printk(qdev, probe, KERN_DEBUG, qdev->ndev,
+ "No skb available, drop the packet.\n");
return NULL;
}
pci_unmap_page(qdev->pdev,
@@ -1573,8 +1844,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
pci_unmap_len(lbq_desc, maplen),
PCI_DMA_FROMDEVICE);
skb_reserve(skb, NET_IP_ALIGN);
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "%d bytes of headers and data in large. Chain page to new skb and pull tail.\n", length);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "%d bytes of headers and data in large. Chain page to new skb and pull tail.\n",
+ length);
skb_fill_page_desc(skb, 0,
lbq_desc->p.pg_chunk.page,
lbq_desc->p.pg_chunk.offset,
@@ -1615,8 +1887,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
* a local buffer and use it to find the
* pages to chain.
*/
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "%d bytes of headers & data in chain of large.\n", length);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "%d bytes of headers & data in chain of large.\n",
+ length);
skb = sbq_desc->p.skb;
sbq_desc->p.skb = NULL;
skb_reserve(skb, NET_IP_ALIGN);
@@ -1626,9 +1899,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
size = (length < rx_ring->lbq_buf_size) ? length :
rx_ring->lbq_buf_size;
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "Adding page %d to skb for %d bytes.\n",
- i, size);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "Adding page %d to skb for %d bytes.\n",
+ i, size);
skb_fill_page_desc(skb, i,
lbq_desc->p.pg_chunk.page,
lbq_desc->p.pg_chunk.offset,
@@ -1646,29 +1919,28 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
}
/* Process an inbound completion from an rx ring. */
-static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
+static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
struct rx_ring *rx_ring,
- struct ib_mac_iocb_rsp *ib_mac_rsp)
+ struct ib_mac_iocb_rsp *ib_mac_rsp,
+ u16 vlan_id)
{
struct net_device *ndev = qdev->ndev;
struct sk_buff *skb = NULL;
- u16 vlan_id = (le16_to_cpu(ib_mac_rsp->vlan_id) &
- IB_MAC_IOCB_RSP_VLAN_MASK)
QL_DUMP_IB_MAC_RSP(ib_mac_rsp);
skb = ql_build_rx_skb(qdev, rx_ring, ib_mac_rsp);
if (unlikely(!skb)) {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "No skb available, drop packet.\n");
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "No skb available, drop packet.\n");
rx_ring->rx_dropped++;
return;
}
/* Frame error, so drop the packet. */
if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
- QPRINTK(qdev, DRV, ERR, "Receive error, flags2 = 0x%x\n",
- ib_mac_rsp->flags2);
+ netif_err(qdev, drv, qdev->ndev,
+ "Receive error, flags2 = 0x%x\n", ib_mac_rsp->flags2);
dev_kfree_skb_any(skb);
rx_ring->rx_errors++;
return;
@@ -1693,17 +1965,18 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
prefetch(skb->data);
skb->dev = ndev;
if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) {
- QPRINTK(qdev, RX_STATUS, DEBUG, "%s%s%s Multicast.\n",
- (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
- IB_MAC_IOCB_RSP_M_HASH ? "Hash" : "",
- (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
- IB_MAC_IOCB_RSP_M_REG ? "Registered" : "",
- (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
- IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : "");
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, "%s Multicast.\n",
+ (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+ IB_MAC_IOCB_RSP_M_HASH ? "Hash" :
+ (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+ IB_MAC_IOCB_RSP_M_REG ? "Registered" :
+ (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+ IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : "");
rx_ring->rx_multicast++;
}
if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P) {
- QPRINTK(qdev, RX_STATUS, DEBUG, "Promiscuous Packet.\n");
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "Promiscuous Packet.\n");
}
skb->protocol = eth_type_trans(skb, ndev);
@@ -1716,8 +1989,8 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
!(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) {
/* TCP frame. */
if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "TCP checksum done!\n");
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "TCP checksum done!\n");
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) &&
(ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) {
@@ -1726,8 +1999,8 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
if (!(iph->frag_off &
cpu_to_be16(IP_MF|IP_OFFSET))) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "TCP checksum done!\n");
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "TCP checksum done!\n");
}
}
}
@@ -1753,6 +2026,56 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
}
}
+/* Process an inbound completion from an rx ring. */
+static unsigned long ql_process_mac_rx_intr(struct ql_adapter *qdev,
+ struct rx_ring *rx_ring,
+ struct ib_mac_iocb_rsp *ib_mac_rsp)
+{
+ u32 length = le32_to_cpu(ib_mac_rsp->data_len);
+ u16 vlan_id = (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ?
+ ((le16_to_cpu(ib_mac_rsp->vlan_id) &
+ IB_MAC_IOCB_RSP_VLAN_MASK)) : 0xffff;
+
+ QL_DUMP_IB_MAC_RSP(ib_mac_rsp);
+
+ if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV) {
+ /* The data and headers are split into
+ * separate buffers.
+ */
+ ql_process_mac_split_rx_intr(qdev, rx_ring, ib_mac_rsp,
+ vlan_id);
+ } else if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DS) {
+ /* The data fit in a single small buffer.
+ * Allocate a new skb, copy the data and
+ * return the buffer to the free pool.
+ */
+ ql_process_mac_rx_skb(qdev, rx_ring, ib_mac_rsp,
+ length, vlan_id);
+ } else if ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL) &&
+ !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK) &&
+ (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T)) {
+ /* TCP packet in a page chunk that's been checksummed.
+ * Tack it on to our GRO skb and let it go.
+ */
+ ql_process_mac_rx_gro_page(qdev, rx_ring, ib_mac_rsp,
+ length, vlan_id);
+ } else if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL) {
+ /* Non-TCP packet in a page chunk. Allocate an
+ * skb, tack it on frags, and send it up.
+ */
+ ql_process_mac_rx_page(qdev, rx_ring, ib_mac_rsp,
+ length, vlan_id);
+ } else {
+ /* Non-TCP/UDP large frames that span multiple buffers
+ * can be processed corrrectly by the split frame logic.
+ */
+ ql_process_mac_split_rx_intr(qdev, rx_ring, ib_mac_rsp,
+ vlan_id);
+ }
+
+ return (unsigned long)length;
+}
+
/* Process an outbound completion from an rx ring. */
static void ql_process_mac_tx_intr(struct ql_adapter *qdev,
struct ob_mac_iocb_rsp *mac_rsp)
@@ -1774,20 +2097,20 @@ static void ql_process_mac_tx_intr(struct ql_adapter *qdev,
OB_MAC_IOCB_RSP_L |
OB_MAC_IOCB_RSP_P | OB_MAC_IOCB_RSP_B))) {
if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_E) {
- QPRINTK(qdev, TX_DONE, WARNING,
- "Total descriptor length did not match transfer length.\n");
+ netif_warn(qdev, tx_done, qdev->ndev,
+ "Total descriptor length did not match transfer length.\n");
}
if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_S) {
- QPRINTK(qdev, TX_DONE, WARNING,
- "Frame too short to be legal, not sent.\n");
+ netif_warn(qdev, tx_done, qdev->ndev,
+ "Frame too short to be valid, not sent.\n");
}
if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_L) {
- QPRINTK(qdev, TX_DONE, WARNING,
- "Frame too long, but sent anyway.\n");
+ netif_warn(qdev, tx_done, qdev->ndev,
+ "Frame too long, but sent anyway.\n");
}
if (mac_rsp->flags1 & OB_MAC_IOCB_RSP_B) {
- QPRINTK(qdev, TX_DONE, WARNING,
- "PCI backplane error. Frame not sent.\n");
+ netif_warn(qdev, tx_done, qdev->ndev,
+ "PCI backplane error. Frame not sent.\n");
}
}
atomic_inc(&tx_ring->tx_count);
@@ -1817,33 +2140,35 @@ static void ql_process_chip_ae_intr(struct ql_adapter *qdev,
{
switch (ib_ae_rsp->event) {
case MGMT_ERR_EVENT:
- QPRINTK(qdev, RX_ERR, ERR,
- "Management Processor Fatal Error.\n");
+ netif_err(qdev, rx_err, qdev->ndev,
+ "Management Processor Fatal Error.\n");
ql_queue_fw_error(qdev);
return;
case CAM_LOOKUP_ERR_EVENT:
- QPRINTK(qdev, LINK, ERR,
- "Multiple CAM hits lookup occurred.\n");
- QPRINTK(qdev, DRV, ERR, "This event shouldn't occur.\n");
+ netif_err(qdev, link, qdev->ndev,
+ "Multiple CAM hits lookup occurred.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "This event shouldn't occur.\n");
ql_queue_asic_error(qdev);
return;
case SOFT_ECC_ERROR_EVENT:
- QPRINTK(qdev, RX_ERR, ERR, "Soft ECC error detected.\n");
+ netif_err(qdev, rx_err, qdev->ndev,
+ "Soft ECC error detected.\n");
ql_queue_asic_error(qdev);
break;
case PCI_ERR_ANON_BUF_RD:
- QPRINTK(qdev, RX_ERR, ERR,
- "PCI error occurred when reading anonymous buffers from rx_ring %d.\n",
- ib_ae_rsp->q_id);
+ netif_err(qdev, rx_err, qdev->ndev,
+ "PCI error occurred when reading anonymous buffers from rx_ring %d.\n",
+ ib_ae_rsp->q_id);
ql_queue_asic_error(qdev);
break;
default:
- QPRINTK(qdev, DRV, ERR, "Unexpected event %d.\n",
- ib_ae_rsp->event);
+ netif_err(qdev, drv, qdev->ndev, "Unexpected event %d.\n",
+ ib_ae_rsp->event);
ql_queue_asic_error(qdev);
break;
}
@@ -1860,9 +2185,9 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring)
/* While there are entries in the completion queue. */
while (prod != rx_ring->cnsmr_idx) {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "cq_id = %d, prod = %d, cnsmr = %d.\n.", rx_ring->cq_id,
- prod, rx_ring->cnsmr_idx);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "cq_id = %d, prod = %d, cnsmr = %d.\n.",
+ rx_ring->cq_id, prod, rx_ring->cnsmr_idx);
net_rsp = (struct ob_mac_iocb_rsp *)rx_ring->curr_entry;
rmb();
@@ -1873,9 +2198,9 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring)
ql_process_mac_tx_intr(qdev, net_rsp);
break;
default:
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "Hit default case, not handled! dropping the packet, opcode = %x.\n",
- net_rsp->opcode);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "Hit default case, not handled! dropping the packet, opcode = %x.\n",
+ net_rsp->opcode);
}
count++;
ql_update_cq(rx_ring);
@@ -1907,9 +2232,9 @@ static int ql_clean_inbound_rx_ring(struct rx_ring *rx_ring, int budget)
/* While there are entries in the completion queue. */
while (prod != rx_ring->cnsmr_idx) {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "cq_id = %d, prod = %d, cnsmr = %d.\n.", rx_ring->cq_id,
- prod, rx_ring->cnsmr_idx);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "cq_id = %d, prod = %d, cnsmr = %d.\n.",
+ rx_ring->cq_id, prod, rx_ring->cnsmr_idx);
net_rsp = rx_ring->curr_entry;
rmb();
@@ -1925,11 +2250,10 @@ static int ql_clean_inbound_rx_ring(struct rx_ring *rx_ring, int budget)
net_rsp);
break;
default:
- {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "Hit default case, not handled! dropping the packet, opcode = %x.\n",
- net_rsp->opcode);
- }
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "Hit default case, not handled! dropping the packet, opcode = %x.\n",
+ net_rsp->opcode);
+ break;
}
count++;
ql_update_cq(rx_ring);
@@ -1950,8 +2274,8 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget)
int i, work_done = 0;
struct intr_context *ctx = &qdev->intr_context[rx_ring->cq_id];
- QPRINTK(qdev, RX_STATUS, DEBUG, "Enter, NAPI POLL cq_id = %d.\n",
- rx_ring->cq_id);
+ netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
+ "Enter, NAPI POLL cq_id = %d.\n", rx_ring->cq_id);
/* Service the TX rings first. They start
* right after the RSS rings. */
@@ -1963,9 +2287,9 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget)
if ((ctx->irq_mask & (1 << trx_ring->cq_id)) &&
(ql_read_sh_reg(trx_ring->prod_idx_sh_reg) !=
trx_ring->cnsmr_idx)) {
- QPRINTK(qdev, INTR, DEBUG,
- "%s: Servicing TX completion ring %d.\n",
- __func__, trx_ring->cq_id);
+ netif_printk(qdev, intr, KERN_DEBUG, qdev->ndev,
+ "%s: Servicing TX completion ring %d.\n",
+ __func__, trx_ring->cq_id);
ql_clean_outbound_rx_ring(trx_ring);
}
}
@@ -1975,9 +2299,9 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget)
*/
if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) !=
rx_ring->cnsmr_idx) {
- QPRINTK(qdev, INTR, DEBUG,
- "%s: Servicing RX completion ring %d.\n",
- __func__, rx_ring->cq_id);
+ netif_printk(qdev, intr, KERN_DEBUG, qdev->ndev,
+ "%s: Servicing RX completion ring %d.\n",
+ __func__, rx_ring->cq_id);
work_done = ql_clean_inbound_rx_ring(rx_ring, budget);
}
@@ -1994,12 +2318,13 @@ static void qlge_vlan_rx_register(struct net_device *ndev, struct vlan_group *gr
qdev->vlgrp = grp;
if (grp) {
- QPRINTK(qdev, IFUP, DEBUG, "Turning on VLAN in NIC_RCV_CFG.\n");
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "Turning on VLAN in NIC_RCV_CFG.\n");
ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK |
NIC_RCV_CFG_VLAN_MATCH_AND_NON);
} else {
- QPRINTK(qdev, IFUP, DEBUG,
- "Turning off VLAN in NIC_RCV_CFG.\n");
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "Turning off VLAN in NIC_RCV_CFG.\n");
ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK);
}
}
@@ -2015,7 +2340,8 @@ static void qlge_vlan_rx_add_vid(struct net_device *ndev, u16 vid)
return;
if (ql_set_mac_addr_reg
(qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) {
- QPRINTK(qdev, IFUP, ERR, "Failed to init vlan address.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to init vlan address.\n");
}
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
}
@@ -2032,7 +2358,8 @@ static void qlge_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
if (ql_set_mac_addr_reg
(qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) {
- QPRINTK(qdev, IFUP, ERR, "Failed to clear vlan address.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to clear vlan address.\n");
}
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
@@ -2061,7 +2388,8 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
spin_lock(&qdev->hw_lock);
if (atomic_read(&qdev->intr_context[0].irq_cnt)) {
- QPRINTK(qdev, INTR, DEBUG, "Shared Interrupt, Not ours!\n");
+ netif_printk(qdev, intr, KERN_DEBUG, qdev->ndev,
+ "Shared Interrupt, Not ours!\n");
spin_unlock(&qdev->hw_lock);
return IRQ_NONE;
}
@@ -2074,10 +2402,11 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
*/
if (var & STS_FE) {
ql_queue_asic_error(qdev);
- QPRINTK(qdev, INTR, ERR, "Got fatal error, STS = %x.\n", var);
+ netif_err(qdev, intr, qdev->ndev,
+ "Got fatal error, STS = %x.\n", var);
var = ql_read32(qdev, ERR_STS);
- QPRINTK(qdev, INTR, ERR,
- "Resetting chip. Error Status Register = 0x%x\n", var);
+ netif_err(qdev, intr, qdev->ndev,
+ "Resetting chip. Error Status Register = 0x%x\n", var);
return IRQ_HANDLED;
}
@@ -2090,7 +2419,8 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
* We've got an async event or mailbox completion.
* Handle it and clear the source of the interrupt.
*/
- QPRINTK(qdev, INTR, ERR, "Got MPI processor interrupt.\n");
+ netif_err(qdev, intr, qdev->ndev,
+ "Got MPI processor interrupt.\n");
ql_disable_completion_interrupt(qdev, intr_context->intr);
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
queue_delayed_work_on(smp_processor_id(),
@@ -2105,8 +2435,8 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
*/
var = ql_read32(qdev, ISR1);
if (var & intr_context->irq_mask) {
- QPRINTK(qdev, INTR, INFO,
- "Waking handler for rx_ring[0].\n");
+ netif_info(qdev, intr, qdev->ndev,
+ "Waking handler for rx_ring[0].\n");
ql_disable_completion_interrupt(qdev, intr_context->intr);
napi_schedule(&rx_ring->napi);
work_done++;
@@ -2203,9 +2533,9 @@ static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_OK;
if (unlikely(atomic_read(&tx_ring->tx_count) < 2)) {
- QPRINTK(qdev, TX_QUEUED, INFO,
- "%s: shutting down tx queue %d du to lack of resources.\n",
- __func__, tx_ring_idx);
+ netif_info(qdev, tx_queued, qdev->ndev,
+ "%s: shutting down tx queue %d du to lack of resources.\n",
+ __func__, tx_ring_idx);
netif_stop_subqueue(ndev, tx_ring->wq_id);
atomic_inc(&tx_ring->queue_stopped);
tx_ring->tx_errors++;
@@ -2226,8 +2556,8 @@ static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev)
mac_iocb_ptr->frame_len = cpu_to_le16((u16) skb->len);
if (qdev->vlgrp && vlan_tx_tag_present(skb)) {
- QPRINTK(qdev, TX_QUEUED, DEBUG, "Adding a vlan tag %d.\n",
- vlan_tx_tag_get(skb));
+ netif_printk(qdev, tx_queued, KERN_DEBUG, qdev->ndev,
+ "Adding a vlan tag %d.\n", vlan_tx_tag_get(skb));
mac_iocb_ptr->flags3 |= OB_MAC_IOCB_V;
mac_iocb_ptr->vlan_tci = cpu_to_le16(vlan_tx_tag_get(skb));
}
@@ -2241,8 +2571,8 @@ static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev)
}
if (ql_map_send(qdev, mac_iocb_ptr, skb, tx_ring_desc) !=
NETDEV_TX_OK) {
- QPRINTK(qdev, TX_QUEUED, ERR,
- "Could not map the segments.\n");
+ netif_err(qdev, tx_queued, qdev->ndev,
+ "Could not map the segments.\n");
tx_ring->tx_errors++;
return NETDEV_TX_BUSY;
}
@@ -2253,8 +2583,9 @@ static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev)
wmb();
ql_write_db_reg(tx_ring->prod_idx, tx_ring->prod_idx_db_reg);
- QPRINTK(qdev, TX_QUEUED, DEBUG, "tx queued, slot %d, len %d\n",
- tx_ring->prod_idx, skb->len);
+ netif_printk(qdev, tx_queued, KERN_DEBUG, qdev->ndev,
+ "tx queued, slot %d, len %d\n",
+ tx_ring->prod_idx, skb->len);
atomic_dec(&tx_ring->tx_count);
return NETDEV_TX_OK;
@@ -2285,8 +2616,8 @@ static int ql_alloc_shadow_space(struct ql_adapter *qdev)
pci_alloc_consistent(qdev->pdev,
PAGE_SIZE, &qdev->rx_ring_shadow_reg_dma);
if (qdev->rx_ring_shadow_reg_area == NULL) {
- QPRINTK(qdev, IFUP, ERR,
- "Allocation of RX shadow space failed.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Allocation of RX shadow space failed.\n");
return -ENOMEM;
}
memset(qdev->rx_ring_shadow_reg_area, 0, PAGE_SIZE);
@@ -2294,8 +2625,8 @@ static int ql_alloc_shadow_space(struct ql_adapter *qdev)
pci_alloc_consistent(qdev->pdev, PAGE_SIZE,
&qdev->tx_ring_shadow_reg_dma);
if (qdev->tx_ring_shadow_reg_area == NULL) {
- QPRINTK(qdev, IFUP, ERR,
- "Allocation of TX shadow space failed.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Allocation of TX shadow space failed.\n");
goto err_wqp_sh_area;
}
memset(qdev->tx_ring_shadow_reg_area, 0, PAGE_SIZE);
@@ -2349,7 +2680,7 @@ static int ql_alloc_tx_resources(struct ql_adapter *qdev,
if ((tx_ring->wq_base == NULL) ||
tx_ring->wq_base_dma & WQ_ADDR_ALIGN) {
- QPRINTK(qdev, IFUP, ERR, "tx_ring alloc failed.\n");
+ netif_err(qdev, ifup, qdev->ndev, "tx_ring alloc failed.\n");
return -ENOMEM;
}
tx_ring->q =
@@ -2400,7 +2731,8 @@ static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring
for (i = 0; i < rx_ring->sbq_len; i++) {
sbq_desc = &rx_ring->sbq[i];
if (sbq_desc == NULL) {
- QPRINTK(qdev, IFUP, ERR, "sbq_desc %d is NULL.\n", i);
+ netif_err(qdev, ifup, qdev->ndev,
+ "sbq_desc %d is NULL.\n", i);
return;
}
if (sbq_desc->p.skb) {
@@ -2527,7 +2859,7 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev,
&rx_ring->cq_base_dma);
if (rx_ring->cq_base == NULL) {
- QPRINTK(qdev, IFUP, ERR, "rx_ring alloc failed.\n");
+ netif_err(qdev, ifup, qdev->ndev, "rx_ring alloc failed.\n");
return -ENOMEM;
}
@@ -2540,8 +2872,8 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev,
&rx_ring->sbq_base_dma);
if (rx_ring->sbq_base == NULL) {
- QPRINTK(qdev, IFUP, ERR,
- "Small buffer queue allocation failed.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Small buffer queue allocation failed.\n");
goto err_mem;
}
@@ -2552,8 +2884,8 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev,
kmalloc(rx_ring->sbq_len * sizeof(struct bq_desc),
GFP_KERNEL);
if (rx_ring->sbq == NULL) {
- QPRINTK(qdev, IFUP, ERR,
- "Small buffer queue control block allocation failed.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Small buffer queue control block allocation failed.\n");
goto err_mem;
}
@@ -2569,8 +2901,8 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev,
&rx_ring->lbq_base_dma);
if (rx_ring->lbq_base == NULL) {
- QPRINTK(qdev, IFUP, ERR,
- "Large buffer queue allocation failed.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Large buffer queue allocation failed.\n");
goto err_mem;
}
/*
@@ -2580,8 +2912,8 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev,
kmalloc(rx_ring->lbq_len * sizeof(struct bq_desc),
GFP_KERNEL);
if (rx_ring->lbq == NULL) {
- QPRINTK(qdev, IFUP, ERR,
- "Large buffer queue control block allocation failed.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Large buffer queue control block allocation failed.\n");
goto err_mem;
}
@@ -2610,10 +2942,10 @@ static void ql_tx_ring_clean(struct ql_adapter *qdev)
for (i = 0; i < tx_ring->wq_len; i++) {
tx_ring_desc = &tx_ring->q[i];
if (tx_ring_desc && tx_ring_desc->skb) {
- QPRINTK(qdev, IFDOWN, ERR,
- "Freeing lost SKB %p, from queue %d, index %d.\n",
- tx_ring_desc->skb, j,
- tx_ring_desc->index);
+ netif_err(qdev, ifdown, qdev->ndev,
+ "Freeing lost SKB %p, from queue %d, index %d.\n",
+ tx_ring_desc->skb, j,
+ tx_ring_desc->index);
ql_unmap_send(qdev, tx_ring_desc,
tx_ring_desc->map_cnt);
dev_kfree_skb(tx_ring_desc->skb);
@@ -2644,16 +2976,16 @@ static int ql_alloc_mem_resources(struct ql_adapter *qdev)
for (i = 0; i < qdev->rx_ring_count; i++) {
if (ql_alloc_rx_resources(qdev, &qdev->rx_ring[i]) != 0) {
- QPRINTK(qdev, IFUP, ERR,
- "RX resource allocation failed.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "RX resource allocation failed.\n");
goto err_mem;
}
}
/* Allocate tx queue resources */
for (i = 0; i < qdev->tx_ring_count; i++) {
if (ql_alloc_tx_resources(qdev, &qdev->tx_ring[i]) != 0) {
- QPRINTK(qdev, IFUP, ERR,
- "TX resource allocation failed.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "TX resource allocation failed.\n");
goto err_mem;
}
}
@@ -2788,14 +3120,15 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
cqicb->pkt_delay = cpu_to_le16(qdev->rx_max_coalesced_frames);
break;
default:
- QPRINTK(qdev, IFUP, DEBUG, "Invalid rx_ring->type = %d.\n",
- rx_ring->type);
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "Invalid rx_ring->type = %d.\n", rx_ring->type);
}
- QPRINTK(qdev, IFUP, DEBUG, "Initializing rx work queue.\n");
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "Initializing rx work queue.\n");
err = ql_write_cfg(qdev, cqicb, sizeof(struct cqicb),
CFG_LCQ, rx_ring->cq_id);
if (err) {
- QPRINTK(qdev, IFUP, ERR, "Failed to load CQICB.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Failed to load CQICB.\n");
return err;
}
return err;
@@ -2841,10 +3174,11 @@ static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring)
err = ql_write_cfg(qdev, wqicb, sizeof(*wqicb), CFG_LRQ,
(u16) tx_ring->wq_id);
if (err) {
- QPRINTK(qdev, IFUP, ERR, "Failed to load tx_ring.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Failed to load tx_ring.\n");
return err;
}
- QPRINTK(qdev, IFUP, DEBUG, "Successfully loaded WQICB.\n");
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "Successfully loaded WQICB.\n");
return err;
}
@@ -2898,15 +3232,15 @@ static void ql_enable_msix(struct ql_adapter *qdev)
if (err < 0) {
kfree(qdev->msi_x_entry);
qdev->msi_x_entry = NULL;
- QPRINTK(qdev, IFUP, WARNING,
- "MSI-X Enable failed, trying MSI.\n");
+ netif_warn(qdev, ifup, qdev->ndev,
+ "MSI-X Enable failed, trying MSI.\n");
qdev->intr_count = 1;
qlge_irq_type = MSI_IRQ;
} else if (err == 0) {
set_bit(QL_MSIX_ENABLED, &qdev->flags);
- QPRINTK(qdev, IFUP, INFO,
- "MSI-X Enabled, got %d vectors.\n",
- qdev->intr_count);
+ netif_info(qdev, ifup, qdev->ndev,
+ "MSI-X Enabled, got %d vectors.\n",
+ qdev->intr_count);
return;
}
}
@@ -2915,13 +3249,14 @@ msi:
if (qlge_irq_type == MSI_IRQ) {
if (!pci_enable_msi(qdev->pdev)) {
set_bit(QL_MSI_ENABLED, &qdev->flags);
- QPRINTK(qdev, IFUP, INFO,
- "Running with MSI interrupts.\n");
+ netif_info(qdev, ifup, qdev->ndev,
+ "Running with MSI interrupts.\n");
return;
}
}
qlge_irq_type = LEG_IRQ;
- QPRINTK(qdev, IFUP, DEBUG, "Running with legacy interrupts.\n");
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "Running with legacy interrupts.\n");
}
/* Each vector services 1 RSS ring and and 1 or more
@@ -3093,12 +3428,12 @@ static void ql_free_irq(struct ql_adapter *qdev)
if (test_bit(QL_MSIX_ENABLED, &qdev->flags)) {
free_irq(qdev->msi_x_entry[i].vector,
&qdev->rx_ring[i]);
- QPRINTK(qdev, IFDOWN, DEBUG,
- "freeing msix interrupt %d.\n", i);
+ netif_printk(qdev, ifdown, KERN_DEBUG, qdev->ndev,
+ "freeing msix interrupt %d.\n", i);
} else {
free_irq(qdev->pdev->irq, &qdev->rx_ring[0]);
- QPRINTK(qdev, IFDOWN, DEBUG,
- "freeing msi interrupt %d.\n", i);
+ netif_printk(qdev, ifdown, KERN_DEBUG, qdev->ndev,
+ "freeing msi interrupt %d.\n", i);
}
}
}
@@ -3123,32 +3458,33 @@ static int ql_request_irq(struct ql_adapter *qdev)
intr_context->name,
&qdev->rx_ring[i]);
if (status) {
- QPRINTK(qdev, IFUP, ERR,
- "Failed request for MSIX interrupt %d.\n",
- i);
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed request for MSIX interrupt %d.\n",
+ i);
goto err_irq;
} else {
- QPRINTK(qdev, IFUP, DEBUG,
- "Hooked intr %d, queue type %s%s%s, with name %s.\n",
- i,
- qdev->rx_ring[i].type ==
- DEFAULT_Q ? "DEFAULT_Q" : "",
- qdev->rx_ring[i].type ==
- TX_Q ? "TX_Q" : "",
- qdev->rx_ring[i].type ==
- RX_Q ? "RX_Q" : "", intr_context->name);
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "Hooked intr %d, queue type %s, with name %s.\n",
+ i,
+ qdev->rx_ring[i].type == DEFAULT_Q ?
+ "DEFAULT_Q" :
+ qdev->rx_ring[i].type == TX_Q ?
+ "TX_Q" :
+ qdev->rx_ring[i].type == RX_Q ?
+ "RX_Q" : "",
+ intr_context->name);
}
} else {
- QPRINTK(qdev, IFUP, DEBUG,
- "trying msi or legacy interrupts.\n");
- QPRINTK(qdev, IFUP, DEBUG,
- "%s: irq = %d.\n", __func__, pdev->irq);
- QPRINTK(qdev, IFUP, DEBUG,
- "%s: context->name = %s.\n", __func__,
- intr_context->name);
- QPRINTK(qdev, IFUP, DEBUG,
- "%s: dev_id = 0x%p.\n", __func__,
- &qdev->rx_ring[0]);
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "trying msi or legacy interrupts.\n");
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "%s: irq = %d.\n", __func__, pdev->irq);
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "%s: context->name = %s.\n", __func__,
+ intr_context->name);
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "%s: dev_id = 0x%p.\n", __func__,
+ &qdev->rx_ring[0]);
status =
request_irq(pdev->irq, qlge_isr,
test_bit(QL_MSI_ENABLED,
@@ -3158,20 +3494,20 @@ static int ql_request_irq(struct ql_adapter *qdev)
if (status)
goto err_irq;
- QPRINTK(qdev, IFUP, ERR,
- "Hooked intr %d, queue type %s%s%s, with name %s.\n",
- i,
- qdev->rx_ring[0].type ==
- DEFAULT_Q ? "DEFAULT_Q" : "",
- qdev->rx_ring[0].type == TX_Q ? "TX_Q" : "",
- qdev->rx_ring[0].type == RX_Q ? "RX_Q" : "",
- intr_context->name);
+ netif_err(qdev, ifup, qdev->ndev,
+ "Hooked intr %d, queue type %s, with name %s.\n",
+ i,
+ qdev->rx_ring[0].type == DEFAULT_Q ?
+ "DEFAULT_Q" :
+ qdev->rx_ring[0].type == TX_Q ? "TX_Q" :
+ qdev->rx_ring[0].type == RX_Q ? "RX_Q" : "",
+ intr_context->name);
}
intr_context->hooked = 1;
}
return status;
err_irq:
- QPRINTK(qdev, IFUP, ERR, "Failed to get the interrupts!!!/n");
+ netif_err(qdev, ifup, qdev->ndev, "Failed to get the interrupts!!!/n");
ql_free_irq(qdev);
return status;
}
@@ -3205,14 +3541,15 @@ static int ql_start_rss(struct ql_adapter *qdev)
memcpy((void *)&ricb->ipv6_hash_key[0], init_hash_seed, 40);
memcpy((void *)&ricb->ipv4_hash_key[0], init_hash_seed, 16);
- QPRINTK(qdev, IFUP, DEBUG, "Initializing RSS.\n");
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, "Initializing RSS.\n");
status = ql_write_cfg(qdev, ricb, sizeof(*ricb), CFG_LR, 0);
if (status) {
- QPRINTK(qdev, IFUP, ERR, "Failed to load RICB.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Failed to load RICB.\n");
return status;
}
- QPRINTK(qdev, IFUP, DEBUG, "Successfully loaded RICB.\n");
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "Successfully loaded RICB.\n");
return status;
}
@@ -3227,9 +3564,8 @@ static int ql_clear_routing_entries(struct ql_adapter *qdev)
for (i = 0; i < 16; i++) {
status = ql_set_routing_reg(qdev, i, 0, 0);
if (status) {
- QPRINTK(qdev, IFUP, ERR,
- "Failed to init routing register for CAM "
- "packets.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to init routing register for CAM packets.\n");
break;
}
}
@@ -3253,14 +3589,14 @@ static int ql_route_initialize(struct ql_adapter *qdev)
status = ql_set_routing_reg(qdev, RT_IDX_ALL_ERR_SLOT, RT_IDX_ERR, 1);
if (status) {
- QPRINTK(qdev, IFUP, ERR,
- "Failed to init routing register for error packets.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to init routing register for error packets.\n");
goto exit;
}
status = ql_set_routing_reg(qdev, RT_IDX_BCAST_SLOT, RT_IDX_BCAST, 1);
if (status) {
- QPRINTK(qdev, IFUP, ERR,
- "Failed to init routing register for broadcast packets.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to init routing register for broadcast packets.\n");
goto exit;
}
/* If we have more than one inbound queue, then turn on RSS in the
@@ -3270,8 +3606,8 @@ static int ql_route_initialize(struct ql_adapter *qdev)
status = ql_set_routing_reg(qdev, RT_IDX_RSS_MATCH_SLOT,
RT_IDX_RSS_MATCH, 1);
if (status) {
- QPRINTK(qdev, IFUP, ERR,
- "Failed to init routing register for MATCH RSS packets.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to init routing register for MATCH RSS packets.\n");
goto exit;
}
}
@@ -3279,8 +3615,8 @@ static int ql_route_initialize(struct ql_adapter *qdev)
status = ql_set_routing_reg(qdev, RT_IDX_CAM_HIT_SLOT,
RT_IDX_CAM_HIT, 1);
if (status)
- QPRINTK(qdev, IFUP, ERR,
- "Failed to init routing register for CAM packets.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to init routing register for CAM packets.\n");
exit:
ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
return status;
@@ -3298,13 +3634,13 @@ int ql_cam_route_initialize(struct ql_adapter *qdev)
set &= qdev->port_link_up;
status = ql_set_mac_addr(qdev, set);
if (status) {
- QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Failed to init mac address.\n");
return status;
}
status = ql_route_initialize(qdev);
if (status)
- QPRINTK(qdev, IFUP, ERR, "Failed to init routing table.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Failed to init routing table.\n");
return status;
}
@@ -3332,15 +3668,15 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
/* Enable the function, set pagesize, enable error checking. */
value = FSC_FE | FSC_EPC_INBOUND | FSC_EPC_OUTBOUND |
- FSC_EC | FSC_VM_PAGE_4K | FSC_SH;
+ FSC_EC | FSC_VM_PAGE_4K;
+ value |= SPLT_SETTING;
/* Set/clear header splitting. */
mask = FSC_VM_PAGESIZE_MASK |
FSC_DBL_MASK | FSC_DBRST_MASK | (value << 16);
ql_write32(qdev, FSC, mask | value);
- ql_write32(qdev, SPLT_HDR, SPLT_HDR_EP |
- min(SMALL_BUF_MAP_SIZE, MAX_SPLIT_SIZE));
+ ql_write32(qdev, SPLT_HDR, SPLT_LEN);
/* Set RX packet routing to use port/pci function on which the
* packet arrived on in addition to usual frame routing.
@@ -3369,8 +3705,8 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
for (i = 0; i < qdev->rx_ring_count; i++) {
status = ql_start_rx_ring(qdev, &qdev->rx_ring[i]);
if (status) {
- QPRINTK(qdev, IFUP, ERR,
- "Failed to start rx ring[%d].\n", i);
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to start rx ring[%d].\n", i);
return status;
}
}
@@ -3381,7 +3717,7 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
if (qdev->rss_ring_count > 1) {
status = ql_start_rss(qdev);
if (status) {
- QPRINTK(qdev, IFUP, ERR, "Failed to start RSS.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Failed to start RSS.\n");
return status;
}
}
@@ -3390,8 +3726,8 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
for (i = 0; i < qdev->tx_ring_count; i++) {
status = ql_start_tx_ring(qdev, &qdev->tx_ring[i]);
if (status) {
- QPRINTK(qdev, IFUP, ERR,
- "Failed to start tx ring[%d].\n", i);
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to start tx ring[%d].\n", i);
return status;
}
}
@@ -3399,20 +3735,20 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
/* Initialize the port and set the max framesize. */
status = qdev->nic_ops->port_initialize(qdev);
if (status)
- QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Failed to start port.\n");
/* Set up the MAC address and frame routing filter. */
status = ql_cam_route_initialize(qdev);
if (status) {
- QPRINTK(qdev, IFUP, ERR,
- "Failed to init CAM/Routing tables.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to init CAM/Routing tables.\n");
return status;
}
/* Start NAPI for the RSS queues. */
for (i = 0; i < qdev->rss_ring_count; i++) {
- QPRINTK(qdev, IFUP, DEBUG, "Enabling NAPI for rx_ring[%d].\n",
- i);
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "Enabling NAPI for rx_ring[%d].\n", i);
napi_enable(&qdev->rx_ring[i].napi);
}
@@ -3429,7 +3765,7 @@ static int ql_adapter_reset(struct ql_adapter *qdev)
/* Clear all the entries in the routing table. */
status = ql_clear_routing_entries(qdev);
if (status) {
- QPRINTK(qdev, IFUP, ERR, "Failed to clear routing bits.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Failed to clear routing bits.\n");
return status;
}
@@ -3452,8 +3788,8 @@ static int ql_adapter_reset(struct ql_adapter *qdev)
} while (time_before(jiffies, end_jiffies));
if (value & RST_FO_FR) {
- QPRINTK(qdev, IFDOWN, ERR,
- "ETIMEDOUT!!! errored out of resetting the chip!\n");
+ netif_err(qdev, ifdown, qdev->ndev,
+ "ETIMEDOUT!!! errored out of resetting the chip!\n");
status = -ETIMEDOUT;
}
@@ -3466,16 +3802,17 @@ static void ql_display_dev_info(struct net_device *ndev)
{
struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
- QPRINTK(qdev, PROBE, INFO,
- "Function #%d, Port %d, NIC Roll %d, NIC Rev = %d, "
- "XG Roll = %d, XG Rev = %d.\n",
- qdev->func,
- qdev->port,
- qdev->chip_rev_id & 0x0000000f,
- qdev->chip_rev_id >> 4 & 0x0000000f,
- qdev->chip_rev_id >> 8 & 0x0000000f,
- qdev->chip_rev_id >> 12 & 0x0000000f);
- QPRINTK(qdev, PROBE, INFO, "MAC address %pM\n", ndev->dev_addr);
+ netif_info(qdev, probe, qdev->ndev,
+ "Function #%d, Port %d, NIC Roll %d, NIC Rev = %d, "
+ "XG Roll = %d, XG Rev = %d.\n",
+ qdev->func,
+ qdev->port,
+ qdev->chip_rev_id & 0x0000000f,
+ qdev->chip_rev_id >> 4 & 0x0000000f,
+ qdev->chip_rev_id >> 8 & 0x0000000f,
+ qdev->chip_rev_id >> 12 & 0x0000000f);
+ netif_info(qdev, probe, qdev->ndev,
+ "MAC address %pM\n", ndev->dev_addr);
}
int ql_wol(struct ql_adapter *qdev)
@@ -3492,23 +3829,23 @@ int ql_wol(struct ql_adapter *qdev)
if (qdev->wol & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_PHY | WAKE_UCAST |
WAKE_MCAST | WAKE_BCAST)) {
- QPRINTK(qdev, IFDOWN, ERR,
- "Unsupported WOL paramter. qdev->wol = 0x%x.\n",
- qdev->wol);
+ netif_err(qdev, ifdown, qdev->ndev,
+ "Unsupported WOL paramter. qdev->wol = 0x%x.\n",
+ qdev->wol);
return -EINVAL;
}
if (qdev->wol & WAKE_MAGIC) {
status = ql_mb_wol_set_magic(qdev, 1);
if (status) {
- QPRINTK(qdev, IFDOWN, ERR,
- "Failed to set magic packet on %s.\n",
- qdev->ndev->name);
+ netif_err(qdev, ifdown, qdev->ndev,
+ "Failed to set magic packet on %s.\n",
+ qdev->ndev->name);
return status;
} else
- QPRINTK(qdev, DRV, INFO,
- "Enabled magic packet successfully on %s.\n",
- qdev->ndev->name);
+ netif_info(qdev, drv, qdev->ndev,
+ "Enabled magic packet successfully on %s.\n",
+ qdev->ndev->name);
wol |= MB_WOL_MAGIC_PKT;
}
@@ -3516,9 +3853,10 @@ int ql_wol(struct ql_adapter *qdev)
if (qdev->wol) {
wol |= MB_WOL_MODE_ON;
status = ql_mb_wol_mode(qdev, wol);
- QPRINTK(qdev, DRV, ERR, "WOL %s (wol code 0x%x) on %s\n",
- (status == 0) ? "Sucessfully set" : "Failed", wol,
- qdev->ndev->name);
+ netif_err(qdev, drv, qdev->ndev,
+ "WOL %s (wol code 0x%x) on %s\n",
+ (status == 0) ? "Successfully set" : "Failed",
+ wol, qdev->ndev->name);
}
return status;
@@ -3538,6 +3876,7 @@ static int ql_adapter_down(struct ql_adapter *qdev)
cancel_delayed_work_sync(&qdev->mpi_reset_work);
cancel_delayed_work_sync(&qdev->mpi_work);
cancel_delayed_work_sync(&qdev->mpi_idc_work);
+ cancel_delayed_work_sync(&qdev->mpi_core_to_log);
cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
for (i = 0; i < qdev->rss_ring_count; i++)
@@ -3558,8 +3897,8 @@ static int ql_adapter_down(struct ql_adapter *qdev)
status = ql_adapter_reset(qdev);
if (status)
- QPRINTK(qdev, IFDOWN, ERR, "reset(func #%d) FAILED!\n",
- qdev->func);
+ netif_err(qdev, ifdown, qdev->ndev, "reset(func #%d) FAILED!\n",
+ qdev->func);
return status;
}
@@ -3569,7 +3908,7 @@ static int ql_adapter_up(struct ql_adapter *qdev)
err = ql_adapter_initialize(qdev);
if (err) {
- QPRINTK(qdev, IFUP, INFO, "Unable to initialize adapter.\n");
+ netif_info(qdev, ifup, qdev->ndev, "Unable to initialize adapter.\n");
goto err_init;
}
set_bit(QL_ADAPTER_UP, &qdev->flags);
@@ -3601,7 +3940,7 @@ static int ql_get_adapter_resources(struct ql_adapter *qdev)
int status = 0;
if (ql_alloc_mem_resources(qdev)) {
- QPRINTK(qdev, IFUP, ERR, "Unable to allocate memory.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Unable to allocate memory.\n");
return -ENOMEM;
}
status = ql_request_irq(qdev);
@@ -3612,6 +3951,16 @@ static int qlge_close(struct net_device *ndev)
{
struct ql_adapter *qdev = netdev_priv(ndev);
+ /* If we hit pci_channel_io_perm_failure
+ * failure condition, then we already
+ * brought the adapter down.
+ */
+ if (test_bit(QL_EEH_FATAL, &qdev->flags)) {
+ netif_err(qdev, drv, qdev->ndev, "EEH fatal did unload.\n");
+ clear_bit(QL_EEH_FATAL, &qdev->flags);
+ return 0;
+ }
+
/*
* Wait for device to recover from a reset.
* (Rarely happens, but possible.)
@@ -3681,9 +4030,10 @@ static int ql_configure_rings(struct ql_adapter *qdev)
rx_ring->lbq_size =
rx_ring->lbq_len * sizeof(__le64);
rx_ring->lbq_buf_size = (u16)lbq_buf_len;
- QPRINTK(qdev, IFUP, DEBUG,
- "lbq_buf_size %d, order = %d\n",
- rx_ring->lbq_buf_size, qdev->lbq_buf_order);
+ netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
+ "lbq_buf_size %d, order = %d\n",
+ rx_ring->lbq_buf_size,
+ qdev->lbq_buf_order);
rx_ring->sbq_len = NUM_SMALL_BUFFERS;
rx_ring->sbq_size =
rx_ring->sbq_len * sizeof(__le64);
@@ -3747,14 +4097,14 @@ static int ql_change_rx_buffers(struct ql_adapter *qdev)
if (!test_bit(QL_ADAPTER_UP, &qdev->flags)) {
int i = 3;
while (i-- && !test_bit(QL_ADAPTER_UP, &qdev->flags)) {
- QPRINTK(qdev, IFUP, ERR,
- "Waiting for adapter UP...\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Waiting for adapter UP...\n");
ssleep(1);
}
if (!i) {
- QPRINTK(qdev, IFUP, ERR,
- "Timed out waiting for adapter UP\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Timed out waiting for adapter UP\n");
return -ETIMEDOUT;
}
}
@@ -3780,8 +4130,8 @@ static int ql_change_rx_buffers(struct ql_adapter *qdev)
return status;
error:
- QPRINTK(qdev, IFUP, ALERT,
- "Driver up/down cycle failed, closing device.\n");
+ netif_alert(qdev, ifup, qdev->ndev,
+ "Driver up/down cycle failed, closing device.\n");
set_bit(QL_ADAPTER_UP, &qdev->flags);
dev_close(qdev->ndev);
return status;
@@ -3793,28 +4143,25 @@ static int qlge_change_mtu(struct net_device *ndev, int new_mtu)
int status;
if (ndev->mtu == 1500 && new_mtu == 9000) {
- QPRINTK(qdev, IFUP, ERR, "Changing to jumbo MTU.\n");
+ netif_err(qdev, ifup, qdev->ndev, "Changing to jumbo MTU.\n");
} else if (ndev->mtu == 9000 && new_mtu == 1500) {
- QPRINTK(qdev, IFUP, ERR, "Changing to normal MTU.\n");
- } else if ((ndev->mtu == 1500 && new_mtu == 1500) ||
- (ndev->mtu == 9000 && new_mtu == 9000)) {
- return 0;
+ netif_err(qdev, ifup, qdev->ndev, "Changing to normal MTU.\n");
} else
return -EINVAL;
queue_delayed_work(qdev->workqueue,
&qdev->mpi_port_cfg_work, 3*HZ);
+ ndev->mtu = new_mtu;
+
if (!netif_running(qdev->ndev)) {
- ndev->mtu = new_mtu;
return 0;
}
- ndev->mtu = new_mtu;
status = ql_change_rx_buffers(qdev);
if (status) {
- QPRINTK(qdev, IFUP, ERR,
- "Changing MTU failed.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Changing MTU failed.\n");
}
return status;
@@ -3874,8 +4221,8 @@ static void qlge_set_multicast_list(struct net_device *ndev)
if (!test_bit(QL_PROMISCUOUS, &qdev->flags)) {
if (ql_set_routing_reg
(qdev, RT_IDX_PROMISCUOUS_SLOT, RT_IDX_VALID, 1)) {
- QPRINTK(qdev, HW, ERR,
- "Failed to set promiscous mode.\n");
+ netif_err(qdev, hw, qdev->ndev,
+ "Failed to set promiscous mode.\n");
} else {
set_bit(QL_PROMISCUOUS, &qdev->flags);
}
@@ -3884,8 +4231,8 @@ static void qlge_set_multicast_list(struct net_device *ndev)
if (test_bit(QL_PROMISCUOUS, &qdev->flags)) {
if (ql_set_routing_reg
(qdev, RT_IDX_PROMISCUOUS_SLOT, RT_IDX_VALID, 0)) {
- QPRINTK(qdev, HW, ERR,
- "Failed to clear promiscous mode.\n");
+ netif_err(qdev, hw, qdev->ndev,
+ "Failed to clear promiscous mode.\n");
} else {
clear_bit(QL_PROMISCUOUS, &qdev->flags);
}
@@ -3897,12 +4244,12 @@ static void qlge_set_multicast_list(struct net_device *ndev)
* transition is taking place.
*/
if ((ndev->flags & IFF_ALLMULTI) ||
- (ndev->mc_count > MAX_MULTICAST_ENTRIES)) {
+ (netdev_mc_count(ndev) > MAX_MULTICAST_ENTRIES)) {
if (!test_bit(QL_ALLMULTI, &qdev->flags)) {
if (ql_set_routing_reg
(qdev, RT_IDX_ALLMULTI_SLOT, RT_IDX_MCAST, 1)) {
- QPRINTK(qdev, HW, ERR,
- "Failed to set all-multi mode.\n");
+ netif_err(qdev, hw, qdev->ndev,
+ "Failed to set all-multi mode.\n");
} else {
set_bit(QL_ALLMULTI, &qdev->flags);
}
@@ -3911,32 +4258,34 @@ static void qlge_set_multicast_list(struct net_device *ndev)
if (test_bit(QL_ALLMULTI, &qdev->flags)) {
if (ql_set_routing_reg
(qdev, RT_IDX_ALLMULTI_SLOT, RT_IDX_MCAST, 0)) {
- QPRINTK(qdev, HW, ERR,
- "Failed to clear all-multi mode.\n");
+ netif_err(qdev, hw, qdev->ndev,
+ "Failed to clear all-multi mode.\n");
} else {
clear_bit(QL_ALLMULTI, &qdev->flags);
}
}
}
- if (ndev->mc_count) {
+ if (!netdev_mc_empty(ndev)) {
status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
if (status)
goto exit;
- for (i = 0, mc_ptr = ndev->mc_list; mc_ptr;
- i++, mc_ptr = mc_ptr->next)
+ i = 0;
+ netdev_for_each_mc_addr(mc_ptr, ndev) {
if (ql_set_mac_addr_reg(qdev, (u8 *) mc_ptr->dmi_addr,
MAC_ADDR_TYPE_MULTI_MAC, i)) {
- QPRINTK(qdev, HW, ERR,
- "Failed to loadmulticast address.\n");
+ netif_err(qdev, hw, qdev->ndev,
+ "Failed to loadmulticast address.\n");
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
goto exit;
}
+ i++;
+ }
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
if (ql_set_routing_reg
(qdev, RT_IDX_MCAST_MATCH_SLOT, RT_IDX_MCAST_MATCH, 1)) {
- QPRINTK(qdev, HW, ERR,
- "Failed to set multicast match mode.\n");
+ netif_err(qdev, hw, qdev->ndev,
+ "Failed to set multicast match mode.\n");
} else {
set_bit(QL_ALLMULTI, &qdev->flags);
}
@@ -3954,6 +4303,8 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
+ /* Update local copy of current mac address. */
+ memcpy(qdev->current_mac_addr, ndev->dev_addr, ndev->addr_len);
status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
if (status)
@@ -3961,7 +4312,7 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p)
status = ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr,
MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ);
if (status)
- QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n");
+ netif_err(qdev, hw, qdev->ndev, "Failed to load MAC address.\n");
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
return status;
}
@@ -3994,8 +4345,8 @@ static void ql_asic_reset_work(struct work_struct *work)
rtnl_unlock();
return;
error:
- QPRINTK(qdev, IFUP, ALERT,
- "Driver up/down cycle failed, closing device\n");
+ netif_alert(qdev, ifup, qdev->ndev,
+ "Driver up/down cycle failed, closing device\n");
set_bit(QL_ADAPTER_UP, &qdev->flags);
dev_close(qdev->ndev);
@@ -4094,6 +4445,7 @@ static void ql_release_all(struct pci_dev *pdev)
iounmap(qdev->reg_base);
if (qdev->doorbell_area)
iounmap(qdev->doorbell_area);
+ vfree(qdev->mpi_coredump);
pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
}
@@ -4119,7 +4471,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
err = pcie_set_readrq(pdev, 4096);
if (err) {
dev_err(&pdev->dev, "Set readrq failed.\n");
- goto err_out;
+ goto err_out1;
}
err = pci_request_regions(pdev, DRV_NAME);
@@ -4140,7 +4492,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
if (err) {
dev_err(&pdev->dev, "No usable DMA configuration.\n");
- goto err_out;
+ goto err_out2;
}
/* Set PCIe reset type for EEH to fundamental. */
@@ -4152,7 +4504,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
if (!qdev->reg_base) {
dev_err(&pdev->dev, "Register mapping failed.\n");
err = -ENOMEM;
- goto err_out;
+ goto err_out2;
}
qdev->doorbell_area_size = pci_resource_len(pdev, 3);
@@ -4162,27 +4514,40 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
if (!qdev->doorbell_area) {
dev_err(&pdev->dev, "Doorbell register mapping failed.\n");
err = -ENOMEM;
- goto err_out;
+ goto err_out2;
}
err = ql_get_board_info(qdev);
if (err) {
dev_err(&pdev->dev, "Register access failed.\n");
err = -EIO;
- goto err_out;
+ goto err_out2;
}
qdev->msg_enable = netif_msg_init(debug, default_msg);
spin_lock_init(&qdev->hw_lock);
spin_lock_init(&qdev->stats_lock);
+ if (qlge_mpi_coredump) {
+ qdev->mpi_coredump =
+ vmalloc(sizeof(struct ql_mpi_coredump));
+ if (qdev->mpi_coredump == NULL) {
+ dev_err(&pdev->dev, "Coredump alloc failed.\n");
+ err = -ENOMEM;
+ goto err_out2;
+ }
+ if (qlge_force_coredump)
+ set_bit(QL_FRC_COREDUMP, &qdev->flags);
+ }
/* make sure the EEPROM is good */
err = qdev->nic_ops->get_flash(qdev);
if (err) {
dev_err(&pdev->dev, "Invalid FLASH.\n");
- goto err_out;
+ goto err_out2;
}
memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
+ /* Keep local copy of current mac address. */
+ memcpy(qdev->current_mac_addr, ndev->dev_addr, ndev->addr_len);
/* Set up the default ring sizes. */
qdev->tx_ring_size = NUM_TX_RING_ENTRIES;
@@ -4204,6 +4569,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work);
INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work);
INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work);
+ INIT_DELAYED_WORK(&qdev->mpi_core_to_log, ql_mpi_core_to_log);
init_completion(&qdev->ide_completion);
if (!cards_found) {
@@ -4212,8 +4578,9 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
DRV_NAME, DRV_VERSION);
}
return 0;
-err_out:
+err_out2:
ql_release_all(pdev);
+err_out1:
pci_disable_device(pdev);
return err;
}
@@ -4233,6 +4600,21 @@ static const struct net_device_ops qlge_netdev_ops = {
.ndo_vlan_rx_kill_vid = qlge_vlan_rx_kill_vid,
};
+static void ql_timer(unsigned long data)
+{
+ struct ql_adapter *qdev = (struct ql_adapter *)data;
+ u32 var = 0;
+
+ var = ql_read32(qdev, STS);
+ if (pci_channel_offline(qdev->pdev)) {
+ netif_err(qdev, ifup, qdev->ndev, "EEH STS = 0x%.08x.\n", var);
+ return;
+ }
+
+ qdev->timer.expires = jiffies + (5*HZ);
+ add_timer(&qdev->timer);
+}
+
static int __devinit qlge_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_entry)
{
@@ -4284,6 +4666,14 @@ static int __devinit qlge_probe(struct pci_dev *pdev,
pci_disable_device(pdev);
return err;
}
+ /* Start up the timer to trigger EEH if
+ * the bus goes dead
+ */
+ init_timer_deferrable(&qdev->timer);
+ qdev->timer.data = (unsigned long)qdev;
+ qdev->timer.function = ql_timer;
+ qdev->timer.expires = jiffies + (5*HZ);
+ add_timer(&qdev->timer);
ql_link_off(qdev);
ql_display_dev_info(ndev);
atomic_set(&qdev->lb_count, 0);
@@ -4304,6 +4694,8 @@ int ql_clean_lb_rx_ring(struct rx_ring *rx_ring, int budget)
static void __devexit qlge_remove(struct pci_dev *pdev)
{
struct net_device *ndev = pci_get_drvdata(pdev);
+ struct ql_adapter *qdev = netdev_priv(ndev);
+ del_timer_sync(&qdev->timer);
unregister_netdev(ndev);
ql_release_all(pdev);
pci_disable_device(pdev);
@@ -4326,6 +4718,7 @@ static void ql_eeh_close(struct net_device *ndev)
cancel_delayed_work_sync(&qdev->mpi_reset_work);
cancel_delayed_work_sync(&qdev->mpi_work);
cancel_delayed_work_sync(&qdev->mpi_idc_work);
+ cancel_delayed_work_sync(&qdev->mpi_core_to_log);
cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
for (i = 0; i < qdev->rss_ring_count; i++)
@@ -4345,6 +4738,7 @@ static pci_ers_result_t qlge_io_error_detected(struct pci_dev *pdev,
enum pci_channel_state state)
{
struct net_device *ndev = pci_get_drvdata(pdev);
+ struct ql_adapter *qdev = netdev_priv(ndev);
switch (state) {
case pci_channel_io_normal:
@@ -4358,6 +4752,8 @@ static pci_ers_result_t qlge_io_error_detected(struct pci_dev *pdev,
case pci_channel_io_perm_failure:
dev_err(&pdev->dev,
"%s: pci_channel_io_perm_failure.\n", __func__);
+ ql_eeh_close(ndev);
+ set_bit(QL_EEH_FATAL, &qdev->flags);
return PCI_ERS_RESULT_DISCONNECT;
}
@@ -4380,11 +4776,18 @@ static pci_ers_result_t qlge_io_slot_reset(struct pci_dev *pdev)
pci_restore_state(pdev);
if (pci_enable_device(pdev)) {
- QPRINTK(qdev, IFUP, ERR,
- "Cannot re-enable PCI device after reset.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Cannot re-enable PCI device after reset.\n");
return PCI_ERS_RESULT_DISCONNECT;
}
pci_set_master(pdev);
+
+ if (ql_adapter_reset(qdev)) {
+ netif_err(qdev, drv, qdev->ndev, "reset FAILED!\n");
+ set_bit(QL_EEH_FATAL, &qdev->flags);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
return PCI_ERS_RESULT_RECOVERED;
}
@@ -4394,19 +4797,19 @@ static void qlge_io_resume(struct pci_dev *pdev)
struct ql_adapter *qdev = netdev_priv(ndev);
int err = 0;
- if (ql_adapter_reset(qdev))
- QPRINTK(qdev, DRV, ERR, "reset FAILED!\n");
if (netif_running(ndev)) {
err = qlge_open(ndev);
if (err) {
- QPRINTK(qdev, IFUP, ERR,
- "Device initialization failed after reset.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Device initialization failed after reset.\n");
return;
}
} else {
- QPRINTK(qdev, IFUP, ERR,
- "Device was not running prior to EEH.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Device was not running prior to EEH.\n");
}
+ qdev->timer.expires = jiffies + (5*HZ);
+ add_timer(&qdev->timer);
netif_device_attach(ndev);
}
@@ -4423,6 +4826,7 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state)
int err;
netif_device_detach(ndev);
+ del_timer_sync(&qdev->timer);
if (netif_running(ndev)) {
err = ql_adapter_down(qdev);
@@ -4453,7 +4857,7 @@ static int qlge_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
err = pci_enable_device(pdev);
if (err) {
- QPRINTK(qdev, IFUP, ERR, "Cannot enable PCI device from suspend\n");
+ netif_err(qdev, ifup, qdev->ndev, "Cannot enable PCI device from suspend\n");
return err;
}
pci_set_master(pdev);
@@ -4467,6 +4871,8 @@ static int qlge_resume(struct pci_dev *pdev)
return err;
}
+ qdev->timer.expires = jiffies + (5*HZ);
+ add_timer(&qdev->timer);
netif_device_attach(ndev);
return 0;
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index e2b2286102d4..3c00462a5d22 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -1,5 +1,54 @@
#include "qlge.h"
+int ql_unpause_mpi_risc(struct ql_adapter *qdev)
+{
+ u32 tmp;
+
+ /* Un-pause the RISC */
+ tmp = ql_read32(qdev, CSR);
+ if (!(tmp & CSR_RP))
+ return -EIO;
+
+ ql_write32(qdev, CSR, CSR_CMD_CLR_PAUSE);
+ return 0;
+}
+
+int ql_pause_mpi_risc(struct ql_adapter *qdev)
+{
+ u32 tmp;
+ int count = UDELAY_COUNT;
+
+ /* Pause the RISC */
+ ql_write32(qdev, CSR, CSR_CMD_SET_PAUSE);
+ do {
+ tmp = ql_read32(qdev, CSR);
+ if (tmp & CSR_RP)
+ break;
+ mdelay(UDELAY_DELAY);
+ count--;
+ } while (count);
+ return (count == 0) ? -ETIMEDOUT : 0;
+}
+
+int ql_hard_reset_mpi_risc(struct ql_adapter *qdev)
+{
+ u32 tmp;
+ int count = UDELAY_COUNT;
+
+ /* Reset the RISC */
+ ql_write32(qdev, CSR, CSR_CMD_SET_RST);
+ do {
+ tmp = ql_read32(qdev, CSR);
+ if (tmp & CSR_RR) {
+ ql_write32(qdev, CSR, CSR_CMD_CLR_RST);
+ break;
+ }
+ mdelay(UDELAY_DELAY);
+ count--;
+ } while (count);
+ return (count == 0) ? -ETIMEDOUT : 0;
+}
+
int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data)
{
int status;
@@ -45,6 +94,35 @@ int ql_soft_reset_mpi_risc(struct ql_adapter *qdev)
return status;
}
+/* Determine if we are in charge of the firwmare. If
+ * we are the lower of the 2 NIC pcie functions, or if
+ * we are the higher function and the lower function
+ * is not enabled.
+ */
+int ql_own_firmware(struct ql_adapter *qdev)
+{
+ u32 temp;
+
+ /* If we are the lower of the 2 NIC functions
+ * on the chip the we are responsible for
+ * core dump and firmware reset after an error.
+ */
+ if (qdev->func < qdev->alt_func)
+ return 1;
+
+ /* If we are the higher of the 2 NIC functions
+ * on the chip and the lower function is not
+ * enabled, then we are responsible for
+ * core dump and firmware reset after an error.
+ */
+ temp = ql_read32(qdev, STS);
+ if (!(temp & (1 << (8 + qdev->alt_func))))
+ return 1;
+
+ return 0;
+
+}
+
static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
{
int i, status;
@@ -57,7 +135,7 @@ static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
ql_read_mpi_reg(qdev, qdev->mailbox_out + i,
&mbcp->mbox_out[i]);
if (status) {
- QPRINTK(qdev, DRV, ERR, "Failed mailbox read.\n");
+ netif_err(qdev, drv, qdev->ndev, "Failed mailbox read.\n");
break;
}
}
@@ -130,7 +208,7 @@ static int ql_idc_req_aen(struct ql_adapter *qdev)
int status;
struct mbox_params *mbcp = &qdev->idc_mbc;
- QPRINTK(qdev, DRV, ERR, "Enter!\n");
+ netif_err(qdev, drv, qdev->ndev, "Enter!\n");
/* Get the status data and start up a thread to
* handle the request.
*/
@@ -138,8 +216,8 @@ static int ql_idc_req_aen(struct ql_adapter *qdev)
mbcp->out_count = 4;
status = ql_get_mb_sts(qdev, mbcp);
if (status) {
- QPRINTK(qdev, DRV, ERR,
- "Could not read MPI, resetting ASIC!\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Could not read MPI, resetting ASIC!\n");
ql_queue_asic_error(qdev);
} else {
/* Begin polled mode early so
@@ -162,8 +240,8 @@ static int ql_idc_cmplt_aen(struct ql_adapter *qdev)
mbcp->out_count = 4;
status = ql_get_mb_sts(qdev, mbcp);
if (status) {
- QPRINTK(qdev, DRV, ERR,
- "Could not read MPI, resetting RISC!\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Could not read MPI, resetting RISC!\n");
ql_queue_fw_error(qdev);
} else
/* Wake up the sleeping mpi_idc_work thread that is
@@ -181,13 +259,13 @@ static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp)
status = ql_get_mb_sts(qdev, mbcp);
if (status) {
- QPRINTK(qdev, DRV, ERR,
- "%s: Could not get mailbox status.\n", __func__);
+ netif_err(qdev, drv, qdev->ndev,
+ "%s: Could not get mailbox status.\n", __func__);
return;
}
qdev->link_status = mbcp->mbox_out[1];
- QPRINTK(qdev, DRV, ERR, "Link Up.\n");
+ netif_err(qdev, drv, qdev->ndev, "Link Up.\n");
/* If we're coming back from an IDC event
* then set up the CAM and frame routing.
@@ -195,8 +273,8 @@ static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp)
if (test_bit(QL_CAM_RT_SET, &qdev->flags)) {
status = ql_cam_route_initialize(qdev);
if (status) {
- QPRINTK(qdev, IFUP, ERR,
- "Failed to init CAM/Routing tables.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to init CAM/Routing tables.\n");
return;
} else
clear_bit(QL_CAM_RT_SET, &qdev->flags);
@@ -207,7 +285,7 @@ static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp)
* to our liking.
*/
if (!test_bit(QL_PORT_CFG, &qdev->flags)) {
- QPRINTK(qdev, DRV, ERR, "Queue Port Config Worker!\n");
+ netif_err(qdev, drv, qdev->ndev, "Queue Port Config Worker!\n");
set_bit(QL_PORT_CFG, &qdev->flags);
/* Begin polled mode early so
* we don't get another interrupt
@@ -229,7 +307,7 @@ static void ql_link_down(struct ql_adapter *qdev, struct mbox_params *mbcp)
status = ql_get_mb_sts(qdev, mbcp);
if (status)
- QPRINTK(qdev, DRV, ERR, "Link down AEN broken!\n");
+ netif_err(qdev, drv, qdev->ndev, "Link down AEN broken!\n");
ql_link_off(qdev);
}
@@ -242,9 +320,9 @@ static int ql_sfp_in(struct ql_adapter *qdev, struct mbox_params *mbcp)
status = ql_get_mb_sts(qdev, mbcp);
if (status)
- QPRINTK(qdev, DRV, ERR, "SFP in AEN broken!\n");
+ netif_err(qdev, drv, qdev->ndev, "SFP in AEN broken!\n");
else
- QPRINTK(qdev, DRV, ERR, "SFP insertion detected.\n");
+ netif_err(qdev, drv, qdev->ndev, "SFP insertion detected.\n");
return status;
}
@@ -257,9 +335,9 @@ static int ql_sfp_out(struct ql_adapter *qdev, struct mbox_params *mbcp)
status = ql_get_mb_sts(qdev, mbcp);
if (status)
- QPRINTK(qdev, DRV, ERR, "SFP out AEN broken!\n");
+ netif_err(qdev, drv, qdev->ndev, "SFP out AEN broken!\n");
else
- QPRINTK(qdev, DRV, ERR, "SFP removal detected.\n");
+ netif_err(qdev, drv, qdev->ndev, "SFP removal detected.\n");
return status;
}
@@ -272,13 +350,13 @@ static int ql_aen_lost(struct ql_adapter *qdev, struct mbox_params *mbcp)
status = ql_get_mb_sts(qdev, mbcp);
if (status)
- QPRINTK(qdev, DRV, ERR, "Lost AEN broken!\n");
+ netif_err(qdev, drv, qdev->ndev, "Lost AEN broken!\n");
else {
int i;
- QPRINTK(qdev, DRV, ERR, "Lost AEN detected.\n");
+ netif_err(qdev, drv, qdev->ndev, "Lost AEN detected.\n");
for (i = 0; i < mbcp->out_count; i++)
- QPRINTK(qdev, DRV, ERR, "mbox_out[%d] = 0x%.08x.\n",
- i, mbcp->mbox_out[i]);
+ netif_err(qdev, drv, qdev->ndev, "mbox_out[%d] = 0x%.08x.\n",
+ i, mbcp->mbox_out[i]);
}
@@ -293,15 +371,15 @@ static void ql_init_fw_done(struct ql_adapter *qdev, struct mbox_params *mbcp)
status = ql_get_mb_sts(qdev, mbcp);
if (status) {
- QPRINTK(qdev, DRV, ERR, "Firmware did not initialize!\n");
+ netif_err(qdev, drv, qdev->ndev, "Firmware did not initialize!\n");
} else {
- QPRINTK(qdev, DRV, ERR, "Firmware Revision = 0x%.08x.\n",
- mbcp->mbox_out[1]);
+ netif_err(qdev, drv, qdev->ndev, "Firmware Revision = 0x%.08x.\n",
+ mbcp->mbox_out[1]);
qdev->fw_rev_id = mbcp->mbox_out[1];
status = ql_cam_route_initialize(qdev);
if (status)
- QPRINTK(qdev, IFUP, ERR,
- "Failed to init CAM/Routing tables.\n");
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to init CAM/Routing tables.\n");
}
}
@@ -320,8 +398,8 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp)
mbcp->out_count = 1;
status = ql_get_mb_sts(qdev, mbcp);
if (status) {
- QPRINTK(qdev, DRV, ERR,
- "Could not read MPI, resetting ASIC!\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Could not read MPI, resetting ASIC!\n");
ql_queue_asic_error(qdev);
goto end;
}
@@ -410,15 +488,14 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp)
mbcp->mbox_out[0] = MB_CMD_STS_ERR;
return status;
}
- QPRINTK(qdev, DRV, ERR,
- "Firmware initialization failed.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Firmware initialization failed.\n");
status = -EIO;
ql_queue_fw_error(qdev);
break;
case AEN_SYS_ERR:
- QPRINTK(qdev, DRV, ERR,
- "System Error.\n");
+ netif_err(qdev, drv, qdev->ndev, "System Error.\n");
ql_queue_fw_error(qdev);
status = -EIO;
break;
@@ -431,8 +508,8 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp)
/* Need to support AEN 8110 */
break;
default:
- QPRINTK(qdev, DRV, ERR,
- "Unsupported AE %.08x.\n", mbcp->mbox_out[0]);
+ netif_err(qdev, drv, qdev->ndev,
+ "Unsupported AE %.08x.\n", mbcp->mbox_out[0]);
/* Clear the MPI firmware status. */
}
end:
@@ -505,8 +582,8 @@ static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp)
goto done;
} while (time_before(jiffies, count));
- QPRINTK(qdev, DRV, ERR,
- "Timed out waiting for mailbox complete.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Timed out waiting for mailbox complete.\n");
status = -ETIMEDOUT;
goto end;
@@ -529,6 +606,22 @@ end:
return status;
}
+int ql_mb_sys_err(struct ql_adapter *qdev)
+{
+ struct mbox_params mbc;
+ struct mbox_params *mbcp = &mbc;
+ int status;
+
+ memset(mbcp, 0, sizeof(struct mbox_params));
+
+ mbcp->in_count = 1;
+ mbcp->out_count = 0;
+
+ mbcp->mbox_in[0] = MB_CMD_MAKE_SYS_ERR;
+
+ status = ql_mailbox_command(qdev, mbcp);
+ return status;
+}
/* Get MPI firmware version. This will be used for
* driver banner and for ethtool info.
@@ -552,8 +645,8 @@ int ql_mb_about_fw(struct ql_adapter *qdev)
return status;
if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
- QPRINTK(qdev, DRV, ERR,
- "Failed about firmware command\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed about firmware command\n");
status = -EIO;
}
@@ -584,8 +677,8 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev)
return status;
if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
- QPRINTK(qdev, DRV, ERR,
- "Failed Get Firmware State.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed Get Firmware State.\n");
status = -EIO;
}
@@ -594,8 +687,8 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev)
* happen.
*/
if (mbcp->mbox_out[1] & 1) {
- QPRINTK(qdev, DRV, ERR,
- "Firmware waiting for initialization.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Firmware waiting for initialization.\n");
status = -EIO;
}
@@ -627,8 +720,7 @@ int ql_mb_idc_ack(struct ql_adapter *qdev)
return status;
if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
- QPRINTK(qdev, DRV, ERR,
- "Failed IDC ACK send.\n");
+ netif_err(qdev, drv, qdev->ndev, "Failed IDC ACK send.\n");
status = -EIO;
}
return status;
@@ -659,16 +751,72 @@ int ql_mb_set_port_cfg(struct ql_adapter *qdev)
return status;
if (mbcp->mbox_out[0] == MB_CMD_STS_INTRMDT) {
- QPRINTK(qdev, DRV, ERR,
- "Port Config sent, wait for IDC.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Port Config sent, wait for IDC.\n");
} else if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
- QPRINTK(qdev, DRV, ERR,
- "Failed Set Port Configuration.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed Set Port Configuration.\n");
status = -EIO;
}
return status;
}
+int ql_mb_dump_ram(struct ql_adapter *qdev, u64 req_dma, u32 addr,
+ u32 size)
+{
+ int status = 0;
+ struct mbox_params mbc;
+ struct mbox_params *mbcp = &mbc;
+
+ memset(mbcp, 0, sizeof(struct mbox_params));
+
+ mbcp->in_count = 9;
+ mbcp->out_count = 1;
+
+ mbcp->mbox_in[0] = MB_CMD_DUMP_RISC_RAM;
+ mbcp->mbox_in[1] = LSW(addr);
+ mbcp->mbox_in[2] = MSW(req_dma);
+ mbcp->mbox_in[3] = LSW(req_dma);
+ mbcp->mbox_in[4] = MSW(size);
+ mbcp->mbox_in[5] = LSW(size);
+ mbcp->mbox_in[6] = MSW(MSD(req_dma));
+ mbcp->mbox_in[7] = LSW(MSD(req_dma));
+ mbcp->mbox_in[8] = MSW(addr);
+
+
+ status = ql_mailbox_command(qdev, mbcp);
+ if (status)
+ return status;
+
+ if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
+ netif_err(qdev, drv, qdev->ndev, "Failed to dump risc RAM.\n");
+ status = -EIO;
+ }
+ return status;
+}
+
+/* Issue a mailbox command to dump RISC RAM. */
+int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf,
+ u32 ram_addr, int word_count)
+{
+ int status;
+ char *my_buf;
+ dma_addr_t buf_dma;
+
+ my_buf = pci_alloc_consistent(qdev->pdev, word_count * sizeof(u32),
+ &buf_dma);
+ if (!my_buf)
+ return -EIO;
+
+ status = ql_mb_dump_ram(qdev, buf_dma, ram_addr, word_count);
+ if (!status)
+ memcpy(buf, my_buf, word_count * sizeof(u32));
+
+ pci_free_consistent(qdev->pdev, word_count * sizeof(u32), my_buf,
+ buf_dma);
+ return status;
+}
+
/* Get link settings and maximum frame size settings
* for the current port.
* Most likely will block.
@@ -691,12 +839,12 @@ int ql_mb_get_port_cfg(struct ql_adapter *qdev)
return status;
if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
- QPRINTK(qdev, DRV, ERR,
- "Failed Get Port Configuration.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed Get Port Configuration.\n");
status = -EIO;
} else {
- QPRINTK(qdev, DRV, DEBUG,
- "Passed Get Port Configuration.\n");
+ netif_printk(qdev, drv, KERN_DEBUG, qdev->ndev,
+ "Passed Get Port Configuration.\n");
qdev->link_config = mbcp->mbox_out[1];
qdev->max_frame_size = mbcp->mbox_out[2];
}
@@ -723,8 +871,7 @@ int ql_mb_wol_mode(struct ql_adapter *qdev, u32 wol)
return status;
if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
- QPRINTK(qdev, DRV, ERR,
- "Failed to set WOL mode.\n");
+ netif_err(qdev, drv, qdev->ndev, "Failed to set WOL mode.\n");
status = -EIO;
}
return status;
@@ -766,8 +913,7 @@ int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol)
return status;
if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
- QPRINTK(qdev, DRV, ERR,
- "Failed to set WOL mode.\n");
+ netif_err(qdev, drv, qdev->ndev, "Failed to set WOL mode.\n");
status = -EIO;
}
return status;
@@ -793,8 +939,7 @@ static int ql_idc_wait(struct ql_adapter *qdev)
wait_for_completion_timeout(&qdev->ide_completion,
wait_time);
if (!wait_time) {
- QPRINTK(qdev, DRV, ERR,
- "IDC Timeout.\n");
+ netif_err(qdev, drv, qdev->ndev, "IDC Timeout.\n");
break;
}
/* Now examine the response from the IDC process.
@@ -802,18 +947,17 @@ static int ql_idc_wait(struct ql_adapter *qdev)
* more wait time.
*/
if (mbcp->mbox_out[0] == AEN_IDC_EXT) {
- QPRINTK(qdev, DRV, ERR,
- "IDC Time Extension from function.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "IDC Time Extension from function.\n");
wait_time += (mbcp->mbox_out[1] >> 8) & 0x0000000f;
} else if (mbcp->mbox_out[0] == AEN_IDC_CMPLT) {
- QPRINTK(qdev, DRV, ERR,
- "IDC Success.\n");
+ netif_err(qdev, drv, qdev->ndev, "IDC Success.\n");
status = 0;
break;
} else {
- QPRINTK(qdev, DRV, ERR,
- "IDC: Invalid State 0x%.04x.\n",
- mbcp->mbox_out[0]);
+ netif_err(qdev, drv, qdev->ndev,
+ "IDC: Invalid State 0x%.04x.\n",
+ mbcp->mbox_out[0]);
status = -EIO;
break;
}
@@ -842,8 +986,8 @@ int ql_mb_set_led_cfg(struct ql_adapter *qdev, u32 led_config)
return status;
if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
- QPRINTK(qdev, DRV, ERR,
- "Failed to set LED Configuration.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed to set LED Configuration.\n");
status = -EIO;
}
@@ -868,8 +1012,8 @@ int ql_mb_get_led_cfg(struct ql_adapter *qdev)
return status;
if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
- QPRINTK(qdev, DRV, ERR,
- "Failed to get LED Configuration.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed to get LED Configuration.\n");
status = -EIO;
} else
qdev->led_config = mbcp->mbox_out[1];
@@ -899,16 +1043,16 @@ int ql_mb_set_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 control)
return status;
if (mbcp->mbox_out[0] == MB_CMD_STS_INVLD_CMD) {
- QPRINTK(qdev, DRV, ERR,
- "Command not supported by firmware.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Command not supported by firmware.\n");
status = -EINVAL;
} else if (mbcp->mbox_out[0] == MB_CMD_STS_ERR) {
/* This indicates that the firmware is
* already in the state we are trying to
* change it to.
*/
- QPRINTK(qdev, DRV, ERR,
- "Command parameters make no change.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Command parameters make no change.\n");
}
return status;
}
@@ -938,12 +1082,12 @@ static int ql_mb_get_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 *control)
}
if (mbcp->mbox_out[0] == MB_CMD_STS_INVLD_CMD) {
- QPRINTK(qdev, DRV, ERR,
- "Command not supported by firmware.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Command not supported by firmware.\n");
status = -EINVAL;
} else if (mbcp->mbox_out[0] == MB_CMD_STS_ERR) {
- QPRINTK(qdev, DRV, ERR,
- "Failed to get MPI traffic control.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Failed to get MPI traffic control.\n");
status = -EIO;
}
return status;
@@ -999,8 +1143,8 @@ void ql_mpi_port_cfg_work(struct work_struct *work)
status = ql_mb_get_port_cfg(qdev);
rtnl_unlock();
if (status) {
- QPRINTK(qdev, DRV, ERR,
- "Bug: Failed to get port config data.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Bug: Failed to get port config data.\n");
goto err;
}
@@ -1013,8 +1157,8 @@ void ql_mpi_port_cfg_work(struct work_struct *work)
qdev->max_frame_size = CFG_DEFAULT_MAX_FRAME_SIZE;
status = ql_set_port_cfg(qdev);
if (status) {
- QPRINTK(qdev, DRV, ERR,
- "Bug: Failed to set port config data.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Bug: Failed to set port config data.\n");
goto err;
}
end:
@@ -1046,8 +1190,8 @@ void ql_mpi_idc_work(struct work_struct *work)
switch (aen) {
default:
- QPRINTK(qdev, DRV, ERR,
- "Bug: Unhandled IDC action.\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Bug: Unhandled IDC action.\n");
break;
case MB_CMD_PORT_RESET:
case MB_CMD_STOP_FW:
@@ -1062,11 +1206,11 @@ void ql_mpi_idc_work(struct work_struct *work)
if (timeout) {
status = ql_mb_idc_ack(qdev);
if (status)
- QPRINTK(qdev, DRV, ERR,
- "Bug: No pending IDC!\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Bug: No pending IDC!\n");
} else {
- QPRINTK(qdev, DRV, DEBUG,
- "IDC ACK not required\n");
+ netif_printk(qdev, drv, KERN_DEBUG, qdev->ndev,
+ "IDC ACK not required\n");
status = 0; /* success */
}
break;
@@ -1095,11 +1239,11 @@ void ql_mpi_idc_work(struct work_struct *work)
if (timeout) {
status = ql_mb_idc_ack(qdev);
if (status)
- QPRINTK(qdev, DRV, ERR,
- "Bug: No pending IDC!\n");
+ netif_err(qdev, drv, qdev->ndev,
+ "Bug: No pending IDC!\n");
} else {
- QPRINTK(qdev, DRV, DEBUG,
- "IDC ACK not required\n");
+ netif_printk(qdev, drv, KERN_DEBUG, qdev->ndev,
+ "IDC ACK not required\n");
status = 0; /* success */
}
break;
@@ -1143,5 +1287,19 @@ void ql_mpi_reset_work(struct work_struct *work)
cancel_delayed_work_sync(&qdev->mpi_work);
cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
cancel_delayed_work_sync(&qdev->mpi_idc_work);
+ /* If we're not the dominant NIC function,
+ * then there is nothing to do.
+ */
+ if (!ql_own_firmware(qdev)) {
+ netif_err(qdev, drv, qdev->ndev, "Don't own firmware!\n");
+ return;
+ }
+
+ if (!ql_core_dump(qdev, qdev->mpi_coredump)) {
+ netif_err(qdev, drv, qdev->ndev, "Core is dumped!\n");
+ qdev->core_is_dumped = 1;
+ queue_delayed_work(qdev->workqueue,
+ &qdev->mpi_core_to_log, 5 * HZ);
+ }
ql_soft_reset_mpi_risc(qdev);
}
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index f03e2e4a15a8..15d5373dc8f3 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -938,7 +938,7 @@ static void r6040_multicast_list(struct net_device *dev)
u16 *adrp;
u16 reg;
unsigned long flags;
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
int i;
/* MAC Address */
@@ -958,25 +958,24 @@ static void r6040_multicast_list(struct net_device *dev)
}
/* Too many multicast addresses
* accept all traffic */
- else if ((dev->mc_count > MCAST_MAX) || (dev->flags & IFF_ALLMULTI))
+ else if ((netdev_mc_count(dev) > MCAST_MAX) ||
+ (dev->flags & IFF_ALLMULTI))
reg |= 0x0020;
iowrite16(reg, ioaddr);
spin_unlock_irqrestore(&lp->lock, flags);
/* Build the hash table */
- if (dev->mc_count > MCAST_MAX) {
+ if (netdev_mc_count(dev) > MCAST_MAX) {
u16 hash_table[4];
u32 crc;
for (i = 0; i < 4; i++)
hash_table[i] = 0;
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
char *addrs = dmi->dmi_addr;
- dmi = dmi->next;
-
if (!(*addrs & 1))
continue;
@@ -994,17 +993,19 @@ static void r6040_multicast_list(struct net_device *dev)
iowrite16(hash_table[3], ioaddr + MAR3);
}
/* Multicast Address 1~4 case */
- for (i = 0, dmi; (i < dev->mc_count) && (i < MCAST_MAX); i++) {
- adrp = (u16 *)dmi->dmi_addr;
- iowrite16(adrp[0], ioaddr + MID_1L + 8*i);
- iowrite16(adrp[1], ioaddr + MID_1M + 8*i);
- iowrite16(adrp[2], ioaddr + MID_1H + 8*i);
- dmi = dmi->next;
- }
- for (i = dev->mc_count; i < MCAST_MAX; i++) {
- iowrite16(0xffff, ioaddr + MID_0L + 8*i);
- iowrite16(0xffff, ioaddr + MID_0M + 8*i);
- iowrite16(0xffff, ioaddr + MID_0H + 8*i);
+ i = 0;
+ netdev_for_each_mc_addr(dmi, dev) {
+ if (i < MCAST_MAX) {
+ adrp = (u16 *) dmi->dmi_addr;
+ iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
+ iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
+ iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
+ } else {
+ iowrite16(0xffff, ioaddr + MID_0L + 8 * i);
+ iowrite16(0xffff, ioaddr + MID_0M + 8 * i);
+ iowrite16(0xffff, ioaddr + MID_0H + 8 * i);
+ }
+ i++;
}
}
@@ -1222,7 +1223,7 @@ static void __devexit r6040_remove_one(struct pci_dev *pdev)
}
-static struct pci_device_id r6040_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(r6040_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_RDC, 0x6040) },
{ 0 }
};
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 60f96c468a24..9d3ebf3e975e 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -168,7 +168,7 @@ static void rtl_hw_start_8169(struct net_device *);
static void rtl_hw_start_8168(struct net_device *);
static void rtl_hw_start_8101(struct net_device *);
-static struct pci_device_id rtl8169_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 },
@@ -187,7 +187,7 @@ static struct pci_device_id rtl8169_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
static int rx_copybreak = 200;
-static int use_dac;
+static int use_dac = -1;
static struct {
u32 msg_enable;
} debug = { -1 };
@@ -511,7 +511,8 @@ MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
module_param(rx_copybreak, int, 0);
MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
module_param(use_dac, int, 0);
-MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot.");
+MODULE_PARM_DESC(use_dac, "Enable PCI DAC. -1 defaults on for PCI Express only."
+" Unsafe on 32 bit PCI slot.");
module_param_named(debug, debug.msg_enable, int, 0);
MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)");
MODULE_LICENSE("GPL");
@@ -744,12 +745,10 @@ static void rtl8169_check_link_status(struct net_device *dev,
spin_lock_irqsave(&tp->lock, flags);
if (tp->link_ok(ioaddr)) {
netif_carrier_on(dev);
- if (netif_msg_ifup(tp))
- printk(KERN_INFO PFX "%s: link up\n", dev->name);
+ netif_info(tp, ifup, dev, "link up\n");
} else {
- if (netif_msg_ifdown(tp))
- printk(KERN_INFO PFX "%s: link down\n", dev->name);
netif_carrier_off(dev);
+ netif_info(tp, ifdown, dev, "link down\n");
}
spin_unlock_irqrestore(&tp->lock, flags);
}
@@ -862,11 +861,8 @@ static int rtl8169_set_speed_tbi(struct net_device *dev,
} else if (autoneg == AUTONEG_ENABLE)
RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
else {
- if (netif_msg_link(tp)) {
- printk(KERN_WARNING "%s: "
- "incorrect speed setting refused in TBI mode\n",
- dev->name);
- }
+ netif_warn(tp, link, dev,
+ "incorrect speed setting refused in TBI mode\n");
ret = -EOPNOTSUPP;
}
@@ -901,9 +897,9 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
(tp->mac_version != RTL_GIGA_MAC_VER_15) &&
(tp->mac_version != RTL_GIGA_MAC_VER_16)) {
giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
- } else if (netif_msg_link(tp)) {
- printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n",
- dev->name);
+ } else {
+ netif_info(tp, link, dev,
+ "PHY does not support 1000Mbps\n");
}
bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
@@ -2705,8 +2701,7 @@ static void rtl8169_phy_timer(unsigned long __opaque)
if (tp->link_ok(ioaddr))
goto out_unlock;
- if (netif_msg_link(tp))
- printk(KERN_WARNING "%s: PHY reset until link up\n", dev->name);
+ netif_warn(tp, link, dev, "PHY reset until link up\n");
tp->phy_reset_enable(ioaddr);
@@ -2776,8 +2771,7 @@ static void rtl8169_phy_reset(struct net_device *dev,
return;
msleep(1);
}
- if (netif_msg_link(tp))
- printk(KERN_ERR "%s: PHY reset failed.\n", dev->name);
+ netif_err(tp, link, dev, "PHY reset failed\n");
}
static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
@@ -2811,8 +2805,8 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
*/
rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL);
- if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp))
- printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);
+ if (RTL_R8(PHYstatus) & TBI_Enable)
+ netif_info(tp, link, dev, "TBI auto-negotiating\n");
}
static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
@@ -2980,6 +2974,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
void __iomem *ioaddr;
unsigned int i;
int rc;
+ int this_use_dac = use_dac;
if (netif_msg_drv(&debug)) {
printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
@@ -3012,8 +3007,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* enable device (incl. PCI PM wakeup and hotplug setup) */
rc = pci_enable_device(pdev);
if (rc < 0) {
- if (netif_msg_probe(tp))
- dev_err(&pdev->dev, "enable failure\n");
+ netif_err(tp, probe, dev, "enable failure\n");
goto err_out_free_dev_1;
}
@@ -3023,45 +3017,46 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* make sure PCI base addr 1 is MMIO */
if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {
- if (netif_msg_probe(tp)) {
- dev_err(&pdev->dev,
- "region #%d not an MMIO resource, aborting\n",
- region);
- }
+ netif_err(tp, probe, dev,
+ "region #%d not an MMIO resource, aborting\n",
+ region);
rc = -ENODEV;
goto err_out_mwi_3;
}
/* check for weird/broken PCI region reporting */
if (pci_resource_len(pdev, region) < R8169_REGS_SIZE) {
- if (netif_msg_probe(tp)) {
- dev_err(&pdev->dev,
- "Invalid PCI region size(s), aborting\n");
- }
+ netif_err(tp, probe, dev,
+ "Invalid PCI region size(s), aborting\n");
rc = -ENODEV;
goto err_out_mwi_3;
}
rc = pci_request_regions(pdev, MODULENAME);
if (rc < 0) {
- if (netif_msg_probe(tp))
- dev_err(&pdev->dev, "could not request regions.\n");
+ netif_err(tp, probe, dev, "could not request regions\n");
goto err_out_mwi_3;
}
tp->cp_cmd = PCIMulRW | RxChkSum;
+ tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ if (!tp->pcie_cap)
+ netif_info(tp, probe, dev, "no PCI Express capability\n");
+
+ if (this_use_dac < 0)
+ this_use_dac = tp->pcie_cap != 0;
+
if ((sizeof(dma_addr_t) > 4) &&
- !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {
+ this_use_dac &&
+ !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ netif_info(tp, probe, dev, "using 64-bit DMA\n");
tp->cp_cmd |= PCIDAC;
dev->features |= NETIF_F_HIGHDMA;
} else {
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc < 0) {
- if (netif_msg_probe(tp)) {
- dev_err(&pdev->dev,
- "DMA configuration failed.\n");
- }
+ netif_err(tp, probe, dev, "DMA configuration failed\n");
goto err_out_free_res_4;
}
}
@@ -3069,16 +3064,11 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* ioremap MMIO region */
ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);
if (!ioaddr) {
- if (netif_msg_probe(tp))
- dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
+ netif_err(tp, probe, dev, "cannot remap MMIO, aborting\n");
rc = -EIO;
goto err_out_free_res_4;
}
- tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
- if (!tp->pcie_cap && netif_msg_probe(tp))
- dev_info(&pdev->dev, "no PCI Express capability\n");
-
RTL_W16(IntrMask, 0x0000);
/* Soft reset the chip. */
@@ -3100,10 +3090,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Use appropriate default if unknown */
if (tp->mac_version == RTL_GIGA_MAC_NONE) {
- if (netif_msg_probe(tp)) {
- dev_notice(&pdev->dev,
- "unknown MAC, using family default\n");
- }
+ netif_notice(tp, probe, dev,
+ "unknown MAC, using family default\n");
tp->mac_version = cfg->default_ver;
}
@@ -3185,19 +3173,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, dev);
- if (netif_msg_probe(tp)) {
- u32 xid = RTL_R32(TxConfig) & 0x9cf0f8ff;
-
- printk(KERN_INFO "%s: %s at 0x%lx, "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
- "XID %08x IRQ %d\n",
- dev->name,
- rtl_chip_info[tp->chipset].name,
- dev->base_addr,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5], xid, dev->irq);
- }
+ netif_info(tp, probe, dev, "%s at 0x%lx, %pM, XID %08x IRQ %d\n",
+ rtl_chip_info[tp->chipset].name,
+ dev->base_addr, dev->dev_addr,
+ (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq);
rtl8169_init_phy(dev, tp);
@@ -4136,10 +4115,10 @@ static void rtl8169_reinit_task(struct work_struct *work)
ret = rtl8169_open(dev);
if (unlikely(ret < 0)) {
- if (net_ratelimit() && netif_msg_drv(tp)) {
- printk(KERN_ERR PFX "%s: reinit failure (status = %d)."
- " Rescheduling.\n", dev->name, ret);
- }
+ if (net_ratelimit())
+ netif_err(tp, drv, dev,
+ "reinit failure (status = %d). Rescheduling\n",
+ ret);
rtl8169_schedule_work(dev, rtl8169_reinit_task);
}
@@ -4169,10 +4148,8 @@ static void rtl8169_reset_task(struct work_struct *work)
netif_wake_queue(dev);
rtl8169_check_link_status(dev, tp, tp->mmio_addr);
} else {
- if (net_ratelimit() && netif_msg_intr(tp)) {
- printk(KERN_EMERG PFX "%s: Rx buffers shortage\n",
- dev->name);
- }
+ if (net_ratelimit())
+ netif_emerg(tp, intr, dev, "Rx buffers shortage\n");
rtl8169_schedule_work(dev, rtl8169_reset_task);
}
@@ -4260,11 +4237,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
u32 opts1;
if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) {
- if (netif_msg_drv(tp)) {
- printk(KERN_ERR
- "%s: BUG! Tx Ring full when queue awake!\n",
- dev->name);
- }
+ netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
goto err_stop;
}
@@ -4297,7 +4270,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
tp->cur_tx += frags + 1;
- smp_wmb();
+ wmb();
RTL_W8(TxPoll, NPQ); /* set polling bit */
@@ -4326,11 +4299,8 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
pci_read_config_word(pdev, PCI_STATUS, &pci_status);
- if (netif_msg_intr(tp)) {
- printk(KERN_ERR
- "%s: PCI error (cmd = 0x%04x, status = 0x%04x).\n",
- dev->name, pci_cmd, pci_status);
- }
+ netif_err(tp, intr, dev, "PCI error (cmd = 0x%04x, status = 0x%04x)\n",
+ pci_cmd, pci_status);
/*
* The recovery sequence below admits a very elaborated explanation:
@@ -4354,8 +4324,7 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
/* The infamous DAC f*ckup only happens at boot time */
if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) {
- if (netif_msg_intr(tp))
- printk(KERN_INFO "%s: disabling PCI DAC.\n", dev->name);
+ netif_info(tp, intr, dev, "disabling PCI DAC\n");
tp->cp_cmd &= ~PCIDAC;
RTL_W16(CPlusCmd, tp->cp_cmd);
dev->features &= ~NETIF_F_HIGHDMA;
@@ -4482,11 +4451,8 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
if (status & DescOwn)
break;
if (unlikely(status & RxRES)) {
- if (netif_msg_rx_err(tp)) {
- printk(KERN_INFO
- "%s: Rx ERROR. status = %08x\n",
- dev->name, status);
- }
+ netif_info(tp, rx_err, dev, "Rx ERROR. status = %08x\n",
+ status);
dev->stats.rx_errors++;
if (status & (RxRWT | RxRUNT))
dev->stats.rx_length_errors++;
@@ -4549,8 +4515,8 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
tp->cur_rx = cur_rx;
delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx);
- if (!delta && count && netif_msg_intr(tp))
- printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name);
+ if (!delta && count)
+ netif_info(tp, intr, dev, "no Rx buffer allocated\n");
tp->dirty_rx += delta;
/*
@@ -4560,8 +4526,8 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
* after refill ?
* - how do others driver handle this condition (Uh oh...).
*/
- if ((tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) && netif_msg_intr(tp))
- printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name);
+ if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx)
+ netif_emerg(tp, intr, dev, "Rx buffers exhausted\n");
return count;
}
@@ -4616,10 +4582,9 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
if (likely(napi_schedule_prep(&tp->napi)))
__napi_schedule(&tp->napi);
- else if (netif_msg_intr(tp)) {
- printk(KERN_INFO "%s: interrupt %04x in poll\n",
- dev->name, status);
- }
+ else
+ netif_info(tp, intr, dev,
+ "interrupt %04x in poll\n", status);
}
/* We only get a new MSI interrupt when all active irq
@@ -4656,7 +4621,7 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
* until it does.
*/
tp->intr_mask = 0xffff;
- smp_wmb();
+ wmb();
RTL_W16(IntrMask, tp->intr_event);
}
@@ -4755,27 +4720,22 @@ static void rtl_set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC) {
/* Unconditionally log net taps. */
- if (netif_msg_link(tp)) {
- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
- dev->name);
- }
+ netif_notice(tp, link, dev, "Promiscuous mode enabled\n");
rx_mode =
AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
AcceptAllPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
- } else if ((dev->mc_count > multicast_filter_limit) ||
+ } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
(dev->flags & IFF_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
} else {
struct dev_mc_list *mclist;
- unsigned int i;
rx_mode = AcceptBroadcast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
rx_mode |= AcceptMulticast;
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 1c257098d0a6..266baf534964 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -1688,7 +1688,7 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
}
-static struct pci_device_id rr_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(rr_pci_tbl) = {
{ PCI_VENDOR_ID_ESSENTIAL, PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER,
PCI_ANY_ID, PCI_ANY_ID, },
{ 0,}
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index cc4218667cba..df70657260dd 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -523,7 +523,7 @@ module_param_array(rts_frm_len, uint, NULL, 0);
* S2IO device table.
* This table lists all the devices that this driver supports.
*/
-static struct pci_device_id s2io_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(s2io_tbl) = {
{PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN,
PCI_ANY_ID, PCI_ANY_ID},
{PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI,
@@ -923,8 +923,8 @@ static int init_shared_mem(struct s2io_nic *nic)
tmp_v_addr = mac_control->stats_mem;
mac_control->stats_info = (struct stat_block *)tmp_v_addr;
memset(tmp_v_addr, 0, size);
- DBG_PRINT(INIT_DBG, "%s: Ring Mem PHY: 0x%llx\n", dev->name,
- (unsigned long long)tmp_p_addr);
+ DBG_PRINT(INIT_DBG, "%s: Ring Mem PHY: 0x%llx\n",
+ dev_name(&nic->pdev->dev), (unsigned long long)tmp_p_addr);
mac_control->stats_info->sw_stat.mem_allocated += mem_allocated;
return SUCCESS;
}
@@ -3421,7 +3421,7 @@ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit,
break;
}
} else {
- if (!(val64 & busy_bit)) {
+ if (val64 & busy_bit) {
ret = SUCCESS;
break;
}
@@ -3480,7 +3480,7 @@ static void s2io_reset(struct s2io_nic *sp)
struct swStat *swstats;
DBG_PRINT(INIT_DBG, "%s: Resetting XFrame card %s\n",
- __func__, sp->dev->name);
+ __func__, pci_name(sp->pdev));
/* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
@@ -5055,8 +5055,8 @@ static void s2io_set_multicast(struct net_device *dev)
}
/* Update individual M_CAST address list */
- if ((!sp->m_cast_flg) && dev->mc_count) {
- if (dev->mc_count >
+ if ((!sp->m_cast_flg) && netdev_mc_count(dev)) {
+ if (netdev_mc_count(dev) >
(config->max_mc_addr - config->max_mac_addr)) {
DBG_PRINT(ERR_DBG,
"%s: No more Rx filters can be added - "
@@ -5066,7 +5066,7 @@ static void s2io_set_multicast(struct net_device *dev)
}
prev_cnt = sp->mc_addr_count;
- sp->mc_addr_count = dev->mc_count;
+ sp->mc_addr_count = netdev_mc_count(dev);
/* Clear out the previous list of Mc in the H/W. */
for (i = 0; i < prev_cnt; i++) {
@@ -5092,8 +5092,8 @@ static void s2io_set_multicast(struct net_device *dev)
}
/* Create the new Rx filter list and update the same in H/W. */
- for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
- i++, mclist = mclist->next) {
+ i = 0;
+ netdev_for_each_mc_addr(mclist, dev) {
memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr,
ETH_ALEN);
mac_addr = 0;
@@ -5121,6 +5121,7 @@ static void s2io_set_multicast(struct net_device *dev)
dev->name);
return;
}
+ i++;
}
}
}
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index 564d4d7f855b..9944e5d662c0 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -2161,13 +2161,13 @@ static void sbmac_setmulti(struct sbmac_softc *sc)
* XXX if the table overflows */
idx = 1; /* skip station address */
- mclist = dev->mc_list;
- while (mclist && (idx < MAC_ADDR_COUNT)) {
+ netdev_for_each_mc_addr(mclist, dev) {
+ if (idx == MAC_ADDR_COUNT)
+ break;
reg = sbmac_addr2reg(mclist->dmi_addr);
port = sc->sbm_base + R_MAC_ADDR_BASE+(idx * sizeof(uint64_t));
__raw_writeq(reg, port);
idx++;
- mclist = mclist->next;
}
/*
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
index e35050322f97..d87c4787fffa 100644
--- a/drivers/net/sc92031.c
+++ b/drivers/net/sc92031.c
@@ -429,13 +429,13 @@ static void _sc92031_set_mar(struct net_device *dev)
u32 mar0 = 0, mar1 = 0;
if ((dev->flags & IFF_PROMISC) ||
- dev->mc_count > multicast_filter_limit ||
+ netdev_mc_count(dev) > multicast_filter_limit ||
(dev->flags & IFF_ALLMULTI))
mar0 = mar1 = 0xffffffff;
else if (dev->flags & IFF_MULTICAST) {
struct dev_mc_list *mc_list;
- for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
+ netdev_for_each_mc_addr(mc_list, dev) {
u32 crc;
unsigned bit = 0;
@@ -1589,7 +1589,7 @@ out:
return 0;
}
-static struct pci_device_id sc92031_pci_device_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(sc92031_pci_device_id_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x2031) },
{ PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x8139) },
{ PCI_DEVICE(0x1088, 0x2031) },
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 103e8b0e2a0d..88f2fb193abe 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1602,11 +1602,10 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
static void efx_set_multicast_list(struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
- struct dev_mc_list *mc_list = net_dev->mc_list;
+ struct dev_mc_list *mc_list;
union efx_multicast_hash *mc_hash = &efx->multicast_hash;
u32 crc;
int bit;
- int i;
efx->promiscuous = !!(net_dev->flags & IFF_PROMISC);
@@ -1615,11 +1614,10 @@ static void efx_set_multicast_list(struct net_device *net_dev)
memset(mc_hash, 0xff, sizeof(*mc_hash));
} else {
memset(mc_hash, 0x00, sizeof(*mc_hash));
- for (i = 0; i < net_dev->mc_count; i++) {
+ netdev_for_each_mc_addr(mc_list, net_dev) {
crc = ether_crc_le(ETH_ALEN, mc_list->dmi_addr);
bit = crc & (EFX_MCAST_HASH_ENTRIES - 1);
set_bit_le(bit, mc_hash->byte);
- mc_list = mc_list->next;
}
/* Broadcast packets go through the multicast hash filter.
@@ -1940,7 +1938,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
**************************************************************************/
/* PCI device ID table */
-static struct pci_device_id efx_pci_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(efx_pci_table) = {
{PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID),
.driver_data = (unsigned long) &falcon_a1_nic_type},
{PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID),
@@ -2284,6 +2282,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
fail2:
efx_fini_struct(efx);
fail1:
+ WARN_ON(rc > 0);
EFX_LOG(efx, "initialisation failed. rc=%d\n", rc);
free_netdev(net_dev);
return rc;
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index a615ac051530..7eff0a615cb3 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -79,8 +79,6 @@ extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);
/* Global */
extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
-extern void efx_suspend(struct efx_nic *efx);
-extern void efx_resume(struct efx_nic *efx);
extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs,
int rx_usecs, bool rx_adaptive);
extern int efx_request_power(struct efx_nic *efx, int mw, const char *name);
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 6c0bbed8c477..d9f9c02a928e 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -196,7 +196,7 @@ int efx_ethtool_get_settings(struct net_device *net_dev,
efx->phy_op->get_settings(efx, ecmd);
mutex_unlock(&efx->mac_lock);
- /* Falcon GMAC does not support 1000Mbps HD */
+ /* GMAC does not support 1000Mbps HD */
ecmd->supported &= ~SUPPORTED_1000baseT_Half;
/* Both MACs support pause frames (bidirectional and respond-only) */
ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
@@ -216,7 +216,7 @@ int efx_ethtool_set_settings(struct net_device *net_dev,
struct efx_nic *efx = netdev_priv(net_dev);
int rc;
- /* Falcon GMAC does not support 1000Mbps HD */
+ /* GMAC does not support 1000Mbps HD */
if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) {
EFX_LOG(efx, "rejecting unsupported 1000Mbps HD"
" setting\n");
@@ -342,8 +342,8 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
unsigned int n = 0, i;
enum efx_loopback_mode mode;
- efx_fill_test(n++, strings, data, &tests->mdio,
- "core", 0, "mdio", NULL);
+ efx_fill_test(n++, strings, data, &tests->phy_alive,
+ "phy", 0, "alive", NULL);
efx_fill_test(n++, strings, data, &tests->nvram,
"core", 0, "nvram", NULL);
efx_fill_test(n++, strings, data, &tests->interrupt,
@@ -379,7 +379,7 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
if (name == NULL)
break;
- efx_fill_test(n++, strings, data, &tests->phy[i],
+ efx_fill_test(n++, strings, data, &tests->phy_ext[i],
"phy", 0, name, NULL);
}
}
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 9d009c46e962..1b8d83657aaa 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -909,6 +909,8 @@ static int falcon_probe_port(struct efx_nic *efx)
efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
else
efx->wanted_fc = EFX_FC_RX;
+ if (efx->mdio.mmds & MDIO_DEVS_AN)
+ efx->wanted_fc |= EFX_FC_AUTO;
/* Allocate buffer for stats */
rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer,
@@ -1006,7 +1008,7 @@ static int falcon_test_nvram(struct efx_nic *efx)
static const struct efx_nic_register_test falcon_b0_register_tests[] = {
{ FR_AZ_ADR_REGION,
- EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) },
+ EFX_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) },
{ FR_AZ_RX_CFG,
EFX_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) },
{ FR_AZ_TX_CFG,
@@ -1728,7 +1730,7 @@ static int falcon_set_wol(struct efx_nic *efx, u32 type)
/**************************************************************************
*
- * Revision-dependent attributes used by efx.c
+ * Revision-dependent attributes used by efx.c and nic.c
*
**************************************************************************
*/
diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c
index bf0b96af5334..5712fddd72f2 100644
--- a/drivers/net/sfc/falcon_boards.c
+++ b/drivers/net/sfc/falcon_boards.c
@@ -29,6 +29,15 @@
#define FALCON_BOARD_SFN4111T 0x51
#define FALCON_BOARD_SFN4112F 0x52
+/* Board temperature is about 15°C above ambient when air flow is
+ * limited. */
+#define FALCON_BOARD_TEMP_BIAS 15
+
+/* SFC4000 datasheet says: 'The maximum permitted junction temperature
+ * is 125°C; the thermal design of the environment for the SFC4000
+ * should aim to keep this well below 100°C.' */
+#define FALCON_JUNC_TEMP_MAX 90
+
/*****************************************************************************
* Support for LM87 sensor chip used on several boards
*/
@@ -548,16 +557,16 @@ fail_hwmon:
static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */
static const u8 sfe4002_lm87_regs[] = {
- LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */
- LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */
- LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */
- LM87_IN_LIMITS(3, 0xb0, 0xc9), /* 5V: 4.6-5.2V */
- LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */
- LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */
- LM87_AIN_LIMITS(0, 0xa0, 0xb2), /* AIN1: 1.66V +/- 5% */
- LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */
- LM87_TEMP_INT_LIMITS(10, 60), /* board */
- LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */
+ LM87_IN_LIMITS(0, 0x7c, 0x99), /* 2.5V: 1.8V +/- 10% */
+ LM87_IN_LIMITS(1, 0x4c, 0x5e), /* Vccp1: 1.2V +/- 10% */
+ LM87_IN_LIMITS(2, 0xac, 0xd4), /* 3.3V: 3.3V +/- 10% */
+ LM87_IN_LIMITS(3, 0xac, 0xd4), /* 5V: 5.0V +/- 10% */
+ LM87_IN_LIMITS(4, 0xac, 0xe0), /* 12V: 10.8-14V */
+ LM87_IN_LIMITS(5, 0x3f, 0x4f), /* Vccp2: 1.0V +/- 10% */
+ LM87_AIN_LIMITS(0, 0x98, 0xbb), /* AIN1: 1.66V +/- 10% */
+ LM87_AIN_LIMITS(1, 0x8a, 0xa9), /* AIN2: 1.5V +/- 10% */
+ LM87_TEMP_INT_LIMITS(0, 80 + FALCON_BOARD_TEMP_BIAS),
+ LM87_TEMP_EXT1_LIMITS(0, FALCON_JUNC_TEMP_MAX),
0
};
@@ -619,14 +628,14 @@ static int sfe4002_init(struct efx_nic *efx)
static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */
static const u8 sfn4112f_lm87_regs[] = {
- LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */
- LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */
- LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */
- LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */
- LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */
- LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */
- LM87_TEMP_INT_LIMITS(10, 60), /* board */
- LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */
+ LM87_IN_LIMITS(0, 0x7c, 0x99), /* 2.5V: 1.8V +/- 10% */
+ LM87_IN_LIMITS(1, 0x4c, 0x5e), /* Vccp1: 1.2V +/- 10% */
+ LM87_IN_LIMITS(2, 0xac, 0xd4), /* 3.3V: 3.3V +/- 10% */
+ LM87_IN_LIMITS(4, 0xac, 0xe0), /* 12V: 10.8-14V */
+ LM87_IN_LIMITS(5, 0x3f, 0x4f), /* Vccp2: 1.0V +/- 10% */
+ LM87_AIN_LIMITS(1, 0x8a, 0xa9), /* AIN2: 1.5V +/- 10% */
+ LM87_TEMP_INT_LIMITS(0, 60 + FALCON_BOARD_TEMP_BIAS),
+ LM87_TEMP_EXT1_LIMITS(0, FALCON_JUNC_TEMP_MAX),
0
};
diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c
index 0d4eba7266ec..c48669c77414 100644
--- a/drivers/net/sfc/mcdi.c
+++ b/drivers/net/sfc/mcdi.c
@@ -127,7 +127,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
efx_dword_t reg;
/* Check for a reboot atomically with respect to efx_mcdi_copyout() */
- rc = efx_mcdi_poll_reboot(efx);
+ rc = -efx_mcdi_poll_reboot(efx);
if (rc)
goto out;
@@ -804,7 +804,7 @@ int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
loff_t offset, u8 *buffer, size_t length)
{
u8 inbuf[MC_CMD_NVRAM_READ_IN_LEN];
- u8 outbuf[MC_CMD_NVRAM_READ_OUT_LEN(length)];
+ u8 outbuf[MC_CMD_NVRAM_READ_OUT_LEN(EFX_MCDI_NVRAM_LEN_MAX)];
size_t outlen;
int rc;
@@ -828,7 +828,7 @@ fail:
int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
loff_t offset, const u8 *buffer, size_t length)
{
- u8 inbuf[MC_CMD_NVRAM_WRITE_IN_LEN(length)];
+ u8 inbuf[MC_CMD_NVRAM_WRITE_IN_LEN(EFX_MCDI_NVRAM_LEN_MAX)];
int rc;
MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type);
@@ -838,7 +838,8 @@ int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0);
- rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf, sizeof(inbuf),
+ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf,
+ ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4),
NULL, 0, NULL);
if (rc)
goto fail;
@@ -895,29 +896,73 @@ fail:
return rc;
}
-int efx_mcdi_handle_assertion(struct efx_nic *efx)
+static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type)
+{
+ u8 inbuf[MC_CMD_NVRAM_TEST_IN_LEN];
+ u8 outbuf[MC_CMD_NVRAM_TEST_OUT_LEN];
+ int rc;
+
+ MCDI_SET_DWORD(inbuf, NVRAM_TEST_IN_TYPE, type);
+
+ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TEST, inbuf, sizeof(inbuf),
+ outbuf, sizeof(outbuf), NULL);
+ if (rc)
+ return rc;
+
+ switch (MCDI_DWORD(outbuf, NVRAM_TEST_OUT_RESULT)) {
+ case MC_CMD_NVRAM_TEST_PASS:
+ case MC_CMD_NVRAM_TEST_NOTSUPP:
+ return 0;
+ default:
+ return -EIO;
+ }
+}
+
+int efx_mcdi_nvram_test_all(struct efx_nic *efx)
+{
+ u32 nvram_types;
+ unsigned int type;
+ int rc;
+
+ rc = efx_mcdi_nvram_types(efx, &nvram_types);
+ if (rc)
+ return rc;
+
+ type = 0;
+ while (nvram_types != 0) {
+ if (nvram_types & 1) {
+ rc = efx_mcdi_nvram_test(efx, type);
+ if (rc)
+ return rc;
+ }
+ type++;
+ nvram_types >>= 1;
+ }
+
+ return 0;
+}
+
+static int efx_mcdi_read_assertion(struct efx_nic *efx)
{
- union {
- u8 asserts[MC_CMD_GET_ASSERTS_IN_LEN];
- u8 reboot[MC_CMD_REBOOT_IN_LEN];
- } inbuf;
- u8 assertion[MC_CMD_GET_ASSERTS_OUT_LEN];
+ u8 inbuf[MC_CMD_GET_ASSERTS_IN_LEN];
+ u8 outbuf[MC_CMD_GET_ASSERTS_OUT_LEN];
unsigned int flags, index, ofst;
const char *reason;
size_t outlen;
int retry;
int rc;
- /* Check if the MC is in the assertion handler, retrying twice. Once
+ /* Attempt to read any stored assertion state before we reboot
+ * the mcfw out of the assertion handler. Retry twice, once
* because a boot-time assertion might cause this command to fail
* with EINTR. And once again because GET_ASSERTS can race with
* MC_CMD_REBOOT running on the other port. */
retry = 2;
do {
- MCDI_SET_DWORD(inbuf.asserts, GET_ASSERTS_IN_CLEAR, 0);
+ MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1);
rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS,
- inbuf.asserts, MC_CMD_GET_ASSERTS_IN_LEN,
- assertion, sizeof(assertion), &outlen);
+ inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
+ outbuf, sizeof(outbuf), &outlen);
} while ((rc == -EINTR || rc == -EIO) && retry-- > 0);
if (rc)
@@ -925,21 +970,11 @@ int efx_mcdi_handle_assertion(struct efx_nic *efx)
if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN)
return -EINVAL;
- flags = MCDI_DWORD(assertion, GET_ASSERTS_OUT_GLOBAL_FLAGS);
+ /* Print out any recorded assertion state */
+ flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS);
if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
return 0;
- /* Reset the hardware atomically such that only one port with succeed.
- * This command will succeed if a reboot is no longer required (because
- * the other port did it first), but fail with EIO if it succeeds.
- */
- BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
- MCDI_SET_DWORD(inbuf.reboot, REBOOT_IN_FLAGS,
- MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
- efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf.reboot, MC_CMD_REBOOT_IN_LEN,
- NULL, 0, NULL);
-
- /* Print out the assertion */
reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
? "system-level assertion"
: (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
@@ -948,20 +983,45 @@ int efx_mcdi_handle_assertion(struct efx_nic *efx)
? "watchdog reset"
: "unknown assertion";
EFX_ERR(efx, "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason,
- MCDI_DWORD(assertion, GET_ASSERTS_OUT_SAVED_PC_OFFS),
- MCDI_DWORD(assertion, GET_ASSERTS_OUT_THREAD_OFFS));
+ MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS),
+ MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS));
/* Print out the registers */
ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
for (index = 1; index < 32; index++) {
EFX_ERR(efx, "R%.2d (?): 0x%.8x\n", index,
- MCDI_DWORD2(assertion, ofst));
+ MCDI_DWORD2(outbuf, ofst));
ofst += sizeof(efx_dword_t);
}
return 0;
}
+static void efx_mcdi_exit_assertion(struct efx_nic *efx)
+{
+ u8 inbuf[MC_CMD_REBOOT_IN_LEN];
+
+ /* Atomically reboot the mcfw out of the assertion handler */
+ BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
+ MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS,
+ MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
+ efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN,
+ NULL, 0, NULL);
+}
+
+int efx_mcdi_handle_assertion(struct efx_nic *efx)
+{
+ int rc;
+
+ rc = efx_mcdi_read_assertion(efx);
+ if (rc)
+ return rc;
+
+ efx_mcdi_exit_assertion(efx);
+
+ return 0;
+}
+
void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
{
u8 inbuf[MC_CMD_SET_ID_LED_IN_LEN];
diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h
index de916728c2e3..f1f89ad4075a 100644
--- a/drivers/net/sfc/mcdi.h
+++ b/drivers/net/sfc/mcdi.h
@@ -111,10 +111,12 @@ extern int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
extern int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
loff_t offset, const u8 *buffer,
size_t length);
+#define EFX_MCDI_NVRAM_LEN_MAX 128
extern int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
loff_t offset, size_t length);
extern int efx_mcdi_nvram_update_finish(struct efx_nic *efx,
unsigned int type);
+extern int efx_mcdi_nvram_test_all(struct efx_nic *efx);
extern int efx_mcdi_handle_assertion(struct efx_nic *efx);
extern void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
extern int efx_mcdi_reset_port(struct efx_nic *efx);
diff --git a/drivers/net/sfc/mcdi_pcol.h b/drivers/net/sfc/mcdi_pcol.h
index 2a85360a46f0..bd59302695b3 100644
--- a/drivers/net/sfc/mcdi_pcol.h
+++ b/drivers/net/sfc/mcdi_pcol.h
@@ -786,16 +786,18 @@
#define MC_CMD_GET_PHY_CFG_OUT_FLAGS_OFST 0
#define MC_CMD_GET_PHY_CFG_PRESENT_LBN 0
#define MC_CMD_GET_PHY_CFG_PRESENT_WIDTH 1
-#define MC_CMD_GET_PHY_CFG_SHORTBIST_LBN 1
-#define MC_CMD_GET_PHY_CFG_SHORTBIST_WIDTH 1
-#define MC_CMD_GET_PHY_CFG_LONGBIST_LBN 2
-#define MC_CMD_GET_PHY_CFG_LONGBIST_WIDTH 1
+#define MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN 1
+#define MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_WIDTH 1
+#define MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN 2
+#define MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_WIDTH 1
#define MC_CMD_GET_PHY_CFG_LOWPOWER_LBN 3
#define MC_CMD_GET_PHY_CFG_LOWPOWER_WIDTH 1
#define MC_CMD_GET_PHY_CFG_POWEROFF_LBN 4
#define MC_CMD_GET_PHY_CFG_POWEROFF_WIDTH 1
#define MC_CMD_GET_PHY_CFG_TXDIS_LBN 5
#define MC_CMD_GET_PHY_CFG_TXDIS_WIDTH 1
+#define MC_CMD_GET_PHY_CFG_BIST_LBN 6
+#define MC_CMD_GET_PHY_CFG_BIST_WIDTH 1
#define MC_CMD_GET_PHY_CFG_OUT_TYPE_OFST 4
/* Bitmask of supported capabilities */
#define MC_CMD_GET_PHY_CFG_OUT_SUPPORTED_CAP_OFST 8
@@ -832,7 +834,7 @@
#define MC_CMD_GET_PHY_CFG_OUT_REVISION_OFST 52
#define MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN 20
-/* MC_CMD_START_PHY_BIST:
+/* MC_CMD_START_BIST:
* Start a BIST test on the PHY.
*
* Locks required: PHY_LOCK if doing a PHY BIST
@@ -840,34 +842,71 @@
*/
#define MC_CMD_START_BIST 0x25
#define MC_CMD_START_BIST_IN_LEN 4
-#define MC_CMD_START_BIST_TYPE_OFST 0
+#define MC_CMD_START_BIST_IN_TYPE_OFST 0
+#define MC_CMD_START_BIST_OUT_LEN 0
-/* Run the PHY's short BIST */
-#define MC_CMD_PHY_BIST_SHORT 1
-/* Run the PHY's long BIST */
-#define MC_CMD_PHY_BIST_LONG 2
+/* Run the PHY's short cable BIST */
+#define MC_CMD_PHY_BIST_CABLE_SHORT 1
+/* Run the PHY's long cable BIST */
+#define MC_CMD_PHY_BIST_CABLE_LONG 2
/* Run BIST on the currently selected BPX Serdes (XAUI or XFI) */
#define MC_CMD_BPX_SERDES_BIST 3
+/* Run the MC loopback tests */
+#define MC_CMD_MC_LOOPBACK_BIST 4
+/* Run the PHY's standard BIST */
+#define MC_CMD_PHY_BIST 5
/* MC_CMD_POLL_PHY_BIST: (variadic output)
* Poll for BIST completion
*
- * Returns a single status code, and a binary blob of phy-specific
- * bist output. If the driver can't succesfully parse the BIST output,
- * it should still respect the Pass/Fail in OUT.RESULT.
+ * Returns a single status code, and optionally some PHY specific
+ * bist output. The driver should only consume the BIST output
+ * after validating OUTLEN and PHY_CFG.PHY_TYPE.
*
- * Locks required: PHY_LOCK if doing a PHY BIST
+ * If a driver can't succesfully parse the BIST output, it should
+ * still respect the pass/Fail in OUT.RESULT
+ *
+ * Locks required: PHY_LOCK if doing a PHY BIST
* Return code: 0, EACCES (if PHY_LOCK is not held)
*/
#define MC_CMD_POLL_BIST 0x26
#define MC_CMD_POLL_BIST_IN_LEN 0
#define MC_CMD_POLL_BIST_OUT_LEN UNKNOWN
+#define MC_CMD_POLL_BIST_OUT_SFT9001_LEN 40
+#define MC_CMD_POLL_BIST_OUT_MRSFP_LEN 8
#define MC_CMD_POLL_BIST_OUT_RESULT_OFST 0
#define MC_CMD_POLL_BIST_RUNNING 1
#define MC_CMD_POLL_BIST_PASSED 2
#define MC_CMD_POLL_BIST_FAILED 3
#define MC_CMD_POLL_BIST_TIMEOUT 4
+/* Generic: */
#define MC_CMD_POLL_BIST_OUT_PRIVATE_OFST 4
+/* SFT9001-specific: */
+/* (offset 4 unused?) */
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A_OFST 8
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B_OFST 12
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C_OFST 16
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D_OFST 20
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_A_OFST 24
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_B_OFST 28
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_C_OFST 32
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_D_OFST 36
+#define MC_CMD_POLL_BIST_SFT9001_PAIR_OK 1
+#define MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN 2
+#define MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT 3
+#define MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT 4
+#define MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY 9
+/* mrsfp "PHY" driver: */
+#define MC_CMD_POLL_BIST_OUT_MRSFP_TEST_OFST 4
+#define MC_CMD_POLL_BIST_MRSFP_TEST_COMPLETE 0
+#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_OFF_I2C_WRITE 1
+#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_OFF_I2C_NO_ACCESS_IO_EXP 2
+#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_OFF_I2C_NO_ACCESS_MODULE 3
+#define MC_CMD_POLL_BIST_MRSFP_TEST_IO_EXP_I2C_CONFIGURE 4
+#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_I2C_NO_CROSSTALK 5
+#define MC_CMD_POLL_BIST_MRSFP_TEST_MODULE_PRESENCE 6
+#define MC_CMD_POLL_BIST_MRSFP_TEST_MODULE_ID_I2C_ACCESS 7
+#define MC_CMD_POLL_BIST_MRSFP_TEST_MODULE_ID_SANE_VALUE 8
/* MC_CMD_PHY_SPI: (variadic in, variadic out)
* Read/Write/Erase the PHY SPI device
@@ -1090,8 +1129,10 @@
#define MC_CMD_MAC_RX_LANES01_DISP_ERR 57
#define MC_CMD_MAC_RX_LANES23_DISP_ERR 58
#define MC_CMD_MAC_RX_MATCH_FAULT 59
+#define MC_CMD_GMAC_DMABUF_START 64
+#define MC_CMD_GMAC_DMABUF_END 95
/* Insert new members here. */
-#define MC_CMD_MAC_GENERATION_END 60
+#define MC_CMD_MAC_GENERATION_END 96
#define MC_CMD_MAC_NSTATS (MC_CMD_MAC_GENERATION_END+1)
/* MC_CMD_MAC_STATS:
@@ -1204,6 +1245,13 @@
#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LAYER4_OFST \
(MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 178)
+#define MC_CMD_WOL_FILTER_SET_IN_LINK_MASK_OFST \
+ MC_CMD_WOL_FILTER_SET_IN_DATA_OFST
+#define MC_CMD_WOL_FILTER_SET_IN_LINK_UP_LBN 0
+#define MC_CMD_WOL_FILTER_SET_IN_LINK_UP_WIDTH 1
+#define MC_CMD_WOL_FILTER_SET_IN_LINK_DOWN_LBN 1
+#define MC_CMD_WOL_FILTER_SET_IN_LINK_DOWN_WIDTH 1
+
#define MC_CMD_WOL_FILTER_SET_OUT_LEN 4
#define MC_CMD_WOL_FILTER_SET_OUT_FILTER_ID_OFST 0
@@ -1214,7 +1262,8 @@
#define MC_CMD_WOL_TYPE_IPV4_SYN 0x3
#define MC_CMD_WOL_TYPE_IPV6_SYN 0x4
#define MC_CMD_WOL_TYPE_BITMAP 0x5
-#define MC_CMD_WOL_TYPE_MAX 0x6
+#define MC_CMD_WOL_TYPE_LINK 0x6
+#define MC_CMD_WOL_TYPE_MAX 0x7
#define MC_CMD_FILTER_MODE_SIMPLE 0x0
#define MC_CMD_FILTER_MODE_STRUCTURED 0xffffffff
@@ -1355,14 +1404,24 @@
* Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held)
*/
#define MC_CMD_NVRAM_UPDATE_FINISH 0x3c
-#define MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN 4
+#define MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN 8
#define MC_CMD_NVRAM_UPDATE_FINISH_IN_TYPE_OFST 0
+#define MC_CMD_NVRAM_UPDATE_FINISH_IN_REBOOT_OFST 4
#define MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN 0
/* MC_CMD_REBOOT:
- * Reboot the MC. The AFTER_ASSERTION flag is intended to be used
- * when the driver notices an assertion failure, to allow two ports to
- * both recover (semi-)gracefully.
+ * Reboot the MC.
+ *
+ * The AFTER_ASSERTION flag is intended to be used when the driver notices
+ * an assertion failure (at which point it is expected to perform a complete
+ * tear down and reinitialise), to allow both ports to reset the MC once
+ * in an atomic fashion.
+ *
+ * Production mc firmwares are generally compiled with REBOOT_ON_ASSERT=1,
+ * which means that they will automatically reboot out of the assertion
+ * handler, so this is in practise an optional operation. It is still
+ * recommended that drivers execute this to support custom firmwares
+ * with REBOOT_ON_ASSERT=0.
*
* Locks required: NONE
* Returns: Nothing. You get back a response with ERR=1, DATALEN=0
@@ -1467,11 +1526,10 @@
((_ofst) + 6)
/* MC_CMD_READ_SENSORS
- * Returns the current (value, state) for each sensor
+ * Returns the current reading from each sensor
*
- * Returns the current (value, state) [each 16bit] of each sensor supported by
- * this board, by DMA'ing a sparse array (indexed by the sensor type) into host
- * memory.
+ * Returns a sparse array of sensor readings (indexed by the sensor
+ * type) into host memory. Each array element is a dword.
*
* The MC will send a SENSOREVT event every time any sensor changes state. The
* driver is responsible for ensuring that it doesn't miss any events. The board
@@ -1484,6 +1542,12 @@
#define MC_CMD_READ_SENSORS_IN_DMA_ADDR_HI_OFST 4
#define MC_CMD_READ_SENSORS_OUT_LEN 0
+/* Sensor reading fields */
+#define MC_CMD_READ_SENSOR_VALUE_LBN 0
+#define MC_CMD_READ_SENSOR_VALUE_WIDTH 16
+#define MC_CMD_READ_SENSOR_STATE_LBN 16
+#define MC_CMD_READ_SENSOR_STATE_WIDTH 8
+
/* MC_CMD_GET_PHY_STATE:
* Report current state of PHY. A "zombie" PHY is a PHY that has failed to
@@ -1575,4 +1639,98 @@
#define MC_CMD_MAC_RESET_RESTORE_IN_LEN 0
#define MC_CMD_MAC_RESET_RESTORE_OUT_LEN 0
+
+/* MC_CMD_TEST_ASSERT:
+ * Deliberately trigger an assert-detonation in the firmware for testing
+ * purposes (i.e. to allow tests that the driver copes gracefully).
+ *
+ * Locks required: None
+ * Returns: 0
+ */
+
+#define MC_CMD_TESTASSERT 0x49
+#define MC_CMD_TESTASSERT_IN_LEN 0
+#define MC_CMD_TESTASSERT_OUT_LEN 0
+
+/* MC_CMD_WORKAROUND 0x4a
+ *
+ * Enable/Disable a given workaround. The mcfw will return EINVAL if it
+ * doesn't understand the given workaround number - which should not
+ * be treated as a hard error by client code.
+ *
+ * This op does not imply any semantics about each workaround, that's between
+ * the driver and the mcfw on a per-workaround basis.
+ *
+ * Locks required: None
+ * Returns: 0, EINVAL
+ */
+#define MC_CMD_WORKAROUND 0x4a
+#define MC_CMD_WORKAROUND_IN_LEN 8
+#define MC_CMD_WORKAROUND_IN_TYPE_OFST 0
+#define MC_CMD_WORKAROUND_BUG17230 1
+#define MC_CMD_WORKAROUND_IN_ENABLED_OFST 4
+#define MC_CMD_WORKAROUND_OUT_LEN 0
+
+/* MC_CMD_GET_PHY_MEDIA_INFO:
+ * Read media-specific data from PHY (e.g. SFP/SFP+ module ID information for
+ * SFP+ PHYs).
+ *
+ * The "media type" can be found via GET_PHY_CFG (GET_PHY_CFG_OUT_MEDIA_TYPE);
+ * the valid "page number" input values, and the output data, are interpreted
+ * on a per-type basis.
+ *
+ * For SFP+: PAGE=0 or 1 returns a 128-byte block read from module I2C address
+ * 0xA0 offset 0 or 0x80.
+ * Anything else: currently undefined.
+ *
+ * Locks required: None
+ * Return code: 0
+ */
+#define MC_CMD_GET_PHY_MEDIA_INFO 0x4b
+#define MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN 4
+#define MC_CMD_GET_PHY_MEDIA_INFO_IN_PAGE_OFST 0
+#define MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(_num_bytes) (4 + (_num_bytes))
+#define MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATALEN_OFST 0
+#define MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST 4
+
+/* MC_CMD_NVRAM_TEST:
+ * Test a particular NVRAM partition for valid contents (where "valid"
+ * depends on the type of partition).
+ *
+ * Locks required: None
+ * Return code: 0
+ */
+#define MC_CMD_NVRAM_TEST 0x4c
+#define MC_CMD_NVRAM_TEST_IN_LEN 4
+#define MC_CMD_NVRAM_TEST_IN_TYPE_OFST 0
+#define MC_CMD_NVRAM_TEST_OUT_LEN 4
+#define MC_CMD_NVRAM_TEST_OUT_RESULT_OFST 0
+#define MC_CMD_NVRAM_TEST_PASS 0
+#define MC_CMD_NVRAM_TEST_FAIL 1
+#define MC_CMD_NVRAM_TEST_NOTSUPP 2
+
+/* MC_CMD_MRSFP_TWEAK: (debug)
+ * Read status and/or set parameters for the "mrsfp" driver in mr_rusty builds.
+ * I2C I/O expander bits are always read; if equaliser parameters are supplied,
+ * they are configured first.
+ *
+ * Locks required: None
+ * Return code: 0, EINVAL
+ */
+#define MC_CMD_MRSFP_TWEAK 0x4d
+#define MC_CMD_MRSFP_TWEAK_IN_LEN_READ_ONLY 0
+#define MC_CMD_MRSFP_TWEAK_IN_LEN_EQ_CONFIG 16
+#define MC_CMD_MRSFP_TWEAK_IN_TXEQ_LEVEL_OFST 0 /* 0-6 low->high de-emph. */
+#define MC_CMD_MRSFP_TWEAK_IN_TXEQ_DT_CFG_OFST 4 /* 0-8 low->high ref.V */
+#define MC_CMD_MRSFP_TWEAK_IN_RXEQ_BOOST_OFST 8 /* 0-8 low->high boost */
+#define MC_CMD_MRSFP_TWEAK_IN_RXEQ_DT_CFG_OFST 12 /* 0-8 low->high ref.V */
+#define MC_CMD_MRSFP_TWEAK_OUT_LEN 12
+#define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_INPUTS_OFST 0 /* input bits */
+#define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_OUTPUTS_OFST 4 /* output bits */
+#define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_DIRECTION_OFST 8 /* dirs: 0=out, 1=in */
+
+/* Do NOT add new commands beyond 0x4f as part of 3.0 : 0x50 - 0x7f will be
+ * used for post-3.0 extensions. If you run out of space, look for gaps or
+ * commands that are unused in the existing range. */
+
#endif /* MCDI_PCOL_H */
diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c
index eb694af7a473..34c22fa986e2 100644
--- a/drivers/net/sfc/mcdi_phy.c
+++ b/drivers/net/sfc/mcdi_phy.c
@@ -381,6 +381,18 @@ static int efx_mcdi_phy_probe(struct efx_nic *efx)
* but by convention we don't */
efx->loopback_modes &= ~(1 << LOOPBACK_NONE);
+ /* Set the initial link mode */
+ efx_mcdi_phy_decode_link(
+ efx, &efx->link_state,
+ MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED),
+ MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS),
+ MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL));
+
+ /* Default to Autonegotiated flow control if the PHY supports it */
+ efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
+ if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
+ efx->wanted_fc |= EFX_FC_AUTO;
+
return 0;
fail:
@@ -436,7 +448,7 @@ void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa)
/* The link partner capabilities are only relevent if the
* link supports flow control autonegotiation */
- if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
+ if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
return;
/* If flow control autoneg is supported and enabled, then fine */
@@ -560,6 +572,27 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec
return 0;
}
+static int efx_mcdi_phy_test_alive(struct efx_nic *efx)
+{
+ u8 outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN];
+ size_t outlen;
+ int rc;
+
+ BUILD_BUG_ON(MC_CMD_GET_PHY_STATE_IN_LEN != 0);
+
+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_STATE, NULL, 0,
+ outbuf, sizeof(outbuf), &outlen);
+ if (rc)
+ return rc;
+
+ if (outlen < MC_CMD_GET_PHY_STATE_OUT_LEN)
+ return -EMSGSIZE;
+ if (MCDI_DWORD(outbuf, GET_PHY_STATE_STATE) != MC_CMD_PHY_STATE_OK)
+ return -EINVAL;
+
+ return 0;
+}
+
struct efx_phy_operations efx_mcdi_phy_ops = {
.probe = efx_mcdi_phy_probe,
.init = efx_port_dummy_op_int,
@@ -569,6 +602,7 @@ struct efx_phy_operations efx_mcdi_phy_ops = {
.remove = efx_mcdi_phy_remove,
.get_settings = efx_mcdi_phy_get_settings,
.set_settings = efx_mcdi_phy_set_settings,
+ .test_alive = efx_mcdi_phy_test_alive,
.run_tests = NULL,
.test_name = NULL,
};
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 1574e52f0594..0548fcbbdcd0 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -335,3 +335,27 @@ enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx)
mii_advertise_flowctrl(efx->wanted_fc),
efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA));
}
+
+int efx_mdio_test_alive(struct efx_nic *efx)
+{
+ int rc;
+ int devad = __ffs(efx->mdio.mmds);
+ u16 physid1, physid2;
+
+ mutex_lock(&efx->mac_lock);
+
+ physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1);
+ physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2);
+
+ if ((physid1 == 0x0000) || (physid1 == 0xffff) ||
+ (physid2 == 0x0000) || (physid2 == 0xffff)) {
+ EFX_ERR(efx, "no MDIO PHY present with ID %d\n",
+ efx->mdio.prtad);
+ rc = -EINVAL;
+ } else {
+ rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0);
+ }
+
+ mutex_unlock(&efx->mac_lock);
+ return rc;
+}
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
index f6ac9503339d..f89e71929603 100644
--- a/drivers/net/sfc/mdio_10g.h
+++ b/drivers/net/sfc/mdio_10g.h
@@ -106,4 +106,7 @@ efx_mdio_set_flag(struct efx_nic *efx, int devad, int addr,
mdio_set_flag(&efx->mdio, efx->mdio.prtad, devad, addr, mask, state);
}
+/* Liveness self-test for MDIO PHYs */
+extern int efx_mdio_test_alive(struct efx_nic *efx);
+
#endif /* EFX_MDIO_10G_H */
diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c
index 3a464529a46b..407bbaddfea6 100644
--- a/drivers/net/sfc/mtd.c
+++ b/drivers/net/sfc/mtd.c
@@ -23,7 +23,6 @@
#include "mcdi_pcol.h"
#define EFX_SPI_VERIFY_BUF_LEN 16
-#define EFX_MCDI_CHUNK_LEN 128
struct efx_mtd_partition {
struct mtd_info mtd;
@@ -428,7 +427,7 @@ static int siena_mtd_read(struct mtd_info *mtd, loff_t start,
int rc = 0;
while (offset < end) {
- chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN);
+ chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX);
rc = efx_mcdi_nvram_read(efx, part->mcdi.nvram_type, offset,
buffer, chunk);
if (rc)
@@ -491,7 +490,7 @@ static int siena_mtd_write(struct mtd_info *mtd, loff_t start,
}
while (offset < end) {
- chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN);
+ chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX);
rc = efx_mcdi_nvram_write(efx, part->mcdi.nvram_type, offset,
buffer, chunk);
if (rc)
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index d5aab5b3fa06..cb018e272097 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -18,7 +18,6 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
-#include <linux/timer.h>
#include <linux/mdio.h>
#include <linux/list.h>
#include <linux/pci.h>
@@ -101,9 +100,6 @@ do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
* Special buffers are used for the event queues and the TX and RX
* descriptor queues for each channel. They are *not* used for the
* actual transmit and receive buffers.
- *
- * Note that for Falcon, TX and RX descriptor queues live in host memory.
- * Allocation and freeing procedures must take this into account.
*/
struct efx_special_buffer {
void *addr;
@@ -300,7 +296,7 @@ struct efx_rx_queue {
* @dma_addr: DMA base address of the buffer
* @len: Buffer length, in bytes
*
- * Falcon uses these buffers for its interrupt status registers and
+ * The NIC uses these buffers for its interrupt status registers and
* MAC stats dumps.
*/
struct efx_buffer {
@@ -516,8 +512,9 @@ struct efx_mac_operations {
* @set_settings: Set ethtool settings. Serialised by the mac_lock.
* @set_npage_adv: Set abilities advertised in (Extended) Next Page
* (only needed where AN bit is set in mmds)
+ * @test_alive: Test that PHY is 'alive' (online)
* @test_name: Get the name of a PHY-specific test/result
- * @run_tests: Run tests and record results as appropriate.
+ * @run_tests: Run tests and record results as appropriate (offline).
* Flags are the ethtool tests flags.
*/
struct efx_phy_operations {
@@ -532,6 +529,7 @@ struct efx_phy_operations {
int (*set_settings) (struct efx_nic *efx,
struct ethtool_cmd *ecmd);
void (*set_npage_adv) (struct efx_nic *efx, u32);
+ int (*test_alive) (struct efx_nic *efx);
const char *(*test_name) (struct efx_nic *efx, unsigned int index);
int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags);
};
@@ -672,7 +670,7 @@ union efx_multicast_hash {
* @irq_status: Interrupt status buffer
* @last_irq_cpu: Last CPU to handle interrupt.
* This register is written with the SMP processor ID whenever an
- * interrupt is handled. It is used by falcon_test_interrupt()
+ * interrupt is handled. It is used by efx_nic_test_interrupt()
* to verify that an interrupt has occurred.
* @spi_flash: SPI flash device
* This field will be %NULL if no flash device is present (or for Siena).
@@ -721,8 +719,7 @@ union efx_multicast_hash {
* @loopback_modes: Supported loopback mode bitmask
* @loopback_selftest: Offline self-test private state
*
- * The @priv field of the corresponding &struct net_device points to
- * this.
+ * This is stored in the private area of the &struct net_device.
*/
struct efx_nic {
char name[IFNAMSIZ];
@@ -995,7 +992,7 @@ static inline void clear_bit_le(unsigned nr, unsigned char *addr)
* that the net driver will program into the MAC as the maximum frame
* length.
*
- * The 10G MAC used in Falcon requires 8-byte alignment on the frame
+ * The 10G MAC requires 8-byte alignment on the frame
* length, so we round up to the nearest 8.
*
* Re-clocking by the XGXS on RX can reduce an IPG to 32 bits (half an
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index db44224ed2ca..b06f8e348307 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -623,10 +623,6 @@ void efx_nic_remove_rx(struct efx_rx_queue *rx_queue)
*
* This writes the EVQ_RPTR_REG register for the specified channel's
* event queue.
- *
- * Note that EVQ_RPTR_REG contains the index of the "last read" event,
- * whereas channel->eventq_read_ptr contains the index of the "next to
- * read" event.
*/
void efx_nic_eventq_read_ack(struct efx_channel *channel)
{
@@ -1384,6 +1380,15 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
efx->last_irq_cpu = raw_smp_processor_id();
EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
+ } else if (EFX_WORKAROUND_15783(efx)) {
+ /* We can't return IRQ_HANDLED more than once on seeing ISR0=0
+ * because this might be a shared interrupt, but we do need to
+ * check the channel every time and preemptively rearm it if
+ * it's idle. */
+ efx_for_each_channel(channel, efx) {
+ if (!channel->work_pending)
+ efx_nic_eventq_read_ack(channel);
+ }
}
return result;
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
index ff8f0a417fa3..1bee62c83001 100644
--- a/drivers/net/sfc/qt202x_phy.c
+++ b/drivers/net/sfc/qt202x_phy.c
@@ -318,15 +318,9 @@ static int qt202x_reset_phy(struct efx_nic *efx)
/* Wait 250ms for the PHY to complete bootup */
msleep(250);
- /* Check that all the MMDs we expect are present and responding. We
- * expect faults on some if the link is down, but not on the PHY XS */
- rc = efx_mdio_check_mmds(efx, QT202X_REQUIRED_DEVS, MDIO_DEVS_PHYXS);
- if (rc < 0)
- goto fail;
-
falcon_board(efx)->type->init_phy(efx);
- return rc;
+ return 0;
fail:
EFX_ERR(efx, "PHY reset timed out\n");
@@ -451,4 +445,5 @@ struct efx_phy_operations falcon_qt202x_phy_ops = {
.remove = qt202x_phy_remove,
.get_settings = qt202x_phy_get_settings,
.set_settings = efx_mdio_set_settings,
+ .test_alive = efx_mdio_test_alive,
};
diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h
index 89d606fe9248..18a3be428348 100644
--- a/drivers/net/sfc/regs.h
+++ b/drivers/net/sfc/regs.h
@@ -95,7 +95,7 @@
#define FRF_AA_INT_ACK_KER_FIELD_LBN 0
#define FRF_AA_INT_ACK_KER_FIELD_WIDTH 32
-/* INT_ISR0_REG: Function 0 Interrupt Acknowlege Status register */
+/* INT_ISR0_REG: Function 0 Interrupt Acknowledge Status register */
#define FR_BZ_INT_ISR0 0x00000090
#define FRF_BZ_INT_ISR_REG_LBN 0
#define FRF_BZ_INT_ISR_REG_WIDTH 64
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 250c8827b842..cf0139a7d9a4 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -24,9 +24,6 @@
#include "nic.h"
#include "selftest.h"
#include "workarounds.h"
-#include "spi.h"
-#include "io.h"
-#include "mdio_10g.h"
/*
* Loopback test packet structure
@@ -76,42 +73,15 @@ struct efx_loopback_state {
*
**************************************************************************/
-static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests)
+static int efx_test_phy_alive(struct efx_nic *efx, struct efx_self_tests *tests)
{
int rc = 0;
- int devad;
- u16 physid1, physid2;
-
- if (efx->mdio.mode_support & MDIO_SUPPORTS_C45)
- devad = __ffs(efx->mdio.mmds);
- else if (efx->mdio.mode_support & MDIO_SUPPORTS_C22)
- devad = MDIO_DEVAD_NONE;
- else
- return 0;
-
- mutex_lock(&efx->mac_lock);
- tests->mdio = -1;
-
- physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1);
- physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2);
- if ((physid1 == 0x0000) || (physid1 == 0xffff) ||
- (physid2 == 0x0000) || (physid2 == 0xffff)) {
- EFX_ERR(efx, "no MDIO PHY present with ID %d\n",
- efx->mdio.prtad);
- rc = -EINVAL;
- goto out;
+ if (efx->phy_op->test_alive) {
+ rc = efx->phy_op->test_alive(efx);
+ tests->phy_alive = rc ? -1 : 1;
}
- if (EFX_IS10G(efx)) {
- rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0);
- if (rc)
- goto out;
- }
-
-out:
- mutex_unlock(&efx->mac_lock);
- tests->mdio = rc ? -1 : 1;
return rc;
}
@@ -258,7 +228,7 @@ static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests,
return 0;
mutex_lock(&efx->mac_lock);
- rc = efx->phy_op->run_tests(efx, tests->phy, flags);
+ rc = efx->phy_op->run_tests(efx, tests->phy_ext, flags);
mutex_unlock(&efx->mac_lock);
return rc;
}
@@ -684,7 +654,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
/* Online (i.e. non-disruptive) testing
* This checks interrupt generation, event delivery and PHY presence. */
- rc = efx_test_mdio(efx, tests);
+ rc = efx_test_phy_alive(efx, tests);
if (rc && !rc_test)
rc_test = rc;
diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h
index f6feee04c96b..643bef72b99d 100644
--- a/drivers/net/sfc/selftest.h
+++ b/drivers/net/sfc/selftest.h
@@ -32,7 +32,7 @@ struct efx_loopback_self_tests {
*/
struct efx_self_tests {
/* online tests */
- int mdio;
+ int phy_alive;
int nvram;
int interrupt;
int eventq_dma[EFX_MAX_CHANNELS];
@@ -40,7 +40,7 @@ struct efx_self_tests {
int eventq_poll[EFX_MAX_CHANNELS];
/* offline tests */
int registers;
- int phy[EFX_MAX_PHY_TESTS];
+ int phy_ext[EFX_MAX_PHY_TESTS];
struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1];
};
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index f8c6771e66d8..1619fb5a64f5 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -106,16 +106,11 @@ static int siena_probe_port(struct efx_nic *efx)
efx->mdio.mdio_read = siena_mdio_read;
efx->mdio.mdio_write = siena_mdio_write;
- /* Fill out MDIO structure and loopback modes */
+ /* Fill out MDIO structure, loopback modes, and initial link state */
rc = efx->phy_op->probe(efx);
if (rc != 0)
return rc;
- /* Initial assumption */
- efx->link_state.speed = 10000;
- efx->link_state.fd = true;
- efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
-
/* Allocate buffer for stats */
rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer,
MC_CMD_MAC_NSTATS * sizeof(u64));
@@ -139,7 +134,7 @@ void siena_remove_port(struct efx_nic *efx)
static const struct efx_nic_register_test siena_register_tests[] = {
{ FR_AZ_ADR_REGION,
- EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) },
+ EFX_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) },
{ FR_CZ_USR_EV_CFG,
EFX_OWORD32(0x000103FF, 0x00000000, 0x00000000, 0x00000000) },
{ FR_AZ_RX_CFG,
@@ -181,6 +176,12 @@ static int siena_test_registers(struct efx_nic *efx)
static int siena_reset_hw(struct efx_nic *efx, enum reset_type method)
{
+ int rc;
+
+ /* Recover from a failed assertion pre-reset */
+ rc = efx_mcdi_handle_assertion(efx);
+ if (rc)
+ return rc;
if (method == RESET_TYPE_WORLD)
return efx_mcdi_reset_mc(efx);
@@ -582,6 +583,7 @@ struct efx_nic_type siena_a0_nic_type = {
.set_wol = siena_set_wol,
.resume_wol = siena_init_wol,
.test_registers = siena_test_registers,
+ .test_nvram = efx_mcdi_nvram_test_all,
.default_mac_ops = &efx_mcdi_mac_operations,
.revision = EFX_REV_SIENA_A0,
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index 3009c297c135..10db071bd837 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -842,6 +842,7 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = {
.get_settings = tenxpress_get_settings,
.set_settings = tenxpress_set_settings,
.set_npage_adv = sfx7101_set_npage_adv,
+ .test_alive = efx_mdio_test_alive,
.test_name = sfx7101_test_name,
.run_tests = sfx7101_run_tests,
};
@@ -856,6 +857,7 @@ struct efx_phy_operations falcon_sft9001_phy_ops = {
.get_settings = tenxpress_get_settings,
.set_settings = tenxpress_set_settings,
.set_npage_adv = sft9001_set_npage_adv,
+ .test_alive = efx_mdio_test_alive,
.test_name = sft9001_test_name,
.run_tests = sft9001_run_tests,
};
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 6b364a6c6c60..ed999d31f1fa 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -660,7 +660,7 @@ static void sgiseeq_set_multicast(struct net_device *dev)
if(dev->flags & IFF_PROMISC)
sp->mode = SEEQ_RCMD_RANY;
- else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count)
+ else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev))
sp->mode = SEEQ_RCMD_RBMCAST;
else
sp->mode = SEEQ_RCMD_RBCAST;
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 7402b858cab7..42a35f086a9f 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -1473,13 +1473,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
if (ret)
goto out_unregister;
- /* pritnt device infomation */
- pr_info("Base address at 0x%x, ",
- (u32)ndev->base_addr);
-
- for (i = 0; i < 5; i++)
- printk("%02X:", ndev->dev_addr[i]);
- printk("%02X, IRQ %d.\n", ndev->dev_addr[i], ndev->irq);
+ /* print device infomation */
+ pr_info("Base address at 0x%x, %pM, IRQ %d.\n",
+ (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
platform_set_drvdata(pdev, ndev);
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 31233b4c44a0..760d9e83a465 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -17,7 +17,9 @@
See the file COPYING in this distribution for more information.
- */
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -32,25 +34,13 @@
#include <linux/dma-mapping.h>
#include <asm/irq.h>
-#define net_drv(p, arg...) if (netif_msg_drv(p)) \
- printk(arg)
-#define net_probe(p, arg...) if (netif_msg_probe(p)) \
- printk(arg)
-#define net_link(p, arg...) if (netif_msg_link(p)) \
- printk(arg)
-#define net_intr(p, arg...) if (netif_msg_intr(p)) \
- printk(arg)
-#define net_tx_err(p, arg...) if (netif_msg_tx_err(p)) \
- printk(arg)
-
#define PHY_MAX_ADDR 32
#define PHY_ID_ANY 0x1f
#define MII_REG_ANY 0x1f
-#define DRV_VERSION "1.3"
+#define DRV_VERSION "1.4"
#define DRV_NAME "sis190"
#define SIS190_DRIVER_NAME DRV_NAME " Gigabit Ethernet driver " DRV_VERSION
-#define PFX DRV_NAME ": "
#define sis190_rx_skb netif_rx
#define sis190_rx_quota(count, quota) count
@@ -294,6 +284,12 @@ struct sis190_private {
struct mii_if_info mii_if;
struct list_head first_phy;
u32 features;
+ u32 negotiated_lpa;
+ enum {
+ LNK_OFF,
+ LNK_ON,
+ LNK_AUTONEG,
+ } link_status;
};
struct sis190_phy {
@@ -334,7 +330,7 @@ static const struct {
{ "SiS 191 PCI Gigabit Ethernet adapter" },
};
-static struct pci_device_id sis190_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(sis190_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0190), 0, 0, 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0191), 0, 0, 1 },
{ 0, },
@@ -381,7 +377,7 @@ static void __mdio_cmd(void __iomem *ioaddr, u32 ctl)
}
if (i > 99)
- printk(KERN_ERR PFX "PHY command failed !\n");
+ pr_err("PHY command failed !\n");
}
static void mdio_write(void __iomem *ioaddr, int phy_id, int reg, int val)
@@ -493,18 +489,24 @@ static struct sk_buff *sis190_alloc_rx_skb(struct sis190_private *tp,
{
u32 rx_buf_sz = tp->rx_buf_sz;
struct sk_buff *skb;
+ dma_addr_t mapping;
skb = netdev_alloc_skb(tp->dev, rx_buf_sz);
- if (likely(skb)) {
- dma_addr_t mapping;
-
- mapping = pci_map_single(tp->pci_dev, skb->data, tp->rx_buf_sz,
- PCI_DMA_FROMDEVICE);
- sis190_map_to_asic(desc, mapping, rx_buf_sz);
- } else
- sis190_make_unusable_by_asic(desc);
+ if (unlikely(!skb))
+ goto skb_alloc_failed;
+ mapping = pci_map_single(tp->pci_dev, skb->data, tp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(tp->pci_dev, mapping))
+ goto out;
+ sis190_map_to_asic(desc, mapping, rx_buf_sz);
return skb;
+
+out:
+ dev_kfree_skb_any(skb);
+skb_alloc_failed:
+ sis190_make_unusable_by_asic(desc);
+ return NULL;
}
static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev,
@@ -589,8 +591,7 @@ static int sis190_rx_interrupt(struct net_device *dev,
status = le32_to_cpu(desc->PSize);
- // net_intr(tp, KERN_INFO "%s: Rx PSize = %08x.\n", dev->name,
- // status);
+ //netif_info(tp, intr, dev, "Rx PSize = %08x\n", status);
if (sis190_rx_pkt_err(status, stats) < 0)
sis190_give_to_asic(desc, tp->rx_buf_sz);
@@ -601,9 +602,8 @@ static int sis190_rx_interrupt(struct net_device *dev,
struct pci_dev *pdev = tp->pci_dev;
if (unlikely(pkt_size > tp->rx_buf_sz)) {
- net_intr(tp, KERN_INFO
- "%s: (frag) status = %08x.\n",
- dev->name, status);
+ netif_info(tp, intr, dev,
+ "(frag) status = %08x\n", status);
stats->rx_dropped++;
stats->rx_length_errors++;
sis190_give_to_asic(desc, tp->rx_buf_sz);
@@ -637,12 +637,12 @@ static int sis190_rx_interrupt(struct net_device *dev,
tp->cur_rx = cur_rx;
delta = sis190_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx);
- if (!delta && count && netif_msg_intr(tp))
- printk(KERN_INFO "%s: no Rx buffer allocated.\n", dev->name);
+ if (!delta && count)
+ netif_info(tp, intr, dev, "no Rx buffer allocated\n");
tp->dirty_rx += delta;
- if (((tp->dirty_rx + NUM_RX_DESC) == tp->cur_rx) && netif_msg_intr(tp))
- printk(KERN_EMERG "%s: Rx buffers exhausted.\n", dev->name);
+ if ((tp->dirty_rx + NUM_RX_DESC) == tp->cur_rx)
+ netif_emerg(tp, intr, dev, "Rx buffers exhausted\n");
return count;
}
@@ -751,10 +751,11 @@ static irqreturn_t sis190_interrupt(int irq, void *__dev)
SIS_W32(IntrStatus, status);
- // net_intr(tp, KERN_INFO "%s: status = %08x.\n", dev->name, status);
+// netif_info(tp, intr, dev, "status = %08x\n", status);
if (status & LinkChange) {
- net_intr(tp, KERN_INFO "%s: link change.\n", dev->name);
+ netif_info(tp, intr, dev, "link change\n");
+ del_timer(&tp->timer);
schedule_work(&tp->phy_task);
}
@@ -841,19 +842,17 @@ static void sis190_set_rx_mode(struct net_device *dev)
AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
AcceptAllPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
- } else if ((dev->mc_count > multicast_filter_limit) ||
+ } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
(dev->flags & IFF_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
} else {
struct dev_mc_list *mclist;
- unsigned int i;
rx_mode = AcceptBroadcast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int bit_nr =
ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f;
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
@@ -929,13 +928,15 @@ static void sis190_phy_task(struct work_struct *work)
if (val & BMCR_RESET) {
// FIXME: needlessly high ? -- FR 02/07/2005
mod_timer(&tp->timer, jiffies + HZ/10);
- } else if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) &
- BMSR_ANEGCOMPLETE)) {
+ goto out_unlock;
+ }
+
+ val = mdio_read_latched(ioaddr, phy_id, MII_BMSR);
+ if (!(val & BMSR_ANEGCOMPLETE) && tp->link_status != LNK_AUTONEG) {
netif_carrier_off(dev);
- net_link(tp, KERN_WARNING "%s: auto-negotiating...\n",
- dev->name);
- mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT);
- } else {
+ netif_warn(tp, link, dev, "auto-negotiating...\n");
+ tp->link_status = LNK_AUTONEG;
+ } else if ((val & BMSR_LSTATUS) && tp->link_status != LNK_ON) {
/* Rejoice ! */
struct {
int val;
@@ -959,13 +960,13 @@ static void sis190_phy_task(struct work_struct *work)
u16 adv, autoexp, gigadv, gigrec;
val = mdio_read(ioaddr, phy_id, 0x1f);
- net_link(tp, KERN_INFO "%s: mii ext = %04x.\n", dev->name, val);
+ netif_info(tp, link, dev, "mii ext = %04x\n", val);
val = mdio_read(ioaddr, phy_id, MII_LPA);
adv = mdio_read(ioaddr, phy_id, MII_ADVERTISE);
autoexp = mdio_read(ioaddr, phy_id, MII_EXPANSION);
- net_link(tp, KERN_INFO "%s: mii lpa=%04x adv=%04x exp=%04x.\n",
- dev->name, val, adv, autoexp);
+ netif_info(tp, link, dev, "mii lpa=%04x adv=%04x exp=%04x\n",
+ val, adv, autoexp);
if (val & LPA_NPAGE && autoexp & EXPANSION_NWAY) {
/* check for gigabit speed */
@@ -1004,10 +1005,14 @@ static void sis190_phy_task(struct work_struct *work)
SIS_W32(RGDelay, 0x0440);
}
- net_link(tp, KERN_INFO "%s: link on %s mode.\n", dev->name,
- p->msg);
+ tp->negotiated_lpa = p->val;
+
+ netif_info(tp, link, dev, "link on %s mode\n", p->msg);
netif_carrier_on(dev);
- }
+ tp->link_status = LNK_ON;
+ } else if (!(val & BMSR_LSTATUS) && tp->link_status != LNK_AUTONEG)
+ tp->link_status = LNK_OFF;
+ mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT);
out_unlock:
rtnl_unlock();
@@ -1191,13 +1196,17 @@ static netdev_tx_t sis190_start_xmit(struct sk_buff *skb,
if (unlikely(le32_to_cpu(desc->status) & OWNbit)) {
netif_stop_queue(dev);
- net_tx_err(tp, KERN_ERR PFX
- "%s: BUG! Tx Ring full when queue awake!\n",
- dev->name);
+ netif_err(tp, tx_err, dev,
+ "BUG! Tx Ring full when queue awake!\n");
return NETDEV_TX_BUSY;
}
mapping = pci_map_single(tp->pci_dev, skb->data, len, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(tp->pci_dev, mapping)) {
+ netif_err(tp, tx_err, dev,
+ "PCI mapping failed, dropping packet");
+ return NETDEV_TX_BUSY;
+ }
tp->Tx_skbuff[entry] = skb;
@@ -1211,6 +1220,12 @@ static netdev_tx_t sis190_start_xmit(struct sk_buff *skb,
wmb();
desc->status = cpu_to_le32(OWNbit | INTbit | DEFbit | CRCbit | PADbit);
+ if (tp->negotiated_lpa & (LPA_1000HALF | LPA_100HALF | LPA_10HALF)) {
+ /* Half Duplex */
+ desc->status |= cpu_to_le32(COLEN | CRSEN | BKFEN);
+ if (tp->negotiated_lpa & (LPA_1000HALF | LPA_1000FULL))
+ desc->status |= cpu_to_le32(EXTEN | BSTEN); /* gigabit HD */
+ }
tp->cur_tx++;
@@ -1287,9 +1302,9 @@ static u16 sis190_default_phy(struct net_device *dev)
if (mii_if->phy_id != phy_default->phy_id) {
mii_if->phy_id = phy_default->phy_id;
- net_probe(tp, KERN_INFO
- "%s: Using transceiver at address %d as default.\n",
- pci_name(tp->pci_dev), mii_if->phy_id);
+ if (netif_msg_probe(tp))
+ pr_info("%s: Using transceiver at address %d as default\n",
+ pci_name(tp->pci_dev), mii_if->phy_id);
}
status = mdio_read(ioaddr, mii_if->phy_id, MII_BMCR);
@@ -1327,14 +1342,15 @@ static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp,
((mii_status & (BMSR_100FULL | BMSR_100HALF)) ?
LAN : HOME) : p->type;
tp->features |= p->feature;
- net_probe(tp, KERN_INFO "%s: %s transceiver at address %d.\n",
- pci_name(tp->pci_dev), p->name, phy_id);
+ if (netif_msg_probe(tp))
+ pr_info("%s: %s transceiver at address %d\n",
+ pci_name(tp->pci_dev), p->name, phy_id);
} else {
phy->type = UNKNOWN;
- net_probe(tp, KERN_INFO
- "%s: unknown PHY 0x%x:0x%x transceiver at address %d\n",
- pci_name(tp->pci_dev),
- phy->id[0], (phy->id[1] & 0xfff0), phy_id);
+ if (netif_msg_probe(tp))
+ pr_info("%s: unknown PHY 0x%x:0x%x transceiver at address %d\n",
+ pci_name(tp->pci_dev),
+ phy->id[0], (phy->id[1] & 0xfff0), phy_id);
}
}
@@ -1398,8 +1414,9 @@ static int __devinit sis190_mii_probe(struct net_device *dev)
}
if (list_empty(&tp->first_phy)) {
- net_probe(tp, KERN_INFO "%s: No MII transceivers found!\n",
- pci_name(tp->pci_dev));
+ if (netif_msg_probe(tp))
+ pr_info("%s: No MII transceivers found!\n",
+ pci_name(tp->pci_dev));
rc = -EIO;
goto out;
}
@@ -1445,7 +1462,8 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev)
dev = alloc_etherdev(sizeof(*tp));
if (!dev) {
- net_drv(&debug, KERN_ERR PFX "unable to alloc new ethernet\n");
+ if (netif_msg_drv(&debug))
+ pr_err("unable to alloc new ethernet\n");
rc = -ENOMEM;
goto err_out_0;
}
@@ -1458,34 +1476,39 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev)
rc = pci_enable_device(pdev);
if (rc < 0) {
- net_probe(tp, KERN_ERR "%s: enable failure\n", pci_name(pdev));
+ if (netif_msg_probe(tp))
+ pr_err("%s: enable failure\n", pci_name(pdev));
goto err_free_dev_1;
}
rc = -ENODEV;
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- net_probe(tp, KERN_ERR "%s: region #0 is no MMIO resource.\n",
- pci_name(pdev));
+ if (netif_msg_probe(tp))
+ pr_err("%s: region #0 is no MMIO resource\n",
+ pci_name(pdev));
goto err_pci_disable_2;
}
if (pci_resource_len(pdev, 0) < SIS190_REGS_SIZE) {
- net_probe(tp, KERN_ERR "%s: invalid PCI region size(s).\n",
- pci_name(pdev));
+ if (netif_msg_probe(tp))
+ pr_err("%s: invalid PCI region size(s)\n",
+ pci_name(pdev));
goto err_pci_disable_2;
}
rc = pci_request_regions(pdev, DRV_NAME);
if (rc < 0) {
- net_probe(tp, KERN_ERR PFX "%s: could not request regions.\n",
- pci_name(pdev));
+ if (netif_msg_probe(tp))
+ pr_err("%s: could not request regions\n",
+ pci_name(pdev));
goto err_pci_disable_2;
}
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc < 0) {
- net_probe(tp, KERN_ERR "%s: DMA configuration failed.\n",
- pci_name(pdev));
+ if (netif_msg_probe(tp))
+ pr_err("%s: DMA configuration failed\n",
+ pci_name(pdev));
goto err_free_res_3;
}
@@ -1493,14 +1516,16 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev)
ioaddr = ioremap(pci_resource_start(pdev, 0), SIS190_REGS_SIZE);
if (!ioaddr) {
- net_probe(tp, KERN_ERR "%s: cannot remap MMIO, aborting\n",
- pci_name(pdev));
+ if (netif_msg_probe(tp))
+ pr_err("%s: cannot remap MMIO, aborting\n",
+ pci_name(pdev));
rc = -EIO;
goto err_free_res_3;
}
tp->pci_dev = pdev;
tp->mmio_addr = ioaddr;
+ tp->link_status = LNK_OFF;
sis190_irq_mask_and_ack(ioaddr);
@@ -1530,9 +1555,8 @@ static void sis190_tx_timeout(struct net_device *dev)
if (tmp8 & CmdTxEnb)
SIS_W8(TxControl, tmp8 & ~CmdTxEnb);
-
- net_tx_err(tp, KERN_INFO "%s: Transmit timeout, status %08x %08x.\n",
- dev->name, SIS_R32(TxControl), SIS_R32(TxSts));
+ netif_info(tp, tx_err, dev, "Transmit timeout, status %08x %08x\n",
+ SIS_R32(TxControl), SIS_R32(TxSts));
/* Disable interrupts by clearing the interrupt mask. */
SIS_W32(IntrMask, 0x0000);
@@ -1561,15 +1585,16 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev,
u16 sig;
int i;
- net_probe(tp, KERN_INFO "%s: Read MAC address from EEPROM\n",
- pci_name(pdev));
+ if (netif_msg_probe(tp))
+ pr_info("%s: Read MAC address from EEPROM\n", pci_name(pdev));
/* Check to see if there is a sane EEPROM */
sig = (u16) sis190_read_eeprom(ioaddr, EEPROMSignature);
if ((sig == 0xffff) || (sig == 0x0000)) {
- net_probe(tp, KERN_INFO "%s: Error EEPROM read %x.\n",
- pci_name(pdev), sig);
+ if (netif_msg_probe(tp))
+ pr_info("%s: Error EEPROM read %x\n",
+ pci_name(pdev), sig);
return -EIO;
}
@@ -1603,8 +1628,8 @@ static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev,
u8 reg, tmp8;
unsigned int i;
- net_probe(tp, KERN_INFO "%s: Read MAC address from APC.\n",
- pci_name(pdev));
+ if (netif_msg_probe(tp))
+ pr_info("%s: Read MAC address from APC\n", pci_name(pdev));
for (i = 0; i < ARRAY_SIZE(ids); i++) {
isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, ids[i], NULL);
@@ -1613,8 +1638,9 @@ static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev,
}
if (!isa_bridge) {
- net_probe(tp, KERN_INFO "%s: Can not find ISA bridge.\n",
- pci_name(pdev));
+ if (netif_msg_probe(tp))
+ pr_info("%s: Can not find ISA bridge\n",
+ pci_name(pdev));
return -EIO;
}
@@ -1695,7 +1721,7 @@ static void sis190_set_speed_auto(struct net_device *dev)
int phy_id = tp->mii_if.phy_id;
int val;
- net_link(tp, KERN_INFO "%s: Enabling Auto-negotiation.\n", dev->name);
+ netif_info(tp, link, dev, "Enabling Auto-negotiation\n");
val = mdio_read(ioaddr, phy_id, MII_ADVERTISE);
@@ -1822,7 +1848,8 @@ static int __devinit sis190_init_one(struct pci_dev *pdev,
int rc;
if (!printed_version) {
- net_drv(&debug, KERN_INFO SIS190_DRIVER_NAME " loaded.\n");
+ if (netif_msg_drv(&debug))
+ pr_info(SIS190_DRIVER_NAME " loaded\n");
printed_version = 1;
}
@@ -1862,12 +1889,14 @@ static int __devinit sis190_init_one(struct pci_dev *pdev,
if (rc < 0)
goto err_remove_mii;
- net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), %pM\n",
- pci_name(pdev), sis_chip_info[ent->driver_data].name,
- ioaddr, dev->irq, dev->dev_addr);
-
- net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name,
- (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII");
+ if (netif_msg_probe(tp)) {
+ netdev_info(dev, "%s: %s at %p (IRQ: %d), %pM\n",
+ pci_name(pdev),
+ sis_chip_info[ent->driver_data].name,
+ ioaddr, dev->irq, dev->dev_addr);
+ netdev_info(dev, "%s mode.\n",
+ (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII");
+ }
netif_carrier_off(dev);
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 7360d4bbf75e..cc0c731c4f09 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -106,7 +106,7 @@ static const char * card_names[] = {
"SiS 900 PCI Fast Ethernet",
"SiS 7016 PCI Fast Ethernet"
};
-static struct pci_device_id sis900_pci_tbl [] = {
+static DEFINE_PCI_DEVICE_TABLE(sis900_pci_tbl) = {
{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_900},
{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016,
@@ -2288,7 +2288,7 @@ static void set_rx_mode(struct net_device *net_dev)
rx_mode = RFPromiscuous;
for (i = 0; i < table_entries; i++)
mc_filter[i] = 0xffff;
- } else if ((net_dev->mc_count > multicast_filter_limit) ||
+ } else if ((netdev_mc_count(net_dev) > multicast_filter_limit) ||
(net_dev->flags & IFF_ALLMULTI)) {
/* too many multicast addresses or accept all multicast packet */
rx_mode = RFAAB | RFAAM;
@@ -2300,9 +2300,8 @@ static void set_rx_mode(struct net_device *net_dev)
* packets */
struct dev_mc_list *mclist;
rx_mode = RFAAB;
- for (i = 0, mclist = net_dev->mc_list;
- mclist && i < net_dev->mc_count;
- i++, mclist = mclist->next) {
+
+ netdev_for_each_mc_addr(mclist, net_dev) {
unsigned int bit_nr =
sis900_mcast_bitnr(mclist->dmi_addr, sis_priv->chipset_rev);
mc_filter[bit_nr >> 4] |= (1 << (bit_nr & 0xf));
diff --git a/drivers/net/skfp/ess.c b/drivers/net/skfp/ess.c
index a85efcfd9d0e..e8387d25f24a 100644
--- a/drivers/net/skfp/ess.c
+++ b/drivers/net/skfp/ess.c
@@ -557,7 +557,7 @@ static void ess_send_alc_req(struct s_smc *smc)
/*
* send never allocation request where the requested payload and
- * overhead is zero or deallocate bandwidht when no bandwidth is
+ * overhead is zero or deallocate bandwidth when no bandwidth is
* parsed
*/
if (!smc->mib.fddiESSPayload) {
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index db216a728503..1921a54ea995 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -149,7 +149,7 @@ extern void mac_drv_rx_mode(struct s_smc *smc, int mode);
extern void mac_drv_clear_rx_queue(struct s_smc *smc);
extern void enable_tx_irq(struct s_smc *smc, u_short queue);
-static struct pci_device_id skfddi_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(skfddi_pci_tbl) = {
{ PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, },
{ } /* Terminating entry */
};
@@ -435,13 +435,7 @@ static int skfp_driver_init(struct net_device *dev)
goto fail;
}
read_address(smc, NULL);
- pr_debug(KERN_INFO "HW-Addr: %02x %02x %02x %02x %02x %02x\n",
- smc->hw.fddi_canon_addr.a[0],
- smc->hw.fddi_canon_addr.a[1],
- smc->hw.fddi_canon_addr.a[2],
- smc->hw.fddi_canon_addr.a[3],
- smc->hw.fddi_canon_addr.a[4],
- smc->hw.fddi_canon_addr.a[5]);
+ pr_debug(KERN_INFO "HW-Addr: %pMF\n", smc->hw.fddi_canon_addr.a);
memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6);
smt_reset_defaults(smc, 0);
@@ -858,8 +852,7 @@ static void skfp_ctl_set_multicast_list(struct net_device *dev)
static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev)
{
struct s_smc *smc = netdev_priv(dev);
- struct dev_mc_list *dmi; /* ptr to multicast addr entry */
- int i;
+ struct dev_mc_list *dmi;
/* Enable promiscuous mode, if necessary */
if (dev->flags & IFF_PROMISC) {
@@ -878,29 +871,19 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev)
if (dev->flags & IFF_ALLMULTI) {
mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI);
pr_debug(KERN_INFO "ENABLE ALL MC ADDRESSES\n");
- } else if (dev->mc_count > 0) {
- if (dev->mc_count <= FPMAX_MULTICAST) {
+ } else if (!netdev_mc_empty(dev)) {
+ if (netdev_mc_count(dev) <= FPMAX_MULTICAST) {
/* use exact filtering */
// point to first multicast addr
- dmi = dev->mc_list;
-
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
mac_add_multicast(smc,
(struct fddi_addr *)dmi->dmi_addr,
1);
- pr_debug(KERN_INFO "ENABLE MC ADDRESS:");
- pr_debug(" %02x %02x %02x ",
- dmi->dmi_addr[0],
- dmi->dmi_addr[1],
- dmi->dmi_addr[2]);
- pr_debug("%02x %02x %02x\n",
- dmi->dmi_addr[3],
- dmi->dmi_addr[4],
- dmi->dmi_addr[5]);
- dmi = dmi->next;
- } // for
+ pr_debug(KERN_INFO "ENABLE MC ADDRESS: %pMF\n",
+ dmi->dmi_addr);
+ }
} else { // more MC addresses than HW supports
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 379a3dc00163..d0058e5bb6ae 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -23,6 +23,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -46,7 +48,6 @@
#define DRV_NAME "skge"
#define DRV_VERSION "1.13"
-#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
#define DEFAULT_RX_RING_SIZE 512
@@ -70,15 +71,15 @@ MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
-static const u32 default_msg
- = NETIF_MSG_DRV| NETIF_MSG_PROBE| NETIF_MSG_LINK
- | NETIF_MSG_IFUP| NETIF_MSG_IFDOWN;
+static const u32 default_msg = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
+ NETIF_MSG_LINK | NETIF_MSG_IFUP |
+ NETIF_MSG_IFDOWN);
static int debug = -1; /* defaults above */
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
-static const struct pci_device_id skge_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(skge_id_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940) },
{ PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B) },
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) },
@@ -187,8 +188,8 @@ static void skge_wol_init(struct skge_port *skge)
/* Force to 10/100 skge_reset will re-enable on resume */
gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
- PHY_AN_100FULL | PHY_AN_100HALF |
- PHY_AN_10FULL | PHY_AN_10HALF| PHY_AN_CSMA);
+ (PHY_AN_100FULL | PHY_AN_100HALF |
+ PHY_AN_10FULL | PHY_AN_10HALF | PHY_AN_CSMA));
/* no 1000 HD/FD */
gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, 0);
gm_phy_write(hw, port, PHY_MARV_CTRL,
@@ -257,25 +258,28 @@ static u32 skge_supported_modes(const struct skge_hw *hw)
u32 supported;
if (hw->copper) {
- supported = SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full
- | SUPPORTED_Autoneg| SUPPORTED_TP;
+ supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_TP);
if (hw->chip_id == CHIP_ID_GENESIS)
- supported &= ~(SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full);
+ supported &= ~(SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full);
else if (hw->chip_id == CHIP_ID_YUKON)
supported &= ~SUPPORTED_1000baseT_Half;
} else
- supported = SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half
- | SUPPORTED_FIBRE | SUPPORTED_Autoneg;
+ supported = (SUPPORTED_1000baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Autoneg);
return supported;
}
@@ -365,7 +369,7 @@ static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
}
}
- return (0);
+ return 0;
}
static void skge_get_drvinfo(struct net_device *dev,
@@ -812,7 +816,7 @@ static int skge_get_eeprom_len(struct net_device *dev)
u32 reg2;
pci_read_config_dword(skge->hw->pdev, PCI_DEV_REG2, &reg2);
- return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8);
+ return 1 << (((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8);
}
static u32 skge_vpd_read(struct pci_dev *pdev, int cap, u16 offset)
@@ -1043,7 +1047,7 @@ static int skge_rx_fill(struct net_device *dev)
skb_reserve(skb, NET_IP_ALIGN);
skge_rx_setup(skge, e, skb, skge->rx_buf_size);
- } while ( (e = e->next) != ring->start);
+ } while ((e = e->next) != ring->start);
ring->to_clean = ring->start;
return 0;
@@ -1051,7 +1055,7 @@ static int skge_rx_fill(struct net_device *dev)
static const char *skge_pause(enum pause_status status)
{
- switch(status) {
+ switch (status) {
case FLOW_STAT_NONE:
return "none";
case FLOW_STAT_REM_SEND:
@@ -1074,13 +1078,11 @@ static void skge_link_up(struct skge_port *skge)
netif_carrier_on(skge->netdev);
netif_wake_queue(skge->netdev);
- if (netif_msg_link(skge)) {
- printk(KERN_INFO PFX
- "%s: Link is up at %d Mbps, %s duplex, flow control %s\n",
- skge->netdev->name, skge->speed,
- skge->duplex == DUPLEX_FULL ? "full" : "half",
- skge_pause(skge->flow_status));
- }
+ netif_info(skge, link, skge->netdev,
+ "Link is up at %d Mbps, %s duplex, flow control %s\n",
+ skge->speed,
+ skge->duplex == DUPLEX_FULL ? "full" : "half",
+ skge_pause(skge->flow_status));
}
static void skge_link_down(struct skge_port *skge)
@@ -1089,8 +1091,7 @@ static void skge_link_down(struct skge_port *skge)
netif_carrier_off(skge->netdev);
netif_stop_queue(skge->netdev);
- if (netif_msg_link(skge))
- printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name);
+ netif_info(skge, link, skge->netdev, "Link is down\n");
}
@@ -1132,8 +1133,7 @@ static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg)
{
u16 v = 0;
if (__xm_phy_read(hw, port, reg, &v))
- printk(KERN_WARNING PFX "%s: phy read timed out\n",
- hw->dev[port]->name);
+ pr_warning("%s: phy read timed out\n", hw->dev[port]->name);
return v;
}
@@ -1255,8 +1255,7 @@ static void bcom_check_link(struct skge_hw *hw, int port)
lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
if (lpa & PHY_B_AN_RF) {
- printk(KERN_NOTICE PFX "%s: remote fault\n",
- dev->name);
+ netdev_notice(dev, "remote fault\n");
return;
}
@@ -1271,8 +1270,7 @@ static void bcom_check_link(struct skge_hw *hw, int port)
skge->duplex = DUPLEX_HALF;
break;
default:
- printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
- dev->name);
+ netdev_notice(dev, "duplex mismatch\n");
return;
}
@@ -1327,7 +1325,7 @@ static void bcom_phy_init(struct skge_port *skge)
/* Optimize MDIO transfer by suppressing preamble. */
r = xm_read16(hw, port, XM_MMU_CMD);
r |= XM_MMU_NO_PRE;
- xm_write16(hw, port, XM_MMU_CMD,r);
+ xm_write16(hw, port, XM_MMU_CMD, r);
switch (id1) {
case PHY_BCOM_ID1_C0:
@@ -1464,8 +1462,7 @@ static int xm_check_link(struct net_device *dev)
lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
if (lpa & PHY_B_AN_RF) {
- printk(KERN_NOTICE PFX "%s: remote fault\n",
- dev->name);
+ netdev_notice(dev, "remote fault\n");
return 0;
}
@@ -1480,8 +1477,7 @@ static int xm_check_link(struct net_device *dev)
skge->duplex = DUPLEX_HALF;
break;
default:
- printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
- dev->name);
+ netdev_notice(dev, "duplex mismatch\n");
return 0;
}
@@ -1519,7 +1515,7 @@ static void xm_link_timer(unsigned long arg)
{
struct skge_port *skge = (struct skge_port *) arg;
struct net_device *dev = skge->netdev;
- struct skge_hw *hw = skge->hw;
+ struct skge_hw *hw = skge->hw;
int port = skge->port;
int i;
unsigned long flags;
@@ -1538,7 +1534,7 @@ static void xm_link_timer(unsigned long arg)
goto link_down;
}
- /* Re-enable interrupt to detect link down */
+ /* Re-enable interrupt to detect link down */
if (xm_check_link(dev)) {
u16 msk = xm_read16(hw, port, XM_IMSK);
msk &= ~XM_IS_INP_ASS;
@@ -1569,7 +1565,7 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
udelay(1);
}
- printk(KERN_WARNING PFX "%s: genesis reset failed\n", dev->name);
+ netdev_warn(dev, "genesis reset failed\n");
reset_ok:
/* Unreset the XMAC. */
@@ -1595,7 +1591,7 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
}
- switch(hw->phy_type) {
+ switch (hw->phy_type) {
case SK_PHY_XMAC:
xm_phy_init(skge);
break;
@@ -1702,7 +1698,7 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
if (jumbo) {
/* Enable frame flushing if jumbo frames used */
- skge_write16(hw, SK_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH);
+ skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_FLUSH);
} else {
/* enable timeout timers if normal frames */
skge_write16(hw, B3_PA_CTRL,
@@ -1717,7 +1713,7 @@ static void genesis_stop(struct skge_port *skge)
unsigned retries = 1000;
u16 cmd;
- /* Disable Tx and Rx */
+ /* Disable Tx and Rx */
cmd = xm_read16(hw, port, XM_MMU_CMD);
cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
xm_write16(hw, port, XM_MMU_CMD, cmd);
@@ -1792,12 +1788,11 @@ static void genesis_mac_intr(struct skge_hw *hw, int port)
struct skge_port *skge = netdev_priv(dev);
u16 status = xm_read16(hw, port, XM_ISRC);
- if (netif_msg_intr(skge))
- printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
- dev->name, status);
+ netif_printk(skge, intr, KERN_DEBUG, skge->netdev,
+ "mac interrupt status 0x%x\n", status);
if (hw->phy_type == SK_PHY_XMAC && (status & XM_IS_INP_ASS)) {
- xm_link_down(hw, port);
+ xm_link_down(hw, port);
mod_timer(&skge->link_timer, jiffies + 1);
}
@@ -1831,7 +1826,7 @@ static void genesis_link_up(struct skge_port *skge)
xm_write16(hw, port, XM_MMU_CMD, cmd);
mode = xm_read32(hw, port, XM_MODE);
- if (skge->flow_status== FLOW_STAT_SYMMETRIC ||
+ if (skge->flow_status == FLOW_STAT_SYMMETRIC ||
skge->flow_status == FLOW_STAT_LOC_SEND) {
/*
* Configure Pause Frame Generation
@@ -1898,12 +1893,11 @@ static inline void bcom_phy_intr(struct skge_port *skge)
u16 isrc;
isrc = xm_phy_read(hw, port, PHY_BCOM_INT_STAT);
- if (netif_msg_intr(skge))
- printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x\n",
- skge->netdev->name, isrc);
+ netif_printk(skge, intr, KERN_DEBUG, skge->netdev,
+ "phy interrupt status 0x%x\n", isrc);
if (isrc & PHY_B_IS_PSE)
- printk(KERN_ERR PFX "%s: uncorrectable pair swap error\n",
+ pr_err("%s: uncorrectable pair swap error\n",
hw->dev[port]->name);
/* Workaround BCom Errata:
@@ -1936,8 +1930,7 @@ static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
return 0;
}
- printk(KERN_WARNING PFX "%s: phy write timeout\n",
- hw->dev[port]->name);
+ pr_warning("%s: phy write timeout\n", hw->dev[port]->name);
return -EIO;
}
@@ -1965,8 +1958,7 @@ static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg)
{
u16 v = 0;
if (__gm_phy_read(hw, port, reg, &v))
- printk(KERN_WARNING PFX "%s: phy read timeout\n",
- hw->dev[port]->name);
+ pr_warning("%s: phy read timeout\n", hw->dev[port]->name);
return v;
}
@@ -2298,9 +2290,8 @@ static void yukon_mac_intr(struct skge_hw *hw, int port)
struct skge_port *skge = netdev_priv(dev);
u8 status = skge_read8(hw, SK_REG(port, GMAC_IRQ_SRC));
- if (netif_msg_intr(skge))
- printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
- dev->name, status);
+ netif_printk(skge, intr, KERN_DEBUG, skge->netdev,
+ "mac interrupt status 0x%x\n", status);
if (status & GM_IS_RX_FF_OR) {
++dev->stats.rx_fifo_errors;
@@ -2379,9 +2370,8 @@ static void yukon_phy_intr(struct skge_port *skge)
istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT);
phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
- if (netif_msg_intr(skge))
- printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x 0x%x\n",
- skge->netdev->name, istatus, phystat);
+ netif_printk(skge, intr, KERN_DEBUG, skge->netdev,
+ "phy interrupt status 0x%x 0x%x\n", istatus, phystat);
if (istatus & PHY_M_IS_AN_COMPL) {
if (gm_phy_read(hw, port, PHY_MARV_AUNE_LP)
@@ -2441,8 +2431,7 @@ static void yukon_phy_intr(struct skge_port *skge)
}
return;
failed:
- printk(KERN_ERR PFX "%s: autonegotiation failed (%s)\n",
- skge->netdev->name, reason);
+ pr_err("%s: autonegotiation failed (%s)\n", skge->netdev->name, reason);
/* XXX restart autonegotiation? */
}
@@ -2480,7 +2469,7 @@ static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (!netif_running(dev))
return -ENODEV; /* Phy still in reset */
- switch(cmd) {
+ switch (cmd) {
case SIOCGMIIPHY:
data->phy_id = hw->phy_addr;
@@ -2571,8 +2560,7 @@ static int skge_up(struct net_device *dev)
if (!is_valid_ether_addr(dev->dev_addr))
return -EINVAL;
- if (netif_msg_ifup(skge))
- printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
+ netif_info(skge, ifup, skge->netdev, "enabling interface\n");
if (dev->mtu > RX_BUF_SIZE)
skge->rx_buf_size = dev->mtu + ETH_HLEN;
@@ -2670,8 +2658,7 @@ static int skge_down(struct net_device *dev)
if (skge->mem == NULL)
return 0;
- if (netif_msg_ifdown(skge))
- printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
+ netif_info(skge, ifdown, skge->netdev, "disabling interface\n");
netif_tx_disable(dev);
@@ -2781,7 +2768,7 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
* does. Looks like hardware is wrong?
*/
if (ipip_hdr(skb)->protocol == IPPROTO_UDP &&
- hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON)
+ hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON)
control = BMU_TCP_CHECK;
else
control = BMU_UDP_CHECK;
@@ -2793,7 +2780,7 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
control = BMU_CHECK;
if (!skb_shinfo(skb)->nr_frags) /* single buffer i.e. no fragments */
- control |= BMU_EOF| BMU_IRQ_EOF;
+ control |= BMU_EOF | BMU_IRQ_EOF;
else {
struct skge_tx_desc *tf = td;
@@ -2825,15 +2812,15 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
skge_write8(hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_START);
- if (unlikely(netif_msg_tx_queued(skge)))
- printk(KERN_DEBUG "%s: tx queued, slot %td, len %d\n",
- dev->name, e - skge->tx_ring.start, skb->len);
+ netif_printk(skge, tx_queued, KERN_DEBUG, skge->netdev,
+ "tx queued, slot %td, len %d\n",
+ e - skge->tx_ring.start, skb->len);
skge->tx_ring.to_use = e->next;
smp_wmb();
if (skge_avail(&skge->tx_ring) <= TX_LOW_WATER) {
- pr_debug("%s: transmit queue full\n", dev->name);
+ netdev_dbg(dev, "transmit queue full\n");
netif_stop_queue(dev);
}
@@ -2858,9 +2845,8 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e,
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);
+ netif_printk(skge, tx_done, KERN_DEBUG, skge->netdev,
+ "tx done slot %td\n", e - skge->tx_ring.start);
dev_kfree_skb(e->skb);
}
@@ -2885,8 +2871,7 @@ static void skge_tx_timeout(struct net_device *dev)
{
struct skge_port *skge = netdev_priv(dev);
- if (netif_msg_timer(skge))
- printk(KERN_DEBUG PFX "%s: tx timeout\n", dev->name);
+ netif_printk(skge, timer, KERN_DEBUG, skge->netdev, "tx timeout\n");
skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_STOP);
skge_tx_clean(dev);
@@ -2932,8 +2917,7 @@ static void genesis_set_multicast(struct net_device *dev)
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
int port = skge->port;
- int i, count = dev->mc_count;
- struct dev_mc_list *list = dev->mc_list;
+ struct dev_mc_list *list;
u32 mode;
u8 filter[8];
@@ -2953,7 +2937,7 @@ static void genesis_set_multicast(struct net_device *dev)
skge->flow_status == FLOW_STAT_SYMMETRIC)
genesis_add_filter(filter, pause_mc_addr);
- for (i = 0; list && i < count; i++, list = list->next)
+ netdev_for_each_mc_addr(list, dev)
genesis_add_filter(filter, list->dmi_addr);
}
@@ -2972,7 +2956,7 @@ static void yukon_set_multicast(struct net_device *dev)
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
int port = skge->port;
- struct dev_mc_list *list = dev->mc_list;
+ struct dev_mc_list *list;
int rx_pause = (skge->flow_status == FLOW_STAT_REM_SEND ||
skge->flow_status == FLOW_STAT_SYMMETRIC);
u16 reg;
@@ -2987,16 +2971,15 @@ static void yukon_set_multicast(struct net_device *dev)
reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
else if (dev->flags & IFF_ALLMULTI) /* all multicast */
memset(filter, 0xff, sizeof(filter));
- else if (dev->mc_count == 0 && !rx_pause)/* no multicast */
+ else if (netdev_mc_empty(dev) && !rx_pause)/* no multicast */
reg &= ~GM_RXCR_MCF_ENA;
else {
- int i;
reg |= GM_RXCR_MCF_ENA;
if (rx_pause)
yukon_add_filter(filter, pause_mc_addr);
- for (i = 0; list && i < dev->mc_count; i++, list = list->next)
+ netdev_for_each_mc_addr(list, dev)
yukon_add_filter(filter, list->dmi_addr);
}
@@ -3054,10 +3037,9 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
struct sk_buff *skb;
u16 len = control & BMU_BBC;
- if (unlikely(netif_msg_rx_status(skge)))
- printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n",
- dev->name, e - skge->rx_ring.start,
- status, len);
+ netif_printk(skge, rx_status, KERN_DEBUG, skge->netdev,
+ "rx slot %td status 0x%x len %d\n",
+ e - skge->rx_ring.start, status, len);
if (len > skge->rx_buf_size)
goto error;
@@ -3096,7 +3078,7 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
pci_unmap_len(e, maplen),
PCI_DMA_FROMDEVICE);
skb = e->skb;
- prefetch(skb->data);
+ prefetch(skb->data);
skge_rx_setup(skge, e, nskb, skge->rx_buf_size);
}
@@ -3111,10 +3093,9 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
return skb;
error:
- if (netif_msg_rx_err(skge))
- printk(KERN_DEBUG PFX "%s: rx err, slot %td control 0x%x status 0x%x\n",
- dev->name, e - skge->rx_ring.start,
- control, status);
+ netif_printk(skge, rx_err, KERN_DEBUG, skge->netdev,
+ "rx err, slot %td control 0x%x status 0x%x\n",
+ e - skge->rx_ring.start, control, status);
if (skge->hw->chip_id == CHIP_ID_GENESIS) {
if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR))
@@ -3574,8 +3555,7 @@ static int skge_reset(struct skge_hw *hw)
hw->ram_offset = 0x80000;
} else
hw->ram_size = t8 * 512;
- }
- else if (t8 == 0)
+ } else if (t8 == 0)
hw->ram_size = 0x20000;
else
hw->ram_size = t8 * 4096;
@@ -3729,7 +3709,7 @@ static int skge_device_event(struct notifier_block *unused,
goto done;
skge = netdev_priv(dev);
- switch(event) {
+ switch (event) {
case NETDEV_CHANGENAME:
if (skge->debugfs) {
d = debugfs_rename(skge_debug, skge->debugfs,
@@ -3737,7 +3717,7 @@ static int skge_device_event(struct notifier_block *unused,
if (d)
skge->debugfs = d;
else {
- pr_info(PFX "%s: rename failed\n", dev->name);
+ netdev_info(dev, "rename failed\n");
debugfs_remove(skge->debugfs);
}
}
@@ -3755,8 +3735,7 @@ static int skge_device_event(struct notifier_block *unused,
skge_debug, dev,
&skge_debug_fops);
if (!d || IS_ERR(d))
- pr_info(PFX "%s: debugfs create failed\n",
- dev->name);
+ netdev_info(dev, "debugfs create failed\n");
else
skge->debugfs = d;
break;
@@ -3777,7 +3756,7 @@ static __init void skge_debug_init(void)
ent = debugfs_create_dir("skge", NULL);
if (!ent || IS_ERR(ent)) {
- pr_info(PFX "debugfs create directory failed\n");
+ pr_info("debugfs create directory failed\n");
return;
}
@@ -3885,9 +3864,7 @@ static void __devinit skge_show_addr(struct net_device *dev)
{
const struct skge_port *skge = netdev_priv(dev);
- if (netif_msg_probe(skge))
- printk(KERN_INFO PFX "%s: addr %pM\n",
- dev->name, dev->dev_addr);
+ netif_info(skge, probe, skge->netdev, "addr %pM\n", dev->dev_addr);
}
static int __devinit skge_probe(struct pci_dev *pdev,
@@ -3937,7 +3914,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
err = -ENOMEM;
/* space for skge@pci:0000:04:00.0 */
- hw = kzalloc(sizeof(*hw) + strlen(DRV_NAME "@pci:" )
+ hw = kzalloc(sizeof(*hw) + strlen(DRV_NAME "@pci:")
+ strlen(pci_name(pdev)) + 1, GFP_KERNEL);
if (!hw) {
dev_err(&pdev->dev, "cannot allocate hardware struct\n");
@@ -3960,9 +3937,10 @@ static int __devinit skge_probe(struct pci_dev *pdev,
if (err)
goto err_out_iounmap;
- printk(KERN_INFO PFX DRV_VERSION " addr 0x%llx irq %d chip %s rev %d\n",
- (unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
- skge_board_name(hw), hw->chip_rev);
+ pr_info("%s addr 0x%llx irq %d chip %s rev %d\n",
+ DRV_VERSION,
+ (unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
+ skge_board_name(hw), hw->chip_rev);
dev = skge_devinit(hw, 0, using_dac);
if (!dev)
@@ -4032,7 +4010,8 @@ static void __devexit skge_remove(struct pci_dev *pdev)
flush_scheduled_work();
- if ((dev1 = hw->dev[1]))
+ dev1 = hw->dev[1];
+ if (dev1)
unregister_netdev(dev1);
dev0 = hw->dev[0];
unregister_netdev(dev0);
@@ -4119,8 +4098,7 @@ static int skge_resume(struct pci_dev *pdev)
err = skge_up(dev);
if (err) {
- printk(KERN_ERR PFX "%s: could not up: %d\n",
- dev->name, err);
+ netdev_err(dev, "could not up: %d\n", err);
dev_close(dev);
goto out;
}
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 37f486b65f63..d8ec4c11fd49 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -22,6 +22,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/crc32.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -50,8 +52,7 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.26"
-#define PFX DRV_NAME " "
+#define DRV_VERSION "1.27"
/*
* The Yukon II chipset takes 64 bit command blocks (called list elements)
@@ -251,6 +252,8 @@ static void sky2_power_on(struct sky2_hw *hw)
sky2_pci_write32(hw, PCI_CFG_REG_1, 0);
+ sky2_write16(hw, B0_CTST, Y2_HW_WOL_ON);
+
/* Enable workaround for dev 4.107 on Yukon-Ultra & Extreme */
reg = sky2_read32(hw, B2_GP_IO);
reg |= GLB_GPIO_STAT_RACE_DIS;
@@ -644,6 +647,7 @@ static void sky2_phy_power_up(struct sky2_hw *hw, unsigned port)
{
u32 reg1;
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
reg1 &= ~phy_power[port];
@@ -651,6 +655,7 @@ static void sky2_phy_power_up(struct sky2_hw *hw, unsigned port)
reg1 |= coma_mode[port];
sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
sky2_pci_read32(hw, PCI_DEV_REG1);
if (hw->chip_id == CHIP_ID_YUKON_FE)
@@ -707,9 +712,11 @@ static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port)
gm_phy_write(hw, port, PHY_MARV_CTRL, PHY_CT_PDOWN);
}
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
reg1 |= phy_power[port]; /* set PHY to PowerDown/COMA Mode */
sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
}
/* Force a renegotiation */
@@ -727,7 +734,6 @@ static void sky2_wol_init(struct sky2_port *sky2)
unsigned port = sky2->port;
enum flow_control save_mode;
u16 ctrl;
- u32 reg1;
/* Bring hardware out of reset */
sky2_write16(hw, B0_CTST, CS_RST_CLR);
@@ -778,14 +784,11 @@ static void sky2_wol_init(struct sky2_port *sky2)
ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT;
sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
- /* Turn on legacy PCI-Express PME mode */
- reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
- reg1 |= PCI_Y2_PME_LEGACY;
- sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+ /* Disable PiG firmware */
+ sky2_write16(hw, B0_CTST, Y2_HW_WOL_OFF);
/* block receiver */
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
-
}
static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
@@ -796,29 +799,15 @@ static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
hw->chip_rev != CHIP_REV_YU_EX_A0) ||
hw->chip_id >= CHIP_ID_YUKON_FE_P) {
/* Yukon-Extreme B0 and further Extreme devices */
- /* enable Store & Forward mode for TX */
-
- if (dev->mtu <= ETH_DATA_LEN)
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_JUMBO_DIS | TX_STFW_ENA);
-
- else
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_JUMBO_ENA| TX_STFW_ENA);
- } else {
- if (dev->mtu <= ETH_DATA_LEN)
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA);
- else {
- /* set Tx GMAC FIFO Almost Empty Threshold */
- sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
- (ECU_JUMBO_WM << 16) | ECU_AE_THR);
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA);
+ } else if (dev->mtu > ETH_DATA_LEN) {
+ /* set Tx GMAC FIFO Almost Empty Threshold */
+ sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
+ (ECU_JUMBO_WM << 16) | ECU_AE_THR);
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_DIS);
-
- /* Can't do offload because of lack of store/forward */
- dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM);
- }
- }
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_DIS);
+ } else
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA);
}
static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
@@ -1021,11 +1010,8 @@ static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr,
static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot)
{
struct sky2_tx_le *le = sky2->tx_le + *slot;
- struct tx_ring_info *re = sky2->tx_ring + *slot;
*slot = RING_NEXT(*slot, sky2->tx_ring_size);
- re->flags = 0;
- re->skb = NULL;
le->ctrl = 0;
return le;
}
@@ -1064,6 +1050,40 @@ static inline struct sky2_rx_le *sky2_next_rx(struct sky2_port *sky2)
return le;
}
+static unsigned sky2_get_rx_threshold(struct sky2_port* sky2)
+{
+ unsigned size;
+
+ /* Space needed for frame data + headers rounded up */
+ size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8);
+
+ /* Stopping point for hardware truncation */
+ return (size - 8) / sizeof(u32);
+}
+
+static unsigned sky2_get_rx_data_size(struct sky2_port* sky2)
+{
+ struct rx_ring_info *re;
+ unsigned size;
+
+ /* Space needed for frame data + headers rounded up */
+ size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8);
+
+ sky2->rx_nfrags = size >> PAGE_SHIFT;
+ BUG_ON(sky2->rx_nfrags > ARRAY_SIZE(re->frag_addr));
+
+ /* Compute residue after pages */
+ size -= sky2->rx_nfrags << PAGE_SHIFT;
+
+ /* Optimize to handle small packets and headers */
+ if (size < copybreak)
+ size = copybreak;
+ if (size < ETH_HLEN)
+ size = ETH_HLEN;
+
+ return size;
+}
+
/* Build description to hardware for one receive segment */
static void sky2_rx_add(struct sky2_port *sky2, u8 op,
dma_addr_t map, unsigned len)
@@ -1102,18 +1122,39 @@ static int sky2_rx_map_skb(struct pci_dev *pdev, struct rx_ring_info *re,
int i;
re->data_addr = pci_map_single(pdev, skb->data, size, PCI_DMA_FROMDEVICE);
- if (unlikely(pci_dma_mapping_error(pdev, re->data_addr)))
- return -EIO;
+ if (pci_dma_mapping_error(pdev, re->data_addr))
+ goto mapping_error;
pci_unmap_len_set(re, data_size, size);
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- re->frag_addr[i] = pci_map_page(pdev,
- skb_shinfo(skb)->frags[i].page,
- skb_shinfo(skb)->frags[i].page_offset,
- skb_shinfo(skb)->frags[i].size,
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ re->frag_addr[i] = pci_map_page(pdev, frag->page,
+ frag->page_offset,
+ frag->size,
PCI_DMA_FROMDEVICE);
+
+ if (pci_dma_mapping_error(pdev, re->frag_addr[i]))
+ goto map_page_error;
+ }
return 0;
+
+map_page_error:
+ while (--i >= 0) {
+ pci_unmap_page(pdev, re->frag_addr[i],
+ skb_shinfo(skb)->frags[i].size,
+ PCI_DMA_FROMDEVICE);
+ }
+
+ pci_unmap_single(pdev, re->data_addr, pci_unmap_len(re, data_size),
+ PCI_DMA_FROMDEVICE);
+
+mapping_error:
+ if (net_ratelimit())
+ dev_warn(&pdev->dev, "%s: rx mapping error\n",
+ skb->dev->name);
+ return -EIO;
}
static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re)
@@ -1172,8 +1213,7 @@ static void sky2_rx_stop(struct sky2_port *sky2)
== sky2_read8(hw, RB_ADDR(rxq, Q_RL)))
goto stopped;
- printk(KERN_WARNING PFX "%s: receiver stop failed\n",
- sky2->netdev->name);
+ netdev_warn(sky2->netdev, "receiver stop failed\n");
stopped:
sky2_write32(hw, Q_ADDR(rxq, Q_CSR), BMU_RST_SET | BMU_FIFO_RST);
@@ -1323,8 +1363,32 @@ static inline void sky2_rx_update(struct sky2_port *sky2, unsigned rxq)
sky2_put_idx(sky2->hw, rxq, sky2->rx_put);
}
+static int sky2_alloc_rx_skbs(struct sky2_port *sky2)
+{
+ struct sky2_hw *hw = sky2->hw;
+ unsigned i;
+
+ sky2->rx_data_size = sky2_get_rx_data_size(sky2);
+
+ /* Fill Rx ring */
+ for (i = 0; i < sky2->rx_pending; i++) {
+ struct rx_ring_info *re = sky2->rx_ring + i;
+
+ re->skb = sky2_rx_alloc(sky2);
+ if (!re->skb)
+ return -ENOMEM;
+
+ if (sky2_rx_map_skb(hw->pdev, re, sky2->rx_data_size)) {
+ dev_kfree_skb(re->skb);
+ re->skb = NULL;
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
/*
- * Allocate and setup receiver buffer pool.
+ * Setup receiver buffer pool.
* Normal case this ends up creating one list element for skb
* in the receive ring. Worst case if using large MTU and each
* allocation falls on a different 64 bit region, that results
@@ -1332,12 +1396,12 @@ static inline void sky2_rx_update(struct sky2_port *sky2, unsigned rxq)
* One element is used for checksum enable/disable, and one
* extra to avoid wrap.
*/
-static int sky2_rx_start(struct sky2_port *sky2)
+static void sky2_rx_start(struct sky2_port *sky2)
{
struct sky2_hw *hw = sky2->hw;
struct rx_ring_info *re;
unsigned rxq = rxqaddr[sky2->port];
- unsigned i, size, thresh;
+ unsigned i, thresh;
sky2->rx_put = sky2->rx_next = 0;
sky2_qset(hw, rxq);
@@ -1358,40 +1422,9 @@ static int sky2_rx_start(struct sky2_port *sky2)
if (!(hw->flags & SKY2_HW_NEW_LE))
rx_set_checksum(sky2);
- /* Space needed for frame data + headers rounded up */
- size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8);
-
- /* Stopping point for hardware truncation */
- thresh = (size - 8) / sizeof(u32);
-
- sky2->rx_nfrags = size >> PAGE_SHIFT;
- BUG_ON(sky2->rx_nfrags > ARRAY_SIZE(re->frag_addr));
-
- /* Compute residue after pages */
- size -= sky2->rx_nfrags << PAGE_SHIFT;
-
- /* Optimize to handle small packets and headers */
- if (size < copybreak)
- size = copybreak;
- if (size < ETH_HLEN)
- size = ETH_HLEN;
-
- sky2->rx_data_size = size;
-
- /* Fill Rx ring */
+ /* submit Rx ring */
for (i = 0; i < sky2->rx_pending; i++) {
re = sky2->rx_ring + i;
-
- re->skb = sky2_rx_alloc(sky2);
- if (!re->skb)
- goto nomem;
-
- if (sky2_rx_map_skb(hw->pdev, re, sky2->rx_data_size)) {
- dev_kfree_skb(re->skb);
- re->skb = NULL;
- goto nomem;
- }
-
sky2_rx_submit(sky2, re);
}
@@ -1401,6 +1434,7 @@ static int sky2_rx_start(struct sky2_port *sky2)
* the register is limited to 9 bits, so if you do frames > 2052
* you better get the MTU right!
*/
+ thresh = sky2_get_rx_threshold(sky2);
if (thresh > 0x1ff)
sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_OFF);
else {
@@ -1432,13 +1466,6 @@ static int sky2_rx_start(struct sky2_port *sky2)
sky2_write32(hw, Q_ADDR(txqaddr[sky2->port], Q_TEST),
TBMU_TEST_HOME_ADD_FIX_EN | TBMU_TEST_ROUTING_ADD_FIX_EN);
}
-
-
-
- return 0;
-nomem:
- sky2_rx_clean(sky2);
- return -ENOMEM;
}
static int sky2_alloc_buffers(struct sky2_port *sky2)
@@ -1469,7 +1496,7 @@ static int sky2_alloc_buffers(struct sky2_port *sky2)
if (!sky2->rx_ring)
goto nomem;
- return 0;
+ return sky2_alloc_rx_skbs(sky2);
nomem:
return -ENOMEM;
}
@@ -1478,6 +1505,8 @@ static void sky2_free_buffers(struct sky2_port *sky2)
{
struct sky2_hw *hw = sky2->hw;
+ sky2_rx_clean(sky2);
+
if (sky2->rx_le) {
pci_free_consistent(hw->pdev, RX_LE_BYTES,
sky2->rx_le, sky2->rx_le_map);
@@ -1496,16 +1525,16 @@ static void sky2_free_buffers(struct sky2_port *sky2)
sky2->rx_ring = NULL;
}
-/* Bring up network interface. */
-static int sky2_up(struct net_device *dev)
+static void sky2_hw_up(struct sky2_port *sky2)
{
- struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
unsigned port = sky2->port;
- u32 imask, ramsize;
- int cap, err;
+ u32 ramsize;
+ int cap;
struct net_device *otherdev = hw->dev[sky2->port^1];
+ tx_init(sky2);
+
/*
* On dual port PCI-X card, there is an problem where status
* can be received out of order due to split transactions
@@ -1517,16 +1546,7 @@ static int sky2_up(struct net_device *dev)
cmd = sky2_pci_read16(hw, cap + PCI_X_CMD);
cmd &= ~PCI_X_CMD_MAX_SPLIT;
sky2_pci_write16(hw, cap + PCI_X_CMD, cmd);
-
- }
-
- netif_carrier_off(dev);
-
- err = sky2_alloc_buffers(sky2);
- if (err)
- goto err_out;
-
- tx_init(sky2);
+ }
sky2_mac_init(hw, port);
@@ -1535,7 +1555,7 @@ static int sky2_up(struct net_device *dev)
if (ramsize > 0) {
u32 rxspace;
- pr_debug(PFX "%s: ram buffer %dK\n", dev->name, ramsize);
+ netdev_dbg(sky2->netdev, "ram buffer %dK\n", ramsize);
if (ramsize < 16)
rxspace = ramsize / 2;
else
@@ -1567,18 +1587,33 @@ static int sky2_up(struct net_device *dev)
sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL);
#endif
- err = sky2_rx_start(sky2);
+ sky2_rx_start(sky2);
+}
+
+/* Bring up network interface. */
+static int sky2_up(struct net_device *dev)
+{
+ struct sky2_port *sky2 = netdev_priv(dev);
+ struct sky2_hw *hw = sky2->hw;
+ unsigned port = sky2->port;
+ u32 imask;
+ int err;
+
+ netif_carrier_off(dev);
+
+ err = sky2_alloc_buffers(sky2);
if (err)
goto err_out;
+ sky2_hw_up(sky2);
+
/* Enable interrupts from phy/mac for port */
imask = sky2_read32(hw, B0_IMSK);
imask |= portirq_msk[port];
sky2_write32(hw, B0_IMSK, imask);
sky2_read32(hw, B0_IMSK);
- if (netif_msg_ifup(sky2))
- printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
+ netif_info(sky2, ifup, dev, "enabling interface\n");
return 0;
@@ -1618,8 +1653,7 @@ static unsigned tx_le_req(const struct sk_buff *skb)
return count;
}
-static void sky2_tx_unmap(struct pci_dev *pdev,
- const struct tx_ring_info *re)
+static void sky2_tx_unmap(struct pci_dev *pdev, struct tx_ring_info *re)
{
if (re->flags & TX_MAP_SINGLE)
pci_unmap_single(pdev, pci_unmap_addr(re, mapaddr),
@@ -1629,6 +1663,7 @@ static void sky2_tx_unmap(struct pci_dev *pdev,
pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr),
pci_unmap_len(re, maplen),
PCI_DMA_TODEVICE);
+ re->flags = 0;
}
/*
@@ -1661,9 +1696,8 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
goto mapping_error;
slot = sky2->tx_prod;
- if (unlikely(netif_msg_tx_queued(sky2)))
- printk(KERN_DEBUG "%s: tx queued, slot %u, len %d\n",
- dev->name, slot, skb->len);
+ netif_printk(sky2, tx_queued, KERN_DEBUG, dev,
+ "tx queued, slot %u, len %d\n", slot, skb->len);
/* Send high bits if needed */
upper = upper_32_bits(mapping);
@@ -1828,13 +1862,13 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
sky2_tx_unmap(sky2->hw->pdev, re);
if (skb) {
- if (unlikely(netif_msg_tx_done(sky2)))
- printk(KERN_DEBUG "%s: tx done %u\n",
- dev->name, idx);
+ netif_printk(sky2, tx_done, KERN_DEBUG, dev,
+ "tx done %u\n", idx);
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
+ re->skb = NULL;
dev_kfree_skb_any(skb);
sky2->tx_next = RING_NEXT(idx, sky2->tx_ring_size);
@@ -1843,10 +1877,6 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
sky2->tx_cons = idx;
smp_mb();
-
- /* Wake unless it's detached, and called e.g. from sky2_down() */
- if (tx_avail(sky2) > MAX_SKB_TX_LE + 4 && netif_device_present(dev))
- netif_wake_queue(dev);
}
static void sky2_tx_reset(struct sky2_hw *hw, unsigned port)
@@ -1871,21 +1901,11 @@ static void sky2_tx_reset(struct sky2_hw *hw, unsigned port)
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
}
-/* Network shutdown */
-static int sky2_down(struct net_device *dev)
+static void sky2_hw_down(struct sky2_port *sky2)
{
- struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
unsigned port = sky2->port;
u16 ctrl;
- u32 imask;
-
- /* Never really got started! */
- if (!sky2->tx_le)
- return 0;
-
- if (netif_msg_ifdown(sky2))
- printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
/* Force flow control off */
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
@@ -1918,15 +1938,6 @@ static int sky2_down(struct net_device *dev)
sky2_rx_stop(sky2);
- /* Disable port IRQ */
- imask = sky2_read32(hw, B0_IMSK);
- imask &= ~portirq_msk[port];
- sky2_write32(hw, B0_IMSK, imask);
- sky2_read32(hw, B0_IMSK);
-
- synchronize_irq(hw->pdev->irq);
- napi_synchronize(&hw->napi);
-
spin_lock_bh(&sky2->phy_lock);
sky2_phy_power_down(hw, port);
spin_unlock_bh(&sky2->phy_lock);
@@ -1935,8 +1946,29 @@ static int sky2_down(struct net_device *dev)
/* Free any pending frames stuck in HW queue */
sky2_tx_complete(sky2, sky2->tx_prod);
+}
- sky2_rx_clean(sky2);
+/* Network shutdown */
+static int sky2_down(struct net_device *dev)
+{
+ struct sky2_port *sky2 = netdev_priv(dev);
+ struct sky2_hw *hw = sky2->hw;
+
+ /* Never really got started! */
+ if (!sky2->tx_le)
+ return 0;
+
+ netif_info(sky2, ifdown, dev, "disabling interface\n");
+
+ /* Disable port IRQ */
+ sky2_write32(hw, B0_IMSK,
+ sky2_read32(hw, B0_IMSK) & ~portirq_msk[sky2->port]);
+ sky2_read32(hw, B0_IMSK);
+
+ synchronize_irq(hw->pdev->irq);
+ napi_synchronize(&hw->napi);
+
+ sky2_hw_down(sky2);
sky2_free_buffers(sky2);
@@ -1992,12 +2024,11 @@ 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 (netif_msg_link(sky2))
- printk(KERN_INFO PFX
- "%s: Link is up at %d Mbps, %s duplex, flow control %s\n",
- sky2->netdev->name, sky2->speed,
- sky2->duplex == DUPLEX_FULL ? "full" : "half",
- fc_name[sky2->flow_status]);
+ netif_info(sky2, link, sky2->netdev,
+ "Link is up at %d Mbps, %s duplex, flow control %s\n",
+ sky2->speed,
+ sky2->duplex == DUPLEX_FULL ? "full" : "half",
+ fc_name[sky2->flow_status]);
}
static void sky2_link_down(struct sky2_port *sky2)
@@ -2017,8 +2048,7 @@ static void sky2_link_down(struct sky2_port *sky2)
/* Turn off link LED */
sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
- if (netif_msg_link(sky2))
- printk(KERN_INFO PFX "%s: Link is down.\n", sky2->netdev->name);
+ netif_info(sky2, link, sky2->netdev, "Link is down\n");
sky2_phy_init(hw, port);
}
@@ -2040,13 +2070,12 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
advert = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV);
lpa = gm_phy_read(hw, port, PHY_MARV_AUNE_LP);
if (lpa & PHY_M_AN_RF) {
- printk(KERN_ERR PFX "%s: remote fault", sky2->netdev->name);
+ netdev_err(sky2->netdev, "remote fault\n");
return -1;
}
if (!(aux & PHY_M_PS_SPDUP_RES)) {
- printk(KERN_ERR PFX "%s: speed/duplex mismatch",
- sky2->netdev->name);
+ netdev_err(sky2->netdev, "speed/duplex mismatch\n");
return -1;
}
@@ -2108,9 +2137,8 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port)
istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT);
phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
- if (netif_msg_intr(sky2))
- printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n",
- sky2->netdev->name, istatus, phystat);
+ netif_info(sky2, intr, sky2->netdev, "phy interrupt status 0x%x 0x%x\n",
+ istatus, phystat);
if (istatus & PHY_M_IS_AN_COMPL) {
if (sky2_autoneg_done(sky2, phystat) == 0)
@@ -2149,7 +2177,9 @@ static void sky2_qlink_intr(struct sky2_hw *hw)
/* reset PHY Link Detect */
phy = sky2_pci_read16(hw, PSM_CONFIG_REG4);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
sky2_pci_write16(hw, PSM_CONFIG_REG4, phy | 1);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
sky2_link_up(sky2);
}
@@ -2162,13 +2192,12 @@ static void sky2_tx_timeout(struct net_device *dev)
struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
- if (netif_msg_timer(sky2))
- printk(KERN_ERR PFX "%s: tx timeout\n", dev->name);
+ netif_err(sky2, timer, dev, "tx timeout\n");
- printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n",
- dev->name, sky2->tx_cons, sky2->tx_prod,
- sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX),
- sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE)));
+ netdev_printk(KERN_DEBUG, dev, "transmit ring %u .. %u report=%u done=%u\n",
+ sky2->tx_cons, sky2->tx_prod,
+ sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX),
+ sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE)));
/* can't restart safely under softirq */
schedule_work(&hw->restart_work);
@@ -2183,14 +2212,20 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
u16 ctl, mode;
u32 imask;
+ /* MTU size outside the spec */
if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
return -EINVAL;
+ /* MTU > 1500 on yukon FE and FE+ not allowed */
if (new_mtu > ETH_DATA_LEN &&
(hw->chip_id == CHIP_ID_YUKON_FE ||
hw->chip_id == CHIP_ID_YUKON_FE_P))
return -EINVAL;
+ /* TSO, etc on Yukon Ultra and MTU > 1500 not supported */
+ if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U)
+ dev->features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM);
+
if (!netif_running(dev)) {
dev->mtu = new_mtu;
return 0;
@@ -2225,7 +2260,11 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
sky2_write8(hw, RB_ADDR(rxqaddr[port], RB_CTRL), RB_ENA_OP_MD);
- err = sky2_rx_start(sky2);
+ err = sky2_alloc_rx_skbs(sky2);
+ if (!err)
+ sky2_rx_start(sky2);
+ else
+ sky2_rx_clean(sky2);
sky2_write32(hw, B0_IMSK, imask);
sky2_read32(hw, B0_Y2_SP_LISR);
@@ -2302,30 +2341,32 @@ static struct sk_buff *receive_new(struct sky2_port *sky2,
struct rx_ring_info *re,
unsigned int length)
{
- struct sk_buff *skb, *nskb;
+ struct sk_buff *skb;
+ struct rx_ring_info nre;
unsigned hdr_space = sky2->rx_data_size;
- /* Don't be tricky about reusing pages (yet) */
- nskb = sky2_rx_alloc(sky2);
- if (unlikely(!nskb))
- return NULL;
+ nre.skb = sky2_rx_alloc(sky2);
+ if (unlikely(!nre.skb))
+ goto nobuf;
+
+ if (sky2_rx_map_skb(sky2->hw->pdev, &nre, hdr_space))
+ goto nomap;
skb = re->skb;
sky2_rx_unmap_skb(sky2->hw->pdev, re);
-
prefetch(skb->data);
- re->skb = nskb;
- if (sky2_rx_map_skb(sky2->hw->pdev, re, hdr_space)) {
- dev_kfree_skb(nskb);
- re->skb = skb;
- return NULL;
- }
+ *re = nre;
if (skb_shinfo(skb)->nr_frags)
skb_put_frags(skb, hdr_space, length);
else
skb_put(skb, length);
return skb;
+
+nomap:
+ dev_kfree_skb(nre.skb);
+nobuf:
+ return NULL;
}
/*
@@ -2346,9 +2387,9 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
count -= VLAN_HLEN;
#endif
- if (unlikely(netif_msg_rx_status(sky2)))
- printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n",
- dev->name, sky2->rx_next, status, length);
+ netif_printk(sky2, rx_status, KERN_DEBUG, dev,
+ "rx slot %u status 0x%x len %d\n",
+ sky2->rx_next, status, length);
sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending;
prefetch(sky2->rx_ring + sky2->rx_next);
@@ -2377,6 +2418,9 @@ okay:
skb = receive_copy(sky2, re, length);
else
skb = receive_new(sky2, re, length);
+
+ dev->stats.rx_dropped += (skb == NULL);
+
resubmit:
sky2_rx_submit(sky2, re);
@@ -2386,9 +2430,10 @@ len_error:
/* Truncation of overlength packets
causes PHY length to not match MAC length */
++dev->stats.rx_length_errors;
- if (netif_msg_rx_err(sky2) && net_ratelimit())
- pr_info(PFX "%s: rx length error: status %#x length %d\n",
- dev->name, status, length);
+ if (net_ratelimit())
+ netif_info(sky2, rx_err, dev,
+ "rx length error: status %#x length %d\n",
+ status, length);
goto resubmit;
error:
@@ -2398,9 +2443,9 @@ error:
goto resubmit;
}
- if (netif_msg_rx_err(sky2) && net_ratelimit())
- printk(KERN_INFO PFX "%s: rx error, status 0x%x length %d\n",
- dev->name, status, length);
+ if (net_ratelimit())
+ netif_info(sky2, rx_err, dev,
+ "rx error, status 0x%x length %d\n", status, length);
if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE))
dev->stats.rx_length_errors++;
@@ -2417,8 +2462,13 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
{
struct sky2_port *sky2 = netdev_priv(dev);
- if (netif_running(dev))
+ if (netif_running(dev)) {
sky2_tx_complete(sky2, last);
+
+ /* Wake unless it's detached, and called e.g. from sky2_down() */
+ if (tx_avail(sky2) > MAX_SKB_TX_LE + 4)
+ netif_wake_queue(dev);
+ }
}
static inline void sky2_skb_rx(const struct sky2_port *sky2,
@@ -2454,6 +2504,32 @@ static inline void sky2_rx_done(struct sky2_hw *hw, unsigned port,
}
}
+static void sky2_rx_checksum(struct sky2_port *sky2, u32 status)
+{
+ /* If this happens then driver assuming wrong format for chip type */
+ BUG_ON(sky2->hw->flags & SKY2_HW_NEW_LE);
+
+ /* Both checksum counters are programmed to start at
+ * the same offset, so unless there is a problem they
+ * should match. This failure is an early indication that
+ * hardware receive checksumming won't work.
+ */
+ if (likely((u16)(status >> 16) == (u16)status)) {
+ struct sk_buff *skb = sky2->rx_ring[sky2->rx_next].skb;
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = le16_to_cpu(status);
+ } else {
+ dev_notice(&sky2->hw->pdev->dev,
+ "%s: receive checksum problem (status = %#x)\n",
+ sky2->netdev->name, status);
+
+ /* Disable checksum offload */
+ sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM;
+ sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+ BMU_DIS_RX_CHKSUM);
+ }
+}
+
/* Process status response ring */
static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
{
@@ -2488,11 +2564,10 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
case OP_RXSTAT:
total_packets[port]++;
total_bytes[port] += length;
+
skb = sky2_receive(dev, length, status);
- if (unlikely(!skb)) {
- dev->stats.rx_dropped++;
+ if (!skb)
break;
- }
/* This chip reports checksum status differently */
if (hw->flags & SKY2_HW_NEW_LE) {
@@ -2523,37 +2598,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
/* fall through */
#endif
case OP_RXCHKS:
- if (!(sky2->flags & SKY2_FLAG_RX_CHECKSUM))
- break;
-
- /* If this happens then driver assuming wrong format */
- if (unlikely(hw->flags & SKY2_HW_NEW_LE)) {
- if (net_ratelimit())
- printk(KERN_NOTICE "%s: unexpected"
- " checksum status\n",
- dev->name);
- break;
- }
-
- /* Both checksum counters are programmed to start at
- * the same offset, so unless there is a problem they
- * should match. This failure is an early indication that
- * hardware receive checksumming won't work.
- */
- if (likely(status >> 16 == (status & 0xffff))) {
- skb = sky2->rx_ring[sky2->rx_next].skb;
- skb->ip_summed = CHECKSUM_COMPLETE;
- skb->csum = le16_to_cpu(status);
- } else {
- printk(KERN_NOTICE PFX "%s: hardware receive "
- "checksum problem (status = %#x)\n",
- dev->name, status);
- sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM;
-
- sky2_write32(sky2->hw,
- Q_ADDR(rxqaddr[port], Q_CSR),
- BMU_DIS_RX_CHKSUM);
- }
+ if (likely(sky2->flags & SKY2_FLAG_RX_CHECKSUM))
+ sky2_rx_checksum(sky2, status);
break;
case OP_TXINDEXLE:
@@ -2567,8 +2613,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
default:
if (net_ratelimit())
- printk(KERN_WARNING PFX
- "unknown status opcode 0x%x\n", opcode);
+ pr_warning("unknown status opcode 0x%x\n", opcode);
}
} while (hw->st_idx != idx);
@@ -2587,41 +2632,37 @@ static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status)
struct net_device *dev = hw->dev[port];
if (net_ratelimit())
- printk(KERN_INFO PFX "%s: hw error interrupt status 0x%x\n",
- dev->name, status);
+ netdev_info(dev, "hw error interrupt status 0x%x\n", status);
if (status & Y2_IS_PAR_RD1) {
if (net_ratelimit())
- printk(KERN_ERR PFX "%s: ram data read parity error\n",
- dev->name);
+ netdev_err(dev, "ram data read parity error\n");
/* Clear IRQ */
sky2_write16(hw, RAM_BUFFER(port, B3_RI_CTRL), RI_CLR_RD_PERR);
}
if (status & Y2_IS_PAR_WR1) {
if (net_ratelimit())
- printk(KERN_ERR PFX "%s: ram data write parity error\n",
- dev->name);
+ netdev_err(dev, "ram data write parity error\n");
sky2_write16(hw, RAM_BUFFER(port, B3_RI_CTRL), RI_CLR_WR_PERR);
}
if (status & Y2_IS_PAR_MAC1) {
if (net_ratelimit())
- printk(KERN_ERR PFX "%s: MAC parity error\n", dev->name);
+ netdev_err(dev, "MAC parity error\n");
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_PE);
}
if (status & Y2_IS_PAR_RX1) {
if (net_ratelimit())
- printk(KERN_ERR PFX "%s: RX parity error\n", dev->name);
+ netdev_err(dev, "RX parity error\n");
sky2_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), BMU_CLR_IRQ_PAR);
}
if (status & Y2_IS_TCP_TXA1) {
if (net_ratelimit())
- printk(KERN_ERR PFX "%s: TCP segmentation error\n",
- dev->name);
+ netdev_err(dev, "TCP segmentation error\n");
sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), BMU_CLR_IRQ_TCP);
}
}
@@ -2640,6 +2681,7 @@ static void sky2_hw_intr(struct sky2_hw *hw)
if (status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) {
u16 pci_err;
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
pci_err = sky2_pci_read16(hw, PCI_STATUS);
if (net_ratelimit())
dev_err(&pdev->dev, "PCI hardware error (0x%x)\n",
@@ -2647,12 +2689,14 @@ static void sky2_hw_intr(struct sky2_hw *hw)
sky2_pci_write16(hw, PCI_STATUS,
pci_err | PCI_STATUS_ERROR_BITS);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
}
if (status & Y2_IS_PCI_EXP) {
/* PCI-Express uncorrectable Error occurred */
u32 err;
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
err = sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS);
sky2_write32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS,
0xfffffffful);
@@ -2660,6 +2704,7 @@ static void sky2_hw_intr(struct sky2_hw *hw)
dev_err(&pdev->dev, "PCI Express error (0x%x)\n", err);
sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
}
if (status & Y2_HWE_L1_MASK)
@@ -2675,9 +2720,7 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port)
struct sky2_port *sky2 = netdev_priv(dev);
u8 status = sky2_read8(hw, SK_REG(port, GMAC_IRQ_SRC));
- if (netif_msg_intr(sky2))
- printk(KERN_INFO PFX "%s: mac interrupt status 0x%x\n",
- dev->name, status);
+ netif_info(sky2, intr, dev, "mac interrupt status 0x%x\n", status);
if (status & GM_IS_RX_CO_OV)
gma_read16(hw, port, GM_RX_IRQ_SRC);
@@ -2702,8 +2745,7 @@ static void sky2_le_error(struct sky2_hw *hw, unsigned port, u16 q)
struct net_device *dev = hw->dev[port];
u16 idx = sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_GET_IDX));
- dev_err(&hw->pdev->dev, PFX
- "%s: descriptor error q=%#x get=%u put=%u\n",
+ dev_err(&hw->pdev->dev, "%s: descriptor error q=%#x get=%u put=%u\n",
dev->name, (unsigned) q, (unsigned) idx,
(unsigned) sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX)));
@@ -2728,9 +2770,10 @@ static int sky2_rx_hung(struct net_device *dev)
/* Check if the PCI RX hang */
(fifo_rp == sky2->check.fifo_rp &&
fifo_lev != 0 && fifo_lev >= sky2->check.fifo_lev))) {
- printk(KERN_DEBUG PFX "%s: hung mac %d:%d fifo %d (%d:%d)\n",
- dev->name, mac_lev, mac_rp, fifo_lev, fifo_rp,
- sky2_read8(hw, Q_ADDR(rxq, Q_WP)));
+ netdev_printk(KERN_DEBUG, dev,
+ "hung mac %d:%d fifo %d (%d:%d)\n",
+ mac_lev, mac_rp, fifo_lev,
+ fifo_rp, sky2_read8(hw, Q_ADDR(rxq, Q_WP)));
return 1;
} else {
sky2->check.last = dev->last_rx;
@@ -2761,8 +2804,7 @@ static void sky2_watchdog(unsigned long arg)
/* For chips with Rx FIFO, check if stuck */
if ((hw->flags & SKY2_HW_RAM_BUFFER) &&
sky2_rx_hung(dev)) {
- pr_info(PFX "%s: receiver hang detected\n",
- dev->name);
+ netdev_info(dev, "receiver hang detected\n");
schedule_work(&hw->restart_work);
return;
}
@@ -3002,11 +3044,20 @@ static void sky2_reset(struct sky2_hw *hw)
u32 hwe_mask = Y2_HWE_ALL_MASK;
/* disable ASF */
- if (hw->chip_id == CHIP_ID_YUKON_EX) {
+ if (hw->chip_id == CHIP_ID_YUKON_EX
+ || hw->chip_id == CHIP_ID_YUKON_SUPR) {
+ sky2_write32(hw, CPU_WDOG, 0);
status = sky2_read16(hw, HCU_CCSR);
status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE |
HCU_CCSR_UC_STATE_MSK);
+ /*
+ * CPU clock divider shouldn't be used because
+ * - ASF firmware may malfunction
+ * - Yukon-Supreme: Parallel FLASH doesn't support divided clocks
+ */
+ status &= ~HCU_CCSR_CPU_CLK_DIVIDE_MSK;
sky2_write16(hw, HCU_CCSR, status);
+ sky2_write32(hw, CPU_WDOG, 0);
} else
sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE);
@@ -3038,6 +3089,7 @@ static void sky2_reset(struct sky2_hw *hw)
}
sky2_power_on(hw);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
for (i = 0; i < hw->ports; i++) {
sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
@@ -3074,6 +3126,7 @@ static void sky2_reset(struct sky2_hw *hw)
reg <<= PSM_CONFIG_REG4_TIMER_PHY_LINK_DETECT_BASE;
/* reset PHY Link Detect */
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
sky2_pci_write16(hw, PSM_CONFIG_REG4,
reg | PSM_CONFIG_REG4_RST_PHY_LINK_DETECT);
sky2_pci_write16(hw, PSM_CONFIG_REG4, reg);
@@ -3087,10 +3140,11 @@ static void sky2_reset(struct sky2_hw *hw)
/* check if PSMv2 was running before */
reg = sky2_pci_read16(hw, PSM_CONFIG_REG3);
if (reg & PCI_EXP_LNKCTL_ASPMC) {
- int cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
/* restore the PCIe Link Control register */
sky2_pci_write16(hw, cap + PCI_EXP_LNKCTL, reg);
}
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
/* re-enable PEX PM in PEX PHY debug reg. 8 (clear bit 12) */
sky2_write32(hw, Y2_PEX_PHY_DATA, PEX_DB_ACCESS | (0x08UL << 16));
@@ -3177,7 +3231,9 @@ static void sky2_reset(struct sky2_hw *hw)
static void sky2_detach(struct net_device *dev)
{
if (netif_running(dev)) {
+ netif_tx_lock(dev);
netif_device_detach(dev); /* stop txq */
+ netif_tx_unlock(dev);
sky2_down(dev);
}
}
@@ -3190,8 +3246,7 @@ static int sky2_reattach(struct net_device *dev)
if (netif_running(dev)) {
err = sky2_up(dev);
if (err) {
- printk(KERN_INFO PFX "%s: could not restart %d\n",
- dev->name, err);
+ netdev_info(dev, "could not restart %d\n", err);
dev_close(dev);
} else {
netif_device_attach(dev);
@@ -3205,20 +3260,46 @@ static int sky2_reattach(struct net_device *dev)
static void sky2_restart(struct work_struct *work)
{
struct sky2_hw *hw = container_of(work, struct sky2_hw, restart_work);
+ u32 imask;
int i;
rtnl_lock();
- for (i = 0; i < hw->ports; i++)
- sky2_detach(hw->dev[i]);
napi_disable(&hw->napi);
+ synchronize_irq(hw->pdev->irq);
+ imask = sky2_read32(hw, B0_IMSK);
sky2_write32(hw, B0_IMSK, 0);
+
+ for (i = 0; i < hw->ports; i++) {
+ struct net_device *dev = hw->dev[i];
+ struct sky2_port *sky2 = netdev_priv(dev);
+
+ if (!netif_running(dev))
+ continue;
+
+ netif_carrier_off(dev);
+ netif_tx_disable(dev);
+ sky2_hw_down(sky2);
+ }
+
sky2_reset(hw);
- sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
- napi_enable(&hw->napi);
- for (i = 0; i < hw->ports; i++)
- sky2_reattach(hw->dev[i]);
+ for (i = 0; i < hw->ports; i++) {
+ struct net_device *dev = hw->dev[i];
+ struct sky2_port *sky2 = netdev_priv(dev);
+
+ if (!netif_running(dev))
+ continue;
+
+ sky2_hw_up(sky2);
+ netif_wake_queue(dev);
+ }
+
+ sky2_write32(hw, B0_IMSK, imask);
+ sky2_read32(hw, B0_IMSK);
+
+ sky2_read32(hw, B0_Y2_SP_LISR);
+ napi_enable(&hw->napi);
rtnl_unlock();
}
@@ -3246,17 +3327,6 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return -EOPNOTSUPP;
sky2->wol = wol->wolopts;
-
- if (hw->chip_id == CHIP_ID_YUKON_EC_U ||
- hw->chip_id == CHIP_ID_YUKON_EX ||
- hw->chip_id == CHIP_ID_YUKON_FE_P)
- sky2_write32(hw, B0_CTST, sky2->wol
- ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
-
- device_set_wakeup_enable(&hw->pdev->dev, sky2->wol);
-
- if (!netif_running(dev))
- sky2_wol_init(sky2);
return 0;
}
@@ -3551,7 +3621,7 @@ static void sky2_set_multicast(struct net_device *dev)
struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
unsigned port = sky2->port;
- struct dev_mc_list *list = dev->mc_list;
+ struct dev_mc_list *list;
u16 reg;
u8 filter[8];
int rx_pause;
@@ -3567,16 +3637,15 @@ static void sky2_set_multicast(struct net_device *dev)
reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
else if (dev->flags & IFF_ALLMULTI)
memset(filter, 0xff, sizeof(filter));
- else if (dev->mc_count == 0 && !rx_pause)
+ else if (netdev_mc_empty(dev) && !rx_pause)
reg &= ~GM_RXCR_MCF_ENA;
else {
- int i;
reg |= GM_RXCR_MCF_ENA;
if (rx_pause)
sky2_add_filter(filter, pause_mc_addr);
- for (i = 0; list && i < dev->mc_count; i++, list = list->next)
+ netdev_for_each_mc_addr(list, dev)
sky2_add_filter(filter, list->dmi_addr);
}
@@ -3838,6 +3907,50 @@ static int sky2_get_regs_len(struct net_device *dev)
return 0x4000;
}
+static int sky2_reg_access_ok(struct sky2_hw *hw, unsigned int b)
+{
+ /* This complicated switch statement is to make sure and
+ * only access regions that are unreserved.
+ * Some blocks are only valid on dual port cards.
+ */
+ switch (b) {
+ /* second port */
+ case 5: /* Tx Arbiter 2 */
+ case 9: /* RX2 */
+ case 14 ... 15: /* TX2 */
+ case 17: case 19: /* Ram Buffer 2 */
+ case 22 ... 23: /* Tx Ram Buffer 2 */
+ case 25: /* Rx MAC Fifo 1 */
+ case 27: /* Tx MAC Fifo 2 */
+ case 31: /* GPHY 2 */
+ case 40 ... 47: /* Pattern Ram 2 */
+ case 52: case 54: /* TCP Segmentation 2 */
+ case 112 ... 116: /* GMAC 2 */
+ return hw->ports > 1;
+
+ case 0: /* Control */
+ case 2: /* Mac address */
+ case 4: /* Tx Arbiter 1 */
+ case 7: /* PCI express reg */
+ case 8: /* RX1 */
+ case 12 ... 13: /* TX1 */
+ case 16: case 18:/* Rx Ram Buffer 1 */
+ case 20 ... 21: /* Tx Ram Buffer 1 */
+ case 24: /* Rx MAC Fifo 1 */
+ case 26: /* Tx MAC Fifo 1 */
+ case 28 ... 29: /* Descriptor and status unit */
+ case 30: /* GPHY 1*/
+ case 32 ... 39: /* Pattern Ram 1 */
+ case 48: case 50: /* TCP Segmentation 1 */
+ case 56 ... 60: /* PCI space */
+ case 80 ... 84: /* GMAC 1 */
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
/*
* Returns copy of control register region
* Note: ethtool_get_regs always provides full size (16k) buffer
@@ -3852,55 +3965,13 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
regs->version = 1;
for (b = 0; b < 128; b++) {
- /* This complicated switch statement is to make sure and
- * only access regions that are unreserved.
- * Some blocks are only valid on dual port cards.
- * and block 3 has some special diagnostic registers that
- * are poison.
- */
- switch (b) {
- case 3:
- /* skip diagnostic ram region */
+ /* skip poisonous diagnostic ram region in block 3 */
+ if (b == 3)
memcpy_fromio(p + 0x10, io + 0x10, 128 - 0x10);
- break;
-
- /* dual port cards only */
- case 5: /* Tx Arbiter 2 */
- case 9: /* RX2 */
- case 14 ... 15: /* TX2 */
- case 17: case 19: /* Ram Buffer 2 */
- case 22 ... 23: /* Tx Ram Buffer 2 */
- case 25: /* Rx MAC Fifo 1 */
- case 27: /* Tx MAC Fifo 2 */
- case 31: /* GPHY 2 */
- case 40 ... 47: /* Pattern Ram 2 */
- case 52: case 54: /* TCP Segmentation 2 */
- case 112 ... 116: /* GMAC 2 */
- if (sky2->hw->ports == 1)
- goto reserved;
- /* fall through */
- case 0: /* Control */
- case 2: /* Mac address */
- case 4: /* Tx Arbiter 1 */
- case 7: /* PCI express reg */
- case 8: /* RX1 */
- case 12 ... 13: /* TX1 */
- case 16: case 18:/* Rx Ram Buffer 1 */
- case 20 ... 21: /* Tx Ram Buffer 1 */
- case 24: /* Rx MAC Fifo 1 */
- case 26: /* Tx MAC Fifo 1 */
- case 28 ... 29: /* Descriptor and status unit */
- case 30: /* GPHY 1*/
- case 32 ... 39: /* Pattern Ram 1 */
- case 48: case 50: /* TCP Segmentation 1 */
- case 56 ... 60: /* PCI space */
- case 80 ... 84: /* GMAC 1 */
+ else if (sky2_reg_access_ok(sky2->hw, b))
memcpy_fromio(p, io, 128);
- break;
- default:
-reserved:
+ else
memset(p, 0, 128);
- }
p += 128;
io += 128;
@@ -3952,7 +4023,7 @@ static int sky2_vpd_wait(const struct sky2_hw *hw, int cap, u16 busy)
while ( (sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F) == busy) {
/* Can take up to 10.6 ms for write */
if (time_after(jiffies, start + HZ/4)) {
- dev_err(&hw->pdev->dev, PFX "VPD cycle timed out");
+ dev_err(&hw->pdev->dev, "VPD cycle timed out\n");
return -ETIMEDOUT;
}
mdelay(1);
@@ -4286,8 +4357,7 @@ static int sky2_device_event(struct notifier_block *unused,
case NETDEV_GOING_DOWN:
if (sky2->debugfs) {
- printk(KERN_DEBUG PFX "%s: remove debugfs\n",
- dev->name);
+ netdev_printk(KERN_DEBUG, dev, "remove debugfs\n");
debugfs_remove(sky2->debugfs);
sky2->debugfs = NULL;
}
@@ -4440,9 +4510,7 @@ static void __devinit sky2_show_addr(struct net_device *dev)
{
const struct sky2_port *sky2 = netdev_priv(dev);
- if (netif_msg_probe(sky2))
- printk(KERN_INFO PFX "%s: addr %pM\n",
- dev->name, dev->dev_addr);
+ netif_info(sky2, probe, dev, "addr %pM\n", dev->dev_addr);
}
/* Handle software interrupt used during MSI test */
@@ -4748,7 +4816,6 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
}
-#ifdef CONFIG_PM
static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct sky2_hw *hw = pci_get_drvdata(pdev);
@@ -4773,6 +4840,8 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
wol |= sky2->wol;
}
+ device_set_wakeup_enable(&pdev->dev, wol != 0);
+
sky2_write32(hw, B0_IMSK, 0);
napi_disable(&hw->napi);
sky2_power_aux(hw);
@@ -4785,6 +4854,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
return 0;
}
+#ifdef CONFIG_PM
static int sky2_resume(struct pci_dev *pdev)
{
struct sky2_hw *hw = pci_get_drvdata(pdev);
@@ -4793,6 +4863,7 @@ static int sky2_resume(struct pci_dev *pdev)
if (!hw)
return 0;
+ rtnl_lock();
err = pci_set_power_state(pdev, PCI_D0);
if (err)
goto out;
@@ -4804,16 +4875,16 @@ static int sky2_resume(struct pci_dev *pdev)
pci_enable_wake(pdev, PCI_D0, 0);
/* Re-enable all clocks */
- if (hw->chip_id == CHIP_ID_YUKON_EX ||
- hw->chip_id == CHIP_ID_YUKON_EC_U ||
- hw->chip_id == CHIP_ID_YUKON_FE_P)
- sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+ err = pci_write_config_dword(pdev, PCI_DEV_REG3, 0);
+ if (err) {
+ dev_err(&pdev->dev, "PCI write config failed\n");
+ goto out;
+ }
sky2_reset(hw);
sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
napi_enable(&hw->napi);
- rtnl_lock();
for (i = 0; i < hw->ports; i++) {
err = sky2_reattach(hw->dev[i]);
if (err)
@@ -4833,34 +4904,7 @@ out:
static void sky2_shutdown(struct pci_dev *pdev)
{
- struct sky2_hw *hw = pci_get_drvdata(pdev);
- int i, wol = 0;
-
- if (!hw)
- return;
-
- rtnl_lock();
- del_timer_sync(&hw->watchdog_timer);
-
- for (i = 0; i < hw->ports; i++) {
- struct net_device *dev = hw->dev[i];
- struct sky2_port *sky2 = netdev_priv(dev);
-
- if (sky2->wol) {
- wol = 1;
- sky2_wol_init(sky2);
- }
- }
-
- if (wol)
- sky2_power_aux(hw);
- rtnl_unlock();
-
- pci_enable_wake(pdev, PCI_D3hot, wol);
- pci_enable_wake(pdev, PCI_D3cold, wol);
-
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
+ sky2_suspend(pdev, PMSG_SUSPEND);
}
static struct pci_driver sky2_driver = {
@@ -4877,7 +4921,7 @@ static struct pci_driver sky2_driver = {
static int __init sky2_init_module(void)
{
- pr_info(PFX "driver version " DRV_VERSION "\n");
+ pr_info("driver version " DRV_VERSION "\n");
sky2_debug_init();
return pci_register_driver(&sky2_driver);
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 365d79c7d834..a5e182dd9819 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1895,14 +1895,14 @@ enum {
/* TX_GMF_CTRL_T 32 bit Tx GMAC FIFO Control/Test */
enum {
- TX_STFW_DIS = 1<<31,/* Disable Store & Forward (Yukon-EC Ultra) */
- TX_STFW_ENA = 1<<30,/* Enable Store & Forward (Yukon-EC Ultra) */
+ TX_STFW_DIS = 1<<31,/* Disable Store & Forward */
+ TX_STFW_ENA = 1<<30,/* Enable Store & Forward */
TX_VLAN_TAG_ON = 1<<25,/* enable VLAN tagging */
TX_VLAN_TAG_OFF = 1<<24,/* disable VLAN tagging */
- TX_JUMBO_ENA = 1<<23,/* PCI Jumbo Mode enable (Yukon-EC Ultra) */
- TX_JUMBO_DIS = 1<<22,/* PCI Jumbo Mode enable (Yukon-EC Ultra) */
+ TX_PCI_JUM_ENA = 1<<23,/* PCI Jumbo Mode enable */
+ TX_PCI_JUM_DIS = 1<<22,/* PCI Jumbo Mode enable */
GMF_WSP_TST_ON = 1<<18,/* Write Shadow Pointer Test On */
GMF_WSP_TST_OFF = 1<<17,/* Write Shadow Pointer Test Off */
@@ -2156,7 +2156,7 @@ struct tx_ring_info {
struct sk_buff *skb;
unsigned long flags;
#define TX_MAP_SINGLE 0x0001
-#define TX_MAP_PAGE 000002
+#define TX_MAP_PAGE 0x0002
DECLARE_PCI_UNMAP_ADDR(mapaddr);
DECLARE_PCI_UNMAP_LEN(maplen);
};
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 44ebbaa7457b..9871a2b61f86 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -1323,7 +1323,7 @@ static void smc911x_set_multicast_list(struct net_device *dev)
* 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) {
+ else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) {
DBG(SMC_DEBUG_MISC, "%s: RCR_ALMUL\n", dev->name);
mcr |= MAC_CR_MCPAS_;
}
@@ -1340,8 +1340,7 @@ static void smc911x_set_multicast_list(struct net_device *dev)
* 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;
+ else if (!netdev_mc_empty(dev)) {
struct dev_mc_list *cur_addr;
/* Set the Hash perfec mode */
@@ -1350,8 +1349,7 @@ static void smc911x_set_multicast_list(struct net_device *dev)
/* 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) {
+ netdev_for_each_mc_addr(cur_addr, dev) {
u32 position;
/* do we have a pointer here? */
@@ -2017,10 +2015,8 @@ static int __devinit smc911x_probe(struct net_device *dev)
"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]);
+ printk("%s: Ethernet addr: %pM\n",
+ dev->name, dev->dev_addr);
}
if (lp->phy_type == 0) {
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
index 05adb6a666cf..3269292efecc 100644
--- a/drivers/net/smc911x.h
+++ b/drivers/net/smc911x.h
@@ -42,12 +42,12 @@
#define SMC_USE_16BIT 0
#define SMC_USE_32BIT 1
#define SMC_IRQ_SENSE IRQF_TRIGGER_LOW
-#elif defined(CONFIG_ARCH_OMAP34XX)
+#elif defined(CONFIG_ARCH_OMAP3)
#define SMC_USE_16BIT 0
#define SMC_USE_32BIT 1
#define SMC_IRQ_SENSE IRQF_TRIGGER_LOW
#define SMC_MEM_RESERVED 1
-#elif defined(CONFIG_ARCH_OMAP24XX)
+#elif defined(CONFIG_ARCH_OMAP2)
#define SMC_USE_16BIT 0
#define SMC_USE_32BIT 1
#define SMC_IRQ_SENSE IRQF_TRIGGER_LOW
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 8371b82323ac..f9a960e7fc1f 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -434,18 +434,18 @@ static void smc_shutdown( int ioaddr )
*/
-static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) {
+static void smc_setmulticast(int ioaddr, struct net_device *dev)
+{
int i;
unsigned char multicast_table[ 8 ];
- struct dev_mc_list * cur_addr;
+ struct dev_mc_list *cur_addr;
/* table for flipping the order of 3 bits */
unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
/* start with a table of all zeros: reject all */
memset( multicast_table, 0, sizeof( multicast_table ) );
- cur_addr = addrs;
- for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) {
+ netdev_for_each_mc_addr(cur_addr, dev) {
int position;
/* do we have a pointer here? */
@@ -1542,7 +1542,7 @@ static void smc_set_multicast_list(struct net_device *dev)
/* We just get all multicast packets even if we only want them
. from one source. This will be changed at some future
. point. */
- else if (dev->mc_count ) {
+ else if (!netdev_mc_empty(dev)) {
/* support hardware multicasting */
/* be sure I get rid of flags I might have set */
@@ -1550,7 +1550,7 @@ static void smc_set_multicast_list(struct net_device *dev)
ioaddr + RCR );
/* NOTE: this has to set the bank, so make sure it is the
last thing called. The bank is set to zero at the top */
- smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list );
+ smc_setmulticast(ioaddr, dev);
}
else {
outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL),
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index ea4fae79d6ec..fc1b5a1a3583 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1395,7 +1395,7 @@ static void smc_set_multicast_list(struct net_device *dev)
* 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) {
+ else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) {
DBG(2, "%s: RCR_ALMUL\n", dev->name);
lp->rcr_cur_mode |= RCR_ALMUL;
}
@@ -1412,8 +1412,7 @@ static void smc_set_multicast_list(struct net_device *dev)
* the number of the 8 bit register, while the low 3 bits are the bit
* within that register.
*/
- else if (dev->mc_count) {
- int i;
+ else if (!netdev_mc_empty(dev)) {
struct dev_mc_list *cur_addr;
/* table for flipping the order of 3 bits */
@@ -1422,13 +1421,9 @@ static void smc_set_multicast_list(struct net_device *dev)
/* 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) {
+ netdev_for_each_mc_addr(cur_addr, dev) {
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))
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index 54799544bda3..8d2772cc42f2 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -330,6 +330,48 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r,
#include <unit/smc91111.h>
+#elif defined(CONFIG_ARCH_MSM)
+
+#define SMC_CAN_USE_8BIT 0
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 0
+#define SMC_NOWAIT 1
+
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_outw(v, a, r) writew(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)
+
+#define SMC_IRQ_FLAGS IRQF_TRIGGER_HIGH
+
+#elif defined(CONFIG_COLDFIRE)
+
+#define SMC_CAN_USE_8BIT 0
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 0
+#define SMC_NOWAIT 1
+
+static inline void mcf_insw(void *a, unsigned char *p, int l)
+{
+ u16 *wp = (u16 *) p;
+ while (l-- > 0)
+ *wp++ = readw(a);
+}
+
+static inline void mcf_outsw(void *a, unsigned char *p, int l)
+{
+ u16 *wp = (u16 *) p;
+ while (l-- > 0)
+ writew(*wp++, a);
+}
+
+#define SMC_inw(a, r) _swapw(readw((a) + (r)))
+#define SMC_outw(v, a, r) writew(_swapw(v), (a) + (r))
+#define SMC_insw(a, r, p, l) mcf_insw(a + r, p, l)
+#define SMC_outsw(a, r, p, l) mcf_outsw(a + r, p, l)
+
+#define SMC_IRQ_FLAGS (IRQF_DISABLED)
+
#else
/*
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index 494cd91ea39c..4fd1d8b38788 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -770,29 +770,25 @@ static int smsc911x_mii_probe(struct net_device *dev)
{
struct smsc911x_data *pdata = netdev_priv(dev);
struct phy_device *phydev = NULL;
- int phy_addr;
+ int ret;
/* find the first phy */
- for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
- if (pdata->mii_bus->phy_map[phy_addr]) {
- phydev = pdata->mii_bus->phy_map[phy_addr];
- SMSC_TRACE(PROBE, "PHY %d: addr %d, phy_id 0x%08X",
- phy_addr, phydev->addr, phydev->phy_id);
- break;
- }
- }
-
+ phydev = phy_find_first(pdata->mii_bus);
if (!phydev) {
pr_err("%s: no PHY found\n", dev->name);
return -ENODEV;
}
- phydev = phy_connect(dev, dev_name(&phydev->dev),
- &smsc911x_phy_adjust_link, 0, pdata->config.phy_interface);
+ SMSC_TRACE(PROBE, "PHY %d: addr %d, phy_id 0x%08X",
+ phy_addr, phydev->addr, phydev->phy_id);
- if (IS_ERR(phydev)) {
+ ret = phy_connect_direct(dev, phydev,
+ &smsc911x_phy_adjust_link, 0,
+ pdata->config.phy_interface);
+
+ if (ret) {
pr_err("%s: Could not attach to PHY\n", dev->name);
- return PTR_ERR(phydev);
+ return ret;
}
pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
@@ -1383,33 +1379,24 @@ static void smsc911x_set_multicast_list(struct net_device *dev)
pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_HPFILT_);
pdata->hashhi = 0;
pdata->hashlo = 0;
- } else if (dev->mc_count > 0) {
+ } else if (!netdev_mc_empty(dev)) {
/* Enabling specific multicast addresses */
unsigned int hash_high = 0;
unsigned int hash_low = 0;
- unsigned int count = 0;
- struct dev_mc_list *mc_list = dev->mc_list;
+ struct dev_mc_list *mc_list;
pdata->set_bits_mask = MAC_CR_HPFILT_;
pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_);
- while (mc_list) {
- count++;
- if ((mc_list->dmi_addrlen) == ETH_ALEN) {
- unsigned int bitnum =
- smsc911x_hash(mc_list->dmi_addr);
- unsigned int mask = 0x01 << (bitnum & 0x1F);
- if (bitnum & 0x20)
- hash_high |= mask;
- else
- hash_low |= mask;
- } else {
- SMSC_WARNING(DRV, "dmi_addrlen != 6");
- }
- mc_list = mc_list->next;
+ netdev_for_each_mc_addr(mc_list, dev) {
+ unsigned int bitnum = smsc911x_hash(mc_list->dmi_addr);
+ unsigned int mask = 0x01 << (bitnum & 0x1F);
+
+ if (bitnum & 0x20)
+ hash_high |= mask;
+ else
+ hash_low |= mask;
}
- if (count != (unsigned int)dev->mc_count)
- SMSC_WARNING(DRV, "mc_count != dev->mc_count");
pdata->hashhi = hash_high;
pdata->hashlo = hash_low;
diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c
index 12f0f5d74e3c..34fa10d8ad40 100644
--- a/drivers/net/smsc9420.c
+++ b/drivers/net/smsc9420.c
@@ -80,7 +80,7 @@ struct smsc9420_pdata {
int last_carrier;
};
-static const struct pci_device_id smsc9420_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(smsc9420_id_table) = {
{ PCI_VENDOR_ID_9420, PCI_DEVICE_ID_9420, PCI_ANY_ID, PCI_ANY_ID, },
{ 0, }
};
@@ -1062,12 +1062,12 @@ static void smsc9420_set_multicast_list(struct net_device *dev)
mac_cr &= (~MAC_CR_PRMS_);
mac_cr |= MAC_CR_MCPAS_;
mac_cr &= (~MAC_CR_HPFILT_);
- } else if (dev->mc_count > 0) {
- struct dev_mc_list *mc_list = dev->mc_list;
+ } else if (!netdev_mc_empty(dev)) {
+ struct dev_mc_list *mc_list;
u32 hash_lo = 0, hash_hi = 0;
smsc_dbg(HW, "Multicast filter enabled");
- while (mc_list) {
+ netdev_for_each_mc_addr(mc_list, dev) {
u32 bit_num = smsc9420_hash(mc_list->dmi_addr);
u32 mask = 1 << (bit_num & 0x1F);
@@ -1076,7 +1076,6 @@ static void smsc9420_set_multicast_list(struct net_device *dev)
else
hash_lo |= mask;
- mc_list = mc_list->next;
}
smsc9420_reg_write(pd, HASHH, hash_hi);
smsc9420_reg_write(pd, HASHL, hash_lo);
@@ -1348,7 +1347,7 @@ static int smsc9420_open(struct net_device *dev)
netif_carrier_off(dev);
- /* disable, mask and acknowlege all interrupts */
+ /* disable, mask and acknowledge all interrupts */
spin_lock_irqsave(&pd->int_lock, flags);
int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_);
smsc9420_reg_write(pd, INT_CFG, int_cfg);
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index 9599ce77ef85..287c251075e5 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -531,7 +531,7 @@ static void sonic_multicast_list(struct net_device *dev)
{
struct sonic_local *lp = netdev_priv(dev);
unsigned int rcr;
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
unsigned char *addr;
int i;
@@ -541,19 +541,22 @@ static void sonic_multicast_list(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
rcr |= SONIC_RCR_PRO;
} else {
- if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15)) {
+ if ((dev->flags & IFF_ALLMULTI) ||
+ (netdev_mc_count(dev) > 15)) {
rcr |= SONIC_RCR_AMC;
} else {
if (sonic_debug > 2)
- printk("sonic_multicast_list: mc_count %d\n", dev->mc_count);
+ printk("sonic_multicast_list: mc_count %d\n",
+ netdev_mc_count(dev));
sonic_set_cam_enable(dev, 1); /* always enable our own address */
- for (i = 1; i <= dev->mc_count; i++) {
+ i = 1;
+ netdev_for_each_mc_addr(dmi, dev) {
addr = dmi->dmi_addr;
- dmi = dmi->next;
sonic_cda_put(dev, i, SONIC_CD_CAP0, addr[1] << 8 | addr[0]);
sonic_cda_put(dev, i, SONIC_CD_CAP1, addr[3] << 8 | addr[2]);
sonic_cda_put(dev, i, SONIC_CD_CAP2, addr[5] << 8 | addr[4]);
sonic_set_cam_enable(dev, sonic_get_cam_enable(dev) | (1 << i));
+ i++;
}
SONIC_WRITE(SONIC_CDC, 16);
/* issue Load CAM command */
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 218524857bfc..5ba9d989f8fc 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -72,7 +72,7 @@ MODULE_PARM_DESC(tx_descriptors, "number of descriptors used " \
char spider_net_driver_name[] = "spidernet";
-static struct pci_device_id spider_net_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(spider_net_pci_tbl) = {
{ PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SPIDER_NET,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ 0, }
@@ -474,7 +474,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
* spider_net_enable_rxchtails - sets RX dmac chain tail addresses
* @card: card structure
*
- * spider_net_enable_rxchtails sets the RX DMAC chain tail adresses in the
+ * spider_net_enable_rxchtails sets the RX DMAC chain tail addresses in the
* chip by writing to the appropriate register. DMA is enabled in
* spider_net_enable_rxdmac.
*/
@@ -646,7 +646,7 @@ spider_net_set_multi(struct net_device *netdev)
hash = spider_net_get_multicast_hash(netdev, netdev->broadcast); */
set_bit(0xfd, bitmask);
- for (mc = netdev->mc_list; mc; mc = mc->next) {
+ netdev_for_each_mc_addr(mc, netdev) {
hash = spider_net_get_multicast_hash(netdev, mc->dmi_addr);
set_bit(hash, bitmask);
}
@@ -1820,7 +1820,7 @@ spider_net_enable_card(struct spider_net_card *card)
spider_net_write_reg(card, SPIDER_NET_ECMODE, SPIDER_NET_ECMODE_VALUE);
- /* set chain tail adress for RX chains and
+ /* set chain tail address for RX chains and
* enable DMA */
spider_net_enable_rxchtails(card);
spider_net_enable_rxdmac(card);
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 95db60adde41..6dfa69899019 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -301,7 +301,7 @@ enum chipset {
CH_6915 = 0,
};
-static struct pci_device_id starfire_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(starfire_pci_tbl) = {
{ 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 },
{ 0, }
};
@@ -1063,7 +1063,7 @@ static int netdev_open(struct net_device *dev)
if (retval) {
printk(KERN_ERR "starfire: Failed to load firmware \"%s\"\n",
FIRMWARE_RX);
- return retval;
+ goto out_init;
}
if (fw_rx->size % 4) {
printk(KERN_ERR "starfire: bogus length %zu in \"%s\"\n",
@@ -1108,6 +1108,9 @@ out_tx:
release_firmware(fw_tx);
out_rx:
release_firmware(fw_rx);
+out_init:
+ if (retval)
+ netdev_close(dev);
return retval;
}
@@ -1793,22 +1796,22 @@ static void set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
rx_mode |= AcceptAll;
- } else if ((dev->mc_count > multicast_filter_limit) ||
+ } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
(dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
rx_mode |= AcceptBroadcast|AcceptAllMulticast|PerfectFilter;
- } else if (dev->mc_count <= 14) {
+ } else if (netdev_mc_count(dev) <= 14) {
/* Use the 16 element perfect filter, skip first two entries. */
void __iomem *filter_addr = ioaddr + PerfFilterTable + 2 * 16;
__be16 *eaddrs;
- for (i = 2, mclist = dev->mc_list; mclist && i < dev->mc_count + 2;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
eaddrs = (__be16 *)mclist->dmi_addr;
writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 4;
writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 8;
}
eaddrs = (__be16 *)dev->dev_addr;
+ i = netdev_mc_count(dev) + 2;
while (i++ < 16) {
writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4;
writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
@@ -1822,8 +1825,7 @@ static void set_rx_mode(struct net_device *dev)
__le16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
/* The chip uses the upper 9 CRC bits
as index into the hash table */
int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23;
diff --git a/drivers/net/stmmac/Kconfig b/drivers/net/stmmac/Kconfig
index 35eaa5251d7f..fb287649a305 100644
--- a/drivers/net/stmmac/Kconfig
+++ b/drivers/net/stmmac/Kconfig
@@ -4,8 +4,9 @@ config STMMAC_ETH
select PHYLIB
depends on NETDEVICES && CPU_SUBTYPE_ST40
help
- This is the driver for the ST MAC 10/100/1000 on-chip Ethernet
- controllers. ST Ethernet IPs are built around a Synopsys IP Core.
+ This is the driver for the Ethernet IPs are built around a
+ Synopsys IP Core and fully tested on the STMicroelectronics
+ platforms.
if STMMAC_ETH
@@ -32,7 +33,8 @@ config STMMAC_TIMER
default n
help
Use an external timer for mitigating the number of network
- interrupts.
+ interrupts. Currently, for SH architectures, it is possible
+ to use the TMU channel 2 and the SH-RTC device.
choice
prompt "Select Timer device"
diff --git a/drivers/net/stmmac/Makefile b/drivers/net/stmmac/Makefile
index b2d7a5564dfa..c776af15fe1a 100644
--- a/drivers/net/stmmac/Makefile
+++ b/drivers/net/stmmac/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_STMMAC_ETH) += stmmac.o
stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o
-stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
- mac100.o gmac.o $(stmmac-y)
+stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
+ dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
+ dwmac100.o $(stmmac-y)
diff --git a/drivers/net/stmmac/common.h b/drivers/net/stmmac/common.h
index e49e5188e887..2a58172e986a 100644
--- a/drivers/net/stmmac/common.h
+++ b/drivers/net/stmmac/common.h
@@ -23,132 +23,7 @@
*******************************************************************************/
#include "descs.h"
-#include <linux/io.h>
-
-/* *********************************************
- DMA CRS Control and Status Register Mapping
- * *********************************************/
-#define DMA_BUS_MODE 0x00001000 /* Bus Mode */
-#define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */
-#define DMA_RCV_POLL_DEMAND 0x00001008 /* Received Poll Demand */
-#define DMA_RCV_BASE_ADDR 0x0000100c /* Receive List Base */
-#define DMA_TX_BASE_ADDR 0x00001010 /* Transmit List Base */
-#define DMA_STATUS 0x00001014 /* Status Register */
-#define DMA_CONTROL 0x00001018 /* Ctrl (Operational Mode) */
-#define DMA_INTR_ENA 0x0000101c /* Interrupt Enable */
-#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */
-#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */
-#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */
-
-/* ********************************
- DMA Control register defines
- * ********************************/
-#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */
-#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */
-
-/* **************************************
- DMA Interrupt Enable register defines
- * **************************************/
-/**** NORMAL INTERRUPT ****/
-#define DMA_INTR_ENA_NIE 0x00010000 /* Normal Summary */
-#define DMA_INTR_ENA_TIE 0x00000001 /* Transmit Interrupt */
-#define DMA_INTR_ENA_TUE 0x00000004 /* Transmit Buffer Unavailable */
-#define DMA_INTR_ENA_RIE 0x00000040 /* Receive Interrupt */
-#define DMA_INTR_ENA_ERE 0x00004000 /* Early Receive */
-
-#define DMA_INTR_NORMAL (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \
- DMA_INTR_ENA_TIE)
-
-/**** ABNORMAL INTERRUPT ****/
-#define DMA_INTR_ENA_AIE 0x00008000 /* Abnormal Summary */
-#define DMA_INTR_ENA_FBE 0x00002000 /* Fatal Bus Error */
-#define DMA_INTR_ENA_ETE 0x00000400 /* Early Transmit */
-#define DMA_INTR_ENA_RWE 0x00000200 /* Receive Watchdog */
-#define DMA_INTR_ENA_RSE 0x00000100 /* Receive Stopped */
-#define DMA_INTR_ENA_RUE 0x00000080 /* Receive Buffer Unavailable */
-#define DMA_INTR_ENA_UNE 0x00000020 /* Tx Underflow */
-#define DMA_INTR_ENA_OVE 0x00000010 /* Receive Overflow */
-#define DMA_INTR_ENA_TJE 0x00000008 /* Transmit Jabber */
-#define DMA_INTR_ENA_TSE 0x00000002 /* Transmit Stopped */
-
-#define DMA_INTR_ABNORMAL (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \
- DMA_INTR_ENA_UNE)
-
-/* DMA default interrupt mask */
-#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
-
-/* ****************************
- * DMA Status register defines
- * ****************************/
-#define DMA_STATUS_GPI 0x10000000 /* PMT interrupt */
-#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
-#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int. */
-#define DMA_STATUS_GMI 0x08000000
-#define DMA_STATUS_GLI 0x04000000
-#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */
-#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */
-#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */
-#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */
-#define DMA_STATUS_TS_SHIFT 20
-#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */
-#define DMA_STATUS_RS_SHIFT 17
-#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */
-#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */
-#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */
-#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */
-#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */
-#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */
-#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */
-#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */
-#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */
-#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */
-#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */
-#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */
-#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */
-#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */
-#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
-
-/* Other defines */
-#define HASH_TABLE_SIZE 64
-#define PAUSE_TIME 0x200
-
-/* Flow Control defines */
-#define FLOW_OFF 0
-#define FLOW_RX 1
-#define FLOW_TX 2
-#define FLOW_AUTO (FLOW_TX | FLOW_RX)
-
-/* DMA STORE-AND-FORWARD Operation Mode */
-#define SF_DMA_MODE 1
-
-#define HW_CSUM 1
-#define NO_HW_CSUM 0
-
-/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
-#define BUF_SIZE_16KiB 16384
-#define BUF_SIZE_8KiB 8192
-#define BUF_SIZE_4KiB 4096
-#define BUF_SIZE_2KiB 2048
-
-/* Power Down and WOL */
-#define PMT_NOT_SUPPORTED 0
-#define PMT_SUPPORTED 1
-
-/* Common MAC defines */
-#define MAC_CTRL_REG 0x00000000 /* MAC Control */
-#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */
-#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */
-
-/* MAC Management Counters register */
-#define MMC_CONTROL 0x00000100 /* MMC Control */
-#define MMC_HIGH_INTR 0x00000104 /* MMC High Interrupt */
-#define MMC_LOW_INTR 0x00000108 /* MMC Low Interrupt */
-#define MMC_HIGH_INTR_MASK 0x0000010c /* MMC High Interrupt Mask */
-#define MMC_LOW_INTR_MASK 0x00000110 /* MMC Low Interrupt Mask */
-
-#define MMC_CONTROL_MAX_FRM_MASK 0x0003ff8 /* Maximum Frame Size */
-#define MMC_CONTROL_MAX_FRM_SHIFT 3
-#define MMC_CONTROL_MAX_FRAME 0x7FF
+#include <linux/netdevice.h>
struct stmmac_extra_stats {
/* Transmit errors */
@@ -169,7 +44,7 @@ struct stmmac_extra_stats {
unsigned long rx_toolong;
unsigned long rx_collision;
unsigned long rx_crc;
- unsigned long rx_lenght;
+ unsigned long rx_length;
unsigned long rx_mii;
unsigned long rx_multicast;
unsigned long rx_gmac_overflow;
@@ -198,66 +73,62 @@ struct stmmac_extra_stats {
unsigned long normal_irq_n;
};
-/* GMAC core can compute the checksums in HW. */
-enum rx_frame_status {
+#define HASH_TABLE_SIZE 64
+#define PAUSE_TIME 0x200
+
+/* Flow Control defines */
+#define FLOW_OFF 0
+#define FLOW_RX 1
+#define FLOW_TX 2
+#define FLOW_AUTO (FLOW_TX | FLOW_RX)
+
+#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
+
+#define HW_CSUM 1
+#define NO_HW_CSUM 0
+enum rx_frame_status { /* IPC status */
good_frame = 0,
discard_frame = 1,
csum_none = 2,
};
-static inline void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
- unsigned int high, unsigned int low)
-{
- unsigned long data;
-
- data = (addr[5] << 8) | addr[4];
- writel(data, ioaddr + high);
- data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
- writel(data, ioaddr + low);
+enum tx_dma_irq_status {
+ tx_hard_error = 1,
+ tx_hard_error_bump_tc = 2,
+ handle_tx_rx = 3,
+};
- return;
-}
+/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
+#define BUF_SIZE_16KiB 16384
+#define BUF_SIZE_8KiB 8192
+#define BUF_SIZE_4KiB 4096
+#define BUF_SIZE_2KiB 2048
-static inline void stmmac_get_mac_addr(unsigned long ioaddr,
- unsigned char *addr, unsigned int high,
- unsigned int low)
-{
- unsigned int hi_addr, lo_addr;
+/* Power Down and WOL */
+#define PMT_NOT_SUPPORTED 0
+#define PMT_SUPPORTED 1
- /* Read the MAC address from the hardware */
- hi_addr = readl(ioaddr + high);
- lo_addr = readl(ioaddr + low);
+/* Common MAC defines */
+#define MAC_CTRL_REG 0x00000000 /* MAC Control */
+#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */
+#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */
- /* Extract the MAC address from the high and low words */
- addr[0] = lo_addr & 0xff;
- addr[1] = (lo_addr >> 8) & 0xff;
- addr[2] = (lo_addr >> 16) & 0xff;
- addr[3] = (lo_addr >> 24) & 0xff;
- addr[4] = hi_addr & 0xff;
- addr[5] = (hi_addr >> 8) & 0xff;
+/* MAC Management Counters register */
+#define MMC_CONTROL 0x00000100 /* MMC Control */
+#define MMC_HIGH_INTR 0x00000104 /* MMC High Interrupt */
+#define MMC_LOW_INTR 0x00000108 /* MMC Low Interrupt */
+#define MMC_HIGH_INTR_MASK 0x0000010c /* MMC High Interrupt Mask */
+#define MMC_LOW_INTR_MASK 0x00000110 /* MMC Low Interrupt Mask */
- return;
-}
+#define MMC_CONTROL_MAX_FRM_MASK 0x0003ff8 /* Maximum Frame Size */
+#define MMC_CONTROL_MAX_FRM_SHIFT 3
+#define MMC_CONTROL_MAX_FRAME 0x7FF
-struct stmmac_ops {
- /* MAC core initialization */
- void (*core_init) (unsigned long ioaddr) ____cacheline_aligned;
- /* DMA core initialization */
- int (*dma_init) (unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx);
- /* Dump MAC registers */
- void (*dump_mac_regs) (unsigned long ioaddr);
- /* Dump DMA registers */
- void (*dump_dma_regs) (unsigned long ioaddr);
- /* Set tx/rx threshold in the csr6 register
- * An invalid value enables the store-and-forward mode */
- void (*dma_mode) (unsigned long ioaddr, int txmode, int rxmode);
- /* To track extra statistic (if supported) */
- void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
- unsigned long ioaddr);
- /* RX descriptor ring initialization */
+struct stmmac_desc_ops {
+ /* DMA RX descriptor ring initialization */
void (*init_rx_desc) (struct dma_desc *p, unsigned int ring_size,
- int disable_rx_ic);
- /* TX descriptor ring initialization */
+ int disable_rx_ic);
+ /* DMA TX descriptor ring initialization */
void (*init_tx_desc) (struct dma_desc *p, unsigned int ring_size);
/* Invoked by the xmit function to prepare the tx descriptor */
@@ -281,7 +152,6 @@ struct stmmac_ops {
/* Get the buffer size from the descriptor */
int (*get_tx_len) (struct dma_desc *p);
/* Handle extra events on specific interrupts hw dependent */
- void (*host_irq_status) (unsigned long ioaddr);
int (*get_rx_owner) (struct dma_desc *p);
void (*set_rx_owner) (struct dma_desc *p);
/* Get the receive frame size */
@@ -289,6 +159,37 @@ struct stmmac_ops {
/* Return the reception status looking at the RDES1 */
int (*rx_status) (void *data, struct stmmac_extra_stats *x,
struct dma_desc *p);
+};
+
+struct stmmac_dma_ops {
+ /* DMA core initialization */
+ int (*init) (unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx);
+ /* Dump DMA registers */
+ void (*dump_regs) (unsigned long ioaddr);
+ /* Set tx/rx threshold in the csr6 register
+ * An invalid value enables the store-and-forward mode */
+ void (*dma_mode) (unsigned long ioaddr, int txmode, int rxmode);
+ /* To track extra statistic (if supported) */
+ void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
+ unsigned long ioaddr);
+ void (*enable_dma_transmission) (unsigned long ioaddr);
+ void (*enable_dma_irq) (unsigned long ioaddr);
+ void (*disable_dma_irq) (unsigned long ioaddr);
+ void (*start_tx) (unsigned long ioaddr);
+ void (*stop_tx) (unsigned long ioaddr);
+ void (*start_rx) (unsigned long ioaddr);
+ void (*stop_rx) (unsigned long ioaddr);
+ int (*dma_interrupt) (unsigned long ioaddr,
+ struct stmmac_extra_stats *x);
+};
+
+struct stmmac_ops {
+ /* MAC core initialization */
+ void (*core_init) (unsigned long ioaddr) ____cacheline_aligned;
+ /* Dump MAC registers */
+ void (*dump_regs) (unsigned long ioaddr);
+ /* Handle extra events on specific interrupts hw dependent */
+ void (*host_irq_status) (unsigned long ioaddr);
/* Multicast filter setting */
void (*set_filter) (struct net_device *dev);
/* Flow control setting */
@@ -298,9 +199,9 @@ struct stmmac_ops {
void (*pmt) (unsigned long ioaddr, unsigned long mode);
/* Set/Get Unicast MAC addresses */
void (*set_umac_addr) (unsigned long ioaddr, unsigned char *addr,
- unsigned int reg_n);
+ unsigned int reg_n);
void (*get_umac_addr) (unsigned long ioaddr, unsigned char *addr,
- unsigned int reg_n);
+ unsigned int reg_n);
};
struct mac_link {
@@ -314,17 +215,19 @@ struct mii_regs {
unsigned int data; /* MII Data */
};
-struct hw_cap {
- unsigned int version; /* Core Version register (GMAC) */
- unsigned int pmt; /* Power-Down mode (GMAC) */
+struct mac_device_info {
+ struct stmmac_ops *mac;
+ struct stmmac_desc_ops *desc;
+ struct stmmac_dma_ops *dma;
+ unsigned int pmt; /* support Power-Down */
+ struct mii_regs mii; /* MII register Addresses */
struct mac_link link;
- struct mii_regs mii;
};
-struct mac_device_info {
- struct hw_cap hw;
- struct stmmac_ops *ops;
-};
+struct mac_device_info *dwmac1000_setup(unsigned long addr);
+struct mac_device_info *dwmac100_setup(unsigned long addr);
-struct mac_device_info *gmac_setup(unsigned long addr);
-struct mac_device_info *mac100_setup(unsigned long addr);
+extern void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
+ unsigned int high, unsigned int low);
+extern void stmmac_get_mac_addr(unsigned long ioaddr, unsigned char *addr,
+ unsigned int high, unsigned int low);
diff --git a/drivers/net/stmmac/descs.h b/drivers/net/stmmac/descs.h
index 6d2a0b2f5e57..63a03e264694 100644
--- a/drivers/net/stmmac/descs.h
+++ b/drivers/net/stmmac/descs.h
@@ -1,6 +1,6 @@
/*******************************************************************************
- Header File to describe the DMA descriptors
- Use enhanced descriptors in case of GMAC Cores.
+ Header File to describe the DMA descriptors.
+ Enhanced descriptors have been in case of DWMAC1000 Cores.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/stmmac/mac100.c b/drivers/net/stmmac/dwmac100.c
index 625171b6062b..803b0373d843 100644
--- a/drivers/net/stmmac/mac100.c
+++ b/drivers/net/stmmac/dwmac100.c
@@ -26,23 +26,23 @@
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
-#include <linux/netdevice.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/phy.h>
#include "common.h"
-#include "mac100.h"
+#include "dwmac100.h"
+#include "dwmac_dma.h"
-#undef MAC100_DEBUG
-/*#define MAC100_DEBUG*/
-#ifdef MAC100_DEBUG
+#undef DWMAC100_DEBUG
+/*#define DWMAC100_DEBUG*/
+#ifdef DWMAC100_DEBUG
#define DBG(fmt, args...) printk(fmt, ## args)
#else
#define DBG(fmt, args...) do { } while (0)
#endif
-static void mac100_core_init(unsigned long ioaddr)
+static void dwmac100_core_init(unsigned long ioaddr)
{
u32 value = readl(ioaddr + MAC_CONTROL);
@@ -54,43 +54,43 @@ static void mac100_core_init(unsigned long ioaddr)
return;
}
-static void mac100_dump_mac_regs(unsigned long ioaddr)
+static void dwmac100_dump_mac_regs(unsigned long ioaddr)
{
pr_info("\t----------------------------------------------\n"
- "\t MAC100 CSR (base addr = 0x%8x)\n"
- "\t----------------------------------------------\n",
- (unsigned int)ioaddr);
+ "\t DWMAC 100 CSR (base addr = 0x%8x)\n"
+ "\t----------------------------------------------\n",
+ (unsigned int)ioaddr);
pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL,
- readl(ioaddr + MAC_CONTROL));
+ readl(ioaddr + MAC_CONTROL));
pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH,
- readl(ioaddr + MAC_ADDR_HIGH));
+ readl(ioaddr + MAC_ADDR_HIGH));
pr_info("\taddr LO (offset 0x%x): 0x%08x\n", MAC_ADDR_LOW,
- readl(ioaddr + MAC_ADDR_LOW));
+ readl(ioaddr + MAC_ADDR_LOW));
pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n",
- MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH));
+ MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH));
pr_info("\tmulticast hash LO (offset 0x%x): 0x%08x\n",
- MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW));
+ MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW));
pr_info("\tflow control (offset 0x%x): 0x%08x\n",
MAC_FLOW_CTRL, readl(ioaddr + MAC_FLOW_CTRL));
pr_info("\tVLAN1 tag (offset 0x%x): 0x%08x\n", MAC_VLAN1,
- readl(ioaddr + MAC_VLAN1));
+ readl(ioaddr + MAC_VLAN1));
pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2,
- readl(ioaddr + MAC_VLAN2));
+ readl(ioaddr + MAC_VLAN2));
pr_info("\n\tMAC management counter registers\n");
pr_info("\t MMC crtl (offset 0x%x): 0x%08x\n",
- MMC_CONTROL, readl(ioaddr + MMC_CONTROL));
+ MMC_CONTROL, readl(ioaddr + MMC_CONTROL));
pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n",
- MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR));
+ MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR));
pr_info("\t MMC Low Interrupt (offset 0x%x): 0x%08x\n",
- MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR));
+ MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR));
pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n",
- MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK));
+ MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK));
pr_info("\t MMC Low Interrupt Mask (offset 0x%x): 0x%08x\n",
- MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
+ MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
return;
}
-static int mac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
+static int dwmac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
u32 dma_rx)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
@@ -117,7 +117,7 @@ static int mac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
/* Store and Forward capability is not used at all..
* The transmit threshold can be programmed by
* setting the TTC bits in the DMA control register.*/
-static void mac100_dma_operation_mode(unsigned long ioaddr, int txmode,
+static void dwmac100_dma_operation_mode(unsigned long ioaddr, int txmode,
int rxmode)
{
u32 csr6 = readl(ioaddr + DMA_CONTROL);
@@ -134,11 +134,11 @@ static void mac100_dma_operation_mode(unsigned long ioaddr, int txmode,
return;
}
-static void mac100_dump_dma_regs(unsigned long ioaddr)
+static void dwmac100_dump_dma_regs(unsigned long ioaddr)
{
int i;
- DBG(KERN_DEBUG "MAC100 DMA CSR \n");
+ DBG(KERN_DEBUG "DWMAC 100 DMA CSR \n");
for (i = 0; i < 9; i++)
pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i,
(DMA_BUS_MODE + i * 4),
@@ -151,8 +151,9 @@ static void mac100_dump_dma_regs(unsigned long ioaddr)
}
/* DMA controller has two counters to track the number of
- the receive missed frames. */
-static void mac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
+ * the receive missed frames. */
+static void dwmac100_dma_diagnostic_fr(void *data,
+ struct stmmac_extra_stats *x,
unsigned long ioaddr)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
@@ -181,7 +182,8 @@ static void mac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
return;
}
-static int mac100_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
+static int dwmac100_get_tx_frame_status(void *data,
+ struct stmmac_extra_stats *x,
struct dma_desc *p, unsigned long ioaddr)
{
int ret = 0;
@@ -217,7 +219,7 @@ static int mac100_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
return ret;
}
-static int mac100_get_tx_len(struct dma_desc *p)
+static int dwmac100_get_tx_len(struct dma_desc *p)
{
return p->des01.tx.buffer1_size;
}
@@ -226,14 +228,15 @@ static int mac100_get_tx_len(struct dma_desc *p)
* and, if required, updates the multicast statistics.
* In case of success, it returns csum_none becasue the device
* is not able to compute the csum in HW. */
-static int mac100_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
+static int dwmac100_get_rx_frame_status(void *data,
+ struct stmmac_extra_stats *x,
struct dma_desc *p)
{
int ret = csum_none;
struct net_device_stats *stats = (struct net_device_stats *)data;
if (unlikely(p->des01.rx.last_descriptor == 0)) {
- pr_warning("mac100 Error: Oversized Ethernet "
+ pr_warning("dwmac100 Error: Oversized Ethernet "
"frame spanned multiple buffers\n");
stats->rx_length_errors++;
return discard_frame;
@@ -262,7 +265,7 @@ static int mac100_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
ret = discard_frame;
if (unlikely(p->des01.rx.length_error)) {
- x->rx_lenght++;
+ x->rx_length++;
ret = discard_frame;
}
if (unlikely(p->des01.rx.mii_error)) {
@@ -276,24 +279,24 @@ static int mac100_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
return ret;
}
-static void mac100_irq_status(unsigned long ioaddr)
+static void dwmac100_irq_status(unsigned long ioaddr)
{
return;
}
-static void mac100_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
+static void dwmac100_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
unsigned int reg_n)
{
stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
}
-static void mac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
+static void dwmac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
unsigned int reg_n)
{
stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
}
-static void mac100_set_filter(struct net_device *dev)
+static void dwmac100_set_filter(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr;
u32 value = readl(ioaddr + MAC_CONTROL);
@@ -302,29 +305,27 @@ static void mac100_set_filter(struct net_device *dev)
value |= MAC_CONTROL_PR;
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO |
MAC_CONTROL_HP);
- } else if ((dev->mc_count > HASH_TABLE_SIZE)
+ } else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
|| (dev->flags & IFF_ALLMULTI)) {
value |= MAC_CONTROL_PM;
value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO);
writel(0xffffffff, ioaddr + MAC_HASH_HIGH);
writel(0xffffffff, ioaddr + MAC_HASH_LOW);
- } else if (dev->mc_count == 0) { /* no multicast */
+ } else if (netdev_mc_empty(dev)) { /* no multicast */
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF |
MAC_CONTROL_HO | MAC_CONTROL_HP);
} else {
- int i;
u32 mc_filter[2];
struct dev_mc_list *mclist;
/* Perfect filter mode for physical address and Hash
filter for multicast */
value |= MAC_CONTROL_HP;
- value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF
- | MAC_CONTROL_HO);
+ value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR |
+ MAC_CONTROL_IF | MAC_CONTROL_HO);
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list;
- mclist && i < dev->mc_count; i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
/* The upper 6 bits of the calculated CRC are used to
* index the contens of the hash table */
int bit_nr =
@@ -347,7 +348,7 @@ static void mac100_set_filter(struct net_device *dev)
return;
}
-static void mac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
+static void dwmac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
unsigned int fc, unsigned int pause_time)
{
unsigned int flow = MAC_FLOW_CTRL_ENABLE;
@@ -359,13 +360,15 @@ static void mac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
return;
}
-/* No PMT module supported in our SoC for the Ethernet Controller. */
-static void mac100_pmt(unsigned long ioaddr, unsigned long mode)
+/* No PMT module supported for this Ethernet Controller.
+ * Tested on ST platforms only.
+ */
+static void dwmac100_pmt(unsigned long ioaddr, unsigned long mode)
{
return;
}
-static void mac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
+static void dwmac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
int disable_rx_ic)
{
int i;
@@ -381,7 +384,7 @@ static void mac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
return;
}
-static void mac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
+static void dwmac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
{
int i;
for (i = 0; i < ring_size; i++) {
@@ -393,32 +396,32 @@ static void mac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
return;
}
-static int mac100_get_tx_owner(struct dma_desc *p)
+static int dwmac100_get_tx_owner(struct dma_desc *p)
{
return p->des01.tx.own;
}
-static int mac100_get_rx_owner(struct dma_desc *p)
+static int dwmac100_get_rx_owner(struct dma_desc *p)
{
return p->des01.rx.own;
}
-static void mac100_set_tx_owner(struct dma_desc *p)
+static void dwmac100_set_tx_owner(struct dma_desc *p)
{
p->des01.tx.own = 1;
}
-static void mac100_set_rx_owner(struct dma_desc *p)
+static void dwmac100_set_rx_owner(struct dma_desc *p)
{
p->des01.rx.own = 1;
}
-static int mac100_get_tx_ls(struct dma_desc *p)
+static int dwmac100_get_tx_ls(struct dma_desc *p)
{
return p->des01.tx.last_segment;
}
-static void mac100_release_tx_desc(struct dma_desc *p)
+static void dwmac100_release_tx_desc(struct dma_desc *p)
{
int ter = p->des01.tx.end_ring;
@@ -444,74 +447,91 @@ static void mac100_release_tx_desc(struct dma_desc *p)
return;
}
-static void mac100_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
+static void dwmac100_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
int csum_flag)
{
p->des01.tx.first_segment = is_fs;
p->des01.tx.buffer1_size = len;
}
-static void mac100_clear_tx_ic(struct dma_desc *p)
+static void dwmac100_clear_tx_ic(struct dma_desc *p)
{
p->des01.tx.interrupt = 0;
}
-static void mac100_close_tx_desc(struct dma_desc *p)
+static void dwmac100_close_tx_desc(struct dma_desc *p)
{
p->des01.tx.last_segment = 1;
p->des01.tx.interrupt = 1;
}
-static int mac100_get_rx_frame_len(struct dma_desc *p)
+static int dwmac100_get_rx_frame_len(struct dma_desc *p)
{
return p->des01.rx.frame_length;
}
-struct stmmac_ops mac100_driver = {
- .core_init = mac100_core_init,
- .dump_mac_regs = mac100_dump_mac_regs,
- .dma_init = mac100_dma_init,
- .dump_dma_regs = mac100_dump_dma_regs,
- .dma_mode = mac100_dma_operation_mode,
- .dma_diagnostic_fr = mac100_dma_diagnostic_fr,
- .tx_status = mac100_get_tx_frame_status,
- .rx_status = mac100_get_rx_frame_status,
- .get_tx_len = mac100_get_tx_len,
- .set_filter = mac100_set_filter,
- .flow_ctrl = mac100_flow_ctrl,
- .pmt = mac100_pmt,
- .init_rx_desc = mac100_init_rx_desc,
- .init_tx_desc = mac100_init_tx_desc,
- .get_tx_owner = mac100_get_tx_owner,
- .get_rx_owner = mac100_get_rx_owner,
- .release_tx_desc = mac100_release_tx_desc,
- .prepare_tx_desc = mac100_prepare_tx_desc,
- .clear_tx_ic = mac100_clear_tx_ic,
- .close_tx_desc = mac100_close_tx_desc,
- .get_tx_ls = mac100_get_tx_ls,
- .set_tx_owner = mac100_set_tx_owner,
- .set_rx_owner = mac100_set_rx_owner,
- .get_rx_frame_len = mac100_get_rx_frame_len,
- .host_irq_status = mac100_irq_status,
- .set_umac_addr = mac100_set_umac_addr,
- .get_umac_addr = mac100_get_umac_addr,
+struct stmmac_ops dwmac100_ops = {
+ .core_init = dwmac100_core_init,
+ .dump_regs = dwmac100_dump_mac_regs,
+ .host_irq_status = dwmac100_irq_status,
+ .set_filter = dwmac100_set_filter,
+ .flow_ctrl = dwmac100_flow_ctrl,
+ .pmt = dwmac100_pmt,
+ .set_umac_addr = dwmac100_set_umac_addr,
+ .get_umac_addr = dwmac100_get_umac_addr,
};
-struct mac_device_info *mac100_setup(unsigned long ioaddr)
+struct stmmac_dma_ops dwmac100_dma_ops = {
+ .init = dwmac100_dma_init,
+ .dump_regs = dwmac100_dump_dma_regs,
+ .dma_mode = dwmac100_dma_operation_mode,
+ .dma_diagnostic_fr = dwmac100_dma_diagnostic_fr,
+ .enable_dma_transmission = dwmac_enable_dma_transmission,
+ .enable_dma_irq = dwmac_enable_dma_irq,
+ .disable_dma_irq = dwmac_disable_dma_irq,
+ .start_tx = dwmac_dma_start_tx,
+ .stop_tx = dwmac_dma_stop_tx,
+ .start_rx = dwmac_dma_start_rx,
+ .stop_rx = dwmac_dma_stop_rx,
+ .dma_interrupt = dwmac_dma_interrupt,
+};
+
+struct stmmac_desc_ops dwmac100_desc_ops = {
+ .tx_status = dwmac100_get_tx_frame_status,
+ .rx_status = dwmac100_get_rx_frame_status,
+ .get_tx_len = dwmac100_get_tx_len,
+ .init_rx_desc = dwmac100_init_rx_desc,
+ .init_tx_desc = dwmac100_init_tx_desc,
+ .get_tx_owner = dwmac100_get_tx_owner,
+ .get_rx_owner = dwmac100_get_rx_owner,
+ .release_tx_desc = dwmac100_release_tx_desc,
+ .prepare_tx_desc = dwmac100_prepare_tx_desc,
+ .clear_tx_ic = dwmac100_clear_tx_ic,
+ .close_tx_desc = dwmac100_close_tx_desc,
+ .get_tx_ls = dwmac100_get_tx_ls,
+ .set_tx_owner = dwmac100_set_tx_owner,
+ .set_rx_owner = dwmac100_set_rx_owner,
+ .get_rx_frame_len = dwmac100_get_rx_frame_len,
+};
+
+struct mac_device_info *dwmac100_setup(unsigned long ioaddr)
{
struct mac_device_info *mac;
mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
- pr_info("\tMAC 10/100\n");
+ pr_info("\tDWMAC100\n");
+
+ mac->mac = &dwmac100_ops;
+ mac->desc = &dwmac100_desc_ops;
+ mac->dma = &dwmac100_dma_ops;
- mac->ops = &mac100_driver;
- mac->hw.pmt = PMT_NOT_SUPPORTED;
- mac->hw.link.port = MAC_CONTROL_PS;
- mac->hw.link.duplex = MAC_CONTROL_F;
- mac->hw.link.speed = 0;
- mac->hw.mii.addr = MAC_MII_ADDR;
- mac->hw.mii.data = MAC_MII_DATA;
+ mac->pmt = PMT_NOT_SUPPORTED;
+ mac->link.port = MAC_CONTROL_PS;
+ mac->link.duplex = MAC_CONTROL_F;
+ mac->link.speed = 0;
+ mac->mii.addr = MAC_MII_ADDR;
+ mac->mii.data = MAC_MII_DATA;
return mac;
}
diff --git a/drivers/net/stmmac/mac100.h b/drivers/net/stmmac/dwmac100.h
index 0f8f110d004a..0f8f110d004a 100644
--- a/drivers/net/stmmac/mac100.h
+++ b/drivers/net/stmmac/dwmac100.h
diff --git a/drivers/net/stmmac/gmac.h b/drivers/net/stmmac/dwmac1000.h
index 2e82d6c9a148..62dca0e384e7 100644
--- a/drivers/net/stmmac/gmac.h
+++ b/drivers/net/stmmac/dwmac1000.h
@@ -20,6 +20,9 @@
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
+#include <linux/phy.h>
+#include "common.h"
+
#define GMAC_CONTROL 0x00000000 /* Configuration */
#define GMAC_FRAME_FILTER 0x00000004 /* Frame Filter */
#define GMAC_HASH_HIGH 0x00000008 /* Multicast Hash Table High */
@@ -32,7 +35,7 @@
#define GMAC_WAKEUP_FILTER 0x00000028 /* Wake-up Frame Filter */
#define GMAC_INT_STATUS 0x00000038 /* interrupt status register */
-enum gmac_irq_status {
+enum dwmac1000_irq_status {
time_stamp_irq = 0x0200,
mmc_rx_csum_offload_irq = 0x0080,
mmc_tx_irq = 0x0040,
@@ -202,3 +205,16 @@ enum rtc_control {
#define GMAC_MMC_RX_INTR 0x104
#define GMAC_MMC_TX_INTR 0x108
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
+
+#undef DWMAC1000_DEBUG
+/* #define DWMAC1000__DEBUG */
+#undef FRAME_FILTER_DEBUG
+/* #define FRAME_FILTER_DEBUG */
+#ifdef DWMAC1000__DEBUG
+#define DBG(fmt, args...) printk(fmt, ## args)
+#else
+#define DBG(fmt, args...) do { } while (0)
+#endif
+
+extern struct stmmac_dma_ops dwmac1000_dma_ops;
+extern struct stmmac_desc_ops dwmac1000_desc_ops;
diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c
new file mode 100644
index 000000000000..a6538ae4694c
--- /dev/null
+++ b/drivers/net/stmmac/dwmac1000_core.c
@@ -0,0 +1,243 @@
+/*******************************************************************************
+ This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
+ DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
+ developing this code.
+
+ This only implements the mac core functions for this chip.
+
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/crc32.h>
+#include "dwmac1000.h"
+
+static void dwmac1000_core_init(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + GMAC_CONTROL);
+ value |= GMAC_CORE_INIT;
+ writel(value, ioaddr + GMAC_CONTROL);
+
+ /* STBus Bridge Configuration */
+ /*writel(0xc5608, ioaddr + 0x00007000);*/
+
+ /* Freeze MMC counters */
+ writel(0x8, ioaddr + GMAC_MMC_CTRL);
+ /* Mask GMAC interrupts */
+ writel(0x207, ioaddr + GMAC_INT_MASK);
+
+#ifdef STMMAC_VLAN_TAG_USED
+ /* Tag detection without filtering */
+ writel(0x0, ioaddr + GMAC_VLAN_TAG);
+#endif
+ return;
+}
+
+static void dwmac1000_dump_regs(unsigned long ioaddr)
+{
+ int i;
+ pr_info("\tDWMAC1000 regs (base addr = 0x%8x)\n", (unsigned int)ioaddr);
+
+ for (i = 0; i < 55; i++) {
+ int offset = i * 4;
+ pr_info("\tReg No. %d (offset 0x%x): 0x%08x\n", i,
+ offset, readl(ioaddr + offset));
+ }
+ return;
+}
+
+static void dwmac1000_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
+ unsigned int reg_n)
+{
+ stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
+ GMAC_ADDR_LOW(reg_n));
+}
+
+static void dwmac1000_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
+ unsigned int reg_n)
+{
+ stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
+ GMAC_ADDR_LOW(reg_n));
+}
+
+static void dwmac1000_set_filter(struct net_device *dev)
+{
+ unsigned long ioaddr = dev->base_addr;
+ unsigned int value = 0;
+
+ DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n",
+ __func__, netdev_mc_count(dev), netdev_uc_count(dev));
+
+ if (dev->flags & IFF_PROMISC)
+ value = GMAC_FRAME_FILTER_PR;
+ else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
+ || (dev->flags & IFF_ALLMULTI)) {
+ value = GMAC_FRAME_FILTER_PM; /* pass all multi */
+ writel(0xffffffff, ioaddr + GMAC_HASH_HIGH);
+ writel(0xffffffff, ioaddr + GMAC_HASH_LOW);
+ } else if (!netdev_mc_empty(dev)) {
+ u32 mc_filter[2];
+ struct dev_mc_list *mclist;
+
+ /* Hash filter for multicast */
+ value = GMAC_FRAME_FILTER_HMC;
+
+ memset(mc_filter, 0, sizeof(mc_filter));
+ netdev_for_each_mc_addr(mclist, dev) {
+ /* The upper 6 bits of the calculated CRC are used to
+ index the contens of the hash table */
+ int bit_nr =
+ bitrev32(~crc32_le(~0, mclist->dmi_addr, 6)) >> 26;
+ /* The most significant bit determines the register to
+ * use (H/L) while the other 5 bits determine the bit
+ * within the register. */
+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+ }
+ writel(mc_filter[0], ioaddr + GMAC_HASH_LOW);
+ writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH);
+ }
+
+ /* Handle multiple unicast addresses (perfect filtering)*/
+ if (netdev_uc_count(dev) > GMAC_MAX_UNICAST_ADDRESSES)
+ /* Switch to promiscuous mode is more than 16 addrs
+ are required */
+ value |= GMAC_FRAME_FILTER_PR;
+ else {
+ int reg = 1;
+ struct netdev_hw_addr *ha;
+
+ netdev_for_each_uc_addr(ha, dev) {
+ dwmac1000_set_umac_addr(ioaddr, ha->addr, reg);
+ reg++;
+ }
+ }
+
+#ifdef FRAME_FILTER_DEBUG
+ /* Enable Receive all mode (to debug filtering_fail errors) */
+ value |= GMAC_FRAME_FILTER_RA;
+#endif
+ writel(value, ioaddr + GMAC_FRAME_FILTER);
+
+ DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: "
+ "HI 0x%08x, LO 0x%08x\n", readl(ioaddr + GMAC_FRAME_FILTER),
+ readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
+
+ return;
+}
+
+static void dwmac1000_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
+ unsigned int fc, unsigned int pause_time)
+{
+ unsigned int flow = 0;
+
+ DBG(KERN_DEBUG "GMAC Flow-Control:\n");
+ if (fc & FLOW_RX) {
+ DBG(KERN_DEBUG "\tReceive Flow-Control ON\n");
+ flow |= GMAC_FLOW_CTRL_RFE;
+ }
+ if (fc & FLOW_TX) {
+ DBG(KERN_DEBUG "\tTransmit Flow-Control ON\n");
+ flow |= GMAC_FLOW_CTRL_TFE;
+ }
+
+ if (duplex) {
+ DBG(KERN_DEBUG "\tduplex mode: pause time: %d\n", pause_time);
+ flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
+ }
+
+ writel(flow, ioaddr + GMAC_FLOW_CTRL);
+ return;
+}
+
+static void dwmac1000_pmt(unsigned long ioaddr, unsigned long mode)
+{
+ unsigned int pmt = 0;
+
+ if (mode == WAKE_MAGIC) {
+ DBG(KERN_DEBUG "GMAC: WOL Magic frame\n");
+ pmt |= power_down | magic_pkt_en;
+ } else if (mode == WAKE_UCAST) {
+ DBG(KERN_DEBUG "GMAC: WOL on global unicast\n");
+ pmt |= global_unicast;
+ }
+
+ writel(pmt, ioaddr + GMAC_PMT);
+ return;
+}
+
+
+static void dwmac1000_irq_status(unsigned long ioaddr)
+{
+ u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
+
+ /* Not used events (e.g. MMC interrupts) are not handled. */
+ if ((intr_status & mmc_tx_irq))
+ DBG(KERN_DEBUG "GMAC: MMC tx interrupt: 0x%08x\n",
+ readl(ioaddr + GMAC_MMC_TX_INTR));
+ if (unlikely(intr_status & mmc_rx_irq))
+ DBG(KERN_DEBUG "GMAC: MMC rx interrupt: 0x%08x\n",
+ readl(ioaddr + GMAC_MMC_RX_INTR));
+ if (unlikely(intr_status & mmc_rx_csum_offload_irq))
+ DBG(KERN_DEBUG "GMAC: MMC rx csum offload: 0x%08x\n",
+ readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
+ if (unlikely(intr_status & pmt_irq)) {
+ DBG(KERN_DEBUG "GMAC: received Magic frame\n");
+ /* clear the PMT bits 5 and 6 by reading the PMT
+ * status register. */
+ readl(ioaddr + GMAC_PMT);
+ }
+
+ return;
+}
+
+struct stmmac_ops dwmac1000_ops = {
+ .core_init = dwmac1000_core_init,
+ .dump_regs = dwmac1000_dump_regs,
+ .host_irq_status = dwmac1000_irq_status,
+ .set_filter = dwmac1000_set_filter,
+ .flow_ctrl = dwmac1000_flow_ctrl,
+ .pmt = dwmac1000_pmt,
+ .set_umac_addr = dwmac1000_set_umac_addr,
+ .get_umac_addr = dwmac1000_get_umac_addr,
+};
+
+struct mac_device_info *dwmac1000_setup(unsigned long ioaddr)
+{
+ struct mac_device_info *mac;
+ u32 uid = readl(ioaddr + GMAC_VERSION);
+
+ pr_info("\tDWMAC1000 - user ID: 0x%x, Synopsys ID: 0x%x\n",
+ ((uid & 0x0000ff00) >> 8), (uid & 0x000000ff));
+
+ mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
+
+ mac->mac = &dwmac1000_ops;
+ mac->desc = &dwmac1000_desc_ops;
+ mac->dma = &dwmac1000_dma_ops;
+
+ mac->pmt = PMT_SUPPORTED;
+ mac->link.port = GMAC_CONTROL_PS;
+ mac->link.duplex = GMAC_CONTROL_DM;
+ mac->link.speed = GMAC_CONTROL_FES;
+ mac->mii.addr = GMAC_MII_ADDR;
+ mac->mii.data = GMAC_MII_DATA;
+
+ return mac;
+}
diff --git a/drivers/net/stmmac/gmac.c b/drivers/net/stmmac/dwmac1000_dma.c
index 52586ee68953..39d436a2da68 100644
--- a/drivers/net/stmmac/gmac.c
+++ b/drivers/net/stmmac/dwmac1000_dma.c
@@ -3,6 +3,8 @@
DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
developing this code.
+ This contains the functions to handle the dma and descriptors.
+
Copyright (C) 2007-2009 STMicroelectronics Ltd
This program is free software; you can redistribute it and/or modify it
@@ -24,41 +26,11 @@
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
-#include <linux/netdevice.h>
-#include <linux/crc32.h>
-#include <linux/mii.h>
-#include <linux/phy.h>
-
-#include "stmmac.h"
-#include "gmac.h"
-
-#undef GMAC_DEBUG
-/*#define GMAC_DEBUG*/
-#undef FRAME_FILTER_DEBUG
-/*#define FRAME_FILTER_DEBUG*/
-#ifdef GMAC_DEBUG
-#define DBG(fmt, args...) printk(fmt, ## args)
-#else
-#define DBG(fmt, args...) do { } while (0)
-#endif
+#include "dwmac1000.h"
+#include "dwmac_dma.h"
-static void gmac_dump_regs(unsigned long ioaddr)
-{
- int i;
- pr_info("\t----------------------------------------------\n"
- "\t GMAC registers (base addr = 0x%8x)\n"
- "\t----------------------------------------------\n",
- (unsigned int)ioaddr);
-
- for (i = 0; i < 55; i++) {
- int offset = i * 4;
- pr_info("\tReg No. %d (offset 0x%x): 0x%08x\n", i,
- offset, readl(ioaddr + offset));
- }
- return;
-}
-
-static int gmac_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx)
+static int dwmac1000_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
+ u32 dma_rx)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
/* DMA SW reset */
@@ -87,7 +59,7 @@ static int gmac_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx)
}
/* Transmit FIFO flush operation */
-static void gmac_flush_tx_fifo(unsigned long ioaddr)
+static void dwmac1000_flush_tx_fifo(unsigned long ioaddr)
{
u32 csr6 = readl(ioaddr + DMA_CONTROL);
writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
@@ -95,7 +67,7 @@ static void gmac_flush_tx_fifo(unsigned long ioaddr)
do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
}
-static void gmac_dma_operation_mode(unsigned long ioaddr, int txmode,
+static void dwmac1000_dma_operation_mode(unsigned long ioaddr, int txmode,
int rxmode)
{
u32 csr6 = readl(ioaddr + DMA_CONTROL);
@@ -148,13 +120,13 @@ static void gmac_dma_operation_mode(unsigned long ioaddr, int txmode,
}
/* Not yet implemented --- no RMON module */
-static void gmac_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
- unsigned long ioaddr)
+static void dwmac1000_dma_diagnostic_fr(void *data,
+ struct stmmac_extra_stats *x, unsigned long ioaddr)
{
return;
}
-static void gmac_dump_dma_regs(unsigned long ioaddr)
+static void dwmac1000_dump_dma_regs(unsigned long ioaddr)
{
int i;
pr_info(" DMA registers\n");
@@ -169,8 +141,9 @@ static void gmac_dump_dma_regs(unsigned long ioaddr)
return;
}
-static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
- struct dma_desc *p, unsigned long ioaddr)
+static int dwmac1000_get_tx_frame_status(void *data,
+ struct stmmac_extra_stats *x,
+ struct dma_desc *p, unsigned long ioaddr)
{
int ret = 0;
struct net_device_stats *stats = (struct net_device_stats *)data;
@@ -185,7 +158,7 @@ static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
if (unlikely(p->des01.etx.frame_flushed)) {
DBG(KERN_ERR "\tframe_flushed error\n");
x->tx_frame_flushed++;
- gmac_flush_tx_fifo(ioaddr);
+ dwmac1000_flush_tx_fifo(ioaddr);
}
if (unlikely(p->des01.etx.loss_carrier)) {
@@ -213,7 +186,7 @@ static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
if (unlikely(p->des01.etx.underflow_error)) {
DBG(KERN_ERR "\tunderflow error\n");
- gmac_flush_tx_fifo(ioaddr);
+ dwmac1000_flush_tx_fifo(ioaddr);
x->tx_underflow++;
}
@@ -225,7 +198,7 @@ static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
if (unlikely(p->des01.etx.payload_error)) {
DBG(KERN_ERR "\tAddr/Payload csum error\n");
x->tx_payload_error++;
- gmac_flush_tx_fifo(ioaddr);
+ dwmac1000_flush_tx_fifo(ioaddr);
}
ret = -1;
@@ -245,19 +218,19 @@ static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
return ret;
}
-static int gmac_get_tx_len(struct dma_desc *p)
+static int dwmac1000_get_tx_len(struct dma_desc *p)
{
return p->des01.etx.buffer1_size;
}
-static int gmac_coe_rdes0(int ipc_err, int type, int payload_err)
+static int dwmac1000_coe_rdes0(int ipc_err, int type, int payload_err)
{
int ret = good_frame;
u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7;
/* bits 5 7 0 | Frame status
* ----------------------------------------------------------
- * 0 0 0 | IEEE 802.3 Type frame (lenght < 1536 octects)
+ * 0 0 0 | IEEE 802.3 Type frame (length < 1536 octects)
* 1 0 0 | IPv4/6 No CSUM errorS.
* 1 0 1 | IPv4/6 CSUM PAYLOAD error
* 1 1 0 | IPv4/6 CSUM IP HR error
@@ -293,8 +266,8 @@ static int gmac_coe_rdes0(int ipc_err, int type, int payload_err)
return ret;
}
-static int gmac_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
- struct dma_desc *p)
+static int dwmac1000_get_rx_frame_status(void *data,
+ struct stmmac_extra_stats *x, struct dma_desc *p)
{
int ret = good_frame;
struct net_device_stats *stats = (struct net_device_stats *)data;
@@ -339,7 +312,7 @@ static int gmac_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
* It doesn't match with the information reported into the databook.
* At any rate, we need to understand if the CSUM hw computation is ok
* and report this info to the upper layers. */
- ret = gmac_coe_rdes0(p->des01.erx.ipc_csum_error,
+ ret = dwmac1000_coe_rdes0(p->des01.erx.ipc_csum_error,
p->des01.erx.frame_type, p->des01.erx.payload_csum_error);
if (unlikely(p->des01.erx.dribbling)) {
@@ -358,7 +331,7 @@ static int gmac_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
}
if (unlikely(p->des01.erx.length_error)) {
DBG(KERN_ERR "GMAC RX: length_error error\n");
- x->rx_lenght++;
+ x->rx_length++;
ret = discard_frame;
}
#ifdef STMMAC_VLAN_TAG_USED
@@ -370,181 +343,7 @@ static int gmac_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
return ret;
}
-static void gmac_irq_status(unsigned long ioaddr)
-{
- u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
-
- /* Not used events (e.g. MMC interrupts) are not handled. */
- if ((intr_status & mmc_tx_irq))
- DBG(KERN_DEBUG "GMAC: MMC tx interrupt: 0x%08x\n",
- readl(ioaddr + GMAC_MMC_TX_INTR));
- if (unlikely(intr_status & mmc_rx_irq))
- DBG(KERN_DEBUG "GMAC: MMC rx interrupt: 0x%08x\n",
- readl(ioaddr + GMAC_MMC_RX_INTR));
- if (unlikely(intr_status & mmc_rx_csum_offload_irq))
- DBG(KERN_DEBUG "GMAC: MMC rx csum offload: 0x%08x\n",
- readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
- if (unlikely(intr_status & pmt_irq)) {
- DBG(KERN_DEBUG "GMAC: received Magic frame\n");
- /* clear the PMT bits 5 and 6 by reading the PMT
- * status register. */
- readl(ioaddr + GMAC_PMT);
- }
-
- return;
-}
-
-static void gmac_core_init(unsigned long ioaddr)
-{
- u32 value = readl(ioaddr + GMAC_CONTROL);
- value |= GMAC_CORE_INIT;
- writel(value, ioaddr + GMAC_CONTROL);
-
- /* STBus Bridge Configuration */
- /*writel(0xc5608, ioaddr + 0x00007000);*/
-
- /* Freeze MMC counters */
- writel(0x8, ioaddr + GMAC_MMC_CTRL);
- /* Mask GMAC interrupts */
- writel(0x207, ioaddr + GMAC_INT_MASK);
-
-#ifdef STMMAC_VLAN_TAG_USED
- /* Tag detection without filtering */
- writel(0x0, ioaddr + GMAC_VLAN_TAG);
-#endif
- return;
-}
-
-static void gmac_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
- unsigned int reg_n)
-{
- stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
- GMAC_ADDR_LOW(reg_n));
-}
-
-static void gmac_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
- unsigned int reg_n)
-{
- stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
- GMAC_ADDR_LOW(reg_n));
-}
-
-static void gmac_set_filter(struct net_device *dev)
-{
- unsigned long ioaddr = dev->base_addr;
- unsigned int value = 0;
-
- DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n",
- __func__, dev->mc_count, dev->uc_count);
-
- if (dev->flags & IFF_PROMISC)
- value = GMAC_FRAME_FILTER_PR;
- else if ((dev->mc_count > HASH_TABLE_SIZE)
- || (dev->flags & IFF_ALLMULTI)) {
- value = GMAC_FRAME_FILTER_PM; /* pass all multi */
- writel(0xffffffff, ioaddr + GMAC_HASH_HIGH);
- writel(0xffffffff, ioaddr + GMAC_HASH_LOW);
- } else if (dev->mc_count > 0) {
- int i;
- u32 mc_filter[2];
- struct dev_mc_list *mclist;
-
- /* Hash filter for multicast */
- value = GMAC_FRAME_FILTER_HMC;
-
- memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list;
- mclist && i < dev->mc_count; i++, mclist = mclist->next) {
- /* The upper 6 bits of the calculated CRC are used to
- index the contens of the hash table */
- int bit_nr =
- bitrev32(~crc32_le(~0, mclist->dmi_addr, 6)) >> 26;
- /* The most significant bit determines the register to
- * use (H/L) while the other 5 bits determine the bit
- * within the register. */
- mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
- }
- writel(mc_filter[0], ioaddr + GMAC_HASH_LOW);
- writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH);
- }
-
- /* Handle multiple unicast addresses (perfect filtering)*/
- if (dev->uc_count > GMAC_MAX_UNICAST_ADDRESSES)
- /* Switch to promiscuous mode is more than 16 addrs
- are required */
- value |= GMAC_FRAME_FILTER_PR;
- else {
- int i;
- struct dev_addr_list *uc_ptr = dev->uc_list;
-
- for (i = 0; i < dev->uc_count; i++) {
- gmac_set_umac_addr(ioaddr, uc_ptr->da_addr,
- i + 1);
-
- DBG(KERN_INFO "\t%d "
- "- Unicast addr %02x:%02x:%02x:%02x:%02x:"
- "%02x\n", i + 1,
- uc_ptr->da_addr[0], uc_ptr->da_addr[1],
- uc_ptr->da_addr[2], uc_ptr->da_addr[3],
- uc_ptr->da_addr[4], uc_ptr->da_addr[5]);
- uc_ptr = uc_ptr->next;
- }
- }
-
-#ifdef FRAME_FILTER_DEBUG
- /* Enable Receive all mode (to debug filtering_fail errors) */
- value |= GMAC_FRAME_FILTER_RA;
-#endif
- writel(value, ioaddr + GMAC_FRAME_FILTER);
-
- DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: "
- "HI 0x%08x, LO 0x%08x\n", readl(ioaddr + GMAC_FRAME_FILTER),
- readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
-
- return;
-}
-
-static void gmac_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
- unsigned int fc, unsigned int pause_time)
-{
- unsigned int flow = 0;
-
- DBG(KERN_DEBUG "GMAC Flow-Control:\n");
- if (fc & FLOW_RX) {
- DBG(KERN_DEBUG "\tReceive Flow-Control ON\n");
- flow |= GMAC_FLOW_CTRL_RFE;
- }
- if (fc & FLOW_TX) {
- DBG(KERN_DEBUG "\tTransmit Flow-Control ON\n");
- flow |= GMAC_FLOW_CTRL_TFE;
- }
-
- if (duplex) {
- DBG(KERN_DEBUG "\tduplex mode: pause time: %d\n", pause_time);
- flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
- }
-
- writel(flow, ioaddr + GMAC_FLOW_CTRL);
- return;
-}
-
-static void gmac_pmt(unsigned long ioaddr, unsigned long mode)
-{
- unsigned int pmt = 0;
-
- if (mode == WAKE_MAGIC) {
- DBG(KERN_DEBUG "GMAC: WOL Magic frame\n");
- pmt |= power_down | magic_pkt_en;
- } else if (mode == WAKE_UCAST) {
- DBG(KERN_DEBUG "GMAC: WOL on global unicast\n");
- pmt |= global_unicast;
- }
-
- writel(pmt, ioaddr + GMAC_PMT);
- return;
-}
-
-static void gmac_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
+static void dwmac1000_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
int disable_rx_ic)
{
int i;
@@ -562,7 +361,7 @@ static void gmac_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
return;
}
-static void gmac_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
+static void dwmac1000_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
{
int i;
@@ -576,32 +375,32 @@ static void gmac_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
return;
}
-static int gmac_get_tx_owner(struct dma_desc *p)
+static int dwmac1000_get_tx_owner(struct dma_desc *p)
{
return p->des01.etx.own;
}
-static int gmac_get_rx_owner(struct dma_desc *p)
+static int dwmac1000_get_rx_owner(struct dma_desc *p)
{
return p->des01.erx.own;
}
-static void gmac_set_tx_owner(struct dma_desc *p)
+static void dwmac1000_set_tx_owner(struct dma_desc *p)
{
p->des01.etx.own = 1;
}
-static void gmac_set_rx_owner(struct dma_desc *p)
+static void dwmac1000_set_rx_owner(struct dma_desc *p)
{
p->des01.erx.own = 1;
}
-static int gmac_get_tx_ls(struct dma_desc *p)
+static int dwmac1000_get_tx_ls(struct dma_desc *p)
{
return p->des01.etx.last_segment;
}
-static void gmac_release_tx_desc(struct dma_desc *p)
+static void dwmac1000_release_tx_desc(struct dma_desc *p)
{
int ter = p->des01.etx.end_ring;
@@ -611,7 +410,7 @@ static void gmac_release_tx_desc(struct dma_desc *p)
return;
}
-static void gmac_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
+static void dwmac1000_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
int csum_flag)
{
p->des01.etx.first_segment = is_fs;
@@ -625,69 +424,51 @@ static void gmac_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
p->des01.etx.checksum_insertion = cic_full;
}
-static void gmac_clear_tx_ic(struct dma_desc *p)
+static void dwmac1000_clear_tx_ic(struct dma_desc *p)
{
p->des01.etx.interrupt = 0;
}
-static void gmac_close_tx_desc(struct dma_desc *p)
+static void dwmac1000_close_tx_desc(struct dma_desc *p)
{
p->des01.etx.last_segment = 1;
p->des01.etx.interrupt = 1;
}
-static int gmac_get_rx_frame_len(struct dma_desc *p)
+static int dwmac1000_get_rx_frame_len(struct dma_desc *p)
{
return p->des01.erx.frame_length;
}
-struct stmmac_ops gmac_driver = {
- .core_init = gmac_core_init,
- .dump_mac_regs = gmac_dump_regs,
- .dma_init = gmac_dma_init,
- .dump_dma_regs = gmac_dump_dma_regs,
- .dma_mode = gmac_dma_operation_mode,
- .dma_diagnostic_fr = gmac_dma_diagnostic_fr,
- .tx_status = gmac_get_tx_frame_status,
- .rx_status = gmac_get_rx_frame_status,
- .get_tx_len = gmac_get_tx_len,
- .set_filter = gmac_set_filter,
- .flow_ctrl = gmac_flow_ctrl,
- .pmt = gmac_pmt,
- .init_rx_desc = gmac_init_rx_desc,
- .init_tx_desc = gmac_init_tx_desc,
- .get_tx_owner = gmac_get_tx_owner,
- .get_rx_owner = gmac_get_rx_owner,
- .release_tx_desc = gmac_release_tx_desc,
- .prepare_tx_desc = gmac_prepare_tx_desc,
- .clear_tx_ic = gmac_clear_tx_ic,
- .close_tx_desc = gmac_close_tx_desc,
- .get_tx_ls = gmac_get_tx_ls,
- .set_tx_owner = gmac_set_tx_owner,
- .set_rx_owner = gmac_set_rx_owner,
- .get_rx_frame_len = gmac_get_rx_frame_len,
- .host_irq_status = gmac_irq_status,
- .set_umac_addr = gmac_set_umac_addr,
- .get_umac_addr = gmac_get_umac_addr,
+struct stmmac_dma_ops dwmac1000_dma_ops = {
+ .init = dwmac1000_dma_init,
+ .dump_regs = dwmac1000_dump_dma_regs,
+ .dma_mode = dwmac1000_dma_operation_mode,
+ .dma_diagnostic_fr = dwmac1000_dma_diagnostic_fr,
+ .enable_dma_transmission = dwmac_enable_dma_transmission,
+ .enable_dma_irq = dwmac_enable_dma_irq,
+ .disable_dma_irq = dwmac_disable_dma_irq,
+ .start_tx = dwmac_dma_start_tx,
+ .stop_tx = dwmac_dma_stop_tx,
+ .start_rx = dwmac_dma_start_rx,
+ .stop_rx = dwmac_dma_stop_rx,
+ .dma_interrupt = dwmac_dma_interrupt,
};
-struct mac_device_info *gmac_setup(unsigned long ioaddr)
-{
- struct mac_device_info *mac;
- u32 uid = readl(ioaddr + GMAC_VERSION);
-
- pr_info("\tGMAC - user ID: 0x%x, Synopsys ID: 0x%x\n",
- ((uid & 0x0000ff00) >> 8), (uid & 0x000000ff));
-
- mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
-
- mac->ops = &gmac_driver;
- mac->hw.pmt = PMT_SUPPORTED;
- mac->hw.link.port = GMAC_CONTROL_PS;
- mac->hw.link.duplex = GMAC_CONTROL_DM;
- mac->hw.link.speed = GMAC_CONTROL_FES;
- mac->hw.mii.addr = GMAC_MII_ADDR;
- mac->hw.mii.data = GMAC_MII_DATA;
-
- return mac;
-}
+struct stmmac_desc_ops dwmac1000_desc_ops = {
+ .tx_status = dwmac1000_get_tx_frame_status,
+ .rx_status = dwmac1000_get_rx_frame_status,
+ .get_tx_len = dwmac1000_get_tx_len,
+ .init_rx_desc = dwmac1000_init_rx_desc,
+ .init_tx_desc = dwmac1000_init_tx_desc,
+ .get_tx_owner = dwmac1000_get_tx_owner,
+ .get_rx_owner = dwmac1000_get_rx_owner,
+ .release_tx_desc = dwmac1000_release_tx_desc,
+ .prepare_tx_desc = dwmac1000_prepare_tx_desc,
+ .clear_tx_ic = dwmac1000_clear_tx_ic,
+ .close_tx_desc = dwmac1000_close_tx_desc,
+ .get_tx_ls = dwmac1000_get_tx_ls,
+ .set_tx_owner = dwmac1000_set_tx_owner,
+ .set_rx_owner = dwmac1000_set_rx_owner,
+ .get_rx_frame_len = dwmac1000_get_rx_frame_len,
+};
diff --git a/drivers/net/stmmac/dwmac_dma.h b/drivers/net/stmmac/dwmac_dma.h
new file mode 100644
index 000000000000..de848d9f6060
--- /dev/null
+++ b/drivers/net/stmmac/dwmac_dma.h
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ DWMAC DMA Header file.
+
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+/* DMA CRS Control and Status Register Mapping */
+#define DMA_BUS_MODE 0x00001000 /* Bus Mode */
+#define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */
+#define DMA_RCV_POLL_DEMAND 0x00001008 /* Received Poll Demand */
+#define DMA_RCV_BASE_ADDR 0x0000100c /* Receive List Base */
+#define DMA_TX_BASE_ADDR 0x00001010 /* Transmit List Base */
+#define DMA_STATUS 0x00001014 /* Status Register */
+#define DMA_CONTROL 0x00001018 /* Ctrl (Operational Mode) */
+#define DMA_INTR_ENA 0x0000101c /* Interrupt Enable */
+#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */
+#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */
+#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */
+
+/* DMA Control register defines */
+#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */
+#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */
+
+/* DMA Normal interrupt */
+#define DMA_INTR_ENA_NIE 0x00010000 /* Normal Summary */
+#define DMA_INTR_ENA_TIE 0x00000001 /* Transmit Interrupt */
+#define DMA_INTR_ENA_TUE 0x00000004 /* Transmit Buffer Unavailable */
+#define DMA_INTR_ENA_RIE 0x00000040 /* Receive Interrupt */
+#define DMA_INTR_ENA_ERE 0x00004000 /* Early Receive */
+
+#define DMA_INTR_NORMAL (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \
+ DMA_INTR_ENA_TIE)
+
+/* DMA Abnormal interrupt */
+#define DMA_INTR_ENA_AIE 0x00008000 /* Abnormal Summary */
+#define DMA_INTR_ENA_FBE 0x00002000 /* Fatal Bus Error */
+#define DMA_INTR_ENA_ETE 0x00000400 /* Early Transmit */
+#define DMA_INTR_ENA_RWE 0x00000200 /* Receive Watchdog */
+#define DMA_INTR_ENA_RSE 0x00000100 /* Receive Stopped */
+#define DMA_INTR_ENA_RUE 0x00000080 /* Receive Buffer Unavailable */
+#define DMA_INTR_ENA_UNE 0x00000020 /* Tx Underflow */
+#define DMA_INTR_ENA_OVE 0x00000010 /* Receive Overflow */
+#define DMA_INTR_ENA_TJE 0x00000008 /* Transmit Jabber */
+#define DMA_INTR_ENA_TSE 0x00000002 /* Transmit Stopped */
+
+#define DMA_INTR_ABNORMAL (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \
+ DMA_INTR_ENA_UNE)
+
+/* DMA default interrupt mask */
+#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
+
+/* DMA Status register defines */
+#define DMA_STATUS_GPI 0x10000000 /* PMT interrupt */
+#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
+#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */
+#define DMA_STATUS_GMI 0x08000000
+#define DMA_STATUS_GLI 0x04000000
+#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */
+#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */
+#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */
+#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */
+#define DMA_STATUS_TS_SHIFT 20
+#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */
+#define DMA_STATUS_RS_SHIFT 17
+#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */
+#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */
+#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */
+#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */
+#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */
+#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */
+#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */
+#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */
+#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */
+#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */
+#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */
+#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */
+#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */
+#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */
+#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
+
+extern void dwmac_enable_dma_transmission(unsigned long ioaddr);
+extern void dwmac_enable_dma_irq(unsigned long ioaddr);
+extern void dwmac_disable_dma_irq(unsigned long ioaddr);
+extern void dwmac_dma_start_tx(unsigned long ioaddr);
+extern void dwmac_dma_stop_tx(unsigned long ioaddr);
+extern void dwmac_dma_start_rx(unsigned long ioaddr);
+extern void dwmac_dma_stop_rx(unsigned long ioaddr);
+extern int dwmac_dma_interrupt(unsigned long ioaddr,
+ struct stmmac_extra_stats *x);
diff --git a/drivers/net/stmmac/dwmac_lib.c b/drivers/net/stmmac/dwmac_lib.c
new file mode 100644
index 000000000000..d4adb1eaa447
--- /dev/null
+++ b/drivers/net/stmmac/dwmac_lib.c
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/io.h>
+#include "common.h"
+#include "dwmac_dma.h"
+
+#undef DWMAC_DMA_DEBUG
+#ifdef DWMAC_DMA_DEBUG
+#define DBG(fmt, args...) printk(fmt, ## args)
+#else
+#define DBG(fmt, args...) do { } while (0)
+#endif
+
+/* CSR1 enables the transmit DMA to check for new descriptor */
+void dwmac_enable_dma_transmission(unsigned long ioaddr)
+{
+ writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
+}
+
+void dwmac_enable_dma_irq(unsigned long ioaddr)
+{
+ writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
+}
+
+void dwmac_disable_dma_irq(unsigned long ioaddr)
+{
+ writel(0, ioaddr + DMA_INTR_ENA);
+}
+
+void dwmac_dma_start_tx(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + DMA_CONTROL);
+ value |= DMA_CONTROL_ST;
+ writel(value, ioaddr + DMA_CONTROL);
+ return;
+}
+
+void dwmac_dma_stop_tx(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + DMA_CONTROL);
+ value &= ~DMA_CONTROL_ST;
+ writel(value, ioaddr + DMA_CONTROL);
+ return;
+}
+
+void dwmac_dma_start_rx(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + DMA_CONTROL);
+ value |= DMA_CONTROL_SR;
+ writel(value, ioaddr + DMA_CONTROL);
+
+ return;
+}
+
+void dwmac_dma_stop_rx(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + DMA_CONTROL);
+ value &= ~DMA_CONTROL_SR;
+ writel(value, ioaddr + DMA_CONTROL);
+
+ return;
+}
+
+#ifdef DWMAC_DMA_DEBUG
+static void show_tx_process_state(unsigned int status)
+{
+ unsigned int state;
+ state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT;
+
+ switch (state) {
+ case 0:
+ pr_info("- TX (Stopped): Reset or Stop command\n");
+ break;
+ case 1:
+ pr_info("- TX (Running):Fetching the Tx desc\n");
+ break;
+ case 2:
+ pr_info("- TX (Running): Waiting for end of tx\n");
+ break;
+ case 3:
+ pr_info("- TX (Running): Reading the data "
+ "and queuing the data into the Tx buf\n");
+ break;
+ case 6:
+ pr_info("- TX (Suspended): Tx Buff Underflow "
+ "or an unavailable Transmit descriptor\n");
+ break;
+ case 7:
+ pr_info("- TX (Running): Closing Tx descriptor\n");
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+static void show_rx_process_state(unsigned int status)
+{
+ unsigned int state;
+ state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT;
+
+ switch (state) {
+ case 0:
+ pr_info("- RX (Stopped): Reset or Stop command\n");
+ break;
+ case 1:
+ pr_info("- RX (Running): Fetching the Rx desc\n");
+ break;
+ case 2:
+ pr_info("- RX (Running):Checking for end of pkt\n");
+ break;
+ case 3:
+ pr_info("- RX (Running): Waiting for Rx pkt\n");
+ break;
+ case 4:
+ pr_info("- RX (Suspended): Unavailable Rx buf\n");
+ break;
+ case 5:
+ pr_info("- RX (Running): Closing Rx descriptor\n");
+ break;
+ case 6:
+ pr_info("- RX(Running): Flushing the current frame"
+ " from the Rx buf\n");
+ break;
+ case 7:
+ pr_info("- RX (Running): Queuing the Rx frame"
+ " from the Rx buf into memory\n");
+ break;
+ default:
+ break;
+ }
+ return;
+}
+#endif
+
+int dwmac_dma_interrupt(unsigned long ioaddr,
+ struct stmmac_extra_stats *x)
+{
+ int ret = 0;
+ /* read the status register (CSR5) */
+ u32 intr_status = readl(ioaddr + DMA_STATUS);
+
+ DBG(INFO, "%s: [CSR5: 0x%08x]\n", __func__, intr_status);
+#ifdef DWMAC_DMA_DEBUG
+ /* It displays the DMA process states (CSR5 register) */
+ show_tx_process_state(intr_status);
+ show_rx_process_state(intr_status);
+#endif
+ /* ABNORMAL interrupts */
+ if (unlikely(intr_status & DMA_STATUS_AIS)) {
+ DBG(INFO, "CSR5[15] DMA ABNORMAL IRQ: ");
+ if (unlikely(intr_status & DMA_STATUS_UNF)) {
+ DBG(INFO, "transmit underflow\n");
+ ret = tx_hard_error_bump_tc;
+ x->tx_undeflow_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_TJT)) {
+ DBG(INFO, "transmit jabber\n");
+ x->tx_jabber_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_OVF)) {
+ DBG(INFO, "recv overflow\n");
+ x->rx_overflow_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_RU)) {
+ DBG(INFO, "receive buffer unavailable\n");
+ x->rx_buf_unav_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_RPS)) {
+ DBG(INFO, "receive process stopped\n");
+ x->rx_process_stopped_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_RWT)) {
+ DBG(INFO, "receive watchdog\n");
+ x->rx_watchdog_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_ETI)) {
+ DBG(INFO, "transmit early interrupt\n");
+ x->tx_early_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_TPS)) {
+ DBG(INFO, "transmit process stopped\n");
+ x->tx_process_stopped_irq++;
+ ret = tx_hard_error;
+ }
+ if (unlikely(intr_status & DMA_STATUS_FBI)) {
+ DBG(INFO, "fatal bus error\n");
+ x->fatal_bus_error_irq++;
+ ret = tx_hard_error;
+ }
+ }
+ /* TX/RX NORMAL interrupts */
+ if (intr_status & DMA_STATUS_NIS) {
+ x->normal_irq_n++;
+ if (likely((intr_status & DMA_STATUS_RI) ||
+ (intr_status & (DMA_STATUS_TI))))
+ ret = handle_tx_rx;
+ }
+ /* Optional hardware blocks, interrupts should be disabled */
+ if (unlikely(intr_status &
+ (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
+ pr_info("%s: unexpected status %08x\n", __func__, intr_status);
+ /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
+ writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
+
+ DBG(INFO, "\n\n");
+ return ret;
+}
+
+
+void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
+ unsigned int high, unsigned int low)
+{
+ unsigned long data;
+
+ data = (addr[5] << 8) | addr[4];
+ writel(data, ioaddr + high);
+ data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+ writel(data, ioaddr + low);
+
+ return;
+}
+
+void stmmac_get_mac_addr(unsigned long ioaddr, unsigned char *addr,
+ unsigned int high, unsigned int low)
+{
+ unsigned int hi_addr, lo_addr;
+
+ /* Read the MAC address from the hardware */
+ hi_addr = readl(ioaddr + high);
+ lo_addr = readl(ioaddr + low);
+
+ /* Extract the MAC address from the high and low words */
+ addr[0] = lo_addr & 0xff;
+ addr[1] = (lo_addr >> 8) & 0xff;
+ addr[2] = (lo_addr >> 16) & 0xff;
+ addr[3] = (lo_addr >> 24) & 0xff;
+ addr[4] = hi_addr & 0xff;
+ addr[5] = (hi_addr >> 8) & 0xff;
+
+ return;
+}
+
diff --git a/drivers/net/stmmac/stmmac.h b/drivers/net/stmmac/stmmac.h
index 6d2eae3040e5..ba35e6943cf4 100644
--- a/drivers/net/stmmac/stmmac.h
+++ b/drivers/net/stmmac/stmmac.h
@@ -20,7 +20,8 @@
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
-#define DRV_MODULE_VERSION "Oct_09"
+#define DRV_MODULE_VERSION "Jan_2010"
+#include <linux/stmmac.h>
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#define STMMAC_VLAN_TAG_USED
@@ -57,7 +58,7 @@ struct stmmac_priv {
int rx_csum;
unsigned int dma_buf_sz;
struct device *device;
- struct mac_device_info *mac_type;
+ struct mac_device_info *hw;
struct stmmac_extra_stats xstats;
struct napi_struct napi;
@@ -69,6 +70,7 @@ struct stmmac_priv {
int phy_mask;
int (*phy_reset) (void *priv);
void (*fix_mac_speed) (void *priv, unsigned int speed);
+ void (*bus_setup)(unsigned long ioaddr);
void *bsp_priv;
int phy_irq;
@@ -93,6 +95,28 @@ struct stmmac_priv {
#endif
};
+#ifdef CONFIG_STM_DRIVERS
+#include <linux/stm/pad.h>
+static inline int stmmac_claim_resource(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct plat_stmmacenet_data *plat_dat = pdev->dev.platform_data;
+
+ /* Pad routing setup */
+ if (IS_ERR(devm_stm_pad_claim(&pdev->dev, plat_dat->pad_config,
+ dev_name(&pdev->dev)))) {
+ printk(KERN_ERR "%s: Failed to request pads!\n", __func__);
+ ret = -ENODEV;
+ }
+ return ret;
+}
+#else
+static inline int stmmac_claim_resource(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
extern int stmmac_mdio_unregister(struct net_device *ndev);
extern int stmmac_mdio_register(struct net_device *ndev);
extern void stmmac_set_ethtool_ops(struct net_device *netdev);
diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c
index 694ebe6a0758..c021eaa3ca69 100644
--- a/drivers/net/stmmac/stmmac_ethtool.c
+++ b/drivers/net/stmmac/stmmac_ethtool.c
@@ -28,6 +28,7 @@
#include <linux/phy.h>
#include "stmmac.h"
+#include "dwmac_dma.h"
#define REG_SPACE_SIZE 0x1054
#define MAC100_ETHTOOL_NAME "st_mac100"
@@ -61,7 +62,7 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(rx_toolong),
STMMAC_STAT(rx_collision),
STMMAC_STAT(rx_crc),
- STMMAC_STAT(rx_lenght),
+ STMMAC_STAT(rx_length),
STMMAC_STAT(rx_mii),
STMMAC_STAT(rx_multicast),
STMMAC_STAT(rx_gmac_overflow),
@@ -268,8 +269,8 @@ stmmac_set_pauseparam(struct net_device *netdev,
}
} else {
unsigned long ioaddr = netdev->base_addr;
- priv->mac_type->ops->flow_ctrl(ioaddr, phy->duplex,
- priv->flow_ctrl, priv->pause);
+ priv->hw->mac->flow_ctrl(ioaddr, phy->duplex,
+ priv->flow_ctrl, priv->pause);
}
spin_unlock(&priv->lock);
return ret;
@@ -283,8 +284,8 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
int i;
/* Update HW stats if supported */
- priv->mac_type->ops->dma_diagnostic_fr(&dev->stats, &priv->xstats,
- ioaddr);
+ priv->hw->dma->dma_diagnostic_fr(&dev->stats, (void *) &priv->xstats,
+ ioaddr);
for (i = 0; i < STMMAC_STATS_LEN; i++) {
char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset;
diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c
index 508fba8fa07f..a6733612d64a 100644
--- a/drivers/net/stmmac/stmmac_main.c
+++ b/drivers/net/stmmac/stmmac_main.c
@@ -32,7 +32,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
-#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/platform_device.h>
#include <linux/ip.h>
@@ -45,7 +44,6 @@
#include <linux/phy.h>
#include <linux/if_vlan.h>
#include <linux/dma-mapping.h>
-#include <linux/stm/soc.h>
#include "stmmac.h"
#define STMMAC_RESOURCE_NAME "stmmaceth"
@@ -226,41 +224,38 @@ static void stmmac_adjust_link(struct net_device *dev)
if (phydev->duplex != priv->oldduplex) {
new_state = 1;
if (!(phydev->duplex))
- ctrl &= ~priv->mac_type->hw.link.duplex;
+ ctrl &= ~priv->hw->link.duplex;
else
- ctrl |= priv->mac_type->hw.link.duplex;
+ ctrl |= priv->hw->link.duplex;
priv->oldduplex = phydev->duplex;
}
/* Flow Control operation */
if (phydev->pause)
- priv->mac_type->ops->flow_ctrl(ioaddr, phydev->duplex,
- fc, pause_time);
+ priv->hw->mac->flow_ctrl(ioaddr, phydev->duplex,
+ fc, pause_time);
if (phydev->speed != priv->speed) {
new_state = 1;
switch (phydev->speed) {
case 1000:
if (likely(priv->is_gmac))
- ctrl &= ~priv->mac_type->hw.link.port;
+ ctrl &= ~priv->hw->link.port;
break;
case 100:
case 10:
if (priv->is_gmac) {
- ctrl |= priv->mac_type->hw.link.port;
+ ctrl |= priv->hw->link.port;
if (phydev->speed == SPEED_100) {
- ctrl |=
- priv->mac_type->hw.link.
- speed;
+ ctrl |= priv->hw->link.speed;
} else {
- ctrl &=
- ~(priv->mac_type->hw.
- link.speed);
+ ctrl &= ~(priv->hw->link.speed);
}
} else {
- ctrl &= ~priv->mac_type->hw.link.port;
+ ctrl &= ~priv->hw->link.port;
}
- priv->fix_mac_speed(priv->bsp_priv,
- phydev->speed);
+ if (likely(priv->fix_mac_speed))
+ priv->fix_mac_speed(priv->bsp_priv,
+ phydev->speed);
break;
default:
if (netif_msg_link(priv))
@@ -305,8 +300,8 @@ static int stmmac_init_phy(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
struct phy_device *phydev;
- char phy_id[BUS_ID_SIZE]; /* PHY to connect */
- char bus_id[BUS_ID_SIZE];
+ char phy_id[MII_BUS_ID_SIZE + 3];
+ char bus_id[MII_BUS_ID_SIZE];
priv->oldlink = 0;
priv->speed = 0;
@@ -318,7 +313,8 @@ static int stmmac_init_phy(struct net_device *dev)
}
snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->bus_id);
- snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, bus_id, priv->phy_addr);
+ snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
+ priv->phy_addr);
pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id);
phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, 0,
@@ -508,8 +504,8 @@ static void init_dma_desc_rings(struct net_device *dev)
priv->cur_tx = 0;
/* Clear the Rx/Tx descriptors */
- priv->mac_type->ops->init_rx_desc(priv->dma_rx, rxsize, dis_ic);
- priv->mac_type->ops->init_tx_desc(priv->dma_tx, txsize);
+ priv->hw->desc->init_rx_desc(priv->dma_rx, rxsize, dis_ic);
+ priv->hw->desc->init_tx_desc(priv->dma_tx, txsize);
if (netif_msg_hw(priv)) {
pr_info("RX descriptor ring:\n");
@@ -544,8 +540,8 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)
struct dma_desc *p = priv->dma_tx + i;
if (p->des2)
dma_unmap_single(priv->device, p->des2,
- priv->mac_type->ops->get_tx_len(p),
- DMA_TO_DEVICE);
+ priv->hw->desc->get_tx_len(p),
+ DMA_TO_DEVICE);
dev_kfree_skb_any(priv->tx_skbuff[i]);
priv->tx_skbuff[i] = NULL;
}
@@ -575,50 +571,6 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
}
/**
- * stmmac_dma_start_tx
- * @ioaddr: device I/O address
- * Description: this function starts the DMA tx process.
- */
-static void stmmac_dma_start_tx(unsigned long ioaddr)
-{
- u32 value = readl(ioaddr + DMA_CONTROL);
- value |= DMA_CONTROL_ST;
- writel(value, ioaddr + DMA_CONTROL);
- return;
-}
-
-static void stmmac_dma_stop_tx(unsigned long ioaddr)
-{
- u32 value = readl(ioaddr + DMA_CONTROL);
- value &= ~DMA_CONTROL_ST;
- writel(value, ioaddr + DMA_CONTROL);
- return;
-}
-
-/**
- * stmmac_dma_start_rx
- * @ioaddr: device I/O address
- * Description: this function starts the DMA rx process.
- */
-static void stmmac_dma_start_rx(unsigned long ioaddr)
-{
- u32 value = readl(ioaddr + DMA_CONTROL);
- value |= DMA_CONTROL_SR;
- writel(value, ioaddr + DMA_CONTROL);
-
- return;
-}
-
-static void stmmac_dma_stop_rx(unsigned long ioaddr)
-{
- u32 value = readl(ioaddr + DMA_CONTROL);
- value &= ~DMA_CONTROL_SR;
- writel(value, ioaddr + DMA_CONTROL);
-
- return;
-}
-
-/**
* stmmac_dma_operation_mode - HW DMA operation mode
* @priv : pointer to the private device structure.
* Description: it sets the DMA operation mode: tx/rx DMA thresholds
@@ -629,18 +581,18 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
{
if (!priv->is_gmac) {
/* MAC 10/100 */
- priv->mac_type->ops->dma_mode(priv->dev->base_addr, tc, 0);
+ priv->hw->dma->dma_mode(priv->dev->base_addr, tc, 0);
priv->tx_coe = NO_HW_CSUM;
} else {
if ((priv->dev->mtu <= ETH_DATA_LEN) && (tx_coe)) {
- priv->mac_type->ops->dma_mode(priv->dev->base_addr,
- SF_DMA_MODE, SF_DMA_MODE);
+ priv->hw->dma->dma_mode(priv->dev->base_addr,
+ SF_DMA_MODE, SF_DMA_MODE);
tc = SF_DMA_MODE;
priv->tx_coe = HW_CSUM;
} else {
/* Checksum computation is performed in software. */
- priv->mac_type->ops->dma_mode(priv->dev->base_addr, tc,
- SF_DMA_MODE);
+ priv->hw->dma->dma_mode(priv->dev->base_addr, tc,
+ SF_DMA_MODE);
priv->tx_coe = NO_HW_CSUM;
}
}
@@ -649,88 +601,6 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
return;
}
-#ifdef STMMAC_DEBUG
-/**
- * show_tx_process_state
- * @status: tx descriptor status field
- * Description: it shows the Transmit Process State for CSR5[22:20]
- */
-static void show_tx_process_state(unsigned int status)
-{
- unsigned int state;
- state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT;
-
- switch (state) {
- case 0:
- pr_info("- TX (Stopped): Reset or Stop command\n");
- break;
- case 1:
- pr_info("- TX (Running):Fetching the Tx desc\n");
- break;
- case 2:
- pr_info("- TX (Running): Waiting for end of tx\n");
- break;
- case 3:
- pr_info("- TX (Running): Reading the data "
- "and queuing the data into the Tx buf\n");
- break;
- case 6:
- pr_info("- TX (Suspended): Tx Buff Underflow "
- "or an unavailable Transmit descriptor\n");
- break;
- case 7:
- pr_info("- TX (Running): Closing Tx descriptor\n");
- break;
- default:
- break;
- }
- return;
-}
-
-/**
- * show_rx_process_state
- * @status: rx descriptor status field
- * Description: it shows the Receive Process State for CSR5[19:17]
- */
-static void show_rx_process_state(unsigned int status)
-{
- unsigned int state;
- state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT;
-
- switch (state) {
- case 0:
- pr_info("- RX (Stopped): Reset or Stop command\n");
- break;
- case 1:
- pr_info("- RX (Running): Fetching the Rx desc\n");
- break;
- case 2:
- pr_info("- RX (Running):Checking for end of pkt\n");
- break;
- case 3:
- pr_info("- RX (Running): Waiting for Rx pkt\n");
- break;
- case 4:
- pr_info("- RX (Suspended): Unavailable Rx buf\n");
- break;
- case 5:
- pr_info("- RX (Running): Closing Rx descriptor\n");
- break;
- case 6:
- pr_info("- RX(Running): Flushing the current frame"
- " from the Rx buf\n");
- break;
- case 7:
- pr_info("- RX (Running): Queuing the Rx frame"
- " from the Rx buf into memory\n");
- break;
- default:
- break;
- }
- return;
-}
-#endif
-
/**
* stmmac_tx:
* @priv: private driver structure
@@ -748,16 +618,16 @@ static void stmmac_tx(struct stmmac_priv *priv)
struct dma_desc *p = priv->dma_tx + entry;
/* Check if the descriptor is owned by the DMA. */
- if (priv->mac_type->ops->get_tx_owner(p))
+ if (priv->hw->desc->get_tx_owner(p))
break;
/* Verify tx error by looking at the last segment */
- last = priv->mac_type->ops->get_tx_ls(p);
+ last = priv->hw->desc->get_tx_ls(p);
if (likely(last)) {
int tx_error =
- priv->mac_type->ops->tx_status(&priv->dev->stats,
- &priv->xstats,
- p, ioaddr);
+ priv->hw->desc->tx_status(&priv->dev->stats,
+ &priv->xstats, p,
+ ioaddr);
if (likely(tx_error == 0)) {
priv->dev->stats.tx_packets++;
priv->xstats.tx_pkt_n++;
@@ -769,7 +639,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
if (likely(p->des2))
dma_unmap_single(priv->device, p->des2,
- priv->mac_type->ops->get_tx_len(p),
+ priv->hw->desc->get_tx_len(p),
DMA_TO_DEVICE);
if (unlikely(p->des3))
p->des3 = 0;
@@ -790,7 +660,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
priv->tx_skbuff[entry] = NULL;
}
- priv->mac_type->ops->release_tx_desc(p);
+ priv->hw->desc->release_tx_desc(p);
entry = (++priv->dirty_tx) % txsize;
}
@@ -814,7 +684,7 @@ static inline void stmmac_enable_irq(struct stmmac_priv *priv)
priv->tm->timer_start(tmrate);
else
#endif
- writel(DMA_INTR_DEFAULT_MASK, priv->dev->base_addr + DMA_INTR_ENA);
+ priv->hw->dma->enable_dma_irq(priv->dev->base_addr);
}
static inline void stmmac_disable_irq(struct stmmac_priv *priv)
@@ -824,7 +694,7 @@ static inline void stmmac_disable_irq(struct stmmac_priv *priv)
priv->tm->timer_stop();
else
#endif
- writel(0, priv->dev->base_addr + DMA_INTR_ENA);
+ priv->hw->dma->disable_dma_irq(priv->dev->base_addr);
}
static int stmmac_has_work(struct stmmac_priv *priv)
@@ -832,7 +702,7 @@ static int stmmac_has_work(struct stmmac_priv *priv)
unsigned int has_work = 0;
int rxret, tx_work = 0;
- rxret = priv->mac_type->ops->get_rx_owner(priv->dma_rx +
+ rxret = priv->hw->desc->get_rx_owner(priv->dma_rx +
(priv->cur_rx % priv->dma_rx_size));
if (priv->dirty_tx != priv->cur_tx)
@@ -883,12 +753,12 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
{
netif_stop_queue(priv->dev);
- stmmac_dma_stop_tx(priv->dev->base_addr);
+ priv->hw->dma->stop_tx(priv->dev->base_addr);
dma_free_tx_skbufs(priv);
- priv->mac_type->ops->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
+ priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
priv->dirty_tx = 0;
priv->cur_tx = 0;
- stmmac_dma_start_tx(priv->dev->base_addr);
+ priv->hw->dma->start_tx(priv->dev->base_addr);
priv->dev->stats.tx_errors++;
netif_wake_queue(priv->dev);
@@ -896,95 +766,27 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
return;
}
-/**
- * stmmac_dma_interrupt - Interrupt handler for the driver
- * @dev: net device structure
- * Description: Interrupt handler for the driver (DMA).
- */
-static void stmmac_dma_interrupt(struct net_device *dev)
-{
- unsigned long ioaddr = dev->base_addr;
- struct stmmac_priv *priv = netdev_priv(dev);
- /* read the status register (CSR5) */
- u32 intr_status = readl(ioaddr + DMA_STATUS);
-
- DBG(intr, INFO, "%s: [CSR5: 0x%08x]\n", __func__, intr_status);
-#ifdef STMMAC_DEBUG
- /* It displays the DMA transmit process state (CSR5 register) */
- if (netif_msg_tx_done(priv))
- show_tx_process_state(intr_status);
- if (netif_msg_rx_status(priv))
- show_rx_process_state(intr_status);
-#endif
- /* ABNORMAL interrupts */
- if (unlikely(intr_status & DMA_STATUS_AIS)) {
- DBG(intr, INFO, "CSR5[15] DMA ABNORMAL IRQ: ");
- if (unlikely(intr_status & DMA_STATUS_UNF)) {
- DBG(intr, INFO, "transmit underflow\n");
- if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) {
- /* Try to bump up the threshold */
- tc += 64;
- priv->mac_type->ops->dma_mode(ioaddr, tc,
- SF_DMA_MODE);
- priv->xstats.threshold = tc;
- }
- stmmac_tx_err(priv);
- priv->xstats.tx_undeflow_irq++;
- }
- if (unlikely(intr_status & DMA_STATUS_TJT)) {
- DBG(intr, INFO, "transmit jabber\n");
- priv->xstats.tx_jabber_irq++;
- }
- if (unlikely(intr_status & DMA_STATUS_OVF)) {
- DBG(intr, INFO, "recv overflow\n");
- priv->xstats.rx_overflow_irq++;
- }
- if (unlikely(intr_status & DMA_STATUS_RU)) {
- DBG(intr, INFO, "receive buffer unavailable\n");
- priv->xstats.rx_buf_unav_irq++;
- }
- if (unlikely(intr_status & DMA_STATUS_RPS)) {
- DBG(intr, INFO, "receive process stopped\n");
- priv->xstats.rx_process_stopped_irq++;
- }
- if (unlikely(intr_status & DMA_STATUS_RWT)) {
- DBG(intr, INFO, "receive watchdog\n");
- priv->xstats.rx_watchdog_irq++;
- }
- if (unlikely(intr_status & DMA_STATUS_ETI)) {
- DBG(intr, INFO, "transmit early interrupt\n");
- priv->xstats.tx_early_irq++;
- }
- if (unlikely(intr_status & DMA_STATUS_TPS)) {
- DBG(intr, INFO, "transmit process stopped\n");
- priv->xstats.tx_process_stopped_irq++;
- stmmac_tx_err(priv);
- }
- if (unlikely(intr_status & DMA_STATUS_FBI)) {
- DBG(intr, INFO, "fatal bus error\n");
- priv->xstats.fatal_bus_error_irq++;
- stmmac_tx_err(priv);
+static void stmmac_dma_interrupt(struct stmmac_priv *priv)
+{
+ unsigned long ioaddr = priv->dev->base_addr;
+ int status;
+
+ status = priv->hw->dma->dma_interrupt(priv->dev->base_addr,
+ &priv->xstats);
+ if (likely(status == handle_tx_rx))
+ _stmmac_schedule(priv);
+
+ else if (unlikely(status == tx_hard_error_bump_tc)) {
+ /* Try to bump up the dma threshold on this failure */
+ if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) {
+ tc += 64;
+ priv->hw->dma->dma_mode(ioaddr, tc, SF_DMA_MODE);
+ priv->xstats.threshold = tc;
}
- }
-
- /* TX/RX NORMAL interrupts */
- if (intr_status & DMA_STATUS_NIS) {
- priv->xstats.normal_irq_n++;
- if (likely((intr_status & DMA_STATUS_RI) ||
- (intr_status & (DMA_STATUS_TI))))
- _stmmac_schedule(priv);
- }
-
- /* Optional hardware blocks, interrupts should be disabled */
- if (unlikely(intr_status &
- (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
- pr_info("%s: unexpected status %08x\n", __func__, intr_status);
-
- /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
- writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
-
- DBG(intr, INFO, "\n\n");
+ stmmac_tx_err(priv);
+ } else if (unlikely(status == tx_hard_error))
+ stmmac_tx_err(priv);
return;
}
@@ -1058,17 +860,20 @@ static int stmmac_open(struct net_device *dev)
init_dma_desc_rings(dev);
/* DMA initialization and SW reset */
- if (unlikely(priv->mac_type->ops->dma_init(ioaddr,
- priv->pbl, priv->dma_tx_phy, priv->dma_rx_phy) < 0)) {
+ if (unlikely(priv->hw->dma->init(ioaddr, priv->pbl, priv->dma_tx_phy,
+ priv->dma_rx_phy) < 0)) {
pr_err("%s: DMA initialization failed\n", __func__);
return -1;
}
/* Copy the MAC addr into the HW */
- priv->mac_type->ops->set_umac_addr(ioaddr, dev->dev_addr, 0);
+ priv->hw->mac->set_umac_addr(ioaddr, dev->dev_addr, 0);
+ /* If required, perform hw setup of the bus. */
+ if (priv->bus_setup)
+ priv->bus_setup(ioaddr);
/* Initialize the MAC Core */
- priv->mac_type->ops->core_init(ioaddr);
+ priv->hw->mac->core_init(ioaddr);
priv->shutdown = 0;
@@ -1089,16 +894,16 @@ static int stmmac_open(struct net_device *dev)
/* Start the ball rolling... */
DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name);
- stmmac_dma_start_tx(ioaddr);
- stmmac_dma_start_rx(ioaddr);
+ priv->hw->dma->start_tx(ioaddr);
+ priv->hw->dma->start_rx(ioaddr);
#ifdef CONFIG_STMMAC_TIMER
priv->tm->timer_start(tmrate);
#endif
/* Dump DMA/MAC registers */
if (netif_msg_hw(priv)) {
- priv->mac_type->ops->dump_mac_regs(ioaddr);
- priv->mac_type->ops->dump_dma_regs(ioaddr);
+ priv->hw->mac->dump_regs(ioaddr);
+ priv->hw->dma->dump_regs(ioaddr);
}
if (priv->phydev)
@@ -1142,8 +947,8 @@ static int stmmac_release(struct net_device *dev)
free_irq(dev->irq, dev);
/* Stop TX/RX DMA and clear the descriptors */
- stmmac_dma_stop_tx(dev->base_addr);
- stmmac_dma_stop_rx(dev->base_addr);
+ priv->hw->dma->stop_tx(dev->base_addr);
+ priv->hw->dma->stop_rx(dev->base_addr);
/* Release and free the Rx/Tx resources */
free_dma_desc_resources(priv);
@@ -1214,8 +1019,8 @@ static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb,
desc->des2 = dma_map_single(priv->device, skb->data,
BUF_SIZE_8KiB, DMA_TO_DEVICE);
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
- priv->mac_type->ops->prepare_tx_desc(desc, 1, BUF_SIZE_8KiB,
- csum_insertion);
+ priv->hw->desc->prepare_tx_desc(desc, 1, BUF_SIZE_8KiB,
+ csum_insertion);
entry = (++priv->cur_tx) % txsize;
desc = priv->dma_tx + entry;
@@ -1224,16 +1029,16 @@ static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb,
skb->data + BUF_SIZE_8KiB,
buf2_size, DMA_TO_DEVICE);
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
- priv->mac_type->ops->prepare_tx_desc(desc, 0,
- buf2_size, csum_insertion);
- priv->mac_type->ops->set_tx_owner(desc);
+ priv->hw->desc->prepare_tx_desc(desc, 0, buf2_size,
+ csum_insertion);
+ priv->hw->desc->set_tx_owner(desc);
priv->tx_skbuff[entry] = NULL;
} else {
desc->des2 = dma_map_single(priv->device, skb->data,
nopaged_len, DMA_TO_DEVICE);
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
- priv->mac_type->ops->prepare_tx_desc(desc, 1, nopaged_len,
- csum_insertion);
+ priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
+ csum_insertion);
}
return entry;
}
@@ -1301,8 +1106,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned int nopaged_len = skb_headlen(skb);
desc->des2 = dma_map_single(priv->device, skb->data,
nopaged_len, DMA_TO_DEVICE);
- priv->mac_type->ops->prepare_tx_desc(desc, 1, nopaged_len,
- csum_insertion);
+ priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
+ csum_insertion);
}
for (i = 0; i < nfrags; i++) {
@@ -1317,21 +1122,20 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
frag->page_offset,
len, DMA_TO_DEVICE);
priv->tx_skbuff[entry] = NULL;
- priv->mac_type->ops->prepare_tx_desc(desc, 0, len,
- csum_insertion);
- priv->mac_type->ops->set_tx_owner(desc);
+ priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion);
+ priv->hw->desc->set_tx_owner(desc);
}
/* Interrupt on completition only for the latest segment */
- priv->mac_type->ops->close_tx_desc(desc);
+ priv->hw->desc->close_tx_desc(desc);
#ifdef CONFIG_STMMAC_TIMER
/* Clean IC while using timer */
if (likely(priv->tm->enable))
- priv->mac_type->ops->clear_tx_ic(desc);
+ priv->hw->desc->clear_tx_ic(desc);
#endif
/* To avoid raise condition */
- priv->mac_type->ops->set_tx_owner(first);
+ priv->hw->desc->set_tx_owner(first);
priv->cur_tx++;
@@ -1353,8 +1157,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
- /* CSR1 enables the transmit DMA to check for new descriptor */
- writel(1, dev->base_addr + DMA_XMT_POLL_DEMAND);
+ priv->hw->dma->enable_dma_transmission(dev->base_addr);
return NETDEV_TX_OK;
}
@@ -1391,7 +1194,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
}
RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);
}
- priv->mac_type->ops->set_rx_owner(p + entry);
+ priv->hw->desc->set_rx_owner(p + entry);
}
return;
}
@@ -1412,7 +1215,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
}
#endif
count = 0;
- while (!priv->mac_type->ops->get_rx_owner(p)) {
+ while (!priv->hw->desc->get_rx_owner(p)) {
int status;
if (count >= limit)
@@ -1425,15 +1228,14 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
prefetch(p_next);
/* read the status of the incoming frame */
- status = (priv->mac_type->ops->rx_status(&priv->dev->stats,
- &priv->xstats, p));
+ status = (priv->hw->desc->rx_status(&priv->dev->stats,
+ &priv->xstats, p));
if (unlikely(status == discard_frame))
priv->dev->stats.rx_errors++;
else {
struct sk_buff *skb;
/* Length should omit the CRC */
- int frame_len =
- priv->mac_type->ops->get_rx_frame_len(p) - 4;
+ int frame_len = priv->hw->desc->get_rx_frame_len(p) - 4;
#ifdef STMMAC_RX_DEBUG
if (frame_len > ETH_FRAME_LEN)
@@ -1569,7 +1371,7 @@ static void stmmac_multicast_list(struct net_device *dev)
struct stmmac_priv *priv = netdev_priv(dev);
spin_lock(&priv->lock);
- priv->mac_type->ops->set_filter(dev);
+ priv->hw->mac->set_filter(dev);
spin_unlock(&priv->lock);
return;
}
@@ -1623,9 +1425,10 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
if (priv->is_gmac) {
unsigned long ioaddr = dev->base_addr;
/* To handle GMAC own interrupts */
- priv->mac_type->ops->host_irq_status(ioaddr);
+ priv->hw->mac->host_irq_status(ioaddr);
}
- stmmac_dma_interrupt(dev);
+
+ stmmac_dma_interrupt(priv);
return IRQ_HANDLED;
}
@@ -1744,7 +1547,7 @@ static int stmmac_probe(struct net_device *dev)
netif_napi_add(dev, &priv->napi, stmmac_poll, 64);
/* Get the MAC address */
- priv->mac_type->ops->get_umac_addr(dev->base_addr, dev->dev_addr, 0);
+ priv->hw->mac->get_umac_addr(dev->base_addr, dev->dev_addr, 0);
if (!is_valid_ether_addr(dev->dev_addr))
pr_warning("\tno valid MAC address;"
@@ -1779,16 +1582,16 @@ static int stmmac_mac_device_setup(struct net_device *dev)
struct mac_device_info *device;
if (priv->is_gmac)
- device = gmac_setup(ioaddr);
+ device = dwmac1000_setup(ioaddr);
else
- device = mac100_setup(ioaddr);
+ device = dwmac100_setup(ioaddr);
if (!device)
return -ENOMEM;
- priv->mac_type = device;
+ priv->hw = device;
- priv->wolenabled = priv->mac_type->hw.pmt; /* PMT supported */
+ priv->wolenabled = priv->hw->pmt; /* PMT supported */
if (priv->wolenabled == PMT_SUPPORTED)
priv->wolopts = WAKE_MAGIC; /* Magic Frame */
@@ -1797,8 +1600,7 @@ static int stmmac_mac_device_setup(struct net_device *dev)
static int stmmacphy_dvr_probe(struct platform_device *pdev)
{
- struct plat_stmmacphy_data *plat_dat;
- plat_dat = (struct plat_stmmacphy_data *)((pdev->dev).platform_data);
+ struct plat_stmmacphy_data *plat_dat = pdev->dev.platform_data;
pr_debug("stmmacphy_dvr_probe: added phy for bus %d\n",
plat_dat->bus_id);
@@ -1830,9 +1632,7 @@ static struct platform_driver stmmacphy_driver = {
static int stmmac_associate_phy(struct device *dev, void *data)
{
struct stmmac_priv *priv = (struct stmmac_priv *)data;
- struct plat_stmmacphy_data *plat_dat;
-
- plat_dat = (struct plat_stmmacphy_data *)(dev->platform_data);
+ struct plat_stmmacphy_data *plat_dat = dev->platform_data;
DBG(probe, DEBUG, "%s: checking phy for bus %d\n", __func__,
plat_dat->bus_id);
@@ -1922,7 +1722,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
priv = netdev_priv(ndev);
priv->device = &(pdev->dev);
priv->dev = ndev;
- plat_dat = (struct plat_stmmacenet_data *)((pdev->dev).platform_data);
+ plat_dat = pdev->dev.platform_data;
priv->bus_id = plat_dat->bus_id;
priv->pbl = plat_dat->pbl; /* TLI */
priv->is_gmac = plat_dat->has_gmac; /* GMAC is on board */
@@ -1932,6 +1732,11 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
/* Set the I/O base addr */
ndev->base_addr = (unsigned long)addr;
+ /* Verify embedded resource for the platform */
+ ret = stmmac_claim_resource(pdev);
+ if (ret < 0)
+ goto out;
+
/* MAC HW revice detection */
ret = stmmac_mac_device_setup(ndev);
if (ret < 0)
@@ -1952,6 +1757,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
}
priv->fix_mac_speed = plat_dat->fix_mac_speed;
+ priv->bus_setup = plat_dat->bus_setup;
priv->bsp_priv = plat_dat->bsp_priv;
pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n"
@@ -1986,12 +1792,13 @@ out:
static int stmmac_dvr_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
+ struct stmmac_priv *priv = netdev_priv(ndev);
struct resource *res;
pr_info("%s:\n\tremoving driver", __func__);
- stmmac_dma_stop_rx(ndev->base_addr);
- stmmac_dma_stop_tx(ndev->base_addr);
+ priv->hw->dma->stop_rx(ndev->base_addr);
+ priv->hw->dma->stop_tx(ndev->base_addr);
stmmac_mac_disable_rx(ndev->base_addr);
stmmac_mac_disable_tx(ndev->base_addr);
@@ -2038,21 +1845,20 @@ static int stmmac_suspend(struct platform_device *pdev, pm_message_t state)
napi_disable(&priv->napi);
/* Stop TX/RX DMA */
- stmmac_dma_stop_tx(dev->base_addr);
- stmmac_dma_stop_rx(dev->base_addr);
+ priv->hw->dma->stop_tx(dev->base_addr);
+ priv->hw->dma->stop_rx(dev->base_addr);
/* Clear the Rx/Tx descriptors */
- priv->mac_type->ops->init_rx_desc(priv->dma_rx,
- priv->dma_rx_size, dis_ic);
- priv->mac_type->ops->init_tx_desc(priv->dma_tx,
- priv->dma_tx_size);
+ priv->hw->desc->init_rx_desc(priv->dma_rx, priv->dma_rx_size,
+ dis_ic);
+ priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
stmmac_mac_disable_tx(dev->base_addr);
if (device_may_wakeup(&(pdev->dev))) {
/* Enable Power down mode by programming the PMT regs */
if (priv->wolenabled == PMT_SUPPORTED)
- priv->mac_type->ops->pmt(dev->base_addr,
- priv->wolopts);
+ priv->hw->mac->pmt(dev->base_addr,
+ priv->wolopts);
} else {
stmmac_mac_disable_rx(dev->base_addr);
}
@@ -2093,15 +1899,15 @@ static int stmmac_resume(struct platform_device *pdev)
* from another devices (e.g. serial console). */
if (device_may_wakeup(&(pdev->dev)))
if (priv->wolenabled == PMT_SUPPORTED)
- priv->mac_type->ops->pmt(dev->base_addr, 0);
+ priv->hw->mac->pmt(dev->base_addr, 0);
netif_device_attach(dev);
/* Enable the MAC and DMA */
stmmac_mac_enable_rx(ioaddr);
stmmac_mac_enable_tx(ioaddr);
- stmmac_dma_start_tx(ioaddr);
- stmmac_dma_start_rx(ioaddr);
+ priv->hw->dma->start_tx(ioaddr);
+ priv->hw->dma->start_rx(ioaddr);
#ifdef CONFIG_STMMAC_TIMER
priv->tm->timer_start(tmrate);
diff --git a/drivers/net/stmmac/stmmac_mdio.c b/drivers/net/stmmac/stmmac_mdio.c
index 8498552a22fc..fffe1d037fe6 100644
--- a/drivers/net/stmmac/stmmac_mdio.c
+++ b/drivers/net/stmmac/stmmac_mdio.c
@@ -24,7 +24,6 @@
Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
-#include <linux/netdevice.h>
#include <linux/mii.h>
#include <linux/phy.h>
@@ -48,8 +47,8 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned long ioaddr = ndev->base_addr;
- unsigned int mii_address = priv->mac_type->hw.mii.addr;
- unsigned int mii_data = priv->mac_type->hw.mii.data;
+ unsigned int mii_address = priv->hw->mii.addr;
+ unsigned int mii_data = priv->hw->mii.data;
int data;
u16 regValue = (((phyaddr << 11) & (0x0000F800)) |
@@ -80,8 +79,8 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned long ioaddr = ndev->base_addr;
- unsigned int mii_address = priv->mac_type->hw.mii.addr;
- unsigned int mii_data = priv->mac_type->hw.mii.data;
+ unsigned int mii_address = priv->hw->mii.addr;
+ unsigned int mii_data = priv->hw->mii.data;
u16 value =
(((phyaddr << 11) & (0x0000F800)) | ((phyreg << 6) & (0x000007C0)))
@@ -112,7 +111,7 @@ static int stmmac_mdio_reset(struct mii_bus *bus)
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned long ioaddr = ndev->base_addr;
- unsigned int mii_address = priv->mac_type->hw.mii.addr;
+ unsigned int mii_address = priv->hw->mii.addr;
if (priv->phy_reset) {
pr_debug("stmmac_mdio_reset: calling phy_reset\n");
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index b447a8719427..2f6a760e5f21 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -413,8 +413,8 @@ static int init586(struct net_device *dev)
volatile struct iasetup_cmd_struct *ias_cmd;
volatile struct tdr_cmd_struct *tdr_cmd;
volatile struct mcsetup_cmd_struct *mc_cmd;
- struct dev_mc_list *dmi=dev->mc_list;
- int num_addrs=dev->mc_count;
+ struct dev_mc_list *dmi;
+ int num_addrs=netdev_mc_count(dev);
ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
@@ -536,8 +536,10 @@ static int init586(struct net_device *dev)
mc_cmd->cmd_link = 0xffff;
mc_cmd->mc_cnt = swab16(num_addrs * 6);
- for(i=0;i<num_addrs;i++,dmi=dmi->next)
- memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr,6);
+ i = 0;
+ netdev_for_each_mc_addr(dmi, dev)
+ memcpy((char *) mc_cmd->mc_list[i++],
+ dmi->dmi_addr, ETH_ALEN);
p->scb->cbl_offset = make16(mc_cmd);
p->scb->cmd_cuc = CUC_START;
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index 0ca4241b4f63..99998862c22e 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -917,7 +917,7 @@ static void set_multicast_list( struct net_device *dev )
REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
} else {
short multicast_table[4];
- int num_addrs = dev->mc_count;
+ int num_addrs = netdev_mc_count(dev);
int i;
/* We don't use the multicast table, but rely on upper-layer
* filtering. */
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 25e81ebd9cd8..a0bd361d5eca 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -999,7 +999,7 @@ static void bigmac_set_multicast(struct net_device *dev)
{
struct bigmac *bp = netdev_priv(dev);
void __iomem *bregs = bp->bregs;
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
char *addrs;
int i;
u32 tmp, crc;
@@ -1013,7 +1013,7 @@ static void bigmac_set_multicast(struct net_device *dev)
while ((sbus_readl(bregs + BMAC_RXCFG) & BIGMAC_RXCFG_ENABLE) != 0)
udelay(20);
- if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+ if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) {
sbus_writel(0xffff, bregs + BMAC_HTABLE0);
sbus_writel(0xffff, bregs + BMAC_HTABLE1);
sbus_writel(0xffff, bregs + BMAC_HTABLE2);
@@ -1028,9 +1028,8 @@ static void bigmac_set_multicast(struct net_device *dev)
for (i = 0; i < 4; i++)
hash_table[i] = 0;
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
addrs = dmi->dmi_addr;
- dmi = dmi->next;
if (!(*addrs & 1))
continue;
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index d58e1891ca60..a855934dfc3b 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -206,7 +206,7 @@ IVc. Errata
#define USE_IO_OPS 1
#endif
-static const struct pci_device_id sundance_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(sundance_pci_tbl) = {
{ 0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0 },
{ 0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1 },
{ 0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2 },
@@ -1517,19 +1517,18 @@ static void set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
memset(mc_filter, 0xff, sizeof(mc_filter));
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys;
- } else if ((dev->mc_count > multicast_filter_limit) ||
+ } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
(dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
memset(mc_filter, 0xff, sizeof(mc_filter));
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
- } else if (dev->mc_count) {
+ } else if (!netdev_mc_empty(dev)) {
struct dev_mc_list *mclist;
int bit;
int index;
int crc;
memset (mc_filter, 0, sizeof (mc_filter));
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
for (index=0, bit=0; bit < 6; bit++, crc <<= 1)
if (crc & 0x80000000) index |= 1 << bit;
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index b571a1babab9..70196bc5fe61 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -107,7 +107,7 @@ MODULE_LICENSE("GPL");
#define GEM_MODULE_NAME "gem"
#define PFX GEM_MODULE_NAME ": "
-static struct pci_device_id gem_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(gem_pci_tbl) = {
{ PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_GEM,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
@@ -782,7 +782,7 @@ static int gem_rx(struct gem *gp, int work_to_do)
break;
/* When writing back RX descriptor, GEM writes status
- * then buffer address, possibly in seperate transactions.
+ * then buffer address, possibly in separate transactions.
* If we don't wait for the chip to write both, we could
* post a new buffer to this descriptor then have GEM spam
* on the buffer address. We sync on the RX completion
@@ -1837,7 +1837,7 @@ static u32 gem_setup_multicast(struct gem *gp)
int i;
if ((gp->dev->flags & IFF_ALLMULTI) ||
- (gp->dev->mc_count > 256)) {
+ (netdev_mc_count(gp->dev) > 256)) {
for (i=0; i<16; i++)
writel(0xffff, gp->regs + MAC_HASH0 + (i << 2));
rxcfg |= MAC_RXCFG_HFE;
@@ -1846,17 +1846,13 @@ static u32 gem_setup_multicast(struct gem *gp)
} else {
u16 hash_table[16];
u32 crc;
- struct dev_mc_list *dmi = gp->dev->mc_list;
+ struct dev_mc_list *dmi;
int i;
- for (i = 0; i < 16; i++)
- hash_table[i] = 0;
-
- for (i = 0; i < gp->dev->mc_count; i++) {
+ memset(hash_table, 0, sizeof(hash_table));
+ netdev_for_each_mc_addr(dmi, gp->dev) {
char *addrs = dmi->dmi_addr;
- dmi = dmi->next;
-
if (!(*addrs & 1))
continue;
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 6762f1c6ec8a..b17dbb11bd67 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1516,24 +1516,20 @@ static int happy_meal_init(struct happy_meal *hp)
HMD(("htable, "));
if ((hp->dev->flags & IFF_ALLMULTI) ||
- (hp->dev->mc_count > 64)) {
+ (netdev_mc_count(hp->dev) > 64)) {
hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff);
hme_write32(hp, bregs + BMAC_HTABLE1, 0xffff);
hme_write32(hp, bregs + BMAC_HTABLE2, 0xffff);
hme_write32(hp, bregs + BMAC_HTABLE3, 0xffff);
} else if ((hp->dev->flags & IFF_PROMISC) == 0) {
u16 hash_table[4];
- struct dev_mc_list *dmi = hp->dev->mc_list;
+ struct dev_mc_list *dmi;
char *addrs;
- int i;
u32 crc;
- for (i = 0; i < 4; i++)
- hash_table[i] = 0;
-
- for (i = 0; i < hp->dev->mc_count; i++) {
+ memset(hash_table, 0, sizeof(hash_table));
+ netdev_for_each_mc_addr(dmi, hp->dev) {
addrs = dmi->dmi_addr;
- dmi = dmi->next;
if (!(*addrs & 1))
continue;
@@ -2366,14 +2362,13 @@ static void happy_meal_set_multicast(struct net_device *dev)
{
struct happy_meal *hp = netdev_priv(dev);
void __iomem *bregs = hp->bigmacregs;
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
char *addrs;
- int i;
u32 crc;
spin_lock_irq(&hp->happy_lock);
- if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+ if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) {
hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff);
hme_write32(hp, bregs + BMAC_HTABLE1, 0xffff);
hme_write32(hp, bregs + BMAC_HTABLE2, 0xffff);
@@ -2384,12 +2379,9 @@ static void happy_meal_set_multicast(struct net_device *dev)
} else {
u16 hash_table[4];
- for (i = 0; i < 4; i++)
- hash_table[i] = 0;
-
- for (i = 0; i < dev->mc_count; i++) {
+ memset(hash_table, 0, sizeof(hash_table));
+ netdev_for_each_mc_addr(dmi, dev) {
addrs = dmi->dmi_addr;
- dmi = dmi->next;
if (!(*addrs & 1))
continue;
@@ -3211,7 +3203,7 @@ static void __devexit happy_meal_pci_remove(struct pci_dev *pdev)
dev_set_drvdata(&pdev->dev, NULL);
}
-static struct pci_device_id happymeal_pci_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(happymeal_pci_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_HAPPYMEAL) },
{ } /* Terminating entry */
};
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 64e7d08c878f..d7c73f478ef5 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1170,9 +1170,8 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
static void lance_load_multicast(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
char *addrs;
- int i;
u32 crc;
u32 val;
@@ -1196,9 +1195,8 @@ static void lance_load_multicast(struct net_device *dev)
return;
/* Add addresses */
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(dmi, dev) {
addrs = dmi->dmi_addr;
- dmi = dmi->next;
/* multicast address? */
if (!(*addrs & 1))
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index 45c383f285ee..be637dce944c 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -627,7 +627,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
static void qe_set_multicast(struct net_device *dev)
{
struct sunqe *qep = netdev_priv(dev);
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
u8 new_mconfig = qep->mconfig;
char *addrs;
int i;
@@ -636,7 +636,7 @@ static void qe_set_multicast(struct net_device *dev)
/* Lock out others. */
netif_stop_queue(dev);
- if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+ if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) {
sbus_writeb(MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_LARESET,
qep->mregs + MREGS_IACONFIG);
while ((sbus_readb(qep->mregs + MREGS_IACONFIG) & MREGS_IACONFIG_ACHNGE) != 0)
@@ -650,12 +650,9 @@ static void qe_set_multicast(struct net_device *dev)
u16 hash_table[4];
u8 *hbytes = (unsigned char *) &hash_table[0];
- for (i = 0; i < 4; i++)
- hash_table[i] = 0;
-
- for (i = 0; i < dev->mc_count; i++) {
+ memset(hash_table, 0, sizeof(hash_table));
+ netdev_for_each_mc_addr(dmi, dev) {
addrs = dmi->dmi_addr;
- dmi = dmi->next;
if (!(*addrs & 1))
continue;
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index bc74db0d12f3..6b1b7cea7f6b 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -765,7 +765,7 @@ static void __update_mc_list(struct vnet *vp, struct net_device *dev)
{
struct dev_addr_list *p;
- for (p = dev->mc_list; p; p = p->next) {
+ netdev_for_each_mc_addr(p, dev) {
struct vnet_mcast_entry *m;
m = __vnet_mc_find(vp, p->dmi_addr);
@@ -1062,10 +1062,7 @@ static struct vnet * __devinit vnet_new(const u64 *local_mac)
goto err_out_free_dev;
}
- printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
-
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+ printk(KERN_INFO "%s: Sun LDOM vnet %pM\n", dev->name, dev->dev_addr);
list_add(&vp->list, &vnet_list);
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 75a669d48e5e..49bd84c0d583 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -65,7 +65,7 @@ static const struct {
{ "TOSHIBA TC35815/TX4939" },
};
-static const struct pci_device_id tc35815_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(tc35815_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF },
{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU },
{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 },
@@ -402,6 +402,7 @@ struct tc35815_local {
* by this lock as well.
*/
spinlock_t lock;
+ spinlock_t rx_lock;
struct mii_bus *mii_bus;
struct phy_device *phy_dev;
@@ -835,6 +836,7 @@ static int __devinit tc35815_init_one(struct pci_dev *pdev,
INIT_WORK(&lp->restart_work, tc35815_restart_work);
spin_lock_init(&lp->lock);
+ spin_lock_init(&lp->rx_lock);
lp->pci_dev = pdev;
lp->chiptype = ent->driver_data;
@@ -1186,6 +1188,7 @@ static void tc35815_restart(struct net_device *dev)
printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name);
}
+ spin_lock_bh(&lp->rx_lock);
spin_lock_irq(&lp->lock);
tc35815_chip_reset(dev);
tc35815_clear_queues(dev);
@@ -1193,6 +1196,7 @@ static void tc35815_restart(struct net_device *dev)
/* Reconfigure CAM again since tc35815_chip_init() initialize it. */
tc35815_set_multicast_list(dev);
spin_unlock_irq(&lp->lock);
+ spin_unlock_bh(&lp->rx_lock);
netif_wake_queue(dev);
}
@@ -1211,11 +1215,14 @@ static void tc35815_schedule_restart(struct net_device *dev)
struct tc35815_local *lp = netdev_priv(dev);
struct tc35815_regs __iomem *tr =
(struct tc35815_regs __iomem *)dev->base_addr;
+ unsigned long flags;
/* disable interrupts */
+ spin_lock_irqsave(&lp->lock, flags);
tc_writel(0, &tr->Int_En);
tc_writel(tc_readl(&tr->DMA_Ctl) | DMA_IntMask, &tr->DMA_Ctl);
schedule_work(&lp->restart_work);
+ spin_unlock_irqrestore(&lp->lock, flags);
}
static void tc35815_tx_timeout(struct net_device *dev)
@@ -1436,8 +1443,9 @@ static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit)
if (status & Int_IntMacTx) {
/* Transmit complete. */
lp->lstats.tx_ints++;
+ spin_lock_irq(&lp->lock);
tc35815_txdone(dev);
- netif_wake_queue(dev);
+ spin_unlock_irq(&lp->lock);
if (ret < 0)
ret = 0;
}
@@ -1650,7 +1658,7 @@ static int tc35815_poll(struct napi_struct *napi, int budget)
int received = 0, handled;
u32 status;
- spin_lock(&lp->lock);
+ spin_lock(&lp->rx_lock);
status = tc_readl(&tr->Int_Src);
do {
/* BLEx, FDAEx will be cleared later */
@@ -1668,7 +1676,7 @@ static int tc35815_poll(struct napi_struct *napi, int budget)
}
status = tc_readl(&tr->Int_Src);
} while (status);
- spin_unlock(&lp->lock);
+ spin_unlock(&lp->rx_lock);
if (received < budget) {
napi_complete(napi);
@@ -1941,23 +1949,23 @@ tc35815_set_multicast_list(struct net_device *dev)
/* Enable promiscuous mode */
tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);
} else if ((dev->flags & IFF_ALLMULTI) ||
- dev->mc_count > CAM_ENTRY_MAX - 3) {
+ netdev_mc_count(dev) > CAM_ENTRY_MAX - 3) {
/* CAM 0, 1, 20 are reserved. */
/* Disable promiscuous mode, use normal mode. */
tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl);
- } else if (dev->mc_count) {
- struct dev_mc_list *cur_addr = dev->mc_list;
+ } else if (!netdev_mc_empty(dev)) {
+ struct dev_mc_list *cur_addr;
int i;
int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE);
tc_writel(0, &tr->CAM_Ctl);
/* Walk the address list, and load the filter */
- for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) {
- if (!cur_addr)
- break;
+ i = 0;
+ netdev_for_each_mc_addr(cur_addr, dev) {
/* entry 0,1 is reserved. */
tc35815_set_cam_entry(dev, i + 2, cur_addr->dmi_addr);
ena_bits |= CAM_Ena_Bit(i + 2);
+ i++;
}
tc_writel(ena_bits, &tr->CAM_Ena);
tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index 80b404f2b938..f5493092521a 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -62,9 +62,11 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "tehuti.h"
-static struct pci_device_id __devinitdata bdx_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(bdx_pci_tbl) = {
{0x1FC9, 0x3009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x1FC9, 0x3010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x1FC9, 0x3014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -105,26 +107,24 @@ static void print_hw_id(struct pci_dev *pdev)
pci_read_config_word(pdev, PCI_LINK_STATUS_REG, &pci_link_status);
pci_read_config_word(pdev, PCI_DEV_CTRL_REG, &pci_ctrl);
- printk(KERN_INFO "tehuti: %s%s\n", BDX_NIC_NAME,
- nic->port_num == 1 ? "" : ", 2-Port");
- printk(KERN_INFO
- "tehuti: srom 0x%x fpga %d build %u lane# %d"
- " max_pl 0x%x mrrs 0x%x\n",
- readl(nic->regs + SROM_VER), readl(nic->regs + FPGA_VER) & 0xFFF,
- readl(nic->regs + FPGA_SEED),
- GET_LINK_STATUS_LANES(pci_link_status),
- GET_DEV_CTRL_MAXPL(pci_ctrl), GET_DEV_CTRL_MRRS(pci_ctrl));
+ pr_info("%s%s\n", BDX_NIC_NAME,
+ nic->port_num == 1 ? "" : ", 2-Port");
+ pr_info("srom 0x%x fpga %d build %u lane# %d max_pl 0x%x mrrs 0x%x\n",
+ readl(nic->regs + SROM_VER), readl(nic->regs + FPGA_VER) & 0xFFF,
+ readl(nic->regs + FPGA_SEED),
+ GET_LINK_STATUS_LANES(pci_link_status),
+ GET_DEV_CTRL_MAXPL(pci_ctrl), GET_DEV_CTRL_MRRS(pci_ctrl));
}
static void print_fw_id(struct pci_nic *nic)
{
- printk(KERN_INFO "tehuti: fw 0x%x\n", readl(nic->regs + FW_VER));
+ pr_info("fw 0x%x\n", readl(nic->regs + FW_VER));
}
static void print_eth_id(struct net_device *ndev)
{
- printk(KERN_INFO "%s: %s, Port %c\n", ndev->name, BDX_NIC_NAME,
- (ndev->if_port == 0) ? 'A' : 'B');
+ netdev_info(ndev, "%s, Port %c\n",
+ BDX_NIC_NAME, (ndev->if_port == 0) ? 'A' : 'B');
}
@@ -160,7 +160,7 @@ bdx_fifo_init(struct bdx_priv *priv, struct fifo *f, int fsz_type,
f->va = pci_alloc_consistent(priv->pdev,
memsz + FIFO_EXTRA_SPACE, &f->da);
if (!f->va) {
- ERR("pci_alloc_consistent failed\n");
+ pr_err("pci_alloc_consistent failed\n");
RET(-ENOMEM);
}
f->reg_CFG0 = reg_CFG0;
@@ -204,13 +204,13 @@ static void bdx_link_changed(struct bdx_priv *priv)
if (netif_carrier_ok(priv->ndev)) {
netif_stop_queue(priv->ndev);
netif_carrier_off(priv->ndev);
- ERR("%s: Link Down\n", priv->ndev->name);
+ netdev_err(priv->ndev, "Link Down\n");
}
} else {
if (!netif_carrier_ok(priv->ndev)) {
netif_wake_queue(priv->ndev);
netif_carrier_on(priv->ndev);
- ERR("%s: Link Up\n", priv->ndev->name);
+ netdev_err(priv->ndev, "Link Up\n");
}
}
}
@@ -226,10 +226,10 @@ static void bdx_isr_extra(struct bdx_priv *priv, u32 isr)
bdx_link_changed(priv);
if (isr & IR_PCIE_LINK)
- ERR("%s: PCI-E Link Fault\n", priv->ndev->name);
+ netdev_err(priv->ndev, "PCI-E Link Fault\n");
if (isr & IR_PCIE_TOUT)
- ERR("%s: PCI-E Time Out\n", priv->ndev->name);
+ netdev_err(priv->ndev, "PCI-E Time Out\n");
}
@@ -345,7 +345,7 @@ out:
release_firmware(fw);
if (rc) {
- ERR("%s: firmware loading failed\n", priv->ndev->name);
+ netdev_err(priv->ndev, "firmware loading failed\n");
if (rc == -EIO)
DBG("VPC = 0x%x VIC = 0x%x INIT_STATUS = 0x%x i=%d\n",
READ_REG(priv, regVPC),
@@ -419,9 +419,11 @@ static int bdx_hw_start(struct bdx_priv *priv)
WRITE_REG(priv, regGMAC_RXF_A, GMAC_RX_FILTER_OSEN |
GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB);
-#define BDX_IRQ_TYPE ((priv->nic->irq_type == IRQ_MSI)?0:IRQF_SHARED)
- if ((rc = request_irq(priv->pdev->irq, bdx_isr_napi, BDX_IRQ_TYPE,
- ndev->name, ndev)))
+#define BDX_IRQ_TYPE ((priv->nic->irq_type == IRQ_MSI) ? 0 : IRQF_SHARED)
+
+ rc = request_irq(priv->pdev->irq, bdx_isr_napi, BDX_IRQ_TYPE,
+ ndev->name, ndev);
+ if (rc)
goto err_irq;
bdx_enable_interrupts(priv);
@@ -462,7 +464,7 @@ static int bdx_hw_reset_direct(void __iomem *regs)
readl(regs + regRXD_CFG0_0);
return 0;
}
- ERR("tehuti: HW reset failed\n");
+ pr_err("HW reset failed\n");
return 1; /* failure */
}
@@ -486,7 +488,7 @@ static int bdx_hw_reset(struct bdx_priv *priv)
READ_REG(priv, regRXD_CFG0_0);
return 0;
}
- ERR("tehuti: HW reset failed\n");
+ pr_err("HW reset failed\n");
return 1; /* failure */
}
@@ -510,8 +512,7 @@ static int bdx_sw_reset(struct bdx_priv *priv)
mdelay(10);
}
if (i == 50)
- ERR("%s: SW reset timeout. continuing anyway\n",
- priv->ndev->name);
+ netdev_err(priv->ndev, "SW reset timeout. continuing anyway\n");
/* 6. disable intrs */
WRITE_REG(priv, regRDINTCM0, 0);
@@ -604,18 +605,15 @@ static int bdx_open(struct net_device *ndev)
if (netif_running(ndev))
netif_stop_queue(priv->ndev);
- if ((rc = bdx_tx_init(priv)))
- goto err;
-
- if ((rc = bdx_rx_init(priv)))
- goto err;
-
- if ((rc = bdx_fw_load(priv)))
+ if ((rc = bdx_tx_init(priv)) ||
+ (rc = bdx_rx_init(priv)) ||
+ (rc = bdx_fw_load(priv)))
goto err;
bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0);
- if ((rc = bdx_hw_start(priv)))
+ rc = bdx_hw_start(priv);
+ if (rc)
goto err;
napi_enable(&priv->napi);
@@ -647,7 +645,7 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd)
if (cmd != SIOCDEVPRIVATE) {
error = copy_from_user(data, ifr->ifr_data, sizeof(data));
if (error) {
- ERR("cant copy from user\n");
+ pr_err("cant copy from user\n");
RET(error);
}
DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]);
@@ -708,7 +706,7 @@ static void __bdx_vlan_rx_vid(struct net_device *ndev, uint16_t vid, int enable)
ENTER;
DBG2("vid=%d value=%d\n", (int)vid, enable);
if (unlikely(vid >= 4096)) {
- ERR("tehuti: invalid VID: %u (> 4096)\n", vid);
+ pr_err("invalid VID: %u (> 4096)\n", vid);
RET();
}
reg = regVLAN_0 + (vid / 32) * 4;
@@ -776,8 +774,8 @@ static int bdx_change_mtu(struct net_device *ndev, int new_mtu)
/* enforce minimum frame size */
if (new_mtu < ETH_ZLEN) {
- ERR("%s: %s mtu %d is less then minimal %d\n",
- BDX_DRV_NAME, ndev->name, new_mtu, ETH_ZLEN);
+ netdev_err(ndev, "mtu %d is less then minimal %d\n",
+ new_mtu, ETH_ZLEN);
RET(-EINVAL);
}
@@ -808,7 +806,7 @@ static void bdx_setmulti(struct net_device *ndev)
/* set IMF to accept all multicast frmaes */
for (i = 0; i < MAC_MCST_HASH_NUM; i++)
WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, ~0);
- } else if (ndev->mc_count) {
+ } else if (!netdev_mc_empty(ndev)) {
u8 hash;
struct dev_mc_list *mclist;
u32 reg, val;
@@ -826,10 +824,8 @@ static void bdx_setmulti(struct net_device *ndev)
/* TBD: sort addreses and write them in ascending order
* into RX_MAC_MCST regs. we skip this phase now and accept ALL
* multicast frames throu IMF */
- mclist = ndev->mc_list;
-
/* accept the rest of addresses throu IMF */
- for (; mclist; mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, ndev) {
hash = 0;
for (i = 0; i < ETH_ALEN; i++)
hash ^= mclist->dmi_addr[i];
@@ -840,7 +836,7 @@ static void bdx_setmulti(struct net_device *ndev)
}
} else {
- DBG("only own mac %d\n", ndev->mc_count);
+ DBG("only own mac %d\n", netdev_mc_count(ndev));
rxf_val |= GMAC_RX_FILTER_AB;
}
WRITE_REG(priv, regGMAC_RXF_A, rxf_val);
@@ -1028,17 +1024,16 @@ static int bdx_rx_init(struct bdx_priv *priv)
regRXF_CFG0_0, regRXF_CFG1_0,
regRXF_RPTR_0, regRXF_WPTR_0))
goto err_mem;
- if (!
- (priv->rxdb =
- bdx_rxdb_create(priv->rxf_fifo0.m.memsz /
- sizeof(struct rxf_desc))))
+ priv->rxdb = bdx_rxdb_create(priv->rxf_fifo0.m.memsz /
+ sizeof(struct rxf_desc));
+ if (!priv->rxdb)
goto err_mem;
priv->rxf_fifo0.m.pktsz = priv->ndev->mtu + VLAN_ETH_HLEN;
return 0;
err_mem:
- ERR("%s: %s: Rx init failed\n", BDX_DRV_NAME, priv->ndev->name);
+ netdev_err(priv->ndev, "Rx init failed\n");
return -ENOMEM;
}
@@ -1115,8 +1110,9 @@ static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f)
ENTER;
dno = bdx_rxdb_available(db) - 1;
while (dno > 0) {
- if (!(skb = dev_alloc_skb(f->m.pktsz + NET_IP_ALIGN))) {
- ERR("NO MEM: dev_alloc_skb failed\n");
+ skb = dev_alloc_skb(f->m.pktsz + NET_IP_ALIGN);
+ if (!skb) {
+ pr_err("NO MEM: dev_alloc_skb failed\n");
break;
}
skb->dev = priv->ndev;
@@ -1337,9 +1333,7 @@ static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget)
static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len,
u16 rxd_vlan)
{
- DBG("ERROR: rxdd bc %d rxfq %d to %d type %d err %d rxp %d "
- "pkt_id %d vtag %d len %d vlan_id %d cfi %d prio %d "
- "va_lo %d va_hi %d\n",
+ DBG("ERROR: rxdd bc %d rxfq %d to %d type %d err %d rxp %d pkt_id %d vtag %d len %d vlan_id %d cfi %d prio %d va_lo %d va_hi %d\n",
GET_RXD_BC(rxd_val1), GET_RXD_RXFQ(rxd_val1), GET_RXD_TO(rxd_val1),
GET_RXD_TYPE(rxd_val1), GET_RXD_ERR(rxd_val1),
GET_RXD_RXP(rxd_val1), GET_RXD_PKT_ID(rxd_val1),
@@ -1591,7 +1585,7 @@ static int bdx_tx_init(struct bdx_priv *priv)
return 0;
err_mem:
- ERR("tehuti: %s: Tx init failed\n", priv->ndev->name);
+ netdev_err(priv->ndev, "Tx init failed\n");
return -ENOMEM;
}
@@ -1609,7 +1603,7 @@ static inline int bdx_tx_space(struct bdx_priv *priv)
fsize = f->m.rptr - f->m.wptr;
if (fsize <= 0)
fsize = f->m.memsz + fsize;
- return (fsize);
+ return fsize;
}
/* bdx_tx_transmit - send packet to NIC
@@ -1857,7 +1851,7 @@ static void bdx_tx_push_desc(struct bdx_priv *priv, void *data, int size)
* @data - desc's data
* @size - desc's size
*
- * NOTE: this func does check for available space and, if neccessary, waits for
+ * NOTE: this func does check for available space and, if necessary, waits for
* NIC to read existing data before writing new one.
*/
static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size)
@@ -1937,8 +1931,9 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
RET(-ENOMEM);
/************** pci *****************/
- if ((err = pci_enable_device(pdev))) /* it trigers interrupt, dunno why. */
- goto err_pci; /* it's not a problem though */
+ err = pci_enable_device(pdev);
+ if (err) /* it triggers interrupt, dunno why. */
+ goto err_pci; /* it's not a problem though */
if (!(err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) &&
!(err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))) {
@@ -1946,14 +1941,14 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
} else {
if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) ||
(err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))) {
- printk(KERN_ERR "tehuti: No usable DMA configuration"
- ", aborting\n");
+ pr_err("No usable DMA configuration, aborting\n");
goto err_dma;
}
pci_using_dac = 0;
}
- if ((err = pci_request_regions(pdev, BDX_DRV_NAME)))
+ err = pci_request_regions(pdev, BDX_DRV_NAME);
+ if (err)
goto err_dma;
pci_set_master(pdev);
@@ -1961,25 +1956,26 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pciaddr = pci_resource_start(pdev, 0);
if (!pciaddr) {
err = -EIO;
- ERR("tehuti: no MMIO resource\n");
+ pr_err("no MMIO resource\n");
goto err_out_res;
}
- if ((regionSize = pci_resource_len(pdev, 0)) < BDX_REGS_SIZE) {
+ regionSize = pci_resource_len(pdev, 0);
+ if (regionSize < BDX_REGS_SIZE) {
err = -EIO;
- ERR("tehuti: MMIO resource (%x) too small\n", regionSize);
+ pr_err("MMIO resource (%x) too small\n", regionSize);
goto err_out_res;
}
nic->regs = ioremap(pciaddr, regionSize);
if (!nic->regs) {
err = -EIO;
- ERR("tehuti: ioremap failed\n");
+ pr_err("ioremap failed\n");
goto err_out_res;
}
if (pdev->irq < 2) {
err = -EIO;
- ERR("tehuti: invalid irq (%d)\n", pdev->irq);
+ pr_err("invalid irq (%d)\n", pdev->irq);
goto err_out_iomap;
}
pci_set_drvdata(pdev, nic);
@@ -1996,8 +1992,9 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
nic->irq_type = IRQ_INTX;
#ifdef BDX_MSI
if ((readl(nic->regs + FPGA_VER) & 0xFFF) >= 378) {
- if ((err = pci_enable_msi(pdev)))
- ERR("Tehuti: Can't eneble msi. error is %d\n", err);
+ err = pci_enable_msi(pdev);
+ if (err)
+ pr_err("Can't eneble msi. error is %d\n", err);
else
nic->irq_type = IRQ_MSI;
} else
@@ -2006,9 +2003,10 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/************** netdev **************/
for (port = 0; port < nic->port_num; port++) {
- if (!(ndev = alloc_etherdev(sizeof(struct bdx_priv)))) {
+ ndev = alloc_etherdev(sizeof(struct bdx_priv));
+ if (!ndev) {
err = -ENOMEM;
- printk(KERN_ERR "tehuti: alloc_etherdev failed\n");
+ pr_err("alloc_etherdev failed\n");
goto err_out_iomap;
}
@@ -2075,12 +2073,13 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/*bdx_hw_reset(priv); */
if (bdx_read_mac(priv)) {
- printk(KERN_ERR "tehuti: load MAC address failed\n");
+ pr_err("load MAC address failed\n");
goto err_out_iomap;
}
SET_NETDEV_DEV(ndev, &pdev->dev);
- if ((err = register_netdev(ndev))) {
- printk(KERN_ERR "tehuti: register_netdev failed\n");
+ err = register_netdev(ndev);
+ if (err) {
+ pr_err("register_netdev failed\n");
goto err_out_free;
}
netif_carrier_off(ndev);
@@ -2294,13 +2293,13 @@ bdx_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal)
/* Convert RX fifo size to number of pending packets */
static inline int bdx_rx_fifo_size_to_packets(int rx_size)
{
- return ((FIFO_SIZE * (1 << rx_size)) / sizeof(struct rxf_desc));
+ return (FIFO_SIZE * (1 << rx_size)) / sizeof(struct rxf_desc);
}
/* Convert TX fifo size to number of pending packets */
static inline int bdx_tx_fifo_size_to_packets(int tx_size)
{
- return ((FIFO_SIZE * (1 << tx_size)) / BDX_TXF_DESC_SZ);
+ return (FIFO_SIZE * (1 << tx_size)) / BDX_TXF_DESC_SZ;
}
/*
@@ -2392,10 +2391,10 @@ static int bdx_get_sset_count(struct net_device *netdev, int stringset)
case ETH_SS_STATS:
BDX_ASSERT(ARRAY_SIZE(bdx_stat_names)
!= sizeof(struct bdx_stats) / sizeof(u64));
- return ((priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names) : 0);
- default:
- return -EINVAL;
+ return (priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names) : 0;
}
+
+ return -EINVAL;
}
/*
@@ -2493,10 +2492,8 @@ static struct pci_driver bdx_pci_driver = {
*/
static void __init print_driver_id(void)
{
- printk(KERN_INFO "%s: %s, %s\n", BDX_DRV_NAME, BDX_DRV_DESC,
- BDX_DRV_VERSION);
- printk(KERN_INFO "%s: Options: hw_csum %s\n", BDX_DRV_NAME,
- BDX_MSI_STRING);
+ pr_info("%s, %s\n", BDX_DRV_DESC, BDX_DRV_VERSION);
+ pr_info("Options: hw_csum %s\n", BDX_MSI_STRING);
}
static int __init bdx_module_init(void)
diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h
index 124141909e42..a19dcf8b6b56 100644
--- a/drivers/net/tehuti.h
+++ b/drivers/net/tehuti.h
@@ -529,28 +529,34 @@ struct txd_desc {
/* Debugging Macros */
-#define ERR(fmt, args...) printk(KERN_ERR fmt, ## args)
-#define DBG2(fmt, args...) \
- printk(KERN_ERR "%s:%-5d: " fmt, __func__, __LINE__, ## args)
+#define DBG2(fmt, args...) \
+ pr_err("%s:%-5d: " fmt, __func__, __LINE__, ## args)
#define BDX_ASSERT(x) BUG_ON(x)
#ifdef DEBUG
-#define ENTER do { \
- printk(KERN_ERR "%s:%-5d: ENTER\n", __func__, __LINE__); \
+#define ENTER \
+do { \
+ pr_err("%s:%-5d: ENTER\n", __func__, __LINE__); \
} while (0)
-#define RET(args...) do { \
- printk(KERN_ERR "%s:%-5d: RETURN\n", __func__, __LINE__); \
-return args; } while (0)
+#define RET(args...) \
+do { \
+ pr_err("%s:%-5d: RETURN\n", __func__, __LINE__); \
+ return args; \
+} while (0)
-#define DBG(fmt, args...) \
- printk(KERN_ERR "%s:%-5d: " fmt, __func__, __LINE__, ## args)
+#define DBG(fmt, args...) \
+ pr_err("%s:%-5d: " fmt, __func__, __LINE__, ## args)
#else
-#define ENTER do { } while (0)
+#define ENTER do { } while (0)
#define RET(args...) return args
-#define DBG(fmt, args...) do { } while (0)
+#define DBG(fmt, args...) \
+do { \
+ if (0) \
+ pr_err(fmt, ##args); \
+} while (0)
#endif
#endif /* _BDX__H */
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 7f82b0238e08..22cf1c446de3 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -67,9 +67,8 @@
#include "tg3.h"
#define DRV_MODULE_NAME "tg3"
-#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.106"
-#define DRV_MODULE_RELDATE "January 12, 2010"
+#define DRV_MODULE_VERSION "3.108"
+#define DRV_MODULE_RELDATE "February 17, 2010"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -158,7 +157,7 @@
#define FIRMWARE_TG3TSO5 "tigon/tg3_tso5.bin"
static char version[] __devinitdata =
- DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")";
MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@pobox.com)");
MODULE_DESCRIPTION("Broadcom Tigon3 ethernet driver");
@@ -174,7 +173,7 @@ static int tg3_debug = -1; /* -1 == use TG3_DEF_MSG_ENABLE as value */
module_param(tg3_debug, int, 0);
MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value");
-static struct pci_device_id tg3_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702)},
@@ -244,6 +243,12 @@ static struct pci_device_id tg3_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5717)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5718)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5724)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57781)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57785)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57761)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57765)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
{PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -636,7 +641,6 @@ static void tg3_disable_ints(struct tg3 *tp)
static void tg3_enable_ints(struct tg3 *tp)
{
int i;
- u32 coal_now = 0;
tp->irq_sync = 0;
wmb();
@@ -644,13 +648,14 @@ static void tg3_enable_ints(struct tg3 *tp)
tw32(TG3PCI_MISC_HOST_CTRL,
(tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
+ tp->coal_now = tp->coalesce_mode | HOSTCC_MODE_ENABLE;
for (i = 0; i < tp->irq_cnt; i++) {
struct tg3_napi *tnapi = &tp->napi[i];
tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24);
if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24);
- coal_now |= tnapi->coal_now;
+ tp->coal_now |= tnapi->coal_now;
}
/* Force an initial interrupt */
@@ -658,8 +663,9 @@ static void tg3_enable_ints(struct tg3 *tp)
(tp->napi[0].hw_status->status & SD_STATUS_UPDATED))
tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
else
- tw32(HOSTCC_MODE, tp->coalesce_mode |
- HOSTCC_MODE_ENABLE | coal_now);
+ tw32(HOSTCC_MODE, tp->coal_now);
+
+ tp->coal_now &= ~(tp->napi[0].coal_now | tp->napi[1].coal_now);
}
static inline unsigned int tg3_has_work(struct tg3_napi *tnapi)
@@ -948,17 +954,17 @@ static void tg3_mdio_config_5785(struct tg3 *tp)
phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
switch (phydev->drv->phy_id & phydev->drv->phy_id_mask) {
- case TG3_PHY_ID_BCM50610:
- case TG3_PHY_ID_BCM50610M:
+ case PHY_ID_BCM50610:
+ case PHY_ID_BCM50610M:
val = MAC_PHYCFG2_50610_LED_MODES;
break;
- case TG3_PHY_ID_BCMAC131:
+ case PHY_ID_BCMAC131:
val = MAC_PHYCFG2_AC131_LED_MODES;
break;
- case TG3_PHY_ID_RTL8211C:
+ case PHY_ID_RTL8211C:
val = MAC_PHYCFG2_RTL8211C_LED_MODES;
break;
- case TG3_PHY_ID_RTL8201E:
+ case PHY_ID_RTL8201E:
val = MAC_PHYCFG2_RTL8201E_LED_MODES;
break;
default:
@@ -977,7 +983,7 @@ static void tg3_mdio_config_5785(struct tg3 *tp)
return;
}
- if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE))
+ if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE))
val |= MAC_PHYCFG2_EMODE_MASK_MASK |
MAC_PHYCFG2_FMODE_MASK_MASK |
MAC_PHYCFG2_GMODE_MASK_MASK |
@@ -990,7 +996,7 @@ static void tg3_mdio_config_5785(struct tg3 *tp)
val = tr32(MAC_PHYCFG1);
val &= ~(MAC_PHYCFG1_RXCLK_TO_MASK | MAC_PHYCFG1_TXCLK_TO_MASK |
MAC_PHYCFG1_RGMII_EXT_RX_DEC | MAC_PHYCFG1_RGMII_SND_STAT_EN);
- if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)) {
+ if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)) {
if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
val |= MAC_PHYCFG1_RGMII_EXT_RX_DEC;
if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
@@ -1008,7 +1014,7 @@ static void tg3_mdio_config_5785(struct tg3 *tp)
MAC_RGMII_MODE_TX_ENABLE |
MAC_RGMII_MODE_TX_LOWPWR |
MAC_RGMII_MODE_TX_RESET);
- if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)) {
+ if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)) {
if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
val |= MAC_RGMII_MODE_RX_INT_B |
MAC_RGMII_MODE_RX_QUALITY |
@@ -1028,6 +1034,17 @@ static void tg3_mdio_start(struct tg3 *tp)
tw32_f(MAC_MI_MODE, tp->mi_mode);
udelay(80);
+ if ((tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+ tg3_mdio_config_5785(tp);
+}
+
+static int tg3_mdio_init(struct tg3 *tp)
+{
+ int i;
+ u32 reg;
+ struct phy_device *phydev;
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
u32 funcnum, is_serdes;
@@ -1047,17 +1064,6 @@ static void tg3_mdio_start(struct tg3 *tp)
} else
tp->phy_addr = TG3_PHY_MII_ADDR;
- if ((tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) &&
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
- tg3_mdio_config_5785(tp);
-}
-
-static int tg3_mdio_init(struct tg3 *tp)
-{
- int i;
- u32 reg;
- struct phy_device *phydev;
-
tg3_mdio_start(tp);
if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) ||
@@ -1092,8 +1098,7 @@ static int tg3_mdio_init(struct tg3 *tp)
i = mdiobus_register(tp->mdio_bus);
if (i) {
- printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n",
- tp->dev->name, i);
+ netdev_warn(tp->dev, "mdiobus_reg failed (0x%x)\n", i);
mdiobus_free(tp->mdio_bus);
return i;
}
@@ -1101,35 +1106,35 @@ static int tg3_mdio_init(struct tg3 *tp)
phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
if (!phydev || !phydev->drv) {
- printk(KERN_WARNING "%s: No PHY devices\n", tp->dev->name);
+ netdev_warn(tp->dev, "No PHY devices\n");
mdiobus_unregister(tp->mdio_bus);
mdiobus_free(tp->mdio_bus);
return -ENODEV;
}
switch (phydev->drv->phy_id & phydev->drv->phy_id_mask) {
- case TG3_PHY_ID_BCM57780:
+ case PHY_ID_BCM57780:
phydev->interface = PHY_INTERFACE_MODE_GMII;
phydev->dev_flags |= PHY_BRCM_AUTO_PWRDWN_ENABLE;
break;
- case TG3_PHY_ID_BCM50610:
- case TG3_PHY_ID_BCM50610M:
+ case PHY_ID_BCM50610:
+ case PHY_ID_BCM50610M:
phydev->dev_flags |= PHY_BRCM_CLEAR_RGMII_MODE |
PHY_BRCM_RX_REFCLK_UNUSED |
PHY_BRCM_DIS_TXCRXC_NOENRGY |
PHY_BRCM_AUTO_PWRDWN_ENABLE;
- if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)
+ if (tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)
phydev->dev_flags |= PHY_BRCM_STD_IBND_DISABLE;
if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE;
if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE;
/* fallthru */
- case TG3_PHY_ID_RTL8211C:
+ case PHY_ID_RTL8211C:
phydev->interface = PHY_INTERFACE_MODE_RGMII;
break;
- case TG3_PHY_ID_RTL8201E:
- case TG3_PHY_ID_BCMAC131:
+ case PHY_ID_RTL8201E:
+ case PHY_ID_BCMAC131:
phydev->interface = PHY_INTERFACE_MODE_MII;
phydev->dev_flags |= PHY_BRCM_AUTO_PWRDWN_ENABLE;
tp->tg3_flags3 |= TG3_FLG3_PHY_IS_FET;
@@ -1245,27 +1250,22 @@ static void tg3_ump_link_report(struct tg3 *tp)
static void tg3_link_report(struct tg3 *tp)
{
if (!netif_carrier_ok(tp->dev)) {
- if (netif_msg_link(tp))
- printk(KERN_INFO PFX "%s: Link is down.\n",
- tp->dev->name);
+ netif_info(tp, link, tp->dev, "Link is down\n");
tg3_ump_link_report(tp);
} else if (netif_msg_link(tp)) {
- printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
- tp->dev->name,
- (tp->link_config.active_speed == SPEED_1000 ?
- 1000 :
- (tp->link_config.active_speed == SPEED_100 ?
- 100 : 10)),
- (tp->link_config.active_duplex == DUPLEX_FULL ?
- "full" : "half"));
-
- printk(KERN_INFO PFX
- "%s: Flow control is %s for TX and %s for RX.\n",
- tp->dev->name,
- (tp->link_config.active_flowctrl & FLOW_CTRL_TX) ?
- "on" : "off",
- (tp->link_config.active_flowctrl & FLOW_CTRL_RX) ?
- "on" : "off");
+ netdev_info(tp->dev, "Link is up at %d Mbps, %s duplex\n",
+ (tp->link_config.active_speed == SPEED_1000 ?
+ 1000 :
+ (tp->link_config.active_speed == SPEED_100 ?
+ 100 : 10)),
+ (tp->link_config.active_duplex == DUPLEX_FULL ?
+ "full" : "half"));
+
+ netdev_info(tp->dev, "Flow control is %s for TX and %s for RX\n",
+ (tp->link_config.active_flowctrl & FLOW_CTRL_TX) ?
+ "on" : "off",
+ (tp->link_config.active_flowctrl & FLOW_CTRL_RX) ?
+ "on" : "off");
tg3_ump_link_report(tp);
}
}
@@ -1464,7 +1464,7 @@ static int tg3_phy_init(struct tg3 *tp)
phydev = phy_connect(tp->dev, dev_name(&phydev->dev), tg3_adjust_link,
phydev->dev_flags, phydev->interface);
if (IS_ERR(phydev)) {
- printk(KERN_ERR "%s: Could not attach to PHY\n", tp->dev->name);
+ netdev_err(tp->dev, "Could not attach to PHY\n");
return PTR_ERR(phydev);
}
@@ -1564,7 +1564,9 @@ static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable)
{
u32 reg;
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
+ (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
return;
if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
@@ -1939,6 +1941,10 @@ static int tg3_phy_reset(struct tg3 *tp)
}
}
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
+ (tp->tg3_flags2 & TG3_FLG2_MII_SERDES))
+ return 0;
+
tg3_phy_apply_otp(tp);
if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD)
@@ -1982,7 +1988,7 @@ out:
}
/* Set Extended packet length bit (bit 14) on all chips that */
/* support jumbo frames */
- if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
+ if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) {
/* Cannot do read-modify-write on 5401 */
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20);
} else if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) {
@@ -2019,7 +2025,9 @@ static void tg3_frob_aux_power(struct tg3 *tp)
{
struct tg3 *tp_peer = tp;
- if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0)
+ /* The GPIOs do something completely different on 57765. */
+ if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
return;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
@@ -2132,7 +2140,7 @@ static int tg3_5700_link_polarity(struct tg3 *tp, u32 speed)
{
if (tp->led_ctrl == LED_CTRL_MODE_PHY_2)
return 1;
- else if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5411) {
+ else if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5411) {
if (speed != SPEED_10)
return 1;
} else if (speed == SPEED_10)
@@ -2485,8 +2493,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
break;
default:
- printk(KERN_ERR PFX "%s: Invalid power state (D%d) requested\n",
- tp->dev->name, state);
+ netdev_err(tp->dev, "Invalid power state (D%d) requested\n",
+ state);
return -EINVAL;
}
@@ -2548,11 +2556,11 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
phy_start_aneg(phydev);
phyid = phydev->drv->phy_id & phydev->drv->phy_id_mask;
- if (phyid != TG3_PHY_ID_BCMAC131) {
- phyid &= TG3_PHY_OUI_MASK;
- if (phyid == TG3_PHY_OUI_1 ||
- phyid == TG3_PHY_OUI_2 ||
- phyid == TG3_PHY_OUI_3)
+ if (phyid != PHY_ID_BCMAC131) {
+ phyid &= PHY_BCM_OUI_MASK;
+ if (phyid == PHY_BCM_OUI_1 ||
+ phyid == PHY_BCM_OUI_2 ||
+ phyid == PHY_BCM_OUI_3)
do_low_power = true;
}
}
@@ -3062,7 +3070,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
if (force_reset)
tg3_phy_reset(tp);
- if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
+ if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) {
tg3_readphy(tp, MII_BMSR, &bmsr);
if (tg3_readphy(tp, MII_BMSR, &bmsr) ||
!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE))
@@ -3083,7 +3091,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
}
}
- if ((tp->phy_id & PHY_ID_REV_MASK) == PHY_REV_BCM5401_B0 &&
+ if ((tp->phy_id & TG3_PHY_ID_REV_MASK) ==
+ TG3_PHY_REV_BCM5401_B0 &&
!(bmsr & BMSR_LSTATUS) &&
tp->link_config.active_speed == SPEED_1000) {
err = tg3_phy_reset(tp);
@@ -3238,7 +3247,7 @@ relink:
/* ??? Without this setting Netgear GA302T PHY does not
* ??? send/receive packets...
*/
- if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5411 &&
+ if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5411 &&
tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) {
tp->mi_mode |= MAC_MI_MODE_AUTO_POLL;
tw32_f(MAC_MI_MODE, tp->mi_mode);
@@ -3953,7 +3962,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
- if (tp->phy_id == PHY_ID_BCM8002)
+ if (tp->phy_id == TG3_PHY_ID_BCM8002)
tg3_init_bcm8002(tp);
/* Enable link change event even when serdes polling. */
@@ -4326,10 +4335,8 @@ 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);
+ netdev_warn(tp->dev, "The system may be re-ordering memory-mapped I/O cycles to the network device, attempting to recover\n"
+ "Please report the problem to the driver maintainer and include system chipset information.\n");
spin_lock(&tp->lock);
tp->tg3_flags |= TG3_FLAG_TX_RECOVERY_PENDING;
@@ -4538,6 +4545,12 @@ static void tg3_recycle_rx(struct tg3_napi *tnapi,
pci_unmap_addr(src_map, mapping));
dest_desc->addr_hi = src_desc->addr_hi;
dest_desc->addr_lo = src_desc->addr_lo;
+
+ /* Ensure that the update to the skb happens after the physical
+ * addresses have been transferred to the new BD location.
+ */
+ smp_wmb();
+
src_map->skb = NULL;
}
@@ -4638,11 +4651,16 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
if (skb_size < 0)
goto drop_it;
- ri->skb = NULL;
-
pci_unmap_single(tp->pdev, dma_addr, skb_size,
PCI_DMA_FROMDEVICE);
+ /* Ensure that the update to the skb happens
+ * after the usage of the old DMA mapping.
+ */
+ smp_wmb();
+
+ ri->skb = NULL;
+
skb_put(skb, len);
} else {
struct sk_buff *copy_skb;
@@ -4719,7 +4737,7 @@ next_pkt_nopost:
tw32_rx_mbox(tnapi->consmbox, sw_idx);
/* Refill RX ring(s). */
- if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) || tnapi == &tp->napi[1]) {
+ if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) {
if (work_mask & RXD_OPAQUE_RING_STD) {
tpr->rx_std_prod_idx = std_prod_idx % TG3_RX_RING_SIZE;
tw32_rx_mbox(TG3_RX_STD_PROD_IDX_REG,
@@ -4741,7 +4759,8 @@ next_pkt_nopost:
tpr->rx_std_prod_idx = std_prod_idx % TG3_RX_RING_SIZE;
tpr->rx_jmb_prod_idx = jmb_prod_idx % TG3_RX_JUMBO_RING_SIZE;
- napi_schedule(&tp->napi[1].napi);
+ if (tnapi != &tp->napi[1])
+ napi_schedule(&tp->napi[1].napi);
}
return received;
@@ -4773,12 +4792,12 @@ static void tg3_poll_link(struct tg3 *tp)
}
}
-static void tg3_rx_prodring_xfer(struct tg3 *tp,
- struct tg3_rx_prodring_set *dpr,
- struct tg3_rx_prodring_set *spr)
+static int tg3_rx_prodring_xfer(struct tg3 *tp,
+ struct tg3_rx_prodring_set *dpr,
+ struct tg3_rx_prodring_set *spr)
{
u32 si, di, cpycnt, src_prod_idx;
- int i;
+ int i, err = 0;
while (1) {
src_prod_idx = spr->rx_std_prod_idx;
@@ -4801,6 +4820,23 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp,
si = spr->rx_std_cons_idx;
di = dpr->rx_std_prod_idx;
+ for (i = di; i < di + cpycnt; i++) {
+ if (dpr->rx_std_buffers[i].skb) {
+ cpycnt = i - di;
+ err = -ENOSPC;
+ break;
+ }
+ }
+
+ if (!cpycnt)
+ break;
+
+ /* Ensure that updates to the rx_std_buffers ring and the
+ * shadowed hardware producer ring from tg3_recycle_skb() are
+ * ordered correctly WRT the skb check above.
+ */
+ smp_rmb();
+
memcpy(&dpr->rx_std_buffers[di],
&spr->rx_std_buffers[si],
cpycnt * sizeof(struct ring_info));
@@ -4841,6 +4877,23 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp,
si = spr->rx_jmb_cons_idx;
di = dpr->rx_jmb_prod_idx;
+ for (i = di; i < di + cpycnt; i++) {
+ if (dpr->rx_jmb_buffers[i].skb) {
+ cpycnt = i - di;
+ err = -ENOSPC;
+ break;
+ }
+ }
+
+ if (!cpycnt)
+ break;
+
+ /* Ensure that updates to the rx_jmb_buffers ring and the
+ * shadowed hardware producer ring from tg3_recycle_skb() are
+ * ordered correctly WRT the skb check above.
+ */
+ smp_rmb();
+
memcpy(&dpr->rx_jmb_buffers[di],
&spr->rx_jmb_buffers[si],
cpycnt * sizeof(struct ring_info));
@@ -4858,6 +4911,8 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp,
dpr->rx_jmb_prod_idx = (dpr->rx_jmb_prod_idx + cpycnt) %
TG3_RX_JUMBO_RING_SIZE;
}
+
+ return err;
}
static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget)
@@ -4879,27 +4934,29 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget)
work_done += tg3_rx(tnapi, budget - work_done);
if ((tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) && tnapi == &tp->napi[1]) {
- int i;
- u32 std_prod_idx = tp->prodring[0].rx_std_prod_idx;
- u32 jmb_prod_idx = tp->prodring[0].rx_jmb_prod_idx;
+ struct tg3_rx_prodring_set *dpr = &tp->prodring[0];
+ int i, err = 0;
+ u32 std_prod_idx = dpr->rx_std_prod_idx;
+ u32 jmb_prod_idx = dpr->rx_jmb_prod_idx;
- for (i = 2; i < tp->irq_cnt; i++)
- tg3_rx_prodring_xfer(tp, tnapi->prodring,
- tp->napi[i].prodring);
+ for (i = 1; i < tp->irq_cnt; i++)
+ err |= tg3_rx_prodring_xfer(tp, dpr,
+ tp->napi[i].prodring);
wmb();
- if (std_prod_idx != tp->prodring[0].rx_std_prod_idx) {
- u32 mbox = TG3_RX_STD_PROD_IDX_REG;
- tw32_rx_mbox(mbox, tp->prodring[0].rx_std_prod_idx);
- }
+ if (std_prod_idx != dpr->rx_std_prod_idx)
+ tw32_rx_mbox(TG3_RX_STD_PROD_IDX_REG,
+ dpr->rx_std_prod_idx);
- if (jmb_prod_idx != tp->prodring[0].rx_jmb_prod_idx) {
- u32 mbox = TG3_RX_JMB_PROD_IDX_REG;
- tw32_rx_mbox(mbox, tp->prodring[0].rx_jmb_prod_idx);
- }
+ if (jmb_prod_idx != dpr->rx_jmb_prod_idx)
+ tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG,
+ dpr->rx_jmb_prod_idx);
mmiowb();
+
+ if (err)
+ tw32_f(HOSTCC_MODE, tp->coal_now);
}
return work_done;
@@ -5203,8 +5260,7 @@ static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
err = tg3_init_hw(tp, reset_phy);
if (err) {
- printk(KERN_ERR PFX "%s: Failed to re-initialize device, "
- "aborting.\n", tp->dev->name);
+ netdev_err(tp->dev, "Failed to re-initialize device, aborting\n");
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_full_unlock(tp);
del_timer_sync(&tp->timer);
@@ -5223,7 +5279,7 @@ static void tg3_poll_controller(struct net_device *dev)
struct tg3 *tp = netdev_priv(dev);
for (i = 0; i < tp->irq_cnt; i++)
- tg3_interrupt(tp->napi[i].irq_vec, dev);
+ tg3_interrupt(tp->napi[i].irq_vec, &tp->napi[i]);
}
#endif
@@ -5277,10 +5333,10 @@ out:
static void tg3_dump_short_state(struct tg3 *tp)
{
- printk(KERN_ERR PFX "DEBUG: MAC_TX_STATUS[%08x] MAC_RX_STATUS[%08x]\n",
- tr32(MAC_TX_STATUS), tr32(MAC_RX_STATUS));
- printk(KERN_ERR PFX "DEBUG: RDMAC_STATUS[%08x] WDMAC_STATUS[%08x]\n",
- tr32(RDMAC_STATUS), tr32(WDMAC_STATUS));
+ netdev_err(tp->dev, "DEBUG: MAC_TX_STATUS[%08x] MAC_RX_STATUS[%08x]\n",
+ tr32(MAC_TX_STATUS), tr32(MAC_RX_STATUS));
+ netdev_err(tp->dev, "DEBUG: RDMAC_STATUS[%08x] WDMAC_STATUS[%08x]\n",
+ tr32(RDMAC_STATUS), tr32(WDMAC_STATUS));
}
static void tg3_tx_timeout(struct net_device *dev)
@@ -5288,8 +5344,7 @@ static void tg3_tx_timeout(struct net_device *dev)
struct tg3 *tp = netdev_priv(dev);
if (netif_msg_tx_err(tp)) {
- printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
- dev->name);
+ netdev_err(dev, "transmit timed out, resetting\n");
tg3_dump_short_state(tp);
}
@@ -5453,8 +5508,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
netif_tx_stop_queue(txq);
/* This is a hard error, log it. */
- printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
- "queue awake!\n", dev->name);
+ netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
}
return NETDEV_TX_BUSY;
}
@@ -5657,8 +5711,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
netif_tx_stop_queue(txq);
/* This is a hard error, log it. */
- printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
- "queue awake!\n", dev->name);
+ netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
}
return NETDEV_TX_BUSY;
}
@@ -6005,11 +6058,8 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp,
/* Now allocate fresh SKBs for each rx ring. */
for (i = 0; i < tp->rx_pending; i++) {
if (tg3_alloc_rx_skb(tp, tpr, RXD_OPAQUE_RING_STD, i) < 0) {
- printk(KERN_WARNING PFX
- "%s: Using a smaller RX standard ring, "
- "only %d out of %d buffers were allocated "
- "successfully.\n",
- tp->dev->name, i, tp->rx_pending);
+ netdev_warn(tp->dev, "Using a smaller RX standard ring, only %d out of %d buffers were allocated successfully\n",
+ i, tp->rx_pending);
if (i == 0)
goto initfail;
tp->rx_pending = i;
@@ -6022,31 +6072,28 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp,
memset(tpr->rx_jmb, 0, TG3_RX_JUMBO_RING_BYTES);
- if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) {
- for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) {
- struct tg3_rx_buffer_desc *rxd;
+ if (!(tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE))
+ goto done;
- rxd = &tpr->rx_jmb[i].std;
- rxd->idx_len = TG3_RX_JMB_DMA_SZ << RXD_LEN_SHIFT;
- rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) |
- RXD_FLAG_JUMBO;
- rxd->opaque = (RXD_OPAQUE_RING_JUMBO |
- (i << RXD_OPAQUE_INDEX_SHIFT));
- }
+ for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) {
+ struct tg3_rx_buffer_desc *rxd;
- for (i = 0; i < tp->rx_jumbo_pending; i++) {
- if (tg3_alloc_rx_skb(tp, tpr, RXD_OPAQUE_RING_JUMBO,
- i) < 0) {
- printk(KERN_WARNING PFX
- "%s: Using a smaller RX jumbo ring, "
- "only %d out of %d buffers were "
- "allocated successfully.\n",
- tp->dev->name, i, tp->rx_jumbo_pending);
- if (i == 0)
- goto initfail;
- tp->rx_jumbo_pending = i;
- break;
- }
+ rxd = &tpr->rx_jmb[i].std;
+ rxd->idx_len = TG3_RX_JMB_DMA_SZ << RXD_LEN_SHIFT;
+ rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) |
+ RXD_FLAG_JUMBO;
+ rxd->opaque = (RXD_OPAQUE_RING_JUMBO |
+ (i << RXD_OPAQUE_INDEX_SHIFT));
+ }
+
+ for (i = 0; i < tp->rx_jumbo_pending; i++) {
+ if (tg3_alloc_rx_skb(tp, tpr, RXD_OPAQUE_RING_JUMBO, i) < 0) {
+ netdev_warn(tp->dev, "Using a smaller RX jumbo ring, only %d out of %d buffers were allocated successfully\n",
+ i, tp->rx_jumbo_pending);
+ if (i == 0)
+ goto initfail;
+ tp->rx_jumbo_pending = i;
+ break;
}
}
@@ -6159,8 +6206,7 @@ static void tg3_free_rings(struct tg3 *tp)
dev_kfree_skb_any(skb);
}
- if (tp->irq_cnt == 1 || j != tp->irq_cnt - 1)
- tg3_rx_prodring_free(tp, &tp->prodring[j]);
+ tg3_rx_prodring_free(tp, &tp->prodring[j]);
}
}
@@ -6196,9 +6242,10 @@ static int tg3_init_rings(struct tg3 *tp)
if (tnapi->rx_rcb)
memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp));
- if ((tp->irq_cnt == 1 || i != tp->irq_cnt - 1) &&
- tg3_rx_prodring_alloc(tp, &tp->prodring[i]))
+ if (tg3_rx_prodring_alloc(tp, &tp->prodring[i])) {
+ tg3_free_rings(tp);
return -ENOMEM;
+ }
}
return 0;
@@ -6245,7 +6292,7 @@ static void tg3_free_consistent(struct tg3 *tp)
tp->hw_stats = NULL;
}
- for (i = 0; i < (tp->irq_cnt == 1 ? 1 : tp->irq_cnt - 1); i++)
+ for (i = 0; i < tp->irq_cnt; i++)
tg3_rx_prodring_fini(tp, &tp->prodring[i]);
}
@@ -6257,7 +6304,7 @@ static int tg3_alloc_consistent(struct tg3 *tp)
{
int i;
- for (i = 0; i < (tp->irq_cnt == 1 ? 1 : tp->irq_cnt - 1); i++) {
+ for (i = 0; i < tp->irq_cnt; i++) {
if (tg3_rx_prodring_init(tp, &tp->prodring[i]))
goto err_out;
}
@@ -6322,10 +6369,7 @@ static int tg3_alloc_consistent(struct tg3 *tp)
break;
}
- if (tp->irq_cnt == 1)
- tnapi->prodring = &tp->prodring[0];
- else if (i)
- tnapi->prodring = &tp->prodring[i - 1];
+ tnapi->prodring = &tp->prodring[i];
/*
* If multivector RSS is enabled, vector 0 does not handle
@@ -6389,8 +6433,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int
}
if (i == MAX_WAIT_CNT && !silent) {
- printk(KERN_ERR PFX "tg3_stop_block timed out, "
- "ofs=%lx enable_bit=%x\n",
+ pr_err("tg3_stop_block timed out, ofs=%lx enable_bit=%x\n",
ofs, enable_bit);
return -ENODEV;
}
@@ -6437,9 +6480,8 @@ static int tg3_abort_hw(struct tg3 *tp, int silent)
break;
}
if (i >= MAX_WAIT_CNT) {
- printk(KERN_ERR PFX "tg3_abort_hw timed out for %s, "
- "TX_MODE_ENABLE will not clear MAC_TX_MODE=%08x\n",
- tp->dev->name, tr32(MAC_TX_MODE));
+ netdev_err(tp->dev, "%s timed out, TX_MODE_ENABLE will not clear MAC_TX_MODE=%08x\n",
+ __func__, tr32(MAC_TX_MODE));
err |= -ENODEV;
}
@@ -6660,8 +6702,14 @@ static int tg3_poll_fw(struct tg3 *tp)
!(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);
+ netdev_info(tp->dev, "No firmware running\n");
+ }
+
+ if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) {
+ /* The 57765 A0 needs a little more
+ * time to do some important work.
+ */
+ mdelay(10);
}
return 0;
@@ -7082,10 +7130,8 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
}
if (i >= 10000) {
- printk(KERN_ERR PFX "tg3_reset_cpu timed out for %s, "
- "and %s CPU\n",
- tp->dev->name,
- (offset == RX_CPU_BASE ? "RX" : "TX"));
+ netdev_err(tp->dev, "%s timed out, %s CPU\n",
+ __func__, offset == RX_CPU_BASE ? "RX" : "TX");
return -ENODEV;
}
@@ -7110,9 +7156,8 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b
if (cpu_base == TX_CPU_BASE &&
(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
- printk(KERN_ERR PFX "tg3_load_firmware_cpu: Trying to load "
- "TX cpu firmware on %s which is 5705.\n",
- tp->dev->name);
+ netdev_err(tp->dev, "%s: Trying to load TX cpu firmware which is 5705\n",
+ __func__);
return -EINVAL;
}
@@ -7191,10 +7236,8 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
udelay(1000);
}
if (i >= 5) {
- printk(KERN_ERR PFX "tg3_load_firmware fails for %s "
- "to set RX CPU PC, is %08x should be %08x\n",
- tp->dev->name, tr32(RX_CPU_BASE + CPU_PC),
- info.fw_base);
+ netdev_err(tp->dev, "tg3_load_firmware fails to set RX CPU PC, is %08x should be %08x\n",
+ tr32(RX_CPU_BASE + CPU_PC), info.fw_base);
return -ENODEV;
}
tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
@@ -7257,10 +7300,8 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
udelay(1000);
}
if (i >= 5) {
- printk(KERN_ERR PFX "tg3_load_tso_firmware fails for %s "
- "to set CPU PC, is %08x should be %08x\n",
- tp->dev->name, tr32(cpu_base + CPU_PC),
- info.fw_base);
+ netdev_err(tp->dev, "%s fails to set CPU PC, is %08x should be %08x\n",
+ __func__, tr32(cpu_base + CPU_PC), info.fw_base);
return -ENODEV;
}
tw32(cpu_base + CPU_STATE, 0xffffffff);
@@ -7439,10 +7480,13 @@ static void tg3_rings_reset(struct tg3 *tp)
for (i = 1; i < TG3_IRQ_MAX_VECS; i++) {
tp->napi[i].tx_prod = 0;
tp->napi[i].tx_cons = 0;
- tw32_mailbox(tp->napi[i].prodmbox, 0);
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)
+ tw32_mailbox(tp->napi[i].prodmbox, 0);
tw32_rx_mbox(tp->napi[i].consmbox, 0);
tw32_mailbox_f(tp->napi[i].int_mbox, 1);
}
+ if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS))
+ tw32_mailbox(tp->napi[0].prodmbox, 0);
} else {
tp->napi[0].tx_prod = 0;
tp->napi[0].tx_cons = 0;
@@ -7528,8 +7572,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tg3_abort_hw(tp, 1);
}
- if (reset_phy &&
- !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB))
+ if (reset_phy)
tg3_phy_reset(tp);
err = tg3_chip_reset(tp);
@@ -7574,6 +7617,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS);
}
+ if (tp->tg3_flags3 & TG3_FLG3_L1PLLPD_EN) {
+ u32 grc_mode = tr32(GRC_MODE);
+
+ /* Access the lower 1K of PL PCIE block registers. */
+ val = grc_mode & ~GRC_MODE_PCIE_PORT_MASK;
+ tw32(GRC_MODE, val | GRC_MODE_PCIE_PL_SEL);
+
+ val = tr32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_PL_LO_PHYCTL1);
+ tw32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_PL_LO_PHYCTL1,
+ val | TG3_PCIE_PL_LO_PHYCTL1_L1PLLPD_EN);
+
+ tw32(GRC_MODE, grc_mode);
+ }
+
/* This works around an issue with Athlon chipsets on
* B3 tigon3 silicon. This bit has no effect on any
* other revision. But do not set this on PCI Express
@@ -7705,8 +7762,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
udelay(10);
}
if (i >= 2000) {
- printk(KERN_ERR PFX "tg3_reset_hw cannot enable BUFMGR for %s.\n",
- tp->dev->name);
+ netdev_err(tp->dev, "%s cannot enable BUFMGR\n", __func__);
return -ENODEV;
}
@@ -7772,7 +7828,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
(RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT) |
BDINFO_FLAGS_USE_EXT_RECV);
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR,
NIC_SRAM_RX_JUMBO_BUFFER_DESC);
} else {
@@ -7834,6 +7890,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
RDMAC_MODE_LNGREAD_ENAB);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+ rdmac_mode |= RDMAC_MODE_MULT_DMA_RD_DIS;
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
@@ -8143,7 +8202,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
/* Prevent chip from dropping frames when flow control
* is enabled.
*/
- tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, 2);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+ val = 1;
+ else
+ val = 2;
+ tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, val);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
@@ -8562,10 +8625,8 @@ static int tg3_test_msi(struct tg3 *tp)
return err;
/* MSI test failed, go back to INTx mode */
- printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, "
- "switching to INTx mode. Please report this failure to "
- "the PCI maintainer and include system chipset information.\n",
- tp->dev->name);
+ netdev_warn(tp->dev, "No interrupt was generated using MSI, switching to INTx mode\n"
+ "Please report this failure to the PCI maintainer and include system chipset information\n");
free_irq(tp->napi[0].irq_vec, &tp->napi[0]);
@@ -8598,8 +8659,8 @@ static int tg3_request_firmware(struct tg3 *tp)
const __be32 *fw_data;
if (request_firmware(&tp->fw, tp->fw_needed, &tp->pdev->dev)) {
- printk(KERN_ERR "%s: Failed to load firmware \"%s\"\n",
- tp->dev->name, tp->fw_needed);
+ netdev_err(tp->dev, "Failed to load firmware \"%s\"\n",
+ tp->fw_needed);
return -ENOENT;
}
@@ -8612,8 +8673,8 @@ static int tg3_request_firmware(struct tg3 *tp)
tp->fw_len = be32_to_cpu(fw_data[2]); /* includes bss */
if (tp->fw_len < (tp->fw->size - 12)) {
- printk(KERN_ERR "%s: bogus length %d in \"%s\"\n",
- tp->dev->name, tp->fw_len, tp->fw_needed);
+ netdev_err(tp->dev, "bogus length %d in \"%s\"\n",
+ tp->fw_len, tp->fw_needed);
release_firmware(tp->fw);
tp->fw = NULL;
return -EINVAL;
@@ -8651,9 +8712,8 @@ static bool tg3_enable_msix(struct tg3 *tp)
return false;
if (pci_enable_msix(tp->pdev, msix_ent, rc))
return false;
- printk(KERN_NOTICE
- "%s: Requested %d MSI-X vectors, received %d\n",
- tp->dev->name, tp->irq_cnt, rc);
+ netdev_notice(tp->dev, "Requested %d MSI-X vectors, received %d\n",
+ tp->irq_cnt, rc);
tp->irq_cnt = rc;
}
@@ -8678,8 +8738,7 @@ static void tg3_ints_init(struct tg3 *tp)
/* All MSI supporting chips should support tagged
* status. Assert that this is the case.
*/
- printk(KERN_WARNING PFX "%s: MSI without TAGGED? "
- "Not using MSI.\n", tp->dev->name);
+ netdev_warn(tp->dev, "MSI without TAGGED? Not using MSI\n");
goto defcfg;
}
@@ -8724,12 +8783,10 @@ static int tg3_open(struct net_device *dev)
if (err)
return err;
} else if (err) {
- printk(KERN_WARNING "%s: TSO capability disabled.\n",
- tp->dev->name);
+ netdev_warn(tp->dev, "TSO capability disabled\n");
tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
} else if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) {
- printk(KERN_NOTICE "%s: TSO capability restored.\n",
- tp->dev->name);
+ netdev_notice(tp->dev, "TSO capability restored\n");
tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
}
}
@@ -9395,21 +9452,18 @@ static void __tg3_set_rx_mode(struct net_device *dev)
} else if (dev->flags & IFF_ALLMULTI) {
/* Accept all multicast. */
tg3_set_multi (tp, 1);
- } else if (dev->mc_count < 1) {
+ } else if (netdev_mc_empty(dev)) {
/* Reject all multicast. */
tg3_set_multi (tp, 0);
} else {
/* Accept one or more multicast(s). */
struct dev_mc_list *mclist;
- unsigned int i;
u32 mc_filter[4] = { 0, };
u32 regidx;
u32 bit;
u32 crc;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
-
+ netdev_for_each_mc_addr(mclist, dev) {
crc = calc_crc (mclist->dmi_addr, ETH_ALEN);
bit = ~crc & 0x7f;
regidx = (bit & 0x60) >> 5;
@@ -9722,7 +9776,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
ADVERTISED_Pause |
ADVERTISED_Asym_Pause;
- if (!(tp->tg3_flags2 & TG3_FLAG_10_100_ONLY))
+ if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
mask |= ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full;
@@ -10001,56 +10055,66 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
int err = 0;
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
- if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
- return -EAGAIN;
+ u32 newadv;
+ struct phy_device *phydev;
- if (epause->autoneg) {
- u32 newadv;
- struct phy_device *phydev;
+ phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
- phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
+ if (!(phydev->supported & SUPPORTED_Pause) ||
+ (!(phydev->supported & SUPPORTED_Asym_Pause) &&
+ ((epause->rx_pause && !epause->tx_pause) ||
+ (!epause->rx_pause && epause->tx_pause))))
+ return -EINVAL;
- if (epause->rx_pause) {
- if (epause->tx_pause)
- newadv = ADVERTISED_Pause;
- else
- newadv = ADVERTISED_Pause |
- ADVERTISED_Asym_Pause;
- } else if (epause->tx_pause) {
- newadv = ADVERTISED_Asym_Pause;
+ tp->link_config.flowctrl = 0;
+ if (epause->rx_pause) {
+ tp->link_config.flowctrl |= FLOW_CTRL_RX;
+
+ if (epause->tx_pause) {
+ tp->link_config.flowctrl |= FLOW_CTRL_TX;
+ newadv = ADVERTISED_Pause;
} else
- newadv = 0;
-
- if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
- u32 oldadv = phydev->advertising &
- (ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
- if (oldadv != newadv) {
- phydev->advertising &=
- ~(ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
- phydev->advertising |= newadv;
- err = phy_start_aneg(phydev);
+ newadv = ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause;
+ } else if (epause->tx_pause) {
+ tp->link_config.flowctrl |= FLOW_CTRL_TX;
+ newadv = ADVERTISED_Asym_Pause;
+ } else
+ newadv = 0;
+
+ if (epause->autoneg)
+ tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
+ else
+ tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
+
+ if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
+ u32 oldadv = phydev->advertising &
+ (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+ if (oldadv != newadv) {
+ phydev->advertising &=
+ ~(ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+ phydev->advertising |= newadv;
+ if (phydev->autoneg) {
+ /*
+ * Always renegotiate the link to
+ * inform our link partner of our
+ * flow control settings, even if the
+ * flow control is forced. Let
+ * tg3_adjust_link() do the final
+ * flow control setup.
+ */
+ return phy_start_aneg(phydev);
}
- } else {
- tp->link_config.advertising &=
- ~(ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
- tp->link_config.advertising |= newadv;
}
- } else {
- if (epause->rx_pause)
- tp->link_config.flowctrl |= FLOW_CTRL_RX;
- else
- tp->link_config.flowctrl &= ~FLOW_CTRL_RX;
-
- if (epause->tx_pause)
- tp->link_config.flowctrl |= FLOW_CTRL_TX;
- else
- tp->link_config.flowctrl &= ~FLOW_CTRL_TX;
- if (netif_running(dev))
+ if (!epause->autoneg)
tg3_setup_flow_control(tp, 0, 0);
+ } else {
+ tp->link_config.orig_advertising &=
+ ~(ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+ tp->link_config.orig_advertising |= newadv;
}
} else {
int irq_sync = 0;
@@ -10584,8 +10648,7 @@ static int tg3_test_registers(struct tg3 *tp)
out:
if (netif_msg_hw(tp))
- printk(KERN_ERR PFX "Register test failed at offset %x\n",
- offset);
+ pr_err("Register test failed at offset %x\n", offset);
tw32(offset, save_val);
return -EIO;
}
@@ -10640,12 +10703,27 @@ static int tg3_test_memory(struct tg3 *tp)
{ 0x00008000, 0x01000},
{ 0x00010000, 0x01000},
{ 0xffffffff, 0x00000}
+ }, mem_tbl_5717[] = {
+ { 0x00000200, 0x00008},
+ { 0x00010000, 0x0a000},
+ { 0x00020000, 0x13c00},
+ { 0xffffffff, 0x00000}
+ }, mem_tbl_57765[] = {
+ { 0x00000200, 0x00008},
+ { 0x00004000, 0x00800},
+ { 0x00006000, 0x09800},
+ { 0x00010000, 0x0a000},
+ { 0xffffffff, 0x00000}
};
struct mem_entry *mem_tbl;
int err = 0;
int i;
- if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+ mem_tbl = mem_tbl_5717;
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+ mem_tbl = mem_tbl_57765;
+ else if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
mem_tbl = mem_tbl_5755;
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
mem_tbl = mem_tbl_5906;
@@ -10678,12 +10756,12 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
struct tg3_napi *tnapi, *rnapi;
struct tg3_rx_prodring_set *tpr = &tp->prodring[0];
+ tnapi = &tp->napi[0];
+ rnapi = &tp->napi[0];
if (tp->irq_cnt > 1) {
- tnapi = &tp->napi[1];
rnapi = &tp->napi[1];
- } else {
- tnapi = &tp->napi[0];
- rnapi = &tp->napi[0];
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)
+ tnapi = &tp->napi[1];
}
coal_now = tnapi->coal_now | rnapi->coal_now;
@@ -10720,8 +10798,12 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
mac_mode = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
- tg3_writephy(tp, MII_TG3_FET_PTEST, 0x1800);
+ tg3_writephy(tp, MII_TG3_FET_PTEST,
+ MII_TG3_FET_PTEST_FRC_TX_LINK |
+ MII_TG3_FET_PTEST_FRC_TX_LOCK);
+ /* The write needs to be flushed for the AC131 */
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+ tg3_readphy(tp, MII_TG3_FET_PTEST, &val);
mac_mode |= MAC_MODE_PORT_MODE_MII;
} else
mac_mode |= MAC_MODE_PORT_MODE_GMII;
@@ -10733,9 +10815,10 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
tw32_f(MAC_RX_MODE, tp->rx_mode);
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
- if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)
+ u32 masked_phy_id = tp->phy_id & TG3_PHY_ID_MASK;
+ if (masked_phy_id == TG3_PHY_ID_BCM5401)
mac_mode &= ~MAC_MODE_LINK_POLARITY;
- else if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5411)
+ else if (masked_phy_id == TG3_PHY_ID_BCM5411)
mac_mode |= MAC_MODE_LINK_POLARITY;
tg3_writephy(tp, MII_TG3_EXT_CTRL,
MII_TG3_EXT_CTRL_LNK3_LED_MODE);
@@ -11692,8 +11775,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
tp->tg3_flags |= TG3_FLAG_NVRAM;
if (tg3_nvram_lock(tp)) {
- printk(KERN_WARNING PFX "%s: Cannot get nvarm lock, "
- "tg3_nvram_init failed.\n", tp->dev->name);
+ netdev_warn(tp->dev, "Cannot get nvram lock, %s failed\n",
+ __func__);
return;
}
tg3_enable_nvram_access(tp);
@@ -11991,45 +12074,71 @@ struct subsys_tbl_ent {
u32 phy_id;
};
-static struct subsys_tbl_ent subsys_id_to_phy_id[] = {
+static struct subsys_tbl_ent subsys_id_to_phy_id[] __devinitdata = {
/* Broadcom boards. */
- { PCI_VENDOR_ID_BROADCOM, 0x1644, PHY_ID_BCM5401 }, /* BCM95700A6 */
- { PCI_VENDOR_ID_BROADCOM, 0x0001, PHY_ID_BCM5701 }, /* BCM95701A5 */
- { PCI_VENDOR_ID_BROADCOM, 0x0002, PHY_ID_BCM8002 }, /* BCM95700T6 */
- { PCI_VENDOR_ID_BROADCOM, 0x0003, 0 }, /* BCM95700A9 */
- { PCI_VENDOR_ID_BROADCOM, 0x0005, PHY_ID_BCM5701 }, /* BCM95701T1 */
- { PCI_VENDOR_ID_BROADCOM, 0x0006, PHY_ID_BCM5701 }, /* BCM95701T8 */
- { PCI_VENDOR_ID_BROADCOM, 0x0007, 0 }, /* BCM95701A7 */
- { PCI_VENDOR_ID_BROADCOM, 0x0008, PHY_ID_BCM5701 }, /* BCM95701A10 */
- { PCI_VENDOR_ID_BROADCOM, 0x8008, PHY_ID_BCM5701 }, /* BCM95701A12 */
- { PCI_VENDOR_ID_BROADCOM, 0x0009, PHY_ID_BCM5703 }, /* BCM95703Ax1 */
- { PCI_VENDOR_ID_BROADCOM, 0x8009, PHY_ID_BCM5703 }, /* BCM95703Ax2 */
+ { TG3PCI_SUBVENDOR_ID_BROADCOM,
+ TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6, TG3_PHY_ID_BCM5401 },
+ { TG3PCI_SUBVENDOR_ID_BROADCOM,
+ TG3PCI_SUBDEVICE_ID_BROADCOM_95701A5, TG3_PHY_ID_BCM5701 },
+ { TG3PCI_SUBVENDOR_ID_BROADCOM,
+ TG3PCI_SUBDEVICE_ID_BROADCOM_95700T6, TG3_PHY_ID_BCM8002 },
+ { TG3PCI_SUBVENDOR_ID_BROADCOM,
+ TG3PCI_SUBDEVICE_ID_BROADCOM_95700A9, 0 },
+ { TG3PCI_SUBVENDOR_ID_BROADCOM,
+ TG3PCI_SUBDEVICE_ID_BROADCOM_95701T1, TG3_PHY_ID_BCM5701 },
+ { TG3PCI_SUBVENDOR_ID_BROADCOM,
+ TG3PCI_SUBDEVICE_ID_BROADCOM_95701T8, TG3_PHY_ID_BCM5701 },
+ { TG3PCI_SUBVENDOR_ID_BROADCOM,
+ TG3PCI_SUBDEVICE_ID_BROADCOM_95701A7, 0 },
+ { TG3PCI_SUBVENDOR_ID_BROADCOM,
+ TG3PCI_SUBDEVICE_ID_BROADCOM_95701A10, TG3_PHY_ID_BCM5701 },
+ { TG3PCI_SUBVENDOR_ID_BROADCOM,
+ TG3PCI_SUBDEVICE_ID_BROADCOM_95701A12, TG3_PHY_ID_BCM5701 },
+ { TG3PCI_SUBVENDOR_ID_BROADCOM,
+ TG3PCI_SUBDEVICE_ID_BROADCOM_95703AX1, TG3_PHY_ID_BCM5703 },
+ { TG3PCI_SUBVENDOR_ID_BROADCOM,
+ TG3PCI_SUBDEVICE_ID_BROADCOM_95703AX2, TG3_PHY_ID_BCM5703 },
/* 3com boards. */
- { PCI_VENDOR_ID_3COM, 0x1000, PHY_ID_BCM5401 }, /* 3C996T */
- { PCI_VENDOR_ID_3COM, 0x1006, PHY_ID_BCM5701 }, /* 3C996BT */
- { PCI_VENDOR_ID_3COM, 0x1004, 0 }, /* 3C996SX */
- { PCI_VENDOR_ID_3COM, 0x1007, PHY_ID_BCM5701 }, /* 3C1000T */
- { PCI_VENDOR_ID_3COM, 0x1008, PHY_ID_BCM5701 }, /* 3C940BR01 */
+ { TG3PCI_SUBVENDOR_ID_3COM,
+ TG3PCI_SUBDEVICE_ID_3COM_3C996T, TG3_PHY_ID_BCM5401 },
+ { TG3PCI_SUBVENDOR_ID_3COM,
+ TG3PCI_SUBDEVICE_ID_3COM_3C996BT, TG3_PHY_ID_BCM5701 },
+ { TG3PCI_SUBVENDOR_ID_3COM,
+ TG3PCI_SUBDEVICE_ID_3COM_3C996SX, 0 },
+ { TG3PCI_SUBVENDOR_ID_3COM,
+ TG3PCI_SUBDEVICE_ID_3COM_3C1000T, TG3_PHY_ID_BCM5701 },
+ { TG3PCI_SUBVENDOR_ID_3COM,
+ TG3PCI_SUBDEVICE_ID_3COM_3C940BR01, TG3_PHY_ID_BCM5701 },
/* DELL boards. */
- { PCI_VENDOR_ID_DELL, 0x00d1, PHY_ID_BCM5401 }, /* VIPER */
- { PCI_VENDOR_ID_DELL, 0x0106, PHY_ID_BCM5401 }, /* JAGUAR */
- { PCI_VENDOR_ID_DELL, 0x0109, PHY_ID_BCM5411 }, /* MERLOT */
- { PCI_VENDOR_ID_DELL, 0x010a, PHY_ID_BCM5411 }, /* SLIM_MERLOT */
+ { TG3PCI_SUBVENDOR_ID_DELL,
+ TG3PCI_SUBDEVICE_ID_DELL_VIPER, TG3_PHY_ID_BCM5401 },
+ { TG3PCI_SUBVENDOR_ID_DELL,
+ TG3PCI_SUBDEVICE_ID_DELL_JAGUAR, TG3_PHY_ID_BCM5401 },
+ { TG3PCI_SUBVENDOR_ID_DELL,
+ TG3PCI_SUBDEVICE_ID_DELL_MERLOT, TG3_PHY_ID_BCM5411 },
+ { TG3PCI_SUBVENDOR_ID_DELL,
+ TG3PCI_SUBDEVICE_ID_DELL_SLIM_MERLOT, TG3_PHY_ID_BCM5411 },
/* Compaq boards. */
- { PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */
- { PCI_VENDOR_ID_COMPAQ, 0x009a, PHY_ID_BCM5701 }, /* BANSHEE_2 */
- { PCI_VENDOR_ID_COMPAQ, 0x007d, 0 }, /* CHANGELING */
- { PCI_VENDOR_ID_COMPAQ, 0x0085, PHY_ID_BCM5701 }, /* NC7780 */
- { PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 }, /* NC7780_2 */
+ { TG3PCI_SUBVENDOR_ID_COMPAQ,
+ TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE, TG3_PHY_ID_BCM5701 },
+ { TG3PCI_SUBVENDOR_ID_COMPAQ,
+ TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE_2, TG3_PHY_ID_BCM5701 },
+ { TG3PCI_SUBVENDOR_ID_COMPAQ,
+ TG3PCI_SUBDEVICE_ID_COMPAQ_CHANGELING, 0 },
+ { TG3PCI_SUBVENDOR_ID_COMPAQ,
+ TG3PCI_SUBDEVICE_ID_COMPAQ_NC7780, TG3_PHY_ID_BCM5701 },
+ { TG3PCI_SUBVENDOR_ID_COMPAQ,
+ TG3PCI_SUBDEVICE_ID_COMPAQ_NC7780_2, TG3_PHY_ID_BCM5701 },
/* IBM boards. */
- { PCI_VENDOR_ID_IBM, 0x0281, 0 } /* IBM??? */
+ { TG3PCI_SUBVENDOR_ID_IBM,
+ TG3PCI_SUBDEVICE_ID_IBM_5703SAX2, 0 }
};
-static inline struct subsys_tbl_ent *lookup_by_subsys(struct tg3 *tp)
+static struct subsys_tbl_ent * __devinit tg3_lookup_by_subsys(struct tg3 *tp)
{
int i;
@@ -12070,7 +12179,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
val = tr32(MEMARB_MODE);
tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
- tp->phy_id = PHY_ID_INVALID;
+ tp->phy_id = TG3_PHY_ID_INVALID;
tp->led_ctrl = LED_CTRL_MODE_PHY_1;
/* Assume an onboard device and WOL capable by default. */
@@ -12244,8 +12353,8 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
}
- if (cfg4 & NIC_SRAM_RGMII_STD_IBND_DISABLE)
- tp->tg3_flags3 |= TG3_FLG3_RGMII_STD_IBND_DISABLE;
+ if (cfg4 & NIC_SRAM_RGMII_INBAND_DISABLE)
+ tp->tg3_flags3 |= TG3_FLG3_RGMII_INBAND_DISABLE;
if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_RX_EN)
tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_RX_EN;
if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN)
@@ -12321,7 +12430,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
err = 0;
if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
- hw_phy_id = hw_phy_id_masked = PHY_ID_INVALID;
+ hw_phy_id = hw_phy_id_masked = TG3_PHY_ID_INVALID;
} else {
/* Now read the physical PHY_ID from the chip and verify
* that it is sane. If it doesn't look good, we fall back
@@ -12335,17 +12444,17 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
hw_phy_id |= (hw_phy_id_2 & 0xfc00) << 16;
hw_phy_id |= (hw_phy_id_2 & 0x03ff) << 0;
- hw_phy_id_masked = hw_phy_id & PHY_ID_MASK;
+ hw_phy_id_masked = hw_phy_id & TG3_PHY_ID_MASK;
}
- if (!err && KNOWN_PHY_ID(hw_phy_id_masked)) {
+ if (!err && TG3_KNOWN_PHY_ID(hw_phy_id_masked)) {
tp->phy_id = hw_phy_id;
- if (hw_phy_id_masked == PHY_ID_BCM8002)
+ if (hw_phy_id_masked == TG3_PHY_ID_BCM8002)
tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
else
tp->tg3_flags2 &= ~TG3_FLG2_PHY_SERDES;
} else {
- if (tp->phy_id != PHY_ID_INVALID) {
+ if (tp->phy_id != TG3_PHY_ID_INVALID) {
/* Do nothing, phy ID already set up in
* tg3_get_eeprom_hw_cfg().
*/
@@ -12355,13 +12464,13 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
/* No eeprom signature? Try the hardcoded
* subsys device table.
*/
- p = lookup_by_subsys(tp);
+ p = tg3_lookup_by_subsys(tp);
if (!p)
return -ENODEV;
tp->phy_id = p->phy_id;
if (!tp->phy_id ||
- tp->phy_id == PHY_ID_BCM8002)
+ tp->phy_id == TG3_PHY_ID_BCM8002)
tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
}
}
@@ -12413,13 +12522,11 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
}
skip_phy_reset:
- if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
+ if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) {
err = tg3_init_5401phy_dsp(tp);
if (err)
return err;
- }
- if (!err && ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)) {
err = tg3_init_5401phy_dsp(tp);
}
@@ -12440,7 +12547,8 @@ skip_phy_reset:
static void __devinit tg3_read_partno(struct tg3 *tp)
{
unsigned char vpd_data[TG3_NVM_VPD_LEN]; /* in little-endian format */
- unsigned int i;
+ unsigned int block_end, rosize, len;
+ int i = 0;
u32 magic;
if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) ||
@@ -12462,7 +12570,7 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
}
} else {
ssize_t cnt;
- unsigned int pos = 0, i = 0;
+ unsigned int pos = 0;
for (; pos < TG3_NVM_VPD_LEN && i < 3; i++, pos += cnt) {
cnt = pci_read_vpd(tp->pdev, pos,
@@ -12477,51 +12585,33 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
goto out_not_found;
}
- /* Now parse and find the part number. */
- for (i = 0; i < TG3_NVM_VPD_LEN - 2; ) {
- unsigned char val = vpd_data[i];
- unsigned int block_end;
-
- if (val == 0x82 || val == 0x91) {
- i = (i + 3 +
- (vpd_data[i + 1] +
- (vpd_data[i + 2] << 8)));
- continue;
- }
-
- if (val != 0x90)
- goto out_not_found;
+ i = pci_vpd_find_tag(vpd_data, 0, TG3_NVM_VPD_LEN,
+ PCI_VPD_LRDT_RO_DATA);
+ if (i < 0)
+ goto out_not_found;
- block_end = (i + 3 +
- (vpd_data[i + 1] +
- (vpd_data[i + 2] << 8)));
- i += 3;
+ rosize = pci_vpd_lrdt_size(&vpd_data[i]);
+ block_end = i + PCI_VPD_LRDT_TAG_SIZE + rosize;
+ i += PCI_VPD_LRDT_TAG_SIZE;
- if (block_end > TG3_NVM_VPD_LEN)
- goto out_not_found;
+ if (block_end > TG3_NVM_VPD_LEN)
+ goto out_not_found;
- while (i < (block_end - 2)) {
- if (vpd_data[i + 0] == 'P' &&
- vpd_data[i + 1] == 'N') {
- int partno_len = vpd_data[i + 2];
+ i = pci_vpd_find_info_keyword(vpd_data, i, rosize,
+ PCI_VPD_RO_KEYWORD_PARTNO);
+ if (i < 0)
+ goto out_not_found;
- i += 3;
- if (partno_len > TG3_BPN_SIZE ||
- (partno_len + i) > TG3_NVM_VPD_LEN)
- goto out_not_found;
+ len = pci_vpd_info_field_size(&vpd_data[i]);
- memcpy(tp->board_part_number,
- &vpd_data[i], partno_len);
+ i += PCI_VPD_INFO_FLD_HDR_SIZE;
+ if (len > TG3_BPN_SIZE ||
+ (len + i) > TG3_NVM_VPD_LEN)
+ goto out_not_found;
- /* Success. */
- return;
- }
- i += 3 + vpd_data[i + 2];
- }
+ memcpy(tp->board_part_number, &vpd_data[i], len);
- /* Part number not found. */
- goto out_not_found;
- }
+ return;
out_not_found:
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
@@ -12538,8 +12628,24 @@ out_not_found:
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 &&
tp->pdev->device == TG3PCI_DEVICE_TIGON3_57788)
strcpy(tp->board_part_number, "BCM57788");
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761)
+ strcpy(tp->board_part_number, "BCM57761");
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57765)
strcpy(tp->board_part_number, "BCM57765");
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781)
+ strcpy(tp->board_part_number, "BCM57781");
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785)
+ strcpy(tp->board_part_number, "BCM57785");
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791)
+ strcpy(tp->board_part_number, "BCM57791");
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795)
+ strcpy(tp->board_part_number, "BCM57795");
else
strcpy(tp->board_part_number, "none");
}
@@ -12642,6 +12748,12 @@ static void __devinit tg3_read_sb_ver(struct tg3 *tp, u32 val)
case TG3_EEPROM_SB_REVISION_3:
offset = TG3_EEPROM_SB_F1R3_EDH_OFF;
break;
+ case TG3_EEPROM_SB_REVISION_4:
+ offset = TG3_EEPROM_SB_F1R4_EDH_OFF;
+ break;
+ case TG3_EEPROM_SB_REVISION_5:
+ offset = TG3_EEPROM_SB_F1R5_EDH_OFF;
+ break;
default:
return;
}
@@ -13102,6 +13214,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->pci_chip_rev_id == CHIPREV_ID_57780_A0 ||
tp->pci_chip_rev_id == CHIPREV_ID_57780_A1)
tp->tg3_flags3 |= TG3_FLG3_CLKREQ_BUG;
+ } else if (tp->pci_chip_rev_id == CHIPREV_ID_5717_A0) {
+ tp->tg3_flags3 |= TG3_FLG3_L1PLLPD_EN;
}
} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
@@ -13109,8 +13223,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX);
if (!tp->pcix_cap) {
- printk(KERN_ERR PFX "Cannot find PCI-X "
- "capability, aborting.\n");
+ pr_err("Cannot find PCI-X capability, aborting\n");
return -EIO;
}
@@ -13290,7 +13403,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761 ||
@@ -13306,8 +13420,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
/* Force the chip into D0. */
err = tg3_set_power_state(tp, PCI_D0);
if (err) {
- printk(KERN_ERR PFX "(%s) transition to D0 failed\n",
- pci_name(tp->pdev));
+ pr_err("(%s) transition to D0 failed\n", pci_name(tp->pdev));
return err;
}
@@ -13474,12 +13587,14 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F ||
tp->pdev->device == PCI_DEVICE_ID_TIGON3_5787F)) ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795 ||
(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET))
tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
err = tg3_phy_probe(tp);
if (err) {
- printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n",
+ pr_err("(%s) phy probe failed, err %d\n",
pci_name(tp->pdev), err);
/* ... but do not return immediately ... */
tg3_mdio_fini(tp);
@@ -13989,7 +14104,8 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
/* Send the buffer to the chip. */
ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 1);
if (ret) {
- printk(KERN_ERR "tg3_test_dma() Write the buffer failed %d\n", ret);
+ pr_err("tg3_test_dma() Write the buffer failed %d\n",
+ ret);
break;
}
@@ -13999,7 +14115,8 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
u32 val;
tg3_read_mem(tp, 0x2100 + (i*4), &val);
if (le32_to_cpu(val) != p[i]) {
- printk(KERN_ERR " tg3_test_dma() Card buffer corrupted on write! (%d != %d)\n", val, i);
+ pr_err(" tg3_test_dma() Card buffer corrupted on write! (%d != %d)\n",
+ val, i);
/* ret = -ENODEV here? */
}
p[i] = 0;
@@ -14008,7 +14125,8 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
/* Now read it back. */
ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 0);
if (ret) {
- printk(KERN_ERR "tg3_test_dma() Read the buffer failed %d\n", ret);
+ pr_err("tg3_test_dma() Read the buffer failed %d\n",
+ ret);
break;
}
@@ -14025,7 +14143,8 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
break;
} else {
- printk(KERN_ERR "tg3_test_dma() buffer corrupted on read back! (%d != %d)\n", p[i], i);
+ pr_err("tg3_test_dma() buffer corrupted on read back! (%d != %d)\n",
+ p[i], i);
ret = -ENODEV;
goto out;
}
@@ -14086,9 +14205,22 @@ static void __devinit tg3_init_link_config(struct tg3 *tp)
static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
{
- if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+ tp->bufmgr_config.mbuf_read_dma_low_water =
+ DEFAULT_MB_RDMA_LOW_WATER_5705;
+ tp->bufmgr_config.mbuf_mac_rx_low_water =
+ DEFAULT_MB_MACRX_LOW_WATER_57765;
+ tp->bufmgr_config.mbuf_high_water =
+ DEFAULT_MB_HIGH_WATER_57765;
+
+ tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
+ DEFAULT_MB_RDMA_LOW_WATER_5705;
+ tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo =
+ DEFAULT_MB_MACRX_LOW_WATER_JUMBO_57765;
+ tp->bufmgr_config.mbuf_high_water_jumbo =
+ DEFAULT_MB_HIGH_WATER_JUMBO_57765;
+ } else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
tp->bufmgr_config.mbuf_read_dma_low_water =
DEFAULT_MB_RDMA_LOW_WATER_5705;
tp->bufmgr_config.mbuf_mac_rx_low_water =
@@ -14130,26 +14262,28 @@ static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
static char * __devinit tg3_phy_string(struct tg3 *tp)
{
- switch (tp->phy_id & PHY_ID_MASK) {
- case PHY_ID_BCM5400: return "5400";
- case PHY_ID_BCM5401: return "5401";
- case PHY_ID_BCM5411: return "5411";
- case PHY_ID_BCM5701: return "5701";
- case PHY_ID_BCM5703: return "5703";
- case PHY_ID_BCM5704: return "5704";
- case PHY_ID_BCM5705: return "5705";
- case PHY_ID_BCM5750: return "5750";
- case PHY_ID_BCM5752: return "5752";
- case PHY_ID_BCM5714: return "5714";
- case PHY_ID_BCM5780: return "5780";
- case PHY_ID_BCM5755: return "5755";
- case PHY_ID_BCM5787: return "5787";
- case PHY_ID_BCM5784: return "5784";
- case PHY_ID_BCM5756: return "5722/5756";
- case PHY_ID_BCM5906: return "5906";
- case PHY_ID_BCM5761: return "5761";
- case PHY_ID_BCM5717: return "5717";
- case PHY_ID_BCM8002: return "8002/serdes";
+ switch (tp->phy_id & TG3_PHY_ID_MASK) {
+ case TG3_PHY_ID_BCM5400: return "5400";
+ case TG3_PHY_ID_BCM5401: return "5401";
+ case TG3_PHY_ID_BCM5411: return "5411";
+ case TG3_PHY_ID_BCM5701: return "5701";
+ case TG3_PHY_ID_BCM5703: return "5703";
+ case TG3_PHY_ID_BCM5704: return "5704";
+ case TG3_PHY_ID_BCM5705: return "5705";
+ case TG3_PHY_ID_BCM5750: return "5750";
+ case TG3_PHY_ID_BCM5752: return "5752";
+ case TG3_PHY_ID_BCM5714: return "5714";
+ case TG3_PHY_ID_BCM5780: return "5780";
+ case TG3_PHY_ID_BCM5755: return "5755";
+ case TG3_PHY_ID_BCM5787: return "5787";
+ case TG3_PHY_ID_BCM5784: return "5784";
+ case TG3_PHY_ID_BCM5756: return "5722/5756";
+ case TG3_PHY_ID_BCM5906: return "5906";
+ case TG3_PHY_ID_BCM5761: return "5761";
+ case TG3_PHY_ID_BCM5718C: return "5718C";
+ case TG3_PHY_ID_BCM5718S: return "5718S";
+ case TG3_PHY_ID_BCM57765: return "57765";
+ case TG3_PHY_ID_BCM8002: return "8002/serdes";
case 0: return "serdes";
default: return "unknown";
}
@@ -14291,7 +14425,6 @@ static const struct net_device_ops tg3_netdev_ops_dma_bug = {
static int __devinit tg3_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- static int tg3_version_printed = 0;
struct net_device *dev;
struct tg3 *tp;
int i, err, pm_cap;
@@ -14299,20 +14432,17 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
char str[40];
u64 dma_mask, persist_dma_mask;
- if (tg3_version_printed++ == 0)
- printk(KERN_INFO "%s", version);
+ printk_once(KERN_INFO "%s\n", version);
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device, "
- "aborting.\n");
+ pr_err("Cannot enable PCI device, aborting\n");
return err;
}
err = pci_request_regions(pdev, DRV_MODULE_NAME);
if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources, "
- "aborting.\n");
+ pr_err("Cannot obtain PCI resources, aborting\n");
goto err_out_disable_pdev;
}
@@ -14321,15 +14451,14 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
/* Find power-management capability. */
pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
if (pm_cap == 0) {
- printk(KERN_ERR PFX "Cannot find PowerManagement capability, "
- "aborting.\n");
+ pr_err("Cannot find PowerManagement capability, aborting\n");
err = -EIO;
goto err_out_free_res;
}
dev = alloc_etherdev_mq(sizeof(*tp), TG3_IRQ_MAX_VECS);
if (!dev) {
- printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ pr_err("Etherdev alloc failed, aborting\n");
err = -ENOMEM;
goto err_out_free_res;
}
@@ -14379,8 +14508,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tp->regs = pci_ioremap_bar(pdev, BAR_0);
if (!tp->regs) {
- printk(KERN_ERR PFX "Cannot map device registers, "
- "aborting.\n");
+ netdev_err(dev, "Cannot map device registers, aborting\n");
err = -ENOMEM;
goto err_out_free_dev;
}
@@ -14396,8 +14524,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
err = tg3_get_invariants(tp);
if (err) {
- printk(KERN_ERR PFX "Problem fetching invariants of chip, "
- "aborting.\n");
+ netdev_err(dev, "Problem fetching invariants of chip, aborting\n");
goto err_out_iounmap;
}
@@ -14432,8 +14559,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
err = pci_set_consistent_dma_mask(pdev,
persist_dma_mask);
if (err < 0) {
- printk(KERN_ERR PFX "Unable to obtain 64 bit "
- "DMA for consistent allocations\n");
+ netdev_err(dev, "Unable to obtain 64 bit DMA for consistent allocations\n");
goto err_out_iounmap;
}
}
@@ -14441,8 +14567,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
if (err || dma_mask == DMA_BIT_MASK(32)) {
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (err) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
- "aborting.\n");
+ netdev_err(dev, "No usable DMA configuration, aborting\n");
goto err_out_iounmap;
}
}
@@ -14491,16 +14616,14 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
err = tg3_get_device_address(tp);
if (err) {
- printk(KERN_ERR PFX "Could not obtain valid ethernet address, "
- "aborting.\n");
+ netdev_err(dev, "Could not obtain valid ethernet address, aborting\n");
goto err_out_iounmap;
}
if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
tp->aperegs = pci_ioremap_bar(pdev, BAR_2);
if (!tp->aperegs) {
- printk(KERN_ERR PFX "Cannot map APE registers, "
- "aborting.\n");
+ netdev_err(dev, "Cannot map APE registers, aborting\n");
err = -ENOMEM;
goto err_out_iounmap;
}
@@ -14524,7 +14647,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
err = tg3_test_dma(tp);
if (err) {
- printk(KERN_ERR PFX "DMA engine test failed, aborting.\n");
+ netdev_err(dev, "DMA engine test failed, aborting\n");
goto err_out_apeunmap;
}
@@ -14585,45 +14708,39 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
err = register_netdev(dev);
if (err) {
- printk(KERN_ERR PFX "Cannot register net device, "
- "aborting.\n");
+ netdev_err(dev, "Cannot register net device, aborting\n");
goto err_out_apeunmap;
}
- printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x] (%s) MAC address %pM\n",
- dev->name,
- tp->board_part_number,
- tp->pci_chip_rev_id,
- tg3_bus_string(tp, str),
- dev->dev_addr);
+ netdev_info(dev, "Tigon3 [partno(%s) rev %04x] (%s) MAC address %pM\n",
+ tp->board_part_number,
+ tp->pci_chip_rev_id,
+ tg3_bus_string(tp, str),
+ dev->dev_addr);
if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
struct phy_device *phydev;
phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
- printk(KERN_INFO
- "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
- tp->dev->name, phydev->drv->name,
- dev_name(&phydev->dev));
+ netdev_info(dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
+ phydev->drv->name, dev_name(&phydev->dev));
} else
- printk(KERN_INFO
- "%s: attached PHY is %s (%s Ethernet) (WireSpeed[%d])\n",
- tp->dev->name, tg3_phy_string(tp),
- ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100Base-TX" :
- ((tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) ? "1000Base-SX" :
- "10/100/1000Base-T")),
- (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0);
-
- printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] MIirq[%d] ASF[%d] TSOcap[%d]\n",
- dev->name,
- (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0,
- (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0,
- (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0,
- (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0,
- (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0);
- printk(KERN_INFO "%s: dma_rwctrl[%08x] dma_mask[%d-bit]\n",
- dev->name, tp->dma_rwctrl,
- (pdev->dma_mask == DMA_BIT_MASK(32)) ? 32 :
- (((u64) pdev->dma_mask == DMA_BIT_MASK(40)) ? 40 : 64));
+ netdev_info(dev, "attached PHY is %s (%s Ethernet) (WireSpeed[%d])\n",
+ tg3_phy_string(tp),
+ ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100Base-TX" :
+ ((tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) ? "1000Base-SX" :
+ "10/100/1000Base-T")),
+ (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0);
+
+ netdev_info(dev, "RXcsums[%d] LinkChgREG[%d] MIirq[%d] ASF[%d] TSOcap[%d]\n",
+ (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0,
+ (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0,
+ (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0,
+ (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0,
+ (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0);
+ netdev_info(dev, "dma_rwctrl[%08x] dma_mask[%d-bit]\n",
+ tp->dma_rwctrl,
+ pdev->dma_mask == DMA_BIT_MASK(32) ? 32 :
+ ((u64)pdev->dma_mask) == DMA_BIT_MASK(40) ? 40 : 64);
return 0;
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 8a167912902b..574a1cc4d353 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -56,7 +56,39 @@
#define TG3PCI_DEVICE_TIGON3_57765 0x16b4
#define TG3PCI_DEVICE_TIGON3_57791 0x16b2
#define TG3PCI_DEVICE_TIGON3_57795 0x16b6
-/* 0x04 --> 0x64 unused */
+/* 0x04 --> 0x2c unused */
+#define TG3PCI_SUBVENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6 0x1644
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95701A5 0x0001
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95700T6 0x0002
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A9 0x0003
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95701T1 0x0005
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95701T8 0x0006
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95701A7 0x0007
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95701A10 0x0008
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95701A12 0x8008
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95703AX1 0x0009
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95703AX2 0x8009
+#define TG3PCI_SUBVENDOR_ID_3COM PCI_VENDOR_ID_3COM
+#define TG3PCI_SUBDEVICE_ID_3COM_3C996T 0x1000
+#define TG3PCI_SUBDEVICE_ID_3COM_3C996BT 0x1006
+#define TG3PCI_SUBDEVICE_ID_3COM_3C996SX 0x1004
+#define TG3PCI_SUBDEVICE_ID_3COM_3C1000T 0x1007
+#define TG3PCI_SUBDEVICE_ID_3COM_3C940BR01 0x1008
+#define TG3PCI_SUBVENDOR_ID_DELL PCI_VENDOR_ID_DELL
+#define TG3PCI_SUBDEVICE_ID_DELL_VIPER 0x00d1
+#define TG3PCI_SUBDEVICE_ID_DELL_JAGUAR 0x0106
+#define TG3PCI_SUBDEVICE_ID_DELL_MERLOT 0x0109
+#define TG3PCI_SUBDEVICE_ID_DELL_SLIM_MERLOT 0x010a
+#define TG3PCI_SUBVENDOR_ID_COMPAQ PCI_VENDOR_ID_COMPAQ
+#define TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE 0x007c
+#define TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE_2 0x009a
+#define TG3PCI_SUBDEVICE_ID_COMPAQ_CHANGELING 0x007d
+#define TG3PCI_SUBDEVICE_ID_COMPAQ_NC7780 0x0085
+#define TG3PCI_SUBDEVICE_ID_COMPAQ_NC7780_2 0x0099
+#define TG3PCI_SUBVENDOR_ID_IBM PCI_VENDOR_ID_IBM
+#define TG3PCI_SUBDEVICE_ID_IBM_5703SAX2 0x0281
+/* 0x30 --> 0x64 unused */
#define TG3PCI_MSI_DATA 0x00000064
/* 0x66 --> 0x68 unused */
#define TG3PCI_MISC_HOST_CTRL 0x00000068
@@ -110,6 +142,7 @@
#define CHIPREV_ID_57780_A0 0x57780000
#define CHIPREV_ID_57780_A1 0x57780001
#define CHIPREV_ID_5717_A0 0x05717000
+#define CHIPREV_ID_57765_A0 0x57785000
#define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12)
#define ASIC_REV_5700 0x07
#define ASIC_REV_5701 0x00
@@ -1206,14 +1239,18 @@
#define DEFAULT_MB_MACRX_LOW_WATER 0x00000020
#define DEFAULT_MB_MACRX_LOW_WATER_5705 0x00000010
#define DEFAULT_MB_MACRX_LOW_WATER_5906 0x00000004
+#define DEFAULT_MB_MACRX_LOW_WATER_57765 0x0000002a
#define DEFAULT_MB_MACRX_LOW_WATER_JUMBO 0x00000098
#define DEFAULT_MB_MACRX_LOW_WATER_JUMBO_5780 0x0000004b
+#define DEFAULT_MB_MACRX_LOW_WATER_JUMBO_57765 0x0000007e
#define BUFMGR_MB_HIGH_WATER 0x00004418
#define DEFAULT_MB_HIGH_WATER 0x00000060
#define DEFAULT_MB_HIGH_WATER_5705 0x00000060
#define DEFAULT_MB_HIGH_WATER_5906 0x00000010
+#define DEFAULT_MB_HIGH_WATER_57765 0x000000a0
#define DEFAULT_MB_HIGH_WATER_JUMBO 0x0000017c
#define DEFAULT_MB_HIGH_WATER_JUMBO_5780 0x00000096
+#define DEFAULT_MB_HIGH_WATER_JUMBO_57765 0x000000ea
#define BUFMGR_RX_MB_ALLOC_REQ 0x0000441c
#define BUFMGR_MB_ALLOC_BIT 0x10000000
#define BUFMGR_RX_MB_ALLOC_RESP 0x00004420
@@ -1253,6 +1290,7 @@
#define RDMAC_MODE_MBUF_SBD_CRPT_ENAB 0x00002000
#define RDMAC_MODE_FIFO_SIZE_128 0x00020000
#define RDMAC_MODE_FIFO_LONG_BURST 0x00030000
+#define RDMAC_MODE_MULT_DMA_RD_DIS 0x01000000
#define RDMAC_MODE_IPV4_LSO_EN 0x08000000
#define RDMAC_MODE_IPV6_LSO_EN 0x10000000
#define RDMAC_STATUS 0x00004804
@@ -1543,6 +1581,8 @@
#define GRC_MODE_HOST_SENDBDS 0x00020000
#define GRC_MODE_NO_TX_PHDR_CSUM 0x00100000
#define GRC_MODE_NVRAM_WR_ENABLE 0x00200000
+#define GRC_MODE_PCIE_TL_SEL 0x00000000
+#define GRC_MODE_PCIE_PL_SEL 0x00400000
#define GRC_MODE_NO_RX_PHDR_CSUM 0x00800000
#define GRC_MODE_IRQ_ON_TX_CPU_ATTN 0x01000000
#define GRC_MODE_IRQ_ON_RX_CPU_ATTN 0x02000000
@@ -1550,7 +1590,13 @@
#define GRC_MODE_IRQ_ON_DMA_ATTN 0x08000000
#define GRC_MODE_IRQ_ON_FLOW_ATTN 0x10000000
#define GRC_MODE_4X_NIC_SEND_RINGS 0x20000000
+#define GRC_MODE_PCIE_DL_SEL 0x20000000
#define GRC_MODE_MCAST_FRM_ENABLE 0x40000000
+#define GRC_MODE_PCIE_HI_1K_EN 0x80000000
+#define GRC_MODE_PCIE_PORT_MASK (GRC_MODE_PCIE_TL_SEL | \
+ GRC_MODE_PCIE_PL_SEL | \
+ GRC_MODE_PCIE_DL_SEL | \
+ GRC_MODE_PCIE_HI_1K_EN)
#define GRC_MISC_CFG 0x00006804
#define GRC_MISC_CFG_CORECLK_RESET 0x00000001
#define GRC_MISC_CFG_PRESCALAR_MASK 0x000000fe
@@ -1804,6 +1850,11 @@
/* 0x7e74 --> 0x8000 unused */
+/* Alternate PCIE definitions */
+#define TG3_PCIE_TLDLPL_PORT 0x00007c00
+#define TG3_PCIE_PL_LO_PHYCTL1 0x00000004
+#define TG3_PCIE_PL_LO_PHYCTL1_L1PLLPD_EN 0x00001000
+
/* OTP bit definitions */
#define TG3_OTP_AGCTGT_MASK 0x000000e0
#define TG3_OTP_AGCTGT_SHIFT 1
@@ -1845,6 +1896,8 @@
#define TG3_EEPROM_SB_REVISION_0 0x00000000
#define TG3_EEPROM_SB_REVISION_2 0x00020000
#define TG3_EEPROM_SB_REVISION_3 0x00030000
+#define TG3_EEPROM_SB_REVISION_4 0x00040000
+#define TG3_EEPROM_SB_REVISION_5 0x00050000
#define TG3_EEPROM_MAGIC_HW 0xabcd
#define TG3_EEPROM_MAGIC_HW_MSK 0xffff
@@ -1862,6 +1915,8 @@
#define TG3_EEPROM_SB_F1R2_EDH_OFF 0x14
#define TG3_EEPROM_SB_F1R2_MBA_OFF 0x10
#define TG3_EEPROM_SB_F1R3_EDH_OFF 0x18
+#define TG3_EEPROM_SB_F1R4_EDH_OFF 0x1c
+#define TG3_EEPROM_SB_F1R5_EDH_OFF 0x20
#define TG3_EEPROM_SB_EDH_MAJ_MASK 0x00000700
#define TG3_EEPROM_SB_EDH_MAJ_SHFT 8
#define TG3_EEPROM_SB_EDH_MIN_MASK 0x000000ff
@@ -1956,7 +2011,7 @@
#define NIC_SRAM_DATA_CFG_4 0x00000d60
#define NIC_SRAM_GMII_MODE 0x00000002
-#define NIC_SRAM_RGMII_STD_IBND_DISABLE 0x00000004
+#define NIC_SRAM_RGMII_INBAND_DISABLE 0x00000004
#define NIC_SRAM_RGMII_EXT_IBND_RX_EN 0x00000008
#define NIC_SRAM_RGMII_EXT_IBND_TX_EN 0x00000010
@@ -2093,6 +2148,9 @@
/* Fast Ethernet Tranceiver definitions */
#define MII_TG3_FET_PTEST 0x17
+#define MII_TG3_FET_PTEST_FRC_TX_LINK 0x1000
+#define MII_TG3_FET_PTEST_FRC_TX_LOCK 0x0800
+
#define MII_TG3_FET_TEST 0x1f
#define MII_TG3_FET_SHADOW_EN 0x0080
@@ -2682,6 +2740,7 @@ struct tg3 {
struct net_device *dev;
struct pci_dev *pdev;
+ u32 coal_now;
u32 msg_enable;
/* begin "tx thread" cacheline section */
@@ -2700,7 +2759,7 @@ struct tg3 {
struct vlan_group *vlgrp;
#endif
- struct tg3_rx_prodring_set prodring[TG3_IRQ_MAX_VECS - 1];
+ struct tg3_rx_prodring_set prodring[TG3_IRQ_MAX_VECS];
/* begin "everything else" cacheline(s) section */
@@ -2798,7 +2857,7 @@ struct tg3 {
#define TG3_FLG3_USE_PHYLIB 0x00000010
#define TG3_FLG3_MDIOBUS_INITED 0x00000020
#define TG3_FLG3_PHY_CONNECTED 0x00000080
-#define TG3_FLG3_RGMII_STD_IBND_DISABLE 0x00000100
+#define TG3_FLG3_RGMII_INBAND_DISABLE 0x00000100
#define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200
#define TG3_FLG3_RGMII_EXT_IBND_TX_EN 0x00000400
#define TG3_FLG3_CLKREQ_BUG 0x00000800
@@ -2812,6 +2871,7 @@ struct tg3 {
#define TG3_FLG3_40BIT_DMA_LIMIT_BUG 0x00100000
#define TG3_FLG3_SHORT_DMA_BUG 0x00200000
#define TG3_FLG3_USE_JUMBO_BDFLAG 0x00400000
+#define TG3_FLG3_L1PLLPD_EN 0x00800000
struct timer_list timer;
u16 timer_counter;
@@ -2861,42 +2921,50 @@ struct tg3 {
/* PHY info */
u32 phy_id;
-#define PHY_ID_MASK 0xfffffff0
-#define PHY_ID_BCM5400 0x60008040
-#define PHY_ID_BCM5401 0x60008050
-#define PHY_ID_BCM5411 0x60008070
-#define PHY_ID_BCM5701 0x60008110
-#define PHY_ID_BCM5703 0x60008160
-#define PHY_ID_BCM5704 0x60008190
-#define PHY_ID_BCM5705 0x600081a0
-#define PHY_ID_BCM5750 0x60008180
-#define PHY_ID_BCM5752 0x60008100
-#define PHY_ID_BCM5714 0x60008340
-#define PHY_ID_BCM5780 0x60008350
-#define PHY_ID_BCM5755 0xbc050cc0
-#define PHY_ID_BCM5787 0xbc050ce0
-#define PHY_ID_BCM5756 0xbc050ed0
-#define PHY_ID_BCM5784 0xbc050fa0
-#define PHY_ID_BCM5761 0xbc050fd0
-#define PHY_ID_BCM5717 0x5c0d8a00
-#define PHY_ID_BCM5906 0xdc00ac40
-#define PHY_ID_BCM8002 0x60010140
-#define PHY_ID_INVALID 0xffffffff
-#define PHY_ID_REV_MASK 0x0000000f
-#define PHY_REV_BCM5401_B0 0x1
-#define PHY_REV_BCM5401_B2 0x3
-#define PHY_REV_BCM5401_C0 0x6
-#define PHY_REV_BCM5411_X0 0x1 /* Found on Netgear GA302T */
-#define TG3_PHY_ID_BCM50610 0x143bd60
-#define TG3_PHY_ID_BCM50610M 0x143bd70
-#define TG3_PHY_ID_BCMAC131 0x143bc70
-#define TG3_PHY_ID_RTL8211C 0x001cc910
-#define TG3_PHY_ID_RTL8201E 0x00008200
-#define TG3_PHY_ID_BCM57780 0x03625d90
-#define TG3_PHY_OUI_MASK 0xfffffc00
-#define TG3_PHY_OUI_1 0x00206000
-#define TG3_PHY_OUI_2 0x0143bc00
-#define TG3_PHY_OUI_3 0x03625c00
+#define TG3_PHY_ID_MASK 0xfffffff0
+#define TG3_PHY_ID_BCM5400 0x60008040
+#define TG3_PHY_ID_BCM5401 0x60008050
+#define TG3_PHY_ID_BCM5411 0x60008070
+#define TG3_PHY_ID_BCM5701 0x60008110
+#define TG3_PHY_ID_BCM5703 0x60008160
+#define TG3_PHY_ID_BCM5704 0x60008190
+#define TG3_PHY_ID_BCM5705 0x600081a0
+#define TG3_PHY_ID_BCM5750 0x60008180
+#define TG3_PHY_ID_BCM5752 0x60008100
+#define TG3_PHY_ID_BCM5714 0x60008340
+#define TG3_PHY_ID_BCM5780 0x60008350
+#define TG3_PHY_ID_BCM5755 0xbc050cc0
+#define TG3_PHY_ID_BCM5787 0xbc050ce0
+#define TG3_PHY_ID_BCM5756 0xbc050ed0
+#define TG3_PHY_ID_BCM5784 0xbc050fa0
+#define TG3_PHY_ID_BCM5761 0xbc050fd0
+#define TG3_PHY_ID_BCM5718C 0x5c0d8a00
+#define TG3_PHY_ID_BCM5718S 0xbc050ff0
+#define TG3_PHY_ID_BCM57765 0x5c0d8a40
+#define TG3_PHY_ID_BCM5906 0xdc00ac40
+#define TG3_PHY_ID_BCM8002 0x60010140
+#define TG3_PHY_ID_INVALID 0xffffffff
+
+#define PHY_ID_RTL8211C 0x001cc910
+#define PHY_ID_RTL8201E 0x00008200
+
+#define TG3_PHY_ID_REV_MASK 0x0000000f
+#define TG3_PHY_REV_BCM5401_B0 0x1
+
+ /* This macro assumes the passed PHY ID is
+ * already masked with TG3_PHY_ID_MASK.
+ */
+#define TG3_KNOWN_PHY_ID(X) \
+ ((X) == TG3_PHY_ID_BCM5400 || (X) == TG3_PHY_ID_BCM5401 || \
+ (X) == TG3_PHY_ID_BCM5411 || (X) == TG3_PHY_ID_BCM5701 || \
+ (X) == TG3_PHY_ID_BCM5703 || (X) == TG3_PHY_ID_BCM5704 || \
+ (X) == TG3_PHY_ID_BCM5705 || (X) == TG3_PHY_ID_BCM5750 || \
+ (X) == TG3_PHY_ID_BCM5752 || (X) == TG3_PHY_ID_BCM5714 || \
+ (X) == TG3_PHY_ID_BCM5780 || (X) == TG3_PHY_ID_BCM5787 || \
+ (X) == TG3_PHY_ID_BCM5755 || (X) == TG3_PHY_ID_BCM5756 || \
+ (X) == TG3_PHY_ID_BCM5906 || (X) == TG3_PHY_ID_BCM5761 || \
+ (X) == TG3_PHY_ID_BCM5718C || (X) == TG3_PHY_ID_BCM5718S || \
+ (X) == TG3_PHY_ID_BCM57765 || (X) == TG3_PHY_ID_BCM8002)
u32 led_ctrl;
u32 phy_otp;
@@ -2909,20 +2977,6 @@ struct tg3 {
u32 pci_clock_ctrl;
struct pci_dev *pdev_peer;
- /* This macro assumes the passed PHY ID is already masked
- * with PHY_ID_MASK.
- */
-#define KNOWN_PHY_ID(X) \
- ((X) == PHY_ID_BCM5400 || (X) == PHY_ID_BCM5401 || \
- (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \
- (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
- (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \
- (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \
- (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
- (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \
- (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM5761 || \
- (X) == PHY_ID_BCM5717 || (X) == PHY_ID_BCM8002)
-
struct tg3_hw_stats *hw_stats;
dma_addr_t stats_mapping;
struct work_struct reset_task;
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index fabaeffb3155..390540c101c7 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -254,7 +254,7 @@ static struct board {
{ "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */
};
-static struct pci_device_id tlan_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(tlan_pci_tbl) = {
{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL10,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100,
@@ -338,7 +338,7 @@ static int TLan_PhyInternalService( struct net_device * );
static int TLan_PhyDp83840aCheck( struct net_device * );
*/
-static int TLan_MiiReadReg( struct net_device *, u16, u16, u16 * );
+static bool TLan_MiiReadReg( struct net_device *, u16, u16, u16 * );
static void TLan_MiiSendData( u16, u32, unsigned );
static void TLan_MiiSync( u16 );
static void TLan_MiiWriteReg( struct net_device *, u16, u16, u16 );
@@ -1314,7 +1314,7 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev )
static void TLan_SetMulticastList( struct net_device *dev )
{
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
u32 hash1 = 0;
u32 hash2 = 0;
int i;
@@ -1335,7 +1335,8 @@ static void TLan_SetMulticastList( struct net_device *dev )
TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF );
TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF );
} else {
- for ( i = 0; i < dev->mc_count; i++ ) {
+ i = 0;
+ netdev_for_each_mc_addr(dmi, dev) {
if ( i < 3 ) {
TLan_SetMac( dev, i + 1,
(char *) &dmi->dmi_addr );
@@ -1346,7 +1347,7 @@ static void TLan_SetMulticastList( struct net_device *dev )
else
hash2 |= ( 1 << ( offset - 32 ) );
}
- dmi = dmi->next;
+ i++;
}
for ( ; i < 3; i++ )
TLan_SetMac( dev, i + 1, NULL );
@@ -2204,7 +2205,7 @@ TLan_ResetAdapter( struct net_device *dev )
u32 data;
u8 data8;
- priv->tlanFullDuplex = FALSE;
+ priv->tlanFullDuplex = false;
priv->phyOnline=0;
netif_carrier_off(dev);
@@ -2259,7 +2260,7 @@ TLan_ResetAdapter( struct net_device *dev )
TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x0a );
} else if ( priv->duplex == TLAN_DUPLEX_FULL ) {
TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x00 );
- priv->tlanFullDuplex = TRUE;
+ priv->tlanFullDuplex = true;
} else {
TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 );
}
@@ -2651,14 +2652,14 @@ static void TLan_PhyStartLink( struct net_device *dev )
TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0000);
} else if ( priv->speed == TLAN_SPEED_10 &&
priv->duplex == TLAN_DUPLEX_FULL) {
- priv->tlanFullDuplex = TRUE;
+ priv->tlanFullDuplex = true;
TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0100);
} else if ( priv->speed == TLAN_SPEED_100 &&
priv->duplex == TLAN_DUPLEX_HALF) {
TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2000);
} else if ( priv->speed == TLAN_SPEED_100 &&
priv->duplex == TLAN_DUPLEX_FULL) {
- priv->tlanFullDuplex = TRUE;
+ priv->tlanFullDuplex = true;
TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100);
} else {
@@ -2695,7 +2696,7 @@ static void TLan_PhyStartLink( struct net_device *dev )
tctl &= ~TLAN_TC_AUISEL;
if ( priv->duplex == TLAN_DUPLEX_FULL ) {
control |= MII_GC_DUPLEX;
- priv->tlanFullDuplex = TRUE;
+ priv->tlanFullDuplex = true;
}
if ( priv->speed == TLAN_SPEED_100 ) {
control |= MII_GC_SPEEDSEL;
@@ -2750,9 +2751,9 @@ static void TLan_PhyFinishAutoNeg( struct net_device *dev )
TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa );
mode = an_adv & an_lpa & 0x03E0;
if ( mode & 0x0100 ) {
- priv->tlanFullDuplex = TRUE;
+ priv->tlanFullDuplex = true;
} else if ( ! ( mode & 0x0080 ) && ( mode & 0x0040 ) ) {
- priv->tlanFullDuplex = TRUE;
+ priv->tlanFullDuplex = true;
}
if ( ( ! ( mode & 0x0180 ) ) &&
@@ -2855,8 +2856,8 @@ void TLan_PhyMonitor( struct net_device *dev )
* TLan_MiiReadReg
*
* Returns:
- * 0 if ack received ok
- * 1 otherwise.
+ * false if ack received ok
+ * true if no ack received or other error
*
* Parms:
* dev The device structure containing
@@ -2875,17 +2876,17 @@ void TLan_PhyMonitor( struct net_device *dev )
*
**************************************************************/
-static int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val )
+static bool TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val )
{
u8 nack;
u16 sio, tmp;
u32 i;
- int err;
+ bool err;
int minten;
TLanPrivateInfo *priv = netdev_priv(dev);
unsigned long flags = 0;
- err = FALSE;
+ err = false;
outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
@@ -2918,7 +2919,7 @@ static int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val )
TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
}
tmp = 0xffff;
- err = TRUE;
+ err = true;
} else { /* ACK, so read data */
for (tmp = 0, i = 0x8000; i; i >>= 1) {
TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h
index 4b82f283e985..d13ff12d7500 100644
--- a/drivers/net/tlan.h
+++ b/drivers/net/tlan.h
@@ -31,9 +31,6 @@
*
****************************************************************/
-#define FALSE 0
-#define TRUE 1
-
#define TLAN_MIN_FRAME_SIZE 64
#define TLAN_MAX_FRAME_SIZE 1600
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index cf552d1d9629..0fb930feea45 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -117,7 +117,7 @@ MODULE_PARM_DESC(message_level, "3c359: Level of reported messages") ;
* will be stuck with 1555 lines of hex #'s in the code.
*/
-static struct pci_device_id xl_pci_tbl[] =
+static DEFINE_PCI_DEVICE_TABLE(xl_pci_tbl) =
{
{PCI_VENDOR_ID_3COM,PCI_DEVICE_ID_3COM_3C359, PCI_ANY_ID, PCI_ANY_ID, },
{ } /* terminate list */
@@ -1390,10 +1390,9 @@ static int xl_close(struct net_device *dev)
static void xl_set_rx_mode(struct net_device *dev)
{
struct xl_private *xl_priv = netdev_priv(dev);
- struct dev_mc_list *dmi ;
+ struct dev_mc_list *dmi;
unsigned char dev_mc_address[4] ;
u16 options ;
- int i ;
if (dev->flags & IFF_PROMISC)
options = 0x0004 ;
@@ -1408,7 +1407,7 @@ static void xl_set_rx_mode(struct net_device *dev)
dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ;
- for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) {
+ netdev_for_each_mc_addr(dmi, dev) {
dev_mc_address[0] |= dmi->dmi_addr[2] ;
dev_mc_address[1] |= dmi->dmi_addr[3] ;
dev_mc_address[2] |= dmi->dmi_addr[4] ;
diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c
index b9db1b5a58a3..515f122777ab 100644
--- a/drivers/net/tokenring/abyss.c
+++ b/drivers/net/tokenring/abyss.c
@@ -45,7 +45,7 @@ static char version[] __devinitdata =
#define ABYSS_IO_EXTENT 64
-static struct pci_device_id abyss_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(abyss_pci_tbl) = {
{ PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_MK2,
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_TOKEN_RING << 8, 0x00ffffff, },
{ } /* Terminating entry */
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 66272f2a0758..1a0967246e2f 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -995,13 +995,11 @@ static void tok_set_multicast_list(struct net_device *dev)
/*BMS ifconfig tr down or hot unplug a PCMCIA card ??hownowbrowncow*/
if (/*BMSHELPdev->start == 0 ||*/ ti->open_status != OPEN) return;
address[0] = address[1] = address[2] = address[3] = 0;
- mclist = dev->mc_list;
- for (i = 0; i < dev->mc_count; i++) {
+ netdev_for_each_mc_addr(mclist, dev) {
address[0] |= mclist->dmi_addr[2];
address[1] |= mclist->dmi_addr[3];
address[2] |= mclist->dmi_addr[4];
address[3] |= mclist->dmi_addr[5];
- mclist = mclist->next;
}
SET_PAGE(ti->srb_page);
for (i = 0; i < sizeof(struct srb_set_funct_addr); i++)
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index d6ccd59c7d07..dd028fee9dc2 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -146,7 +146,7 @@
static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n"
" v0.5.3 11/13/02 - Kent Yoder";
-static struct pci_device_id streamer_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(streamer_pci_tbl) = {
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,},
{} /* terminating entry */
};
@@ -1268,7 +1268,6 @@ static void streamer_set_rx_mode(struct net_device *dev)
__u8 options = 0;
struct dev_mc_list *dmi;
unsigned char dev_mc_address[5];
- int i;
writel(streamer_priv->srb, streamer_mmio + LAPA);
options = streamer_priv->streamer_copy_all_options;
@@ -1303,8 +1302,7 @@ static void streamer_set_rx_mode(struct net_device *dev)
writel(streamer_priv->srb,streamer_mmio+LAPA);
dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ;
- for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next)
- {
+ netdev_for_each_mc_addr(dmi, dev) {
dev_mc_address[0] |= dmi->dmi_addr[2] ;
dev_mc_address[1] |= dmi->dmi_addr[3] ;
dev_mc_address[2] |= dmi->dmi_addr[4] ;
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index df32025c5132..3a25e0434ae2 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -172,7 +172,7 @@ module_param_array(message_level, int, NULL, 0) ;
static int network_monitor[OLYMPIC_MAX_ADAPTERS] = {0,};
module_param_array(network_monitor, int, NULL, 0);
-static struct pci_device_id olympic_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(olympic_pci_tbl) = {
{PCI_VENDOR_ID_IBM,PCI_DEVICE_ID_IBM_TR_WAKE,PCI_ANY_ID,PCI_ANY_ID,},
{ } /* Terminating Entry */
};
@@ -1139,9 +1139,8 @@ static void olympic_set_rx_mode(struct net_device *dev)
u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ;
u8 options = 0;
u8 __iomem *srb;
- struct dev_mc_list *dmi ;
+ struct dev_mc_list *dmi;
unsigned char dev_mc_address[4] ;
- int i ;
writel(olympic_priv->srb,olympic_mmio+LAPA);
srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
@@ -1178,7 +1177,7 @@ static void olympic_set_rx_mode(struct net_device *dev)
dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ;
- for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) {
+ netdev_for_each_mc_addr(dmi, dev) {
dev_mc_address[0] |= dmi->dmi_addr[2] ;
dev_mc_address[1] |= dmi->dmi_addr[3] ;
dev_mc_address[2] |= dmi->dmi_addr[4] ;
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index e3c42f5ac4a9..ee71bcfb3753 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -693,7 +693,7 @@ static netdev_tx_t tms380tr_hardware_send_packet(struct sk_buff *skb,
* NOTE: This function should be used whenever the status of any TPL must be
* modified by the driver, because the compiler may otherwise change the
* order of instructions such that writing the TPL status may be executed at
- * an undesireable time. When this function is used, the status is always
+ * an undesirable time. When this function is used, the status is always
* written when the function is called.
*/
static void tms380tr_write_tpl_status(TPL *tpl, unsigned int Status)
@@ -1212,10 +1212,9 @@ static void tms380tr_set_multicast_list(struct net_device *dev)
}
else
{
- int i;
- struct dev_mc_list *mclist = dev->mc_list;
- for (i=0; i< dev->mc_count; i++)
- {
+ struct dev_mc_list *mclist;
+
+ netdev_for_each_mc_addr(mclist, dev) {
((char *)(&tp->ocpl.FunctAddr))[0] |=
mclist->dmi_addr[2];
((char *)(&tp->ocpl.FunctAddr))[1] |=
@@ -1224,7 +1223,6 @@ static void tms380tr_set_multicast_list(struct net_device *dev)
mclist->dmi_addr[4];
((char *)(&tp->ocpl.FunctAddr))[3] |=
mclist->dmi_addr[5];
- mclist = mclist->next;
}
}
tms380tr_exec_cmd(dev, OC_SET_FUNCT_ADDR);
@@ -2266,7 +2264,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev)
* This function should be used whenever the status of any RPL must be
* modified by the driver, because the compiler may otherwise change the
* order of instructions such that writing the RPL status may be executed
- * at an undesireable time. When this function is used, the status is
+ * at an undesirable time. When this function is used, the status is
* always written when the function is called.
*/
static void tms380tr_write_rpl_status(RPL *rpl, unsigned int Status)
diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c
index f92fe86fdcae..d4c7c0c0a3d6 100644
--- a/drivers/net/tokenring/tmspci.c
+++ b/drivers/net/tokenring/tmspci.c
@@ -57,7 +57,7 @@ static struct card_info card_info_table[] = {
{ {0x03, 0x01}, "3Com Token Link Velocity"},
};
-static struct pci_device_id tmspci_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(tmspci_pci_tbl) = {
{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TOKENRING, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_TR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
{ PCI_VENDOR_ID_TCONRAD, PCI_DEVICE_ID_TCONRAD_TOKENRING, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index a69c4a48bab9..647cdd1d4e20 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -1184,29 +1184,19 @@ static void tsi108_set_rx_mode(struct net_device *dev)
rxcfg &= ~(TSI108_EC_RXCFG_UFE | TSI108_EC_RXCFG_MFE);
- if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
+ if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev)) {
int i;
- struct dev_mc_list *mc = dev->mc_list;
+ struct dev_mc_list *mc;
rxcfg |= TSI108_EC_RXCFG_MFE | TSI108_EC_RXCFG_MC_HASH;
memset(data->mc_hash, 0, sizeof(data->mc_hash));
- while (mc) {
+ netdev_for_each_mc_addr(mc, dev) {
u32 hash, crc;
- if (mc->dmi_addrlen == 6) {
- crc = ether_crc(6, mc->dmi_addr);
- hash = crc >> 23;
-
- __set_bit(hash, &data->mc_hash[0]);
- } else {
- printk(KERN_ERR
- "%s: got multicast address of length %d instead of 6.\n",
- dev->name,
- mc->dmi_addrlen);
- }
-
- mc = mc->next;
+ crc = ether_crc(6, mc->dmi_addr);
+ hash = crc >> 23;
+ __set_bit(hash, &data->mc_hash[0]);
}
TSI_WRITE(TSI108_EC_HASHADDR,
diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
index 9f6742fad6ca..007d8e75666d 100644
--- a/drivers/net/tulip/21142.c
+++ b/drivers/net/tulip/21142.c
@@ -43,8 +43,8 @@ void t21142_media_task(struct work_struct *work)
if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000)
csr12 |= 6;
if (tulip_debug > 2)
- printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n",
- dev->name, csr12, medianame[dev->if_port]);
+ dev_info(&dev->dev, "21143 negotiation status %08x, %s\n",
+ csr12, medianame[dev->if_port]);
if (tulip_media_cap[dev->if_port] & MediaIsMII) {
if (tulip_check_duplex(dev) < 0) {
netif_carrier_off(dev);
@@ -56,23 +56,26 @@ void t21142_media_task(struct work_struct *work)
} else if (tp->nwayset) {
/* Don't screw up a negotiated session! */
if (tulip_debug > 1)
- printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n",
- dev->name, medianame[dev->if_port], csr12);
+ dev_info(&dev->dev,
+ "Using NWay-set %s media, csr12 %08x\n",
+ medianame[dev->if_port], csr12);
} else if (tp->medialock) {
;
} else if (dev->if_port == 3) {
if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */
if (tulip_debug > 1)
- printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, "
- "trying NWay.\n", dev->name, csr12);
+ dev_info(&dev->dev,
+ "No 21143 100baseTx link beat, %08x, trying NWay\n",
+ csr12);
t21142_start_nway(dev);
next_tick = 3*HZ;
}
} else if ((csr12 & 0x7000) != 0x5000) {
/* Negotiation failed. Search media types. */
if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n",
- dev->name, csr12);
+ dev_info(&dev->dev,
+ "21143 negotiation failed, status %08x\n",
+ csr12);
if (!(csr12 & 4)) { /* 10mbps link beat good. */
new_csr6 = 0x82420000;
dev->if_port = 0;
@@ -90,8 +93,8 @@ void t21142_media_task(struct work_struct *work)
iowrite32(1, ioaddr + CSR13);
}
if (tulip_debug > 1)
- printk(KERN_INFO"%s: Testing new 21143 media %s.\n",
- dev->name, medianame[dev->if_port]);
+ dev_info(&dev->dev, "Testing new 21143 media %s\n",
+ medianame[dev->if_port]);
if (new_csr6 != (tp->csr6 & ~0x00D5)) {
tp->csr6 &= 0x00D5;
tp->csr6 |= new_csr6;
@@ -119,8 +122,8 @@ void t21142_start_nway(struct net_device *dev)
tp->nway = tp->mediasense = 1;
tp->nwayset = tp->lpar = 0;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%8.8x.\n",
- dev->name, csr14);
+ printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%08x\n",
+ dev->name, csr14);
iowrite32(0x0001, ioaddr + CSR13);
udelay(100);
iowrite32(csr14, ioaddr + CSR14);
@@ -147,8 +150,9 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000)
csr12 |= 6;
if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, "
- "%8.8x.\n", dev->name, csr12, csr5, csr14);
+ dev_info(&dev->dev,
+ "21143 link status interrupt %08x, CSR5 %x, %08x\n",
+ csr12, csr5, csr14);
/* If NWay finished and we have a negotiated partner capability. */
if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) {
@@ -171,14 +175,15 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
if (tulip_debug > 1) {
if (tp->nwayset)
- printk(KERN_INFO "%s: Switching to %s based on link "
- "negotiation %4.4x & %4.4x = %4.4x.\n",
- dev->name, medianame[dev->if_port], tp->sym_advertise,
- tp->lpar, negotiated);
+ dev_info(&dev->dev,
+ "Switching to %s based on link negotiation %04x & %04x = %04x\n",
+ medianame[dev->if_port],
+ tp->sym_advertise, tp->lpar,
+ negotiated);
else
- printk(KERN_INFO "%s: Autonegotiation failed, using %s,"
- " link beat status %4.4x.\n",
- dev->name, medianame[dev->if_port], csr12);
+ dev_info(&dev->dev,
+ "Autonegotiation failed, using %s, link beat status %04x\n",
+ medianame[dev->if_port], csr12);
}
if (tp->mtable) {
@@ -201,14 +206,14 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
#if 0 /* Restart shouldn't be needed. */
iowrite32(tp->csr6 | RxOn, ioaddr + CSR6);
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n",
- dev->name, ioread32(ioaddr + CSR5));
+ printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %08x\n",
+ dev->name, ioread32(ioaddr + CSR5));
#endif
tulip_start_rxtx(tp);
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n",
- dev->name, tp->csr6, ioread32(ioaddr + CSR6),
- ioread32(ioaddr + CSR12));
+ printk(KERN_DEBUG "%s: Setting CSR6 %08x/%x CSR12 %08x\n",
+ dev->name, tp->csr6, ioread32(ioaddr + CSR6),
+ ioread32(ioaddr + CSR12));
} else if ((tp->nwayset && (csr5 & 0x08000000) &&
(dev->if_port == 3 || dev->if_port == 5) &&
(csr12 & 2) == 2) ||
@@ -220,9 +225,9 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
add_timer(&tp->timer);
} else if (dev->if_port == 3 || dev->if_port == 5) {
if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21143 %s link beat %s.\n",
- dev->name, medianame[dev->if_port],
- (csr12 & 2) ? "failed" : "good");
+ dev_info(&dev->dev, "21143 %s link beat %s\n",
+ medianame[dev->if_port],
+ (csr12 & 2) ? "failed" : "good");
if ((csr12 & 2) && ! tp->medialock) {
del_timer_sync(&tp->timer);
t21142_start_nway(dev);
@@ -232,21 +237,18 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
iowrite32(csr14 & ~0x080, ioaddr + CSR14);
} else if (dev->if_port == 0 || dev->if_port == 4) {
if ((csr12 & 4) == 0)
- printk(KERN_INFO"%s: 21143 10baseT link beat good.\n",
- dev->name);
+ dev_info(&dev->dev, "21143 10baseT link beat good\n");
} else if (!(csr12 & 4)) { /* 10mbps link beat good. */
if (tulip_debug)
- printk(KERN_INFO"%s: 21143 10mbps sensed media.\n",
- dev->name);
+ dev_info(&dev->dev, "21143 10mbps sensed media\n");
dev->if_port = 0;
} else if (tp->nwayset) {
if (tulip_debug)
- printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n",
- dev->name, medianame[dev->if_port], tp->csr6);
+ dev_info(&dev->dev, "21143 using NWay-set %s, csr6 %08x\n",
+ medianame[dev->if_port], tp->csr6);
} else { /* 100mbps link beat good. */
if (tulip_debug)
- printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n",
- dev->name);
+ dev_info(&dev->dev, "21143 100baseTx sensed media\n");
dev->if_port = 3;
tp->csr6 = 0x838E0000 | (tp->csr6 & 0x20ff);
iowrite32(0x0003FF7F, ioaddr + CSR14);
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index d4255d44cb75..cb429723b2c8 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -337,7 +337,7 @@ static void de21041_media_timer (unsigned long data);
static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media);
-static struct pci_device_id de_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(de_pci_tbl) = {
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
@@ -382,9 +382,9 @@ static void de_rx_err_acct (struct de_private *de, unsigned rx_tail,
/* Ingore earlier buffers. */
if ((status & 0xffff) != 0x7fff) {
if (netif_msg_rx_err(de))
- printk(KERN_WARNING "%s: Oversized Ethernet frame "
- "spanned multiple buffers, status %8.8x!\n",
- de->dev->name, status);
+ dev_warn(&de->dev->dev,
+ "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
+ status);
de->net_stats.rx_length_errors++;
}
} else if (status & RxError) {
@@ -487,7 +487,7 @@ rx_next:
}
if (!rx_work)
- printk(KERN_WARNING "%s: rx work limit reached\n", de->dev->name);
+ dev_warn(&de->dev->dev, "rx work limit reached\n");
de->rx_tail = rx_tail;
}
@@ -504,7 +504,8 @@ static irqreturn_t de_interrupt (int irq, void *dev_instance)
if (netif_msg_intr(de))
printk(KERN_DEBUG "%s: intr, status %08x mode %08x desc %u/%u/%u\n",
- dev->name, status, dr32(MacMode), de->rx_tail, de->tx_head, de->tx_tail);
+ dev->name, status, dr32(MacMode),
+ de->rx_tail, de->tx_head, de->tx_tail);
dw32(MacStatus, status);
@@ -529,8 +530,9 @@ static irqreturn_t de_interrupt (int irq, void *dev_instance)
pci_read_config_word(de->pdev, PCI_STATUS, &pci_status);
pci_write_config_word(de->pdev, PCI_STATUS, pci_status);
- printk(KERN_ERR "%s: PCI bus error, status=%08x, PCI status=%04x\n",
- dev->name, status, pci_status);
+ dev_err(&de->dev->dev,
+ "PCI bus error, status=%08x, PCI status=%04x\n",
+ status, pci_status);
}
return IRQ_HANDLED;
@@ -582,7 +584,8 @@ static void de_tx (struct de_private *de)
de->net_stats.tx_packets++;
de->net_stats.tx_bytes += skb->len;
if (netif_msg_tx_done(de))
- printk(KERN_DEBUG "%s: tx done, slot %d\n", de->dev->name, tx_tail);
+ printk(KERN_DEBUG "%s: tx done, slot %d\n",
+ de->dev->name, tx_tail);
}
dev_kfree_skb_irq(skb);
}
@@ -674,18 +677,17 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev)
memset(hash_table, 0, sizeof(hash_table));
set_bit_le(255, hash_table); /* Broadcast entry */
/* This should work on big-endian machines as well. */
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int index = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff;
set_bit_le(index, hash_table);
+ }
- for (i = 0; i < 32; i++) {
- *setup_frm++ = hash_table[i];
- *setup_frm++ = hash_table[i];
- }
- setup_frm = &de->setup_frame[13*6];
+ for (i = 0; i < 32; i++) {
+ *setup_frm++ = hash_table[i];
+ *setup_frm++ = hash_table[i];
}
+ setup_frm = &de->setup_frame[13*6];
/* Fill the final entry with our physical address. */
eaddrs = (u16 *)dev->dev_addr;
@@ -698,20 +700,18 @@ static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev)
{
struct de_private *de = netdev_priv(dev);
struct dev_mc_list *mclist;
- int i;
u16 *eaddrs;
/* We have <= 14 addresses so we can use the wonderful
16 address perfect filtering of the Tulip. */
- for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
eaddrs = (u16 *)mclist->dmi_addr;
*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
}
/* Fill the unused entries with the broadcast address. */
- memset(setup_frm, 0xff, (15-i)*12);
+ memset(setup_frm, 0xff, (15 - netdev_mc_count(dev)) * 12);
setup_frm = &de->setup_frame[15*6];
/* Fill the final entry with our physical address. */
@@ -738,7 +738,7 @@ static void __de_set_rx_mode (struct net_device *dev)
goto out;
}
- if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
+ if ((netdev_mc_count(dev) > 1000) || (dev->flags & IFF_ALLMULTI)) {
/* Too many to filter well -- accept all multicasts. */
macmode |= AcceptAllMulticast;
goto out;
@@ -746,7 +746,7 @@ static void __de_set_rx_mode (struct net_device *dev)
/* Note that only the low-address shortword of setup_frame is valid!
The values are doubled for big-endian architectures. */
- if (dev->mc_count > 14) /* Must use a multicast hash table. */
+ if (netdev_mc_count(dev) > 14) /* Must use a multicast hash table. */
build_setup_frame_hash (de->setup_frame, dev);
else
build_setup_frame_perfect (de->setup_frame, dev);
@@ -870,7 +870,7 @@ static void de_stop_rxtx (struct de_private *de)
udelay(100);
}
- printk(KERN_WARNING "%s: timeout expired stopping DMA\n", de->dev->name);
+ dev_warn(&de->dev->dev, "timeout expired stopping DMA\n");
}
static inline void de_start_rxtx (struct de_private *de)
@@ -905,8 +905,8 @@ static void de_link_up(struct de_private *de)
if (!netif_carrier_ok(de->dev)) {
netif_carrier_on(de->dev);
if (netif_msg_link(de))
- printk(KERN_INFO "%s: link up, media %s\n",
- de->dev->name, media_name[de->media_type]);
+ dev_info(&de->dev->dev, "link up, media %s\n",
+ media_name[de->media_type]);
}
}
@@ -915,7 +915,7 @@ static void de_link_down(struct de_private *de)
if (netif_carrier_ok(de->dev)) {
netif_carrier_off(de->dev);
if (netif_msg_link(de))
- printk(KERN_INFO "%s: link down\n", de->dev->name);
+ dev_info(&de->dev->dev, "link down\n");
}
}
@@ -925,7 +925,8 @@ static void de_set_media (struct de_private *de)
u32 macmode = dr32(MacMode);
if (de_is_running(de))
- printk(KERN_WARNING "%s: chip is running while changing media!\n", de->dev->name);
+ dev_warn(&de->dev->dev,
+ "chip is running while changing media!\n");
if (de->de21040)
dw32(CSR11, FULL_DUPLEX_MAGIC);
@@ -945,15 +946,15 @@ static void de_set_media (struct de_private *de)
macmode &= ~FullDuplex;
if (netif_msg_link(de)) {
- printk(KERN_INFO
- "%s: set link %s\n"
- "%s: mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n"
- "%s: set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
- de->dev->name, media_name[media],
- de->dev->name, dr32(MacMode), dr32(SIAStatus),
- dr32(CSR13), dr32(CSR14), dr32(CSR15),
- de->dev->name, macmode, de->media[media].csr13,
- de->media[media].csr14, de->media[media].csr15);
+ dev_info(&de->dev->dev, "set link %s\n", media_name[media]);
+ dev_info(&de->dev->dev, "mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n",
+ dr32(MacMode), dr32(SIAStatus),
+ dr32(CSR13), dr32(CSR14), dr32(CSR15));
+
+ dev_info(&de->dev->dev,
+ "set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
+ macmode, de->media[media].csr13,
+ de->media[media].csr14, de->media[media].csr15);
}
if (macmode != dr32(MacMode))
dw32(MacMode, macmode);
@@ -992,9 +993,8 @@ static void de21040_media_timer (unsigned long data)
de_link_up(de);
else
if (netif_msg_timer(de))
- printk(KERN_INFO "%s: %s link ok, status %x\n",
- dev->name, media_name[de->media_type],
- status);
+ dev_info(&dev->dev, "%s link ok, status %x\n",
+ media_name[de->media_type], status);
return;
}
@@ -1022,8 +1022,8 @@ no_link_yet:
add_timer(&de->media_timer);
if (netif_msg_timer(de))
- printk(KERN_INFO "%s: no link, trying media %s, status %x\n",
- dev->name, media_name[de->media_type], status);
+ dev_info(&dev->dev, "no link, trying media %s, status %x\n",
+ media_name[de->media_type], status);
}
static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media)
@@ -1079,9 +1079,10 @@ static void de21041_media_timer (unsigned long data)
de_link_up(de);
else
if (netif_msg_timer(de))
- printk(KERN_INFO "%s: %s link ok, mode %x status %x\n",
- dev->name, media_name[de->media_type],
- dr32(MacMode), status);
+ dev_info(&dev->dev,
+ "%s link ok, mode %x status %x\n",
+ media_name[de->media_type],
+ dr32(MacMode), status);
return;
}
@@ -1150,8 +1151,8 @@ no_link_yet:
add_timer(&de->media_timer);
if (netif_msg_timer(de))
- printk(KERN_INFO "%s: no link, trying media %s, status %x\n",
- dev->name, media_name[de->media_type], status);
+ dev_info(&dev->dev, "no link, trying media %s, status %x\n",
+ media_name[de->media_type], status);
}
static void de_media_interrupt (struct de_private *de, u32 status)
@@ -1378,8 +1379,7 @@ static int de_open (struct net_device *dev)
rc = de_alloc_rings(de);
if (rc) {
- printk(KERN_ERR "%s: ring allocation failure, err=%d\n",
- dev->name, rc);
+ dev_err(&dev->dev, "ring allocation failure, err=%d\n", rc);
return rc;
}
@@ -1387,15 +1387,14 @@ static int de_open (struct net_device *dev)
rc = request_irq(dev->irq, de_interrupt, IRQF_SHARED, dev->name, dev);
if (rc) {
- printk(KERN_ERR "%s: IRQ %d request failure, err=%d\n",
- dev->name, dev->irq, rc);
+ dev_err(&dev->dev, "IRQ %d request failure, err=%d\n",
+ dev->irq, rc);
goto err_out_free;
}
rc = de_init_hw(de);
if (rc) {
- printk(KERN_ERR "%s: h/w init failure, err=%d\n",
- dev->name, rc);
+ dev_err(&dev->dev, "h/w init failure, err=%d\n", rc);
goto err_out_free_irq;
}
@@ -1666,8 +1665,8 @@ static int de_nway_reset(struct net_device *dev)
status = dr32(SIAStatus);
dw32(SIAStatus, (status & ~NWayState) | NWayRestart);
if (netif_msg_link(de))
- printk(KERN_INFO "%s: link nway restart, status %x,%x\n",
- de->dev->name, status, dr32(SIAStatus));
+ dev_info(&de->dev->dev, "link nway restart, status %x,%x\n",
+ status, dr32(SIAStatus));
return 0;
}
@@ -1711,7 +1710,7 @@ static void __devinit de21040_get_mac_address (struct de_private *de)
de->dev->dev_addr[i] = value;
udelay(1);
if (boguscnt <= 0)
- printk(KERN_WARNING PFX "timeout reading 21040 MAC address byte %u\n", i);
+ pr_warning(PFX "timeout reading 21040 MAC address byte %u\n", i);
}
}
@@ -1830,9 +1829,8 @@ static void __devinit de21041_get_srom_info (struct de_private *de)
}
if (netif_msg_probe(de))
- printk(KERN_INFO "de%d: SROM leaf offset %u, default media %s\n",
- de->board_idx, ofs,
- media_name[de->media_type]);
+ pr_info("de%d: SROM leaf offset %u, default media %s\n",
+ de->board_idx, ofs, media_name[de->media_type]);
/* init SIA register values to defaults */
for (i = 0; i < DE_MAX_MEDIA; i++) {
@@ -1879,9 +1877,9 @@ static void __devinit de21041_get_srom_info (struct de_private *de)
de->media[idx].type = idx;
if (netif_msg_probe(de))
- printk(KERN_INFO "de%d: media block #%u: %s",
- de->board_idx, i,
- media_name[de->media[idx].type]);
+ pr_info("de%d: media block #%u: %s",
+ de->board_idx, i,
+ media_name[de->media[idx].type]);
bufp += sizeof (ib->opts);
@@ -1893,13 +1891,13 @@ static void __devinit de21041_get_srom_info (struct de_private *de)
sizeof(ib->csr15);
if (netif_msg_probe(de))
- printk(" (%x,%x,%x)\n",
- de->media[idx].csr13,
- de->media[idx].csr14,
- de->media[idx].csr15);
+ pr_cont(" (%x,%x,%x)\n",
+ de->media[idx].csr13,
+ de->media[idx].csr14,
+ de->media[idx].csr15);
} else if (netif_msg_probe(de))
- printk("\n");
+ pr_cont("\n");
if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3]))
break;
@@ -2005,7 +2003,7 @@ static int __devinit de_init_one (struct pci_dev *pdev,
/* check for invalid IRQ value */
if (pdev->irq < 2) {
rc = -EIO;
- printk(KERN_ERR PFX "invalid irq (%d) for pci dev %s\n",
+ pr_err(PFX "invalid irq (%d) for pci dev %s\n",
pdev->irq, pci_name(pdev));
goto err_out_res;
}
@@ -2016,14 +2014,14 @@ static int __devinit de_init_one (struct pci_dev *pdev,
pciaddr = pci_resource_start(pdev, 1);
if (!pciaddr) {
rc = -EIO;
- printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n",
- pci_name(pdev));
+ pr_err(PFX "no MMIO resource for pci dev %s\n", pci_name(pdev));
goto err_out_res;
}
if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) {
rc = -EIO;
- printk(KERN_ERR PFX "MMIO resource (%llx) too small on pci dev %s\n",
- (unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev));
+ pr_err(PFX "MMIO resource (%llx) too small on pci dev %s\n",
+ (unsigned long long)pci_resource_len(pdev, 1),
+ pci_name(pdev));
goto err_out_res;
}
@@ -2031,9 +2029,9 @@ static int __devinit de_init_one (struct pci_dev *pdev,
regs = ioremap_nocache(pciaddr, DE_REGS_SIZE);
if (!regs) {
rc = -EIO;
- printk(KERN_ERR PFX "Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n",
- (unsigned long long)pci_resource_len(pdev, 1),
- pciaddr, pci_name(pdev));
+ pr_err(PFX "Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n",
+ (unsigned long long)pci_resource_len(pdev, 1),
+ pciaddr, pci_name(pdev));
goto err_out_res;
}
dev->base_addr = (unsigned long) regs;
@@ -2044,8 +2042,7 @@ static int __devinit de_init_one (struct pci_dev *pdev,
/* make sure hardware is not running */
rc = de_reset_mac(de);
if (rc) {
- printk(KERN_ERR PFX "Cannot reset MAC, pci dev %s\n",
- pci_name(pdev));
+ pr_err(PFX "Cannot reset MAC, pci dev %s\n", pci_name(pdev));
goto err_out_iomap;
}
@@ -2065,12 +2062,11 @@ static int __devinit de_init_one (struct pci_dev *pdev,
goto err_out_iomap;
/* print info about board and interface just registered */
- printk (KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n",
- dev->name,
- de->de21040 ? "21040" : "21041",
- dev->base_addr,
- dev->dev_addr,
- dev->irq);
+ dev_info(&dev->dev, "%s at 0x%lx, %pM, IRQ %d\n",
+ de->de21040 ? "21040" : "21041",
+ dev->base_addr,
+ dev->dev_addr,
+ dev->irq);
pci_set_drvdata(pdev, dev);
@@ -2158,8 +2154,7 @@ static int de_resume (struct pci_dev *pdev)
if (!netif_running(dev))
goto out_attach;
if ((retval = pci_enable_device(pdev))) {
- printk (KERN_ERR "%s: pci_enable_device failed in resume\n",
- dev->name);
+ dev_err(&dev->dev, "pci_enable_device failed in resume\n");
goto out;
}
de_init_hw(de);
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index a8349b7200b5..c4ecb9a95409 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -1951,9 +1951,9 @@ static void
SetMulticastFilter(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
- struct dev_mc_list *dmi=dev->mc_list;
+ struct dev_mc_list *dmi;
u_long iobase = dev->base_addr;
- int i, j, bit, byte;
+ int i, bit, byte;
u16 hashcode;
u32 omr, crc;
char *pa;
@@ -1963,12 +1963,11 @@ SetMulticastFilter(struct net_device *dev)
omr &= ~(OMR_PR | OMR_PM);
pa = build_setup_frame(dev, ALL); /* Build the basic frame */
- if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) {
+ if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 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;
+ netdev_for_each_mc_addr(dmi, dev) {
+ addrs = dmi->dmi_addr;
if ((*addrs & 0x01) == 1) { /* multicast address? */
crc = ether_crc_le(ETH_ALEN, addrs);
hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */
@@ -1984,9 +1983,8 @@ SetMulticastFilter(struct net_device *dev)
}
}
} else { /* Perfect filtering */
- for (j=0; j<dev->mc_count; j++) {
- addrs=dmi->dmi_addr;
- dmi=dmi->next;
+ netdev_for_each_mc_addr(dmi, dev) {
+ addrs = dmi->dmi_addr;
for (i=0; i<ETH_ALEN; i++) {
*(pa + (i&1)) = *addrs++;
if (i & 0x01) pa += 4;
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 6f44ebf58910..95b38d803e9b 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -61,6 +61,8 @@
Test and make sure PCI latency is now correct for all cases.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define DRV_NAME "dmfe"
#define DRV_VERSION "1.36.4"
#define DRV_RELDATE "2002-01-17"
@@ -149,16 +151,17 @@
#define DMFE_TX_TIMEOUT ((3*HZ)/2) /* tx packet time-out time 1.5 s" */
#define DMFE_TX_KICK (HZ/2) /* tx packet Kick-out time 0.5 s" */
-#define DMFE_DBUG(dbug_now, msg, value) \
- do { \
- if (dmfe_debug || (dbug_now)) \
- printk(KERN_ERR DRV_NAME ": %s %lx\n",\
- (msg), (long) (value)); \
+#define DMFE_DBUG(dbug_now, msg, value) \
+ do { \
+ if (dmfe_debug || (dbug_now)) \
+ pr_err("%s %lx\n", \
+ (msg), (long) (value)); \
} while (0)
-#define SHOW_MEDIA_TYPE(mode) \
- printk (KERN_INFO DRV_NAME ": Change Speed to %sMhz %s duplex\n" , \
- (mode & 1) ? "100":"10", (mode & 4) ? "full":"half");
+#define SHOW_MEDIA_TYPE(mode) \
+ pr_info("Change Speed to %sMhz %s duplex\n" , \
+ (mode & 1) ? "100":"10", \
+ (mode & 4) ? "full":"half");
/* CR9 definition: SROM/MII */
@@ -327,8 +330,8 @@ static void poll_dmfe (struct net_device *dev);
static void dmfe_descriptor_init(struct dmfe_board_info *, unsigned long);
static void allocate_rx_buffer(struct dmfe_board_info *);
static void update_cr6(u32, unsigned long);
-static void send_filter_frame(struct DEVICE * ,int);
-static void dm9132_id_table(struct DEVICE * ,int);
+static void send_filter_frame(struct DEVICE *);
+static void dm9132_id_table(struct DEVICE *);
static u16 phy_read(unsigned long, u8, u8, u32);
static void phy_write(unsigned long, u8, u8, u16, u32);
static void phy_write_1bit(unsigned long, u32);
@@ -391,8 +394,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
struct device_node *dp = pci_device_to_OF_node(pdev);
if (dp && of_get_property(dp, "local-mac-address", NULL)) {
- printk(KERN_INFO DRV_NAME
- ": skipping on-board DM910x (use tulip)\n");
+ pr_info("skipping on-board DM910x (use tulip)\n");
return -ENODEV;
}
}
@@ -405,8 +407,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
- printk(KERN_WARNING DRV_NAME
- ": 32-bit PCI DMA not available.\n");
+ pr_warning("32-bit PCI DMA not available\n");
err = -ENODEV;
goto err_out_free;
}
@@ -417,13 +418,13 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
goto err_out_free;
if (!pci_resource_start(pdev, 0)) {
- printk(KERN_ERR DRV_NAME ": I/O base is zero\n");
+ pr_err("I/O base is zero\n");
err = -ENODEV;
goto err_out_disable;
}
if (pci_resource_len(pdev, 0) < (CHK_IO_SIZE(pdev)) ) {
- printk(KERN_ERR DRV_NAME ": Allocated I/O size too small\n");
+ pr_err("Allocated I/O size too small\n");
err = -ENODEV;
goto err_out_disable;
}
@@ -438,7 +439,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
#endif
if (pci_request_regions(pdev, DRV_NAME)) {
- printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n");
+ pr_err("Failed to request PCI regions\n");
err = -ENODEV;
goto err_out_disable;
}
@@ -497,12 +498,9 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
if (err)
goto err_out_free_buf;
- printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, %pM, irq %d.\n",
- dev->name,
- ent->driver_data >> 16,
- pci_name(pdev),
- dev->dev_addr,
- dev->irq);
+ dev_info(&dev->dev, "Davicom DM%04lx at pci%s, %pM, irq %d\n",
+ ent->driver_data >> 16,
+ pci_name(pdev), dev->dev_addr, dev->irq);
pci_set_master(pdev);
@@ -660,9 +658,9 @@ static void dmfe_init_dm910x(struct DEVICE *dev)
/* Send setup frame */
if (db->chip_id == PCI_DM9132_ID)
- dm9132_id_table(dev, dev->mc_count); /* DM9132 */
+ dm9132_id_table(dev); /* DM9132 */
else
- send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */
+ send_filter_frame(dev); /* DM9102/DM9102A */
/* Init CR7, interrupt active bit */
db->cr7_data = CR7_DEFAULT;
@@ -696,7 +694,7 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
/* Too large packet check */
if (skb->len > MAX_PACKET_SIZE) {
- printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
+ pr_err("big packet = %d\n", (u16)skb->len);
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -706,8 +704,7 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
/* No Tx resource check, it never happen nromally */
if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
spin_unlock_irqrestore(&db->lock, flags);
- printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n",
- db->tx_queue_cnt);
+ pr_err("No Tx resource %ld\n", db->tx_queue_cnt);
return NETDEV_TX_BUSY;
}
@@ -779,12 +776,11 @@ static int dmfe_stop(struct DEVICE *dev)
#if 0
/* show statistic counter */
- printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx"
- " LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
- db->tx_fifo_underrun, db->tx_excessive_collision,
- db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
- db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
- db->reset_fatal, db->reset_TXtimeout);
+ printk("FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
+ db->tx_fifo_underrun, db->tx_excessive_collision,
+ db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
+ db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
+ db->reset_fatal, db->reset_TXtimeout);
#endif
return 0;
@@ -885,7 +881,7 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
txptr = db->tx_remove_ptr;
while(db->tx_packet_cnt) {
tdes0 = le32_to_cpu(txptr->tdes0);
- /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
+ pr_debug("tdes0=%x\n", tdes0);
if (tdes0 & 0x80000000)
break;
@@ -895,7 +891,7 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
/* Transmit statistic counter */
if ( tdes0 != 0x7fffffff ) {
- /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
+ pr_debug("tdes0=%x\n", tdes0);
dev->stats.collisions += (tdes0 >> 3) & 0xf;
dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
if (tdes0 & TDES0_ERR_MASK) {
@@ -992,7 +988,7 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
/* error summary bit check */
if (rdes0 & 0x8000) {
/* This is a error packet */
- //printk(DRV_NAME ": rdes0: %lx\n", rdes0);
+ pr_debug("rdes0: %x\n", rdes0);
dev->stats.rx_errors++;
if (rdes0 & 1)
dev->stats.rx_fifo_errors++;
@@ -1056,6 +1052,7 @@ static void dmfe_set_filter_mode(struct DEVICE * dev)
{
struct dmfe_board_info *db = netdev_priv(dev);
unsigned long flags;
+ int mc_count = netdev_mc_count(dev);
DMFE_DBUG(0, "dmfe_set_filter_mode()", 0);
spin_lock_irqsave(&db->lock, flags);
@@ -1068,19 +1065,19 @@ static void dmfe_set_filter_mode(struct DEVICE * dev)
return;
}
- if (dev->flags & IFF_ALLMULTI || dev->mc_count > DMFE_MAX_MULTICAST) {
- DMFE_DBUG(0, "Pass all multicast address", dev->mc_count);
+ if (dev->flags & IFF_ALLMULTI || mc_count > DMFE_MAX_MULTICAST) {
+ DMFE_DBUG(0, "Pass all multicast address", mc_count);
db->cr6_data &= ~(CR6_PM | CR6_PBF);
db->cr6_data |= CR6_PAM;
spin_unlock_irqrestore(&db->lock, flags);
return;
}
- DMFE_DBUG(0, "Set multicast address", dev->mc_count);
+ DMFE_DBUG(0, "Set multicast address", mc_count);
if (db->chip_id == PCI_DM9132_ID)
- dm9132_id_table(dev, dev->mc_count); /* DM9132 */
+ dm9132_id_table(dev); /* DM9132 */
else
- send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */
+ send_filter_frame(dev); /* DM9102/DM9102A */
spin_unlock_irqrestore(&db->lock, flags);
}
@@ -1191,8 +1188,7 @@ static void dmfe_timer(unsigned long data)
if ( time_after(jiffies, dev->trans_start + DMFE_TX_TIMEOUT) ) {
db->reset_TXtimeout++;
db->wait_reset = 1;
- printk(KERN_WARNING "%s: Tx timeout - resetting\n",
- dev->name);
+ dev_warn(&dev->dev, "Tx timeout - resetting\n");
}
}
@@ -1456,7 +1452,7 @@ static void update_cr6(u32 cr6_data, unsigned long ioaddr)
* This setup frame initilize DM910X address filter mode
*/
-static void dm9132_id_table(struct DEVICE *dev, int mc_cnt)
+static void dm9132_id_table(struct DEVICE *dev)
{
struct dev_mc_list *mcptr;
u16 * addrptr;
@@ -1476,15 +1472,14 @@ static void dm9132_id_table(struct DEVICE *dev, int mc_cnt)
ioaddr += 4;
/* Clear Hash Table */
- for (i = 0; i < 4; i++)
- hash_table[i] = 0x0;
+ memset(hash_table, 0, sizeof(hash_table));
/* broadcast address */
hash_table[3] = 0x8000;
/* the multicast address in Hash Table : 64 bits */
- for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
- hash_val = cal_CRC( (char *) mcptr->dmi_addr, 6, 0) & 0x3f;
+ netdev_for_each_mc_addr(mcptr, dev) {
+ hash_val = cal_CRC((char *) mcptr->dmi_addr, 6, 0) & 0x3f;
hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
}
@@ -1499,7 +1494,7 @@ static void dm9132_id_table(struct DEVICE *dev, int mc_cnt)
* This setup frame initilize DM910X address filter mode
*/
-static void send_filter_frame(struct DEVICE *dev, int mc_cnt)
+static void send_filter_frame(struct DEVICE *dev)
{
struct dmfe_board_info *db = netdev_priv(dev);
struct dev_mc_list *mcptr;
@@ -1525,14 +1520,14 @@ static void send_filter_frame(struct DEVICE *dev, int mc_cnt)
*suptr++ = 0xffff;
/* fit the multicast address */
- for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
+ netdev_for_each_mc_addr(mcptr, dev) {
addrptr = (u16 *) mcptr->dmi_addr;
*suptr++ = addrptr[0];
*suptr++ = addrptr[1];
*suptr++ = addrptr[2];
}
- for (; i<14; i++) {
+ for (i = netdev_mc_count(dev); i < 14; i++) {
*suptr++ = 0xffff;
*suptr++ = 0xffff;
*suptr++ = 0xffff;
@@ -1646,7 +1641,7 @@ static u8 dmfe_sense_speed(struct dmfe_board_info * db)
else /* DM9102/DM9102A */
phy_mode = phy_read(db->ioaddr,
db->phy_addr, 17, db->chip_id) & 0xf000;
- /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */
+ pr_debug("Phy_mode %x\n", phy_mode);
switch (phy_mode) {
case 0x1000: db->op_mode = DMFE_10MHF; break;
case 0x2000: db->op_mode = DMFE_10MFD; break;
@@ -2089,7 +2084,7 @@ static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
-static struct pci_device_id dmfe_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(dmfe_pci_tbl) = {
{ 0x1282, 0x9132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9132_ID },
{ 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID },
{ 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID },
diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
index 889f57aae89b..49f05d1431f5 100644
--- a/drivers/net/tulip/eeprom.c
+++ b/drivers/net/tulip/eeprom.c
@@ -143,6 +143,12 @@ static void __devinit tulip_build_fake_mediatable(struct tulip_private *tp)
void __devinit tulip_parse_eeprom(struct net_device *dev)
{
+ /*
+ dev is not registered at this point, so logging messages can't
+ use dev_<level> or netdev_<level> but dev->name is good via a
+ hack in the caller
+ */
+
/* The last media info list parsed, for multiport boards. */
static struct mediatable *last_mediatable;
static unsigned char *last_ee_data;
@@ -161,15 +167,14 @@ void __devinit tulip_parse_eeprom(struct net_device *dev)
if (ee_data[0] == 0xff) {
if (last_mediatable) {
controller_index++;
- printk(KERN_INFO "%s: Controller %d of multiport board.\n",
- dev->name, controller_index);
+ pr_info("%s: Controller %d of multiport board\n",
+ dev->name, controller_index);
tp->mtable = last_mediatable;
ee_data = last_ee_data;
goto subsequent_board;
} else
- printk(KERN_INFO "%s: Missing EEPROM, this interface may "
- "not work correctly!\n",
- dev->name);
+ pr_info("%s: Missing EEPROM, this interface may not work correctly!\n",
+ dev->name);
return;
}
/* Do a fix-up based on the vendor half of the station address prefix. */
@@ -181,16 +186,14 @@ void __devinit tulip_parse_eeprom(struct net_device *dev)
i++; /* An Accton EN1207, not an outlaw Maxtech. */
memcpy(ee_data + 26, eeprom_fixups[i].newtable,
sizeof(eeprom_fixups[i].newtable));
- printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using"
- " substitute media control info.\n",
- dev->name, eeprom_fixups[i].name);
+ pr_info("%s: Old format EEPROM on '%s' board. Using substitute media control info\n",
+ dev->name, eeprom_fixups[i].name);
break;
}
}
if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
- printk(KERN_INFO "%s: Old style EEPROM with no media selection "
- "information.\n",
- dev->name);
+ pr_info("%s: Old style EEPROM with no media selection information\n",
+ dev->name);
return;
}
}
@@ -218,7 +221,8 @@ subsequent_board:
/* there is no phy information, don't even try to build mtable */
if (count == 0) {
if (tulip_debug > 0)
- printk(KERN_WARNING "%s: no phy info, aborting mtable build\n", dev->name);
+ pr_warning("%s: no phy info, aborting mtable build\n",
+ dev->name);
return;
}
@@ -234,8 +238,10 @@ subsequent_board:
mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0;
mtable->csr15dir = mtable->csr15val = 0;
- printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name,
- media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]);
+ pr_info("%s: EEPROM default media type %s\n",
+ dev->name,
+ media & 0x0800 ? "Autosense"
+ : medianame[media & MEDIA_MASK]);
for (i = 0; i < count; i++) {
struct medialeaf *leaf = &mtable->mleaf[i];
@@ -298,16 +304,17 @@ subsequent_board:
}
if (tulip_debug > 1 && leaf->media == 11) {
unsigned char *bp = leaf->leafdata;
- printk(KERN_INFO "%s: MII interface PHY %d, setup/reset "
- "sequences %d/%d long, capabilities %2.2x %2.2x.\n",
- dev->name, bp[0], bp[1], bp[2 + bp[1]*2],
- bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
+ pr_info("%s: MII interface PHY %d, setup/reset sequences %d/%d long, capabilities %02x %02x\n",
+ dev->name,
+ bp[0], bp[1], bp[2 + bp[1]*2],
+ bp[5 + bp[2 + bp[1]*2]*2],
+ bp[4 + bp[2 + bp[1]*2]*2]);
}
- printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described "
- "by a %s (%d) block.\n",
- dev->name, i, medianame[leaf->media & 15], leaf->media,
- leaf->type < ARRAY_SIZE(block_name) ? block_name[leaf->type] : "<unknown>",
- leaf->type);
+ pr_info("%s: Index #%d - Media %s (#%d) described by a %s (%d) block\n",
+ dev->name,
+ i, medianame[leaf->media & 15], leaf->media,
+ leaf->type < ARRAY_SIZE(block_name) ? block_name[leaf->type] : "<unknown>",
+ leaf->type);
}
if (new_advertise)
tp->sym_advertise = new_advertise;
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 2e8e8ee893c7..1faf7a4d7202 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -125,12 +125,12 @@ int tulip_poll(struct napi_struct *napi, int budget)
#endif
if (tulip_debug > 4)
- printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
- tp->rx_ring[entry].status);
+ printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n",
+ entry, tp->rx_ring[entry].status);
do {
if (ioread32(tp->base_addr + CSR5) == 0xffffffff) {
- printk(KERN_DEBUG " In tulip_poll(), hardware disappeared.\n");
+ printk(KERN_DEBUG " In tulip_poll(), hardware disappeared\n");
break;
}
/* Acknowledge current RX interrupt sources. */
@@ -146,7 +146,7 @@ int tulip_poll(struct napi_struct *napi, int budget)
break;
if (tulip_debug > 5)
- printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
+ printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n",
dev->name, entry, status);
if (++work_done >= budget)
@@ -177,15 +177,15 @@ int tulip_poll(struct napi_struct *napi, int budget)
/* Ingore earlier buffers. */
if ((status & 0xffff) != 0x7fff) {
if (tulip_debug > 1)
- printk(KERN_WARNING "%s: Oversized Ethernet frame "
- "spanned multiple buffers, status %8.8x!\n",
- dev->name, status);
+ dev_warn(&dev->dev,
+ "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
+ status);
tp->stats.rx_length_errors++;
}
} else {
/* There was a fatal error. */
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
+ printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n",
dev->name, status);
tp->stats.rx_errors++; /* end of a packet.*/
if (pkt_len > 1518 ||
@@ -226,12 +226,11 @@ int tulip_poll(struct napi_struct *napi, int budget)
#ifndef final_version
if (tp->rx_buffers[entry].mapping !=
le32_to_cpu(tp->rx_ring[entry].buffer1)) {
- printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
- "do not match in tulip_rx: %08x vs. %08llx %p / %p.\n",
- dev->name,
- le32_to_cpu(tp->rx_ring[entry].buffer1),
- (unsigned long long)tp->rx_buffers[entry].mapping,
- skb->head, temp);
+ dev_err(&dev->dev,
+ "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %08llx %p / %p\n",
+ le32_to_cpu(tp->rx_ring[entry].buffer1),
+ (unsigned long long)tp->rx_buffers[entry].mapping,
+ skb->head, temp);
}
#endif
@@ -365,16 +364,16 @@ static int tulip_rx(struct net_device *dev)
int received = 0;
if (tulip_debug > 4)
- printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
- tp->rx_ring[entry].status);
+ printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n",
+ entry, tp->rx_ring[entry].status);
/* 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);
short pkt_len;
if (tulip_debug > 5)
- printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
- dev->name, entry, status);
+ printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n",
+ dev->name, entry, status);
if (--rx_work_limit < 0)
break;
@@ -402,16 +401,16 @@ static int tulip_rx(struct net_device *dev)
/* Ingore earlier buffers. */
if ((status & 0xffff) != 0x7fff) {
if (tulip_debug > 1)
- printk(KERN_WARNING "%s: Oversized Ethernet frame "
- "spanned multiple buffers, status %8.8x!\n",
- dev->name, status);
+ dev_warn(&dev->dev,
+ "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
+ status);
tp->stats.rx_length_errors++;
}
} else {
/* There was a fatal error. */
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
- dev->name, status);
+ printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n",
+ dev->name, status);
tp->stats.rx_errors++; /* end of a packet.*/
if (pkt_len > 1518 ||
(status & RxDescRunt))
@@ -450,12 +449,11 @@ static int tulip_rx(struct net_device *dev)
#ifndef final_version
if (tp->rx_buffers[entry].mapping !=
le32_to_cpu(tp->rx_ring[entry].buffer1)) {
- printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
- "do not match in tulip_rx: %08x vs. %Lx %p / %p.\n",
- dev->name,
- le32_to_cpu(tp->rx_ring[entry].buffer1),
- (long long)tp->rx_buffers[entry].mapping,
- skb->head, temp);
+ dev_err(&dev->dev,
+ "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %Lx %p / %p\n",
+ le32_to_cpu(tp->rx_ring[entry].buffer1),
+ (long long)tp->rx_buffers[entry].mapping,
+ skb->head, temp);
}
#endif
@@ -569,7 +567,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
#endif /* CONFIG_TULIP_NAPI */
if (tulip_debug > 4)
- printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n",
+ printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x\n",
dev->name, csr5, ioread32(ioaddr + CSR5));
@@ -601,8 +599,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
/* There was an major error, log it. */
#ifndef final_version
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
- dev->name, status);
+ printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n",
+ dev->name, status);
#endif
tp->stats.tx_errors++;
if (status & 0x4104) tp->stats.tx_aborted_errors++;
@@ -631,8 +629,9 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
#ifndef final_version
if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
- printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d.\n",
- dev->name, dirty_tx, tp->cur_tx);
+ dev_err(&dev->dev,
+ "Out-of-sync dirty pointer, %d vs. %d\n",
+ dirty_tx, tp->cur_tx);
dirty_tx += TX_RING_SIZE;
}
#endif
@@ -643,9 +642,10 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
tp->dirty_tx = dirty_tx;
if (csr5 & TxDied) {
if (tulip_debug > 2)
- printk(KERN_WARNING "%s: The transmitter stopped."
- " CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
- dev->name, csr5, ioread32(ioaddr + CSR6), tp->csr6);
+ dev_warn(&dev->dev,
+ "The transmitter stopped. CSR5 is %x, CSR6 %x, new CSR6 %x\n",
+ csr5, ioread32(ioaddr + CSR6),
+ tp->csr6);
tulip_restart_rxtx(tp);
}
spin_unlock(&tp->lock);
@@ -696,8 +696,9 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
* to the 21142/3 docs that is).
* -- rmk
*/
- printk(KERN_ERR "%s: (%lu) System Error occurred (%d)\n",
- dev->name, tp->nir, error);
+ dev_err(&dev->dev,
+ "(%lu) System Error occurred (%d)\n",
+ tp->nir, error);
}
/* Clear all error sources, included undocumented ones! */
iowrite32(0x0800f7ba, ioaddr + CSR5);
@@ -706,16 +707,17 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
if (csr5 & TimerInt) {
if (tulip_debug > 2)
- printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
- dev->name, csr5);
+ dev_err(&dev->dev,
+ "Re-enabling interrupts, %08x\n",
+ csr5);
iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
tp->ttimer = 0;
oi++;
}
if (tx > maxtx || rx > maxrx || oi > maxoi) {
if (tulip_debug > 1)
- printk(KERN_WARNING "%s: Too much work during an interrupt, "
- "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi);
+ dev_warn(&dev->dev, "Too much work during an interrupt, csr5=0x%08x. (%lu) (%d,%d,%d)\n",
+ csr5, tp->nir, tx, rx, oi);
/* Acknowledge all interrupt sources. */
iowrite32(0x8001ffff, ioaddr + CSR5);
@@ -764,14 +766,18 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
entry = tp->dirty_rx % RX_RING_SIZE;
if (tp->rx_buffers[entry].skb == NULL) {
if (tulip_debug > 1)
- printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx);
+ dev_warn(&dev->dev,
+ "in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n",
+ tp->nir, tp->cur_rx, tp->ttimer, rx);
if (tp->chip_id == LC82C168) {
iowrite32(0x00, ioaddr + CSR7);
mod_timer(&tp->timer, RUN_AT(HZ/50));
} else {
if (tp->ttimer == 0 || (ioread32(ioaddr + CSR11) & 0xffff) == 0) {
if (tulip_debug > 1)
- printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir);
+ dev_warn(&dev->dev,
+ "in rx suspend mode: (%lu) set timer\n",
+ tp->nir);
iowrite32(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
ioaddr + CSR7);
iowrite32(TimerInt, ioaddr + CSR5);
@@ -787,8 +793,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
}
if (tulip_debug > 4)
- printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
- dev->name, ioread32(ioaddr + CSR5));
+ printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#04x\n",
+ dev->name, ioread32(ioaddr + CSR5));
return IRQ_HANDLED;
}
diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
index d8fda83705bf..68b170ae4d15 100644
--- a/drivers/net/tulip/media.c
+++ b/drivers/net/tulip/media.c
@@ -182,9 +182,8 @@ void tulip_select_media(struct net_device *dev, int startup)
switch (mleaf->type) {
case 0: /* 21140 non-MII xcvr. */
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver"
- " with control setting %2.2x.\n",
- dev->name, p[1]);
+ printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver with control setting %02x\n",
+ dev->name, p[1]);
dev->if_port = p[0];
if (startup)
iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
@@ -205,15 +204,15 @@ void tulip_select_media(struct net_device *dev, int startup)
struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
unsigned char *rst = rleaf->leafdata;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Resetting the transceiver.\n",
- dev->name);
+ printk(KERN_DEBUG "%s: Resetting the transceiver\n",
+ dev->name);
for (i = 0; i < rst[0]; i++)
iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
}
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control "
- "%4.4x/%4.4x.\n",
- dev->name, medianame[dev->if_port], setup[0], setup[1]);
+ printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control %04x/%04x\n",
+ dev->name, medianame[dev->if_port],
+ setup[0], setup[1]);
if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */
csr13val = setup[0];
csr14val = setup[1];
@@ -240,8 +239,8 @@ void tulip_select_media(struct net_device *dev, int startup)
if (startup) iowrite32(csr13val, ioaddr + CSR13);
}
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n",
- dev->name, csr15dir, csr15val);
+ printk(KERN_DEBUG "%s: Setting CSR15 to %08x/%08x\n",
+ dev->name, csr15dir, csr15val);
if (mleaf->type == 4)
new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
else
@@ -317,8 +316,9 @@ void tulip_select_media(struct net_device *dev, int startup)
if (tp->mii_advertise == 0)
tp->mii_advertise = tp->advertising[phy_num];
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Advertising %4.4x on MII %d.\n",
- dev->name, tp->mii_advertise, tp->phys[phy_num]);
+ printk(KERN_DEBUG "%s: Advertising %04x on MII %d\n",
+ dev->name, tp->mii_advertise,
+ tp->phys[phy_num]);
tulip_mdio_write(dev, tp->phys[phy_num], 4, tp->mii_advertise);
}
break;
@@ -335,8 +335,8 @@ void tulip_select_media(struct net_device *dev, int startup)
struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
unsigned char *rst = rleaf->leafdata;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Resetting the transceiver.\n",
- dev->name);
+ printk(KERN_DEBUG "%s: Resetting the transceiver\n",
+ dev->name);
for (i = 0; i < rst[0]; i++)
iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
}
@@ -344,20 +344,20 @@ void tulip_select_media(struct net_device *dev, int startup)
break;
}
default:
- printk(KERN_DEBUG "%s: Invalid media table selection %d.\n",
- dev->name, mleaf->type);
+ printk(KERN_DEBUG "%s: Invalid media table selection %d\n",
+ dev->name, mleaf->type);
new_csr6 = 0x020E0000;
}
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
- dev->name, medianame[dev->if_port],
+ printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %02x\n",
+ dev->name, medianame[dev->if_port],
ioread32(ioaddr + CSR12) & 0xff);
} else if (tp->chip_id == LC82C168) {
if (startup && ! tp->medialock)
dev->if_port = tp->mii_cnt ? 11 : 0;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n",
- dev->name, ioread32(ioaddr + 0xB8), medianame[dev->if_port]);
+ printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s\n",
+ dev->name, ioread32(ioaddr + 0xB8), medianame[dev->if_port]);
if (tp->mii_cnt) {
new_csr6 = 0x810C0000;
iowrite32(0x0001, ioaddr + CSR15);
@@ -388,10 +388,9 @@ void tulip_select_media(struct net_device *dev, int startup)
} else
new_csr6 = 0x03860000;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: No media description table, assuming "
- "%s transceiver, CSR12 %2.2x.\n",
- dev->name, medianame[dev->if_port],
- ioread32(ioaddr + CSR12));
+ printk(KERN_DEBUG "%s: No media description table, assuming %s transceiver, CSR12 %02x\n",
+ dev->name, medianame[dev->if_port],
+ ioread32(ioaddr + CSR12));
}
tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
@@ -415,16 +414,17 @@ int tulip_check_duplex(struct net_device *dev)
bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR);
lpa = tulip_mdio_read(dev, tp->phys[0], MII_LPA);
if (tulip_debug > 1)
- printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
- "%4.4x.\n", dev->name, bmsr, lpa);
+ dev_info(&dev->dev, "MII status %04x, Link partner report %04x\n",
+ bmsr, lpa);
if (bmsr == 0xffff)
return -2;
if ((bmsr & BMSR_LSTATUS) == 0) {
int new_bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR);
if ((new_bmsr & BMSR_LSTATUS) == 0) {
if (tulip_debug > 1)
- printk(KERN_INFO "%s: No link beat on the MII interface,"
- " status %4.4x.\n", dev->name, new_bmsr);
+ dev_info(&dev->dev,
+ "No link beat on the MII interface, status %04x\n",
+ new_bmsr);
return -1;
}
}
@@ -443,10 +443,10 @@ int tulip_check_duplex(struct net_device *dev)
tulip_restart_rxtx(tp);
if (tulip_debug > 0)
- printk(KERN_INFO "%s: Setting %s-duplex based on MII"
- "#%d link partner capability of %4.4x.\n",
- dev->name, tp->full_duplex ? "full" : "half",
- tp->phys[0], lpa);
+ dev_info(&dev->dev,
+ "Setting %s-duplex based on MII#%d link partner capability of %04x\n",
+ tp->full_duplex ? "full" : "half",
+ tp->phys[0], lpa);
return 1;
}
@@ -501,15 +501,13 @@ void __devinit tulip_find_mii (struct net_device *dev, int board_idx)
tp->phys[phy_idx++] = phy;
- printk (KERN_INFO "tulip%d: MII transceiver #%d "
- "config %4.4x status %4.4x advertising %4.4x.\n",
+ pr_info("tulip%d: MII transceiver #%d config %04x status %04x advertising %04x\n",
board_idx, phy, mii_reg0, mii_status, mii_advert);
/* Fixup for DLink with miswired PHY. */
if (mii_advert != to_advert) {
- printk (KERN_DEBUG "tulip%d: Advertising %4.4x on PHY %d,"
- " previously advertising %4.4x.\n",
- board_idx, to_advert, phy, mii_advert);
+ printk(KERN_DEBUG "tulip%d: Advertising %04x on PHY %d, previously advertising %04x\n",
+ board_idx, to_advert, phy, mii_advert);
tulip_mdio_write (dev, phy, 4, to_advert);
}
@@ -554,7 +552,7 @@ void __devinit tulip_find_mii (struct net_device *dev, int board_idx)
}
tp->mii_cnt = phy_idx;
if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) {
- printk (KERN_INFO "tulip%d: ***WARNING***: No MII transceiver found!\n",
+ pr_info("tulip%d: ***WARNING***: No MII transceiver found!\n",
board_idx);
tp->phys[0] = 1;
}
diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c
index d3253ed09dfc..966efa1a27d7 100644
--- a/drivers/net/tulip/pnic.c
+++ b/drivers/net/tulip/pnic.c
@@ -40,8 +40,8 @@ void pnic_do_nway(struct net_device *dev)
new_csr6 |= 0x00000200;
}
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n",
- dev->name, phy_reg, medianame[dev->if_port]);
+ printk(KERN_DEBUG "%s: PNIC autonegotiated status %08x, %s\n",
+ dev->name, phy_reg, medianame[dev->if_port]);
if (tp->csr6 != new_csr6) {
tp->csr6 = new_csr6;
/* Restart Tx */
@@ -58,8 +58,8 @@ void pnic_lnk_change(struct net_device *dev, int csr5)
int phy_reg = ioread32(ioaddr + 0xB8);
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n",
- dev->name, phy_reg, csr5);
+ printk(KERN_DEBUG "%s: PNIC link changed state %08x, CSR5 %08x\n",
+ dev->name, phy_reg, csr5);
if (ioread32(ioaddr + CSR5) & TPLnkFail) {
iowrite32((ioread32(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
/* If we use an external MII, then we mustn't use the
@@ -114,9 +114,8 @@ void pnic_timer(unsigned long data)
int csr5 = ioread32(ioaddr + CSR5);
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s "
- "CSR5 %8.8x.\n",
- dev->name, phy_reg, medianame[dev->if_port], csr5);
+ printk(KERN_DEBUG "%s: PNIC timer PHY status %08x, %s CSR5 %08x\n",
+ dev->name, phy_reg, medianame[dev->if_port], csr5);
if (phy_reg & 0x04000000) { /* Remote link fault */
iowrite32(0x0201F078, ioaddr + 0xB8);
next_tick = 1*HZ;
@@ -126,10 +125,11 @@ void pnic_timer(unsigned long data)
next_tick = 60*HZ;
} else if (csr5 & TPLnkFail) { /* 100baseTx link beat */
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
- "CSR5 %8.8x, PHY %3.3x.\n",
- dev->name, medianame[dev->if_port], csr12,
- ioread32(ioaddr + CSR5), ioread32(ioaddr + 0xB8));
+ printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %04x, CSR5 %08x, PHY %03x\n",
+ dev->name, medianame[dev->if_port],
+ csr12,
+ ioread32(ioaddr + CSR5),
+ ioread32(ioaddr + 0xB8));
next_tick = 3*HZ;
if (tp->medialock) {
} else if (tp->nwayset && (dev->if_port & 1)) {
@@ -151,10 +151,11 @@ void pnic_timer(unsigned long data)
tulip_restart_rxtx(tp);
dev->trans_start = jiffies;
if (tulip_debug > 1)
- printk(KERN_INFO "%s: Changing PNIC configuration to %s "
- "%s-duplex, CSR6 %8.8x.\n",
- dev->name, medianame[dev->if_port],
- tp->full_duplex ? "full" : "half", new_csr6);
+ dev_info(&dev->dev,
+ "Changing PNIC configuration to %s %s-duplex, CSR6 %08x\n",
+ medianame[dev->if_port],
+ tp->full_duplex ? "full" : "half",
+ new_csr6);
}
}
}
@@ -162,7 +163,7 @@ too_good_connection:
mod_timer(&tp->timer, RUN_AT(next_tick));
if(!ioread32(ioaddr + CSR7)) {
if (tulip_debug > 1)
- printk(KERN_INFO "%s: sw timer wakeup.\n", dev->name);
+ dev_info(&dev->dev, "sw timer wakeup\n");
disable_irq(dev->irq);
tulip_refill_rx(dev);
enable_irq(dev->irq);
diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c
index d8418694bf46..b8197666021e 100644
--- a/drivers/net/tulip/pnic2.c
+++ b/drivers/net/tulip/pnic2.c
@@ -87,8 +87,8 @@ void pnic2_timer(unsigned long data)
int next_tick = 60*HZ;
if (tulip_debug > 3)
- printk(KERN_INFO"%s: PNIC2 negotiation status %8.8x.\n",
- dev->name,ioread32(ioaddr + CSR12));
+ dev_info(&dev->dev, "PNIC2 negotiation status %08x\n",
+ ioread32(ioaddr + CSR12));
if (next_tick) {
mod_timer(&tp->timer, RUN_AT(next_tick));
@@ -125,8 +125,8 @@ void pnic2_start_nway(struct net_device *dev)
csr14 |= 0x00001184;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Restarting PNIC2 autonegotiation, "
- "csr14=%8.8x.\n", dev->name, csr14);
+ printk(KERN_DEBUG "%s: Restarting PNIC2 autonegotiation, csr14=%08x\n",
+ dev->name, csr14);
/* tell pnic2_lnk_change we are doing an nway negotiation */
dev->if_port = 0;
@@ -137,8 +137,8 @@ void pnic2_start_nway(struct net_device *dev)
tp->csr6 = ioread32(ioaddr + CSR6);
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: On Entry to Nway, "
- "csr6=%8.8x.\n", dev->name, tp->csr6);
+ printk(KERN_DEBUG "%s: On Entry to Nway, csr6=%08x\n",
+ dev->name, tp->csr6);
/* mask off any bits not to touch
* comment at top of file explains mask value
@@ -181,9 +181,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
int csr12 = ioread32(ioaddr + CSR12);
if (tulip_debug > 1)
- printk(KERN_INFO"%s: PNIC2 link status interrupt %8.8x, "
- " CSR5 %x, %8.8x.\n", dev->name, csr12,
- csr5, ioread32(ioaddr + CSR14));
+ dev_info(&dev->dev,
+ "PNIC2 link status interrupt %08x, CSR5 %x, %08x\n",
+ csr12, csr5, ioread32(ioaddr + CSR14));
/* If NWay finished and we have a negotiated partner capability.
* check bits 14:12 for bit pattern 101 - all is good
@@ -215,9 +215,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
else if (negotiated & 0x0020) dev->if_port = 0;
else {
if (tulip_debug > 1)
- printk(KERN_INFO "%s: funny autonegotiate result "
- "csr12 %8.8x advertising %4.4x\n",
- dev->name, csr12, tp->sym_advertise);
+ dev_info(&dev->dev,
+ "funny autonegotiate result csr12 %08x advertising %04x\n",
+ csr12, tp->sym_advertise);
tp->nwayset = 0;
/* so check if 100baseTx link state is okay */
if ((csr12 & 2) == 0 && (tp->sym_advertise & 0x0180))
@@ -231,10 +231,11 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
if (tulip_debug > 1) {
if (tp->nwayset)
- printk(KERN_INFO "%s: Switching to %s based on link "
- "negotiation %4.4x & %4.4x = %4.4x.\n",
- dev->name, medianame[dev->if_port],
- tp->sym_advertise, tp->lpar, negotiated);
+ dev_info(&dev->dev,
+ "Switching to %s based on link negotiation %04x & %04x = %04x\n",
+ medianame[dev->if_port],
+ tp->sym_advertise, tp->lpar,
+ negotiated);
}
/* remember to turn off bit 7 - autonegotiate
@@ -270,9 +271,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
iowrite32(1, ioaddr + CSR13);
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 "
- "%8.8x.\n", dev->name, tp->csr6,
- ioread32(ioaddr + CSR6), ioread32(ioaddr + CSR12));
+ printk(KERN_DEBUG "%s: Setting CSR6 %08x/%x CSR12 %08x\n",
+ dev->name, tp->csr6,
+ ioread32(ioaddr + CSR6), ioread32(ioaddr + CSR12));
/* now the following actually writes out the
* new csr6 values
@@ -282,9 +283,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
return;
} else {
- printk(KERN_INFO "%s: Autonegotiation failed, "
- "using %s, link beat status %4.4x.\n",
- dev->name, medianame[dev->if_port], csr12);
+ dev_info(&dev->dev,
+ "Autonegotiation failed, using %s, link beat status %04x\n",
+ medianame[dev->if_port], csr12);
/* remember to turn off bit 7 - autonegotiate
* enable so we don't forget
@@ -339,9 +340,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
/* we are at 100mb and a potential link change occurred */
if (tulip_debug > 1)
- printk(KERN_INFO"%s: PNIC2 %s link beat %s.\n",
- dev->name, medianame[dev->if_port],
- (csr12 & 2) ? "failed" : "good");
+ dev_info(&dev->dev, "PNIC2 %s link beat %s\n",
+ medianame[dev->if_port],
+ (csr12 & 2) ? "failed" : "good");
/* check 100 link beat */
@@ -364,9 +365,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
/* we are at 10mb and a potential link change occurred */
if (tulip_debug > 1)
- printk(KERN_INFO"%s: PNIC2 %s link beat %s.\n",
- dev->name, medianame[dev->if_port],
- (csr12 & 4) ? "failed" : "good");
+ dev_info(&dev->dev, "PNIC2 %s link beat %s\n",
+ medianame[dev->if_port],
+ (csr12 & 4) ? "failed" : "good");
tp->nway = 0;
@@ -385,7 +386,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
if (tulip_debug > 1)
- printk(KERN_INFO"%s: PNIC2 Link Change Default?\n",dev->name);
+ dev_info(&dev->dev, "PNIC2 Link Change Default?\n");
/* if all else fails default to trying 10baseT-HD */
dev->if_port = 0;
diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c
index a0e084223082..36c2725ec886 100644
--- a/drivers/net/tulip/timer.c
+++ b/drivers/net/tulip/timer.c
@@ -28,11 +28,11 @@ void tulip_media_task(struct work_struct *work)
unsigned long flags;
if (tulip_debug > 2) {
- printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode"
- " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n",
- dev->name, medianame[dev->if_port], ioread32(ioaddr + CSR5),
- ioread32(ioaddr + CSR6), csr12, ioread32(ioaddr + CSR13),
- ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));
+ printk(KERN_DEBUG "%s: Media selection tick, %s, status %08x mode %08x SIA %08x %08x %08x %08x\n",
+ dev->name, medianame[dev->if_port],
+ ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR6),
+ csr12, ioread32(ioaddr + CSR13),
+ ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));
}
switch (tp->chip_id) {
case DC21140:
@@ -48,9 +48,9 @@ void tulip_media_task(struct work_struct *work)
Assume this a generic MII or SYM transceiver. */
next_tick = 60*HZ;
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x "
- "CSR12 0x%2.2x.\n",
- dev->name, ioread32(ioaddr + CSR6), csr12 & 0xff);
+ printk(KERN_DEBUG "%s: network media monitor CSR6 %08x CSR12 0x%02x\n",
+ dev->name,
+ ioread32(ioaddr + CSR6), csr12 & 0xff);
break;
}
mleaf = &tp->mtable->mleaf[tp->cur_index];
@@ -62,9 +62,8 @@ void tulip_media_task(struct work_struct *work)
s8 bitnum = p[offset];
if (p[offset+1] & 0x80) {
if (tulip_debug > 1)
- printk(KERN_DEBUG"%s: Transceiver monitor tick "
- "CSR12=%#2.2x, no media sense.\n",
- dev->name, csr12);
+ printk(KERN_DEBUG "%s: Transceiver monitor tick CSR12=%#02x, no media sense\n",
+ dev->name, csr12);
if (mleaf->type == 4) {
if (mleaf->media == 3 && (csr12 & 0x02))
goto select_next_media;
@@ -72,16 +71,16 @@ void tulip_media_task(struct work_struct *work)
break;
}
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x"
- " bit %d is %d, expecting %d.\n",
- dev->name, csr12, (bitnum >> 1) & 7,
- (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
- (bitnum >= 0));
+ printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#02x bit %d is %d, expecting %d\n",
+ dev->name, csr12, (bitnum >> 1) & 7,
+ (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
+ (bitnum >= 0));
/* Check that the specified bit has the proper value. */
if ((bitnum < 0) !=
((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
+ printk(KERN_DEBUG "%s: Link beat detected for %s\n",
+ dev->name,
medianame[mleaf->media & MEDIA_MASK]);
if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */
goto actually_mii;
@@ -100,9 +99,9 @@ void tulip_media_task(struct work_struct *work)
if (tulip_media_cap[dev->if_port] & MediaIsFD)
goto select_next_media; /* Skip FD entries. */
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: No link beat on media %s,"
- " trying transceiver type %s.\n",
- dev->name, medianame[mleaf->media & MEDIA_MASK],
+ printk(KERN_DEBUG "%s: No link beat on media %s, trying transceiver type %s\n",
+ dev->name,
+ medianame[mleaf->media & MEDIA_MASK],
medianame[tp->mtable->mleaf[tp->cur_index].media]);
tulip_select_media(dev, 0);
/* Restart the transmit process. */
@@ -151,8 +150,8 @@ void mxic_timer(unsigned long data)
int next_tick = 60*HZ;
if (tulip_debug > 3) {
- printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
- ioread32(ioaddr + CSR12));
+ dev_info(&dev->dev, "MXIC negotiation status %08x\n",
+ ioread32(ioaddr + CSR12));
}
if (next_tick) {
mod_timer(&tp->timer, RUN_AT(next_tick));
@@ -167,11 +166,10 @@ void comet_timer(unsigned long data)
int next_tick = 60*HZ;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
- "%4.4x.\n",
- dev->name,
- tulip_mdio_read(dev, tp->phys[0], 1),
- tulip_mdio_read(dev, tp->phys[0], 5));
+ printk(KERN_DEBUG "%s: Comet link status %04x partner capability %04x\n",
+ dev->name,
+ tulip_mdio_read(dev, tp->phys[0], 1),
+ tulip_mdio_read(dev, tp->phys[0], 5));
/* mod_timer synchronizes us with potential add_timer calls
* from interrupts.
*/
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 595777dcadb1..7f544ef2f5fc 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -41,7 +41,6 @@
static char version[] __devinitdata =
"Linux Tulip driver version " DRV_VERSION " (" DRV_RELDATE ")\n";
-
/* A few user-configurable values. */
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
@@ -211,7 +210,7 @@ struct tulip_chip_table tulip_tbl[] = {
};
-static struct pci_device_id tulip_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(tulip_pci_tbl) = {
{ 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
{ 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21143 },
{ 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 },
@@ -249,6 +248,7 @@ static struct pci_device_id tulip_pci_tbl[] = {
{ 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
{ 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */
{ 0x14ea, 0xab08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* Planex FNW-3602-TX */
+ { 0x1414, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* Microsoft MN-120 */
{ 0x1414, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
{ } /* terminate list */
};
@@ -325,7 +325,8 @@ static void tulip_up(struct net_device *dev)
udelay(100);
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq);
+ printk(KERN_DEBUG "%s: tulip_up(), irq==%d\n",
+ dev->name, dev->irq);
iowrite32(tp->rx_ring_dma, ioaddr + CSR3);
iowrite32(tp->tx_ring_dma, ioaddr + CSR4);
@@ -386,8 +387,9 @@ static void tulip_up(struct net_device *dev)
(dev->if_port == 12 ? 0 : dev->if_port);
for (i = 0; i < tp->mtable->leafcount; i++)
if (tp->mtable->mleaf[i].media == looking_for) {
- printk(KERN_INFO "%s: Using user-specified media %s.\n",
- dev->name, medianame[dev->if_port]);
+ dev_info(&dev->dev,
+ "Using user-specified media %s\n",
+ medianame[dev->if_port]);
goto media_picked;
}
}
@@ -395,8 +397,9 @@ static void tulip_up(struct net_device *dev)
int looking_for = tp->mtable->defaultmedia & MEDIA_MASK;
for (i = 0; i < tp->mtable->leafcount; i++)
if (tp->mtable->mleaf[i].media == looking_for) {
- printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
- dev->name, medianame[looking_for]);
+ dev_info(&dev->dev,
+ "Using EEPROM-set media %s\n",
+ medianame[looking_for]);
goto media_picked;
}
}
@@ -423,9 +426,10 @@ media_picked:
if (tp->mii_cnt) {
tulip_select_media(dev, 1);
if (tulip_debug > 1)
- printk(KERN_INFO "%s: Using MII transceiver %d, status "
- "%4.4x.\n",
- dev->name, tp->phys[0], tulip_mdio_read(dev, tp->phys[0], 1));
+ dev_info(&dev->dev,
+ "Using MII transceiver %d, status %04x\n",
+ tp->phys[0],
+ tulip_mdio_read(dev, tp->phys[0], 1));
iowrite32(csr6_mask_defstate, ioaddr + CSR6);
tp->csr6 = csr6_mask_hdcap;
dev->if_port = 11;
@@ -489,9 +493,10 @@ media_picked:
iowrite32(0, ioaddr + CSR2); /* Rx poll demand */
if (tulip_debug > 2) {
- printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
- dev->name, ioread32(ioaddr + CSR0), ioread32(ioaddr + CSR5),
- ioread32(ioaddr + CSR6));
+ printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %08x, CSR5 %08x CSR6 %08x\n",
+ dev->name, ioread32(ioaddr + CSR0),
+ ioread32(ioaddr + CSR5),
+ ioread32(ioaddr + CSR6));
}
/* Set the timer to switch to check for link beat and perhaps switch
@@ -539,27 +544,30 @@ static void tulip_tx_timeout(struct net_device *dev)
if (tulip_media_cap[dev->if_port] & MediaIsMII) {
/* Do nothing -- the media monitor should handle this. */
if (tulip_debug > 1)
- printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
- dev->name);
+ dev_warn(&dev->dev,
+ "Transmit timeout using MII device\n");
} else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 ||
tp->chip_id == MX98713 || tp->chip_id == COMPEX9881 ||
tp->chip_id == DM910X) {
- printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
- "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
- dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12),
- ioread32(ioaddr + CSR13), ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));
+ dev_warn(&dev->dev,
+ "21140 transmit timed out, status %08x, SIA %08x %08x %08x %08x, resetting...\n",
+ ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12),
+ ioread32(ioaddr + CSR13), ioread32(ioaddr + CSR14),
+ ioread32(ioaddr + CSR15));
tp->timeout_recovery = 1;
schedule_work(&tp->media_work);
goto out_unlock;
} else if (tp->chip_id == PNIC2) {
- printk(KERN_WARNING "%s: PNIC2 transmit timed out, status %8.8x, "
- "CSR6/7 %8.8x / %8.8x CSR12 %8.8x, resetting...\n",
- dev->name, (int)ioread32(ioaddr + CSR5), (int)ioread32(ioaddr + CSR6),
- (int)ioread32(ioaddr + CSR7), (int)ioread32(ioaddr + CSR12));
+ dev_warn(&dev->dev,
+ "PNIC2 transmit timed out, status %08x, CSR6/7 %08x / %08x CSR12 %08x, resetting...\n",
+ (int)ioread32(ioaddr + CSR5),
+ (int)ioread32(ioaddr + CSR6),
+ (int)ioread32(ioaddr + CSR7),
+ (int)ioread32(ioaddr + CSR12));
} else {
- printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 "
- "%8.8x, resetting...\n",
- dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12));
+ dev_warn(&dev->dev,
+ "Transmit timed out, status %08x, CSR12 %08x, resetting...\n",
+ ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12));
dev->if_port = 0;
}
@@ -569,26 +577,26 @@ static void tulip_tx_timeout(struct net_device *dev)
for (i = 0; i < RX_RING_SIZE; i++) {
u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);
int j;
- printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x "
- "%2.2x %2.2x %2.2x.\n",
- i, (unsigned int)tp->rx_ring[i].status,
- (unsigned int)tp->rx_ring[i].length,
- (unsigned int)tp->rx_ring[i].buffer1,
- (unsigned int)tp->rx_ring[i].buffer2,
- buf[0], buf[1], buf[2]);
+ printk(KERN_DEBUG
+ "%2d: %08x %08x %08x %08x %02x %02x %02x\n",
+ i,
+ (unsigned int)tp->rx_ring[i].status,
+ (unsigned int)tp->rx_ring[i].length,
+ (unsigned int)tp->rx_ring[i].buffer1,
+ (unsigned int)tp->rx_ring[i].buffer2,
+ buf[0], buf[1], buf[2]);
for (j = 0; buf[j] != 0xee && j < 1600; j++)
if (j < 100)
- printk(KERN_CONT " %2.2x", buf[j]);
- printk(KERN_CONT " j=%d.\n", j);
+ pr_cont(" %02x", buf[j]);
+ pr_cont(" j=%d\n", j);
}
- printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring);
+ printk(KERN_DEBUG " Rx ring %08x: ", (int)tp->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
- printk(KERN_CONT " %8.8x",
- (unsigned int)tp->rx_ring[i].status);
- printk(KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring);
+ pr_cont(" %08x", (unsigned int)tp->rx_ring[i].status);
+ printk(KERN_DEBUG " Tx ring %08x: ", (int)tp->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
- printk(KERN_CONT " %8.8x", (unsigned int)tp->tx_ring[i].status);
- printk(KERN_CONT "\n");
+ pr_cont(" %08x", (unsigned int)tp->tx_ring[i].status);
+ pr_cont("\n");
}
#endif
@@ -831,8 +839,9 @@ static int tulip_close (struct net_device *dev)
tulip_down (dev);
if (tulip_debug > 1)
- printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
- dev->name, ioread32 (ioaddr + CSR5));
+ dev_printk(KERN_DEBUG, &dev->dev,
+ "Shutting down ethercard, status was %02x\n",
+ ioread32 (ioaddr + CSR5));
free_irq (dev->irq, dev);
@@ -988,12 +997,10 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev)
memset(hash_table, 0, sizeof(hash_table));
set_bit_le(255, hash_table); /* Broadcast entry */
/* This should work on big-endian machines as well. */
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int index = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff;
set_bit_le(index, hash_table);
-
}
for (i = 0; i < 32; i++) {
*setup_frm++ = hash_table[i];
@@ -1012,20 +1019,18 @@ static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev)
{
struct tulip_private *tp = netdev_priv(dev);
struct dev_mc_list *mclist;
- int i;
u16 *eaddrs;
/* We have <= 14 addresses so we can use the wonderful
16 address perfect filtering of the Tulip. */
- for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
eaddrs = (u16 *)mclist->dmi_addr;
*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
}
/* Fill the unused entries with the broadcast address. */
- memset(setup_frm, 0xff, (15-i)*12);
+ memset(setup_frm, 0xff, (15 - netdev_mc_count(dev)) * 12);
setup_frm = &tp->setup_frame[15*6];
/* Fill the final entry with our physical address. */
@@ -1048,7 +1053,8 @@ static void set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
tp->csr6 |= AcceptAllMulticast | AcceptAllPhys;
csr6 |= AcceptAllMulticast | AcceptAllPhys;
- } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
+ } else if ((netdev_mc_count(dev) > 1000) ||
+ (dev->flags & IFF_ALLMULTI)) {
/* Too many to filter well -- accept all multicasts. */
tp->csr6 |= AcceptAllMulticast;
csr6 |= AcceptAllMulticast;
@@ -1056,15 +1062,14 @@ static void set_rx_mode(struct net_device *dev)
/* Some work-alikes have only a 64-entry hash filter table. */
/* Should verify correctness on big-endian/__powerpc__ */
struct dev_mc_list *mclist;
- int i;
- if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */
+ if (netdev_mc_count(dev) > 64) {
+ /* Arbitrary non-effective limit. */
tp->csr6 |= AcceptAllMulticast;
csr6 |= AcceptAllMulticast;
} else {
u32 mc_filter[2] = {0, 0}; /* Multicast hash filter */
int filterbit;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
if (tp->flags & COMET_MAC_ADDR)
filterbit = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
else
@@ -1072,10 +1077,10 @@ static void set_rx_mode(struct net_device *dev)
filterbit &= 0x3f;
mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
if (tulip_debug > 2)
- printk(KERN_INFO "%s: Added filter for %pM"
- " %8.8x bit %d.\n",
- dev->name, mclist->dmi_addr,
- ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
+ dev_info(&dev->dev,
+ "Added filter for %pM %08x bit %d\n",
+ mclist->dmi_addr,
+ ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
}
if (mc_filter[0] == tp->mc_filter[0] &&
mc_filter[1] == tp->mc_filter[1])
@@ -1098,7 +1103,8 @@ static void set_rx_mode(struct net_device *dev)
/* Note that only the low-address shortword of setup_frame is valid!
The values are doubled for big-endian architectures. */
- if (dev->mc_count > 14) { /* Must use a multicast hash table. */
+ if (netdev_mc_count(dev) > 14) {
+ /* Must use a multicast hash table. */
build_setup_frame_hash(tp->setup_frame, dev);
tx_flags = 0x08400000 | 192;
} else {
@@ -1287,9 +1293,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
unsigned int force_csr0 = 0;
#ifndef MODULE
- static int did_version; /* Already printed version info. */
- if (tulip_debug > 0 && did_version++ == 0)
- printk (KERN_INFO "%s", version);
+ if (tulip_debug > 0)
+ printk_once(KERN_INFO "%s", version);
#endif
board_idx++;
@@ -1300,7 +1305,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
*/
if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) {
- printk (KERN_ERR PFX "skipping LMC card.\n");
+ pr_err(PFX "skipping LMC card\n");
return -ENODEV;
}
@@ -1316,15 +1321,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
if (pdev->vendor == 0x1282 && pdev->device == 0x9100 &&
pdev->revision < 0x30) {
- printk(KERN_INFO PFX
- "skipping early DM9100 with Crc bug (use dmfe)\n");
+ pr_info(PFX "skipping early DM9100 with Crc bug (use dmfe)\n");
return -ENODEV;
}
dp = pci_device_to_OF_node(pdev);
if (!(dp && of_get_property(dp, "local-mac-address", NULL))) {
- printk(KERN_INFO PFX
- "skipping DM910x expansion card (use dmfe)\n");
+ pr_info(PFX "skipping DM910x expansion card (use dmfe)\n");
return -ENODEV;
}
}
@@ -1371,9 +1374,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
i = pci_enable_device(pdev);
if (i) {
- printk (KERN_ERR PFX
- "Cannot enable tulip board #%d, aborting\n",
- board_idx);
+ pr_err(PFX "Cannot enable tulip board #%d, aborting\n",
+ board_idx);
return i;
}
@@ -1382,22 +1384,22 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
/* alloc_etherdev ensures aligned and zeroed private structures */
dev = alloc_etherdev (sizeof (*tp));
if (!dev) {
- printk (KERN_ERR PFX "ether device alloc failed, aborting\n");
+ pr_err(PFX "ether device alloc failed, aborting\n");
return -ENOMEM;
}
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
- printk (KERN_ERR PFX "%s: I/O region (0x%llx@0x%llx) too small, "
- "aborting\n", pci_name(pdev),
- (unsigned long long)pci_resource_len (pdev, 0),
- (unsigned long long)pci_resource_start (pdev, 0));
+ pr_err(PFX "%s: I/O region (0x%llx@0x%llx) too small, aborting\n",
+ pci_name(pdev),
+ (unsigned long long)pci_resource_len (pdev, 0),
+ (unsigned long long)pci_resource_start (pdev, 0));
goto err_out_free_netdev;
}
/* grab all resources from both PIO and MMIO regions, as we
* don't want anyone else messing around with our hardware */
- if (pci_request_regions (pdev, "tulip"))
+ if (pci_request_regions (pdev, DRV_NAME))
goto err_out_free_netdev;
ioaddr = pci_iomap(pdev, TULIP_BAR, tulip_tbl[chip_idx].io_size);
@@ -1610,8 +1612,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
if (dev->mem_start & MEDIA_MASK)
tp->default_port = dev->mem_start & MEDIA_MASK;
if (tp->default_port) {
- printk(KERN_INFO "tulip%d: Transceiver selection forced to %s.\n",
- board_idx, medianame[tp->default_port & MEDIA_MASK]);
+ pr_info(DRV_NAME "%d: Transceiver selection forced to %s\n",
+ board_idx, medianame[tp->default_port & MEDIA_MASK]);
tp->medialock = 1;
if (tulip_media_cap[tp->default_port] & MediaAlwaysFD)
tp->full_duplex = 1;
@@ -1626,7 +1628,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
}
if (tp->flags & HAS_MEDIA_TABLE) {
- sprintf(dev->name, "tulip%d", board_idx); /* hack */
+ sprintf(dev->name, DRV_NAME "%d", board_idx); /* hack */
tulip_parse_eeprom(dev);
strcpy(dev->name, "eth%d"); /* un-hack */
}
@@ -1662,20 +1664,18 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
if (register_netdev(dev))
goto err_out_free_ring;
- printk(KERN_INFO "%s: %s rev %d at "
+ pci_set_drvdata(pdev, dev);
+
+ dev_info(&dev->dev,
#ifdef CONFIG_TULIP_MMIO
- "MMIO"
+ "%s rev %d at MMIO %#llx,%s %pM, IRQ %d\n",
#else
- "Port"
+ "%s rev %d at Port %#llx,%s %pM, IRQ %d\n",
#endif
- " %#llx,", dev->name, chip_name, pdev->revision,
- (unsigned long long) pci_resource_start(pdev, TULIP_BAR));
- pci_set_drvdata(pdev, dev);
-
- if (eeprom_missing)
- printk(" EEPROM not present,");
- printk(" %pM", dev->dev_addr);
- printk(", IRQ %d.\n", irq);
+ chip_name, pdev->revision,
+ (unsigned long long)pci_resource_start(pdev, TULIP_BAR),
+ eeprom_missing ? " EEPROM not present," : "",
+ dev->dev_addr, irq);
if (tp->chip_id == PNIC2)
tp->link_change = pnic2_lnk_change;
@@ -1798,12 +1798,12 @@ static int tulip_resume(struct pci_dev *pdev)
return 0;
if ((retval = pci_enable_device(pdev))) {
- printk (KERN_ERR "tulip: pci_enable_device failed in resume\n");
+ pr_err(PFX "pci_enable_device failed in resume\n");
return retval;
}
if ((retval = request_irq(dev->irq, tulip_interrupt, IRQF_SHARED, dev->name, dev))) {
- printk (KERN_ERR "tulip: request_irq failed in resume\n");
+ pr_err(PFX "request_irq failed in resume\n");
return retval;
}
@@ -1873,7 +1873,7 @@ static struct pci_driver tulip_driver = {
static int __init tulip_init (void)
{
#ifdef MODULE
- printk (KERN_INFO "%s", version);
+ pr_info("%s", version);
#endif
/* copy module parms into globals */
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index fa019cabc355..0ab05af237e5 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -12,6 +12,8 @@
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define DRV_NAME "uli526x"
#define DRV_VERSION "0.9.3"
#define DRV_RELDATE "2005-7-29"
@@ -82,9 +84,16 @@
#define ULI526X_TX_TIMEOUT ((16*HZ)/2) /* tx packet time-out time 8 s" */
#define ULI526X_TX_KICK (4*HZ/2) /* tx packet Kick-out time 2 s" */
-#define ULI526X_DBUG(dbug_now, msg, value) if (uli526x_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value))
+#define ULI526X_DBUG(dbug_now, msg, value) \
+do { \
+ if (uli526x_debug || (dbug_now)) \
+ pr_err("%s %lx\n", (msg), (long) (value)); \
+} while (0)
-#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half");
+#define SHOW_MEDIA_TYPE(mode) \
+ pr_err("Change Speed to %sMhz %s duplex\n", \
+ mode & 1 ? "100" : "10", \
+ mode & 4 ? "full" : "half");
/* CR9 definition: SROM/MII */
@@ -284,7 +293,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
- printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n");
+ pr_warning("32-bit PCI DMA not available\n");
err = -ENODEV;
goto err_out_free;
}
@@ -295,19 +304,19 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
goto err_out_free;
if (!pci_resource_start(pdev, 0)) {
- printk(KERN_ERR DRV_NAME ": I/O base is zero\n");
+ pr_err("I/O base is zero\n");
err = -ENODEV;
goto err_out_disable;
}
if (pci_resource_len(pdev, 0) < (ULI526X_IO_SIZE) ) {
- printk(KERN_ERR DRV_NAME ": Allocated I/O size too small\n");
+ pr_err("Allocated I/O size too small\n");
err = -ENODEV;
goto err_out_disable;
}
if (pci_request_regions(pdev, DRV_NAME)) {
- printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n");
+ pr_err("Failed to request PCI regions\n");
err = -ENODEV;
goto err_out_disable;
}
@@ -382,9 +391,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
if (err)
goto err_out_res;
- printk(KERN_INFO "%s: ULi M%04lx at pci%s, %pM, irq %d.\n",
- dev->name,ent->driver_data >> 16,pci_name(pdev),
- dev->dev_addr, dev->irq);
+ dev_info(&dev->dev, "ULi M%04lx at pci%s, %pM, irq %d\n",
+ ent->driver_data >> 16, pci_name(pdev),
+ dev->dev_addr, dev->irq);
pci_set_master(pdev);
@@ -516,7 +525,7 @@ static void uli526x_init(struct net_device *dev)
}
}
if(phy_tmp == 32)
- printk(KERN_WARNING "Can not find the phy address!!!");
+ pr_warning("Can not find the phy address!!!");
/* Parser SROM and media mode */
db->media_mode = uli526x_media_mode;
@@ -548,7 +557,7 @@ static void uli526x_init(struct net_device *dev)
update_cr6(db->cr6_data, ioaddr);
/* Send setup frame */
- send_filter_frame(dev, dev->mc_count); /* M5261/M5263 */
+ send_filter_frame(dev, netdev_mc_count(dev)); /* M5261/M5263 */
/* Init CR7, interrupt active bit */
db->cr7_data = CR7_DEFAULT;
@@ -582,7 +591,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb,
/* Too large packet check */
if (skb->len > MAX_PACKET_SIZE) {
- printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
+ pr_err("big packet = %d\n", (u16)skb->len);
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -592,7 +601,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb,
/* No Tx resource check, it never happen nromally */
if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) {
spin_unlock_irqrestore(&db->lock, flags);
- printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_packet_cnt);
+ pr_err("No Tx resource %ld\n", db->tx_packet_cnt);
return NETDEV_TX_BUSY;
}
@@ -897,16 +906,18 @@ static void uli526x_set_filter_mode(struct net_device * dev)
return;
}
- if (dev->flags & IFF_ALLMULTI || dev->mc_count > ULI5261_MAX_MULTICAST) {
- ULI526X_DBUG(0, "Pass all multicast address", dev->mc_count);
+ if (dev->flags & IFF_ALLMULTI ||
+ netdev_mc_count(dev) > ULI5261_MAX_MULTICAST) {
+ ULI526X_DBUG(0, "Pass all multicast address",
+ netdev_mc_count(dev));
db->cr6_data &= ~(CR6_PM | CR6_PBF);
db->cr6_data |= CR6_PAM;
spin_unlock_irqrestore(&db->lock, flags);
return;
}
- ULI526X_DBUG(0, "Set multicast address", dev->mc_count);
- send_filter_frame(dev, dev->mc_count); /* M5261/M5263 */
+ ULI526X_DBUG(0, "Set multicast address", netdev_mc_count(dev));
+ send_filter_frame(dev, netdev_mc_count(dev)); /* M5261/M5263 */
spin_unlock_irqrestore(&db->lock, flags);
}
@@ -1058,7 +1069,7 @@ static void uli526x_timer(unsigned long data)
/* Link Failed */
ULI526X_DBUG(0, "Link Failed", tmp_cr12);
netif_carrier_off(dev);
- printk(KERN_INFO "uli526x: %s NIC Link is Down\n",dev->name);
+ pr_info("%s NIC Link is Down\n",dev->name);
db->link_failed = 1;
/* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
@@ -1090,11 +1101,11 @@ static void uli526x_timer(unsigned long data)
}
if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD)
{
- printk(KERN_INFO "uli526x: %s NIC Link is Up %d Mbps Full duplex\n",dev->name,TmpSpeed);
+ pr_info("%s NIC Link is Up %d Mbps Full duplex\n",dev->name,TmpSpeed);
}
else
{
- printk(KERN_INFO "uli526x: %s NIC Link is Up %d Mbps Half duplex\n",dev->name,TmpSpeed);
+ pr_info("%s NIC Link is Up %d Mbps Half duplex\n",dev->name,TmpSpeed);
}
netif_carrier_on(dev);
}
@@ -1104,7 +1115,7 @@ static void uli526x_timer(unsigned long data)
{
if(db->init==1)
{
- printk(KERN_INFO "uli526x: %s NIC Link is Down\n",dev->name);
+ pr_info("%s NIC Link is Down\n",dev->name);
netif_carrier_off(dev);
}
}
@@ -1230,8 +1241,7 @@ static int uli526x_resume(struct pci_dev *pdev)
err = pci_set_power_state(pdev, PCI_D0);
if (err) {
- printk(KERN_WARNING "%s: Could not put device into D0\n",
- dev->name);
+ dev_warn(&dev->dev, "Could not put device into D0\n");
return err;
}
@@ -1405,14 +1415,14 @@ static void send_filter_frame(struct net_device *dev, int mc_cnt)
*suptr++ = 0xffff << FLT_SHIFT;
/* fit the multicast address */
- for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
+ netdev_for_each_mc_addr(mcptr, dev) {
addrptr = (u16 *) mcptr->dmi_addr;
*suptr++ = addrptr[0] << FLT_SHIFT;
*suptr++ = addrptr[1] << FLT_SHIFT;
*suptr++ = addrptr[2] << FLT_SHIFT;
}
- for (; i<14; i++) {
+ for (i = netdev_mc_count(dev); i < 14; i++) {
*suptr++ = 0xffff << FLT_SHIFT;
*suptr++ = 0xffff << FLT_SHIFT;
*suptr++ = 0xffff << FLT_SHIFT;
@@ -1432,7 +1442,7 @@ static void send_filter_frame(struct net_device *dev, int mc_cnt)
update_cr6(db->cr6_data, dev->base_addr);
dev->trans_start = jiffies;
} else
- printk(KERN_ERR DRV_NAME ": No Tx resource - Send_filter_frame!\n");
+ pr_err("No Tx resource - Send_filter_frame!\n");
}
@@ -1783,7 +1793,7 @@ static u16 phy_read_1bit(unsigned long ioaddr, u32 chip_id)
}
-static struct pci_device_id uli526x_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(uli526x_pci_tbl) = {
{ 0x10B9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ULI5261_ID },
{ 0x10B9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ULI5263_ID },
{ 0, }
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 869a7a0005f9..304f43866c44 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -218,7 +218,7 @@ enum chip_capability_flags {
CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,
};
-static const struct pci_device_id w840_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(w840_pci_tbl) = {
{ 0x1050, 0x0840, PCI_ANY_ID, 0x8153, 0, 0, 0 },
{ 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
{ 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
@@ -376,8 +376,8 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
irq = pdev->irq;
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
- printk(KERN_WARNING "Winbond-840: Device %s disabled due to DMA limitations.\n",
- pci_name(pdev));
+ pr_warning("Winbond-840: Device %s disabled due to DMA limitations\n",
+ pci_name(pdev));
return -EIO;
}
dev = alloc_etherdev(sizeof(*np));
@@ -422,8 +422,9 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
if (option & 0x200)
np->mii_if.full_duplex = 1;
if (option & 15)
- printk(KERN_INFO "%s: ignoring user supplied media type %d",
- dev->name, option & 15);
+ dev_info(&dev->dev,
+ "ignoring user supplied media type %d",
+ option & 15);
}
if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0)
np->mii_if.full_duplex = 1;
@@ -440,9 +441,8 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
if (i)
goto err_out_cleardev;
- printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n",
- dev->name, pci_id_tbl[chip_idx].name, ioaddr,
- dev->dev_addr, irq);
+ dev_info(&dev->dev, "%s at %p, %pM, IRQ %d\n",
+ pci_id_tbl[chip_idx].name, ioaddr, dev->dev_addr, irq);
if (np->drv_flags & CanHaveMII) {
int phy, phy_idx = 0;
@@ -453,16 +453,17 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
np->mii = (mdio_read(dev, phy, MII_PHYSID1) << 16)+
mdio_read(dev, phy, MII_PHYSID2);
- printk(KERN_INFO "%s: MII PHY %8.8xh found at address %d, status "
- "0x%4.4x advertising %4.4x.\n",
- dev->name, np->mii, phy, mii_status, np->mii_if.advertising);
+ dev_info(&dev->dev,
+ "MII PHY %08xh found at address %d, status 0x%04x advertising %04x\n",
+ np->mii, phy, mii_status,
+ np->mii_if.advertising);
}
}
np->mii_cnt = phy_idx;
np->mii_if.phy_id = np->phys[0];
if (phy_idx == 0) {
- printk(KERN_WARNING "%s: MII PHY not found -- this device may "
- "not operate correctly.\n", dev->name);
+ dev_warn(&dev->dev,
+ "MII PHY not found -- this device may not operate correctly\n");
}
}
@@ -644,8 +645,8 @@ static int netdev_open(struct net_device *dev)
goto out_err;
if (debug > 1)
- printk(KERN_DEBUG "%s: w89c840_open() irq %d.\n",
- dev->name, dev->irq);
+ printk(KERN_DEBUG "%s: w89c840_open() irq %d\n",
+ dev->name, dev->irq);
if((i=alloc_ringdesc(dev)))
goto out_err;
@@ -657,7 +658,7 @@ static int netdev_open(struct net_device *dev)
netif_start_queue(dev);
if (debug > 2)
- printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name);
+ printk(KERN_DEBUG "%s: Done netdev_open()\n", dev->name);
/* Set the timer to check for link beat. */
init_timer(&np->timer);
@@ -688,16 +689,18 @@ static int update_link(struct net_device *dev)
if (!(mii_reg & 0x4)) {
if (netif_carrier_ok(dev)) {
if (debug)
- printk(KERN_INFO "%s: MII #%d reports no link. Disabling watchdog.\n",
- dev->name, np->phys[0]);
+ dev_info(&dev->dev,
+ "MII #%d reports no link. Disabling watchdog\n",
+ np->phys[0]);
netif_carrier_off(dev);
}
return np->csr6;
}
if (!netif_carrier_ok(dev)) {
if (debug)
- printk(KERN_INFO "%s: MII #%d link is back. Enabling watchdog.\n",
- dev->name, np->phys[0]);
+ dev_info(&dev->dev,
+ "MII #%d link is back. Enabling watchdog\n",
+ np->phys[0]);
netif_carrier_on(dev);
}
@@ -729,9 +732,10 @@ static int update_link(struct net_device *dev)
if (fasteth)
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,
- duplex ? "full" : "half", np->phys[0]);
+ dev_info(&dev->dev,
+ "Setting %dMBit-%s-duplex based on MII#%d\n",
+ fasteth ? 100 : 10, duplex ? "full" : "half",
+ np->phys[0]);
return result;
}
@@ -763,8 +767,8 @@ static inline void update_csr6(struct net_device *dev, int new)
limit--;
if(!limit) {
- printk(KERN_INFO "%s: couldn't stop rxtx, IntrStatus %xh.\n",
- dev->name, csr5);
+ dev_info(&dev->dev,
+ "couldn't stop rxtx, IntrStatus %xh\n", csr5);
break;
}
udelay(1);
@@ -783,10 +787,9 @@ static void netdev_timer(unsigned long data)
void __iomem *ioaddr = np->base_addr;
if (debug > 2)
- printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x "
- "config %8.8x.\n",
- dev->name, ioread32(ioaddr + IntrStatus),
- ioread32(ioaddr + NetworkConfig));
+ printk(KERN_DEBUG "%s: Media selection timer tick, status %08x config %08x\n",
+ dev->name, ioread32(ioaddr + IntrStatus),
+ ioread32(ioaddr + NetworkConfig));
spin_lock_irq(&np->lock);
update_csr6(dev, update_link(dev));
spin_unlock_irq(&np->lock);
@@ -899,8 +902,8 @@ static void init_registers(struct net_device *dev)
/* When not a module we can work around broken '486 PCI boards. */
if (boot_cpu_data.x86 <= 4) {
i |= 0x4800;
- printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
- "alignment to 8 longwords.\n", dev->name);
+ dev_info(&dev->dev,
+ "This is a 386/486 PCI system, setting cache alignment to 8 longwords\n");
} else {
i |= 0xE000;
}
@@ -931,22 +934,23 @@ static void tx_timeout(struct net_device *dev)
struct netdev_private *np = netdev_priv(dev);
void __iomem *ioaddr = np->base_addr;
- printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
- " resetting...\n", dev->name, ioread32(ioaddr + IntrStatus));
+ dev_warn(&dev->dev, "Transmit timed out, status %08x, resetting...\n",
+ ioread32(ioaddr + IntrStatus));
{
int i;
printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
- printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
- printk(KERN_DEBUG" Tx ring %p: ", np->tx_ring);
+ printk(KERN_CONT " %08x", (unsigned int)np->rx_ring[i].status);
+ printk(KERN_CONT "\n");
+ printk(KERN_DEBUG " Tx ring %p: ", np->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
- printk(" %8.8x", np->tx_ring[i].status);
- printk("\n");
+ printk(KERN_CONT " %08x", np->tx_ring[i].status);
+ printk(KERN_CONT "\n");
}
- printk(KERN_DEBUG "Tx cur %d Tx dirty %d Tx Full %d, q bytes %d.\n",
- np->cur_tx, np->dirty_tx, np->tx_full, np->tx_q_bytes);
- printk(KERN_DEBUG "Tx Descriptor addr %xh.\n",ioread32(ioaddr+0x4C));
+ printk(KERN_DEBUG "Tx cur %d Tx dirty %d Tx Full %d, q bytes %d\n",
+ np->cur_tx, np->dirty_tx, np->tx_full, np->tx_q_bytes);
+ printk(KERN_DEBUG "Tx Descriptor addr %xh\n", ioread32(ioaddr+0x4C));
disable_irq(dev->irq);
spin_lock_irq(&np->lock);
@@ -1055,8 +1059,8 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
if (debug > 4) {
- printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
- dev->name, np->cur_tx, entry);
+ printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d\n",
+ dev->name, np->cur_tx, entry);
}
return NETDEV_TX_OK;
}
@@ -1073,8 +1077,8 @@ static void netdev_tx_done(struct net_device *dev)
if (tx_status & 0x8000) { /* There was an error, log it. */
#ifndef final_version
if (debug > 1)
- printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
- dev->name, tx_status);
+ printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n",
+ dev->name, tx_status);
#endif
np->stats.tx_errors++;
if (tx_status & 0x0104) np->stats.tx_aborted_errors++;
@@ -1086,8 +1090,8 @@ static void netdev_tx_done(struct net_device *dev)
} else {
#ifndef final_version
if (debug > 3)
- printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %8.8x.\n",
- dev->name, entry, tx_status);
+ printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %08x\n",
+ dev->name, entry, tx_status);
#endif
np->stats.tx_bytes += np->tx_skbuff[entry]->len;
np->stats.collisions += (tx_status >> 3) & 15;
@@ -1130,8 +1134,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
iowrite32(intr_status & 0x001ffff, ioaddr + IntrStatus);
if (debug > 4)
- printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
- dev->name, intr_status);
+ printk(KERN_DEBUG "%s: Interrupt, status %04x\n",
+ dev->name, intr_status);
if ((intr_status & (NormalIntr|AbnormalIntr)) == 0)
break;
@@ -1156,8 +1160,9 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
netdev_error(dev, intr_status);
if (--work_limit < 0) {
- printk(KERN_WARNING "%s: Too much work at interrupt, "
- "status=0x%4.4x.\n", dev->name, intr_status);
+ dev_warn(&dev->dev,
+ "Too much work at interrupt, status=0x%04x\n",
+ intr_status);
/* Set the timer to re-enable the other interrupts after
10*82usec ticks. */
spin_lock(&np->lock);
@@ -1171,8 +1176,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
} while (1);
if (debug > 3)
- printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
- dev->name, ioread32(ioaddr + IntrStatus));
+ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x\n",
+ dev->name, ioread32(ioaddr + IntrStatus));
return IRQ_RETVAL(handled);
}
@@ -1185,8 +1190,8 @@ static int netdev_rx(struct net_device *dev)
int work_limit = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
if (debug > 4) {
- printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
- entry, np->rx_ring[entry].status);
+ printk(KERN_DEBUG " In netdev_rx(), entry %d status %04x\n",
+ entry, np->rx_ring[entry].status);
}
/* If EOP is set on the next entry, it's a new packet. Send it up. */
@@ -1195,24 +1200,24 @@ static int netdev_rx(struct net_device *dev)
s32 status = desc->status;
if (debug > 4)
- printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n",
- status);
+ printk(KERN_DEBUG " netdev_rx() status was %08x\n",
+ status);
if (status < 0)
break;
if ((status & 0x38008300) != 0x0300) {
if ((status & 0x38000300) != 0x0300) {
/* Ingore earlier buffers. */
if ((status & 0xffff) != 0x7fff) {
- printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
- "multiple buffers, entry %#x status %4.4x!\n",
- dev->name, np->cur_rx, status);
+ dev_warn(&dev->dev,
+ "Oversized Ethernet frame spanned multiple buffers, entry %#x status %04x!\n",
+ np->cur_rx, status);
np->stats.rx_length_errors++;
}
} else if (status & 0x8000) {
/* There was a fatal error. */
if (debug > 2)
- printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
- dev->name, status);
+ printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n",
+ dev->name, status);
np->stats.rx_errors++; /* end of a packet.*/
if (status & 0x0890) np->stats.rx_length_errors++;
if (status & 0x004C) np->stats.rx_frame_errors++;
@@ -1225,8 +1230,8 @@ static int netdev_rx(struct net_device *dev)
#ifndef final_version
if (debug > 4)
- printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d"
- " status %x.\n", pkt_len, status);
+ printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d status %x\n",
+ pkt_len, status);
#endif
/* Check if the packet is long enough to accept without copying
to a minimally-sized skbuff. */
@@ -1251,11 +1256,10 @@ static int netdev_rx(struct net_device *dev)
#ifndef final_version /* Remove after testing. */
/* You will want this info for the initial debug. */
if (debug > 5)
- printk(KERN_DEBUG " Rx data %pM %pM"
- " %2.2x%2.2x %d.%d.%d.%d.\n",
+ printk(KERN_DEBUG " Rx data %pM %pM %02x%02x %pI4\n",
&skb->data[0], &skb->data[6],
skb->data[12], skb->data[13],
- skb->data[14], skb->data[15], skb->data[16], skb->data[17]);
+ &skb->data[14]);
#endif
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
@@ -1293,8 +1297,8 @@ static void netdev_error(struct net_device *dev, int intr_status)
void __iomem *ioaddr = np->base_addr;
if (debug > 2)
- printk(KERN_DEBUG "%s: Abnormal event, %8.8x.\n",
- dev->name, intr_status);
+ printk(KERN_DEBUG "%s: Abnormal event, %08x\n",
+ dev->name, intr_status);
if (intr_status == 0xffffffff)
return;
spin_lock(&np->lock);
@@ -1314,8 +1318,8 @@ static void netdev_error(struct net_device *dev, int intr_status)
new = 127; /* load full packet before starting */
new = (np->csr6 & ~(0x7F << 14)) | (new<<14);
#endif
- printk(KERN_DEBUG "%s: Tx underflow, new csr6 %8.8x.\n",
- dev->name, new);
+ printk(KERN_DEBUG "%s: Tx underflow, new csr6 %08x\n",
+ dev->name, new);
update_csr6(dev, new);
}
if (intr_status & RxDied) { /* Missed a Rx frame. */
@@ -1357,17 +1361,16 @@ static u32 __set_rx_mode(struct net_device *dev)
memset(mc_filter, 0xff, sizeof(mc_filter));
rx_mode = RxAcceptBroadcast | AcceptMulticast | RxAcceptAllPhys
| AcceptMyPhys;
- } else if ((dev->mc_count > multicast_filter_limit) ||
+ } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
(dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
memset(mc_filter, 0xff, sizeof(mc_filter));
rx_mode = RxAcceptBroadcast | AcceptMulticast | AcceptMyPhys;
} else {
struct dev_mc_list *mclist;
- int i;
+
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int filterbit = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F;
filterbit &= 0x3f;
mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
@@ -1487,11 +1490,13 @@ static int netdev_close(struct net_device *dev)
netif_stop_queue(dev);
if (debug > 1) {
- printk(KERN_DEBUG "%s: Shutting down ethercard, status was %8.8x "
- "Config %8.8x.\n", dev->name, ioread32(ioaddr + IntrStatus),
- ioread32(ioaddr + NetworkConfig));
- printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
- dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %08x Config %08x\n",
+ dev->name, ioread32(ioaddr + IntrStatus),
+ ioread32(ioaddr + NetworkConfig));
+ printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d\n",
+ dev->name,
+ np->cur_tx, np->dirty_tx,
+ np->cur_rx, np->dirty_rx);
}
/* Stop the chip's Tx and Rx processes. */
@@ -1512,18 +1517,16 @@ static int netdev_close(struct net_device *dev)
if (debug > 2) {
int i;
- printk(KERN_DEBUG" Tx ring at %8.8x:\n",
- (int)np->tx_ring);
+ printk(KERN_DEBUG" Tx ring at %08x:\n", (int)np->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
- printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x.\n",
- i, np->tx_ring[i].length,
- np->tx_ring[i].status, np->tx_ring[i].buffer1);
- printk(KERN_DEBUG " Rx ring %8.8x:\n",
- (int)np->rx_ring);
+ printk(KERN_DEBUG " #%d desc. %04x %04x %08x\n",
+ i, np->tx_ring[i].length,
+ np->tx_ring[i].status, np->tx_ring[i].buffer1);
+ printk(KERN_DEBUG " Rx ring %08x:\n", (int)np->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++) {
- printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
- i, np->rx_ring[i].length,
- np->rx_ring[i].status, np->rx_ring[i].buffer1);
+ printk(KERN_DEBUG " #%d desc. %04x %04x %08x\n",
+ i, np->rx_ring[i].length,
+ np->rx_ring[i].status, np->rx_ring[i].buffer1);
}
}
#endif /* __i386__ debugging only */
@@ -1622,9 +1625,8 @@ static int w840_resume (struct pci_dev *pdev)
goto out; /* device not suspended */
if (netif_running(dev)) {
if ((retval = pci_enable_device(pdev))) {
- printk (KERN_ERR
- "%s: pci_enable_device failed in resume\n",
- dev->name);
+ dev_err(&dev->dev,
+ "pci_enable_device failed in resume\n");
goto out;
}
spin_lock_irq(&np->lock);
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 9924c4c7e2d6..acfeeb980562 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -14,6 +14,8 @@
* $Id: xircom_cb.c,v 1.33 2001/03/19 14:02:07 arjanv Exp $
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -144,7 +146,7 @@ static int link_status(struct xircom_private *card);
-static struct pci_device_id xircom_pci_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(xircom_pci_table) = {
{0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID,},
{0,},
};
@@ -234,7 +236,7 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
pci_write_config_word (pdev, PCI_STATUS,tmp16);
if (!request_region(pci_resource_start(pdev, 0), 128, "xircom_cb")) {
- printk(KERN_ERR "xircom_probe: failed to allocate io-region\n");
+ pr_err("%s: failed to allocate io-region\n", __func__);
return -ENODEV;
}
@@ -245,7 +247,7 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
*/
dev = alloc_etherdev(sizeof(struct xircom_private));
if (!dev) {
- printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n");
+ pr_err("%s: failed to allocate etherdev\n", __func__);
goto device_fail;
}
private = netdev_priv(dev);
@@ -253,12 +255,12 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
/* 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");
+ pr_err("%s: no memory for rx buffer\n", __func__);
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");
+ pr_err("%s: no memory for tx buffer\n", __func__);
goto tx_buf_fail;
}
@@ -281,11 +283,12 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
pci_set_drvdata(pdev, dev);
if (register_netdev(dev)) {
- printk(KERN_ERR "xircom_probe: netdevice registration failed.\n");
+ pr_err("%s: netdevice registration failed\n", __func__);
goto reg_fail;
}
- printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, pdev->revision, pdev->irq);
+ dev_info(&dev->dev, "Xircom cardbus revision %i at irq %i\n",
+ pdev->revision, pdev->irq);
/* start the transmitter to get a heartbeat */
/* TODO: send 2 dummy packets here */
transceiver_voodoo(private);
@@ -347,8 +350,10 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance)
#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]);
+ 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
/* Handle shared irq and hotplug */
if (status == 0 || status == 0xffffffff) {
@@ -358,9 +363,9 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance)
if (link_status_changed(card)) {
int newlink;
- printk(KERN_DEBUG "xircom_cb: Link status has changed \n");
+ printk(KERN_DEBUG "xircom_cb: Link status has changed\n");
newlink = link_status(card);
- printk(KERN_INFO "xircom_cb: Link is %i mbit \n",newlink);
+ dev_info(&dev->dev, "Link is %i mbit\n", newlink);
if (newlink)
netif_carrier_on(dev);
else
@@ -457,7 +462,8 @@ static int xircom_open(struct net_device *dev)
struct xircom_private *xp = netdev_priv(dev);
int retval;
enter("xircom_open");
- printk(KERN_INFO "xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq);
+ pr_info("xircom cardbus adaptor found, registering as %s, using irq %i \n",
+ dev->name, dev->irq);
retval = request_irq(dev->irq, xircom_interrupt, IRQF_SHARED, dev->name, dev);
if (retval) {
leave("xircom_open - No IRQ");
@@ -770,7 +776,7 @@ static void activate_receiver(struct xircom_private *card)
udelay(50);
counter--;
if (counter <= 0)
- printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n");
+ pr_err("Receiver failed to deactivate\n");
}
/* enable the receiver */
@@ -787,7 +793,7 @@ static void activate_receiver(struct xircom_private *card)
udelay(50);
counter--;
if (counter <= 0)
- printk(KERN_ERR "xircom_cb: Receiver failed to re-activate\n");
+ pr_err("Receiver failed to re-activate\n");
}
leave("activate_receiver");
@@ -818,7 +824,7 @@ static void deactivate_receiver(struct xircom_private *card)
udelay(50);
counter--;
if (counter <= 0)
- printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n");
+ pr_err("Receiver failed to deactivate\n");
}
@@ -861,7 +867,7 @@ static void activate_transmitter(struct xircom_private *card)
udelay(50);
counter--;
if (counter <= 0)
- printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n");
+ pr_err("Transmitter failed to deactivate\n");
}
/* enable the transmitter */
@@ -878,7 +884,7 @@ static void activate_transmitter(struct xircom_private *card)
udelay(50);
counter--;
if (counter <= 0)
- printk(KERN_ERR "xircom_cb: Transmitter failed to re-activate\n");
+ pr_err("Transmitter failed to re-activate\n");
}
leave("activate_transmitter");
@@ -909,7 +915,7 @@ static void deactivate_transmitter(struct xircom_private *card)
udelay(50);
counter--;
if (counter <= 0)
- printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n");
+ pr_err("Transmitter failed to deactivate\n");
}
@@ -1184,7 +1190,7 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri
struct sk_buff *skb;
if (pkt_len > 1518) {
- printk(KERN_ERR "xircom_cb: Packet length %i is bogus \n",pkt_len);
+ pr_err("Packet length %i is bogus\n", pkt_len);
pkt_len = 1518;
}
@@ -1222,7 +1228,7 @@ static void investigate_write_descriptor(struct net_device *dev, struct xircom_p
status = le32_to_cpu(card->tx_buffer[4*descnr]);
#if 0
if (status & 0x8000) { /* Major error */
- printk(KERN_ERR "Major transmit error status %x \n", status);
+ pr_err("Major transmit error status %x\n", status);
card->tx_buffer[4*descnr] = 0;
netif_wake_queue (dev);
}
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 2834a01bae24..96c39bddc78c 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -61,6 +61,7 @@
#include <linux/crc32.h>
#include <linux/nsproxy.h>
#include <linux/virtio_net.h>
+#include <linux/rcupdate.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/rtnetlink.h>
@@ -144,6 +145,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
err = 0;
tfile->tun = tun;
tun->tfile = tfile;
+ tun->socket.file = file;
dev_hold(tun->dev);
sock_hold(tun->socket.sk);
atomic_inc(&tfile->count);
@@ -158,6 +160,7 @@ static void __tun_detach(struct tun_struct *tun)
/* Detach from net device */
netif_tx_lock_bh(tun->dev);
tun->tfile = NULL;
+ tun->socket.file = NULL;
netif_tx_unlock_bh(tun->dev);
/* Drop read queue */
@@ -364,6 +367,10 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
if (!check_filter(&tun->txflt, skb))
goto drop;
+ if (tun->socket.sk->sk_filter &&
+ sk_filter(tun->socket.sk, skb))
+ goto drop;
+
if (skb_queue_len(&tun->socket.sk->sk_receive_queue) >= dev->tx_queue_len) {
if (!(tun->flags & TUN_ONE_QUEUE)) {
/* Normal queueing mode. */
@@ -387,7 +394,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
/* Notify and wake up reader process */
if (tun->flags & TUN_FASYNC)
kill_fasync(&tun->fasync, SIGIO, POLL_IN);
- wake_up_interruptible(&tun->socket.wait);
+ wake_up_interruptible_poll(&tun->socket.wait, POLLIN |
+ POLLRDNORM | POLLRDBAND);
return NETDEV_TX_OK;
drop:
@@ -743,7 +751,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
len = min_t(int, skb->len, len);
skb_copy_datagram_const_iovec(skb, 0, iv, total, len);
- total += len;
+ total += skb->len;
tun->dev->stats.tx_packets++;
tun->dev->stats.tx_bytes += len;
@@ -751,34 +759,23 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
return total;
}
-static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
- unsigned long count, loff_t pos)
+static ssize_t tun_do_read(struct tun_struct *tun,
+ struct kiocb *iocb, const struct iovec *iv,
+ ssize_t len, int noblock)
{
- struct file *file = iocb->ki_filp;
- struct tun_file *tfile = file->private_data;
- struct tun_struct *tun = __tun_get(tfile);
DECLARE_WAITQUEUE(wait, current);
struct sk_buff *skb;
- ssize_t len, ret = 0;
-
- if (!tun)
- return -EBADFD;
+ ssize_t ret = 0;
DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name);
- len = iov_length(iv, count);
- if (len < 0) {
- ret = -EINVAL;
- goto out;
- }
-
add_wait_queue(&tun->socket.wait, &wait);
while (len) {
current->state = TASK_INTERRUPTIBLE;
/* Read frames from the queue */
if (!(skb=skb_dequeue(&tun->socket.sk->sk_receive_queue))) {
- if (file->f_flags & O_NONBLOCK) {
+ if (noblock) {
ret = -EAGAIN;
break;
}
@@ -805,6 +802,27 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
current->state = TASK_RUNNING;
remove_wait_queue(&tun->socket.wait, &wait);
+ return ret;
+}
+
+static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
+ unsigned long count, loff_t pos)
+{
+ struct file *file = iocb->ki_filp;
+ struct tun_file *tfile = file->private_data;
+ struct tun_struct *tun = __tun_get(tfile);
+ ssize_t len, ret;
+
+ if (!tun)
+ return -EBADFD;
+ len = iov_length(iv, count);
+ if (len < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = tun_do_read(tun, iocb, iv, len, file->f_flags & O_NONBLOCK);
+ ret = min_t(ssize_t, ret, len);
out:
tun_put(tun);
return ret;
@@ -847,7 +865,8 @@ static void tun_sock_write_space(struct sock *sk)
return;
if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
- wake_up_interruptible_sync(sk->sk_sleep);
+ wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT |
+ POLLWRNORM | POLLWRBAND);
tun = tun_sk(sk)->tun;
kill_fasync(&tun->fasync, SIGIO, POLL_OUT);
@@ -858,6 +877,37 @@ static void tun_sock_destruct(struct sock *sk)
free_netdev(tun_sk(sk)->tun->dev);
}
+static int tun_sendmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *m, size_t total_len)
+{
+ struct tun_struct *tun = container_of(sock, struct tun_struct, socket);
+ return tun_get_user(tun, m->msg_iov, total_len,
+ m->msg_flags & MSG_DONTWAIT);
+}
+
+static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *m, size_t total_len,
+ int flags)
+{
+ struct tun_struct *tun = container_of(sock, struct tun_struct, socket);
+ int ret;
+ if (flags & ~(MSG_DONTWAIT|MSG_TRUNC))
+ return -EINVAL;
+ ret = tun_do_read(tun, iocb, m->msg_iov, total_len,
+ flags & MSG_DONTWAIT);
+ if (ret > total_len) {
+ m->msg_flags |= MSG_TRUNC;
+ ret = flags & MSG_TRUNC ? ret : total_len;
+ }
+ return ret;
+}
+
+/* Ops structure to mimic raw sockets with tun */
+static const struct proto_ops tun_socket_ops = {
+ .sendmsg = tun_sendmsg,
+ .recvmsg = tun_recvmsg,
+};
+
static struct proto tun_proto = {
.name = "tun",
.owner = THIS_MODULE,
@@ -986,6 +1036,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
goto err_free_dev;
init_waitqueue_head(&tun->socket.wait);
+ tun->socket.ops = &tun_socket_ops;
sock_init_data(&tun->socket, sk);
sk->sk_write_space = tun_sock_write_space;
sk->sk_sndbuf = INT_MAX;
@@ -1116,6 +1167,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
struct tun_file *tfile = file->private_data;
struct tun_struct *tun;
void __user* argp = (void __user*)arg;
+ struct sock_fprog fprog;
struct ifreq ifr;
int sndbuf;
int ret;
@@ -1263,6 +1315,26 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
tun->socket.sk->sk_sndbuf = sndbuf;
break;
+ case TUNATTACHFILTER:
+ /* Can be set only for TAPs */
+ ret = -EINVAL;
+ if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV)
+ break;
+ ret = -EFAULT;
+ if (copy_from_user(&fprog, argp, sizeof(fprog)))
+ break;
+
+ ret = sk_attach_filter(&fprog, tun->socket.sk);
+ break;
+
+ case TUNDETACHFILTER:
+ /* Can be set only for TAPs */
+ ret = -EINVAL;
+ if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV)
+ break;
+ ret = sk_detach_filter(tun->socket.sk);
+ break;
+
default:
ret = -EINVAL;
break;
@@ -1365,7 +1437,7 @@ static int tun_chr_close(struct inode *inode, struct file *file)
__tun_detach(tun);
- /* If desireable, unregister the netdevice. */
+ /* If desirable, unregister the netdevice. */
if (!(tun->flags & TUN_PERSIST)) {
rtnl_lock();
if (dev->reg_state == NETREG_REGISTERED)
@@ -1525,6 +1597,23 @@ static void tun_cleanup(void)
rtnl_link_unregister(&tun_link_ops);
}
+/* Get an underlying socket object from tun file. Returns error unless file is
+ * attached to a device. The returned object works like a packet socket, it
+ * can be used for sock_sendmsg/sock_recvmsg. The caller is responsible for
+ * holding a reference to the file for as long as the socket is in use. */
+struct socket *tun_get_socket(struct file *file)
+{
+ struct tun_struct *tun;
+ if (file->f_op != &tun_fops)
+ return ERR_PTR(-EINVAL);
+ tun = tun_get(file);
+ if (!tun)
+ return ERR_PTR(-EBADFD);
+ tun_put(tun);
+ return &tun->socket;
+}
+EXPORT_SYMBOL_GPL(tun_get_socket);
+
module_init(tun_init);
module_exit(tun_cleanup);
MODULE_DESCRIPTION(DRV_DESCRIPTION);
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 39f1fc650be6..cd24e5f2b2a2 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -98,14 +98,10 @@ static const int multicast_filter_limit = 32;
#define TX_TIMEOUT (2*HZ)
#define PKT_BUF_SZ 1536
-
-#define DRV_MODULE_NAME "typhoon"
-#define DRV_MODULE_VERSION "1.5.9"
-#define DRV_MODULE_RELDATE "Mar 2, 2009"
-#define PFX DRV_MODULE_NAME ": "
-#define ERR_PFX KERN_ERR PFX
#define FIRMWARE_NAME "3com/typhoon.bin"
+#define pr_fmt(fmt) KBUILD_MODNAME " " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -132,14 +128,12 @@ static const int multicast_filter_limit = 32;
#include <linux/in6.h>
#include <linux/dma-mapping.h>
#include <linux/firmware.h>
+#include <generated/utsrelease.h>
#include "typhoon.h"
-static char version[] __devinitdata =
- "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
-
MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
-MODULE_VERSION(DRV_MODULE_VERSION);
+MODULE_VERSION(UTS_RELEASE);
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(FIRMWARE_NAME);
MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)");
@@ -161,8 +155,8 @@ module_param(use_mmio, int, 0);
#endif
struct typhoon_card_info {
- char *name;
- int capabilities;
+ const char *name;
+ const int capabilities;
};
#define TYPHOON_CRYPTO_NONE 0x00
@@ -215,7 +209,7 @@ static struct typhoon_card_info typhoon_card_info[] __devinitdata = {
* bit 8 indicates if this is a (0) copper or (1) fiber card
* bits 12-16 indicate card type: (0) client and (1) server
*/
-static struct pci_device_id typhoon_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(typhoon_pci_tbl) = {
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,TYPHOON_TX },
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_TX_95,
@@ -299,7 +293,6 @@ struct typhoon {
struct basic_ring respRing;
struct net_device_stats stats;
struct net_device_stats stats_saved;
- const char * name;
struct typhoon_shared * shared;
dma_addr_t shared_dma;
__le16 xcvr_select;
@@ -487,7 +480,7 @@ typhoon_hello(struct typhoon *tp)
typhoon_inc_cmd_index(&ring->lastWrite, 1);
INIT_COMMAND_NO_RESPONSE(cmd, TYPHOON_CMD_HELLO_RESP);
- smp_wmb();
+ wmb();
iowrite32(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY);
spin_unlock(&tp->command_lock);
}
@@ -534,13 +527,13 @@ typhoon_process_response(struct typhoon *tp, int resp_size,
} else if(resp->cmd == TYPHOON_CMD_HELLO_RESP) {
typhoon_hello(tp);
} else {
- printk(KERN_ERR "%s: dumping unexpected response "
- "0x%04x:%d:0x%02x:0x%04x:%08x:%08x\n",
- tp->name, le16_to_cpu(resp->cmd),
- resp->numDesc, resp->flags,
- le16_to_cpu(resp->parm1),
- le32_to_cpu(resp->parm2),
- le32_to_cpu(resp->parm3));
+ netdev_err(tp->dev,
+ "dumping unexpected response 0x%04x:%d:0x%02x:0x%04x:%08x:%08x\n",
+ le16_to_cpu(resp->cmd),
+ resp->numDesc, resp->flags,
+ le16_to_cpu(resp->parm1),
+ le32_to_cpu(resp->parm2),
+ le32_to_cpu(resp->parm3));
}
cleanup:
@@ -606,9 +599,8 @@ typhoon_issue_command(struct typhoon *tp, int num_cmd, struct cmd_desc *cmd,
freeResp = typhoon_num_free_resp(tp);
if(freeCmd < num_cmd || freeResp < num_resp) {
- printk("%s: no descs for cmd, had (needed) %d (%d) cmd, "
- "%d (%d) resp\n", tp->name, freeCmd, num_cmd,
- freeResp, num_resp);
+ netdev_err(tp->dev, "no descs for cmd, had (needed) %d (%d) cmd, %d (%d) resp\n",
+ freeCmd, num_cmd, freeResp, num_resp);
err = -ENOMEM;
goto out;
}
@@ -733,7 +725,7 @@ typhoon_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
spin_unlock_bh(&tp->state_lock);
err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
if(err < 0)
- printk("%s: vlan offload error %d\n", tp->name, -err);
+ netdev_err(tp->dev, "vlan offload error %d\n", -err);
spin_lock_bh(&tp->state_lock);
}
@@ -924,17 +916,15 @@ typhoon_set_rx_mode(struct net_device *dev)
filter = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST;
if(dev->flags & IFF_PROMISC) {
filter |= TYPHOON_RX_FILTER_PROMISCOUS;
- } else if((dev->mc_count > multicast_filter_limit) ||
+ } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
(dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
filter |= TYPHOON_RX_FILTER_ALL_MCAST;
- } else if(dev->mc_count) {
+ } else if (!netdev_mc_empty(dev)) {
struct dev_mc_list *mclist;
- int i;
memset(mc_filter, 0, sizeof(mc_filter));
- for(i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int bit = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f;
mc_filter[bit >> 5] |= 1 << (bit & 0x1f);
}
@@ -1020,7 +1010,7 @@ typhoon_get_stats(struct net_device *dev)
return saved;
if(typhoon_do_get_stats(tp) < 0) {
- printk(KERN_ERR "%s: error getting stats\n", dev->name);
+ netdev_err(dev, "error getting stats\n");
return saved;
}
@@ -1062,8 +1052,8 @@ typhoon_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
}
}
- strcpy(info->driver, DRV_MODULE_NAME);
- strcpy(info->version, DRV_MODULE_VERSION);
+ strcpy(info->driver, KBUILD_MODNAME);
+ strcpy(info->version, UTS_RELEASE);
strcpy(info->bus_info, pci_name(pci_dev));
}
@@ -1321,13 +1311,15 @@ typhoon_init_interface(struct typhoon *tp)
tp->txlo_dma_addr = le32_to_cpu(iface->txLoAddr);
tp->card_state = Sleeping;
- smp_wmb();
tp->offload = TYPHOON_OFFLOAD_IP_CHKSUM | TYPHOON_OFFLOAD_TCP_CHKSUM;
tp->offload |= TYPHOON_OFFLOAD_UDP_CHKSUM | TSO_OFFLOAD_ON;
spin_lock_init(&tp->command_lock);
spin_lock_init(&tp->state_lock);
+
+ /* Force the writes to the shared memory area out before continuing. */
+ wmb();
}
static void
@@ -1365,8 +1357,8 @@ typhoon_request_firmware(struct typhoon *tp)
err = request_firmware(&typhoon_fw, FIRMWARE_NAME, &tp->pdev->dev);
if (err) {
- printk(KERN_ERR "%s: Failed to load firmware \"%s\"\n",
- tp->name, FIRMWARE_NAME);
+ netdev_err(tp->dev, "Failed to load firmware \"%s\"\n",
+ FIRMWARE_NAME);
return err;
}
@@ -1401,7 +1393,7 @@ typhoon_request_firmware(struct typhoon *tp)
return 0;
invalid_fw:
- printk(KERN_ERR "%s: Invalid firmware image\n", tp->name);
+ netdev_err(tp->dev, "Invalid firmware image\n");
release_firmware(typhoon_fw);
typhoon_fw = NULL;
return -EINVAL;
@@ -1438,7 +1430,7 @@ typhoon_download_firmware(struct typhoon *tp)
err = -ENOMEM;
dpage = pci_alloc_consistent(pdev, PAGE_SIZE, &dpage_dma);
if(!dpage) {
- printk(KERN_ERR "%s: no DMA mem for firmware\n", tp->name);
+ netdev_err(tp->dev, "no DMA mem for firmware\n");
goto err_out;
}
@@ -1451,7 +1443,7 @@ typhoon_download_firmware(struct typhoon *tp)
err = -ETIMEDOUT;
if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
- printk(KERN_ERR "%s: card ready timeout\n", tp->name);
+ netdev_err(tp->dev, "card ready timeout\n");
goto err_out_irq;
}
@@ -1491,8 +1483,7 @@ typhoon_download_firmware(struct typhoon *tp)
if(typhoon_wait_interrupt(ioaddr) < 0 ||
ioread32(ioaddr + TYPHOON_REG_STATUS) !=
TYPHOON_STATUS_WAITING_FOR_SEGMENT) {
- printk(KERN_ERR "%s: segment ready timeout\n",
- tp->name);
+ netdev_err(tp->dev, "segment ready timeout\n");
goto err_out_irq;
}
@@ -1502,8 +1493,8 @@ typhoon_download_firmware(struct typhoon *tp)
* the checksum, we can do this once, at the end.
*/
csum = csum_fold(csum_partial_copy_nocheck(image_data,
- dpage, len,
- 0));
+ dpage, len,
+ 0));
iowrite32(len, ioaddr + TYPHOON_REG_BOOT_LENGTH);
iowrite32(le16_to_cpu((__force __le16)csum),
@@ -1514,7 +1505,7 @@ typhoon_download_firmware(struct typhoon *tp)
iowrite32(dpage_dma, ioaddr + TYPHOON_REG_BOOT_DATA_LO);
typhoon_post_pci_writes(ioaddr);
iowrite32(TYPHOON_BOOTCMD_SEG_AVAILABLE,
- ioaddr + TYPHOON_REG_COMMAND);
+ ioaddr + TYPHOON_REG_COMMAND);
image_data += len;
load_addr += len;
@@ -1525,15 +1516,15 @@ typhoon_download_firmware(struct typhoon *tp)
if(typhoon_wait_interrupt(ioaddr) < 0 ||
ioread32(ioaddr + TYPHOON_REG_STATUS) !=
TYPHOON_STATUS_WAITING_FOR_SEGMENT) {
- printk(KERN_ERR "%s: final segment ready timeout\n", tp->name);
+ netdev_err(tp->dev, "final segment ready timeout\n");
goto err_out_irq;
}
iowrite32(TYPHOON_BOOTCMD_DNLD_COMPLETE, ioaddr + TYPHOON_REG_COMMAND);
if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_BOOT) < 0) {
- printk(KERN_ERR "%s: boot ready timeout, status 0x%0x\n",
- tp->name, ioread32(ioaddr + TYPHOON_REG_STATUS));
+ netdev_err(tp->dev, "boot ready timeout, status 0x%0x\n",
+ ioread32(ioaddr + TYPHOON_REG_STATUS));
goto err_out_irq;
}
@@ -1555,7 +1546,7 @@ typhoon_boot_3XP(struct typhoon *tp, u32 initial_status)
void __iomem *ioaddr = tp->ioaddr;
if(typhoon_wait_status(ioaddr, initial_status) < 0) {
- printk(KERN_ERR "%s: boot ready timeout\n", tp->name);
+ netdev_err(tp->dev, "boot ready timeout\n");
goto out_timeout;
}
@@ -1566,8 +1557,8 @@ typhoon_boot_3XP(struct typhoon *tp, u32 initial_status)
ioaddr + TYPHOON_REG_COMMAND);
if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_RUNNING) < 0) {
- printk(KERN_ERR "%s: boot finish timeout (status 0x%x)\n",
- tp->name, ioread32(ioaddr + TYPHOON_REG_STATUS));
+ netdev_err(tp->dev, "boot finish timeout (status 0x%x)\n",
+ ioread32(ioaddr + TYPHOON_REG_STATUS));
goto out_timeout;
}
@@ -1866,8 +1857,7 @@ typhoon_interrupt(int irq, void *dev_instance)
typhoon_post_pci_writes(ioaddr);
__napi_schedule(&tp->napi);
} else {
- printk(KERN_ERR "%s: Error, poll already scheduled\n",
- dev->name);
+ netdev_err(dev, "Error, poll already scheduled\n");
}
return IRQ_HANDLED;
}
@@ -1900,16 +1890,15 @@ typhoon_sleep(struct typhoon *tp, pci_power_t state, __le16 events)
xp_cmd.parm1 = events;
err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
if(err < 0) {
- printk(KERN_ERR "%s: typhoon_sleep(): wake events cmd err %d\n",
- tp->name, err);
+ netdev_err(tp->dev, "typhoon_sleep(): wake events cmd err %d\n",
+ err);
return err;
}
INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_GOTO_SLEEP);
err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
if(err < 0) {
- printk(KERN_ERR "%s: typhoon_sleep(): sleep cmd err %d\n",
- tp->name, err);
+ netdev_err(tp->dev, "typhoon_sleep(): sleep cmd err %d\n", err);
return err;
}
@@ -1960,12 +1949,12 @@ typhoon_start_runtime(struct typhoon *tp)
err = typhoon_download_firmware(tp);
if(err < 0) {
- printk("%s: cannot load runtime on 3XP\n", tp->name);
+ netdev_err(tp->dev, "cannot load runtime on 3XP\n");
goto error_out;
}
if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_BOOT) < 0) {
- printk("%s: cannot boot 3XP\n", tp->name);
+ netdev_err(tp->dev, "cannot boot 3XP\n");
err = -EIO;
goto error_out;
}
@@ -2069,9 +2058,7 @@ typhoon_stop_runtime(struct typhoon *tp, int wait_type)
}
if(i == TYPHOON_WAIT_TIMEOUT)
- printk(KERN_ERR
- "%s: halt timed out waiting for Tx to complete\n",
- tp->name);
+ netdev_err(tp->dev, "halt timed out waiting for Tx to complete\n");
INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_TX_DISABLE);
typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
@@ -2088,11 +2075,10 @@ typhoon_stop_runtime(struct typhoon *tp, int wait_type)
typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_HALTED) < 0)
- printk(KERN_ERR "%s: timed out waiting for 3XP to halt\n",
- tp->name);
+ netdev_err(tp->dev, "timed out waiting for 3XP to halt\n");
if(typhoon_reset(ioaddr, wait_type) < 0) {
- printk(KERN_ERR "%s: unable to reset 3XP\n", tp->name);
+ netdev_err(tp->dev, "unable to reset 3XP\n");
return -ETIMEDOUT;
}
@@ -2111,9 +2097,8 @@ typhoon_tx_timeout(struct net_device *dev)
struct typhoon *tp = netdev_priv(dev);
if(typhoon_reset(tp->ioaddr, WaitNoSleep) < 0) {
- printk(KERN_WARNING "%s: could not reset in tx timeout\n",
- dev->name);
- goto truely_dead;
+ netdev_warn(dev, "could not reset in tx timeout\n");
+ goto truly_dead;
}
/* If we ever start using the Hi ring, it will need cleaning too */
@@ -2121,15 +2106,14 @@ typhoon_tx_timeout(struct net_device *dev)
typhoon_free_rx_rings(tp);
if(typhoon_start_runtime(tp) < 0) {
- printk(KERN_ERR "%s: could not start runtime in tx timeout\n",
- dev->name);
- goto truely_dead;
+ netdev_err(dev, "could not start runtime in tx timeout\n");
+ goto truly_dead;
}
netif_wake_queue(dev);
return;
-truely_dead:
+truly_dead:
/* Reset the hardware, and turn off carrier to avoid more timeouts */
typhoon_reset(tp->ioaddr, NoWait);
netif_carrier_off(dev);
@@ -2147,7 +2131,7 @@ typhoon_open(struct net_device *dev)
err = typhoon_wakeup(tp, WaitSleep);
if(err < 0) {
- printk(KERN_ERR "%s: unable to wakeup device\n", dev->name);
+ netdev_err(dev, "unable to wakeup device\n");
goto out_sleep;
}
@@ -2172,14 +2156,13 @@ out_irq:
out_sleep:
if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
- printk(KERN_ERR "%s: unable to reboot into sleep img\n",
- dev->name);
+ netdev_err(dev, "unable to reboot into sleep img\n");
typhoon_reset(tp->ioaddr, NoWait);
goto out;
}
if(typhoon_sleep(tp, PCI_D3hot, 0) < 0)
- printk(KERN_ERR "%s: unable to go back to sleep\n", dev->name);
+ netdev_err(dev, "unable to go back to sleep\n");
out:
return err;
@@ -2194,7 +2177,7 @@ typhoon_close(struct net_device *dev)
napi_disable(&tp->napi);
if(typhoon_stop_runtime(tp, WaitSleep) < 0)
- printk(KERN_ERR "%s: unable to stop runtime\n", dev->name);
+ netdev_err(dev, "unable to stop runtime\n");
/* Make sure there is no irq handler running on a different CPU. */
free_irq(dev->irq, dev);
@@ -2203,10 +2186,10 @@ typhoon_close(struct net_device *dev)
typhoon_init_rings(tp);
if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0)
- printk(KERN_ERR "%s: unable to boot sleep image\n", dev->name);
+ netdev_err(dev, "unable to boot sleep image\n");
if(typhoon_sleep(tp, PCI_D3hot, 0) < 0)
- printk(KERN_ERR "%s: unable to put card to sleep\n", dev->name);
+ netdev_err(dev, "unable to put card to sleep\n");
return 0;
}
@@ -2224,14 +2207,12 @@ typhoon_resume(struct pci_dev *pdev)
return 0;
if(typhoon_wakeup(tp, WaitNoSleep) < 0) {
- printk(KERN_ERR "%s: critical: could not wake up in resume\n",
- dev->name);
+ netdev_err(dev, "critical: could not wake up in resume\n");
goto reset;
}
if(typhoon_start_runtime(tp) < 0) {
- printk(KERN_ERR "%s: critical: could not start runtime in "
- "resume\n", dev->name);
+ netdev_err(dev, "critical: could not start runtime in resume\n");
goto reset;
}
@@ -2258,8 +2239,7 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
spin_lock_bh(&tp->state_lock);
if(tp->vlgrp && tp->wol_events & TYPHOON_WAKE_MAGIC_PKT) {
spin_unlock_bh(&tp->state_lock);
- printk(KERN_ERR "%s: cannot do WAKE_MAGIC with VLANS\n",
- dev->name);
+ netdev_err(dev, "cannot do WAKE_MAGIC with VLANS\n");
return -EBUSY;
}
spin_unlock_bh(&tp->state_lock);
@@ -2267,7 +2247,7 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
netif_device_detach(dev);
if(typhoon_stop_runtime(tp, WaitNoSleep) < 0) {
- printk(KERN_ERR "%s: unable to stop runtime\n", dev->name);
+ netdev_err(dev, "unable to stop runtime\n");
goto need_resume;
}
@@ -2275,7 +2255,7 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
typhoon_init_rings(tp);
if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
- printk(KERN_ERR "%s: unable to boot sleep image\n", dev->name);
+ netdev_err(dev, "unable to boot sleep image\n");
goto need_resume;
}
@@ -2283,21 +2263,19 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0]));
xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2]));
if(typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL) < 0) {
- printk(KERN_ERR "%s: unable to set mac address in suspend\n",
- dev->name);
+ netdev_err(dev, "unable to set mac address in suspend\n");
goto need_resume;
}
INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_RX_FILTER);
xp_cmd.parm1 = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST;
if(typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL) < 0) {
- printk(KERN_ERR "%s: unable to set rx filter in suspend\n",
- dev->name);
+ netdev_err(dev, "unable to set rx filter in suspend\n");
goto need_resume;
}
if(typhoon_sleep(tp, pci_choose_state(pdev, state), tp->wol_events) < 0) {
- printk(KERN_ERR "%s: unable to put card to sleep\n", dev->name);
+ netdev_err(dev, "unable to put card to sleep\n");
goto need_resume;
}
@@ -2351,7 +2329,7 @@ out_unmap:
out:
if(!mode)
- printk(KERN_INFO PFX "falling back to port IO\n");
+ pr_info("%s: falling back to port IO\n", pci_name(pdev));
return mode;
}
@@ -2371,7 +2349,6 @@ static const struct net_device_ops typhoon_netdev_ops = {
static int __devinit
typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int did_version = 0;
struct net_device *dev;
struct typhoon *tp;
int card_id = (int) ent->driver_data;
@@ -2381,14 +2358,11 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
struct cmd_desc xp_cmd;
struct resp_desc xp_resp[3];
int err = 0;
-
- if(!did_version++)
- printk(KERN_INFO "%s", version);
+ const char *err_msg;
dev = alloc_etherdev(sizeof(*tp));
if(dev == NULL) {
- printk(ERR_PFX "%s: unable to alloc new net device\n",
- pci_name(pdev));
+ err_msg = "unable to alloc new net device";
err = -ENOMEM;
goto error_out;
}
@@ -2396,57 +2370,48 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
err = pci_enable_device(pdev);
if(err < 0) {
- printk(ERR_PFX "%s: unable to enable device\n",
- pci_name(pdev));
+ err_msg = "unable to enable device";
goto error_out_dev;
}
err = pci_set_mwi(pdev);
if(err < 0) {
- printk(ERR_PFX "%s: unable to set MWI\n", pci_name(pdev));
+ err_msg = "unable to set MWI";
goto error_out_disable;
}
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if(err < 0) {
- printk(ERR_PFX "%s: No usable DMA configuration\n",
- pci_name(pdev));
+ err_msg = "No usable DMA configuration";
goto error_out_mwi;
}
/* sanity checks on IO and MMIO BARs
*/
if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
- printk(ERR_PFX
- "%s: region #1 not a PCI IO resource, aborting\n",
- pci_name(pdev));
+ err_msg = "region #1 not a PCI IO resource, aborting";
err = -ENODEV;
goto error_out_mwi;
}
if(pci_resource_len(pdev, 0) < 128) {
- printk(ERR_PFX "%s: Invalid PCI IO region size, aborting\n",
- pci_name(pdev));
+ err_msg = "Invalid PCI IO region size, aborting";
err = -ENODEV;
goto error_out_mwi;
}
if(!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
- printk(ERR_PFX
- "%s: region #1 not a PCI MMIO resource, aborting\n",
- pci_name(pdev));
+ err_msg = "region #1 not a PCI MMIO resource, aborting";
err = -ENODEV;
goto error_out_mwi;
}
if(pci_resource_len(pdev, 1) < 128) {
- printk(ERR_PFX "%s: Invalid PCI MMIO region size, aborting\n",
- pci_name(pdev));
+ err_msg = "Invalid PCI MMIO region size, aborting";
err = -ENODEV;
goto error_out_mwi;
}
- err = pci_request_regions(pdev, "typhoon");
+ err = pci_request_regions(pdev, KBUILD_MODNAME);
if(err < 0) {
- printk(ERR_PFX "%s: could not request regions\n",
- pci_name(pdev));
+ err_msg = "could not request regions";
goto error_out_mwi;
}
@@ -2457,8 +2422,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
ioaddr = pci_iomap(pdev, use_mmio, 128);
if (!ioaddr) {
- printk(ERR_PFX "%s: cannot remap registers, aborting\n",
- pci_name(pdev));
+ err_msg = "cannot remap registers, aborting";
err = -EIO;
goto error_out_regions;
}
@@ -2468,8 +2432,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
shared = pci_alloc_consistent(pdev, sizeof(struct typhoon_shared),
&shared_dma);
if(!shared) {
- printk(ERR_PFX "%s: could not allocate DMA memory\n",
- pci_name(pdev));
+ err_msg = "could not allocate DMA memory";
err = -ENOMEM;
goto error_out_remap;
}
@@ -2492,7 +2455,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
* 5) Put the card to sleep.
*/
if (typhoon_reset(ioaddr, WaitSleep) < 0) {
- printk(ERR_PFX "%s: could not reset 3XP\n", pci_name(pdev));
+ err_msg = "could not reset 3XP";
err = -EIO;
goto error_out_dma;
}
@@ -2504,26 +2467,18 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
pci_save_state(pdev);
- /* dev->name is not valid until we register, but we need to
- * use some common routines to initialize the card. So that those
- * routines print the right name, we keep our oun pointer to the name
- */
- tp->name = pci_name(pdev);
-
typhoon_init_interface(tp);
typhoon_init_rings(tp);
if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
- printk(ERR_PFX "%s: cannot boot 3XP sleep image\n",
- pci_name(pdev));
+ err_msg = "cannot boot 3XP sleep image";
err = -EIO;
goto error_out_reset;
}
INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_MAC_ADDRESS);
if(typhoon_issue_command(tp, 1, &xp_cmd, 1, xp_resp) < 0) {
- printk(ERR_PFX "%s: cannot read MAC address\n",
- pci_name(pdev));
+ err_msg = "cannot read MAC address";
err = -EIO;
goto error_out_reset;
}
@@ -2532,8 +2487,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
*(__be32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
if(!is_valid_ether_addr(dev->dev_addr)) {
- printk(ERR_PFX "%s: Could not obtain valid ethernet address, "
- "aborting\n", pci_name(pdev));
+ err_msg = "Could not obtain valid ethernet address, aborting";
goto error_out_reset;
}
@@ -2542,8 +2496,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_VERSIONS);
if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) {
- printk(ERR_PFX "%s: Could not get Sleep Image version\n",
- pci_name(pdev));
+ err_msg = "Could not get Sleep Image version";
goto error_out_reset;
}
@@ -2560,8 +2513,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->capabilities |= TYPHOON_WAKEUP_NEEDS_RESET;
if(typhoon_sleep(tp, PCI_D3hot, 0) < 0) {
- printk(ERR_PFX "%s: cannot put adapter to sleep\n",
- pci_name(pdev));
+ err_msg = "cannot put adapter to sleep";
err = -EIO;
goto error_out_reset;
}
@@ -2580,19 +2532,18 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
dev->features |= NETIF_F_TSO;
- if(register_netdev(dev) < 0)
+ if(register_netdev(dev) < 0) {
+ err_msg = "unable to register netdev";
goto error_out_reset;
-
- /* fixup our local name */
- tp->name = dev->name;
+ }
pci_set_drvdata(pdev, dev);
- printk(KERN_INFO "%s: %s at %s 0x%llx, %pM\n",
- dev->name, typhoon_card_info[card_id].name,
- use_mmio ? "MMIO" : "IO",
- (unsigned long long)pci_resource_start(pdev, use_mmio),
- dev->dev_addr);
+ netdev_info(dev, "%s at %s 0x%llx, %pM\n",
+ typhoon_card_info[card_id].name,
+ use_mmio ? "MMIO" : "IO",
+ (unsigned long long)pci_resource_start(pdev, use_mmio),
+ dev->dev_addr);
/* xp_resp still contains the response to the READ_VERSIONS command.
* For debugging, let the user know what version he has.
@@ -2602,23 +2553,20 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
* of version is Month/Day of build.
*/
u16 monthday = le32_to_cpu(xp_resp[0].parm2) & 0xffff;
- printk(KERN_INFO "%s: Typhoon 1.0 Sleep Image built "
- "%02u/%02u/2000\n", dev->name, monthday >> 8,
- monthday & 0xff);
+ netdev_info(dev, "Typhoon 1.0 Sleep Image built %02u/%02u/2000\n",
+ monthday >> 8, monthday & 0xff);
} else if(xp_resp[0].numDesc == 2) {
/* This is the Typhoon 1.1+ type Sleep Image
*/
u32 sleep_ver = le32_to_cpu(xp_resp[0].parm2);
u8 *ver_string = (u8 *) &xp_resp[1];
ver_string[25] = 0;
- printk(KERN_INFO "%s: Typhoon 1.1+ Sleep Image version "
- "%02x.%03x.%03x %s\n", dev->name, sleep_ver >> 24,
- (sleep_ver >> 12) & 0xfff, sleep_ver & 0xfff,
- ver_string);
+ netdev_info(dev, "Typhoon 1.1+ Sleep Image version %02x.%03x.%03x %s\n",
+ sleep_ver >> 24, (sleep_ver >> 12) & 0xfff,
+ sleep_ver & 0xfff, ver_string);
} else {
- printk(KERN_WARNING "%s: Unknown Sleep Image version "
- "(%u:%04x)\n", dev->name, xp_resp[0].numDesc,
- le32_to_cpu(xp_resp[0].parm2));
+ netdev_warn(dev, "Unknown Sleep Image version (%u:%04x)\n",
+ xp_resp[0].numDesc, le32_to_cpu(xp_resp[0].parm2));
}
return 0;
@@ -2640,6 +2588,7 @@ error_out_disable:
error_out_dev:
free_netdev(dev);
error_out:
+ pr_err("%s: %s\n", pci_name(pdev), err_msg);
return err;
}
@@ -2664,7 +2613,7 @@ typhoon_remove_one(struct pci_dev *pdev)
}
static struct pci_driver typhoon_driver = {
- .name = DRV_MODULE_NAME,
+ .name = KBUILD_MODNAME,
.id_table = typhoon_pci_tbl,
.probe = typhoon_init_one,
.remove = __devexit_p(typhoon_remove_one),
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 96bdc0b43889..1b0aef37e495 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -37,6 +37,7 @@
#include <asm/qe.h>
#include <asm/ucc.h>
#include <asm/ucc_fast.h>
+#include <asm/machdep.h>
#include "ucc_geth.h"
#include "fsl_pq_mdio.h"
@@ -429,7 +430,7 @@ static void hw_add_addr_in_hash(struct ucc_geth_private *ugeth,
ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
/* Ethernet frames are defined in Little Endian mode,
- therefor to insert */
+ therefore to insert */
/* the address to the hash (Big Endian mode), we reverse the bytes.*/
set_mac_addr(&p_82xx_addr_filt->taddr.h, p_enet_addr);
@@ -1334,7 +1335,7 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
struct ucc_geth __iomem *ug_regs;
struct ucc_fast __iomem *uf_regs;
int ret_val;
- u32 upsmr, maccfg2, tbiBaseAddress;
+ u32 upsmr, maccfg2;
u16 value;
ugeth_vdbg("%s: IN", __func__);
@@ -1389,14 +1390,20 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
/* Note that this depends on proper setting in utbipar register. */
if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
- tbiBaseAddress = in_be32(&ug_regs->utbipar);
- tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK;
- tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT;
- value = ugeth->phydev->bus->read(ugeth->phydev->bus,
- (u8) tbiBaseAddress, ENET_TBI_MII_CR);
+ struct ucc_geth_info *ug_info = ugeth->ug_info;
+ struct phy_device *tbiphy;
+
+ if (!ug_info->tbi_node)
+ ugeth_warn("TBI mode requires that the device "
+ "tree specify a tbi-handle\n");
+
+ tbiphy = of_phy_find_device(ug_info->tbi_node);
+ if (!tbiphy)
+ ugeth_warn("Could not get TBI device\n");
+
+ value = phy_read(tbiphy, ENET_TBI_MII_CR);
value &= ~0x1000; /* Turn off autonegotiation */
- ugeth->phydev->bus->write(ugeth->phydev->bus,
- (u8) tbiBaseAddress, ENET_TBI_MII_CR, value);
+ phy_write(tbiphy, ENET_TBI_MII_CR, value);
}
init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2);
@@ -1995,7 +2002,6 @@ static void ucc_geth_set_multi(struct net_device *dev)
struct dev_mc_list *dmi;
struct ucc_fast __iomem *uf_regs;
struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
- int i;
ugeth = netdev_priv(dev);
@@ -2022,10 +2028,7 @@ static void ucc_geth_set_multi(struct net_device *dev)
out_be32(&p_82xx_addr_filt->gaddr_h, 0x0);
out_be32(&p_82xx_addr_filt->gaddr_l, 0x0);
- dmi = dev->mc_list;
-
- for (i = 0; i < dev->mc_count; i++, dmi = dmi->next) {
-
+ netdev_for_each_mc_addr(dmi, dev) {
/* Only support group multicast for now.
*/
if (!(dmi->dmi_addr[0] & 1))
@@ -3279,13 +3282,12 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
/* Handle the transmitted buffer and release */
/* the BD to be used with the current frame */
- if (bd == ugeth->txBd[txQ]) /* queue empty? */
+ skb = ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]];
+ if (!skb)
break;
dev->stats.tx_packets++;
- skb = ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]];
-
if (skb_queue_len(&ugeth->rx_recycle) < RX_BD_RING_LEN &&
skb_recycle_check(skb,
ugeth->ug_info->uf_info.max_rx_buf_length +
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index a516185cbc9f..9e05639435f2 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -54,6 +54,7 @@ static const char driver_name [] = "asix";
#define AX_CMD_WRITE_IPG0 0x12
#define AX_CMD_WRITE_IPG1 0x13
#define AX_CMD_READ_NODE_ID 0x13
+#define AX_CMD_WRITE_NODE_ID 0x14
#define AX_CMD_WRITE_IPG2 0x14
#define AX_CMD_WRITE_MULTI_FILTER 0x16
#define AX88172_CMD_READ_NODE_ID 0x17
@@ -165,6 +166,7 @@ static const char driver_name [] = "asix";
/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
struct asix_data {
u8 multi_filter[AX_MCAST_FILTER_SIZE];
+ u8 mac_addr[ETH_ALEN];
u8 phymode;
u8 ledmode;
u8 eeprom_len;
@@ -184,8 +186,8 @@ static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
void *buf;
int err = -ENOMEM;
- devdbg(dev,"asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d",
- cmd, value, index, size);
+ netdev_dbg(dev->net, "asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
+ cmd, value, index, size);
buf = kmalloc(size, GFP_KERNEL);
if (!buf)
@@ -217,8 +219,8 @@ static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
void *buf = NULL;
int err = -ENOMEM;
- devdbg(dev,"asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d",
- cmd, value, index, size);
+ netdev_dbg(dev->net, "asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
+ cmd, value, index, size);
if (data) {
buf = kmalloc(size, GFP_KERNEL);
@@ -264,15 +266,15 @@ asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
int status;
struct urb *urb;
- devdbg(dev,"asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d",
- cmd, value, index, size);
+ netdev_dbg(dev->net, "asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
+ cmd, value, index, size);
if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {
- deverr(dev, "Error allocating URB in write_cmd_async!");
+ netdev_err(dev->net, "Error allocating URB in write_cmd_async!\n");
return;
}
if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) {
- deverr(dev, "Failed to allocate memory for control request");
+ netdev_err(dev->net, "Failed to allocate memory for control request\n");
usb_free_urb(urb);
return;
}
@@ -289,8 +291,8 @@ asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
asix_async_cmd_callback, req);
if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- deverr(dev, "Error submitting the control message: status=%d",
- status);
+ netdev_err(dev->net, "Error submitting the control message: status=%d\n",
+ status);
kfree(req);
usb_free_urb(urb);
}
@@ -314,7 +316,7 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
while (skb->len > 0) {
if ((short)(header & 0x0000ffff) !=
~((short)((header & 0xffff0000) >> 16))) {
- deverr(dev,"asix_rx_fixup() Bad Header Length");
+ netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
}
/* get the packet length */
size = (u16) (header & 0x0000ffff);
@@ -322,7 +324,8 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
if ((skb->len) - ((size + 1) & 0xfffe) == 0)
return 2;
if (size > ETH_FRAME_LEN) {
- deverr(dev,"asix_rx_fixup() Bad RX Length %d", size);
+ netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
+ size);
return 0;
}
ax_skb = skb_clone(skb, GFP_ATOMIC);
@@ -348,7 +351,8 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
}
if (skb->len < 0) {
- deverr(dev,"asix_rx_fixup() Bad SKB Length %d", skb->len);
+ netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n",
+ skb->len);
return 0;
}
return 1;
@@ -409,7 +413,7 @@ static void asix_status(struct usbnet *dev, struct urb *urb)
usbnet_defer_kevent (dev, EVENT_LINK_RESET );
} else
netif_carrier_off(dev->net);
- devdbg(dev, "Link Status is: %d", link);
+ netdev_dbg(dev->net, "Link Status is: %d\n", link);
}
}
@@ -418,7 +422,7 @@ static inline int asix_set_sw_mii(struct usbnet *dev)
int ret;
ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
if (ret < 0)
- deverr(dev, "Failed to enable software MII access");
+ netdev_err(dev->net, "Failed to enable software MII access\n");
return ret;
}
@@ -427,7 +431,7 @@ static inline int asix_set_hw_mii(struct usbnet *dev)
int ret;
ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
if (ret < 0)
- deverr(dev, "Failed to enable hardware MII access");
+ netdev_err(dev->net, "Failed to enable hardware MII access\n");
return ret;
}
@@ -436,13 +440,14 @@ static inline int asix_get_phy_addr(struct usbnet *dev)
u8 buf[2];
int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf);
- devdbg(dev, "asix_get_phy_addr()");
+ netdev_dbg(dev->net, "asix_get_phy_addr()\n");
if (ret < 0) {
- deverr(dev, "Error reading PHYID register: %02x", ret);
+ netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret);
goto out;
}
- devdbg(dev, "asix_get_phy_addr() returning 0x%04x", *((__le16 *)buf));
+ netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n",
+ *((__le16 *)buf));
ret = buf[1];
out:
@@ -455,7 +460,7 @@ static int asix_sw_reset(struct usbnet *dev, u8 flags)
ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);
if (ret < 0)
- deverr(dev,"Failed to send software reset: %02x", ret);
+ netdev_err(dev->net, "Failed to send software reset: %02x\n", ret);
return ret;
}
@@ -466,7 +471,7 @@ static u16 asix_read_rx_ctl(struct usbnet *dev)
int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v);
if (ret < 0) {
- deverr(dev, "Error reading RX_CTL register: %02x", ret);
+ netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret);
goto out;
}
ret = le16_to_cpu(v);
@@ -478,11 +483,11 @@ static int asix_write_rx_ctl(struct usbnet *dev, u16 mode)
{
int ret;
- devdbg(dev,"asix_write_rx_ctl() - mode = 0x%04x", mode);
+ netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode);
ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
if (ret < 0)
- deverr(dev, "Failed to write RX_CTL mode to 0x%04x: %02x",
- mode, ret);
+ netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n",
+ mode, ret);
return ret;
}
@@ -493,7 +498,8 @@ static u16 asix_read_medium_status(struct usbnet *dev)
int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v);
if (ret < 0) {
- deverr(dev, "Error reading Medium Status register: %02x", ret);
+ netdev_err(dev->net, "Error reading Medium Status register: %02x\n",
+ ret);
goto out;
}
ret = le16_to_cpu(v);
@@ -505,11 +511,11 @@ static int asix_write_medium_mode(struct usbnet *dev, u16 mode)
{
int ret;
- devdbg(dev,"asix_write_medium_mode() - mode = 0x%04x", mode);
+ netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode);
ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
if (ret < 0)
- deverr(dev, "Failed to write Medium Mode mode to 0x%04x: %02x",
- mode, ret);
+ netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n",
+ mode, ret);
return ret;
}
@@ -518,11 +524,11 @@ static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep)
{
int ret;
- devdbg(dev,"asix_write_gpio() - value = 0x%04x", value);
+ netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value);
ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
if (ret < 0)
- deverr(dev, "Failed to write GPIO value 0x%04x: %02x",
- value, ret);
+ netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n",
+ value, ret);
if (sleep)
msleep(sleep);
@@ -542,29 +548,27 @@ static void asix_set_multicast(struct net_device *net)
if (net->flags & IFF_PROMISC) {
rx_ctl |= AX_RX_CTL_PRO;
} else if (net->flags & IFF_ALLMULTI ||
- net->mc_count > AX_MAX_MCAST) {
+ netdev_mc_count(net) > AX_MAX_MCAST) {
rx_ctl |= AX_RX_CTL_AMALL;
- } else if (net->mc_count == 0) {
+ } else if (netdev_mc_empty(net)) {
/* just broadcast and directed */
} else {
/* We use the 20 byte dev->data
* for our 8 byte filter buffer
* to avoid allocating memory that
* is tricky to free later */
- struct dev_mc_list *mc_list = net->mc_list;
+ struct dev_mc_list *mc_list;
u32 crc_bits;
- int i;
memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
/* Build the multicast hash filter. */
- for (i = 0; i < net->mc_count; i++) {
+ netdev_for_each_mc_addr(mc_list, net) {
crc_bits =
ether_crc(ETH_ALEN,
mc_list->dmi_addr) >> 26;
data->multi_filter[crc_bits >> 3] |=
1 << (crc_bits & 7);
- mc_list = mc_list->next;
}
asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
@@ -588,7 +592,8 @@ static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
asix_set_hw_mii(dev);
mutex_unlock(&dev->phy_mutex);
- devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res));
+ netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+ phy_id, loc, le16_to_cpu(res));
return le16_to_cpu(res);
}
@@ -599,7 +604,8 @@ asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
struct usbnet *dev = netdev_priv(netdev);
__le16 res = cpu_to_le16(val);
- devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val);
+ netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+ phy_id, loc, val);
mutex_lock(&dev->phy_mutex);
asix_set_sw_mii(dev);
asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res);
@@ -728,6 +734,30 @@ static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
+static int asix_set_mac_address(struct net_device *net, void *p)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct asix_data *data = (struct asix_data *)&dev->data;
+ struct sockaddr *addr = p;
+
+ if (netif_running(net))
+ return -EBUSY;
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);
+
+ /* We use the 20 byte dev->data
+ * for our 6 byte mac buffer
+ * to avoid allocating memory that
+ * is tricky to free later */
+ memcpy(data->mac_addr, addr->sa_data, ETH_ALEN);
+ asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
+ data->mac_addr);
+
+ return 0;
+}
+
/* We need to override some ethtool_ops so we require our
own structure so we don't interfere with other usbnet
devices that may be connected at the same time. */
@@ -754,29 +784,27 @@ static void ax88172_set_multicast(struct net_device *net)
if (net->flags & IFF_PROMISC) {
rx_ctl |= 0x01;
} else if (net->flags & IFF_ALLMULTI ||
- net->mc_count > AX_MAX_MCAST) {
+ netdev_mc_count(net) > AX_MAX_MCAST) {
rx_ctl |= 0x02;
- } else if (net->mc_count == 0) {
+ } else if (netdev_mc_empty(net)) {
/* just broadcast and directed */
} else {
/* We use the 20 byte dev->data
* for our 8 byte filter buffer
* to avoid allocating memory that
* is tricky to free later */
- struct dev_mc_list *mc_list = net->mc_list;
+ struct dev_mc_list *mc_list;
u32 crc_bits;
- int i;
memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
/* Build the multicast hash filter. */
- for (i = 0; i < net->mc_count; i++) {
+ netdev_for_each_mc_addr(mc_list, net) {
crc_bits =
ether_crc(ETH_ALEN,
mc_list->dmi_addr) >> 26;
data->multi_filter[crc_bits >> 3] |=
1 << (crc_bits & 7);
- mc_list = mc_list->next;
}
asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
@@ -800,7 +828,8 @@ static int ax88172_link_reset(struct usbnet *dev)
if (ecmd.duplex != DUPLEX_FULL)
mode |= ~AX88172_MEDIUM_FD;
- devdbg(dev, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);
+ netdev_dbg(dev->net, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n",
+ ecmd.speed, ecmd.duplex, mode);
asix_write_medium_mode(dev, mode);
@@ -902,7 +931,8 @@ static int ax88772_link_reset(struct usbnet *dev)
if (ecmd.duplex != DUPLEX_FULL)
mode &= ~AX_MEDIUM_FD;
- devdbg(dev, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);
+ netdev_dbg(dev->net, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n",
+ ecmd.speed, ecmd.duplex, mode);
asix_write_medium_mode(dev, mode);
@@ -915,7 +945,7 @@ static const struct net_device_ops ax88772_netdev_ops = {
.ndo_start_xmit = usbnet_start_xmit,
.ndo_tx_timeout = usbnet_tx_timeout,
.ndo_change_mtu = usbnet_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_mac_address = asix_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = asix_ioctl,
.ndo_set_multicast_list = asix_set_multicast,
@@ -1059,10 +1089,10 @@ static int marvell_phy_init(struct usbnet *dev)
struct asix_data *data = (struct asix_data *)&dev->data;
u16 reg;
- devdbg(dev,"marvell_phy_init()");
+ netdev_dbg(dev->net, "marvell_phy_init()\n");
reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS);
- devdbg(dev,"MII_MARVELL_STATUS = 0x%04x", reg);
+ netdev_dbg(dev->net, "MII_MARVELL_STATUS = 0x%04x\n", reg);
asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL,
MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY);
@@ -1070,7 +1100,7 @@ static int marvell_phy_init(struct usbnet *dev)
if (data->ledmode) {
reg = asix_mdio_read(dev->net, dev->mii.phy_id,
MII_MARVELL_LED_CTRL);
- devdbg(dev,"MII_MARVELL_LED_CTRL (1) = 0x%04x", reg);
+ netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (1) = 0x%04x\n", reg);
reg &= 0xf8ff;
reg |= (1 + 0x0100);
@@ -1079,7 +1109,7 @@ static int marvell_phy_init(struct usbnet *dev)
reg = asix_mdio_read(dev->net, dev->mii.phy_id,
MII_MARVELL_LED_CTRL);
- devdbg(dev,"MII_MARVELL_LED_CTRL (2) = 0x%04x", reg);
+ netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (2) = 0x%04x\n", reg);
reg &= 0xfc0f;
}
@@ -1090,7 +1120,7 @@ static int marvell_led_status(struct usbnet *dev, u16 speed)
{
u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL);
- devdbg(dev, "marvell_led_status() read 0x%04x", reg);
+ netdev_dbg(dev->net, "marvell_led_status() read 0x%04x\n", reg);
/* Clear out the center LED bits - 0x03F0 */
reg &= 0xfc0f;
@@ -1106,7 +1136,7 @@ static int marvell_led_status(struct usbnet *dev, u16 speed)
reg |= 0x02f0;
}
- devdbg(dev, "marvell_led_status() writing 0x%04x", reg);
+ netdev_dbg(dev->net, "marvell_led_status() writing 0x%04x\n", reg);
asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg);
return 0;
@@ -1118,7 +1148,7 @@ static int ax88178_link_reset(struct usbnet *dev)
struct ethtool_cmd ecmd;
struct asix_data *data = (struct asix_data *)&dev->data;
- devdbg(dev,"ax88178_link_reset()");
+ netdev_dbg(dev->net, "ax88178_link_reset()\n");
mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
@@ -1138,7 +1168,8 @@ static int ax88178_link_reset(struct usbnet *dev)
else
mode &= ~AX_MEDIUM_FD;
- devdbg(dev, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);
+ netdev_dbg(dev->net, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n",
+ ecmd.speed, ecmd.duplex, mode);
asix_write_medium_mode(dev, mode);
@@ -1188,7 +1219,7 @@ static int ax88178_change_mtu(struct net_device *net, int new_mtu)
struct usbnet *dev = netdev_priv(net);
int ll_mtu = new_mtu + net->hard_header_len + 4;
- devdbg(dev, "ax88178_change_mtu() new_mtu=%d", new_mtu);
+ netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", new_mtu);
if (new_mtu <= 0 || ll_mtu > 16384)
return -EINVAL;
@@ -1208,7 +1239,7 @@ static const struct net_device_ops ax88178_netdev_ops = {
.ndo_stop = usbnet_stop,
.ndo_start_xmit = usbnet_start_xmit,
.ndo_tx_timeout = usbnet_tx_timeout,
- .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_mac_address = asix_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_multicast_list = asix_set_multicast,
.ndo_do_ioctl = asix_ioctl,
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 22b87e64a810..96f1ebe0d348 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -632,7 +632,6 @@ static void catc_set_multicast_list(struct net_device *netdev)
struct dev_mc_list *mc;
u8 broadcast[6];
u8 rx = RxEnable | RxPolarity | RxMultiCast;
- int i;
memset(broadcast, 0xff, 6);
memset(catc->multicast, 0, 64);
@@ -648,7 +647,7 @@ static void catc_set_multicast_list(struct net_device *netdev)
if (netdev->flags & IFF_ALLMULTI) {
memset(catc->multicast, 0xff, 64);
} else {
- for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next) {
+ netdev_for_each_mc_addr(mc, netdev) {
u32 crc = ether_crc_le(6, mc->dmi_addr);
if (!catc->is_f5u011) {
catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);
@@ -897,11 +896,9 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
f5u011_rxmode(catc, catc->rxmode);
}
dbg("Init done.");
- printk(KERN_INFO "%s: %s USB Ethernet at usb-%s-%s, ",
+ printk(KERN_INFO "%s: %s USB Ethernet at usb-%s-%s, %pM.\n",
netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate",
- usbdev->bus->bus_name, usbdev->devpath);
- for (i = 0; i < 5; i++) printk("%2.2x:", netdev->dev_addr[i]);
- printk("%2.2x.\n", netdev->dev_addr[i]);
+ usbdev->bus->bus_name, usbdev->devpath, netdev->dev_addr);
usb_set_intfdata(intf, catc);
SET_NETDEV_DEV(netdev, &intf->dev);
diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c
index c337ffc3304a..a4a85a6ed86d 100644
--- a/drivers/net/usb/cdc_eem.c
+++ b/drivers/net/usb/cdc_eem.c
@@ -73,7 +73,7 @@ static void eem_linkcmd(struct usbnet *dev, struct sk_buff *skb)
usb_free_urb(urb);
fail:
dev_kfree_skb(skb);
- devwarn(dev, "link cmd failure\n");
+ netdev_warn(dev->net, "link cmd failure\n");
return;
}
}
@@ -212,7 +212,8 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
* b15: 1 (EEM command)
*/
if (header & BIT(14)) {
- devdbg(dev, "reserved command %04x\n", header);
+ netdev_dbg(dev->net, "reserved command %04x\n",
+ header);
continue;
}
@@ -255,8 +256,9 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
case 1: /* Echo response */
case 5: /* Tickle */
default: /* reserved */
- devwarn(dev, "unexpected link command %d\n",
- bmEEMCmd);
+ netdev_warn(dev->net,
+ "unexpected link command %d\n",
+ bmEEMCmd);
continue;
}
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 21e183a83b99..c8cdb7f30adc 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -339,10 +339,10 @@ EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
static void dumpspeed(struct usbnet *dev, __le32 *speeds)
{
- if (netif_msg_timer(dev))
- devinfo(dev, "link speeds: %u kbps up, %u kbps down",
- __le32_to_cpu(speeds[0]) / 1000,
- __le32_to_cpu(speeds[1]) / 1000);
+ netif_info(dev, timer, dev->net,
+ "link speeds: %u kbps up, %u kbps down\n",
+ __le32_to_cpu(speeds[0]) / 1000,
+ __le32_to_cpu(speeds[1]) / 1000);
}
static void cdc_status(struct usbnet *dev, struct urb *urb)
@@ -361,18 +361,16 @@ static void cdc_status(struct usbnet *dev, struct urb *urb)
event = urb->transfer_buffer;
switch (event->bNotificationType) {
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
- if (netif_msg_timer(dev))
- devdbg(dev, "CDC: carrier %s",
- event->wValue ? "on" : "off");
+ netif_dbg(dev, timer, dev->net, "CDC: carrier %s\n",
+ event->wValue ? "on" : "off");
if (event->wValue)
netif_carrier_on(dev->net);
else
netif_carrier_off(dev->net);
break;
case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */
- if (netif_msg_timer(dev))
- devdbg(dev, "CDC: speed change (len %d)",
- urb->actual_length);
+ netif_dbg(dev, timer, dev->net, "CDC: speed change (len %d)\n",
+ urb->actual_length);
if (urb->actual_length != (sizeof *event + 8))
set_bit(EVENT_STS_SPLIT, &dev->flags);
else
@@ -382,8 +380,8 @@ static void cdc_status(struct usbnet *dev, struct urb *urb)
* but there are no standard formats for the response data.
*/
default:
- deverr(dev, "CDC: unexpected notification %02x!",
- event->bNotificationType);
+ netdev_err(dev->net, "CDC: unexpected notification %02x!\n",
+ event->bNotificationType);
break;
}
}
@@ -419,7 +417,7 @@ static int cdc_manage_power(struct usbnet *dev, int on)
static const struct driver_info cdc_info = {
.description = "CDC Ethernet Device",
- .flags = FLAG_ETHER | FLAG_LINK_INTR,
+ .flags = FLAG_ETHER,
// .check_connect = cdc_check_connect,
.bind = cdc_bind,
.unbind = usbnet_cdc_unbind,
@@ -584,6 +582,11 @@ static const struct usb_device_id products [] = {
USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
.driver_info = (unsigned long) &mbm_info,
}, {
+ /* Ericsson C3607w ver 2 */
+ USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x190b, USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long) &mbm_info,
+}, {
/* Toshiba F3507g */
USB_DEVICE_AND_INTERFACE_INFO(0x0930, 0x130b, USB_CLASS_COMM,
USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index 3d406f9b2f29..269339769f47 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -58,7 +58,7 @@ static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data)
void *buf;
int err = -ENOMEM;
- devdbg(dev, "dm_read() reg=0x%02x length=%d", reg, length);
+ netdev_dbg(dev->net, "dm_read() reg=0x%02x length=%d\n", reg, length);
buf = kmalloc(length, GFP_KERNEL);
if (!buf)
@@ -89,7 +89,7 @@ static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data)
void *buf = NULL;
int err = -ENOMEM;
- devdbg(dev, "dm_write() reg=0x%02x, length=%d", reg, length);
+ netdev_dbg(dev->net, "dm_write() reg=0x%02x, length=%d\n", reg, length);
if (data) {
buf = kmalloc(length, GFP_KERNEL);
@@ -112,7 +112,8 @@ static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data)
static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value)
{
- devdbg(dev, "dm_write_reg() reg=0x%02x, value=0x%02x", reg, value);
+ netdev_dbg(dev->net, "dm_write_reg() reg=0x%02x, value=0x%02x\n",
+ reg, value);
return usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
DM_WRITE_REG,
@@ -142,13 +143,13 @@ static void dm_write_async_helper(struct usbnet *dev, u8 reg, u8 value,
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
- deverr(dev, "Error allocating URB in dm_write_async_helper!");
+ netdev_err(dev->net, "Error allocating URB in dm_write_async_helper!\n");
return;
}
req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
if (!req) {
- deverr(dev, "Failed to allocate memory for control request");
+ netdev_err(dev->net, "Failed to allocate memory for control request\n");
usb_free_urb(urb);
return;
}
@@ -166,8 +167,8 @@ static void dm_write_async_helper(struct usbnet *dev, u8 reg, u8 value,
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status < 0) {
- deverr(dev, "Error submitting the control message: status=%d",
- status);
+ netdev_err(dev->net, "Error submitting the control message: status=%d\n",
+ status);
kfree(req);
usb_free_urb(urb);
}
@@ -175,15 +176,15 @@ static void dm_write_async_helper(struct usbnet *dev, u8 reg, u8 value,
static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
{
- devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length);
+ netdev_dbg(dev->net, "dm_write_async() reg=0x%02x length=%d\n", reg, length);
dm_write_async_helper(dev, reg, 0, length, data);
}
static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
{
- devdbg(dev, "dm_write_reg_async() reg=0x%02x value=0x%02x",
- reg, value);
+ netdev_dbg(dev->net, "dm_write_reg_async() reg=0x%02x value=0x%02x\n",
+ reg, value);
dm_write_async_helper(dev, reg, value, 0, NULL);
}
@@ -211,7 +212,7 @@ static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *valu
}
if (i == DM_TIMEOUT) {
- deverr(dev, "%s read timed out!", phy ? "phy" : "eeprom");
+ netdev_err(dev->net, "%s read timed out!\n", phy ? "phy" : "eeprom");
ret = -EIO;
goto out;
}
@@ -219,8 +220,8 @@ static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *valu
dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
ret = dm_read(dev, DM_SHARED_DATA, 2, value);
- devdbg(dev, "read shared %d 0x%02x returned 0x%04x, %d",
- phy, reg, *value, ret);
+ netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
+ phy, reg, *value, ret);
out:
mutex_unlock(&dev->phy_mutex);
@@ -254,7 +255,7 @@ static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 valu
}
if (i == DM_TIMEOUT) {
- deverr(dev, "%s write timed out!", phy ? "phy" : "eeprom");
+ netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
ret = -EIO;
goto out;
}
@@ -304,15 +305,15 @@ static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc)
__le16 res;
if (phy_id) {
- devdbg(dev, "Only internal phy supported");
+ netdev_dbg(dev->net, "Only internal phy supported\n");
return 0;
}
dm_read_shared_word(dev, 1, loc, &res);
- devdbg(dev,
- "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x",
- phy_id, loc, le16_to_cpu(res));
+ netdev_dbg(dev->net,
+ "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+ phy_id, loc, le16_to_cpu(res));
return le16_to_cpu(res);
}
@@ -324,12 +325,12 @@ static void dm9601_mdio_write(struct net_device *netdev, int phy_id, int loc,
__le16 res = cpu_to_le16(val);
if (phy_id) {
- devdbg(dev, "Only internal phy supported");
+ netdev_dbg(dev->net, "Only internal phy supported\n");
return;
}
- devdbg(dev,"dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x",
- phy_id, loc, val);
+ netdev_dbg(dev->net, "dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+ phy_id, loc, val);
dm_write_shared_word(dev, 1, loc, res);
}
@@ -381,13 +382,13 @@ static void dm9601_set_multicast(struct net_device *net)
if (net->flags & IFF_PROMISC) {
rx_ctl |= 0x02;
- } else if (net->flags & IFF_ALLMULTI || net->mc_count > DM_MAX_MCAST) {
+ } else if (net->flags & IFF_ALLMULTI ||
+ netdev_mc_count(net) > DM_MAX_MCAST) {
rx_ctl |= 0x04;
- } else if (net->mc_count) {
- struct dev_mc_list *mc_list = net->mc_list;
- int i;
+ } else if (!netdev_mc_empty(net)) {
+ struct dev_mc_list *mc_list;
- for (i = 0; i < net->mc_count; i++, mc_list = mc_list->next) {
+ netdev_for_each_mc_addr(mc_list, net) {
u32 crc = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
hashes[crc >> 3] |= 1 << (crc & 0x7);
}
@@ -592,7 +593,7 @@ static void dm9601_status(struct usbnet *dev, struct urb *urb)
}
else
netif_carrier_off(dev->net);
- devdbg(dev, "Link Status is: %d", link);
+ netdev_dbg(dev->net, "Link Status is: %d\n", link);
}
}
@@ -603,8 +604,8 @@ static int dm9601_link_reset(struct usbnet *dev)
mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
- devdbg(dev, "link_reset() speed: %d duplex: %d",
- ecmd.speed, ecmd.duplex);
+ netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
+ ecmd.speed, ecmd.duplex);
return 0;
}
diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c
index 55cf7081de10..3c228df57062 100644
--- a/drivers/net/usb/int51x1.c
+++ b/drivers/net/usb/int51x1.c
@@ -51,7 +51,7 @@ static int int51x1_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
int len;
if (!(pskb_may_pull(skb, INT51X1_HEADER_SIZE))) {
- deverr(dev, "unexpected tiny rx frame");
+ netdev_err(dev->net, "unexpected tiny rx frame\n");
return 0;
}
@@ -138,25 +138,25 @@ static void int51x1_set_multicast(struct net_device *netdev)
if (netdev->flags & IFF_PROMISC) {
/* do not expect to see traffic of other PLCs */
filter |= PACKET_TYPE_PROMISCUOUS;
- devinfo(dev, "promiscuous mode enabled");
- } else if (netdev->mc_count ||
+ netdev_info(dev->net, "promiscuous mode enabled\n");
+ } else if (!netdev_mc_empty(netdev) ||
(netdev->flags & IFF_ALLMULTI)) {
filter |= PACKET_TYPE_ALL_MULTICAST;
- devdbg(dev, "receive all multicast enabled");
+ netdev_dbg(dev->net, "receive all multicast enabled\n");
} else {
/* ~PROMISCUOUS, ~MULTICAST */
- devdbg(dev, "receive own packets only");
+ netdev_dbg(dev->net, "receive own packets only\n");
}
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
- devwarn(dev, "Error allocating URB");
+ netdev_warn(dev->net, "Error allocating URB\n");
return;
}
req = kmalloc(sizeof(*req), GFP_ATOMIC);
if (!req) {
- devwarn(dev, "Error allocating control msg");
+ netdev_warn(dev->net, "Error allocating control msg\n");
goto out;
}
@@ -173,7 +173,8 @@ static void int51x1_set_multicast(struct net_device *netdev)
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status < 0) {
- devwarn(dev, "Error submitting control msg, sts=%d", status);
+ netdev_warn(dev->net, "Error submitting control msg, sts=%d\n",
+ status);
goto out1;
}
return;
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index f1d64ef67efa..52671ea043a7 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -881,7 +881,7 @@ static void kaweth_set_rx_mode(struct net_device *net)
if (net->flags & IFF_PROMISC) {
packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS;
}
- else if ((net->mc_count) || (net->flags & IFF_ALLMULTI)) {
+ else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) {
packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST;
}
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index 87374317f480..70978219e98a 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -1,13 +1,27 @@
/*
- * MosChips MCS7830 based USB 2.0 Ethernet Devices
+ * MOSCHIP MCS7830 based USB 2.0 Ethernet Devices
*
* based on usbnet.c, asix.c and the vendor provided mcs7830 driver
*
+ * Copyright (C) 2010 Andreas Mohr <andi@lisas.de>
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>
* Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
* Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
* Copyright (c) 2002-2003 TiVo Inc.
*
+ * Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!).
+ *
+ * TODO:
+ * - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?)
+ * - implement ethtool_ops get_pauseparam/set_pauseparam
+ * via HIF_REG_PAUSE_THRESHOLD (>= revision C only!)
+ * - implement get_eeprom/[set_eeprom]
+ * - switch PHY on/off on ifup/ifdown (perhaps in usbnet.c, via MII)
+ * - mcs7830_get_regs() handling is weird: for rev 2 we return 32 regs,
+ * can access only ~ 24, remaining user buffer is uninitialized garbage
+ * - anything else?
+ *
+ *
* 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
@@ -55,7 +69,7 @@
ADVERTISE_100HALF | ADVERTISE_10FULL | \
ADVERTISE_10HALF | ADVERTISE_CSMA)
-/* HIF_REG_XX coressponding index value */
+/* HIF_REG_XX corresponding index value */
enum {
HIF_REG_MULTICAST_HASH = 0x00,
HIF_REG_PACKET_GAP1 = 0x08,
@@ -69,6 +83,7 @@ enum {
HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80,
HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40,
HIF_REG_CONFIG = 0x0e,
+ /* hmm, spec sez: "R/W", "Except bit 3" (likely TXENABLE). */
HIF_REG_CONFIG_CFG = 0x80,
HIF_REG_CONFIG_SPEED100 = 0x40,
HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20,
@@ -76,13 +91,24 @@ enum {
HIF_REG_CONFIG_TXENABLE = 0x08,
HIF_REG_CONFIG_SLEEPMODE = 0x04,
HIF_REG_CONFIG_ALLMULTICAST = 0x02,
- HIF_REG_CONFIG_PROMISCIOUS = 0x01,
+ HIF_REG_CONFIG_PROMISCUOUS = 0x01,
HIF_REG_ETHERNET_ADDR = 0x0f,
- HIF_REG_22 = 0x15,
+ HIF_REG_FRAME_DROP_COUNTER = 0x15, /* 0..ff; reset: 0 */
HIF_REG_PAUSE_THRESHOLD = 0x16,
HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0,
};
+/* Trailing status byte in Ethernet Rx frame */
+enum {
+ MCS7830_RX_SHORT_FRAME = 0x01, /* < 64 bytes */
+ MCS7830_RX_LENGTH_ERROR = 0x02, /* framelen != Ethernet length field */
+ MCS7830_RX_ALIGNMENT_ERROR = 0x04, /* non-even number of nibbles */
+ MCS7830_RX_CRC_ERROR = 0x08,
+ MCS7830_RX_LARGE_FRAME = 0x10, /* > 1518 bytes */
+ MCS7830_RX_FRAME_CORRECT = 0x20, /* frame is correct */
+ /* [7:6] reserved */
+};
+
struct mcs7830_data {
u8 multi_filter[8];
u8 config;
@@ -109,7 +135,7 @@ static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data)
return ret;
}
-static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data)
+static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, const void *data)
{
struct usb_device *xdev = dev->udev;
int ret;
@@ -183,13 +209,43 @@ out:
usb_free_urb(urb);
}
-static int mcs7830_get_address(struct usbnet *dev)
+static int mcs7830_hif_get_mac_address(struct usbnet *dev, unsigned char *addr)
+{
+ int ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int mcs7830_hif_set_mac_address(struct usbnet *dev, unsigned char *addr)
+{
+ int ret = mcs7830_set_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr);
+
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int mcs7830_set_mac_address(struct net_device *netdev, void *p)
{
int ret;
- ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN,
- dev->net->dev_addr);
+ struct usbnet *dev = netdev_priv(netdev);
+ struct sockaddr *addr = p;
+
+ if (netif_running(netdev))
+ return -EBUSY;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ ret = mcs7830_hif_set_mac_address(dev, addr->sa_data);
+
if (ret < 0)
return ret;
+
+ /* it worked --> adopt it on netdev side */
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+
return 0;
}
@@ -307,7 +363,7 @@ static int mcs7830_get_rev(struct usbnet *dev)
{
u8 dummy[2];
int ret;
- ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy);
+ ret = mcs7830_get_reg(dev, HIF_REG_FRAME_DROP_COUNTER, 2, dummy);
if (ret > 0)
return 2; /* Rev C or later */
return 1; /* earlier revision */
@@ -331,33 +387,6 @@ static void mcs7830_rev_C_fixup(struct usbnet *dev)
}
}
-static int mcs7830_init_dev(struct usbnet *dev)
-{
- int ret;
- int retry;
-
- /* Read MAC address from EEPROM */
- ret = -EINVAL;
- for (retry = 0; retry < 5 && ret; retry++)
- ret = mcs7830_get_address(dev);
- if (ret) {
- dev_warn(&dev->udev->dev, "Cannot read MAC address\n");
- goto out;
- }
-
- /* Set up PHY */
- ret = mcs7830_set_autoneg(dev, 0);
- if (ret) {
- dev_info(&dev->udev->dev, "Cannot set autoneg\n");
- goto out;
- }
-
- mcs7830_rev_C_fixup(dev);
- ret = 0;
-out:
- return ret;
-}
-
static int mcs7830_mdio_read(struct net_device *netdev, int phy_id,
int location)
{
@@ -378,11 +407,33 @@ static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
-/* credits go to asix_set_multicast */
-static void mcs7830_set_multicast(struct net_device *net)
+static inline struct mcs7830_data *mcs7830_get_data(struct usbnet *dev)
+{
+ return (struct mcs7830_data *)&dev->data;
+}
+
+static void mcs7830_hif_update_multicast_hash(struct usbnet *dev)
+{
+ struct mcs7830_data *data = mcs7830_get_data(dev);
+ mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH,
+ sizeof data->multi_filter,
+ data->multi_filter);
+}
+
+static void mcs7830_hif_update_config(struct usbnet *dev)
+{
+ /* implementation specific to data->config
+ (argument needs to be heap-based anyway - USB DMA!) */
+ struct mcs7830_data *data = mcs7830_get_data(dev);
+ mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config);
+}
+
+static void mcs7830_data_set_multicast(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
- struct mcs7830_data *data = (struct mcs7830_data *)&dev->data;
+ struct mcs7830_data *data = mcs7830_get_data(dev);
+
+ memset(data->multi_filter, 0, sizeof data->multi_filter);
data->config = HIF_REG_CONFIG_TXENABLE;
@@ -390,36 +441,64 @@ static void mcs7830_set_multicast(struct net_device *net)
data->config |= HIF_REG_CONFIG_ALLMULTICAST;
if (net->flags & IFF_PROMISC) {
- data->config |= HIF_REG_CONFIG_PROMISCIOUS;
+ data->config |= HIF_REG_CONFIG_PROMISCUOUS;
} else if (net->flags & IFF_ALLMULTI ||
- net->mc_count > MCS7830_MAX_MCAST) {
+ netdev_mc_count(net) > MCS7830_MAX_MCAST) {
data->config |= HIF_REG_CONFIG_ALLMULTICAST;
- } else if (net->mc_count == 0) {
+ } else if (netdev_mc_empty(net)) {
/* just broadcast and directed */
} else {
/* We use the 20 byte dev->data
* for our 8 byte filter buffer
* to avoid allocating memory that
* is tricky to free later */
- struct dev_mc_list *mc_list = net->mc_list;
+ struct dev_mc_list *mc_list;
u32 crc_bits;
- int i;
-
- memset(data->multi_filter, 0, sizeof data->multi_filter);
/* Build the multicast hash filter. */
- for (i = 0; i < net->mc_count; i++) {
+ netdev_for_each_mc_addr(mc_list, net) {
crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7);
- mc_list = mc_list->next;
}
+ }
+}
- mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH,
- sizeof data->multi_filter,
- data->multi_filter);
+static int mcs7830_apply_base_config(struct usbnet *dev)
+{
+ int ret;
+
+ /* re-configure known MAC (suspend case etc.) */
+ ret = mcs7830_hif_set_mac_address(dev, dev->net->dev_addr);
+ if (ret) {
+ dev_info(&dev->udev->dev, "Cannot set MAC address\n");
+ goto out;
}
- mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config);
+ /* Set up PHY */
+ ret = mcs7830_set_autoneg(dev, 0);
+ if (ret) {
+ dev_info(&dev->udev->dev, "Cannot set autoneg\n");
+ goto out;
+ }
+
+ mcs7830_hif_update_multicast_hash(dev);
+ mcs7830_hif_update_config(dev);
+
+ mcs7830_rev_C_fixup(dev);
+ ret = 0;
+out:
+ return ret;
+}
+
+/* credits go to asix_set_multicast */
+static void mcs7830_set_multicast(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ mcs7830_data_set_multicast(net);
+
+ mcs7830_hif_update_multicast_hash(dev);
+ mcs7830_hif_update_config(dev);
}
static int mcs7830_get_regs_len(struct net_device *net)
@@ -463,29 +542,6 @@ static const struct ethtool_ops mcs7830_ethtool_ops = {
.nway_reset = usbnet_nway_reset,
};
-static int mcs7830_set_mac_address(struct net_device *netdev, void *p)
-{
- int ret;
- struct usbnet *dev = netdev_priv(netdev);
- struct sockaddr *addr = p;
-
- if (netif_running(netdev))
- return -EBUSY;
-
- if (!is_valid_ether_addr(addr->sa_data))
- return -EINVAL;
-
- memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-
- ret = mcs7830_set_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN,
- netdev->dev_addr);
-
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
static const struct net_device_ops mcs7830_netdev_ops = {
.ndo_open = usbnet_open,
.ndo_stop = usbnet_stop,
@@ -495,21 +551,32 @@ static const struct net_device_ops mcs7830_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = mcs7830_ioctl,
.ndo_set_multicast_list = mcs7830_set_multicast,
- .ndo_set_mac_address = mcs7830_set_mac_address,
+ .ndo_set_mac_address = mcs7830_set_mac_address,
};
static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev)
{
struct net_device *net = dev->net;
int ret;
+ int retry;
- ret = mcs7830_init_dev(dev);
+ /* Initial startup: Gather MAC address setting from EEPROM */
+ ret = -EINVAL;
+ for (retry = 0; retry < 5 && ret; retry++)
+ ret = mcs7830_hif_get_mac_address(dev, net->dev_addr);
+ if (ret) {
+ dev_warn(&dev->udev->dev, "Cannot read MAC address\n");
+ goto out;
+ }
+
+ mcs7830_data_set_multicast(net);
+
+ ret = mcs7830_apply_base_config(dev);
if (ret)
goto out;
net->ethtool_ops = &mcs7830_ethtool_ops;
net->netdev_ops = &mcs7830_netdev_ops;
- mcs7830_set_multicast(net);
/* reserve space for the status byte on rx */
dev->rx_urb_size = ETH_FRAME_LEN + 1;
@@ -526,7 +593,7 @@ out:
return ret;
}
-/* The chip always appends a status bytes that we need to strip */
+/* The chip always appends a status byte that we need to strip */
static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
u8 status;
@@ -539,9 +606,23 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
skb_trim(skb, skb->len - 1);
status = skb->data[skb->len];
- if (status != 0x20)
+ if (status != MCS7830_RX_FRAME_CORRECT) {
dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status);
+ /* hmm, perhaps usbnet.c already sees a globally visible
+ frame error and increments rx_errors on its own already? */
+ dev->net->stats.rx_errors++;
+
+ if (status & (MCS7830_RX_SHORT_FRAME
+ |MCS7830_RX_LENGTH_ERROR
+ |MCS7830_RX_LARGE_FRAME))
+ dev->net->stats.rx_length_errors++;
+ if (status & MCS7830_RX_ALIGNMENT_ERROR)
+ dev->net->stats.rx_frame_errors++;
+ if (status & MCS7830_RX_CRC_ERROR)
+ dev->net->stats.rx_crc_errors++;
+ }
+
return skb->len > 0;
}
@@ -580,6 +661,20 @@ static const struct usb_device_id products[] = {
};
MODULE_DEVICE_TABLE(usb, products);
+static int mcs7830_reset_resume (struct usb_interface *intf)
+{
+ /* YES, this function is successful enough that ethtool -d
+ does show same output pre-/post-suspend */
+
+ struct usbnet *dev = usb_get_intfdata(intf);
+
+ mcs7830_apply_base_config(dev);
+
+ usbnet_resume(intf);
+
+ return 0;
+}
+
static struct usb_driver mcs7830_driver = {
.name = driver_name,
.id_table = products,
@@ -587,6 +682,7 @@ static struct usb_driver mcs7830_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .reset_resume = mcs7830_reset_resume,
};
static int __init mcs7830_init(void)
diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c
index aeb1ab03a9ee..bdcad45954a3 100644
--- a/drivers/net/usb/net1080.c
+++ b/drivers/net/usb/net1080.c
@@ -203,25 +203,23 @@ static void nc_dump_registers(struct usbnet *dev)
static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl)
{
- if (!netif_msg_link(dev))
- return;
- devdbg(dev, "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s;"
- " this%s%s;"
- " other%s%s; r/o 0x%x",
- dev->udev->bus->bus_name, dev->udev->devpath,
- usbctl,
- (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "",
- (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "",
- (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "",
- (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "",
- (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "",
-
- (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "",
- (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "",
- (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "",
- (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "",
- usbctl & ~USBCTL_WRITABLE_MASK
- );
+ netif_dbg(dev, link, dev->net,
+ "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s; this%s%s; other%s%s; r/o 0x%x\n",
+ dev->udev->bus->bus_name, dev->udev->devpath,
+ usbctl,
+ (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "",
+ (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "",
+ (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "",
+ (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "",
+ (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "",
+
+ (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "",
+ (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "",
+
+ (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "",
+ (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "",
+
+ usbctl & ~USBCTL_WRITABLE_MASK);
}
/*-------------------------------------------------------------------------*/
@@ -248,30 +246,26 @@ static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl)
static inline void nc_dump_status(struct usbnet *dev, u16 status)
{
- if (!netif_msg_link(dev))
- return;
- devdbg(dev, "net1080 %s-%s status 0x%x:"
- " this (%c) PKT=%d%s%s%s;"
- " other PKT=%d%s%s%s; unspec 0x%x",
- dev->udev->bus->bus_name, dev->udev->devpath,
- status,
-
- // XXX the packet counts don't seem right
- // (1 at reset, not 0); maybe UNSPEC too
-
- (status & STATUS_PORT_A) ? 'A' : 'B',
- STATUS_PACKETS_THIS(status),
- (status & STATUS_CONN_THIS) ? " CON" : "",
- (status & STATUS_SUSPEND_THIS) ? " SUS" : "",
- (status & STATUS_MAILBOX_THIS) ? " MBOX" : "",
-
- STATUS_PACKETS_OTHER(status),
- (status & STATUS_CONN_OTHER) ? " CON" : "",
- (status & STATUS_SUSPEND_OTHER) ? " SUS" : "",
- (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "",
-
- status & STATUS_UNSPEC_MASK
- );
+ netif_dbg(dev, link, dev->net,
+ "net1080 %s-%s status 0x%x: this (%c) PKT=%d%s%s%s; other PKT=%d%s%s%s; unspec 0x%x\n",
+ dev->udev->bus->bus_name, dev->udev->devpath,
+ status,
+
+ // XXX the packet counts don't seem right
+ // (1 at reset, not 0); maybe UNSPEC too
+
+ (status & STATUS_PORT_A) ? 'A' : 'B',
+ STATUS_PACKETS_THIS(status),
+ (status & STATUS_CONN_THIS) ? " CON" : "",
+ (status & STATUS_SUSPEND_THIS) ? " SUS" : "",
+ (status & STATUS_MAILBOX_THIS) ? " MBOX" : "",
+
+ STATUS_PACKETS_OTHER(status),
+ (status & STATUS_CONN_OTHER) ? " CON" : "",
+ (status & STATUS_SUSPEND_OTHER) ? " SUS" : "",
+ (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "",
+
+ status & STATUS_UNSPEC_MASK);
}
/*-------------------------------------------------------------------------*/
@@ -286,10 +280,9 @@ static inline void nc_dump_status(struct usbnet *dev, u16 status)
static inline void nc_dump_ttl(struct usbnet *dev, u16 ttl)
{
- if (netif_msg_link(dev))
- devdbg(dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d",
- dev->udev->bus->bus_name, dev->udev->devpath,
- ttl, TTL_THIS(ttl), TTL_OTHER(ttl));
+ netif_dbg(dev, link, dev->net, "net1080 %s-%s ttl 0x%x this = %d, other = %d\n",
+ dev->udev->bus->bus_name, dev->udev->devpath,
+ ttl, TTL_THIS(ttl), TTL_OTHER(ttl));
}
/*-------------------------------------------------------------------------*/
@@ -334,11 +327,9 @@ static int net1080_reset(struct usbnet *dev)
MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) );
dbg("%s: assigned TTL, %d ms", dev->net->name, NC_READ_TTL_MS);
- if (netif_msg_link(dev))
- devinfo(dev, "port %c, peer %sconnected",
- (status & STATUS_PORT_A) ? 'A' : 'B',
- (status & STATUS_CONN_OTHER) ? "" : "dis"
- );
+ netif_info(dev, link, dev->net, "port %c, peer %sconnected\n",
+ (status & STATUS_PORT_A) ? 'A' : 'B',
+ (status & STATUS_CONN_OTHER) ? "" : "dis");
retval = 0;
done:
@@ -415,8 +406,8 @@ static void nc_ensure_sync(struct usbnet *dev)
return;
}
- if (netif_msg_rx_err(dev))
- devdbg(dev, "flush net1080; too many framing errors");
+ netif_dbg(dev, rx_err, dev->net,
+ "flush net1080; too many framing errors\n");
dev->frame_errors = 0;
}
}
@@ -486,8 +477,8 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
return 0;
}
#if 0
- devdbg(dev, "frame <rx h %d p %d id %d", header->hdr_len,
- header->packet_len, header->packet_id);
+ netdev_dbg(dev->net, "frame <rx h %d p %d id %d\n", header->hdr_len,
+ header->packet_len, header->packet_id);
#endif
dev->frame_errors = 0;
return 1;
@@ -547,9 +538,9 @@ encapsulate:
trailer = (struct nc_trailer *) skb_put(skb, sizeof *trailer);
put_unaligned(header->packet_id, &trailer->packet_id);
#if 0
- devdbg(dev, "frame >tx h %d p %d id %d",
- header->hdr_len, header->packet_len,
- header->packet_id);
+ netdev_dbg(dev->net, "frame >tx h %d p %d id %d\n",
+ header->hdr_len, header->packet_len,
+ header->packet_id);
#endif
return skb;
}
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index ed4a508ef262..41838773b568 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -132,9 +132,10 @@ static void ctrl_callback(struct urb *urb)
case -ENOENT:
break;
default:
- if (netif_msg_drv(pegasus) && printk_ratelimit())
- dev_dbg(&pegasus->intf->dev, "%s, status %d\n",
- __func__, status);
+ if (net_ratelimit())
+ netif_dbg(pegasus, drv, pegasus->net,
+ "%s, status %d\n", __func__, status);
+ break;
}
pegasus->flags &= ~ETH_REGS_CHANGED;
wake_up(&pegasus->ctrl_wait);
@@ -149,9 +150,8 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
buffer = kmalloc(size, GFP_KERNEL);
if (!buffer) {
- if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "out of memory in %s\n",
- __func__);
+ netif_warn(pegasus, drv, pegasus->net,
+ "out of memory in %s\n", __func__);
return -ENOMEM;
}
add_wait_queue(&pegasus->ctrl_wait, &wait);
@@ -181,9 +181,9 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
set_current_state(TASK_RUNNING);
if (ret == -ENODEV)
netif_device_detach(pegasus->net);
- if (netif_msg_drv(pegasus) && printk_ratelimit())
- dev_err(&pegasus->intf->dev, "%s, status %d\n",
- __func__, ret);
+ if (net_ratelimit())
+ netif_err(pegasus, drv, pegasus->net,
+ "%s, status %d\n", __func__, ret);
goto out;
}
@@ -205,9 +205,8 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
buffer = kmalloc(size, GFP_KERNEL);
if (!buffer) {
- if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "out of memory in %s\n",
- __func__);
+ netif_warn(pegasus, drv, pegasus->net,
+ "out of memory in %s\n", __func__);
return -ENOMEM;
}
memcpy(buffer, data, size);
@@ -237,9 +236,8 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
if (ret == -ENODEV)
netif_device_detach(pegasus->net);
- if (netif_msg_drv(pegasus))
- dev_err(&pegasus->intf->dev, "%s, status %d\n",
- __func__, ret);
+ netif_err(pegasus, drv, pegasus->net,
+ "%s, status %d\n", __func__, ret);
goto out;
}
@@ -259,9 +257,8 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
tmp = kmalloc(1, GFP_KERNEL);
if (!tmp) {
- if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "out of memory in %s\n",
- __func__);
+ netif_warn(pegasus, drv, pegasus->net,
+ "out of memory in %s\n", __func__);
return -ENOMEM;
}
memcpy(tmp, &data, 1);
@@ -290,9 +287,9 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
if (ret == -ENODEV)
netif_device_detach(pegasus->net);
- if (netif_msg_drv(pegasus) && printk_ratelimit())
- dev_err(&pegasus->intf->dev, "%s, status %d\n",
- __func__, ret);
+ if (net_ratelimit())
+ netif_err(pegasus, drv, pegasus->net,
+ "%s, status %d\n", __func__, ret);
goto out;
}
@@ -323,9 +320,8 @@ static int update_eth_regs_async(pegasus_t * pegasus)
if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
if (ret == -ENODEV)
netif_device_detach(pegasus->net);
- if (netif_msg_drv(pegasus))
- dev_err(&pegasus->intf->dev, "%s, status %d\n",
- __func__, ret);
+ netif_err(pegasus, drv, pegasus->net,
+ "%s, status %d\n", __func__, ret);
}
return ret;
@@ -349,14 +345,16 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
if (data[0] & PHY_DONE)
break;
}
- if (i < REG_TIMEOUT) {
- ret = get_registers(pegasus, PhyData, 2, &regdi);
- *regd = le16_to_cpu(regdi);
- return ret;
- }
+
+ if (i >= REG_TIMEOUT)
+ goto fail;
+
+ ret = get_registers(pegasus, PhyData, 2, &regdi);
+ *regd = le16_to_cpu(regdi);
+ return ret;
+
fail:
- if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "%s failed\n", __func__);
+ netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__);
return ret;
}
@@ -388,12 +386,14 @@ static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
if (data[0] & PHY_DONE)
break;
}
- if (i < REG_TIMEOUT)
- return ret;
+
+ if (i >= REG_TIMEOUT)
+ goto fail;
+
+ return ret;
fail:
- if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "%s failed\n", __func__);
+ netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__);
return -ETIMEDOUT;
}
@@ -422,15 +422,15 @@ static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata)
if (ret == -ESHUTDOWN)
goto fail;
}
- if (i < REG_TIMEOUT) {
- ret = get_registers(pegasus, EpromData, 2, &retdatai);
- *retdata = le16_to_cpu(retdatai);
- return ret;
- }
+ if (i >= REG_TIMEOUT)
+ goto fail;
+
+ ret = get_registers(pegasus, EpromData, 2, &retdatai);
+ *retdata = le16_to_cpu(retdatai);
+ return ret;
fail:
- if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "%s failed\n", __func__);
+ netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__);
return -ETIMEDOUT;
}
@@ -475,11 +475,13 @@ static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data)
break;
}
disable_eprom_write(pegasus);
- if (i < REG_TIMEOUT)
- return ret;
+ if (i >= REG_TIMEOUT)
+ goto fail;
+
+ return ret;
+
fail:
- if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "%s failed\n", __func__);
+ netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__);
return -ETIMEDOUT;
}
#endif /* PEGASUS_WRITE_EEPROM */
@@ -642,25 +644,20 @@ static void read_bulk_callback(struct urb *urb)
case 0:
break;
case -ETIME:
- if (netif_msg_rx_err(pegasus))
- pr_debug("%s: reset MAC\n", net->name);
+ netif_dbg(pegasus, rx_err, net, "reset MAC\n");
pegasus->flags &= ~PEGASUS_RX_BUSY;
break;
case -EPIPE: /* stall, or disconnect from TT */
/* FIXME schedule work to clear the halt */
- if (netif_msg_rx_err(pegasus))
- printk(KERN_WARNING "%s: no rx stall recovery\n",
- net->name);
+ netif_warn(pegasus, rx_err, net, "no rx stall recovery\n");
return;
case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
- if (netif_msg_ifdown(pegasus))
- pr_debug("%s: rx unlink, %d\n", net->name, status);
+ netif_dbg(pegasus, ifdown, net, "rx unlink, %d\n", status);
return;
default:
- if (netif_msg_rx_err(pegasus))
- pr_debug("%s: RX status %d\n", net->name, status);
+ netif_dbg(pegasus, rx_err, net, "RX status %d\n", status);
goto goon;
}
@@ -669,9 +666,8 @@ static void read_bulk_callback(struct urb *urb)
rx_status = buf[count - 2];
if (rx_status & 0x1e) {
- if (netif_msg_rx_err(pegasus))
- pr_debug("%s: RX packet error %x\n",
- net->name, rx_status);
+ netif_dbg(pegasus, rx_err, net,
+ "RX packet error %x\n", rx_status);
pegasus->stats.rx_errors++;
if (rx_status & 0x06) // long or runt
pegasus->stats.rx_length_errors++;
@@ -758,9 +754,7 @@ static void rx_fixup(unsigned long data)
pegasus->rx_skb = pull_skb(pegasus);
}
if (pegasus->rx_skb == NULL) {
- if (netif_msg_rx_err(pegasus))
- printk(KERN_WARNING "%s: low on memory\n",
- pegasus->net->name);
+ netif_warn(pegasus, rx_err, pegasus->net, "low on memory\n");
tasklet_schedule(&pegasus->rx_tl);
goto done;
}
@@ -800,19 +794,15 @@ static void write_bulk_callback(struct urb *urb)
case -EPIPE:
/* FIXME schedule_work() to clear the tx halt */
netif_stop_queue(net);
- if (netif_msg_tx_err(pegasus))
- printk(KERN_WARNING "%s: no tx stall recovery\n",
- net->name);
+ netif_warn(pegasus, tx_err, net, "no tx stall recovery\n");
return;
case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
- if (netif_msg_ifdown(pegasus))
- pr_debug("%s: tx unlink, %d\n", net->name, status);
+ netif_dbg(pegasus, ifdown, net, "tx unlink, %d\n", status);
return;
default:
- if (netif_msg_tx_err(pegasus))
- pr_info("%s: TX status %d\n", net->name, status);
+ netif_info(pegasus, tx_err, net, "TX status %d\n", status);
/* FALL THROUGH */
case 0:
break;
@@ -843,9 +833,7 @@ static void intr_callback(struct urb *urb)
/* some Pegasus-I products report LOTS of data
* toggle errors... avoid log spamming
*/
- if (netif_msg_timer(pegasus))
- pr_debug("%s: intr status %d\n", net->name,
- status);
+ netif_dbg(pegasus, timer, net, "intr status %d\n", status);
}
if (urb->actual_length >= 6) {
@@ -875,16 +863,15 @@ static void intr_callback(struct urb *urb)
res = usb_submit_urb(urb, GFP_ATOMIC);
if (res == -ENODEV)
netif_device_detach(pegasus->net);
- if (res && netif_msg_timer(pegasus))
- printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n",
- net->name, res);
+ if (res)
+ netif_err(pegasus, timer, net,
+ "can't resubmit interrupt urb, %d\n", res);
}
static void pegasus_tx_timeout(struct net_device *net)
{
pegasus_t *pegasus = netdev_priv(net);
- if (netif_msg_timer(pegasus))
- printk(KERN_WARNING "%s: tx timeout\n", net->name);
+ netif_warn(pegasus, timer, net, "tx timeout\n");
usb_unlink_urb(pegasus->tx_urb);
pegasus->stats.tx_errors++;
}
@@ -906,9 +893,7 @@ static netdev_tx_t pegasus_start_xmit(struct sk_buff *skb,
pegasus->tx_buff, count,
write_bulk_callback, pegasus);
if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) {
- if (netif_msg_tx_err(pegasus))
- printk(KERN_WARNING "%s: fail tx, %d\n",
- net->name, res);
+ netif_warn(pegasus, tx_err, net, "fail tx, %d\n", res);
switch (res) {
case -EPIPE: /* stall, or disconnect from TT */
/* cleanup should already have been scheduled */
@@ -952,10 +937,9 @@ static inline void get_interrupt_interval(pegasus_t * pegasus)
interval = data >> 8;
if (pegasus->usb->speed != USB_SPEED_HIGH) {
if (interval < 0x80) {
- if (netif_msg_timer(pegasus))
- dev_info(&pegasus->intf->dev, "intr interval "
- "changed from %ums to %ums\n",
- interval, 0x80);
+ netif_info(pegasus, timer, pegasus->net,
+ "intr interval changed from %ums to %ums\n",
+ interval, 0x80);
interval = 0x80;
data = (data & 0x00FF) | ((u16)interval << 8);
#ifdef PEGASUS_WRITE_EEPROM
@@ -1046,8 +1030,7 @@ static int pegasus_open(struct net_device *net)
if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) {
if (res == -ENODEV)
netif_device_detach(pegasus->net);
- if (netif_msg_ifup(pegasus))
- pr_debug("%s: failed rx_urb, %d", net->name, res);
+ netif_dbg(pegasus, ifup, net, "failed rx_urb, %d\n", res);
goto exit;
}
@@ -1058,15 +1041,13 @@ static int pegasus_open(struct net_device *net)
if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) {
if (res == -ENODEV)
netif_device_detach(pegasus->net);
- if (netif_msg_ifup(pegasus))
- pr_debug("%s: failed intr_urb, %d\n", net->name, res);
+ netif_dbg(pegasus, ifup, net, "failed intr_urb, %d\n", res);
usb_kill_urb(pegasus->rx_urb);
goto exit;
}
if ((res = enable_net_traffic(net, pegasus->usb))) {
- if (netif_msg_ifup(pegasus))
- pr_debug("%s: can't enable_net_traffic() - %d\n",
- net->name, res);
+ netif_dbg(pegasus, ifup, net,
+ "can't enable_net_traffic() - %d\n", res);
res = -EIO;
usb_kill_urb(pegasus->rx_urb);
usb_kill_urb(pegasus->intr_urb);
@@ -1075,8 +1056,7 @@ static int pegasus_open(struct net_device *net)
}
set_carrier(net);
netif_start_queue(net);
- if (netif_msg_ifup(pegasus))
- pr_debug("%s: open\n", net->name);
+ netif_dbg(pegasus, ifup, net, "open\n");
res = 0;
exit:
return res;
@@ -1230,13 +1210,11 @@ static void pegasus_set_multicast(struct net_device *net)
if (net->flags & IFF_PROMISC) {
pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
- if (netif_msg_link(pegasus))
- pr_info("%s: Promiscuous mode enabled.\n", net->name);
- } else if (net->mc_count || (net->flags & IFF_ALLMULTI)) {
+ netif_info(pegasus, link, net, "Promiscuous mode enabled\n");
+ } else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) {
pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
- if (netif_msg_link(pegasus))
- pr_debug("%s: set allmulti\n", net->name);
+ netif_dbg(pegasus, link, net, "set allmulti\n");
} else {
pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST;
pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
diff --git a/drivers/net/usb/pegasus.h b/drivers/net/usb/pegasus.h
index 5d02f0200737..b90d8766ab74 100644
--- a/drivers/net/usb/pegasus.h
+++ b/drivers/net/usb/pegasus.h
@@ -177,7 +177,7 @@ PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c,
PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c,
- DEFAULT_GPIO_RESET | PEGASUS_II )
+ DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
@@ -208,6 +208,8 @@ PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
*/
PEGASUS_DEV_CLASS( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, 0x00,
DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "Belkin F5U122 10/100 USB Ethernet", VENDOR_BELKIN, 0x0122,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987,
@@ -249,7 +251,7 @@ PEGASUS_DEV( "GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002,
PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "HP hn210c Ethernet USB", VENDOR_HP, 0x811c,
- DEFAULT_GPIO_RESET | PEGASUS_II )
+ DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913,
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 490fa8f55424..4ce331fb1e1e 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -57,8 +57,8 @@
*/
void rndis_status(struct usbnet *dev, struct urb *urb)
{
- devdbg(dev, "rndis status urb, len %d stat %d",
- urb->actual_length, urb->status);
+ netdev_dbg(dev->net, "rndis status urb, len %d stat %d\n",
+ urb->actual_length, urb->status);
// FIXME for keepalives, respond immediately (asynchronously)
// if not an RNDIS status, do like cdc_status(dev,urb) does
}
@@ -335,8 +335,8 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1);
if (dev->maxpacket == 0) {
- if (netif_msg_probe(dev))
- dev_dbg(&intf->dev, "dev->maxpacket can't be 0\n");
+ netif_dbg(dev, probe, dev->net,
+ "dev->maxpacket can't be 0\n");
retval = -EINVAL;
goto fail_and_release;
}
@@ -394,17 +394,15 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
}
if ((flags & FLAG_RNDIS_PHYM_WIRELESS) &&
*phym != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) {
- if (netif_msg_probe(dev))
- dev_dbg(&intf->dev, "driver requires wireless "
- "physical medium, but device is not.\n");
+ netif_dbg(dev, probe, dev->net,
+ "driver requires wireless physical medium, but device is not\n");
retval = -ENODEV;
goto halt_fail_and_release;
}
if ((flags & FLAG_RNDIS_PHYM_NOT_WIRELESS) &&
*phym == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) {
- if (netif_msg_probe(dev))
- dev_dbg(&intf->dev, "driver requires non-wireless "
- "physical medium, but device is wireless.\n");
+ netif_dbg(dev, probe, dev->net,
+ "driver requires non-wireless physical medium, but device is wireless.\n");
retval = -ENODEV;
goto halt_fail_and_release;
}
@@ -497,9 +495,9 @@ int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
skb->len < msg_len ||
(data_offset + data_len + 8) > msg_len)) {
dev->net->stats.rx_frame_errors++;
- devdbg(dev, "bad rndis message %d/%d/%d/%d, len %d",
- le32_to_cpu(hdr->msg_type),
- msg_len, data_offset, data_len, skb->len);
+ netdev_dbg(dev->net, "bad rndis message %d/%d/%d/%d, len %d\n",
+ le32_to_cpu(hdr->msg_type),
+ msg_len, data_offset, data_len, skb->len);
return 0;
}
skb_pull(skb, 8 + data_offset);
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index fd19db0d2504..e85c89c6706d 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -313,20 +313,17 @@ static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
{
struct sockaddr *addr = p;
rtl8150_t *dev = netdev_priv(netdev);
- int i;
if (netif_running(netdev))
return -EBUSY;
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
- dbg("%s: Setting MAC address to ", netdev->name);
- for (i = 0; i < 5; i++)
- dbg("%02X:", netdev->dev_addr[i]);
- dbg("%02X\n", netdev->dev_addr[i]);
+ dbg("%s: Setting MAC address to %pM\n", netdev->name, netdev->dev_addr);
/* Set the IDR registers. */
set_registers(dev, IDR, netdev->addr_len, netdev->dev_addr);
#ifdef EEPROM_WRITE
{
+ int i;
u8 cr;
/* Get the CR contents. */
get_registers(dev, CR, 1, &cr);
@@ -714,7 +711,7 @@ static void rtl8150_set_multicast(struct net_device *netdev)
if (netdev->flags & IFF_PROMISC) {
dev->rx_creg |= cpu_to_le16(0x0001);
dev_info(&netdev->dev, "%s: promiscuous mode\n", netdev->name);
- } else if (netdev->mc_count ||
+ } else if (!netdev_mc_empty(netdev) ||
(netdev->flags & IFF_ALLMULTI)) {
dev->rx_creg &= cpu_to_le16(0xfffe);
dev->rx_creg |= cpu_to_le16(0x0002);
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 0c3c738d7419..df9179a1c93b 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -78,7 +78,7 @@ static int smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data)
00, index, buf, 4, USB_CTRL_GET_TIMEOUT);
if (unlikely(ret < 0))
- devwarn(dev, "Failed to read register index 0x%08x", index);
+ netdev_warn(dev->net, "Failed to read register index 0x%08x\n", index);
le32_to_cpus(buf);
*data = *buf;
@@ -106,7 +106,7 @@ static int smsc95xx_write_reg(struct usbnet *dev, u32 index, u32 data)
00, index, buf, 4, USB_CTRL_SET_TIMEOUT);
if (unlikely(ret < 0))
- devwarn(dev, "Failed to write register index 0x%08x", index);
+ netdev_warn(dev->net, "Failed to write register index 0x%08x\n", index);
kfree(buf);
@@ -138,7 +138,7 @@ static int smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
/* confirm MII not busy */
if (smsc95xx_phy_wait_not_busy(dev)) {
- devwarn(dev, "MII is busy in smsc95xx_mdio_read");
+ netdev_warn(dev->net, "MII is busy in smsc95xx_mdio_read\n");
mutex_unlock(&dev->phy_mutex);
return -EIO;
}
@@ -150,7 +150,7 @@ static int smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
smsc95xx_write_reg(dev, MII_ADDR, addr);
if (smsc95xx_phy_wait_not_busy(dev)) {
- devwarn(dev, "Timed out reading MII reg %02X", idx);
+ netdev_warn(dev->net, "Timed out reading MII reg %02X\n", idx);
mutex_unlock(&dev->phy_mutex);
return -EIO;
}
@@ -172,7 +172,7 @@ static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
/* confirm MII not busy */
if (smsc95xx_phy_wait_not_busy(dev)) {
- devwarn(dev, "MII is busy in smsc95xx_mdio_write");
+ netdev_warn(dev->net, "MII is busy in smsc95xx_mdio_write\n");
mutex_unlock(&dev->phy_mutex);
return;
}
@@ -187,7 +187,7 @@ static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
smsc95xx_write_reg(dev, MII_ADDR, addr);
if (smsc95xx_phy_wait_not_busy(dev))
- devwarn(dev, "Timed out writing MII reg %02X", idx);
+ netdev_warn(dev->net, "Timed out writing MII reg %02X\n", idx);
mutex_unlock(&dev->phy_mutex);
}
@@ -205,7 +205,7 @@ static int smsc95xx_wait_eeprom(struct usbnet *dev)
} while (!time_after(jiffies, start_time + HZ));
if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) {
- devwarn(dev, "EEPROM read operation timeout");
+ netdev_warn(dev->net, "EEPROM read operation timeout\n");
return -EIO;
}
@@ -226,7 +226,7 @@ static int smsc95xx_eeprom_confirm_not_busy(struct usbnet *dev)
udelay(40);
} while (!time_after(jiffies, start_time + HZ));
- devwarn(dev, "EEPROM is busy");
+ netdev_warn(dev->net, "EEPROM is busy\n");
return -EIO;
}
@@ -308,7 +308,7 @@ static void smsc95xx_async_cmd_callback(struct urb *urb)
int status = urb->status;
if (status < 0)
- devwarn(dev, "async callback failed with %d", status);
+ netdev_warn(dev->net, "async callback failed with %d\n", status);
kfree(usb_context);
usb_free_urb(urb);
@@ -323,13 +323,13 @@ static int smsc95xx_write_reg_async(struct usbnet *dev, u16 index, u32 *data)
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
- devwarn(dev, "Error allocating URB");
+ netdev_warn(dev->net, "Error allocating URB\n");
return -ENOMEM;
}
usb_context = kmalloc(sizeof(struct usb_context), GFP_ATOMIC);
if (usb_context == NULL) {
- devwarn(dev, "Error allocating control msg");
+ netdev_warn(dev->net, "Error allocating control msg\n");
usb_free_urb(urb);
return -ENOMEM;
}
@@ -348,7 +348,8 @@ static int smsc95xx_write_reg_async(struct usbnet *dev, u16 index, u32 *data)
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status < 0) {
- devwarn(dev, "Error submitting control msg, sts=%d", status);
+ netdev_warn(dev->net, "Error submitting control msg, sts=%d\n",
+ status);
kfree(usb_context);
usb_free_urb(urb);
}
@@ -375,46 +376,32 @@ static void smsc95xx_set_multicast(struct net_device *netdev)
spin_lock_irqsave(&pdata->mac_cr_lock, flags);
if (dev->net->flags & IFF_PROMISC) {
- if (netif_msg_drv(dev))
- devdbg(dev, "promiscuous mode enabled");
+ netif_dbg(dev, drv, dev->net, "promiscuous mode enabled\n");
pdata->mac_cr |= MAC_CR_PRMS_;
pdata->mac_cr &= ~(MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
} else if (dev->net->flags & IFF_ALLMULTI) {
- if (netif_msg_drv(dev))
- devdbg(dev, "receive all multicast enabled");
+ netif_dbg(dev, drv, dev->net, "receive all multicast enabled\n");
pdata->mac_cr |= MAC_CR_MCPAS_;
pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_HPFILT_);
- } else if (dev->net->mc_count > 0) {
- struct dev_mc_list *mc_list = dev->net->mc_list;
- int count = 0;
+ } else if (!netdev_mc_empty(dev->net)) {
+ struct dev_mc_list *mc_list;
pdata->mac_cr |= MAC_CR_HPFILT_;
pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_);
- while (mc_list) {
- count++;
- if (mc_list->dmi_addrlen == ETH_ALEN) {
- u32 bitnum = smsc95xx_hash(mc_list->dmi_addr);
- u32 mask = 0x01 << (bitnum & 0x1F);
- if (bitnum & 0x20)
- hash_hi |= mask;
- else
- hash_lo |= mask;
- } else {
- devwarn(dev, "dmi_addrlen != 6");
- }
- mc_list = mc_list->next;
+ netdev_for_each_mc_addr(mc_list, netdev) {
+ u32 bitnum = smsc95xx_hash(mc_list->dmi_addr);
+ u32 mask = 0x01 << (bitnum & 0x1F);
+ if (bitnum & 0x20)
+ hash_hi |= mask;
+ else
+ hash_lo |= mask;
}
- if (count != ((u32)dev->net->mc_count))
- devwarn(dev, "mc_count != dev->mc_count");
-
- if (netif_msg_drv(dev))
- devdbg(dev, "HASHH=0x%08X, HASHL=0x%08X", hash_hi,
- hash_lo);
+ netif_dbg(dev, drv, dev->net, "HASHH=0x%08X, HASHL=0x%08X\n",
+ hash_hi, hash_lo);
} else {
- if (netif_msg_drv(dev))
- devdbg(dev, "receive own packets only");
+ netif_dbg(dev, drv, dev->net, "receive own packets only\n");
pdata->mac_cr &=
~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
}
@@ -434,7 +421,7 @@ static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
int ret = smsc95xx_read_reg(dev, AFC_CFG, &afc_cfg);
if (ret < 0) {
- devwarn(dev, "error reading AFC_CFG");
+ netdev_warn(dev->net, "error reading AFC_CFG\n");
return;
}
@@ -451,13 +438,11 @@ static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
else
afc_cfg &= ~0xF;
- if (netif_msg_link(dev))
- devdbg(dev, "rx pause %s, tx pause %s",
- (cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
- (cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
+ netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s\n",
+ cap & FLOW_CTRL_RX ? "enabled" : "disabled",
+ cap & FLOW_CTRL_TX ? "enabled" : "disabled");
} else {
- if (netif_msg_link(dev))
- devdbg(dev, "half duplex");
+ netif_dbg(dev, link, dev->net, "half duplex\n");
flow = 0;
afc_cfg |= 0xF;
}
@@ -485,9 +470,8 @@ static int smsc95xx_link_reset(struct usbnet *dev)
lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
- if (netif_msg_link(dev))
- devdbg(dev, "speed: %d duplex: %d lcladv: %04x rmtadv: %04x",
- ecmd.speed, ecmd.duplex, lcladv, rmtadv);
+ netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x rmtadv: %04x\n",
+ ecmd.speed, ecmd.duplex, lcladv, rmtadv);
spin_lock_irqsave(&pdata->mac_cr_lock, flags);
if (ecmd.duplex != DUPLEX_FULL) {
@@ -511,20 +495,21 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb)
u32 intdata;
if (urb->actual_length != 4) {
- devwarn(dev, "unexpected urb length %d", urb->actual_length);
+ netdev_warn(dev->net, "unexpected urb length %d\n",
+ urb->actual_length);
return;
}
memcpy(&intdata, urb->transfer_buffer, 4);
le32_to_cpus(&intdata);
- if (netif_msg_link(dev))
- devdbg(dev, "intdata: 0x%08X", intdata);
+ netif_dbg(dev, link, dev->net, "intdata: 0x%08X\n", intdata);
if (intdata & INT_ENP_PHY_INT_)
usbnet_defer_kevent(dev, EVENT_LINK_RESET);
else
- devwarn(dev, "unexpected interrupt, intdata=0x%08X", intdata);
+ netdev_warn(dev->net, "unexpected interrupt, intdata=0x%08X\n",
+ intdata);
}
/* Enable or disable Tx & Rx checksum offload engines */
@@ -534,7 +519,7 @@ static int smsc95xx_set_csums(struct usbnet *dev)
u32 read_buf;
int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to read COE_CR: %d", ret);
+ netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret);
return ret;
}
@@ -550,12 +535,11 @@ static int smsc95xx_set_csums(struct usbnet *dev)
ret = smsc95xx_write_reg(dev, COE_CR, read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to write COE_CR: %d", ret);
+ netdev_warn(dev->net, "Failed to write COE_CR: %d\n", ret);
return ret;
}
- if (netif_msg_hw(dev))
- devdbg(dev, "COE_CR = 0x%08x", read_buf);
+ netif_dbg(dev, hw, dev->net, "COE_CR = 0x%08x\n", read_buf);
return 0;
}
@@ -580,8 +564,8 @@ static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev,
struct usbnet *dev = netdev_priv(netdev);
if (ee->magic != LAN95XX_EEPROM_MAGIC) {
- devwarn(dev, "EEPROM: magic value mismatch, magic = 0x%x",
- ee->magic);
+ netdev_warn(dev->net, "EEPROM: magic value mismatch, magic = 0x%x\n",
+ ee->magic);
return -EINVAL;
}
@@ -659,16 +643,14 @@ static void smsc95xx_init_mac_address(struct usbnet *dev)
dev->net->dev_addr) == 0) {
if (is_valid_ether_addr(dev->net->dev_addr)) {
/* eeprom values are valid so use them */
- if (netif_msg_ifup(dev))
- devdbg(dev, "MAC address read from EEPROM");
+ netif_dbg(dev, ifup, dev->net, "MAC address read from EEPROM\n");
return;
}
}
/* no eeprom, or eeprom values are invalid. generate random MAC */
random_ether_addr(dev->net->dev_addr);
- if (netif_msg_ifup(dev))
- devdbg(dev, "MAC address set to random_ether_addr");
+ netif_dbg(dev, ifup, dev->net, "MAC address set to random_ether_addr\n");
}
static int smsc95xx_set_mac_address(struct usbnet *dev)
@@ -680,13 +662,13 @@ static int smsc95xx_set_mac_address(struct usbnet *dev)
ret = smsc95xx_write_reg(dev, ADDRL, addr_lo);
if (ret < 0) {
- devwarn(dev, "Failed to write ADDRL: %d", ret);
+ netdev_warn(dev->net, "Failed to write ADDRL: %d\n", ret);
return ret;
}
ret = smsc95xx_write_reg(dev, ADDRH, addr_hi);
if (ret < 0) {
- devwarn(dev, "Failed to write ADDRH: %d", ret);
+ netdev_warn(dev->net, "Failed to write ADDRH: %d\n", ret);
return ret;
}
@@ -747,8 +729,7 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
PHY_INT_MASK_DEFAULT_);
mii_nway_restart(&dev->mii);
- if (netif_msg_ifup(dev))
- devdbg(dev, "phy initialised successfully");
+ netif_dbg(dev, ifup, dev->net, "phy initialised successfully\n");
return 0;
}
@@ -759,14 +740,13 @@ static int smsc95xx_reset(struct usbnet *dev)
u32 read_buf, write_buf, burst_cap;
int ret = 0, timeout;
- if (netif_msg_ifup(dev))
- devdbg(dev, "entering smsc95xx_reset");
+ netif_dbg(dev, ifup, dev->net, "entering smsc95xx_reset\n");
write_buf = HW_CFG_LRST_;
ret = smsc95xx_write_reg(dev, HW_CFG, write_buf);
if (ret < 0) {
- devwarn(dev, "Failed to write HW_CFG_LRST_ bit in HW_CFG "
- "register, ret = %d", ret);
+ netdev_warn(dev->net, "Failed to write HW_CFG_LRST_ bit in HW_CFG register, ret = %d\n",
+ ret);
return ret;
}
@@ -774,7 +754,7 @@ static int smsc95xx_reset(struct usbnet *dev)
do {
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to read HW_CFG: %d", ret);
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
return ret;
}
msleep(10);
@@ -782,14 +762,14 @@ static int smsc95xx_reset(struct usbnet *dev)
} while ((read_buf & HW_CFG_LRST_) && (timeout < 100));
if (timeout >= 100) {
- devwarn(dev, "timeout waiting for completion of Lite Reset");
+ netdev_warn(dev->net, "timeout waiting for completion of Lite Reset\n");
return ret;
}
write_buf = PM_CTL_PHY_RST_;
ret = smsc95xx_write_reg(dev, PM_CTRL, write_buf);
if (ret < 0) {
- devwarn(dev, "Failed to write PM_CTRL: %d", ret);
+ netdev_warn(dev->net, "Failed to write PM_CTRL: %d\n", ret);
return ret;
}
@@ -797,7 +777,7 @@ static int smsc95xx_reset(struct usbnet *dev)
do {
ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to read PM_CTRL: %d", ret);
+ netdev_warn(dev->net, "Failed to read PM_CTRL: %d\n", ret);
return ret;
}
msleep(10);
@@ -805,7 +785,7 @@ static int smsc95xx_reset(struct usbnet *dev)
} while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
if (timeout >= 100) {
- devwarn(dev, "timeout waiting for PHY Reset");
+ netdev_warn(dev->net, "timeout waiting for PHY Reset\n");
return ret;
}
@@ -815,35 +795,35 @@ static int smsc95xx_reset(struct usbnet *dev)
if (ret < 0)
return ret;
- if (netif_msg_ifup(dev))
- devdbg(dev, "MAC Address: %pM", dev->net->dev_addr);
+ netif_dbg(dev, ifup, dev->net,
+ "MAC Address: %pM\n", dev->net->dev_addr);
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to read HW_CFG: %d", ret);
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
return ret;
}
- if (netif_msg_ifup(dev))
- devdbg(dev, "Read Value from HW_CFG : 0x%08x", read_buf);
+ netif_dbg(dev, ifup, dev->net,
+ "Read Value from HW_CFG : 0x%08x\n", read_buf);
read_buf |= HW_CFG_BIR_;
ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to write HW_CFG_BIR_ bit in HW_CFG "
- "register, ret = %d", ret);
+ netdev_warn(dev->net, "Failed to write HW_CFG_BIR_ bit in HW_CFG register, ret = %d\n",
+ ret);
return ret;
}
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to read HW_CFG: %d", ret);
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
return ret;
}
- if (netif_msg_ifup(dev))
- devdbg(dev, "Read Value from HW_CFG after writing "
- "HW_CFG_BIR_: 0x%08x", read_buf);
+ netif_dbg(dev, ifup, dev->net,
+ "Read Value from HW_CFG after writing HW_CFG_BIR_: 0x%08x\n",
+ read_buf);
if (!turbo_mode) {
burst_cap = 0;
@@ -856,47 +836,47 @@ static int smsc95xx_reset(struct usbnet *dev)
dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
}
- if (netif_msg_ifup(dev))
- devdbg(dev, "rx_urb_size=%ld", (ulong)dev->rx_urb_size);
+ netif_dbg(dev, ifup, dev->net,
+ "rx_urb_size=%ld\n", (ulong)dev->rx_urb_size);
ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap);
if (ret < 0) {
- devwarn(dev, "Failed to write BURST_CAP: %d", ret);
+ netdev_warn(dev->net, "Failed to write BURST_CAP: %d\n", ret);
return ret;
}
ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to read BURST_CAP: %d", ret);
+ netdev_warn(dev->net, "Failed to read BURST_CAP: %d\n", ret);
return ret;
}
- if (netif_msg_ifup(dev))
- devdbg(dev, "Read Value from BURST_CAP after writing: 0x%08x",
- read_buf);
+ netif_dbg(dev, ifup, dev->net,
+ "Read Value from BURST_CAP after writing: 0x%08x\n",
+ read_buf);
read_buf = DEFAULT_BULK_IN_DELAY;
ret = smsc95xx_write_reg(dev, BULK_IN_DLY, read_buf);
if (ret < 0) {
- devwarn(dev, "ret = %d", ret);
+ netdev_warn(dev->net, "ret = %d\n", ret);
return ret;
}
ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to read BULK_IN_DLY: %d", ret);
+ netdev_warn(dev->net, "Failed to read BULK_IN_DLY: %d\n", ret);
return ret;
}
- if (netif_msg_ifup(dev))
- devdbg(dev, "Read Value from BULK_IN_DLY after writing: "
- "0x%08x", read_buf);
+ netif_dbg(dev, ifup, dev->net,
+ "Read Value from BULK_IN_DLY after writing: 0x%08x\n",
+ read_buf);
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to read HW_CFG: %d", ret);
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
return ret;
}
- if (netif_msg_ifup(dev))
- devdbg(dev, "Read Value from HW_CFG: 0x%08x", read_buf);
+ netif_dbg(dev, ifup, dev->net,
+ "Read Value from HW_CFG: 0x%08x\n", read_buf);
if (turbo_mode)
read_buf |= (HW_CFG_MEF_ | HW_CFG_BCE_);
@@ -908,41 +888,41 @@ static int smsc95xx_reset(struct usbnet *dev)
ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to write HW_CFG register, ret=%d", ret);
+ netdev_warn(dev->net, "Failed to write HW_CFG register, ret=%d\n",
+ ret);
return ret;
}
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to read HW_CFG: %d", ret);
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
return ret;
}
- if (netif_msg_ifup(dev))
- devdbg(dev, "Read Value from HW_CFG after writing: 0x%08x",
- read_buf);
+ netif_dbg(dev, ifup, dev->net,
+ "Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
write_buf = 0xFFFFFFFF;
ret = smsc95xx_write_reg(dev, INT_STS, write_buf);
if (ret < 0) {
- devwarn(dev, "Failed to write INT_STS register, ret=%d", ret);
+ netdev_warn(dev->net, "Failed to write INT_STS register, ret=%d\n",
+ ret);
return ret;
}
ret = smsc95xx_read_reg(dev, ID_REV, &read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to read ID_REV: %d", ret);
+ netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret);
return ret;
}
- if (netif_msg_ifup(dev))
- devdbg(dev, "ID_REV = 0x%08x", read_buf);
+ netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", read_buf);
/* Configure GPIO pins as LED outputs */
write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED |
LED_GPIO_CFG_FDX_LED;
ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf);
if (ret < 0) {
- devwarn(dev, "Failed to write LED_GPIO_CFG register, ret=%d",
- ret);
+ netdev_warn(dev->net, "Failed to write LED_GPIO_CFG register, ret=%d\n",
+ ret);
return ret;
}
@@ -950,21 +930,21 @@ static int smsc95xx_reset(struct usbnet *dev)
write_buf = 0;
ret = smsc95xx_write_reg(dev, FLOW, write_buf);
if (ret < 0) {
- devwarn(dev, "Failed to write FLOW: %d", ret);
+ netdev_warn(dev->net, "Failed to write FLOW: %d\n", ret);
return ret;
}
read_buf = AFC_CFG_DEFAULT;
ret = smsc95xx_write_reg(dev, AFC_CFG, read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to write AFC_CFG: %d", ret);
+ netdev_warn(dev->net, "Failed to write AFC_CFG: %d\n", ret);
return ret;
}
/* Don't need mac_cr_lock during initialisation */
ret = smsc95xx_read_reg(dev, MAC_CR, &pdata->mac_cr);
if (ret < 0) {
- devwarn(dev, "Failed to read MAC_CR: %d", ret);
+ netdev_warn(dev->net, "Failed to read MAC_CR: %d\n", ret);
return ret;
}
@@ -973,7 +953,7 @@ static int smsc95xx_reset(struct usbnet *dev)
write_buf = (u32)ETH_P_8021Q;
ret = smsc95xx_write_reg(dev, VLAN1, write_buf);
if (ret < 0) {
- devwarn(dev, "Failed to write VAN1: %d", ret);
+ netdev_warn(dev->net, "Failed to write VAN1: %d\n", ret);
return ret;
}
@@ -981,7 +961,7 @@ static int smsc95xx_reset(struct usbnet *dev)
ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
ret = smsc95xx_set_csums(dev);
if (ret < 0) {
- devwarn(dev, "Failed to set csum offload: %d", ret);
+ netdev_warn(dev->net, "Failed to set csum offload: %d\n", ret);
return ret;
}
@@ -992,7 +972,7 @@ static int smsc95xx_reset(struct usbnet *dev)
ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to read INT_EP_CTL: %d", ret);
+ netdev_warn(dev->net, "Failed to read INT_EP_CTL: %d\n", ret);
return ret;
}
@@ -1001,15 +981,14 @@ static int smsc95xx_reset(struct usbnet *dev)
ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf);
if (ret < 0) {
- devwarn(dev, "Failed to write INT_EP_CTL: %d", ret);
+ netdev_warn(dev->net, "Failed to write INT_EP_CTL: %d\n", ret);
return ret;
}
smsc95xx_start_tx_path(dev);
smsc95xx_start_rx_path(dev);
- if (netif_msg_ifup(dev))
- devdbg(dev, "smsc95xx_reset, return 0");
+ netif_dbg(dev, ifup, dev->net, "smsc95xx_reset, return 0\n");
return 0;
}
@@ -1034,7 +1013,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
ret = usbnet_get_endpoints(dev, intf);
if (ret < 0) {
- devwarn(dev, "usbnet_get_endpoints failed: %d", ret);
+ netdev_warn(dev->net, "usbnet_get_endpoints failed: %d\n", ret);
return ret;
}
@@ -1043,7 +1022,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
pdata = (struct smsc95xx_priv *)(dev->data[0]);
if (!pdata) {
- devwarn(dev, "Unable to allocate struct smsc95xx_priv");
+ netdev_warn(dev->net, "Unable to allocate struct smsc95xx_priv\n");
return -ENOMEM;
}
@@ -1066,8 +1045,7 @@ static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf)
{
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
if (pdata) {
- if (netif_msg_ifdown(dev))
- devdbg(dev, "free pdata");
+ netif_dbg(dev, ifdown, dev->net, "free pdata\n");
kfree(pdata);
pdata = NULL;
dev->data[0] = 0;
@@ -1101,8 +1079,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4;
if (unlikely(header & RX_STS_ES_)) {
- if (netif_msg_rx_err(dev))
- devdbg(dev, "Error header=0x%08x", header);
+ netif_dbg(dev, rx_err, dev->net,
+ "Error header=0x%08x\n", header);
dev->net->stats.rx_errors++;
dev->net->stats.rx_dropped++;
@@ -1119,9 +1097,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
} else {
/* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */
if (unlikely(size > (ETH_FRAME_LEN + 12))) {
- if (netif_msg_rx_err(dev))
- devdbg(dev, "size err header=0x%08x",
- header);
+ netif_dbg(dev, rx_err, dev->net,
+ "size err header=0x%08x\n", header);
return 0;
}
@@ -1137,7 +1114,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
ax_skb = skb_clone(skb, GFP_ATOMIC);
if (unlikely(!ax_skb)) {
- devwarn(dev, "Error allocating skb");
+ netdev_warn(dev->net, "Error allocating skb\n");
return 0;
}
@@ -1161,7 +1138,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
}
if (unlikely(skb->len < 0)) {
- devwarn(dev, "invalid rx length<0 %d", skb->len);
+ netdev_warn(dev->net, "invalid rx length<0 %d\n", skb->len);
return 0;
}
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 035fab04c0a0..17b6a62d206e 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -242,13 +242,13 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
dev->net->stats.rx_packets++;
dev->net->stats.rx_bytes += skb->len;
- if (netif_msg_rx_status (dev))
- devdbg (dev, "< rx, len %zu, type 0x%x",
- skb->len + sizeof (struct ethhdr), skb->protocol);
+ netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n",
+ skb->len + sizeof (struct ethhdr), skb->protocol);
memset (skb->cb, 0, sizeof (struct skb_data));
status = netif_rx (skb);
- if (status != NET_RX_SUCCESS && netif_msg_rx_err (dev))
- devdbg (dev, "netif_rx status %d", status);
+ if (status != NET_RX_SUCCESS)
+ netif_dbg(dev, rx_err, dev->net,
+ "netif_rx status %d\n", status);
}
EXPORT_SYMBOL_GPL(usbnet_skb_return);
@@ -313,9 +313,9 @@ void usbnet_defer_kevent (struct usbnet *dev, int work)
{
set_bit (work, &dev->flags);
if (!schedule_work (&dev->kevent))
- deverr (dev, "kevent %d may have been dropped", work);
+ netdev_err(dev->net, "kevent %d may have been dropped\n", work);
else
- devdbg (dev, "kevent %d scheduled", work);
+ netdev_dbg(dev->net, "kevent %d scheduled\n", work);
}
EXPORT_SYMBOL_GPL(usbnet_defer_kevent);
@@ -332,8 +332,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
size_t size = dev->rx_urb_size;
if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) {
- if (netif_msg_rx_err (dev))
- devdbg (dev, "no rx skb");
+ netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
usb_free_urb (urb);
return;
@@ -363,21 +362,19 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
break;
case -ENODEV:
- if (netif_msg_ifdown (dev))
- devdbg (dev, "device gone");
+ netif_dbg(dev, ifdown, dev->net, "device gone\n");
netif_device_detach (dev->net);
break;
default:
- if (netif_msg_rx_err (dev))
- devdbg (dev, "rx submit, %d", retval);
+ netif_dbg(dev, rx_err, dev->net,
+ "rx submit, %d\n", retval);
tasklet_schedule (&dev->bh);
break;
case 0:
__skb_queue_tail (&dev->rxq, skb);
}
} else {
- if (netif_msg_ifdown (dev))
- devdbg (dev, "rx: stopped");
+ netif_dbg(dev, ifdown, dev->net, "rx: stopped\n");
retval = -ENOLINK;
}
spin_unlock_irqrestore (&dev->rxq.lock, lockflags);
@@ -400,8 +397,7 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
if (skb->len)
usbnet_skb_return (dev, skb);
else {
- if (netif_msg_rx_err (dev))
- devdbg (dev, "drop");
+ netif_dbg(dev, rx_err, dev->net, "drop\n");
error:
dev->net->stats.rx_errors++;
skb_queue_tail (&dev->done, skb);
@@ -428,8 +424,8 @@ static void rx_complete (struct urb *urb)
entry->state = rx_cleanup;
dev->net->stats.rx_errors++;
dev->net->stats.rx_length_errors++;
- if (netif_msg_rx_err (dev))
- devdbg (dev, "rx length %d", skb->len);
+ netif_dbg(dev, rx_err, dev->net,
+ "rx length %d\n", skb->len);
}
break;
@@ -446,8 +442,8 @@ static void rx_complete (struct urb *urb)
/* software-driven interface shutdown */
case -ECONNRESET: /* async unlink */
case -ESHUTDOWN: /* hardware gone */
- if (netif_msg_ifdown (dev))
- devdbg (dev, "rx shutdown, code %d", urb_status);
+ netif_dbg(dev, ifdown, dev->net,
+ "rx shutdown, code %d\n", urb_status);
goto block;
/* we get controller i/o faults during khubd disconnect() delays.
@@ -460,8 +456,8 @@ static void rx_complete (struct urb *urb)
dev->net->stats.rx_errors++;
if (!timer_pending (&dev->delay)) {
mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
- if (netif_msg_link (dev))
- devdbg (dev, "rx throttle %d", urb_status);
+ netif_dbg(dev, link, dev->net,
+ "rx throttle %d\n", urb_status);
}
block:
entry->state = rx_cleanup;
@@ -477,8 +473,7 @@ block:
default:
entry->state = rx_cleanup;
dev->net->stats.rx_errors++;
- if (netif_msg_rx_err (dev))
- devdbg (dev, "rx status %d", urb_status);
+ netif_dbg(dev, rx_err, dev->net, "rx status %d\n", urb_status);
break;
}
@@ -492,8 +487,7 @@ block:
}
usb_free_urb (urb);
}
- if (netif_msg_rx_err (dev))
- devdbg (dev, "no read resubmitted");
+ netif_dbg(dev, rx_err, dev->net, "no read resubmitted\n");
}
static void intr_complete (struct urb *urb)
@@ -510,15 +504,15 @@ static void intr_complete (struct urb *urb)
/* software-driven interface shutdown */
case -ENOENT: /* urb killed */
case -ESHUTDOWN: /* hardware gone */
- if (netif_msg_ifdown (dev))
- devdbg (dev, "intr shutdown, code %d", status);
+ netif_dbg(dev, ifdown, dev->net,
+ "intr shutdown, code %d\n", status);
return;
/* NOTE: not throttling like RX/TX, since this endpoint
* already polls infrequently
*/
default:
- devdbg (dev, "intr status %d", status);
+ netdev_dbg(dev->net, "intr status %d\n", status);
break;
}
@@ -527,8 +521,9 @@ static void intr_complete (struct urb *urb)
memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
status = usb_submit_urb (urb, GFP_ATOMIC);
- if (status != 0 && netif_msg_timer (dev))
- deverr(dev, "intr resubmit --> %d", status);
+ if (status != 0)
+ netif_err(dev, timer, dev->net,
+ "intr resubmit --> %d\n", status);
}
/*-------------------------------------------------------------------------*/
@@ -536,8 +531,7 @@ void usbnet_pause_rx(struct usbnet *dev)
{
set_bit(EVENT_RX_PAUSED, &dev->flags);
- if (netif_msg_rx_status(dev))
- devdbg(dev, "paused rx queue enabled");
+ netif_dbg(dev, rx_status, dev->net, "paused rx queue enabled\n");
}
EXPORT_SYMBOL_GPL(usbnet_pause_rx);
@@ -555,8 +549,8 @@ void usbnet_resume_rx(struct usbnet *dev)
tasklet_schedule(&dev->bh);
- if (netif_msg_rx_status(dev))
- devdbg(dev, "paused rx queue disabled, %d skbs requeued", num);
+ netif_dbg(dev, rx_status, dev->net,
+ "paused rx queue disabled, %d skbs requeued\n", num);
}
EXPORT_SYMBOL_GPL(usbnet_resume_rx);
@@ -589,7 +583,7 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
// these (async) unlinks complete immediately
retval = usb_unlink_urb (urb);
if (retval != -EINPROGRESS && retval != 0)
- devdbg (dev, "unlink urb err, %d", retval);
+ netdev_dbg(dev->net, "unlink urb err, %d\n", retval);
else
count++;
}
@@ -631,9 +625,8 @@ static void usbnet_terminate_urbs(struct usbnet *dev)
&& !skb_queue_empty(&dev->done)) {
schedule_timeout(UNLINK_TIMEOUT_MS);
set_current_state(TASK_UNINTERRUPTIBLE);
- if (netif_msg_ifdown(dev))
- devdbg(dev, "waited for %d urb completions",
- temp);
+ netif_dbg(dev, ifdown, dev->net,
+ "waited for %d urb completions\n", temp);
}
set_current_state(TASK_RUNNING);
dev->wait = NULL;
@@ -648,22 +641,21 @@ int usbnet_stop (struct net_device *net)
netif_stop_queue (net);
- if (netif_msg_ifdown (dev))
- devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld",
- net->stats.rx_packets, net->stats.tx_packets,
- net->stats.rx_errors, net->stats.tx_errors
- );
+ netif_info(dev, ifdown, dev->net,
+ "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
+ net->stats.rx_packets, net->stats.tx_packets,
+ net->stats.rx_errors, net->stats.tx_errors);
/* allow minidriver to stop correctly (wireless devices to turn off
* radio etc) */
if (info->stop) {
retval = info->stop(dev);
- if (retval < 0 && netif_msg_ifdown(dev))
- devinfo(dev,
- "stop fail (%d) usbnet usb-%s-%s, %s",
- retval,
- dev->udev->bus->bus_name, dev->udev->devpath,
- info->description);
+ if (retval < 0)
+ netif_info(dev, ifdown, dev->net,
+ "stop fail (%d) usbnet usb-%s-%s, %s\n",
+ retval,
+ dev->udev->bus->bus_name, dev->udev->devpath,
+ info->description);
}
if (!(info->flags & FLAG_AVOID_UNLINK_URBS))
@@ -702,30 +694,29 @@ int usbnet_open (struct net_device *net)
struct driver_info *info = dev->driver_info;
if ((retval = usb_autopm_get_interface(dev->intf)) < 0) {
- if (netif_msg_ifup (dev))
- devinfo (dev,
- "resumption fail (%d) usbnet usb-%s-%s, %s",
- retval,
- dev->udev->bus->bus_name, dev->udev->devpath,
- info->description);
+ netif_info(dev, ifup, dev->net,
+ "resumption fail (%d) usbnet usb-%s-%s, %s\n",
+ retval,
+ dev->udev->bus->bus_name,
+ dev->udev->devpath,
+ info->description);
goto done_nopm;
}
// put into "known safe" state
if (info->reset && (retval = info->reset (dev)) < 0) {
- if (netif_msg_ifup (dev))
- devinfo (dev,
- "open reset fail (%d) usbnet usb-%s-%s, %s",
- retval,
- dev->udev->bus->bus_name, dev->udev->devpath,
- info->description);
+ netif_info(dev, ifup, dev->net,
+ "open reset fail (%d) usbnet usb-%s-%s, %s\n",
+ retval,
+ dev->udev->bus->bus_name,
+ dev->udev->devpath,
+ info->description);
goto done;
}
// insist peer be connected
if (info->check_connect && (retval = info->check_connect (dev)) < 0) {
- if (netif_msg_ifup (dev))
- devdbg (dev, "can't open; %d", retval);
+ netif_dbg(dev, ifup, dev->net, "can't open; %d\n", retval);
goto done;
}
@@ -733,34 +724,23 @@ int usbnet_open (struct net_device *net)
if (dev->interrupt) {
retval = usb_submit_urb (dev->interrupt, GFP_KERNEL);
if (retval < 0) {
- if (netif_msg_ifup (dev))
- deverr (dev, "intr submit %d", retval);
+ netif_err(dev, ifup, dev->net,
+ "intr submit %d\n", retval);
goto done;
}
}
netif_start_queue (net);
- if (netif_msg_ifup (dev)) {
- char *framing;
-
- if (dev->driver_info->flags & FLAG_FRAMING_NC)
- framing = "NetChip";
- else if (dev->driver_info->flags & FLAG_FRAMING_GL)
- framing = "GeneSys";
- else if (dev->driver_info->flags & FLAG_FRAMING_Z)
- framing = "Zaurus";
- else if (dev->driver_info->flags & FLAG_FRAMING_RN)
- framing = "RNDIS";
- else if (dev->driver_info->flags & FLAG_FRAMING_AX)
- framing = "ASIX";
- else
- framing = "simple";
-
- devinfo (dev, "open: enable queueing "
- "(rx %d, tx %d) mtu %d %s framing",
- (int)RX_QLEN (dev), (int)TX_QLEN (dev), dev->net->mtu,
- framing);
- }
+ netif_info(dev, ifup, dev->net,
+ "open: enable queueing (rx %d, tx %d) mtu %d %s framing\n",
+ (int)RX_QLEN(dev), (int)TX_QLEN(dev),
+ dev->net->mtu,
+ (dev->driver_info->flags & FLAG_FRAMING_NC) ? "NetChip" :
+ (dev->driver_info->flags & FLAG_FRAMING_GL) ? "GeneSys" :
+ (dev->driver_info->flags & FLAG_FRAMING_Z) ? "Zaurus" :
+ (dev->driver_info->flags & FLAG_FRAMING_RN) ? "RNDIS" :
+ (dev->driver_info->flags & FLAG_FRAMING_AX) ? "ASIX" :
+ "simple");
// delay posting reads until we're fully open
tasklet_schedule (&dev->bh);
@@ -771,6 +751,7 @@ int usbnet_open (struct net_device *net)
usb_autopm_put_interface(dev->intf);
}
return retval;
+
done:
usb_autopm_put_interface(dev->intf);
done_nopm:
@@ -908,8 +889,8 @@ kevent (struct work_struct *work)
status != -ESHUTDOWN) {
if (netif_msg_tx_err (dev))
fail_pipe:
- deverr (dev, "can't clear tx halt, status %d",
- status);
+ netdev_err(dev->net, "can't clear tx halt, status %d\n",
+ status);
} else {
clear_bit (EVENT_TX_HALT, &dev->flags);
if (status != -ESHUTDOWN)
@@ -928,8 +909,8 @@ fail_pipe:
status != -ESHUTDOWN) {
if (netif_msg_rx_err (dev))
fail_halt:
- deverr (dev, "can't clear rx halt, status %d",
- status);
+ netdev_err(dev->net, "can't clear rx halt, status %d\n",
+ status);
} else {
clear_bit (EVENT_RX_HALT, &dev->flags);
tasklet_schedule (&dev->bh);
@@ -967,18 +948,18 @@ fail_lowmem:
if(info->link_reset && (retval = info->link_reset(dev)) < 0) {
usb_autopm_put_interface(dev->intf);
skip_reset:
- devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s",
- retval,
- dev->udev->bus->bus_name, dev->udev->devpath,
- info->description);
+ netdev_info(dev->net, "link reset failed (%d) usbnet usb-%s-%s, %s\n",
+ retval,
+ dev->udev->bus->bus_name,
+ dev->udev->devpath,
+ info->description);
} else {
usb_autopm_put_interface(dev->intf);
}
}
if (dev->flags)
- devdbg (dev, "kevent done, flags = 0x%lx",
- dev->flags);
+ netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags);
}
/*-------------------------------------------------------------------------*/
@@ -1014,15 +995,14 @@ static void tx_complete (struct urb *urb)
if (!timer_pending (&dev->delay)) {
mod_timer (&dev->delay,
jiffies + THROTTLE_JIFFIES);
- if (netif_msg_link (dev))
- devdbg (dev, "tx throttle %d",
- urb->status);
+ netif_dbg(dev, link, dev->net,
+ "tx throttle %d\n", urb->status);
}
netif_stop_queue (dev->net);
break;
default:
- if (netif_msg_tx_err (dev))
- devdbg (dev, "tx err %d", entry->urb->status);
+ netif_dbg(dev, tx_err, dev->net,
+ "tx err %d\n", entry->urb->status);
break;
}
}
@@ -1064,16 +1044,14 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
if (info->tx_fixup) {
skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
if (!skb) {
- if (netif_msg_tx_err (dev))
- devdbg (dev, "can't tx_fixup skb");
+ netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
goto drop;
}
}
length = skb->len;
if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) {
- if (netif_msg_tx_err (dev))
- devdbg (dev, "no urb");
+ netif_dbg(dev, tx_err, dev->net, "no urb\n");
goto drop;
}
@@ -1113,7 +1091,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
/* no use to process more packets */
netif_stop_queue(net);
spin_unlock_irqrestore(&dev->txq.lock, flags);
- devdbg(dev, "Delaying transmission for resumption");
+ netdev_dbg(dev->net, "Delaying transmission for resumption\n");
goto deferred;
}
#endif
@@ -1126,8 +1104,8 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
break;
default:
usb_autopm_put_interface_async(dev->intf);
- if (netif_msg_tx_err (dev))
- devdbg (dev, "tx: submit urb err %d", retval);
+ netif_dbg(dev, tx_err, dev->net,
+ "tx: submit urb err %d\n", retval);
break;
case 0:
net->trans_start = jiffies;
@@ -1138,17 +1116,15 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
spin_unlock_irqrestore (&dev->txq.lock, flags);
if (retval) {
- if (netif_msg_tx_err (dev))
- devdbg (dev, "drop, code %d", retval);
+ netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval);
drop:
dev->net->stats.tx_dropped++;
if (skb)
dev_kfree_skb_any (skb);
usb_free_urb (urb);
- } else if (netif_msg_tx_queued (dev)) {
- devdbg (dev, "> tx, len %d, type 0x%x",
- length, skb->protocol);
- }
+ } else
+ netif_dbg(dev, tx_queued, dev->net,
+ "> tx, len %d, type 0x%x\n", length, skb->protocol);
#ifdef CONFIG_PM
deferred:
#endif
@@ -1179,7 +1155,7 @@ static void usbnet_bh (unsigned long param)
dev_kfree_skb (skb);
continue;
default:
- devdbg (dev, "bogus skb state %d", entry->state);
+ netdev_dbg(dev->net, "bogus skb state %d\n", entry->state);
}
}
@@ -1207,9 +1183,10 @@ static void usbnet_bh (unsigned long param)
if (urb != NULL)
rx_submit (dev, urb, GFP_ATOMIC);
}
- if (temp != dev->rxq.qlen && netif_msg_link (dev))
- devdbg (dev, "rxqlen %d --> %d",
- temp, dev->rxq.qlen);
+ if (temp != dev->rxq.qlen)
+ netif_dbg(dev, link, dev->net,
+ "rxqlen %d --> %d\n",
+ temp, dev->rxq.qlen);
if (dev->rxq.qlen < qlen)
tasklet_schedule (&dev->bh);
}
@@ -1240,11 +1217,10 @@ void usbnet_disconnect (struct usb_interface *intf)
xdev = interface_to_usbdev (intf);
- if (netif_msg_probe (dev))
- devinfo (dev, "unregister '%s' usb-%s-%s, %s",
- intf->dev.driver->name,
- xdev->bus->bus_name, xdev->devpath,
- dev->driver_info->description);
+ netif_info(dev, probe, dev->net, "unregister '%s' usb-%s-%s, %s\n",
+ intf->dev.driver->name,
+ xdev->bus->bus_name, xdev->devpath,
+ dev->driver_info->description);
net = dev->net;
unregister_netdev (net);
@@ -1407,12 +1383,12 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
status = register_netdev (net);
if (status)
goto out3;
- if (netif_msg_probe (dev))
- devinfo (dev, "register '%s' at usb-%s-%s, %s, %pM",
- udev->dev.driver->name,
- xdev->bus->bus_name, xdev->devpath,
- dev->driver_info->description,
- net->dev_addr);
+ netif_info(dev, probe, dev->net,
+ "register '%s' at usb-%s-%s, %s, %pM\n",
+ udev->dev.driver->name,
+ xdev->bus->bus_name, xdev->devpath,
+ dev->driver_info->description,
+ net->dev_addr);
// ok, it's ready to go.
usb_set_intfdata (udev, dev);
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 3a15de56df9c..b583d4968add 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -34,7 +34,7 @@ struct veth_net_stats {
struct veth_priv {
struct net_device *peer;
- struct veth_net_stats *stats;
+ struct veth_net_stats __percpu *stats;
unsigned ip_summed;
};
@@ -263,7 +263,7 @@ static int veth_change_mtu(struct net_device *dev, int new_mtu)
static int veth_dev_init(struct net_device *dev)
{
- struct veth_net_stats *stats;
+ struct veth_net_stats __percpu *stats;
struct veth_priv *priv;
stats = alloc_percpu(struct veth_net_stats);
@@ -333,19 +333,17 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
struct veth_priv *priv;
char ifname[IFNAMSIZ];
struct nlattr *peer_tb[IFLA_MAX + 1], **tbp;
+ struct ifinfomsg *ifmp;
struct net *net;
/*
* create and register peer first
- *
- * struct ifinfomsg is at the head of VETH_INFO_PEER, but we
- * skip it since no info from it is useful yet
*/
-
if (data != NULL && data[VETH_INFO_PEER] != NULL) {
struct nlattr *nla_peer;
nla_peer = data[VETH_INFO_PEER];
+ ifmp = nla_data(nla_peer);
err = nla_parse(peer_tb, IFLA_MAX,
nla_data(nla_peer) + sizeof(struct ifinfomsg),
nla_len(nla_peer) - sizeof(struct ifinfomsg),
@@ -358,8 +356,10 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
return err;
tbp = peer_tb;
- } else
+ } else {
+ ifmp = NULL;
tbp = tb;
+ }
if (tbp[IFLA_IFNAME])
nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ);
@@ -387,6 +387,10 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
netif_carrier_off(peer);
+ err = rtnl_configure_link(peer, ifmp);
+ if (err < 0)
+ goto err_configure_peer;
+
/*
* register dev last
*
@@ -428,6 +432,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
err_register_dev:
/* nothing to do */
err_alloc_name:
+err_configure_peer:
unregister_netdevice(peer);
return err;
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 611b80435955..50f881aa3939 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -267,7 +267,7 @@ enum rhine_quirks {
/* Beware of PCI posted writes */
#define IOSYNC do { ioread8(ioaddr + StationAddr); } while (0)
-static const struct pci_device_id rhine_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(rhine_pci_tbl) = {
{ 0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, }, /* VT86C100A */
{ 0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, }, /* VT6102 */
{ 0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, }, /* 6105{,L,LOM} */
@@ -1697,7 +1697,7 @@ static void rhine_set_rx_mode(struct net_device *dev)
rx_mode = 0x1C;
iowrite32(0xffffffff, ioaddr + MulticastFilter0);
iowrite32(0xffffffff, ioaddr + MulticastFilter1);
- } else if ((dev->mc_count > multicast_filter_limit) ||
+ } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
(dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
iowrite32(0xffffffff, ioaddr + MulticastFilter0);
@@ -1705,10 +1705,9 @@ static void rhine_set_rx_mode(struct net_device *dev)
rx_mode = 0x0C;
} else {
struct dev_mc_list *mclist;
- int i;
+
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index c93f58f5c6f2..3a486f3bad3d 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -361,7 +361,7 @@ static struct velocity_info_tbl chip_info_table[] = {
* Describe the PCI device identifiers that we support in this
* device driver. Used for hotplug autoloading.
*/
-static const struct pci_device_id velocity_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(velocity_id_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
{ }
};
@@ -1132,7 +1132,7 @@ static void velocity_set_multi(struct net_device *dev)
writel(0xffffffff, &regs->MARCAM[0]);
writel(0xffffffff, &regs->MARCAM[4]);
rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
- } else if ((dev->mc_count > vptr->multicast_limit) ||
+ } else if ((netdev_mc_count(dev) > vptr->multicast_limit) ||
(dev->flags & IFF_ALLMULTI)) {
writel(0xffffffff, &regs->MARCAM[0]);
writel(0xffffffff, &regs->MARCAM[4]);
@@ -1141,9 +1141,11 @@ static void velocity_set_multi(struct net_device *dev)
int offset = MCAM_SIZE - vptr->multicast_limit;
mac_get_cam_mask(regs, vptr->mCAMmask);
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
+ i = 0;
+ netdev_for_each_mc_addr(mclist, dev) {
mac_set_cam(regs, i + offset, mclist->dmi_addr);
vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
+ i++;
}
mac_set_cam_mask(regs, vptr->mCAMmask);
@@ -1877,13 +1879,12 @@ static void velocity_error(struct velocity_info *vptr, int status)
/**
* tx_srv - transmit interrupt service
* @vptr; Velocity
- * @status:
*
* Scan the queues looking for transmitted packets that
* we can complete and clean up. Update any statistics as
* necessary/
*/
-static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
+static int velocity_tx_srv(struct velocity_info *vptr)
{
struct tx_desc *td;
int qnum;
@@ -2090,14 +2091,12 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
/**
* velocity_rx_srv - service RX interrupt
* @vptr: velocity
- * @status: adapter status (unused)
*
* Walk the receive ring of the velocity adapter and remove
* any received packets from the receive queue. Hand the ring
* slots back to the adapter for reuse.
*/
-static int velocity_rx_srv(struct velocity_info *vptr, int status,
- int budget_left)
+static int velocity_rx_srv(struct velocity_info *vptr, int budget_left)
{
struct net_device_stats *stats = &vptr->dev->stats;
int rd_curr = vptr->rx.curr;
@@ -2151,32 +2150,24 @@ static int velocity_poll(struct napi_struct *napi, int budget)
struct velocity_info *vptr = container_of(napi,
struct velocity_info, napi);
unsigned int rx_done;
- u32 isr_status;
-
- spin_lock(&vptr->lock);
- isr_status = mac_read_isr(vptr->mac_regs);
-
- /* Ack the interrupt */
- mac_write_isr(vptr->mac_regs, isr_status);
- if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
- velocity_error(vptr, isr_status);
+ unsigned long flags;
+ spin_lock_irqsave(&vptr->lock, flags);
/*
* Do rx and tx twice for performance (taken from the VIA
* out-of-tree driver).
*/
- rx_done = velocity_rx_srv(vptr, isr_status, budget / 2);
- velocity_tx_srv(vptr, isr_status);
- rx_done += velocity_rx_srv(vptr, isr_status, budget - rx_done);
- velocity_tx_srv(vptr, isr_status);
-
- spin_unlock(&vptr->lock);
+ rx_done = velocity_rx_srv(vptr, budget / 2);
+ velocity_tx_srv(vptr);
+ rx_done += velocity_rx_srv(vptr, budget - rx_done);
+ velocity_tx_srv(vptr);
/* If budget not fully consumed, exit the polling mode */
if (rx_done < budget) {
napi_complete(napi);
mac_enable_int(vptr->mac_regs);
}
+ spin_unlock_irqrestore(&vptr->lock, flags);
return rx_done;
}
@@ -2206,10 +2197,17 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance)
return IRQ_NONE;
}
+ /* Ack the interrupt */
+ mac_write_isr(vptr->mac_regs, isr_status);
+
if (likely(napi_schedule_prep(&vptr->napi))) {
mac_disable_int(vptr->mac_regs);
__napi_schedule(&vptr->napi);
}
+
+ if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
+ velocity_error(vptr, isr_status);
+
spin_unlock(&vptr->lock);
return IRQ_HANDLED;
@@ -2702,10 +2700,8 @@ static void __devinit velocity_print_info(struct velocity_info *vptr)
struct net_device *dev = vptr->dev;
printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
- printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
- dev->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_INFO "%s: Ethernet Address: %pM\n",
+ dev->name, dev->dev_addr);
}
static u32 velocity_get_link(struct net_device *dev)
@@ -2829,7 +2825,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT);
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
- NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM;
+ NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM | NETIF_F_SG;
ret = register_netdev(dev);
if (ret < 0)
@@ -3100,7 +3096,7 @@ static int velocity_resume(struct pci_dev *pdev)
velocity_init_registers(vptr, VELOCITY_INIT_WOL);
mac_disable_int(vptr->mac_regs);
- velocity_tx_srv(vptr, 0);
+ velocity_tx_srv(vptr);
for (i = 0; i < vptr->tx.numq; i++) {
if (vptr->tx.used[i])
@@ -3344,6 +3340,7 @@ static int velocity_set_coalesce(struct net_device *dev,
{
struct velocity_info *vptr = netdev_priv(dev);
int max_us = 0x3f * 64;
+ unsigned long flags;
/* 6 bits of */
if (ecmd->tx_coalesce_usecs > max_us)
@@ -3365,6 +3362,7 @@ static int velocity_set_coalesce(struct net_device *dev,
ecmd->tx_coalesce_usecs);
/* Setup the interrupt suppression and queue timers */
+ spin_lock_irqsave(&vptr->lock, flags);
mac_disable_int(vptr->mac_regs);
setup_adaptive_interrupts(vptr);
setup_queue_timers(vptr);
@@ -3372,6 +3370,7 @@ static int velocity_set_coalesce(struct net_device *dev,
mac_write_int_mask(vptr->int_mask, vptr->mac_regs);
mac_clear_isr(vptr->mac_regs);
mac_enable_int(vptr->mac_regs);
+ spin_unlock_irqrestore(&vptr->lock, flags);
return 0;
}
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index c708ecc3cb2e..25dc77ccbf58 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -56,10 +56,6 @@ struct virtnet_info
/* Host will merge rx buffers for big packets (shake it! shake it!) */
bool mergeable_rx_bufs;
- /* Receive & send queues. */
- struct sk_buff_head recv;
- struct sk_buff_head send;
-
/* Work struct for refilling if we run low on memory. */
struct delayed_work refill;
@@ -75,34 +71,44 @@ struct skb_vnet_hdr {
unsigned int num_sg;
};
+struct padded_vnet_hdr {
+ struct virtio_net_hdr hdr;
+ /*
+ * virtio_net_hdr should be in a separated sg buffer because of a
+ * QEMU bug, and data sg buffer shares same page with this header sg.
+ * This padding makes next sg 16 byte aligned after virtio_net_hdr.
+ */
+ char padding[6];
+};
+
static inline struct skb_vnet_hdr *skb_vnet_hdr(struct sk_buff *skb)
{
return (struct skb_vnet_hdr *)skb->cb;
}
-static void give_a_page(struct virtnet_info *vi, struct page *page)
-{
- page->private = (unsigned long)vi->pages;
- vi->pages = page;
-}
-
-static void trim_pages(struct virtnet_info *vi, struct sk_buff *skb)
+/*
+ * private is used to chain pages for big packets, put the whole
+ * most recent used list in the beginning for reuse
+ */
+static void give_pages(struct virtnet_info *vi, struct page *page)
{
- unsigned int i;
+ struct page *end;
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- give_a_page(vi, skb_shinfo(skb)->frags[i].page);
- skb_shinfo(skb)->nr_frags = 0;
- skb->data_len = 0;
+ /* Find end of list, sew whole thing into vi->pages. */
+ for (end = page; end->private; end = (struct page *)end->private);
+ end->private = (unsigned long)vi->pages;
+ vi->pages = page;
}
static struct page *get_a_page(struct virtnet_info *vi, gfp_t gfp_mask)
{
struct page *p = vi->pages;
- if (p)
+ if (p) {
vi->pages = (struct page *)p->private;
- else
+ /* clear private here, it is used to chain pages */
+ p->private = 0;
+ } else
p = alloc_page(gfp_mask);
return p;
}
@@ -118,99 +124,142 @@ static void skb_xmit_done(struct virtqueue *svq)
netif_wake_queue(vi->dev);
}
-static void receive_skb(struct net_device *dev, struct sk_buff *skb,
- unsigned len)
+static void set_skb_frag(struct sk_buff *skb, struct page *page,
+ unsigned int offset, unsigned int *len)
{
- struct virtnet_info *vi = netdev_priv(dev);
- struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
- int err;
- int i;
+ int i = skb_shinfo(skb)->nr_frags;
+ skb_frag_t *f;
+
+ f = &skb_shinfo(skb)->frags[i];
+ f->size = min((unsigned)PAGE_SIZE - offset, *len);
+ f->page_offset = offset;
+ f->page = page;
+
+ skb->data_len += f->size;
+ skb->len += f->size;
+ skb_shinfo(skb)->nr_frags++;
+ *len -= f->size;
+}
- if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
- pr_debug("%s: short packet %i\n", dev->name, len);
- dev->stats.rx_length_errors++;
- goto drop;
- }
+static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+ struct page *page, unsigned int len)
+{
+ struct sk_buff *skb;
+ struct skb_vnet_hdr *hdr;
+ unsigned int copy, hdr_len, offset;
+ char *p;
- if (vi->mergeable_rx_bufs) {
- unsigned int copy;
- char *p = page_address(skb_shinfo(skb)->frags[0].page);
+ p = page_address(page);
- if (len > PAGE_SIZE)
- len = PAGE_SIZE;
- len -= sizeof(struct virtio_net_hdr_mrg_rxbuf);
-
- memcpy(&hdr->mhdr, p, sizeof(hdr->mhdr));
- p += sizeof(hdr->mhdr);
+ /* copy small packet so we can reuse these pages for small data */
+ skb = netdev_alloc_skb_ip_align(vi->dev, GOOD_COPY_LEN);
+ if (unlikely(!skb))
+ return NULL;
- copy = len;
- if (copy > skb_tailroom(skb))
- copy = skb_tailroom(skb);
+ hdr = skb_vnet_hdr(skb);
- memcpy(skb_put(skb, copy), p, copy);
+ if (vi->mergeable_rx_bufs) {
+ hdr_len = sizeof hdr->mhdr;
+ offset = hdr_len;
+ } else {
+ hdr_len = sizeof hdr->hdr;
+ offset = sizeof(struct padded_vnet_hdr);
+ }
- len -= copy;
+ memcpy(hdr, p, hdr_len);
- if (!len) {
- give_a_page(vi, skb_shinfo(skb)->frags[0].page);
- skb_shinfo(skb)->nr_frags--;
- } else {
- skb_shinfo(skb)->frags[0].page_offset +=
- sizeof(hdr->mhdr) + copy;
- skb_shinfo(skb)->frags[0].size = len;
- skb->data_len += len;
- skb->len += len;
- }
+ len -= hdr_len;
+ p += offset;
- while (--hdr->mhdr.num_buffers) {
- struct sk_buff *nskb;
+ copy = len;
+ if (copy > skb_tailroom(skb))
+ copy = skb_tailroom(skb);
+ memcpy(skb_put(skb, copy), p, copy);
- i = skb_shinfo(skb)->nr_frags;
- if (i >= MAX_SKB_FRAGS) {
- pr_debug("%s: packet too long %d\n", dev->name,
- len);
- dev->stats.rx_length_errors++;
- goto drop;
- }
+ len -= copy;
+ offset += copy;
- nskb = vi->rvq->vq_ops->get_buf(vi->rvq, &len);
- if (!nskb) {
- pr_debug("%s: rx error: %d buffers missing\n",
- dev->name, hdr->mhdr.num_buffers);
- dev->stats.rx_length_errors++;
- goto drop;
- }
+ while (len) {
+ set_skb_frag(skb, page, offset, &len);
+ page = (struct page *)page->private;
+ offset = 0;
+ }
- __skb_unlink(nskb, &vi->recv);
- vi->num--;
+ if (page)
+ give_pages(vi, page);
- skb_shinfo(skb)->frags[i] = skb_shinfo(nskb)->frags[0];
- skb_shinfo(nskb)->nr_frags = 0;
- kfree_skb(nskb);
+ return skb;
+}
- if (len > PAGE_SIZE)
- len = PAGE_SIZE;
+static int receive_mergeable(struct virtnet_info *vi, struct sk_buff *skb)
+{
+ struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
+ struct page *page;
+ int num_buf, i, len;
+
+ num_buf = hdr->mhdr.num_buffers;
+ while (--num_buf) {
+ i = skb_shinfo(skb)->nr_frags;
+ if (i >= MAX_SKB_FRAGS) {
+ pr_debug("%s: packet too long\n", skb->dev->name);
+ skb->dev->stats.rx_length_errors++;
+ return -EINVAL;
+ }
- skb_shinfo(skb)->frags[i].size = len;
- skb_shinfo(skb)->nr_frags++;
- skb->data_len += len;
- skb->len += len;
+ page = vi->rvq->vq_ops->get_buf(vi->rvq, &len);
+ if (!page) {
+ pr_debug("%s: rx error: %d buffers missing\n",
+ skb->dev->name, hdr->mhdr.num_buffers);
+ skb->dev->stats.rx_length_errors++;
+ return -EINVAL;
}
- } else {
- len -= sizeof(hdr->hdr);
+ if (len > PAGE_SIZE)
+ len = PAGE_SIZE;
+
+ set_skb_frag(skb, page, 0, &len);
- if (len <= MAX_PACKET_LEN)
- trim_pages(vi, skb);
+ --vi->num;
+ }
+ return 0;
+}
- err = pskb_trim(skb, len);
- if (err) {
- pr_debug("%s: pskb_trim failed %i %d\n", dev->name,
- len, err);
+static void receive_buf(struct net_device *dev, void *buf, unsigned int len)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
+ struct sk_buff *skb;
+ struct page *page;
+ struct skb_vnet_hdr *hdr;
+
+ if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
+ pr_debug("%s: short packet %i\n", dev->name, len);
+ dev->stats.rx_length_errors++;
+ if (vi->mergeable_rx_bufs || vi->big_packets)
+ give_pages(vi, buf);
+ else
+ dev_kfree_skb(buf);
+ return;
+ }
+
+ if (!vi->mergeable_rx_bufs && !vi->big_packets) {
+ skb = buf;
+ len -= sizeof(struct virtio_net_hdr);
+ skb_trim(skb, len);
+ } else {
+ page = buf;
+ skb = page_to_skb(vi, page, len);
+ if (unlikely(!skb)) {
dev->stats.rx_dropped++;
- goto drop;
+ give_pages(vi, page);
+ return;
}
+ if (vi->mergeable_rx_bufs)
+ if (receive_mergeable(vi, skb)) {
+ dev_kfree_skb(skb);
+ return;
+ }
}
+ hdr = skb_vnet_hdr(skb);
skb->truesize += skb->data_len;
dev->stats.rx_bytes += skb->len;
dev->stats.rx_packets++;
@@ -267,110 +316,119 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
frame_err:
dev->stats.rx_frame_errors++;
-drop:
dev_kfree_skb(skb);
}
-static bool try_fill_recv_maxbufs(struct virtnet_info *vi, gfp_t gfp)
+static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)
{
struct sk_buff *skb;
- struct scatterlist sg[2+MAX_SKB_FRAGS];
- int num, err, i;
- bool oom = false;
-
- sg_init_table(sg, 2+MAX_SKB_FRAGS);
- do {
- struct skb_vnet_hdr *hdr;
+ struct skb_vnet_hdr *hdr;
+ struct scatterlist sg[2];
+ int err;
- skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);
- if (unlikely(!skb)) {
- oom = true;
- break;
- }
+ skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);
+ if (unlikely(!skb))
+ return -ENOMEM;
- skb_put(skb, MAX_PACKET_LEN);
+ skb_put(skb, MAX_PACKET_LEN);
- hdr = skb_vnet_hdr(skb);
- sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr));
+ hdr = skb_vnet_hdr(skb);
+ sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr);
- if (vi->big_packets) {
- for (i = 0; i < MAX_SKB_FRAGS; i++) {
- skb_frag_t *f = &skb_shinfo(skb)->frags[i];
- f->page = get_a_page(vi, gfp);
- if (!f->page)
- break;
+ skb_to_sgvec(skb, sg + 1, 0, skb->len);
- f->page_offset = 0;
- f->size = PAGE_SIZE;
+ err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, 2, skb);
+ if (err < 0)
+ dev_kfree_skb(skb);
- skb->data_len += PAGE_SIZE;
- skb->len += PAGE_SIZE;
+ return err;
+}
- skb_shinfo(skb)->nr_frags++;
- }
+static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)
+{
+ struct scatterlist sg[MAX_SKB_FRAGS + 2];
+ struct page *first, *list = NULL;
+ char *p;
+ int i, err, offset;
+
+ /* page in sg[MAX_SKB_FRAGS + 1] is list tail */
+ for (i = MAX_SKB_FRAGS + 1; i > 1; --i) {
+ first = get_a_page(vi, gfp);
+ if (!first) {
+ if (list)
+ give_pages(vi, list);
+ return -ENOMEM;
}
+ sg_set_buf(&sg[i], page_address(first), PAGE_SIZE);
- num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
- skb_queue_head(&vi->recv, skb);
+ /* chain new page in list head to match sg */
+ first->private = (unsigned long)list;
+ list = first;
+ }
- err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, num, skb);
- if (err < 0) {
- skb_unlink(skb, &vi->recv);
- trim_pages(vi, skb);
- kfree_skb(skb);
- break;
- }
- vi->num++;
- } while (err >= num);
- if (unlikely(vi->num > vi->max))
- vi->max = vi->num;
- vi->rvq->vq_ops->kick(vi->rvq);
- return !oom;
+ first = get_a_page(vi, gfp);
+ if (!first) {
+ give_pages(vi, list);
+ return -ENOMEM;
+ }
+ p = page_address(first);
+
+ /* sg[0], sg[1] share the same page */
+ /* a separated sg[0] for virtio_net_hdr only during to QEMU bug*/
+ sg_set_buf(&sg[0], p, sizeof(struct virtio_net_hdr));
+
+ /* sg[1] for data packet, from offset */
+ offset = sizeof(struct padded_vnet_hdr);
+ sg_set_buf(&sg[1], p + offset, PAGE_SIZE - offset);
+
+ /* chain first in list head */
+ first->private = (unsigned long)list;
+ err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, MAX_SKB_FRAGS + 2,
+ first);
+ if (err < 0)
+ give_pages(vi, first);
+
+ return err;
}
-/* Returns false if we couldn't fill entirely (OOM). */
-static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
+static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp)
{
- struct sk_buff *skb;
- struct scatterlist sg[1];
+ struct page *page;
+ struct scatterlist sg;
int err;
- bool oom = false;
- if (!vi->mergeable_rx_bufs)
- return try_fill_recv_maxbufs(vi, gfp);
+ page = get_a_page(vi, gfp);
+ if (!page)
+ return -ENOMEM;
- do {
- skb_frag_t *f;
+ sg_init_one(&sg, page_address(page), PAGE_SIZE);
- skb = netdev_alloc_skb_ip_align(vi->dev, GOOD_COPY_LEN);
- if (unlikely(!skb)) {
- oom = true;
- break;
- }
+ err = vi->rvq->vq_ops->add_buf(vi->rvq, &sg, 0, 1, page);
+ if (err < 0)
+ give_pages(vi, page);
- f = &skb_shinfo(skb)->frags[0];
- f->page = get_a_page(vi, gfp);
- if (!f->page) {
- oom = true;
- kfree_skb(skb);
- break;
- }
-
- f->page_offset = 0;
- f->size = PAGE_SIZE;
+ return err;
+}
- skb_shinfo(skb)->nr_frags++;
+/* Returns false if we couldn't fill entirely (OOM). */
+static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
+{
+ int err;
+ bool oom = false;
- sg_init_one(sg, page_address(f->page), PAGE_SIZE);
- skb_queue_head(&vi->recv, skb);
+ do {
+ if (vi->mergeable_rx_bufs)
+ err = add_recvbuf_mergeable(vi, gfp);
+ else if (vi->big_packets)
+ err = add_recvbuf_big(vi, gfp);
+ else
+ err = add_recvbuf_small(vi, gfp);
- err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, 1, skb);
if (err < 0) {
- skb_unlink(skb, &vi->recv);
- kfree_skb(skb);
+ oom = true;
break;
}
- vi->num++;
+ ++vi->num;
} while (err > 0);
if (unlikely(vi->num > vi->max))
vi->max = vi->num;
@@ -395,8 +453,7 @@ static void refill_work(struct work_struct *work)
vi = container_of(work, struct virtnet_info, refill.work);
napi_disable(&vi->napi);
- try_fill_recv(vi, GFP_KERNEL);
- still_empty = (vi->num == 0);
+ still_empty = !try_fill_recv(vi, GFP_KERNEL);
napi_enable(&vi->napi);
/* In theory, this can happen: if we don't get any buffers in
@@ -408,15 +465,14 @@ static void refill_work(struct work_struct *work)
static int virtnet_poll(struct napi_struct *napi, int budget)
{
struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
- struct sk_buff *skb = NULL;
+ void *buf;
unsigned int len, received = 0;
again:
while (received < budget &&
- (skb = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) {
- __skb_unlink(skb, &vi->recv);
- receive_skb(vi->dev, skb, len);
- vi->num--;
+ (buf = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) {
+ receive_buf(vi->dev, buf, len);
+ --vi->num;
received++;
}
@@ -446,7 +502,6 @@ static unsigned int free_old_xmit_skbs(struct virtnet_info *vi)
while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) {
pr_debug("Sent skb %p\n", skb);
- __skb_unlink(skb, &vi->send);
vi->dev->stats.tx_bytes += skb->len;
vi->dev->stats.tx_packets++;
tot_sgs += skb_vnet_hdr(skb)->num_sg;
@@ -496,9 +551,9 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
/* Encode metadata header at front. */
if (vi->mergeable_rx_bufs)
- sg_set_buf(sg, &hdr->mhdr, sizeof(hdr->mhdr));
+ sg_set_buf(sg, &hdr->mhdr, sizeof hdr->mhdr);
else
- sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr));
+ sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr);
hdr->num_sg = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
return vi->svq->vq_ops->add_buf(vi->svq, sg, hdr->num_sg, 0, skb);
@@ -529,15 +584,6 @@ again:
}
vi->svq->vq_ops->kick(vi->svq);
- /*
- * Put new one in send queue. You'd expect we'd need this before
- * xmit_skb calls add_buf(), since the callback can be triggered
- * immediately after that. But since the callback just triggers
- * another call back here, normal network xmit locking prevents the
- * race.
- */
- __skb_queue_head(&vi->send, skb);
-
/* Don't wait up for transmitted skbs to be freed. */
skb_orphan(skb);
nf_reset(skb);
@@ -675,6 +721,8 @@ static void virtnet_set_rx_mode(struct net_device *dev)
struct virtio_net_ctrl_mac *mac_data;
struct dev_addr_list *addr;
struct netdev_hw_addr *ha;
+ int uc_count;
+ int mc_count;
void *buf;
int i;
@@ -701,9 +749,12 @@ static void virtnet_set_rx_mode(struct net_device *dev)
dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n",
allmulti ? "en" : "dis");
+ uc_count = netdev_uc_count(dev);
+ mc_count = netdev_mc_count(dev);
/* MAC filter - use one buffer for both lists */
- mac_data = buf = kzalloc(((dev->uc.count + dev->mc_count) * ETH_ALEN) +
- (2 * sizeof(mac_data->entries)), GFP_ATOMIC);
+ buf = kzalloc(((uc_count + mc_count) * ETH_ALEN) +
+ (2 * sizeof(mac_data->entries)), GFP_ATOMIC);
+ mac_data = buf;
if (!buf) {
dev_warn(&dev->dev, "No memory for MAC address buffer\n");
return;
@@ -712,24 +763,24 @@ static void virtnet_set_rx_mode(struct net_device *dev)
sg_init_table(sg, 2);
/* Store the unicast list and count in the front of the buffer */
- mac_data->entries = dev->uc.count;
+ mac_data->entries = uc_count;
i = 0;
- list_for_each_entry(ha, &dev->uc.list, list)
+ netdev_for_each_uc_addr(ha, dev)
memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN);
sg_set_buf(&sg[0], mac_data,
- sizeof(mac_data->entries) + (dev->uc.count * ETH_ALEN));
+ sizeof(mac_data->entries) + (uc_count * ETH_ALEN));
/* multicast list and count fill the end */
- mac_data = (void *)&mac_data->macs[dev->uc.count][0];
+ mac_data = (void *)&mac_data->macs[uc_count][0];
- mac_data->entries = dev->mc_count;
- addr = dev->mc_list;
- for (i = 0; i < dev->mc_count; i++, addr = addr->next)
- memcpy(&mac_data->macs[i][0], addr->da_addr, ETH_ALEN);
+ mac_data->entries = mc_count;
+ i = 0;
+ netdev_for_each_mc_addr(addr, dev)
+ memcpy(&mac_data->macs[i++][0], addr->da_addr, ETH_ALEN);
sg_set_buf(&sg[1], mac_data,
- sizeof(mac_data->entries) + (dev->mc_count * ETH_ALEN));
+ sizeof(mac_data->entries) + (mc_count * ETH_ALEN));
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC,
VIRTIO_NET_CTRL_MAC_TABLE_SET,
@@ -916,10 +967,6 @@ static int virtnet_probe(struct virtio_device *vdev)
dev->features |= NETIF_F_HW_VLAN_FILTER;
}
- /* Initialize our empty receive and send queues. */
- skb_queue_head_init(&vi->recv);
- skb_queue_head_init(&vi->send);
-
err = register_netdev(dev);
if (err) {
pr_debug("virtio_net: registering device failed\n");
@@ -952,26 +999,42 @@ free:
return err;
}
+static void free_unused_bufs(struct virtnet_info *vi)
+{
+ void *buf;
+ while (1) {
+ buf = vi->svq->vq_ops->detach_unused_buf(vi->svq);
+ if (!buf)
+ break;
+ dev_kfree_skb(buf);
+ }
+ while (1) {
+ buf = vi->rvq->vq_ops->detach_unused_buf(vi->rvq);
+ if (!buf)
+ break;
+ if (vi->mergeable_rx_bufs || vi->big_packets)
+ give_pages(vi, buf);
+ else
+ dev_kfree_skb(buf);
+ --vi->num;
+ }
+ BUG_ON(vi->num != 0);
+}
+
static void __devexit virtnet_remove(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
- struct sk_buff *skb;
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
- /* Free our skbs in send and recv queues, if any. */
- while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
- kfree_skb(skb);
- vi->num--;
- }
- __skb_queue_purge(&vi->send);
-
- BUG_ON(vi->num != 0);
unregister_netdev(vi->dev);
cancel_delayed_work_sync(&vi->refill);
+ /* Free unused buffers in both send and recv, if any. */
+ free_unused_bufs(vi);
+
vdev->config->del_vqs(vi->vdev);
while (vi->pages)
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 9cc438282d77..cff3485d9673 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -35,7 +35,7 @@ char vmxnet3_driver_name[] = "vmxnet3";
* PCI Device ID Table
* Last entry must be all 0s
*/
-static const struct pci_device_id vmxnet3_pciid_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(vmxnet3_pciid_table) = {
{PCI_VDEVICE(VMWARE, PCI_DEVICE_ID_VMWARE_VMXNET3)},
{0}
};
@@ -1668,22 +1668,19 @@ static u8 *
vmxnet3_copy_mc(struct net_device *netdev)
{
u8 *buf = NULL;
- u32 sz = netdev->mc_count * ETH_ALEN;
+ u32 sz = netdev_mc_count(netdev) * ETH_ALEN;
/* struct Vmxnet3_RxFilterConf.mfTableLen is u16. */
if (sz <= 0xffff) {
/* We may be called with BH disabled */
buf = kmalloc(sz, GFP_ATOMIC);
if (buf) {
- int i;
- struct dev_mc_list *mc = netdev->mc_list;
+ struct dev_mc_list *mc;
+ int i = 0;
- for (i = 0; i < netdev->mc_count; i++) {
- BUG_ON(!mc);
- memcpy(buf + i * ETH_ALEN, mc->dmi_addr,
+ netdev_for_each_mc_addr(mc, netdev)
+ memcpy(buf + i++ * ETH_ALEN, mc->dmi_addr,
ETH_ALEN);
- mc = mc->next;
- }
}
}
return buf;
@@ -1708,12 +1705,12 @@ vmxnet3_set_mc(struct net_device *netdev)
if (netdev->flags & IFF_ALLMULTI)
new_mode |= VMXNET3_RXM_ALL_MULTI;
else
- if (netdev->mc_count > 0) {
+ if (!netdev_mc_empty(netdev)) {
new_table = vmxnet3_copy_mc(netdev);
if (new_table) {
new_mode |= VMXNET3_RXM_MCAST;
rxConf->mfTableLen = cpu_to_le16(
- netdev->mc_count * ETH_ALEN);
+ netdev_mc_count(netdev) * ETH_ALEN);
rxConf->mfTablePA = cpu_to_le64(virt_to_phys(
new_table));
} else {
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
index b9685e82f7b6..46a7c9e689ec 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -54,7 +54,7 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Neterion's X3100 Series 10GbE PCIe I/O"
"Virtualized Server Adapter");
-static struct pci_device_id vxge_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(vxge_id_table) = {
{PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_WIN, PCI_ANY_ID,
PCI_ANY_ID},
{PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_UNI, PCI_ANY_ID,
@@ -1178,11 +1178,11 @@ static void vxge_set_multicast(struct net_device *dev)
memset(&mac_info, 0, sizeof(struct macInfo));
/* Update individual M_CAST address list */
- if ((!vdev->all_multi_flg) && dev->mc_count) {
+ if ((!vdev->all_multi_flg) && netdev_mc_count(dev)) {
mcast_cnt = vdev->vpaths[0].mcast_addr_cnt;
list_head = &vdev->vpaths[0].mac_addr_list;
- if ((dev->mc_count +
+ if ((netdev_mc_count(dev) +
(vdev->vpaths[0].mac_addr_cnt - mcast_cnt)) >
vdev->vpaths[0].max_mac_addr_cnt)
goto _set_all_mcast;
@@ -1217,9 +1217,7 @@ static void vxge_set_multicast(struct net_device *dev)
}
/* Add new ones */
- for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
- i++, mclist = mclist->next) {
-
+ netdev_for_each_mc_addr(mclist, dev) {
memcpy(mac_info.macaddr, mclist->dmi_addr, ETH_ALEN);
for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath;
vpath_idx++) {
@@ -4297,10 +4295,8 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_debug_init(VXGE_TRACE, "%s: Neterion %s Server Adapter",
vdev->ndev->name, ll_config.device_hw_info.product_desc);
- vxge_debug_init(VXGE_TRACE,
- "%s: MAC ADDR: %02X:%02X:%02X:%02X:%02X:%02X",
- vdev->ndev->name, macaddr[0], macaddr[1], macaddr[2],
- macaddr[3], macaddr[4], macaddr[5]);
+ vxge_debug_init(VXGE_TRACE, "%s: MAC ADDR: %pM",
+ vdev->ndev->name, macaddr);
vxge_debug_init(VXGE_TRACE, "%s: Link Width x%d",
vdev->ndev->name, vxge_hw_device_link_width_get(hldev));
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index b36bf96eb502..f0bd70fb650c 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -811,7 +811,7 @@ static ssize_t cosa_read(struct file *file,
cosa_enable_rx(chan);
spin_lock_irqsave(&cosa->lock, flags);
add_wait_queue(&chan->rxwaitq, &wait);
- while(!chan->rx_status) {
+ while (!chan->rx_status) {
current->state = TASK_INTERRUPTIBLE;
spin_unlock_irqrestore(&cosa->lock, flags);
schedule();
@@ -896,7 +896,7 @@ static ssize_t cosa_write(struct file *file,
spin_lock_irqsave(&cosa->lock, flags);
add_wait_queue(&chan->txwaitq, &wait);
- while(!chan->tx_status) {
+ while (!chan->tx_status) {
current->state = TASK_INTERRUPTIBLE;
spin_unlock_irqrestore(&cosa->lock, flags);
schedule();
@@ -1153,7 +1153,7 @@ static int cosa_ioctl_common(struct cosa_data *cosa,
struct channel_data *channel, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
- switch(cmd) {
+ switch (cmd) {
case COSAIORSET: /* Reset the device */
if (!capable(CAP_NET_ADMIN))
return -EACCES;
@@ -1704,7 +1704,7 @@ static inline void tx_interrupt(struct cosa_data *cosa, int status)
spin_unlock_irqrestore(&cosa->lock, flags);
return;
}
- while(1) {
+ while (1) {
cosa->txchan++;
i++;
if (cosa->txchan >= cosa->nchannels)
@@ -2010,7 +2010,7 @@ again:
static void debug_status_in(struct cosa_data *cosa, int status)
{
char *s;
- switch(status & SR_CMD_FROM_SRP_MASK) {
+ switch (status & SR_CMD_FROM_SRP_MASK) {
case SR_UP_REQUEST:
s = "RX_REQ";
break;
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 3f759daf3ca4..f88c07c13197 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -2050,7 +2050,7 @@ static int __init dscc4_setup(char *str)
__setup("dscc4.setup=", dscc4_setup);
#endif
-static struct pci_device_id dscc4_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(dscc4_pci_tbl) = {
{ PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_DSCC4,
PCI_ANY_ID, PCI_ANY_ID, },
{ 0,}
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 9bc2e3649157..40d724a8e020 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -528,7 +528,7 @@ static int fst_debug_mask = { FST_DEBUG };
/*
* PCI ID lookup table
*/
-static struct pci_device_id fst_pci_dev_id[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(fst_pci_dev_id) = {
{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T2P, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, FST_TYPE_T2P},
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index f1bff98acd1f..1ceccf1ca6c7 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -141,7 +141,7 @@ static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
data->address != CISCO_UNICAST)
return cpu_to_be16(ETH_P_HDLC);
- switch(data->protocol) {
+ switch (data->protocol) {
case cpu_to_be16(ETH_P_IP):
case cpu_to_be16(ETH_P_IPX):
case cpu_to_be16(ETH_P_IPV6):
@@ -190,7 +190,7 @@ static int cisco_rx(struct sk_buff *skb)
cisco_data = (struct cisco_packet*)(skb->data + sizeof
(struct hdlc_header));
- switch(ntohl (cisco_data->type)) {
+ switch (ntohl (cisco_data->type)) {
case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
in_dev = dev->ip_ptr;
addr = 0;
@@ -245,8 +245,8 @@ static int cisco_rx(struct sk_buff *skb)
dev_kfree_skb_any(skb);
return NET_RX_SUCCESS;
- } /* switch(keepalive type) */
- } /* switch(protocol) */
+ } /* switch (keepalive type) */
+ } /* switch (protocol) */
printk(KERN_INFO "%s: Unsupported protocol %x\n", dev->name,
ntohs(data->protocol));
diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
index aa9248f8eb1a..6e1ca256effd 100644
--- a/drivers/net/wan/hdlc_x25.c
+++ b/drivers/net/wan/hdlc_x25.c
@@ -202,10 +202,10 @@ static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
return 0; /* return protocol only, no settable parameters */
case IF_PROTO_X25:
- if(!capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if(dev->flags & IFF_UP)
+ if (dev->flags & IFF_UP)
return -EBUSY;
result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 4b6f27e7c820..b27850377121 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -77,7 +77,7 @@
static int LMC_PKT_BUF_SZ = 1542;
-static struct pci_device_id lmc_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(lmc_pci_tbl) = {
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
PCI_VENDOR_ID_LMC, PCI_ANY_ID },
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index aec4d3955420..f4f1c00d0d23 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -251,7 +251,7 @@ static char rcsid[] =
#undef PC300_DEBUG_RX
#undef PC300_DEBUG_OTHER
-static struct pci_device_id cpc_pci_dev_id[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(cpc_pci_dev_id) = {
/* PC300/RSV or PC300/X21, 2 chan */
{0x120e, 0x300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x300},
/* PC300/RSV or PC300/X21, 1 chan */
diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c
index 60ece54bdd94..c7ab3becd261 100644
--- a/drivers/net/wan/pc300too.c
+++ b/drivers/net/wan/pc300too.c
@@ -481,7 +481,7 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
-static struct pci_device_id pc300_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(pc300_pci_tbl) = {
{ PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_1, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_2, PCI_ANY_ID,
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index f1340faaf022..e2cff64a446a 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -417,7 +417,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
-static struct pci_device_id pci200_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(pci200_pci_tbl) = {
{ 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/wan/wanxl.c b/drivers/net/wan/wanxl.c
index daee8a0624ee..541c700dceef 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -814,7 +814,7 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
return 0;
}
-static struct pci_device_id wanxl_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(wanxl_pci_tbl) = {
{ PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_SBE_WANXL100, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_SBE_WANXL200, PCI_ANY_ID,
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 96a615fe09de..6cead321bc15 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -301,24 +301,15 @@ int i2400m_check_mac_addr(struct i2400m *i2400m)
/* Extract MAC addresss */
ddi = (void *) skb->data;
BUILD_BUG_ON(ETH_ALEN != sizeof(ddi->mac_address));
- d_printf(2, dev, "GET DEVICE INFO: mac addr "
- "%02x:%02x:%02x:%02x:%02x:%02x\n",
- ddi->mac_address[0], ddi->mac_address[1],
- ddi->mac_address[2], ddi->mac_address[3],
- ddi->mac_address[4], ddi->mac_address[5]);
+ d_printf(2, dev, "GET DEVICE INFO: mac addr %pM\n",
+ ddi->mac_address);
if (!memcmp(net_dev->perm_addr, ddi->mac_address,
sizeof(ddi->mac_address)))
goto ok;
dev_warn(dev, "warning: device reports a different MAC address "
"to that of boot mode's\n");
- dev_warn(dev, "device reports %02x:%02x:%02x:%02x:%02x:%02x\n",
- ddi->mac_address[0], ddi->mac_address[1],
- ddi->mac_address[2], ddi->mac_address[3],
- ddi->mac_address[4], ddi->mac_address[5]);
- dev_warn(dev, "boot mode reported %02x:%02x:%02x:%02x:%02x:%02x\n",
- net_dev->perm_addr[0], net_dev->perm_addr[1],
- net_dev->perm_addr[2], net_dev->perm_addr[3],
- net_dev->perm_addr[4], net_dev->perm_addr[5]);
+ dev_warn(dev, "device reports %pM\n", ddi->mac_address);
+ dev_warn(dev, "boot mode reported %pM\n", net_dev->perm_addr);
if (!memcmp(zeromac, ddi->mac_address, sizeof(zeromac)))
dev_err(dev, "device reports an invalid MAC address, "
"not updating\n");
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 64cdfeb299ca..25c24f0368d8 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -612,7 +612,7 @@ ssize_t i2400m_bm_cmd(struct i2400m *i2400m,
goto error_wait_for_ack;
}
rx_bytes = result;
- /* verify the ack and read more if neccessary [result is the
+ /* verify the ack and read more if necessary [result is the
* final amount of bytes we get in the ack] */
result = __i2400m_bm_ack_verify(i2400m, opcode, ack, ack_size, flags);
if (result < 0)
@@ -1041,21 +1041,14 @@ int i2400m_read_mac_addr(struct i2400m *i2400m)
dev_err(dev, "BM: read mac addr failed: %d\n", result);
goto error_read_mac;
}
- d_printf(2, dev,
- "mac addr is %02x:%02x:%02x:%02x:%02x:%02x\n",
- ack_buf.ack_pl[0], ack_buf.ack_pl[1],
- ack_buf.ack_pl[2], ack_buf.ack_pl[3],
- ack_buf.ack_pl[4], ack_buf.ack_pl[5]);
+ d_printf(2, dev, "mac addr is %pM\n", ack_buf.ack_pl);
if (i2400m->bus_bm_mac_addr_impaired == 1) {
ack_buf.ack_pl[0] = 0x00;
ack_buf.ack_pl[1] = 0x16;
ack_buf.ack_pl[2] = 0xd3;
get_random_bytes(&ack_buf.ack_pl[3], 3);
dev_err(dev, "BM is MAC addr impaired, faking MAC addr to "
- "mac addr is %02x:%02x:%02x:%02x:%02x:%02x\n",
- ack_buf.ack_pl[0], ack_buf.ack_pl[1],
- ack_buf.ack_pl[2], ack_buf.ack_pl[3],
- ack_buf.ack_pl[4], ack_buf.ack_pl[5]);
+ "mac addr is %pM\n", ack_buf.ack_pl);
result = 0;
}
net_dev->addr_len = ETH_ALEN;
diff --git a/drivers/net/wimax/i2400m/i2400m-usb.h b/drivers/net/wimax/i2400m/i2400m-usb.h
index 5cc0f279417e..2d7c96d7e865 100644
--- a/drivers/net/wimax/i2400m/i2400m-usb.h
+++ b/drivers/net/wimax/i2400m/i2400m-usb.h
@@ -151,6 +151,7 @@ enum {
/* Device IDs */
USB_DEVICE_ID_I6050 = 0x0186,
+ USB_DEVICE_ID_I6050_2 = 0x0188,
};
@@ -234,6 +235,7 @@ struct i2400mu {
u8 rx_size_auto_shrink;
struct dentry *debugfs_dentry;
+ unsigned i6050:1; /* 1 if this is a 6050 based SKU */
};
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 04df9bbe340f..820b128705ec 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -627,7 +627,7 @@ enum i2400m_bm_cmd_flags {
* @I2400M_BRI_NO_REBOOT: Do not reboot the device and proceed
* directly to wait for a reboot barker from the device.
* @I2400M_BRI_MAC_REINIT: We need to reinitialize the boot
- * rom after reading the MAC adress. This is quite a dirty hack,
+ * rom after reading the MAC address. This is quite a dirty hack,
* if you ask me -- the device requires the bootrom to be
* intialized after reading the MAC address.
*/
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 76a50ac02ebb..14f876b1358b 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -304,7 +304,7 @@ error_kzalloc:
*
* The device will be fully reset internally, but won't be
* disconnected from the bus (so no reenumeration will
- * happen). Firmware upload will be neccessary.
+ * happen). Firmware upload will be necessary.
*
* The device will send a reboot barker that will trigger the driver
* to reinitialize the state via __i2400m_dev_reset_handle.
@@ -314,7 +314,7 @@ error_kzalloc:
*
* The device will be fully reset internally, disconnected from the
* bus an a reenumeration will happen. Firmware upload will be
- * neccessary. Thus, we don't do any locking or struct
+ * necessary. Thus, we don't do any locking or struct
* reinitialization, as we are going to be fully disconnected and
* reenumerated.
*
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 3b48681f8a0d..99f04c475898 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -246,7 +246,7 @@ error_kzalloc:
*
* The device will be fully reset internally, but won't be
* disconnected from the USB bus (so no reenumeration will
- * happen). Firmware upload will be neccessary.
+ * happen). Firmware upload will be necessary.
*
* The device will send a reboot barker in the notification endpoint
* that will trigger the driver to reinitialize the state
@@ -257,7 +257,7 @@ error_kzalloc:
*
* The device will be fully reset internally, disconnected from the
* USB bus an a reenumeration will happen. Firmware upload will be
- * neccessary. Thus, we don't do any locking or struct
+ * necessary. Thus, we don't do any locking or struct
* reinitialization, as we are going to be fully disconnected and
* reenumerated.
*
@@ -478,7 +478,16 @@ int i2400mu_probe(struct usb_interface *iface,
i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack;
i2400m->bus_bm_mac_addr_impaired = 0;
- if (id->idProduct == USB_DEVICE_ID_I6050) {
+ switch (id->idProduct) {
+ case USB_DEVICE_ID_I6050:
+ case USB_DEVICE_ID_I6050_2:
+ i2400mu->i6050 = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (i2400mu->i6050) {
i2400m->bus_fw_names = i2400mu_bus_fw_names_6050;
i2400mu->endpoint_cfg.bulk_out = 0;
i2400mu->endpoint_cfg.notification = 3;
@@ -719,6 +728,7 @@ int i2400mu_post_reset(struct usb_interface *iface)
static
struct usb_device_id i2400mu_id_table[] = {
{ USB_DEVICE(0x8086, USB_DEVICE_ID_I6050) },
+ { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050_2) },
{ USB_DEVICE(0x8086, 0x0181) },
{ USB_DEVICE(0x8086, 0x1403) },
{ USB_DEVICE(0x8086, 0x1405) },
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 56dd6650c97a..588943660755 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -112,6 +112,7 @@ config AIRO_CS
depends on PCMCIA && (BROKEN || !M32R)
select WIRELESS_EXT
select WEXT_SPY
+ select WEXT_PRIV
select CRYPTO
select CRYPTO_AES
---help---
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 39410016b4ff..547912e6843f 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -39,7 +39,7 @@ static unsigned int rx_ring_size __read_mostly = 16;
module_param(tx_ring_size, uint, 0);
module_param(rx_ring_size, uint, 0);
-static struct pci_device_id adm8211_pci_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(adm8211_pci_id_table) = {
/* ADMtek ADM8211 */
{ PCI_DEVICE(0x10B7, 0x6000) }, /* 3Com 3CRSHPW796 */
{ PCI_DEVICE(0x1200, 0x8201) }, /* ? */
@@ -302,18 +302,6 @@ static int adm8211_get_stats(struct ieee80211_hw *dev,
return 0;
}
-static int adm8211_get_tx_stats(struct ieee80211_hw *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct adm8211_priv *priv = dev->priv;
-
- stats[0].len = priv->cur_tx - priv->dirty_tx;
- stats[0].limit = priv->tx_ring_size - 2;
- stats[0].count = priv->dirty_tx;
-
- return 0;
-}
-
static void adm8211_interrupt_tci(struct ieee80211_hw *dev)
{
struct adm8211_priv *priv = dev->priv;
@@ -1400,15 +1388,15 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
}
static int adm8211_add_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct adm8211_priv *priv = dev->priv;
if (priv->mode != NL80211_IFTYPE_MONITOR)
return -EOPNOTSUPP;
- switch (conf->type) {
+ switch (vif->type) {
case NL80211_IFTYPE_STATION:
- priv->mode = conf->type;
+ priv->mode = vif->type;
break;
default:
return -EOPNOTSUPP;
@@ -1416,8 +1404,8 @@ static int adm8211_add_interface(struct ieee80211_hw *dev,
ADM8211_IDLE();
- ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)conf->mac_addr));
- ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(conf->mac_addr + 4)));
+ ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)vif->addr));
+ ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(vif->addr + 4)));
adm8211_update_mode(dev);
@@ -1427,7 +1415,7 @@ static int adm8211_add_interface(struct ieee80211_hw *dev,
}
static void adm8211_remove_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct adm8211_priv *priv = dev->priv;
priv->mode = NL80211_IFTYPE_MONITOR;
@@ -1773,7 +1761,6 @@ static const struct ieee80211_ops adm8211_ops = {
.prepare_multicast = adm8211_prepare_multicast,
.configure_filter = adm8211_configure_filter,
.get_stats = adm8211_get_stats,
- .get_tx_stats = adm8211_get_tx_stats,
.get_tsf = adm8211_get_tsft
};
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 4331d675fcc6..dc5018a6d9ed 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -51,13 +51,14 @@
#include <linux/freezer.h>
#include <linux/ieee80211.h>
+#include <net/iw_handler.h>
#include "airo.h"
#define DRV_NAME "airo"
#ifdef CONFIG_PCI
-static struct pci_device_id card_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(card_ids) = {
{ 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, },
{ 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID },
{ 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, },
@@ -2310,7 +2311,7 @@ static void airo_set_multicast_list(struct net_device *dev) {
airo_set_promisc(ai);
}
- if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) {
+ if ((dev->flags&IFF_ALLMULTI) || !netdev_mc_empty(dev)) {
/* Turn on multicast. (Should be already setup...) */
}
}
@@ -5254,11 +5255,8 @@ static int set_wep_key(struct airo_info *ai, u16 index, const char *key,
WepKeyRid wkr;
int rc;
- if (keylen == 0) {
- airo_print_err(ai->dev->name, "%s: key length to set was zero",
- __func__);
+ if (WARN_ON(keylen == 0))
return -1;
- }
memset(&wkr, 0, sizeof(wkr));
wkr.len = cpu_to_le16(sizeof(wkr));
@@ -6405,11 +6403,7 @@ static int airo_set_encode(struct net_device *dev,
if (dwrq->length > MIN_KEY_SIZE)
key.len = MAX_KEY_SIZE;
else
- if (dwrq->length > 0)
- key.len = MIN_KEY_SIZE;
- else
- /* Disable the key */
- key.len = 0;
+ key.len = MIN_KEY_SIZE;
/* Check if the key is not marked as invalid */
if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
/* Cleanup */
@@ -6590,12 +6584,22 @@ static int airo_set_encodeext(struct net_device *dev,
default:
return -EINVAL;
}
- /* Send the key to the card */
- rc = set_wep_key(local, idx, key.key, key.len, perm, 1);
- if (rc < 0) {
- airo_print_err(local->dev->name, "failed to set WEP key"
- " at index %d: %d.", idx, rc);
- return rc;
+ if (key.len == 0) {
+ rc = set_wep_tx_idx(local, idx, perm, 1);
+ if (rc < 0) {
+ airo_print_err(local->dev->name,
+ "failed to set WEP transmit index to %d: %d.",
+ idx, rc);
+ return rc;
+ }
+ } else {
+ rc = set_wep_key(local, idx, key.key, key.len, perm, 1);
+ if (rc < 0) {
+ airo_print_err(local->dev->name,
+ "failed to set WEP key at index %d: %d.",
+ idx, rc);
+ return rc;
+ }
}
}
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 2517364d3ebe..0fb419936dff 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1789,7 +1789,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw)
}
static int at76_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct at76_priv *priv = hw->priv;
int ret = 0;
@@ -1798,7 +1798,7 @@ static int at76_add_interface(struct ieee80211_hw *hw,
mutex_lock(&priv->mtx);
- switch (conf->type) {
+ switch (vif->type) {
case NL80211_IFTYPE_STATION:
priv->iw_mode = IW_MODE_INFRA;
break;
@@ -1814,7 +1814,7 @@ exit:
}
static void at76_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
at76_dbg(DBG_MAC80211, "%s()", __func__);
}
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index 9f9459860d82..dc662b76a1c8 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -109,7 +109,6 @@ struct ar9170_rxstream_mpdu_merge {
bool has_plcp;
};
-#define AR9170_NUM_MAX_BA_RETRY 5
#define AR9170_NUM_TID 16
#define WME_BA_BMP_SIZE 64
#define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE)
@@ -143,7 +142,12 @@ struct ar9170_sta_tid {
u16 tid;
enum ar9170_tid_state state;
bool active;
- u8 retry;
+};
+
+struct ar9170_tx_queue_stats {
+ unsigned int len;
+ unsigned int limit;
+ unsigned int count;
};
#define AR9170_QUEUE_TIMEOUT 64
@@ -154,12 +158,15 @@ struct ar9170_sta_tid {
#define AR9170_NUM_TX_STATUS 128
#define AR9170_NUM_TX_AGG_MAX 30
+#define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH
+#define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10)
struct ar9170 {
struct ieee80211_hw *hw;
struct ath_common common;
struct mutex mutex;
enum ar9170_device_state state;
+ bool registered;
unsigned long bad_hw_nagger;
int (*open)(struct ar9170 *);
@@ -211,7 +218,7 @@ struct ar9170 {
/* qos queue settings */
spinlock_t tx_stats_lock;
- struct ieee80211_tx_queue_stats tx_stats[5];
+ struct ar9170_tx_queue_stats tx_stats[5];
struct ieee80211_tx_queue_params edcf[5];
spinlock_t cmdlock;
@@ -248,13 +255,8 @@ struct ar9170_sta_info {
unsigned int ampdu_max_len;
};
-#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0)
-#define AR9170_TX_FLAG_NO_ACK BIT(1)
-#define AR9170_TX_FLAG_BLOCK_ACK BIT(2)
-
struct ar9170_tx_info {
unsigned long timeout;
- unsigned int flags;
};
#define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED)
diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h
index 701ddb7d8400..0a1d4c28e68a 100644
--- a/drivers/net/wireless/ath/ar9170/hw.h
+++ b/drivers/net/wireless/ath/ar9170/hw.h
@@ -276,6 +276,7 @@ struct ar9170_tx_control {
#define AR9170_TX_MAC_RATE_PROBE 0x8000
/* either-or */
+#define AR9170_TX_PHY_MOD_MASK 0x00000003
#define AR9170_TX_PHY_MOD_CCK 0x00000000
#define AR9170_TX_PHY_MOD_OFDM 0x00000001
#define AR9170_TX_PHY_MOD_HT 0x00000002
diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c
index ddc8c09dc79e..857e86104295 100644
--- a/drivers/net/wireless/ath/ar9170/mac.c
+++ b/drivers/net/wireless/ath/ar9170/mac.c
@@ -117,7 +117,7 @@ int ar9170_set_qos(struct ar9170 *ar)
ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP,
ar->edcf[0].txop | ar->edcf[1].txop << 16);
ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP,
- ar->edcf[1].txop | ar->edcf[3].txop << 16);
+ ar->edcf[2].txop | ar->edcf[3].txop << 16);
ar9170_regwrite_finish();
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index f9d6db8d013e..257c734733d1 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -194,12 +194,15 @@ static inline u16 ar9170_get_seq(struct sk_buff *skb)
return ar9170_get_seq_h((void *) txc->frame_data);
}
+static inline u16 ar9170_get_tid_h(struct ieee80211_hdr *hdr)
+{
+ return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
static inline u16 ar9170_get_tid(struct sk_buff *skb)
{
struct ar9170_tx_control *txc = (void *) skb->data;
- struct ieee80211_hdr *hdr = (void *) txc->frame_data;
-
- return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+ return ar9170_get_tid_h((struct ieee80211_hdr *) txc->frame_data);
}
#define GET_NEXT_SEQ(seq) ((seq + 1) & 0x0fff)
@@ -213,10 +216,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
struct ieee80211_hdr *hdr = (void *) txc->frame_data;
- printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d "
+ printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] s:%d "
"mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
- ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr),
+ ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr),
le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
jiffies_to_msecs(arinfo->timeout - jiffies));
}
@@ -391,7 +394,7 @@ static void ar9170_tx_fake_ampdu_status(struct ar9170 *ar)
ieee80211_tx_status_irqsafe(ar->hw, skb);
}
- for_each_bit(i, &queue_bitmap, BITS_PER_BYTE) {
+ for_each_set_bit(i, &queue_bitmap, BITS_PER_BYTE) {
#ifdef AR9170_QUEUE_STOP_DEBUG
printk(KERN_DEBUG "%s: wake queue %d\n",
wiphy_name(ar->hw->wiphy), i);
@@ -430,7 +433,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
spin_lock_irqsave(&ar->tx_stats_lock, flags);
ar->tx_stats[queue].len--;
- if (skb_queue_empty(&ar->tx_pending[queue])) {
+ if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) {
#ifdef AR9170_QUEUE_STOP_DEBUG
printk(KERN_DEBUG "%s: wake queue %d\n",
wiphy_name(ar->hw->wiphy), queue);
@@ -440,22 +443,17 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
}
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
- if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) {
- ar9170_tx_ampdu_callback(ar, skb);
- } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) {
- arinfo->timeout = jiffies +
- msecs_to_jiffies(AR9170_TX_TIMEOUT);
-
- skb_queue_tail(&ar->tx_status[queue], skb);
- } else if (arinfo->flags & AR9170_TX_FLAG_NO_ACK) {
+ if (info->flags & IEEE80211_TX_CTL_NO_ACK) {
ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED);
} else {
-#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: unsupported frame flags!\n",
- wiphy_name(ar->hw->wiphy));
- ar9170_print_txheader(ar, skb);
-#endif /* AR9170_QUEUE_DEBUG */
- dev_kfree_skb_any(skb);
+ if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+ ar9170_tx_ampdu_callback(ar, skb);
+ } else {
+ arinfo->timeout = jiffies +
+ msecs_to_jiffies(AR9170_TX_TIMEOUT);
+
+ skb_queue_tail(&ar->tx_status[queue], skb);
+ }
}
if (!ar->tx_stats[queue].len &&
@@ -1407,17 +1405,6 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
(is_valid_ether_addr(ieee80211_get_DA(hdr)))) {
- if (info->flags & IEEE80211_TX_CTL_AMPDU) {
- if (unlikely(!info->control.sta))
- goto err_out;
-
- txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
- arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK;
-
- goto out;
- }
-
- txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
/*
* WARNING:
* Putting the QoS queue bits into an unexplored territory is
@@ -1431,12 +1418,17 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
txc->phy_control |=
cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT);
- arinfo->flags = AR9170_TX_FLAG_WAIT_FOR_ACK;
- } else {
- arinfo->flags = AR9170_TX_FLAG_NO_ACK;
+
+ if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+ if (unlikely(!info->control.sta))
+ goto err_out;
+
+ txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
+ } else {
+ txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
+ }
}
-out:
return 0;
err_out:
@@ -1671,8 +1663,7 @@ static bool ar9170_tx_ampdu(struct ar9170 *ar)
* tell the FW/HW that this is the last frame,
* that way it will wait for the immediate block ack.
*/
- if (likely(skb_peek_tail(&agg)))
- ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
+ ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
#ifdef AR9170_TXAGG_DEBUG
printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
@@ -1716,6 +1707,21 @@ static void ar9170_tx(struct ar9170 *ar)
for (i = 0; i < __AR9170_NUM_TXQ; i++) {
spin_lock_irqsave(&ar->tx_stats_lock, flags);
+ frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len,
+ skb_queue_len(&ar->tx_pending[i]));
+
+ if (remaining_space < frames) {
+#ifdef AR9170_QUEUE_DEBUG
+ printk(KERN_DEBUG "%s: tx quota reached queue:%d, "
+ "remaining slots:%d, needed:%d\n",
+ wiphy_name(ar->hw->wiphy), i, remaining_space,
+ frames);
+#endif /* AR9170_QUEUE_DEBUG */
+ frames = remaining_space;
+ }
+
+ ar->tx_stats[i].len += frames;
+ ar->tx_stats[i].count += frames;
if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) {
#ifdef AR9170_QUEUE_DEBUG
printk(KERN_DEBUG "%s: queue %d full\n",
@@ -1733,25 +1739,8 @@ static void ar9170_tx(struct ar9170 *ar)
__ar9170_dump_txstats(ar);
#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_stop_queue(ar->hw, i);
- spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
- continue;
}
- frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len,
- skb_queue_len(&ar->tx_pending[i]));
-
- if (remaining_space < frames) {
-#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: tx quota reached queue:%d, "
- "remaining slots:%d, needed:%d\n",
- wiphy_name(ar->hw->wiphy), i, remaining_space,
- frames);
-#endif /* AR9170_QUEUE_DEBUG */
- frames = remaining_space;
- }
-
- ar->tx_stats[i].len += frames;
- ar->tx_stats[i].count += frames;
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
if (!frames)
@@ -1773,7 +1762,7 @@ static void ar9170_tx(struct ar9170 *ar)
arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT);
- if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
atomic_inc(&ar->tx_ampdu_pending);
#ifdef AR9170_QUEUE_DEBUG
@@ -1784,7 +1773,7 @@ static void ar9170_tx(struct ar9170 *ar)
err = ar->tx(ar, skb);
if (unlikely(err)) {
- if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
atomic_dec(&ar->tx_ampdu_pending);
frames_failed++;
@@ -1950,7 +1939,7 @@ err_free:
}
static int ar9170_op_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct ar9170 *ar = hw->priv;
struct ath_common *common = &ar->common;
@@ -1963,8 +1952,8 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw,
goto unlock;
}
- ar->vif = conf->vif;
- memcpy(common->macaddr, conf->mac_addr, ETH_ALEN);
+ ar->vif = vif;
+ memcpy(common->macaddr, vif->addr, ETH_ALEN);
if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) {
ar->rx_software_decryption = true;
@@ -1984,7 +1973,7 @@ unlock:
}
static void ar9170_op_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct ar9170 *ar = hw->priv;
@@ -2340,55 +2329,55 @@ out:
return err;
}
-static void ar9170_sta_notify(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- enum sta_notify_cmd cmd,
- struct ieee80211_sta *sta)
+static int ar9170_sta_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
{
struct ar9170 *ar = hw->priv;
struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
unsigned int i;
- switch (cmd) {
- case STA_NOTIFY_ADD:
- memset(sta_info, 0, sizeof(*sta_info));
+ memset(sta_info, 0, sizeof(*sta_info));
- if (!sta->ht_cap.ht_supported)
- break;
+ if (!sta->ht_cap.ht_supported)
+ return 0;
- if (sta->ht_cap.ampdu_density > ar->global_ampdu_density)
- ar->global_ampdu_density = sta->ht_cap.ampdu_density;
+ if (sta->ht_cap.ampdu_density > ar->global_ampdu_density)
+ ar->global_ampdu_density = sta->ht_cap.ampdu_density;
- if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor)
- ar->global_ampdu_factor = sta->ht_cap.ampdu_factor;
+ if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor)
+ ar->global_ampdu_factor = sta->ht_cap.ampdu_factor;
- for (i = 0; i < AR9170_NUM_TID; i++) {
- sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
- sta_info->agg[i].active = false;
- sta_info->agg[i].ssn = 0;
- sta_info->agg[i].retry = 0;
- sta_info->agg[i].tid = i;
- INIT_LIST_HEAD(&sta_info->agg[i].list);
- skb_queue_head_init(&sta_info->agg[i].queue);
- }
+ for (i = 0; i < AR9170_NUM_TID; i++) {
+ sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
+ sta_info->agg[i].active = false;
+ sta_info->agg[i].ssn = 0;
+ sta_info->agg[i].tid = i;
+ INIT_LIST_HEAD(&sta_info->agg[i].list);
+ skb_queue_head_init(&sta_info->agg[i].queue);
+ }
- sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
- break;
+ sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
- case STA_NOTIFY_REMOVE:
- if (!sta->ht_cap.ht_supported)
- break;
+ return 0;
+}
- for (i = 0; i < AR9170_NUM_TID; i++) {
- sta_info->agg[i].state = AR9170_TID_STATE_INVALID;
- skb_queue_purge(&sta_info->agg[i].queue);
- }
+static int ar9170_sta_remove(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
+ unsigned int i;
- break;
+ if (!sta->ht_cap.ht_supported)
+ return 0;
- default:
- break;
+ for (i = 0; i < AR9170_NUM_TID; i++) {
+ sta_info->agg[i].state = AR9170_TID_STATE_INVALID;
+ skb_queue_purge(&sta_info->agg[i].queue);
}
+
+ return 0;
}
static int ar9170_get_stats(struct ieee80211_hw *hw,
@@ -2408,18 +2397,6 @@ static int ar9170_get_stats(struct ieee80211_hw *hw,
return 0;
}
-static int ar9170_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *tx_stats)
-{
- struct ar9170 *ar = hw->priv;
-
- spin_lock_bh(&ar->tx_stats_lock);
- memcpy(tx_stats, ar->tx_stats, sizeof(tx_stats[0]) * hw->queues);
- spin_unlock_bh(&ar->tx_stats_lock);
-
- return 0;
-}
-
static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *param)
{
@@ -2519,9 +2496,9 @@ static const struct ieee80211_ops ar9170_ops = {
.bss_info_changed = ar9170_op_bss_info_changed,
.get_tsf = ar9170_op_get_tsf,
.set_key = ar9170_set_key,
- .sta_notify = ar9170_sta_notify,
+ .sta_add = ar9170_sta_add,
+ .sta_remove = ar9170_sta_remove,
.get_stats = ar9170_get_stats,
- .get_tx_stats = ar9170_get_tx_stats,
.ampdu_action = ar9170_ampdu_action,
};
@@ -2535,7 +2512,7 @@ void *ar9170_alloc(size_t priv_size)
/*
* this buffer is used for rx stream reconstruction.
* Under heavy load this device (or the transport layer?)
- * tends to split the streams into seperate rx descriptors.
+ * tends to split the streams into separate rx descriptors.
*/
skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE, GFP_KERNEL);
@@ -2724,7 +2701,8 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev)
dev_info(pdev, "Atheros AR9170 is registered as '%s'\n",
wiphy_name(ar->hw->wiphy));
- return err;
+ ar->registered = true;
+ return 0;
err_unreg:
ieee80211_unregister_hw(ar->hw);
@@ -2735,11 +2713,14 @@ err_out:
void ar9170_unregister(struct ar9170 *ar)
{
+ if (ar->registered) {
#ifdef CONFIG_AR9170_LEDS
- ar9170_unregister_leds(ar);
+ ar9170_unregister_leds(ar);
#endif /* CONFIG_AR9170_LEDS */
- kfree_skb(ar->rx_failover);
ieee80211_unregister_hw(ar->hw);
+ }
+
+ kfree_skb(ar->rx_failover);
mutex_destroy(&ar->mutex);
}
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index e0799d924057..4e30197afff6 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -84,6 +84,8 @@ static struct usb_device_id ar9170_usb_ids[] = {
{ USB_DEVICE(0x0cde, 0x0023) },
/* Z-Com UB82 ABG */
{ USB_DEVICE(0x0cde, 0x0026) },
+ /* Sphairon Homelink 1202 */
+ { USB_DEVICE(0x0cde, 0x0027) },
/* Arcadyan WN7512 */
{ USB_DEVICE(0x083a, 0xf522) },
/* Planex GWUS300 */
@@ -580,43 +582,6 @@ static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data,
return 0;
}
-static int ar9170_usb_request_firmware(struct ar9170_usb *aru)
-{
- int err = 0;
-
- err = request_firmware(&aru->firmware, "ar9170.fw",
- &aru->udev->dev);
- if (!err) {
- aru->init_values = NULL;
- return 0;
- }
-
- if (aru->req_one_stage_fw) {
- dev_err(&aru->udev->dev, "ar9170.fw firmware file "
- "not found and is required for this device\n");
- return -EINVAL;
- }
-
- dev_err(&aru->udev->dev, "ar9170.fw firmware file "
- "not found, trying old firmware...\n");
-
- err = request_firmware(&aru->init_values, "ar9170-1.fw",
- &aru->udev->dev);
- if (err) {
- dev_err(&aru->udev->dev, "file with init values not found.\n");
- return err;
- }
-
- err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev);
- if (err) {
- release_firmware(aru->init_values);
- dev_err(&aru->udev->dev, "firmware file not found.\n");
- return err;
- }
-
- return err;
-}
-
static int ar9170_usb_reset(struct ar9170_usb *aru)
{
int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING);
@@ -755,6 +720,103 @@ err_out:
return err;
}
+static void ar9170_usb_firmware_failed(struct ar9170_usb *aru)
+{
+ struct device *parent = aru->udev->dev.parent;
+
+ /* unbind anything failed */
+ if (parent)
+ down(&parent->sem);
+ device_release_driver(&aru->udev->dev);
+ if (parent)
+ up(&parent->sem);
+}
+
+static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context)
+{
+ struct ar9170_usb *aru = context;
+ int err;
+
+ aru->firmware = fw;
+
+ if (!fw) {
+ dev_err(&aru->udev->dev, "firmware file not found.\n");
+ goto err_freefw;
+ }
+
+ err = ar9170_usb_init_device(aru);
+ if (err)
+ goto err_freefw;
+
+ err = ar9170_usb_open(&aru->common);
+ if (err)
+ goto err_unrx;
+
+ err = ar9170_register(&aru->common, &aru->udev->dev);
+
+ ar9170_usb_stop(&aru->common);
+ if (err)
+ goto err_unrx;
+
+ return;
+
+ err_unrx:
+ ar9170_usb_cancel_urbs(aru);
+
+ err_freefw:
+ ar9170_usb_firmware_failed(aru);
+}
+
+static void ar9170_usb_firmware_inits(const struct firmware *fw,
+ void *context)
+{
+ struct ar9170_usb *aru = context;
+ int err;
+
+ if (!fw) {
+ dev_err(&aru->udev->dev, "file with init values not found.\n");
+ ar9170_usb_firmware_failed(aru);
+ return;
+ }
+
+ aru->init_values = fw;
+
+ /* ok so we have the init values -- get code for two-stage */
+
+ err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-2.fw",
+ &aru->udev->dev, GFP_KERNEL, aru,
+ ar9170_usb_firmware_finish);
+ if (err)
+ ar9170_usb_firmware_failed(aru);
+}
+
+static void ar9170_usb_firmware_step2(const struct firmware *fw, void *context)
+{
+ struct ar9170_usb *aru = context;
+ int err;
+
+ if (fw) {
+ ar9170_usb_firmware_finish(fw, context);
+ return;
+ }
+
+ if (aru->req_one_stage_fw) {
+ dev_err(&aru->udev->dev, "ar9170.fw firmware file "
+ "not found and is required for this device\n");
+ ar9170_usb_firmware_failed(aru);
+ return;
+ }
+
+ dev_err(&aru->udev->dev, "ar9170.fw firmware file "
+ "not found, trying old firmware...\n");
+
+ err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-1.fw",
+ &aru->udev->dev, GFP_KERNEL, aru,
+ ar9170_usb_firmware_inits);
+ if (err)
+ ar9170_usb_firmware_failed(aru);
+}
+
static bool ar9170_requires_one_stage(const struct usb_device_id *id)
{
if (!id->driver_info)
@@ -812,33 +874,9 @@ static int ar9170_usb_probe(struct usb_interface *intf,
if (err)
goto err_freehw;
- err = ar9170_usb_request_firmware(aru);
- if (err)
- goto err_freehw;
-
- err = ar9170_usb_init_device(aru);
- if (err)
- goto err_freefw;
-
- err = ar9170_usb_open(ar);
- if (err)
- goto err_unrx;
-
- err = ar9170_register(ar, &udev->dev);
-
- ar9170_usb_stop(ar);
- if (err)
- goto err_unrx;
-
- return 0;
-
-err_unrx:
- ar9170_usb_cancel_urbs(aru);
-
-err_freefw:
- release_firmware(aru->init_values);
- release_firmware(aru->firmware);
-
+ return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw",
+ &aru->udev->dev, GFP_KERNEL, aru,
+ ar9170_usb_firmware_step2);
err_freehw:
usb_set_intfdata(intf, NULL);
usb_put_dev(udev);
@@ -858,12 +896,12 @@ static void ar9170_usb_disconnect(struct usb_interface *intf)
ar9170_unregister(&aru->common);
ar9170_usb_cancel_urbs(aru);
- release_firmware(aru->init_values);
- release_firmware(aru->firmware);
-
usb_put_dev(aru->udev);
usb_set_intfdata(intf, NULL);
ieee80211_free_hw(aru->common.hw);
+
+ release_firmware(aru->init_values);
+ release_firmware(aru->firmware);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 9e05648356fe..71fc960814f0 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -74,7 +74,6 @@ struct ath_common;
struct ath_bus_ops {
void (*read_cachesize)(struct ath_common *common, int *csz);
- void (*cleanup)(struct ath_common *common);
bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
void (*bt_coex_prep)(struct ath_common *common);
};
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 6a2a96761111..ac67f02e26d8 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -535,13 +535,12 @@ struct ath5k_txq_info {
u32 tqi_cbr_period; /* Constant bit rate period */
u32 tqi_cbr_overflow_limit;
u32 tqi_burst_time;
- u32 tqi_ready_time; /* Not used */
+ u32 tqi_ready_time; /* Time queue waits after an event */
};
/*
* Transmit packet types.
* used on tx control descriptor
- * TODO: Use them inside base.c corectly
*/
enum ath5k_pkt_type {
AR5K_PKT_TYPE_NORMAL = 0,
@@ -1063,6 +1062,7 @@ struct ath5k_hw {
u32 ah_cw_min;
u32 ah_cw_max;
u32 ah_limit_tx_retries;
+ u8 ah_coverage_class;
/* Antenna Control */
u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
@@ -1200,6 +1200,7 @@ extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah);
/* Protocol Control Unit Functions */
extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
+extern void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class);
/* BSSID Functions */
extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
extern void ath5k_hw_set_associd(struct ath5k_hw *ah);
@@ -1231,6 +1232,10 @@ extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout);
extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah);
extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout);
extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah);
+/* Clock rate related functions */
+unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec);
+unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock);
+unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah);
/* Key table (WEP) functions */
extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry);
@@ -1310,24 +1315,6 @@ extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower);
* Functions used internaly
*/
-/*
- * Translate usec to hw clock units
- * TODO: Half/quarter rate
- */
-static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
-{
- return turbo ? (usec * 80) : (usec * 40);
-}
-
-/*
- * Translate hw clock units to usec
- * TODO: Half/quarter rate
- */
-static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
-{
- return turbo ? (clock / 80) : (clock / 40);
-}
-
static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah)
{
return &ah->common;
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index e63b7c40d0ee..8dce0077b023 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -83,7 +83,7 @@ MODULE_VERSION("0.6.0 (EXPERIMENTAL)");
/* Known PCI ids */
-static const struct pci_device_id ath5k_pci_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = {
{ PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */
{ PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */
{ PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/
@@ -225,9 +225,9 @@ static int ath5k_reset_wake(struct ath5k_softc *sc);
static int ath5k_start(struct ieee80211_hw *hw);
static void ath5k_stop(struct ieee80211_hw *hw);
static int ath5k_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf);
+ struct ieee80211_vif *vif);
static void ath5k_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf);
+ struct ieee80211_vif *vif);
static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
int mc_count, struct dev_addr_list *mc_list);
@@ -241,8 +241,6 @@ static int ath5k_set_key(struct ieee80211_hw *hw,
struct ieee80211_key_conf *key);
static int ath5k_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats);
-static int ath5k_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *stats);
static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf);
static void ath5k_reset_tsf(struct ieee80211_hw *hw);
@@ -254,6 +252,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
u32 changes);
static void ath5k_sw_scan_start(struct ieee80211_hw *hw);
static void ath5k_sw_scan_complete(struct ieee80211_hw *hw);
+static void ath5k_set_coverage_class(struct ieee80211_hw *hw,
+ u8 coverage_class);
static const struct ieee80211_ops ath5k_hw_ops = {
.tx = ath5k_tx,
@@ -267,13 +267,13 @@ static const struct ieee80211_ops ath5k_hw_ops = {
.set_key = ath5k_set_key,
.get_stats = ath5k_get_stats,
.conf_tx = NULL,
- .get_tx_stats = ath5k_get_tx_stats,
.get_tsf = ath5k_get_tsf,
.set_tsf = ath5k_set_tsf,
.reset_tsf = ath5k_reset_tsf,
.bss_info_changed = ath5k_bss_info_changed,
.sw_scan_start = ath5k_sw_scan_start,
.sw_scan_complete = ath5k_sw_scan_complete,
+ .set_coverage_class = ath5k_set_coverage_class,
};
/*
@@ -1246,6 +1246,29 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
return 0;
}
+static enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr;
+ enum ath5k_pkt_type htype;
+ __le16 fc;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+
+ if (ieee80211_is_beacon(fc))
+ htype = AR5K_PKT_TYPE_BEACON;
+ else if (ieee80211_is_probe_resp(fc))
+ htype = AR5K_PKT_TYPE_PROBE_RESP;
+ else if (ieee80211_is_atim(fc))
+ htype = AR5K_PKT_TYPE_ATIM;
+ else if (ieee80211_is_pspoll(fc))
+ htype = AR5K_PKT_TYPE_PSPOLL;
+ else
+ htype = AR5K_PKT_TYPE_NORMAL;
+
+ return htype;
+}
+
static int
ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
struct ath5k_txq *txq)
@@ -1300,7 +1323,8 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
sc->vif, pktlen, info));
}
ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
- ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
+ ieee80211_get_hdrlen_from_skb(skb),
+ get_hw_packet_type(skb),
(sc->power_level * 2),
hw_rate,
info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags,
@@ -1329,7 +1353,6 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
spin_lock_bh(&txq->lock);
list_add_tail(&bf->list, &txq->q);
- sc->tx_stats[txq->qnum].len++;
if (txq->link == NULL) /* is this first packet? */
ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr);
else /* no, so only link it */
@@ -1513,7 +1536,8 @@ ath5k_beaconq_config(struct ath5k_softc *sc)
ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi);
if (ret)
- return ret;
+ goto err;
+
if (sc->opmode == NL80211_IFTYPE_AP ||
sc->opmode == NL80211_IFTYPE_MESH_POINT) {
/*
@@ -1540,10 +1564,25 @@ ath5k_beaconq_config(struct ath5k_softc *sc)
if (ret) {
ATH5K_ERR(sc, "%s: unable to update parameters for beacon "
"hardware queue!\n", __func__);
- return ret;
+ goto err;
}
+ ret = ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */
+ if (ret)
+ goto err;
+
+ /* reconfigure cabq with ready time to 80% of beacon_interval */
+ ret = ath5k_hw_get_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi);
+ if (ret)
+ goto err;
+
+ qi.tqi_ready_time = (sc->bintval * 80) / 100;
+ ret = ath5k_hw_set_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi);
+ if (ret)
+ goto err;
- return ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */;
+ ret = ath5k_hw_reset_tx_queue(ah, AR5K_TX_QUEUE_ID_CAB);
+err:
+ return ret;
}
static void
@@ -1562,7 +1601,6 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
ath5k_txbuf_free(sc, bf);
spin_lock_bh(&sc->txbuflock);
- sc->tx_stats[txq->qnum].len--;
list_move_tail(&bf->list, &sc->txbuf);
sc->txbuf_len++;
spin_unlock_bh(&sc->txbuflock);
@@ -1992,10 +2030,8 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
}
ieee80211_tx_status(sc->hw, skb);
- sc->tx_stats[txq->qnum].count++;
spin_lock(&sc->txbuflock);
- sc->tx_stats[txq->qnum].len--;
list_move_tail(&bf->list, &sc->txbuf);
sc->txbuf_len++;
spin_unlock(&sc->txbuflock);
@@ -2773,7 +2809,7 @@ static void ath5k_stop(struct ieee80211_hw *hw)
}
static int ath5k_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct ath5k_softc *sc = hw->priv;
int ret;
@@ -2784,22 +2820,22 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
goto end;
}
- sc->vif = conf->vif;
+ sc->vif = vif;
- switch (conf->type) {
+ switch (vif->type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_MONITOR:
- sc->opmode = conf->type;
+ sc->opmode = vif->type;
break;
default:
ret = -EOPNOTSUPP;
goto end;
}
- ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
+ ath5k_hw_set_lladdr(sc->ah, vif->addr);
ath5k_mode_setup(sc);
ret = 0;
@@ -2810,13 +2846,13 @@ end:
static void
ath5k_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct ath5k_softc *sc = hw->priv;
u8 mac[ETH_ALEN] = {};
mutex_lock(&sc->lock);
- if (sc->vif != conf->vif)
+ if (sc->vif != vif)
goto end;
ath5k_hw_set_lladdr(sc->ah, mac);
@@ -3097,17 +3133,6 @@ ath5k_get_stats(struct ieee80211_hw *hw,
return 0;
}
-static int
-ath5k_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct ath5k_softc *sc = hw->priv;
-
- memcpy(stats, &sc->tx_stats, sizeof(sc->tx_stats));
-
- return 0;
-}
-
static u64
ath5k_get_tsf(struct ieee80211_hw *hw)
{
@@ -3262,3 +3287,22 @@ static void ath5k_sw_scan_complete(struct ieee80211_hw *hw)
ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
AR5K_LED_ASSOC : AR5K_LED_INIT);
}
+
+/**
+ * ath5k_set_coverage_class - Set IEEE 802.11 coverage class
+ *
+ * @hw: struct ieee80211_hw pointer
+ * @coverage_class: IEEE 802.11 coverage class number
+ *
+ * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given
+ * coverage class. The values are persistent, they are restored after device
+ * reset.
+ */
+static void ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
+{
+ struct ath5k_softc *sc = hw->priv;
+
+ mutex_lock(&sc->lock);
+ ath5k_hw_set_coverage_class(sc->ah, coverage_class);
+ mutex_unlock(&sc->lock);
+}
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 952b3a21bbc3..7e1a88a5abdb 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -117,7 +117,6 @@ struct ath5k_softc {
struct pci_dev *pdev; /* for dma mapping */
void __iomem *iobase; /* address of the device */
struct mutex lock; /* dev-level lock */
- struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES];
struct ieee80211_low_level_stats ll_stats;
struct ieee80211_hw *hw; /* IEEE 802.11 common */
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index 6a3f4da7fb48..10b52262b232 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -429,8 +429,8 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
AR5K_EEPROM_READ(o++, val);
- ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
- ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+ ee->ee_i_cal[mode] = (val >> 5) & 0x3f;
+ ee->ee_q_cal[mode] = val & 0x1f;
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
AR5K_EEPROM_READ(o++, val);
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index 60f547503d75..67aa52e9bf94 100644
--- a/drivers/net/wireless/ath/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -77,6 +77,8 @@ static const struct pci_device_id ath5k_led_devices[] = {
{ ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137a), ATH_LED(3, 1) },
/* HP Compaq C700 (nitrousnrg@gmail.com) */
{ ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 1) },
+ /* LiteOn AR5BXB63 (magooz@salug.it) */
+ { ATH_SDEVICE(PCI_VENDOR_ID_ATHEROS, 0x3067), ATH_LED(3, 0) },
/* IBM-specific AR5212 (all others) */
{ PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) },
/* Dell Vostro A860 (shahar@shahar-or.co.il) */
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index 64fc1eb9b6d9..aefe84f9c04b 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -187,8 +187,8 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
{
ATH5K_TRACE(ah->ah_sc);
- return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
- AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo);
+ return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah,
+ AR5K_TIME_OUT), AR5K_TIME_OUT_ACK));
}
/**
@@ -200,12 +200,12 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
{
ATH5K_TRACE(ah->ah_sc);
- if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK),
- ah->ah_turbo) <= timeout)
+ if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK))
+ <= timeout)
return -EINVAL;
AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
- ath5k_hw_htoclock(timeout, ah->ah_turbo));
+ ath5k_hw_htoclock(ah, timeout));
return 0;
}
@@ -218,8 +218,8 @@ int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
{
ATH5K_TRACE(ah->ah_sc);
- return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
- AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo);
+ return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah,
+ AR5K_TIME_OUT), AR5K_TIME_OUT_CTS));
}
/**
@@ -231,17 +231,97 @@ unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
{
ATH5K_TRACE(ah->ah_sc);
- if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS),
- ah->ah_turbo) <= timeout)
+ if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS))
+ <= timeout)
return -EINVAL;
AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
- ath5k_hw_htoclock(timeout, ah->ah_turbo));
+ ath5k_hw_htoclock(ah, timeout));
return 0;
}
/**
+ * ath5k_hw_htoclock - Translate usec to hw clock units
+ *
+ * @ah: The &struct ath5k_hw
+ * @usec: value in microseconds
+ */
+unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
+{
+ return usec * ath5k_hw_get_clockrate(ah);
+}
+
+/**
+ * ath5k_hw_clocktoh - Translate hw clock units to usec
+ * @clock: value in hw clock units
+ */
+unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
+{
+ return clock / ath5k_hw_get_clockrate(ah);
+}
+
+/**
+ * ath5k_hw_get_clockrate - Get the clock rate for current mode
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah)
+{
+ struct ieee80211_channel *channel = ah->ah_current_channel;
+ int clock;
+
+ if (channel->hw_value & CHANNEL_5GHZ)
+ clock = 40; /* 802.11a */
+ else if (channel->hw_value & CHANNEL_CCK)
+ clock = 22; /* 802.11b */
+ else
+ clock = 44; /* 802.11g */
+
+ /* Clock rate in turbo modes is twice the normal rate */
+ if (channel->hw_value & CHANNEL_TURBO)
+ clock *= 2;
+
+ return clock;
+}
+
+/**
+ * ath5k_hw_get_default_slottime - Get the default slot time for current mode
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
+{
+ struct ieee80211_channel *channel = ah->ah_current_channel;
+
+ if (channel->hw_value & CHANNEL_TURBO)
+ return 6; /* both turbo modes */
+
+ if (channel->hw_value & CHANNEL_CCK)
+ return 20; /* 802.11b */
+
+ return 9; /* 802.11 a/g */
+}
+
+/**
+ * ath5k_hw_get_default_sifs - Get the default SIFS for current mode
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
+{
+ struct ieee80211_channel *channel = ah->ah_current_channel;
+
+ if (channel->hw_value & CHANNEL_TURBO)
+ return 8; /* both turbo modes */
+
+ if (channel->hw_value & CHANNEL_5GHZ)
+ return 16; /* 802.11a */
+
+ return 10; /* 802.11 b/g */
+}
+
+/**
* ath5k_hw_set_lladdr - Set station id
*
* @ah: The &struct ath5k_hw
@@ -1050,3 +1130,24 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
return 0;
}
+/**
+ * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class
+ *
+ * @ah: The &struct ath5k_hw
+ * @coverage_class: IEEE 802.11 coverage class number
+ *
+ * Sets slot time, ACK timeout and CTS timeout for given coverage class.
+ */
+void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
+{
+ /* As defined by IEEE 802.11-2007 17.3.8.6 */
+ int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class;
+ int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time;
+ int cts_timeout = ack_timeout;
+
+ ath5k_hw_set_slot_time(ah, slot_time);
+ ath5k_hw_set_ack_timeout(ah, ack_timeout);
+ ath5k_hw_set_cts_timeout(ah, cts_timeout);
+
+ ah->ah_coverage_class = coverage_class;
+}
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 72474c0ccaff..eff3323efb4b 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1386,38 +1386,39 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
goto done;
/* Calibration has finished, get the results and re-run */
+
+ /* work around empty results which can apparently happen on 5212 */
for (i = 0; i <= 10; i++) {
iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
+ ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+ "iq_corr:%x i_pwr:%x q_pwr:%x", iq_corr, i_pwr, q_pwr);
+ if (i_pwr && q_pwr)
+ break;
}
i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
q_coffd = q_pwr >> 7;
- /* No correction */
- if (i_coffd == 0 || q_coffd == 0)
+ /* protect against divide by 0 and loss of sign bits */
+ if (i_coffd == 0 || q_coffd < 2)
goto done;
- i_coff = ((-iq_corr) / i_coffd);
-
- /* Boundary check */
- if (i_coff > 31)
- i_coff = 31;
- if (i_coff < -32)
- i_coff = -32;
+ i_coff = (-iq_corr) / i_coffd;
+ i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */
- q_coff = (((s32)i_pwr / q_coffd) - 128);
+ q_coff = (i_pwr / q_coffd) - 128;
+ q_coff = clamp(q_coff, -16, 15); /* signed 5 bit */
- /* Boundary check */
- if (q_coff > 15)
- q_coff = 15;
- if (q_coff < -16)
- q_coff = -16;
+ ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+ "new I:%d Q:%d (i_coffd:%x q_coffd:%x)",
+ i_coff, q_coff, i_coffd, q_coffd);
- /* Commit new I/Q value */
- AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE |
- ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
+ /* Commit new I/Q values (set enable bit last to match HAL sources) */
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_I_COFF, i_coff);
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_Q_COFF, q_coff);
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE);
/* Re-enable calibration -if we don't we'll commit
* the same values again and again */
@@ -1873,7 +1874,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
break;
case AR5K_ANTMODE_FIXED_A:
def_ant = 1;
- tx_ant = 0;
+ tx_ant = 1;
use_def_for_tx = true;
update_def_on_tx = false;
use_def_for_rts = true;
@@ -1882,7 +1883,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
break;
case AR5K_ANTMODE_FIXED_B:
def_ant = 2;
- tx_ant = 0;
+ tx_ant = 2;
use_def_for_tx = true;
update_def_on_tx = false;
use_def_for_rts = true;
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index eeebb9aef206..9122a8556f45 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -408,12 +408,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
break;
case AR5K_TX_QUEUE_CAB:
+ /* XXX: use BCN_SENT_GT, if we can figure out how */
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
- AR5K_QCU_MISC_FRSHED_BCN_SENT_GT |
+ AR5K_QCU_MISC_FRSHED_DBA_GT |
AR5K_QCU_MISC_CBREXP_DIS |
AR5K_QCU_MISC_CBREXP_BCN_DIS);
- ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
+ ath5k_hw_reg_write(ah, ((tq->tqi_ready_time -
(AR5K_TUNE_SW_BEACON_RESP -
AR5K_TUNE_DMA_BEACON_RESP) -
AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
@@ -520,12 +521,16 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
*/
unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah)
{
+ unsigned int slot_time_clock;
+
ATH5K_TRACE(ah->ah_sc);
+
if (ah->ah_version == AR5K_AR5210)
- return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah,
- AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo);
+ slot_time_clock = ath5k_hw_reg_read(ah, AR5K_SLOT_TIME);
else
- return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff;
+ slot_time_clock = ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT);
+
+ return ath5k_hw_clocktoh(ah, slot_time_clock & 0xffff);
}
/*
@@ -533,15 +538,17 @@ unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah)
*/
int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
{
+ u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
+
ATH5K_TRACE(ah->ah_sc);
- if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
+
+ if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
return -EINVAL;
if (ah->ah_version == AR5K_AR5210)
- ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
- ah->ah_turbo), AR5K_SLOT_TIME);
+ ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
else
- ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
+ ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);
return 0;
}
diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h
index 4cb9c5df9f46..1464f89b249c 100644
--- a/drivers/net/wireless/ath/ath5k/reg.h
+++ b/drivers/net/wireless/ath/ath5k/reg.h
@@ -2187,6 +2187,7 @@
*/
#define AR5K_PHY_IQ 0x9920 /* Register Address */
#define AR5K_PHY_IQ_CORR_Q_Q_COFF 0x0000001f /* Mask for q correction info */
+#define AR5K_PHY_IQ_CORR_Q_Q_COFF_S 0
#define AR5K_PHY_IQ_CORR_Q_I_COFF 0x000007e0 /* Mask for i correction info */
#define AR5K_PHY_IQ_CORR_Q_I_COFF_S 5
#define AR5K_PHY_IQ_CORR_ENABLE 0x00000800 /* Enable i/q correction */
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 62954fc77869..cbf28e379843 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -60,12 +60,11 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
!(channel->hw_value & CHANNEL_OFDM));
/* Get coefficient
- * ALGO: coef = (5 * clock * carrier_freq) / 2)
+ * ALGO: coef = (5 * clock / carrier_freq) / 2
* we scale coef by shifting clock value by 24 for
* better precision since we use integers */
/* TODO: Half/quarter rate */
- clock = ath5k_hw_htoclock(1, channel->hw_value & CHANNEL_TURBO);
-
+ clock = (channel->hw_value & CHANNEL_TURBO) ? 80 : 40;
coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq;
/* Get exponent
@@ -852,12 +851,15 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
AR5K_INIT_CYCRSSI_THR1);
- /* I/Q correction
- * TODO: Per channel i/q infos ? */
- AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
- AR5K_PHY_IQ_CORR_ENABLE |
- (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) |
- ee->ee_q_cal[ee_mode]);
+ /* I/Q correction (set enable bit last to match HAL sources) */
+ /* TODO: Per channel i/q infos ? */
+ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_I_COFF,
+ ee->ee_i_cal[ee_mode]);
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_Q_COFF,
+ ee->ee_q_cal[ee_mode]);
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE);
+ }
/* Heavy clipping -disable for now */
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1)
@@ -1317,6 +1319,10 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
/* Restore antenna mode */
ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
+ /* Restore slot time and ACK timeouts */
+ if (ah->ah_coverage_class > 0)
+ ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class);
+
/*
* Configure QCUs/DCUs
*/
@@ -1371,15 +1377,15 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
* Set clocks to 32KHz operation and use an
* external 32KHz crystal when sleeping if one
* exists */
- if (ah->ah_version == AR5K_AR5212)
- ath5k_hw_set_sleep_clock(ah, true);
+ if (ah->ah_version == AR5K_AR5212 &&
+ ah->ah_op_mode != NL80211_IFTYPE_AP)
+ ath5k_hw_set_sleep_clock(ah, true);
/*
- * Disable beacons and reset the register
+ * Disable beacons and reset the TSF
*/
- AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE |
- AR5K_BEACON_RESET_TSF);
-
+ AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
+ ath5k_hw_reset_tsf(ah);
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 4985b2b1b0a9..6b50d5eb9ec3 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -1,4 +1,6 @@
ath9k-y += beacon.o \
+ gpio.o \
+ init.o \
main.o \
recv.o \
xmit.o \
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 329e6bc137ab..ca4994f13151 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -27,12 +27,6 @@ static void ath_ahb_read_cachesize(struct ath_common *common, int *csz)
*csz = L1_CACHE_BYTES >> 2;
}
-static void ath_ahb_cleanup(struct ath_common *common)
-{
- struct ath_softc *sc = (struct ath_softc *)common->priv;
- iounmap(sc->mem);
-}
-
static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{
struct ath_softc *sc = (struct ath_softc *)common->priv;
@@ -54,8 +48,6 @@ static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
static struct ath_bus_ops ath_ahb_bus_ops = {
.read_cachesize = ath_ahb_read_cachesize,
- .cleanup = ath_ahb_cleanup,
-
.eeprom_read = ath_ahb_eeprom_read,
};
@@ -121,16 +113,19 @@ static int ath_ahb_probe(struct platform_device *pdev)
sc->mem = mem;
sc->irq = irq;
- ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops);
+ /* Will be cleared in ath9k_start() */
+ sc->sc_flags |= SC_OP_INVALID;
+
+ ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
if (ret) {
- dev_err(&pdev->dev, "failed to initialize device\n");
+ dev_err(&pdev->dev, "request_irq failed\n");
goto err_free_hw;
}
- ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
+ ret = ath9k_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops);
if (ret) {
- dev_err(&pdev->dev, "request_irq failed\n");
- goto err_detach;
+ dev_err(&pdev->dev, "failed to initialize device\n");
+ goto err_irq;
}
ah = sc->sc_ah;
@@ -143,8 +138,8 @@ static int ath_ahb_probe(struct platform_device *pdev)
return 0;
- err_detach:
- ath_detach(sc);
+ err_irq:
+ free_irq(irq, sc);
err_free_hw:
ieee80211_free_hw(hw);
platform_set_drvdata(pdev, NULL);
@@ -161,8 +156,12 @@ static int ath_ahb_remove(struct platform_device *pdev)
if (hw) {
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ void __iomem *mem = sc->mem;
- ath_cleanup(sc);
+ ath9k_deinit_device(sc);
+ free_irq(sc->irq, sc);
+ ieee80211_free_hw(sc->hw);
+ iounmap(mem);
platform_set_drvdata(pdev, NULL);
}
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 1597a42731ed..83c7ea4c007f 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -267,6 +267,7 @@ void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn);
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+void ath9k_enable_ps(struct ath_softc *sc);
/********/
/* VIFs */
@@ -341,6 +342,12 @@ int ath_beaconq_config(struct ath_softc *sc);
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
+void ath_ani_calibrate(unsigned long data);
+
+/**********/
+/* BTCOEX */
+/**********/
+
/* Defines the BT AR_BT_COEX_WGHT used */
enum ath_stomp_type {
ATH_BTCOEX_NO_STOMP,
@@ -358,9 +365,14 @@ struct ath_btcoex {
int bt_stomp_type; /* Types of BT stomping */
u32 btcoex_no_stomp; /* in usec */
u32 btcoex_period; /* in usec */
+ u32 btscan_no_stomp; /* in usec */
struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
};
+int ath_init_btcoex_timer(struct ath_softc *sc);
+void ath9k_btcoex_timer_resume(struct ath_softc *sc);
+void ath9k_btcoex_timer_pause(struct ath_softc *sc);
+
/********************/
/* LED Control */
/********************/
@@ -385,6 +397,9 @@ struct ath_led {
bool registered;
};
+void ath_init_leds(struct ath_softc *sc);
+void ath_deinit_leds(struct ath_softc *sc);
+
/********************/
/* Main driver core */
/********************/
@@ -403,26 +418,29 @@ struct ath_led {
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
#define ATH_RATE_DUMMY_MARKER 0
-#define SC_OP_INVALID BIT(0)
-#define SC_OP_BEACONS BIT(1)
-#define SC_OP_RXAGGR BIT(2)
-#define SC_OP_TXAGGR BIT(3)
-#define SC_OP_FULL_RESET BIT(4)
-#define SC_OP_PREAMBLE_SHORT BIT(5)
-#define SC_OP_PROTECT_ENABLE BIT(6)
-#define SC_OP_RXFLUSH BIT(7)
-#define SC_OP_LED_ASSOCIATED BIT(8)
-#define SC_OP_WAIT_FOR_BEACON BIT(12)
-#define SC_OP_LED_ON BIT(13)
-#define SC_OP_SCANNING BIT(14)
-#define SC_OP_TSF_RESET BIT(15)
-#define SC_OP_WAIT_FOR_CAB BIT(16)
-#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17)
-#define SC_OP_WAIT_FOR_TX_ACK BIT(18)
-#define SC_OP_BEACON_SYNC BIT(19)
-#define SC_OP_BT_PRIORITY_DETECTED BIT(21)
-#define SC_OP_NULLFUNC_COMPLETED BIT(22)
-#define SC_OP_PS_ENABLED BIT(23)
+#define SC_OP_INVALID BIT(0)
+#define SC_OP_BEACONS BIT(1)
+#define SC_OP_RXAGGR BIT(2)
+#define SC_OP_TXAGGR BIT(3)
+#define SC_OP_FULL_RESET BIT(4)
+#define SC_OP_PREAMBLE_SHORT BIT(5)
+#define SC_OP_PROTECT_ENABLE BIT(6)
+#define SC_OP_RXFLUSH BIT(7)
+#define SC_OP_LED_ASSOCIATED BIT(8)
+#define SC_OP_LED_ON BIT(9)
+#define SC_OP_SCANNING BIT(10)
+#define SC_OP_TSF_RESET BIT(11)
+#define SC_OP_BT_PRIORITY_DETECTED BIT(12)
+#define SC_OP_BT_SCAN BIT(13)
+
+/* Powersave flags */
+#define PS_WAIT_FOR_BEACON BIT(0)
+#define PS_WAIT_FOR_CAB BIT(1)
+#define PS_WAIT_FOR_PSPOLL_DATA BIT(2)
+#define PS_WAIT_FOR_TX_ACK BIT(3)
+#define PS_BEACON_SYNC BIT(4)
+#define PS_NULLFUNC_COMPLETED BIT(5)
+#define PS_ENABLED BIT(6)
struct ath_wiphy;
struct ath_rate_table;
@@ -453,16 +471,17 @@ struct ath_softc {
int irq;
spinlock_t sc_resetlock;
spinlock_t sc_serial_rw;
- spinlock_t ani_lock;
spinlock_t sc_pm_lock;
struct mutex mutex;
u32 intrstatus;
u32 sc_flags; /* SC_OP_* */
+ u16 ps_flags; /* PS_* */
u16 curtxpow;
u8 nbcnvifs;
u16 nvifs;
bool ps_enabled;
+ bool ps_idle;
unsigned long ps_usecount;
enum ath9k_int imask;
@@ -509,6 +528,7 @@ struct ath_wiphy {
int chan_is_ht;
};
+void ath9k_tasklet(unsigned long data);
int ath_reset(struct ath_softc *sc, bool retry_tx);
int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
@@ -519,21 +539,16 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
common->bus_ops->read_cachesize(common, csz);
}
-static inline void ath_bus_cleanup(struct ath_common *common)
-{
- common->bus_ops->cleanup(common);
-}
-
extern struct ieee80211_ops ath9k_ops;
+extern int modparam_nohwcrypt;
irqreturn_t ath_isr(int irq, void *dev);
-void ath_cleanup(struct ath_softc *sc);
-int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
const struct ath_bus_ops *bus_ops);
-void ath_detach(struct ath_softc *sc);
+void ath9k_deinit_device(struct ath_softc *sc);
const char *ath_mac_bb_name(u32 mac_bb_version);
const char *ath_rf_name(u16 rf_version);
-void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
+void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
struct ath9k_channel *ichan);
void ath_update_chainmask(struct ath_softc *sc, int is_ht);
@@ -542,6 +557,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw);
void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
+bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode);
#ifdef CONFIG_PCI
int ath_pci_init(void);
@@ -583,4 +599,8 @@ void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue);
void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
+
+void ath_start_rfkill_poll(struct ath_softc *sc);
+extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
+
#endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 1660ef17aaf5..b4a31a43a62c 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -62,7 +62,7 @@ int ath_beaconq_config(struct ath_softc *sc)
* Beacons are always sent out at the lowest rate, and are not retried.
*/
static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
- struct ath_buf *bf)
+ struct ath_buf *bf, int rateidx)
{
struct sk_buff *skb = bf->bf_mpdu;
struct ath_hw *ah = sc->sc_ah;
@@ -96,9 +96,9 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
ds->ds_data = bf->bf_buf_addr;
sband = &sc->sbands[common->hw->conf.channel->band];
- rate = sband->bitrates[0].hw_value;
+ rate = sband->bitrates[rateidx].hw_value;
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
- rate |= sband->bitrates[0].hw_value_short;
+ rate |= sband->bitrates[rateidx].hw_value_short;
ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN,
ATH9K_PKT_TYPE_BEACON,
@@ -206,7 +206,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
}
}
- ath_beacon_setup(sc, avp, bf);
+ ath_beacon_setup(sc, avp, bf, info->control.rates[0].idx);
while (skb) {
ath_tx_cabq(hw, skb);
@@ -237,7 +237,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc,
bf = avp->av_bcbuf;
skb = bf->bf_mpdu;
- ath_beacon_setup(sc, avp, bf);
+ ath_beacon_setup(sc, avp, bf, 0);
/* NB: caller is known to have already stopped tx dma */
ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
@@ -480,7 +480,8 @@ void ath_beacon_tasklet(unsigned long data)
sc->beacon.updateslot = COMMIT; /* commit next beacon */
sc->beacon.slotupdate = slot;
} else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) {
- ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime);
+ ah->slottime = sc->beacon.slottime;
+ ath9k_hw_init_global_settings(ah);
sc->beacon.updateslot = OK;
}
if (bfaddr != 0) {
@@ -525,16 +526,13 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
{
u32 nexttbtt, intval;
- /* Configure the timers only when the TSF has to be reset */
-
- if (!(sc->sc_flags & SC_OP_TSF_RESET))
- return;
-
/* NB: the beacon interval is kept internally in TU's */
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
intval /= ATH_BCBUF; /* for staggered beacons */
nexttbtt = intval;
- intval |= ATH9K_BEACON_RESET_TSF;
+
+ if (sc->sc_flags & SC_OP_TSF_RESET)
+ intval |= ATH9K_BEACON_RESET_TSF;
/*
* In AP mode we enable the beacon timers and SWBA interrupts to
@@ -576,6 +574,13 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
u64 tsf;
int num_beacons, offset, dtim_dec_count, cfp_dec_count;
+ /* No need to configure beacon if we are not associated */
+ if (!common->curaid) {
+ ath_print(common, ATH_DBG_BEACON,
+ "STA is not yet associated..skipping beacon config\n");
+ return;
+ }
+
memset(&bs, 0, sizeof(bs));
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
@@ -738,7 +743,6 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
enum nl80211_iftype iftype;
/* Setup the beacon configuration parameters */
-
if (vif) {
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index 1ba31a73317c..1ee5a15ccbb1 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -25,10 +25,12 @@
#define ATH_BTCOEX_DEF_BT_PERIOD 45
#define ATH_BTCOEX_DEF_DUTY_CYCLE 55
+#define ATH_BTCOEX_BTSCAN_DUTY_CYCLE 90
#define ATH_BTCOEX_BMISS_THRESH 50
#define ATH_BT_PRIORITY_TIME_THRESHOLD 1000 /* ms */
#define ATH_BT_CNT_THRESHOLD 3
+#define ATH_BT_CNT_SCAN_THRESHOLD 15
enum ath_btcoex_scheme {
ATH_BTCOEX_CFG_NONE,
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index b66f72dbf7b9..42d2a506845a 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -75,17 +75,24 @@ static const struct file_operations fops_debug = {
#endif
+#define DMA_BUF_LEN 1024
+
static ssize_t read_file_dma(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
struct ath_hw *ah = sc->sc_ah;
- char buf[1024];
+ char *buf;
+ int retval;
unsigned int len = 0;
u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
int i, qcuOffset = 0, dcuOffset = 0;
u32 *qcuBase = &val[0], *dcuBase = &val[4];
+ buf = kmalloc(DMA_BUF_LEN, GFP_KERNEL);
+ if (!buf)
+ return 0;
+
ath9k_ps_wakeup(sc);
REG_WRITE_D(ah, AR_MACMISC,
@@ -93,20 +100,20 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
(AR_MACMISC_MISC_OBS_BUS_1 <<
AR_MACMISC_MISC_OBS_BUS_MSB_S)));
- len += snprintf(buf + len, sizeof(buf) - len,
+ len += snprintf(buf + len, DMA_BUF_LEN - len,
"Raw DMA Debug values:\n");
for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
if (i % 4 == 0)
- len += snprintf(buf + len, sizeof(buf) - len, "\n");
+ len += snprintf(buf + len, DMA_BUF_LEN - len, "\n");
val[i] = REG_READ_D(ah, AR_DMADBG_0 + (i * sizeof(u32)));
- len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ",
+ len += snprintf(buf + len, DMA_BUF_LEN - len, "%d: %08x ",
i, val[i]);
}
- len += snprintf(buf + len, sizeof(buf) - len, "\n\n");
- len += snprintf(buf + len, sizeof(buf) - len,
+ len += snprintf(buf + len, DMA_BUF_LEN - len, "\n\n");
+ len += snprintf(buf + len, DMA_BUF_LEN - len,
"Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) {
@@ -120,7 +127,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
dcuBase++;
}
- len += snprintf(buf + len, sizeof(buf) - len,
+ len += snprintf(buf + len, DMA_BUF_LEN - len,
"%2d %2x %1x %2x %2x\n",
i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
(*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3),
@@ -128,35 +135,37 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
(*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
}
- len += snprintf(buf + len, sizeof(buf) - len, "\n");
+ len += snprintf(buf + len, DMA_BUF_LEN - len, "\n");
- len += snprintf(buf + len, sizeof(buf) - len,
+ len += snprintf(buf + len, DMA_BUF_LEN - len,
"qcu_stitch state: %2x qcu_fetch state: %2x\n",
(val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
- len += snprintf(buf + len, sizeof(buf) - len,
+ len += snprintf(buf + len, DMA_BUF_LEN - len,
"qcu_complete state: %2x dcu_complete state: %2x\n",
(val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
- len += snprintf(buf + len, sizeof(buf) - len,
+ len += snprintf(buf + len, DMA_BUF_LEN - len,
"dcu_arb state: %2x dcu_fp state: %2x\n",
(val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
- len += snprintf(buf + len, sizeof(buf) - len,
+ len += snprintf(buf + len, DMA_BUF_LEN - len,
"chan_idle_dur: %3d chan_idle_dur_valid: %1d\n",
(val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
- len += snprintf(buf + len, sizeof(buf) - len,
+ len += snprintf(buf + len, DMA_BUF_LEN - len,
"txfifo_valid_0: %1d txfifo_valid_1: %1d\n",
(val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
- len += snprintf(buf + len, sizeof(buf) - len,
+ len += snprintf(buf + len, DMA_BUF_LEN - len,
"txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n",
(val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
- len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n",
+ len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x \n",
REG_READ_D(ah, AR_OBS_BUS_1));
- len += snprintf(buf + len, sizeof(buf) - len,
+ len += snprintf(buf + len, DMA_BUF_LEN - len,
"AR_CR: 0x%x \n", REG_READ_D(ah, AR_CR));
ath9k_ps_restore(sc);
- return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+ return retval;
}
static const struct file_operations fops_dma = {
@@ -289,23 +298,49 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
if (sc->cur_rate_table == NULL)
return 0;
- max = 80 + sc->cur_rate_table->rate_cnt * 64;
+ max = 80 + sc->cur_rate_table->rate_cnt * 1024;
buf = kmalloc(max + 1, GFP_KERNEL);
if (buf == NULL)
return 0;
buf[max] = 0;
- len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success",
- "Retries", "XRetries", "PER");
+ len += sprintf(buf, "%6s %6s %6s "
+ "%10s %10s %10s %10s\n",
+ "HT", "MCS", "Rate",
+ "Success", "Retries", "XRetries", "PER");
for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) {
u32 ratekbps = sc->cur_rate_table->info[i].ratekbps;
struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i];
+ char mcs[5];
+ char htmode[5];
+ int used_mcs = 0, used_htmode = 0;
+
+ if (WLAN_RC_PHY_HT(sc->cur_rate_table->info[i].phy)) {
+ used_mcs = snprintf(mcs, 5, "%d",
+ sc->cur_rate_table->info[i].ratecode);
+
+ if (WLAN_RC_PHY_40(sc->cur_rate_table->info[i].phy))
+ used_htmode = snprintf(htmode, 5, "HT40");
+ else if (WLAN_RC_PHY_20(sc->cur_rate_table->info[i].phy))
+ used_htmode = snprintf(htmode, 5, "HT20");
+ else
+ used_htmode = snprintf(htmode, 5, "????");
+ }
+
+ mcs[used_mcs] = '\0';
+ htmode[used_htmode] = '\0';
len += snprintf(buf + len, max - len,
- "%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000,
- (ratekbps % 1000) / 100, stats->success,
- stats->retries, stats->xretries,
+ "%6s %6s %3u.%d: "
+ "%10u %10u %10u %10u\n",
+ htmode,
+ mcs,
+ ratekbps / 1000,
+ (ratekbps % 1000) / 100,
+ stats->success,
+ stats->retries,
+ stats->xretries,
stats->per);
}
@@ -554,6 +589,116 @@ static const struct file_operations fops_xmit = {
.owner = THIS_MODULE
};
+static ssize_t read_file_recv(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+#define PHY_ERR(s, p) \
+ len += snprintf(buf + len, size - len, "%18s : %10u\n", s, \
+ sc->debug.stats.rxstats.phy_err_stats[p]);
+
+ struct ath_softc *sc = file->private_data;
+ char *buf;
+ unsigned int len = 0, size = 1152;
+ ssize_t retval = 0;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return 0;
+
+ len += snprintf(buf + len, size - len,
+ "%18s : %10u\n", "CRC ERR",
+ sc->debug.stats.rxstats.crc_err);
+ len += snprintf(buf + len, size - len,
+ "%18s : %10u\n", "DECRYPT CRC ERR",
+ sc->debug.stats.rxstats.decrypt_crc_err);
+ len += snprintf(buf + len, size - len,
+ "%18s : %10u\n", "PHY ERR",
+ sc->debug.stats.rxstats.phy_err);
+ len += snprintf(buf + len, size - len,
+ "%18s : %10u\n", "MIC ERR",
+ sc->debug.stats.rxstats.mic_err);
+ len += snprintf(buf + len, size - len,
+ "%18s : %10u\n", "PRE-DELIM CRC ERR",
+ sc->debug.stats.rxstats.pre_delim_crc_err);
+ len += snprintf(buf + len, size - len,
+ "%18s : %10u\n", "POST-DELIM CRC ERR",
+ sc->debug.stats.rxstats.post_delim_crc_err);
+ len += snprintf(buf + len, size - len,
+ "%18s : %10u\n", "DECRYPT BUSY ERR",
+ sc->debug.stats.rxstats.decrypt_busy_err);
+
+ PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
+ PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
+ PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
+ PHY_ERR("RATE", ATH9K_PHYERR_RATE);
+ PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH);
+ PHY_ERR("RADAR", ATH9K_PHYERR_RADAR);
+ PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE);
+ PHY_ERR("TOR", ATH9K_PHYERR_TOR);
+ PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING);
+ PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
+ PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
+ PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
+ PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP);
+ PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE);
+ PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART);
+ PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT);
+ PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING);
+ PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC);
+ PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
+ PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE);
+ PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART);
+ PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
+ PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP);
+ PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR);
+ PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
+ PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+
+#undef PHY_ERR
+}
+
+void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf)
+{
+#define RX_STAT_INC(c) sc->debug.stats.rxstats.c++
+#define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++
+
+ struct ath_desc *ds = bf->bf_desc;
+ u32 phyerr;
+
+ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
+ RX_STAT_INC(crc_err);
+ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT)
+ RX_STAT_INC(decrypt_crc_err);
+ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC)
+ RX_STAT_INC(mic_err);
+ if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_PRE)
+ RX_STAT_INC(pre_delim_crc_err);
+ if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_POST)
+ RX_STAT_INC(post_delim_crc_err);
+ if (ds->ds_rxstat.rs_status & ATH9K_RX_DECRYPT_BUSY)
+ RX_STAT_INC(decrypt_busy_err);
+
+ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) {
+ RX_STAT_INC(phy_err);
+ phyerr = ds->ds_rxstat.rs_phyerr & 0x24;
+ RX_PHY_ERR_INC(phyerr);
+ }
+
+#undef RX_STAT_INC
+#undef RX_PHY_ERR_INC
+}
+
+static const struct file_operations fops_recv = {
+ .read = read_file_recv,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE
+};
+
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
@@ -606,6 +751,13 @@ int ath9k_init_debug(struct ath_hw *ah)
if (!sc->debug.debugfs_xmit)
goto err;
+ sc->debug.debugfs_recv = debugfs_create_file("recv",
+ S_IRUSR,
+ sc->debug.debugfs_phy,
+ sc, &fops_recv);
+ if (!sc->debug.debugfs_recv)
+ goto err;
+
return 0;
err:
ath9k_exit_debug(ah);
@@ -617,6 +769,7 @@ void ath9k_exit_debug(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
struct ath_softc *sc = (struct ath_softc *) common->priv;
+ debugfs_remove(sc->debug.debugfs_recv);
debugfs_remove(sc->debug.debugfs_xmit);
debugfs_remove(sc->debug.debugfs_wiphy);
debugfs_remove(sc->debug.debugfs_rcstat);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 536663e3ee11..86780e68b31e 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -116,10 +116,35 @@ struct ath_tx_stats {
u32 delim_underrun;
};
+/**
+ * struct ath_rx_stats - RX Statistics
+ * @crc_err: No. of frames with incorrect CRC value
+ * @decrypt_crc_err: No. of frames whose CRC check failed after
+ decryption process completed
+ * @phy_err: No. of frames whose reception failed because the PHY
+ encountered an error
+ * @mic_err: No. of frames with incorrect TKIP MIC verification failure
+ * @pre_delim_crc_err: Pre-Frame delimiter CRC error detections
+ * @post_delim_crc_err: Post-Frame delimiter CRC error detections
+ * @decrypt_busy_err: Decryption interruptions counter
+ * @phy_err_stats: Individual PHY error statistics
+ */
+struct ath_rx_stats {
+ u32 crc_err;
+ u32 decrypt_crc_err;
+ u32 phy_err;
+ u32 mic_err;
+ u32 pre_delim_crc_err;
+ u32 post_delim_crc_err;
+ u32 decrypt_busy_err;
+ u32 phy_err_stats[ATH9K_PHYERR_MAX];
+};
+
struct ath_stats {
struct ath_interrupt_stats istats;
struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
+ struct ath_rx_stats rxstats;
};
struct ath9k_debug {
@@ -130,6 +155,7 @@ struct ath9k_debug {
struct dentry *debugfs_rcstat;
struct dentry *debugfs_wiphy;
struct dentry *debugfs_xmit;
+ struct dentry *debugfs_recv;
struct ath_stats stats;
};
@@ -142,6 +168,7 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
void ath_debug_stat_rc(struct ath_softc *sc, int final_rate);
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf);
+void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf);
void ath_debug_stat_retries(struct ath_softc *sc, int rix,
int xretries, int retries, u8 per);
@@ -181,6 +208,11 @@ static inline void ath_debug_stat_tx(struct ath_softc *sc,
{
}
+static inline void ath_debug_stat_rx(struct ath_softc *sc,
+ struct ath_buf *bf)
+{
+}
+
static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix,
int xretries, int retries, u8 per)
{
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
new file mode 100644
index 000000000000..deab8beb0680
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+
+/********************************/
+/* LED functions */
+/********************************/
+
+static void ath_led_blink_work(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ ath_led_blink_work.work);
+
+ if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED))
+ return;
+
+ if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
+ (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
+ else
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
+ (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
+
+ ieee80211_queue_delayed_work(sc->hw,
+ &sc->ath_led_blink_work,
+ (sc->sc_flags & SC_OP_LED_ON) ?
+ msecs_to_jiffies(sc->led_off_duration) :
+ msecs_to_jiffies(sc->led_on_duration));
+
+ sc->led_on_duration = sc->led_on_cnt ?
+ max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) :
+ ATH_LED_ON_DURATION_IDLE;
+ sc->led_off_duration = sc->led_off_cnt ?
+ max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) :
+ ATH_LED_OFF_DURATION_IDLE;
+ sc->led_on_cnt = sc->led_off_cnt = 0;
+ if (sc->sc_flags & SC_OP_LED_ON)
+ sc->sc_flags &= ~SC_OP_LED_ON;
+ else
+ sc->sc_flags |= SC_OP_LED_ON;
+}
+
+static void ath_led_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
+ struct ath_softc *sc = led->sc;
+
+ switch (brightness) {
+ case LED_OFF:
+ if (led->led_type == ATH_LED_ASSOC ||
+ led->led_type == ATH_LED_RADIO) {
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
+ (led->led_type == ATH_LED_RADIO));
+ sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
+ if (led->led_type == ATH_LED_RADIO)
+ sc->sc_flags &= ~SC_OP_LED_ON;
+ } else {
+ sc->led_off_cnt++;
+ }
+ break;
+ case LED_FULL:
+ if (led->led_type == ATH_LED_ASSOC) {
+ sc->sc_flags |= SC_OP_LED_ASSOCIATED;
+ ieee80211_queue_delayed_work(sc->hw,
+ &sc->ath_led_blink_work, 0);
+ } else if (led->led_type == ATH_LED_RADIO) {
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
+ sc->sc_flags |= SC_OP_LED_ON;
+ } else {
+ sc->led_on_cnt++;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
+ char *trigger)
+{
+ int ret;
+
+ led->sc = sc;
+ led->led_cdev.name = led->name;
+ led->led_cdev.default_trigger = trigger;
+ led->led_cdev.brightness_set = ath_led_brightness;
+
+ ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
+ if (ret)
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Failed to register led:%s", led->name);
+ else
+ led->registered = 1;
+ return ret;
+}
+
+static void ath_unregister_led(struct ath_led *led)
+{
+ if (led->registered) {
+ led_classdev_unregister(&led->led_cdev);
+ led->registered = 0;
+ }
+}
+
+void ath_deinit_leds(struct ath_softc *sc)
+{
+ ath_unregister_led(&sc->assoc_led);
+ sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
+ ath_unregister_led(&sc->tx_led);
+ ath_unregister_led(&sc->rx_led);
+ ath_unregister_led(&sc->radio_led);
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
+}
+
+void ath_init_leds(struct ath_softc *sc)
+{
+ char *trigger;
+ int ret;
+
+ if (AR_SREV_9287(sc->sc_ah))
+ sc->sc_ah->led_pin = ATH_LED_PIN_9287;
+ else
+ sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
+
+ /* Configure gpio 1 for output */
+ ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ /* LED off, active low */
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
+
+ INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
+
+ trigger = ieee80211_get_radio_led_name(sc->hw);
+ snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
+ "ath9k-%s::radio", wiphy_name(sc->hw->wiphy));
+ ret = ath_register_led(sc, &sc->radio_led, trigger);
+ sc->radio_led.led_type = ATH_LED_RADIO;
+ if (ret)
+ goto fail;
+
+ trigger = ieee80211_get_assoc_led_name(sc->hw);
+ snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
+ "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy));
+ ret = ath_register_led(sc, &sc->assoc_led, trigger);
+ sc->assoc_led.led_type = ATH_LED_ASSOC;
+ if (ret)
+ goto fail;
+
+ trigger = ieee80211_get_tx_led_name(sc->hw);
+ snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
+ "ath9k-%s::tx", wiphy_name(sc->hw->wiphy));
+ ret = ath_register_led(sc, &sc->tx_led, trigger);
+ sc->tx_led.led_type = ATH_LED_TX;
+ if (ret)
+ goto fail;
+
+ trigger = ieee80211_get_rx_led_name(sc->hw);
+ snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
+ "ath9k-%s::rx", wiphy_name(sc->hw->wiphy));
+ ret = ath_register_led(sc, &sc->rx_led, trigger);
+ sc->rx_led.led_type = ATH_LED_RX;
+ if (ret)
+ goto fail;
+
+ return;
+
+fail:
+ cancel_delayed_work_sync(&sc->ath_led_blink_work);
+ ath_deinit_leds(sc);
+}
+
+/*******************/
+/* Rfkill */
+/*******************/
+
+static bool ath_is_rfkill_set(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+
+ return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
+ ah->rfkill_polarity;
+}
+
+void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)
+{
+ struct ath_wiphy *aphy = hw->priv;
+ struct ath_softc *sc = aphy->sc;
+ bool blocked = !!ath_is_rfkill_set(sc);
+
+ wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
+}
+
+void ath_start_rfkill_poll(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+ wiphy_rfkill_start_polling(sc->hw->wiphy);
+}
+
+/******************/
+/* BTCOEX */
+/******************/
+
+/*
+ * Detects if there is any priority bt traffic
+ */
+static void ath_detect_bt_priority(struct ath_softc *sc)
+{
+ struct ath_btcoex *btcoex = &sc->btcoex;
+ struct ath_hw *ah = sc->sc_ah;
+
+ if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio))
+ btcoex->bt_priority_cnt++;
+
+ if (time_after(jiffies, btcoex->bt_priority_time +
+ msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
+ sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN);
+ /* Detect if colocated bt started scanning */
+ if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
+ "BT scan detected");
+ sc->sc_flags |= (SC_OP_BT_SCAN |
+ SC_OP_BT_PRIORITY_DETECTED);
+ } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
+ "BT priority traffic detected");
+ sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
+ }
+
+ btcoex->bt_priority_cnt = 0;
+ btcoex->bt_priority_time = jiffies;
+ }
+}
+
+/*
+ * Configures appropriate weight based on stomp type.
+ */
+static void ath9k_btcoex_bt_stomp(struct ath_softc *sc,
+ enum ath_stomp_type stomp_type)
+{
+ struct ath_hw *ah = sc->sc_ah;
+
+ switch (stomp_type) {
+ case ATH_BTCOEX_STOMP_ALL:
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_ALL_WLAN_WGHT);
+ break;
+ case ATH_BTCOEX_STOMP_LOW:
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_LOW_WLAN_WGHT);
+ break;
+ case ATH_BTCOEX_STOMP_NONE:
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_NONE_WLAN_WGHT);
+ break;
+ default:
+ ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "Invalid Stomptype\n");
+ break;
+ }
+
+ ath9k_hw_btcoex_enable(ah);
+}
+
+static void ath9k_gen_timer_start(struct ath_hw *ah,
+ struct ath_gen_timer *timer,
+ u32 timer_next,
+ u32 timer_period)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+ ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
+
+ if ((sc->imask & ATH9K_INT_GENTIMER) == 0) {
+ ath9k_hw_set_interrupts(ah, 0);
+ sc->imask |= ATH9K_INT_GENTIMER;
+ ath9k_hw_set_interrupts(ah, sc->imask);
+ }
+}
+
+static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+
+ ath9k_hw_gen_timer_stop(ah, timer);
+
+ /* if no timer is enabled, turn off interrupt mask */
+ if (timer_table->timer_mask.val == 0) {
+ ath9k_hw_set_interrupts(ah, 0);
+ sc->imask &= ~ATH9K_INT_GENTIMER;
+ ath9k_hw_set_interrupts(ah, sc->imask);
+ }
+}
+
+/*
+ * This is the master bt coex timer which runs for every
+ * 45ms, bt traffic will be given priority during 55% of this
+ * period while wlan gets remaining 45%
+ */
+static void ath_btcoex_period_timer(unsigned long data)
+{
+ struct ath_softc *sc = (struct ath_softc *) data;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_btcoex *btcoex = &sc->btcoex;
+ u32 timer_period;
+ bool is_btscan;
+
+ ath_detect_bt_priority(sc);
+
+ is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
+
+ spin_lock_bh(&btcoex->btcoex_lock);
+
+ ath9k_btcoex_bt_stomp(sc, is_btscan ? ATH_BTCOEX_STOMP_ALL :
+ btcoex->bt_stomp_type);
+
+ spin_unlock_bh(&btcoex->btcoex_lock);
+
+ if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) {
+ if (btcoex->hw_timer_enabled)
+ ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
+
+ timer_period = is_btscan ? btcoex->btscan_no_stomp :
+ btcoex->btcoex_no_stomp;
+ ath9k_gen_timer_start(ah,
+ btcoex->no_stomp_timer,
+ (ath9k_hw_gettsf32(ah) +
+ timer_period), timer_period * 10);
+ btcoex->hw_timer_enabled = true;
+ }
+
+ mod_timer(&btcoex->period_timer, jiffies +
+ msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
+}
+
+/*
+ * Generic tsf based hw timer which configures weight
+ * registers to time slice between wlan and bt traffic
+ */
+static void ath_btcoex_no_stomp_timer(void *arg)
+{
+ struct ath_softc *sc = (struct ath_softc *)arg;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_btcoex *btcoex = &sc->btcoex;
+ bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
+
+ ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "no stomp timer running \n");
+
+ spin_lock_bh(&btcoex->btcoex_lock);
+
+ if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
+ ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE);
+ else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
+ ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW);
+
+ spin_unlock_bh(&btcoex->btcoex_lock);
+}
+
+int ath_init_btcoex_timer(struct ath_softc *sc)
+{
+ struct ath_btcoex *btcoex = &sc->btcoex;
+
+ btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
+ btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
+ btcoex->btcoex_period / 100;
+ btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
+ btcoex->btcoex_period / 100;
+
+ setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
+ (unsigned long) sc);
+
+ spin_lock_init(&btcoex->btcoex_lock);
+
+ btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah,
+ ath_btcoex_no_stomp_timer,
+ ath_btcoex_no_stomp_timer,
+ (void *) sc, AR_FIRST_NDP_TIMER);
+
+ if (!btcoex->no_stomp_timer)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/*
+ * (Re)start btcoex timers
+ */
+void ath9k_btcoex_timer_resume(struct ath_softc *sc)
+{
+ struct ath_btcoex *btcoex = &sc->btcoex;
+ struct ath_hw *ah = sc->sc_ah;
+
+ ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "Starting btcoex timers");
+
+ /* make sure duty cycle timer is also stopped when resuming */
+ if (btcoex->hw_timer_enabled)
+ ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
+
+ btcoex->bt_priority_cnt = 0;
+ btcoex->bt_priority_time = jiffies;
+ sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN);
+
+ mod_timer(&btcoex->period_timer, jiffies);
+}
+
+
+/*
+ * Pause btcoex timer and bt duty cycle timer
+ */
+void ath9k_btcoex_timer_pause(struct ath_softc *sc)
+{
+ struct ath_btcoex *btcoex = &sc->btcoex;
+ struct ath_hw *ah = sc->sc_ah;
+
+ del_timer_sync(&btcoex->period_timer);
+
+ if (btcoex->hw_timer_enabled)
+ ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
+
+ btcoex->hw_timer_enabled = false;
+}
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 2ec61f08cfdb..2e767cf22f1e 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -52,28 +52,6 @@ module_exit(ath9k_exit);
/* Helper Functions */
/********************/
-static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks)
-{
- struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
-
- if (!ah->curchan) /* should really check for CCK instead */
- return clks / ATH9K_CLOCK_RATE_CCK;
- if (conf->channel->band == IEEE80211_BAND_2GHZ)
- return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM;
-
- return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM;
-}
-
-static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks)
-{
- struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
-
- if (conf_is_ht40(conf))
- return ath9k_hw_mac_usec(ah, clks) / 2;
- else
- return ath9k_hw_mac_usec(ah, clks);
-}
-
static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs)
{
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
@@ -343,30 +321,6 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
return true;
}
-static const char *ath9k_hw_devname(u16 devid)
-{
- switch (devid) {
- case AR5416_DEVID_PCI:
- return "Atheros 5416";
- case AR5416_DEVID_PCIE:
- return "Atheros 5418";
- case AR9160_DEVID_PCI:
- return "Atheros 9160";
- case AR5416_AR9100_DEVID:
- return "Atheros 9100";
- case AR9280_DEVID_PCI:
- case AR9280_DEVID_PCIE:
- return "Atheros 9280";
- case AR9285_DEVID_PCIE:
- return "Atheros 9285";
- case AR5416_DEVID_AR9287_PCI:
- case AR5416_DEVID_AR9287_PCIE:
- return "Atheros 9287";
- }
-
- return NULL;
-}
-
static void ath9k_hw_init_config(struct ath_hw *ah)
{
int i;
@@ -380,7 +334,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
ah->config.pcie_clock_req = 0;
ah->config.pcie_waen = 0;
ah->config.analog_shiftreg = 1;
- ah->config.ht_enable = 1;
ah->config.ofdm_trig_low = 200;
ah->config.ofdm_trig_high = 500;
ah->config.cck_trig_high = 200;
@@ -392,7 +345,12 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
ah->config.spurchans[i][1] = AR_NO_SPUR;
}
- ah->config.intr_mitigation = true;
+ if (ah->hw_version.devid != AR2427_DEVID_PCIE)
+ ah->config.ht_enable = 1;
+ else
+ ah->config.ht_enable = 0;
+
+ ah->config.rx_intr_mitigation = true;
/*
* We need this for PCI devices only (Cardbus, PCI, miniPCI)
@@ -437,8 +395,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
ah->beacon_interval = 100;
ah->enable_32kHz_clock = DONT_USE_32KHZ;
ah->slottime = (u32) -1;
- ah->acktimeout = (u32) -1;
- ah->ctstimeout = (u32) -1;
ah->globaltxtimeout = (u32) -1;
ah->power_mode = ATH9K_PM_UNDEFINED;
}
@@ -590,6 +546,7 @@ static bool ath9k_hw_devid_supported(u16 devid)
case AR5416_DEVID_AR9287_PCI:
case AR5416_DEVID_AR9287_PCIE:
case AR9271_USB:
+ case AR2427_DEVID_PCIE:
return true;
default:
break;
@@ -855,12 +812,11 @@ static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
}
}
-static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah)
+static void ath9k_hw_init_eeprom_fix(struct ath_hw *ah)
{
u32 i, j;
- if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
- test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) {
+ if (ah->hw_version.devid == AR9280_DEVID_PCI) {
/* EEPROM Fixup */
for (i = 0; i < ah->iniModes.ia_rows; i++) {
@@ -980,7 +936,7 @@ int ath9k_hw_init(struct ath_hw *ah)
if (r)
return r;
- ath9k_hw_init_11a_eeprom_fix(ah);
+ ath9k_hw_init_eeprom_fix(ah);
r = ath9k_hw_init_macaddr(ah);
if (r) {
@@ -1184,7 +1140,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
AR_IMR_RXORN |
AR_IMR_BCNMISC;
- if (ah->config.intr_mitigation)
+ if (ah->config.rx_intr_mitigation)
ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
else
ah->mask_reg |= AR_IMR_RXOK;
@@ -1204,34 +1160,25 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
}
}
-static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
+static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
{
- if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
- "bad ack timeout %u\n", us);
- ah->acktimeout = (u32) -1;
- return false;
- } else {
- REG_RMW_FIELD(ah, AR_TIME_OUT,
- AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us));
- ah->acktimeout = us;
- return true;
- }
+ u32 val = ath9k_hw_mac_to_clks(ah, us);
+ val = min(val, (u32) 0xFFFF);
+ REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val);
}
-static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
+static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
{
- if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
- "bad cts timeout %u\n", us);
- ah->ctstimeout = (u32) -1;
- return false;
- } else {
- REG_RMW_FIELD(ah, AR_TIME_OUT,
- AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us));
- ah->ctstimeout = us;
- return true;
- }
+ u32 val = ath9k_hw_mac_to_clks(ah, us);
+ val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK));
+ REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val);
+}
+
+static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
+{
+ u32 val = ath9k_hw_mac_to_clks(ah, us);
+ val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS));
+ REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_CTS, val);
}
static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
@@ -1248,31 +1195,48 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
}
}
-static void ath9k_hw_init_user_settings(struct ath_hw *ah)
+void ath9k_hw_init_global_settings(struct ath_hw *ah)
{
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
+ int acktimeout;
+ int slottime;
+ int sifstime;
+
ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n",
ah->misc_mode);
if (ah->misc_mode != 0)
REG_WRITE(ah, AR_PCU_MISC,
REG_READ(ah, AR_PCU_MISC) | ah->misc_mode);
- if (ah->slottime != (u32) -1)
- ath9k_hw_setslottime(ah, ah->slottime);
- if (ah->acktimeout != (u32) -1)
- ath9k_hw_set_ack_timeout(ah, ah->acktimeout);
- if (ah->ctstimeout != (u32) -1)
- ath9k_hw_set_cts_timeout(ah, ah->ctstimeout);
+
+ if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ)
+ sifstime = 16;
+ else
+ sifstime = 10;
+
+ /* As defined by IEEE 802.11-2007 17.3.8.6 */
+ slottime = ah->slottime + 3 * ah->coverage_class;
+ acktimeout = slottime + sifstime;
+
+ /*
+ * Workaround for early ACK timeouts, add an offset to match the
+ * initval's 64us ack timeout value.
+ * This was initially only meant to work around an issue with delayed
+ * BA frames in some implementations, but it has been found to fix ACK
+ * timeout issues in other cases as well.
+ */
+ if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ)
+ acktimeout += 64 - sifstime - ah->slottime;
+
+ ath9k_hw_setslottime(ah, slottime);
+ ath9k_hw_set_ack_timeout(ah, acktimeout);
+ ath9k_hw_set_cts_timeout(ah, acktimeout);
if (ah->globaltxtimeout != (u32) -1)
ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout);
}
+EXPORT_SYMBOL(ath9k_hw_init_global_settings);
-const char *ath9k_hw_probe(u16 vendorid, u16 devid)
-{
- return vendorid == ATHEROS_VENDOR_ID ?
- ath9k_hw_devname(devid) : NULL;
-}
-
-void ath9k_hw_detach(struct ath_hw *ah)
+void ath9k_hw_deinit(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
@@ -1290,7 +1254,7 @@ free_hw:
kfree(ah);
ah = NULL;
}
-EXPORT_SYMBOL(ath9k_hw_detach);
+EXPORT_SYMBOL(ath9k_hw_deinit);
/*******/
/* INI */
@@ -1346,6 +1310,16 @@ static void ath9k_hw_override_ini(struct ath_hw *ah,
* Necessary to avoid issues on AR5416 2.0
*/
REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
+
+ /*
+ * Disable RIFS search on some chips to avoid baseband
+ * hang issues.
+ */
+ if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) {
+ val = REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS);
+ val &= ~AR_PHY_RIFS_INIT_DELAY;
+ REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val);
+ }
}
static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah,
@@ -2091,7 +2065,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
ath9k_enable_rfkill(ah);
- ath9k_hw_init_user_settings(ah);
+ ath9k_hw_init_global_settings(ah);
if (AR_SREV_9287_12_OR_LATER(ah)) {
REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
@@ -2121,7 +2095,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
REG_WRITE(ah, AR_OBS, 8);
- if (ah->config.intr_mitigation) {
+ if (ah->config.rx_intr_mitigation) {
REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
}
@@ -2781,7 +2755,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
*masked = isr & ATH9K_INT_COMMON;
- if (ah->config.intr_mitigation) {
+ if (ah->config.rx_intr_mitigation) {
if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
*masked |= ATH9K_INT_RX;
}
@@ -2914,7 +2888,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
}
if (ints & ATH9K_INT_RX) {
mask |= AR_IMR_RXERR;
- if (ah->config.intr_mitigation)
+ if (ah->config.rx_intr_mitigation)
mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
else
mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
@@ -3688,21 +3662,6 @@ u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp)
}
EXPORT_SYMBOL(ath9k_hw_extend_tsf);
-bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
-{
- if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
- "bad slot time %u\n", us);
- ah->slottime = (u32) -1;
- return false;
- } else {
- REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us));
- ah->slottime = us;
- return true;
- }
-}
-EXPORT_SYMBOL(ath9k_hw_setslottime);
-
void ath9k_hw_set11nmac2040(struct ath_hw *ah)
{
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index e2b0c73a616f..dbbf7ca5f97d 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -40,6 +40,7 @@
#define AR9280_DEVID_PCI 0x0029
#define AR9280_DEVID_PCIE 0x002a
#define AR9285_DEVID_PCIE 0x002b
+#define AR2427_DEVID_PCIE 0x002c
#define AR5416_AR9100_DEVID 0x000b
@@ -212,7 +213,7 @@ struct ath9k_ops_config {
u32 cck_trig_low;
u32 enable_ani;
int serialize_regmode;
- bool intr_mitigation;
+ bool rx_intr_mitigation;
#define SPUR_DISABLE 0
#define SPUR_ENABLE_IOCTL 1
#define SPUR_ENABLE_EEPROM 2
@@ -551,10 +552,9 @@ struct ath_hw {
u32 *bank6Temp;
int16_t txpower_indexoffset;
+ int coverage_class;
u32 beacon_interval;
u32 slottime;
- u32 acktimeout;
- u32 ctstimeout;
u32 globaltxtimeout;
/* ANI */
@@ -616,7 +616,7 @@ static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah)
/* Initialization, Detach, Reset */
const char *ath9k_hw_probe(u16 vendorid, u16 devid);
-void ath9k_hw_detach(struct ath_hw *ah);
+void ath9k_hw_deinit(struct ath_hw *ah);
int ath9k_hw_init(struct ath_hw *ah);
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
bool bChannelChange);
@@ -668,7 +668,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
void ath9k_hw_reset_tsf(struct ath_hw *ah);
void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp);
-bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
+void ath9k_hw_init_global_settings(struct ath_hw *ah);
void ath9k_hw_set11nmac2040(struct ath_hw *ah);
void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
new file mode 100644
index 000000000000..623c2f884987
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -0,0 +1,863 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+
+static char *dev_info = "ath9k";
+
+MODULE_AUTHOR("Atheros Communications");
+MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
+MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static unsigned int ath9k_debug = ATH_DBG_DEFAULT;
+module_param_named(debug, ath9k_debug, uint, 0);
+MODULE_PARM_DESC(debug, "Debugging mask");
+
+int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
+
+/* We use the hw_value as an index into our private channel structure */
+
+#define CHAN2G(_freq, _idx) { \
+ .center_freq = (_freq), \
+ .hw_value = (_idx), \
+ .max_power = 20, \
+}
+
+#define CHAN5G(_freq, _idx) { \
+ .band = IEEE80211_BAND_5GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_idx), \
+ .max_power = 20, \
+}
+
+/* Some 2 GHz radios are actually tunable on 2312-2732
+ * on 5 MHz steps, we support the channels which we know
+ * we have calibration data for all cards though to make
+ * this static */
+static struct ieee80211_channel ath9k_2ghz_chantable[] = {
+ CHAN2G(2412, 0), /* Channel 1 */
+ CHAN2G(2417, 1), /* Channel 2 */
+ CHAN2G(2422, 2), /* Channel 3 */
+ CHAN2G(2427, 3), /* Channel 4 */
+ CHAN2G(2432, 4), /* Channel 5 */
+ CHAN2G(2437, 5), /* Channel 6 */
+ CHAN2G(2442, 6), /* Channel 7 */
+ CHAN2G(2447, 7), /* Channel 8 */
+ CHAN2G(2452, 8), /* Channel 9 */
+ CHAN2G(2457, 9), /* Channel 10 */
+ CHAN2G(2462, 10), /* Channel 11 */
+ CHAN2G(2467, 11), /* Channel 12 */
+ CHAN2G(2472, 12), /* Channel 13 */
+ CHAN2G(2484, 13), /* Channel 14 */
+};
+
+/* Some 5 GHz radios are actually tunable on XXXX-YYYY
+ * on 5 MHz steps, we support the channels which we know
+ * we have calibration data for all cards though to make
+ * this static */
+static struct ieee80211_channel ath9k_5ghz_chantable[] = {
+ /* _We_ call this UNII 1 */
+ CHAN5G(5180, 14), /* Channel 36 */
+ CHAN5G(5200, 15), /* Channel 40 */
+ CHAN5G(5220, 16), /* Channel 44 */
+ CHAN5G(5240, 17), /* Channel 48 */
+ /* _We_ call this UNII 2 */
+ CHAN5G(5260, 18), /* Channel 52 */
+ CHAN5G(5280, 19), /* Channel 56 */
+ CHAN5G(5300, 20), /* Channel 60 */
+ CHAN5G(5320, 21), /* Channel 64 */
+ /* _We_ call this "Middle band" */
+ CHAN5G(5500, 22), /* Channel 100 */
+ CHAN5G(5520, 23), /* Channel 104 */
+ CHAN5G(5540, 24), /* Channel 108 */
+ CHAN5G(5560, 25), /* Channel 112 */
+ CHAN5G(5580, 26), /* Channel 116 */
+ CHAN5G(5600, 27), /* Channel 120 */
+ CHAN5G(5620, 28), /* Channel 124 */
+ CHAN5G(5640, 29), /* Channel 128 */
+ CHAN5G(5660, 30), /* Channel 132 */
+ CHAN5G(5680, 31), /* Channel 136 */
+ CHAN5G(5700, 32), /* Channel 140 */
+ /* _We_ call this UNII 3 */
+ CHAN5G(5745, 33), /* Channel 149 */
+ CHAN5G(5765, 34), /* Channel 153 */
+ CHAN5G(5785, 35), /* Channel 157 */
+ CHAN5G(5805, 36), /* Channel 161 */
+ CHAN5G(5825, 37), /* Channel 165 */
+};
+
+/* Atheros hardware rate code addition for short premble */
+#define SHPCHECK(__hw_rate, __flags) \
+ ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
+
+#define RATE(_bitrate, _hw_rate, _flags) { \
+ .bitrate = (_bitrate), \
+ .flags = (_flags), \
+ .hw_value = (_hw_rate), \
+ .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \
+}
+
+static struct ieee80211_rate ath9k_legacy_rates[] = {
+ RATE(10, 0x1b, 0),
+ RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(60, 0x0b, 0),
+ RATE(90, 0x0f, 0),
+ RATE(120, 0x0a, 0),
+ RATE(180, 0x0e, 0),
+ RATE(240, 0x09, 0),
+ RATE(360, 0x0d, 0),
+ RATE(480, 0x08, 0),
+ RATE(540, 0x0c, 0),
+};
+
+static void ath9k_deinit_softc(struct ath_softc *sc);
+
+/*
+ * Read and write, they both share the same lock. We do this to serialize
+ * reads and writes on Atheros 802.11n PCI devices only. This is required
+ * as the FIFO on these devices can only accept sanely 2 requests.
+ */
+
+static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
+{
+ struct ath_hw *ah = (struct ath_hw *) hw_priv;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+ if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
+ unsigned long flags;
+ spin_lock_irqsave(&sc->sc_serial_rw, flags);
+ iowrite32(val, sc->mem + reg_offset);
+ spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
+ } else
+ iowrite32(val, sc->mem + reg_offset);
+}
+
+static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
+{
+ struct ath_hw *ah = (struct ath_hw *) hw_priv;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+ u32 val;
+
+ if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
+ unsigned long flags;
+ spin_lock_irqsave(&sc->sc_serial_rw, flags);
+ val = ioread32(sc->mem + reg_offset);
+ spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
+ } else
+ val = ioread32(sc->mem + reg_offset);
+ return val;
+}
+
+static const struct ath_ops ath9k_common_ops = {
+ .read = ath9k_ioread32,
+ .write = ath9k_iowrite32,
+};
+
+/**************************/
+/* Initialization */
+/**************************/
+
+static void setup_ht_cap(struct ath_softc *sc,
+ struct ieee80211_sta_ht_cap *ht_info)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ u8 tx_streams, rx_streams;
+
+ ht_info->ht_supported = true;
+ ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_SM_PS |
+ IEEE80211_HT_CAP_SGI_40 |
+ IEEE80211_HT_CAP_DSSSCCK40;
+
+ ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
+
+ /* set up supported mcs set */
+ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+ tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ?
+ 1 : 2;
+ rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ?
+ 1 : 2;
+
+ if (tx_streams != rx_streams) {
+ ath_print(common, ATH_DBG_CONFIG,
+ "TX streams %d, RX streams: %d\n",
+ tx_streams, rx_streams);
+ ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+ ht_info->mcs.tx_params |= ((tx_streams - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
+ }
+
+ ht_info->mcs.rx_mask[0] = 0xff;
+ if (rx_streams >= 2)
+ ht_info->mcs.rx_mask[1] = 0xff;
+
+ ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
+}
+
+static int ath9k_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct ath_wiphy *aphy = hw->priv;
+ struct ath_softc *sc = aphy->sc;
+ struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah);
+
+ return ath_reg_notifier_apply(wiphy, request, reg);
+}
+
+/*
+ * This function will allocate both the DMA descriptor structure, and the
+ * buffers it contains. These are used to contain the descriptors used
+ * by the system.
+*/
+int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
+ struct list_head *head, const char *name,
+ int nbuf, int ndesc)
+{
+#define DS2PHYS(_dd, _ds) \
+ ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
+#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
+#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_desc *ds;
+ struct ath_buf *bf;
+ int i, bsize, error;
+
+ ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
+ name, nbuf, ndesc);
+
+ INIT_LIST_HEAD(head);
+ /* ath_desc must be a multiple of DWORDs */
+ if ((sizeof(struct ath_desc) % 4) != 0) {
+ ath_print(common, ATH_DBG_FATAL,
+ "ath_desc not DWORD aligned\n");
+ BUG_ON((sizeof(struct ath_desc) % 4) != 0);
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
+
+ /*
+ * Need additional DMA memory because we can't use
+ * descriptors that cross the 4K page boundary. Assume
+ * one skipped descriptor per 4K page.
+ */
+ if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+ u32 ndesc_skipped =
+ ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
+ u32 dma_len;
+
+ while (ndesc_skipped) {
+ dma_len = ndesc_skipped * sizeof(struct ath_desc);
+ dd->dd_desc_len += dma_len;
+
+ ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
+ };
+ }
+
+ /* allocate descriptors */
+ dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
+ &dd->dd_desc_paddr, GFP_KERNEL);
+ if (dd->dd_desc == NULL) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ ds = dd->dd_desc;
+ ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
+ name, ds, (u32) dd->dd_desc_len,
+ ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
+
+ /* allocate buffers */
+ bsize = sizeof(struct ath_buf) * nbuf;
+ bf = kzalloc(bsize, GFP_KERNEL);
+ if (bf == NULL) {
+ error = -ENOMEM;
+ goto fail2;
+ }
+ dd->dd_bufptr = bf;
+
+ for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
+ bf->bf_desc = ds;
+ bf->bf_daddr = DS2PHYS(dd, ds);
+
+ if (!(sc->sc_ah->caps.hw_caps &
+ ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+ /*
+ * Skip descriptor addresses which can cause 4KB
+ * boundary crossing (addr + length) with a 32 dword
+ * descriptor fetch.
+ */
+ while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
+ BUG_ON((caddr_t) bf->bf_desc >=
+ ((caddr_t) dd->dd_desc +
+ dd->dd_desc_len));
+
+ ds += ndesc;
+ bf->bf_desc = ds;
+ bf->bf_daddr = DS2PHYS(dd, ds);
+ }
+ }
+ list_add_tail(&bf->list, head);
+ }
+ return 0;
+fail2:
+ dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
+ dd->dd_desc_paddr);
+fail:
+ memset(dd, 0, sizeof(*dd));
+ return error;
+#undef ATH_DESC_4KB_BOUND_CHECK
+#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
+#undef DS2PHYS
+}
+
+static void ath9k_init_crypto(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ int i = 0;
+
+ /* Get the hardware key cache size. */
+ common->keymax = sc->sc_ah->caps.keycache_size;
+ if (common->keymax > ATH_KEYMAX) {
+ ath_print(common, ATH_DBG_ANY,
+ "Warning, using only %u entries in %u key cache\n",
+ ATH_KEYMAX, common->keymax);
+ common->keymax = ATH_KEYMAX;
+ }
+
+ /*
+ * Reset the key cache since some parts do not
+ * reset the contents on initial power up.
+ */
+ for (i = 0; i < common->keymax; i++)
+ ath9k_hw_keyreset(sc->sc_ah, (u16) i);
+
+ if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER,
+ ATH9K_CIPHER_TKIP, NULL)) {
+ /*
+ * Whether we should enable h/w TKIP MIC.
+ * XXX: if we don't support WME TKIP MIC, then we wouldn't
+ * report WMM capable, so it's always safe to turn on
+ * TKIP MIC in this case.
+ */
+ ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, 0, 1, NULL);
+ }
+
+ /*
+ * Check whether the separate key cache entries
+ * are required to handle both tx+rx MIC keys.
+ * With split mic keys the number of stations is limited
+ * to 27 otherwise 59.
+ */
+ if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER,
+ ATH9K_CIPHER_TKIP, NULL)
+ && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER,
+ ATH9K_CIPHER_MIC, NULL)
+ && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_TKIP_SPLIT,
+ 0, NULL))
+ common->splitmic = 1;
+
+ /* turn on mcast key search if possible */
+ if (!ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
+ (void)ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH,
+ 1, 1, NULL);
+
+}
+
+static int ath9k_init_btcoex(struct ath_softc *sc)
+{
+ int r, qnum;
+
+ switch (sc->sc_ah->btcoex_hw.scheme) {
+ case ATH_BTCOEX_CFG_NONE:
+ break;
+ case ATH_BTCOEX_CFG_2WIRE:
+ ath9k_hw_btcoex_init_2wire(sc->sc_ah);
+ break;
+ case ATH_BTCOEX_CFG_3WIRE:
+ ath9k_hw_btcoex_init_3wire(sc->sc_ah);
+ r = ath_init_btcoex_timer(sc);
+ if (r)
+ return -1;
+ qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
+ ath9k_hw_init_btcoex_hw(sc->sc_ah, qnum);
+ sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ return 0;
+}
+
+static int ath9k_init_queues(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++)
+ sc->tx.hwq_map[i] = -1;
+
+ sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah);
+ if (sc->beacon.beaconq == -1) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup a beacon xmit queue\n");
+ goto err;
+ }
+
+ sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
+ if (sc->beacon.cabq == NULL) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup CAB xmit queue\n");
+ goto err;
+ }
+
+ sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
+ ath_cabq_update(sc);
+
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for BK traffic\n");
+ goto err;
+ }
+
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for BE traffic\n");
+ goto err;
+ }
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for VI traffic\n");
+ goto err;
+ }
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for VO traffic\n");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+
+ return -EIO;
+}
+
+static void ath9k_init_channels_rates(struct ath_softc *sc)
+{
+ if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) {
+ sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable;
+ sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
+ sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
+ ARRAY_SIZE(ath9k_2ghz_chantable);
+ sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
+ sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
+ ARRAY_SIZE(ath9k_legacy_rates);
+ }
+
+ if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) {
+ sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable;
+ sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
+ sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
+ ARRAY_SIZE(ath9k_5ghz_chantable);
+ sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
+ ath9k_legacy_rates + 4;
+ sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
+ ARRAY_SIZE(ath9k_legacy_rates) - 4;
+ }
+}
+
+static void ath9k_init_misc(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ int i = 0;
+
+ common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR;
+ setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
+
+ sc->config.txpowlimit = ATH_TXPOWER_MAX;
+
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
+ sc->sc_flags |= SC_OP_TXAGGR;
+ sc->sc_flags |= SC_OP_RXAGGR;
+ }
+
+ common->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
+ common->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
+
+ ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
+ sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah);
+
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
+ memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
+
+ sc->beacon.slottime = ATH9K_SLOT_TIME_9;
+
+ for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
+ sc->beacon.bslot[i] = NULL;
+ sc->beacon.bslot_aphy[i] = NULL;
+ }
+}
+
+static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
+ const struct ath_bus_ops *bus_ops)
+{
+ struct ath_hw *ah = NULL;
+ struct ath_common *common;
+ int ret = 0, i;
+ int csz = 0;
+
+ ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
+ if (!ah)
+ return -ENOMEM;
+
+ ah->hw_version.devid = devid;
+ ah->hw_version.subsysid = subsysid;
+ sc->sc_ah = ah;
+
+ common = ath9k_hw_common(ah);
+ common->ops = &ath9k_common_ops;
+ common->bus_ops = bus_ops;
+ common->ah = ah;
+ common->hw = sc->hw;
+ common->priv = sc;
+ common->debug_mask = ath9k_debug;
+
+ spin_lock_init(&sc->wiphy_lock);
+ spin_lock_init(&sc->sc_resetlock);
+ spin_lock_init(&sc->sc_serial_rw);
+ spin_lock_init(&sc->sc_pm_lock);
+ mutex_init(&sc->mutex);
+ tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
+ tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
+ (unsigned long)sc);
+
+ /*
+ * Cache line size is used to size and align various
+ * structures used to communicate with the hardware.
+ */
+ ath_read_cachesize(common, &csz);
+ common->cachelsz = csz << 2; /* convert to bytes */
+
+ ret = ath9k_hw_init(ah);
+ if (ret) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to initialize hardware; "
+ "initialization status: %d\n", ret);
+ goto err_hw;
+ }
+
+ ret = ath9k_init_debug(ah);
+ if (ret) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to create debugfs files\n");
+ goto err_debug;
+ }
+
+ ret = ath9k_init_queues(sc);
+ if (ret)
+ goto err_queues;
+
+ ret = ath9k_init_btcoex(sc);
+ if (ret)
+ goto err_btcoex;
+
+ ath9k_init_crypto(sc);
+ ath9k_init_channels_rates(sc);
+ ath9k_init_misc(sc);
+
+ return 0;
+
+err_btcoex:
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+err_queues:
+ ath9k_exit_debug(ah);
+err_debug:
+ ath9k_hw_deinit(ah);
+err_hw:
+ tasklet_kill(&sc->intr_tq);
+ tasklet_kill(&sc->bcon_tasklet);
+
+ kfree(ah);
+ sc->sc_ah = NULL;
+
+ return ret;
+}
+
+void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK |
+ IEEE80211_HW_SPECTRUM_MGMT |
+ IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
+ hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+
+ if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt)
+ hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+
+ hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_MESH_POINT);
+
+ hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+ hw->queues = 4;
+ hw->max_rates = 4;
+ hw->channel_change_time = 5000;
+ hw->max_listen_interval = 10;
+ hw->max_rate_tries = 10;
+ hw->sta_data_size = sizeof(struct ath_node);
+ hw->vif_data_size = sizeof(struct ath_vif);
+
+ hw->rate_control_algorithm = "ath9k_rate_control";
+
+ if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes))
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &sc->sbands[IEEE80211_BAND_2GHZ];
+ if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &sc->sbands[IEEE80211_BAND_5GHZ];
+
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
+ if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes))
+ setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+ if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
+ setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
+ }
+
+ SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
+}
+
+int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+ const struct ath_bus_ops *bus_ops)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_common *common;
+ struct ath_hw *ah;
+ int error = 0;
+ struct ath_regulatory *reg;
+
+ /* Bring up device */
+ error = ath9k_init_softc(devid, sc, subsysid, bus_ops);
+ if (error != 0)
+ goto error_init;
+
+ ah = sc->sc_ah;
+ common = ath9k_hw_common(ah);
+ ath9k_set_hw_capab(sc, hw);
+
+ /* Initialize regulatory */
+ error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
+ ath9k_reg_notifier);
+ if (error)
+ goto error_regd;
+
+ reg = &common->regulatory;
+
+ /* Setup TX DMA */
+ error = ath_tx_init(sc, ATH_TXBUF);
+ if (error != 0)
+ goto error_tx;
+
+ /* Setup RX DMA */
+ error = ath_rx_init(sc, ATH_RXBUF);
+ if (error != 0)
+ goto error_rx;
+
+ /* Register with mac80211 */
+ error = ieee80211_register_hw(hw);
+ if (error)
+ goto error_register;
+
+ /* Handle world regulatory */
+ if (!ath_is_world_regd(reg)) {
+ error = regulatory_hint(hw->wiphy, reg->alpha2);
+ if (error)
+ goto error_world;
+ }
+
+ INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
+ INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
+ sc->wiphy_scheduler_int = msecs_to_jiffies(500);
+
+ ath_init_leds(sc);
+ ath_start_rfkill_poll(sc);
+
+ return 0;
+
+error_world:
+ ieee80211_unregister_hw(hw);
+error_register:
+ ath_rx_cleanup(sc);
+error_rx:
+ ath_tx_cleanup(sc);
+error_tx:
+ /* Nothing */
+error_regd:
+ ath9k_deinit_softc(sc);
+error_init:
+ return error;
+}
+
+/*****************************/
+/* De-Initialization */
+/*****************************/
+
+static void ath9k_deinit_softc(struct ath_softc *sc)
+{
+ int i = 0;
+
+ if ((sc->btcoex.no_stomp_timer) &&
+ sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
+
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+
+ ath9k_exit_debug(sc->sc_ah);
+ ath9k_hw_deinit(sc->sc_ah);
+
+ tasklet_kill(&sc->intr_tq);
+ tasklet_kill(&sc->bcon_tasklet);
+}
+
+void ath9k_deinit_device(struct ath_softc *sc)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ int i = 0;
+
+ ath9k_ps_wakeup(sc);
+
+ wiphy_rfkill_stop_polling(sc->hw->wiphy);
+ ath_deinit_leds(sc);
+
+ for (i = 0; i < sc->num_sec_wiphy; i++) {
+ struct ath_wiphy *aphy = sc->sec_wiphy[i];
+ if (aphy == NULL)
+ continue;
+ sc->sec_wiphy[i] = NULL;
+ ieee80211_unregister_hw(aphy->hw);
+ ieee80211_free_hw(aphy->hw);
+ }
+ kfree(sc->sec_wiphy);
+
+ ieee80211_unregister_hw(hw);
+ ath_rx_cleanup(sc);
+ ath_tx_cleanup(sc);
+ ath9k_deinit_softc(sc);
+}
+
+void ath_descdma_cleanup(struct ath_softc *sc,
+ struct ath_descdma *dd,
+ struct list_head *head)
+{
+ dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
+ dd->dd_desc_paddr);
+
+ INIT_LIST_HEAD(head);
+ kfree(dd->dd_bufptr);
+ memset(dd, 0, sizeof(*dd));
+}
+
+/************************/
+/* Module Hooks */
+/************************/
+
+static int __init ath9k_init(void)
+{
+ int error;
+
+ /* Register rate control algorithm */
+ error = ath_rate_control_register();
+ if (error != 0) {
+ printk(KERN_ERR
+ "ath9k: Unable to register rate control "
+ "algorithm: %d\n",
+ error);
+ goto err_out;
+ }
+
+ error = ath9k_debug_create_root();
+ if (error) {
+ printk(KERN_ERR
+ "ath9k: Unable to create debugfs root: %d\n",
+ error);
+ goto err_rate_unregister;
+ }
+
+ error = ath_pci_init();
+ if (error < 0) {
+ printk(KERN_ERR
+ "ath9k: No PCI devices found, driver not installed.\n");
+ error = -ENODEV;
+ goto err_remove_root;
+ }
+
+ error = ath_ahb_init();
+ if (error < 0) {
+ error = -ENODEV;
+ goto err_pci_exit;
+ }
+
+ return 0;
+
+ err_pci_exit:
+ ath_pci_exit();
+
+ err_remove_root:
+ ath9k_debug_remove_root();
+ err_rate_unregister:
+ ath_rate_control_unregister();
+ err_out:
+ return error;
+}
+module_init(ath9k_init);
+
+static void __exit ath9k_exit(void)
+{
+ ath_ahb_exit();
+ ath_pci_exit();
+ ath9k_debug_remove_root();
+ ath_rate_control_unregister();
+ printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
+}
+module_exit(ath9k_exit);
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index e185479e295e..29851e6376a9 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -167,6 +167,40 @@ struct ath_rx_status {
#define ATH9K_RXKEYIX_INVALID ((u8)-1)
#define ATH9K_TXKEYIX_INVALID ((u32)-1)
+enum ath9k_phyerr {
+ ATH9K_PHYERR_UNDERRUN = 0, /* Transmit underrun */
+ ATH9K_PHYERR_TIMING = 1, /* Timing error */
+ ATH9K_PHYERR_PARITY = 2, /* Illegal parity */
+ ATH9K_PHYERR_RATE = 3, /* Illegal rate */
+ ATH9K_PHYERR_LENGTH = 4, /* Illegal length */
+ ATH9K_PHYERR_RADAR = 5, /* Radar detect */
+ ATH9K_PHYERR_SERVICE = 6, /* Illegal service */
+ ATH9K_PHYERR_TOR = 7, /* Transmit override receive */
+
+ ATH9K_PHYERR_OFDM_TIMING = 17,
+ ATH9K_PHYERR_OFDM_SIGNAL_PARITY = 18,
+ ATH9K_PHYERR_OFDM_RATE_ILLEGAL = 19,
+ ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL = 20,
+ ATH9K_PHYERR_OFDM_POWER_DROP = 21,
+ ATH9K_PHYERR_OFDM_SERVICE = 22,
+ ATH9K_PHYERR_OFDM_RESTART = 23,
+ ATH9K_PHYERR_FALSE_RADAR_EXT = 24,
+
+ ATH9K_PHYERR_CCK_TIMING = 25,
+ ATH9K_PHYERR_CCK_HEADER_CRC = 26,
+ ATH9K_PHYERR_CCK_RATE_ILLEGAL = 27,
+ ATH9K_PHYERR_CCK_SERVICE = 30,
+ ATH9K_PHYERR_CCK_RESTART = 31,
+ ATH9K_PHYERR_CCK_LENGTH_ILLEGAL = 32,
+ ATH9K_PHYERR_CCK_POWER_DROP = 33,
+
+ ATH9K_PHYERR_HT_CRC_ERROR = 34,
+ ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 35,
+ ATH9K_PHYERR_HT_RATE_ILLEGAL = 36,
+
+ ATH9K_PHYERR_MAX = 37,
+};
+
struct ath_desc {
u32 ds_link;
u32 ds_data;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 996eb90263cc..67ca4e5a6017 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -18,118 +18,6 @@
#include "ath9k.h"
#include "btcoex.h"
-static char *dev_info = "ath9k";
-
-MODULE_AUTHOR("Atheros Communications");
-MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
-MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
-MODULE_LICENSE("Dual BSD/GPL");
-
-static int modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
-MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
-
-static unsigned int ath9k_debug = ATH_DBG_DEFAULT;
-module_param_named(debug, ath9k_debug, uint, 0);
-MODULE_PARM_DESC(debug, "Debugging mask");
-
-/* We use the hw_value as an index into our private channel structure */
-
-#define CHAN2G(_freq, _idx) { \
- .center_freq = (_freq), \
- .hw_value = (_idx), \
- .max_power = 20, \
-}
-
-#define CHAN5G(_freq, _idx) { \
- .band = IEEE80211_BAND_5GHZ, \
- .center_freq = (_freq), \
- .hw_value = (_idx), \
- .max_power = 20, \
-}
-
-/* Some 2 GHz radios are actually tunable on 2312-2732
- * on 5 MHz steps, we support the channels which we know
- * we have calibration data for all cards though to make
- * this static */
-static struct ieee80211_channel ath9k_2ghz_chantable[] = {
- CHAN2G(2412, 0), /* Channel 1 */
- CHAN2G(2417, 1), /* Channel 2 */
- CHAN2G(2422, 2), /* Channel 3 */
- CHAN2G(2427, 3), /* Channel 4 */
- CHAN2G(2432, 4), /* Channel 5 */
- CHAN2G(2437, 5), /* Channel 6 */
- CHAN2G(2442, 6), /* Channel 7 */
- CHAN2G(2447, 7), /* Channel 8 */
- CHAN2G(2452, 8), /* Channel 9 */
- CHAN2G(2457, 9), /* Channel 10 */
- CHAN2G(2462, 10), /* Channel 11 */
- CHAN2G(2467, 11), /* Channel 12 */
- CHAN2G(2472, 12), /* Channel 13 */
- CHAN2G(2484, 13), /* Channel 14 */
-};
-
-/* Some 5 GHz radios are actually tunable on XXXX-YYYY
- * on 5 MHz steps, we support the channels which we know
- * we have calibration data for all cards though to make
- * this static */
-static struct ieee80211_channel ath9k_5ghz_chantable[] = {
- /* _We_ call this UNII 1 */
- CHAN5G(5180, 14), /* Channel 36 */
- CHAN5G(5200, 15), /* Channel 40 */
- CHAN5G(5220, 16), /* Channel 44 */
- CHAN5G(5240, 17), /* Channel 48 */
- /* _We_ call this UNII 2 */
- CHAN5G(5260, 18), /* Channel 52 */
- CHAN5G(5280, 19), /* Channel 56 */
- CHAN5G(5300, 20), /* Channel 60 */
- CHAN5G(5320, 21), /* Channel 64 */
- /* _We_ call this "Middle band" */
- CHAN5G(5500, 22), /* Channel 100 */
- CHAN5G(5520, 23), /* Channel 104 */
- CHAN5G(5540, 24), /* Channel 108 */
- CHAN5G(5560, 25), /* Channel 112 */
- CHAN5G(5580, 26), /* Channel 116 */
- CHAN5G(5600, 27), /* Channel 120 */
- CHAN5G(5620, 28), /* Channel 124 */
- CHAN5G(5640, 29), /* Channel 128 */
- CHAN5G(5660, 30), /* Channel 132 */
- CHAN5G(5680, 31), /* Channel 136 */
- CHAN5G(5700, 32), /* Channel 140 */
- /* _We_ call this UNII 3 */
- CHAN5G(5745, 33), /* Channel 149 */
- CHAN5G(5765, 34), /* Channel 153 */
- CHAN5G(5785, 35), /* Channel 157 */
- CHAN5G(5805, 36), /* Channel 161 */
- CHAN5G(5825, 37), /* Channel 165 */
-};
-
-/* Atheros hardware rate code addition for short premble */
-#define SHPCHECK(__hw_rate, __flags) \
- ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
-
-#define RATE(_bitrate, _hw_rate, _flags) { \
- .bitrate = (_bitrate), \
- .flags = (_flags), \
- .hw_value = (_hw_rate), \
- .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \
-}
-
-static struct ieee80211_rate ath9k_legacy_rates[] = {
- RATE(10, 0x1b, 0),
- RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
- RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
- RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
- RATE(60, 0x0b, 0),
- RATE(90, 0x0f, 0),
- RATE(120, 0x0a, 0),
- RATE(180, 0x0e, 0),
- RATE(240, 0x09, 0),
- RATE(360, 0x0d, 0),
- RATE(480, 0x08, 0),
- RATE(540, 0x0c, 0),
-};
-
static void ath_cache_conf_rate(struct ath_softc *sc,
struct ieee80211_conf *conf)
{
@@ -221,7 +109,7 @@ static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc,
return channel;
}
-static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
+bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
{
unsigned long flags;
bool ret;
@@ -255,11 +143,13 @@ void ath9k_ps_restore(struct ath_softc *sc)
if (--sc->ps_usecount != 0)
goto unlock;
- if (sc->ps_enabled &&
- !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
- SC_OP_WAIT_FOR_CAB |
- SC_OP_WAIT_FOR_PSPOLL_DATA |
- SC_OP_WAIT_FOR_TX_ACK)))
+ if (sc->ps_idle)
+ ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
+ else if (sc->ps_enabled &&
+ !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
+ PS_WAIT_FOR_CAB |
+ PS_WAIT_FOR_PSPOLL_DATA |
+ PS_WAIT_FOR_TX_ACK)))
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
unlock:
@@ -316,7 +206,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
r = ath9k_hw_reset(ah, hchan, fastcc);
if (r) {
ath_print(common, ATH_DBG_FATAL,
- "Unable to reset channel (%u Mhz) "
+ "Unable to reset channel (%u MHz), "
"reset status %d\n",
channel->center_freq, r);
spin_unlock_bh(&sc->sc_resetlock);
@@ -349,7 +239,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
* When the task is complete, it reschedules itself depending on the
* appropriate interval that was calculated.
*/
-static void ath_ani_calibrate(unsigned long data)
+void ath_ani_calibrate(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
struct ath_hw *ah = sc->sc_ah;
@@ -363,14 +253,6 @@ static void ath_ani_calibrate(unsigned long data)
short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
- /*
- * don't calibrate when we're scanning.
- * we are most likely not on our home channel.
- */
- spin_lock(&sc->ani_lock);
- if (sc->sc_flags & SC_OP_SCANNING)
- goto set_timer;
-
/* Only calibrate if awake */
if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
goto set_timer;
@@ -437,7 +319,6 @@ static void ath_ani_calibrate(unsigned long data)
ath9k_ps_restore(sc);
set_timer:
- spin_unlock(&sc->ani_lock);
/*
* Set timer interval based on previous results.
* The interval must be the shortest necessary to satisfy ANI,
@@ -513,7 +394,7 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
ath_tx_node_cleanup(sc, an);
}
-static void ath9k_tasklet(unsigned long data)
+void ath9k_tasklet(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
struct ath_hw *ah = sc->sc_ah;
@@ -545,7 +426,7 @@ static void ath9k_tasklet(unsigned long data)
*/
ath_print(common, ATH_DBG_PS,
"TSFOOR - Sync with next Beacon\n");
- sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC;
+ sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
}
if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
@@ -646,7 +527,7 @@ irqreturn_t ath_isr(int irq, void *dev)
* receive frames */
ath9k_setpower(sc, ATH9K_PM_AWAKE);
ath9k_hw_setrxabort(sc->sc_ah, 0);
- sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
+ sc->ps_flags |= PS_WAIT_FOR_BEACON;
}
chip_reset:
@@ -928,49 +809,12 @@ static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf
clear_bit(key->hw_key_idx + 64, common->keymap);
if (common->splitmic) {
+ ath9k_hw_keyreset(ah, key->hw_key_idx + 32);
clear_bit(key->hw_key_idx + 32, common->keymap);
clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
}
}
-static void setup_ht_cap(struct ath_softc *sc,
- struct ieee80211_sta_ht_cap *ht_info)
-{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- u8 tx_streams, rx_streams;
-
- ht_info->ht_supported = true;
- ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
- IEEE80211_HT_CAP_SM_PS |
- IEEE80211_HT_CAP_SGI_40 |
- IEEE80211_HT_CAP_DSSSCCK40;
-
- ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
- ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
-
- /* set up supported mcs set */
- memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
- tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ?
- 1 : 2;
- rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ?
- 1 : 2;
-
- if (tx_streams != rx_streams) {
- ath_print(common, ATH_DBG_CONFIG,
- "TX streams %d, RX streams: %d\n",
- tx_streams, rx_streams);
- ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
- ht_info->mcs.tx_params |= ((tx_streams - 1) <<
- IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
- }
-
- ht_info->mcs.rx_mask[0] = 0xff;
- if (rx_streams >= 2)
- ht_info->mcs.rx_mask[1] = 0xff;
-
- ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
-}
-
static void ath9k_bss_assoc_info(struct ath_softc *sc,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
@@ -992,7 +836,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
* on the receipt of the first Beacon frame (i.e.,
* after time sync with the AP).
*/
- sc->sc_flags |= SC_OP_BEACON_SYNC;
+ sc->ps_flags |= PS_BEACON_SYNC;
/* Configure the beacon */
ath_beacon_config(sc, vif);
@@ -1009,174 +853,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
}
}
-/********************************/
-/* LED functions */
-/********************************/
-
-static void ath_led_blink_work(struct work_struct *work)
-{
- struct ath_softc *sc = container_of(work, struct ath_softc,
- ath_led_blink_work.work);
-
- if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED))
- return;
-
- if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
- (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
- else
- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
- (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
-
- ieee80211_queue_delayed_work(sc->hw,
- &sc->ath_led_blink_work,
- (sc->sc_flags & SC_OP_LED_ON) ?
- msecs_to_jiffies(sc->led_off_duration) :
- msecs_to_jiffies(sc->led_on_duration));
-
- sc->led_on_duration = sc->led_on_cnt ?
- max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) :
- ATH_LED_ON_DURATION_IDLE;
- sc->led_off_duration = sc->led_off_cnt ?
- max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) :
- ATH_LED_OFF_DURATION_IDLE;
- sc->led_on_cnt = sc->led_off_cnt = 0;
- if (sc->sc_flags & SC_OP_LED_ON)
- sc->sc_flags &= ~SC_OP_LED_ON;
- else
- sc->sc_flags |= SC_OP_LED_ON;
-}
-
-static void ath_led_brightness(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
- struct ath_softc *sc = led->sc;
-
- switch (brightness) {
- case LED_OFF:
- if (led->led_type == ATH_LED_ASSOC ||
- led->led_type == ATH_LED_RADIO) {
- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
- (led->led_type == ATH_LED_RADIO));
- sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
- if (led->led_type == ATH_LED_RADIO)
- sc->sc_flags &= ~SC_OP_LED_ON;
- } else {
- sc->led_off_cnt++;
- }
- break;
- case LED_FULL:
- if (led->led_type == ATH_LED_ASSOC) {
- sc->sc_flags |= SC_OP_LED_ASSOCIATED;
- ieee80211_queue_delayed_work(sc->hw,
- &sc->ath_led_blink_work, 0);
- } else if (led->led_type == ATH_LED_RADIO) {
- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
- sc->sc_flags |= SC_OP_LED_ON;
- } else {
- sc->led_on_cnt++;
- }
- break;
- default:
- break;
- }
-}
-
-static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
- char *trigger)
-{
- int ret;
-
- led->sc = sc;
- led->led_cdev.name = led->name;
- led->led_cdev.default_trigger = trigger;
- led->led_cdev.brightness_set = ath_led_brightness;
-
- ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
- if (ret)
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
- "Failed to register led:%s", led->name);
- else
- led->registered = 1;
- return ret;
-}
-
-static void ath_unregister_led(struct ath_led *led)
-{
- if (led->registered) {
- led_classdev_unregister(&led->led_cdev);
- led->registered = 0;
- }
-}
-
-static void ath_deinit_leds(struct ath_softc *sc)
-{
- ath_unregister_led(&sc->assoc_led);
- sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
- ath_unregister_led(&sc->tx_led);
- ath_unregister_led(&sc->rx_led);
- ath_unregister_led(&sc->radio_led);
- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
-}
-
-static void ath_init_leds(struct ath_softc *sc)
-{
- char *trigger;
- int ret;
-
- if (AR_SREV_9287(sc->sc_ah))
- sc->sc_ah->led_pin = ATH_LED_PIN_9287;
- else
- sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
-
- /* Configure gpio 1 for output */
- ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
- AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
- /* LED off, active low */
- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
-
- INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
-
- trigger = ieee80211_get_radio_led_name(sc->hw);
- snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
- "ath9k-%s::radio", wiphy_name(sc->hw->wiphy));
- ret = ath_register_led(sc, &sc->radio_led, trigger);
- sc->radio_led.led_type = ATH_LED_RADIO;
- if (ret)
- goto fail;
-
- trigger = ieee80211_get_assoc_led_name(sc->hw);
- snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
- "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy));
- ret = ath_register_led(sc, &sc->assoc_led, trigger);
- sc->assoc_led.led_type = ATH_LED_ASSOC;
- if (ret)
- goto fail;
-
- trigger = ieee80211_get_tx_led_name(sc->hw);
- snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
- "ath9k-%s::tx", wiphy_name(sc->hw->wiphy));
- ret = ath_register_led(sc, &sc->tx_led, trigger);
- sc->tx_led.led_type = ATH_LED_TX;
- if (ret)
- goto fail;
-
- trigger = ieee80211_get_rx_led_name(sc->hw);
- snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
- "ath9k-%s::rx", wiphy_name(sc->hw->wiphy));
- ret = ath_register_led(sc, &sc->rx_led, trigger);
- sc->rx_led.led_type = ATH_LED_RX;
- if (ret)
- goto fail;
-
- return;
-
-fail:
- cancel_delayed_work_sync(&sc->ath_led_blink_work);
- ath_deinit_leds(sc);
-}
-
void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
{
struct ath_hw *ah = sc->sc_ah;
@@ -1194,7 +870,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
r = ath9k_hw_reset(ah, ah->curchan, false);
if (r) {
ath_print(common, ATH_DBG_FATAL,
- "Unable to reset channel %u (%uMhz) ",
+ "Unable to reset channel (%u MHz), "
"reset status %d\n",
channel->center_freq, r);
}
@@ -1249,7 +925,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
r = ath9k_hw_reset(ah, ah->curchan, false);
if (r) {
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
- "Unable to reset channel %u (%uMhz) "
+ "Unable to reset channel (%u MHz), "
"reset status %d\n",
channel->center_freq, r);
}
@@ -1261,711 +937,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
}
-/*******************/
-/* Rfkill */
-/*******************/
-
-static bool ath_is_rfkill_set(struct ath_softc *sc)
-{
- struct ath_hw *ah = sc->sc_ah;
-
- return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
- ah->rfkill_polarity;
-}
-
-static void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)
-{
- struct ath_wiphy *aphy = hw->priv;
- struct ath_softc *sc = aphy->sc;
- bool blocked = !!ath_is_rfkill_set(sc);
-
- wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
-}
-
-static void ath_start_rfkill_poll(struct ath_softc *sc)
-{
- struct ath_hw *ah = sc->sc_ah;
-
- if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
- wiphy_rfkill_start_polling(sc->hw->wiphy);
-}
-
-static void ath9k_uninit_hw(struct ath_softc *sc)
-{
- struct ath_hw *ah = sc->sc_ah;
-
- BUG_ON(!ah);
-
- ath9k_exit_debug(ah);
- ath9k_hw_detach(ah);
- sc->sc_ah = NULL;
-}
-
-static void ath_clean_core(struct ath_softc *sc)
-{
- struct ieee80211_hw *hw = sc->hw;
- struct ath_hw *ah = sc->sc_ah;
- int i = 0;
-
- ath9k_ps_wakeup(sc);
-
- dev_dbg(sc->dev, "Detach ATH hw\n");
-
- ath_deinit_leds(sc);
- wiphy_rfkill_stop_polling(sc->hw->wiphy);
-
- for (i = 0; i < sc->num_sec_wiphy; i++) {
- struct ath_wiphy *aphy = sc->sec_wiphy[i];
- if (aphy == NULL)
- continue;
- sc->sec_wiphy[i] = NULL;
- ieee80211_unregister_hw(aphy->hw);
- ieee80211_free_hw(aphy->hw);
- }
- ieee80211_unregister_hw(hw);
- ath_rx_cleanup(sc);
- ath_tx_cleanup(sc);
-
- tasklet_kill(&sc->intr_tq);
- tasklet_kill(&sc->bcon_tasklet);
-
- if (!(sc->sc_flags & SC_OP_INVALID))
- ath9k_setpower(sc, ATH9K_PM_AWAKE);
-
- /* cleanup tx queues */
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
- if (ATH_TXQ_SETUP(sc, i))
- ath_tx_cleanupq(sc, &sc->tx.txq[i]);
-
- if ((sc->btcoex.no_stomp_timer) &&
- ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
- ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer);
-}
-
-void ath_detach(struct ath_softc *sc)
-{
- ath_clean_core(sc);
- ath9k_uninit_hw(sc);
-}
-
-void ath_cleanup(struct ath_softc *sc)
-{
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
-
- ath_clean_core(sc);
- free_irq(sc->irq, sc);
- ath_bus_cleanup(common);
- kfree(sc->sec_wiphy);
- ieee80211_free_hw(sc->hw);
-
- ath9k_uninit_hw(sc);
-}
-
-static int ath9k_reg_notifier(struct wiphy *wiphy,
- struct regulatory_request *request)
-{
- struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
- struct ath_wiphy *aphy = hw->priv;
- struct ath_softc *sc = aphy->sc;
- struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah);
-
- return ath_reg_notifier_apply(wiphy, request, reg);
-}
-
-/*
- * Detects if there is any priority bt traffic
- */
-static void ath_detect_bt_priority(struct ath_softc *sc)
-{
- struct ath_btcoex *btcoex = &sc->btcoex;
- struct ath_hw *ah = sc->sc_ah;
-
- if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio))
- btcoex->bt_priority_cnt++;
-
- if (time_after(jiffies, btcoex->bt_priority_time +
- msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
- if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
- "BT priority traffic detected");
- sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
- } else {
- sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
- }
-
- btcoex->bt_priority_cnt = 0;
- btcoex->bt_priority_time = jiffies;
- }
-}
-
-/*
- * Configures appropriate weight based on stomp type.
- */
-static void ath9k_btcoex_bt_stomp(struct ath_softc *sc,
- enum ath_stomp_type stomp_type)
-{
- struct ath_hw *ah = sc->sc_ah;
-
- switch (stomp_type) {
- case ATH_BTCOEX_STOMP_ALL:
- ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
- AR_STOMP_ALL_WLAN_WGHT);
- break;
- case ATH_BTCOEX_STOMP_LOW:
- ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
- AR_STOMP_LOW_WLAN_WGHT);
- break;
- case ATH_BTCOEX_STOMP_NONE:
- ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
- AR_STOMP_NONE_WLAN_WGHT);
- break;
- default:
- ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
- "Invalid Stomptype\n");
- break;
- }
-
- ath9k_hw_btcoex_enable(ah);
-}
-
-static void ath9k_gen_timer_start(struct ath_hw *ah,
- struct ath_gen_timer *timer,
- u32 timer_next,
- u32 timer_period)
-{
- struct ath_common *common = ath9k_hw_common(ah);
- struct ath_softc *sc = (struct ath_softc *) common->priv;
-
- ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
-
- if ((sc->imask & ATH9K_INT_GENTIMER) == 0) {
- ath9k_hw_set_interrupts(ah, 0);
- sc->imask |= ATH9K_INT_GENTIMER;
- ath9k_hw_set_interrupts(ah, sc->imask);
- }
-}
-
-static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
-{
- struct ath_common *common = ath9k_hw_common(ah);
- struct ath_softc *sc = (struct ath_softc *) common->priv;
- struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
-
- ath9k_hw_gen_timer_stop(ah, timer);
-
- /* if no timer is enabled, turn off interrupt mask */
- if (timer_table->timer_mask.val == 0) {
- ath9k_hw_set_interrupts(ah, 0);
- sc->imask &= ~ATH9K_INT_GENTIMER;
- ath9k_hw_set_interrupts(ah, sc->imask);
- }
-}
-
-/*
- * This is the master bt coex timer which runs for every
- * 45ms, bt traffic will be given priority during 55% of this
- * period while wlan gets remaining 45%
- */
-static void ath_btcoex_period_timer(unsigned long data)
-{
- struct ath_softc *sc = (struct ath_softc *) data;
- struct ath_hw *ah = sc->sc_ah;
- struct ath_btcoex *btcoex = &sc->btcoex;
-
- ath_detect_bt_priority(sc);
-
- spin_lock_bh(&btcoex->btcoex_lock);
-
- ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type);
-
- spin_unlock_bh(&btcoex->btcoex_lock);
-
- if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) {
- if (btcoex->hw_timer_enabled)
- ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
-
- ath9k_gen_timer_start(ah,
- btcoex->no_stomp_timer,
- (ath9k_hw_gettsf32(ah) +
- btcoex->btcoex_no_stomp),
- btcoex->btcoex_no_stomp * 10);
- btcoex->hw_timer_enabled = true;
- }
-
- mod_timer(&btcoex->period_timer, jiffies +
- msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
-}
-
-/*
- * Generic tsf based hw timer which configures weight
- * registers to time slice between wlan and bt traffic
- */
-static void ath_btcoex_no_stomp_timer(void *arg)
-{
- struct ath_softc *sc = (struct ath_softc *)arg;
- struct ath_hw *ah = sc->sc_ah;
- struct ath_btcoex *btcoex = &sc->btcoex;
-
- ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
- "no stomp timer running \n");
-
- spin_lock_bh(&btcoex->btcoex_lock);
-
- if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
- ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE);
- else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
- ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW);
-
- spin_unlock_bh(&btcoex->btcoex_lock);
-}
-
-static int ath_init_btcoex_timer(struct ath_softc *sc)
-{
- struct ath_btcoex *btcoex = &sc->btcoex;
-
- btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
- btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
- btcoex->btcoex_period / 100;
-
- setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
- (unsigned long) sc);
-
- spin_lock_init(&btcoex->btcoex_lock);
-
- btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah,
- ath_btcoex_no_stomp_timer,
- ath_btcoex_no_stomp_timer,
- (void *) sc, AR_FIRST_NDP_TIMER);
-
- if (!btcoex->no_stomp_timer)
- return -ENOMEM;
-
- return 0;
-}
-
-/*
- * Read and write, they both share the same lock. We do this to serialize
- * reads and writes on Atheros 802.11n PCI devices only. This is required
- * as the FIFO on these devices can only accept sanely 2 requests. After
- * that the device goes bananas. Serializing the reads/writes prevents this
- * from happening.
- */
-
-static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
-{
- struct ath_hw *ah = (struct ath_hw *) hw_priv;
- struct ath_common *common = ath9k_hw_common(ah);
- struct ath_softc *sc = (struct ath_softc *) common->priv;
-
- if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
- unsigned long flags;
- spin_lock_irqsave(&sc->sc_serial_rw, flags);
- iowrite32(val, sc->mem + reg_offset);
- spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
- } else
- iowrite32(val, sc->mem + reg_offset);
-}
-
-static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
-{
- struct ath_hw *ah = (struct ath_hw *) hw_priv;
- struct ath_common *common = ath9k_hw_common(ah);
- struct ath_softc *sc = (struct ath_softc *) common->priv;
- u32 val;
-
- if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
- unsigned long flags;
- spin_lock_irqsave(&sc->sc_serial_rw, flags);
- val = ioread32(sc->mem + reg_offset);
- spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
- } else
- val = ioread32(sc->mem + reg_offset);
- return val;
-}
-
-static const struct ath_ops ath9k_common_ops = {
- .read = ath9k_ioread32,
- .write = ath9k_iowrite32,
-};
-
-/*
- * Initialize and fill ath_softc, ath_sofct is the
- * "Software Carrier" struct. Historically it has existed
- * to allow the separation between hardware specific
- * variables (now in ath_hw) and driver specific variables.
- */
-static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
- const struct ath_bus_ops *bus_ops)
-{
- struct ath_hw *ah = NULL;
- struct ath_common *common;
- int r = 0, i;
- int csz = 0;
- int qnum;
-
- /* XXX: hardware will not be ready until ath_open() being called */
- sc->sc_flags |= SC_OP_INVALID;
-
- spin_lock_init(&sc->wiphy_lock);
- spin_lock_init(&sc->sc_resetlock);
- spin_lock_init(&sc->sc_serial_rw);
- spin_lock_init(&sc->ani_lock);
- spin_lock_init(&sc->sc_pm_lock);
- mutex_init(&sc->mutex);
- tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
- tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
- (unsigned long)sc);
-
- ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
- if (!ah)
- return -ENOMEM;
-
- ah->hw_version.devid = devid;
- ah->hw_version.subsysid = subsysid;
- sc->sc_ah = ah;
-
- common = ath9k_hw_common(ah);
- common->ops = &ath9k_common_ops;
- common->bus_ops = bus_ops;
- common->ah = ah;
- common->hw = sc->hw;
- common->priv = sc;
- common->debug_mask = ath9k_debug;
-
- /*
- * Cache line size is used to size and align various
- * structures used to communicate with the hardware.
- */
- ath_read_cachesize(common, &csz);
- /* XXX assert csz is non-zero */
- common->cachelsz = csz << 2; /* convert to bytes */
-
- r = ath9k_hw_init(ah);
- if (r) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to initialize hardware; "
- "initialization status: %d\n", r);
- goto bad_free_hw;
- }
-
- if (ath9k_init_debug(ah) < 0) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to create debugfs files\n");
- goto bad_free_hw;
- }
-
- /* Get the hardware key cache size. */
- common->keymax = ah->caps.keycache_size;
- if (common->keymax > ATH_KEYMAX) {
- ath_print(common, ATH_DBG_ANY,
- "Warning, using only %u entries in %u key cache\n",
- ATH_KEYMAX, common->keymax);
- common->keymax = ATH_KEYMAX;
- }
-
- /*
- * Reset the key cache since some parts do not
- * reset the contents on initial power up.
- */
- for (i = 0; i < common->keymax; i++)
- ath9k_hw_keyreset(ah, (u16) i);
-
- /* default to MONITOR mode */
- sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR;
-
- /*
- * Allocate hardware transmit queues: one queue for
- * beacon frames and one data queue for each QoS
- * priority. Note that the hal handles reseting
- * these queues at the needed time.
- */
- sc->beacon.beaconq = ath9k_hw_beaconq_setup(ah);
- if (sc->beacon.beaconq == -1) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup a beacon xmit queue\n");
- r = -EIO;
- goto bad2;
- }
- sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
- if (sc->beacon.cabq == NULL) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup CAB xmit queue\n");
- r = -EIO;
- goto bad2;
- }
-
- sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
- ath_cabq_update(sc);
-
- for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++)
- sc->tx.hwq_map[i] = -1;
-
- /* Setup data queues */
- /* NB: ensure BK queue is the lowest priority h/w queue */
- if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup xmit queue for BK traffic\n");
- r = -EIO;
- goto bad2;
- }
-
- if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup xmit queue for BE traffic\n");
- r = -EIO;
- goto bad2;
- }
- if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup xmit queue for VI traffic\n");
- r = -EIO;
- goto bad2;
- }
- if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to setup xmit queue for VO traffic\n");
- r = -EIO;
- goto bad2;
- }
-
- /* Initializes the noise floor to a reasonable default value.
- * Later on this will be updated during ANI processing. */
-
- common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR;
- setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
-
- if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_TKIP, NULL)) {
- /*
- * Whether we should enable h/w TKIP MIC.
- * XXX: if we don't support WME TKIP MIC, then we wouldn't
- * report WMM capable, so it's always safe to turn on
- * TKIP MIC in this case.
- */
- ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC,
- 0, 1, NULL);
- }
-
- /*
- * Check whether the separate key cache entries
- * are required to handle both tx+rx MIC keys.
- * With split mic keys the number of stations is limited
- * to 27 otherwise 59.
- */
- if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_TKIP, NULL)
- && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_MIC, NULL)
- && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
- 0, NULL))
- common->splitmic = 1;
-
- /* turn on mcast key search if possible */
- if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
- (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1,
- 1, NULL);
-
- sc->config.txpowlimit = ATH_TXPOWER_MAX;
-
- /* 11n Capabilities */
- if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
- sc->sc_flags |= SC_OP_TXAGGR;
- sc->sc_flags |= SC_OP_RXAGGR;
- }
-
- common->tx_chainmask = ah->caps.tx_chainmask;
- common->rx_chainmask = ah->caps.rx_chainmask;
-
- ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
- sc->rx.defant = ath9k_hw_getdefantenna(ah);
-
- if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
- memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
-
- sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */
-
- /* initialize beacon slots */
- for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
- sc->beacon.bslot[i] = NULL;
- sc->beacon.bslot_aphy[i] = NULL;
- }
-
- /* setup channels and rates */
-
- if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) {
- sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable;
- sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
- sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
- ARRAY_SIZE(ath9k_2ghz_chantable);
- sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
- sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
- ARRAY_SIZE(ath9k_legacy_rates);
- }
-
- if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) {
- sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable;
- sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
- sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
- ARRAY_SIZE(ath9k_5ghz_chantable);
- sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
- ath9k_legacy_rates + 4;
- sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
- ARRAY_SIZE(ath9k_legacy_rates) - 4;
- }
-
- switch (ah->btcoex_hw.scheme) {
- case ATH_BTCOEX_CFG_NONE:
- break;
- case ATH_BTCOEX_CFG_2WIRE:
- ath9k_hw_btcoex_init_2wire(ah);
- break;
- case ATH_BTCOEX_CFG_3WIRE:
- ath9k_hw_btcoex_init_3wire(ah);
- r = ath_init_btcoex_timer(sc);
- if (r)
- goto bad2;
- qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
- ath9k_hw_init_btcoex_hw(ah, qnum);
- sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
- break;
- default:
- WARN_ON(1);
- break;
- }
-
- return 0;
-bad2:
- /* cleanup tx queues */
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
- if (ATH_TXQ_SETUP(sc, i))
- ath_tx_cleanupq(sc, &sc->tx.txq[i]);
-
-bad_free_hw:
- ath9k_uninit_hw(sc);
- return r;
-}
-
-void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
-{
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK |
- IEEE80211_HW_SPECTRUM_MGMT;
-
- if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt)
- hw->flags |= IEEE80211_HW_MFP_CAPABLE;
-
- hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_MESH_POINT);
-
- hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
-
- hw->queues = 4;
- hw->max_rates = 4;
- hw->channel_change_time = 5000;
- hw->max_listen_interval = 10;
- /* Hardware supports 10 but we use 4 */
- hw->max_rate_tries = 4;
- hw->sta_data_size = sizeof(struct ath_node);
- hw->vif_data_size = sizeof(struct ath_vif);
-
- hw->rate_control_algorithm = "ath9k_rate_control";
-
- if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes))
- hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
- &sc->sbands[IEEE80211_BAND_2GHZ];
- if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
- hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
- &sc->sbands[IEEE80211_BAND_5GHZ];
-}
-
-/* Device driver core initialization */
-int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
- const struct ath_bus_ops *bus_ops)
-{
- struct ieee80211_hw *hw = sc->hw;
- struct ath_common *common;
- struct ath_hw *ah;
- int error = 0, i;
- struct ath_regulatory *reg;
-
- dev_dbg(sc->dev, "Attach ATH hw\n");
-
- error = ath_init_softc(devid, sc, subsysid, bus_ops);
- if (error != 0)
- return error;
-
- ah = sc->sc_ah;
- common = ath9k_hw_common(ah);
-
- /* get mac address from hardware and set in mac80211 */
-
- SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
-
- ath_set_hw_capab(sc, hw);
-
- error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
- ath9k_reg_notifier);
- if (error)
- return error;
-
- reg = &common->regulatory;
-
- if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
- if (test_bit(ATH9K_MODE_11G, ah->caps.wireless_modes))
- setup_ht_cap(sc,
- &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
- if (test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes))
- setup_ht_cap(sc,
- &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
- }
-
- /* initialize tx/rx engine */
- error = ath_tx_init(sc, ATH_TXBUF);
- if (error != 0)
- goto error_attach;
-
- error = ath_rx_init(sc, ATH_RXBUF);
- if (error != 0)
- goto error_attach;
-
- INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
- INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
- sc->wiphy_scheduler_int = msecs_to_jiffies(500);
-
- error = ieee80211_register_hw(hw);
-
- if (!ath_is_world_regd(reg)) {
- error = regulatory_hint(hw->wiphy, reg->alpha2);
- if (error)
- goto error_attach;
- }
-
- /* Initialize LED control */
- ath_init_leds(sc);
-
- ath_start_rfkill_poll(sc);
-
- return 0;
-
-error_attach:
- /* cleanup tx queues */
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
- if (ATH_TXQ_SETUP(sc, i))
- ath_tx_cleanupq(sc, &sc->tx.txq[i]);
-
- ath9k_uninit_hw(sc);
-
- return error;
-}
-
int ath_reset(struct ath_softc *sc, bool retry_tx)
{
struct ath_hw *ah = sc->sc_ah;
@@ -1976,6 +947,8 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
/* Stop ANI */
del_timer_sync(&common->ani.timer);
+ ieee80211_stop_queues(hw);
+
ath9k_hw_set_interrupts(ah, 0);
ath_drain_all_txq(sc, retry_tx);
ath_stoprecv(sc);
@@ -2017,131 +990,14 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
}
}
+ ieee80211_wake_queues(hw);
+
/* Start ANI */
ath_start_ani(common);
return r;
}
-/*
- * This function will allocate both the DMA descriptor structure, and the
- * buffers it contains. These are used to contain the descriptors used
- * by the system.
-*/
-int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
- struct list_head *head, const char *name,
- int nbuf, int ndesc)
-{
-#define DS2PHYS(_dd, _ds) \
- ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
-#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
-#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_desc *ds;
- struct ath_buf *bf;
- int i, bsize, error;
-
- ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
- name, nbuf, ndesc);
-
- INIT_LIST_HEAD(head);
- /* ath_desc must be a multiple of DWORDs */
- if ((sizeof(struct ath_desc) % 4) != 0) {
- ath_print(common, ATH_DBG_FATAL,
- "ath_desc not DWORD aligned\n");
- BUG_ON((sizeof(struct ath_desc) % 4) != 0);
- error = -ENOMEM;
- goto fail;
- }
-
- dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
-
- /*
- * Need additional DMA memory because we can't use
- * descriptors that cross the 4K page boundary. Assume
- * one skipped descriptor per 4K page.
- */
- if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
- u32 ndesc_skipped =
- ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
- u32 dma_len;
-
- while (ndesc_skipped) {
- dma_len = ndesc_skipped * sizeof(struct ath_desc);
- dd->dd_desc_len += dma_len;
-
- ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
- };
- }
-
- /* allocate descriptors */
- dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
- &dd->dd_desc_paddr, GFP_KERNEL);
- if (dd->dd_desc == NULL) {
- error = -ENOMEM;
- goto fail;
- }
- ds = dd->dd_desc;
- ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
- name, ds, (u32) dd->dd_desc_len,
- ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
-
- /* allocate buffers */
- bsize = sizeof(struct ath_buf) * nbuf;
- bf = kzalloc(bsize, GFP_KERNEL);
- if (bf == NULL) {
- error = -ENOMEM;
- goto fail2;
- }
- dd->dd_bufptr = bf;
-
- for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
- bf->bf_desc = ds;
- bf->bf_daddr = DS2PHYS(dd, ds);
-
- if (!(sc->sc_ah->caps.hw_caps &
- ATH9K_HW_CAP_4KB_SPLITTRANS)) {
- /*
- * Skip descriptor addresses which can cause 4KB
- * boundary crossing (addr + length) with a 32 dword
- * descriptor fetch.
- */
- while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
- BUG_ON((caddr_t) bf->bf_desc >=
- ((caddr_t) dd->dd_desc +
- dd->dd_desc_len));
-
- ds += ndesc;
- bf->bf_desc = ds;
- bf->bf_daddr = DS2PHYS(dd, ds);
- }
- }
- list_add_tail(&bf->list, head);
- }
- return 0;
-fail2:
- dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
- dd->dd_desc_paddr);
-fail:
- memset(dd, 0, sizeof(*dd));
- return error;
-#undef ATH_DESC_4KB_BOUND_CHECK
-#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
-#undef DS2PHYS
-}
-
-void ath_descdma_cleanup(struct ath_softc *sc,
- struct ath_descdma *dd,
- struct list_head *head)
-{
- dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
- dd->dd_desc_paddr);
-
- INIT_LIST_HEAD(head);
- kfree(dd->dd_bufptr);
- memset(dd, 0, sizeof(*dd));
-}
-
int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
{
int qnum;
@@ -2220,28 +1076,6 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
/* mac80211 callbacks */
/**********************/
-/*
- * (Re)start btcoex timers
- */
-static void ath9k_btcoex_timer_resume(struct ath_softc *sc)
-{
- struct ath_btcoex *btcoex = &sc->btcoex;
- struct ath_hw *ah = sc->sc_ah;
-
- ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
- "Starting btcoex timers");
-
- /* make sure duty cycle timer is also stopped when resuming */
- if (btcoex->hw_timer_enabled)
- ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
-
- btcoex->bt_priority_cnt = 0;
- btcoex->bt_priority_time = jiffies;
- sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
-
- mod_timer(&btcoex->period_timer, jiffies);
-}
-
static int ath9k_start(struct ieee80211_hw *hw)
{
struct ath_wiphy *aphy = hw->priv;
@@ -2411,11 +1245,11 @@ static int ath9k_tx(struct ieee80211_hw *hw,
if (ieee80211_is_pspoll(hdr->frame_control)) {
ath_print(common, ATH_DBG_PS,
"Sending PS-Poll to pick a buffered frame\n");
- sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA;
+ sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA;
} else {
ath_print(common, ATH_DBG_PS,
"Wake up to complete TX\n");
- sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK;
+ sc->ps_flags |= PS_WAIT_FOR_TX_ACK;
}
/*
* The actual restore operation will happen only after
@@ -2468,22 +1302,6 @@ exit:
return 0;
}
-/*
- * Pause btcoex timer and bt duty cycle timer
- */
-static void ath9k_btcoex_timer_pause(struct ath_softc *sc)
-{
- struct ath_btcoex *btcoex = &sc->btcoex;
- struct ath_hw *ah = sc->sc_ah;
-
- del_timer_sync(&btcoex->period_timer);
-
- if (btcoex->hw_timer_enabled)
- ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
-
- btcoex->hw_timer_enabled = false;
-}
-
static void ath9k_stop(struct ieee80211_hw *hw)
{
struct ath_wiphy *aphy = hw->priv;
@@ -2550,12 +1368,12 @@ static void ath9k_stop(struct ieee80211_hw *hw)
}
static int ath9k_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_vif *avp = (void *)conf->vif->drv_priv;
+ struct ath_vif *avp = (void *)vif->drv_priv;
enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
int ret = 0;
@@ -2567,7 +1385,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
goto out;
}
- switch (conf->type) {
+ switch (vif->type) {
case NL80211_IFTYPE_STATION:
ic_opmode = NL80211_IFTYPE_STATION;
break;
@@ -2578,11 +1396,11 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
ret = -ENOBUFS;
goto out;
}
- ic_opmode = conf->type;
+ ic_opmode = vif->type;
break;
default:
ath_print(common, ATH_DBG_FATAL,
- "Interface type %d not yet supported\n", conf->type);
+ "Interface type %d not yet supported\n", vif->type);
ret = -EOPNOTSUPP;
goto out;
}
@@ -2614,18 +1432,18 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
* Enable MIB interrupts when there are hardware phy counters.
* Note we only do this (at the moment) for station mode.
*/
- if ((conf->type == NL80211_IFTYPE_STATION) ||
- (conf->type == NL80211_IFTYPE_ADHOC) ||
- (conf->type == NL80211_IFTYPE_MESH_POINT)) {
+ if ((vif->type == NL80211_IFTYPE_STATION) ||
+ (vif->type == NL80211_IFTYPE_ADHOC) ||
+ (vif->type == NL80211_IFTYPE_MESH_POINT)) {
sc->imask |= ATH9K_INT_MIB;
sc->imask |= ATH9K_INT_TSFOOR;
}
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
- if (conf->type == NL80211_IFTYPE_AP ||
- conf->type == NL80211_IFTYPE_ADHOC ||
- conf->type == NL80211_IFTYPE_MONITOR)
+ if (vif->type == NL80211_IFTYPE_AP ||
+ vif->type == NL80211_IFTYPE_ADHOC ||
+ vif->type == NL80211_IFTYPE_MONITOR)
ath_start_ani(common);
out:
@@ -2634,12 +1452,12 @@ out:
}
static void ath9k_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_vif *avp = (void *)conf->vif->drv_priv;
+ struct ath_vif *avp = (void *)vif->drv_priv;
int i;
ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
@@ -2655,14 +1473,14 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
(sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) {
ath9k_ps_wakeup(sc);
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
- ath_beacon_return(sc, avp);
ath9k_ps_restore(sc);
}
+ ath_beacon_return(sc, avp);
sc->sc_flags &= ~SC_OP_BEACONS;
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
- if (sc->beacon.bslot[i] == conf->vif) {
+ if (sc->beacon.bslot[i] == vif) {
printk(KERN_DEBUG "%s: vif had allocated beacon "
"slot\n", __func__);
sc->beacon.bslot[i] = NULL;
@@ -2675,6 +1493,19 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
mutex_unlock(&sc->mutex);
}
+void ath9k_enable_ps(struct ath_softc *sc)
+{
+ sc->ps_enabled = true;
+ if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+ if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
+ sc->imask |= ATH9K_INT_TIM_TIMER;
+ ath9k_hw_set_interrupts(sc->sc_ah,
+ sc->imask);
+ }
+ }
+ ath9k_hw_setrxabort(sc->sc_ah, 1);
+}
+
static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath_wiphy *aphy = hw->priv;
@@ -2713,6 +1544,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
spin_unlock_bh(&sc->wiphy_lock);
if (enable_radio) {
+ sc->ps_idle = false;
ath_radio_enable(sc, hw);
ath_print(common, ATH_DBG_CONFIG,
"not-idle: enabling radio\n");
@@ -2727,36 +1559,27 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
*/
if (changed & IEEE80211_CONF_CHANGE_PS) {
if (conf->flags & IEEE80211_CONF_PS) {
- sc->sc_flags |= SC_OP_PS_ENABLED;
- if (!(ah->caps.hw_caps &
- ATH9K_HW_CAP_AUTOSLEEP)) {
- if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
- sc->imask |= ATH9K_INT_TIM_TIMER;
- ath9k_hw_set_interrupts(sc->sc_ah,
- sc->imask);
- }
- }
+ sc->ps_flags |= PS_ENABLED;
/*
* At this point we know hardware has received an ACK
* of a previously sent null data frame.
*/
- if ((sc->sc_flags & SC_OP_NULLFUNC_COMPLETED)) {
- sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED;
- sc->ps_enabled = true;
- ath9k_hw_setrxabort(sc->sc_ah, 1);
+ if ((sc->ps_flags & PS_NULLFUNC_COMPLETED)) {
+ sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
+ ath9k_enable_ps(sc);
}
} else {
sc->ps_enabled = false;
- sc->sc_flags &= ~(SC_OP_PS_ENABLED |
- SC_OP_NULLFUNC_COMPLETED);
+ sc->ps_flags &= ~(PS_ENABLED |
+ PS_NULLFUNC_COMPLETED);
ath9k_setpower(sc, ATH9K_PM_AWAKE);
if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) {
ath9k_hw_setrxabort(sc->sc_ah, 0);
- sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON |
- SC_OP_WAIT_FOR_CAB |
- SC_OP_WAIT_FOR_PSPOLL_DATA |
- SC_OP_WAIT_FOR_TX_ACK);
+ sc->ps_flags &= ~(PS_WAIT_FOR_BEACON |
+ PS_WAIT_FOR_CAB |
+ PS_WAIT_FOR_PSPOLL_DATA |
+ PS_WAIT_FOR_TX_ACK);
if (sc->imask & ATH9K_INT_TIM_TIMER) {
sc->imask &= ~ATH9K_INT_TIM_TIMER;
ath9k_hw_set_interrupts(sc->sc_ah,
@@ -2766,6 +1589,14 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
}
+ if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
+ if (conf->flags & IEEE80211_CONF_MONITOR) {
+ ath_print(common, ATH_DBG_CONFIG,
+ "HW opmode set to Monitor mode\n");
+ sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR;
+ }
+ }
+
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
struct ieee80211_channel *curchan = hw->conf.channel;
int pos = curchan->hw_value;
@@ -2801,8 +1632,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
skip_chan_change:
- if (changed & IEEE80211_CONF_CHANGE_POWER)
+ if (changed & IEEE80211_CONF_CHANGE_POWER) {
sc->config.txpowlimit = 2 * conf->power_level;
+ ath_update_txpow(sc);
+ }
spin_lock_bh(&sc->wiphy_lock);
disable_radio = ath9k_all_wiphys_idle(sc);
@@ -2810,6 +1643,7 @@ skip_chan_change:
if (disable_radio) {
ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
+ sc->ps_idle = true;
ath_radio_disable(sc, hw);
}
@@ -2850,24 +1684,28 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
"Set HW RX filter: 0x%x\n", rfilt);
}
-static void ath9k_sta_notify(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- enum sta_notify_cmd cmd,
- struct ieee80211_sta *sta)
+static int ath9k_sta_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
- switch (cmd) {
- case STA_NOTIFY_ADD:
- ath_node_attach(sc, sta);
- break;
- case STA_NOTIFY_REMOVE:
- ath_node_detach(sc, sta);
- break;
- default:
- break;
- }
+ ath_node_attach(sc, sta);
+
+ return 0;
+}
+
+static int ath9k_sta_remove(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct ath_wiphy *aphy = hw->priv;
+ struct ath_softc *sc = aphy->sc;
+
+ ath_node_detach(sc, sta);
+
+ return 0;
}
static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
@@ -2966,6 +1804,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = (void *)vif->drv_priv;
+ int slottime;
int error;
mutex_lock(&sc->mutex);
@@ -3001,6 +1840,25 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
ath_beacon_config(sc, vif);
}
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ if (bss_conf->use_short_slot)
+ slottime = 9;
+ else
+ slottime = 20;
+ if (vif->type == NL80211_IFTYPE_AP) {
+ /*
+ * Defer update, so that connected stations can adjust
+ * their settings at the same time.
+ * See beacon.c for more details
+ */
+ sc->beacon.slottime = slottime;
+ sc->beacon.updateslot = UPDATE;
+ } else {
+ ah->slottime = slottime;
+ ath9k_hw_init_global_settings(ah);
+ }
+ }
+
/* Disable transmission of beacons */
if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon)
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
@@ -3133,6 +1991,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
mutex_lock(&sc->mutex);
if (ath9k_wiphy_scanning(sc)) {
@@ -3148,10 +2007,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
aphy->state = ATH_WIPHY_SCAN;
ath9k_wiphy_pause_all_forced(sc, aphy);
-
- spin_lock_bh(&sc->ani_lock);
sc->sc_flags |= SC_OP_SCANNING;
- spin_unlock_bh(&sc->ani_lock);
+ del_timer_sync(&common->ani.timer);
+ cancel_delayed_work_sync(&sc->tx_complete_work);
mutex_unlock(&sc->mutex);
}
@@ -3159,17 +2017,30 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
mutex_lock(&sc->mutex);
- spin_lock_bh(&sc->ani_lock);
aphy->state = ATH_WIPHY_ACTIVE;
sc->sc_flags &= ~SC_OP_SCANNING;
sc->sc_flags |= SC_OP_FULL_RESET;
- spin_unlock_bh(&sc->ani_lock);
+ ath_start_ani(common);
+ ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
ath_beacon_config(sc, NULL);
mutex_unlock(&sc->mutex);
}
+static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
+{
+ struct ath_wiphy *aphy = hw->priv;
+ struct ath_softc *sc = aphy->sc;
+ struct ath_hw *ah = sc->sc_ah;
+
+ mutex_lock(&sc->mutex);
+ ah->coverage_class = coverage_class;
+ ath9k_hw_init_global_settings(ah);
+ mutex_unlock(&sc->mutex);
+}
+
struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
.start = ath9k_start,
@@ -3178,7 +2049,8 @@ struct ieee80211_ops ath9k_ops = {
.remove_interface = ath9k_remove_interface,
.config = ath9k_config,
.configure_filter = ath9k_configure_filter,
- .sta_notify = ath9k_sta_notify,
+ .sta_add = ath9k_sta_add,
+ .sta_remove = ath9k_sta_remove,
.conf_tx = ath9k_conf_tx,
.bss_info_changed = ath9k_bss_info_changed,
.set_key = ath9k_set_key,
@@ -3189,64 +2061,5 @@ struct ieee80211_ops ath9k_ops = {
.sw_scan_start = ath9k_sw_scan_start,
.sw_scan_complete = ath9k_sw_scan_complete,
.rfkill_poll = ath9k_rfkill_poll_state,
+ .set_coverage_class = ath9k_set_coverage_class,
};
-
-static int __init ath9k_init(void)
-{
- int error;
-
- /* Register rate control algorithm */
- error = ath_rate_control_register();
- if (error != 0) {
- printk(KERN_ERR
- "ath9k: Unable to register rate control "
- "algorithm: %d\n",
- error);
- goto err_out;
- }
-
- error = ath9k_debug_create_root();
- if (error) {
- printk(KERN_ERR
- "ath9k: Unable to create debugfs root: %d\n",
- error);
- goto err_rate_unregister;
- }
-
- error = ath_pci_init();
- if (error < 0) {
- printk(KERN_ERR
- "ath9k: No PCI devices found, driver not installed.\n");
- error = -ENODEV;
- goto err_remove_root;
- }
-
- error = ath_ahb_init();
- if (error < 0) {
- error = -ENODEV;
- goto err_pci_exit;
- }
-
- return 0;
-
- err_pci_exit:
- ath_pci_exit();
-
- err_remove_root:
- ath9k_debug_remove_root();
- err_rate_unregister:
- ath_rate_control_unregister();
- err_out:
- return error;
-}
-module_init(ath9k_init);
-
-static void __exit ath9k_exit(void)
-{
- ath_ahb_exit();
- ath_pci_exit();
- ath9k_debug_remove_root();
- ath_rate_control_unregister();
- printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
-}
-module_exit(ath9k_exit);
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index f7af5ea54753..9441c6718a30 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -18,13 +18,14 @@
#include <linux/pci.h>
#include "ath9k.h"
-static struct pci_device_id ath_pci_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
{ PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */
{ PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
{ PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
+ { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
{ PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
{ 0 }
@@ -49,16 +50,6 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz)
*csz = DEFAULT_CACHELINE >> 2; /* Use the default size */
}
-static void ath_pci_cleanup(struct ath_common *common)
-{
- struct ath_softc *sc = (struct ath_softc *) common->priv;
- struct pci_dev *pdev = to_pci_dev(sc->dev);
-
- pci_iounmap(pdev, sc->mem);
- pci_disable_device(pdev);
- pci_release_region(pdev, 0);
-}
-
static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{
struct ath_hw *ah = (struct ath_hw *) common->ah;
@@ -98,7 +89,6 @@ static void ath_pci_bt_coex_prep(struct ath_common *common)
static const struct ath_bus_ops ath_pci_bus_ops = {
.read_cachesize = ath_pci_read_cachesize,
- .cleanup = ath_pci_cleanup,
.eeprom_read = ath_pci_eeprom_read,
.bt_coex_prep = ath_pci_bt_coex_prep,
};
@@ -113,25 +103,22 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
u16 subsysid;
u32 val;
int ret = 0;
- struct ath_hw *ah;
char hw_name[64];
if (pci_enable_device(pdev))
return -EIO;
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-
if (ret) {
printk(KERN_ERR "ath9k: 32-bit DMA not available\n");
- goto bad;
+ goto err_dma;
}
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-
if (ret) {
printk(KERN_ERR "ath9k: 32-bit DMA consistent "
"DMA enable failed\n");
- goto bad;
+ goto err_dma;
}
/*
@@ -171,22 +158,22 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret) {
dev_err(&pdev->dev, "PCI memory region reserve error\n");
ret = -ENODEV;
- goto bad;
+ goto err_region;
}
mem = pci_iomap(pdev, 0, 0);
if (!mem) {
printk(KERN_ERR "PCI memory map error\n") ;
ret = -EIO;
- goto bad1;
+ goto err_iomap;
}
hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) +
sizeof(struct ath_softc), &ath9k_ops);
if (!hw) {
- dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
+ dev_err(&pdev->dev, "No memory for ieee80211_hw\n");
ret = -ENOMEM;
- goto bad2;
+ goto err_alloc_hw;
}
SET_IEEE80211_DEV(hw, &pdev->dev);
@@ -201,25 +188,25 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sc->dev = &pdev->dev;
sc->mem = mem;
- pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid);
- ret = ath_init_device(id->device, sc, subsysid, &ath_pci_bus_ops);
- if (ret) {
- dev_err(&pdev->dev, "failed to initialize device\n");
- goto bad3;
- }
-
- /* setup interrupt service routine */
+ /* Will be cleared in ath9k_start() */
+ sc->sc_flags |= SC_OP_INVALID;
ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc);
if (ret) {
dev_err(&pdev->dev, "request_irq failed\n");
- goto bad4;
+ goto err_irq;
}
sc->irq = pdev->irq;
- ah = sc->sc_ah;
- ath9k_hw_name(ah, hw_name, sizeof(hw_name));
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid);
+ ret = ath9k_init_device(id->device, sc, subsysid, &ath_pci_bus_ops);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize device\n");
+ goto err_init;
+ }
+
+ ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name));
printk(KERN_INFO
"%s: %s mem=0x%lx, irq=%d\n",
wiphy_name(hw->wiphy),
@@ -227,15 +214,18 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
(unsigned long)mem, pdev->irq);
return 0;
-bad4:
- ath_detach(sc);
-bad3:
+
+err_init:
+ free_irq(sc->irq, sc);
+err_irq:
ieee80211_free_hw(hw);
-bad2:
+err_alloc_hw:
pci_iounmap(pdev, mem);
-bad1:
+err_iomap:
pci_release_region(pdev, 0);
-bad:
+err_region:
+ /* Nothing */
+err_dma:
pci_disable_device(pdev);
return ret;
}
@@ -245,8 +235,15 @@ static void ath_pci_remove(struct pci_dev *pdev)
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ void __iomem *mem = sc->mem;
+
+ ath9k_deinit_device(sc);
+ free_irq(sc->irq, sc);
+ ieee80211_free_hw(sc->hw);
- ath_cleanup(sc);
+ pci_iounmap(pdev, mem);
+ pci_disable_device(pdev);
+ pci_release_region(pdev, 0);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index 31de27dc0c4a..0999a495fd46 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -384,6 +384,9 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
#define AR_PHY_HEAVY_CLIP_ENABLE 0x99E0
+#define AR_PHY_HEAVY_CLIP_FACTOR_RIFS 0x99EC
+#define AR_PHY_RIFS_INIT_DELAY 0x03ff0000
+
#define AR_PHY_M_SLEEP 0x99f0
#define AR_PHY_REFCLKDLY 0x99f4
#define AR_PHY_REFCLKPD 0x99f8
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 70fdb9d8db82..0e79e58cf4c9 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -668,7 +668,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
struct ieee80211_tx_rate *rates = tx_info->control.rates;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
- u8 try_per_rate, i = 0, rix, nrix;
+ u8 try_per_rate, i = 0, rix;
int is_probe = 0;
if (rate_control_send_low(sta, priv_sta, txrc))
@@ -678,48 +678,47 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
* For Multi Rate Retry we use a different number of
* retry attempt counts. This ends up looking like this:
*
- * MRR[0] = 2
- * MRR[1] = 2
- * MRR[2] = 2
- * MRR[3] = 4
+ * MRR[0] = 4
+ * MRR[1] = 4
+ * MRR[2] = 4
+ * MRR[3] = 8
*
*/
- try_per_rate = sc->hw->max_rate_tries;
+ try_per_rate = 4;
rate_table = sc->cur_rate_table;
rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
- nrix = rix;
if (is_probe) {
/* set one try for probe rates. For the
* probes don't enable rts */
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
- 1, nrix, 0);
+ 1, rix, 0);
/* Get the next tried/allowed rate. No RTS for the next series
* after the probe rate
*/
- ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
- try_per_rate, nrix, 0);
+ try_per_rate, rix, 0);
tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
} else {
/* Set the choosen rate. No RTS for first series entry. */
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
- try_per_rate, nrix, 0);
+ try_per_rate, rix, 0);
}
/* Fill in the other rates for multirate retry */
for ( ; i < 4; i++) {
/* Use twice the number of tries for the last MRR segment. */
if (i + 1 == 4)
- try_per_rate = 4;
+ try_per_rate = 8;
- ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
/* All other rates in the series have RTS enabled */
ath_rc_rate_set_series(rate_table, &rates[i], txrc,
- try_per_rate, nrix, 1);
+ try_per_rate, rix, 1);
}
/*
@@ -1324,7 +1323,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
- u32 changed)
+ u32 changed, enum nl80211_channel_type oper_chan_type)
{
struct ath_softc *sc = priv;
struct ath_rate_priv *ath_rc_priv = priv_sta;
@@ -1341,8 +1340,8 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
return;
- if (sc->hw->conf.channel_type == NL80211_CHAN_HT40MINUS ||
- sc->hw->conf.channel_type == NL80211_CHAN_HT40PLUS)
+ if (oper_chan_type == NL80211_CHAN_HT40MINUS ||
+ oper_chan_type == NL80211_CHAN_HT40PLUS)
oper_cw40 = true;
oper_sgi40 = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index 9eb96f506998..4f6d6fd442f4 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -57,6 +57,10 @@ enum {
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+#define WLAN_RC_PHY_20(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS) \
+ || (_phy == WLAN_RC_PHY_HT_20_DS) \
+ || (_phy == WLAN_RC_PHY_HT_20_SS_HGI) \
+ || (_phy == WLAN_RC_PHY_HT_20_DS_HGI))
#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 477365e5ae69..1ca42e5148c8 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -364,10 +364,10 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0)
return; /* not from our current AP */
- sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
+ sc->ps_flags &= ~PS_WAIT_FOR_BEACON;
- if (sc->sc_flags & SC_OP_BEACON_SYNC) {
- sc->sc_flags &= ~SC_OP_BEACON_SYNC;
+ if (sc->ps_flags & PS_BEACON_SYNC) {
+ sc->ps_flags &= ~PS_BEACON_SYNC;
ath_print(common, ATH_DBG_PS,
"Reconfigure Beacon timers based on "
"timestamp from the AP\n");
@@ -384,17 +384,17 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
*/
ath_print(common, ATH_DBG_PS, "Received DTIM beacon indicating "
"buffered broadcast/multicast frame(s)\n");
- sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON;
+ sc->ps_flags |= PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON;
return;
}
- if (sc->sc_flags & SC_OP_WAIT_FOR_CAB) {
+ if (sc->ps_flags & PS_WAIT_FOR_CAB) {
/*
* This can happen if a broadcast frame is dropped or the AP
* fails to send a frame indicating that all CAB frames have
* been delivered.
*/
- sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
+ sc->ps_flags &= ~PS_WAIT_FOR_CAB;
ath_print(common, ATH_DBG_PS,
"PS wait for CAB frames timed out\n");
}
@@ -408,10 +408,10 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
hdr = (struct ieee80211_hdr *)skb->data;
/* Process Beacon and CAB receive in PS state */
- if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) &&
+ if ((sc->ps_flags & PS_WAIT_FOR_BEACON) &&
ieee80211_is_beacon(hdr->frame_control))
ath_rx_ps_beacon(sc, skb);
- else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) &&
+ else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
(ieee80211_is_data(hdr->frame_control) ||
ieee80211_is_action(hdr->frame_control)) &&
is_multicast_ether_addr(hdr->addr1) &&
@@ -420,20 +420,20 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
* No more broadcast/multicast frames to be received at this
* point.
*/
- sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
+ sc->ps_flags &= ~PS_WAIT_FOR_CAB;
ath_print(common, ATH_DBG_PS,
"All PS CAB frames received, back to sleep\n");
- } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) &&
+ } else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) &&
!is_multicast_ether_addr(hdr->addr1) &&
!ieee80211_has_morefrags(hdr->frame_control)) {
- sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA;
+ sc->ps_flags &= ~PS_WAIT_FOR_PSPOLL_DATA;
ath_print(common, ATH_DBG_PS,
"Going back to sleep after having received "
- "PS-Poll data (0x%x)\n",
- sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
- SC_OP_WAIT_FOR_CAB |
- SC_OP_WAIT_FOR_PSPOLL_DATA |
- SC_OP_WAIT_FOR_TX_ACK));
+ "PS-Poll data (0x%lx)\n",
+ sc->ps_flags & (PS_WAIT_FOR_BEACON |
+ PS_WAIT_FOR_CAB |
+ PS_WAIT_FOR_PSPOLL_DATA |
+ PS_WAIT_FOR_TX_ACK));
}
}
@@ -571,6 +571,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
hw = ath_get_virt_hw(sc, hdr);
rx_stats = &ds->ds_rxstat;
+ ath_debug_stat_rx(sc, bf);
+
/*
* If we're asked to flush receive queue, directly
* chain it back at the queue without processing it.
@@ -631,9 +633,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
sc->rx.rxotherant = 0;
}
- if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
- SC_OP_WAIT_FOR_CAB |
- SC_OP_WAIT_FOR_PSPOLL_DATA)))
+ if (unlikely(sc->ps_flags & (PS_WAIT_FOR_BEACON |
+ PS_WAIT_FOR_CAB |
+ PS_WAIT_FOR_PSPOLL_DATA)))
ath_rx_ps(sc, skb);
ath_rx_send_to_mac80211(hw, sc, skb, rxs);
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 8e653fb937a1..72cfa8ebd9ae 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -1547,9 +1547,9 @@ enum {
#define AR_BT_COEX_WEIGHT 0x8174
#define AR_BT_COEX_WGHT 0xff55
-#define AR_STOMP_ALL_WLAN_WGHT 0xffcc
-#define AR_STOMP_LOW_WLAN_WGHT 0xaaa8
-#define AR_STOMP_NONE_WLAN_WGHT 0xaa00
+#define AR_STOMP_ALL_WLAN_WGHT 0xfcfc
+#define AR_STOMP_LOW_WLAN_WGHT 0xa8a8
+#define AR_STOMP_NONE_WLAN_WGHT 0x0000
#define AR_BTCOEX_BT_WGHT 0x0000ffff
#define AR_BTCOEX_BT_WGHT_S 0
#define AR_BTCOEX_WL_WGHT 0xffff0000
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index cd26caaf44e7..a43fbf84dab9 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -152,7 +152,7 @@ int ath9k_wiphy_add(struct ath_softc *sc)
SET_IEEE80211_PERM_ADDR(hw, addr);
- ath_set_hw_capab(sc, hw);
+ ath9k_set_hw_capab(sc, hw);
error = ieee80211_register_hw(hw);
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index fa12b9060b0b..b2c8207f7bc1 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1498,26 +1498,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
ctsrate |= rate->hw_value_short;
- /*
- * ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive.
- * Check the first rate in the series to decide whether RTS/CTS
- * or CTS-to-self has to be used.
- */
- if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
- flags = ATH9K_TXDESC_CTSENA;
- else if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
- flags = ATH9K_TXDESC_RTSENA;
-
- /* FIXME: Handle aggregation protection */
- if (sc->config.ath_aggr_prot &&
- (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) {
- flags = ATH9K_TXDESC_RTSENA;
- }
-
- /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
- if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
- flags &= ~(ATH9K_TXDESC_RTSENA);
-
for (i = 0; i < 4; i++) {
bool is_40, is_sgi, is_sp;
int phy;
@@ -1529,8 +1509,15 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
series[i].Tries = rates[i].count;
series[i].ChSel = common->tx_chainmask;
- if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+ if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
+ (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
+ series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+ flags |= ATH9K_TXDESC_RTSENA;
+ } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+ flags |= ATH9K_TXDESC_CTSENA;
+ }
+
if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
series[i].RateFlags |= ATH9K_RATESERIES_2040;
if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
@@ -1568,6 +1555,14 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
}
+ /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
+ if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
+ flags &= ~ATH9K_TXDESC_RTSENA;
+
+ /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
+ if (flags & ATH9K_TXDESC_RTSENA)
+ flags &= ~ATH9K_TXDESC_CTSENA;
+
/* set dur_update_en for l-sig computation except for PS-Poll frames */
ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
bf->bf_lastbf->bf_desc,
@@ -1615,7 +1610,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
bf->bf_frmlen -= padsize;
}
- if (conf_is_ht(&hw->conf) && !is_pae(skb))
+ if (conf_is_ht(&hw->conf))
bf->bf_state.bf_type |= BUF_HT;
bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq);
@@ -1648,7 +1643,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
/* tag if this is a nullfunc frame to enable PS when AP acks it */
if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
bf->bf_isnullfunc = true;
- sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED;
+ sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
} else
bf->bf_isnullfunc = false;
@@ -1701,7 +1696,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
goto tx_done;
}
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && !is_pae(skb)) {
/*
* Try aggregation if it's a unicast data frame
* and the destination is HT capable.
@@ -1858,15 +1853,15 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
skb_pull(skb, padsize);
}
- if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) {
- sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK;
+ if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
+ sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
ath_print(common, ATH_DBG_PS,
"Going back to sleep after having "
- "received TX status (0x%x)\n",
- sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
- SC_OP_WAIT_FOR_CAB |
- SC_OP_WAIT_FOR_PSPOLL_DATA |
- SC_OP_WAIT_FOR_TX_ACK));
+ "received TX status (0x%lx)\n",
+ sc->ps_flags & (PS_WAIT_FOR_BEACON |
+ PS_WAIT_FOR_CAB |
+ PS_WAIT_FOR_PSPOLL_DATA |
+ PS_WAIT_FOR_TX_ACK));
}
if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
@@ -2053,11 +2048,10 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
*/
if (bf->bf_isnullfunc &&
(ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) {
- if ((sc->sc_flags & SC_OP_PS_ENABLED)) {
- sc->ps_enabled = true;
- ath9k_hw_setrxabort(sc->sc_ah, 1);
- } else
- sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED;
+ if ((sc->ps_flags & PS_ENABLED))
+ ath9k_enable_ps(sc);
+ else
+ sc->ps_flags |= PS_NULLFUNC_COMPLETED;
}
/*
@@ -2264,7 +2258,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
if (ATH_TXQ_SETUP(sc, i)) {
txq = &sc->tx.txq[i];
- spin_lock(&txq->axq_lock);
+ spin_lock_bh(&txq->axq_lock);
list_for_each_entry_safe(ac,
ac_tmp, &txq->axq_acq, list) {
@@ -2285,7 +2279,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
}
}
- spin_unlock(&txq->axq_lock);
+ spin_unlock_bh(&txq->axq_lock);
}
}
}
diff --git a/drivers/net/wireless/ath/debug.h b/drivers/net/wireless/ath/debug.h
index d6b685a06c5e..8263633c003c 100644
--- a/drivers/net/wireless/ath/debug.h
+++ b/drivers/net/wireless/ath/debug.h
@@ -65,11 +65,11 @@ enum ATH_DEBUG {
#define ATH_DBG_DEFAULT (ATH_DBG_FATAL)
#ifdef CONFIG_ATH_DEBUG
-void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...);
+void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
#else
-static inline void ath_print(struct ath_common *common,
- int dbg_mask,
- const char *fmt, ...)
+static inline void __attribute__ ((format (printf, 3, 4)))
+ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...)
{
}
#endif /* CONFIG_ATH_DEBUG */
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index 039ac490465c..04abd1f556b7 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -110,8 +110,9 @@ static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = {
static inline bool is_wwr_sku(u16 regd)
{
- return ((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||
- (regd == WORLD);
+ return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) &&
+ (((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||
+ (regd == WORLD));
}
static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg)
diff --git a/drivers/net/wireless/atmel_pci.c b/drivers/net/wireless/atmel_pci.c
index 92f87fbe750f..9ab1192004c0 100644
--- a/drivers/net/wireless/atmel_pci.c
+++ b/drivers/net/wireless/atmel_pci.c
@@ -31,7 +31,7 @@ MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.")
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("Atmel at76c506 PCI wireless cards");
-static struct pci_device_id card_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(card_ids) = {
{ 0x1114, 0x0506, PCI_ANY_ID, PCI_ANY_ID },
{ 0, }
};
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 64c12e1bced3..0a00d42642cd 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -78,11 +78,11 @@ config B43_SDIO
If unsure, say N.
-# Data transfers to the device via PIO
-# This is only needed on PCMCIA and SDIO devices. All others can do DMA properly.
+#Data transfers to the device via PIO. We want it as a fallback even
+# if we can do DMA.
config B43_PIO
bool
- depends on B43 && (B43_SDIO || B43_PCMCIA || B43_FORCE_PIO)
+ depends on B43
select SSB_BLOCKIO
default y
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
index 84772a2542dc..5e83b6f0a3a0 100644
--- a/drivers/net/wireless/b43/Makefile
+++ b/drivers/net/wireless/b43/Makefile
@@ -12,7 +12,7 @@ b43-y += xmit.o
b43-y += lo.o
b43-y += wa.o
b43-y += dma.o
-b43-$(CONFIG_B43_PIO) += pio.o
+b43-y += pio.o
b43-y += rfkill.o
b43-$(CONFIG_B43_LEDS) += leds.o
b43-$(CONFIG_B43_PCMCIA) += pcmcia.o
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index fe3bf9491997..b8807fb12c92 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -115,6 +115,7 @@
#define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */
#define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */
#define B43_MMIO_RNG 0x65A
+#define B43_MMIO_IFSSLOT 0x684 /* Interframe slot time */
#define B43_MMIO_IFSCTL 0x688 /* Interframe space control */
#define B43_MMIO_IFSCTL_USE_EDCF 0x0004
#define B43_MMIO_POWERUP_DELAY 0x6A8
@@ -253,6 +254,14 @@ enum {
#define B43_SHM_SH_MAXBFRAMES 0x0080 /* Maximum number of frames in a burst */
#define B43_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */
#define B43_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */
+/* SHM_SHARED tx iq workarounds */
+#define B43_SHM_SH_NPHY_TXIQW0 0x0700
+#define B43_SHM_SH_NPHY_TXIQW1 0x0702
+#define B43_SHM_SH_NPHY_TXIQW2 0x0704
+#define B43_SHM_SH_NPHY_TXIQW3 0x0706
+/* SHM_SHARED tx pwr ctrl */
+#define B43_SHM_SH_NPHY_TXPWR_INDX0 0x0708
+#define B43_SHM_SH_NPHY_TXPWR_INDX1 0x070E
/* SHM_SCRATCH offsets */
#define B43_SHM_SC_MINCONT 0x0003 /* Minimum contention window */
@@ -693,6 +702,7 @@ struct b43_wldev {
bool radio_hw_enable; /* saved state of radio hardware enabled state */
bool qos_enabled; /* TRUE, if QoS is used. */
bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */
+ bool use_pio; /* TRUE if next init should use PIO */
/* PHY/Radio device. */
struct b43_phy phy;
@@ -821,11 +831,9 @@ struct b43_wl {
/* The device LEDs. */
struct b43_leds leds;
-#ifdef CONFIG_B43_PIO
/* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */
u8 pio_scratchspace[110] __attribute__((__aligned__(8)));
u8 pio_tailspace[4] __attribute__((__aligned__(8)));
-#endif /* CONFIG_B43_PIO */
};
static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
@@ -876,20 +884,15 @@ static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)
static inline bool b43_using_pio_transfers(struct b43_wldev *dev)
{
-#ifdef CONFIG_B43_PIO
return dev->__using_pio_transfers;
-#else
- return 0;
-#endif
}
#ifdef CONFIG_B43_FORCE_PIO
-# define B43_FORCE_PIO 1
+# define B43_PIO_DEFAULT 1
#else
-# define B43_FORCE_PIO 0
+# define B43_PIO_DEFAULT 0
#endif
-
/* Message printing */
void b43info(struct b43_wl *wl, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 88d1fd02d40a..be7abf8916ad 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -1369,7 +1369,6 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
b43err(dev->wl, "DMA tx mapping failure\n");
goto out;
}
- ring->nr_tx_packets++;
if ((free_slots(ring) < TX_SLOTS_PER_FRAME) ||
should_inject_overflow(ring)) {
/* This TX ring is full. */
@@ -1500,22 +1499,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
}
}
-void b43_dma_get_tx_stats(struct b43_wldev *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
- const int nr_queues = dev->wl->hw->queues;
- struct b43_dmaring *ring;
- int i;
-
- for (i = 0; i < nr_queues; i++) {
- ring = select_ring_by_priority(dev, i);
-
- stats[i].len = ring->used_slots / TX_SLOTS_PER_FRAME;
- stats[i].limit = ring->nr_slots / TX_SLOTS_PER_FRAME;
- stats[i].count = ring->nr_tx_packets;
- }
-}
-
static void dma_rx(struct b43_dmaring *ring, int *slot)
{
const struct b43_dma_ops *ops = ring->ops;
@@ -1653,7 +1636,6 @@ void b43_dma_tx_resume(struct b43_wldev *dev)
b43_power_saving_ctl_bits(dev, 0);
}
-#ifdef CONFIG_B43_PIO
static void direct_fifo_rx(struct b43_wldev *dev, enum b43_dmatype type,
u16 mmio_base, bool enable)
{
@@ -1687,4 +1669,3 @@ void b43_dma_direct_fifo_rx(struct b43_wldev *dev,
mmio_base = b43_dmacontroller_base(type, engine_index);
direct_fifo_rx(dev, type, mmio_base, enable);
}
-#endif /* CONFIG_B43_PIO */
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index f7ab37c4cdbc..dc91944d6022 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -228,8 +228,6 @@ struct b43_dmaring {
int used_slots;
/* Currently used slot in the ring. */
int current_slot;
- /* Total number of packets sent. Statistics only. */
- unsigned int nr_tx_packets;
/* Frameoffset in octets. */
u32 frameoffset;
/* Descriptor buffer size. */
@@ -278,9 +276,6 @@ void b43_dma_free(struct b43_wldev *dev);
void b43_dma_tx_suspend(struct b43_wldev *dev);
void b43_dma_tx_resume(struct b43_wldev *dev);
-void b43_dma_get_tx_stats(struct b43_wldev *dev,
- struct ieee80211_tx_queue_stats *stats);
-
int b43_dma_tx(struct b43_wldev *dev,
struct sk_buff *skb);
void b43_dma_handle_txstatus(struct b43_wldev *dev,
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 4c41cfe44f26..1521b1e78d21 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -67,7 +67,12 @@ MODULE_AUTHOR("Gábor Stefanik");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID);
-
+MODULE_FIRMWARE("b43/ucode11.fw");
+MODULE_FIRMWARE("b43/ucode13.fw");
+MODULE_FIRMWARE("b43/ucode14.fw");
+MODULE_FIRMWARE("b43/ucode15.fw");
+MODULE_FIRMWARE("b43/ucode5.fw");
+MODULE_FIRMWARE("b43/ucode9.fw");
static int modparam_bad_frames_preempt;
module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
@@ -102,6 +107,9 @@ int b43_modparam_verbose = B43_VERBOSITY_DEFAULT;
module_param_named(verbose, b43_modparam_verbose, int, 0644);
MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
+int b43_modparam_pio = B43_PIO_DEFAULT;
+module_param_named(pio, b43_modparam_pio, int, 0644);
+MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO");
static const struct ssb_device_id b43_ssb_tbl[] = {
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
@@ -110,6 +118,7 @@ static const struct ssb_device_id b43_ssb_tbl[] = {
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 12),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16),
@@ -628,10 +637,17 @@ static void b43_upload_card_macaddress(struct b43_wldev *dev)
static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
{
/* slot_time is in usec. */
- if (dev->phy.type != B43_PHYTYPE_G)
+ /* This test used to exit for all but a G PHY. */
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
return;
- b43_write16(dev, 0x684, 510 + slot_time);
- b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
+ b43_write16(dev, B43_MMIO_IFSSLOT, 510 + slot_time);
+ /* Shared memory location 0x0010 is the slot time and should be
+ * set to slot_time; however, this register is initially 0 and changing
+ * the value adversely affects the transmit rate for BCM4311
+ * devices. Until this behavior is unterstood, delete this step
+ *
+ * b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
+ */
}
static void b43_short_slot_timing_enable(struct b43_wldev *dev)
@@ -835,8 +851,10 @@ static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32,
}
static void b43_op_update_tkip_key(struct ieee80211_hw *hw,
- struct ieee80211_key_conf *keyconf, const u8 *addr,
- u32 iv32, u16 *phase1key)
+ struct ieee80211_vif *vif,
+ struct ieee80211_key_conf *keyconf,
+ struct ieee80211_sta *sta,
+ u32 iv32, u16 *phase1key)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev;
@@ -845,19 +863,19 @@ static void b43_op_update_tkip_key(struct ieee80211_hw *hw,
if (B43_WARN_ON(!modparam_hwtkip))
return;
- mutex_lock(&wl->mutex);
-
+ /* This is only called from the RX path through mac80211, where
+ * our mutex is already locked. */
+ B43_WARN_ON(!mutex_is_locked(&wl->mutex));
dev = wl->current_dev;
- if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
- goto out_unlock;
+ B43_WARN_ON(!dev || b43_status(dev) < B43_STAT_INITIALIZED);
keymac_write(dev, index, NULL); /* First zero out mac to avoid race */
rx_tkip_phase1_write(dev, index, iv32, phase1key);
- keymac_write(dev, index, addr);
-
-out_unlock:
- mutex_unlock(&wl->mutex);
+ /* only pairwise TKIP keys are supported right now */
+ if (WARN_ON(!sta))
+ return;
+ keymac_write(dev, index, sta->addr);
}
static void do_key_write(struct b43_wldev *dev,
@@ -1786,8 +1804,9 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev)
dma_reason[4], dma_reason[5]);
b43err(dev->wl, "This device does not support DMA "
"on your system. Please use PIO instead.\n");
- b43err(dev->wl, "CONFIG_B43_FORCE_PIO must be set in "
- "your kernel configuration.\n");
+ /* Fall back to PIO transfers if we get fatal DMA errors! */
+ dev->use_pio = 1;
+ b43_controller_restart(dev, "DMA error");
return;
}
if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
@@ -3338,27 +3357,6 @@ out_unlock:
return err;
}
-static int b43_op_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct b43_wl *wl = hw_to_b43_wl(hw);
- struct b43_wldev *dev;
- int err = -ENODEV;
-
- mutex_lock(&wl->mutex);
- dev = wl->current_dev;
- if (dev && b43_status(dev) >= B43_STAT_STARTED) {
- if (b43_using_pio_transfers(dev))
- b43_pio_get_tx_stats(dev, stats);
- else
- b43_dma_get_tx_stats(dev, stats);
- err = 0;
- }
- mutex_unlock(&wl->mutex);
-
- return err;
-}
-
static int b43_op_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
@@ -3562,6 +3560,12 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
dev = wl->current_dev;
phy = &dev->phy;
+ if (conf_is_ht(conf))
+ phy->is_40mhz =
+ (conf_is_ht40_minus(conf) || conf_is_ht40_plus(conf));
+ else
+ phy->is_40mhz = false;
+
b43_mac_suspend(dev);
if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
@@ -3963,6 +3967,7 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
}
/* We are ready to run. */
+ ieee80211_wake_queues(dev->wl->hw);
b43_set_status(dev, B43_STAT_STARTED);
/* Start data flow (TX/RX). */
@@ -4353,7 +4358,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
(dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) ||
- B43_FORCE_PIO) {
+ dev->use_pio) {
dev->__using_pio_transfers = 1;
err = b43_pio_init(dev);
} else {
@@ -4372,8 +4377,6 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
ieee80211_wake_queues(dev->wl->hw);
- ieee80211_wake_queues(dev->wl->hw);
-
b43_set_status(dev, B43_STAT_INITIALIZED);
out:
@@ -4388,7 +4391,7 @@ err_busdown:
}
static int b43_op_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev;
@@ -4396,24 +4399,24 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
/* TODO: allow WDS/AP devices to coexist */
- if (conf->type != NL80211_IFTYPE_AP &&
- conf->type != NL80211_IFTYPE_MESH_POINT &&
- conf->type != NL80211_IFTYPE_STATION &&
- conf->type != NL80211_IFTYPE_WDS &&
- conf->type != NL80211_IFTYPE_ADHOC)
+ if (vif->type != NL80211_IFTYPE_AP &&
+ vif->type != NL80211_IFTYPE_MESH_POINT &&
+ vif->type != NL80211_IFTYPE_STATION &&
+ vif->type != NL80211_IFTYPE_WDS &&
+ vif->type != NL80211_IFTYPE_ADHOC)
return -EOPNOTSUPP;
mutex_lock(&wl->mutex);
if (wl->operating)
goto out_mutex_unlock;
- b43dbg(wl, "Adding Interface type %d\n", conf->type);
+ b43dbg(wl, "Adding Interface type %d\n", vif->type);
dev = wl->current_dev;
wl->operating = 1;
- wl->vif = conf->vif;
- wl->if_type = conf->type;
- memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+ wl->vif = vif;
+ wl->if_type = vif->type;
+ memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
b43_adjust_opmode(dev);
b43_set_pretbtt(dev);
@@ -4428,17 +4431,17 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
}
static void b43_op_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev = wl->current_dev;
- b43dbg(wl, "Removing Interface type %d\n", conf->type);
+ b43dbg(wl, "Removing Interface type %d\n", vif->type);
mutex_lock(&wl->mutex);
B43_WARN_ON(!wl->operating);
- B43_WARN_ON(wl->vif != conf->vif);
+ B43_WARN_ON(wl->vif != vif);
wl->vif = NULL;
wl->operating = 0;
@@ -4579,7 +4582,6 @@ static const struct ieee80211_ops b43_hw_ops = {
.set_key = b43_op_set_key,
.update_tkip_key = b43_op_update_tkip_key,
.get_stats = b43_op_get_stats,
- .get_tx_stats = b43_op_get_tx_stats,
.get_tsf = b43_op_get_tsf,
.set_tsf = b43_op_set_tsf,
.start = b43_op_start,
@@ -4823,6 +4825,7 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
if (!wldev)
goto out;
+ wldev->use_pio = b43_modparam_pio;
wldev->dev = dev;
wldev->wl = wl;
b43_set_status(wldev, B43_STAT_UNINIT);
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 75b26e175e8f..8f7d7eff2d80 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -421,3 +421,48 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on)
{
b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/Cordic */
+struct b43_c32 b43_cordic(int theta)
+{
+ u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304,
+ 58666, 29335, 14668, 7334, 3667, 1833, 917, 458,
+ 229, 115, 57, 29, };
+ u8 i;
+ s32 tmp;
+ s8 signx = 1;
+ u32 angle = 0;
+ struct b43_c32 ret = { .i = 39797, .q = 0, };
+
+ while (theta > (180 << 16))
+ theta -= (360 << 16);
+ while (theta < -(180 << 16))
+ theta += (360 << 16);
+
+ if (theta > (90 << 16)) {
+ theta -= (180 << 16);
+ signx = -1;
+ } else if (theta < -(90 << 16)) {
+ theta += (180 << 16);
+ signx = -1;
+ }
+
+ for (i = 0; i <= 17; i++) {
+ if (theta > angle) {
+ tmp = ret.i - (ret.q >> i);
+ ret.q += ret.i >> i;
+ ret.i = tmp;
+ angle += arctg[i];
+ } else {
+ tmp = ret.i + (ret.q >> i);
+ ret.q -= ret.i >> i;
+ ret.i = tmp;
+ angle -= arctg[i];
+ }
+ }
+
+ ret.i *= signx;
+ ret.q *= signx;
+
+ return ret;
+}
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h
index 9edd4e8e0c85..bd480b481bfc 100644
--- a/drivers/net/wireless/b43/phy_common.h
+++ b/drivers/net/wireless/b43/phy_common.h
@@ -5,6 +5,12 @@
struct b43_wldev;
+/* Complex number using 2 32-bit signed integers */
+struct b43_c32 { s32 i, q; };
+
+#define CORDIC_CONVERT(value) (((value) >= 0) ? \
+ ((((value) >> 15) + 1) >> 1) : \
+ -((((-(value)) >> 15) + 1) >> 1))
/* PHY register routing bits */
#define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */
@@ -212,6 +218,9 @@ struct b43_phy {
bool supports_2ghz;
bool supports_5ghz;
+ /* HT info */
+ bool is_40mhz;
+
/* GMODE bit enabled? */
bool gmode;
@@ -418,5 +427,6 @@ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset);
*/
void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on);
+struct b43_c32 b43_cordic(int theta);
#endif /* LINUX_B43_PHY_COMMON_H_ */
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index 3e046ec1ff86..185219e0a552 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -80,6 +80,7 @@ static void b43_lpphy_op_free(struct b43_wldev *dev)
dev->phy.lp = NULL;
}
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */
static void lpphy_read_band_sprom(struct b43_wldev *dev)
{
struct b43_phy_lp *lpphy = dev->phy.lp;
@@ -101,6 +102,12 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev)
maxpwr = bus->sprom.maxpwr_bg;
lpphy->max_tx_pwr_med_band = maxpwr;
cckpo = bus->sprom.cck2gpo;
+ /*
+ * We don't read SPROM's opo as specs say. On rev8 SPROMs
+ * opo == ofdm2gpo and we don't know any SSB with LP-PHY
+ * and SPROM rev below 8.
+ */
+ B43_WARN_ON(bus->sprom.revision < 8);
ofdmpo = bus->sprom.ofdm2gpo;
if (cckpo) {
for (i = 0; i < 4; i++) {
@@ -1703,19 +1710,6 @@ static const struct lpphy_rx_iq_comp lpphy_rev2plus_iq_comp = {
.c0 = 0,
};
-static u8 lpphy_nbits(s32 val)
-{
- u32 tmp = abs(val);
- u8 nbits = 0;
-
- while (tmp != 0) {
- nbits++;
- tmp >>= 1;
- }
-
- return nbits;
-}
-
static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples)
{
struct lpphy_iq_est iq_est;
@@ -1742,8 +1736,8 @@ static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples)
goto out;
}
- prod_msb = lpphy_nbits(prod);
- q_msb = lpphy_nbits(qpwr);
+ prod_msb = fls(abs(prod));
+ q_msb = fls(abs(qpwr));
tmp1 = prod_msb - 20;
if (tmp1 >= 0) {
@@ -1773,47 +1767,6 @@ out:
return ret;
}
-/* Complex number using 2 32-bit signed integers */
-typedef struct {s32 i, q;} lpphy_c32;
-
-static lpphy_c32 lpphy_cordic(int theta)
-{
- u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304,
- 58666, 29335, 14668, 7334, 3667, 1833, 917, 458,
- 229, 115, 57, 29, };
- int i, tmp, signx = 1, angle = 0;
- lpphy_c32 ret = { .i = 39797, .q = 0, };
-
- theta = clamp_t(int, theta, -180, 180);
-
- if (theta > 90) {
- theta -= 180;
- signx = -1;
- } else if (theta < -90) {
- theta += 180;
- signx = -1;
- }
-
- for (i = 0; i <= 17; i++) {
- if (theta > angle) {
- tmp = ret.i - (ret.q >> i);
- ret.q += ret.i >> i;
- ret.i = tmp;
- angle += arctg[i];
- } else {
- tmp = ret.i + (ret.q >> i);
- ret.q -= ret.i >> i;
- ret.i = tmp;
- angle -= arctg[i];
- }
- }
-
- ret.i *= signx;
- ret.q *= signx;
-
- return ret;
-}
-
static void lpphy_run_samples(struct b43_wldev *dev, u16 samples, u16 loops,
u16 wait)
{
@@ -1831,8 +1784,9 @@ static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max)
{
struct b43_phy_lp *lpphy = dev->phy.lp;
u16 buf[64];
- int i, samples = 0, angle = 0, rotation = (9 * freq) / 500;
- lpphy_c32 sample;
+ int i, samples = 0, angle = 0;
+ int rotation = (((36 * freq) / 20) << 16) / 100;
+ struct b43_c32 sample;
lpphy->tx_tone_freq = freq;
@@ -1848,10 +1802,10 @@ static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max)
}
for (i = 0; i < samples; i++) {
- sample = lpphy_cordic(angle);
+ sample = b43_cordic(angle);
angle += rotation;
- buf[i] = ((sample.i * max) & 0xFF) << 8;
- buf[i] |= (sample.q * max) & 0xFF;
+ buf[i] = CORDIC_CONVERT((sample.i * max) & 0xFF) << 8;
+ buf[i] |= CORDIC_CONVERT((sample.q * max) & 0xFF);
}
b43_lptab_write_bulk(dev, B43_LPTAB16(5, 0), samples, buf);
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 992318a78077..795bb1e3345d 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -28,7 +28,50 @@
#include "b43.h"
#include "phy_n.h"
#include "tables_nphy.h"
+#include "main.h"
+struct nphy_txgains {
+ u16 txgm[2];
+ u16 pga[2];
+ u16 pad[2];
+ u16 ipa[2];
+};
+
+struct nphy_iqcal_params {
+ u16 txgm;
+ u16 pga;
+ u16 pad;
+ u16 ipa;
+ u16 cal_gain;
+ u16 ncorr[5];
+};
+
+struct nphy_iq_est {
+ s32 iq0_prod;
+ u32 i0_pwr;
+ u32 q0_pwr;
+ s32 iq1_prod;
+ u32 i1_pwr;
+ u32 q1_pwr;
+};
+
+enum b43_nphy_rf_sequence {
+ B43_RFSEQ_RX2TX,
+ B43_RFSEQ_TX2RX,
+ B43_RFSEQ_RESET2RX,
+ B43_RFSEQ_UPDATE_GAINH,
+ B43_RFSEQ_UPDATE_GAINL,
+ B43_RFSEQ_UPDATE_GAINU,
+};
+
+static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
+ u8 *events, u8 *delays, u8 length);
+static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
+ enum b43_nphy_rf_sequence seq);
+static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
+ u16 value, u8 core, bool off);
+static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
+ u16 value, u8 core);
void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
{//TODO
@@ -197,173 +240,1020 @@ void b43_nphy_radio_turn_off(struct b43_wldev *dev)
~B43_NPHY_RFCTL_CMD_EN);
}
-#define ntab_upload(dev, offset, data) do { \
- unsigned int i; \
- for (i = 0; i < (offset##_SIZE); i++) \
- b43_ntab_write(dev, (offset) + i, (data)[i]); \
- } while (0)
-
-/* Upload the N-PHY tables. */
+/*
+ * Upload the N-PHY tables.
+ * http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables
+ */
static void b43_nphy_tables_init(struct b43_wldev *dev)
{
- /* Static tables */
- ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct);
- ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup);
- ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap);
- ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn);
- ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel);
- ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot);
- ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
- ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0);
- ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1);
- ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0);
- ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1);
- ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
- ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest);
- ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs);
-
- /* Volatile tables */
- ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10);
- ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11);
- ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0);
- ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1);
- ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0);
- ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1);
- ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
- ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
- ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0);
- ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1);
- ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0);
- ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1);
+ if (dev->phy.rev < 3)
+ b43_nphy_rev0_1_2_tables_init(dev);
+ else
+ b43_nphy_rev3plus_tables_init(dev);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */
+static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ enum ieee80211_band band;
+ u16 tmp;
+
+ if (!enable) {
+ nphy->rfctrl_intc1_save = b43_phy_read(dev,
+ B43_NPHY_RFCTL_INTC1);
+ nphy->rfctrl_intc2_save = b43_phy_read(dev,
+ B43_NPHY_RFCTL_INTC2);
+ band = b43_current_band(dev->wl);
+ if (dev->phy.rev >= 3) {
+ if (band == IEEE80211_BAND_5GHZ)
+ tmp = 0x600;
+ else
+ tmp = 0x480;
+ } else {
+ if (band == IEEE80211_BAND_5GHZ)
+ tmp = 0x180;
+ else
+ tmp = 0x120;
+ }
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, tmp);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, tmp);
+ } else {
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC1,
+ nphy->rfctrl_intc1_save);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC2,
+ nphy->rfctrl_intc2_save);
+ }
}
-static void b43_nphy_workarounds(struct b43_wldev *dev)
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw */
+static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ u16 tmp;
+ enum ieee80211_band band = b43_current_band(dev->wl);
+ bool ipa = (nphy->ipa2g_on && band == IEEE80211_BAND_2GHZ) ||
+ (nphy->ipa5g_on && band == IEEE80211_BAND_5GHZ);
+
+ if (dev->phy.rev >= 3) {
+ if (ipa) {
+ tmp = 4;
+ b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2,
+ (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp);
+ }
+
+ tmp = 1;
+ b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S2,
+ (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp);
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */
+static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force)
+{
+ u32 tmslow;
+
+ if (dev->phy.type != B43_PHYTYPE_N)
+ return;
+
+ tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+ if (force)
+ tmslow |= SSB_TMSLOW_FGC;
+ else
+ tmslow &= ~SSB_TMSLOW_FGC;
+ ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */
+static void b43_nphy_reset_cca(struct b43_wldev *dev)
+{
+ u16 bbcfg;
+
+ b43_nphy_bmac_clock_fgc(dev, 1);
+ bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
+ b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg | B43_NPHY_BBCFG_RSTCCA);
+ udelay(1);
+ b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
+ b43_nphy_bmac_clock_fgc(dev, 0);
+ b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MIMOConfig */
+static void b43_nphy_update_mimo_config(struct b43_wldev *dev, s32 preamble)
+{
+ u16 mimocfg = b43_phy_read(dev, B43_NPHY_MIMOCFG);
+
+ mimocfg |= B43_NPHY_MIMOCFG_AUTO;
+ if (preamble == 1)
+ mimocfg |= B43_NPHY_MIMOCFG_GFMIX;
+ else
+ mimocfg &= ~B43_NPHY_MIMOCFG_GFMIX;
+
+ b43_phy_write(dev, B43_NPHY_MIMOCFG, mimocfg);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */
+static void b43_nphy_update_txrx_chain(struct b43_wldev *dev)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+
+ bool override = false;
+ u16 chain = 0x33;
+
+ if (nphy->txrx_chain == 0) {
+ chain = 0x11;
+ override = true;
+ } else if (nphy->txrx_chain == 1) {
+ chain = 0x22;
+ override = true;
+ }
+
+ b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
+ ~(B43_NPHY_RFSEQCA_TXEN | B43_NPHY_RFSEQCA_RXEN),
+ chain);
+
+ if (override)
+ b43_phy_set(dev, B43_NPHY_RFSEQMODE,
+ B43_NPHY_RFSEQMODE_CAOVER);
+ else
+ b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+ ~B43_NPHY_RFSEQMODE_CAOVER);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */
+static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est,
+ u16 samps, u8 time, bool wait)
+{
+ int i;
+ u16 tmp;
+
+ b43_phy_write(dev, B43_NPHY_IQEST_SAMCNT, samps);
+ b43_phy_maskset(dev, B43_NPHY_IQEST_WT, ~B43_NPHY_IQEST_WT_VAL, time);
+ if (wait)
+ b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_MODE);
+ else
+ b43_phy_mask(dev, B43_NPHY_IQEST_CMD, ~B43_NPHY_IQEST_CMD_MODE);
+
+ b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_START);
+
+ for (i = 1000; i; i--) {
+ tmp = b43_phy_read(dev, B43_NPHY_IQEST_CMD);
+ if (!(tmp & B43_NPHY_IQEST_CMD_START)) {
+ est->i0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI0) << 16) |
+ b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO0);
+ est->q0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI0) << 16) |
+ b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO0);
+ est->iq0_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI0) << 16) |
+ b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO0);
+
+ est->i1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI1) << 16) |
+ b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO1);
+ est->q1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI1) << 16) |
+ b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO1);
+ est->iq1_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI1) << 16) |
+ b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO1);
+ return;
+ }
+ udelay(10);
+ }
+ memset(est, 0, sizeof(*est));
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqCoeffs */
+static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write,
+ struct b43_phy_n_iq_comp *pcomp)
+{
+ if (write) {
+ b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPA0, pcomp->a0);
+ b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPB0, pcomp->b0);
+ b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPA1, pcomp->a1);
+ b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPB1, pcomp->b1);
+ } else {
+ pcomp->a0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPA0);
+ pcomp->b0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPB0);
+ pcomp->a1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPA1);
+ pcomp->b1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPB1);
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhyCleanup */
+static void b43_nphy_rx_cal_phy_cleanup(struct b43_wldev *dev, u8 core)
+{
+ u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs;
+
+ b43_phy_write(dev, B43_NPHY_RFSEQCA, regs[0]);
+ if (core == 0) {
+ b43_phy_write(dev, B43_NPHY_AFECTL_C1, regs[1]);
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, regs[2]);
+ } else {
+ b43_phy_write(dev, B43_NPHY_AFECTL_C2, regs[1]);
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[2]);
+ }
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[3]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[4]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO1, regs[5]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO2, regs[6]);
+ b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, regs[7]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_OVER, regs[8]);
+ b43_phy_write(dev, B43_NPHY_PAPD_EN0, regs[9]);
+ b43_phy_write(dev, B43_NPHY_PAPD_EN1, regs[10]);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhySetup */
+static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core)
+{
+ u8 rxval, txval;
+ u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs;
+
+ regs[0] = b43_phy_read(dev, B43_NPHY_RFSEQCA);
+ if (core == 0) {
+ regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
+ regs[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1);
+ } else {
+ regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
+ regs[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+ }
+ regs[3] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
+ regs[4] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
+ regs[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1);
+ regs[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2);
+ regs[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S1);
+ regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER);
+ regs[9] = b43_phy_read(dev, B43_NPHY_PAPD_EN0);
+ regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1);
+
+ b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001);
+ b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001);
+
+ b43_phy_maskset(dev, B43_NPHY_RFSEQCA, (u16)~B43_NPHY_RFSEQCA_RXDIS,
+ ((1 - core) << B43_NPHY_RFSEQCA_RXDIS_SHIFT));
+ b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN,
+ ((1 - core) << B43_NPHY_RFSEQCA_TXEN_SHIFT));
+ b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_RXEN,
+ (core << B43_NPHY_RFSEQCA_RXEN_SHIFT));
+ b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXDIS,
+ (core << B43_NPHY_RFSEQCA_TXDIS_SHIFT));
+
+ if (core == 0) {
+ b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x0007);
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0007);
+ } else {
+ b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x0007);
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0007);
+ }
+
+ b43_nphy_rf_control_intc_override(dev, 2, 0, 3);
+ b43_nphy_rf_control_override(dev, 8, 0, 3, false);
+ b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
+
+ if (core == 0) {
+ rxval = 1;
+ txval = 8;
+ } else {
+ rxval = 4;
+ txval = 2;
+ }
+ b43_nphy_rf_control_intc_override(dev, 1, rxval, (core + 1));
+ b43_nphy_rf_control_intc_override(dev, 1, txval, (2 - core));
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */
+static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask)
+{
+ int i;
+ s32 iq;
+ u32 ii;
+ u32 qq;
+ int iq_nbits, qq_nbits;
+ int arsh, brsh;
+ u16 tmp, a, b;
+
+ struct nphy_iq_est est;
+ struct b43_phy_n_iq_comp old;
+ struct b43_phy_n_iq_comp new = { };
+ bool error = false;
+
+ if (mask == 0)
+ return;
+
+ b43_nphy_rx_iq_coeffs(dev, false, &old);
+ b43_nphy_rx_iq_coeffs(dev, true, &new);
+ b43_nphy_rx_iq_est(dev, &est, 0x4000, 32, false);
+ new = old;
+
+ for (i = 0; i < 2; i++) {
+ if (i == 0 && (mask & 1)) {
+ iq = est.iq0_prod;
+ ii = est.i0_pwr;
+ qq = est.q0_pwr;
+ } else if (i == 1 && (mask & 2)) {
+ iq = est.iq1_prod;
+ ii = est.i1_pwr;
+ qq = est.q1_pwr;
+ } else {
+ B43_WARN_ON(1);
+ continue;
+ }
+
+ if (ii + qq < 2) {
+ error = true;
+ break;
+ }
+
+ iq_nbits = fls(abs(iq));
+ qq_nbits = fls(qq);
+
+ arsh = iq_nbits - 20;
+ if (arsh >= 0) {
+ a = -((iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
+ tmp = ii >> arsh;
+ } else {
+ a = -((iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
+ tmp = ii << -arsh;
+ }
+ if (tmp == 0) {
+ error = true;
+ break;
+ }
+ a /= tmp;
+
+ brsh = qq_nbits - 11;
+ if (brsh >= 0) {
+ b = (qq << (31 - qq_nbits));
+ tmp = ii >> brsh;
+ } else {
+ b = (qq << (31 - qq_nbits));
+ tmp = ii << -brsh;
+ }
+ if (tmp == 0) {
+ error = true;
+ break;
+ }
+ b = int_sqrt(b / tmp - a * a) - (1 << 10);
+
+ if (i == 0 && (mask & 0x1)) {
+ if (dev->phy.rev >= 3) {
+ new.a0 = a & 0x3FF;
+ new.b0 = b & 0x3FF;
+ } else {
+ new.a0 = b & 0x3FF;
+ new.b0 = a & 0x3FF;
+ }
+ } else if (i == 1 && (mask & 0x2)) {
+ if (dev->phy.rev >= 3) {
+ new.a1 = a & 0x3FF;
+ new.b1 = b & 0x3FF;
+ } else {
+ new.a1 = b & 0x3FF;
+ new.b1 = a & 0x3FF;
+ }
+ }
+ }
+
+ if (error)
+ new = old;
+
+ b43_nphy_rx_iq_coeffs(dev, true, &new);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxIqWar */
+static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev)
+{
+ u16 array[4];
+ int i;
+
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C50);
+ for (i = 0; i < 4; i++)
+ array[i] = b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW0, array[0]);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW1, array[1]);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW2, array[2]);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW3, array[3]);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */
+static void b43_nphy_write_clip_detection(struct b43_wldev *dev, u16 *clip_st)
+{
+ b43_phy_write(dev, B43_NPHY_C1_CLIP1THRES, clip_st[0]);
+ b43_phy_write(dev, B43_NPHY_C2_CLIP1THRES, clip_st[1]);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */
+static void b43_nphy_read_clip_detection(struct b43_wldev *dev, u16 *clip_st)
+{
+ clip_st[0] = b43_phy_read(dev, B43_NPHY_C1_CLIP1THRES);
+ clip_st[1] = b43_phy_read(dev, B43_NPHY_C2_CLIP1THRES);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */
+static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val)
+{
+ u16 tmp;
+
+ if (dev->dev->id.revision == 16)
+ b43_mac_suspend(dev);
+
+ tmp = b43_phy_read(dev, B43_NPHY_CLASSCTL);
+ tmp &= (B43_NPHY_CLASSCTL_CCKEN | B43_NPHY_CLASSCTL_OFDMEN |
+ B43_NPHY_CLASSCTL_WAITEDEN);
+ tmp &= ~mask;
+ tmp |= (val & mask);
+ b43_phy_maskset(dev, B43_NPHY_CLASSCTL, 0xFFF8, tmp);
+
+ if (dev->dev->id.revision == 16)
+ b43_mac_enable(dev);
+
+ return tmp;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/carriersearch */
+static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable)
{
struct b43_phy *phy = &dev->phy;
- unsigned int i;
+ struct b43_phy_n *nphy = phy->n;
- b43_phy_set(dev, B43_NPHY_IQFLIP,
- B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
- if (1 /* FIXME band is 2.4GHz */) {
- b43_phy_set(dev, B43_NPHY_CLASSCTL,
- B43_NPHY_CLASSCTL_CCKEN);
- } else {
- b43_phy_mask(dev, B43_NPHY_CLASSCTL,
- ~B43_NPHY_CLASSCTL_CCKEN);
- }
- b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
- b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8);
-
- /* Fixup some tables */
- b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA);
- b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA);
- b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
- b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
- b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0);
- b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0);
- b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
- b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
- b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800);
- b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800);
-
- b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
- b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
- b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
- b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
-
- //TODO set RF sequence
-
- /* Set narrowband clip threshold */
- b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66);
- b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66);
-
- /* Set wideband clip 2 threshold */
- b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
- ~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
- 21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT);
- b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
- ~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
- 21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT);
-
- /* Set Clip 2 detect */
- b43_phy_set(dev, B43_NPHY_C1_CGAINI,
- B43_NPHY_C1_CGAINI_CL2DETECT);
- b43_phy_set(dev, B43_NPHY_C2_CGAINI,
- B43_NPHY_C2_CGAINI_CL2DETECT);
-
- if (0 /*FIXME*/) {
- /* Set dwell lengths */
- b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43);
- b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43);
- b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9);
- b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9);
-
- /* Set gain backoff */
- b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
- ~B43_NPHY_C1_CGAINI_GAINBKOFF,
- 1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT);
- b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
- ~B43_NPHY_C2_CGAINI_GAINBKOFF,
- 1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT);
+ if (enable) {
+ u16 clip[] = { 0xFFFF, 0xFFFF };
+ if (nphy->deaf_count++ == 0) {
+ nphy->classifier_state = b43_nphy_classifier(dev, 0, 0);
+ b43_nphy_classifier(dev, 0x7, 0);
+ b43_nphy_read_clip_detection(dev, nphy->clip_state);
+ b43_nphy_write_clip_detection(dev, clip);
+ }
+ b43_nphy_reset_cca(dev);
+ } else {
+ if (--nphy->deaf_count == 0) {
+ b43_nphy_classifier(dev, 0x7, nphy->classifier_state);
+ b43_nphy_write_clip_detection(dev, nphy->clip_state);
+ }
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */
+static void b43_nphy_stop_playback(struct b43_wldev *dev)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ u16 tmp;
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 1);
+
+ tmp = b43_phy_read(dev, B43_NPHY_SAMP_STAT);
+ if (tmp & 0x1)
+ b43_phy_set(dev, B43_NPHY_SAMP_CMD, B43_NPHY_SAMP_CMD_STOP);
+ else if (tmp & 0x2)
+ b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, (u16)~0x8000);
+
+ b43_phy_mask(dev, B43_NPHY_SAMP_CMD, ~0x0004);
+
+ if (nphy->bb_mult_save & 0x80000000) {
+ tmp = nphy->bb_mult_save & 0xFFFF;
+ b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
+ nphy->bb_mult_save = 0;
+ }
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 0);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SpurWar */
+static void b43_nphy_spur_workaround(struct b43_wldev *dev)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+
+ unsigned int channel;
+ int tone[2] = { 57, 58 };
+ u32 noise[2] = { 0x3FF, 0x3FF };
+
+ B43_WARN_ON(dev->phy.rev < 3);
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 1);
+
+ /* FIXME: channel = radio_chanspec */
+
+ if (nphy->gband_spurwar_en) {
+ /* TODO: N PHY Adjust Analog Pfbw (7) */
+ if (channel == 11 && dev->phy.is_40mhz)
+ ; /* TODO: N PHY Adjust Min Noise Var(2, tone, noise)*/
+ else
+ ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/
+ /* TODO: N PHY Adjust CRS Min Power (0x1E) */
+ }
+
+ if (nphy->aband_spurwar_en) {
+ if (channel == 54) {
+ tone[0] = 0x20;
+ noise[0] = 0x25F;
+ } else if (channel == 38 || channel == 102 || channel == 118) {
+ if (0 /* FIXME */) {
+ tone[0] = 0x20;
+ noise[0] = 0x21F;
+ } else {
+ tone[0] = 0;
+ noise[0] = 0;
+ }
+ } else if (channel == 134) {
+ tone[0] = 0x20;
+ noise[0] = 0x21F;
+ } else if (channel == 151) {
+ tone[0] = 0x10;
+ noise[0] = 0x23F;
+ } else if (channel == 153 || channel == 161) {
+ tone[0] = 0x30;
+ noise[0] = 0x23F;
+ } else {
+ tone[0] = 0;
+ noise[0] = 0;
+ }
+
+ if (!tone[0] && !noise[0])
+ ; /* TODO: N PHY Adjust Min Noise Var(1, tone, noise)*/
+ else
+ ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/
+ }
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 0);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
+static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ u8 i, j;
+ u8 code;
+
+ /* TODO: for PHY >= 3
+ s8 *lna1_gain, *lna2_gain;
+ u8 *gain_db, *gain_bits;
+ u16 *rfseq_init;
+ u8 lpf_gain[6] = { 0x00, 0x06, 0x0C, 0x12, 0x12, 0x12 };
+ u8 lpf_bits[6] = { 0, 1, 2, 3, 3, 3 };
+ */
+
+ u8 rfseq_events[3] = { 6, 8, 7 };
+ u8 rfseq_delays[3] = { 10, 30, 1 };
+
+ if (dev->phy.rev >= 3) {
+ /* TODO */
+ } else {
+ /* Set Clip 2 detect */
+ b43_phy_set(dev, B43_NPHY_C1_CGAINI,
+ B43_NPHY_C1_CGAINI_CL2DETECT);
+ b43_phy_set(dev, B43_NPHY_C2_CGAINI,
+ B43_NPHY_C2_CGAINI_CL2DETECT);
+
+ /* Set narrowband clip threshold */
+ b43_phy_set(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84);
+ b43_phy_set(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84);
+
+ if (!dev->phy.is_40mhz) {
+ /* Set dwell lengths */
+ b43_phy_set(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B);
+ b43_phy_set(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B);
+ b43_phy_set(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 0x0009);
+ b43_phy_set(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 0x0009);
+ }
+
+ /* Set wideband clip 2 threshold */
+ b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
+ ~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
+ 21);
+ b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
+ ~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
+ 21);
+
+ if (!dev->phy.is_40mhz) {
+ b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
+ ~B43_NPHY_C1_CGAINI_GAINBKOFF, 0x1);
+ b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
+ ~B43_NPHY_C2_CGAINI_GAINBKOFF, 0x1);
+ b43_phy_maskset(dev, B43_NPHY_C1_CCK_CGAINI,
+ ~B43_NPHY_C1_CCK_CGAINI_GAINBKOFF, 0x1);
+ b43_phy_maskset(dev, B43_NPHY_C2_CCK_CGAINI,
+ ~B43_NPHY_C2_CCK_CGAINI_GAINBKOFF, 0x1);
+ }
+
+ b43_phy_set(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C);
+
+ if (nphy->gain_boost) {
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ &&
+ dev->phy.is_40mhz)
+ code = 4;
+ else
+ code = 5;
+ } else {
+ code = dev->phy.is_40mhz ? 6 : 7;
+ }
/* Set HPVGA2 index */
b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
~B43_NPHY_C1_INITGAIN_HPVGA2,
- 6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
+ code << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
~B43_NPHY_C2_INITGAIN_HPVGA2,
- 6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
+ code << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
+
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+ (code << 8 | 0x7C));
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+ (code << 8 | 0x7C));
+
+ /* TODO: b43_nphy_adjust_lna_gain_table(dev); */
+
+ if (nphy->elna_gain_config) {
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0808);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0C08);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+ (code << 8 | 0x74));
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+ (code << 8 | 0x74));
+ }
- //FIXME verify that the specs really mean to use autoinc here.
- for (i = 0; i < 3; i++)
- b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673);
+ if (dev->phy.rev == 2) {
+ for (i = 0; i < 4; i++) {
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
+ (0x0400 * i) + 0x0020);
+ for (j = 0; j < 21; j++)
+ b43_phy_write(dev,
+ B43_NPHY_TABLE_DATALO, 3 * j);
+ }
+
+ b43_nphy_set_rf_sequence(dev, 5,
+ rfseq_events, rfseq_delays, 3);
+ b43_phy_maskset(dev, B43_NPHY_OVER_DGAIN1,
+ (u16)~B43_NPHY_OVER_DGAIN_CCKDGECV,
+ 0x5A << B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT);
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ b43_phy_maskset(dev, B43_PHY_N(0xC5D),
+ 0xFF80, 4);
+ }
}
+}
- /* Set minimum gain value */
- b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN,
- ~B43_NPHY_C1_MINGAIN,
- 23 << B43_NPHY_C1_MINGAIN_SHIFT);
- b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN,
- ~B43_NPHY_C2_MINGAIN,
- 23 << B43_NPHY_C2_MINGAIN_SHIFT);
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */
+static void b43_nphy_workarounds(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy *phy = &dev->phy;
+ struct b43_phy_n *nphy = phy->n;
- if (phy->rev < 2) {
- b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
- ~B43_NPHY_SCRAM_SIGCTL_SCM);
+ u8 events1[7] = { 0x0, 0x1, 0x2, 0x8, 0x4, 0x5, 0x3 };
+ u8 delays1[7] = { 0x8, 0x6, 0x6, 0x2, 0x4, 0x3C, 0x1 };
+
+ u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 };
+ u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 };
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ b43_nphy_classifier(dev, 1, 0);
+ else
+ b43_nphy_classifier(dev, 1, 1);
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 1);
+
+ b43_phy_set(dev, B43_NPHY_IQFLIP,
+ B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
+
+ if (dev->phy.rev >= 3) {
+ /* TODO */
+ } else {
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ &&
+ nphy->band5g_pwrgain) {
+ b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8);
+ b43_radio_mask(dev, B2055_C2_TX_RF_SPARE, ~0x8);
+ } else {
+ b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
+ b43_radio_set(dev, B2055_C2_TX_RF_SPARE, 0x8);
+ }
+
+ /* TODO: convert to b43_ntab_write? */
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2000);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x000A);
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2010);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x000A);
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2002);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0xCDAA);
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2012);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0xCDAA);
+
+ if (dev->phy.rev < 2) {
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2008);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0000);
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2018);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0000);
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2007);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x7AAB);
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2017);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x7AAB);
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2006);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0800);
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2016);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0800);
+ }
+
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
+
+ if (bus->sprom.boardflags2_lo & 0x100 &&
+ bus->boardinfo.type == 0x8B) {
+ delays1[0] = 0x1;
+ delays1[5] = 0x14;
+ }
+ b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);
+ b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
+
+ b43_nphy_gain_crtl_workarounds(dev);
+
+ if (dev->phy.rev < 2) {
+ if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2)
+ ; /*TODO: b43_mhf(dev, 2, 0x0010, 0x0010, 3);*/
+ } else if (dev->phy.rev == 2) {
+ b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0);
+ b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0);
+ }
+
+ if (dev->phy.rev < 2)
+ b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
+ ~B43_NPHY_SCRAM_SIGCTL_SCM);
+
+ /* Set phase track alpha and beta */
+ b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
+ b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
+ b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
+
+ b43_phy_mask(dev, B43_NPHY_PIL_DW1,
+ (u16)~B43_NPHY_PIL_DW_64QAM);
+ b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
+ b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
+ b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
+
+ if (dev->phy.rev == 2)
+ b43_phy_set(dev, B43_NPHY_FINERX2_CGC,
+ B43_NPHY_FINERX2_CGC_DECGC);
}
- /* Set phase track alpha and beta */
- b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
- b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
- b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
- b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
- b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
- b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 0);
}
-static void b43_nphy_reset_cca(struct b43_wldev *dev)
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/LoadSampleTable */
+static int b43_nphy_load_samples(struct b43_wldev *dev,
+ struct b43_c32 *samples, u16 len) {
+ struct b43_phy_n *nphy = dev->phy.n;
+ u16 i;
+ u32 *data;
+
+ data = kzalloc(len * sizeof(u32), GFP_KERNEL);
+ if (!data) {
+ b43err(dev->wl, "allocation for samples loading failed\n");
+ return -ENOMEM;
+ }
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 1);
+
+ for (i = 0; i < len; i++) {
+ data[i] = (samples[i].i & 0x3FF << 10);
+ data[i] |= samples[i].q & 0x3FF;
+ }
+ b43_ntab_write_bulk(dev, B43_NTAB32(17, 0), len, data);
+
+ kfree(data);
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 0);
+ return 0;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */
+static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max,
+ bool test)
{
- u16 bbcfg;
+ int i;
+ u16 bw, len, rot, angle;
+ struct b43_c32 *samples;
- ssb_write32(dev->dev, SSB_TMSLOW,
- ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC);
- bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
- b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA);
- b43_phy_write(dev, B43_NPHY_BBCFG,
- bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
- ssb_write32(dev->dev, SSB_TMSLOW,
- ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC);
+
+ bw = (dev->phy.is_40mhz) ? 40 : 20;
+ len = bw << 3;
+
+ if (test) {
+ if (b43_phy_read(dev, B43_NPHY_BBCFG) & B43_NPHY_BBCFG_RSTRX)
+ bw = 82;
+ else
+ bw = 80;
+
+ if (dev->phy.is_40mhz)
+ bw <<= 1;
+
+ len = bw << 1;
+ }
+
+ samples = kzalloc(len * sizeof(struct b43_c32), GFP_KERNEL);
+ if (!samples) {
+ b43err(dev->wl, "allocation for samples generation failed\n");
+ return 0;
+ }
+ rot = (((freq * 36) / bw) << 16) / 100;
+ angle = 0;
+
+ for (i = 0; i < len; i++) {
+ samples[i] = b43_cordic(angle);
+ angle += rot;
+ samples[i].q = CORDIC_CONVERT(samples[i].q * max);
+ samples[i].i = CORDIC_CONVERT(samples[i].i * max);
+ }
+
+ i = b43_nphy_load_samples(dev, samples, len);
+ kfree(samples);
+ return (i < 0) ? 0 : len;
}
-enum b43_nphy_rf_sequence {
- B43_RFSEQ_RX2TX,
- B43_RFSEQ_TX2RX,
- B43_RFSEQ_RESET2RX,
- B43_RFSEQ_UPDATE_GAINH,
- B43_RFSEQ_UPDATE_GAINL,
- B43_RFSEQ_UPDATE_GAINU,
-};
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */
+static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
+ u16 wait, bool iqmode, bool dac_test)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ int i;
+ u16 seq_mode;
+ u32 tmp;
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, true);
+
+ if ((nphy->bb_mult_save & 0x80000000) == 0) {
+ tmp = b43_ntab_read(dev, B43_NTAB16(15, 87));
+ nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000;
+ }
+
+ if (!dev->phy.is_40mhz)
+ tmp = 0x6464;
+ else
+ tmp = 0x4747;
+ b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, false);
+
+ b43_phy_write(dev, B43_NPHY_SAMP_DEPCNT, (samps - 1));
+
+ if (loops != 0xFFFF)
+ b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, (loops - 1));
+ else
+ b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, loops);
+
+ b43_phy_write(dev, B43_NPHY_SAMP_WAITCNT, wait);
+
+ seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE);
+
+ b43_phy_set(dev, B43_NPHY_RFSEQMODE, B43_NPHY_RFSEQMODE_CAOVER);
+ if (iqmode) {
+ b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
+ b43_phy_set(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8000);
+ } else {
+ if (dac_test)
+ b43_phy_write(dev, B43_NPHY_SAMP_CMD, 5);
+ else
+ b43_phy_write(dev, B43_NPHY_SAMP_CMD, 1);
+ }
+ for (i = 0; i < 100; i++) {
+ if (b43_phy_read(dev, B43_NPHY_RFSEQST) & 1) {
+ i = 0;
+ break;
+ }
+ udelay(10);
+ }
+ if (i)
+ b43err(dev->wl, "run samples timeout\n");
+
+ b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
+}
+
+/*
+ * Transmits a known value for LO calibration
+ * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone
+ */
+static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val,
+ bool iqmode, bool dac_test)
+{
+ u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test);
+ if (samp == 0)
+ return -1;
+ b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test);
+ return 0;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */
+static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ int i, j;
+ u32 tmp;
+ u32 cur_real, cur_imag, real_part, imag_part;
+
+ u16 buffer[7];
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, true);
+
+ b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer);
+
+ for (i = 0; i < 2; i++) {
+ tmp = ((buffer[i * 2] & 0x3FF) << 10) |
+ (buffer[i * 2 + 1] & 0x3FF);
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
+ (((i + 26) << 10) | 320));
+ for (j = 0; j < 128; j++) {
+ b43_phy_write(dev, B43_NPHY_TABLE_DATAHI,
+ ((tmp >> 16) & 0xFFFF));
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+ (tmp & 0xFFFF));
+ }
+ }
+
+ for (i = 0; i < 2; i++) {
+ tmp = buffer[5 + i];
+ real_part = (tmp >> 8) & 0xFF;
+ imag_part = (tmp & 0xFF);
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
+ (((i + 26) << 10) | 448));
+
+ if (dev->phy.rev >= 3) {
+ cur_real = real_part;
+ cur_imag = imag_part;
+ tmp = ((cur_real & 0xFF) << 8) | (cur_imag & 0xFF);
+ }
+
+ for (j = 0; j < 128; j++) {
+ if (dev->phy.rev < 3) {
+ cur_real = (real_part * loscale[j] + 128) >> 8;
+ cur_imag = (imag_part * loscale[j] + 128) >> 8;
+ tmp = ((cur_real & 0xFF) << 8) |
+ (cur_imag & 0xFF);
+ }
+ b43_phy_write(dev, B43_NPHY_TABLE_DATAHI,
+ ((tmp >> 16) & 0xFFFF));
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+ (tmp & 0xFFFF));
+ }
+ }
+
+ if (dev->phy.rev >= 3) {
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_NPHY_TXPWR_INDX0, 0xFFFF);
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_NPHY_TXPWR_INDX1, 0xFFFF);
+ }
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, false);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRfSeq */
+static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
+ u8 *events, u8 *delays, u8 length)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ u8 i;
+ u8 end = (dev->phy.rev >= 3) ? 0x1F : 0x0F;
+ u16 offset1 = cmd << 4;
+ u16 offset2 = offset1 + 0x80;
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, true);
+
+ b43_ntab_write_bulk(dev, B43_NTAB8(7, offset1), length, events);
+ b43_ntab_write_bulk(dev, B43_NTAB8(7, offset2), length, delays);
+
+ for (i = length; i < 16; i++) {
+ b43_ntab_write(dev, B43_NTAB8(7, offset1 + i), end);
+ b43_ntab_write(dev, B43_NTAB8(7, offset2 + i), 1);
+ }
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, false);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */
static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
enum b43_nphy_rf_sequence seq)
{
@@ -376,6 +1266,7 @@ static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
[B43_RFSEQ_UPDATE_GAINU] = B43_NPHY_RFSEQTR_UPGU,
};
int i;
+ u16 seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE);
B43_WARN_ON(seq >= ARRAY_SIZE(trigger));
@@ -389,8 +1280,181 @@ static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
}
b43err(dev->wl, "RF sequence status timeout\n");
ok:
- b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
- ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER));
+ b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
+static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
+ u16 value, u8 core, bool off)
+{
+ int i;
+ u8 index = fls(field);
+ u8 addr, en_addr, val_addr;
+ /* we expect only one bit set */
+ B43_WARN_ON(field & (~(1 << (index - 1))));
+
+ if (dev->phy.rev >= 3) {
+ const struct nphy_rf_control_override_rev3 *rf_ctrl;
+ for (i = 0; i < 2; i++) {
+ if (index == 0 || index == 16) {
+ b43err(dev->wl,
+ "Unsupported RF Ctrl Override call\n");
+ return;
+ }
+
+ rf_ctrl = &tbl_rf_control_override_rev3[index - 1];
+ en_addr = B43_PHY_N((i == 0) ?
+ rf_ctrl->en_addr0 : rf_ctrl->en_addr1);
+ val_addr = B43_PHY_N((i == 0) ?
+ rf_ctrl->val_addr0 : rf_ctrl->val_addr1);
+
+ if (off) {
+ b43_phy_mask(dev, en_addr, ~(field));
+ b43_phy_mask(dev, val_addr,
+ ~(rf_ctrl->val_mask));
+ } else {
+ if (core == 0 || ((1 << core) & i) != 0) {
+ b43_phy_set(dev, en_addr, field);
+ b43_phy_maskset(dev, val_addr,
+ ~(rf_ctrl->val_mask),
+ (value << rf_ctrl->val_shift));
+ }
+ }
+ }
+ } else {
+ const struct nphy_rf_control_override_rev2 *rf_ctrl;
+ if (off) {
+ b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~(field));
+ value = 0;
+ } else {
+ b43_phy_set(dev, B43_NPHY_RFCTL_OVER, field);
+ }
+
+ for (i = 0; i < 2; i++) {
+ if (index <= 1 || index == 16) {
+ b43err(dev->wl,
+ "Unsupported RF Ctrl Override call\n");
+ return;
+ }
+
+ if (index == 2 || index == 10 ||
+ (index >= 13 && index <= 15)) {
+ core = 1;
+ }
+
+ rf_ctrl = &tbl_rf_control_override_rev2[index - 2];
+ addr = B43_PHY_N((i == 0) ?
+ rf_ctrl->addr0 : rf_ctrl->addr1);
+
+ if ((core & (1 << i)) != 0)
+ b43_phy_maskset(dev, addr, ~(rf_ctrl->bmask),
+ (value << rf_ctrl->shift));
+
+ b43_phy_set(dev, B43_NPHY_RFCTL_OVER, 0x1);
+ b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+ B43_NPHY_RFCTL_CMD_START);
+ udelay(1);
+ b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, 0xFFFE);
+ }
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */
+static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
+ u16 value, u8 core)
+{
+ u8 i, j;
+ u16 reg, tmp, val;
+
+ B43_WARN_ON(dev->phy.rev < 3);
+ B43_WARN_ON(field > 4);
+
+ for (i = 0; i < 2; i++) {
+ if ((core == 1 && i == 1) || (core == 2 && !i))
+ continue;
+
+ reg = (i == 0) ?
+ B43_NPHY_RFCTL_INTC1 : B43_NPHY_RFCTL_INTC2;
+ b43_phy_mask(dev, reg, 0xFBFF);
+
+ switch (field) {
+ case 0:
+ b43_phy_write(dev, reg, 0);
+ b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+ break;
+ case 1:
+ if (!i) {
+ b43_phy_maskset(dev, B43_NPHY_RFCTL_INTC1,
+ 0xFC3F, (value << 6));
+ b43_phy_maskset(dev, B43_NPHY_TXF_40CO_B1S1,
+ 0xFFFE, 1);
+ b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+ B43_NPHY_RFCTL_CMD_START);
+ for (j = 0; j < 100; j++) {
+ if (b43_phy_read(dev, B43_NPHY_RFCTL_CMD) & B43_NPHY_RFCTL_CMD_START) {
+ j = 0;
+ break;
+ }
+ udelay(10);
+ }
+ if (j)
+ b43err(dev->wl,
+ "intc override timeout\n");
+ b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S1,
+ 0xFFFE);
+ } else {
+ b43_phy_maskset(dev, B43_NPHY_RFCTL_INTC2,
+ 0xFC3F, (value << 6));
+ b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
+ 0xFFFE, 1);
+ b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+ B43_NPHY_RFCTL_CMD_RXTX);
+ for (j = 0; j < 100; j++) {
+ if (b43_phy_read(dev, B43_NPHY_RFCTL_CMD) & B43_NPHY_RFCTL_CMD_RXTX) {
+ j = 0;
+ break;
+ }
+ udelay(10);
+ }
+ if (j)
+ b43err(dev->wl,
+ "intc override timeout\n");
+ b43_phy_mask(dev, B43_NPHY_RFCTL_OVER,
+ 0xFFFE);
+ }
+ break;
+ case 2:
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+ tmp = 0x0020;
+ val = value << 5;
+ } else {
+ tmp = 0x0010;
+ val = value << 4;
+ }
+ b43_phy_maskset(dev, reg, ~tmp, val);
+ break;
+ case 3:
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+ tmp = 0x0001;
+ val = value;
+ } else {
+ tmp = 0x0004;
+ val = value << 2;
+ }
+ b43_phy_maskset(dev, reg, ~tmp, val);
+ break;
+ case 4:
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+ tmp = 0x0002;
+ val = value << 1;
+ } else {
+ tmp = 0x0008;
+ val = value << 3;
+ }
+ b43_phy_maskset(dev, reg, ~tmp, val);
+ break;
+ }
+ }
}
static void b43_nphy_bphy_init(struct b43_wldev *dev)
@@ -411,81 +1475,1680 @@ static void b43_nphy_bphy_init(struct b43_wldev *dev)
b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
}
-/* RSSI Calibration */
-static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type)
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */
+static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
+ s8 offset, u8 core, u8 rail, u8 type)
{
- //TODO
+ u16 tmp;
+ bool core1or5 = (core == 1) || (core == 5);
+ bool core2or5 = (core == 2) || (core == 5);
+
+ offset = clamp_val(offset, -32, 31);
+ tmp = ((scale & 0x3F) << 8) | (offset & 0x3F);
+
+ if (core1or5 && (rail == 0) && (type == 2))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, tmp);
+ if (core1or5 && (rail == 1) && (type == 2))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, tmp);
+ if (core2or5 && (rail == 0) && (type == 2))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, tmp);
+ if (core2or5 && (rail == 1) && (type == 2))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, tmp);
+ if (core1or5 && (rail == 0) && (type == 0))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, tmp);
+ if (core1or5 && (rail == 1) && (type == 0))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, tmp);
+ if (core2or5 && (rail == 0) && (type == 0))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, tmp);
+ if (core2or5 && (rail == 1) && (type == 0))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, tmp);
+ if (core1or5 && (rail == 0) && (type == 1))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, tmp);
+ if (core1or5 && (rail == 1) && (type == 1))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, tmp);
+ if (core2or5 && (rail == 0) && (type == 1))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, tmp);
+ if (core2or5 && (rail == 1) && (type == 1))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, tmp);
+ if (core1or5 && (rail == 0) && (type == 6))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TBD, tmp);
+ if (core1or5 && (rail == 1) && (type == 6))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TBD, tmp);
+ if (core2or5 && (rail == 0) && (type == 6))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TBD, tmp);
+ if (core2or5 && (rail == 1) && (type == 6))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TBD, tmp);
+ if (core1or5 && (rail == 0) && (type == 3))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_PWRDET, tmp);
+ if (core1or5 && (rail == 1) && (type == 3))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_PWRDET, tmp);
+ if (core2or5 && (rail == 0) && (type == 3))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_PWRDET, tmp);
+ if (core2or5 && (rail == 1) && (type == 3))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_PWRDET, tmp);
+ if (core1or5 && (type == 4))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TSSI, tmp);
+ if (core2or5 && (type == 4))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TSSI, tmp);
+ if (core1or5 && (type == 5))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TSSI, tmp);
+ if (core2or5 && (type == 5))
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp);
+}
+
+static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+{
+ u16 val;
+
+ if (type < 3)
+ val = 0;
+ else if (type == 6)
+ val = 1;
+ else if (type == 3)
+ val = 2;
+ else
+ val = 3;
+
+ val = (val << 12) | (val << 14);
+ b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val);
+ b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val);
+
+ if (type < 3) {
+ b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF,
+ (type + 1) << 4);
+ b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF,
+ (type + 1) << 4);
+ }
+
+ /* TODO use some definitions */
+ if (code == 0) {
+ b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, 0);
+ if (type < 3) {
+ b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFEC7, 0);
+ b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xEFDC, 0);
+ b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0);
+ udelay(20);
+ b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0);
+ }
+ } else {
+ b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF,
+ 0x3000);
+ if (type < 3) {
+ b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
+ 0xFEC7, 0x0180);
+ b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
+ 0xEFDC, (code << 1 | 0x1021));
+ b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0x1);
+ udelay(20);
+ b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0);
+ }
+ }
+}
+
+static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ u8 i;
+ u16 reg, val;
+
+ if (code == 0) {
+ b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, 0xFDFF);
+ b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, 0xFDFF);
+ b43_phy_mask(dev, B43_NPHY_AFECTL_C1, 0xFCFF);
+ b43_phy_mask(dev, B43_NPHY_AFECTL_C2, 0xFCFF);
+ b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S0, 0xFFDF);
+ b43_phy_mask(dev, B43_NPHY_TXF_40CO_B32S1, 0xFFDF);
+ b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0xFFC3);
+ b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0xFFC3);
+ } else {
+ for (i = 0; i < 2; i++) {
+ if ((code == 1 && i == 1) || (code == 2 && !i))
+ continue;
+
+ reg = (i == 0) ?
+ B43_NPHY_AFECTL_OVER1 : B43_NPHY_AFECTL_OVER;
+ b43_phy_maskset(dev, reg, 0xFDFF, 0x0200);
+
+ if (type < 3) {
+ reg = (i == 0) ?
+ B43_NPHY_AFECTL_C1 :
+ B43_NPHY_AFECTL_C2;
+ b43_phy_maskset(dev, reg, 0xFCFF, 0);
+
+ reg = (i == 0) ?
+ B43_NPHY_RFCTL_LUT_TRSW_UP1 :
+ B43_NPHY_RFCTL_LUT_TRSW_UP2;
+ b43_phy_maskset(dev, reg, 0xFFC3, 0);
+
+ if (type == 0)
+ val = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ? 4 : 8;
+ else if (type == 1)
+ val = 16;
+ else
+ val = 32;
+ b43_phy_set(dev, reg, val);
+
+ reg = (i == 0) ?
+ B43_NPHY_TXF_40CO_B1S0 :
+ B43_NPHY_TXF_40CO_B32S1;
+ b43_phy_set(dev, reg, 0x0020);
+ } else {
+ if (type == 6)
+ val = 0x0100;
+ else if (type == 3)
+ val = 0x0200;
+ else
+ val = 0x0300;
+
+ reg = (i == 0) ?
+ B43_NPHY_AFECTL_C1 :
+ B43_NPHY_AFECTL_C2;
+
+ b43_phy_maskset(dev, reg, 0xFCFF, val);
+ b43_phy_maskset(dev, reg, 0xF3FF, val << 2);
+
+ if (type != 3 && type != 6) {
+ enum ieee80211_band band =
+ b43_current_band(dev->wl);
+
+ if ((nphy->ipa2g_on &&
+ band == IEEE80211_BAND_2GHZ) ||
+ (nphy->ipa5g_on &&
+ band == IEEE80211_BAND_5GHZ))
+ val = (band == IEEE80211_BAND_5GHZ) ? 0xC : 0xE;
+ else
+ val = 0x11;
+ reg = (i == 0) ? 0x2000 : 0x3000;
+ reg |= B2055_PADDRV;
+ b43_radio_write16(dev, reg, val);
+
+ reg = (i == 0) ?
+ B43_NPHY_AFECTL_OVER1 :
+ B43_NPHY_AFECTL_OVER;
+ b43_phy_set(dev, reg, 0x0200);
+ }
+ }
+ }
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */
+static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+{
+ if (dev->phy.rev >= 3)
+ b43_nphy_rev3_rssi_select(dev, code, type);
+ else
+ b43_nphy_rev2_rssi_select(dev, code, type);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */
+static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, u8 type, u8 *buf)
+{
+ int i;
+ for (i = 0; i < 2; i++) {
+ if (type == 2) {
+ if (i == 0) {
+ b43_radio_maskset(dev, B2055_C1_B0NB_RSSIVCM,
+ 0xFC, buf[0]);
+ b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5,
+ 0xFC, buf[1]);
+ } else {
+ b43_radio_maskset(dev, B2055_C2_B0NB_RSSIVCM,
+ 0xFC, buf[2 * i]);
+ b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5,
+ 0xFC, buf[2 * i + 1]);
+ }
+ } else {
+ if (i == 0)
+ b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5,
+ 0xF3, buf[0] << 2);
+ else
+ b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5,
+ 0xF3, buf[2 * i + 1] << 2);
+ }
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */
+static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
+ u8 nsamp)
+{
+ int i;
+ int out;
+ u16 save_regs_phy[9];
+ u16 s[2];
+
+ if (dev->phy.rev >= 3) {
+ save_regs_phy[0] = b43_phy_read(dev,
+ B43_NPHY_RFCTL_LUT_TRSW_UP1);
+ save_regs_phy[1] = b43_phy_read(dev,
+ B43_NPHY_RFCTL_LUT_TRSW_UP2);
+ save_regs_phy[2] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
+ save_regs_phy[3] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
+ save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1);
+ save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+ save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0);
+ save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1);
+ }
+
+ b43_nphy_rssi_select(dev, 5, type);
+
+ if (dev->phy.rev < 2) {
+ save_regs_phy[8] = b43_phy_read(dev, B43_NPHY_GPIO_SEL);
+ b43_phy_write(dev, B43_NPHY_GPIO_SEL, 5);
+ }
+
+ for (i = 0; i < 4; i++)
+ buf[i] = 0;
+
+ for (i = 0; i < nsamp; i++) {
+ if (dev->phy.rev < 2) {
+ s[0] = b43_phy_read(dev, B43_NPHY_GPIO_LOOUT);
+ s[1] = b43_phy_read(dev, B43_NPHY_GPIO_HIOUT);
+ } else {
+ s[0] = b43_phy_read(dev, B43_NPHY_RSSI1);
+ s[1] = b43_phy_read(dev, B43_NPHY_RSSI2);
+ }
+
+ buf[0] += ((s8)((s[0] & 0x3F) << 2)) >> 2;
+ buf[1] += ((s8)(((s[0] >> 8) & 0x3F) << 2)) >> 2;
+ buf[2] += ((s8)((s[1] & 0x3F) << 2)) >> 2;
+ buf[3] += ((s8)(((s[1] >> 8) & 0x3F) << 2)) >> 2;
+ }
+ out = (buf[0] & 0xFF) << 24 | (buf[1] & 0xFF) << 16 |
+ (buf[2] & 0xFF) << 8 | (buf[3] & 0xFF);
+
+ if (dev->phy.rev < 2)
+ b43_phy_write(dev, B43_NPHY_GPIO_SEL, save_regs_phy[8]);
+
+ if (dev->phy.rev >= 3) {
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1,
+ save_regs_phy[0]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2,
+ save_regs_phy[1]);
+ b43_phy_write(dev, B43_NPHY_AFECTL_C1, save_regs_phy[2]);
+ b43_phy_write(dev, B43_NPHY_AFECTL_C2, save_regs_phy[3]);
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, save_regs_phy[4]);
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[5]);
+ b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, save_regs_phy[6]);
+ b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, save_regs_phy[7]);
+ }
+
+ return out;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */
+static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
+{
+ int i, j;
+ u8 state[4];
+ u8 code, val;
+ u16 class, override;
+ u8 regs_save_radio[2];
+ u16 regs_save_phy[2];
+ s8 offset[4];
+
+ u16 clip_state[2];
+ u16 clip_off[2] = { 0xFFFF, 0xFFFF };
+ s32 results_min[4] = { };
+ u8 vcm_final[4] = { };
+ s32 results[4][4] = { };
+ s32 miniq[4][2] = { };
+
+ if (type == 2) {
+ code = 0;
+ val = 6;
+ } else if (type < 2) {
+ code = 25;
+ val = 4;
+ } else {
+ B43_WARN_ON(1);
+ return;
+ }
+
+ class = b43_nphy_classifier(dev, 0, 0);
+ b43_nphy_classifier(dev, 7, 4);
+ b43_nphy_read_clip_detection(dev, clip_state);
+ b43_nphy_write_clip_detection(dev, clip_off);
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+ override = 0x140;
+ else
+ override = 0x110;
+
+ regs_save_phy[0] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
+ regs_save_radio[0] = b43_radio_read16(dev, B2055_C1_PD_RXTX);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, override);
+ b43_radio_write16(dev, B2055_C1_PD_RXTX, val);
+
+ regs_save_phy[1] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
+ regs_save_radio[1] = b43_radio_read16(dev, B2055_C2_PD_RXTX);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, override);
+ b43_radio_write16(dev, B2055_C2_PD_RXTX, val);
+
+ state[0] = b43_radio_read16(dev, B2055_C1_PD_RSSIMISC) & 0x07;
+ state[1] = b43_radio_read16(dev, B2055_C2_PD_RSSIMISC) & 0x07;
+ b43_radio_mask(dev, B2055_C1_PD_RSSIMISC, 0xF8);
+ b43_radio_mask(dev, B2055_C2_PD_RSSIMISC, 0xF8);
+ state[2] = b43_radio_read16(dev, B2055_C1_SP_RSSI) & 0x07;
+ state[3] = b43_radio_read16(dev, B2055_C2_SP_RSSI) & 0x07;
+
+ b43_nphy_rssi_select(dev, 5, type);
+ b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 0, type);
+ b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 1, type);
+
+ for (i = 0; i < 4; i++) {
+ u8 tmp[4];
+ for (j = 0; j < 4; j++)
+ tmp[j] = i;
+ if (type != 1)
+ b43_nphy_set_rssi_2055_vcm(dev, type, tmp);
+ b43_nphy_poll_rssi(dev, type, results[i], 8);
+ if (type < 2)
+ for (j = 0; j < 2; j++)
+ miniq[i][j] = min(results[i][2 * j],
+ results[i][2 * j + 1]);
+ }
+
+ for (i = 0; i < 4; i++) {
+ s32 mind = 40;
+ u8 minvcm = 0;
+ s32 minpoll = 249;
+ s32 curr;
+ for (j = 0; j < 4; j++) {
+ if (type == 2)
+ curr = abs(results[j][i]);
+ else
+ curr = abs(miniq[j][i / 2] - code * 8);
+
+ if (curr < mind) {
+ mind = curr;
+ minvcm = j;
+ }
+
+ if (results[j][i] < minpoll)
+ minpoll = results[j][i];
+ }
+ results_min[i] = minpoll;
+ vcm_final[i] = minvcm;
+ }
+
+ if (type != 1)
+ b43_nphy_set_rssi_2055_vcm(dev, type, vcm_final);
+
+ for (i = 0; i < 4; i++) {
+ offset[i] = (code * 8) - results[vcm_final[i]][i];
+
+ if (offset[i] < 0)
+ offset[i] = -((abs(offset[i]) + 4) / 8);
+ else
+ offset[i] = (offset[i] + 4) / 8;
+
+ if (results_min[i] == 248)
+ offset[i] = code - 32;
+
+ if (i % 2 == 0)
+ b43_nphy_scale_offset_rssi(dev, 0, offset[i], 1, 0,
+ type);
+ else
+ b43_nphy_scale_offset_rssi(dev, 0, offset[i], 2, 1,
+ type);
+ }
+
+ b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[0]);
+ b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[1]);
+
+ switch (state[2]) {
+ case 1:
+ b43_nphy_rssi_select(dev, 1, 2);
+ break;
+ case 4:
+ b43_nphy_rssi_select(dev, 1, 0);
+ break;
+ case 2:
+ b43_nphy_rssi_select(dev, 1, 1);
+ break;
+ default:
+ b43_nphy_rssi_select(dev, 1, 1);
+ break;
+ }
+
+ switch (state[3]) {
+ case 1:
+ b43_nphy_rssi_select(dev, 2, 2);
+ break;
+ case 4:
+ b43_nphy_rssi_select(dev, 2, 0);
+ break;
+ default:
+ b43_nphy_rssi_select(dev, 2, 1);
+ break;
+ }
+
+ b43_nphy_rssi_select(dev, 0, type);
+
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs_save_phy[0]);
+ b43_radio_write16(dev, B2055_C1_PD_RXTX, regs_save_radio[0]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs_save_phy[1]);
+ b43_radio_write16(dev, B2055_C2_PD_RXTX, regs_save_radio[1]);
+
+ b43_nphy_classifier(dev, 7, class);
+ b43_nphy_write_clip_detection(dev, clip_state);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */
+static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
+{
+ /* TODO */
+}
+
+/*
+ * RSSI Calibration
+ * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal
+ */
+static void b43_nphy_rssi_cal(struct b43_wldev *dev)
+{
+ if (dev->phy.rev >= 3) {
+ b43_nphy_rev3_rssi_cal(dev);
+ } else {
+ b43_nphy_rev2_rssi_cal(dev, 2);
+ b43_nphy_rev2_rssi_cal(dev, 0);
+ b43_nphy_rev2_rssi_cal(dev, 1);
+ }
}
+/*
+ * Restore RSSI Calibration
+ * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreRssiCal
+ */
+static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+
+ u16 *rssical_radio_regs = NULL;
+ u16 *rssical_phy_regs = NULL;
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ if (!nphy->rssical_chanspec_2G)
+ return;
+ rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_2G;
+ rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_2G;
+ } else {
+ if (!nphy->rssical_chanspec_5G)
+ return;
+ rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_5G;
+ rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G;
+ }
+
+ /* TODO use some definitions */
+ b43_radio_maskset(dev, 0x602B, 0xE3, rssical_radio_regs[0]);
+ b43_radio_maskset(dev, 0x702B, 0xE3, rssical_radio_regs[1]);
+
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, rssical_phy_regs[0]);
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, rssical_phy_regs[1]);
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, rssical_phy_regs[2]);
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, rssical_phy_regs[3]);
+
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, rssical_phy_regs[4]);
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, rssical_phy_regs[5]);
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, rssical_phy_regs[6]);
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, rssical_phy_regs[7]);
+
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, rssical_phy_regs[8]);
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, rssical_phy_regs[9]);
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, rssical_phy_regs[10]);
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, rssical_phy_regs[11]);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetIpaGainTbl */
+static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev)
+{
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ if (dev->phy.rev >= 6) {
+ /* TODO If the chip is 47162
+ return txpwrctrl_tx_gain_ipa_rev5 */
+ return txpwrctrl_tx_gain_ipa_rev6;
+ } else if (dev->phy.rev >= 5) {
+ return txpwrctrl_tx_gain_ipa_rev5;
+ } else {
+ return txpwrctrl_tx_gain_ipa;
+ }
+ } else {
+ return txpwrctrl_tx_gain_ipa_5g;
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */
+static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ u16 *save = nphy->tx_rx_cal_radio_saveregs;
+ u16 tmp;
+ u8 offset, i;
+
+ if (dev->phy.rev >= 3) {
+ for (i = 0; i < 2; i++) {
+ tmp = (i == 0) ? 0x2000 : 0x3000;
+ offset = i * 11;
+
+ save[offset + 0] = b43_radio_read16(dev, B2055_CAL_RVARCTL);
+ save[offset + 1] = b43_radio_read16(dev, B2055_CAL_LPOCTL);
+ save[offset + 2] = b43_radio_read16(dev, B2055_CAL_TS);
+ save[offset + 3] = b43_radio_read16(dev, B2055_CAL_RCCALRTS);
+ save[offset + 4] = b43_radio_read16(dev, B2055_CAL_RCALRTS);
+ save[offset + 5] = b43_radio_read16(dev, B2055_PADDRV);
+ save[offset + 6] = b43_radio_read16(dev, B2055_XOCTL1);
+ save[offset + 7] = b43_radio_read16(dev, B2055_XOCTL2);
+ save[offset + 8] = b43_radio_read16(dev, B2055_XOREGUL);
+ save[offset + 9] = b43_radio_read16(dev, B2055_XOMISC);
+ save[offset + 10] = b43_radio_read16(dev, B2055_PLL_LFC1);
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+ b43_radio_write16(dev, tmp | B2055_CAL_RVARCTL, 0x0A);
+ b43_radio_write16(dev, tmp | B2055_CAL_LPOCTL, 0x40);
+ b43_radio_write16(dev, tmp | B2055_CAL_TS, 0x55);
+ b43_radio_write16(dev, tmp | B2055_CAL_RCCALRTS, 0);
+ b43_radio_write16(dev, tmp | B2055_CAL_RCALRTS, 0);
+ if (nphy->ipa5g_on) {
+ b43_radio_write16(dev, tmp | B2055_PADDRV, 4);
+ b43_radio_write16(dev, tmp | B2055_XOCTL1, 1);
+ } else {
+ b43_radio_write16(dev, tmp | B2055_PADDRV, 0);
+ b43_radio_write16(dev, tmp | B2055_XOCTL1, 0x2F);
+ }
+ b43_radio_write16(dev, tmp | B2055_XOCTL2, 0);
+ } else {
+ b43_radio_write16(dev, tmp | B2055_CAL_RVARCTL, 0x06);
+ b43_radio_write16(dev, tmp | B2055_CAL_LPOCTL, 0x40);
+ b43_radio_write16(dev, tmp | B2055_CAL_TS, 0x55);
+ b43_radio_write16(dev, tmp | B2055_CAL_RCCALRTS, 0);
+ b43_radio_write16(dev, tmp | B2055_CAL_RCALRTS, 0);
+ b43_radio_write16(dev, tmp | B2055_XOCTL1, 0);
+ if (nphy->ipa2g_on) {
+ b43_radio_write16(dev, tmp | B2055_PADDRV, 6);
+ b43_radio_write16(dev, tmp | B2055_XOCTL2,
+ (dev->phy.rev < 5) ? 0x11 : 0x01);
+ } else {
+ b43_radio_write16(dev, tmp | B2055_PADDRV, 0);
+ b43_radio_write16(dev, tmp | B2055_XOCTL2, 0);
+ }
+ }
+ b43_radio_write16(dev, tmp | B2055_XOREGUL, 0);
+ b43_radio_write16(dev, tmp | B2055_XOMISC, 0);
+ b43_radio_write16(dev, tmp | B2055_PLL_LFC1, 0);
+ }
+ } else {
+ save[0] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL1);
+ b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL1, 0x29);
+
+ save[1] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL2);
+ b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL2, 0x54);
+
+ save[2] = b43_radio_read16(dev, B2055_C2_TX_RF_IQCAL1);
+ b43_radio_write16(dev, B2055_C2_TX_RF_IQCAL1, 0x29);
+
+ save[3] = b43_radio_read16(dev, B2055_C2_TX_RF_IQCAL2);
+ b43_radio_write16(dev, B2055_C2_TX_RF_IQCAL2, 0x54);
+
+ save[3] = b43_radio_read16(dev, B2055_C1_PWRDET_RXTX);
+ save[4] = b43_radio_read16(dev, B2055_C2_PWRDET_RXTX);
+
+ if (!(b43_phy_read(dev, B43_NPHY_BANDCTL) &
+ B43_NPHY_BANDCTL_5GHZ)) {
+ b43_radio_write16(dev, B2055_C1_PWRDET_RXTX, 0x04);
+ b43_radio_write16(dev, B2055_C2_PWRDET_RXTX, 0x04);
+ } else {
+ b43_radio_write16(dev, B2055_C1_PWRDET_RXTX, 0x20);
+ b43_radio_write16(dev, B2055_C2_PWRDET_RXTX, 0x20);
+ }
+
+ if (dev->phy.rev < 2) {
+ b43_radio_set(dev, B2055_C1_TX_BB_MXGM, 0x20);
+ b43_radio_set(dev, B2055_C2_TX_BB_MXGM, 0x20);
+ } else {
+ b43_radio_mask(dev, B2055_C1_TX_BB_MXGM, ~0x20);
+ b43_radio_mask(dev, B2055_C2_TX_BB_MXGM, ~0x20);
+ }
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */
+static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core,
+ struct nphy_txgains target,
+ struct nphy_iqcal_params *params)
+{
+ int i, j, indx;
+ u16 gain;
+
+ if (dev->phy.rev >= 3) {
+ params->txgm = target.txgm[core];
+ params->pga = target.pga[core];
+ params->pad = target.pad[core];
+ params->ipa = target.ipa[core];
+ params->cal_gain = (params->txgm << 12) | (params->pga << 8) |
+ (params->pad << 4) | (params->ipa);
+ for (j = 0; j < 5; j++)
+ params->ncorr[j] = 0x79;
+ } else {
+ gain = (target.pad[core]) | (target.pga[core] << 4) |
+ (target.txgm[core] << 8);
+
+ indx = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ?
+ 1 : 0;
+ for (i = 0; i < 9; i++)
+ if (tbl_iqcal_gainparams[indx][i][0] == gain)
+ break;
+ i = min(i, 8);
+
+ params->txgm = tbl_iqcal_gainparams[indx][i][1];
+ params->pga = tbl_iqcal_gainparams[indx][i][2];
+ params->pad = tbl_iqcal_gainparams[indx][i][3];
+ params->cal_gain = (params->txgm << 7) | (params->pga << 4) |
+ (params->pad << 2);
+ for (j = 0; j < 4; j++)
+ params->ncorr[j] = tbl_iqcal_gainparams[indx][i][4 + j];
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/UpdateTxCalLadder */
+static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ int i;
+ u16 scale, entry;
+
+ u16 tmp = nphy->txcal_bbmult;
+ if (core == 0)
+ tmp >>= 8;
+ tmp &= 0xff;
+
+ for (i = 0; i < 18; i++) {
+ scale = (ladder_lo[i].percent * tmp) / 100;
+ entry = ((scale & 0xFF) << 8) | ladder_lo[i].g_env;
+ b43_ntab_write(dev, B43_NTAB16(15, i), entry);
+
+ scale = (ladder_iq[i].percent * tmp) / 100;
+ entry = ((scale & 0xFF) << 8) | ladder_iq[i].g_env;
+ b43_ntab_write(dev, B43_NTAB16(15, i + 32), entry);
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ExtPaSetTxDigiFilts */
+static void b43_nphy_ext_pa_set_tx_dig_filters(struct b43_wldev *dev)
+{
+ int i;
+ for (i = 0; i < 15; i++)
+ b43_phy_write(dev, B43_PHY_N(0x2C5 + i),
+ tbl_tx_filter_coef_rev4[2][i]);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IpaSetTxDigiFilts */
+static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev)
+{
+ int i, j;
+ /* B43_NPHY_TXF_20CO_S0A1, B43_NPHY_TXF_40CO_S0A1, unknown */
+ u16 offset[] = { 0x186, 0x195, 0x2C5 };
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 15; j++)
+ b43_phy_write(dev, B43_PHY_N(offset[i] + j),
+ tbl_tx_filter_coef_rev4[i][j]);
+
+ if (dev->phy.is_40mhz) {
+ for (j = 0; j < 15; j++)
+ b43_phy_write(dev, B43_PHY_N(offset[0] + j),
+ tbl_tx_filter_coef_rev4[3][j]);
+ } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+ for (j = 0; j < 15; j++)
+ b43_phy_write(dev, B43_PHY_N(offset[0] + j),
+ tbl_tx_filter_coef_rev4[5][j]);
+ }
+
+ if (dev->phy.channel == 14)
+ for (j = 0; j < 15; j++)
+ b43_phy_write(dev, B43_PHY_N(offset[0] + j),
+ tbl_tx_filter_coef_rev4[6][j]);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */
+static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+
+ u16 curr_gain[2];
+ struct nphy_txgains target;
+ const u32 *table = NULL;
+
+ if (nphy->txpwrctrl == 0) {
+ int i;
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, true);
+ b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, curr_gain);
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, false);
+
+ for (i = 0; i < 2; ++i) {
+ if (dev->phy.rev >= 3) {
+ target.ipa[i] = curr_gain[i] & 0x000F;
+ target.pad[i] = (curr_gain[i] & 0x00F0) >> 4;
+ target.pga[i] = (curr_gain[i] & 0x0F00) >> 8;
+ target.txgm[i] = (curr_gain[i] & 0x7000) >> 12;
+ } else {
+ target.ipa[i] = curr_gain[i] & 0x0003;
+ target.pad[i] = (curr_gain[i] & 0x000C) >> 2;
+ target.pga[i] = (curr_gain[i] & 0x0070) >> 4;
+ target.txgm[i] = (curr_gain[i] & 0x0380) >> 7;
+ }
+ }
+ } else {
+ int i;
+ u16 index[2];
+ index[0] = (b43_phy_read(dev, B43_NPHY_C1_TXPCTL_STAT) &
+ B43_NPHY_TXPCTL_STAT_BIDX) >>
+ B43_NPHY_TXPCTL_STAT_BIDX_SHIFT;
+ index[1] = (b43_phy_read(dev, B43_NPHY_C2_TXPCTL_STAT) &
+ B43_NPHY_TXPCTL_STAT_BIDX) >>
+ B43_NPHY_TXPCTL_STAT_BIDX_SHIFT;
+
+ for (i = 0; i < 2; ++i) {
+ if (dev->phy.rev >= 3) {
+ enum ieee80211_band band =
+ b43_current_band(dev->wl);
+
+ if ((nphy->ipa2g_on &&
+ band == IEEE80211_BAND_2GHZ) ||
+ (nphy->ipa5g_on &&
+ band == IEEE80211_BAND_5GHZ)) {
+ table = b43_nphy_get_ipa_gain_table(dev);
+ } else {
+ if (band == IEEE80211_BAND_5GHZ) {
+ if (dev->phy.rev == 3)
+ table = b43_ntab_tx_gain_rev3_5ghz;
+ else if (dev->phy.rev == 4)
+ table = b43_ntab_tx_gain_rev4_5ghz;
+ else
+ table = b43_ntab_tx_gain_rev5plus_5ghz;
+ } else {
+ table = b43_ntab_tx_gain_rev3plus_2ghz;
+ }
+ }
+
+ target.ipa[i] = (table[index[i]] >> 16) & 0xF;
+ target.pad[i] = (table[index[i]] >> 20) & 0xF;
+ target.pga[i] = (table[index[i]] >> 24) & 0xF;
+ target.txgm[i] = (table[index[i]] >> 28) & 0xF;
+ } else {
+ table = b43_ntab_tx_gain_rev0_1_2;
+
+ target.ipa[i] = (table[index[i]] >> 16) & 0x3;
+ target.pad[i] = (table[index[i]] >> 18) & 0x3;
+ target.pga[i] = (table[index[i]] >> 20) & 0x7;
+ target.txgm[i] = (table[index[i]] >> 23) & 0x7;
+ }
+ }
+ }
+
+ return target;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhyCleanup */
+static void b43_nphy_tx_cal_phy_cleanup(struct b43_wldev *dev)
+{
+ u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs;
+
+ if (dev->phy.rev >= 3) {
+ b43_phy_write(dev, B43_NPHY_AFECTL_C1, regs[0]);
+ b43_phy_write(dev, B43_NPHY_AFECTL_C2, regs[1]);
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, regs[2]);
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[3]);
+ b43_phy_write(dev, B43_NPHY_BBCFG, regs[4]);
+ b43_ntab_write(dev, B43_NTAB16(8, 3), regs[5]);
+ b43_ntab_write(dev, B43_NTAB16(8, 19), regs[6]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[7]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[8]);
+ b43_phy_write(dev, B43_NPHY_PAPD_EN0, regs[9]);
+ b43_phy_write(dev, B43_NPHY_PAPD_EN1, regs[10]);
+ b43_nphy_reset_cca(dev);
+ } else {
+ b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, regs[0]);
+ b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, regs[1]);
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[2]);
+ b43_ntab_write(dev, B43_NTAB16(8, 2), regs[3]);
+ b43_ntab_write(dev, B43_NTAB16(8, 18), regs[4]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[5]);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[6]);
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhySetup */
+static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev)
+{
+ u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs;
+ u16 tmp;
+
+ regs[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
+ regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
+ if (dev->phy.rev >= 3) {
+ b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0xF0FF, 0x0A00);
+ b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0xF0FF, 0x0A00);
+
+ tmp = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1);
+ regs[2] = tmp;
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, tmp | 0x0600);
+
+ tmp = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+ regs[3] = tmp;
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp | 0x0600);
+
+ regs[4] = b43_phy_read(dev, B43_NPHY_BBCFG);
+ b43_phy_mask(dev, B43_NPHY_BBCFG, (u16)~B43_NPHY_BBCFG_RSTRX);
+
+ tmp = b43_ntab_read(dev, B43_NTAB16(8, 3));
+ regs[5] = tmp;
+ b43_ntab_write(dev, B43_NTAB16(8, 3), 0);
+
+ tmp = b43_ntab_read(dev, B43_NTAB16(8, 19));
+ regs[6] = tmp;
+ b43_ntab_write(dev, B43_NTAB16(8, 19), 0);
+ regs[7] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
+ regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
+
+ b43_nphy_rf_control_intc_override(dev, 2, 1, 3);
+ b43_nphy_rf_control_intc_override(dev, 1, 2, 1);
+ b43_nphy_rf_control_intc_override(dev, 1, 8, 2);
+
+ regs[9] = b43_phy_read(dev, B43_NPHY_PAPD_EN0);
+ regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1);
+ b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001);
+ b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001);
+ } else {
+ b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, 0xA000);
+ b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, 0xA000);
+ tmp = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+ regs[2] = tmp;
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp | 0x3000);
+ tmp = b43_ntab_read(dev, B43_NTAB16(8, 2));
+ regs[3] = tmp;
+ tmp |= 0x2000;
+ b43_ntab_write(dev, B43_NTAB16(8, 2), tmp);
+ tmp = b43_ntab_read(dev, B43_NTAB16(8, 18));
+ regs[4] = tmp;
+ tmp |= 0x2000;
+ b43_ntab_write(dev, B43_NTAB16(8, 18), tmp);
+ regs[5] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
+ regs[6] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+ tmp = 0x0180;
+ else
+ tmp = 0x0120;
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, tmp);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, tmp);
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SaveCal */
+static void b43_nphy_save_cal(struct b43_wldev *dev)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+
+ struct b43_phy_n_iq_comp *rxcal_coeffs = NULL;
+ u16 *txcal_radio_regs = NULL;
+ u8 *iqcal_chanspec;
+ u16 *table = NULL;
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 1);
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_2G;
+ txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_2G;
+ iqcal_chanspec = &nphy->iqcal_chanspec_2G;
+ table = nphy->cal_cache.txcal_coeffs_2G;
+ } else {
+ rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_5G;
+ txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_5G;
+ iqcal_chanspec = &nphy->iqcal_chanspec_5G;
+ table = nphy->cal_cache.txcal_coeffs_5G;
+ }
+
+ b43_nphy_rx_iq_coeffs(dev, false, rxcal_coeffs);
+ /* TODO use some definitions */
+ if (dev->phy.rev >= 3) {
+ txcal_radio_regs[0] = b43_radio_read(dev, 0x2021);
+ txcal_radio_regs[1] = b43_radio_read(dev, 0x2022);
+ txcal_radio_regs[2] = b43_radio_read(dev, 0x3021);
+ txcal_radio_regs[3] = b43_radio_read(dev, 0x3022);
+ txcal_radio_regs[4] = b43_radio_read(dev, 0x2023);
+ txcal_radio_regs[5] = b43_radio_read(dev, 0x2024);
+ txcal_radio_regs[6] = b43_radio_read(dev, 0x3023);
+ txcal_radio_regs[7] = b43_radio_read(dev, 0x3024);
+ } else {
+ txcal_radio_regs[0] = b43_radio_read(dev, 0x8B);
+ txcal_radio_regs[1] = b43_radio_read(dev, 0xBA);
+ txcal_radio_regs[2] = b43_radio_read(dev, 0x8D);
+ txcal_radio_regs[3] = b43_radio_read(dev, 0xBC);
+ }
+ *iqcal_chanspec = nphy->radio_chanspec;
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 8, table);
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 0);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */
+static void b43_nphy_restore_cal(struct b43_wldev *dev)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+
+ u16 coef[4];
+ u16 *loft = NULL;
+ u16 *table = NULL;
+
+ int i;
+ u16 *txcal_radio_regs = NULL;
+ struct b43_phy_n_iq_comp *rxcal_coeffs = NULL;
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ if (nphy->iqcal_chanspec_2G == 0)
+ return;
+ table = nphy->cal_cache.txcal_coeffs_2G;
+ loft = &nphy->cal_cache.txcal_coeffs_2G[5];
+ } else {
+ if (nphy->iqcal_chanspec_5G == 0)
+ return;
+ table = nphy->cal_cache.txcal_coeffs_5G;
+ loft = &nphy->cal_cache.txcal_coeffs_5G[5];
+ }
+
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 4, table);
+
+ for (i = 0; i < 4; i++) {
+ if (dev->phy.rev >= 3)
+ table[i] = coef[i];
+ else
+ coef[i] = 0;
+ }
+
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4, coef);
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2, loft);
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 93), 2, loft);
+
+ if (dev->phy.rev < 2)
+ b43_nphy_tx_iq_workaround(dev);
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_2G;
+ rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_2G;
+ } else {
+ txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_5G;
+ rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_5G;
+ }
+
+ /* TODO use some definitions */
+ if (dev->phy.rev >= 3) {
+ b43_radio_write(dev, 0x2021, txcal_radio_regs[0]);
+ b43_radio_write(dev, 0x2022, txcal_radio_regs[1]);
+ b43_radio_write(dev, 0x3021, txcal_radio_regs[2]);
+ b43_radio_write(dev, 0x3022, txcal_radio_regs[3]);
+ b43_radio_write(dev, 0x2023, txcal_radio_regs[4]);
+ b43_radio_write(dev, 0x2024, txcal_radio_regs[5]);
+ b43_radio_write(dev, 0x3023, txcal_radio_regs[6]);
+ b43_radio_write(dev, 0x3024, txcal_radio_regs[7]);
+ } else {
+ b43_radio_write(dev, 0x8B, txcal_radio_regs[0]);
+ b43_radio_write(dev, 0xBA, txcal_radio_regs[1]);
+ b43_radio_write(dev, 0x8D, txcal_radio_regs[2]);
+ b43_radio_write(dev, 0xBC, txcal_radio_regs[3]);
+ }
+ b43_nphy_rx_iq_coeffs(dev, true, rxcal_coeffs);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalTxIqlo */
+static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
+ struct nphy_txgains target,
+ bool full, bool mphase)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ int i;
+ int error = 0;
+ int freq;
+ bool avoid = false;
+ u8 length;
+ u16 tmp, core, type, count, max, numb, last, cmd;
+ const u16 *table;
+ bool phy6or5x;
+
+ u16 buffer[11];
+ u16 diq_start = 0;
+ u16 save[2];
+ u16 gain[2];
+ struct nphy_iqcal_params params[2];
+ bool updated[2] = { };
+
+ b43_nphy_stay_in_carrier_search(dev, true);
+
+ if (dev->phy.rev >= 4) {
+ avoid = nphy->hang_avoid;
+ nphy->hang_avoid = 0;
+ }
+
+ b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, save);
+
+ for (i = 0; i < 2; i++) {
+ b43_nphy_iq_cal_gain_params(dev, i, target, &params[i]);
+ gain[i] = params[i].cal_gain;
+ }
+
+ b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, gain);
+
+ b43_nphy_tx_cal_radio_setup(dev);
+ b43_nphy_tx_cal_phy_setup(dev);
+
+ phy6or5x = dev->phy.rev >= 6 ||
+ (dev->phy.rev == 5 && nphy->ipa2g_on &&
+ b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ);
+ if (phy6or5x) {
+ if (dev->phy.is_40mhz) {
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 0), 18,
+ tbl_tx_iqlo_cal_loft_ladder_40);
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 32), 18,
+ tbl_tx_iqlo_cal_iqimb_ladder_40);
+ } else {
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 0), 18,
+ tbl_tx_iqlo_cal_loft_ladder_20);
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 32), 18,
+ tbl_tx_iqlo_cal_iqimb_ladder_20);
+ }
+ }
+
+ b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9);
+
+ if (!dev->phy.is_40mhz)
+ freq = 2500;
+ else
+ freq = 5000;
+
+ if (nphy->mphase_cal_phase_id > 2)
+ b43_nphy_run_samples(dev, (dev->phy.is_40mhz ? 40 : 20) * 8,
+ 0xFFFF, 0, true, false);
+ else
+ error = b43_nphy_tx_tone(dev, freq, 250, true, false);
+
+ if (error == 0) {
+ if (nphy->mphase_cal_phase_id > 2) {
+ table = nphy->mphase_txcal_bestcoeffs;
+ length = 11;
+ if (dev->phy.rev < 3)
+ length -= 2;
+ } else {
+ if (!full && nphy->txiqlocal_coeffsvalid) {
+ table = nphy->txiqlocal_bestc;
+ length = 11;
+ if (dev->phy.rev < 3)
+ length -= 2;
+ } else {
+ full = true;
+ if (dev->phy.rev >= 3) {
+ table = tbl_tx_iqlo_cal_startcoefs_nphyrev3;
+ length = B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3;
+ } else {
+ table = tbl_tx_iqlo_cal_startcoefs;
+ length = B43_NTAB_TX_IQLO_CAL_STARTCOEFS;
+ }
+ }
+ }
+
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 64), length, table);
+
+ if (full) {
+ if (dev->phy.rev >= 3)
+ max = B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3;
+ else
+ max = B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL;
+ } else {
+ if (dev->phy.rev >= 3)
+ max = B43_NTAB_TX_IQLO_CAL_CMDS_RECAL_REV3;
+ else
+ max = B43_NTAB_TX_IQLO_CAL_CMDS_RECAL;
+ }
+
+ if (mphase) {
+ count = nphy->mphase_txcal_cmdidx;
+ numb = min(max,
+ (u16)(count + nphy->mphase_txcal_numcmds));
+ } else {
+ count = 0;
+ numb = max;
+ }
+
+ for (; count < numb; count++) {
+ if (full) {
+ if (dev->phy.rev >= 3)
+ cmd = tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[count];
+ else
+ cmd = tbl_tx_iqlo_cal_cmds_fullcal[count];
+ } else {
+ if (dev->phy.rev >= 3)
+ cmd = tbl_tx_iqlo_cal_cmds_recal_nphyrev3[count];
+ else
+ cmd = tbl_tx_iqlo_cal_cmds_recal[count];
+ }
+
+ core = (cmd & 0x3000) >> 12;
+ type = (cmd & 0x0F00) >> 8;
+
+ if (phy6or5x && updated[core] == 0) {
+ b43_nphy_update_tx_cal_ladder(dev, core);
+ updated[core] = 1;
+ }
+
+ tmp = (params[core].ncorr[type] << 8) | 0x66;
+ b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDNNUM, tmp);
+
+ if (type == 1 || type == 3 || type == 4) {
+ buffer[0] = b43_ntab_read(dev,
+ B43_NTAB16(15, 69 + core));
+ diq_start = buffer[0];
+ buffer[0] = 0;
+ b43_ntab_write(dev, B43_NTAB16(15, 69 + core),
+ 0);
+ }
+
+ b43_phy_write(dev, B43_NPHY_IQLOCAL_CMD, cmd);
+ for (i = 0; i < 2000; i++) {
+ tmp = b43_phy_read(dev, B43_NPHY_IQLOCAL_CMD);
+ if (tmp & 0xC000)
+ break;
+ udelay(10);
+ }
+
+ b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length,
+ buffer);
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 64), length,
+ buffer);
+
+ if (type == 1 || type == 3 || type == 4)
+ buffer[0] = diq_start;
+ }
+
+ if (mphase)
+ nphy->mphase_txcal_cmdidx = (numb >= max) ? 0 : numb;
+
+ last = (dev->phy.rev < 3) ? 6 : 7;
+
+ if (!mphase || nphy->mphase_cal_phase_id == last) {
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 96), 4, buffer);
+ b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 4, buffer);
+ if (dev->phy.rev < 3) {
+ buffer[0] = 0;
+ buffer[1] = 0;
+ buffer[2] = 0;
+ buffer[3] = 0;
+ }
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4,
+ buffer);
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 101), 2,
+ buffer);
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2,
+ buffer);
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 93), 2,
+ buffer);
+ length = 11;
+ if (dev->phy.rev < 3)
+ length -= 2;
+ b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length,
+ nphy->txiqlocal_bestc);
+ nphy->txiqlocal_coeffsvalid = true;
+ /* TODO: Set nphy->txiqlocal_chanspec to
+ the current channel */
+ } else {
+ length = 11;
+ if (dev->phy.rev < 3)
+ length -= 2;
+ b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length,
+ nphy->mphase_txcal_bestcoeffs);
+ }
+
+ b43_nphy_stop_playback(dev);
+ b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0);
+ }
+
+ b43_nphy_tx_cal_phy_cleanup(dev);
+ b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, save);
+
+ if (dev->phy.rev < 2 && (!mphase || nphy->mphase_cal_phase_id == last))
+ b43_nphy_tx_iq_workaround(dev);
+
+ if (dev->phy.rev >= 4)
+ nphy->hang_avoid = avoid;
+
+ b43_nphy_stay_in_carrier_search(dev, false);
+
+ return error;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ReapplyTxCalCoeffs */
+static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ u8 i;
+ u16 buffer[7];
+ bool equal = true;
+
+ if (!nphy->txiqlocal_coeffsvalid || 1 /* FIXME */)
+ return;
+
+ b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer);
+ for (i = 0; i < 4; i++) {
+ if (buffer[i] != nphy->txiqlocal_bestc[i]) {
+ equal = false;
+ break;
+ }
+ }
+
+ if (!equal) {
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 4,
+ nphy->txiqlocal_bestc);
+ for (i = 0; i < 4; i++)
+ buffer[i] = 0;
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4,
+ buffer);
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2,
+ &nphy->txiqlocal_bestc[5]);
+ b43_ntab_write_bulk(dev, B43_NTAB16(15, 93), 2,
+ &nphy->txiqlocal_bestc[5]);
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIqRev2 */
+static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
+ struct nphy_txgains target, u8 type, bool debug)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ int i, j, index;
+ u8 rfctl[2];
+ u8 afectl_core;
+ u16 tmp[6];
+ u16 cur_hpf1, cur_hpf2, cur_lna;
+ u32 real, imag;
+ enum ieee80211_band band;
+
+ u8 use;
+ u16 cur_hpf;
+ u16 lna[3] = { 3, 3, 1 };
+ u16 hpf1[3] = { 7, 2, 0 };
+ u16 hpf2[3] = { 2, 0, 0 };
+ u32 power[3] = { };
+ u16 gain_save[2];
+ u16 cal_gain[2];
+ struct nphy_iqcal_params cal_params[2];
+ struct nphy_iq_est est;
+ int ret = 0;
+ bool playtone = true;
+ int desired = 13;
+
+ b43_nphy_stay_in_carrier_search(dev, 1);
+
+ if (dev->phy.rev < 2)
+ b43_nphy_reapply_tx_cal_coeffs(dev);
+ b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save);
+ for (i = 0; i < 2; i++) {
+ b43_nphy_iq_cal_gain_params(dev, i, target, &cal_params[i]);
+ cal_gain[i] = cal_params[i].cal_gain;
+ }
+ b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, cal_gain);
+
+ for (i = 0; i < 2; i++) {
+ if (i == 0) {
+ rfctl[0] = B43_NPHY_RFCTL_INTC1;
+ rfctl[1] = B43_NPHY_RFCTL_INTC2;
+ afectl_core = B43_NPHY_AFECTL_C1;
+ } else {
+ rfctl[0] = B43_NPHY_RFCTL_INTC2;
+ rfctl[1] = B43_NPHY_RFCTL_INTC1;
+ afectl_core = B43_NPHY_AFECTL_C2;
+ }
+
+ tmp[1] = b43_phy_read(dev, B43_NPHY_RFSEQCA);
+ tmp[2] = b43_phy_read(dev, afectl_core);
+ tmp[3] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+ tmp[4] = b43_phy_read(dev, rfctl[0]);
+ tmp[5] = b43_phy_read(dev, rfctl[1]);
+
+ b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
+ (u16)~B43_NPHY_RFSEQCA_RXDIS,
+ ((1 - i) << B43_NPHY_RFSEQCA_RXDIS_SHIFT));
+ b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN,
+ (1 - i));
+ b43_phy_set(dev, afectl_core, 0x0006);
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0006);
+
+ band = b43_current_band(dev->wl);
+
+ if (nphy->rxcalparams & 0xFF000000) {
+ if (band == IEEE80211_BAND_5GHZ)
+ b43_phy_write(dev, rfctl[0], 0x140);
+ else
+ b43_phy_write(dev, rfctl[0], 0x110);
+ } else {
+ if (band == IEEE80211_BAND_5GHZ)
+ b43_phy_write(dev, rfctl[0], 0x180);
+ else
+ b43_phy_write(dev, rfctl[0], 0x120);
+ }
+
+ if (band == IEEE80211_BAND_5GHZ)
+ b43_phy_write(dev, rfctl[1], 0x148);
+ else
+ b43_phy_write(dev, rfctl[1], 0x114);
+
+ if (nphy->rxcalparams & 0x10000) {
+ b43_radio_maskset(dev, B2055_C1_GENSPARE2, 0xFC,
+ (i + 1));
+ b43_radio_maskset(dev, B2055_C2_GENSPARE2, 0xFC,
+ (2 - i));
+ }
+
+ for (j = 0; i < 4; j++) {
+ if (j < 3) {
+ cur_lna = lna[j];
+ cur_hpf1 = hpf1[j];
+ cur_hpf2 = hpf2[j];
+ } else {
+ if (power[1] > 10000) {
+ use = 1;
+ cur_hpf = cur_hpf1;
+ index = 2;
+ } else {
+ if (power[0] > 10000) {
+ use = 1;
+ cur_hpf = cur_hpf1;
+ index = 1;
+ } else {
+ index = 0;
+ use = 2;
+ cur_hpf = cur_hpf2;
+ }
+ }
+ cur_lna = lna[index];
+ cur_hpf1 = hpf1[index];
+ cur_hpf2 = hpf2[index];
+ cur_hpf += desired - hweight32(power[index]);
+ cur_hpf = clamp_val(cur_hpf, 0, 10);
+ if (use == 1)
+ cur_hpf1 = cur_hpf;
+ else
+ cur_hpf2 = cur_hpf;
+ }
+
+ tmp[0] = ((cur_hpf2 << 8) | (cur_hpf1 << 4) |
+ (cur_lna << 2));
+ b43_nphy_rf_control_override(dev, 0x400, tmp[0], 3,
+ false);
+ b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+ b43_nphy_stop_playback(dev);
+
+ if (playtone) {
+ ret = b43_nphy_tx_tone(dev, 4000,
+ (nphy->rxcalparams & 0xFFFF),
+ false, false);
+ playtone = false;
+ } else {
+ b43_nphy_run_samples(dev, 160, 0xFFFF, 0,
+ false, false);
+ }
+
+ if (ret == 0) {
+ if (j < 3) {
+ b43_nphy_rx_iq_est(dev, &est, 1024, 32,
+ false);
+ if (i == 0) {
+ real = est.i0_pwr;
+ imag = est.q0_pwr;
+ } else {
+ real = est.i1_pwr;
+ imag = est.q1_pwr;
+ }
+ power[i] = ((real + imag) / 1024) + 1;
+ } else {
+ b43_nphy_calc_rx_iq_comp(dev, 1 << i);
+ }
+ b43_nphy_stop_playback(dev);
+ }
+
+ if (ret != 0)
+ break;
+ }
+
+ b43_radio_mask(dev, B2055_C1_GENSPARE2, 0xFC);
+ b43_radio_mask(dev, B2055_C2_GENSPARE2, 0xFC);
+ b43_phy_write(dev, rfctl[1], tmp[5]);
+ b43_phy_write(dev, rfctl[0], tmp[4]);
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp[3]);
+ b43_phy_write(dev, afectl_core, tmp[2]);
+ b43_phy_write(dev, B43_NPHY_RFSEQCA, tmp[1]);
+
+ if (ret != 0)
+ break;
+ }
+
+ b43_nphy_rf_control_override(dev, 0x400, 0, 3, true);
+ b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+ b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save);
+
+ b43_nphy_stay_in_carrier_search(dev, 0);
+
+ return ret;
+}
+
+static int b43_nphy_rev3_cal_rx_iq(struct b43_wldev *dev,
+ struct nphy_txgains target, u8 type, bool debug)
+{
+ return -1;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIq */
+static int b43_nphy_cal_rx_iq(struct b43_wldev *dev,
+ struct nphy_txgains target, u8 type, bool debug)
+{
+ if (dev->phy.rev >= 3)
+ return b43_nphy_rev3_cal_rx_iq(dev, target, type, debug);
+ else
+ return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug);
+}
+
+/*
+ * Init N-PHY
+ * http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N
+ */
int b43_phy_initn(struct b43_wldev *dev)
{
+ struct ssb_bus *bus = dev->dev->bus;
struct b43_phy *phy = &dev->phy;
+ struct b43_phy_n *nphy = phy->n;
+ u8 tx_pwr_state;
+ struct nphy_txgains target;
u16 tmp;
+ enum ieee80211_band tmp2;
+ bool do_rssi_cal;
- //TODO: Spectral management
+ u16 clip[2];
+ bool do_cal = false;
+
+ if ((dev->phy.rev >= 3) &&
+ (bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
+ (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) {
+ chipco_set32(&dev->dev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40);
+ }
+ nphy->deaf_count = 0;
b43_nphy_tables_init(dev);
+ nphy->crsminpwr_adjusted = false;
+ nphy->noisevars_adjusted = false;
/* Clear all overrides */
- b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
+ if (dev->phy.rev >= 3) {
+ b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, 0);
+ b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
+ b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, 0);
+ b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, 0);
+ } else {
+ b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
+ }
b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0);
b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0);
- b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0);
- b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0);
+ if (dev->phy.rev < 6) {
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0);
+ }
b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
~(B43_NPHY_RFSEQMODE_CAOVER |
B43_NPHY_RFSEQMODE_TROVER));
+ if (dev->phy.rev >= 3)
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, 0);
b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0);
- tmp = (phy->rev < 2) ? 64 : 59;
- b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
- ~B43_NPHY_BPHY_CTL3_SCALE,
- tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT);
-
+ if (dev->phy.rev <= 2) {
+ tmp = (dev->phy.rev == 2) ? 0x3B : 0x40;
+ b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
+ ~B43_NPHY_BPHY_CTL3_SCALE,
+ tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT);
+ }
b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
- b43_phy_write(dev, B43_NPHY_TXREALFD, 184);
- b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200);
- b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80);
- b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511);
+ if (bus->sprom.boardflags2_lo & 0x100 ||
+ (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
+ bus->boardinfo.type == 0x8B))
+ b43_phy_write(dev, B43_NPHY_TXREALFD, 0xA0);
+ else
+ b43_phy_write(dev, B43_NPHY_TXREALFD, 0xB8);
+ b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 0xC8);
+ b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x50);
+ b43_phy_write(dev, B43_NPHY_TXRIFS_FRDEL, 0x30);
- //TODO MIMO-Config
- //TODO Update TX/RX chain
+ b43_nphy_update_mimo_config(dev, nphy->preamble_override);
+ b43_nphy_update_txrx_chain(dev);
if (phy->rev < 2) {
b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8);
b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4);
}
+
+ tmp2 = b43_current_band(dev->wl);
+ if ((nphy->ipa2g_on && tmp2 == IEEE80211_BAND_2GHZ) ||
+ (nphy->ipa5g_on && tmp2 == IEEE80211_BAND_5GHZ)) {
+ b43_phy_set(dev, B43_NPHY_PAPD_EN0, 0x1);
+ b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ0, 0x007F,
+ nphy->papd_epsilon_offset[0] << 7);
+ b43_phy_set(dev, B43_NPHY_PAPD_EN1, 0x1);
+ b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ1, 0x007F,
+ nphy->papd_epsilon_offset[1] << 7);
+ b43_nphy_int_pa_set_tx_dig_filters(dev);
+ } else if (phy->rev >= 5) {
+ b43_nphy_ext_pa_set_tx_dig_filters(dev);
+ }
+
b43_nphy_workarounds(dev);
- b43_nphy_reset_cca(dev);
- ssb_write32(dev->dev, SSB_TMSLOW,
- ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN);
+ /* Reset CCA, in init code it differs a little from standard way */
+ b43_nphy_bmac_clock_fgc(dev, 1);
+ tmp = b43_phy_read(dev, B43_NPHY_BBCFG);
+ b43_phy_write(dev, B43_NPHY_BBCFG, tmp | B43_NPHY_BBCFG_RSTCCA);
+ b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA);
+ b43_nphy_bmac_clock_fgc(dev, 0);
+
+ /* TODO N PHY MAC PHY Clock Set with argument 1 */
+
+ b43_nphy_pa_override(dev, false);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+ b43_nphy_pa_override(dev, true);
+
+ b43_nphy_classifier(dev, 0, 0);
+ b43_nphy_read_clip_detection(dev, clip);
+ tx_pwr_state = nphy->txpwrctrl;
+ /* TODO N PHY TX power control with argument 0
+ (turning off power control) */
+ /* TODO Fix the TX Power Settings */
+ /* TODO N PHY TX Power Control Idle TSSI */
+ /* TODO N PHY TX Power Control Setup */
+
+ if (phy->rev >= 3) {
+ /* TODO */
+ } else {
+ b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128,
+ b43_ntab_tx_gain_rev0_1_2);
+ b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128,
+ b43_ntab_tx_gain_rev0_1_2);
+ }
+
+ if (nphy->phyrxchain != 3)
+ ;/* TODO N PHY RX Core Set State with phyrxchain as argument */
+ if (nphy->mphase_cal_phase_id > 0)
+ ;/* TODO PHY Periodic Calibration Multi-Phase Restart */
+
+ do_rssi_cal = false;
+ if (phy->rev >= 3) {
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ do_rssi_cal = (nphy->rssical_chanspec_2G == 0);
+ else
+ do_rssi_cal = (nphy->rssical_chanspec_5G == 0);
+
+ if (do_rssi_cal)
+ b43_nphy_rssi_cal(dev);
+ else
+ b43_nphy_restore_rssi_cal(dev);
+ } else {
+ b43_nphy_rssi_cal(dev);
+ }
+
+ if (!((nphy->measure_hold & 0x6) != 0)) {
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ do_cal = (nphy->iqcal_chanspec_2G == 0);
+ else
+ do_cal = (nphy->iqcal_chanspec_5G == 0);
+
+ if (nphy->mute)
+ do_cal = false;
+
+ if (do_cal) {
+ target = b43_nphy_get_tx_gains(dev);
+
+ if (nphy->antsel_type == 2)
+ ;/*TODO NPHY Superswitch Init with argument 1*/
+ if (nphy->perical != 2) {
+ b43_nphy_rssi_cal(dev);
+ if (phy->rev >= 3) {
+ nphy->cal_orig_pwr_idx[0] =
+ nphy->txpwrindex[0].index_internal;
+ nphy->cal_orig_pwr_idx[1] =
+ nphy->txpwrindex[1].index_internal;
+ /* TODO N PHY Pre Calibrate TX Gain */
+ target = b43_nphy_get_tx_gains(dev);
+ }
+ }
+ }
+ }
+
+ if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false)) {
+ if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0)
+ b43_nphy_save_cal(dev);
+ else if (nphy->mphase_cal_phase_id == 0)
+ ;/* N PHY Periodic Calibration with argument 3 */
+ } else {
+ b43_nphy_restore_cal(dev);
+ }
- b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */
- //TODO read core1/2 clip1 thres regs
-
- if (1 /* FIXME Band is 2.4GHz */)
- b43_nphy_bphy_init(dev);
- //TODO disable TX power control
- //TODO Fix the TX power settings
- //TODO Init periodic calibration with reason 3
- b43_nphy_rssi_cal(dev, 2);
- b43_nphy_rssi_cal(dev, 0);
- b43_nphy_rssi_cal(dev, 1);
- //TODO get TX gain
- //TODO init superswitch
- //TODO calibrate LO
- //TODO idle TSSI TX pctl
- //TODO TX power control power setup
- //TODO table writes
- //TODO TX power control coefficients
- //TODO enable TX power control
- //TODO control antenna selection
- //TODO init radar detection
- //TODO reset channel if changed
+ b43_nphy_tx_pwr_ctrl_coef_setup(dev);
+ /* TODO N PHY TX Power Control Enable with argument tx_pwr_state */
+ b43_phy_write(dev, B43_NPHY_TXMACIF_HOLDOFF, 0x0015);
+ b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320);
+ if (phy->rev >= 3 && phy->rev <= 6)
+ b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0014);
+ b43_nphy_tx_lp_fbw(dev);
+ if (phy->rev >= 3)
+ b43_nphy_spur_workaround(dev);
b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n");
return 0;
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h
index 1749aef4147d..403aad3f894f 100644
--- a/drivers/net/wireless/b43/phy_n.h
+++ b/drivers/net/wireless/b43/phy_n.h
@@ -231,6 +231,7 @@
#define B43_NPHY_C2_TXIQ_COMP_OFF B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */
#define B43_NPHY_C1_TXCTL B43_PHY_N(0x08B) /* Core 1 TX control */
#define B43_NPHY_C2_TXCTL B43_PHY_N(0x08C) /* Core 2 TX control */
+#define B43_NPHY_AFECTL_OVER1 B43_PHY_N(0x08F) /* AFE control override 1 */
#define B43_NPHY_SCRAM_SIGCTL B43_PHY_N(0x090) /* Scram signal control */
#define B43_NPHY_SCRAM_SIGCTL_INITST 0x007F /* Initial state value */
#define B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT 0
@@ -705,6 +706,10 @@
#define B43_NPHY_TXPCTL_INIT B43_PHY_N(0x222) /* TX power controll init */
#define B43_NPHY_TXPCTL_INIT_PIDXI1 0x00FF /* Power index init 1 */
#define B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT 0
+#define B43_NPHY_PAPD_EN0 B43_PHY_N(0x297) /* PAPD Enable0 TBD */
+#define B43_NPHY_EPS_TABLE_ADJ0 B43_PHY_N(0x298) /* EPS Table Adj0 TBD */
+#define B43_NPHY_PAPD_EN1 B43_PHY_N(0x29B) /* PAPD Enable1 TBD */
+#define B43_NPHY_EPS_TABLE_ADJ1 B43_PHY_N(0x29C) /* EPS Table Adj1 TBD */
@@ -919,8 +924,99 @@
struct b43_wldev;
+struct b43_phy_n_iq_comp {
+ s16 a0;
+ s16 b0;
+ s16 a1;
+ s16 b1;
+};
+
+struct b43_phy_n_rssical_cache {
+ u16 rssical_radio_regs_2G[2];
+ u16 rssical_phy_regs_2G[12];
+
+ u16 rssical_radio_regs_5G[2];
+ u16 rssical_phy_regs_5G[12];
+};
+
+struct b43_phy_n_cal_cache {
+ u16 txcal_radio_regs_2G[8];
+ u16 txcal_coeffs_2G[8];
+ struct b43_phy_n_iq_comp rxcal_coeffs_2G;
+
+ u16 txcal_radio_regs_5G[8];
+ u16 txcal_coeffs_5G[8];
+ struct b43_phy_n_iq_comp rxcal_coeffs_5G;
+};
+
+struct b43_phy_n_txpwrindex {
+ s8 index;
+ s8 index_internal;
+ s8 index_internal_save;
+ u16 AfectrlOverride;
+ u16 AfeCtrlDacGain;
+ u16 rad_gain;
+ u8 bbmult;
+ u16 iqcomp_a;
+ u16 iqcomp_b;
+ u16 locomp;
+};
+
struct b43_phy_n {
- //TODO lots of missing stuff
+ u8 antsel_type;
+ u8 cal_orig_pwr_idx[2];
+ u8 measure_hold;
+ u8 phyrxchain;
+ u8 perical;
+ u32 deaf_count;
+ u32 rxcalparams;
+ bool hang_avoid;
+ bool mute;
+ u16 papd_epsilon_offset[2];
+ s32 preamble_override;
+ u32 bb_mult_save;
+ u16 radio_chanspec;
+
+ bool gain_boost;
+ bool elna_gain_config;
+ bool band5g_pwrgain;
+
+ u8 mphase_cal_phase_id;
+ u16 mphase_txcal_cmdidx;
+ u16 mphase_txcal_numcmds;
+ u16 mphase_txcal_bestcoeffs[11];
+
+ u8 txpwrctrl;
+ u16 txcal_bbmult;
+ u16 txiqlocal_bestc[11];
+ bool txiqlocal_coeffsvalid;
+ struct b43_phy_n_txpwrindex txpwrindex[2];
+
+ u8 txrx_chain;
+ u16 tx_rx_cal_phy_saveregs[11];
+ u16 tx_rx_cal_radio_saveregs[22];
+
+ u16 rfctrl_intc1_save;
+ u16 rfctrl_intc2_save;
+
+ u16 classifier_state;
+ u16 clip_state[2];
+
+ bool aband_spurwar_en;
+ bool gband_spurwar_en;
+
+ bool ipa2g_on;
+ u8 iqcal_chanspec_2G;
+ u8 rssical_chanspec_2G;
+
+ bool ipa5g_on;
+ u8 iqcal_chanspec_5G;
+ u8 rssical_chanspec_5G;
+
+ struct b43_phy_n_rssical_cache rssical_cache;
+ struct b43_phy_n_cal_cache cal_cache;
+ bool crsminpwr_adjusted;
+ bool noisevars_adjusted;
};
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
index c01b8e02412f..a6062c3e89a5 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -559,7 +559,6 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb)
b43err(dev->wl, "PIO transmission failure\n");
goto out;
}
- q->nr_tx_packets++;
B43_WARN_ON(q->buffer_used > q->buffer_size);
if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) ||
@@ -605,22 +604,6 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
}
}
-void b43_pio_get_tx_stats(struct b43_wldev *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
- const int nr_queues = dev->wl->hw->queues;
- struct b43_pio_txqueue *q;
- int i;
-
- for (i = 0; i < nr_queues; i++) {
- q = select_queue_by_priority(dev, i);
-
- stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots;
- stats[i].limit = B43_PIO_MAX_NR_TXPACKETS;
- stats[i].count = q->nr_tx_packets;
- }
-}
-
/* Returns whether we should fetch another frame. */
static bool pio_rx_frame(struct b43_pio_rxqueue *q)
{
diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h
index 7dd649c9ddad..1e516147424f 100644
--- a/drivers/net/wireless/b43/pio.h
+++ b/drivers/net/wireless/b43/pio.h
@@ -55,8 +55,6 @@
#define B43_PIO_MAX_NR_TXPACKETS 32
-#ifdef CONFIG_B43_PIO
-
struct b43_pio_txpacket {
/* Pointer to the TX queue we belong to. */
struct b43_pio_txqueue *queue;
@@ -92,9 +90,6 @@ struct b43_pio_txqueue {
struct b43_pio_txpacket packets[B43_PIO_MAX_NR_TXPACKETS];
struct list_head packets_list;
- /* Total number of transmitted packets. */
- unsigned int nr_tx_packets;
-
/* Shortcut to the 802.11 core revision. This is to
* avoid horrible pointer dereferencing in the fastpaths. */
u8 rev;
@@ -162,49 +157,9 @@ void b43_pio_free(struct b43_wldev *dev);
int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb);
void b43_pio_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status);
-void b43_pio_get_tx_stats(struct b43_wldev *dev,
- struct ieee80211_tx_queue_stats *stats);
void b43_pio_rx(struct b43_pio_rxqueue *q);
void b43_pio_tx_suspend(struct b43_wldev *dev);
void b43_pio_tx_resume(struct b43_wldev *dev);
-
-#else /* CONFIG_B43_PIO */
-
-
-static inline int b43_pio_init(struct b43_wldev *dev)
-{
- return 0;
-}
-static inline void b43_pio_free(struct b43_wldev *dev)
-{
-}
-static inline void b43_pio_stop(struct b43_wldev *dev)
-{
-}
-static inline int b43_pio_tx(struct b43_wldev *dev,
- struct sk_buff *skb)
-{
- return 0;
-}
-static inline void b43_pio_handle_txstatus(struct b43_wldev *dev,
- const struct b43_txstatus *status)
-{
-}
-static inline void b43_pio_get_tx_stats(struct b43_wldev *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
-}
-static inline void b43_pio_rx(struct b43_pio_rxqueue *q)
-{
-}
-static inline void b43_pio_tx_suspend(struct b43_wldev *dev)
-{
-}
-static inline void b43_pio_tx_resume(struct b43_wldev *dev)
-{
-}
-
-#endif /* CONFIG_B43_PIO */
#endif /* B43_PIO_H_ */
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index 4e2336315545..a00d509150f7 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -1336,7 +1336,7 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel)
}
-const u8 b43_ntab_adjustpower0[] = {
+static const u8 b43_ntab_adjustpower0[] = {
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
@@ -1355,7 +1355,7 @@ const u8 b43_ntab_adjustpower0[] = {
0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
};
-const u8 b43_ntab_adjustpower1[] = {
+static const u8 b43_ntab_adjustpower1[] = {
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
@@ -1374,11 +1374,11 @@ const u8 b43_ntab_adjustpower1[] = {
0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
};
-const u16 b43_ntab_bdi[] = {
+static const u16 b43_ntab_bdi[] = {
0x0070, 0x0126, 0x012C, 0x0246, 0x048D, 0x04D2,
};
-const u32 b43_ntab_channelest[] = {
+static const u32 b43_ntab_channelest[] = {
0x44444444, 0x44444444, 0x44444444, 0x44444444,
0x44444444, 0x44444444, 0x44444444, 0x44444444,
0x10101010, 0x10101010, 0x10101010, 0x10101010,
@@ -1405,7 +1405,7 @@ const u32 b43_ntab_channelest[] = {
0x10101010, 0x10101010, 0x10101010, 0x10101010,
};
-const u8 b43_ntab_estimatepowerlt0[] = {
+static const u8 b43_ntab_estimatepowerlt0[] = {
0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49,
0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39,
@@ -1416,7 +1416,7 @@ const u8 b43_ntab_estimatepowerlt0[] = {
0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
};
-const u8 b43_ntab_estimatepowerlt1[] = {
+static const u8 b43_ntab_estimatepowerlt1[] = {
0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49,
0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39,
@@ -1427,14 +1427,14 @@ const u8 b43_ntab_estimatepowerlt1[] = {
0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
};
-const u8 b43_ntab_framelookup[] = {
+static const u8 b43_ntab_framelookup[] = {
0x02, 0x04, 0x14, 0x14, 0x03, 0x05, 0x16, 0x16,
0x0A, 0x0C, 0x1C, 0x1C, 0x0B, 0x0D, 0x1E, 0x1E,
0x06, 0x08, 0x18, 0x18, 0x07, 0x09, 0x1A, 0x1A,
0x0E, 0x10, 0x20, 0x28, 0x0F, 0x11, 0x22, 0x2A,
};
-const u32 b43_ntab_framestruct[] = {
+static const u32 b43_ntab_framestruct[] = {
0x08004A04, 0x00100000, 0x01000A05, 0x00100020,
0x09804506, 0x00100030, 0x09804507, 0x00100030,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
@@ -1645,7 +1645,7 @@ const u32 b43_ntab_framestruct[] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000,
};
-const u32 b43_ntab_gainctl0[] = {
+static const u32 b43_ntab_gainctl0[] = {
0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
@@ -1680,7 +1680,7 @@ const u32 b43_ntab_gainctl0[] = {
0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
};
-const u32 b43_ntab_gainctl1[] = {
+static const u32 b43_ntab_gainctl1[] = {
0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
@@ -1715,12 +1715,12 @@ const u32 b43_ntab_gainctl1[] = {
0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
};
-const u32 b43_ntab_intlevel[] = {
+static const u32 b43_ntab_intlevel[] = {
0x00802070, 0x0671188D, 0x0A60192C, 0x0A300E46,
0x00C1188D, 0x080024D2, 0x00000070,
};
-const u32 b43_ntab_iqlt0[] = {
+static const u32 b43_ntab_iqlt0[] = {
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
@@ -1755,7 +1755,7 @@ const u32 b43_ntab_iqlt0[] = {
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
};
-const u32 b43_ntab_iqlt1[] = {
+static const u32 b43_ntab_iqlt1[] = {
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
@@ -1790,7 +1790,7 @@ const u32 b43_ntab_iqlt1[] = {
0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
};
-const u16 b43_ntab_loftlt0[] = {
+static const u16 b43_ntab_loftlt0[] = {
0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
@@ -1815,7 +1815,7 @@ const u16 b43_ntab_loftlt0[] = {
0x0002, 0x0103,
};
-const u16 b43_ntab_loftlt1[] = {
+static const u16 b43_ntab_loftlt1[] = {
0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
@@ -1840,7 +1840,7 @@ const u16 b43_ntab_loftlt1[] = {
0x0002, 0x0103,
};
-const u8 b43_ntab_mcs[] = {
+static const u8 b43_ntab_mcs[] = {
0x00, 0x08, 0x0A, 0x10, 0x12, 0x19, 0x1A, 0x1C,
0x40, 0x48, 0x4A, 0x50, 0x52, 0x59, 0x5A, 0x5C,
0x80, 0x88, 0x8A, 0x90, 0x92, 0x99, 0x9A, 0x9C,
@@ -1859,7 +1859,7 @@ const u8 b43_ntab_mcs[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
-const u32 b43_ntab_noisevar10[] = {
+static const u32 b43_ntab_noisevar10[] = {
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
@@ -1926,7 +1926,7 @@ const u32 b43_ntab_noisevar10[] = {
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
};
-const u32 b43_ntab_noisevar11[] = {
+static const u32 b43_ntab_noisevar11[] = {
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
@@ -1993,7 +1993,7 @@ const u32 b43_ntab_noisevar11[] = {
0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
};
-const u16 b43_ntab_pilot[] = {
+static const u16 b43_ntab_pilot[] = {
0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08,
0xFF08, 0xFF08, 0x80D5, 0x80D5, 0x80D5, 0x80D5,
0x80D5, 0x80D5, 0x80D5, 0x80D5, 0xFF0A, 0xFF82,
@@ -2011,12 +2011,12 @@ const u16 b43_ntab_pilot[] = {
0xF0A0, 0xF028, 0xFFFF, 0xFFFF,
};
-const u32 b43_ntab_pilotlt[] = {
+static const u32 b43_ntab_pilotlt[] = {
0x76540123, 0x62407351, 0x76543201, 0x76540213,
0x76540123, 0x76430521,
};
-const u32 b43_ntab_tdi20a0[] = {
+static const u32 b43_ntab_tdi20a0[] = {
0x00091226, 0x000A1429, 0x000B56AD, 0x000C58B0,
0x000D5AB3, 0x000E9CB6, 0x000F9EBA, 0x0000C13D,
0x00020301, 0x00030504, 0x00040708, 0x0005090B,
@@ -2033,7 +2033,7 @@ const u32 b43_ntab_tdi20a0[] = {
0x00000000, 0x00000000, 0x00000000,
};
-const u32 b43_ntab_tdi20a1[] = {
+static const u32 b43_ntab_tdi20a1[] = {
0x00014B26, 0x00028D29, 0x000393AD, 0x00049630,
0x0005D833, 0x0006DA36, 0x00099C3A, 0x000A9E3D,
0x000BC081, 0x000CC284, 0x000DC488, 0x000F068B,
@@ -2050,7 +2050,7 @@ const u32 b43_ntab_tdi20a1[] = {
0x00000000, 0x00000000, 0x00000000,
};
-const u32 b43_ntab_tdi40a0[] = {
+static const u32 b43_ntab_tdi40a0[] = {
0x0011A346, 0x00136CCF, 0x0014F5D9, 0x001641E2,
0x0017CB6B, 0x00195475, 0x001B2383, 0x001CAD0C,
0x001E7616, 0x0000821F, 0x00020BA8, 0x0003D4B2,
@@ -2081,7 +2081,7 @@ const u32 b43_ntab_tdi40a0[] = {
0x00000000, 0x00000000,
};
-const u32 b43_ntab_tdi40a1[] = {
+static const u32 b43_ntab_tdi40a1[] = {
0x001EDB36, 0x000129CA, 0x0002B353, 0x00047CDD,
0x0005C8E6, 0x000791EF, 0x00091BF9, 0x000AAA07,
0x000C3391, 0x000DFD1A, 0x00120923, 0x0013D22D,
@@ -2112,7 +2112,7 @@ const u32 b43_ntab_tdi40a1[] = {
0x00000000, 0x00000000,
};
-const u32 b43_ntab_tdtrn[] = {
+static const u32 b43_ntab_tdtrn[] = {
0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6,
0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68,
0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52,
@@ -2291,7 +2291,7 @@ const u32 b43_ntab_tdtrn[] = {
0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE,
};
-const u32 b43_ntab_tmap[] = {
+static const u32 b43_ntab_tmap[] = {
0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
0xF1111110, 0x11111111, 0x11F11111, 0x00000111,
@@ -2406,6 +2406,544 @@ const u32 b43_ntab_tmap[] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000,
};
+const u32 b43_ntab_tx_gain_rev0_1_2[] = {
+ 0x03cc2b44, 0x03cc2b42, 0x03cc2a44, 0x03cc2a42,
+ 0x03cc2944, 0x03c82b44, 0x03c82b42, 0x03c82a44,
+ 0x03c82a42, 0x03c82944, 0x03c82942, 0x03c82844,
+ 0x03c82842, 0x03c42b44, 0x03c42b42, 0x03c42a44,
+ 0x03c42a42, 0x03c42944, 0x03c42942, 0x03c42844,
+ 0x03c42842, 0x03c42744, 0x03c42742, 0x03c42644,
+ 0x03c42642, 0x03c42544, 0x03c42542, 0x03c42444,
+ 0x03c42442, 0x03c02b44, 0x03c02b42, 0x03c02a44,
+ 0x03c02a42, 0x03c02944, 0x03c02942, 0x03c02844,
+ 0x03c02842, 0x03c02744, 0x03c02742, 0x03b02b44,
+ 0x03b02b42, 0x03b02a44, 0x03b02a42, 0x03b02944,
+ 0x03b02942, 0x03b02844, 0x03b02842, 0x03b02744,
+ 0x03b02742, 0x03b02644, 0x03b02642, 0x03b02544,
+ 0x03b02542, 0x03a02b44, 0x03a02b42, 0x03a02a44,
+ 0x03a02a42, 0x03a02944, 0x03a02942, 0x03a02844,
+ 0x03a02842, 0x03a02744, 0x03a02742, 0x03902b44,
+ 0x03902b42, 0x03902a44, 0x03902a42, 0x03902944,
+ 0x03902942, 0x03902844, 0x03902842, 0x03902744,
+ 0x03902742, 0x03902644, 0x03902642, 0x03902544,
+ 0x03902542, 0x03802b44, 0x03802b42, 0x03802a44,
+ 0x03802a42, 0x03802944, 0x03802942, 0x03802844,
+ 0x03802842, 0x03802744, 0x03802742, 0x03802644,
+ 0x03802642, 0x03802544, 0x03802542, 0x03802444,
+ 0x03802442, 0x03802344, 0x03802342, 0x03802244,
+ 0x03802242, 0x03802144, 0x03802142, 0x03802044,
+ 0x03802042, 0x03801f44, 0x03801f42, 0x03801e44,
+ 0x03801e42, 0x03801d44, 0x03801d42, 0x03801c44,
+ 0x03801c42, 0x03801b44, 0x03801b42, 0x03801a44,
+ 0x03801a42, 0x03801944, 0x03801942, 0x03801844,
+ 0x03801842, 0x03801744, 0x03801742, 0x03801644,
+ 0x03801642, 0x03801544, 0x03801542, 0x03801444,
+ 0x03801442, 0x03801344, 0x03801342, 0x00002b00,
+};
+
+const u32 b43_ntab_tx_gain_rev3plus_2ghz[] = {
+ 0x1f410044, 0x1f410042, 0x1f410040, 0x1f41003e,
+ 0x1f41003c, 0x1f41003b, 0x1f410039, 0x1f410037,
+ 0x1e410044, 0x1e410042, 0x1e410040, 0x1e41003e,
+ 0x1e41003c, 0x1e41003b, 0x1e410039, 0x1e410037,
+ 0x1d410044, 0x1d410042, 0x1d410040, 0x1d41003e,
+ 0x1d41003c, 0x1d41003b, 0x1d410039, 0x1d410037,
+ 0x1c410044, 0x1c410042, 0x1c410040, 0x1c41003e,
+ 0x1c41003c, 0x1c41003b, 0x1c410039, 0x1c410037,
+ 0x1b410044, 0x1b410042, 0x1b410040, 0x1b41003e,
+ 0x1b41003c, 0x1b41003b, 0x1b410039, 0x1b410037,
+ 0x1a410044, 0x1a410042, 0x1a410040, 0x1a41003e,
+ 0x1a41003c, 0x1a41003b, 0x1a410039, 0x1a410037,
+ 0x19410044, 0x19410042, 0x19410040, 0x1941003e,
+ 0x1941003c, 0x1941003b, 0x19410039, 0x19410037,
+ 0x18410044, 0x18410042, 0x18410040, 0x1841003e,
+ 0x1841003c, 0x1841003b, 0x18410039, 0x18410037,
+ 0x17410044, 0x17410042, 0x17410040, 0x1741003e,
+ 0x1741003c, 0x1741003b, 0x17410039, 0x17410037,
+ 0x16410044, 0x16410042, 0x16410040, 0x1641003e,
+ 0x1641003c, 0x1641003b, 0x16410039, 0x16410037,
+ 0x15410044, 0x15410042, 0x15410040, 0x1541003e,
+ 0x1541003c, 0x1541003b, 0x15410039, 0x15410037,
+ 0x14410044, 0x14410042, 0x14410040, 0x1441003e,
+ 0x1441003c, 0x1441003b, 0x14410039, 0x14410037,
+ 0x13410044, 0x13410042, 0x13410040, 0x1341003e,
+ 0x1341003c, 0x1341003b, 0x13410039, 0x13410037,
+ 0x12410044, 0x12410042, 0x12410040, 0x1241003e,
+ 0x1241003c, 0x1241003b, 0x12410039, 0x12410037,
+ 0x11410044, 0x11410042, 0x11410040, 0x1141003e,
+ 0x1141003c, 0x1141003b, 0x11410039, 0x11410037,
+ 0x10410044, 0x10410042, 0x10410040, 0x1041003e,
+ 0x1041003c, 0x1041003b, 0x10410039, 0x10410037,
+};
+
+const u32 b43_ntab_tx_gain_rev3_5ghz[] = {
+ 0xcff70044, 0xcff70042, 0xcff70040, 0xcff7003e,
+ 0xcff7003c, 0xcff7003b, 0xcff70039, 0xcff70037,
+ 0xcef70044, 0xcef70042, 0xcef70040, 0xcef7003e,
+ 0xcef7003c, 0xcef7003b, 0xcef70039, 0xcef70037,
+ 0xcdf70044, 0xcdf70042, 0xcdf70040, 0xcdf7003e,
+ 0xcdf7003c, 0xcdf7003b, 0xcdf70039, 0xcdf70037,
+ 0xccf70044, 0xccf70042, 0xccf70040, 0xccf7003e,
+ 0xccf7003c, 0xccf7003b, 0xccf70039, 0xccf70037,
+ 0xcbf70044, 0xcbf70042, 0xcbf70040, 0xcbf7003e,
+ 0xcbf7003c, 0xcbf7003b, 0xcbf70039, 0xcbf70037,
+ 0xcaf70044, 0xcaf70042, 0xcaf70040, 0xcaf7003e,
+ 0xcaf7003c, 0xcaf7003b, 0xcaf70039, 0xcaf70037,
+ 0xc9f70044, 0xc9f70042, 0xc9f70040, 0xc9f7003e,
+ 0xc9f7003c, 0xc9f7003b, 0xc9f70039, 0xc9f70037,
+ 0xc8f70044, 0xc8f70042, 0xc8f70040, 0xc8f7003e,
+ 0xc8f7003c, 0xc8f7003b, 0xc8f70039, 0xc8f70037,
+ 0xc7f70044, 0xc7f70042, 0xc7f70040, 0xc7f7003e,
+ 0xc7f7003c, 0xc7f7003b, 0xc7f70039, 0xc7f70037,
+ 0xc6f70044, 0xc6f70042, 0xc6f70040, 0xc6f7003e,
+ 0xc6f7003c, 0xc6f7003b, 0xc6f70039, 0xc6f70037,
+ 0xc5f70044, 0xc5f70042, 0xc5f70040, 0xc5f7003e,
+ 0xc5f7003c, 0xc5f7003b, 0xc5f70039, 0xc5f70037,
+ 0xc4f70044, 0xc4f70042, 0xc4f70040, 0xc4f7003e,
+ 0xc4f7003c, 0xc4f7003b, 0xc4f70039, 0xc4f70037,
+ 0xc3f70044, 0xc3f70042, 0xc3f70040, 0xc3f7003e,
+ 0xc3f7003c, 0xc3f7003b, 0xc3f70039, 0xc3f70037,
+ 0xc2f70044, 0xc2f70042, 0xc2f70040, 0xc2f7003e,
+ 0xc2f7003c, 0xc2f7003b, 0xc2f70039, 0xc2f70037,
+ 0xc1f70044, 0xc1f70042, 0xc1f70040, 0xc1f7003e,
+ 0xc1f7003c, 0xc1f7003b, 0xc1f70039, 0xc1f70037,
+ 0xc0f70044, 0xc0f70042, 0xc0f70040, 0xc0f7003e,
+ 0xc0f7003c, 0xc0f7003b, 0xc0f70039, 0xc0f70037,
+};
+
+const u32 b43_ntab_tx_gain_rev4_5ghz[] = {
+ 0x2ff20044, 0x2ff20042, 0x2ff20040, 0x2ff2003e,
+ 0x2ff2003c, 0x2ff2003b, 0x2ff20039, 0x2ff20037,
+ 0x2ef20044, 0x2ef20042, 0x2ef20040, 0x2ef2003e,
+ 0x2ef2003c, 0x2ef2003b, 0x2ef20039, 0x2ef20037,
+ 0x2df20044, 0x2df20042, 0x2df20040, 0x2df2003e,
+ 0x2df2003c, 0x2df2003b, 0x2df20039, 0x2df20037,
+ 0x2cf20044, 0x2cf20042, 0x2cf20040, 0x2cf2003e,
+ 0x2cf2003c, 0x2cf2003b, 0x2cf20039, 0x2cf20037,
+ 0x2bf20044, 0x2bf20042, 0x2bf20040, 0x2bf2003e,
+ 0x2bf2003c, 0x2bf2003b, 0x2bf20039, 0x2bf20037,
+ 0x2af20044, 0x2af20042, 0x2af20040, 0x2af2003e,
+ 0x2af2003c, 0x2af2003b, 0x2af20039, 0x2af20037,
+ 0x29f20044, 0x29f20042, 0x29f20040, 0x29f2003e,
+ 0x29f2003c, 0x29f2003b, 0x29f20039, 0x29f20037,
+ 0x28f20044, 0x28f20042, 0x28f20040, 0x28f2003e,
+ 0x28f2003c, 0x28f2003b, 0x28f20039, 0x28f20037,
+ 0x27f20044, 0x27f20042, 0x27f20040, 0x27f2003e,
+ 0x27f2003c, 0x27f2003b, 0x27f20039, 0x27f20037,
+ 0x26f20044, 0x26f20042, 0x26f20040, 0x26f2003e,
+ 0x26f2003c, 0x26f2003b, 0x26f20039, 0x26f20037,
+ 0x25f20044, 0x25f20042, 0x25f20040, 0x25f2003e,
+ 0x25f2003c, 0x25f2003b, 0x25f20039, 0x25f20037,
+ 0x24f20044, 0x24f20042, 0x24f20040, 0x24f2003e,
+ 0x24f2003c, 0x24f2003b, 0x24f20039, 0x24f20038,
+ 0x23f20041, 0x23f20040, 0x23f2003f, 0x23f2003e,
+ 0x23f2003c, 0x23f2003b, 0x23f20039, 0x23f20037,
+ 0x22f20044, 0x22f20042, 0x22f20040, 0x22f2003e,
+ 0x22f2003c, 0x22f2003b, 0x22f20039, 0x22f20037,
+ 0x21f20044, 0x21f20042, 0x21f20040, 0x21f2003e,
+ 0x21f2003c, 0x21f2003b, 0x21f20039, 0x21f20037,
+ 0x20d20043, 0x20d20041, 0x20d2003e, 0x20d2003c,
+ 0x20d2003a, 0x20d20038, 0x20d20036, 0x20d20034,
+};
+
+const u32 b43_ntab_tx_gain_rev5plus_5ghz[] = {
+ 0x0f62004a, 0x0f620048, 0x0f620046, 0x0f620044,
+ 0x0f620042, 0x0f620040, 0x0f62003e, 0x0f62003c,
+ 0x0e620044, 0x0e620042, 0x0e620040, 0x0e62003e,
+ 0x0e62003c, 0x0e62003d, 0x0e62003b, 0x0e62003a,
+ 0x0d620043, 0x0d620041, 0x0d620040, 0x0d62003e,
+ 0x0d62003d, 0x0d62003c, 0x0d62003b, 0x0d62003a,
+ 0x0c620041, 0x0c620040, 0x0c62003f, 0x0c62003e,
+ 0x0c62003c, 0x0c62003b, 0x0c620039, 0x0c620037,
+ 0x0b620046, 0x0b620044, 0x0b620042, 0x0b620040,
+ 0x0b62003e, 0x0b62003c, 0x0b62003b, 0x0b62003a,
+ 0x0a620041, 0x0a620040, 0x0a62003e, 0x0a62003c,
+ 0x0a62003b, 0x0a62003a, 0x0a620039, 0x0a620038,
+ 0x0962003e, 0x0962003d, 0x0962003c, 0x0962003b,
+ 0x09620039, 0x09620037, 0x09620035, 0x09620033,
+ 0x08620044, 0x08620042, 0x08620040, 0x0862003e,
+ 0x0862003c, 0x0862003b, 0x0862003a, 0x08620039,
+ 0x07620043, 0x07620042, 0x07620040, 0x0762003f,
+ 0x0762003d, 0x0762003b, 0x0762003a, 0x07620039,
+ 0x0662003e, 0x0662003d, 0x0662003c, 0x0662003b,
+ 0x06620039, 0x06620037, 0x06620035, 0x06620033,
+ 0x05620046, 0x05620044, 0x05620042, 0x05620040,
+ 0x0562003e, 0x0562003c, 0x0562003b, 0x05620039,
+ 0x04620044, 0x04620042, 0x04620040, 0x0462003e,
+ 0x0462003c, 0x0462003b, 0x04620039, 0x04620038,
+ 0x0362003c, 0x0362003b, 0x0362003a, 0x03620039,
+ 0x03620038, 0x03620037, 0x03620035, 0x03620033,
+ 0x0262004c, 0x0262004a, 0x02620048, 0x02620047,
+ 0x02620046, 0x02620044, 0x02620043, 0x02620042,
+ 0x0162004a, 0x01620048, 0x01620046, 0x01620044,
+ 0x01620043, 0x01620042, 0x01620041, 0x01620040,
+ 0x00620042, 0x00620040, 0x0062003e, 0x0062003c,
+ 0x0062003b, 0x00620039, 0x00620037, 0x00620035,
+};
+
+const u32 txpwrctrl_tx_gain_ipa[] = {
+ 0x5ff7002d, 0x5ff7002b, 0x5ff7002a, 0x5ff70029,
+ 0x5ff70028, 0x5ff70027, 0x5ff70026, 0x5ff70025,
+ 0x5ef7002d, 0x5ef7002b, 0x5ef7002a, 0x5ef70029,
+ 0x5ef70028, 0x5ef70027, 0x5ef70026, 0x5ef70025,
+ 0x5df7002d, 0x5df7002b, 0x5df7002a, 0x5df70029,
+ 0x5df70028, 0x5df70027, 0x5df70026, 0x5df70025,
+ 0x5cf7002d, 0x5cf7002b, 0x5cf7002a, 0x5cf70029,
+ 0x5cf70028, 0x5cf70027, 0x5cf70026, 0x5cf70025,
+ 0x5bf7002d, 0x5bf7002b, 0x5bf7002a, 0x5bf70029,
+ 0x5bf70028, 0x5bf70027, 0x5bf70026, 0x5bf70025,
+ 0x5af7002d, 0x5af7002b, 0x5af7002a, 0x5af70029,
+ 0x5af70028, 0x5af70027, 0x5af70026, 0x5af70025,
+ 0x59f7002d, 0x59f7002b, 0x59f7002a, 0x59f70029,
+ 0x59f70028, 0x59f70027, 0x59f70026, 0x59f70025,
+ 0x58f7002d, 0x58f7002b, 0x58f7002a, 0x58f70029,
+ 0x58f70028, 0x58f70027, 0x58f70026, 0x58f70025,
+ 0x57f7002d, 0x57f7002b, 0x57f7002a, 0x57f70029,
+ 0x57f70028, 0x57f70027, 0x57f70026, 0x57f70025,
+ 0x56f7002d, 0x56f7002b, 0x56f7002a, 0x56f70029,
+ 0x56f70028, 0x56f70027, 0x56f70026, 0x56f70025,
+ 0x55f7002d, 0x55f7002b, 0x55f7002a, 0x55f70029,
+ 0x55f70028, 0x55f70027, 0x55f70026, 0x55f70025,
+ 0x54f7002d, 0x54f7002b, 0x54f7002a, 0x54f70029,
+ 0x54f70028, 0x54f70027, 0x54f70026, 0x54f70025,
+ 0x53f7002d, 0x53f7002b, 0x53f7002a, 0x53f70029,
+ 0x53f70028, 0x53f70027, 0x53f70026, 0x53f70025,
+ 0x52f7002d, 0x52f7002b, 0x52f7002a, 0x52f70029,
+ 0x52f70028, 0x52f70027, 0x52f70026, 0x52f70025,
+ 0x51f7002d, 0x51f7002b, 0x51f7002a, 0x51f70029,
+ 0x51f70028, 0x51f70027, 0x51f70026, 0x51f70025,
+ 0x50f7002d, 0x50f7002b, 0x50f7002a, 0x50f70029,
+ 0x50f70028, 0x50f70027, 0x50f70026, 0x50f70025,
+};
+
+const u32 txpwrctrl_tx_gain_ipa_rev5[] = {
+ 0x1ff7002d, 0x1ff7002b, 0x1ff7002a, 0x1ff70029,
+ 0x1ff70028, 0x1ff70027, 0x1ff70026, 0x1ff70025,
+ 0x1ef7002d, 0x1ef7002b, 0x1ef7002a, 0x1ef70029,
+ 0x1ef70028, 0x1ef70027, 0x1ef70026, 0x1ef70025,
+ 0x1df7002d, 0x1df7002b, 0x1df7002a, 0x1df70029,
+ 0x1df70028, 0x1df70027, 0x1df70026, 0x1df70025,
+ 0x1cf7002d, 0x1cf7002b, 0x1cf7002a, 0x1cf70029,
+ 0x1cf70028, 0x1cf70027, 0x1cf70026, 0x1cf70025,
+ 0x1bf7002d, 0x1bf7002b, 0x1bf7002a, 0x1bf70029,
+ 0x1bf70028, 0x1bf70027, 0x1bf70026, 0x1bf70025,
+ 0x1af7002d, 0x1af7002b, 0x1af7002a, 0x1af70029,
+ 0x1af70028, 0x1af70027, 0x1af70026, 0x1af70025,
+ 0x19f7002d, 0x19f7002b, 0x19f7002a, 0x19f70029,
+ 0x19f70028, 0x19f70027, 0x19f70026, 0x19f70025,
+ 0x18f7002d, 0x18f7002b, 0x18f7002a, 0x18f70029,
+ 0x18f70028, 0x18f70027, 0x18f70026, 0x18f70025,
+ 0x17f7002d, 0x17f7002b, 0x17f7002a, 0x17f70029,
+ 0x17f70028, 0x17f70027, 0x17f70026, 0x17f70025,
+ 0x16f7002d, 0x16f7002b, 0x16f7002a, 0x16f70029,
+ 0x16f70028, 0x16f70027, 0x16f70026, 0x16f70025,
+ 0x15f7002d, 0x15f7002b, 0x15f7002a, 0x15f70029,
+ 0x15f70028, 0x15f70027, 0x15f70026, 0x15f70025,
+ 0x14f7002d, 0x14f7002b, 0x14f7002a, 0x14f70029,
+ 0x14f70028, 0x14f70027, 0x14f70026, 0x14f70025,
+ 0x13f7002d, 0x13f7002b, 0x13f7002a, 0x13f70029,
+ 0x13f70028, 0x13f70027, 0x13f70026, 0x13f70025,
+ 0x12f7002d, 0x12f7002b, 0x12f7002a, 0x12f70029,
+ 0x12f70028, 0x12f70027, 0x12f70026, 0x12f70025,
+ 0x11f7002d, 0x11f7002b, 0x11f7002a, 0x11f70029,
+ 0x11f70028, 0x11f70027, 0x11f70026, 0x11f70025,
+ 0x10f7002d, 0x10f7002b, 0x10f7002a, 0x10f70029,
+ 0x10f70028, 0x10f70027, 0x10f70026, 0x10f70025,
+};
+
+const u32 txpwrctrl_tx_gain_ipa_rev6[] = {
+ 0x0ff7002d, 0x0ff7002b, 0x0ff7002a, 0x0ff70029,
+ 0x0ff70028, 0x0ff70027, 0x0ff70026, 0x0ff70025,
+ 0x0ef7002d, 0x0ef7002b, 0x0ef7002a, 0x0ef70029,
+ 0x0ef70028, 0x0ef70027, 0x0ef70026, 0x0ef70025,
+ 0x0df7002d, 0x0df7002b, 0x0df7002a, 0x0df70029,
+ 0x0df70028, 0x0df70027, 0x0df70026, 0x0df70025,
+ 0x0cf7002d, 0x0cf7002b, 0x0cf7002a, 0x0cf70029,
+ 0x0cf70028, 0x0cf70027, 0x0cf70026, 0x0cf70025,
+ 0x0bf7002d, 0x0bf7002b, 0x0bf7002a, 0x0bf70029,
+ 0x0bf70028, 0x0bf70027, 0x0bf70026, 0x0bf70025,
+ 0x0af7002d, 0x0af7002b, 0x0af7002a, 0x0af70029,
+ 0x0af70028, 0x0af70027, 0x0af70026, 0x0af70025,
+ 0x09f7002d, 0x09f7002b, 0x09f7002a, 0x09f70029,
+ 0x09f70028, 0x09f70027, 0x09f70026, 0x09f70025,
+ 0x08f7002d, 0x08f7002b, 0x08f7002a, 0x08f70029,
+ 0x08f70028, 0x08f70027, 0x08f70026, 0x08f70025,
+ 0x07f7002d, 0x07f7002b, 0x07f7002a, 0x07f70029,
+ 0x07f70028, 0x07f70027, 0x07f70026, 0x07f70025,
+ 0x06f7002d, 0x06f7002b, 0x06f7002a, 0x06f70029,
+ 0x06f70028, 0x06f70027, 0x06f70026, 0x06f70025,
+ 0x05f7002d, 0x05f7002b, 0x05f7002a, 0x05f70029,
+ 0x05f70028, 0x05f70027, 0x05f70026, 0x05f70025,
+ 0x04f7002d, 0x04f7002b, 0x04f7002a, 0x04f70029,
+ 0x04f70028, 0x04f70027, 0x04f70026, 0x04f70025,
+ 0x03f7002d, 0x03f7002b, 0x03f7002a, 0x03f70029,
+ 0x03f70028, 0x03f70027, 0x03f70026, 0x03f70025,
+ 0x02f7002d, 0x02f7002b, 0x02f7002a, 0x02f70029,
+ 0x02f70028, 0x02f70027, 0x02f70026, 0x02f70025,
+ 0x01f7002d, 0x01f7002b, 0x01f7002a, 0x01f70029,
+ 0x01f70028, 0x01f70027, 0x01f70026, 0x01f70025,
+ 0x00f7002d, 0x00f7002b, 0x00f7002a, 0x00f70029,
+ 0x00f70028, 0x00f70027, 0x00f70026, 0x00f70025,
+};
+
+const u32 txpwrctrl_tx_gain_ipa_5g[] = {
+ 0x7ff70035, 0x7ff70033, 0x7ff70032, 0x7ff70031,
+ 0x7ff7002f, 0x7ff7002e, 0x7ff7002d, 0x7ff7002b,
+ 0x7ff7002a, 0x7ff70029, 0x7ff70028, 0x7ff70027,
+ 0x7ff70026, 0x7ff70024, 0x7ff70023, 0x7ff70022,
+ 0x7ef70028, 0x7ef70027, 0x7ef70026, 0x7ef70025,
+ 0x7ef70024, 0x7ef70023, 0x7df70028, 0x7df70027,
+ 0x7df70026, 0x7df70025, 0x7df70024, 0x7df70023,
+ 0x7df70022, 0x7cf70029, 0x7cf70028, 0x7cf70027,
+ 0x7cf70026, 0x7cf70025, 0x7cf70023, 0x7cf70022,
+ 0x7bf70029, 0x7bf70028, 0x7bf70026, 0x7bf70025,
+ 0x7bf70024, 0x7bf70023, 0x7bf70022, 0x7bf70021,
+ 0x7af70029, 0x7af70028, 0x7af70027, 0x7af70026,
+ 0x7af70025, 0x7af70024, 0x7af70023, 0x7af70022,
+ 0x79f70029, 0x79f70028, 0x79f70027, 0x79f70026,
+ 0x79f70025, 0x79f70024, 0x79f70023, 0x79f70022,
+ 0x78f70029, 0x78f70028, 0x78f70027, 0x78f70026,
+ 0x78f70025, 0x78f70024, 0x78f70023, 0x78f70022,
+ 0x77f70029, 0x77f70028, 0x77f70027, 0x77f70026,
+ 0x77f70025, 0x77f70024, 0x77f70023, 0x77f70022,
+ 0x76f70029, 0x76f70028, 0x76f70027, 0x76f70026,
+ 0x76f70024, 0x76f70023, 0x76f70022, 0x76f70021,
+ 0x75f70029, 0x75f70028, 0x75f70027, 0x75f70026,
+ 0x75f70025, 0x75f70024, 0x75f70023, 0x74f70029,
+ 0x74f70028, 0x74f70026, 0x74f70025, 0x74f70024,
+ 0x74f70023, 0x74f70022, 0x73f70029, 0x73f70027,
+ 0x73f70026, 0x73f70025, 0x73f70024, 0x73f70023,
+ 0x73f70022, 0x72f70028, 0x72f70027, 0x72f70026,
+ 0x72f70025, 0x72f70024, 0x72f70023, 0x72f70022,
+ 0x71f70028, 0x71f70027, 0x71f70026, 0x71f70025,
+ 0x71f70024, 0x71f70023, 0x70f70028, 0x70f70027,
+ 0x70f70026, 0x70f70024, 0x70f70023, 0x70f70022,
+ 0x70f70021, 0x70f70020, 0x70f70020, 0x70f7001f,
+};
+
+const u16 tbl_iqcal_gainparams[2][9][8] = {
+ {
+ { 0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69 },
+ { 0x700, 7, 0, 0, 0x69, 0x69, 0x69, 0x69 },
+ { 0x710, 7, 1, 0, 0x68, 0x68, 0x68, 0x68 },
+ { 0x720, 7, 2, 0, 0x67, 0x67, 0x67, 0x67 },
+ { 0x730, 7, 3, 0, 0x66, 0x66, 0x66, 0x66 },
+ { 0x740, 7, 4, 0, 0x65, 0x65, 0x65, 0x65 },
+ { 0x741, 7, 4, 1, 0x65, 0x65, 0x65, 0x65 },
+ { 0x742, 7, 4, 2, 0x65, 0x65, 0x65, 0x65 },
+ { 0x743, 7, 4, 3, 0x65, 0x65, 0x65, 0x65 }
+ },
+ {
+ { 0x000, 7, 0, 0, 0x79, 0x79, 0x79, 0x79 },
+ { 0x700, 7, 0, 0, 0x79, 0x79, 0x79, 0x79 },
+ { 0x710, 7, 1, 0, 0x79, 0x79, 0x79, 0x79 },
+ { 0x720, 7, 2, 0, 0x78, 0x78, 0x78, 0x78 },
+ { 0x730, 7, 3, 0, 0x78, 0x78, 0x78, 0x78 },
+ { 0x740, 7, 4, 0, 0x78, 0x78, 0x78, 0x78 },
+ { 0x741, 7, 4, 1, 0x78, 0x78, 0x78, 0x78 },
+ { 0x742, 7, 4, 2, 0x78, 0x78, 0x78, 0x78 },
+ { 0x743, 7, 4, 3, 0x78, 0x78, 0x78, 0x78 }
+ }
+};
+
+const struct nphy_txiqcal_ladder ladder_lo[] = {
+ { 3, 0 },
+ { 4, 0 },
+ { 6, 0 },
+ { 9, 0 },
+ { 13, 0 },
+ { 18, 0 },
+ { 25, 0 },
+ { 25, 1 },
+ { 25, 2 },
+ { 25, 3 },
+ { 25, 4 },
+ { 25, 5 },
+ { 25, 6 },
+ { 25, 7 },
+ { 35, 7 },
+ { 50, 7 },
+ { 71, 7 },
+ { 100, 7 }
+};
+
+const struct nphy_txiqcal_ladder ladder_iq[] = {
+ { 3, 0 },
+ { 4, 0 },
+ { 6, 0 },
+ { 9, 0 },
+ { 13, 0 },
+ { 18, 0 },
+ { 25, 0 },
+ { 35, 0 },
+ { 50, 0 },
+ { 71, 0 },
+ { 100, 0 },
+ { 100, 1 },
+ { 100, 2 },
+ { 100, 3 },
+ { 100, 4 },
+ { 100, 5 },
+ { 100, 6 },
+ { 100, 7 }
+};
+
+const u16 loscale[] = {
+ 256, 256, 271, 271,
+ 287, 256, 256, 271,
+ 271, 287, 287, 304,
+ 304, 256, 256, 271,
+ 271, 287, 287, 304,
+ 304, 322, 322, 341,
+ 341, 362, 362, 383,
+ 383, 256, 256, 271,
+ 271, 287, 287, 304,
+ 304, 322, 322, 256,
+ 256, 271, 271, 287,
+ 287, 304, 304, 322,
+ 322, 341, 341, 362,
+ 362, 256, 256, 271,
+ 271, 287, 287, 304,
+ 304, 322, 322, 256,
+ 256, 271, 271, 287,
+ 287, 304, 304, 322,
+ 322, 341, 341, 362,
+ 362, 256, 256, 271,
+ 271, 287, 287, 304,
+ 304, 322, 322, 341,
+ 341, 362, 362, 383,
+ 383, 406, 406, 430,
+ 430, 455, 455, 482,
+ 482, 511, 511, 541,
+ 541, 573, 573, 607,
+ 607, 643, 643, 681,
+ 681, 722, 722, 764,
+ 764, 810, 810, 858,
+ 858, 908, 908, 962,
+ 962, 1019, 1019, 256
+};
+
+const u16 tbl_tx_iqlo_cal_loft_ladder_40[] = {
+ 0x0200, 0x0300, 0x0400, 0x0700,
+ 0x0900, 0x0c00, 0x1200, 0x1201,
+ 0x1202, 0x1203, 0x1204, 0x1205,
+ 0x1206, 0x1207, 0x1907, 0x2307,
+ 0x3207, 0x4707
+};
+
+const u16 tbl_tx_iqlo_cal_loft_ladder_20[] = {
+ 0x0300, 0x0500, 0x0700, 0x0900,
+ 0x0d00, 0x1100, 0x1900, 0x1901,
+ 0x1902, 0x1903, 0x1904, 0x1905,
+ 0x1906, 0x1907, 0x2407, 0x3207,
+ 0x4607, 0x6407
+};
+
+const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = {
+ 0x0100, 0x0200, 0x0400, 0x0700,
+ 0x0900, 0x0c00, 0x1200, 0x1900,
+ 0x2300, 0x3200, 0x4700, 0x4701,
+ 0x4702, 0x4703, 0x4704, 0x4705,
+ 0x4706, 0x4707
+};
+
+const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = {
+ 0x0200, 0x0300, 0x0600, 0x0900,
+ 0x0d00, 0x1100, 0x1900, 0x2400,
+ 0x3200, 0x4600, 0x6400, 0x6401,
+ 0x6402, 0x6403, 0x6404, 0x6405,
+ 0x6406, 0x6407
+};
+
+const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3] = { };
+
+const u16 tbl_tx_iqlo_cal_startcoefs[B43_NTAB_TX_IQLO_CAL_STARTCOEFS] = { };
+
+const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = {
+ 0x8423, 0x8323, 0x8073, 0x8256,
+ 0x8045, 0x8223, 0x9423, 0x9323,
+ 0x9073, 0x9256, 0x9045, 0x9223
+};
+
+const u16 tbl_tx_iqlo_cal_cmds_recal[] = {
+ 0x8101, 0x8253, 0x8053, 0x8234,
+ 0x8034, 0x9101, 0x9253, 0x9053,
+ 0x9234, 0x9034
+};
+
+const u16 tbl_tx_iqlo_cal_cmds_fullcal[] = {
+ 0x8123, 0x8264, 0x8086, 0x8245,
+ 0x8056, 0x9123, 0x9264, 0x9086,
+ 0x9245, 0x9056
+};
+
+const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = {
+ 0x8434, 0x8334, 0x8084, 0x8267,
+ 0x8056, 0x8234, 0x9434, 0x9334,
+ 0x9084, 0x9267, 0x9056, 0x9234
+};
+
+const s16 tbl_tx_filter_coef_rev4[7][15] = {
+ { -377, 137, -407, 208, -1527,
+ 956, 93, 186, 93, 230,
+ -44, 230, 20, -191, 201 },
+ { -77, 20, -98, 49, -93,
+ 60, 56, 111, 56, 26,
+ -5, 26, 34, -32, 34 },
+ { -360, 164, -376, 164, -1533,
+ 576, 308, -314, 308, 121,
+ -73, 121, 91, 124, 91 },
+ { -295, 200, -363, 142, -1391,
+ 826, 151, 301, 151, 151,
+ 301, 151, 602, -752, 602 },
+ { -92, 58, -96, 49, -104,
+ 44, 17, 35, 17, 12,
+ 25, 12, 13, 27, 13 },
+ { -375, 136, -399, 209, -1479,
+ 949, 130, 260, 130, 230,
+ -44, 230, 201, -191, 201 },
+ { 0xed9, 0xc8, 0xe95, 0x8e, 0xa91,
+ 0x33a, 0x97, 0x12d, 0x97, 0x97,
+ 0x12d, 0x97, 0x25a, 0xd10, 0x25a }
+};
+
+/* addr0, addr1, bmask, shift */
+const struct nphy_rf_control_override_rev2 tbl_rf_control_override_rev2[] = {
+ { 0x78, 0x78, 0x0038, 3 }, /* for field == 0x0002 (fls == 2) */
+ { 0x7A, 0x7D, 0x0001, 0 }, /* for field == 0x0004 (fls == 3) */
+ { 0x7A, 0x7D, 0x0002, 1 }, /* for field == 0x0008 (fls == 4) */
+ { 0x7A, 0x7D, 0x0004, 2 }, /* for field == 0x0010 (fls == 5) */
+ { 0x7A, 0x7D, 0x0030, 4 }, /* for field == 0x0020 (fls == 6) */
+ { 0x7A, 0x7D, 0x00C0, 6 }, /* for field == 0x0040 (fls == 7) */
+ { 0x7A, 0x7D, 0x0100, 8 }, /* for field == 0x0080 (fls == 8) */
+ { 0x7A, 0x7D, 0x0200, 9 }, /* for field == 0x0100 (fls == 9) */
+ { 0x78, 0x78, 0x0004, 2 }, /* for field == 0x0200 (fls == 10) */
+ { 0x7B, 0x7E, 0x01FF, 0 }, /* for field == 0x0400 (fls == 11) */
+ { 0x7C, 0x7F, 0x01FF, 0 }, /* for field == 0x0800 (fls == 12) */
+ { 0x78, 0x78, 0x0100, 8 }, /* for field == 0x1000 (fls == 13) */
+ { 0x78, 0x78, 0x0200, 9 }, /* for field == 0x2000 (fls == 14) */
+ { 0x78, 0x78, 0xF000, 12 } /* for field == 0x4000 (fls == 15) */
+};
+
+/* val_mask, val_shift, en_addr0, val_addr0, en_addr1, val_addr1 */
+const struct nphy_rf_control_override_rev3 tbl_rf_control_override_rev3[] = {
+ { 0x8000, 15, 0xE5, 0xF9, 0xE6, 0xFB }, /* field == 0x0001 (fls 1) */
+ { 0x0001, 0, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0002 (fls 2) */
+ { 0x0002, 1, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0004 (fls 3) */
+ { 0x0004, 2, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0008 (fls 4) */
+ { 0x0016, 4, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0010 (fls 5) */
+ { 0x0020, 5, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0020 (fls 6) */
+ { 0x0040, 6, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0040 (fls 7) */
+ { 0x0080, 6, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0080 (fls 8) */
+ { 0x0100, 7, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0100 (fls 9) */
+ { 0x0007, 0, 0xE7, 0xF8, 0xEC, 0xFA }, /* field == 0x0200 (fls 10) */
+ { 0x0070, 4, 0xE7, 0xF8, 0xEC, 0xFA }, /* field == 0x0400 (fls 11) */
+ { 0xE000, 13, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0800 (fls 12) */
+ { 0xFFFF, 0, 0xE7, 0x7B, 0xEC, 0x7E }, /* field == 0x1000 (fls 13) */
+ { 0xFFFF, 0, 0xE7, 0x7C, 0xEC, 0x7F }, /* field == 0x2000 (fls 14) */
+ { 0x00C0, 6, 0xE7, 0xF9, 0xEC, 0xFB } /* field == 0x4000 (fls 15) */
+};
+
static inline void assert_ntab_array_sizes(void)
{
#undef check
@@ -2442,6 +2980,72 @@ static inline void assert_ntab_array_sizes(void)
#undef check
}
+u32 b43_ntab_read(struct b43_wldev *dev, u32 offset)
+{
+ u32 type, value;
+
+ type = offset & B43_NTAB_TYPEMASK;
+ offset &= ~B43_NTAB_TYPEMASK;
+ B43_WARN_ON(offset > 0xFFFF);
+
+ switch (type) {
+ case B43_NTAB_8BIT:
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+ value = b43_phy_read(dev, B43_NPHY_TABLE_DATALO) & 0xFF;
+ break;
+ case B43_NTAB_16BIT:
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+ value = b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+ break;
+ case B43_NTAB_32BIT:
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+ value = b43_phy_read(dev, B43_NPHY_TABLE_DATAHI);
+ value <<= 16;
+ value |= b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+ break;
+ default:
+ B43_WARN_ON(1);
+ value = 0;
+ }
+
+ return value;
+}
+
+void b43_ntab_read_bulk(struct b43_wldev *dev, u32 offset,
+ unsigned int nr_elements, void *_data)
+{
+ u32 type;
+ u8 *data = _data;
+ unsigned int i;
+
+ type = offset & B43_NTAB_TYPEMASK;
+ offset &= ~B43_NTAB_TYPEMASK;
+ B43_WARN_ON(offset > 0xFFFF);
+
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+
+ for (i = 0; i < nr_elements; i++) {
+ switch (type) {
+ case B43_NTAB_8BIT:
+ *data = b43_phy_read(dev, B43_NPHY_TABLE_DATALO) & 0xFF;
+ data++;
+ break;
+ case B43_NTAB_16BIT:
+ *((u16 *)data) = b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+ data += 2;
+ break;
+ case B43_NTAB_32BIT:
+ *((u32 *)data) = b43_phy_read(dev, B43_NPHY_TABLE_DATAHI);
+ *((u32 *)data) <<= 16;
+ *((u32 *)data) |= b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+ data += 4;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ }
+}
+
void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value)
{
u32 type;
@@ -2474,3 +3078,91 @@ void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value)
/* Some compiletime assertions... */
assert_ntab_array_sizes();
}
+
+void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset,
+ unsigned int nr_elements, const void *_data)
+{
+ u32 type, value;
+ const u8 *data = _data;
+ unsigned int i;
+
+ type = offset & B43_NTAB_TYPEMASK;
+ offset &= ~B43_NTAB_TYPEMASK;
+ B43_WARN_ON(offset > 0xFFFF);
+
+ b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+
+ for (i = 0; i < nr_elements; i++) {
+ switch (type) {
+ case B43_NTAB_8BIT:
+ value = *data;
+ data++;
+ B43_WARN_ON(value & ~0xFF);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value);
+ break;
+ case B43_NTAB_16BIT:
+ value = *((u16 *)data);
+ data += 2;
+ B43_WARN_ON(value & ~0xFFFF);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value);
+ break;
+ case B43_NTAB_32BIT:
+ value = *((u32 *)data);
+ data += 4;
+ b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, value >> 16);
+ b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+ value & 0xFFFF);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ }
+}
+
+#define ntab_upload(dev, offset, data) do { \
+ unsigned int i; \
+ for (i = 0; i < (offset##_SIZE); i++) \
+ b43_ntab_write(dev, (offset) + i, (data)[i]); \
+ } while (0)
+
+void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev)
+{
+ /* Static tables */
+ ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct);
+ ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup);
+ ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap);
+ ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn);
+ ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel);
+ ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot);
+ ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
+ ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0);
+ ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1);
+ ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0);
+ ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1);
+ ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
+ ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest);
+ ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs);
+
+ /* Volatile tables */
+ ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10);
+ ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11);
+ ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0);
+ ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1);
+ ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0);
+ ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1);
+ ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
+ ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
+ ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0);
+ ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1);
+ ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0);
+ ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1);
+}
+
+void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev)
+{
+ /* Static tables */
+ /* TODO */
+
+ /* Volatile tables */
+ /* TODO */
+}
diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h
index 4d498b053ec7..9c1c6ecd3672 100644
--- a/drivers/net/wireless/b43/tables_nphy.h
+++ b/drivers/net/wireless/b43/tables_nphy.h
@@ -46,6 +46,27 @@ struct b43_nphy_channeltab_entry {
struct b43_wldev;
+struct nphy_txiqcal_ladder {
+ u8 percent;
+ u8 g_env;
+};
+
+struct nphy_rf_control_override_rev2 {
+ u8 addr0;
+ u8 addr1;
+ u16 bmask;
+ u8 shift;
+};
+
+struct nphy_rf_control_override_rev3 {
+ u16 val_mask;
+ u8 val_shift;
+ u8 en_addr0;
+ u8 val_addr0;
+ u8 en_addr1;
+ u8 val_addr1;
+};
+
/* Upload the default register value table.
* If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz
* table is uploaded. If "ignore_uploadflag" is true, we upload any value
@@ -126,34 +147,57 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel);
#define B43_NTAB_C1_LOFEEDTH B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */
#define B43_NTAB_C1_LOFEEDTH_SIZE 128
+#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_40_SIZE 18
+#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_20_SIZE 18
+#define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_40_SIZE 18
+#define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_20_SIZE 18
+#define B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3 11
+#define B43_NTAB_TX_IQLO_CAL_STARTCOEFS 9
+#define B43_NTAB_TX_IQLO_CAL_CMDS_RECAL_REV3 12
+#define B43_NTAB_TX_IQLO_CAL_CMDS_RECAL 10
+#define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL 10
+#define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3 12
+
+u32 b43_ntab_read(struct b43_wldev *dev, u32 offset);
+void b43_ntab_read_bulk(struct b43_wldev *dev, u32 offset,
+ unsigned int nr_elements, void *_data);
void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value);
-
-extern const u8 b43_ntab_adjustpower0[];
-extern const u8 b43_ntab_adjustpower1[];
-extern const u16 b43_ntab_bdi[];
-extern const u32 b43_ntab_channelest[];
-extern const u8 b43_ntab_estimatepowerlt0[];
-extern const u8 b43_ntab_estimatepowerlt1[];
-extern const u8 b43_ntab_framelookup[];
-extern const u32 b43_ntab_framestruct[];
-extern const u32 b43_ntab_gainctl0[];
-extern const u32 b43_ntab_gainctl1[];
-extern const u32 b43_ntab_intlevel[];
-extern const u32 b43_ntab_iqlt0[];
-extern const u32 b43_ntab_iqlt1[];
-extern const u16 b43_ntab_loftlt0[];
-extern const u16 b43_ntab_loftlt1[];
-extern const u8 b43_ntab_mcs[];
-extern const u32 b43_ntab_noisevar10[];
-extern const u32 b43_ntab_noisevar11[];
-extern const u16 b43_ntab_pilot[];
-extern const u32 b43_ntab_pilotlt[];
-extern const u32 b43_ntab_tdi20a0[];
-extern const u32 b43_ntab_tdi20a1[];
-extern const u32 b43_ntab_tdi40a0[];
-extern const u32 b43_ntab_tdi40a1[];
-extern const u32 b43_ntab_tdtrn[];
-extern const u32 b43_ntab_tmap[];
-
+void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset,
+ unsigned int nr_elements, const void *_data);
+
+void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev);
+void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev);
+
+extern const u32 b43_ntab_tx_gain_rev0_1_2[];
+extern const u32 b43_ntab_tx_gain_rev3plus_2ghz[];
+extern const u32 b43_ntab_tx_gain_rev3_5ghz[];
+extern const u32 b43_ntab_tx_gain_rev4_5ghz[];
+extern const u32 b43_ntab_tx_gain_rev5plus_5ghz[];
+
+extern const u32 txpwrctrl_tx_gain_ipa[];
+extern const u32 txpwrctrl_tx_gain_ipa_rev5[];
+extern const u32 txpwrctrl_tx_gain_ipa_rev6[];
+extern const u32 txpwrctrl_tx_gain_ipa_5g[];
+extern const u16 tbl_iqcal_gainparams[2][9][8];
+extern const struct nphy_txiqcal_ladder ladder_lo[];
+extern const struct nphy_txiqcal_ladder ladder_iq[];
+extern const u16 loscale[];
+
+extern const u16 tbl_tx_iqlo_cal_loft_ladder_40[];
+extern const u16 tbl_tx_iqlo_cal_loft_ladder_20[];
+extern const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[];
+extern const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[];
+extern const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[];
+extern const u16 tbl_tx_iqlo_cal_startcoefs[];
+extern const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[];
+extern const u16 tbl_tx_iqlo_cal_cmds_recal[];
+extern const u16 tbl_tx_iqlo_cal_cmds_fullcal[];
+extern const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[];
+extern const s16 tbl_tx_filter_coef_rev4[7][15];
+
+extern const struct nphy_rf_control_override_rev2
+ tbl_rf_control_override_rev2[];
+extern const struct nphy_rf_control_override_rev3
+ tbl_rf_control_override_rev3[];
#endif /* B43_TABLES_NPHY_H_ */
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index 0a86bdf53154..8b9387c6ff36 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -1411,7 +1411,6 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
b43legacyerr(dev->wl, "DMA tx mapping failure\n");
goto out_unlock;
}
- ring->nr_tx_packets++;
if ((free_slots(ring) < SLOTS_PER_PACKET) ||
should_inject_overflow(ring)) {
/* This TX ring is full. */
@@ -1527,25 +1526,6 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
spin_unlock(&ring->lock);
}
-void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
- const int nr_queues = dev->wl->hw->queues;
- struct b43legacy_dmaring *ring;
- unsigned long flags;
- int i;
-
- for (i = 0; i < nr_queues; i++) {
- ring = priority_to_txring(dev, i);
-
- spin_lock_irqsave(&ring->lock, flags);
- stats[i].len = ring->used_slots / SLOTS_PER_PACKET;
- stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET;
- stats[i].count = ring->nr_tx_packets;
- spin_unlock_irqrestore(&ring->lock, flags);
- }
-}
-
static void dma_rx(struct b43legacy_dmaring *ring,
int *slot)
{
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h
index 2f186003c31e..f9681041c2d8 100644
--- a/drivers/net/wireless/b43legacy/dma.h
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -243,8 +243,6 @@ struct b43legacy_dmaring {
int used_slots;
/* Currently used slot in the ring. */
int current_slot;
- /* Total number of packets sent. Statistics only. */
- unsigned int nr_tx_packets;
/* Frameoffset in octets. */
u32 frameoffset;
/* Descriptor buffer size. */
@@ -292,9 +290,6 @@ void b43legacy_dma_free(struct b43legacy_wldev *dev);
void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev);
void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev);
-void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
- struct ieee80211_tx_queue_stats *stats);
-
int b43legacy_dma_tx(struct b43legacy_wldev *dev,
struct sk_buff *skb);
void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
@@ -315,11 +310,6 @@ void b43legacy_dma_free(struct b43legacy_wldev *dev)
{
}
static inline
-void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
-}
-static inline
int b43legacy_dma_tx(struct b43legacy_wldev *dev,
struct sk_buff *skb)
{
diff --git a/drivers/net/wireless/b43legacy/leds.h b/drivers/net/wireless/b43legacy/leds.h
index 82167a90088f..9ff6750dc57f 100644
--- a/drivers/net/wireless/b43legacy/leds.h
+++ b/drivers/net/wireless/b43legacy/leds.h
@@ -45,7 +45,7 @@ enum b43legacy_led_behaviour {
void b43legacy_leds_init(struct b43legacy_wldev *dev);
void b43legacy_leds_exit(struct b43legacy_wldev *dev);
-#else /* CONFIG_B43EGACY_LEDS */
+#else /* CONFIG_B43LEGACY_LEDS */
/* LED support disabled */
struct b43legacy_led {
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 4a905b6a886b..1d070be5a678 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -61,6 +61,8 @@ MODULE_AUTHOR("Michael Buesch");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID);
+MODULE_FIRMWARE("b43legacy/ucode2.fw");
+MODULE_FIRMWARE("b43legacy/ucode4.fw");
#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)
static int modparam_pio;
@@ -2444,29 +2446,6 @@ static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
return 0;
}
-static int b43legacy_op_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
- struct b43legacy_wldev *dev = wl->current_dev;
- unsigned long flags;
- int err = -ENODEV;
-
- if (!dev)
- goto out;
- spin_lock_irqsave(&wl->irq_lock, flags);
- if (likely(b43legacy_status(dev) >= B43legacy_STAT_STARTED)) {
- if (b43legacy_using_pio(dev))
- b43legacy_pio_get_tx_stats(dev, stats);
- else
- b43legacy_dma_get_tx_stats(dev, stats);
- err = 0;
- }
- spin_unlock_irqrestore(&wl->irq_lock, flags);
-out:
- return err;
-}
-
static int b43legacy_op_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
@@ -2921,6 +2900,7 @@ static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev)
goto out;
}
/* We are ready to run. */
+ ieee80211_wake_queues(dev->wl->hw);
b43legacy_set_status(dev, B43legacy_STAT_STARTED);
/* Start data flow (TX/RX) */
@@ -3341,6 +3321,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
b43legacy_security_init(dev);
b43legacy_rng_init(wl);
+ ieee80211_wake_queues(dev->wl->hw);
b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
b43legacy_leds_init(dev);
@@ -3361,7 +3342,7 @@ err_kfree_lo_control:
}
static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
struct b43legacy_wldev *dev;
@@ -3370,23 +3351,23 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
/* TODO: allow WDS/AP devices to coexist */
- if (conf->type != NL80211_IFTYPE_AP &&
- conf->type != NL80211_IFTYPE_STATION &&
- conf->type != NL80211_IFTYPE_WDS &&
- conf->type != NL80211_IFTYPE_ADHOC)
+ if (vif->type != NL80211_IFTYPE_AP &&
+ vif->type != NL80211_IFTYPE_STATION &&
+ vif->type != NL80211_IFTYPE_WDS &&
+ vif->type != NL80211_IFTYPE_ADHOC)
return -EOPNOTSUPP;
mutex_lock(&wl->mutex);
if (wl->operating)
goto out_mutex_unlock;
- b43legacydbg(wl, "Adding Interface type %d\n", conf->type);
+ b43legacydbg(wl, "Adding Interface type %d\n", vif->type);
dev = wl->current_dev;
wl->operating = 1;
- wl->vif = conf->vif;
- wl->if_type = conf->type;
- memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+ wl->vif = vif;
+ wl->if_type = vif->type;
+ memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
spin_lock_irqsave(&wl->irq_lock, flags);
b43legacy_adjust_opmode(dev);
@@ -3403,18 +3384,18 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
}
static void b43legacy_op_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
struct b43legacy_wldev *dev = wl->current_dev;
unsigned long flags;
- b43legacydbg(wl, "Removing Interface type %d\n", conf->type);
+ b43legacydbg(wl, "Removing Interface type %d\n", vif->type);
mutex_lock(&wl->mutex);
B43legacy_WARN_ON(!wl->operating);
- B43legacy_WARN_ON(wl->vif != conf->vif);
+ B43legacy_WARN_ON(wl->vif != vif);
wl->vif = NULL;
wl->operating = 0;
@@ -3509,7 +3490,6 @@ static const struct ieee80211_ops b43legacy_hw_ops = {
.bss_info_changed = b43legacy_op_bss_info_changed,
.configure_filter = b43legacy_op_configure_filter,
.get_stats = b43legacy_op_get_stats,
- .get_tx_stats = b43legacy_op_get_tx_stats,
.start = b43legacy_op_start,
.stop = b43legacy_op_stop,
.set_tim = b43legacy_op_beacon_set_tim,
@@ -3960,7 +3940,7 @@ static struct ssb_driver b43legacy_ssb_driver = {
static void b43legacy_print_driverinfo(void)
{
- const char *feat_pci = "", *feat_leds = "", *feat_rfkill = "",
+ const char *feat_pci = "", *feat_leds = "",
*feat_pio = "", *feat_dma = "";
#ifdef CONFIG_B43LEGACY_PCI_AUTOSELECT
@@ -3969,9 +3949,6 @@ static void b43legacy_print_driverinfo(void)
#ifdef CONFIG_B43LEGACY_LEDS
feat_leds = "L";
#endif
-#ifdef CONFIG_B43LEGACY_RFKILL
- feat_rfkill = "R";
-#endif
#ifdef CONFIG_B43LEGACY_PIO
feat_pio = "I";
#endif
@@ -3979,9 +3956,9 @@ static void b43legacy_print_driverinfo(void)
feat_dma = "D";
#endif
printk(KERN_INFO "Broadcom 43xx-legacy driver loaded "
- "[ Features: %s%s%s%s%s, Firmware-ID: "
+ "[ Features: %s%s%s%s, Firmware-ID: "
B43legacy_SUPPORTED_FIRMWARE_ID " ]\n",
- feat_pci, feat_leds, feat_rfkill, feat_pio, feat_dma);
+ feat_pci, feat_leds, feat_pio, feat_dma);
}
static int __init b43legacy_init(void)
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c
index 51866c9a2769..017c0e9c37ef 100644
--- a/drivers/net/wireless/b43legacy/pio.c
+++ b/drivers/net/wireless/b43legacy/pio.c
@@ -477,7 +477,6 @@ int b43legacy_pio_tx(struct b43legacy_wldev *dev,
list_move_tail(&packet->list, &queue->txqueue);
queue->nr_txfree--;
- queue->nr_tx_packets++;
B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS);
tasklet_schedule(&queue->txtask);
@@ -546,18 +545,6 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
tasklet_schedule(&queue->txtask);
}
-void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct b43legacy_pio *pio = &dev->pio;
- struct b43legacy_pioqueue *queue;
-
- queue = pio->queue1;
- stats[0].len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree;
- stats[0].limit = B43legacy_PIO_MAXTXPACKETS;
- stats[0].count = queue->nr_tx_packets;
-}
-
static void pio_rx_error(struct b43legacy_pioqueue *queue,
int clear_buffers,
const char *error)
diff --git a/drivers/net/wireless/b43legacy/pio.h b/drivers/net/wireless/b43legacy/pio.h
index 464fec05a06d..8e6773ea6e75 100644
--- a/drivers/net/wireless/b43legacy/pio.h
+++ b/drivers/net/wireless/b43legacy/pio.h
@@ -74,10 +74,6 @@ struct b43legacy_pioqueue {
* posted to the device. We are waiting for the txstatus.
*/
struct list_head txrunning;
- /* Total number or packets sent.
- * (This counter can obviously wrap).
- */
- unsigned int nr_tx_packets;
struct tasklet_struct txtask;
struct b43legacy_pio_txpacket
tx_packets_cache[B43legacy_PIO_MAXTXPACKETS];
@@ -106,8 +102,6 @@ int b43legacy_pio_tx(struct b43legacy_wldev *dev,
struct sk_buff *skb);
void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
const struct b43legacy_txstatus *status);
-void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
- struct ieee80211_tx_queue_stats *stats);
void b43legacy_pio_rx(struct b43legacy_pioqueue *queue);
/* Suspend TX queue in hardware. */
@@ -140,11 +134,6 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
{
}
static inline
-void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
-}
-static inline
void b43legacy_pio_rx(struct b43legacy_pioqueue *queue)
{
}
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index c9640a3e02c9..d19748d90aaf 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -794,13 +794,6 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus",
0x7a954bd9, 0x74be00c6),
PCMCIA_DEVICE_PROD_ID123(
- "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P",
- 0x4b801a17, 0x6345a0bf, 0xc9049a39),
- /* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */
- PCMCIA_DEVICE_PROD_ID123(
- "D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10",
- 0x1a424a1c, 0x6ea57632, 0xdd97a26b),
- PCMCIA_DEVICE_PROD_ID123(
"Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
0xe6ec52ce, 0x08649af2, 0x4b74baa0),
PCMCIA_DEVICE_PROD_ID123(
@@ -834,14 +827,12 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
"Ver. 1.00",
0x5cd01705, 0x4271660f, 0x9d08ee12),
PCMCIA_DEVICE_PROD_ID123(
- "corega", "WL PCCL-11", "ISL37300P",
- 0xa21501a, 0x59868926, 0xc9049a39),
- PCMCIA_DEVICE_PROD_ID123(
- "The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P",
- 0xa5f472c2, 0x9c05598d, 0xc9049a39),
- PCMCIA_DEVICE_PROD_ID123(
"Wireless LAN" , "11Mbps PC Card", "Version 01.02",
0x4b8870ff, 0x70e946d1, 0x4b74baa0),
+ PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092),
+ PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
+ PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
+ PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index ff9b5c882184..d70732819423 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -2618,6 +2618,15 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id)
int events = 0;
u16 ev;
+ /* Detect early interrupt before driver is fully configued */
+ if (!dev->base_addr) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n",
+ dev->name);
+ }
+ return IRQ_HANDLED;
+ }
+
iface = netdev_priv(dev);
local = iface->local;
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index 8fdd41f4b4f2..4d97ae37499b 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -39,7 +39,7 @@ struct hostap_pci_priv {
/* FIX: do we need mb/wmb/rmb with memory operations? */
-static struct pci_device_id prism2_pci_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(prism2_pci_id_table) = {
/* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */
{ 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID },
/* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index 0e5d51086a44..fc04ccdc5bef 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -60,7 +60,7 @@ struct hostap_plx_priv {
#define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
-static struct pci_device_id prism2_plx_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(prism2_plx_id_table) = {
PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
PLXDEV(0x126c, 0x8030, "Nortel emobility"),
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 56afcf041f81..9b72c45a7748 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -6585,7 +6585,7 @@ static void ipw2100_shutdown(struct pci_dev *pci_dev)
#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
-static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(ipw2100_pci_id_table) = {
IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 09ddd3e6bedc..5c7aa1b1eb56 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -3177,14 +3177,27 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len)
int total_nr = 0;
int i;
struct pci_pool *pool;
- u32 *virts[CB_NUMBER_OF_ELEMENTS_SMALL];
- dma_addr_t phys[CB_NUMBER_OF_ELEMENTS_SMALL];
+ void **virts;
+ dma_addr_t *phys;
IPW_DEBUG_TRACE("<< : \n");
+ virts = kmalloc(sizeof(void *) * CB_NUMBER_OF_ELEMENTS_SMALL,
+ GFP_KERNEL);
+ if (!virts)
+ return -ENOMEM;
+
+ phys = kmalloc(sizeof(dma_addr_t) * CB_NUMBER_OF_ELEMENTS_SMALL,
+ GFP_KERNEL);
+ if (!phys) {
+ kfree(virts);
+ return -ENOMEM;
+ }
pool = pci_pool_create("ipw2200", priv->pci_dev, CB_MAX_LENGTH, 0, 0);
if (!pool) {
IPW_ERROR("pci_pool_create failed\n");
+ kfree(phys);
+ kfree(virts);
return -ENOMEM;
}
@@ -3254,6 +3267,8 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len)
pci_pool_free(pool, virts[i], phys[i]);
pci_pool_destroy(pool);
+ kfree(phys);
+ kfree(virts);
return ret;
}
@@ -11524,7 +11539,7 @@ out:
}
/* PCI driver stuff */
-static struct pci_device_id card_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(card_ids) = {
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2701, 0, 0, 0},
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2702, 0, 0, 0},
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2711, 0, 0, 0},
diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h
index bf45391172f3..a6d5e42647e4 100644
--- a/drivers/net/wireless/ipw2x00/libipw.h
+++ b/drivers/net/wireless/ipw2x00/libipw.h
@@ -797,7 +797,7 @@ struct libipw_device {
/* Probe / Beacon management */
struct list_head network_free_list;
struct list_head network_list;
- struct libipw_network *networks;
+ struct libipw_network *networks[MAX_NETWORK_COUNT];
int scans;
int scan_age;
diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c
index 1ae0b2b02c38..2fa55867bd8b 100644
--- a/drivers/net/wireless/ipw2x00/libipw_module.c
+++ b/drivers/net/wireless/ipw2x00/libipw_module.c
@@ -67,16 +67,17 @@ void *libipw_wiphy_privid = &libipw_wiphy_privid;
static int libipw_networks_allocate(struct libipw_device *ieee)
{
- if (ieee->networks)
- return 0;
-
- ieee->networks =
- kzalloc(MAX_NETWORK_COUNT * sizeof(struct libipw_network),
- GFP_KERNEL);
- if (!ieee->networks) {
- printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
- ieee->dev->name);
- return -ENOMEM;
+ int i, j;
+
+ for (i = 0; i < MAX_NETWORK_COUNT; i++) {
+ ieee->networks[i] = kzalloc(sizeof(struct libipw_network),
+ GFP_KERNEL);
+ if (!ieee->networks[i]) {
+ LIBIPW_ERROR("Out of memory allocating beacons\n");
+ for (j = 0; j < i; j++)
+ kfree(ieee->networks[j]);
+ return -ENOMEM;
+ }
}
return 0;
@@ -97,15 +98,11 @@ static inline void libipw_networks_free(struct libipw_device *ieee)
{
int i;
- if (!ieee->networks)
- return;
-
- for (i = 0; i < MAX_NETWORK_COUNT; i++)
- if (ieee->networks[i].ibss_dfs)
- kfree(ieee->networks[i].ibss_dfs);
-
- kfree(ieee->networks);
- ieee->networks = NULL;
+ for (i = 0; i < MAX_NETWORK_COUNT; i++) {
+ if (ieee->networks[i]->ibss_dfs)
+ kfree(ieee->networks[i]->ibss_dfs);
+ kfree(ieee->networks[i]);
+ }
}
void libipw_networks_age(struct libipw_device *ieee,
@@ -130,7 +127,7 @@ static void libipw_networks_initialize(struct libipw_device *ieee)
INIT_LIST_HEAD(&ieee->network_free_list);
INIT_LIST_HEAD(&ieee->network_list);
for (i = 0; i < MAX_NETWORK_COUNT; i++)
- list_add_tail(&ieee->networks[i].list,
+ list_add_tail(&ieee->networks[i]->list,
&ieee->network_free_list);
}
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index b16b06c2031f..dc8ed1527666 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -1,14 +1,8 @@
config IWLWIFI
tristate "Intel Wireless Wifi"
- depends on PCI && MAC80211 && EXPERIMENTAL
+ depends on PCI && MAC80211
select FW_LOADER
-config IWLWIFI_SPECTRUM_MEASUREMENT
- bool "Enable Spectrum Measurement in iwlagn driver"
- depends on IWLWIFI
- ---help---
- This option will enable spectrum measurement for the iwlagn driver.
-
config IWLWIFI_DEBUG
bool "Enable full debugging output in iwlagn and iwl3945 drivers"
depends on IWLWIFI
@@ -120,9 +114,3 @@ config IWL3945
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/kbuild/modules.txt>. The
module will be called iwl3945.
-
-config IWL3945_SPECTRUM_MEASUREMENT
- bool "Enable Spectrum Measurement in iwl3945 driver"
- depends on IWL3945
- ---help---
- This option will enable spectrum measurement for the iwl3945 driver.
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 7f82044af242..4e378faee650 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -3,7 +3,6 @@ iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o
iwlcore-objs += iwl-scan.o iwl-led.o
iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
-iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o
iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
CFLAGS_iwl-devtrace.o := -I$(src)
@@ -20,3 +19,5 @@ iwlagn-$(CONFIG_IWL5000) += iwl-1000.o
# 3945
obj-$(CONFIG_IWL3945) += iwl3945.o
iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 8414178bcff4..3bf2e6e9b2d9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2008-2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -89,8 +89,78 @@ static void iwl1000_nic_config(struct iwl_priv *priv)
~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
}
+static struct iwl_sensitivity_ranges iwl1000_sensitivity = {
+ .min_nrg_cck = 95,
+ .max_nrg_cck = 0, /* not used, set to 0 */
+ .auto_corr_min_ofdm = 90,
+ .auto_corr_min_ofdm_mrc = 170,
+ .auto_corr_min_ofdm_x1 = 120,
+ .auto_corr_min_ofdm_mrc_x1 = 240,
+
+ .auto_corr_max_ofdm = 120,
+ .auto_corr_max_ofdm_mrc = 210,
+ .auto_corr_max_ofdm_x1 = 155,
+ .auto_corr_max_ofdm_mrc_x1 = 290,
+
+ .auto_corr_min_cck = 125,
+ .auto_corr_max_cck = 200,
+ .auto_corr_min_cck_mrc = 170,
+ .auto_corr_max_cck_mrc = 400,
+ .nrg_th_cck = 95,
+ .nrg_th_ofdm = 95,
+
+ .barker_corr_th_min = 190,
+ .barker_corr_th_min_mrc = 390,
+ .nrg_th_cca = 62,
+};
+
+static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
+{
+ if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
+ priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES)
+ priv->cfg->num_of_queues =
+ priv->cfg->mod_params->num_of_queues;
+
+ priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+ priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
+ priv->hw_params.scd_bc_tbls_size =
+ priv->cfg->num_of_queues *
+ sizeof(struct iwl5000_scd_bc_tbl);
+ priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
+ priv->hw_params.max_stations = IWL5000_STATION_COUNT;
+ priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+
+ priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
+ priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
+
+ priv->hw_params.max_bsm_size = 0;
+ priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
+ BIT(IEEE80211_BAND_5GHZ);
+ priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
+
+ priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+ priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+ priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
+ priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
+
+ if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
+ priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+
+ /* Set initial sensitivity parameters */
+ /* Set initial calibration set */
+ priv->hw_params.sens = &iwl1000_sensitivity;
+ priv->hw_params.calib_init_cfg =
+ BIT(IWL_CALIB_XTAL) |
+ BIT(IWL_CALIB_LO) |
+ BIT(IWL_CALIB_TX_IQ) |
+ BIT(IWL_CALIB_TX_IQ_PERD) |
+ BIT(IWL_CALIB_BASE_BAND);
+
+ return 0;
+}
+
static struct iwl_lib_ops iwl1000_lib = {
- .set_hw_params = iwl5000_hw_set_hw_params,
+ .set_hw_params = iwl1000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
.txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwl5000_txq_set_sched,
@@ -105,6 +175,8 @@ static struct iwl_lib_ops iwl1000_lib = {
.load_ucode = iwl5000_load_ucode,
.dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log,
+ .dump_csr = iwl_dump_csr,
+ .dump_fh = iwl_dump_fh,
.init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
@@ -138,9 +210,10 @@ static struct iwl_lib_ops iwl1000_lib = {
.temperature = iwl5000_temperature,
.set_ct_kill = iwl1000_set_ct_threshold,
},
+ .add_bcast_station = iwl_add_bcast_station,
};
-static struct iwl_ops iwl1000_ops = {
+static const struct iwl_ops iwl1000_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl1000_lib,
.hcmd = &iwl5000_hcmd,
@@ -173,7 +246,8 @@ struct iwl_cfg iwl1000_bgn_cfg = {
.use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.support_ct_kill_exit = true,
- .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
};
struct iwl_cfg iwl1000_bg_cfg = {
@@ -200,6 +274,8 @@ struct iwl_cfg iwl1000_bg_cfg = {
.led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
};
MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-fh.h b/drivers/net/wireless/iwlwifi/iwl-3945-fh.h
index 08ce259a0e60..042f6bc0df13 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-fh.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 6fd10d443ba3..3a876a8ece38 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index a871d09d598f..abe2b739c4dc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
index 5a1033ca7aaa..ce990adc51e7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index d4b49883b30e..47909f94271e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 234891d8cc10..e0678d921055 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -45,8 +45,8 @@
#include "iwl-sta.h"
#include "iwl-3945.h"
#include "iwl-eeprom.h"
-#include "iwl-helpers.h"
#include "iwl-core.h"
+#include "iwl-helpers.h"
#include "iwl-led.h"
#include "iwl-3945-led.h"
@@ -184,7 +184,7 @@ static int iwl3945_hwrate_to_plcp_idx(u8 plcp)
{
int idx;
- for (idx = 0; idx < IWL_RATE_COUNT; idx++)
+ for (idx = 0; idx < IWL_RATE_COUNT_3945; idx++)
if (iwl3945_rates[idx].plcp == plcp)
return idx;
return -1;
@@ -805,7 +805,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
int sta_id, int tx_id)
{
u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value;
- u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1);
+ u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT_3945);
u16 rate_mask;
int rate;
u8 rts_retry_limit;
@@ -1951,11 +1951,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
}
/* Add the broadcast address so we can send broadcast frames */
- if (iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL) ==
- IWL_INVALID_STATION) {
- IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n");
- return -EIO;
- }
+ priv->cfg->ops->lib->add_bcast_station(priv);
/* If we have set the ASSOC_MSK and we are in BSS mode then
* add the IWL_AP_ID to the station rate table */
@@ -2150,7 +2146,7 @@ static void iwl3945_hw_reg_init_channel_groups(struct iwl_priv *priv)
/* fill in channel group's nominal powers for each rate */
for (rate_index = 0;
- rate_index < IWL_RATE_COUNT; rate_index++, clip_pwrs++) {
+ rate_index < IWL_RATE_COUNT_3945; rate_index++, clip_pwrs++) {
switch (rate_index) {
case IWL_RATE_36M_INDEX_TABLE:
if (i == 0) /* B/G */
@@ -2474,11 +2470,9 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
memset((void *)&priv->hw_params, 0,
sizeof(struct iwl_hw_params));
- priv->shared_virt =
- pci_alloc_consistent(priv->pci_dev,
- sizeof(struct iwl3945_shared),
- &priv->shared_phys);
-
+ priv->shared_virt = dma_alloc_coherent(&priv->pci_dev->dev,
+ sizeof(struct iwl3945_shared),
+ &priv->shared_phys, GFP_KERNEL);
if (!priv->shared_virt) {
IWL_ERR(priv, "failed to allocate pci memory\n");
mutex_unlock(&priv->mutex);
@@ -2796,6 +2790,7 @@ static struct iwl_lib_ops iwl3945_lib = {
.post_associate = iwl3945_post_associate,
.isr = iwl_isr_legacy,
.config_ap = iwl3945_config_ap,
+ .add_bcast_station = iwl3945_add_bcast_station,
};
static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
@@ -2804,7 +2799,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
.rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
};
-static struct iwl_ops iwl3945_ops = {
+static const struct iwl_ops iwl3945_ops = {
.ucode = &iwl3945_ucode,
.lib = &iwl3945_lib,
.hcmd = &iwl3945_hcmd,
@@ -2830,6 +2825,7 @@ static struct iwl_cfg iwl3945_bg_cfg = {
.ht_greenfield_support = false,
.led_compensation = 64,
.broken_powersave = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
};
static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2847,9 +2843,10 @@ static struct iwl_cfg iwl3945_abg_cfg = {
.ht_greenfield_support = false,
.led_compensation = 64,
.broken_powersave = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
};
-struct pci_device_id iwl3945_hw_card_ids[] = {
+DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = {
{IWL_PCI_DEVICE(0x4222, 0x1005, iwl3945_bg_cfg)},
{IWL_PCI_DEVICE(0x4222, 0x1034, iwl3945_bg_cfg)},
{IWL_PCI_DEVICE(0x4222, 0x1044, iwl3945_bg_cfg)},
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 531fa125f5a6..452dfd5456c6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -37,7 +37,7 @@
#include <net/ieee80211_radiotap.h>
/* Hardware specific file defines the PCI IDs table for that hardware module */
-extern struct pci_device_id iwl3945_hw_card_ids[];
+extern const struct pci_device_id iwl3945_hw_card_ids[];
#include "iwl-csr.h"
#include "iwl-prph.h"
@@ -171,24 +171,6 @@ struct iwl3945_frame {
#define SCAN_INTERVAL 100
-#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
-#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */
-#define STATUS_INT_ENABLED 2
-#define STATUS_RF_KILL_HW 3
-#define STATUS_INIT 5
-#define STATUS_ALIVE 6
-#define STATUS_READY 7
-#define STATUS_TEMPERATURE 8
-#define STATUS_GEO_CONFIGURED 9
-#define STATUS_EXIT_PENDING 10
-#define STATUS_STATISTICS 12
-#define STATUS_SCANNING 13
-#define STATUS_SCAN_ABORTING 14
-#define STATUS_SCAN_HW 15
-#define STATUS_POWER_PMI 16
-#define STATUS_FW_ERROR 17
-#define STATUS_CONF_PENDING 18
-
#define MAX_TID_COUNT 9
#define IWL_INVALID_RATE 0xFF
@@ -226,7 +208,8 @@ extern void iwl3945_rx_replenish(void *data);
extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
struct ieee80211_hdr *hdr,int left);
-extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
+extern int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+ char **buf, bool display);
extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv);
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index c606366b582c..67ef562e8db1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 9b4b8b5c7574..1bd2cd836026 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -581,6 +581,13 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+ /* make sure all queue are not stopped */
+ memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
+ for (i = 0; i < 4; i++)
+ atomic_set(&priv->queue_stop_count[i], 0);
+
+ /* reset to 0 to enable all the queue first */
+ priv->txq_ctx_active_msk = 0;
/* Map each Tx/cmd queue to its corresponding fifo */
for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
int ac = default_queue_to_tx_fifo[i];
@@ -2008,7 +2015,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim scd_ssn "
"%d index %d\n", scd_ssn , index);
freed = iwl_tx_queue_reclaim(priv, txq_id, index);
- priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+ iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
if (priv->mac80211_registered &&
(iwl_queue_space(&txq->q) > txq->q.low_mark) &&
@@ -2206,9 +2213,10 @@ static struct iwl_lib_ops iwl4965_lib = {
.temperature = iwl4965_temperature_calib,
.set_ct_kill = iwl4965_set_ct_threshold,
},
+ .add_bcast_station = iwl_add_bcast_station,
};
-static struct iwl_ops iwl4965_ops = {
+static const struct iwl_ops iwl4965_ops = {
.ucode = &iwl4965_ucode,
.lib = &iwl4965_lib,
.hcmd = &iwl4965_hcmd,
@@ -2239,7 +2247,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
.broken_powersave = true,
.led_compensation = 61,
.chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
- .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
};
/* Module firmware */
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
index bc056e9ab85f..714e032f6217 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 33a5866538e7..e476acb53aa7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -179,14 +179,24 @@ static void iwl5000_gain_computation(struct iwl_priv *priv,
data->delta_gain_code[i] = 0;
continue;
}
- delta_g = (1000 * ((s32)average_noise[default_chain] -
+
+ delta_g = (priv->cfg->chain_noise_scale *
+ ((s32)average_noise[default_chain] -
(s32)average_noise[i])) / 1500;
+
/* bound gain by 2 bits value max, 3rd bit is sign */
data->delta_gain_code[i] =
min(abs(delta_g), (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
if (delta_g < 0)
- /* set negative sign */
+ /*
+ * set negative sign ...
+ * note to Intel developers: This is uCode API format,
+ * not the format of any internal device registers.
+ * Do not change this format for e.g. 6050 or similar
+ * devices. Change format only if more resolution
+ * (i.e. more than 2 bits magnitude) is needed.
+ */
data->delta_gain_code[i] |= (1 << 2);
}
@@ -263,8 +273,8 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.auto_corr_max_ofdm = 120,
.auto_corr_max_ofdm_mrc = 210,
- .auto_corr_max_ofdm_x1 = 155,
- .auto_corr_max_ofdm_mrc_x1 = 290,
+ .auto_corr_max_ofdm_x1 = 120,
+ .auto_corr_max_ofdm_mrc_x1 = 240,
.auto_corr_min_cck = 125,
.auto_corr_max_cck = 200,
@@ -412,12 +422,14 @@ static void iwl5000_rx_calib_complete(struct iwl_priv *priv,
/*
* ucode
*/
-static int iwl5000_load_section(struct iwl_priv *priv,
- struct fw_desc *image,
- u32 dst_addr)
+static int iwl5000_load_section(struct iwl_priv *priv, const char *name,
+ struct fw_desc *image, u32 dst_addr)
{
dma_addr_t phy_addr = image->p_addr;
u32 byte_cnt = image->len;
+ int ret;
+
+ priv->ucode_write_complete = 0;
iwl_write_direct32(priv,
FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
@@ -447,57 +459,36 @@ static int iwl5000_load_section(struct iwl_priv *priv,
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
- return 0;
-}
-
-static int iwl5000_load_given_ucode(struct iwl_priv *priv,
- struct fw_desc *inst_image,
- struct fw_desc *data_image)
-{
- int ret = 0;
-
- ret = iwl5000_load_section(priv, inst_image,
- IWL50_RTC_INST_LOWER_BOUND);
- if (ret)
- return ret;
-
- IWL_DEBUG_INFO(priv, "INST uCode section being loaded...\n");
+ IWL_DEBUG_INFO(priv, "%s uCode section being loaded...\n", name);
ret = wait_event_interruptible_timeout(priv->wait_command_queue,
priv->ucode_write_complete, 5 * HZ);
if (ret == -ERESTARTSYS) {
- IWL_ERR(priv, "Could not load the INST uCode section due "
- "to interrupt\n");
+ IWL_ERR(priv, "Could not load the %s uCode section due "
+ "to interrupt\n", name);
return ret;
}
if (!ret) {
- IWL_ERR(priv, "Could not load the INST uCode section\n");
+ IWL_ERR(priv, "Could not load the %s uCode section\n",
+ name);
return -ETIMEDOUT;
}
- priv->ucode_write_complete = 0;
-
- ret = iwl5000_load_section(
- priv, data_image, IWL50_RTC_DATA_LOWER_BOUND);
- if (ret)
- return ret;
+ return 0;
+}
- IWL_DEBUG_INFO(priv, "DATA uCode section being loaded...\n");
+static int iwl5000_load_given_ucode(struct iwl_priv *priv,
+ struct fw_desc *inst_image,
+ struct fw_desc *data_image)
+{
+ int ret = 0;
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
- priv->ucode_write_complete, 5 * HZ);
- if (ret == -ERESTARTSYS) {
- IWL_ERR(priv, "Could not load the INST uCode section due "
- "to interrupt\n");
+ ret = iwl5000_load_section(priv, "INST", inst_image,
+ IWL50_RTC_INST_LOWER_BOUND);
+ if (ret)
return ret;
- } else if (!ret) {
- IWL_ERR(priv, "Could not load the DATA uCode section\n");
- return -ETIMEDOUT;
- } else
- ret = 0;
- priv->ucode_write_complete = 0;
-
- return ret;
+ return iwl5000_load_section(priv, "DATA", data_image,
+ IWL50_RTC_DATA_LOWER_BOUND);
}
int iwl5000_load_ucode(struct iwl_priv *priv)
@@ -657,6 +648,13 @@ int iwl5000_alive_notify(struct iwl_priv *priv)
iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+ /* make sure all queue are not stopped */
+ memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
+ for (i = 0; i < 4; i++)
+ atomic_set(&priv->queue_stop_count[i], 0);
+
+ /* reset to 0 to enable all the queue first */
+ priv->txq_ctx_active_msk = 0;
/* map qos queues to fifos one-to-one */
for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) {
int ac = iwl5000_default_queue_to_tx_fifo[i];
@@ -781,7 +779,7 @@ void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
- if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+ if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
scd_bc_tbl[txq_id].
tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
}
@@ -800,12 +798,12 @@ void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
if (txq_id != IWL_CMD_QUEUE_NUM)
sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
- bc_ent = cpu_to_le16(1 | (sta_id << 12));
+ bc_ent = cpu_to_le16(1 | (sta_id << 12));
scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
- if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+ if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
scd_bc_tbl[txq_id].
- tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
+ tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
}
static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
@@ -1125,7 +1123,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
scd_ssn , index, txq_id, txq->swq_id);
freed = iwl_tx_queue_reclaim(priv, txq_id, index);
- priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+ iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
if (priv->mac80211_registered &&
(iwl_queue_space(&txq->q) > txq->q.low_mark) &&
@@ -1153,16 +1151,14 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
tx_resp->failure_frame);
freed = iwl_tx_queue_reclaim(priv, txq_id, index);
- if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
- priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+ iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
if (priv->mac80211_registered &&
(iwl_queue_space(&txq->q) > txq->q.low_mark))
iwl_wake_queue(priv, txq_id);
}
- if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
- iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+ iwl_txq_check_empty(priv, sta_id, tid, txq_id);
if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
IWL_ERR(priv, "TODO: Implement Tx ABORT REQUIRED!!!\n");
@@ -1466,6 +1462,8 @@ struct iwl_lib_ops iwl5000_lib = {
.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
.dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log,
+ .dump_csr = iwl_dump_csr,
+ .dump_fh = iwl_dump_fh,
.load_ucode = iwl5000_load_ucode,
.init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify,
@@ -1501,6 +1499,7 @@ struct iwl_lib_ops iwl5000_lib = {
.temperature = iwl5000_temperature,
.set_ct_kill = iwl5000_set_ct_threshold,
},
+ .add_bcast_station = iwl_add_bcast_station,
};
static struct iwl_lib_ops iwl5150_lib = {
@@ -1518,6 +1517,7 @@ static struct iwl_lib_ops iwl5150_lib = {
.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
.dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log,
+ .dump_csr = iwl_dump_csr,
.load_ucode = iwl5000_load_ucode,
.init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify,
@@ -1553,9 +1553,10 @@ static struct iwl_lib_ops iwl5150_lib = {
.temperature = iwl5150_temperature,
.set_ct_kill = iwl5150_set_ct_threshold,
},
+ .add_bcast_station = iwl_add_bcast_station,
};
-static struct iwl_ops iwl5000_ops = {
+static const struct iwl_ops iwl5000_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
@@ -1563,7 +1564,7 @@ static struct iwl_ops iwl5000_ops = {
.led = &iwlagn_led_ops,
};
-static struct iwl_ops iwl5150_ops = {
+static const struct iwl_ops iwl5150_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl5150_lib,
.hcmd = &iwl5000_hcmd,
@@ -1598,8 +1599,10 @@ struct iwl_cfg iwl5300_agn_cfg = {
.use_bsm = false,
.ht_greenfield_support = true,
.led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
};
struct iwl_cfg iwl5100_bgn_cfg = {
@@ -1622,7 +1625,10 @@ struct iwl_cfg iwl5100_bgn_cfg = {
.use_bsm = false,
.ht_greenfield_support = true,
.led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
};
struct iwl_cfg iwl5100_abg_cfg = {
@@ -1645,6 +1651,8 @@ struct iwl_cfg iwl5100_abg_cfg = {
.use_bsm = false,
.led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
};
struct iwl_cfg iwl5100_agn_cfg = {
@@ -1667,8 +1675,10 @@ struct iwl_cfg iwl5100_agn_cfg = {
.use_bsm = false,
.ht_greenfield_support = true,
.led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
};
struct iwl_cfg iwl5350_agn_cfg = {
@@ -1691,8 +1701,10 @@ struct iwl_cfg iwl5350_agn_cfg = {
.use_bsm = false,
.ht_greenfield_support = true,
.led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
};
struct iwl_cfg iwl5150_agn_cfg = {
@@ -1715,8 +1727,10 @@ struct iwl_cfg iwl5150_agn_cfg = {
.use_bsm = false,
.ht_greenfield_support = true,
.led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
};
struct iwl_cfg iwl5150_abg_cfg = {
@@ -1739,6 +1753,8 @@ struct iwl_cfg iwl5150_abg_cfg = {
.use_bsm = false,
.led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
};
MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h
index 90185777d98b..ddba39999997 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 74e571049273..c4844adff92a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2008-2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -70,6 +70,14 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
}
+/* Indicate calibration version to uCode. */
+static void iwl6050_set_calib_version(struct iwl_priv *priv)
+{
+ if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
+ iwl_set_bit(priv, CSR_GP_DRIVER_REG,
+ CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
+}
+
/* NIC configuration for 6000 series */
static void iwl6000_nic_config(struct iwl_priv *priv)
{
@@ -96,6 +104,8 @@ static void iwl6000_nic_config(struct iwl_priv *priv)
CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
}
/* else do nothing, uCode configured */
+ if (priv->cfg->ops->lib->temp_ops.set_calib_version)
+ priv->cfg->ops->lib->temp_ops.set_calib_version(priv);
}
static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
@@ -108,7 +118,7 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
.auto_corr_max_ofdm = 145,
.auto_corr_max_ofdm_mrc = 232,
- .auto_corr_max_ofdm_x1 = 145,
+ .auto_corr_max_ofdm_x1 = 110,
.auto_corr_max_ofdm_mrc_x1 = 232,
.auto_corr_min_cck = 125,
@@ -158,11 +168,25 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
/* Set initial sensitivity parameters */
/* Set initial calibration set */
priv->hw_params.sens = &iwl6000_sensitivity;
- priv->hw_params.calib_init_cfg =
+ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+ case CSR_HW_REV_TYPE_6x50:
+ priv->hw_params.calib_init_cfg =
+ BIT(IWL_CALIB_XTAL) |
+ BIT(IWL_CALIB_DC) |
+ BIT(IWL_CALIB_LO) |
+ BIT(IWL_CALIB_TX_IQ) |
+ BIT(IWL_CALIB_BASE_BAND);
+
+ break;
+ default:
+ priv->hw_params.calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_BASE_BAND);
+ break;
+ }
+
return 0;
}
@@ -215,6 +239,8 @@ static struct iwl_lib_ops iwl6000_lib = {
.load_ucode = iwl5000_load_ucode,
.dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log,
+ .dump_csr = iwl_dump_csr,
+ .dump_fh = iwl_dump_fh,
.init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
@@ -250,9 +276,10 @@ static struct iwl_lib_ops iwl6000_lib = {
.temperature = iwl5000_temperature,
.set_ct_kill = iwl6000_set_ct_threshold,
},
+ .add_bcast_station = iwl_add_bcast_station,
};
-static struct iwl_ops iwl6000_ops = {
+static const struct iwl_ops iwl6000_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl6000_lib,
.hcmd = &iwl5000_hcmd,
@@ -260,18 +287,68 @@ static struct iwl_ops iwl6000_ops = {
.led = &iwlagn_led_ops,
};
-static struct iwl_hcmd_utils_ops iwl6050_hcmd_utils = {
- .get_hcmd_size = iwl5000_get_hcmd_size,
- .build_addsta_hcmd = iwl5000_build_addsta_hcmd,
- .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag,
- .calc_rssi = iwl5000_calc_rssi,
+static struct iwl_lib_ops iwl6050_lib = {
+ .set_hw_params = iwl6000_hw_set_hw_params,
+ .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
+ .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
+ .txq_set_sched = iwl5000_txq_set_sched,
+ .txq_agg_enable = iwl5000_txq_agg_enable,
+ .txq_agg_disable = iwl5000_txq_agg_disable,
+ .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
+ .txq_free_tfd = iwl_hw_txq_free_tfd,
+ .txq_init = iwl_hw_tx_queue_init,
+ .rx_handler_setup = iwl5000_rx_handler_setup,
+ .setup_deferred_work = iwl5000_setup_deferred_work,
+ .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+ .load_ucode = iwl5000_load_ucode,
+ .dump_nic_event_log = iwl_dump_nic_event_log,
+ .dump_nic_error_log = iwl_dump_nic_error_log,
+ .dump_csr = iwl_dump_csr,
+ .dump_fh = iwl_dump_fh,
+ .init_alive_start = iwl5000_init_alive_start,
+ .alive_notify = iwl5000_alive_notify,
+ .send_tx_power = iwl5000_send_tx_power,
+ .update_chain_flags = iwl_update_chain_flags,
+ .set_channel_switch = iwl6000_hw_channel_switch,
+ .apm_ops = {
+ .init = iwl_apm_init,
+ .stop = iwl_apm_stop,
+ .config = iwl6000_nic_config,
+ .set_pwr_src = iwl_set_pwr_src,
+ },
+ .eeprom_ops = {
+ .regulatory_bands = {
+ EEPROM_5000_REG_BAND_1_CHANNELS,
+ EEPROM_5000_REG_BAND_2_CHANNELS,
+ EEPROM_5000_REG_BAND_3_CHANNELS,
+ EEPROM_5000_REG_BAND_4_CHANNELS,
+ EEPROM_5000_REG_BAND_5_CHANNELS,
+ EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
+ EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+ },
+ .verify_signature = iwlcore_eeprom_verify_signature,
+ .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+ .release_semaphore = iwlcore_eeprom_release_semaphore,
+ .calib_version = iwl5000_eeprom_calib_version,
+ .query_addr = iwl5000_eeprom_query_addr,
+ .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
+ },
+ .post_associate = iwl_post_associate,
+ .isr = iwl_isr_ict,
+ .config_ap = iwl_config_ap,
+ .temp_ops = {
+ .temperature = iwl5000_temperature,
+ .set_ct_kill = iwl6000_set_ct_threshold,
+ .set_calib_version = iwl6050_set_calib_version,
+ },
+ .add_bcast_station = iwl_add_bcast_station,
};
-static struct iwl_ops iwl6050_ops = {
+static const struct iwl_ops iwl6050_ops = {
.ucode = &iwl5000_ucode,
- .lib = &iwl6000_lib,
+ .lib = &iwl6050_lib,
.hcmd = &iwl5000_hcmd,
- .utils = &iwl6050_hcmd_utils,
+ .utils = &iwl5000_hcmd_utils,
.led = &iwlagn_led_ops,
};
@@ -306,7 +383,8 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
.supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
- .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
};
struct iwl_cfg iwl6000i_2abg_cfg = {
@@ -336,6 +414,8 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
.supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
};
struct iwl_cfg iwl6000i_2bg_cfg = {
@@ -365,6 +445,8 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
.supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
};
struct iwl_cfg iwl6050_2agn_cfg = {
@@ -395,7 +477,8 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
- .sm_ps_mode = WLAN_HT_CAP_SM_PS_DYNAMIC,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1500,
};
struct iwl_cfg iwl6050_2abg_cfg = {
@@ -425,6 +508,8 @@ struct iwl_cfg iwl6050_2abg_cfg = {
.supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1500,
};
struct iwl_cfg iwl6000_3agn_cfg = {
@@ -455,7 +540,8 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
- .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
};
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c
index 3bccba20f6da..1a24946bc203 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h
index ab55f92a161d..a594e4fdc6b8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index b93e49158196..8bf7c20b9d39 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -298,10 +298,23 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
struct iwl_lq_sta *lq_data, u8 tid,
struct ieee80211_sta *sta)
{
+ int ret;
+
if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
sta->addr, tid);
- ieee80211_start_tx_ba_session(sta, tid);
+ ret = ieee80211_start_tx_ba_session(sta, tid);
+ if (ret == -EAGAIN) {
+ /*
+ * driver and mac80211 is out of sync
+ * this might be cause by reloading firmware
+ * stop the tx ba session here
+ */
+ IWL_DEBUG_HT(priv, "Fail start Tx agg on tid: %d\n",
+ tid);
+ ret = ieee80211_stop_tx_ba_session(sta, tid,
+ WLAN_BACK_INITIATOR);
+ }
}
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index affc0c5a2f2c..e71923961e69 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -191,7 +191,7 @@ enum {
IWL_RATE_2M_MASK)
#define IWL_CCK_RATES_MASK \
- (IWL_BASIC_RATES_MASK | \
+ (IWL_CCK_BASIC_RATES_MASK | \
IWL_RATE_5M_MASK | \
IWL_RATE_11M_MASK)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 1c9866daf815..818367b57bab 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -73,13 +73,7 @@
#define VD
#endif
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
-#define VS "s"
-#else
-#define VS
-#endif
-
-#define DRV_VERSION IWLWIFI_VERSION VD VS
+#define DRV_VERSION IWLWIFI_VERSION VD
MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -203,7 +197,8 @@ int iwl_commit_rxon(struct iwl_priv *priv)
priv->start_calib = 0;
/* Add the broadcast address so we can send broadcast frames */
- iwl_add_bcast_station(priv);
+ priv->cfg->ops->lib->add_bcast_station(priv);
+
/* If we have set the ASSOC_MSK and we are in BSS mode then
* add the IWL_AP_ID to the station rate table */
@@ -657,6 +652,131 @@ static void iwl_bg_statistics_periodic(unsigned long data)
iwl_send_statistics_request(priv, CMD_ASYNC, false);
}
+
+static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
+ u32 start_idx, u32 num_events,
+ u32 mode)
+{
+ u32 i;
+ u32 ptr; /* SRAM byte address of log data */
+ u32 ev, time, data; /* event log data */
+ unsigned long reg_flags;
+
+ if (mode == 0)
+ ptr = base + (4 * sizeof(u32)) + (start_idx * 2 * sizeof(u32));
+ else
+ ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
+
+ /* Make sure device is powered up for SRAM reads */
+ spin_lock_irqsave(&priv->reg_lock, reg_flags);
+ if (iwl_grab_nic_access(priv)) {
+ spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+ return;
+ }
+
+ /* Set starting address; reads will auto-increment */
+ _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr);
+ rmb();
+
+ /*
+ * "time" is actually "data" for mode 0 (no timestamp).
+ * place event id # at far right for easier visual parsing.
+ */
+ for (i = 0; i < num_events; i++) {
+ ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+ time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+ if (mode == 0) {
+ trace_iwlwifi_dev_ucode_cont_event(priv,
+ 0, time, ev);
+ } else {
+ data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+ trace_iwlwifi_dev_ucode_cont_event(priv,
+ time, data, ev);
+ }
+ }
+ /* Allow device to power down */
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+}
+
+static void iwl_continuous_event_trace(struct iwl_priv *priv)
+{
+ u32 capacity; /* event log capacity in # entries */
+ u32 base; /* SRAM byte address of event log header */
+ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
+ u32 num_wraps; /* # times uCode wrapped to top of log */
+ u32 next_entry; /* index of next entry to be written by uCode */
+
+ if (priv->ucode_type == UCODE_INIT)
+ base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
+ else
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+ capacity = iwl_read_targ_mem(priv, base);
+ num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
+ mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
+ next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+ } else
+ return;
+
+ if (num_wraps == priv->event_log.num_wraps) {
+ iwl_print_cont_event_trace(priv,
+ base, priv->event_log.next_entry,
+ next_entry - priv->event_log.next_entry,
+ mode);
+ priv->event_log.non_wraps_count++;
+ } else {
+ if ((num_wraps - priv->event_log.num_wraps) > 1)
+ priv->event_log.wraps_more_count++;
+ else
+ priv->event_log.wraps_once_count++;
+ trace_iwlwifi_dev_ucode_wrap_event(priv,
+ num_wraps - priv->event_log.num_wraps,
+ next_entry, priv->event_log.next_entry);
+ if (next_entry < priv->event_log.next_entry) {
+ iwl_print_cont_event_trace(priv, base,
+ priv->event_log.next_entry,
+ capacity - priv->event_log.next_entry,
+ mode);
+
+ iwl_print_cont_event_trace(priv, base, 0,
+ next_entry, mode);
+ } else {
+ iwl_print_cont_event_trace(priv, base,
+ next_entry, capacity - next_entry,
+ mode);
+
+ iwl_print_cont_event_trace(priv, base, 0,
+ next_entry, mode);
+ }
+ }
+ priv->event_log.num_wraps = num_wraps;
+ priv->event_log.next_entry = next_entry;
+}
+
+/**
+ * iwl_bg_ucode_trace - Timer callback to log ucode event
+ *
+ * The timer is continually set to execute every
+ * UCODE_TRACE_PERIOD milliseconds after the last timer expired
+ * this function is to perform continuous uCode event logging operation
+ * if enabled
+ */
+static void iwl_bg_ucode_trace(unsigned long data)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)data;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (priv->event_log.ucode_trace) {
+ iwl_continuous_event_trace(priv);
+ /* Reschedule the timer to occur in UCODE_TRACE_PERIOD */
+ mod_timer(&priv->ucode_trace,
+ jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
+ }
+}
+
static void iwl_rx_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
@@ -689,12 +809,14 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status;
- IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
+ IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n",
(flags & HW_CARD_DISABLED) ? "Kill" : "On",
- (flags & SW_CARD_DISABLED) ? "Kill" : "On");
+ (flags & SW_CARD_DISABLED) ? "Kill" : "On",
+ (flags & CT_CARD_DISABLED) ?
+ "Reached" : "Not reached");
if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
- RF_CARD_DISABLED)) {
+ CT_CARD_DISABLED)) {
iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
@@ -708,10 +830,10 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
iwl_write_direct32(priv, HBUS_TARG_MBX_C,
HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
}
- if (flags & RF_CARD_DISABLED)
+ if (flags & CT_CARD_DISABLED)
iwl_tt_enter_ct_kill(priv);
}
- if (!(flags & RF_CARD_DISABLED))
+ if (!(flags & CT_CARD_DISABLED))
iwl_tt_exit_ct_kill(priv);
if (flags & HW_CARD_DISABLED)
@@ -761,6 +883,8 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+ priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+ iwl_rx_spectrum_measure_notif;
priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
iwl_rx_pm_debug_statistics_notif;
@@ -774,7 +898,6 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_reply_statistics;
priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics;
- iwl_setup_spectrum_handlers(priv);
iwl_setup_rx_scan_handlers(priv);
/* status change handler */
@@ -1340,59 +1463,66 @@ static void iwl_nic_start(struct iwl_priv *priv)
}
+static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
+static int iwl_mac_setup_register(struct iwl_priv *priv);
+
+static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
+{
+ const char *name_pre = priv->cfg->fw_name_pre;
+
+ if (first)
+ priv->fw_index = priv->cfg->ucode_api_max;
+ else
+ priv->fw_index--;
+
+ if (priv->fw_index < priv->cfg->ucode_api_min) {
+ IWL_ERR(priv, "no suitable firmware found!\n");
+ return -ENOENT;
+ }
+
+ sprintf(priv->firmware_name, "%s%d%s",
+ name_pre, priv->fw_index, ".ucode");
+
+ IWL_DEBUG_INFO(priv, "attempting to load firmware '%s'\n",
+ priv->firmware_name);
+
+ return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name,
+ &priv->pci_dev->dev, GFP_KERNEL, priv,
+ iwl_ucode_callback);
+}
+
/**
- * iwl_read_ucode - Read uCode images from disk file.
+ * iwl_ucode_callback - callback when firmware was loaded
*
- * Copy into buffers for card to fetch via bus-mastering
+ * If loaded successfully, copies the firmware into buffers
+ * for the card to fetch (via DMA).
*/
-static int iwl_read_ucode(struct iwl_priv *priv)
+static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
{
+ struct iwl_priv *priv = context;
struct iwl_ucode_header *ucode;
- int ret = -EINVAL, index;
- const struct firmware *ucode_raw;
- const char *name_pre = priv->cfg->fw_name_pre;
const unsigned int api_max = priv->cfg->ucode_api_max;
const unsigned int api_min = priv->cfg->ucode_api_min;
- char buf[25];
u8 *src;
size_t len;
u32 api_ver, build;
u32 inst_size, data_size, init_size, init_data_size, boot_size;
+ int err;
u16 eeprom_ver;
- /* Ask kernel firmware_class module to get the boot firmware off disk.
- * request_firmware() is synchronous, file is in memory on return. */
- for (index = api_max; index >= api_min; index--) {
- sprintf(buf, "%s%d%s", name_pre, index, ".ucode");
- ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev);
- if (ret < 0) {
- IWL_ERR(priv, "%s firmware file req failed: %d\n",
- buf, ret);
- if (ret == -ENOENT)
- continue;
- else
- goto error;
- } else {
- if (index < api_max)
- IWL_ERR(priv, "Loaded firmware %s, "
- "which is deprecated. "
- "Please use API v%u instead.\n",
- buf, api_max);
-
- IWL_DEBUG_INFO(priv, "Got firmware '%s' file (%zd bytes) from disk\n",
- buf, ucode_raw->size);
- break;
- }
+ if (!ucode_raw) {
+ IWL_ERR(priv, "request for firmware file '%s' failed.\n",
+ priv->firmware_name);
+ goto try_again;
}
- if (ret < 0)
- goto error;
+ IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n",
+ priv->firmware_name, ucode_raw->size);
/* Make sure that we got at least the v1 header! */
if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n");
- ret = -EINVAL;
- goto err_release;
+ goto try_again;
}
/* Data from ucode file: header followed by uCode images */
@@ -1417,10 +1547,9 @@ static int iwl_read_ucode(struct iwl_priv *priv)
IWL_ERR(priv, "Driver unable to support your firmware API. "
"Driver supports v%u, firmware is v%u.\n",
api_max, api_ver);
- priv->ucode_ver = 0;
- ret = -EINVAL;
- goto err_release;
+ goto try_again;
}
+
if (api_ver != api_max)
IWL_ERR(priv, "Firmware has old API version. Expected v%u, "
"got v%u. New firmware can be obtained "
@@ -1462,6 +1591,12 @@ static int iwl_read_ucode(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %u\n",
boot_size);
+ /*
+ * For any of the failures below (before allocating pci memory)
+ * we will try to load a version with a smaller API -- maybe the
+ * user just got a corrupted version of the latest API.
+ */
+
/* Verify size of file vs. image size info in file's header */
if (ucode_raw->size !=
priv->cfg->ops->ucode->get_header_size(api_ver) +
@@ -1471,41 +1606,35 @@ static int iwl_read_ucode(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv,
"uCode file size %d does not match expected size\n",
(int)ucode_raw->size);
- ret = -EINVAL;
- goto err_release;
+ goto try_again;
}
/* Verify that uCode images will fit in card's SRAM */
if (inst_size > priv->hw_params.max_inst_size) {
IWL_DEBUG_INFO(priv, "uCode instr len %d too large to fit in\n",
inst_size);
- ret = -EINVAL;
- goto err_release;
+ goto try_again;
}
if (data_size > priv->hw_params.max_data_size) {
IWL_DEBUG_INFO(priv, "uCode data len %d too large to fit in\n",
data_size);
- ret = -EINVAL;
- goto err_release;
+ goto try_again;
}
if (init_size > priv->hw_params.max_inst_size) {
IWL_INFO(priv, "uCode init instr len %d too large to fit in\n",
init_size);
- ret = -EINVAL;
- goto err_release;
+ goto try_again;
}
if (init_data_size > priv->hw_params.max_data_size) {
IWL_INFO(priv, "uCode init data len %d too large to fit in\n",
init_data_size);
- ret = -EINVAL;
- goto err_release;
+ goto try_again;
}
if (boot_size > priv->hw_params.max_bsm_size) {
IWL_INFO(priv, "uCode boot instr len %d too large to fit in\n",
boot_size);
- ret = -EINVAL;
- goto err_release;
+ goto try_again;
}
/* Allocate ucode buffers for card's bus-master loading ... */
@@ -1589,20 +1718,36 @@ static int iwl_read_ucode(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
memcpy(priv->ucode_boot.v_addr, src, len);
+ /**************************************************
+ * This is still part of probe() in a sense...
+ *
+ * 9. Setup and register with mac80211 and debugfs
+ **************************************************/
+ err = iwl_mac_setup_register(priv);
+ if (err)
+ goto out_unbind;
+
+ err = iwl_dbgfs_register(priv, DRV_NAME);
+ if (err)
+ IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
+
/* We have our copies now, allow OS release its copies */
release_firmware(ucode_raw);
- return 0;
+ return;
+
+ try_again:
+ /* try next, if any */
+ if (iwl_request_firmware(priv, false))
+ goto out_unbind;
+ release_firmware(ucode_raw);
+ return;
err_pci_alloc:
IWL_ERR(priv, "failed to allocate pci memory\n");
- ret = -ENOMEM;
iwl_dealloc_ucode_pci(priv);
-
- err_release:
+ out_unbind:
+ device_release_driver(&priv->pci_dev->dev);
release_firmware(ucode_raw);
-
- error:
- return ret;
}
static const char *desc_lookup_text[] = {
@@ -1634,7 +1779,7 @@ static const char *desc_lookup_text[] = {
"DEBUG_1",
"DEBUG_2",
"DEBUG_3",
- "UNKNOWN"
+ "ADVANCED SYSASSERT"
};
static const char *desc_lookup(int i)
@@ -1705,8 +1850,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
* iwl_print_event_log - Dump error event log to syslog
*
*/
-static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
- u32 num_events, u32 mode)
+static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+ u32 num_events, u32 mode,
+ int pos, char **buf, size_t bufsz)
{
u32 i;
u32 base; /* SRAM byte address of event log header */
@@ -1716,7 +1862,7 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
unsigned long reg_flags;
if (num_events == 0)
- return;
+ return pos;
if (priv->ucode_type == UCODE_INIT)
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
else
@@ -1744,27 +1890,44 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
if (mode == 0) {
/* data, ev */
- trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
- IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
+ if (bufsz) {
+ pos += scnprintf(*buf + pos, bufsz - pos,
+ "EVT_LOG:0x%08x:%04u\n",
+ time, ev);
+ } else {
+ trace_iwlwifi_dev_ucode_event(priv, 0,
+ time, ev);
+ IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n",
+ time, ev);
+ }
} else {
data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
- IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
+ if (bufsz) {
+ pos += scnprintf(*buf + pos, bufsz - pos,
+ "EVT_LOGT:%010u:0x%08x:%04u\n",
+ time, data, ev);
+ } else {
+ IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
time, data, ev);
- trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
+ trace_iwlwifi_dev_ucode_event(priv, time,
+ data, ev);
+ }
}
}
/* Allow device to power down */
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+ return pos;
}
/**
* iwl_print_last_event_logs - Dump the newest # of event log to syslog
*/
-static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
- u32 num_wraps, u32 next_entry,
- u32 size, u32 mode)
+static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
+ u32 num_wraps, u32 next_entry,
+ u32 size, u32 mode,
+ int pos, char **buf, size_t bufsz)
{
/*
* display the newest DEFAULT_LOG_ENTRIES entries
@@ -1772,21 +1935,26 @@ static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
*/
if (num_wraps) {
if (next_entry < size) {
- iwl_print_event_log(priv,
- capacity - (size - next_entry),
- size - next_entry, mode);
- iwl_print_event_log(priv, 0,
- next_entry, mode);
+ pos = iwl_print_event_log(priv,
+ capacity - (size - next_entry),
+ size - next_entry, mode,
+ pos, buf, bufsz);
+ pos = iwl_print_event_log(priv, 0,
+ next_entry, mode,
+ pos, buf, bufsz);
} else
- iwl_print_event_log(priv, next_entry - size,
- size, mode);
+ pos = iwl_print_event_log(priv, next_entry - size,
+ size, mode, pos, buf, bufsz);
} else {
- if (next_entry < size)
- iwl_print_event_log(priv, 0, next_entry, mode);
- else
- iwl_print_event_log(priv, next_entry - size,
- size, mode);
+ if (next_entry < size) {
+ pos = iwl_print_event_log(priv, 0, next_entry,
+ mode, pos, buf, bufsz);
+ } else {
+ pos = iwl_print_event_log(priv, next_entry - size,
+ size, mode, pos, buf, bufsz);
+ }
}
+ return pos;
}
/* For sanity check only. Actual size is determined by uCode, typ. 512 */
@@ -1794,7 +1962,8 @@ static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
-void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
+int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+ char **buf, bool display)
{
u32 base; /* SRAM byte address of event log header */
u32 capacity; /* event log capacity in # entries */
@@ -1802,6 +1971,8 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
u32 num_wraps; /* # times uCode wrapped to top of log */
u32 next_entry; /* index of next entry to be written by uCode */
u32 size; /* # entries that we'll print */
+ int pos = 0;
+ size_t bufsz = 0;
if (priv->ucode_type == UCODE_INIT)
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
@@ -1812,7 +1983,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
IWL_ERR(priv,
"Invalid event log pointer 0x%08X for %s uCode\n",
base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT");
- return;
+ return -EINVAL;
}
/* event log header */
@@ -1838,7 +2009,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
/* bail out if nothing in log */
if (size == 0) {
IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
- return;
+ return pos;
}
#ifdef CONFIG_IWLWIFI_DEBUG
@@ -1853,6 +2024,15 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
size);
#ifdef CONFIG_IWLWIFI_DEBUG
+ if (display) {
+ if (full_log)
+ bufsz = capacity * 48;
+ else
+ bufsz = size * 48;
+ *buf = kmalloc(bufsz, GFP_KERNEL);
+ if (!*buf)
+ return -ENOMEM;
+ }
if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
/*
* if uCode has wrapped back to top of log,
@@ -1860,17 +2040,22 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
* i.e the next one that uCode would fill.
*/
if (num_wraps)
- iwl_print_event_log(priv, next_entry,
- capacity - next_entry, mode);
+ pos = iwl_print_event_log(priv, next_entry,
+ capacity - next_entry, mode,
+ pos, buf, bufsz);
/* (then/else) start at top of log */
- iwl_print_event_log(priv, 0, next_entry, mode);
+ pos = iwl_print_event_log(priv, 0,
+ next_entry, mode, pos, buf, bufsz);
} else
- iwl_print_last_event_logs(priv, capacity, num_wraps,
- next_entry, size, mode);
+ pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
+ next_entry, size, mode,
+ pos, buf, bufsz);
#else
- iwl_print_last_event_logs(priv, capacity, num_wraps,
- next_entry, size, mode);
+ pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
+ next_entry, size, mode,
+ pos, buf, bufsz);
#endif
+ return pos;
}
/**
@@ -2276,18 +2461,6 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
return;
}
-static void iwl_bg_up(struct work_struct *data)
-{
- struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- mutex_lock(&priv->mutex);
- __iwl_up(priv);
- mutex_unlock(&priv->mutex);
-}
-
static void iwl_bg_restart(struct work_struct *data)
{
struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
@@ -2304,7 +2477,13 @@ static void iwl_bg_restart(struct work_struct *data)
ieee80211_restart_hw(priv->hw);
} else {
iwl_down(priv);
- queue_work(priv->workqueue, &priv->up);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ __iwl_up(priv);
+ mutex_unlock(&priv->mutex);
}
}
@@ -2440,7 +2619,7 @@ void iwl_post_associate(struct iwl_priv *priv)
* Not a mac80211 entry point function, but it fits in with all the
* other mac80211 functions grouped here.
*/
-static int iwl_setup_mac(struct iwl_priv *priv)
+static int iwl_mac_setup_register(struct iwl_priv *priv)
{
int ret;
struct ieee80211_hw *hw = priv->hw;
@@ -2456,6 +2635,10 @@ static int iwl_setup_mac(struct iwl_priv *priv)
hw->flags |= IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+ if (priv->cfg->sku & IWL_SKU_N)
+ hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
+ IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+
hw->sta_data_size = sizeof(struct iwl_station_priv);
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
@@ -2506,21 +2689,7 @@ static int iwl_mac_start(struct ieee80211_hw *hw)
/* we should be verifying the device is ready to be opened */
mutex_lock(&priv->mutex);
-
- /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
- * ucode filename and max sizes are card-specific. */
-
- if (!priv->ucode_code.len) {
- ret = iwl_read_ucode(priv);
- if (ret) {
- IWL_ERR(priv, "Could not read microcode: %d\n", ret);
- mutex_unlock(&priv->mutex);
- return ret;
- }
- }
-
ret = __iwl_up(priv);
-
mutex_unlock(&priv->mutex);
if (ret)
@@ -2668,14 +2837,18 @@ void iwl_config_ap(struct iwl_priv *priv)
}
static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
- struct ieee80211_key_conf *keyconf, const u8 *addr,
- u32 iv32, u16 *phase1key)
+ struct ieee80211_vif *vif,
+ struct ieee80211_key_conf *keyconf,
+ struct ieee80211_sta *sta,
+ u32 iv32, u16 *phase1key)
{
struct iwl_priv *priv = hw->priv;
IWL_DEBUG_MAC80211(priv, "enter\n");
- iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key);
+ iwl_update_tkip_key(priv, keyconf,
+ sta ? sta->addr : iwl_bcast_addr,
+ iv32, phase1key);
IWL_DEBUG_MAC80211(priv, "leave\n");
}
@@ -2784,6 +2957,9 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
return 0;
else
return ret;
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+ /* do nothing */
+ return -EOPNOTSUPP;
default:
IWL_DEBUG_HT(priv, "unknown\n");
return -EINVAL;
@@ -2833,6 +3009,8 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
break;
case STA_NOTIFY_AWAKE:
WARN_ON(!sta_priv->client);
+ if (!sta_priv->asleep)
+ break;
sta_priv->asleep = false;
sta_id = iwl_find_station(priv, sta->addr);
if (sta_id != IWL_INVALID_STATION)
@@ -3109,7 +3287,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
init_waitqueue_head(&priv->wait_command_queue);
- INIT_WORK(&priv->up, iwl_bg_up);
INIT_WORK(&priv->restart, iwl_bg_restart);
INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
@@ -3126,6 +3303,10 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
priv->statistics_periodic.data = (unsigned long)priv;
priv->statistics_periodic.function = iwl_bg_statistics_periodic;
+ init_timer(&priv->ucode_trace);
+ priv->ucode_trace.data = (unsigned long)priv;
+ priv->ucode_trace.function = iwl_bg_ucode_trace;
+
if (!priv->cfg->use_isr_legacy)
tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
iwl_irq_tasklet, (unsigned long)priv);
@@ -3144,6 +3325,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
cancel_delayed_work(&priv->alive_start);
cancel_work_sync(&priv->beacon_update);
del_timer_sync(&priv->statistics_periodic);
+ del_timer_sync(&priv->ucode_trace);
}
static void iwl_init_hw_rates(struct iwl_priv *priv,
@@ -3179,6 +3361,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
INIT_LIST_HEAD(&priv->free_frames);
mutex_init(&priv->mutex);
+ mutex_init(&priv->sync_cmd_mutex);
/* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv);
@@ -3188,6 +3371,14 @@ static int iwl_init_drv(struct iwl_priv *priv)
priv->band = IEEE80211_BAND_2GHZ;
priv->iw_mode = NL80211_IFTYPE_STATION;
+ priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
+ priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
+
+ /* initialize force reset */
+ priv->force_reset[IWL_RF_RESET].reset_duration =
+ IWL_DELAY_NEXT_FORCE_RF_RESET;
+ priv->force_reset[IWL_FW_RESET].reset_duration =
+ IWL_DELAY_NEXT_FORCE_FW_RELOAD;
/* Choose which receivers/antennas to use */
if (priv->cfg->ops->hcmd->set_rxon_chain)
@@ -3264,7 +3455,6 @@ static struct ieee80211_ops iwl_hw_ops = {
.set_key = iwl_mac_set_key,
.update_tkip_key = iwl_mac_update_tkip_key,
.get_stats = iwl_mac_get_stats,
- .get_tx_stats = iwl_mac_get_tx_stats,
.conf_tx = iwl_mac_conf_tx,
.reset_tsf = iwl_mac_reset_tsf,
.bss_info_changed = iwl_bss_info_changed,
@@ -3365,6 +3555,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
spin_lock_init(&priv->reg_lock);
spin_lock_init(&priv->lock);
+
+ /*
+ * stop and reset the on-board processor just in case it is in a
+ * strange state ... like being left stranded by a primary kernel
+ * and this is now the kdump kernel trying to start up
+ */
+ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
iwl_hw_detect(priv);
IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n",
priv->cfg->name, priv->hw_rev);
@@ -3439,9 +3637,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
iwl_setup_deferred_work(priv);
iwl_setup_rx_handlers(priv);
- /**********************************
- * 8. Setup and register mac80211
- **********************************/
+ /*********************************************
+ * 8. Enable interrupts and read RFKILL state
+ *********************************************/
/* enable interrupts if needed: hw bug w/a */
pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd);
@@ -3452,14 +3650,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
iwl_enable_interrupts(priv);
- err = iwl_setup_mac(priv);
- if (err)
- goto out_remove_sysfs;
-
- err = iwl_dbgfs_register(priv, DRV_NAME);
- if (err)
- IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
-
/* If platform's RF_KILL switch is NOT set to KILL */
if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
clear_bit(STATUS_RF_KILL_HW, &priv->status);
@@ -3471,6 +3661,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
iwl_power_initialize(priv);
iwl_tt_initialize(priv);
+
+ err = iwl_request_firmware(priv, true);
+ if (err)
+ goto out_remove_sysfs;
+
return 0;
out_remove_sysfs:
@@ -3589,7 +3784,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
*****************************************************************************/
/* Hardware specific file defines the PCI IDs table for that hardware module */
-static struct pci_device_id iwl_hw_card_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
#ifdef CONFIG_IWL4965
{IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
{IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index 95a57b36a7ea..845831ac053e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -414,7 +414,6 @@ static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
static int iwl_sensitivity_write(struct iwl_priv *priv)
{
- int ret = 0;
struct iwl_sensitivity_cmd cmd ;
struct iwl_sensitivity_data *data = NULL;
struct iwl_host_cmd cmd_out = {
@@ -477,11 +476,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
sizeof(u16)*HD_TABLE_SIZE);
- ret = iwl_send_cmd(priv, &cmd_out);
- if (ret)
- IWL_ERR(priv, "SENSITIVITY_CMD failed\n");
-
- return ret;
+ return iwl_send_cmd(priv, &cmd_out);
}
void iwl_init_sensitivity(struct iwl_priv *priv)
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h
index b6cef989a796..2b7b1df83ba0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.h
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index e91507531923..6383d9f8c9b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -120,7 +120,6 @@ enum {
CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
/* 802.11h related */
- RADAR_NOTIFICATION = 0x70, /* not used */
REPLY_QUIET_CMD = 0x71, /* not used */
REPLY_CHANNEL_SWITCH = 0x72,
CHANNEL_SWITCH_NOTIFICATION = 0x73,
@@ -2248,10 +2247,22 @@ struct iwl_link_quality_cmd {
__le32 reserved2;
} __attribute__ ((packed));
+/*
+ * BT configuration enable flags:
+ * bit 0 - 1: BT channel announcement enabled
+ * 0: disable
+ * bit 1 - 1: priority of BT device enabled
+ * 0: disable
+ * bit 2 - 1: BT 2 wire support enabled
+ * 0: disable
+ */
+#define BT_COEX_DISABLE (0x0)
+#define BT_ENABLE_CHANNEL_ANNOUNCE BIT(0)
+#define BT_ENABLE_PRIORITY BIT(1)
+#define BT_ENABLE_2_WIRE BIT(2)
+
#define BT_COEX_DISABLE (0x0)
-#define BT_COEX_MODE_2W (0x1)
-#define BT_COEX_MODE_3W (0x2)
-#define BT_COEX_MODE_4W (0x3)
+#define BT_COEX_ENABLE (BT_ENABLE_CHANNEL_ANNOUNCE | BT_ENABLE_PRIORITY)
#define BT_LEAD_TIME_MIN (0x0)
#define BT_LEAD_TIME_DEF (0x1E)
@@ -2510,7 +2521,7 @@ struct iwl_card_state_notif {
#define HW_CARD_DISABLED 0x01
#define SW_CARD_DISABLED 0x02
-#define RF_CARD_DISABLED 0x04
+#define CT_CARD_DISABLED 0x04
#define RXON_CARD_DISABLED 0x10
struct iwl_ct_kill_config {
@@ -2612,6 +2623,7 @@ struct iwl_ssid_ie {
#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF)
#define IWL_GOOD_CRC_TH cpu_to_le16(1)
#define IWL_MAX_SCAN_SIZE 1024
+#define IWL_MAX_CMD_SIZE 4096
#define IWL_MAX_PROBE_REQUEST 200
/*
@@ -2984,7 +2996,7 @@ struct statistics_rx_ht_phy {
__le32 agg_crc32_good;
__le32 agg_mpdu_cnt;
__le32 agg_cnt;
- __le32 reserved2;
+ __le32 unsupport_mcs;
} __attribute__ ((packed));
#define INTERFERENCE_DATA_AVAILABLE cpu_to_le32(1)
@@ -3087,8 +3099,8 @@ struct statistics_div {
} __attribute__ ((packed));
struct statistics_general {
- __le32 temperature;
- __le32 temperature_m;
+ __le32 temperature; /* radio temperature */
+ __le32 temperature_m; /* for 5000 and up, this is radio voltage */
struct statistics_dbg dbg;
__le32 sleep_time;
__le32 slots_out;
@@ -3096,7 +3108,12 @@ struct statistics_general {
__le32 ttl_timestamp;
struct statistics_div div;
__le32 rx_enable_counter;
- __le32 reserved1;
+ /*
+ * num_of_sos_states:
+ * count the number of times we have to re-tune
+ * in order to get out of bad PHY status
+ */
+ __le32 num_of_sos_states;
__le32 reserved2;
__le32 reserved3;
} __attribute__ ((packed));
@@ -3161,13 +3178,30 @@ struct iwl_notif_statistics {
/*
* MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
+ *
+ * uCode send MISSED_BEACONS_NOTIFICATION to driver when detect beacon missed
+ * in regardless of how many missed beacons, which mean when driver receive the
+ * notification, inside the command, it can find all the beacons information
+ * which include number of total missed beacons, number of consecutive missed
+ * beacons, number of beacons received and number of beacons expected to
+ * receive.
+ *
+ * If uCode detected consecutive_missed_beacons > 5, it will reset the radio
+ * in order to bring the radio/PHY back to working state; which has no relation
+ * to when driver will perform sensitivity calibration.
+ *
+ * Driver should set it own missed_beacon_threshold to decide when to perform
+ * sensitivity calibration based on number of consecutive missed beacons in
+ * order to improve overall performance, especially in noisy environment.
+ *
*/
-/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row,
- * then this notification will be sent. */
-#define CONSECUTIVE_MISSED_BCONS_TH 20
+
+#define IWL_MISSED_BEACON_THRESHOLD_MIN (1)
+#define IWL_MISSED_BEACON_THRESHOLD_DEF (5)
+#define IWL_MISSED_BEACON_THRESHOLD_MAX IWL_MISSED_BEACON_THRESHOLD_DEF
struct iwl_missed_beacon_notif {
- __le32 consequtive_missed_beacons;
+ __le32 consecutive_missed_beacons;
__le32 total_missed_becons;
__le32 num_expected_beacons;
__le32 num_recvd_beacons;
@@ -3437,11 +3471,7 @@ enum {
IWL_PHY_CALIBRATE_DIFF_GAIN_CMD = 7,
IWL_PHY_CALIBRATE_DC_CMD = 8,
IWL_PHY_CALIBRATE_LO_CMD = 9,
- IWL_PHY_CALIBRATE_RX_BB_CMD = 10,
IWL_PHY_CALIBRATE_TX_IQ_CMD = 11,
- IWL_PHY_CALIBRATE_RX_IQ_CMD = 12,
- IWL_PHY_CALIBRATION_NOISE_CMD = 13,
- IWL_PHY_CALIBRATE_AGC_TABLE_CMD = 14,
IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15,
IWL_PHY_CALIBRATE_BASE_BAND_CMD = 16,
IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17,
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 5461f105bd2d..112149e9b31e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -47,6 +47,26 @@ MODULE_VERSION(IWLWIFI_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");
+/*
+ * set bt_coex_active to true, uCode will do kill/defer
+ * every time the priority line is asserted (BT is sending signals on the
+ * priority line in the PCIx).
+ * set bt_coex_active to false, uCode will ignore the BT activity and
+ * perform the normal operation
+ *
+ * User might experience transmit issue on some platform due to WiFi/BT
+ * co-exist problem. The possible behaviors are:
+ * Able to scan and finding all the available AP
+ * Not able to associate with any AP
+ * On those platforms, WiFi communication can be restored by set
+ * "bt_coex_active" module parameter to "false"
+ *
+ * default: bt_coex_active = true (BT_COEX_ENABLE)
+ */
+static bool bt_coex_active = true;
+module_param(bt_coex_active, bool, S_IRUGO);
+MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist\n");
+
static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
{COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
0, COEX_UNASSOC_IDLE_FLAGS},
@@ -257,8 +277,8 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
spin_lock_irqsave(&priv->lock, flags);
priv->cfg->ops->lib->apm_ops.init(priv);
- /* Set interrupt coalescing timer to 512 usecs */
- iwl_write8(priv, CSR_INT_COALESCING, 512 / 32);
+ /* Set interrupt coalescing calibration timer to default (512 usecs) */
+ iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -450,8 +470,6 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
if (priv->cfg->ht_greenfield_support)
ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
- ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
- (priv->cfg->sm_ps_mode << 2));
max_bit_rate = MAX_BIT_RATE_20_MHZ;
if (priv->hw_params.ht40_channel & BIT(band)) {
ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
@@ -636,7 +654,7 @@ EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag);
static bool is_single_rx_stream(struct iwl_priv *priv)
{
- return !priv->current_ht_config.is_ht ||
+ return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||
priv->current_ht_config.single_chain_sufficient;
}
@@ -1003,28 +1021,18 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
*/
static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
{
- int idle_cnt = active_cnt;
- bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
-
- /* # Rx chains when idling and maybe trying to save power */
- switch (priv->cfg->sm_ps_mode) {
- case WLAN_HT_CAP_SM_PS_STATIC:
- idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE;
- break;
- case WLAN_HT_CAP_SM_PS_DYNAMIC:
- idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
- IWL_NUM_IDLE_CHAINS_SINGLE;
- break;
- case WLAN_HT_CAP_SM_PS_DISABLED:
- break;
- case WLAN_HT_CAP_SM_PS_INVALID:
+ /* # Rx chains when idling, depending on SMPS mode */
+ switch (priv->current_ht_config.smps) {
+ case IEEE80211_SMPS_STATIC:
+ case IEEE80211_SMPS_DYNAMIC:
+ return IWL_NUM_IDLE_CHAINS_SINGLE;
+ case IEEE80211_SMPS_OFF:
+ return active_cnt;
default:
- IWL_ERR(priv, "invalid sm_ps mode %u\n",
- priv->cfg->sm_ps_mode);
- WARN_ON(1);
- break;
+ WARN(1, "invalid SMPS mode %d",
+ priv->current_ht_config.smps);
+ return active_cnt;
}
- return idle_cnt;
}
/* up to 4 chains */
@@ -1363,7 +1371,11 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
priv->cfg->ops->lib->dump_nic_error_log(priv);
- priv->cfg->ops->lib->dump_nic_event_log(priv, false);
+ if (priv->cfg->ops->lib->dump_csr)
+ priv->cfg->ops->lib->dump_csr(priv);
+ if (priv->cfg->ops->lib->dump_fh)
+ priv->cfg->ops->lib->dump_fh(priv, NULL, false);
+ priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false);
#ifdef CONFIG_IWLWIFI_DEBUG
if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
iwl_print_rx_config_cmd(priv);
@@ -1658,9 +1670,9 @@ EXPORT_SYMBOL(iwl_set_tx_power);
void iwl_free_isr_ict(struct iwl_priv *priv)
{
if (priv->ict_tbl_vir) {
- pci_free_consistent(priv->pci_dev, (sizeof(u32) * ICT_COUNT) +
- PAGE_SIZE, priv->ict_tbl_vir,
- priv->ict_tbl_dma);
+ dma_free_coherent(&priv->pci_dev->dev,
+ (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
+ priv->ict_tbl_vir, priv->ict_tbl_dma);
priv->ict_tbl_vir = NULL;
}
}
@@ -1676,9 +1688,9 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv)
if (priv->cfg->use_isr_legacy)
return 0;
/* allocate shrared data table */
- priv->ict_tbl_vir = pci_alloc_consistent(priv->pci_dev, (sizeof(u32) *
- ICT_COUNT) + PAGE_SIZE,
- &priv->ict_tbl_dma);
+ priv->ict_tbl_vir = dma_alloc_coherent(&priv->pci_dev->dev,
+ (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
+ &priv->ict_tbl_dma, GFP_KERNEL);
if (!priv->ict_tbl_vir)
return -ENOMEM;
@@ -1813,6 +1825,16 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
if (val == 0xffffffff)
val = 0;
+ /*
+ * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
+ * (bit 15 before shifting it to 31) to clear when using interrupt
+ * coalescing. fortunately, bits 18 and 19 stay set when this happens
+ * so we use them to decide on the real state of the Rx bit.
+ * In order words, bit 15 is set if bit 18 or bit 19 are set.
+ */
+ if (val & 0xC0000)
+ val |= 0x8000;
+
inta = (0xff & val) | ((0xff00 & val) << 16);
IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
inta, inta_mask, val);
@@ -1975,13 +1997,20 @@ EXPORT_SYMBOL(iwl_isr_legacy);
int iwl_send_bt_config(struct iwl_priv *priv)
{
struct iwl_bt_cmd bt_cmd = {
- .flags = BT_COEX_MODE_4W,
.lead_time = BT_LEAD_TIME_DEF,
.max_kill = BT_MAX_KILL_DEF,
.kill_ack_mask = 0,
.kill_cts_mask = 0,
};
+ if (!bt_coex_active)
+ bt_cmd.flags = BT_COEX_DISABLE;
+ else
+ bt_cmd.flags = BT_COEX_ENABLE;
+
+ IWL_DEBUG_INFO(priv, "BT coex %s\n",
+ (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
+
return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
sizeof(struct iwl_bt_cmd), &bt_cmd);
}
@@ -2599,44 +2628,43 @@ int iwl_set_mode(struct iwl_priv *priv, int mode)
EXPORT_SYMBOL(iwl_set_mode);
int iwl_mac_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct iwl_priv *priv = hw->priv;
- unsigned long flags;
+ int err = 0;
- IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type);
+ IWL_DEBUG_MAC80211(priv, "enter: type %d\n", vif->type);
+
+ mutex_lock(&priv->mutex);
if (priv->vif) {
IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
- return -EOPNOTSUPP;
+ err = -EOPNOTSUPP;
+ goto out;
}
- spin_lock_irqsave(&priv->lock, flags);
- priv->vif = conf->vif;
- priv->iw_mode = conf->type;
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- mutex_lock(&priv->mutex);
+ priv->vif = vif;
+ priv->iw_mode = vif->type;
- if (conf->mac_addr) {
- IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr);
- memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+ if (vif->addr) {
+ IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr);
+ memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
}
- if (iwl_set_mode(priv, conf->type) == -EAGAIN)
+ if (iwl_set_mode(priv, vif->type) == -EAGAIN)
/* we are not ready, will run again when ready */
set_bit(STATUS_MODE_PENDING, &priv->status);
+ out:
mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
- return 0;
+ return err;
}
EXPORT_SYMBOL(iwl_mac_add_interface);
void iwl_mac_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct iwl_priv *priv = hw->priv;
@@ -2649,7 +2677,7 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
iwlcore_commit_rxon(priv);
}
- if (priv->vif == conf->vif) {
+ if (priv->vif == vif) {
priv->vif = NULL;
memset(priv->bssid, 0, ETH_ALEN);
}
@@ -2689,6 +2717,21 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
}
+ if (changed & (IEEE80211_CONF_CHANGE_SMPS |
+ IEEE80211_CONF_CHANGE_CHANNEL)) {
+ /* mac80211 uses static for non-HT which is what we want */
+ priv->current_ht_config.smps = conf->smps_mode;
+
+ /*
+ * Recalculate chain counts.
+ *
+ * If monitor mode is enabled then mac80211 will
+ * set up the SM PS mode to OFF if an HT channel is
+ * configured.
+ */
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv);
+ }
/* during scanning mac80211 will delay channel setting until
* scan finish with changed = 0
@@ -2745,6 +2788,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
priv->staging_rxon.flags = 0;
iwl_set_rxon_channel(priv, conf->channel);
+ iwl_set_rxon_ht(priv, ht_conf);
iwl_set_flags_for_band(priv, conf->channel->band);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -2785,10 +2829,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
iwl_set_tx_power(priv, conf->power_level, false);
}
- /* call to ensure that 4965 rx_chain is set properly in monitor mode */
- if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv);
-
if (!iwl_is_ready(priv)) {
IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
goto out;
@@ -2811,42 +2851,6 @@ out:
}
EXPORT_SYMBOL(iwl_mac_config);
-int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct iwl_priv *priv = hw->priv;
- int i, avail;
- struct iwl_tx_queue *txq;
- struct iwl_queue *q;
- unsigned long flags;
-
- IWL_DEBUG_MAC80211(priv, "enter\n");
-
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- for (i = 0; i < AC_NUM; i++) {
- txq = &priv->txq[i];
- q = &txq->q;
- avail = iwl_queue_space(q);
-
- stats[i].len = q->n_window - avail;
- stats[i].limit = q->n_window - q->high_mark;
- stats[i].count = q->n_window;
-
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
-
- return 0;
-}
-EXPORT_SYMBOL(iwl_mac_get_tx_stats);
-
void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
@@ -3196,6 +3200,207 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
EXPORT_SYMBOL(iwl_update_stats);
#endif
+const static char *get_csr_string(int cmd)
+{
+ switch (cmd) {
+ IWL_CMD(CSR_HW_IF_CONFIG_REG);
+ IWL_CMD(CSR_INT_COALESCING);
+ IWL_CMD(CSR_INT);
+ IWL_CMD(CSR_INT_MASK);
+ IWL_CMD(CSR_FH_INT_STATUS);
+ IWL_CMD(CSR_GPIO_IN);
+ IWL_CMD(CSR_RESET);
+ IWL_CMD(CSR_GP_CNTRL);
+ IWL_CMD(CSR_HW_REV);
+ IWL_CMD(CSR_EEPROM_REG);
+ IWL_CMD(CSR_EEPROM_GP);
+ IWL_CMD(CSR_OTP_GP_REG);
+ IWL_CMD(CSR_GIO_REG);
+ IWL_CMD(CSR_GP_UCODE_REG);
+ IWL_CMD(CSR_GP_DRIVER_REG);
+ IWL_CMD(CSR_UCODE_DRV_GP1);
+ IWL_CMD(CSR_UCODE_DRV_GP2);
+ IWL_CMD(CSR_LED_REG);
+ IWL_CMD(CSR_DRAM_INT_TBL_REG);
+ IWL_CMD(CSR_GIO_CHICKEN_BITS);
+ IWL_CMD(CSR_ANA_PLL_CFG);
+ IWL_CMD(CSR_HW_REV_WA_REG);
+ IWL_CMD(CSR_DBG_HPET_MEM_REG);
+ default:
+ return "UNKNOWN";
+
+ }
+}
+
+void iwl_dump_csr(struct iwl_priv *priv)
+{
+ int i;
+ u32 csr_tbl[] = {
+ CSR_HW_IF_CONFIG_REG,
+ CSR_INT_COALESCING,
+ CSR_INT,
+ CSR_INT_MASK,
+ CSR_FH_INT_STATUS,
+ CSR_GPIO_IN,
+ CSR_RESET,
+ CSR_GP_CNTRL,
+ CSR_HW_REV,
+ CSR_EEPROM_REG,
+ CSR_EEPROM_GP,
+ CSR_OTP_GP_REG,
+ CSR_GIO_REG,
+ CSR_GP_UCODE_REG,
+ CSR_GP_DRIVER_REG,
+ CSR_UCODE_DRV_GP1,
+ CSR_UCODE_DRV_GP2,
+ CSR_LED_REG,
+ CSR_DRAM_INT_TBL_REG,
+ CSR_GIO_CHICKEN_BITS,
+ CSR_ANA_PLL_CFG,
+ CSR_HW_REV_WA_REG,
+ CSR_DBG_HPET_MEM_REG
+ };
+ IWL_ERR(priv, "CSR values:\n");
+ IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is "
+ "CSR_INT_PERIODIC_REG)\n");
+ for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) {
+ IWL_ERR(priv, " %25s: 0X%08x\n",
+ get_csr_string(csr_tbl[i]),
+ iwl_read32(priv, csr_tbl[i]));
+ }
+}
+EXPORT_SYMBOL(iwl_dump_csr);
+
+const static char *get_fh_string(int cmd)
+{
+ switch (cmd) {
+ IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
+ IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
+ IWL_CMD(FH_RSCSR_CHNL0_WPTR);
+ IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
+ IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
+ IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
+ IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
+ IWL_CMD(FH_TSSR_TX_STATUS_REG);
+ IWL_CMD(FH_TSSR_TX_ERROR_REG);
+ default:
+ return "UNKNOWN";
+
+ }
+}
+
+int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
+{
+ int i;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ int pos = 0;
+ size_t bufsz = 0;
+#endif
+ u32 fh_tbl[] = {
+ FH_RSCSR_CHNL0_STTS_WPTR_REG,
+ FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+ FH_RSCSR_CHNL0_WPTR,
+ FH_MEM_RCSR_CHNL0_CONFIG_REG,
+ FH_MEM_RSSR_SHARED_CTRL_REG,
+ FH_MEM_RSSR_RX_STATUS_REG,
+ FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
+ FH_TSSR_TX_STATUS_REG,
+ FH_TSSR_TX_ERROR_REG
+ };
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (display) {
+ bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
+ *buf = kmalloc(bufsz, GFP_KERNEL);
+ if (!*buf)
+ return -ENOMEM;
+ pos += scnprintf(*buf + pos, bufsz - pos,
+ "FH register values:\n");
+ for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
+ pos += scnprintf(*buf + pos, bufsz - pos,
+ " %34s: 0X%08x\n",
+ get_fh_string(fh_tbl[i]),
+ iwl_read_direct32(priv, fh_tbl[i]));
+ }
+ return pos;
+ }
+#endif
+ IWL_ERR(priv, "FH register values:\n");
+ for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
+ IWL_ERR(priv, " %34s: 0X%08x\n",
+ get_fh_string(fh_tbl[i]),
+ iwl_read_direct32(priv, fh_tbl[i]));
+ }
+ return 0;
+}
+EXPORT_SYMBOL(iwl_dump_fh);
+
+static void iwl_force_rf_reset(struct iwl_priv *priv)
+{
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (!iwl_is_associated(priv)) {
+ IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
+ return;
+ }
+ /*
+ * There is no easy and better way to force reset the radio,
+ * the only known method is switching channel which will force to
+ * reset and tune the radio.
+ * Use internal short scan (single channel) operation to should
+ * achieve this objective.
+ * Driver should reset the radio when number of consecutive missed
+ * beacon, or any other uCode error condition detected.
+ */
+ IWL_DEBUG_INFO(priv, "perform radio reset.\n");
+ iwl_internal_short_hw_scan(priv);
+ return;
+}
+
+
+int iwl_force_reset(struct iwl_priv *priv, int mode)
+{
+ struct iwl_force_reset *force_reset;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return -EINVAL;
+
+ if (mode >= IWL_MAX_FORCE_RESET) {
+ IWL_DEBUG_INFO(priv, "invalid reset request.\n");
+ return -EINVAL;
+ }
+ force_reset = &priv->force_reset[mode];
+ force_reset->reset_request_count++;
+ if (force_reset->last_force_reset_jiffies &&
+ time_after(force_reset->last_force_reset_jiffies +
+ force_reset->reset_duration, jiffies)) {
+ IWL_DEBUG_INFO(priv, "force reset rejected\n");
+ force_reset->reset_reject_count++;
+ return -EAGAIN;
+ }
+ force_reset->reset_success_count++;
+ force_reset->last_force_reset_jiffies = jiffies;
+ IWL_DEBUG_INFO(priv, "perform force reset (%d)\n", mode);
+ switch (mode) {
+ case IWL_RF_RESET:
+ iwl_force_rf_reset(priv);
+ break;
+ case IWL_FW_RESET:
+ IWL_ERR(priv, "On demand firmware reload\n");
+ /* Set the FW error flag -- cleared on iwl_down */
+ set_bit(STATUS_FW_ERROR, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
+ /*
+ * Keep the restart process from trying to send host
+ * commands by clearing the INIT status bit
+ */
+ clear_bit(STATUS_READY, &priv->status);
+ queue_work(priv->workqueue, &priv->restart);
+ break;
+ }
+ return 0;
+}
+
#ifdef CONFIG_PM
int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 27ca859e7453..4ef7739f9e8e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,8 +63,6 @@
#ifndef __iwl_core_h__
#define __iwl_core_h__
-#include <generated/utsrelease.h>
-
/************************
* forward declarations *
************************/
@@ -72,8 +70,8 @@ struct iwl_host_cmd;
struct iwl_cmd;
-#define IWLWIFI_VERSION UTS_RELEASE "-k"
-#define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation"
+#define IWLWIFI_VERSION "in-tree:"
+#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation"
#define DRV_AUTHOR "<ilw@linux.intel.com>"
#define IWL_PCI_DEVICE(dev, subdev, cfg) \
@@ -119,6 +117,7 @@ struct iwl_apm_ops {
struct iwl_temp_ops {
void (*temperature)(struct iwl_priv *priv);
void (*set_ct_kill)(struct iwl_priv *priv);
+ void (*set_calib_version)(struct iwl_priv *priv);
};
struct iwl_ucode_ops {
@@ -169,8 +168,11 @@ struct iwl_lib_ops {
int (*is_valid_rtc_data_addr)(u32 addr);
/* 1st ucode load */
int (*load_ucode)(struct iwl_priv *priv);
- void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log);
+ int (*dump_nic_event_log)(struct iwl_priv *priv,
+ bool full_log, char **buf, bool display);
void (*dump_nic_error_log)(struct iwl_priv *priv);
+ void (*dump_csr)(struct iwl_priv *priv);
+ int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display);
int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
/* power management */
struct iwl_apm_ops apm_ops;
@@ -187,6 +189,8 @@ struct iwl_lib_ops {
/* temperature */
struct iwl_temp_ops temp_ops;
+ /* station management */
+ void (*add_bcast_station)(struct iwl_priv *priv);
};
struct iwl_led_ops {
@@ -230,8 +234,9 @@ struct iwl_mod_params {
* @chain_noise_num_beacons: number of beacons used to compute chain noise
* @adv_thermal_throttle: support advance thermal throttle
* @support_ct_kill_exit: support ct kill exit condition
- * @sm_ps_mode: spatial multiplexing power save mode
* @support_wimax_coexist: support wimax/wifi co-exist
+ * @plcp_delta_threshold: plcp error rate threshold used to trigger
+ * radio tuning when there is a high receiving plcp error rate
*
* We enable the driver to be backward compatible wrt API version. The
* driver specifies which APIs it supports (with @ucode_api_max being the
@@ -287,8 +292,9 @@ struct iwl_cfg {
const bool supports_idle;
bool adv_thermal_throttle;
bool support_ct_kill_exit;
- u8 sm_ps_mode;
const bool support_wimax_coexist;
+ u8 plcp_delta_threshold;
+ s32 chain_noise_scale;
};
/***************************
@@ -332,13 +338,11 @@ int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
int iwl_commit_rxon(struct iwl_priv *priv);
int iwl_set_mode(struct iwl_priv *priv, int mode);
int iwl_mac_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf);
+ struct ieee80211_vif *vif);
void iwl_mac_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf);
+ struct ieee80211_vif *vif);
int iwl_mac_config(struct ieee80211_hw *hw, u32 changed);
void iwl_config_ap(struct iwl_priv *priv);
-int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *stats);
void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
int iwl_alloc_txq_mem(struct iwl_priv *priv);
void iwl_free_txq_mem(struct iwl_priv *priv);
@@ -411,13 +415,13 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
void iwl_cmd_queue_free(struct iwl_priv *priv);
int iwl_rx_queue_alloc(struct iwl_priv *priv);
void iwl_rx_handle(struct iwl_priv *priv);
-int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
+void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
struct iwl_rx_queue *q);
void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
void iwl_rx_replenish(struct iwl_priv *priv);
void iwl_rx_replenish_now(struct iwl_priv *priv);
int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
-int iwl_rx_queue_restock(struct iwl_priv *priv);
+void iwl_rx_queue_restock(struct iwl_priv *priv);
int iwl_rx_queue_space(const struct iwl_rx_queue *q);
void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority);
void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
@@ -425,6 +429,8 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
/* Handlers */
void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
+void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb);
void iwl_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
void iwl_reply_statistics(struct iwl_priv *priv,
@@ -445,7 +451,9 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
int iwl_hw_tx_queue_init(struct iwl_priv *priv,
struct iwl_tx_queue *txq);
-int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+void iwl_free_tfds_in_queue(struct iwl_priv *priv,
+ int sta_id, int tid, int freed);
+void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
int slots_num, u32 txq_id);
void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
@@ -495,6 +503,8 @@ void iwl_init_scan_params(struct iwl_priv *priv);
int iwl_scan_cancel(struct iwl_priv *priv);
int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
+int iwl_internal_short_hw_scan(struct iwl_priv *priv);
+int iwl_force_reset(struct iwl_priv *priv, int mode);
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
const u8 *ie, int ie_len, int left);
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
@@ -525,14 +535,6 @@ int iwl_send_calib_results(struct iwl_priv *priv);
int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len);
void iwl_calib_free_results(struct iwl_priv *priv);
-/*******************************************************************************
- * Spectrum Measureemtns in iwl-spectrum.c
- ******************************************************************************/
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
-void iwl_setup_spectrum_handlers(struct iwl_priv *priv);
-#else
-static inline void iwl_setup_spectrum_handlers(struct iwl_priv *priv) {}
-#endif
/*****************************************************
* S e n d i n g H o s t C o m m a n d s *
*****************************************************/
@@ -581,7 +583,10 @@ int iwl_pci_resume(struct pci_dev *pdev);
* Error Handling Debugging
******************************************************/
void iwl_dump_nic_error_log(struct iwl_priv *priv);
-void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
+int iwl_dump_nic_event_log(struct iwl_priv *priv,
+ bool full_log, char **buf, bool display);
+void iwl_dump_csr(struct iwl_priv *priv);
+int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
#ifdef CONFIG_IWLWIFI_DEBUG
void iwl_print_rx_config_cmd(struct iwl_priv *priv);
#else
@@ -601,7 +606,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);
/*************** DRIVER STATUS FUNCTIONS *****/
#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
-#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */
+/* 1 is unused (used to be STATUS_HCMD_SYNC_ACTIVE) */
#define STATUS_INT_ENABLED 2
#define STATUS_RF_KILL_HW 3
#define STATUS_CT_KILL 4
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 1ec8cb4d5eae..808b7146bead 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -369,7 +369,7 @@
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_3x3_HYB (0x00000000)
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB (0x00000001)
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002)
-
+#define CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6 (0x00000004)
/* GIO Chicken Bits (PCI Express bus link power management) */
#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index d61293ab67c9..1c7b53d511c7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project.
*
@@ -67,57 +67,6 @@ do { \
DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
} while (0)
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-struct iwl_debugfs {
- const char *name;
- struct dentry *dir_drv;
- struct dentry *dir_data;
- struct dentry *dir_debug;
- struct dentry *dir_rf;
- struct dir_data_files {
- struct dentry *file_sram;
- struct dentry *file_nvm;
- struct dentry *file_stations;
- struct dentry *file_log_event;
- struct dentry *file_channels;
- struct dentry *file_status;
- struct dentry *file_interrupt;
- struct dentry *file_qos;
- struct dentry *file_thermal_throttling;
- struct dentry *file_led;
- struct dentry *file_disable_ht40;
- struct dentry *file_sleep_level_override;
- struct dentry *file_current_sleep_command;
- } dbgfs_data_files;
- struct dir_rf_files {
- struct dentry *file_disable_sensitivity;
- struct dentry *file_disable_chain_noise;
- struct dentry *file_disable_tx_power;
- } dbgfs_rf_files;
- struct dir_debug_files {
- struct dentry *file_rx_statistics;
- struct dentry *file_tx_statistics;
- struct dentry *file_traffic_log;
- struct dentry *file_rx_queue;
- struct dentry *file_tx_queue;
- struct dentry *file_ucode_rx_stats;
- struct dentry *file_ucode_tx_stats;
- struct dentry *file_ucode_general_stats;
- struct dentry *file_sensitivity;
- struct dentry *file_chain_noise;
- struct dentry *file_tx_power;
- struct dentry *file_power_save_status;
- struct dentry *file_clear_ucode_statistics;
- struct dentry *file_clear_traffic_statistics;
- } dbgfs_debug_files;
- u32 sram_offset;
- u32 sram_len;
-};
-
-int iwl_dbgfs_register(struct iwl_priv *priv, const char *name);
-void iwl_dbgfs_unregister(struct iwl_priv *priv);
-#endif
-
#else
#define IWL_DEBUG(__priv, level, fmt, args...)
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...)
@@ -126,9 +75,10 @@ static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
{}
#endif /* CONFIG_IWLWIFI_DEBUG */
-
-
-#ifndef CONFIG_IWLWIFI_DEBUGFS
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+int iwl_dbgfs_register(struct iwl_priv *priv, const char *name);
+void iwl_dbgfs_unregister(struct iwl_priv *priv);
+#else
static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
{
return 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 21e0f6699daf..7bf44f146799 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -41,43 +41,28 @@
#include "iwl-calib.h"
/* create and remove of files */
-#define DEBUGFS_ADD_DIR(name, parent) do { \
- dbgfs->dir_##name = debugfs_create_dir(#name, parent); \
- if (!(dbgfs->dir_##name)) \
- goto err; \
+#define DEBUGFS_ADD_FILE(name, parent, mode) do { \
+ if (!debugfs_create_file(#name, mode, parent, priv, \
+ &iwl_dbgfs_##name##_ops)) \
+ goto err; \
} while (0)
-#define DEBUGFS_ADD_FILE(name, parent, mode) do { \
- dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_file(#name, mode, \
- dbgfs->dir_##parent, priv, \
- &iwl_dbgfs_##name##_ops); \
- if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \
- goto err; \
+#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
+ struct dentry *__tmp; \
+ __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \
+ parent, ptr); \
+ if (IS_ERR(__tmp) || !__tmp) \
+ goto err; \
} while (0)
-#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
- dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \
- dbgfs->dir_##parent, ptr); \
- if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
- || !dbgfs->dbgfs_##parent##_files.file_##name) \
- goto err; \
+#define DEBUGFS_ADD_X32(name, parent, ptr) do { \
+ struct dentry *__tmp; \
+ __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR, \
+ parent, ptr); \
+ if (IS_ERR(__tmp) || !__tmp) \
+ goto err; \
} while (0)
-#define DEBUGFS_ADD_X32(name, parent, ptr) do { \
- dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_x32(#name, S_IRUSR, dbgfs->dir_##parent, ptr); \
- if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
- || !dbgfs->dbgfs_##parent##_files.file_##name) \
- goto err; \
-} while (0)
-
-#define DEBUGFS_REMOVE(name) do { \
- debugfs_remove(name); \
- name = NULL; \
-} while (0);
-
/* file operation */
#define DEBUGFS_READ_FUNC(name) \
static ssize_t iwl_dbgfs_##name##_read(struct file *file, \
@@ -125,7 +110,7 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
char *buf;
int pos = 0;
@@ -184,7 +169,7 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
char *buf;
int pos = 0;
int cnt;
@@ -232,28 +217,28 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
ssize_t ret;
int i;
int pos = 0;
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
size_t bufsz;
/* default is to dump the entire data segment */
- if (!priv->dbgfs->sram_offset && !priv->dbgfs->sram_len) {
- priv->dbgfs->sram_offset = 0x800000;
+ if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
+ priv->dbgfs_sram_offset = 0x800000;
if (priv->ucode_type == UCODE_INIT)
- priv->dbgfs->sram_len = priv->ucode_init_data.len;
+ priv->dbgfs_sram_len = priv->ucode_init_data.len;
else
- priv->dbgfs->sram_len = priv->ucode_data.len;
+ priv->dbgfs_sram_len = priv->ucode_data.len;
}
- bufsz = 30 + priv->dbgfs->sram_len * sizeof(char) * 10;
+ bufsz = 30 + priv->dbgfs_sram_len * sizeof(char) * 10;
buf = kmalloc(bufsz, GFP_KERNEL);
if (!buf)
return -ENOMEM;
pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
- priv->dbgfs->sram_len);
+ priv->dbgfs_sram_len);
pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
- priv->dbgfs->sram_offset);
- for (i = priv->dbgfs->sram_len; i > 0; i -= 4) {
- val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \
- priv->dbgfs->sram_len - i);
+ priv->dbgfs_sram_offset);
+ for (i = priv->dbgfs_sram_len; i > 0; i -= 4) {
+ val = iwl_read_targ_mem(priv, priv->dbgfs_sram_offset + \
+ priv->dbgfs_sram_len - i);
if (i < 4) {
switch (i) {
case 1:
@@ -293,11 +278,11 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file,
return -EFAULT;
if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
- priv->dbgfs->sram_offset = offset;
- priv->dbgfs->sram_len = len;
+ priv->dbgfs_sram_offset = offset;
+ priv->dbgfs_sram_len = len;
} else {
- priv->dbgfs->sram_offset = 0;
- priv->dbgfs->sram_len = 0;
+ priv->dbgfs_sram_offset = 0;
+ priv->dbgfs_sram_len = 0;
}
return count;
@@ -306,7 +291,7 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file,
static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
struct iwl_station_entry *station;
int max_sta = priv->hw_params.max_stations;
char *buf;
@@ -376,7 +361,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
loff_t *ppos)
{
ssize_t ret;
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
int pos = 0, ofs = 0, buf_size = 0;
const u8 *ptr;
char *buf;
@@ -420,6 +405,24 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
return ret;
}
+static ssize_t iwl_dbgfs_log_event_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ char *buf;
+ int pos = 0;
+ ssize_t ret = -ENOMEM;
+
+ ret = pos = priv->cfg->ops->lib->dump_nic_event_log(
+ priv, true, &buf, true);
+ if (buf) {
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ }
+ return ret;
+}
+
static ssize_t iwl_dbgfs_log_event_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
@@ -436,7 +439,8 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
if (sscanf(buf, "%d", &event_log_flag) != 1)
return -EFAULT;
if (event_log_flag == 1)
- priv->cfg->ops->lib->dump_nic_event_log(priv, true);
+ priv->cfg->ops->lib->dump_nic_event_log(priv, true,
+ NULL, false);
return count;
}
@@ -446,7 +450,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
struct ieee80211_channel *channels = NULL;
const struct ieee80211_supported_band *supp_band = NULL;
int pos = 0, i, bufsz = PAGE_SIZE;
@@ -519,15 +523,13 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
char buf[512];
int pos = 0;
const size_t bufsz = sizeof(buf);
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
test_bit(STATUS_HCMD_ACTIVE, &priv->status));
- pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_SYNC_ACTIVE: %d\n",
- test_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n",
test_bit(STATUS_INT_ENABLED, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
@@ -567,7 +569,7 @@ static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
int pos = 0;
int cnt = 0;
char *buf;
@@ -654,7 +656,7 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
int pos = 0, i;
char buf[256];
const size_t bufsz = sizeof(buf);
@@ -677,7 +679,7 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
int pos = 0;
char buf[256];
const size_t bufsz = sizeof(buf);
@@ -703,7 +705,7 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
struct iwl_tt_restriction *restriction;
char buf[100];
@@ -763,7 +765,7 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
char buf[100];
int pos = 0;
const size_t bufsz = sizeof(buf);
@@ -811,7 +813,9 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
priv->power_data.debug_sleep_level_override = value;
+ mutex_lock(&priv->mutex);
iwl_power_update_mode(priv, true);
+ mutex_unlock(&priv->mutex);
return count;
}
@@ -820,7 +824,7 @@ static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
char buf[10];
int pos, value;
const size_t bufsz = sizeof(buf);
@@ -838,7 +842,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
char buf[200];
int pos = 0, i;
const size_t bufsz = sizeof(buf);
@@ -859,7 +863,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
}
DEBUGFS_READ_WRITE_FILE_OPS(sram);
-DEBUGFS_WRITE_FILE_OPS(log_event);
+DEBUGFS_READ_WRITE_FILE_OPS(log_event);
DEBUGFS_READ_FILE_OPS(nvm);
DEBUGFS_READ_FILE_OPS(stations);
DEBUGFS_READ_FILE_OPS(channels);
@@ -976,7 +980,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
struct iwl_tx_queue *txq;
struct iwl_queue *q;
char *buf;
@@ -1022,7 +1026,7 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
struct iwl_rx_queue *rxq = &priv->rxq;
char buf[256];
int pos = 0;
@@ -1063,36 +1067,33 @@ static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf,
return p;
}
+static const char ucode_stats_header[] =
+ "%-32s current acumulative delta max\n";
+static const char ucode_stats_short_format[] =
+ " %-30s %10u\n";
+static const char ucode_stats_format[] =
+ " %-30s %10u %10u %10u %10u\n";
static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
int pos = 0;
char *buf;
- int bufsz = sizeof(struct statistics_rx_phy) * 20 +
- sizeof(struct statistics_rx_non_phy) * 20 +
- sizeof(struct statistics_rx_ht_phy) * 20 + 400;
+ int bufsz = sizeof(struct statistics_rx_phy) * 40 +
+ sizeof(struct statistics_rx_non_phy) * 40 +
+ sizeof(struct statistics_rx_ht_phy) * 40 + 400;
ssize_t ret;
- struct statistics_rx_phy *ofdm, *accum_ofdm;
- struct statistics_rx_phy *cck, *accum_cck;
+ struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
+ struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
struct statistics_rx_non_phy *general, *accum_general;
- struct statistics_rx_ht_phy *ht, *accum_ht;
+ struct statistics_rx_non_phy *delta_general, *max_general;
+ struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
if (!iwl_is_alive(priv))
return -EAGAIN;
- /* make request to uCode to retrieve statistics information */
- mutex_lock(&priv->mutex);
- ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
- mutex_unlock(&priv->mutex);
-
- if (ret) {
- IWL_ERR(priv,
- "Error sending statistics request: %zd\n", ret);
- return -EAGAIN;
- }
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf) {
IWL_ERR(priv, "Can not allocate Buffer\n");
@@ -1111,264 +1112,401 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
accum_cck = &priv->accum_statistics.rx.cck;
accum_general = &priv->accum_statistics.rx.general;
accum_ht = &priv->accum_statistics.rx.ofdm_ht;
+ delta_ofdm = &priv->delta_statistics.rx.ofdm;
+ delta_cck = &priv->delta_statistics.rx.cck;
+ delta_general = &priv->delta_statistics.rx.general;
+ delta_ht = &priv->delta_statistics.rx.ofdm_ht;
+ max_ofdm = &priv->max_delta.rx.ofdm;
+ max_cck = &priv->max_delta.rx.cck;
+ max_general = &priv->max_delta.rx.general;
+ max_ht = &priv->max_delta.rx.ofdm_ht;
+
pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
- pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n");
- pos += scnprintf(buf + pos, bufsz - pos,
- "\t\t\tcurrent\t\t\taccumulative\n");
- pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n",
- le32_to_cpu(ofdm->ina_cnt), accum_ofdm->ina_cnt);
- pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n",
- le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt);
- pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
- le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err);
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
- le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- "overrun_err:\t\t%u\t\t\t%u\n",
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
+ "Statistics_Rx - OFDM:");
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "ina_cnt:", le32_to_cpu(ofdm->ina_cnt),
+ accum_ofdm->ina_cnt,
+ delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "fina_cnt:",
+ le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
+ delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "plcp_err:",
+ le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
+ delta_ofdm->plcp_err, max_ofdm->plcp_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "crc32_err:",
+ le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
+ delta_ofdm->crc32_err, max_ofdm->crc32_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "overrun_err:",
le32_to_cpu(ofdm->overrun_err),
- accum_ofdm->overrun_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- "early_overrun_err:\t%u\t\t\t%u\n",
+ accum_ofdm->overrun_err,
+ delta_ofdm->overrun_err, max_ofdm->overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "early_overrun_err:",
le32_to_cpu(ofdm->early_overrun_err),
- accum_ofdm->early_overrun_err);
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
+ accum_ofdm->early_overrun_err,
+ delta_ofdm->early_overrun_err,
+ max_ofdm->early_overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "crc32_good:",
le32_to_cpu(ofdm->crc32_good),
- accum_ofdm->crc32_good);
- pos += scnprintf(buf + pos, bufsz - pos,
- "false_alarm_cnt:\t%u\t\t\t%u\n",
+ accum_ofdm->crc32_good,
+ delta_ofdm->crc32_good, max_ofdm->crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "false_alarm_cnt:",
le32_to_cpu(ofdm->false_alarm_cnt),
- accum_ofdm->false_alarm_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "fina_sync_err_cnt:\t%u\t\t\t%u\n",
+ accum_ofdm->false_alarm_cnt,
+ delta_ofdm->false_alarm_cnt,
+ max_ofdm->false_alarm_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "fina_sync_err_cnt:",
le32_to_cpu(ofdm->fina_sync_err_cnt),
- accum_ofdm->fina_sync_err_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "sfd_timeout:\t\t%u\t\t\t%u\n",
+ accum_ofdm->fina_sync_err_cnt,
+ delta_ofdm->fina_sync_err_cnt,
+ max_ofdm->fina_sync_err_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "sfd_timeout:",
le32_to_cpu(ofdm->sfd_timeout),
- accum_ofdm->sfd_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- "fina_timeout:\t\t%u\t\t\t%u\n",
+ accum_ofdm->sfd_timeout,
+ delta_ofdm->sfd_timeout,
+ max_ofdm->sfd_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "fina_timeout:",
le32_to_cpu(ofdm->fina_timeout),
- accum_ofdm->fina_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- "unresponded_rts:\t%u\t\t\t%u\n",
+ accum_ofdm->fina_timeout,
+ delta_ofdm->fina_timeout,
+ max_ofdm->fina_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "unresponded_rts:",
le32_to_cpu(ofdm->unresponded_rts),
- accum_ofdm->unresponded_rts);
- pos += scnprintf(buf + pos, bufsz - pos,
- "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n",
+ accum_ofdm->unresponded_rts,
+ delta_ofdm->unresponded_rts,
+ max_ofdm->unresponded_rts);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "rxe_frame_lmt_ovrun:",
le32_to_cpu(ofdm->rxe_frame_limit_overrun),
- accum_ofdm->rxe_frame_limit_overrun);
- pos += scnprintf(buf + pos, bufsz - pos,
- "sent_ack_cnt:\t\t%u\t\t\t%u\n",
+ accum_ofdm->rxe_frame_limit_overrun,
+ delta_ofdm->rxe_frame_limit_overrun,
+ max_ofdm->rxe_frame_limit_overrun);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "sent_ack_cnt:",
le32_to_cpu(ofdm->sent_ack_cnt),
- accum_ofdm->sent_ack_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "sent_cts_cnt:\t\t%u\t\t\t%u\n",
+ accum_ofdm->sent_ack_cnt,
+ delta_ofdm->sent_ack_cnt,
+ max_ofdm->sent_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "sent_cts_cnt:",
le32_to_cpu(ofdm->sent_cts_cnt),
- accum_ofdm->sent_cts_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "sent_ba_rsp_cnt:\t%u\t\t\t%u\n",
+ accum_ofdm->sent_cts_cnt,
+ delta_ofdm->sent_cts_cnt, max_ofdm->sent_cts_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "sent_ba_rsp_cnt:",
le32_to_cpu(ofdm->sent_ba_rsp_cnt),
- accum_ofdm->sent_ba_rsp_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "dsp_self_kill:\t\t%u\t\t\t%u\n",
+ accum_ofdm->sent_ba_rsp_cnt,
+ delta_ofdm->sent_ba_rsp_cnt,
+ max_ofdm->sent_ba_rsp_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "dsp_self_kill:",
le32_to_cpu(ofdm->dsp_self_kill),
- accum_ofdm->dsp_self_kill);
- pos += scnprintf(buf + pos, bufsz - pos,
- "mh_format_err:\t\t%u\t\t\t%u\n",
+ accum_ofdm->dsp_self_kill,
+ delta_ofdm->dsp_self_kill,
+ max_ofdm->dsp_self_kill);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "mh_format_err:",
le32_to_cpu(ofdm->mh_format_err),
- accum_ofdm->mh_format_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- "re_acq_main_rssi_sum:\t%u\t\t\t%u\n",
+ accum_ofdm->mh_format_err,
+ delta_ofdm->mh_format_err,
+ max_ofdm->mh_format_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "re_acq_main_rssi_sum:",
le32_to_cpu(ofdm->re_acq_main_rssi_sum),
- accum_ofdm->re_acq_main_rssi_sum);
-
- pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n");
- pos += scnprintf(buf + pos, bufsz - pos,
- "\t\t\tcurrent\t\t\taccumulative\n");
- pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n",
- le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt);
- pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n",
- le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt);
- pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
- le32_to_cpu(cck->plcp_err), accum_cck->plcp_err);
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
- le32_to_cpu(cck->crc32_err), accum_cck->crc32_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- "overrun_err:\t\t%u\t\t\t%u\n",
+ accum_ofdm->re_acq_main_rssi_sum,
+ delta_ofdm->re_acq_main_rssi_sum,
+ max_ofdm->re_acq_main_rssi_sum);
+
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
+ "Statistics_Rx - CCK:");
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "ina_cnt:",
+ le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
+ delta_cck->ina_cnt, max_cck->ina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "fina_cnt:",
+ le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
+ delta_cck->fina_cnt, max_cck->fina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "plcp_err:",
+ le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
+ delta_cck->plcp_err, max_cck->plcp_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "crc32_err:",
+ le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
+ delta_cck->crc32_err, max_cck->crc32_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "overrun_err:",
le32_to_cpu(cck->overrun_err),
- accum_cck->overrun_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- "early_overrun_err:\t%u\t\t\t%u\n",
+ accum_cck->overrun_err,
+ delta_cck->overrun_err, max_cck->overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "early_overrun_err:",
le32_to_cpu(cck->early_overrun_err),
- accum_cck->early_overrun_err);
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
- le32_to_cpu(cck->crc32_good), accum_cck->crc32_good);
- pos += scnprintf(buf + pos, bufsz - pos,
- "false_alarm_cnt:\t%u\t\t\t%u\n",
+ accum_cck->early_overrun_err,
+ delta_cck->early_overrun_err,
+ max_cck->early_overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "crc32_good:",
+ le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
+ delta_cck->crc32_good,
+ max_cck->crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "false_alarm_cnt:",
le32_to_cpu(cck->false_alarm_cnt),
- accum_cck->false_alarm_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "fina_sync_err_cnt:\t%u\t\t\t%u\n",
+ accum_cck->false_alarm_cnt,
+ delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "fina_sync_err_cnt:",
le32_to_cpu(cck->fina_sync_err_cnt),
- accum_cck->fina_sync_err_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "sfd_timeout:\t\t%u\t\t\t%u\n",
+ accum_cck->fina_sync_err_cnt,
+ delta_cck->fina_sync_err_cnt,
+ max_cck->fina_sync_err_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "sfd_timeout:",
le32_to_cpu(cck->sfd_timeout),
- accum_cck->sfd_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- "fina_timeout:\t\t%u\t\t\t%u\n",
+ accum_cck->sfd_timeout,
+ delta_cck->sfd_timeout, max_cck->sfd_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "fina_timeout:",
le32_to_cpu(cck->fina_timeout),
- accum_cck->fina_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- "unresponded_rts:\t%u\t\t\t%u\n",
+ accum_cck->fina_timeout,
+ delta_cck->fina_timeout, max_cck->fina_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "unresponded_rts:",
le32_to_cpu(cck->unresponded_rts),
- accum_cck->unresponded_rts);
- pos += scnprintf(buf + pos, bufsz - pos,
- "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n",
+ accum_cck->unresponded_rts,
+ delta_cck->unresponded_rts,
+ max_cck->unresponded_rts);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "rxe_frame_lmt_ovrun:",
le32_to_cpu(cck->rxe_frame_limit_overrun),
- accum_cck->rxe_frame_limit_overrun);
- pos += scnprintf(buf + pos, bufsz - pos,
- "sent_ack_cnt:\t\t%u\t\t\t%u\n",
+ accum_cck->rxe_frame_limit_overrun,
+ delta_cck->rxe_frame_limit_overrun,
+ max_cck->rxe_frame_limit_overrun);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "sent_ack_cnt:",
le32_to_cpu(cck->sent_ack_cnt),
- accum_cck->sent_ack_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "sent_cts_cnt:\t\t%u\t\t\t%u\n",
+ accum_cck->sent_ack_cnt,
+ delta_cck->sent_ack_cnt,
+ max_cck->sent_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "sent_cts_cnt:",
le32_to_cpu(cck->sent_cts_cnt),
- accum_cck->sent_cts_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "sent_ba_rsp_cnt:\t%u\t\t\t%u\n",
+ accum_cck->sent_cts_cnt,
+ delta_cck->sent_cts_cnt,
+ max_cck->sent_cts_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "sent_ba_rsp_cnt:",
le32_to_cpu(cck->sent_ba_rsp_cnt),
- accum_cck->sent_ba_rsp_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "dsp_self_kill:\t\t%u\t\t\t%u\n",
+ accum_cck->sent_ba_rsp_cnt,
+ delta_cck->sent_ba_rsp_cnt,
+ max_cck->sent_ba_rsp_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "dsp_self_kill:",
le32_to_cpu(cck->dsp_self_kill),
- accum_cck->dsp_self_kill);
- pos += scnprintf(buf + pos, bufsz - pos,
- "mh_format_err:\t\t%u\t\t\t%u\n",
+ accum_cck->dsp_self_kill,
+ delta_cck->dsp_self_kill,
+ max_cck->dsp_self_kill);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "mh_format_err:",
le32_to_cpu(cck->mh_format_err),
- accum_cck->mh_format_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- "re_acq_main_rssi_sum:\t%u\t\t\t%u\n",
+ accum_cck->mh_format_err,
+ delta_cck->mh_format_err, max_cck->mh_format_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "re_acq_main_rssi_sum:",
le32_to_cpu(cck->re_acq_main_rssi_sum),
- accum_cck->re_acq_main_rssi_sum);
-
- pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n");
- pos += scnprintf(buf + pos, bufsz - pos,
- "\t\t\tcurrent\t\t\taccumulative\n");
- pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts:\t\t%u\t\t\t%u\n",
+ accum_cck->re_acq_main_rssi_sum,
+ delta_cck->re_acq_main_rssi_sum,
+ max_cck->re_acq_main_rssi_sum);
+
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
+ "Statistics_Rx - GENERAL:");
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "bogus_cts:",
le32_to_cpu(general->bogus_cts),
- accum_general->bogus_cts);
- pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack:\t\t%u\t\t\t%u\n",
+ accum_general->bogus_cts,
+ delta_general->bogus_cts, max_general->bogus_cts);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "bogus_ack:",
le32_to_cpu(general->bogus_ack),
- accum_general->bogus_ack);
- pos += scnprintf(buf + pos, bufsz - pos,
- "non_bssid_frames:\t%u\t\t\t%u\n",
+ accum_general->bogus_ack,
+ delta_general->bogus_ack, max_general->bogus_ack);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "non_bssid_frames:",
le32_to_cpu(general->non_bssid_frames),
- accum_general->non_bssid_frames);
- pos += scnprintf(buf + pos, bufsz - pos,
- "filtered_frames:\t%u\t\t\t%u\n",
+ accum_general->non_bssid_frames,
+ delta_general->non_bssid_frames,
+ max_general->non_bssid_frames);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "filtered_frames:",
le32_to_cpu(general->filtered_frames),
- accum_general->filtered_frames);
- pos += scnprintf(buf + pos, bufsz - pos,
- "non_channel_beacons:\t%u\t\t\t%u\n",
+ accum_general->filtered_frames,
+ delta_general->filtered_frames,
+ max_general->filtered_frames);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "non_channel_beacons:",
le32_to_cpu(general->non_channel_beacons),
- accum_general->non_channel_beacons);
- pos += scnprintf(buf + pos, bufsz - pos,
- "channel_beacons:\t%u\t\t\t%u\n",
+ accum_general->non_channel_beacons,
+ delta_general->non_channel_beacons,
+ max_general->non_channel_beacons);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "channel_beacons:",
le32_to_cpu(general->channel_beacons),
- accum_general->channel_beacons);
- pos += scnprintf(buf + pos, bufsz - pos,
- "num_missed_bcon:\t%u\t\t\t%u\n",
+ accum_general->channel_beacons,
+ delta_general->channel_beacons,
+ max_general->channel_beacons);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "num_missed_bcon:",
le32_to_cpu(general->num_missed_bcon),
- accum_general->num_missed_bcon);
- pos += scnprintf(buf + pos, bufsz - pos,
- "adc_rx_saturation_time:\t%u\t\t\t%u\n",
+ accum_general->num_missed_bcon,
+ delta_general->num_missed_bcon,
+ max_general->num_missed_bcon);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "adc_rx_saturation_time:",
le32_to_cpu(general->adc_rx_saturation_time),
- accum_general->adc_rx_saturation_time);
- pos += scnprintf(buf + pos, bufsz - pos,
- "ina_detect_search_tm:\t%u\t\t\t%u\n",
+ accum_general->adc_rx_saturation_time,
+ delta_general->adc_rx_saturation_time,
+ max_general->adc_rx_saturation_time);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "ina_detect_search_tm:",
le32_to_cpu(general->ina_detection_search_time),
- accum_general->ina_detection_search_time);
- pos += scnprintf(buf + pos, bufsz - pos,
- "beacon_silence_rssi_a:\t%u\t\t\t%u\n",
+ accum_general->ina_detection_search_time,
+ delta_general->ina_detection_search_time,
+ max_general->ina_detection_search_time);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "beacon_silence_rssi_a:",
le32_to_cpu(general->beacon_silence_rssi_a),
- accum_general->beacon_silence_rssi_a);
- pos += scnprintf(buf + pos, bufsz - pos,
- "beacon_silence_rssi_b:\t%u\t\t\t%u\n",
+ accum_general->beacon_silence_rssi_a,
+ delta_general->beacon_silence_rssi_a,
+ max_general->beacon_silence_rssi_a);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "beacon_silence_rssi_b:",
le32_to_cpu(general->beacon_silence_rssi_b),
- accum_general->beacon_silence_rssi_b);
- pos += scnprintf(buf + pos, bufsz - pos,
- "beacon_silence_rssi_c:\t%u\t\t\t%u\n",
+ accum_general->beacon_silence_rssi_b,
+ delta_general->beacon_silence_rssi_b,
+ max_general->beacon_silence_rssi_b);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "beacon_silence_rssi_c:",
le32_to_cpu(general->beacon_silence_rssi_c),
- accum_general->beacon_silence_rssi_c);
- pos += scnprintf(buf + pos, bufsz - pos,
- "interference_data_flag:\t%u\t\t\t%u\n",
+ accum_general->beacon_silence_rssi_c,
+ delta_general->beacon_silence_rssi_c,
+ max_general->beacon_silence_rssi_c);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "interference_data_flag:",
le32_to_cpu(general->interference_data_flag),
- accum_general->interference_data_flag);
- pos += scnprintf(buf + pos, bufsz - pos,
- "channel_load:\t\t%u\t\t\t%u\n",
+ accum_general->interference_data_flag,
+ delta_general->interference_data_flag,
+ max_general->interference_data_flag);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "channel_load:",
le32_to_cpu(general->channel_load),
- accum_general->channel_load);
- pos += scnprintf(buf + pos, bufsz - pos,
- "dsp_false_alarms:\t%u\t\t\t%u\n",
+ accum_general->channel_load,
+ delta_general->channel_load,
+ max_general->channel_load);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "dsp_false_alarms:",
le32_to_cpu(general->dsp_false_alarms),
- accum_general->dsp_false_alarms);
- pos += scnprintf(buf + pos, bufsz - pos,
- "beacon_rssi_a:\t\t%u\t\t\t%u\n",
+ accum_general->dsp_false_alarms,
+ delta_general->dsp_false_alarms,
+ max_general->dsp_false_alarms);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "beacon_rssi_a:",
le32_to_cpu(general->beacon_rssi_a),
- accum_general->beacon_rssi_a);
- pos += scnprintf(buf + pos, bufsz - pos,
- "beacon_rssi_b:\t\t%u\t\t\t%u\n",
+ accum_general->beacon_rssi_a,
+ delta_general->beacon_rssi_a,
+ max_general->beacon_rssi_a);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "beacon_rssi_b:",
le32_to_cpu(general->beacon_rssi_b),
- accum_general->beacon_rssi_b);
- pos += scnprintf(buf + pos, bufsz - pos,
- "beacon_rssi_c:\t\t%u\t\t\t%u\n",
+ accum_general->beacon_rssi_b,
+ delta_general->beacon_rssi_b,
+ max_general->beacon_rssi_b);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "beacon_rssi_c:",
le32_to_cpu(general->beacon_rssi_c),
- accum_general->beacon_rssi_c);
- pos += scnprintf(buf + pos, bufsz - pos,
- "beacon_energy_a:\t%u\t\t\t%u\n",
+ accum_general->beacon_rssi_c,
+ delta_general->beacon_rssi_c,
+ max_general->beacon_rssi_c);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "beacon_energy_a:",
le32_to_cpu(general->beacon_energy_a),
- accum_general->beacon_energy_a);
- pos += scnprintf(buf + pos, bufsz - pos,
- "beacon_energy_b:\t%u\t\t\t%u\n",
+ accum_general->beacon_energy_a,
+ delta_general->beacon_energy_a,
+ max_general->beacon_energy_a);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "beacon_energy_b:",
le32_to_cpu(general->beacon_energy_b),
- accum_general->beacon_energy_b);
- pos += scnprintf(buf + pos, bufsz - pos,
- "beacon_energy_c:\t%u\t\t\t%u\n",
+ accum_general->beacon_energy_b,
+ delta_general->beacon_energy_b,
+ max_general->beacon_energy_b);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "beacon_energy_c:",
le32_to_cpu(general->beacon_energy_c),
- accum_general->beacon_energy_c);
+ accum_general->beacon_energy_c,
+ delta_general->beacon_energy_c,
+ max_general->beacon_energy_c);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n");
- pos += scnprintf(buf + pos, bufsz - pos,
- "\t\t\tcurrent\t\t\taccumulative\n");
- pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
- le32_to_cpu(ht->plcp_err), accum_ht->plcp_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- "overrun_err:\t\t%u\t\t\t%u\n",
- le32_to_cpu(ht->overrun_err), accum_ht->overrun_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- "early_overrun_err:\t%u\t\t\t%u\n",
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
+ "Statistics_Rx - OFDM_HT:");
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "plcp_err:",
+ le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
+ delta_ht->plcp_err, max_ht->plcp_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "overrun_err:",
+ le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
+ delta_ht->overrun_err, max_ht->overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "early_overrun_err:",
le32_to_cpu(ht->early_overrun_err),
- accum_ht->early_overrun_err);
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
- le32_to_cpu(ht->crc32_good), accum_ht->crc32_good);
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
- le32_to_cpu(ht->crc32_err), accum_ht->crc32_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- "mh_format_err:\t\t%u\t\t\t%u\n",
+ accum_ht->early_overrun_err,
+ delta_ht->early_overrun_err,
+ max_ht->early_overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "crc32_good:",
+ le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
+ delta_ht->crc32_good, max_ht->crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "crc32_err:",
+ le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
+ delta_ht->crc32_err, max_ht->crc32_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "mh_format_err:",
le32_to_cpu(ht->mh_format_err),
- accum_ht->mh_format_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg_crc32_good:\t\t%u\t\t\t%u\n",
+ accum_ht->mh_format_err,
+ delta_ht->mh_format_err, max_ht->mh_format_err);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "agg_crc32_good:",
le32_to_cpu(ht->agg_crc32_good),
- accum_ht->agg_crc32_good);
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg_mpdu_cnt:\t\t%u\t\t\t%u\n",
+ accum_ht->agg_crc32_good,
+ delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "agg_mpdu_cnt:",
le32_to_cpu(ht->agg_mpdu_cnt),
- accum_ht->agg_mpdu_cnt);
- pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n",
- le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt);
+ accum_ht->agg_mpdu_cnt,
+ delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "agg_cnt:",
+ le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
+ delta_ht->agg_cnt, max_ht->agg_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "unsupport_mcs:",
+ le32_to_cpu(ht->unsupport_mcs),
+ accum_ht->unsupport_mcs,
+ delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
@@ -1379,26 +1517,16 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
int pos = 0;
char *buf;
- int bufsz = (sizeof(struct statistics_tx) * 24) + 250;
+ int bufsz = (sizeof(struct statistics_tx) * 48) + 250;
ssize_t ret;
- struct statistics_tx *tx, *accum_tx;
+ struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
if (!iwl_is_alive(priv))
return -EAGAIN;
- /* make request to uCode to retrieve statistics information */
- mutex_lock(&priv->mutex);
- ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
- mutex_unlock(&priv->mutex);
-
- if (ret) {
- IWL_ERR(priv,
- "Error sending statistics request: %zd\n", ret);
- return -EAGAIN;
- }
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf) {
IWL_ERR(priv, "Can not allocate Buffer\n");
@@ -1411,106 +1539,148 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
*/
tx = &priv->statistics.tx;
accum_tx = &priv->accum_statistics.tx;
+ delta_tx = &priv->delta_statistics.tx;
+ max_tx = &priv->max_delta.tx;
pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
- pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n");
- pos += scnprintf(buf + pos, bufsz - pos,
- "\t\t\tcurrent\t\t\taccumulative\n");
- pos += scnprintf(buf + pos, bufsz - pos, "preamble:\t\t\t%u\t\t\t%u\n",
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
+ "Statistics_Tx:");
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "preamble:",
le32_to_cpu(tx->preamble_cnt),
- accum_tx->preamble_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "rx_detected_cnt:\t\t%u\t\t\t%u\n",
+ accum_tx->preamble_cnt,
+ delta_tx->preamble_cnt, max_tx->preamble_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "rx_detected_cnt:",
le32_to_cpu(tx->rx_detected_cnt),
- accum_tx->rx_detected_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "bt_prio_defer_cnt:\t\t%u\t\t\t%u\n",
+ accum_tx->rx_detected_cnt,
+ delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "bt_prio_defer_cnt:",
le32_to_cpu(tx->bt_prio_defer_cnt),
- accum_tx->bt_prio_defer_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "bt_prio_kill_cnt:\t\t%u\t\t\t%u\n",
+ accum_tx->bt_prio_defer_cnt,
+ delta_tx->bt_prio_defer_cnt,
+ max_tx->bt_prio_defer_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "bt_prio_kill_cnt:",
le32_to_cpu(tx->bt_prio_kill_cnt),
- accum_tx->bt_prio_kill_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "few_bytes_cnt:\t\t\t%u\t\t\t%u\n",
+ accum_tx->bt_prio_kill_cnt,
+ delta_tx->bt_prio_kill_cnt,
+ max_tx->bt_prio_kill_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "few_bytes_cnt:",
le32_to_cpu(tx->few_bytes_cnt),
- accum_tx->few_bytes_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "cts_timeout:\t\t\t%u\t\t\t%u\n",
- le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- "ack_timeout:\t\t\t%u\t\t\t%u\n",
+ accum_tx->few_bytes_cnt,
+ delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "cts_timeout:",
+ le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
+ delta_tx->cts_timeout, max_tx->cts_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "ack_timeout:",
le32_to_cpu(tx->ack_timeout),
- accum_tx->ack_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- "expected_ack_cnt:\t\t%u\t\t\t%u\n",
+ accum_tx->ack_timeout,
+ delta_tx->ack_timeout, max_tx->ack_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "expected_ack_cnt:",
le32_to_cpu(tx->expected_ack_cnt),
- accum_tx->expected_ack_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "actual_ack_cnt:\t\t\t%u\t\t\t%u\n",
+ accum_tx->expected_ack_cnt,
+ delta_tx->expected_ack_cnt,
+ max_tx->expected_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "actual_ack_cnt:",
le32_to_cpu(tx->actual_ack_cnt),
- accum_tx->actual_ack_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "dump_msdu_cnt:\t\t\t%u\t\t\t%u\n",
+ accum_tx->actual_ack_cnt,
+ delta_tx->actual_ack_cnt,
+ max_tx->actual_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "dump_msdu_cnt:",
le32_to_cpu(tx->dump_msdu_cnt),
- accum_tx->dump_msdu_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "abort_nxt_frame_mismatch:"
- "\t%u\t\t\t%u\n",
+ accum_tx->dump_msdu_cnt,
+ delta_tx->dump_msdu_cnt,
+ max_tx->dump_msdu_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "abort_nxt_frame_mismatch:",
le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
- accum_tx->burst_abort_next_frame_mismatch_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "abort_missing_nxt_frame:"
- "\t%u\t\t\t%u\n",
+ accum_tx->burst_abort_next_frame_mismatch_cnt,
+ delta_tx->burst_abort_next_frame_mismatch_cnt,
+ max_tx->burst_abort_next_frame_mismatch_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "abort_missing_nxt_frame:",
le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
- accum_tx->burst_abort_missing_next_frame_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "cts_timeout_collision:\t\t%u\t\t\t%u\n",
+ accum_tx->burst_abort_missing_next_frame_cnt,
+ delta_tx->burst_abort_missing_next_frame_cnt,
+ max_tx->burst_abort_missing_next_frame_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "cts_timeout_collision:",
le32_to_cpu(tx->cts_timeout_collision),
- accum_tx->cts_timeout_collision);
- pos += scnprintf(buf + pos, bufsz - pos,
- "ack_ba_timeout_collision:\t%u\t\t\t%u\n",
+ accum_tx->cts_timeout_collision,
+ delta_tx->cts_timeout_collision,
+ max_tx->cts_timeout_collision);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "ack_ba_timeout_collision:",
le32_to_cpu(tx->ack_or_ba_timeout_collision),
- accum_tx->ack_or_ba_timeout_collision);
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg ba_timeout:\t\t\t%u\t\t\t%u\n",
+ accum_tx->ack_or_ba_timeout_collision,
+ delta_tx->ack_or_ba_timeout_collision,
+ max_tx->ack_or_ba_timeout_collision);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "agg ba_timeout:",
le32_to_cpu(tx->agg.ba_timeout),
- accum_tx->agg.ba_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg ba_resched_frames:\t\t%u\t\t\t%u\n",
+ accum_tx->agg.ba_timeout,
+ delta_tx->agg.ba_timeout,
+ max_tx->agg.ba_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "agg ba_resched_frames:",
le32_to_cpu(tx->agg.ba_reschedule_frames),
- accum_tx->agg.ba_reschedule_frames);
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg scd_query_agg_frame:\t%u\t\t\t%u\n",
+ accum_tx->agg.ba_reschedule_frames,
+ delta_tx->agg.ba_reschedule_frames,
+ max_tx->agg.ba_reschedule_frames);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "agg scd_query_agg_frame:",
le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
- accum_tx->agg.scd_query_agg_frame_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg scd_query_no_agg:\t\t%u\t\t\t%u\n",
+ accum_tx->agg.scd_query_agg_frame_cnt,
+ delta_tx->agg.scd_query_agg_frame_cnt,
+ max_tx->agg.scd_query_agg_frame_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "agg scd_query_no_agg:",
le32_to_cpu(tx->agg.scd_query_no_agg),
- accum_tx->agg.scd_query_no_agg);
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg scd_query_agg:\t\t%u\t\t\t%u\n",
+ accum_tx->agg.scd_query_no_agg,
+ delta_tx->agg.scd_query_no_agg,
+ max_tx->agg.scd_query_no_agg);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "agg scd_query_agg:",
le32_to_cpu(tx->agg.scd_query_agg),
- accum_tx->agg.scd_query_agg);
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg scd_query_mismatch:\t\t%u\t\t\t%u\n",
+ accum_tx->agg.scd_query_agg,
+ delta_tx->agg.scd_query_agg,
+ max_tx->agg.scd_query_agg);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "agg scd_query_mismatch:",
le32_to_cpu(tx->agg.scd_query_mismatch),
- accum_tx->agg.scd_query_mismatch);
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg frame_not_ready:\t\t%u\t\t\t%u\n",
+ accum_tx->agg.scd_query_mismatch,
+ delta_tx->agg.scd_query_mismatch,
+ max_tx->agg.scd_query_mismatch);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "agg frame_not_ready:",
le32_to_cpu(tx->agg.frame_not_ready),
- accum_tx->agg.frame_not_ready);
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg underrun:\t\t\t%u\t\t\t%u\n",
+ accum_tx->agg.frame_not_ready,
+ delta_tx->agg.frame_not_ready,
+ max_tx->agg.frame_not_ready);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "agg underrun:",
le32_to_cpu(tx->agg.underrun),
- accum_tx->agg.underrun);
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg bt_prio_kill:\t\t%u\t\t\t%u\n",
+ accum_tx->agg.underrun,
+ delta_tx->agg.underrun, max_tx->agg.underrun);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "agg bt_prio_kill:",
le32_to_cpu(tx->agg.bt_prio_kill),
- accum_tx->agg.bt_prio_kill);
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg rx_ba_rsp_cnt:\t\t%u\t\t\t%u\n",
+ accum_tx->agg.bt_prio_kill,
+ delta_tx->agg.bt_prio_kill,
+ max_tx->agg.bt_prio_kill);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "agg rx_ba_rsp_cnt:",
le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
- accum_tx->agg.rx_ba_rsp_cnt);
+ accum_tx->agg.rx_ba_rsp_cnt,
+ delta_tx->agg.rx_ba_rsp_cnt,
+ max_tx->agg.rx_ba_rsp_cnt);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
@@ -1521,28 +1691,19 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
int pos = 0;
char *buf;
- int bufsz = sizeof(struct statistics_general) * 4 + 250;
+ int bufsz = sizeof(struct statistics_general) * 10 + 300;
ssize_t ret;
struct statistics_general *general, *accum_general;
- struct statistics_dbg *dbg, *accum_dbg;
- struct statistics_div *div, *accum_div;
+ struct statistics_general *delta_general, *max_general;
+ struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
+ struct statistics_div *div, *accum_div, *delta_div, *max_div;
if (!iwl_is_alive(priv))
return -EAGAIN;
- /* make request to uCode to retrieve statistics information */
- mutex_lock(&priv->mutex);
- ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
- mutex_unlock(&priv->mutex);
-
- if (ret) {
- IWL_ERR(priv,
- "Error sending statistics request: %zd\n", ret);
- return -EAGAIN;
- }
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf) {
IWL_ERR(priv, "Can not allocate Buffer\n");
@@ -1557,52 +1718,78 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
dbg = &priv->statistics.general.dbg;
div = &priv->statistics.general.div;
accum_general = &priv->accum_statistics.general;
+ delta_general = &priv->delta_statistics.general;
+ max_general = &priv->max_delta.general;
accum_dbg = &priv->accum_statistics.general.dbg;
+ delta_dbg = &priv->delta_statistics.general.dbg;
+ max_dbg = &priv->max_delta.general.dbg;
accum_div = &priv->accum_statistics.general.div;
+ delta_div = &priv->delta_statistics.general.div;
+ max_div = &priv->max_delta.general.div;
pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
- pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n");
- pos += scnprintf(buf + pos, bufsz - pos,
- "\t\t\tcurrent\t\t\taccumulative\n");
- pos += scnprintf(buf + pos, bufsz - pos, "temperature:\t\t\t%u\n",
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
+ "Statistics_General:");
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_short_format,
+ "temperature:",
le32_to_cpu(general->temperature));
- pos += scnprintf(buf + pos, bufsz - pos, "temperature_m:\t\t\t%u\n",
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_short_format,
+ "temperature_m:",
le32_to_cpu(general->temperature_m));
- pos += scnprintf(buf + pos, bufsz - pos,
- "burst_check:\t\t\t%u\t\t\t%u\n",
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "burst_check:",
le32_to_cpu(dbg->burst_check),
- accum_dbg->burst_check);
- pos += scnprintf(buf + pos, bufsz - pos,
- "burst_count:\t\t\t%u\t\t\t%u\n",
+ accum_dbg->burst_check,
+ delta_dbg->burst_check, max_dbg->burst_check);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "burst_count:",
le32_to_cpu(dbg->burst_count),
- accum_dbg->burst_count);
- pos += scnprintf(buf + pos, bufsz - pos,
- "sleep_time:\t\t\t%u\t\t\t%u\n",
+ accum_dbg->burst_count,
+ delta_dbg->burst_count, max_dbg->burst_count);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "sleep_time:",
le32_to_cpu(general->sleep_time),
- accum_general->sleep_time);
- pos += scnprintf(buf + pos, bufsz - pos,
- "slots_out:\t\t\t%u\t\t\t%u\n",
+ accum_general->sleep_time,
+ delta_general->sleep_time, max_general->sleep_time);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "slots_out:",
le32_to_cpu(general->slots_out),
- accum_general->slots_out);
- pos += scnprintf(buf + pos, bufsz - pos,
- "slots_idle:\t\t\t%u\t\t\t%u\n",
+ accum_general->slots_out,
+ delta_general->slots_out, max_general->slots_out);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "slots_idle:",
le32_to_cpu(general->slots_idle),
- accum_general->slots_idle);
+ accum_general->slots_idle,
+ delta_general->slots_idle, max_general->slots_idle);
pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n",
le32_to_cpu(general->ttl_timestamp));
- pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a:\t\t\t%u\t\t\t%u\n",
- le32_to_cpu(div->tx_on_a), accum_div->tx_on_a);
- pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b:\t\t\t%u\t\t\t%u\n",
- le32_to_cpu(div->tx_on_b), accum_div->tx_on_b);
- pos += scnprintf(buf + pos, bufsz - pos,
- "exec_time:\t\t\t%u\t\t\t%u\n",
- le32_to_cpu(div->exec_time), accum_div->exec_time);
- pos += scnprintf(buf + pos, bufsz - pos,
- "probe_time:\t\t\t%u\t\t\t%u\n",
- le32_to_cpu(div->probe_time), accum_div->probe_time);
- pos += scnprintf(buf + pos, bufsz - pos,
- "rx_enable_counter:\t\t%u\t\t\t%u\n",
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "tx_on_a:",
+ le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
+ delta_div->tx_on_a, max_div->tx_on_a);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "tx_on_b:",
+ le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
+ delta_div->tx_on_b, max_div->tx_on_b);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "exec_time:",
+ le32_to_cpu(div->exec_time), accum_div->exec_time,
+ delta_div->exec_time, max_div->exec_time);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "probe_time:",
+ le32_to_cpu(div->probe_time), accum_div->probe_time,
+ delta_div->probe_time, max_div->probe_time);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "rx_enable_counter:",
le32_to_cpu(general->rx_enable_counter),
- accum_general->rx_enable_counter);
+ accum_general->rx_enable_counter,
+ delta_general->rx_enable_counter,
+ max_general->rx_enable_counter);
+ pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+ "num_of_sos_states:",
+ le32_to_cpu(general->num_of_sos_states),
+ accum_general->num_of_sos_states,
+ delta_general->num_of_sos_states,
+ max_general->num_of_sos_states);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
return ret;
@@ -1612,7 +1799,7 @@ static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
int pos = 0;
int cnt = 0;
char *buf;
@@ -1693,7 +1880,7 @@ static ssize_t iwl_dbgfs_chain_noise_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
int pos = 0;
int cnt = 0;
char *buf;
@@ -1751,26 +1938,15 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
char buf[128];
int pos = 0;
- ssize_t ret;
const size_t bufsz = sizeof(buf);
struct statistics_tx *tx;
if (!iwl_is_alive(priv))
pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
else {
- /* make request to uCode to retrieve statistics information */
- mutex_lock(&priv->mutex);
- ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
- mutex_unlock(&priv->mutex);
-
- if (ret) {
- IWL_ERR(priv, "Error sending statistics request: %zd\n",
- ret);
- return -EAGAIN;
- }
tx = &priv->statistics.tx;
if (tx->tx_power.ant_a ||
tx->tx_power.ant_b ||
@@ -1802,7 +1978,7 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
char buf[60];
int pos = 0;
const size_t bufsz = sizeof(buf);
@@ -1845,6 +2021,262 @@ static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,
return count;
}
+static ssize_t iwl_dbgfs_csr_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+ int csr;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%d", &csr) != 1)
+ return -EFAULT;
+
+ if (priv->cfg->ops->lib->dump_csr)
+ priv->cfg->ops->lib->dump_csr(priv);
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ char buf[128];
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n",
+ priv->event_log.ucode_trace ? "On" : "Off");
+ pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n",
+ priv->event_log.non_wraps_count);
+ pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n",
+ priv->event_log.wraps_once_count);
+ pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n",
+ priv->event_log.wraps_more_count);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+ int trace;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%d", &trace) != 1)
+ return -EFAULT;
+
+ if (trace) {
+ priv->event_log.ucode_trace = true;
+ /* schedule the ucode timer to occur in UCODE_TRACE_PERIOD */
+ mod_timer(&priv->ucode_trace,
+ jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
+ } else {
+ priv->event_log.ucode_trace = false;
+ del_timer_sync(&priv->ucode_trace);
+ }
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ char *buf;
+ int pos = 0;
+ ssize_t ret = -EFAULT;
+
+ if (priv->cfg->ops->lib->dump_fh) {
+ ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true);
+ if (buf) {
+ ret = simple_read_from_buffer(user_buf,
+ count, ppos, buf, pos);
+ kfree(buf);
+ }
+ }
+
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_missed_beacon_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = file->private_data;
+ int pos = 0;
+ char buf[12];
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ pos += scnprintf(buf + pos, bufsz - pos, "%d\n",
+ priv->missed_beacon_threshold);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+ int missed;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%d", &missed) != 1)
+ return -EINVAL;
+
+ if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN ||
+ missed > IWL_MISSED_BEACON_THRESHOLD_MAX)
+ priv->missed_beacon_threshold =
+ IWL_MISSED_BEACON_THRESHOLD_DEF;
+ else
+ priv->missed_beacon_threshold = missed;
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_internal_scan_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+ int scan;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%d", &scan) != 1)
+ return -EINVAL;
+
+ iwl_internal_short_hw_scan(priv);
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ char buf[12];
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
+ priv->cfg->plcp_delta_threshold);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+ int plcp;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%d", &plcp) != 1)
+ return -EINVAL;
+ if ((plcp <= IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
+ (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
+ priv->cfg->plcp_delta_threshold =
+ IWL_MAX_PLCP_ERR_THRESHOLD_DEF;
+ else
+ priv->cfg->plcp_delta_threshold = plcp;
+ return count;
+}
+
+static ssize_t iwl_dbgfs_force_reset_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = file->private_data;
+ int i, pos = 0;
+ char buf[300];
+ const size_t bufsz = sizeof(buf);
+ struct iwl_force_reset *force_reset;
+
+ for (i = 0; i < IWL_MAX_FORCE_RESET; i++) {
+ force_reset = &priv->force_reset[i];
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Force reset method %d\n", i);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tnumber of reset request: %d\n",
+ force_reset->reset_request_count);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tnumber of reset request success: %d\n",
+ force_reset->reset_success_count);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tnumber of reset request reject: %d\n",
+ force_reset->reset_reject_count);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\treset duration: %lu\n",
+ force_reset->reset_duration);
+ }
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_force_reset_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+ int reset, ret;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%d", &reset) != 1)
+ return -EINVAL;
+ switch (reset) {
+ case IWL_RF_RESET:
+ case IWL_FW_RESET:
+ ret = iwl_force_reset(priv, reset);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return ret ? ret : count;
+}
+
DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1859,6 +2291,13 @@ DEBUGFS_READ_FILE_OPS(tx_power);
DEBUGFS_READ_FILE_OPS(power_save_status);
DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
+DEBUGFS_WRITE_FILE_OPS(csr);
+DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
+DEBUGFS_READ_FILE_OPS(fh_reg);
+DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
+DEBUGFS_WRITE_FILE_OPS(internal_scan);
+DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
+DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
/*
* Create the debugfs files and directories
@@ -1866,69 +2305,74 @@ DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
*/
int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
{
- struct iwl_debugfs *dbgfs;
struct dentry *phyd = priv->hw->wiphy->debugfsdir;
- int ret = 0;
+ struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
- dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL);
- if (!dbgfs) {
- ret = -ENOMEM;
- goto err;
- }
+ dir_drv = debugfs_create_dir(name, phyd);
+ if (!dir_drv)
+ return -ENOMEM;
+
+ priv->debugfs_dir = dir_drv;
- priv->dbgfs = dbgfs;
- dbgfs->name = name;
- dbgfs->dir_drv = debugfs_create_dir(name, phyd);
- if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)) {
- ret = -ENOENT;
+ dir_data = debugfs_create_dir("data", dir_drv);
+ if (!dir_data)
+ goto err;
+ dir_rf = debugfs_create_dir("rf", dir_drv);
+ if (!dir_rf)
+ goto err;
+ dir_debug = debugfs_create_dir("debug", dir_drv);
+ if (!dir_debug)
goto err;
- }
- DEBUGFS_ADD_DIR(data, dbgfs->dir_drv);
- DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv);
- DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv);
- DEBUGFS_ADD_FILE(nvm, data, S_IRUSR);
- DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(log_event, data, S_IWUSR);
- DEBUGFS_ADD_FILE(stations, data, S_IRUSR);
- DEBUGFS_ADD_FILE(channels, data, S_IRUSR);
- DEBUGFS_ADD_FILE(status, data, S_IRUSR);
- DEBUGFS_ADD_FILE(interrupt, data, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(qos, data, S_IRUSR);
- DEBUGFS_ADD_FILE(led, data, S_IRUSR);
- DEBUGFS_ADD_FILE(sleep_level_override, data, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(current_sleep_command, data, S_IRUSR);
- DEBUGFS_ADD_FILE(thermal_throttling, data, S_IRUSR);
- DEBUGFS_ADD_FILE(disable_ht40, data, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(rx_statistics, debug, S_IRUSR);
- DEBUGFS_ADD_FILE(tx_statistics, debug, S_IRUSR);
- DEBUGFS_ADD_FILE(traffic_log, debug, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(rx_queue, debug, S_IRUSR);
- DEBUGFS_ADD_FILE(tx_queue, debug, S_IRUSR);
- DEBUGFS_ADD_FILE(tx_power, debug, S_IRUSR);
- DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR);
- DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR);
- DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR);
+ DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
+ DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(log_event, dir_data, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
+ DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
+ DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
+ DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
+ DEBUGFS_ADD_FILE(led, dir_data, S_IRUSR);
+ DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
+ DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
+ DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(tx_power, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
+ DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR);
+ DEBUGFS_ADD_FILE(csr, dir_debug, S_IWUSR);
+ DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
+ DEBUGFS_ADD_FILE(internal_scan, dir_debug, S_IWUSR);
+ DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
- DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR);
- DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);
- DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR);
- DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR);
- DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
}
- DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
- DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
+ DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, &priv->disable_sens_cal);
+ DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
&priv->disable_chain_noise_cal);
if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
- DEBUGFS_ADD_BOOL(disable_tx_power, rf,
+ DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
&priv->disable_tx_power_cal);
return 0;
err:
- IWL_ERR(priv, "Can't open the debugfs directory\n");
+ IWL_ERR(priv, "Can't create the debugfs directory\n");
iwl_dbgfs_unregister(priv);
- return ret;
+ return -ENOMEM;
}
EXPORT_SYMBOL(iwl_dbgfs_register);
@@ -1938,56 +2382,11 @@ EXPORT_SYMBOL(iwl_dbgfs_register);
*/
void iwl_dbgfs_unregister(struct iwl_priv *priv)
{
- if (!priv->dbgfs)
+ if (!priv->debugfs_dir)
return;
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sleep_level_override);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_current_sleep_command);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40);
- DEBUGFS_REMOVE(priv->dbgfs->dir_data);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_statistics);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_statistics);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
- file_clear_ucode_statistics);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
- file_clear_traffic_statistics);
- if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
- file_ucode_rx_stats);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
- file_ucode_tx_stats);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
- file_ucode_general_stats);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
- file_sensitivity);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
- file_chain_noise);
- }
- DEBUGFS_REMOVE(priv->dbgfs->dir_debug);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
- if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
- ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power);
- DEBUGFS_REMOVE(priv->dbgfs->dir_rf);
- DEBUGFS_REMOVE(priv->dbgfs->dir_drv);
- kfree(priv->dbgfs);
- priv->dbgfs = NULL;
+ debugfs_remove_recursive(priv->debugfs_dir);
+ priv->debugfs_dir = NULL;
}
EXPORT_SYMBOL(iwl_dbgfs_unregister);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 3822cf53e368..6054c5fba0c1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -512,6 +512,7 @@ struct iwl_ht_config {
bool is_ht;
bool is_40mhz;
bool single_chain_sufficient;
+ enum ieee80211_smps_mode smps; /* current smps mode */
/* BSS related data */
u8 extension_chan_offset;
u8 ht_protection;
@@ -984,6 +985,74 @@ struct iwl_switch_rxon {
__le16 channel;
};
+/*
+ * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds
+ * to perform continuous uCode event logging operation if enabled
+ */
+#define UCODE_TRACE_PERIOD (100)
+
+/*
+ * iwl_event_log: current uCode event log position
+ *
+ * @ucode_trace: enable/disable ucode continuous trace timer
+ * @num_wraps: how many times the event buffer wraps
+ * @next_entry: the entry just before the next one that uCode would fill
+ * @non_wraps_count: counter for no wrap detected when dump ucode events
+ * @wraps_once_count: counter for wrap once detected when dump ucode events
+ * @wraps_more_count: counter for wrap more than once detected
+ * when dump ucode events
+ */
+struct iwl_event_log {
+ bool ucode_trace;
+ u32 num_wraps;
+ u32 next_entry;
+ int non_wraps_count;
+ int wraps_once_count;
+ int wraps_more_count;
+};
+
+/*
+ * host interrupt timeout value
+ * used with setting interrupt coalescing timer
+ * the CSR_INT_COALESCING is an 8 bit register in 32-usec unit
+ *
+ * default interrupt coalescing timer is 64 x 32 = 2048 usecs
+ * default interrupt coalescing calibration timer is 16 x 32 = 512 usecs
+ */
+#define IWL_HOST_INT_TIMEOUT_MAX (0xFF)
+#define IWL_HOST_INT_TIMEOUT_DEF (0x40)
+#define IWL_HOST_INT_TIMEOUT_MIN (0x0)
+#define IWL_HOST_INT_CALIB_TIMEOUT_MAX (0xFF)
+#define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10)
+#define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0)
+
+/*
+ * This is the threshold value of plcp error rate per 100mSecs. It is
+ * used to set and check for the validity of plcp_delta.
+ */
+#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (0)
+#define IWL_MAX_PLCP_ERR_THRESHOLD_DEF (50)
+#define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF (100)
+#define IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF (200)
+#define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255)
+
+#define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3)
+#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5)
+
+enum iwl_reset {
+ IWL_RF_RESET = 0,
+ IWL_FW_RESET,
+ IWL_MAX_FORCE_RESET,
+};
+
+struct iwl_force_reset {
+ int reset_request_count;
+ int reset_success_count;
+ int reset_reject_count;
+ unsigned long reset_duration;
+ unsigned long last_force_reset_jiffies;
+};
+
struct iwl_priv {
/* ieee device used by generic ieee processing code */
@@ -1004,13 +1073,19 @@ struct iwl_priv {
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
-#if defined(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) || defined(CONFIG_IWL3945_SPECTRUM_MEASUREMENT)
/* spectrum measurement report caching */
struct iwl_spectrum_notification measure_report;
u8 measurement_status;
-#endif
+
/* ucode beacon time */
u32 ucode_beacon_time;
+ int missed_beacon_threshold;
+
+ /* storing the jiffies when the plcp error rate is received */
+ unsigned long plcp_jiffies;
+
+ /* force reset */
+ struct iwl_force_reset force_reset[IWL_MAX_FORCE_RESET];
/* we allocate array of iwl4965_channel_info for NIC's valid channels.
* Access via channel # using indirect index array */
@@ -1029,7 +1104,6 @@ struct iwl_priv {
struct iwl_calib_result calib_results[IWL_CALIB_MAX];
/* Scan related variables */
- unsigned long last_scan_jiffies;
unsigned long next_scan_jiffies;
unsigned long scan_start;
unsigned long scan_pass_start;
@@ -1037,6 +1111,7 @@ struct iwl_priv {
void *scan;
int scan_bands;
struct cfg80211_scan_request *scan_request;
+ bool is_internal_short_scan;
u8 scan_tx_ant[IEEE80211_NUM_BANDS];
u8 mgmt_tx_ant;
@@ -1045,6 +1120,7 @@ struct iwl_priv {
spinlock_t hcmd_lock; /* protect hcmd */
spinlock_t reg_lock; /* protect hw register access */
struct mutex mutex;
+ struct mutex sync_cmd_mutex; /* enable serialization of sync commands */
/* basic pci-network driver stuff */
struct pci_dev *pci_dev;
@@ -1056,6 +1132,7 @@ struct iwl_priv {
u8 rev_id;
/* uCode images, save to reload in case of failure */
+ int fw_index; /* firmware we're trying to load */
u32 ucode_ver; /* version of ucode, copy of
iwl_ucode.ver */
struct fw_desc ucode_code; /* runtime inst */
@@ -1066,6 +1143,7 @@ struct iwl_priv {
struct fw_desc ucode_boot; /* bootstrap inst */
enum ucode_type ucode_type;
u8 ucode_write_complete; /* the image write is complete */
+ char firmware_name[25];
struct iwl_rxon_time_cmd rxon_timing;
@@ -1135,6 +1213,8 @@ struct iwl_priv {
struct iwl_notif_statistics statistics;
#ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_notif_statistics accum_statistics;
+ struct iwl_notif_statistics delta_statistics;
+ struct iwl_notif_statistics max_delta;
#endif
/* context information */
@@ -1207,15 +1287,10 @@ struct iwl_priv {
struct workqueue_struct *workqueue;
- struct work_struct up;
struct work_struct restart;
- struct work_struct calibrated_work;
struct work_struct scan_completed;
struct work_struct rx_replenish;
struct work_struct abort_scan;
- struct work_struct update_link_led;
- struct work_struct auth_work;
- struct work_struct report_work;
struct work_struct request_scan;
struct work_struct beacon_update;
struct work_struct tt_work;
@@ -1251,7 +1326,8 @@ struct iwl_priv {
u16 rx_traffic_idx;
u8 *tx_traffic;
u8 *rx_traffic;
- struct iwl_debugfs *dbgfs;
+ struct dentry *debugfs_dir;
+ u32 dbgfs_sram_offset, dbgfs_sram_len;
#endif /* CONFIG_IWLWIFI_DEBUGFS */
#endif /* CONFIG_IWLWIFI_DEBUG */
@@ -1261,6 +1337,7 @@ struct iwl_priv {
u32 disable_tx_power_cal;
struct work_struct run_time_calib_work;
struct timer_list statistics_periodic;
+ struct timer_list ucode_trace;
bool hw_ready;
/*For 3945*/
#define IWL_DEFAULT_TX_POWER 0x0F
@@ -1268,6 +1345,8 @@ struct iwl_priv {
struct iwl3945_notif_statistics statistics_39;
u32 sta_supp_rates;
+
+ struct iwl_event_log event_log;
}; /*iwl_priv */
static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
index e7d88d1da15d..36580d8d8b8d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
@@ -1,3 +1,29 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
#include <linux/module.h>
/* sparse doesn't like tracepoint macros */
@@ -11,4 +37,6 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
index 21361968ab7e..ff4d012ce260 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -1,3 +1,29 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
#if !defined(__IWLWIFI_DEVICE_TRACE) || defined(TRACE_HEADER_MULTI_READ)
#define __IWLWIFI_DEVICE_TRACE
@@ -65,6 +91,50 @@ TRACE_EVENT(iwlwifi_dev_iowrite32,
);
#undef TRACE_SYSTEM
+#define TRACE_SYSTEM iwlwifi_ucode
+
+TRACE_EVENT(iwlwifi_dev_ucode_cont_event,
+ TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
+ TP_ARGS(priv, time, data, ev),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+
+ __field(u32, time)
+ __field(u32, data)
+ __field(u32, ev)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ __entry->time = time;
+ __entry->data = data;
+ __entry->ev = ev;
+ ),
+ TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u",
+ __entry->priv, __entry->time, __entry->data, __entry->ev)
+);
+
+TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
+ TP_PROTO(struct iwl_priv *priv, u32 wraps, u32 n_entry, u32 p_entry),
+ TP_ARGS(priv, wraps, n_entry, p_entry),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+
+ __field(u32, wraps)
+ __field(u32, n_entry)
+ __field(u32, p_entry)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ __entry->wraps = wraps;
+ __entry->n_entry = n_entry;
+ __entry->p_entry = p_entry;
+ ),
+ TP_printk("[%p] wraps=#%02d n=0x%X p=0x%X",
+ __entry->priv, __entry->wraps, __entry->n_entry,
+ __entry->p_entry)
+);
+
+#undef TRACE_SYSTEM
#define TRACE_SYSTEM iwlwifi
TRACE_EVENT(iwlwifi_dev_hcmd,
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 4a30969689ff..fd37152abae3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 0cd9c02ee044..4e1ba824dc50 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index 65fa8a69fd5a..113c3669b9ce 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -379,6 +379,25 @@
#define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010)
+/**
+ * Bit fields for TSSR(Tx Shared Status & Control) error status register:
+ * 31: Indicates an address error when accessed to internal memory
+ * uCode/driver must write "1" in order to clear this flag
+ * 30: Indicates that Host did not send the expected number of dwords to FH
+ * uCode/driver must write "1" in order to clear this flag
+ * 16-9:Each status bit is for one channel. Indicates that an (Error) ActDMA
+ * command was received from the scheduler while the TRB was already full
+ * with previous command
+ * uCode/driver must write "1" in order to clear this flag
+ * 7-0: Each status bit indicates a channel's TxCredit error. When an error
+ * bit is set, it indicates that the FH has received a full indication
+ * from the RTC TxFIFO and the current value of the TxCredit counter was
+ * not equal to zero. This mean that the credit mechanism was not
+ * synchronized to the TxFIFO status
+ * uCode/driver must write "1" in order to clear this flag
+ */
+#define FH_TSSR_TX_ERROR_REG (FH_TSSR_LOWER_BOUND + 0x018)
+
#define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24)
#define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16)
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 30e9ea6d54ec..73681c4fefe7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -58,7 +58,6 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(COEX_PRIORITY_TABLE_CMD);
IWL_CMD(COEX_MEDIUM_NOTIFICATION);
IWL_CMD(COEX_EVENT_CMD);
- IWL_CMD(RADAR_NOTIFICATION);
IWL_CMD(REPLY_QUIET_CMD);
IWL_CMD(REPLY_CHANNEL_SWITCH);
IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
@@ -165,15 +164,13 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
/* A synchronous command can not have a callback set. */
BUG_ON(cmd->callback);
- if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) {
- IWL_ERR(priv,
- "Error sending %s: Already sending a host command\n",
+ IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
get_cmd_string(cmd->id));
- ret = -EBUSY;
- goto out;
- }
+ mutex_lock(&priv->sync_cmd_mutex);
set_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s \n",
+ get_cmd_string(cmd->id));
cmd_idx = iwl_enqueue_hcmd(priv, cmd);
if (cmd_idx < 0) {
@@ -194,6 +191,8 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
+ get_cmd_string(cmd->id));
ret = -ETIMEDOUT;
goto cancel;
}
@@ -238,7 +237,7 @@ fail:
cmd->reply_page = 0;
}
out:
- clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
+ mutex_unlock(&priv->sync_cmd_mutex);
return ret;
}
EXPORT_SYMBOL(iwl_send_cmd_sync);
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index bd0b12efb5c7..51a67fb2e185 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -80,8 +80,8 @@ static inline void iwl_free_fw_desc(struct pci_dev *pci_dev,
struct fw_desc *desc)
{
if (desc->v_addr)
- pci_free_consistent(pci_dev, desc->len,
- desc->v_addr, desc->p_addr);
+ dma_free_coherent(&pci_dev->dev, desc->len,
+ desc->v_addr, desc->p_addr);
desc->v_addr = NULL;
desc->len = 0;
}
@@ -89,7 +89,8 @@ static inline void iwl_free_fw_desc(struct pci_dev *pci_dev,
static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev,
struct fw_desc *desc)
{
- desc->v_addr = pci_alloc_consistent(pci_dev, desc->len, &desc->p_addr);
+ desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len,
+ &desc->p_addr, GFP_KERNEL);
return (desc->v_addr != NULL) ? 0 : -ENOMEM;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index e552d4c4bdbe..c719baf2585a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project.
*
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index 46c7a95b88f0..a6f9c918aabc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
index f47f053f02ea..49a70baa3fb6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 8ccc0bb1d9ed..1a1a9f081cc7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -303,13 +303,12 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
sizeof(struct iwl_powertable_cmd), cmd);
}
-
+/* priv->mutex must be held */
int iwl_power_update_mode(struct iwl_priv *priv, bool force)
{
int ret = 0;
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
- bool enabled = (priv->iw_mode == NL80211_IFTYPE_STATION) &&
- (priv->hw->conf.flags & IEEE80211_CONF_PS);
+ bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
bool update_chains;
struct iwl_powertable_cmd cmd;
int dtimper;
@@ -319,7 +318,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
if (priv->vif)
- dtimper = priv->vif->bss_conf.dtim_period;
+ dtimper = priv->hw->conf.ps_dtim_period;
else
dtimper = 1;
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index 310c32e8f698..5db91c10dcc8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 6d95832db06d..d2d2a9174900 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 6f36b6e79f5e..df257bc15f49 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -123,12 +123,11 @@ EXPORT_SYMBOL(iwl_rx_queue_space);
/**
* iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
*/
-int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
{
unsigned long flags;
u32 rx_wrt_ptr_reg = priv->hw_params.rx_wrt_ptr_reg;
u32 reg;
- int ret = 0;
spin_lock_irqsave(&q->lock, flags);
@@ -161,7 +160,6 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
exit_unlock:
spin_unlock_irqrestore(&q->lock, flags);
- return ret;
}
EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr);
/**
@@ -184,14 +182,13 @@ static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
* also updates the memory address in the firmware to reference the new
* target buffer.
*/
-int iwl_rx_queue_restock(struct iwl_priv *priv)
+void iwl_rx_queue_restock(struct iwl_priv *priv)
{
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
unsigned long flags;
int write;
- int ret = 0;
spin_lock_irqsave(&rxq->lock, flags);
write = rxq->write & ~0x7;
@@ -220,10 +217,8 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
spin_lock_irqsave(&rxq->lock, flags);
rxq->need_update = 1;
spin_unlock_irqrestore(&rxq->lock, flags);
- ret = iwl_rx_queue_update_write_ptr(priv, rxq);
+ iwl_rx_queue_update_write_ptr(priv, rxq);
}
-
- return ret;
}
EXPORT_SYMBOL(iwl_rx_queue_restock);
@@ -350,10 +345,10 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
}
}
- pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
- rxq->dma_addr);
- pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status),
- rxq->rb_stts, rxq->rb_stts_dma);
+ dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+ rxq->dma_addr);
+ dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
+ rxq->rb_stts, rxq->rb_stts_dma);
rxq->bd = NULL;
rxq->rb_stts = NULL;
}
@@ -362,7 +357,7 @@ EXPORT_SYMBOL(iwl_rx_queue_free);
int iwl_rx_queue_alloc(struct iwl_priv *priv)
{
struct iwl_rx_queue *rxq = &priv->rxq;
- struct pci_dev *dev = priv->pci_dev;
+ struct device *dev = &priv->pci_dev->dev;
int i;
spin_lock_init(&rxq->lock);
@@ -370,12 +365,13 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
INIT_LIST_HEAD(&rxq->rx_used);
/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
- rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
+ rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr,
+ GFP_KERNEL);
if (!rxq->bd)
goto err_bd;
- rxq->rb_stts = pci_alloc_consistent(dev, sizeof(struct iwl_rb_status),
- &rxq->rb_stts_dma);
+ rxq->rb_stts = dma_alloc_coherent(dev, sizeof(struct iwl_rb_status),
+ &rxq->rb_stts_dma, GFP_KERNEL);
if (!rxq->rb_stts)
goto err_rb;
@@ -392,8 +388,8 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
return 0;
err_rb:
- pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
- rxq->dma_addr);
+ dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+ rxq->dma_addr);
err_bd:
return -ENOMEM;
}
@@ -473,8 +469,8 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
(rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
(rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
- /* Set interrupt coalescing timer to 64 x 32 = 2048 usecs */
- iwl_write8(priv, CSR_INT_COALESCING, 0x40);
+ /* Set interrupt coalescing timer to default (2048 usecs) */
+ iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
return 0;
}
@@ -499,9 +495,10 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
struct iwl_missed_beacon_notif *missed_beacon;
missed_beacon = &pkt->u.missed_beacon;
- if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
+ if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
+ priv->missed_beacon_threshold) {
IWL_DEBUG_CALIB(priv, "missed bcn cnsq %d totl %d rcd %d expctd %d\n",
- le32_to_cpu(missed_beacon->consequtive_missed_beacons),
+ le32_to_cpu(missed_beacon->consecutive_missed_beacons),
le32_to_cpu(missed_beacon->total_missed_becons),
le32_to_cpu(missed_beacon->num_recvd_beacons),
le32_to_cpu(missed_beacon->num_expected_beacons));
@@ -511,6 +508,24 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);
+void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
+
+ if (!report->state) {
+ IWL_DEBUG_11H(priv,
+ "Spectrum Measure Notification: Start\n");
+ return;
+ }
+
+ memcpy(&priv->measure_report, report, sizeof(*report));
+ priv->measurement_status |= MEASUREMENT_READY;
+}
+EXPORT_SYMBOL(iwl_rx_spectrum_measure_notif);
+
+
/* Calculate noise level, based on measurements during network silence just
* before arriving beacon. This measurement can be done only if we know
@@ -564,15 +579,24 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
int i;
__le32 *prev_stats;
u32 *accum_stats;
+ u32 *delta, *max_delta;
prev_stats = (__le32 *)&priv->statistics;
accum_stats = (u32 *)&priv->accum_statistics;
+ delta = (u32 *)&priv->delta_statistics;
+ max_delta = (u32 *)&priv->max_delta;
for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics);
- i += sizeof(__le32), stats++, prev_stats++, accum_stats++)
- if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats))
- *accum_stats += (le32_to_cpu(*stats) -
+ i += sizeof(__le32), stats++, prev_stats++, delta++,
+ max_delta++, accum_stats++) {
+ if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
+ *delta = (le32_to_cpu(*stats) -
le32_to_cpu(*prev_stats));
+ *accum_stats += *delta;
+ if (*delta > *max_delta)
+ *max_delta = *delta;
+ }
+ }
/* reset accumulative statistics for "no-counter" type statistics */
priv->accum_statistics.general.temperature =
@@ -592,11 +616,15 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
#define REG_RECALIB_PERIOD (60)
+#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n"
void iwl_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
int change;
struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ int combined_plcp_delta;
+ unsigned int plcp_msec;
+ unsigned long plcp_received_jiffies;
IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
(int)sizeof(priv->statistics),
@@ -611,6 +639,56 @@ void iwl_rx_statistics(struct iwl_priv *priv,
#ifdef CONFIG_IWLWIFI_DEBUG
iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
#endif
+ /*
+ * check for plcp_err and trigger radio reset if it exceeds
+ * the plcp error threshold plcp_delta.
+ */
+ plcp_received_jiffies = jiffies;
+ plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
+ (long) priv->plcp_jiffies);
+ priv->plcp_jiffies = plcp_received_jiffies;
+ /*
+ * check to make sure plcp_msec is not 0 to prevent division
+ * by zero.
+ */
+ if (plcp_msec) {
+ combined_plcp_delta =
+ (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) -
+ le32_to_cpu(priv->statistics.rx.ofdm.plcp_err)) +
+ (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) -
+ le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err));
+
+ if ((combined_plcp_delta > 0) &&
+ ((combined_plcp_delta * 100) / plcp_msec) >
+ priv->cfg->plcp_delta_threshold) {
+ /*
+ * if plcp_err exceed the threshold, the following
+ * data is printed in csv format:
+ * Text: plcp_err exceeded %d,
+ * Received ofdm.plcp_err,
+ * Current ofdm.plcp_err,
+ * Received ofdm_ht.plcp_err,
+ * Current ofdm_ht.plcp_err,
+ * combined_plcp_delta,
+ * plcp_msec
+ */
+ IWL_DEBUG_RADIO(priv, PLCP_MSG,
+ priv->cfg->plcp_delta_threshold,
+ le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),
+ le32_to_cpu(priv->statistics.rx.ofdm.plcp_err),
+ le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),
+ le32_to_cpu(
+ priv->statistics.rx.ofdm_ht.plcp_err),
+ combined_plcp_delta, plcp_msec);
+
+ /*
+ * Reset the RF radio due to the high plcp
+ * error rate
+ */
+ iwl_force_reset(priv, IWL_RF_RESET);
+ }
+ }
+
memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
set_bit(STATUS_STATISTICS, &priv->status);
@@ -638,11 +716,13 @@ void iwl_reply_statistics(struct iwl_priv *priv,
struct iwl_rx_packet *pkt = rxb_addr(rxb);
if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
- memset(&priv->statistics, 0,
- sizeof(struct iwl_notif_statistics));
#ifdef CONFIG_IWLWIFI_DEBUG
memset(&priv->accum_statistics, 0,
sizeof(struct iwl_notif_statistics));
+ memset(&priv->delta_statistics, 0,
+ sizeof(struct iwl_notif_statistics));
+ memset(&priv->max_delta, 0,
+ sizeof(struct iwl_notif_statistics));
#endif
IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
}
@@ -928,7 +1008,10 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
if (ieee80211_is_mgmt(fc) ||
ieee80211_has_protected(fc) ||
ieee80211_has_morefrags(fc) ||
- le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
+ le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG ||
+ (ieee80211_is_data_qos(fc) &&
+ *ieee80211_get_qos_ctl(hdr) &
+ IEEE80211_QOS_CONTROL_A_MSDU_PRESENT))
ret = skb_linearize(skb);
else
ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index fa1c89ba6459..bd2f7c420563 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -192,19 +192,17 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
IWL_DEBUG_SCAN(priv, "Scan ch.res: "
"%d [802.11%s] "
"(TSF: 0x%08X:%08X) - %d "
- "elapsed=%lu usec (%dms since last)\n",
+ "elapsed=%lu usec\n",
notif->channel,
notif->band ? "bg" : "a",
le32_to_cpu(notif->tsf_high),
le32_to_cpu(notif->tsf_low),
le32_to_cpu(notif->statistics[0]),
- le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf,
- jiffies_to_msecs(elapsed_jiffies
- (priv->last_scan_jiffies, jiffies)));
+ le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);
#endif
- priv->last_scan_jiffies = jiffies;
- priv->next_scan_jiffies = 0;
+ if (!priv->is_internal_short_scan)
+ priv->next_scan_jiffies = 0;
}
/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
@@ -250,8 +248,9 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
goto reschedule;
}
- priv->last_scan_jiffies = jiffies;
- priv->next_scan_jiffies = 0;
+ if (!priv->is_internal_short_scan)
+ priv->next_scan_jiffies = 0;
+
IWL_DEBUG_INFO(priv, "Setting scan to off\n");
clear_bit(STATUS_SCANNING, &priv->status);
@@ -314,6 +313,72 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwl_get_passive_dwell_time);
+static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
+ enum ieee80211_band band,
+ struct iwl_scan_channel *scan_ch)
+{
+ const struct ieee80211_supported_band *sband;
+ const struct iwl_channel_info *ch_info;
+ u16 passive_dwell = 0;
+ u16 active_dwell = 0;
+ int i, added = 0;
+ u16 channel = 0;
+
+ sband = iwl_get_hw_mode(priv, band);
+ if (!sband) {
+ IWL_ERR(priv, "invalid band\n");
+ return added;
+ }
+
+ active_dwell = iwl_get_active_dwell_time(priv, band, 0);
+ passive_dwell = iwl_get_passive_dwell_time(priv, band);
+
+ if (passive_dwell <= active_dwell)
+ passive_dwell = active_dwell + 1;
+
+ /* only scan single channel, good enough to reset the RF */
+ /* pick the first valid not in-use channel */
+ if (band == IEEE80211_BAND_5GHZ) {
+ for (i = 14; i < priv->channel_count; i++) {
+ if (priv->channel_info[i].channel !=
+ le16_to_cpu(priv->staging_rxon.channel)) {
+ channel = priv->channel_info[i].channel;
+ ch_info = iwl_get_channel_info(priv,
+ band, channel);
+ if (is_channel_valid(ch_info))
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < 14; i++) {
+ if (priv->channel_info[i].channel !=
+ le16_to_cpu(priv->staging_rxon.channel)) {
+ channel =
+ priv->channel_info[i].channel;
+ ch_info = iwl_get_channel_info(priv,
+ band, channel);
+ if (is_channel_valid(ch_info))
+ break;
+ }
+ }
+ }
+ if (channel) {
+ scan_ch->channel = cpu_to_le16(channel);
+ scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+ scan_ch->active_dwell = cpu_to_le16(active_dwell);
+ scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+ /* Set txpower levels to defaults */
+ scan_ch->dsp_atten = 110;
+ if (band == IEEE80211_BAND_5GHZ)
+ scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+ else
+ scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+ added++;
+ } else
+ IWL_ERR(priv, "no valid channel found\n");
+ return added;
+}
+
static int iwl_get_channels_for_scan(struct iwl_priv *priv,
enum ieee80211_band band,
u8 is_active, u8 n_probes,
@@ -404,23 +469,9 @@ EXPORT_SYMBOL(iwl_init_scan_params);
static int iwl_scan_initiate(struct iwl_priv *priv)
{
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n");
- return -EIO;
- }
-
- if (test_bit(STATUS_SCANNING, &priv->status)) {
- IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
- return -EAGAIN;
- }
-
- if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
- IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
- return -EAGAIN;
- }
-
IWL_DEBUG_INFO(priv, "Starting scan...\n");
set_bit(STATUS_SCANNING, &priv->status);
+ priv->is_internal_short_scan = false;
priv->scan_start = jiffies;
priv->scan_pass_start = priv->scan_start;
@@ -449,6 +500,18 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
goto out_unlock;
}
+ if (test_bit(STATUS_SCANNING, &priv->status)) {
+ IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
+ ret = -EAGAIN;
+ goto out_unlock;
+ }
+
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
+ ret = -EAGAIN;
+ goto out_unlock;
+ }
+
/* We don't schedule scan within next_scan_jiffies period.
* Avoid scanning during possible EAPOL exchange, return
* success immediately.
@@ -461,15 +524,6 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
goto out_unlock;
}
- /* if we just finished scan ask for delay */
- if (iwl_is_associated(priv) && priv->last_scan_jiffies &&
- time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) {
- IWL_DEBUG_SCAN(priv, "scan rejected: within previous scan period\n");
- queue_work(priv->workqueue, &priv->scan_completed);
- ret = 0;
- goto out_unlock;
- }
-
priv->scan_bands = 0;
for (i = 0; i < req->n_channels; i++)
priv->scan_bands |= BIT(req->channels[i]->band);
@@ -488,6 +542,46 @@ out_unlock:
}
EXPORT_SYMBOL(iwl_mac_hw_scan);
+/*
+ * internal short scan, this function should only been called while associated.
+ * It will reset and tune the radio to prevent possible RF related problem
+ */
+int iwl_internal_short_hw_scan(struct iwl_priv *priv)
+{
+ int ret = 0;
+
+ if (!iwl_is_ready_rf(priv)) {
+ ret = -EIO;
+ IWL_DEBUG_SCAN(priv, "not ready or exit pending\n");
+ goto out;
+ }
+ if (test_bit(STATUS_SCANNING, &priv->status)) {
+ IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
+ ret = -EAGAIN;
+ goto out;
+ }
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ priv->scan_bands = 0;
+ if (priv->band == IEEE80211_BAND_5GHZ)
+ priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
+ else
+ priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
+
+ IWL_DEBUG_SCAN(priv, "Start internal short scan...\n");
+ set_bit(STATUS_SCANNING, &priv->status);
+ priv->is_internal_short_scan = true;
+ queue_work(priv->workqueue, &priv->request_scan);
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL(iwl_internal_short_hw_scan);
+
#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
void iwl_bg_scan_check(struct work_struct *data)
@@ -551,7 +645,8 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
if (WARN_ON(left < ie_len))
return len;
- memcpy(pos, ies, ie_len);
+ if (ies)
+ memcpy(pos, ies, ie_len);
len += ie_len;
left -= ie_len;
@@ -654,7 +749,6 @@ static void iwl_bg_request_scan(struct work_struct *data)
unsigned long flags;
IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
-
spin_lock_irqsave(&priv->lock, flags);
interval = priv->beacon_int;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -672,7 +766,9 @@ static void iwl_bg_request_scan(struct work_struct *data)
scan_suspend_time, interval);
}
- if (priv->scan_request->n_ssids) {
+ if (priv->is_internal_short_scan) {
+ IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
+ } else if (priv->scan_request->n_ssids) {
int i, p = 0;
IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
for (i = 0; i < priv->scan_request->n_ssids; i++) {
@@ -753,24 +849,38 @@ static void iwl_bg_request_scan(struct work_struct *data)
rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
scan->rx_chain = cpu_to_le16(rx_chain);
- cmd_len = iwl_fill_probe_req(priv,
- (struct ieee80211_mgmt *)scan->data,
- priv->scan_request->ie,
- priv->scan_request->ie_len,
- IWL_MAX_SCAN_SIZE - sizeof(*scan));
+ if (!priv->is_internal_short_scan) {
+ cmd_len = iwl_fill_probe_req(priv,
+ (struct ieee80211_mgmt *)scan->data,
+ priv->scan_request->ie,
+ priv->scan_request->ie_len,
+ IWL_MAX_SCAN_SIZE - sizeof(*scan));
+ } else {
+ cmd_len = iwl_fill_probe_req(priv,
+ (struct ieee80211_mgmt *)scan->data,
+ NULL, 0,
+ IWL_MAX_SCAN_SIZE - sizeof(*scan));
+ }
scan->tx_cmd.len = cpu_to_le16(cmd_len);
-
if (iwl_is_monitor_mode(priv))
scan->filter_flags = RXON_FILTER_PROMISC_MSK;
scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
RXON_FILTER_BCON_AWARE_MSK);
- scan->channel_count =
- iwl_get_channels_for_scan(priv, band, is_active, n_probes,
- (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
-
+ if (priv->is_internal_short_scan) {
+ scan->channel_count =
+ iwl_get_single_channel_for_scan(priv, band,
+ (void *)&scan->data[le16_to_cpu(
+ scan->tx_cmd.len)]);
+ } else {
+ scan->channel_count =
+ iwl_get_channels_for_scan(priv, band,
+ is_active, n_probes,
+ (void *)&scan->data[le16_to_cpu(
+ scan->tx_cmd.len)]);
+ }
if (scan->channel_count == 0) {
IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
goto done;
@@ -831,7 +941,12 @@ void iwl_bg_scan_completed(struct work_struct *work)
cancel_delayed_work(&priv->scan_check);
- ieee80211_scan_completed(priv->hw, false);
+ if (!priv->is_internal_short_scan)
+ ieee80211_scan_completed(priv->hw, false);
+ else {
+ priv->is_internal_short_scan = false;
+ IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
+ }
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c
deleted file mode 100644
index 1ea5cd345fe8..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-spectrum.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/wireless.h>
-
-#include <net/mac80211.h>
-
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-core.h"
-#include "iwl-io.h"
-#include "iwl-spectrum.h"
-
-#define BEACON_TIME_MASK_LOW 0x00FFFFFF
-#define BEACON_TIME_MASK_HIGH 0xFF000000
-#define TIME_UNIT 1024
-
-/*
- * extended beacon time format
- * time in usec will be changed into a 32-bit value in 8:24 format
- * the high 1 byte is the beacon counts
- * the lower 3 bytes is the time in usec within one beacon interval
- */
-
-/* TOOD: was used in sysfs debug interface need to add to mac */
-#if 0
-static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
-{
- u32 quot;
- u32 rem;
- u32 interval = beacon_interval * 1024;
-
- if (!interval || !usec)
- return 0;
-
- quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
- rem = (usec % interval) & BEACON_TIME_MASK_LOW;
-
- return (quot << 24) + rem;
-}
-
-/* base is usually what we get from ucode with each received frame,
- * the same as HW timer counter counting down
- */
-
-static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
-{
- u32 base_low = base & BEACON_TIME_MASK_LOW;
- u32 addon_low = addon & BEACON_TIME_MASK_LOW;
- u32 interval = beacon_interval * TIME_UNIT;
- u32 res = (base & BEACON_TIME_MASK_HIGH) +
- (addon & BEACON_TIME_MASK_HIGH);
-
- if (base_low > addon_low)
- res += base_low - addon_low;
- else if (base_low < addon_low) {
- res += interval + base_low - addon_low;
- res += (1 << 24);
- } else
- res += (1 << 24);
-
- return cpu_to_le32(res);
-}
-static int iwl_get_measurement(struct iwl_priv *priv,
- struct ieee80211_measurement_params *params,
- u8 type)
-{
- struct iwl4965_spectrum_cmd spectrum;
- struct iwl_rx_packet *res;
- struct iwl_host_cmd cmd = {
- .id = REPLY_SPECTRUM_MEASUREMENT_CMD,
- .data = (void *)&spectrum,
- .meta.flags = CMD_WANT_SKB,
- };
- u32 add_time = le64_to_cpu(params->start_time);
- int rc;
- int spectrum_resp_status;
- int duration = le16_to_cpu(params->duration);
-
- if (iwl_is_associated(priv))
- add_time =
- iwl_usecs_to_beacons(
- le64_to_cpu(params->start_time) - priv->last_tsf,
- le16_to_cpu(priv->rxon_timing.beacon_interval));
-
- memset(&spectrum, 0, sizeof(spectrum));
-
- spectrum.channel_count = cpu_to_le16(1);
- spectrum.flags =
- RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
- spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
- cmd.len = sizeof(spectrum);
- spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
-
- if (iwl_is_associated(priv))
- spectrum.start_time =
- iwl_add_beacon_time(priv->last_beacon_time,
- add_time,
- le16_to_cpu(priv->rxon_timing.beacon_interval));
- else
- spectrum.start_time = 0;
-
- spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
- spectrum.channels[0].channel = params->channel;
- spectrum.channels[0].type = type;
- if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
- spectrum.flags |= RXON_FLG_BAND_24G_MSK |
- RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
-
- rc = iwl_send_cmd_sync(priv, &cmd);
- if (rc)
- return rc;
-
- res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
- IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n");
- rc = -EIO;
- }
-
- spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
- switch (spectrum_resp_status) {
- case 0: /* Command will be handled */
- if (res->u.spectrum.id != 0xff) {
- IWL_DEBUG_INFO(priv,
- "Replaced existing measurement: %d\n",
- res->u.spectrum.id);
- priv->measurement_status &= ~MEASUREMENT_READY;
- }
- priv->measurement_status |= MEASUREMENT_ACTIVE;
- rc = 0;
- break;
-
- case 1: /* Command will not be handled */
- rc = -EAGAIN;
- break;
- }
-
- dev_kfree_skb_any(cmd.meta.u.skb);
-
- return rc;
-}
-#endif
-
-static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
-{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
-
- if (!report->state) {
- IWL_DEBUG_11H(priv,
- "Spectrum Measure Notification: Start\n");
- return;
- }
-
- memcpy(&priv->measure_report, report, sizeof(*report));
- priv->measurement_status |= MEASUREMENT_READY;
-}
-
-void iwl_setup_spectrum_handlers(struct iwl_priv *priv)
-{
- priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
- iwl_rx_spectrum_measure_notif;
-}
-EXPORT_SYMBOL(iwl_setup_spectrum_handlers);
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
index a77c1e619062..af6babee2891 100644
--- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ieee80211 subsystem header files.
*
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index cde09a890b73..4a6686fa6b36 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -80,46 +80,103 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
}
EXPORT_SYMBOL(iwl_get_ra_sta_id);
+/* priv->sta_lock must be held */
static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
- IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n",
- sta_id);
-
- priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
- IWL_DEBUG_ASSOC(priv, "Added STA to Ucode: %pM\n",
- priv->stations[sta_id].sta.sta.addr);
+ IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u addr %pM\n",
+ sta_id, priv->stations[sta_id].sta.sta.addr);
- spin_unlock_irqrestore(&priv->sta_lock, flags);
+ if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) {
+ IWL_DEBUG_ASSOC(priv,
+ "STA id %u addr %pM already present in uCode (according to driver)\n",
+ sta_id, priv->stations[sta_id].sta.sta.addr);
+ } else {
+ priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
+ IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n",
+ sta_id, priv->stations[sta_id].sta.sta.addr);
+ }
}
-static void iwl_add_sta_callback(struct iwl_priv *priv,
- struct iwl_device_cmd *cmd,
- struct iwl_rx_packet *pkt)
+static void iwl_process_add_sta_resp(struct iwl_priv *priv,
+ struct iwl_addsta_cmd *addsta,
+ struct iwl_rx_packet *pkt,
+ bool sync)
{
- struct iwl_addsta_cmd *addsta =
- (struct iwl_addsta_cmd *)cmd->cmd.payload;
u8 sta_id = addsta->sta.sta_id;
+ unsigned long flags;
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
- pkt->hdr.flags);
+ pkt->hdr.flags);
return;
}
+ IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
+ sta_id);
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
switch (pkt->u.add_sta.status) {
case ADD_STA_SUCCESS_MSK:
+ IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
iwl_sta_ucode_activate(priv, sta_id);
- /* fall through */
+ break;
+ case ADD_STA_NO_ROOM_IN_TABLE:
+ IWL_ERR(priv, "Adding station %d failed, no room in table.\n",
+ sta_id);
+ break;
+ case ADD_STA_NO_BLOCK_ACK_RESOURCE:
+ IWL_ERR(priv, "Adding station %d failed, no block ack resource.\n",
+ sta_id);
+ break;
+ case ADD_STA_MODIFY_NON_EXIST_STA:
+ IWL_ERR(priv, "Attempting to modify non-existing station %d \n",
+ sta_id);
+ break;
default:
- IWL_DEBUG_HC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
- pkt->u.add_sta.status);
+ IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
+ pkt->u.add_sta.status);
break;
}
+
+ IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n",
+ priv->stations[sta_id].sta.mode ==
+ STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
+ sta_id, priv->stations[sta_id].sta.sta.addr);
+
+ /*
+ * XXX: The MAC address in the command buffer is often changed from
+ * the original sent to the device. That is, the MAC address
+ * written to the command buffer often is not the same MAC adress
+ * read from the command buffer when the command returns. This
+ * issue has not yet been resolved and this debugging is left to
+ * observe the problem.
+ */
+ IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n",
+ priv->stations[sta_id].sta.mode ==
+ STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
+ addsta->sta.addr);
+
+ /*
+ * Determine if we wanted to modify or add a station,
+ * if adding a station succeeded we have some more initialization
+ * to do when using station notification. TODO
+ */
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+
+static void iwl_add_sta_callback(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct iwl_rx_packet *pkt)
+{
+ struct iwl_addsta_cmd *addsta =
+ (struct iwl_addsta_cmd *)cmd->cmd.payload;
+
+ iwl_process_add_sta_resp(priv, addsta, pkt, false);
+
}
int iwl_send_add_sta(struct iwl_priv *priv,
@@ -145,24 +202,9 @@ int iwl_send_add_sta(struct iwl_priv *priv,
if (ret || (flags & CMD_ASYNC))
return ret;
- pkt = (struct iwl_rx_packet *)cmd.reply_page;
- if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
- IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
- pkt->hdr.flags);
- ret = -EIO;
- }
-
if (ret == 0) {
- switch (pkt->u.add_sta.status) {
- case ADD_STA_SUCCESS_MSK:
- iwl_sta_ucode_activate(priv, sta->sta.sta_id);
- IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
- break;
- default:
- ret = -EIO;
- IWL_WARN(priv, "REPLY_ADD_STA failed\n");
- break;
- }
+ pkt = (struct iwl_rx_packet *)cmd.reply_page;
+ iwl_process_add_sta_resp(priv, sta, pkt, true);
}
iwl_free_pages(priv, cmd.reply_page);
@@ -297,7 +339,7 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags,
}
EXPORT_SYMBOL(iwl_add_station);
-static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
+static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const u8 *addr)
{
unsigned long flags;
u8 sta_id = iwl_find_station(priv, addr);
@@ -324,7 +366,7 @@ static void iwl_remove_sta_callback(struct iwl_priv *priv,
{
struct iwl_rem_sta_cmd *rm_sta =
(struct iwl_rem_sta_cmd *)cmd->cmd.payload;
- const char *addr = rm_sta->addr;
+ const u8 *addr = rm_sta->addr;
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
@@ -1003,24 +1045,19 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap)
struct ieee80211_sta_ht_cap *cur_ht_config = NULL;
u8 sta_id;
- /* Add station to device's station table */
-
/*
- * XXX: This check is definitely not correct, if we're an AP
- * it'll always be false which is not what we want, but
- * it doesn't look like iwlagn is prepared to be an HT
- * AP anyway.
+ * Set HT capabilities. It is ok to set this struct even if not using
+ * HT config: the priv->current_ht_config.is_ht flag will just be false
*/
- if (priv->current_ht_config.is_ht) {
- rcu_read_lock();
- sta = ieee80211_find_sta(priv->vif, addr);
- if (sta) {
- memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config));
- cur_ht_config = &ht_config;
- }
- rcu_read_unlock();
+ rcu_read_lock();
+ sta = ieee80211_find_sta(priv->vif, addr);
+ if (sta) {
+ memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config));
+ cur_ht_config = &ht_config;
}
+ rcu_read_unlock();
+ /* Add station to device's station table */
sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config);
/* Set up default rate scaling table in device's station table */
@@ -1085,6 +1122,7 @@ static void iwl_sta_init_bcast_lq(struct iwl_priv *priv)
*/
void iwl_add_bcast_station(struct iwl_priv *priv)
{
+ IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n");
iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL);
/* Set up default rate scaling table in device's station table */
@@ -1093,6 +1131,16 @@ void iwl_add_bcast_station(struct iwl_priv *priv)
EXPORT_SYMBOL(iwl_add_bcast_station);
/**
+ * iwl3945_add_bcast_station - add broadcast station into station table.
+ */
+void iwl3945_add_bcast_station(struct iwl_priv *priv)
+{
+ IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n");
+ iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL);
+}
+EXPORT_SYMBOL(iwl3945_add_bcast_station);
+
+/**
* iwl_get_sta_id - Find station's index within station table
*
* If new IBSS station, create new entry in station table
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index 8d052de2d405..2dc35fe28f56 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -53,6 +53,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap);
void iwl_add_bcast_station(struct iwl_priv *priv);
+void iwl3945_add_bcast_station(struct iwl_priv *priv);
int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap);
void iwl_clear_stations_table(struct iwl_priv *priv);
int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 87ce2bd292c7..1ed5206721ec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -60,7 +60,8 @@ static const u16 default_tid_to_tx_fifo[] = {
static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv,
struct iwl_dma_ptr *ptr, size_t size)
{
- ptr->addr = pci_alloc_consistent(priv->pci_dev, size, &ptr->dma);
+ ptr->addr = dma_alloc_coherent(&priv->pci_dev->dev, size, &ptr->dma,
+ GFP_KERNEL);
if (!ptr->addr)
return -ENOMEM;
ptr->size = size;
@@ -73,21 +74,20 @@ static inline void iwl_free_dma_ptr(struct iwl_priv *priv,
if (unlikely(!ptr->addr))
return;
- pci_free_consistent(priv->pci_dev, ptr->size, ptr->addr, ptr->dma);
+ dma_free_coherent(&priv->pci_dev->dev, ptr->size, ptr->addr, ptr->dma);
memset(ptr, 0, sizeof(*ptr));
}
/**
* iwl_txq_update_write_ptr - Send new write index to hardware
*/
-int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
{
u32 reg = 0;
- int ret = 0;
int txq_id = txq->q.id;
if (txq->need_update == 0)
- return ret;
+ return;
/* if we're trying to save power */
if (test_bit(STATUS_POWER_PMI, &priv->status)) {
@@ -101,7 +101,7 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
txq_id, reg);
iwl_set_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- return ret;
+ return;
}
iwl_write_direct32(priv, HBUS_TARG_WRPTR,
@@ -114,12 +114,24 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
txq->q.write_ptr | (txq_id << 8));
txq->need_update = 0;
-
- return ret;
}
EXPORT_SYMBOL(iwl_txq_update_write_ptr);
+void iwl_free_tfds_in_queue(struct iwl_priv *priv,
+ int sta_id, int tid, int freed)
+{
+ if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
+ priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+ else {
+ IWL_ERR(priv, "free more than tfds_in_queue (%u:%d)\n",
+ priv->stations[sta_id].tid[tid].tfds_in_queue,
+ freed);
+ priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
+ }
+}
+EXPORT_SYMBOL(iwl_free_tfds_in_queue);
+
/**
* iwl_tx_queue_free - Deallocate DMA queue.
* @txq: Transmit queue to deallocate.
@@ -132,7 +144,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
{
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct iwl_queue *q = &txq->q;
- struct pci_dev *dev = priv->pci_dev;
+ struct device *dev = &priv->pci_dev->dev;
int i;
if (q->n_bd == 0)
@@ -149,8 +161,8 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
/* De-alloc circular buffer of TFDs */
if (txq->q.n_bd)
- pci_free_consistent(dev, priv->hw_params.tfd_size *
- txq->q.n_bd, txq->tfds, txq->q.dma_addr);
+ dma_free_coherent(dev, priv->hw_params.tfd_size *
+ txq->q.n_bd, txq->tfds, txq->q.dma_addr);
/* De-alloc array of per-TFD driver data */
kfree(txq->txb);
@@ -179,7 +191,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
{
struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
struct iwl_queue *q = &txq->q;
- struct pci_dev *dev = priv->pci_dev;
+ struct device *dev = &priv->pci_dev->dev;
int i;
if (q->n_bd == 0)
@@ -191,8 +203,8 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
/* De-alloc circular buffer of TFDs */
if (txq->q.n_bd)
- pci_free_consistent(dev, priv->hw_params.tfd_size *
- txq->q.n_bd, txq->tfds, txq->q.dma_addr);
+ dma_free_coherent(dev, priv->hw_params.tfd_size * txq->q.n_bd,
+ txq->tfds, txq->q.dma_addr);
/* deallocate arrays */
kfree(txq->cmd);
@@ -283,7 +295,7 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
static int iwl_tx_queue_alloc(struct iwl_priv *priv,
struct iwl_tx_queue *txq, u32 id)
{
- struct pci_dev *dev = priv->pci_dev;
+ struct device *dev = &priv->pci_dev->dev;
size_t tfd_sz = priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX;
/* Driver private data, only for Tx (not command) queues,
@@ -302,8 +314,8 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
/* Circular buffer of transmit frame descriptors (TFDs),
* shared with device */
- txq->tfds = pci_alloc_consistent(dev, tfd_sz, &txq->q.dma_addr);
-
+ txq->tfds = dma_alloc_coherent(dev, tfd_sz, &txq->q.dma_addr,
+ GFP_KERNEL);
if (!txq->tfds) {
IWL_ERR(priv, "pci_alloc_consistent(%zd) failed\n", tfd_sz);
goto error;
@@ -352,7 +364,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
for (i = 0; i < actual_slots; i++) {
/* only happens for cmd queue */
if (i == slots_num)
- len += IWL_MAX_SCAN_SIZE;
+ len = IWL_MAX_CMD_SIZE;
txq->cmd[i] = kmalloc(len, GFP_KERNEL);
if (!txq->cmd[i])
@@ -731,7 +743,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
u8 tid = 0;
u8 *qc = NULL;
unsigned long flags;
- int ret;
spin_lock_irqsave(&priv->lock, flags);
if (iwl_is_rfkill(priv)) {
@@ -806,8 +817,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr->seq_ctrl |= cpu_to_le16(seq_number);
seq_number += 0x10;
/* aggregation is on for this <sta,tid> */
- if (info->flags & IEEE80211_TX_CTL_AMPDU)
+ if (info->flags & IEEE80211_TX_CTL_AMPDU &&
+ priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) {
txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
+ }
}
txq = &priv->txq[txq_id];
@@ -949,7 +962,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Tell device the write index *just past* this latest filled TFD */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
- ret = iwl_txq_update_write_ptr(priv, txq);
+ iwl_txq_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->lock, flags);
/*
@@ -963,9 +976,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (sta_priv && sta_priv->client)
atomic_inc(&sta_priv->pending_frames);
- if (ret)
- return ret;
-
if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
if (wait_write_ptr) {
spin_lock_irqsave(&priv->lock, flags);
@@ -1004,7 +1014,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
struct iwl_cmd_meta *out_meta;
dma_addr_t phys_addr;
unsigned long flags;
- int len, ret;
+ int len;
u32 idx;
u16 fix_size;
@@ -1013,9 +1023,12 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
/* If any of the command structures end up being larger than
* the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
- * we will need to increase the size of the TFD entries */
+ * we will need to increase the size of the TFD entries
+ * Also, check to see if command buffer should not exceed the size
+ * of device_cmd and max_cmd_size. */
BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
!(cmd->flags & CMD_SIZE_HUGE));
+ BUG_ON(fix_size > IWL_MAX_CMD_SIZE);
if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
IWL_WARN(priv, "Not sending command - %s KILL\n",
@@ -1059,8 +1072,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
if (cmd->flags & CMD_SIZE_HUGE)
out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
len = sizeof(struct iwl_device_cmd);
- len += (idx == TFD_CMD_SLOTS) ? IWL_MAX_SCAN_SIZE : 0;
-
+ if (idx == TFD_CMD_SLOTS)
+ len = IWL_MAX_CMD_SIZE;
#ifdef CONFIG_IWLWIFI_DEBUG
switch (out_cmd->hdr.cmd) {
@@ -1101,10 +1114,10 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
/* Increment and update queue's write index */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
- ret = iwl_txq_update_write_ptr(priv, txq);
+ iwl_txq_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->hcmd_lock, flags);
- return ret ? ret : idx;
+ return idx;
}
static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
@@ -1131,6 +1144,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
struct iwl_queue *q = &txq->q;
struct iwl_tx_info *tx_info;
int nfreed = 0;
+ struct ieee80211_hdr *hdr;
if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, "
@@ -1145,13 +1159,16 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
tx_info = &txq->txb[txq->q.read_ptr];
iwl_tx_status(priv, tx_info->skb[0]);
+
+ hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
+ if (hdr && ieee80211_is_data_qos(hdr->frame_control))
+ nfreed++;
tx_info->skb[0] = NULL;
if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
priv->cfg->ops->lib->txq_free_tfd(priv, txq);
- nfreed++;
}
return nfreed;
}
@@ -1242,6 +1259,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
if (!(meta->flags & CMD_ASYNC)) {
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
+ get_cmd_string(cmd->hdr.cmd));
wake_up_interruptible(&priv->wait_command_queue);
}
}
@@ -1328,7 +1347,7 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
{
int tx_fifo_id, txq_id, sta_id, ssn = -1;
struct iwl_tid_data *tid_data;
- int ret, write_ptr, read_ptr;
+ int write_ptr, read_ptr;
unsigned long flags;
if (!ra) {
@@ -1380,13 +1399,17 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
spin_lock_irqsave(&priv->lock, flags);
- ret = priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
+ /*
+ * the only reason this call can fail is queue number out of range,
+ * which can happen if uCode is reloaded and all the station
+ * information are lost. if it is outside the range, there is no need
+ * to deactivate the uCode queue, just return "success" to allow
+ * mac80211 to clean up it own data.
+ */
+ priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
tx_fifo_id);
spin_unlock_irqrestore(&priv->lock, flags);
- if (ret)
- return ret;
-
ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid);
return 0;
@@ -1559,7 +1582,7 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
/* calculate mac80211 ampdu sw queue to wake */
int freed = iwl_tx_queue_reclaim(priv, scd_flow, index);
- priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+ iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
if ((iwl_queue_space(&txq->q) > txq->q.low_mark) &&
priv->mac80211_registered &&
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index f8e4e4b18d02..54daa38ecba3 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -53,9 +53,10 @@
#include "iwl-commands.h"
#include "iwl-sta.h"
#include "iwl-3945.h"
-#include "iwl-helpers.h"
#include "iwl-core.h"
+#include "iwl-helpers.h"
#include "iwl-dev.h"
+#include "iwl-spectrum.h"
/*
* module name, copyright, version, etc.
@@ -70,14 +71,13 @@
#define VD
#endif
-#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
-#define VS "s"
-#else
-#define VS
-#endif
-
-#define DRV_VERSION IWLWIFI_VERSION VD VS
-#define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation"
+/*
+ * add "s" to indicate spectrum measurement included.
+ * we add it here to be consistent with previous releases in which
+ * this was configurable.
+ */
+#define DRV_VERSION IWLWIFI_VERSION VD "s"
+#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation"
#define DRV_AUTHOR "<ilw@linux.intel.com>"
MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -352,10 +352,10 @@ static int iwl3945_send_beacon_cmd(struct iwl_priv *priv)
static void iwl3945_unset_hw_params(struct iwl_priv *priv)
{
if (priv->shared_virt)
- pci_free_consistent(priv->pci_dev,
- sizeof(struct iwl3945_shared),
- priv->shared_virt,
- priv->shared_phys);
+ dma_free_coherent(&priv->pci_dev->dev,
+ sizeof(struct iwl3945_shared),
+ priv->shared_virt,
+ priv->shared_phys);
}
static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
@@ -478,7 +478,6 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
u8 wait_write_ptr = 0;
u8 *qc = NULL;
unsigned long flags;
- int rc;
spin_lock_irqsave(&priv->lock, flags);
if (iwl_is_rfkill(priv)) {
@@ -663,12 +662,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Tell device the write index *just past* this latest filled TFD */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
- rc = iwl_txq_update_write_ptr(priv, txq);
+ iwl_txq_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->lock, flags);
- if (rc)
- return rc;
-
if ((iwl_queue_space(q) < q->high_mark)
&& priv->mac80211_registered) {
if (wait_write_ptr) {
@@ -689,10 +685,6 @@ drop:
return -1;
}
-#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
-
-#include "iwl-spectrum.h"
-
#define BEACON_TIME_MASK_LOW 0x00FFFFFF
#define BEACON_TIME_MASK_HIGH 0xFF000000
#define TIME_UNIT 1024
@@ -819,7 +811,6 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
return rc;
}
-#endif
static void iwl3945_rx_reply_alive(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
@@ -962,6 +953,8 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv)
priv->rx_handlers[REPLY_ADD_STA] = iwl3945_rx_reply_add_sta;
priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+ priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+ iwl_rx_spectrum_measure_notif;
priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
iwl_rx_pm_debug_statistics_notif;
@@ -975,7 +968,6 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv)
priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics;
priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics;
- iwl_setup_spectrum_handlers(priv);
iwl_setup_rx_scan_handlers(priv);
priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif;
@@ -1067,13 +1059,13 @@ static inline __le32 iwl3945_dma_addr2rbd_ptr(struct iwl_priv *priv,
* also updates the memory address in the firmware to reference the new
* target buffer.
*/
-static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
+static void iwl3945_rx_queue_restock(struct iwl_priv *priv)
{
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
unsigned long flags;
- int write, rc;
+ int write;
spin_lock_irqsave(&rxq->lock, flags);
write = rxq->write & ~0x7;
@@ -1103,12 +1095,8 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
spin_lock_irqsave(&rxq->lock, flags);
rxq->need_update = 1;
spin_unlock_irqrestore(&rxq->lock, flags);
- rc = iwl_rx_queue_update_write_ptr(priv, rxq);
- if (rc)
- return rc;
+ iwl_rx_queue_update_write_ptr(priv, rxq);
}
-
- return 0;
}
/**
@@ -1253,10 +1241,10 @@ static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rx
}
}
- pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
- rxq->dma_addr);
- pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status),
- rxq->rb_stts, rxq->rb_stts_dma);
+ dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+ rxq->dma_addr);
+ dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
+ rxq->rb_stts, rxq->rb_stts_dma);
rxq->bd = NULL;
rxq->rb_stts = NULL;
}
@@ -1518,8 +1506,9 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
* iwl3945_print_event_log - Dump error event log to syslog
*
*/
-static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
- u32 num_events, u32 mode)
+static int iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
+ u32 num_events, u32 mode,
+ int pos, char **buf, size_t bufsz)
{
u32 i;
u32 base; /* SRAM byte address of event log header */
@@ -1529,7 +1518,7 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
unsigned long reg_flags;
if (num_events == 0)
- return;
+ return pos;
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
@@ -1555,26 +1544,43 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
if (mode == 0) {
/* data, ev */
- IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
- trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
+ if (bufsz) {
+ pos += scnprintf(*buf + pos, bufsz - pos,
+ "0x%08x:%04u\n",
+ time, ev);
+ } else {
+ IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
+ trace_iwlwifi_dev_ucode_event(priv, 0,
+ time, ev);
+ }
} else {
data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
- IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev);
- trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
+ if (bufsz) {
+ pos += scnprintf(*buf + pos, bufsz - pos,
+ "%010u:0x%08x:%04u\n",
+ time, data, ev);
+ } else {
+ IWL_ERR(priv, "%010u\t0x%08x\t%04u\n",
+ time, data, ev);
+ trace_iwlwifi_dev_ucode_event(priv, time,
+ data, ev);
+ }
}
}
/* Allow device to power down */
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+ return pos;
}
/**
* iwl3945_print_last_event_logs - Dump the newest # of event log to syslog
*/
-static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
+static int iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
u32 num_wraps, u32 next_entry,
- u32 size, u32 mode)
+ u32 size, u32 mode,
+ int pos, char **buf, size_t bufsz)
{
/*
* display the newest DEFAULT_LOG_ENTRIES entries
@@ -1582,21 +1588,28 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
*/
if (num_wraps) {
if (next_entry < size) {
- iwl3945_print_event_log(priv,
- capacity - (size - next_entry),
- size - next_entry, mode);
- iwl3945_print_event_log(priv, 0,
- next_entry, mode);
+ pos = iwl3945_print_event_log(priv,
+ capacity - (size - next_entry),
+ size - next_entry, mode,
+ pos, buf, bufsz);
+ pos = iwl3945_print_event_log(priv, 0,
+ next_entry, mode,
+ pos, buf, bufsz);
} else
- iwl3945_print_event_log(priv, next_entry - size,
- size, mode);
+ pos = iwl3945_print_event_log(priv, next_entry - size,
+ size, mode,
+ pos, buf, bufsz);
} else {
if (next_entry < size)
- iwl3945_print_event_log(priv, 0, next_entry, mode);
+ pos = iwl3945_print_event_log(priv, 0,
+ next_entry, mode,
+ pos, buf, bufsz);
else
- iwl3945_print_event_log(priv, next_entry - size,
- size, mode);
+ pos = iwl3945_print_event_log(priv, next_entry - size,
+ size, mode,
+ pos, buf, bufsz);
}
+ return pos;
}
/* For sanity check only. Actual size is determined by uCode, typ. 512 */
@@ -1604,7 +1617,8 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
#define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20)
-void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
+int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+ char **buf, bool display)
{
u32 base; /* SRAM byte address of event log header */
u32 capacity; /* event log capacity in # entries */
@@ -1612,11 +1626,13 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
u32 num_wraps; /* # times uCode wrapped to top of log */
u32 next_entry; /* index of next entry to be written by uCode */
u32 size; /* # entries that we'll print */
+ int pos = 0;
+ size_t bufsz = 0;
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
if (!iwl3945_hw_valid_rtc_data_addr(base)) {
IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
- return;
+ return -EINVAL;
}
/* event log header */
@@ -1642,7 +1658,7 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
/* bail out if nothing in log */
if (size == 0) {
IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
- return;
+ return pos;
}
#ifdef CONFIG_IWLWIFI_DEBUG
@@ -1658,25 +1674,38 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
size);
#ifdef CONFIG_IWLWIFI_DEBUG
+ if (display) {
+ if (full_log)
+ bufsz = capacity * 48;
+ else
+ bufsz = size * 48;
+ *buf = kmalloc(bufsz, GFP_KERNEL);
+ if (!*buf)
+ return -ENOMEM;
+ }
if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
/* if uCode has wrapped back to top of log,
* start at the oldest entry,
* i.e the next one that uCode would fill.
*/
if (num_wraps)
- iwl3945_print_event_log(priv, next_entry,
- capacity - next_entry, mode);
+ pos = iwl3945_print_event_log(priv, next_entry,
+ capacity - next_entry, mode,
+ pos, buf, bufsz);
/* (then/else) start at top of log */
- iwl3945_print_event_log(priv, 0, next_entry, mode);
+ pos = iwl3945_print_event_log(priv, 0, next_entry, mode,
+ pos, buf, bufsz);
} else
- iwl3945_print_last_event_logs(priv, capacity, num_wraps,
- next_entry, size, mode);
+ pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps,
+ next_entry, size, mode,
+ pos, buf, bufsz);
#else
- iwl3945_print_last_event_logs(priv, capacity, num_wraps,
- next_entry, size, mode);
+ pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps,
+ next_entry, size, mode,
+ pos, buf, bufsz);
#endif
-
+ return pos;
}
static void iwl3945_irq_tasklet(struct iwl_priv *priv)
@@ -2996,18 +3025,6 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
mutex_unlock(&priv->mutex);
}
-static void iwl3945_bg_up(struct work_struct *data)
-{
- struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- mutex_lock(&priv->mutex);
- __iwl3945_up(priv);
- mutex_unlock(&priv->mutex);
-}
-
static void iwl3945_bg_restart(struct work_struct *data)
{
struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
@@ -3024,7 +3041,13 @@ static void iwl3945_bg_restart(struct work_struct *data)
ieee80211_restart_hw(priv->hw);
} else {
iwl3945_down(priv);
- queue_work(priv->workqueue, &priv->up);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ __iwl3945_up(priv);
+ mutex_unlock(&priv->mutex);
}
}
@@ -3528,8 +3551,6 @@ static ssize_t store_filter_flags(struct device *d,
static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
store_filter_flags);
-#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
-
static ssize_t show_measurement(struct device *d,
struct device_attribute *attr, char *buf)
{
@@ -3599,7 +3620,6 @@ static ssize_t store_measurement(struct device *d,
static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
show_measurement, store_measurement);
-#endif /* CONFIG_IWL3945_SPECTRUM_MEASUREMENT */
static ssize_t store_retry_rate(struct device *d,
struct device_attribute *attr,
@@ -3748,7 +3768,6 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
init_waitqueue_head(&priv->wait_command_queue);
- INIT_WORK(&priv->up, iwl3945_bg_up);
INIT_WORK(&priv->restart, iwl3945_bg_restart);
INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish);
INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
@@ -3782,9 +3801,7 @@ static struct attribute *iwl3945_sysfs_entries[] = {
&dev_attr_dump_errors.attr,
&dev_attr_flags.attr,
&dev_attr_filter_flags.attr,
-#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
&dev_attr_measurement.attr,
-#endif
&dev_attr_retry_rate.attr,
&dev_attr_statistics.attr,
&dev_attr_status.attr,
@@ -3810,7 +3827,6 @@ static struct ieee80211_ops iwl3945_hw_ops = {
.config = iwl_mac_config,
.configure_filter = iwl_configure_filter,
.set_key = iwl3945_mac_set_key,
- .get_tx_stats = iwl_mac_get_tx_stats,
.conf_tx = iwl_mac_conf_tx,
.reset_tsf = iwl_mac_reset_tsf,
.bss_info_changed = iwl_bss_info_changed,
@@ -3831,6 +3847,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
INIT_LIST_HEAD(&priv->free_frames);
mutex_init(&priv->mutex);
+ mutex_init(&priv->sync_cmd_mutex);
/* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv);
@@ -3840,6 +3857,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
priv->band = IEEE80211_BAND_2GHZ;
priv->iw_mode = NL80211_IFTYPE_STATION;
+ priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
iwl_reset_qos(priv);
@@ -4022,6 +4040,13 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
spin_lock_init(&priv->reg_lock);
spin_lock_init(&priv->lock);
+ /*
+ * stop and reset the on-board processor just in case it is in a
+ * strange state ... like being left stranded by a primary kernel
+ * and this is now the kdump kernel trying to start up
+ */
+ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
/***********************
* 4. Read EEPROM
* ********************/
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 777584d76a88..1e41ad0fcad5 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -973,6 +973,10 @@ int iwm_send_pmkid_update(struct iwm_priv *iwm,
memset(&update, 0, sizeof(struct iwm_umac_pmkid_update));
+ update.hdr.oid = UMAC_WIFI_IF_CMD_PMKID_UPDATE;
+ update.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_pmkid_update) -
+ sizeof(struct iwm_umac_wifi_if));
+
update.command = cpu_to_le32(command);
if (pmksa->bssid)
memcpy(&update.bssid, pmksa->bssid, ETH_ALEN);
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index 06af0552cd75..3dfd9f0e9003 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -463,6 +463,7 @@ struct iwm_umac_cmd_stop_resume_tx {
#define IWM_CMD_PMKID_FLUSH 3
struct iwm_umac_pmkid_update {
+ struct iwm_umac_wifi_if hdr;
__le32 command;
u8 bssid[ETH_ALEN];
__le16 reserved;
diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c
index be992ca41cf1..c29c994de0e2 100644
--- a/drivers/net/wireless/iwmc3200wifi/debugfs.c
+++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c
@@ -89,7 +89,7 @@ static int iwm_debugfs_dbg_modules_write(void *data, u64 val)
for (i = 0; i < __IWM_DM_NR; i++)
iwm->dbg.dbg_module[i] = 0;
- for_each_bit(bit, &iwm->dbg.dbg_modules, __IWM_DM_NR)
+ for_each_set_bit(bit, &iwm->dbg.dbg_modules, __IWM_DM_NR)
iwm->dbg.dbg_module[bit] = iwm->dbg.dbg_level;
return 0;
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 842811142bef..79ffa3b98d73 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -268,7 +268,7 @@ struct iwm_priv {
struct sk_buff_head rx_list;
struct list_head rx_tickets;
- struct list_head rx_packets[IWM_RX_ID_HASH + 1];
+ struct list_head rx_packets[IWM_RX_ID_HASH];
struct workqueue_struct *rx_wq;
struct work_struct rx_worker;
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
index a3a79b5e2898..a855a99e49b8 100644
--- a/drivers/net/wireless/iwmc3200wifi/lmac.h
+++ b/drivers/net/wireless/iwmc3200wifi/lmac.h
@@ -262,7 +262,7 @@ struct iwm_ct_kill_cfg_cmd {
/* Power Management */
#define POWER_TABLE_CMD 0x77
-#define SAVE_RESTORE_ADRESS_CMD 0x78
+#define SAVE_RESTORE_ADDRESS_CMD 0x78
#define REPLY_WATERMARK_CMD 0x79
#define PM_DEBUG_STATISTIC_NOTIFIC 0x7B
#define PD_FLUSH_N_NOTIFICATION 0x7C
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 6d6ed7485175..8456b4dbd146 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -794,7 +794,7 @@ static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf,
}
bss->bss = kzalloc(bss_len, GFP_KERNEL);
- if (!bss) {
+ if (!bss->bss) {
kfree(bss);
IWM_ERR(iwm, "Couldn't allocate bss\n");
return -ENOMEM;
@@ -868,36 +868,35 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
struct iwm_umac_notif_mgt_frame *mgt_frame =
(struct iwm_umac_notif_mgt_frame *)buf;
struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
- u8 *ie;
IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
le16_to_cpu(mgt_frame->len));
if (ieee80211_is_assoc_req(mgt->frame_control)) {
- ie = mgt->u.assoc_req.variable;;
- iwm->req_ie_len =
- le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
+ - offsetof(struct ieee80211_mgmt,
+ u.assoc_req.variable);
kfree(iwm->req_ie);
iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
iwm->req_ie_len, GFP_KERNEL);
} else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
- ie = mgt->u.reassoc_req.variable;;
- iwm->req_ie_len =
- le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
+ - offsetof(struct ieee80211_mgmt,
+ u.reassoc_req.variable);
kfree(iwm->req_ie);
iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
iwm->req_ie_len, GFP_KERNEL);
} else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
- ie = mgt->u.assoc_resp.variable;;
- iwm->resp_ie_len =
- le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
+ - offsetof(struct ieee80211_mgmt,
+ u.assoc_resp.variable);
kfree(iwm->resp_ie);
iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
iwm->resp_ie_len, GFP_KERNEL);
} else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
- ie = mgt->u.reassoc_resp.variable;;
- iwm->resp_ie_len =
- le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
+ - offsetof(struct ieee80211_mgmt,
+ u.reassoc_resp.variable);
kfree(iwm->resp_ie);
iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
iwm->resp_ie_len, GFP_KERNEL);
@@ -1117,7 +1116,7 @@ static int iwm_ntf_stop_resume_tx(struct iwm_priv *iwm, u8 *buf,
return -EINVAL;
}
- for_each_bit(bit, (unsigned long *)&tid_msk, IWM_UMAC_TID_NR) {
+ for_each_set_bit(bit, (unsigned long *)&tid_msk, IWM_UMAC_TID_NR) {
tid_info = &sta_info->tid_info[bit];
mutex_lock(&tid_info->mutex);
@@ -1534,6 +1533,33 @@ static void classify8023(struct sk_buff *skb)
}
}
+static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb)
+{
+ struct wireless_dev *wdev = iwm_to_wdev(iwm);
+ struct net_device *ndev = iwm_to_ndev(iwm);
+ struct sk_buff_head list;
+ struct sk_buff *frame;
+
+ IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len);
+
+ __skb_queue_head_init(&list);
+ ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0);
+
+ while ((frame = __skb_dequeue(&list))) {
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += frame->len;
+
+ frame->protocol = eth_type_trans(frame, ndev);
+ frame->ip_summed = CHECKSUM_NONE;
+ memset(frame->cb, 0, sizeof(frame->cb));
+
+ if (netif_rx_ni(frame) == NET_RX_DROP) {
+ IWM_ERR(iwm, "Packet dropped\n");
+ ndev->stats.rx_dropped++;
+ }
+ }
+}
+
static void iwm_rx_process_packet(struct iwm_priv *iwm,
struct iwm_rx_packet *packet,
struct iwm_rx_ticket_node *ticket_node)
@@ -1548,25 +1574,34 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
switch (le16_to_cpu(ticket_node->ticket->action)) {
case IWM_RX_TICKET_RELEASE:
IWM_DBG_RX(iwm, DBG, "RELEASE packet\n");
- classify8023(skb);
+
iwm_rx_adjust_packet(iwm, packet, ticket_node);
+ skb->dev = iwm_to_ndev(iwm);
+ classify8023(skb);
+
+ if (le16_to_cpu(ticket_node->ticket->flags) &
+ IWM_RX_TICKET_AMSDU_MSK) {
+ iwm_rx_process_amsdu(iwm, skb);
+ break;
+ }
+
ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype);
if (ret < 0) {
IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - "
"%d\n", ret);
+ kfree_skb(packet->skb);
break;
}
IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len);
- skb->dev = iwm_to_ndev(iwm);
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += skb->len;
+
skb->protocol = eth_type_trans(skb, ndev);
skb->ip_summed = CHECKSUM_NONE;
memset(skb->cb, 0, sizeof(skb->cb));
- ndev->stats.rx_packets++;
- ndev->stats.rx_bytes += skb->len;
-
if (netif_rx_ni(skb) == NET_RX_DROP) {
IWM_ERR(iwm, "Packet dropped\n");
ndev->stats.rx_dropped++;
diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig
index 30aa9d48d67e..0485c9957575 100644
--- a/drivers/net/wireless/libertas/Kconfig
+++ b/drivers/net/wireless/libertas/Kconfig
@@ -37,3 +37,9 @@ config LIBERTAS_DEBUG
depends on LIBERTAS
---help---
Debugging support.
+
+config LIBERTAS_MESH
+ bool "Enable mesh support"
+ depends on LIBERTAS
+ help
+ This enables Libertas' MESH support, used by e.g. the OLPC people.
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index b188cd97a053..45e870e33117 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -5,11 +5,11 @@ libertas-y += cmdresp.o
libertas-y += debugfs.o
libertas-y += ethtool.o
libertas-y += main.o
-libertas-y += mesh.o
libertas-y += rx.o
libertas-y += scan.o
libertas-y += tx.o
libertas-y += wext.o
+libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o
usb8xxx-objs += if_usb.o
libertas_cs-objs += if_cs.o
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index 751067369ba8..f03d5e4e59c3 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -390,10 +390,8 @@ int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
- if (!ret && cmd_action == CMD_ACT_GET) {
- priv->ratebitmap = le16_to_cpu(cmd.bitmap);
+ if (!ret && cmd_action == CMD_ACT_GET)
priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
- }
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
@@ -807,8 +805,7 @@ static int lbs_try_associate(struct lbs_private *priv,
}
/* Use short preamble only when both the BSS and firmware support it */
- if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
- (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
+ if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
preamble = RADIO_PREAMBLE_SHORT;
ret = lbs_set_radio(priv, preamble, 1);
@@ -939,8 +936,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
}
/* Use short preamble only when both the BSS and firmware support it */
- if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
- (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
+ if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
lbs_deb_join("AdhocJoin: Short preamble\n");
preamble = RADIO_PREAMBLE_SHORT;
}
@@ -1049,7 +1045,7 @@ static int lbs_adhoc_start(struct lbs_private *priv,
struct assoc_request *assoc_req)
{
struct cmd_ds_802_11_ad_hoc_start cmd;
- u8 preamble = RADIO_PREAMBLE_LONG;
+ u8 preamble = RADIO_PREAMBLE_SHORT;
size_t ratesize = 0;
u16 tmpcap = 0;
int ret = 0;
@@ -1057,11 +1053,6 @@ static int lbs_adhoc_start(struct lbs_private *priv,
lbs_deb_enter(LBS_DEB_ASSOC);
- if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
- lbs_deb_join("ADHOC_START: Will use short preamble\n");
- preamble = RADIO_PREAMBLE_SHORT;
- }
-
ret = lbs_set_radio(priv, preamble, 1);
if (ret)
goto out;
@@ -1169,11 +1160,11 @@ int lbs_adhoc_stop(struct lbs_private *priv)
static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
struct bss_descriptor *match_bss)
{
- if (!secinfo->wep_enabled && !secinfo->WPAenabled
- && !secinfo->WPA2enabled
- && match_bss->wpa_ie[0] != WLAN_EID_GENERIC
- && match_bss->rsn_ie[0] != WLAN_EID_RSN
- && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
+ if (!secinfo->wep_enabled &&
+ !secinfo->WPAenabled && !secinfo->WPA2enabled &&
+ match_bss->wpa_ie[0] != WLAN_EID_GENERIC &&
+ match_bss->rsn_ie[0] != WLAN_EID_RSN &&
+ !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
return 1;
else
return 0;
@@ -1182,9 +1173,9 @@ static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
struct bss_descriptor *match_bss)
{
- if (secinfo->wep_enabled && !secinfo->WPAenabled
- && !secinfo->WPA2enabled
- && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
+ if (secinfo->wep_enabled &&
+ !secinfo->WPAenabled && !secinfo->WPA2enabled &&
+ (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
return 1;
else
return 0;
@@ -1193,8 +1184,8 @@ static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
struct bss_descriptor *match_bss)
{
- if (!secinfo->wep_enabled && secinfo->WPAenabled
- && (match_bss->wpa_ie[0] == WLAN_EID_GENERIC)
+ if (!secinfo->wep_enabled && secinfo->WPAenabled &&
+ (match_bss->wpa_ie[0] == WLAN_EID_GENERIC)
/* privacy bit may NOT be set in some APs like LinkSys WRT54G
&& (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
)
@@ -1219,11 +1210,11 @@ static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
struct bss_descriptor *match_bss)
{
- if (!secinfo->wep_enabled && !secinfo->WPAenabled
- && !secinfo->WPA2enabled
- && (match_bss->wpa_ie[0] != WLAN_EID_GENERIC)
- && (match_bss->rsn_ie[0] != WLAN_EID_RSN)
- && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
+ if (!secinfo->wep_enabled &&
+ !secinfo->WPAenabled && !secinfo->WPA2enabled &&
+ (match_bss->wpa_ie[0] != WLAN_EID_GENERIC) &&
+ (match_bss->rsn_ie[0] != WLAN_EID_RSN) &&
+ (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
return 1;
else
return 0;
@@ -1534,8 +1525,8 @@ static int assoc_helper_associate(struct lbs_private *priv,
/* If we're given and 'any' BSSID, try associating based on SSID */
if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
- if (compare_ether_addr(bssid_any, assoc_req->bssid)
- && compare_ether_addr(bssid_off, assoc_req->bssid)) {
+ if (compare_ether_addr(bssid_any, assoc_req->bssid) &&
+ compare_ether_addr(bssid_off, assoc_req->bssid)) {
ret = assoc_helper_bssid(priv, assoc_req);
done = 1;
}
@@ -1621,11 +1612,9 @@ static int assoc_helper_channel(struct lbs_private *priv,
goto restore_mesh;
}
- if ( assoc_req->secinfo.wep_enabled
- && (assoc_req->wep_keys[0].len
- || assoc_req->wep_keys[1].len
- || assoc_req->wep_keys[2].len
- || assoc_req->wep_keys[3].len)) {
+ if (assoc_req->secinfo.wep_enabled &&
+ (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
+ assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)) {
/* Make sure WEP keys are re-sent to firmware */
set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
}
@@ -1992,14 +1981,14 @@ void lbs_association_worker(struct work_struct *work)
assoc_req->secinfo.auth_mode);
/* If 'any' SSID was specified, find an SSID to associate with */
- if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
- && !assoc_req->ssid_len)
+ if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) &&
+ !assoc_req->ssid_len)
find_any_ssid = 1;
/* But don't use 'any' SSID if there's a valid locked BSSID to use */
if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
- if (compare_ether_addr(assoc_req->bssid, bssid_any)
- && compare_ether_addr(assoc_req->bssid, bssid_off))
+ if (compare_ether_addr(assoc_req->bssid, bssid_any) &&
+ compare_ether_addr(assoc_req->bssid, bssid_off))
find_any_ssid = 0;
}
@@ -2061,13 +2050,6 @@ void lbs_association_worker(struct work_struct *work)
goto out;
}
- if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
- || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
- ret = assoc_helper_wep_keys(priv, assoc_req);
- if (ret)
- goto out;
- }
-
if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
ret = assoc_helper_secinfo(priv, assoc_req);
if (ret)
@@ -2080,18 +2062,31 @@ void lbs_association_worker(struct work_struct *work)
goto out;
}
- if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
- || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+ /*
+ * v10 FW wants WPA keys to be set/cleared before WEP key operations,
+ * otherwise it will fail to correctly associate to WEP networks.
+ * Other firmware versions don't appear to care.
+ */
+ if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) ||
+ test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
ret = assoc_helper_wpa_keys(priv, assoc_req);
if (ret)
goto out;
}
+ if (test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) ||
+ test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
+ ret = assoc_helper_wep_keys(priv, assoc_req);
+ if (ret)
+ goto out;
+ }
+
+
/* SSID/BSSID should be the _last_ config option set, because they
* trigger the association attempt.
*/
- if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
- || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) ||
+ test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
int success = 1;
ret = assoc_helper_associate(priv, assoc_req);
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 42611bea76a3..82371ef39524 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -143,19 +143,6 @@ int lbs_update_hw_spec(struct lbs_private *priv)
lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
cmd.hwifversion, cmd.version);
- /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
- /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
- /* 5.110.22 have mesh command with 0xa3 command id */
- /* 10.0.0.p0 FW brings in mesh config command with different id */
- /* Check FW version MSB and initialize mesh_fw_ver */
- if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
- priv->mesh_fw_ver = MESH_FW_OLD;
- else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
- (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK))
- priv->mesh_fw_ver = MESH_FW_NEW;
- else
- priv->mesh_fw_ver = MESH_NONE;
-
/* Clamp region code to 8-bit since FW spec indicates that it should
* only ever be 8-bit, even though the field size is 16-bit. Some firmware
* returns non-zero high 8 bits here.
@@ -855,9 +842,6 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
if (priv->fwrelease < 0x09000000) {
switch (preamble) {
case RADIO_PREAMBLE_SHORT:
- if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
- goto out;
- /* Fall through */
case RADIO_PREAMBLE_AUTO:
case RADIO_PREAMBLE_LONG:
cmd.control = cpu_to_le16(preamble);
@@ -1011,6 +995,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = 0;
break;
+#ifdef CONFIG_LIBERTAS_MESH
+
case CMD_BT_ACCESS:
ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
break;
@@ -1019,6 +1005,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
break;
+#endif
+
case CMD_802_11_BEACON_CTRL:
ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
break;
@@ -1317,7 +1305,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
if ((priv->psmode != LBS802_11POWERMODECAM) &&
(priv->psstate == PS_STATE_FULL_POWER) &&
((priv->connect_status == LBS_CONNECTED) ||
- (priv->mesh_connect_status == LBS_CONNECTED))) {
+ lbs_mesh_connected(priv))) {
if (priv->secinfo.WPAenabled ||
priv->secinfo.WPA2enabled) {
/* check for valid WPA group keys */
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 2862748aef70..cb4138a55fdf 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -110,18 +110,6 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val);
int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val);
-/* Mesh related */
-
-int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
- struct cmd_ds_mesh_access *cmd);
-
-int lbs_mesh_config_send(struct lbs_private *priv,
- struct cmd_ds_mesh_config *cmd,
- uint16_t action, uint16_t type);
-
-int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
-
-
/* Commands only used in wext.c, assoc. and scan.c */
int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 21d57690c20a..e7470442f76b 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -240,11 +240,6 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
/* Now we got response from FW, cancel the command timer */
del_timer(&priv->command_timer);
priv->cmd_timed_out = 0;
- if (priv->nr_retries) {
- lbs_pr_info("Received result %x to command %x after %d retries\n",
- result, curcmd, priv->nr_retries);
- priv->nr_retries = 0;
- }
/* Store the response code to cur_cmd_retcode. */
priv->cur_cmd_retcode = result;
@@ -485,20 +480,8 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
break;
case MACREG_INT_CODE_MESH_AUTO_STARTED:
- /* Ignore spurious autostart events if autostart is disabled */
- if (!priv->mesh_autostart_enabled) {
- lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
- break;
- }
- lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
- priv->mesh_connect_status = LBS_CONNECTED;
- if (priv->mesh_open) {
- netif_carrier_on(priv->mesh_dev);
- if (!priv->tx_pending_len)
- netif_wake_queue(priv->mesh_dev);
- }
- priv->mode = IW_MODE_ADHOC;
- schedule_work(&priv->sync_channel);
+ /* Ignore spurious autostart events */
+ lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
break;
default:
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 6b6ea9f7bf5b..ea3f10ef4e00 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -397,13 +397,6 @@ enum KEY_INFO_WPA {
KEY_INFO_WPA_ENABLED = 0x04
};
-/** mesh_fw_ver */
-enum _mesh_fw_ver {
- MESH_NONE = 0, /* MESH is not supported */
- MESH_FW_OLD, /* MESH is supported in FW V5 */
- MESH_FW_NEW, /* MESH is supported in FW V10 and newer */
-};
-
/* Default values for fwt commands. */
#define FWT_DEFAULT_METRIC 0
#define FWT_DEFAULT_DIR 1
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 05bb298dfae9..6977ee820214 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -39,15 +39,14 @@ struct lbs_private {
/* Mesh */
struct net_device *mesh_dev; /* Virtual device */
+#ifdef CONFIG_LIBERTAS_MESH
u32 mesh_connect_status;
struct lbs_mesh_stats mstats;
int mesh_open;
- int mesh_fw_ver;
- int mesh_autostart_enabled;
uint16_t mesh_tlv;
u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 mesh_ssid_len;
- struct work_struct sync_channel;
+#endif
/* Monitor mode */
struct net_device *rtap_net_dev;
@@ -110,7 +109,6 @@ struct lbs_private {
struct list_head cmdpendingq; /* pending command buffers */
wait_queue_head_t cmd_pending;
struct timer_list command_timer;
- int nr_retries;
int cmd_timed_out;
/* Command responses sent from the hardware to the driver */
@@ -176,9 +174,7 @@ struct lbs_private {
struct bss_descriptor *networks;
struct assoc_request * pending_assoc_req;
struct assoc_request * in_progress_assoc_req;
- u16 capability;
uint16_t enablehwauto;
- uint16_t ratebitmap;
/* ADHOC */
u16 beacon_period;
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 63d020374c2b..3804a58d7f4e 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -114,9 +114,11 @@ const struct ethtool_ops lbs_ethtool_ops = {
.get_drvinfo = lbs_ethtool_get_drvinfo,
.get_eeprom = lbs_ethtool_get_eeprom,
.get_eeprom_len = lbs_ethtool_get_eeprom_len,
+#ifdef CONFIG_LIBERTAS_MESH
.get_sset_count = lbs_mesh_ethtool_get_sset_count,
.get_ethtool_stats = lbs_mesh_ethtool_get_stats,
.get_strings = lbs_mesh_ethtool_get_strings,
+#endif
.get_wol = lbs_ethtool_get_wol,
.set_wol = lbs_ethtool_set_wol,
};
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index bf4bfbae6227..3ea03f259ee7 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -23,6 +23,7 @@
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/netdevice.h>
+#include <linux/semaphore.h>
#include <linux/spi/libertas_spi.h>
#include <linux/spi/spi.h>
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index c2975c8e2f21..28a1c9d1627a 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -123,7 +123,7 @@ static ssize_t lbs_rtap_set(struct device *dev,
if (priv->monitormode == monitor_mode)
return strlen(buf);
if (!priv->monitormode) {
- if (priv->infra_open || priv->mesh_open)
+ if (priv->infra_open || lbs_mesh_open(priv))
return -EBUSY;
if (priv->mode == IW_MODE_INFRA)
lbs_cmd_80211_deauthenticate(priv,
@@ -319,15 +319,18 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
{
int i = nr_addrs;
struct dev_mc_list *mc_list;
+ int cnt;
if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST))
return nr_addrs;
netif_addr_lock_bh(dev);
- for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
+ cnt = netdev_mc_count(dev);
+ netdev_for_each_mc_addr(mc_list, dev) {
if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) {
lbs_deb_net("mcast address %s:%pM skipped\n", dev->name,
mc_list->dmi_addr);
+ cnt--;
continue;
}
@@ -337,9 +340,10 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
lbs_deb_net("mcast address %s:%pM added to filter\n", dev->name,
mc_list->dmi_addr);
i++;
+ cnt--;
}
netif_addr_unlock_bh(dev);
- if (mc_list)
+ if (cnt)
return -EOVERFLOW;
return i;
@@ -536,31 +540,14 @@ static int lbs_thread(void *data)
if (priv->cmd_timed_out && priv->cur_cmd) {
struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
- if (++priv->nr_retries > 3) {
- lbs_pr_info("Excessive timeouts submitting "
- "command 0x%04x\n",
- le16_to_cpu(cmdnode->cmdbuf->command));
- lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
- priv->nr_retries = 0;
- if (priv->reset_card)
- priv->reset_card(priv);
- } else {
- priv->cur_cmd = NULL;
- priv->dnld_sent = DNLD_RES_RECEIVED;
- lbs_pr_info("requeueing command 0x%04x due "
- "to timeout (#%d)\n",
- le16_to_cpu(cmdnode->cmdbuf->command),
- priv->nr_retries);
-
- /* Stick it back at the _top_ of the pending queue
- for immediate resubmission */
- list_add(&cmdnode->list, &priv->cmdpendingq);
- }
+ lbs_pr_info("Timeout submitting command 0x%04x\n",
+ le16_to_cpu(cmdnode->cmdbuf->command));
+ lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
+ if (priv->reset_card)
+ priv->reset_card(priv);
}
priv->cmd_timed_out = 0;
-
-
if (!priv->fw_ready)
continue;
@@ -622,7 +609,7 @@ static int lbs_thread(void *data)
if (priv->connect_status == LBS_CONNECTED)
netif_wake_queue(priv->dev);
if (priv->mesh_dev &&
- priv->mesh_connect_status == LBS_CONNECTED)
+ lbs_mesh_connected(priv))
netif_wake_queue(priv->mesh_dev);
}
}
@@ -732,7 +719,7 @@ done:
* This function handles the timeout of command sending.
* It will re-send the same command again.
*/
-static void command_timer_fn(unsigned long data)
+static void lbs_cmd_timeout_handler(unsigned long data)
{
struct lbs_private *priv = (struct lbs_private *)data;
unsigned long flags;
@@ -809,18 +796,6 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
return 0;
}
-static void lbs_sync_channel_worker(struct work_struct *work)
-{
- struct lbs_private *priv = container_of(work, struct lbs_private,
- sync_channel);
-
- lbs_deb_enter(LBS_DEB_MAIN);
- if (lbs_update_channel(priv))
- lbs_pr_info("Channel synchronization failed.");
- lbs_deb_leave(LBS_DEB_MAIN);
-}
-
-
static int lbs_init_adapter(struct lbs_private *priv)
{
size_t bufsize;
@@ -848,14 +823,12 @@ static int lbs_init_adapter(struct lbs_private *priv)
memset(priv->current_addr, 0xff, ETH_ALEN);
priv->connect_status = LBS_DISCONNECTED;
- priv->mesh_connect_status = LBS_DISCONNECTED;
priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
priv->mode = IW_MODE_INFRA;
priv->channel = DEFAULT_AD_HOC_CHANNEL;
priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
priv->radio_on = 1;
priv->enablehwauto = 1;
- priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
priv->psmode = LBS802_11POWERMODECAM;
priv->psstate = PS_STATE_FULL_POWER;
priv->is_deep_sleep = 0;
@@ -865,7 +838,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
mutex_init(&priv->lock);
- setup_timer(&priv->command_timer, command_timer_fn,
+ setup_timer(&priv->command_timer, lbs_cmd_timeout_handler,
(unsigned long)priv);
setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
(unsigned long)priv);
@@ -998,11 +971,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
- INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker);
-
- priv->mesh_open = 0;
- sprintf(priv->mesh_ssid, "mesh");
- priv->mesh_ssid_len = 4;
priv->wol_criteria = 0xffffffff;
priv->wol_gpio = 0xff;
@@ -1076,6 +1044,17 @@ void lbs_remove_card(struct lbs_private *priv)
EXPORT_SYMBOL_GPL(lbs_remove_card);
+static int lbs_rtap_supported(struct lbs_private *priv)
+{
+ if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
+ return 1;
+
+ /* newer firmware use a capability mask */
+ return ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
+ (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK));
+}
+
+
int lbs_start_card(struct lbs_private *priv)
{
struct net_device *dev = priv->dev;
@@ -1095,12 +1074,14 @@ int lbs_start_card(struct lbs_private *priv)
lbs_update_channel(priv);
+ lbs_init_mesh(priv);
+
/*
* While rtap isn't related to mesh, only mesh-enabled
* firmware implements the rtap functionality via
* CMD_802_11_MONITOR_MODE.
*/
- if (lbs_init_mesh(priv)) {
+ if (lbs_rtap_supported(priv)) {
if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
lbs_pr_err("cannot register lbs_rtap attribute\n");
}
@@ -1134,7 +1115,9 @@ void lbs_stop_card(struct lbs_private *priv)
netif_carrier_off(dev);
lbs_debugfs_remove_one(priv);
- if (lbs_deinit_mesh(priv))
+ lbs_deinit_mesh(priv);
+
+ if (lbs_rtap_supported(priv))
device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
/* Delete the timeout of the currently processing command */
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index 92b7a357a5e4..e385af1f4583 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -1,4 +1,3 @@
-#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
@@ -197,7 +196,14 @@ int lbs_init_mesh(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_MESH);
- if (priv->mesh_fw_ver == MESH_FW_OLD) {
+ priv->mesh_connect_status = LBS_DISCONNECTED;
+
+ /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
+ /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
+ /* 5.110.22 have mesh command with 0xa3 command id */
+ /* 10.0.0.p0 FW brings in mesh config command with different id */
+ /* Check FW version MSB and initialize mesh_fw_ver */
+ if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
/* Enable mesh, if supported, and work out which TLV it uses.
0x100 + 291 is an unofficial value used in 5.110.20.pXX
0x100 + 37 is the official value used in 5.110.21.pXX
@@ -219,7 +225,9 @@ int lbs_init_mesh(struct lbs_private *priv)
priv->channel))
priv->mesh_tlv = 0;
}
- } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
+ } else
+ if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
+ (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
/* 10.0.0.pXX new firmwares should succeed with TLV
* 0x100+37; Do not invoke command with old TLV.
*/
@@ -228,7 +236,12 @@ int lbs_init_mesh(struct lbs_private *priv)
priv->channel))
priv->mesh_tlv = 0;
}
+
+
if (priv->mesh_tlv) {
+ sprintf(priv->mesh_ssid, "mesh");
+ priv->mesh_ssid_len = 4;
+
lbs_add_mesh(priv);
if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
@@ -416,10 +429,10 @@ struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
struct net_device *dev, struct rxpd *rxpd)
{
if (priv->mesh_dev) {
- if (priv->mesh_fw_ver == MESH_FW_OLD) {
+ if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
if (rxpd->rx_control & RxPD_MESH_FRAME)
dev = priv->mesh_dev;
- } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
+ } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
dev = priv->mesh_dev;
}
@@ -432,9 +445,9 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,
struct net_device *dev, struct txpd *txpd)
{
if (dev == priv->mesh_dev) {
- if (priv->mesh_fw_ver == MESH_FW_OLD)
+ if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
- else if (priv->mesh_fw_ver == MESH_FW_NEW)
+ else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
txpd->u.bss.bss_num = MESH_IFACE_ID;
}
}
@@ -538,7 +551,7 @@ static int __lbs_mesh_config_send(struct lbs_private *priv,
* Command id is 0xac for v10 FW along with mesh interface
* id in bits 14-13-12.
*/
- if (priv->mesh_fw_ver == MESH_FW_NEW)
+ if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
command = CMD_MESH_CONFIG |
(MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h
index fea9b5d005fc..e2573303a328 100644
--- a/drivers/net/wireless/libertas/mesh.h
+++ b/drivers/net/wireless/libertas/mesh.h
@@ -9,6 +9,8 @@
#include <net/lib80211.h>
+#ifdef CONFIG_LIBERTAS_MESH
+
/* Mesh statistics */
struct lbs_mesh_stats {
u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
@@ -46,11 +48,20 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,
/* Command handling */
struct cmd_ds_command;
+struct cmd_ds_mesh_access;
+struct cmd_ds_mesh_config;
int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
u16 cmd_action, void *pdata_buf);
int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
u16 cmd_action, void *pdata_buf);
+int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
+ struct cmd_ds_mesh_access *cmd);
+int lbs_mesh_config_send(struct lbs_private *priv,
+ struct cmd_ds_mesh_config *cmd,
+ uint16_t action, uint16_t type);
+int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
+
/* Persistent configuration */
@@ -75,4 +86,25 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev,
uint32_t stringset, uint8_t *s);
+/* Accessors */
+
+#define lbs_mesh_open(priv) (priv->mesh_open)
+#define lbs_mesh_connected(priv) (priv->mesh_connect_status == LBS_CONNECTED)
+
+#else
+
+#define lbs_init_mesh(priv)
+#define lbs_deinit_mesh(priv)
+#define lbs_add_mesh(priv)
+#define lbs_remove_mesh(priv)
+#define lbs_mesh_set_dev(priv, dev, rxpd) (dev)
+#define lbs_mesh_set_txpd(priv, dev, txpd)
+#define lbs_mesh_config(priv, enable, chan)
+#define lbs_mesh_open(priv) (0)
+#define lbs_mesh_connected(priv) (0)
+
+#endif
+
+
+
#endif
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index b0b1c7841500..220361e69cd3 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -635,7 +635,7 @@ out:
if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len)
netif_wake_queue(priv->dev);
- if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED) &&
+ if (priv->mesh_dev && lbs_mesh_connected(priv) &&
!priv->tx_pending_len)
netif_wake_queue(priv->mesh_dev);
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index 315d1ce286ca..52d244ea3d97 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -198,7 +198,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
if (priv->connect_status == LBS_CONNECTED)
netif_wake_queue(priv->dev);
- if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED))
+ if (priv->mesh_dev && lbs_mesh_connected(priv))
netif_wake_queue(priv->mesh_dev);
}
EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 4b1aab593a84..71f88a08e090 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -192,7 +192,7 @@ static void copy_active_data_rates(struct lbs_private *priv, u8 *rates)
lbs_deb_enter(LBS_DEB_WEXT);
if ((priv->connect_status != LBS_CONNECTED) &&
- (priv->mesh_connect_status != LBS_CONNECTED))
+ !lbs_mesh_connected(priv))
memcpy(rates, lbs_bg_rates, MAX_RATES);
else
memcpy(rates, priv->curbssparams.rates, MAX_RATES);
@@ -298,6 +298,7 @@ static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
return 0;
}
+#ifdef CONFIG_LIBERTAS_MESH
static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
@@ -307,7 +308,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
/* Use nickname to indicate that mesh is on */
- if (priv->mesh_connect_status == LBS_CONNECTED) {
+ if (lbs_mesh_connected(priv)) {
strncpy(extra, "Mesh", 12);
extra[12] = '\0';
dwrq->length = strlen(extra);
@@ -321,6 +322,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
}
+#endif
static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
@@ -422,6 +424,7 @@ static int lbs_get_mode(struct net_device *dev,
return 0;
}
+#ifdef CONFIG_LIBERTAS_MESH
static int mesh_wlan_get_mode(struct net_device *dev,
struct iw_request_info *info, u32 * uwrq,
char *extra)
@@ -433,6 +436,7 @@ static int mesh_wlan_get_mode(struct net_device *dev,
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
}
+#endif
static int lbs_get_txpow(struct net_device *dev,
struct iw_request_info *info,
@@ -863,7 +867,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
/* If we're not associated, all quality values are meaningless */
if ((priv->connect_status != LBS_CONNECTED) &&
- (priv->mesh_connect_status != LBS_CONNECTED))
+ !lbs_mesh_connected(priv))
goto out;
/* Quality by RSSI */
@@ -1010,6 +1014,7 @@ out:
return ret;
}
+#ifdef CONFIG_LIBERTAS_MESH
static int lbs_mesh_set_freq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *fwrq, char *extra)
@@ -1061,6 +1066,7 @@ out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
}
+#endif
static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
@@ -2108,6 +2114,7 @@ out:
return ret;
}
+#ifdef CONFIG_LIBERTAS_MESH
static int lbs_mesh_get_essid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
@@ -2161,6 +2168,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
}
+#endif
/**
* @brief Connect to the AP or Ad-hoc Network with specific bssid
@@ -2267,7 +2275,13 @@ static const iw_handler lbs_handler[] = {
(iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
(iw_handler) NULL, /* SIOCSIWPMKSA */
};
+struct iw_handler_def lbs_handler_def = {
+ .num_standard = ARRAY_SIZE(lbs_handler),
+ .standard = (iw_handler *) lbs_handler,
+ .get_wireless_stats = lbs_get_wireless_stats,
+};
+#ifdef CONFIG_LIBERTAS_MESH
static const iw_handler mesh_wlan_handler[] = {
(iw_handler) NULL, /* SIOCSIWCOMMIT */
(iw_handler) lbs_get_name, /* SIOCGIWNAME */
@@ -2325,14 +2339,10 @@ static const iw_handler mesh_wlan_handler[] = {
(iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
(iw_handler) NULL, /* SIOCSIWPMKSA */
};
-struct iw_handler_def lbs_handler_def = {
- .num_standard = ARRAY_SIZE(lbs_handler),
- .standard = (iw_handler *) lbs_handler,
- .get_wireless_stats = lbs_get_wireless_stats,
-};
struct iw_handler_def mesh_handler_def = {
.num_standard = ARRAY_SIZE(mesh_wlan_handler),
.standard = (iw_handler *) mesh_wlan_handler,
.get_wireless_stats = lbs_get_wireless_stats,
};
+#endif
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 26a1abd5bb03..6ab30033c26c 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -318,14 +318,14 @@ static void lbtf_op_stop(struct ieee80211_hw *hw)
}
static int lbtf_op_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct lbtf_private *priv = hw->priv;
if (priv->vif != NULL)
return -EOPNOTSUPP;
- priv->vif = conf->vif;
- switch (conf->type) {
+ priv->vif = vif;
+ switch (vif->type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
lbtf_set_mode(priv, LBTF_AP_MODE);
@@ -337,12 +337,12 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw,
priv->vif = NULL;
return -EOPNOTSUPP;
}
- lbtf_set_mac_address(priv, (u8 *) conf->mac_addr);
+ lbtf_set_mac_address(priv, (u8 *) vif->addr);
return 0;
}
static void lbtf_op_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct lbtf_private *priv = hw->priv;
@@ -555,6 +555,9 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev)
priv->band.n_channels = ARRAY_SIZE(lbtf_channels);
priv->band.channels = priv->channels;
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
+ hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC);
skb_queue_head_init(&priv->bc_ps_buf);
SET_IEEE80211_DEV(hw, dmdev);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 88e41176e7fd..6ea77e95277b 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -32,6 +32,10 @@ static int radios = 2;
module_param(radios, int, 0444);
MODULE_PARM_DESC(radios, "Number of simulated radios");
+static bool fake_hw_scan;
+module_param(fake_hw_scan, bool, 0444);
+MODULE_PARM_DESC(fake_hw_scan, "Install fake (no-op) hw-scan handler");
+
/**
* enum hwsim_regtest - the type of regulatory tests we offer
*
@@ -281,6 +285,8 @@ struct mac80211_hwsim_data {
struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)];
struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
+ struct mac_address addresses[2];
+
struct ieee80211_channel *channel;
unsigned long beacon_int; /* in jiffies unit */
unsigned int rx_filter;
@@ -436,6 +442,38 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
}
+struct mac80211_hwsim_addr_match_data {
+ bool ret;
+ const u8 *addr;
+};
+
+static void mac80211_hwsim_addr_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct mac80211_hwsim_addr_match_data *md = data;
+ if (memcmp(mac, md->addr, ETH_ALEN) == 0)
+ md->ret = true;
+}
+
+
+static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data,
+ const u8 *addr)
+{
+ struct mac80211_hwsim_addr_match_data md;
+
+ if (memcmp(addr, data->hw->wiphy->perm_addr, ETH_ALEN) == 0)
+ return true;
+
+ md.ret = false;
+ md.addr = addr;
+ ieee80211_iterate_active_interfaces_atomic(data->hw,
+ mac80211_hwsim_addr_iter,
+ &md);
+
+ return md.ret;
+}
+
+
static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
struct sk_buff *skb)
{
@@ -488,8 +526,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
if (nskb == NULL)
continue;
- if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr,
- ETH_ALEN) == 0)
+ if (mac80211_hwsim_addr_match(data2, hdr->addr1))
ack = true;
memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
ieee80211_rx_irqsafe(data2->hw, nskb);
@@ -553,24 +590,24 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
- wiphy_name(hw->wiphy), __func__, conf->type,
- conf->mac_addr);
- hwsim_set_magic(conf->vif);
+ wiphy_name(hw->wiphy), __func__, vif->type,
+ vif->addr);
+ hwsim_set_magic(vif);
return 0;
}
static void mac80211_hwsim_remove_interface(
- struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf)
+ struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
- wiphy_name(hw->wiphy), __func__, conf->type,
- conf->mac_addr);
- hwsim_check_magic(conf->vif);
- hwsim_clear_magic(conf->vif);
+ wiphy_name(hw->wiphy), __func__, vif->type,
+ vif->addr);
+ hwsim_check_magic(vif);
+ hwsim_clear_magic(vif);
}
@@ -618,12 +655,26 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
{
struct mac80211_hwsim_data *data = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
-
- printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n",
+ static const char *chantypes[4] = {
+ [NL80211_CHAN_NO_HT] = "noht",
+ [NL80211_CHAN_HT20] = "ht20",
+ [NL80211_CHAN_HT40MINUS] = "ht40-",
+ [NL80211_CHAN_HT40PLUS] = "ht40+",
+ };
+ static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
+ [IEEE80211_SMPS_AUTOMATIC] = "auto",
+ [IEEE80211_SMPS_OFF] = "off",
+ [IEEE80211_SMPS_STATIC] = "static",
+ [IEEE80211_SMPS_DYNAMIC] = "dynamic",
+ };
+
+ printk(KERN_DEBUG "%s:%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
wiphy_name(hw->wiphy), __func__,
conf->channel->center_freq,
+ chantypes[conf->channel_type],
!!(conf->flags & IEEE80211_CONF_IDLE),
- !!(conf->flags & IEEE80211_CONF_PS));
+ !!(conf->flags & IEEE80211_CONF_PS),
+ smps_modes[conf->smps_mode]);
data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
@@ -720,23 +771,41 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
}
}
+static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ hwsim_check_magic(vif);
+ hwsim_set_sta_magic(sta);
+
+ return 0;
+}
+
+static int mac80211_hwsim_sta_remove(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ hwsim_check_magic(vif);
+ hwsim_clear_sta_magic(sta);
+
+ return 0;
+}
+
static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta)
{
hwsim_check_magic(vif);
+
switch (cmd) {
- case STA_NOTIFY_ADD:
- hwsim_set_sta_magic(sta);
- break;
- case STA_NOTIFY_REMOVE:
- hwsim_clear_sta_magic(sta);
- break;
case STA_NOTIFY_SLEEP:
case STA_NOTIFY_AWAKE:
/* TODO: make good use of these flags */
break;
+ default:
+ WARN(1, "Invalid sta notify: %d\n", cmd);
+ break;
}
}
@@ -827,7 +896,77 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
}
#endif
-static const struct ieee80211_ops mac80211_hwsim_ops =
+static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+ switch (action) {
+ case IEEE80211_AMPDU_TX_START:
+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+ case IEEE80211_AMPDU_TX_STOP:
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+ break;
+ case IEEE80211_AMPDU_RX_START:
+ case IEEE80211_AMPDU_RX_STOP:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)
+{
+ /*
+ * In this special case, there's nothing we need to
+ * do because hwsim does transmission synchronously.
+ * In the future, when it does transmissions via
+ * userspace, we may need to do something.
+ */
+}
+
+struct hw_scan_done {
+ struct delayed_work w;
+ struct ieee80211_hw *hw;
+};
+
+static void hw_scan_done(struct work_struct *work)
+{
+ struct hw_scan_done *hsd =
+ container_of(work, struct hw_scan_done, w.work);
+
+ ieee80211_scan_completed(hsd->hw, false);
+ kfree(hsd);
+}
+
+static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
+ struct cfg80211_scan_request *req)
+{
+ struct hw_scan_done *hsd = kzalloc(sizeof(*hsd), GFP_KERNEL);
+ int i;
+
+ if (!hsd)
+ return -ENOMEM;
+
+ hsd->hw = hw;
+ INIT_DELAYED_WORK(&hsd->w, hw_scan_done);
+
+ printk(KERN_DEBUG "hwsim scan request\n");
+ for (i = 0; i < req->n_channels; i++)
+ printk(KERN_DEBUG "hwsim scan freq %d\n",
+ req->channels[i]->center_freq);
+
+ ieee80211_queue_delayed_work(hw, &hsd->w, 2 * HZ);
+
+ return 0;
+}
+
+static struct ieee80211_ops mac80211_hwsim_ops =
{
.tx = mac80211_hwsim_tx,
.start = mac80211_hwsim_start,
@@ -837,10 +976,14 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
.config = mac80211_hwsim_config,
.configure_filter = mac80211_hwsim_configure_filter,
.bss_info_changed = mac80211_hwsim_bss_info_changed,
+ .sta_add = mac80211_hwsim_sta_add,
+ .sta_remove = mac80211_hwsim_sta_remove,
.sta_notify = mac80211_hwsim_sta_notify,
.set_tim = mac80211_hwsim_set_tim,
.conf_tx = mac80211_hwsim_conf_tx,
CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
+ .ampdu_action = mac80211_hwsim_ampdu_action,
+ .flush = mac80211_hwsim_flush,
};
@@ -1035,6 +1178,9 @@ static int __init init_mac80211_hwsim(void)
if (radios < 1 || radios > 100)
return -EINVAL;
+ if (fake_hw_scan)
+ mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan;
+
spin_lock_init(&hwsim_radio_lock);
INIT_LIST_HEAD(&hwsim_radios);
@@ -1072,7 +1218,11 @@ static int __init init_mac80211_hwsim(void)
SET_IEEE80211_DEV(hw, data->dev);
addr[3] = i >> 8;
addr[4] = i;
- SET_IEEE80211_PERM_ADDR(hw, addr);
+ memcpy(data->addresses[0].addr, addr, ETH_ALEN);
+ memcpy(data->addresses[1].addr, addr, ETH_ALEN);
+ data->addresses[1].addr[0] |= 0x40;
+ hw->wiphy->n_addresses = 2;
+ hw->wiphy->addresses = data->addresses;
hw->channel_change_time = 1;
hw->queues = 4;
@@ -1082,7 +1232,9 @@ static int __init init_mac80211_hwsim(void)
BIT(NL80211_IFTYPE_MESH_POINT);
hw->flags = IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_STATIC_SMPS |
+ IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;
/* ask mac80211 to reserve space for magic */
hw->vif_data_size = sizeof(struct hwsim_vif_priv);
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 59f92105b0c2..ac65e13eb0de 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2,7 +2,7 @@
* drivers/net/wireless/mwl8k.c
* Driver for Marvell TOPDOG 802.11 Wireless cards
*
- * Copyright (C) 2008-2009 Marvell Semiconductor Inc.
+ * Copyright (C) 2008, 2009, 2010 Marvell Semiconductor Inc.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -26,7 +26,7 @@
#define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver"
#define MWL8K_NAME KBUILD_MODNAME
-#define MWL8K_VERSION "0.10"
+#define MWL8K_VERSION "0.12"
/* Register definitions */
#define MWL8K_HIU_GEN_PTR 0x00000c10
@@ -92,8 +92,7 @@ struct mwl8k_device_info {
char *part_name;
char *helper_image;
char *fw_image;
- struct rxd_ops *rxd_ops;
- u16 modes;
+ struct rxd_ops *ap_rxd_ops;
};
struct mwl8k_rx_queue {
@@ -120,34 +119,36 @@ struct mwl8k_tx_queue {
/* sw appends here */
int tail;
- struct ieee80211_tx_queue_stats stats;
+ unsigned int len;
struct mwl8k_tx_desc *txd;
dma_addr_t txd_dma;
struct sk_buff **skb;
};
-/* Pointers to the firmware data and meta information about it. */
-struct mwl8k_firmware {
- /* Boot helper code */
- struct firmware *helper;
+struct mwl8k_priv {
+ struct ieee80211_hw *hw;
+ struct pci_dev *pdev;
- /* Microcode */
- struct firmware *ucode;
-};
+ struct mwl8k_device_info *device_info;
-struct mwl8k_priv {
void __iomem *sram;
void __iomem *regs;
- struct ieee80211_hw *hw;
- struct pci_dev *pdev;
+ /* firmware */
+ struct firmware *fw_helper;
+ struct firmware *fw_ucode;
- struct mwl8k_device_info *device_info;
+ /* hardware/firmware parameters */
bool ap_fw;
struct rxd_ops *rxd_ops;
-
- /* firmware files and meta data */
- struct mwl8k_firmware fw;
+ struct ieee80211_supported_band band_24;
+ struct ieee80211_channel channels_24[14];
+ struct ieee80211_rate rates_24[14];
+ struct ieee80211_supported_band band_50;
+ struct ieee80211_channel channels_50[4];
+ struct ieee80211_rate rates_50[9];
+ u32 ap_macids_supported;
+ u32 sta_macids_supported;
/* firmware access */
struct mutex fw_mutex;
@@ -161,9 +162,9 @@ struct mwl8k_priv {
/* TX quiesce completion, protected by fw_mutex and tx_lock */
struct completion *tx_wait;
- struct ieee80211_vif *vif;
-
- struct ieee80211_channel *current_channel;
+ /* List of interfaces. */
+ u32 macids_used;
+ struct list_head vif_list;
/* power management status cookie from firmware */
u32 *cookie;
@@ -182,11 +183,6 @@ struct mwl8k_priv {
struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES];
struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES];
- /* PHY parameters */
- struct ieee80211_supported_band band;
- struct ieee80211_channel channels[14];
- struct ieee80211_rate rates[14];
-
bool radio_on;
bool radio_short_preamble;
bool sniffer_enabled;
@@ -205,32 +201,33 @@ struct mwl8k_priv {
*/
struct work_struct finalize_join_worker;
- /* Tasklet to reclaim TX descriptors and buffers after tx */
- struct tasklet_struct tx_reclaim_task;
+ /* Tasklet to perform TX reclaim. */
+ struct tasklet_struct poll_tx_task;
+
+ /* Tasklet to perform RX. */
+ struct tasklet_struct poll_rx_task;
};
/* Per interface specific private data */
struct mwl8k_vif {
- /* backpointer to parent config block */
- struct mwl8k_priv *priv;
-
- /* BSS config of AP or IBSS from mac80211*/
- struct ieee80211_bss_conf bss_info;
-
- /* BSSID of AP or IBSS */
- u8 bssid[ETH_ALEN];
- u8 mac_addr[ETH_ALEN];
+ struct list_head list;
+ struct ieee80211_vif *vif;
- /* Index into station database.Returned by update_sta_db call */
- u8 peer_id;
+ /* Firmware macid for this vif. */
+ int macid;
- /* Non AMPDU sequence number assigned by driver */
- u16 seqno;
+ /* Non AMPDU sequence number assigned by driver. */
+ u16 seqno;
};
-
#define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv))
-static const struct ieee80211_channel mwl8k_channels[] = {
+struct mwl8k_sta {
+ /* Index into station database. Returned by UPDATE_STADB. */
+ u8 peer_id;
+};
+#define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv))
+
+static const struct ieee80211_channel mwl8k_channels_24[] = {
{ .center_freq = 2412, .hw_value = 1, },
{ .center_freq = 2417, .hw_value = 2, },
{ .center_freq = 2422, .hw_value = 3, },
@@ -242,9 +239,12 @@ static const struct ieee80211_channel mwl8k_channels[] = {
{ .center_freq = 2452, .hw_value = 9, },
{ .center_freq = 2457, .hw_value = 10, },
{ .center_freq = 2462, .hw_value = 11, },
+ { .center_freq = 2467, .hw_value = 12, },
+ { .center_freq = 2472, .hw_value = 13, },
+ { .center_freq = 2484, .hw_value = 14, },
};
-static const struct ieee80211_rate mwl8k_rates[] = {
+static const struct ieee80211_rate mwl8k_rates_24[] = {
{ .bitrate = 10, .hw_value = 2, },
{ .bitrate = 20, .hw_value = 4, },
{ .bitrate = 55, .hw_value = 11, },
@@ -261,8 +261,23 @@ static const struct ieee80211_rate mwl8k_rates[] = {
{ .bitrate = 720, .hw_value = 144, },
};
-static const u8 mwl8k_rateids[12] = {
- 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108,
+static const struct ieee80211_channel mwl8k_channels_50[] = {
+ { .center_freq = 5180, .hw_value = 36, },
+ { .center_freq = 5200, .hw_value = 40, },
+ { .center_freq = 5220, .hw_value = 44, },
+ { .center_freq = 5240, .hw_value = 48, },
+};
+
+static const struct ieee80211_rate mwl8k_rates_50[] = {
+ { .bitrate = 60, .hw_value = 12, },
+ { .bitrate = 90, .hw_value = 18, },
+ { .bitrate = 120, .hw_value = 24, },
+ { .bitrate = 180, .hw_value = 36, },
+ { .bitrate = 240, .hw_value = 48, },
+ { .bitrate = 360, .hw_value = 72, },
+ { .bitrate = 480, .hw_value = 96, },
+ { .bitrate = 540, .hw_value = 108, },
+ { .bitrate = 720, .hw_value = 144, },
};
/* Set or get info from Firmware */
@@ -278,6 +293,7 @@ static const u8 mwl8k_rateids[12] = {
#define MWL8K_CMD_RADIO_CONTROL 0x001c
#define MWL8K_CMD_RF_TX_POWER 0x001e
#define MWL8K_CMD_RF_ANTENNA 0x0020
+#define MWL8K_CMD_SET_BEACON 0x0100 /* per-vif */
#define MWL8K_CMD_SET_PRE_SCAN 0x0107
#define MWL8K_CMD_SET_POST_SCAN 0x0108
#define MWL8K_CMD_SET_RF_CHANNEL 0x010a
@@ -291,8 +307,10 @@ static const u8 mwl8k_rateids[12] = {
#define MWL8K_CMD_MIMO_CONFIG 0x0125
#define MWL8K_CMD_USE_FIXED_RATE 0x0126
#define MWL8K_CMD_ENABLE_SNIFFER 0x0150
-#define MWL8K_CMD_SET_MAC_ADDR 0x0202
+#define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */
#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203
+#define MWL8K_CMD_BSS_START 0x1100 /* per-vif */
+#define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */
#define MWL8K_CMD_UPDATE_STADB 0x1123
static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
@@ -310,6 +328,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
MWL8K_CMDNAME(RADIO_CONTROL);
MWL8K_CMDNAME(RF_TX_POWER);
MWL8K_CMDNAME(RF_ANTENNA);
+ MWL8K_CMDNAME(SET_BEACON);
MWL8K_CMDNAME(SET_PRE_SCAN);
MWL8K_CMDNAME(SET_POST_SCAN);
MWL8K_CMDNAME(SET_RF_CHANNEL);
@@ -325,6 +344,8 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
MWL8K_CMDNAME(ENABLE_SNIFFER);
MWL8K_CMDNAME(SET_MAC_ADDR);
MWL8K_CMDNAME(SET_RATEADAPT_MODE);
+ MWL8K_CMDNAME(BSS_START);
+ MWL8K_CMDNAME(SET_NEW_STN);
MWL8K_CMDNAME(UPDATE_STADB);
default:
snprintf(buf, bufsize, "0x%x", cmd);
@@ -355,8 +376,8 @@ static void mwl8k_release_fw(struct firmware **fw)
static void mwl8k_release_firmware(struct mwl8k_priv *priv)
{
- mwl8k_release_fw(&priv->fw.ucode);
- mwl8k_release_fw(&priv->fw.helper);
+ mwl8k_release_fw(&priv->fw_ucode);
+ mwl8k_release_fw(&priv->fw_helper);
}
/* Request fw image */
@@ -377,7 +398,7 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv)
int rc;
if (di->helper_image != NULL) {
- rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw.helper);
+ rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw_helper);
if (rc) {
printk(KERN_ERR "%s: Error requesting helper "
"firmware file %s\n", pci_name(priv->pdev),
@@ -386,24 +407,22 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv)
}
}
- rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw.ucode);
+ rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw_ucode);
if (rc) {
printk(KERN_ERR "%s: Error requesting firmware file %s\n",
pci_name(priv->pdev), di->fw_image);
- mwl8k_release_fw(&priv->fw.helper);
+ mwl8k_release_fw(&priv->fw_helper);
return rc;
}
return 0;
}
-MODULE_FIRMWARE("mwl8k/helper_8687.fw");
-MODULE_FIRMWARE("mwl8k/fmimage_8687.fw");
-
struct mwl8k_cmd_pkt {
__le16 code;
__le16 length;
- __le16 seq_num;
+ __u8 seq_num;
+ __u8 macid;
__le16 result;
char payload[0];
} __attribute__((packed));
@@ -461,6 +480,7 @@ static int mwl8k_load_fw_image(struct mwl8k_priv *priv,
cmd->code = cpu_to_le16(MWL8K_CMD_CODE_DNLD);
cmd->seq_num = 0;
+ cmd->macid = 0;
cmd->result = 0;
done = 0;
@@ -551,13 +571,12 @@ static int mwl8k_feed_fw_image(struct mwl8k_priv *priv,
static int mwl8k_load_firmware(struct ieee80211_hw *hw)
{
struct mwl8k_priv *priv = hw->priv;
- struct firmware *fw = priv->fw.ucode;
- struct mwl8k_device_info *di = priv->device_info;
+ struct firmware *fw = priv->fw_ucode;
int rc;
int loops;
if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) {
- struct firmware *helper = priv->fw.helper;
+ struct firmware *helper = priv->fw_helper;
if (helper == NULL) {
printk(KERN_ERR "%s: helper image needed but none "
@@ -584,10 +603,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
return rc;
}
- if (di->modes & BIT(NL80211_IFTYPE_AP))
- iowrite32(MWL8K_MODE_AP, priv->regs + MWL8K_HIU_GEN_PTR);
- else
- iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR);
+ iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR);
loops = 500000;
do {
@@ -610,91 +626,6 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
}
-/*
- * Defines shared between transmission and reception.
- */
-/* HT control fields for firmware */
-struct ewc_ht_info {
- __le16 control1;
- __le16 control2;
- __le16 control3;
-} __attribute__((packed));
-
-/* Firmware Station database operations */
-#define MWL8K_STA_DB_ADD_ENTRY 0
-#define MWL8K_STA_DB_MODIFY_ENTRY 1
-#define MWL8K_STA_DB_DEL_ENTRY 2
-#define MWL8K_STA_DB_FLUSH 3
-
-/* Peer Entry flags - used to define the type of the peer node */
-#define MWL8K_PEER_TYPE_ACCESSPOINT 2
-
-struct peer_capability_info {
- /* Peer type - AP vs. STA. */
- __u8 peer_type;
-
- /* Basic 802.11 capabilities from assoc resp. */
- __le16 basic_caps;
-
- /* Set if peer supports 802.11n high throughput (HT). */
- __u8 ht_support;
-
- /* Valid if HT is supported. */
- __le16 ht_caps;
- __u8 extended_ht_caps;
- struct ewc_ht_info ewc_info;
-
- /* Legacy rate table. Intersection of our rates and peer rates. */
- __u8 legacy_rates[12];
-
- /* HT rate table. Intersection of our rates and peer rates. */
- __u8 ht_rates[16];
- __u8 pad[16];
-
- /* If set, interoperability mode, no proprietary extensions. */
- __u8 interop;
- __u8 pad2;
- __u8 station_id;
- __le16 amsdu_enabled;
-} __attribute__((packed));
-
-/* Inline functions to manipulate QoS field in data descriptor. */
-static inline u16 mwl8k_qos_setbit_eosp(u16 qos)
-{
- u16 val_mask = 1 << 4;
-
- /* End of Service Period Bit 4 */
- return qos | val_mask;
-}
-
-static inline u16 mwl8k_qos_setbit_ack(u16 qos, u8 ack_policy)
-{
- u16 val_mask = 0x3;
- u8 shift = 5;
- u16 qos_mask = ~(val_mask << shift);
-
- /* Ack Policy Bit 5-6 */
- return (qos & qos_mask) | ((ack_policy & val_mask) << shift);
-}
-
-static inline u16 mwl8k_qos_setbit_amsdu(u16 qos)
-{
- u16 val_mask = 1 << 7;
-
- /* AMSDU present Bit 7 */
- return qos | val_mask;
-}
-
-static inline u16 mwl8k_qos_setbit_qlen(u16 qos, u8 len)
-{
- u16 val_mask = 0xff;
- u8 shift = 8;
- u16 qos_mask = ~(val_mask << shift);
-
- /* Queue Length Bits 8-15 */
- return (qos & qos_mask) | ((len & val_mask) << shift);
-}
-
/* DMA header used by firmware and hardware. */
struct mwl8k_dma_data {
__le16 fwlen;
@@ -761,9 +692,9 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb)
/*
- * Packet reception for 88w8366.
+ * Packet reception for 88w8366 AP firmware.
*/
-struct mwl8k_rxd_8366 {
+struct mwl8k_rxd_8366_ap {
__le16 pkt_len;
__u8 sq2;
__u8 rate;
@@ -781,23 +712,23 @@ struct mwl8k_rxd_8366 {
__u8 rx_ctrl;
} __attribute__((packed));
-#define MWL8K_8366_RATE_INFO_MCS_FORMAT 0x80
-#define MWL8K_8366_RATE_INFO_40MHZ 0x40
-#define MWL8K_8366_RATE_INFO_RATEID(x) ((x) & 0x3f)
+#define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT 0x80
+#define MWL8K_8366_AP_RATE_INFO_40MHZ 0x40
+#define MWL8K_8366_AP_RATE_INFO_RATEID(x) ((x) & 0x3f)
-#define MWL8K_8366_RX_CTRL_OWNED_BY_HOST 0x80
+#define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80
-static void mwl8k_rxd_8366_init(void *_rxd, dma_addr_t next_dma_addr)
+static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr)
{
- struct mwl8k_rxd_8366 *rxd = _rxd;
+ struct mwl8k_rxd_8366_ap *rxd = _rxd;
rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
- rxd->rx_ctrl = MWL8K_8366_RX_CTRL_OWNED_BY_HOST;
+ rxd->rx_ctrl = MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST;
}
-static void mwl8k_rxd_8366_refill(void *_rxd, dma_addr_t addr, int len)
+static void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len)
{
- struct mwl8k_rxd_8366 *rxd = _rxd;
+ struct mwl8k_rxd_8366_ap *rxd = _rxd;
rxd->pkt_len = cpu_to_le16(len);
rxd->pkt_phys_addr = cpu_to_le32(addr);
@@ -806,12 +737,12 @@ static void mwl8k_rxd_8366_refill(void *_rxd, dma_addr_t addr, int len)
}
static int
-mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status,
- __le16 *qos)
+mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
+ __le16 *qos)
{
- struct mwl8k_rxd_8366 *rxd = _rxd;
+ struct mwl8k_rxd_8366_ap *rxd = _rxd;
- if (!(rxd->rx_ctrl & MWL8K_8366_RX_CTRL_OWNED_BY_HOST))
+ if (!(rxd->rx_ctrl & MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST))
return -1;
rmb();
@@ -820,23 +751,29 @@ mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status,
status->signal = -rxd->rssi;
status->noise = -rxd->noise_floor;
- if (rxd->rate & MWL8K_8366_RATE_INFO_MCS_FORMAT) {
+ if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) {
status->flag |= RX_FLAG_HT;
- if (rxd->rate & MWL8K_8366_RATE_INFO_40MHZ)
+ if (rxd->rate & MWL8K_8366_AP_RATE_INFO_40MHZ)
status->flag |= RX_FLAG_40MHZ;
- status->rate_idx = MWL8K_8366_RATE_INFO_RATEID(rxd->rate);
+ status->rate_idx = MWL8K_8366_AP_RATE_INFO_RATEID(rxd->rate);
} else {
int i;
- for (i = 0; i < ARRAY_SIZE(mwl8k_rates); i++) {
- if (mwl8k_rates[i].hw_value == rxd->rate) {
+ for (i = 0; i < ARRAY_SIZE(mwl8k_rates_24); i++) {
+ if (mwl8k_rates_24[i].hw_value == rxd->rate) {
status->rate_idx = i;
break;
}
}
}
- status->band = IEEE80211_BAND_2GHZ;
+ if (rxd->channel > 14) {
+ status->band = IEEE80211_BAND_5GHZ;
+ if (!(status->flag & RX_FLAG_HT))
+ status->rate_idx -= 5;
+ } else {
+ status->band = IEEE80211_BAND_2GHZ;
+ }
status->freq = ieee80211_channel_to_frequency(rxd->channel);
*qos = rxd->qos_control;
@@ -844,17 +781,17 @@ mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status,
return le16_to_cpu(rxd->pkt_len);
}
-static struct rxd_ops rxd_8366_ops = {
- .rxd_size = sizeof(struct mwl8k_rxd_8366),
- .rxd_init = mwl8k_rxd_8366_init,
- .rxd_refill = mwl8k_rxd_8366_refill,
- .rxd_process = mwl8k_rxd_8366_process,
+static struct rxd_ops rxd_8366_ap_ops = {
+ .rxd_size = sizeof(struct mwl8k_rxd_8366_ap),
+ .rxd_init = mwl8k_rxd_8366_ap_init,
+ .rxd_refill = mwl8k_rxd_8366_ap_refill,
+ .rxd_process = mwl8k_rxd_8366_ap_process,
};
/*
- * Packet reception for 88w8687.
+ * Packet reception for STA firmware.
*/
-struct mwl8k_rxd_8687 {
+struct mwl8k_rxd_sta {
__le16 pkt_len;
__u8 link_quality;
__u8 noise_level;
@@ -871,26 +808,26 @@ struct mwl8k_rxd_8687 {
__u8 pad2[2];
} __attribute__((packed));
-#define MWL8K_8687_RATE_INFO_SHORTPRE 0x8000
-#define MWL8K_8687_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3)
-#define MWL8K_8687_RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f)
-#define MWL8K_8687_RATE_INFO_40MHZ 0x0004
-#define MWL8K_8687_RATE_INFO_SHORTGI 0x0002
-#define MWL8K_8687_RATE_INFO_MCS_FORMAT 0x0001
+#define MWL8K_STA_RATE_INFO_SHORTPRE 0x8000
+#define MWL8K_STA_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3)
+#define MWL8K_STA_RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f)
+#define MWL8K_STA_RATE_INFO_40MHZ 0x0004
+#define MWL8K_STA_RATE_INFO_SHORTGI 0x0002
+#define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001
-#define MWL8K_8687_RX_CTRL_OWNED_BY_HOST 0x02
+#define MWL8K_STA_RX_CTRL_OWNED_BY_HOST 0x02
-static void mwl8k_rxd_8687_init(void *_rxd, dma_addr_t next_dma_addr)
+static void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr)
{
- struct mwl8k_rxd_8687 *rxd = _rxd;
+ struct mwl8k_rxd_sta *rxd = _rxd;
rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
- rxd->rx_ctrl = MWL8K_8687_RX_CTRL_OWNED_BY_HOST;
+ rxd->rx_ctrl = MWL8K_STA_RX_CTRL_OWNED_BY_HOST;
}
-static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len)
+static void mwl8k_rxd_sta_refill(void *_rxd, dma_addr_t addr, int len)
{
- struct mwl8k_rxd_8687 *rxd = _rxd;
+ struct mwl8k_rxd_sta *rxd = _rxd;
rxd->pkt_len = cpu_to_le16(len);
rxd->pkt_phys_addr = cpu_to_le32(addr);
@@ -899,13 +836,13 @@ static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len)
}
static int
-mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status,
+mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status,
__le16 *qos)
{
- struct mwl8k_rxd_8687 *rxd = _rxd;
+ struct mwl8k_rxd_sta *rxd = _rxd;
u16 rate_info;
- if (!(rxd->rx_ctrl & MWL8K_8687_RX_CTRL_OWNED_BY_HOST))
+ if (!(rxd->rx_ctrl & MWL8K_STA_RX_CTRL_OWNED_BY_HOST))
return -1;
rmb();
@@ -915,19 +852,25 @@ mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status,
status->signal = -rxd->rssi;
status->noise = -rxd->noise_level;
- status->antenna = MWL8K_8687_RATE_INFO_ANTSELECT(rate_info);
- status->rate_idx = MWL8K_8687_RATE_INFO_RATEID(rate_info);
+ status->antenna = MWL8K_STA_RATE_INFO_ANTSELECT(rate_info);
+ status->rate_idx = MWL8K_STA_RATE_INFO_RATEID(rate_info);
- if (rate_info & MWL8K_8687_RATE_INFO_SHORTPRE)
+ if (rate_info & MWL8K_STA_RATE_INFO_SHORTPRE)
status->flag |= RX_FLAG_SHORTPRE;
- if (rate_info & MWL8K_8687_RATE_INFO_40MHZ)
+ if (rate_info & MWL8K_STA_RATE_INFO_40MHZ)
status->flag |= RX_FLAG_40MHZ;
- if (rate_info & MWL8K_8687_RATE_INFO_SHORTGI)
+ if (rate_info & MWL8K_STA_RATE_INFO_SHORTGI)
status->flag |= RX_FLAG_SHORT_GI;
- if (rate_info & MWL8K_8687_RATE_INFO_MCS_FORMAT)
+ if (rate_info & MWL8K_STA_RATE_INFO_MCS_FORMAT)
status->flag |= RX_FLAG_HT;
- status->band = IEEE80211_BAND_2GHZ;
+ if (rxd->channel > 14) {
+ status->band = IEEE80211_BAND_5GHZ;
+ if (!(status->flag & RX_FLAG_HT))
+ status->rate_idx -= 5;
+ } else {
+ status->band = IEEE80211_BAND_2GHZ;
+ }
status->freq = ieee80211_channel_to_frequency(rxd->channel);
*qos = rxd->qos_control;
@@ -935,11 +878,11 @@ mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status,
return le16_to_cpu(rxd->pkt_len);
}
-static struct rxd_ops rxd_8687_ops = {
- .rxd_size = sizeof(struct mwl8k_rxd_8687),
- .rxd_init = mwl8k_rxd_8687_init,
- .rxd_refill = mwl8k_rxd_8687_refill,
- .rxd_process = mwl8k_rxd_8687_process,
+static struct rxd_ops rxd_sta_ops = {
+ .rxd_size = sizeof(struct mwl8k_rxd_sta),
+ .rxd_init = mwl8k_rxd_sta_init,
+ .rxd_refill = mwl8k_rxd_sta_refill,
+ .rxd_process = mwl8k_rxd_sta_process,
};
@@ -1153,16 +1096,18 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
* Packet transmission.
*/
-/* Transmit packet ACK policy */
-#define MWL8K_TXD_ACK_POLICY_NORMAL 0
-#define MWL8K_TXD_ACK_POLICY_BLOCKACK 3
-
#define MWL8K_TXD_STATUS_OK 0x00000001
#define MWL8K_TXD_STATUS_OK_RETRY 0x00000002
#define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004
#define MWL8K_TXD_STATUS_MULTICAST_TX 0x00000008
#define MWL8K_TXD_STATUS_FW_OWNED 0x80000000
+#define MWL8K_QOS_QLEN_UNSPEC 0xff00
+#define MWL8K_QOS_ACK_POLICY_MASK 0x0060
+#define MWL8K_QOS_ACK_POLICY_NORMAL 0x0000
+#define MWL8K_QOS_ACK_POLICY_BLOCKACK 0x0060
+#define MWL8K_QOS_EOSP 0x0010
+
struct mwl8k_tx_desc {
__le32 status;
__u8 data_rate;
@@ -1187,8 +1132,7 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index)
int size;
int i;
- memset(&txq->stats, 0, sizeof(struct ieee80211_tx_queue_stats));
- txq->stats.limit = MWL8K_TX_DESCS;
+ txq->len = 0;
txq->head = 0;
txq->tail = 0;
@@ -1264,7 +1208,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw)
printk(KERN_ERR "%s: txq[%d] len=%d head=%d tail=%d "
"fw_owned=%d drv_owned=%d unused=%d\n",
wiphy_name(hw->wiphy), i,
- txq->stats.len, txq->head, txq->tail,
+ txq->len, txq->head, txq->tail,
fw_owned, drv_owned, unused);
}
}
@@ -1272,7 +1216,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw)
/*
* Must be called with priv->fw_mutex held and tx queues stopped.
*/
-#define MWL8K_TX_WAIT_TIMEOUT_MS 1000
+#define MWL8K_TX_WAIT_TIMEOUT_MS 5000
static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
{
@@ -1316,8 +1260,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
}
if (priv->pending_tx_pkts < oldcount) {
- printk(KERN_NOTICE "%s: timeout waiting for tx "
- "rings to drain (%d -> %d pkts), retrying\n",
+ printk(KERN_NOTICE "%s: waiting for tx rings "
+ "to drain (%d -> %d pkts)\n",
wiphy_name(hw->wiphy), oldcount,
priv->pending_tx_pkts);
retry = 1;
@@ -1342,13 +1286,15 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
MWL8K_TXD_STATUS_OK_RETRY | \
MWL8K_TXD_STATUS_OK_MORE_RETRY))
-static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
+static int
+mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force)
{
struct mwl8k_priv *priv = hw->priv;
struct mwl8k_tx_queue *txq = priv->txq + index;
- int wake = 0;
+ int processed;
- while (txq->stats.len > 0) {
+ processed = 0;
+ while (txq->len > 0 && limit--) {
int tx;
struct mwl8k_tx_desc *tx_desc;
unsigned long addr;
@@ -1370,8 +1316,8 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
}
txq->head = (tx + 1) % MWL8K_TX_DESCS;
- BUG_ON(txq->stats.len == 0);
- txq->stats.len--;
+ BUG_ON(txq->len == 0);
+ txq->len--;
priv->pending_tx_pkts--;
addr = le32_to_cpu(tx_desc->pkt_phys_addr);
@@ -1395,11 +1341,13 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
ieee80211_tx_status_irqsafe(hw, skb);
- wake = 1;
+ processed++;
}
- if (wake && priv->radio_on && !mutex_is_locked(&priv->fw_mutex))
+ if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex))
ieee80211_wake_queue(hw, index);
+
+ return processed;
}
/* must be called only when the card's transmit is completely halted */
@@ -1408,7 +1356,7 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index)
struct mwl8k_priv *priv = hw->priv;
struct mwl8k_tx_queue *txq = priv->txq + index;
- mwl8k_txq_reclaim(hw, index, 1);
+ mwl8k_txq_reclaim(hw, index, INT_MAX, 1);
kfree(txq->skb);
txq->skb = NULL;
@@ -1446,11 +1394,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
mwl8k_vif = MWL8K_VIF(tx_info->control.vif);
if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
- u16 seqno = mwl8k_vif->seqno;
-
wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
- wh->seq_ctrl |= cpu_to_le16(seqno << 4);
- mwl8k_vif->seqno = seqno++ % 4096;
+ wh->seq_ctrl |= cpu_to_le16(mwl8k_vif->seqno);
+ mwl8k_vif->seqno += 0x10;
}
/* Setup firmware control bit fields for each frame type. */
@@ -1459,24 +1405,17 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
if (ieee80211_is_mgmt(wh->frame_control) ||
ieee80211_is_ctl(wh->frame_control)) {
txdatarate = 0;
- qos = mwl8k_qos_setbit_eosp(qos);
- /* Set Queue size to unspecified */
- qos = mwl8k_qos_setbit_qlen(qos, 0xff);
+ qos |= MWL8K_QOS_QLEN_UNSPEC | MWL8K_QOS_EOSP;
} else if (ieee80211_is_data(wh->frame_control)) {
txdatarate = 1;
if (is_multicast_ether_addr(wh->addr1))
txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX;
- /* Send pkt in an aggregate if AMPDU frame. */
+ qos &= ~MWL8K_QOS_ACK_POLICY_MASK;
if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
- qos = mwl8k_qos_setbit_ack(qos,
- MWL8K_TXD_ACK_POLICY_BLOCKACK);
+ qos |= MWL8K_QOS_ACK_POLICY_BLOCKACK;
else
- qos = mwl8k_qos_setbit_ack(qos,
- MWL8K_TXD_ACK_POLICY_NORMAL);
-
- if (qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
- qos = mwl8k_qos_setbit_amsdu(qos);
+ qos |= MWL8K_QOS_ACK_POLICY_NORMAL;
}
dma = pci_map_single(priv->pdev, skb->data,
@@ -1503,12 +1442,14 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
tx->pkt_phys_addr = cpu_to_le32(dma);
tx->pkt_len = cpu_to_le16(skb->len);
tx->rate_info = 0;
- tx->peer_id = mwl8k_vif->peer_id;
+ if (!priv->ap_fw && tx_info->control.sta != NULL)
+ tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id;
+ else
+ tx->peer_id = 0;
wmb();
tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus);
- txq->stats.count++;
- txq->stats.len++;
+ txq->len++;
priv->pending_tx_pkts++;
txq->tail++;
@@ -1656,6 +1597,56 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
return rc;
}
+static int mwl8k_post_pervif_cmd(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct mwl8k_cmd_pkt *cmd)
+{
+ if (vif != NULL)
+ cmd->macid = MWL8K_VIF(vif)->macid;
+ return mwl8k_post_cmd(hw, cmd);
+}
+
+/*
+ * Setup code shared between STA and AP firmware images.
+ */
+static void mwl8k_setup_2ghz_band(struct ieee80211_hw *hw)
+{
+ struct mwl8k_priv *priv = hw->priv;
+
+ BUILD_BUG_ON(sizeof(priv->channels_24) != sizeof(mwl8k_channels_24));
+ memcpy(priv->channels_24, mwl8k_channels_24, sizeof(mwl8k_channels_24));
+
+ BUILD_BUG_ON(sizeof(priv->rates_24) != sizeof(mwl8k_rates_24));
+ memcpy(priv->rates_24, mwl8k_rates_24, sizeof(mwl8k_rates_24));
+
+ priv->band_24.band = IEEE80211_BAND_2GHZ;
+ priv->band_24.channels = priv->channels_24;
+ priv->band_24.n_channels = ARRAY_SIZE(mwl8k_channels_24);
+ priv->band_24.bitrates = priv->rates_24;
+ priv->band_24.n_bitrates = ARRAY_SIZE(mwl8k_rates_24);
+
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band_24;
+}
+
+static void mwl8k_setup_5ghz_band(struct ieee80211_hw *hw)
+{
+ struct mwl8k_priv *priv = hw->priv;
+
+ BUILD_BUG_ON(sizeof(priv->channels_50) != sizeof(mwl8k_channels_50));
+ memcpy(priv->channels_50, mwl8k_channels_50, sizeof(mwl8k_channels_50));
+
+ BUILD_BUG_ON(sizeof(priv->rates_50) != sizeof(mwl8k_rates_50));
+ memcpy(priv->rates_50, mwl8k_rates_50, sizeof(mwl8k_rates_50));
+
+ priv->band_50.band = IEEE80211_BAND_5GHZ;
+ priv->band_50.channels = priv->channels_50;
+ priv->band_50.n_channels = ARRAY_SIZE(mwl8k_channels_50);
+ priv->band_50.bitrates = priv->rates_50;
+ priv->band_50.n_bitrates = ARRAY_SIZE(mwl8k_rates_50);
+
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->band_50;
+}
+
/*
* CMD_GET_HW_SPEC (STA version).
*/
@@ -1678,6 +1669,89 @@ struct mwl8k_cmd_get_hw_spec_sta {
__le32 total_rxd;
} __attribute__((packed));
+#define MWL8K_CAP_MAX_AMSDU 0x20000000
+#define MWL8K_CAP_GREENFIELD 0x08000000
+#define MWL8K_CAP_AMPDU 0x04000000
+#define MWL8K_CAP_RX_STBC 0x01000000
+#define MWL8K_CAP_TX_STBC 0x00800000
+#define MWL8K_CAP_SHORTGI_40MHZ 0x00400000
+#define MWL8K_CAP_SHORTGI_20MHZ 0x00200000
+#define MWL8K_CAP_RX_ANTENNA_MASK 0x000e0000
+#define MWL8K_CAP_TX_ANTENNA_MASK 0x0001c000
+#define MWL8K_CAP_DELAY_BA 0x00003000
+#define MWL8K_CAP_MIMO 0x00000200
+#define MWL8K_CAP_40MHZ 0x00000100
+#define MWL8K_CAP_BAND_MASK 0x00000007
+#define MWL8K_CAP_5GHZ 0x00000004
+#define MWL8K_CAP_2GHZ4 0x00000001
+
+static void
+mwl8k_set_ht_caps(struct ieee80211_hw *hw,
+ struct ieee80211_supported_band *band, u32 cap)
+{
+ int rx_streams;
+ int tx_streams;
+
+ band->ht_cap.ht_supported = 1;
+
+ if (cap & MWL8K_CAP_MAX_AMSDU)
+ band->ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+ if (cap & MWL8K_CAP_GREENFIELD)
+ band->ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD;
+ if (cap & MWL8K_CAP_AMPDU) {
+ hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+ band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
+ }
+ if (cap & MWL8K_CAP_RX_STBC)
+ band->ht_cap.cap |= IEEE80211_HT_CAP_RX_STBC;
+ if (cap & MWL8K_CAP_TX_STBC)
+ band->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC;
+ if (cap & MWL8K_CAP_SHORTGI_40MHZ)
+ band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+ if (cap & MWL8K_CAP_SHORTGI_20MHZ)
+ band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
+ if (cap & MWL8K_CAP_DELAY_BA)
+ band->ht_cap.cap |= IEEE80211_HT_CAP_DELAY_BA;
+ if (cap & MWL8K_CAP_40MHZ)
+ band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+ rx_streams = hweight32(cap & MWL8K_CAP_RX_ANTENNA_MASK);
+ tx_streams = hweight32(cap & MWL8K_CAP_TX_ANTENNA_MASK);
+
+ band->ht_cap.mcs.rx_mask[0] = 0xff;
+ if (rx_streams >= 2)
+ band->ht_cap.mcs.rx_mask[1] = 0xff;
+ if (rx_streams >= 3)
+ band->ht_cap.mcs.rx_mask[2] = 0xff;
+ band->ht_cap.mcs.rx_mask[4] = 0x01;
+ band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+
+ if (rx_streams != tx_streams) {
+ band->ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+ band->ht_cap.mcs.tx_params |= (tx_streams - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+ }
+}
+
+static void
+mwl8k_set_caps(struct ieee80211_hw *hw, u32 caps)
+{
+ struct mwl8k_priv *priv = hw->priv;
+
+ if ((caps & MWL8K_CAP_2GHZ4) || !(caps & MWL8K_CAP_BAND_MASK)) {
+ mwl8k_setup_2ghz_band(hw);
+ if (caps & MWL8K_CAP_MIMO)
+ mwl8k_set_ht_caps(hw, &priv->band_24, caps);
+ }
+
+ if (caps & MWL8K_CAP_5GHZ) {
+ mwl8k_setup_5ghz_band(hw);
+ if (caps & MWL8K_CAP_MIMO)
+ mwl8k_set_ht_caps(hw, &priv->band_50, caps);
+ }
+}
+
static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw)
{
struct mwl8k_priv *priv = hw->priv;
@@ -1708,6 +1782,9 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw)
priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs);
priv->fw_rev = le32_to_cpu(cmd->fw_rev);
priv->hw_rev = cmd->hw_rev;
+ mwl8k_set_caps(hw, le32_to_cpu(cmd->caps));
+ priv->ap_macids_supported = 0x00000000;
+ priv->sta_macids_supported = 0x00000001;
}
kfree(cmd);
@@ -1761,6 +1838,9 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs);
priv->fw_rev = le32_to_cpu(cmd->fw_rev);
priv->hw_rev = cmd->hw_rev;
+ mwl8k_setup_2ghz_band(hw);
+ priv->ap_macids_supported = 0x000000ff;
+ priv->sta_macids_supported = 0x00000000;
off = le32_to_cpu(cmd->wcbbase0) & 0xffff;
iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off);
@@ -1806,7 +1886,9 @@ struct mwl8k_cmd_set_hw_spec {
__le32 total_rxd;
} __attribute__((packed));
-#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080
+#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080
+#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020
+#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010
static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw)
{
@@ -1827,7 +1909,9 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw)
cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES);
for (i = 0; i < MWL8K_TX_QUEUES; i++)
cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma);
- cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT);
+ cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT |
+ MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP |
+ MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON);
cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS);
cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS);
@@ -1897,9 +1981,9 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti,
}
/*
- * CMD_802_11_GET_STAT.
+ * CMD_GET_STAT.
*/
-struct mwl8k_cmd_802_11_get_stat {
+struct mwl8k_cmd_get_stat {
struct mwl8k_cmd_pkt header;
__le32 stats[64];
} __attribute__((packed));
@@ -1909,10 +1993,10 @@ struct mwl8k_cmd_802_11_get_stat {
#define MWL8K_STAT_FCS_ERROR 24
#define MWL8K_STAT_RTS_SUCCESS 11
-static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw,
- struct ieee80211_low_level_stats *stats)
+static int mwl8k_cmd_get_stat(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
{
- struct mwl8k_cmd_802_11_get_stat *cmd;
+ struct mwl8k_cmd_get_stat *cmd;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -1939,9 +2023,9 @@ static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw,
}
/*
- * CMD_802_11_RADIO_CONTROL.
+ * CMD_RADIO_CONTROL.
*/
-struct mwl8k_cmd_802_11_radio_control {
+struct mwl8k_cmd_radio_control {
struct mwl8k_cmd_pkt header;
__le16 action;
__le16 control;
@@ -1949,10 +2033,10 @@ struct mwl8k_cmd_802_11_radio_control {
} __attribute__((packed));
static int
-mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
+mwl8k_cmd_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
{
struct mwl8k_priv *priv = hw->priv;
- struct mwl8k_cmd_802_11_radio_control *cmd;
+ struct mwl8k_cmd_radio_control *cmd;
int rc;
if (enable == priv->radio_on && !force)
@@ -1977,36 +2061,32 @@ mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
return rc;
}
-static int mwl8k_cmd_802_11_radio_disable(struct ieee80211_hw *hw)
+static int mwl8k_cmd_radio_disable(struct ieee80211_hw *hw)
{
- return mwl8k_cmd_802_11_radio_control(hw, 0, 0);
+ return mwl8k_cmd_radio_control(hw, 0, 0);
}
-static int mwl8k_cmd_802_11_radio_enable(struct ieee80211_hw *hw)
+static int mwl8k_cmd_radio_enable(struct ieee80211_hw *hw)
{
- return mwl8k_cmd_802_11_radio_control(hw, 1, 0);
+ return mwl8k_cmd_radio_control(hw, 1, 0);
}
static int
mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble)
{
- struct mwl8k_priv *priv;
-
- if (hw == NULL || hw->priv == NULL)
- return -EINVAL;
- priv = hw->priv;
+ struct mwl8k_priv *priv = hw->priv;
priv->radio_short_preamble = short_preamble;
- return mwl8k_cmd_802_11_radio_control(hw, 1, 1);
+ return mwl8k_cmd_radio_control(hw, 1, 1);
}
/*
- * CMD_802_11_RF_TX_POWER.
+ * CMD_RF_TX_POWER.
*/
#define MWL8K_TX_POWER_LEVEL_TOTAL 8
-struct mwl8k_cmd_802_11_rf_tx_power {
+struct mwl8k_cmd_rf_tx_power {
struct mwl8k_cmd_pkt header;
__le16 action;
__le16 support_level;
@@ -2015,9 +2095,9 @@ struct mwl8k_cmd_802_11_rf_tx_power {
__le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
} __attribute__((packed));
-static int mwl8k_cmd_802_11_rf_tx_power(struct ieee80211_hw *hw, int dBm)
+static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm)
{
- struct mwl8k_cmd_802_11_rf_tx_power *cmd;
+ struct mwl8k_cmd_rf_tx_power *cmd;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -2069,6 +2149,36 @@ mwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask)
}
/*
+ * CMD_SET_BEACON.
+ */
+struct mwl8k_cmd_set_beacon {
+ struct mwl8k_cmd_pkt header;
+ __le16 beacon_len;
+ __u8 beacon[0];
+};
+
+static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u8 *beacon, int len)
+{
+ struct mwl8k_cmd_set_beacon *cmd;
+ int rc;
+
+ cmd = kzalloc(sizeof(*cmd) + len, GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_BEACON);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd) + len);
+ cmd->beacon_len = cpu_to_le16(len);
+ memcpy(cmd->beacon, beacon, len);
+
+ rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
+ kfree(cmd);
+
+ return rc;
+}
+
+/*
* CMD_SET_PRE_SCAN.
*/
struct mwl8k_cmd_set_pre_scan {
@@ -2103,7 +2213,7 @@ struct mwl8k_cmd_set_post_scan {
} __attribute__((packed));
static int
-mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 *mac)
+mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac)
{
struct mwl8k_cmd_set_post_scan *cmd;
int rc;
@@ -2134,8 +2244,9 @@ struct mwl8k_cmd_set_rf_channel {
} __attribute__((packed));
static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
- struct ieee80211_channel *channel)
+ struct ieee80211_conf *conf)
{
+ struct ieee80211_channel *channel = conf->channel;
struct mwl8k_cmd_set_rf_channel *cmd;
int rc;
@@ -2147,10 +2258,19 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
cmd->header.length = cpu_to_le16(sizeof(*cmd));
cmd->action = cpu_to_le16(MWL8K_CMD_SET);
cmd->current_channel = channel->hw_value;
+
if (channel->band == IEEE80211_BAND_2GHZ)
- cmd->channel_flags = cpu_to_le32(0x00000081);
- else
- cmd->channel_flags = cpu_to_le32(0x00000000);
+ cmd->channel_flags |= cpu_to_le32(0x00000001);
+ else if (channel->band == IEEE80211_BAND_5GHZ)
+ cmd->channel_flags |= cpu_to_le32(0x00000004);
+
+ if (conf->channel_type == NL80211_CHAN_NO_HT ||
+ conf->channel_type == NL80211_CHAN_HT20)
+ cmd->channel_flags |= cpu_to_le32(0x00000080);
+ else if (conf->channel_type == NL80211_CHAN_HT40MINUS)
+ cmd->channel_flags |= cpu_to_le32(0x000001900);
+ else if (conf->channel_type == NL80211_CHAN_HT40PLUS)
+ cmd->channel_flags |= cpu_to_le32(0x000000900);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
@@ -2159,85 +2279,75 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
}
/*
- * CMD_SET_SLOT.
+ * CMD_SET_AID.
*/
-struct mwl8k_cmd_set_slot {
- struct mwl8k_cmd_pkt header;
- __le16 action;
- __u8 short_slot;
-} __attribute__((packed));
-
-static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
-{
- struct mwl8k_cmd_set_slot *cmd;
- int rc;
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (cmd == NULL)
- return -ENOMEM;
-
- cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT);
- cmd->header.length = cpu_to_le16(sizeof(*cmd));
- cmd->action = cpu_to_le16(MWL8K_CMD_SET);
- cmd->short_slot = short_slot_time;
-
- rc = mwl8k_post_cmd(hw, &cmd->header);
- kfree(cmd);
+#define MWL8K_FRAME_PROT_DISABLED 0x00
+#define MWL8K_FRAME_PROT_11G 0x07
+#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02
+#define MWL8K_FRAME_PROT_11N_HT_ALL 0x06
- return rc;
-}
+struct mwl8k_cmd_update_set_aid {
+ struct mwl8k_cmd_pkt header;
+ __le16 aid;
-/*
- * CMD_MIMO_CONFIG.
- */
-struct mwl8k_cmd_mimo_config {
- struct mwl8k_cmd_pkt header;
- __le32 action;
- __u8 rx_antenna_map;
- __u8 tx_antenna_map;
+ /* AP's MAC address (BSSID) */
+ __u8 bssid[ETH_ALEN];
+ __le16 protection_mode;
+ __u8 supp_rates[14];
} __attribute__((packed));
-static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx)
+static void legacy_rate_mask_to_array(u8 *rates, u32 mask)
{
- struct mwl8k_cmd_mimo_config *cmd;
- int rc;
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (cmd == NULL)
- return -ENOMEM;
-
- cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG);
- cmd->header.length = cpu_to_le16(sizeof(*cmd));
- cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET);
- cmd->rx_antenna_map = rx;
- cmd->tx_antenna_map = tx;
+ int i;
+ int j;
- rc = mwl8k_post_cmd(hw, &cmd->header);
- kfree(cmd);
+ /*
+ * Clear nonstandard rates 4 and 13.
+ */
+ mask &= 0x1fef;
- return rc;
+ for (i = 0, j = 0; i < 14; i++) {
+ if (mask & (1 << i))
+ rates[j++] = mwl8k_rates_24[i].hw_value;
+ }
}
-/*
- * CMD_ENABLE_SNIFFER.
- */
-struct mwl8k_cmd_enable_sniffer {
- struct mwl8k_cmd_pkt header;
- __le32 action;
-} __attribute__((packed));
-
-static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable)
+static int
+mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u32 legacy_rate_mask)
{
- struct mwl8k_cmd_enable_sniffer *cmd;
+ struct mwl8k_cmd_update_set_aid *cmd;
+ u16 prot_mode;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
- cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER);
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
- cmd->action = cpu_to_le32(!!enable);
+ cmd->aid = cpu_to_le16(vif->bss_conf.aid);
+ memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN);
+
+ if (vif->bss_conf.use_cts_prot) {
+ prot_mode = MWL8K_FRAME_PROT_11G;
+ } else {
+ switch (vif->bss_conf.ht_operation_mode &
+ IEEE80211_HT_OP_MODE_PROTECTION) {
+ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
+ prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY;
+ break;
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
+ prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL;
+ break;
+ default:
+ prot_mode = MWL8K_FRAME_PROT_DISABLED;
+ break;
+ }
+ }
+ cmd->protection_mode = cpu_to_le16(prot_mode);
+
+ legacy_rate_mask_to_array(cmd->supp_rates, legacy_rate_mask);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
@@ -2246,37 +2356,32 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable)
}
/*
- * CMD_SET_MAC_ADDR.
+ * CMD_SET_RATE.
*/
-struct mwl8k_cmd_set_mac_addr {
- struct mwl8k_cmd_pkt header;
- union {
- struct {
- __le16 mac_type;
- __u8 mac_addr[ETH_ALEN];
- } mbss;
- __u8 mac_addr[ETH_ALEN];
- };
+struct mwl8k_cmd_set_rate {
+ struct mwl8k_cmd_pkt header;
+ __u8 legacy_rates[14];
+
+ /* Bitmap for supported MCS codes. */
+ __u8 mcs_set[16];
+ __u8 reserved[16];
} __attribute__((packed));
-static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac)
+static int
+mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u32 legacy_rate_mask, u8 *mcs_rates)
{
- struct mwl8k_priv *priv = hw->priv;
- struct mwl8k_cmd_set_mac_addr *cmd;
+ struct mwl8k_cmd_set_rate *cmd;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
- cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR);
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
- if (priv->ap_fw) {
- cmd->mbss.mac_type = 0;
- memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN);
- } else {
- memcpy(cmd->mac_addr, mac, ETH_ALEN);
- }
+ legacy_rate_mask_to_array(cmd->legacy_rates, legacy_rate_mask);
+ memcpy(cmd->mcs_set, mcs_rates, 16);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
@@ -2284,29 +2389,40 @@ static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac)
return rc;
}
-
/*
- * CMD_SET_RATEADAPT_MODE.
+ * CMD_FINALIZE_JOIN.
*/
-struct mwl8k_cmd_set_rate_adapt_mode {
+#define MWL8K_FJ_BEACON_MAXLEN 128
+
+struct mwl8k_cmd_finalize_join {
struct mwl8k_cmd_pkt header;
- __le16 action;
- __le16 mode;
+ __le32 sleep_interval; /* Number of beacon periods to sleep */
+ __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN];
} __attribute__((packed));
-static int mwl8k_cmd_setrateadaptmode(struct ieee80211_hw *hw, __u16 mode)
+static int mwl8k_cmd_finalize_join(struct ieee80211_hw *hw, void *frame,
+ int framelen, int dtim)
{
- struct mwl8k_cmd_set_rate_adapt_mode *cmd;
+ struct mwl8k_cmd_finalize_join *cmd;
+ struct ieee80211_mgmt *payload = frame;
+ int payload_len;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
- cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE);
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
- cmd->action = cpu_to_le16(MWL8K_CMD_SET);
- cmd->mode = cpu_to_le16(mode);
+ cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1);
+
+ payload_len = framelen - ieee80211_hdrlen(payload->frame_control);
+ if (payload_len < 0)
+ payload_len = 0;
+ else if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
+ payload_len = MWL8K_FJ_BEACON_MAXLEN;
+
+ memcpy(cmd->beacon_data, &payload->u.beacon, payload_len);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
@@ -2315,59 +2431,57 @@ static int mwl8k_cmd_setrateadaptmode(struct ieee80211_hw *hw, __u16 mode)
}
/*
- * CMD_SET_WMM_MODE.
+ * CMD_SET_RTS_THRESHOLD.
*/
-struct mwl8k_cmd_set_wmm {
+struct mwl8k_cmd_set_rts_threshold {
struct mwl8k_cmd_pkt header;
__le16 action;
+ __le16 threshold;
} __attribute__((packed));
-static int mwl8k_set_wmm(struct ieee80211_hw *hw, bool enable)
+static int
+mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh)
{
- struct mwl8k_priv *priv = hw->priv;
- struct mwl8k_cmd_set_wmm *cmd;
+ struct mwl8k_cmd_set_rts_threshold *cmd;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
- cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE);
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
- cmd->action = cpu_to_le16(!!enable);
+ cmd->action = cpu_to_le16(MWL8K_CMD_SET);
+ cmd->threshold = cpu_to_le16(rts_thresh);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
- if (!rc)
- priv->wmm_enabled = enable;
-
return rc;
}
/*
- * CMD_SET_RTS_THRESHOLD.
+ * CMD_SET_SLOT.
*/
-struct mwl8k_cmd_rts_threshold {
+struct mwl8k_cmd_set_slot {
struct mwl8k_cmd_pkt header;
__le16 action;
- __le16 threshold;
+ __u8 short_slot;
} __attribute__((packed));
-static int mwl8k_rts_threshold(struct ieee80211_hw *hw,
- u16 action, u16 threshold)
+static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
{
- struct mwl8k_cmd_rts_threshold *cmd;
+ struct mwl8k_cmd_set_slot *cmd;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
- cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD);
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
- cmd->action = cpu_to_le16(action);
- cmd->threshold = cpu_to_le16(threshold);
+ cmd->action = cpu_to_le16(MWL8K_CMD_SET);
+ cmd->short_slot = short_slot_time;
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
@@ -2426,9 +2540,9 @@ struct mwl8k_cmd_set_edca_params {
MWL8K_SET_EDCA_AIFS)
static int
-mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
- __u16 cw_min, __u16 cw_max,
- __u8 aifs, __u16 txop)
+mwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
+ __u16 cw_min, __u16 cw_max,
+ __u8 aifs, __u16 txop)
{
struct mwl8k_priv *priv = hw->priv;
struct mwl8k_cmd_set_edca_params *cmd;
@@ -2438,12 +2552,6 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
if (cmd == NULL)
return -ENOMEM;
- /*
- * Queues 0 (BE) and 1 (BK) are swapped in hardware for
- * this call.
- */
- qnum ^= !(qnum >> 1);
-
cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL);
@@ -2467,170 +2575,259 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
}
/*
- * CMD_FINALIZE_JOIN.
+ * CMD_SET_WMM_MODE.
*/
-#define MWL8K_FJ_BEACON_MAXLEN 128
-
-struct mwl8k_cmd_finalize_join {
+struct mwl8k_cmd_set_wmm_mode {
struct mwl8k_cmd_pkt header;
- __le32 sleep_interval; /* Number of beacon periods to sleep */
- __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN];
+ __le16 action;
} __attribute__((packed));
-static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame,
- int framelen, int dtim)
+static int mwl8k_cmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable)
{
- struct mwl8k_cmd_finalize_join *cmd;
- struct ieee80211_mgmt *payload = frame;
- int payload_len;
+ struct mwl8k_priv *priv = hw->priv;
+ struct mwl8k_cmd_set_wmm_mode *cmd;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
- cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN);
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
- cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1);
-
- payload_len = framelen - ieee80211_hdrlen(payload->frame_control);
- if (payload_len < 0)
- payload_len = 0;
- else if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
- payload_len = MWL8K_FJ_BEACON_MAXLEN;
-
- memcpy(cmd->beacon_data, &payload->u.beacon, payload_len);
+ cmd->action = cpu_to_le16(!!enable);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
+ if (!rc)
+ priv->wmm_enabled = enable;
+
return rc;
}
/*
- * CMD_UPDATE_STADB.
+ * CMD_MIMO_CONFIG.
*/
-struct mwl8k_cmd_update_sta_db {
+struct mwl8k_cmd_mimo_config {
struct mwl8k_cmd_pkt header;
+ __le32 action;
+ __u8 rx_antenna_map;
+ __u8 tx_antenna_map;
+} __attribute__((packed));
- /* See STADB_ACTION_TYPE */
- __le32 action;
+static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx)
+{
+ struct mwl8k_cmd_mimo_config *cmd;
+ int rc;
- /* Peer MAC address */
- __u8 peer_addr[ETH_ALEN];
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
- __le32 reserved;
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+ cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET);
+ cmd->rx_antenna_map = rx;
+ cmd->tx_antenna_map = tx;
- /* Peer info - valid during add/update. */
- struct peer_capability_info peer_info;
+ rc = mwl8k_post_cmd(hw, &cmd->header);
+ kfree(cmd);
+
+ return rc;
+}
+
+/*
+ * CMD_USE_FIXED_RATE (STA version).
+ */
+struct mwl8k_cmd_use_fixed_rate_sta {
+ struct mwl8k_cmd_pkt header;
+ __le32 action;
+ __le32 allow_rate_drop;
+ __le32 num_rates;
+ struct {
+ __le32 is_ht_rate;
+ __le32 enable_retry;
+ __le32 rate;
+ __le32 retry_count;
+ } rate_entry[8];
+ __le32 rate_type;
+ __le32 reserved1;
+ __le32 reserved2;
} __attribute__((packed));
-static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, __u32 action)
+#define MWL8K_USE_AUTO_RATE 0x0002
+#define MWL8K_UCAST_RATE 0
+
+static int mwl8k_cmd_use_fixed_rate_sta(struct ieee80211_hw *hw)
{
- struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
- struct ieee80211_bss_conf *info = &mv_vif->bss_info;
- struct mwl8k_cmd_update_sta_db *cmd;
- struct peer_capability_info *peer_info;
+ struct mwl8k_cmd_use_fixed_rate_sta *cmd;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
- cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB);
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
+ cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE);
+ cmd->rate_type = cpu_to_le32(MWL8K_UCAST_RATE);
- cmd->action = cpu_to_le32(action);
- peer_info = &cmd->peer_info;
- memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN);
+ rc = mwl8k_post_cmd(hw, &cmd->header);
+ kfree(cmd);
- switch (action) {
- case MWL8K_STA_DB_ADD_ENTRY:
- case MWL8K_STA_DB_MODIFY_ENTRY:
- /* Build peer_info block */
- peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT;
- peer_info->basic_caps = cpu_to_le16(info->assoc_capability);
- memcpy(peer_info->legacy_rates, mwl8k_rateids,
- sizeof(mwl8k_rateids));
- peer_info->interop = 1;
- peer_info->amsdu_enabled = 0;
-
- rc = mwl8k_post_cmd(hw, &cmd->header);
- if (rc == 0)
- mv_vif->peer_id = peer_info->station_id;
+ return rc;
+}
- break;
+/*
+ * CMD_USE_FIXED_RATE (AP version).
+ */
+struct mwl8k_cmd_use_fixed_rate_ap {
+ struct mwl8k_cmd_pkt header;
+ __le32 action;
+ __le32 allow_rate_drop;
+ __le32 num_rates;
+ struct mwl8k_rate_entry_ap {
+ __le32 is_ht_rate;
+ __le32 enable_retry;
+ __le32 rate;
+ __le32 retry_count;
+ } rate_entry[4];
+ u8 multicast_rate;
+ u8 multicast_rate_type;
+ u8 management_rate;
+} __attribute__((packed));
- case MWL8K_STA_DB_DEL_ENTRY:
- case MWL8K_STA_DB_FLUSH:
- default:
- rc = mwl8k_post_cmd(hw, &cmd->header);
- if (rc == 0)
- mv_vif->peer_id = 0;
- break;
- }
+static int
+mwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt)
+{
+ struct mwl8k_cmd_use_fixed_rate_ap *cmd;
+ int rc;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+ cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE);
+ cmd->multicast_rate = mcast;
+ cmd->management_rate = mgmt;
+
+ rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
return rc;
}
/*
- * CMD_SET_AID.
+ * CMD_ENABLE_SNIFFER.
*/
-#define MWL8K_FRAME_PROT_DISABLED 0x00
-#define MWL8K_FRAME_PROT_11G 0x07
-#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02
-#define MWL8K_FRAME_PROT_11N_HT_ALL 0x06
-
-struct mwl8k_cmd_update_set_aid {
- struct mwl8k_cmd_pkt header;
- __le16 aid;
-
- /* AP's MAC address (BSSID) */
- __u8 bssid[ETH_ALEN];
- __le16 protection_mode;
- __u8 supp_rates[14];
+struct mwl8k_cmd_enable_sniffer {
+ struct mwl8k_cmd_pkt header;
+ __le32 action;
} __attribute__((packed));
-static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+static int mwl8k_cmd_enable_sniffer(struct ieee80211_hw *hw, bool enable)
{
- struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
- struct ieee80211_bss_conf *info = &mv_vif->bss_info;
- struct mwl8k_cmd_update_set_aid *cmd;
- u16 prot_mode;
+ struct mwl8k_cmd_enable_sniffer *cmd;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
- cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID);
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
- cmd->aid = cpu_to_le16(info->aid);
+ cmd->action = cpu_to_le32(!!enable);
- memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN);
+ rc = mwl8k_post_cmd(hw, &cmd->header);
+ kfree(cmd);
- if (info->use_cts_prot) {
- prot_mode = MWL8K_FRAME_PROT_11G;
+ return rc;
+}
+
+/*
+ * CMD_SET_MAC_ADDR.
+ */
+struct mwl8k_cmd_set_mac_addr {
+ struct mwl8k_cmd_pkt header;
+ union {
+ struct {
+ __le16 mac_type;
+ __u8 mac_addr[ETH_ALEN];
+ } mbss;
+ __u8 mac_addr[ETH_ALEN];
+ };
+} __attribute__((packed));
+
+#define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0
+#define MWL8K_MAC_TYPE_SECONDARY_CLIENT 1
+#define MWL8K_MAC_TYPE_PRIMARY_AP 2
+#define MWL8K_MAC_TYPE_SECONDARY_AP 3
+
+static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u8 *mac)
+{
+ struct mwl8k_priv *priv = hw->priv;
+ struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+ struct mwl8k_cmd_set_mac_addr *cmd;
+ int mac_type;
+ int rc;
+
+ mac_type = MWL8K_MAC_TYPE_PRIMARY_AP;
+ if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) {
+ if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported))
+ mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT;
+ else
+ mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT;
+ } else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) {
+ if (mwl8k_vif->macid + 1 == ffs(priv->ap_macids_supported))
+ mac_type = MWL8K_MAC_TYPE_PRIMARY_AP;
+ else
+ mac_type = MWL8K_MAC_TYPE_SECONDARY_AP;
+ }
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+ if (priv->ap_fw) {
+ cmd->mbss.mac_type = cpu_to_le16(mac_type);
+ memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN);
} else {
- switch (info->ht_operation_mode &
- IEEE80211_HT_OP_MODE_PROTECTION) {
- case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
- prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY;
- break;
- case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
- prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL;
- break;
- default:
- prot_mode = MWL8K_FRAME_PROT_DISABLED;
- break;
- }
+ memcpy(cmd->mac_addr, mac, ETH_ALEN);
}
- cmd->protection_mode = cpu_to_le16(prot_mode);
- memcpy(cmd->supp_rates, mwl8k_rateids, sizeof(mwl8k_rateids));
+ rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
+ kfree(cmd);
+
+ return rc;
+}
+
+/*
+ * CMD_SET_RATEADAPT_MODE.
+ */
+struct mwl8k_cmd_set_rate_adapt_mode {
+ struct mwl8k_cmd_pkt header;
+ __le16 action;
+ __le16 mode;
+} __attribute__((packed));
+
+static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode)
+{
+ struct mwl8k_cmd_set_rate_adapt_mode *cmd;
+ int rc;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+ cmd->action = cpu_to_le16(MWL8K_CMD_SET);
+ cmd->mode = cpu_to_le16(mode);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
@@ -2639,115 +2836,255 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
}
/*
- * CMD_SET_RATE.
+ * CMD_BSS_START.
*/
-struct mwl8k_cmd_update_rateset {
- struct mwl8k_cmd_pkt header;
- __u8 legacy_rates[14];
-
- /* Bitmap for supported MCS codes. */
- __u8 mcs_set[16];
- __u8 reserved[16];
+struct mwl8k_cmd_bss_start {
+ struct mwl8k_cmd_pkt header;
+ __le32 enable;
} __attribute__((packed));
-static int mwl8k_update_rateset(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, int enable)
{
- struct mwl8k_cmd_update_rateset *cmd;
+ struct mwl8k_cmd_bss_start *cmd;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
- cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE);
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_BSS_START);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
- memcpy(cmd->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids));
+ cmd->enable = cpu_to_le32(enable);
- rc = mwl8k_post_cmd(hw, &cmd->header);
+ rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
kfree(cmd);
return rc;
}
/*
- * CMD_USE_FIXED_RATE.
+ * CMD_SET_NEW_STN.
*/
-#define MWL8K_RATE_TABLE_SIZE 8
-#define MWL8K_UCAST_RATE 0
-#define MWL8K_USE_AUTO_RATE 0x0002
+struct mwl8k_cmd_set_new_stn {
+ struct mwl8k_cmd_pkt header;
+ __le16 aid;
+ __u8 mac_addr[6];
+ __le16 stn_id;
+ __le16 action;
+ __le16 rsvd;
+ __le32 legacy_rates;
+ __u8 ht_rates[4];
+ __le16 cap_info;
+ __le16 ht_capabilities_info;
+ __u8 mac_ht_param_info;
+ __u8 rev;
+ __u8 control_channel;
+ __u8 add_channel;
+ __le16 op_mode;
+ __le16 stbc;
+ __u8 add_qos_info;
+ __u8 is_qos_sta;
+ __le32 fw_sta_ptr;
+} __attribute__((packed));
+
+#define MWL8K_STA_ACTION_ADD 0
+#define MWL8K_STA_ACTION_REMOVE 2
+
+static int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mwl8k_cmd_set_new_stn *cmd;
+ u32 rates;
+ int rc;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+ cmd->aid = cpu_to_le16(sta->aid);
+ memcpy(cmd->mac_addr, sta->addr, ETH_ALEN);
+ cmd->stn_id = cpu_to_le16(sta->aid);
+ cmd->action = cpu_to_le16(MWL8K_STA_ACTION_ADD);
+ if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+ rates = sta->supp_rates[IEEE80211_BAND_2GHZ];
+ else
+ rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5;
+ cmd->legacy_rates = cpu_to_le32(rates);
+ if (sta->ht_cap.ht_supported) {
+ cmd->ht_rates[0] = sta->ht_cap.mcs.rx_mask[0];
+ cmd->ht_rates[1] = sta->ht_cap.mcs.rx_mask[1];
+ cmd->ht_rates[2] = sta->ht_cap.mcs.rx_mask[2];
+ cmd->ht_rates[3] = sta->ht_cap.mcs.rx_mask[3];
+ cmd->ht_capabilities_info = cpu_to_le16(sta->ht_cap.cap);
+ cmd->mac_ht_param_info = (sta->ht_cap.ampdu_factor & 3) |
+ ((sta->ht_cap.ampdu_density & 7) << 2);
+ cmd->is_qos_sta = 1;
+ }
+
+ rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
+ kfree(cmd);
+
+ return rc;
+}
+
+static int mwl8k_cmd_set_new_stn_add_self(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct mwl8k_cmd_set_new_stn *cmd;
+ int rc;
-struct mwl8k_rate_entry {
- /* Set to 1 if HT rate, 0 if legacy. */
- __le32 is_ht_rate;
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
- /* Set to 1 to use retry_count field. */
- __le32 enable_retry;
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+ memcpy(cmd->mac_addr, vif->addr, ETH_ALEN);
- /* Specified legacy rate or MCS. */
- __le32 rate;
+ rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
+ kfree(cmd);
- /* Number of allowed retries. */
- __le32 retry_count;
+ return rc;
+}
+
+static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u8 *addr)
+{
+ struct mwl8k_cmd_set_new_stn *cmd;
+ int rc;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+ memcpy(cmd->mac_addr, addr, ETH_ALEN);
+ cmd->action = cpu_to_le16(MWL8K_STA_ACTION_REMOVE);
+
+ rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
+ kfree(cmd);
+
+ return rc;
+}
+
+/*
+ * CMD_UPDATE_STADB.
+ */
+struct ewc_ht_info {
+ __le16 control1;
+ __le16 control2;
+ __le16 control3;
} __attribute__((packed));
-struct mwl8k_rate_table {
- /* 1 to allow specified rate and below */
- __le32 allow_rate_drop;
- __le32 num_rates;
- struct mwl8k_rate_entry rate_entry[MWL8K_RATE_TABLE_SIZE];
+struct peer_capability_info {
+ /* Peer type - AP vs. STA. */
+ __u8 peer_type;
+
+ /* Basic 802.11 capabilities from assoc resp. */
+ __le16 basic_caps;
+
+ /* Set if peer supports 802.11n high throughput (HT). */
+ __u8 ht_support;
+
+ /* Valid if HT is supported. */
+ __le16 ht_caps;
+ __u8 extended_ht_caps;
+ struct ewc_ht_info ewc_info;
+
+ /* Legacy rate table. Intersection of our rates and peer rates. */
+ __u8 legacy_rates[12];
+
+ /* HT rate table. Intersection of our rates and peer rates. */
+ __u8 ht_rates[16];
+ __u8 pad[16];
+
+ /* If set, interoperability mode, no proprietary extensions. */
+ __u8 interop;
+ __u8 pad2;
+ __u8 station_id;
+ __le16 amsdu_enabled;
} __attribute__((packed));
-struct mwl8k_cmd_use_fixed_rate {
- struct mwl8k_cmd_pkt header;
+struct mwl8k_cmd_update_stadb {
+ struct mwl8k_cmd_pkt header;
+
+ /* See STADB_ACTION_TYPE */
__le32 action;
- struct mwl8k_rate_table rate_table;
- /* Unicast, Broadcast or Multicast */
- __le32 rate_type;
- __le32 reserved1;
- __le32 reserved2;
+ /* Peer MAC address */
+ __u8 peer_addr[ETH_ALEN];
+
+ __le32 reserved;
+
+ /* Peer info - valid during add/update. */
+ struct peer_capability_info peer_info;
} __attribute__((packed));
-static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw,
- u32 action, u32 rate_type, struct mwl8k_rate_table *rate_table)
+#define MWL8K_STA_DB_MODIFY_ENTRY 1
+#define MWL8K_STA_DB_DEL_ENTRY 2
+
+/* Peer Entry flags - used to define the type of the peer node */
+#define MWL8K_PEER_TYPE_ACCESSPOINT 2
+
+static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
{
- struct mwl8k_cmd_use_fixed_rate *cmd;
- int count;
+ struct mwl8k_cmd_update_stadb *cmd;
+ struct peer_capability_info *p;
+ u32 rates;
int rc;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
- cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE);
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
+ cmd->action = cpu_to_le32(MWL8K_STA_DB_MODIFY_ENTRY);
+ memcpy(cmd->peer_addr, sta->addr, ETH_ALEN);
+
+ p = &cmd->peer_info;
+ p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT;
+ p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability);
+ p->ht_support = sta->ht_cap.ht_supported;
+ p->ht_caps = sta->ht_cap.cap;
+ p->extended_ht_caps = (sta->ht_cap.ampdu_factor & 3) |
+ ((sta->ht_cap.ampdu_density & 7) << 2);
+ if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+ rates = sta->supp_rates[IEEE80211_BAND_2GHZ];
+ else
+ rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5;
+ legacy_rate_mask_to_array(p->legacy_rates, rates);
+ memcpy(p->ht_rates, sta->ht_cap.mcs.rx_mask, 16);
+ p->interop = 1;
+ p->amsdu_enabled = 0;
- cmd->action = cpu_to_le32(action);
- cmd->rate_type = cpu_to_le32(rate_type);
+ rc = mwl8k_post_cmd(hw, &cmd->header);
+ kfree(cmd);
- if (rate_table != NULL) {
- /*
- * Copy over each field manually so that endian
- * conversion can be done.
- */
- cmd->rate_table.allow_rate_drop =
- cpu_to_le32(rate_table->allow_rate_drop);
- cmd->rate_table.num_rates =
- cpu_to_le32(rate_table->num_rates);
-
- for (count = 0; count < rate_table->num_rates; count++) {
- struct mwl8k_rate_entry *dst =
- &cmd->rate_table.rate_entry[count];
- struct mwl8k_rate_entry *src =
- &rate_table->rate_entry[count];
-
- dst->is_ht_rate = cpu_to_le32(src->is_ht_rate);
- dst->enable_retry = cpu_to_le32(src->enable_retry);
- dst->rate = cpu_to_le32(src->rate);
- dst->retry_count = cpu_to_le32(src->retry_count);
- }
- }
+ return rc ? rc : p->station_id;
+}
+
+static int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u8 *addr)
+{
+ struct mwl8k_cmd_update_stadb *cmd;
+ int rc;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+ cmd->action = cpu_to_le32(MWL8K_STA_DB_DEL_ENTRY);
+ memcpy(cmd->peer_addr, addr, ETH_ALEN);
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
@@ -2766,19 +3103,22 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
u32 status;
status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
- iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
-
if (!status)
return IRQ_NONE;
- if (status & MWL8K_A2H_INT_TX_DONE)
- tasklet_schedule(&priv->tx_reclaim_task);
+ if (status & MWL8K_A2H_INT_TX_DONE) {
+ status &= ~MWL8K_A2H_INT_TX_DONE;
+ tasklet_schedule(&priv->poll_tx_task);
+ }
if (status & MWL8K_A2H_INT_RX_READY) {
- while (rxq_process(hw, 0, 1))
- rxq_refill(hw, 0, 1);
+ status &= ~MWL8K_A2H_INT_RX_READY;
+ tasklet_schedule(&priv->poll_rx_task);
}
+ if (status)
+ iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+
if (status & MWL8K_A2H_INT_OPC_DONE) {
if (priv->hostcmd_wait != NULL)
complete(priv->hostcmd_wait);
@@ -2793,6 +3133,53 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void mwl8k_tx_poll(unsigned long data)
+{
+ struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+ struct mwl8k_priv *priv = hw->priv;
+ int limit;
+ int i;
+
+ limit = 32;
+
+ spin_lock_bh(&priv->tx_lock);
+
+ for (i = 0; i < MWL8K_TX_QUEUES; i++)
+ limit -= mwl8k_txq_reclaim(hw, i, limit, 0);
+
+ if (!priv->pending_tx_pkts && priv->tx_wait != NULL) {
+ complete(priv->tx_wait);
+ priv->tx_wait = NULL;
+ }
+
+ spin_unlock_bh(&priv->tx_lock);
+
+ if (limit) {
+ writel(~MWL8K_A2H_INT_TX_DONE,
+ priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+ } else {
+ tasklet_schedule(&priv->poll_tx_task);
+ }
+}
+
+static void mwl8k_rx_poll(unsigned long data)
+{
+ struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+ struct mwl8k_priv *priv = hw->priv;
+ int limit;
+
+ limit = 32;
+ limit -= rxq_process(hw, 0, limit);
+ limit -= rxq_refill(hw, 0, limit);
+
+ if (limit) {
+ writel(~MWL8K_A2H_INT_RX_READY,
+ priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+ } else {
+ tasklet_schedule(&priv->poll_rx_task);
+ }
+}
+
/*
* Core driver operations.
@@ -2803,7 +3190,7 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
int index = skb_get_queue_mapping(skb);
int rc;
- if (priv->current_channel == NULL) {
+ if (!priv->radio_on) {
printk(KERN_DEBUG "%s: dropped TX frame since radio "
"disabled\n", wiphy_name(hw->wiphy));
dev_kfree_skb(skb);
@@ -2828,19 +3215,20 @@ static int mwl8k_start(struct ieee80211_hw *hw)
return -EIO;
}
- /* Enable tx reclaim tasklet */
- tasklet_enable(&priv->tx_reclaim_task);
+ /* Enable TX reclaim and RX tasklets. */
+ tasklet_enable(&priv->poll_tx_task);
+ tasklet_enable(&priv->poll_rx_task);
/* Enable interrupts */
iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
rc = mwl8k_fw_lock(hw);
if (!rc) {
- rc = mwl8k_cmd_802_11_radio_enable(hw);
+ rc = mwl8k_cmd_radio_enable(hw);
if (!priv->ap_fw) {
if (!rc)
- rc = mwl8k_enable_sniffer(hw, 0);
+ rc = mwl8k_cmd_enable_sniffer(hw, 0);
if (!rc)
rc = mwl8k_cmd_set_pre_scan(hw);
@@ -2851,10 +3239,10 @@ static int mwl8k_start(struct ieee80211_hw *hw)
}
if (!rc)
- rc = mwl8k_cmd_setrateadaptmode(hw, 0);
+ rc = mwl8k_cmd_set_rateadapt_mode(hw, 0);
if (!rc)
- rc = mwl8k_set_wmm(hw, 0);
+ rc = mwl8k_cmd_set_wmm_mode(hw, 0);
mwl8k_fw_unlock(hw);
}
@@ -2862,7 +3250,8 @@ static int mwl8k_start(struct ieee80211_hw *hw)
if (rc) {
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
free_irq(priv->pdev->irq, hw);
- tasklet_disable(&priv->tx_reclaim_task);
+ tasklet_disable(&priv->poll_tx_task);
+ tasklet_disable(&priv->poll_rx_task);
}
return rc;
@@ -2873,7 +3262,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
struct mwl8k_priv *priv = hw->priv;
int i;
- mwl8k_cmd_802_11_radio_disable(hw);
+ mwl8k_cmd_radio_disable(hw);
ieee80211_stop_queues(hw);
@@ -2886,36 +3275,27 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
if (priv->beacon_skb != NULL)
dev_kfree_skb(priv->beacon_skb);
- /* Stop tx reclaim tasklet */
- tasklet_disable(&priv->tx_reclaim_task);
+ /* Stop TX reclaim and RX tasklets. */
+ tasklet_disable(&priv->poll_tx_task);
+ tasklet_disable(&priv->poll_rx_task);
/* Return all skbs to mac80211 */
for (i = 0; i < MWL8K_TX_QUEUES; i++)
- mwl8k_txq_reclaim(hw, i, 1);
+ mwl8k_txq_reclaim(hw, i, INT_MAX, 1);
}
static int mwl8k_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct mwl8k_priv *priv = hw->priv;
struct mwl8k_vif *mwl8k_vif;
-
- /*
- * We only support one active interface at a time.
- */
- if (priv->vif != NULL)
- return -EBUSY;
-
- /*
- * We only support managed interfaces for now.
- */
- if (conf->type != NL80211_IFTYPE_STATION)
- return -EINVAL;
+ u32 macids_supported;
+ int macid;
/*
* Reject interface creation if sniffer mode is active, as
* STA operation is mutually exclusive with hardware sniffer
- * mode.
+ * mode. (Sniffer mode is only used on STA firmware.)
*/
if (priv->sniffer_enabled) {
printk(KERN_INFO "%s: unable to create STA "
@@ -2924,37 +3304,54 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
return -EINVAL;
}
- /* Clean out driver private area */
- mwl8k_vif = MWL8K_VIF(conf->vif);
- memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
- /* Set and save the mac address */
- mwl8k_set_mac_addr(hw, conf->mac_addr);
- memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN);
+ switch (vif->type) {
+ case NL80211_IFTYPE_AP:
+ macids_supported = priv->ap_macids_supported;
+ break;
+ case NL80211_IFTYPE_STATION:
+ macids_supported = priv->sta_macids_supported;
+ break;
+ default:
+ return -EINVAL;
+ }
- /* Back pointer to parent config block */
- mwl8k_vif->priv = priv;
+ macid = ffs(macids_supported & ~priv->macids_used);
+ if (!macid--)
+ return -EBUSY;
- /* Set Initial sequence number to zero */
+ /* Setup driver private area. */
+ mwl8k_vif = MWL8K_VIF(vif);
+ memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
+ mwl8k_vif->vif = vif;
+ mwl8k_vif->macid = macid;
mwl8k_vif->seqno = 0;
- priv->vif = conf->vif;
- priv->current_channel = NULL;
+ /* Set the mac address. */
+ mwl8k_cmd_set_mac_addr(hw, vif, vif->addr);
+
+ if (priv->ap_fw)
+ mwl8k_cmd_set_new_stn_add_self(hw, vif);
+
+ priv->macids_used |= 1 << mwl8k_vif->macid;
+ list_add_tail(&mwl8k_vif->list, &priv->vif_list);
return 0;
}
static void mwl8k_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct mwl8k_priv *priv = hw->priv;
+ struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
- if (priv->vif == NULL)
- return;
+ if (priv->ap_fw)
+ mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr);
- mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00");
+ mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00");
- priv->vif = NULL;
+ priv->macids_used &= ~(1 << mwl8k_vif->macid);
+ list_del(&mwl8k_vif->list);
}
static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
@@ -2964,8 +3361,7 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
int rc;
if (conf->flags & IEEE80211_CONF_IDLE) {
- mwl8k_cmd_802_11_radio_disable(hw);
- priv->current_channel = NULL;
+ mwl8k_cmd_radio_disable(hw);
return 0;
}
@@ -2973,19 +3369,17 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
if (rc)
return rc;
- rc = mwl8k_cmd_802_11_radio_enable(hw);
+ rc = mwl8k_cmd_radio_enable(hw);
if (rc)
goto out;
- rc = mwl8k_cmd_set_rf_channel(hw, conf->channel);
+ rc = mwl8k_cmd_set_rf_channel(hw, conf);
if (rc)
goto out;
- priv->current_channel = conf->channel;
-
if (conf->power_level > 18)
conf->power_level = 18;
- rc = mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level);
+ rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level);
if (rc)
goto out;
@@ -3003,79 +3397,160 @@ out:
return rc;
}
-static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info,
- u32 changed)
+static void
+mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info, u32 changed)
{
struct mwl8k_priv *priv = hw->priv;
- struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+ u32 ap_legacy_rates;
+ u8 ap_mcs_rates[16];
int rc;
- if ((changed & BSS_CHANGED_ASSOC) == 0)
+ if (mwl8k_fw_lock(hw))
return;
- priv->capture_beacon = false;
-
- rc = mwl8k_fw_lock(hw);
- if (rc)
- return;
+ /*
+ * No need to capture a beacon if we're no longer associated.
+ */
+ if ((changed & BSS_CHANGED_ASSOC) && !vif->bss_conf.assoc)
+ priv->capture_beacon = false;
- if (info->assoc) {
- memcpy(&mwl8k_vif->bss_info, info,
- sizeof(struct ieee80211_bss_conf));
+ /*
+ * Get the AP's legacy and MCS rates.
+ */
+ if (vif->bss_conf.assoc) {
+ struct ieee80211_sta *ap;
- memcpy(mwl8k_vif->bssid, info->bssid, ETH_ALEN);
+ rcu_read_lock();
- /* Install rates */
- rc = mwl8k_update_rateset(hw, vif);
- if (rc)
+ ap = ieee80211_find_sta(vif, vif->bss_conf.bssid);
+ if (ap == NULL) {
+ rcu_read_unlock();
goto out;
+ }
+
+ if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
+ ap_legacy_rates = ap->supp_rates[IEEE80211_BAND_2GHZ];
+ } else {
+ ap_legacy_rates =
+ ap->supp_rates[IEEE80211_BAND_5GHZ] << 5;
+ }
+ memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16);
- /* Turn on rate adaptation */
- rc = mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE,
- MWL8K_UCAST_RATE, NULL);
+ rcu_read_unlock();
+ }
+
+ if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) {
+ rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates);
if (rc)
goto out;
- /* Set radio preamble */
- rc = mwl8k_set_radio_preamble(hw, info->use_short_preamble);
+ rc = mwl8k_cmd_use_fixed_rate_sta(hw);
if (rc)
goto out;
+ }
- /* Set slot time */
- rc = mwl8k_cmd_set_slot(hw, info->use_short_slot);
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ rc = mwl8k_set_radio_preamble(hw,
+ vif->bss_conf.use_short_preamble);
if (rc)
goto out;
+ }
- /* Update peer rate info */
- rc = mwl8k_cmd_update_sta_db(hw, vif,
- MWL8K_STA_DB_MODIFY_ENTRY);
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot);
if (rc)
goto out;
+ }
- /* Set AID */
- rc = mwl8k_cmd_set_aid(hw, vif);
+ if (vif->bss_conf.assoc &&
+ (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT |
+ BSS_CHANGED_HT))) {
+ rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates);
if (rc)
goto out;
+ }
+ if (vif->bss_conf.assoc &&
+ (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INT))) {
/*
* Finalize the join. Tell rx handler to process
* next beacon from our BSSID.
*/
- memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN);
+ memcpy(priv->capture_bssid, vif->bss_conf.bssid, ETH_ALEN);
priv->capture_beacon = true;
- } else {
- rc = mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY);
- memset(&mwl8k_vif->bss_info, 0,
- sizeof(struct ieee80211_bss_conf));
- memset(mwl8k_vif->bssid, 0, ETH_ALEN);
}
out:
mwl8k_fw_unlock(hw);
}
+static void
+mwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info, u32 changed)
+{
+ int rc;
+
+ if (mwl8k_fw_lock(hw))
+ return;
+
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ rc = mwl8k_set_radio_preamble(hw,
+ vif->bss_conf.use_short_preamble);
+ if (rc)
+ goto out;
+ }
+
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ int idx;
+ int rate;
+
+ /*
+ * Use lowest supported basic rate for multicasts
+ * and management frames (such as probe responses --
+ * beacons will always go out at 1 Mb/s).
+ */
+ idx = ffs(vif->bss_conf.basic_rates);
+ if (idx)
+ idx--;
+
+ if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+ rate = mwl8k_rates_24[idx].hw_value;
+ else
+ rate = mwl8k_rates_50[idx].hw_value;
+
+ mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate);
+ }
+
+ if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) {
+ struct sk_buff *skb;
+
+ skb = ieee80211_beacon_get(hw, vif);
+ if (skb != NULL) {
+ mwl8k_cmd_set_beacon(hw, vif, skb->data, skb->len);
+ kfree_skb(skb);
+ }
+ }
+
+ if (changed & BSS_CHANGED_BEACON_ENABLED)
+ mwl8k_cmd_bss_start(hw, vif, info->enable_beacon);
+
+out:
+ mwl8k_fw_unlock(hw);
+}
+
+static void
+mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info, u32 changed)
+{
+ struct mwl8k_priv *priv = hw->priv;
+
+ if (!priv->ap_fw)
+ mwl8k_bss_info_changed_sta(hw, vif, info, changed);
+ else
+ mwl8k_bss_info_changed_ap(hw, vif, info, changed);
+}
+
static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
int mc_count, struct dev_addr_list *mclist)
{
@@ -3105,7 +3580,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw,
* operation, so refuse to enable sniffer mode if a STA
* interface is active.
*/
- if (priv->vif != NULL) {
+ if (!list_empty(&priv->vif_list)) {
if (net_ratelimit())
printk(KERN_INFO "%s: not enabling sniffer "
"mode because STA interface is active\n",
@@ -3114,7 +3589,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw,
}
if (!priv->sniffer_enabled) {
- if (mwl8k_enable_sniffer(hw, 1))
+ if (mwl8k_cmd_enable_sniffer(hw, 1))
return 0;
priv->sniffer_enabled = true;
}
@@ -3126,6 +3601,14 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw,
return 1;
}
+static struct mwl8k_vif *mwl8k_first_vif(struct mwl8k_priv *priv)
+{
+ if (!list_empty(&priv->vif_list))
+ return list_entry(priv->vif_list.next, struct mwl8k_vif, list);
+
+ return NULL;
+}
+
static void mwl8k_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
@@ -3163,7 +3646,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
}
if (priv->sniffer_enabled) {
- mwl8k_enable_sniffer(hw, 0);
+ mwl8k_cmd_enable_sniffer(hw, 0);
priv->sniffer_enabled = false;
}
@@ -3174,7 +3657,8 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
*/
mwl8k_cmd_set_pre_scan(hw);
} else {
- u8 *bssid;
+ struct mwl8k_vif *mwl8k_vif;
+ const u8 *bssid;
/*
* Enable the BSS filter.
@@ -3184,9 +3668,11 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
* (where the OUI part needs to be nonzero for
* the BSSID to be accepted by POST_SCAN).
*/
- bssid = "\x01\x00\x00\x00\x00\x00";
- if (priv->vif != NULL)
- bssid = MWL8K_VIF(priv->vif)->bssid;
+ mwl8k_vif = mwl8k_first_vif(priv);
+ if (mwl8k_vif != NULL)
+ bssid = mwl8k_vif->vif->bss_conf.bssid;
+ else
+ bssid = "\x01\x00\x00\x00\x00\x00";
mwl8k_cmd_set_post_scan(hw, bssid);
}
@@ -3213,7 +3699,39 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
- return mwl8k_rts_threshold(hw, MWL8K_CMD_SET, value);
+ return mwl8k_cmd_set_rts_threshold(hw, value);
+}
+
+static int mwl8k_sta_remove(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mwl8k_priv *priv = hw->priv;
+
+ if (priv->ap_fw)
+ return mwl8k_cmd_set_new_stn_del(hw, vif, sta->addr);
+ else
+ return mwl8k_cmd_update_stadb_del(hw, vif, sta->addr);
+}
+
+static int mwl8k_sta_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mwl8k_priv *priv = hw->priv;
+ int ret;
+
+ if (!priv->ap_fw) {
+ ret = mwl8k_cmd_update_stadb_add(hw, vif, sta);
+ if (ret >= 0) {
+ MWL8K_STA(sta)->peer_id = ret;
+ return 0;
+ }
+
+ return ret;
+ }
+
+ return mwl8k_cmd_set_new_stn_add(hw, vif, sta);
}
static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
@@ -3225,14 +3743,14 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
rc = mwl8k_fw_lock(hw);
if (!rc) {
if (!priv->wmm_enabled)
- rc = mwl8k_set_wmm(hw, 1);
+ rc = mwl8k_cmd_set_wmm_mode(hw, 1);
if (!rc)
- rc = mwl8k_set_edca_params(hw, queue,
- params->cw_min,
- params->cw_max,
- params->aifs,
- params->txop);
+ rc = mwl8k_cmd_set_edca_params(hw, queue,
+ params->cw_min,
+ params->cw_max,
+ params->aifs,
+ params->txop);
mwl8k_fw_unlock(hw);
}
@@ -3240,28 +3758,26 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
return rc;
}
-static int mwl8k_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *stats)
+static int mwl8k_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
{
- struct mwl8k_priv *priv = hw->priv;
- struct mwl8k_tx_queue *txq;
- int index;
-
- spin_lock_bh(&priv->tx_lock);
- for (index = 0; index < MWL8K_TX_QUEUES; index++) {
- txq = priv->txq + index;
- memcpy(&stats[index], &txq->stats,
- sizeof(struct ieee80211_tx_queue_stats));
- }
- spin_unlock_bh(&priv->tx_lock);
-
- return 0;
+ return mwl8k_cmd_get_stat(hw, stats);
}
-static int mwl8k_get_stats(struct ieee80211_hw *hw,
- struct ieee80211_low_level_stats *stats)
+static int
+mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
- return mwl8k_cmd_802_11_get_stat(hw, stats);
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ case IEEE80211_AMPDU_RX_STOP:
+ if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
+ return -ENOTSUPP;
+ return 0;
+ default:
+ return -ENOTSUPP;
+ }
}
static const struct ieee80211_ops mwl8k_ops = {
@@ -3275,67 +3791,72 @@ static const struct ieee80211_ops mwl8k_ops = {
.prepare_multicast = mwl8k_prepare_multicast,
.configure_filter = mwl8k_configure_filter,
.set_rts_threshold = mwl8k_set_rts_threshold,
+ .sta_add = mwl8k_sta_add,
+ .sta_remove = mwl8k_sta_remove,
.conf_tx = mwl8k_conf_tx,
- .get_tx_stats = mwl8k_get_tx_stats,
.get_stats = mwl8k_get_stats,
+ .ampdu_action = mwl8k_ampdu_action,
};
-static void mwl8k_tx_reclaim_handler(unsigned long data)
-{
- int i;
- struct ieee80211_hw *hw = (struct ieee80211_hw *) data;
- struct mwl8k_priv *priv = hw->priv;
-
- spin_lock_bh(&priv->tx_lock);
- for (i = 0; i < MWL8K_TX_QUEUES; i++)
- mwl8k_txq_reclaim(hw, i, 0);
-
- if (priv->tx_wait != NULL && !priv->pending_tx_pkts) {
- complete(priv->tx_wait);
- priv->tx_wait = NULL;
- }
- spin_unlock_bh(&priv->tx_lock);
-}
-
static void mwl8k_finalize_join_worker(struct work_struct *work)
{
struct mwl8k_priv *priv =
container_of(work, struct mwl8k_priv, finalize_join_worker);
struct sk_buff *skb = priv->beacon_skb;
- u8 dtim = MWL8K_VIF(priv->vif)->bss_info.dtim_period;
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ int len = skb->len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
+ const u8 *tim = cfg80211_find_ie(WLAN_EID_TIM,
+ mgmt->u.beacon.variable, len);
+ int dtim_period = 1;
- mwl8k_finalize_join(priv->hw, skb->data, skb->len, dtim);
- dev_kfree_skb(skb);
+ if (tim && tim[1] >= 2)
+ dtim_period = tim[3];
+
+ mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, dtim_period);
+ dev_kfree_skb(skb);
priv->beacon_skb = NULL;
}
enum {
- MWL8687 = 0,
+ MWL8363 = 0,
+ MWL8687,
MWL8366,
};
static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = {
- {
+ [MWL8363] = {
+ .part_name = "88w8363",
+ .helper_image = "mwl8k/helper_8363.fw",
+ .fw_image = "mwl8k/fmimage_8363.fw",
+ },
+ [MWL8687] = {
.part_name = "88w8687",
.helper_image = "mwl8k/helper_8687.fw",
.fw_image = "mwl8k/fmimage_8687.fw",
- .rxd_ops = &rxd_8687_ops,
- .modes = BIT(NL80211_IFTYPE_STATION),
},
- {
+ [MWL8366] = {
.part_name = "88w8366",
.helper_image = "mwl8k/helper_8366.fw",
.fw_image = "mwl8k/fmimage_8366.fw",
- .rxd_ops = &rxd_8366_ops,
- .modes = 0,
+ .ap_rxd_ops = &rxd_8366_ap_ops,
},
};
+MODULE_FIRMWARE("mwl8k/helper_8363.fw");
+MODULE_FIRMWARE("mwl8k/fmimage_8363.fw");
+MODULE_FIRMWARE("mwl8k/helper_8687.fw");
+MODULE_FIRMWARE("mwl8k/fmimage_8687.fw");
+MODULE_FIRMWARE("mwl8k/helper_8366.fw");
+MODULE_FIRMWARE("mwl8k/fmimage_8366.fw");
+
static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
+ { PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, },
+ { PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, },
{ PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, },
{ PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, },
{ PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, },
+ { PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, },
{ },
};
MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table);
@@ -3354,6 +3875,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
printed_version = 1;
}
+
rc = pci_enable_device(pdev);
if (rc) {
printk(KERN_ERR "%s: Cannot enable new PCI device\n",
@@ -3370,6 +3892,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
pci_set_master(pdev);
+
hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops);
if (hw == NULL) {
printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME);
@@ -3377,17 +3900,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
goto err_free_reg;
}
+ SET_IEEE80211_DEV(hw, &pdev->dev);
+ pci_set_drvdata(pdev, hw);
+
priv = hw->priv;
priv->hw = hw;
priv->pdev = pdev;
priv->device_info = &mwl8k_info_tbl[id->driver_data];
- priv->rxd_ops = priv->device_info->rxd_ops;
- priv->sniffer_enabled = false;
- priv->wmm_enabled = false;
- priv->pending_tx_pkts = 0;
- SET_IEEE80211_DEV(hw, &pdev->dev);
- pci_set_drvdata(pdev, hw);
priv->sram = pci_iomap(pdev, 0, 0x10000);
if (priv->sram == NULL) {
@@ -3410,16 +3930,46 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
}
}
- memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels));
- priv->band.band = IEEE80211_BAND_2GHZ;
- priv->band.channels = priv->channels;
- priv->band.n_channels = ARRAY_SIZE(mwl8k_channels);
- priv->band.bitrates = priv->rates;
- priv->band.n_bitrates = ARRAY_SIZE(mwl8k_rates);
- hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
- BUILD_BUG_ON(sizeof(priv->rates) != sizeof(mwl8k_rates));
- memcpy(priv->rates, mwl8k_rates, sizeof(mwl8k_rates));
+ /* Reset firmware and hardware */
+ mwl8k_hw_reset(priv);
+
+ /* Ask userland hotplug daemon for the device firmware */
+ rc = mwl8k_request_firmware(priv);
+ if (rc) {
+ printk(KERN_ERR "%s: Firmware files not found\n",
+ wiphy_name(hw->wiphy));
+ goto err_stop_firmware;
+ }
+
+ /* Load firmware into hardware */
+ rc = mwl8k_load_firmware(hw);
+ if (rc) {
+ printk(KERN_ERR "%s: Cannot start firmware\n",
+ wiphy_name(hw->wiphy));
+ goto err_stop_firmware;
+ }
+
+ /* Reclaim memory once firmware is successfully loaded */
+ mwl8k_release_firmware(priv);
+
+
+ if (priv->ap_fw) {
+ priv->rxd_ops = priv->device_info->ap_rxd_ops;
+ if (priv->rxd_ops == NULL) {
+ printk(KERN_ERR "%s: Driver does not have AP "
+ "firmware image support for this hardware\n",
+ wiphy_name(hw->wiphy));
+ goto err_stop_firmware;
+ }
+ } else {
+ priv->rxd_ops = &rxd_sta_ops;
+ }
+
+ priv->sniffer_enabled = false;
+ priv->wmm_enabled = false;
+ priv->pending_tx_pkts = 0;
+
/*
* Extra headroom is the size of the required DMA header
@@ -3432,12 +3982,13 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
hw->queues = MWL8K_TX_QUEUES;
- hw->wiphy->interface_modes = priv->device_info->modes;
-
/* Set rssi and noise values to dBm */
hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM;
hw->vif_data_size = sizeof(struct mwl8k_vif);
- priv->vif = NULL;
+ hw->sta_data_size = sizeof(struct mwl8k_sta);
+
+ priv->macids_used = 0;
+ INIT_LIST_HEAD(&priv->vif_list);
/* Set default radio state and preamble */
priv->radio_on = 0;
@@ -3446,19 +3997,20 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
/* Finalize join worker */
INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
- /* TX reclaim tasklet */
- tasklet_init(&priv->tx_reclaim_task,
- mwl8k_tx_reclaim_handler, (unsigned long)hw);
- tasklet_disable(&priv->tx_reclaim_task);
+ /* TX reclaim and RX tasklets. */
+ tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw);
+ tasklet_disable(&priv->poll_tx_task);
+ tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw);
+ tasklet_disable(&priv->poll_rx_task);
/* Power management cookie */
priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
if (priv->cookie == NULL)
- goto err_iounmap;
+ goto err_stop_firmware;
rc = mwl8k_rxq_init(hw, 0);
if (rc)
- goto err_iounmap;
+ goto err_free_cookie;
rxq_refill(hw, 0, INT_MAX);
mutex_init(&priv->fw_mutex);
@@ -3478,7 +4030,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
- iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
+ iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY,
+ priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
rc = request_irq(priv->pdev->irq, mwl8k_interrupt,
@@ -3489,31 +4042,9 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
goto err_free_queues;
}
- /* Reset firmware and hardware */
- mwl8k_hw_reset(priv);
-
- /* Ask userland hotplug daemon for the device firmware */
- rc = mwl8k_request_firmware(priv);
- if (rc) {
- printk(KERN_ERR "%s: Firmware files not found\n",
- wiphy_name(hw->wiphy));
- goto err_free_irq;
- }
-
- /* Load firmware into hardware */
- rc = mwl8k_load_firmware(hw);
- if (rc) {
- printk(KERN_ERR "%s: Cannot start firmware\n",
- wiphy_name(hw->wiphy));
- goto err_stop_firmware;
- }
-
- /* Reclaim memory once firmware is successfully loaded */
- mwl8k_release_firmware(priv);
-
/*
* Temporarily enable interrupts. Initial firmware host
- * commands use interrupts and avoids polling. Disable
+ * commands use interrupts and avoid polling. Disable
* interrupts when done.
*/
iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
@@ -3529,22 +4060,29 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
if (rc) {
printk(KERN_ERR "%s: Cannot initialise firmware\n",
wiphy_name(hw->wiphy));
- goto err_stop_firmware;
+ goto err_free_irq;
}
+ hw->wiphy->interface_modes = 0;
+ if (priv->ap_macids_supported)
+ hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
+ if (priv->sta_macids_supported)
+ hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION);
+
+
/* Turn radio off */
- rc = mwl8k_cmd_802_11_radio_disable(hw);
+ rc = mwl8k_cmd_radio_disable(hw);
if (rc) {
printk(KERN_ERR "%s: Cannot disable\n", wiphy_name(hw->wiphy));
- goto err_stop_firmware;
+ goto err_free_irq;
}
/* Clear MAC address */
- rc = mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00");
+ rc = mwl8k_cmd_set_mac_addr(hw, NULL, "\x00\x00\x00\x00\x00\x00");
if (rc) {
printk(KERN_ERR "%s: Cannot clear MAC address\n",
wiphy_name(hw->wiphy));
- goto err_stop_firmware;
+ goto err_free_irq;
}
/* Disable interrupts */
@@ -3555,7 +4093,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
if (rc) {
printk(KERN_ERR "%s: Cannot register device\n",
wiphy_name(hw->wiphy));
- goto err_stop_firmware;
+ goto err_free_queues;
}
printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n",
@@ -3567,10 +4105,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
return 0;
-err_stop_firmware:
- mwl8k_hw_reset(priv);
- mwl8k_release_firmware(priv);
-
err_free_irq:
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
free_irq(priv->pdev->irq, hw);
@@ -3580,11 +4114,16 @@ err_free_queues:
mwl8k_txq_deinit(hw, i);
mwl8k_rxq_deinit(hw, 0);
-err_iounmap:
+err_free_cookie:
if (priv->cookie != NULL)
pci_free_consistent(priv->pdev, 4,
priv->cookie, priv->cookie_dma);
+err_stop_firmware:
+ mwl8k_hw_reset(priv);
+ mwl8k_release_firmware(priv);
+
+err_iounmap:
if (priv->regs != NULL)
pci_iounmap(pdev, priv->regs);
@@ -3622,15 +4161,16 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
ieee80211_unregister_hw(hw);
- /* Remove tx reclaim tasklet */
- tasklet_kill(&priv->tx_reclaim_task);
+ /* Remove TX reclaim and RX tasklets. */
+ tasklet_kill(&priv->poll_tx_task);
+ tasklet_kill(&priv->poll_rx_task);
/* Stop hardware */
mwl8k_hw_reset(priv);
/* Return all skbs to mac80211 */
for (i = 0; i < MWL8K_TX_QUEUES; i++)
- mwl8k_txq_reclaim(hw, i, 1);
+ mwl8k_txq_reclaim(hw, i, INT_MAX, 1);
for (i = 0; i < MWL8K_TX_QUEUES; i++)
mwl8k_txq_deinit(hw, i);
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index 404830f47ab2..e6369242e49c 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -1028,7 +1028,7 @@ int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx)
}
int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
- struct dev_addr_list *mc_list,
+ struct net_device *dev,
int mc_count, int promisc)
{
hermes_t *hw = &priv->hw;
@@ -1049,24 +1049,16 @@ int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
* group address if either we want to multicast, or if we were
* multicasting and want to stop */
if (!promisc && (mc_count || priv->mc_count)) {
- struct dev_mc_list *p = mc_list;
+ struct dev_mc_list *p;
struct hermes_multicast mclist;
- int i;
+ int i = 0;
- for (i = 0; i < mc_count; i++) {
- /* paranoia: is list shorter than mc_count? */
- BUG_ON(!p);
- /* paranoia: bad address size in list? */
- BUG_ON(p->dmi_addrlen != ETH_ALEN);
-
- memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
- p = p->next;
+ netdev_for_each_mc_addr(p, dev) {
+ if (i == mc_count)
+ break;
+ memcpy(mclist.addr[i++], p->dmi_addr, ETH_ALEN);
}
- if (p)
- printk(KERN_WARNING "%s: Multicast list is "
- "longer than mc_count\n", priv->ndev->name);
-
err = hermes_write_ltv(hw, USER_BAP,
HERMES_RID_CNFGROUPADDRESSES,
HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h
index e2f7fdc4d45a..9799a1d14a63 100644
--- a/drivers/net/wireless/orinoco/hw.h
+++ b/drivers/net/wireless/orinoco/hw.h
@@ -43,7 +43,7 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
u8 *tsc, size_t tsc_len);
int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
- struct dev_addr_list *mc_list,
+ struct net_device *dev,
int mc_count, int promisc);
int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
char buf[IW_ESSID_MAX_SIZE+1]);
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 753a1804eee7..b42634c614b5 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -1668,16 +1668,15 @@ __orinoco_set_multicast_list(struct net_device *dev)
/* The Hermes doesn't seem to have an allmulti mode, so we go
* into promiscuous mode and let the upper levels deal. */
if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
- (dev->mc_count > MAX_MULTICAST(priv))) {
+ (netdev_mc_count(dev) > MAX_MULTICAST(priv))) {
promisc = 1;
mc_count = 0;
} else {
promisc = 0;
- mc_count = dev->mc_count;
+ mc_count = netdev_mc_count(dev);
}
- err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count,
- promisc);
+ err = __orinoco_hw_set_multicast_list(priv, dev, mc_count, promisc);
return err;
}
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index f27bb8367c98..1d4ada188eda 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -407,7 +407,6 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5),
PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2),
- PCMCIA_DEVICE_PROD_ID123("AIRVAST", "IEEE 802.11b Wireless PCMCIA Card", "HFA3863", 0xea569531, 0x4bcb9645, 0x355cb092),
PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f),
PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842),
PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e),
@@ -417,7 +416,6 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18),
PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b),
- PCMCIA_DEVICE_PROD_ID123("corega", "WL PCCL-11", "ISL37300P", 0x0a21501a, 0x59868926, 0xc9049a39),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae),
@@ -432,7 +430,6 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18),
PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77),
PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf),
- PCMCIA_DEVICE_PROD_ID123("Intersil", "PRISM Freedom PCMCIA Adapter", "ISL37100P", 0x4b801a17, 0xf222ec2d, 0x630d52b2),
PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92),
PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395),
PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a),
@@ -445,7 +442,6 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767),
PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6),
PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed),
- PCMCIA_DEVICE_PROD_ID123("PCMCIA", "11M WLAN Card v2.5", "ISL37300P", 0x281f1c5d, 0x6e440487, 0xc9049a39),
PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264),
PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178),
PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9),
@@ -454,8 +450,11 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757),
PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a),
PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e),
- PCMCIA_DEVICE_PROD_ID123("The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", 0xa5f472c2, 0x590eb502, 0xc9049a39),
PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee),
+ PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092),
+ PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
+ PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
+ PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids);
diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c
index c13a4c383410..075f446b3139 100644
--- a/drivers/net/wireless/orinoco/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco/orinoco_nortel.c
@@ -274,7 +274,7 @@ static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-static struct pci_device_id orinoco_nortel_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(orinoco_nortel_id_table) = {
/* Nortel emobility PCI */
{0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
/* Symbol LA-4123 PCI */
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c
index fea7781948e7..bda5317cc596 100644
--- a/drivers/net/wireless/orinoco/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco/orinoco_pci.c
@@ -212,7 +212,7 @@ static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-static struct pci_device_id orinoco_pci_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(orinoco_pci_id_table) = {
/* Intersil Prism 3 */
{0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
/* Intersil Prism 2.5 */
diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c
index 3f2942a1e4f5..e0d5874ab42f 100644
--- a/drivers/net/wireless/orinoco/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco/orinoco_plx.c
@@ -310,7 +310,7 @@ static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-static struct pci_device_id orinoco_plx_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(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? */
diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c
index d3452548cc71..88cbc7902aa0 100644
--- a/drivers/net/wireless/orinoco/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco/orinoco_tmd.c
@@ -203,7 +203,7 @@ static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-static struct pci_device_id orinoco_tmd_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(orinoco_tmd_id_table) = {
{0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */
{0,},
};
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index 18012dbfb45d..4f752a21495f 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -33,21 +33,29 @@ MODULE_DESCRIPTION("Softmac Prism54 common code");
MODULE_LICENSE("GPL");
MODULE_ALIAS("prism54common");
+static int p54_sta_add_remove(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct p54_common *priv = hw->priv;
+
+ /*
+ * Notify the firmware that we don't want or we don't
+ * need to buffer frames for this station anymore.
+ */
+
+ p54_sta_unlock(priv, sta->addr);
+
+ return 0;
+}
+
static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
enum sta_notify_cmd notify_cmd,
struct ieee80211_sta *sta)
{
struct p54_common *priv = dev->priv;
- switch (notify_cmd) {
- case STA_NOTIFY_ADD:
- case STA_NOTIFY_REMOVE:
- /*
- * Notify the firmware that we don't want or we don't
- * need to buffer frames for this station anymore.
- */
- p54_sta_unlock(priv, sta->addr);
- break;
+ switch (notify_cmd) {
case STA_NOTIFY_AWAKE:
/* update the firmware's filter table */
p54_sta_unlock(priv, sta->addr);
@@ -216,7 +224,7 @@ static void p54_stop(struct ieee80211_hw *dev)
}
static int p54_add_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct p54_common *priv = dev->priv;
@@ -226,28 +234,28 @@ static int p54_add_interface(struct ieee80211_hw *dev,
return -EOPNOTSUPP;
}
- priv->vif = conf->vif;
+ priv->vif = vif;
- switch (conf->type) {
+ switch (vif->type) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
- priv->mode = conf->type;
+ priv->mode = vif->type;
break;
default:
mutex_unlock(&priv->conf_mutex);
return -EOPNOTSUPP;
}
- memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+ memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
p54_setup_mac(priv);
mutex_unlock(&priv->conf_mutex);
return 0;
}
static void p54_remove_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct p54_common *priv = dev->priv;
@@ -358,16 +366,6 @@ static int p54_get_stats(struct ieee80211_hw *dev,
return 0;
}
-static int p54_get_tx_stats(struct ieee80211_hw *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct p54_common *priv = dev->priv;
-
- memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA],
- sizeof(stats[0]) * dev->queues);
- return 0;
-}
-
static void p54_bss_info_changed(struct ieee80211_hw *dev,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
@@ -516,13 +514,14 @@ static const struct ieee80211_ops p54_ops = {
.remove_interface = p54_remove_interface,
.set_tim = p54_set_tim,
.sta_notify = p54_sta_notify,
+ .sta_add = p54_sta_add_remove,
+ .sta_remove = p54_sta_add_remove,
.set_key = p54_set_key,
.config = p54_config,
.bss_info_changed = p54_bss_info_changed,
.configure_filter = p54_configure_filter,
.conf_tx = p54_conf_tx,
.get_stats = p54_get_stats,
- .get_tx_stats = p54_get_tx_stats
};
struct ieee80211_hw *p54_init_common(size_t priv_data_len)
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index 1afc39410e85..43a3b2ead81a 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -157,6 +157,12 @@ struct p54_led_dev {
#endif /* CONFIG_P54_LEDS */
+struct p54_tx_queue_stats {
+ unsigned int len;
+ unsigned int limit;
+ unsigned int count;
+};
+
struct p54_common {
struct ieee80211_hw *hw;
struct ieee80211_vif *vif;
@@ -183,7 +189,7 @@ struct p54_common {
/* (e)DCF / QOS state */
bool use_short_slot;
spinlock_t tx_stats_lock;
- struct ieee80211_tx_queue_stats tx_stats[8];
+ struct p54_tx_queue_stats tx_stats[8];
struct p54_edcf_queue_param qos_params[8];
/* Radio data */
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index a15962a19b2a..ed4bdffdd63e 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -31,7 +31,7 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("prism54pci");
MODULE_FIRMWARE("isl3886pci");
-static struct pci_device_id p54p_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(p54p_table) = {
/* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
{ PCI_DEVICE(0x1260, 0x3890) },
/* 3COM 3CRWE154G72 Wireless LAN adapter */
@@ -157,6 +157,14 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
skb_tail_pointer(skb),
priv->common.rx_mtu + 32,
PCI_DMA_FROMDEVICE);
+
+ if (pci_dma_mapping_error(priv->pdev, mapping)) {
+ dev_kfree_skb_any(skb);
+ dev_err(&priv->pdev->dev,
+ "RX DMA Mapping error\n");
+ break;
+ }
+
desc->host_addr = cpu_to_le32(mapping);
desc->device_addr = 0; // FIXME: necessary?
desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
@@ -197,6 +205,14 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
i %= ring_limit;
continue;
}
+
+ if (unlikely(len > priv->common.rx_mtu)) {
+ if (net_ratelimit())
+ dev_err(&priv->pdev->dev, "rx'd frame size "
+ "exceeds length threshold.\n");
+
+ len = priv->common.rx_mtu;
+ }
skb_put(skb, len);
if (p54_rx(dev, skb)) {
@@ -218,14 +234,14 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf);
}
-/* caller must hold priv->lock */
static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
int ring_index, struct p54p_desc *ring, u32 ring_limit,
- void **tx_buf)
+ struct sk_buff **tx_buf)
{
struct p54p_priv *priv = dev->priv;
struct p54p_ring_control *ring_control = priv->ring_control;
struct p54p_desc *desc;
+ struct sk_buff *skb;
u32 idx, i;
i = (*index) % ring_limit;
@@ -234,9 +250,8 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
while (i != idx) {
desc = &ring[i];
- if (tx_buf[i])
- if (FREE_AFTER_TX((struct sk_buff *) tx_buf[i]))
- p54_free_skb(dev, tx_buf[i]);
+
+ skb = tx_buf[i];
tx_buf[i] = NULL;
pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
@@ -247,17 +262,28 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
desc->len = 0;
desc->flags = 0;
+ if (skb && FREE_AFTER_TX(skb))
+ p54_free_skb(dev, skb);
+
i++;
i %= ring_limit;
}
}
-static void p54p_rx_tasklet(unsigned long dev_id)
+static void p54p_tasklet(unsigned long dev_id)
{
struct ieee80211_hw *dev = (struct ieee80211_hw *)dev_id;
struct p54p_priv *priv = dev->priv;
struct p54p_ring_control *ring_control = priv->ring_control;
+ p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, 3, ring_control->tx_mgmt,
+ ARRAY_SIZE(ring_control->tx_mgmt),
+ priv->tx_buf_mgmt);
+
+ p54p_check_tx_ring(dev, &priv->tx_idx_data, 1, ring_control->tx_data,
+ ARRAY_SIZE(ring_control->tx_data),
+ priv->tx_buf_data);
+
p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt,
ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt);
@@ -272,59 +298,49 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id)
{
struct ieee80211_hw *dev = dev_id;
struct p54p_priv *priv = dev->priv;
- struct p54p_ring_control *ring_control = priv->ring_control;
__le32 reg;
- spin_lock(&priv->lock);
reg = P54P_READ(int_ident);
if (unlikely(reg == cpu_to_le32(0xFFFFFFFF))) {
- spin_unlock(&priv->lock);
- return IRQ_HANDLED;
+ goto out;
}
-
P54P_WRITE(int_ack, reg);
reg &= P54P_READ(int_enable);
- if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) {
- p54p_check_tx_ring(dev, &priv->tx_idx_mgmt,
- 3, ring_control->tx_mgmt,
- ARRAY_SIZE(ring_control->tx_mgmt),
- priv->tx_buf_mgmt);
-
- p54p_check_tx_ring(dev, &priv->tx_idx_data,
- 1, ring_control->tx_data,
- ARRAY_SIZE(ring_control->tx_data),
- priv->tx_buf_data);
-
- tasklet_schedule(&priv->rx_tasklet);
-
- } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))
+ if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE))
+ tasklet_schedule(&priv->tasklet);
+ else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))
complete(&priv->boot_comp);
- spin_unlock(&priv->lock);
-
+out:
return reg ? IRQ_HANDLED : IRQ_NONE;
}
static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
+ unsigned long flags;
struct p54p_priv *priv = dev->priv;
struct p54p_ring_control *ring_control = priv->ring_control;
- unsigned long flags;
struct p54p_desc *desc;
dma_addr_t mapping;
u32 device_idx, idx, i;
spin_lock_irqsave(&priv->lock, flags);
-
device_idx = le32_to_cpu(ring_control->device_idx[1]);
idx = le32_to_cpu(ring_control->host_idx[1]);
i = idx % ARRAY_SIZE(ring_control->tx_data);
- priv->tx_buf_data[i] = skb;
mapping = pci_map_single(priv->pdev, skb->data, skb->len,
PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(priv->pdev, mapping)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ p54_free_skb(dev, skb);
+ dev_err(&priv->pdev->dev, "TX DMA mapping error\n");
+ return ;
+ }
+ priv->tx_buf_data[i] = skb;
+
desc = &ring_control->tx_data[i];
desc->host_addr = cpu_to_le32(mapping);
desc->device_addr = ((struct p54_hdr *)skb->data)->req_id;
@@ -346,14 +362,14 @@ static void p54p_stop(struct ieee80211_hw *dev)
unsigned int i;
struct p54p_desc *desc;
- tasklet_kill(&priv->rx_tasklet);
-
P54P_WRITE(int_enable, cpu_to_le32(0));
P54P_READ(int_enable);
udelay(10);
free_irq(priv->pdev->irq, dev);
+ tasklet_kill(&priv->tasklet);
+
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) {
@@ -537,7 +553,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
priv->common.tx = p54p_tx;
spin_lock_init(&priv->lock);
- tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev);
+ tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev);
err = request_firmware(&priv->firmware, "isl3886pci",
&priv->pdev->dev);
diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h
index fbb683953fb2..2feead617a3b 100644
--- a/drivers/net/wireless/p54/p54pci.h
+++ b/drivers/net/wireless/p54/p54pci.h
@@ -92,7 +92,7 @@ struct p54p_priv {
struct p54_common common;
struct pci_dev *pdev;
struct p54p_csr __iomem *map;
- struct tasklet_struct rx_tasklet;
+ struct tasklet_struct tasklet;
const struct firmware *firmware;
spinlock_t lock;
struct p54p_ring_control *ring_control;
@@ -101,8 +101,8 @@ struct p54p_priv {
u32 rx_idx_mgmt, tx_idx_mgmt;
struct sk_buff *rx_buf_data[8];
struct sk_buff *rx_buf_mgmt[4];
- void *tx_buf_data[32];
- void *tx_buf_mgmt[4];
+ struct sk_buff *tx_buf_data[32];
+ struct sk_buff *tx_buf_mgmt[4];
struct completion boot_comp;
};
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 92af9b96bb7a..b3c4fbd80d8d 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -36,6 +36,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
/* Version 1 devices (pci chip + net2280) */
{USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
{USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
+ {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */
{USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
{USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
{USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
@@ -60,6 +61,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
{USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
{USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
+ {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
{USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
{USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
{USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index b6dda2b27fb5..66057999a93c 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -183,10 +183,10 @@ static int p54_tx_qos_accounting_alloc(struct p54_common *priv,
struct sk_buff *skb,
const u16 p54_queue)
{
- struct ieee80211_tx_queue_stats *queue;
+ struct p54_tx_queue_stats *queue;
unsigned long flags;
- if (WARN_ON(p54_queue > P54_QUEUE_NUM))
+ if (WARN_ON(p54_queue >= P54_QUEUE_NUM))
return -EINVAL;
queue = &priv->tx_stats[p54_queue];
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index e4f2bb7368f2..dc14420a9adc 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -39,7 +39,7 @@ module_param(init_pcitm, int, 0);
* driver_data
* If you have an update for this please contact prism54-devel@prism54.org
* The latest list can be found at http://prism54.org/supported_cards.php */
-static const struct pci_device_id prism54_id_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(prism54_id_tbl) = {
/* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
{
0x1260, 0x3890,
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 88e1e4e32b22..84c530aa52f9 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -1871,10 +1871,8 @@ static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value,
/*===========================================================================*/
static void ray_update_multi_list(struct net_device *dev, int all)
{
- struct dev_mc_list *dmi, **dmip;
int ccsindex;
struct ccs __iomem *pccs;
- int i = 0;
ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
void __iomem *p = local->sram + HOST_TO_ECF_BASE;
@@ -1895,9 +1893,11 @@ static void ray_update_multi_list(struct net_device *dev, int all)
writeb(0xff, &pccs->var);
local->num_multi = 0xff;
} else {
+ struct dev_mc_list *dmi;
+ int i = 0;
+
/* Copy the kernel's list of MC addresses to card */
- for (dmip = &dev->mc_list; (dmi = *dmip) != NULL;
- dmip = &dmi->next) {
+ netdev_for_each_mc_addr(dmi, dev) {
memcpy_toio(p, dmi->dmi_addr, ETH_ALEN);
dev_dbg(&link->dev,
"ray_update_multi add addr %02x%02x%02x%02x%02x%02x\n",
@@ -1950,7 +1950,7 @@ static void set_multicast_list(struct net_device *dev)
if (dev->flags & IFF_ALLMULTI)
ray_update_multi_list(dev, 1);
else {
- if (local->num_multi != dev->mc_count)
+ if (local->num_multi != netdev_mc_count(dev))
ray_update_multi_list(dev, 0);
}
} /* end set_multicast_list */
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 2ecbedb26e15..2887047069f2 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -728,9 +728,9 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
ret = rndis_command(dev, u.header, buflen);
priv->current_command_oid = 0;
if (ret < 0)
- devdbg(dev, "rndis_query_oid(%s): rndis_command() failed, %d "
- "(%08x)", oid_to_string(oid), ret,
- le32_to_cpu(u.get_c->status));
+ netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n",
+ __func__, oid_to_string(oid), ret,
+ le32_to_cpu(u.get_c->status));
if (ret == 0) {
memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len);
@@ -741,9 +741,9 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
ret = rndis_error_status(u.get_c->status);
if (ret < 0)
- devdbg(dev, "rndis_query_oid(%s): device returned "
- "error, 0x%08x (%d)", oid_to_string(oid),
- le32_to_cpu(u.get_c->status), ret);
+ netdev_dbg(dev->net, "%s(%s): device returned error, 0x%08x (%d)\n",
+ __func__, oid_to_string(oid),
+ le32_to_cpu(u.get_c->status), ret);
}
mutex_unlock(&priv->command_lock);
@@ -791,17 +791,17 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
ret = rndis_command(dev, u.header, buflen);
priv->current_command_oid = 0;
if (ret < 0)
- devdbg(dev, "rndis_set_oid(%s): rndis_command() failed, %d "
- "(%08x)", oid_to_string(oid), ret,
- le32_to_cpu(u.set_c->status));
+ netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n",
+ __func__, oid_to_string(oid), ret,
+ le32_to_cpu(u.set_c->status));
if (ret == 0) {
ret = rndis_error_status(u.set_c->status);
if (ret < 0)
- devdbg(dev, "rndis_set_oid(%s): device returned error, "
- "0x%08x (%d)", oid_to_string(oid),
- le32_to_cpu(u.set_c->status), ret);
+ netdev_dbg(dev->net, "%s(%s): device returned error, 0x%08x (%d)\n",
+ __func__, oid_to_string(oid),
+ le32_to_cpu(u.set_c->status), ret);
}
mutex_unlock(&priv->command_lock);
@@ -870,11 +870,11 @@ static int rndis_set_config_parameter(struct usbnet *dev, char *param,
#endif
if (value_type == 2)
- devdbg(dev, "setting config parameter: %s, value: %s",
- param, (u8 *)value);
+ netdev_dbg(dev->net, "setting config parameter: %s, value: %s\n",
+ param, (u8 *)value);
else
- devdbg(dev, "setting config parameter: %s, value: %d",
- param, *(u32 *)value);
+ netdev_dbg(dev->net, "setting config parameter: %s, value: %d\n",
+ param, *(u32 *)value);
infobuf->name_offs = cpu_to_le32(sizeof(*infobuf));
infobuf->name_length = cpu_to_le32(param_len);
@@ -897,20 +897,21 @@ static int rndis_set_config_parameter(struct usbnet *dev, char *param,
}
#ifdef DEBUG
- devdbg(dev, "info buffer (len: %d):", info_len);
+ netdev_dbg(dev->net, "info buffer (len: %d)\n", info_len);
for (i = 0; i < info_len; i += 12) {
u32 *tmp = (u32 *)((u8 *)infobuf + i);
- devdbg(dev, "%08X:%08X:%08X",
- cpu_to_be32(tmp[0]),
- cpu_to_be32(tmp[1]),
- cpu_to_be32(tmp[2]));
+ netdev_dbg(dev->net, "%08X:%08X:%08X\n",
+ cpu_to_be32(tmp[0]),
+ cpu_to_be32(tmp[1]),
+ cpu_to_be32(tmp[2]));
}
#endif
ret = rndis_set_oid(dev, OID_GEN_RNDIS_CONFIG_PARAMETER,
infobuf, info_len);
if (ret != 0)
- devdbg(dev, "setting rndis config parameter failed, %d.", ret);
+ netdev_dbg(dev->net, "setting rndis config parameter failed, %d\n",
+ ret);
kfree(infobuf);
return ret;
@@ -945,13 +946,13 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid));
if (ret < 0) {
- devwarn(usbdev, "setting SSID failed (%08X)", ret);
+ netdev_warn(usbdev->net, "setting SSID failed (%08X)\n", ret);
return ret;
}
if (ret == 0) {
memcpy(&priv->essid, ssid, sizeof(priv->essid));
priv->radio_on = true;
- devdbg(usbdev, "set_essid: radio_on = true");
+ netdev_dbg(usbdev->net, "%s(): radio_on = true\n", __func__);
}
return ret;
@@ -963,7 +964,8 @@ static int set_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN])
ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN);
if (ret < 0) {
- devwarn(usbdev, "setting BSSID[%pM] failed (%08X)", bssid, ret);
+ netdev_warn(usbdev->net, "setting BSSID[%pM] failed (%08X)\n",
+ bssid, ret);
return ret;
}
@@ -1021,7 +1023,8 @@ static int disassociate(struct usbnet *usbdev, bool reset_ssid)
ret = rndis_set_oid(usbdev, OID_802_11_DISASSOCIATE, NULL, 0);
if (ret == 0) {
priv->radio_on = false;
- devdbg(usbdev, "disassociate: radio_on = false");
+ netdev_dbg(usbdev->net, "%s(): radio_on = false\n",
+ __func__);
if (reset_ssid)
msleep(100);
@@ -1054,8 +1057,8 @@ static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version,
__le32 tmp;
int auth_mode, ret;
- devdbg(usbdev, "set_auth_mode: wpa_version=0x%x authalg=0x%x "
- "keymgmt=0x%x", wpa_version, auth_type, keymgmt);
+ netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x authalg=0x%x keymgmt=0x%x\n",
+ __func__, wpa_version, auth_type, keymgmt);
if (wpa_version & NL80211_WPA_VERSION_2) {
if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X)
@@ -1082,7 +1085,8 @@ static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version,
ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp,
sizeof(tmp));
if (ret != 0) {
- devwarn(usbdev, "setting auth mode failed (%08X)", ret);
+ netdev_warn(usbdev->net, "setting auth mode failed (%08X)\n",
+ ret);
return ret;
}
@@ -1098,7 +1102,8 @@ static int set_priv_filter(struct usbnet *usbdev)
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
__le32 tmp;
- devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version);
+ netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x\n",
+ __func__, priv->wpa_version);
if (priv->wpa_version & NL80211_WPA_VERSION_2 ||
priv->wpa_version & NL80211_WPA_VERSION_1)
@@ -1116,8 +1121,8 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
__le32 tmp;
int encr_mode, ret;
- devdbg(usbdev, "set_encr_mode: cipher_pair=0x%x cipher_group=0x%x",
- pairwise, groupwise);
+ netdev_dbg(usbdev->net, "%s(): cipher_pair=0x%x cipher_group=0x%x\n",
+ __func__, pairwise, groupwise);
if (pairwise & RNDIS_WLAN_ALG_CCMP)
encr_mode = NDIS_80211_ENCR_CCMP_ENABLED;
@@ -1136,7 +1141,8 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
ret = rndis_set_oid(usbdev, OID_802_11_ENCRYPTION_STATUS, &tmp,
sizeof(tmp));
if (ret != 0) {
- devwarn(usbdev, "setting encr mode failed (%08X)", ret);
+ netdev_warn(usbdev->net, "setting encr mode failed (%08X)\n",
+ ret);
return ret;
}
@@ -1151,13 +1157,15 @@ static int set_infra_mode(struct usbnet *usbdev, int mode)
__le32 tmp;
int ret;
- devdbg(usbdev, "set_infra_mode: infra_mode=0x%x", priv->infra_mode);
+ netdev_dbg(usbdev->net, "%s(): infra_mode=0x%x\n",
+ __func__, priv->infra_mode);
tmp = cpu_to_le32(mode);
ret = rndis_set_oid(usbdev, OID_802_11_INFRASTRUCTURE_MODE, &tmp,
sizeof(tmp));
if (ret != 0) {
- devwarn(usbdev, "setting infra mode failed (%08X)", ret);
+ netdev_warn(usbdev->net, "setting infra mode failed (%08X)\n",
+ ret);
return ret;
}
@@ -1174,7 +1182,7 @@ static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold)
{
__le32 tmp;
- devdbg(usbdev, "set_rts_threshold %i", rts_threshold);
+ netdev_dbg(usbdev->net, "%s(): %i\n", __func__, rts_threshold);
if (rts_threshold < 0 || rts_threshold > 2347)
rts_threshold = 2347;
@@ -1188,7 +1196,7 @@ static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold)
{
__le32 tmp;
- devdbg(usbdev, "set_frag_threshold %i", frag_threshold);
+ netdev_dbg(usbdev->net, "%s(): %i\n", __func__, frag_threshold);
if (frag_threshold < 256 || frag_threshold > 2346)
frag_threshold = 2346;
@@ -1222,7 +1230,7 @@ static int set_channel(struct usbnet *usbdev, int channel)
unsigned int dsconfig;
int len, ret;
- devdbg(usbdev, "set_channel(%d)", channel);
+ netdev_dbg(usbdev->net, "%s(%d)\n", __func__, channel);
/* this OID is valid only when not associated */
if (is_associated(usbdev))
@@ -1233,7 +1241,8 @@ static int set_channel(struct usbnet *usbdev, int channel)
len = sizeof(config);
ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len);
if (ret < 0) {
- devdbg(usbdev, "set_channel: querying configuration failed");
+ netdev_dbg(usbdev->net, "%s(): querying configuration failed\n",
+ __func__);
return ret;
}
@@ -1241,7 +1250,7 @@ static int set_channel(struct usbnet *usbdev, int channel)
ret = rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config,
sizeof(config));
- devdbg(usbdev, "set_channel: %d -> %d", channel, ret);
+ netdev_dbg(usbdev->net, "%s(): %d -> %d\n", __func__, channel, ret);
return ret;
}
@@ -1255,7 +1264,8 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len,
u32 cipher;
int ret;
- devdbg(usbdev, "add_wep_key(idx: %d, len: %d)", index, key_len);
+ netdev_dbg(usbdev->net, "%s(idx: %d, len: %d)\n",
+ __func__, index, key_len);
if ((key_len != 5 && key_len != 13) || index < 0 || index > 3)
return -EINVAL;
@@ -1277,15 +1287,15 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len,
ret = set_encr_mode(usbdev, RNDIS_WLAN_ALG_WEP,
RNDIS_WLAN_ALG_NONE);
if (ret)
- devwarn(usbdev, "encryption couldn't be enabled (%08X)",
- ret);
+ netdev_warn(usbdev->net, "encryption couldn't be enabled (%08X)\n",
+ ret);
}
ret = rndis_set_oid(usbdev, OID_802_11_ADD_WEP, &ndis_key,
sizeof(ndis_key));
if (ret != 0) {
- devwarn(usbdev, "adding encryption key %d failed (%08X)",
- index+1, ret);
+ netdev_warn(usbdev->net, "adding encryption key %d failed (%08X)\n",
+ index + 1, ret);
return ret;
}
@@ -1307,22 +1317,23 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
int ret;
if (index < 0 || index >= 4) {
- devdbg(usbdev, "add_wpa_key: index out of range (%i)", index);
+ netdev_dbg(usbdev->net, "%s(): index out of range (%i)\n",
+ __func__, index);
return -EINVAL;
}
if (key_len > sizeof(ndis_key.material) || key_len < 0) {
- devdbg(usbdev, "add_wpa_key: key length out of range (%i)",
- key_len);
+ netdev_dbg(usbdev->net, "%s(): key length out of range (%i)\n",
+ __func__, key_len);
return -EINVAL;
}
if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) {
if (!rx_seq || seq_len <= 0) {
- devdbg(usbdev, "add_wpa_key: recv seq flag without"
- "buffer");
+ netdev_dbg(usbdev->net, "%s(): recv seq flag without buffer\n",
+ __func__);
return -EINVAL;
}
if (rx_seq && seq_len > sizeof(ndis_key.rsc)) {
- devdbg(usbdev, "add_wpa_key: too big recv seq buffer");
+ netdev_dbg(usbdev->net, "%s(): too big recv seq buffer\n", __func__);
return -EINVAL;
}
}
@@ -1330,15 +1341,16 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
is_addr_ok = addr && !is_zero_ether_addr(addr) &&
!is_broadcast_ether_addr(addr);
if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) {
- devdbg(usbdev, "add_wpa_key: pairwise but bssid invalid (%pM)",
- addr);
+ netdev_dbg(usbdev->net, "%s(): pairwise but bssid invalid (%pM)\n",
+ __func__, addr);
return -EINVAL;
}
- devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index,
- !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY),
- !!(flags & NDIS_80211_ADDKEY_PAIRWISE_KEY),
- !!(flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ));
+ netdev_dbg(usbdev->net, "%s(%i): flags:%i%i%i\n",
+ __func__, index,
+ !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY),
+ !!(flags & NDIS_80211_ADDKEY_PAIRWISE_KEY),
+ !!(flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ));
memset(&ndis_key, 0, sizeof(ndis_key));
@@ -1372,7 +1384,8 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key,
le32_to_cpu(ndis_key.size));
- devdbg(usbdev, "add_wpa_key: OID_802_11_ADD_KEY -> %08X", ret);
+ netdev_dbg(usbdev->net, "%s(): OID_802_11_ADD_KEY -> %08X\n",
+ __func__, ret);
if (ret != 0)
return ret;
@@ -1401,7 +1414,7 @@ static int restore_key(struct usbnet *usbdev, int key_idx)
key = priv->encr_keys[key_idx];
- devdbg(usbdev, "restore_key: %i:%i", key_idx, key.len);
+ netdev_dbg(usbdev->net, "%s(): %i:%i\n", __func__, key_idx, key.len);
if (key.len == 0)
return 0;
@@ -1436,8 +1449,9 @@ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid)
is_wpa = is_wpa_key(priv, index);
- devdbg(usbdev, "remove_key: %i:%s:%i", index, is_wpa ? "wpa" : "wep",
- priv->encr_keys[index].len);
+ netdev_dbg(usbdev->net, "%s(): %i:%s:%i\n",
+ __func__, index, is_wpa ? "wpa" : "wep",
+ priv->encr_keys[index].len);
clear_key(priv, index);
@@ -1464,9 +1478,9 @@ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid)
ret = rndis_set_oid(usbdev, OID_802_11_REMOVE_WEP, &keyindex,
sizeof(keyindex));
if (ret != 0) {
- devwarn(usbdev,
- "removing encryption key %d failed (%08X)",
- index, ret);
+ netdev_warn(usbdev->net,
+ "removing encryption key %d failed (%08X)\n",
+ index, ret);
return ret;
}
}
@@ -1482,59 +1496,76 @@ static void set_multicast_list(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
struct dev_mc_list *mclist;
- __le32 filter;
- int ret, i, size;
- char *buf;
+ __le32 filter, basefilter;
+ int ret;
+ char *mc_addrs = NULL;
+ int mc_count;
- filter = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST;
+ basefilter = filter = RNDIS_PACKET_TYPE_DIRECTED |
+ RNDIS_PACKET_TYPE_BROADCAST;
if (usbdev->net->flags & IFF_PROMISC) {
filter |= RNDIS_PACKET_TYPE_PROMISCUOUS |
RNDIS_PACKET_TYPE_ALL_LOCAL;
- } else if (usbdev->net->flags & IFF_ALLMULTI ||
- usbdev->net->mc_count > priv->multicast_size) {
+ } else if (usbdev->net->flags & IFF_ALLMULTI) {
+ filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST;
+ }
+
+ if (filter != basefilter)
+ goto set_filter;
+
+ /*
+ * mc_list should be accessed holding the lock, so copy addresses to
+ * local buffer first.
+ */
+ netif_addr_lock_bh(usbdev->net);
+ mc_count = netdev_mc_count(usbdev->net);
+ if (mc_count > priv->multicast_size) {
filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST;
- } else if (usbdev->net->mc_count > 0) {
- size = min(priv->multicast_size, usbdev->net->mc_count);
- buf = kmalloc(size * ETH_ALEN, GFP_KERNEL);
- if (!buf) {
- devwarn(usbdev,
- "couldn't alloc %d bytes of memory",
- size * ETH_ALEN);
+ } else if (mc_count) {
+ int i = 0;
+
+ mc_addrs = kmalloc(mc_count * ETH_ALEN, GFP_ATOMIC);
+ if (!mc_addrs) {
+ netdev_warn(usbdev->net,
+ "couldn't alloc %d bytes of memory\n",
+ mc_count * ETH_ALEN);
+ netif_addr_unlock_bh(usbdev->net);
return;
}
- mclist = usbdev->net->mc_list;
- for (i = 0; i < size && mclist; mclist = mclist->next) {
- if (mclist->dmi_addrlen != ETH_ALEN)
- continue;
+ netdev_for_each_mc_addr(mclist, usbdev->net)
+ memcpy(mc_addrs + i++ * ETH_ALEN,
+ mclist->dmi_addr, ETH_ALEN);
+ }
+ netif_addr_unlock_bh(usbdev->net);
- memcpy(buf + i * ETH_ALEN, mclist->dmi_addr, ETH_ALEN);
- i++;
- }
+ if (filter != basefilter)
+ goto set_filter;
- ret = rndis_set_oid(usbdev, OID_802_3_MULTICAST_LIST, buf,
- i * ETH_ALEN);
- if (ret == 0 && i > 0)
+ if (mc_count) {
+ ret = rndis_set_oid(usbdev, OID_802_3_MULTICAST_LIST, mc_addrs,
+ mc_count * ETH_ALEN);
+ kfree(mc_addrs);
+ if (ret == 0)
filter |= RNDIS_PACKET_TYPE_MULTICAST;
else
filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST;
- devdbg(usbdev, "OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d",
- i, priv->multicast_size, ret);
-
- kfree(buf);
+ netdev_dbg(usbdev->net, "OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d\n",
+ mc_count, priv->multicast_size, ret);
}
+set_filter:
ret = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter,
sizeof(filter));
if (ret < 0) {
- devwarn(usbdev, "couldn't set packet filter: %08x",
- le32_to_cpu(filter));
+ netdev_warn(usbdev->net, "couldn't set packet filter: %08x\n",
+ le32_to_cpu(filter));
}
- devdbg(usbdev, "OID_GEN_CURRENT_PACKET_FILTER(%08x) -> %d",
- le32_to_cpu(filter), ret);
+ netdev_dbg(usbdev->net, "OID_GEN_CURRENT_PACKET_FILTER(%08x) -> %d\n",
+ le32_to_cpu(filter), ret);
}
/*
@@ -1592,7 +1623,8 @@ static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
- devdbg(usbdev, "rndis_set_tx_power type:0x%x dbm:%i", type, dbm);
+ netdev_dbg(usbdev->net, "%s(): type:0x%x dbm:%i\n",
+ __func__, type, dbm);
/* Device doesn't support changing txpower after initialization, only
* turn off/on radio. Support 'auto' mode and setting same dBm that is
@@ -1615,7 +1647,7 @@ static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm)
*dbm = get_bcm4320_power_dbm(priv);
- devdbg(usbdev, "rndis_get_tx_power dbm:%i", *dbm);
+ netdev_dbg(usbdev->net, "%s(): dbm:%i\n", __func__, *dbm);
return 0;
}
@@ -1629,7 +1661,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
int ret;
__le32 tmp;
- devdbg(usbdev, "cfg80211.scan");
+ netdev_dbg(usbdev->net, "cfg80211.scan\n");
/* Get current bssid list from device before new scan, as new scan
* clears internal bssid list.
@@ -1669,8 +1701,8 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
int ie_len, bssid_len;
u8 *ie;
- devdbg(usbdev, " found bssid: '%.32s' [%pM]", bssid->ssid.essid,
- bssid->mac);
+ netdev_dbg(usbdev->net, " found bssid: '%.32s' [%pM]\n",
+ bssid->ssid.essid, bssid->mac);
/* parse bssid structure */
bssid_len = le32_to_cpu(bssid->length);
@@ -1712,7 +1744,7 @@ static int rndis_check_bssid_list(struct usbnet *usbdev)
int ret = -EINVAL, len, count, bssid_len;
bool resized = false;
- devdbg(usbdev, "check_bssid_list");
+ netdev_dbg(usbdev->net, "check_bssid_list\n");
len = CONTROL_BUFFER_SIZE;
resize_buf:
@@ -1736,8 +1768,8 @@ resize_buf:
bssid = bssid_list->bssid;
bssid_len = le32_to_cpu(bssid->length);
count = le32_to_cpu(bssid_list->num_items);
- devdbg(usbdev, "check_bssid_list: %d BSSIDs found (buflen: %d)", count,
- len);
+ netdev_dbg(usbdev->net, "check_bssid_list: %d BSSIDs found (buflen: %d)\n",
+ count, len);
while (count && ((void *)bssid + bssid_len) <= (buf + len)) {
rndis_bss_info_update(usbdev, bssid);
@@ -1759,7 +1791,7 @@ static void rndis_get_scan_results(struct work_struct *work)
struct usbnet *usbdev = priv->usbdev;
int ret;
- devdbg(usbdev, "get_scan_results");
+ netdev_dbg(usbdev->net, "get_scan_results\n");
if (!priv->scan_request)
return;
@@ -1793,7 +1825,7 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
if (sme->crypto.n_ciphers_pairwise > 0 &&
pairwise == RNDIS_WLAN_ALG_NONE) {
- deverr(usbdev, "Unsupported pairwise cipher");
+ netdev_err(usbdev->net, "Unsupported pairwise cipher\n");
return -ENOTSUPP;
}
@@ -1803,28 +1835,30 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
if (sme->crypto.n_akm_suites > 0 &&
keymgmt == RNDIS_WLAN_KEY_MGMT_NONE) {
- deverr(usbdev, "Invalid keymgmt");
+ netdev_err(usbdev->net, "Invalid keymgmt\n");
return -ENOTSUPP;
}
- devdbg(usbdev, "cfg80211.connect('%.32s':[%pM]:%d:[%d,0x%x:0x%x]:[0x%x:"
- "0x%x]:0x%x)", sme->ssid, sme->bssid, chan,
- sme->privacy, sme->crypto.wpa_versions, sme->auth_type,
- groupwise, pairwise, keymgmt);
+ netdev_dbg(usbdev->net, "cfg80211.connect('%.32s':[%pM]:%d:[%d,0x%x:0x%x]:[0x%x:0x%x]:0x%x)\n",
+ sme->ssid, sme->bssid, chan,
+ sme->privacy, sme->crypto.wpa_versions, sme->auth_type,
+ groupwise, pairwise, keymgmt);
if (is_associated(usbdev))
disassociate(usbdev, false);
ret = set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA);
if (ret < 0) {
- devdbg(usbdev, "connect: set_infra_mode failed, %d", ret);
+ netdev_dbg(usbdev->net, "connect: set_infra_mode failed, %d\n",
+ ret);
goto err_turn_radio_on;
}
ret = set_auth_mode(usbdev, sme->crypto.wpa_versions, sme->auth_type,
keymgmt);
if (ret < 0) {
- devdbg(usbdev, "connect: set_auth_mode failed, %d", ret);
+ netdev_dbg(usbdev->net, "connect: set_auth_mode failed, %d\n",
+ ret);
goto err_turn_radio_on;
}
@@ -1832,14 +1866,16 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
ret = set_encr_mode(usbdev, pairwise, groupwise);
if (ret < 0) {
- devdbg(usbdev, "connect: set_encr_mode failed, %d", ret);
+ netdev_dbg(usbdev->net, "connect: set_encr_mode failed, %d\n",
+ ret);
goto err_turn_radio_on;
}
if (channel) {
ret = set_channel(usbdev, chan);
if (ret < 0) {
- devdbg(usbdev, "connect: set_channel failed, %d", ret);
+ netdev_dbg(usbdev->net, "connect: set_channel failed, %d\n",
+ ret);
goto err_turn_radio_on;
}
}
@@ -1848,8 +1884,8 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
priv->encr_tx_key_index = sme->key_idx;
ret = add_wep_key(usbdev, sme->key, sme->key_len, sme->key_idx);
if (ret < 0) {
- devdbg(usbdev, "connect: add_wep_key failed, %d "
- "(%d, %d)", ret, sme->key_len, sme->key_idx);
+ netdev_dbg(usbdev->net, "connect: add_wep_key failed, %d (%d, %d)\n",
+ ret, sme->key_len, sme->key_idx);
goto err_turn_radio_on;
}
}
@@ -1858,7 +1894,8 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
!is_broadcast_ether_addr(sme->bssid)) {
ret = set_bssid(usbdev, sme->bssid);
if (ret < 0) {
- devdbg(usbdev, "connect: set_bssid failed, %d", ret);
+ netdev_dbg(usbdev->net, "connect: set_bssid failed, %d\n",
+ ret);
goto err_turn_radio_on;
}
} else
@@ -1880,7 +1917,7 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
ret = set_essid(usbdev, &ssid);
if (ret < 0)
- devdbg(usbdev, "connect: set_essid failed, %d", ret);
+ netdev_dbg(usbdev->net, "connect: set_essid failed, %d\n", ret);
return ret;
err_turn_radio_on:
@@ -1895,7 +1932,7 @@ static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev,
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
- devdbg(usbdev, "cfg80211.disconnect(%d)", reason_code);
+ netdev_dbg(usbdev->net, "cfg80211.disconnect(%d)\n", reason_code);
priv->connected = false;
memset(priv->bssid, 0, ETH_ALEN);
@@ -1929,21 +1966,23 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
alg = RNDIS_WLAN_ALG_NONE;
}
- devdbg(usbdev, "cfg80211.join_ibss('%.32s':[%pM]:%d:%d)", params->ssid,
- params->bssid, chan, params->privacy);
+ netdev_dbg(usbdev->net, "cfg80211.join_ibss('%.32s':[%pM]:%d:%d)\n",
+ params->ssid, params->bssid, chan, params->privacy);
if (is_associated(usbdev))
disassociate(usbdev, false);
ret = set_infra_mode(usbdev, NDIS_80211_INFRA_ADHOC);
if (ret < 0) {
- devdbg(usbdev, "join_ibss: set_infra_mode failed, %d", ret);
+ netdev_dbg(usbdev->net, "join_ibss: set_infra_mode failed, %d\n",
+ ret);
goto err_turn_radio_on;
}
ret = set_auth_mode(usbdev, 0, auth_type, RNDIS_WLAN_KEY_MGMT_NONE);
if (ret < 0) {
- devdbg(usbdev, "join_ibss: set_auth_mode failed, %d", ret);
+ netdev_dbg(usbdev->net, "join_ibss: set_auth_mode failed, %d\n",
+ ret);
goto err_turn_radio_on;
}
@@ -1951,15 +1990,16 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
ret = set_encr_mode(usbdev, alg, RNDIS_WLAN_ALG_NONE);
if (ret < 0) {
- devdbg(usbdev, "join_ibss: set_encr_mode failed, %d", ret);
+ netdev_dbg(usbdev->net, "join_ibss: set_encr_mode failed, %d\n",
+ ret);
goto err_turn_radio_on;
}
if (channel) {
ret = set_channel(usbdev, chan);
if (ret < 0) {
- devdbg(usbdev, "join_ibss: set_channel failed, %d",
- ret);
+ netdev_dbg(usbdev->net, "join_ibss: set_channel failed, %d\n",
+ ret);
goto err_turn_radio_on;
}
}
@@ -1968,7 +2008,8 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
!is_broadcast_ether_addr(params->bssid)) {
ret = set_bssid(usbdev, params->bssid);
if (ret < 0) {
- devdbg(usbdev, "join_ibss: set_bssid failed, %d", ret);
+ netdev_dbg(usbdev->net, "join_ibss: set_bssid failed, %d\n",
+ ret);
goto err_turn_radio_on;
}
} else
@@ -1988,7 +2029,8 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
ret = set_essid(usbdev, &ssid);
if (ret < 0)
- devdbg(usbdev, "join_ibss: set_essid failed, %d", ret);
+ netdev_dbg(usbdev->net, "join_ibss: set_essid failed, %d\n",
+ ret);
return ret;
err_turn_radio_on:
@@ -2002,7 +2044,7 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
- devdbg(usbdev, "cfg80211.leave_ibss()");
+ netdev_dbg(usbdev->net, "cfg80211.leave_ibss()\n");
priv->connected = false;
memset(priv->bssid, 0, ETH_ALEN);
@@ -2028,8 +2070,8 @@ static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
struct usbnet *usbdev = priv->usbdev;
__le32 flags;
- devdbg(usbdev, "rndis_add_key(%i, %pM, %08x)", key_index, mac_addr,
- params->cipher);
+ netdev_dbg(usbdev->net, "%s(%i, %pM, %08x)\n",
+ __func__, key_index, mac_addr, params->cipher);
switch (params->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
@@ -2050,8 +2092,8 @@ static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
key_index, mac_addr, params->seq,
params->seq_len, params->cipher, flags);
default:
- devdbg(usbdev, "rndis_add_key: unsupported cipher %08x",
- params->cipher);
+ netdev_dbg(usbdev->net, "%s(): unsupported cipher %08x\n",
+ __func__, params->cipher);
return -ENOTSUPP;
}
}
@@ -2062,7 +2104,7 @@ static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
- devdbg(usbdev, "rndis_del_key(%i, %pM)", key_index, mac_addr);
+ netdev_dbg(usbdev->net, "%s(%i, %pM)\n", __func__, key_index, mac_addr);
return remove_key(usbdev, key_index, mac_addr);
}
@@ -2074,7 +2116,7 @@ static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
struct usbnet *usbdev = priv->usbdev;
struct rndis_wlan_encr_key key;
- devdbg(usbdev, "rndis_set_default_key(%i)", key_index);
+ netdev_dbg(usbdev->net, "%s(%i)\n", __func__, key_index);
priv->encr_tx_key_index = key_index;
@@ -2188,7 +2230,8 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
if (ret < 0)
memset(bssid, 0, sizeof(bssid));
- devdbg(usbdev, "link up work: [%pM] %s", bssid, roamed ? "roamed" : "");
+ netdev_dbg(usbdev->net, "link up work: [%pM]%s\n",
+ bssid, roamed ? " roamed" : "");
/* Internal bss list in device always contains at least the currently
* connected bss and we can get it to cfg80211 with
@@ -2270,8 +2313,8 @@ static void rndis_wlan_auth_indication(struct usbnet *usbdev,
/* must have at least one array entry */
if (len < offsetof(struct ndis_80211_status_indication, u) +
sizeof(struct ndis_80211_auth_request)) {
- devinfo(usbdev, "authentication indication: "
- "too short message (%i)", len);
+ netdev_info(usbdev->net, "authentication indication: too short message (%i)\n",
+ len);
return;
}
@@ -2298,8 +2341,8 @@ static void rndis_wlan_auth_indication(struct usbnet *usbdev,
type = "group_error";
}
- devinfo(usbdev, "authentication indication: %s (0x%08x)", type,
- le32_to_cpu(auth_req->flags));
+ netdev_info(usbdev->net, "authentication indication: %s (0x%08x)\n",
+ type, le32_to_cpu(auth_req->flags));
if (pairwise_error) {
key_type = NL80211_KEYTYPE_PAIRWISE;
@@ -2335,8 +2378,8 @@ static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev,
if (len < offsetof(struct ndis_80211_status_indication, u) +
sizeof(struct ndis_80211_pmkid_cand_list)) {
- devinfo(usbdev, "pmkid candidate list indication: "
- "too short message (%i)", len);
+ netdev_info(usbdev->net, "pmkid candidate list indication: too short message (%i)\n",
+ len);
return;
}
@@ -2346,18 +2389,16 @@ static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev,
offsetof(struct ndis_80211_status_indication, u);
if (len < expected_len) {
- devinfo(usbdev, "pmkid candidate list indication: "
- "list larger than buffer (%i < %i)",
- len, expected_len);
+ netdev_info(usbdev->net, "pmkid candidate list indication: list larger than buffer (%i < %i)\n",
+ len, expected_len);
return;
}
cand_list = &indication->u.cand_list;
- devinfo(usbdev, "pmkid candidate list indication: "
- "version %i, candidates %i",
- le32_to_cpu(cand_list->version),
- le32_to_cpu(cand_list->num_candidates));
+ netdev_info(usbdev->net, "pmkid candidate list indication: version %i, candidates %i\n",
+ le32_to_cpu(cand_list->version),
+ le32_to_cpu(cand_list->num_candidates));
if (le32_to_cpu(cand_list->version) != 1)
return;
@@ -2366,8 +2407,8 @@ static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev,
struct ndis_80211_pmkid_candidate *cand =
&cand_list->candidate_list[i];
- devdbg(usbdev, "cand[%i]: flags: 0x%08x, bssid: %pM",
- i, le32_to_cpu(cand->flags), cand->bssid);
+ netdev_dbg(usbdev->net, "cand[%i]: flags: 0x%08x, bssid: %pM\n",
+ i, le32_to_cpu(cand->flags), cand->bssid);
#if 0
struct iw_pmkid_cand pcand;
@@ -2398,15 +2439,14 @@ static void rndis_wlan_media_specific_indication(struct usbnet *usbdev,
len = le32_to_cpu(msg->length);
if (len < 8) {
- devinfo(usbdev, "media specific indication, "
- "ignore too short message (%i < 8)", len);
+ netdev_info(usbdev->net, "media specific indication, ignore too short message (%i < 8)\n",
+ len);
return;
}
if (offset + len > buflen) {
- devinfo(usbdev, "media specific indication, "
- "too large to fit to buffer (%i > %i)",
- offset + len, buflen);
+ netdev_info(usbdev->net, "media specific indication, too large to fit to buffer (%i > %i)\n",
+ offset + len, buflen);
return;
}
@@ -2414,13 +2454,13 @@ static void rndis_wlan_media_specific_indication(struct usbnet *usbdev,
switch (le32_to_cpu(indication->status_type)) {
case NDIS_80211_STATUSTYPE_RADIOSTATE:
- devinfo(usbdev, "radio state indication: %i",
- le32_to_cpu(indication->u.radio_status));
+ netdev_info(usbdev->net, "radio state indication: %i\n",
+ le32_to_cpu(indication->u.radio_status));
return;
case NDIS_80211_STATUSTYPE_MEDIASTREAMMODE:
- devinfo(usbdev, "media stream mode indication: %i",
- le32_to_cpu(indication->u.media_stream_mode));
+ netdev_info(usbdev->net, "media stream mode indication: %i\n",
+ le32_to_cpu(indication->u.media_stream_mode));
return;
case NDIS_80211_STATUSTYPE_AUTHENTICATION:
@@ -2432,9 +2472,8 @@ static void rndis_wlan_media_specific_indication(struct usbnet *usbdev,
return;
default:
- devinfo(usbdev, "media specific indication: "
- "unknown status type 0x%08x",
- le32_to_cpu(indication->status_type));
+ netdev_info(usbdev->net, "media specific indication: unknown status type 0x%08x\n",
+ le32_to_cpu(indication->status_type));
}
}
@@ -2451,14 +2490,13 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen)
* and userspace to think that device is
* roaming/reassociating when it isn't.
*/
- devdbg(usbdev, "ignored OID_802_11_ADD_KEY triggered "
- "'media connect'");
+ netdev_dbg(usbdev->net, "ignored OID_802_11_ADD_KEY triggered 'media connect'\n");
return;
}
usbnet_pause_rx(usbdev);
- devinfo(usbdev, "media connect");
+ netdev_info(usbdev->net, "media connect\n");
/* queue work to avoid recursive calls into rndis_command */
set_bit(WORK_LINK_UP, &priv->work_pending);
@@ -2466,7 +2504,7 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen)
break;
case RNDIS_STATUS_MEDIA_DISCONNECT:
- devinfo(usbdev, "media disconnect");
+ netdev_info(usbdev->net, "media disconnect\n");
/* queue work to avoid recursive calls into rndis_command */
set_bit(WORK_LINK_DOWN, &priv->work_pending);
@@ -2478,8 +2516,8 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen)
break;
default:
- devinfo(usbdev, "indication: 0x%08x",
- le32_to_cpu(msg->status));
+ netdev_info(usbdev->net, "indication: 0x%08x\n",
+ le32_to_cpu(msg->status));
break;
}
}
@@ -2544,8 +2582,8 @@ static void rndis_device_poller(struct work_struct *work)
if (ret == 0)
priv->last_qual = level_to_qual(le32_to_cpu(rssi));
- devdbg(usbdev, "dev-poller: OID_802_11_RSSI -> %d, rssi:%d, qual: %d",
- ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi)));
+ netdev_dbg(usbdev->net, "dev-poller: OID_802_11_RSSI -> %d, rssi:%d, qual: %d\n",
+ ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi)));
/* Workaround transfer stalls on poor quality links.
* TODO: find right way to fix these stalls (as stalls do not happen
@@ -2594,23 +2632,9 @@ end:
/*
* driver/device initialization
*/
-static int bcm4320a_early_init(struct usbnet *usbdev)
-{
- /* bcm4320a doesn't handle configuration parameters well. Try
- * set any and you get partially zeroed mac and broken device.
- */
-
- return 0;
-}
-
-static int bcm4320b_early_init(struct usbnet *usbdev)
+static void rndis_copy_module_params(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- char buf[8];
-
- /* Early initialization settings, setting these won't have effect
- * if called after generic_rndis_bind().
- */
priv->param_country[0] = modparam_country[0];
priv->param_country[1] = modparam_country[1];
@@ -2652,6 +2676,32 @@ static int bcm4320b_early_init(struct usbnet *usbdev)
priv->param_workaround_interval = 500;
else
priv->param_workaround_interval = modparam_workaround_interval;
+}
+
+static int bcm4320a_early_init(struct usbnet *usbdev)
+{
+ /* copy module parameters for bcm4320a so that iwconfig reports txpower
+ * and workaround parameter is copied to private structure correctly.
+ */
+ rndis_copy_module_params(usbdev);
+
+ /* bcm4320a doesn't handle configuration parameters well. Try
+ * set any and you get partially zeroed mac and broken device.
+ */
+
+ return 0;
+}
+
+static int bcm4320b_early_init(struct usbnet *usbdev)
+{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ char buf[8];
+
+ rndis_copy_module_params(usbdev);
+
+ /* Early initialization settings, setting these won't have effect
+ * if called after generic_rndis_bind().
+ */
rndis_set_config_parameter_str(usbdev, "Country", priv->param_country);
rndis_set_config_parameter_str(usbdev, "FrameBursting",
@@ -2826,11 +2876,11 @@ static int rndis_wlan_reset(struct usbnet *usbdev)
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
int retval;
- devdbg(usbdev, "rndis_wlan_reset");
+ netdev_dbg(usbdev->net, "%s()\n", __func__);
retval = rndis_reset(usbdev);
if (retval)
- devwarn(usbdev, "rndis_reset() failed: %d", retval);
+ netdev_warn(usbdev->net, "rndis_reset failed: %d\n", retval);
/* rndis_reset cleared multicast list, so restore here.
(set_multicast_list() also turns on current packet filter) */
@@ -2848,7 +2898,7 @@ static int rndis_wlan_stop(struct usbnet *usbdev)
int retval;
__le32 filter;
- devdbg(usbdev, "rndis_wlan_stop");
+ netdev_dbg(usbdev->net, "%s()\n", __func__);
retval = disassociate(usbdev, false);
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index bf60689aaabb..5239e082cd0f 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -54,17 +54,17 @@ config RT61PCI
When compiled as a module, this driver will be called rt61pci.
config RT2800PCI_PCI
- tristate
+ boolean
depends on PCI
default y
config RT2800PCI_SOC
- tristate
+ boolean
depends on RALINK_RT288X || RALINK_RT305X
default y
config RT2800PCI
- tristate "Ralink rt2800 (PCI/PCMCIA) support (VERY EXPERIMENTAL)"
+ tristate "Ralink rt28xx/rt30xx/rt35xx (PCI/PCIe/PCMCIA) support (EXPERIMENTAL)"
depends on (RT2800PCI_PCI || RT2800PCI_SOC) && EXPERIMENTAL
select RT2800_LIB
select RT2X00_LIB_PCI if RT2800PCI_PCI
@@ -75,7 +75,7 @@ config RT2800PCI
select CRC_CCITT
select EEPROM_93CX6
---help---
- This adds support for rt2800 wireless chipset family.
+ This adds support for rt2800/rt3000/rt3500 wireless chipset family.
Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890 & RT3052
This driver is non-functional at the moment and is intended for
@@ -83,6 +83,32 @@ config RT2800PCI
When compiled as a module, this driver will be called "rt2800pci.ko".
+if RT2800PCI
+
+config RT2800PCI_RT30XX
+ bool "rt2800pci - Include support for rt30xx (PCI/PCIe/PCMCIA) devices"
+ default n
+ ---help---
+ This adds support for rt30xx wireless chipset family to the
+ rt2800pci driver.
+ Supported chips: RT3090, RT3091 & RT3092
+
+ Support for these devices is non-functional at the moment and is
+ intended for testers and developers.
+
+config RT2800PCI_RT35XX
+ bool "rt2800pci - Include support for rt35xx (PCI/PCIe/PCMCIA) devices"
+ default n
+ ---help---
+ This adds support for rt35xx wireless chipset family to the
+ rt2800pci driver.
+ Supported chips: RT3060, RT3062, RT3562, RT3592
+
+ Support for these devices is non-functional at the moment and is
+ intended for testers and developers.
+
+endif
+
config RT2500USB
tristate "Ralink rt2500 (USB) support"
depends on USB
@@ -126,6 +152,43 @@ config RT2800USB
When compiled as a module, this driver will be called "rt2800usb.ko".
+if RT2800USB
+
+config RT2800USB_RT30XX
+ bool "rt2800usb - Include support for rt30xx (USB) devices"
+ default n
+ ---help---
+ This adds support for rt30xx wireless chipset family to the
+ rt2800usb driver.
+ Supported chips: RT3070, RT3071 & RT3072
+
+ Support for these devices is non-functional at the moment and is
+ intended for testers and developers.
+
+config RT2800USB_RT35XX
+ bool "rt2800usb - Include support for rt35xx (USB) devices"
+ default n
+ ---help---
+ This adds support for rt35xx wireless chipset family to the
+ rt2800usb driver.
+ Supported chips: RT3572
+
+ Support for these devices is non-functional at the moment and is
+ intended for testers and developers.
+
+config RT2800USB_UNKNOWN
+ bool "rt2800usb - Include support for unknown (USB) devices"
+ default n
+ ---help---
+ This adds support for rt2800 family devices that are known to
+ have a rt2800 family chipset, but for which the exact chipset
+ is unknown.
+
+ Support status for these devices is unknown, and enabling these
+ devices may or may not work.
+
+endif
+
config RT2800_LIB
tristate
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index e7f46405a418..c22b04042d5c 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -451,7 +451,7 @@ static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev,
/*
* RF2420 chipset don't need any additional actions.
*/
- if (rt2x00_rf(&rt2x00dev->chip, RF2420))
+ if (rt2x00_rf(rt2x00dev, RF2420))
return;
/*
@@ -1340,11 +1340,10 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
- rt2x00_set_chip_rf(rt2x00dev, value, reg);
- rt2x00_print_chip(rt2x00dev);
+ rt2x00_set_chip(rt2x00dev, RT2460, value,
+ rt2x00_get_field32(reg, CSR0_REVISION));
- if (!rt2x00_rf(&rt2x00dev->chip, RF2420) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2421)) {
+ if (!rt2x00_rf(rt2x00dev, RF2420) && !rt2x00_rf(rt2x00dev, RF2421)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
@@ -1562,7 +1561,6 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2400pci_conf_tx,
- .get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2400pci_get_tsf,
.tx_last_beacon = rt2400pci_tx_last_beacon,
.rfkill_poll = rt2x00mac_rfkill_poll,
@@ -1643,7 +1641,7 @@ static const struct rt2x00_ops rt2400pci_ops = {
/*
* RT2400pci module information.
*/
-static struct pci_device_id rt2400pci_device_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(rt2400pci_device_table) = {
{ PCI_DEVICE(0x1814, 0x0101), PCI_DEVICE_DATA(&rt2400pci_ops) },
{ 0, }
};
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index c3dea697b907..c048b18f4133 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -65,6 +65,7 @@
* CSR0: ASIC revision number.
*/
#define CSR0 0x0000
+#define CSR0_REVISION FIELD32(0x0000ffff)
/*
* CSR1: System control register.
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 408fcfc120f5..52bbcf1bd17c 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -440,8 +440,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
/*
* RT2525E and RT5222 need to flip TX I/Q
*/
- if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
- rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) {
rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
@@ -449,7 +448,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
/*
* RT2525E does not need RX I/Q Flip.
*/
- if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+ if (rt2x00_rf(rt2x00dev, RF2525E))
rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
} else {
rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
@@ -475,14 +474,14 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
* Switch on tuning bits.
* For RT2523 devices we do not need to update the R1 register.
*/
- if (!rt2x00_rf(&rt2x00dev->chip, RF2523))
+ if (!rt2x00_rf(rt2x00dev, RF2523))
rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1);
rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1);
/*
* For RT2525 we should first set the channel to half band higher.
*/
- if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+ if (rt2x00_rf(rt2x00dev, RF2525)) {
static const u32 vals[] = {
0x00080cbe, 0x00080d02, 0x00080d06, 0x00080d0a,
0x00080d0e, 0x00080d12, 0x00080d16, 0x00080d1a,
@@ -516,7 +515,7 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
* Switch off tuning bits.
* For RT2523 devices we do not need to update the R1 register.
*/
- if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+ if (!rt2x00_rf(rt2x00dev, RF2523)) {
rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0);
rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
}
@@ -640,7 +639,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev,
* up to version C the link tuning should halt after 20
* seconds while being associated.
*/
- if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D &&
+ if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D &&
rt2x00dev->intf_associated && count > 20)
return;
@@ -650,7 +649,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev,
* should go straight to dynamic CCA tuning when they
* are not associated.
*/
- if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D ||
+ if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D ||
!rt2x00dev->intf_associated)
goto dynamic_cca_tune;
@@ -1504,15 +1503,15 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
- rt2x00_set_chip_rf(rt2x00dev, value, reg);
- rt2x00_print_chip(rt2x00dev);
-
- if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2523) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2524) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2525) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
- !rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ rt2x00_set_chip(rt2x00dev, RT2560, value,
+ rt2x00_get_field32(reg, CSR0_REVISION));
+
+ if (!rt2x00_rf(rt2x00dev, RF2522) &&
+ !rt2x00_rf(rt2x00dev, RF2523) &&
+ !rt2x00_rf(rt2x00dev, RF2524) &&
+ !rt2x00_rf(rt2x00dev, RF2525) &&
+ !rt2x00_rf(rt2x00dev, RF2525E) &&
+ !rt2x00_rf(rt2x00dev, RF5222)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
@@ -1744,22 +1743,22 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
- if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
+ if (rt2x00_rf(rt2x00dev, RF2522)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
spec->channels = rf_vals_bg_2522;
- } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+ } else if (rt2x00_rf(rt2x00dev, RF2523)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
spec->channels = rf_vals_bg_2523;
- } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
+ } else if (rt2x00_rf(rt2x00dev, RF2524)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
spec->channels = rf_vals_bg_2524;
- } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+ } else if (rt2x00_rf(rt2x00dev, RF2525)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
spec->channels = rf_vals_bg_2525;
- } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+ } else if (rt2x00_rf(rt2x00dev, RF2525E)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
spec->channels = rf_vals_bg_2525e;
- } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ } else if (rt2x00_rf(rt2x00dev, RF5222)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_5222);
spec->channels = rf_vals_5222;
@@ -1860,7 +1859,6 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
- .get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2500pci_get_tsf,
.tx_last_beacon = rt2500pci_tx_last_beacon,
.rfkill_poll = rt2x00mac_rfkill_poll,
@@ -1941,7 +1939,7 @@ static const struct rt2x00_ops rt2500pci_ops = {
/*
* RT2500pci module information.
*/
-static struct pci_device_id rt2500pci_device_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(rt2500pci_device_table) = {
{ PCI_DEVICE(0x1814, 0x0201), PCI_DEVICE_DATA(&rt2500pci_ops) },
{ 0, }
};
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
index c6bd1fcae7eb..d708031361ac 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -76,6 +76,7 @@
* CSR0: ASIC revision number.
*/
#define CSR0 0x0000
+#define CSR0_REVISION FIELD32(0x0000ffff)
/*
* CSR1: System control register.
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 83f2592c59de..9b04964deced 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -368,7 +368,7 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
/*
* The encryption key doesn't fit within the CSR cache,
- * this means we should allocate it seperately and use
+ * this means we should allocate it separately and use
* rt2x00usb_vendor_request() to send the key to the hardware.
*/
reg = KEY_ENTRY(key->hw_key_idx);
@@ -382,7 +382,7 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
/*
* The driver does not support the IV/EIV generation
* in hardware. However it demands the data to be provided
- * both seperately as well as inside the frame.
+ * both separately as well as inside the frame.
* We already provided the CONFIG_CRYPTO_COPY_IV to rt2x00lib
* to ensure rt2x00lib will not strip the data from the
* frame after the copy, now we must tell mac80211
@@ -565,8 +565,7 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev,
/*
* RT2525E and RT5222 need to flip TX I/Q
*/
- if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
- rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) {
rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 1);
rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 1);
@@ -574,7 +573,7 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev,
/*
* RT2525E does not need RX I/Q Flip.
*/
- if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+ if (rt2x00_rf(rt2x00dev, RF2525E))
rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
} else {
rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 0);
@@ -598,7 +597,7 @@ static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
/*
* For RT2525E we should first set the channel to half band higher.
*/
- if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+ if (rt2x00_rf(rt2x00dev, RF2525E)) {
static const u32 vals[] = {
0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
@@ -793,7 +792,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 1);
rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
- if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) {
+ if (rt2x00_rev(rt2x00dev) >= RT2570_VERSION_C) {
rt2500usb_register_read(rt2x00dev, PHY_CSR2, &reg);
rt2x00_set_field16(&reg, PHY_CSR2_LNA, 0);
} else {
@@ -1409,21 +1408,18 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2500usb_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
- rt2x00_print_chip(rt2x00dev);
-
- if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0) ||
- rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {
+ if (((reg & 0xfff0) != 0) || ((reg & 0x0000000f) == 0)) {
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
return -ENODEV;
}
- if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2523) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2524) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2525) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
- !rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ if (!rt2x00_rf(rt2x00dev, RF2522) &&
+ !rt2x00_rf(rt2x00dev, RF2523) &&
+ !rt2x00_rf(rt2x00dev, RF2524) &&
+ !rt2x00_rf(rt2x00dev, RF2525) &&
+ !rt2x00_rf(rt2x00dev, RF2525E) &&
+ !rt2x00_rf(rt2x00dev, RF5222)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
@@ -1667,22 +1663,22 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
- if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
+ if (rt2x00_rf(rt2x00dev, RF2522)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
spec->channels = rf_vals_bg_2522;
- } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+ } else if (rt2x00_rf(rt2x00dev, RF2523)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
spec->channels = rf_vals_bg_2523;
- } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
+ } else if (rt2x00_rf(rt2x00dev, RF2524)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
spec->channels = rf_vals_bg_2524;
- } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+ } else if (rt2x00_rf(rt2x00dev, RF2525)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
spec->channels = rf_vals_bg_2525;
- } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+ } else if (rt2x00_rf(rt2x00dev, RF2525E)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
spec->channels = rf_vals_bg_2525e;
- } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ } else if (rt2x00_rf(rt2x00dev, RF5222)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_5222);
spec->channels = rf_vals_5222;
@@ -1763,7 +1759,6 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
- .get_tx_stats = rt2x00mac_get_tx_stats,
.rfkill_poll = rt2x00mac_rfkill_poll,
};
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 1a7eae357fef..74c0433dba37 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -60,11 +60,11 @@
/*
* Chipset version.
*/
-#define RT2860C_VERSION 0x28600100
-#define RT2860D_VERSION 0x28600101
-#define RT2880E_VERSION 0x28720200
-#define RT2883_VERSION 0x28830300
-#define RT3070_VERSION 0x30700200
+#define RT2860C_VERSION 0x0100
+#define RT2860D_VERSION 0x0101
+#define RT2880E_VERSION 0x0200
+#define RT2883_VERSION 0x0300
+#define RT3070_VERSION 0x0200
/*
* Signal information.
@@ -408,8 +408,8 @@
* ASIC_VER: 2860 or 2870
*/
#define MAC_CSR0 0x1000
-#define MAC_CSR0_ASIC_REV FIELD32(0x0000ffff)
-#define MAC_CSR0_ASIC_VER FIELD32(0xffff0000)
+#define MAC_CSR0_REVISION FIELD32(0x0000ffff)
+#define MAC_CSR0_CHIPSET FIELD32(0xffff0000)
/*
* MAC_SYS_CTRL:
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 9deae41cb784..18d4d8e4ae6b 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -37,9 +37,12 @@
#include <linux/module.h>
#include "rt2x00.h"
-#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE)
+#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
#include "rt2x00usb.h"
#endif
+#if defined(CONFIG_RT2X00_LIB_PCI) || defined(CONFIG_RT2X00_LIB_PCI_MODULE)
+#include "rt2x00pci.h"
+#endif
#include "rt2800lib.h"
#include "rt2800.h"
#include "rt2800usb.h"
@@ -89,7 +92,7 @@ static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 0);
- if (rt2x00_intf_is_pci(rt2x00dev))
+ if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);
@@ -118,7 +121,7 @@ static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 1);
- if (rt2x00_intf_is_pci(rt2x00dev))
+ if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);
@@ -218,10 +221,9 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
u32 reg;
/*
- * RT2880 and RT3052 don't support MCU requests.
+ * SOC devices don't support MCU requests.
*/
- if (rt2x00_rt(&rt2x00dev->chip, RT2880) ||
- rt2x00_rt(&rt2x00dev->chip, RT3052))
+ if (rt2x00_is_soc(rt2x00dev))
return;
mutex_lock(&rt2x00dev->csr_mutex);
@@ -246,6 +248,25 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2800_mcu_request);
+int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u32 reg;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+ if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
+ !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
+ return 0;
+
+ msleep(1);
+ }
+
+ ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n");
+ return -EACCES;
+}
+EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
+
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
const struct rt2x00debug rt2800_rt2x00debug = {
.owner = THIS_MODULE,
@@ -348,7 +369,7 @@ static int rt2800_blink_set(struct led_classdev *led_cdev,
return 0;
}
-void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
+static void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
struct rt2x00_led *led, enum led_type type)
{
led->rt2x00dev = rt2x00dev;
@@ -357,7 +378,6 @@ void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
led->led_dev.blink_set = rt2800_blink_set;
led->flags = LED_INITIALIZED;
}
-EXPORT_SYMBOL_GPL(rt2800_init_led);
#endif /* CONFIG_RT2X00_LIB_LEDS */
/*
@@ -643,7 +663,7 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
switch ((int)ant->tx) {
case 1:
rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
- if (rt2x00_intf_is_pci(rt2x00dev))
+ if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);
break;
case 2:
@@ -806,12 +826,12 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
unsigned int tx_pin;
u8 bbp;
- if ((rt2x00_rt(&rt2x00dev->chip, RT3070) ||
- rt2x00_rt(&rt2x00dev->chip, RT3090)) &&
- (rt2x00_rf(&rt2x00dev->chip, RF2020) ||
- rt2x00_rf(&rt2x00dev->chip, RF3020) ||
- rt2x00_rf(&rt2x00dev->chip, RF3021) ||
- rt2x00_rf(&rt2x00dev->chip, RF3022)))
+ if ((rt2x00_rt(rt2x00dev, RT3070) ||
+ rt2x00_rt(rt2x00dev, RT3090)) &&
+ (rt2x00_rf(rt2x00dev, RF2020) ||
+ rt2x00_rf(rt2x00dev, RF3020) ||
+ rt2x00_rf(rt2x00dev, RF3021) ||
+ rt2x00_rf(rt2x00dev, RF3022)))
rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info);
else
rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info);
@@ -878,7 +898,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf));
rt2800_bbp_write(rt2x00dev, 3, bbp);
- if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
+ if (rt2x00_rt(rt2x00dev, RT2860) &&
+ (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) {
if (conf_is_ht40(conf)) {
rt2800_bbp_write(rt2x00dev, 69, 0x1a);
rt2800_bbp_write(rt2x00dev, 70, 0x0a);
@@ -1040,8 +1061,9 @@ EXPORT_SYMBOL_GPL(rt2800_link_stats);
static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
- if (rt2x00_intf_is_usb(rt2x00dev) &&
- rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION)
+ if (rt2x00_is_usb(rt2x00dev) &&
+ rt2x00_rt(rt2x00dev, RT3070) &&
+ (rt2x00_rev(rt2x00dev) == RT3070_VERSION))
return 0x1c + (2 * rt2x00dev->lna_gain);
else
return 0x2e + rt2x00dev->lna_gain;
@@ -1072,7 +1094,8 @@ EXPORT_SYMBOL_GPL(rt2800_reset_tuner);
void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
const u32 count)
{
- if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION)
+ if (rt2x00_rt(rt2x00dev, RT2860) &&
+ (rt2x00_rev(rt2x00dev) == RT2860C_VERSION))
return;
/*
@@ -1092,7 +1115,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
u32 reg;
unsigned int i;
- if (rt2x00_intf_is_usb(rt2x00dev)) {
+ if (rt2x00_is_usb(rt2x00dev)) {
/*
* Wait until BBP and RF are ready.
*/
@@ -1111,7 +1134,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL,
reg & ~0x00002000);
- } else if (rt2x00_intf_is_pci(rt2x00dev))
+ } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
@@ -1119,9 +1142,9 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
- if (rt2x00_intf_is_usb(rt2x00dev)) {
+ if (rt2x00_is_usb(rt2x00dev)) {
rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
-#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE)
+#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
USB_MODE_RESET, REGISTER_TIMEOUT);
#endif
@@ -1157,8 +1180,9 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0);
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
- if (rt2x00_intf_is_usb(rt2x00dev) &&
- rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) {
+ if (rt2x00_is_usb(rt2x00dev) &&
+ rt2x00_rt(rt2x00dev, RT3070) &&
+ (rt2x00_rev(rt2x00dev) == RT3070_VERSION)) {
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
@@ -1185,8 +1209,14 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, MAX_LEN_CFG, &reg);
rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE);
- if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION &&
- rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION)
+ if ((rt2x00_rt(rt2x00dev, RT2872) &&
+ (rt2x00_rev(rt2x00dev) >= RT2880E_VERSION)) ||
+ rt2x00_rt(rt2x00dev, RT2880) ||
+ rt2x00_rt(rt2x00dev, RT2883) ||
+ rt2x00_rt(rt2x00dev, RT2890) ||
+ rt2x00_rt(rt2x00dev, RT3052) ||
+ (rt2x00_rt(rt2x00dev, RT3070) &&
+ (rt2x00_rev(rt2x00dev) < RT3070_VERSION)))
rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 2);
else
rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 1);
@@ -1276,7 +1306,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1);
rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg);
- if (rt2x00_intf_is_usb(rt2x00dev)) {
+ if (rt2x00_is_usb(rt2x00dev)) {
rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006);
rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
@@ -1336,7 +1366,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0);
rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0);
- if (rt2x00_intf_is_usb(rt2x00dev)) {
+ if (rt2x00_is_usb(rt2x00dev)) {
rt2800_register_read(rt2x00dev, USB_CYC_CFG, &reg);
rt2x00_set_field32(&reg, USB_CYC_CFG_CLOCK_CYCLE, 30);
rt2800_register_write(rt2x00dev, USB_CYC_CFG, reg);
@@ -1465,22 +1495,25 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
rt2800_bbp_write(rt2x00dev, 103, 0x00);
rt2800_bbp_write(rt2x00dev, 105, 0x05);
- if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
+ if (rt2x00_rt(rt2x00dev, RT2860) &&
+ (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) {
rt2800_bbp_write(rt2x00dev, 69, 0x16);
rt2800_bbp_write(rt2x00dev, 73, 0x12);
}
- if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION)
+ if (rt2x00_rt(rt2x00dev, RT2860) &&
+ (rt2x00_rev(rt2x00dev) > RT2860D_VERSION))
rt2800_bbp_write(rt2x00dev, 84, 0x19);
- if (rt2x00_intf_is_usb(rt2x00dev) &&
- rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) {
+ if (rt2x00_is_usb(rt2x00dev) &&
+ rt2x00_rt(rt2x00dev, RT3070) &&
+ (rt2x00_rev(rt2x00dev) == RT3070_VERSION)) {
rt2800_bbp_write(rt2x00dev, 70, 0x0a);
rt2800_bbp_write(rt2x00dev, 84, 0x99);
rt2800_bbp_write(rt2x00dev, 105, 0x05);
}
- if (rt2x00_rt(&rt2x00dev->chip, RT3052)) {
+ if (rt2x00_rt(rt2x00dev, RT3052)) {
rt2800_bbp_write(rt2x00dev, 31, 0x08);
rt2800_bbp_write(rt2x00dev, 78, 0x0e);
rt2800_bbp_write(rt2x00dev, 80, 0x08);
@@ -1565,14 +1598,15 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
u8 rfcsr;
u8 bbp;
- if (rt2x00_intf_is_usb(rt2x00dev) &&
- rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION)
+ if (rt2x00_is_usb(rt2x00dev) &&
+ rt2x00_rt(rt2x00dev, RT3070) &&
+ (rt2x00_rev(rt2x00dev) != RT3070_VERSION))
return 0;
- if (rt2x00_intf_is_pci(rt2x00dev)) {
- if (!rt2x00_rf(&rt2x00dev->chip, RF3020) &&
- !rt2x00_rf(&rt2x00dev->chip, RF3021) &&
- !rt2x00_rf(&rt2x00dev->chip, RF3022))
+ if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) {
+ if (!rt2x00_rf(rt2x00dev, RF3020) &&
+ !rt2x00_rf(rt2x00dev, RF3021) &&
+ !rt2x00_rf(rt2x00dev, RF3022))
return 0;
}
@@ -1586,7 +1620,7 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0);
rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
- if (rt2x00_intf_is_usb(rt2x00dev)) {
+ if (rt2x00_is_usb(rt2x00dev)) {
rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
@@ -1607,7 +1641,7 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
- } else if (rt2x00_intf_is_pci(rt2x00dev)) {
+ } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) {
rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
rt2800_rfcsr_write(rt2x00dev, 2, 0xf7);
@@ -1737,7 +1771,12 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
- } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) {
+ } else if (rt2x00_rt(rt2x00dev, RT2860) ||
+ rt2x00_rt(rt2x00dev, RT2870) ||
+ rt2x00_rt(rt2x00dev, RT2872) ||
+ rt2x00_rt(rt2x00dev, RT2880) ||
+ (rt2x00_rt(rt2x00dev, RT2883) &&
+ (rt2x00_rev(rt2x00dev) < RT2883_VERSION))) {
/*
* There is a max of 2 RX streams for RT28x0 series
*/
@@ -1836,36 +1875,34 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
- rt2x00_set_chip_rf(rt2x00dev, value, reg);
-
- if (rt2x00_intf_is_usb(rt2x00dev)) {
- struct rt2x00_chip *chip = &rt2x00dev->chip;
-
- /*
- * The check for rt2860 is not a typo, some rt2870 hardware
- * identifies itself as rt2860 in the CSR register.
- */
- if (rt2x00_check_rev(chip, 0xfff00000, 0x28600000) ||
- rt2x00_check_rev(chip, 0xfff00000, 0x28700000) ||
- rt2x00_check_rev(chip, 0xfff00000, 0x28800000)) {
- rt2x00_set_chip_rt(rt2x00dev, RT2870);
- } else if (rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) {
- rt2x00_set_chip_rt(rt2x00dev, RT3070);
- } else {
- ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
- return -ENODEV;
- }
+ rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
+ value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
+
+ if (!rt2x00_rt(rt2x00dev, RT2860) &&
+ !rt2x00_rt(rt2x00dev, RT2870) &&
+ !rt2x00_rt(rt2x00dev, RT2872) &&
+ !rt2x00_rt(rt2x00dev, RT2880) &&
+ !rt2x00_rt(rt2x00dev, RT2883) &&
+ !rt2x00_rt(rt2x00dev, RT2890) &&
+ !rt2x00_rt(rt2x00dev, RT3052) &&
+ !rt2x00_rt(rt2x00dev, RT3070) &&
+ !rt2x00_rt(rt2x00dev, RT3071) &&
+ !rt2x00_rt(rt2x00dev, RT3090) &&
+ !rt2x00_rt(rt2x00dev, RT3390) &&
+ !rt2x00_rt(rt2x00dev, RT3572)) {
+ ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
+ return -ENODEV;
}
- rt2x00_print_chip(rt2x00dev);
-
- if (!rt2x00_rf(&rt2x00dev->chip, RF2820) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2850) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2720) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2750) &&
- !rt2x00_rf(&rt2x00dev->chip, RF3020) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2020) &&
- !rt2x00_rf(&rt2x00dev->chip, RF3021) &&
- !rt2x00_rf(&rt2x00dev->chip, RF3022)) {
+
+ if (!rt2x00_rf(rt2x00dev, RF2820) &&
+ !rt2x00_rf(rt2x00dev, RF2850) &&
+ !rt2x00_rf(rt2x00dev, RF2720) &&
+ !rt2x00_rf(rt2x00dev, RF2750) &&
+ !rt2x00_rf(rt2x00dev, RF3020) &&
+ !rt2x00_rf(rt2x00dev, RF2020) &&
+ !rt2x00_rf(rt2x00dev, RF3021) &&
+ !rt2x00_rf(rt2x00dev, RF3022) &&
+ !rt2x00_rf(rt2x00dev, RF3052)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
@@ -2013,7 +2050,6 @@ static const struct rf_channel rf_vals_302x[] = {
int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
- struct rt2x00_chip *chip = &rt2x00dev->chip;
struct hw_mode_spec *spec = &rt2x00dev->spec;
struct channel_info *info;
char *tx_power1;
@@ -2024,7 +2060,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Disable powersaving as default on PCI devices.
*/
- if (rt2x00_intf_is_pci(rt2x00dev))
+ if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
/*
@@ -2049,19 +2085,19 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
- if (rt2x00_rf(chip, RF2820) ||
- rt2x00_rf(chip, RF2720) ||
- (rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(chip, RF3052))) {
+ if (rt2x00_rf(rt2x00dev, RF2820) ||
+ rt2x00_rf(rt2x00dev, RF2720) ||
+ rt2x00_rf(rt2x00dev, RF3052)) {
spec->num_channels = 14;
spec->channels = rf_vals;
- } else if (rt2x00_rf(chip, RF2850) || rt2x00_rf(chip, RF2750)) {
+ } else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, RF2750)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals);
spec->channels = rf_vals;
- } else if (rt2x00_rf(chip, RF3020) ||
- rt2x00_rf(chip, RF2020) ||
- rt2x00_rf(chip, RF3021) ||
- rt2x00_rf(chip, RF3022)) {
+ } else if (rt2x00_rf(rt2x00dev, RF3020) ||
+ rt2x00_rf(rt2x00dev, RF2020) ||
+ rt2x00_rf(rt2x00dev, RF3021) ||
+ rt2x00_rf(rt2x00dev, RF3022)) {
spec->num_channels = ARRAY_SIZE(rf_vals_302x);
spec->channels = rf_vals_302x;
}
@@ -2069,7 +2105,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize HT information.
*/
- if (!rt2x00_rf(chip, RF2020))
+ if (!rt2x00_rf(rt2x00dev, RF2020))
spec->ht.ht_supported = true;
else
spec->ht.ht_supported = false;
@@ -2282,7 +2318,6 @@ const struct ieee80211_ops rt2800_mac80211_ops = {
.set_rts_threshold = rt2800_set_rts_threshold,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2800_conf_tx,
- .get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2800_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
};
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 535ce22f2ac8..ebabeae62d1b 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -114,8 +114,6 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
extern const struct rt2x00debug rt2800_rt2x00debug;
int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev);
-void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
- struct rt2x00_led *led, enum led_type type);
int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key);
@@ -139,6 +137,7 @@ void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
int rt2800_init_registers(struct rt2x00_dev *rt2x00dev);
int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev);
int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev);
+int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev);
int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev);
void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index dfc886fcb44d..91cce2d0f6db 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -48,14 +48,6 @@
#include "rt2800.h"
#include "rt2800pci.h"
-#ifdef CONFIG_RT2800PCI_PCI_MODULE
-#define CONFIG_RT2800PCI_PCI
-#endif
-
-#ifdef CONFIG_RT2800PCI_WISOC_MODULE
-#define CONFIG_RT2800PCI_WISOC
-#endif
-
/*
* Allow hardware encryption to be disabled.
*/
@@ -87,7 +79,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
}
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
{
u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */
@@ -98,7 +90,7 @@ static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
{
}
-#endif /* CONFIG_RT2800PCI_WISOC */
+#endif /* CONFIG_RT2800PCI_SOC */
#ifdef CONFIG_RT2800PCI_PCI
static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
@@ -461,24 +453,6 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
}
-static int rt2800pci_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
-{
- unsigned int i;
- u32 reg;
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
- if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
- !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
- return 0;
-
- msleep(1);
- }
-
- ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n");
- return -EACCES;
-}
-
static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -487,10 +461,10 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all registers.
*/
- if (unlikely(rt2800pci_wait_wpdma_ready(rt2x00dev) ||
+ if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
rt2800pci_init_queues(rt2x00dev) ||
rt2800_init_registers(rt2x00dev) ||
- rt2800pci_wait_wpdma_ready(rt2x00dev) ||
+ rt2800_wait_wpdma_ready(rt2x00dev) ||
rt2800_init_bbp(rt2x00dev) ||
rt2800_init_rfcsr(rt2x00dev)))
return -EIO;
@@ -570,7 +544,7 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
/* Wait for DMA, ignore error */
- rt2800pci_wait_wpdma_ready(rt2x00dev);
+ rt2800_wait_wpdma_ready(rt2x00dev);
}
static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
@@ -835,7 +809,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
__le32 *rxd = entry_priv->desc;
__le32 *rxwi = (__le32 *)entry->skb->data;
@@ -883,10 +856,8 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS;
- if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD)) {
+ if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD))
rxdesc->dev_flags |= RXDONE_L2PAD;
- skbdesc->flags |= SKBDESC_L2_PADDED;
- }
if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
rxdesc->flags |= RX_FLAG_SHORT_GI;
@@ -927,7 +898,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
* Remove TXWI descriptor from start of buffer.
*/
skb_pull(entry->skb, RXWI_DESC_SIZE);
- skb_trim(entry->skb, rxdesc->size);
}
/*
@@ -1071,18 +1041,12 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Read EEPROM into buffer
*/
- switch (rt2x00dev->chip.rt) {
- case RT2880:
- case RT3052:
+ if (rt2x00_is_soc(rt2x00dev))
rt2800pci_read_eeprom_soc(rt2x00dev);
- break;
- default:
- if (rt2800pci_efuse_detect(rt2x00dev))
- rt2800pci_read_eeprom_efuse(rt2x00dev);
- else
- rt2800pci_read_eeprom_pci(rt2x00dev);
- break;
- }
+ else if (rt2800pci_efuse_detect(rt2x00dev))
+ rt2800pci_read_eeprom_efuse(rt2x00dev);
+ else
+ rt2800pci_read_eeprom_pci(rt2x00dev);
return rt2800_validate_eeprom(rt2x00dev);
}
@@ -1133,8 +1097,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* This device requires firmware.
*/
- if (!rt2x00_rt(&rt2x00dev->chip, RT2880) &&
- !rt2x00_rt(&rt2x00dev->chip, RT3052))
+ if (!rt2x00_is_soc(rt2x00dev))
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
@@ -1221,8 +1184,11 @@ static const struct rt2x00_ops rt2800pci_ops = {
/*
* RT2800pci module information.
*/
-static struct pci_device_id rt2800pci_device_table[] = {
- { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) },
+static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
+ { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) },
@@ -1230,18 +1196,19 @@ static struct pci_device_id rt2800pci_device_table[] = {
{ PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) },
+#ifdef CONFIG_RT2800PCI_RT30XX
{ PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) },
+#endif
+#ifdef CONFIG_RT2800PCI_RT35XX
+ { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) },
{ PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) },
+#endif
{ 0, }
};
@@ -1255,12 +1222,11 @@ MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);
#endif /* CONFIG_RT2800PCI_PCI */
MODULE_LICENSE("GPL");
-#ifdef CONFIG_RT2800PCI_WISOC
-#if defined(CONFIG_RALINK_RT288X)
-__rt2x00soc_probe(RT2880, &rt2800pci_ops);
-#elif defined(CONFIG_RALINK_RT305X)
-__rt2x00soc_probe(RT3052, &rt2800pci_ops);
-#endif
+#ifdef CONFIG_RT2800PCI_SOC
+static int rt2800soc_probe(struct platform_device *pdev)
+{
+ return rt2x00soc_probe(pdev, &rt2800pci_ops);
+}
static struct platform_driver rt2800soc_driver = {
.driver = {
@@ -1268,12 +1234,12 @@ static struct platform_driver rt2800soc_driver = {
.owner = THIS_MODULE,
.mod_name = KBUILD_MODNAME,
},
- .probe = __rt2x00soc_probe,
+ .probe = rt2800soc_probe,
.remove = __devexit_p(rt2x00soc_remove),
.suspend = rt2x00soc_suspend,
.resume = rt2x00soc_resume,
};
-#endif /* CONFIG_RT2800PCI_WISOC */
+#endif /* CONFIG_RT2800PCI_SOC */
#ifdef CONFIG_RT2800PCI_PCI
static struct pci_driver rt2800pci_driver = {
@@ -1290,7 +1256,7 @@ static int __init rt2800pci_init(void)
{
int ret = 0;
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
ret = platform_driver_register(&rt2800soc_driver);
if (ret)
return ret;
@@ -1298,7 +1264,7 @@ static int __init rt2800pci_init(void)
#ifdef CONFIG_RT2800PCI_PCI
ret = pci_register_driver(&rt2800pci_driver);
if (ret) {
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
platform_driver_unregister(&rt2800soc_driver);
#endif
return ret;
@@ -1313,7 +1279,7 @@ static void __exit rt2800pci_exit(void)
#ifdef CONFIG_RT2800PCI_PCI
pci_unregister_driver(&rt2800pci_driver);
#endif
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
platform_driver_unregister(&rt2800soc_driver);
#endif
}
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index ab95346cf6a3..d27d7d5d850c 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -92,7 +92,6 @@ static bool rt2800usb_check_crc(const u8 *data, const size_t len)
static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
- u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff;
size_t offset = 0;
/*
@@ -100,7 +99,7 @@ static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev,
* There are 2 variations of the rt2870 firmware.
* a) size: 4kb
* b) size: 8kb
- * Note that (b) contains 2 seperate firmware blobs of 4k
+ * Note that (b) contains 2 separate firmware blobs of 4k
* within the file. The first blob is the same firmware as (a),
* but the second blob is for the additional chipsets.
*/
@@ -111,14 +110,14 @@ static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev,
* Check if we need the upper 4kb firmware data or not.
*/
if ((len == 4096) &&
- (chipset != 0x2860) &&
- (chipset != 0x2872) &&
- (chipset != 0x3070))
+ !rt2x00_rt(rt2x00dev, RT2860) &&
+ !rt2x00_rt(rt2x00dev, RT2872) &&
+ !rt2x00_rt(rt2x00dev, RT3070))
return FW_BAD_VERSION;
/*
* 8kb firmware files must be checked as if it were
- * 2 seperate firmware files.
+ * 2 separate firmware files.
*/
while (offset < len) {
if (!rt2800usb_check_crc(data + offset, 4096))
@@ -138,14 +137,13 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
u32 reg;
u32 offset;
u32 length;
- u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff;
/*
* Check which section of the firmware we need.
*/
- if ((chipset == 0x2860) ||
- (chipset == 0x2872) ||
- (chipset == 0x3070)) {
+ if (rt2x00_rt(rt2x00dev, RT2860) ||
+ rt2x00_rt(rt2x00dev, RT2872) ||
+ rt2x00_rt(rt2x00dev, RT3070)) {
offset = 0;
length = 4096;
} else {
@@ -200,9 +198,9 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
*/
rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0);
- if ((chipset == 0x3070) ||
- (chipset == 0x3071) ||
- (chipset == 0x3572)) {
+ if (rt2x00_rt(rt2x00dev, RT3070) ||
+ rt2x00_rt(rt2x00dev, RT3071) ||
+ rt2x00_rt(rt2x00dev, RT3572)) {
udelay(200);
rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0);
udelay(10);
@@ -248,24 +246,6 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
}
-static int rt2800usb_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
-{
- unsigned int i;
- u32 reg;
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
- if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
- !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
- return 0;
-
- msleep(1);
- }
-
- ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n");
- return -EACCES;
-}
-
static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -274,7 +254,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all registers.
*/
- if (unlikely(rt2800usb_wait_wpdma_ready(rt2x00dev) ||
+ if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
rt2800_init_registers(rt2x00dev) ||
rt2800_init_bbp(rt2x00dev) ||
rt2800_init_rfcsr(rt2x00dev)))
@@ -295,9 +275,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, USB_DMA_CFG, &reg);
rt2x00_set_field32(&reg, USB_DMA_CFG_PHY_CLEAR, 0);
- /* Don't use bulk in aggregation when working with USB 1.1 */
- rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_EN,
- (rt2x00dev->rx->usb_maxpacket == 512));
+ rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_EN, 0);
rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128);
/*
* Total room for RX frames in kilobytes, PBF might still exceed
@@ -346,7 +324,7 @@ static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
/* Wait for DMA, ignore error */
- rt2800usb_wait_wpdma_ready(rt2x00dev);
+ rt2800_wait_wpdma_ready(rt2x00dev);
rt2x00usb_disable_radio(rt2x00dev);
}
@@ -573,41 +551,57 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- __le32 *rxd = (__le32 *)entry->skb->data;
+ __le32 *rxi = (__le32 *)entry->skb->data;
__le32 *rxwi;
- u32 rxd0;
+ __le32 *rxd;
+ u32 rxi0;
u32 rxwi0;
u32 rxwi1;
u32 rxwi2;
u32 rxwi3;
+ u32 rxd0;
+ int rx_pkt_len;
+
+ /*
+ * RX frame format is :
+ * | RXINFO | RXWI | header | L2 pad | payload | pad | RXD | USB pad |
+ * |<------------ rx_pkt_len -------------->|
+ */
+ rt2x00_desc_read(rxi, 0, &rxi0);
+ rx_pkt_len = rt2x00_get_field32(rxi0, RXINFO_W0_USB_DMA_RX_PKT_LEN);
+
+ rxwi = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE);
+
+ /*
+ * FIXME : we need to check for rx_pkt_len validity
+ */
+ rxd = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE + rx_pkt_len);
/*
* Copy descriptor to the skbdesc->desc buffer, making it safe from
* moving of frame data in rt2x00usb.
*/
- memcpy(skbdesc->desc, rxd, skbdesc->desc_len);
- rxd = (__le32 *)skbdesc->desc;
- rxwi = &rxd[RXINFO_DESC_SIZE / sizeof(__le32)];
+ memcpy(skbdesc->desc, rxi, skbdesc->desc_len);
/*
* It is now safe to read the descriptor on all architectures.
*/
- rt2x00_desc_read(rxd, 0, &rxd0);
rt2x00_desc_read(rxwi, 0, &rxwi0);
rt2x00_desc_read(rxwi, 1, &rxwi1);
rt2x00_desc_read(rxwi, 2, &rxwi2);
rt2x00_desc_read(rxwi, 3, &rxwi3);
+ rt2x00_desc_read(rxd, 0, &rxd0);
- if (rt2x00_get_field32(rxd0, RXINFO_W0_CRC_ERROR))
+ if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF);
rxdesc->cipher_status =
- rt2x00_get_field32(rxd0, RXINFO_W0_CIPHER_ERROR);
+ rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR);
}
- if (rt2x00_get_field32(rxd0, RXINFO_W0_DECRYPTED)) {
+ if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) {
/*
* Hardware has stripped IV/EIV data from 802.11 frame during
* decryption. Unfortunately the descriptor doesn't contain
@@ -622,13 +616,11 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
rxdesc->flags |= RX_FLAG_MMIC_ERROR;
}
- if (rt2x00_get_field32(rxd0, RXINFO_W0_MY_BSS))
+ if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS;
- if (rt2x00_get_field32(rxd0, RXINFO_W0_L2PAD)) {
+ if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD))
rxdesc->dev_flags |= RXDONE_L2PAD;
- skbdesc->flags |= SKBDESC_L2_PADDED;
- }
if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
rxdesc->flags |= RX_FLAG_SHORT_GI;
@@ -663,7 +655,6 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
* Remove RXWI descriptor from start of buffer.
*/
skb_pull(entry->skb, skbdesc->desc_len);
- skb_trim(entry->skb, rxdesc->size);
}
/*
@@ -814,51 +805,27 @@ static struct usb_device_id rt2800usb_device_table[] = {
/* Abocom */
{ USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* AirTies */
- { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Amigo */
- { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Amit */
{ USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Askey */
{ USB_DEVICE(0x1690, 0x0740), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) },
/* ASUS */
{ USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
/* AzureWave */
{ USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Belkin */
{ USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Buffalo */
{ USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Cisco */
- { USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Conceptronic */
{ USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -867,157 +834,257 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) },
/* D-Link */
{ USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Edimax */
+ { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* EnGenius */
+ { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Gigabyte */
+ { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Hawking */
+ { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Linksys */
+ { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Logitec */
+ { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Motorola */
+ { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* MSI */
+ { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Philips */
+ { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Planex */
+ { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Ralink */
+ { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Samsung */
+ { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Siemens */
+ { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Sitecom */
+ { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* SMC */
+ { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Sparklan */
+ { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Sweex */
+ { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* U-Media*/
+ { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* ZCOM */
+ { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Zinwell */
+ { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Zyxel */
+ { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
+#ifdef CONFIG_RT2800USB_RT30XX
+ /* Abocom */
+ { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* AirTies */
+ { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* AzureWave */
+ { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Conceptronic */
+ { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Corega */
+ { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* D-Link */
{ USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Edimax */
{ USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Encore */
{ USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
/* EnGenius */
- { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Gigabyte */
+ { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* I-O DATA */
+ { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* MSI */
+ { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Pegatron */
+ { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Planex */
+ { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Quanta */
+ { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Ralink */
+ { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Sitecom */
+ { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* SMC */
+ { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Zinwell */
+ { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
+#endif
+#ifdef CONFIG_RT2800USB_RT35XX
+ /* Askey */
+ { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Cisco */
+ { USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* EnGenius */
+ { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* I-O DATA */
+ { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Ralink */
+ { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Sitecom */
+ { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Zinwell */
+ { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) },
+#endif
+#ifdef CONFIG_RT2800USB_UNKNOWN
+ /*
+ * Unclear what kind of devices these are (they aren't supported by the
+ * vendor driver).
+ */
+ /* Allwin */
+ { USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Amigo */
+ { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Askey */
+ { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* ASUS */
+ { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* AzureWave */
+ { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Belkin */
+ { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Buffalo */
+ { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0411, 0x0148), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0411, 0x0150), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0411, 0x015d), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Conceptronic */
+ { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Corega */
+ { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* D-Link */
+ { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* Encore */
+ { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
+ /* EnGenius */
{ USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Gemtek */
{ USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Gigabyte */
- { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Hawking */
- { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
/* I-O DATA */
- { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
/* LevelOne */
{ USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Linksys */
- { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1737, 0x0078), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Logitec */
- { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Motorola */
- { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) },
/* MSI */
- { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Ovislink */
{ USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Para */
{ USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Pegatron */
+ { USB_DEVICE(0x05a6, 0x0101), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Philips */
- { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Planex */
- { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Qcom */
{ USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Quanta */
- { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Ralink */
- { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Samsung */
- { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Siemens */
- { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Sitecom */
- { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x004a), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x004d), USB_DEVICE_DATA(&rt2800usb_ops) },
/* SMC */
- { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Sparklan */
- { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x083a, 0xd522), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Sweex */
{ USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* U-Media*/
- { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* ZCOM */
- { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Zinwell */
- { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Zyxel */
- { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) },
+#endif
{ 0, }
};
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h
index 1e4340a182ef..d1d8ae94b4d4 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.h
+++ b/drivers/net/wireless/rt2x00/rt2800usb.h
@@ -79,6 +79,8 @@
*/
#define TXINFO_DESC_SIZE ( 1 * sizeof(__le32) )
#define RXINFO_DESC_SIZE ( 1 * sizeof(__le32) )
+#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) )
+#define RXD_DESC_SIZE ( 1 * sizeof(__le32) )
/*
* TX Info structure
@@ -101,6 +103,54 @@
#define TXINFO_W0_USB_DMA_TX_BURST FIELD32(0x80000000)
/*
+ * RX Info structure
+ */
+
+/*
+ * Word 0
+ */
+
+#define RXINFO_W0_USB_DMA_RX_PKT_LEN FIELD32(0x0000ffff)
+
+/*
+ * RX WI structure
+ */
+
+/*
+ * Word0
+ */
+#define RXWI_W0_WIRELESS_CLI_ID FIELD32(0x000000ff)
+#define RXWI_W0_KEY_INDEX FIELD32(0x00000300)
+#define RXWI_W0_BSSID FIELD32(0x00001c00)
+#define RXWI_W0_UDF FIELD32(0x0000e000)
+#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000)
+#define RXWI_W0_TID FIELD32(0xf0000000)
+
+/*
+ * Word1
+ */
+#define RXWI_W1_FRAG FIELD32(0x0000000f)
+#define RXWI_W1_SEQUENCE FIELD32(0x0000fff0)
+#define RXWI_W1_MCS FIELD32(0x007f0000)
+#define RXWI_W1_BW FIELD32(0x00800000)
+#define RXWI_W1_SHORT_GI FIELD32(0x01000000)
+#define RXWI_W1_STBC FIELD32(0x06000000)
+#define RXWI_W1_PHYMODE FIELD32(0xc0000000)
+
+/*
+ * Word2
+ */
+#define RXWI_W2_RSSI0 FIELD32(0x000000ff)
+#define RXWI_W2_RSSI1 FIELD32(0x0000ff00)
+#define RXWI_W2_RSSI2 FIELD32(0x00ff0000)
+
+/*
+ * Word3
+ */
+#define RXWI_W3_SNR0 FIELD32(0x000000ff)
+#define RXWI_W3_SNR1 FIELD32(0x0000ff00)
+
+/*
* RX descriptor format for RX Ring.
*/
@@ -115,25 +165,25 @@
* AMSDU: rx with 802.3 header, not 802.11 header.
*/
-#define RXINFO_W0_BA FIELD32(0x00000001)
-#define RXINFO_W0_DATA FIELD32(0x00000002)
-#define RXINFO_W0_NULLDATA FIELD32(0x00000004)
-#define RXINFO_W0_FRAG FIELD32(0x00000008)
-#define RXINFO_W0_UNICAST_TO_ME FIELD32(0x00000010)
-#define RXINFO_W0_MULTICAST FIELD32(0x00000020)
-#define RXINFO_W0_BROADCAST FIELD32(0x00000040)
-#define RXINFO_W0_MY_BSS FIELD32(0x00000080)
-#define RXINFO_W0_CRC_ERROR FIELD32(0x00000100)
-#define RXINFO_W0_CIPHER_ERROR FIELD32(0x00000600)
-#define RXINFO_W0_AMSDU FIELD32(0x00000800)
-#define RXINFO_W0_HTC FIELD32(0x00001000)
-#define RXINFO_W0_RSSI FIELD32(0x00002000)
-#define RXINFO_W0_L2PAD FIELD32(0x00004000)
-#define RXINFO_W0_AMPDU FIELD32(0x00008000)
-#define RXINFO_W0_DECRYPTED FIELD32(0x00010000)
-#define RXINFO_W0_PLCP_RSSI FIELD32(0x00020000)
-#define RXINFO_W0_CIPHER_ALG FIELD32(0x00040000)
-#define RXINFO_W0_LAST_AMSDU FIELD32(0x00080000)
-#define RXINFO_W0_PLCP_SIGNAL FIELD32(0xfff00000)
+#define RXD_W0_BA FIELD32(0x00000001)
+#define RXD_W0_DATA FIELD32(0x00000002)
+#define RXD_W0_NULLDATA FIELD32(0x00000004)
+#define RXD_W0_FRAG FIELD32(0x00000008)
+#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000010)
+#define RXD_W0_MULTICAST FIELD32(0x00000020)
+#define RXD_W0_BROADCAST FIELD32(0x00000040)
+#define RXD_W0_MY_BSS FIELD32(0x00000080)
+#define RXD_W0_CRC_ERROR FIELD32(0x00000100)
+#define RXD_W0_CIPHER_ERROR FIELD32(0x00000600)
+#define RXD_W0_AMSDU FIELD32(0x00000800)
+#define RXD_W0_HTC FIELD32(0x00001000)
+#define RXD_W0_RSSI FIELD32(0x00002000)
+#define RXD_W0_L2PAD FIELD32(0x00004000)
+#define RXD_W0_AMPDU FIELD32(0x00008000)
+#define RXD_W0_DECRYPTED FIELD32(0x00010000)
+#define RXD_W0_PLCP_RSSI FIELD32(0x00020000)
+#define RXD_W0_CIPHER_ALG FIELD32(0x00040000)
+#define RXD_W0_LAST_AMSDU FIELD32(0x00080000)
+#define RXD_W0_PLCP_SIGNAL FIELD32(0xfff00000)
#endif /* RT2800USB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index dcfc8c25d1a7..d9daa9c406fa 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -104,6 +104,12 @@
#define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate))
/*
+ * Determine the number of L2 padding bytes required between the header and
+ * the payload.
+ */
+#define L2PAD_SIZE(__hdrlen) (-(__hdrlen) & 3)
+
+/*
* Determine the alignment requirement,
* to make sure the 802.11 payload is padded to a 4-byte boundrary
* we must determine the address of the payload and calculate the
@@ -154,6 +160,7 @@ struct avg_val {
enum rt2x00_chip_intf {
RT2X00_CHIP_INTF_PCI,
RT2X00_CHIP_INTF_USB,
+ RT2X00_CHIP_INTF_SOC,
};
/*
@@ -163,25 +170,26 @@ enum rt2x00_chip_intf {
*/
struct rt2x00_chip {
u16 rt;
-#define RT2460 0x0101
-#define RT2560 0x0201
-#define RT2570 0x1201
-#define RT2561s 0x0301 /* Turbo */
-#define RT2561 0x0302
-#define RT2661 0x0401
-#define RT2571 0x1300
-#define RT2860 0x0601 /* 2.4GHz PCI/CB */
-#define RT2860D 0x0681 /* 2.4GHz, 5GHz PCI/CB */
-#define RT2890 0x0701 /* 2.4GHz PCIe */
-#define RT2890D 0x0781 /* 2.4GHz, 5GHz PCIe */
+#define RT2460 0x2460
+#define RT2560 0x2560
+#define RT2570 0x2570
+#define RT2661 0x2661
+#define RT2573 0x2573
+#define RT2860 0x2860 /* 2.4GHz PCI/CB */
+#define RT2870 0x2870
+#define RT2872 0x2872
#define RT2880 0x2880 /* WSOC */
+#define RT2883 0x2883 /* WSOC */
+#define RT2890 0x2890 /* 2.4GHz PCIe */
#define RT3052 0x3052 /* WSOC */
+#define RT3070 0x3070
+#define RT3071 0x3071
#define RT3090 0x3090 /* 2.4GHz PCIe */
-#define RT2870 0x1600
-#define RT3070 0x1800
+#define RT3390 0x3390
+#define RT3572 0x3572
u16 rf;
- u32 rev;
+ u16 rev;
enum rt2x00_chip_intf intf;
};
@@ -911,51 +919,30 @@ static inline void rt2x00_eeprom_write(struct rt2x00_dev *rt2x00dev,
* Chipset handlers
*/
static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev,
- const u16 rt, const u16 rf, const u32 rev)
+ const u16 rt, const u16 rf, const u16 rev)
{
rt2x00dev->chip.rt = rt;
rt2x00dev->chip.rf = rf;
rt2x00dev->chip.rev = rev;
-}
-
-static inline void rt2x00_set_chip_rt(struct rt2x00_dev *rt2x00dev,
- const u16 rt)
-{
- rt2x00dev->chip.rt = rt;
-}
-
-static inline void rt2x00_set_chip_rf(struct rt2x00_dev *rt2x00dev,
- const u16 rf, const u32 rev)
-{
- rt2x00_set_chip(rt2x00dev, rt2x00dev->chip.rt, rf, rev);
-}
-static inline void rt2x00_print_chip(struct rt2x00_dev *rt2x00dev)
-{
INFO(rt2x00dev,
- "Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n",
+ "Chipset detected - rt: %04x, rf: %04x, rev: %04x.\n",
rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev);
}
-static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip)
+static inline char rt2x00_rt(struct rt2x00_dev *rt2x00dev, const u16 rt)
{
- return (chipset->rt == chip);
+ return (rt2x00dev->chip.rt == rt);
}
-static inline char rt2x00_rf(const struct rt2x00_chip *chipset, const u16 chip)
+static inline char rt2x00_rf(struct rt2x00_dev *rt2x00dev, const u16 rf)
{
- return (chipset->rf == chip);
+ return (rt2x00dev->chip.rf == rf);
}
-static inline u32 rt2x00_rev(const struct rt2x00_chip *chipset)
+static inline u16 rt2x00_rev(struct rt2x00_dev *rt2x00dev)
{
- return chipset->rev;
-}
-
-static inline bool rt2x00_check_rev(const struct rt2x00_chip *chipset,
- const u32 mask, const u32 rev)
-{
- return ((chipset->rev & mask) == rev);
+ return rt2x00dev->chip.rev;
}
static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev,
@@ -964,20 +951,25 @@ static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev,
rt2x00dev->chip.intf = intf;
}
-static inline bool rt2x00_intf(const struct rt2x00_chip *chipset,
+static inline bool rt2x00_intf(struct rt2x00_dev *rt2x00dev,
enum rt2x00_chip_intf intf)
{
- return (chipset->intf == intf);
+ return (rt2x00dev->chip.intf == intf);
+}
+
+static inline bool rt2x00_is_pci(struct rt2x00_dev *rt2x00dev)
+{
+ return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
}
-static inline bool rt2x00_intf_is_pci(struct rt2x00_dev *rt2x00dev)
+static inline bool rt2x00_is_usb(struct rt2x00_dev *rt2x00dev)
{
- return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_PCI);
+ return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
}
-static inline bool rt2x00_intf_is_usb(struct rt2x00_dev *rt2x00dev)
+static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev)
{
- return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_USB);
+ return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC);
}
/**
@@ -1019,9 +1011,9 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
int rt2x00mac_start(struct ieee80211_hw *hw);
void rt2x00mac_stop(struct ieee80211_hw *hw);
int rt2x00mac_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf);
+ struct ieee80211_vif *vif);
void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf);
+ struct ieee80211_vif *vif);
int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed);
void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
@@ -1038,8 +1030,6 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
#endif /* CONFIG_RT2X00_LIB_CRYPTO */
int rt2x00mac_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats);
-int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *stats);
void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 7d323a763b54..28a1c46ec4eb 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -109,7 +109,7 @@ struct rt2x00debug_intf {
/*
* HW crypto statistics.
- * All statistics are stored seperately per cipher type.
+ * All statistics are stored separately per cipher type.
*/
struct rt2x00debug_crypto crypto_stats[CIPHER_MAX];
@@ -184,7 +184,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
dump_hdr->data_length = cpu_to_le32(skb->len);
dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);
dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
- dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev);
+ dump_hdr->chip_rev = cpu_to_le16(rt2x00dev->chip.rev);
dump_hdr->type = cpu_to_le16(type);
dump_hdr->queue_index = desc->entry->queue->qid;
dump_hdr->entry_index = desc->entry->entry_idx;
@@ -573,7 +573,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name,
blob->data = data;
data += sprintf(data, "rt chip:\t%04x\n", intf->rt2x00dev->chip.rt);
data += sprintf(data, "rf chip:\t%04x\n", intf->rt2x00dev->chip.rf);
- data += sprintf(data, "revision:\t%08x\n", intf->rt2x00dev->chip.rev);
+ data += sprintf(data, "revision:\t%04x\n", intf->rt2x00dev->chip.rev);
data += sprintf(data, "\n");
data += sprintf(data, "register\tbase\twords\twordsize\n");
data += sprintf(data, "csr\t%d\t%d\t%d\n",
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 265e66dba552..dd5ab8fe2321 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -385,9 +385,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
memset(&rxdesc, 0, sizeof(rxdesc));
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
- /* Trim buffer to correct size */
- skb_trim(entry->skb, rxdesc.size);
-
/*
* The data behind the ieee80211 header must be
* aligned on a 4 byte boundary.
@@ -397,18 +394,23 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
/*
* Hardware might have stripped the IV/EIV/ICV data,
* in that case it is possible that the data was
- * provided seperately (through hardware descriptor)
+ * provided separately (through hardware descriptor)
* in which case we should reinsert the data into the frame.
*/
if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) &&
(rxdesc.flags & RX_FLAG_IV_STRIPPED))
rt2x00crypto_rx_insert_iv(entry->skb, header_length,
&rxdesc);
- else if (rxdesc.dev_flags & RXDONE_L2PAD)
+ else if (header_length &&
+ (rxdesc.size > header_length) &&
+ (rxdesc.dev_flags & RXDONE_L2PAD))
rt2x00queue_remove_l2pad(entry->skb, header_length);
else
rt2x00queue_align_payload(entry->skb, header_length);
+ /* Trim buffer to correct size */
+ skb_trim(entry->skb, rxdesc.size);
+
/*
* Check if the frame was received using HT. In that case,
* the rate is the MCS index and should be passed to mac80211
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index de549c244ed8..abbd857ec759 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -187,10 +187,10 @@ void rt2x00mac_stop(struct ieee80211_hw *hw)
EXPORT_SYMBOL_GPL(rt2x00mac_stop);
int rt2x00mac_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct rt2x00_intf *intf = vif_to_intf(conf->vif);
+ struct rt2x00_intf *intf = vif_to_intf(vif);
struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON);
struct queue_entry *entry = NULL;
unsigned int i;
@@ -203,7 +203,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
return -ENODEV;
- switch (conf->type) {
+ switch (vif->type) {
case NL80211_IFTYPE_AP:
/*
* We don't support mixed combinations of
@@ -263,7 +263,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
* increase interface count and start initialization.
*/
- if (conf->type == NL80211_IFTYPE_AP)
+ if (vif->type == NL80211_IFTYPE_AP)
rt2x00dev->intf_ap_count++;
else
rt2x00dev->intf_sta_count++;
@@ -273,16 +273,16 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
mutex_init(&intf->beacon_skb_mutex);
intf->beacon = entry;
- if (conf->type == NL80211_IFTYPE_AP)
- memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
- memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
+ if (vif->type == NL80211_IFTYPE_AP)
+ memcpy(&intf->bssid, vif->addr, ETH_ALEN);
+ memcpy(&intf->mac, vif->addr, ETH_ALEN);
/*
* The MAC adddress must be configured after the device
* has been initialized. Otherwise the device can reset
* the MAC registers.
*/
- rt2x00lib_config_intf(rt2x00dev, intf, conf->type, intf->mac, NULL);
+ rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, NULL);
/*
* Some filters depend on the current working mode. We can force
@@ -296,10 +296,10 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
EXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct rt2x00_intf *intf = vif_to_intf(conf->vif);
+ struct rt2x00_intf *intf = vif_to_intf(vif);
/*
* Don't allow interfaces to be remove while
@@ -307,11 +307,11 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
* no interface is present.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
- (conf->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) ||
- (conf->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count))
+ (vif->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) ||
+ (vif->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count))
return;
- if (conf->type == NL80211_IFTYPE_AP)
+ if (vif->type == NL80211_IFTYPE_AP)
rt2x00dev->intf_ap_count--;
else
rt2x00dev->intf_sta_count--;
@@ -555,22 +555,6 @@ int rt2x00mac_get_stats(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(rt2x00mac_get_stats);
-int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
- unsigned int i;
-
- for (i = 0; i < rt2x00dev->ops->tx_queues; i++) {
- stats[i].len = rt2x00dev->tx[i].length;
- stats[i].limit = rt2x00dev->tx[i].limit;
- stats[i].count = rt2x00dev->tx[i].count;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats);
-
void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 0feb4d0e4668..047123b766fc 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -41,6 +41,9 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
{
unsigned int i;
+ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+ return 0;
+
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2x00pci_register_read(rt2x00dev, offset, reg);
if (!rt2x00_get_field32(*reg, field))
@@ -269,7 +272,6 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
int retval;
- u16 chip;
retval = pci_request_regions(pci_dev, pci_name(pci_dev));
if (retval) {
@@ -312,12 +314,6 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
- /*
- * Determine RT chipset by reading PCI header.
- */
- pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip);
- rt2x00_set_chip_rt(rt2x00dev, chip);
-
retval = rt2x00pci_alloc_reg(rt2x00dev);
if (retval)
goto exit_free_device;
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index d4f9449ab0a4..8149ff68410a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -27,6 +27,7 @@
#define RT2X00PCI_H
#include <linux/io.h>
+#include <linux/pci.h>
/*
* This variable should be used with the
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 9915a09141ef..5b6b789cad3d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -177,55 +177,45 @@ void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length)
void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
{
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- unsigned int frame_length = skb->len;
+ unsigned int payload_length = skb->len - header_length;
unsigned int header_align = ALIGN_SIZE(skb, 0);
unsigned int payload_align = ALIGN_SIZE(skb, header_length);
- unsigned int l2pad = 4 - (payload_align - header_align);
+ unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0;
- if (header_align == payload_align) {
- /*
- * Both header and payload must be moved the same
- * amount of bytes to align them properly. This means
- * we don't use the L2 padding but just move the entire
- * frame.
- */
- rt2x00queue_align_frame(skb);
- } else if (!payload_align) {
- /*
- * Simple L2 padding, only the header needs to be moved,
- * the payload is already properly aligned.
- */
- skb_push(skb, header_align);
- memmove(skb->data, skb->data + header_align, frame_length);
- skbdesc->flags |= SKBDESC_L2_PADDED;
- } else {
- /*
- *
- * Complicated L2 padding, both header and payload need
- * to be moved. By default we only move to the start
- * of the buffer, so our header alignment needs to be
- * increased if there is not enough room for the header
- * to be moved.
- */
- if (payload_align > header_align)
- header_align += 4;
+ /*
+ * Adjust the header alignment if the payload needs to be moved more
+ * than the header.
+ */
+ if (payload_align > header_align)
+ header_align += 4;
+
+ /* There is nothing to do if no alignment is needed */
+ if (!header_align)
+ return;
+
+ /* Reserve the amount of space needed in front of the frame */
+ skb_push(skb, header_align);
+
+ /*
+ * Move the header.
+ */
+ memmove(skb->data, skb->data + header_align, header_length);
- skb_push(skb, header_align);
- memmove(skb->data, skb->data + header_align, header_length);
+ /* Move the payload, if present and if required */
+ if (payload_length && payload_align)
memmove(skb->data + header_length + l2pad,
skb->data + header_length + l2pad + payload_align,
- frame_length - header_length);
- skbdesc->flags |= SKBDESC_L2_PADDED;
- }
+ payload_length);
+
+ /* Trim the skb to the correct size */
+ skb_trim(skb, header_length + l2pad + payload_length);
}
void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
{
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- unsigned int l2pad = 4 - (header_length & 3);
+ unsigned int l2pad = L2PAD_SIZE(header_length);
- if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED))
+ if (!l2pad)
return;
memmove(skb->data + l2pad, skb->data, header_length);
@@ -346,7 +336,9 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
* Header and alignment information.
*/
txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
- txdesc->l2pad = ALIGN_SIZE(entry->skb, txdesc->header_length);
+ if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags) &&
+ (entry->skb->len > txdesc->header_length))
+ txdesc->l2pad = L2PAD_SIZE(txdesc->header_length);
/*
* Check whether this frame is to be acked.
@@ -387,10 +379,13 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
/*
* Beacons and probe responses require the tsf timestamp
- * to be inserted into the frame.
+ * to be inserted into the frame, except for a frame that has been injected
+ * through a monitor interface. This latter is needed for testing a
+ * monitor interface.
*/
- if (ieee80211_is_beacon(hdr->frame_control) ||
- ieee80211_is_probe_resp(hdr->frame_control))
+ if ((ieee80211_is_beacon(hdr->frame_control) ||
+ ieee80211_is_probe_resp(hdr->frame_control)) &&
+ (!(tx_info->flags & IEEE80211_TX_CTL_INJECTED)))
__set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags);
/*
@@ -502,7 +497,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
/*
* When hardware encryption is supported, and this frame
* is to be encrypted, we should strip the IV/EIV data from
- * the frame so we can provide it to the driver seperately.
+ * the frame so we can provide it to the driver separately.
*/
if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
!test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) {
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 70775e5ba1ac..c1e482bb37b3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -92,8 +92,6 @@ enum data_queue_qid {
* @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX
* @SKBDESC_IV_STRIPPED: Frame contained a IV/EIV provided by
* mac80211 but was stripped for processing by the driver.
- * @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment,
- * the padded bytes are located between header and payload.
* @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211,
* don't try to pass it back.
*/
@@ -101,8 +99,7 @@ enum skb_frame_desc_flags {
SKBDESC_DMA_MAPPED_RX = 1 << 0,
SKBDESC_DMA_MAPPED_TX = 1 << 1,
SKBDESC_IV_STRIPPED = 1 << 2,
- SKBDESC_L2_PADDED = 1 << 3,
- SKBDESC_NOT_MAC80211 = 1 << 4,
+ SKBDESC_NOT_MAC80211 = 1 << 3,
};
/**
diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c
index 19e684f8ffa1..111c0ff5c6c7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00soc.c
+++ b/drivers/net/wireless/rt2x00/rt2x00soc.c
@@ -71,9 +71,7 @@ exit:
return -ENOMEM;
}
-int rt2x00soc_probe(struct platform_device *pdev,
- const unsigned short chipset,
- const struct rt2x00_ops *ops)
+int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops)
{
struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
@@ -94,12 +92,7 @@ int rt2x00soc_probe(struct platform_device *pdev,
rt2x00dev->irq = platform_get_irq(pdev, 0);
rt2x00dev->name = pdev->dev.driver->name;
- /*
- * SoC devices mimic PCI behavior.
- */
- rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
-
- rt2x00_set_chip_rt(rt2x00dev, chipset);
+ rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC);
retval = rt2x00soc_alloc_reg(rt2x00dev);
if (retval)
@@ -119,6 +112,7 @@ exit_free_device:
return retval;
}
+EXPORT_SYMBOL_GPL(rt2x00soc_probe);
int rt2x00soc_remove(struct platform_device *pdev)
{
diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.h b/drivers/net/wireless/rt2x00/rt2x00soc.h
index 8a3416624af5..474cbfc1efc7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00soc.h
+++ b/drivers/net/wireless/rt2x00/rt2x00soc.h
@@ -26,20 +26,10 @@
#ifndef RT2X00SOC_H
#define RT2X00SOC_H
-#define KSEG1ADDR(__ptr) __ptr
-
-#define __rt2x00soc_probe(__chipset, __ops) \
-static int __rt2x00soc_probe(struct platform_device *pdev) \
-{ \
- return rt2x00soc_probe(pdev, (__chipset), (__ops)); \
-}
-
/*
* SoC driver handlers.
*/
-int rt2x00soc_probe(struct platform_device *pdev,
- const unsigned short chipset,
- const struct rt2x00_ops *ops);
+int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops);
int rt2x00soc_remove(struct platform_device *pdev);
#ifdef CONFIG_PM
int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 0ca589306d71..177472742172 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -476,7 +476,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
* The driver does not support the IV/EIV generation
* in hardware. However it doesn't support the IV/EIV
* inside the ieee80211 frame either, but requires it
- * to be provided seperately for the descriptor.
+ * to be provided separately for the descriptor.
* rt2x00lib will cut the IV/EIV data out of all frames
* given to us by mac80211, but we must tell mac80211
* to generate the IV/EIV data.
@@ -637,8 +637,7 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
rt61pci_bbp_read(rt2x00dev, 4, &r4);
rt61pci_bbp_read(rt2x00dev, 77, &r77);
- rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
- rt2x00_rf(&rt2x00dev->chip, RF5325));
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF5325));
/*
* Configure the RX antenna.
@@ -684,8 +683,7 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
rt61pci_bbp_read(rt2x00dev, 4, &r4);
rt61pci_bbp_read(rt2x00dev, 77, &r77);
- rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
- rt2x00_rf(&rt2x00dev->chip, RF2529));
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529));
rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
!test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
@@ -833,12 +831,11 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg);
- if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
- rt2x00_rf(&rt2x00dev->chip, RF5325))
+ if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325))
rt61pci_config_antenna_5x(rt2x00dev, ant);
- else if (rt2x00_rf(&rt2x00dev->chip, RF2527))
+ else if (rt2x00_rf(rt2x00dev, RF2527))
rt61pci_config_antenna_2x(rt2x00dev, ant);
- else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) {
+ else if (rt2x00_rf(rt2x00dev, RF2529)) {
if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags))
rt61pci_config_antenna_2x(rt2x00dev, ant);
else
@@ -879,8 +876,7 @@ static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
- smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
- rt2x00_rf(&rt2x00dev->chip, RF2527));
+ smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527));
rt61pci_bbp_read(rt2x00dev, 3, &r3);
rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
@@ -1135,16 +1131,18 @@ dynamic_cca_tune:
*/
static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
{
+ u16 chip;
char *fw_name;
- switch (rt2x00dev->chip.rt) {
- case RT2561:
+ pci_read_config_word(to_pci_dev(rt2x00dev->dev), PCI_DEVICE_ID, &chip);
+ switch (chip) {
+ case RT2561_PCI_ID:
fw_name = FIRMWARE_RT2561;
break;
- case RT2561s:
+ case RT2561s_PCI_ID:
fw_name = FIRMWARE_RT2561s;
break;
- case RT2661:
+ case RT2661_PCI_ID:
fw_name = FIRMWARE_RT2661;
break;
default:
@@ -2299,13 +2297,13 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
- rt2x00_set_chip_rf(rt2x00dev, value, reg);
- rt2x00_print_chip(rt2x00dev);
+ rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
+ value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
- if (!rt2x00_rf(&rt2x00dev->chip, RF5225) &&
- !rt2x00_rf(&rt2x00dev->chip, RF5325) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2527) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2529)) {
+ if (!rt2x00_rf(rt2x00dev, RF5225) &&
+ !rt2x00_rf(rt2x00dev, RF5325) &&
+ !rt2x00_rf(rt2x00dev, RF2527) &&
+ !rt2x00_rf(rt2x00dev, RF2529)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
@@ -2360,7 +2358,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* the antenna settings should be gathered from the NIC
* eeprom word.
*/
- if (rt2x00_rf(&rt2x00dev->chip, RF2529) &&
+ if (rt2x00_rf(rt2x00dev, RF2529) &&
!test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) {
rt2x00dev->default_ant.rx =
ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED);
@@ -2571,8 +2569,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->channels = rf_vals_seq;
}
- if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
- rt2x00_rf(&rt2x00dev->chip, RF5325)) {
+ if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_seq);
}
@@ -2735,7 +2732,6 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt61pci_conf_tx,
- .get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt61pci_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
};
@@ -2812,7 +2808,7 @@ static const struct rt2x00_ops rt61pci_ops = {
/*
* RT61pci module information.
*/
-static struct pci_device_id rt61pci_device_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(rt61pci_device_table) = {
/* RT2561s */
{ PCI_DEVICE(0x1814, 0x0301), PCI_DEVICE_DATA(&rt61pci_ops) },
/* RT2561 v2 */
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 8f13810622bd..df80f1af22a4 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -28,6 +28,13 @@
#define RT61PCI_H
/*
+ * RT chip PCI IDs.
+ */
+#define RT2561s_PCI_ID 0x0301
+#define RT2561_PCI_ID 0x0302
+#define RT2661_PCI_ID 0x0401
+
+/*
* RF chip defines.
*/
#define RF5225 0x0001
@@ -225,6 +232,8 @@ struct hw_pairwise_ta_entry {
* MAC_CSR0: ASIC revision number.
*/
#define MAC_CSR0 0x3000
+#define MAC_CSR0_REVISION FIELD32(0x0000000f)
+#define MAC_CSR0_CHIPSET FIELD32(0x000ffff0)
/*
* MAC_CSR1: System control register.
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index ced3b6ab5e16..290d70bc5d22 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -136,8 +136,8 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
* all others contain 20 bits.
*/
rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
- 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
- rt2x00_rf(&rt2x00dev->chip, RF2527)));
+ 20 + (rt2x00_rf(rt2x00dev, RF5225) ||
+ rt2x00_rf(rt2x00dev, RF2527)));
rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
@@ -339,7 +339,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
* The driver does not support the IV/EIV generation
* in hardware. However it doesn't support the IV/EIV
* inside the ieee80211 frame either, but requires it
- * to be provided seperately for the descriptor.
+ * to be provided separately for the descriptor.
* rt2x00lib will cut the IV/EIV data out of all frames
* given to us by mac80211, but we must tell mac80211
* to generate the IV/EIV data.
@@ -439,7 +439,7 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
* The driver does not support the IV/EIV generation
* in hardware. However it doesn't support the IV/EIV
* inside the ieee80211 frame either, but requires it
- * to be provided seperately for the descriptor.
+ * to be provided separately for the descriptor.
* rt2x00lib will cut the IV/EIV data out of all frames
* given to us by mac80211, but we must tell mac80211
* to generate the IV/EIV data.
@@ -741,11 +741,9 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev,
rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg);
- if (rt2x00_rf(&rt2x00dev->chip, RF5226) ||
- rt2x00_rf(&rt2x00dev->chip, RF5225))
+ if (rt2x00_rf(rt2x00dev, RF5226) || rt2x00_rf(rt2x00dev, RF5225))
rt73usb_config_antenna_5x(rt2x00dev, ant);
- else if (rt2x00_rf(&rt2x00dev->chip, RF2528) ||
- rt2x00_rf(&rt2x00dev->chip, RF2527))
+ else if (rt2x00_rf(rt2x00dev, RF2528) || rt2x00_rf(rt2x00dev, RF2527))
rt73usb_config_antenna_2x(rt2x00dev, ant);
}
@@ -779,8 +777,7 @@ static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
- smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
- rt2x00_rf(&rt2x00dev->chip, RF2527));
+ smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527));
rt73usb_bbp_read(rt2x00dev, 3, &r3);
rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
@@ -1210,8 +1207,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
reg = 0x000023b0;
- if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
- rt2x00_rf(&rt2x00dev->chip, RF2527))
+ if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527))
rt2x00_set_field32(&reg, PHY_CSR1_RF_RPI, 1);
rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg);
@@ -1665,7 +1661,7 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
/*
* Hardware has stripped IV/EIV data from 802.11 frame during
- * decryption. It has provided the data seperately but rt2x00lib
+ * decryption. It has provided the data separately but rt2x00lib
* should decide if it should be reinserted.
*/
rxdesc->flags |= RX_FLAG_IV_STRIPPED;
@@ -1824,19 +1820,18 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00usb_register_read(rt2x00dev, MAC_CSR0, &reg);
- rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
- rt2x00_print_chip(rt2x00dev);
+ rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
+ value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
- if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) ||
- rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {
+ if (!rt2x00_rt(rt2x00dev, RT2573) || (rt2x00_rev(rt2x00dev) == 0)) {
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
return -ENODEV;
}
- if (!rt2x00_rf(&rt2x00dev->chip, RF5226) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2528) &&
- !rt2x00_rf(&rt2x00dev->chip, RF5225) &&
- !rt2x00_rf(&rt2x00dev->chip, RF2527)) {
+ if (!rt2x00_rf(rt2x00dev, RF5226) &&
+ !rt2x00_rf(rt2x00dev, RF2528) &&
+ !rt2x00_rf(rt2x00dev, RF5225) &&
+ !rt2x00_rf(rt2x00dev, RF2527)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
@@ -2081,17 +2076,17 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
- if (rt2x00_rf(&rt2x00dev->chip, RF2528)) {
+ if (rt2x00_rf(rt2x00dev, RF2528)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528);
spec->channels = rf_vals_bg_2528;
- } else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) {
+ } else if (rt2x00_rf(rt2x00dev, RF5226)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_5226);
spec->channels = rf_vals_5226;
- } else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) {
+ } else if (rt2x00_rf(rt2x00dev, RF2527)) {
spec->num_channels = 14;
spec->channels = rf_vals_5225_2527;
- } else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) {
+ } else if (rt2x00_rf(rt2x00dev, RF5225)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527);
spec->channels = rf_vals_5225_2527;
@@ -2249,7 +2244,6 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt73usb_conf_tx,
- .get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt73usb_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
};
@@ -2354,9 +2348,12 @@ static struct usb_device_id rt73usb_device_table[] = {
{ USB_DEVICE(0x08dd, 0x0120), USB_DEVICE_DATA(&rt73usb_ops) },
/* Buffalo */
{ USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0411, 0x00d9), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* CEIVA */
+ { USB_DEVICE(0x178d, 0x02be), USB_DEVICE_DATA(&rt73usb_ops) },
/* CNet */
{ USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) },
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 7942f810e928..7abe7eb14555 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -142,6 +142,8 @@ struct hw_pairwise_ta_entry {
* MAC_CSR0: ASIC revision number.
*/
#define MAC_CSR0 0x3000
+#define MAC_CSR0_REVISION FIELD32(0x0000000f)
+#define MAC_CSR0_CHIPSET FIELD32(0x000ffff0)
/*
* MAC_CSR1: System control register.
diff --git a/drivers/net/wireless/rtl818x/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180.h
index 8721282a8185..de3844fe06d8 100644
--- a/drivers/net/wireless/rtl818x/rtl8180.h
+++ b/drivers/net/wireless/rtl818x/rtl8180.h
@@ -60,7 +60,6 @@ struct rtl8180_priv {
struct rtl818x_csr __iomem *map;
const struct rtl818x_rf_ops *rf;
struct ieee80211_vif *vif;
- int mode;
/* rtl8180 driver specific */
spinlock_t lock;
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index 8a40a1439984..2b928ecf47bd 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -33,7 +33,7 @@ MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
MODULE_DESCRIPTION("RTL8180 / RTL8185 PCI wireless driver");
MODULE_LICENSE("GPL");
-static struct pci_device_id rtl8180_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(rtl8180_table) = {
/* rtl8185 */
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) },
{ PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x700f) },
@@ -82,8 +82,6 @@ static const struct ieee80211_channel rtl818x_channels[] = {
};
-
-
void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
{
struct rtl8180_priv *priv = dev->priv;
@@ -615,7 +613,6 @@ static int rtl8180_start(struct ieee80211_hw *dev)
reg |= RTL818X_CMD_TX_ENABLE;
rtl818x_iowrite8(priv, &priv->map->CMD, reg);
- priv->mode = NL80211_IFTYPE_MONITOR;
return 0;
err_free_rings:
@@ -633,8 +630,6 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
u8 reg;
int i;
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
-
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
reg = rtl818x_ioread8(priv, &priv->map->CMD);
@@ -657,38 +652,39 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
}
static int rtl8180_add_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct rtl8180_priv *priv = dev->priv;
- if (priv->mode != NL80211_IFTYPE_MONITOR)
- return -EOPNOTSUPP;
+ /*
+ * We only support one active interface at a time.
+ */
+ if (priv->vif)
+ return -EBUSY;
- switch (conf->type) {
+ switch (vif->type) {
case NL80211_IFTYPE_STATION:
- priv->mode = conf->type;
break;
default:
return -EOPNOTSUPP;
}
- priv->vif = conf->vif;
+ priv->vif = vif;
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0],
- le32_to_cpu(*(__le32 *)conf->mac_addr));
+ le32_to_cpu(*(__le32 *)vif->addr));
rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4],
- le16_to_cpu(*(__le16 *)(conf->mac_addr + 4)));
+ le16_to_cpu(*(__le16 *)(vif->addr + 4)));
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
return 0;
}
static void rtl8180_remove_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct rtl8180_priv *priv = dev->priv;
- priv->mode = NL80211_IFTYPE_MONITOR;
priv->vif = NULL;
}
@@ -765,6 +761,14 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev,
rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf);
}
+static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
+{
+ struct rtl8180_priv *priv = dev->priv;
+
+ return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
+ (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
+}
+
static const struct ieee80211_ops rtl8180_ops = {
.tx = rtl8180_tx,
.start = rtl8180_start,
@@ -775,6 +779,7 @@ static const struct ieee80211_ops rtl8180_ops = {
.bss_info_changed = rtl8180_bss_info_changed,
.prepare_multicast = rtl8180_prepare_multicast,
.configure_filter = rtl8180_configure_filter,
+ .get_tsf = rtl8180_get_tsf,
};
static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom)
diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h
index 6af0f3f71f3a..6bb32112e65c 100644
--- a/drivers/net/wireless/rtl818x/rtl8187.h
+++ b/drivers/net/wireless/rtl818x/rtl8187.h
@@ -92,7 +92,7 @@ struct rtl8187_priv {
struct rtl818x_csr *map;
const struct rtl818x_rf_ops *rf;
struct ieee80211_vif *vif;
- int mode;
+
/* The mutex protects the TX loopback state.
* Any attempt to set channels concurrently locks the device.
*/
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index bc5726dd5fe4..0fb850e0c656 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -65,6 +65,7 @@ static struct usb_device_id rtl8187_table[] __devinitdata = {
/* Sitecom */
{USB_DEVICE(0x0df6, 0x000d), .driver_info = DEVICE_RTL8187},
{USB_DEVICE(0x0df6, 0x0028), .driver_info = DEVICE_RTL8187B},
+ {USB_DEVICE(0x0df6, 0x0029), .driver_info = DEVICE_RTL8187B},
/* Sphairon Access Systems GmbH */
{USB_DEVICE(0x114B, 0x0150), .driver_info = DEVICE_RTL8187},
/* Dick Smith Electronics */
@@ -1018,31 +1019,30 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
}
static int rtl8187_add_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct rtl8187_priv *priv = dev->priv;
int i;
int ret = -EOPNOTSUPP;
mutex_lock(&priv->conf_mutex);
- if (priv->mode != NL80211_IFTYPE_MONITOR)
+ if (priv->vif)
goto exit;
- switch (conf->type) {
+ switch (vif->type) {
case NL80211_IFTYPE_STATION:
- priv->mode = conf->type;
break;
default:
goto exit;
}
ret = 0;
- priv->vif = conf->vif;
+ priv->vif = vif;
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
for (i = 0; i < ETH_ALEN; i++)
rtl818x_iowrite8(priv, &priv->map->MAC[i],
- ((u8 *)conf->mac_addr)[i]);
+ ((u8 *)vif->addr)[i]);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
exit:
@@ -1051,11 +1051,10 @@ exit:
}
static void rtl8187_remove_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct rtl8187_priv *priv = dev->priv;
mutex_lock(&priv->conf_mutex);
- priv->mode = NL80211_IFTYPE_MONITOR;
priv->vif = NULL;
mutex_unlock(&priv->conf_mutex);
}
@@ -1267,6 +1266,14 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue,
return 0;
}
+static u64 rtl8187_get_tsf(struct ieee80211_hw *dev)
+{
+ struct rtl8187_priv *priv = dev->priv;
+
+ return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
+ (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
+}
+
static const struct ieee80211_ops rtl8187_ops = {
.tx = rtl8187_tx,
.start = rtl8187_start,
@@ -1278,7 +1285,8 @@ static const struct ieee80211_ops rtl8187_ops = {
.prepare_multicast = rtl8187_prepare_multicast,
.configure_filter = rtl8187_configure_filter,
.conf_tx = rtl8187_conf_tx,
- .rfkill_poll = rtl8187_rfkill_poll
+ .rfkill_poll = rtl8187_rfkill_poll,
+ .get_tsf = rtl8187_get_tsf,
};
static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -1365,7 +1373,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
- priv->mode = NL80211_IFTYPE_MONITOR;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_RX_INCLUDES_FCS;
diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c
index ded44c045eb2..4637337d5ce6 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_leds.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c
@@ -33,7 +33,7 @@ static void led_turn_on(struct work_struct *work)
struct rtl8187_led *led = &priv->led_tx;
/* Don't change the LED, when the device is down. */
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
return ;
/* Skip if the LED is not registered. */
@@ -71,7 +71,7 @@ static void led_turn_off(struct work_struct *work)
struct rtl8187_led *led = &priv->led_tx;
/* Don't change the LED, when the device is down. */
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
return ;
/* Skip if the LED is not registered. */
@@ -241,5 +241,5 @@ void rtl8187_leds_exit(struct ieee80211_hw *dev)
cancel_delayed_work_sync(&priv->led_off);
cancel_delayed_work_sync(&priv->led_on);
}
-#endif /* def CONFIG_RTL8187_LED */
+#endif /* def CONFIG_RTL8187_LEDS */
diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.h b/drivers/net/wireless/rtl818x/rtl8187_leds.h
index efe8041bdda4..d743c96d4a20 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_leds.h
+++ b/drivers/net/wireless/rtl818x/rtl8187_leds.h
@@ -54,6 +54,6 @@ struct rtl8187_led {
void rtl8187_leds_init(struct ieee80211_hw *dev, u16 code);
void rtl8187_leds_exit(struct ieee80211_hw *dev);
-#endif /* def CONFIG_RTL8187_LED */
+#endif /* def CONFIG_RTL8187_LEDS */
#endif /* RTL8187_LED_H */
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index 62e37ad01cc0..f47ec94c16dc 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -10,5 +10,7 @@ obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o
wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \
wl1271_event.o wl1271_tx.o wl1271_rx.o \
wl1271_ps.o wl1271_acx.o wl1271_boot.o \
- wl1271_init.o wl1271_debugfs.o
+ wl1271_init.o wl1271_debugfs.o wl1271_io.o
+
+wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o
obj-$(CONFIG_WL1271) += wl1271.o
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h
index 054533f7a124..37c61c19cae5 100644
--- a/drivers/net/wireless/wl12xx/wl1251.h
+++ b/drivers/net/wireless/wl12xx/wl1251.h
@@ -247,6 +247,7 @@ struct wl1251_debugfs {
struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
struct dentry *tx_queue_len;
+ struct dentry *tx_queue_status;
struct dentry *retry_count;
struct dentry *excessive_retries;
@@ -340,9 +341,6 @@ struct wl1251 {
/* Are we currently scanning */
bool scanning;
- /* Our association ID */
- u16 aid;
-
/* Default key (for WEP) */
u32 default_key;
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c
index acfa086dbfc5..beff084040b5 100644
--- a/drivers/net/wireless/wl12xx/wl1251_acx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.c
@@ -976,3 +976,72 @@ out:
kfree(acx);
return ret;
}
+
+int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
+ u8 aifs, u16 txop)
+{
+ struct wl1251_acx_ac_cfg *acx;
+ int ret = 0;
+
+ wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d "
+ "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop);
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->ac = ac;
+ acx->cw_min = cw_min;
+ acx->cw_max = cw_max;
+ acx->aifsn = aifs;
+ acx->txop_limit = txop;
+
+ ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("acx ac cfg failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue,
+ enum wl1251_acx_channel_type type,
+ u8 tsid, enum wl1251_acx_ps_scheme ps_scheme,
+ enum wl1251_acx_ack_policy ack_policy)
+{
+ struct wl1251_acx_tid_cfg *acx;
+ int ret = 0;
+
+ wl1251_debug(DEBUG_ACX, "acx tid cfg %d type %d tsid %d "
+ "ps_scheme %d ack_policy %d", queue, type, tsid,
+ ps_scheme, ack_policy);
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->queue = queue;
+ acx->type = type;
+ acx->tsid = tsid;
+ acx->ps_scheme = ps_scheme;
+ acx->ack_policy = ack_policy;
+
+ ret = wl1251_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("acx tid cfg failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h
index 652371432cd8..26160c45784c 100644
--- a/drivers/net/wireless/wl12xx/wl1251_acx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.h
@@ -1166,6 +1166,87 @@ struct wl1251_acx_wr_tbtt_and_dtim {
u8 padding;
} __attribute__ ((packed));
+struct wl1251_acx_ac_cfg {
+ struct acx_header header;
+
+ /*
+ * Access Category - The TX queue's access category
+ * (refer to AccessCategory_enum)
+ */
+ u8 ac;
+
+ /*
+ * The contention window minimum size (in slots) for
+ * the access class.
+ */
+ u8 cw_min;
+
+ /*
+ * The contention window maximum size (in slots) for
+ * the access class.
+ */
+ u16 cw_max;
+
+ /* The AIF value (in slots) for the access class. */
+ u8 aifsn;
+
+ u8 reserved;
+
+ /* The TX Op Limit (in microseconds) for the access class. */
+ u16 txop_limit;
+} __attribute__ ((packed));
+
+
+enum wl1251_acx_channel_type {
+ CHANNEL_TYPE_DCF = 0,
+ CHANNEL_TYPE_EDCF = 1,
+ CHANNEL_TYPE_HCCA = 2,
+};
+
+enum wl1251_acx_ps_scheme {
+ /* regular ps: simple sending of packets */
+ WL1251_ACX_PS_SCHEME_LEGACY = 0,
+
+ /* sending a packet triggers a unscheduled apsd downstream */
+ WL1251_ACX_PS_SCHEME_UPSD_TRIGGER = 1,
+
+ /* a pspoll packet will be sent before every data packet */
+ WL1251_ACX_PS_SCHEME_LEGACY_PSPOLL = 2,
+
+ /* scheduled apsd mode */
+ WL1251_ACX_PS_SCHEME_SAPSD = 3,
+};
+
+enum wl1251_acx_ack_policy {
+ WL1251_ACX_ACK_POLICY_LEGACY = 0,
+ WL1251_ACX_ACK_POLICY_NO_ACK = 1,
+ WL1251_ACX_ACK_POLICY_BLOCK = 2,
+};
+
+struct wl1251_acx_tid_cfg {
+ struct acx_header header;
+
+ /* tx queue id number (0-7) */
+ u8 queue;
+
+ /* channel access type for the queue, enum wl1251_acx_channel_type */
+ u8 type;
+
+ /* EDCA: ac index (0-3), HCCA: traffic stream id (8-15) */
+ u8 tsid;
+
+ /* ps scheme of the specified queue, enum wl1251_acx_ps_scheme */
+ u8 ps_scheme;
+
+ /* the tx queue ack policy, enum wl1251_acx_ack_policy */
+ u8 ack_policy;
+
+ u8 padding[3];
+
+ /* not supported */
+ u32 apsdconf[2];
+} __attribute__ ((packed));
+
/*************************************************************************
Host Interrupt Register (WiLink -> Host)
@@ -1322,5 +1403,11 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
int wl1251_acx_rate_policies(struct wl1251 *wl);
int wl1251_acx_mem_cfg(struct wl1251 *wl);
int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim);
+int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
+ u8 aifs, u16 txop);
+int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue,
+ enum wl1251_acx_channel_type type,
+ u8 tsid, enum wl1251_acx_ps_scheme ps_scheme,
+ enum wl1251_acx_ack_policy ack_policy);
#endif /* __WL1251_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c
index 770f260726bd..0320b478bb3f 100644
--- a/drivers/net/wireless/wl12xx/wl1251_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c
@@ -410,3 +410,86 @@ out:
kfree(cmd);
return ret;
}
+
+int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len,
+ struct ieee80211_channel *channels[],
+ unsigned int n_channels, unsigned int n_probes)
+{
+ struct wl1251_cmd_scan *cmd;
+ int i, ret = 0;
+
+ wl1251_debug(DEBUG_CMD, "cmd scan");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
+ cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN |
+ CFG_RX_MGMT_EN |
+ CFG_RX_BCN_EN);
+ cmd->params.scan_options = 0;
+ cmd->params.num_channels = n_channels;
+ cmd->params.num_probe_requests = n_probes;
+ cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */
+ cmd->params.tid_trigger = 0;
+
+ for (i = 0; i < n_channels; i++) {
+ cmd->channels[i].min_duration =
+ cpu_to_le32(WL1251_SCAN_MIN_DURATION);
+ cmd->channels[i].max_duration =
+ cpu_to_le32(WL1251_SCAN_MAX_DURATION);
+ memset(&cmd->channels[i].bssid_lsb, 0xff, 4);
+ memset(&cmd->channels[i].bssid_msb, 0xff, 2);
+ cmd->channels[i].early_termination = 0;
+ cmd->channels[i].tx_power_att = 0;
+ cmd->channels[i].channel = channels[i]->hw_value;
+ }
+
+ cmd->params.ssid_len = ssid_len;
+ if (ssid)
+ memcpy(cmd->params.ssid, ssid, ssid_len);
+
+ ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("cmd scan failed: %d", ret);
+ goto out;
+ }
+
+ wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
+
+ if (cmd->header.status != CMD_STATUS_SUCCESS) {
+ wl1251_error("cmd scan status wasn't success: %d",
+ cmd->header.status);
+ ret = -EIO;
+ goto out;
+ }
+
+out:
+ kfree(cmd);
+ return ret;
+}
+
+int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout)
+{
+ struct wl1251_cmd_trigger_scan_to *cmd;
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd trigger scan to");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->timeout = timeout;
+
+ ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("cmd trigger scan to failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(cmd);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h
index dff798ad0ef5..4ad67cae94d2 100644
--- a/drivers/net/wireless/wl12xx/wl1251_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h
@@ -27,6 +27,8 @@
#include "wl1251.h"
+#include <net/cfg80211.h>
+
struct acx_header;
int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len);
@@ -43,6 +45,10 @@ int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
size_t len);
int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
void *buf, size_t buf_len);
+int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len,
+ struct ieee80211_channel *channels[],
+ unsigned int n_channels, unsigned int n_probes);
+int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout);
/* unit ms */
#define WL1251_COMMAND_TIMEOUT 2000
@@ -163,8 +169,12 @@ struct cmd_read_write_memory {
#define CMDMBOX_HEADER_LEN 4
#define CMDMBOX_INFO_ELEM_HEADER_LEN 4
+#define WL1251_SCAN_MIN_DURATION 30000
+#define WL1251_SCAN_MAX_DURATION 60000
+
+#define WL1251_SCAN_NUM_PROBES 3
-struct basic_scan_parameters {
+struct wl1251_scan_parameters {
u32 rx_config_options;
u32 rx_filter_options;
@@ -189,11 +199,11 @@ struct basic_scan_parameters {
u8 tid_trigger;
u8 ssid_len;
- u32 ssid[8];
+ u8 ssid[32];
} __attribute__ ((packed));
-struct basic_scan_channel_parameters {
+struct wl1251_scan_ch_parameters {
u32 min_duration; /* in TU */
u32 max_duration; /* in TU */
u32 bssid_lsb;
@@ -213,11 +223,11 @@ struct basic_scan_channel_parameters {
/* SCAN parameters */
#define SCAN_MAX_NUM_OF_CHANNELS 16
-struct cmd_scan {
+struct wl1251_cmd_scan {
struct wl1251_cmd_header header;
- struct basic_scan_parameters params;
- struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
+ struct wl1251_scan_parameters params;
+ struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
} __attribute__ ((packed));
enum {
diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c
index a00723059f83..0ccba57fb9fb 100644
--- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c
+++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c
@@ -237,6 +237,27 @@ static const struct file_operations tx_queue_len_ops = {
.open = wl1251_open_file_generic,
};
+static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1251 *wl = file->private_data;
+ char buf[3], status;
+ int len;
+
+ if (wl->tx_queue_stopped)
+ status = 's';
+ else
+ status = 'r';
+
+ len = scnprintf(buf, sizeof(buf), "%c\n", status);
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static const struct file_operations tx_queue_status_ops = {
+ .read = tx_queue_status_read,
+ .open = wl1251_open_file_generic,
+};
+
static void wl1251_debugfs_delete_files(struct wl1251 *wl)
{
DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
@@ -331,6 +352,7 @@ static void wl1251_debugfs_delete_files(struct wl1251 *wl)
DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data);
DEBUGFS_DEL(tx_queue_len);
+ DEBUGFS_DEL(tx_queue_status);
DEBUGFS_DEL(retry_count);
DEBUGFS_DEL(excessive_retries);
}
@@ -431,6 +453,7 @@ static int wl1251_debugfs_add_files(struct wl1251 *wl)
DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir);
+ DEBUGFS_ADD(tx_queue_status, wl->debugfs.rootdir);
DEBUGFS_ADD(retry_count, wl->debugfs.rootdir);
DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir);
diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c
index 5cb573383eeb..5aad56ea7153 100644
--- a/drivers/net/wireless/wl12xx/wl1251_init.c
+++ b/drivers/net/wireless/wl12xx/wl1251_init.c
@@ -294,6 +294,11 @@ static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
goto out;
}
+ wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE);
+ wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK);
+ wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI);
+ wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO);
+
out:
kfree(config);
return ret;
diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h
index b3b25ec885ea..269cefb3e7d4 100644
--- a/drivers/net/wireless/wl12xx/wl1251_init.h
+++ b/drivers/net/wireless/wl12xx/wl1251_init.h
@@ -26,6 +26,53 @@
#include "wl1251.h"
+enum {
+ /* best effort/legacy */
+ AC_BE = 0,
+
+ /* background */
+ AC_BK = 1,
+
+ /* video */
+ AC_VI = 2,
+
+ /* voice */
+ AC_VO = 3,
+
+ /* broadcast dummy access category */
+ AC_BCAST = 4,
+
+ NUM_ACCESS_CATEGORIES = 4
+};
+
+/* following are defult values for the IE fields*/
+#define CWMIN_BK 15
+#define CWMIN_BE 15
+#define CWMIN_VI 7
+#define CWMIN_VO 3
+#define CWMAX_BK 1023
+#define CWMAX_BE 63
+#define CWMAX_VI 15
+#define CWMAX_VO 7
+
+/* slot number setting to start transmission at PIFS interval */
+#define AIFS_PIFS 1
+
+/*
+ * slot number setting to start transmission at DIFS interval - normal DCF
+ * access
+ */
+#define AIFS_DIFS 2
+
+#define AIFSN_BK 7
+#define AIFSN_BE 3
+#define AIFSN_VI AIFS_PIFS
+#define AIFSN_VO AIFS_PIFS
+#define TXOP_BK 0
+#define TXOP_BE 0
+#define TXOP_VI 3008
+#define TXOP_VO 1504
+
int wl1251_hw_init_hwenc_config(struct wl1251 *wl);
int wl1251_hw_init_templates_config(struct wl1251 *wl);
int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter);
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 2f50a256efa5..24ae6a360ac8 100644
--- a/drivers/net/wireless/wl12xx/wl1251_main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -395,6 +395,7 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* the queue here, otherwise the queue will get too long.
*/
if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) {
+ wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues");
ieee80211_stop_queues(wl->hw);
/*
@@ -510,13 +511,13 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
}
static int wl1251_op_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct wl1251 *wl = hw->priv;
int ret = 0;
wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
- conf->type, conf->mac_addr);
+ vif->type, vif->addr);
mutex_lock(&wl->mutex);
if (wl->vif) {
@@ -524,9 +525,9 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
- wl->vif = conf->vif;
+ wl->vif = vif;
- switch (conf->type) {
+ switch (vif->type) {
case NL80211_IFTYPE_STATION:
wl->bss_type = BSS_TYPE_STA_BSS;
break;
@@ -538,8 +539,8 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
- if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) {
- memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+ if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) {
+ memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
ret = wl1251_acx_station_id(wl);
if (ret < 0)
@@ -552,7 +553,7 @@ out:
}
static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct wl1251 *wl = hw->priv;
@@ -562,43 +563,25 @@ static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
mutex_unlock(&wl->mutex);
}
-static int wl1251_build_null_data(struct wl1251 *wl)
+static int wl1251_build_qos_null_data(struct wl1251 *wl)
{
- struct wl12xx_null_data_template template;
+ struct ieee80211_qos_hdr template;
- if (!is_zero_ether_addr(wl->bssid)) {
- memcpy(template.header.da, wl->bssid, ETH_ALEN);
- memcpy(template.header.bssid, wl->bssid, ETH_ALEN);
- } else {
- memset(template.header.da, 0xff, ETH_ALEN);
- memset(template.header.bssid, 0xff, ETH_ALEN);
- }
-
- memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
- template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
- IEEE80211_STYPE_NULLFUNC |
- IEEE80211_FCTL_TODS);
-
- return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template,
- sizeof(template));
-
-}
-
-static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid)
-{
- struct wl12xx_ps_poll_template template;
+ memset(&template, 0, sizeof(template));
- memcpy(template.bssid, wl->bssid, ETH_ALEN);
- memcpy(template.ta, wl->mac_addr, ETH_ALEN);
+ memcpy(template.addr1, wl->bssid, ETH_ALEN);
+ memcpy(template.addr2, wl->mac_addr, ETH_ALEN);
+ memcpy(template.addr3, wl->bssid, ETH_ALEN);
- /* aid in PS-Poll has its two MSBs each set to 1 */
- template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid);
+ template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ IEEE80211_STYPE_QOS_NULLFUNC |
+ IEEE80211_FCTL_TODS);
- template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
+ /* FIXME: not sure what priority to use here */
+ template.qos_ctrl = cpu_to_le16(0);
- return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template,
+ return wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, &template,
sizeof(template));
-
}
static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
@@ -634,26 +617,34 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
wl->psm_requested = true;
+ wl->dtim_period = conf->ps_dtim_period;
+
+ ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int,
+ wl->dtim_period);
+
/*
- * We enter PSM only if we're already associated.
- * If we're not, we'll enter it when joining an SSID,
- * through the bss_info_changed() hook.
+ * mac80211 enables PSM only if we're already associated.
*/
ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+ if (ret < 0)
+ goto out_sleep;
} else if (!(conf->flags & IEEE80211_CONF_PS) &&
wl->psm_requested) {
wl1251_debug(DEBUG_PSM, "psm disabled");
wl->psm_requested = false;
- if (wl->psm)
+ if (wl->psm) {
ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ if (ret < 0)
+ goto out_sleep;
+ }
}
if (conf->power_level != wl->power_level) {
ret = wl1251_acx_tx_power(wl, conf->power_level);
if (ret < 0)
- goto out;
+ goto out_sleep;
wl->power_level = conf->power_level;
}
@@ -864,199 +855,61 @@ out:
return ret;
}
-static int wl1251_build_basic_rates(char *rates)
-{
- u8 index = 0;
-
- rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
- rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
- rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
- rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
-
- return index;
-}
-
-static int wl1251_build_extended_rates(char *rates)
+static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
+ struct cfg80211_scan_request *req)
{
- u8 index = 0;
-
- rates[index++] = IEEE80211_OFDM_RATE_6MB;
- rates[index++] = IEEE80211_OFDM_RATE_9MB;
- rates[index++] = IEEE80211_OFDM_RATE_12MB;
- rates[index++] = IEEE80211_OFDM_RATE_18MB;
- rates[index++] = IEEE80211_OFDM_RATE_24MB;
- rates[index++] = IEEE80211_OFDM_RATE_36MB;
- rates[index++] = IEEE80211_OFDM_RATE_48MB;
- rates[index++] = IEEE80211_OFDM_RATE_54MB;
-
- return index;
-}
-
+ struct wl1251 *wl = hw->priv;
+ struct sk_buff *skb;
+ size_t ssid_len = 0;
+ u8 *ssid = NULL;
+ int ret;
-static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len)
-{
- struct wl12xx_probe_req_template template;
- struct wl12xx_ie_rates *rates;
- char *ptr;
- u16 size;
-
- ptr = (char *)&template;
- size = sizeof(struct ieee80211_header);
-
- memset(template.header.da, 0xff, ETH_ALEN);
- memset(template.header.bssid, 0xff, ETH_ALEN);
- memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
- template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
-
- /* IEs */
- /* SSID */
- template.ssid.header.id = WLAN_EID_SSID;
- template.ssid.header.len = ssid_len;
- if (ssid_len && ssid)
- memcpy(template.ssid.ssid, ssid, ssid_len);
- size += sizeof(struct wl12xx_ie_header) + ssid_len;
- ptr += size;
-
- /* Basic Rates */
- rates = (struct wl12xx_ie_rates *)ptr;
- rates->header.id = WLAN_EID_SUPP_RATES;
- rates->header.len = wl1251_build_basic_rates(rates->rates);
- size += sizeof(struct wl12xx_ie_header) + rates->header.len;
- ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;
-
- /* Extended rates */
- rates = (struct wl12xx_ie_rates *)ptr;
- rates->header.id = WLAN_EID_EXT_SUPP_RATES;
- rates->header.len = wl1251_build_extended_rates(rates->rates);
- size += sizeof(struct wl12xx_ie_header) + rates->header.len;
-
- wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
-
- return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template,
- size);
-}
+ wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan");
-static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len,
- u8 active_scan, u8 high_prio, u8 num_channels,
- u8 probe_requests)
-{
- struct wl1251_cmd_trigger_scan_to *trigger = NULL;
- struct cmd_scan *params = NULL;
- int i, ret;
- u16 scan_options = 0;
-
- if (wl->scanning)
- return -EINVAL;
-
- params = kzalloc(sizeof(*params), GFP_KERNEL);
- if (!params)
- return -ENOMEM;
-
- params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
- params->params.rx_filter_options =
- cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
-
- /* High priority scan */
- if (!active_scan)
- scan_options |= SCAN_PASSIVE;
- if (high_prio)
- scan_options |= SCAN_PRIORITY_HIGH;
- params->params.scan_options = scan_options;
-
- params->params.num_channels = num_channels;
- params->params.num_probe_requests = probe_requests;
- params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */
- params->params.tid_trigger = 0;
-
- for (i = 0; i < num_channels; i++) {
- params->channels[i].min_duration = cpu_to_le32(30000);
- params->channels[i].max_duration = cpu_to_le32(60000);
- memset(&params->channels[i].bssid_lsb, 0xff, 4);
- memset(&params->channels[i].bssid_msb, 0xff, 2);
- params->channels[i].early_termination = 0;
- params->channels[i].tx_power_att = 0;
- params->channels[i].channel = i + 1;
- memset(params->channels[i].pad, 0, 3);
+ if (req->n_ssids) {
+ ssid = req->ssids[0].ssid;
+ ssid_len = req->ssids[0].ssid_len;
}
- for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++)
- memset(&params->channels[i], 0,
- sizeof(struct basic_scan_channel_parameters));
-
- if (len && ssid) {
- params->params.ssid_len = len;
- memcpy(params->params.ssid, ssid, len);
- } else {
- params->params.ssid_len = 0;
- memset(params->params.ssid, 0, 32);
- }
+ mutex_lock(&wl->mutex);
- ret = wl1251_build_probe_req(wl, ssid, len);
- if (ret < 0) {
- wl1251_error("PROBE request template failed");
+ if (wl->scanning) {
+ wl1251_debug(DEBUG_SCAN, "scan already in progress");
+ ret = -EINVAL;
goto out;
}
- trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
- if (!trigger)
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
goto out;
- trigger->timeout = 0;
-
- ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
- sizeof(*trigger));
- if (ret < 0) {
- wl1251_error("trigger scan to failed for hw scan");
+ skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
+ req->ie, req->ie_len);
+ if (!skb) {
+ ret = -ENOMEM;
goto out;
}
- wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
-
- wl->scanning = true;
+ ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data,
+ skb->len);
+ dev_kfree_skb(skb);
+ if (ret < 0)
+ goto out_sleep;
- ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
+ ret = wl1251_cmd_trigger_scan_to(wl, 0);
if (ret < 0)
- wl1251_error("SCAN failed");
+ goto out_sleep;
- wl1251_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
+ wl->scanning = true;
- if (params->header.status != CMD_STATUS_SUCCESS) {
- wl1251_error("TEST command answer error: %d",
- params->header.status);
+ ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels,
+ req->n_channels, WL1251_SCAN_NUM_PROBES);
+ if (ret < 0) {
wl->scanning = false;
- ret = -EIO;
- goto out;
- }
-
-out:
- kfree(params);
- return ret;
-
-}
-
-static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
- struct cfg80211_scan_request *req)
-{
- struct wl1251 *wl = hw->priv;
- int ret;
- u8 *ssid = NULL;
- size_t ssid_len = 0;
-
- wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan");
-
- if (req->n_ssids) {
- ssid = req->ssids[0].ssid;
- ssid_len = req->ssids[0].ssid_len;
+ goto out_sleep;
}
- mutex_lock(&wl->mutex);
-
- ret = wl1251_ps_elp_wakeup(wl);
- if (ret < 0)
- goto out;
-
- ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
-
+out_sleep:
wl1251_ps_elp_sleep(wl);
out:
@@ -1093,9 +946,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *bss_conf,
u32 changed)
{
- enum wl1251_cmd_ps_mode mode;
struct wl1251 *wl = hw->priv;
- struct sk_buff *beacon;
+ struct sk_buff *beacon, *skb;
int ret;
wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed");
@@ -1109,7 +961,17 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BSSID) {
memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
- ret = wl1251_build_null_data(wl);
+ skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
+ if (!skb)
+ goto out_sleep;
+
+ ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA,
+ skb->data, skb->len);
+ dev_kfree_skb(skb);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wl1251_build_qos_null_data(wl);
if (ret < 0)
goto out;
@@ -1124,27 +986,21 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
wl->beacon_int = bss_conf->beacon_int;
- wl->dtim_period = bss_conf->dtim_period;
- ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int,
- wl->dtim_period);
- wl->aid = bss_conf->aid;
+ skb = ieee80211_pspoll_get(wl->hw, wl->vif);
+ if (!skb)
+ goto out_sleep;
- ret = wl1251_build_ps_poll(wl, wl->aid);
+ ret = wl1251_cmd_template_set(wl, CMD_PS_POLL,
+ skb->data,
+ skb->len);
+ dev_kfree_skb(skb);
if (ret < 0)
goto out_sleep;
- ret = wl1251_acx_aid(wl, wl->aid);
+ ret = wl1251_acx_aid(wl, bss_conf->aid);
if (ret < 0)
goto out_sleep;
-
- /* If we want to go in PSM but we're not there yet */
- if (wl->psm_requested && !wl->psm) {
- mode = STATION_POWER_SAVE_MODE;
- ret = wl1251_ps_set_mode(wl, mode);
- if (ret < 0)
- goto out_sleep;
- }
} else {
/* use defaults when not associated */
wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
@@ -1176,7 +1032,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE);
if (ret < 0) {
wl1251_warning("Set ctsprotect failed %d", ret);
- goto out;
+ goto out_sleep;
}
}
@@ -1187,7 +1043,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret < 0) {
dev_kfree_skb(beacon);
- goto out;
+ goto out_sleep;
}
ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data,
@@ -1196,13 +1052,13 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
dev_kfree_skb(beacon);
if (ret < 0)
- goto out;
+ goto out_sleep;
ret = wl1251_join(wl, wl->bss_type, wl->beacon_int,
wl->channel, wl->dtim_period);
if (ret < 0)
- goto out;
+ goto out_sleep;
}
out_sleep:
@@ -1273,6 +1129,49 @@ static struct ieee80211_channel wl1251_channels[] = {
{ .hw_value = 13, .center_freq = 2472},
};
+static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ enum wl1251_acx_ps_scheme ps_scheme;
+ struct wl1251 *wl = hw->priv;
+ int ret;
+
+ mutex_lock(&wl->mutex);
+
+ wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
+
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ /* mac80211 uses units of 32 usec */
+ ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue),
+ params->cw_min, params->cw_max,
+ params->aifs, params->txop * 32);
+ if (ret < 0)
+ goto out_sleep;
+
+ if (params->uapsd)
+ ps_scheme = WL1251_ACX_PS_SCHEME_UPSD_TRIGGER;
+ else
+ ps_scheme = WL1251_ACX_PS_SCHEME_LEGACY;
+
+ ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue),
+ CHANNEL_TYPE_EDCF,
+ wl1251_tx_get_queue(queue), ps_scheme,
+ WL1251_ACX_ACK_POLICY_LEGACY);
+ if (ret < 0)
+ goto out_sleep;
+
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
/* can't be const, mac80211 writes to this */
static struct ieee80211_supported_band wl1251_band_2ghz = {
.channels = wl1251_channels,
@@ -1293,6 +1192,7 @@ static const struct ieee80211_ops wl1251_ops = {
.hw_scan = wl1251_op_hw_scan,
.bss_info_changed = wl1251_op_bss_info_changed,
.set_rts_threshold = wl1251_op_set_rts_threshold,
+ .conf_tx = wl1251_op_conf_tx,
};
static int wl1251_register_hw(struct wl1251 *wl)
@@ -1332,12 +1232,15 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_BEACON_FILTER;
+ IEEE80211_HW_BEACON_FILTER |
+ IEEE80211_HW_SUPPORTS_UAPSD;
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
wl->hw->wiphy->max_scan_ssids = 1;
wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz;
+ wl->hw->queues = 4;
+
ret = wl1251_register_hw(wl);
if (ret)
goto out;
diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c
index 9931b197ff77..851dfb65e474 100644
--- a/drivers/net/wireless/wl12xx/wl1251_ps.c
+++ b/drivers/net/wireless/wl12xx/wl1251_ps.c
@@ -26,7 +26,8 @@
#include "wl1251_cmd.h"
#include "wl1251_io.h"
-#define WL1251_WAKEUP_TIMEOUT 2000
+/* in ms */
+#define WL1251_WAKEUP_TIMEOUT 100
void wl1251_elp_work(struct work_struct *work)
{
@@ -67,7 +68,7 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl)
int wl1251_ps_elp_wakeup(struct wl1251 *wl)
{
- unsigned long timeout;
+ unsigned long timeout, start;
u32 elp_reg;
if (!wl->elp)
@@ -75,6 +76,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
wl1251_debug(DEBUG_PSM, "waking up chip from elp");
+ start = jiffies;
timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);
wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
@@ -95,8 +97,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
}
wl1251_debug(DEBUG_PSM, "wakeup time: %u ms",
- jiffies_to_msecs(jiffies) -
- (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT));
+ jiffies_to_msecs(jiffies - start));
wl->elp = false;
diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c
index f84cc89cbffc..b56732226cc0 100644
--- a/drivers/net/wireless/wl12xx/wl1251_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.c
@@ -126,7 +126,7 @@ static void wl1251_rx_body(struct wl1251 *wl,
if (wl->rx_current_buffer)
rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
- skb = dev_alloc_skb(length);
+ skb = __dev_alloc_skb(length, GFP_KERNEL);
if (!skb) {
wl1251_error("Couldn't allocate RX frame");
return;
diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c
index f85970615849..c8223185efd2 100644
--- a/drivers/net/wireless/wl12xx/wl1251_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.c
@@ -167,8 +167,7 @@ static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb,
tx_hdr->expiry_time = cpu_to_le32(1 << 16);
tx_hdr->id = id;
- /* FIXME: how to get the correct queue id? */
- tx_hdr->xmit_queue = 0;
+ tx_hdr->xmit_queue = wl1251_tx_get_queue(skb_get_queue_mapping(skb));
wl1251_tx_control(tx_hdr, control, fc);
wl1251_tx_frag_block_num(tx_hdr);
@@ -220,6 +219,7 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
/* align the buffer on a 4-byte boundary */
skb_reserve(skb, offset);
memmove(skb->data, src, skb->len);
+ tx_hdr = (struct tx_double_buffer_desc *) skb->data;
} else {
wl1251_info("No handler, fixme!");
return -EINVAL;
@@ -237,8 +237,9 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
wl1251_mem_write(wl, addr, skb->data, len);
- wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
- tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate);
+ wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x "
+ "queue %d", tx_hdr->id, skb, tx_hdr->length,
+ tx_hdr->rate, tx_hdr->xmit_queue);
return 0;
}
diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h
index 7c1c1665c810..55856c6bb97a 100644
--- a/drivers/net/wireless/wl12xx/wl1251_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.h
@@ -26,6 +26,7 @@
#define __WL1251_TX_H__
#include <linux/bitops.h>
+#include "wl1251_acx.h"
/*
*
@@ -209,6 +210,22 @@ struct tx_result {
u8 done_2;
} __attribute__ ((packed));
+static inline int wl1251_tx_get_queue(int queue)
+{
+ switch (queue) {
+ case 0:
+ return QOS_AC_VO;
+ case 1:
+ return QOS_AC_VI;
+ case 2:
+ return QOS_AC_BE;
+ case 3:
+ return QOS_AC_BK;
+ default:
+ return QOS_AC_BE;
+ }
+}
+
void wl1251_tx_work(struct work_struct *work);
void wl1251_tx_complete(struct wl1251 *wl);
void wl1251_tx_flush(struct wl1251 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 94359b1a861f..97ea5096bc8c 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -43,7 +43,7 @@ enum {
DEBUG_SPI = BIT(1),
DEBUG_BOOT = BIT(2),
DEBUG_MAILBOX = BIT(3),
- DEBUG_NETLINK = BIT(4),
+ DEBUG_TESTMODE = BIT(4),
DEBUG_EVENT = BIT(5),
DEBUG_TX = BIT(6),
DEBUG_RX = BIT(7),
@@ -107,11 +107,36 @@ enum {
CFG_RX_CTL_EN | CFG_RX_BCN_EN | \
CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
-#define WL1271_DEFAULT_BASIC_RATE_SET (CONF_TX_RATE_MASK_ALL)
-
#define WL1271_FW_NAME "wl1271-fw.bin"
#define WL1271_NVS_NAME "wl1271-nvs.bin"
+/* NVS data structure */
+#define WL1271_NVS_SECTION_SIZE 468
+
+#define WL1271_NVS_GENERAL_PARAMS_SIZE 57
+#define WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED \
+ (WL1271_NVS_GENERAL_PARAMS_SIZE + 1)
+#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE 17
+#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED \
+ (WL1271_NVS_STAT_RADIO_PARAMS_SIZE + 1)
+#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE 65
+#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED \
+ (WL1271_NVS_DYN_RADIO_PARAMS_SIZE + 1)
+#define WL1271_NVS_FEM_COUNT 2
+#define WL1271_NVS_INI_SPARE_SIZE 124
+
+struct wl1271_nvs_file {
+ /* NVS section */
+ u8 nvs[WL1271_NVS_SECTION_SIZE];
+
+ /* INI section */
+ u8 general_params[WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED];
+ u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED];
+ u8 dyn_radio_params[WL1271_NVS_FEM_COUNT]
+ [WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED];
+ u8 ini_spare[WL1271_NVS_INI_SPARE_SIZE];
+} __attribute__ ((packed));
+
/*
* Enable/disable 802.11a support for WL1273
*/
@@ -276,6 +301,7 @@ struct wl1271_debugfs {
struct dentry *retry_count;
struct dentry *excessive_retries;
+ struct dentry *gpio_power;
};
#define NUM_TX_QUEUES 4
@@ -322,6 +348,17 @@ struct wl1271 {
enum wl1271_state state;
struct mutex mutex;
+#define WL1271_FLAG_STA_RATES_CHANGED (0)
+#define WL1271_FLAG_STA_ASSOCIATED (1)
+#define WL1271_FLAG_JOINED (2)
+#define WL1271_FLAG_GPIO_POWER (3)
+#define WL1271_FLAG_TX_QUEUE_STOPPED (4)
+#define WL1271_FLAG_SCANNING (5)
+#define WL1271_FLAG_IN_ELP (6)
+#define WL1271_FLAG_PSM (7)
+#define WL1271_FLAG_PSM_REQUESTED (8)
+ unsigned long flags;
+
struct wl1271_partition_set part;
struct wl1271_chip chip;
@@ -331,8 +368,7 @@ struct wl1271 {
u8 *fw;
size_t fw_len;
- u8 *nvs;
- size_t nvs_len;
+ struct wl1271_nvs_file *nvs;
u8 bssid[ETH_ALEN];
u8 mac_addr[ETH_ALEN];
@@ -359,7 +395,6 @@ struct wl1271 {
/* Frames scheduled for transmission, not handled yet */
struct sk_buff_head tx_queue;
- bool tx_queue_stopped;
struct work_struct tx_work;
@@ -387,14 +422,15 @@ struct wl1271 {
u32 mbox_ptr[2];
/* Are we currently scanning */
- bool scanning;
struct wl1271_scan scan;
/* Our association ID */
u16 aid;
/* currently configured rate set */
+ u32 sta_rate_set;
u32 basic_rate_set;
+ u32 rate_set;
/* The current band */
enum ieee80211_band band;
@@ -405,18 +441,9 @@ struct wl1271 {
unsigned int rx_config;
unsigned int rx_filter;
- /* is firmware in elp mode */
- bool elp;
-
struct completion *elp_compl;
struct delayed_work elp_work;
- /* we can be in psm, but not in elp, we have to differentiate */
- bool psm;
-
- /* PSM mode requested */
- bool psm_requested;
-
/* retry counter for PSM entries */
u8 psm_entry_retry;
@@ -435,9 +462,6 @@ struct wl1271 {
struct ieee80211_vif *vif;
- /* Used for a workaround to send disconnect before rejoining */
- bool joined;
-
/* Current chipset configuration */
struct conf_drv_settings conf;
@@ -455,11 +479,14 @@ int wl1271_plt_stop(struct wl1271 *wl);
#define WL1271_TX_QUEUE_MAX_LENGTH 20
-/* WL1271 needs a 200ms sleep after power on */
+/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power
+ on in case is has been shut down shortly before */
+#define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */
#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
static inline bool wl1271_11a_enabled(void)
{
+ /* FIXME: this could be determined based on the NVS-INI file */
#ifdef WL1271_80211A_ENABLED
return true;
#else
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c
index 5cc89bbdac7a..60f10dce4800 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.c
@@ -390,6 +390,35 @@ out:
return ret;
}
+int wl1271_acx_dco_itrim_params(struct wl1271 *wl)
+{
+ struct acx_dco_itrim_params *dco;
+ struct conf_itrim_settings *c = &wl->conf.itrim;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx dco itrim parameters");
+
+ dco = kzalloc(sizeof(*dco), GFP_KERNEL);
+ if (!dco) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ dco->enable = c->enable;
+ dco->timeout = cpu_to_le32(c->timeout);
+
+ ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS,
+ dco, sizeof(*dco));
+ if (ret < 0) {
+ wl1271_warning("failed to set dco itrim parameters: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(dco);
+ return ret;
+}
+
int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
{
struct acx_beacon_filter_option *beacon_filter = NULL;
@@ -758,10 +787,11 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
return 0;
}
-int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates)
+int wl1271_acx_rate_policies(struct wl1271 *wl)
{
struct acx_rate_policy *acx;
struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf;
+ int idx = 0;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx rate policies");
@@ -773,12 +803,21 @@ int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates)
goto out;
}
- /* configure one default (one-size-fits-all) rate class */
- acx->rate_class_cnt = cpu_to_le32(1);
- acx->rate_class[0].enabled_rates = cpu_to_le32(enabled_rates);
- acx->rate_class[0].short_retry_limit = c->short_retry_limit;
- acx->rate_class[0].long_retry_limit = c->long_retry_limit;
- acx->rate_class[0].aflags = c->aflags;
+ /* configure one basic rate class */
+ idx = ACX_TX_BASIC_RATE;
+ acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate_set);
+ acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
+ acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
+ acx->rate_class[idx].aflags = c->aflags;
+
+ /* configure one AP supported rate class */
+ idx = ACX_TX_AP_FULL_RATE;
+ acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set);
+ acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
+ acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
+ acx->rate_class[idx].aflags = c->aflags;
+
+ acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT);
ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
if (ret < 0) {
@@ -791,12 +830,14 @@ out:
return ret;
}
-int wl1271_acx_ac_cfg(struct wl1271 *wl)
+int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
+ u8 aifsn, u16 txop)
{
struct acx_ac_cfg *acx;
- int i, ret = 0;
+ int ret = 0;
- wl1271_debug(DEBUG_ACX, "acx access category config");
+ wl1271_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d "
+ "aifs %d txop %d", ac, cw_min, cw_max, aifsn, txop);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
@@ -805,21 +846,16 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl)
goto out;
}
- for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
- struct conf_tx_ac_category *c = &(wl->conf.tx.ac_conf[i]);
- acx->ac = c->ac;
- acx->cw_min = c->cw_min;
- acx->cw_max = cpu_to_le16(c->cw_max);
- acx->aifsn = c->aifsn;
- acx->reserved = 0;
- acx->tx_op_limit = cpu_to_le16(c->tx_op_limit);
+ acx->ac = ac;
+ acx->cw_min = cw_min;
+ acx->cw_max = cpu_to_le16(cw_max);
+ acx->aifsn = aifsn;
+ acx->tx_op_limit = cpu_to_le16(txop);
- ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx));
- if (ret < 0) {
- wl1271_warning("Setting of access category "
- "config: %d", ret);
- goto out;
- }
+ ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx ac cfg failed: %d", ret);
+ goto out;
}
out:
@@ -827,10 +863,12 @@ out:
return ret;
}
-int wl1271_acx_tid_cfg(struct wl1271 *wl)
+int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
+ u8 tsid, u8 ps_scheme, u8 ack_policy,
+ u32 apsd_conf0, u32 apsd_conf1)
{
struct acx_tid_config *acx;
- int i, ret = 0;
+ int ret = 0;
wl1271_debug(DEBUG_ACX, "acx tid config");
@@ -841,21 +879,18 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl)
goto out;
}
- for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
- struct conf_tx_tid *c = &(wl->conf.tx.tid_conf[i]);
- acx->queue_id = c->queue_id;
- acx->channel_type = c->channel_type;
- acx->tsid = c->tsid;
- acx->ps_scheme = c->ps_scheme;
- acx->ack_policy = c->ack_policy;
- acx->apsd_conf[0] = cpu_to_le32(c->apsd_conf[0]);
- acx->apsd_conf[1] = cpu_to_le32(c->apsd_conf[1]);
+ acx->queue_id = queue_id;
+ acx->channel_type = channel_type;
+ acx->tsid = tsid;
+ acx->ps_scheme = ps_scheme;
+ acx->ack_policy = ack_policy;
+ acx->apsd_conf[0] = cpu_to_le32(apsd_conf0);
+ acx->apsd_conf[1] = cpu_to_le32(apsd_conf1);
- ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx));
- if (ret < 0) {
- wl1271_warning("Setting of tid config failed: %d", ret);
- goto out;
- }
+ ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("Setting of tid config failed: %d", ret);
+ goto out;
}
out:
@@ -1012,59 +1047,6 @@ out:
return ret;
}
-int wl1271_acx_smart_reflex(struct wl1271 *wl)
-{
- struct acx_smart_reflex_state *sr_state = NULL;
- struct acx_smart_reflex_config_params *sr_param = NULL;
- int i, ret;
-
- wl1271_debug(DEBUG_ACX, "acx smart reflex");
-
- sr_param = kzalloc(sizeof(*sr_param), GFP_KERNEL);
- if (!sr_param) {
- ret = -ENOMEM;
- goto out;
- }
-
- for (i = 0; i < CONF_SR_ERR_TBL_COUNT; i++) {
- struct conf_mart_reflex_err_table *e =
- &(wl->conf.init.sr_err_tbl[i]);
-
- sr_param->error_table[i].len = e->len;
- sr_param->error_table[i].upper_limit = e->upper_limit;
- memcpy(sr_param->error_table[i].values, e->values, e->len);
- }
-
- ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_PARAMS,
- sr_param, sizeof(*sr_param));
- if (ret < 0) {
- wl1271_warning("failed to set smart reflex params: %d", ret);
- goto out;
- }
-
- sr_state = kzalloc(sizeof(*sr_state), GFP_KERNEL);
- if (!sr_state) {
- ret = -ENOMEM;
- goto out;
- }
-
- /* enable smart reflex */
- sr_state->enable = wl->conf.init.sr_enable;
-
- ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_STATE,
- sr_state, sizeof(*sr_state));
- if (ret < 0) {
- wl1271_warning("failed to set smart reflex params: %d", ret);
- goto out;
- }
-
-out:
- kfree(sr_state);
- kfree(sr_param);
- return ret;
-
-}
-
int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
{
struct wl1271_acx_bet_enable *acx = NULL;
@@ -1132,3 +1114,31 @@ out:
kfree(acx);
return ret;
}
+
+int wl1271_acx_pm_config(struct wl1271 *wl)
+{
+ struct wl1271_acx_pm_config *acx = NULL;
+ struct conf_pm_config_settings *c = &wl->conf.pm_config;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_ACX, "acx pm config");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time);
+ acx->host_fast_wakeup_support = c->host_fast_wakeup_support;
+
+ ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx pm config failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h
index 2ce0a8128542..aeccc98581eb 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.h
@@ -2,7 +2,7 @@
* This file is part of wl1271
*
* Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
- * Copyright (C) 2008-2009 Nokia Corporation
+ * Copyright (C) 2008-2010 Nokia Corporation
*
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
@@ -348,7 +348,7 @@ struct acx_beacon_filter_option {
* ACXBeaconFilterEntry (not 221)
* Byte Offset Size (Bytes) Definition
* =========== ============ ==========
- * 0 1 IE identifier
+ * 0 1 IE identifier
* 1 1 Treatment bit mask
*
* ACXBeaconFilterEntry (221)
@@ -381,8 +381,8 @@ struct acx_beacon_filter_ie_table {
struct acx_header header;
u8 num_ie;
- u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
u8 pad[3];
+ u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
} __attribute__ ((packed));
struct acx_conn_monit_params {
@@ -415,23 +415,12 @@ struct acx_bt_wlan_coex {
u8 pad[3];
} __attribute__ ((packed));
-struct acx_smart_reflex_state {
+struct acx_dco_itrim_params {
struct acx_header header;
u8 enable;
u8 padding[3];
-} __attribute__ ((packed));
-
-struct smart_reflex_err_table {
- u8 len;
- s8 upper_limit;
- s8 values[14];
-} __attribute__ ((packed));
-
-struct acx_smart_reflex_config_params {
- struct acx_header header;
-
- struct smart_reflex_err_table error_table[3];
+ __le32 timeout;
} __attribute__ ((packed));
#define PTA_ANTENNA_TYPE_DEF (0)
@@ -837,6 +826,9 @@ struct acx_rate_class {
u8 reserved;
};
+#define ACX_TX_BASIC_RATE 0
+#define ACX_TX_AP_FULL_RATE 1
+#define ACX_TX_RATE_POLICY_CNT 2
struct acx_rate_policy {
struct acx_header header;
@@ -877,8 +869,8 @@ struct acx_tx_config_options {
__le16 tx_compl_threshold; /* number of packets */
} __attribute__ ((packed));
-#define ACX_RX_MEM_BLOCKS 64
-#define ACX_TX_MIN_MEM_BLOCKS 64
+#define ACX_RX_MEM_BLOCKS 70
+#define ACX_TX_MIN_MEM_BLOCKS 40
#define ACX_TX_DESCRIPTORS 32
#define ACX_NUM_SSID_PROFILES 1
@@ -969,6 +961,13 @@ struct wl1271_acx_arp_filter {
used. */
} __attribute__((packed));
+struct wl1271_acx_pm_config {
+ struct acx_header header;
+
+ __le32 host_clk_settling_time;
+ u8 host_fast_wakeup_support;
+ u8 padding[3];
+} __attribute__ ((packed));
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
@@ -1027,13 +1026,13 @@ enum {
ACX_HT_BSS_OPERATION = 0x0058,
ACX_COEX_ACTIVITY = 0x0059,
ACX_SET_SMART_REFLEX_DEBUG = 0x005A,
- ACX_SET_SMART_REFLEX_STATE = 0x005B,
- ACX_SET_SMART_REFLEX_PARAMS = 0x005F,
+ ACX_SET_DCO_ITRIM_PARAMS = 0x0061,
DOT11_RX_MSDU_LIFE_TIME = 0x1004,
DOT11_CUR_TX_PWR = 0x100D,
DOT11_RX_DOT11_MODE = 0x1012,
DOT11_RTS_THRESHOLD = 0x1013,
DOT11_GROUP_ADDRESS_TBL = 0x1014,
+ ACX_PM_CONFIG = 0x1016,
MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL,
@@ -1056,6 +1055,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
void *mc_list, u32 mc_list_len);
int wl1271_acx_service_period_timeout(struct wl1271 *wl);
int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold);
+int wl1271_acx_dco_itrim_params(struct wl1271 *wl);
int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
int wl1271_acx_conn_monit_params(struct wl1271 *wl);
@@ -1069,9 +1069,12 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
int wl1271_acx_cts_protect(struct wl1271 *wl,
enum acx_ctsprotect_type ctsprotect);
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
-int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates);
-int wl1271_acx_ac_cfg(struct wl1271 *wl);
-int wl1271_acx_tid_cfg(struct wl1271 *wl);
+int wl1271_acx_rate_policies(struct wl1271 *wl);
+int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
+ u8 aifsn, u16 txop);
+int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
+ u8 tsid, u8 ps_scheme, u8 ack_policy,
+ u32 apsd_conf0, u32 apsd_conf1);
int wl1271_acx_frag_threshold(struct wl1271 *wl);
int wl1271_acx_tx_config_options(struct wl1271 *wl);
int wl1271_acx_mem_cfg(struct wl1271 *wl);
@@ -1081,5 +1084,6 @@ int wl1271_acx_smart_reflex(struct wl1271 *wl);
int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
u8 version);
+int wl1271_acx_pm_config(struct wl1271 *wl);
#endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c
index b7c96454cca3..2be76ee42bb9 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.c
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.c
@@ -27,6 +27,7 @@
#include "wl1271_reg.h"
#include "wl1271_boot.h"
#include "wl1271_spi.h"
+#include "wl1271_io.h"
#include "wl1271_event.h"
static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
@@ -93,19 +94,19 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
u32 cpu_ctrl;
/* 10.5.0 run the firmware (I) */
- cpu_ctrl = wl1271_spi_read32(wl, ACX_REG_ECPU_CONTROL);
+ cpu_ctrl = wl1271_read32(wl, ACX_REG_ECPU_CONTROL);
/* 10.5.1 run the firmware (II) */
cpu_ctrl |= flag;
- wl1271_spi_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
+ wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
}
static void wl1271_boot_fw_version(struct wl1271 *wl)
{
struct wl1271_static_data static_data;
- wl1271_spi_read(wl, wl->cmd_box_addr,
- &static_data, sizeof(static_data), false);
+ wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data),
+ false);
strncpy(wl->chip.fw_ver, static_data.fw_version,
sizeof(wl->chip.fw_ver));
@@ -164,7 +165,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
memcpy(chunk, p, CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
p, addr);
- wl1271_spi_write(wl, addr, chunk, CHUNK_SIZE, false);
+ wl1271_write(wl, addr, chunk, CHUNK_SIZE, false);
chunk_num++;
}
@@ -175,7 +176,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
fw_data_len % CHUNK_SIZE, p, addr);
- wl1271_spi_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
+ wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
kfree(chunk);
return 0;
@@ -219,23 +220,14 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
size_t nvs_len, burst_len;
int i;
u32 dest_addr, val;
- u8 *nvs_ptr, *nvs, *nvs_aligned;
+ u8 *nvs_ptr, *nvs_aligned;
- nvs = wl->nvs;
- if (nvs == NULL)
+ if (wl->nvs == NULL)
return -ENODEV;
- nvs_ptr = nvs;
-
- nvs_len = wl->nvs_len;
-
- /* Update the device MAC address into the nvs */
- nvs[11] = wl->mac_addr[0];
- nvs[10] = wl->mac_addr[1];
- nvs[6] = wl->mac_addr[2];
- nvs[5] = wl->mac_addr[3];
- nvs[4] = wl->mac_addr[4];
- nvs[3] = wl->mac_addr[5];
+ /* only the first part of the NVS needs to be uploaded */
+ nvs_len = sizeof(wl->nvs->nvs);
+ nvs_ptr = (u8 *)wl->nvs->nvs;
/*
* Layout before the actual NVS tables:
@@ -265,7 +257,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT,
"nvs burst write 0x%x: 0x%x",
dest_addr, val);
- wl1271_spi_write32(wl, dest_addr, val);
+ wl1271_write32(wl, dest_addr, val);
nvs_ptr += 4;
dest_addr += 4;
@@ -277,7 +269,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
* is 7 bytes further.
*/
nvs_ptr += 7;
- nvs_len -= nvs_ptr - nvs;
+ nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs;
nvs_len = ALIGN(nvs_len, 4);
/* FIXME: The driver sets the partition here, but this is not needed,
@@ -286,15 +278,20 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
wl1271_set_partition(wl, &part_table[PART_WORK]);
/* Copy the NVS tables to a new block to ensure alignment */
- nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
- if (!nvs_aligned)
- return -ENOMEM;
+ /* FIXME: We jump 3 more bytes before uploading the NVS. It seems
+ that our NVS files have three extra zeros here. I'm not sure whether
+ the problem is in our NVS generation or we should really jumpt these
+ 3 bytes here */
+ nvs_ptr += 3;
+
+ nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); if
+ (!nvs_aligned) return -ENOMEM;
/* And finally we upload the NVS tables */
/* FIXME: In wl1271, we upload everything at once.
No endianness handling needed here?! The ref driver doesn't do
anything about it at this point */
- wl1271_spi_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
+ wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
kfree(nvs_aligned);
return 0;
@@ -303,9 +300,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
{
enable_irq(wl->irq);
- wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
- WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
- wl1271_spi_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
+ wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
+ WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
+ wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
}
static int wl1271_boot_soft_reset(struct wl1271 *wl)
@@ -314,13 +311,12 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
u32 boot_data;
/* perform soft reset */
- wl1271_spi_write32(wl, ACX_REG_SLV_SOFT_RESET,
- ACX_SLV_SOFT_RESET_BIT);
+ wl1271_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
/* SOFT_RESET is self clearing */
timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
while (1) {
- boot_data = wl1271_spi_read32(wl, ACX_REG_SLV_SOFT_RESET);
+ boot_data = wl1271_read32(wl, ACX_REG_SLV_SOFT_RESET);
wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
break;
@@ -336,10 +332,10 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
}
/* disable Rx/Tx */
- wl1271_spi_write32(wl, ENABLE, 0x0);
+ wl1271_write32(wl, ENABLE, 0x0);
/* disable auto calibration on start*/
- wl1271_spi_write32(wl, SPARE_A2, 0xffff);
+ wl1271_write32(wl, SPARE_A2, 0xffff);
return 0;
}
@@ -351,7 +347,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
- chip_id = wl1271_spi_read32(wl, CHIP_ID_B);
+ chip_id = wl1271_read32(wl, CHIP_ID_B);
wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
@@ -364,8 +360,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
loop = 0;
while (loop++ < INIT_LOOP) {
udelay(INIT_LOOP_DELAY);
- interrupt = wl1271_spi_read32(wl,
- ACX_REG_INTERRUPT_NO_CLEAR);
+ interrupt = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
if (interrupt == 0xffffffff) {
wl1271_error("error reading hardware complete "
@@ -374,8 +369,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
}
/* check that ACX_INTR_INIT_COMPLETE is enabled */
else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) {
- wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK,
- WL1271_ACX_INTR_INIT_COMPLETE);
+ wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
+ WL1271_ACX_INTR_INIT_COMPLETE);
break;
}
}
@@ -387,10 +382,10 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
}
/* get hardware config command mail box */
- wl->cmd_box_addr = wl1271_spi_read32(wl, REG_COMMAND_MAILBOX_PTR);
+ wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR);
/* get hardware config event mail box */
- wl->event_box_addr = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
/* set the working partition to its "running" mode offset */
wl1271_set_partition(wl, &part_table[PART_WORK]);
@@ -463,9 +458,9 @@ int wl1271_boot(struct wl1271 *wl)
wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
}
- wl1271_spi_write32(wl, PLL_PARAMETERS, clk);
+ wl1271_write32(wl, PLL_PARAMETERS, clk);
- pause = wl1271_spi_read32(wl, PLL_PARAMETERS);
+ pause = wl1271_read32(wl, PLL_PARAMETERS);
wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
@@ -474,10 +469,10 @@ int wl1271_boot(struct wl1271 *wl)
* 0x3ff (magic number ). How does
* this work?! */
pause |= WU_COUNTER_PAUSE_VAL;
- wl1271_spi_write32(wl, WU_COUNTER_PAUSE, pause);
+ wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
/* Continue the ELP wake up sequence */
- wl1271_spi_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
+ wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
udelay(500);
wl1271_set_partition(wl, &part_table[PART_DRPW]);
@@ -487,18 +482,18 @@ int wl1271_boot(struct wl1271 *wl)
before taking DRPw out of reset */
wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
- clk = wl1271_spi_read32(wl, DRPW_SCRATCH_START);
+ clk = wl1271_read32(wl, DRPW_SCRATCH_START);
wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
/* 2 */
clk |= (REF_CLOCK << 1) << 4;
- wl1271_spi_write32(wl, DRPW_SCRATCH_START, clk);
+ wl1271_write32(wl, DRPW_SCRATCH_START, clk);
wl1271_set_partition(wl, &part_table[PART_WORK]);
/* Disable interrupts */
- wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+ wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
ret = wl1271_boot_soft_reset(wl);
if (ret < 0)
@@ -513,23 +508,22 @@ int wl1271_boot(struct wl1271 *wl)
* ACX_EEPROMLESS_IND_REG */
wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
- wl1271_spi_write32(wl, ACX_EEPROMLESS_IND_REG,
- ACX_EEPROMLESS_IND_REG);
+ wl1271_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
- tmp = wl1271_spi_read32(wl, CHIP_ID_B);
+ tmp = wl1271_read32(wl, CHIP_ID_B);
wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
/* 6. read the EEPROM parameters */
- tmp = wl1271_spi_read32(wl, SCR_PAD2);
+ tmp = wl1271_read32(wl, SCR_PAD2);
ret = wl1271_boot_write_irq_polarity(wl);
if (ret < 0)
goto out;
/* FIXME: Need to check whether this is really what we want */
- wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
- WL1271_ACX_ALL_EVENTS_VECTOR);
+ wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
+ WL1271_ACX_ALL_EVENTS_VECTOR);
/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
* to upload_fw) */
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index c3385b3d246c..36a64e06f290 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -30,6 +30,7 @@
#include "wl1271.h"
#include "wl1271_reg.h"
#include "wl1271_spi.h"
+#include "wl1271_io.h"
#include "wl1271_acx.h"
#include "wl12xx_80211.h"
#include "wl1271_cmd.h"
@@ -57,13 +58,13 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
WARN_ON(len % 4 != 0);
- wl1271_spi_write(wl, wl->cmd_box_addr, buf, len, false);
+ wl1271_write(wl, wl->cmd_box_addr, buf, len, false);
- wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
+ wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
- intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
if (time_after(jiffies, timeout)) {
wl1271_error("command complete timeout");
@@ -73,13 +74,13 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
msleep(1);
- intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
}
/* read back the status code of the command */
if (res_len == 0)
res_len = sizeof(struct wl1271_cmd_header);
- wl1271_spi_read(wl, wl->cmd_box_addr, cmd, res_len, false);
+ wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false);
status = le16_to_cpu(cmd->status);
if (status != CMD_STATUS_SUCCESS) {
@@ -87,8 +88,8 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
ret = -EIO;
}
- wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK,
- WL1271_ACX_INTR_CMD_COMPLETE);
+ wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
+ WL1271_ACX_INTR_CMD_COMPLETE);
out:
return ret;
@@ -191,23 +192,19 @@ static int wl1271_cmd_cal(struct wl1271 *wl)
int wl1271_cmd_general_parms(struct wl1271 *wl)
{
struct wl1271_general_parms_cmd *gen_parms;
- struct conf_general_parms *g = &wl->conf.init.genparam;
int ret;
+ if (!wl->nvs)
+ return -ENODEV;
+
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
if (!gen_parms)
return -ENOMEM;
gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
- gen_parms->ref_clk = g->ref_clk;
- gen_parms->settling_time = g->settling_time;
- gen_parms->clk_valid_on_wakeup = g->clk_valid_on_wakeup;
- gen_parms->dc2dcmode = g->dc2dcmode;
- gen_parms->single_dual_band = g->single_dual_band;
- gen_parms->tx_bip_fem_autodetect = g->tx_bip_fem_autodetect;
- gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer;
- gen_parms->settings = g->settings;
+ memcpy(gen_parms->params, wl->nvs->general_params,
+ WL1271_NVS_GENERAL_PARAMS_SIZE);
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
if (ret < 0)
@@ -220,8 +217,11 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
int wl1271_cmd_radio_parms(struct wl1271 *wl)
{
struct wl1271_radio_parms_cmd *radio_parms;
- struct conf_radio_parms *r = &wl->conf.init.radioparam;
- int i, ret;
+ struct conf_radio_parms *rparam = &wl->conf.init.radioparam;
+ int ret;
+
+ if (!wl->nvs)
+ return -ENODEV;
radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
if (!radio_parms)
@@ -229,60 +229,13 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
- /* Static radio parameters */
- radio_parms->rx_trace_loss = r->rx_trace_loss;
- radio_parms->tx_trace_loss = r->tx_trace_loss;
- memcpy(radio_parms->rx_rssi_and_proc_compens,
- r->rx_rssi_and_proc_compens,
- CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE);
-
- memcpy(radio_parms->rx_trace_loss_5, r->rx_trace_loss_5,
- CONF_NUMBER_OF_SUB_BANDS_5);
- memcpy(radio_parms->tx_trace_loss_5, r->tx_trace_loss_5,
- CONF_NUMBER_OF_SUB_BANDS_5);
- memcpy(radio_parms->rx_rssi_and_proc_compens_5,
- r->rx_rssi_and_proc_compens_5,
- CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE);
-
- /* Dynamic radio parameters */
- radio_parms->tx_ref_pd_voltage = cpu_to_le16(r->tx_ref_pd_voltage);
- radio_parms->tx_ref_power = r->tx_ref_power;
- radio_parms->tx_offset_db = r->tx_offset_db;
-
- memcpy(radio_parms->tx_rate_limits_normal, r->tx_rate_limits_normal,
- CONF_NUMBER_OF_RATE_GROUPS);
- memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded,
- CONF_NUMBER_OF_RATE_GROUPS);
-
- memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b,
- CONF_NUMBER_OF_CHANNELS_2_4);
- memcpy(radio_parms->tx_channel_limits_ofdm, r->tx_channel_limits_ofdm,
- CONF_NUMBER_OF_CHANNELS_2_4);
- memcpy(radio_parms->tx_pdv_rate_offsets, r->tx_pdv_rate_offsets,
- CONF_NUMBER_OF_RATE_GROUPS);
- memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS);
-
- radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss;
-
- for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++)
- radio_parms->tx_ref_pd_voltage_5[i] =
- cpu_to_le16(r->tx_ref_pd_voltage_5[i]);
- memcpy(radio_parms->tx_ref_power_5, r->tx_ref_power_5,
- CONF_NUMBER_OF_SUB_BANDS_5);
- memcpy(radio_parms->tx_offset_db_5, r->tx_offset_db_5,
- CONF_NUMBER_OF_SUB_BANDS_5);
- memcpy(radio_parms->tx_rate_limits_normal_5,
- r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS);
- memcpy(radio_parms->tx_rate_limits_degraded_5,
- r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS);
- memcpy(radio_parms->tx_channel_limits_ofdm_5,
- r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5);
- memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5,
- CONF_NUMBER_OF_RATE_GROUPS);
- memcpy(radio_parms->tx_ibias_5, r->tx_ibias_5,
- CONF_NUMBER_OF_RATE_GROUPS);
- memcpy(radio_parms->rx_fem_insertion_loss_5,
- r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5);
+ memcpy(radio_parms->stat_radio_params, wl->nvs->stat_radio_params,
+ WL1271_NVS_STAT_RADIO_PARAMS_SIZE);
+ memcpy(radio_parms->dyn_radio_params,
+ wl->nvs->dyn_radio_params[rparam->fem],
+ WL1271_NVS_DYN_RADIO_PARAMS_SIZE);
+
+ /* FIXME: current NVS is missing 5GHz parameters */
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
radio_parms, sizeof(*radio_parms));
@@ -311,19 +264,6 @@ int wl1271_cmd_join(struct wl1271 *wl)
do_cal = false;
}
- /* FIXME: This is a workaround, because with the current stack, we
- * cannot know when we have disassociated. So, if we have already
- * joined, we disconnect before joining again. */
- if (wl->joined) {
- ret = wl1271_cmd_disconnect(wl);
- if (ret < 0) {
- wl1271_error("failed to disconnect before rejoining");
- goto out;
- }
-
- wl->joined = false;
- }
-
join = kzalloc(sizeof(*join), GFP_KERNEL);
if (!join) {
ret = -ENOMEM;
@@ -388,8 +328,6 @@ int wl1271_cmd_join(struct wl1271 *wl)
goto out_free;
}
- wl->joined = true;
-
/*
* ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
* simplify locking we just sleep instead, for now
@@ -487,7 +425,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
return 0;
}
-int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
+int wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
{
struct cmd_enabledisable_path *cmd;
int ret;
@@ -501,7 +439,8 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
goto out;
}
- cmd->channel = channel;
+ /* the channel here is only used for calibration, so hardcoded to 1 */
+ cmd->channel = 1;
if (enable) {
cmd_rx = CMD_ENABLE_RX;
@@ -514,29 +453,29 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("rx %s cmd for channel %d failed",
- enable ? "start" : "stop", channel);
+ enable ? "start" : "stop", cmd->channel);
goto out;
}
wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d",
- enable ? "start" : "stop", channel);
+ enable ? "start" : "stop", cmd->channel);
ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("tx %s cmd for channel %d failed",
- enable ? "start" : "stop", channel);
+ enable ? "start" : "stop", cmd->channel);
return ret;
}
wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
- enable ? "start" : "stop", channel);
+ enable ? "start" : "stop", cmd->channel);
out:
kfree(cmd);
return ret;
}
-int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
+int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
{
struct wl1271_cmd_ps_params *ps_params = NULL;
int ret = 0;
@@ -557,7 +496,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
}
ps_params->ps_mode = ps_mode;
- ps_params->send_null_data = 1;
+ ps_params->send_null_data = send;
ps_params->retries = 5;
ps_params->hang_over_period = 128;
ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
@@ -636,7 +575,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
channels = wl->hw->wiphy->bands[ieee_band]->channels;
n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
- if (wl->scanning)
+ if (test_bit(WL1271_FLAG_SCANNING, &wl->flags))
return -EINVAL;
params = kzalloc(sizeof(*params), GFP_KERNEL);
@@ -711,7 +650,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
- wl->scanning = true;
+ set_bit(WL1271_FLAG_SCANNING, &wl->flags);
if (wl1271_11a_enabled()) {
wl->scan.state = band;
if (band == WL1271_SCAN_BAND_DUAL) {
@@ -729,7 +668,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0);
if (ret < 0) {
wl1271_error("SCAN failed");
- wl->scanning = false;
+ clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
goto out;
}
@@ -1003,7 +942,7 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_warning("could not set keys");
- goto out;
+ goto out;
}
out:
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h
index b4fa4acb9229..2dc06c73532b 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h
@@ -37,8 +37,8 @@ int wl1271_cmd_join(struct wl1271 *wl);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
-int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable);
-int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
+int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
+int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
size_t len);
int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
@@ -428,67 +428,24 @@ struct wl1271_general_parms_cmd {
struct wl1271_cmd_test_header test;
- u8 ref_clk;
- u8 settling_time;
- u8 clk_valid_on_wakeup;
- u8 dc2dcmode;
- u8 single_dual_band;
-
- u8 tx_bip_fem_autodetect;
- u8 tx_bip_fem_manufacturer;
- u8 settings;
+ u8 params[WL1271_NVS_GENERAL_PARAMS_SIZE];
+ s8 reserved[23];
} __attribute__ ((packed));
+#define WL1271_STAT_RADIO_PARAMS_5_SIZE 29
+#define WL1271_DYN_RADIO_PARAMS_5_SIZE 104
+
struct wl1271_radio_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
- /* Static radio parameters */
- /* 2.4GHz */
- u8 rx_trace_loss;
- u8 tx_trace_loss;
- s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
-
- /* 5GHz */
- u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
- u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
- s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
-
- /* Dynamic radio parameters */
- /* 2.4GHz */
- __le16 tx_ref_pd_voltage;
- s8 tx_ref_power;
- s8 tx_offset_db;
-
- s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
- s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
-
- s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
- s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
- s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS];
-
- u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
- u8 rx_fem_insertion_loss;
+ u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE];
+ u8 stat_radio_params_5[WL1271_STAT_RADIO_PARAMS_5_SIZE];
- u8 padding2;
-
- /* 5GHz */
- __le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
- s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
- s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
-
- s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
- s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
-
- s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
- s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
-
- /* FIXME: this is inconsistent with the types for 2.4GHz */
- s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
- s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
-
- u8 padding3[2];
+ u8 dyn_radio_params[WL1271_NVS_DYN_RADIO_PARAMS_SIZE];
+ u8 reserved;
+ u8 dyn_radio_params_5[WL1271_DYN_RADIO_PARAMS_5_SIZE];
} __attribute__ ((packed));
struct wl1271_cmd_cal_channel_tune {
diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h
index 565373ede265..6f9e75cc5640 100644
--- a/drivers/net/wireless/wl12xx/wl1271_conf.h
+++ b/drivers/net/wireless/wl12xx/wl1271_conf.h
@@ -258,7 +258,8 @@ struct conf_rx_settings {
#define CONF_TX_MAX_RATE_CLASSES 8
#define CONF_TX_RATE_MASK_UNSPECIFIED 0
-#define CONF_TX_RATE_MASK_ALL 0x1eff
+#define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \
+ CONF_HW_BIT_RATE_2MBPS)
#define CONF_TX_RATE_RETRY_LIMIT 10
struct conf_tx_rate_class {
@@ -722,31 +723,6 @@ struct conf_conn_settings {
u8 psm_entry_retries;
};
-#define CONF_SR_ERR_TBL_MAX_VALUES 14
-
-struct conf_mart_reflex_err_table {
- /*
- * Length of the error table values table.
- *
- * Range: 0 - CONF_SR_ERR_TBL_MAX_VALUES
- */
- u8 len;
-
- /*
- * Smart Reflex error table upper limit.
- *
- * Range: s8
- */
- s8 upper_limit;
-
- /*
- * Smart Reflex error table values.
- *
- * Range: s8
- */
- s8 values[CONF_SR_ERR_TBL_MAX_VALUES];
-};
-
enum {
CONF_REF_CLK_19_2_E,
CONF_REF_CLK_26_E,
@@ -759,64 +735,6 @@ enum single_dual_band_enum {
CONF_DUAL_BAND
};
-struct conf_general_parms {
- /*
- * RF Reference Clock type / speed
- *
- * Range: CONF_REF_CLK_*
- */
- u8 ref_clk;
-
- /*
- * Settling time of the reference clock after boot.
- *
- * Range: u8
- */
- u8 settling_time;
-
- /*
- * Flag defining whether clock is valid on wakeup.
- *
- * Range: 0 - not valid on wakeup, 1 - valid on wakeup
- */
- u8 clk_valid_on_wakeup;
-
- /*
- * DC-to-DC mode.
- *
- * Range: Unknown
- */
- u8 dc2dcmode;
-
- /*
- * Flag defining whether used as single or dual-band.
- *
- * Range: CONF_SINGLE_BAND, CONF_DUAL_BAND
- */
- u8 single_dual_band;
-
- /*
- * TX bip fem autodetect flag.
- *
- * Range: Unknown
- */
- u8 tx_bip_fem_autodetect;
-
- /*
- * TX bip gem manufacturer.
- *
- * Range: Unknown
- */
- u8 tx_bip_fem_manufacturer;
-
- /*
- * Settings flags.
- *
- * Range: Unknown
- */
- u8 settings;
-};
-
#define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15
#define CONF_NUMBER_OF_SUB_BANDS_5 7
#define CONF_NUMBER_OF_RATE_GROUPS 6
@@ -825,87 +743,43 @@ struct conf_general_parms {
struct conf_radio_parms {
/*
- * Static radio parameters for 2.4GHz
- *
- * Range: unknown
- */
- u8 rx_trace_loss;
- u8 tx_trace_loss;
- s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
-
- /*
- * Static radio parameters for 5GHz
- *
- * Range: unknown
- */
- u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
- u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
- s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
-
- /*
- * Dynamic radio parameters for 2.4GHz
+ * FEM parameter set to use
*
- * Range: unknown
+ * Range: 0 or 1
*/
- s16 tx_ref_pd_voltage;
- s8 tx_ref_power;
- s8 tx_offset_db;
-
- s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
- s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
-
- s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
- s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
- s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS];
-
- u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
- u8 rx_fem_insertion_loss;
+ u8 fem;
+};
+struct conf_init_settings {
/*
- * Dynamic radio parameters for 5GHz
- *
- * Range: unknown
+ * Configure radio parameters.
*/
- s16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
- s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
- s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
-
- s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
- s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
-
- s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
- s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
+ struct conf_radio_parms radioparam;
- /* FIXME: this is inconsistent with the types for 2.4GHz */
- s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
- s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
};
-#define CONF_SR_ERR_TBL_COUNT 3
+struct conf_itrim_settings {
+ /* enable dco itrim */
+ u8 enable;
-struct conf_init_settings {
- /*
- * Configure Smart Reflex error table values.
- */
- struct conf_mart_reflex_err_table sr_err_tbl[CONF_SR_ERR_TBL_COUNT];
+ /* moderation timeout in microsecs from the last TX */
+ u32 timeout;
+};
+struct conf_pm_config_settings {
/*
- * Smart Reflex enable flag.
+ * Host clock settling time
*
- * Range: 1 - Smart Reflex enabled, 0 - Smart Reflex disabled
- */
- u8 sr_enable;
-
- /*
- * Configure general parameters.
+ * Range: 0 - 30000 us
*/
- struct conf_general_parms genparam;
+ u32 host_clk_settling_time;
/*
- * Configure radio parameters.
+ * Host fast wakeup support
+ *
+ * Range: true, false
*/
- struct conf_radio_parms radioparam;
-
+ bool host_fast_wakeup_support;
};
struct conf_drv_settings {
@@ -914,6 +788,8 @@ struct conf_drv_settings {
struct conf_tx_settings tx;
struct conf_conn_settings conn;
struct conf_init_settings init;
+ struct conf_itrim_settings itrim;
+ struct conf_pm_config_settings pm_config;
};
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c
index c1805e5f8964..8d7588ca68fd 100644
--- a/drivers/net/wireless/wl12xx/wl1271_debugfs.c
+++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.c
@@ -237,6 +237,64 @@ static const struct file_operations tx_queue_len_ops = {
.open = wl1271_open_file_generic,
};
+static ssize_t gpio_power_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+
+ int res;
+ char buf[10];
+
+ res = scnprintf(buf, sizeof(buf), "%d\n", state);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, res);
+}
+
+static ssize_t gpio_power_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ char buf[10];
+ size_t len;
+ unsigned long value;
+ int ret;
+
+ mutex_lock(&wl->mutex);
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ buf[len] = '\0';
+
+ ret = strict_strtoul(buf, 0, &value);
+ if (ret < 0) {
+ wl1271_warning("illegal value in gpio_power");
+ goto out;
+ }
+
+ if (value) {
+ wl->set_power(true);
+ set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+ } else {
+ wl->set_power(false);
+ clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+ }
+
+out:
+ mutex_unlock(&wl->mutex);
+ return count;
+}
+
+static const struct file_operations gpio_power_ops = {
+ .read = gpio_power_read,
+ .write = gpio_power_write,
+ .open = wl1271_open_file_generic
+};
+
static void wl1271_debugfs_delete_files(struct wl1271 *wl)
{
DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
@@ -333,6 +391,8 @@ static void wl1271_debugfs_delete_files(struct wl1271 *wl)
DEBUGFS_DEL(tx_queue_len);
DEBUGFS_DEL(retry_count);
DEBUGFS_DEL(excessive_retries);
+
+ DEBUGFS_DEL(gpio_power);
}
static int wl1271_debugfs_add_files(struct wl1271 *wl)
@@ -434,6 +494,8 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl)
DEBUGFS_ADD(retry_count, wl->debugfs.rootdir);
DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir);
+ DEBUGFS_ADD(gpio_power, wl->debugfs.rootdir);
+
out:
if (ret < 0)
wl1271_debugfs_delete_files(wl);
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c
index d13fdd99c85c..7468ef10194b 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.c
+++ b/drivers/net/wireless/wl12xx/wl1271_event.c
@@ -24,6 +24,7 @@
#include "wl1271.h"
#include "wl1271_reg.h"
#include "wl1271_spi.h"
+#include "wl1271_io.h"
#include "wl1271_event.h"
#include "wl1271_ps.h"
#include "wl12xx_80211.h"
@@ -35,7 +36,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
wl1271_debug(DEBUG_EVENT, "status: 0x%x",
mbox->scheduled_scan_status);
- if (wl->scanning) {
+ if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
NULL, size);
@@ -43,7 +44,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
* to the wl1271_cmd_scan function that we are not
* scanning as it checks that.
*/
- wl->scanning = false;
+ clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
wl->scan.active,
wl->scan.high_prio,
@@ -62,7 +63,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, false);
mutex_lock(&wl->mutex);
- wl->scanning = false;
+ clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
}
}
return 0;
@@ -78,25 +79,61 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
switch (mbox->ps_status) {
case EVENT_ENTER_POWER_SAVE_FAIL:
- if (!wl->psm) {
+ wl1271_debug(DEBUG_PSM, "PSM entry failed");
+
+ if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
+ /* remain in active mode */
wl->psm_entry_retry = 0;
break;
}
if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) {
wl->psm_entry_retry++;
- ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+ ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
+ true);
} else {
wl1271_error("PSM entry failed, giving up.\n");
+ /* FIXME: this may need to be reconsidered. for now it
+ is not possible to indicate to the mac80211
+ afterwards that PSM entry failed. To maximize
+ functionality (receiving data and remaining
+ associated) make sure that we are in sync with the
+ AP in regard of PSM mode. */
+ ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
+ false);
wl->psm_entry_retry = 0;
- *beacon_loss = true;
}
break;
case EVENT_ENTER_POWER_SAVE_SUCCESS:
wl->psm_entry_retry = 0;
+
+ /* enable beacon filtering */
+ ret = wl1271_acx_beacon_filter_opt(wl, true);
+ if (ret < 0)
+ break;
+
+ /* enable beacon early termination */
+ ret = wl1271_acx_bet_enable(wl, true);
+ if (ret < 0)
+ break;
+
+ /* go to extremely low power mode */
+ wl1271_ps_elp_sleep(wl);
+ if (ret < 0)
+ break;
break;
case EVENT_EXIT_POWER_SAVE_FAIL:
- wl1271_info("PSM exit failed");
+ wl1271_debug(DEBUG_PSM, "PSM exit failed");
+
+ if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
+ wl->psm_entry_retry = 0;
+ break;
+ }
+
+ /* make sure the firmware goes to active mode - the frame to
+ be sent next will indicate to the AP, that we are active. */
+ ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
+ false);
break;
case EVENT_EXIT_POWER_SAVE_SUCCESS:
default:
@@ -136,7 +173,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
* filtering) is enabled. Without PSM, the stack will receive all
* beacons and can detect beacon loss by itself.
*/
- if (vector & BSS_LOSE_EVENT_ID && wl->psm) {
+ if (vector & BSS_LOSE_EVENT_ID &&
+ test_bit(WL1271_FLAG_PSM, &wl->flags)) {
wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
/* indicate to the stack, that beacons have been lost */
@@ -150,7 +188,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
return ret;
}
- if (beacon_loss) {
+ if (wl->vif && beacon_loss) {
/* Obviously, it's dangerous to release the mutex while
we are holding many of the variables in the wl struct.
That's why it's done last in the function, and care must
@@ -177,14 +215,14 @@ int wl1271_event_unmask(struct wl1271 *wl)
void wl1271_event_mbox_config(struct wl1271 *wl)
{
- wl->mbox_ptr[0] = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
wl->mbox_ptr[0], wl->mbox_ptr[1]);
}
-int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack)
+int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
{
struct event_mailbox mbox;
int ret;
@@ -195,8 +233,8 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack)
return -EINVAL;
/* first we read the mbox descriptor */
- wl1271_spi_read(wl, wl->mbox_ptr[mbox_num], &mbox,
- sizeof(struct event_mailbox), false);
+ wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox,
+ sizeof(struct event_mailbox), false);
/* process the descriptor */
ret = wl1271_event_process(wl, &mbox);
@@ -204,9 +242,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack)
return ret;
/* then we let the firmware know it can go on...*/
- if (do_ack)
- wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG,
- INTR_TRIG_EVENT_ACK);
+ wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
return 0;
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h
index 4e3f55ebb1a8..278f9206aa56 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.h
+++ b/drivers/net/wireless/wl12xx/wl1271_event.h
@@ -112,6 +112,6 @@ struct event_mailbox {
int wl1271_event_unmask(struct wl1271 *wl);
void wl1271_event_mbox_config(struct wl1271 *wl);
-int wl1271_event_handle(struct wl1271 *wl, u8 mbox, bool do_ack);
+int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c
index 11249b436cf1..86c30a86a456 100644
--- a/drivers/net/wireless/wl12xx/wl1271_init.c
+++ b/drivers/net/wireless/wl12xx/wl1271_init.c
@@ -49,7 +49,7 @@ static int wl1271_init_hwenc_config(struct wl1271 *wl)
return 0;
}
-static int wl1271_init_templates_config(struct wl1271 *wl)
+int wl1271_init_templates_config(struct wl1271 *wl)
{
int ret;
@@ -113,7 +113,7 @@ static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter)
return 0;
}
-static int wl1271_init_phy_config(struct wl1271 *wl)
+int wl1271_init_phy_config(struct wl1271 *wl)
{
int ret;
@@ -156,7 +156,7 @@ static int wl1271_init_beacon_filter(struct wl1271 *wl)
return 0;
}
-static int wl1271_init_pta(struct wl1271 *wl)
+int wl1271_init_pta(struct wl1271 *wl)
{
int ret;
@@ -171,7 +171,7 @@ static int wl1271_init_pta(struct wl1271 *wl)
return 0;
}
-static int wl1271_init_energy_detection(struct wl1271 *wl)
+int wl1271_init_energy_detection(struct wl1271 *wl)
{
int ret;
@@ -195,7 +195,9 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
int wl1271_hw_init(struct wl1271 *wl)
{
- int ret;
+ struct conf_tx_ac_category *conf_ac;
+ struct conf_tx_tid *conf_tid;
+ int ret, i;
ret = wl1271_cmd_general_parms(wl);
if (ret < 0)
@@ -229,6 +231,10 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
+ ret = wl1271_acx_dco_itrim_params(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
/* Initialize connection monitoring thresholds */
ret = wl1271_acx_conn_monit_params(wl);
if (ret < 0)
@@ -270,22 +276,36 @@ int wl1271_hw_init(struct wl1271 *wl)
goto out_free_memmap;
/* Default TID configuration */
- ret = wl1271_acx_tid_cfg(wl);
- if (ret < 0)
- goto out_free_memmap;
+ for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
+ conf_tid = &wl->conf.tx.tid_conf[i];
+ ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
+ conf_tid->channel_type,
+ conf_tid->tsid,
+ conf_tid->ps_scheme,
+ conf_tid->ack_policy,
+ conf_tid->apsd_conf[0],
+ conf_tid->apsd_conf[1]);
+ if (ret < 0)
+ goto out_free_memmap;
+ }
/* Default AC configuration */
- ret = wl1271_acx_ac_cfg(wl);
- if (ret < 0)
- goto out_free_memmap;
+ for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
+ conf_ac = &wl->conf.tx.ac_conf[i];
+ ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
+ conf_ac->cw_max, conf_ac->aifsn,
+ conf_ac->tx_op_limit);
+ if (ret < 0)
+ goto out_free_memmap;
+ }
/* Configure TX rate classes */
- ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_ALL);
+ ret = wl1271_acx_rate_policies(wl);
if (ret < 0)
goto out_free_memmap;
/* Enable data path */
- ret = wl1271_cmd_data_path(wl, wl->channel, 1);
+ ret = wl1271_cmd_data_path(wl, 1);
if (ret < 0)
goto out_free_memmap;
@@ -299,8 +319,8 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
- /* Configure smart reflex */
- ret = wl1271_acx_smart_reflex(wl);
+ /* configure PM */
+ ret = wl1271_acx_pm_config(wl);
if (ret < 0)
goto out_free_memmap;
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.h b/drivers/net/wireless/wl12xx/wl1271_init.h
index 930677fbe852..bc26f8c53b91 100644
--- a/drivers/net/wireless/wl12xx/wl1271_init.h
+++ b/drivers/net/wireless/wl12xx/wl1271_init.h
@@ -27,6 +27,10 @@
#include "wl1271.h"
int wl1271_hw_init_power_auth(struct wl1271 *wl);
+int wl1271_init_templates_config(struct wl1271 *wl);
+int wl1271_init_phy_config(struct wl1271 *wl);
+int wl1271_init_pta(struct wl1271 *wl);
+int wl1271_init_energy_detection(struct wl1271 *wl);
int wl1271_hw_init(struct wl1271 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_io.c b/drivers/net/wireless/wl12xx/wl1271_io.c
new file mode 100644
index 000000000000..5cd94d5666c2
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_io.c
@@ -0,0 +1,213 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/crc7.h>
+#include <linux/spi/spi.h>
+
+#include "wl1271.h"
+#include "wl12xx_80211.h"
+#include "wl1271_spi.h"
+#include "wl1271_io.h"
+
+static int wl1271_translate_addr(struct wl1271 *wl, int addr)
+{
+ /*
+ * To translate, first check to which window of addresses the
+ * particular address belongs. Then subtract the starting address
+ * of that window from the address. Then, add offset of the
+ * translated region.
+ *
+ * The translated regions occur next to each other in physical device
+ * memory, so just add the sizes of the preceeding address regions to
+ * get the offset to the new region.
+ *
+ * Currently, only the two first regions are addressed, and the
+ * assumption is that all addresses will fall into either of those
+ * two.
+ */
+ if ((addr >= wl->part.reg.start) &&
+ (addr < wl->part.reg.start + wl->part.reg.size))
+ return addr - wl->part.reg.start + wl->part.mem.size;
+ else
+ return addr - wl->part.mem.start;
+}
+
+/* Set the SPI partitions to access the chip addresses
+ *
+ * To simplify driver code, a fixed (virtual) memory map is defined for
+ * register and memory addresses. Because in the chipset, in different stages
+ * of operation, those addresses will move around, an address translation
+ * mechanism is required.
+ *
+ * There are four partitions (three memory and one register partition),
+ * which are mapped to two different areas of the hardware memory.
+ *
+ * Virtual address
+ * space
+ *
+ * | |
+ * ...+----+--> mem.start
+ * Physical address ... | |
+ * space ... | | [PART_0]
+ * ... | |
+ * 00000000 <--+----+... ...+----+--> mem.start + mem.size
+ * | | ... | |
+ * |MEM | ... | |
+ * | | ... | |
+ * mem.size <--+----+... | | {unused area)
+ * | | ... | |
+ * |REG | ... | |
+ * mem.size | | ... | |
+ * + <--+----+... ...+----+--> reg.start
+ * reg.size | | ... | |
+ * |MEM2| ... | | [PART_1]
+ * | | ... | |
+ * ...+----+--> reg.start + reg.size
+ * | |
+ *
+ */
+int wl1271_set_partition(struct wl1271 *wl,
+ struct wl1271_partition_set *p)
+{
+ /* copy partition info */
+ memcpy(&wl->part, p, sizeof(*p));
+
+ wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ p->mem.start, p->mem.size);
+ wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ p->reg.start, p->reg.size);
+ wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X",
+ p->mem2.start, p->mem2.size);
+ wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X",
+ p->mem3.start, p->mem3.size);
+
+ /* write partition info to the chipset */
+ wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
+ wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
+ wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
+ wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
+ wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
+ wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
+ wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
+
+ return 0;
+}
+
+void wl1271_io_reset(struct wl1271 *wl)
+{
+ wl1271_spi_reset(wl);
+}
+
+void wl1271_io_init(struct wl1271 *wl)
+{
+ wl1271_spi_init(wl);
+}
+
+void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
+{
+ wl1271_spi_raw_write(wl, addr, buf, len, fixed);
+}
+
+void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
+{
+ wl1271_spi_raw_read(wl, addr, buf, len, fixed);
+}
+
+void wl1271_read(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed)
+{
+ int physical;
+
+ physical = wl1271_translate_addr(wl, addr);
+
+ wl1271_spi_raw_read(wl, physical, buf, len, fixed);
+}
+
+void wl1271_write(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed)
+{
+ int physical;
+
+ physical = wl1271_translate_addr(wl, addr);
+
+ wl1271_spi_raw_write(wl, physical, buf, len, fixed);
+}
+
+u32 wl1271_read32(struct wl1271 *wl, int addr)
+{
+ return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
+}
+
+void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
+{
+ wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val);
+}
+
+void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
+{
+ /* write address >> 1 + 0x30000 to OCP_POR_CTR */
+ addr = (addr >> 1) + 0x30000;
+ wl1271_write32(wl, OCP_POR_CTR, addr);
+
+ /* write value to OCP_POR_WDATA */
+ wl1271_write32(wl, OCP_DATA_WRITE, val);
+
+ /* write 1 to OCP_CMD */
+ wl1271_write32(wl, OCP_CMD, OCP_CMD_WRITE);
+}
+
+u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
+{
+ u32 val;
+ int timeout = OCP_CMD_LOOP;
+
+ /* write address >> 1 + 0x30000 to OCP_POR_CTR */
+ addr = (addr >> 1) + 0x30000;
+ wl1271_write32(wl, OCP_POR_CTR, addr);
+
+ /* write 2 to OCP_CMD */
+ wl1271_write32(wl, OCP_CMD, OCP_CMD_READ);
+
+ /* poll for data ready */
+ do {
+ val = wl1271_read32(wl, OCP_DATA_READ);
+ } while (!(val & OCP_READY_MASK) && --timeout);
+
+ if (!timeout) {
+ wl1271_warning("Top register access timed out.");
+ return 0xffff;
+ }
+
+ /* check data status and return if OK */
+ if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK)
+ return val & 0xffff;
+ else {
+ wl1271_warning("Top register access returned error.");
+ return 0xffff;
+ }
+}
+
diff --git a/drivers/net/wireless/wl12xx/wl1271_io.h b/drivers/net/wireless/wl12xx/wl1271_io.h
new file mode 100644
index 000000000000..fa9a0b35788f
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_io.h
@@ -0,0 +1,68 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
+ * Copyright (C) 2008-2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_IO_H__
+#define __WL1271_IO_H__
+
+struct wl1271;
+
+void wl1271_io_reset(struct wl1271 *wl);
+void wl1271_io_init(struct wl1271 *wl);
+
+/* Raw target IO, address is not translated */
+void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed);
+void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed);
+
+/* Translated target IO */
+void wl1271_read(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+void wl1271_write(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+u32 wl1271_read32(struct wl1271 *wl, int addr);
+void wl1271_write32(struct wl1271 *wl, int addr, u32 val);
+
+/* Top Register IO */
+void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val);
+u16 wl1271_top_reg_read(struct wl1271 *wl, int addr);
+
+int wl1271_set_partition(struct wl1271 *wl,
+ struct wl1271_partition_set *p);
+
+static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
+{
+ wl1271_raw_read(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
+
+ return wl->buffer_32;
+}
+
+static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
+{
+ wl->buffer_32 = val;
+ wl1271_raw_write(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
+}
+#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index b62c00ff42fe..2a864b24291d 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -1,7 +1,7 @@
/*
* This file is part of wl1271
*
- * Copyright (C) 2008-2009 Nokia Corporation
+ * Copyright (C) 2008-2010 Nokia Corporation
*
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
@@ -38,6 +38,7 @@
#include "wl12xx_80211.h"
#include "wl1271_reg.h"
#include "wl1271_spi.h"
+#include "wl1271_io.h"
#include "wl1271_event.h"
#include "wl1271_tx.h"
#include "wl1271_rx.h"
@@ -46,6 +47,9 @@
#include "wl1271_debugfs.h"
#include "wl1271_cmd.h"
#include "wl1271_boot.h"
+#include "wl1271_testmode.h"
+
+#define WL1271_BOOT_RETRIES 3
static struct conf_drv_settings default_conf = {
.sg = {
@@ -67,16 +71,17 @@ static struct conf_drv_settings default_conf = {
.ps_poll_timeout = 15,
.upsd_timeout = 15,
.rts_threshold = 2347,
- .rx_cca_threshold = 0xFFEF,
- .irq_blk_threshold = 0,
- .irq_pkt_threshold = USHORT_MAX,
- .irq_timeout = 5,
+ .rx_cca_threshold = 0,
+ .irq_blk_threshold = 0xFFFF,
+ .irq_pkt_threshold = 0,
+ .irq_timeout = 600,
.queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
},
.tx = {
.tx_energy_detection = 0,
.rc_conf = {
- .enabled_rates = CONF_TX_RATE_MASK_UNSPECIFIED,
+ .enabled_rates = CONF_HW_BIT_RATE_1MBPS |
+ CONF_HW_BIT_RATE_2MBPS,
.short_retry_limit = 10,
.long_retry_limit = 10,
.aflags = 0
@@ -172,8 +177,8 @@ static struct conf_drv_settings default_conf = {
}
},
.frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
- .tx_compl_timeout = 5,
- .tx_compl_threshold = 5
+ .tx_compl_timeout = 700,
+ .tx_compl_threshold = 4
},
.conn = {
.wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
@@ -186,12 +191,12 @@ static struct conf_drv_settings default_conf = {
.rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
}
},
- .synch_fail_thold = 5,
+ .synch_fail_thold = 10,
.bss_lose_timeout = 100,
.beacon_rx_timeout = 10000,
.broadcast_timeout = 20000,
.rx_broadcast_in_ps = 1,
- .ps_poll_threshold = 4,
+ .ps_poll_threshold = 20,
.sig_trigger_count = 2,
.sig_trigger = {
[0] = {
@@ -226,97 +231,17 @@ static struct conf_drv_settings default_conf = {
.psm_entry_retries = 3
},
.init = {
- .sr_err_tbl = {
- [0] = {
- .len = 7,
- .upper_limit = 0x03,
- .values = {
- 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
- 0x00 }
- },
- [1] = {
- .len = 7,
- .upper_limit = 0x03,
- .values = {
- 0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8,
- 0x00 }
- },
- [2] = {
- .len = 7,
- .upper_limit = 0x03,
- .values = {
- 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
- 0x00 }
- }
- },
- .sr_enable = 1,
- .genparam = {
- .ref_clk = CONF_REF_CLK_38_4_E,
- .settling_time = 5,
- .clk_valid_on_wakeup = 0,
- .dc2dcmode = 0,
- .single_dual_band = CONF_SINGLE_BAND,
- .tx_bip_fem_autodetect = 0,
- .tx_bip_fem_manufacturer = 1,
- .settings = 1,
- },
.radioparam = {
- .rx_trace_loss = 10,
- .tx_trace_loss = 10,
- .rx_rssi_and_proc_compens = {
- 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
- 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8,
- 0x00, 0x0a, 0x14 },
- .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
- .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
- .rx_rssi_and_proc_compens_5 = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00 },
- .tx_ref_pd_voltage = 0x24e,
- .tx_ref_power = 0x78,
- .tx_offset_db = 0x0,
- .tx_rate_limits_normal = {
- 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 },
- .tx_rate_limits_degraded = {
- 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
- .tx_channel_limits_11b = {
- 0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
- 0x22, 0x50 },
- .tx_channel_limits_ofdm = {
- 0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
- 0x20, 0x50 },
- .tx_pdv_rate_offsets = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- .tx_ibias = {
- 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 },
- .rx_fem_insertion_loss = 0x14,
- .tx_ref_pd_voltage_5 = {
- 0x0190, 0x01a4, 0x01c3, 0x01d8,
- 0x020a, 0x021c },
- .tx_ref_power_5 = {
- 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
- .tx_offset_db_5 = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- .tx_rate_limits_normal_5 = {
- 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
- .tx_rate_limits_degraded_5 = {
- 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
- .tx_channel_limits_ofdm_5 = {
- 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x50 },
- .tx_pdv_rate_offsets_5 = {
- 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 },
- .tx_ibias_5 = {
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
- .rx_fem_insertion_loss_5 = {
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }
+ .fem = 1,
}
+ },
+ .itrim = {
+ .enable = false,
+ .timeout = 50000,
+ },
+ .pm_config = {
+ .host_clk_settling_time = 5000,
+ .host_fast_wakeup_support = false
}
};
@@ -337,15 +262,14 @@ static void wl1271_conf_init(struct wl1271 *wl)
/* apply driver default configuration */
memcpy(&wl->conf, &default_conf, sizeof(default_conf));
-
- if (wl1271_11a_enabled())
- wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND;
}
static int wl1271_plt_init(struct wl1271 *wl)
{
- int ret;
+ struct conf_tx_ac_category *conf_ac;
+ struct conf_tx_tid *conf_tid;
+ int ret, i;
ret = wl1271_cmd_general_parms(wl);
if (ret < 0)
@@ -355,15 +279,89 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0)
return ret;
- ret = wl1271_acx_init_mem_config(wl);
+ ret = wl1271_init_templates_config(wl);
if (ret < 0)
return ret;
- ret = wl1271_cmd_data_path(wl, wl->channel, 1);
+ ret = wl1271_acx_init_mem_config(wl);
if (ret < 0)
return ret;
+ /* PHY layer config */
+ ret = wl1271_init_phy_config(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ ret = wl1271_acx_dco_itrim_params(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Initialize connection monitoring thresholds */
+ ret = wl1271_acx_conn_monit_params(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Bluetooth WLAN coexistence */
+ ret = wl1271_init_pta(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Energy detection */
+ ret = wl1271_init_energy_detection(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Default fragmentation threshold */
+ ret = wl1271_acx_frag_threshold(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Default TID configuration */
+ for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
+ conf_tid = &wl->conf.tx.tid_conf[i];
+ ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
+ conf_tid->channel_type,
+ conf_tid->tsid,
+ conf_tid->ps_scheme,
+ conf_tid->ack_policy,
+ conf_tid->apsd_conf[0],
+ conf_tid->apsd_conf[1]);
+ if (ret < 0)
+ goto out_free_memmap;
+ }
+
+ /* Default AC configuration */
+ for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
+ conf_ac = &wl->conf.tx.ac_conf[i];
+ ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
+ conf_ac->cw_max, conf_ac->aifsn,
+ conf_ac->tx_op_limit);
+ if (ret < 0)
+ goto out_free_memmap;
+ }
+
+ /* Enable data path */
+ ret = wl1271_cmd_data_path(wl, 1);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* Configure for CAM power saving (ie. always active) */
+ ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+ if (ret < 0)
+ goto out_free_memmap;
+
+ /* configure PM */
+ ret = wl1271_acx_pm_config(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
return 0;
+
+ out_free_memmap:
+ kfree(wl->target_mem_map);
+ wl->target_mem_map = NULL;
+
+ return ret;
}
static void wl1271_disable_interrupts(struct wl1271 *wl)
@@ -374,11 +372,13 @@ static void wl1271_disable_interrupts(struct wl1271 *wl)
static void wl1271_power_off(struct wl1271 *wl)
{
wl->set_power(false);
+ clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
}
static void wl1271_power_on(struct wl1271 *wl)
{
wl->set_power(true);
+ set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
}
static void wl1271_fw_status(struct wl1271 *wl,
@@ -387,8 +387,7 @@ static void wl1271_fw_status(struct wl1271 *wl,
u32 total = 0;
int i;
- wl1271_spi_read(wl, FW_STATUS_ADDR, status,
- sizeof(*status), false);
+ wl1271_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
"drv_rx_counter = %d, tx_results_counter = %d)",
@@ -435,7 +434,7 @@ static void wl1271_irq_work(struct work_struct *work)
if (ret < 0)
goto out;
- wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+ wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
wl1271_fw_status(wl, wl->fw_status);
intr = le32_to_cpu(wl->fw_status->intr);
@@ -447,14 +446,13 @@ static void wl1271_irq_work(struct work_struct *work)
intr &= WL1271_INTR_MASK;
if (intr & WL1271_ACX_INTR_EVENT_A) {
- bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true;
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
- wl1271_event_handle(wl, 0, do_ack);
+ wl1271_event_handle(wl, 0);
}
if (intr & WL1271_ACX_INTR_EVENT_B) {
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
- wl1271_event_handle(wl, 1, true);
+ wl1271_event_handle(wl, 1);
}
if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
@@ -478,8 +476,8 @@ static void wl1271_irq_work(struct work_struct *work)
}
out_sleep:
- wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
- WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
+ wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
+ WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
wl1271_ps_elp_sleep(wl);
out:
@@ -546,6 +544,40 @@ out:
return ret;
}
+static int wl1271_update_mac_addr(struct wl1271 *wl)
+{
+ int ret = 0;
+ u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
+
+ /* get mac address from the NVS */
+ wl->mac_addr[0] = nvs_ptr[11];
+ wl->mac_addr[1] = nvs_ptr[10];
+ wl->mac_addr[2] = nvs_ptr[6];
+ wl->mac_addr[3] = nvs_ptr[5];
+ wl->mac_addr[4] = nvs_ptr[4];
+ wl->mac_addr[5] = nvs_ptr[3];
+
+ /* FIXME: if it is a zero-address, we should bail out. Now, instead,
+ we randomize an address */
+ if (is_zero_ether_addr(wl->mac_addr)) {
+ static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
+ memcpy(wl->mac_addr, nokia_oui, 3);
+ get_random_bytes(wl->mac_addr + 3, 3);
+
+ /* update this address to the NVS */
+ nvs_ptr[11] = wl->mac_addr[0];
+ nvs_ptr[10] = wl->mac_addr[1];
+ nvs_ptr[6] = wl->mac_addr[2];
+ nvs_ptr[5] = wl->mac_addr[3];
+ nvs_ptr[4] = wl->mac_addr[4];
+ nvs_ptr[3] = wl->mac_addr[5];
+ }
+
+ SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
+
+ return ret;
+}
+
static int wl1271_fetch_nvs(struct wl1271 *wl)
{
const struct firmware *fw;
@@ -558,15 +590,14 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
return ret;
}
- if (fw->size % 4) {
- wl1271_error("nvs size is not multiple of 32 bits: %zu",
- fw->size);
+ if (fw->size != sizeof(struct wl1271_nvs_file)) {
+ wl1271_error("nvs size is not as expected: %zu != %zu",
+ fw->size, sizeof(struct wl1271_nvs_file));
ret = -EILSEQ;
goto out;
}
- wl->nvs_len = fw->size;
- wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
+ wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
if (!wl->nvs) {
wl1271_error("could not allocate memory for the nvs file");
@@ -574,9 +605,9 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
goto out;
}
- memcpy(wl->nvs, fw->data, wl->nvs_len);
+ memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
- ret = 0;
+ ret = wl1271_update_mac_addr(wl);
out:
release_firmware(fw);
@@ -614,10 +645,11 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
struct wl1271_partition_set partition;
int ret = 0;
+ msleep(WL1271_PRE_POWER_ON_SLEEP);
wl1271_power_on(wl);
msleep(WL1271_POWER_ON_SLEEP);
- wl1271_spi_reset(wl);
- wl1271_spi_init(wl);
+ wl1271_io_reset(wl);
+ wl1271_io_init(wl);
/* We don't need a real memory partition here, because we only want
* to use the registers at this point. */
@@ -632,7 +664,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
/* whal_FwCtrl_BootSm() */
/* 0. read chip id from CHIP_ID */
- wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
+ wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
/* 1. check if chip id is valid */
@@ -643,7 +675,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
ret = wl1271_setup(wl);
if (ret < 0)
- goto out_power_off;
+ goto out;
break;
case CHIP_ID_1271_PG20:
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
@@ -651,38 +683,34 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
ret = wl1271_setup(wl);
if (ret < 0)
- goto out_power_off;
+ goto out;
break;
default:
- wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
+ wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
- goto out_power_off;
+ goto out;
}
if (wl->fw == NULL) {
ret = wl1271_fetch_firmware(wl);
if (ret < 0)
- goto out_power_off;
+ goto out;
}
/* No NVS from netlink, try to get it from the filesystem */
if (wl->nvs == NULL) {
ret = wl1271_fetch_nvs(wl);
if (ret < 0)
- goto out_power_off;
+ goto out;
}
- goto out;
-
-out_power_off:
- wl1271_power_off(wl);
-
out:
return ret;
}
int wl1271_plt_start(struct wl1271 *wl)
{
+ int retries = WL1271_BOOT_RETRIES;
int ret;
mutex_lock(&wl->mutex);
@@ -696,35 +724,43 @@ int wl1271_plt_start(struct wl1271 *wl)
goto out;
}
- wl->state = WL1271_STATE_PLT;
-
- ret = wl1271_chip_wakeup(wl);
- if (ret < 0)
- goto out;
-
- ret = wl1271_boot(wl);
- if (ret < 0)
- goto out_power_off;
-
- wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
-
- ret = wl1271_plt_init(wl);
- if (ret < 0)
- goto out_irq_disable;
+ while (retries) {
+ retries--;
+ ret = wl1271_chip_wakeup(wl);
+ if (ret < 0)
+ goto power_off;
- /* Make sure power saving is disabled */
- ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
- if (ret < 0)
- goto out_irq_disable;
+ ret = wl1271_boot(wl);
+ if (ret < 0)
+ goto power_off;
- goto out;
+ ret = wl1271_plt_init(wl);
+ if (ret < 0)
+ goto irq_disable;
-out_irq_disable:
- wl1271_disable_interrupts(wl);
+ wl->state = WL1271_STATE_PLT;
+ wl1271_notice("firmware booted in PLT mode (%s)",
+ wl->chip.fw_ver);
+ goto out;
-out_power_off:
- wl1271_power_off(wl);
+irq_disable:
+ wl1271_disable_interrupts(wl);
+ mutex_unlock(&wl->mutex);
+ /* Unlocking the mutex in the middle of handling is
+ inherently unsafe. In this case we deem it safe to do,
+ because we need to let any possibly pending IRQ out of
+ the system (and while we are WL1271_STATE_OFF the IRQ
+ work function will not do anything.) Also, any other
+ possible concurrent operations will fail due to the
+ current state, hence the wl1271 struct should be safe. */
+ cancel_work_sync(&wl->irq_work);
+ mutex_lock(&wl->mutex);
+power_off:
+ wl1271_power_off(wl);
+ }
+ wl1271_error("firmware boot in PLT mode failed despite %d retries",
+ WL1271_BOOT_RETRIES);
out:
mutex_unlock(&wl->mutex);
@@ -762,7 +798,20 @@ out:
static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct wl1271 *wl = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+ struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
+ struct ieee80211_sta *sta = txinfo->control.sta;
+ unsigned long flags;
+
+ /* peek into the rates configured in the STA entry */
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
+ wl->sta_rate_set = sta->supp_rates[conf->channel->band];
+ set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
+ }
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ /* queue the packet */
skb_queue_tail(&wl->tx_queue, skb);
/*
@@ -784,7 +833,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* protected. Maybe fix this by removing the stupid
* variable altogether and checking the real queue state?
*/
- wl->tx_queue_stopped = true;
+ set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
}
return NETDEV_TX_OK;
@@ -880,6 +929,7 @@ static struct notifier_block wl1271_dev_notifier = {
static int wl1271_op_start(struct ieee80211_hw *hw)
{
struct wl1271 *wl = hw->priv;
+ int retries = WL1271_BOOT_RETRIES;
int ret = 0;
wl1271_debug(DEBUG_MAC80211, "mac80211 start");
@@ -893,30 +943,42 @@ static int wl1271_op_start(struct ieee80211_hw *hw)
goto out;
}
- ret = wl1271_chip_wakeup(wl);
- if (ret < 0)
- goto out;
-
- ret = wl1271_boot(wl);
- if (ret < 0)
- goto out_power_off;
-
- ret = wl1271_hw_init(wl);
- if (ret < 0)
- goto out_irq_disable;
-
- wl->state = WL1271_STATE_ON;
+ while (retries) {
+ retries--;
+ ret = wl1271_chip_wakeup(wl);
+ if (ret < 0)
+ goto power_off;
- wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
+ ret = wl1271_boot(wl);
+ if (ret < 0)
+ goto power_off;
- goto out;
+ ret = wl1271_hw_init(wl);
+ if (ret < 0)
+ goto irq_disable;
-out_irq_disable:
- wl1271_disable_interrupts(wl);
+ wl->state = WL1271_STATE_ON;
+ wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
+ goto out;
-out_power_off:
- wl1271_power_off(wl);
+irq_disable:
+ wl1271_disable_interrupts(wl);
+ mutex_unlock(&wl->mutex);
+ /* Unlocking the mutex in the middle of handling is
+ inherently unsafe. In this case we deem it safe to do,
+ because we need to let any possibly pending IRQ out of
+ the system (and while we are WL1271_STATE_OFF the IRQ
+ work function will not do anything.) Also, any other
+ possible concurrent operations will fail due to the
+ current state, hence the wl1271 struct should be safe. */
+ cancel_work_sync(&wl->irq_work);
+ mutex_lock(&wl->mutex);
+power_off:
+ wl1271_power_off(wl);
+ }
+ wl1271_error("firmware boot failed despite %d retries",
+ WL1271_BOOT_RETRIES);
out:
mutex_unlock(&wl->mutex);
@@ -944,11 +1006,10 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
WARN_ON(wl->state != WL1271_STATE_ON);
- if (wl->scanning) {
+ if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, true);
mutex_lock(&wl->mutex);
- wl->scanning = false;
}
wl->state = WL1271_STATE_OFF;
@@ -973,10 +1034,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl->band = IEEE80211_BAND_2GHZ;
wl->rx_counter = 0;
- wl->elp = false;
- wl->psm = 0;
wl->psm_entry_retry = 0;
- wl->tx_queue_stopped = false;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->tx_blocks_available = 0;
wl->tx_results_count = 0;
@@ -986,7 +1044,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl->tx_security_seq_32 = 0;
wl->time_offset = 0;
wl->session_counter = 0;
- wl->joined = false;
+ wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+ wl->sta_rate_set = 0;
+ wl->flags = 0;
for (i = 0; i < NUM_TX_QUEUES; i++)
wl->tx_blocks_freed[i] = 0;
@@ -996,13 +1056,13 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
}
static int wl1271_op_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct wl1271 *wl = hw->priv;
int ret = 0;
wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
- conf->type, conf->mac_addr);
+ vif->type, vif->addr);
mutex_lock(&wl->mutex);
if (wl->vif) {
@@ -1010,9 +1070,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
- wl->vif = conf->vif;
+ wl->vif = vif;
- switch (conf->type) {
+ switch (vif->type) {
case NL80211_IFTYPE_STATION:
wl->bss_type = BSS_TYPE_STA_BSS;
break;
@@ -1032,7 +1092,7 @@ out:
}
static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct wl1271 *wl = hw->priv;
@@ -1109,6 +1169,51 @@ out:
}
#endif
+static int wl1271_join_channel(struct wl1271 *wl, int channel)
+{
+ int ret = 0;
+ /* we need to use a dummy BSSID for now */
+ static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
+ 0xad, 0xbe, 0xef };
+
+ /* the dummy join is not required for ad-hoc */
+ if (wl->bss_type == BSS_TYPE_IBSS)
+ goto out;
+
+ /* disable mac filter, so we hear everything */
+ wl->rx_config &= ~CFG_BSSID_FILTER_EN;
+
+ wl->channel = channel;
+ memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
+
+ ret = wl1271_cmd_join(wl);
+ if (ret < 0)
+ goto out;
+
+ set_bit(WL1271_FLAG_JOINED, &wl->flags);
+
+out:
+ return ret;
+}
+
+static int wl1271_unjoin_channel(struct wl1271 *wl)
+{
+ int ret;
+
+ /* to stop listening to a channel, we disconnect */
+ ret = wl1271_cmd_disconnect(wl);
+ if (ret < 0)
+ goto out;
+
+ clear_bit(WL1271_FLAG_JOINED, &wl->flags);
+ wl->channel = 0;
+ memset(wl->bssid, 0, ETH_ALEN);
+ wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
+
+out:
+ return ret;
+}
+
static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct wl1271 *wl = hw->priv;
@@ -1117,10 +1222,11 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
- wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
+ wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
channel,
conf->flags & IEEE80211_CONF_PS ? "on" : "off",
- conf->power_level);
+ conf->power_level,
+ conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
mutex_lock(&wl->mutex);
@@ -1130,35 +1236,55 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
if (ret < 0)
goto out;
- if (channel != wl->channel) {
- /*
- * We assume that the stack will configure the right channel
- * before associating, so we don't need to send a join
- * command here. We will join the right channel when the
- * BSSID changes
- */
- wl->channel = channel;
+ if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+ if (conf->flags & IEEE80211_CONF_IDLE &&
+ test_bit(WL1271_FLAG_JOINED, &wl->flags))
+ wl1271_unjoin_channel(wl);
+ else if (!(conf->flags & IEEE80211_CONF_IDLE))
+ wl1271_join_channel(wl, channel);
+
+ if (conf->flags & IEEE80211_CONF_IDLE) {
+ wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+ wl->sta_rate_set = 0;
+ wl1271_acx_rate_policies(wl);
+ }
}
- if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
- wl1271_info("psm enabled");
+ /* if the channel changes while joined, join again */
+ if (channel != wl->channel &&
+ test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
+ wl->channel = channel;
+ /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
+ ret = wl1271_cmd_join(wl);
+ if (ret < 0)
+ wl1271_warning("cmd join to update channel failed %d",
+ ret);
+ } else
+ wl->channel = channel;
- wl->psm_requested = true;
+ if (conf->flags & IEEE80211_CONF_PS &&
+ !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
+ set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
/*
* We enter PSM only if we're already associated.
* If we're not, we'll enter it when joining an SSID,
* through the bss_info_changed() hook.
*/
- ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
+ wl1271_info("psm enabled");
+ ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
+ true);
+ }
} else if (!(conf->flags & IEEE80211_CONF_PS) &&
- wl->psm_requested) {
+ test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
wl1271_info("psm disabled");
- wl->psm_requested = false;
+ clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
- if (wl->psm)
- ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ if (test_bit(WL1271_FLAG_PSM, &wl->flags))
+ ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
+ true);
}
if (conf->power_level != wl->power_level) {
@@ -1350,9 +1476,24 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
wl1271_error("Could not add or replace key");
goto out_sleep;
}
+
+ /* the default WEP key needs to be configured at least once */
+ if (key_type == KEY_WEP) {
+ ret = wl1271_cmd_set_default_wep_key(wl,
+ wl->default_key);
+ if (ret < 0)
+ goto out_sleep;
+ }
break;
case DISABLE_KEY:
+ /* The wl1271 does not allow to remove unicast keys - they
+ will be cleared automatically on next CMD_JOIN. Ignore the
+ request silently, as we dont want the mac80211 to emit
+ an error message. */
+ if (!is_broadcast_ether_addr(addr))
+ break;
+
ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
key_conf->keyidx, key_type,
key_conf->keylen, key_conf->key,
@@ -1440,20 +1581,21 @@ out:
return ret;
}
-static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
+static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
{
- struct ieee80211_supported_band *band;
- u32 enabled_rates = 0;
- int bit;
-
- band = wl->hw->wiphy->bands[wl->band];
- for (bit = 0; bit < band->n_bitrates; bit++) {
- if (basic_rate_set & 0x1)
- enabled_rates |= band->bitrates[bit].hw_value;
- basic_rate_set >>= 1;
+ u8 *ptr = beacon->data +
+ offsetof(struct ieee80211_mgmt, u.beacon.variable);
+
+ /* find the location of the ssid in the beacon */
+ while (ptr < beacon->data + beacon->len) {
+ if (ptr[0] == WLAN_EID_SSID) {
+ wl->ssid_len = ptr[1];
+ memcpy(wl->ssid, ptr+2, wl->ssid_len);
+ return;
+ }
+ ptr += ptr[1];
}
-
- return enabled_rates;
+ wl1271_error("ad-hoc beacon template has no SSID!\n");
}
static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
@@ -1463,6 +1605,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
{
enum wl1271_cmd_ps_mode mode;
struct wl1271 *wl = hw->priv;
+ bool do_join = false;
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
@@ -1473,9 +1616,67 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
+ if (wl->bss_type == BSS_TYPE_IBSS) {
+ /* FIXME: This implements rudimentary ad-hoc support -
+ proper templates are on the wish list and notification
+ on when they change. This patch will update the templates
+ on every call to this function. */
+ struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+
+ if (beacon) {
+ struct ieee80211_hdr *hdr;
+
+ wl1271_ssid_set(wl, beacon);
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
+ beacon->data,
+ beacon->len);
+
+ if (ret < 0) {
+ dev_kfree_skb(beacon);
+ goto out_sleep;
+ }
+
+ hdr = (struct ieee80211_hdr *) beacon->data;
+ hdr->frame_control = cpu_to_le16(
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_PROBE_RESP);
+
+ ret = wl1271_cmd_template_set(wl,
+ CMD_TEMPL_PROBE_RESPONSE,
+ beacon->data,
+ beacon->len);
+ dev_kfree_skb(beacon);
+ if (ret < 0)
+ goto out_sleep;
+
+ /* Need to update the SSID (for filtering etc) */
+ do_join = true;
+ }
+ }
+
+ if ((changed & BSS_CHANGED_BSSID) &&
+ /*
+ * Now we know the correct bssid, so we send a new join command
+ * and enable the BSSID filter
+ */
+ memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
+ wl->rx_config |= CFG_BSSID_FILTER_EN;
+ memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
+ ret = wl1271_cmd_build_null_data(wl);
+ if (ret < 0) {
+ wl1271_warning("cmd buld null data failed %d",
+ ret);
+ goto out_sleep;
+ }
+
+ /* Need to update the BSSID (for filtering etc) */
+ do_join = true;
+ }
+
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
wl->aid = bss_conf->aid;
+ set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
/*
* with wl1271, we don't need to update the
@@ -1492,15 +1693,16 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
goto out_sleep;
/* If we want to go in PSM but we're not there yet */
- if (wl->psm_requested && !wl->psm) {
+ if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
+ !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
mode = STATION_POWER_SAVE_MODE;
- ret = wl1271_ps_set_mode(wl, mode);
+ ret = wl1271_ps_set_mode(wl, mode, true);
if (ret < 0)
goto out_sleep;
}
} else {
/* use defaults when not associated */
- wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
+ clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
wl->aid = 0;
}
@@ -1535,15 +1737,13 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
}
}
- if (changed & BSS_CHANGED_BASIC_RATES) {
- wl->basic_rate_set = wl1271_enabled_rates_get(
- wl, bss_conf->basic_rates);
-
- ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
+ if (do_join) {
+ ret = wl1271_cmd_join(wl);
if (ret < 0) {
- wl1271_warning("Set rate policies failed %d", ret);
+ wl1271_warning("cmd join failed %d", ret);
goto out_sleep;
}
+ set_bit(WL1271_FLAG_JOINED, &wl->flags);
}
out_sleep:
@@ -1553,6 +1753,43 @@ out:
mutex_unlock(&wl->mutex);
}
+static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct wl1271 *wl = hw->priv;
+ int ret;
+
+ mutex_lock(&wl->mutex);
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
+ params->cw_min, params->cw_max,
+ params->aifs, params->txop);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
+ CONF_CHANNEL_TYPE_EDCF,
+ wl1271_tx_get_queue(queue),
+ CONF_PS_SCHEME_LEGACY_PSPOLL,
+ CONF_ACK_POLICY_LEGACY, 0, 0);
+ if (ret < 0)
+ goto out_sleep;
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
/* can't be const, mac80211 writes to this */
static struct ieee80211_rate wl1271_rates[] = {
@@ -1599,19 +1836,19 @@ static struct ieee80211_rate wl1271_rates[] = {
/* can't be const, mac80211 writes to this */
static struct ieee80211_channel wl1271_channels[] = {
- { .hw_value = 1, .center_freq = 2412},
- { .hw_value = 2, .center_freq = 2417},
- { .hw_value = 3, .center_freq = 2422},
- { .hw_value = 4, .center_freq = 2427},
- { .hw_value = 5, .center_freq = 2432},
- { .hw_value = 6, .center_freq = 2437},
- { .hw_value = 7, .center_freq = 2442},
- { .hw_value = 8, .center_freq = 2447},
- { .hw_value = 9, .center_freq = 2452},
- { .hw_value = 10, .center_freq = 2457},
- { .hw_value = 11, .center_freq = 2462},
- { .hw_value = 12, .center_freq = 2467},
- { .hw_value = 13, .center_freq = 2472},
+ { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
+ { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
+ { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
+ { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
+ { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
+ { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
+ { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
+ { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
+ { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
+ { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
+ { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
+ { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
+ { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
};
/* can't be const, mac80211 writes to this */
@@ -1718,6 +1955,8 @@ static const struct ieee80211_ops wl1271_ops = {
.hw_scan = wl1271_op_hw_scan,
.bss_info_changed = wl1271_op_bss_info_changed,
.set_rts_threshold = wl1271_op_set_rts_threshold,
+ .conf_tx = wl1271_op_conf_tx,
+ CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
static int wl1271_register_hw(struct wl1271 *wl)
@@ -1757,7 +1996,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_BEACON_FILTER |
IEEE80211_HW_SUPPORTS_PS;
- wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC);
wl->hw->wiphy->max_scan_ssids = 1;
wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
@@ -1785,24 +2025,17 @@ static struct platform_device wl1271_device = {
};
#define WL1271_DEFAULT_CHANNEL 0
-static int __devinit wl1271_probe(struct spi_device *spi)
+
+static struct ieee80211_hw *wl1271_alloc_hw(void)
{
- struct wl12xx_platform_data *pdata;
struct ieee80211_hw *hw;
struct wl1271 *wl;
- int ret, i;
- static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
-
- pdata = spi->dev.platform_data;
- if (!pdata) {
- wl1271_error("no platform data");
- return -ENODEV;
- }
+ int i;
hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
if (!hw) {
wl1271_error("could not alloc ieee80211_hw");
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
wl = hw->priv;
@@ -1811,44 +2044,80 @@ static int __devinit wl1271_probe(struct spi_device *spi)
INIT_LIST_HEAD(&wl->list);
wl->hw = hw;
- dev_set_drvdata(&spi->dev, wl);
- wl->spi = spi;
skb_queue_head_init(&wl->tx_queue);
INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
wl->channel = WL1271_DEFAULT_CHANNEL;
- wl->scanning = false;
wl->default_key = 0;
wl->rx_counter = 0;
wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
- wl->elp = false;
- wl->psm = 0;
- wl->psm_requested = false;
wl->psm_entry_retry = 0;
- wl->tx_queue_stopped = false;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
- wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
+ wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
+ wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+ wl->sta_rate_set = 0;
wl->band = IEEE80211_BAND_2GHZ;
wl->vif = NULL;
- wl->joined = false;
+ wl->flags = 0;
for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
wl->tx_frames[i] = NULL;
spin_lock_init(&wl->wl_lock);
- /*
- * In case our MAC address is not correctly set,
- * we use a random but Nokia MAC.
- */
- memcpy(wl->mac_addr, nokia_oui, 3);
- get_random_bytes(wl->mac_addr + 3, 3);
-
wl->state = WL1271_STATE_OFF;
mutex_init(&wl->mutex);
+ /* Apply default driver configuration. */
+ wl1271_conf_init(wl);
+
+ return hw;
+}
+
+int wl1271_free_hw(struct wl1271 *wl)
+{
+ ieee80211_unregister_hw(wl->hw);
+
+ wl1271_debugfs_exit(wl);
+
+ kfree(wl->target_mem_map);
+ vfree(wl->fw);
+ wl->fw = NULL;
+ kfree(wl->nvs);
+ wl->nvs = NULL;
+
+ kfree(wl->fw_status);
+ kfree(wl->tx_res_if);
+
+ ieee80211_free_hw(wl->hw);
+
+ return 0;
+}
+
+static int __devinit wl1271_probe(struct spi_device *spi)
+{
+ struct wl12xx_platform_data *pdata;
+ struct ieee80211_hw *hw;
+ struct wl1271 *wl;
+ int ret;
+
+ pdata = spi->dev.platform_data;
+ if (!pdata) {
+ wl1271_error("no platform data");
+ return -ENODEV;
+ }
+
+ hw = wl1271_alloc_hw();
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ wl = hw->priv;
+
+ dev_set_drvdata(&spi->dev, wl);
+ wl->spi = spi;
+
/* This is the only SPI value that we need to set here, the rest
* comes from the board-peripherals file */
spi->bits_per_word = 32;
@@ -1890,9 +2159,6 @@ static int __devinit wl1271_probe(struct spi_device *spi)
}
dev_set_drvdata(&wl1271_device.dev, wl);
- /* Apply default driver configuration. */
- wl1271_conf_init(wl);
-
ret = wl1271_init_ieee80211(wl);
if (ret)
goto out_platform;
@@ -1923,21 +2189,10 @@ static int __devexit wl1271_remove(struct spi_device *spi)
{
struct wl1271 *wl = dev_get_drvdata(&spi->dev);
- ieee80211_unregister_hw(wl->hw);
-
- wl1271_debugfs_exit(wl);
platform_device_unregister(&wl1271_device);
free_irq(wl->irq, wl);
- kfree(wl->target_mem_map);
- vfree(wl->fw);
- wl->fw = NULL;
- kfree(wl->nvs);
- wl->nvs = NULL;
- kfree(wl->fw_status);
- kfree(wl->tx_res_if);
-
- ieee80211_free_hw(wl->hw);
+ wl1271_free_hw(wl);
return 0;
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c
index 507cd91d7eed..e2b1ebf096e8 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.c
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.c
@@ -24,6 +24,7 @@
#include "wl1271_reg.h"
#include "wl1271_ps.h"
#include "wl1271_spi.h"
+#include "wl1271_io.h"
#define WL1271_WAKEUP_TIMEOUT 500
@@ -39,12 +40,13 @@ void wl1271_elp_work(struct work_struct *work)
mutex_lock(&wl->mutex);
- if (wl->elp || !wl->psm)
+ if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
+ !test_bit(WL1271_FLAG_PSM, &wl->flags))
goto out;
wl1271_debug(DEBUG_PSM, "chip to elp");
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
- wl->elp = true;
+ set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
out:
mutex_unlock(&wl->mutex);
@@ -55,7 +57,7 @@ out:
/* Routines to toggle sleep mode while in ELP */
void wl1271_ps_elp_sleep(struct wl1271 *wl)
{
- if (wl->psm) {
+ if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
cancel_delayed_work(&wl->elp_work);
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
msecs_to_jiffies(ELP_ENTRY_DELAY));
@@ -70,7 +72,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
u32 start_time = jiffies;
bool pending = false;
- if (!wl->elp)
+ if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
return 0;
wl1271_debug(DEBUG_PSM, "waking up chip from elp");
@@ -101,7 +103,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
}
}
- wl->elp = false;
+ clear_bit(WL1271_FLAG_IN_ELP, &wl->flags);
wl1271_debug(DEBUG_PSM, "wakeup time: %u ms",
jiffies_to_msecs(jiffies - start_time));
@@ -117,7 +119,8 @@ out:
return 0;
}
-int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
+int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
+ bool send)
{
int ret;
@@ -125,25 +128,11 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
case STATION_POWER_SAVE_MODE:
wl1271_debug(DEBUG_PSM, "entering psm");
- /* enable beacon filtering */
- ret = wl1271_acx_beacon_filter_opt(wl, true);
+ ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, send);
if (ret < 0)
return ret;
- /* enable beacon early termination */
- ret = wl1271_acx_bet_enable(wl, true);
- if (ret < 0)
- return ret;
-
- ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
- if (ret < 0)
- return ret;
-
- wl1271_ps_elp_sleep(wl);
- if (ret < 0)
- return ret;
-
- wl->psm = 1;
+ set_bit(WL1271_FLAG_PSM, &wl->flags);
break;
case STATION_ACTIVE_MODE:
default:
@@ -162,11 +151,11 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
if (ret < 0)
return ret;
- ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE, send);
if (ret < 0)
return ret;
- wl->psm = 0;
+ clear_bit(WL1271_FLAG_PSM, &wl->flags);
break;
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/wl1271_ps.h
index 779653d0ae85..940276f517a4 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.h
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.h
@@ -27,7 +27,8 @@
#include "wl1271.h"
#include "wl1271_acx.h"
-int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode);
+int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
+ bool send);
void wl1271_ps_elp_sleep(struct wl1271 *wl);
int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake);
void wl1271_elp_work(struct work_struct *work);
diff --git a/drivers/net/wireless/wl12xx/wl1271_reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h
index 1f237389d1c7..990960771528 100644
--- a/drivers/net/wireless/wl12xx/wl1271_reg.h
+++ b/drivers/net/wireless/wl12xx/wl1271_reg.h
@@ -62,73 +62,10 @@
#define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008)
#define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c)
#define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018)
-/*
- * Interrupt registers.
- * 64 bit interrupt sources registers ws ced.
- * sme interupts were removed and new ones were added.
- * Order was changed.
- */
-#define FIQ_MASK (REGISTERS_BASE + 0x0400)
-#define FIQ_MASK_L (REGISTERS_BASE + 0x0400)
-#define FIQ_MASK_H (REGISTERS_BASE + 0x0404)
-#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408)
-#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408)
-#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C)
-#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410)
-#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410)
-#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414)
-#define IRQ_MASK (REGISTERS_BASE + 0x0418)
-#define IRQ_MASK_L (REGISTERS_BASE + 0x0418)
-#define IRQ_MASK_H (REGISTERS_BASE + 0x041C)
-#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420)
-#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420)
-#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424)
-#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428)
-#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428)
-#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C)
-#define ECPU_MASK (REGISTERS_BASE + 0x0448)
-#define FIQ_STS_L (REGISTERS_BASE + 0x044C)
-#define FIQ_STS_H (REGISTERS_BASE + 0x0450)
-#define IRQ_STS_L (REGISTERS_BASE + 0x0454)
-#define IRQ_STS_H (REGISTERS_BASE + 0x0458)
-#define INT_STS_ND (REGISTERS_BASE + 0x0464)
-#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464)
-#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468)
-#define INT_STS_CLR (REGISTERS_BASE + 0x04B4)
-#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4)
-#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8)
-#define INT_ACK (REGISTERS_BASE + 0x046C)
-#define INT_ACK_L (REGISTERS_BASE + 0x046C)
-#define INT_ACK_H (REGISTERS_BASE + 0x0470)
-#define INT_TRIG (REGISTERS_BASE + 0x0474)
-#define INT_TRIG_L (REGISTERS_BASE + 0x0474)
-#define INT_TRIG_H (REGISTERS_BASE + 0x0478)
-#define HOST_STS_L (REGISTERS_BASE + 0x045C)
-#define HOST_STS_H (REGISTERS_BASE + 0x0460)
-#define HOST_MASK (REGISTERS_BASE + 0x0430)
-#define HOST_MASK_L (REGISTERS_BASE + 0x0430)
-#define HOST_MASK_H (REGISTERS_BASE + 0x0434)
-#define HOST_MASK_SET (REGISTERS_BASE + 0x0438)
-#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438)
-#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C)
-#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440)
-#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440)
-#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444)
#define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474)
#define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478)
-/* Host Interrupts*/
-#define HINT_MASK (REGISTERS_BASE + 0x0494)
-#define HINT_MASK_SET (REGISTERS_BASE + 0x0498)
-#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C)
-#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0)
-/*1150 spec calls this HINT_STS_RAW*/
-#define HINT_STS_ND (REGISTERS_BASE + 0x04B0)
-#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4)
-#define HINT_ACK (REGISTERS_BASE + 0x04A8)
-#define HINT_TRIG (REGISTERS_BASE + 0x04AC)
-
/*=============================================
Host Interrupt Mask Register - 32bit (RW)
------------------------------------------
@@ -433,16 +370,6 @@
/*===============================================
- Phy regs
- ===============================================*/
-#define ACX_PHY_ADDR_REG SBB_ADDR
-#define ACX_PHY_DATA_REG SBB_DATA
-#define ACX_PHY_CTRL_REG SBB_CTL
-#define ACX_PHY_REG_WR_MASK 0x00000001ul
-#define ACX_PHY_REG_RD_MASK 0x00000002ul
-
-
-/*===============================================
EEPROM Read/Write Request 32bit RW
------------------------------------------
1 EE_READ - EEPROM Read Request 1 - Setting this bit
@@ -511,28 +438,6 @@
#define ACX_CONT_WIND_MIN_MASK 0x0000007f
#define ACX_CONT_WIND_MAX 0x03ff0000
-/*
- * Indirect slave register/memory registers
- * ----------------------------------------
- */
-#define HW_SLAVE_REG_ADDR_REG 0x00000004
-#define HW_SLAVE_REG_DATA_REG 0x00000008
-#define HW_SLAVE_REG_CTRL_REG 0x0000000c
-
-#define SLAVE_AUTO_INC 0x00010000
-#define SLAVE_NO_AUTO_INC 0x00000000
-#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000
-
-#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR
-#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA
-#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL
-#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL
-
-#define HW_FUNC_EVENT_INT_EN 0x8000
-#define HW_FUNC_EVENT_MASK_REG 0x00000034
-
-#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP)
-
/*===============================================
HI_CFG Interface Configuration Register Values
------------------------------------------
@@ -647,10 +552,6 @@ b12-b0 - Supported Rate indicator bits as defined below.
******************************************************************************/
-#define TNETW1251_CHIP_ID_PG1_0 0x07010101
-#define TNETW1251_CHIP_ID_PG1_1 0x07020101
-#define TNETW1251_CHIP_ID_PG1_2 0x07030101
-
/*************************************************************************
Interrupt Trigger Register (Host -> WiLink)
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c
index ca645f38109b..6730f5b96e76 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.c
@@ -26,6 +26,7 @@
#include "wl1271_reg.h"
#include "wl1271_rx.h"
#include "wl1271_spi.h"
+#include "wl1271_io.h"
static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status,
u32 drv_rx_counter)
@@ -166,7 +167,7 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
}
buf = skb_put(skb, length);
- wl1271_spi_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
+ wl1271_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
/* the data read starts with the descriptor */
desc = (struct wl1271_rx_descriptor *) buf;
@@ -210,15 +211,13 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
wl->rx_mem_pool_addr.addr + 4;
/* Choose the block we want to read */
- wl1271_spi_write(wl, WL1271_SLV_REG_DATA,
- &wl->rx_mem_pool_addr,
- sizeof(wl->rx_mem_pool_addr), false);
+ wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr,
+ sizeof(wl->rx_mem_pool_addr), false);
wl1271_rx_handle_data(wl, buf_size);
wl->rx_counter++;
drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
+ wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
}
-
- wl1271_spi_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index 02978a16e732..67a82934f36e 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -30,28 +30,6 @@
#include "wl12xx_80211.h"
#include "wl1271_spi.h"
-static int wl1271_translate_addr(struct wl1271 *wl, int addr)
-{
- /*
- * To translate, first check to which window of addresses the
- * particular address belongs. Then subtract the starting address
- * of that window from the address. Then, add offset of the
- * translated region.
- *
- * The translated regions occur next to each other in physical device
- * memory, so just add the sizes of the preceeding address regions to
- * get the offset to the new region.
- *
- * Currently, only the two first regions are addressed, and the
- * assumption is that all addresses will fall into either of those
- * two.
- */
- if ((addr >= wl->part.reg.start) &&
- (addr < wl->part.reg.start + wl->part.reg.size))
- return addr - wl->part.reg.start + wl->part.mem.size;
- else
- return addr - wl->part.mem.start;
-}
void wl1271_spi_reset(struct wl1271 *wl)
{
@@ -133,67 +111,6 @@ void wl1271_spi_init(struct wl1271 *wl)
wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
}
-/* Set the SPI partitions to access the chip addresses
- *
- * To simplify driver code, a fixed (virtual) memory map is defined for
- * register and memory addresses. Because in the chipset, in different stages
- * of operation, those addresses will move around, an address translation
- * mechanism is required.
- *
- * There are four partitions (three memory and one register partition),
- * which are mapped to two different areas of the hardware memory.
- *
- * Virtual address
- * space
- *
- * | |
- * ...+----+--> mem.start
- * Physical address ... | |
- * space ... | | [PART_0]
- * ... | |
- * 00000000 <--+----+... ...+----+--> mem.start + mem.size
- * | | ... | |
- * |MEM | ... | |
- * | | ... | |
- * mem.size <--+----+... | | {unused area)
- * | | ... | |
- * |REG | ... | |
- * mem.size | | ... | |
- * + <--+----+... ...+----+--> reg.start
- * reg.size | | ... | |
- * |MEM2| ... | | [PART_1]
- * | | ... | |
- * ...+----+--> reg.start + reg.size
- * | |
- *
- */
-int wl1271_set_partition(struct wl1271 *wl,
- struct wl1271_partition_set *p)
-{
- /* copy partition info */
- memcpy(&wl->part, p, sizeof(*p));
-
- wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
- p->mem.start, p->mem.size);
- wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
- p->reg.start, p->reg.size);
- wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X",
- p->mem2.start, p->mem2.size);
- wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X",
- p->mem3.start, p->mem3.size);
-
- /* write partition info to the chipset */
- wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
- wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
- wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
- wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
- wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
- wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
- wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
-
- return 0;
-}
-
#define WL1271_BUSY_WORD_TIMEOUT 1000
/* FIXME: Check busy words, removed due to SPI bug */
@@ -338,78 +255,3 @@ void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
}
-
-void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed)
-{
- int physical;
-
- physical = wl1271_translate_addr(wl, addr);
-
- wl1271_spi_raw_read(wl, physical, buf, len, fixed);
-}
-
-void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed)
-{
- int physical;
-
- physical = wl1271_translate_addr(wl, addr);
-
- wl1271_spi_raw_write(wl, physical, buf, len, fixed);
-}
-
-u32 wl1271_spi_read32(struct wl1271 *wl, int addr)
-{
- return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
-}
-
-void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val)
-{
- wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val);
-}
-
-void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
-{
- /* write address >> 1 + 0x30000 to OCP_POR_CTR */
- addr = (addr >> 1) + 0x30000;
- wl1271_spi_write32(wl, OCP_POR_CTR, addr);
-
- /* write value to OCP_POR_WDATA */
- wl1271_spi_write32(wl, OCP_DATA_WRITE, val);
-
- /* write 1 to OCP_CMD */
- wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_WRITE);
-}
-
-u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
-{
- u32 val;
- int timeout = OCP_CMD_LOOP;
-
- /* write address >> 1 + 0x30000 to OCP_POR_CTR */
- addr = (addr >> 1) + 0x30000;
- wl1271_spi_write32(wl, OCP_POR_CTR, addr);
-
- /* write 2 to OCP_CMD */
- wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_READ);
-
- /* poll for data ready */
- do {
- val = wl1271_spi_read32(wl, OCP_DATA_READ);
- timeout--;
- } while (!(val & OCP_READY_MASK) && timeout);
-
- if (!timeout) {
- wl1271_warning("Top register access timed out.");
- return 0xffff;
- }
-
- /* check data status and return if OK */
- if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK)
- return val & 0xffff;
- else {
- wl1271_warning("Top register access returned error.");
- return 0xffff;
- }
-}
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h
index cb7df1c56314..a803596dad4a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.h
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.h
@@ -90,37 +90,7 @@ void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed);
-/* Translated target IO */
-void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed);
-void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed);
-u32 wl1271_spi_read32(struct wl1271 *wl, int addr);
-void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val);
-
-/* Top Register IO */
-void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val);
-u16 wl1271_top_reg_read(struct wl1271 *wl, int addr);
-
/* INIT and RESET words */
void wl1271_spi_reset(struct wl1271 *wl);
void wl1271_spi_init(struct wl1271 *wl);
-int wl1271_set_partition(struct wl1271 *wl,
- struct wl1271_partition_set *p);
-
-static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
-{
- wl1271_spi_raw_read(wl, addr, &wl->buffer_32,
- sizeof(wl->buffer_32), false);
-
- return wl->buffer_32;
-}
-
-static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
-{
- wl->buffer_32 = val;
- wl1271_spi_raw_write(wl, addr, &wl->buffer_32,
- sizeof(wl->buffer_32), false);
-}
-
#endif /* __WL1271_SPI_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c
new file mode 100644
index 000000000000..3919102e942e
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c
@@ -0,0 +1,283 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include "wl1271_testmode.h"
+
+#include <net/genetlink.h>
+
+#include "wl1271.h"
+#include "wl1271_spi.h"
+#include "wl1271_acx.h"
+
+#define WL1271_TM_MAX_DATA_LENGTH 1024
+
+enum wl1271_tm_commands {
+ WL1271_TM_CMD_UNSPEC,
+ WL1271_TM_CMD_TEST,
+ WL1271_TM_CMD_INTERROGATE,
+ WL1271_TM_CMD_CONFIGURE,
+ WL1271_TM_CMD_NVS_PUSH,
+ WL1271_TM_CMD_SET_PLT_MODE,
+
+ __WL1271_TM_CMD_AFTER_LAST
+};
+#define WL1271_TM_CMD_MAX (__WL1271_TM_CMD_AFTER_LAST - 1)
+
+enum wl1271_tm_attrs {
+ WL1271_TM_ATTR_UNSPEC,
+ WL1271_TM_ATTR_CMD_ID,
+ WL1271_TM_ATTR_ANSWER,
+ WL1271_TM_ATTR_DATA,
+ WL1271_TM_ATTR_IE_ID,
+ WL1271_TM_ATTR_PLT_MODE,
+
+ __WL1271_TM_ATTR_AFTER_LAST
+};
+#define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1)
+
+static struct nla_policy wl1271_tm_policy[WL1271_TM_ATTR_MAX + 1] = {
+ [WL1271_TM_ATTR_CMD_ID] = { .type = NLA_U32 },
+ [WL1271_TM_ATTR_ANSWER] = { .type = NLA_U8 },
+ [WL1271_TM_ATTR_DATA] = { .type = NLA_BINARY,
+ .len = WL1271_TM_MAX_DATA_LENGTH },
+ [WL1271_TM_ATTR_IE_ID] = { .type = NLA_U32 },
+ [WL1271_TM_ATTR_PLT_MODE] = { .type = NLA_U32 },
+};
+
+
+static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
+{
+ int buf_len, ret, len;
+ struct sk_buff *skb;
+ void *buf;
+ u8 answer = 0;
+
+ wl1271_debug(DEBUG_TESTMODE, "testmode cmd test");
+
+ if (!tb[WL1271_TM_ATTR_DATA])
+ return -EINVAL;
+
+ buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
+ buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
+
+ if (tb[WL1271_TM_ATTR_ANSWER])
+ answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]);
+
+ if (buf_len > sizeof(struct wl1271_command))
+ return -EMSGSIZE;
+
+ mutex_lock(&wl->mutex);
+ ret = wl1271_cmd_test(wl, buf, buf_len, answer);
+ mutex_unlock(&wl->mutex);
+
+ if (ret < 0) {
+ wl1271_warning("testmode cmd test failed: %d", ret);
+ return ret;
+ }
+
+ if (answer) {
+ len = nla_total_size(buf_len);
+ skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
+ if (!skb)
+ return -ENOMEM;
+
+ NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf);
+ ret = cfg80211_testmode_reply(skb);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+
+nla_put_failure:
+ kfree_skb(skb);
+ return -EMSGSIZE;
+}
+
+static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
+{
+ int ret;
+ struct wl1271_command *cmd;
+ struct sk_buff *skb;
+ u8 ie_id;
+
+ wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate");
+
+ if (!tb[WL1271_TM_ATTR_IE_ID])
+ return -EINVAL;
+
+ ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ mutex_lock(&wl->mutex);
+ ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd));
+ mutex_unlock(&wl->mutex);
+
+ if (ret < 0) {
+ wl1271_warning("testmode cmd interrogate failed: %d", ret);
+ return ret;
+ }
+
+ skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd);
+
+ return 0;
+
+nla_put_failure:
+ kfree_skb(skb);
+ return -EMSGSIZE;
+}
+
+static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[])
+{
+ int buf_len, ret;
+ void *buf;
+ u8 ie_id;
+
+ wl1271_debug(DEBUG_TESTMODE, "testmode cmd configure");
+
+ if (!tb[WL1271_TM_ATTR_DATA])
+ return -EINVAL;
+ if (!tb[WL1271_TM_ATTR_IE_ID])
+ return -EINVAL;
+
+ ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
+ buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
+ buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
+
+ if (buf_len > sizeof(struct wl1271_command))
+ return -EMSGSIZE;
+
+ mutex_lock(&wl->mutex);
+ ret = wl1271_cmd_configure(wl, ie_id, buf, buf_len);
+ mutex_unlock(&wl->mutex);
+
+ if (ret < 0) {
+ wl1271_warning("testmode cmd configure failed: %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
+{
+ int ret = 0;
+ size_t len;
+ void *buf;
+
+ wl1271_debug(DEBUG_TESTMODE, "testmode cmd nvs push");
+
+ if (!tb[WL1271_TM_ATTR_DATA])
+ return -EINVAL;
+
+ buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
+ len = nla_len(tb[WL1271_TM_ATTR_DATA]);
+
+ if (len != sizeof(struct wl1271_nvs_file)) {
+ wl1271_error("nvs size is not as expected: %zu != %zu",
+ len, sizeof(struct wl1271_nvs_file));
+ return -EMSGSIZE;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ kfree(wl->nvs);
+
+ wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
+ if (!wl->nvs) {
+ wl1271_error("could not allocate memory for the nvs file");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(wl->nvs, buf, len);
+
+ wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs");
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
+{
+ u32 val;
+ int ret;
+
+ wl1271_debug(DEBUG_TESTMODE, "testmode cmd set plt mode");
+
+ if (!tb[WL1271_TM_ATTR_PLT_MODE])
+ return -EINVAL;
+
+ val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]);
+
+ switch (val) {
+ case 0:
+ ret = wl1271_plt_stop(wl);
+ break;
+ case 1:
+ ret = wl1271_plt_start(wl);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
+{
+ struct wl1271 *wl = hw->priv;
+ struct nlattr *tb[WL1271_TM_ATTR_MAX + 1];
+ int err;
+
+ err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy);
+ if (err)
+ return err;
+
+ if (!tb[WL1271_TM_ATTR_CMD_ID])
+ return -EINVAL;
+
+ switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) {
+ case WL1271_TM_CMD_TEST:
+ return wl1271_tm_cmd_test(wl, tb);
+ case WL1271_TM_CMD_INTERROGATE:
+ return wl1271_tm_cmd_interrogate(wl, tb);
+ case WL1271_TM_CMD_CONFIGURE:
+ return wl1271_tm_cmd_configure(wl, tb);
+ case WL1271_TM_CMD_NVS_PUSH:
+ return wl1271_tm_cmd_nvs_push(wl, tb);
+ case WL1271_TM_CMD_SET_PLT_MODE:
+ return wl1271_tm_cmd_set_plt_mode(wl, tb);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.h b/drivers/net/wireless/wl12xx/wl1271_testmode.h
new file mode 100644
index 000000000000..c196d28f9d9d
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_testmode.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_TESTMODE_H__
+#define __WL1271_TESTMODE_H__
+
+#include <net/mac80211.h>
+
+int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len);
+
+#endif /* __WL1271_TESTMODE_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index 00af065c77c2..811e739d05bf 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -26,6 +26,7 @@
#include "wl1271.h"
#include "wl1271_spi.h"
+#include "wl1271_io.h"
#include "wl1271_reg.h"
#include "wl1271_ps.h"
#include "wl1271_tx.h"
@@ -87,7 +88,7 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
u32 extra, struct ieee80211_tx_info *control)
{
struct wl1271_tx_hw_descr *desc;
- int pad;
+ int pad, ac;
u16 tx_attr;
desc = (struct wl1271_tx_hw_descr *) skb->data;
@@ -107,9 +108,11 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
/* configure the tx attributes */
tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
- /* FIXME: do we know the packet priority? can we identify mgmt
- packets, and use max prio for them at least? */
- desc->tid = 0;
+
+ /* queue */
+ ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
+ desc->tid = wl1271_tx_ac_to_tid(ac);
+
desc->aid = TX_HW_DEFAULT_AID;
desc->reserved = 0;
@@ -121,6 +124,11 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
pad = pad - skb->len;
tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
+ /* if the packets are destined for AP (have a STA entry) send them
+ with AP rate policies, otherwise use default basic rates */
+ if (control->control.sta)
+ tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY;
+
desc->tx_attr = cpu_to_le16(tx_attr);
wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad);
@@ -158,11 +166,11 @@ static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb,
len = WL1271_TX_ALIGN(skb->len);
/* perform a fixed address block write with the packet */
- wl1271_spi_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
+ wl1271_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
/* write packet new counter into the write access register */
wl->tx_packets_count++;
- wl1271_spi_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
+ wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
desc = (struct wl1271_tx_hw_descr *) skb->data;
wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)",
@@ -196,6 +204,7 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
ret = wl1271_cmd_set_default_wep_key(wl, idx);
if (ret < 0)
return ret;
+ wl->default_key = idx;
}
}
@@ -214,18 +223,50 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
return ret;
}
+static u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
+{
+ struct ieee80211_supported_band *band;
+ u32 enabled_rates = 0;
+ int bit;
+
+ band = wl->hw->wiphy->bands[wl->band];
+ for (bit = 0; bit < band->n_bitrates; bit++) {
+ if (rate_set & 0x1)
+ enabled_rates |= band->bitrates[bit].hw_value;
+ rate_set >>= 1;
+ }
+
+ return enabled_rates;
+}
+
void wl1271_tx_work(struct work_struct *work)
{
struct wl1271 *wl = container_of(work, struct wl1271, tx_work);
struct sk_buff *skb;
bool woken_up = false;
+ u32 sta_rates = 0;
int ret;
+ /* check if the rates supported by the AP have changed */
+ if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED,
+ &wl->flags))) {
+ unsigned long flags;
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ sta_rates = wl->sta_rate_set;
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ }
+
mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
+ /* if rates have changed, re-configure the rate policy */
+ if (unlikely(sta_rates)) {
+ wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
+ wl1271_acx_rate_policies(wl);
+ }
+
while ((skb = skb_dequeue(&wl->tx_queue))) {
if (!woken_up) {
ret = wl1271_ps_elp_wakeup(wl, false);
@@ -240,18 +281,18 @@ void wl1271_tx_work(struct work_struct *work)
wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, "
"stop queues");
ieee80211_stop_queues(wl->hw);
- wl->tx_queue_stopped = true;
+ set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
skb_queue_head(&wl->tx_queue, skb);
goto out;
} else if (ret < 0) {
dev_kfree_skb(skb);
goto out;
- } else if (wl->tx_queue_stopped) {
+ } else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED,
+ &wl->flags)) {
/* firmware buffer has space, restart queues */
wl1271_debug(DEBUG_TX,
"complete_packet: waking queues");
ieee80211_wake_queues(wl->hw);
- wl->tx_queue_stopped = false;
}
}
@@ -335,8 +376,8 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
/* read the tx results from the chipset */
- wl1271_spi_read(wl, le32_to_cpu(memmap->tx_result),
- wl->tx_res_if, sizeof(*wl->tx_res_if), false);
+ wl1271_read(wl, le32_to_cpu(memmap->tx_result),
+ wl->tx_res_if, sizeof(*wl->tx_res_if), false);
/* verify that the result buffer is not getting overrun */
if (count > TX_HW_RESULT_QUEUE_LEN) {
@@ -357,10 +398,10 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
}
/* write host counter to chipset (to ack) */
- wl1271_spi_write32(wl, le32_to_cpu(memmap->tx_result) +
- offsetof(struct wl1271_tx_hw_res_if,
- tx_result_host_counter),
- le32_to_cpu(wl->tx_res_if->tx_result_fw_counter));
+ wl1271_write32(wl, le32_to_cpu(memmap->tx_result) +
+ offsetof(struct wl1271_tx_hw_res_if,
+ tx_result_host_counter),
+ le32_to_cpu(wl->tx_res_if->tx_result_fw_counter));
}
/* caller must hold wl->mutex */
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h
index 416396caf0a0..17e405a09caa 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.h
@@ -123,6 +123,42 @@ struct wl1271_tx_hw_res_if {
struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN];
} __attribute__ ((packed));
+static inline int wl1271_tx_get_queue(int queue)
+{
+ /* FIXME: use best effort until WMM is enabled */
+ return CONF_TX_AC_BE;
+
+ switch (queue) {
+ case 0:
+ return CONF_TX_AC_VO;
+ case 1:
+ return CONF_TX_AC_VI;
+ case 2:
+ return CONF_TX_AC_BE;
+ case 3:
+ return CONF_TX_AC_BK;
+ default:
+ return CONF_TX_AC_BE;
+ }
+}
+
+/* wl1271 tx descriptor needs the tid and we need to convert it from ac */
+static inline int wl1271_tx_ac_to_tid(int ac)
+{
+ switch (ac) {
+ case 0:
+ return 0;
+ case 1:
+ return 2;
+ case 2:
+ return 4;
+ case 3:
+ return 6;
+ default:
+ return 0;
+ }
+}
+
void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_complete(struct wl1271 *wl, u32 count);
void wl1271_tx_flush(struct wl1271 *wl);
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 33c8be7ec8e6..6917286edcae 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -875,20 +875,18 @@ static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev)
static void zd1201_set_multicast(struct net_device *dev)
{
struct zd1201 *zd = netdev_priv(dev);
- struct dev_mc_list *mc = dev->mc_list;
+ struct dev_mc_list *mc;
unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI];
int i;
- if (dev->mc_count > ZD1201_MAXMULTI)
+ if (netdev_mc_count(dev) > ZD1201_MAXMULTI)
return;
- for (i=0; i<dev->mc_count; i++) {
- memcpy(reqbuf+i*ETH_ALEN, mc->dmi_addr, ETH_ALEN);
- mc = mc->next;
- }
+ i = 0;
+ netdev_for_each_mc_addr(mc, dev)
+ memcpy(reqbuf + i++ * ETH_ALEN, mc->dmi_addr, ETH_ALEN);
zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf,
- dev->mc_count*ETH_ALEN, 0);
-
+ netdev_mc_count(dev) * ETH_ALEN, 0);
}
static int zd1201_config_commit(struct net_device *dev,
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index f14deb0c8514..00e09e26c826 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -350,7 +350,7 @@ static void zd_mac_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
first_idx = info->status.rates[0].idx;
ZD_ASSERT(0<=first_idx && first_idx<ARRAY_SIZE(zd_retry_rates));
retries = &zd_retry_rates[first_idx];
- ZD_ASSERT(0<=retry && retry<=retries->count);
+ ZD_ASSERT(1 <= retry && retry <= retries->count);
info->status.rates[0].idx = retries->rate[0];
info->status.rates[0].count = 1; // (retry > 1 ? 2 : 1);
@@ -360,7 +360,7 @@ static void zd_mac_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
info->status.rates[i].count = 1; // ((i==retry-1) && success ? 1:2);
}
for (; i<IEEE80211_TX_MAX_RATES && i<retry; i++) {
- info->status.rates[i].idx = retries->rate[retry-1];
+ info->status.rates[i].idx = retries->rate[retry - 1];
info->status.rates[i].count = 1; // (success ? 1:2);
}
if (i<IEEE80211_TX_MAX_RATES)
@@ -374,7 +374,7 @@ static void zd_mac_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
* zd_mac_tx_failed - callback for failed frames
* @dev: the mac80211 wireless device
*
- * This function is called if a frame couldn't be successfully be
+ * This function is called if a frame couldn't be successfully
* transferred. The first frame from the tx queue, will be selected and
* reported as error to the upper layers.
*/
@@ -424,12 +424,10 @@ void zd_mac_tx_failed(struct urb *urb)
first_idx = info->status.rates[0].idx;
ZD_ASSERT(0<=first_idx && first_idx<ARRAY_SIZE(zd_retry_rates));
retries = &zd_retry_rates[first_idx];
- if (retry < 0 || retry > retries->count) {
+ if (retry <= 0 || retry > retries->count)
continue;
- }
- ZD_ASSERT(0<=retry && retry<=retries->count);
- final_idx = retries->rate[retry-1];
+ final_idx = retries->rate[retry - 1];
final_rate = zd_rates[final_idx].hw_value;
if (final_rate != tx_status->rate) {
@@ -869,7 +867,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
}
static int zd_op_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct zd_mac *mac = zd_hw_mac(hw);
@@ -877,22 +875,22 @@ static int zd_op_add_interface(struct ieee80211_hw *hw,
if (mac->type != NL80211_IFTYPE_UNSPECIFIED)
return -EOPNOTSUPP;
- switch (conf->type) {
+ switch (vif->type) {
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
- mac->type = conf->type;
+ mac->type = vif->type;
break;
default:
return -EOPNOTSUPP;
}
- return zd_write_mac_addr(&mac->chip, conf->mac_addr);
+ return zd_write_mac_addr(&mac->chip, vif->addr);
}
static void zd_op_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct zd_mac *mac = zd_hw_mac(hw);
mac->type = NL80211_IFTYPE_UNSPECIFIED;
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index ac19ecd19cfe..442fc1117326 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -62,6 +62,7 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
/* ZD1211B */
{ USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0409, 0x0248), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
@@ -1078,11 +1079,15 @@ static int eject_installer(struct usb_interface *intf)
int r;
/* Find bulk out endpoint */
- endpoint = &iface_desc->endpoint[1].desc;
- if (usb_endpoint_dir_out(endpoint) &&
- usb_endpoint_xfer_bulk(endpoint)) {
- bulk_out_ep = endpoint->bEndpointAddress;
- } else {
+ for (r = 1; r >= 0; r--) {
+ endpoint = &iface_desc->endpoint[r].desc;
+ if (usb_endpoint_dir_out(endpoint) &&
+ usb_endpoint_xfer_bulk(endpoint)) {
+ bulk_out_ep = endpoint->bEndpointAddress;
+ break;
+ }
+ }
+ if (r == -1) {
dev_err(&udev->dev,
"zd1211rw: Could not find bulk out endpoint\n");
return -ENODEV;
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index 8c777ba4e2b3..1a74594224b1 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -22,11 +22,17 @@
#include <linux/of_device.h>
#include <linux/of_platform.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
#define DRIVER_NAME "xilinx_emaclite"
/* Register offsets for the EmacLite Core */
#define XEL_TXBUFF_OFFSET 0x0 /* Transmit Buffer */
+#define XEL_MDIOADDR_OFFSET 0x07E4 /* MDIO Address Register */
+#define XEL_MDIOWR_OFFSET 0x07E8 /* MDIO Write Data Register */
+#define XEL_MDIORD_OFFSET 0x07EC /* MDIO Read Data Register */
+#define XEL_MDIOCTRL_OFFSET 0x07F0 /* MDIO Control Register */
#define XEL_GIER_OFFSET 0x07F8 /* GIE Register */
#define XEL_TSR_OFFSET 0x07FC /* Tx status */
#define XEL_TPLR_OFFSET 0x07F4 /* Tx packet length */
@@ -37,6 +43,22 @@
#define XEL_BUFFER_OFFSET 0x0800 /* Next Tx/Rx buffer's offset */
+/* MDIO Address Register Bit Masks */
+#define XEL_MDIOADDR_REGADR_MASK 0x0000001F /* Register Address */
+#define XEL_MDIOADDR_PHYADR_MASK 0x000003E0 /* PHY Address */
+#define XEL_MDIOADDR_PHYADR_SHIFT 5
+#define XEL_MDIOADDR_OP_MASK 0x00000400 /* RD/WR Operation */
+
+/* MDIO Write Data Register Bit Masks */
+#define XEL_MDIOWR_WRDATA_MASK 0x0000FFFF /* Data to be Written */
+
+/* MDIO Read Data Register Bit Masks */
+#define XEL_MDIORD_RDDATA_MASK 0x0000FFFF /* Data to be Read */
+
+/* MDIO Control Register Bit Masks */
+#define XEL_MDIOCTRL_MDIOSTS_MASK 0x00000001 /* MDIO Status Mask */
+#define XEL_MDIOCTRL_MDIOEN_MASK 0x00000008 /* MDIO Enable */
+
/* Global Interrupt Enable Register (GIER) Bit Masks */
#define XEL_GIER_GIE_MASK 0x80000000 /* Global Enable */
@@ -87,6 +109,12 @@
* @reset_lock: lock used for synchronization
* @deferred_skb: holds an skb (for transmission at a later time) when the
* Tx buffer is not free
+ * @phy_dev: pointer to the PHY device
+ * @phy_node: pointer to the PHY device node
+ * @mii_bus: pointer to the MII bus
+ * @mdio_irqs: IRQs table for MDIO bus
+ * @last_link: last link status
+ * @has_mdio: indicates whether MDIO is included in the HW
*/
struct net_local {
@@ -100,6 +128,15 @@ struct net_local {
spinlock_t reset_lock;
struct sk_buff *deferred_skb;
+
+ struct phy_device *phy_dev;
+ struct device_node *phy_node;
+
+ struct mii_bus *mii_bus;
+ int mdio_irqs[PHY_MAX_ADDR];
+
+ int last_link;
+ bool has_mdio;
};
@@ -431,7 +468,7 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
}
/**
- * xemaclite_set_mac_address - Set the MAC address for this device
+ * xemaclite_update_address - Update the MAC address in the device
* @drvdata: Pointer to the Emaclite device private data
* @address_ptr:Pointer to the MAC address (MAC address is a 48-bit value)
*
@@ -441,8 +478,8 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
* The MAC address can be programmed using any of the two transmit
* buffers (if configured).
*/
-static void xemaclite_set_mac_address(struct net_local *drvdata,
- u8 *address_ptr)
+static void xemaclite_update_address(struct net_local *drvdata,
+ u8 *address_ptr)
{
void __iomem *addr;
u32 reg_data;
@@ -465,6 +502,30 @@ static void xemaclite_set_mac_address(struct net_local *drvdata,
}
/**
+ * xemaclite_set_mac_address - Set the MAC address for this device
+ * @dev: Pointer to the network device instance
+ * @addr: Void pointer to the sockaddr structure
+ *
+ * This function copies the HW address from the sockaddr strucutre to the
+ * net_device structure and updates the address in HW.
+ *
+ * Return: Error if the net device is busy or 0 if the addr is set
+ * successfully
+ */
+static int xemaclite_set_mac_address(struct net_device *dev, void *address)
+{
+ struct net_local *lp = (struct net_local *) netdev_priv(dev);
+ struct sockaddr *addr = address;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ xemaclite_update_address(lp, dev->dev_addr);
+ return 0;
+}
+
+/**
* xemaclite_tx_timeout - Callback for Tx Timeout
* @dev: Pointer to the network device
*
@@ -641,12 +702,219 @@ static irqreturn_t xemaclite_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/**********************/
+/* MDIO Bus functions */
+/**********************/
+
+/**
+ * xemaclite_mdio_wait - Wait for the MDIO to be ready to use
+ * @lp: Pointer to the Emaclite device private data
+ *
+ * This function waits till the device is ready to accept a new MDIO
+ * request.
+ *
+ * Return: 0 for success or ETIMEDOUT for a timeout
+ */
+
+static int xemaclite_mdio_wait(struct net_local *lp)
+{
+ long end = jiffies + 2;
+
+ /* wait for the MDIO interface to not be busy or timeout
+ after some time.
+ */
+ while (in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET) &
+ XEL_MDIOCTRL_MDIOSTS_MASK) {
+ if (end - jiffies <= 0) {
+ WARN_ON(1);
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+ return 0;
+}
+
+/**
+ * xemaclite_mdio_read - Read from a given MII management register
+ * @bus: the mii_bus struct
+ * @phy_id: the phy address
+ * @reg: register number to read from
+ *
+ * This function waits till the device is ready to accept a new MDIO
+ * request and then writes the phy address to the MDIO Address register
+ * and reads data from MDIO Read Data register, when its available.
+ *
+ * Return: Value read from the MII management register
+ */
+static int xemaclite_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+ struct net_local *lp = bus->priv;
+ u32 ctrl_reg;
+ u32 rc;
+
+ if (xemaclite_mdio_wait(lp))
+ return -ETIMEDOUT;
+
+ /* Write the PHY address, register number and set the OP bit in the
+ * MDIO Address register. Set the Status bit in the MDIO Control
+ * register to start a MDIO read transaction.
+ */
+ ctrl_reg = in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET);
+ out_be32(lp->base_addr + XEL_MDIOADDR_OFFSET,
+ XEL_MDIOADDR_OP_MASK |
+ ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg));
+ out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
+ ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK);
+
+ if (xemaclite_mdio_wait(lp))
+ return -ETIMEDOUT;
+
+ rc = in_be32(lp->base_addr + XEL_MDIORD_OFFSET);
+
+ dev_dbg(&lp->ndev->dev,
+ "xemaclite_mdio_read(phy_id=%i, reg=%x) == %x\n",
+ phy_id, reg, rc);
+
+ return rc;
+}
+
+/**
+ * xemaclite_mdio_write - Write to a given MII management register
+ * @bus: the mii_bus struct
+ * @phy_id: the phy address
+ * @reg: register number to write to
+ * @val: value to write to the register number specified by reg
+ *
+ * This fucntion waits till the device is ready to accept a new MDIO
+ * request and then writes the val to the MDIO Write Data register.
+ */
+static int xemaclite_mdio_write(struct mii_bus *bus, int phy_id, int reg,
+ u16 val)
+{
+ struct net_local *lp = bus->priv;
+ u32 ctrl_reg;
+
+ dev_dbg(&lp->ndev->dev,
+ "xemaclite_mdio_write(phy_id=%i, reg=%x, val=%x)\n",
+ phy_id, reg, val);
+
+ if (xemaclite_mdio_wait(lp))
+ return -ETIMEDOUT;
+
+ /* Write the PHY address, register number and clear the OP bit in the
+ * MDIO Address register and then write the value into the MDIO Write
+ * Data register. Finally, set the Status bit in the MDIO Control
+ * register to start a MDIO write transaction.
+ */
+ ctrl_reg = in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET);
+ out_be32(lp->base_addr + XEL_MDIOADDR_OFFSET,
+ ~XEL_MDIOADDR_OP_MASK &
+ ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg));
+ out_be32(lp->base_addr + XEL_MDIOWR_OFFSET, val);
+ out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
+ ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK);
+
+ return 0;
+}
+
+/**
+ * xemaclite_mdio_reset - Reset the mdio bus.
+ * @bus: Pointer to the MII bus
+ *
+ * This function is required(?) as per Documentation/networking/phy.txt.
+ * There is no reset in this device; this function always returns 0.
+ */
+static int xemaclite_mdio_reset(struct mii_bus *bus)
+{
+ return 0;
+}
+
+/**
+ * xemaclite_mdio_setup - Register mii_bus for the Emaclite device
+ * @lp: Pointer to the Emaclite device private data
+ * @ofdev: Pointer to OF device structure
+ *
+ * This function enables MDIO bus in the Emaclite device and registers a
+ * mii_bus.
+ *
+ * Return: 0 upon success or a negative error upon failure
+ */
+static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)
+{
+ struct mii_bus *bus;
+ int rc;
+ struct resource res;
+ struct device_node *np = of_get_parent(lp->phy_node);
+
+ /* Don't register the MDIO bus if the phy_node or its parent node
+ * can't be found.
+ */
+ if (!np)
+ return -ENODEV;
+
+ /* Enable the MDIO bus by asserting the enable bit in MDIO Control
+ * register.
+ */
+ out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
+ XEL_MDIOCTRL_MDIOEN_MASK);
+
+ bus = mdiobus_alloc();
+ if (!bus)
+ return -ENOMEM;
+
+ of_address_to_resource(np, 0, &res);
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+ (unsigned long long)res.start);
+ bus->priv = lp;
+ bus->name = "Xilinx Emaclite MDIO";
+ bus->read = xemaclite_mdio_read;
+ bus->write = xemaclite_mdio_write;
+ bus->reset = xemaclite_mdio_reset;
+ bus->parent = dev;
+ bus->irq = lp->mdio_irqs; /* preallocated IRQ table */
+
+ lp->mii_bus = bus;
+
+ rc = of_mdiobus_register(bus, np);
+ if (rc)
+ goto err_register;
+
+ return 0;
+
+err_register:
+ mdiobus_free(bus);
+ return rc;
+}
+
+/**
+ * xemaclite_adjust_link - Link state callback for the Emaclite device
+ * @ndev: pointer to net_device struct
+ *
+ * There's nothing in the Emaclite device to be configured when the link
+ * state changes. We just print the status.
+ */
+void xemaclite_adjust_link(struct net_device *ndev)
+{
+ struct net_local *lp = netdev_priv(ndev);
+ struct phy_device *phy = lp->phy_dev;
+ int link_state;
+
+ /* hash together the state values to decide if something has changed */
+ link_state = phy->speed | (phy->duplex << 1) | phy->link;
+
+ if (lp->last_link != link_state) {
+ lp->last_link = link_state;
+ phy_print_status(phy);
+ }
+}
+
/**
* xemaclite_open - Open the network device
* @dev: Pointer to the network device
*
* This function sets the MAC address, requests an IRQ and enables interrupts
* for the Emaclite device and starts the Tx queue.
+ * It also connects to the phy device, if MDIO is included in Emaclite device.
*/
static int xemaclite_open(struct net_device *dev)
{
@@ -656,14 +924,47 @@ static int xemaclite_open(struct net_device *dev)
/* Just to be safe, stop the device first */
xemaclite_disable_interrupts(lp);
+ if (lp->phy_node) {
+ u32 bmcr;
+
+ lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
+ xemaclite_adjust_link, 0,
+ PHY_INTERFACE_MODE_MII);
+ if (!lp->phy_dev) {
+ dev_err(&lp->ndev->dev, "of_phy_connect() failed\n");
+ return -ENODEV;
+ }
+
+ /* EmacLite doesn't support giga-bit speeds */
+ lp->phy_dev->supported &= (PHY_BASIC_FEATURES);
+ lp->phy_dev->advertising = lp->phy_dev->supported;
+
+ /* Don't advertise 1000BASE-T Full/Half duplex speeds */
+ phy_write(lp->phy_dev, MII_CTRL1000, 0);
+
+ /* Advertise only 10 and 100mbps full/half duplex speeds */
+ phy_write(lp->phy_dev, MII_ADVERTISE, ADVERTISE_ALL);
+
+ /* Restart auto negotiation */
+ bmcr = phy_read(lp->phy_dev, MII_BMCR);
+ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ phy_write(lp->phy_dev, MII_BMCR, bmcr);
+
+ phy_start(lp->phy_dev);
+ }
+
/* Set the MAC address each time opened */
- xemaclite_set_mac_address(lp, dev->dev_addr);
+ xemaclite_update_address(lp, dev->dev_addr);
/* Grab the IRQ */
retval = request_irq(dev->irq, xemaclite_interrupt, 0, dev->name, dev);
if (retval) {
dev_err(&lp->ndev->dev, "Could not allocate interrupt %d\n",
dev->irq);
+ if (lp->phy_dev)
+ phy_disconnect(lp->phy_dev);
+ lp->phy_dev = NULL;
+
return retval;
}
@@ -682,6 +983,7 @@ static int xemaclite_open(struct net_device *dev)
*
* This function stops the Tx queue, disables interrupts and frees the IRQ for
* the Emaclite device.
+ * It also disconnects the phy device associated with the Emaclite device.
*/
static int xemaclite_close(struct net_device *dev)
{
@@ -691,6 +993,10 @@ static int xemaclite_close(struct net_device *dev)
xemaclite_disable_interrupts(lp);
free_irq(dev->irq, dev);
+ if (lp->phy_dev)
+ phy_disconnect(lp->phy_dev);
+ lp->phy_dev = NULL;
+
return 0;
}
@@ -754,42 +1060,6 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
}
/**
- * xemaclite_ioctl - Perform IO Control operations on the network device
- * @dev: Pointer to the network device
- * @rq: Pointer to the interface request structure
- * @cmd: IOCTL command
- *
- * The only IOCTL operation supported by this function is setting the MAC
- * address. An error is reported if any other operations are requested.
- *
- * Return: 0 to indicate success, or a negative error for failure.
- */
-static int xemaclite_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct net_local *lp = (struct net_local *) netdev_priv(dev);
- struct hw_addr_data *hw_addr = (struct hw_addr_data *) &rq->ifr_hwaddr;
-
- switch (cmd) {
- case SIOCETHTOOL:
- return -EIO;
-
- case SIOCSIFHWADDR:
- dev_err(&lp->ndev->dev, "SIOCSIFHWADDR\n");
-
- /* Copy MAC address in from user space */
- copy_from_user((void __force *) dev->dev_addr,
- (void __user __force *) hw_addr,
- IFHWADDRLEN);
- xemaclite_set_mac_address(lp, dev->dev_addr);
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
-/**
* xemaclite_remove_ndev - Free the network device
* @ndev: Pointer to the network device to be freed
*
@@ -840,6 +1110,8 @@ static struct net_device_ops xemaclite_netdev_ops;
* This function probes for the Emaclite device in the device tree.
* It initializes the driver data structure and the hardware, sets the MAC
* address and registers the network device.
+ * It also registers a mii_bus for the Emaclite device, if MDIO is included
+ * in the device.
*
* Return: 0, if the driver is bound to the Emaclite device, or
* a negative error if there is failure.
@@ -880,6 +1152,7 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
}
dev_set_drvdata(dev, ndev);
+ SET_NETDEV_DEV(ndev, &ofdev->dev);
ndev->irq = r_irq.start;
ndev->mem_start = r_mem.start;
@@ -923,13 +1196,14 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
out_be32(lp->base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET, 0);
/* Set the MAC address in the EmacLite device */
- xemaclite_set_mac_address(lp, ndev->dev_addr);
+ xemaclite_update_address(lp, ndev->dev_addr);
- dev_info(dev,
- "MAC address is now %2x:%2x:%2x:%2x:%2x:%2x\n",
- ndev->dev_addr[0], ndev->dev_addr[1],
- ndev->dev_addr[2], ndev->dev_addr[3],
- ndev->dev_addr[4], ndev->dev_addr[5]);
+ lp->phy_node = of_parse_phandle(ofdev->node, "phy-handle", 0);
+ rc = xemaclite_mdio_setup(lp, &ofdev->dev);
+ if (rc)
+ dev_warn(&ofdev->dev, "error registering MDIO bus\n");
+
+ dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr);
ndev->netdev_ops = &xemaclite_netdev_ops;
ndev->flags &= ~IFF_MULTICAST;
@@ -972,12 +1246,25 @@ static int __devexit xemaclite_of_remove(struct of_device *of_dev)
struct device *dev = &of_dev->dev;
struct net_device *ndev = dev_get_drvdata(dev);
+ struct net_local *lp = (struct net_local *) netdev_priv(ndev);
+
+ /* Un-register the mii_bus, if configured */
+ if (lp->has_mdio) {
+ mdiobus_unregister(lp->mii_bus);
+ kfree(lp->mii_bus->irq);
+ mdiobus_free(lp->mii_bus);
+ lp->mii_bus = NULL;
+ }
+
unregister_netdev(ndev);
+ if (lp->phy_node)
+ of_node_put(lp->phy_node);
+ lp->phy_node = NULL;
+
release_mem_region(ndev->mem_start, ndev->mem_end-ndev->mem_start + 1);
xemaclite_remove_ndev(ndev);
-
dev_set_drvdata(dev, NULL);
return 0;
@@ -987,7 +1274,7 @@ static struct net_device_ops xemaclite_netdev_ops = {
.ndo_open = xemaclite_open,
.ndo_stop = xemaclite_close,
.ndo_start_xmit = xemaclite_send,
- .ndo_do_ioctl = xemaclite_ioctl,
+ .ndo_set_mac_address = xemaclite_set_mac_address,
.ndo_tx_timeout = xemaclite_tx_timeout,
.ndo_get_stats = xemaclite_get_stats,
};
@@ -999,6 +1286,7 @@ static struct of_device_id xemaclite_of_match[] __devinitdata = {
{ .compatible = "xlnx,xps-ethernetlite-1.00.a", },
{ .compatible = "xlnx,xps-ethernetlite-2.00.a", },
{ .compatible = "xlnx,xps-ethernetlite-2.01.a", },
+ { .compatible = "xlnx,xps-ethernetlite-3.00.a", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, xemaclite_of_match);
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 0f773a9a3ff2..7d4107f5eeb0 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -23,12 +23,12 @@
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define DRV_NAME "yellowfin"
#define DRV_VERSION "2.1"
#define DRV_RELDATE "Sep 11, 2006"
-#define PFX DRV_NAME ": "
-
/* The user-configurable values.
These may be modified when a driver module is loaded.*/
@@ -237,7 +237,7 @@ static const struct pci_id_info pci_id_tbl[] = {
{ }
};
-static const struct pci_device_id yellowfin_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(yellowfin_pci_tbl) = {
{ 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
{ }
@@ -399,7 +399,7 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*np));
if (!dev) {
- printk (KERN_ERR PFX "cannot allocate ethernet device\n");
+ pr_err("cannot allocate ethernet device\n");
return -ENOMEM;
}
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -487,10 +487,10 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
if (i)
goto err_out_unmap_status;
- printk(KERN_INFO "%s: %s type %8x at %p, %pM, IRQ %d.\n",
- dev->name, pci_id_tbl[chip_idx].name,
- ioread32(ioaddr + ChipRev), ioaddr,
- dev->dev_addr, irq);
+ netdev_info(dev, "%s type %8x at %p, %pM, IRQ %d\n",
+ pci_id_tbl[chip_idx].name,
+ ioread32(ioaddr + ChipRev), ioaddr,
+ dev->dev_addr, irq);
if (np->drv_flags & HasMII) {
int phy, phy_idx = 0;
@@ -499,9 +499,8 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
if (mii_status != 0xffff && mii_status != 0x0000) {
np->phys[phy_idx++] = phy;
np->advertising = mdio_read(ioaddr, phy, 4);
- printk(KERN_INFO "%s: MII PHY found at address %d, status "
- "0x%4.4x advertising %4.4x.\n",
- dev->name, phy, mii_status, np->advertising);
+ netdev_info(dev, "MII PHY found at address %d, status 0x%04x advertising %04x\n",
+ phy, mii_status, np->advertising);
}
}
np->mii_cnt = phy_idx;
@@ -584,8 +583,8 @@ static int yellowfin_open(struct net_device *dev)
return ret;
if (yellowfin_debug > 1)
- printk(KERN_DEBUG "%s: yellowfin_open() irq %d.\n",
- dev->name, dev->irq);
+ netdev_printk(KERN_DEBUG, dev, "%s() irq %d\n",
+ __func__, dev->irq);
ret = yellowfin_init_ring(dev);
if (ret) {
@@ -642,8 +641,7 @@ static int yellowfin_open(struct net_device *dev)
iowrite32(0x80008000, ioaddr + TxCtrl);
if (yellowfin_debug > 2) {
- printk(KERN_DEBUG "%s: Done yellowfin_open().\n",
- dev->name);
+ netdev_printk(KERN_DEBUG, dev, "Done %s()\n", __func__);
}
/* Set the timer to check for link beat. */
@@ -664,8 +662,8 @@ static void yellowfin_timer(unsigned long data)
int next_tick = 60*HZ;
if (yellowfin_debug > 3) {
- printk(KERN_DEBUG "%s: Yellowfin timer tick, status %8.8x.\n",
- dev->name, ioread16(ioaddr + IntrStatus));
+ netdev_printk(KERN_DEBUG, dev, "Yellowfin timer tick, status %08x\n",
+ ioread16(ioaddr + IntrStatus));
}
if (yp->mii_cnt) {
@@ -673,9 +671,8 @@ static void yellowfin_timer(unsigned long data)
int lpa = mdio_read(ioaddr, yp->phys[0], MII_LPA);
int negotiated = lpa & yp->advertising;
if (yellowfin_debug > 1)
- printk(KERN_DEBUG "%s: MII #%d status register is %4.4x, "
- "link partner capability %4.4x.\n",
- dev->name, yp->phys[0], bmsr, lpa);
+ netdev_printk(KERN_DEBUG, dev, "MII #%d status register is %04x, link partner capability %04x\n",
+ yp->phys[0], bmsr, lpa);
yp->full_duplex = mii_duplex(yp->duplex_lock, negotiated);
@@ -696,25 +693,24 @@ static void yellowfin_tx_timeout(struct net_device *dev)
struct yellowfin_private *yp = netdev_priv(dev);
void __iomem *ioaddr = yp->base;
- printk(KERN_WARNING "%s: Yellowfin transmit timed out at %d/%d Tx "
- "status %4.4x, Rx status %4.4x, resetting...\n",
- dev->name, yp->cur_tx, yp->dirty_tx,
- ioread32(ioaddr + TxStatus), ioread32(ioaddr + RxStatus));
+ netdev_warn(dev, "Yellowfin transmit timed out at %d/%d Tx status %04x, Rx status %04x, resetting...\n",
+ yp->cur_tx, yp->dirty_tx,
+ ioread32(ioaddr + TxStatus),
+ ioread32(ioaddr + RxStatus));
/* Note: these should be KERN_DEBUG. */
if (yellowfin_debug) {
int i;
- printk(KERN_WARNING " Rx ring %p: ", yp->rx_ring);
+ pr_warning(" Rx ring %p: ", yp->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
- printk(KERN_CONT " %8.8x",
- yp->rx_ring[i].result_status);
- printk(KERN_CONT "\n");
- printk(KERN_WARNING" Tx ring %p: ", yp->tx_ring);
+ pr_cont(" %08x", yp->rx_ring[i].result_status);
+ pr_cont("\n");
+ pr_warning(" Tx ring %p: ", yp->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
- printk(KERN_CONT " %4.4x /%8.8x",
+ pr_cont(" %04x /%08x",
yp->tx_status[i].tx_errs,
yp->tx_ring[i].result_status);
- printk(KERN_CONT "\n");
+ pr_cont("\n");
}
/* If the hardware is found to hang regularly, we will update the code
@@ -891,8 +887,8 @@ static netdev_tx_t yellowfin_start_xmit(struct sk_buff *skb,
yp->tx_full = 1;
if (yellowfin_debug > 4) {
- printk(KERN_DEBUG "%s: Yellowfin transmit frame #%d queued in slot %d.\n",
- dev->name, yp->cur_tx, entry);
+ netdev_printk(KERN_DEBUG, dev, "Yellowfin transmit frame #%d queued in slot %d\n",
+ yp->cur_tx, entry);
}
return NETDEV_TX_OK;
}
@@ -916,8 +912,8 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
u16 intr_status = ioread16(ioaddr + IntrClear);
if (yellowfin_debug > 4)
- printk(KERN_DEBUG "%s: Yellowfin interrupt, status %4.4x.\n",
- dev->name, intr_status);
+ netdev_printk(KERN_DEBUG, dev, "Yellowfin interrupt, status %04x\n",
+ intr_status);
if (intr_status == 0)
break;
@@ -963,13 +959,12 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
#ifndef final_version
if (yellowfin_debug > 5)
- printk(KERN_DEBUG "%s: Tx queue %d check, Tx status "
- "%4.4x %4.4x %4.4x %4.4x.\n",
- dev->name, entry,
- yp->tx_status[entry].tx_cnt,
- yp->tx_status[entry].tx_errs,
- yp->tx_status[entry].total_tx_cnt,
- yp->tx_status[entry].paused);
+ netdev_printk(KERN_DEBUG, dev, "Tx queue %d check, Tx status %04x %04x %04x %04x\n",
+ entry,
+ yp->tx_status[entry].tx_cnt,
+ yp->tx_status[entry].tx_errs,
+ yp->tx_status[entry].total_tx_cnt,
+ yp->tx_status[entry].paused);
#endif
if (tx_errs == 0)
break; /* It still hasn't been Txed */
@@ -978,8 +973,8 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
/* There was an major error, log it. */
#ifndef final_version
if (yellowfin_debug > 1)
- printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n",
- dev->name, tx_errs);
+ netdev_printk(KERN_DEBUG, dev, "Transmit error, Tx status %04x\n",
+ tx_errs);
#endif
dev->stats.tx_errors++;
if (tx_errs & 0xF800) dev->stats.tx_aborted_errors++;
@@ -989,8 +984,8 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
} else {
#ifndef final_version
if (yellowfin_debug > 4)
- printk(KERN_DEBUG "%s: Normal transmit, Tx status %4.4x.\n",
- dev->name, tx_errs);
+ netdev_printk(KERN_DEBUG, dev, "Normal transmit, Tx status %04x\n",
+ tx_errs);
#endif
dev->stats.tx_bytes += skb->len;
dev->stats.collisions += tx_errs & 15;
@@ -1008,8 +1003,8 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
#ifndef final_version
if (yp->cur_tx - dirty_tx > TX_RING_SIZE) {
- printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
- dev->name, dirty_tx, yp->cur_tx, yp->tx_full);
+ netdev_err(dev, "Out-of-sync dirty pointer, %d vs. %d, full=%d\n",
+ dirty_tx, yp->cur_tx, yp->tx_full);
dirty_tx += TX_RING_SIZE;
}
#endif
@@ -1031,16 +1026,15 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
yellowfin_error(dev, intr_status);
if (--boguscnt < 0) {
- printk(KERN_WARNING "%s: Too much work at interrupt, "
- "status=0x%4.4x.\n",
- dev->name, intr_status);
+ netdev_warn(dev, "Too much work at interrupt, status=%#04x\n",
+ intr_status);
break;
}
} while (1);
if (yellowfin_debug > 3)
- printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
- dev->name, ioread16(ioaddr + IntrStatus));
+ netdev_printk(KERN_DEBUG, dev, "exiting interrupt, status=%#04x\n",
+ ioread16(ioaddr + IntrStatus));
spin_unlock (&yp->lock);
return IRQ_RETVAL(handled);
@@ -1055,9 +1049,9 @@ static int yellowfin_rx(struct net_device *dev)
int boguscnt = yp->dirty_rx + RX_RING_SIZE - yp->cur_rx;
if (yellowfin_debug > 4) {
- printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %8.8x.\n",
+ printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %08x\n",
entry, yp->rx_ring[entry].result_status);
- printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n",
+ printk(KERN_DEBUG " #%d desc. %08x %08x %08x\n",
entry, yp->rx_ring[entry].dbdma_cmd, yp->rx_ring[entry].addr,
yp->rx_ring[entry].result_status);
}
@@ -1081,20 +1075,20 @@ static int yellowfin_rx(struct net_device *dev)
le32_to_cpu(desc->result_status)) & 0xffff;
frame_status = get_unaligned_le16(&(buf_addr[data_size - 2]));
if (yellowfin_debug > 4)
- printk(KERN_DEBUG " yellowfin_rx() status was %4.4x.\n",
- frame_status);
+ printk(KERN_DEBUG " %s() status was %04x\n",
+ __func__, frame_status);
if (--boguscnt < 0)
break;
if ( ! (desc_status & RX_EOP)) {
if (data_size != 0)
- printk(KERN_WARNING "%s: Oversized Ethernet frame spanned multiple buffers,"
- " status %4.4x, data_size %d!\n", dev->name, desc_status, data_size);
+ netdev_warn(dev, "Oversized Ethernet frame spanned multiple buffers, status %04x, data_size %d!\n",
+ desc_status, data_size);
dev->stats.rx_length_errors++;
} else if ((yp->drv_flags & IsGigabit) && (frame_status & 0x0038)) {
/* There was a error. */
if (yellowfin_debug > 3)
- printk(KERN_DEBUG " yellowfin_rx() Rx error was %4.4x.\n",
- frame_status);
+ printk(KERN_DEBUG " %s() Rx error was %04x\n",
+ __func__, frame_status);
dev->stats.rx_errors++;
if (frame_status & 0x0060) dev->stats.rx_length_errors++;
if (frame_status & 0x0008) dev->stats.rx_frame_errors++;
@@ -1118,8 +1112,8 @@ static int yellowfin_rx(struct net_device *dev)
entry*sizeof(struct yellowfin_desc)),
"\377\377\377\377\377\377", 6) != 0) {
if (bogus_rx++ == 0)
- printk(KERN_WARNING "%s: Bad frame to %pM\n",
- dev->name, buf_addr);
+ netdev_warn(dev, "Bad frame to %pM\n",
+ buf_addr);
#endif
} else {
struct sk_buff *skb;
@@ -1129,9 +1123,8 @@ static int yellowfin_rx(struct net_device *dev)
#ifndef final_version
if (yellowfin_debug > 4)
- printk(KERN_DEBUG " yellowfin_rx() normal Rx pkt length %d"
- " of %d, bogus_cnt %d.\n",
- pkt_len, data_size, boguscnt);
+ printk(KERN_DEBUG " %s() normal Rx pkt length %d of %d, bogus_cnt %d\n",
+ __func__, pkt_len, data_size, boguscnt);
#endif
/* Check if the packet is long enough to just pass up the skbuff
without copying to a properly sized skbuff. */
@@ -1191,8 +1184,7 @@ static int yellowfin_rx(struct net_device *dev)
static void yellowfin_error(struct net_device *dev, int intr_status)
{
- printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
- dev->name, intr_status);
+ netdev_err(dev, "Something Wicked happened! %04x\n", intr_status);
/* Hmmmmm, it's not clear what to do here. */
if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))
dev->stats.tx_errors++;
@@ -1209,13 +1201,13 @@ static int yellowfin_close(struct net_device *dev)
netif_stop_queue (dev);
if (yellowfin_debug > 1) {
- printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x "
- "Rx %4.4x Int %2.2x.\n",
- dev->name, ioread16(ioaddr + TxStatus),
- ioread16(ioaddr + RxStatus),
- ioread16(ioaddr + IntrStatus));
- printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
- dev->name, yp->cur_tx, yp->dirty_tx, yp->cur_rx, yp->dirty_rx);
+ netdev_printk(KERN_DEBUG, dev, "Shutting down ethercard, status was Tx %04x Rx %04x Int %02x\n",
+ ioread16(ioaddr + TxStatus),
+ ioread16(ioaddr + RxStatus),
+ ioread16(ioaddr + IntrStatus));
+ netdev_printk(KERN_DEBUG, dev, "Queue pointers were Tx %d / %d, Rx %d / %d\n",
+ yp->cur_tx, yp->dirty_tx,
+ yp->cur_rx, yp->dirty_rx);
}
/* Disable interrupts by clearing the interrupt mask. */
@@ -1229,33 +1221,35 @@ static int yellowfin_close(struct net_device *dev)
#if defined(__i386__)
if (yellowfin_debug > 2) {
- printk(KERN_DEBUG" Tx ring at %8.8llx:\n",
+ printk(KERN_DEBUG " Tx ring at %08llx:\n",
(unsigned long long)yp->tx_ring_dma);
for (i = 0; i < TX_RING_SIZE*2; i++)
- printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x %8.8x %8.8x.\n",
+ printk(KERN_DEBUG " %c #%d desc. %08x %08x %08x %08x\n",
ioread32(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ',
i, yp->tx_ring[i].dbdma_cmd, yp->tx_ring[i].addr,
yp->tx_ring[i].branch_addr, yp->tx_ring[i].result_status);
printk(KERN_DEBUG " Tx status %p:\n", yp->tx_status);
for (i = 0; i < TX_RING_SIZE; i++)
- printk(KERN_DEBUG " #%d status %4.4x %4.4x %4.4x %4.4x.\n",
+ printk(KERN_DEBUG " #%d status %04x %04x %04x %04x\n",
i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs,
yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused);
- printk(KERN_DEBUG " Rx ring %8.8llx:\n",
+ printk(KERN_DEBUG " Rx ring %08llx:\n",
(unsigned long long)yp->rx_ring_dma);
for (i = 0; i < RX_RING_SIZE; i++) {
- printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x %8.8x\n",
+ printk(KERN_DEBUG " %c #%d desc. %08x %08x %08x\n",
ioread32(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ',
i, yp->rx_ring[i].dbdma_cmd, yp->rx_ring[i].addr,
yp->rx_ring[i].result_status);
if (yellowfin_debug > 6) {
if (get_unaligned((u8*)yp->rx_ring[i].addr) != 0x69) {
int j;
+
+ printk(KERN_DEBUG);
for (j = 0; j < 0x50; j++)
- printk(" %4.4x",
- get_unaligned(((u16*)yp->rx_ring[i].addr) + j));
- printk("\n");
+ pr_cont(" %04x",
+ get_unaligned(((u16*)yp->rx_ring[i].addr) + j));
+ pr_cont("\n");
}
}
}
@@ -1281,8 +1275,8 @@ static int yellowfin_close(struct net_device *dev)
#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
if (yellowfin_debug > 0) {
- printk(KERN_DEBUG "%s: Received %d frames that we should not have.\n",
- dev->name, bogus_rx);
+ netdev_printk(KERN_DEBUG, dev, "Received %d frames that we should not have\n",
+ bogus_rx);
}
#endif
@@ -1301,16 +1295,17 @@ static void set_rx_mode(struct net_device *dev)
iowrite16(cfg_value & ~0x1000, ioaddr + Cnfg);
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
iowrite16(0x000F, ioaddr + AddrMode);
- } else if ((dev->mc_count > 64) || (dev->flags & IFF_ALLMULTI)) {
+ } else if ((netdev_mc_count(dev) > 64) ||
+ (dev->flags & IFF_ALLMULTI)) {
/* Too many to filter well, or accept all multicasts. */
iowrite16(0x000B, ioaddr + AddrMode);
- } else if (dev->mc_count > 0) { /* Must use the multicast hash table. */
+ } else if (!netdev_mc_empty(dev)) { /* Must use the multicast hash table. */
struct dev_mc_list *mclist;
u16 hash_table[4];
int i;
+
memset(hash_table, 0, sizeof(hash_table));
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
unsigned int bit;
/* Due to a bug in the early chip versions, multiple filter
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index bc5ae0f6e934..def49d2ec69a 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -313,7 +313,8 @@ static void znet_set_multicast_list (struct net_device *dev)
/* Byte D */
cfblk->dummy_1 = 1; /* set to 1 */
cfblk->tx_ifs_retrig = 3; /* Hmm... Disabled */
- cfblk->mc_all = (dev->mc_list || (dev->flags&IFF_ALLMULTI));/* multicast all mode */
+ cfblk->mc_all = (!netdev_mc_empty(dev) ||
+ (dev->flags & IFF_ALLMULTI)); /* multicast all mode */
cfblk->rcv_mon = 0; /* Monitor mode disabled */
cfblk->frag_acpt = 0; /* Do not accept fragments */
cfblk->tstrttrs = 0; /* No start transmission threshold */
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index d2fa27c5c1b2..7cecc8fea9bd 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -1,3 +1,11 @@
+config OF_FLATTREE
+ bool
+ depends on OF
+
+config OF_DYNAMIC
+ def_bool y
+ depends on OF && PPC_OF
+
config OF_DEVICE
def_bool y
depends on OF && (SPARC || PPC_OF || MICROBLAZE)
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index bdfb5f5d4b06..f232cc98ce00 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -1,4 +1,5 @@
obj-y = base.o
+obj-$(CONFIG_OF_FLATTREE) += fdt.o
obj-$(CONFIG_OF_DEVICE) += device.o platform.o
obj-$(CONFIG_OF_GPIO) += gpio.o
obj-$(CONFIG_OF_I2C) += of_i2c.o
diff --git a/drivers/of/base.c b/drivers/of/base.c
index e6627b2320f1..cb96888d1427 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -20,8 +20,10 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
struct device_node *allnodes;
+struct device_node *of_chosen;
/* use when traversing tree through the allnext, child, sibling,
* or parent members of struct device_node.
@@ -37,7 +39,7 @@ int of_n_addr_cells(struct device_node *np)
np = np->parent;
ip = of_get_property(np, "#address-cells", NULL);
if (ip)
- return *ip;
+ return be32_to_cpup(ip);
} while (np->parent);
/* No #address-cells property for the root node */
return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
@@ -53,13 +55,88 @@ int of_n_size_cells(struct device_node *np)
np = np->parent;
ip = of_get_property(np, "#size-cells", NULL);
if (ip)
- return *ip;
+ return be32_to_cpup(ip);
} while (np->parent);
/* No #size-cells property for the root node */
return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
}
EXPORT_SYMBOL(of_n_size_cells);
+#if !defined(CONFIG_SPARC) /* SPARC doesn't do ref counting (yet) */
+/**
+ * of_node_get - Increment refcount of a node
+ * @node: Node to inc refcount, NULL is supported to
+ * simplify writing of callers
+ *
+ * Returns node.
+ */
+struct device_node *of_node_get(struct device_node *node)
+{
+ if (node)
+ kref_get(&node->kref);
+ return node;
+}
+EXPORT_SYMBOL(of_node_get);
+
+static inline struct device_node *kref_to_device_node(struct kref *kref)
+{
+ return container_of(kref, struct device_node, kref);
+}
+
+/**
+ * of_node_release - release a dynamically allocated node
+ * @kref: kref element of the node to be released
+ *
+ * In of_node_put() this function is passed to kref_put()
+ * as the destructor.
+ */
+static void of_node_release(struct kref *kref)
+{
+ struct device_node *node = kref_to_device_node(kref);
+ struct property *prop = node->properties;
+
+ /* We should never be releasing nodes that haven't been detached. */
+ if (!of_node_check_flag(node, OF_DETACHED)) {
+ pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name);
+ dump_stack();
+ kref_init(&node->kref);
+ return;
+ }
+
+ if (!of_node_check_flag(node, OF_DYNAMIC))
+ return;
+
+ while (prop) {
+ struct property *next = prop->next;
+ kfree(prop->name);
+ kfree(prop->value);
+ kfree(prop);
+ prop = next;
+
+ if (!prop) {
+ prop = node->deadprops;
+ node->deadprops = NULL;
+ }
+ }
+ kfree(node->full_name);
+ kfree(node->data);
+ kfree(node);
+}
+
+/**
+ * of_node_put - Decrement refcount of a node
+ * @node: Node to dec refcount, NULL is supported to
+ * simplify writing of callers
+ *
+ */
+void of_node_put(struct device_node *node)
+{
+ if (node)
+ kref_put(&node->kref, of_node_release);
+}
+EXPORT_SYMBOL(of_node_put);
+#endif /* !CONFIG_SPARC */
+
struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp)
@@ -144,6 +221,27 @@ int of_device_is_compatible(const struct device_node *device,
EXPORT_SYMBOL(of_device_is_compatible);
/**
+ * of_machine_is_compatible - Test root of device tree for a given compatible value
+ * @compat: compatible string to look for in root node's compatible property.
+ *
+ * Returns true if the root node has the given value in its
+ * compatible property.
+ */
+int of_machine_is_compatible(const char *compat)
+{
+ struct device_node *root;
+ int rc = 0;
+
+ root = of_find_node_by_path("/");
+ if (root) {
+ rc = of_device_is_compatible(root, compat);
+ of_node_put(root);
+ }
+ return rc;
+}
+EXPORT_SYMBOL(of_machine_is_compatible);
+
+/**
* of_device_is_available - check if a device is available for use
*
* @device: Node to check for availability
@@ -519,6 +617,27 @@ int of_modalias_node(struct device_node *node, char *modalias, int len)
EXPORT_SYMBOL_GPL(of_modalias_node);
/**
+ * of_find_node_by_phandle - Find a node given a phandle
+ * @handle: phandle of the node to find
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_phandle(phandle handle)
+{
+ struct device_node *np;
+
+ read_lock(&devtree_lock);
+ for (np = allnodes; np; np = np->allnext)
+ if (np->phandle == handle)
+ break;
+ of_node_get(np);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_phandle);
+
+/**
* of_parse_phandle - Resolve a phandle property to a device_node pointer
* @np: Pointer to device node holding phandle property
* @phandle_name: Name of property holding a phandle value
@@ -578,8 +697,8 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
const void **out_args)
{
int ret = -EINVAL;
- const u32 *list;
- const u32 *list_end;
+ const __be32 *list;
+ const __be32 *list_end;
int size;
int cur_index = 0;
struct device_node *node = NULL;
@@ -593,7 +712,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
list_end = list + size / sizeof(*list);
while (list < list_end) {
- const u32 *cells;
+ const __be32 *cells;
const phandle *phandle;
phandle = list++;
@@ -617,7 +736,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
goto err1;
}
- list += *cells;
+ list += be32_to_cpup(cells);
if (list > list_end) {
pr_debug("%s: insufficient arguments length\n",
np->full_name);
@@ -658,3 +777,190 @@ err0:
return ret;
}
EXPORT_SYMBOL(of_parse_phandles_with_args);
+
+/**
+ * prom_add_property - Add a property to a node
+ */
+int prom_add_property(struct device_node *np, struct property *prop)
+{
+ struct property **next;
+ unsigned long flags;
+
+ prop->next = NULL;
+ write_lock_irqsave(&devtree_lock, flags);
+ next = &np->properties;
+ while (*next) {
+ if (strcmp(prop->name, (*next)->name) == 0) {
+ /* duplicate ! don't insert it */
+ write_unlock_irqrestore(&devtree_lock, flags);
+ return -1;
+ }
+ next = &(*next)->next;
+ }
+ *next = prop;
+ write_unlock_irqrestore(&devtree_lock, flags);
+
+#ifdef CONFIG_PROC_DEVICETREE
+ /* try to add to proc as well if it was initialized */
+ if (np->pde)
+ proc_device_tree_add_prop(np->pde, prop);
+#endif /* CONFIG_PROC_DEVICETREE */
+
+ return 0;
+}
+
+/**
+ * prom_remove_property - Remove a property from a node.
+ *
+ * Note that we don't actually remove it, since we have given out
+ * who-knows-how-many pointers to the data using get-property.
+ * Instead we just move the property to the "dead properties"
+ * list, so it won't be found any more.
+ */
+int prom_remove_property(struct device_node *np, struct property *prop)
+{
+ struct property **next;
+ unsigned long flags;
+ int found = 0;
+
+ write_lock_irqsave(&devtree_lock, flags);
+ next = &np->properties;
+ while (*next) {
+ if (*next == prop) {
+ /* found the node */
+ *next = prop->next;
+ prop->next = np->deadprops;
+ np->deadprops = prop;
+ found = 1;
+ break;
+ }
+ next = &(*next)->next;
+ }
+ write_unlock_irqrestore(&devtree_lock, flags);
+
+ if (!found)
+ return -ENODEV;
+
+#ifdef CONFIG_PROC_DEVICETREE
+ /* try to remove the proc node as well */
+ if (np->pde)
+ proc_device_tree_remove_prop(np->pde, prop);
+#endif /* CONFIG_PROC_DEVICETREE */
+
+ return 0;
+}
+
+/*
+ * prom_update_property - Update a property in a node.
+ *
+ * Note that we don't actually remove it, since we have given out
+ * who-knows-how-many pointers to the data using get-property.
+ * Instead we just move the property to the "dead properties" list,
+ * and add the new property to the property list
+ */
+int prom_update_property(struct device_node *np,
+ struct property *newprop,
+ struct property *oldprop)
+{
+ struct property **next;
+ unsigned long flags;
+ int found = 0;
+
+ write_lock_irqsave(&devtree_lock, flags);
+ next = &np->properties;
+ while (*next) {
+ if (*next == oldprop) {
+ /* found the node */
+ newprop->next = oldprop->next;
+ *next = newprop;
+ oldprop->next = np->deadprops;
+ np->deadprops = oldprop;
+ found = 1;
+ break;
+ }
+ next = &(*next)->next;
+ }
+ write_unlock_irqrestore(&devtree_lock, flags);
+
+ if (!found)
+ return -ENODEV;
+
+#ifdef CONFIG_PROC_DEVICETREE
+ /* try to add to proc as well if it was initialized */
+ if (np->pde)
+ proc_device_tree_update_prop(np->pde, newprop, oldprop);
+#endif /* CONFIG_PROC_DEVICETREE */
+
+ return 0;
+}
+
+#if defined(CONFIG_OF_DYNAMIC)
+/*
+ * Support for dynamic device trees.
+ *
+ * On some platforms, the device tree can be manipulated at runtime.
+ * The routines in this section support adding, removing and changing
+ * device tree nodes.
+ */
+
+/**
+ * of_attach_node - Plug a device node into the tree and global list.
+ */
+void of_attach_node(struct device_node *np)
+{
+ unsigned long flags;
+
+ write_lock_irqsave(&devtree_lock, flags);
+ np->sibling = np->parent->child;
+ np->allnext = allnodes;
+ np->parent->child = np;
+ allnodes = np;
+ write_unlock_irqrestore(&devtree_lock, flags);
+}
+
+/**
+ * of_detach_node - "Unplug" a node from the device tree.
+ *
+ * The caller must hold a reference to the node. The memory associated with
+ * the node is not freed until its refcount goes to zero.
+ */
+void of_detach_node(struct device_node *np)
+{
+ struct device_node *parent;
+ unsigned long flags;
+
+ write_lock_irqsave(&devtree_lock, flags);
+
+ parent = np->parent;
+ if (!parent)
+ goto out_unlock;
+
+ if (allnodes == np)
+ allnodes = np->allnext;
+ else {
+ struct device_node *prev;
+ for (prev = allnodes;
+ prev->allnext != np;
+ prev = prev->allnext)
+ ;
+ prev->allnext = np->allnext;
+ }
+
+ if (parent->child == np)
+ parent->child = np->sibling;
+ else {
+ struct device_node *prevsib;
+ for (prevsib = np->parent->child;
+ prevsib->sibling != np;
+ prevsib = prevsib->sibling)
+ ;
+ prevsib->sibling = np->sibling;
+ }
+
+ of_node_set_flag(np, OF_DETACHED);
+
+out_unlock:
+ write_unlock_irqrestore(&devtree_lock, flags);
+}
+#endif /* defined(CONFIG_OF_DYNAMIC) */
+
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
new file mode 100644
index 000000000000..406757a9d7ea
--- /dev/null
+++ b/drivers/of/fdt.c
@@ -0,0 +1,590 @@
+/*
+ * Functions for working with the Flattened Device Tree data format
+ *
+ * Copyright 2009 Benjamin Herrenschmidt, IBM Corp
+ * benh@kernel.crashing.org
+ *
+ * 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/kernel.h>
+#include <linux/initrd.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#ifdef CONFIG_PPC
+#include <asm/machdep.h>
+#endif /* CONFIG_PPC */
+
+#include <asm/page.h>
+
+int __initdata dt_root_addr_cells;
+int __initdata dt_root_size_cells;
+
+struct boot_param_header *initial_boot_params;
+
+char *find_flat_dt_string(u32 offset)
+{
+ return ((char *)initial_boot_params) +
+ be32_to_cpu(initial_boot_params->off_dt_strings) + offset;
+}
+
+/**
+ * of_scan_flat_dt - scan flattened tree blob and call callback on each.
+ * @it: callback function
+ * @data: context data pointer
+ *
+ * This function is used to scan the flattened device-tree, it is
+ * used to extract the memory information at boot before we can
+ * unflatten the tree
+ */
+int __init of_scan_flat_dt(int (*it)(unsigned long node,
+ const char *uname, int depth,
+ void *data),
+ void *data)
+{
+ unsigned long p = ((unsigned long)initial_boot_params) +
+ be32_to_cpu(initial_boot_params->off_dt_struct);
+ int rc = 0;
+ int depth = -1;
+
+ do {
+ u32 tag = be32_to_cpup((__be32 *)p);
+ char *pathp;
+
+ p += 4;
+ if (tag == OF_DT_END_NODE) {
+ depth--;
+ continue;
+ }
+ if (tag == OF_DT_NOP)
+ continue;
+ if (tag == OF_DT_END)
+ break;
+ if (tag == OF_DT_PROP) {
+ u32 sz = be32_to_cpup((__be32 *)p);
+ p += 8;
+ if (be32_to_cpu(initial_boot_params->version) < 0x10)
+ p = _ALIGN(p, sz >= 8 ? 8 : 4);
+ p += sz;
+ p = _ALIGN(p, 4);
+ continue;
+ }
+ if (tag != OF_DT_BEGIN_NODE) {
+ pr_err("Invalid tag %x in flat device tree!\n", tag);
+ return -EINVAL;
+ }
+ depth++;
+ pathp = (char *)p;
+ p = _ALIGN(p + strlen(pathp) + 1, 4);
+ if ((*pathp) == '/') {
+ char *lp, *np;
+ for (lp = NULL, np = pathp; *np; np++)
+ if ((*np) == '/')
+ lp = np+1;
+ if (lp != NULL)
+ pathp = lp;
+ }
+ rc = it(p, pathp, depth, data);
+ if (rc != 0)
+ break;
+ } while (1);
+
+ return rc;
+}
+
+/**
+ * of_get_flat_dt_root - find the root node in the flat blob
+ */
+unsigned long __init of_get_flat_dt_root(void)
+{
+ unsigned long p = ((unsigned long)initial_boot_params) +
+ be32_to_cpu(initial_boot_params->off_dt_struct);
+
+ while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
+ p += 4;
+ BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
+ p += 4;
+ return _ALIGN(p + strlen((char *)p) + 1, 4);
+}
+
+/**
+ * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
+ *
+ * This function can be used within scan_flattened_dt callback to get
+ * access to properties
+ */
+void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
+ unsigned long *size)
+{
+ unsigned long p = node;
+
+ do {
+ u32 tag = be32_to_cpup((__be32 *)p);
+ u32 sz, noff;
+ const char *nstr;
+
+ p += 4;
+ if (tag == OF_DT_NOP)
+ continue;
+ if (tag != OF_DT_PROP)
+ return NULL;
+
+ sz = be32_to_cpup((__be32 *)p);
+ noff = be32_to_cpup((__be32 *)(p + 4));
+ p += 8;
+ if (be32_to_cpu(initial_boot_params->version) < 0x10)
+ p = _ALIGN(p, sz >= 8 ? 8 : 4);
+
+ nstr = find_flat_dt_string(noff);
+ if (nstr == NULL) {
+ pr_warning("Can't find property index name !\n");
+ return NULL;
+ }
+ if (strcmp(name, nstr) == 0) {
+ if (size)
+ *size = sz;
+ return (void *)p;
+ }
+ p += sz;
+ p = _ALIGN(p, 4);
+ } while (1);
+}
+
+/**
+ * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
+ * @node: node to test
+ * @compat: compatible string to compare with compatible list.
+ */
+int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
+{
+ const char *cp;
+ unsigned long cplen, l;
+
+ cp = of_get_flat_dt_prop(node, "compatible", &cplen);
+ if (cp == NULL)
+ return 0;
+ while (cplen > 0) {
+ if (strncasecmp(cp, compat, strlen(compat)) == 0)
+ return 1;
+ l = strlen(cp) + 1;
+ cp += l;
+ cplen -= l;
+ }
+
+ return 0;
+}
+
+static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
+ unsigned long align)
+{
+ void *res;
+
+ *mem = _ALIGN(*mem, align);
+ res = (void *)*mem;
+ *mem += size;
+
+ return res;
+}
+
+/**
+ * unflatten_dt_node - Alloc and populate a device_node from the flat tree
+ * @p: pointer to node in flat tree
+ * @dad: Parent struct device_node
+ * @allnextpp: pointer to ->allnext from last allocated device_node
+ * @fpsize: Size of the node path up at the current depth.
+ */
+unsigned long __init unflatten_dt_node(unsigned long mem,
+ unsigned long *p,
+ struct device_node *dad,
+ struct device_node ***allnextpp,
+ unsigned long fpsize)
+{
+ struct device_node *np;
+ struct property *pp, **prev_pp = NULL;
+ char *pathp;
+ u32 tag;
+ unsigned int l, allocl;
+ int has_name = 0;
+ int new_format = 0;
+
+ tag = be32_to_cpup((__be32 *)(*p));
+ if (tag != OF_DT_BEGIN_NODE) {
+ pr_err("Weird tag at start of node: %x\n", tag);
+ return mem;
+ }
+ *p += 4;
+ pathp = (char *)*p;
+ l = allocl = strlen(pathp) + 1;
+ *p = _ALIGN(*p + l, 4);
+
+ /* version 0x10 has a more compact unit name here instead of the full
+ * path. we accumulate the full path size using "fpsize", we'll rebuild
+ * it later. We detect this because the first character of the name is
+ * not '/'.
+ */
+ if ((*pathp) != '/') {
+ new_format = 1;
+ if (fpsize == 0) {
+ /* root node: special case. fpsize accounts for path
+ * plus terminating zero. root node only has '/', so
+ * fpsize should be 2, but we want to avoid the first
+ * level nodes to have two '/' so we use fpsize 1 here
+ */
+ fpsize = 1;
+ allocl = 2;
+ } else {
+ /* account for '/' and path size minus terminal 0
+ * already in 'l'
+ */
+ fpsize += l;
+ allocl = fpsize;
+ }
+ }
+
+ np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
+ __alignof__(struct device_node));
+ if (allnextpp) {
+ memset(np, 0, sizeof(*np));
+ np->full_name = ((char *)np) + sizeof(struct device_node);
+ if (new_format) {
+ char *fn = np->full_name;
+ /* rebuild full path for new format */
+ if (dad && dad->parent) {
+ strcpy(fn, dad->full_name);
+#ifdef DEBUG
+ if ((strlen(fn) + l + 1) != allocl) {
+ pr_debug("%s: p: %d, l: %d, a: %d\n",
+ pathp, (int)strlen(fn),
+ l, allocl);
+ }
+#endif
+ fn += strlen(fn);
+ }
+ *(fn++) = '/';
+ memcpy(fn, pathp, l);
+ } else
+ memcpy(np->full_name, pathp, l);
+ prev_pp = &np->properties;
+ **allnextpp = np;
+ *allnextpp = &np->allnext;
+ if (dad != NULL) {
+ np->parent = dad;
+ /* we temporarily use the next field as `last_child'*/
+ if (dad->next == NULL)
+ dad->child = np;
+ else
+ dad->next->sibling = np;
+ dad->next = np;
+ }
+ kref_init(&np->kref);
+ }
+ while (1) {
+ u32 sz, noff;
+ char *pname;
+
+ tag = be32_to_cpup((__be32 *)(*p));
+ if (tag == OF_DT_NOP) {
+ *p += 4;
+ continue;
+ }
+ if (tag != OF_DT_PROP)
+ break;
+ *p += 4;
+ sz = be32_to_cpup((__be32 *)(*p));
+ noff = be32_to_cpup((__be32 *)((*p) + 4));
+ *p += 8;
+ if (be32_to_cpu(initial_boot_params->version) < 0x10)
+ *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
+
+ pname = find_flat_dt_string(noff);
+ if (pname == NULL) {
+ pr_info("Can't find property name in list !\n");
+ break;
+ }
+ if (strcmp(pname, "name") == 0)
+ has_name = 1;
+ l = strlen(pname) + 1;
+ pp = unflatten_dt_alloc(&mem, sizeof(struct property),
+ __alignof__(struct property));
+ if (allnextpp) {
+ /* We accept flattened tree phandles either in
+ * ePAPR-style "phandle" properties, or the
+ * legacy "linux,phandle" properties. If both
+ * appear and have different values, things
+ * will get weird. Don't do that. */
+ if ((strcmp(pname, "phandle") == 0) ||
+ (strcmp(pname, "linux,phandle") == 0)) {
+ if (np->phandle == 0)
+ np->phandle = *((u32 *)*p);
+ }
+ /* And we process the "ibm,phandle" property
+ * used in pSeries dynamic device tree
+ * stuff */
+ if (strcmp(pname, "ibm,phandle") == 0)
+ np->phandle = *((u32 *)*p);
+ pp->name = pname;
+ pp->length = sz;
+ pp->value = (void *)*p;
+ *prev_pp = pp;
+ prev_pp = &pp->next;
+ }
+ *p = _ALIGN((*p) + sz, 4);
+ }
+ /* with version 0x10 we may not have the name property, recreate
+ * it here from the unit name if absent
+ */
+ if (!has_name) {
+ char *p1 = pathp, *ps = pathp, *pa = NULL;
+ int sz;
+
+ while (*p1) {
+ if ((*p1) == '@')
+ pa = p1;
+ if ((*p1) == '/')
+ ps = p1 + 1;
+ p1++;
+ }
+ if (pa < ps)
+ pa = p1;
+ sz = (pa - ps) + 1;
+ pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
+ __alignof__(struct property));
+ if (allnextpp) {
+ pp->name = "name";
+ pp->length = sz;
+ pp->value = pp + 1;
+ *prev_pp = pp;
+ prev_pp = &pp->next;
+ memcpy(pp->value, ps, sz - 1);
+ ((char *)pp->value)[sz - 1] = 0;
+ pr_debug("fixed up name for %s -> %s\n", pathp,
+ (char *)pp->value);
+ }
+ }
+ if (allnextpp) {
+ *prev_pp = NULL;
+ np->name = of_get_property(np, "name", NULL);
+ np->type = of_get_property(np, "device_type", NULL);
+
+ if (!np->name)
+ np->name = "<NULL>";
+ if (!np->type)
+ np->type = "<NULL>";
+ }
+ while (tag == OF_DT_BEGIN_NODE) {
+ mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
+ tag = be32_to_cpup((__be32 *)(*p));
+ }
+ if (tag != OF_DT_END_NODE) {
+ pr_err("Weird tag at end of node: %x\n", tag);
+ return mem;
+ }
+ *p += 4;
+ return mem;
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+/**
+ * early_init_dt_check_for_initrd - Decode initrd location from flat tree
+ * @node: reference to node containing initrd location ('chosen')
+ */
+void __init early_init_dt_check_for_initrd(unsigned long node)
+{
+ unsigned long start, end, len;
+ __be32 *prop;
+
+ pr_debug("Looking for initrd properties... ");
+
+ prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
+ if (!prop)
+ return;
+ start = of_read_ulong(prop, len/4);
+
+ prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len);
+ if (!prop)
+ return;
+ end = of_read_ulong(prop, len/4);
+
+ early_init_dt_setup_initrd_arch(start, end);
+ pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", start, end);
+}
+#else
+inline void early_init_dt_check_for_initrd(unsigned long node)
+{
+}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+/**
+ * early_init_dt_scan_root - fetch the top level address and size cells
+ */
+int __init early_init_dt_scan_root(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ __be32 *prop;
+
+ if (depth != 0)
+ return 0;
+
+ dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+ dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+
+ prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
+ if (prop)
+ dt_root_size_cells = be32_to_cpup(prop);
+ pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells);
+
+ prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
+ if (prop)
+ dt_root_addr_cells = be32_to_cpup(prop);
+ pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells);
+
+ /* break now */
+ return 1;
+}
+
+u64 __init dt_mem_next_cell(int s, __be32 **cellp)
+{
+ __be32 *p = *cellp;
+
+ *cellp = p + s;
+ return of_read_number(p, s);
+}
+
+/**
+ * early_init_dt_scan_memory - Look for an parse memory nodes
+ */
+int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ char *type = of_get_flat_dt_prop(node, "device_type", NULL);
+ __be32 *reg, *endp;
+ unsigned long l;
+
+ /* We are scanning "memory" nodes only */
+ if (type == NULL) {
+ /*
+ * The longtrail doesn't have a device_type on the
+ * /memory node, so look for the node called /memory@0.
+ */
+ if (depth != 1 || strcmp(uname, "memory@0") != 0)
+ return 0;
+ } else if (strcmp(type, "memory") != 0)
+ return 0;
+
+ reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
+ if (reg == NULL)
+ reg = of_get_flat_dt_prop(node, "reg", &l);
+ if (reg == NULL)
+ return 0;
+
+ endp = reg + (l / sizeof(__be32));
+
+ pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n",
+ uname, l, reg[0], reg[1], reg[2], reg[3]);
+
+ while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
+ u64 base, size;
+
+ base = dt_mem_next_cell(dt_root_addr_cells, &reg);
+ size = dt_mem_next_cell(dt_root_size_cells, &reg);
+
+ if (size == 0)
+ continue;
+ pr_debug(" - %llx , %llx\n", (unsigned long long)base,
+ (unsigned long long)size);
+
+ early_init_dt_add_memory_arch(base, size);
+ }
+
+ return 0;
+}
+
+int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ unsigned long l;
+ char *p;
+
+ pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
+
+ if (depth != 1 ||
+ (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
+ return 0;
+
+ early_init_dt_check_for_initrd(node);
+
+ /* Retreive command line */
+ p = of_get_flat_dt_prop(node, "bootargs", &l);
+ if (p != NULL && l > 0)
+ strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));
+
+#ifdef CONFIG_CMDLINE
+#ifndef CONFIG_CMDLINE_FORCE
+ if (p == NULL || l == 0 || (l == 1 && (*p) == 0))
+#endif
+ strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
+#endif /* CONFIG_CMDLINE */
+
+ early_init_dt_scan_chosen_arch(node);
+
+ pr_debug("Command line is: %s\n", cmd_line);
+
+ /* break now */
+ return 1;
+}
+
+/**
+ * unflatten_device_tree - create tree of device_nodes from flat blob
+ *
+ * unflattens the device-tree passed by the firmware, creating the
+ * tree of struct device_node. It also fills the "name" and "type"
+ * pointers of the nodes so the normal device-tree walking functions
+ * can be used.
+ */
+void __init unflatten_device_tree(void)
+{
+ unsigned long start, mem, size;
+ struct device_node **allnextp = &allnodes;
+
+ pr_debug(" -> unflatten_device_tree()\n");
+
+ /* First pass, scan for size */
+ start = ((unsigned long)initial_boot_params) +
+ be32_to_cpu(initial_boot_params->off_dt_struct);
+ size = unflatten_dt_node(0, &start, NULL, NULL, 0);
+ size = (size | 3) + 1;
+
+ pr_debug(" size is %lx, allocating...\n", size);
+
+ /* Allocate memory for the expanded device tree */
+ mem = early_init_dt_alloc_memory_arch(size + 4,
+ __alignof__(struct device_node));
+ mem = (unsigned long) __va(mem);
+
+ ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
+
+ pr_debug(" unflattening %lx...\n", mem);
+
+ /* Second pass, do actual unflattening */
+ start = ((unsigned long)initial_boot_params) +
+ be32_to_cpu(initial_boot_params->off_dt_struct);
+ unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
+ if (be32_to_cpup((__be32 *)start) != OF_DT_END)
+ pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
+ if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
+ pr_warning("End of tree marker overwritten: %08x\n",
+ be32_to_cpu(((__be32 *)mem)[size / 4]));
+ *allnextp = NULL;
+
+ /* Get pointer to OF "/chosen" node for use everywhere */
+ of_chosen = of_find_node_by_path("/chosen");
+ if (of_chosen == NULL)
+ of_chosen = of_find_node_by_path("/chosen@0");
+
+ pr_debug(" <- unflatten_device_tree()\n");
+}
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
index 6eea601a9204..24c3606217f8 100644
--- a/drivers/of/gpio.c
+++ b/drivers/of/gpio.c
@@ -36,7 +36,7 @@ int of_get_gpio_flags(struct device_node *np, int index,
struct of_gpio_chip *of_gc = NULL;
int size;
const void *gpio_spec;
- const u32 *gpio_cells;
+ const __be32 *gpio_cells;
ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index,
&gc, &gpio_spec);
@@ -55,7 +55,7 @@ int of_get_gpio_flags(struct device_node *np, int index,
gpio_cells = of_get_property(gc, "#gpio-cells", &size);
if (!gpio_cells || size != sizeof(*gpio_cells) ||
- *gpio_cells != of_gc->gpio_cells) {
+ be32_to_cpup(gpio_cells) != of_gc->gpio_cells) {
pr_debug("%s: wrong #gpio-cells for %s\n",
np->full_name, gc->full_name);
ret = -EINVAL;
@@ -127,7 +127,8 @@ EXPORT_SYMBOL(of_gpio_count);
int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np,
const void *gpio_spec, enum of_gpio_flags *flags)
{
- const u32 *gpio = gpio_spec;
+ const __be32 *gpio = gpio_spec;
+ const u32 n = be32_to_cpup(gpio);
/*
* We're discouraging gpio_cells < 2, since that way you'll have to
@@ -140,13 +141,13 @@ int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np,
return -EINVAL;
}
- if (*gpio > of_gc->gc.ngpio)
+ if (n > of_gc->gc.ngpio)
return -EINVAL;
if (flags)
- *flags = gpio[1];
+ *flags = be32_to_cpu(gpio[1]);
- return *gpio;
+ return n;
}
EXPORT_SYMBOL(of_gpio_simple_xlate);
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index fa65a2b2ae2e..a3a708e590d0 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -25,7 +25,7 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
for_each_child_of_node(adap_node, node) {
struct i2c_board_info info = {};
struct dev_archdata dev_ad = {};
- const u32 *addr;
+ const __be32 *addr;
int len;
if (of_modalias_node(node, info.type, sizeof(info.type)) < 0)
@@ -40,7 +40,7 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
info.irq = irq_of_parse_and_map(node, 0);
- info.addr = *addr;
+ info.addr = be32_to_cpup(addr);
dev_archdata_set_node(&dev_ad, node);
info.archdata = &dev_ad;
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 4b22ba568b19..18ecae4a4375 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -51,7 +51,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
/* Loop over the child nodes and register a phy_device for each one */
for_each_child_of_node(np, child) {
- const u32 *addr;
+ const __be32 *addr;
int len;
/* A PHY must have a reg property in the range [0-31] */
@@ -68,7 +68,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
mdio->irq[*addr] = PHY_POLL;
}
- phy = get_phy_device(mdio, *addr);
+ phy = get_phy_device(mdio, be32_to_cpup(addr));
if (!phy) {
dev_err(&mdio->dev, "error probing PHY at address %i\n",
*addr);
@@ -160,7 +160,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
struct device_node *net_np;
char bus_id[MII_BUS_ID_SIZE + 3];
struct phy_device *phy;
- const u32 *phy_id;
+ const __be32 *phy_id;
int sz;
if (!dev->dev.parent)
@@ -174,7 +174,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
if (!phy_id || sz < sizeof(*phy_id))
return NULL;
- sprintf(bus_id, PHY_ID_FMT, "0", phy_id[0]);
+ sprintf(bus_id, PHY_ID_FMT, "0", be32_to_cpu(phy_id[0]));
phy = phy_connect(dev, bus_id, hndlr, 0, iface);
return IS_ERR(phy) ? NULL : phy;
diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c
index bed0ed6dcdc1..f65f48b98448 100644
--- a/drivers/of/of_spi.c
+++ b/drivers/of/of_spi.c
@@ -23,7 +23,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np)
{
struct spi_device *spi;
struct device_node *nc;
- const u32 *prop;
+ const __be32 *prop;
int rc;
int len;
@@ -54,7 +54,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np)
spi_dev_put(spi);
continue;
}
- spi->chip_select = *prop;
+ spi->chip_select = be32_to_cpup(prop);
/* Mode (clock phase/polarity/etc.) */
if (of_find_property(nc, "spi-cpha", NULL))
@@ -72,7 +72,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np)
spi_dev_put(spi);
continue;
}
- spi->max_speed_hz = *prop;
+ spi->max_speed_hz = be32_to_cpup(prop);
/* IRQ */
spi->irq = irq_of_parse_and_map(nc, 0);
diff --git a/drivers/parisc/eisa_enumerator.c b/drivers/parisc/eisa_enumerator.c
index 0be1d50645ab..caa153133754 100644
--- a/drivers/parisc/eisa_enumerator.c
+++ b/drivers/parisc/eisa_enumerator.c
@@ -460,7 +460,7 @@ static int init_slot(int slot, struct eeprom_eisa_slot_info *es)
slot, id_string);
print_eisa_id(id_string, es->eisa_slot_id);
- printk(" expected %s \n", id_string);
+ printk(" expected %s\n", id_string);
return -1;
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index 0bc5d474b168..1062b8ffe244 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -481,7 +481,7 @@ pdcspath_attr_store(struct kobject *kobj, struct attribute *attr,
return ret;
}
-static struct sysfs_ops pdcspath_attr_ops = {
+static const struct sysfs_ops pdcspath_attr_ops = {
.show = pdcspath_attr_show,
.store = pdcspath_attr_store,
};
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index a35c9c5b89e8..f7806d81f1e0 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -169,7 +169,7 @@ superio_init(struct pci_dev *pcidev)
/* ...then properly fixup the USB to point at suckyio PIC */
sio->usb_pdev->irq = superio_fixup_irq(sio->usb_pdev);
- printk(KERN_INFO PFX "Found NS87560 Legacy I/O device at %s (IRQ %i) \n",
+ printk(KERN_INFO PFX "Found NS87560 Legacy I/O device at %s (IRQ %i)\n",
pci_name(pdev), pdev->irq);
pci_read_config_dword (pdev, SIO_SP1BAR, &sio->sp1_base);
diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog
deleted file mode 100644
index 8565bbbeb6ec..000000000000
--- a/drivers/parport/ChangeLog
+++ /dev/null
@@ -1,583 +0,0 @@
-2001-10-11 Tim Waugh <twaugh@redhat.com>
- * parport_pc.c, parport_serial.c: Support for NetMos cards.
- + Patch originally from Michael Reinelt <reinelt@eunet.at>.
-
-2002-04-25 Tim Waugh <twaugh@redhat.com>
-
- * parport_serial.c, parport_pc.c: Move some SIIG cards around.
- Patch from Andrey Panin.
-
-2002-01-20 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_compat_write_block_pio,
- parport_pc_ecp_write_block_pio, parport_pc_ecp_read_block_pio):
- Use the default implementations if the caller wants to use
- O_NONBLOCK.
-
-2002-02-25 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c: Make sure that priv->ctr_writable includes IntEn
- even if IRQ is given as a parameter.
-
-2002-01-21 Tim Waugh <twaugh@redhat.com>
-
- * daisy.c: Apply patch from Max Vorobiev to make parport_daisy_select
- work for ECP/EPP modes.
-
-2002-01-13 Niels Kristian Bech Jensen <nkbj@image.dk>
-
- * parport_pc.c: Change some occurrences of frob_set_mode to
- ECR_WRITE. This fixes PLIP.
-
-2002-01-04 Tim Waugh <twaugh@redhat.com>
-
- * share.c (parport_claim_or_block): Sleep interruptibly to prevent
- a possible deadlock.
-
-2001-12-07 Damian Gruszka <damian.gruszka@VisionSystems.de>
-
- * parport_pc.c (ECR_WRITE): Define. If there are forbidden bits
- in the ECR register for some chips, this will be a useful place to
- put that knowledge.
- (change_mode): Use ECR_WRITE.
- (parport_pc_restore_state): Likewise.
- (parport_ECPPS2_supported): Likewise.
- (parport_ECPEPP_supported): Likewise.
- (irq_probe_EPP): Likewise.
- (programmable_irq_support): Likewise.
- (programmable_dma_support): Likewise.
- (parport_pc_probe_port): Likewise.
-
- (frob_set_mode): New function. Set the mode bits of the ECR.
- (get_fifo_residue): Use frob_set_mode.
- (parport_pc_ecpepp_read_data): Likewise.
- (parport_pc_ecpepp_write_data): Likewise.
- (parport_pc_ecpepp_read_addr): Likewise.
- (parport_pc_ecpepp_write_addr): Likewise.
- (parport_pc_compat_write_block_pio): Likewise.
- (parport_pc_ecp_write_block_pio): Likewise.
- (parport_ECR_present): Likewise.
- (parport_ECP_supported): Likewise.
- (parport_EPP_supported): Likewise.
- (parport_ECPEPP_supported): Likewise.
- (programmable_irq_support): Likewise.
- (irq_probe_ECP): Likewise.
- (programmable_dma_support): Likewise.
-
- (parport_pc_enable_irq): Only enable interrupts if we know which
- IRQ line they will come from.
- (parport_pc_init_state): Set nErrIntrEn at initialisation.
- (parport_pc_restore_state): Only write writable bits of CTR.
- (parport_irq_probe): If no IRQ is found, take ackIntEn out of the
- writable bit set.
-
-2001-12-07 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_fifo_write_block_pio): Correct typo.
- (parport_pc_init_state): Only set ackIntEn if we know which IRQ
- line the interrupts will come from.
-
-2001-12-07 Tim Waugh <twaugh@redhat.com>
-
- * ieee1284_ops.c (parport_ieee1284_epp_write_addr,
- parport_ieee1284_epp_read_addr): Actually do something useful.
-
-2001-12-07 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (dmaval): Don't use DMA by default. It seems to be
- too buggy at the moment. Use 'dma=auto' to restore the previous
- behaviour.
-
-2001-12-07 Tim Waugh <twaugh@redhat.com>
-
- * daisy.c (DEBUG): Undefine.
-
-2001-12-06 Tim Waugh <twaugh@redhat.com>
-
- * ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off
- PARPORT_CONTROL_AUTOFD as well. Bug spotted by Joe
- <joeja@mindspring.com>.
-
-2001-12-03 Rich Liu <Rich.Liu@ite.com.tw>
-
- * parport_pc.c (sio_ite_8872_probe): ITE8873 is a single-port
- serial board, not a serial+parallel.
-
-2001-11-30 Niels Kristian Bech Jensen <nkbj@image.dk>
-
- * parport_pc.c: Fix compiler warning.
-
-2001-11-14 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_pci_probe): Hooks for PCI cards before
- and after probing for ports.
- * parport_serial.c (parport_register): Likewise.
-
-2001-11-12 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (init_module): Warn when parameters are ignored.
-
-2001-11-01 Damian Gruszka <damian.gruszka@VisionSystems.de>
-
- * parport_serial.c (serial_register): Set base_baud before
- calling register_serial.
-
-2001-10-26 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_irq_probe): When ECR programmable IRQ
- support fails, generate interrupts using the FIFO even if we don't
- want to use the FIFO for real data transfers.
- (parport_pc_probe_port): Display the ECR address if we have an
- ECR, not just if we will use the FIFO.
-
-2001-10-24 Dave Strauss <D.Strauss@motorola.com>
-
- * parport_pc.c (parport_pc_compat_write_block_pio,
- parport_pc_ecp_write_block_pio): Allow a few seconds for an ECP
- transfer to finish up.
-
-2001-10-11 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc (sio_ite_8872_probe): New function, submitted by Rich
- Liu from ITE. Cleaned up, removed bogus phys_to_virt calls.
-
-2001-10-24 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c: Support for AKS AladdinCARD. Patch from
- Aladdin Knowledge Systems (Christian Groessler).
-
-2001-10-24 Tim Waugh <twaugh@redhat.com>
-
- * ieee1284_ops.c (parport_ieee1284_ecp_read_data): Try to minimise
- turnaround time.
-
- * ieee1284.c (parport_poll_peripheral): Try a couple of times
- first without delaying.
-
-2001-10-10 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c: Support for OX16PCI954 PCI card.
-
-2001-10-10 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c: Support for OX12PCI840 PCI card (reported by
- mk@daveg.com). Lock-ups diagnosed by Ronnie Arosa (and now we
- just don't trust its ECR).
-
-2001-10-10 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
-
- * parport_pc.c: Support for AVLAB cards.
-
-2001-10-10 Tim Waugh <twaugh@redhat.com>
-
- * ieee1284_ops.c (ecp_forward_to_reverse, ecp_reverse_to_forward):
- Remember to retry direction switch if it fails. Patch from David
- Lambert.
-
-2001-10-08 David C. Hansen <haveblue@us.ibm.com>
-
- * share.c: Make driverlist_lock and parportlist_lock static.
-
-2001-10-08 Philip Blundell <philb@gnu.org>
-
- * parport_pc.c: New modular parameter verbose_logging.
- Make port->modes indicate the modes that we are prepared to use,
- rather than the modes that are available.
-
-2001-10-07 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_probe_port): Fix memory leak spotted by
- Kipp Cannon.
-
-2001-10-07 Tim Waugh <twaugh@redhat.com>
-
- * parport_serial.c: Remove NetMos support, since it causes problems
- for some people.
-
-2001-08-30 Tim Waugh <twaugh@redhat.com>
-
- * parport_serial.c (parport_serial_pci_probe): Clean-up on partial
- registration failure.
-
-2001-08-14 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_init_superio): Allow for more than one
- SuperIO device. Patch from Rich Lio (ITE).
-
-2001-08-11 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c: Support for Titan Electronics cards.
-
-2001-08-08 Tim Waugh <twaugh@redhat.com>
-
- * share.c (parport_unregister_device): Remove device from wait list
- too.
-
-2001-06-20 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c: Make 'io_hi=0' work.
-
-2001-05-31 Tim Waugh <twaugh@redhat.com>
-
- * parport_serial.c: New file.
-
-2001-06-05 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_unregister_port): New exported function.
- Do the opposite of parport_pc_probe_port.
- (cleanup_module): Use it.
-
-2001-05-22 Juan Quintela <quintela@mandrakesoft.com>
-
- * parport_amiga.c: Set printk levels.
- * parport_gsc.c: Likewise.
- * parport_mfc3.c: Likewise.
- * parport_pc.c: Likewise.
- * parport_sunbpp.c: Likewise.
- * probe.c: Likewise.
- * share.c: Likewise.
-
-2001-05-10 Fred Barnes <frmb2@ukc.ac.uk>
-
- * parport_pc.c (parport_pc_epp_read_data): added support for
- reading from a w91284pic peripheral, flag is PARPORT_W91284PIC.
-
-2001-05-07 Fred Barnes <frmb2@ukc.ac.uk>
-
- * parport_pc.c (parport_pc_epp_read_data,
- parport_pc_epp_write_data, parport_pc_epp_read_addr,
- parport_pc_epp_write_addr): support for fast reads/writes using
- the PARPORT_EPP_FAST flag.
-
- * ieee1284.c (parport_read, parport_write): added code to handle
- software EPP mode (IEEE1284_MODE_EPPSWE). Added code to allow
- BYTE mode reverse transfers (previously always went for NIBBLE
- mode).
-
- * ieee1284_ops.c (parport_ieee1284_epp_read_data,
- parport_ieee1284_epp_write_data): fixed various polarity problems.
- Also (theoretically) fixed address versions (.._addr), but no
- hardware to test this on.
-
- * parport_pc.h: added parport_dump_state() function for debugging.
- Needs to have DEBUG_PARPORT to be defined for it to be included.
-
-2001-05-03 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c: Fix the compile problem I introduce from the last
- change.
-
-2001-04-20 Paul Gortmaker <p_gortmaker@yahoo.com>
-
- * parport_pc.c: Cut down the size quite a bit (more than 4k off
- the object, about 1k off the zImage) for the older non-PCI
- machines which are typically resource starved anyway...
-
-2001-03-26 R Horn <rjh@world.std.com>
-
- * parport_pc.c: Some commentary changes.
-
-2001-04-19 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_probe_port): Remove __devinit
- attribute. Export unconditionally.
-
-2001-04-14 Jeff Garzik <jgarzik@pobox.com>
-
- Merged: 2001-03-30 Tim Waugh <twaugh@redhat.com>
-
- * drivers/parport/parport_pc.c: Make Via SuperIO chipsets behave
- like everything else with respect to irq= and dma= parameters.
-
-2001-04-08 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_save_state): Read from the soft copy of
- the control port.
- (parport_pc_restore_state): Update the soft copy of the control
- port.
-
-2001-03-26 Tim Waugh <twaugh@redhat.com>
-
- * share.c (parport_find_number, parport_find_base): Trigger
- a lowlevel driver load if there are no ports yet.
-
-2001-03-26 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_ECP_supported): Remove the IRQ conflict
- check since it seems totally unreliable.
-
-2001-03-02 Tim Waugh <twaugh@redhat.com>
-
- * ieee1284_ops.c (parport_ieee1284_read_nibble): Reset nAutoFd
- on timeout. Matches 2.2.x behaviour.
-
-2001-03-02 Andrew Morton
-
- * parport_pc.c (registered_parport): New static variable.
- (parport_pc_find_ports): Set it when we register PCI driver.
- (init_module): Unregister PCI driver if necessary when we
- fail.
-
-2001-03-02 Tim Waugh <twaugh@redhat.com>
-
- * ieee1284_ops.c (parport_ieee1284_write_compat): Don't use
- down_trylock to reset the IRQ count. Don't even use sema_init,
- because it's not even necessary to reset the count. I can't
- remember why we ever did.
-
-2001-01-04 Peter Osterlund <peter.osterlund@mailbox.swipnet.se>
-
- * ieee1284.c (parport_negotiate): Fix missing printk argument.
-
-2001-01-03 Paul Schleger <Paul.Schleger@t-online.de>
-
- * probe.c (parse_data): Get rid of trailing blanks in values.
- Needed for XEROX XJ8C printer.
-
-2001-01-03 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_probe_port): Say something when probes
- are omitted.
-
-2001-01-03 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (sio_via_686a_probe): Correct dma=255 fix.
-
-2000-11-21 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_ecp_write_block_pio): Fix
- reverse-to-forward logic. Spotted by Roland Kuck
- <rci@cityweb.de>.
-
-2000-09-16 Cesar Eduardo Barros <cesarb@nitnet.com.br>
-
- * parport_pc.c (sio_via_686a_probe): Handle case
- where hardware returns 255 for IRQ or DMA.
-
-2000-07-20 Eddie C. Dost <ecd@skynet.be>
-
- * share.c (attach_driver_chain): attach[i](port) needs to be
- replaced by attach[count](port).
-
-2000-07-20 Eddie C. Dost <ecd@skynet.be>
-
- * daisy.c (add_dev): kmalloc args are in wrong order.
-
-2000-07-12 Tim Waugh <twaugh@redhat.com>
-
- * share.c: Documentation for parport_{get,port}_port,
- parport_find_{number,base}.
-
-2000-07-12 Tim Waugh <twaugh@redhat.com>
-
- * share.c (parport_unregister_device): Remove unneeded locking
- (test cad==dev).
- (parport_claim): Likewise.
- (parport_find_number): New function.
-
-2000-07-12 Tim Waugh <twaugh@redhat.com>
-
- * share.c (parport_register_port): Hold the parportlist_lock while
- looking for a free parport number.
- (parport_register_driver): Make sure that attach can block.
- (attach_driver_chain): Likewise.
-
-2000-07-12 Tim Waugh <twaugh@redhat.com>
-
- * share.c (call_driver_chain): Do reference counting things.
- (parport_get_port): New function.
- (parport_put_port): New function.
- (parport_register_port): Initialise reference count to zero.
- (parport_unregister_port): Check reference count rather than
- driver list to see if we can free the port.
-
-2000-07-12 Tim Waugh <twaugh@redhat.com>
-
- * share.c: Clarifications in doc comments.
-
-2000-07-12 Tim Waugh <twaugh@redhat.com>
-
- * share.c (parport_unregister_port): Fix typo in comment.
-
-2000-07-11 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
-
- * parport_pc.c: Support for the full range of Timedia cards.
-
-2000-07-08 Tim Waugh <twaugh@redhat.com>
-
- * daisy.c: License block comments as part of parportbook.
- * ieee1284.c: Likewise.
- * share.c: Likewise.
-
-2000-06-30 Petr Vandrovec <vandrove@vc.cvut.cz>
-
- * procfs.c (do_hardware_modes): Generated string can be up to 34
- chars long.
-
-2000-06-20 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
-
- * parport_pc.c (parport_pc_compat_write_block_pio): Warn about
- change_mode failures.
- (parport_pc_ecp_write_block_pio): Likewise.
- (parport_pc_ecp_read_block_pio): Likewise.
-
-2000-06-20 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
-
- * parport_pc.c (parport_SPP_supported): Warn more about possibly
- incorrect parameters.
-
-2000-06-15 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_ECP_supported): Set PARPORT_MODE_COMPAT
- for ECP ports, since they can all do hardware accelerated
- compatibility mode (I assume).
-
-2000-06-13 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (cleanup_module): Remark about possible bugs.
-
-2000-06-13 Tim Waugh <twaugh@redhat.com>
-
- * procfs.c: Break 'hardware' out into separate files.
-
-2000-05-28 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
-
- * Fix PCI ID printk for non-superio PCI cards.
-
-2000-05-28 Tim Waugh <twaugh@redhat.com>
-
- * share.c (call_driver_chain): Get the driverlist_lock.
- (parport_register_device): Make sure that port->devices always
- looks consistent.
- (parport_register_driver): Ensure that parport drivers are given
- parameters that are valid for the duration of the callback by
- locking the portlist against changes.
- (parport_unregister_driver): Likewise.
- (parport_claim): Don't overwrite flags.
-
-2000-05-28 Tim Waugh <twaugh@redhat.com>
-
- * daisy.c (assign_addrs): Avoid double-probing daisy-chain devices
- if the first probe succeeds.
-
-2000-05-16 Tim Waugh <twaugh@redhat.com>
-
- * share.c (parport_claim): Fix SMP race.
-
-2000-05-15 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
-
- * parport_pc.c (parport_pc_compat_write_block_pio): Check for
- timeouts.
- (parport_pc_ecp_write_block_pio): Likewise.
- (parport_pc_ecp_read_block_pio): Likewise.
-
-2000-05-02 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
-
- * parport_pc.c: PCI SYBA patch and verbose PCI detection.
-
-2000-05-02 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
-
- * parport_pc.c (decode_smsc): Fix SMSC 665/666 identification.
-
-2000-04-28 Tim Waugh <twaugh@redhat.com>
-
- * ieee1284.c: Short function descriptions can't be multiline.
-
- * daisy.c: Short function descriptions can't be multiline.
-
-2000-04-19 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_fifo_write_block_dma): Make maxlen
- calculation a bit clearer.
-
- * ieee1284.c (parport_negotiate): Turn on data line drivers.
-
- * ieee1284_ops.c (parport_ieee1284_read_byte): Turn off data line
- drivers.
- (parport_ieee1284_write_compat): Turn on data line drivers.
-
- * daisy.c (assign_addrs): Turn on data line drivers.
- (cpp_mux): Likewise.
- (cpp_daisy): Likewise.
-
-2000-04-04 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c: Add support for another PCI card.
-
-2000-04-04 Tim Waugh <twaugh@redhat.com>
-
- * daisy.c: Documentation in kernel-doc format.
-
- * ieee1284.c: Likewise.
-
- * share.c: Likewise.
-
-2000-04-01 Tim Waugh <twaugh@redhat.com>
-
- * share.c (parport_register_device): Need to hold the module
- reference counts before sleeping.
-
-2000-03-27 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_ecp_read_block_pio): Correct operation
- when peripheral is trying to send data when we stop listening.
-
-2000-03-22 Tim Waugh <twaugh@redhat.com>
-
- * init.c (parport_setup): Fix return value.
-
-2000-03-21 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_pci_probe): Fix return value; call
- pci_enable_device.
-
-2000-03-16 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_ECP_supported): This seems to trigger on
- machines that don't have an IRQ conflict; toned down the warning
- message accordingly.
-
-2000-03-16 Gunther Mayer <gunther.mayer@braunschweig.netsurf.de>
-
- * parport_pc.c (show_parconfig_smsc37c669): Fix typo.
- (decode_winbond): More IDs.
- (winbond_check): Protect against false positives.
- (winbond_check2): Likewise.
- (smsc_check): Likewise.
-
-2000-03-15 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (cleanup_module): Don't call pci_unregister_driver
- if we didn't call pci_register_driver first.
-
-2000-03-13 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (parport_pc_init): Moved from asm/parport.h.
-
- * Config.in: CONFIG_PARPORT_PC_SUPERIO: new option.
-
- * parport_pc.c (show_parconfig_smsc37c669): Make __devinit.
- (show_parconfig_winbond): Likewise.
- (decode_winbond): Likewise.
- (decode_smsc): Likewise.
- (winbond_check): Likewise.
- (winbond_check2): Likewise.
- (smsc_check): Likewise.
- (detect_and_report_winbond): Likewise.
- (detect_and_report_smsc): Likewise.
- (get_superio_dma): Likewise.
- (get_superio_irq): Likewise.
- (parport_pc_find_isa_ports): New function.
- (parport_pc_find_ports): New function.
- (init_module): Make superio a config option, not a parameter.
-
-2000-03-10 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c (decode_winbond): Use correct 83877ATF chip ID.
- (decode_winbond): Fix typo.
-
-2000-03-09 Tim Waugh <twaugh@redhat.com>
-
- * parport_pc.c: Integrate SuperIO PCI probe with normal PCI card
- probe, so that the MODULE_DEVICE_TABLE is complete.
-
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index ad113b0f62db..0950fa40684f 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2908,6 +2908,7 @@ enum parport_pc_pci_cards {
netmos_9805,
netmos_9815,
netmos_9901,
+ netmos_9865,
quatech_sppxp100,
};
@@ -2989,6 +2990,7 @@ static struct parport_pc_pci {
/* netmos_9805 */ { 1, { { 0, -1 }, } },
/* netmos_9815 */ { 2, { { 0, -1 }, { 2, -1 }, } },
/* netmos_9901 */ { 1, { { 0, -1 }, } },
+ /* netmos_9865 */ { 1, { { 0, -1 }, } },
/* quatech_sppxp100 */ { 1, { { 0, 1 }, } },
};
@@ -3092,6 +3094,10 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
0xA000, 0x2000, 0, 0, netmos_9901 },
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+ 0xA000, 0x1000, 0, 0, netmos_9865 },
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+ 0xA000, 0x2000, 0, 0, netmos_9865 },
/* Quatech SPPXP-100 Parallel port PCI ExpressCard */
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 },
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index b1ecefa2a23d..7858a117e80b 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -21,17 +21,6 @@ config PCI_MSI
If you don't know what to do here, say N.
-config PCI_LEGACY
- bool "Enable deprecated pci_find_* API"
- depends on PCI
- default y
- help
- Say Y here if you want to include support for the deprecated
- pci_find_device() API. Most drivers have been converted over
- to using the proper hotplug APIs, so this option serves to
- include/exclude only a few drivers that are still using this
- API.
-
config PCI_DEBUG
bool "PCI Debugging"
depends on PCI && DEBUG_KERNEL
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 4df48d58eaa6..3d102dd87c9f 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -2,14 +2,13 @@
# Makefile for the PCI bus specific drivers.
#
-obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \
+obj-y += access.o bus.o probe.o remove.o pci.o \
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
- irq.o
+ irq.o vpd.o
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o
-obj-$(CONFIG_PCI_LEGACY) += legacy.o
-CFLAGS_legacy.o += -Wno-deprecated-declarations
+obj-$(CONFIG_PCI_QUIRKS) += quirks.o
# Build PCI Express stuff if needed
obj-$(CONFIG_PCIEPORTBUS) += pcie/
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index cef28a79103f..26301cb25e7f 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -17,6 +17,52 @@
#include "pci.h"
+void pci_bus_add_resource(struct pci_bus *bus, struct resource *res,
+ unsigned int flags)
+{
+ struct pci_bus_resource *bus_res;
+
+ bus_res = kzalloc(sizeof(struct pci_bus_resource), GFP_KERNEL);
+ if (!bus_res) {
+ dev_err(&bus->dev, "can't add %pR resource\n", res);
+ return;
+ }
+
+ bus_res->res = res;
+ bus_res->flags = flags;
+ list_add_tail(&bus_res->list, &bus->resources);
+}
+
+struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n)
+{
+ struct pci_bus_resource *bus_res;
+
+ if (n < PCI_BRIDGE_RESOURCE_NUM)
+ return bus->resource[n];
+
+ n -= PCI_BRIDGE_RESOURCE_NUM;
+ list_for_each_entry(bus_res, &bus->resources, list) {
+ if (n-- == 0)
+ return bus_res->res;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(pci_bus_resource_n);
+
+void pci_bus_remove_resources(struct pci_bus *bus)
+{
+ struct pci_bus_resource *bus_res, *tmp;
+ int i;
+
+ for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
+ bus->resource[i] = 0;
+
+ list_for_each_entry_safe(bus_res, tmp, &bus->resources, list) {
+ list_del(&bus_res->list);
+ kfree(bus_res);
+ }
+}
+
/**
* pci_bus_alloc_resource - allocate a resource from a parent bus
* @bus: PCI bus
@@ -36,11 +82,14 @@ int
pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
resource_size_t size, resource_size_t align,
resource_size_t min, unsigned int type_mask,
- void (*alignf)(void *, struct resource *, resource_size_t,
- resource_size_t),
+ resource_size_t (*alignf)(void *,
+ const struct resource *,
+ resource_size_t,
+ resource_size_t),
void *alignf_data)
{
int i, ret = -ENOMEM;
+ struct resource *r;
resource_size_t max = -1;
type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
@@ -49,8 +98,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
if (!(res->flags & IORESOURCE_MEM_64))
max = PCIBIOS_MAX_MEM_32;
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- struct resource *r = bus->resource[i];
+ pci_bus_for_each_resource(bus, r, i) {
if (!r)
continue;
@@ -240,9 +288,9 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
next = dev->bus_list.next;
/* Run device routines with the device locked */
- down(&dev->dev.sem);
+ device_lock(&dev->dev);
retval = cb(dev, userdata);
- up(&dev->dev.sem);
+ device_unlock(&dev->dev);
if (retval)
break;
}
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index 4dd7114964ac..efa9f2de51c1 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -332,8 +332,6 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
slot->hotplug_slot->info->attention_status = 0;
slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
- slot->hotplug_slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;
- slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
acpiphp_slot->slot = slot;
snprintf(name, SLOT_NAME_SIZE, "%llu", slot->acpi_slot->sun);
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 8e952fdab764..b5dad9f37453 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -720,12 +720,6 @@ static int acpiphp_bus_add(struct acpiphp_func *func)
-ret_val);
goto acpiphp_bus_add_out;
}
- /*
- * try to start anyway. We could have failed to add
- * simply because this bus had previously been added
- * on another add. Don't bother with the return value
- * we just keep going.
- */
ret_val = acpi_bus_start(device);
acpiphp_bus_add_out:
@@ -755,6 +749,24 @@ static int acpiphp_bus_trim(acpi_handle handle)
return retval;
}
+static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
+{
+ struct acpiphp_func *func;
+ union acpi_object params[2];
+ struct acpi_object_list arg_list;
+
+ list_for_each_entry(func, &slot->funcs, sibling) {
+ arg_list.count = 2;
+ arg_list.pointer = params;
+ params[0].type = ACPI_TYPE_INTEGER;
+ params[0].integer.value = ACPI_ADR_SPACE_PCI_CONFIG;
+ params[1].type = ACPI_TYPE_INTEGER;
+ params[1].integer.value = 1;
+ /* _REG is optional, we don't care about if there is failure */
+ acpi_evaluate_object(func->handle, "_REG", &arg_list, NULL);
+ }
+}
+
/**
* enable_device - enable, configure a slot
* @slot: slot to be enabled
@@ -811,6 +823,7 @@ static int __ref enable_device(struct acpiphp_slot *slot)
pci_bus_assign_resources(bus);
acpiphp_sanitize_bus(bus);
acpiphp_set_hpp_values(bus);
+ acpiphp_set_acpi_region(slot);
pci_enable_bridges(bus);
pci_bus_add_devices(bus);
diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c
index 148fb463b81c..fb3f84661bdc 100644
--- a/drivers/pci/hotplug/cpcihp_generic.c
+++ b/drivers/pci/hotplug/cpcihp_generic.c
@@ -162,6 +162,7 @@ static int __init cpcihp_generic_init(void)
dev = pci_get_slot(bus, PCI_DEVFN(bridge_slot, 0));
if(!dev || dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
err("Invalid bridge device %s", bridge);
+ pci_dev_put(dev);
return -EINVAL;
}
bus = dev->subordinate;
diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h
index 9c6a9fd26812..d8ffc7366801 100644
--- a/drivers/pci/hotplug/cpqphp.h
+++ b/drivers/pci/hotplug/cpqphp.h
@@ -310,8 +310,6 @@ struct controller {
u8 first_slot;
u8 add_support;
u8 push_flag;
- enum pci_bus_speed speed;
- enum pci_bus_speed speed_capability;
u8 push_button; /* 0 = no pushbutton, 1 = pushbutton present */
u8 slot_switch_type; /* 0 = no switch, 1 = switch present */
u8 defeature_PHP; /* 0 = PHP not supported, 1 = PHP supported */
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index 075b4f4b6e0d..f184d1d2ecbe 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -583,30 +583,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
return 0;
}
-static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
-{
- struct slot *slot = hotplug_slot->private;
- struct controller *ctrl = slot->ctrl;
-
- dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
-
- *value = ctrl->speed_capability;
-
- return 0;
-}
-
-static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
-{
- struct slot *slot = hotplug_slot->private;
- struct controller *ctrl = slot->ctrl;
-
- dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
-
- *value = ctrl->speed;
-
- return 0;
-}
-
static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = {
.set_attention_status = set_attention_status,
.enable_slot = process_SI,
@@ -616,8 +592,6 @@ static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = {
.get_attention_status = get_attention_status,
.get_latch_status = get_latch_status,
.get_adapter_status = get_adapter_status,
- .get_max_bus_speed = get_max_bus_speed,
- .get_cur_bus_speed = get_cur_bus_speed,
};
#define SLOT_NAME_SIZE 10
@@ -629,6 +603,7 @@ static int ctrl_slot_setup(struct controller *ctrl,
struct slot *slot;
struct hotplug_slot *hotplug_slot;
struct hotplug_slot_info *hotplug_slot_info;
+ struct pci_bus *bus = ctrl->pci_bus;
u8 number_of_slots;
u8 slot_device;
u8 slot_number;
@@ -694,7 +669,7 @@ static int ctrl_slot_setup(struct controller *ctrl,
slot->capabilities |= PCISLOT_64_BIT_SUPPORTED;
if (is_slot66mhz(slot))
slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED;
- if (ctrl->speed == PCI_SPEED_66MHz)
+ if (bus->cur_bus_speed == PCI_SPEED_66MHz)
slot->capabilities |= PCISLOT_66_MHZ_OPERATION;
ctrl_slot =
@@ -844,6 +819,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
u32 rc;
struct controller *ctrl;
struct pci_func *func;
+ struct pci_bus *bus;
int err;
err = pci_enable_device(pdev);
@@ -852,6 +828,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_name(pdev), err);
return err;
}
+ bus = pdev->subordinate;
/* Need to read VID early b/c it's used to differentiate CPQ and INTC
* discovery
@@ -929,22 +906,22 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_read_config_byte(pdev, 0x41, &bus_cap);
if (bus_cap & 0x80) {
dbg("bus max supports 133MHz PCI-X\n");
- ctrl->speed_capability = PCI_SPEED_133MHz_PCIX;
+ bus->max_bus_speed = PCI_SPEED_133MHz_PCIX;
break;
}
if (bus_cap & 0x40) {
dbg("bus max supports 100MHz PCI-X\n");
- ctrl->speed_capability = PCI_SPEED_100MHz_PCIX;
+ bus->max_bus_speed = PCI_SPEED_100MHz_PCIX;
break;
}
if (bus_cap & 20) {
dbg("bus max supports 66MHz PCI-X\n");
- ctrl->speed_capability = PCI_SPEED_66MHz_PCIX;
+ bus->max_bus_speed = PCI_SPEED_66MHz_PCIX;
break;
}
if (bus_cap & 10) {
dbg("bus max supports 66MHz PCI\n");
- ctrl->speed_capability = PCI_SPEED_66MHz;
+ bus->max_bus_speed = PCI_SPEED_66MHz;
break;
}
@@ -955,7 +932,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
case PCI_SUB_HPC_ID:
/* Original 6500/7000 implementation */
ctrl->slot_switch_type = 1;
- ctrl->speed_capability = PCI_SPEED_33MHz;
+ bus->max_bus_speed = PCI_SPEED_33MHz;
ctrl->push_button = 0;
ctrl->pci_config_space = 1;
ctrl->defeature_PHP = 1;
@@ -966,7 +943,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* First Pushbutton implementation */
ctrl->push_flag = 1;
ctrl->slot_switch_type = 1;
- ctrl->speed_capability = PCI_SPEED_33MHz;
+ bus->max_bus_speed = PCI_SPEED_33MHz;
ctrl->push_button = 1;
ctrl->pci_config_space = 1;
ctrl->defeature_PHP = 1;
@@ -976,7 +953,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
case PCI_SUB_HPC_ID_INTC:
/* Third party (6500/7000) */
ctrl->slot_switch_type = 1;
- ctrl->speed_capability = PCI_SPEED_33MHz;
+ bus->max_bus_speed = PCI_SPEED_33MHz;
ctrl->push_button = 0;
ctrl->pci_config_space = 1;
ctrl->defeature_PHP = 1;
@@ -987,7 +964,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* First 66 Mhz implementation */
ctrl->push_flag = 1;
ctrl->slot_switch_type = 1;
- ctrl->speed_capability = PCI_SPEED_66MHz;
+ bus->max_bus_speed = PCI_SPEED_66MHz;
ctrl->push_button = 1;
ctrl->pci_config_space = 1;
ctrl->defeature_PHP = 1;
@@ -998,7 +975,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* First PCI-X implementation, 100MHz */
ctrl->push_flag = 1;
ctrl->slot_switch_type = 1;
- ctrl->speed_capability = PCI_SPEED_100MHz_PCIX;
+ bus->max_bus_speed = PCI_SPEED_100MHz_PCIX;
ctrl->push_button = 1;
ctrl->pci_config_space = 1;
ctrl->defeature_PHP = 1;
@@ -1015,9 +992,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
case PCI_VENDOR_ID_INTEL:
/* Check for speed capability (0=33, 1=66) */
if (subsystem_deviceid & 0x0001)
- ctrl->speed_capability = PCI_SPEED_66MHz;
+ bus->max_bus_speed = PCI_SPEED_66MHz;
else
- ctrl->speed_capability = PCI_SPEED_33MHz;
+ bus->max_bus_speed = PCI_SPEED_33MHz;
/* Check for push button */
if (subsystem_deviceid & 0x0002)
@@ -1079,7 +1056,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pdev->bus->number);
dbg("Hotplug controller capabilities:\n");
- dbg(" speed_capability %d\n", ctrl->speed_capability);
+ dbg(" speed_capability %d\n", bus->max_bus_speed);
dbg(" slot_switch_type %s\n", ctrl->slot_switch_type ?
"switch present" : "no switch");
dbg(" defeature_PHP %s\n", ctrl->defeature_PHP ?
@@ -1142,7 +1119,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* Check for 66Mhz operation */
- ctrl->speed = get_controller_speed(ctrl);
+ bus->cur_bus_speed = get_controller_speed(ctrl);
/********************************************************
diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
index 0ff689afa757..e43908d9b5df 100644
--- a/drivers/pci/hotplug/cpqphp_ctrl.c
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c
@@ -1130,12 +1130,13 @@ static int is_bridge(struct pci_func * func)
static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_slot)
{
struct slot *slot;
+ struct pci_bus *bus = ctrl->pci_bus;
u8 reg;
u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER);
u16 reg16;
u32 leds = readl(ctrl->hpc_reg + LED_CONTROL);
- if (ctrl->speed == adapter_speed)
+ if (bus->cur_bus_speed == adapter_speed)
return 0;
/* We don't allow freq/mode changes if we find another adapter running
@@ -1152,7 +1153,7 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
* lower speed/mode, we allow the new adapter to function at
* this rate if supported
*/
- if (ctrl->speed < adapter_speed)
+ if (bus->cur_bus_speed < adapter_speed)
return 0;
return 1;
@@ -1161,20 +1162,20 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
/* If the controller doesn't support freq/mode changes and the
* controller is running at a higher mode, we bail
*/
- if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability))
+ if ((bus->cur_bus_speed > adapter_speed) && (!ctrl->pcix_speed_capability))
return 1;
/* But we allow the adapter to run at a lower rate if possible */
- if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability))
+ if ((bus->cur_bus_speed < adapter_speed) && (!ctrl->pcix_speed_capability))
return 0;
/* We try to set the max speed supported by both the adapter and
* controller
*/
- if (ctrl->speed_capability < adapter_speed) {
- if (ctrl->speed == ctrl->speed_capability)
+ if (bus->max_bus_speed < adapter_speed) {
+ if (bus->cur_bus_speed == bus->max_bus_speed)
return 0;
- adapter_speed = ctrl->speed_capability;
+ adapter_speed = bus->max_bus_speed;
}
writel(0x0L, ctrl->hpc_reg + LED_CONTROL);
@@ -1229,8 +1230,8 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
pci_write_config_byte(ctrl->pci_dev, 0x43, reg);
/* Only if mode change...*/
- if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) ||
- ((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz)))
+ if (((bus->cur_bus_speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) ||
+ ((bus->cur_bus_speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz)))
set_SOGO(ctrl);
wait_for_ctrl_irq(ctrl);
@@ -1243,7 +1244,7 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
set_SOGO(ctrl);
wait_for_ctrl_irq(ctrl);
- ctrl->speed = adapter_speed;
+ bus->cur_bus_speed = adapter_speed;
slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
info("Successfully changed frequency/mode for adapter in slot %d\n",
@@ -1269,6 +1270,7 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
*/
static u32 board_replaced(struct pci_func *func, struct controller *ctrl)
{
+ struct pci_bus *bus = ctrl->pci_bus;
u8 hp_slot;
u8 temp_byte;
u8 adapter_speed;
@@ -1309,7 +1311,7 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl)
wait_for_ctrl_irq (ctrl);
adapter_speed = get_adapter_speed(ctrl, hp_slot);
- if (ctrl->speed != adapter_speed)
+ if (bus->cur_bus_speed != adapter_speed)
if (set_controller_speed(ctrl, adapter_speed, hp_slot))
rc = WRONG_BUS_FREQUENCY;
@@ -1426,6 +1428,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl)
u32 temp_register = 0xFFFFFFFF;
u32 rc = 0;
struct pci_func *new_slot = NULL;
+ struct pci_bus *bus = ctrl->pci_bus;
struct slot *p_slot;
struct resource_lists res_lists;
@@ -1456,7 +1459,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl)
wait_for_ctrl_irq (ctrl);
adapter_speed = get_adapter_speed(ctrl, hp_slot);
- if (ctrl->speed != adapter_speed)
+ if (bus->cur_bus_speed != adapter_speed)
if (set_controller_speed(ctrl, adapter_speed, hp_slot))
rc = WRONG_BUS_FREQUENCY;
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
index 6151389fd903..0a894efd4b9b 100644
--- a/drivers/pci/hotplug/fakephp.c
+++ b/drivers/pci/hotplug/fakephp.c
@@ -73,7 +73,7 @@ static void legacy_release(struct kobject *kobj)
}
static struct kobj_type legacy_ktype = {
- .sysfs_ops = &(struct sysfs_ops){
+ .sysfs_ops = &(const struct sysfs_ops){
.store = legacy_store, .show = legacy_show
},
.release = &legacy_release,
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index 7485ffda950c..d934dd4fa873 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -395,89 +395,40 @@ static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 * value)
return rc;
}
-static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+static int get_max_bus_speed(struct slot *slot)
{
- int rc = -ENODEV;
- struct slot *pslot;
+ int rc;
u8 mode = 0;
+ enum pci_bus_speed speed;
+ struct pci_bus *bus = slot->hotplug_slot->pci_slot->bus;
- debug("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __func__,
- hotplug_slot, value);
+ debug("%s - Entry slot[%p]\n", __func__, slot);
ibmphp_lock_operations();
-
- if (hotplug_slot) {
- pslot = hotplug_slot->private;
- if (pslot) {
- rc = 0;
- mode = pslot->supported_bus_mode;
- *value = pslot->supported_speed;
- switch (*value) {
- case BUS_SPEED_33:
- break;
- case BUS_SPEED_66:
- if (mode == BUS_MODE_PCIX)
- *value += 0x01;
- break;
- case BUS_SPEED_100:
- case BUS_SPEED_133:
- *value = pslot->supported_speed + 0x01;
- break;
- default:
- /* Note (will need to change): there would be soon 256, 512 also */
- rc = -ENODEV;
- }
- }
- }
-
+ mode = slot->supported_bus_mode;
+ speed = slot->supported_speed;
ibmphp_unlock_operations();
- debug("%s - Exit rc[%d] value[%x]\n", __func__, rc, *value);
- return rc;
-}
-static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
-{
- int rc = -ENODEV;
- struct slot *pslot;
- u8 mode = 0;
-
- debug("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __func__,
- hotplug_slot, value);
-
- ibmphp_lock_operations();
-
- if (hotplug_slot) {
- pslot = hotplug_slot->private;
- if (pslot) {
- rc = get_cur_bus_info(&pslot);
- if (!rc) {
- mode = pslot->bus_on->current_bus_mode;
- *value = pslot->bus_on->current_speed;
- switch (*value) {
- case BUS_SPEED_33:
- break;
- case BUS_SPEED_66:
- if (mode == BUS_MODE_PCIX)
- *value += 0x01;
- else if (mode == BUS_MODE_PCI)
- ;
- else
- *value = PCI_SPEED_UNKNOWN;
- break;
- case BUS_SPEED_100:
- case BUS_SPEED_133:
- *value += 0x01;
- break;
- default:
- /* Note of change: there would also be 256, 512 soon */
- rc = -ENODEV;
- }
- }
- }
+ switch (speed) {
+ case BUS_SPEED_33:
+ break;
+ case BUS_SPEED_66:
+ if (mode == BUS_MODE_PCIX)
+ speed += 0x01;
+ break;
+ case BUS_SPEED_100:
+ case BUS_SPEED_133:
+ speed += 0x01;
+ break;
+ default:
+ /* Note (will need to change): there would be soon 256, 512 also */
+ rc = -ENODEV;
}
- ibmphp_unlock_operations();
- debug("%s - Exit rc[%d] value[%x]\n", __func__, rc, *value);
+ if (!rc)
+ bus->max_bus_speed = speed;
+
+ debug("%s - Exit rc[%d] speed[%x]\n", __func__, rc, speed);
return rc;
}
@@ -572,6 +523,7 @@ static int __init init_ops(void)
if (slot_cur->bus_on->current_speed == 0xFF)
if (get_cur_bus_info(&slot_cur))
return -1;
+ get_max_bus_speed(slot_cur);
if (slot_cur->ctrl->options == 0xFF)
if (get_hpc_options(slot_cur, &slot_cur->ctrl->options))
@@ -655,6 +607,7 @@ static int validate(struct slot *slot_cur, int opn)
int ibmphp_update_slot_info(struct slot *slot_cur)
{
struct hotplug_slot_info *info;
+ struct pci_bus *bus = slot_cur->hotplug_slot->pci_slot->bus;
int rc;
u8 bus_speed;
u8 mode;
@@ -700,8 +653,7 @@ int ibmphp_update_slot_info(struct slot *slot_cur)
bus_speed = PCI_SPEED_UNKNOWN;
}
- info->cur_bus_speed = bus_speed;
- info->max_bus_speed = slot_cur->hotplug_slot->info->max_bus_speed;
+ bus->cur_bus_speed = bus_speed;
// To do: bus_names
rc = pci_hp_change_slot_info(slot_cur->hotplug_slot, info);
@@ -1326,8 +1278,6 @@ struct hotplug_slot_ops ibmphp_hotplug_slot_ops = {
.get_attention_status = get_attention_status,
.get_latch_status = get_latch_status,
.get_adapter_status = get_adapter_present,
- .get_max_bus_speed = get_max_bus_speed,
- .get_cur_bus_speed = get_cur_bus_speed,
/* .get_max_adapter_speed = get_max_adapter_speed,
.get_bus_name_status = get_bus_name,
*/
diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
index c1abac8ab5c3..5becbdee4027 100644
--- a/drivers/pci/hotplug/ibmphp_ebda.c
+++ b/drivers/pci/hotplug/ibmphp_ebda.c
@@ -245,7 +245,7 @@ static void __init print_ebda_hpc (void)
int __init ibmphp_access_ebda (void)
{
- u8 format, num_ctlrs, rio_complete, hs_complete;
+ u8 format, num_ctlrs, rio_complete, hs_complete, ebda_sz;
u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, re, rc_id, re_id, base;
int rc = 0;
@@ -260,7 +260,16 @@ int __init ibmphp_access_ebda (void)
iounmap (io_mem);
debug ("returned ebda segment: %x\n", ebda_seg);
- io_mem = ioremap(ebda_seg<<4, 1024);
+ io_mem = ioremap(ebda_seg<<4, 1);
+ if (!io_mem)
+ return -ENOMEM;
+ ebda_sz = readb(io_mem);
+ iounmap(io_mem);
+ debug("ebda size: %d(KiB)\n", ebda_sz);
+ if (ebda_sz == 0)
+ return -ENOMEM;
+
+ io_mem = ioremap(ebda_seg<<4, (ebda_sz * 1024));
if (!io_mem )
return -ENOMEM;
next_offset = 0x180;
diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c
index c7084f0eca5a..1aaf3f32d3cd 100644
--- a/drivers/pci/hotplug/ibmphp_hpc.c
+++ b/drivers/pci/hotplug/ibmphp_hpc.c
@@ -35,6 +35,7 @@
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/sched.h>
+#include <linux/semaphore.h>
#include <linux/kthread.h>
#include "ibmphp.h"
diff --git a/drivers/pci/hotplug/ibmphp_res.c b/drivers/pci/hotplug/ibmphp_res.c
index ec73294d1fa6..e2dc289f767c 100644
--- a/drivers/pci/hotplug/ibmphp_res.c
+++ b/drivers/pci/hotplug/ibmphp_res.c
@@ -40,7 +40,7 @@ static void update_resources (struct bus_node *bus_cur, int type, int rangeno);
static int once_over (void);
static int remove_ranges (struct bus_node *, struct bus_node *);
static int update_bridge_ranges (struct bus_node **);
-static int add_range (int type, struct range_node *, struct bus_node *);
+static int add_bus_range (int type, struct range_node *, struct bus_node *);
static void fix_resources (struct bus_node *);
static struct bus_node *find_bus_wprev (u8, struct bus_node **, u8);
@@ -133,7 +133,7 @@ static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node
newrange->rangeno = 1;
else {
/* need to insert our range */
- add_range (flag, newrange, newbus);
+ add_bus_range (flag, newrange, newbus);
debug ("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end);
}
@@ -384,7 +384,7 @@ int __init ibmphp_rsrc_init (void)
* Input: type of the resource, range to add, current bus
* Output: 0 or -1, bus and range ptrs
********************************************************************************/
-static int add_range (int type, struct range_node *range, struct bus_node *bus_cur)
+static int add_bus_range (int type, struct range_node *range, struct bus_node *bus_cur)
{
struct range_node *range_cur = NULL;
struct range_node *range_prev;
@@ -455,7 +455,7 @@ static int add_range (int type, struct range_node *range, struct bus_node *bus_c
/*******************************************************************************
* This routine goes through the list of resources of type 'type' and updates
- * the range numbers that they correspond to. It was called from add_range fnc
+ * the range numbers that they correspond to. It was called from add_bus_range fnc
*
* Input: bus, type of the resource, the rangeno starting from which to update
******************************************************************************/
@@ -1999,7 +1999,7 @@ static int __init update_bridge_ranges (struct bus_node **bus)
if (bus_sec->noIORanges > 0) {
if (!range_exists_already (range, bus_sec, IO)) {
- add_range (IO, range, bus_sec);
+ add_bus_range (IO, range, bus_sec);
++bus_sec->noIORanges;
} else {
kfree (range);
@@ -2048,7 +2048,7 @@ static int __init update_bridge_ranges (struct bus_node **bus)
if (bus_sec->noMemRanges > 0) {
if (!range_exists_already (range, bus_sec, MEM)) {
- add_range (MEM, range, bus_sec);
+ add_bus_range (MEM, range, bus_sec);
++bus_sec->noMemRanges;
} else {
kfree (range);
@@ -2102,7 +2102,7 @@ static int __init update_bridge_ranges (struct bus_node **bus)
if (bus_sec->noPFMemRanges > 0) {
if (!range_exists_already (range, bus_sec, PFMEM)) {
- add_range (PFMEM, range, bus_sec);
+ add_bus_range (PFMEM, range, bus_sec);
++bus_sec->noPFMemRanges;
} else {
kfree (range);
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index 38183a534b65..728b119f71ad 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -64,32 +64,6 @@ static int debug;
static LIST_HEAD(pci_hotplug_slot_list);
static DEFINE_MUTEX(pci_hp_mutex);
-/* these strings match up with the values in pci_bus_speed */
-static char *pci_bus_speed_strings[] = {
- "33 MHz PCI", /* 0x00 */
- "66 MHz PCI", /* 0x01 */
- "66 MHz PCI-X", /* 0x02 */
- "100 MHz PCI-X", /* 0x03 */
- "133 MHz PCI-X", /* 0x04 */
- NULL, /* 0x05 */
- NULL, /* 0x06 */
- NULL, /* 0x07 */
- NULL, /* 0x08 */
- "66 MHz PCI-X 266", /* 0x09 */
- "100 MHz PCI-X 266", /* 0x0a */
- "133 MHz PCI-X 266", /* 0x0b */
- NULL, /* 0x0c */
- NULL, /* 0x0d */
- NULL, /* 0x0e */
- NULL, /* 0x0f */
- NULL, /* 0x10 */
- "66 MHz PCI-X 533", /* 0x11 */
- "100 MHz PCI-X 533", /* 0x12 */
- "133 MHz PCI-X 533", /* 0x13 */
- "2.5 GT/s PCIe", /* 0x14 */
- "5.0 GT/s PCIe", /* 0x15 */
-};
-
#ifdef CONFIG_HOTPLUG_PCI_CPCI
extern int cpci_hotplug_init(int debug);
extern void cpci_hotplug_exit(void);
@@ -118,8 +92,6 @@ GET_STATUS(power_status, u8)
GET_STATUS(attention_status, u8)
GET_STATUS(latch_status, u8)
GET_STATUS(adapter_status, u8)
-GET_STATUS(max_bus_speed, enum pci_bus_speed)
-GET_STATUS(cur_bus_speed, enum pci_bus_speed)
static ssize_t power_read_file(struct pci_slot *slot, char *buf)
{
@@ -263,60 +235,6 @@ static struct pci_slot_attribute hotplug_slot_attr_presence = {
.show = presence_read_file,
};
-static char *unknown_speed = "Unknown bus speed";
-
-static ssize_t max_bus_speed_read_file(struct pci_slot *slot, char *buf)
-{
- char *speed_string;
- int retval;
- enum pci_bus_speed value;
-
- retval = get_max_bus_speed(slot->hotplug, &value);
- if (retval)
- goto exit;
-
- if (value == PCI_SPEED_UNKNOWN)
- speed_string = unknown_speed;
- else
- speed_string = pci_bus_speed_strings[value];
-
- retval = sprintf (buf, "%s\n", speed_string);
-
-exit:
- return retval;
-}
-
-static struct pci_slot_attribute hotplug_slot_attr_max_bus_speed = {
- .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO},
- .show = max_bus_speed_read_file,
-};
-
-static ssize_t cur_bus_speed_read_file(struct pci_slot *slot, char *buf)
-{
- char *speed_string;
- int retval;
- enum pci_bus_speed value;
-
- retval = get_cur_bus_speed(slot->hotplug, &value);
- if (retval)
- goto exit;
-
- if (value == PCI_SPEED_UNKNOWN)
- speed_string = unknown_speed;
- else
- speed_string = pci_bus_speed_strings[value];
-
- retval = sprintf (buf, "%s\n", speed_string);
-
-exit:
- return retval;
-}
-
-static struct pci_slot_attribute hotplug_slot_attr_cur_bus_speed = {
- .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO},
- .show = cur_bus_speed_read_file,
-};
-
static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf,
size_t count)
{
@@ -391,26 +309,6 @@ static bool has_adapter_file(struct pci_slot *pci_slot)
return false;
}
-static bool has_max_bus_speed_file(struct pci_slot *pci_slot)
-{
- struct hotplug_slot *slot = pci_slot->hotplug;
- if ((!slot) || (!slot->ops))
- return false;
- if (slot->ops->get_max_bus_speed)
- return true;
- return false;
-}
-
-static bool has_cur_bus_speed_file(struct pci_slot *pci_slot)
-{
- struct hotplug_slot *slot = pci_slot->hotplug;
- if ((!slot) || (!slot->ops))
- return false;
- if (slot->ops->get_cur_bus_speed)
- return true;
- return false;
-}
-
static bool has_test_file(struct pci_slot *pci_slot)
{
struct hotplug_slot *slot = pci_slot->hotplug;
@@ -456,20 +354,6 @@ static int fs_add_slot(struct pci_slot *slot)
goto exit_adapter;
}
- if (has_max_bus_speed_file(slot)) {
- retval = sysfs_create_file(&slot->kobj,
- &hotplug_slot_attr_max_bus_speed.attr);
- if (retval)
- goto exit_max_speed;
- }
-
- if (has_cur_bus_speed_file(slot)) {
- retval = sysfs_create_file(&slot->kobj,
- &hotplug_slot_attr_cur_bus_speed.attr);
- if (retval)
- goto exit_cur_speed;
- }
-
if (has_test_file(slot)) {
retval = sysfs_create_file(&slot->kobj,
&hotplug_slot_attr_test.attr);
@@ -480,14 +364,6 @@ static int fs_add_slot(struct pci_slot *slot)
goto exit;
exit_test:
- if (has_cur_bus_speed_file(slot))
- sysfs_remove_file(&slot->kobj,
- &hotplug_slot_attr_cur_bus_speed.attr);
-exit_cur_speed:
- if (has_max_bus_speed_file(slot))
- sysfs_remove_file(&slot->kobj,
- &hotplug_slot_attr_max_bus_speed.attr);
-exit_max_speed:
if (has_adapter_file(slot))
sysfs_remove_file(&slot->kobj,
&hotplug_slot_attr_presence.attr);
@@ -523,14 +399,6 @@ static void fs_remove_slot(struct pci_slot *slot)
sysfs_remove_file(&slot->kobj,
&hotplug_slot_attr_presence.attr);
- if (has_max_bus_speed_file(slot))
- sysfs_remove_file(&slot->kobj,
- &hotplug_slot_attr_max_bus_speed.attr);
-
- if (has_cur_bus_speed_file(slot))
- sysfs_remove_file(&slot->kobj,
- &hotplug_slot_attr_cur_bus_speed.attr);
-
if (has_test_file(slot))
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr);
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 5674b2075bdc..920f820edf87 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -69,8 +69,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value);
static int get_attention_status (struct hotplug_slot *slot, u8 *value);
static int get_latch_status (struct hotplug_slot *slot, u8 *value);
static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
-static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
-static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
/**
* release_slot - free up the memory used by a slot
@@ -113,8 +111,6 @@ static int init_slot(struct controller *ctrl)
ops->disable_slot = disable_slot;
ops->get_power_status = get_power_status;
ops->get_adapter_status = get_adapter_status;
- ops->get_max_bus_speed = get_max_bus_speed;
- ops->get_cur_bus_speed = get_cur_bus_speed;
if (MRL_SENS(ctrl))
ops->get_latch_status = get_latch_status;
if (ATTN_LED(ctrl)) {
@@ -227,27 +223,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
return pciehp_get_adapter_status(slot, value);
}
-static int get_max_bus_speed(struct hotplug_slot *hotplug_slot,
- enum pci_bus_speed *value)
-{
- struct slot *slot = hotplug_slot->private;
-
- ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
- __func__, slot_name(slot));
-
- return pciehp_get_max_link_speed(slot, value);
-}
-
-static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
-{
- struct slot *slot = hotplug_slot->private;
-
- ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
- __func__, slot_name(slot));
-
- return pciehp_get_cur_link_speed(slot, value);
-}
-
static int pciehp_probe(struct pcie_device *dev)
{
int rc;
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index d6ac1b261dd9..9a7f247e8ac1 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -341,6 +341,7 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
p_slot->state = POWERON_STATE;
break;
default:
+ kfree(info);
goto out;
}
queue_work(pciehp_wq, &info->work);
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 10040d58c8ef..40b48f569b1e 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -492,6 +492,7 @@ int pciehp_power_on_slot(struct slot * slot)
u16 slot_cmd;
u16 cmd_mask;
u16 slot_status;
+ u16 lnk_status;
int retval = 0;
/* Clear sticky power-fault bit from previous power failures */
@@ -523,6 +524,14 @@ int pciehp_power_on_slot(struct slot * slot)
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
+ retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status);
+ if (retval) {
+ ctrl_err(ctrl, "%s: Cannot read LNKSTA register\n",
+ __func__);
+ return retval;
+ }
+ pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status);
+
return retval;
}
@@ -610,37 +619,6 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-int pciehp_get_max_link_speed(struct slot *slot, enum pci_bus_speed *value)
-{
- struct controller *ctrl = slot->ctrl;
- enum pcie_link_speed lnk_speed;
- u32 lnk_cap;
- int retval = 0;
-
- retval = pciehp_readl(ctrl, PCI_EXP_LNKCAP, &lnk_cap);
- if (retval) {
- ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__);
- return retval;
- }
-
- switch (lnk_cap & 0x000F) {
- case 1:
- lnk_speed = PCIE_2_5GB;
- break;
- case 2:
- lnk_speed = PCIE_5_0GB;
- break;
- default:
- lnk_speed = PCIE_LNK_SPEED_UNKNOWN;
- break;
- }
-
- *value = lnk_speed;
- ctrl_dbg(ctrl, "Max link speed = %d\n", lnk_speed);
-
- return retval;
-}
-
int pciehp_get_max_lnk_width(struct slot *slot,
enum pcie_link_width *value)
{
@@ -691,38 +669,6 @@ int pciehp_get_max_lnk_width(struct slot *slot,
return retval;
}
-int pciehp_get_cur_link_speed(struct slot *slot, enum pci_bus_speed *value)
-{
- struct controller *ctrl = slot->ctrl;
- enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
- int retval = 0;
- u16 lnk_status;
-
- retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status);
- if (retval) {
- ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n",
- __func__);
- return retval;
- }
-
- switch (lnk_status & PCI_EXP_LNKSTA_CLS) {
- case 1:
- lnk_speed = PCIE_2_5GB;
- break;
- case 2:
- lnk_speed = PCIE_5_0GB;
- break;
- default:
- lnk_speed = PCIE_LNK_SPEED_UNKNOWN;
- break;
- }
-
- *value = lnk_speed;
- ctrl_dbg(ctrl, "Current link speed = %d\n", lnk_speed);
-
- return retval;
-}
-
int pciehp_get_cur_lnk_width(struct slot *slot,
enum pcie_link_width *value)
{
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index 21733108adde..0a16444c14c9 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -53,17 +53,15 @@ static int __ref pciehp_add_bridge(struct pci_dev *dev)
busnr = pci_scan_bridge(parent, dev, busnr, pass);
if (!dev->subordinate)
return -1;
- pci_bus_size_bridges(dev->subordinate);
- pci_bus_assign_resources(parent);
- pci_enable_bridges(parent);
- pci_bus_add_devices(parent);
+
return 0;
}
int pciehp_configure_device(struct slot *p_slot)
{
struct pci_dev *dev;
- struct pci_bus *parent = p_slot->ctrl->pcie->port->subordinate;
+ struct pci_dev *bridge = p_slot->ctrl->pcie->port;
+ struct pci_bus *parent = bridge->subordinate;
int num, fn;
struct controller *ctrl = p_slot->ctrl;
@@ -96,12 +94,25 @@ int pciehp_configure_device(struct slot *p_slot)
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
pciehp_add_bridge(dev);
}
+ pci_dev_put(dev);
+ }
+
+ pci_assign_unassigned_bridge_resources(bridge);
+
+ for (fn = 0; fn < 8; fn++) {
+ dev = pci_get_slot(parent, PCI_DEVFN(0, fn));
+ if (!dev)
+ continue;
+ if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
+ pci_dev_put(dev);
+ continue;
+ }
pci_configure_slot(dev);
pci_dev_put(dev);
}
- pci_bus_assign_resources(parent);
pci_bus_add_devices(parent);
+
return 0;
}
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
index c159223389ec..dcaae725fd79 100644
--- a/drivers/pci/hotplug/rpaphp_core.c
+++ b/drivers/pci/hotplug/rpaphp_core.c
@@ -130,10 +130,9 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
return 0;
}
-static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+static enum pci_bus_speed get_max_bus_speed(struct slot *slot)
{
- struct slot *slot = (struct slot *)hotplug_slot->private;
-
+ enum pci_bus_speed speed;
switch (slot->type) {
case 1:
case 2:
@@ -141,30 +140,30 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
case 4:
case 5:
case 6:
- *value = PCI_SPEED_33MHz; /* speed for case 1-6 */
+ speed = PCI_SPEED_33MHz; /* speed for case 1-6 */
break;
case 7:
case 8:
- *value = PCI_SPEED_66MHz;
+ speed = PCI_SPEED_66MHz;
break;
case 11:
case 14:
- *value = PCI_SPEED_66MHz_PCIX;
+ speed = PCI_SPEED_66MHz_PCIX;
break;
case 12:
case 15:
- *value = PCI_SPEED_100MHz_PCIX;
+ speed = PCI_SPEED_100MHz_PCIX;
break;
case 13:
case 16:
- *value = PCI_SPEED_133MHz_PCIX;
+ speed = PCI_SPEED_133MHz_PCIX;
break;
default:
- *value = PCI_SPEED_UNKNOWN;
+ speed = PCI_SPEED_UNKNOWN;
break;
-
}
- return 0;
+
+ return speed;
}
static int get_children_props(struct device_node *dn, const int **drc_indexes,
@@ -408,6 +407,8 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
slot->state = NOT_VALID;
return -EINVAL;
}
+
+ slot->bus->max_bus_speed = get_max_bus_speed(slot);
return 0;
}
@@ -429,7 +430,6 @@ struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
.get_power_status = get_power_status,
.get_attention_status = get_attention_status,
.get_adapter_status = get_adapter_status,
- .get_max_bus_speed = get_max_bus_speed,
};
module_init(rpaphp_init);
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 8e210cd76e55..d2627e1c3ac1 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -333,8 +333,6 @@ struct hpc_ops {
int (*set_attention_status)(struct slot *slot, u8 status);
int (*get_latch_status)(struct slot *slot, u8 *status);
int (*get_adapter_status)(struct slot *slot, u8 *status);
- int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
- int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
int (*get_adapter_speed)(struct slot *slot, enum pci_bus_speed *speed);
int (*get_mode1_ECC_cap)(struct slot *slot, u8 *mode);
int (*get_prog_int)(struct slot *slot, u8 *prog_int);
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 8a520a3d0f59..a5062297f488 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -65,8 +65,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value);
static int get_attention_status (struct hotplug_slot *slot, u8 *value);
static int get_latch_status (struct hotplug_slot *slot, u8 *value);
static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
-static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
-static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
.set_attention_status = set_attention_status,
@@ -76,8 +74,6 @@ static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
.get_attention_status = get_attention_status,
.get_latch_status = get_latch_status,
.get_adapter_status = get_adapter_status,
- .get_max_bus_speed = get_max_bus_speed,
- .get_cur_bus_speed = get_cur_bus_speed,
};
/**
@@ -279,37 +275,6 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
return 0;
}
-static int get_max_bus_speed(struct hotplug_slot *hotplug_slot,
- enum pci_bus_speed *value)
-{
- struct slot *slot = get_slot(hotplug_slot);
- int retval;
-
- ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
- __func__, slot_name(slot));
-
- retval = slot->hpc_ops->get_max_bus_speed(slot, value);
- if (retval < 0)
- *value = PCI_SPEED_UNKNOWN;
-
- return 0;
-}
-
-static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
-{
- struct slot *slot = get_slot(hotplug_slot);
- int retval;
-
- ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
- __func__, slot_name(slot));
-
- retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
- if (retval < 0)
- *value = PCI_SPEED_UNKNOWN;
-
- return 0;
-}
-
static int is_shpc_capable(struct pci_dev *dev)
{
if ((dev->vendor == PCI_VENDOR_ID_AMD) || (dev->device ==
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index b8ab2796e66a..3bba0c0888ff 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -285,17 +285,8 @@ static int board_added(struct slot *p_slot)
return WRONG_BUS_FREQUENCY;
}
- rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bsp);
- if (rc) {
- ctrl_err(ctrl, "Can't get bus operation speed\n");
- return WRONG_BUS_FREQUENCY;
- }
-
- rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &msp);
- if (rc) {
- ctrl_err(ctrl, "Can't get max bus operation speed\n");
- msp = bsp;
- }
+ bsp = ctrl->pci_dev->bus->cur_bus_speed;
+ msp = ctrl->pci_dev->bus->max_bus_speed;
/* Check if there are other slots or devices on the same bus */
if (!list_empty(&ctrl->pci_dev->subordinate->devices))
@@ -462,6 +453,7 @@ void shpchp_queue_pushbutton_work(struct work_struct *work)
p_slot->state = POWERON_STATE;
break;
default:
+ kfree(info);
goto out;
}
queue_work(shpchp_wq, &info->work);
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index 86dc39847769..5f5e8d2e3552 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -660,6 +660,75 @@ static int hpc_slot_disable(struct slot * slot)
return retval;
}
+static int shpc_get_cur_bus_speed(struct controller *ctrl)
+{
+ int retval = 0;
+ struct pci_bus *bus = ctrl->pci_dev->subordinate;
+ enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
+ u16 sec_bus_reg = shpc_readw(ctrl, SEC_BUS_CONFIG);
+ u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
+ u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7);
+
+ if ((pi == 1) && (speed_mode > 4)) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ switch (speed_mode) {
+ case 0x0:
+ bus_speed = PCI_SPEED_33MHz;
+ break;
+ case 0x1:
+ bus_speed = PCI_SPEED_66MHz;
+ break;
+ case 0x2:
+ bus_speed = PCI_SPEED_66MHz_PCIX;
+ break;
+ case 0x3:
+ bus_speed = PCI_SPEED_100MHz_PCIX;
+ break;
+ case 0x4:
+ bus_speed = PCI_SPEED_133MHz_PCIX;
+ break;
+ case 0x5:
+ bus_speed = PCI_SPEED_66MHz_PCIX_ECC;
+ break;
+ case 0x6:
+ bus_speed = PCI_SPEED_100MHz_PCIX_ECC;
+ break;
+ case 0x7:
+ bus_speed = PCI_SPEED_133MHz_PCIX_ECC;
+ break;
+ case 0x8:
+ bus_speed = PCI_SPEED_66MHz_PCIX_266;
+ break;
+ case 0x9:
+ bus_speed = PCI_SPEED_100MHz_PCIX_266;
+ break;
+ case 0xa:
+ bus_speed = PCI_SPEED_133MHz_PCIX_266;
+ break;
+ case 0xb:
+ bus_speed = PCI_SPEED_66MHz_PCIX_533;
+ break;
+ case 0xc:
+ bus_speed = PCI_SPEED_100MHz_PCIX_533;
+ break;
+ case 0xd:
+ bus_speed = PCI_SPEED_133MHz_PCIX_533;
+ break;
+ default:
+ retval = -ENODEV;
+ break;
+ }
+
+ out:
+ bus->cur_bus_speed = bus_speed;
+ dbg("Current bus speed = %d\n", bus_speed);
+ return retval;
+}
+
+
static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
{
int retval;
@@ -720,6 +789,8 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
retval = shpc_write_cmd(slot, 0, cmd);
if (retval)
ctrl_err(ctrl, "%s: Write command failed!\n", __func__);
+ else
+ shpc_get_cur_bus_speed(ctrl);
return retval;
}
@@ -803,10 +874,10 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
+static int shpc_get_max_bus_speed(struct controller *ctrl)
{
int retval = 0;
- struct controller *ctrl = slot->ctrl;
+ struct pci_bus *bus = ctrl->pci_dev->subordinate;
enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1);
@@ -842,79 +913,12 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
retval = -ENODEV;
}
- *value = bus_speed;
+ bus->max_bus_speed = bus_speed;
ctrl_dbg(ctrl, "Max bus speed = %d\n", bus_speed);
return retval;
}
-static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
-{
- int retval = 0;
- struct controller *ctrl = slot->ctrl;
- enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
- u16 sec_bus_reg = shpc_readw(ctrl, SEC_BUS_CONFIG);
- u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
- u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7);
-
- if ((pi == 1) && (speed_mode > 4)) {
- *value = PCI_SPEED_UNKNOWN;
- return -ENODEV;
- }
-
- switch (speed_mode) {
- case 0x0:
- *value = PCI_SPEED_33MHz;
- break;
- case 0x1:
- *value = PCI_SPEED_66MHz;
- break;
- case 0x2:
- *value = PCI_SPEED_66MHz_PCIX;
- break;
- case 0x3:
- *value = PCI_SPEED_100MHz_PCIX;
- break;
- case 0x4:
- *value = PCI_SPEED_133MHz_PCIX;
- break;
- case 0x5:
- *value = PCI_SPEED_66MHz_PCIX_ECC;
- break;
- case 0x6:
- *value = PCI_SPEED_100MHz_PCIX_ECC;
- break;
- case 0x7:
- *value = PCI_SPEED_133MHz_PCIX_ECC;
- break;
- case 0x8:
- *value = PCI_SPEED_66MHz_PCIX_266;
- break;
- case 0x9:
- *value = PCI_SPEED_100MHz_PCIX_266;
- break;
- case 0xa:
- *value = PCI_SPEED_133MHz_PCIX_266;
- break;
- case 0xb:
- *value = PCI_SPEED_66MHz_PCIX_533;
- break;
- case 0xc:
- *value = PCI_SPEED_100MHz_PCIX_533;
- break;
- case 0xd:
- *value = PCI_SPEED_133MHz_PCIX_533;
- break;
- default:
- *value = PCI_SPEED_UNKNOWN;
- retval = -ENODEV;
- break;
- }
-
- ctrl_dbg(ctrl, "Current bus speed = %d\n", bus_speed);
- return retval;
-}
-
static struct hpc_ops shpchp_hpc_ops = {
.power_on_slot = hpc_power_on_slot,
.slot_enable = hpc_slot_enable,
@@ -926,8 +930,6 @@ static struct hpc_ops shpchp_hpc_ops = {
.get_latch_status = hpc_get_latch_status,
.get_adapter_status = hpc_get_adapter_status,
- .get_max_bus_speed = hpc_get_max_bus_speed,
- .get_cur_bus_speed = hpc_get_cur_bus_speed,
.get_adapter_speed = hpc_get_adapter_speed,
.get_mode1_ECC_cap = hpc_get_mode1_ECC_cap,
.get_prog_int = hpc_get_prog_int,
@@ -1086,6 +1088,9 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
}
ctrl_dbg(ctrl, "HPC at %s irq=%x\n", pci_name(pdev), pdev->irq);
+ shpc_get_max_bus_speed(ctrl);
+ shpc_get_cur_bus_speed(ctrl);
+
/*
* If this is the first controller to be initialized,
* initialize the shpchpd work queue
diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c
index 29fa9d26adae..071b7dc0094b 100644
--- a/drivers/pci/hotplug/shpchp_sysfs.c
+++ b/drivers/pci/hotplug/shpchp_sysfs.c
@@ -47,8 +47,7 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
bus = pdev->subordinate;
out += sprintf(buf, "Free resources: memory\n");
- for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) {
- res = bus->resource[index];
+ pci_bus_for_each_resource(bus, res, index) {
if (res && (res->flags & IORESOURCE_MEM) &&
!(res->flags & IORESOURCE_PREFETCH)) {
out += sprintf(out, "start = %8.8llx, "
@@ -58,8 +57,7 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
}
}
out += sprintf(out, "Free resources: prefetchable memory\n");
- for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) {
- res = bus->resource[index];
+ pci_bus_for_each_resource(bus, res, index) {
if (res && (res->flags & IORESOURCE_MEM) &&
(res->flags & IORESOURCE_PREFETCH)) {
out += sprintf(out, "start = %8.8llx, "
@@ -69,8 +67,7 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
}
}
out += sprintf(out, "Free resources: IO\n");
- for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) {
- res = bus->resource[index];
+ pci_bus_for_each_resource(bus, res, index) {
if (res && (res->flags & IORESOURCE_IO)) {
out += sprintf(out, "start = %8.8llx, "
"length = %8.8llx\n",
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index b2a448e19fe6..3e5ab2bf6a5c 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -706,6 +706,21 @@ irqreturn_t pci_sriov_migration(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(pci_sriov_migration);
+/**
+ * pci_num_vf - return number of VFs associated with a PF device_release_driver
+ * @dev: the PCI device
+ *
+ * Returns number of VFs, or 0 if SR-IOV is not enabled.
+ */
+int pci_num_vf(struct pci_dev *dev)
+{
+ if (!dev || !dev->is_physfn)
+ return 0;
+ else
+ return dev->sriov->nr_virtfn;
+}
+EXPORT_SYMBOL_GPL(pci_num_vf);
+
static int ats_alloc_one(struct pci_dev *dev, int ps)
{
int pos;
diff --git a/drivers/pci/legacy.c b/drivers/pci/legacy.c
deleted file mode 100644
index 871f65c15936..000000000000
--- a/drivers/pci/legacy.c
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include "pci.h"
-
-/**
- * pci_find_device - begin or continue searching for a PCI device by vendor/device id
- * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
- * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
- * @from: Previous PCI device found in search, or %NULL for new search.
- *
- * Iterates through the list of known PCI devices. If a PCI device is found
- * with a matching @vendor and @device, a pointer to its device structure is
- * returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL as the @from argument.
- * Otherwise if @from is not %NULL, searches continue from next device
- * on the global list.
- *
- * NOTE: Do not use this function any more; use pci_get_device() instead, as
- * the PCI device returned by this function can disappear at any moment in
- * time.
- */
-struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device,
- struct pci_dev *from)
-{
- struct pci_dev *pdev;
-
- pci_dev_get(from);
- pdev = pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
- pci_dev_put(pdev);
- return pdev;
-}
-EXPORT_SYMBOL(pci_find_device);
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 7e2829538a4c..2e7a3bf13824 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -16,8 +16,144 @@
#include <acpi/acpi_bus.h>
#include <linux/pci-acpi.h>
+#include <linux/pm_runtime.h>
#include "pci.h"
+static DEFINE_MUTEX(pci_acpi_pm_notify_mtx);
+
+/**
+ * pci_acpi_wake_bus - Wake-up notification handler for root buses.
+ * @handle: ACPI handle of a device the notification is for.
+ * @event: Type of the signaled event.
+ * @context: PCI root bus to wake up devices on.
+ */
+static void pci_acpi_wake_bus(acpi_handle handle, u32 event, void *context)
+{
+ struct pci_bus *pci_bus = context;
+
+ if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_bus)
+ pci_pme_wakeup_bus(pci_bus);
+}
+
+/**
+ * pci_acpi_wake_dev - Wake-up notification handler for PCI devices.
+ * @handle: ACPI handle of a device the notification is for.
+ * @event: Type of the signaled event.
+ * @context: PCI device object to wake up.
+ */
+static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
+{
+ struct pci_dev *pci_dev = context;
+
+ if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) {
+ pci_check_pme_status(pci_dev);
+ pm_runtime_resume(&pci_dev->dev);
+ if (pci_dev->subordinate)
+ pci_pme_wakeup_bus(pci_dev->subordinate);
+ }
+}
+
+/**
+ * add_pm_notifier - Register PM notifier for given ACPI device.
+ * @dev: ACPI device to add the notifier for.
+ * @context: PCI device or bus to check for PME status if an event is signaled.
+ *
+ * NOTE: @dev need not be a run-wake or wake-up device to be a valid source of
+ * PM wake-up events. For example, wake-up events may be generated for bridges
+ * if one of the devices below the bridge is signaling PME, even if the bridge
+ * itself doesn't have a wake-up GPE associated with it.
+ */
+static acpi_status add_pm_notifier(struct acpi_device *dev,
+ acpi_notify_handler handler,
+ void *context)
+{
+ acpi_status status = AE_ALREADY_EXISTS;
+
+ mutex_lock(&pci_acpi_pm_notify_mtx);
+
+ if (dev->wakeup.flags.notifier_present)
+ goto out;
+
+ status = acpi_install_notify_handler(dev->handle,
+ ACPI_SYSTEM_NOTIFY,
+ handler, context);
+ if (ACPI_FAILURE(status))
+ goto out;
+
+ dev->wakeup.flags.notifier_present = true;
+
+ out:
+ mutex_unlock(&pci_acpi_pm_notify_mtx);
+ return status;
+}
+
+/**
+ * remove_pm_notifier - Unregister PM notifier from given ACPI device.
+ * @dev: ACPI device to remove the notifier from.
+ */
+static acpi_status remove_pm_notifier(struct acpi_device *dev,
+ acpi_notify_handler handler)
+{
+ acpi_status status = AE_BAD_PARAMETER;
+
+ mutex_lock(&pci_acpi_pm_notify_mtx);
+
+ if (!dev->wakeup.flags.notifier_present)
+ goto out;
+
+ status = acpi_remove_notify_handler(dev->handle,
+ ACPI_SYSTEM_NOTIFY,
+ handler);
+ if (ACPI_FAILURE(status))
+ goto out;
+
+ dev->wakeup.flags.notifier_present = false;
+
+ out:
+ mutex_unlock(&pci_acpi_pm_notify_mtx);
+ return status;
+}
+
+/**
+ * pci_acpi_add_bus_pm_notifier - Register PM notifier for given PCI bus.
+ * @dev: ACPI device to add the notifier for.
+ * @pci_bus: PCI bus to walk checking for PME status if an event is signaled.
+ */
+acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev,
+ struct pci_bus *pci_bus)
+{
+ return add_pm_notifier(dev, pci_acpi_wake_bus, pci_bus);
+}
+
+/**
+ * pci_acpi_remove_bus_pm_notifier - Unregister PCI bus PM notifier.
+ * @dev: ACPI device to remove the notifier from.
+ */
+acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev)
+{
+ return remove_pm_notifier(dev, pci_acpi_wake_bus);
+}
+
+/**
+ * pci_acpi_add_pm_notifier - Register PM notifier for given PCI device.
+ * @dev: ACPI device to add the notifier for.
+ * @pci_dev: PCI device to check for the PME status if an event is signaled.
+ */
+acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
+ struct pci_dev *pci_dev)
+{
+ return add_pm_notifier(dev, pci_acpi_wake_dev, pci_dev);
+}
+
+/**
+ * pci_acpi_remove_pm_notifier - Unregister PCI device PM notifier.
+ * @dev: ACPI device to remove the notifier from.
+ */
+acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
+{
+ return remove_pm_notifier(dev, pci_acpi_wake_dev);
+}
+
/*
* _SxD returns the D-state with the highest power
* (lowest D-state number) supported in the S-state "x".
@@ -131,19 +267,94 @@ static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable)
return 0;
}
+/**
+ * acpi_dev_run_wake - Enable/disable wake-up for given device.
+ * @phys_dev: Device to enable/disable the platform to wake-up the system for.
+ * @enable: Whether enable or disable the wake-up functionality.
+ *
+ * Find the ACPI device object corresponding to @pci_dev and try to
+ * enable/disable the GPE associated with it.
+ */
+static int acpi_dev_run_wake(struct device *phys_dev, bool enable)
+{
+ struct acpi_device *dev;
+ acpi_handle handle;
+ int error = -ENODEV;
+
+ if (!device_run_wake(phys_dev))
+ return -EINVAL;
+
+ handle = DEVICE_ACPI_HANDLE(phys_dev);
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &dev))) {
+ dev_dbg(phys_dev, "ACPI handle has no context in %s!\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ if (enable) {
+ if (!dev->wakeup.run_wake_count++) {
+ acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0);
+ acpi_enable_gpe(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number,
+ ACPI_GPE_TYPE_RUNTIME);
+ }
+ } else if (dev->wakeup.run_wake_count > 0) {
+ if (!--dev->wakeup.run_wake_count) {
+ acpi_disable_gpe(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number,
+ ACPI_GPE_TYPE_RUNTIME);
+ acpi_disable_wakeup_device_power(dev);
+ }
+ } else {
+ error = -EALREADY;
+ }
+
+ return error;
+}
+
+static void acpi_pci_propagate_run_wake(struct pci_bus *bus, bool enable)
+{
+ while (bus->parent) {
+ struct pci_dev *bridge = bus->self;
+
+ if (bridge->pme_interrupt)
+ return;
+ if (!acpi_dev_run_wake(&bridge->dev, enable))
+ return;
+ bus = bus->parent;
+ }
+
+ /* We have reached the root bus. */
+ if (bus->bridge)
+ acpi_dev_run_wake(bus->bridge, enable);
+}
+
+static int acpi_pci_run_wake(struct pci_dev *dev, bool enable)
+{
+ if (dev->pme_interrupt)
+ return 0;
+
+ if (!acpi_dev_run_wake(&dev->dev, enable))
+ return 0;
+
+ acpi_pci_propagate_run_wake(dev->bus, enable);
+ return 0;
+}
+
static struct pci_platform_pm_ops acpi_pci_platform_pm = {
.is_manageable = acpi_pci_power_manageable,
.set_state = acpi_pci_set_power_state,
.choose_state = acpi_pci_choose_state,
.can_wakeup = acpi_pci_can_wakeup,
.sleep_wake = acpi_pci_sleep_wake,
+ .run_wake = acpi_pci_run_wake,
};
/* ACPI bus type */
static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
{
struct pci_dev * pci_dev;
- acpi_integer addr;
+ u64 addr;
pci_dev = to_pci_dev(dev);
/* Please ref to ACPI spec for the syntax of _ADR */
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index e5d47be3c6d7..f9a0aec3abcf 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/cpu.h>
+#include <linux/pm_runtime.h>
#include "pci.h"
struct pci_dynid {
@@ -404,6 +405,35 @@ static void pci_device_shutdown(struct device *dev)
pci_msix_shutdown(pci_dev);
}
+#ifdef CONFIG_PM_OPS
+
+/* Auxiliary functions used for system resume and run-time resume. */
+
+/**
+ * pci_restore_standard_config - restore standard config registers of PCI device
+ * @pci_dev: PCI device to handle
+ */
+static int pci_restore_standard_config(struct pci_dev *pci_dev)
+{
+ pci_update_current_state(pci_dev, PCI_UNKNOWN);
+
+ if (pci_dev->current_state != PCI_D0) {
+ int error = pci_set_power_state(pci_dev, PCI_D0);
+ if (error)
+ return error;
+ }
+
+ return pci_restore_state(pci_dev);
+}
+
+static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
+{
+ pci_restore_standard_config(pci_dev);
+ pci_fixup_device(pci_fixup_resume_early, pci_dev);
+}
+
+#endif
+
#ifdef CONFIG_PM_SLEEP
/*
@@ -520,29 +550,6 @@ static int pci_legacy_resume(struct device *dev)
/* Auxiliary functions used by the new power management framework */
-/**
- * pci_restore_standard_config - restore standard config registers of PCI device
- * @pci_dev: PCI device to handle
- */
-static int pci_restore_standard_config(struct pci_dev *pci_dev)
-{
- pci_update_current_state(pci_dev, PCI_UNKNOWN);
-
- if (pci_dev->current_state != PCI_D0) {
- int error = pci_set_power_state(pci_dev, PCI_D0);
- if (error)
- return error;
- }
-
- return pci_restore_state(pci_dev);
-}
-
-static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev)
-{
- pci_restore_standard_config(pci_dev);
- pci_fixup_device(pci_fixup_resume_early, pci_dev);
-}
-
static void pci_pm_default_resume(struct pci_dev *pci_dev)
{
pci_fixup_device(pci_fixup_resume, pci_dev);
@@ -581,6 +588,17 @@ static int pci_pm_prepare(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
+ /*
+ * PCI devices suspended at run time need to be resumed at this
+ * point, because in general it is necessary to reconfigure them for
+ * system suspend. Namely, if the device is supposed to wake up the
+ * system from the sleep state, we may need to reconfigure it for this
+ * purpose. In turn, if the device is not supposed to wake up the
+ * system from the sleep state, we'll have to prevent it from signaling
+ * wake-up.
+ */
+ pm_runtime_resume(dev);
+
if (drv && drv->pm && drv->pm->prepare)
error = drv->pm->prepare(dev);
@@ -595,6 +613,13 @@ static void pci_pm_complete(struct device *dev)
drv->pm->complete(dev);
}
+#else /* !CONFIG_PM_SLEEP */
+
+#define pci_pm_prepare NULL
+#define pci_pm_complete NULL
+
+#endif /* !CONFIG_PM_SLEEP */
+
#ifdef CONFIG_SUSPEND
static int pci_pm_suspend(struct device *dev)
@@ -681,7 +706,7 @@ static int pci_pm_resume_noirq(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
- pci_pm_default_resume_noirq(pci_dev);
+ pci_pm_default_resume_early(pci_dev);
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_resume_early(dev);
@@ -879,7 +904,7 @@ static int pci_pm_restore_noirq(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
- pci_pm_default_resume_noirq(pci_dev);
+ pci_pm_default_resume_early(pci_dev);
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_resume_early(dev);
@@ -931,6 +956,84 @@ static int pci_pm_restore(struct device *dev)
#endif /* !CONFIG_HIBERNATION */
+#ifdef CONFIG_PM_RUNTIME
+
+static int pci_pm_runtime_suspend(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ pci_power_t prev = pci_dev->current_state;
+ int error;
+
+ if (!pm || !pm->runtime_suspend)
+ return -ENOSYS;
+
+ error = pm->runtime_suspend(dev);
+ suspend_report_result(pm->runtime_suspend, error);
+ if (error)
+ return error;
+
+ pci_fixup_device(pci_fixup_suspend, pci_dev);
+
+ if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
+ && pci_dev->current_state != PCI_UNKNOWN) {
+ WARN_ONCE(pci_dev->current_state != prev,
+ "PCI PM: State of device not saved by %pF\n",
+ pm->runtime_suspend);
+ return 0;
+ }
+
+ if (!pci_dev->state_saved)
+ pci_save_state(pci_dev);
+
+ pci_finish_runtime_suspend(pci_dev);
+
+ return 0;
+}
+
+static int pci_pm_runtime_resume(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (!pm || !pm->runtime_resume)
+ return -ENOSYS;
+
+ pci_pm_default_resume_early(pci_dev);
+ __pci_enable_wake(pci_dev, PCI_D0, true, false);
+ pci_fixup_device(pci_fixup_resume, pci_dev);
+
+ return pm->runtime_resume(dev);
+}
+
+static int pci_pm_runtime_idle(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+ if (!pm)
+ return -ENOSYS;
+
+ if (pm->runtime_idle) {
+ int ret = pm->runtime_idle(dev);
+ if (ret)
+ return ret;
+ }
+
+ pm_runtime_suspend(dev);
+
+ return 0;
+}
+
+#else /* !CONFIG_PM_RUNTIME */
+
+#define pci_pm_runtime_suspend NULL
+#define pci_pm_runtime_resume NULL
+#define pci_pm_runtime_idle NULL
+
+#endif /* !CONFIG_PM_RUNTIME */
+
+#ifdef CONFIG_PM_OPS
+
const struct dev_pm_ops pci_dev_pm_ops = {
.prepare = pci_pm_prepare,
.complete = pci_pm_complete,
@@ -946,15 +1049,18 @@ const struct dev_pm_ops pci_dev_pm_ops = {
.thaw_noirq = pci_pm_thaw_noirq,
.poweroff_noirq = pci_pm_poweroff_noirq,
.restore_noirq = pci_pm_restore_noirq,
+ .runtime_suspend = pci_pm_runtime_suspend,
+ .runtime_resume = pci_pm_runtime_resume,
+ .runtime_idle = pci_pm_runtime_idle,
};
#define PCI_PM_OPS_PTR (&pci_dev_pm_ops)
-#else /* !CONFIG_PM_SLEEP */
+#else /* !COMFIG_PM_OPS */
#define PCI_PM_OPS_PTR NULL
-#endif /* !CONFIG_PM_SLEEP */
+#endif /* !COMFIG_PM_OPS */
/**
* __pci_register_driver - register a new pci driver
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 807224ec8351..de296452c957 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -642,6 +642,7 @@ void pci_create_legacy_files(struct pci_bus *b)
if (!b->legacy_io)
goto kzalloc_err;
+ sysfs_bin_attr_init(b->legacy_io);
b->legacy_io->attr.name = "legacy_io";
b->legacy_io->size = 0xffff;
b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
@@ -654,6 +655,7 @@ void pci_create_legacy_files(struct pci_bus *b)
goto legacy_io_err;
/* Allocated above after the legacy_io struct */
+ sysfs_bin_attr_init(b->legacy_mem);
b->legacy_mem = b->legacy_io + 1;
b->legacy_mem->attr.name = "legacy_mem";
b->legacy_mem->size = 1024*1024;
@@ -800,6 +802,7 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
if (res_attr) {
char *res_attr_name = (char *)(res_attr + 1);
+ sysfs_bin_attr_init(res_attr);
if (write_combine) {
pdev->res_attr_wc[num] = res_attr;
sprintf(res_attr_name, "resource%d_wc", num);
@@ -972,6 +975,7 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
if (!attr)
return -ENOMEM;
+ sysfs_bin_attr_init(attr);
attr->size = dev->vpd->len;
attr->attr.name = "vpd";
attr->attr.mode = S_IRUSR | S_IWUSR;
@@ -1038,6 +1042,7 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
retval = -ENOMEM;
goto err_resource_files;
}
+ sysfs_bin_attr_init(attr);
attr->size = rom_size;
attr->attr.name = "rom";
attr->attr.mode = S_IRUSR;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 315fea47e784..cb1dd5f4988c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -19,8 +19,8 @@
#include <linux/pci-aspm.h>
#include <linux/pm_wakeup.h>
#include <linux/interrupt.h>
-#include <asm/dma.h> /* isa_dma_bridge_buggy */
#include <linux/device.h>
+#include <linux/pm_runtime.h>
#include <asm/setup.h>
#include "pci.h"
@@ -29,6 +29,12 @@ const char *pci_power_names[] = {
};
EXPORT_SYMBOL_GPL(pci_power_names);
+int isa_dma_bridge_buggy;
+EXPORT_SYMBOL(isa_dma_bridge_buggy);
+
+int pci_pci_problems;
+EXPORT_SYMBOL(pci_pci_problems);
+
unsigned int pci_pm_d3_delay;
static void pci_dev_d3_sleep(struct pci_dev *dev)
@@ -297,6 +303,49 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap)
}
EXPORT_SYMBOL_GPL(pci_find_ext_capability);
+/**
+ * pci_bus_find_ext_capability - find an extended capability
+ * @bus: the PCI bus to query
+ * @devfn: PCI device to query
+ * @cap: capability code
+ *
+ * Like pci_find_ext_capability() but works for pci devices that do not have a
+ * pci_dev structure set up yet.
+ *
+ * Returns the address of the requested capability structure within the
+ * device's PCI configuration space or 0 in case the device does not
+ * support it.
+ */
+int pci_bus_find_ext_capability(struct pci_bus *bus, unsigned int devfn,
+ int cap)
+{
+ u32 header;
+ int ttl;
+ int pos = PCI_CFG_SPACE_SIZE;
+
+ /* minimum 8 bytes per capability */
+ ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
+
+ if (!pci_bus_read_config_dword(bus, devfn, pos, &header))
+ return 0;
+ if (header == 0xffffffff || header == 0)
+ return 0;
+
+ while (ttl-- > 0) {
+ if (PCI_EXT_CAP_ID(header) == cap)
+ return pos;
+
+ pos = PCI_EXT_CAP_NEXT(header);
+ if (pos < PCI_CFG_SPACE_SIZE)
+ break;
+
+ if (!pci_bus_read_config_dword(bus, devfn, pos, &header))
+ break;
+ }
+
+ return 0;
+}
+
static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap)
{
int rc, ttl = PCI_FIND_CAP_TTL;
@@ -380,10 +429,9 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
{
const struct pci_bus *bus = dev->bus;
int i;
- struct resource *best = NULL;
+ struct resource *best = NULL, *r;
- for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- struct resource *r = bus->resource[i];
+ pci_bus_for_each_resource(bus, r, i) {
if (!r)
continue;
if (res->start && !(res->start >= r->start && res->end <= r->end))
@@ -457,6 +505,12 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
pci_platform_pm->sleep_wake(dev, enable) : -ENODEV;
}
+static inline int platform_pci_run_wake(struct pci_dev *dev, bool enable)
+{
+ return pci_platform_pm ?
+ pci_platform_pm->run_wake(dev, enable) : -ENODEV;
+}
+
/**
* pci_raw_set_power_state - Use PCI PM registers to set the power state of
* given PCI device
@@ -1190,6 +1244,66 @@ int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
}
/**
+ * pci_check_pme_status - Check if given device has generated PME.
+ * @dev: Device to check.
+ *
+ * Check the PME status of the device and if set, clear it and clear PME enable
+ * (if set). Return 'true' if PME status and PME enable were both set or
+ * 'false' otherwise.
+ */
+bool pci_check_pme_status(struct pci_dev *dev)
+{
+ int pmcsr_pos;
+ u16 pmcsr;
+ bool ret = false;
+
+ if (!dev->pm_cap)
+ return false;
+
+ pmcsr_pos = dev->pm_cap + PCI_PM_CTRL;
+ pci_read_config_word(dev, pmcsr_pos, &pmcsr);
+ if (!(pmcsr & PCI_PM_CTRL_PME_STATUS))
+ return false;
+
+ /* Clear PME status. */
+ pmcsr |= PCI_PM_CTRL_PME_STATUS;
+ if (pmcsr & PCI_PM_CTRL_PME_ENABLE) {
+ /* Disable PME to avoid interrupt flood. */
+ pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
+ ret = true;
+ }
+
+ pci_write_config_word(dev, pmcsr_pos, pmcsr);
+
+ return ret;
+}
+
+/**
+ * pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set.
+ * @dev: Device to handle.
+ * @ign: Ignored.
+ *
+ * Check if @dev has generated PME and queue a resume request for it in that
+ * case.
+ */
+static int pci_pme_wakeup(struct pci_dev *dev, void *ign)
+{
+ if (pci_check_pme_status(dev))
+ pm_request_resume(&dev->dev);
+ return 0;
+}
+
+/**
+ * pci_pme_wakeup_bus - Walk given bus and wake up devices on it, if necessary.
+ * @bus: Top bus of the subtree to walk.
+ */
+void pci_pme_wakeup_bus(struct pci_bus *bus)
+{
+ if (bus)
+ pci_walk_bus(bus, pci_pme_wakeup, NULL);
+}
+
+/**
* pci_pme_capable - check the capability of PCI device to generate PME#
* @dev: PCI device to handle.
* @state: PCI state from which device will issue PME#.
@@ -1230,9 +1344,10 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
}
/**
- * pci_enable_wake - enable PCI device as wakeup event source
+ * __pci_enable_wake - enable PCI device as wakeup event source
* @dev: PCI device affected
* @state: PCI state from which device will issue wakeup events
+ * @runtime: True if the events are to be generated at run time
* @enable: True to enable event generation; false to disable
*
* This enables the device as a wakeup event source, or disables it.
@@ -1248,11 +1363,12 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
* Error code depending on the platform is returned if both the platform and
* the native mechanism fail to enable the generation of wake-up events
*/
-int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
+int __pci_enable_wake(struct pci_dev *dev, pci_power_t state,
+ bool runtime, bool enable)
{
int ret = 0;
- if (enable && !device_may_wakeup(&dev->dev))
+ if (enable && !runtime && !device_may_wakeup(&dev->dev))
return -EINVAL;
/* Don't do the same thing twice in a row for one device. */
@@ -1272,19 +1388,24 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
pci_pme_active(dev, true);
else
ret = 1;
- error = platform_pci_sleep_wake(dev, true);
+ error = runtime ? platform_pci_run_wake(dev, true) :
+ platform_pci_sleep_wake(dev, true);
if (ret)
ret = error;
if (!ret)
dev->wakeup_prepared = true;
} else {
- platform_pci_sleep_wake(dev, false);
+ if (runtime)
+ platform_pci_run_wake(dev, false);
+ else
+ platform_pci_sleep_wake(dev, false);
pci_pme_active(dev, false);
dev->wakeup_prepared = false;
}
return ret;
}
+EXPORT_SYMBOL(__pci_enable_wake);
/**
* pci_wake_from_d3 - enable/disable device to wake up from D3_hot or D3_cold
@@ -1394,6 +1515,66 @@ int pci_back_from_sleep(struct pci_dev *dev)
}
/**
+ * pci_finish_runtime_suspend - Carry out PCI-specific part of runtime suspend.
+ * @dev: PCI device being suspended.
+ *
+ * Prepare @dev to generate wake-up events at run time and put it into a low
+ * power state.
+ */
+int pci_finish_runtime_suspend(struct pci_dev *dev)
+{
+ pci_power_t target_state = pci_target_state(dev);
+ int error;
+
+ if (target_state == PCI_POWER_ERROR)
+ return -EIO;
+
+ __pci_enable_wake(dev, target_state, true, pci_dev_run_wake(dev));
+
+ error = pci_set_power_state(dev, target_state);
+
+ if (error)
+ __pci_enable_wake(dev, target_state, true, false);
+
+ return error;
+}
+
+/**
+ * pci_dev_run_wake - Check if device can generate run-time wake-up events.
+ * @dev: Device to check.
+ *
+ * Return true if the device itself is cabable of generating wake-up events
+ * (through the platform or using the native PCIe PME) or if the device supports
+ * PME and one of its upstream bridges can generate wake-up events.
+ */
+bool pci_dev_run_wake(struct pci_dev *dev)
+{
+ struct pci_bus *bus = dev->bus;
+
+ if (device_run_wake(&dev->dev))
+ return true;
+
+ if (!dev->pme_support)
+ return false;
+
+ while (bus->parent) {
+ struct pci_dev *bridge = bus->self;
+
+ if (device_run_wake(&bridge->dev))
+ return true;
+
+ bus = bus->parent;
+ }
+
+ /* We have reached the root bus. */
+ if (bus->bridge)
+ return device_run_wake(bus->bridge);
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(pci_dev_run_wake);
+
+/**
* pci_pm_init - Initialize PM functions of given PCI device
* @dev: PCI device to handle.
*/
@@ -1402,7 +1583,10 @@ void pci_pm_init(struct pci_dev *dev)
int pm;
u16 pmc;
+ pm_runtime_forbid(&dev->dev);
+ device_enable_async_suspend(&dev->dev);
dev->wakeup_prepared = false;
+
dev->pm_cap = 0;
/* find PCI PM capability in list */
@@ -2114,35 +2298,6 @@ void pci_msi_off(struct pci_dev *dev)
}
}
-#ifndef HAVE_ARCH_PCI_SET_DMA_MASK
-/*
- * These can be overridden by arch-specific implementations
- */
-int
-pci_set_dma_mask(struct pci_dev *dev, u64 mask)
-{
- if (!pci_dma_supported(dev, mask))
- return -EIO;
-
- dev->dma_mask = mask;
- dev_dbg(&dev->dev, "using %dbit DMA mask\n", fls64(mask));
-
- return 0;
-}
-
-int
-pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
-{
- if (!pci_dma_supported(dev, mask))
- return -EIO;
-
- dev->dev.coherent_dma_mask = mask;
- dev_dbg(&dev->dev, "using %dbit consistent DMA mask\n", fls64(mask));
-
- return 0;
-}
-#endif
-
#ifndef HAVE_ARCH_PCI_SET_DMA_MAX_SEGMENT_SIZE
int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size)
{
@@ -2304,7 +2459,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe)
if (!probe) {
pci_block_user_cfg_access(dev);
/* block PM suspend, driver probe, etc. */
- down(&dev->dev.sem);
+ device_lock(&dev->dev);
}
rc = pci_dev_specific_reset(dev, probe);
@@ -2326,7 +2481,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe)
rc = pci_parent_bus_reset(dev, probe);
done:
if (!probe) {
- up(&dev->dev.sem);
+ device_unlock(&dev->dev);
pci_unblock_user_cfg_access(dev);
}
@@ -2615,6 +2770,23 @@ int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
return 0;
}
+/* Some architectures require additional programming to enable VGA */
+static arch_set_vga_state_t arch_set_vga_state;
+
+void __init pci_register_set_vga_state(arch_set_vga_state_t func)
+{
+ arch_set_vga_state = func; /* NULL disables */
+}
+
+static int pci_set_vga_state_arch(struct pci_dev *dev, bool decode,
+ unsigned int command_bits, bool change_bridge)
+{
+ if (arch_set_vga_state)
+ return arch_set_vga_state(dev, decode, command_bits,
+ change_bridge);
+ return 0;
+}
+
/**
* pci_set_vga_state - set VGA decode state on device and parents if requested
* @dev: the PCI device
@@ -2628,9 +2800,15 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
struct pci_bus *bus;
struct pci_dev *bridge;
u16 cmd;
+ int rc;
WARN_ON(command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
+ /* ARCH specific VGA enables */
+ rc = pci_set_vga_state_arch(dev, decode, command_bits, change_bridge);
+ if (rc)
+ return rc;
+
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (decode == true)
cmd |= command_bits;
@@ -2845,6 +3023,7 @@ EXPORT_SYMBOL(pcim_pin_device);
EXPORT_SYMBOL(pci_disable_device);
EXPORT_SYMBOL(pci_find_capability);
EXPORT_SYMBOL(pci_bus_find_capability);
+EXPORT_SYMBOL(pci_register_set_vga_state);
EXPORT_SYMBOL(pci_release_regions);
EXPORT_SYMBOL(pci_request_regions);
EXPORT_SYMBOL(pci_request_regions_exclusive);
@@ -2860,8 +3039,6 @@ EXPORT_SYMBOL(pci_set_mwi);
EXPORT_SYMBOL(pci_try_set_mwi);
EXPORT_SYMBOL(pci_clear_mwi);
EXPORT_SYMBOL_GPL(pci_intx);
-EXPORT_SYMBOL(pci_set_dma_mask);
-EXPORT_SYMBOL(pci_set_consistent_dma_mask);
EXPORT_SYMBOL(pci_assign_resource);
EXPORT_SYMBOL(pci_find_parent_resource);
EXPORT_SYMBOL(pci_select_bars);
@@ -2871,10 +3048,8 @@ EXPORT_SYMBOL(pci_save_state);
EXPORT_SYMBOL(pci_restore_state);
EXPORT_SYMBOL(pci_pme_capable);
EXPORT_SYMBOL(pci_pme_active);
-EXPORT_SYMBOL(pci_enable_wake);
EXPORT_SYMBOL(pci_wake_from_d3);
EXPORT_SYMBOL(pci_target_state);
EXPORT_SYMBOL(pci_prepare_to_sleep);
EXPORT_SYMBOL(pci_back_from_sleep);
EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
-
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index fbd0e3adbca3..4eb10f48d270 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -35,6 +35,10 @@ int pci_probe_reset_function(struct pci_dev *dev);
*
* @sleep_wake: enables/disables the system wake up capability of given device
*
+ * @run_wake: enables/disables the platform to generate run-time wake-up events
+ * for given device (the device's wake-up capability has to be
+ * enabled by @sleep_wake for this feature to work)
+ *
* If given platform is generally capable of power managing PCI devices, all of
* these callbacks are mandatory.
*/
@@ -44,11 +48,16 @@ struct pci_platform_pm_ops {
pci_power_t (*choose_state)(struct pci_dev *dev);
bool (*can_wakeup)(struct pci_dev *dev);
int (*sleep_wake)(struct pci_dev *dev, bool enable);
+ int (*run_wake)(struct pci_dev *dev, bool enable);
};
extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
extern void pci_disable_enabled_device(struct pci_dev *dev);
+extern bool pci_check_pme_status(struct pci_dev *dev);
+extern int pci_finish_runtime_suspend(struct pci_dev *dev);
+extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
+extern void pci_pme_wakeup_bus(struct pci_bus *bus);
extern void pci_pm_init(struct pci_dev *dev);
extern void platform_pci_wakeup_init(struct pci_dev *dev);
extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
@@ -319,6 +328,13 @@ struct pci_dev_reset_methods {
int (*reset)(struct pci_dev *dev, int probe);
};
+#ifdef CONFIG_PCI_QUIRKS
extern int pci_dev_specific_reset(struct pci_dev *dev, int probe);
+#else
+static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
+{
+ return -ENOTTY;
+}
+#endif
#endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 5a0c6ad53f8e..b8b494b3e0d0 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -46,3 +46,7 @@ config PCIEASPM_DEBUG
help
This enables PCI Express ASPM debug support. It will add per-device
interface to control ASPM.
+
+config PCIE_PME
+ def_bool y
+ depends on PCIEPORTBUS && PM_RUNTIME && EXPERIMENTAL && ACPI
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
index 11f6bb1eae24..ea654545e7c4 100644
--- a/drivers/pci/pcie/Makefile
+++ b/drivers/pci/pcie/Makefile
@@ -11,3 +11,5 @@ obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o
# Build PCI Express AER if needed
obj-$(CONFIG_PCIEAER) += aer/
+
+obj-$(CONFIG_PCIE_PME) += pme/
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c
index 8c30a9544d61..223052b73563 100644
--- a/drivers/pci/pcie/aer/aer_inject.c
+++ b/drivers/pci/pcie/aer/aer_inject.c
@@ -321,7 +321,7 @@ static int aer_inject(struct aer_error_inj *einj)
unsigned long flags;
unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn);
int pos_cap_err, rp_pos_cap_err;
- u32 sever, mask;
+ u32 sever, cor_mask, uncor_mask;
int ret = 0;
dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn);
@@ -339,6 +339,9 @@ static int aer_inject(struct aer_error_inj *einj)
goto out_put;
}
pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever);
+ pci_read_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, &cor_mask);
+ pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK,
+ &uncor_mask);
rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR);
if (!rp_pos_cap_err) {
@@ -374,17 +377,14 @@ static int aer_inject(struct aer_error_inj *einj)
err->header_log2 = einj->header_log2;
err->header_log3 = einj->header_log3;
- pci_read_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, &mask);
- if (einj->cor_status && !(einj->cor_status & ~mask)) {
+ if (einj->cor_status && !(einj->cor_status & ~cor_mask)) {
ret = -EINVAL;
printk(KERN_WARNING "The correctable error(s) is masked "
"by device\n");
spin_unlock_irqrestore(&inject_lock, flags);
goto out_put;
}
-
- pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, &mask);
- if (einj->uncor_status && !(einj->uncor_status & ~mask)) {
+ if (einj->uncor_status && !(einj->uncor_status & ~uncor_mask)) {
ret = -EINVAL;
printk(KERN_WARNING "The uncorrectable error(s) is masked "
"by device\n");
diff --git a/drivers/pci/pcie/pme/Makefile b/drivers/pci/pcie/pme/Makefile
new file mode 100644
index 000000000000..8b9238053080
--- /dev/null
+++ b/drivers/pci/pcie/pme/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for PCI-Express Root Port PME signaling driver
+#
+
+obj-$(CONFIG_PCIE_PME) += pmedriver.o
+
+pmedriver-objs := pcie_pme.o
+pmedriver-$(CONFIG_ACPI) += pcie_pme_acpi.o
diff --git a/drivers/pci/pcie/pme/pcie_pme.c b/drivers/pci/pcie/pme/pcie_pme.c
new file mode 100644
index 000000000000..7b3cbff547ee
--- /dev/null
+++ b/drivers/pci/pcie/pme/pcie_pme.c
@@ -0,0 +1,505 @@
+/*
+ * PCIe Native PME support
+ *
+ * Copyright (C) 2007 - 2009 Intel Corp
+ * Copyright (C) 2007 - 2009 Shaohua Li <shaohua.li@intel.com>
+ * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License V2. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/pcieport_if.h>
+#include <linux/acpi.h>
+#include <linux/pci-acpi.h>
+#include <linux/pm_runtime.h>
+
+#include "../../pci.h"
+#include "pcie_pme.h"
+
+#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */
+#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */
+
+/*
+ * If set, this switch will prevent the PCIe root port PME service driver from
+ * being registered. Consequently, the interrupt-based PCIe PME signaling will
+ * not be used by any PCIe root ports in that case.
+ */
+static bool pcie_pme_disabled;
+
+/*
+ * The PCI Express Base Specification 2.0, Section 6.1.8, states the following:
+ * "In order to maintain compatibility with non-PCI Express-aware system
+ * software, system power management logic must be configured by firmware to use
+ * the legacy mechanism of signaling PME by default. PCI Express-aware system
+ * software must notify the firmware prior to enabling native, interrupt-based
+ * PME signaling." However, if the platform doesn't provide us with a suitable
+ * notification mechanism or the notification fails, it is not clear whether or
+ * not we are supposed to use the interrupt-based PCIe PME signaling. The
+ * switch below can be used to indicate the desired behaviour. When set, it
+ * will make the kernel use the interrupt-based PCIe PME signaling regardless of
+ * the platform notification status, although the kernel will attempt to notify
+ * the platform anyway. When unset, it will prevent the kernel from using the
+ * the interrupt-based PCIe PME signaling if the platform notification fails,
+ * which is the default.
+ */
+static bool pcie_pme_force_enable;
+
+/*
+ * If this switch is set, MSI will not be used for PCIe PME signaling. This
+ * causes the PCIe port driver to use INTx interrupts only, but it turns out
+ * that using MSI for PCIe PME signaling doesn't play well with PCIe PME-based
+ * wake-up from system sleep states.
+ */
+bool pcie_pme_msi_disabled;
+
+static int __init pcie_pme_setup(char *str)
+{
+ if (!strcmp(str, "off"))
+ pcie_pme_disabled = true;
+ else if (!strcmp(str, "force"))
+ pcie_pme_force_enable = true;
+ else if (!strcmp(str, "nomsi"))
+ pcie_pme_msi_disabled = true;
+ return 1;
+}
+__setup("pcie_pme=", pcie_pme_setup);
+
+/**
+ * pcie_pme_platform_setup - Ensure that the kernel controls the PCIe PME.
+ * @srv: PCIe PME root port service to use for carrying out the check.
+ *
+ * Notify the platform that the native PCIe PME is going to be used and return
+ * 'true' if the control of the PCIe PME registers has been acquired from the
+ * platform.
+ */
+static bool pcie_pme_platform_setup(struct pcie_device *srv)
+{
+ if (!pcie_pme_platform_notify(srv))
+ return true;
+ return pcie_pme_force_enable;
+}
+
+struct pcie_pme_service_data {
+ spinlock_t lock;
+ struct pcie_device *srv;
+ struct work_struct work;
+ bool noirq; /* Don't enable the PME interrupt used by this service. */
+};
+
+/**
+ * pcie_pme_interrupt_enable - Enable/disable PCIe PME interrupt generation.
+ * @dev: PCIe root port or event collector.
+ * @enable: Enable or disable the interrupt.
+ */
+static void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable)
+{
+ int rtctl_pos;
+ u16 rtctl;
+
+ rtctl_pos = pci_pcie_cap(dev) + PCI_EXP_RTCTL;
+
+ pci_read_config_word(dev, rtctl_pos, &rtctl);
+ if (enable)
+ rtctl |= PCI_EXP_RTCTL_PMEIE;
+ else
+ rtctl &= ~PCI_EXP_RTCTL_PMEIE;
+ pci_write_config_word(dev, rtctl_pos, rtctl);
+}
+
+/**
+ * pcie_pme_clear_status - Clear root port PME interrupt status.
+ * @dev: PCIe root port or event collector.
+ */
+static void pcie_pme_clear_status(struct pci_dev *dev)
+{
+ int rtsta_pos;
+ u32 rtsta;
+
+ rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA;
+
+ pci_read_config_dword(dev, rtsta_pos, &rtsta);
+ rtsta |= PCI_EXP_RTSTA_PME;
+ pci_write_config_dword(dev, rtsta_pos, rtsta);
+}
+
+/**
+ * pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#.
+ * @bus: PCI bus to scan.
+ *
+ * Scan given PCI bus and all buses under it for devices asserting PME#.
+ */
+static bool pcie_pme_walk_bus(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+ bool ret = false;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ /* Skip PCIe devices in case we started from a root port. */
+ if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) {
+ pm_request_resume(&dev->dev);
+ ret = true;
+ }
+
+ if (dev->subordinate && pcie_pme_walk_bus(dev->subordinate))
+ ret = true;
+ }
+
+ return ret;
+}
+
+/**
+ * pcie_pme_from_pci_bridge - Check if PCIe-PCI bridge generated a PME.
+ * @bus: Secondary bus of the bridge.
+ * @devfn: Device/function number to check.
+ *
+ * PME from PCI devices under a PCIe-PCI bridge may be converted to an in-band
+ * PCIe PME message. In such that case the bridge should use the Requester ID
+ * of device/function number 0 on its secondary bus.
+ */
+static bool pcie_pme_from_pci_bridge(struct pci_bus *bus, u8 devfn)
+{
+ struct pci_dev *dev;
+ bool found = false;
+
+ if (devfn)
+ return false;
+
+ dev = pci_dev_get(bus->self);
+ if (!dev)
+ return false;
+
+ if (pci_is_pcie(dev) && dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
+ down_read(&pci_bus_sem);
+ if (pcie_pme_walk_bus(bus))
+ found = true;
+ up_read(&pci_bus_sem);
+ }
+
+ pci_dev_put(dev);
+ return found;
+}
+
+/**
+ * pcie_pme_handle_request - Find device that generated PME and handle it.
+ * @port: Root port or event collector that generated the PME interrupt.
+ * @req_id: PCIe Requester ID of the device that generated the PME.
+ */
+static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id)
+{
+ u8 busnr = req_id >> 8, devfn = req_id & 0xff;
+ struct pci_bus *bus;
+ struct pci_dev *dev;
+ bool found = false;
+
+ /* First, check if the PME is from the root port itself. */
+ if (port->devfn == devfn && port->bus->number == busnr) {
+ if (pci_check_pme_status(port)) {
+ pm_request_resume(&port->dev);
+ found = true;
+ } else {
+ /*
+ * Apparently, the root port generated the PME on behalf
+ * of a non-PCIe device downstream. If this is done by
+ * a root port, the Requester ID field in its status
+ * register may contain either the root port's, or the
+ * source device's information (PCI Express Base
+ * Specification, Rev. 2.0, Section 6.1.9).
+ */
+ down_read(&pci_bus_sem);
+ found = pcie_pme_walk_bus(port->subordinate);
+ up_read(&pci_bus_sem);
+ }
+ goto out;
+ }
+
+ /* Second, find the bus the source device is on. */
+ bus = pci_find_bus(pci_domain_nr(port->bus), busnr);
+ if (!bus)
+ goto out;
+
+ /* Next, check if the PME is from a PCIe-PCI bridge. */
+ found = pcie_pme_from_pci_bridge(bus, devfn);
+ if (found)
+ goto out;
+
+ /* Finally, try to find the PME source on the bus. */
+ down_read(&pci_bus_sem);
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ pci_dev_get(dev);
+ if (dev->devfn == devfn) {
+ found = true;
+ break;
+ }
+ pci_dev_put(dev);
+ }
+ up_read(&pci_bus_sem);
+
+ if (found) {
+ /* The device is there, but we have to check its PME status. */
+ found = pci_check_pme_status(dev);
+ if (found)
+ pm_request_resume(&dev->dev);
+ pci_dev_put(dev);
+ } else if (devfn) {
+ /*
+ * The device is not there, but we can still try to recover by
+ * assuming that the PME was reported by a PCIe-PCI bridge that
+ * used devfn different from zero.
+ */
+ dev_dbg(&port->dev, "PME interrupt generated for "
+ "non-existent device %02x:%02x.%d\n",
+ busnr, PCI_SLOT(devfn), PCI_FUNC(devfn));
+ found = pcie_pme_from_pci_bridge(bus, 0);
+ }
+
+ out:
+ if (!found)
+ dev_dbg(&port->dev, "Spurious native PME interrupt!\n");
+}
+
+/**
+ * pcie_pme_work_fn - Work handler for PCIe PME interrupt.
+ * @work: Work structure giving access to service data.
+ */
+static void pcie_pme_work_fn(struct work_struct *work)
+{
+ struct pcie_pme_service_data *data =
+ container_of(work, struct pcie_pme_service_data, work);
+ struct pci_dev *port = data->srv->port;
+ int rtsta_pos;
+ u32 rtsta;
+
+ rtsta_pos = pci_pcie_cap(port) + PCI_EXP_RTSTA;
+
+ spin_lock_irq(&data->lock);
+
+ for (;;) {
+ if (data->noirq)
+ break;
+
+ pci_read_config_dword(port, rtsta_pos, &rtsta);
+ if (rtsta & PCI_EXP_RTSTA_PME) {
+ /*
+ * Clear PME status of the port. If there are other
+ * pending PMEs, the status will be set again.
+ */
+ pcie_pme_clear_status(port);
+
+ spin_unlock_irq(&data->lock);
+ pcie_pme_handle_request(port, rtsta & 0xffff);
+ spin_lock_irq(&data->lock);
+
+ continue;
+ }
+
+ /* No need to loop if there are no more PMEs pending. */
+ if (!(rtsta & PCI_EXP_RTSTA_PENDING))
+ break;
+
+ spin_unlock_irq(&data->lock);
+ cpu_relax();
+ spin_lock_irq(&data->lock);
+ }
+
+ if (!data->noirq)
+ pcie_pme_interrupt_enable(port, true);
+
+ spin_unlock_irq(&data->lock);
+}
+
+/**
+ * pcie_pme_irq - Interrupt handler for PCIe root port PME interrupt.
+ * @irq: Interrupt vector.
+ * @context: Interrupt context pointer.
+ */
+static irqreturn_t pcie_pme_irq(int irq, void *context)
+{
+ struct pci_dev *port;
+ struct pcie_pme_service_data *data;
+ int rtsta_pos;
+ u32 rtsta;
+ unsigned long flags;
+
+ port = ((struct pcie_device *)context)->port;
+ data = get_service_data((struct pcie_device *)context);
+
+ rtsta_pos = pci_pcie_cap(port) + PCI_EXP_RTSTA;
+
+ spin_lock_irqsave(&data->lock, flags);
+ pci_read_config_dword(port, rtsta_pos, &rtsta);
+
+ if (!(rtsta & PCI_EXP_RTSTA_PME)) {
+ spin_unlock_irqrestore(&data->lock, flags);
+ return IRQ_NONE;
+ }
+
+ pcie_pme_interrupt_enable(port, false);
+ spin_unlock_irqrestore(&data->lock, flags);
+
+ /* We don't use pm_wq, because it's freezable. */
+ schedule_work(&data->work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * pcie_pme_set_native - Set the PME interrupt flag for given device.
+ * @dev: PCI device to handle.
+ * @ign: Ignored.
+ */
+static int pcie_pme_set_native(struct pci_dev *dev, void *ign)
+{
+ dev_info(&dev->dev, "Signaling PME through PCIe PME interrupt\n");
+
+ device_set_run_wake(&dev->dev, true);
+ dev->pme_interrupt = true;
+ return 0;
+}
+
+/**
+ * pcie_pme_mark_devices - Set the PME interrupt flag for devices below a port.
+ * @port: PCIe root port or event collector to handle.
+ *
+ * For each device below given root port, including the port itself (or for each
+ * root complex integrated endpoint if @port is a root complex event collector)
+ * set the flag indicating that it can signal run-time wake-up events via PCIe
+ * PME interrupts.
+ */
+static void pcie_pme_mark_devices(struct pci_dev *port)
+{
+ pcie_pme_set_native(port, NULL);
+ if (port->subordinate) {
+ pci_walk_bus(port->subordinate, pcie_pme_set_native, NULL);
+ } else {
+ struct pci_bus *bus = port->bus;
+ struct pci_dev *dev;
+
+ /* Check if this is a root port event collector. */
+ if (port->pcie_type != PCI_EXP_TYPE_RC_EC || !bus)
+ return;
+
+ down_read(&pci_bus_sem);
+ list_for_each_entry(dev, &bus->devices, bus_list)
+ if (pci_is_pcie(dev)
+ && dev->pcie_type == PCI_EXP_TYPE_RC_END)
+ pcie_pme_set_native(dev, NULL);
+ up_read(&pci_bus_sem);
+ }
+}
+
+/**
+ * pcie_pme_probe - Initialize PCIe PME service for given root port.
+ * @srv: PCIe service to initialize.
+ */
+static int pcie_pme_probe(struct pcie_device *srv)
+{
+ struct pci_dev *port;
+ struct pcie_pme_service_data *data;
+ int ret;
+
+ if (!pcie_pme_platform_setup(srv))
+ return -EACCES;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock_init(&data->lock);
+ INIT_WORK(&data->work, pcie_pme_work_fn);
+ data->srv = srv;
+ set_service_data(srv, data);
+
+ port = srv->port;
+ pcie_pme_interrupt_enable(port, false);
+ pcie_pme_clear_status(port);
+
+ ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv);
+ if (ret) {
+ kfree(data);
+ } else {
+ pcie_pme_mark_devices(port);
+ pcie_pme_interrupt_enable(port, true);
+ }
+
+ return ret;
+}
+
+/**
+ * pcie_pme_suspend - Suspend PCIe PME service device.
+ * @srv: PCIe service device to suspend.
+ */
+static int pcie_pme_suspend(struct pcie_device *srv)
+{
+ struct pcie_pme_service_data *data = get_service_data(srv);
+ struct pci_dev *port = srv->port;
+
+ spin_lock_irq(&data->lock);
+ pcie_pme_interrupt_enable(port, false);
+ pcie_pme_clear_status(port);
+ data->noirq = true;
+ spin_unlock_irq(&data->lock);
+
+ synchronize_irq(srv->irq);
+
+ return 0;
+}
+
+/**
+ * pcie_pme_resume - Resume PCIe PME service device.
+ * @srv - PCIe service device to resume.
+ */
+static int pcie_pme_resume(struct pcie_device *srv)
+{
+ struct pcie_pme_service_data *data = get_service_data(srv);
+ struct pci_dev *port = srv->port;
+
+ spin_lock_irq(&data->lock);
+ data->noirq = false;
+ pcie_pme_clear_status(port);
+ pcie_pme_interrupt_enable(port, true);
+ spin_unlock_irq(&data->lock);
+
+ return 0;
+}
+
+/**
+ * pcie_pme_remove - Prepare PCIe PME service device for removal.
+ * @srv - PCIe service device to resume.
+ */
+static void pcie_pme_remove(struct pcie_device *srv)
+{
+ pcie_pme_suspend(srv);
+ free_irq(srv->irq, srv);
+ kfree(get_service_data(srv));
+}
+
+static struct pcie_port_service_driver pcie_pme_driver = {
+ .name = "pcie_pme",
+ .port_type = PCI_EXP_TYPE_ROOT_PORT,
+ .service = PCIE_PORT_SERVICE_PME,
+
+ .probe = pcie_pme_probe,
+ .suspend = pcie_pme_suspend,
+ .resume = pcie_pme_resume,
+ .remove = pcie_pme_remove,
+};
+
+/**
+ * pcie_pme_service_init - Register the PCIe PME service driver.
+ */
+static int __init pcie_pme_service_init(void)
+{
+ return pcie_pme_disabled ?
+ -ENODEV : pcie_port_service_register(&pcie_pme_driver);
+}
+
+module_init(pcie_pme_service_init);
diff --git a/drivers/pci/pcie/pme/pcie_pme.h b/drivers/pci/pcie/pme/pcie_pme.h
new file mode 100644
index 000000000000..b30d2b7c9775
--- /dev/null
+++ b/drivers/pci/pcie/pme/pcie_pme.h
@@ -0,0 +1,28 @@
+/*
+ * drivers/pci/pcie/pme/pcie_pme.h
+ *
+ * PCI Express Root Port PME signaling support
+ *
+ * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ */
+
+#ifndef _PCIE_PME_H_
+#define _PCIE_PME_H_
+
+struct pcie_device;
+
+#ifdef CONFIG_ACPI
+extern int pcie_pme_acpi_setup(struct pcie_device *srv);
+
+static inline int pcie_pme_platform_notify(struct pcie_device *srv)
+{
+ return pcie_pme_acpi_setup(srv);
+}
+#else /* !CONFIG_ACPI */
+static inline int pcie_pme_platform_notify(struct pcie_device *srv)
+{
+ return 0;
+}
+#endif /* !CONFIG_ACPI */
+
+#endif
diff --git a/drivers/pci/pcie/pme/pcie_pme_acpi.c b/drivers/pci/pcie/pme/pcie_pme_acpi.c
new file mode 100644
index 000000000000..83ab2287ae3f
--- /dev/null
+++ b/drivers/pci/pcie/pme/pcie_pme_acpi.c
@@ -0,0 +1,54 @@
+/*
+ * PCIe Native PME support, ACPI-related part
+ *
+ * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License V2. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/acpi.h>
+#include <linux/pci-acpi.h>
+#include <linux/pcieport_if.h>
+
+/**
+ * pcie_pme_acpi_setup - Request the ACPI BIOS to release control over PCIe PME.
+ * @srv - PCIe PME service for a root port or event collector.
+ *
+ * Invoked when the PCIe bus type loads PCIe PME service driver. To avoid
+ * conflict with the BIOS PCIe support requires the BIOS to yield PCIe PME
+ * control to the kernel.
+ */
+int pcie_pme_acpi_setup(struct pcie_device *srv)
+{
+ acpi_status status = AE_NOT_FOUND;
+ struct pci_dev *port = srv->port;
+ acpi_handle handle;
+ int error = 0;
+
+ if (acpi_pci_disabled)
+ return -ENOSYS;
+
+ dev_info(&port->dev, "Requesting control of PCIe PME from ACPI BIOS\n");
+
+ handle = acpi_find_root_bridge_handle(port);
+ if (!handle)
+ return -EINVAL;
+
+ status = acpi_pci_osc_control_set(handle,
+ OSC_PCI_EXPRESS_PME_CONTROL |
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+ if (ACPI_FAILURE(status)) {
+ dev_info(&port->dev,
+ "Failed to receive control of PCIe PME service: %s\n",
+ (status == AE_SUPPORT || status == AE_NOT_FOUND) ?
+ "no _OSC support" : "ACPI _OSC failed");
+ error = -ENODEV;
+ }
+
+ return error;
+}
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index aaeb9d21cba5..813a5c3427b6 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -30,4 +30,21 @@ extern void pcie_port_device_remove(struct pci_dev *dev);
extern int __must_check pcie_port_bus_register(void);
extern void pcie_port_bus_unregister(void);
+#ifdef CONFIG_PCIE_PME
+extern bool pcie_pme_msi_disabled;
+
+static inline void pcie_pme_disable_msi(void)
+{
+ pcie_pme_msi_disabled = true;
+}
+
+static inline bool pcie_pme_no_msi(void)
+{
+ return pcie_pme_msi_disabled;
+}
+#else /* !CONFIG_PCIE_PME */
+static inline void pcie_pme_disable_msi(void) {}
+static inline bool pcie_pme_no_msi(void) { return false; }
+#endif /* !CONFIG_PCIE_PME */
+
#endif /* _PORTDRV_H_ */
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index b174188ac121..e73effbe402c 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -186,16 +186,24 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask)
*/
static int init_service_irqs(struct pci_dev *dev, int *irqs, int mask)
{
- int i, irq;
+ int i, irq = -1;
+
+ /* We have to use INTx if MSI cannot be used for PCIe PME. */
+ if ((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) {
+ if (dev->pin)
+ irq = dev->irq;
+ goto no_msi;
+ }
/* Try to use MSI-X if supported */
if (!pcie_port_enable_msix(dev, irqs, mask))
return 0;
+
/* We're not going to use MSI-X, so try MSI and fall back to INTx */
- irq = -1;
if (!pci_enable_msi(dev) || dev->pin)
irq = dev->irq;
+ no_msi:
for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
irqs[i] = irq;
irqs[PCIE_PORT_SERVICE_VC_SHIFT] = -1;
@@ -277,6 +285,7 @@ static int pcie_device_init(struct pci_dev *pdev, int service, int irq)
pci_name(pdev),
get_descriptor_id(pdev->pcie_type, service));
device->parent = &pdev->dev;
+ device_enable_async_suspend(device);
retval = device_register(device);
if (retval)
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index 13c8972886e6..127e8f169d9c 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/pcieport_if.h>
#include <linux/aer.h>
+#include <linux/dmi.h>
#include "portdrv.h"
#include "aer/aerdrv.h"
@@ -273,10 +274,36 @@ static struct pci_driver pcie_portdriver = {
.driver.pm = PCIE_PORTDRV_PM_OPS,
};
+static int __init dmi_pcie_pme_disable_msi(const struct dmi_system_id *d)
+{
+ pr_notice("%s detected: will not use MSI for PCIe PME signaling\n",
+ d->ident);
+ pcie_pme_disable_msi();
+ return 0;
+}
+
+static struct dmi_system_id __initdata pcie_portdrv_dmi_table[] = {
+ /*
+ * Boxes that should not use MSI for PCIe PME signaling.
+ */
+ {
+ .callback = dmi_pcie_pme_disable_msi,
+ .ident = "MSI Wind U-100",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "MICRO-STAR INTERNATIONAL CO., LTD"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "U-100"),
+ },
+ },
+ {}
+};
+
static int __init pcie_portdrv_init(void)
{
int retval;
+ dmi_check_system(pcie_portdrv_dmi_table);
+
retval = pcie_port_bus_register();
if (retval) {
printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 98ffb2de22e9..2a943090a3b7 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -89,6 +89,7 @@ static void release_pcibus_dev(struct device *dev)
if (pci_bus->bridge)
put_device(pci_bus->bridge);
+ pci_bus_remove_resources(pci_bus);
kfree(pci_bus);
}
@@ -281,26 +282,12 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
}
}
-void __devinit pci_read_bridge_bases(struct pci_bus *child)
+static void __devinit pci_read_bridge_io(struct pci_bus *child)
{
struct pci_dev *dev = child->self;
u8 io_base_lo, io_limit_lo;
- u16 mem_base_lo, mem_limit_lo;
unsigned long base, limit;
struct resource *res;
- int i;
-
- if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */
- return;
-
- dev_info(&dev->dev, "PCI bridge to [bus %02x-%02x]%s\n",
- child->secondary, child->subordinate,
- dev->transparent ? " (subtractive decode)": "");
-
- if (dev->transparent) {
- for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++)
- child->resource[i] = child->parent->resource[i - 3];
- }
res = child->resource[0];
pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
@@ -316,26 +303,50 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
limit |= (io_limit_hi << 16);
}
- if (base <= limit) {
+ if (base && base <= limit) {
res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
if (!res->start)
res->start = base;
if (!res->end)
res->end = limit + 0xfff;
dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
+ } else {
+ dev_printk(KERN_DEBUG, &dev->dev,
+ " bridge window [io %04lx - %04lx] reg reading\n",
+ base, limit);
}
+}
+
+static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
+{
+ struct pci_dev *dev = child->self;
+ u16 mem_base_lo, mem_limit_lo;
+ unsigned long base, limit;
+ struct resource *res;
res = child->resource[1];
pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
- if (base <= limit) {
+ if (base && base <= limit) {
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
res->start = base;
res->end = limit + 0xfffff;
dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
+ } else {
+ dev_printk(KERN_DEBUG, &dev->dev,
+ " bridge window [mem 0x%08lx - 0x%08lx] reg reading\n",
+ base, limit + 0xfffff);
}
+}
+
+static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
+{
+ struct pci_dev *dev = child->self;
+ u16 mem_base_lo, mem_limit_lo;
+ unsigned long base, limit;
+ struct resource *res;
res = child->resource[2];
pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
@@ -366,7 +377,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
#endif
}
}
- if (base <= limit) {
+ if (base && base <= limit) {
res->flags = (mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) |
IORESOURCE_MEM | IORESOURCE_PREFETCH;
if (res->flags & PCI_PREF_RANGE_TYPE_64)
@@ -374,6 +385,44 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
res->start = base;
res->end = limit + 0xfffff;
dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
+ } else {
+ dev_printk(KERN_DEBUG, &dev->dev,
+ " bridge window [mem 0x%08lx - %08lx pref] reg reading\n",
+ base, limit + 0xfffff);
+ }
+}
+
+void __devinit pci_read_bridge_bases(struct pci_bus *child)
+{
+ struct pci_dev *dev = child->self;
+ struct resource *res;
+ int i;
+
+ if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */
+ return;
+
+ dev_info(&dev->dev, "PCI bridge to [bus %02x-%02x]%s\n",
+ child->secondary, child->subordinate,
+ dev->transparent ? " (subtractive decode)" : "");
+
+ pci_bus_remove_resources(child);
+ for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
+ child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+
+ pci_read_bridge_io(child);
+ pci_read_bridge_mmio(child);
+ pci_read_bridge_mmio_pref(child);
+
+ if (dev->transparent) {
+ pci_bus_for_each_resource(child->parent, res, i) {
+ if (res) {
+ pci_bus_add_resource(child, res,
+ PCI_SUBTRACTIVE_DECODE);
+ dev_printk(KERN_DEBUG, &dev->dev,
+ " bridge window %pR (subtractive decode)\n",
+ res);
+ }
+ }
}
}
@@ -387,10 +436,147 @@ static struct pci_bus * pci_alloc_bus(void)
INIT_LIST_HEAD(&b->children);
INIT_LIST_HEAD(&b->devices);
INIT_LIST_HEAD(&b->slots);
+ INIT_LIST_HEAD(&b->resources);
+ b->max_bus_speed = PCI_SPEED_UNKNOWN;
+ b->cur_bus_speed = PCI_SPEED_UNKNOWN;
}
return b;
}
+static unsigned char pcix_bus_speed[] = {
+ PCI_SPEED_UNKNOWN, /* 0 */
+ PCI_SPEED_66MHz_PCIX, /* 1 */
+ PCI_SPEED_100MHz_PCIX, /* 2 */
+ PCI_SPEED_133MHz_PCIX, /* 3 */
+ PCI_SPEED_UNKNOWN, /* 4 */
+ PCI_SPEED_66MHz_PCIX_ECC, /* 5 */
+ PCI_SPEED_100MHz_PCIX_ECC, /* 6 */
+ PCI_SPEED_133MHz_PCIX_ECC, /* 7 */
+ PCI_SPEED_UNKNOWN, /* 8 */
+ PCI_SPEED_66MHz_PCIX_266, /* 9 */
+ PCI_SPEED_100MHz_PCIX_266, /* A */
+ PCI_SPEED_133MHz_PCIX_266, /* B */
+ PCI_SPEED_UNKNOWN, /* C */
+ PCI_SPEED_66MHz_PCIX_533, /* D */
+ PCI_SPEED_100MHz_PCIX_533, /* E */
+ PCI_SPEED_133MHz_PCIX_533 /* F */
+};
+
+static unsigned char pcie_link_speed[] = {
+ PCI_SPEED_UNKNOWN, /* 0 */
+ PCIE_SPEED_2_5GT, /* 1 */
+ PCIE_SPEED_5_0GT, /* 2 */
+ PCIE_SPEED_8_0GT, /* 3 */
+ PCI_SPEED_UNKNOWN, /* 4 */
+ PCI_SPEED_UNKNOWN, /* 5 */
+ PCI_SPEED_UNKNOWN, /* 6 */
+ PCI_SPEED_UNKNOWN, /* 7 */
+ PCI_SPEED_UNKNOWN, /* 8 */
+ PCI_SPEED_UNKNOWN, /* 9 */
+ PCI_SPEED_UNKNOWN, /* A */
+ PCI_SPEED_UNKNOWN, /* B */
+ PCI_SPEED_UNKNOWN, /* C */
+ PCI_SPEED_UNKNOWN, /* D */
+ PCI_SPEED_UNKNOWN, /* E */
+ PCI_SPEED_UNKNOWN /* F */
+};
+
+void pcie_update_link_speed(struct pci_bus *bus, u16 linksta)
+{
+ bus->cur_bus_speed = pcie_link_speed[linksta & 0xf];
+}
+EXPORT_SYMBOL_GPL(pcie_update_link_speed);
+
+static unsigned char agp_speeds[] = {
+ AGP_UNKNOWN,
+ AGP_1X,
+ AGP_2X,
+ AGP_4X,
+ AGP_8X
+};
+
+static enum pci_bus_speed agp_speed(int agp3, int agpstat)
+{
+ int index = 0;
+
+ if (agpstat & 4)
+ index = 3;
+ else if (agpstat & 2)
+ index = 2;
+ else if (agpstat & 1)
+ index = 1;
+ else
+ goto out;
+
+ if (agp3) {
+ index += 2;
+ if (index == 5)
+ index = 0;
+ }
+
+ out:
+ return agp_speeds[index];
+}
+
+
+static void pci_set_bus_speed(struct pci_bus *bus)
+{
+ struct pci_dev *bridge = bus->self;
+ int pos;
+
+ pos = pci_find_capability(bridge, PCI_CAP_ID_AGP);
+ if (!pos)
+ pos = pci_find_capability(bridge, PCI_CAP_ID_AGP3);
+ if (pos) {
+ u32 agpstat, agpcmd;
+
+ pci_read_config_dword(bridge, pos + PCI_AGP_STATUS, &agpstat);
+ bus->max_bus_speed = agp_speed(agpstat & 8, agpstat & 7);
+
+ pci_read_config_dword(bridge, pos + PCI_AGP_COMMAND, &agpcmd);
+ bus->cur_bus_speed = agp_speed(agpstat & 8, agpcmd & 7);
+ }
+
+ pos = pci_find_capability(bridge, PCI_CAP_ID_PCIX);
+ if (pos) {
+ u16 status;
+ enum pci_bus_speed max;
+ pci_read_config_word(bridge, pos + 2, &status);
+
+ if (status & 0x8000) {
+ max = PCI_SPEED_133MHz_PCIX_533;
+ } else if (status & 0x4000) {
+ max = PCI_SPEED_133MHz_PCIX_266;
+ } else if (status & 0x0002) {
+ if (((status >> 12) & 0x3) == 2) {
+ max = PCI_SPEED_133MHz_PCIX_ECC;
+ } else {
+ max = PCI_SPEED_133MHz_PCIX;
+ }
+ } else {
+ max = PCI_SPEED_66MHz_PCIX;
+ }
+
+ bus->max_bus_speed = max;
+ bus->cur_bus_speed = pcix_bus_speed[(status >> 6) & 0xf];
+
+ return;
+ }
+
+ pos = pci_find_capability(bridge, PCI_CAP_ID_EXP);
+ if (pos) {
+ u32 linkcap;
+ u16 linksta;
+
+ pci_read_config_dword(bridge, pos + PCI_EXP_LNKCAP, &linkcap);
+ bus->max_bus_speed = pcie_link_speed[linkcap & 0xf];
+
+ pci_read_config_word(bridge, pos + PCI_EXP_LNKSTA, &linksta);
+ pcie_update_link_speed(bus, linksta);
+ }
+}
+
+
static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
struct pci_dev *bridge, int busnr)
{
@@ -430,6 +616,8 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
child->self = bridge;
child->bridge = get_device(&bridge->dev);
+ pci_set_bus_speed(child);
+
/* Set up default resource pointers and names.. */
for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i];
@@ -681,7 +869,7 @@ static void pci_read_irq(struct pci_dev *dev)
dev->irq = irq;
}
-static void set_pcie_port_type(struct pci_dev *pdev)
+void set_pcie_port_type(struct pci_dev *pdev)
{
int pos;
u16 reg16;
@@ -695,7 +883,7 @@ static void set_pcie_port_type(struct pci_dev *pdev)
pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
}
-static void set_pcie_hotplug_bridge(struct pci_dev *pdev)
+void set_pcie_hotplug_bridge(struct pci_dev *pdev)
{
int pos;
u16 reg16;
@@ -1081,6 +1269,45 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
}
EXPORT_SYMBOL(pci_scan_single_device);
+static unsigned next_ari_fn(struct pci_dev *dev, unsigned fn)
+{
+ u16 cap;
+ unsigned pos, next_fn;
+
+ if (!dev)
+ return 0;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
+ if (!pos)
+ return 0;
+ pci_read_config_word(dev, pos + 4, &cap);
+ next_fn = cap >> 8;
+ if (next_fn <= fn)
+ return 0;
+ return next_fn;
+}
+
+static unsigned next_trad_fn(struct pci_dev *dev, unsigned fn)
+{
+ return (fn + 1) % 8;
+}
+
+static unsigned no_next_fn(struct pci_dev *dev, unsigned fn)
+{
+ return 0;
+}
+
+static int only_one_child(struct pci_bus *bus)
+{
+ struct pci_dev *parent = bus->self;
+ if (!parent || !pci_is_pcie(parent))
+ return 0;
+ if (parent->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
+ parent->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
+ return 1;
+ return 0;
+}
+
/**
* pci_scan_slot - scan a PCI slot on a bus for devices.
* @bus: PCI bus to scan
@@ -1094,21 +1321,30 @@ EXPORT_SYMBOL(pci_scan_single_device);
*/
int pci_scan_slot(struct pci_bus *bus, int devfn)
{
- int fn, nr = 0;
+ unsigned fn, nr = 0;
struct pci_dev *dev;
+ unsigned (*next_fn)(struct pci_dev *, unsigned) = no_next_fn;
+
+ if (only_one_child(bus) && (devfn > 0))
+ return 0; /* Already scanned the entire slot */
dev = pci_scan_single_device(bus, devfn);
- if (dev && !dev->is_added) /* new device? */
+ if (!dev)
+ return 0;
+ if (!dev->is_added)
nr++;
- if (dev && dev->multifunction) {
- for (fn = 1; fn < 8; fn++) {
- dev = pci_scan_single_device(bus, devfn + fn);
- if (dev) {
- if (!dev->is_added)
- nr++;
- dev->multifunction = 1;
- }
+ if (pci_ari_enabled(bus))
+ next_fn = next_ari_fn;
+ else if (dev->multifunction)
+ next_fn = next_trad_fn;
+
+ for (fn = next_fn(dev, 0); fn > 0; fn = next_fn(dev, fn)) {
+ dev = pci_scan_single_device(bus, devfn + fn);
+ if (dev) {
+ if (!dev->is_added)
+ nr++;
+ dev->multifunction = 1;
}
}
@@ -1200,6 +1436,7 @@ struct pci_bus * pci_create_bus(struct device *parent,
if (error)
goto dev_reg_err;
b->bridge = get_device(dev);
+ device_enable_async_suspend(b->bridge);
if (!parent)
set_dev_node(b->bridge, pcibus_to_node(b));
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index c74694345b6e..81d19d5683ac 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -25,14 +25,9 @@
#include <linux/dmi.h>
#include <linux/pci-aspm.h>
#include <linux/ioport.h>
+#include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h"
-int isa_dma_bridge_buggy;
-EXPORT_SYMBOL(isa_dma_bridge_buggy);
-int pci_pci_problems;
-EXPORT_SYMBOL(pci_pci_problems);
-
-#ifdef CONFIG_PCI_QUIRKS
/*
* This quirk function disables memory decoding and releases memory resources
* of the device specified by kernel's boot parameter 'pci=resource_alignment='.
@@ -338,6 +333,23 @@ static void __devinit quirk_s3_64M(struct pci_dev *dev)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M);
+/*
+ * Some CS5536 BIOSes (for example, the Soekris NET5501 board w/ comBIOS
+ * ver. 1.33 20070103) don't set the correct ISA PCI region header info.
+ * BAR0 should be 8 bytes; instead, it may be set to something like 8k
+ * (which conflicts w/ BAR1's memory range).
+ */
+static void __devinit quirk_cs5536_vsa(struct pci_dev *dev)
+{
+ if (pci_resource_len(dev, 0) != 8) {
+ struct resource *res = &dev->resource[0];
+ res->end = res->start + 8 - 1;
+ dev_info(&dev->dev, "CS5536 ISA bridge bug detected "
+ "(incorrect header); workaround applied.\n");
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_cs5536_vsa);
+
static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region,
unsigned size, int nr, const char *name)
{
@@ -2517,9 +2529,95 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e7, quirk_i82576_sriov);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e8, quirk_i82576_sriov);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x150a, quirk_i82576_sriov);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x150d, quirk_i82576_sriov);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1518, quirk_i82576_sriov);
#endif /* CONFIG_PCI_IOV */
+/*
+ * This is a quirk for the Ricoh MMC controller found as a part of
+ * some mulifunction chips.
+
+ * This is very similiar and based on the ricoh_mmc driver written by
+ * Philip Langdale. Thank you for these magic sequences.
+ *
+ * These chips implement the four main memory card controllers (SD, MMC, MS, xD)
+ * and one or both of cardbus or firewire.
+ *
+ * It happens that they implement SD and MMC
+ * support as separate controllers (and PCI functions). The linux SDHCI
+ * driver supports MMC cards but the chip detects MMC cards in hardware
+ * and directs them to the MMC controller - so the SDHCI driver never sees
+ * them.
+ *
+ * To get around this, we must disable the useless MMC controller.
+ * At that point, the SDHCI controller will start seeing them
+ * It seems to be the case that the relevant PCI registers to deactivate the
+ * MMC controller live on PCI function 0, which might be the cardbus controller
+ * or the firewire controller, depending on the particular chip in question
+ *
+ * This has to be done early, because as soon as we disable the MMC controller
+ * other pci functions shift up one level, e.g. function #2 becomes function
+ * #1, and this will confuse the pci core.
+ */
+
+#ifdef CONFIG_MMC_RICOH_MMC
+static void ricoh_mmc_fixup_rl5c476(struct pci_dev *dev)
+{
+ /* disable via cardbus interface */
+ u8 write_enable;
+ u8 write_target;
+ u8 disable;
+
+ /* disable must be done via function #0 */
+ if (PCI_FUNC(dev->devfn))
+ return;
+
+ pci_read_config_byte(dev, 0xB7, &disable);
+ if (disable & 0x02)
+ return;
+
+ pci_read_config_byte(dev, 0x8E, &write_enable);
+ pci_write_config_byte(dev, 0x8E, 0xAA);
+ pci_read_config_byte(dev, 0x8D, &write_target);
+ pci_write_config_byte(dev, 0x8D, 0xB7);
+ pci_write_config_byte(dev, 0xB7, disable | 0x02);
+ pci_write_config_byte(dev, 0x8E, write_enable);
+ pci_write_config_byte(dev, 0x8D, write_target);
+
+ dev_notice(&dev->dev, "proprietary Ricoh MMC controller disabled (via cardbus function)\n");
+ dev_notice(&dev->dev, "MMC cards are now supported by standard SDHCI controller\n");
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, ricoh_mmc_fixup_rl5c476);
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, ricoh_mmc_fixup_rl5c476);
+
+static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev)
+{
+ /* disable via firewire interface */
+ u8 write_enable;
+ u8 disable;
+
+ /* disable must be done via function #0 */
+ if (PCI_FUNC(dev->devfn))
+ return;
+
+ pci_read_config_byte(dev, 0xCB, &disable);
+
+ if (disable & 0x02)
+ return;
+
+ pci_read_config_byte(dev, 0xCA, &write_enable);
+ pci_write_config_byte(dev, 0xCA, 0x57);
+ pci_write_config_byte(dev, 0xCB, disable | 0x02);
+ pci_write_config_byte(dev, 0xCA, write_enable);
+
+ dev_notice(&dev->dev, "proprietary Ricoh MMC controller disabled (via firewire function)\n");
+ dev_notice(&dev->dev, "MMC cards are now supported by standard SDHCI controller\n");
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832);
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832);
+#endif /*CONFIG_MMC_RICOH_MMC*/
+
+
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
struct pci_fixup *end)
{
@@ -2595,6 +2693,7 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
}
pci_do_fixups(dev, start, end);
}
+EXPORT_SYMBOL(pci_fixup_device);
static int __init pci_apply_final_quirks(void)
{
@@ -2706,9 +2805,3 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe)
return -ENOTTY;
}
-
-#else
-void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {}
-int pci_dev_specific_reset(struct pci_dev *dev, int probe) { return -ENOTTY; }
-#endif
-EXPORT_SYMBOL(pci_fixup_device);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index c48cd377b3f5..4fe36d2e1049 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -27,37 +27,91 @@
#include <linux/slab.h>
#include "pci.h"
-static void pbus_assign_resources_sorted(const struct pci_bus *bus)
-{
- struct pci_dev *dev;
+struct resource_list_x {
+ struct resource_list_x *next;
struct resource *res;
- struct resource_list head, *list, *tmp;
- int idx;
+ struct pci_dev *dev;
+ resource_size_t start;
+ resource_size_t end;
+ unsigned long flags;
+};
- head.next = NULL;
- list_for_each_entry(dev, &bus->devices, bus_list) {
- u16 class = dev->class >> 8;
+static void add_to_failed_list(struct resource_list_x *head,
+ struct pci_dev *dev, struct resource *res)
+{
+ struct resource_list_x *list = head;
+ struct resource_list_x *ln = list->next;
+ struct resource_list_x *tmp;
- /* Don't touch classless devices or host bridges or ioapics. */
- if (class == PCI_CLASS_NOT_DEFINED ||
- class == PCI_CLASS_BRIDGE_HOST)
- continue;
+ tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp) {
+ pr_warning("add_to_failed_list: kmalloc() failed!\n");
+ return;
+ }
- /* Don't touch ioapic devices already enabled by firmware */
- if (class == PCI_CLASS_SYSTEM_PIC) {
- u16 command;
- pci_read_config_word(dev, PCI_COMMAND, &command);
- if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
- continue;
- }
+ tmp->next = ln;
+ tmp->res = res;
+ tmp->dev = dev;
+ tmp->start = res->start;
+ tmp->end = res->end;
+ tmp->flags = res->flags;
+ list->next = tmp;
+}
+
+static void free_failed_list(struct resource_list_x *head)
+{
+ struct resource_list_x *list, *tmp;
- pdev_sort_resources(dev, &head);
+ for (list = head->next; list;) {
+ tmp = list;
+ list = list->next;
+ kfree(tmp);
}
- for (list = head.next; list;) {
+ head->next = NULL;
+}
+
+static void __dev_sort_resources(struct pci_dev *dev,
+ struct resource_list *head)
+{
+ u16 class = dev->class >> 8;
+
+ /* Don't touch classless devices or host bridges or ioapics. */
+ if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST)
+ return;
+
+ /* Don't touch ioapic devices already enabled by firmware */
+ if (class == PCI_CLASS_SYSTEM_PIC) {
+ u16 command;
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
+ return;
+ }
+
+ pdev_sort_resources(dev, head);
+}
+
+static void __assign_resources_sorted(struct resource_list *head,
+ struct resource_list_x *fail_head)
+{
+ struct resource *res;
+ struct resource_list *list, *tmp;
+ int idx;
+
+ for (list = head->next; list;) {
res = list->res;
idx = res - &list->dev->resource[0];
+
if (pci_assign_resource(list->dev, idx)) {
+ if (fail_head && !pci_is_root_bus(list->dev->bus)) {
+ /*
+ * if the failed res is for ROM BAR, and it will
+ * be enabled later, don't add it to the list
+ */
+ if (!((idx == PCI_ROM_RESOURCE) &&
+ (!(res->flags & IORESOURCE_ROM_ENABLE))))
+ add_to_failed_list(fail_head, list->dev, res);
+ }
res->start = 0;
res->end = 0;
res->flags = 0;
@@ -68,6 +122,30 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus)
}
}
+static void pdev_assign_resources_sorted(struct pci_dev *dev,
+ struct resource_list_x *fail_head)
+{
+ struct resource_list head;
+
+ head.next = NULL;
+ __dev_sort_resources(dev, &head);
+ __assign_resources_sorted(&head, fail_head);
+
+}
+
+static void pbus_assign_resources_sorted(const struct pci_bus *bus,
+ struct resource_list_x *fail_head)
+{
+ struct pci_dev *dev;
+ struct resource_list head;
+
+ head.next = NULL;
+ list_for_each_entry(dev, &bus->devices, bus_list)
+ __dev_sort_resources(dev, &head);
+
+ __assign_resources_sorted(&head, fail_head);
+}
+
void pci_setup_cardbus(struct pci_bus *bus)
{
struct pci_dev *bridge = bus->self;
@@ -134,18 +212,12 @@ EXPORT_SYMBOL(pci_setup_cardbus);
config space writes, so it's quite possible that an I/O window of
the bridge will have some undesirable address (e.g. 0) after the
first write. Ditto 64-bit prefetchable MMIO. */
-static void pci_setup_bridge(struct pci_bus *bus)
+static void pci_setup_bridge_io(struct pci_bus *bus)
{
struct pci_dev *bridge = bus->self;
struct resource *res;
struct pci_bus_region region;
- u32 l, bu, lu, io_upper16;
-
- if (pci_is_enabled(bridge))
- return;
-
- dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n",
- bus->secondary, bus->subordinate);
+ u32 l, io_upper16;
/* Set up the top and bottom of the PCI I/O segment for this bus. */
res = bus->resource[0];
@@ -158,8 +230,7 @@ static void pci_setup_bridge(struct pci_bus *bus)
/* Set up upper 16 bits of I/O base/limit. */
io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
dev_info(&bridge->dev, " bridge window %pR\n", res);
- }
- else {
+ } else {
/* Clear upper 16 bits of I/O base/limit. */
io_upper16 = 0;
l = 0x00f0;
@@ -171,21 +242,35 @@ static void pci_setup_bridge(struct pci_bus *bus)
pci_write_config_dword(bridge, PCI_IO_BASE, l);
/* Update upper 16 bits of I/O base/limit. */
pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);
+}
+
+static void pci_setup_bridge_mmio(struct pci_bus *bus)
+{
+ struct pci_dev *bridge = bus->self;
+ struct resource *res;
+ struct pci_bus_region region;
+ u32 l;
- /* Set up the top and bottom of the PCI Memory segment
- for this bus. */
+ /* Set up the top and bottom of the PCI Memory segment for this bus. */
res = bus->resource[1];
pcibios_resource_to_bus(bridge, &region, res);
if (res->flags & IORESOURCE_MEM) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
dev_info(&bridge->dev, " bridge window %pR\n", res);
- }
- else {
+ } else {
l = 0x0000fff0;
dev_info(&bridge->dev, " bridge window [mem disabled]\n");
}
pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
+}
+
+static void pci_setup_bridge_mmio_pref(struct pci_bus *bus)
+{
+ struct pci_dev *bridge = bus->self;
+ struct resource *res;
+ struct pci_bus_region region;
+ u32 l, bu, lu;
/* Clear out the upper 32 bits of PREF limit.
If PCI_PREF_BASE_UPPER32 was non-zero, this temporarily
@@ -204,8 +289,7 @@ static void pci_setup_bridge(struct pci_bus *bus)
lu = upper_32_bits(region.end);
}
dev_info(&bridge->dev, " bridge window %pR\n", res);
- }
- else {
+ } else {
l = 0x0000fff0;
dev_info(&bridge->dev, " bridge window [mem pref disabled]\n");
}
@@ -214,10 +298,35 @@ static void pci_setup_bridge(struct pci_bus *bus)
/* Set the upper 32 bits of PREF base & limit. */
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
+}
+
+static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type)
+{
+ struct pci_dev *bridge = bus->self;
+
+ dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n",
+ bus->secondary, bus->subordinate);
+
+ if (type & IORESOURCE_IO)
+ pci_setup_bridge_io(bus);
+
+ if (type & IORESOURCE_MEM)
+ pci_setup_bridge_mmio(bus);
+
+ if (type & IORESOURCE_PREFETCH)
+ pci_setup_bridge_mmio_pref(bus);
pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
}
+static void pci_setup_bridge(struct pci_bus *bus)
+{
+ unsigned long type = IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_PREFETCH;
+
+ __pci_setup_bridge(bus, type);
+}
+
/* Check whether the bridge supports optional I/O and
prefetchable memory ranges. If not, the respective
base/limit registers must be read-only and read as 0. */
@@ -253,8 +362,11 @@ static void pci_bridge_check_ranges(struct pci_bus *bus)
}
if (pmem) {
b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
- if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64)
+ if ((pmem & PCI_PREF_RANGE_TYPE_MASK) ==
+ PCI_PREF_RANGE_TYPE_64) {
b_res[2].flags |= IORESOURCE_MEM_64;
+ b_res[2].flags |= PCI_PREF_RANGE_TYPE_64;
+ }
}
/* double check if bridge does support 64 bit pref */
@@ -283,8 +395,7 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned lon
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
IORESOURCE_PREFETCH;
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- r = bus->resource[i];
+ pci_bus_for_each_resource(bus, r, i) {
if (r == &ioport_resource || r == &iomem_resource)
continue;
if (r && (r->flags & type_mask) == type && !r->parent)
@@ -301,7 +412,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size)
{
struct pci_dev *dev;
struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
- unsigned long size = 0, size1 = 0;
+ unsigned long size = 0, size1 = 0, old_size;
if (!b_res)
return;
@@ -326,12 +437,17 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size)
}
if (size < min_size)
size = min_size;
+ old_size = resource_size(b_res);
+ if (old_size == 1)
+ old_size = 0;
/* To be fixed in 2.5: we should have sort of HAVE_ISA
flag in the struct pci_bus. */
#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
size = (size & 0xff) + ((size & ~0xffUL) << 2);
#endif
size = ALIGN(size + size1, 4096);
+ if (size < old_size)
+ size = old_size;
if (!size) {
if (b_res->start || b_res->end)
dev_info(&bus->self->dev, "disabling bridge window "
@@ -352,7 +468,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
unsigned long type, resource_size_t min_size)
{
struct pci_dev *dev;
- resource_size_t min_align, align, size;
+ resource_size_t min_align, align, size, old_size;
resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */
int order, max_order;
struct resource *b_res = find_free_bus_resource(bus, type);
@@ -402,6 +518,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
}
if (size < min_size)
size = min_size;
+ old_size = resource_size(b_res);
+ if (old_size == 1)
+ old_size = 0;
+ if (size < old_size)
+ size = old_size;
align = 0;
min_align = 0;
@@ -538,23 +659,25 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
}
EXPORT_SYMBOL(pci_bus_size_bridges);
-void __ref pci_bus_assign_resources(const struct pci_bus *bus)
+static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
+ struct resource_list_x *fail_head)
{
struct pci_bus *b;
struct pci_dev *dev;
- pbus_assign_resources_sorted(bus);
+ pbus_assign_resources_sorted(bus, fail_head);
list_for_each_entry(dev, &bus->devices, bus_list) {
b = dev->subordinate;
if (!b)
continue;
- pci_bus_assign_resources(b);
+ __pci_bus_assign_resources(b, fail_head);
switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
- pci_setup_bridge(b);
+ if (!pci_is_enabled(dev))
+ pci_setup_bridge(b);
break;
case PCI_CLASS_BRIDGE_CARDBUS:
@@ -568,15 +691,130 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus)
}
}
}
+
+void __ref pci_bus_assign_resources(const struct pci_bus *bus)
+{
+ __pci_bus_assign_resources(bus, NULL);
+}
EXPORT_SYMBOL(pci_bus_assign_resources);
+static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,
+ struct resource_list_x *fail_head)
+{
+ struct pci_bus *b;
+
+ pdev_assign_resources_sorted((struct pci_dev *)bridge, fail_head);
+
+ b = bridge->subordinate;
+ if (!b)
+ return;
+
+ __pci_bus_assign_resources(b, fail_head);
+
+ switch (bridge->class >> 8) {
+ case PCI_CLASS_BRIDGE_PCI:
+ pci_setup_bridge(b);
+ break;
+
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ pci_setup_cardbus(b);
+ break;
+
+ default:
+ dev_info(&bridge->dev, "not setting up bridge for bus "
+ "%04x:%02x\n", pci_domain_nr(b), b->number);
+ break;
+ }
+}
+static void pci_bridge_release_resources(struct pci_bus *bus,
+ unsigned long type)
+{
+ int idx;
+ bool changed = false;
+ struct pci_dev *dev;
+ struct resource *r;
+ unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_PREFETCH;
+
+ dev = bus->self;
+ for (idx = PCI_BRIDGE_RESOURCES; idx <= PCI_BRIDGE_RESOURCE_END;
+ idx++) {
+ r = &dev->resource[idx];
+ if ((r->flags & type_mask) != type)
+ continue;
+ if (!r->parent)
+ continue;
+ /*
+ * if there are children under that, we should release them
+ * all
+ */
+ release_child_resources(r);
+ if (!release_resource(r)) {
+ dev_printk(KERN_DEBUG, &dev->dev,
+ "resource %d %pR released\n", idx, r);
+ /* keep the old size */
+ r->end = resource_size(r) - 1;
+ r->start = 0;
+ r->flags = 0;
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ /* avoiding touch the one without PREF */
+ if (type & IORESOURCE_PREFETCH)
+ type = IORESOURCE_PREFETCH;
+ __pci_setup_bridge(bus, type);
+ }
+}
+
+enum release_type {
+ leaf_only,
+ whole_subtree,
+};
+/*
+ * try to release pci bridge resources that is from leaf bridge,
+ * so we can allocate big new one later
+ */
+static void __ref pci_bus_release_bridge_resources(struct pci_bus *bus,
+ unsigned long type,
+ enum release_type rel_type)
+{
+ struct pci_dev *dev;
+ bool is_leaf_bridge = true;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ struct pci_bus *b = dev->subordinate;
+ if (!b)
+ continue;
+
+ is_leaf_bridge = false;
+
+ if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+ continue;
+
+ if (rel_type == whole_subtree)
+ pci_bus_release_bridge_resources(b, type,
+ whole_subtree);
+ }
+
+ if (pci_is_root_bus(bus))
+ return;
+
+ if ((bus->self->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+ return;
+
+ if ((rel_type == whole_subtree) || is_leaf_bridge)
+ pci_bridge_release_resources(bus, type);
+}
+
static void pci_bus_dump_res(struct pci_bus *bus)
{
- int i;
+ struct resource *res;
+ int i;
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- struct resource *res = bus->resource[i];
- if (!res || !res->end)
+ pci_bus_for_each_resource(bus, res, i) {
+ if (!res || !res->end || !res->flags)
continue;
dev_printk(KERN_DEBUG, &bus->dev, "resource %d %pR\n", i, res);
@@ -600,11 +838,65 @@ static void pci_bus_dump_resources(struct pci_bus *bus)
}
}
+static int __init pci_bus_get_depth(struct pci_bus *bus)
+{
+ int depth = 0;
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ int ret;
+ struct pci_bus *b = dev->subordinate;
+ if (!b)
+ continue;
+
+ ret = pci_bus_get_depth(b);
+ if (ret + 1 > depth)
+ depth = ret + 1;
+ }
+
+ return depth;
+}
+static int __init pci_get_max_depth(void)
+{
+ int depth = 0;
+ struct pci_bus *bus;
+
+ list_for_each_entry(bus, &pci_root_buses, node) {
+ int ret;
+
+ ret = pci_bus_get_depth(bus);
+ if (ret > depth)
+ depth = ret;
+ }
+
+ return depth;
+}
+
+/*
+ * first try will not touch pci bridge res
+ * second and later try will clear small leaf bridge res
+ * will stop till to the max deepth if can not find good one
+ */
void __init
pci_assign_unassigned_resources(void)
{
struct pci_bus *bus;
+ int tried_times = 0;
+ enum release_type rel_type = leaf_only;
+ struct resource_list_x head, *list;
+ unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_PREFETCH;
+ unsigned long failed_type;
+ int max_depth = pci_get_max_depth();
+ int pci_try_num;
+
+ head.next = NULL;
+
+ pci_try_num = max_depth + 1;
+ printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
+ max_depth, pci_try_num);
+again:
/* Depth first, calculate sizes and alignments of all
subordinate buses. */
list_for_each_entry(bus, &pci_root_buses, node) {
@@ -612,12 +904,130 @@ pci_assign_unassigned_resources(void)
}
/* Depth last, allocate resources and update the hardware. */
list_for_each_entry(bus, &pci_root_buses, node) {
- pci_bus_assign_resources(bus);
- pci_enable_bridges(bus);
+ __pci_bus_assign_resources(bus, &head);
}
+ tried_times++;
+
+ /* any device complain? */
+ if (!head.next)
+ goto enable_and_dump;
+ failed_type = 0;
+ for (list = head.next; list;) {
+ failed_type |= list->flags;
+ list = list->next;
+ }
+ /*
+ * io port are tight, don't try extra
+ * or if reach the limit, don't want to try more
+ */
+ failed_type &= type_mask;
+ if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) {
+ free_failed_list(&head);
+ goto enable_and_dump;
+ }
+
+ printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n",
+ tried_times + 1);
+
+ /* third times and later will not check if it is leaf */
+ if ((tried_times + 1) > 2)
+ rel_type = whole_subtree;
+
+ /*
+ * Try to release leaf bridge's resources that doesn't fit resource of
+ * child device under that bridge
+ */
+ for (list = head.next; list;) {
+ bus = list->dev->bus;
+ pci_bus_release_bridge_resources(bus, list->flags & type_mask,
+ rel_type);
+ list = list->next;
+ }
+ /* restore size and flags */
+ for (list = head.next; list;) {
+ struct resource *res = list->res;
+
+ res->start = list->start;
+ res->end = list->end;
+ res->flags = list->flags;
+ if (list->dev->subordinate)
+ res->flags = 0;
+
+ list = list->next;
+ }
+ free_failed_list(&head);
+
+ goto again;
+
+enable_and_dump:
+ /* Depth last, update the hardware. */
+ list_for_each_entry(bus, &pci_root_buses, node)
+ pci_enable_bridges(bus);
/* dump the resource on buses */
list_for_each_entry(bus, &pci_root_buses, node) {
pci_bus_dump_resources(bus);
}
}
+
+void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
+{
+ struct pci_bus *parent = bridge->subordinate;
+ int tried_times = 0;
+ struct resource_list_x head, *list;
+ int retval;
+ unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_PREFETCH;
+
+ head.next = NULL;
+
+again:
+ pci_bus_size_bridges(parent);
+ __pci_bridge_assign_resources(bridge, &head);
+ retval = pci_reenable_device(bridge);
+ pci_set_master(bridge);
+ pci_enable_bridges(parent);
+
+ tried_times++;
+
+ if (!head.next)
+ return;
+
+ if (tried_times >= 2) {
+ /* still fail, don't need to try more */
+ free_failed_list(&head);
+ return;
+ }
+
+ printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n",
+ tried_times + 1);
+
+ /*
+ * Try to release leaf bridge's resources that doesn't fit resource of
+ * child device under that bridge
+ */
+ for (list = head.next; list;) {
+ struct pci_bus *bus = list->dev->bus;
+ unsigned long flags = list->flags;
+
+ pci_bus_release_bridge_resources(bus, flags & type_mask,
+ whole_subtree);
+ list = list->next;
+ }
+ /* restore size and flags */
+ for (list = head.next; list;) {
+ struct resource *res = list->res;
+
+ res->start = list->start;
+ res->end = list->end;
+ res->flags = list->flags;
+ if (list->dev->subordinate)
+ res->flags = 0;
+
+ list = list->next;
+ }
+ free_failed_list(&head);
+
+ goto again;
+}
+EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index 8c02b6c53bdb..f75a44d37fbe 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -29,7 +29,7 @@ static ssize_t pci_slot_attr_store(struct kobject *kobj,
return attribute->store ? attribute->store(slot, buf, len) : -EIO;
}
-static struct sysfs_ops pci_slot_sysfs_ops = {
+static const struct sysfs_ops pci_slot_sysfs_ops = {
.show = pci_slot_attr_show,
.store = pci_slot_attr_store,
};
@@ -47,6 +47,55 @@ static ssize_t address_read_file(struct pci_slot *slot, char *buf)
slot->number);
}
+/* these strings match up with the values in pci_bus_speed */
+static char *pci_bus_speed_strings[] = {
+ "33 MHz PCI", /* 0x00 */
+ "66 MHz PCI", /* 0x01 */
+ "66 MHz PCI-X", /* 0x02 */
+ "100 MHz PCI-X", /* 0x03 */
+ "133 MHz PCI-X", /* 0x04 */
+ NULL, /* 0x05 */
+ NULL, /* 0x06 */
+ NULL, /* 0x07 */
+ NULL, /* 0x08 */
+ "66 MHz PCI-X 266", /* 0x09 */
+ "100 MHz PCI-X 266", /* 0x0a */
+ "133 MHz PCI-X 266", /* 0x0b */
+ "Unknown AGP", /* 0x0c */
+ "1x AGP", /* 0x0d */
+ "2x AGP", /* 0x0e */
+ "4x AGP", /* 0x0f */
+ "8x AGP", /* 0x10 */
+ "66 MHz PCI-X 533", /* 0x11 */
+ "100 MHz PCI-X 533", /* 0x12 */
+ "133 MHz PCI-X 533", /* 0x13 */
+ "2.5 GT/s PCIe", /* 0x14 */
+ "5.0 GT/s PCIe", /* 0x15 */
+ "8.0 GT/s PCIe", /* 0x16 */
+};
+
+static ssize_t bus_speed_read(enum pci_bus_speed speed, char *buf)
+{
+ const char *speed_string;
+
+ if (speed < ARRAY_SIZE(pci_bus_speed_strings))
+ speed_string = pci_bus_speed_strings[speed];
+ else
+ speed_string = "Unknown";
+
+ return sprintf(buf, "%s\n", speed_string);
+}
+
+static ssize_t max_speed_read_file(struct pci_slot *slot, char *buf)
+{
+ return bus_speed_read(slot->bus->max_bus_speed, buf);
+}
+
+static ssize_t cur_speed_read_file(struct pci_slot *slot, char *buf)
+{
+ return bus_speed_read(slot->bus->cur_bus_speed, buf);
+}
+
static void pci_slot_release(struct kobject *kobj)
{
struct pci_dev *dev;
@@ -66,9 +115,15 @@ static void pci_slot_release(struct kobject *kobj)
static struct pci_slot_attribute pci_slot_attr_address =
__ATTR(address, (S_IFREG | S_IRUGO), address_read_file, NULL);
+static struct pci_slot_attribute pci_slot_attr_max_speed =
+ __ATTR(max_bus_speed, (S_IFREG | S_IRUGO), max_speed_read_file, NULL);
+static struct pci_slot_attribute pci_slot_attr_cur_speed =
+ __ATTR(cur_bus_speed, (S_IFREG | S_IRUGO), cur_speed_read_file, NULL);
static struct attribute *pci_slot_default_attrs[] = {
&pci_slot_attr_address.attr,
+ &pci_slot_attr_max_speed.attr,
+ &pci_slot_attr_cur_speed.attr,
NULL,
};
diff --git a/drivers/pci/vpd.c b/drivers/pci/vpd.c
new file mode 100644
index 000000000000..a5a5ca17cfe6
--- /dev/null
+++ b/drivers/pci/vpd.c
@@ -0,0 +1,61 @@
+/*
+ * File: vpd.c
+ * Purpose: Provide PCI VPD support
+ *
+ * Copyright (C) 2010 Broadcom Corporation.
+ */
+
+#include <linux/pci.h>
+
+int pci_vpd_find_tag(const u8 *buf, unsigned int off, unsigned int len, u8 rdt)
+{
+ int i;
+
+ for (i = off; i < len; ) {
+ u8 val = buf[i];
+
+ if (val & PCI_VPD_LRDT) {
+ /* Don't return success of the tag isn't complete */
+ if (i + PCI_VPD_LRDT_TAG_SIZE > len)
+ break;
+
+ if (val == rdt)
+ return i;
+
+ i += PCI_VPD_LRDT_TAG_SIZE +
+ pci_vpd_lrdt_size(&buf[i]);
+ } else {
+ u8 tag = val & ~PCI_VPD_SRDT_LEN_MASK;
+
+ if (tag == rdt)
+ return i;
+
+ if (tag == PCI_VPD_SRDT_END)
+ break;
+
+ i += PCI_VPD_SRDT_TAG_SIZE +
+ pci_vpd_srdt_size(&buf[i]);
+ }
+ }
+
+ return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(pci_vpd_find_tag);
+
+int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off,
+ unsigned int len, const char *kw)
+{
+ int i;
+
+ for (i = off; i + PCI_VPD_INFO_FLD_HDR_SIZE <= off + len;) {
+ if (buf[i + 0] == kw[0] &&
+ buf[i + 1] == kw[1])
+ return i;
+
+ i += PCI_VPD_INFO_FLD_HDR_SIZE +
+ pci_vpd_info_field_size(&buf[i]);
+ }
+
+ return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(pci_vpd_find_info_keyword);
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 9f3adbd9f700..d189e4743e69 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -51,17 +51,23 @@ config PCMCIA_LOAD_CIS
config PCMCIA_IOCTL
bool "PCMCIA control ioctl (obsolete)"
- depends on PCMCIA
+ depends on PCMCIA && ARM && !SMP && !PREEMPT
default y
help
If you say Y here, the deprecated ioctl interface to the PCMCIA
- subsystem will be built. It is needed by cardmgr and cardctl
- (pcmcia-cs) to function properly.
+ subsystem will be built. It is needed by the deprecated pcmcia-cs
+ tools (cardmgr, cardctl) to function properly.
You should use the new pcmciautils package instead (see
<file:Documentation/Changes> for location and details).
- If unsure, say Y.
+ This config option will most likely be removed from kernel 2.6.35,
+ the associated code from kernel 2.6.36.
+
+ As the PCMCIA ioctl is not locking safe, it depends on !SMP and
+ !PREEMPT.
+
+ If unsure, say N.
config CARDBUS
bool "32-bit CardBus support"
@@ -84,7 +90,7 @@ config YENTA
tristate "CardBus yenta-compatible bridge support"
depends on PCI
select CARDBUS if !EMBEDDED
- select PCCARD_NONSTATIC
+ select PCCARD_NONSTATIC if PCMCIA != n
---help---
This option enables support for CardBus host bridges. Virtually
all modern PCMCIA bridges are CardBus compatible. A "bridge" is
@@ -161,9 +167,8 @@ config TCIC
config PCMCIA_M8XX
tristate "MPC8xx PCMCIA support"
- depends on PCMCIA && PPC && 8xx
- select PCCARD_IODYN
- select PCCARD_NONSTATIC
+ depends on PCCARD && PPC && 8xx
+ select PCCARD_IODYN if PCMCIA != n
help
Say Y here to include support for PowerPC 8xx series PCMCIA
controller.
@@ -174,6 +179,27 @@ config PCMCIA_AU1X00
tristate "Au1x00 pcmcia support"
depends on SOC_AU1X00 && PCMCIA
+config PCMCIA_ALCHEMY_DEVBOARD
+ tristate "Alchemy Db/Pb1xxx PCMCIA socket services"
+ depends on SOC_AU1X00 && PCMCIA
+ select 64BIT_PHYS_ADDR
+ help
+ Enable this driver of you want PCMCIA support on your Alchemy
+ Db1000, Db/Pb1100, Db/Pb1500, Db/Pb1550, Db/Pb1200 board.
+ NOT suitable for the PB1000!
+
+ This driver is also available as a module called db1xxx_ss.ko
+
+config PCMCIA_XXS1500
+ tristate "MyCable XXS1500 PCMCIA socket support"
+ depends on PCMCIA && MIPS_XXS1500
+ select 64BIT_PHYS_ADDR
+ help
+ Support for the PCMCIA/CF socket interface on MyCable XXS1500
+ systems.
+
+ This driver is also available as a module called xxs1500_ss.ko
+
config PCMCIA_BCM63XX
tristate "bcm63xx pcmcia support"
depends on BCM63XX && PCMCIA
@@ -238,14 +264,12 @@ config PCMCIA_PROBE
config M32R_PCC
bool "M32R PCMCIA I/F"
depends on M32R && CHIP_M32700 && PCMCIA
- select PCCARD_NONSTATIC
help
Say Y here to use the M32R PCMCIA controller.
config M32R_CFC
bool "M32R CF I/F Controller"
depends on M32R && (PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_MAPPI3 || PLAT_OPSPUT)
- select PCCARD_NONSTATIC
help
Say Y here to use the M32R CompactFlash controller.
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 83ff802de544..381b031d9d75 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -2,11 +2,11 @@
# Makefile for the kernel pcmcia subsystem (c/o David Hinds)
#
-pcmcia_core-y += cs.o cistpl.o rsrc_mgr.o socket_sysfs.o
+pcmcia_core-y += cs.o rsrc_mgr.o socket_sysfs.o
pcmcia_core-$(CONFIG_CARDBUS) += cardbus.o
obj-$(CONFIG_PCCARD) += pcmcia_core.o
-pcmcia-y += ds.o pcmcia_resource.o
+pcmcia-y += ds.o pcmcia_resource.o cistpl.o
pcmcia-$(CONFIG_PCMCIA_IOCTL) += pcmcia_ioctl.o
obj-$(CONFIG_PCMCIA) += pcmcia.o
@@ -35,18 +35,10 @@ obj-$(CONFIG_OMAP_CF) += omap_cf.o
obj-$(CONFIG_BFIN_CFPCMCIA) += bfin_cf_pcmcia.o
obj-$(CONFIG_AT91_CF) += at91_cf.o
obj-$(CONFIG_ELECTRA_CF) += electra_cf.o
+obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD) += db1xxx_ss.o
au1x00_ss-y += au1000_generic.o
au1x00_ss-$(CONFIG_MIPS_PB1000) += au1000_pb1x00.o
-au1x00_ss-$(CONFIG_MIPS_PB1100) += au1000_pb1x00.o
-au1x00_ss-$(CONFIG_MIPS_PB1200) += au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_PB1500) += au1000_pb1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1000) += au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1100) += au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1200) += au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1500) += au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1550) += au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_XXS1500) += au1000_xxs1500.o
sa1111_cs-y += sa1111_generic.o
sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o
@@ -76,3 +68,5 @@ pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o
pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o
obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y)
+
+obj-$(CONFIG_PCMCIA_XXS1500) += xxs1500_ss.o
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index e1dccedc5960..5d228071ec69 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -52,8 +52,6 @@ struct at91_cf_socket {
unsigned long phys_baseaddr;
};
-#define SZ_2K (2 * SZ_1K)
-
static inline int at91_cf_present(struct at91_cf_socket *cf)
{
return !gpio_get_value(cf->board->det_pin);
diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c
deleted file mode 100644
index c78d77fd7e3b..000000000000
--- a/drivers/pcmcia/au1000_db1x00.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- *
- * Alchemy Semi Db1x00 boards specific pcmcia routines.
- *
- * Copyright 2002 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * Copyright 2004 Pete Popov, updated the driver to 2.6.
- * Followed the sa11xx API and largely copied many of the hardware
- * independent functions.
- *
- * ########################################################################
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/init.h>
-
-#include <asm/irq.h>
-#include <asm/signal.h>
-#include <asm/mach-au1x00/au1000.h>
-
-#if defined(CONFIG_MIPS_DB1200)
- #include <db1200.h>
-#elif defined(CONFIG_MIPS_PB1200)
- #include <pb1200.h>
-#else
- #include <asm/mach-db1x00/db1x00.h>
- static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-#endif
-
-#include "au1000_generic.h"
-
-#if 0
-#define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args)
-#else
-#define debug(x,args...)
-#endif
-
-
-struct au1000_pcmcia_socket au1000_pcmcia_socket[PCMCIA_NUM_SOCKS];
-extern int au1x00_pcmcia_socket_probe(struct device *, struct pcmcia_low_level *, int, int);
-
-static int db1x00_pcmcia_hw_init(struct au1000_pcmcia_socket *skt)
-{
-#ifdef CONFIG_MIPS_DB1550
- skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_3;
-#elif defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200)
- skt->irq = skt->nr ? BOARD_PC1_INT : BOARD_PC0_INT;
-#else
- skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_2;
-#endif
- return 0;
-}
-
-static void db1x00_pcmcia_shutdown(struct au1000_pcmcia_socket *skt)
-{
- bcsr->pcmcia = 0; /* turn off power */
- au_sync_delay(2);
-}
-
-static void
-db1x00_pcmcia_socket_state(struct au1000_pcmcia_socket *skt, struct pcmcia_state *state)
-{
- u32 inserted;
- unsigned char vs;
-
- state->ready = 0;
- state->vs_Xv = 0;
- state->vs_3v = 0;
- state->detect = 0;
-
- switch (skt->nr) {
- case 0:
- vs = bcsr->status & 0x3;
-#if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200)
- inserted = BOARD_CARD_INSERTED(0);
-#else
- inserted = !(bcsr->status & (1<<4));
-#endif
- break;
- case 1:
- vs = (bcsr->status & 0xC)>>2;
-#if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200)
- inserted = BOARD_CARD_INSERTED(1);
-#else
- inserted = !(bcsr->status & (1<<5));
-#endif
- break;
- default:/* should never happen */
- return;
- }
-
- if (inserted)
- debug("db1x00 socket %d: inserted %d, vs %d pcmcia %x\n",
- skt->nr, inserted, vs, bcsr->pcmcia);
-
- if (inserted) {
- switch (vs) {
- case 0:
- case 2:
- state->vs_3v=1;
- break;
- case 3: /* 5V */
- break;
- default:
- /* return without setting 'detect' */
- printk(KERN_ERR "db1x00 bad VS (%d)\n",
- vs);
- }
- state->detect = 1;
- state->ready = 1;
- }
- else {
- /* if the card was previously inserted and then ejected,
- * we should turn off power to it
- */
- if ((skt->nr == 0) && (bcsr->pcmcia & BCSR_PCMCIA_PC0RST)) {
- bcsr->pcmcia &= ~(BCSR_PCMCIA_PC0RST |
- BCSR_PCMCIA_PC0DRVEN |
- BCSR_PCMCIA_PC0VPP |
- BCSR_PCMCIA_PC0VCC);
- au_sync_delay(10);
- }
- else if ((skt->nr == 1) && bcsr->pcmcia & BCSR_PCMCIA_PC1RST) {
- bcsr->pcmcia &= ~(BCSR_PCMCIA_PC1RST |
- BCSR_PCMCIA_PC1DRVEN |
- BCSR_PCMCIA_PC1VPP |
- BCSR_PCMCIA_PC1VCC);
- au_sync_delay(10);
- }
- }
-
- state->bvd1=1;
- state->bvd2=1;
- state->wrprot=0;
-}
-
-static int
-db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_state_t *state)
-{
- u16 pwr;
- int sock = skt->nr;
-
- debug("config_skt %d Vcc %dV Vpp %dV, reset %d\n",
- sock, state->Vcc, state->Vpp,
- state->flags & SS_RESET);
-
- /* pcmcia reg was set to zero at init time. Be careful when
- * initializing a socket not to wipe out the settings of the
- * other socket.
- */
- pwr = bcsr->pcmcia;
- pwr &= ~(0xf << sock*8); /* clear voltage settings */
-
- state->Vpp = 0;
- switch(state->Vcc){
- case 0: /* Vcc 0 */
- pwr |= SET_VCC_VPP(0,0,sock);
- break;
- case 50: /* Vcc 5V */
- switch(state->Vpp) {
- case 0:
- pwr |= SET_VCC_VPP(2,0,sock);
- break;
- case 50:
- pwr |= SET_VCC_VPP(2,1,sock);
- break;
- case 12:
- pwr |= SET_VCC_VPP(2,2,sock);
- break;
- case 33:
- default:
- pwr |= SET_VCC_VPP(0,0,sock);
- printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __func__,
- state->Vcc,
- state->Vpp);
- break;
- }
- break;
- case 33: /* Vcc 3.3V */
- switch(state->Vpp) {
- case 0:
- pwr |= SET_VCC_VPP(1,0,sock);
- break;
- case 12:
- pwr |= SET_VCC_VPP(1,2,sock);
- break;
- case 33:
- pwr |= SET_VCC_VPP(1,1,sock);
- break;
- case 50:
- default:
- pwr |= SET_VCC_VPP(0,0,sock);
- printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __func__,
- state->Vcc,
- state->Vpp);
- break;
- }
- break;
- default: /* what's this ? */
- pwr |= SET_VCC_VPP(0,0,sock);
- printk(KERN_ERR "%s: bad Vcc %d\n",
- __func__, state->Vcc);
- break;
- }
-
- bcsr->pcmcia = pwr;
- au_sync_delay(300);
-
- if (sock == 0) {
- if (!(state->flags & SS_RESET)) {
- pwr |= BCSR_PCMCIA_PC0DRVEN;
- bcsr->pcmcia = pwr;
- au_sync_delay(300);
- pwr |= BCSR_PCMCIA_PC0RST;
- bcsr->pcmcia = pwr;
- au_sync_delay(100);
- }
- else {
- pwr &= ~(BCSR_PCMCIA_PC0RST | BCSR_PCMCIA_PC0DRVEN);
- bcsr->pcmcia = pwr;
- au_sync_delay(100);
- }
- }
- else {
- if (!(state->flags & SS_RESET)) {
- pwr |= BCSR_PCMCIA_PC1DRVEN;
- bcsr->pcmcia = pwr;
- au_sync_delay(300);
- pwr |= BCSR_PCMCIA_PC1RST;
- bcsr->pcmcia = pwr;
- au_sync_delay(100);
- }
- else {
- pwr &= ~(BCSR_PCMCIA_PC1RST | BCSR_PCMCIA_PC1DRVEN);
- bcsr->pcmcia = pwr;
- au_sync_delay(100);
- }
- }
- return 0;
-}
-
-/*
- * Enable card status IRQs on (re-)initialisation. This can
- * be called at initialisation, power management event, or
- * pcmcia event.
- */
-void db1x00_socket_init(struct au1000_pcmcia_socket *skt)
-{
- /* nothing to do for now */
-}
-
-/*
- * Disable card status IRQs and PCMCIA bus on suspend.
- */
-void db1x00_socket_suspend(struct au1000_pcmcia_socket *skt)
-{
- /* nothing to do for now */
-}
-
-struct pcmcia_low_level db1x00_pcmcia_ops = {
- .owner = THIS_MODULE,
-
- .hw_init = db1x00_pcmcia_hw_init,
- .hw_shutdown = db1x00_pcmcia_shutdown,
-
- .socket_state = db1x00_pcmcia_socket_state,
- .configure_socket = db1x00_pcmcia_configure_socket,
-
- .socket_init = db1x00_socket_init,
- .socket_suspend = db1x00_socket_suspend
-};
-
-int au1x_board_init(struct device *dev)
-{
- int ret = -ENODEV;
- bcsr->pcmcia = 0; /* turn off power, if it's not already off */
- au_sync_delay(2);
- ret = au1x00_pcmcia_socket_probe(dev, &db1x00_pcmcia_ops, 0, 2);
- return ret;
-}
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
index 02088704ac2c..171c8a654887 100644
--- a/drivers/pcmcia/au1000_generic.c
+++ b/drivers/pcmcia/au1000_generic.c
@@ -405,18 +405,16 @@ int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops,
skt->virt_io = (void *)
(ioremap((phys_t)AU1X_SOCK0_IO, 0x1000) -
(u32)mips_io_port_base);
- skt->phys_attr = AU1X_SOCK0_PSEUDO_PHYS_ATTR;
- skt->phys_mem = AU1X_SOCK0_PSEUDO_PHYS_MEM;
+ skt->phys_attr = AU1X_SOCK0_PHYS_ATTR;
+ skt->phys_mem = AU1X_SOCK0_PHYS_MEM;
}
-#ifndef CONFIG_MIPS_XXS1500
else {
skt->virt_io = (void *)
(ioremap((phys_t)AU1X_SOCK1_IO, 0x1000) -
(u32)mips_io_port_base);
- skt->phys_attr = AU1X_SOCK1_PSEUDO_PHYS_ATTR;
- skt->phys_mem = AU1X_SOCK1_PSEUDO_PHYS_MEM;
+ skt->phys_attr = AU1X_SOCK1_PHYS_ATTR;
+ skt->phys_mem = AU1X_SOCK1_PHYS_MEM;
}
-#endif
pcmcia_base_vaddrs[i] = (u32 *)skt->virt_io;
ret = ops->hw_init(skt);
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h
index 13a4fbc58711..a324d329dea6 100644
--- a/drivers/pcmcia/au1000_generic.h
+++ b/drivers/pcmcia/au1000_generic.h
@@ -36,30 +36,14 @@
#define AU1X_SOCK0_IO 0xF00000000ULL
#define AU1X_SOCK0_PHYS_ATTR 0xF40000000ULL
#define AU1X_SOCK0_PHYS_MEM 0xF80000000ULL
-/* pseudo 32 bit phys addresses, which get fixed up to the
- * real 36 bit address in fixup_bigphys_addr() */
-#define AU1X_SOCK0_PSEUDO_PHYS_ATTR 0xF4000000
-#define AU1X_SOCK0_PSEUDO_PHYS_MEM 0xF8000000
/* pcmcia socket 1 needs external glue logic so the memory map
* differs from board to board.
*/
-#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || \
- defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) || \
- defined(CONFIG_MIPS_PB1200)
+#if defined(CONFIG_MIPS_PB1000)
#define AU1X_SOCK1_IO 0xF08000000ULL
#define AU1X_SOCK1_PHYS_ATTR 0xF48000000ULL
#define AU1X_SOCK1_PHYS_MEM 0xF88000000ULL
-#define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4800000
-#define AU1X_SOCK1_PSEUDO_PHYS_MEM 0xF8800000
-#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || \
- defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) || \
- defined(CONFIG_MIPS_DB1200)
-#define AU1X_SOCK1_IO 0xF04000000ULL
-#define AU1X_SOCK1_PHYS_ATTR 0xF44000000ULL
-#define AU1X_SOCK1_PHYS_MEM 0xF84000000ULL
-#define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4400000
-#define AU1X_SOCK1_PSEUDO_PHYS_MEM 0xF8400000
#endif
struct pcmcia_state {
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index b1984ed72d1d..5a979cb8f3e6 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -1,6 +1,6 @@
/*
*
- * Alchemy Semi Pb1x00 boards specific pcmcia routines.
+ * Alchemy Semi Pb1000 boards specific pcmcia routines.
*
* Copyright 2002 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
@@ -46,20 +46,11 @@
#define debug(fmt, arg...) do { } while (0)
-#ifdef CONFIG_MIPS_PB1000
#include <asm/pb1000.h>
#define PCMCIA_IRQ AU1000_GPIO_15
-#elif defined (CONFIG_MIPS_PB1500)
-#include <asm/pb1500.h>
-#define PCMCIA_IRQ AU1500_GPIO_203
-#elif defined (CONFIG_MIPS_PB1100)
-#include <asm/pb1100.h>
-#define PCMCIA_IRQ AU1000_GPIO_11
-#endif
static int pb1x00_pcmcia_init(struct pcmcia_init *init)
{
-#ifdef CONFIG_MIPS_PB1000
u16 pcr;
pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
@@ -74,21 +65,10 @@ static int pb1x00_pcmcia_init(struct pcmcia_init *init)
au_sync_delay(20);
return PCMCIA_NUM_SOCKS;
-
-#else /* fixme -- take care of the Pb1500 at some point */
-
- u16 pcr;
- pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf; /* turn off power */
- pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN);
- au_writew(pcr, PCMCIA_BOARD_REG);
- au_sync_delay(500);
- return PCMCIA_NUM_SOCKS;
-#endif
}
static int pb1x00_pcmcia_shutdown(void)
{
-#ifdef CONFIG_MIPS_PB1000
u16 pcr;
pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0);
@@ -96,14 +76,6 @@ static int pb1x00_pcmcia_shutdown(void)
au_writel(pcr, PB1000_PCR);
au_sync_delay(20);
return 0;
-#else
- u16 pcr;
- pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf; /* turn off power */
- pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN);
- au_writew(pcr, PCMCIA_BOARD_REG);
- au_sync_delay(2);
- return 0;
-#endif
}
static int
@@ -112,21 +84,11 @@ pb1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
u32 inserted0, inserted1;
u16 vs0, vs1;
-#ifdef CONFIG_MIPS_PB1000
vs0 = vs1 = (u16)au_readl(PB1000_ACR1);
inserted0 = !(vs0 & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2));
inserted1 = !(vs1 & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2));
vs0 = (vs0 >> 4) & 0x3;
vs1 = (vs1 >> 12) & 0x3;
-#else
- vs0 = (au_readw(BOARD_STATUS_REG) >> 4) & 0x3;
-#ifdef CONFIG_MIPS_PB1500
- inserted0 = !((au_readl(GPIO2_PINSTATE) >> 1) & 0x1); /* gpio 201 */
-#else /* Pb1100 */
- inserted0 = !((au_readl(SYS_PINSTATERD) >> 9) & 0x1); /* gpio 9 */
-#endif
- inserted1 = 0;
-#endif
state->ready = 0;
state->vs_Xv = 0;
@@ -203,7 +165,6 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
if(configure->sock > PCMCIA_MAX_SOCK) return -1;
-#ifdef CONFIG_MIPS_PB1000
pcr = au_readl(PB1000_PCR);
if (configure->sock == 0) {
@@ -323,84 +284,6 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
au_writel(pcr, PB1000_PCR);
au_sync_delay(300);
-#else
-
- pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf;
-
- debug("Vcc %dV Vpp %dV, pcr %x, reset %d\n",
- configure->vcc, configure->vpp, pcr, configure->reset);
-
-
- switch(configure->vcc){
- case 0: /* Vcc 0 */
- pcr |= SET_VCC_VPP(0,0);
- break;
- case 50: /* Vcc 5V */
- switch(configure->vpp) {
- case 0:
- pcr |= SET_VCC_VPP(2,0);
- break;
- case 50:
- pcr |= SET_VCC_VPP(2,1);
- break;
- case 12:
- pcr |= SET_VCC_VPP(2,2);
- break;
- case 33:
- default:
- pcr |= SET_VCC_VPP(0,0);
- printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __func__,
- configure->vcc,
- configure->vpp);
- break;
- }
- break;
- case 33: /* Vcc 3.3V */
- switch(configure->vpp) {
- case 0:
- pcr |= SET_VCC_VPP(1,0);
- break;
- case 12:
- pcr |= SET_VCC_VPP(1,2);
- break;
- case 33:
- pcr |= SET_VCC_VPP(1,1);
- break;
- case 50:
- default:
- pcr |= SET_VCC_VPP(0,0);
- printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __func__,
- configure->vcc,
- configure->vpp);
- break;
- }
- break;
- default: /* what's this ? */
- pcr |= SET_VCC_VPP(0,0);
- printk(KERN_ERR "%s: bad Vcc %d\n",
- __func__, configure->vcc);
- break;
- }
-
- au_writew(pcr, PCMCIA_BOARD_REG);
- au_sync_delay(300);
-
- if (!configure->reset) {
- pcr |= PC_DRV_EN;
- au_writew(pcr, PCMCIA_BOARD_REG);
- au_sync_delay(100);
- pcr |= PC_DEASSERT_RST;
- au_writew(pcr, PCMCIA_BOARD_REG);
- au_sync_delay(100);
- }
- else {
- pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN);
- au_writew(pcr, PCMCIA_BOARD_REG);
- au_sync_delay(100);
- }
-#endif
return 0;
}
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
deleted file mode 100644
index b43d47b50819..000000000000
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- *
- * MyCable board specific pcmcia routines.
- *
- * Copyright 2003 MontaVista Software Inc.
- * Author: Pete Popov, MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * ########################################################################
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- *
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/proc_fs.h>
-#include <linux/types.h>
-
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/ss.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/bus_ops.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include <asm/au1000.h>
-#include <asm/au1000_pcmcia.h>
-
-#define PCMCIA_MAX_SOCK 0
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-#define PCMCIA_IRQ AU1000_GPIO_4
-
-#if 0
-#define DEBUG(x, args...) printk(__func__ ": " x, ##args)
-#else
-#define DEBUG(x,args...)
-#endif
-
-static int xxs1500_pcmcia_init(struct pcmcia_init *init)
-{
- return PCMCIA_NUM_SOCKS;
-}
-
-static int xxs1500_pcmcia_shutdown(void)
-{
- /* turn off power */
- au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30),
- GPIO2_OUTPUT);
- au_sync_delay(100);
-
- /* assert reset */
- au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20),
- GPIO2_OUTPUT);
- au_sync_delay(100);
- return 0;
-}
-
-
-static int
-xxs1500_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
-{
- u32 inserted; u32 vs;
- unsigned long gpio, gpio2;
-
- if(sock > PCMCIA_MAX_SOCK) return -1;
-
- gpio = au_readl(SYS_PINSTATERD);
- gpio2 = au_readl(GPIO2_PINSTATE);
-
- vs = gpio2 & ((1<<8) | (1<<9));
- inserted = (!(gpio & 0x1) && !(gpio & 0x2));
-
- state->ready = 0;
- state->vs_Xv = 0;
- state->vs_3v = 0;
- state->detect = 0;
-
- if (inserted) {
- switch (vs) {
- case 0:
- case 1:
- case 2:
- state->vs_3v=1;
- break;
- case 3: /* 5V */
- default:
- /* return without setting 'detect' */
- printk(KERN_ERR "au1x00_cs: unsupported VS\n",
- vs);
- return;
- }
- state->detect = 1;
- }
-
- if (state->detect) {
- state->ready = 1;
- }
-
- state->bvd1= gpio2 & (1<<10);
- state->bvd2 = gpio2 & (1<<11);
- state->wrprot=0;
- return 1;
-}
-
-
-static int xxs1500_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
-{
-
- if(info->sock > PCMCIA_MAX_SOCK) return -1;
- info->irq = PCMCIA_IRQ;
- return 0;
-}
-
-
-static int
-xxs1500_pcmcia_configure_socket(const struct pcmcia_configure *configure)
-{
-
- if(configure->sock > PCMCIA_MAX_SOCK) return -1;
-
- DEBUG("Vcc %dV Vpp %dV, reset %d\n",
- configure->vcc, configure->vpp, configure->reset);
-
- switch(configure->vcc){
- case 33: /* Vcc 3.3V */
- /* turn on power */
- DEBUG("turn on power\n");
- au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<14))|(1<<30),
- GPIO2_OUTPUT);
- au_sync_delay(100);
- break;
- case 50: /* Vcc 5V */
- default: /* what's this ? */
- printk(KERN_ERR "au1x00_cs: unsupported VCC\n");
- case 0: /* Vcc 0 */
- /* turn off power */
- au_sync_delay(100);
- au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30),
- GPIO2_OUTPUT);
- break;
- }
-
- if (!configure->reset) {
- DEBUG("deassert reset\n");
- au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<4))|(1<<20),
- GPIO2_OUTPUT);
- au_sync_delay(100);
- au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<5))|(1<<21),
- GPIO2_OUTPUT);
- }
- else {
- DEBUG("assert reset\n");
- au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20),
- GPIO2_OUTPUT);
- }
- au_sync_delay(100);
- return 0;
-}
-
-struct pcmcia_low_level xxs1500_pcmcia_ops = {
- xxs1500_pcmcia_init,
- xxs1500_pcmcia_shutdown,
- xxs1500_pcmcia_socket_state,
- xxs1500_pcmcia_get_irq_info,
- xxs1500_pcmcia_configure_socket
-};
diff --git a/drivers/pcmcia/bfin_cf_pcmcia.c b/drivers/pcmcia/bfin_cf_pcmcia.c
index 300b368605c9..2482ce7ac6dc 100644
--- a/drivers/pcmcia/bfin_cf_pcmcia.c
+++ b/drivers/pcmcia/bfin_cf_pcmcia.c
@@ -205,7 +205,7 @@ static int __devinit bfin_cf_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "Blackfin CompactFlash/PCMCIA Socket Driver\n");
irq = platform_get_irq(pdev, 0);
- if (!irq)
+ if (irq <= 0)
return -EINVAL;
cd_pfx = platform_get_irq(pdev, 1); /*Card Detect GPIO PIN */
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index d99f846451a3..e6ab2a47d8cb 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -20,170 +20,12 @@
*/
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <asm/irq.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include "cs_internal.h"
-
-/*====================================================================*/
-
-/* Offsets in the Expansion ROM Image Header */
-#define ROM_SIGNATURE 0x0000 /* 2 bytes */
-#define ROM_DATA_PTR 0x0018 /* 2 bytes */
-
-/* Offsets in the CardBus PC Card Data Structure */
-#define PCDATA_SIGNATURE 0x0000 /* 4 bytes */
-#define PCDATA_VPD_PTR 0x0008 /* 2 bytes */
-#define PCDATA_LENGTH 0x000a /* 2 bytes */
-#define PCDATA_REVISION 0x000c
-#define PCDATA_IMAGE_SZ 0x0010 /* 2 bytes */
-#define PCDATA_ROM_LEVEL 0x0012 /* 2 bytes */
-#define PCDATA_CODE_TYPE 0x0014
-#define PCDATA_INDICATOR 0x0015
-
-/*=====================================================================
-
- Expansion ROM's have a special layout, and pointers specify an
- image number and an offset within that image. xlate_rom_addr()
- converts an image/offset address to an absolute offset from the
- ROM's base address.
-
-=====================================================================*/
-
-static u_int xlate_rom_addr(void __iomem *b, u_int addr)
-{
- u_int img = 0, ofs = 0, sz;
- u_short data;
- while ((readb(b) == 0x55) && (readb(b + 1) == 0xaa)) {
- if (img == (addr >> 28))
- return (addr & 0x0fffffff) + ofs;
- data = readb(b + ROM_DATA_PTR) + (readb(b + ROM_DATA_PTR + 1) << 8);
- sz = 512 * (readb(b + data + PCDATA_IMAGE_SZ) +
- (readb(b + data + PCDATA_IMAGE_SZ + 1) << 8));
- if ((sz == 0) || (readb(b + data + PCDATA_INDICATOR) & 0x80))
- break;
- b += sz;
- ofs += sz;
- img++;
- }
- return 0;
-}
-
-/*=====================================================================
-
- These are similar to setup_cis_mem and release_cis_mem for 16-bit
- cards. The "result" that is used externally is the cb_cis_virt
- pointer in the struct pcmcia_socket structure.
-
-=====================================================================*/
-
-static void cb_release_cis_mem(struct pcmcia_socket *s)
-{
- if (s->cb_cis_virt) {
- dev_dbg(&s->dev, "cb_release_cis_mem()\n");
- iounmap(s->cb_cis_virt);
- s->cb_cis_virt = NULL;
- s->cb_cis_res = NULL;
- }
-}
-
-static int cb_setup_cis_mem(struct pcmcia_socket *s, struct resource *res)
-{
- unsigned int start, size;
-
- if (res == s->cb_cis_res)
- return 0;
-
- if (s->cb_cis_res)
- cb_release_cis_mem(s);
-
- start = res->start;
- size = res->end - start + 1;
- s->cb_cis_virt = ioremap(start, size);
-
- if (!s->cb_cis_virt)
- return -1;
-
- s->cb_cis_res = res;
-
- return 0;
-}
-
-/*=====================================================================
-
- This is used by the CIS processing code to read CIS information
- from a CardBus device.
-
-=====================================================================*/
-
-int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len,
- void *ptr)
-{
- struct pci_dev *dev;
- struct resource *res;
-
- dev_dbg(&s->dev, "read_cb_mem(%d, %#x, %u)\n", space, addr, len);
- dev = pci_get_slot(s->cb_dev->subordinate, 0);
- if (!dev)
- goto fail;
-
- /* Config space? */
- if (space == 0) {
- if (addr + len > 0x100)
- goto failput;
- for (; len; addr++, ptr++, len--)
- pci_read_config_byte(dev, addr, ptr);
- return 0;
- }
-
- res = dev->resource + space - 1;
-
- pci_dev_put(dev);
-
- if (!res->flags)
- goto fail;
-
- if (cb_setup_cis_mem(s, res) != 0)
- goto fail;
-
- if (space == 7) {
- addr = xlate_rom_addr(s->cb_cis_virt, addr);
- if (addr == 0)
- goto fail;
- }
-
- if (addr + len > res->end - res->start)
- goto fail;
-
- memcpy_fromio(ptr, s->cb_cis_virt + addr, len);
- return 0;
-
-failput:
- pci_dev_put(dev);
-fail:
- memset(ptr, 0xff, len);
- return -1;
-}
-
-/*=====================================================================
-
- cb_alloc() and cb_free() allocate and free the kernel data
- structures for a Cardbus device, and handle the lowest level PCI
- device setup issues.
-
-=====================================================================*/
static void cardbus_config_irq_and_cls(struct pci_bus *bus, int irq)
{
@@ -215,6 +57,13 @@ static void cardbus_config_irq_and_cls(struct pci_bus *bus, int irq)
}
}
+/**
+ * cb_alloc() - add CardBus device
+ * @s: the pcmcia_socket where the CardBus device is located
+ *
+ * cb_alloc() allocates the kernel data structures for a Cardbus device
+ * and handles the lowest level PCI device setup issues.
+ */
int __ref cb_alloc(struct pcmcia_socket *s)
{
struct pci_bus *bus = s->cb_dev->subordinate;
@@ -222,7 +71,7 @@ int __ref cb_alloc(struct pcmcia_socket *s)
unsigned int max, pass;
s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0));
- pci_fixup_cardbus(bus);
+ pci_fixup_cardbus(bus);
max = bus->secondary;
for (pass = 0; pass < 2; pass++)
@@ -249,12 +98,16 @@ int __ref cb_alloc(struct pcmcia_socket *s)
return 0;
}
+/**
+ * cb_free() - remove CardBus device
+ * @s: the pcmcia_socket where the CardBus device was located
+ *
+ * cb_free() handles the lowest level PCI device cleanup.
+ */
void cb_free(struct pcmcia_socket *s)
{
struct pci_dev *bridge = s->cb_dev;
- cb_release_cis_mem(s);
-
if (bridge)
pci_remove_behind_bridge(bridge);
}
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 25b1cd219e37..f230f6543bff 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -54,43 +54,44 @@ static const u_int exponent[] = {
/* Upper limit on reasonable # of tuples */
#define MAX_TUPLES 200
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
/* 16-bit CIS? */
static int cis_width;
module_param(cis_width, int, 0444);
void release_cis_mem(struct pcmcia_socket *s)
{
- if (s->cis_mem.flags & MAP_ACTIVE) {
- s->cis_mem.flags &= ~MAP_ACTIVE;
- s->ops->set_mem_map(s, &s->cis_mem);
- if (s->cis_mem.res) {
- release_resource(s->cis_mem.res);
- kfree(s->cis_mem.res);
- s->cis_mem.res = NULL;
+ mutex_lock(&s->ops_mutex);
+ if (s->cis_mem.flags & MAP_ACTIVE) {
+ s->cis_mem.flags &= ~MAP_ACTIVE;
+ s->ops->set_mem_map(s, &s->cis_mem);
+ if (s->cis_mem.res) {
+ release_resource(s->cis_mem.res);
+ kfree(s->cis_mem.res);
+ s->cis_mem.res = NULL;
+ }
+ iounmap(s->cis_virt);
+ s->cis_virt = NULL;
}
- iounmap(s->cis_virt);
- s->cis_virt = NULL;
- }
+ mutex_unlock(&s->ops_mutex);
}
-EXPORT_SYMBOL(release_cis_mem);
-/*
- * Map the card memory at "card_offset" into virtual space.
+/**
+ * set_cis_map() - map the card memory at "card_offset" into virtual space.
+ *
* If flags & MAP_ATTRIB, map the attribute space, otherwise
* map the memory space.
+ *
+ * Must be called with ops_mutex held.
*/
-static void __iomem *
-set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags)
+static void __iomem *set_cis_map(struct pcmcia_socket *s,
+ unsigned int card_offset, unsigned int flags)
{
pccard_mem_map *mem = &s->cis_mem;
int ret;
if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) {
- mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s);
+ mem->res = pcmcia_find_mem_region(0, s->map_size,
+ s->map_size, 0, s);
if (mem->res == NULL) {
dev_printk(KERN_NOTICE, &s->dev,
"cs: unable to map card memory!\n");
@@ -121,176 +122,200 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
return s->cis_virt;
}
-/*======================================================================
-
- Low-level functions to read and write CIS memory. I think the
- write routine is only useful for writing one-byte registers.
-
-======================================================================*/
/* Bits in attr field */
#define IS_ATTR 1
#define IS_INDIRECT 8
+/**
+ * pcmcia_read_cis_mem() - low-level function to read CIS memory
+ */
int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
u_int len, void *ptr)
{
- void __iomem *sys, *end;
- unsigned char *buf = ptr;
-
- dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
-
- if (attr & IS_INDIRECT) {
- /* Indirect accesses use a bunch of special registers at fixed
- locations in common memory */
- u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
- if (attr & IS_ATTR) {
- addr *= 2;
- flags = ICTRL0_AUTOINC;
- }
+ void __iomem *sys, *end;
+ unsigned char *buf = ptr;
+
+ dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+
+ mutex_lock(&s->ops_mutex);
+ if (attr & IS_INDIRECT) {
+ /* Indirect accesses use a bunch of special registers at fixed
+ locations in common memory */
+ u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
+ if (attr & IS_ATTR) {
+ addr *= 2;
+ flags = ICTRL0_AUTOINC;
+ }
- sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0));
- if (!sys) {
- memset(ptr, 0xff, len);
- return -1;
- }
+ sys = set_cis_map(s, 0, MAP_ACTIVE |
+ ((cis_width) ? MAP_16BIT : 0));
+ if (!sys) {
+ dev_dbg(&s->dev, "could not map memory\n");
+ memset(ptr, 0xff, len);
+ mutex_unlock(&s->ops_mutex);
+ return -1;
+ }
- writeb(flags, sys+CISREG_ICTRL0);
- writeb(addr & 0xff, sys+CISREG_IADDR0);
- writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
- writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
- writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
- for ( ; len > 0; len--, buf++)
- *buf = readb(sys+CISREG_IDATA0);
- } else {
- u_int inc = 1, card_offset, flags;
-
- flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
- if (attr) {
- flags |= MAP_ATTRIB;
- inc++;
- addr *= 2;
- }
+ writeb(flags, sys+CISREG_ICTRL0);
+ writeb(addr & 0xff, sys+CISREG_IADDR0);
+ writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
+ writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
+ writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
+ for ( ; len > 0; len--, buf++)
+ *buf = readb(sys+CISREG_IDATA0);
+ } else {
+ u_int inc = 1, card_offset, flags;
- card_offset = addr & ~(s->map_size-1);
- while (len) {
- sys = set_cis_map(s, card_offset, flags);
- if (!sys) {
- memset(ptr, 0xff, len);
- return -1;
- }
- end = sys + s->map_size;
- sys = sys + (addr & (s->map_size-1));
- for ( ; len > 0; len--, buf++, sys += inc) {
- if (sys == end)
- break;
- *buf = readb(sys);
- }
- card_offset += s->map_size;
- addr = 0;
+ if (addr > CISTPL_MAX_CIS_SIZE)
+ dev_dbg(&s->dev,
+ "attempt to read CIS mem at addr %#x", addr);
+
+ flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
+ if (attr) {
+ flags |= MAP_ATTRIB;
+ inc++;
+ addr *= 2;
+ }
+
+ card_offset = addr & ~(s->map_size-1);
+ while (len) {
+ sys = set_cis_map(s, card_offset, flags);
+ if (!sys) {
+ dev_dbg(&s->dev, "could not map memory\n");
+ memset(ptr, 0xff, len);
+ mutex_unlock(&s->ops_mutex);
+ return -1;
+ }
+ end = sys + s->map_size;
+ sys = sys + (addr & (s->map_size-1));
+ for ( ; len > 0; len--, buf++, sys += inc) {
+ if (sys == end)
+ break;
+ *buf = readb(sys);
+ }
+ card_offset += s->map_size;
+ addr = 0;
+ }
}
- }
- dev_dbg(&s->dev, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
- *(u_char *)(ptr+0), *(u_char *)(ptr+1),
- *(u_char *)(ptr+2), *(u_char *)(ptr+3));
- return 0;
+ mutex_unlock(&s->ops_mutex);
+ dev_dbg(&s->dev, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
+ *(u_char *)(ptr+0), *(u_char *)(ptr+1),
+ *(u_char *)(ptr+2), *(u_char *)(ptr+3));
+ return 0;
}
-EXPORT_SYMBOL(pcmcia_read_cis_mem);
+/**
+ * pcmcia_write_cis_mem() - low-level function to write CIS memory
+ *
+ * Probably only useful for writing one-byte registers.
+ */
void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
u_int len, void *ptr)
{
- void __iomem *sys, *end;
- unsigned char *buf = ptr;
-
- dev_dbg(&s->dev, "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
-
- if (attr & IS_INDIRECT) {
- /* Indirect accesses use a bunch of special registers at fixed
- locations in common memory */
- u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
- if (attr & IS_ATTR) {
- addr *= 2;
- flags = ICTRL0_AUTOINC;
- }
+ void __iomem *sys, *end;
+ unsigned char *buf = ptr;
+
+ dev_dbg(&s->dev,
+ "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+
+ mutex_lock(&s->ops_mutex);
+ if (attr & IS_INDIRECT) {
+ /* Indirect accesses use a bunch of special registers at fixed
+ locations in common memory */
+ u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
+ if (attr & IS_ATTR) {
+ addr *= 2;
+ flags = ICTRL0_AUTOINC;
+ }
- sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0));
- if (!sys)
- return; /* FIXME: Error */
-
- writeb(flags, sys+CISREG_ICTRL0);
- writeb(addr & 0xff, sys+CISREG_IADDR0);
- writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
- writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
- writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
- for ( ; len > 0; len--, buf++)
- writeb(*buf, sys+CISREG_IDATA0);
- } else {
- u_int inc = 1, card_offset, flags;
-
- flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
- if (attr & IS_ATTR) {
- flags |= MAP_ATTRIB;
- inc++;
- addr *= 2;
- }
+ sys = set_cis_map(s, 0, MAP_ACTIVE |
+ ((cis_width) ? MAP_16BIT : 0));
+ if (!sys) {
+ dev_dbg(&s->dev, "could not map memory\n");
+ mutex_unlock(&s->ops_mutex);
+ return; /* FIXME: Error */
+ }
+
+ writeb(flags, sys+CISREG_ICTRL0);
+ writeb(addr & 0xff, sys+CISREG_IADDR0);
+ writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
+ writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
+ writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
+ for ( ; len > 0; len--, buf++)
+ writeb(*buf, sys+CISREG_IDATA0);
+ } else {
+ u_int inc = 1, card_offset, flags;
+
+ flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
+ if (attr & IS_ATTR) {
+ flags |= MAP_ATTRIB;
+ inc++;
+ addr *= 2;
+ }
- card_offset = addr & ~(s->map_size-1);
- while (len) {
- sys = set_cis_map(s, card_offset, flags);
- if (!sys)
- return; /* FIXME: error */
-
- end = sys + s->map_size;
- sys = sys + (addr & (s->map_size-1));
- for ( ; len > 0; len--, buf++, sys += inc) {
- if (sys == end)
- break;
- writeb(*buf, sys);
- }
- card_offset += s->map_size;
- addr = 0;
+ card_offset = addr & ~(s->map_size-1);
+ while (len) {
+ sys = set_cis_map(s, card_offset, flags);
+ if (!sys) {
+ dev_dbg(&s->dev, "could not map memory\n");
+ mutex_unlock(&s->ops_mutex);
+ return; /* FIXME: error */
+ }
+
+ end = sys + s->map_size;
+ sys = sys + (addr & (s->map_size-1));
+ for ( ; len > 0; len--, buf++, sys += inc) {
+ if (sys == end)
+ break;
+ writeb(*buf, sys);
+ }
+ card_offset += s->map_size;
+ addr = 0;
+ }
}
- }
+ mutex_unlock(&s->ops_mutex);
}
-EXPORT_SYMBOL(pcmcia_write_cis_mem);
-/*======================================================================
+/**
+ * read_cis_cache() - read CIS memory or its associated cache
+ *
+ * This is a wrapper around read_cis_mem, with the same interface,
+ * but which caches information, for cards whose CIS may not be
+ * readable all the time.
+ */
+static int read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
+ size_t len, void *ptr)
+{
+ struct cis_cache_entry *cis;
+ int ret = 0;
- This is a wrapper around read_cis_mem, with the same interface,
- but which caches information, for cards whose CIS may not be
- readable all the time.
+ if (s->state & SOCKET_CARDBUS)
+ return -EINVAL;
-======================================================================*/
+ mutex_lock(&s->ops_mutex);
+ if (s->fake_cis) {
+ if (s->fake_cis_len >= addr+len)
+ memcpy(ptr, s->fake_cis+addr, len);
+ else {
+ memset(ptr, 0xff, len);
+ ret = -EINVAL;
+ }
+ mutex_unlock(&s->ops_mutex);
+ return ret;
+ }
-static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
- size_t len, void *ptr)
-{
- struct cis_cache_entry *cis;
- int ret;
-
- if (s->fake_cis) {
- if (s->fake_cis_len >= addr+len)
- memcpy(ptr, s->fake_cis+addr, len);
- else
- memset(ptr, 0xff, len);
- return;
- }
-
- list_for_each_entry(cis, &s->cis_cache, node) {
- if (cis->addr == addr && cis->len == len && cis->attr == attr) {
- memcpy(ptr, cis->cache, len);
- return;
+ list_for_each_entry(cis, &s->cis_cache, node) {
+ if (cis->addr == addr && cis->len == len && cis->attr == attr) {
+ memcpy(ptr, cis->cache, len);
+ mutex_unlock(&s->ops_mutex);
+ return 0;
+ }
}
- }
+ mutex_unlock(&s->ops_mutex);
-#ifdef CONFIG_CARDBUS
- if (s->state & SOCKET_CARDBUS)
- ret = read_cb_mem(s, attr, addr, len, ptr);
- else
-#endif
ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr);
if (ret == 0) {
@@ -301,9 +326,12 @@ static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
cis->len = len;
cis->attr = attr;
memcpy(cis->cache, ptr, len);
+ mutex_lock(&s->ops_mutex);
list_add(&cis->node, &s->cis_cache);
+ mutex_unlock(&s->ops_mutex);
}
}
+ return ret;
}
static void
@@ -311,44 +339,46 @@ remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len)
{
struct cis_cache_entry *cis;
+ mutex_lock(&s->ops_mutex);
list_for_each_entry(cis, &s->cis_cache, node)
if (cis->addr == addr && cis->len == len && cis->attr == attr) {
list_del(&cis->node);
kfree(cis);
break;
}
+ mutex_unlock(&s->ops_mutex);
}
+/**
+ * destroy_cis_cache() - destroy the CIS cache
+ * @s: pcmcia_socket for which CIS cache shall be destroyed
+ *
+ * This destroys the CIS cache but keeps any fake CIS alive. Must be
+ * called with ops_mutex held.
+ */
void destroy_cis_cache(struct pcmcia_socket *s)
{
struct list_head *l, *n;
+ struct cis_cache_entry *cis;
list_for_each_safe(l, n, &s->cis_cache) {
- struct cis_cache_entry *cis = list_entry(l, struct cis_cache_entry, node);
-
+ cis = list_entry(l, struct cis_cache_entry, node);
list_del(&cis->node);
kfree(cis);
}
-
- /*
- * If there was a fake CIS, destroy that as well.
- */
- kfree(s->fake_cis);
- s->fake_cis = NULL;
}
-EXPORT_SYMBOL(destroy_cis_cache);
-
-/*======================================================================
-
- This verifies if the CIS of a card matches what is in the CIS
- cache.
-
-======================================================================*/
+/**
+ * verify_cis_cache() - does the CIS match what is in the CIS cache?
+ */
int verify_cis_cache(struct pcmcia_socket *s)
{
struct cis_cache_entry *cis;
char *buf;
+ int ret;
+
+ if (s->state & SOCKET_CARDBUS)
+ return -EINVAL;
buf = kmalloc(256, GFP_KERNEL);
if (buf == NULL) {
@@ -361,14 +391,9 @@ int verify_cis_cache(struct pcmcia_socket *s)
if (len > 256)
len = 256;
-#ifdef CONFIG_CARDBUS
- if (s->state & SOCKET_CARDBUS)
- read_cb_mem(s, cis->attr, cis->addr, len, buf);
- else
-#endif
- pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf);
-
- if (memcmp(buf, cis->cache, len) != 0) {
+
+ ret = pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf);
+ if (ret || memcmp(buf, cis->cache, len) != 0) {
kfree(buf);
return -1;
}
@@ -377,13 +402,12 @@ int verify_cis_cache(struct pcmcia_socket *s)
return 0;
}
-/*======================================================================
-
- For really bad cards, we provide a facility for uploading a
- replacement CIS.
-
-======================================================================*/
-
+/**
+ * pcmcia_replace_cis() - use a replacement CIS instead of the card's CIS
+ *
+ * For really bad cards, we provide a facility for uploading a
+ * replacement CIS.
+ */
int pcmcia_replace_cis(struct pcmcia_socket *s,
const u8 *data, const size_t len)
{
@@ -391,29 +415,28 @@ int pcmcia_replace_cis(struct pcmcia_socket *s,
dev_printk(KERN_WARNING, &s->dev, "replacement CIS too big\n");
return -EINVAL;
}
+ mutex_lock(&s->ops_mutex);
kfree(s->fake_cis);
s->fake_cis = kmalloc(len, GFP_KERNEL);
if (s->fake_cis == NULL) {
dev_printk(KERN_WARNING, &s->dev, "no memory to replace CIS\n");
+ mutex_unlock(&s->ops_mutex);
return -ENOMEM;
}
s->fake_cis_len = len;
memcpy(s->fake_cis, data, len);
+ dev_info(&s->dev, "Using replacement CIS\n");
+ mutex_unlock(&s->ops_mutex);
return 0;
}
-EXPORT_SYMBOL(pcmcia_replace_cis);
-/*======================================================================
-
- The high-level CIS tuple services
-
-======================================================================*/
+/* The high-level CIS tuple services */
typedef struct tuple_flags {
- u_int link_space:4;
- u_int has_link:1;
- u_int mfc_fn:3;
- u_int space:4;
+ u_int link_space:4;
+ u_int has_link:1;
+ u_int mfc_fn:3;
+ u_int space:4;
} tuple_flags;
#define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space)
@@ -421,1099 +444,962 @@ typedef struct tuple_flags {
#define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn)
#define SPACE(f) (((tuple_flags *)(&(f)))->space)
-int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple)
+int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function,
+ tuple_t *tuple)
{
- if (!s)
- return -EINVAL;
- if (!(s->state & SOCKET_PRESENT))
- return -ENODEV;
- tuple->TupleLink = tuple->Flags = 0;
-#ifdef CONFIG_CARDBUS
- if (s->state & SOCKET_CARDBUS) {
- struct pci_dev *dev = s->cb_dev;
- u_int ptr;
- pci_bus_read_config_dword(dev->subordinate, 0, PCI_CARDBUS_CIS, &ptr);
- tuple->CISOffset = ptr & ~7;
- SPACE(tuple->Flags) = (ptr & 7);
- } else
-#endif
- {
+ if (!s)
+ return -EINVAL;
+
+ if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS))
+ return -ENODEV;
+ tuple->TupleLink = tuple->Flags = 0;
+
/* Assume presence of a LONGLINK_C to address 0 */
tuple->CISOffset = tuple->LinkOffset = 0;
SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1;
- }
- if (!(s->state & SOCKET_CARDBUS) && (s->functions > 1) &&
- !(tuple->Attributes & TUPLE_RETURN_COMMON)) {
- cisdata_t req = tuple->DesiredTuple;
- tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
- if (pccard_get_next_tuple(s, function, tuple) == 0) {
- tuple->DesiredTuple = CISTPL_LINKTARGET;
- if (pccard_get_next_tuple(s, function, tuple) != 0)
- return -ENOSPC;
- } else
- tuple->CISOffset = tuple->TupleLink = 0;
- tuple->DesiredTuple = req;
- }
- return pccard_get_next_tuple(s, function, tuple);
+
+ if ((s->functions > 1) && !(tuple->Attributes & TUPLE_RETURN_COMMON)) {
+ cisdata_t req = tuple->DesiredTuple;
+ tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
+ if (pccard_get_next_tuple(s, function, tuple) == 0) {
+ tuple->DesiredTuple = CISTPL_LINKTARGET;
+ if (pccard_get_next_tuple(s, function, tuple) != 0)
+ return -ENOSPC;
+ } else
+ tuple->CISOffset = tuple->TupleLink = 0;
+ tuple->DesiredTuple = req;
+ }
+ return pccard_get_next_tuple(s, function, tuple);
}
-EXPORT_SYMBOL(pccard_get_first_tuple);
static int follow_link(struct pcmcia_socket *s, tuple_t *tuple)
{
- u_char link[5];
- u_int ofs;
-
- if (MFC_FN(tuple->Flags)) {
- /* Get indirect link from the MFC tuple */
- read_cis_cache(s, LINK_SPACE(tuple->Flags),
- tuple->LinkOffset, 5, link);
- ofs = get_unaligned_le32(link + 1);
- SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
- /* Move to the next indirect link */
- tuple->LinkOffset += 5;
- MFC_FN(tuple->Flags)--;
- } else if (HAS_LINK(tuple->Flags)) {
- ofs = tuple->LinkOffset;
- SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags);
- HAS_LINK(tuple->Flags) = 0;
- } else {
- return -1;
- }
- if (!(s->state & SOCKET_CARDBUS) && SPACE(tuple->Flags)) {
- /* This is ugly, but a common CIS error is to code the long
- link offset incorrectly, so we check the right spot... */
- read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
+ u_char link[5];
+ u_int ofs;
+ int ret;
+
+ if (MFC_FN(tuple->Flags)) {
+ /* Get indirect link from the MFC tuple */
+ ret = read_cis_cache(s, LINK_SPACE(tuple->Flags),
+ tuple->LinkOffset, 5, link);
+ if (ret)
+ return -1;
+ ofs = get_unaligned_le32(link + 1);
+ SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
+ /* Move to the next indirect link */
+ tuple->LinkOffset += 5;
+ MFC_FN(tuple->Flags)--;
+ } else if (HAS_LINK(tuple->Flags)) {
+ ofs = tuple->LinkOffset;
+ SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags);
+ HAS_LINK(tuple->Flags) = 0;
+ } else
+ return -1;
+
+ if (SPACE(tuple->Flags)) {
+ /* This is ugly, but a common CIS error is to code the long
+ link offset incorrectly, so we check the right spot... */
+ ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
+ if (ret)
+ return -1;
+ if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
+ (strncmp(link+2, "CIS", 3) == 0))
+ return ofs;
+ remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
+ /* Then, we try the wrong spot... */
+ ofs = ofs >> 1;
+ }
+ ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
+ if (ret)
+ return -1;
if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
- (strncmp(link+2, "CIS", 3) == 0))
- return ofs;
+ (strncmp(link+2, "CIS", 3) == 0))
+ return ofs;
remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
- /* Then, we try the wrong spot... */
- ofs = ofs >> 1;
- }
- read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
- if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
- (strncmp(link+2, "CIS", 3) == 0))
- return ofs;
- remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
- return -1;
+ return -1;
}
-int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple)
+int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function,
+ tuple_t *tuple)
{
- u_char link[2], tmp;
- int ofs, i, attr;
+ u_char link[2], tmp;
+ int ofs, i, attr;
+ int ret;
- if (!s)
- return -EINVAL;
- if (!(s->state & SOCKET_PRESENT))
- return -ENODEV;
+ if (!s)
+ return -EINVAL;
+ if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS))
+ return -ENODEV;
+
+ link[1] = tuple->TupleLink;
+ ofs = tuple->CISOffset + tuple->TupleLink;
+ attr = SPACE(tuple->Flags);
+
+ for (i = 0; i < MAX_TUPLES; i++) {
+ if (link[1] == 0xff)
+ link[0] = CISTPL_END;
+ else {
+ ret = read_cis_cache(s, attr, ofs, 2, link);
+ if (ret)
+ return -1;
+ if (link[0] == CISTPL_NULL) {
+ ofs++;
+ continue;
+ }
+ }
- link[1] = tuple->TupleLink;
- ofs = tuple->CISOffset + tuple->TupleLink;
- attr = SPACE(tuple->Flags);
+ /* End of chain? Follow long link if possible */
+ if (link[0] == CISTPL_END) {
+ ofs = follow_link(s, tuple);
+ if (ofs < 0)
+ return -ENOSPC;
+ attr = SPACE(tuple->Flags);
+ ret = read_cis_cache(s, attr, ofs, 2, link);
+ if (ret)
+ return -1;
+ }
- for (i = 0; i < MAX_TUPLES; i++) {
- if (link[1] == 0xff) {
- link[0] = CISTPL_END;
- } else {
- read_cis_cache(s, attr, ofs, 2, link);
- if (link[0] == CISTPL_NULL) {
- ofs++; continue;
- }
+ /* Is this a link tuple? Make a note of it */
+ if ((link[0] == CISTPL_LONGLINK_A) ||
+ (link[0] == CISTPL_LONGLINK_C) ||
+ (link[0] == CISTPL_LONGLINK_MFC) ||
+ (link[0] == CISTPL_LINKTARGET) ||
+ (link[0] == CISTPL_INDIRECT) ||
+ (link[0] == CISTPL_NO_LINK)) {
+ switch (link[0]) {
+ case CISTPL_LONGLINK_A:
+ HAS_LINK(tuple->Flags) = 1;
+ LINK_SPACE(tuple->Flags) = attr | IS_ATTR;
+ ret = read_cis_cache(s, attr, ofs+2, 4,
+ &tuple->LinkOffset);
+ if (ret)
+ return -1;
+ break;
+ case CISTPL_LONGLINK_C:
+ HAS_LINK(tuple->Flags) = 1;
+ LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR;
+ ret = read_cis_cache(s, attr, ofs+2, 4,
+ &tuple->LinkOffset);
+ if (ret)
+ return -1;
+ break;
+ case CISTPL_INDIRECT:
+ HAS_LINK(tuple->Flags) = 1;
+ LINK_SPACE(tuple->Flags) = IS_ATTR |
+ IS_INDIRECT;
+ tuple->LinkOffset = 0;
+ break;
+ case CISTPL_LONGLINK_MFC:
+ tuple->LinkOffset = ofs + 3;
+ LINK_SPACE(tuple->Flags) = attr;
+ if (function == BIND_FN_ALL) {
+ /* Follow all the MFC links */
+ ret = read_cis_cache(s, attr, ofs+2,
+ 1, &tmp);
+ if (ret)
+ return -1;
+ MFC_FN(tuple->Flags) = tmp;
+ } else {
+ /* Follow exactly one of the links */
+ MFC_FN(tuple->Flags) = 1;
+ tuple->LinkOffset += function * 5;
+ }
+ break;
+ case CISTPL_NO_LINK:
+ HAS_LINK(tuple->Flags) = 0;
+ break;
+ }
+ if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
+ (tuple->DesiredTuple == RETURN_FIRST_TUPLE))
+ break;
+ } else
+ if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
+ break;
+
+ if (link[0] == tuple->DesiredTuple)
+ break;
+ ofs += link[1] + 2;
}
-
- /* End of chain? Follow long link if possible */
- if (link[0] == CISTPL_END) {
- ofs = follow_link(s, tuple);
- if (ofs < 0)
+ if (i == MAX_TUPLES) {
+ dev_dbg(&s->dev, "cs: overrun in pcmcia_get_next_tuple\n");
return -ENOSPC;
- attr = SPACE(tuple->Flags);
- read_cis_cache(s, attr, ofs, 2, link);
}
- /* Is this a link tuple? Make a note of it */
- if ((link[0] == CISTPL_LONGLINK_A) ||
- (link[0] == CISTPL_LONGLINK_C) ||
- (link[0] == CISTPL_LONGLINK_MFC) ||
- (link[0] == CISTPL_LINKTARGET) ||
- (link[0] == CISTPL_INDIRECT) ||
- (link[0] == CISTPL_NO_LINK)) {
- switch (link[0]) {
- case CISTPL_LONGLINK_A:
- HAS_LINK(tuple->Flags) = 1;
- LINK_SPACE(tuple->Flags) = attr | IS_ATTR;
- read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
- break;
- case CISTPL_LONGLINK_C:
- HAS_LINK(tuple->Flags) = 1;
- LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR;
- read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
- break;
- case CISTPL_INDIRECT:
- HAS_LINK(tuple->Flags) = 1;
- LINK_SPACE(tuple->Flags) = IS_ATTR | IS_INDIRECT;
- tuple->LinkOffset = 0;
- break;
- case CISTPL_LONGLINK_MFC:
- tuple->LinkOffset = ofs + 3;
- LINK_SPACE(tuple->Flags) = attr;
- if (function == BIND_FN_ALL) {
- /* Follow all the MFC links */
- read_cis_cache(s, attr, ofs+2, 1, &tmp);
- MFC_FN(tuple->Flags) = tmp;
- } else {
- /* Follow exactly one of the links */
- MFC_FN(tuple->Flags) = 1;
- tuple->LinkOffset += function * 5;
- }
- break;
- case CISTPL_NO_LINK:
- HAS_LINK(tuple->Flags) = 0;
- break;
- }
- if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
- (tuple->DesiredTuple == RETURN_FIRST_TUPLE))
- break;
- } else
- if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
- break;
-
- if (link[0] == tuple->DesiredTuple)
- break;
- ofs += link[1] + 2;
- }
- if (i == MAX_TUPLES) {
- dev_dbg(&s->dev, "cs: overrun in pcmcia_get_next_tuple\n");
- return -ENOSPC;
- }
-
- tuple->TupleCode = link[0];
- tuple->TupleLink = link[1];
- tuple->CISOffset = ofs + 2;
- return 0;
+ tuple->TupleCode = link[0];
+ tuple->TupleLink = link[1];
+ tuple->CISOffset = ofs + 2;
+ return 0;
}
-EXPORT_SYMBOL(pccard_get_next_tuple);
-
-/*====================================================================*/
-
-#define _MIN(a, b) (((a) < (b)) ? (a) : (b))
int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple)
{
- u_int len;
+ u_int len;
+ int ret;
- if (!s)
- return -EINVAL;
+ if (!s)
+ return -EINVAL;
- if (tuple->TupleLink < tuple->TupleOffset)
- return -ENOSPC;
- len = tuple->TupleLink - tuple->TupleOffset;
- tuple->TupleDataLen = tuple->TupleLink;
- if (len == 0)
+ if (tuple->TupleLink < tuple->TupleOffset)
+ return -ENOSPC;
+ len = tuple->TupleLink - tuple->TupleOffset;
+ tuple->TupleDataLen = tuple->TupleLink;
+ if (len == 0)
+ return 0;
+ ret = read_cis_cache(s, SPACE(tuple->Flags),
+ tuple->CISOffset + tuple->TupleOffset,
+ min(len, (u_int) tuple->TupleDataMax),
+ tuple->TupleData);
+ if (ret)
+ return -1;
return 0;
- read_cis_cache(s, SPACE(tuple->Flags),
- tuple->CISOffset + tuple->TupleOffset,
- _MIN(len, tuple->TupleDataMax), tuple->TupleData);
- return 0;
}
-EXPORT_SYMBOL(pccard_get_tuple_data);
-/*======================================================================
-
- Parsing routines for individual tuples
-
-======================================================================*/
+/* Parsing routines for individual tuples */
static int parse_device(tuple_t *tuple, cistpl_device_t *device)
{
- int i;
- u_char scale;
- u_char *p, *q;
+ int i;
+ u_char scale;
+ u_char *p, *q;
- p = (u_char *)tuple->TupleData;
- q = p + tuple->TupleDataLen;
+ p = (u_char *)tuple->TupleData;
+ q = p + tuple->TupleDataLen;
- device->ndev = 0;
- for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
+ device->ndev = 0;
+ for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
- if (*p == 0xff)
- break;
- device->dev[i].type = (*p >> 4);
- device->dev[i].wp = (*p & 0x08) ? 1 : 0;
- switch (*p & 0x07) {
- case 0:
- device->dev[i].speed = 0;
- break;
- case 1:
- device->dev[i].speed = 250;
- break;
- case 2:
- device->dev[i].speed = 200;
- break;
- case 3:
- device->dev[i].speed = 150;
- break;
- case 4:
- device->dev[i].speed = 100;
- break;
- case 7:
- if (++p == q)
- return -EINVAL;
- device->dev[i].speed = SPEED_CVT(*p);
- while (*p & 0x80)
+ if (*p == 0xff)
+ break;
+ device->dev[i].type = (*p >> 4);
+ device->dev[i].wp = (*p & 0x08) ? 1 : 0;
+ switch (*p & 0x07) {
+ case 0:
+ device->dev[i].speed = 0;
+ break;
+ case 1:
+ device->dev[i].speed = 250;
+ break;
+ case 2:
+ device->dev[i].speed = 200;
+ break;
+ case 3:
+ device->dev[i].speed = 150;
+ break;
+ case 4:
+ device->dev[i].speed = 100;
+ break;
+ case 7:
if (++p == q)
return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
+ device->dev[i].speed = SPEED_CVT(*p);
+ while (*p & 0x80)
+ if (++p == q)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
- if (++p == q)
- return -EINVAL;
- if (*p == 0xff)
- break;
- scale = *p & 7;
- if (scale == 7)
- return -EINVAL;
- device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
- device->ndev++;
- if (++p == q)
- break;
- }
+ if (++p == q)
+ return -EINVAL;
+ if (*p == 0xff)
+ break;
+ scale = *p & 7;
+ if (scale == 7)
+ return -EINVAL;
+ device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
+ device->ndev++;
+ if (++p == q)
+ break;
+ }
- return 0;
+ return 0;
}
-/*====================================================================*/
static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
{
- u_char *p;
- if (tuple->TupleDataLen < 5)
- return -EINVAL;
- p = (u_char *) tuple->TupleData;
- csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2;
- csum->len = get_unaligned_le16(p + 2);
- csum->sum = *(p + 4);
- return 0;
+ u_char *p;
+ if (tuple->TupleDataLen < 5)
+ return -EINVAL;
+ p = (u_char *) tuple->TupleData;
+ csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2;
+ csum->len = get_unaligned_le16(p + 2);
+ csum->sum = *(p + 4);
+ return 0;
}
-/*====================================================================*/
static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
{
- if (tuple->TupleDataLen < 4)
- return -EINVAL;
- link->addr = get_unaligned_le32(tuple->TupleData);
- return 0;
+ if (tuple->TupleDataLen < 4)
+ return -EINVAL;
+ link->addr = get_unaligned_le32(tuple->TupleData);
+ return 0;
}
-/*====================================================================*/
-static int parse_longlink_mfc(tuple_t *tuple,
- cistpl_longlink_mfc_t *link)
+static int parse_longlink_mfc(tuple_t *tuple, cistpl_longlink_mfc_t *link)
{
- u_char *p;
- int i;
-
- p = (u_char *)tuple->TupleData;
-
- link->nfn = *p; p++;
- if (tuple->TupleDataLen <= link->nfn*5)
- return -EINVAL;
- for (i = 0; i < link->nfn; i++) {
- link->fn[i].space = *p; p++;
- link->fn[i].addr = get_unaligned_le32(p);
- p += 4;
- }
- return 0;
+ u_char *p;
+ int i;
+
+ p = (u_char *)tuple->TupleData;
+
+ link->nfn = *p; p++;
+ if (tuple->TupleDataLen <= link->nfn*5)
+ return -EINVAL;
+ for (i = 0; i < link->nfn; i++) {
+ link->fn[i].space = *p; p++;
+ link->fn[i].addr = get_unaligned_le32(p);
+ p += 4;
+ }
+ return 0;
}
-/*====================================================================*/
static int parse_strings(u_char *p, u_char *q, int max,
char *s, u_char *ofs, u_char *found)
{
- int i, j, ns;
+ int i, j, ns;
- if (p == q)
- return -EINVAL;
- ns = 0; j = 0;
- for (i = 0; i < max; i++) {
- if (*p == 0xff)
- break;
- ofs[i] = j;
- ns++;
- for (;;) {
- s[j++] = (*p == 0xff) ? '\0' : *p;
- if ((*p == '\0') || (*p == 0xff))
- break;
- if (++p == q)
- return -EINVAL;
+ if (p == q)
+ return -EINVAL;
+ ns = 0; j = 0;
+ for (i = 0; i < max; i++) {
+ if (*p == 0xff)
+ break;
+ ofs[i] = j;
+ ns++;
+ for (;;) {
+ s[j++] = (*p == 0xff) ? '\0' : *p;
+ if ((*p == '\0') || (*p == 0xff))
+ break;
+ if (++p == q)
+ return -EINVAL;
+ }
+ if ((*p == 0xff) || (++p == q))
+ break;
}
- if ((*p == 0xff) || (++p == q))
- break;
- }
- if (found) {
- *found = ns;
- return 0;
- } else {
+ if (found) {
+ *found = ns;
+ return 0;
+ }
+
return (ns == max) ? 0 : -EINVAL;
- }
}
-/*====================================================================*/
static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
{
- u_char *p, *q;
+ u_char *p, *q;
- p = (u_char *)tuple->TupleData;
- q = p + tuple->TupleDataLen;
+ p = (u_char *)tuple->TupleData;
+ q = p + tuple->TupleDataLen;
- vers_1->major = *p; p++;
- vers_1->minor = *p; p++;
- if (p >= q)
- return -EINVAL;
+ vers_1->major = *p; p++;
+ vers_1->minor = *p; p++;
+ if (p >= q)
+ return -EINVAL;
- return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
- vers_1->str, vers_1->ofs, &vers_1->ns);
+ return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
+ vers_1->str, vers_1->ofs, &vers_1->ns);
}
-/*====================================================================*/
static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr)
{
- u_char *p, *q;
+ u_char *p, *q;
- p = (u_char *)tuple->TupleData;
- q = p + tuple->TupleDataLen;
+ p = (u_char *)tuple->TupleData;
+ q = p + tuple->TupleDataLen;
- return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
- altstr->str, altstr->ofs, &altstr->ns);
+ return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
+ altstr->str, altstr->ofs, &altstr->ns);
}
-/*====================================================================*/
static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
{
- u_char *p, *q;
- int nid;
+ u_char *p, *q;
+ int nid;
- p = (u_char *)tuple->TupleData;
- q = p + tuple->TupleDataLen;
+ p = (u_char *)tuple->TupleData;
+ q = p + tuple->TupleDataLen;
- for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
- if (p > q-2)
- break;
- jedec->id[nid].mfr = p[0];
- jedec->id[nid].info = p[1];
- p += 2;
- }
- jedec->nid = nid;
- return 0;
+ for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
+ if (p > q-2)
+ break;
+ jedec->id[nid].mfr = p[0];
+ jedec->id[nid].info = p[1];
+ p += 2;
+ }
+ jedec->nid = nid;
+ return 0;
}
-/*====================================================================*/
static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
{
- if (tuple->TupleDataLen < 4)
- return -EINVAL;
- m->manf = get_unaligned_le16(tuple->TupleData);
- m->card = get_unaligned_le16(tuple->TupleData + 2);
- return 0;
+ if (tuple->TupleDataLen < 4)
+ return -EINVAL;
+ m->manf = get_unaligned_le16(tuple->TupleData);
+ m->card = get_unaligned_le16(tuple->TupleData + 2);
+ return 0;
}
-/*====================================================================*/
static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
{
- u_char *p;
- if (tuple->TupleDataLen < 2)
- return -EINVAL;
- p = (u_char *)tuple->TupleData;
- f->func = p[0];
- f->sysinit = p[1];
- return 0;
+ u_char *p;
+ if (tuple->TupleDataLen < 2)
+ return -EINVAL;
+ p = (u_char *)tuple->TupleData;
+ f->func = p[0];
+ f->sysinit = p[1];
+ return 0;
}
-/*====================================================================*/
static int parse_funce(tuple_t *tuple, cistpl_funce_t *f)
{
- u_char *p;
- int i;
- if (tuple->TupleDataLen < 1)
- return -EINVAL;
- p = (u_char *)tuple->TupleData;
- f->type = p[0];
- for (i = 1; i < tuple->TupleDataLen; i++)
- f->data[i-1] = p[i];
- return 0;
+ u_char *p;
+ int i;
+ if (tuple->TupleDataLen < 1)
+ return -EINVAL;
+ p = (u_char *)tuple->TupleData;
+ f->type = p[0];
+ for (i = 1; i < tuple->TupleDataLen; i++)
+ f->data[i-1] = p[i];
+ return 0;
}
-/*====================================================================*/
static int parse_config(tuple_t *tuple, cistpl_config_t *config)
{
- int rasz, rmsz, i;
- u_char *p;
-
- p = (u_char *)tuple->TupleData;
- rasz = *p & 0x03;
- rmsz = (*p & 0x3c) >> 2;
- if (tuple->TupleDataLen < rasz+rmsz+4)
- return -EINVAL;
- config->last_idx = *(++p);
- p++;
- config->base = 0;
- for (i = 0; i <= rasz; i++)
- config->base += p[i] << (8*i);
- p += rasz+1;
- for (i = 0; i < 4; i++)
- config->rmask[i] = 0;
- for (i = 0; i <= rmsz; i++)
- config->rmask[i>>2] += p[i] << (8*(i%4));
- config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
- return 0;
+ int rasz, rmsz, i;
+ u_char *p;
+
+ p = (u_char *)tuple->TupleData;
+ rasz = *p & 0x03;
+ rmsz = (*p & 0x3c) >> 2;
+ if (tuple->TupleDataLen < rasz+rmsz+4)
+ return -EINVAL;
+ config->last_idx = *(++p);
+ p++;
+ config->base = 0;
+ for (i = 0; i <= rasz; i++)
+ config->base += p[i] << (8*i);
+ p += rasz+1;
+ for (i = 0; i < 4; i++)
+ config->rmask[i] = 0;
+ for (i = 0; i <= rmsz; i++)
+ config->rmask[i>>2] += p[i] << (8*(i%4));
+ config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
+ return 0;
}
-/*======================================================================
+/* The following routines are all used to parse the nightmarish
+ * config table entries.
+ */
+
+static u_char *parse_power(u_char *p, u_char *q, cistpl_power_t *pwr)
+{
+ int i;
+ u_int scale;
- The following routines are all used to parse the nightmarish
- config table entries.
+ if (p == q)
+ return NULL;
+ pwr->present = *p;
+ pwr->flags = 0;
+ p++;
+ for (i = 0; i < 7; i++)
+ if (pwr->present & (1<<i)) {
+ if (p == q)
+ return NULL;
+ pwr->param[i] = POWER_CVT(*p);
+ scale = POWER_SCALE(*p);
+ while (*p & 0x80) {
+ if (++p == q)
+ return NULL;
+ if ((*p & 0x7f) < 100)
+ pwr->param[i] +=
+ (*p & 0x7f) * scale / 100;
+ else if (*p == 0x7d)
+ pwr->flags |= CISTPL_POWER_HIGHZ_OK;
+ else if (*p == 0x7e)
+ pwr->param[i] = 0;
+ else if (*p == 0x7f)
+ pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
+ else
+ return NULL;
+ }
+ p++;
+ }
+ return p;
+}
-======================================================================*/
-static u_char *parse_power(u_char *p, u_char *q,
- cistpl_power_t *pwr)
+static u_char *parse_timing(u_char *p, u_char *q, cistpl_timing_t *timing)
{
- int i;
- u_int scale;
-
- if (p == q)
- return NULL;
- pwr->present = *p;
- pwr->flags = 0;
- p++;
- for (i = 0; i < 7; i++)
- if (pwr->present & (1<<i)) {
- if (p == q)
- return NULL;
- pwr->param[i] = POWER_CVT(*p);
- scale = POWER_SCALE(*p);
- while (*p & 0x80) {
+ u_char scale;
+
+ if (p == q)
+ return NULL;
+ scale = *p;
+ if ((scale & 3) != 3) {
if (++p == q)
return NULL;
- if ((*p & 0x7f) < 100)
- pwr->param[i] += (*p & 0x7f) * scale / 100;
- else if (*p == 0x7d)
- pwr->flags |= CISTPL_POWER_HIGHZ_OK;
- else if (*p == 0x7e)
- pwr->param[i] = 0;
- else if (*p == 0x7f)
- pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
- else
- return NULL;
- }
- p++;
- }
- return p;
+ timing->wait = SPEED_CVT(*p);
+ timing->waitscale = exponent[scale & 3];
+ } else
+ timing->wait = 0;
+ scale >>= 2;
+ if ((scale & 7) != 7) {
+ if (++p == q)
+ return NULL;
+ timing->ready = SPEED_CVT(*p);
+ timing->rdyscale = exponent[scale & 7];
+ } else
+ timing->ready = 0;
+ scale >>= 3;
+ if (scale != 7) {
+ if (++p == q)
+ return NULL;
+ timing->reserved = SPEED_CVT(*p);
+ timing->rsvscale = exponent[scale];
+ } else
+ timing->reserved = 0;
+ p++;
+ return p;
}
-/*====================================================================*/
-static u_char *parse_timing(u_char *p, u_char *q,
- cistpl_timing_t *timing)
+static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
{
- u_char scale;
+ int i, j, bsz, lsz;
- if (p == q)
- return NULL;
- scale = *p;
- if ((scale & 3) != 3) {
- if (++p == q)
- return NULL;
- timing->wait = SPEED_CVT(*p);
- timing->waitscale = exponent[scale & 3];
- } else
- timing->wait = 0;
- scale >>= 2;
- if ((scale & 7) != 7) {
- if (++p == q)
+ if (p == q)
return NULL;
- timing->ready = SPEED_CVT(*p);
- timing->rdyscale = exponent[scale & 7];
- } else
- timing->ready = 0;
- scale >>= 3;
- if (scale != 7) {
+ io->flags = *p;
+
+ if (!(*p & 0x80)) {
+ io->nwin = 1;
+ io->win[0].base = 0;
+ io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
+ return p+1;
+ }
+
if (++p == q)
return NULL;
- timing->reserved = SPEED_CVT(*p);
- timing->rsvscale = exponent[scale];
- } else
- timing->reserved = 0;
- p++;
- return p;
-}
-
-/*====================================================================*/
+ io->nwin = (*p & 0x0f) + 1;
+ bsz = (*p & 0x30) >> 4;
+ if (bsz == 3)
+ bsz++;
+ lsz = (*p & 0xc0) >> 6;
+ if (lsz == 3)
+ lsz++;
+ p++;
-static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
-{
- int i, j, bsz, lsz;
-
- if (p == q)
- return NULL;
- io->flags = *p;
-
- if (!(*p & 0x80)) {
- io->nwin = 1;
- io->win[0].base = 0;
- io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
- return p+1;
- }
-
- if (++p == q)
- return NULL;
- io->nwin = (*p & 0x0f) + 1;
- bsz = (*p & 0x30) >> 4;
- if (bsz == 3)
- bsz++;
- lsz = (*p & 0xc0) >> 6;
- if (lsz == 3)
- lsz++;
- p++;
-
- for (i = 0; i < io->nwin; i++) {
- io->win[i].base = 0;
- io->win[i].len = 1;
- for (j = 0; j < bsz; j++, p++) {
- if (p == q)
- return NULL;
- io->win[i].base += *p << (j*8);
- }
- for (j = 0; j < lsz; j++, p++) {
- if (p == q)
- return NULL;
- io->win[i].len += *p << (j*8);
+ for (i = 0; i < io->nwin; i++) {
+ io->win[i].base = 0;
+ io->win[i].len = 1;
+ for (j = 0; j < bsz; j++, p++) {
+ if (p == q)
+ return NULL;
+ io->win[i].base += *p << (j*8);
+ }
+ for (j = 0; j < lsz; j++, p++) {
+ if (p == q)
+ return NULL;
+ io->win[i].len += *p << (j*8);
+ }
}
- }
- return p;
+ return p;
}
-/*====================================================================*/
static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
{
- int i, j, asz, lsz, has_ha;
- u_int len, ca, ha;
-
- if (p == q)
- return NULL;
-
- mem->nwin = (*p & 0x07) + 1;
- lsz = (*p & 0x18) >> 3;
- asz = (*p & 0x60) >> 5;
- has_ha = (*p & 0x80);
- if (++p == q)
- return NULL;
-
- for (i = 0; i < mem->nwin; i++) {
- len = ca = ha = 0;
- for (j = 0; j < lsz; j++, p++) {
- if (p == q)
- return NULL;
- len += *p << (j*8);
- }
- for (j = 0; j < asz; j++, p++) {
- if (p == q)
- return NULL;
- ca += *p << (j*8);
+ int i, j, asz, lsz, has_ha;
+ u_int len, ca, ha;
+
+ if (p == q)
+ return NULL;
+
+ mem->nwin = (*p & 0x07) + 1;
+ lsz = (*p & 0x18) >> 3;
+ asz = (*p & 0x60) >> 5;
+ has_ha = (*p & 0x80);
+ if (++p == q)
+ return NULL;
+
+ for (i = 0; i < mem->nwin; i++) {
+ len = ca = ha = 0;
+ for (j = 0; j < lsz; j++, p++) {
+ if (p == q)
+ return NULL;
+ len += *p << (j*8);
+ }
+ for (j = 0; j < asz; j++, p++) {
+ if (p == q)
+ return NULL;
+ ca += *p << (j*8);
+ }
+ if (has_ha)
+ for (j = 0; j < asz; j++, p++) {
+ if (p == q)
+ return NULL;
+ ha += *p << (j*8);
+ }
+ mem->win[i].len = len << 8;
+ mem->win[i].card_addr = ca << 8;
+ mem->win[i].host_addr = ha << 8;
}
- if (has_ha)
- for (j = 0; j < asz; j++, p++) {
- if (p == q)
- return NULL;
- ha += *p << (j*8);
- }
- mem->win[i].len = len << 8;
- mem->win[i].card_addr = ca << 8;
- mem->win[i].host_addr = ha << 8;
- }
- return p;
+ return p;
}
-/*====================================================================*/
static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
{
- if (p == q)
- return NULL;
- irq->IRQInfo1 = *p; p++;
- if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
- if (p+2 > q)
+ if (p == q)
return NULL;
- irq->IRQInfo2 = (p[1]<<8) + p[0];
- p += 2;
- }
- return p;
+ irq->IRQInfo1 = *p; p++;
+ if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
+ if (p+2 > q)
+ return NULL;
+ irq->IRQInfo2 = (p[1]<<8) + p[0];
+ p += 2;
+ }
+ return p;
}
-/*====================================================================*/
static int parse_cftable_entry(tuple_t *tuple,
cistpl_cftable_entry_t *entry)
{
- u_char *p, *q, features;
-
- p = tuple->TupleData;
- q = p + tuple->TupleDataLen;
- entry->index = *p & 0x3f;
- entry->flags = 0;
- if (*p & 0x40)
- entry->flags |= CISTPL_CFTABLE_DEFAULT;
- if (*p & 0x80) {
- if (++p == q)
- return -EINVAL;
- if (*p & 0x10)
- entry->flags |= CISTPL_CFTABLE_BVDS;
- if (*p & 0x20)
- entry->flags |= CISTPL_CFTABLE_WP;
- if (*p & 0x40)
- entry->flags |= CISTPL_CFTABLE_RDYBSY;
- if (*p & 0x80)
- entry->flags |= CISTPL_CFTABLE_MWAIT;
- entry->interface = *p & 0x0f;
- } else
- entry->interface = 0;
-
- /* Process optional features */
- if (++p == q)
- return -EINVAL;
- features = *p; p++;
-
- /* Power options */
- if ((features & 3) > 0) {
- p = parse_power(p, q, &entry->vcc);
- if (p == NULL)
- return -EINVAL;
- } else
- entry->vcc.present = 0;
- if ((features & 3) > 1) {
- p = parse_power(p, q, &entry->vpp1);
- if (p == NULL)
- return -EINVAL;
- } else
- entry->vpp1.present = 0;
- if ((features & 3) > 2) {
- p = parse_power(p, q, &entry->vpp2);
- if (p == NULL)
- return -EINVAL;
- } else
- entry->vpp2.present = 0;
-
- /* Timing options */
- if (features & 0x04) {
- p = parse_timing(p, q, &entry->timing);
- if (p == NULL)
- return -EINVAL;
- } else {
- entry->timing.wait = 0;
- entry->timing.ready = 0;
- entry->timing.reserved = 0;
- }
-
- /* I/O window options */
- if (features & 0x08) {
- p = parse_io(p, q, &entry->io);
- if (p == NULL)
- return -EINVAL;
- } else
- entry->io.nwin = 0;
+ u_char *p, *q, features;
- /* Interrupt options */
- if (features & 0x10) {
- p = parse_irq(p, q, &entry->irq);
- if (p == NULL)
- return -EINVAL;
- } else
- entry->irq.IRQInfo1 = 0;
-
- switch (features & 0x60) {
- case 0x00:
- entry->mem.nwin = 0;
- break;
- case 0x20:
- entry->mem.nwin = 1;
- entry->mem.win[0].len = get_unaligned_le16(p) << 8;
- entry->mem.win[0].card_addr = 0;
- entry->mem.win[0].host_addr = 0;
- p += 2;
- if (p > q)
- return -EINVAL;
- break;
- case 0x40:
- entry->mem.nwin = 1;
- entry->mem.win[0].len = get_unaligned_le16(p) << 8;
- entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8;
- entry->mem.win[0].host_addr = 0;
- p += 4;
- if (p > q)
- return -EINVAL;
- break;
- case 0x60:
- p = parse_mem(p, q, &entry->mem);
- if (p == NULL)
- return -EINVAL;
- break;
- }
+ p = tuple->TupleData;
+ q = p + tuple->TupleDataLen;
+ entry->index = *p & 0x3f;
+ entry->flags = 0;
+ if (*p & 0x40)
+ entry->flags |= CISTPL_CFTABLE_DEFAULT;
+ if (*p & 0x80) {
+ if (++p == q)
+ return -EINVAL;
+ if (*p & 0x10)
+ entry->flags |= CISTPL_CFTABLE_BVDS;
+ if (*p & 0x20)
+ entry->flags |= CISTPL_CFTABLE_WP;
+ if (*p & 0x40)
+ entry->flags |= CISTPL_CFTABLE_RDYBSY;
+ if (*p & 0x80)
+ entry->flags |= CISTPL_CFTABLE_MWAIT;
+ entry->interface = *p & 0x0f;
+ } else
+ entry->interface = 0;
- /* Misc features */
- if (features & 0x80) {
- if (p == q)
+ /* Process optional features */
+ if (++p == q)
return -EINVAL;
- entry->flags |= (*p << 8);
- while (*p & 0x80)
- if (++p == q)
- return -EINVAL;
- p++;
- }
+ features = *p; p++;
- entry->subtuples = q-p;
-
- return 0;
-}
-
-/*====================================================================*/
-
-#ifdef CONFIG_CARDBUS
-
-static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar)
-{
- u_char *p;
- if (tuple->TupleDataLen < 6)
- return -EINVAL;
- p = (u_char *)tuple->TupleData;
- bar->attr = *p;
- p += 2;
- bar->size = get_unaligned_le32(p);
- return 0;
-}
+ /* Power options */
+ if ((features & 3) > 0) {
+ p = parse_power(p, q, &entry->vcc);
+ if (p == NULL)
+ return -EINVAL;
+ } else
+ entry->vcc.present = 0;
+ if ((features & 3) > 1) {
+ p = parse_power(p, q, &entry->vpp1);
+ if (p == NULL)
+ return -EINVAL;
+ } else
+ entry->vpp1.present = 0;
+ if ((features & 3) > 2) {
+ p = parse_power(p, q, &entry->vpp2);
+ if (p == NULL)
+ return -EINVAL;
+ } else
+ entry->vpp2.present = 0;
-static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
-{
- u_char *p;
-
- p = (u_char *)tuple->TupleData;
- if ((*p != 3) || (tuple->TupleDataLen < 6))
- return -EINVAL;
- config->last_idx = *(++p);
- p++;
- config->base = get_unaligned_le32(p);
- config->subtuples = tuple->TupleDataLen - 6;
- return 0;
-}
+ /* Timing options */
+ if (features & 0x04) {
+ p = parse_timing(p, q, &entry->timing);
+ if (p == NULL)
+ return -EINVAL;
+ } else {
+ entry->timing.wait = 0;
+ entry->timing.ready = 0;
+ entry->timing.reserved = 0;
+ }
-static int parse_cftable_entry_cb(tuple_t *tuple,
- cistpl_cftable_entry_cb_t *entry)
-{
- u_char *p, *q, features;
-
- p = tuple->TupleData;
- q = p + tuple->TupleDataLen;
- entry->index = *p & 0x3f;
- entry->flags = 0;
- if (*p & 0x40)
- entry->flags |= CISTPL_CFTABLE_DEFAULT;
-
- /* Process optional features */
- if (++p == q)
- return -EINVAL;
- features = *p; p++;
-
- /* Power options */
- if ((features & 3) > 0) {
- p = parse_power(p, q, &entry->vcc);
- if (p == NULL)
- return -EINVAL;
- } else
- entry->vcc.present = 0;
- if ((features & 3) > 1) {
- p = parse_power(p, q, &entry->vpp1);
- if (p == NULL)
- return -EINVAL;
- } else
- entry->vpp1.present = 0;
- if ((features & 3) > 2) {
- p = parse_power(p, q, &entry->vpp2);
- if (p == NULL)
- return -EINVAL;
- } else
- entry->vpp2.present = 0;
+ /* I/O window options */
+ if (features & 0x08) {
+ p = parse_io(p, q, &entry->io);
+ if (p == NULL)
+ return -EINVAL;
+ } else
+ entry->io.nwin = 0;
- /* I/O window options */
- if (features & 0x08) {
- if (p == q)
- return -EINVAL;
- entry->io = *p; p++;
- } else
- entry->io = 0;
-
- /* Interrupt options */
- if (features & 0x10) {
- p = parse_irq(p, q, &entry->irq);
- if (p == NULL)
- return -EINVAL;
- } else
- entry->irq.IRQInfo1 = 0;
+ /* Interrupt options */
+ if (features & 0x10) {
+ p = parse_irq(p, q, &entry->irq);
+ if (p == NULL)
+ return -EINVAL;
+ } else
+ entry->irq.IRQInfo1 = 0;
- if (features & 0x20) {
- if (p == q)
- return -EINVAL;
- entry->mem = *p; p++;
- } else
- entry->mem = 0;
+ switch (features & 0x60) {
+ case 0x00:
+ entry->mem.nwin = 0;
+ break;
+ case 0x20:
+ entry->mem.nwin = 1;
+ entry->mem.win[0].len = get_unaligned_le16(p) << 8;
+ entry->mem.win[0].card_addr = 0;
+ entry->mem.win[0].host_addr = 0;
+ p += 2;
+ if (p > q)
+ return -EINVAL;
+ break;
+ case 0x40:
+ entry->mem.nwin = 1;
+ entry->mem.win[0].len = get_unaligned_le16(p) << 8;
+ entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8;
+ entry->mem.win[0].host_addr = 0;
+ p += 4;
+ if (p > q)
+ return -EINVAL;
+ break;
+ case 0x60:
+ p = parse_mem(p, q, &entry->mem);
+ if (p == NULL)
+ return -EINVAL;
+ break;
+ }
- /* Misc features */
- if (features & 0x80) {
- if (p == q)
- return -EINVAL;
- entry->flags |= (*p << 8);
- if (*p & 0x80) {
- if (++p == q)
- return -EINVAL;
- entry->flags |= (*p << 16);
+ /* Misc features */
+ if (features & 0x80) {
+ if (p == q)
+ return -EINVAL;
+ entry->flags |= (*p << 8);
+ while (*p & 0x80)
+ if (++p == q)
+ return -EINVAL;
+ p++;
}
- while (*p & 0x80)
- if (++p == q)
- return -EINVAL;
- p++;
- }
- entry->subtuples = q-p;
+ entry->subtuples = q-p;
- return 0;
+ return 0;
}
-#endif
-
-/*====================================================================*/
static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
{
- u_char *p, *q;
- int n;
+ u_char *p, *q;
+ int n;
- p = (u_char *)tuple->TupleData;
- q = p + tuple->TupleDataLen;
+ p = (u_char *)tuple->TupleData;
+ q = p + tuple->TupleDataLen;
- for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
- if (p > q-6)
- break;
- geo->geo[n].buswidth = p[0];
- geo->geo[n].erase_block = 1 << (p[1]-1);
- geo->geo[n].read_block = 1 << (p[2]-1);
- geo->geo[n].write_block = 1 << (p[3]-1);
- geo->geo[n].partition = 1 << (p[4]-1);
- geo->geo[n].interleave = 1 << (p[5]-1);
- p += 6;
- }
- geo->ngeo = n;
- return 0;
+ for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
+ if (p > q-6)
+ break;
+ geo->geo[n].buswidth = p[0];
+ geo->geo[n].erase_block = 1 << (p[1]-1);
+ geo->geo[n].read_block = 1 << (p[2]-1);
+ geo->geo[n].write_block = 1 << (p[3]-1);
+ geo->geo[n].partition = 1 << (p[4]-1);
+ geo->geo[n].interleave = 1 << (p[5]-1);
+ p += 6;
+ }
+ geo->ngeo = n;
+ return 0;
}
-/*====================================================================*/
static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
{
- u_char *p, *q;
-
- if (tuple->TupleDataLen < 10)
- return -EINVAL;
-
- p = tuple->TupleData;
- q = p + tuple->TupleDataLen;
-
- v2->vers = p[0];
- v2->comply = p[1];
- v2->dindex = get_unaligned_le16(p + 2);
- v2->vspec8 = p[6];
- v2->vspec9 = p[7];
- v2->nhdr = p[8];
- p += 9;
- return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
+ u_char *p, *q;
+
+ if (tuple->TupleDataLen < 10)
+ return -EINVAL;
+
+ p = tuple->TupleData;
+ q = p + tuple->TupleDataLen;
+
+ v2->vers = p[0];
+ v2->comply = p[1];
+ v2->dindex = get_unaligned_le16(p + 2);
+ v2->vspec8 = p[6];
+ v2->vspec9 = p[7];
+ v2->nhdr = p[8];
+ p += 9;
+ return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
}
-/*====================================================================*/
static int parse_org(tuple_t *tuple, cistpl_org_t *org)
{
- u_char *p, *q;
- int i;
-
- p = tuple->TupleData;
- q = p + tuple->TupleDataLen;
- if (p == q)
- return -EINVAL;
- org->data_org = *p;
- if (++p == q)
- return -EINVAL;
- for (i = 0; i < 30; i++) {
- org->desc[i] = *p;
- if (*p == '\0')
- break;
+ u_char *p, *q;
+ int i;
+
+ p = tuple->TupleData;
+ q = p + tuple->TupleDataLen;
+ if (p == q)
+ return -EINVAL;
+ org->data_org = *p;
if (++p == q)
return -EINVAL;
- }
- return 0;
+ for (i = 0; i < 30; i++) {
+ org->desc[i] = *p;
+ if (*p == '\0')
+ break;
+ if (++p == q)
+ return -EINVAL;
+ }
+ return 0;
}
-/*====================================================================*/
static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
{
- u_char *p;
+ u_char *p;
- if (tuple->TupleDataLen < 10)
- return -EINVAL;
+ if (tuple->TupleDataLen < 10)
+ return -EINVAL;
- p = tuple->TupleData;
+ p = tuple->TupleData;
- fmt->type = p[0];
- fmt->edc = p[1];
- fmt->offset = get_unaligned_le32(p + 2);
- fmt->length = get_unaligned_le32(p + 6);
+ fmt->type = p[0];
+ fmt->edc = p[1];
+ fmt->offset = get_unaligned_le32(p + 2);
+ fmt->length = get_unaligned_le32(p + 6);
- return 0;
+ return 0;
}
-/*====================================================================*/
int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse)
{
- int ret = 0;
-
- if (tuple->TupleDataLen > tuple->TupleDataMax)
- return -EINVAL;
- switch (tuple->TupleCode) {
- case CISTPL_DEVICE:
- case CISTPL_DEVICE_A:
- ret = parse_device(tuple, &parse->device);
- break;
-#ifdef CONFIG_CARDBUS
- case CISTPL_BAR:
- ret = parse_bar(tuple, &parse->bar);
- break;
- case CISTPL_CONFIG_CB:
- ret = parse_config_cb(tuple, &parse->config);
- break;
- case CISTPL_CFTABLE_ENTRY_CB:
- ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb);
- break;
-#endif
- case CISTPL_CHECKSUM:
- ret = parse_checksum(tuple, &parse->checksum);
- break;
- case CISTPL_LONGLINK_A:
- case CISTPL_LONGLINK_C:
- ret = parse_longlink(tuple, &parse->longlink);
- break;
- case CISTPL_LONGLINK_MFC:
- ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
- break;
- case CISTPL_VERS_1:
- ret = parse_vers_1(tuple, &parse->version_1);
- break;
- case CISTPL_ALTSTR:
- ret = parse_altstr(tuple, &parse->altstr);
- break;
- case CISTPL_JEDEC_A:
- case CISTPL_JEDEC_C:
- ret = parse_jedec(tuple, &parse->jedec);
- break;
- case CISTPL_MANFID:
- ret = parse_manfid(tuple, &parse->manfid);
- break;
- case CISTPL_FUNCID:
- ret = parse_funcid(tuple, &parse->funcid);
- break;
- case CISTPL_FUNCE:
- ret = parse_funce(tuple, &parse->funce);
- break;
- case CISTPL_CONFIG:
- ret = parse_config(tuple, &parse->config);
- break;
- case CISTPL_CFTABLE_ENTRY:
- ret = parse_cftable_entry(tuple, &parse->cftable_entry);
- break;
- case CISTPL_DEVICE_GEO:
- case CISTPL_DEVICE_GEO_A:
- ret = parse_device_geo(tuple, &parse->device_geo);
- break;
- case CISTPL_VERS_2:
- ret = parse_vers_2(tuple, &parse->vers_2);
- break;
- case CISTPL_ORG:
- ret = parse_org(tuple, &parse->org);
- break;
- case CISTPL_FORMAT:
- case CISTPL_FORMAT_A:
- ret = parse_format(tuple, &parse->format);
- break;
- case CISTPL_NO_LINK:
- case CISTPL_LINKTARGET:
- ret = 0;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- if (ret)
- pr_debug("parse_tuple failed %d\n", ret);
- return ret;
+ int ret = 0;
+
+ if (tuple->TupleDataLen > tuple->TupleDataMax)
+ return -EINVAL;
+ switch (tuple->TupleCode) {
+ case CISTPL_DEVICE:
+ case CISTPL_DEVICE_A:
+ ret = parse_device(tuple, &parse->device);
+ break;
+ case CISTPL_CHECKSUM:
+ ret = parse_checksum(tuple, &parse->checksum);
+ break;
+ case CISTPL_LONGLINK_A:
+ case CISTPL_LONGLINK_C:
+ ret = parse_longlink(tuple, &parse->longlink);
+ break;
+ case CISTPL_LONGLINK_MFC:
+ ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
+ break;
+ case CISTPL_VERS_1:
+ ret = parse_vers_1(tuple, &parse->version_1);
+ break;
+ case CISTPL_ALTSTR:
+ ret = parse_altstr(tuple, &parse->altstr);
+ break;
+ case CISTPL_JEDEC_A:
+ case CISTPL_JEDEC_C:
+ ret = parse_jedec(tuple, &parse->jedec);
+ break;
+ case CISTPL_MANFID:
+ ret = parse_manfid(tuple, &parse->manfid);
+ break;
+ case CISTPL_FUNCID:
+ ret = parse_funcid(tuple, &parse->funcid);
+ break;
+ case CISTPL_FUNCE:
+ ret = parse_funce(tuple, &parse->funce);
+ break;
+ case CISTPL_CONFIG:
+ ret = parse_config(tuple, &parse->config);
+ break;
+ case CISTPL_CFTABLE_ENTRY:
+ ret = parse_cftable_entry(tuple, &parse->cftable_entry);
+ break;
+ case CISTPL_DEVICE_GEO:
+ case CISTPL_DEVICE_GEO_A:
+ ret = parse_device_geo(tuple, &parse->device_geo);
+ break;
+ case CISTPL_VERS_2:
+ ret = parse_vers_2(tuple, &parse->vers_2);
+ break;
+ case CISTPL_ORG:
+ ret = parse_org(tuple, &parse->org);
+ break;
+ case CISTPL_FORMAT:
+ case CISTPL_FORMAT_A:
+ ret = parse_format(tuple, &parse->format);
+ break;
+ case CISTPL_NO_LINK:
+ case CISTPL_LINKTARGET:
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ pr_debug("parse_tuple failed %d\n", ret);
+ return ret;
}
EXPORT_SYMBOL(pcmcia_parse_tuple);
-/*======================================================================
- This is used internally by Card Services to look up CIS stuff.
-
-======================================================================*/
-
-int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse)
+/**
+ * pccard_read_tuple() - internal CIS tuple access
+ * @s: the struct pcmcia_socket where the card is inserted
+ * @function: the device function we loop for
+ * @code: which CIS code shall we look for?
+ * @parse: buffer where the tuple shall be parsed (or NULL, if no parse)
+ *
+ * pccard_read_tuple() reads out one tuple and attempts to parse it
+ */
+int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function,
+ cisdata_t code, void *parse)
{
- tuple_t tuple;
- cisdata_t *buf;
- int ret;
-
- buf = kmalloc(256, GFP_KERNEL);
- if (buf == NULL) {
- dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n");
- return -ENOMEM;
- }
- tuple.DesiredTuple = code;
- tuple.Attributes = 0;
- if (function == BIND_FN_ALL)
- tuple.Attributes = TUPLE_RETURN_COMMON;
- ret = pccard_get_first_tuple(s, function, &tuple);
- if (ret != 0)
- goto done;
- tuple.TupleData = buf;
- tuple.TupleOffset = 0;
- tuple.TupleDataMax = 255;
- ret = pccard_get_tuple_data(s, &tuple);
- if (ret != 0)
- goto done;
- ret = pcmcia_parse_tuple(&tuple, parse);
+ tuple_t tuple;
+ cisdata_t *buf;
+ int ret;
+
+ buf = kmalloc(256, GFP_KERNEL);
+ if (buf == NULL) {
+ dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n");
+ return -ENOMEM;
+ }
+ tuple.DesiredTuple = code;
+ tuple.Attributes = 0;
+ if (function == BIND_FN_ALL)
+ tuple.Attributes = TUPLE_RETURN_COMMON;
+ ret = pccard_get_first_tuple(s, function, &tuple);
+ if (ret != 0)
+ goto done;
+ tuple.TupleData = buf;
+ tuple.TupleOffset = 0;
+ tuple.TupleDataMax = 255;
+ ret = pccard_get_tuple_data(s, &tuple);
+ if (ret != 0)
+ goto done;
+ ret = pcmcia_parse_tuple(&tuple, parse);
done:
- kfree(buf);
- return ret;
+ kfree(buf);
+ return ret;
}
-EXPORT_SYMBOL(pccard_read_tuple);
/**
@@ -1573,84 +1459,238 @@ next_entry:
kfree(buf);
return ret;
}
-EXPORT_SYMBOL(pccard_loop_tuple);
-/*======================================================================
+/**
+ * pccard_validate_cis() - check whether card has a sensible CIS
+ * @s: the struct pcmcia_socket we are to check
+ * @info: returns the number of tuples in the (valid) CIS, or 0
+ *
+ * This tries to determine if a card has a sensible CIS. In @info, it
+ * returns the number of tuples in the CIS, or 0 if the CIS looks bad. The
+ * checks include making sure several critical tuples are present and
+ * valid; seeing if the total number of tuples is reasonable; and
+ * looking for tuples that use reserved codes.
+ *
+ * The function returns 0 on success.
+ */
+int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
+{
+ tuple_t *tuple;
+ cisparse_t *p;
+ unsigned int count = 0;
+ int ret, reserved, dev_ok = 0, ident_ok = 0;
- This tries to determine if a card has a sensible CIS. It returns
- the number of tuples in the CIS, or 0 if the CIS looks bad. The
- checks include making sure several critical tuples are present and
- valid; seeing if the total number of tuples is reasonable; and
- looking for tuples that use reserved codes.
+ if (!s)
+ return -EINVAL;
-======================================================================*/
+ /* We do not want to validate the CIS cache... */
+ mutex_lock(&s->ops_mutex);
+ destroy_cis_cache(s);
+ mutex_unlock(&s->ops_mutex);
-int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
-{
- tuple_t *tuple;
- cisparse_t *p;
- unsigned int count = 0;
- int ret, reserved, dev_ok = 0, ident_ok = 0;
-
- if (!s)
- return -EINVAL;
-
- tuple = kmalloc(sizeof(*tuple), GFP_KERNEL);
- if (tuple == NULL) {
- dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n");
- return -ENOMEM;
- }
- p = kmalloc(sizeof(*p), GFP_KERNEL);
- if (p == NULL) {
- kfree(tuple);
- dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n");
- return -ENOMEM;
- }
-
- count = reserved = 0;
- tuple->DesiredTuple = RETURN_FIRST_TUPLE;
- tuple->Attributes = TUPLE_RETURN_COMMON;
- ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple);
- if (ret != 0)
- goto done;
-
- /* First tuple should be DEVICE; we should really have either that
- or a CFTABLE_ENTRY of some sort */
- if ((tuple->TupleCode == CISTPL_DEVICE) ||
- (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p) == 0) ||
- (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p) == 0))
- dev_ok++;
-
- /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2
- tuple, for card identification. Certain old D-Link and Linksys
- cards have only a broken VERS_2 tuple; hence the bogus test. */
- if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) ||
- (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) ||
- (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC))
- ident_ok++;
-
- if (!dev_ok && !ident_ok)
- goto done;
-
- for (count = 1; count < MAX_TUPLES; count++) {
- ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple);
+ tuple = kmalloc(sizeof(*tuple), GFP_KERNEL);
+ if (tuple == NULL) {
+ dev_warn(&s->dev, "no memory to validate CIS\n");
+ return -ENOMEM;
+ }
+ p = kmalloc(sizeof(*p), GFP_KERNEL);
+ if (p == NULL) {
+ kfree(tuple);
+ dev_warn(&s->dev, "no memory to validate CIS\n");
+ return -ENOMEM;
+ }
+
+ count = reserved = 0;
+ tuple->DesiredTuple = RETURN_FIRST_TUPLE;
+ tuple->Attributes = TUPLE_RETURN_COMMON;
+ ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple);
if (ret != 0)
- break;
- if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) ||
- ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) ||
- ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff)))
- reserved++;
- }
- if ((count == MAX_TUPLES) || (reserved > 5) ||
- ((!dev_ok || !ident_ok) && (count > 10)))
- count = 0;
+ goto done;
+
+ /* First tuple should be DEVICE; we should really have either that
+ or a CFTABLE_ENTRY of some sort */
+ if ((tuple->TupleCode == CISTPL_DEVICE) ||
+ (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p)) ||
+ (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p)))
+ dev_ok++;
+
+ /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2
+ tuple, for card identification. Certain old D-Link and Linksys
+ cards have only a broken VERS_2 tuple; hence the bogus test. */
+ if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) ||
+ (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) ||
+ (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC))
+ ident_ok++;
+
+ if (!dev_ok && !ident_ok)
+ goto done;
+
+ for (count = 1; count < MAX_TUPLES; count++) {
+ ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple);
+ if (ret != 0)
+ break;
+ if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) ||
+ ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) ||
+ ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff)))
+ reserved++;
+ }
+ if ((count == MAX_TUPLES) || (reserved > 5) ||
+ ((!dev_ok || !ident_ok) && (count > 10)))
+ count = 0;
+
+ ret = 0;
done:
- if (info)
- *info = count;
- kfree(tuple);
- kfree(p);
- return 0;
+ /* invalidate CIS cache on failure */
+ if (!dev_ok || !ident_ok || !count) {
+ mutex_lock(&s->ops_mutex);
+ destroy_cis_cache(s);
+ mutex_unlock(&s->ops_mutex);
+ ret = -EIO;
+ }
+
+ if (info)
+ *info = count;
+ kfree(tuple);
+ kfree(p);
+ return ret;
}
-EXPORT_SYMBOL(pccard_validate_cis);
+
+
+#define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev)
+
+static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf,
+ loff_t off, size_t count)
+{
+ tuple_t tuple;
+ int status, i;
+ loff_t pointer = 0;
+ ssize_t ret = 0;
+ u_char *tuplebuffer;
+ u_char *tempbuffer;
+
+ tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL);
+ if (!tuplebuffer)
+ return -ENOMEM;
+
+ tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL);
+ if (!tempbuffer) {
+ ret = -ENOMEM;
+ goto free_tuple;
+ }
+
+ memset(&tuple, 0, sizeof(tuple_t));
+
+ tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
+ tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+ tuple.TupleOffset = 0;
+
+ status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple);
+ while (!status) {
+ tuple.TupleData = tuplebuffer;
+ tuple.TupleDataMax = 255;
+ memset(tuplebuffer, 0, sizeof(u_char) * 255);
+
+ status = pccard_get_tuple_data(s, &tuple);
+ if (status)
+ break;
+
+ if (off < (pointer + 2 + tuple.TupleDataLen)) {
+ tempbuffer[0] = tuple.TupleCode & 0xff;
+ tempbuffer[1] = tuple.TupleLink & 0xff;
+ for (i = 0; i < tuple.TupleDataLen; i++)
+ tempbuffer[i + 2] = tuplebuffer[i] & 0xff;
+
+ for (i = 0; i < (2 + tuple.TupleDataLen); i++) {
+ if (((i + pointer) >= off) &&
+ (i + pointer) < (off + count)) {
+ buf[ret] = tempbuffer[i];
+ ret++;
+ }
+ }
+ }
+
+ pointer += 2 + tuple.TupleDataLen;
+
+ if (pointer >= (off + count))
+ break;
+
+ if (tuple.TupleCode == CISTPL_END)
+ break;
+ status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple);
+ }
+
+ kfree(tempbuffer);
+ free_tuple:
+ kfree(tuplebuffer);
+
+ return ret;
+}
+
+
+static ssize_t pccard_show_cis(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ unsigned int size = 0x200;
+
+ if (off >= size)
+ count = 0;
+ else {
+ struct pcmcia_socket *s;
+ unsigned int chains;
+
+ if (off + count > size)
+ count = size - off;
+
+ s = to_socket(container_of(kobj, struct device, kobj));
+
+ if (!(s->state & SOCKET_PRESENT))
+ return -ENODEV;
+ if (pccard_validate_cis(s, &chains))
+ return -EIO;
+ if (!chains)
+ return -ENODATA;
+
+ count = pccard_extract_cis(s, buf, off, count);
+ }
+
+ return count;
+}
+
+
+static ssize_t pccard_store_cis(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct pcmcia_socket *s;
+ int error;
+
+ s = to_socket(container_of(kobj, struct device, kobj));
+
+ if (off)
+ return -EINVAL;
+
+ if (count >= CISTPL_MAX_CIS_SIZE)
+ return -EINVAL;
+
+ if (!(s->state & SOCKET_PRESENT))
+ return -ENODEV;
+
+ error = pcmcia_replace_cis(s, buf, count);
+ if (error)
+ return -EIO;
+
+ pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
+
+ return count;
+}
+
+
+struct bin_attribute pccard_cis_attr = {
+ .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR },
+ .size = 0x200,
+ .read = pccard_show_cis,
+ .write = pccard_store_cis,
+};
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 6d6f82b38a68..e679e708db63 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -140,19 +140,13 @@ struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt)
struct device *dev = get_device(&skt->dev);
if (!dev)
return NULL;
- skt = dev_get_drvdata(dev);
- if (!try_module_get(skt->owner)) {
- put_device(&skt->dev);
- return NULL;
- }
- return skt;
+ return dev_get_drvdata(dev);
}
EXPORT_SYMBOL(pcmcia_get_socket);
void pcmcia_put_socket(struct pcmcia_socket *skt)
{
- module_put(skt->owner);
put_device(&skt->dev);
}
EXPORT_SYMBOL(pcmcia_put_socket);
@@ -181,8 +175,6 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
dev_dbg(&socket->dev, "pcmcia_register_socket(0x%p)\n", socket->ops);
- spin_lock_init(&socket->lock);
-
/* try to obtain a socket number [yes, it gets ugly if we
* register more than 2^sizeof(unsigned int) pcmcia
* sockets... but the socket number is deprecated
@@ -228,10 +220,13 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
init_completion(&socket->socket_released);
init_completion(&socket->thread_done);
mutex_init(&socket->skt_mutex);
+ mutex_init(&socket->ops_mutex);
spin_lock_init(&socket->thread_lock);
if (socket->resource_ops->init) {
+ mutex_lock(&socket->ops_mutex);
ret = socket->resource_ops->init(socket);
+ mutex_unlock(&socket->ops_mutex);
if (ret)
goto err;
}
@@ -283,15 +278,17 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket)
if (socket->thread)
kthread_stop(socket->thread);
- release_cis_mem(socket);
-
/* remove from our own list */
down_write(&pcmcia_socket_list_rwsem);
list_del(&socket->socket_list);
up_write(&pcmcia_socket_list_rwsem);
/* wait for sysfs to drop all references */
- release_resource_db(socket);
+ if (socket->resource_ops->exit) {
+ mutex_lock(&socket->ops_mutex);
+ socket->resource_ops->exit(socket);
+ mutex_unlock(&socket->ops_mutex);
+ }
wait_for_completion(&socket->socket_released);
} /* pcmcia_unregister_socket */
EXPORT_SYMBOL(pcmcia_unregister_socket);
@@ -328,7 +325,7 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority)
{
int ret;
- if (s->state & SOCKET_CARDBUS)
+ if ((s->state & SOCKET_CARDBUS) && (event != CS_EVENT_CARD_REMOVAL))
return 0;
dev_dbg(&s->dev, "send_event(event %d, pri %d, callback 0x%p)\n",
@@ -346,13 +343,6 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority)
return ret;
}
-static void socket_remove_drivers(struct pcmcia_socket *skt)
-{
- dev_dbg(&skt->dev, "remove_drivers\n");
-
- send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
-}
-
static int socket_reset(struct pcmcia_socket *skt)
{
int status, i;
@@ -395,7 +385,9 @@ static void socket_shutdown(struct pcmcia_socket *s)
dev_dbg(&s->dev, "shutdown\n");
- socket_remove_drivers(s);
+ send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
+
+ mutex_lock(&s->ops_mutex);
s->state &= SOCKET_INUSE | SOCKET_PRESENT;
msleep(shutdown_delay * 10);
s->state &= SOCKET_INUSE;
@@ -406,11 +398,21 @@ static void socket_shutdown(struct pcmcia_socket *s)
s->ops->set_socket(s, &s->socket);
s->irq.AssignedIRQ = s->irq.Config = 0;
s->lock_count = 0;
- destroy_cis_cache(s);
+ kfree(s->fake_cis);
+ s->fake_cis = NULL;
+ s->functions = 0;
+
+ /* From here on we can be sure that only we (that is, the
+ * pccardd thread) accesses this socket, and all (16-bit)
+ * PCMCIA interactions are gone. Therefore, release
+ * ops_mutex so that we don't get a sysfs-related lockdep
+ * warning.
+ */
+ mutex_unlock(&s->ops_mutex);
+
#ifdef CONFIG_CARDBUS
cb_free(s);
#endif
- s->functions = 0;
/* give socket some time to power down */
msleep(100);
@@ -421,7 +423,7 @@ static void socket_shutdown(struct pcmcia_socket *s)
"*** DANGER *** unable to remove socket power\n");
}
- cs_socket_put(s);
+ s->state &= ~SOCKET_INUSE;
}
static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
@@ -460,7 +462,8 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
return -EINVAL;
}
skt->state |= SOCKET_CARDBUS;
- }
+ } else
+ skt->state &= ~SOCKET_CARDBUS;
/*
* Decode the card voltage requirements, and apply power to the card.
@@ -509,8 +512,12 @@ static int socket_insert(struct pcmcia_socket *skt)
dev_dbg(&skt->dev, "insert\n");
- if (!cs_socket_get(skt))
- return -ENODEV;
+ mutex_lock(&skt->ops_mutex);
+ if (skt->state & SOCKET_INUSE) {
+ mutex_unlock(&skt->ops_mutex);
+ return -EINVAL;
+ }
+ skt->state |= SOCKET_INUSE;
ret = socket_setup(skt, setup_delay);
if (ret == 0) {
@@ -528,9 +535,11 @@ static int socket_insert(struct pcmcia_socket *skt)
}
#endif
dev_dbg(&skt->dev, "insert done\n");
+ mutex_unlock(&skt->ops_mutex);
send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
} else {
+ mutex_unlock(&skt->ops_mutex);
socket_shutdown(skt);
}
@@ -542,58 +551,66 @@ static int socket_suspend(struct pcmcia_socket *skt)
if (skt->state & SOCKET_SUSPEND)
return -EBUSY;
+ mutex_lock(&skt->ops_mutex);
+ skt->suspended_state = skt->state;
+
send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
skt->socket = dead_socket;
skt->ops->set_socket(skt, &skt->socket);
if (skt->ops->suspend)
skt->ops->suspend(skt);
skt->state |= SOCKET_SUSPEND;
-
+ mutex_unlock(&skt->ops_mutex);
return 0;
}
static int socket_early_resume(struct pcmcia_socket *skt)
{
+ mutex_lock(&skt->ops_mutex);
skt->socket = dead_socket;
skt->ops->init(skt);
skt->ops->set_socket(skt, &skt->socket);
if (skt->state & SOCKET_PRESENT)
skt->resume_status = socket_setup(skt, resume_delay);
+ mutex_unlock(&skt->ops_mutex);
return 0;
}
static int socket_late_resume(struct pcmcia_socket *skt)
{
- if (!(skt->state & SOCKET_PRESENT)) {
- skt->state &= ~SOCKET_SUSPEND;
+ mutex_lock(&skt->ops_mutex);
+ skt->state &= ~SOCKET_SUSPEND;
+ mutex_unlock(&skt->ops_mutex);
+
+ if (!(skt->state & SOCKET_PRESENT))
return socket_insert(skt);
+
+ if (skt->resume_status) {
+ socket_shutdown(skt);
+ return 0;
}
- if (skt->resume_status == 0) {
- /*
- * FIXME: need a better check here for cardbus cards.
- */
- if (verify_cis_cache(skt) != 0) {
- dev_dbg(&skt->dev, "cis mismatch - different card\n");
- socket_remove_drivers(skt);
- destroy_cis_cache(skt);
- /*
- * Workaround: give DS time to schedule removal.
- * Remove me once the 100ms delay is eliminated
- * in ds.c
- */
- msleep(200);
- send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
- } else {
- dev_dbg(&skt->dev, "cis matches cache\n");
- send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
- }
- } else {
+ if (skt->suspended_state != skt->state) {
+ dev_dbg(&skt->dev,
+ "suspend state 0x%x != resume state 0x%x\n",
+ skt->suspended_state, skt->state);
+
socket_shutdown(skt);
+ return socket_insert(skt);
}
- skt->state &= ~SOCKET_SUSPEND;
+#ifdef CONFIG_CARDBUS
+ if (skt->state & SOCKET_CARDBUS) {
+ /* We can't be sure the CardBus card is the same
+ * as the one previously inserted. Therefore, remove
+ * and re-add... */
+ cb_free(skt);
+ cb_alloc(skt);
+ return 0;
+ }
+#endif
+ send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
return 0;
}
@@ -672,20 +689,26 @@ static int pccardd(void *__skt)
complete(&skt->thread_done);
+ /* wait for userspace to catch up */
+ msleep(250);
+
set_freezable();
for (;;) {
unsigned long flags;
unsigned int events;
+ unsigned int sysfs_events;
set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&skt->thread_lock, flags);
events = skt->thread_events;
skt->thread_events = 0;
+ sysfs_events = skt->sysfs_events;
+ skt->sysfs_events = 0;
spin_unlock_irqrestore(&skt->thread_lock, flags);
+ mutex_lock(&skt->skt_mutex);
if (events) {
- mutex_lock(&skt->skt_mutex);
if (events & SS_DETECT)
socket_detect_change(skt);
if (events & SS_BATDEAD)
@@ -694,10 +717,39 @@ static int pccardd(void *__skt)
send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
if (events & SS_READY)
send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
- mutex_unlock(&skt->skt_mutex);
- continue;
}
+ if (sysfs_events) {
+ if (sysfs_events & PCMCIA_UEVENT_EJECT)
+ socket_remove(skt);
+ if (sysfs_events & PCMCIA_UEVENT_INSERT)
+ socket_insert(skt);
+ if ((sysfs_events & PCMCIA_UEVENT_RESUME) &&
+ !(skt->state & SOCKET_CARDBUS)) {
+ ret = socket_resume(skt);
+ if (!ret && skt->callback)
+ skt->callback->resume(skt);
+ }
+ if ((sysfs_events & PCMCIA_UEVENT_SUSPEND) &&
+ !(skt->state & SOCKET_CARDBUS)) {
+ if (skt->callback)
+ ret = skt->callback->suspend(skt);
+ else
+ ret = 0;
+ if (!ret)
+ socket_suspend(skt);
+ }
+ if ((sysfs_events & PCMCIA_UEVENT_REQUERY) &&
+ !(skt->state & SOCKET_CARDBUS)) {
+ if (!ret && skt->callback)
+ skt->callback->requery(skt);
+ }
+ }
+ mutex_unlock(&skt->skt_mutex);
+
+ if (events || sysfs_events)
+ continue;
+
if (kthread_should_stop())
break;
@@ -707,6 +759,13 @@ static int pccardd(void *__skt)
/* make sure we are running before we exit */
set_current_state(TASK_RUNNING);
+ /* shut down socket, if a device is still present */
+ if (skt->state & SOCKET_PRESENT) {
+ mutex_lock(&skt->skt_mutex);
+ socket_remove(skt);
+ mutex_unlock(&skt->skt_mutex);
+ }
+
/* remove from the device core */
pccard_sysfs_remove_socket(&skt->dev);
device_unregister(&skt->dev);
@@ -732,6 +791,31 @@ void pcmcia_parse_events(struct pcmcia_socket *s, u_int events)
} /* pcmcia_parse_events */
EXPORT_SYMBOL(pcmcia_parse_events);
+/**
+ * pcmcia_parse_uevents() - tell pccardd to issue manual commands
+ * @s: the PCMCIA socket we wan't to command
+ * @events: events to pass to pccardd
+ *
+ * userspace-issued insert, eject, suspend and resume commands must be
+ * handled by pccardd to avoid any sysfs-related deadlocks. Valid events
+ * are PCMCIA_UEVENT_EJECT (for eject), PCMCIA_UEVENT__INSERT (for insert),
+ * PCMCIA_UEVENT_RESUME (for resume), PCMCIA_UEVENT_SUSPEND (for suspend)
+ * and PCMCIA_UEVENT_REQUERY (for re-querying the PCMCIA card).
+ */
+void pcmcia_parse_uevents(struct pcmcia_socket *s, u_int events)
+{
+ unsigned long flags;
+ dev_dbg(&s->dev, "parse_uevents: events %08x\n", events);
+ if (s->thread) {
+ spin_lock_irqsave(&s->thread_lock, flags);
+ s->sysfs_events |= events;
+ spin_unlock_irqrestore(&s->thread_lock, flags);
+
+ wake_up_process(s->thread);
+ }
+}
+EXPORT_SYMBOL(pcmcia_parse_uevents);
+
/* register pcmcia_callback */
int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
@@ -796,7 +880,10 @@ int pcmcia_reset_card(struct pcmcia_socket *skt)
send_event(skt, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
if (skt->callback)
skt->callback->suspend(skt);
- if (socket_reset(skt) == 0) {
+ mutex_lock(&skt->ops_mutex);
+ ret = socket_reset(skt);
+ mutex_unlock(&skt->ops_mutex);
+ if (ret == 0) {
send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
if (skt->callback)
skt->callback->resume(skt);
@@ -812,121 +899,6 @@ int pcmcia_reset_card(struct pcmcia_socket *skt)
EXPORT_SYMBOL(pcmcia_reset_card);
-/* These shut down or wake up a socket. They are sort of user
- * initiated versions of the APM suspend and resume actions.
- */
-int pcmcia_suspend_card(struct pcmcia_socket *skt)
-{
- int ret;
-
- dev_dbg(&skt->dev, "suspending socket\n");
-
- mutex_lock(&skt->skt_mutex);
- do {
- if (!(skt->state & SOCKET_PRESENT)) {
- ret = -ENODEV;
- break;
- }
- if (skt->state & SOCKET_CARDBUS) {
- ret = -EPERM;
- break;
- }
- if (skt->callback) {
- ret = skt->callback->suspend(skt);
- if (ret)
- break;
- }
- ret = socket_suspend(skt);
- } while (0);
- mutex_unlock(&skt->skt_mutex);
-
- return ret;
-} /* suspend_card */
-EXPORT_SYMBOL(pcmcia_suspend_card);
-
-
-int pcmcia_resume_card(struct pcmcia_socket *skt)
-{
- int ret;
-
- dev_dbg(&skt->dev, "waking up socket\n");
-
- mutex_lock(&skt->skt_mutex);
- do {
- if (!(skt->state & SOCKET_PRESENT)) {
- ret = -ENODEV;
- break;
- }
- if (skt->state & SOCKET_CARDBUS) {
- ret = -EPERM;
- break;
- }
- ret = socket_resume(skt);
- if (!ret && skt->callback)
- skt->callback->resume(skt);
- } while (0);
- mutex_unlock(&skt->skt_mutex);
-
- return ret;
-} /* resume_card */
-EXPORT_SYMBOL(pcmcia_resume_card);
-
-
-/* These handle user requests to eject or insert a card. */
-int pcmcia_eject_card(struct pcmcia_socket *skt)
-{
- int ret;
-
- dev_dbg(&skt->dev, "user eject request\n");
-
- mutex_lock(&skt->skt_mutex);
- do {
- if (!(skt->state & SOCKET_PRESENT)) {
- ret = -ENODEV;
- break;
- }
-
- ret = send_event(skt, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW);
- if (ret != 0) {
- ret = -EINVAL;
- break;
- }
-
- socket_remove(skt);
- ret = 0;
- } while (0);
- mutex_unlock(&skt->skt_mutex);
-
- return ret;
-} /* eject_card */
-EXPORT_SYMBOL(pcmcia_eject_card);
-
-
-int pcmcia_insert_card(struct pcmcia_socket *skt)
-{
- int ret;
-
- dev_dbg(&skt->dev, "user insert request\n");
-
- mutex_lock(&skt->skt_mutex);
- do {
- if (skt->state & SOCKET_PRESENT) {
- ret = -EBUSY;
- break;
- }
- if (socket_insert(skt) == -ENODEV) {
- ret = -ENODEV;
- break;
- }
- ret = 0;
- } while (0);
- mutex_unlock(&skt->skt_mutex);
-
- return ret;
-} /* insert_card */
-EXPORT_SYMBOL(pcmcia_insert_card);
-
-
static int pcmcia_socket_uevent(struct device *dev,
struct kobj_uevent_env *env)
{
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 3bc02d53a3a3..f95864c2191e 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -87,37 +87,11 @@ struct pccard_resource_ops {
#define SOCKET_CARDBUS 0x8000
#define SOCKET_CARDBUS_CONFIG 0x10000
-static inline int cs_socket_get(struct pcmcia_socket *skt)
-{
- int ret;
-
- WARN_ON(skt->state & SOCKET_INUSE);
-
- ret = try_module_get(skt->owner);
- if (ret)
- skt->state |= SOCKET_INUSE;
- return ret;
-}
-
-static inline void cs_socket_put(struct pcmcia_socket *skt)
-{
- if (skt->state & SOCKET_INUSE) {
- skt->state &= ~SOCKET_INUSE;
- module_put(skt->owner);
- }
-}
-
/*
* Stuff internal to module "pcmcia_core":
*/
-/* cistpl.c */
-int verify_cis_cache(struct pcmcia_socket *s);
-
-/* rsrc_mgr.c */
-void release_resource_db(struct pcmcia_socket *s);
-
/* socket_sysfs.c */
extern int pccard_sysfs_add_socket(struct device *dev);
extern void pccard_sysfs_remove_socket(struct device *dev);
@@ -125,8 +99,6 @@ extern void pccard_sysfs_remove_socket(struct device *dev);
/* cardbus.c */
int cb_alloc(struct pcmcia_socket *s);
void cb_free(struct pcmcia_socket *s);
-int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len,
- void *ptr);
@@ -138,7 +110,8 @@ struct pcmcia_callback{
struct module *owner;
int (*event) (struct pcmcia_socket *s,
event_t event, int priority);
- void (*requery) (struct pcmcia_socket *s, int new_cis);
+ void (*requery) (struct pcmcia_socket *s);
+ int (*validate) (struct pcmcia_socket *s, unsigned int *i);
int (*suspend) (struct pcmcia_socket *s);
int (*resume) (struct pcmcia_socket *s);
};
@@ -151,16 +124,35 @@ extern struct class pcmcia_socket_class;
int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr);
-int pcmcia_suspend_card(struct pcmcia_socket *skt);
-int pcmcia_resume_card(struct pcmcia_socket *skt);
-
-int pcmcia_eject_card(struct pcmcia_socket *skt);
-int pcmcia_insert_card(struct pcmcia_socket *skt);
+void pcmcia_parse_uevents(struct pcmcia_socket *socket, unsigned int events);
+#define PCMCIA_UEVENT_EJECT 0x0001
+#define PCMCIA_UEVENT_INSERT 0x0002
+#define PCMCIA_UEVENT_SUSPEND 0x0004
+#define PCMCIA_UEVENT_RESUME 0x0008
+#define PCMCIA_UEVENT_REQUERY 0x0010
struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt);
void pcmcia_put_socket(struct pcmcia_socket *skt);
+/*
+ * Stuff internal to module "pcmcia".
+ */
+/* ds.c */
+extern struct bus_type pcmcia_bus_type;
+
+/* pcmcia_resource.c */
+extern int pcmcia_release_configuration(struct pcmcia_device *p_dev);
+extern int pcmcia_validate_mem(struct pcmcia_socket *s);
+extern struct resource *pcmcia_find_mem_region(u_long base,
+ u_long num,
+ u_long align,
+ int low,
+ struct pcmcia_socket *s);
+
+
/* cistpl.c */
+extern struct bin_attribute pccard_cis_attr;
+
int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr,
u_int addr, u_int len, void *ptr);
void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr,
@@ -172,8 +164,8 @@ int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function,
int pcmcia_replace_cis(struct pcmcia_socket *s,
const u8 *data, const size_t len);
int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *count);
+int verify_cis_cache(struct pcmcia_socket *s);
-/* loop over CIS entries */
int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function,
cisdata_t code, cisparse_t *parse, void *priv_data,
int (*loop_tuple) (tuple_t *tuple,
@@ -189,35 +181,8 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function,
int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple);
-/* rsrc_mgr.c */
-int pcmcia_validate_mem(struct pcmcia_socket *s);
-struct resource *pcmcia_find_io_region(unsigned long base,
- int num,
- unsigned long align,
- struct pcmcia_socket *s);
-int pcmcia_adjust_io_region(struct resource *res,
- unsigned long r_start,
- unsigned long r_end,
- struct pcmcia_socket *s);
-struct resource *pcmcia_find_mem_region(u_long base,
- u_long num,
- u_long align,
- int low,
- struct pcmcia_socket *s);
-
-/*
- * Stuff internal to module "pcmcia".
- */
-/* ds.c */
-extern struct bus_type pcmcia_bus_type;
-
-/* pcmcia_resource.c */
-extern int pcmcia_release_configuration(struct pcmcia_device *p_dev);
-
#ifdef CONFIG_PCMCIA_IOCTL
/* ds.c */
-extern spinlock_t pcmcia_dev_list_lock;
-
extern struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev);
extern void pcmcia_put_dev(struct pcmcia_device *p_dev);
diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c
new file mode 100644
index 000000000000..9254ab0b29b1
--- /dev/null
+++ b/drivers/pcmcia/db1xxx_ss.c
@@ -0,0 +1,612 @@
+/*
+ * PCMCIA socket code for the Alchemy Db1xxx/Pb1xxx boards.
+ *
+ * Copyright (c) 2009 Manuel Lauss <manuel.lauss@gmail.com>
+ *
+ */
+
+/* This is a fairly generic PCMCIA socket driver suitable for the
+ * following Alchemy Development boards:
+ * Db1000, Db/Pb1500, Db/Pb1100, Db/Pb1550, Db/Pb1200.
+ *
+ * The Db1000 is used as a reference: Per-socket card-, carddetect- and
+ * statuschange IRQs connected to SoC GPIOs, control and status register
+ * bits arranged in per-socket groups in an external PLD. All boards
+ * listed here use this layout, including bit positions and meanings.
+ * Of course there are exceptions in later boards:
+ *
+ * - Pb1100/Pb1500: single socket only; voltage key bits VS are
+ * at STATUS[5:4] (instead of STATUS[1:0]).
+ * - Au1200-based: additional card-eject irqs, irqs not gpios!
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/spinlock.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-db1x00/bcsr.h>
+
+#define MEM_MAP_SIZE 0x400000
+#define IO_MAP_SIZE 0x1000
+
+struct db1x_pcmcia_sock {
+ struct pcmcia_socket socket;
+ int nr; /* socket number */
+ void *virt_io;
+
+ phys_addr_t phys_io;
+ phys_addr_t phys_attr;
+ phys_addr_t phys_mem;
+
+ /* previous flags for set_socket() */
+ unsigned int old_flags;
+
+ /* interrupt sources: linux irq numbers! */
+ int insert_irq; /* default carddetect irq */
+ int stschg_irq; /* card-status-change irq */
+ int card_irq; /* card irq */
+ int eject_irq; /* db1200/pb1200 have these */
+
+#define BOARD_TYPE_DEFAULT 0 /* most boards */
+#define BOARD_TYPE_DB1200 1 /* IRQs aren't gpios */
+#define BOARD_TYPE_PB1100 2 /* VS bits slightly different */
+ int board_type;
+};
+
+#define to_db1x_socket(x) container_of(x, struct db1x_pcmcia_sock, socket)
+
+/* DB/PB1200: check CPLD SIGSTATUS register bit 10/12 */
+static int db1200_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+ unsigned short sigstat;
+
+ sigstat = bcsr_read(BCSR_SIGSTAT);
+ return sigstat & 1 << (8 + 2 * sock->nr);
+}
+
+/* carddetect gpio: low-active */
+static int db1000_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+ return !gpio_get_value(irq_to_gpio(sock->insert_irq));
+}
+
+static int db1x_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+ switch (sock->board_type) {
+ case BOARD_TYPE_DB1200:
+ return db1200_card_inserted(sock);
+ default:
+ return db1000_card_inserted(sock);
+ }
+}
+
+/* STSCHG tends to bounce heavily when cards are inserted/ejected.
+ * To avoid this, the interrupt is normally disabled and only enabled
+ * after reset to a card has been de-asserted.
+ */
+static inline void set_stschg(struct db1x_pcmcia_sock *sock, int en)
+{
+ if (sock->stschg_irq != -1) {
+ if (en)
+ enable_irq(sock->stschg_irq);
+ else
+ disable_irq(sock->stschg_irq);
+ }
+}
+
+static irqreturn_t db1000_pcmcia_cdirq(int irq, void *data)
+{
+ struct db1x_pcmcia_sock *sock = data;
+
+ pcmcia_parse_events(&sock->socket, SS_DETECT);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t db1000_pcmcia_stschgirq(int irq, void *data)
+{
+ struct db1x_pcmcia_sock *sock = data;
+
+ pcmcia_parse_events(&sock->socket, SS_STSCHG);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t db1200_pcmcia_cdirq(int irq, void *data)
+{
+ struct db1x_pcmcia_sock *sock = data;
+
+ /* Db/Pb1200 have separate per-socket insertion and ejection
+ * interrupts which stay asserted as long as the card is
+ * inserted/missing. The one which caused us to be called
+ * needs to be disabled and the other one enabled.
+ */
+ if (irq == sock->insert_irq) {
+ disable_irq_nosync(sock->insert_irq);
+ enable_irq(sock->eject_irq);
+ } else {
+ disable_irq_nosync(sock->eject_irq);
+ enable_irq(sock->insert_irq);
+ }
+
+ pcmcia_parse_events(&sock->socket, SS_DETECT);
+
+ return IRQ_HANDLED;
+}
+
+static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
+{
+ int ret;
+ unsigned long flags;
+
+ if (sock->stschg_irq != -1) {
+ ret = request_irq(sock->stschg_irq, db1000_pcmcia_stschgirq,
+ 0, "pcmcia_stschg", sock);
+ if (ret)
+ return ret;
+ }
+
+ /* Db/Pb1200 have separate per-socket insertion and ejection
+ * interrupts, which should show edge behaviour but don't.
+ * So interrupts are disabled until both insertion and
+ * ejection handler have been registered and the currently
+ * active one disabled.
+ */
+ if (sock->board_type == BOARD_TYPE_DB1200) {
+ local_irq_save(flags);
+
+ ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq,
+ IRQF_DISABLED, "pcmcia_insert", sock);
+ if (ret)
+ goto out1;
+
+ ret = request_irq(sock->eject_irq, db1200_pcmcia_cdirq,
+ IRQF_DISABLED, "pcmcia_eject", sock);
+ if (ret) {
+ free_irq(sock->insert_irq, sock);
+ local_irq_restore(flags);
+ goto out1;
+ }
+
+ /* disable the currently active one */
+ if (db1200_card_inserted(sock))
+ disable_irq_nosync(sock->insert_irq);
+ else
+ disable_irq_nosync(sock->eject_irq);
+
+ local_irq_restore(flags);
+ } else {
+ /* all other (older) Db1x00 boards use a GPIO to show
+ * card detection status: use both-edge triggers.
+ */
+ set_irq_type(sock->insert_irq, IRQ_TYPE_EDGE_BOTH);
+ ret = request_irq(sock->insert_irq, db1000_pcmcia_cdirq,
+ 0, "pcmcia_carddetect", sock);
+
+ if (ret)
+ goto out1;
+ }
+
+ return 0; /* all done */
+
+out1:
+ if (sock->stschg_irq != -1)
+ free_irq(sock->stschg_irq, sock);
+
+ return ret;
+}
+
+static void db1x_pcmcia_free_irqs(struct db1x_pcmcia_sock *sock)
+{
+ if (sock->stschg_irq != -1)
+ free_irq(sock->stschg_irq, sock);
+
+ free_irq(sock->insert_irq, sock);
+ if (sock->eject_irq != -1)
+ free_irq(sock->eject_irq, sock);
+}
+
+/*
+ * configure a PCMCIA socket on the Db1x00 series of boards (and
+ * compatibles).
+ *
+ * 2 external registers are involved:
+ * pcmcia_status (offset 0x04): bits [0:1/2:3]: read card voltage id
+ * pcmcia_control(offset 0x10):
+ * bits[0:1] set vcc for card
+ * bits[2:3] set vpp for card
+ * bit 4: enable data buffers
+ * bit 7: reset# for card
+ * add 8 for second socket.
+ */
+static int db1x_pcmcia_configure(struct pcmcia_socket *skt,
+ struct socket_state_t *state)
+{
+ struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+ unsigned short cr_clr, cr_set;
+ unsigned int changed;
+ int v, p, ret;
+
+ /* card voltage setup */
+ cr_clr = (0xf << (sock->nr * 8)); /* clear voltage settings */
+ cr_set = 0;
+ v = p = ret = 0;
+
+ switch (state->Vcc) {
+ case 50:
+ ++v;
+ case 33:
+ ++v;
+ case 0:
+ break;
+ default:
+ printk(KERN_INFO "pcmcia%d unsupported Vcc %d\n",
+ sock->nr, state->Vcc);
+ }
+
+ switch (state->Vpp) {
+ case 12:
+ ++p;
+ case 33:
+ case 50:
+ ++p;
+ case 0:
+ break;
+ default:
+ printk(KERN_INFO "pcmcia%d unsupported Vpp %d\n",
+ sock->nr, state->Vpp);
+ }
+
+ /* sanity check: Vpp must be 0, 12, or Vcc */
+ if (((state->Vcc == 33) && (state->Vpp == 50)) ||
+ ((state->Vcc == 50) && (state->Vpp == 33))) {
+ printk(KERN_INFO "pcmcia%d bad Vcc/Vpp combo (%d %d)\n",
+ sock->nr, state->Vcc, state->Vpp);
+ v = p = 0;
+ ret = -EINVAL;
+ }
+
+ /* create new voltage code */
+ cr_set |= ((v << 2) | p) << (sock->nr * 8);
+
+ changed = state->flags ^ sock->old_flags;
+
+ if (changed & SS_RESET) {
+ if (state->flags & SS_RESET) {
+ set_stschg(sock, 0);
+ /* assert reset, disable io buffers */
+ cr_clr |= (1 << (7 + (sock->nr * 8)));
+ cr_clr |= (1 << (4 + (sock->nr * 8)));
+ } else {
+ /* de-assert reset, enable io buffers */
+ cr_set |= 1 << (7 + (sock->nr * 8));
+ cr_set |= 1 << (4 + (sock->nr * 8));
+ }
+ }
+
+ /* update PCMCIA configuration */
+ bcsr_mod(BCSR_PCMCIA, cr_clr, cr_set);
+
+ sock->old_flags = state->flags;
+
+ /* reset was taken away: give card time to initialize properly */
+ if ((changed & SS_RESET) && !(state->flags & SS_RESET)) {
+ msleep(500);
+ set_stschg(sock, 1);
+ }
+
+ return ret;
+}
+
+/* VCC bits at [3:2]/[11:10] */
+#define GET_VCC(cr, socknr) \
+ ((((cr) >> 2) >> ((socknr) * 8)) & 3)
+
+/* VS bits at [0:1]/[3:2] */
+#define GET_VS(sr, socknr) \
+ (((sr) >> (2 * (socknr))) & 3)
+
+/* reset bits at [7]/[15] */
+#define GET_RESET(cr, socknr) \
+ ((cr) & (1 << (7 + (8 * (socknr)))))
+
+static int db1x_pcmcia_get_status(struct pcmcia_socket *skt,
+ unsigned int *value)
+{
+ struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+ unsigned short cr, sr;
+ unsigned int status;
+
+ status = db1x_card_inserted(sock) ? SS_DETECT : 0;
+
+ cr = bcsr_read(BCSR_PCMCIA);
+ sr = bcsr_read(BCSR_STATUS);
+
+ /* PB1100/PB1500: voltage key bits are at [5:4] */
+ if (sock->board_type == BOARD_TYPE_PB1100)
+ sr >>= 4;
+
+ /* determine card type */
+ switch (GET_VS(sr, sock->nr)) {
+ case 0:
+ case 2:
+ status |= SS_3VCARD; /* 3V card */
+ case 3:
+ break; /* 5V card: set nothing */
+ default:
+ status |= SS_XVCARD; /* treated as unsupported in core */
+ }
+
+ /* if Vcc is not zero, we have applied power to a card */
+ status |= GET_VCC(cr, sock->nr) ? SS_POWERON : 0;
+
+ /* reset de-asserted? then we're ready */
+ status |= (GET_RESET(cr, sock->nr)) ? SS_READY : SS_RESET;
+
+ *value = status;
+
+ return 0;
+}
+
+static int db1x_pcmcia_sock_init(struct pcmcia_socket *skt)
+{
+ return 0;
+}
+
+static int db1x_pcmcia_sock_suspend(struct pcmcia_socket *skt)
+{
+ return 0;
+}
+
+static int au1x00_pcmcia_set_io_map(struct pcmcia_socket *skt,
+ struct pccard_io_map *map)
+{
+ struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+
+ map->start = (u32)sock->virt_io;
+ map->stop = map->start + IO_MAP_SIZE;
+
+ return 0;
+}
+
+static int au1x00_pcmcia_set_mem_map(struct pcmcia_socket *skt,
+ struct pccard_mem_map *map)
+{
+ struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+
+ if (map->flags & MAP_ATTRIB)
+ map->static_start = sock->phys_attr + map->card_start;
+ else
+ map->static_start = sock->phys_mem + map->card_start;
+
+ return 0;
+}
+
+static struct pccard_operations db1x_pcmcia_operations = {
+ .init = db1x_pcmcia_sock_init,
+ .suspend = db1x_pcmcia_sock_suspend,
+ .get_status = db1x_pcmcia_get_status,
+ .set_socket = db1x_pcmcia_configure,
+ .set_io_map = au1x00_pcmcia_set_io_map,
+ .set_mem_map = au1x00_pcmcia_set_mem_map,
+};
+
+static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev)
+{
+ struct db1x_pcmcia_sock *sock;
+ struct resource *r;
+ int ret, bid;
+
+ sock = kzalloc(sizeof(struct db1x_pcmcia_sock), GFP_KERNEL);
+ if (!sock)
+ return -ENOMEM;
+
+ sock->nr = pdev->id;
+
+ bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
+ switch (bid) {
+ case BCSR_WHOAMI_PB1500:
+ case BCSR_WHOAMI_PB1500R2:
+ case BCSR_WHOAMI_PB1100:
+ sock->board_type = BOARD_TYPE_PB1100;
+ break;
+ case BCSR_WHOAMI_DB1000 ... BCSR_WHOAMI_PB1550_SDR:
+ sock->board_type = BOARD_TYPE_DEFAULT;
+ break;
+ case BCSR_WHOAMI_PB1200 ... BCSR_WHOAMI_DB1200:
+ sock->board_type = BOARD_TYPE_DB1200;
+ break;
+ default:
+ printk(KERN_INFO "db1xxx-ss: unknown board %d!\n", bid);
+ ret = -ENODEV;
+ goto out0;
+ };
+
+ /*
+ * gather resources necessary and optional nice-to-haves to
+ * operate a socket:
+ * This includes IRQs for Carddetection/ejection, the card
+ * itself and optional status change detection.
+ * Also, the memory areas covered by a socket. For these
+ * we require the real 36bit addresses (see the au1000.h
+ * header for more information).
+ */
+
+ /* card: irq assigned to the card itself. */
+ r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "card");
+ sock->card_irq = r ? r->start : 0;
+
+ /* insert: irq which triggers on card insertion/ejection */
+ r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "insert");
+ sock->insert_irq = r ? r->start : -1;
+
+ /* stschg: irq which trigger on card status change (optional) */
+ r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "stschg");
+ sock->stschg_irq = r ? r->start : -1;
+
+ /* eject: irq which triggers on ejection (DB1200/PB1200 only) */
+ r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "eject");
+ sock->eject_irq = r ? r->start : -1;
+
+ ret = -ENODEV;
+
+ /* 36bit PCMCIA Attribute area address */
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-attr");
+ if (!r) {
+ printk(KERN_ERR "pcmcia%d has no 'pseudo-attr' resource!\n",
+ sock->nr);
+ goto out0;
+ }
+ sock->phys_attr = r->start;
+
+ /* 36bit PCMCIA Memory area address */
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-mem");
+ if (!r) {
+ printk(KERN_ERR "pcmcia%d has no 'pseudo-mem' resource!\n",
+ sock->nr);
+ goto out0;
+ }
+ sock->phys_mem = r->start;
+
+ /* 36bit PCMCIA IO area address */
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-io");
+ if (!r) {
+ printk(KERN_ERR "pcmcia%d has no 'pseudo-io' resource!\n",
+ sock->nr);
+ goto out0;
+ }
+ sock->phys_io = r->start;
+
+ /*
+ * PCMCIA client drivers use the inb/outb macros to access
+ * the IO registers. Since mips_io_port_base is added
+ * to the access address of the mips implementation of
+ * inb/outb, we need to subtract it here because we want
+ * to access the I/O or MEM address directly, without
+ * going through this "mips_io_port_base" mechanism.
+ */
+ sock->virt_io = (void *)(ioremap(sock->phys_io, IO_MAP_SIZE) -
+ mips_io_port_base);
+
+ if (!sock->virt_io) {
+ printk(KERN_ERR "pcmcia%d: cannot remap IO area\n",
+ sock->nr);
+ ret = -ENOMEM;
+ goto out0;
+ }
+
+ sock->socket.ops = &db1x_pcmcia_operations;
+ sock->socket.owner = THIS_MODULE;
+ sock->socket.pci_irq = sock->card_irq;
+ sock->socket.features = SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+ sock->socket.map_size = MEM_MAP_SIZE;
+ sock->socket.io_offset = (unsigned long)sock->virt_io;
+ sock->socket.dev.parent = &pdev->dev;
+ sock->socket.resource_ops = &pccard_static_ops;
+
+ platform_set_drvdata(pdev, sock);
+
+ ret = db1x_pcmcia_setup_irqs(sock);
+ if (ret) {
+ printk(KERN_ERR "pcmcia%d cannot setup interrupts\n",
+ sock->nr);
+ goto out1;
+ }
+
+ set_stschg(sock, 0);
+
+ ret = pcmcia_register_socket(&sock->socket);
+ if (ret) {
+ printk(KERN_ERR "pcmcia%d failed to register\n", sock->nr);
+ goto out2;
+ }
+
+ printk(KERN_INFO "Alchemy Db/Pb1xxx pcmcia%d @ io/attr/mem %09llx"
+ "(%p) %09llx %09llx card/insert/stschg/eject irqs @ %d "
+ "%d %d %d\n", sock->nr, sock->phys_io, sock->virt_io,
+ sock->phys_attr, sock->phys_mem, sock->card_irq,
+ sock->insert_irq, sock->stschg_irq, sock->eject_irq);
+
+ return 0;
+
+out2:
+ db1x_pcmcia_free_irqs(sock);
+out1:
+ iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+out0:
+ kfree(sock);
+ return ret;
+}
+
+static int __devexit db1x_pcmcia_socket_remove(struct platform_device *pdev)
+{
+ struct db1x_pcmcia_sock *sock = platform_get_drvdata(pdev);
+
+ db1x_pcmcia_free_irqs(sock);
+ pcmcia_unregister_socket(&sock->socket);
+ iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+ kfree(sock);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int db1x_pcmcia_suspend(struct device *dev)
+{
+ return pcmcia_socket_dev_suspend(dev);
+}
+
+static int db1x_pcmcia_resume(struct device *dev)
+{
+ return pcmcia_socket_dev_resume(dev);
+}
+
+static struct dev_pm_ops db1x_pcmcia_pmops = {
+ .resume = db1x_pcmcia_resume,
+ .suspend = db1x_pcmcia_suspend,
+ .thaw = db1x_pcmcia_resume,
+ .freeze = db1x_pcmcia_suspend,
+};
+
+#define DB1XXX_SS_PMOPS &db1x_pcmcia_pmops
+
+#else
+
+#define DB1XXX_SS_PMOPS NULL
+
+#endif
+
+static struct platform_driver db1x_pcmcia_socket_driver = {
+ .driver = {
+ .name = "db1xxx_pcmcia",
+ .owner = THIS_MODULE,
+ .pm = DB1XXX_SS_PMOPS
+ },
+ .probe = db1x_pcmcia_socket_probe,
+ .remove = __devexit_p(db1x_pcmcia_socket_remove),
+};
+
+int __init db1x_pcmcia_socket_load(void)
+{
+ return platform_driver_register(&db1x_pcmcia_socket_driver);
+}
+
+void __exit db1x_pcmcia_socket_unload(void)
+{
+ platform_driver_unregister(&db1x_pcmcia_socket_driver);
+}
+
+module_init(db1x_pcmcia_socket_load);
+module_exit(db1x_pcmcia_socket_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCMCIA Socket Services for Alchemy Db/Pb1x00 boards");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 1a4a3c49cc15..ad93ebd7b2a2 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -42,8 +42,6 @@ MODULE_DESCRIPTION("PCMCIA Driver Services");
MODULE_LICENSE("GPL");
-spinlock_t pcmcia_dev_list_lock;
-
/*====================================================================*/
static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
@@ -126,9 +124,9 @@ pcmcia_store_new_id(struct device_driver *driver, const char *buf, size_t count)
dynid->id.device_no = device_no;
memcpy(dynid->id.prod_id_hash, prod_id_hash, sizeof(__u32) * 4);
- spin_lock(&pdrv->dynids.lock);
+ mutex_lock(&pdrv->dynids.lock);
list_add_tail(&dynid->node, &pdrv->dynids.list);
- spin_unlock(&pdrv->dynids.lock);
+ mutex_unlock(&pdrv->dynids.lock);
if (get_driver(&pdrv->drv)) {
retval = driver_attach(&pdrv->drv);
@@ -146,12 +144,12 @@ pcmcia_free_dynids(struct pcmcia_driver *drv)
{
struct pcmcia_dynid *dynid, *n;
- spin_lock(&drv->dynids.lock);
+ mutex_lock(&drv->dynids.lock);
list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
list_del(&dynid->node);
kfree(dynid);
}
- spin_unlock(&drv->dynids.lock);
+ mutex_unlock(&drv->dynids.lock);
}
static int
@@ -182,7 +180,7 @@ int pcmcia_register_driver(struct pcmcia_driver *driver)
/* initialize common fields */
driver->drv.bus = &pcmcia_bus_type;
driver->drv.owner = driver->owner;
- spin_lock_init(&driver->dynids.lock);
+ mutex_init(&driver->dynids.lock);
INIT_LIST_HEAD(&driver->dynids.list);
pr_debug("registering driver %s\n", driver->drv.name);
@@ -239,30 +237,21 @@ static void pcmcia_release_function(struct kref *ref)
static void pcmcia_release_dev(struct device *dev)
{
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+ int i;
dev_dbg(dev, "releasing device\n");
pcmcia_put_socket(p_dev->socket);
+ for (i = 0; i < 4; i++)
+ kfree(p_dev->prod_id[i]);
kfree(p_dev->devname);
kref_put(&p_dev->function_config->ref, pcmcia_release_function);
kfree(p_dev);
}
-static void pcmcia_add_device_later(struct pcmcia_socket *s, int mfc)
-{
- if (!s->pcmcia_state.device_add_pending) {
- dev_dbg(&s->dev, "scheduling to add %s secondary"
- " device to %d\n", mfc ? "mfc" : "pfc", s->sock);
- s->pcmcia_state.device_add_pending = 1;
- s->pcmcia_state.mfc_pfc = mfc;
- schedule_work(&s->device_add);
- }
- return;
-}
static int pcmcia_device_probe(struct device *dev)
{
struct pcmcia_device *p_dev;
struct pcmcia_driver *p_drv;
- struct pcmcia_device_id *did;
struct pcmcia_socket *s;
cistpl_config_t cis_config;
int ret = 0;
@@ -275,18 +264,6 @@ static int pcmcia_device_probe(struct device *dev)
p_drv = to_pcmcia_drv(dev->driver);
s = p_dev->socket;
- /* The PCMCIA code passes the match data in via dev_set_drvdata(dev)
- * which is an ugly hack. Once the driver probe is called it may
- * and often will overwrite the match data so we must save it first
- *
- * handle pseudo multifunction devices:
- * there are at most two pseudo multifunction devices.
- * if we're matching against the first, schedule a
- * call which will then check whether there are two
- * pseudo devices, and if not, add the second one.
- */
- did = dev_get_drvdata(&p_dev->dev);
-
dev_dbg(dev, "trying to bind to %s\n", p_drv->drv.name);
if ((!p_drv->probe) || (!p_dev->function_config) ||
@@ -315,9 +292,11 @@ static int pcmcia_device_probe(struct device *dev)
goto put_module;
}
- if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
+ mutex_lock(&s->ops_mutex);
+ if ((s->pcmcia_state.has_pfc) &&
(p_dev->socket->device_count == 1) && (p_dev->device_no == 0))
- pcmcia_add_device_later(p_dev->socket, 0);
+ pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
+ mutex_unlock(&s->ops_mutex);
put_module:
if (ret)
@@ -336,26 +315,27 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le
{
struct pcmcia_device *p_dev;
struct pcmcia_device *tmp;
- unsigned long flags;
dev_dbg(leftover ? &leftover->dev : &s->dev,
"pcmcia_card_remove(%d) %s\n", s->sock,
leftover ? leftover->devname : "");
+ mutex_lock(&s->ops_mutex);
if (!leftover)
s->device_count = 0;
else
s->device_count = 1;
+ mutex_unlock(&s->ops_mutex);
/* unregister all pcmcia_devices registered with this socket, except leftover */
list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) {
if (p_dev == leftover)
continue;
- spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ mutex_lock(&s->ops_mutex);
list_del(&p_dev->socket_device_list);
p_dev->_removed = 1;
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ mutex_unlock(&s->ops_mutex);
dev_dbg(&p_dev->dev, "unregistering device\n");
device_unregister(&p_dev->dev);
@@ -368,7 +348,6 @@ static int pcmcia_device_remove(struct device *dev)
{
struct pcmcia_device *p_dev;
struct pcmcia_driver *p_drv;
- struct pcmcia_device_id *did;
int i;
p_dev = to_pcmcia_dev(dev);
@@ -380,9 +359,8 @@ static int pcmcia_device_remove(struct device *dev)
* pseudo multi-function card, we need to unbind
* all devices
*/
- did = dev_get_drvdata(&p_dev->dev);
- if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
- (p_dev->socket->device_count != 0) &&
+ if ((p_dev->socket->pcmcia_state.has_pfc) &&
+ (p_dev->socket->device_count > 0) &&
(p_dev->device_no == 0))
pcmcia_card_remove(p_dev->socket, p_dev);
@@ -431,16 +409,20 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL,
CISTPL_MANFID, &manf_id)) {
+ mutex_lock(&p_dev->socket->ops_mutex);
p_dev->manf_id = manf_id.manf;
p_dev->card_id = manf_id.card;
p_dev->has_manf_id = 1;
p_dev->has_card_id = 1;
+ mutex_unlock(&p_dev->socket->ops_mutex);
}
if (!pccard_read_tuple(p_dev->socket, p_dev->func,
CISTPL_FUNCID, &func_id)) {
+ mutex_lock(&p_dev->socket->ops_mutex);
p_dev->func_id = func_id.func;
p_dev->has_func_id = 1;
+ mutex_unlock(&p_dev->socket->ops_mutex);
} else {
/* rule of thumb: cards with no FUNCID, but with
* common memory device geometry information, are
@@ -457,17 +439,21 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
dev_dbg(&p_dev->dev,
"mem device geometry probably means "
"FUNCID_MEMORY\n");
+ mutex_lock(&p_dev->socket->ops_mutex);
p_dev->func_id = CISTPL_FUNCID_MEMORY;
p_dev->has_func_id = 1;
+ mutex_unlock(&p_dev->socket->ops_mutex);
}
kfree(devgeo);
}
if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL, CISTPL_VERS_1,
vers1)) {
+ mutex_lock(&p_dev->socket->ops_mutex);
for (i = 0; i < min_t(unsigned int, 4, vers1->ns); i++) {
char *tmp;
unsigned int length;
+ char *new;
tmp = vers1->str + vers1->ofs[i];
@@ -475,14 +461,17 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
if ((length < 2) || (length > 255))
continue;
- p_dev->prod_id[i] = kmalloc(sizeof(char) * length,
- GFP_KERNEL);
- if (!p_dev->prod_id[i])
+ new = kmalloc(sizeof(char) * length, GFP_KERNEL);
+ if (!new)
continue;
- p_dev->prod_id[i] = strncpy(p_dev->prod_id[i],
- tmp, length);
+ new = strncpy(new, tmp, length);
+
+ tmp = p_dev->prod_id[i];
+ p_dev->prod_id[i] = new;
+ kfree(tmp);
}
+ mutex_unlock(&p_dev->socket->ops_mutex);
}
kfree(vers1);
@@ -502,7 +491,7 @@ static DEFINE_MUTEX(device_add_lock);
struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
{
struct pcmcia_device *p_dev, *tmp_dev;
- unsigned long flags;
+ int i;
s = pcmcia_get_socket(s);
if (!s)
@@ -512,16 +501,19 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
pr_debug("adding device to %d, function %d\n", s->sock, function);
- /* max of 4 devices per card */
- if (s->device_count == 4)
- goto err_put;
-
p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
if (!p_dev)
goto err_put;
- p_dev->socket = s;
+ mutex_lock(&s->ops_mutex);
p_dev->device_no = (s->device_count++);
+ mutex_unlock(&s->ops_mutex);
+
+ /* max of 2 devices per card */
+ if (p_dev->device_no >= 2)
+ goto err_free;
+
+ p_dev->socket = s;
p_dev->func = function;
p_dev->dev.bus = &pcmcia_bus_type;
@@ -538,7 +530,7 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
goto err_free;
dev_dbg(&p_dev->dev, "devname is %s\n", p_dev->devname);
- spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ mutex_lock(&s->ops_mutex);
/*
* p_dev->function_config must be the same for all card functions.
@@ -556,7 +548,7 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
/* Add to the list in pcmcia_bus_socket */
list_add(&p_dev->socket_device_list, &s->devices_list);
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ mutex_unlock(&s->ops_mutex);
if (!p_dev->function_config) {
dev_dbg(&p_dev->dev, "creating config_t\n");
@@ -581,14 +573,19 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
return p_dev;
err_unreg:
- spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ mutex_lock(&s->ops_mutex);
list_del(&p_dev->socket_device_list);
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ mutex_unlock(&s->ops_mutex);
err_free:
+ mutex_lock(&s->ops_mutex);
+ s->device_count--;
+ mutex_unlock(&s->ops_mutex);
+
+ for (i = 0; i < 4; i++)
+ kfree(p_dev->prod_id[i]);
kfree(p_dev->devname);
kfree(p_dev);
- s->device_count--;
err_put:
mutex_unlock(&device_add_lock);
pcmcia_put_socket(s);
@@ -601,19 +598,23 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
{
cistpl_longlink_mfc_t mfc;
unsigned int no_funcs, i, no_chains;
- int ret = 0;
+ int ret = -EAGAIN;
+ mutex_lock(&s->ops_mutex);
if (!(s->resource_setup_done)) {
dev_dbg(&s->dev,
"no resources available, delaying card_add\n");
+ mutex_unlock(&s->ops_mutex);
return -EAGAIN; /* try again, but later... */
}
if (pcmcia_validate_mem(s)) {
dev_dbg(&s->dev, "validating mem resources failed, "
"delaying card_add\n");
+ mutex_unlock(&s->ops_mutex);
return -EAGAIN; /* try again, but later... */
}
+ mutex_unlock(&s->ops_mutex);
ret = pccard_validate_cis(s, &no_chains);
if (ret || !no_chains) {
@@ -634,17 +635,7 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
}
-static void pcmcia_delayed_add_device(struct work_struct *work)
-{
- struct pcmcia_socket *s =
- container_of(work, struct pcmcia_socket, device_add);
- dev_dbg(&s->dev, "adding additional device to %d\n", s->sock);
- pcmcia_device_add(s, s->pcmcia_state.mfc_pfc);
- s->pcmcia_state.device_add_pending = 0;
- s->pcmcia_state.mfc_pfc = 0;
-}
-
-static int pcmcia_requery(struct device *dev, void * _data)
+static int pcmcia_requery_callback(struct device *dev, void * _data)
{
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
if (!p_dev->dev.driver) {
@@ -655,45 +646,67 @@ static int pcmcia_requery(struct device *dev, void * _data)
return 0;
}
-static void pcmcia_bus_rescan(struct pcmcia_socket *skt, int new_cis)
-{
- int no_devices = 0;
- int ret = 0;
- unsigned long flags;
- /* must be called with skt_mutex held */
- dev_dbg(&skt->dev, "re-scanning socket %d\n", skt->sock);
+static void pcmcia_requery(struct pcmcia_socket *s)
+{
+ int present, has_pfc;
- spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
- if (list_empty(&skt->devices_list))
- no_devices = 1;
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ mutex_lock(&s->ops_mutex);
+ present = s->pcmcia_state.present;
+ mutex_unlock(&s->ops_mutex);
- /* If this is because of a CIS override, start over */
- if (new_cis && !no_devices)
- pcmcia_card_remove(skt, NULL);
+ if (!present)
+ return;
- /* if no devices were added for this socket yet because of
- * missing resource information or other trouble, we need to
- * do this now. */
- if (no_devices || new_cis) {
- ret = pcmcia_card_add(skt);
- if (ret)
- return;
+ if (s->functions == 0) {
+ pcmcia_card_add(s);
+ return;
}
/* some device information might have changed because of a CIS
* update or because we can finally read it correctly... so
* determine it again, overwriting old values if necessary. */
- bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery);
+ bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery_callback);
+
+ /* if the CIS changed, we need to check whether the number of
+ * functions changed. */
+ if (s->fake_cis) {
+ int old_funcs, new_funcs;
+ cistpl_longlink_mfc_t mfc;
+
+ /* does this cis override add or remove functions? */
+ old_funcs = s->functions;
+
+ if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
+ &mfc))
+ new_funcs = mfc.nfn;
+ else
+ new_funcs = 1;
+ if (old_funcs > new_funcs) {
+ pcmcia_card_remove(s, NULL);
+ pcmcia_card_add(s);
+ } else if (new_funcs > old_funcs) {
+ s->functions = new_funcs;
+ pcmcia_device_add(s, 1);
+ }
+ }
+
+ /* If the PCMCIA device consists of two pseudo devices,
+ * call pcmcia_device_add() -- which will fail if both
+ * devices are already registered. */
+ mutex_lock(&s->ops_mutex);
+ has_pfc = s->pcmcia_state.has_pfc;
+ mutex_unlock(&s->ops_mutex);
+ if (has_pfc)
+ pcmcia_device_add(s, 0);
/* we re-scan all devices, not just the ones connected to this
* socket. This does not matter, though. */
- ret = bus_rescan_devices(&pcmcia_bus_type);
- if (ret)
- printk(KERN_INFO "pcmcia: bus_rescan_devices failed\n");
+ if (bus_rescan_devices(&pcmcia_bus_type))
+ dev_warn(&s->dev, "rescanning the bus failed\n");
}
+
#ifdef CONFIG_PCMCIA_LOAD_CIS
/**
@@ -710,9 +723,6 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
struct pcmcia_socket *s = dev->socket;
const struct firmware *fw;
int ret = -ENOMEM;
- int no_funcs;
- int old_funcs;
- cistpl_longlink_mfc_t mfc;
if (!filename)
return -EINVAL;
@@ -739,19 +749,8 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
/* update information */
pcmcia_device_query(dev);
- /* does this cis override add or remove functions? */
- old_funcs = s->functions;
-
- if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc))
- no_funcs = mfc.nfn;
- else
- no_funcs = 1;
- s->functions = no_funcs;
-
- if (old_funcs > no_funcs)
- pcmcia_card_remove(s, dev);
- else if (no_funcs > old_funcs)
- pcmcia_add_device_later(s, 1);
+ /* requery (as number of functions might have changed) */
+ pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
}
release:
release_firmware(fw);
@@ -818,9 +817,14 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
if (dev->device_no != did->device_no)
return 0;
+ mutex_lock(&dev->socket->ops_mutex);
+ dev->socket->pcmcia_state.has_pfc = 1;
+ mutex_unlock(&dev->socket->ops_mutex);
}
if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
+ int ret;
+
if ((!dev->has_func_id) || (dev->func_id != did->func_id))
return 0;
@@ -835,10 +839,15 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
* after it has re-checked that there is no possible module
* with a prod_id/manf_id/card_id match.
*/
- dev_dbg(&dev->dev,
- "skipping FUNC_ID match until userspace interaction\n");
- if (!dev->allow_func_id_match)
+ mutex_lock(&dev->socket->ops_mutex);
+ ret = dev->allow_func_id_match;
+ mutex_unlock(&dev->socket->ops_mutex);
+
+ if (!ret) {
+ dev_dbg(&dev->dev,
+ "skipping FUNC_ID match until userspace ACK\n");
return 0;
+ }
}
if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
@@ -859,8 +868,6 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
return 0;
}
- dev_set_drvdata(&dev->dev, did);
-
return 1;
}
@@ -873,16 +880,16 @@ static int pcmcia_bus_match(struct device *dev, struct device_driver *drv)
struct pcmcia_dynid *dynid;
/* match dynamic devices first */
- spin_lock(&p_drv->dynids.lock);
+ mutex_lock(&p_drv->dynids.lock);
list_for_each_entry(dynid, &p_drv->dynids.list, node) {
dev_dbg(dev, "trying to match to %s\n", drv->name);
if (pcmcia_devmatch(p_dev, &dynid->id)) {
dev_dbg(dev, "matched to %s\n", drv->name);
- spin_unlock(&p_drv->dynids.lock);
+ mutex_unlock(&p_drv->dynids.lock);
return 1;
}
}
- spin_unlock(&p_drv->dynids.lock);
+ mutex_unlock(&p_drv->dynids.lock);
#ifdef CONFIG_PCMCIA_IOCTL
/* matching by cardmgr */
@@ -964,19 +971,20 @@ static int runtime_suspend(struct device *dev)
{
int rc;
- down(&dev->sem);
+ device_lock(dev);
rc = pcmcia_dev_suspend(dev, PMSG_SUSPEND);
- up(&dev->sem);
+ device_unlock(dev);
return rc;
}
-static void runtime_resume(struct device *dev)
+static int runtime_resume(struct device *dev)
{
int rc;
- down(&dev->sem);
+ device_lock(dev);
rc = pcmcia_dev_resume(dev);
- up(&dev->sem);
+ device_unlock(dev);
+ return rc;
}
/************************ per-device sysfs output ***************************/
@@ -1027,7 +1035,7 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute
if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
ret = runtime_suspend(dev);
else if (p_dev->suspended && !strncmp(buf, "on", 2))
- runtime_resume(dev);
+ ret = runtime_resume(dev);
return ret ? ret : count;
}
@@ -1059,19 +1067,14 @@ static ssize_t pcmcia_store_allow_func_id_match(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
- int ret;
if (!count)
return -EINVAL;
- mutex_lock(&p_dev->socket->skt_mutex);
+ mutex_lock(&p_dev->socket->ops_mutex);
p_dev->allow_func_id_match = 1;
- mutex_unlock(&p_dev->socket->skt_mutex);
-
- ret = bus_rescan_devices(&pcmcia_bus_type);
- if (ret)
- printk(KERN_INFO "pcmcia: bus_rescan_devices failed after "
- "allowing func_id matches\n");
+ mutex_unlock(&p_dev->socket->ops_mutex);
+ pcmcia_parse_uevents(p_dev->socket, PCMCIA_UEVENT_REQUERY);
return count;
}
@@ -1099,8 +1102,13 @@ static int pcmcia_dev_suspend(struct device *dev, pm_message_t state)
struct pcmcia_driver *p_drv = NULL;
int ret = 0;
- if (p_dev->suspended)
+ mutex_lock(&p_dev->socket->ops_mutex);
+ if (p_dev->suspended) {
+ mutex_unlock(&p_dev->socket->ops_mutex);
return 0;
+ }
+ p_dev->suspended = 1;
+ mutex_unlock(&p_dev->socket->ops_mutex);
dev_dbg(dev, "suspending\n");
@@ -1117,6 +1125,9 @@ static int pcmcia_dev_suspend(struct device *dev, pm_message_t state)
"pcmcia: device %s (driver %s) did "
"not want to go to sleep (%d)\n",
p_dev->devname, p_drv->drv.name, ret);
+ mutex_lock(&p_dev->socket->ops_mutex);
+ p_dev->suspended = 0;
+ mutex_unlock(&p_dev->socket->ops_mutex);
goto out;
}
}
@@ -1127,8 +1138,6 @@ static int pcmcia_dev_suspend(struct device *dev, pm_message_t state)
}
out:
- if (!ret)
- p_dev->suspended = 1;
return ret;
}
@@ -1139,8 +1148,13 @@ static int pcmcia_dev_resume(struct device *dev)
struct pcmcia_driver *p_drv = NULL;
int ret = 0;
- if (!p_dev->suspended)
+ mutex_lock(&p_dev->socket->ops_mutex);
+ if (!p_dev->suspended) {
+ mutex_unlock(&p_dev->socket->ops_mutex);
return 0;
+ }
+ p_dev->suspended = 0;
+ mutex_unlock(&p_dev->socket->ops_mutex);
dev_dbg(dev, "resuming\n");
@@ -1161,8 +1175,6 @@ static int pcmcia_dev_resume(struct device *dev)
ret = p_drv->resume(p_dev);
out:
- if (!ret)
- p_dev->suspended = 0;
return ret;
}
@@ -1237,13 +1249,22 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
switch (event) {
case CS_EVENT_CARD_REMOVAL:
+ mutex_lock(&s->ops_mutex);
s->pcmcia_state.present = 0;
+ mutex_unlock(&s->ops_mutex);
pcmcia_card_remove(skt, NULL);
handle_event(skt, event);
+ mutex_lock(&s->ops_mutex);
+ destroy_cis_cache(s);
+ mutex_unlock(&s->ops_mutex);
break;
case CS_EVENT_CARD_INSERTION:
+ mutex_lock(&s->ops_mutex);
+ s->pcmcia_state.has_pfc = 0;
s->pcmcia_state.present = 1;
+ destroy_cis_cache(s); /* to be on the safe side... */
+ mutex_unlock(&s->ops_mutex);
pcmcia_card_add(skt);
handle_event(skt, event);
break;
@@ -1251,8 +1272,24 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
case CS_EVENT_EJECTION_REQUEST:
break;
- case CS_EVENT_PM_SUSPEND:
case CS_EVENT_PM_RESUME:
+ if (verify_cis_cache(skt) != 0) {
+ dev_dbg(&skt->dev, "cis mismatch - different card\n");
+ /* first, remove the card */
+ ds_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
+ mutex_lock(&s->ops_mutex);
+ destroy_cis_cache(skt);
+ kfree(skt->fake_cis);
+ skt->fake_cis = NULL;
+ mutex_unlock(&s->ops_mutex);
+ /* now, add the new card */
+ ds_event(skt, CS_EVENT_CARD_INSERTION,
+ CS_EVENT_PRI_LOW);
+ }
+ handle_event(skt, event);
+ break;
+
+ case CS_EVENT_PM_SUSPEND:
case CS_EVENT_RESET_PHYSICAL:
case CS_EVENT_CARD_RESET:
default:
@@ -1275,9 +1312,13 @@ struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
if (!p_dev)
return NULL;
+ mutex_lock(&p_dev->socket->ops_mutex);
if (!p_dev->socket->pcmcia_state.present)
goto out;
+ if (p_dev->socket->pcmcia_state.dead)
+ goto out;
+
if (p_dev->_removed)
goto out;
@@ -1286,6 +1327,7 @@ struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
ret = p_dev;
out:
+ mutex_unlock(&p_dev->socket->ops_mutex);
pcmcia_put_dev(p_dev);
return ret;
}
@@ -1295,7 +1337,8 @@ EXPORT_SYMBOL(pcmcia_dev_present);
static struct pcmcia_callback pcmcia_bus_callback = {
.owner = THIS_MODULE,
.event = ds_event,
- .requery = pcmcia_bus_rescan,
+ .requery = pcmcia_requery,
+ .validate = pccard_validate_cis,
.suspend = pcmcia_bus_suspend,
.resume = pcmcia_bus_resume,
};
@@ -1313,17 +1356,17 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev,
return -ENODEV;
}
- /*
- * Ugly. But we want to wait for the socket threads to have started up.
- * We really should let the drivers themselves drive some of this..
- */
- msleep(250);
+ ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
+ if (ret) {
+ dev_printk(KERN_ERR, dev, "PCMCIA registration failed\n");
+ pcmcia_put_socket(socket);
+ return ret;
+ }
#ifdef CONFIG_PCMCIA_IOCTL
init_waitqueue_head(&socket->queue);
#endif
INIT_LIST_HEAD(&socket->devices_list);
- INIT_WORK(&socket->device_add, pcmcia_delayed_add_device);
memset(&socket->pcmcia_state, 0, sizeof(u8));
socket->device_count = 0;
@@ -1345,14 +1388,20 @@ static void pcmcia_bus_remove_socket(struct device *dev,
if (!socket)
return;
+ mutex_lock(&socket->ops_mutex);
socket->pcmcia_state.dead = 1;
+ mutex_unlock(&socket->ops_mutex);
+
pccard_register_pcmcia(socket, NULL);
/* unregister any unbound devices */
mutex_lock(&socket->skt_mutex);
pcmcia_card_remove(socket, NULL);
+ release_cis_mem(socket);
mutex_unlock(&socket->skt_mutex);
+ sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
+
pcmcia_put_socket(socket);
return;
@@ -1383,8 +1432,6 @@ static int __init init_pcmcia_bus(void)
{
int ret;
- spin_lock_init(&pcmcia_dev_list_lock);
-
ret = bus_register(&pcmcia_bus_type);
if (ret < 0) {
printk(KERN_WARNING "pcmcia: bus_register error: %d\n", ret);
diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c
index d187ba4c5e0e..89cfddca089a 100644
--- a/drivers/pcmcia/electra_cf.c
+++ b/drivers/pcmcia/electra_cf.c
@@ -347,7 +347,7 @@ static int __devexit electra_cf_remove(struct of_device *ofdev)
return 0;
}
-static struct of_device_id electra_cf_match[] = {
+static const struct of_device_id electra_cf_match[] = {
{
.compatible = "electra-cf",
},
diff --git a/drivers/pcmcia/i82365.h b/drivers/pcmcia/i82365.h
index 622860c689d9..849ef1b5d687 100644
--- a/drivers/pcmcia/i82365.h
+++ b/drivers/pcmcia/i82365.h
@@ -77,8 +77,8 @@
#define I365_VPP2_5V 0x04 /* Vpp2 = 5.0v */
#define I365_VPP2_12V 0x08 /* Vpp2 = 12.0v */
#define I365_VPP1_MASK 0x03 /* Mask for turning off Vpp1 */
-#define I365_VPP1_5V 0x01 /* Vpp2 = 5.0v */
-#define I365_VPP1_12V 0x02 /* Vpp2 = 12.0v */
+#define I365_VPP1_5V 0x01 /* Vpp1 = 5.0v */
+#define I365_VPP1_12V 0x02 /* Vpp1 = 12.0v */
/* Flags for I365_INTCTL */
#define I365_RING_ENA 0x80
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index 26a621c9e2fc..0ece2cd4a85e 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -764,7 +764,7 @@ static int __init init_m32r_pcc(void)
for (i = 0 ; i < pcc_sockets ; i++) {
socket[i].socket.dev.parent = &pcc_device.dev;
socket[i].socket.ops = &pcc_operations;
- socket[i].socket.resource_ops = &pccard_nonstatic_ops;
+ socket[i].socket.resource_ops = &pccard_static_ops;
socket[i].socket.owner = THIS_MODULE;
socket[i].number = i;
ret = pcmcia_register_socket(&socket[i].socket);
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 7f79c4e169ae..61c215918128 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -1233,7 +1233,7 @@ static int __init m8xx_probe(struct of_device *ofdev,
socket[i].socket.io_offset = 0;
socket[i].socket.pci_irq = pcmcia_schlvl;
socket[i].socket.ops = &m8xx_services;
- socket[i].socket.resource_ops = &pccard_nonstatic_ops;
+ socket[i].socket.resource_ops = &pccard_iodyn_ops;
socket[i].socket.cb_dev = NULL;
socket[i].socket.dev.parent = &ofdev->dev;
socket[i].pcmcia = pcmcia;
@@ -1303,7 +1303,7 @@ static int m8xx_resume(struct platform_device *pdev)
#define m8xx_resume NULL
#endif
-static struct of_device_id m8xx_pcmcia_match[] = {
+static const struct of_device_id m8xx_pcmcia_match[] = {
{
.type = "pcmcia",
.compatible = "fsl,pq-pcmcia",
diff --git a/drivers/pcmcia/o2micro.h b/drivers/pcmcia/o2micro.h
index 624442fc0d35..e74bebac2695 100644
--- a/drivers/pcmcia/o2micro.h
+++ b/drivers/pcmcia/o2micro.h
@@ -116,13 +116,12 @@ static int o2micro_override(struct yenta_socket *socket)
* from Eric Still, 02Micro.
*/
u8 a, b;
+ bool use_speedup;
if (PCI_FUNC(socket->dev->devfn) == 0) {
a = config_readb(socket, O2_RESERVED1);
b = config_readb(socket, O2_RESERVED2);
-
- dev_printk(KERN_INFO, &socket->dev->dev,
- "O2: res at 0x94/0xD4: %02x/%02x\n", a, b);
+ dev_dbg(&socket->dev->dev, "O2: 0x94/0xD4: %02x/%02x\n", a, b);
switch (socket->dev->device) {
/*
@@ -135,23 +134,37 @@ static int o2micro_override(struct yenta_socket *socket)
case PCI_DEVICE_ID_O2_6812:
case PCI_DEVICE_ID_O2_6832:
case PCI_DEVICE_ID_O2_6836:
- case PCI_DEVICE_ID_O2_6933:
- dev_printk(KERN_INFO, &socket->dev->dev,
- "Yenta O2: old bridge, disabling read "
- "prefetch/write burst\n");
- config_writeb(socket, O2_RESERVED1,
- a & ~(O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST));
- config_writeb(socket, O2_RESERVED2,
- b & ~(O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST));
+ case PCI_DEVICE_ID_O2_6933:
+ use_speedup = false;
break;
-
default:
- dev_printk(KERN_INFO , &socket->dev->dev,
- "O2: enabling read prefetch/write burst\n");
+ use_speedup = true;
+ break;
+ }
+
+ /* the user may override our decision */
+ if (strcasecmp(o2_speedup, "on") == 0)
+ use_speedup = true;
+ else if (strcasecmp(o2_speedup, "off") == 0)
+ use_speedup = false;
+ else if (strcasecmp(o2_speedup, "default") != 0)
+ dev_warn(&socket->dev->dev,
+ "O2: Unknown parameter, using 'default'");
+
+ if (use_speedup) {
+ dev_info(&socket->dev->dev,
+ "O2: enabling read prefetch/write burst\n");
+ config_writeb(socket, O2_RESERVED1,
+ a | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST);
+ config_writeb(socket, O2_RESERVED2,
+ b | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST);
+ } else {
+ dev_info(&socket->dev->dev,
+ "O2: disabling read prefetch/write burst\n");
config_writeb(socket, O2_RESERVED1,
- a | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST);
+ a & ~(O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST));
config_writeb(socket, O2_RESERVED2,
- b | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST);
+ b & ~(O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST));
}
}
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index 663781d20129..3ef991552398 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -71,8 +71,6 @@ struct omap_cf_socket {
#define POLL_INTERVAL (2 * HZ)
-#define SZ_2K (2 * SZ_1K)
-
/*--------------------------------------------------------------------------*/
static int omap_cf_ss_init(struct pcmcia_socket *s)
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index f73fd5beaa37..13a7132cf688 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -62,16 +62,15 @@ static struct pcmcia_device *get_pcmcia_device(struct pcmcia_socket *s,
unsigned int function)
{
struct pcmcia_device *p_dev = NULL;
- unsigned long flags;
- spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ mutex_lock(&s->ops_mutex);
list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
if (p_dev->func == function) {
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ mutex_unlock(&s->ops_mutex);
return pcmcia_get_dev(p_dev);
}
}
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ mutex_unlock(&s->ops_mutex);
return NULL;
}
@@ -169,7 +168,6 @@ static int pcmcia_adjust_resource_info(adjust_t *adj)
{
struct pcmcia_socket *s;
int ret = -ENOSYS;
- unsigned long flags;
down_read(&pcmcia_socket_list_rwsem);
list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
@@ -182,14 +180,13 @@ static int pcmcia_adjust_resource_info(adjust_t *adj)
/* you can't use the old interface if the new
* one was used before */
- spin_lock_irqsave(&s->lock, flags);
+ mutex_lock(&s->ops_mutex);
if ((s->resource_setup_new) &&
!(s->resource_setup_old)) {
- spin_unlock_irqrestore(&s->lock, flags);
+ mutex_unlock(&s->ops_mutex);
continue;
} else if (!(s->resource_setup_old))
s->resource_setup_old = 1;
- spin_unlock_irqrestore(&s->lock, flags);
switch (adj->Resource) {
case RES_MEMORY_RANGE:
@@ -208,10 +205,9 @@ static int pcmcia_adjust_resource_info(adjust_t *adj)
* last call to adjust_resource_info, we
* always need to assume this is the latest
* one... */
- spin_lock_irqsave(&s->lock, flags);
s->resource_setup_done = 1;
- spin_unlock_irqrestore(&s->lock, flags);
}
+ mutex_unlock(&s->ops_mutex);
}
}
up_read(&pcmcia_socket_list_rwsem);
@@ -470,7 +466,6 @@ static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
struct pcmcia_driver *p_drv;
struct pcmcia_device *p_dev;
int ret = 0;
- unsigned long flags;
s = pcmcia_get_socket(s);
if (!s)
@@ -490,7 +485,7 @@ static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
goto err_put_driver;
}
- spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ mutex_lock(&s->ops_mutex);
list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
if (p_dev->func == bind_info->function) {
if ((p_dev->dev.driver == &p_drv->drv)) {
@@ -499,7 +494,7 @@ static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
* registered, and it was registered
* by userspace before, we need to
* return the "instance". */
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ mutex_unlock(&s->ops_mutex);
bind_info->instance = p_dev;
ret = -EBUSY;
goto err_put_module;
@@ -507,7 +502,7 @@ static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
/* the correct driver managed to bind
* itself magically to the correct
* device. */
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ mutex_unlock(&s->ops_mutex);
p_dev->cardmgr = p_drv;
ret = 0;
goto err_put_module;
@@ -516,12 +511,12 @@ static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
/* there's already a device available where
* no device has been bound to yet. So we don't
* need to register a device! */
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ mutex_unlock(&s->ops_mutex);
goto rescan;
}
}
}
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ mutex_unlock(&s->ops_mutex);
p_dev = pcmcia_device_add(s, bind_info->function);
if (!p_dev) {
@@ -578,7 +573,6 @@ static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int
dev_node_t *node;
struct pcmcia_device *p_dev;
struct pcmcia_driver *p_drv;
- unsigned long flags;
int ret = 0;
#ifdef CONFIG_CARDBUS
@@ -617,7 +611,7 @@ static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int
}
#endif
- spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ mutex_lock(&s->ops_mutex);
list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
if (p_dev->func == bind_info->function) {
p_dev = pcmcia_get_dev(p_dev);
@@ -626,11 +620,11 @@ static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int
goto found;
}
}
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ mutex_unlock(&s->ops_mutex);
return -ENODEV;
found:
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ mutex_unlock(&s->ops_mutex);
p_drv = to_pcmcia_drv(p_dev->dev.driver);
if (p_drv && !p_dev->_locked) {
@@ -931,16 +925,16 @@ static int ds_ioctl(struct inode *inode, struct file *file,
ret = pccard_validate_cis(s, &buf->cisinfo.Chains);
break;
case DS_SUSPEND_CARD:
- ret = pcmcia_suspend_card(s);
+ pcmcia_parse_uevents(s, PCMCIA_UEVENT_SUSPEND);
break;
case DS_RESUME_CARD:
- ret = pcmcia_resume_card(s);
+ pcmcia_parse_uevents(s, PCMCIA_UEVENT_RESUME);
break;
case DS_EJECT_CARD:
- err = pcmcia_eject_card(s);
+ pcmcia_parse_uevents(s, PCMCIA_UEVENT_EJECT);
break;
case DS_INSERT_CARD:
- err = pcmcia_insert_card(s);
+ pcmcia_parse_uevents(s, PCMCIA_UEVENT_INSERT);
break;
case DS_ACCESS_CONFIGURATION_REGISTER:
if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index d5db95644b64..b2df04199a21 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -43,6 +43,39 @@ module_param(io_speed, int, 0444);
static u8 pcmcia_used_irq[NR_IRQS];
#endif
+static int pcmcia_adjust_io_region(struct resource *res, unsigned long start,
+ unsigned long end, struct pcmcia_socket *s)
+{
+ if (s->resource_ops->adjust_io_region)
+ return s->resource_ops->adjust_io_region(res, start, end, s);
+ return -ENOMEM;
+}
+
+static struct resource *pcmcia_find_io_region(unsigned long base, int num,
+ unsigned long align,
+ struct pcmcia_socket *s)
+{
+ if (s->resource_ops->find_io)
+ return s->resource_ops->find_io(base, num, align, s);
+ return NULL;
+}
+
+int pcmcia_validate_mem(struct pcmcia_socket *s)
+{
+ if (s->resource_ops->validate_mem)
+ return s->resource_ops->validate_mem(s);
+ /* if there is no callback, we can assume that everything is OK */
+ return 0;
+}
+
+struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
+ int low, struct pcmcia_socket *s)
+{
+ if (s->resource_ops->find_mem)
+ return s->resource_ops->find_mem(base, num, align, low, s);
+ return NULL;
+}
+
/** alloc_io_space
*
@@ -158,14 +191,18 @@ int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
return -EINVAL;
s = p_dev->socket;
+
+ mutex_lock(&s->ops_mutex);
c = p_dev->function_config;
if (!(c->state & CONFIG_LOCKED)) {
dev_dbg(&s->dev, "Configuration isnt't locked\n");
+ mutex_unlock(&s->ops_mutex);
return -EACCES;
}
addr = (c->ConfigBase + reg->Offset) >> 1;
+ mutex_unlock(&s->ops_mutex);
switch (reg->Action) {
case CS_READ:
@@ -190,6 +227,7 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh,
memreq_t *req)
{
struct pcmcia_socket *s = p_dev->socket;
+ int ret;
wh--;
if (wh >= MAX_WIN)
@@ -198,12 +236,13 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh,
dev_dbg(&s->dev, "failure: requested page is zero\n");
return -EINVAL;
}
+ mutex_lock(&s->ops_mutex);
s->win[wh].card_start = req->CardOffset;
- if (s->ops->set_mem_map(s, &s->win[wh]) != 0) {
- dev_dbg(&s->dev, "failed to set_mem_map\n");
- return -EIO;
- }
- return 0;
+ ret = s->ops->set_mem_map(s, &s->win[wh]);
+ if (ret)
+ dev_warn(&s->dev, "failed to set_mem_map\n");
+ mutex_unlock(&s->ops_mutex);
+ return ret;
} /* pcmcia_map_mem_page */
EXPORT_SYMBOL(pcmcia_map_mem_page);
@@ -219,14 +258,18 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
config_t *c;
s = p_dev->socket;
+
+ mutex_lock(&s->ops_mutex);
c = p_dev->function_config;
if (!(s->state & SOCKET_PRESENT)) {
dev_dbg(&s->dev, "No card present\n");
+ mutex_unlock(&s->ops_mutex);
return -ENODEV;
}
if (!(c->state & CONFIG_LOCKED)) {
dev_dbg(&s->dev, "Configuration isnt't locked\n");
+ mutex_unlock(&s->ops_mutex);
return -EACCES;
}
@@ -251,10 +294,12 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
(mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
if (mod->Vpp1 != mod->Vpp2) {
dev_dbg(&s->dev, "Vpp1 and Vpp2 must be the same\n");
+ mutex_unlock(&s->ops_mutex);
return -EINVAL;
}
s->socket.Vpp = mod->Vpp1;
if (s->ops->set_socket(s, &s->socket)) {
+ mutex_unlock(&s->ops_mutex);
dev_printk(KERN_WARNING, &s->dev,
"Unable to set VPP\n");
return -EIO;
@@ -262,6 +307,7 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
} else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
(mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
dev_dbg(&s->dev, "changing Vcc is not allowed at this time\n");
+ mutex_unlock(&s->ops_mutex);
return -EINVAL;
}
@@ -286,6 +332,7 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
s->ops->set_io_map(s, &io_on);
}
}
+ mutex_unlock(&s->ops_mutex);
return 0;
} /* modify_configuration */
@@ -296,9 +343,11 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
{
pccard_io_map io = { 0, 0, 0, 0, 1 };
struct pcmcia_socket *s = p_dev->socket;
- config_t *c = p_dev->function_config;
+ config_t *c;
int i;
+ mutex_lock(&s->ops_mutex);
+ c = p_dev->function_config;
if (p_dev->_locked) {
p_dev->_locked = 0;
if (--(s->lock_count) == 0) {
@@ -321,6 +370,7 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
s->ops->set_io_map(s, &io);
}
}
+ mutex_unlock(&s->ops_mutex);
return 0;
} /* pcmcia_release_configuration */
@@ -337,10 +387,14 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
{
struct pcmcia_socket *s = p_dev->socket;
- config_t *c = p_dev->function_config;
+ int ret = -EINVAL;
+ config_t *c;
+
+ mutex_lock(&s->ops_mutex);
+ c = p_dev->function_config;
if (!p_dev->_io)
- return -EINVAL;
+ goto out;
p_dev->_io = 0;
@@ -348,7 +402,7 @@ static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
(c->io.NumPorts1 != req->NumPorts1) ||
(c->io.BasePort2 != req->BasePort2) ||
(c->io.NumPorts2 != req->NumPorts2))
- return -EINVAL;
+ goto out;
c->state &= ~CONFIG_IO_REQ;
@@ -356,28 +410,38 @@ static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
if (req->NumPorts2)
release_io_space(s, req->BasePort2, req->NumPorts2);
- return 0;
+out:
+ mutex_unlock(&s->ops_mutex);
+
+ return ret;
} /* pcmcia_release_io */
static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
{
struct pcmcia_socket *s = p_dev->socket;
- config_t *c = p_dev->function_config;
+ config_t *c;
+ int ret = -EINVAL;
+
+ mutex_lock(&s->ops_mutex);
+
+ c = p_dev->function_config;
if (!p_dev->_irq)
- return -EINVAL;
+ goto out;
+
p_dev->_irq = 0;
if (c->state & CONFIG_LOCKED)
- return -EACCES;
+ goto out;
+
if (c->irq.Attributes != req->Attributes) {
dev_dbg(&s->dev, "IRQ attributes must match assigned ones\n");
- return -EINVAL;
+ goto out;
}
if (s->irq.AssignedIRQ != req->AssignedIRQ) {
dev_dbg(&s->dev, "IRQ must match assigned one\n");
- return -EINVAL;
+ goto out;
}
if (--s->irq.Config == 0) {
c->state &= ~CONFIG_IRQ_REQ;
@@ -390,8 +454,12 @@ static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
#ifdef CONFIG_PCMCIA_PROBE
pcmcia_used_irq[req->AssignedIRQ]--;
#endif
+ ret = 0;
- return 0;
+out:
+ mutex_unlock(&s->ops_mutex);
+
+ return ret;
} /* pcmcia_release_irq */
@@ -404,10 +472,12 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh)
if (wh >= MAX_WIN)
return -EINVAL;
+ mutex_lock(&s->ops_mutex);
win = &s->win[wh];
if (!(p_dev->_win & CLIENT_WIN_REQ(wh))) {
dev_dbg(&s->dev, "not releasing unknown window\n");
+ mutex_unlock(&s->ops_mutex);
return -EINVAL;
}
@@ -423,6 +493,7 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh)
win->res = NULL;
}
p_dev->_win &= ~CLIENT_WIN_REQ(wh);
+ mutex_unlock(&s->ops_mutex);
return 0;
} /* pcmcia_release_window */
@@ -445,8 +516,11 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
dev_dbg(&s->dev, "IntType may not be INT_CARDBUS\n");
return -EINVAL;
}
+
+ mutex_lock(&s->ops_mutex);
c = p_dev->function_config;
if (c->state & CONFIG_LOCKED) {
+ mutex_unlock(&s->ops_mutex);
dev_dbg(&s->dev, "Configuration is locked\n");
return -EACCES;
}
@@ -454,6 +528,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
/* Do power control. We don't allow changes in Vcc. */
s->socket.Vpp = req->Vpp;
if (s->ops->set_socket(s, &s->socket)) {
+ mutex_unlock(&s->ops_mutex);
dev_printk(KERN_WARNING, &s->dev,
"Unable to set socket state\n");
return -EINVAL;
@@ -476,6 +551,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
s->socket.io_irq = 0;
s->ops->set_socket(s, &s->socket);
s->lock_count++;
+ mutex_unlock(&s->ops_mutex);
/* Set up CIS configuration registers */
base = c->ConfigBase = req->ConfigBase;
@@ -524,6 +600,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
/* Configure I/O windows */
if (c->state & CONFIG_IO_REQ) {
+ mutex_lock(&s->ops_mutex);
iomap.speed = io_speed;
for (i = 0; i < MAX_IO_WIN; i++)
if (s->io[i].res) {
@@ -542,6 +619,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
s->ops->set_io_map(s, &iomap);
s->io[i].Config++;
}
+ mutex_unlock(&s->ops_mutex);
}
c->state |= CONFIG_LOCKED;
@@ -560,54 +638,65 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
{
struct pcmcia_socket *s = p_dev->socket;
config_t *c;
+ int ret = -EINVAL;
+
+ mutex_lock(&s->ops_mutex);
if (!(s->state & SOCKET_PRESENT)) {
dev_dbg(&s->dev, "No card present\n");
- return -ENODEV;
+ goto out;
}
if (!req)
- return -EINVAL;
+ goto out;
+
c = p_dev->function_config;
if (c->state & CONFIG_LOCKED) {
dev_dbg(&s->dev, "Configuration is locked\n");
- return -EACCES;
+ goto out;
}
if (c->state & CONFIG_IO_REQ) {
dev_dbg(&s->dev, "IO already configured\n");
- return -EBUSY;
+ goto out;
}
if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) {
dev_dbg(&s->dev, "bad attribute setting for IO region 1\n");
- return -EINVAL;
+ goto out;
}
if ((req->NumPorts2 > 0) &&
(req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) {
dev_dbg(&s->dev, "bad attribute setting for IO region 2\n");
- return -EINVAL;
+ goto out;
}
dev_dbg(&s->dev, "trying to allocate resource 1\n");
- if (alloc_io_space(s, req->Attributes1, &req->BasePort1,
- req->NumPorts1, req->IOAddrLines)) {
+ ret = alloc_io_space(s, req->Attributes1, &req->BasePort1,
+ req->NumPorts1, req->IOAddrLines);
+ if (ret) {
dev_dbg(&s->dev, "allocation of resource 1 failed\n");
- return -EBUSY;
+ goto out;
}
if (req->NumPorts2) {
dev_dbg(&s->dev, "trying to allocate resource 2\n");
- if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
- req->NumPorts2, req->IOAddrLines)) {
+ ret = alloc_io_space(s, req->Attributes2, &req->BasePort2,
+ req->NumPorts2, req->IOAddrLines);
+ if (ret) {
dev_dbg(&s->dev, "allocation of resource 2 failed\n");
release_io_space(s, req->BasePort1, req->NumPorts1);
- return -EBUSY;
+ goto out;
}
}
c->io = *req;
c->state |= CONFIG_IO_REQ;
p_dev->_io = 1;
- return 0;
+ dev_dbg(&s->dev, "allocating resources succeeded: %d\n", ret);
+
+out:
+ mutex_unlock(&s->ops_mutex);
+
+ return ret;
} /* pcmcia_request_io */
EXPORT_SYMBOL(pcmcia_request_io);
@@ -636,18 +725,20 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
int ret = -EINVAL, irq = 0;
int type;
+ mutex_lock(&s->ops_mutex);
+
if (!(s->state & SOCKET_PRESENT)) {
dev_dbg(&s->dev, "No card present\n");
- return -ENODEV;
+ goto out;
}
c = p_dev->function_config;
if (c->state & CONFIG_LOCKED) {
dev_dbg(&s->dev, "Configuration is locked\n");
- return -EACCES;
+ goto out;
}
if (c->state & CONFIG_IRQ_REQ) {
dev_dbg(&s->dev, "IRQ already configured\n");
- return -EBUSY;
+ goto out;
}
/* Decide what type of interrupt we are registering */
@@ -708,7 +799,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
if (ret && !s->irq.AssignedIRQ) {
if (!s->pci_irq) {
dev_printk(KERN_INFO, &s->dev, "no IRQ found\n");
- return ret;
+ goto out;
}
type = IRQF_SHARED;
irq = s->pci_irq;
@@ -720,7 +811,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
if (ret) {
dev_printk(KERN_INFO, &s->dev,
"request_irq() failed\n");
- return ret;
+ goto out;
}
}
@@ -743,7 +834,10 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
pcmcia_used_irq[irq]++;
#endif
- return 0;
+ ret = 0;
+out:
+ mutex_unlock(&s->ops_mutex);
+ return ret;
} /* pcmcia_request_irq */
EXPORT_SYMBOL(pcmcia_request_irq);
@@ -796,6 +890,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
return -EINVAL;
}
+ mutex_lock(&s->ops_mutex);
win = &s->win[w];
if (!(s->features & SS_CAP_STATIC_MAP)) {
@@ -803,6 +898,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
(req->Attributes & WIN_MAP_BELOW_1MB), s);
if (!win->res) {
dev_dbg(&s->dev, "allocating mem region failed\n");
+ mutex_unlock(&s->ops_mutex);
return -EINVAL;
}
}
@@ -821,8 +917,10 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
if (req->Attributes & WIN_USE_WAIT)
win->flags |= MAP_USE_WAIT;
win->card_start = 0;
+
if (s->ops->set_mem_map(s, win) != 0) {
dev_dbg(&s->dev, "failed to set memory mapping\n");
+ mutex_unlock(&s->ops_mutex);
return -EIO;
}
s->state |= SOCKET_WIN_REQ(w);
@@ -833,6 +931,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
else
req->Base = win->res->start;
+ mutex_unlock(&s->ops_mutex);
*wh = w + 1;
return 0;
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index e1741cd875aa..7c204910a777 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -48,23 +48,13 @@ MODULE_AUTHOR("Jun Komuro <komurojun-mbn@nifty.com>");
* Specifies the interrupt delivery mode. The default (1) is to use PCI
* interrupts; a value of 0 selects ISA interrupts. This must be set for
* correct operation of PCI card readers.
- *
- * irq_list=i,j,...
- * This list limits the set of interrupts that can be used by PCMCIA
- * cards.
- * The default list is 3,4,5,7,9,10,11.
- * (irq_list parameter is not used, if irq_mode = 1)
*/
static int irq_mode = 1; /* 0 = ISA interrupt, 1 = PCI interrupt */
-static int irq_list[16];
-static unsigned int irq_list_count = 0;
module_param(irq_mode, int, 0444);
-module_param_array(irq_list, int, &irq_list_count, 0444);
MODULE_PARM_DESC(irq_mode,
"interrupt delivery mode. 0 = ISA, 1 = PCI. default is 1");
-MODULE_PARM_DESC(irq_list, "interrupts that can be used by PCMCIA cards");
static DEFINE_SPINLOCK(port_lock);
@@ -605,13 +595,7 @@ static u_int __devinit pd6729_isa_scan(void)
return 0;
}
- if (irq_list_count == 0)
- mask0 = 0xffff;
- else
- for (i = mask0 = 0; i < irq_list_count; i++)
- mask0 |= (1<<irq_list[i]);
-
- mask0 &= PD67_MASK;
+ mask0 = PD67_MASK;
/* just find interrupts that aren't in use */
for (i = 0; i < 16; i++)
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index 52db17263d8b..452c83b512c4 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -21,60 +21,12 @@
#include <pcmcia/cistpl.h>
#include "cs_internal.h"
-
-int pcmcia_validate_mem(struct pcmcia_socket *s)
-{
- if (s->resource_ops->validate_mem)
- return s->resource_ops->validate_mem(s);
- /* if there is no callback, we can assume that everything is OK */
- return 0;
-}
-EXPORT_SYMBOL(pcmcia_validate_mem);
-
-int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start,
- unsigned long r_end, struct pcmcia_socket *s)
-{
- if (s->resource_ops->adjust_io_region)
- return s->resource_ops->adjust_io_region(res, r_start, r_end, s);
- return -ENOMEM;
-}
-EXPORT_SYMBOL(pcmcia_adjust_io_region);
-
-struct resource *pcmcia_find_io_region(unsigned long base, int num,
- unsigned long align, struct pcmcia_socket *s)
-{
- if (s->resource_ops->find_io)
- return s->resource_ops->find_io(base, num, align, s);
- return NULL;
-}
-EXPORT_SYMBOL(pcmcia_find_io_region);
-
-struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
- int low, struct pcmcia_socket *s)
-{
- if (s->resource_ops->find_mem)
- return s->resource_ops->find_mem(base, num, align, low, s);
- return NULL;
-}
-EXPORT_SYMBOL(pcmcia_find_mem_region);
-
-void release_resource_db(struct pcmcia_socket *s)
-{
- if (s->resource_ops->exit)
- s->resource_ops->exit(s);
-}
-
-
static int static_init(struct pcmcia_socket *s)
{
- unsigned long flags;
-
/* the good thing about SS_CAP_STATIC_MAP sockets is
* that they don't need a resource database */
- spin_lock_irqsave(&s->lock, flags);
s->resource_setup_done = 1;
- spin_unlock_irqrestore(&s->lock, flags);
return 0;
}
@@ -114,32 +66,32 @@ struct pcmcia_align_data {
unsigned long offset;
};
-static void pcmcia_align(void *align_data, struct resource *res,
- unsigned long size, unsigned long align)
+static resource_size_t pcmcia_align(void *align_data,
+ const struct resource *res,
+ resource_size_t size, resource_size_t align)
{
struct pcmcia_align_data *data = align_data;
- unsigned long start;
+ resource_size_t start;
start = (res->start & ~data->mask) + data->offset;
if (start < res->start)
start += data->mask + 1;
- res->start = start;
#ifdef CONFIG_X86
if (res->flags & IORESOURCE_IO) {
- if (start & 0x300) {
+ if (start & 0x300)
start = (start + 0x3ff) & ~0x3ff;
- res->start = start;
- }
}
#endif
#ifdef CONFIG_M68K
if (res->flags & IORESOURCE_IO) {
if ((res->start + size - 1) >= 1024)
- res->start = res->end;
+ start = res->end;
}
#endif
+
+ return start;
}
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 9b0dc433a8c3..4663b3fa9f96 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -55,11 +55,10 @@ struct resource_map {
struct socket_data {
struct resource_map mem_db;
+ struct resource_map mem_db_valid;
struct resource_map io_db;
- unsigned int rsrc_mem_probe;
};
-static DEFINE_MUTEX(rsrc_mutex);
#define MEM_PROBE_LOW (1 << 0)
#define MEM_PROBE_HIGH (1 << 1)
@@ -125,8 +124,10 @@ static int add_interval(struct resource_map *map, u_long base, u_long num)
struct resource_map *p, *q;
for (p = map; ; p = p->next) {
- if ((p != map) && (p->base+p->num-1 >= base))
- return -1;
+ if ((p != map) && (p->base+p->num >= base)) {
+ p->num = max(num + base - p->base, p->num);
+ return 0;
+ }
if ((p->next == map) || (p->next->base > base+num-1))
break;
}
@@ -264,36 +265,44 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
}
#endif
-/*======================================================================
-
- This is tricky... when we set up CIS memory, we try to validate
- the memory window space allocations.
-
-======================================================================*/
+/*======================================================================*/
-/* Validation function for cards with a valid CIS */
+/**
+ * readable() - iomem validation function for cards with a valid CIS
+ */
static int readable(struct pcmcia_socket *s, struct resource *res,
unsigned int *count)
{
- int ret = -1;
+ int ret = -EINVAL;
+
+ if (s->fake_cis) {
+ dev_dbg(&s->dev, "fake CIS is being used: can't validate mem\n");
+ return 0;
+ }
s->cis_mem.res = res;
s->cis_virt = ioremap(res->start, s->map_size);
if (s->cis_virt) {
- ret = pccard_validate_cis(s, count);
- /* invalidate mapping and CIS cache */
+ mutex_unlock(&s->ops_mutex);
+ /* as we're only called from pcmcia.c, we're safe */
+ if (s->callback->validate)
+ ret = s->callback->validate(s, count);
+ /* invalidate mapping */
+ mutex_lock(&s->ops_mutex);
iounmap(s->cis_virt);
s->cis_virt = NULL;
- destroy_cis_cache(s);
}
s->cis_mem.res = NULL;
- if ((ret != 0) || (*count == 0))
- return 0;
- return 1;
+ if ((ret) || (*count == 0))
+ return -EINVAL;
+ return 0;
}
-/* Validation function for simple memory cards */
-static int checksum(struct pcmcia_socket *s, struct resource *res)
+/**
+ * checksum() - iomem validation function for simple memory cards
+ */
+static int checksum(struct pcmcia_socket *s, struct resource *res,
+ unsigned int *value)
{
pccard_mem_map map;
int i, a = 0, b = -1, d;
@@ -321,61 +330,90 @@ static int checksum(struct pcmcia_socket *s, struct resource *res)
iounmap(virt);
}
- return (b == -1) ? -1 : (a>>1);
+ if (b == -1)
+ return -EINVAL;
+
+ *value = a;
+
+ return 0;
}
-static int
-cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size)
+/**
+ * do_validate_mem() - low level validate a memory region for PCMCIA use
+ * @s: PCMCIA socket to validate
+ * @base: start address of resource to check
+ * @size: size of resource to check
+ * @validate: validation function to use
+ *
+ * do_validate_mem() splits up the memory region which is to be checked
+ * into two parts. Both are passed to the @validate() function. If
+ * @validate() returns non-zero, or the value parameter to @validate()
+ * is zero, or the value parameter is different between both calls,
+ * the check fails, and -EINVAL is returned. Else, 0 is returned.
+ */
+static int do_validate_mem(struct pcmcia_socket *s,
+ unsigned long base, unsigned long size,
+ int validate (struct pcmcia_socket *s,
+ struct resource *res,
+ unsigned int *value))
{
+ struct socket_data *s_data = s->resource_data;
struct resource *res1, *res2;
- unsigned int info1, info2;
- int ret = 0;
+ unsigned int info1 = 1, info2 = 1;
+ int ret = -EINVAL;
res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
"PCMCIA memprobe");
if (res1 && res2) {
- ret = readable(s, res1, &info1);
- ret += readable(s, res2, &info2);
+ ret = 0;
+ if (validate) {
+ ret = validate(s, res1, &info1);
+ ret += validate(s, res2, &info2);
+ }
}
free_region(res2);
free_region(res1);
- return (ret == 2) && (info1 == info2);
-}
-
-static int
-checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size)
-{
- struct resource *res1, *res2;
- int a = -1, b = -1;
+ dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %p %p %u %u %u",
+ base, base+size-1, res1, res2, ret, info1, info2);
- res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
- res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
- "PCMCIA memprobe");
+ if ((ret) || (info1 != info2) || (info1 == 0))
+ return -EINVAL;
- if (res1 && res2) {
- a = checksum(s, res1);
- b = checksum(s, res2);
+ if (validate && !s->fake_cis) {
+ /* move it to the validated data set */
+ add_interval(&s_data->mem_db_valid, base, size);
+ sub_interval(&s_data->mem_db, base, size);
}
- free_region(res2);
- free_region(res1);
-
- return (a == b) && (a >= 0);
+ return 0;
}
-/*======================================================================
-
- The memory probe. If the memory list includes a 64K-aligned block
- below 1MB, we probe in 64K chunks, and as soon as we accumulate at
- least mem_limit free space, we quit.
-======================================================================*/
-
-static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
+/**
+ * do_mem_probe() - validate a memory region for PCMCIA use
+ * @s: PCMCIA socket to validate
+ * @base: start address of resource to check
+ * @num: size of resource to check
+ * @validate: validation function to use
+ * @fallback: validation function to use if validate fails
+ *
+ * do_mem_probe() checks a memory region for use by the PCMCIA subsystem.
+ * To do so, the area is split up into sensible parts, and then passed
+ * into the @validate() function. Only if @validate() and @fallback() fail,
+ * the area is marked as unavaibale for use by the PCMCIA subsystem. The
+ * function returns the size of the usable memory area.
+ */
+static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num,
+ int validate (struct pcmcia_socket *s,
+ struct resource *res,
+ unsigned int *value),
+ int fallback (struct pcmcia_socket *s,
+ struct resource *res,
+ unsigned int *value))
{
struct socket_data *s_data = s->resource_data;
u_long i, j, bad, fail, step;
@@ -393,15 +431,14 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
for (i = j = base; i < base+num; i = j + step) {
if (!fail) {
for (j = i; j < base+num; j += step) {
- if (cis_readable(s, j, step))
+ if (!do_validate_mem(s, j, step, validate))
break;
}
fail = ((i == base) && (j == base+num));
}
- if (fail) {
- for (j = i; j < base+num; j += 2*step)
- if (checksum_match(s, j, step) &&
- checksum_match(s, j + step, step))
+ if ((fail) && (fallback)) {
+ for (j = i; j < base+num; j += step)
+ if (!do_validate_mem(s, j, step, fallback))
break;
}
if (i != j) {
@@ -416,8 +453,14 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
return num - bad;
}
+
#ifdef CONFIG_PCMCIA_PROBE
+/**
+ * inv_probe() - top-to-bottom search for one usuable high memory area
+ * @s: PCMCIA socket to validate
+ * @m: resource_map to check
+ */
static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
{
struct socket_data *s_data = s->resource_data;
@@ -432,9 +475,18 @@ static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
}
if (m->base < 0x100000)
return 0;
- return do_mem_probe(m->base, m->num, s);
+ return do_mem_probe(s, m->base, m->num, readable, checksum);
}
+/**
+ * validate_mem() - memory probe function
+ * @s: PCMCIA socket to validate
+ * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH
+ *
+ * The memory probe. If the memory list includes a 64K-aligned block
+ * below 1MB, we probe in 64K chunks, and as soon as we accumulate at
+ * least mem_limit free space, we quit. Returns 0 on usuable ports.
+ */
static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
{
struct resource_map *m, mm;
@@ -446,6 +498,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
if (probe_mask & MEM_PROBE_HIGH) {
if (inv_probe(s_data->mem_db.next, s) > 0)
return 0;
+ if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
+ return 0;
dev_printk(KERN_NOTICE, &s->dev,
"cs: warning: no high memory space available!\n");
return -ENODEV;
@@ -457,7 +511,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
if (mm.base >= 0x100000)
continue;
if ((mm.base | mm.num) & 0xffff) {
- ok += do_mem_probe(mm.base, mm.num, s);
+ ok += do_mem_probe(s, mm.base, mm.num, readable,
+ checksum);
continue;
}
/* Special probe for 64K-aligned block */
@@ -467,7 +522,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
if (ok >= mem_limit)
sub_interval(&s_data->mem_db, b, 0x10000);
else
- ok += do_mem_probe(b, 0x10000, s);
+ ok += do_mem_probe(s, b, 0x10000,
+ readable, checksum);
}
}
}
@@ -480,6 +536,13 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
#else /* CONFIG_PCMCIA_PROBE */
+/**
+ * validate_mem() - memory probe function
+ * @s: PCMCIA socket to validate
+ * @probe_mask: ignored
+ *
+ * Returns 0 on usuable ports.
+ */
static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
{
struct resource_map *m, mm;
@@ -488,7 +551,7 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
mm = *m;
- ok += do_mem_probe(mm.base, mm.num, s);
+ ok += do_mem_probe(s, mm.base, mm.num, readable, checksum);
}
if (ok > 0)
return 0;
@@ -498,31 +561,31 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
#endif /* CONFIG_PCMCIA_PROBE */
-/*
+/**
+ * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use
+ * @s: PCMCIA socket to validate
+ *
+ * This is tricky... when we set up CIS memory, we try to validate
+ * the memory window space allocations.
+ *
* Locking note: Must be called with skt_mutex held!
*/
static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
{
struct socket_data *s_data = s->resource_data;
unsigned int probe_mask = MEM_PROBE_LOW;
- int ret = 0;
+ int ret;
- if (!probe_mem)
+ if (!probe_mem || !(s->state & SOCKET_PRESENT))
return 0;
- mutex_lock(&rsrc_mutex);
-
if (s->features & SS_CAP_PAGE_REGS)
probe_mask = MEM_PROBE_HIGH;
- if (probe_mask & ~s_data->rsrc_mem_probe) {
- if (s->state & SOCKET_PRESENT)
- ret = validate_mem(s, probe_mask);
- if (!ret)
- s_data->rsrc_mem_probe |= probe_mask;
- }
+ ret = validate_mem(s, probe_mask);
- mutex_unlock(&rsrc_mutex);
+ if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
+ return 0;
return ret;
}
@@ -533,8 +596,8 @@ struct pcmcia_align_data {
struct resource_map *map;
};
-static void
-pcmcia_common_align(void *align_data, struct resource *res,
+static resource_size_t
+pcmcia_common_align(void *align_data, const struct resource *res,
resource_size_t size, resource_size_t align)
{
struct pcmcia_align_data *data = align_data;
@@ -545,17 +608,18 @@ pcmcia_common_align(void *align_data, struct resource *res,
start = (res->start & ~data->mask) + data->offset;
if (start < res->start)
start += data->mask + 1;
- res->start = start;
+ return start;
}
-static void
-pcmcia_align(void *align_data, struct resource *res, resource_size_t size,
- resource_size_t align)
+static resource_size_t
+pcmcia_align(void *align_data, const struct resource *res,
+ resource_size_t size, resource_size_t align)
{
struct pcmcia_align_data *data = align_data;
struct resource_map *m;
+ resource_size_t start;
- pcmcia_common_align(data, res, size, align);
+ start = pcmcia_common_align(data, res, size, align);
for (m = data->map->next; m != data->map; m = m->next) {
unsigned long start = m->base;
@@ -567,8 +631,7 @@ pcmcia_align(void *align_data, struct resource *res, resource_size_t size,
* fit here.
*/
if (res->start < start) {
- res->start = start;
- pcmcia_common_align(data, res, size, align);
+ start = pcmcia_common_align(data, res, size, align);
}
/*
@@ -586,7 +649,9 @@ pcmcia_align(void *align_data, struct resource *res, resource_size_t size,
* If we failed to find something suitable, ensure we fail.
*/
if (m == data->map)
- res->start = res->end;
+ start = res->end;
+
+ return start;
}
/*
@@ -600,7 +665,6 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
struct socket_data *s_data = s->resource_data;
int ret = -ENOMEM;
- mutex_lock(&rsrc_mutex);
for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
unsigned long start = m->base;
unsigned long end = m->base + m->num - 1;
@@ -611,7 +675,6 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
ret = adjust_resource(res, r_start, r_end - r_start + 1);
break;
}
- mutex_unlock(&rsrc_mutex);
return ret;
}
@@ -645,7 +708,6 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
data.offset = base & data.mask;
data.map = &s_data->io_db;
- mutex_lock(&rsrc_mutex);
#ifdef CONFIG_PCI
if (s->cb_dev) {
ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
@@ -654,7 +716,6 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
#endif
ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
1, pcmcia_align, &data);
- mutex_unlock(&rsrc_mutex);
if (ret != 0) {
kfree(res);
@@ -670,15 +731,15 @@ static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
struct socket_data *s_data = s->resource_data;
struct pcmcia_align_data data;
unsigned long min, max;
- int ret, i;
+ int ret, i, j;
low = low || !(s->features & SS_CAP_PAGE_REGS);
data.mask = align - 1;
data.offset = base & data.mask;
- data.map = &s_data->mem_db;
for (i = 0; i < 2; i++) {
+ data.map = &s_data->mem_db_valid;
if (low) {
max = 0x100000UL;
min = base < max ? base : 0;
@@ -687,17 +748,23 @@ static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
min = 0x100000UL + base;
}
- mutex_lock(&rsrc_mutex);
+ for (j = 0; j < 2; j++) {
#ifdef CONFIG_PCI
- if (s->cb_dev) {
- ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num,
- 1, min, 0,
- pcmcia_align, &data);
- } else
+ if (s->cb_dev) {
+ ret = pci_bus_alloc_resource(s->cb_dev->bus,
+ res, num, 1, min, 0,
+ pcmcia_align, &data);
+ } else
#endif
- ret = allocate_resource(&iomem_resource, res, num, min,
- max, 1, pcmcia_align, &data);
- mutex_unlock(&rsrc_mutex);
+ {
+ ret = allocate_resource(&iomem_resource,
+ res, num, min, max, 1,
+ pcmcia_align, &data);
+ }
+ if (ret == 0)
+ break;
+ data.map = &s_data->mem_db;
+ }
if (ret == 0 || low)
break;
low = 1;
@@ -720,25 +787,18 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned
if (end < start)
return -EINVAL;
- mutex_lock(&rsrc_mutex);
switch (action) {
case ADD_MANAGED_RESOURCE:
ret = add_interval(&data->mem_db, start, size);
+ if (!ret)
+ do_mem_probe(s, start, size, NULL, NULL);
break;
case REMOVE_MANAGED_RESOURCE:
ret = sub_interval(&data->mem_db, start, size);
- if (!ret) {
- struct pcmcia_socket *socket;
- down_read(&pcmcia_socket_list_rwsem);
- list_for_each_entry(socket, &pcmcia_socket_list, socket_list)
- release_cis_mem(socket);
- up_read(&pcmcia_socket_list_rwsem);
- }
break;
default:
ret = -EINVAL;
}
- mutex_unlock(&rsrc_mutex);
return ret;
}
@@ -756,7 +816,6 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long
if (end > IO_SPACE_LIMIT)
return -EINVAL;
- mutex_lock(&rsrc_mutex);
switch (action) {
case ADD_MANAGED_RESOURCE:
if (add_interval(&data->io_db, start, size) != 0) {
@@ -775,7 +834,6 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long
ret = -EINVAL;
break;
}
- mutex_unlock(&rsrc_mutex);
return ret;
}
@@ -801,8 +859,7 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
return -EINVAL;
#endif
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- res = s->cb_dev->bus->resource[i];
+ pci_bus_for_each_resource(s->cb_dev->bus, res, i) {
if (!res)
continue;
@@ -859,6 +916,7 @@ static int nonstatic_init(struct pcmcia_socket *s)
return -ENOMEM;
data->mem_db.next = &data->mem_db;
+ data->mem_db_valid.next = &data->mem_db_valid;
data->io_db.next = &data->io_db;
s->resource_data = (void *) data;
@@ -873,7 +931,10 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s)
struct socket_data *data = s->resource_data;
struct resource_map *p, *q;
- mutex_lock(&rsrc_mutex);
+ for (p = data->mem_db_valid.next; p != &data->mem_db_valid; p = q) {
+ q = p->next;
+ kfree(p);
+ }
for (p = data->mem_db.next; p != &data->mem_db; p = q) {
q = p->next;
kfree(p);
@@ -882,7 +943,6 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s)
q = p->next;
kfree(p);
}
- mutex_unlock(&rsrc_mutex);
}
@@ -909,7 +969,7 @@ static ssize_t show_io_db(struct device *dev,
struct resource_map *p;
ssize_t ret = 0;
- mutex_lock(&rsrc_mutex);
+ mutex_lock(&s->ops_mutex);
data = s->resource_data;
for (p = data->io_db.next; p != &data->io_db; p = p->next) {
@@ -921,7 +981,7 @@ static ssize_t show_io_db(struct device *dev,
((unsigned long) p->base + p->num - 1));
}
- mutex_unlock(&rsrc_mutex);
+ mutex_unlock(&s->ops_mutex);
return ret;
}
@@ -949,9 +1009,11 @@ static ssize_t store_io_db(struct device *dev,
if (end_addr < start_addr)
return -EINVAL;
+ mutex_lock(&s->ops_mutex);
ret = adjust_io(s, add, start_addr, end_addr);
if (!ret)
s->resource_setup_new = 1;
+ mutex_unlock(&s->ops_mutex);
return ret ? ret : count;
}
@@ -965,9 +1027,19 @@ static ssize_t show_mem_db(struct device *dev,
struct resource_map *p;
ssize_t ret = 0;
- mutex_lock(&rsrc_mutex);
+ mutex_lock(&s->ops_mutex);
data = s->resource_data;
+ for (p = data->mem_db_valid.next; p != &data->mem_db_valid;
+ p = p->next) {
+ if (ret > (PAGE_SIZE - 10))
+ continue;
+ ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
+ "0x%08lx - 0x%08lx\n",
+ ((unsigned long) p->base),
+ ((unsigned long) p->base + p->num - 1));
+ }
+
for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
if (ret > (PAGE_SIZE - 10))
continue;
@@ -977,7 +1049,7 @@ static ssize_t show_mem_db(struct device *dev,
((unsigned long) p->base + p->num - 1));
}
- mutex_unlock(&rsrc_mutex);
+ mutex_unlock(&s->ops_mutex);
return ret;
}
@@ -1005,9 +1077,11 @@ static ssize_t store_mem_db(struct device *dev,
if (end_addr < start_addr)
return -EINVAL;
+ mutex_lock(&s->ops_mutex);
ret = adjust_memory(s, add, start_addr, end_addr);
if (!ret)
s->resource_setup_new = 1;
+ mutex_unlock(&s->ops_mutex);
return ret ? ret : count;
}
diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c
index de6bc333d299..db79ca61cf96 100644
--- a/drivers/pcmcia/sa1111_generic.c
+++ b/drivers/pcmcia/sa1111_generic.c
@@ -21,11 +21,18 @@
#include "sa1111_generic.h"
+#define IDX_IRQ_S0_READY_NINT (0)
+#define IDX_IRQ_S0_CD_VALID (1)
+#define IDX_IRQ_S0_BVD1_STSCHG (2)
+#define IDX_IRQ_S1_READY_NINT (3)
+#define IDX_IRQ_S1_CD_VALID (4)
+#define IDX_IRQ_S1_BVD1_STSCHG (5)
+
static struct pcmcia_irqs irqs[] = {
- { 0, IRQ_S0_CD_VALID, "SA1111 PCMCIA card detect" },
- { 0, IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" },
- { 1, IRQ_S1_CD_VALID, "SA1111 CF card detect" },
- { 1, IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1" },
+ { 0, NO_IRQ, "SA1111 PCMCIA card detect" },
+ { 0, NO_IRQ, "SA1111 PCMCIA BVD1" },
+ { 1, NO_IRQ, "SA1111 CF card detect" },
+ { 1, NO_IRQ, "SA1111 CF BVD1" },
};
static int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
@@ -136,7 +143,9 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
s->soc.ops = ops;
s->soc.socket.owner = ops->owner;
s->soc.socket.dev.parent = &dev->dev;
- s->soc.socket.pci_irq = s->soc.nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT;
+ s->soc.socket.pci_irq = s->soc.nr ?
+ dev->irq[IDX_IRQ_S0_READY_NINT] :
+ dev->irq[IDX_IRQ_S1_READY_NINT];
s->dev = dev;
ret = add(&s->soc);
@@ -162,6 +171,12 @@ static int pcmcia_probe(struct sa1111_dev *dev)
base = dev->mapbase;
+ /* Initialize PCMCIA IRQs */
+ irqs[0].irq = dev->irq[IDX_IRQ_S0_CD_VALID];
+ irqs[1].irq = dev->irq[IDX_IRQ_S0_BVD1_STSCHG];
+ irqs[2].irq = dev->irq[IDX_IRQ_S1_CD_VALID];
+ irqs[3].irq = dev->irq[IDX_IRQ_S1_BVD1_STSCHG];
+
/*
* Initialise the suspend state.
*/
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index 7a456000332a..08278016e58d 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -88,15 +88,14 @@ static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- ssize_t ret;
struct pcmcia_socket *s = to_socket(dev);
if (!count)
return -EINVAL;
- ret = pcmcia_insert_card(s);
+ pcmcia_parse_uevents(s, PCMCIA_UEVENT_INSERT);
- return ret ? ret : count;
+ return count;
}
static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
@@ -113,18 +112,22 @@ static ssize_t pccard_store_card_pm_state(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- ssize_t ret = -EINVAL;
struct pcmcia_socket *s = to_socket(dev);
+ ssize_t ret = count;
if (!count)
return -EINVAL;
- if (!(s->state & SOCKET_SUSPEND) && !strncmp(buf, "off", 3))
- ret = pcmcia_suspend_card(s);
- else if ((s->state & SOCKET_SUSPEND) && !strncmp(buf, "on", 2))
- ret = pcmcia_resume_card(s);
+ if (!strncmp(buf, "off", 3))
+ pcmcia_parse_uevents(s, PCMCIA_UEVENT_SUSPEND);
+ else {
+ if (!strncmp(buf, "on", 2))
+ pcmcia_parse_uevents(s, PCMCIA_UEVENT_RESUME);
+ else
+ ret = -EINVAL;
+ }
- return ret ? -ENODEV : count;
+ return ret;
}
static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
@@ -132,15 +135,14 @@ static ssize_t pccard_store_eject(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- ssize_t ret;
struct pcmcia_socket *s = to_socket(dev);
if (!count)
return -EINVAL;
- ret = pcmcia_eject_card(s);
+ pcmcia_parse_uevents(s, PCMCIA_UEVENT_EJECT);
- return ret ? ret : count;
+ return count;
}
static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
@@ -167,7 +169,9 @@ static ssize_t pccard_store_irq_mask(struct device *dev,
ret = sscanf(buf, "0x%x\n", &mask);
if (ret == 1) {
+ mutex_lock(&s->ops_mutex);
s->irq_mask &= mask;
+ mutex_unlock(&s->ops_mutex);
ret = 0;
}
@@ -187,163 +191,21 @@ static ssize_t pccard_store_resource(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- unsigned long flags;
struct pcmcia_socket *s = to_socket(dev);
if (!count)
return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
+ mutex_lock(&s->ops_mutex);
if (!s->resource_setup_done)
s->resource_setup_done = 1;
- spin_unlock_irqrestore(&s->lock, flags);
-
- mutex_lock(&s->skt_mutex);
- if ((s->callback) &&
- (s->state & SOCKET_PRESENT) &&
- !(s->state & SOCKET_CARDBUS)) {
- if (try_module_get(s->callback->owner)) {
- s->callback->requery(s, 0);
- module_put(s->callback->owner);
- }
- }
- mutex_unlock(&s->skt_mutex);
-
- return count;
-}
-static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
+ mutex_unlock(&s->ops_mutex);
-
-static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count)
-{
- tuple_t tuple;
- int status, i;
- loff_t pointer = 0;
- ssize_t ret = 0;
- u_char *tuplebuffer;
- u_char *tempbuffer;
-
- tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL);
- if (!tuplebuffer)
- return -ENOMEM;
-
- tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL);
- if (!tempbuffer) {
- ret = -ENOMEM;
- goto free_tuple;
- }
-
- memset(&tuple, 0, sizeof(tuple_t));
-
- tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
- tuple.DesiredTuple = RETURN_FIRST_TUPLE;
- tuple.TupleOffset = 0;
-
- status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple);
- while (!status) {
- tuple.TupleData = tuplebuffer;
- tuple.TupleDataMax = 255;
- memset(tuplebuffer, 0, sizeof(u_char) * 255);
-
- status = pccard_get_tuple_data(s, &tuple);
- if (status)
- break;
-
- if (off < (pointer + 2 + tuple.TupleDataLen)) {
- tempbuffer[0] = tuple.TupleCode & 0xff;
- tempbuffer[1] = tuple.TupleLink & 0xff;
- for (i = 0; i < tuple.TupleDataLen; i++)
- tempbuffer[i + 2] = tuplebuffer[i] & 0xff;
-
- for (i = 0; i < (2 + tuple.TupleDataLen); i++) {
- if (((i + pointer) >= off) &&
- (i + pointer) < (off + count)) {
- buf[ret] = tempbuffer[i];
- ret++;
- }
- }
- }
-
- pointer += 2 + tuple.TupleDataLen;
-
- if (pointer >= (off + count))
- break;
-
- if (tuple.TupleCode == CISTPL_END)
- break;
- status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple);
- }
-
- kfree(tempbuffer);
- free_tuple:
- kfree(tuplebuffer);
-
- return ret;
-}
-
-static ssize_t pccard_show_cis(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
-{
- unsigned int size = 0x200;
-
- if (off >= size)
- count = 0;
- else {
- struct pcmcia_socket *s;
- unsigned int chains;
-
- if (off + count > size)
- count = size - off;
-
- s = to_socket(container_of(kobj, struct device, kobj));
-
- if (!(s->state & SOCKET_PRESENT))
- return -ENODEV;
- if (pccard_validate_cis(s, &chains))
- return -EIO;
- if (!chains)
- return -ENODATA;
-
- count = pccard_extract_cis(s, buf, off, count);
- }
-
- return count;
-}
-
-static ssize_t pccard_store_cis(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
-{
- struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj));
- int error;
-
- if (off)
- return -EINVAL;
-
- if (count >= CISTPL_MAX_CIS_SIZE)
- return -EINVAL;
-
- if (!(s->state & SOCKET_PRESENT))
- return -ENODEV;
-
- error = pcmcia_replace_cis(s, buf, count);
- if (error)
- return -EIO;
-
- mutex_lock(&s->skt_mutex);
- if ((s->callback) && (s->state & SOCKET_PRESENT) &&
- !(s->state & SOCKET_CARDBUS)) {
- if (try_module_get(s->callback->owner)) {
- s->callback->requery(s, 1);
- module_put(s->callback->owner);
- }
- }
- mutex_unlock(&s->skt_mutex);
+ pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
return count;
}
-
+static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
static struct attribute *pccard_socket_attributes[] = {
&dev_attr_card_type.attr,
@@ -362,28 +224,12 @@ static const struct attribute_group socket_attrs = {
.attrs = pccard_socket_attributes,
};
-static struct bin_attribute pccard_cis_attr = {
- .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR },
- .size = 0x200,
- .read = pccard_show_cis,
- .write = pccard_store_cis,
-};
-
int pccard_sysfs_add_socket(struct device *dev)
{
- int ret = 0;
-
- ret = sysfs_create_group(&dev->kobj, &socket_attrs);
- if (!ret) {
- ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
- if (ret)
- sysfs_remove_group(&dev->kobj, &socket_attrs);
- }
- return ret;
+ return sysfs_create_group(&dev->kobj, &socket_attrs);
}
void pccard_sysfs_remove_socket(struct device *dev)
{
- sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
sysfs_remove_group(&dev->kobj, &socket_attrs);
}
diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c
new file mode 100644
index 000000000000..f9009d34254b
--- /dev/null
+++ b/drivers/pcmcia/xxs1500_ss.c
@@ -0,0 +1,340 @@
+/*
+ * PCMCIA socket code for the MyCable XXS1500 system.
+ *
+ * Copyright (c) 2009 Manuel Lauss <manuel.lauss@gmail.com>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/resource.h>
+#include <linux/spinlock.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#define MEM_MAP_SIZE 0x400000
+#define IO_MAP_SIZE 0x1000
+
+
+/*
+ * 3.3V cards only; all interfacing is done via gpios:
+ *
+ * 0/1: carddetect (00 = card present, xx = huh)
+ * 4: card irq
+ * 204: reset (high-act)
+ * 205: buffer enable (low-act)
+ * 208/209: card voltage key (00,01,10,11)
+ * 210: battwarn
+ * 211: batdead
+ * 214: power (low-act)
+ */
+#define GPIO_CDA 0
+#define GPIO_CDB 1
+#define GPIO_CARDIRQ 4
+#define GPIO_RESET 204
+#define GPIO_OUTEN 205
+#define GPIO_VSL 208
+#define GPIO_VSH 209
+#define GPIO_BATTDEAD 210
+#define GPIO_BATTWARN 211
+#define GPIO_POWER 214
+
+struct xxs1500_pcmcia_sock {
+ struct pcmcia_socket socket;
+ void *virt_io;
+
+ phys_addr_t phys_io;
+ phys_addr_t phys_attr;
+ phys_addr_t phys_mem;
+
+ /* previous flags for set_socket() */
+ unsigned int old_flags;
+};
+
+#define to_xxs_socket(x) container_of(x, struct xxs1500_pcmcia_sock, socket)
+
+static irqreturn_t cdirq(int irq, void *data)
+{
+ struct xxs1500_pcmcia_sock *sock = data;
+
+ pcmcia_parse_events(&sock->socket, SS_DETECT);
+
+ return IRQ_HANDLED;
+}
+
+static int xxs1500_pcmcia_configure(struct pcmcia_socket *skt,
+ struct socket_state_t *state)
+{
+ struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+ unsigned int changed;
+
+ /* power control */
+ switch (state->Vcc) {
+ case 0:
+ gpio_set_value(GPIO_POWER, 1); /* power off */
+ break;
+ case 33:
+ gpio_set_value(GPIO_POWER, 0); /* power on */
+ break;
+ case 50:
+ default:
+ return -EINVAL;
+ }
+
+ changed = state->flags ^ sock->old_flags;
+
+ if (changed & SS_RESET) {
+ if (state->flags & SS_RESET) {
+ gpio_set_value(GPIO_RESET, 1); /* assert reset */
+ gpio_set_value(GPIO_OUTEN, 1); /* buffers off */
+ } else {
+ gpio_set_value(GPIO_RESET, 0); /* deassert reset */
+ gpio_set_value(GPIO_OUTEN, 0); /* buffers on */
+ msleep(500);
+ }
+ }
+
+ sock->old_flags = state->flags;
+
+ return 0;
+}
+
+static int xxs1500_pcmcia_get_status(struct pcmcia_socket *skt,
+ unsigned int *value)
+{
+ unsigned int status;
+ int i;
+
+ status = 0;
+
+ /* check carddetects: GPIO[0:1] must both be low */
+ if (!gpio_get_value(GPIO_CDA) && !gpio_get_value(GPIO_CDB))
+ status |= SS_DETECT;
+
+ /* determine card voltage: GPIO[208:209] binary value */
+ i = (!!gpio_get_value(GPIO_VSL)) | ((!!gpio_get_value(GPIO_VSH)) << 1);
+
+ switch (i) {
+ case 0:
+ case 1:
+ case 2:
+ status |= SS_3VCARD; /* 3V card */
+ break;
+ case 3: /* 5V card, unsupported */
+ default:
+ status |= SS_XVCARD; /* treated as unsupported in core */
+ }
+
+ /* GPIO214: low active power switch */
+ status |= gpio_get_value(GPIO_POWER) ? 0 : SS_POWERON;
+
+ /* GPIO204: high-active reset line */
+ status |= gpio_get_value(GPIO_RESET) ? SS_RESET : SS_READY;
+
+ /* other stuff */
+ status |= gpio_get_value(GPIO_BATTDEAD) ? 0 : SS_BATDEAD;
+ status |= gpio_get_value(GPIO_BATTWARN) ? 0 : SS_BATWARN;
+
+ *value = status;
+
+ return 0;
+}
+
+static int xxs1500_pcmcia_sock_init(struct pcmcia_socket *skt)
+{
+ gpio_direction_input(GPIO_CDA);
+ gpio_direction_input(GPIO_CDB);
+ gpio_direction_input(GPIO_VSL);
+ gpio_direction_input(GPIO_VSH);
+ gpio_direction_input(GPIO_BATTDEAD);
+ gpio_direction_input(GPIO_BATTWARN);
+ gpio_direction_output(GPIO_RESET, 1); /* assert reset */
+ gpio_direction_output(GPIO_OUTEN, 1); /* disable buffers */
+ gpio_direction_output(GPIO_POWER, 1); /* power off */
+
+ return 0;
+}
+
+static int xxs1500_pcmcia_sock_suspend(struct pcmcia_socket *skt)
+{
+ return 0;
+}
+
+static int au1x00_pcmcia_set_io_map(struct pcmcia_socket *skt,
+ struct pccard_io_map *map)
+{
+ struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+
+ map->start = (u32)sock->virt_io;
+ map->stop = map->start + IO_MAP_SIZE;
+
+ return 0;
+}
+
+static int au1x00_pcmcia_set_mem_map(struct pcmcia_socket *skt,
+ struct pccard_mem_map *map)
+{
+ struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+
+ if (map->flags & MAP_ATTRIB)
+ map->static_start = sock->phys_attr + map->card_start;
+ else
+ map->static_start = sock->phys_mem + map->card_start;
+
+ return 0;
+}
+
+static struct pccard_operations xxs1500_pcmcia_operations = {
+ .init = xxs1500_pcmcia_sock_init,
+ .suspend = xxs1500_pcmcia_sock_suspend,
+ .get_status = xxs1500_pcmcia_get_status,
+ .set_socket = xxs1500_pcmcia_configure,
+ .set_io_map = au1x00_pcmcia_set_io_map,
+ .set_mem_map = au1x00_pcmcia_set_mem_map,
+};
+
+static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev)
+{
+ struct xxs1500_pcmcia_sock *sock;
+ struct resource *r;
+ int ret, irq;
+
+ sock = kzalloc(sizeof(struct xxs1500_pcmcia_sock), GFP_KERNEL);
+ if (!sock)
+ return -ENOMEM;
+
+ ret = -ENODEV;
+
+ /* 36bit PCMCIA Attribute area address */
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-attr");
+ if (!r) {
+ dev_err(&pdev->dev, "missing 'pcmcia-attr' resource!\n");
+ goto out0;
+ }
+ sock->phys_attr = r->start;
+
+ /* 36bit PCMCIA Memory area address */
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-mem");
+ if (!r) {
+ dev_err(&pdev->dev, "missing 'pcmcia-mem' resource!\n");
+ goto out0;
+ }
+ sock->phys_mem = r->start;
+
+ /* 36bit PCMCIA IO area address */
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-io");
+ if (!r) {
+ dev_err(&pdev->dev, "missing 'pcmcia-io' resource!\n");
+ goto out0;
+ }
+ sock->phys_io = r->start;
+
+
+ /*
+ * PCMCIA client drivers use the inb/outb macros to access
+ * the IO registers. Since mips_io_port_base is added
+ * to the access address of the mips implementation of
+ * inb/outb, we need to subtract it here because we want
+ * to access the I/O or MEM address directly, without
+ * going through this "mips_io_port_base" mechanism.
+ */
+ sock->virt_io = (void *)(ioremap(sock->phys_io, IO_MAP_SIZE) -
+ mips_io_port_base);
+
+ if (!sock->virt_io) {
+ dev_err(&pdev->dev, "cannot remap IO area\n");
+ ret = -ENOMEM;
+ goto out0;
+ }
+
+ sock->socket.ops = &xxs1500_pcmcia_operations;
+ sock->socket.owner = THIS_MODULE;
+ sock->socket.pci_irq = gpio_to_irq(GPIO_CARDIRQ);
+ sock->socket.features = SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+ sock->socket.map_size = MEM_MAP_SIZE;
+ sock->socket.io_offset = (unsigned long)sock->virt_io;
+ sock->socket.dev.parent = &pdev->dev;
+ sock->socket.resource_ops = &pccard_static_ops;
+
+ platform_set_drvdata(pdev, sock);
+
+ /* setup carddetect irq: use one of the 2 GPIOs as an
+ * edge detector.
+ */
+ irq = gpio_to_irq(GPIO_CDA);
+ set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
+ ret = request_irq(irq, cdirq, 0, "pcmcia_carddetect", sock);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot setup cd irq\n");
+ goto out1;
+ }
+
+ ret = pcmcia_register_socket(&sock->socket);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register\n");
+ goto out2;
+ }
+
+ printk(KERN_INFO "MyCable XXS1500 PCMCIA socket services\n");
+
+ return 0;
+
+out2:
+ free_irq(gpio_to_irq(GPIO_CDA), sock);
+out1:
+ iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+out0:
+ kfree(sock);
+ return ret;
+}
+
+static int __devexit xxs1500_pcmcia_remove(struct platform_device *pdev)
+{
+ struct xxs1500_pcmcia_sock *sock = platform_get_drvdata(pdev);
+
+ pcmcia_unregister_socket(&sock->socket);
+ free_irq(gpio_to_irq(GPIO_CDA), sock);
+ iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+ kfree(sock);
+
+ return 0;
+}
+
+static struct platform_driver xxs1500_pcmcia_socket_driver = {
+ .driver = {
+ .name = "xxs1500_pcmcia",
+ .owner = THIS_MODULE,
+ },
+ .probe = xxs1500_pcmcia_probe,
+ .remove = __devexit_p(xxs1500_pcmcia_remove),
+};
+
+int __init xxs1500_pcmcia_socket_load(void)
+{
+ return platform_driver_register(&xxs1500_pcmcia_socket_driver);
+}
+
+void __exit xxs1500_pcmcia_socket_unload(void)
+{
+ platform_driver_unregister(&xxs1500_pcmcia_socket_driver);
+}
+
+module_init(xxs1500_pcmcia_socket_load);
+module_exit(xxs1500_pcmcia_socket_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCMCIA Socket Services for MyCable XXS1500 systems");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index e4d12acdd525..967c766f53ba 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -37,6 +37,11 @@ static int pwr_irqs_off;
module_param(pwr_irqs_off, bool, 0644);
MODULE_PARM_DESC(pwr_irqs_off, "Force IRQs off during power-on of slot. Use only when seeing IRQ storms!");
+static char o2_speedup[] = "default";
+module_param_string(o2_speedup, o2_speedup, sizeof(o2_speedup), 0444);
+MODULE_PARM_DESC(o2_speedup, "Use prefetch/burst for O2-bridges: 'on', 'off' "
+ "or 'default' (uses recommended behaviour for the detected bridge)");
+
#define debug(x, s, args...) dev_dbg(&s->dev->dev, x, ##args)
/* Don't ask.. */
@@ -649,9 +654,10 @@ static int yenta_search_one_res(struct resource *root, struct resource *res,
static int yenta_search_res(struct yenta_socket *socket, struct resource *res,
u32 min)
{
+ struct resource *root;
int i;
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- struct resource *root = socket->dev->bus->resource[i];
+
+ pci_bus_for_each_resource(socket->dev->bus, root, i) {
if (!root)
continue;
@@ -1402,10 +1408,10 @@ static struct pci_device_id yenta_table[] = {
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7510, TI12XX),
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7610, TI12XX),
- CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_710, TI12XX),
- CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_712, TI12XX),
- CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_720, TI12XX),
- CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_722, TI12XX),
+ CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_710, ENE),
+ CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_712, ENE),
+ CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_720, ENE),
+ CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_722, ENE),
CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1211, ENE),
CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1225, ENE),
CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1410, ENE),
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index db32c25e3605..e631dbeafd79 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -59,6 +59,8 @@ config ASUS_LAPTOP
select NEW_LEDS
select BACKLIGHT_CLASS_DEVICE
depends on INPUT
+ depends on RFKILL || RFKILL = n
+ select INPUT_SPARSEKMAP
---help---
This is the new Linux driver for Asus laptops. It may also support some
MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
@@ -79,6 +81,7 @@ config DELL_LAPTOP
depends on BACKLIGHT_CLASS_DEVICE
depends on RFKILL || RFKILL = n
depends on POWER_SUPPLY
+ depends on SERIO_I8042
default n
---help---
This driver adds support for rfkill and backlight control to Dell
@@ -147,6 +150,7 @@ config MSI_LAPTOP
tristate "MSI Laptop Extras"
depends on ACPI
depends on BACKLIGHT_CLASS_DEVICE
+ depends on RFKILL
---help---
This is a driver for laptops built by MSI (MICRO-STAR
INTERNATIONAL):
@@ -176,6 +180,7 @@ config COMPAL_LAPTOP
tristate "Compal Laptop Extras"
depends on ACPI
depends on BACKLIGHT_CLASS_DEVICE
+ depends on RFKILL
---help---
This is a driver for laptops built by Compal:
@@ -319,9 +324,15 @@ config THINKPAD_ACPI_VIDEO
server running, phase of the moon, and the current mood of
Schroedinger's cat. If you can use X.org's RandR to control
your ThinkPad's video output ports instead of this feature,
- don't think twice: do it and say N here to save some memory.
+ don't think twice: do it and say N here to save memory and avoid
+ bad interactions with X.org.
+
+ NOTE: access to this feature is limited to processes with the
+ CAP_SYS_ADMIN capability, to avoid local DoS issues in platforms
+ where it interacts badly with X.org.
- If you are not sure, say Y here.
+ If you are not sure, say Y here but do try to check if you could
+ be using X.org RandR instead.
config THINKPAD_ACPI_HOTKEY_POLL
bool "Support NVRAM polling for hot keys"
@@ -364,6 +375,7 @@ config EEEPC_LAPTOP
select HWMON
select LEDS_CLASS
select NEW_LEDS
+ select INPUT_SPARSEKMAP
---help---
This driver supports the Fn-Fx keys on Eee PC laptops.
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 07d14dfdf0b4..226b3e93498c 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -934,7 +934,7 @@ static int __devinit acer_backlight_init(struct device *dev)
acer_backlight_device = bd;
bd->props.power = FB_BLANK_UNBLANK;
- bd->props.brightness = max_brightness;
+ bd->props.brightness = read_brightness(bd);
bd->props.max_brightness = max_brightness;
backlight_update_status(bd);
return 0;
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 61a1c7503658..791fcf321506 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -45,58 +45,23 @@
#include <linux/fb.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/rfkill.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
-#include <asm/uaccess.h>
-#include <linux/input.h>
-
-#define ASUS_LAPTOP_VERSION "0.42"
-
-#define ASUS_HOTK_NAME "Asus Laptop Support"
-#define ASUS_HOTK_CLASS "hotkey"
-#define ASUS_HOTK_DEVICE_NAME "Hotkey"
-#define ASUS_HOTK_FILE KBUILD_MODNAME
-#define ASUS_HOTK_PREFIX "\\_SB.ATKD."
+#define ASUS_LAPTOP_VERSION "0.42"
-/*
- * Some events we use, same for all Asus
- */
-#define ATKD_BR_UP 0x10
-#define ATKD_BR_DOWN 0x20
-#define ATKD_LCD_ON 0x33
-#define ATKD_LCD_OFF 0x34
-
-/*
- * Known bits returned by \_SB.ATKD.HWRS
- */
-#define WL_HWRS 0x80
-#define BT_HWRS 0x100
-
-/*
- * Flags for hotk status
- * WL_ON and BT_ON are also used for wireless_status()
- */
-#define WL_ON 0x01 /* internal Wifi */
-#define BT_ON 0x02 /* internal Bluetooth */
-#define MLED_ON 0x04 /* mail LED */
-#define TLED_ON 0x08 /* touchpad LED */
-#define RLED_ON 0x10 /* Record LED */
-#define PLED_ON 0x20 /* Phone LED */
-#define GLED_ON 0x40 /* Gaming LED */
-#define LCD_ON 0x80 /* LCD backlight */
-#define GPS_ON 0x100 /* GPS */
-#define KEY_ON 0x200 /* Keyboard backlight */
-
-#define ASUS_LOG ASUS_HOTK_FILE ": "
-#define ASUS_ERR KERN_ERR ASUS_LOG
-#define ASUS_WARNING KERN_WARNING ASUS_LOG
-#define ASUS_NOTICE KERN_NOTICE ASUS_LOG
-#define ASUS_INFO KERN_INFO ASUS_LOG
-#define ASUS_DEBUG KERN_DEBUG ASUS_LOG
+#define ASUS_LAPTOP_NAME "Asus Laptop Support"
+#define ASUS_LAPTOP_CLASS "hotkey"
+#define ASUS_LAPTOP_DEVICE_NAME "Hotkey"
+#define ASUS_LAPTOP_FILE KBUILD_MODNAME
+#define ASUS_LAPTOP_PREFIX "\\_SB.ATKD."
MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
-MODULE_DESCRIPTION(ASUS_HOTK_NAME);
+MODULE_DESCRIPTION(ASUS_LAPTOP_NAME);
MODULE_LICENSE("GPL");
/*
@@ -113,225 +78,209 @@ static uint wapf = 1;
module_param(wapf, uint, 0644);
MODULE_PARM_DESC(wapf, "WAPF value");
-#define ASUS_HANDLE(object, paths...) \
- static acpi_handle object##_handle = NULL; \
- static char *object##_paths[] = { paths }
+static uint wlan_status = 1;
+static uint bluetooth_status = 1;
+
+module_param(wlan_status, uint, 0644);
+MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot "
+ "(0 = disabled, 1 = enabled, -1 = don't do anything). "
+ "default is 1");
+
+module_param(bluetooth_status, uint, 0644);
+MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
+ "(0 = disabled, 1 = enabled, -1 = don't do anything). "
+ "default is 1");
+
+/*
+ * Some events we use, same for all Asus
+ */
+#define ATKD_BR_UP 0x10 /* (event & ~ATKD_BR_UP) = brightness level */
+#define ATKD_BR_DOWN 0x20 /* (event & ~ATKD_BR_DOWN) = britghness level */
+#define ATKD_BR_MIN ATKD_BR_UP
+#define ATKD_BR_MAX (ATKD_BR_DOWN | 0xF) /* 0x2f */
+#define ATKD_LCD_ON 0x33
+#define ATKD_LCD_OFF 0x34
+
+/*
+ * Known bits returned by \_SB.ATKD.HWRS
+ */
+#define WL_HWRS 0x80
+#define BT_HWRS 0x100
+
+/*
+ * Flags for hotk status
+ * WL_ON and BT_ON are also used for wireless_status()
+ */
+#define WL_RSTS 0x01 /* internal Wifi */
+#define BT_RSTS 0x02 /* internal Bluetooth */
/* LED */
-ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED");
-ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED");
-ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */
-ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */
-ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */
+#define METHOD_MLED "MLED"
+#define METHOD_TLED "TLED"
+#define METHOD_RLED "RLED" /* W1JC */
+#define METHOD_PLED "PLED" /* A7J */
+#define METHOD_GLED "GLED" /* G1, G2 (probably) */
/* LEDD */
-ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
+#define METHOD_LEDD "SLCM"
/*
* Bluetooth and WLAN
* WLED and BLED are not handled like other XLED, because in some dsdt
* they also control the WLAN/Bluetooth device.
*/
-ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED");
-ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED");
-ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS"); /* All new models */
+#define METHOD_WLAN "WLED"
+#define METHOD_BLUETOOTH "BLED"
+#define METHOD_WL_STATUS "RSTS"
/* Brightness */
-ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV");
-ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "GPLV");
+#define METHOD_BRIGHTNESS_SET "SPLV"
+#define METHOD_BRIGHTNESS_GET "GPLV"
/* Backlight */
-ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
- "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */
- "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */
- "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
- "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
- "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */
- "\\_SB.PCI0.PX40.Q10", /* S1x */
- "\\Q10"); /* A2x, L2D, L3D, M2E */
+static acpi_handle lcd_switch_handle;
+static const char *lcd_switch_paths[] = {
+ "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
+ "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */
+ "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */
+ "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
+ "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
+ "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */
+ "\\_SB.PCI0.PX40.Q10", /* S1x */
+ "\\Q10"}; /* A2x, L2D, L3D, M2E */
/* Display */
-ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");
-ASUS_HANDLE(display_get,
- /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
- "\\_SB.PCI0.P0P1.VGA.GETD",
- /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
- "\\_SB.PCI0.P0P2.VGA.GETD",
- /* A6V A6Q */
- "\\_SB.PCI0.P0P3.VGA.GETD",
- /* A6T, A6M */
- "\\_SB.PCI0.P0PA.VGA.GETD",
- /* L3C */
- "\\_SB.PCI0.PCI1.VGAC.NMAP",
- /* Z96F */
- "\\_SB.PCI0.VGA.GETD",
- /* A2D */
- "\\ACTD",
- /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
- "\\ADVG",
- /* P30 */
- "\\DNXT",
- /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
- "\\INFB",
- /* A3F A6F A3N A3L M6N W3N W6A */
- "\\SSTE");
-
-ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */
-ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */
+#define METHOD_SWITCH_DISPLAY "SDSP"
+
+static acpi_handle display_get_handle;
+static const char *display_get_paths[] = {
+ /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
+ "\\_SB.PCI0.P0P1.VGA.GETD",
+ /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
+ "\\_SB.PCI0.P0P2.VGA.GETD",
+ /* A6V A6Q */
+ "\\_SB.PCI0.P0P3.VGA.GETD",
+ /* A6T, A6M */
+ "\\_SB.PCI0.P0PA.VGA.GETD",
+ /* L3C */
+ "\\_SB.PCI0.PCI1.VGAC.NMAP",
+ /* Z96F */
+ "\\_SB.PCI0.VGA.GETD",
+ /* A2D */
+ "\\ACTD",
+ /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
+ "\\ADVG",
+ /* P30 */
+ "\\DNXT",
+ /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
+ "\\INFB",
+ /* A3F A6F A3N A3L M6N W3N W6A */
+ "\\SSTE"};
+
+#define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */
+#define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */
/* GPS */
/* R2H use different handle for GPS on/off */
-ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON"); /* R2H */
-ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */
-ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST");
+#define METHOD_GPS_ON "SDON"
+#define METHOD_GPS_OFF "SDOF"
+#define METHOD_GPS_STATUS "GPST"
/* Keyboard light */
-ASUS_HANDLE(kled_set, ASUS_HOTK_PREFIX "SLKB");
-ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB");
+#define METHOD_KBD_LIGHT_SET "SLKB"
+#define METHOD_KBD_LIGHT_GET "GLKB"
/*
- * This is the main structure, we can use it to store anything interesting
- * about the hotk device
+ * Define a specific led structure to keep the main structure clean
*/
-struct asus_hotk {
- char *name; /* laptop name */
- struct acpi_device *device; /* the device we are in */
- acpi_handle handle; /* the handle of the hotk device */
- char status; /* status of the hotk, for LEDs, ... */
- u32 ledd_status; /* status of the LED display */
- u8 light_level; /* light sensor level */
- u8 light_switch; /* light sensor switch value */
- u16 event_count[128]; /* count for each event TODO make this better */
- struct input_dev *inputdev;
- u16 *keycode_map;
+struct asus_led {
+ int wk;
+ struct work_struct work;
+ struct led_classdev led;
+ struct asus_laptop *asus;
+ const char *method;
};
/*
- * This header is made available to allow proper configuration given model,
- * revision number , ... this info cannot go in struct asus_hotk because it is
- * available before the hotk
- */
-static struct acpi_table_header *asus_info;
-
-/* The actual device the driver binds to */
-static struct asus_hotk *hotk;
-
-/*
- * The hotkey driver declaration
+ * This is the main structure, we can use it to store anything interesting
+ * about the hotk device
*/
-static const struct acpi_device_id asus_device_ids[] = {
- {"ATK0100", 0},
- {"ATK0101", 0},
- {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, asus_device_ids);
+struct asus_laptop {
+ char *name; /* laptop name */
-static int asus_hotk_add(struct acpi_device *device);
-static int asus_hotk_remove(struct acpi_device *device, int type);
-static void asus_hotk_notify(struct acpi_device *device, u32 event);
+ struct acpi_table_header *dsdt_info;
+ struct platform_device *platform_device;
+ struct acpi_device *device; /* the device we are in */
+ struct backlight_device *backlight_device;
-static struct acpi_driver asus_hotk_driver = {
- .name = ASUS_HOTK_NAME,
- .class = ASUS_HOTK_CLASS,
- .owner = THIS_MODULE,
- .ids = asus_device_ids,
- .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
- .ops = {
- .add = asus_hotk_add,
- .remove = asus_hotk_remove,
- .notify = asus_hotk_notify,
- },
-};
+ struct input_dev *inputdev;
+ struct key_entry *keymap;
-/* The backlight device /sys/class/backlight */
-static struct backlight_device *asus_backlight_device;
+ struct asus_led mled;
+ struct asus_led tled;
+ struct asus_led rled;
+ struct asus_led pled;
+ struct asus_led gled;
+ struct asus_led kled;
+ struct workqueue_struct *led_workqueue;
-/*
- * The backlight class declaration
- */
-static int read_brightness(struct backlight_device *bd);
-static int update_bl_status(struct backlight_device *bd);
-static struct backlight_ops asusbl_ops = {
- .get_brightness = read_brightness,
- .update_status = update_bl_status,
-};
+ int wireless_status;
+ bool have_rsts;
+ int lcd_state;
-/*
- * These functions actually update the LED's, and are called from a
- * workqueue. By doing this as separate work rather than when the LED
- * subsystem asks, we avoid messing with the Asus ACPI stuff during a
- * potentially bad time, such as a timer interrupt.
- */
-static struct workqueue_struct *led_workqueue;
-
-#define ASUS_LED(object, ledname, max) \
- static void object##_led_set(struct led_classdev *led_cdev, \
- enum led_brightness value); \
- static enum led_brightness object##_led_get( \
- struct led_classdev *led_cdev); \
- static void object##_led_update(struct work_struct *ignored); \
- static int object##_led_wk; \
- static DECLARE_WORK(object##_led_work, object##_led_update); \
- static struct led_classdev object##_led = { \
- .name = "asus::" ledname, \
- .brightness_set = object##_led_set, \
- .brightness_get = object##_led_get, \
- .max_brightness = max \
- }
+ struct rfkill *gps_rfkill;
-ASUS_LED(mled, "mail", 1);
-ASUS_LED(tled, "touchpad", 1);
-ASUS_LED(rled, "record", 1);
-ASUS_LED(pled, "phone", 1);
-ASUS_LED(gled, "gaming", 1);
-ASUS_LED(kled, "kbd_backlight", 3);
-
-struct key_entry {
- char type;
- u8 code;
- u16 keycode;
+ acpi_handle handle; /* the handle of the hotk device */
+ u32 ledd_status; /* status of the LED display */
+ u8 light_level; /* light sensor level */
+ u8 light_switch; /* light sensor switch value */
+ u16 event_count[128]; /* count for each event TODO make this better */
+ u16 *keycode_map;
};
-enum { KE_KEY, KE_END };
-
-static struct key_entry asus_keymap[] = {
- {KE_KEY, 0x02, KEY_SCREENLOCK},
- {KE_KEY, 0x05, KEY_WLAN},
- {KE_KEY, 0x08, KEY_F13},
- {KE_KEY, 0x17, KEY_ZOOM},
- {KE_KEY, 0x1f, KEY_BATTERY},
- {KE_KEY, 0x30, KEY_VOLUMEUP},
- {KE_KEY, 0x31, KEY_VOLUMEDOWN},
- {KE_KEY, 0x32, KEY_MUTE},
- {KE_KEY, 0x33, KEY_SWITCHVIDEOMODE},
- {KE_KEY, 0x34, KEY_SWITCHVIDEOMODE},
- {KE_KEY, 0x40, KEY_PREVIOUSSONG},
- {KE_KEY, 0x41, KEY_NEXTSONG},
- {KE_KEY, 0x43, KEY_STOPCD},
- {KE_KEY, 0x45, KEY_PLAYPAUSE},
- {KE_KEY, 0x4c, KEY_MEDIA},
- {KE_KEY, 0x50, KEY_EMAIL},
- {KE_KEY, 0x51, KEY_WWW},
- {KE_KEY, 0x55, KEY_CALC},
- {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */
- {KE_KEY, 0x5D, KEY_WLAN},
- {KE_KEY, 0x5E, KEY_WLAN},
- {KE_KEY, 0x5F, KEY_WLAN},
- {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE},
- {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE},
- {KE_KEY, 0x62, KEY_SWITCHVIDEOMODE},
- {KE_KEY, 0x63, KEY_SWITCHVIDEOMODE},
- {KE_KEY, 0x6B, KEY_F13}, /* Lock Touchpad */
- {KE_KEY, 0x82, KEY_CAMERA},
- {KE_KEY, 0x88, KEY_WLAN },
- {KE_KEY, 0x8A, KEY_PROG1},
- {KE_KEY, 0x95, KEY_MEDIA},
- {KE_KEY, 0x99, KEY_PHONE},
- {KE_KEY, 0xc4, KEY_KBDILLUMUP},
- {KE_KEY, 0xc5, KEY_KBDILLUMDOWN},
+static const struct key_entry asus_keymap[] = {
+ /* Lenovo SL Specific keycodes */
+ {KE_KEY, 0x02, { KEY_SCREENLOCK } },
+ {KE_KEY, 0x05, { KEY_WLAN } },
+ {KE_KEY, 0x08, { KEY_F13 } },
+ {KE_KEY, 0x17, { KEY_ZOOM } },
+ {KE_KEY, 0x1f, { KEY_BATTERY } },
+ /* End of Lenovo SL Specific keycodes */
+ {KE_KEY, 0x30, { KEY_VOLUMEUP } },
+ {KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
+ {KE_KEY, 0x32, { KEY_MUTE } },
+ {KE_KEY, 0x33, { KEY_SWITCHVIDEOMODE } },
+ {KE_KEY, 0x34, { KEY_SWITCHVIDEOMODE } },
+ {KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
+ {KE_KEY, 0x41, { KEY_NEXTSONG } },
+ {KE_KEY, 0x43, { KEY_STOPCD } },
+ {KE_KEY, 0x45, { KEY_PLAYPAUSE } },
+ {KE_KEY, 0x4c, { KEY_MEDIA } },
+ {KE_KEY, 0x50, { KEY_EMAIL } },
+ {KE_KEY, 0x51, { KEY_WWW } },
+ {KE_KEY, 0x55, { KEY_CALC } },
+ {KE_KEY, 0x5C, { KEY_SCREENLOCK } }, /* Screenlock */
+ {KE_KEY, 0x5D, { KEY_WLAN } },
+ {KE_KEY, 0x5E, { KEY_WLAN } },
+ {KE_KEY, 0x5F, { KEY_WLAN } },
+ {KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } },
+ {KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } },
+ {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
+ {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
+ {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */
+ {KE_KEY, 0x7E, { KEY_BLUETOOTH } },
+ {KE_KEY, 0x7D, { KEY_BLUETOOTH } },
+ {KE_KEY, 0x82, { KEY_CAMERA } },
+ {KE_KEY, 0x88, { KEY_WLAN } },
+ {KE_KEY, 0x8A, { KEY_PROG1 } },
+ {KE_KEY, 0x95, { KEY_MEDIA } },
+ {KE_KEY, 0x99, { KEY_PHONE } },
+ {KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
+ {KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
{KE_END, 0},
};
+
/*
* This function evaluates an ACPI method, given an int as parameter, the
* method is searched within the scope of the handle, can be NULL. The output
@@ -339,8 +288,8 @@ static struct key_entry asus_keymap[] = {
*
* returns 0 if write is successful, -1 else.
*/
-static int write_acpi_int(acpi_handle handle, const char *method, int val,
- struct acpi_buffer *output)
+static int write_acpi_int_ret(acpi_handle handle, const char *method, int val,
+ struct acpi_buffer *output)
{
struct acpi_object_list params; /* list of input parameters (an int) */
union acpi_object in_obj; /* the only param we use */
@@ -361,102 +310,82 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
return -1;
}
-static int read_wireless_status(int mask)
+static int write_acpi_int(acpi_handle handle, const char *method, int val)
{
- unsigned long long status;
- acpi_status rv = AE_OK;
+ return write_acpi_int_ret(handle, method, val, NULL);
+}
+
+static int acpi_check_handle(acpi_handle handle, const char *method,
+ acpi_handle *ret)
+{
+ acpi_status status;
- if (!wireless_status_handle)
- return (hotk->status & mask) ? 1 : 0;
+ if (method == NULL)
+ return -ENODEV;
- rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status);
- if (ACPI_FAILURE(rv))
- pr_warning("Error reading Wireless status\n");
- else
- return (status & mask) ? 1 : 0;
+ if (ret)
+ status = acpi_get_handle(handle, (char *)method,
+ ret);
+ else {
+ acpi_handle dummy;
- return (hotk->status & mask) ? 1 : 0;
+ status = acpi_get_handle(handle, (char *)method,
+ &dummy);
+ }
+
+ if (status != AE_OK) {
+ if (ret)
+ pr_warning("Error finding %s\n", method);
+ return -ENODEV;
+ }
+ return 0;
}
-static int read_gps_status(void)
+/* Generic LED function */
+static int asus_led_set(struct asus_laptop *asus, const char *method,
+ int value)
{
- unsigned long long status;
- acpi_status rv = AE_OK;
-
- rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status);
- if (ACPI_FAILURE(rv))
- pr_warning("Error reading GPS status\n");
+ if (!strcmp(method, METHOD_MLED))
+ value = !value;
+ else if (!strcmp(method, METHOD_GLED))
+ value = !value + 1;
else
- return status ? 1 : 0;
+ value = !!value;
- return (hotk->status & GPS_ON) ? 1 : 0;
+ return write_acpi_int(asus->handle, method, value);
}
-/* Generic LED functions */
-static int read_status(int mask)
+/*
+ * LEDs
+ */
+/* /sys/class/led handlers */
+static void asus_led_cdev_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
- /* There is a special method for both wireless devices */
- if (mask == BT_ON || mask == WL_ON)
- return read_wireless_status(mask);
- else if (mask == GPS_ON)
- return read_gps_status();
+ struct asus_led *led = container_of(led_cdev, struct asus_led, led);
+ struct asus_laptop *asus = led->asus;
- return (hotk->status & mask) ? 1 : 0;
+ led->wk = !!value;
+ queue_work(asus->led_workqueue, &led->work);
}
-static void write_status(acpi_handle handle, int out, int mask)
+static void asus_led_cdev_update(struct work_struct *work)
{
- hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);
-
- switch (mask) {
- case MLED_ON:
- out = !(out & 0x1);
- break;
- case GLED_ON:
- out = (out & 0x1) + 1;
- break;
- case GPS_ON:
- handle = (out) ? gps_on_handle : gps_off_handle;
- out = 0x02;
- break;
- default:
- out &= 0x1;
- break;
- }
+ struct asus_led *led = container_of(work, struct asus_led, work);
+ struct asus_laptop *asus = led->asus;
- if (write_acpi_int(handle, NULL, out, NULL))
- pr_warning(" write failed %x\n", mask);
+ asus_led_set(asus, led->method, led->wk);
}
-/* /sys/class/led handlers */
-#define ASUS_LED_HANDLER(object, mask) \
- static void object##_led_set(struct led_classdev *led_cdev, \
- enum led_brightness value) \
- { \
- object##_led_wk = (value > 0) ? 1 : 0; \
- queue_work(led_workqueue, &object##_led_work); \
- } \
- static void object##_led_update(struct work_struct *ignored) \
- { \
- int value = object##_led_wk; \
- write_status(object##_set_handle, value, (mask)); \
- } \
- static enum led_brightness object##_led_get( \
- struct led_classdev *led_cdev) \
- { \
- return led_cdev->brightness; \
- }
-
-ASUS_LED_HANDLER(mled, MLED_ON);
-ASUS_LED_HANDLER(pled, PLED_ON);
-ASUS_LED_HANDLER(rled, RLED_ON);
-ASUS_LED_HANDLER(tled, TLED_ON);
-ASUS_LED_HANDLER(gled, GLED_ON);
+static enum led_brightness asus_led_cdev_get(struct led_classdev *led_cdev)
+{
+ return led_cdev->brightness;
+}
/*
- * Keyboard backlight
+ * Keyboard backlight (also a LED)
*/
-static int get_kled_lvl(void)
+static int asus_kled_lvl(struct asus_laptop *asus)
{
unsigned long long kblv;
struct acpi_object_list params;
@@ -468,75 +397,183 @@ static int get_kled_lvl(void)
in_obj.type = ACPI_TYPE_INTEGER;
in_obj.integer.value = 2;
- rv = acpi_evaluate_integer(kled_get_handle, NULL, &params, &kblv);
+ rv = acpi_evaluate_integer(asus->handle, METHOD_KBD_LIGHT_GET,
+ &params, &kblv);
if (ACPI_FAILURE(rv)) {
pr_warning("Error reading kled level\n");
- return 0;
+ return -ENODEV;
}
return kblv;
}
-static int set_kled_lvl(int kblv)
+static int asus_kled_set(struct asus_laptop *asus, int kblv)
{
if (kblv > 0)
kblv = (1 << 7) | (kblv & 0x7F);
else
kblv = 0;
- if (write_acpi_int(kled_set_handle, NULL, kblv, NULL)) {
+ if (write_acpi_int(asus->handle, METHOD_KBD_LIGHT_SET, kblv)) {
pr_warning("Keyboard LED display write failed\n");
return -EINVAL;
}
return 0;
}
-static void kled_led_set(struct led_classdev *led_cdev,
- enum led_brightness value)
+static void asus_kled_cdev_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
- kled_led_wk = value;
- queue_work(led_workqueue, &kled_led_work);
+ struct asus_led *led = container_of(led_cdev, struct asus_led, led);
+ struct asus_laptop *asus = led->asus;
+
+ led->wk = value;
+ queue_work(asus->led_workqueue, &led->work);
}
-static void kled_led_update(struct work_struct *ignored)
+static void asus_kled_cdev_update(struct work_struct *work)
{
- set_kled_lvl(kled_led_wk);
+ struct asus_led *led = container_of(work, struct asus_led, work);
+ struct asus_laptop *asus = led->asus;
+
+ asus_kled_set(asus, led->wk);
}
-static enum led_brightness kled_led_get(struct led_classdev *led_cdev)
+static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev)
{
- return get_kled_lvl();
+ struct asus_led *led = container_of(led_cdev, struct asus_led, led);
+ struct asus_laptop *asus = led->asus;
+
+ return asus_kled_lvl(asus);
}
-static int get_lcd_state(void)
+static void asus_led_exit(struct asus_laptop *asus)
{
- return read_status(LCD_ON);
+ if (asus->mled.led.dev)
+ led_classdev_unregister(&asus->mled.led);
+ if (asus->tled.led.dev)
+ led_classdev_unregister(&asus->tled.led);
+ if (asus->pled.led.dev)
+ led_classdev_unregister(&asus->pled.led);
+ if (asus->rled.led.dev)
+ led_classdev_unregister(&asus->rled.led);
+ if (asus->gled.led.dev)
+ led_classdev_unregister(&asus->gled.led);
+ if (asus->kled.led.dev)
+ led_classdev_unregister(&asus->kled.led);
+ if (asus->led_workqueue) {
+ destroy_workqueue(asus->led_workqueue);
+ asus->led_workqueue = NULL;
+ }
}
-static int set_lcd_state(int value)
+/* Ugly macro, need to fix that later */
+static int asus_led_register(struct asus_laptop *asus,
+ struct asus_led *led,
+ const char *name, const char *method)
+{
+ struct led_classdev *led_cdev = &led->led;
+
+ if (!method || acpi_check_handle(asus->handle, method, NULL))
+ return 0; /* Led not present */
+
+ led->asus = asus;
+ led->method = method;
+
+ INIT_WORK(&led->work, asus_led_cdev_update);
+ led_cdev->name = name;
+ led_cdev->brightness_set = asus_led_cdev_set;
+ led_cdev->brightness_get = asus_led_cdev_get;
+ led_cdev->max_brightness = 1;
+ return led_classdev_register(&asus->platform_device->dev, led_cdev);
+}
+
+static int asus_led_init(struct asus_laptop *asus)
+{
+ int r;
+
+ /*
+ * Functions that actually update the LED's are called from a
+ * workqueue. By doing this as separate work rather than when the LED
+ * subsystem asks, we avoid messing with the Asus ACPI stuff during a
+ * potentially bad time, such as a timer interrupt.
+ */
+ asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
+ if (!asus->led_workqueue)
+ return -ENOMEM;
+
+ r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED);
+ if (r)
+ goto error;
+ r = asus_led_register(asus, &asus->tled, "asus::touchpad", METHOD_TLED);
+ if (r)
+ goto error;
+ r = asus_led_register(asus, &asus->rled, "asus::record", METHOD_RLED);
+ if (r)
+ goto error;
+ r = asus_led_register(asus, &asus->pled, "asus::phone", METHOD_PLED);
+ if (r)
+ goto error;
+ r = asus_led_register(asus, &asus->gled, "asus::gaming", METHOD_GLED);
+ if (r)
+ goto error;
+ if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL) &&
+ !acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) {
+ struct asus_led *led = &asus->kled;
+ struct led_classdev *cdev = &led->led;
+
+ led->asus = asus;
+
+ INIT_WORK(&led->work, asus_kled_cdev_update);
+ cdev->name = "asus::kbd_backlight";
+ cdev->brightness_set = asus_kled_cdev_set;
+ cdev->brightness_get = asus_kled_cdev_get;
+ cdev->max_brightness = 3;
+ r = led_classdev_register(&asus->platform_device->dev, cdev);
+ }
+error:
+ if (r)
+ asus_led_exit(asus);
+ return r;
+}
+
+/*
+ * Backlight device
+ */
+static int asus_lcd_status(struct asus_laptop *asus)
+{
+ return asus->lcd_state;
+}
+
+static int asus_lcd_set(struct asus_laptop *asus, int value)
{
int lcd = 0;
acpi_status status = 0;
- lcd = value ? 1 : 0;
+ lcd = !!value;
- if (lcd == get_lcd_state())
+ if (lcd == asus_lcd_status(asus))
return 0;
- if (lcd_switch_handle) {
- status = acpi_evaluate_object(lcd_switch_handle,
- NULL, NULL, NULL);
+ if (!lcd_switch_handle)
+ return -ENODEV;
+
+ status = acpi_evaluate_object(lcd_switch_handle,
+ NULL, NULL, NULL);
- if (ACPI_FAILURE(status))
- pr_warning("Error switching LCD\n");
+ if (ACPI_FAILURE(status)) {
+ pr_warning("Error switching LCD\n");
+ return -ENODEV;
}
- write_status(NULL, lcd, LCD_ON);
+ asus->lcd_state = lcd;
return 0;
}
-static void lcd_blank(int blank)
+static void lcd_blank(struct asus_laptop *asus, int blank)
{
- struct backlight_device *bd = asus_backlight_device;
+ struct backlight_device *bd = asus->backlight_device;
+
+ asus->lcd_state = (blank == FB_BLANK_UNBLANK);
if (bd) {
bd->props.power = blank;
@@ -544,44 +581,91 @@ static void lcd_blank(int blank)
}
}
-static int read_brightness(struct backlight_device *bd)
+static int asus_read_brightness(struct backlight_device *bd)
{
+ struct asus_laptop *asus = bl_get_data(bd);
unsigned long long value;
acpi_status rv = AE_OK;
- rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value);
+ rv = acpi_evaluate_integer(asus->handle, METHOD_BRIGHTNESS_GET,
+ NULL, &value);
if (ACPI_FAILURE(rv))
pr_warning("Error reading brightness\n");
return value;
}
-static int set_brightness(struct backlight_device *bd, int value)
+static int asus_set_brightness(struct backlight_device *bd, int value)
{
- int ret = 0;
-
- value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
- /* 0 <= value <= 15 */
+ struct asus_laptop *asus = bl_get_data(bd);
- if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
+ if (write_acpi_int(asus->handle, METHOD_BRIGHTNESS_SET, value)) {
pr_warning("Error changing brightness\n");
- ret = -EIO;
+ return -EIO;
}
-
- return ret;
+ return 0;
}
static int update_bl_status(struct backlight_device *bd)
{
+ struct asus_laptop *asus = bl_get_data(bd);
int rv;
int value = bd->props.brightness;
- rv = set_brightness(bd, value);
+ rv = asus_set_brightness(bd, value);
if (rv)
return rv;
value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0;
- return set_lcd_state(value);
+ return asus_lcd_set(asus, value);
+}
+
+static struct backlight_ops asusbl_ops = {
+ .get_brightness = asus_read_brightness,
+ .update_status = update_bl_status,
+};
+
+static int asus_backlight_notify(struct asus_laptop *asus)
+{
+ struct backlight_device *bd = asus->backlight_device;
+ int old = bd->props.brightness;
+
+ backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
+
+ return old;
+}
+
+static int asus_backlight_init(struct asus_laptop *asus)
+{
+ struct backlight_device *bd;
+ struct device *dev = &asus->platform_device->dev;
+
+ if (!acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) &&
+ !acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) &&
+ lcd_switch_handle) {
+ bd = backlight_device_register(ASUS_LAPTOP_FILE, dev,
+ asus, &asusbl_ops);
+ if (IS_ERR(bd)) {
+ pr_err("Could not register asus backlight device\n");
+ asus->backlight_device = NULL;
+ return PTR_ERR(bd);
+ }
+
+ asus->backlight_device = bd;
+
+ bd->props.max_brightness = 15;
+ bd->props.power = FB_BLANK_UNBLANK;
+ bd->props.brightness = asus_read_brightness(bd);
+ backlight_update_status(bd);
+ }
+ return 0;
+}
+
+static void asus_backlight_exit(struct asus_laptop *asus)
+{
+ if (asus->backlight_device)
+ backlight_device_unregister(asus->backlight_device);
+ asus->backlight_device = NULL;
}
/*
@@ -596,25 +680,26 @@ static int update_bl_status(struct backlight_device *bd)
static ssize_t show_infos(struct device *dev,
struct device_attribute *attr, char *page)
{
+ struct asus_laptop *asus = dev_get_drvdata(dev);
int len = 0;
unsigned long long temp;
char buf[16]; /* enough for all info */
acpi_status rv = AE_OK;
/*
- * We use the easy way, we don't care of off and count, so we don't set eof
- * to 1
+ * We use the easy way, we don't care of off and count,
+ * so we don't set eof to 1
*/
- len += sprintf(page, ASUS_HOTK_NAME " " ASUS_LAPTOP_VERSION "\n");
- len += sprintf(page + len, "Model reference : %s\n", hotk->name);
+ len += sprintf(page, ASUS_LAPTOP_NAME " " ASUS_LAPTOP_VERSION "\n");
+ len += sprintf(page + len, "Model reference : %s\n", asus->name);
/*
* The SFUN method probably allows the original driver to get the list
* of features supported by a given model. For now, 0x0100 or 0x0800
* bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
* The significance of others is yet to be found.
*/
- rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp);
+ rv = acpi_evaluate_integer(asus->handle, "SFUN", NULL, &temp);
if (!ACPI_FAILURE(rv))
len += sprintf(page + len, "SFUN value : %#x\n",
(uint) temp);
@@ -624,7 +709,7 @@ static ssize_t show_infos(struct device *dev,
* The significance of others is yet to be found.
* If we don't find the method, we assume the device are present.
*/
- rv = acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &temp);
+ rv = acpi_evaluate_integer(asus->handle, "HRWS", NULL, &temp);
if (!ACPI_FAILURE(rv))
len += sprintf(page + len, "HRWS value : %#x\n",
(uint) temp);
@@ -635,26 +720,26 @@ static ssize_t show_infos(struct device *dev,
* Note: since not all the laptops provide this method, errors are
* silently ignored.
*/
- rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp);
+ rv = acpi_evaluate_integer(asus->handle, "ASYM", NULL, &temp);
if (!ACPI_FAILURE(rv))
len += sprintf(page + len, "ASYM value : %#x\n",
(uint) temp);
- if (asus_info) {
- snprintf(buf, 16, "%d", asus_info->length);
+ if (asus->dsdt_info) {
+ snprintf(buf, 16, "%d", asus->dsdt_info->length);
len += sprintf(page + len, "DSDT length : %s\n", buf);
- snprintf(buf, 16, "%d", asus_info->checksum);
+ snprintf(buf, 16, "%d", asus->dsdt_info->checksum);
len += sprintf(page + len, "DSDT checksum : %s\n", buf);
- snprintf(buf, 16, "%d", asus_info->revision);
+ snprintf(buf, 16, "%d", asus->dsdt_info->revision);
len += sprintf(page + len, "DSDT revision : %s\n", buf);
- snprintf(buf, 7, "%s", asus_info->oem_id);
+ snprintf(buf, 7, "%s", asus->dsdt_info->oem_id);
len += sprintf(page + len, "OEM id : %s\n", buf);
- snprintf(buf, 9, "%s", asus_info->oem_table_id);
+ snprintf(buf, 9, "%s", asus->dsdt_info->oem_table_id);
len += sprintf(page + len, "OEM table id : %s\n", buf);
- snprintf(buf, 16, "%x", asus_info->oem_revision);
+ snprintf(buf, 16, "%x", asus->dsdt_info->oem_revision);
len += sprintf(page + len, "OEM revision : 0x%s\n", buf);
- snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
+ snprintf(buf, 5, "%s", asus->dsdt_info->asl_compiler_id);
len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
- snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
+ snprintf(buf, 16, "%x", asus->dsdt_info->asl_compiler_revision);
len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf);
}
@@ -672,8 +757,9 @@ static int parse_arg(const char *buf, unsigned long count, int *val)
return count;
}
-static ssize_t store_status(const char *buf, size_t count,
- acpi_handle handle, int mask)
+static ssize_t sysfs_acpi_set(struct asus_laptop *asus,
+ const char *buf, size_t count,
+ const char *method)
{
int rv, value;
int out = 0;
@@ -682,8 +768,8 @@ static ssize_t store_status(const char *buf, size_t count,
if (rv > 0)
out = value ? 1 : 0;
- write_status(handle, out, mask);
-
+ if (write_acpi_int(asus->handle, method, value))
+ return -ENODEV;
return rv;
}
@@ -693,67 +779,116 @@ static ssize_t store_status(const char *buf, size_t count,
static ssize_t show_ledd(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "0x%08x\n", hotk->ledd_status);
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sprintf(buf, "0x%08x\n", asus->ledd_status);
}
static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct asus_laptop *asus = dev_get_drvdata(dev);
int rv, value;
rv = parse_arg(buf, count, &value);
if (rv > 0) {
- if (write_acpi_int(ledd_set_handle, NULL, value, NULL))
+ if (write_acpi_int(asus->handle, METHOD_LEDD, value))
pr_warning("LED display write failed\n");
else
- hotk->ledd_status = (u32) value;
+ asus->ledd_status = (u32) value;
}
return rv;
}
/*
+ * Wireless
+ */
+static int asus_wireless_status(struct asus_laptop *asus, int mask)
+{
+ unsigned long long status;
+ acpi_status rv = AE_OK;
+
+ if (!asus->have_rsts)
+ return (asus->wireless_status & mask) ? 1 : 0;
+
+ rv = acpi_evaluate_integer(asus->handle, METHOD_WL_STATUS,
+ NULL, &status);
+ if (ACPI_FAILURE(rv)) {
+ pr_warning("Error reading Wireless status\n");
+ return -EINVAL;
+ }
+ return !!(status & mask);
+}
+
+/*
* WLAN
*/
+static int asus_wlan_set(struct asus_laptop *asus, int status)
+{
+ if (write_acpi_int(asus->handle, METHOD_WLAN, !!status)) {
+ pr_warning("Error setting wlan status to %d", status);
+ return -EIO;
+ }
+ return 0;
+}
+
static ssize_t show_wlan(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%d\n", read_status(WL_ON));
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", asus_wireless_status(asus, WL_RSTS));
}
static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- return store_status(buf, count, wl_switch_handle, WL_ON);
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sysfs_acpi_set(asus, buf, count, METHOD_WLAN);
}
/*
* Bluetooth
*/
+static int asus_bluetooth_set(struct asus_laptop *asus, int status)
+{
+ if (write_acpi_int(asus->handle, METHOD_BLUETOOTH, !!status)) {
+ pr_warning("Error setting bluetooth status to %d", status);
+ return -EIO;
+ }
+ return 0;
+}
+
static ssize_t show_bluetooth(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%d\n", read_status(BT_ON));
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", asus_wireless_status(asus, BT_RSTS));
}
static ssize_t store_bluetooth(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
- return store_status(buf, count, bt_switch_handle, BT_ON);
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sysfs_acpi_set(asus, buf, count, METHOD_BLUETOOTH);
}
/*
* Display
*/
-static void set_display(int value)
+static void asus_set_display(struct asus_laptop *asus, int value)
{
/* no sanity check needed for now */
- if (write_acpi_int(display_set_handle, NULL, value, NULL))
+ if (write_acpi_int(asus->handle, METHOD_SWITCH_DISPLAY, value))
pr_warning("Error setting display\n");
return;
}
-static int read_display(void)
+static int read_display(struct asus_laptop *asus)
{
unsigned long long value = 0;
acpi_status rv = AE_OK;
@@ -769,7 +904,7 @@ static int read_display(void)
pr_warning("Error reading display status\n");
}
- value &= 0x0F; /* needed for some models, shouldn't hurt others */
+ value &= 0x0F; /* needed for some models, shouldn't hurt others */
return value;
}
@@ -781,7 +916,11 @@ static int read_display(void)
static ssize_t show_disp(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%d\n", read_display());
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ if (!display_get_handle)
+ return -ENODEV;
+ return sprintf(buf, "%d\n", read_display(asus));
}
/*
@@ -794,65 +933,72 @@ static ssize_t show_disp(struct device *dev,
static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct asus_laptop *asus = dev_get_drvdata(dev);
int rv, value;
rv = parse_arg(buf, count, &value);
if (rv > 0)
- set_display(value);
+ asus_set_display(asus, value);
return rv;
}
/*
* Light Sens
*/
-static void set_light_sens_switch(int value)
+static void asus_als_switch(struct asus_laptop *asus, int value)
{
- if (write_acpi_int(ls_switch_handle, NULL, value, NULL))
+ if (write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value))
pr_warning("Error setting light sensor switch\n");
- hotk->light_switch = value;
+ asus->light_switch = value;
}
static ssize_t show_lssw(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%d\n", hotk->light_switch);
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", asus->light_switch);
}
static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct asus_laptop *asus = dev_get_drvdata(dev);
int rv, value;
rv = parse_arg(buf, count, &value);
if (rv > 0)
- set_light_sens_switch(value ? 1 : 0);
+ asus_als_switch(asus, value ? 1 : 0);
return rv;
}
-static void set_light_sens_level(int value)
+static void asus_als_level(struct asus_laptop *asus, int value)
{
- if (write_acpi_int(ls_level_handle, NULL, value, NULL))
+ if (write_acpi_int(asus->handle, METHOD_ALS_LEVEL, value))
pr_warning("Error setting light sensor level\n");
- hotk->light_level = value;
+ asus->light_level = value;
}
static ssize_t show_lslvl(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%d\n", hotk->light_level);
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", asus->light_level);
}
static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct asus_laptop *asus = dev_get_drvdata(dev);
int rv, value;
rv = parse_arg(buf, count, &value);
if (rv > 0) {
value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
/* 0 <= value <= 15 */
- set_light_sens_level(value);
+ asus_als_level(asus, value);
}
return rv;
@@ -861,197 +1007,309 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
/*
* GPS
*/
+static int asus_gps_status(struct asus_laptop *asus)
+{
+ unsigned long long status;
+ acpi_status rv = AE_OK;
+
+ rv = acpi_evaluate_integer(asus->handle, METHOD_GPS_STATUS,
+ NULL, &status);
+ if (ACPI_FAILURE(rv)) {
+ pr_warning("Error reading GPS status\n");
+ return -ENODEV;
+ }
+ return !!status;
+}
+
+static int asus_gps_switch(struct asus_laptop *asus, int status)
+{
+ const char *meth = status ? METHOD_GPS_ON : METHOD_GPS_OFF;
+
+ if (write_acpi_int(asus->handle, meth, 0x02))
+ return -ENODEV;
+ return 0;
+}
+
static ssize_t show_gps(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%d\n", read_status(GPS_ON));
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", asus_gps_status(asus));
}
static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- return store_status(buf, count, NULL, GPS_ON);
+ struct asus_laptop *asus = dev_get_drvdata(dev);
+ int rv, value;
+ int ret;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv <= 0)
+ return -EINVAL;
+ ret = asus_gps_switch(asus, !!value);
+ if (ret)
+ return ret;
+ rfkill_set_sw_state(asus->gps_rfkill, !value);
+ return rv;
}
/*
- * Hotkey functions
+ * rfkill
*/
-static struct key_entry *asus_get_entry_by_scancode(int code)
+static int asus_gps_rfkill_set(void *data, bool blocked)
{
- struct key_entry *key;
-
- for (key = asus_keymap; key->type != KE_END; key++)
- if (code == key->code)
- return key;
+ acpi_handle handle = data;
- return NULL;
+ return asus_gps_switch(handle, !blocked);
}
-static struct key_entry *asus_get_entry_by_keycode(int code)
-{
- struct key_entry *key;
-
- for (key = asus_keymap; key->type != KE_END; key++)
- if (code == key->keycode && key->type == KE_KEY)
- return key;
+static const struct rfkill_ops asus_gps_rfkill_ops = {
+ .set_block = asus_gps_rfkill_set,
+};
- return NULL;
+static void asus_rfkill_exit(struct asus_laptop *asus)
+{
+ if (asus->gps_rfkill) {
+ rfkill_unregister(asus->gps_rfkill);
+ rfkill_destroy(asus->gps_rfkill);
+ asus->gps_rfkill = NULL;
+ }
}
-static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+static int asus_rfkill_init(struct asus_laptop *asus)
{
- struct key_entry *key = asus_get_entry_by_scancode(scancode);
+ int result;
- if (key && key->type == KE_KEY) {
- *keycode = key->keycode;
+ if (acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) ||
+ acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) ||
+ acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
return 0;
+
+ asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev,
+ RFKILL_TYPE_GPS,
+ &asus_gps_rfkill_ops, NULL);
+ if (!asus->gps_rfkill)
+ return -EINVAL;
+
+ result = rfkill_register(asus->gps_rfkill);
+ if (result) {
+ rfkill_destroy(asus->gps_rfkill);
+ asus->gps_rfkill = NULL;
}
- return -EINVAL;
+ return result;
}
-static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode)
+/*
+ * Input device (i.e. hotkeys)
+ */
+static void asus_input_notify(struct asus_laptop *asus, int event)
{
- struct key_entry *key;
- int old_keycode;
+ if (asus->inputdev)
+ sparse_keymap_report_event(asus->inputdev, event, 1, true);
+}
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
+static int asus_input_init(struct asus_laptop *asus)
+{
+ struct input_dev *input;
+ int error;
- key = asus_get_entry_by_scancode(scancode);
- if (key && key->type == KE_KEY) {
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!asus_get_entry_by_keycode(old_keycode))
- clear_bit(old_keycode, dev->keybit);
+ input = input_allocate_device();
+ if (!input) {
+ pr_info("Unable to allocate input device\n");
return 0;
}
+ input->name = "Asus Laptop extra buttons";
+ input->phys = ASUS_LAPTOP_FILE "/input0";
+ input->id.bustype = BUS_HOST;
+ input->dev.parent = &asus->platform_device->dev;
+ input_set_drvdata(input, asus);
+
+ error = sparse_keymap_setup(input, asus_keymap, NULL);
+ if (error) {
+ pr_err("Unable to setup input device keymap\n");
+ goto err_keymap;
+ }
+ error = input_register_device(input);
+ if (error) {
+ pr_info("Unable to register input device\n");
+ goto err_device;
+ }
+
+ asus->inputdev = input;
+ return 0;
- return -EINVAL;
+err_keymap:
+ sparse_keymap_free(input);
+err_device:
+ input_free_device(input);
+ return error;
}
-static void asus_hotk_notify(struct acpi_device *device, u32 event)
+static void asus_input_exit(struct asus_laptop *asus)
{
- static struct key_entry *key;
- u16 count;
+ if (asus->inputdev) {
+ sparse_keymap_free(asus->inputdev);
+ input_unregister_device(asus->inputdev);
+ }
+}
- /* TODO Find a better way to handle events count. */
- if (!hotk)
- return;
+/*
+ * ACPI driver
+ */
+static void asus_acpi_notify(struct acpi_device *device, u32 event)
+{
+ struct asus_laptop *asus = acpi_driver_data(device);
+ u16 count;
/*
* We need to tell the backlight device when the backlight power is
* switched
*/
- if (event == ATKD_LCD_ON) {
- write_status(NULL, 1, LCD_ON);
- lcd_blank(FB_BLANK_UNBLANK);
- } else if (event == ATKD_LCD_OFF) {
- write_status(NULL, 0, LCD_ON);
- lcd_blank(FB_BLANK_POWERDOWN);
- }
+ if (event == ATKD_LCD_ON)
+ lcd_blank(asus, FB_BLANK_UNBLANK);
+ else if (event == ATKD_LCD_OFF)
+ lcd_blank(asus, FB_BLANK_POWERDOWN);
- count = hotk->event_count[event % 128]++;
- acpi_bus_generate_proc_event(hotk->device, event, count);
- acpi_bus_generate_netlink_event(hotk->device->pnp.device_class,
- dev_name(&hotk->device->dev), event,
+ /* TODO Find a better way to handle events count. */
+ count = asus->event_count[event % 128]++;
+ acpi_bus_generate_proc_event(asus->device, event, count);
+ acpi_bus_generate_netlink_event(asus->device->pnp.device_class,
+ dev_name(&asus->device->dev), event,
count);
- if (hotk->inputdev) {
- key = asus_get_entry_by_scancode(event);
- if (!key)
- return ;
-
- switch (key->type) {
- case KE_KEY:
- input_report_key(hotk->inputdev, key->keycode, 1);
- input_sync(hotk->inputdev);
- input_report_key(hotk->inputdev, key->keycode, 0);
- input_sync(hotk->inputdev);
- break;
+ /* Brightness events are special */
+ if (event >= ATKD_BR_MIN && event <= ATKD_BR_MAX) {
+
+ /* Ignore them completely if the acpi video driver is used */
+ if (asus->backlight_device != NULL) {
+ /* Update the backlight device. */
+ asus_backlight_notify(asus);
}
+ return ;
}
+ asus_input_notify(asus, event);
}
-#define ASUS_CREATE_DEVICE_ATTR(_name) \
- struct device_attribute dev_attr_##_name = { \
- .attr = { \
- .name = __stringify(_name), \
- .mode = 0 }, \
- .show = NULL, \
- .store = NULL, \
+static DEVICE_ATTR(infos, S_IRUGO, show_infos, NULL);
+static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan);
+static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR, show_bluetooth,
+ store_bluetooth);
+static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp);
+static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
+static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
+static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
+static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps);
+
+static void asus_sysfs_exit(struct asus_laptop *asus)
+{
+ struct platform_device *device = asus->platform_device;
+
+ device_remove_file(&device->dev, &dev_attr_infos);
+ device_remove_file(&device->dev, &dev_attr_wlan);
+ device_remove_file(&device->dev, &dev_attr_bluetooth);
+ device_remove_file(&device->dev, &dev_attr_display);
+ device_remove_file(&device->dev, &dev_attr_ledd);
+ device_remove_file(&device->dev, &dev_attr_ls_switch);
+ device_remove_file(&device->dev, &dev_attr_ls_level);
+ device_remove_file(&device->dev, &dev_attr_gps);
+}
+
+static int asus_sysfs_init(struct asus_laptop *asus)
+{
+ struct platform_device *device = asus->platform_device;
+ int err;
+
+ err = device_create_file(&device->dev, &dev_attr_infos);
+ if (err)
+ return err;
+
+ if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL)) {
+ err = device_create_file(&device->dev, &dev_attr_wlan);
+ if (err)
+ return err;
}
-#define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store) \
- do { \
- dev_attr_##_name.attr.mode = _mode; \
- dev_attr_##_name.show = _show; \
- dev_attr_##_name.store = _store; \
- } while(0)
-
-static ASUS_CREATE_DEVICE_ATTR(infos);
-static ASUS_CREATE_DEVICE_ATTR(wlan);
-static ASUS_CREATE_DEVICE_ATTR(bluetooth);
-static ASUS_CREATE_DEVICE_ATTR(display);
-static ASUS_CREATE_DEVICE_ATTR(ledd);
-static ASUS_CREATE_DEVICE_ATTR(ls_switch);
-static ASUS_CREATE_DEVICE_ATTR(ls_level);
-static ASUS_CREATE_DEVICE_ATTR(gps);
-
-static struct attribute *asuspf_attributes[] = {
- &dev_attr_infos.attr,
- &dev_attr_wlan.attr,
- &dev_attr_bluetooth.attr,
- &dev_attr_display.attr,
- &dev_attr_ledd.attr,
- &dev_attr_ls_switch.attr,
- &dev_attr_ls_level.attr,
- &dev_attr_gps.attr,
- NULL
-};
+ if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL)) {
+ err = device_create_file(&device->dev, &dev_attr_bluetooth);
+ if (err)
+ return err;
+ }
-static struct attribute_group asuspf_attribute_group = {
- .attrs = asuspf_attributes
-};
+ if (!acpi_check_handle(asus->handle, METHOD_SWITCH_DISPLAY, NULL)) {
+ err = device_create_file(&device->dev, &dev_attr_display);
+ if (err)
+ return err;
+ }
-static struct platform_driver asuspf_driver = {
- .driver = {
- .name = ASUS_HOTK_FILE,
- .owner = THIS_MODULE,
- }
-};
+ if (!acpi_check_handle(asus->handle, METHOD_LEDD, NULL)) {
+ err = device_create_file(&device->dev, &dev_attr_ledd);
+ if (err)
+ return err;
+ }
-static struct platform_device *asuspf_device;
+ if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) &&
+ !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) {
+ err = device_create_file(&device->dev, &dev_attr_ls_switch);
+ if (err)
+ return err;
+ err = device_create_file(&device->dev, &dev_attr_ls_level);
+ if (err)
+ return err;
+ }
-static void asus_hotk_add_fs(void)
-{
- ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL);
+ if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
+ !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
+ !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) {
+ err = device_create_file(&device->dev, &dev_attr_gps);
+ if (err)
+ return err;
+ }
- if (wl_switch_handle)
- ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan);
+ return err;
+}
+
+static int asus_platform_init(struct asus_laptop *asus)
+{
+ int err;
- if (bt_switch_handle)
- ASUS_SET_DEVICE_ATTR(bluetooth, 0644,
- show_bluetooth, store_bluetooth);
+ asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1);
+ if (!asus->platform_device)
+ return -ENOMEM;
+ platform_set_drvdata(asus->platform_device, asus);
- if (display_set_handle && display_get_handle)
- ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, store_disp);
- else if (display_set_handle)
- ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp);
+ err = platform_device_add(asus->platform_device);
+ if (err)
+ goto fail_platform_device;
- if (ledd_set_handle)
- ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd);
+ err = asus_sysfs_init(asus);
+ if (err)
+ goto fail_sysfs;
+ return 0;
- if (ls_switch_handle && ls_level_handle) {
- ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl);
- ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw);
- }
+fail_sysfs:
+ asus_sysfs_exit(asus);
+ platform_device_del(asus->platform_device);
+fail_platform_device:
+ platform_device_put(asus->platform_device);
+ return err;
+}
- if (gps_status_handle && gps_on_handle && gps_off_handle)
- ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps);
+static void asus_platform_exit(struct asus_laptop *asus)
+{
+ asus_sysfs_exit(asus);
+ platform_device_unregister(asus->platform_device);
}
+static struct platform_driver platform_driver = {
+ .driver = {
+ .name = ASUS_LAPTOP_FILE,
+ .owner = THIS_MODULE,
+ }
+};
+
static int asus_handle_init(char *name, acpi_handle * handle,
char **paths, int num_paths)
{
@@ -1073,10 +1331,11 @@ static int asus_handle_init(char *name, acpi_handle * handle,
ARRAY_SIZE(object##_paths))
/*
- * This function is used to initialize the hotk with right values. In this
- * method, we can make all the detection we want, and modify the hotk struct
+ * This function is used to initialize the context with right values. In this
+ * method, we can make all the detection we want, and modify the asus_laptop
+ * struct
*/
-static int asus_hotk_get_info(void)
+static int asus_laptop_get_info(struct asus_laptop *asus)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *model = NULL;
@@ -1089,22 +1348,21 @@ static int asus_hotk_get_info(void)
* models, but late enough to allow acpi_bus_register_driver() to fail
* before doing anything ACPI-specific. Should we encounter a machine,
* which needs special handling (i.e. its hotkey device has a different
- * HID), this bit will be moved. A global variable asus_info contains
- * the DSDT header.
+ * HID), this bit will be moved.
*/
- status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
+ status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus->dsdt_info);
if (ACPI_FAILURE(status))
pr_warning("Couldn't get the DSDT table header\n");
/* We have to write 0 on init this far for all ASUS models */
- if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
+ if (write_acpi_int_ret(asus->handle, "INIT", 0, &buffer)) {
pr_err("Hotkey initialization failed\n");
return -ENODEV;
}
/* This needs to be called for some laptops to init properly */
status =
- acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result);
+ acpi_evaluate_integer(asus->handle, "BSTS", NULL, &bsts_result);
if (ACPI_FAILURE(status))
pr_warning("Error calling BSTS\n");
else if (bsts_result)
@@ -1112,8 +1370,8 @@ static int asus_hotk_get_info(void)
(uint) bsts_result);
/* This too ... */
- write_acpi_int(hotk->handle, "CWAP", wapf, NULL);
-
+ if (write_acpi_int(asus->handle, "CWAP", wapf))
+ pr_err("Error calling CWAP(%d)\n", wapf);
/*
* Try to match the object returned by INIT to the specific model.
* Handle every possible object (or the lack of thereof) the DSDT
@@ -1134,397 +1392,210 @@ static int asus_hotk_get_info(void)
break;
}
}
- hotk->name = kstrdup(string, GFP_KERNEL);
- if (!hotk->name)
+ asus->name = kstrdup(string, GFP_KERNEL);
+ if (!asus->name)
return -ENOMEM;
if (*string)
pr_notice(" %s model detected\n", string);
- ASUS_HANDLE_INIT(mled_set);
- ASUS_HANDLE_INIT(tled_set);
- ASUS_HANDLE_INIT(rled_set);
- ASUS_HANDLE_INIT(pled_set);
- ASUS_HANDLE_INIT(gled_set);
-
- ASUS_HANDLE_INIT(ledd_set);
-
- ASUS_HANDLE_INIT(kled_set);
- ASUS_HANDLE_INIT(kled_get);
-
/*
* The HWRS method return informations about the hardware.
* 0x80 bit is for WLAN, 0x100 for Bluetooth.
* The significance of others is yet to be found.
- * If we don't find the method, we assume the device are present.
*/
status =
- acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result);
- if (ACPI_FAILURE(status))
- hwrs_result = WL_HWRS | BT_HWRS;
-
- if (hwrs_result & WL_HWRS)
- ASUS_HANDLE_INIT(wl_switch);
- if (hwrs_result & BT_HWRS)
- ASUS_HANDLE_INIT(bt_switch);
-
- ASUS_HANDLE_INIT(wireless_status);
+ acpi_evaluate_integer(asus->handle, "HRWS", NULL, &hwrs_result);
+ if (!ACPI_FAILURE(status))
+ pr_notice(" HRWS returned %x", (int)hwrs_result);
- ASUS_HANDLE_INIT(brightness_set);
- ASUS_HANDLE_INIT(brightness_get);
+ if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL))
+ asus->have_rsts = true;
+ /* Scheduled for removal */
ASUS_HANDLE_INIT(lcd_switch);
-
- ASUS_HANDLE_INIT(display_set);
ASUS_HANDLE_INIT(display_get);
- /*
- * There is a lot of models with "ALSL", but a few get
- * a real light sens, so we need to check it.
- */
- if (!ASUS_HANDLE_INIT(ls_switch))
- ASUS_HANDLE_INIT(ls_level);
-
- ASUS_HANDLE_INIT(gps_on);
- ASUS_HANDLE_INIT(gps_off);
- ASUS_HANDLE_INIT(gps_status);
-
kfree(model);
return AE_OK;
}
-static int asus_input_init(void)
-{
- const struct key_entry *key;
- int result;
+static bool asus_device_present;
- hotk->inputdev = input_allocate_device();
- if (!hotk->inputdev) {
- pr_info("Unable to allocate input device\n");
- return 0;
- }
- hotk->inputdev->name = "Asus Laptop extra buttons";
- hotk->inputdev->phys = ASUS_HOTK_FILE "/input0";
- hotk->inputdev->id.bustype = BUS_HOST;
- hotk->inputdev->getkeycode = asus_getkeycode;
- hotk->inputdev->setkeycode = asus_setkeycode;
-
- for (key = asus_keymap; key->type != KE_END; key++) {
- switch (key->type) {
- case KE_KEY:
- set_bit(EV_KEY, hotk->inputdev->evbit);
- set_bit(key->keycode, hotk->inputdev->keybit);
- break;
- }
- }
- result = input_register_device(hotk->inputdev);
- if (result) {
- pr_info("Unable to register input device\n");
- input_free_device(hotk->inputdev);
- }
- return result;
-}
-
-static int asus_hotk_check(void)
+static int __devinit asus_acpi_init(struct asus_laptop *asus)
{
int result = 0;
- result = acpi_bus_get_status(hotk->device);
+ result = acpi_bus_get_status(asus->device);
if (result)
return result;
-
- if (hotk->device->status.present) {
- result = asus_hotk_get_info();
- } else {
+ if (!asus->device->status.present) {
pr_err("Hotkey device not present, aborting\n");
- return -EINVAL;
+ return -ENODEV;
}
- return result;
-}
-
-static int asus_hotk_found;
-
-static int asus_hotk_add(struct acpi_device *device)
-{
- int result;
-
- pr_notice("Asus Laptop Support version %s\n",
- ASUS_LAPTOP_VERSION);
-
- hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
- if (!hotk)
- return -ENOMEM;
-
- hotk->handle = device->handle;
- strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
- strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
- device->driver_data = hotk;
- hotk->device = device;
-
- result = asus_hotk_check();
+ result = asus_laptop_get_info(asus);
if (result)
- goto end;
-
- asus_hotk_add_fs();
-
- asus_hotk_found = 1;
+ return result;
/* WLED and BLED are on by default */
- write_status(bt_switch_handle, 1, BT_ON);
- write_status(wl_switch_handle, 1, WL_ON);
-
- /* If the h/w switch is off, we need to check the real status */
- write_status(NULL, read_status(BT_ON), BT_ON);
- write_status(NULL, read_status(WL_ON), WL_ON);
+ if (bluetooth_status >= 0)
+ asus_bluetooth_set(asus, !!bluetooth_status);
- /* LCD Backlight is on by default */
- write_status(NULL, 1, LCD_ON);
+ if (wlan_status >= 0)
+ asus_wlan_set(asus, !!wlan_status);
/* Keyboard Backlight is on by default */
- if (kled_set_handle)
- set_kled_lvl(1);
+ if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL))
+ asus_kled_set(asus, 1);
/* LED display is off by default */
- hotk->ledd_status = 0xFFF;
+ asus->ledd_status = 0xFFF;
/* Set initial values of light sensor and level */
- hotk->light_switch = 0; /* Default to light sensor disabled */
- hotk->light_level = 5; /* level 5 for sensor sensitivity */
+ asus->light_switch = 0; /* Default to light sensor disabled */
+ asus->light_level = 5; /* level 5 for sensor sensitivity */
- if (ls_switch_handle)
- set_light_sens_switch(hotk->light_switch);
-
- if (ls_level_handle)
- set_light_sens_level(hotk->light_level);
-
- /* GPS is on by default */
- write_status(NULL, 1, GPS_ON);
-
-end:
- if (result) {
- kfree(hotk->name);
- kfree(hotk);
+ if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) &&
+ !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) {
+ asus_als_switch(asus, asus->light_switch);
+ asus_als_level(asus, asus->light_level);
}
+ asus->lcd_state = 1; /* LCD should be on when the module load */
return result;
}
-static int asus_hotk_remove(struct acpi_device *device, int type)
-{
- kfree(hotk->name);
- kfree(hotk);
-
- return 0;
-}
-
-static void asus_backlight_exit(void)
+static int __devinit asus_acpi_add(struct acpi_device *device)
{
- if (asus_backlight_device)
- backlight_device_unregister(asus_backlight_device);
-}
-
-#define ASUS_LED_UNREGISTER(object) \
- if (object##_led.dev) \
- led_classdev_unregister(&object##_led)
+ struct asus_laptop *asus;
+ int result;
-static void asus_led_exit(void)
-{
- destroy_workqueue(led_workqueue);
- ASUS_LED_UNREGISTER(mled);
- ASUS_LED_UNREGISTER(tled);
- ASUS_LED_UNREGISTER(pled);
- ASUS_LED_UNREGISTER(rled);
- ASUS_LED_UNREGISTER(gled);
- ASUS_LED_UNREGISTER(kled);
-}
+ pr_notice("Asus Laptop Support version %s\n",
+ ASUS_LAPTOP_VERSION);
+ asus = kzalloc(sizeof(struct asus_laptop), GFP_KERNEL);
+ if (!asus)
+ return -ENOMEM;
+ asus->handle = device->handle;
+ strcpy(acpi_device_name(device), ASUS_LAPTOP_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ASUS_LAPTOP_CLASS);
+ device->driver_data = asus;
+ asus->device = device;
-static void asus_input_exit(void)
-{
- if (hotk->inputdev)
- input_unregister_device(hotk->inputdev);
-}
+ result = asus_acpi_init(asus);
+ if (result)
+ goto fail_platform;
-static void __exit asus_laptop_exit(void)
-{
- asus_backlight_exit();
- asus_led_exit();
- asus_input_exit();
+ /*
+ * Register the platform device first. It is used as a parent for the
+ * sub-devices below.
+ */
+ result = asus_platform_init(asus);
+ if (result)
+ goto fail_platform;
- acpi_bus_unregister_driver(&asus_hotk_driver);
- sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group);
- platform_device_unregister(asuspf_device);
- platform_driver_unregister(&asuspf_driver);
-}
+ if (!acpi_video_backlight_support()) {
+ result = asus_backlight_init(asus);
+ if (result)
+ goto fail_backlight;
+ } else
+ pr_info("Backlight controlled by ACPI video driver\n");
-static int asus_backlight_init(struct device *dev)
-{
- struct backlight_device *bd;
+ result = asus_input_init(asus);
+ if (result)
+ goto fail_input;
- if (brightness_set_handle && lcd_switch_handle) {
- bd = backlight_device_register(ASUS_HOTK_FILE, dev,
- NULL, &asusbl_ops);
- if (IS_ERR(bd)) {
- pr_err("Could not register asus backlight device\n");
- asus_backlight_device = NULL;
- return PTR_ERR(bd);
- }
+ result = asus_led_init(asus);
+ if (result)
+ goto fail_led;
- asus_backlight_device = bd;
+ result = asus_rfkill_init(asus);
+ if (result)
+ goto fail_rfkill;
- bd->props.max_brightness = 15;
- bd->props.brightness = read_brightness(NULL);
- bd->props.power = FB_BLANK_UNBLANK;
- backlight_update_status(bd);
- }
+ asus_device_present = true;
return 0;
-}
-static int asus_led_register(acpi_handle handle,
- struct led_classdev *ldev, struct device *dev)
-{
- if (!handle)
- return 0;
+fail_rfkill:
+ asus_led_exit(asus);
+fail_led:
+ asus_input_exit(asus);
+fail_input:
+ asus_backlight_exit(asus);
+fail_backlight:
+ asus_platform_exit(asus);
+fail_platform:
+ kfree(asus->name);
+ kfree(asus);
- return led_classdev_register(dev, ldev);
+ return result;
}
-#define ASUS_LED_REGISTER(object, device) \
- asus_led_register(object##_set_handle, &object##_led, device)
-
-static int asus_led_init(struct device *dev)
+static int asus_acpi_remove(struct acpi_device *device, int type)
{
- int rv;
-
- rv = ASUS_LED_REGISTER(mled, dev);
- if (rv)
- goto out;
-
- rv = ASUS_LED_REGISTER(tled, dev);
- if (rv)
- goto out1;
-
- rv = ASUS_LED_REGISTER(rled, dev);
- if (rv)
- goto out2;
-
- rv = ASUS_LED_REGISTER(pled, dev);
- if (rv)
- goto out3;
-
- rv = ASUS_LED_REGISTER(gled, dev);
- if (rv)
- goto out4;
+ struct asus_laptop *asus = acpi_driver_data(device);
- if (kled_set_handle && kled_get_handle)
- rv = ASUS_LED_REGISTER(kled, dev);
- if (rv)
- goto out5;
-
- led_workqueue = create_singlethread_workqueue("led_workqueue");
- if (!led_workqueue)
- goto out6;
+ asus_backlight_exit(asus);
+ asus_rfkill_exit(asus);
+ asus_led_exit(asus);
+ asus_input_exit(asus);
+ asus_platform_exit(asus);
+ kfree(asus->name);
+ kfree(asus);
return 0;
-out6:
- rv = -ENOMEM;
- ASUS_LED_UNREGISTER(kled);
-out5:
- ASUS_LED_UNREGISTER(gled);
-out4:
- ASUS_LED_UNREGISTER(pled);
-out3:
- ASUS_LED_UNREGISTER(rled);
-out2:
- ASUS_LED_UNREGISTER(tled);
-out1:
- ASUS_LED_UNREGISTER(mled);
-out:
- return rv;
}
+static const struct acpi_device_id asus_device_ids[] = {
+ {"ATK0100", 0},
+ {"ATK0101", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, asus_device_ids);
+
+static struct acpi_driver asus_acpi_driver = {
+ .name = ASUS_LAPTOP_NAME,
+ .class = ASUS_LAPTOP_CLASS,
+ .owner = THIS_MODULE,
+ .ids = asus_device_ids,
+ .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
+ .ops = {
+ .add = asus_acpi_add,
+ .remove = asus_acpi_remove,
+ .notify = asus_acpi_notify,
+ },
+};
+
static int __init asus_laptop_init(void)
{
int result;
- result = acpi_bus_register_driver(&asus_hotk_driver);
+ result = platform_driver_register(&platform_driver);
if (result < 0)
return result;
- /*
- * This is a bit of a kludge. We only want this module loaded
- * for ASUS systems, but there's currently no way to probe the
- * ACPI namespace for ASUS HIDs. So we just return failure if
- * we didn't find one, which will cause the module to be
- * unloaded.
- */
- if (!asus_hotk_found) {
- acpi_bus_unregister_driver(&asus_hotk_driver);
- return -ENODEV;
- }
-
- result = asus_input_init();
- if (result)
- goto fail_input;
-
- /* Register platform stuff */
- result = platform_driver_register(&asuspf_driver);
- if (result)
- goto fail_platform_driver;
-
- asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1);
- if (!asuspf_device) {
- result = -ENOMEM;
- goto fail_platform_device1;
+ result = acpi_bus_register_driver(&asus_acpi_driver);
+ if (result < 0)
+ goto fail_acpi_driver;
+ if (!asus_device_present) {
+ result = -ENODEV;
+ goto fail_no_device;
}
-
- result = platform_device_add(asuspf_device);
- if (result)
- goto fail_platform_device2;
-
- result = sysfs_create_group(&asuspf_device->dev.kobj,
- &asuspf_attribute_group);
- if (result)
- goto fail_sysfs;
-
- result = asus_led_init(&asuspf_device->dev);
- if (result)
- goto fail_led;
-
- if (!acpi_video_backlight_support()) {
- result = asus_backlight_init(&asuspf_device->dev);
- if (result)
- goto fail_backlight;
- } else
- pr_info("Brightness ignored, must be controlled by "
- "ACPI video driver\n");
-
return 0;
-fail_backlight:
- asus_led_exit();
-
-fail_led:
- sysfs_remove_group(&asuspf_device->dev.kobj,
- &asuspf_attribute_group);
-
-fail_sysfs:
- platform_device_del(asuspf_device);
-
-fail_platform_device2:
- platform_device_put(asuspf_device);
-
-fail_platform_device1:
- platform_driver_unregister(&asuspf_driver);
-
-fail_platform_driver:
- asus_input_exit();
-
-fail_input:
-
+fail_no_device:
+ acpi_bus_unregister_driver(&asus_acpi_driver);
+fail_acpi_driver:
+ platform_driver_unregister(&platform_driver);
return result;
}
+static void __exit asus_laptop_exit(void)
+{
+ acpi_bus_unregister_driver(&asus_acpi_driver);
+ platform_driver_unregister(&platform_driver);
+}
+
module_init(asus_laptop_init);
module_exit(asus_laptop_exit);
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
index c1d2aeeea948..1381430e1105 100644
--- a/drivers/platform/x86/asus_acpi.c
+++ b/drivers/platform/x86/asus_acpi.c
@@ -1225,9 +1225,8 @@ static int asus_model_match(char *model)
else if (strncmp(model, "M2N", 3) == 0 ||
strncmp(model, "M3N", 3) == 0 ||
strncmp(model, "M5N", 3) == 0 ||
- strncmp(model, "M6N", 3) == 0 ||
strncmp(model, "S1N", 3) == 0 ||
- strncmp(model, "S5N", 3) == 0 || strncmp(model, "W1N", 3) == 0)
+ strncmp(model, "S5N", 3) == 0)
return xxN;
else if (strncmp(model, "M1", 2) == 0)
return M1A;
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
index ed90082cdf1d..035a7dd65a3f 100644
--- a/drivers/platform/x86/classmate-laptop.c
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -34,6 +34,11 @@ struct cmpc_accel {
#define CMPC_ACCEL_SENSITIVITY_DEFAULT 5
+#define CMPC_ACCEL_HID "ACCE0000"
+#define CMPC_TABLET_HID "TBLT0000"
+#define CMPC_BL_HID "IPML200"
+#define CMPC_KEYS_HID "FnBT0000"
+
/*
* Generic input device code.
*/
@@ -282,10 +287,9 @@ static int cmpc_accel_remove(struct acpi_device *acpi, int type)
}
static const struct acpi_device_id cmpc_accel_device_ids[] = {
- {"ACCE0000", 0},
+ {CMPC_ACCEL_HID, 0},
{"", 0}
};
-MODULE_DEVICE_TABLE(acpi, cmpc_accel_device_ids);
static struct acpi_driver cmpc_accel_acpi_driver = {
.owner = THIS_MODULE,
@@ -366,10 +370,9 @@ static int cmpc_tablet_resume(struct acpi_device *acpi)
}
static const struct acpi_device_id cmpc_tablet_device_ids[] = {
- {"TBLT0000", 0},
+ {CMPC_TABLET_HID, 0},
{"", 0}
};
-MODULE_DEVICE_TABLE(acpi, cmpc_tablet_device_ids);
static struct acpi_driver cmpc_tablet_acpi_driver = {
.owner = THIS_MODULE,
@@ -477,17 +480,16 @@ static int cmpc_bl_remove(struct acpi_device *acpi, int type)
return 0;
}
-static const struct acpi_device_id cmpc_device_ids[] = {
- {"IPML200", 0},
+static const struct acpi_device_id cmpc_bl_device_ids[] = {
+ {CMPC_BL_HID, 0},
{"", 0}
};
-MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);
static struct acpi_driver cmpc_bl_acpi_driver = {
.owner = THIS_MODULE,
.name = "cmpc",
.class = "cmpc",
- .ids = cmpc_device_ids,
+ .ids = cmpc_bl_device_ids,
.ops = {
.add = cmpc_bl_add,
.remove = cmpc_bl_remove
@@ -505,6 +507,10 @@ static int cmpc_keys_codes[] = {
KEY_BRIGHTNESSDOWN,
KEY_BRIGHTNESSUP,
KEY_VENDOR,
+ KEY_UNKNOWN,
+ KEY_CAMERA,
+ KEY_BACK,
+ KEY_FORWARD,
KEY_MAX
};
@@ -540,10 +546,9 @@ static int cmpc_keys_remove(struct acpi_device *acpi, int type)
}
static const struct acpi_device_id cmpc_keys_device_ids[] = {
- {"FnBT0000", 0},
+ {CMPC_KEYS_HID, 0},
{"", 0}
};
-MODULE_DEVICE_TABLE(acpi, cmpc_keys_device_ids);
static struct acpi_driver cmpc_keys_acpi_driver = {
.owner = THIS_MODULE,
@@ -607,3 +612,13 @@ static void cmpc_exit(void)
module_init(cmpc_init);
module_exit(cmpc_exit);
+
+static const struct acpi_device_id cmpc_device_ids[] = {
+ {CMPC_ACCEL_HID, 0},
+ {CMPC_TABLET_HID, 0},
+ {CMPC_BL_HID, 0},
+ {CMPC_KEYS_HID, 0},
+ {"", 0}
+};
+
+MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index 1a387e79f719..2740b40aad9b 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -26,17 +26,8 @@
/*
* comapl-laptop.c - Compal laptop support.
*
- * This driver exports a few files in /sys/devices/platform/compal-laptop/:
- *
- * wlan - wlan subsystem state: contains 0 or 1 (rw)
- *
- * bluetooth - Bluetooth subsystem state: contains 0 or 1 (rw)
- *
- * raw - raw value taken from embedded controller register (ro)
- *
- * In addition to these platform device attributes the driver
- * registers itself in the Linux backlight control subsystem and is
- * available to userspace under /sys/class/backlight/compal-laptop/.
+ * The driver registers itself with the rfkill subsystem and
+ * the Linux backlight control subsystem.
*
* This driver might work on other laptops produced by Compal. If you
* want to try it you can pass force=1 as argument to the module which
@@ -51,6 +42,7 @@
#include <linux/dmi.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
+#include <linux/rfkill.h>
#define COMPAL_DRIVER_VERSION "0.2.6"
@@ -63,6 +55,10 @@
#define WLAN_MASK 0x01
#define BT_MASK 0x02
+static struct rfkill *wifi_rfkill;
+static struct rfkill *bt_rfkill;
+static struct platform_device *compal_device;
+
static int force;
module_param(force, bool, 0);
MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
@@ -88,65 +84,75 @@ static int get_lcd_level(void)
return (int) result;
}
-static int set_wlan_state(int state)
+static int compal_rfkill_set(void *data, bool blocked)
{
+ unsigned long radio = (unsigned long) data;
u8 result, value;
ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
- if ((result & KILLSWITCH_MASK) == 0)
- return -EINVAL;
- else {
- if (state)
- value = (u8) (result | WLAN_MASK);
- else
- value = (u8) (result & ~WLAN_MASK);
- ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
- }
+ if (!blocked)
+ value = (u8) (result | radio);
+ else
+ value = (u8) (result & ~radio);
+ ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
return 0;
}
-static int set_bluetooth_state(int state)
+static void compal_rfkill_poll(struct rfkill *rfkill, void *data)
{
- u8 result, value;
+ u8 result;
+ bool hw_blocked;
ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
- if ((result & KILLSWITCH_MASK) == 0)
- return -EINVAL;
- else {
- if (state)
- value = (u8) (result | BT_MASK);
- else
- value = (u8) (result & ~BT_MASK);
- ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
- }
-
- return 0;
+ hw_blocked = !(result & KILLSWITCH_MASK);
+ rfkill_set_hw_state(rfkill, hw_blocked);
}
-static int get_wireless_state(int *wlan, int *bluetooth)
+static const struct rfkill_ops compal_rfkill_ops = {
+ .poll = compal_rfkill_poll,
+ .set_block = compal_rfkill_set,
+};
+
+static int setup_rfkill(void)
{
- u8 result;
+ int ret;
- ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
+ wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
+ RFKILL_TYPE_WLAN, &compal_rfkill_ops,
+ (void *) WLAN_MASK);
+ if (!wifi_rfkill)
+ return -ENOMEM;
- if (wlan) {
- if ((result & KILLSWITCH_MASK) == 0)
- *wlan = 0;
- else
- *wlan = result & WLAN_MASK;
- }
+ ret = rfkill_register(wifi_rfkill);
+ if (ret)
+ goto err_wifi;
- if (bluetooth) {
- if ((result & KILLSWITCH_MASK) == 0)
- *bluetooth = 0;
- else
- *bluetooth = (result & BT_MASK) >> 1;
+ bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
+ RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
+ (void *) BT_MASK);
+ if (!bt_rfkill) {
+ ret = -ENOMEM;
+ goto err_allocate_bt;
}
+ ret = rfkill_register(bt_rfkill);
+ if (ret)
+ goto err_register_bt;
return 0;
+
+err_register_bt:
+ rfkill_destroy(bt_rfkill);
+
+err_allocate_bt:
+ rfkill_unregister(wifi_rfkill);
+
+err_wifi:
+ rfkill_destroy(wifi_rfkill);
+
+ return ret;
}
/* Backlight device stuff */
@@ -169,86 +175,6 @@ static struct backlight_ops compalbl_ops = {
static struct backlight_device *compalbl_device;
-/* Platform device */
-
-static ssize_t show_wlan(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int ret, enabled;
-
- ret = get_wireless_state(&enabled, NULL);
- if (ret < 0)
- return ret;
-
- return sprintf(buf, "%i\n", enabled);
-}
-
-static ssize_t show_raw(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- u8 result;
-
- ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
-
- return sprintf(buf, "%i\n", result);
-}
-
-static ssize_t show_bluetooth(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int ret, enabled;
-
- ret = get_wireless_state(NULL, &enabled);
- if (ret < 0)
- return ret;
-
- return sprintf(buf, "%i\n", enabled);
-}
-
-static ssize_t store_wlan_state(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int state, ret;
-
- if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
- return -EINVAL;
-
- ret = set_wlan_state(state);
- if (ret < 0)
- return ret;
-
- return count;
-}
-
-static ssize_t store_bluetooth_state(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int state, ret;
-
- if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
- return -EINVAL;
-
- ret = set_bluetooth_state(state);
- if (ret < 0)
- return ret;
-
- return count;
-}
-
-static DEVICE_ATTR(bluetooth, 0644, show_bluetooth, store_bluetooth_state);
-static DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan_state);
-static DEVICE_ATTR(raw, 0444, show_raw, NULL);
-
-static struct attribute *compal_attributes[] = {
- &dev_attr_bluetooth.attr,
- &dev_attr_wlan.attr,
- &dev_attr_raw.attr,
- NULL
-};
-
-static struct attribute_group compal_attribute_group = {
- .attrs = compal_attributes
-};
static struct platform_driver compal_driver = {
.driver = {
@@ -257,8 +183,6 @@ static struct platform_driver compal_driver = {
}
};
-static struct platform_device *compal_device;
-
/* Initialization */
static int dmi_check_cb(const struct dmi_system_id *id)
@@ -310,6 +234,47 @@ static struct dmi_system_id __initdata compal_dmi_table[] = {
},
.callback = dmi_check_cb
},
+ {
+ .ident = "Dell Mini 9",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
+ },
+ .callback = dmi_check_cb
+ },
+ {
+ .ident = "Dell Mini 10",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
+ },
+ .callback = dmi_check_cb
+ },
+ {
+ .ident = "Dell Mini 10v",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
+ },
+ .callback = dmi_check_cb
+ },
+ {
+ .ident = "Dell Inspiron 11z",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
+ },
+ .callback = dmi_check_cb
+ },
+ {
+ .ident = "Dell Mini 12",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
+ },
+ .callback = dmi_check_cb
+ },
+
{ }
};
@@ -348,23 +313,21 @@ static int __init compal_init(void)
ret = platform_device_add(compal_device);
if (ret)
- goto fail_platform_device1;
+ goto fail_platform_device;
- ret = sysfs_create_group(&compal_device->dev.kobj,
- &compal_attribute_group);
+ ret = setup_rfkill();
if (ret)
- goto fail_platform_device2;
+ goto fail_rfkill;
printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION
" successfully loaded.\n");
return 0;
-fail_platform_device2:
-
+fail_rfkill:
platform_device_del(compal_device);
-fail_platform_device1:
+fail_platform_device:
platform_device_put(compal_device);
@@ -382,10 +345,13 @@ fail_backlight:
static void __exit compal_cleanup(void)
{
- sysfs_remove_group(&compal_device->dev.kobj, &compal_attribute_group);
platform_device_unregister(compal_device);
platform_driver_unregister(&compal_driver);
backlight_device_unregister(compalbl_device);
+ rfkill_unregister(wifi_rfkill);
+ rfkill_destroy(wifi_rfkill);
+ rfkill_unregister(bt_rfkill);
+ rfkill_destroy(bt_rfkill);
printk(KERN_INFO "compal-laptop: driver unloaded.\n");
}
@@ -403,3 +369,8 @@ MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
+MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*");
+MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*");
+MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
+MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*");
+MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*");
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 3780994dc8f2..ef614979afe9 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -22,6 +22,8 @@
#include <linux/rfkill.h>
#include <linux/power_supply.h>
#include <linux/acpi.h>
+#include <linux/mm.h>
+#include <linux/i8042.h>
#include "../../firmware/dcdbas.h"
#define BRIGHTNESS_TOKEN 0x7d
@@ -79,9 +81,73 @@ static const struct dmi_system_id __initdata dell_device_table[] = {
DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
},
},
+ {
+ .ident = "Dell Computer Corporation",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
+ },
+ },
{ }
};
+static struct dmi_system_id __devinitdata dell_blacklist[] = {
+ /* Supported by compal-laptop */
+ {
+ .ident = "Dell Mini 9",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
+ },
+ },
+ {
+ .ident = "Dell Mini 10",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
+ },
+ },
+ {
+ .ident = "Dell Mini 10v",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
+ },
+ },
+ {
+ .ident = "Dell Inspiron 11z",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
+ },
+ },
+ {
+ .ident = "Dell Mini 12",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
+ },
+ },
+ {}
+};
+
+static struct calling_interface_buffer *buffer;
+static struct page *bufferpage;
+static DEFINE_MUTEX(buffer_mutex);
+
+static int hwswitch_state;
+
+static void get_buffer(void)
+{
+ mutex_lock(&buffer_mutex);
+ memset(buffer, 0, sizeof(struct calling_interface_buffer));
+}
+
+static void release_buffer(void)
+{
+ mutex_unlock(&buffer_mutex);
+}
+
static void __init parse_da_table(const struct dmi_header *dm)
{
/* Final token is a terminator, so we don't want to copy it */
@@ -160,6 +226,8 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
/* Derived from information in DellWirelessCtl.cpp:
Class 17, select 11 is radio control. It returns an array of 32-bit values.
+ Input byte 0 = 0: Wireless information
+
result[0]: return code
result[1]:
Bit 0: Hardware switch supported
@@ -180,33 +248,62 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
Bits 20-31: Reserved
result[2]: NVRAM size in bytes
result[3]: NVRAM format version number
+
+ Input byte 0 = 2: Wireless switch configuration
+ result[0]: return code
+ result[1]:
+ Bit 0: Wifi controlled by switch
+ Bit 1: Bluetooth controlled by switch
+ Bit 2: WWAN controlled by switch
+ Bits 3-6: Reserved
+ Bit 7: Wireless switch config locked
+ Bit 8: Wifi locator enabled
+ Bits 9-14: Reserved
+ Bit 15: Wifi locator setting locked
+ Bits 16-31: Reserved
*/
static int dell_rfkill_set(void *data, bool blocked)
{
- struct calling_interface_buffer buffer;
int disable = blocked ? 1 : 0;
unsigned long radio = (unsigned long)data;
+ int hwswitch_bit = (unsigned long)data - 1;
+ int ret = 0;
+
+ get_buffer();
+ dell_send_request(buffer, 17, 11);
+
+ /* If the hardware switch controls this radio, and the hardware
+ switch is disabled, don't allow changing the software state */
+ if ((hwswitch_state & BIT(hwswitch_bit)) &&
+ !(buffer->output[1] & BIT(16))) {
+ ret = -EINVAL;
+ goto out;
+ }
- memset(&buffer, 0, sizeof(struct calling_interface_buffer));
- buffer.input[0] = (1 | (radio<<8) | (disable << 16));
- dell_send_request(&buffer, 17, 11);
+ buffer->input[0] = (1 | (radio<<8) | (disable << 16));
+ dell_send_request(buffer, 17, 11);
- return 0;
+out:
+ release_buffer();
+ return ret;
}
static void dell_rfkill_query(struct rfkill *rfkill, void *data)
{
- struct calling_interface_buffer buffer;
int status;
int bit = (unsigned long)data + 16;
+ int hwswitch_bit = (unsigned long)data - 1;
- memset(&buffer, 0, sizeof(struct calling_interface_buffer));
- dell_send_request(&buffer, 17, 11);
- status = buffer.output[1];
+ get_buffer();
+ dell_send_request(buffer, 17, 11);
+ status = buffer->output[1];
+ release_buffer();
rfkill_set_sw_state(rfkill, !!(status & BIT(bit)));
- rfkill_set_hw_state(rfkill, !(status & BIT(16)));
+
+ if (hwswitch_state & (BIT(hwswitch_bit)))
+ rfkill_set_hw_state(rfkill, !(status & BIT(16)));
}
static const struct rfkill_ops dell_rfkill_ops = {
@@ -214,15 +311,36 @@ static const struct rfkill_ops dell_rfkill_ops = {
.query = dell_rfkill_query,
};
+static void dell_update_rfkill(struct work_struct *ignored)
+{
+ if (wifi_rfkill)
+ dell_rfkill_query(wifi_rfkill, (void *)1);
+ if (bluetooth_rfkill)
+ dell_rfkill_query(bluetooth_rfkill, (void *)2);
+ if (wwan_rfkill)
+ dell_rfkill_query(wwan_rfkill, (void *)3);
+}
+static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
+
+
static int __init dell_setup_rfkill(void)
{
- struct calling_interface_buffer buffer;
int status;
int ret;
- memset(&buffer, 0, sizeof(struct calling_interface_buffer));
- dell_send_request(&buffer, 17, 11);
- status = buffer.output[1];
+ if (dmi_check_system(dell_blacklist)) {
+ printk(KERN_INFO "dell-laptop: Blacklisted hardware detected - "
+ "not enabling rfkill\n");
+ return 0;
+ }
+
+ get_buffer();
+ dell_send_request(buffer, 17, 11);
+ status = buffer->output[1];
+ buffer->input[0] = 0x2;
+ dell_send_request(buffer, 17, 11);
+ hwswitch_state = buffer->output[1];
+ release_buffer();
if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev,
@@ -298,39 +416,49 @@ static void dell_cleanup_rfkill(void)
static int dell_send_intensity(struct backlight_device *bd)
{
- struct calling_interface_buffer buffer;
+ int ret = 0;
- memset(&buffer, 0, sizeof(struct calling_interface_buffer));
- buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN);
- buffer.input[1] = bd->props.brightness;
+ get_buffer();
+ buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
+ buffer->input[1] = bd->props.brightness;
- if (buffer.input[0] == -1)
- return -ENODEV;
+ if (buffer->input[0] == -1) {
+ ret = -ENODEV;
+ goto out;
+ }
if (power_supply_is_system_supplied() > 0)
- dell_send_request(&buffer, 1, 2);
+ dell_send_request(buffer, 1, 2);
else
- dell_send_request(&buffer, 1, 1);
+ dell_send_request(buffer, 1, 1);
+out:
+ release_buffer();
return 0;
}
static int dell_get_intensity(struct backlight_device *bd)
{
- struct calling_interface_buffer buffer;
+ int ret = 0;
- memset(&buffer, 0, sizeof(struct calling_interface_buffer));
- buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN);
+ get_buffer();
+ buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
- if (buffer.input[0] == -1)
- return -ENODEV;
+ if (buffer->input[0] == -1) {
+ ret = -ENODEV;
+ goto out;
+ }
if (power_supply_is_system_supplied() > 0)
- dell_send_request(&buffer, 0, 2);
+ dell_send_request(buffer, 0, 2);
else
- dell_send_request(&buffer, 0, 1);
+ dell_send_request(buffer, 0, 1);
- return buffer.output[1];
+out:
+ release_buffer();
+ if (ret)
+ return ret;
+ return buffer->output[1];
}
static struct backlight_ops dell_ops = {
@@ -338,9 +466,32 @@ static struct backlight_ops dell_ops = {
.update_status = dell_send_intensity,
};
+bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
+ struct serio *port)
+{
+ static bool extended;
+
+ if (str & 0x20)
+ return false;
+
+ if (unlikely(data == 0xe0)) {
+ extended = true;
+ return false;
+ } else if (unlikely(extended)) {
+ switch (data) {
+ case 0x8:
+ schedule_delayed_work(&dell_rfkill_work,
+ round_jiffies_relative(HZ));
+ break;
+ }
+ extended = false;
+ }
+
+ return false;
+}
+
static int __init dell_init(void)
{
- struct calling_interface_buffer buffer;
int max_intensity = 0;
int ret;
@@ -366,6 +517,17 @@ static int __init dell_init(void)
if (ret)
goto fail_platform_device2;
+ /*
+ * Allocate buffer below 4GB for SMI data--only 32-bit physical addr
+ * is passed to SMI handler.
+ */
+ bufferpage = alloc_page(GFP_KERNEL | GFP_DMA32);
+
+ if (!bufferpage)
+ goto fail_buffer;
+ buffer = page_address(bufferpage);
+ mutex_init(&buffer_mutex);
+
ret = dell_setup_rfkill();
if (ret) {
@@ -373,6 +535,13 @@ static int __init dell_init(void)
goto fail_rfkill;
}
+ ret = i8042_install_filter(dell_laptop_i8042_filter);
+ if (ret) {
+ printk(KERN_WARNING
+ "dell-laptop: Unable to install key filter\n");
+ goto fail_filter;
+ }
+
#ifdef CONFIG_ACPI
/* In the event of an ACPI backlight being available, don't
* register the platform controller.
@@ -381,13 +550,13 @@ static int __init dell_init(void)
return 0;
#endif
- memset(&buffer, 0, sizeof(struct calling_interface_buffer));
- buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN);
-
- if (buffer.input[0] != -1) {
- dell_send_request(&buffer, 0, 2);
- max_intensity = buffer.output[3];
+ get_buffer();
+ buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
+ if (buffer->input[0] != -1) {
+ dell_send_request(buffer, 0, 2);
+ max_intensity = buffer->output[3];
}
+ release_buffer();
if (max_intensity) {
dell_backlight_device = backlight_device_register(
@@ -410,8 +579,13 @@ static int __init dell_init(void)
return 0;
fail_backlight:
+ i8042_remove_filter(dell_laptop_i8042_filter);
+ cancel_delayed_work_sync(&dell_rfkill_work);
+fail_filter:
dell_cleanup_rfkill();
fail_rfkill:
+ free_page((unsigned long)bufferpage);
+fail_buffer:
platform_device_del(platform_device);
fail_platform_device2:
platform_device_put(platform_device);
@@ -424,8 +598,16 @@ fail_platform_driver:
static void __exit dell_exit(void)
{
+ i8042_remove_filter(dell_laptop_i8042_filter);
+ cancel_delayed_work_sync(&dell_rfkill_work);
backlight_device_unregister(dell_backlight_device);
dell_cleanup_rfkill();
+ if (platform_device) {
+ platform_device_unregister(platform_device);
+ platform_driver_unregister(&platform_driver);
+ }
+ kfree(da_tokens);
+ free_page((unsigned long)buffer);
}
module_init(dell_init);
@@ -435,3 +617,4 @@ MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
MODULE_DESCRIPTION("Dell laptop driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*");
+MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*");
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 1b1dddbd5744..bed764e3ea2a 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -142,7 +142,7 @@ static struct key_entry *dell_wmi_keymap = dell_legacy_wmi_keymap;
static struct input_dev *dell_wmi_input_dev;
-static struct key_entry *dell_wmi_get_entry_by_scancode(int code)
+static struct key_entry *dell_wmi_get_entry_by_scancode(unsigned int code)
{
struct key_entry *key;
@@ -153,7 +153,7 @@ static struct key_entry *dell_wmi_get_entry_by_scancode(int code)
return NULL;
}
-static struct key_entry *dell_wmi_get_entry_by_keycode(int keycode)
+static struct key_entry *dell_wmi_get_entry_by_keycode(unsigned int keycode)
{
struct key_entry *key;
@@ -164,8 +164,8 @@ static struct key_entry *dell_wmi_get_entry_by_keycode(int keycode)
return NULL;
}
-static int dell_wmi_getkeycode(struct input_dev *dev, int scancode,
- int *keycode)
+static int dell_wmi_getkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int *keycode)
{
struct key_entry *key = dell_wmi_get_entry_by_scancode(scancode);
@@ -177,13 +177,11 @@ static int dell_wmi_getkeycode(struct input_dev *dev, int scancode,
return -EINVAL;
}
-static int dell_wmi_setkeycode(struct input_dev *dev, int scancode, int keycode)
+static int dell_wmi_setkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int keycode)
{
struct key_entry *key;
- int old_keycode;
-
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
+ unsigned int old_keycode;
key = dell_wmi_get_entry_by_scancode(scancode);
if (key && key->type == KE_KEY) {
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 5838c69b2fb3..9a844caa3756 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -31,10 +31,12 @@
#include <acpi/acpi_bus.h>
#include <linux/uaccess.h>
#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#include <linux/rfkill.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/leds.h>
+#include <linux/dmi.h>
#define EEEPC_LAPTOP_VERSION "0.1"
#define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver"
@@ -48,6 +50,14 @@ MODULE_AUTHOR("Corentin Chary, Eric Cooper");
MODULE_DESCRIPTION(EEEPC_LAPTOP_NAME);
MODULE_LICENSE("GPL");
+static bool hotplug_disabled;
+
+module_param(hotplug_disabled, bool, 0644);
+MODULE_PARM_DESC(hotplug_disabled,
+ "Disable hotplug for wireless device. "
+ "If your laptop need that, please report to "
+ "acpi4asus-user@lists.sourceforge.net.");
+
/*
* Definitions for Asus EeePC
*/
@@ -120,38 +130,28 @@ static const char *cm_setv[] = {
NULL, NULL, "PBPS", "TPDS"
};
-struct key_entry {
- char type;
- u8 code;
- u16 keycode;
-};
-
-enum { KE_KEY, KE_END };
-
static const struct key_entry eeepc_keymap[] = {
- /* Sleep already handled via generic ACPI code */
- {KE_KEY, 0x10, KEY_WLAN },
- {KE_KEY, 0x11, KEY_WLAN },
- {KE_KEY, 0x12, KEY_PROG1 },
- {KE_KEY, 0x13, KEY_MUTE },
- {KE_KEY, 0x14, KEY_VOLUMEDOWN },
- {KE_KEY, 0x15, KEY_VOLUMEUP },
- {KE_KEY, 0x16, KEY_DISPLAY_OFF },
- {KE_KEY, 0x1a, KEY_COFFEE },
- {KE_KEY, 0x1b, KEY_ZOOM },
- {KE_KEY, 0x1c, KEY_PROG2 },
- {KE_KEY, 0x1d, KEY_PROG3 },
- {KE_KEY, NOTIFY_BRN_MIN, KEY_BRIGHTNESSDOWN },
- {KE_KEY, NOTIFY_BRN_MAX, KEY_BRIGHTNESSUP },
- {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
- {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
- {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
- {KE_KEY, 0x37, KEY_F13 }, /* Disable Touchpad */
- {KE_KEY, 0x38, KEY_F14 },
- {KE_END, 0},
+ { KE_KEY, 0x10, { KEY_WLAN } },
+ { KE_KEY, 0x11, { KEY_WLAN } },
+ { KE_KEY, 0x12, { KEY_PROG1 } },
+ { KE_KEY, 0x13, { KEY_MUTE } },
+ { KE_KEY, 0x14, { KEY_VOLUMEDOWN } },
+ { KE_KEY, 0x15, { KEY_VOLUMEUP } },
+ { KE_KEY, 0x16, { KEY_DISPLAY_OFF } },
+ { KE_KEY, 0x1a, { KEY_COFFEE } },
+ { KE_KEY, 0x1b, { KEY_ZOOM } },
+ { KE_KEY, 0x1c, { KEY_PROG2 } },
+ { KE_KEY, 0x1d, { KEY_PROG3 } },
+ { KE_KEY, NOTIFY_BRN_MIN, { KEY_BRIGHTNESSDOWN } },
+ { KE_KEY, NOTIFY_BRN_MAX, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, 0x30, { KEY_SWITCHVIDEOMODE } },
+ { KE_KEY, 0x31, { KEY_SWITCHVIDEOMODE } },
+ { KE_KEY, 0x32, { KEY_SWITCHVIDEOMODE } },
+ { KE_KEY, 0x37, { KEY_F13 } }, /* Disable Touchpad */
+ { KE_KEY, 0x38, { KEY_F14 } },
+ { KE_END, 0 },
};
-
/*
* This is the main structure, we can use it to store useful information
*/
@@ -159,6 +159,8 @@ struct eeepc_laptop {
acpi_handle handle; /* the handle of the acpi device */
u32 cm_supported; /* the control methods supported
by this BIOS */
+ bool cpufv_disabled;
+ bool hotplug_disabled;
u16 event_count[128]; /* count for each event */
struct platform_device *platform_device;
@@ -378,6 +380,8 @@ static ssize_t store_cpufv(struct device *dev,
struct eeepc_cpufv c;
int rv, value;
+ if (eeepc->cpufv_disabled)
+ return -EPERM;
if (get_cpufv(eeepc, &c))
return -ENODEV;
rv = parse_arg(buf, count, &value);
@@ -389,6 +393,41 @@ static ssize_t store_cpufv(struct device *dev,
return rv;
}
+static ssize_t show_cpufv_disabled(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", eeepc->cpufv_disabled);
+}
+
+static ssize_t store_cpufv_disabled(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv < 0)
+ return rv;
+
+ switch (value) {
+ case 0:
+ if (eeepc->cpufv_disabled)
+ pr_warning("cpufv enabled (not officially supported "
+ "on this model)\n");
+ eeepc->cpufv_disabled = false;
+ return rv;
+ case 1:
+ return -EPERM;
+ default:
+ return -EINVAL;
+ }
+}
+
+
static struct device_attribute dev_attr_cpufv = {
.attr = {
.name = "cpufv",
@@ -404,12 +443,22 @@ static struct device_attribute dev_attr_available_cpufv = {
.show = show_available_cpufv
};
+static struct device_attribute dev_attr_cpufv_disabled = {
+ .attr = {
+ .name = "cpufv_disabled",
+ .mode = 0644 },
+ .show = show_cpufv_disabled,
+ .store = store_cpufv_disabled
+};
+
+
static struct attribute *platform_attributes[] = {
&dev_attr_camera.attr,
&dev_attr_cardr.attr,
&dev_attr_disp.attr,
&dev_attr_cpufv.attr,
&dev_attr_available_cpufv.attr,
+ &dev_attr_cpufv_disabled.attr,
NULL
};
@@ -529,6 +578,8 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc)
struct pci_dev *dev;
struct pci_bus *bus;
bool blocked = eeepc_wlan_rfkill_blocked(eeepc);
+ bool absent;
+ u32 l;
if (eeepc->wlan_rfkill)
rfkill_set_sw_state(eeepc->wlan_rfkill, blocked);
@@ -542,6 +593,22 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc)
goto out_unlock;
}
+ if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) {
+ pr_err("Unable to read PCI config space?\n");
+ goto out_unlock;
+ }
+ absent = (l == 0xffffffff);
+
+ if (blocked != absent) {
+ pr_warning("BIOS says wireless lan is %s, "
+ "but the pci device is %s\n",
+ blocked ? "blocked" : "unblocked",
+ absent ? "absent" : "present");
+ pr_warning("skipped wireless hotplug as probably "
+ "inappropriate for this model\n");
+ goto out_unlock;
+ }
+
if (!blocked) {
dev = pci_get_slot(bus, 0);
if (dev) {
@@ -796,6 +863,9 @@ static int eeepc_rfkill_init(struct eeepc_laptop *eeepc)
if (result && result != -ENODEV)
goto exit;
+ if (eeepc->hotplug_disabled)
+ return 0;
+
result = eeepc_setup_pci_hotplug(eeepc);
/*
* If we get -EBUSY then something else is handling the PCI hotplug -
@@ -1090,120 +1160,42 @@ static void eeepc_backlight_exit(struct eeepc_laptop *eeepc)
/*
* Input device (i.e. hotkeys)
*/
-static struct key_entry *eeepc_get_entry_by_scancode(
- struct eeepc_laptop *eeepc,
- int code)
+static int eeepc_input_init(struct eeepc_laptop *eeepc)
{
- struct key_entry *key;
-
- for (key = eeepc->keymap; key->type != KE_END; key++)
- if (code == key->code)
- return key;
-
- return NULL;
-}
+ struct input_dev *input;
+ int error;
-static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
-{
- static struct key_entry *key;
-
- key = eeepc_get_entry_by_scancode(eeepc, event);
- if (key) {
- switch (key->type) {
- case KE_KEY:
- input_report_key(eeepc->inputdev, key->keycode,
- 1);
- input_sync(eeepc->inputdev);
- input_report_key(eeepc->inputdev, key->keycode,
- 0);
- input_sync(eeepc->inputdev);
- break;
- }
+ input = input_allocate_device();
+ if (!input) {
+ pr_info("Unable to allocate input device\n");
+ return -ENOMEM;
}
-}
-
-static struct key_entry *eeepc_get_entry_by_keycode(
- struct eeepc_laptop *eeepc, int code)
-{
- struct key_entry *key;
-
- for (key = eeepc->keymap; key->type != KE_END; key++)
- if (code == key->keycode && key->type == KE_KEY)
- return key;
- return NULL;
-}
+ input->name = "Asus EeePC extra buttons";
+ input->phys = EEEPC_LAPTOP_FILE "/input0";
+ input->id.bustype = BUS_HOST;
+ input->dev.parent = &eeepc->platform_device->dev;
-static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
-{
- struct eeepc_laptop *eeepc = input_get_drvdata(dev);
- struct key_entry *key = eeepc_get_entry_by_scancode(eeepc, scancode);
-
- if (key && key->type == KE_KEY) {
- *keycode = key->keycode;
- return 0;
+ error = sparse_keymap_setup(input, eeepc_keymap, NULL);
+ if (error) {
+ pr_err("Unable to setup input device keymap\n");
+ goto err_free_dev;
}
- return -EINVAL;
-}
-
-static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
-{
- struct eeepc_laptop *eeepc = input_get_drvdata(dev);
- struct key_entry *key;
- int old_keycode;
-
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
-
- key = eeepc_get_entry_by_scancode(eeepc, scancode);
- if (key && key->type == KE_KEY) {
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!eeepc_get_entry_by_keycode(eeepc, old_keycode))
- clear_bit(old_keycode, dev->keybit);
- return 0;
+ error = input_register_device(input);
+ if (error) {
+ pr_err("Unable to register input device\n");
+ goto err_free_keymap;
}
- return -EINVAL;
-}
-
-static int eeepc_input_init(struct eeepc_laptop *eeepc)
-{
- const struct key_entry *key;
- int result;
-
- eeepc->inputdev = input_allocate_device();
- if (!eeepc->inputdev) {
- pr_info("Unable to allocate input device\n");
- return -ENOMEM;
- }
- eeepc->inputdev->name = "Asus EeePC extra buttons";
- eeepc->inputdev->dev.parent = &eeepc->platform_device->dev;
- eeepc->inputdev->phys = EEEPC_LAPTOP_FILE "/input0";
- eeepc->inputdev->id.bustype = BUS_HOST;
- eeepc->inputdev->getkeycode = eeepc_getkeycode;
- eeepc->inputdev->setkeycode = eeepc_setkeycode;
- input_set_drvdata(eeepc->inputdev, eeepc);
-
- eeepc->keymap = kmemdup(eeepc_keymap, sizeof(eeepc_keymap),
- GFP_KERNEL);
- for (key = eeepc_keymap; key->type != KE_END; key++) {
- switch (key->type) {
- case KE_KEY:
- set_bit(EV_KEY, eeepc->inputdev->evbit);
- set_bit(key->keycode, eeepc->inputdev->keybit);
- break;
- }
- }
- result = input_register_device(eeepc->inputdev);
- if (result) {
- pr_info("Unable to register input device\n");
- input_free_device(eeepc->inputdev);
- return result;
- }
+ eeepc->inputdev = input;
return 0;
+
+ err_free_keymap:
+ sparse_keymap_free(input);
+ err_free_dev:
+ input_free_device(input);
+ return error;
}
static void eeepc_input_exit(struct eeepc_laptop *eeepc)
@@ -1253,11 +1245,60 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
* event will be desired value (or else ignored)
*/
}
- eeepc_input_notify(eeepc, event);
+ sparse_keymap_report_event(eeepc->inputdev, event,
+ 1, true);
}
} else {
/* Everything else is a bona-fide keypress event */
- eeepc_input_notify(eeepc, event);
+ sparse_keymap_report_event(eeepc->inputdev, event, 1, true);
+ }
+}
+
+static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
+{
+ const char *model;
+
+ model = dmi_get_system_info(DMI_PRODUCT_NAME);
+ if (!model)
+ return;
+
+ /*
+ * Blacklist for setting cpufv (cpu speed).
+ *
+ * EeePC 4G ("701") implements CFVS, but it is not supported
+ * by the pre-installed OS, and the original option to change it
+ * in the BIOS setup screen was removed in later versions.
+ *
+ * Judging by the lack of "Super Hybrid Engine" on Asus product pages,
+ * this applies to all "701" models (4G/4G Surf/2G Surf).
+ *
+ * So Asus made a deliberate decision not to support it on this model.
+ * We have several reports that using it can cause the system to hang
+ *
+ * The hang has also been reported on a "702" (Model name "8G"?).
+ *
+ * We avoid dmi_check_system() / dmi_match(), because they use
+ * substring matching. We don't want to affect the "701SD"
+ * and "701SDX" models, because they do support S.H.E.
+ */
+ if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) {
+ eeepc->cpufv_disabled = true;
+ pr_info("model %s does not officially support setting cpu "
+ "speed\n", model);
+ pr_info("cpufv disabled to avoid instability\n");
+ }
+
+ /*
+ * Blacklist for wlan hotplug
+ *
+ * Eeepc 1005HA doesn't work like others models and don't need the
+ * hotplug code. In fact, current hotplug code seems to unplug another
+ * device...
+ */
+ if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0 ||
+ strcmp(model, "1005PE") == 0) {
+ eeepc->hotplug_disabled = true;
+ pr_info("wlan hotplug disabled\n");
}
}
@@ -1342,6 +1383,10 @@ static int __devinit eeepc_acpi_add(struct acpi_device *device)
strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS);
device->driver_data = eeepc;
+ eeepc->hotplug_disabled = hotplug_disabled;
+
+ eeepc_dmi_check(eeepc);
+
result = eeepc_acpi_init(eeepc, device);
if (result)
goto fail_platform;
@@ -1452,10 +1497,12 @@ static int __init eeepc_laptop_init(void)
result = acpi_bus_register_driver(&eeepc_acpi_driver);
if (result < 0)
goto fail_acpi_driver;
+
if (!eeepc_device_present) {
result = -ENODEV;
goto fail_no_device;
}
+
return 0;
fail_no_device:
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index ad4c414dbfbc..56086363becc 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -57,7 +57,7 @@ enum hp_wmi_radio {
HPWMI_WWAN = 2,
};
-static int __init hp_wmi_bios_setup(struct platform_device *device);
+static int __devinit hp_wmi_bios_setup(struct platform_device *device);
static int __exit hp_wmi_bios_remove(struct platform_device *device);
static int hp_wmi_resume_handler(struct device *device);
@@ -89,6 +89,7 @@ static struct key_entry hp_wmi_keymap[] = {
{KE_KEY, 0x20e6, KEY_PROG1},
{KE_KEY, 0x2142, KEY_MEDIA},
{KE_KEY, 0x213b, KEY_INFO},
+ {KE_KEY, 0x2169, KEY_DIRECTION},
{KE_KEY, 0x231b, KEY_HELP},
{KE_END, 0}
};
@@ -277,7 +278,7 @@ static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
-static struct key_entry *hp_wmi_get_entry_by_scancode(int code)
+static struct key_entry *hp_wmi_get_entry_by_scancode(unsigned int code)
{
struct key_entry *key;
@@ -288,7 +289,7 @@ static struct key_entry *hp_wmi_get_entry_by_scancode(int code)
return NULL;
}
-static struct key_entry *hp_wmi_get_entry_by_keycode(int keycode)
+static struct key_entry *hp_wmi_get_entry_by_keycode(unsigned int keycode)
{
struct key_entry *key;
@@ -299,7 +300,8 @@ static struct key_entry *hp_wmi_get_entry_by_keycode(int keycode)
return NULL;
}
-static int hp_wmi_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+static int hp_wmi_getkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int *keycode)
{
struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
@@ -311,13 +313,11 @@ static int hp_wmi_getkeycode(struct input_dev *dev, int scancode, int *keycode)
return -EINVAL;
}
-static int hp_wmi_setkeycode(struct input_dev *dev, int scancode, int keycode)
+static int hp_wmi_setkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int keycode)
{
struct key_entry *key;
- int old_keycode;
-
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
+ unsigned int old_keycode;
key = hp_wmi_get_entry_by_scancode(scancode);
if (key && key->type == KE_KEY) {
@@ -446,7 +446,7 @@ static void cleanup_sysfs(struct platform_device *device)
device_remove_file(&device->dev, &dev_attr_tablet);
}
-static int __init hp_wmi_bios_setup(struct platform_device *device)
+static int __devinit hp_wmi_bios_setup(struct platform_device *device)
{
int err;
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 759763d18e4c..c2b05da4289a 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -58,6 +58,7 @@
#include <linux/dmi.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
+#include <linux/rfkill.h>
#define MSI_DRIVER_VERSION "0.5"
@@ -66,6 +67,20 @@
#define MSI_EC_COMMAND_WIRELESS 0x10
#define MSI_EC_COMMAND_LCD_LEVEL 0x11
+#define MSI_STANDARD_EC_COMMAND_ADDRESS 0x2e
+#define MSI_STANDARD_EC_BLUETOOTH_MASK (1 << 0)
+#define MSI_STANDARD_EC_WEBCAM_MASK (1 << 1)
+#define MSI_STANDARD_EC_WLAN_MASK (1 << 3)
+#define MSI_STANDARD_EC_3G_MASK (1 << 4)
+
+/* For set SCM load flag to disable BIOS fn key */
+#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d
+#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0)
+
+static int msi_laptop_resume(struct platform_device *device);
+
+#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
+
static int force;
module_param(force, bool, 0);
MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
@@ -74,6 +89,23 @@ static int auto_brightness;
module_param(auto_brightness, int, 0);
MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
+static bool old_ec_model;
+static int wlan_s, bluetooth_s, threeg_s;
+static int threeg_exists;
+
+/* Some MSI 3G netbook only have one fn key to control Wlan/Bluetooth/3G,
+ * those netbook will load the SCM (windows app) to disable the original
+ * Wlan/Bluetooth control by BIOS when user press fn key, then control
+ * Wlan/Bluetooth/3G by SCM (software control by OS). Without SCM, user
+ * cann't on/off 3G module on those 3G netbook.
+ * On Linux, msi-laptop driver will do the same thing to disable the
+ * original BIOS control, then might need use HAL or other userland
+ * application to do the software control that simulate with SCM.
+ * e.g. MSI N034 netbook
+ */
+static bool load_scm_model;
+static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg;
+
/* Hardware access */
static int set_lcd_level(int level)
@@ -130,6 +162,35 @@ static int set_auto_brightness(int enable)
return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1);
}
+static ssize_t set_device_state(const char *buf, size_t count, u8 mask)
+{
+ int status;
+ u8 wdata = 0, rdata;
+ int result;
+
+ if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1))
+ return -EINVAL;
+
+ /* read current device state */
+ result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
+ if (result < 0)
+ return -EINVAL;
+
+ if (!!(rdata & mask) != status) {
+ /* reverse device bit */
+ if (rdata & mask)
+ wdata = rdata & ~mask;
+ else
+ wdata = rdata | mask;
+
+ result = ec_write(MSI_STANDARD_EC_COMMAND_ADDRESS, wdata);
+ if (result < 0)
+ return -EINVAL;
+ }
+
+ return count;
+}
+
static int get_wireless_state(int *wlan, int *bluetooth)
{
u8 wdata = 0, rdata;
@@ -148,6 +209,38 @@ static int get_wireless_state(int *wlan, int *bluetooth)
return 0;
}
+static int get_wireless_state_ec_standard(void)
+{
+ u8 rdata;
+ int result;
+
+ result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
+ if (result < 0)
+ return -1;
+
+ wlan_s = !!(rdata & MSI_STANDARD_EC_WLAN_MASK);
+
+ bluetooth_s = !!(rdata & MSI_STANDARD_EC_BLUETOOTH_MASK);
+
+ threeg_s = !!(rdata & MSI_STANDARD_EC_3G_MASK);
+
+ return 0;
+}
+
+static int get_threeg_exists(void)
+{
+ u8 rdata;
+ int result;
+
+ result = ec_read(MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS, &rdata);
+ if (result < 0)
+ return -1;
+
+ threeg_exists = !!(rdata & MSI_STANDARD_EC_3G_MASK);
+
+ return 0;
+}
+
/* Backlight device stuff */
static int bl_get_brightness(struct backlight_device *b)
@@ -176,26 +269,71 @@ static ssize_t show_wlan(struct device *dev,
int ret, enabled;
- ret = get_wireless_state(&enabled, NULL);
+ if (old_ec_model) {
+ ret = get_wireless_state(&enabled, NULL);
+ } else {
+ ret = get_wireless_state_ec_standard();
+ enabled = wlan_s;
+ }
if (ret < 0)
return ret;
return sprintf(buf, "%i\n", enabled);
}
+static ssize_t store_wlan(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return set_device_state(buf, count, MSI_STANDARD_EC_WLAN_MASK);
+}
+
static ssize_t show_bluetooth(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret, enabled;
- ret = get_wireless_state(NULL, &enabled);
+ if (old_ec_model) {
+ ret = get_wireless_state(NULL, &enabled);
+ } else {
+ ret = get_wireless_state_ec_standard();
+ enabled = bluetooth_s;
+ }
if (ret < 0)
return ret;
return sprintf(buf, "%i\n", enabled);
}
+static ssize_t store_bluetooth(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return set_device_state(buf, count, MSI_STANDARD_EC_BLUETOOTH_MASK);
+}
+
+static ssize_t show_threeg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ int ret;
+
+ /* old msi ec not support 3G */
+ if (old_ec_model)
+ return -1;
+
+ ret = get_wireless_state_ec_standard();
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%i\n", threeg_s);
+}
+
+static ssize_t store_threeg(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return set_device_state(buf, count, MSI_STANDARD_EC_3G_MASK);
+}
+
static ssize_t show_lcd_level(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -258,6 +396,7 @@ static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness);
static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
+static DEVICE_ATTR(threeg, 0444, show_threeg, NULL);
static struct attribute *msipf_attributes[] = {
&dev_attr_lcd_level.attr,
@@ -275,7 +414,8 @@ static struct platform_driver msipf_driver = {
.driver = {
.name = "msi-laptop-pf",
.owner = THIS_MODULE,
- }
+ },
+ .resume = msi_laptop_resume,
};
static struct platform_device *msipf_device;
@@ -332,6 +472,192 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
{ }
};
+static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
+ {
+ .ident = "MSI N034",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "MICRO-STAR INTERNATIONAL CO., LTD"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MS-N034"),
+ DMI_MATCH(DMI_CHASSIS_VENDOR,
+ "MICRO-STAR INTERNATIONAL CO., LTD")
+ },
+ .callback = dmi_check_cb
+ },
+ { }
+};
+
+static int rfkill_bluetooth_set(void *data, bool blocked)
+{
+ /* Do something with blocked...*/
+ /*
+ * blocked == false is on
+ * blocked == true is off
+ */
+ if (blocked)
+ set_device_state("0", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
+ else
+ set_device_state("1", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
+
+ return 0;
+}
+
+static int rfkill_wlan_set(void *data, bool blocked)
+{
+ if (blocked)
+ set_device_state("0", 0, MSI_STANDARD_EC_WLAN_MASK);
+ else
+ set_device_state("1", 0, MSI_STANDARD_EC_WLAN_MASK);
+
+ return 0;
+}
+
+static int rfkill_threeg_set(void *data, bool blocked)
+{
+ if (blocked)
+ set_device_state("0", 0, MSI_STANDARD_EC_3G_MASK);
+ else
+ set_device_state("1", 0, MSI_STANDARD_EC_3G_MASK);
+
+ return 0;
+}
+
+static struct rfkill_ops rfkill_bluetooth_ops = {
+ .set_block = rfkill_bluetooth_set
+};
+
+static struct rfkill_ops rfkill_wlan_ops = {
+ .set_block = rfkill_wlan_set
+};
+
+static struct rfkill_ops rfkill_threeg_ops = {
+ .set_block = rfkill_threeg_set
+};
+
+static void rfkill_cleanup(void)
+{
+ if (rfk_bluetooth) {
+ rfkill_unregister(rfk_bluetooth);
+ rfkill_destroy(rfk_bluetooth);
+ }
+
+ if (rfk_threeg) {
+ rfkill_unregister(rfk_threeg);
+ rfkill_destroy(rfk_threeg);
+ }
+
+ if (rfk_wlan) {
+ rfkill_unregister(rfk_wlan);
+ rfkill_destroy(rfk_wlan);
+ }
+}
+
+static int rfkill_init(struct platform_device *sdev)
+{
+ /* add rfkill */
+ int retval;
+
+ rfk_bluetooth = rfkill_alloc("msi-bluetooth", &sdev->dev,
+ RFKILL_TYPE_BLUETOOTH,
+ &rfkill_bluetooth_ops, NULL);
+ if (!rfk_bluetooth) {
+ retval = -ENOMEM;
+ goto err_bluetooth;
+ }
+ retval = rfkill_register(rfk_bluetooth);
+ if (retval)
+ goto err_bluetooth;
+
+ rfk_wlan = rfkill_alloc("msi-wlan", &sdev->dev, RFKILL_TYPE_WLAN,
+ &rfkill_wlan_ops, NULL);
+ if (!rfk_wlan) {
+ retval = -ENOMEM;
+ goto err_wlan;
+ }
+ retval = rfkill_register(rfk_wlan);
+ if (retval)
+ goto err_wlan;
+
+ if (threeg_exists) {
+ rfk_threeg = rfkill_alloc("msi-threeg", &sdev->dev,
+ RFKILL_TYPE_WWAN, &rfkill_threeg_ops, NULL);
+ if (!rfk_threeg) {
+ retval = -ENOMEM;
+ goto err_threeg;
+ }
+ retval = rfkill_register(rfk_threeg);
+ if (retval)
+ goto err_threeg;
+ }
+
+ return 0;
+
+err_threeg:
+ rfkill_destroy(rfk_threeg);
+ if (rfk_wlan)
+ rfkill_unregister(rfk_wlan);
+err_wlan:
+ rfkill_destroy(rfk_wlan);
+ if (rfk_bluetooth)
+ rfkill_unregister(rfk_bluetooth);
+err_bluetooth:
+ rfkill_destroy(rfk_bluetooth);
+
+ return retval;
+}
+
+static int msi_laptop_resume(struct platform_device *device)
+{
+ u8 data;
+ int result;
+
+ if (!load_scm_model)
+ return 0;
+
+ /* set load SCM to disable hardware control by fn key */
+ result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
+ if (result < 0)
+ return result;
+
+ result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
+ data | MSI_STANDARD_EC_SCM_LOAD_MASK);
+ if (result < 0)
+ return result;
+
+ return 0;
+}
+
+static int load_scm_model_init(struct platform_device *sdev)
+{
+ u8 data;
+ int result;
+
+ /* allow userland write sysfs file */
+ dev_attr_bluetooth.store = store_bluetooth;
+ dev_attr_wlan.store = store_wlan;
+ dev_attr_threeg.store = store_threeg;
+ dev_attr_bluetooth.attr.mode |= S_IWUSR;
+ dev_attr_wlan.attr.mode |= S_IWUSR;
+ dev_attr_threeg.attr.mode |= S_IWUSR;
+
+ /* disable hardware control by fn key */
+ result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
+ if (result < 0)
+ return result;
+
+ result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
+ data | MSI_STANDARD_EC_SCM_LOAD_MASK);
+ if (result < 0)
+ return result;
+
+ /* initial rfkill */
+ result = rfkill_init(sdev);
+ if (result < 0)
+ return result;
+
+ return 0;
+}
+
static int __init msi_init(void)
{
int ret;
@@ -339,8 +665,14 @@ static int __init msi_init(void)
if (acpi_disabled)
return -ENODEV;
- if (!force && !dmi_check_system(msi_dmi_table))
- return -ENODEV;
+ if (force || dmi_check_system(msi_dmi_table))
+ old_ec_model = 1;
+
+ if (!old_ec_model)
+ get_threeg_exists();
+
+ if (!old_ec_model && dmi_check_system(msi_load_scm_models_dmi_table))
+ load_scm_model = 1;
if (auto_brightness < 0 || auto_brightness > 2)
return -EINVAL;
@@ -374,10 +706,23 @@ static int __init msi_init(void)
if (ret)
goto fail_platform_device1;
+ if (load_scm_model && (load_scm_model_init(msipf_device) < 0)) {
+ ret = -EINVAL;
+ goto fail_platform_device1;
+ }
+
ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group);
if (ret)
goto fail_platform_device2;
+ if (!old_ec_model) {
+ if (threeg_exists)
+ ret = device_create_file(&msipf_device->dev,
+ &dev_attr_threeg);
+ if (ret)
+ goto fail_platform_device2;
+ }
+
/* Disable automatic brightness control by default because
* this module was probably loaded to do brightness control in
* software. */
@@ -412,10 +757,14 @@ static void __exit msi_cleanup(void)
{
sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
+ if (!old_ec_model && threeg_exists)
+ device_remove_file(&msipf_device->dev, &dev_attr_threeg);
platform_device_unregister(msipf_device);
platform_driver_unregister(&msipf_driver);
backlight_device_unregister(msibl_device);
+ rfkill_cleanup();
+
/* Enable automatic brightness control again */
if (auto_brightness != 2)
set_auto_brightness(1);
@@ -435,3 +784,4 @@ MODULE_ALIAS("dmi:*:svnMICRO-STARINT'LCO.,LTD:pnMS-1013:pvr0131*:cvnMICRO-STARIN
MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*");
MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
+MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N034:*");
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index fe7cf0188acc..c9fc479fc290 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -200,7 +200,7 @@ static struct acpi_driver acpi_pcc_driver = {
};
#define KEYMAP_SIZE 11
-static const int initial_keymap[KEYMAP_SIZE] = {
+static const unsigned int initial_keymap[KEYMAP_SIZE] = {
/* 0 */ KEY_RESERVED,
/* 1 */ KEY_BRIGHTNESSDOWN,
/* 2 */ KEY_BRIGHTNESSUP,
@@ -222,7 +222,7 @@ struct pcc_acpi {
struct acpi_device *device;
struct input_dev *input_dev;
struct backlight_device *backlight;
- int keymap[KEYMAP_SIZE];
+ unsigned int keymap[KEYMAP_SIZE];
};
struct pcc_keyinput {
@@ -445,7 +445,8 @@ static struct attribute_group pcc_attr_group = {
/* hotkey input device driver */
-static int pcc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+static int pcc_getkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int *keycode)
{
struct pcc_acpi *pcc = input_get_drvdata(dev);
@@ -457,7 +458,7 @@ static int pcc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
return 0;
}
-static int keymap_get_by_keycode(struct pcc_acpi *pcc, int keycode)
+static int keymap_get_by_keycode(struct pcc_acpi *pcc, unsigned int keycode)
{
int i;
@@ -469,7 +470,8 @@ static int keymap_get_by_keycode(struct pcc_acpi *pcc, int keycode)
return 0;
}
-static int pcc_setkeycode(struct input_dev *dev, int scancode, int keycode)
+static int pcc_setkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int keycode)
{
struct pcc_acpi *pcc = input_get_drvdata(dev);
int oldkeycode;
@@ -477,9 +479,6 @@ static int pcc_setkeycode(struct input_dev *dev, int scancode, int keycode)
if (scancode >= ARRAY_SIZE(pcc->keymap))
return -EINVAL;
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
-
oldkeycode = pcc->keymap[scancode];
pcc->keymap[scancode] = keycode;
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 5af53340da6f..5a3d8514c66d 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -145,7 +145,7 @@ struct sony_laptop_input_s {
struct input_dev *key_dev;
struct kfifo fifo;
spinlock_t fifo_lock;
- struct workqueue_struct *wq;
+ struct timer_list release_key_timer;
};
static struct sony_laptop_input_s sony_laptop_input = {
@@ -299,20 +299,26 @@ static int sony_laptop_input_keycode_map[] = {
};
/* release buttons after a short delay if pressed */
-static void do_sony_laptop_release_key(struct work_struct *work)
+static void do_sony_laptop_release_key(unsigned long unused)
{
struct sony_laptop_keypress kp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sony_laptop_input.fifo_lock, flags);
- while (kfifo_out_locked(&sony_laptop_input.fifo, (unsigned char *)&kp,
- sizeof(kp), &sony_laptop_input.fifo_lock)
- == sizeof(kp)) {
- msleep(10);
+ if (kfifo_out(&sony_laptop_input.fifo,
+ (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
input_report_key(kp.dev, kp.key, 0);
input_sync(kp.dev);
}
+
+ /* If there is something in the fifo schedule next release. */
+ if (kfifo_len(&sony_laptop_input.fifo) != 0)
+ mod_timer(&sony_laptop_input.release_key_timer,
+ jiffies + msecs_to_jiffies(10));
+
+ spin_unlock_irqrestore(&sony_laptop_input.fifo_lock, flags);
}
-static DECLARE_WORK(sony_laptop_release_key_work,
- do_sony_laptop_release_key);
/* forward event to the input subsystem */
static void sony_laptop_report_input_event(u8 event)
@@ -366,13 +372,13 @@ static void sony_laptop_report_input_event(u8 event)
/* we emit the scancode so we can always remap the key */
input_event(kp.dev, EV_MSC, MSC_SCAN, event);
input_sync(kp.dev);
- kfifo_in_locked(&sony_laptop_input.fifo,
- (unsigned char *)&kp, sizeof(kp),
- &sony_laptop_input.fifo_lock);
- if (!work_pending(&sony_laptop_release_key_work))
- queue_work(sony_laptop_input.wq,
- &sony_laptop_release_key_work);
+ /* schedule key release */
+ kfifo_in_locked(&sony_laptop_input.fifo,
+ (unsigned char *)&kp, sizeof(kp),
+ &sony_laptop_input.fifo_lock);
+ mod_timer(&sony_laptop_input.release_key_timer,
+ jiffies + msecs_to_jiffies(10));
} else
dprintk("unknown input event %.2x\n", event);
}
@@ -390,27 +396,21 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
/* kfifo */
spin_lock_init(&sony_laptop_input.fifo_lock);
- error =
- kfifo_alloc(&sony_laptop_input.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
+ error = kfifo_alloc(&sony_laptop_input.fifo,
+ SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
if (error) {
printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
goto err_dec_users;
}
- /* init workqueue */
- sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop");
- if (!sony_laptop_input.wq) {
- printk(KERN_ERR DRV_PFX
- "Unable to create workqueue.\n");
- error = -ENXIO;
- goto err_free_kfifo;
- }
+ setup_timer(&sony_laptop_input.release_key_timer,
+ do_sony_laptop_release_key, 0);
/* input keys */
key_dev = input_allocate_device();
if (!key_dev) {
error = -ENOMEM;
- goto err_destroy_wq;
+ goto err_free_kfifo;
}
key_dev->name = "Sony Vaio Keys";
@@ -419,18 +419,15 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
key_dev->dev.parent = &acpi_device->dev;
/* Initialize the Input Drivers: special keys */
- set_bit(EV_KEY, key_dev->evbit);
- set_bit(EV_MSC, key_dev->evbit);
- set_bit(MSC_SCAN, key_dev->mscbit);
+ input_set_capability(key_dev, EV_MSC, MSC_SCAN);
+
+ __set_bit(EV_KEY, key_dev->evbit);
key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
key_dev->keycode = &sony_laptop_input_keycode_map;
- for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) {
- if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) {
- set_bit(sony_laptop_input_keycode_map[i],
- key_dev->keybit);
- }
- }
+ for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++)
+ __set_bit(sony_laptop_input_keycode_map[i], key_dev->keybit);
+ __clear_bit(KEY_RESERVED, key_dev->keybit);
error = input_register_device(key_dev);
if (error)
@@ -450,9 +447,8 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
key_dev->dev.parent = &acpi_device->dev;
- jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
- jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE);
- jog_dev->relbit[0] = BIT_MASK(REL_WHEEL);
+ input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
+ input_set_capability(jog_dev, EV_REL, REL_WHEEL);
error = input_register_device(jog_dev);
if (error)
@@ -473,9 +469,6 @@ err_unregister_keydev:
err_free_keydev:
input_free_device(key_dev);
-err_destroy_wq:
- destroy_workqueue(sony_laptop_input.wq);
-
err_free_kfifo:
kfifo_free(&sony_laptop_input.fifo);
@@ -486,12 +479,23 @@ err_dec_users:
static void sony_laptop_remove_input(void)
{
- /* cleanup only after the last user has gone */
+ struct sony_laptop_keypress kp = { NULL };
+
+ /* Cleanup only after the last user has gone */
if (!atomic_dec_and_test(&sony_laptop_input.users))
return;
- /* flush workqueue first */
- flush_workqueue(sony_laptop_input.wq);
+ del_timer_sync(&sony_laptop_input.release_key_timer);
+
+ /*
+ * Generate key-up events for remaining keys. Note that we don't
+ * need locking since nobody is adding new events to the kfifo.
+ */
+ while (kfifo_out(&sony_laptop_input.fifo,
+ (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
+ input_report_key(kp.dev, kp.key, 0);
+ input_sync(kp.dev);
+ }
/* destroy input devs */
input_unregister_device(sony_laptop_input.key_dev);
@@ -502,7 +506,6 @@ static void sony_laptop_remove_input(void)
sony_laptop_input.jog_dev = NULL;
}
- destroy_workqueue(sony_laptop_input.wq);
kfifo_free(&sony_laptop_input.fifo);
}
@@ -1201,9 +1204,12 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
/* the buffer is filled with magic numbers describing the devices
* available, 0xff terminates the enumeration
*/
- while ((dev_code = *(device_enum->buffer.pointer + i)) != 0xff &&
- i < device_enum->buffer.length) {
- i++;
+ for (i = 0; i < device_enum->buffer.length; i++) {
+
+ dev_code = *(device_enum->buffer.pointer + i);
+ if (dev_code == 0xff)
+ break;
+
dprintk("Radio devices, looking at 0x%.2x\n", dev_code);
if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI])
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index e67e4feb35cb..c64e3528889b 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -286,6 +286,7 @@ struct ibm_init_struct {
char param[32];
int (*init) (struct ibm_init_struct *);
+ mode_t base_procfs_mode;
struct ibm_struct *data;
};
@@ -1667,7 +1668,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv)
* Table of recommended minimum BIOS versions
*
* Reasons for listing:
- * 1. Stable BIOS, listed because the unknown ammount of
+ * 1. Stable BIOS, listed because the unknown amount of
* bugs and bad ACPI behaviour on older versions
*
* 2. BIOS or EC fw with known bugs that trigger on Linux
@@ -2082,6 +2083,7 @@ static struct attribute_set *hotkey_dev_attributes;
static void tpacpi_driver_event(const unsigned int hkey_event);
static void hotkey_driver_event(const unsigned int scancode);
+static void hotkey_poll_setup(const bool may_warn);
/* HKEY.MHKG() return bits */
#define TP_HOTKEY_TABLET_MASK (1 << 3)
@@ -2264,6 +2266,8 @@ static int tpacpi_hotkey_driver_mask_set(const u32 mask)
rc = hotkey_mask_set((hotkey_acpi_mask | hotkey_driver_mask) &
~hotkey_source_mask);
+ hotkey_poll_setup(true);
+
mutex_unlock(&hotkey_mutex);
return rc;
@@ -2548,7 +2552,7 @@ static void hotkey_poll_stop_sync(void)
}
/* call with hotkey_mutex held */
-static void hotkey_poll_setup(bool may_warn)
+static void hotkey_poll_setup(const bool may_warn)
{
const u32 poll_driver_mask = hotkey_driver_mask & hotkey_source_mask;
const u32 poll_user_mask = hotkey_user_mask & hotkey_source_mask;
@@ -2579,7 +2583,7 @@ static void hotkey_poll_setup(bool may_warn)
}
}
-static void hotkey_poll_setup_safe(bool may_warn)
+static void hotkey_poll_setup_safe(const bool may_warn)
{
mutex_lock(&hotkey_mutex);
hotkey_poll_setup(may_warn);
@@ -2597,7 +2601,11 @@ static void hotkey_poll_set_freq(unsigned int freq)
#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
-static void hotkey_poll_setup_safe(bool __unused)
+static void hotkey_poll_setup(const bool __unused)
+{
+}
+
+static void hotkey_poll_setup_safe(const bool __unused)
{
}
@@ -2607,16 +2615,11 @@ static int hotkey_inputdev_open(struct input_dev *dev)
{
switch (tpacpi_lifecycle) {
case TPACPI_LIFE_INIT:
- /*
- * hotkey_init will call hotkey_poll_setup_safe
- * at the appropriate moment
- */
- return 0;
- case TPACPI_LIFE_EXITING:
- return -EBUSY;
case TPACPI_LIFE_RUNNING:
hotkey_poll_setup_safe(false);
return 0;
+ case TPACPI_LIFE_EXITING:
+ return -EBUSY;
}
/* Should only happen if tpacpi_lifecycle is corrupt */
@@ -2627,7 +2630,7 @@ static int hotkey_inputdev_open(struct input_dev *dev)
static void hotkey_inputdev_close(struct input_dev *dev)
{
/* disable hotkey polling when possible */
- if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING &&
+ if (tpacpi_lifecycle != TPACPI_LIFE_EXITING &&
!(hotkey_source_mask & hotkey_driver_mask))
hotkey_poll_setup_safe(false);
}
@@ -3655,13 +3658,19 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
break;
case 3:
/* 0x3000-0x3FFF: bay-related wakeups */
- if (hkey == TP_HKEY_EV_BAYEJ_ACK) {
+ switch (hkey) {
+ case TP_HKEY_EV_BAYEJ_ACK:
hotkey_autosleep_ack = 1;
printk(TPACPI_INFO
"bay ejected\n");
hotkey_wakeup_hotunplug_complete_notify_change();
known_ev = true;
- } else {
+ break;
+ case TP_HKEY_EV_OPTDRV_EJ:
+ /* FIXME: kick libata if SATA link offline */
+ known_ev = true;
+ break;
+ default:
known_ev = false;
}
break;
@@ -3870,7 +3879,7 @@ enum {
TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
TP_ACPI_BLUETOOTH_RESUMECTRL = 0x04, /* Bluetooth state at resume:
- off / last state */
+ 0 = disable, 1 = enable */
};
enum {
@@ -3916,10 +3925,11 @@ static int bluetooth_set_status(enum tpacpi_rfkill_state state)
}
#endif
- /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */
- status = TP_ACPI_BLUETOOTH_RESUMECTRL;
if (state == TPACPI_RFK_RADIO_ON)
- status |= TP_ACPI_BLUETOOTH_RADIOSSW;
+ status = TP_ACPI_BLUETOOTH_RADIOSSW
+ | TP_ACPI_BLUETOOTH_RESUMECTRL;
+ else
+ status = 0;
if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
return -EIO;
@@ -4070,7 +4080,7 @@ enum {
TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
TP_ACPI_WANCARD_RESUMECTRL = 0x04, /* Wan state at resume:
- off / last state */
+ 0 = disable, 1 = enable */
};
#define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw"
@@ -4107,10 +4117,11 @@ static int wan_set_status(enum tpacpi_rfkill_state state)
}
#endif
- /* We make sure to set TP_ACPI_WANCARD_RESUMECTRL */
- status = TP_ACPI_WANCARD_RESUMECTRL;
if (state == TPACPI_RFK_RADIO_ON)
- status |= TP_ACPI_WANCARD_RADIOSSW;
+ status = TP_ACPI_WANCARD_RADIOSSW
+ | TP_ACPI_WANCARD_RESUMECTRL;
+ else
+ status = 0;
if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
return -EIO;
@@ -4619,6 +4630,10 @@ static int video_read(struct seq_file *m)
return 0;
}
+ /* Even reads can crash X.org, so... */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
status = video_outputsw_get();
if (status < 0)
return status;
@@ -4652,6 +4667,10 @@ static int video_write(char *buf)
if (video_supported == TPACPI_VIDEO_NONE)
return -ENODEV;
+ /* Even reads can crash X.org, let alone writes... */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
enable = 0;
disable = 0;
@@ -5771,7 +5790,7 @@ static void thermal_exit(void)
case TPACPI_THERMAL_ACPI_TMP07:
case TPACPI_THERMAL_ACPI_UPDT:
sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
- &thermal_temp_input16_group);
+ &thermal_temp_input8_group);
break;
case TPACPI_THERMAL_NONE:
default:
@@ -6133,13 +6152,13 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = {
TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */
/* Models with ATI GPUs that can use ECNVRAM */
- TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC),
+ TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC), /* R50,51 T40-42 */
TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
- TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
+ TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_EC), /* R52 */
TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
/* Models with Intel Extreme Graphics 2 */
- TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC),
+ TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), /* X40 */
TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
@@ -6522,7 +6541,8 @@ static int volume_set_status(const u8 status)
return volume_set_status_ec(status);
}
-static int volume_set_mute_ec(const bool mute)
+/* returns < 0 on error, 0 on no change, 1 on change */
+static int __volume_set_mute_ec(const bool mute)
{
int rc;
u8 s, n;
@@ -6537,22 +6557,37 @@ static int volume_set_mute_ec(const bool mute)
n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK :
s & ~TP_EC_AUDIO_MUTESW_MSK;
- if (n != s)
+ if (n != s) {
rc = volume_set_status_ec(n);
+ if (!rc)
+ rc = 1;
+ }
unlock:
mutex_unlock(&volume_mutex);
return rc;
}
+static int volume_alsa_set_mute(const bool mute)
+{
+ dbg_printk(TPACPI_DBG_MIXER, "ALSA: trying to %smute\n",
+ (mute) ? "" : "un");
+ return __volume_set_mute_ec(mute);
+}
+
static int volume_set_mute(const bool mute)
{
+ int rc;
+
dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n",
(mute) ? "" : "un");
- return volume_set_mute_ec(mute);
+
+ rc = __volume_set_mute_ec(mute);
+ return (rc < 0) ? rc : 0;
}
-static int volume_set_volume_ec(const u8 vol)
+/* returns < 0 on error, 0 on no change, 1 on change */
+static int __volume_set_volume_ec(const u8 vol)
{
int rc;
u8 s, n;
@@ -6569,19 +6604,22 @@ static int volume_set_volume_ec(const u8 vol)
n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol;
- if (n != s)
+ if (n != s) {
rc = volume_set_status_ec(n);
+ if (!rc)
+ rc = 1;
+ }
unlock:
mutex_unlock(&volume_mutex);
return rc;
}
-static int volume_set_volume(const u8 vol)
+static int volume_alsa_set_volume(const u8 vol)
{
dbg_printk(TPACPI_DBG_MIXER,
- "trying to set volume level to %hu\n", vol);
- return volume_set_volume_ec(vol);
+ "ALSA: trying to set volume level to %hu\n", vol);
+ return __volume_set_volume_ec(vol);
}
static void volume_alsa_notify_change(void)
@@ -6628,7 +6666,7 @@ static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol,
static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- return volume_set_volume(ucontrol->value.integer.value[0]);
+ return volume_alsa_set_volume(ucontrol->value.integer.value[0]);
}
#define volume_alsa_mute_info snd_ctl_boolean_mono_info
@@ -6651,7 +6689,7 @@ static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol,
static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- return volume_set_mute(!ucontrol->value.integer.value[0]);
+ return volume_alsa_set_mute(!ucontrol->value.integer.value[0]);
}
static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = {
@@ -7070,7 +7108,7 @@ static struct ibm_struct volume_driver_data = {
*
* Fan speed changes of any sort (including those caused by the
* disengaged mode) are usually done slowly by the firmware as the
- * maximum ammount of fan duty cycle change per second seems to be
+ * maximum amount of fan duty cycle change per second seems to be
* limited.
*
* Reading is not available if GFAN exists.
@@ -8477,9 +8515,10 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
"%s installed\n", ibm->name);
if (ibm->read) {
- mode_t mode;
+ mode_t mode = iibm->base_procfs_mode;
- mode = S_IRUGO;
+ if (!mode)
+ mode = S_IRUGO;
if (ibm->write)
mode |= S_IWUSR;
entry = proc_create_data(ibm->name, mode, proc_dir,
@@ -8670,6 +8709,7 @@ static struct ibm_init_struct ibms_init[] __initdata = {
#ifdef CONFIG_THINKPAD_ACPI_VIDEO
{
.init = video_init,
+ .base_procfs_mode = S_IRUSR,
.data = &video_driver_data,
},
#endif
@@ -9032,6 +9072,9 @@ static int __init thinkpad_acpi_module_init(void)
return ret;
}
}
+
+ tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
+
ret = input_register_device(tpacpi_inputdev);
if (ret < 0) {
printk(TPACPI_ERR "unable to register input device\n");
@@ -9041,7 +9084,6 @@ static int __init thinkpad_acpi_module_init(void)
tp_features.input_device_registered = 1;
}
- tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
return 0;
}
diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c
index 02f3d4e9e666..4d6516fded7e 100644
--- a/drivers/platform/x86/topstar-laptop.c
+++ b/drivers/platform/x86/topstar-laptop.c
@@ -46,7 +46,7 @@ static struct tps_key_entry topstar_keymap[] = {
{ }
};
-static struct tps_key_entry *tps_get_key_by_scancode(int code)
+static struct tps_key_entry *tps_get_key_by_scancode(unsigned int code)
{
struct tps_key_entry *key;
@@ -57,7 +57,7 @@ static struct tps_key_entry *tps_get_key_by_scancode(int code)
return NULL;
}
-static struct tps_key_entry *tps_get_key_by_keycode(int code)
+static struct tps_key_entry *tps_get_key_by_keycode(unsigned int code)
{
struct tps_key_entry *key;
@@ -126,7 +126,8 @@ static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state)
return 0;
}
-static int topstar_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+static int topstar_getkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int *keycode)
{
struct tps_key_entry *key = tps_get_key_by_scancode(scancode);
@@ -137,14 +138,12 @@ static int topstar_getkeycode(struct input_dev *dev, int scancode, int *keycode)
return 0;
}
-static int topstar_setkeycode(struct input_dev *dev, int scancode, int keycode)
+static int topstar_setkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int keycode)
{
struct tps_key_entry *key;
int old_keycode;
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
-
key = tps_get_key_by_scancode(scancode);
if (!key)
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 77bf5d8f893a..789240d1b577 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -46,6 +46,7 @@
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>
+#include <linux/input.h>
#include <asm/uaccess.h>
@@ -62,9 +63,10 @@ MODULE_LICENSE("GPL");
/* Toshiba ACPI method paths */
#define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM"
-#define METHOD_HCI_1 "\\_SB_.VALD.GHCI"
-#define METHOD_HCI_2 "\\_SB_.VALZ.GHCI"
+#define TOSH_INTERFACE_1 "\\_SB_.VALD"
+#define TOSH_INTERFACE_2 "\\_SB_.VALZ"
#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
+#define GHCI_METHOD ".GHCI"
/* Toshiba HCI interface definitions
*
@@ -116,6 +118,36 @@ static const struct acpi_device_id toshiba_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
+struct key_entry {
+ char type;
+ u16 code;
+ u16 keycode;
+};
+
+enum {KE_KEY, KE_END};
+
+static struct key_entry toshiba_acpi_keymap[] = {
+ {KE_KEY, 0x101, KEY_MUTE},
+ {KE_KEY, 0x13b, KEY_COFFEE},
+ {KE_KEY, 0x13c, KEY_BATTERY},
+ {KE_KEY, 0x13d, KEY_SLEEP},
+ {KE_KEY, 0x13e, KEY_SUSPEND},
+ {KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE},
+ {KE_KEY, 0x140, KEY_BRIGHTNESSDOWN},
+ {KE_KEY, 0x141, KEY_BRIGHTNESSUP},
+ {KE_KEY, 0x142, KEY_WLAN},
+ {KE_KEY, 0x143, KEY_PROG1},
+ {KE_KEY, 0xb05, KEY_PROG2},
+ {KE_KEY, 0xb06, KEY_WWW},
+ {KE_KEY, 0xb07, KEY_MAIL},
+ {KE_KEY, 0xb30, KEY_STOP},
+ {KE_KEY, 0xb31, KEY_PREVIOUSSONG},
+ {KE_KEY, 0xb32, KEY_NEXTSONG},
+ {KE_KEY, 0xb33, KEY_PLAYPAUSE},
+ {KE_KEY, 0xb5a, KEY_MEDIA},
+ {KE_END, 0, 0},
+};
+
/* utility
*/
@@ -251,6 +283,8 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
struct toshiba_acpi_dev {
struct platform_device *p_dev;
struct rfkill *bt_rfk;
+ struct input_dev *hotkey_dev;
+ acpi_handle handle;
const char *bt_name;
@@ -711,8 +745,158 @@ static struct backlight_ops toshiba_backlight_data = {
.update_status = set_lcd_status,
};
+static struct key_entry *toshiba_acpi_get_entry_by_scancode(unsigned int code)
+{
+ struct key_entry *key;
+
+ for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
+ if (code == key->code)
+ return key;
+
+ return NULL;
+}
+
+static struct key_entry *toshiba_acpi_get_entry_by_keycode(unsigned int code)
+{
+ struct key_entry *key;
+
+ for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
+ if (code == key->keycode && key->type == KE_KEY)
+ return key;
+
+ return NULL;
+}
+
+static int toshiba_acpi_getkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int *keycode)
+{
+ struct key_entry *key = toshiba_acpi_get_entry_by_scancode(scancode);
+
+ if (key && key->type == KE_KEY) {
+ *keycode = key->keycode;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int toshiba_acpi_setkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int keycode)
+{
+ struct key_entry *key;
+ unsigned int old_keycode;
+
+ key = toshiba_acpi_get_entry_by_scancode(scancode);
+ if (key && key->type == KE_KEY) {
+ old_keycode = key->keycode;
+ key->keycode = keycode;
+ set_bit(keycode, dev->keybit);
+ if (!toshiba_acpi_get_entry_by_keycode(old_keycode))
+ clear_bit(old_keycode, dev->keybit);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
+{
+ u32 hci_result, value;
+ struct key_entry *key;
+
+ if (event != 0x80)
+ return;
+ do {
+ hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
+ if (hci_result == HCI_SUCCESS) {
+ if (value == 0x100)
+ continue;
+ /* act on key press; ignore key release */
+ if (value & 0x80)
+ continue;
+
+ key = toshiba_acpi_get_entry_by_scancode
+ (value);
+ if (!key) {
+ printk(MY_INFO "Unknown key %x\n",
+ value);
+ continue;
+ }
+ input_report_key(toshiba_acpi.hotkey_dev,
+ key->keycode, 1);
+ input_sync(toshiba_acpi.hotkey_dev);
+ input_report_key(toshiba_acpi.hotkey_dev,
+ key->keycode, 0);
+ input_sync(toshiba_acpi.hotkey_dev);
+ } else if (hci_result == HCI_NOT_SUPPORTED) {
+ /* This is a workaround for an unresolved issue on
+ * some machines where system events sporadically
+ * become disabled. */
+ hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
+ printk(MY_NOTICE "Re-enabled hotkeys\n");
+ }
+ } while (hci_result != HCI_EMPTY);
+}
+
+static int toshiba_acpi_setup_keyboard(char *device)
+{
+ acpi_status status;
+ acpi_handle handle;
+ int result;
+ const struct key_entry *key;
+
+ status = acpi_get_handle(NULL, device, &handle);
+ if (ACPI_FAILURE(status)) {
+ printk(MY_INFO "Unable to get notification device\n");
+ return -ENODEV;
+ }
+
+ toshiba_acpi.handle = handle;
+
+ status = acpi_evaluate_object(handle, "ENAB", NULL, NULL);
+ if (ACPI_FAILURE(status)) {
+ printk(MY_INFO "Unable to enable hotkeys\n");
+ return -ENODEV;
+ }
+
+ status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY,
+ toshiba_acpi_notify, NULL);
+ if (ACPI_FAILURE(status)) {
+ printk(MY_INFO "Unable to install hotkey notification\n");
+ return -ENODEV;
+ }
+
+ toshiba_acpi.hotkey_dev = input_allocate_device();
+ if (!toshiba_acpi.hotkey_dev) {
+ printk(MY_INFO "Unable to register input device\n");
+ return -ENOMEM;
+ }
+
+ toshiba_acpi.hotkey_dev->name = "Toshiba input device";
+ toshiba_acpi.hotkey_dev->phys = device;
+ toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST;
+ toshiba_acpi.hotkey_dev->getkeycode = toshiba_acpi_getkeycode;
+ toshiba_acpi.hotkey_dev->setkeycode = toshiba_acpi_setkeycode;
+
+ for (key = toshiba_acpi_keymap; key->type != KE_END; key++) {
+ set_bit(EV_KEY, toshiba_acpi.hotkey_dev->evbit);
+ set_bit(key->keycode, toshiba_acpi.hotkey_dev->keybit);
+ }
+
+ result = input_register_device(toshiba_acpi.hotkey_dev);
+ if (result) {
+ printk(MY_INFO "Unable to register input device\n");
+ return result;
+ }
+
+ return 0;
+}
+
static void toshiba_acpi_exit(void)
{
+ if (toshiba_acpi.hotkey_dev)
+ input_unregister_device(toshiba_acpi.hotkey_dev);
+
if (toshiba_acpi.bt_rfk) {
rfkill_unregister(toshiba_acpi.bt_rfk);
rfkill_destroy(toshiba_acpi.bt_rfk);
@@ -726,6 +910,9 @@ static void toshiba_acpi_exit(void)
if (toshiba_proc_dir)
remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+ acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
+ toshiba_acpi_notify);
+
platform_device_unregister(toshiba_acpi.p_dev);
return;
@@ -742,11 +929,15 @@ static int __init toshiba_acpi_init(void)
return -ENODEV;
/* simple device detection: look for HCI method */
- if (is_valid_acpi_path(METHOD_HCI_1))
- method_hci = METHOD_HCI_1;
- else if (is_valid_acpi_path(METHOD_HCI_2))
- method_hci = METHOD_HCI_2;
- else
+ if (is_valid_acpi_path(TOSH_INTERFACE_1 GHCI_METHOD)) {
+ method_hci = TOSH_INTERFACE_1 GHCI_METHOD;
+ if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_1))
+ printk(MY_INFO "Unable to activate hotkeys\n");
+ } else if (is_valid_acpi_path(TOSH_INTERFACE_2 GHCI_METHOD)) {
+ method_hci = TOSH_INTERFACE_2 GHCI_METHOD;
+ if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_2))
+ printk(MY_INFO "Unable to activate hotkeys\n");
+ } else
return -ENODEV;
printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n",
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c
index a350418e87ea..944068611919 100644
--- a/drivers/platform/x86/toshiba_bluetooth.c
+++ b/drivers/platform/x86/toshiba_bluetooth.c
@@ -57,7 +57,7 @@ static struct acpi_driver toshiba_bt_rfkill_driver = {
static int toshiba_bluetooth_enable(acpi_handle handle)
{
acpi_status res1, res2;
- acpi_integer result;
+ u64 result;
/*
* Query ACPI to verify RFKill switch is set to 'on'.
@@ -95,7 +95,7 @@ static int toshiba_bt_resume(struct acpi_device *device)
static int toshiba_bt_rfkill_add(struct acpi_device *device)
{
acpi_status status;
- acpi_integer bt_present;
+ u64 bt_present;
int result = -ENODEV;
/*
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index b104302fea0a..09e9918c69c1 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -796,7 +796,7 @@ static __init acpi_status parse_wdg(acpi_handle handle)
*/
static acpi_status
acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
- u32 bits, acpi_integer * value,
+ u32 bits, u64 *value,
void *handler_context, void *region_context)
{
int result = 0, i = 0;
@@ -813,7 +813,7 @@ acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
if (function == ACPI_READ) {
result = ec_read(address, &temp);
- (*value) |= ((acpi_integer)temp) << i;
+ (*value) |= ((u64)temp) << i;
} else {
temp = 0xff & ((*value) >> i);
result = ec_write(address, temp);
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
index 0b8d14050efa..0bab84ebb15d 100644
--- a/drivers/pnp/base.h
+++ b/drivers/pnp/base.h
@@ -166,6 +166,9 @@ struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
resource_size_t start,
resource_size_t end, int flags);
+struct pnp_resource *pnp_add_bus_resource(struct pnp_dev *dev,
+ resource_size_t start,
+ resource_size_t end);
extern int pnp_debug;
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index 68b0c04987e4..cfaf5b73540b 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -278,9 +278,12 @@ static ssize_t pnp_show_current_resources(struct device *dmdev,
switch (pnp_resource_type(res)) {
case IORESOURCE_IO:
case IORESOURCE_MEM:
- pnp_printf(buffer, " %#llx-%#llx\n",
+ case IORESOURCE_BUS:
+ pnp_printf(buffer, " %#llx-%#llx%s\n",
(unsigned long long) res->start,
- (unsigned long long) res->end);
+ (unsigned long long) res->end,
+ res->flags & IORESOURCE_WINDOW ?
+ " window" : "");
break;
case IORESOURCE_IRQ:
case IORESOURCE_DMA:
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 5702b2c8691f..54514aa35b09 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -177,7 +177,8 @@ static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
}
static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start,
- u64 len, int io_decode)
+ u64 len, int io_decode,
+ int window)
{
int flags = 0;
u64 end = start + len - 1;
@@ -186,6 +187,8 @@ static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start,
flags |= IORESOURCE_IO_16BIT_ADDR;
if (len == 0 || end >= 0x10003)
flags |= IORESOURCE_DISABLED;
+ if (window)
+ flags |= IORESOURCE_WINDOW;
pnp_add_io_resource(dev, start, end, flags);
}
@@ -247,7 +250,7 @@ static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev,
static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,
u64 start, u64 len,
- int write_protect)
+ int write_protect, int window)
{
int flags = 0;
u64 end = start + len - 1;
@@ -256,15 +259,26 @@ static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,
flags |= IORESOURCE_DISABLED;
if (write_protect == ACPI_READ_WRITE_MEMORY)
flags |= IORESOURCE_MEM_WRITEABLE;
+ if (window)
+ flags |= IORESOURCE_WINDOW;
pnp_add_mem_resource(dev, start, end, flags);
}
+static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev,
+ u64 start, u64 len)
+{
+ u64 end = start + len - 1;
+
+ pnp_add_bus_resource(dev, start, end);
+}
+
static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
struct acpi_resource *res)
{
struct acpi_resource_address64 addr, *p = &addr;
acpi_status status;
+ int window;
status = acpi_resource_to_address64(res, p);
if (!ACPI_SUCCESS(status)) {
@@ -273,37 +287,42 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
return;
}
- if (p->producer_consumer == ACPI_PRODUCER)
- return;
+ window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
if (p->resource_type == ACPI_MEMORY_RANGE)
pnpacpi_parse_allocated_memresource(dev,
p->minimum, p->address_length,
- p->info.mem.write_protect);
+ p->info.mem.write_protect, window);
else if (p->resource_type == ACPI_IO_RANGE)
pnpacpi_parse_allocated_ioresource(dev,
p->minimum, p->address_length,
p->granularity == 0xfff ? ACPI_DECODE_10 :
- ACPI_DECODE_16);
+ ACPI_DECODE_16, window);
+ else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
+ pnpacpi_parse_allocated_busresource(dev, p->minimum,
+ p->address_length);
}
static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev,
struct acpi_resource *res)
{
struct acpi_resource_extended_address64 *p = &res->data.ext_address64;
+ int window;
- if (p->producer_consumer == ACPI_PRODUCER)
- return;
+ window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
if (p->resource_type == ACPI_MEMORY_RANGE)
pnpacpi_parse_allocated_memresource(dev,
p->minimum, p->address_length,
- p->info.mem.write_protect);
+ p->info.mem.write_protect, window);
else if (p->resource_type == ACPI_IO_RANGE)
pnpacpi_parse_allocated_ioresource(dev,
p->minimum, p->address_length,
p->granularity == 0xfff ? ACPI_DECODE_10 :
- ACPI_DECODE_16);
+ ACPI_DECODE_16, window);
+ else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
+ pnpacpi_parse_allocated_busresource(dev, p->minimum,
+ p->address_length);
}
static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
@@ -368,7 +387,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
pnpacpi_parse_allocated_ioresource(dev,
io->minimum,
io->address_length,
- io->io_decode);
+ io->io_decode, 0);
break;
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -380,7 +399,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
pnpacpi_parse_allocated_ioresource(dev,
fixed_io->address,
fixed_io->address_length,
- ACPI_DECODE_10);
+ ACPI_DECODE_10, 0);
break;
case ACPI_RESOURCE_TYPE_VENDOR:
@@ -396,21 +415,21 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
pnpacpi_parse_allocated_memresource(dev,
memory24->minimum,
memory24->address_length,
- memory24->write_protect);
+ memory24->write_protect, 0);
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
memory32 = &res->data.memory32;
pnpacpi_parse_allocated_memresource(dev,
memory32->minimum,
memory32->address_length,
- memory32->write_protect);
+ memory32->write_protect, 0);
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
fixed_memory32 = &res->data.fixed_memory32;
pnpacpi_parse_allocated_memresource(dev,
fixed_memory32->address,
fixed_memory32->address_length,
- fixed_memory32->write_protect);
+ fixed_memory32->write_protect, 0);
break;
case ACPI_RESOURCE_TYPE_ADDRESS16:
case ACPI_RESOURCE_TYPE_ADDRESS32:
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index 64d0596bafb5..5b277dbaacde 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -470,7 +470,8 @@ int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
unsigned long pnp_resource_type(struct resource *res)
{
return res->flags & (IORESOURCE_IO | IORESOURCE_MEM |
- IORESOURCE_IRQ | IORESOURCE_DMA);
+ IORESOURCE_IRQ | IORESOURCE_DMA |
+ IORESOURCE_BUS);
}
struct resource *pnp_get_resource(struct pnp_dev *dev,
@@ -590,6 +591,30 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
return pnp_res;
}
+struct pnp_resource *pnp_add_bus_resource(struct pnp_dev *dev,
+ resource_size_t start,
+ resource_size_t end)
+{
+ struct pnp_resource *pnp_res;
+ struct resource *res;
+
+ pnp_res = pnp_new_resource(dev);
+ if (!pnp_res) {
+ dev_err(&dev->dev, "can't add resource for BUS %#llx-%#llx\n",
+ (unsigned long long) start,
+ (unsigned long long) end);
+ return NULL;
+ }
+
+ res = &pnp_res->res;
+ res->flags = IORESOURCE_BUS;
+ res->start = start;
+ res->end = end;
+
+ pnp_dbg(&dev->dev, " add %pr\n", res);
+ return pnp_res;
+}
+
/*
* Determine whether the specified resource is a possible configuration
* for this device.
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index 9585c1c1cc36..f5beb24d036a 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -69,8 +69,10 @@ char *pnp_resource_type_name(struct resource *res)
return "irq";
case IORESOURCE_DMA:
return "dma";
+ case IORESOURCE_BUS:
+ return "bus";
}
- return NULL;
+ return "unknown";
}
void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc)
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index d4b3d67f0548..faaa9b4d0d07 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -29,6 +29,13 @@ config APM_POWER
Say Y here to enable support APM status emulation using
battery class devices.
+config MAX8925_POWER
+ tristate "MAX8925 battery charger support"
+ depends on MFD_MAX8925
+ help
+ Say Y here to enable support for the battery charger in the Maxim
+ MAX8925 PMIC.
+
config WM831X_BACKUP
tristate "WM831X backup battery charger support"
depends on MFD_WM831X
@@ -98,10 +105,10 @@ config BATTERY_WM97XX
Say Y to enable support for battery measured by WM97xx aux port.
config BATTERY_BQ27x00
- tristate "BQ27200 battery driver"
+ tristate "BQ27x00 battery driver"
depends on I2C
help
- Say Y here to enable support for batteries with BQ27200(I2C) chip.
+ Say Y here to enable support for batteries with BQ27x00 (I2C) chips.
config BATTERY_DA9030
tristate "DA9030 battery driver"
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 573597c683b4..a2ba7c85c97a 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
obj-$(CONFIG_PDA_POWER) += pda_power.o
obj-$(CONFIG_APM_POWER) += apm_power.o
+obj-$(CONFIG_MAX8925_POWER) += max8925_power.o
obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o
obj-$(CONFIG_WM831X_POWER) += wm831x_power.o
obj-$(CONFIG_WM8350_POWER) += wm8350_power.o
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index 62bb98124e26..bece33ed873c 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -26,13 +26,22 @@
#include <linux/i2c.h>
#include <asm/unaligned.h>
-#define DRIVER_VERSION "1.0.0"
+#define DRIVER_VERSION "1.1.0"
#define BQ27x00_REG_TEMP 0x06
#define BQ27x00_REG_VOLT 0x08
-#define BQ27x00_REG_RSOC 0x0B /* Relative State-of-Charge */
#define BQ27x00_REG_AI 0x14
#define BQ27x00_REG_FLAGS 0x0A
+#define BQ27x00_REG_TTE 0x16
+#define BQ27x00_REG_TTF 0x18
+#define BQ27x00_REG_TTECP 0x26
+
+#define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */
+#define BQ27000_FLAG_CHGS BIT(7)
+
+#define BQ27500_REG_SOC 0x2c
+#define BQ27500_FLAG_DSC BIT(0)
+#define BQ27500_FLAG_FC BIT(9)
/* If the system has several batteries we need a different name for each
* of them...
@@ -46,25 +55,28 @@ struct bq27x00_access_methods {
struct bq27x00_device_info *di);
};
+enum bq27x00_chip { BQ27000, BQ27500 };
+
struct bq27x00_device_info {
struct device *dev;
int id;
- int voltage_uV;
- int current_uA;
- int temp_C;
- int charge_rsoc;
struct bq27x00_access_methods *bus;
struct power_supply bat;
+ enum bq27x00_chip chip;
struct i2c_client *client;
};
static enum power_supply_property bq27x00_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
+ POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
};
/*
@@ -74,16 +86,11 @@ static enum power_supply_property bq27x00_battery_props[] = {
static int bq27x00_read(u8 reg, int *rt_value, int b_single,
struct bq27x00_device_info *di)
{
- int ret;
-
- ret = di->bus->read(reg, rt_value, b_single, di);
- *rt_value = be16_to_cpu(*rt_value);
-
- return ret;
+ return di->bus->read(reg, rt_value, b_single, di);
}
/*
- * Return the battery temperature in Celsius degrees
+ * Return the battery temperature in tenths of degree Celsius
* Or < 0 if something fails.
*/
static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
@@ -97,7 +104,10 @@ static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
return ret;
}
- return (temp >> 2) - 273;
+ if (di->chip == BQ27500)
+ return temp - 2731;
+ else
+ return ((temp >> 2) - 273) * 10;
}
/*
@@ -115,7 +125,7 @@ static int bq27x00_battery_voltage(struct bq27x00_device_info *di)
return ret;
}
- return volt;
+ return volt * 1000;
}
/*
@@ -134,16 +144,23 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di)
dev_err(di->dev, "error reading current\n");
return 0;
}
- ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
- if (ret < 0) {
- dev_err(di->dev, "error reading flags\n");
- return 0;
- }
- if ((flags & (1 << 7)) != 0) {
- dev_dbg(di->dev, "negative current!\n");
- return -curr;
+
+ if (di->chip == BQ27500) {
+ /* bq27500 returns signed value */
+ curr = (int)(s16)curr;
+ } else {
+ ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
+ if (ret < 0) {
+ dev_err(di->dev, "error reading flags\n");
+ return 0;
+ }
+ if (flags & BQ27000_FLAG_CHGS) {
+ dev_dbg(di->dev, "negative current!\n");
+ curr = -curr;
+ }
}
- return curr;
+
+ return curr * 1000;
}
/*
@@ -155,13 +172,70 @@ static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
int ret;
int rsoc = 0;
- ret = bq27x00_read(BQ27x00_REG_RSOC, &rsoc, 1, di);
+ if (di->chip == BQ27500)
+ ret = bq27x00_read(BQ27500_REG_SOC, &rsoc, 0, di);
+ else
+ ret = bq27x00_read(BQ27000_REG_RSOC, &rsoc, 1, di);
if (ret) {
dev_err(di->dev, "error reading relative State-of-Charge\n");
return ret;
}
- return rsoc >> 8;
+ return rsoc;
+}
+
+static int bq27x00_battery_status(struct bq27x00_device_info *di,
+ union power_supply_propval *val)
+{
+ int flags = 0;
+ int status;
+ int ret;
+
+ ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
+ if (ret < 0) {
+ dev_err(di->dev, "error reading flags\n");
+ return ret;
+ }
+
+ if (di->chip == BQ27500) {
+ if (flags & BQ27500_FLAG_FC)
+ status = POWER_SUPPLY_STATUS_FULL;
+ else if (flags & BQ27500_FLAG_DSC)
+ status = POWER_SUPPLY_STATUS_DISCHARGING;
+ else
+ status = POWER_SUPPLY_STATUS_CHARGING;
+ } else {
+ if (flags & BQ27000_FLAG_CHGS)
+ status = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ status = POWER_SUPPLY_STATUS_DISCHARGING;
+ }
+
+ val->intval = status;
+ return 0;
+}
+
+/*
+ * Read a time register.
+ * Return < 0 if something fails.
+ */
+static int bq27x00_battery_time(struct bq27x00_device_info *di, int reg,
+ union power_supply_propval *val)
+{
+ int tval = 0;
+ int ret;
+
+ ret = bq27x00_read(reg, &tval, 0, di);
+ if (ret) {
+ dev_err(di->dev, "error reading register %02x\n", reg);
+ return ret;
+ }
+
+ if (tval == 65535)
+ return -ENODATA;
+
+ val->intval = tval * 60;
+ return 0;
}
#define to_bq27x00_device_info(x) container_of((x), \
@@ -171,9 +245,13 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
+ int ret = 0;
struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = bq27x00_battery_status(di, val);
+ break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
case POWER_SUPPLY_PROP_PRESENT:
val->intval = bq27x00_battery_voltage(di);
@@ -189,11 +267,20 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_TEMP:
val->intval = bq27x00_battery_temperature(di);
break;
+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
+ ret = bq27x00_battery_time(di, BQ27x00_REG_TTE, val);
+ break;
+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
+ ret = bq27x00_battery_time(di, BQ27x00_REG_TTECP, val);
+ break;
+ case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
+ ret = bq27x00_battery_time(di, BQ27x00_REG_TTF, val);
+ break;
default:
return -EINVAL;
}
- return 0;
+ return ret;
}
static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
@@ -206,10 +293,10 @@ static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
}
/*
- * BQ27200 specific code
+ * i2c specific code
*/
-static int bq27200_read(u8 reg, int *rt_value, int b_single,
+static int bq27x00_read_i2c(u8 reg, int *rt_value, int b_single,
struct bq27x00_device_info *di)
{
struct i2c_client *client = di->client;
@@ -238,7 +325,7 @@ static int bq27200_read(u8 reg, int *rt_value, int b_single,
err = i2c_transfer(client->adapter, msg, 1);
if (err >= 0) {
if (!b_single)
- *rt_value = get_unaligned_be16(data);
+ *rt_value = get_unaligned_le16(data);
else
*rt_value = data[0];
@@ -248,7 +335,7 @@ static int bq27200_read(u8 reg, int *rt_value, int b_single,
return err;
}
-static int bq27200_battery_probe(struct i2c_client *client,
+static int bq27x00_battery_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
char *name;
@@ -267,7 +354,7 @@ static int bq27200_battery_probe(struct i2c_client *client,
if (retval < 0)
return retval;
- name = kasprintf(GFP_KERNEL, "bq27200-%d", num);
+ name = kasprintf(GFP_KERNEL, "%s-%d", id->name, num);
if (!name) {
dev_err(&client->dev, "failed to allocate device name\n");
retval = -ENOMEM;
@@ -281,6 +368,7 @@ static int bq27200_battery_probe(struct i2c_client *client,
goto batt_failed_2;
}
di->id = num;
+ di->chip = id->driver_data;
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
if (!bus) {
@@ -293,7 +381,7 @@ static int bq27200_battery_probe(struct i2c_client *client,
i2c_set_clientdata(client, di);
di->dev = &client->dev;
di->bat.name = name;
- bus->read = &bq27200_read;
+ bus->read = &bq27x00_read_i2c;
di->bus = bus;
di->client = client;
@@ -323,7 +411,7 @@ batt_failed_1:
return retval;
}
-static int bq27200_battery_remove(struct i2c_client *client)
+static int bq27x00_battery_remove(struct i2c_client *client)
{
struct bq27x00_device_info *di = i2c_get_clientdata(client);
@@ -344,27 +432,28 @@ static int bq27200_battery_remove(struct i2c_client *client)
* Module stuff
*/
-static const struct i2c_device_id bq27200_id[] = {
- { "bq27200", 0 },
+static const struct i2c_device_id bq27x00_id[] = {
+ { "bq27200", BQ27000 }, /* bq27200 is same as bq27000, but with i2c */
+ { "bq27500", BQ27500 },
{},
};
-static struct i2c_driver bq27200_battery_driver = {
+static struct i2c_driver bq27x00_battery_driver = {
.driver = {
- .name = "bq27200-battery",
+ .name = "bq27x00-battery",
},
- .probe = bq27200_battery_probe,
- .remove = bq27200_battery_remove,
- .id_table = bq27200_id,
+ .probe = bq27x00_battery_probe,
+ .remove = bq27x00_battery_remove,
+ .id_table = bq27x00_id,
};
static int __init bq27x00_battery_init(void)
{
int ret;
- ret = i2c_add_driver(&bq27200_battery_driver);
+ ret = i2c_add_driver(&bq27x00_battery_driver);
if (ret)
- printk(KERN_ERR "Unable to register BQ27200 driver\n");
+ printk(KERN_ERR "Unable to register BQ27x00 driver\n");
return ret;
}
@@ -372,7 +461,7 @@ module_init(bq27x00_battery_init);
static void __exit bq27x00_battery_exit(void)
{
- i2c_del_driver(&bq27200_battery_driver);
+ i2c_del_driver(&bq27x00_battery_driver);
}
module_exit(bq27x00_battery_exit);
diff --git a/drivers/power/da9030_battery.c b/drivers/power/da9030_battery.c
index 3364198134a1..a2e71f7b27fb 100644
--- a/drivers/power/da9030_battery.c
+++ b/drivers/power/da9030_battery.c
@@ -509,7 +509,7 @@ static int da9030_battery_probe(struct platform_device *pdev)
charger->master = pdev->dev.parent;
- /* 10 seconds between monotor runs unless platfrom defines other
+ /* 10 seconds between monitor runs unless platform defines other
interval */
charger->interval = msecs_to_jiffies(
(pdata->batmon_interval ? : 10) * 1000);
diff --git a/drivers/power/max8925_power.c b/drivers/power/max8925_power.c
new file mode 100644
index 000000000000..a1b4410544d7
--- /dev/null
+++ b/drivers/power/max8925_power.c
@@ -0,0 +1,534 @@
+/*
+ * Battery driver for Maxim MAX8925
+ *
+ * Copyright (c) 2009-2010 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/max8925.h>
+
+/* registers in GPM */
+#define MAX8925_OUT5VEN 0x54
+#define MAX8925_OUT3VEN 0x58
+#define MAX8925_CHG_CNTL1 0x7c
+
+/* bits definition */
+#define MAX8925_CHG_STAT_VSYSLOW (1 << 0)
+#define MAX8925_CHG_STAT_MODE_MASK (3 << 2)
+#define MAX8925_CHG_STAT_EN_MASK (1 << 4)
+#define MAX8925_CHG_MBDET (1 << 1)
+#define MAX8925_CHG_AC_RANGE_MASK (3 << 6)
+
+/* registers in ADC */
+#define MAX8925_ADC_RES_CNFG1 0x06
+#define MAX8925_ADC_AVG_CNFG1 0x07
+#define MAX8925_ADC_ACQ_CNFG1 0x08
+#define MAX8925_ADC_ACQ_CNFG2 0x09
+/* 2 bytes registers in below. MSB is 1st, LSB is 2nd. */
+#define MAX8925_ADC_AUX2 0x62
+#define MAX8925_ADC_VCHG 0x64
+#define MAX8925_ADC_VBBATT 0x66
+#define MAX8925_ADC_VMBATT 0x68
+#define MAX8925_ADC_ISNS 0x6a
+#define MAX8925_ADC_THM 0x6c
+#define MAX8925_ADC_TDIE 0x6e
+#define MAX8925_CMD_AUX2 0xc8
+#define MAX8925_CMD_VCHG 0xd0
+#define MAX8925_CMD_VBBATT 0xd8
+#define MAX8925_CMD_VMBATT 0xe0
+#define MAX8925_CMD_ISNS 0xe8
+#define MAX8925_CMD_THM 0xf0
+#define MAX8925_CMD_TDIE 0xf8
+
+enum {
+ MEASURE_AUX2,
+ MEASURE_VCHG,
+ MEASURE_VBBATT,
+ MEASURE_VMBATT,
+ MEASURE_ISNS,
+ MEASURE_THM,
+ MEASURE_TDIE,
+ MEASURE_MAX,
+};
+
+struct max8925_power_info {
+ struct max8925_chip *chip;
+ struct i2c_client *gpm;
+ struct i2c_client *adc;
+
+ struct power_supply ac;
+ struct power_supply usb;
+ struct power_supply battery;
+ int irq_base;
+ unsigned ac_online:1;
+ unsigned usb_online:1;
+ unsigned bat_online:1;
+ unsigned chg_mode:2;
+ unsigned batt_detect:1; /* detecing MB by ID pin */
+ unsigned topoff_threshold:2;
+ unsigned fast_charge:3;
+
+ int (*set_charger) (int);
+};
+
+static int __set_charger(struct max8925_power_info *info, int enable)
+{
+ struct max8925_chip *chip = info->chip;
+ if (enable) {
+ /* enable charger in platform */
+ if (info->set_charger)
+ info->set_charger(1);
+ /* enable charger */
+ max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 0);
+ } else {
+ /* disable charge */
+ max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7);
+ if (info->set_charger)
+ info->set_charger(0);
+ }
+ dev_dbg(chip->dev, "%s\n", (enable) ? "Enable charger"
+ : "Disable charger");
+ return 0;
+}
+
+static irqreturn_t max8925_charger_handler(int irq, void *data)
+{
+ struct max8925_power_info *info = (struct max8925_power_info *)data;
+ struct max8925_chip *chip = info->chip;
+
+ switch (irq - chip->irq_base) {
+ case MAX8925_IRQ_VCHG_DC_R:
+ info->ac_online = 1;
+ __set_charger(info, 1);
+ dev_dbg(chip->dev, "Adapter inserted\n");
+ break;
+ case MAX8925_IRQ_VCHG_DC_F:
+ info->ac_online = 0;
+ __set_charger(info, 0);
+ dev_dbg(chip->dev, "Adapter is removal\n");
+ break;
+ case MAX8925_IRQ_VCHG_USB_R:
+ info->usb_online = 1;
+ __set_charger(info, 1);
+ dev_dbg(chip->dev, "USB inserted\n");
+ break;
+ case MAX8925_IRQ_VCHG_USB_F:
+ info->usb_online = 0;
+ __set_charger(info, 0);
+ dev_dbg(chip->dev, "USB is removal\n");
+ break;
+ case MAX8925_IRQ_VCHG_THM_OK_F:
+ /* Battery is not ready yet */
+ dev_dbg(chip->dev, "Battery temperature is out of range\n");
+ case MAX8925_IRQ_VCHG_DC_OVP:
+ dev_dbg(chip->dev, "Error detection\n");
+ __set_charger(info, 0);
+ break;
+ case MAX8925_IRQ_VCHG_THM_OK_R:
+ /* Battery is ready now */
+ dev_dbg(chip->dev, "Battery temperature is in range\n");
+ break;
+ case MAX8925_IRQ_VCHG_SYSLOW_R:
+ /* VSYS is low */
+ dev_info(chip->dev, "Sys power is too low\n");
+ break;
+ case MAX8925_IRQ_VCHG_SYSLOW_F:
+ dev_dbg(chip->dev, "Sys power is above low threshold\n");
+ break;
+ case MAX8925_IRQ_VCHG_DONE:
+ __set_charger(info, 0);
+ dev_dbg(chip->dev, "Charging is done\n");
+ break;
+ case MAX8925_IRQ_VCHG_TOPOFF:
+ dev_dbg(chip->dev, "Charging in top-off mode\n");
+ break;
+ case MAX8925_IRQ_VCHG_TMR_FAULT:
+ __set_charger(info, 0);
+ dev_dbg(chip->dev, "Safe timer is expired\n");
+ break;
+ case MAX8925_IRQ_VCHG_RST:
+ __set_charger(info, 0);
+ dev_dbg(chip->dev, "Charger is reset\n");
+ break;
+ }
+ return IRQ_HANDLED;
+}
+
+static int start_measure(struct max8925_power_info *info, int type)
+{
+ unsigned char buf[2] = {0, 0};
+ int meas_reg = 0, ret;
+
+ switch (type) {
+ case MEASURE_VCHG:
+ meas_reg = MAX8925_ADC_VCHG;
+ break;
+ case MEASURE_VBBATT:
+ meas_reg = MAX8925_ADC_VBBATT;
+ break;
+ case MEASURE_VMBATT:
+ meas_reg = MAX8925_ADC_VMBATT;
+ break;
+ case MEASURE_ISNS:
+ meas_reg = MAX8925_ADC_ISNS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ max8925_bulk_read(info->adc, meas_reg, 2, buf);
+ ret = (buf[0] << 4) | (buf[1] >> 4);
+
+ return ret;
+}
+
+static int max8925_ac_get_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent);
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = info->ac_online;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ if (info->ac_online) {
+ ret = start_measure(info, MEASURE_VCHG);
+ if (ret >= 0) {
+ val->intval = ret << 1; /* unit is mV */
+ goto out;
+ }
+ }
+ ret = -ENODATA;
+ break;
+ default:
+ ret = -ENODEV;
+ break;
+ }
+out:
+ return ret;
+}
+
+static enum power_supply_property max8925_ac_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+static int max8925_usb_get_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent);
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = info->usb_online;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ if (info->usb_online) {
+ ret = start_measure(info, MEASURE_VCHG);
+ if (ret >= 0) {
+ val->intval = ret << 1; /* unit is mV */
+ goto out;
+ }
+ }
+ ret = -ENODATA;
+ break;
+ default:
+ ret = -ENODEV;
+ break;
+ }
+out:
+ return ret;
+}
+
+static enum power_supply_property max8925_usb_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+static int max8925_bat_get_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent);
+ long long int tmp = 0;
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = info->bat_online;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ if (info->bat_online) {
+ ret = start_measure(info, MEASURE_VMBATT);
+ if (ret >= 0) {
+ val->intval = ret << 1; /* unit is mV */
+ ret = 0;
+ break;
+ }
+ }
+ ret = -ENODATA;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ if (info->bat_online) {
+ ret = start_measure(info, MEASURE_ISNS);
+ if (ret >= 0) {
+ tmp = (long long int)ret * 6250 / 4096 - 3125;
+ ret = (int)tmp;
+ val->intval = 0;
+ if (ret > 0)
+ val->intval = ret; /* unit is mA */
+ ret = 0;
+ break;
+ }
+ }
+ ret = -ENODATA;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ if (!info->bat_online) {
+ ret = -ENODATA;
+ break;
+ }
+ ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS);
+ ret = (ret & MAX8925_CHG_STAT_MODE_MASK) >> 2;
+ switch (ret) {
+ case 1:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ break;
+ case 0:
+ case 2:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ break;
+ case 3:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ break;
+ }
+ ret = 0;
+ break;
+ case POWER_SUPPLY_PROP_STATUS:
+ if (!info->bat_online) {
+ ret = -ENODATA;
+ break;
+ }
+ ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS);
+ if (info->usb_online || info->ac_online) {
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ if (ret & MAX8925_CHG_STAT_EN_MASK)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ } else
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ ret = 0;
+ break;
+ default:
+ ret = -ENODEV;
+ break;
+ }
+ return ret;
+}
+
+static enum power_supply_property max8925_battery_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_STATUS,
+};
+
+#define REQUEST_IRQ(_irq, _name) \
+do { \
+ ret = request_threaded_irq(chip->irq_base + _irq, NULL, \
+ max8925_charger_handler, \
+ IRQF_ONESHOT, _name, info); \
+ if (ret) \
+ dev_err(chip->dev, "Failed to request IRQ #%d: %d\n", \
+ _irq, ret); \
+} while (0)
+
+static __devinit int max8925_init_charger(struct max8925_chip *chip,
+ struct max8925_power_info *info)
+{
+ int ret;
+
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_OVP, "ac-ovp");
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_F, "ac-remove");
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_R, "ac-insert");
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_OVP, "usb-ovp");
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_F, "usb-remove");
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_R, "usb-insert");
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_R, "batt-temp-in-range");
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_F, "batt-temp-out-range");
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_F, "vsys-high");
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_R, "vsys-low");
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_RST, "charger-reset");
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_DONE, "charger-done");
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_TOPOFF, "charger-topoff");
+ REQUEST_IRQ(MAX8925_IRQ_VCHG_TMR_FAULT, "charger-timer-expire");
+
+ info->ac_online = 0;
+ info->usb_online = 0;
+ info->bat_online = 0;
+ ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS);
+ if (ret >= 0) {
+ /*
+ * If battery detection is enabled, ID pin of battery is
+ * connected to MBDET pin of MAX8925. It could be used to
+ * detect battery presence.
+ * Otherwise, we have to assume that battery is always on.
+ */
+ if (info->batt_detect)
+ info->bat_online = (ret & MAX8925_CHG_MBDET) ? 0 : 1;
+ else
+ info->bat_online = 1;
+ if (ret & MAX8925_CHG_AC_RANGE_MASK)
+ info->ac_online = 1;
+ else
+ info->ac_online = 0;
+ }
+ /* disable charge */
+ max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7);
+ /* set charging current in charge topoff mode */
+ max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 3 << 5,
+ info->topoff_threshold << 5);
+ /* set charing current in fast charge mode */
+ max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 7, info->fast_charge);
+
+ return 0;
+}
+
+static __devexit int max8925_deinit_charger(struct max8925_power_info *info)
+{
+ struct max8925_chip *chip = info->chip;
+ int irq;
+
+ irq = chip->irq_base + MAX8925_IRQ_VCHG_DC_OVP;
+ for (; irq <= chip->irq_base + MAX8925_IRQ_VCHG_TMR_FAULT; irq++)
+ free_irq(irq, info);
+
+ return 0;
+}
+
+static __devinit int max8925_power_probe(struct platform_device *pdev)
+{
+ struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct max8925_platform_data *max8925_pdata;
+ struct max8925_power_pdata *pdata = NULL;
+ struct max8925_power_info *info;
+ int ret;
+
+ if (pdev->dev.parent->platform_data) {
+ max8925_pdata = pdev->dev.parent->platform_data;
+ pdata = max8925_pdata->power;
+ }
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "platform data isn't assigned to "
+ "power supply\n");
+ return -EINVAL;
+ }
+
+ info = kzalloc(sizeof(struct max8925_power_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->chip = chip;
+ info->gpm = chip->i2c;
+ info->adc = chip->adc;
+
+ info->ac.name = "max8925-ac";
+ info->ac.type = POWER_SUPPLY_TYPE_MAINS;
+ info->ac.properties = max8925_ac_props;
+ info->ac.num_properties = ARRAY_SIZE(max8925_ac_props);
+ info->ac.get_property = max8925_ac_get_prop;
+ ret = power_supply_register(&pdev->dev, &info->ac);
+ if (ret)
+ goto out;
+ info->ac.dev->parent = &pdev->dev;
+
+ info->usb.name = "max8925-usb";
+ info->usb.type = POWER_SUPPLY_TYPE_USB;
+ info->usb.properties = max8925_usb_props;
+ info->usb.num_properties = ARRAY_SIZE(max8925_usb_props);
+ info->usb.get_property = max8925_usb_get_prop;
+ ret = power_supply_register(&pdev->dev, &info->usb);
+ if (ret)
+ goto out_usb;
+ info->usb.dev->parent = &pdev->dev;
+
+ info->battery.name = "max8925-battery";
+ info->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ info->battery.properties = max8925_battery_props;
+ info->battery.num_properties = ARRAY_SIZE(max8925_battery_props);
+ info->battery.get_property = max8925_bat_get_prop;
+ ret = power_supply_register(&pdev->dev, &info->battery);
+ if (ret)
+ goto out_battery;
+ info->battery.dev->parent = &pdev->dev;
+
+ info->batt_detect = pdata->batt_detect;
+ info->topoff_threshold = pdata->topoff_threshold;
+ info->fast_charge = pdata->fast_charge;
+ info->set_charger = pdata->set_charger;
+ dev_set_drvdata(&pdev->dev, info);
+ platform_set_drvdata(pdev, info);
+
+ max8925_init_charger(chip, info);
+ return 0;
+out_battery:
+ power_supply_unregister(&info->battery);
+out_usb:
+ power_supply_unregister(&info->ac);
+out:
+ kfree(info);
+ return ret;
+}
+
+static __devexit int max8925_power_remove(struct platform_device *pdev)
+{
+ struct max8925_power_info *info = platform_get_drvdata(pdev);
+
+ if (info) {
+ power_supply_unregister(&info->ac);
+ power_supply_unregister(&info->usb);
+ power_supply_unregister(&info->battery);
+ max8925_deinit_charger(info);
+ kfree(info);
+ }
+ return 0;
+}
+
+static struct platform_driver max8925_power_driver = {
+ .probe = max8925_power_probe,
+ .remove = __devexit_p(max8925_power_remove),
+ .driver = {
+ .name = "max8925-power",
+ },
+};
+
+static int __init max8925_power_init(void)
+{
+ return platform_driver_register(&max8925_power_driver);
+}
+module_init(max8925_power_init);
+
+static void __exit max8925_power_exit(void)
+{
+ platform_driver_unregister(&max8925_power_driver);
+}
+module_exit(max8925_power_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Power supply driver for MAX8925");
+MODULE_ALIAS("platform:max8925-power");
diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c
index ad4f071e1287..0693902d6151 100644
--- a/drivers/power/wm8350_power.c
+++ b/drivers/power/wm8350_power.c
@@ -190,7 +190,7 @@ static irqreturn_t wm8350_charger_handler(int irq, void *data)
struct wm8350_power *power = &wm8350->power;
struct wm8350_charger_policy *policy = power->policy;
- switch (irq) {
+ switch (irq - wm8350->irq_base) {
case WM8350_IRQ_CHG_BAT_FAIL:
dev_err(wm8350->dev, "battery failed\n");
break;
@@ -428,18 +428,18 @@ static void wm8350_init_charger(struct wm8350 *wm8350)
static void free_charger_irq(struct wm8350 *wm8350)
{
- wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
- wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
- wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
- wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO);
- wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END);
- wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START);
- wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
- wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
- wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
- wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
- wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
- wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350);
+ wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350);
+ wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350);
+ wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, wm8350);
}
static __devinit int wm8350_power_probe(struct platform_device *pdev)
diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c
index fa39e759a275..23eed356a854 100644
--- a/drivers/power/wm97xx_battery.c
+++ b/drivers/power/wm97xx_battery.c
@@ -26,7 +26,7 @@
static DEFINE_MUTEX(bat_lock);
static struct work_struct bat_work;
-struct mutex work_lock;
+static struct mutex work_lock;
static int bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
static struct wm97xx_batt_info *gpdata;
static enum power_supply_property *prop;
@@ -175,8 +175,14 @@ static int __devinit wm97xx_bat_probe(struct platform_device *dev)
dev_err(&dev->dev, "Do not pass platform_data through "
"wm97xx_bat_set_pdata!\n");
return -EINVAL;
- } else
- pdata = wmdata->batt_pdata;
+ }
+
+ if (!wmdata) {
+ dev_err(&dev->dev, "No platform data supplied\n");
+ return -EINVAL;
+ }
+
+ pdata = wmdata->batt_pdata;
if (dev->id != -1)
return -EINVAL;
@@ -197,7 +203,7 @@ static int __devinit wm97xx_bat_probe(struct platform_device *dev)
goto err2;
ret = request_irq(gpio_to_irq(pdata->charge_gpio),
wm97xx_chrg_irq, IRQF_DISABLED,
- "AC Detect", 0);
+ "AC Detect", dev);
if (ret)
goto err2;
props++; /* POWER_SUPPLY_PROP_STATUS */
diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig
index cc2eb8edb514..1afe4e03440f 100644
--- a/drivers/pps/Kconfig
+++ b/drivers/pps/Kconfig
@@ -30,4 +30,6 @@ config PPS_DEBUG
messages to the system log. Select this if you are having a
problem with PPS support and want to see more of what is going on.
+source drivers/pps/clients/Kconfig
+
endmenu
diff --git a/drivers/pps/Makefile b/drivers/pps/Makefile
index 19ea582f431d..98960ddd3188 100644
--- a/drivers/pps/Makefile
+++ b/drivers/pps/Makefile
@@ -4,5 +4,6 @@
pps_core-y := pps.o kapi.o sysfs.o
obj-$(CONFIG_PPS) := pps_core.o
+obj-y += clients/
ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
diff --git a/drivers/pps/clients/Kconfig b/drivers/pps/clients/Kconfig
new file mode 100644
index 000000000000..4e801bd7254f
--- /dev/null
+++ b/drivers/pps/clients/Kconfig
@@ -0,0 +1,25 @@
+#
+# PPS clients configuration
+#
+
+if PPS
+
+comment "PPS clients support"
+
+config PPS_CLIENT_KTIMER
+ tristate "Kernel timer client (Testing client, use for debug)"
+ help
+ If you say yes here you get support for a PPS debugging client
+ which uses a kernel timer to generate the PPS signal.
+
+ This driver can also be built as a module. If so, the module
+ will be called pps-ktimer.
+
+config PPS_CLIENT_LDISC
+ tristate "PPS line discipline"
+ depends on PPS
+ help
+ If you say yes here you get support for a PPS source connected
+ with the CD (Carrier Detect) pin of your serial port.
+
+endif
diff --git a/drivers/pps/clients/Makefile b/drivers/pps/clients/Makefile
new file mode 100644
index 000000000000..812c9b19b430
--- /dev/null
+++ b/drivers/pps/clients/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for PPS clients.
+#
+
+obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o
+obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o
+
+ifeq ($(CONFIG_PPS_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c
new file mode 100644
index 000000000000..e7ef5b8186d0
--- /dev/null
+++ b/drivers/pps/clients/pps-ktimer.c
@@ -0,0 +1,123 @@
+/*
+ * pps-ktimer.c -- kernel timer test client
+ *
+ *
+ * Copyright (C) 2005-2006 Rodolfo Giometti <giometti@linux.it>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/pps_kernel.h>
+
+/*
+ * Global variables
+ */
+
+static int source;
+static struct timer_list ktimer;
+
+/*
+ * The kernel timer
+ */
+
+static void pps_ktimer_event(unsigned long ptr)
+{
+ struct timespec __ts;
+ struct pps_ktime ts;
+
+ /* First of all we get the time stamp... */
+ getnstimeofday(&__ts);
+
+ pr_info("PPS event at %lu\n", jiffies);
+
+ /* ... and translate it to PPS time data struct */
+ ts.sec = __ts.tv_sec;
+ ts.nsec = __ts.tv_nsec;
+
+ pps_event(source, &ts, PPS_CAPTUREASSERT, NULL);
+
+ mod_timer(&ktimer, jiffies + HZ);
+}
+
+/*
+ * The echo function
+ */
+
+static void pps_ktimer_echo(int source, int event, void *data)
+{
+ pr_info("echo %s %s for source %d\n",
+ event & PPS_CAPTUREASSERT ? "assert" : "",
+ event & PPS_CAPTURECLEAR ? "clear" : "",
+ source);
+}
+
+/*
+ * The PPS info struct
+ */
+
+static struct pps_source_info pps_ktimer_info = {
+ .name = "ktimer",
+ .path = "",
+ .mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
+ PPS_ECHOASSERT |
+ PPS_CANWAIT | PPS_TSFMT_TSPEC,
+ .echo = pps_ktimer_echo,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Module staff
+ */
+
+static void __exit pps_ktimer_exit(void)
+{
+ del_timer_sync(&ktimer);
+ pps_unregister_source(source);
+
+ pr_info("ktimer PPS source unregistered\n");
+}
+
+static int __init pps_ktimer_init(void)
+{
+ int ret;
+
+ ret = pps_register_source(&pps_ktimer_info,
+ PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
+ if (ret < 0) {
+ printk(KERN_ERR "cannot register ktimer source\n");
+ return ret;
+ }
+ source = ret;
+
+ setup_timer(&ktimer, pps_ktimer_event, 0);
+ mod_timer(&ktimer, jiffies + HZ);
+
+ pr_info("ktimer PPS source registered at %d\n", source);
+
+ return 0;
+}
+
+module_init(pps_ktimer_init);
+module_exit(pps_ktimer_exit);
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("dummy PPS source by using a kernel timer (just for debug)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c
new file mode 100644
index 000000000000..8e1932d29fd4
--- /dev/null
+++ b/drivers/pps/clients/pps-ldisc.c
@@ -0,0 +1,154 @@
+/*
+ * pps-ldisc.c -- PPS line discipline
+ *
+ *
+ * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it>
+ *
+ * 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/module.h>
+#include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/pps_kernel.h>
+
+#define PPS_TTY_MAGIC 0x0001
+
+static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status,
+ struct timespec *ts)
+{
+ int id = (long)tty->disc_data;
+ struct timespec __ts;
+ struct pps_ktime pps_ts;
+
+ /* First of all we get the time stamp... */
+ getnstimeofday(&__ts);
+
+ /* Does caller give us a timestamp? */
+ if (ts) { /* Yes. Let's use it! */
+ pps_ts.sec = ts->tv_sec;
+ pps_ts.nsec = ts->tv_nsec;
+ } else { /* No. Do it ourself! */
+ pps_ts.sec = __ts.tv_sec;
+ pps_ts.nsec = __ts.tv_nsec;
+ }
+
+ /* Now do the PPS event report */
+ pps_event(id, &pps_ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR,
+ NULL);
+
+ pr_debug("PPS %s at %lu on source #%d\n",
+ status ? "assert" : "clear", jiffies, id);
+}
+
+static int (*alias_n_tty_open)(struct tty_struct *tty);
+
+static int pps_tty_open(struct tty_struct *tty)
+{
+ struct pps_source_info info;
+ struct tty_driver *drv = tty->driver;
+ int index = tty->index + drv->name_base;
+ int ret;
+
+ info.owner = THIS_MODULE;
+ info.dev = NULL;
+ snprintf(info.name, PPS_MAX_NAME_LEN, "%s%d", drv->driver_name, index);
+ snprintf(info.path, PPS_MAX_NAME_LEN, "/dev/%s%d", drv->name, index);
+ info.mode = PPS_CAPTUREBOTH | \
+ PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
+ PPS_CANWAIT | PPS_TSFMT_TSPEC;
+
+ ret = pps_register_source(&info, PPS_CAPTUREBOTH | \
+ PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
+ if (ret < 0) {
+ pr_err("cannot register PPS source \"%s\"\n", info.path);
+ return ret;
+ }
+ tty->disc_data = (void *)(long)ret;
+
+ /* Should open N_TTY ldisc too */
+ ret = alias_n_tty_open(tty);
+ if (ret < 0)
+ pps_unregister_source((long)tty->disc_data);
+
+ pr_info("PPS source #%d \"%s\" added\n", ret, info.path);
+
+ return 0;
+}
+
+static void (*alias_n_tty_close)(struct tty_struct *tty);
+
+static void pps_tty_close(struct tty_struct *tty)
+{
+ int id = (long)tty->disc_data;
+
+ pps_unregister_source(id);
+ alias_n_tty_close(tty);
+
+ pr_info("PPS source #%d removed\n", id);
+}
+
+static struct tty_ldisc_ops pps_ldisc_ops;
+
+/*
+ * Module stuff
+ */
+
+static int __init pps_tty_init(void)
+{
+ int err;
+
+ /* Inherit the N_TTY's ops */
+ n_tty_inherit_ops(&pps_ldisc_ops);
+
+ /* Save N_TTY's open()/close() methods */
+ alias_n_tty_open = pps_ldisc_ops.open;
+ alias_n_tty_close = pps_ldisc_ops.close;
+
+ /* Init PPS_TTY data */
+ pps_ldisc_ops.owner = THIS_MODULE;
+ pps_ldisc_ops.magic = PPS_TTY_MAGIC;
+ pps_ldisc_ops.name = "pps_tty";
+ pps_ldisc_ops.dcd_change = pps_tty_dcd_change;
+ pps_ldisc_ops.open = pps_tty_open;
+ pps_ldisc_ops.close = pps_tty_close;
+
+ err = tty_register_ldisc(N_PPS, &pps_ldisc_ops);
+ if (err)
+ pr_err("can't register PPS line discipline\n");
+ else
+ pr_info("PPS line discipline registered\n");
+
+ return err;
+}
+
+static void __exit pps_tty_cleanup(void)
+{
+ int err;
+
+ err = tty_unregister_ldisc(N_PPS);
+ if (err)
+ pr_err("can't unregister PPS line discipline\n");
+ else
+ pr_info("PPS line discipline removed\n");
+}
+
+module_init(pps_tty_init);
+module_exit(pps_tty_cleanup);
+
+MODULE_ALIAS_LDISC(N_PPS);
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("PPS TTY device driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index e82d8c9c6cda..95a689befc84 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -532,7 +532,7 @@ static void ps3av_set_videomode_packet(u32 id)
res = ps3av_cmd_avb_param(&avb_param, len);
if (res == PS3AV_STATUS_NO_SYNC_HEAD)
printk(KERN_WARNING
- "%s: Command failed. Please try your request again. \n",
+ "%s: Command failed. Please try your request again.\n",
__func__);
else if (res)
dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n");
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index 04719551381b..5fb83e2ced25 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -11,15 +11,17 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
+#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
-#include <linux/mfd/88pm8607.h>
+#include <linux/mfd/88pm860x.h>
struct pm8607_regulator_info {
struct regulator_desc desc;
- struct pm8607_chip *chip;
+ struct pm860x_chip *chip;
struct regulator_dev *regulator;
+ struct i2c_client *i2c;
int min_uV;
int max_uV;
@@ -46,7 +48,6 @@ static inline int check_range(struct pm8607_regulator_info *info,
static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
{
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
- uint8_t chip_id = info->chip->chip_id;
int ret = -EINVAL;
switch (info->desc.id) {
@@ -88,79 +89,29 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
case PM8607_ID_LDO2:
case PM8607_ID_LDO3:
case PM8607_ID_LDO9:
- switch (chip_id) {
- case PM8607_CHIP_A0:
- case PM8607_CHIP_A1:
- ret = (index < 3) ? (index * 50000 + 1800000) :
- ((index < 8) ? (index * 50000 + 2550000) :
- -EINVAL);
- break;
- case PM8607_CHIP_B0:
- ret = (index < 3) ? (index * 50000 + 1800000) :
- ((index < 7) ? (index * 50000 + 2550000) :
- 3300000);
- break;
- }
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 7) ? (index * 50000 + 2550000) :
+ 3300000);
break;
case PM8607_ID_LDO4:
- switch (chip_id) {
- case PM8607_CHIP_A0:
- case PM8607_CHIP_A1:
- ret = (index < 3) ? (index * 50000 + 1800000) :
- ((index < 8) ? (index * 50000 + 2550000) :
- -EINVAL);
- break;
- case PM8607_CHIP_B0:
- ret = (index < 3) ? (index * 50000 + 1800000) :
- ((index < 6) ? (index * 50000 + 2550000) :
- ((index == 6) ? 2900000 : 3300000));
- break;
- }
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 6) ? (index * 50000 + 2550000) :
+ ((index == 6) ? 2900000 : 3300000));
break;
case PM8607_ID_LDO6:
- switch (chip_id) {
- case PM8607_CHIP_A0:
- case PM8607_CHIP_A1:
- ret = (index < 3) ? (index * 50000 + 1800000) :
- ((index < 8) ? (index * 50000 + 2450000) :
- -EINVAL);
- break;
- case PM8607_CHIP_B0:
- ret = (index < 2) ? (index * 50000 + 1800000) :
- ((index < 7) ? (index * 50000 + 2500000) :
- 3300000);
- break;
- }
+ ret = (index < 2) ? (index * 50000 + 1800000) :
+ ((index < 7) ? (index * 50000 + 2500000) :
+ 3300000);
break;
case PM8607_ID_LDO10:
- switch (chip_id) {
- case PM8607_CHIP_A0:
- case PM8607_CHIP_A1:
- ret = (index < 3) ? (index * 50000 + 1800000) :
- ((index < 8) ? (index * 50000 + 2550000) :
- 1200000);
- break;
- case PM8607_CHIP_B0:
- ret = (index < 3) ? (index * 50000 + 1800000) :
- ((index < 7) ? (index * 50000 + 2550000) :
- ((index == 7) ? 3300000 : 1200000));
- break;
- }
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 7) ? (index * 50000 + 2550000) :
+ ((index == 7) ? 3300000 : 1200000));
break;
case PM8607_ID_LDO14:
- switch (chip_id) {
- case PM8607_CHIP_A0:
- case PM8607_CHIP_A1:
- ret = (index < 3) ? (index * 50000 + 1800000) :
- ((index < 8) ? (index * 50000 + 2550000) :
- -EINVAL);
- break;
- case PM8607_CHIP_B0:
- ret = (index < 2) ? (index * 50000 + 1800000) :
- ((index < 7) ? (index * 50000 + 2600000) :
- 3300000);
- break;
- }
+ ret = (index < 2) ? (index * 50000 + 1800000) :
+ ((index < 7) ? (index * 50000 + 2600000) :
+ 3300000);
break;
}
return ret;
@@ -169,7 +120,6 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
{
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
- uint8_t chip_id = info->chip->chip_id;
int val = -ENOENT;
int ret;
@@ -254,161 +204,77 @@ static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
case PM8607_ID_LDO2:
case PM8607_ID_LDO3:
case PM8607_ID_LDO9:
- switch (chip_id) {
- case PM8607_CHIP_A0:
- case PM8607_CHIP_A1:
- if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */
- if (min_uV <= 1800000)
- val = 0;
- else if (min_uV <= 1900000)
- val = (min_uV - 1750001) / 50000;
- else
- val = 3; /* 2700mV */
- else { /* 2700mV ~ 2900mV / 50mV */
- if (min_uV <= 2900000) {
- val = (min_uV - 2650001) / 50000;
- val += 3;
- } else
- val = -EINVAL;
- }
- break;
- case PM8607_CHIP_B0:
- if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
- if (min_uV <= 1800000)
- val = 0;
- else if (min_uV <= 1900000)
- val = (min_uV - 1750001) / 50000;
- else
- val = 3; /* 2700mV */
- } else { /* 2700mV ~ 2850mV / 50mV */
- if (min_uV <= 2850000) {
- val = (min_uV - 2650001) / 50000;
- val += 3;
- } else if (min_uV <= 3300000)
- val = 7;
- else
- val = -EINVAL;
- }
- break;
+ if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ } else { /* 2700mV ~ 2850mV / 50mV */
+ if (min_uV <= 2850000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
}
break;
case PM8607_ID_LDO4:
- switch (chip_id) {
- case PM8607_CHIP_A0:
- case PM8607_CHIP_A1:
- if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */
- if (min_uV <= 1800000)
- val = 0;
- else if (min_uV <= 1900000)
- val = (min_uV - 1750001) / 50000;
- else
- val = 3; /* 2700mV */
- else { /* 2700mV ~ 2900mV / 50mV */
- if (min_uV <= 2900000) {
- val = (min_uV - 2650001) / 50000;
- val += 3;
- } else
- val = -EINVAL;
- }
- break;
- case PM8607_CHIP_B0:
- if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
- if (min_uV <= 1800000)
- val = 0;
- else if (min_uV <= 1900000)
- val = (min_uV - 1750001) / 50000;
- else
- val = 3; /* 2700mV */
- } else { /* 2700mV ~ 2800mV / 50mV */
- if (min_uV <= 2850000) {
- val = (min_uV - 2650001) / 50000;
- val += 3;
- } else if (min_uV <= 2900000)
- val = 6;
- else if (min_uV <= 3300000)
- val = 7;
- else
- val = -EINVAL;
- }
- break;
+ if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ } else { /* 2700mV ~ 2800mV / 50mV */
+ if (min_uV <= 2850000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else if (min_uV <= 2900000)
+ val = 6;
+ else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
}
break;
case PM8607_ID_LDO6:
- switch (chip_id) {
- case PM8607_CHIP_A0:
- case PM8607_CHIP_A1:
- if (min_uV < 2600000) { /* 1800mV ~ 1900mV / 50mV */
- if (min_uV <= 1800000)
- val = 0;
- else if (min_uV <= 1900000)
- val = (min_uV - 1750001) / 50000;
- else
- val = 3; /* 2600mV */
- } else { /* 2600mV ~ 2800mV / 50mV */
- if (min_uV <= 2800000) {
- val = (min_uV - 2550001) / 50000;
- val += 3;
- } else
- val = -EINVAL;
- }
- break;
- case PM8607_CHIP_B0:
- if (min_uV < 2600000) { /* 1800mV ~ 1850mV / 50mV */
- if (min_uV <= 1800000)
- val = 0;
- else if (min_uV <= 1850000)
- val = (min_uV - 1750001) / 50000;
- else
- val = 2; /* 2600mV */
- } else { /* 2600mV ~ 2800mV / 50mV */
- if (min_uV <= 2800000) {
- val = (min_uV - 2550001) / 50000;
- val += 2;
- } else if (min_uV <= 3300000)
- val = 7;
- else
- val = -EINVAL;
- }
- break;
+ if (min_uV < 2600000) { /* 1800mV ~ 1850mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1850000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 2; /* 2600mV */
+ } else { /* 2600mV ~ 2800mV / 50mV */
+ if (min_uV <= 2800000) {
+ val = (min_uV - 2550001) / 50000;
+ val += 2;
+ } else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
}
break;
case PM8607_ID_LDO14:
- switch (chip_id) {
- case PM8607_CHIP_A0:
- case PM8607_CHIP_A1:
- if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
- if (min_uV <= 1800000)
- val = 0;
- else if (min_uV <= 1900000)
- val = (min_uV - 1750001) / 50000;
- else
- val = 3; /* 2700mV */
- } else { /* 2700mV ~ 2900mV / 50mV */
- if (min_uV <= 2900000) {
- val = (min_uV - 2650001) / 50000;
- val += 3;
- } else
- val = -EINVAL;
- }
- break;
- case PM8607_CHIP_B0:
- if (min_uV < 2700000) { /* 1800mV ~ 1850mV / 50mV */
- if (min_uV <= 1800000)
- val = 0;
- else if (min_uV <= 1850000)
- val = (min_uV - 1750001) / 50000;
- else
- val = 2; /* 2700mV */
- } else { /* 2700mV ~ 2900mV / 50mV */
- if (min_uV <= 2900000) {
- val = (min_uV - 2650001) / 50000;
- val += 2;
- } else if (min_uV <= 3300000)
- val = 7;
- else
- val = -EINVAL;
- }
- break;
+ if (min_uV < 2700000) { /* 1800mV ~ 1850mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1850000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 2; /* 2700mV */
+ } else { /* 2700mV ~ 2900mV / 50mV */
+ if (min_uV <= 2900000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 2;
+ } else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
}
break;
}
@@ -428,7 +294,6 @@ static int pm8607_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
- struct pm8607_chip *chip = info->chip;
uint8_t val, mask;
int ret;
@@ -443,13 +308,13 @@ static int pm8607_set_voltage(struct regulator_dev *rdev,
val = (uint8_t)(ret << info->vol_shift);
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
- ret = pm8607_set_bits(chip, info->vol_reg, mask, val);
+ ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, val);
if (ret)
return ret;
switch (info->desc.id) {
case PM8607_ID_BUCK1:
case PM8607_ID_BUCK3:
- ret = pm8607_set_bits(chip, info->update_reg,
+ ret = pm860x_set_bits(info->i2c, info->update_reg,
1 << info->update_bit,
1 << info->update_bit);
break;
@@ -460,11 +325,10 @@ static int pm8607_set_voltage(struct regulator_dev *rdev,
static int pm8607_get_voltage(struct regulator_dev *rdev)
{
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
- struct pm8607_chip *chip = info->chip;
uint8_t val, mask;
int ret;
- ret = pm8607_reg_read(chip, info->vol_reg);
+ ret = pm860x_reg_read(info->i2c, info->vol_reg);
if (ret < 0)
return ret;
@@ -477,9 +341,8 @@ static int pm8607_get_voltage(struct regulator_dev *rdev)
static int pm8607_enable(struct regulator_dev *rdev)
{
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
- struct pm8607_chip *chip = info->chip;
- return pm8607_set_bits(chip, info->enable_reg,
+ return pm860x_set_bits(info->i2c, info->enable_reg,
1 << info->enable_bit,
1 << info->enable_bit);
}
@@ -487,19 +350,17 @@ static int pm8607_enable(struct regulator_dev *rdev)
static int pm8607_disable(struct regulator_dev *rdev)
{
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
- struct pm8607_chip *chip = info->chip;
- return pm8607_set_bits(chip, info->enable_reg,
+ return pm860x_set_bits(info->i2c, info->enable_reg,
1 << info->enable_bit, 0);
}
static int pm8607_is_enabled(struct regulator_dev *rdev)
{
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
- struct pm8607_chip *chip = info->chip;
int ret;
- ret = pm8607_reg_read(chip, info->enable_reg);
+ ret = pm860x_reg_read(info->i2c, info->enable_reg);
if (ret < 0)
return ret;
@@ -589,8 +450,8 @@ static inline struct pm8607_regulator_info *find_regulator_info(int id)
static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
{
- struct pm8607_chip *chip = dev_get_drvdata(pdev->dev.parent);
- struct pm8607_platform_data *pdata = chip->dev->platform_data;
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm860x_platform_data *pdata = chip->dev->platform_data;
struct pm8607_regulator_info *info = NULL;
info = find_regulator_info(pdev->id);
@@ -599,6 +460,7 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
return -EINVAL;
}
+ info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
info->chip = chip;
info->regulator = regulator_register(&info->desc, &pdev->dev,
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 262f62eec837..04f2e085116a 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -27,6 +27,17 @@ config REGULATOR_DEBUG
help
Say yes here to enable debugging support.
+config REGULATOR_DUMMY
+ bool "Provide a dummy regulator if regulator lookups fail"
+ help
+ If this option is enabled then when a regulator lookup fails
+ and the board has not specified that it has provided full
+ constraints then the regulator core will provide an always
+ enabled dummy regulator will be provided, allowing consumer
+ drivers to continue.
+
+ A warning will be generated when this substitution is done.
+
config REGULATOR_FIXED_VOLTAGE
tristate "Fixed voltage regulator support"
help
@@ -69,6 +80,13 @@ config REGULATOR_MAX1586
regulator via I2C bus. The provided regulator is suitable
for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
+config REGULATOR_MAX8649
+ tristate "Maxim 8649 voltage regulator"
+ depends on I2C
+ help
+ This driver controls a Maxim 8649 voltage output regulator via
+ I2C bus.
+
config REGULATOR_MAX8660
tristate "Maxim 8660/8661 voltage regulator"
depends on I2C
@@ -76,6 +94,12 @@ config REGULATOR_MAX8660
This driver controls a Maxim 8660/8661 voltage output
regulator via I2C bus.
+config REGULATOR_MAX8925
+ tristate "Maxim MAX8925 Power Management IC"
+ depends on MFD_MAX8925
+ help
+ Say y here to support the voltage regulaltor of Maxim MAX8925 PMIC.
+
config REGULATOR_TWL4030
bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC"
depends on TWL4030_CORE
@@ -91,19 +115,26 @@ config REGULATOR_WM831X
of PMIC devices.
config REGULATOR_WM8350
- tristate "Wolfson Microelectroncis WM8350 AudioPlus PMIC"
+ tristate "Wolfson Microelectronics WM8350 AudioPlus PMIC"
depends on MFD_WM8350
help
This driver provides support for the voltage and current regulators
of the WM8350 AudioPlus PMIC.
config REGULATOR_WM8400
- tristate "Wolfson Microelectroncis WM8400 AudioPlus PMIC"
+ tristate "Wolfson Microelectronics WM8400 AudioPlus PMIC"
depends on MFD_WM8400
help
This driver provides support for the voltage regulators of the
WM8400 AudioPlus PMIC.
+config REGULATOR_WM8994
+ tristate "Wolfson Microelectronics WM8994 CODEC"
+ depends on MFD_WM8994
+ help
+ This driver provides support for the voltage regulators on the
+ WM8994 CODEC.
+
config REGULATOR_DA903X
tristate "Support regulators on Dialog Semiconductor DA9030/DA9034 PMIC"
depends on PMIC_DA903X
@@ -166,7 +197,7 @@ config REGULATOR_TPS6507X
config REGULATOR_88PM8607
bool "Marvell 88PM8607 Power regulators"
- depends on MFD_88PM8607=y
+ depends on MFD_88PM860X=y
help
This driver supports 88PM8607 voltage regulator chips.
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index b3c806c79415..4e7feece22d5 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -9,15 +9,19 @@ obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
+obj-$(CONFIG_REGULATOR_DUMMY) += dummy.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
+obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
+obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
+obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index b349db4504b7..7de950959ed2 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -561,7 +561,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
* for all the different regulators.
*/
-static int __init ab3100_regulators_probe(struct platform_device *pdev)
+static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
{
struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
struct ab3100 *ab3100 = platform_get_drvdata(pdev);
@@ -641,7 +641,7 @@ static int __init ab3100_regulators_probe(struct platform_device *pdev)
return 0;
}
-static int __exit ab3100_regulators_remove(struct platform_device *pdev)
+static int __devexit ab3100_regulators_remove(struct platform_device *pdev)
{
int i;
@@ -659,7 +659,7 @@ static struct platform_driver ab3100_regulators_driver = {
.owner = THIS_MODULE,
},
.probe = ab3100_regulators_probe,
- .remove = __exit_p(ab3100_regulators_remove),
+ .remove = __devexit_p(ab3100_regulators_remove),
};
static __init int ab3100_regulators_init(void)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 686ef270ecf7..c7bbe30010f7 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -19,10 +19,13 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/suspend.h>
+#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include "dummy.h"
+
#define REGULATOR_VERSION "0.5"
static DEFINE_MUTEX(regulator_list_mutex);
@@ -661,7 +664,7 @@ static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state)
static void print_constraints(struct regulator_dev *rdev)
{
struct regulation_constraints *constraints = rdev->constraints;
- char buf[80];
+ char buf[80] = "";
int count = 0;
int ret;
@@ -1084,6 +1087,13 @@ overflow_err:
return NULL;
}
+static int _regulator_get_enable_time(struct regulator_dev *rdev)
+{
+ if (!rdev->desc->ops->enable_time)
+ return 0;
+ return rdev->desc->ops->enable_time(rdev);
+}
+
/* Internal regulator request function */
static struct regulator *_regulator_get(struct device *dev, const char *id,
int exclusive)
@@ -1115,6 +1125,22 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
goto found;
}
}
+
+#ifdef CONFIG_REGULATOR_DUMMY
+ if (!devname)
+ devname = "deviceless";
+
+ /* If the board didn't flag that it was fully constrained then
+ * substitute in a dummy regulator so consumers can continue.
+ */
+ if (!has_full_constraints) {
+ pr_warning("%s supply %s not found, using dummy regulator\n",
+ devname, id);
+ rdev = dummy_regulator_rdev;
+ goto found;
+ }
+#endif
+
mutex_unlock(&regulator_list_mutex);
return regulator;
@@ -1251,7 +1277,7 @@ static int _regulator_can_change_status(struct regulator_dev *rdev)
/* locks held by regulator_enable() */
static int _regulator_enable(struct regulator_dev *rdev)
{
- int ret;
+ int ret, delay;
/* do we need to enable the supply regulator first */
if (rdev->supply) {
@@ -1275,13 +1301,34 @@ static int _regulator_enable(struct regulator_dev *rdev)
if (!_regulator_can_change_status(rdev))
return -EPERM;
- if (rdev->desc->ops->enable) {
- ret = rdev->desc->ops->enable(rdev);
- if (ret < 0)
- return ret;
- } else {
+ if (!rdev->desc->ops->enable)
return -EINVAL;
+
+ /* Query before enabling in case configuration
+ * dependant. */
+ ret = _regulator_get_enable_time(rdev);
+ if (ret >= 0) {
+ delay = ret;
+ } else {
+ printk(KERN_WARNING
+ "%s: enable_time() failed for %s: %d\n",
+ __func__, rdev_get_name(rdev),
+ ret);
+ delay = 0;
}
+
+ /* Allow the regulator to ramp; it would be useful
+ * to extend this for bulk operations so that the
+ * regulators can ramp together. */
+ ret = rdev->desc->ops->enable(rdev);
+ if (ret < 0)
+ return ret;
+
+ if (delay >= 1000)
+ mdelay(delay / 1000);
+ else if (delay)
+ udelay(delay);
+
} else if (ret < 0) {
printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n",
__func__, rdev_get_name(rdev), ret);
@@ -1341,6 +1388,9 @@ static int _regulator_disable(struct regulator_dev *rdev)
__func__, rdev_get_name(rdev));
return ret;
}
+
+ _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
+ NULL);
}
/* decrease our supplies ref count and disable if required */
@@ -1399,8 +1449,8 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
return ret;
}
/* notify other consumers that power has been forced off */
- _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE,
- NULL);
+ _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
+ REGULATOR_EVENT_DISABLE, NULL);
}
/* decrease our supplies ref count and disable if required */
@@ -1434,9 +1484,9 @@ EXPORT_SYMBOL_GPL(regulator_force_disable);
static int _regulator_is_enabled(struct regulator_dev *rdev)
{
- /* sanity check */
+ /* If we don't know then assume that the regulator is always on */
if (!rdev->desc->ops->is_enabled)
- return -EINVAL;
+ return 1;
return rdev->desc->ops->is_enabled(rdev);
}
@@ -2451,8 +2501,15 @@ EXPORT_SYMBOL_GPL(regulator_get_init_drvdata);
static int __init regulator_init(void)
{
+ int ret;
+
printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION);
- return class_register(&regulator_class);
+
+ ret = class_register(&regulator_class);
+
+ regulator_dummy_init();
+
+ return ret;
}
/* init early to allow our consumers to complete system booting */
diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c
new file mode 100644
index 000000000000..c7410bde7b5d
--- /dev/null
+++ b/drivers/regulator/dummy.c
@@ -0,0 +1,66 @@
+/*
+ * dummy.c
+ *
+ * Copyright 2010 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This is useful for systems with mixed controllable and
+ * non-controllable regulators, as well as for allowing testing on
+ * systems with no controllable regulators.
+ */
+
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#include "dummy.h"
+
+struct regulator_dev *dummy_regulator_rdev;
+
+static struct regulator_init_data dummy_initdata;
+
+static struct regulator_ops dummy_ops;
+
+static struct regulator_desc dummy_desc = {
+ .name = "dummy",
+ .id = -1,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .ops = &dummy_ops,
+};
+
+static struct platform_device *dummy_pdev;
+
+void __init regulator_dummy_init(void)
+{
+ int ret;
+
+ dummy_pdev = platform_device_alloc("reg-dummy", -1);
+ if (!dummy_pdev) {
+ pr_err("Failed to allocate dummy regulator device\n");
+ return;
+ }
+
+ ret = platform_device_add(dummy_pdev);
+ if (ret != 0) {
+ pr_err("Failed to register dummy regulator device: %d\n", ret);
+ platform_device_put(dummy_pdev);
+ return;
+ }
+
+ dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
+ &dummy_initdata, NULL);
+ if (IS_ERR(dummy_regulator_rdev)) {
+ ret = PTR_ERR(dummy_regulator_rdev);
+ pr_err("Failed to register regulator: %d\n", ret);
+ platform_device_unregister(dummy_pdev);
+ return;
+ }
+}
diff --git a/drivers/regulator/dummy.h b/drivers/regulator/dummy.h
new file mode 100644
index 000000000000..3921c0e24249
--- /dev/null
+++ b/drivers/regulator/dummy.h
@@ -0,0 +1,31 @@
+/*
+ * dummy.h
+ *
+ * Copyright 2010 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This is useful for systems with mixed controllable and
+ * non-controllable regulators, as well as for allowing testing on
+ * systems with no controllable regulators.
+ */
+
+#ifndef _DUMMY_H
+#define _DUMMY_H
+
+struct regulator_dev;
+
+extern struct regulator_dev *dummy_regulator_rdev;
+
+#ifdef CONFIG_REGULATOR_DUMMY
+void __init regulator_dummy_init(void);
+#else
+static inline void regulator_dummy_init(void) { }
+#endif
+
+#endif
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index f9f516a3028a..d11f7622430b 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -24,14 +24,16 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/fixed.h>
#include <linux/gpio.h>
+#include <linux/delay.h>
struct fixed_voltage_data {
struct regulator_desc desc;
struct regulator_dev *dev;
int microvolts;
int gpio;
- unsigned enable_high:1;
- unsigned is_enabled:1;
+ unsigned startup_delay;
+ bool enable_high;
+ bool is_enabled;
};
static int fixed_voltage_is_enabled(struct regulator_dev *dev)
@@ -47,7 +49,7 @@ static int fixed_voltage_enable(struct regulator_dev *dev)
if (gpio_is_valid(data->gpio)) {
gpio_set_value_cansleep(data->gpio, data->enable_high);
- data->is_enabled = 1;
+ data->is_enabled = true;
}
return 0;
@@ -59,12 +61,19 @@ static int fixed_voltage_disable(struct regulator_dev *dev)
if (gpio_is_valid(data->gpio)) {
gpio_set_value_cansleep(data->gpio, !data->enable_high);
- data->is_enabled = 0;
+ data->is_enabled = false;
}
return 0;
}
+static int fixed_voltage_enable_time(struct regulator_dev *dev)
+{
+ struct fixed_voltage_data *data = rdev_get_drvdata(dev);
+
+ return data->startup_delay;
+}
+
static int fixed_voltage_get_voltage(struct regulator_dev *dev)
{
struct fixed_voltage_data *data = rdev_get_drvdata(dev);
@@ -87,11 +96,12 @@ static struct regulator_ops fixed_voltage_ops = {
.is_enabled = fixed_voltage_is_enabled,
.enable = fixed_voltage_enable,
.disable = fixed_voltage_disable,
+ .enable_time = fixed_voltage_enable_time,
.get_voltage = fixed_voltage_get_voltage,
.list_voltage = fixed_voltage_list_voltage,
};
-static int regulator_fixed_voltage_probe(struct platform_device *pdev)
+static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
{
struct fixed_voltage_config *config = pdev->dev.platform_data;
struct fixed_voltage_data *drvdata;
@@ -117,6 +127,7 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
drvdata->microvolts = config->microvolts;
drvdata->gpio = config->gpio;
+ drvdata->startup_delay = config->startup_delay;
if (gpio_is_valid(config->gpio)) {
drvdata->enable_high = config->enable_high;
@@ -163,7 +174,7 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
/* Regulator without GPIO control is considered
* always enabled
*/
- drvdata->is_enabled = 1;
+ drvdata->is_enabled = true;
}
drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev,
@@ -191,7 +202,7 @@ err:
return ret;
}
-static int regulator_fixed_voltage_remove(struct platform_device *pdev)
+static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev)
{
struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev);
@@ -205,10 +216,11 @@ static int regulator_fixed_voltage_remove(struct platform_device *pdev)
}
static struct platform_driver regulator_fixed_voltage_driver = {
- .probe = regulator_fixed_voltage_probe,
- .remove = regulator_fixed_voltage_remove,
+ .probe = reg_fixed_voltage_probe,
+ .remove = __devexit_p(reg_fixed_voltage_remove),
.driver = {
.name = "reg-fixed-voltage",
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 76d08c282f9c..f5532ed79272 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -54,7 +54,7 @@ static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val);
#define LP3971_BUCK2_BASE 0x29
#define LP3971_BUCK3_BASE 0x32
-const static int buck_base_addr[] = {
+static const int buck_base_addr[] = {
LP3971_BUCK1_BASE,
LP3971_BUCK2_BASE,
LP3971_BUCK3_BASE,
@@ -63,7 +63,7 @@ const static int buck_base_addr[] = {
#define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x])
#define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1)
-const static int buck_voltage_map[] = {
+static const int buck_voltage_map[] = {
0, 800, 850, 900, 950, 1000, 1050, 1100,
1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,
1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800,
@@ -96,17 +96,17 @@ const static int buck_voltage_map[] = {
#define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2)
#define LDO_VOL_CONTR_MASK 0x0f
-const static int ldo45_voltage_map[] = {
+static const int ldo45_voltage_map[] = {
1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,
1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,
};
-const static int ldo123_voltage_map[] = {
+static const int ldo123_voltage_map[] = {
1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,
2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,
};
-const static int *ldo_voltage_map[] = {
+static const int *ldo_voltage_map[] = {
ldo123_voltage_map, /* LDO1 */
ldo123_voltage_map, /* LDO2 */
ldo123_voltage_map, /* LDO3 */
@@ -183,7 +183,7 @@ static int lp3971_ldo_set_voltage(struct regulator_dev *dev,
if (vol_map[val] >= min_vol)
break;
- if (vol_map[val] > max_vol)
+ if (val > LDO_VOL_MAX_IDX || vol_map[val] > max_vol)
return -EINVAL;
return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo),
@@ -272,7 +272,7 @@ static int lp3971_dcdc_set_voltage(struct regulator_dev *dev,
if (vol_map[val] >= min_vol)
break;
- if (vol_map[val] > max_vol)
+ if (val > BUCK_TARGET_VOL_MAX_IDX || vol_map[val] > max_vol)
return -EINVAL;
ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck),
@@ -431,20 +431,20 @@ static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val)
return ret;
}
-static int setup_regulators(struct lp3971 *lp3971,
- struct lp3971_platform_data *pdata)
+static int __devinit setup_regulators(struct lp3971 *lp3971,
+ struct lp3971_platform_data *pdata)
{
int i, err;
- int num_regulators = pdata->num_regulators;
- lp3971->num_regulators = num_regulators;
- lp3971->rdev = kzalloc(sizeof(struct regulator_dev *) * num_regulators,
- GFP_KERNEL);
+
+ lp3971->num_regulators = pdata->num_regulators;
+ lp3971->rdev = kcalloc(pdata->num_regulators,
+ sizeof(struct regulator_dev *), GFP_KERNEL);
/* Instantiate the regulators */
- for (i = 0; i < num_regulators; i++) {
- int id = pdata->regulators[i].id;
- lp3971->rdev[i] = regulator_register(&regulators[id],
- lp3971->dev, pdata->regulators[i].initdata, lp3971);
+ for (i = 0; i < pdata->num_regulators; i++) {
+ struct lp3971_regulator_subdev *reg = &pdata->regulators[i];
+ lp3971->rdev[i] = regulator_register(&regulators[reg->id],
+ lp3971->dev, reg->initdata, lp3971);
if (IS_ERR(lp3971->rdev[i])) {
err = PTR_ERR(lp3971->rdev[i]);
@@ -455,10 +455,10 @@ static int setup_regulators(struct lp3971 *lp3971,
}
return 0;
+
error:
- for (i = 0; i < num_regulators; i++)
- if (lp3971->rdev[i])
- regulator_unregister(lp3971->rdev[i]);
+ while (--i >= 0)
+ regulator_unregister(lp3971->rdev[i]);
kfree(lp3971->rdev);
lp3971->rdev = NULL;
return err;
@@ -472,15 +472,17 @@ static int __devinit lp3971_i2c_probe(struct i2c_client *i2c,
int ret;
u16 val;
- lp3971 = kzalloc(sizeof(struct lp3971), GFP_KERNEL);
- if (lp3971 == NULL) {
- ret = -ENOMEM;
- goto err;
+ if (!pdata) {
+ dev_dbg(&i2c->dev, "No platform init data supplied\n");
+ return -ENODEV;
}
+ lp3971 = kzalloc(sizeof(struct lp3971), GFP_KERNEL);
+ if (lp3971 == NULL)
+ return -ENOMEM;
+
lp3971->i2c = i2c;
lp3971->dev = &i2c->dev;
- i2c_set_clientdata(i2c, lp3971);
mutex_init(&lp3971->io_lock);
@@ -493,19 +495,15 @@ static int __devinit lp3971_i2c_probe(struct i2c_client *i2c,
goto err_detect;
}
- if (pdata) {
- ret = setup_regulators(lp3971, pdata);
- if (ret < 0)
- goto err_detect;
- } else
- dev_warn(lp3971->dev, "No platform init data supplied\n");
+ ret = setup_regulators(lp3971, pdata);
+ if (ret < 0)
+ goto err_detect;
+ i2c_set_clientdata(i2c, lp3971);
return 0;
err_detect:
- i2c_set_clientdata(i2c, NULL);
kfree(lp3971);
-err:
return ret;
}
@@ -513,11 +511,13 @@ static int __devexit lp3971_i2c_remove(struct i2c_client *i2c)
{
struct lp3971 *lp3971 = i2c_get_clientdata(i2c);
int i;
+
+ i2c_set_clientdata(i2c, NULL);
+
for (i = 0; i < lp3971->num_regulators; i++)
- if (lp3971->rdev[i])
- regulator_unregister(lp3971->rdev[i]);
+ regulator_unregister(lp3971->rdev[i]);
+
kfree(lp3971->rdev);
- i2c_set_clientdata(i2c, NULL);
kfree(lp3971);
return 0;
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index 2c082d3ef484..a49fc952c9a9 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -179,8 +179,8 @@ static struct regulator_desc max1586_reg[] = {
},
};
-static int max1586_pmic_probe(struct i2c_client *client,
- const struct i2c_device_id *i2c_id)
+static int __devinit max1586_pmic_probe(struct i2c_client *client,
+ const struct i2c_device_id *i2c_id)
{
struct regulator_dev **rdev;
struct max1586_platform_data *pdata = client->dev.platform_data;
@@ -235,7 +235,7 @@ out:
return ret;
}
-static int max1586_pmic_remove(struct i2c_client *client)
+static int __devexit max1586_pmic_remove(struct i2c_client *client)
{
struct regulator_dev **rdev = i2c_get_clientdata(client);
int i;
@@ -257,9 +257,10 @@ MODULE_DEVICE_TABLE(i2c, max1586_id);
static struct i2c_driver max1586_pmic_driver = {
.probe = max1586_pmic_probe,
- .remove = max1586_pmic_remove,
+ .remove = __devexit_p(max1586_pmic_remove),
.driver = {
.name = "max1586",
+ .owner = THIS_MODULE,
},
.id_table = max1586_id,
};
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
new file mode 100644
index 000000000000..3ebdf698c648
--- /dev/null
+++ b/drivers/regulator/max8649.c
@@ -0,0 +1,408 @@
+/*
+ * Regulators driver for Maxim max8649
+ *
+ * Copyright (C) 2009-2010 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/max8649.h>
+
+#define MAX8649_DCDC_VMIN 750000 /* uV */
+#define MAX8649_DCDC_VMAX 1380000 /* uV */
+#define MAX8649_DCDC_STEP 10000 /* uV */
+#define MAX8649_VOL_MASK 0x3f
+
+/* Registers */
+#define MAX8649_MODE0 0x00
+#define MAX8649_MODE1 0x01
+#define MAX8649_MODE2 0x02
+#define MAX8649_MODE3 0x03
+#define MAX8649_CONTROL 0x04
+#define MAX8649_SYNC 0x05
+#define MAX8649_RAMP 0x06
+#define MAX8649_CHIP_ID1 0x08
+#define MAX8649_CHIP_ID2 0x09
+
+/* Bits */
+#define MAX8649_EN_PD (1 << 7)
+#define MAX8649_VID0_PD (1 << 6)
+#define MAX8649_VID1_PD (1 << 5)
+#define MAX8649_VID_MASK (3 << 5)
+
+#define MAX8649_FORCE_PWM (1 << 7)
+#define MAX8649_SYNC_EXTCLK (1 << 6)
+
+#define MAX8649_EXT_MASK (3 << 6)
+
+#define MAX8649_RAMP_MASK (7 << 5)
+#define MAX8649_RAMP_DOWN (1 << 1)
+
+struct max8649_regulator_info {
+ struct regulator_dev *regulator;
+ struct i2c_client *i2c;
+ struct device *dev;
+ struct mutex io_lock;
+
+ int vol_reg;
+ unsigned mode:2; /* bit[1:0] = VID1, VID0 */
+ unsigned extclk_freq:2;
+ unsigned extclk:1;
+ unsigned ramp_timing:3;
+ unsigned ramp_down:1;
+};
+
+/* I2C operations */
+
+static inline int max8649_read_device(struct i2c_client *i2c,
+ int reg, int bytes, void *dest)
+{
+ unsigned char data;
+ int ret;
+
+ data = (unsigned char)reg;
+ ret = i2c_master_send(i2c, &data, 1);
+ if (ret < 0)
+ return ret;
+ ret = i2c_master_recv(i2c, dest, bytes);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static inline int max8649_write_device(struct i2c_client *i2c,
+ int reg, int bytes, void *src)
+{
+ unsigned char buf[bytes + 1];
+ int ret;
+
+ buf[0] = (unsigned char)reg;
+ memcpy(&buf[1], src, bytes);
+
+ ret = i2c_master_send(i2c, buf, bytes + 1);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int max8649_reg_read(struct i2c_client *i2c, int reg)
+{
+ struct max8649_regulator_info *info = i2c_get_clientdata(i2c);
+ unsigned char data;
+ int ret;
+
+ mutex_lock(&info->io_lock);
+ ret = max8649_read_device(i2c, reg, 1, &data);
+ mutex_unlock(&info->io_lock);
+
+ if (ret < 0)
+ return ret;
+ return (int)data;
+}
+
+static int max8649_set_bits(struct i2c_client *i2c, int reg,
+ unsigned char mask, unsigned char data)
+{
+ struct max8649_regulator_info *info = i2c_get_clientdata(i2c);
+ unsigned char value;
+ int ret;
+
+ mutex_lock(&info->io_lock);
+ ret = max8649_read_device(i2c, reg, 1, &value);
+ if (ret < 0)
+ goto out;
+ value &= ~mask;
+ value |= data;
+ ret = max8649_write_device(i2c, reg, 1, &value);
+out:
+ mutex_unlock(&info->io_lock);
+ return ret;
+}
+
+static inline int check_range(int min_uV, int max_uV)
+{
+ if ((min_uV < MAX8649_DCDC_VMIN) || (max_uV > MAX8649_DCDC_VMAX)
+ || (min_uV > max_uV))
+ return -EINVAL;
+ return 0;
+}
+
+static int max8649_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+ return (MAX8649_DCDC_VMIN + index * MAX8649_DCDC_STEP);
+}
+
+static int max8649_get_voltage(struct regulator_dev *rdev)
+{
+ struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+ unsigned char data;
+ int ret;
+
+ ret = max8649_reg_read(info->i2c, info->vol_reg);
+ if (ret < 0)
+ return ret;
+ data = (unsigned char)ret & MAX8649_VOL_MASK;
+ return max8649_list_voltage(rdev, data);
+}
+
+static int max8649_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+ unsigned char data, mask;
+
+ if (check_range(min_uV, max_uV)) {
+ dev_err(info->dev, "invalid voltage range (%d, %d) uV\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+ data = (min_uV - MAX8649_DCDC_VMIN + MAX8649_DCDC_STEP - 1)
+ / MAX8649_DCDC_STEP;
+ mask = MAX8649_VOL_MASK;
+
+ return max8649_set_bits(info->i2c, info->vol_reg, mask, data);
+}
+
+/* EN_PD means pulldown on EN input */
+static int max8649_enable(struct regulator_dev *rdev)
+{
+ struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+ return max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_EN_PD, 0);
+}
+
+/*
+ * Applied internal pulldown resistor on EN input pin.
+ * If pulldown EN pin outside, it would be better.
+ */
+static int max8649_disable(struct regulator_dev *rdev)
+{
+ struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+ return max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_EN_PD,
+ MAX8649_EN_PD);
+}
+
+static int max8649_is_enabled(struct regulator_dev *rdev)
+{
+ struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = max8649_reg_read(info->i2c, MAX8649_CONTROL);
+ if (ret < 0)
+ return ret;
+ return !((unsigned char)ret & MAX8649_EN_PD);
+}
+
+static int max8649_enable_time(struct regulator_dev *rdev)
+{
+ struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+ int voltage, rate, ret;
+
+ /* get voltage */
+ ret = max8649_reg_read(info->i2c, info->vol_reg);
+ if (ret < 0)
+ return ret;
+ ret &= MAX8649_VOL_MASK;
+ voltage = max8649_list_voltage(rdev, (unsigned char)ret); /* uV */
+
+ /* get rate */
+ ret = max8649_reg_read(info->i2c, MAX8649_RAMP);
+ if (ret < 0)
+ return ret;
+ ret = (ret & MAX8649_RAMP_MASK) >> 5;
+ rate = (32 * 1000) >> ret; /* uV/uS */
+
+ return (voltage / rate);
+}
+
+static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ max8649_set_bits(info->i2c, info->vol_reg, MAX8649_FORCE_PWM,
+ MAX8649_FORCE_PWM);
+ break;
+ case REGULATOR_MODE_NORMAL:
+ max8649_set_bits(info->i2c, info->vol_reg,
+ MAX8649_FORCE_PWM, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static unsigned int max8649_get_mode(struct regulator_dev *rdev)
+{
+ struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = max8649_reg_read(info->i2c, info->vol_reg);
+ if (ret & MAX8649_FORCE_PWM)
+ return REGULATOR_MODE_FAST;
+ return REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops max8649_dcdc_ops = {
+ .set_voltage = max8649_set_voltage,
+ .get_voltage = max8649_get_voltage,
+ .list_voltage = max8649_list_voltage,
+ .enable = max8649_enable,
+ .disable = max8649_disable,
+ .is_enabled = max8649_is_enabled,
+ .enable_time = max8649_enable_time,
+ .set_mode = max8649_set_mode,
+ .get_mode = max8649_get_mode,
+
+};
+
+static struct regulator_desc dcdc_desc = {
+ .name = "max8649",
+ .ops = &max8649_dcdc_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 1 << 6,
+ .owner = THIS_MODULE,
+};
+
+static int __devinit max8649_regulator_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max8649_platform_data *pdata = client->dev.platform_data;
+ struct max8649_regulator_info *info = NULL;
+ unsigned char data;
+ int ret;
+
+ info = kzalloc(sizeof(struct max8649_regulator_info), GFP_KERNEL);
+ if (!info) {
+ dev_err(&client->dev, "No enough memory\n");
+ return -ENOMEM;
+ }
+
+ info->i2c = client;
+ info->dev = &client->dev;
+ mutex_init(&info->io_lock);
+ i2c_set_clientdata(client, info);
+
+ info->mode = pdata->mode;
+ switch (info->mode) {
+ case 0:
+ info->vol_reg = MAX8649_MODE0;
+ break;
+ case 1:
+ info->vol_reg = MAX8649_MODE1;
+ break;
+ case 2:
+ info->vol_reg = MAX8649_MODE2;
+ break;
+ case 3:
+ info->vol_reg = MAX8649_MODE3;
+ break;
+ default:
+ break;
+ }
+
+ ret = max8649_reg_read(info->i2c, MAX8649_CHIP_ID1);
+ if (ret < 0) {
+ dev_err(info->dev, "Failed to detect ID of MAX8649:%d\n",
+ ret);
+ goto out;
+ }
+ dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", ret);
+
+ /* enable VID0 & VID1 */
+ max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_VID_MASK, 0);
+
+ /* enable/disable external clock synchronization */
+ info->extclk = pdata->extclk;
+ data = (info->extclk) ? MAX8649_SYNC_EXTCLK : 0;
+ max8649_set_bits(info->i2c, info->vol_reg, MAX8649_SYNC_EXTCLK, data);
+ if (info->extclk) {
+ /* set external clock frequency */
+ info->extclk_freq = pdata->extclk_freq;
+ max8649_set_bits(info->i2c, MAX8649_SYNC, MAX8649_EXT_MASK,
+ info->extclk_freq);
+ }
+
+ if (pdata->ramp_timing) {
+ info->ramp_timing = pdata->ramp_timing;
+ max8649_set_bits(info->i2c, MAX8649_RAMP, MAX8649_RAMP_MASK,
+ info->ramp_timing << 5);
+ }
+
+ info->ramp_down = pdata->ramp_down;
+ if (info->ramp_down) {
+ max8649_set_bits(info->i2c, MAX8649_RAMP, MAX8649_RAMP_DOWN,
+ MAX8649_RAMP_DOWN);
+ }
+
+ info->regulator = regulator_register(&dcdc_desc, &client->dev,
+ pdata->regulator, info);
+ if (IS_ERR(info->regulator)) {
+ dev_err(info->dev, "failed to register regulator %s\n",
+ dcdc_desc.name);
+ ret = PTR_ERR(info->regulator);
+ goto out;
+ }
+
+ dev_info(info->dev, "Max8649 regulator device is detected.\n");
+ return 0;
+out:
+ kfree(info);
+ return ret;
+}
+
+static int __devexit max8649_regulator_remove(struct i2c_client *client)
+{
+ struct max8649_regulator_info *info = i2c_get_clientdata(client);
+
+ if (info) {
+ if (info->regulator)
+ regulator_unregister(info->regulator);
+ kfree(info);
+ }
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+
+static const struct i2c_device_id max8649_id[] = {
+ { "max8649", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max8649_id);
+
+static struct i2c_driver max8649_driver = {
+ .probe = max8649_regulator_probe,
+ .remove = __devexit_p(max8649_regulator_remove),
+ .driver = {
+ .name = "max8649",
+ },
+ .id_table = max8649_id,
+};
+
+static int __init max8649_init(void)
+{
+ return i2c_add_driver(&max8649_driver);
+}
+subsys_initcall(max8649_init);
+
+static void __exit max8649_exit(void)
+{
+ i2c_del_driver(&max8649_driver);
+}
+module_exit(max8649_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MAXIM 8649 voltage regulator driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
index acc2fb7b6087..f12f1bb62138 100644
--- a/drivers/regulator/max8660.c
+++ b/drivers/regulator/max8660.c
@@ -345,8 +345,8 @@ static struct regulator_desc max8660_reg[] = {
},
};
-static int max8660_probe(struct i2c_client *client,
- const struct i2c_device_id *i2c_id)
+static int __devinit max8660_probe(struct i2c_client *client,
+ const struct i2c_device_id *i2c_id)
{
struct regulator_dev **rdev;
struct max8660_platform_data *pdata = client->dev.platform_data;
@@ -354,7 +354,7 @@ static int max8660_probe(struct i2c_client *client,
int boot_on, i, id, ret = -EINVAL;
if (pdata->num_subdevs > MAX8660_V_END) {
- dev_err(&client->dev, "Too much regulators found!\n");
+ dev_err(&client->dev, "Too many regulators found!\n");
goto out;
}
@@ -462,7 +462,7 @@ out:
return ret;
}
-static int max8660_remove(struct i2c_client *client)
+static int __devexit max8660_remove(struct i2c_client *client)
{
struct regulator_dev **rdev = i2c_get_clientdata(client);
int i;
@@ -485,9 +485,10 @@ MODULE_DEVICE_TABLE(i2c, max8660_id);
static struct i2c_driver max8660_driver = {
.probe = max8660_probe,
- .remove = max8660_remove,
+ .remove = __devexit_p(max8660_remove),
.driver = {
.name = "max8660",
+ .owner = THIS_MODULE,
},
.id_table = max8660_id,
};
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
new file mode 100644
index 000000000000..67873f08ed40
--- /dev/null
+++ b/drivers/regulator/max8925-regulator.c
@@ -0,0 +1,306 @@
+/*
+ * Regulators driver for Maxim max8925
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/max8925.h>
+
+#define SD1_DVM_VMIN 850000
+#define SD1_DVM_VMAX 1000000
+#define SD1_DVM_STEP 50000
+#define SD1_DVM_SHIFT 5 /* SDCTL1 bit5 */
+#define SD1_DVM_EN 6 /* SDV1 bit 6 */
+
+struct max8925_regulator_info {
+ struct regulator_desc desc;
+ struct regulator_dev *regulator;
+ struct i2c_client *i2c;
+ struct max8925_chip *chip;
+
+ int min_uV;
+ int max_uV;
+ int step_uV;
+ int vol_reg;
+ int vol_shift;
+ int vol_nbits;
+ int enable_bit;
+ int enable_reg;
+};
+
+static inline int check_range(struct max8925_regulator_info *info,
+ int min_uV, int max_uV)
+{
+ if (min_uV < info->min_uV || min_uV > info->max_uV)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int max8925_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+ struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+ return info->min_uV + index * info->step_uV;
+}
+
+static int max8925_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+ unsigned char data, mask;
+
+ if (check_range(info, min_uV, max_uV)) {
+ dev_err(info->chip->dev, "invalid voltage range (%d, %d) uV\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+ data = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ data <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+
+ return max8925_set_bits(info->i2c, info->vol_reg, mask, data);
+}
+
+static int max8925_get_voltage(struct regulator_dev *rdev)
+{
+ struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+ unsigned char data, mask;
+ int ret;
+
+ ret = max8925_reg_read(info->i2c, info->vol_reg);
+ if (ret < 0)
+ return ret;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ data = (ret & mask) >> info->vol_shift;
+
+ return max8925_list_voltage(rdev, data);
+}
+
+static int max8925_enable(struct regulator_dev *rdev)
+{
+ struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+
+ return max8925_set_bits(info->i2c, info->enable_reg,
+ 1 << info->enable_bit,
+ 1 << info->enable_bit);
+}
+
+static int max8925_disable(struct regulator_dev *rdev)
+{
+ struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+
+ return max8925_set_bits(info->i2c, info->enable_reg,
+ 1 << info->enable_bit, 0);
+}
+
+static int max8925_is_enabled(struct regulator_dev *rdev)
+{
+ struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = max8925_reg_read(info->i2c, info->vol_reg);
+ if (ret < 0)
+ return ret;
+
+ return ret & (1 << info->enable_bit);
+}
+
+static int max8925_set_dvm_voltage(struct regulator_dev *rdev, int uV)
+{
+ struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+ unsigned char data, mask;
+
+ if (uV < SD1_DVM_VMIN || uV > SD1_DVM_VMAX)
+ return -EINVAL;
+
+ data = (uV - SD1_DVM_VMIN + SD1_DVM_STEP - 1) / SD1_DVM_STEP;
+ data <<= SD1_DVM_SHIFT;
+ mask = 3 << SD1_DVM_SHIFT;
+
+ return max8925_set_bits(info->i2c, info->enable_reg, mask, data);
+}
+
+static int max8925_set_dvm_enable(struct regulator_dev *rdev)
+{
+ struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+
+ return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN,
+ 1 << SD1_DVM_EN);
+}
+
+static int max8925_set_dvm_disable(struct regulator_dev *rdev)
+{
+ struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+
+ return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN, 0);
+}
+
+static struct regulator_ops max8925_regulator_sdv_ops = {
+ .set_voltage = max8925_set_voltage,
+ .get_voltage = max8925_get_voltage,
+ .enable = max8925_enable,
+ .disable = max8925_disable,
+ .is_enabled = max8925_is_enabled,
+ .set_suspend_voltage = max8925_set_dvm_voltage,
+ .set_suspend_enable = max8925_set_dvm_enable,
+ .set_suspend_disable = max8925_set_dvm_disable,
+};
+
+static struct regulator_ops max8925_regulator_ldo_ops = {
+ .set_voltage = max8925_set_voltage,
+ .get_voltage = max8925_get_voltage,
+ .enable = max8925_enable,
+ .disable = max8925_disable,
+ .is_enabled = max8925_is_enabled,
+};
+
+#define MAX8925_SDV(_id, min, max, step) \
+{ \
+ .desc = { \
+ .name = "SDV" #_id, \
+ .ops = &max8925_regulator_sdv_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MAX8925_ID_SD##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .min_uV = min * 1000, \
+ .max_uV = max * 1000, \
+ .step_uV = step * 1000, \
+ .vol_reg = MAX8925_SDV##_id, \
+ .vol_shift = 0, \
+ .vol_nbits = 6, \
+ .enable_reg = MAX8925_SDCTL##_id, \
+ .enable_bit = 0, \
+}
+
+#define MAX8925_LDO(_id, min, max, step) \
+{ \
+ .desc = { \
+ .name = "LDO" #_id, \
+ .ops = &max8925_regulator_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MAX8925_ID_LDO##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .min_uV = min * 1000, \
+ .max_uV = max * 1000, \
+ .step_uV = step * 1000, \
+ .vol_reg = MAX8925_LDOVOUT##_id, \
+ .vol_shift = 0, \
+ .vol_nbits = 6, \
+ .enable_reg = MAX8925_LDOCTL##_id, \
+ .enable_bit = 0, \
+}
+
+static struct max8925_regulator_info max8925_regulator_info[] = {
+ MAX8925_SDV(1, 637.5, 1425, 12.5),
+ MAX8925_SDV(2, 650, 2225, 25),
+ MAX8925_SDV(3, 750, 3900, 50),
+
+ MAX8925_LDO(1, 750, 3900, 50),
+ MAX8925_LDO(2, 650, 2250, 25),
+ MAX8925_LDO(3, 650, 2250, 25),
+ MAX8925_LDO(4, 750, 3900, 50),
+ MAX8925_LDO(5, 750, 3900, 50),
+ MAX8925_LDO(6, 750, 3900, 50),
+ MAX8925_LDO(7, 750, 3900, 50),
+ MAX8925_LDO(8, 750, 3900, 50),
+ MAX8925_LDO(9, 750, 3900, 50),
+ MAX8925_LDO(10, 750, 3900, 50),
+ MAX8925_LDO(11, 750, 3900, 50),
+ MAX8925_LDO(12, 750, 3900, 50),
+ MAX8925_LDO(13, 750, 3900, 50),
+ MAX8925_LDO(14, 750, 3900, 50),
+ MAX8925_LDO(15, 750, 3900, 50),
+ MAX8925_LDO(16, 750, 3900, 50),
+ MAX8925_LDO(17, 650, 2250, 25),
+ MAX8925_LDO(18, 650, 2250, 25),
+ MAX8925_LDO(19, 750, 3900, 50),
+ MAX8925_LDO(20, 750, 3900, 50),
+};
+
+static inline struct max8925_regulator_info *find_regulator_info(int id)
+{
+ struct max8925_regulator_info *ri;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) {
+ ri = &max8925_regulator_info[i];
+ if (ri->desc.id == id)
+ return ri;
+ }
+ return NULL;
+}
+
+static int __devinit max8925_regulator_probe(struct platform_device *pdev)
+{
+ struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct max8925_platform_data *pdata = chip->dev->platform_data;
+ struct max8925_regulator_info *ri = NULL;
+ struct regulator_dev *rdev;
+
+ ri = find_regulator_info(pdev->id);
+ if (ri == NULL) {
+ dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ return -EINVAL;
+ }
+ ri->i2c = chip->i2c;
+ ri->chip = chip;
+
+ rdev = regulator_register(&ri->desc, &pdev->dev,
+ pdata->regulator[pdev->id], ri);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ ri->desc.name);
+ return PTR_ERR(rdev);
+ }
+
+ platform_set_drvdata(pdev, rdev);
+ return 0;
+}
+
+static int __devexit max8925_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+ regulator_unregister(rdev);
+ return 0;
+}
+
+static struct platform_driver max8925_regulator_driver = {
+ .driver = {
+ .name = "max8925-regulator",
+ .owner = THIS_MODULE,
+ },
+ .probe = max8925_regulator_probe,
+ .remove = __devexit_p(max8925_regulator_remove),
+};
+
+static int __init max8925_regulator_init(void)
+{
+ return platform_driver_register(&max8925_regulator_driver);
+}
+subsys_initcall(max8925_regulator_init);
+
+static void __exit max8925_regulator_exit(void)
+{
+ platform_driver_unregister(&max8925_regulator_driver);
+}
+module_exit(max8925_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("Regulator Driver for Maxim 8925 PMIC");
+MODULE_ALIAS("platform:max8925-regulator");
+
diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c
index 39c495300045..f7b81845a196 100644
--- a/drivers/regulator/mc13783-regulator.c
+++ b/drivers/regulator/mc13783-regulator.c
@@ -2,6 +2,7 @@
* Regulator Driver for Freescale MC13783 PMIC
*
* Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.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
@@ -16,11 +17,44 @@
#include <linux/init.h>
#include <linux/err.h>
-#define MC13783_REG_SWITCHERS4 28
-#define MC13783_REG_SWITCHERS4_PLLEN (1 << 18)
-
#define MC13783_REG_SWITCHERS5 29
#define MC13783_REG_SWITCHERS5_SW3EN (1 << 20)
+#define MC13783_REG_SWITCHERS5_SW3VSEL 18
+#define MC13783_REG_SWITCHERS5_SW3VSEL_M (3 << 18)
+
+#define MC13783_REG_REGULATORSETTING0 30
+#define MC13783_REG_REGULATORSETTING0_VIOLOVSEL 2
+#define MC13783_REG_REGULATORSETTING0_VDIGVSEL 4
+#define MC13783_REG_REGULATORSETTING0_VGENVSEL 6
+#define MC13783_REG_REGULATORSETTING0_VRFDIGVSEL 9
+#define MC13783_REG_REGULATORSETTING0_VRFREFVSEL 11
+#define MC13783_REG_REGULATORSETTING0_VRFCPVSEL 13
+#define MC13783_REG_REGULATORSETTING0_VSIMVSEL 14
+#define MC13783_REG_REGULATORSETTING0_VESIMVSEL 15
+#define MC13783_REG_REGULATORSETTING0_VCAMVSEL 16
+
+#define MC13783_REG_REGULATORSETTING0_VIOLOVSEL_M (3 << 2)
+#define MC13783_REG_REGULATORSETTING0_VDIGVSEL_M (3 << 4)
+#define MC13783_REG_REGULATORSETTING0_VGENVSEL_M (7 << 6)
+#define MC13783_REG_REGULATORSETTING0_VRFDIGVSEL_M (3 << 9)
+#define MC13783_REG_REGULATORSETTING0_VRFREFVSEL_M (3 << 11)
+#define MC13783_REG_REGULATORSETTING0_VRFCPVSEL_M (1 << 13)
+#define MC13783_REG_REGULATORSETTING0_VSIMVSEL_M (1 << 14)
+#define MC13783_REG_REGULATORSETTING0_VESIMVSEL_M (1 << 15)
+#define MC13783_REG_REGULATORSETTING0_VCAMVSEL_M (7 << 16)
+
+#define MC13783_REG_REGULATORSETTING1 31
+#define MC13783_REG_REGULATORSETTING1_VVIBVSEL 0
+#define MC13783_REG_REGULATORSETTING1_VRF1VSEL 2
+#define MC13783_REG_REGULATORSETTING1_VRF2VSEL 4
+#define MC13783_REG_REGULATORSETTING1_VMMC1VSEL 6
+#define MC13783_REG_REGULATORSETTING1_VMMC2VSEL 9
+
+#define MC13783_REG_REGULATORSETTING1_VVIBVSEL_M (3 << 0)
+#define MC13783_REG_REGULATORSETTING1_VRF1VSEL_M (3 << 2)
+#define MC13783_REG_REGULATORSETTING1_VRF2VSEL_M (3 << 4)
+#define MC13783_REG_REGULATORSETTING1_VMMC1VSEL_M (7 << 6)
+#define MC13783_REG_REGULATORSETTING1_VMMC2VSEL_M (7 << 9)
#define MC13783_REG_REGULATORMODE0 32
#define MC13783_REG_REGULATORMODE0_VAUDIOEN (1 << 0)
@@ -48,19 +82,107 @@
#define MC13783_REG_POWERMISC_GPO2EN (1 << 8)
#define MC13783_REG_POWERMISC_GPO3EN (1 << 10)
#define MC13783_REG_POWERMISC_GPO4EN (1 << 12)
+#define MC13783_REG_POWERMISC_PWGT1SPIEN (1 << 15)
+#define MC13783_REG_POWERMISC_PWGT2SPIEN (1 << 16)
+
+#define MC13783_REG_POWERMISC_PWGTSPI_M (3 << 15)
+
struct mc13783_regulator {
struct regulator_desc desc;
int reg;
int enable_bit;
+ int vsel_reg;
+ int vsel_shift;
+ int vsel_mask;
+ int const *voltages;
+};
+
+/* Voltage Values */
+static const int const mc13783_sw3_val[] = {
+ 5000000, 5000000, 5000000, 5500000,
+};
+
+static const int const mc13783_vaudio_val[] = {
+ 2775000,
+};
+
+static const int const mc13783_viohi_val[] = {
+ 2775000,
+};
+
+static const int const mc13783_violo_val[] = {
+ 1200000, 1300000, 1500000, 1800000,
+};
+
+static const int const mc13783_vdig_val[] = {
+ 1200000, 1300000, 1500000, 1800000,
+};
+
+static const int const mc13783_vgen_val[] = {
+ 1200000, 1300000, 1500000, 1800000,
+ 1100000, 2000000, 2775000, 2400000,
+};
+
+static const int const mc13783_vrfdig_val[] = {
+ 1200000, 1500000, 1800000, 1875000,
+};
+
+static const int const mc13783_vrfref_val[] = {
+ 2475000, 2600000, 2700000, 2775000,
+};
+
+static const int const mc13783_vrfcp_val[] = {
+ 2700000, 2775000,
+};
+
+static const int const mc13783_vsim_val[] = {
+ 1800000, 2900000, 3000000,
+};
+
+static const int const mc13783_vesim_val[] = {
+ 1800000, 2900000,
+};
+
+static const int const mc13783_vcam_val[] = {
+ 1500000, 1800000, 2500000, 2550000,
+ 2600000, 2750000, 2800000, 3000000,
+};
+
+static const int const mc13783_vrfbg_val[] = {
+ 1250000,
+};
+
+static const int const mc13783_vvib_val[] = {
+ 1300000, 1800000, 2000000, 3000000,
+};
+
+static const int const mc13783_vmmc_val[] = {
+ 1600000, 1800000, 2000000, 2600000,
+ 2700000, 2800000, 2900000, 3000000,
+};
+
+static const int const mc13783_vrf_val[] = {
+ 1500000, 1875000, 2700000, 2775000,
+};
+
+static const int const mc13783_gpo_val[] = {
+ 3100000,
+};
+
+static const int const mc13783_pwgtdrv_val[] = {
+ 5500000,
};
static struct regulator_ops mc13783_regulator_ops;
+static struct regulator_ops mc13783_fixed_regulator_ops;
+static struct regulator_ops mc13783_gpo_regulator_ops;
-#define MC13783_DEFINE(prefix, _name, _reg) \
+#define MC13783_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages) \
[MC13783_ ## prefix ## _ ## _name] = { \
.desc = { \
.name = #prefix "_" #_name, \
+ .n_voltages = ARRAY_SIZE(_voltages), \
.ops = &mc13783_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.id = MC13783_ ## prefix ## _ ## _name, \
@@ -68,40 +190,92 @@ static struct regulator_ops mc13783_regulator_ops;
}, \
.reg = MC13783_REG_ ## _reg, \
.enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \
+ .vsel_reg = MC13783_REG_ ## _vsel_reg, \
+ .vsel_shift = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL,\
+ .vsel_mask = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL_M,\
+ .voltages = _voltages, \
+ }
+
+#define MC13783_FIXED_DEFINE(prefix, _name, _reg, _voltages) \
+ [MC13783_ ## prefix ## _ ## _name] = { \
+ .desc = { \
+ .name = #prefix "_" #_name, \
+ .n_voltages = ARRAY_SIZE(_voltages), \
+ .ops = &mc13783_fixed_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MC13783_ ## prefix ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ }, \
+ .reg = MC13783_REG_ ## _reg, \
+ .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \
+ .voltages = _voltages, \
}
-#define MC13783_DEFINE_SW(_name, _reg) MC13783_DEFINE(SW, _name, _reg)
-#define MC13783_DEFINE_REGU(_name, _reg) MC13783_DEFINE(REGU, _name, _reg)
+#define MC13783_GPO_DEFINE(prefix, _name, _reg, _voltages) \
+ [MC13783_ ## prefix ## _ ## _name] = { \
+ .desc = { \
+ .name = #prefix "_" #_name, \
+ .n_voltages = ARRAY_SIZE(_voltages), \
+ .ops = &mc13783_gpo_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MC13783_ ## prefix ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ }, \
+ .reg = MC13783_REG_ ## _reg, \
+ .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \
+ .voltages = _voltages, \
+ }
+
+#define MC13783_DEFINE_SW(_name, _reg, _vsel_reg, _voltages) \
+ MC13783_DEFINE(SW, _name, _reg, _vsel_reg, _voltages)
+#define MC13783_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages) \
+ MC13783_DEFINE(REGU, _name, _reg, _vsel_reg, _voltages)
static struct mc13783_regulator mc13783_regulators[] = {
- MC13783_DEFINE_SW(SW3, SWITCHERS5),
- MC13783_DEFINE_SW(PLL, SWITCHERS4),
-
- MC13783_DEFINE_REGU(VAUDIO, REGULATORMODE0),
- MC13783_DEFINE_REGU(VIOHI, REGULATORMODE0),
- MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0),
- MC13783_DEFINE_REGU(VDIG, REGULATORMODE0),
- MC13783_DEFINE_REGU(VGEN, REGULATORMODE0),
- MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0),
- MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0),
- MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0),
- MC13783_DEFINE_REGU(VSIM, REGULATORMODE1),
- MC13783_DEFINE_REGU(VESIM, REGULATORMODE1),
- MC13783_DEFINE_REGU(VCAM, REGULATORMODE1),
- MC13783_DEFINE_REGU(VRFBG, REGULATORMODE1),
- MC13783_DEFINE_REGU(VVIB, REGULATORMODE1),
- MC13783_DEFINE_REGU(VRF1, REGULATORMODE1),
- MC13783_DEFINE_REGU(VRF2, REGULATORMODE1),
- MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1),
- MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1),
- MC13783_DEFINE_REGU(GPO1, POWERMISC),
- MC13783_DEFINE_REGU(GPO2, POWERMISC),
- MC13783_DEFINE_REGU(GPO3, POWERMISC),
- MC13783_DEFINE_REGU(GPO4, POWERMISC),
+ MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val),
+
+ MC13783_FIXED_DEFINE(REGU, VAUDIO, REGULATORMODE0, mc13783_vaudio_val),
+ MC13783_FIXED_DEFINE(REGU, VIOHI, REGULATORMODE0, mc13783_viohi_val),
+ MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0, \
+ mc13783_violo_val),
+ MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, \
+ mc13783_vdig_val),
+ MC13783_DEFINE_REGU(VGEN, REGULATORMODE0, REGULATORSETTING0, \
+ mc13783_vgen_val),
+ MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0, REGULATORSETTING0, \
+ mc13783_vrfdig_val),
+ MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0, REGULATORSETTING0, \
+ mc13783_vrfref_val),
+ MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0, REGULATORSETTING0, \
+ mc13783_vrfcp_val),
+ MC13783_DEFINE_REGU(VSIM, REGULATORMODE1, REGULATORSETTING0, \
+ mc13783_vsim_val),
+ MC13783_DEFINE_REGU(VESIM, REGULATORMODE1, REGULATORSETTING0, \
+ mc13783_vesim_val),
+ MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \
+ mc13783_vcam_val),
+ MC13783_FIXED_DEFINE(REGU, VRFBG, REGULATORMODE1, mc13783_vrfbg_val),
+ MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1, \
+ mc13783_vvib_val),
+ MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1, \
+ mc13783_vrf_val),
+ MC13783_DEFINE_REGU(VRF2, REGULATORMODE1, REGULATORSETTING1, \
+ mc13783_vrf_val),
+ MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1, REGULATORSETTING1, \
+ mc13783_vmmc_val),
+ MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1, \
+ mc13783_vmmc_val),
+ MC13783_GPO_DEFINE(REGU, GPO1, POWERMISC, mc13783_gpo_val),
+ MC13783_GPO_DEFINE(REGU, GPO2, POWERMISC, mc13783_gpo_val),
+ MC13783_GPO_DEFINE(REGU, GPO3, POWERMISC, mc13783_gpo_val),
+ MC13783_GPO_DEFINE(REGU, GPO4, POWERMISC, mc13783_gpo_val),
+ MC13783_GPO_DEFINE(REGU, PWGT1SPI, POWERMISC, mc13783_pwgtdrv_val),
+ MC13783_GPO_DEFINE(REGU, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val),
};
struct mc13783_regulator_priv {
struct mc13783 *mc13783;
+ u32 powermisc_pwgt_state;
struct regulator_dev *regulators[];
};
@@ -154,10 +328,241 @@ static int mc13783_regulator_is_enabled(struct regulator_dev *rdev)
return (val & mc13783_regulators[id].enable_bit) != 0;
}
+static int mc13783_regulator_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ int id = rdev_get_id(rdev);
+
+ if (selector >= mc13783_regulators[id].desc.n_voltages)
+ return -EINVAL;
+
+ return mc13783_regulators[id].voltages[selector];
+}
+
+static int mc13783_get_best_voltage_index(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int reg_id = rdev_get_id(rdev);
+ int i;
+ int bestmatch;
+ int bestindex;
+
+ /*
+ * Locate the minimum voltage fitting the criteria on
+ * this regulator. The switchable voltages are not
+ * in strict falling order so we need to check them
+ * all for the best match.
+ */
+ bestmatch = INT_MAX;
+ bestindex = -1;
+ for (i = 0; i < mc13783_regulators[reg_id].desc.n_voltages; i++) {
+ if (mc13783_regulators[reg_id].voltages[i] >= min_uV &&
+ mc13783_regulators[reg_id].voltages[i] < bestmatch) {
+ bestmatch = mc13783_regulators[reg_id].voltages[i];
+ bestindex = i;
+ }
+ }
+
+ if (bestindex < 0 || bestmatch > max_uV) {
+ dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+ return bestindex;
+}
+
+static int mc13783_regulator_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int value, id = rdev_get_id(rdev);
+ int ret;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
+ __func__, id, min_uV, max_uV);
+
+ /* Find the best index */
+ value = mc13783_get_best_voltage_index(rdev, min_uV, max_uV);
+ dev_dbg(rdev_get_dev(rdev), "%s best value: %d \n", __func__, value);
+ if (value < 0)
+ return value;
+
+ mc13783_lock(priv->mc13783);
+ ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].vsel_reg,
+ mc13783_regulators[id].vsel_mask,
+ value << mc13783_regulators[id].vsel_shift);
+ mc13783_unlock(priv->mc13783);
+
+ return ret;
+}
+
+static int mc13783_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int ret, id = rdev_get_id(rdev);
+ unsigned int val;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ mc13783_lock(priv->mc13783);
+ ret = mc13783_reg_read(priv->mc13783,
+ mc13783_regulators[id].vsel_reg, &val);
+ mc13783_unlock(priv->mc13783);
+
+ if (ret)
+ return ret;
+
+ val = (val & mc13783_regulators[id].vsel_mask)
+ >> mc13783_regulators[id].vsel_shift;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
+
+ BUG_ON(val < 0 || val > mc13783_regulators[id].desc.n_voltages);
+
+ return mc13783_regulators[id].voltages[val];
+}
+
static struct regulator_ops mc13783_regulator_ops = {
.enable = mc13783_regulator_enable,
.disable = mc13783_regulator_disable,
.is_enabled = mc13783_regulator_is_enabled,
+ .list_voltage = mc13783_regulator_list_voltage,
+ .set_voltage = mc13783_regulator_set_voltage,
+ .get_voltage = mc13783_regulator_get_voltage,
+};
+
+static int mc13783_fixed_regulator_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int id = rdev_get_id(rdev);
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
+ __func__, id, min_uV, max_uV);
+
+ if (min_uV > mc13783_regulators[id].voltages[0] &&
+ max_uV < mc13783_regulators[id].voltages[0])
+ return 0;
+ else
+ return -EINVAL;
+}
+
+static int mc13783_fixed_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ int id = rdev_get_id(rdev);
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ return mc13783_regulators[id].voltages[0];
+}
+
+static struct regulator_ops mc13783_fixed_regulator_ops = {
+ .enable = mc13783_regulator_enable,
+ .disable = mc13783_regulator_disable,
+ .is_enabled = mc13783_regulator_is_enabled,
+ .list_voltage = mc13783_regulator_list_voltage,
+ .set_voltage = mc13783_fixed_regulator_set_voltage,
+ .get_voltage = mc13783_fixed_regulator_get_voltage,
+};
+
+int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask,
+ u32 val)
+{
+ struct mc13783 *mc13783 = priv->mc13783;
+ int ret;
+ u32 valread;
+
+ BUG_ON(val & ~mask);
+
+ ret = mc13783_reg_read(mc13783, MC13783_REG_POWERMISC, &valread);
+ if (ret)
+ return ret;
+
+ /* Update the stored state for Power Gates. */
+ priv->powermisc_pwgt_state =
+ (priv->powermisc_pwgt_state & ~mask) | val;
+ priv->powermisc_pwgt_state &= MC13783_REG_POWERMISC_PWGTSPI_M;
+
+ /* Construct the new register value */
+ valread = (valread & ~mask) | val;
+ /* Overwrite the PWGTxEN with the stored version */
+ valread = (valread & ~MC13783_REG_POWERMISC_PWGTSPI_M) |
+ priv->powermisc_pwgt_state;
+
+ return mc13783_reg_write(mc13783, MC13783_REG_POWERMISC, valread);
+}
+
+static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev)
+{
+ struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ int ret;
+ u32 en_val = mc13783_regulators[id].enable_bit;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ /* Power Gate enable value is 0 */
+ if (id == MC13783_REGU_PWGT1SPI ||
+ id == MC13783_REGU_PWGT2SPI)
+ en_val = 0;
+
+ mc13783_lock(priv->mc13783);
+ ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit,
+ en_val);
+ mc13783_unlock(priv->mc13783);
+
+ return ret;
+}
+
+static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev)
+{
+ struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ int ret;
+ u32 dis_val = 0;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ /* Power Gate disable value is 1 */
+ if (id == MC13783_REGU_PWGT1SPI ||
+ id == MC13783_REGU_PWGT2SPI)
+ dis_val = mc13783_regulators[id].enable_bit;
+
+ mc13783_lock(priv->mc13783);
+ ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit,
+ dis_val);
+ mc13783_unlock(priv->mc13783);
+
+ return ret;
+}
+
+static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int ret, id = rdev_get_id(rdev);
+ unsigned int val;
+
+ mc13783_lock(priv->mc13783);
+ ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val);
+ mc13783_unlock(priv->mc13783);
+
+ if (ret)
+ return ret;
+
+ /* Power Gates state is stored in powermisc_pwgt_state
+ * where the meaning of bits is negated */
+ val = (val & ~MC13783_REG_POWERMISC_PWGTSPI_M) |
+ (priv->powermisc_pwgt_state ^ MC13783_REG_POWERMISC_PWGTSPI_M);
+
+ return (val & mc13783_regulators[id].enable_bit) != 0;
+}
+
+static struct regulator_ops mc13783_gpo_regulator_ops = {
+ .enable = mc13783_gpo_regulator_enable,
+ .disable = mc13783_gpo_regulator_disable,
+ .is_enabled = mc13783_gpo_regulator_is_enabled,
+ .list_voltage = mc13783_regulator_list_voltage,
+ .set_voltage = mc13783_fixed_regulator_set_voltage,
+ .get_voltage = mc13783_fixed_regulator_get_voltage,
};
static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c
index 33d7d899e030..29d0566379ae 100644
--- a/drivers/regulator/pcap-regulator.c
+++ b/drivers/regulator/pcap-regulator.c
@@ -288,16 +288,18 @@ static int __devexit pcap_regulator_remove(struct platform_device *pdev)
struct regulator_dev *rdev = platform_get_drvdata(pdev);
regulator_unregister(rdev);
+ platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver pcap_regulator_driver = {
.driver = {
- .name = "pcap-regulator",
+ .name = "pcap-regulator",
+ .owner = THIS_MODULE,
},
- .probe = pcap_regulator_probe,
- .remove = __devexit_p(pcap_regulator_remove),
+ .probe = pcap_regulator_probe,
+ .remove = __devexit_p(pcap_regulator_remove),
};
static int __init pcap_regulator_init(void)
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index 07fda0a75adf..1f183543bdbd 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -457,8 +457,8 @@ static struct regulator_ops tps65023_ldo_ops = {
.list_voltage = tps65023_ldo_list_voltage,
};
-static
-int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int __devinit tps_65023_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
static int desc_id;
const struct tps_info *info = (void *)id->driver_data;
@@ -466,6 +466,7 @@ int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id)
struct regulator_dev *rdev;
struct tps_pmic *tps;
int i;
+ int error;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
@@ -475,7 +476,6 @@ int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id)
* coming from the board-evm file.
*/
init_data = client->dev.platform_data;
-
if (!init_data)
return -EIO;
@@ -502,21 +502,12 @@ int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* Register the regulators */
rdev = regulator_register(&tps->desc[i], &client->dev,
- init_data, tps);
+ init_data, tps);
if (IS_ERR(rdev)) {
dev_err(&client->dev, "failed to register %s\n",
id->name);
-
- /* Unregister */
- while (i)
- regulator_unregister(tps->rdev[--i]);
-
- tps->client = NULL;
-
- /* clear the client data in i2c */
- i2c_set_clientdata(client, NULL);
- kfree(tps);
- return PTR_ERR(rdev);
+ error = PTR_ERR(rdev);
+ goto fail;
}
/* Save regulator for cleanup */
@@ -526,6 +517,13 @@ int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id)
i2c_set_clientdata(client, tps);
return 0;
+
+ fail:
+ while (--i >= 0)
+ regulator_unregister(tps->rdev[i]);
+
+ kfree(tps);
+ return error;
}
/**
@@ -539,13 +537,12 @@ static int __devexit tps_65023_remove(struct i2c_client *client)
struct tps_pmic *tps = i2c_get_clientdata(client);
int i;
+ /* clear the client data in i2c */
+ i2c_set_clientdata(client, NULL);
+
for (i = 0; i < TPS65023_NUM_REGULATOR; i++)
regulator_unregister(tps->rdev[i]);
- tps->client = NULL;
-
- /* clear the client data in i2c */
- i2c_set_clientdata(client, NULL);
kfree(tps);
return 0;
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index f8a6dfbef751..c2a9539acd72 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -538,8 +538,8 @@ static struct regulator_ops tps6507x_ldo_ops = {
.list_voltage = tps6507x_ldo_list_voltage,
};
-static
-int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int __devinit tps_6507x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
static int desc_id;
const struct tps_info *info = (void *)id->driver_data;
@@ -547,6 +547,7 @@ int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)
struct regulator_dev *rdev;
struct tps_pmic *tps;
int i;
+ int error;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA))
@@ -557,7 +558,6 @@ int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)
* coming from the board-evm file.
*/
init_data = client->dev.platform_data;
-
if (!init_data)
return -EIO;
@@ -586,18 +586,8 @@ int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (IS_ERR(rdev)) {
dev_err(&client->dev, "failed to register %s\n",
id->name);
-
- /* Unregister */
- while (i)
- regulator_unregister(tps->rdev[--i]);
-
- tps->client = NULL;
-
- /* clear the client data in i2c */
- i2c_set_clientdata(client, NULL);
-
- kfree(tps);
- return PTR_ERR(rdev);
+ error = PTR_ERR(rdev);
+ goto fail;
}
/* Save regulator for cleanup */
@@ -607,6 +597,13 @@ int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)
i2c_set_clientdata(client, tps);
return 0;
+
+fail:
+ while (--i >= 0)
+ regulator_unregister(tps->rdev[i]);
+
+ kfree(tps);
+ return error;
}
/**
@@ -620,13 +617,12 @@ static int __devexit tps_6507x_remove(struct i2c_client *client)
struct tps_pmic *tps = i2c_get_clientdata(client);
int i;
+ /* clear the client data in i2c */
+ i2c_set_clientdata(client, NULL);
+
for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)
regulator_unregister(tps->rdev[i]);
- tps->client = NULL;
-
- /* clear the client data in i2c */
- i2c_set_clientdata(client, NULL);
kfree(tps);
return 0;
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index 7e674859bd59..9729d760fb4d 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -519,19 +519,19 @@ static struct twlreg_info twl_regs[] = {
/* 6030 REG with base as PMC Slave Misc : 0x0030 */
/* Turnon-delay and remap configuration values for 6030 are not
verified since the specification is not public */
- TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1, 0, 0x08),
- TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 2, 0, 0x08),
- TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 3, 0, 0x08),
- TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 4, 0, 0x08),
- TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 5, 0, 0x08),
- TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 7, 0, 0x08),
- TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x08),
- TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x08),
- TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x08),
- TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x08)
+ TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1, 0, 0x21),
+ TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 2, 0, 0x21),
+ TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 3, 0, 0x21),
+ TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 4, 0, 0x21),
+ TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 5, 0, 0x21),
+ TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 7, 0, 0x21),
+ TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x21),
+ TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x21),
+ TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x21),
+ TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x21)
};
-static int twlreg_probe(struct platform_device *pdev)
+static int __devinit twlreg_probe(struct platform_device *pdev)
{
int i;
struct twlreg_info *info;
diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c
index addc032c84bf..d96cecaac73d 100644
--- a/drivers/regulator/virtual.c
+++ b/drivers/regulator/virtual.c
@@ -19,7 +19,7 @@
struct virtual_consumer_data {
struct mutex lock;
struct regulator *regulator;
- int enabled;
+ bool enabled;
int min_uV;
int max_uV;
int min_uA;
@@ -49,7 +49,7 @@ static void update_voltage_constraints(struct device *dev,
dev_dbg(dev, "Enabling regulator\n");
ret = regulator_enable(data->regulator);
if (ret == 0)
- data->enabled = 1;
+ data->enabled = true;
else
dev_err(dev, "regulator_enable() failed: %d\n",
ret);
@@ -59,7 +59,7 @@ static void update_voltage_constraints(struct device *dev,
dev_dbg(dev, "Disabling regulator\n");
ret = regulator_disable(data->regulator);
if (ret == 0)
- data->enabled = 0;
+ data->enabled = false;
else
dev_err(dev, "regulator_disable() failed: %d\n",
ret);
@@ -89,7 +89,7 @@ static void update_current_limit_constraints(struct device *dev,
dev_dbg(dev, "Enabling regulator\n");
ret = regulator_enable(data->regulator);
if (ret == 0)
- data->enabled = 1;
+ data->enabled = true;
else
dev_err(dev, "regulator_enable() failed: %d\n",
ret);
@@ -99,7 +99,7 @@ static void update_current_limit_constraints(struct device *dev,
dev_dbg(dev, "Disabling regulator\n");
ret = regulator_disable(data->regulator);
if (ret == 0)
- data->enabled = 0;
+ data->enabled = false;
else
dev_err(dev, "regulator_disable() failed: %d\n",
ret);
@@ -270,24 +270,28 @@ static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA);
static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA);
static DEVICE_ATTR(mode, 0666, show_mode, set_mode);
-static struct device_attribute *attributes[] = {
- &dev_attr_min_microvolts,
- &dev_attr_max_microvolts,
- &dev_attr_min_microamps,
- &dev_attr_max_microamps,
- &dev_attr_mode,
+static struct attribute *regulator_virtual_attributes[] = {
+ &dev_attr_min_microvolts.attr,
+ &dev_attr_max_microvolts.attr,
+ &dev_attr_min_microamps.attr,
+ &dev_attr_max_microamps.attr,
+ &dev_attr_mode.attr,
+ NULL
};
-static int regulator_virtual_consumer_probe(struct platform_device *pdev)
+static const struct attribute_group regulator_virtual_attr_group = {
+ .attrs = regulator_virtual_attributes,
+};
+
+static int __devinit regulator_virtual_probe(struct platform_device *pdev)
{
char *reg_id = pdev->dev.platform_data;
struct virtual_consumer_data *drvdata;
- int ret, i;
+ int ret;
drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL);
- if (drvdata == NULL) {
+ if (drvdata == NULL)
return -ENOMEM;
- }
mutex_init(&drvdata->lock);
@@ -299,13 +303,12 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
goto err;
}
- for (i = 0; i < ARRAY_SIZE(attributes); i++) {
- ret = device_create_file(&pdev->dev, attributes[i]);
- if (ret != 0) {
- dev_err(&pdev->dev, "Failed to create attr %d: %d\n",
- i, ret);
- goto err_regulator;
- }
+ ret = sysfs_create_group(&pdev->dev.kobj,
+ &regulator_virtual_attr_group);
+ if (ret != 0) {
+ dev_err(&pdev->dev,
+ "Failed to create attribute group: %d\n", ret);
+ goto err_regulator;
}
drvdata->mode = regulator_get_mode(drvdata->regulator);
@@ -317,37 +320,36 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
err_regulator:
regulator_put(drvdata->regulator);
err:
- for (i = 0; i < ARRAY_SIZE(attributes); i++)
- device_remove_file(&pdev->dev, attributes[i]);
kfree(drvdata);
return ret;
}
-static int regulator_virtual_consumer_remove(struct platform_device *pdev)
+static int __devexit regulator_virtual_remove(struct platform_device *pdev)
{
struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev);
- int i;
- for (i = 0; i < ARRAY_SIZE(attributes); i++)
- device_remove_file(&pdev->dev, attributes[i]);
+ sysfs_remove_group(&pdev->dev.kobj, &regulator_virtual_attr_group);
+
if (drvdata->enabled)
regulator_disable(drvdata->regulator);
regulator_put(drvdata->regulator);
kfree(drvdata);
+ platform_set_drvdata(pdev, NULL);
+
return 0;
}
static struct platform_driver regulator_virtual_consumer_driver = {
- .probe = regulator_virtual_consumer_probe,
- .remove = regulator_virtual_consumer_remove,
+ .probe = regulator_virtual_probe,
+ .remove = __devexit_p(regulator_virtual_remove),
.driver = {
.name = "reg-virt-consumer",
+ .owner = THIS_MODULE,
},
};
-
static int __init regulator_virtual_consumer_init(void)
{
return platform_driver_register(&regulator_virtual_consumer_driver);
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index 0a6577577e8d..6e18e56d850b 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -600,6 +600,8 @@ static __devexit int wm831x_buckv_remove(struct platform_device *pdev)
struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
struct wm831x *wm831x = dcdc->wm831x;
+ platform_set_drvdata(pdev, NULL);
+
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "HC"), dcdc);
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);
regulator_unregister(dcdc->regulator);
@@ -615,6 +617,7 @@ static struct platform_driver wm831x_buckv_driver = {
.remove = __devexit_p(wm831x_buckv_remove),
.driver = {
.name = "wm831x-buckv",
+ .owner = THIS_MODULE,
},
};
@@ -769,6 +772,8 @@ static __devexit int wm831x_buckp_remove(struct platform_device *pdev)
struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
struct wm831x *wm831x = dcdc->wm831x;
+ platform_set_drvdata(pdev, NULL);
+
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);
regulator_unregister(dcdc->regulator);
kfree(dcdc);
@@ -781,6 +786,7 @@ static struct platform_driver wm831x_buckp_driver = {
.remove = __devexit_p(wm831x_buckp_remove),
.driver = {
.name = "wm831x-buckp",
+ .owner = THIS_MODULE,
},
};
@@ -895,6 +901,8 @@ static __devexit int wm831x_boostp_remove(struct platform_device *pdev)
struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
struct wm831x *wm831x = dcdc->wm831x;
+ platform_set_drvdata(pdev, NULL);
+
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);
regulator_unregister(dcdc->regulator);
kfree(dcdc);
@@ -907,6 +915,7 @@ static struct platform_driver wm831x_boostp_driver = {
.remove = __devexit_p(wm831x_boostp_remove),
.driver = {
.name = "wm831x-boostp",
+ .owner = THIS_MODULE,
},
};
@@ -979,6 +988,8 @@ static __devexit int wm831x_epe_remove(struct platform_device *pdev)
{
struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, NULL);
+
regulator_unregister(dcdc->regulator);
kfree(dcdc);
@@ -990,6 +1001,7 @@ static struct platform_driver wm831x_epe_driver = {
.remove = __devexit_p(wm831x_epe_remove),
.driver = {
.name = "wm831x-epe",
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c
index 48857008758c..ca0f6b6c384b 100644
--- a/drivers/regulator/wm831x-isink.c
+++ b/drivers/regulator/wm831x-isink.c
@@ -222,6 +222,8 @@ static __devexit int wm831x_isink_remove(struct platform_device *pdev)
struct wm831x_isink *isink = platform_get_drvdata(pdev);
struct wm831x *wm831x = isink->wm831x;
+ platform_set_drvdata(pdev, NULL);
+
wm831x_free_irq(wm831x, platform_get_irq(pdev, 0), isink);
regulator_unregister(isink->regulator);
@@ -235,6 +237,7 @@ static struct platform_driver wm831x_isink_driver = {
.remove = __devexit_p(wm831x_isink_remove),
.driver = {
.name = "wm831x-isink",
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index 61e02ac2fda3..d2406c1519a1 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -371,6 +371,8 @@ static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev)
struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
struct wm831x *wm831x = ldo->wm831x;
+ platform_set_drvdata(pdev, NULL);
+
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), ldo);
regulator_unregister(ldo->regulator);
kfree(ldo);
@@ -383,6 +385,7 @@ static struct platform_driver wm831x_gp_ldo_driver = {
.remove = __devexit_p(wm831x_gp_ldo_remove),
.driver = {
.name = "wm831x-ldo",
+ .owner = THIS_MODULE,
},
};
@@ -640,6 +643,7 @@ static struct platform_driver wm831x_aldo_driver = {
.remove = __devexit_p(wm831x_aldo_remove),
.driver = {
.name = "wm831x-aldo",
+ .owner = THIS_MODULE,
},
};
@@ -811,6 +815,7 @@ static struct platform_driver wm831x_alive_ldo_driver = {
.remove = __devexit_p(wm831x_alive_ldo_remove),
.driver = {
.name = "wm831x-alive-ldo",
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index 1bbff099a546..723cd1fb4867 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -290,6 +290,51 @@ static int wm8350_isink_is_enabled(struct regulator_dev *rdev)
return -EINVAL;
}
+static int wm8350_isink_enable_time(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int isink = rdev_get_id(rdev);
+ int reg;
+
+ switch (isink) {
+ case WM8350_ISINK_A:
+ reg = wm8350_reg_read(wm8350, WM8350_CSA_FLASH_CONTROL);
+ break;
+ case WM8350_ISINK_B:
+ reg = wm8350_reg_read(wm8350, WM8350_CSB_FLASH_CONTROL);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (reg & WM8350_CS1_FLASH_MODE) {
+ switch (reg & WM8350_CS1_ON_RAMP_MASK) {
+ case 0:
+ return 0;
+ case 1:
+ return 1950;
+ case 2:
+ return 3910;
+ case 3:
+ return 7800;
+ }
+ } else {
+ switch (reg & WM8350_CS1_ON_RAMP_MASK) {
+ case 0:
+ return 0;
+ case 1:
+ return 250000;
+ case 2:
+ return 500000;
+ case 3:
+ return 1000000;
+ }
+ }
+
+ return -EINVAL;
+}
+
+
int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
u16 trigger, u16 duration, u16 on_ramp, u16 off_ramp,
u16 drive)
@@ -1221,6 +1266,7 @@ static struct regulator_ops wm8350_isink_ops = {
.enable = wm8350_isink_enable,
.disable = wm8350_isink_disable,
.is_enabled = wm8350_isink_is_enabled,
+ .enable_time = wm8350_isink_enable_time,
};
static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
@@ -1407,7 +1453,7 @@ static int wm8350_regulator_remove(struct platform_device *pdev)
struct regulator_dev *rdev = platform_get_drvdata(pdev);
struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
- wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq);
+ wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq, rdev);
regulator_unregister(rdev);
@@ -1504,7 +1550,8 @@ int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink,
led->isink_init.consumer_supplies = &led->isink_consumer;
led->isink_init.constraints.min_uA = 0;
led->isink_init.constraints.max_uA = pdata->max_uA;
- led->isink_init.constraints.valid_ops_mask = REGULATOR_CHANGE_CURRENT;
+ led->isink_init.constraints.valid_ops_mask
+ = REGULATOR_CHANGE_CURRENT | REGULATOR_CHANGE_STATUS;
led->isink_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL;
ret = wm8350_register_regulator(wm8350, isink, &led->isink_init);
if (ret != 0) {
@@ -1517,6 +1564,7 @@ int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink,
led->dcdc_init.num_consumer_supplies = 1;
led->dcdc_init.consumer_supplies = &led->dcdc_consumer;
led->dcdc_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL;
+ led->dcdc_init.constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS;
ret = wm8350_register_regulator(wm8350, dcdc, &led->dcdc_init);
if (ret != 0) {
platform_device_put(pdev);
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index d9a2c988c6e7..924c7eb29ee9 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -317,14 +317,17 @@ static struct regulator_desc regulators[] = {
static int __devinit wm8400_regulator_probe(struct platform_device *pdev)
{
+ struct wm8400 *wm8400 = container_of(pdev, struct wm8400, regulators[pdev->id]);
struct regulator_dev *rdev;
rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
- pdev->dev.platform_data, dev_get_drvdata(&pdev->dev));
+ pdev->dev.platform_data, wm8400);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
+ platform_set_drvdata(pdev, rdev);
+
return 0;
}
@@ -332,6 +335,7 @@ static int __devexit wm8400_regulator_remove(struct platform_device *pdev)
{
struct regulator_dev *rdev = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, NULL);
regulator_unregister(rdev);
return 0;
@@ -370,7 +374,6 @@ int wm8400_register_regulator(struct device *dev, int reg,
wm8400->regulators[reg].id = reg;
wm8400->regulators[reg].dev.parent = dev;
wm8400->regulators[reg].dev.platform_data = initdata;
- dev_set_drvdata(&wm8400->regulators[reg].dev, wm8400);
return platform_device_register(&wm8400->regulators[reg]);
}
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
new file mode 100644
index 000000000000..95454a4637b7
--- /dev/null
+++ b/drivers/regulator/wm8994-regulator.c
@@ -0,0 +1,307 @@
+/*
+ * wm8994-regulator.c -- Regulator driver for the WM8994
+ *
+ * Copyright 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/gpio.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include <linux/mfd/wm8994/pdata.h>
+
+struct wm8994_ldo {
+ int enable;
+ bool is_enabled;
+ struct regulator_dev *regulator;
+ struct wm8994 *wm8994;
+};
+
+#define WM8994_LDO1_MAX_SELECTOR 0x7
+#define WM8994_LDO2_MAX_SELECTOR 0x3
+
+static int wm8994_ldo_enable(struct regulator_dev *rdev)
+{
+ struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+
+ /* If we have no soft control assume that the LDO is always enabled. */
+ if (!ldo->enable)
+ return 0;
+
+ gpio_set_value(ldo->enable, 1);
+ ldo->is_enabled = true;
+
+ return 0;
+}
+
+static int wm8994_ldo_disable(struct regulator_dev *rdev)
+{
+ struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+
+ /* If we have no soft control assume that the LDO is always enabled. */
+ if (!ldo->enable)
+ return -EINVAL;
+
+ gpio_set_value(ldo->enable, 0);
+ ldo->is_enabled = false;
+
+ return 0;
+}
+
+static int wm8994_ldo_is_enabled(struct regulator_dev *rdev)
+{
+ struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+
+ return ldo->is_enabled;
+}
+
+static int wm8994_ldo_enable_time(struct regulator_dev *rdev)
+{
+ /* 3ms is fairly conservative but this shouldn't be too performance
+ * critical; can be tweaked per-system if required. */
+ return 3000;
+}
+
+static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ if (selector > WM8994_LDO1_MAX_SELECTOR)
+ return -EINVAL;
+
+ return (selector * 100000) + 2400000;
+}
+
+static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev)
+{
+ struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+ int val;
+
+ val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_1);
+ if (val < 0)
+ return val;
+
+ val = (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT;
+
+ return wm8994_ldo1_list_voltage(rdev, val);
+}
+
+static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+ int selector, v;
+
+ selector = (min_uV - 2400000) / 100000;
+ v = wm8994_ldo1_list_voltage(rdev, selector);
+ if (v < 0 || v > max_uV)
+ return -EINVAL;
+
+ selector <<= WM8994_LDO1_VSEL_SHIFT;
+
+ return wm8994_set_bits(ldo->wm8994, WM8994_LDO_1,
+ WM8994_LDO1_VSEL_MASK, selector);
+}
+
+static struct regulator_ops wm8994_ldo1_ops = {
+ .enable = wm8994_ldo_enable,
+ .disable = wm8994_ldo_disable,
+ .is_enabled = wm8994_ldo_is_enabled,
+ .enable_time = wm8994_ldo_enable_time,
+
+ .list_voltage = wm8994_ldo1_list_voltage,
+ .get_voltage = wm8994_ldo1_get_voltage,
+ .set_voltage = wm8994_ldo1_set_voltage,
+};
+
+static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ if (selector > WM8994_LDO2_MAX_SELECTOR)
+ return -EINVAL;
+
+ return (selector * 100000) + 900000;
+}
+
+static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev)
+{
+ struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+ int val;
+
+ val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_2);
+ if (val < 0)
+ return val;
+
+ val = (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT;
+
+ return wm8994_ldo2_list_voltage(rdev, val);
+}
+
+static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+ int selector, v;
+
+ selector = (min_uV - 900000) / 100000;
+ v = wm8994_ldo2_list_voltage(rdev, selector);
+ if (v < 0 || v > max_uV)
+ return -EINVAL;
+
+ selector <<= WM8994_LDO2_VSEL_SHIFT;
+
+ return wm8994_set_bits(ldo->wm8994, WM8994_LDO_2,
+ WM8994_LDO2_VSEL_MASK, selector);
+}
+
+static struct regulator_ops wm8994_ldo2_ops = {
+ .enable = wm8994_ldo_enable,
+ .disable = wm8994_ldo_disable,
+ .is_enabled = wm8994_ldo_is_enabled,
+ .enable_time = wm8994_ldo_enable_time,
+
+ .list_voltage = wm8994_ldo2_list_voltage,
+ .get_voltage = wm8994_ldo2_get_voltage,
+ .set_voltage = wm8994_ldo2_set_voltage,
+};
+
+static struct regulator_desc wm8994_ldo_desc[] = {
+ {
+ .name = "LDO1",
+ .id = 1,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = WM8994_LDO1_MAX_SELECTOR + 1,
+ .ops = &wm8994_ldo1_ops,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO2",
+ .id = 2,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = WM8994_LDO2_MAX_SELECTOR + 1,
+ .ops = &wm8994_ldo2_ops,
+ .owner = THIS_MODULE,
+ },
+};
+
+static __devinit int wm8994_ldo_probe(struct platform_device *pdev)
+{
+ struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
+ struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+ int id = pdev->id % ARRAY_SIZE(pdata->ldo);
+ struct wm8994_ldo *ldo;
+ int ret;
+
+ dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
+
+ if (!pdata)
+ return -ENODEV;
+
+ ldo = kzalloc(sizeof(struct wm8994_ldo), GFP_KERNEL);
+ if (ldo == NULL) {
+ dev_err(&pdev->dev, "Unable to allocate private data\n");
+ return -ENOMEM;
+ }
+
+ ldo->wm8994 = wm8994;
+
+ ldo->is_enabled = true;
+
+ if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) {
+ ldo->enable = pdata->ldo[id].enable;
+
+ ret = gpio_request(ldo->enable, "WM8994 LDO enable");
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n",
+ ret);
+ goto err;
+ }
+
+ ret = gpio_direction_output(ldo->enable, ldo->is_enabled);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to set GPIO up: %d\n",
+ ret);
+ goto err_gpio;
+ }
+ }
+
+ ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev,
+ pdata->ldo[id].init_data, ldo);
+ if (IS_ERR(ldo->regulator)) {
+ ret = PTR_ERR(ldo->regulator);
+ dev_err(wm8994->dev, "Failed to register LDO%d: %d\n",
+ id + 1, ret);
+ goto err_gpio;
+ }
+
+ platform_set_drvdata(pdev, ldo);
+
+ return 0;
+
+err_gpio:
+ if (gpio_is_valid(ldo->enable))
+ gpio_free(ldo->enable);
+err:
+ kfree(ldo);
+ return ret;
+}
+
+static __devexit int wm8994_ldo_remove(struct platform_device *pdev)
+{
+ struct wm8994_ldo *ldo = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ regulator_unregister(ldo->regulator);
+ if (gpio_is_valid(ldo->enable))
+ gpio_free(ldo->enable);
+ kfree(ldo);
+
+ return 0;
+}
+
+static struct platform_driver wm8994_ldo_driver = {
+ .probe = wm8994_ldo_probe,
+ .remove = __devexit_p(wm8994_ldo_remove),
+ .driver = {
+ .name = "wm8994-ldo",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init wm8994_ldo_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&wm8994_ldo_driver);
+ if (ret != 0)
+ pr_err("Failed to register Wm8994 GP LDO driver: %d\n", ret);
+
+ return ret;
+}
+subsys_initcall(wm8994_ldo_init);
+
+static void __exit wm8994_ldo_exit(void)
+{
+ platform_driver_unregister(&wm8994_ldo_driver);
+}
+module_exit(wm8994_ldo_exit);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM8994 LDO driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8994-ldo");
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 8167e9e6827a..6a1303759432 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -175,6 +175,16 @@ config RTC_DRV_MAX6900
This driver can also be built as a module. If so, the module
will be called rtc-max6900.
+config RTC_DRV_MAX8925
+ tristate "Maxim MAX8925"
+ depends on MFD_MAX8925
+ help
+ If you say yes here you will get support for the
+ RTC of Maxim MAX8925 PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-max8925.
+
config RTC_DRV_RS5C372
tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
help
@@ -868,4 +878,14 @@ config RTC_DRV_MC13783
help
This enables support for the Freescale MC13783 PMIC RTC
+config RTC_DRV_MPC5121
+ tristate "Freescale MPC5121 built-in RTC"
+ depends on PPC_MPC512x && RTC_CLASS
+ help
+ If you say yes here you will get support for the
+ built-in RTC MPC5121.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-mpc5121.
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index e5160fddc446..44ef194a9573 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -52,9 +52,11 @@ obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_MXC) += rtc-mxc.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
+obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_MC13783) += rtc-mc13783.o
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
+obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index be5a6b73e601..40845c7e9322 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -226,6 +226,7 @@ static void __exit rtc_exit(void)
{
rtc_dev_exit();
class_destroy(rtc_class);
+ idr_destroy(&rtc_idr);
}
subsys_initcall(rtc_init);
diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
index 33c0e98243ee..bc90b091f195 100644
--- a/drivers/rtc/hctosys.c
+++ b/drivers/rtc/hctosys.c
@@ -22,48 +22,57 @@
* the best guess is to add 0.5s.
*/
+int rtc_hctosys_ret = -ENODEV;
+
static int __init rtc_hctosys(void)
{
- int err;
+ int err = -ENODEV;
struct rtc_time tm;
+ struct timespec tv = {
+ .tv_nsec = NSEC_PER_SEC >> 1,
+ };
struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
if (rtc == NULL) {
- printk("%s: unable to open rtc device (%s)\n",
+ pr_err("%s: unable to open rtc device (%s)\n",
__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
- return -ENODEV;
+ goto err_open;
}
err = rtc_read_time(rtc, &tm);
- if (err == 0) {
- err = rtc_valid_tm(&tm);
- if (err == 0) {
- struct timespec tv;
+ if (err) {
+ dev_err(rtc->dev.parent,
+ "hctosys: unable to read the hardware clock\n");
+ goto err_read;
- tv.tv_nsec = NSEC_PER_SEC >> 1;
+ }
- rtc_tm_to_time(&tm, &tv.tv_sec);
+ err = rtc_valid_tm(&tm);
+ if (err) {
+ dev_err(rtc->dev.parent,
+ "hctosys: invalid date/time\n");
+ goto err_invalid;
+ }
- do_settimeofday(&tv);
+ rtc_tm_to_time(&tm, &tv.tv_sec);
- dev_info(rtc->dev.parent,
- "setting system clock to "
- "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n",
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec,
- (unsigned int) tv.tv_sec);
- }
- else
- dev_err(rtc->dev.parent,
- "hctosys: invalid date/time\n");
- }
- else
- dev_err(rtc->dev.parent,
- "hctosys: unable to read the hardware clock\n");
+ do_settimeofday(&tv);
+ dev_info(rtc->dev.parent,
+ "setting system clock to "
+ "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec,
+ (unsigned int) tv.tv_sec);
+
+err_invalid:
+err_read:
rtc_class_close(rtc);
- return 0;
+err_open:
+ rtc_hctosys_ret = err;
+
+ return err;
}
late_initcall(rtc_hctosys);
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index 86c61f143515..78a018b5c941 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -161,7 +161,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
if (offset == 0)
return -EILSEQ;
- memset(alrm, 0, sizeof(alrm));
+ memset(alrm, 0, sizeof(*alrm));
if (alarm != ALARM_DISABLED && offset != 0) {
rtc_time_to_tm(offset + alarm, tm);
diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c
index 03ea530981d1..44c4399ee714 100644
--- a/drivers/rtc/rtc-coh901331.c
+++ b/drivers/rtc/rtc-coh901331.c
@@ -271,12 +271,13 @@ static int coh901331_resume(struct platform_device *pdev)
{
struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
- if (device_may_wakeup(&pdev->dev))
+ if (device_may_wakeup(&pdev->dev)) {
disable_irq_wake(rtap->irq);
- else
+ } else {
clk_enable(rtap->clk);
writel(rtap->irqmaskstore, rtap->virtbase + COH901331_IRQ_MASK);
clk_disable(rtap->clk);
+ }
return 0;
}
#else
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c
index 9da02d108b73..91bde976bc0f 100644
--- a/drivers/rtc/rtc-ep93xx.c
+++ b/drivers/rtc/rtc-ep93xx.c
@@ -115,6 +115,15 @@ static ssize_t ep93xx_rtc_show_comp_delete(struct device *dev,
}
static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_rtc_show_comp_delete, NULL);
+static struct attribute *ep93xx_rtc_attrs[] = {
+ &dev_attr_comp_preload.attr,
+ &dev_attr_comp_delete.attr,
+ NULL
+};
+
+static const struct attribute_group ep93xx_rtc_sysfs_files = {
+ .attrs = ep93xx_rtc_attrs,
+};
static int __init ep93xx_rtc_probe(struct platform_device *pdev)
{
@@ -123,27 +132,22 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
struct rtc_device *rtc;
int err;
- ep93xx_rtc = kzalloc(sizeof(struct ep93xx_rtc), GFP_KERNEL);
- if (ep93xx_rtc == NULL)
+ ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL);
+ if (!ep93xx_rtc)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- err = -ENXIO;
- goto fail_free;
- }
+ if (!res)
+ return -ENXIO;
- res = request_mem_region(res->start, resource_size(res), pdev->name);
- if (res == NULL) {
- err = -EBUSY;
- goto fail_free;
- }
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), pdev->name))
+ return -EBUSY;
- ep93xx_rtc->mmio_base = ioremap(res->start, resource_size(res));
- if (ep93xx_rtc->mmio_base == NULL) {
- err = -ENXIO;
- goto fail;
- }
+ ep93xx_rtc->mmio_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!ep93xx_rtc->mmio_base)
+ return -ENXIO;
pdev->dev.platform_data = ep93xx_rtc;
@@ -151,53 +155,34 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
&pdev->dev, &ep93xx_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
err = PTR_ERR(rtc);
- goto fail;
+ goto exit;
}
platform_set_drvdata(pdev, rtc);
- err = device_create_file(&pdev->dev, &dev_attr_comp_preload);
+ err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
if (err)
goto fail;
- err = device_create_file(&pdev->dev, &dev_attr_comp_delete);
- if (err) {
- device_remove_file(&pdev->dev, &dev_attr_comp_preload);
- goto fail;
- }
return 0;
fail:
- if (ep93xx_rtc->mmio_base) {
- iounmap(ep93xx_rtc->mmio_base);
- pdev->dev.platform_data = NULL;
- }
- release_mem_region(res->start, resource_size(res));
-fail_free:
- kfree(ep93xx_rtc);
+ platform_set_drvdata(pdev, NULL);
+ rtc_device_unregister(rtc);
+exit:
+ pdev->dev.platform_data = NULL;
return err;
}
static int __exit ep93xx_rtc_remove(struct platform_device *pdev)
{
struct rtc_device *rtc = platform_get_drvdata(pdev);
- struct ep93xx_rtc *ep93xx_rtc = pdev->dev.platform_data;
- struct resource *res;
-
- /* cleanup sysfs */
- device_remove_file(&pdev->dev, &dev_attr_comp_delete);
- device_remove_file(&pdev->dev, &dev_attr_comp_preload);
+ sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
+ platform_set_drvdata(pdev, NULL);
rtc_device_unregister(rtc);
-
- iounmap(ep93xx_rtc->mmio_base);
pdev->dev.platform_data = NULL;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
index 3a7be11cc6b9..812c66755083 100644
--- a/drivers/rtc/rtc-fm3130.c
+++ b/drivers/rtc/rtc-fm3130.c
@@ -376,20 +376,22 @@ static int __devinit fm3130_probe(struct i2c_client *client,
}
/* Disabling calibration mode */
- if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL)
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL) {
i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
fm3130->regs[FM3130_RTC_CONTROL] &
~(FM3130_RTC_CONTROL_BIT_CAL));
dev_warn(&client->dev, "Disabling calibration mode!\n");
+ }
/* Disabling read and write modes */
if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_WRITE ||
- fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_READ)
+ fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_READ) {
i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
fm3130->regs[FM3130_RTC_CONTROL] &
~(FM3130_RTC_CONTROL_BIT_READ |
FM3130_RTC_CONTROL_BIT_WRITE));
dev_warn(&client->dev, "Disabling READ or WRITE mode!\n");
+ }
/* oscillator off? turn it on, so clock can tick. */
if (fm3130->regs[FM3130_CAL_CONTROL] & FM3130_CAL_CONTROL_BIT_nOSCEN)
diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c
new file mode 100644
index 000000000000..acdbb1760187
--- /dev/null
+++ b/drivers/rtc/rtc-max8925.c
@@ -0,0 +1,314 @@
+/*
+ * RTC driver for Maxim MAX8925
+ *
+ * Copyright (C) 2009-2010 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max8925.h>
+
+enum {
+ RTC_SEC = 0,
+ RTC_MIN,
+ RTC_HOUR,
+ RTC_WEEKDAY,
+ RTC_DATE,
+ RTC_MONTH,
+ RTC_YEAR1,
+ RTC_YEAR2,
+};
+
+#define MAX8925_RTC_SEC 0x00
+#define MAX8925_RTC_MIN 0x01
+#define MAX8925_RTC_HOUR 0x02
+#define MAX8925_RTC_WEEKDAY 0x03
+#define MAX8925_RTC_DATE 0x04
+#define MAX8925_RTC_MONTH 0x05
+#define MAX8925_RTC_YEAR1 0x06
+#define MAX8925_RTC_YEAR2 0x07
+#define MAX8925_ALARM0_SEC 0x08
+#define MAX8925_ALARM0_MIN 0x09
+#define MAX8925_ALARM0_HOUR 0x0a
+#define MAX8925_ALARM0_WEEKDAY 0x0b
+#define MAX8925_ALARM0_DATE 0x0c
+#define MAX8925_ALARM0_MON 0x0d
+#define MAX8925_ALARM0_YEAR1 0x0e
+#define MAX8925_ALARM0_YEAR2 0x0f
+#define MAX8925_ALARM1_SEC 0x10
+#define MAX8925_ALARM1_MIN 0x11
+#define MAX8925_ALARM1_HOUR 0x12
+#define MAX8925_ALARM1_WEEKDAY 0x13
+#define MAX8925_ALARM1_DATE 0x14
+#define MAX8925_ALARM1_MON 0x15
+#define MAX8925_ALARM1_YEAR1 0x16
+#define MAX8925_ALARM1_YEAR2 0x17
+#define MAX8925_RTC_CNTL 0x1b
+#define MAX8925_RTC_STATUS 0x20
+
+#define TIME_NUM 8
+#define ALARM_1SEC (1 << 7)
+#define HOUR_12 (1 << 7)
+#define HOUR_AM_PM (1 << 5)
+#define ALARM0_IRQ (1 << 3)
+#define ALARM1_IRQ (1 << 2)
+#define ALARM0_STATUS (1 << 2)
+#define ALARM1_STATUS (1 << 1)
+
+
+struct max8925_rtc_info {
+ struct rtc_device *rtc_dev;
+ struct max8925_chip *chip;
+ struct i2c_client *rtc;
+ struct device *dev;
+};
+
+static irqreturn_t rtc_update_handler(int irq, void *data)
+{
+ struct max8925_rtc_info *info = (struct max8925_rtc_info *)data;
+
+ /* disable ALARM0 except for 1SEC alarm */
+ max8925_set_bits(info->rtc, MAX8925_ALARM0_CNTL, 0x7f, 0);
+ rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
+ return IRQ_HANDLED;
+}
+
+static int tm_calc(struct rtc_time *tm, unsigned char *buf, int len)
+{
+ if (len < TIME_NUM)
+ return -EINVAL;
+ tm->tm_year = (buf[RTC_YEAR2] >> 4) * 1000
+ + (buf[RTC_YEAR2] & 0xf) * 100
+ + (buf[RTC_YEAR1] >> 4) * 10
+ + (buf[RTC_YEAR1] & 0xf);
+ tm->tm_year -= 1900;
+ tm->tm_mon = ((buf[RTC_MONTH] >> 4) & 0x01) * 10
+ + (buf[RTC_MONTH] & 0x0f);
+ tm->tm_mday = ((buf[RTC_DATE] >> 4) & 0x03) * 10
+ + (buf[RTC_DATE] & 0x0f);
+ tm->tm_wday = buf[RTC_WEEKDAY] & 0x07;
+ if (buf[RTC_HOUR] & HOUR_12) {
+ tm->tm_hour = ((buf[RTC_HOUR] >> 4) & 0x1) * 10
+ + (buf[RTC_HOUR] & 0x0f);
+ if (buf[RTC_HOUR] & HOUR_AM_PM)
+ tm->tm_hour += 12;
+ } else
+ tm->tm_hour = ((buf[RTC_HOUR] >> 4) & 0x03) * 10
+ + (buf[RTC_HOUR] & 0x0f);
+ tm->tm_min = ((buf[RTC_MIN] >> 4) & 0x7) * 10
+ + (buf[RTC_MIN] & 0x0f);
+ tm->tm_sec = ((buf[RTC_SEC] >> 4) & 0x7) * 10
+ + (buf[RTC_SEC] & 0x0f);
+ return 0;
+}
+
+static int data_calc(unsigned char *buf, struct rtc_time *tm, int len)
+{
+ unsigned char high, low;
+
+ if (len < TIME_NUM)
+ return -EINVAL;
+
+ high = (tm->tm_year + 1900) / 1000;
+ low = (tm->tm_year + 1900) / 100;
+ low = low - high * 10;
+ buf[RTC_YEAR2] = (high << 4) + low;
+ high = (tm->tm_year + 1900) / 10;
+ low = tm->tm_year + 1900;
+ low = low - high * 10;
+ high = high - (high / 10) * 10;
+ buf[RTC_YEAR1] = (high << 4) + low;
+ high = tm->tm_mon / 10;
+ low = tm->tm_mon;
+ low = low - high * 10;
+ buf[RTC_MONTH] = (high << 4) + low;
+ high = tm->tm_mday / 10;
+ low = tm->tm_mday;
+ low = low - high * 10;
+ buf[RTC_DATE] = (high << 4) + low;
+ buf[RTC_WEEKDAY] = tm->tm_wday;
+ high = tm->tm_hour / 10;
+ low = tm->tm_hour;
+ low = low - high * 10;
+ buf[RTC_HOUR] = (high << 4) + low;
+ high = tm->tm_min / 10;
+ low = tm->tm_min;
+ low = low - high * 10;
+ buf[RTC_MIN] = (high << 4) + low;
+ high = tm->tm_sec / 10;
+ low = tm->tm_sec;
+ low = low - high * 10;
+ buf[RTC_SEC] = (high << 4) + low;
+ return 0;
+}
+
+static int max8925_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct max8925_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[TIME_NUM];
+ int ret;
+
+ ret = max8925_bulk_read(info->rtc, MAX8925_RTC_SEC, TIME_NUM, buf);
+ if (ret < 0)
+ goto out;
+ ret = tm_calc(tm, buf, TIME_NUM);
+out:
+ return ret;
+}
+
+static int max8925_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct max8925_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[TIME_NUM];
+ int ret;
+
+ ret = data_calc(buf, tm, TIME_NUM);
+ if (ret < 0)
+ goto out;
+ ret = max8925_bulk_write(info->rtc, MAX8925_RTC_SEC, TIME_NUM, buf);
+out:
+ return ret;
+}
+
+static int max8925_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct max8925_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[TIME_NUM];
+ int ret;
+
+ ret = max8925_bulk_read(info->rtc, MAX8925_ALARM0_SEC, TIME_NUM, buf);
+ if (ret < 0)
+ goto out;
+ ret = tm_calc(&alrm->time, buf, TIME_NUM);
+ if (ret < 0)
+ goto out;
+ ret = max8925_reg_read(info->rtc, MAX8925_RTC_IRQ_MASK);
+ if (ret < 0)
+ goto out;
+ if ((ret & ALARM0_IRQ) == 0)
+ alrm->enabled = 1;
+ else
+ alrm->enabled = 0;
+ ret = max8925_reg_read(info->rtc, MAX8925_RTC_STATUS);
+ if (ret < 0)
+ goto out;
+ if (ret & ALARM0_STATUS)
+ alrm->pending = 1;
+ else
+ alrm->pending = 0;
+out:
+ return ret;
+}
+
+static int max8925_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct max8925_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[TIME_NUM];
+ int ret;
+
+ ret = data_calc(buf, &alrm->time, TIME_NUM);
+ if (ret < 0)
+ goto out;
+ ret = max8925_bulk_write(info->rtc, MAX8925_ALARM0_SEC, TIME_NUM, buf);
+ if (ret < 0)
+ goto out;
+ /* only enable alarm on year/month/day/hour/min/sec */
+ ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x77);
+ if (ret < 0)
+ goto out;
+out:
+ return ret;
+}
+
+static const struct rtc_class_ops max8925_rtc_ops = {
+ .read_time = max8925_rtc_read_time,
+ .set_time = max8925_rtc_set_time,
+ .read_alarm = max8925_rtc_read_alarm,
+ .set_alarm = max8925_rtc_set_alarm,
+};
+
+static int __devinit max8925_rtc_probe(struct platform_device *pdev)
+{
+ struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct max8925_rtc_info *info;
+ int irq, ret;
+
+ info = kzalloc(sizeof(struct max8925_rtc_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->chip = chip;
+ info->rtc = chip->rtc;
+ info->dev = &pdev->dev;
+ irq = chip->irq_base + MAX8925_IRQ_RTC_ALARM0;
+
+ ret = request_threaded_irq(irq, NULL, rtc_update_handler,
+ IRQF_ONESHOT, "rtc-alarm0", info);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+ irq, ret);
+ goto out_irq;
+ }
+
+ info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev,
+ &max8925_rtc_ops, THIS_MODULE);
+ ret = PTR_ERR(info->rtc_dev);
+ if (IS_ERR(info->rtc_dev)) {
+ dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+ goto out_rtc;
+ }
+
+ dev_set_drvdata(&pdev->dev, info);
+ platform_set_drvdata(pdev, info);
+
+ return 0;
+out_rtc:
+ free_irq(chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info);
+out_irq:
+ kfree(info);
+ return ret;
+}
+
+static int __devexit max8925_rtc_remove(struct platform_device *pdev)
+{
+ struct max8925_rtc_info *info = platform_get_drvdata(pdev);
+
+ if (info) {
+ free_irq(info->chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info);
+ rtc_device_unregister(info->rtc_dev);
+ kfree(info);
+ }
+ return 0;
+}
+
+static struct platform_driver max8925_rtc_driver = {
+ .driver = {
+ .name = "max8925-rtc",
+ .owner = THIS_MODULE,
+ },
+ .probe = max8925_rtc_probe,
+ .remove = __devexit_p(max8925_rtc_remove),
+};
+
+static int __init max8925_rtc_init(void)
+{
+ return platform_driver_register(&max8925_rtc_driver);
+}
+module_init(max8925_rtc_init);
+
+static void __exit max8925_rtc_exit(void)
+{
+ platform_driver_unregister(&max8925_rtc_driver);
+}
+module_exit(max8925_rtc_exit);
+
+MODULE_DESCRIPTION("Maxim MAX8925 RTC driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/rtc/rtc-mc13783.c b/drivers/rtc/rtc-mc13783.c
index 850f983c039c..d60c81b7b693 100644
--- a/drivers/rtc/rtc-mc13783.c
+++ b/drivers/rtc/rtc-mc13783.c
@@ -28,6 +28,34 @@ struct mc13783_rtc {
int valid;
};
+static int mc13783_rtc_irq_enable_unlocked(struct device *dev,
+ unsigned int enabled, int irq)
+{
+ struct mc13783_rtc *priv = dev_get_drvdata(dev);
+ int (*func)(struct mc13783 *mc13783, int irq);
+
+ if (!priv->valid)
+ return -ENODATA;
+
+ func = enabled ? mc13783_irq_unmask : mc13783_irq_mask;
+ return func(priv->mc13783, irq);
+}
+
+static int mc13783_rtc_irq_enable(struct device *dev,
+ unsigned int enabled, int irq)
+{
+ struct mc13783_rtc *priv = dev_get_drvdata(dev);
+ int ret;
+
+ mc13783_lock(priv->mc13783);
+
+ ret = mc13783_rtc_irq_enable_unlocked(dev, enabled, irq);
+
+ mc13783_unlock(priv->mc13783);
+
+ return ret;
+}
+
static int mc13783_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct mc13783_rtc *priv = dev_get_drvdata(dev);
@@ -78,6 +106,7 @@ static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs)
{
struct mc13783_rtc *priv = dev_get_drvdata(dev);
unsigned int seconds, days;
+ unsigned int alarmseconds;
int ret;
seconds = secs % 86400;
@@ -86,7 +115,22 @@ static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs)
mc13783_lock(priv->mc13783);
/*
- * first write seconds=0 to prevent a day switch between writing days
+ * temporarily invalidate alarm to prevent triggering it when the day is
+ * already updated while the time isn't yet.
+ */
+ ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTODA, &alarmseconds);
+ if (unlikely(ret))
+ goto out;
+
+ if (alarmseconds < 86400) {
+ ret = mc13783_reg_write(priv->mc13783,
+ MC13783_RTCTODA, 0x1ffff);
+ if (unlikely(ret))
+ goto out;
+ }
+
+ /*
+ * write seconds=0 to prevent a day switch between writing days
* and seconds below
*/
ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, 0);
@@ -101,11 +145,19 @@ static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs)
if (unlikely(ret))
goto out;
- ret = mc13783_ackirq(priv->mc13783, MC13783_IRQ_RTCRST);
+ /* restore alarm */
+ if (alarmseconds < 86400) {
+ ret = mc13783_reg_write(priv->mc13783,
+ MC13783_RTCTODA, alarmseconds);
+ if (unlikely(ret))
+ goto out;
+ }
+
+ ret = mc13783_irq_ack(priv->mc13783, MC13783_IRQ_RTCRST);
if (unlikely(ret))
goto out;
- ret = mc13783_unmask(priv->mc13783, MC13783_IRQ_RTCRST);
+ ret = mc13783_irq_unmask(priv->mc13783, MC13783_IRQ_RTCRST);
out:
priv->valid = !ret;
@@ -114,41 +166,139 @@ out:
return ret;
}
-static irqreturn_t mc13783_rtc_update_handler(int irq, void *dev)
+static int mc13783_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- struct mc13783_rtc *priv = dev;
- struct mc13783 *mc13783 = priv->mc13783;
+ struct mc13783_rtc *priv = dev_get_drvdata(dev);
+ unsigned seconds, days;
+ unsigned long s1970;
+ int enabled, pending;
+ int ret;
- dev_dbg(&priv->rtc->dev, "1HZ\n");
+ mc13783_lock(priv->mc13783);
- rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF);
+ ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTODA, &seconds);
+ if (unlikely(ret))
+ goto out;
+ if (seconds >= 86400) {
+ ret = -ENODATA;
+ goto out;
+ }
+
+ ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days);
+ if (unlikely(ret))
+ goto out;
- mc13783_ackirq(mc13783, irq);
+ ret = mc13783_irq_status(priv->mc13783, MC13783_IRQ_TODA,
+ &enabled, &pending);
- return IRQ_HANDLED;
+out:
+ mc13783_unlock(priv->mc13783);
+
+ if (ret)
+ return ret;
+
+ alarm->enabled = enabled;
+ alarm->pending = pending;
+
+ s1970 = days * 86400 + seconds;
+
+ rtc_time_to_tm(s1970, &alarm->time);
+ dev_dbg(dev, "%s: %lu\n", __func__, s1970);
+
+ return 0;
}
-static int mc13783_rtc_update_irq_enable(struct device *dev,
- unsigned int enabled)
+static int mc13783_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct mc13783_rtc *priv = dev_get_drvdata(dev);
- int ret = -ENODATA;
+ unsigned long s1970;
+ unsigned seconds, days;
+ int ret;
mc13783_lock(priv->mc13783);
- if (!priv->valid)
+
+ /* disable alarm to prevent false triggering */
+ ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTODA, 0x1ffff);
+ if (unlikely(ret))
goto out;
- ret = (enabled ? mc13783_unmask : mc13783_mask)(priv->mc13783,
- MC13783_IRQ_1HZ);
+ ret = mc13783_irq_ack(priv->mc13783, MC13783_IRQ_TODA);
+ if (unlikely(ret))
+ goto out;
+
+ ret = rtc_tm_to_time(&alarm->time, &s1970);
+ if (unlikely(ret))
+ goto out;
+
+ dev_dbg(dev, "%s: o%2.s %lu\n", __func__, alarm->enabled ? "n" : "ff",
+ s1970);
+
+ ret = mc13783_rtc_irq_enable_unlocked(dev, alarm->enabled,
+ MC13783_IRQ_TODA);
+ if (unlikely(ret))
+ goto out;
+
+ seconds = s1970 % 86400;
+ days = s1970 / 86400;
+
+ ret = mc13783_reg_write(priv->mc13783, MC13783_RTCDAYA, days);
+ if (unlikely(ret))
+ goto out;
+
+ ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTODA, seconds);
+
out:
mc13783_unlock(priv->mc13783);
return ret;
}
+static irqreturn_t mc13783_rtc_alarm_handler(int irq, void *dev)
+{
+ struct mc13783_rtc *priv = dev;
+ struct mc13783 *mc13783 = priv->mc13783;
+
+ dev_dbg(&priv->rtc->dev, "Alarm\n");
+
+ rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF);
+
+ mc13783_irq_ack(mc13783, irq);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mc13783_rtc_update_handler(int irq, void *dev)
+{
+ struct mc13783_rtc *priv = dev;
+ struct mc13783 *mc13783 = priv->mc13783;
+
+ dev_dbg(&priv->rtc->dev, "1HZ\n");
+
+ rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF);
+
+ mc13783_irq_ack(mc13783, irq);
+
+ return IRQ_HANDLED;
+}
+
+static int mc13783_rtc_update_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ return mc13783_rtc_irq_enable(dev, enabled, MC13783_IRQ_1HZ);
+}
+
+static int mc13783_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ return mc13783_rtc_irq_enable(dev, enabled, MC13783_IRQ_TODA);
+}
+
static const struct rtc_class_ops mc13783_rtc_ops = {
.read_time = mc13783_rtc_read_time,
.set_mmss = mc13783_rtc_set_mmss,
+ .read_alarm = mc13783_rtc_read_alarm,
+ .set_alarm = mc13783_rtc_set_alarm,
+ .alarm_irq_enable = mc13783_rtc_alarm_irq_enable,
.update_irq_enable = mc13783_rtc_update_irq_enable,
};
@@ -160,7 +310,7 @@ static irqreturn_t mc13783_rtc_reset_handler(int irq, void *dev)
dev_dbg(&priv->rtc->dev, "RTCRST\n");
priv->valid = 0;
- mc13783_mask(mc13783, irq);
+ mc13783_irq_mask(mc13783, irq);
return IRQ_HANDLED;
}
@@ -169,6 +319,7 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev)
{
int ret;
struct mc13783_rtc *priv;
+ int rtcrst_pending;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -177,8 +328,6 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev)
priv->mc13783 = dev_get_drvdata(pdev->dev.parent);
platform_set_drvdata(pdev, priv);
- priv->valid = 1;
-
mc13783_lock(priv->mc13783);
ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_RTCRST,
@@ -186,33 +335,45 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev)
if (ret)
goto err_reset_irq_request;
+ ret = mc13783_irq_status(priv->mc13783, MC13783_IRQ_RTCRST,
+ NULL, &rtcrst_pending);
+ if (ret)
+ goto err_reset_irq_status;
+
+ priv->valid = !rtcrst_pending;
+
ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_1HZ,
mc13783_rtc_update_handler, DRIVER_NAME, priv);
if (ret)
goto err_update_irq_request;
- mc13783_unlock(priv->mc13783);
+ ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_TODA,
+ mc13783_rtc_alarm_handler, DRIVER_NAME, priv);
+ if (ret)
+ goto err_alarm_irq_request;
priv->rtc = rtc_device_register(pdev->name,
&pdev->dev, &mc13783_rtc_ops, THIS_MODULE);
-
if (IS_ERR(priv->rtc)) {
ret = PTR_ERR(priv->rtc);
- mc13783_lock(priv->mc13783);
+ mc13783_irq_free(priv->mc13783, MC13783_IRQ_TODA, priv);
+err_alarm_irq_request:
mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv);
err_update_irq_request:
+err_reset_irq_status:
+
mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv);
err_reset_irq_request:
- mc13783_unlock(priv->mc13783);
-
platform_set_drvdata(pdev, NULL);
kfree(priv);
}
+ mc13783_unlock(priv->mc13783);
+
return ret;
}
@@ -220,10 +381,11 @@ static int __devexit mc13783_rtc_remove(struct platform_device *pdev)
{
struct mc13783_rtc *priv = platform_get_drvdata(pdev);
- rtc_device_unregister(priv->rtc);
-
mc13783_lock(priv->mc13783);
+ rtc_device_unregister(priv->rtc);
+
+ mc13783_irq_free(priv->mc13783, MC13783_IRQ_TODA, priv);
mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv);
mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv);
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
new file mode 100644
index 000000000000..4313ca03a96d
--- /dev/null
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -0,0 +1,387 @@
+/*
+ * Real-time clock driver for MPC5121
+ *
+ * Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
+ * Copyright 2008, Freescale Semiconductor, Inc. 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+
+struct mpc5121_rtc_regs {
+ u8 set_time; /* RTC + 0x00 */
+ u8 hour_set; /* RTC + 0x01 */
+ u8 minute_set; /* RTC + 0x02 */
+ u8 second_set; /* RTC + 0x03 */
+
+ u8 set_date; /* RTC + 0x04 */
+ u8 month_set; /* RTC + 0x05 */
+ u8 weekday_set; /* RTC + 0x06 */
+ u8 date_set; /* RTC + 0x07 */
+
+ u8 write_sw; /* RTC + 0x08 */
+ u8 sw_set; /* RTC + 0x09 */
+ u16 year_set; /* RTC + 0x0a */
+
+ u8 alm_enable; /* RTC + 0x0c */
+ u8 alm_hour_set; /* RTC + 0x0d */
+ u8 alm_min_set; /* RTC + 0x0e */
+ u8 int_enable; /* RTC + 0x0f */
+
+ u8 reserved1;
+ u8 hour; /* RTC + 0x11 */
+ u8 minute; /* RTC + 0x12 */
+ u8 second; /* RTC + 0x13 */
+
+ u8 month; /* RTC + 0x14 */
+ u8 wday_mday; /* RTC + 0x15 */
+ u16 year; /* RTC + 0x16 */
+
+ u8 int_alm; /* RTC + 0x18 */
+ u8 int_sw; /* RTC + 0x19 */
+ u8 alm_status; /* RTC + 0x1a */
+ u8 sw_minute; /* RTC + 0x1b */
+
+ u8 bus_error_1; /* RTC + 0x1c */
+ u8 int_day; /* RTC + 0x1d */
+ u8 int_min; /* RTC + 0x1e */
+ u8 int_sec; /* RTC + 0x1f */
+
+ /*
+ * target_time:
+ * intended to be used for hibernation but hibernation
+ * does not work on silicon rev 1.5 so use it for non-volatile
+ * storage of offset between the actual_time register and linux
+ * time
+ */
+ u32 target_time; /* RTC + 0x20 */
+ /*
+ * actual_time:
+ * readonly time since VBAT_RTC was last connected
+ */
+ u32 actual_time; /* RTC + 0x24 */
+ u32 keep_alive; /* RTC + 0x28 */
+};
+
+struct mpc5121_rtc_data {
+ unsigned irq;
+ unsigned irq_periodic;
+ struct mpc5121_rtc_regs __iomem *regs;
+ struct rtc_device *rtc;
+ struct rtc_wkalrm wkalarm;
+};
+
+/*
+ * Update second/minute/hour registers.
+ *
+ * This is just so alarm will work.
+ */
+static void mpc5121_rtc_update_smh(struct mpc5121_rtc_regs __iomem *regs,
+ struct rtc_time *tm)
+{
+ out_8(&regs->second_set, tm->tm_sec);
+ out_8(&regs->minute_set, tm->tm_min);
+ out_8(&regs->hour_set, tm->tm_hour);
+
+ /* set time sequence */
+ out_8(&regs->set_time, 0x1);
+ out_8(&regs->set_time, 0x3);
+ out_8(&regs->set_time, 0x1);
+ out_8(&regs->set_time, 0x0);
+}
+
+static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+ unsigned long now;
+
+ /*
+ * linux time is actual_time plus the offset saved in target_time
+ */
+ now = in_be32(&regs->actual_time) + in_be32(&regs->target_time);
+
+ rtc_time_to_tm(now, tm);
+
+ /*
+ * update second minute hour registers
+ * so alarms will work
+ */
+ mpc5121_rtc_update_smh(regs, tm);
+
+ return rtc_valid_tm(tm);
+}
+
+static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+ int ret;
+ unsigned long now;
+
+ /*
+ * The actual_time register is read only so we write the offset
+ * between it and linux time to the target_time register.
+ */
+ ret = rtc_tm_to_time(tm, &now);
+ if (ret == 0)
+ out_be32(&regs->target_time, now - in_be32(&regs->actual_time));
+
+ /*
+ * update second minute hour registers
+ * so alarms will work
+ */
+ mpc5121_rtc_update_smh(regs, tm);
+
+ return 0;
+}
+
+static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ *alarm = rtc->wkalarm;
+
+ alarm->pending = in_8(&regs->alm_status);
+
+ return 0;
+}
+
+static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ /*
+ * the alarm has no seconds so deal with it
+ */
+ if (alarm->time.tm_sec) {
+ alarm->time.tm_sec = 0;
+ alarm->time.tm_min++;
+ if (alarm->time.tm_min >= 60) {
+ alarm->time.tm_min = 0;
+ alarm->time.tm_hour++;
+ if (alarm->time.tm_hour >= 24)
+ alarm->time.tm_hour = 0;
+ }
+ }
+
+ alarm->time.tm_mday = -1;
+ alarm->time.tm_mon = -1;
+ alarm->time.tm_year = -1;
+
+ out_8(&regs->alm_min_set, alarm->time.tm_min);
+ out_8(&regs->alm_hour_set, alarm->time.tm_hour);
+
+ out_8(&regs->alm_enable, alarm->enabled);
+
+ rtc->wkalarm = *alarm;
+ return 0;
+}
+
+static irqreturn_t mpc5121_rtc_handler(int irq, void *dev)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ if (in_8(&regs->int_alm)) {
+ /* acknowledge and clear status */
+ out_8(&regs->int_alm, 1);
+ out_8(&regs->alm_status, 1);
+
+ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ if (in_8(&regs->int_sec) && (in_8(&regs->int_enable) & 0x1)) {
+ /* acknowledge */
+ out_8(&regs->int_sec, 1);
+
+ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int mpc5121_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+ int val;
+
+ if (enabled)
+ val = 1;
+ else
+ val = 0;
+
+ out_8(&regs->alm_enable, val);
+ rtc->wkalarm.enabled = val;
+
+ return 0;
+}
+
+static int mpc5121_rtc_update_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+ int val;
+
+ val = in_8(&regs->int_enable);
+
+ if (enabled)
+ val = (val & ~0x8) | 0x1;
+ else
+ val &= ~0x1;
+
+ out_8(&regs->int_enable, val);
+
+ return 0;
+}
+
+static const struct rtc_class_ops mpc5121_rtc_ops = {
+ .read_time = mpc5121_rtc_read_time,
+ .set_time = mpc5121_rtc_set_time,
+ .read_alarm = mpc5121_rtc_read_alarm,
+ .set_alarm = mpc5121_rtc_set_alarm,
+ .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
+ .update_irq_enable = mpc5121_rtc_update_irq_enable,
+};
+
+static int __devinit mpc5121_rtc_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct mpc5121_rtc_data *rtc;
+ int err = 0;
+ u32 ka;
+
+ rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->regs = of_iomap(op->node, 0);
+ if (!rtc->regs) {
+ dev_err(&op->dev, "%s: couldn't map io space\n", __func__);
+ err = -ENOSYS;
+ goto out_free;
+ }
+
+ device_init_wakeup(&op->dev, 1);
+
+ dev_set_drvdata(&op->dev, rtc);
+
+ rtc->irq = irq_of_parse_and_map(op->node, 1);
+ err = request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED,
+ "mpc5121-rtc", &op->dev);
+ if (err) {
+ dev_err(&op->dev, "%s: could not request irq: %i\n",
+ __func__, rtc->irq);
+ goto out_dispose;
+ }
+
+ rtc->irq_periodic = irq_of_parse_and_map(op->node, 0);
+ err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd,
+ IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev);
+ if (err) {
+ dev_err(&op->dev, "%s: could not request irq: %i\n",
+ __func__, rtc->irq_periodic);
+ goto out_dispose2;
+ }
+
+ ka = in_be32(&rtc->regs->keep_alive);
+ if (ka & 0x02) {
+ dev_warn(&op->dev,
+ "mpc5121-rtc: Battery or oscillator failure!\n");
+ out_be32(&rtc->regs->keep_alive, ka);
+ }
+
+ rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev,
+ &mpc5121_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc)) {
+ err = PTR_ERR(rtc->rtc);
+ goto out_free_irq;
+ }
+
+ return 0;
+
+out_free_irq:
+ free_irq(rtc->irq_periodic, &op->dev);
+out_dispose2:
+ irq_dispose_mapping(rtc->irq_periodic);
+ free_irq(rtc->irq, &op->dev);
+out_dispose:
+ irq_dispose_mapping(rtc->irq);
+ iounmap(rtc->regs);
+out_free:
+ kfree(rtc);
+
+ return err;
+}
+
+static int __devexit mpc5121_rtc_remove(struct of_device *op)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(&op->dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ /* disable interrupt, so there are no nasty surprises */
+ out_8(&regs->alm_enable, 0);
+ out_8(&regs->int_enable, in_8(&regs->int_enable) & ~0x1);
+
+ rtc_device_unregister(rtc->rtc);
+ iounmap(rtc->regs);
+ free_irq(rtc->irq, &op->dev);
+ free_irq(rtc->irq_periodic, &op->dev);
+ irq_dispose_mapping(rtc->irq);
+ irq_dispose_mapping(rtc->irq_periodic);
+ dev_set_drvdata(&op->dev, NULL);
+ kfree(rtc);
+
+ return 0;
+}
+
+static struct of_device_id mpc5121_rtc_match[] __devinitdata = {
+ { .compatible = "fsl,mpc5121-rtc", },
+ {},
+};
+
+static struct of_platform_driver mpc5121_rtc_driver = {
+ .owner = THIS_MODULE,
+ .name = "mpc5121-rtc",
+ .match_table = mpc5121_rtc_match,
+ .probe = mpc5121_rtc_probe,
+ .remove = __devexit_p(mpc5121_rtc_remove),
+};
+
+static int __init mpc5121_rtc_init(void)
+{
+ return of_register_platform_driver(&mpc5121_rtc_driver);
+}
+module_init(mpc5121_rtc_init);
+
+static void __exit mpc5121_rtc_exit(void)
+{
+ of_unregister_platform_driver(&mpc5121_rtc_driver);
+}
+module_exit(mpc5121_rtc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Rigby <jcrigby@gmail.com>");
diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c
index 6bd5072d4eb7..8710f9415d98 100644
--- a/drivers/rtc/rtc-mxc.c
+++ b/drivers/rtc/rtc-mxc.c
@@ -396,8 +396,11 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
pdata->ioaddr = ioremap(res->start, resource_size(res));
clk = clk_get(&pdev->dev, "ckil");
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ if (IS_ERR(clk)) {
+ iounmap(pdata->ioaddr);
+ ret = PTR_ERR(clk);
+ goto exit_free_pdata;
+ }
rate = clk_get_rate(clk);
clk_put(clk);
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index e75df9d50e27..2ceb365533b2 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -315,7 +315,7 @@ kfree_exit:
return ret;
}
-static int pcf2123_remove(struct spi_device *spi)
+static int __devexit pcf2123_remove(struct spi_device *spi)
{
struct pcf2123_plat_data *pdata = spi->dev.platform_data;
int i;
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index 0264b117893b..c256aacfa954 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -7,6 +7,9 @@
*
* Copyright 2006 (c) MontaVista Software, Inc.
*
+ * Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
+ * Copyright 2010 (c) ST-Ericsson AB
+ *
* 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
@@ -18,6 +21,9 @@
#include <linux/interrupt.h>
#include <linux/amba/bus.h>
#include <linux/io.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/version.h>
/*
* Register definitions
@@ -30,35 +36,207 @@
#define RTC_RIS 0x14 /* Raw interrupt status register */
#define RTC_MIS 0x18 /* Masked interrupt status register */
#define RTC_ICR 0x1c /* Interrupt clear register */
+/* ST variants have additional timer functionality */
+#define RTC_TDR 0x20 /* Timer data read register */
+#define RTC_TLR 0x24 /* Timer data load register */
+#define RTC_TCR 0x28 /* Timer control register */
+#define RTC_YDR 0x30 /* Year data read register */
+#define RTC_YMR 0x34 /* Year match register */
+#define RTC_YLR 0x38 /* Year data load register */
+
+#define RTC_CR_CWEN (1 << 26) /* Clockwatch enable bit */
+
+#define RTC_TCR_EN (1 << 1) /* Periodic timer enable bit */
+
+/* Common bit definitions for Interrupt status and control registers */
+#define RTC_BIT_AI (1 << 0) /* Alarm interrupt bit */
+#define RTC_BIT_PI (1 << 1) /* Periodic interrupt bit. ST variants only. */
+
+/* Common bit definations for ST v2 for reading/writing time */
+#define RTC_SEC_SHIFT 0
+#define RTC_SEC_MASK (0x3F << RTC_SEC_SHIFT) /* Second [0-59] */
+#define RTC_MIN_SHIFT 6
+#define RTC_MIN_MASK (0x3F << RTC_MIN_SHIFT) /* Minute [0-59] */
+#define RTC_HOUR_SHIFT 12
+#define RTC_HOUR_MASK (0x1F << RTC_HOUR_SHIFT) /* Hour [0-23] */
+#define RTC_WDAY_SHIFT 17
+#define RTC_WDAY_MASK (0x7 << RTC_WDAY_SHIFT) /* Day of Week [1-7] 1=Sunday */
+#define RTC_MDAY_SHIFT 20
+#define RTC_MDAY_MASK (0x1F << RTC_MDAY_SHIFT) /* Day of Month [1-31] */
+#define RTC_MON_SHIFT 25
+#define RTC_MON_MASK (0xF << RTC_MON_SHIFT) /* Month [1-12] 1=January */
+
+#define RTC_TIMER_FREQ 32768
struct pl031_local {
struct rtc_device *rtc;
void __iomem *base;
+ u8 hw_designer;
+ u8 hw_revision:4;
};
-static irqreturn_t pl031_interrupt(int irq, void *dev_id)
+static int pl031_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+ unsigned long imsc;
+
+ /* Clear any pending alarm interrupts. */
+ writel(RTC_BIT_AI, ldata->base + RTC_ICR);
+
+ imsc = readl(ldata->base + RTC_IMSC);
+
+ if (enabled == 1)
+ writel(imsc | RTC_BIT_AI, ldata->base + RTC_IMSC);
+ else
+ writel(imsc & ~RTC_BIT_AI, ldata->base + RTC_IMSC);
+
+ return 0;
+}
+
+/*
+ * Convert Gregorian date to ST v2 RTC format.
+ */
+static int pl031_stv2_tm_to_time(struct device *dev,
+ struct rtc_time *tm, unsigned long *st_time,
+ unsigned long *bcd_year)
+{
+ int year = tm->tm_year + 1900;
+ int wday = tm->tm_wday;
+
+ /* wday masking is not working in hardware so wday must be valid */
+ if (wday < -1 || wday > 6) {
+ dev_err(dev, "invalid wday value %d\n", tm->tm_wday);
+ return -EINVAL;
+ } else if (wday == -1) {
+ /* wday is not provided, calculate it here */
+ unsigned long time;
+ struct rtc_time calc_tm;
+
+ rtc_tm_to_time(tm, &time);
+ rtc_time_to_tm(time, &calc_tm);
+ wday = calc_tm.tm_wday;
+ }
+
+ *bcd_year = (bin2bcd(year % 100) | bin2bcd(year / 100) << 8);
+
+ *st_time = ((tm->tm_mon + 1) << RTC_MON_SHIFT)
+ | (tm->tm_mday << RTC_MDAY_SHIFT)
+ | ((wday + 1) << RTC_WDAY_SHIFT)
+ | (tm->tm_hour << RTC_HOUR_SHIFT)
+ | (tm->tm_min << RTC_MIN_SHIFT)
+ | (tm->tm_sec << RTC_SEC_SHIFT);
+
+ return 0;
+}
+
+/*
+ * Convert ST v2 RTC format to Gregorian date.
+ */
+static int pl031_stv2_time_to_tm(unsigned long st_time, unsigned long bcd_year,
+ struct rtc_time *tm)
+{
+ tm->tm_year = bcd2bin(bcd_year) + (bcd2bin(bcd_year >> 8) * 100);
+ tm->tm_mon = ((st_time & RTC_MON_MASK) >> RTC_MON_SHIFT) - 1;
+ tm->tm_mday = ((st_time & RTC_MDAY_MASK) >> RTC_MDAY_SHIFT);
+ tm->tm_wday = ((st_time & RTC_WDAY_MASK) >> RTC_WDAY_SHIFT) - 1;
+ tm->tm_hour = ((st_time & RTC_HOUR_MASK) >> RTC_HOUR_SHIFT);
+ tm->tm_min = ((st_time & RTC_MIN_MASK) >> RTC_MIN_SHIFT);
+ tm->tm_sec = ((st_time & RTC_SEC_MASK) >> RTC_SEC_SHIFT);
+
+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+ tm->tm_year -= 1900;
+
+ return 0;
+}
+
+static int pl031_stv2_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ pl031_stv2_time_to_tm(readl(ldata->base + RTC_DR),
+ readl(ldata->base + RTC_YDR), tm);
+
+ return 0;
+}
+
+static int pl031_stv2_set_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned long time;
+ unsigned long bcd_year;
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pl031_stv2_tm_to_time(dev, tm, &time, &bcd_year);
+ if (ret == 0) {
+ writel(bcd_year, ldata->base + RTC_YLR);
+ writel(time, ldata->base + RTC_LR);
+ }
+
+ return ret;
+}
+
+static int pl031_stv2_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- struct rtc_device *rtc = dev_id;
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+ int ret;
- rtc_update_irq(rtc, 1, RTC_AF);
+ ret = pl031_stv2_time_to_tm(readl(ldata->base + RTC_MR),
+ readl(ldata->base + RTC_YMR), &alarm->time);
- return IRQ_HANDLED;
+ alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
+ alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
+
+ return ret;
}
-static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int pl031_stv2_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct pl031_local *ldata = dev_get_drvdata(dev);
+ unsigned long time;
+ unsigned long bcd_year;
+ int ret;
+
+ /* At the moment, we can only deal with non-wildcarded alarm times. */
+ ret = rtc_valid_tm(&alarm->time);
+ if (ret == 0) {
+ ret = pl031_stv2_tm_to_time(dev, &alarm->time,
+ &time, &bcd_year);
+ if (ret == 0) {
+ writel(bcd_year, ldata->base + RTC_YMR);
+ writel(time, ldata->base + RTC_MR);
+
+ pl031_alarm_irq_enable(dev, alarm->enabled);
+ }
+ }
+
+ return ret;
+}
+
+static irqreturn_t pl031_interrupt(int irq, void *dev_id)
+{
+ struct pl031_local *ldata = dev_id;
+ unsigned long rtcmis;
+ unsigned long events = 0;
+
+ rtcmis = readl(ldata->base + RTC_MIS);
+ if (rtcmis) {
+ writel(rtcmis, ldata->base + RTC_ICR);
+
+ if (rtcmis & RTC_BIT_AI)
+ events |= (RTC_AF | RTC_IRQF);
+
+ /* Timer interrupt is only available in ST variants */
+ if ((rtcmis & RTC_BIT_PI) &&
+ (ldata->hw_designer == AMBA_VENDOR_ST))
+ events |= (RTC_PF | RTC_IRQF);
+
+ rtc_update_irq(ldata->rtc, 1, events);
- switch (cmd) {
- case RTC_AIE_OFF:
- writel(1, ldata->base + RTC_MIS);
- return 0;
- case RTC_AIE_ON:
- writel(0, ldata->base + RTC_MIS);
- return 0;
+ return IRQ_HANDLED;
}
- return -ENOIOCTLCMD;
+ return IRQ_NONE;
}
static int pl031_read_time(struct device *dev, struct rtc_time *tm)
@@ -74,11 +252,14 @@ static int pl031_set_time(struct device *dev, struct rtc_time *tm)
{
unsigned long time;
struct pl031_local *ldata = dev_get_drvdata(dev);
+ int ret;
- rtc_tm_to_time(tm, &time);
- writel(time, ldata->base + RTC_LR);
+ ret = rtc_tm_to_time(tm, &time);
- return 0;
+ if (ret == 0)
+ writel(time, ldata->base + RTC_LR);
+
+ return ret;
}
static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
@@ -86,8 +267,9 @@ static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
struct pl031_local *ldata = dev_get_drvdata(dev);
rtc_time_to_tm(readl(ldata->base + RTC_MR), &alarm->time);
- alarm->pending = readl(ldata->base + RTC_RIS);
- alarm->enabled = readl(ldata->base + RTC_IMSC);
+
+ alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
+ alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
return 0;
}
@@ -96,22 +278,71 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct pl031_local *ldata = dev_get_drvdata(dev);
unsigned long time;
+ int ret;
+
+ /* At the moment, we can only deal with non-wildcarded alarm times. */
+ ret = rtc_valid_tm(&alarm->time);
+ if (ret == 0) {
+ ret = rtc_tm_to_time(&alarm->time, &time);
+ if (ret == 0) {
+ writel(time, ldata->base + RTC_MR);
+ pl031_alarm_irq_enable(dev, alarm->enabled);
+ }
+ }
+
+ return ret;
+}
+
+/* Periodic interrupt is only available in ST variants. */
+static int pl031_irq_set_state(struct device *dev, int enabled)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ if (enabled == 1) {
+ /* Clear any pending timer interrupt. */
+ writel(RTC_BIT_PI, ldata->base + RTC_ICR);
+
+ writel(readl(ldata->base + RTC_IMSC) | RTC_BIT_PI,
+ ldata->base + RTC_IMSC);
- rtc_tm_to_time(&alarm->time, &time);
+ /* Now start the timer */
+ writel(readl(ldata->base + RTC_TCR) | RTC_TCR_EN,
+ ldata->base + RTC_TCR);
- writel(time, ldata->base + RTC_MR);
- writel(!alarm->enabled, ldata->base + RTC_MIS);
+ } else {
+ writel(readl(ldata->base + RTC_IMSC) & (~RTC_BIT_PI),
+ ldata->base + RTC_IMSC);
+
+ /* Also stop the timer */
+ writel(readl(ldata->base + RTC_TCR) & (~RTC_TCR_EN),
+ ldata->base + RTC_TCR);
+ }
+ /* Wait at least 1 RTC32 clock cycle to ensure next access
+ * to RTC_TCR will succeed.
+ */
+ udelay(40);
return 0;
}
-static const struct rtc_class_ops pl031_ops = {
- .ioctl = pl031_ioctl,
- .read_time = pl031_read_time,
- .set_time = pl031_set_time,
- .read_alarm = pl031_read_alarm,
- .set_alarm = pl031_set_alarm,
-};
+static int pl031_irq_set_freq(struct device *dev, int freq)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ /* Cant set timer if it is already enabled */
+ if (readl(ldata->base + RTC_TCR) & RTC_TCR_EN) {
+ dev_err(dev, "can't change frequency while timer enabled\n");
+ return -EINVAL;
+ }
+
+ /* If self start bit in RTC_TCR is set timer will start here,
+ * but we never set that bit. Instead we start the timer when
+ * set_state is called with enabled == 1.
+ */
+ writel(RTC_TIMER_FREQ / freq, ldata->base + RTC_TLR);
+
+ return 0;
+}
static int pl031_remove(struct amba_device *adev)
{
@@ -131,18 +362,20 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id)
{
int ret;
struct pl031_local *ldata;
+ struct rtc_class_ops *ops = id->data;
ret = amba_request_regions(adev, NULL);
if (ret)
goto err_req;
- ldata = kmalloc(sizeof(struct pl031_local), GFP_KERNEL);
+ ldata = kzalloc(sizeof(struct pl031_local), GFP_KERNEL);
if (!ldata) {
ret = -ENOMEM;
goto out;
}
ldata->base = ioremap(adev->res.start, resource_size(&adev->res));
+
if (!ldata->base) {
ret = -ENOMEM;
goto out_no_remap;
@@ -150,24 +383,36 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id)
amba_set_drvdata(adev, ldata);
- if (request_irq(adev->irq[0], pl031_interrupt, IRQF_DISABLED,
- "rtc-pl031", ldata->rtc)) {
- ret = -EIO;
- goto out_no_irq;
- }
+ ldata->hw_designer = amba_manf(adev);
+ ldata->hw_revision = amba_rev(adev);
+
+ dev_dbg(&adev->dev, "designer ID = 0x%02x\n", ldata->hw_designer);
+ dev_dbg(&adev->dev, "revision = 0x%01x\n", ldata->hw_revision);
- ldata->rtc = rtc_device_register("pl031", &adev->dev, &pl031_ops,
- THIS_MODULE);
+ /* Enable the clockwatch on ST Variants */
+ if ((ldata->hw_designer == AMBA_VENDOR_ST) &&
+ (ldata->hw_revision > 1))
+ writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN,
+ ldata->base + RTC_CR);
+
+ ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,
+ THIS_MODULE);
if (IS_ERR(ldata->rtc)) {
ret = PTR_ERR(ldata->rtc);
goto out_no_rtc;
}
+ if (request_irq(adev->irq[0], pl031_interrupt,
+ IRQF_DISABLED | IRQF_SHARED, "rtc-pl031", ldata)) {
+ ret = -EIO;
+ goto out_no_irq;
+ }
+
return 0;
-out_no_rtc:
- free_irq(adev->irq[0], ldata->rtc);
out_no_irq:
+ rtc_device_unregister(ldata->rtc);
+out_no_rtc:
iounmap(ldata->base);
amba_set_drvdata(adev, NULL);
out_no_remap:
@@ -175,13 +420,57 @@ out_no_remap:
out:
amba_release_regions(adev);
err_req:
+
return ret;
}
+/* Operations for the original ARM version */
+static struct rtc_class_ops arm_pl031_ops = {
+ .read_time = pl031_read_time,
+ .set_time = pl031_set_time,
+ .read_alarm = pl031_read_alarm,
+ .set_alarm = pl031_set_alarm,
+ .alarm_irq_enable = pl031_alarm_irq_enable,
+};
+
+/* The First ST derivative */
+static struct rtc_class_ops stv1_pl031_ops = {
+ .read_time = pl031_read_time,
+ .set_time = pl031_set_time,
+ .read_alarm = pl031_read_alarm,
+ .set_alarm = pl031_set_alarm,
+ .alarm_irq_enable = pl031_alarm_irq_enable,
+ .irq_set_state = pl031_irq_set_state,
+ .irq_set_freq = pl031_irq_set_freq,
+};
+
+/* And the second ST derivative */
+static struct rtc_class_ops stv2_pl031_ops = {
+ .read_time = pl031_stv2_read_time,
+ .set_time = pl031_stv2_set_time,
+ .read_alarm = pl031_stv2_read_alarm,
+ .set_alarm = pl031_stv2_set_alarm,
+ .alarm_irq_enable = pl031_alarm_irq_enable,
+ .irq_set_state = pl031_irq_set_state,
+ .irq_set_freq = pl031_irq_set_freq,
+};
+
static struct amba_id pl031_ids[] __initdata = {
{
.id = 0x00041031,
.mask = 0x000fffff,
+ .data = &arm_pl031_ops,
+ },
+ /* ST Micro variants */
+ {
+ .id = 0x00180031,
+ .mask = 0x00ffffff,
+ .data = &stv1_pl031_ops,
+ },
+ {
+ .id = 0x00280031,
+ .mask = 0x00ffffff,
+ .data = &stv2_pl031_ops,
},
{0, 0},
};
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 7dd23a6fc825..380083ca572f 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -107,8 +107,9 @@ rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr,
char *buf)
{
#ifdef CONFIG_RTC_HCTOSYS_DEVICE
- if (strcmp(dev_name(&to_rtc_device(dev)->dev),
- CONFIG_RTC_HCTOSYS_DEVICE) == 0)
+ if (rtc_hctosys_ret == 0 &&
+ strcmp(dev_name(&to_rtc_device(dev)->dev),
+ CONFIG_RTC_HCTOSYS_DEVICE) == 0)
return sprintf(buf, "1\n");
else
#endif
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index c6a83a2a722c..ed1b86828124 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -57,7 +57,7 @@ enum {
REG_RTC_COMP_LSB_REG,
REG_RTC_COMP_MSB_REG,
};
-const static u8 twl4030_rtc_reg_map[] = {
+static const u8 twl4030_rtc_reg_map[] = {
[REG_SECONDS_REG] = 0x00,
[REG_MINUTES_REG] = 0x01,
[REG_HOURS_REG] = 0x02,
@@ -80,7 +80,7 @@ const static u8 twl4030_rtc_reg_map[] = {
[REG_RTC_COMP_LSB_REG] = 0x10,
[REG_RTC_COMP_MSB_REG] = 0x11,
};
-const static u8 twl6030_rtc_reg_map[] = {
+static const u8 twl6030_rtc_reg_map[] = {
[REG_SECONDS_REG] = 0x00,
[REG_MINUTES_REG] = 0x01,
[REG_HOURS_REG] = 0x02,
diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c
index f1e440521c54..3d0dc76b38af 100644
--- a/drivers/rtc/rtc-wm8350.c
+++ b/drivers/rtc/rtc-wm8350.c
@@ -307,11 +307,18 @@ static int wm8350_rtc_update_irq_enable(struct device *dev,
{
struct wm8350 *wm8350 = dev_get_drvdata(dev);
+ /* Suppress duplicate changes since genirq nests enable and
+ * disable calls. */
+ if (enabled == wm8350->rtc.update_enabled)
+ return 0;
+
if (enabled)
wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_SEC);
else
wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
+ wm8350->rtc.update_enabled = enabled;
+
return 0;
}
@@ -478,8 +485,8 @@ static int __devexit wm8350_rtc_remove(struct platform_device *pdev)
struct wm8350 *wm8350 = platform_get_drvdata(pdev);
struct wm8350_rtc *wm_rtc = &wm8350->rtc;
- wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC);
- wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM);
+ wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC, wm8350);
+ wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM, wm8350);
rtc_device_unregister(wm_rtc->rtc);
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index fdb2e7c14506..bbea90baf98f 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -20,11 +20,13 @@
#include <linux/buffer_head.h>
#include <linux/hdreg.h>
#include <linux/async.h>
+#include <linux/mutex.h>
#include <asm/ccwdev.h>
#include <asm/ebcdic.h>
#include <asm/idals.h>
#include <asm/itcw.h>
+#include <asm/diag.h>
/* This is ugly... */
#define PRINTK_HEADER "dasd:"
@@ -112,6 +114,7 @@ struct dasd_device *dasd_alloc_device(void)
INIT_WORK(&device->restore_device, do_restore_device);
device->state = DASD_STATE_NEW;
device->target = DASD_STATE_NEW;
+ mutex_init(&device->state_mutex);
return device;
}
@@ -321,8 +324,8 @@ static int dasd_state_ready_to_basic(struct dasd_device *device)
device->state = DASD_STATE_READY;
return rc;
}
- dasd_destroy_partitions(block);
dasd_flush_request_queue(block);
+ dasd_destroy_partitions(block);
block->blocks = 0;
block->bp_block = 0;
block->s2b_shift = 0;
@@ -484,10 +487,8 @@ static void dasd_change_state(struct dasd_device *device)
if (rc)
device->target = device->state;
- if (device->state == device->target) {
+ if (device->state == device->target)
wake_up(&dasd_init_waitq);
- dasd_put_device(device);
- }
/* let user-space know that the device status changed */
kobject_uevent(&device->cdev->dev.kobj, KOBJ_CHANGE);
@@ -502,7 +503,9 @@ static void dasd_change_state(struct dasd_device *device)
static void do_kick_device(struct work_struct *work)
{
struct dasd_device *device = container_of(work, struct dasd_device, kick_work);
+ mutex_lock(&device->state_mutex);
dasd_change_state(device);
+ mutex_unlock(&device->state_mutex);
dasd_schedule_device_bh(device);
dasd_put_device(device);
}
@@ -539,18 +542,19 @@ void dasd_restore_device(struct dasd_device *device)
void dasd_set_target_state(struct dasd_device *device, int target)
{
dasd_get_device(device);
+ mutex_lock(&device->state_mutex);
/* If we are in probeonly mode stop at DASD_STATE_READY. */
if (dasd_probeonly && target > DASD_STATE_READY)
target = DASD_STATE_READY;
if (device->target != target) {
- if (device->state == target) {
+ if (device->state == target)
wake_up(&dasd_init_waitq);
- dasd_put_device(device);
- }
device->target = target;
}
if (device->state != device->target)
dasd_change_state(device);
+ mutex_unlock(&device->state_mutex);
+ dasd_put_device(device);
}
/*
@@ -1000,12 +1004,20 @@ static void dasd_handle_killed_request(struct ccw_device *cdev,
return;
}
- device = (struct dasd_device *) cqr->startdev;
- if (device == NULL ||
- device != dasd_device_from_cdev_locked(cdev) ||
- strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
- DBF_DEV_EVENT(DBF_DEBUG, device, "invalid device in request: "
- "bus_id %s", dev_name(&cdev->dev));
+ device = dasd_device_from_cdev_locked(cdev);
+ if (IS_ERR(device)) {
+ DBF_EVENT_DEVID(DBF_DEBUG, cdev, "%s",
+ "unable to get device from cdev");
+ return;
+ }
+
+ if (!cqr->startdev ||
+ device != cqr->startdev ||
+ strncmp(cqr->startdev->discipline->ebcname,
+ (char *) &cqr->magic, 4)) {
+ DBF_EVENT_DEVID(DBF_DEBUG, cdev, "%s",
+ "invalid device in request");
+ dasd_put_device(device);
return;
}
@@ -1078,8 +1090,8 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
device = (struct dasd_device *) cqr->startdev;
if (!device ||
strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
- DBF_DEV_EVENT(DBF_DEBUG, device, "invalid device in request: "
- "bus_id %s", dev_name(&cdev->dev));
+ DBF_EVENT_DEVID(DBF_DEBUG, cdev, "%s",
+ "invalid device in request");
return;
}
@@ -1692,7 +1704,6 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr)
cqr, rc);
} else {
cqr->stopclk = get_clock();
- rc = 1;
}
break;
default: /* already finished or clear pending - do nothing */
@@ -2129,9 +2140,8 @@ static void dasd_setup_queue(struct dasd_block *block)
blk_queue_logical_block_size(block->request_queue, block->bp_block);
max = block->base->discipline->max_blocks << block->s2b_shift;
- blk_queue_max_sectors(block->request_queue, max);
- blk_queue_max_phys_segments(block->request_queue, -1L);
- blk_queue_max_hw_segments(block->request_queue, -1L);
+ blk_queue_max_hw_sectors(block->request_queue, max);
+ blk_queue_max_segments(block->request_queue, -1L);
/* with page sized segments we can translate each segement into
* one idaw/tidaw
*/
@@ -2170,9 +2180,13 @@ static void dasd_flush_request_queue(struct dasd_block *block)
static int dasd_open(struct block_device *bdev, fmode_t mode)
{
struct dasd_block *block = bdev->bd_disk->private_data;
- struct dasd_device *base = block->base;
+ struct dasd_device *base;
int rc;
+ if (!block)
+ return -ENODEV;
+
+ base = block->base;
atomic_inc(&block->open_count);
if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) {
rc = -ENODEV;
@@ -2199,6 +2213,13 @@ static int dasd_open(struct block_device *bdev, fmode_t mode)
goto out;
}
+ if ((mode & FMODE_WRITE) &&
+ (test_bit(DASD_FLAG_DEVICE_RO, &base->flags) ||
+ (base->features & DASD_FEATURE_READONLY))) {
+ rc = -EROFS;
+ goto out;
+ }
+
return 0;
out:
@@ -2276,6 +2297,34 @@ dasd_exit(void)
* SECTION: common functions for ccw_driver use
*/
+/*
+ * Is the device read-only?
+ * Note that this function does not report the setting of the
+ * readonly device attribute, but how it is configured in z/VM.
+ */
+int dasd_device_is_ro(struct dasd_device *device)
+{
+ struct ccw_dev_id dev_id;
+ struct diag210 diag_data;
+ int rc;
+
+ if (!MACHINE_IS_VM)
+ return 0;
+ ccw_device_get_id(device->cdev, &dev_id);
+ memset(&diag_data, 0, sizeof(diag_data));
+ diag_data.vrdcdvno = dev_id.devno;
+ diag_data.vrdclen = sizeof(diag_data);
+ rc = diag210(&diag_data);
+ if (rc == 0 || rc == 2) {
+ return diag_data.vrdcvfla & 0x80;
+ } else {
+ DBF_EVENT(DBF_WARNING, "diag210 failed for dev=%04x with rc=%d",
+ dev_id.devno, rc);
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(dasd_device_is_ro);
+
static void dasd_generic_auto_online(void *data, async_cookie_t cookie)
{
struct ccw_device *cdev = data;
@@ -2285,11 +2334,6 @@ static void dasd_generic_auto_online(void *data, async_cookie_t cookie)
if (ret)
pr_warning("%s: Setting the DASD online failed with rc=%d\n",
dev_name(&cdev->dev), ret);
- else {
- struct dasd_device *device = dasd_device_from_cdev(cdev);
- wait_event(dasd_init_waitq, _wait_for_device(device));
- dasd_put_device(device);
- }
}
/*
@@ -2424,6 +2468,9 @@ int dasd_generic_set_online(struct ccw_device *cdev,
} else
pr_debug("dasd_generic device %s found\n",
dev_name(&cdev->dev));
+
+ wait_event(dasd_init_waitq, _wait_for_device(device));
+
dasd_put_device(device);
return rc;
}
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 44796ba4eb9b..51224f76b980 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -1045,6 +1045,10 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
erp->retries = 5;
+ } else if (sense[1] & SNS1_WRITE_INHIBITED) {
+ dev_err(&device->cdev->dev, "An I/O request was rejected"
+ " because writing is inhibited\n");
+ erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
} else {
/* fatal error - set status to FAILED
internal error 09 - Command Reject */
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 4cac5b54f26a..8e23919c8704 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -742,6 +742,7 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct dasd_devmap *devmap;
+ struct dasd_device *device;
int val;
char *endp;
@@ -758,12 +759,14 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
devmap->features |= DASD_FEATURE_READONLY;
else
devmap->features &= ~DASD_FEATURE_READONLY;
- if (devmap->device)
- devmap->device->features = devmap->features;
- if (devmap->device && devmap->device->block
- && devmap->device->block->gdp)
- set_disk_ro(devmap->device->block->gdp, val);
+ device = devmap->device;
+ if (device) {
+ device->features = devmap->features;
+ val = val || test_bit(DASD_FLAG_DEVICE_RO, &device->flags);
+ }
spin_unlock(&dasd_devmap_lock);
+ if (device && device->block && device->block->gdp)
+ set_disk_ro(device->block->gdp, val);
return count;
}
@@ -874,12 +877,19 @@ dasd_discipline_show(struct device *dev, struct device_attribute *attr,
ssize_t len;
device = dasd_device_from_cdev(to_ccwdev(dev));
- if (!IS_ERR(device) && device->discipline) {
+ if (IS_ERR(device))
+ goto out;
+ else if (!device->discipline) {
+ dasd_put_device(device);
+ goto out;
+ } else {
len = snprintf(buf, PAGE_SIZE, "%s\n",
device->discipline->name);
dasd_put_device(device);
- } else
- len = snprintf(buf, PAGE_SIZE, "none\n");
+ return len;
+ }
+out:
+ len = snprintf(buf, PAGE_SIZE, "none\n");
return len;
}
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 6e14863f5c70..687f323cdc38 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -145,12 +145,10 @@ dasd_diag_erp(struct dasd_device *device)
mdsk_term_io(device);
rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
if (rc == 4) {
- if (!(device->features & DASD_FEATURE_READONLY)) {
+ if (!(test_and_set_bit(DASD_FLAG_DEVICE_RO, &device->flags)))
pr_warning("%s: The access mode of a DIAG device "
"changed to read-only\n",
dev_name(&device->cdev->dev));
- device->features |= DASD_FEATURE_READONLY;
- }
rc = 0;
}
if (rc)
@@ -449,7 +447,7 @@ dasd_diag_check_device(struct dasd_device *device)
rc = -EIO;
} else {
if (rc == 4)
- device->features |= DASD_FEATURE_READONLY;
+ set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
pr_info("%s: New DASD with %ld byte/block, total size %ld "
"KB%s\n", dev_name(&device->cdev->dev),
(unsigned long) block->bp_block,
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 1c500c462225..01f4e7a34aa8 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1089,6 +1089,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
struct dasd_eckd_private *private;
struct dasd_block *block;
int is_known, rc;
+ int readonly;
if (!ccw_device_is_pathgroup(device->cdev)) {
dev_warn(&device->cdev->dev,
@@ -1182,15 +1183,20 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
else
private->real_cyl = private->rdc_data.no_cyl;
+ readonly = dasd_device_is_ro(device);
+ if (readonly)
+ set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
+
dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) "
- "with %d cylinders, %d heads, %d sectors\n",
+ "with %d cylinders, %d heads, %d sectors%s\n",
private->rdc_data.dev_type,
private->rdc_data.dev_model,
private->rdc_data.cu_type,
private->rdc_data.cu_model.model,
private->real_cyl,
private->rdc_data.trk_per_cyl,
- private->rdc_data.sec_per_trk);
+ private->rdc_data.sec_per_trk,
+ readonly ? ", read-only device" : "");
return 0;
out_err3:
@@ -2839,8 +2845,13 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)
char *psf_data, *rssd_result;
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
+ char psf0, psf1;
int rc;
+ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ psf0 = psf1 = 0;
+
/* Copy parms from caller */
rc = -EFAULT;
if (copy_from_user(&usrparm, argp, sizeof(usrparm)))
@@ -2869,12 +2880,8 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)
(void __user *)(unsigned long) usrparm.psf_data,
usrparm.psf_data_len))
goto out_free;
-
- /* sanity check on syscall header */
- if (psf_data[0] != 0x17 && psf_data[1] != 0xce) {
- rc = -EINVAL;
- goto out_free;
- }
+ psf0 = psf_data[0];
+ psf1 = psf_data[1];
/* setup CCWs for PSF + RSSD */
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 , 0, device);
@@ -2925,7 +2932,9 @@ out_free:
kfree(rssd_result);
kfree(psf_data);
out:
- DBF_DEV_EVENT(DBF_WARNING, device, "Symmetrix ioctl: rc=%d", rc);
+ DBF_DEV_EVENT(DBF_WARNING, device,
+ "Symmetrix ioctl (0x%02x 0x%02x): rc=%d",
+ (int) psf0, (int) psf1, rc);
return rc;
}
@@ -3033,7 +3042,7 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
" in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d\n",
req, scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw),
- scsw_cc(&irb->scsw), req->intrc);
+ scsw_cc(&irb->scsw), req ? req->intrc : 0);
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
" device %s: Failing CCW: %p\n",
dev_name(&device->cdev->dev),
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index 0f152444ac77..37282b90eecc 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -124,6 +124,7 @@ dasd_fba_check_characteristics(struct dasd_device *device)
struct dasd_fba_private *private;
struct ccw_device *cdev = device->cdev;
int rc;
+ int readonly;
private = (struct dasd_fba_private *) device->private;
if (!private) {
@@ -162,16 +163,21 @@ dasd_fba_check_characteristics(struct dasd_device *device)
return rc;
}
+ readonly = dasd_device_is_ro(device);
+ if (readonly)
+ set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
+
dev_info(&device->cdev->dev,
"New FBA DASD %04X/%02X (CU %04X/%02X) with %d MB "
- "and %d B/blk\n",
+ "and %d B/blk%s\n",
cdev->id.dev_type,
cdev->id.dev_model,
cdev->id.cu_type,
cdev->id.cu_model,
((private->rdc_data.blk_bdsa *
(private->rdc_data.blk_size >> 9)) >> 11),
- private->rdc_data.blk_size);
+ private->rdc_data.blk_size,
+ readonly ? ", read-only device" : "");
return 0;
}
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index d3198303b93c..30a1ca3d08b7 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -70,7 +70,8 @@ int dasd_gendisk_alloc(struct dasd_block *block)
}
len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26));
- if (block->base->features & DASD_FEATURE_READONLY)
+ if (base->features & DASD_FEATURE_READONLY ||
+ test_bit(DASD_FLAG_DEVICE_RO, &base->flags))
set_disk_ro(gdp, 1);
gdp->private_data = block;
gdp->queue = block->request_queue;
@@ -88,6 +89,7 @@ void dasd_gendisk_free(struct dasd_block *block)
if (block->gdp) {
del_gendisk(block->gdp);
block->gdp->queue = NULL;
+ block->gdp->private_data = NULL;
put_disk(block->gdp);
block->gdp = NULL;
}
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index e4c2143dabf6..a91d4a97d4f2 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -368,6 +368,7 @@ struct dasd_device {
/* Device state and target state. */
int state, target;
+ struct mutex state_mutex;
int stopped; /* device (ccw_device_start) was stopped */
/* reference count. */
@@ -435,6 +436,10 @@ struct dasd_block {
#define DASD_FLAG_OFFLINE 3 /* device is in offline processing */
#define DASD_FLAG_EER_SNSS 4 /* A SNSS is required */
#define DASD_FLAG_EER_IN_USE 5 /* A SNSS request is running */
+#define DASD_FLAG_DEVICE_RO 6 /* The device itself is read-only. Don't
+ * confuse this with the user specified
+ * read-only feature.
+ */
void dasd_put_device_wake(struct dasd_device *);
@@ -608,6 +613,9 @@ char *dasd_get_sense(struct irb *);
void dasd_device_set_stop_bits(struct dasd_device *, int);
void dasd_device_remove_stop_bits(struct dasd_device *, int);
+int dasd_device_is_ro(struct dasd_device *);
+
+
/* externals in dasd_devmap.c */
extern int dasd_max_devindex;
extern int dasd_probeonly;
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index fc7b30b4a255..3479f8158a1b 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -199,7 +199,8 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp)
if (!argp)
return -EINVAL;
- if (block->base->features & DASD_FEATURE_READONLY)
+ if (block->base->features & DASD_FEATURE_READONLY ||
+ test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags))
return -EROFS;
if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))
return -EFAULT;
@@ -260,7 +261,7 @@ static int dasd_ioctl_information(struct dasd_block *block,
struct ccw_dev_id dev_id;
base = block->base;
- if (!base->discipline->fill_info)
+ if (!base->discipline || !base->discipline->fill_info)
return -EINVAL;
dasd_info = kzalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
@@ -303,10 +304,7 @@ static int dasd_ioctl_information(struct dasd_block *block,
dasd_info->features |=
((base->features & DASD_FEATURE_READONLY) != 0);
- if (base->discipline)
- memcpy(dasd_info->type, base->discipline->name, 4);
- else
- memcpy(dasd_info->type, "none", 4);
+ memcpy(dasd_info->type, base->discipline->name, 4);
if (block->request_queue->request_fn) {
struct list_head *l;
@@ -352,7 +350,8 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
return -EINVAL;
if (get_user(intval, (int __user *)argp))
return -EFAULT;
-
+ if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags))
+ return -EROFS;
set_disk_ro(bdev->bd_disk, intval);
return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval);
}
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 6315fbd8e68b..f13a0bdd148c 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -72,7 +72,7 @@ dasd_devices_show(struct seq_file *m, void *v)
/* Print device number. */
seq_printf(m, "%s", dev_name(&device->cdev->dev));
/* Print discipline string. */
- if (device != NULL && device->discipline != NULL)
+ if (device->discipline != NULL)
seq_printf(m, "(%s)", device->discipline->name);
else
seq_printf(m, "(none)");
@@ -92,10 +92,7 @@ dasd_devices_show(struct seq_file *m, void *v)
substr = (device->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
seq_printf(m, "%4s: ", substr);
/* Print device status information. */
- switch ((device != NULL) ? device->state : -1) {
- case -1:
- seq_printf(m, "unknown");
- break;
+ switch (device->state) {
case DASD_STATE_NEW:
seq_printf(m, "new");
break;
@@ -168,51 +165,32 @@ static const struct file_operations dasd_devices_file_ops = {
.release = seq_release,
};
-static int
-dasd_calc_metrics(char *page, char **start, off_t off,
- int count, int *eof, int len)
-{
- len = (len > off) ? len - off : 0;
- if (len > count)
- len = count;
- if (len < count)
- *eof = 1;
- *start = page + off;
- return len;
-}
-
#ifdef CONFIG_DASD_PROFILE
-static char *
-dasd_statistics_array(char *str, unsigned int *array, int factor)
+static void dasd_statistics_array(struct seq_file *m, unsigned int *array, int factor)
{
int i;
for (i = 0; i < 32; i++) {
- str += sprintf(str, "%7d ", array[i] / factor);
+ seq_printf(m, "%7d ", array[i] / factor);
if (i == 15)
- str += sprintf(str, "\n");
+ seq_putc(m, '\n');
}
- str += sprintf(str,"\n");
- return str;
+ seq_putc(m, '\n');
}
#endif /* CONFIG_DASD_PROFILE */
-static int
-dasd_statistics_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int dasd_stats_proc_show(struct seq_file *m, void *v)
{
- unsigned long len;
#ifdef CONFIG_DASD_PROFILE
struct dasd_profile_info_t *prof;
- char *str;
int factor;
/* check for active profiling */
if (dasd_profile_level == DASD_PROFILE_OFF) {
- len = sprintf(page, "Statistics are off - they might be "
+ seq_printf(m, "Statistics are off - they might be "
"switched on using 'echo set on > "
"/proc/dasd/statistics'\n");
- return dasd_calc_metrics(page, start, off, count, eof, len);
+ return 0;
}
prof = &dasd_global_profile;
@@ -220,47 +198,49 @@ dasd_statistics_read(char *page, char **start, off_t off,
for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999;
factor *= 10);
- str = page;
- str += sprintf(str, "%d dasd I/O requests\n", prof->dasd_io_reqs);
- str += sprintf(str, "with %u sectors(512B each)\n",
+ seq_printf(m, "%d dasd I/O requests\n", prof->dasd_io_reqs);
+ seq_printf(m, "with %u sectors(512B each)\n",
prof->dasd_io_sects);
- str += sprintf(str, "Scale Factor is %d\n", factor);
- str += sprintf(str,
+ seq_printf(m, "Scale Factor is %d\n", factor);
+ seq_printf(m,
" __<4 ___8 __16 __32 __64 _128 "
" _256 _512 __1k __2k __4k __8k "
" _16k _32k _64k 128k\n");
- str += sprintf(str,
+ seq_printf(m,
" _256 _512 __1M __2M __4M __8M "
" _16M _32M _64M 128M 256M 512M "
" __1G __2G __4G " " _>4G\n");
- str += sprintf(str, "Histogram of sizes (512B secs)\n");
- str = dasd_statistics_array(str, prof->dasd_io_secs, factor);
- str += sprintf(str, "Histogram of I/O times (microseconds)\n");
- str = dasd_statistics_array(str, prof->dasd_io_times, factor);
- str += sprintf(str, "Histogram of I/O times per sector\n");
- str = dasd_statistics_array(str, prof->dasd_io_timps, factor);
- str += sprintf(str, "Histogram of I/O time till ssch\n");
- str = dasd_statistics_array(str, prof->dasd_io_time1, factor);
- str += sprintf(str, "Histogram of I/O time between ssch and irq\n");
- str = dasd_statistics_array(str, prof->dasd_io_time2, factor);
- str += sprintf(str, "Histogram of I/O time between ssch "
+ seq_printf(m, "Histogram of sizes (512B secs)\n");
+ dasd_statistics_array(m, prof->dasd_io_secs, factor);
+ seq_printf(m, "Histogram of I/O times (microseconds)\n");
+ dasd_statistics_array(m, prof->dasd_io_times, factor);
+ seq_printf(m, "Histogram of I/O times per sector\n");
+ dasd_statistics_array(m, prof->dasd_io_timps, factor);
+ seq_printf(m, "Histogram of I/O time till ssch\n");
+ dasd_statistics_array(m, prof->dasd_io_time1, factor);
+ seq_printf(m, "Histogram of I/O time between ssch and irq\n");
+ dasd_statistics_array(m, prof->dasd_io_time2, factor);
+ seq_printf(m, "Histogram of I/O time between ssch "
"and irq per sector\n");
- str = dasd_statistics_array(str, prof->dasd_io_time2ps, factor);
- str += sprintf(str, "Histogram of I/O time between irq and end\n");
- str = dasd_statistics_array(str, prof->dasd_io_time3, factor);
- str += sprintf(str, "# of req in chanq at enqueuing (1..32) \n");
- str = dasd_statistics_array(str, prof->dasd_io_nr_req, factor);
- len = str - page;
+ dasd_statistics_array(m, prof->dasd_io_time2ps, factor);
+ seq_printf(m, "Histogram of I/O time between irq and end\n");
+ dasd_statistics_array(m, prof->dasd_io_time3, factor);
+ seq_printf(m, "# of req in chanq at enqueuing (1..32) \n");
+ dasd_statistics_array(m, prof->dasd_io_nr_req, factor);
#else
- len = sprintf(page, "Statistics are not activated in this kernel\n");
+ seq_printf(m, "Statistics are not activated in this kernel\n");
#endif
- return dasd_calc_metrics(page, start, off, count, eof, len);
+ return 0;
}
-static int
-dasd_statistics_write(struct file *file, const char __user *user_buf,
- unsigned long user_len, void *data)
+static int dasd_stats_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dasd_stats_proc_show, NULL);
+}
+
+static ssize_t dasd_stats_proc_write(struct file *file,
+ const char __user *user_buf, size_t user_len, loff_t *pos)
{
#ifdef CONFIG_DASD_PROFILE
char *buffer, *str;
@@ -311,6 +291,15 @@ out_error:
#endif /* CONFIG_DASD_PROFILE */
}
+static const struct file_operations dasd_stats_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = dasd_stats_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = dasd_stats_proc_write,
+};
+
/*
* Create dasd proc-fs entries.
* In case creation failed, cleanup and return -ENOENT.
@@ -327,13 +316,12 @@ dasd_proc_init(void)
&dasd_devices_file_ops);
if (!dasd_devices_entry)
goto out_nodevices;
- dasd_statistics_entry = create_proc_entry("statistics",
- S_IFREG | S_IRUGO | S_IWUSR,
- dasd_proc_root_entry);
+ dasd_statistics_entry = proc_create("statistics",
+ S_IFREG | S_IRUGO | S_IWUSR,
+ dasd_proc_root_entry,
+ &dasd_stats_proc_fops);
if (!dasd_statistics_entry)
goto out_nostatistics;
- dasd_statistics_entry->read_proc = dasd_statistics_read;
- dasd_statistics_entry->write_proc = dasd_statistics_write;
return 0;
out_nostatistics:
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 62ddf5202b79..2a4c566456e7 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -373,7 +373,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
(unsigned long) rq, 0, 0);
if (rq->rc == 0)
- return; /* Sucessfully restarted. */
+ return; /* Successfully restarted. */
break;
case RAW3270_IO_STOP:
if (!rq)
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index ec88c59842e3..f6d72e1f2a38 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -196,7 +196,7 @@ __sclp_start_request(struct sclp_req *req)
req->start_count++;
if (rc == 0) {
- /* Sucessfully started request */
+ /* Successfully started request */
req->status = SCLP_REQ_RUNNING;
sclp_running_state = sclp_running_state_running;
__sclp_set_request_timer(SCLP_RETRY_INTERVAL * HZ,
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index b9d2a007e93b..3796ffdb8479 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -495,6 +495,10 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp)
if (tty->driver_data == NULL)
return -ENOMEM;
tty->low_latency = 0;
+ if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
+ tty->winsize.ws_row = 24;
+ tty->winsize.ws_col = 80;
+ }
}
return 0;
}
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index 8d3d720737da..097da8ce6be6 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -222,9 +222,8 @@ tapeblock_setup_device(struct tape_device * device)
goto cleanup_queue;
blk_queue_logical_block_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE);
- blk_queue_max_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC);
- blk_queue_max_phys_segments(blkdat->request_queue, -1L);
- blk_queue_max_hw_segments(blkdat->request_queue, -1L);
+ blk_queue_max_hw_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC);
+ blk_queue_max_segments(blkdat->request_queue, -1L);
blk_queue_max_segment_size(blkdat->request_queue, -1L);
blk_queue_segment_boundary(blkdat->request_queue, -1L);
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 82daa3c1dc9c..3438658b66b7 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/debugfs.h>
+#include <asm/asm-offsets.h>
#include <asm/ipl.h>
#include <asm/sclp.h>
#include <asm/setup.h>
@@ -40,12 +41,12 @@ enum arch_id {
/* dump system info */
struct sys_info {
- enum arch_id arch;
- unsigned long sa_base;
- u32 sa_size;
- int cpu_map[NR_CPUS];
- unsigned long mem_size;
- union save_area lc_mask;
+ enum arch_id arch;
+ unsigned long sa_base;
+ u32 sa_size;
+ int cpu_map[NR_CPUS];
+ unsigned long mem_size;
+ struct save_area lc_mask;
};
struct ipib_info {
@@ -183,52 +184,9 @@ static int memcpy_real_user(void __user *dest, unsigned long src, size_t count)
return 0;
}
-#ifdef __s390x__
-/*
- * Convert s390x (64 bit) cpu info to s390 (32 bit) cpu info
- */
-static void __init s390x_to_s390_regs(union save_area *out, union save_area *in,
- int cpu)
-{
- int i;
-
- for (i = 0; i < 16; i++) {
- out->s390.gp_regs[i] = in->s390x.gp_regs[i] & 0x00000000ffffffff;
- out->s390.acc_regs[i] = in->s390x.acc_regs[i];
- out->s390.ctrl_regs[i] =
- in->s390x.ctrl_regs[i] & 0x00000000ffffffff;
- }
- /* locore for 31 bit has only space for fpregs 0,2,4,6 */
- out->s390.fp_regs[0] = in->s390x.fp_regs[0];
- out->s390.fp_regs[1] = in->s390x.fp_regs[2];
- out->s390.fp_regs[2] = in->s390x.fp_regs[4];
- out->s390.fp_regs[3] = in->s390x.fp_regs[6];
- memcpy(&(out->s390.psw[0]), &(in->s390x.psw[0]), 4);
- out->s390.psw[1] |= 0x8; /* set bit 12 */
- memcpy(&(out->s390.psw[4]),&(in->s390x.psw[12]), 4);
- out->s390.psw[4] |= 0x80; /* set (31bit) addressing bit */
- out->s390.pref_reg = in->s390x.pref_reg;
- out->s390.timer = in->s390x.timer;
- out->s390.clk_cmp = in->s390x.clk_cmp;
-}
-
-static void __init s390x_to_s390_save_areas(void)
-{
- int i = 1;
- static union save_area tmp;
-
- while (zfcpdump_save_areas[i]) {
- s390x_to_s390_regs(&tmp, zfcpdump_save_areas[i], i);
- memcpy(zfcpdump_save_areas[i], &tmp, sizeof(tmp));
- i++;
- }
-}
-
-#endif /* __s390x__ */
-
static int __init init_cpu_info(enum arch_id arch)
{
- union save_area *sa;
+ struct save_area *sa;
/* get info for boot cpu from lowcore, stored in the HSA */
@@ -241,20 +199,12 @@ static int __init init_cpu_info(enum arch_id arch)
return -EIO;
}
zfcpdump_save_areas[0] = sa;
-
-#ifdef __s390x__
- /* convert s390x regs to s390, if we are dumping an s390 Linux */
-
- if (arch == ARCH_S390)
- s390x_to_s390_save_areas();
-#endif
-
return 0;
}
static DEFINE_MUTEX(zcore_mutex);
-#define DUMP_VERSION 0x3
+#define DUMP_VERSION 0x5
#define DUMP_MAGIC 0xa8190173618f23fdULL
#define DUMP_ARCH_S390X 2
#define DUMP_ARCH_S390 1
@@ -279,7 +229,14 @@ struct zcore_header {
u32 volnr;
u32 build_arch;
u64 rmem_size;
- char pad2[4016];
+ u8 mvdump;
+ u16 cpu_cnt;
+ u16 real_cpu_cnt;
+ u8 end_pad1[0x200-0x061];
+ u64 mvdump_sign;
+ u64 mvdump_zipl_time;
+ u8 end_pad2[0x800-0x210];
+ u32 lc_vec[512];
} __attribute__((packed,__aligned__(16)));
static struct zcore_header zcore_header = {
@@ -289,7 +246,7 @@ static struct zcore_header zcore_header = {
.dump_level = 0,
.page_size = PAGE_SIZE,
.mem_start = 0,
-#ifdef __s390x__
+#ifdef CONFIG_64BIT
.build_arch = DUMP_ARCH_S390X,
#else
.build_arch = DUMP_ARCH_S390,
@@ -340,11 +297,7 @@ static int zcore_add_lc(char __user *buf, unsigned long start, size_t count)
unsigned long prefix;
unsigned long sa_off, len, buf_off;
- if (sys_info.arch == ARCH_S390)
- prefix = zfcpdump_save_areas[i]->s390.pref_reg;
- else
- prefix = zfcpdump_save_areas[i]->s390x.pref_reg;
-
+ prefix = zfcpdump_save_areas[i]->pref_reg;
sa_start = prefix + sys_info.sa_base;
sa_end = prefix + sys_info.sa_base + sys_info.sa_size;
@@ -561,34 +514,39 @@ static const struct file_operations zcore_reipl_fops = {
.release = zcore_reipl_release,
};
+#ifdef CONFIG_32BIT
-static void __init set_s390_lc_mask(union save_area *map)
+static void __init set_lc_mask(struct save_area *map)
{
- memset(&map->s390.ext_save, 0xff, sizeof(map->s390.ext_save));
- memset(&map->s390.timer, 0xff, sizeof(map->s390.timer));
- memset(&map->s390.clk_cmp, 0xff, sizeof(map->s390.clk_cmp));
- memset(&map->s390.psw, 0xff, sizeof(map->s390.psw));
- memset(&map->s390.pref_reg, 0xff, sizeof(map->s390.pref_reg));
- memset(&map->s390.acc_regs, 0xff, sizeof(map->s390.acc_regs));
- memset(&map->s390.fp_regs, 0xff, sizeof(map->s390.fp_regs));
- memset(&map->s390.gp_regs, 0xff, sizeof(map->s390.gp_regs));
- memset(&map->s390.ctrl_regs, 0xff, sizeof(map->s390.ctrl_regs));
+ memset(&map->ext_save, 0xff, sizeof(map->ext_save));
+ memset(&map->timer, 0xff, sizeof(map->timer));
+ memset(&map->clk_cmp, 0xff, sizeof(map->clk_cmp));
+ memset(&map->psw, 0xff, sizeof(map->psw));
+ memset(&map->pref_reg, 0xff, sizeof(map->pref_reg));
+ memset(&map->acc_regs, 0xff, sizeof(map->acc_regs));
+ memset(&map->fp_regs, 0xff, sizeof(map->fp_regs));
+ memset(&map->gp_regs, 0xff, sizeof(map->gp_regs));
+ memset(&map->ctrl_regs, 0xff, sizeof(map->ctrl_regs));
}
-static void __init set_s390x_lc_mask(union save_area *map)
+#else /* CONFIG_32BIT */
+
+static void __init set_lc_mask(struct save_area *map)
{
- memset(&map->s390x.fp_regs, 0xff, sizeof(map->s390x.fp_regs));
- memset(&map->s390x.gp_regs, 0xff, sizeof(map->s390x.gp_regs));
- memset(&map->s390x.psw, 0xff, sizeof(map->s390x.psw));
- memset(&map->s390x.pref_reg, 0xff, sizeof(map->s390x.pref_reg));
- memset(&map->s390x.fp_ctrl_reg, 0xff, sizeof(map->s390x.fp_ctrl_reg));
- memset(&map->s390x.tod_reg, 0xff, sizeof(map->s390x.tod_reg));
- memset(&map->s390x.timer, 0xff, sizeof(map->s390x.timer));
- memset(&map->s390x.clk_cmp, 0xff, sizeof(map->s390x.clk_cmp));
- memset(&map->s390x.acc_regs, 0xff, sizeof(map->s390x.acc_regs));
- memset(&map->s390x.ctrl_regs, 0xff, sizeof(map->s390x.ctrl_regs));
+ memset(&map->fp_regs, 0xff, sizeof(map->fp_regs));
+ memset(&map->gp_regs, 0xff, sizeof(map->gp_regs));
+ memset(&map->psw, 0xff, sizeof(map->psw));
+ memset(&map->pref_reg, 0xff, sizeof(map->pref_reg));
+ memset(&map->fp_ctrl_reg, 0xff, sizeof(map->fp_ctrl_reg));
+ memset(&map->tod_reg, 0xff, sizeof(map->tod_reg));
+ memset(&map->timer, 0xff, sizeof(map->timer));
+ memset(&map->clk_cmp, 0xff, sizeof(map->clk_cmp));
+ memset(&map->acc_regs, 0xff, sizeof(map->acc_regs));
+ memset(&map->ctrl_regs, 0xff, sizeof(map->ctrl_regs));
}
+#endif /* CONFIG_32BIT */
+
/*
* Initialize dump globals for a given architecture
*/
@@ -599,21 +557,18 @@ static int __init sys_info_init(enum arch_id arch)
switch (arch) {
case ARCH_S390X:
pr_alert("DETECTED 'S390X (64 bit) OS'\n");
- sys_info.sa_base = SAVE_AREA_BASE_S390X;
- sys_info.sa_size = sizeof(struct save_area_s390x);
- set_s390x_lc_mask(&sys_info.lc_mask);
break;
case ARCH_S390:
pr_alert("DETECTED 'S390 (32 bit) OS'\n");
- sys_info.sa_base = SAVE_AREA_BASE_S390;
- sys_info.sa_size = sizeof(struct save_area_s390);
- set_s390_lc_mask(&sys_info.lc_mask);
break;
default:
pr_alert("0x%x is an unknown architecture.\n",arch);
return -EINVAL;
}
+ sys_info.sa_base = SAVE_AREA_BASE;
+ sys_info.sa_size = sizeof(struct save_area);
sys_info.arch = arch;
+ set_lc_mask(&sys_info.lc_mask);
rc = init_cpu_info(arch);
if (rc)
return rc;
@@ -660,8 +615,9 @@ static int __init get_mem_size(unsigned long *mem)
static int __init zcore_header_init(int arch, struct zcore_header *hdr)
{
- int rc;
+ int rc, i;
unsigned long memory = 0;
+ u32 prefix;
if (arch == ARCH_S390X)
hdr->arch_id = DUMP_ARCH_S390X;
@@ -676,6 +632,14 @@ static int __init zcore_header_init(int arch, struct zcore_header *hdr)
hdr->num_pages = memory / PAGE_SIZE;
hdr->tod = get_clock();
get_cpu_id(&hdr->cpu_id);
+ for (i = 0; zfcpdump_save_areas[i]; i++) {
+ prefix = zfcpdump_save_areas[i]->pref_reg;
+ hdr->real_cpu_cnt++;
+ if (!prefix)
+ continue;
+ hdr->lc_vec[hdr->cpu_cnt] = prefix;
+ hdr->cpu_cnt++;
+ }
return 0;
}
@@ -741,14 +705,21 @@ static int __init zcore_init(void)
if (rc)
goto fail;
-#ifndef __s390x__
+#ifdef CONFIG_64BIT
+ if (arch == ARCH_S390) {
+ pr_alert("The 64-bit dump tool cannot be used for a "
+ "32-bit system\n");
+ rc = -EINVAL;
+ goto fail;
+ }
+#else /* CONFIG_64BIT */
if (arch == ARCH_S390X) {
pr_alert("The 32-bit dump tool cannot be used for a "
"64-bit system\n");
rc = -EINVAL;
goto fail;
}
-#endif
+#endif /* CONFIG_64BIT */
rc = sys_info_init(arch);
if (rc)
diff --git a/drivers/s390/cio/ccwreq.c b/drivers/s390/cio/ccwreq.c
index 7a28a3029a3f..37df42af05ec 100644
--- a/drivers/s390/cio/ccwreq.c
+++ b/drivers/s390/cio/ccwreq.c
@@ -224,8 +224,8 @@ static void ccwreq_log_status(struct ccw_device *cdev, enum io_status status)
*/
void ccw_request_handler(struct ccw_device *cdev)
{
+ struct irb *irb = (struct irb *)&S390_lowcore.irb;
struct ccw_request *req = &cdev->private->req;
- struct irb *irb = (struct irb *) __LC_IRB;
enum io_status status;
int rc = -EOPNOTSUPP;
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 1ecd3e567648..4038f5b4f144 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -574,7 +574,7 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
secm_area->request.length = 0x0050;
secm_area->request.code = 0x0016;
- secm_area->key = PAGE_DEFAULT_KEY;
+ secm_area->key = PAGE_DEFAULT_KEY >> 4;
secm_area->cub_addr1 = (u64)(unsigned long)css->cub_addr1;
secm_area->cub_addr2 = (u64)(unsigned long)css->cub_addr2;
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index c84ac9443079..852612f5dba0 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -51,7 +51,7 @@ static void chsc_subchannel_irq(struct subchannel *sch)
{
struct chsc_private *private = sch->private;
struct chsc_request *request = private->request;
- struct irb *irb = (struct irb *)__LC_IRB;
+ struct irb *irb = (struct irb *)&S390_lowcore.irb;
CHSC_LOG(4, "irb");
CHSC_LOG_HEX(4, irb, sizeof(*irb));
@@ -237,7 +237,7 @@ static int chsc_async(struct chsc_async_area *chsc_area,
int ret = -ENODEV;
char dbf[10];
- chsc_area->header.key = PAGE_DEFAULT_KEY;
+ chsc_area->header.key = PAGE_DEFAULT_KEY >> 4;
while ((sch = chsc_get_next_subchannel(sch))) {
spin_lock(sch->lock);
private = sch->private;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 126f240715a4..f736cdcf08ad 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -625,8 +625,8 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
/*
* Get interrupt information from lowcore
*/
- tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID;
- irb = (struct irb *) __LC_IRB;
+ tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id;
+ irb = (struct irb *)&S390_lowcore.irb;
do {
kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++;
/*
@@ -661,7 +661,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
* We don't do this for VM because a tpi drops the cpu
* out of the sie which costs more cycles than it saves.
*/
- } while (!MACHINE_IS_VM && tpi (NULL) != 0);
+ } while (MACHINE_IS_LPAR && tpi(NULL) != 0);
irq_exit();
set_irq_regs(old_regs);
}
@@ -682,10 +682,10 @@ static int cio_tpi(void)
struct irb *irb;
int irq_context;
- tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID;
+ tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id;
if (tpi(NULL) != 1)
return 0;
- irb = (struct irb *) __LC_IRB;
+ irb = (struct irb *)&S390_lowcore.irb;
/* Store interrupt response block to lowcore. */
if (tsch(tpi_info->schid, irb) != 0)
/* Not status pending or not operational. */
@@ -885,7 +885,7 @@ __clear_io_subchannel_easy(struct subchannel_id schid)
struct tpi_info ti;
if (tpi(&ti)) {
- tsch(ti.schid, (struct irb *)__LC_IRB);
+ tsch(ti.schid, (struct irb *)&S390_lowcore.irb);
if (schid_equal(&ti.schid, &schid))
return 0;
}
@@ -1083,7 +1083,7 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
struct subchannel_id schid;
struct schib schib;
- schid = *(struct subchannel_id *)__LC_SUBCHANNEL_ID;
+ schid = *(struct subchannel_id *)&S390_lowcore.subchannel_id;
if (!schid.one)
return -ENODEV;
if (stsch(schid, &schib))
diff --git a/drivers/s390/cio/crw.c b/drivers/s390/cio/crw.c
index d157665d0e76..425f741a280c 100644
--- a/drivers/s390/cio/crw.c
+++ b/drivers/s390/cio/crw.c
@@ -8,15 +8,16 @@
* Heiko Carstens <heiko.carstens@de.ibm.com>,
*/
-#include <linux/semaphore.h>
#include <linux/mutex.h>
#include <linux/kthread.h>
#include <linux/init.h>
+#include <linux/wait.h>
#include <asm/crw.h>
-static struct semaphore crw_semaphore;
static DEFINE_MUTEX(crw_handler_mutex);
static crw_handler_t crw_handlers[NR_RSCS];
+static atomic_t crw_nr_req = ATOMIC_INIT(0);
+static DECLARE_WAIT_QUEUE_HEAD(crw_handler_wait_q);
/**
* crw_register_handler() - register a channel report word handler
@@ -59,12 +60,14 @@ void crw_unregister_handler(int rsc)
static int crw_collect_info(void *unused)
{
struct crw crw[2];
- int ccode;
+ int ccode, signal;
unsigned int chain;
- int ignore;
repeat:
- ignore = down_interruptible(&crw_semaphore);
+ signal = wait_event_interruptible(crw_handler_wait_q,
+ atomic_read(&crw_nr_req) > 0);
+ if (unlikely(signal))
+ atomic_inc(&crw_nr_req);
chain = 0;
while (1) {
crw_handler_t handler;
@@ -122,25 +125,23 @@ repeat:
/* chain is always 0 or 1 here. */
chain = crw[chain].chn ? chain + 1 : 0;
}
+ if (atomic_dec_and_test(&crw_nr_req))
+ wake_up(&crw_handler_wait_q);
goto repeat;
return 0;
}
void crw_handle_channel_report(void)
{
- up(&crw_semaphore);
+ atomic_inc(&crw_nr_req);
+ wake_up(&crw_handler_wait_q);
}
-/*
- * Separate initcall needed for semaphore initialization since
- * crw_handle_channel_report might be called before crw_machine_check_init.
- */
-static int __init crw_init_semaphore(void)
+void crw_wait_for_channel_report(void)
{
- init_MUTEX_LOCKED(&crw_semaphore);
- return 0;
+ crw_handle_channel_report();
+ wait_event(crw_handler_wait_q, atomic_read(&crw_nr_req) == 0);
}
-pure_initcall(crw_init_semaphore);
/*
* Machine checks for the channel subsystem must be enabled
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 7679aee6fa14..2769da54f2b9 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -18,6 +18,7 @@
#include <linux/list.h>
#include <linux/reboot.h>
#include <linux/suspend.h>
+#include <linux/proc_fs.h>
#include <asm/isc.h>
#include <asm/crw.h>
@@ -232,7 +233,7 @@ void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo)
if (!get_device(&sch->dev))
return;
sch->todo = todo;
- if (!queue_work(slow_path_wq, &sch->todo_work)) {
+ if (!queue_work(cio_work_q, &sch->todo_work)) {
/* Already queued, release workqueue ref. */
put_device(&sch->dev);
}
@@ -543,7 +544,7 @@ static void css_slow_path_func(struct work_struct *unused)
}
static DECLARE_WORK(slow_path_work, css_slow_path_func);
-struct workqueue_struct *slow_path_wq;
+struct workqueue_struct *cio_work_q;
void css_schedule_eval(struct subchannel_id schid)
{
@@ -552,7 +553,7 @@ void css_schedule_eval(struct subchannel_id schid)
spin_lock_irqsave(&slow_subchannel_lock, flags);
idset_sch_add(slow_subchannel_set, schid);
atomic_set(&css_eval_scheduled, 1);
- queue_work(slow_path_wq, &slow_path_work);
+ queue_work(cio_work_q, &slow_path_work);
spin_unlock_irqrestore(&slow_subchannel_lock, flags);
}
@@ -563,7 +564,7 @@ void css_schedule_eval_all(void)
spin_lock_irqsave(&slow_subchannel_lock, flags);
idset_fill(slow_subchannel_set);
atomic_set(&css_eval_scheduled, 1);
- queue_work(slow_path_wq, &slow_path_work);
+ queue_work(cio_work_q, &slow_path_work);
spin_unlock_irqrestore(&slow_subchannel_lock, flags);
}
@@ -594,14 +595,14 @@ void css_schedule_eval_all_unreg(void)
spin_lock_irqsave(&slow_subchannel_lock, flags);
idset_add_set(slow_subchannel_set, unreg_set);
atomic_set(&css_eval_scheduled, 1);
- queue_work(slow_path_wq, &slow_path_work);
+ queue_work(cio_work_q, &slow_path_work);
spin_unlock_irqrestore(&slow_subchannel_lock, flags);
idset_free(unreg_set);
}
void css_wait_for_slow_path(void)
{
- flush_workqueue(slow_path_wq);
+ flush_workqueue(cio_work_q);
}
/* Schedule reprobing of all unregistered subchannels. */
@@ -992,12 +993,21 @@ static int __init channel_subsystem_init(void)
ret = css_bus_init();
if (ret)
return ret;
-
+ cio_work_q = create_singlethread_workqueue("cio");
+ if (!cio_work_q) {
+ ret = -ENOMEM;
+ goto out_bus;
+ }
ret = io_subchannel_init();
if (ret)
- css_bus_cleanup();
+ goto out_wq;
return ret;
+out_wq:
+ destroy_workqueue(cio_work_q);
+out_bus:
+ css_bus_cleanup();
+ return ret;
}
subsys_initcall(channel_subsystem_init);
@@ -1006,10 +1016,25 @@ static int css_settle(struct device_driver *drv, void *unused)
struct css_driver *cssdrv = to_cssdriver(drv);
if (cssdrv->settle)
- cssdrv->settle();
+ return cssdrv->settle();
return 0;
}
+int css_complete_work(void)
+{
+ int ret;
+
+ /* Wait for the evaluation of subchannels to finish. */
+ ret = wait_event_interruptible(css_eval_wq,
+ atomic_read(&css_eval_scheduled) == 0);
+ if (ret)
+ return -EINTR;
+ flush_workqueue(cio_work_q);
+ /* Wait for the subchannel type specific initialization to finish */
+ return bus_for_each_drv(&css_bus_type, NULL, NULL, css_settle);
+}
+
+
/*
* Wait for the initialization of devices to finish, to make sure we are
* done with our setup if the search for the root device starts.
@@ -1018,13 +1043,41 @@ static int __init channel_subsystem_init_sync(void)
{
/* Start initial subchannel evaluation. */
css_schedule_eval_all();
- /* Wait for the evaluation of subchannels to finish. */
- wait_event(css_eval_wq, atomic_read(&css_eval_scheduled) == 0);
- /* Wait for the subchannel type specific initialization to finish */
- return bus_for_each_drv(&css_bus_type, NULL, NULL, css_settle);
+ css_complete_work();
+ return 0;
}
subsys_initcall_sync(channel_subsystem_init_sync);
+#ifdef CONFIG_PROC_FS
+static ssize_t cio_settle_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int ret;
+
+ /* Handle pending CRW's. */
+ crw_wait_for_channel_report();
+ ret = css_complete_work();
+
+ return ret ? ret : count;
+}
+
+static const struct file_operations cio_settle_proc_fops = {
+ .write = cio_settle_write,
+};
+
+static int __init cio_settle_init(void)
+{
+ struct proc_dir_entry *entry;
+
+ entry = proc_create("cio_settle", S_IWUSR, NULL,
+ &cio_settle_proc_fops);
+ if (!entry)
+ return -ENOMEM;
+ return 0;
+}
+device_initcall(cio_settle_init);
+#endif /*CONFIG_PROC_FS*/
+
int sch_is_pseudo_sch(struct subchannel *sch)
{
return sch == to_css(sch->dev.parent)->pseudo_subchannel;
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index fe84b92cde60..7e37886de231 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -95,7 +95,7 @@ struct css_driver {
int (*freeze)(struct subchannel *);
int (*thaw) (struct subchannel *);
int (*restore)(struct subchannel *);
- void (*settle)(void);
+ int (*settle)(void);
const char *name;
};
@@ -146,12 +146,13 @@ extern struct channel_subsystem *channel_subsystems[];
/* Helper functions to build lists for the slow path. */
void css_schedule_eval(struct subchannel_id schid);
void css_schedule_eval_all(void);
+int css_complete_work(void);
int sch_is_pseudo_sch(struct subchannel *);
struct schib;
int css_sch_is_valid(struct schib *);
-extern struct workqueue_struct *slow_path_wq;
+extern struct workqueue_struct *cio_work_q;
void css_wait_for_slow_path(void);
void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo);
#endif
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index a6c7d5426fb2..6d229f3523a0 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -136,7 +136,6 @@ static int io_subchannel_sch_event(struct subchannel *, int);
static int io_subchannel_chp_event(struct subchannel *, struct chp_link *,
int);
static void recovery_func(unsigned long data);
-struct workqueue_struct *ccw_device_work;
wait_queue_head_t ccw_device_init_wq;
atomic_t ccw_device_init_count;
@@ -159,11 +158,16 @@ static int io_subchannel_prepare(struct subchannel *sch)
return 0;
}
-static void io_subchannel_settle(void)
+static int io_subchannel_settle(void)
{
- wait_event(ccw_device_init_wq,
- atomic_read(&ccw_device_init_count) == 0);
- flush_workqueue(ccw_device_work);
+ int ret;
+
+ ret = wait_event_interruptible(ccw_device_init_wq,
+ atomic_read(&ccw_device_init_count) == 0);
+ if (ret)
+ return -EINTR;
+ flush_workqueue(cio_work_q);
+ return 0;
}
static struct css_driver io_subchannel_driver = {
@@ -188,27 +192,13 @@ int __init io_subchannel_init(void)
atomic_set(&ccw_device_init_count, 0);
setup_timer(&recovery_timer, recovery_func, 0);
- ccw_device_work = create_singlethread_workqueue("cio");
- if (!ccw_device_work)
- return -ENOMEM;
- slow_path_wq = create_singlethread_workqueue("kslowcrw");
- if (!slow_path_wq) {
- ret = -ENOMEM;
- goto out_err;
- }
- if ((ret = bus_register (&ccw_bus_type)))
- goto out_err;
-
+ ret = bus_register(&ccw_bus_type);
+ if (ret)
+ return ret;
ret = css_driver_register(&io_subchannel_driver);
if (ret)
- goto out_err;
+ bus_unregister(&ccw_bus_type);
- return 0;
-out_err:
- if (ccw_device_work)
- destroy_workqueue(ccw_device_work);
- if (slow_path_wq)
- destroy_workqueue(slow_path_wq);
return ret;
}
@@ -774,7 +764,7 @@ static void sch_create_and_recog_new_device(struct subchannel *sch)
static void io_subchannel_register(struct ccw_device *cdev)
{
struct subchannel *sch;
- int ret;
+ int ret, adjust_init_count = 1;
unsigned long flags;
sch = to_subchannel(cdev->dev.parent);
@@ -803,6 +793,7 @@ static void io_subchannel_register(struct ccw_device *cdev)
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
}
+ adjust_init_count = 0;
goto out;
}
/*
@@ -828,7 +819,7 @@ out:
cdev->private->flags.recog_done = 1;
wake_up(&cdev->private->wait_q);
out_err:
- if (atomic_dec_and_test(&ccw_device_init_count))
+ if (adjust_init_count && atomic_dec_and_test(&ccw_device_init_count))
wake_up(&ccw_device_init_wq);
}
@@ -1348,7 +1339,7 @@ static enum io_sch_action sch_get_action(struct subchannel *sch)
/* Not operational. */
if (!cdev)
return IO_SCH_UNREG;
- if (!ccw_device_notify(cdev, CIO_GONE))
+ if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK)
return IO_SCH_UNREG;
return IO_SCH_ORPH_UNREG;
}
@@ -1356,12 +1347,12 @@ static enum io_sch_action sch_get_action(struct subchannel *sch)
if (!cdev)
return IO_SCH_ATTACH;
if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
- if (!ccw_device_notify(cdev, CIO_GONE))
+ if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK)
return IO_SCH_UNREG_ATTACH;
return IO_SCH_ORPH_ATTACH;
}
if ((sch->schib.pmcw.pam & sch->opm) == 0) {
- if (!ccw_device_notify(cdev, CIO_NO_PATH))
+ if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK)
return IO_SCH_UNREG;
return IO_SCH_DISC;
}
@@ -1410,6 +1401,12 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
rc = 0;
goto out_unlock;
case IO_SCH_VERIFY:
+ if (cdev->private->flags.resuming == 1) {
+ if (cio_enable_subchannel(sch, (u32)(addr_t)sch)) {
+ ccw_device_set_notoper(cdev);
+ break;
+ }
+ }
/* Trigger path verification. */
io_subchannel_verify(sch);
rc = 0;
@@ -1448,7 +1445,8 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
break;
case IO_SCH_UNREG_ATTACH:
/* Unregister ccw device. */
- ccw_device_unregister(cdev);
+ if (!cdev->private->flags.resuming)
+ ccw_device_unregister(cdev);
break;
default:
break;
@@ -1457,7 +1455,8 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
switch (action) {
case IO_SCH_ORPH_UNREG:
case IO_SCH_UNREG:
- css_sch_device_unregister(sch);
+ if (!cdev || !cdev->private->flags.resuming)
+ css_sch_device_unregister(sch);
break;
case IO_SCH_ORPH_ATTACH:
case IO_SCH_UNREG_ATTACH:
@@ -1779,26 +1778,42 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev)
{
struct subchannel *sch = to_subchannel(cdev->dev.parent);
- if (cio_is_console(sch->schid))
- goto out;
+ spin_lock_irq(sch->lock);
+ if (cio_is_console(sch->schid)) {
+ cio_enable_subchannel(sch, (u32)(addr_t)sch);
+ goto out_unlock;
+ }
/*
* While we were sleeping, devices may have gone or become
* available again. Kick re-detection.
*/
- spin_lock_irq(sch->lock);
cdev->private->flags.resuming = 1;
+ css_schedule_eval(sch->schid);
+ spin_unlock_irq(sch->lock);
+ css_complete_work();
+
+ /* cdev may have been moved to a different subchannel. */
+ sch = to_subchannel(cdev->dev.parent);
+ spin_lock_irq(sch->lock);
+ if (cdev->private->state != DEV_STATE_ONLINE &&
+ cdev->private->state != DEV_STATE_OFFLINE)
+ goto out_unlock;
+
ccw_device_recognition(cdev);
spin_unlock_irq(sch->lock);
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) ||
cdev->private->state == DEV_STATE_DISCONNECTED);
-out:
+ spin_lock_irq(sch->lock);
+
+out_unlock:
cdev->private->flags.resuming = 0;
+ spin_unlock_irq(sch->lock);
}
static int resume_handle_boxed(struct ccw_device *cdev)
{
cdev->private->state = DEV_STATE_BOXED;
- if (ccw_device_notify(cdev, CIO_BOXED))
+ if (ccw_device_notify(cdev, CIO_BOXED) == NOTIFY_OK)
return 0;
ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
return -ENODEV;
@@ -1807,7 +1822,7 @@ static int resume_handle_boxed(struct ccw_device *cdev)
static int resume_handle_disc(struct ccw_device *cdev)
{
cdev->private->state = DEV_STATE_DISCONNECTED;
- if (ccw_device_notify(cdev, CIO_GONE))
+ if (ccw_device_notify(cdev, CIO_GONE) == NOTIFY_OK)
return 0;
ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
return -ENODEV;
@@ -1816,40 +1831,31 @@ static int resume_handle_disc(struct ccw_device *cdev)
static int ccw_device_pm_restore(struct device *dev)
{
struct ccw_device *cdev = to_ccwdev(dev);
- struct subchannel *sch = to_subchannel(cdev->dev.parent);
- int ret = 0, cm_enabled;
+ struct subchannel *sch;
+ int ret = 0;
__ccw_device_pm_restore(cdev);
+ sch = to_subchannel(cdev->dev.parent);
spin_lock_irq(sch->lock);
- if (cio_is_console(sch->schid)) {
- cio_enable_subchannel(sch, (u32)(addr_t)sch);
- spin_unlock_irq(sch->lock);
+ if (cio_is_console(sch->schid))
goto out_restore;
- }
- cdev->private->flags.donotify = 0;
+
/* check recognition results */
switch (cdev->private->state) {
case DEV_STATE_OFFLINE:
+ case DEV_STATE_ONLINE:
+ cdev->private->flags.donotify = 0;
break;
case DEV_STATE_BOXED:
ret = resume_handle_boxed(cdev);
- spin_unlock_irq(sch->lock);
if (ret)
- goto out;
+ goto out_unlock;
goto out_restore;
- case DEV_STATE_DISCONNECTED:
- goto out_disc_unlock;
default:
- goto out_unreg_unlock;
- }
- /* check if the device id has changed */
- if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
- CIO_MSG_EVENT(0, "resume: sch 0.%x.%04x: failed (devno "
- "changed from %04x to %04x)\n",
- sch->schid.ssid, sch->schid.sch_no,
- cdev->private->dev_id.devno,
- sch->schib.pmcw.dev);
- goto out_unreg_unlock;
+ ret = resume_handle_disc(cdev);
+ if (ret)
+ goto out_unlock;
+ goto out_restore;
}
/* check if the device type has changed */
if (!ccw_device_test_sense_data(cdev)) {
@@ -1858,24 +1864,30 @@ static int ccw_device_pm_restore(struct device *dev)
ret = -ENODEV;
goto out_unlock;
}
- if (!cdev->online) {
- ret = 0;
+ if (!cdev->online)
goto out_unlock;
- }
- ret = ccw_device_online(cdev);
- if (ret)
- goto out_disc_unlock;
- cm_enabled = cdev->private->cmb != NULL;
+ if (ccw_device_online(cdev)) {
+ ret = resume_handle_disc(cdev);
+ if (ret)
+ goto out_unlock;
+ goto out_restore;
+ }
spin_unlock_irq(sch->lock);
-
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
- if (cdev->private->state != DEV_STATE_ONLINE) {
- spin_lock_irq(sch->lock);
- goto out_disc_unlock;
+ spin_lock_irq(sch->lock);
+
+ if (ccw_device_notify(cdev, CIO_OPER) == NOTIFY_BAD) {
+ ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
+ ret = -ENODEV;
+ goto out_unlock;
}
- if (cm_enabled) {
+
+ /* reenable cmf, if needed */
+ if (cdev->private->cmb) {
+ spin_unlock_irq(sch->lock);
ret = ccw_set_cmf(cdev, 1);
+ spin_lock_irq(sch->lock);
if (ret) {
CIO_MSG_EVENT(2, "resume: cdev 0.%x.%04x: cmf failed "
"(rc=%d)\n", cdev->private->dev_id.ssid,
@@ -1885,21 +1897,11 @@ static int ccw_device_pm_restore(struct device *dev)
}
out_restore:
+ spin_unlock_irq(sch->lock);
if (cdev->online && cdev->drv && cdev->drv->restore)
ret = cdev->drv->restore(cdev);
-out:
return ret;
-out_disc_unlock:
- ret = resume_handle_disc(cdev);
- spin_unlock_irq(sch->lock);
- if (ret)
- return ret;
- goto out_restore;
-
-out_unreg_unlock:
- ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL);
- ret = -ENODEV;
out_unlock:
spin_unlock_irq(sch->lock);
return ret;
@@ -2028,7 +2030,7 @@ void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo)
/* Get workqueue ref. */
if (!get_device(&cdev->dev))
return;
- if (!queue_work(slow_path_wq, &cdev->private->todo_work)) {
+ if (!queue_work(cio_work_q, &cdev->private->todo_work)) {
/* Already queued, release workqueue ref. */
put_device(&cdev->dev);
}
@@ -2041,5 +2043,4 @@ EXPORT_SYMBOL(ccw_driver_register);
EXPORT_SYMBOL(ccw_driver_unregister);
EXPORT_SYMBOL(get_ccwdev_by_busid);
EXPORT_SYMBOL(ccw_bus_type);
-EXPORT_SYMBOL(ccw_device_work);
EXPORT_SYMBOL_GPL(ccw_device_get_subchannel_id);
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index bcfe13e42638..379de2d1ec49 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -4,7 +4,7 @@
#include <asm/ccwdev.h>
#include <asm/atomic.h>
#include <linux/wait.h>
-
+#include <linux/notifier.h>
#include "io_sch.h"
/*
@@ -71,7 +71,6 @@ dev_fsm_final_state(struct ccw_device *cdev)
cdev->private->state == DEV_STATE_BOXED);
}
-extern struct workqueue_struct *ccw_device_work;
extern wait_queue_head_t ccw_device_init_wq;
extern atomic_t ccw_device_init_count;
int __init io_subchannel_init(void);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index ae760658a131..c56ab94612f9 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -313,21 +313,43 @@ ccw_device_sense_id_done(struct ccw_device *cdev, int err)
}
}
+/**
+ * ccw_device_notify() - inform the device's driver about an event
+ * @cdev: device for which an event occured
+ * @event: event that occurred
+ *
+ * Returns:
+ * -%EINVAL if the device is offline or has no driver.
+ * -%EOPNOTSUPP if the device's driver has no notifier registered.
+ * %NOTIFY_OK if the driver wants to keep the device.
+ * %NOTIFY_BAD if the driver doesn't want to keep the device.
+ */
int ccw_device_notify(struct ccw_device *cdev, int event)
{
+ int ret = -EINVAL;
+
if (!cdev->drv)
- return 0;
+ goto out;
if (!cdev->online)
- return 0;
+ goto out;
CIO_MSG_EVENT(2, "notify called for 0.%x.%04x, event=%d\n",
cdev->private->dev_id.ssid, cdev->private->dev_id.devno,
event);
- return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0;
+ if (!cdev->drv->notify) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+ if (cdev->drv->notify(cdev, event))
+ ret = NOTIFY_OK;
+ else
+ ret = NOTIFY_BAD;
+out:
+ return ret;
}
static void ccw_device_oper_notify(struct ccw_device *cdev)
{
- if (ccw_device_notify(cdev, CIO_OPER)) {
+ if (ccw_device_notify(cdev, CIO_OPER) == NOTIFY_OK) {
/* Reenable channel measurements, if needed. */
ccw_device_sched_todo(cdev, CDEV_TODO_ENABLE_CMF);
return;
@@ -361,14 +383,15 @@ ccw_device_done(struct ccw_device *cdev, int state)
case DEV_STATE_BOXED:
CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n",
cdev->private->dev_id.devno, sch->schid.sch_no);
- if (cdev->online && !ccw_device_notify(cdev, CIO_BOXED))
+ if (cdev->online &&
+ ccw_device_notify(cdev, CIO_BOXED) != NOTIFY_OK)
ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
cdev->private->flags.donotify = 0;
break;
case DEV_STATE_NOT_OPER:
CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n",
cdev->private->dev_id.devno, sch->schid.sch_no);
- if (!ccw_device_notify(cdev, CIO_GONE))
+ if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK)
ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
else
ccw_device_set_disconnected(cdev);
@@ -378,7 +401,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel "
"%04x\n", cdev->private->dev_id.devno,
sch->schid.sch_no);
- if (!ccw_device_notify(cdev, CIO_NO_PATH))
+ if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK)
ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
else
ccw_device_set_disconnected(cdev);
@@ -586,7 +609,7 @@ ccw_device_offline(struct ccw_device *cdev)
static void ccw_device_generic_notoper(struct ccw_device *cdev,
enum dev_event dev_event)
{
- if (!ccw_device_notify(cdev, CIO_GONE))
+ if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK)
ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
else
ccw_device_set_disconnected(cdev);
@@ -667,7 +690,7 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
struct irb *irb;
int is_cmd;
- irb = (struct irb *) __LC_IRB;
+ irb = (struct irb *)&S390_lowcore.irb;
is_cmd = !scsw_is_tm(&irb->scsw);
/* Check for unsolicited interrupt. */
if (!scsw_is_solicited(&irb->scsw)) {
@@ -732,7 +755,7 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
{
struct irb *irb;
- irb = (struct irb *) __LC_IRB;
+ irb = (struct irb *)&S390_lowcore.irb;
/* Check for unsolicited interrupt. */
if (scsw_stctl(&irb->scsw) ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 44f2f6a97f33..48aa0647432b 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -208,18 +208,27 @@ struct qdio_dev_perf_stat {
unsigned int eqbs_partial;
unsigned int sqbs;
unsigned int sqbs_partial;
+} ____cacheline_aligned;
+
+struct qdio_queue_perf_stat {
+ /*
+ * Sorted into order-2 buckets: 1, 2-3, 4-7, ... 64-127, 128.
+ * Since max. 127 SBALs are scanned reuse entry for 128 as queue full
+ * aka 127 SBALs found.
+ */
+ unsigned int nr_sbals[8];
+ unsigned int nr_sbal_error;
+ unsigned int nr_sbal_nop;
+ unsigned int nr_sbal_total;
};
struct qdio_input_q {
/* input buffer acknowledgement flag */
int polling;
-
/* first ACK'ed buffer */
int ack_start;
-
/* how much sbals are acknowledged with qebsm */
int ack_count;
-
/* last time of noticing incoming data */
u64 timestamp;
};
@@ -227,40 +236,27 @@ struct qdio_input_q {
struct qdio_output_q {
/* PCIs are enabled for the queue */
int pci_out_enabled;
-
/* IQDIO: output multiple buffers (enhanced SIGA) */
int use_enh_siga;
-
/* timer to check for more outbound work */
struct timer_list timer;
};
+/*
+ * Note on cache alignment: grouped slsb and write mostly data at the beginning
+ * sbal[] is read-only and starts on a new cacheline followed by read mostly.
+ */
struct qdio_q {
struct slsb slsb;
+
union {
struct qdio_input_q in;
struct qdio_output_q out;
} u;
- /* queue number */
- int nr;
-
- /* bitmask of queue number */
- int mask;
-
- /* input or output queue */
- int is_input_q;
-
- /* list of thinint input queues */
- struct list_head entry;
-
- /* upper-layer program handler */
- qdio_handler_t (*handler);
-
/*
* inbound: next buffer the program should check for
- * outbound: next buffer to check for having been processed
- * by the card
+ * outbound: next buffer to check if adapter processed it
*/
int first_to_check;
@@ -273,16 +269,32 @@ struct qdio_q {
/* number of buffers in use by the adapter */
atomic_t nr_buf_used;
- struct qdio_irq *irq_ptr;
- struct dentry *debugfs_q;
- struct tasklet_struct tasklet;
-
/* error condition during a data transfer */
unsigned int qdio_error;
- struct sl *sl;
- struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q];
+ struct tasklet_struct tasklet;
+ struct qdio_queue_perf_stat q_stats;
+
+ struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q] ____cacheline_aligned;
+
+ /* queue number */
+ int nr;
+
+ /* bitmask of queue number */
+ int mask;
+
+ /* input or output queue */
+ int is_input_q;
+
+ /* list of thinint input queues */
+ struct list_head entry;
+ /* upper-layer program handler */
+ qdio_handler_t (*handler);
+
+ struct dentry *debugfs_q;
+ struct qdio_irq *irq_ptr;
+ struct sl *sl;
/*
* Warning: Leave this member at the end so it won't be cleared in
* qdio_fill_qs. A page is allocated under this pointer and used for
@@ -317,12 +329,8 @@ struct qdio_irq {
struct qdio_ssqd_desc ssqd_desc;
void (*orig_handler) (struct ccw_device *, unsigned long, struct irb *);
- struct qdio_dev_perf_stat perf_stat;
int perf_stat_enabled;
- /*
- * Warning: Leave these members together at the end so they won't be
- * cleared in qdio_setup_irq.
- */
+
struct qdr *qdr;
unsigned long chsc_page;
@@ -331,6 +339,7 @@ struct qdio_irq {
debug_info_t *debug_area;
struct mutex setup_mutex;
+ struct qdio_dev_perf_stat perf_stat;
};
/* helper functions */
@@ -341,9 +350,20 @@ struct qdio_irq {
(irq->qib.qfmt == QDIO_IQDIO_QFMT || \
css_general_characteristics.aif_osa)
-#define qperf(qdev,attr) qdev->perf_stat.attr
-#define qperf_inc(q,attr) if (q->irq_ptr->perf_stat_enabled) \
- q->irq_ptr->perf_stat.attr++
+#define qperf(__qdev, __attr) ((__qdev)->perf_stat.(__attr))
+
+#define qperf_inc(__q, __attr) \
+({ \
+ struct qdio_irq *qdev = (__q)->irq_ptr; \
+ if (qdev->perf_stat_enabled) \
+ (qdev->perf_stat.__attr)++; \
+})
+
+static inline void account_sbals_error(struct qdio_q *q, int count)
+{
+ q->q_stats.nr_sbal_error += count;
+ q->q_stats.nr_sbal_total += count;
+}
/* the highest iqdio queue is used for multicast */
static inline int multicast_outbound(struct qdio_q *q)
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index f49761ff9a00..6ce83f56d537 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -33,7 +33,6 @@ void qdio_allocate_dbf(struct qdio_initialize *init_data,
DBF_HEX(&init_data->input_handler, sizeof(void *));
DBF_HEX(&init_data->output_handler, sizeof(void *));
DBF_HEX(&init_data->int_parm, sizeof(long));
- DBF_HEX(&init_data->flags, sizeof(long));
DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
@@ -60,7 +59,7 @@ static int qstat_show(struct seq_file *m, void *v)
seq_printf(m, "ftc: %d last_move: %d\n", q->first_to_check, q->last_move);
seq_printf(m, "polling: %d ack start: %d ack count: %d\n",
q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count);
- seq_printf(m, "slsb buffer states:\n");
+ seq_printf(m, "SBAL states:\n");
seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
@@ -97,6 +96,20 @@ static int qstat_show(struct seq_file *m, void *v)
}
seq_printf(m, "\n");
seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
+
+ seq_printf(m, "\nSBAL statistics:");
+ if (!q->irq_ptr->perf_stat_enabled) {
+ seq_printf(m, " disabled\n");
+ return 0;
+ }
+
+ seq_printf(m, "\n1 2.. 4.. 8.. "
+ "16.. 32.. 64.. 127\n");
+ for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
+ seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
+ seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n",
+ q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
+ q->q_stats.nr_sbal_total);
return 0;
}
@@ -181,9 +194,10 @@ static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
{
struct seq_file *seq = file->private_data;
struct qdio_irq *irq_ptr = seq->private;
+ struct qdio_q *q;
unsigned long val;
char buf[8];
- int ret;
+ int ret, i;
if (!irq_ptr)
return 0;
@@ -201,6 +215,10 @@ static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
case 0:
irq_ptr->perf_stat_enabled = 0;
memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
+ for_each_input_queue(irq_ptr, q, i)
+ memset(&q->q_stats, 0, sizeof(q->q_stats));
+ for_each_output_queue(irq_ptr, q, i)
+ memset(&q->q_stats, 0, sizeof(q->q_stats));
break;
case 1:
irq_ptr->perf_stat_enabled = 1;
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 999fe80c4051..4f8f74311778 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -392,6 +392,20 @@ static inline void qdio_stop_polling(struct qdio_q *q)
set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT);
}
+static inline void account_sbals(struct qdio_q *q, int count)
+{
+ int pos = 0;
+
+ q->q_stats.nr_sbal_total += count;
+ if (count == QDIO_MAX_BUFFERS_MASK) {
+ q->q_stats.nr_sbals[7]++;
+ return;
+ }
+ while (count >>= 1)
+ pos++;
+ q->q_stats.nr_sbals[pos]++;
+}
+
static void announce_buffer_error(struct qdio_q *q, int count)
{
q->qdio_error |= QDIO_ERROR_SLSB_STATE;
@@ -487,16 +501,22 @@ static int get_inbound_buffer_frontier(struct qdio_q *q)
q->first_to_check = add_buf(q->first_to_check, count);
if (atomic_sub(count, &q->nr_buf_used) == 0)
qperf_inc(q, inbound_queue_full);
+ if (q->irq_ptr->perf_stat_enabled)
+ account_sbals(q, count);
break;
case SLSB_P_INPUT_ERROR:
announce_buffer_error(q, count);
/* process the buffer, the upper layer will take care of it */
q->first_to_check = add_buf(q->first_to_check, count);
atomic_sub(count, &q->nr_buf_used);
+ if (q->irq_ptr->perf_stat_enabled)
+ account_sbals_error(q, count);
break;
case SLSB_CU_INPUT_EMPTY:
case SLSB_P_INPUT_NOT_INIT:
case SLSB_P_INPUT_ACK:
+ if (q->irq_ptr->perf_stat_enabled)
+ q->q_stats.nr_sbal_nop++;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in nop");
break;
default:
@@ -514,7 +534,7 @@ static int qdio_inbound_q_moved(struct qdio_q *q)
if ((bufnr != q->last_move) || q->qdio_error) {
q->last_move = bufnr;
- if (!is_thinint_irq(q->irq_ptr) && !MACHINE_IS_VM)
+ if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR)
q->u.in.timestamp = get_usecs();
return 1;
} else
@@ -531,7 +551,7 @@ static inline int qdio_inbound_q_done(struct qdio_q *q)
qdio_siga_sync_q(q);
get_buf_state(q, q->first_to_check, &state, 0);
- if (state == SLSB_P_INPUT_PRIMED)
+ if (state == SLSB_P_INPUT_PRIMED || state == SLSB_P_INPUT_ERROR)
/* more work coming */
return 0;
@@ -568,10 +588,11 @@ static void qdio_kick_handler(struct qdio_q *q)
if (q->is_input_q) {
qperf_inc(q, inbound_handler);
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%02x c:%02x", start, count);
- } else
+ } else {
qperf_inc(q, outbound_handler);
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x",
start, count);
+ }
q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count,
q->irq_ptr->int_parm);
@@ -643,15 +664,21 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
atomic_sub(count, &q->nr_buf_used);
q->first_to_check = add_buf(q->first_to_check, count);
+ if (q->irq_ptr->perf_stat_enabled)
+ account_sbals(q, count);
break;
case SLSB_P_OUTPUT_ERROR:
announce_buffer_error(q, count);
/* process the buffer, the upper layer will take care of it */
q->first_to_check = add_buf(q->first_to_check, count);
atomic_sub(count, &q->nr_buf_used);
+ if (q->irq_ptr->perf_stat_enabled)
+ account_sbals_error(q, count);
break;
case SLSB_CU_OUTPUT_PRIMED:
/* the adapter has not fetched the output yet */
+ if (q->irq_ptr->perf_stat_enabled)
+ q->q_stats.nr_sbal_nop++;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out primed:%1d", q->nr);
break;
case SLSB_P_OUTPUT_NOT_INIT:
@@ -960,6 +987,8 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
qdio_handle_activate_check(cdev, intparm, cstat,
dstat);
break;
+ case QDIO_IRQ_STATE_STOPPED:
+ break;
default:
WARN_ON(1);
}
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 8c2dea5fa2b4..7f4a75465140 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -333,10 +333,10 @@ static void __qdio_allocate_fill_qdr(struct qdio_irq *irq_ptr,
irq_ptr->qdr->qdf0[i + nr].slsba =
(unsigned long)&irq_ptr_qs[i]->slsb.val[0];
- irq_ptr->qdr->qdf0[i + nr].akey = PAGE_DEFAULT_KEY;
- irq_ptr->qdr->qdf0[i + nr].bkey = PAGE_DEFAULT_KEY;
- irq_ptr->qdr->qdf0[i + nr].ckey = PAGE_DEFAULT_KEY;
- irq_ptr->qdr->qdf0[i + nr].dkey = PAGE_DEFAULT_KEY;
+ irq_ptr->qdr->qdf0[i + nr].akey = PAGE_DEFAULT_KEY >> 4;
+ irq_ptr->qdr->qdf0[i + nr].bkey = PAGE_DEFAULT_KEY >> 4;
+ irq_ptr->qdr->qdf0[i + nr].ckey = PAGE_DEFAULT_KEY >> 4;
+ irq_ptr->qdr->qdf0[i + nr].dkey = PAGE_DEFAULT_KEY >> 4;
}
static void setup_qdr(struct qdio_irq *irq_ptr,
@@ -350,7 +350,7 @@ static void setup_qdr(struct qdio_irq *irq_ptr,
irq_ptr->qdr->iqdsz = sizeof(struct qdesfmt0) / 4; /* size in words */
irq_ptr->qdr->oqdsz = sizeof(struct qdesfmt0) / 4;
irq_ptr->qdr->qiba = (unsigned long)&irq_ptr->qib;
- irq_ptr->qdr->qkey = PAGE_DEFAULT_KEY;
+ irq_ptr->qdr->qkey = PAGE_DEFAULT_KEY >> 4;
for (i = 0; i < qdio_init->no_input_qs; i++)
__qdio_allocate_fill_qdr(irq_ptr, irq_ptr->input_qs, i, 0);
@@ -382,7 +382,15 @@ int qdio_setup_irq(struct qdio_initialize *init_data)
struct qdio_irq *irq_ptr = init_data->cdev->private->qdio_data;
int rc;
- memset(irq_ptr, 0, ((char *)&irq_ptr->qdr) - ((char *)irq_ptr));
+ memset(&irq_ptr->qib, 0, sizeof(irq_ptr->qib));
+ memset(&irq_ptr->siga_flag, 0, sizeof(irq_ptr->siga_flag));
+ memset(&irq_ptr->ccw, 0, sizeof(irq_ptr->ccw));
+ memset(&irq_ptr->ssqd_desc, 0, sizeof(irq_ptr->ssqd_desc));
+ memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
+
+ irq_ptr->debugfs_dev = irq_ptr->debugfs_perf = NULL;
+ irq_ptr->sch_token = irq_ptr->state = irq_ptr->perf_stat_enabled = 0;
+
/* wipes qib.ac, required by ar7063 */
memset(irq_ptr->qdr, 0, sizeof(struct qdr));
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index 091d904d3182..9942c1031b25 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -198,8 +198,8 @@ static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset)
.code = 0x0021,
};
scssc_area->operation_code = 0;
- scssc_area->ks = PAGE_DEFAULT_KEY;
- scssc_area->kc = PAGE_DEFAULT_KEY;
+ scssc_area->ks = PAGE_DEFAULT_KEY >> 4;
+ scssc_area->kc = PAGE_DEFAULT_KEY >> 4;
scssc_area->isc = QDIO_AIRQ_ISC;
scssc_area->schid = irq_ptr->schid;
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index c68be24e27d9..ba50fe02e572 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -33,6 +33,7 @@
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/compat.h>
#include <linux/smp_lock.h>
#include <asm/atomic.h>
@@ -912,126 +913,105 @@ static struct miscdevice zcrypt_misc_device = {
*/
static struct proc_dir_entry *zcrypt_entry;
-static int sprintcl(unsigned char *outaddr, unsigned char *addr,
- unsigned int len)
+static void sprintcl(struct seq_file *m, unsigned char *addr, unsigned int len)
{
- int hl, i;
+ int i;
- hl = 0;
for (i = 0; i < len; i++)
- hl += sprintf(outaddr+hl, "%01x", (unsigned int) addr[i]);
- hl += sprintf(outaddr+hl, " ");
- return hl;
+ seq_printf(m, "%01x", (unsigned int) addr[i]);
+ seq_putc(m, ' ');
}
-static int sprintrw(unsigned char *outaddr, unsigned char *addr,
- unsigned int len)
+static void sprintrw(struct seq_file *m, unsigned char *addr, unsigned int len)
{
- int hl, inl, c, cx;
+ int inl, c, cx;
- hl = sprintf(outaddr, " ");
+ seq_printf(m, " ");
inl = 0;
for (c = 0; c < (len / 16); c++) {
- hl += sprintcl(outaddr+hl, addr+inl, 16);
+ sprintcl(m, addr+inl, 16);
inl += 16;
}
cx = len%16;
if (cx) {
- hl += sprintcl(outaddr+hl, addr+inl, cx);
+ sprintcl(m, addr+inl, cx);
inl += cx;
}
- hl += sprintf(outaddr+hl, "\n");
- return hl;
+ seq_putc(m, '\n');
}
-static int sprinthx(unsigned char *title, unsigned char *outaddr,
- unsigned char *addr, unsigned int len)
+static void sprinthx(unsigned char *title, struct seq_file *m,
+ unsigned char *addr, unsigned int len)
{
- int hl, inl, r, rx;
+ int inl, r, rx;
- hl = sprintf(outaddr, "\n%s\n", title);
+ seq_printf(m, "\n%s\n", title);
inl = 0;
for (r = 0; r < (len / 64); r++) {
- hl += sprintrw(outaddr+hl, addr+inl, 64);
+ sprintrw(m, addr+inl, 64);
inl += 64;
}
rx = len % 64;
if (rx) {
- hl += sprintrw(outaddr+hl, addr+inl, rx);
+ sprintrw(m, addr+inl, rx);
inl += rx;
}
- hl += sprintf(outaddr+hl, "\n");
- return hl;
+ seq_putc(m, '\n');
}
-static int sprinthx4(unsigned char *title, unsigned char *outaddr,
- unsigned int *array, unsigned int len)
+static void sprinthx4(unsigned char *title, struct seq_file *m,
+ unsigned int *array, unsigned int len)
{
- int hl, r;
+ int r;
- hl = sprintf(outaddr, "\n%s\n", title);
+ seq_printf(m, "\n%s\n", title);
for (r = 0; r < len; r++) {
if ((r % 8) == 0)
- hl += sprintf(outaddr+hl, " ");
- hl += sprintf(outaddr+hl, "%08X ", array[r]);
+ seq_printf(m, " ");
+ seq_printf(m, "%08X ", array[r]);
if ((r % 8) == 7)
- hl += sprintf(outaddr+hl, "\n");
+ seq_putc(m, '\n');
}
- hl += sprintf(outaddr+hl, "\n");
- return hl;
+ seq_putc(m, '\n');
}
-static int zcrypt_status_read(char *resp_buff, char **start, off_t offset,
- int count, int *eof, void *data)
+static int zcrypt_proc_show(struct seq_file *m, void *v)
{
- unsigned char *workarea;
- int len;
-
- len = 0;
-
- /* resp_buff is a page. Use the right half for a work area */
- workarea = resp_buff + 2000;
- len += sprintf(resp_buff + len, "\nzcrypt version: %d.%d.%d\n",
- ZCRYPT_VERSION, ZCRYPT_RELEASE, ZCRYPT_VARIANT);
- len += sprintf(resp_buff + len, "Cryptographic domain: %d\n",
- ap_domain_index);
- len += sprintf(resp_buff + len, "Total device count: %d\n",
- zcrypt_device_count);
- len += sprintf(resp_buff + len, "PCICA count: %d\n",
- zcrypt_count_type(ZCRYPT_PCICA));
- len += sprintf(resp_buff + len, "PCICC count: %d\n",
- zcrypt_count_type(ZCRYPT_PCICC));
- len += sprintf(resp_buff + len, "PCIXCC MCL2 count: %d\n",
- zcrypt_count_type(ZCRYPT_PCIXCC_MCL2));
- len += sprintf(resp_buff + len, "PCIXCC MCL3 count: %d\n",
- zcrypt_count_type(ZCRYPT_PCIXCC_MCL3));
- len += sprintf(resp_buff + len, "CEX2C count: %d\n",
- zcrypt_count_type(ZCRYPT_CEX2C));
- len += sprintf(resp_buff + len, "CEX2A count: %d\n",
- zcrypt_count_type(ZCRYPT_CEX2A));
- len += sprintf(resp_buff + len, "CEX3C count: %d\n",
- zcrypt_count_type(ZCRYPT_CEX3C));
- len += sprintf(resp_buff + len, "CEX3A count: %d\n",
- zcrypt_count_type(ZCRYPT_CEX3A));
- len += sprintf(resp_buff + len, "requestq count: %d\n",
- zcrypt_requestq_count());
- len += sprintf(resp_buff + len, "pendingq count: %d\n",
- zcrypt_pendingq_count());
- len += sprintf(resp_buff + len, "Total open handles: %d\n\n",
- atomic_read(&zcrypt_open_count));
+ char workarea[sizeof(int) * AP_DEVICES];
+
+ seq_printf(m, "\nzcrypt version: %d.%d.%d\n",
+ ZCRYPT_VERSION, ZCRYPT_RELEASE, ZCRYPT_VARIANT);
+ seq_printf(m, "Cryptographic domain: %d\n", ap_domain_index);
+ seq_printf(m, "Total device count: %d\n", zcrypt_device_count);
+ seq_printf(m, "PCICA count: %d\n", zcrypt_count_type(ZCRYPT_PCICA));
+ seq_printf(m, "PCICC count: %d\n", zcrypt_count_type(ZCRYPT_PCICC));
+ seq_printf(m, "PCIXCC MCL2 count: %d\n",
+ zcrypt_count_type(ZCRYPT_PCIXCC_MCL2));
+ seq_printf(m, "PCIXCC MCL3 count: %d\n",
+ zcrypt_count_type(ZCRYPT_PCIXCC_MCL3));
+ seq_printf(m, "CEX2C count: %d\n", zcrypt_count_type(ZCRYPT_CEX2C));
+ seq_printf(m, "CEX2A count: %d\n", zcrypt_count_type(ZCRYPT_CEX2A));
+ seq_printf(m, "CEX3C count: %d\n", zcrypt_count_type(ZCRYPT_CEX3C));
+ seq_printf(m, "CEX3A count: %d\n", zcrypt_count_type(ZCRYPT_CEX3A));
+ seq_printf(m, "requestq count: %d\n", zcrypt_requestq_count());
+ seq_printf(m, "pendingq count: %d\n", zcrypt_pendingq_count());
+ seq_printf(m, "Total open handles: %d\n\n",
+ atomic_read(&zcrypt_open_count));
zcrypt_status_mask(workarea);
- len += sprinthx("Online devices: 1=PCICA 2=PCICC 3=PCIXCC(MCL2) "
- "4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A 7=CEX3C 8=CEX3A",
- resp_buff+len, workarea, AP_DEVICES);
+ sprinthx("Online devices: 1=PCICA 2=PCICC 3=PCIXCC(MCL2) "
+ "4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A 7=CEX3C 8=CEX3A",
+ m, workarea, AP_DEVICES);
zcrypt_qdepth_mask(workarea);
- len += sprinthx("Waiting work element counts",
- resp_buff+len, workarea, AP_DEVICES);
+ sprinthx("Waiting work element counts", m, workarea, AP_DEVICES);
zcrypt_perdev_reqcnt((int *) workarea);
- len += sprinthx4("Per-device successfully completed request counts",
- resp_buff+len,(unsigned int *) workarea, AP_DEVICES);
- *eof = 1;
- memset((void *) workarea, 0x00, AP_DEVICES * sizeof(unsigned int));
- return len;
+ sprinthx4("Per-device successfully completed request counts",
+ m, (unsigned int *) workarea, AP_DEVICES);
+ return 0;
+}
+
+static int zcrypt_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, zcrypt_proc_show, NULL);
}
static void zcrypt_disable_card(int index)
@@ -1061,11 +1041,11 @@ static void zcrypt_enable_card(int index)
spin_unlock_bh(&zcrypt_device_lock);
}
-static int zcrypt_status_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+static ssize_t zcrypt_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *pos)
{
unsigned char *lbuf, *ptr;
- unsigned long local_count;
+ size_t local_count;
int j;
if (count <= 0)
@@ -1115,6 +1095,15 @@ out:
return count;
}
+static const struct file_operations zcrypt_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = zcrypt_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = zcrypt_proc_write,
+};
+
static int zcrypt_rng_device_count;
static u32 *zcrypt_rng_buffer;
static int zcrypt_rng_buffer_index;
@@ -1197,14 +1186,11 @@ int __init zcrypt_api_init(void)
goto out;
/* Set up the proc file system */
- zcrypt_entry = create_proc_entry("driver/z90crypt", 0644, NULL);
+ zcrypt_entry = proc_create("driver/z90crypt", 0644, NULL, &zcrypt_proc_fops);
if (!zcrypt_entry) {
rc = -ENOMEM;
goto out_misc;
}
- zcrypt_entry->data = NULL;
- zcrypt_entry->read_proc = zcrypt_status_read;
- zcrypt_entry->write_proc = zcrypt_status_write;
return 0;
diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c
index a23726a0735c..142f72a2ca5a 100644
--- a/drivers/s390/crypto/zcrypt_pcicc.c
+++ b/drivers/s390/crypto/zcrypt_pcicc.c
@@ -373,6 +373,8 @@ static int convert_type86(struct zcrypt_device *zdev,
zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD;
return -EAGAIN;
}
+ if (service_rc == 8 && service_rs == 72)
+ return -EINVAL;
zdev->online = 0;
return -EAGAIN; /* repeat the request on a different device. */
}
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index 79c120578e61..68f3e6204db8 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -470,6 +470,8 @@ static int convert_type86_ica(struct zcrypt_device *zdev,
}
if (service_rc == 12 && service_rs == 769)
return -EINVAL;
+ if (service_rc == 8 && service_rs == 72)
+ return -EINVAL;
zdev->online = 0;
return -EAGAIN; /* repeat the request on a different device. */
}
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index 2930fc763ac5..b2fc4fd63f7f 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -340,11 +340,11 @@ static void kvm_extint_handler(u16 code)
return;
/* The LSB might be overloaded, we have to mask it */
- vq = (struct virtqueue *) ((*(long *) __LC_PFAULT_INTPARM) & ~1UL);
+ vq = (struct virtqueue *)(S390_lowcore.ext_params2 & ~1UL);
/* We use the LSB of extparam, to decide, if this interrupt is a config
* change or a "standard" interrupt */
- config_changed = (*(int *) __LC_EXT_PARAMS & 1);
+ config_changed = S390_lowcore.ext_params & 1;
if (config_changed) {
struct virtio_driver *drv;
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index cb909a5b5047..977bb4d4ed15 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -43,6 +43,16 @@ config SMSGIUCV
Select this option if you want to be able to receive SMSG messages
from other VM guest systems.
+config SMSGIUCV_EVENT
+ tristate "Deliver IUCV special messages as uevents (VM only)"
+ depends on SMSGIUCV
+ help
+ Select this option to deliver CP special messages (SMSGs) as
+ uevents. The driver handles only those special messages that
+ start with "APP".
+
+ To compile as a module, choose M. The module name is "smsgiucv_app".
+
config CLAW
tristate "CLAW device support"
depends on CCW && NETDEVICES
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
index 6cab5a62f99e..4dfe8c1092da 100644
--- a/drivers/s390/net/Makefile
+++ b/drivers/s390/net/Makefile
@@ -6,6 +6,7 @@ ctcm-y += ctcm_main.o ctcm_fsms.o ctcm_mpc.o ctcm_sysfs.o ctcm_dbug.o
obj-$(CONFIG_CTCM) += ctcm.o fsm.o
obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
+obj-$(CONFIG_SMSGIUCV_EVENT) += smsgiucv_app.o
obj-$(CONFIG_LCS) += lcs.o
obj-$(CONFIG_CLAW) += claw.o
qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index b232693378cd..fcd005aad989 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -649,6 +649,7 @@ struct qeth_card_options {
int performance_stats;
int rx_sg_cb;
enum qeth_ipa_isolation_modes isolation;
+ int sniffer;
};
/*
@@ -737,6 +738,7 @@ struct qeth_card {
struct qeth_discipline discipline;
atomic_t force_alloc_skb;
struct service_level qeth_service_level;
+ struct qdio_ssqd_desc ssqd;
};
struct qeth_card_list_struct {
@@ -761,7 +763,8 @@ static inline int qeth_get_micros(void)
static inline int qeth_get_ip_version(struct sk_buff *skb)
{
- switch (skb->protocol) {
+ struct ethhdr *ehdr = (struct ethhdr *)skb->data;
+ switch (ehdr->h_proto) {
case ETH_P_IPV6:
return 6;
case ETH_P_IP:
@@ -811,7 +814,8 @@ int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *,
struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *,
enum qeth_ipa_cmds, enum qeth_prot_versions);
int qeth_query_setadapterparms(struct qeth_card *);
-int qeth_check_qdio_errors(struct qdio_buffer *, unsigned int, const char *);
+int qeth_check_qdio_errors(struct qeth_card *, struct qdio_buffer *,
+ unsigned int, const char *);
void qeth_queue_input_buffer(struct qeth_card *, int);
struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
struct qdio_buffer *, struct qdio_buffer_element **, int *,
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index d34804d5ece1..3bd4206f3470 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -269,6 +269,7 @@ int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt)
card->qdio.init_pool.buf_count = bufcnt;
return qeth_alloc_buffer_pool(card);
}
+EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool);
static int qeth_issue_next_read(struct qeth_card *card)
{
@@ -350,8 +351,10 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
if (IS_IPA(iob->data)) {
cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
if (IS_IPA_REPLY(cmd)) {
- if (cmd->hdr.command < IPA_CMD_SETCCID ||
- cmd->hdr.command > IPA_CMD_MODCCID)
+ if (cmd->hdr.command != IPA_CMD_SETCCID &&
+ cmd->hdr.command != IPA_CMD_DELCCID &&
+ cmd->hdr.command != IPA_CMD_MODCCID &&
+ cmd->hdr.command != IPA_CMD_SET_DIAG_ASS)
qeth_issue_ipa_msg(cmd,
cmd->hdr.return_code, card);
return cmd;
@@ -534,7 +537,8 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel,
dev_err(&card->gdev->dev,
"The qeth device is not configured "
"for the OSI layer required by z/VM\n");
- qeth_schedule_recovery(card);
+ else
+ qeth_schedule_recovery(card);
goto out;
}
@@ -1100,11 +1104,6 @@ static int qeth_setup_card(struct qeth_card *card)
card->thread_running_mask = 0;
INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread);
INIT_LIST_HEAD(&card->ip_list);
- card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL);
- if (!card->ip_tbd_list) {
- QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
- return -ENOMEM;
- }
INIT_LIST_HEAD(card->ip_tbd_list);
INIT_LIST_HEAD(&card->cmd_waiter_list);
init_waitqueue_head(&card->wait_q);
@@ -1115,8 +1114,6 @@ static int qeth_setup_card(struct qeth_card *card)
card->ipato.enabled = 0;
card->ipato.invert4 = 0;
card->ipato.invert6 = 0;
- if (card->info.type == QETH_CARD_TYPE_IQD)
- card->options.checksum_type = NO_CHECKSUMMING;
/* init QDIO stuff */
qeth_init_qdio_info(card);
return 0;
@@ -1138,21 +1135,30 @@ static struct qeth_card *qeth_alloc_card(void)
QETH_DBF_TEXT(SETUP, 2, "alloccrd");
card = kzalloc(sizeof(struct qeth_card), GFP_DMA|GFP_KERNEL);
if (!card)
- return NULL;
+ goto out;
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
- if (qeth_setup_channel(&card->read)) {
- kfree(card);
- return NULL;
- }
- if (qeth_setup_channel(&card->write)) {
- qeth_clean_channel(&card->read);
- kfree(card);
- return NULL;
+ card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+ if (!card->ip_tbd_list) {
+ QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
+ goto out_card;
}
+ if (qeth_setup_channel(&card->read))
+ goto out_ip;
+ if (qeth_setup_channel(&card->write))
+ goto out_channel;
card->options.layer2 = -1;
card->qeth_service_level.seq_print = qeth_core_sl_print;
register_service_level(&card->qeth_service_level);
return card;
+
+out_channel:
+ qeth_clean_channel(&card->read);
+out_ip:
+ kfree(card->ip_tbd_list);
+out_card:
+ kfree(card);
+out:
+ return NULL;
}
static int qeth_determine_card_type(struct qeth_card *card)
@@ -1355,26 +1361,29 @@ static int qeth_read_conf_data(struct qeth_card *card, void **buffer,
return ret;
}
-static int qeth_get_unitaddr(struct qeth_card *card)
+static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd)
{
- int length;
- char *prcd;
- int rc;
-
- QETH_DBF_TEXT(SETUP, 2, "getunit");
- rc = qeth_read_conf_data(card, (void **) &prcd, &length);
- if (rc) {
- QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
- dev_name(&card->gdev->dev), rc);
- return rc;
- }
+ QETH_DBF_TEXT(SETUP, 2, "cfgunit");
card->info.chpid = prcd[30];
card->info.unit_addr2 = prcd[31];
card->info.cula = prcd[63];
card->info.guestlan = ((prcd[0x10] == _ascebc['V']) &&
(prcd[0x11] == _ascebc['M']));
- kfree(prcd);
- return 0;
+}
+
+static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd)
+{
+ QETH_DBF_TEXT(SETUP, 2, "cfgblkt");
+
+ if (prcd[74] == 0xF0 && prcd[75] == 0xF0 && prcd[76] == 0xF5) {
+ card->info.blkt.time_total = 250;
+ card->info.blkt.inter_packet = 5;
+ card->info.blkt.inter_packet_jumbo = 15;
+ } else {
+ card->info.blkt.time_total = 0;
+ card->info.blkt.inter_packet = 0;
+ card->info.blkt.inter_packet_jumbo = 0;
+ }
}
static void qeth_init_tokens(struct qeth_card *card)
@@ -2573,8 +2582,8 @@ int qeth_query_setadapterparms(struct qeth_card *card)
}
EXPORT_SYMBOL_GPL(qeth_query_setadapterparms);
-int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
- const char *dbftext)
+int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf,
+ unsigned int qdio_error, const char *dbftext)
{
if (qdio_error) {
QETH_DBF_TEXT(TRACE, 2, dbftext);
@@ -2584,7 +2593,11 @@ int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
QETH_DBF_TEXT_(QERR, 2, " F14=%02X",
buf->element[14].flags & 0xff);
QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error);
- return 1;
+ if ((buf->element[15].flags & 0xff) == 0x12) {
+ card->stats.rx_dropped++;
+ return 0;
+ } else
+ return 1;
}
return 0;
}
@@ -2667,7 +2680,7 @@ static int qeth_handle_send_error(struct qeth_card *card,
qdio_err = 1;
}
}
- qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr");
+ qeth_check_qdio_errors(card, buffer->buffer, qdio_err, "qouterr");
if (!qdio_err)
return QETH_SEND_ERROR_NONE;
@@ -3509,6 +3522,7 @@ void qeth_tx_timeout(struct net_device *dev)
{
struct qeth_card *card;
+ QETH_DBF_TEXT(TRACE, 4, "txtimeo");
card = dev->ml_priv;
card->stats.tx_errors++;
qeth_schedule_recovery(card);
@@ -3790,9 +3804,6 @@ static int qeth_qdio_establish(struct qeth_card *card)
init_data.input_handler = card->discipline.input_handler;
init_data.output_handler = card->discipline.output_handler;
init_data.int_parm = (unsigned long) card;
- init_data.flags = QDIO_INBOUND_0COPY_SBALS |
- QDIO_OUTBOUND_0COPY_SBALS |
- QDIO_USE_OUTBOUND_PCIS;
init_data.input_sbal_addr_array = (void **) in_sbal_ptrs;
init_data.output_sbal_addr_array = (void **) out_sbal_ptrs;
@@ -3847,9 +3858,7 @@ static int qeth_core_driver_group(const char *buf, struct device *root_dev,
int qeth_core_hardsetup_card(struct qeth_card *card)
{
- struct qdio_ssqd_desc *ssqd;
int retries = 0;
- int mpno = 0;
int rc;
QETH_DBF_TEXT(SETUP, 2, "hrdsetup");
@@ -3882,31 +3891,6 @@ retriable:
else
goto retry;
}
-
- rc = qeth_get_unitaddr(card);
- if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
- return rc;
- }
-
- ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL);
- if (!ssqd) {
- rc = -ENOMEM;
- goto out;
- }
- rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd);
- if (rc == 0)
- mpno = ssqd->pcnt;
- kfree(ssqd);
-
- if (mpno)
- mpno = min(mpno - 1, QETH_MAX_PORTNO);
- if (card->info.portno > mpno) {
- QETH_DBF_MESSAGE(2, "Device %s does not offer port number %d"
- "\n.", CARD_BUS_ID(card), card->info.portno);
- rc = -ENODEV;
- goto out;
- }
qeth_init_tokens(card);
qeth_init_func_level(card);
rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb);
@@ -3990,7 +3974,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
struct qdio_buffer_element *element = *__element;
int offset = *__offset;
struct sk_buff *skb = NULL;
- int skb_len;
+ int skb_len = 0;
void *data_ptr;
int data_len;
int headroom = 0;
@@ -4009,20 +3993,24 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
*hdr = element->addr + offset;
offset += sizeof(struct qeth_hdr);
- if (card->options.layer2) {
- if (card->info.type == QETH_CARD_TYPE_OSN) {
- skb_len = (*hdr)->hdr.osn.pdu_length;
- headroom = sizeof(struct qeth_hdr);
- } else {
- skb_len = (*hdr)->hdr.l2.pkt_length;
- }
- } else {
+ switch ((*hdr)->hdr.l2.id) {
+ case QETH_HEADER_TYPE_LAYER2:
+ skb_len = (*hdr)->hdr.l2.pkt_length;
+ break;
+ case QETH_HEADER_TYPE_LAYER3:
skb_len = (*hdr)->hdr.l3.length;
if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) ||
(card->info.link_type == QETH_LINK_TYPE_HSTR))
headroom = TR_HLEN;
else
headroom = ETH_HLEN;
+ break;
+ case QETH_HEADER_TYPE_OSN:
+ skb_len = (*hdr)->hdr.osn.pdu_length;
+ headroom = sizeof(struct qeth_hdr);
+ break;
+ default:
+ break;
}
if (!skb_len)
@@ -4177,6 +4165,41 @@ void qeth_core_free_discipline(struct qeth_card *card)
card->discipline.ccwgdriver = NULL;
}
+static void qeth_determine_capabilities(struct qeth_card *card)
+{
+ int rc;
+ int length;
+ char *prcd;
+
+ QETH_DBF_TEXT(SETUP, 2, "detcapab");
+ rc = ccw_device_set_online(CARD_DDEV(card));
+ if (rc) {
+ QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+ goto out;
+ }
+
+
+ rc = qeth_read_conf_data(card, (void **) &prcd, &length);
+ if (rc) {
+ QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
+ dev_name(&card->gdev->dev), rc);
+ QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+ goto out_offline;
+ }
+ qeth_configure_unitaddr(card, prcd);
+ qeth_configure_blkt_default(card, prcd);
+ kfree(prcd);
+
+ rc = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
+ if (rc)
+ QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+
+out_offline:
+ ccw_device_set_offline(CARD_DDEV(card));
+out:
+ return;
+}
+
static int qeth_core_probe_device(struct ccwgroup_device *gdev)
{
struct qeth_card *card;
@@ -4242,6 +4265,8 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
list_add_tail(&card->list, &qeth_core_card_list.list);
write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);
+
+ qeth_determine_capabilities(card);
return 0;
err_card:
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index 1ba51152f667..104a3351e02b 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -156,6 +156,8 @@ enum qeth_ipa_return_codes {
IPA_RC_IP_TABLE_FULL = 0x0002,
IPA_RC_UNKNOWN_ERROR = 0x0003,
IPA_RC_UNSUPPORTED_COMMAND = 0x0004,
+ IPA_RC_TRACE_ALREADY_ACTIVE = 0x0005,
+ IPA_RC_INVALID_FORMAT = 0x0006,
IPA_RC_DUP_IPV6_REMOTE = 0x0008,
IPA_RC_DUP_IPV6_HOME = 0x0010,
IPA_RC_UNREGISTERED_ADDR = 0x0011,
@@ -196,6 +198,11 @@ enum qeth_ipa_return_codes {
IPA_RC_INVALID_IP_VERSION2 = 0xf001,
IPA_RC_FFFF = 0xffff
};
+/* for DELIP */
+#define IPA_RC_IP_ADDRESS_NOT_DEFINED IPA_RC_PRIMARY_ALREADY_DEFINED
+/* for SET_DIAGNOSTIC_ASSIST */
+#define IPA_RC_INVALID_SUBCMD IPA_RC_IP_TABLE_FULL
+#define IPA_RC_HARDWARE_AUTH_ERROR IPA_RC_UNKNOWN_ERROR
/* IPA function flags; each flag marks availability of respective function */
enum qeth_ipa_funcs {
@@ -246,6 +253,7 @@ enum qeth_ipa_setadp_cmd {
IPA_SETADP_SET_SNMP_CONTROL = 0x00000200L,
IPA_SETADP_QUERY_CARD_INFO = 0x00000400L,
IPA_SETADP_SET_PROMISC_MODE = 0x00000800L,
+ IPA_SETADP_SET_DIAG_ASSIST = 0x00002000L,
IPA_SETADP_SET_ACCESS_CONTROL = 0x00010000L,
};
enum qeth_ipa_mac_ops {
@@ -424,6 +432,40 @@ struct qeth_create_destroy_address {
__u8 unique_id[8];
} __attribute__ ((packed));
+/* SET DIAGNOSTIC ASSIST IPA Command: *************************************/
+
+enum qeth_diags_cmds {
+ QETH_DIAGS_CMD_QUERY = 0x0001,
+ QETH_DIAGS_CMD_TRAP = 0x0002,
+ QETH_DIAGS_CMD_TRACE = 0x0004,
+ QETH_DIAGS_CMD_NOLOG = 0x0008,
+ QETH_DIAGS_CMD_DUMP = 0x0010,
+};
+
+enum qeth_diags_trace_types {
+ QETH_DIAGS_TYPE_HIPERSOCKET = 0x02,
+};
+
+enum qeth_diags_trace_cmds {
+ QETH_DIAGS_CMD_TRACE_ENABLE = 0x0001,
+ QETH_DIAGS_CMD_TRACE_DISABLE = 0x0002,
+ QETH_DIAGS_CMD_TRACE_MODIFY = 0x0004,
+ QETH_DIAGS_CMD_TRACE_REPLACE = 0x0008,
+ QETH_DIAGS_CMD_TRACE_QUERY = 0x0010,
+};
+
+struct qeth_ipacmd_diagass {
+ __u32 host_tod2;
+ __u32:32;
+ __u16 subcmd_len;
+ __u16:16;
+ __u32 subcmd;
+ __u8 type;
+ __u8 action;
+ __u16 options;
+ __u32:32;
+} __attribute__ ((packed));
+
/* Header for each IPA command */
struct qeth_ipacmd_hdr {
__u8 command;
@@ -452,6 +494,7 @@ struct qeth_ipa_cmd {
struct qeth_create_destroy_address create_destroy_addr;
struct qeth_ipacmd_setadpparms setadapterparms;
struct qeth_set_routing setrtg;
+ struct qeth_ipacmd_diagass diagass;
} data;
} __attribute__ ((packed));
@@ -469,7 +512,6 @@ enum qeth_ipa_arp_return_codes {
QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008,
};
-
extern char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc);
extern char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd);
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index 9ff2b36fdc43..25dfd5abd19b 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -8,6 +8,9 @@
* Frank Blaschka <frank.blaschka@de.ibm.com>
*/
+#define KMSG_COMPONENT "qeth"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/list.h>
#include <linux/rwsem.h>
#include <asm/ebcdic.h>
@@ -118,7 +121,7 @@ static ssize_t qeth_dev_portno_store(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
char *tmp;
- unsigned int portno;
+ unsigned int portno, limit;
if (!card)
return -EINVAL;
@@ -128,9 +131,11 @@ static ssize_t qeth_dev_portno_store(struct device *dev,
return -EPERM;
portno = simple_strtoul(buf, &tmp, 16);
- if (portno > QETH_MAX_PORTNO) {
+ if (portno > QETH_MAX_PORTNO)
+ return -EINVAL;
+ limit = (card->ssqd.pcnt ? card->ssqd.pcnt - 1 : card->ssqd.pcnt);
+ if (portno > limit)
return -EINVAL;
- }
card->info.portno = portno;
return count;
@@ -537,7 +542,7 @@ static ssize_t qeth_dev_blkt_total_store(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev);
return qeth_dev_blkt_store(card, buf, count,
- &card->info.blkt.time_total, 1000);
+ &card->info.blkt.time_total, 5000);
}
@@ -559,7 +564,7 @@ static ssize_t qeth_dev_blkt_inter_store(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev);
return qeth_dev_blkt_store(card, buf, count,
- &card->info.blkt.inter_packet, 100);
+ &card->info.blkt.inter_packet, 1000);
}
static DEVICE_ATTR(inter, 0644, qeth_dev_blkt_inter_show,
@@ -580,7 +585,7 @@ static ssize_t qeth_dev_blkt_inter_jumbo_store(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev);
return qeth_dev_blkt_store(card, buf, count,
- &card->info.blkt.inter_packet_jumbo, 100);
+ &card->info.blkt.inter_packet_jumbo, 1000);
}
static DEVICE_ATTR(inter_jumbo, 0644, qeth_dev_blkt_inter_jumbo_show,
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 0b763396d5d1..6f1e3036bafd 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -486,22 +486,14 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card,
case IPA_RC_L2_DUP_MAC:
case IPA_RC_L2_DUP_LAYER3_MAC:
dev_warn(&card->gdev->dev,
- "MAC address "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
- "already exists\n",
- card->dev->dev_addr[0], card->dev->dev_addr[1],
- card->dev->dev_addr[2], card->dev->dev_addr[3],
- card->dev->dev_addr[4], card->dev->dev_addr[5]);
+ "MAC address %pM already exists\n",
+ card->dev->dev_addr);
break;
case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP:
case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP:
dev_warn(&card->gdev->dev,
- "MAC address "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
- "is not authorized\n",
- card->dev->dev_addr[0], card->dev->dev_addr[1],
- card->dev->dev_addr[2], card->dev->dev_addr[3],
- card->dev->dev_addr[4], card->dev->dev_addr[5]);
+ "MAC address %pM is not authorized\n",
+ card->dev->dev_addr);
break;
default:
break;
@@ -512,12 +504,8 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card,
memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac,
OSA_ADDR_LEN);
dev_info(&card->gdev->dev,
- "MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
- "successfully registered on device %s\n",
- card->dev->dev_addr[0], card->dev->dev_addr[1],
- card->dev->dev_addr[2], card->dev->dev_addr[3],
- card->dev->dev_addr[4], card->dev->dev_addr[5],
- card->dev->name);
+ "MAC address %pM successfully registered on device %s\n",
+ card->dev->dev_addr, card->dev->name);
}
return 0;
}
@@ -634,7 +622,7 @@ static void qeth_l2_set_multicast_list(struct net_device *dev)
for (dm = dev->mc_list; dm; dm = dm->next)
qeth_l2_add_mc(card, dm->da_addr, 0);
- list_for_each_entry(ha, &dev->uc.list, list)
+ netdev_for_each_uc_addr(ha, dev)
qeth_l2_add_mc(card, ha->addr, 1);
spin_unlock_bh(&card->mclock);
@@ -781,7 +769,8 @@ static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev,
index = i % QDIO_MAX_BUFFERS_PER_Q;
buffer = &card->qdio.in_q->bufs[index];
if (!(qdio_err &&
- qeth_check_qdio_errors(buffer->buffer, qdio_err, "qinerr")))
+ qeth_check_qdio_errors(card, buffer->buffer, qdio_err,
+ "qinerr")))
qeth_l2_process_inbound_buffer(card, buffer, index);
/* clear buffer and give back to hardware */
qeth_put_buffer_pool_entry(card, buffer->pool_entry);
@@ -938,7 +927,6 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
QETH_DBF_TEXT(SETUP, 2, "setonlin");
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
- qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1);
recover_flag = card->state;
rc = qeth_core_hardsetup_card(card);
if (rc) {
@@ -1083,11 +1071,9 @@ static int qeth_l2_recover(void *ptr)
dev_info(&card->gdev->dev,
"Device successfully recovered!\n");
else {
- if (card->dev) {
- rtnl_lock();
- dev_close(card->dev);
- rtnl_unlock();
- }
+ rtnl_lock();
+ dev_close(card->dev);
+ rtnl_unlock();
dev_warn(&card->gdev->dev, "The qeth device driver "
"failed to recover an error on the device\n");
}
@@ -1141,11 +1127,9 @@ static int qeth_l2_pm_resume(struct ccwgroup_device *gdev)
if (card->state == CARD_STATE_RECOVER) {
rc = __qeth_l2_set_online(card->gdev, 1);
if (rc) {
- if (card->dev) {
- rtnl_lock();
- dev_close(card->dev);
- rtnl_unlock();
- }
+ rtnl_lock();
+ dev_close(card->dev);
+ rtnl_unlock();
}
} else
rc = __qeth_l2_set_online(card->gdev, 0);
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h
index 321988fa9f7d..8447d233d0b3 100644
--- a/drivers/s390/net/qeth_l3.h
+++ b/drivers/s390/net/qeth_l3.h
@@ -13,6 +13,8 @@
#include "qeth_core.h"
+#define QETH_SNIFF_AVAIL 0x0008
+
struct qeth_ipaddr {
struct list_head entry;
enum qeth_ip_types type;
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index fd1b6ed3721f..b3b6e872d806 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -242,6 +242,8 @@ static int __qeth_l3_insert_ip_todo(struct qeth_card *card,
struct qeth_ipaddr *tmp, *t;
int found = 0;
+ if (card->options.sniffer)
+ return 0;
list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) {
if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) &&
(tmp->type == QETH_IP_TYPE_DEL_ALL_MC))
@@ -457,6 +459,8 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card)
QETH_DBF_TEXT(TRACE, 2, "sdiplist");
QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *));
+ if (card->options.sniffer)
+ return;
spin_lock_irqsave(&card->ip_lock, flags);
tbd_list = card->ip_tbd_list;
card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC);
@@ -495,7 +499,7 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card)
spin_unlock_irqrestore(&card->ip_lock, flags);
rc = qeth_l3_deregister_addr_entry(card, addr);
spin_lock_irqsave(&card->ip_lock, flags);
- if (!rc || (rc == IPA_RC_PRIMARY_ALREADY_DEFINED))
+ if (!rc || (rc == IPA_RC_IP_ADDRESS_NOT_DEFINED))
kfree(addr);
else
list_add_tail(&addr->entry, &card->ip_list);
@@ -513,6 +517,8 @@ static void qeth_l3_clear_ip_list(struct qeth_card *card, int clean,
unsigned long flags;
QETH_DBF_TEXT(TRACE, 4, "clearip");
+ if (recover && card->options.sniffer)
+ return;
spin_lock_irqsave(&card->ip_lock, flags);
/* clear todo list */
list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry) {
@@ -1674,6 +1680,80 @@ static int qeth_l3_get_unique_id(struct qeth_card *card)
return rc;
}
+static int
+qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply,
+ unsigned long data)
+{
+ struct qeth_ipa_cmd *cmd;
+ __u16 rc;
+
+ QETH_DBF_TEXT(SETUP, 2, "diastrcb");
+
+ cmd = (struct qeth_ipa_cmd *)data;
+ rc = cmd->hdr.return_code;
+ if (rc)
+ QETH_DBF_TEXT_(TRACE, 2, "dxter%x", rc);
+ switch (cmd->data.diagass.action) {
+ case QETH_DIAGS_CMD_TRACE_QUERY:
+ break;
+ case QETH_DIAGS_CMD_TRACE_DISABLE:
+ switch (rc) {
+ case 0:
+ case IPA_RC_INVALID_SUBCMD:
+ card->info.promisc_mode = SET_PROMISC_MODE_OFF;
+ dev_info(&card->gdev->dev, "The HiperSockets network "
+ "traffic analyzer is deactivated\n");
+ break;
+ default:
+ break;
+ }
+ break;
+ case QETH_DIAGS_CMD_TRACE_ENABLE:
+ switch (rc) {
+ case 0:
+ card->info.promisc_mode = SET_PROMISC_MODE_ON;
+ dev_info(&card->gdev->dev, "The HiperSockets network "
+ "traffic analyzer is activated\n");
+ break;
+ case IPA_RC_HARDWARE_AUTH_ERROR:
+ dev_warn(&card->gdev->dev, "The device is not "
+ "authorized to run as a HiperSockets network "
+ "traffic analyzer\n");
+ break;
+ case IPA_RC_TRACE_ALREADY_ACTIVE:
+ dev_warn(&card->gdev->dev, "A HiperSockets "
+ "network traffic analyzer is already "
+ "active in the HiperSockets LAN\n");
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ QETH_DBF_MESSAGE(2, "Unknown sniffer action (0x%04x) on %s\n",
+ cmd->data.diagass.action, QETH_CARD_IFNAME(card));
+ }
+
+ return 0;
+}
+
+static int
+qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd)
+{
+ struct qeth_cmd_buffer *iob;
+ struct qeth_ipa_cmd *cmd;
+
+ QETH_DBF_TEXT(SETUP, 2, "diagtrac");
+
+ iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
+ cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+ cmd->data.diagass.subcmd_len = 16;
+ cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRACE;
+ cmd->data.diagass.type = QETH_DIAGS_TYPE_HIPERSOCKET;
+ cmd->data.diagass.action = diags_cmd;
+ return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL);
+}
+
static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac,
struct net_device *dev)
{
@@ -1951,7 +2031,10 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card,
case QETH_CAST_ANYCAST:
case QETH_CAST_NOCAST:
default:
- skb->pkt_type = PACKET_HOST;
+ if (card->options.sniffer)
+ skb->pkt_type = PACKET_OTHERHOST;
+ else
+ skb->pkt_type = PACKET_HOST;
memcpy(tg_addr, card->dev->dev_addr,
card->dev->addr_len);
}
@@ -2007,7 +2090,6 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card,
int offset;
__u16 vlan_tag = 0;
unsigned int len;
-
/* get first element of current buffer */
element = (struct qdio_buffer_element *)&buf->buffer->element[0];
offset = 0;
@@ -2026,7 +2108,7 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card,
case QETH_HEADER_TYPE_LAYER3:
vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr);
len = skb->len;
- if (vlan_tag)
+ if (vlan_tag && !card->options.sniffer)
if (card->vlangrp)
vlan_hwaccel_rx(skb, card->vlangrp,
vlan_tag);
@@ -2037,6 +2119,16 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card,
else
netif_rx(skb);
break;
+ case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */
+ skb->pkt_type = PACKET_HOST;
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ if (card->options.checksum_type == NO_CHECKSUMMING)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+ len = skb->len;
+ netif_receive_skb(skb);
+ break;
default:
dev_kfree_skb_any(skb);
QETH_DBF_TEXT(TRACE, 3, "inbunkno");
@@ -2118,17 +2210,18 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
qeth_set_allowed_threads(card, 0, 1);
+ if (card->options.sniffer &&
+ (card->info.promisc_mode == SET_PROMISC_MODE_ON))
+ qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE);
if (card->read.state == CH_STATE_UP &&
card->write.state == CH_STATE_UP &&
(card->state == CARD_STATE_UP)) {
if (recovery_mode)
qeth_l3_stop(card->dev);
else {
- if (card->dev) {
- rtnl_lock();
- dev_close(card->dev);
- rtnl_unlock();
- }
+ rtnl_lock();
+ dev_close(card->dev);
+ rtnl_unlock();
}
if (!card->use_hard_stop) {
rc = qeth_send_stoplan(card);
@@ -2162,6 +2255,36 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
return rc;
}
+/*
+ * test for and Switch promiscuous mode (on or off)
+ * either for guestlan or HiperSocket Sniffer
+ */
+static void
+qeth_l3_handle_promisc_mode(struct qeth_card *card)
+{
+ struct net_device *dev = card->dev;
+
+ if (((dev->flags & IFF_PROMISC) &&
+ (card->info.promisc_mode == SET_PROMISC_MODE_ON)) ||
+ (!(dev->flags & IFF_PROMISC) &&
+ (card->info.promisc_mode == SET_PROMISC_MODE_OFF)))
+ return;
+
+ if (card->info.guestlan) { /* Guestlan trace */
+ if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
+ qeth_setadp_promisc_mode(card);
+ } else if (card->options.sniffer && /* HiperSockets trace */
+ qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) {
+ if (dev->flags & IFF_PROMISC) {
+ QETH_DBF_TEXT(TRACE, 3, "+promisc");
+ qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_ENABLE);
+ } else {
+ QETH_DBF_TEXT(TRACE, 3, "-promisc");
+ qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE);
+ }
+ }
+}
+
static void qeth_l3_set_multicast_list(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
@@ -2170,15 +2293,17 @@ static void qeth_l3_set_multicast_list(struct net_device *dev)
if (qeth_threads_running(card, QETH_RECOVER_THREAD) &&
(card->state != CARD_STATE_UP))
return;
- qeth_l3_delete_mc_addresses(card);
- qeth_l3_add_multicast_ipv4(card);
+ if (!card->options.sniffer) {
+ qeth_l3_delete_mc_addresses(card);
+ qeth_l3_add_multicast_ipv4(card);
#ifdef CONFIG_QETH_IPV6
- qeth_l3_add_multicast_ipv6(card);
+ qeth_l3_add_multicast_ipv6(card);
#endif
- qeth_l3_set_ip_addr_list(card);
- if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
- return;
- qeth_setadp_promisc_mode(card);
+ qeth_l3_set_ip_addr_list(card);
+ if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
+ return;
+ }
+ qeth_l3_handle_promisc_mode(card);
}
static const char *qeth_l3_arp_get_error_cause(int *rc)
@@ -2777,9 +2902,8 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
int data_offset = -1;
int nr_frags;
- if ((card->info.type == QETH_CARD_TYPE_IQD) &&
- (skb->protocol != htons(ETH_P_IPV6)) &&
- (skb->protocol != htons(ETH_P_IP)))
+ if (((card->info.type == QETH_CARD_TYPE_IQD) && (!ipv)) ||
+ card->options.sniffer)
goto tx_drop;
if ((card->state != CARD_STATE_UP) || !card->lan_online) {
@@ -2825,14 +2949,14 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (data_offset < 0)
skb_pull(new_skb, ETH_HLEN);
} else {
- if (new_skb->protocol == htons(ETH_P_IP)) {
+ if (ipv == 4) {
if (card->dev->type == ARPHRD_IEEE802_TR)
skb_pull(new_skb, TR_HLEN);
else
skb_pull(new_skb, ETH_HLEN);
}
- if (new_skb->protocol == ETH_P_IPV6 && card->vlangrp &&
+ if (ipv == 6 && card->vlangrp &&
vlan_tx_tag_present(new_skb)) {
skb_push(new_skb, VLAN_HLEN);
skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4);
@@ -3155,7 +3279,7 @@ static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev,
index = i % QDIO_MAX_BUFFERS_PER_Q;
buffer = &card->qdio.in_q->bufs[index];
if (!(qdio_err &&
- qeth_check_qdio_errors(buffer->buffer,
+ qeth_check_qdio_errors(card, buffer->buffer,
qdio_err, "qinerr")))
qeth_l3_process_inbound_buffer(card, buffer, index);
/* clear buffer and give back to hardware */
@@ -3214,8 +3338,6 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
QETH_DBF_TEXT(SETUP, 2, "setonlin");
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
- qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1);
-
recover_flag = card->state;
rc = qeth_core_hardsetup_card(card);
if (rc) {
@@ -3250,20 +3372,22 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
goto out_remove;
} else
card->lan_online = 1;
- qeth_l3_set_large_send(card, card->options.large_send);
rc = qeth_l3_setadapter_parms(card);
if (rc)
QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
- rc = qeth_l3_start_ipassists(card);
- if (rc)
- QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
- rc = qeth_l3_setrouting_v4(card);
- if (rc)
- QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc);
- rc = qeth_l3_setrouting_v6(card);
- if (rc)
- QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+ if (!card->options.sniffer) {
+ rc = qeth_l3_start_ipassists(card);
+ if (rc)
+ QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+ qeth_l3_set_large_send(card, card->options.large_send);
+ rc = qeth_l3_setrouting_v4(card);
+ if (rc)
+ QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc);
+ rc = qeth_l3_setrouting_v6(card);
+ if (rc)
+ QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+ }
netif_tx_disable(card->dev);
rc = qeth_init_qdio_queues(card);
@@ -3410,11 +3534,9 @@ static int qeth_l3_pm_resume(struct ccwgroup_device *gdev)
if (card->state == CARD_STATE_RECOVER) {
rc = __qeth_l3_set_online(card->gdev, 1);
if (rc) {
- if (card->dev) {
- rtnl_lock();
- dev_close(card->dev);
- rtnl_unlock();
- }
+ rtnl_lock();
+ dev_close(card->dev);
+ rtnl_unlock();
}
} else
rc = __qeth_l3_set_online(card->gdev, 0);
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index 3360b0941aa1..3f08b11274ae 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -319,6 +319,61 @@ static ssize_t qeth_l3_dev_checksum_store(struct device *dev,
static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show,
qeth_l3_dev_checksum_store);
+static ssize_t qeth_l3_dev_sniffer_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qeth_card *card = dev_get_drvdata(dev);
+
+ if (!card)
+ return -EINVAL;
+
+ return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0);
+}
+
+static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct qeth_card *card = dev_get_drvdata(dev);
+ int ret;
+ unsigned long i;
+
+ if (!card)
+ return -EINVAL;
+
+ if (card->info.type != QETH_CARD_TYPE_IQD)
+ return -EPERM;
+
+ if ((card->state != CARD_STATE_DOWN) &&
+ (card->state != CARD_STATE_RECOVER))
+ return -EPERM;
+
+ ret = strict_strtoul(buf, 16, &i);
+ if (ret)
+ return -EINVAL;
+ switch (i) {
+ case 0:
+ card->options.sniffer = i;
+ break;
+ case 1:
+ ret = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
+ if (card->ssqd.qdioac2 & QETH_SNIFF_AVAIL) {
+ card->options.sniffer = i;
+ if (card->qdio.init_pool.buf_count !=
+ QETH_IN_BUF_COUNT_MAX)
+ qeth_realloc_buffer_pool(card,
+ QETH_IN_BUF_COUNT_MAX);
+ break;
+ } else
+ return -EPERM;
+ default: /* fall through */
+ return -EINVAL;
+ }
+ return count;
+}
+
+static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
+ qeth_l3_dev_sniffer_store);
+
static ssize_t qeth_l3_dev_large_send_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -373,6 +428,7 @@ static struct attribute *qeth_l3_device_attrs[] = {
&dev_attr_broadcast_mode.attr,
&dev_attr_canonical_macaddr.attr,
&dev_attr_checksumming.attr,
+ &dev_attr_sniffer.attr,
&dev_attr_large_send.attr,
NULL,
};
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index 67f2485d2372..ecef1edee701 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -31,9 +31,9 @@
struct smsg_callback {
struct list_head list;
- char *prefix;
+ const char *prefix;
int len;
- void (*callback)(char *from, char *str);
+ void (*callback)(const char *from, char *str);
};
MODULE_AUTHOR
@@ -100,8 +100,8 @@ static void smsg_message_pending(struct iucv_path *path,
kfree(buffer);
}
-int smsg_register_callback(char *prefix,
- void (*callback)(char *from, char *str))
+int smsg_register_callback(const char *prefix,
+ void (*callback)(const char *from, char *str))
{
struct smsg_callback *cb;
@@ -117,8 +117,9 @@ int smsg_register_callback(char *prefix,
return 0;
}
-void smsg_unregister_callback(char *prefix,
- void (*callback)(char *from, char *str))
+void smsg_unregister_callback(const char *prefix,
+ void (*callback)(const char *from,
+ char *str))
{
struct smsg_callback *cb, *tmp;
@@ -176,7 +177,7 @@ static const struct dev_pm_ops smsg_pm_ops = {
static struct device_driver smsg_driver = {
.owner = THIS_MODULE,
- .name = "SMSGIUCV",
+ .name = SMSGIUCV_DRV_NAME,
.bus = &iucv_bus,
.pm = &smsg_pm_ops,
};
diff --git a/drivers/s390/net/smsgiucv.h b/drivers/s390/net/smsgiucv.h
index 67f5d4f8378d..149a1151608d 100644
--- a/drivers/s390/net/smsgiucv.h
+++ b/drivers/s390/net/smsgiucv.h
@@ -5,6 +5,10 @@
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
*/
-int smsg_register_callback(char *, void (*)(char *, char *));
-void smsg_unregister_callback(char *, void (*)(char *, char *));
+#define SMSGIUCV_DRV_NAME "SMSGIUCV"
+
+int smsg_register_callback(const char *,
+ void (*)(const char *, char *));
+void smsg_unregister_callback(const char *,
+ void (*)(const char *, char *));
diff --git a/drivers/s390/net/smsgiucv_app.c b/drivers/s390/net/smsgiucv_app.c
new file mode 100644
index 000000000000..91579dc6a2b0
--- /dev/null
+++ b/drivers/s390/net/smsgiucv_app.c
@@ -0,0 +1,211 @@
+/*
+ * Deliver z/VM CP special messages (SMSG) as uevents.
+ *
+ * The driver registers for z/VM CP special messages with the
+ * "APP" prefix. Incoming messages are delivered to user space
+ * as uevents.
+ *
+ * Copyright IBM Corp. 2010
+ * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ *
+ */
+#define KMSG_COMPONENT "smsgiucv_app"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <net/iucv/iucv.h>
+#include "smsgiucv.h"
+
+/* prefix used for SMSG registration */
+#define SMSG_PREFIX "APP"
+
+/* SMSG related uevent environment variables */
+#define ENV_SENDER_STR "SMSG_SENDER="
+#define ENV_SENDER_LEN (strlen(ENV_SENDER_STR) + 8 + 1)
+#define ENV_PREFIX_STR "SMSG_ID="
+#define ENV_PREFIX_LEN (strlen(ENV_PREFIX_STR) + \
+ strlen(SMSG_PREFIX) + 1)
+#define ENV_TEXT_STR "SMSG_TEXT="
+#define ENV_TEXT_LEN(msg) (strlen(ENV_TEXT_STR) + strlen((msg)) + 1)
+
+/* z/VM user ID which is permitted to send SMSGs
+ * If the value is undefined or empty (""), special messages are
+ * accepted from any z/VM user ID. */
+static char *sender;
+module_param(sender, charp, 0400);
+MODULE_PARM_DESC(sender, "z/VM user ID from which CP SMSGs are accepted");
+
+/* SMSG device representation */
+static struct device *smsg_app_dev;
+
+/* list element for queuing received messages for delivery */
+struct smsg_app_event {
+ struct list_head list;
+ char *buf;
+ char *envp[4];
+};
+
+/* queue for outgoing uevents */
+static LIST_HEAD(smsg_event_queue);
+static DEFINE_SPINLOCK(smsg_event_queue_lock);
+
+static void smsg_app_event_free(struct smsg_app_event *ev)
+{
+ kfree(ev->buf);
+ kfree(ev);
+}
+
+static struct smsg_app_event *smsg_app_event_alloc(const char *from,
+ const char *msg)
+{
+ struct smsg_app_event *ev;
+
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+ if (!ev)
+ return NULL;
+
+ ev->buf = kzalloc(ENV_SENDER_LEN + ENV_PREFIX_LEN +
+ ENV_TEXT_LEN(msg), GFP_ATOMIC);
+ if (!ev->buf) {
+ kfree(ev);
+ return NULL;
+ }
+
+ /* setting up environment pointers into buf */
+ ev->envp[0] = ev->buf;
+ ev->envp[1] = ev->envp[0] + ENV_SENDER_LEN;
+ ev->envp[2] = ev->envp[1] + ENV_PREFIX_LEN;
+ ev->envp[3] = NULL;
+
+ /* setting up environment: sender, prefix name, and message text */
+ snprintf(ev->envp[0], ENV_SENDER_LEN, ENV_SENDER_STR "%s", from);
+ snprintf(ev->envp[1], ENV_PREFIX_LEN, ENV_PREFIX_STR "%s", SMSG_PREFIX);
+ snprintf(ev->envp[2], ENV_TEXT_LEN(msg), ENV_TEXT_STR "%s", msg);
+
+ return ev;
+}
+
+static void smsg_event_work_fn(struct work_struct *work)
+{
+ LIST_HEAD(event_queue);
+ struct smsg_app_event *p, *n;
+ struct device *dev;
+
+ dev = get_device(smsg_app_dev);
+ if (!dev)
+ return;
+
+ spin_lock_bh(&smsg_event_queue_lock);
+ list_splice_init(&smsg_event_queue, &event_queue);
+ spin_unlock_bh(&smsg_event_queue_lock);
+
+ list_for_each_entry_safe(p, n, &event_queue, list) {
+ list_del(&p->list);
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, p->envp);
+ smsg_app_event_free(p);
+ }
+
+ put_device(dev);
+}
+static DECLARE_WORK(smsg_event_work, smsg_event_work_fn);
+
+static void smsg_app_callback(const char *from, char *msg)
+{
+ struct smsg_app_event *se;
+
+ /* check if the originating z/VM user ID matches
+ * the configured sender. */
+ if (sender && strlen(sender) > 0 && strcmp(from, sender) != 0)
+ return;
+
+ /* get start of message text (skip prefix and leading blanks) */
+ msg += strlen(SMSG_PREFIX);
+ while (*msg && isspace(*msg))
+ msg++;
+ if (*msg == '\0')
+ return;
+
+ /* allocate event list element and its environment */
+ se = smsg_app_event_alloc(from, msg);
+ if (!se)
+ return;
+
+ /* queue event and schedule work function */
+ spin_lock(&smsg_event_queue_lock);
+ list_add_tail(&se->list, &smsg_event_queue);
+ spin_unlock(&smsg_event_queue_lock);
+
+ schedule_work(&smsg_event_work);
+ return;
+}
+
+static int __init smsgiucv_app_init(void)
+{
+ struct device_driver *smsgiucv_drv;
+ int rc;
+
+ if (!MACHINE_IS_VM)
+ return -ENODEV;
+
+ smsg_app_dev = kzalloc(sizeof(*smsg_app_dev), GFP_KERNEL);
+ if (!smsg_app_dev)
+ return -ENOMEM;
+
+ smsgiucv_drv = driver_find(SMSGIUCV_DRV_NAME, &iucv_bus);
+ if (!smsgiucv_drv) {
+ kfree(smsg_app_dev);
+ return -ENODEV;
+ }
+
+ rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT);
+ if (rc) {
+ kfree(smsg_app_dev);
+ goto fail_put_driver;
+ }
+ smsg_app_dev->bus = &iucv_bus;
+ smsg_app_dev->parent = iucv_root;
+ smsg_app_dev->release = (void (*)(struct device *)) kfree;
+ smsg_app_dev->driver = smsgiucv_drv;
+ rc = device_register(smsg_app_dev);
+ if (rc) {
+ put_device(smsg_app_dev);
+ goto fail_put_driver;
+ }
+
+ /* register with the smsgiucv device driver */
+ rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback);
+ if (rc) {
+ device_unregister(smsg_app_dev);
+ goto fail_put_driver;
+ }
+
+ rc = 0;
+fail_put_driver:
+ put_driver(smsgiucv_drv);
+ return rc;
+}
+module_init(smsgiucv_app_init);
+
+static void __exit smsgiucv_app_exit(void)
+{
+ /* unregister callback */
+ smsg_unregister_callback(SMSG_PREFIX, smsg_app_callback);
+
+ /* cancel pending work and flush any queued event work */
+ cancel_work_sync(&smsg_event_work);
+ smsg_event_work_fn(&smsg_event_work);
+
+ device_unregister(smsg_app_dev);
+}
+module_exit(smsgiucv_app_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Deliver z/VM CP SMSG as uevents");
+MODULE_AUTHOR("Hendrik Brueckner <brueckner@linux.vnet.ibm.com>");
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 9d0c941b7d33..66d6c01fcf3e 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -3,7 +3,7 @@
*
* Module interface and handling of zfcp data structures.
*
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
*/
/*
@@ -32,6 +32,7 @@
#include <linux/seq_file.h>
#include "zfcp_ext.h"
#include "zfcp_fc.h"
+#include "zfcp_reqlist.h"
#define ZFCP_BUS_ID_SIZE 20
@@ -49,36 +50,6 @@ static struct kmem_cache *zfcp_cache_hw_align(const char *name,
return kmem_cache_create(name, size, roundup_pow_of_two(size), 0, NULL);
}
-static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter)
-{
- int idx;
-
- adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head),
- GFP_KERNEL);
- if (!adapter->req_list)
- return -ENOMEM;
-
- for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
- INIT_LIST_HEAD(&adapter->req_list[idx]);
- return 0;
-}
-
-/**
- * zfcp_reqlist_isempty - is the request list empty
- * @adapter: pointer to struct zfcp_adapter
- *
- * Returns: true if list is empty, false otherwise
- */
-int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)
-{
- unsigned int idx;
-
- for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
- if (!list_empty(&adapter->req_list[idx]))
- return 0;
- return 1;
-}
-
static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)
{
struct ccw_device *cdev;
@@ -110,7 +81,7 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)
flush_work(&unit->scsi_work);
out_unit:
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
out_port:
zfcp_ccw_adapter_put(adapter);
out_ccw_device:
@@ -255,7 +226,7 @@ struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun)
read_lock_irqsave(&port->unit_list_lock, flags);
list_for_each_entry(unit, &port->unit_list, list)
if (unit->fcp_lun == fcp_lun) {
- if (!get_device(&unit->sysfs_device))
+ if (!get_device(&unit->dev))
unit = NULL;
read_unlock_irqrestore(&port->unit_list_lock, flags);
return unit;
@@ -280,7 +251,7 @@ struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter,
read_lock_irqsave(&adapter->port_list_lock, flags);
list_for_each_entry(port, &adapter->port_list, list)
if (port->wwpn == wwpn) {
- if (!get_device(&port->sysfs_device))
+ if (!get_device(&port->dev))
port = NULL;
read_unlock_irqrestore(&adapter->port_list_lock, flags);
return port;
@@ -298,10 +269,9 @@ struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter,
*/
static void zfcp_unit_release(struct device *dev)
{
- struct zfcp_unit *unit = container_of(dev, struct zfcp_unit,
- sysfs_device);
+ struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev);
- put_device(&unit->port->sysfs_device);
+ put_device(&unit->port->dev);
kfree(unit);
}
@@ -318,11 +288,11 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
struct zfcp_unit *unit;
int retval = -ENOMEM;
- get_device(&port->sysfs_device);
+ get_device(&port->dev);
unit = zfcp_get_unit_by_lun(port, fcp_lun);
if (unit) {
- put_device(&unit->sysfs_device);
+ put_device(&unit->dev);
retval = -EEXIST;
goto err_out;
}
@@ -333,10 +303,10 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
unit->port = port;
unit->fcp_lun = fcp_lun;
- unit->sysfs_device.parent = &port->sysfs_device;
- unit->sysfs_device.release = zfcp_unit_release;
+ unit->dev.parent = &port->dev;
+ unit->dev.release = zfcp_unit_release;
- if (dev_set_name(&unit->sysfs_device, "0x%016llx",
+ if (dev_set_name(&unit->dev, "0x%016llx",
(unsigned long long) fcp_lun)) {
kfree(unit);
goto err_out;
@@ -353,13 +323,12 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
unit->latencies.cmd.channel.min = 0xFFFFFFFF;
unit->latencies.cmd.fabric.min = 0xFFFFFFFF;
- if (device_register(&unit->sysfs_device)) {
- put_device(&unit->sysfs_device);
+ if (device_register(&unit->dev)) {
+ put_device(&unit->dev);
goto err_out;
}
- if (sysfs_create_group(&unit->sysfs_device.kobj,
- &zfcp_sysfs_unit_attrs))
+ if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs))
goto err_out_put;
write_lock_irq(&port->unit_list_lock);
@@ -371,9 +340,9 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
return unit;
err_out_put:
- device_unregister(&unit->sysfs_device);
+ device_unregister(&unit->dev);
err_out:
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
return ERR_PTR(retval);
}
@@ -539,7 +508,8 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
if (zfcp_allocate_low_mem_buffers(adapter))
goto failed;
- if (zfcp_reqlist_alloc(adapter))
+ adapter->req_list = zfcp_reqlist_alloc();
+ if (!adapter->req_list)
goto failed;
if (zfcp_dbf_adapter_register(adapter))
@@ -560,8 +530,6 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
INIT_LIST_HEAD(&adapter->erp_ready_head);
INIT_LIST_HEAD(&adapter->erp_running_head);
- spin_lock_init(&adapter->req_list_lock);
-
rwlock_init(&adapter->erp_lock);
rwlock_init(&adapter->abort_lock);
@@ -640,8 +608,7 @@ void zfcp_device_unregister(struct device *dev,
static void zfcp_port_release(struct device *dev)
{
- struct zfcp_port *port = container_of(dev, struct zfcp_port,
- sysfs_device);
+ struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
zfcp_ccw_adapter_put(port->adapter);
kfree(port);
@@ -669,7 +636,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
port = zfcp_get_port_by_wwpn(adapter, wwpn);
if (port) {
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
retval = -EEXIST;
goto err_out;
}
@@ -689,22 +656,21 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
port->d_id = d_id;
port->wwpn = wwpn;
port->rport_task = RPORT_NONE;
- port->sysfs_device.parent = &adapter->ccw_device->dev;
- port->sysfs_device.release = zfcp_port_release;
+ port->dev.parent = &adapter->ccw_device->dev;
+ port->dev.release = zfcp_port_release;
- if (dev_set_name(&port->sysfs_device, "0x%016llx",
- (unsigned long long)wwpn)) {
+ if (dev_set_name(&port->dev, "0x%016llx", (unsigned long long)wwpn)) {
kfree(port);
goto err_out;
}
retval = -EINVAL;
- if (device_register(&port->sysfs_device)) {
- put_device(&port->sysfs_device);
+ if (device_register(&port->dev)) {
+ put_device(&port->dev);
goto err_out;
}
- if (sysfs_create_group(&port->sysfs_device.kobj,
+ if (sysfs_create_group(&port->dev.kobj,
&zfcp_sysfs_port_attrs))
goto err_out_put;
@@ -717,7 +683,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
return port;
err_out_put:
- device_unregister(&port->sysfs_device);
+ device_unregister(&port->dev);
err_out:
zfcp_ccw_adapter_put(adapter);
return ERR_PTR(retval);
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index c22cb72a5ae8..ce1cc7a11fb4 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -3,13 +3,14 @@
*
* Registration and callback for the s390 common I/O layer.
*
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
*/
#define KMSG_COMPONENT "zfcp"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include "zfcp_ext.h"
+#include "zfcp_reqlist.h"
#define ZFCP_MODEL_PRIV 0x4
@@ -122,12 +123,10 @@ static void zfcp_ccw_remove(struct ccw_device *cdev)
zfcp_ccw_adapter_put(adapter); /* put from zfcp_ccw_adapter_by_cdev */
list_for_each_entry_safe(unit, u, &unit_remove_lh, list)
- zfcp_device_unregister(&unit->sysfs_device,
- &zfcp_sysfs_unit_attrs);
+ zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs);
list_for_each_entry_safe(port, p, &port_remove_lh, list)
- zfcp_device_unregister(&port->sysfs_device,
- &zfcp_sysfs_port_attrs);
+ zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs);
zfcp_adapter_unregister(adapter);
}
@@ -162,7 +161,7 @@ static int zfcp_ccw_set_online(struct ccw_device *cdev)
}
/* initialize request counter */
- BUG_ON(!zfcp_reqlist_isempty(adapter));
+ BUG_ON(!zfcp_reqlist_isempty(adapter->req_list));
adapter->req_no = 0;
zfcp_erp_modify_adapter_status(adapter, "ccsonl1", NULL,
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c
index f932400e980a..0eb6eefd2c1a 100644
--- a/drivers/s390/scsi/zfcp_cfdc.c
+++ b/drivers/s390/scsi/zfcp_cfdc.c
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/miscdevice.h>
+#include <asm/compat.h>
#include <asm/ccwdev.h>
#include "zfcp_def.h"
#include "zfcp_ext.h"
@@ -163,7 +164,7 @@ static void zfcp_cfdc_req_to_sense(struct zfcp_cfdc_data *data,
}
static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
- unsigned long buffer)
+ unsigned long arg)
{
struct zfcp_cfdc_data *data;
struct zfcp_cfdc_data __user *data_user;
@@ -175,7 +176,11 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
if (command != ZFCP_CFDC_IOC)
return -ENOTTY;
- data_user = (void __user *) buffer;
+ if (is_compat_task())
+ data_user = compat_ptr(arg);
+ else
+ data_user = (void __user *)arg;
+
if (!data_user)
return -EINVAL;
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 84450955ae11..7a149fd85f6d 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -140,9 +140,9 @@ void _zfcp_dbf_hba_fsf_response(const char *tag2, int level,
memcpy(response->fsf_status_qual,
fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE);
response->fsf_req_status = fsf_req->status;
- response->sbal_first = fsf_req->queue_req.sbal_first;
- response->sbal_last = fsf_req->queue_req.sbal_last;
- response->sbal_response = fsf_req->queue_req.sbal_response;
+ response->sbal_first = fsf_req->qdio_req.sbal_first;
+ response->sbal_last = fsf_req->qdio_req.sbal_last;
+ response->sbal_response = fsf_req->qdio_req.sbal_response;
response->pool = fsf_req->pool != NULL;
response->erp_action = (unsigned long)fsf_req->erp_action;
@@ -327,7 +327,7 @@ static void zfcp_dbf_hba_view_response(char **p,
break;
zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd);
zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial);
- p += sprintf(*p, "\n");
+ *p += sprintf(*p, "\n");
break;
case FSF_QTCB_OPEN_PORT_WITH_DID:
@@ -576,7 +576,8 @@ void zfcp_dbf_rec_adapter(char *id, void *ref, struct zfcp_dbf *dbf)
struct zfcp_adapter *adapter = dbf->adapter;
zfcp_dbf_rec_target(id, ref, dbf, &adapter->status,
- &adapter->erp_counter, 0, 0, 0);
+ &adapter->erp_counter, 0, 0,
+ ZFCP_DBF_INVALID_LUN);
}
/**
@@ -590,8 +591,8 @@ void zfcp_dbf_rec_port(char *id, void *ref, struct zfcp_port *port)
struct zfcp_dbf *dbf = port->adapter->dbf;
zfcp_dbf_rec_target(id, ref, dbf, &port->status,
- &port->erp_counter, port->wwpn, port->d_id,
- 0);
+ &port->erp_counter, port->wwpn, port->d_id,
+ ZFCP_DBF_INVALID_LUN);
}
/**
@@ -642,10 +643,9 @@ void zfcp_dbf_rec_trigger(char *id2, void *ref, u8 want, u8 need, void *action,
r->u.trigger.ps = atomic_read(&port->status);
r->u.trigger.wwpn = port->wwpn;
}
- if (unit) {
+ if (unit)
r->u.trigger.us = atomic_read(&unit->status);
- r->u.trigger.fcp_lun = unit->fcp_lun;
- }
+ r->u.trigger.fcp_lun = unit ? unit->fcp_lun : ZFCP_DBF_INVALID_LUN;
debug_event(dbf->rec, action ? 1 : 4, r, sizeof(*r));
spin_unlock_irqrestore(&dbf->rec_lock, flags);
}
@@ -668,7 +668,7 @@ void zfcp_dbf_rec_action(char *id2, struct zfcp_erp_action *erp_action)
r->u.action.action = (unsigned long)erp_action;
r->u.action.status = erp_action->status;
r->u.action.step = erp_action->step;
- r->u.action.fsf_req = (unsigned long)erp_action->fsf_req;
+ r->u.action.fsf_req = erp_action->fsf_req_id;
debug_event(dbf->rec, 5, r, sizeof(*r));
spin_unlock_irqrestore(&dbf->rec_lock, flags);
}
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h
index 8b7fd9a1033e..457e046f2d28 100644
--- a/drivers/s390/scsi/zfcp_dbf.h
+++ b/drivers/s390/scsi/zfcp_dbf.h
@@ -30,6 +30,8 @@
#define ZFCP_DBF_TAG_SIZE 4
#define ZFCP_DBF_ID_SIZE 7
+#define ZFCP_DBF_INVALID_LUN 0xFFFFFFFFFFFFFFFFull
+
struct zfcp_dbf_dump {
u8 tag[ZFCP_DBF_TAG_SIZE];
u32 total_size; /* size of total dump data */
@@ -192,10 +194,10 @@ struct zfcp_dbf_san_record {
struct zfcp_dbf_san_record_ct_response ct_resp;
struct zfcp_dbf_san_record_els els;
} u;
-#define ZFCP_DBF_SAN_MAX_PAYLOAD 1024
- u8 payload[32];
} __attribute__ ((packed));
+#define ZFCP_DBF_SAN_MAX_PAYLOAD 1024
+
struct zfcp_dbf_scsi_record {
u8 tag[ZFCP_DBF_TAG_SIZE];
u8 tag2[ZFCP_DBF_TAG_SIZE];
@@ -301,17 +303,31 @@ void zfcp_dbf_scsi(const char *tag, const char *tag2, int level,
/**
* zfcp_dbf_scsi_result - trace event for SCSI command completion
- * @tag: tag indicating success or failure of SCSI command
- * @level: trace level applicable for this event
- * @adapter: adapter that has been used to issue the SCSI command
+ * @dbf: adapter dbf trace
+ * @scmd: SCSI command pointer
+ * @req: FSF request used to issue SCSI command
+ */
+static inline
+void zfcp_dbf_scsi_result(struct zfcp_dbf *dbf, struct scsi_cmnd *scmd,
+ struct zfcp_fsf_req *req)
+{
+ if (scmd->result != 0)
+ zfcp_dbf_scsi("rslt", "erro", 3, dbf, scmd, req, 0);
+ else if (scmd->retries > 0)
+ zfcp_dbf_scsi("rslt", "retr", 4, dbf, scmd, req, 0);
+ else
+ zfcp_dbf_scsi("rslt", "norm", 6, dbf, scmd, req, 0);
+}
+
+/**
+ * zfcp_dbf_scsi_fail_send - trace event for failure to send SCSI command
+ * @dbf: adapter dbf trace
* @scmd: SCSI command pointer
- * @fsf_req: request used to issue SCSI command (might be NULL)
*/
static inline
-void zfcp_dbf_scsi_result(const char *tag, int level, struct zfcp_dbf *dbf,
- struct scsi_cmnd *scmd, struct zfcp_fsf_req *fsf_req)
+void zfcp_dbf_scsi_fail_send(struct zfcp_dbf *dbf, struct scsi_cmnd *scmd)
{
- zfcp_dbf_scsi("rslt", tag, level, dbf, scmd, fsf_req, 0);
+ zfcp_dbf_scsi("rslt", "fail", 4, dbf, scmd, NULL, 0);
}
/**
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index e1b5b88e2ddb..7131c7db1f04 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -3,7 +3,7 @@
*
* Global definitions for the zfcp device driver.
*
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
*/
#ifndef ZFCP_DEF_H
@@ -33,15 +33,13 @@
#include <scsi/scsi_transport_fc.h>
#include <scsi/scsi_bsg_fc.h>
#include <asm/ccwdev.h>
-#include <asm/qdio.h>
#include <asm/debug.h>
#include <asm/ebcdic.h>
#include <asm/sysinfo.h>
#include "zfcp_fsf.h"
+#include "zfcp_qdio.h"
-/********************* GENERAL DEFINES *********************************/
-
-#define REQUEST_LIST_SIZE 128
+struct zfcp_reqlist;
/********************* SCSI SPECIFIC DEFINES *********************************/
#define ZFCP_SCSI_ER_TIMEOUT (10*HZ)
@@ -129,12 +127,6 @@ struct zfcp_adapter_mempool {
mempool_t *qtcb_pool;
};
-struct zfcp_qdio_queue {
- struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q];
- u8 first; /* index of next free bfr in queue */
- atomic_t count; /* number of free buffers in queue */
-};
-
struct zfcp_erp_action {
struct list_head list;
int action; /* requested action code */
@@ -143,8 +135,7 @@ struct zfcp_erp_action {
struct zfcp_unit *unit;
u32 status; /* recovery status */
u32 step; /* active step of this erp action */
- struct zfcp_fsf_req *fsf_req; /* fsf request currently pending
- for this action */
+ unsigned long fsf_req_id;
struct timer_list timer;
};
@@ -167,29 +158,6 @@ struct zfcp_latencies {
spinlock_t lock;
};
-/** struct zfcp_qdio - basic QDIO data structure
- * @resp_q: response queue
- * @req_q: request queue
- * @stat_lock: lock to protect req_q_util and req_q_time
- * @req_q_lock; lock to serialize access to request queue
- * @req_q_time: time of last fill level change
- * @req_q_util: used for accounting
- * @req_q_full: queue full incidents
- * @req_q_wq: used to wait for SBAL availability
- * @adapter: adapter used in conjunction with this QDIO structure
- */
-struct zfcp_qdio {
- struct zfcp_qdio_queue resp_q;
- struct zfcp_qdio_queue req_q;
- spinlock_t stat_lock;
- spinlock_t req_q_lock;
- unsigned long long req_q_time;
- u64 req_q_util;
- atomic_t req_q_full;
- wait_queue_head_t req_q_wq;
- struct zfcp_adapter *adapter;
-};
-
struct zfcp_adapter {
struct kref ref;
u64 peer_wwnn; /* P2P peer WWNN */
@@ -207,8 +175,7 @@ struct zfcp_adapter {
struct list_head port_list; /* remote port list */
rwlock_t port_list_lock; /* port list lock */
unsigned long req_no; /* unique FSF req number */
- struct list_head *req_list; /* list of pending reqs */
- spinlock_t req_list_lock; /* request list lock */
+ struct zfcp_reqlist *req_list;
u32 fsf_req_seq_no; /* FSF cmnd seq number */
rwlock_t abort_lock; /* Protects against SCSI
stack abort/command
@@ -241,7 +208,7 @@ struct zfcp_adapter {
};
struct zfcp_port {
- struct device sysfs_device; /* sysfs device */
+ struct device dev;
struct fc_rport *rport; /* rport of fc transport class */
struct list_head list; /* list of remote ports */
struct zfcp_adapter *adapter; /* adapter used to access port */
@@ -263,7 +230,7 @@ struct zfcp_port {
};
struct zfcp_unit {
- struct device sysfs_device; /* sysfs device */
+ struct device dev;
struct list_head list; /* list of logical units */
struct zfcp_port *port; /* remote port of unit */
atomic_t status; /* status of this logical unit */
@@ -277,33 +244,11 @@ struct zfcp_unit {
};
/**
- * struct zfcp_queue_req - queue related values for a request
- * @sbal_number: number of free SBALs
- * @sbal_first: first SBAL for this request
- * @sbal_last: last SBAL for this request
- * @sbal_limit: last possible SBAL for this request
- * @sbale_curr: current SBALE at creation of this request
- * @sbal_response: SBAL used in interrupt
- * @qdio_outb_usage: usage of outbound queue
- * @qdio_inb_usage: usage of inbound queue
- */
-struct zfcp_queue_req {
- u8 sbal_number;
- u8 sbal_first;
- u8 sbal_last;
- u8 sbal_limit;
- u8 sbale_curr;
- u8 sbal_response;
- u16 qdio_outb_usage;
- u16 qdio_inb_usage;
-};
-
-/**
* struct zfcp_fsf_req - basic FSF request structure
* @list: list of FSF requests
* @req_id: unique request ID
* @adapter: adapter this request belongs to
- * @queue_req: queue related values
+ * @qdio_req: qdio queue related values
* @completion: used to signal the completion of the request
* @status: status of the request
* @fsf_command: FSF command issued
@@ -321,7 +266,7 @@ struct zfcp_fsf_req {
struct list_head list;
unsigned long req_id;
struct zfcp_adapter *adapter;
- struct zfcp_queue_req queue_req;
+ struct zfcp_qdio_req qdio_req;
struct completion completion;
u32 status;
u32 fsf_command;
@@ -352,45 +297,4 @@ struct zfcp_data {
#define ZFCP_SET 0x00000100
#define ZFCP_CLEAR 0x00000200
-/*
- * Helper functions for request ID management.
- */
-static inline int zfcp_reqlist_hash(unsigned long req_id)
-{
- return req_id % REQUEST_LIST_SIZE;
-}
-
-static inline void zfcp_reqlist_remove(struct zfcp_adapter *adapter,
- struct zfcp_fsf_req *fsf_req)
-{
- list_del(&fsf_req->list);
-}
-
-static inline struct zfcp_fsf_req *
-zfcp_reqlist_find(struct zfcp_adapter *adapter, unsigned long req_id)
-{
- struct zfcp_fsf_req *request;
- unsigned int idx;
-
- idx = zfcp_reqlist_hash(req_id);
- list_for_each_entry(request, &adapter->req_list[idx], list)
- if (request->req_id == req_id)
- return request;
- return NULL;
-}
-
-static inline struct zfcp_fsf_req *
-zfcp_reqlist_find_safe(struct zfcp_adapter *adapter, struct zfcp_fsf_req *req)
-{
- struct zfcp_fsf_req *request;
- unsigned int idx;
-
- for (idx = 0; idx < REQUEST_LIST_SIZE; idx++) {
- list_for_each_entry(request, &adapter->req_list[idx], list)
- if (request == req)
- return request;
- }
- return NULL;
-}
-
#endif /* ZFCP_DEF_H */
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index b51a11a82e63..0be5e7ea2828 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -3,7 +3,7 @@
*
* Error Recovery Procedures (ERP).
*
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
*/
#define KMSG_COMPONENT "zfcp"
@@ -11,6 +11,7 @@
#include <linux/kthread.h>
#include "zfcp_ext.h"
+#include "zfcp_reqlist.h"
#define ZFCP_MAX_ERPS 3
@@ -174,7 +175,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
switch (need) {
case ZFCP_ERP_ACTION_REOPEN_UNIT:
- if (!get_device(&unit->sysfs_device))
+ if (!get_device(&unit->dev))
return NULL;
atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status);
erp_action = &unit->erp_action;
@@ -184,7 +185,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
case ZFCP_ERP_ACTION_REOPEN_PORT:
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
- if (!get_device(&port->sysfs_device))
+ if (!get_device(&port->dev))
return NULL;
zfcp_erp_action_dismiss_port(port);
atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
@@ -478,26 +479,27 @@ static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
{
struct zfcp_adapter *adapter = act->adapter;
+ struct zfcp_fsf_req *req;
- if (!act->fsf_req)
+ if (!act->fsf_req_id)
return;
- spin_lock(&adapter->req_list_lock);
- if (zfcp_reqlist_find_safe(adapter, act->fsf_req) &&
- act->fsf_req->erp_action == act) {
+ spin_lock(&adapter->req_list->lock);
+ req = _zfcp_reqlist_find(adapter->req_list, act->fsf_req_id);
+ if (req && req->erp_action == act) {
if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
ZFCP_STATUS_ERP_TIMEDOUT)) {
- act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
+ req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
zfcp_dbf_rec_action("erscf_1", act);
- act->fsf_req->erp_action = NULL;
+ req->erp_action = NULL;
}
if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
zfcp_dbf_rec_action("erscf_2", act);
- if (act->fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
- act->fsf_req = NULL;
+ if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
+ act->fsf_req_id = 0;
} else
- act->fsf_req = NULL;
- spin_unlock(&adapter->req_list_lock);
+ act->fsf_req_id = 0;
+ spin_unlock(&adapter->req_list->lock);
}
/**
@@ -1179,19 +1181,19 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
switch (act->action) {
case ZFCP_ERP_ACTION_REOPEN_UNIT:
if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
- get_device(&unit->sysfs_device);
+ get_device(&unit->dev);
if (scsi_queue_work(unit->port->adapter->scsi_host,
&unit->scsi_work) <= 0)
- put_device(&unit->sysfs_device);
+ put_device(&unit->dev);
}
- put_device(&unit->sysfs_device);
+ put_device(&unit->dev);
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
case ZFCP_ERP_ACTION_REOPEN_PORT:
if (result == ZFCP_ERP_SUCCEEDED)
zfcp_scsi_schedule_rport_register(port);
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 03dec832b465..8786a79c7f8f 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -21,7 +21,6 @@ extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *);
extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32,
u32);
extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64);
-extern int zfcp_reqlist_isempty(struct zfcp_adapter *);
extern void zfcp_sg_free_table(struct scatterlist *, int);
extern int zfcp_sg_setup_table(struct scatterlist *, int);
extern void zfcp_device_unregister(struct device *,
@@ -108,6 +107,7 @@ extern void zfcp_fc_wka_ports_force_offline(struct zfcp_fc_wka_ports *);
extern int zfcp_fc_gs_setup(struct zfcp_adapter *);
extern void zfcp_fc_gs_destroy(struct zfcp_adapter *);
extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *);
+extern int zfcp_fc_timeout_bsg_job(struct fc_bsg_job *);
/* zfcp_fsf.c */
extern int zfcp_fsf_open_port(struct zfcp_erp_action *);
@@ -129,9 +129,9 @@ extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *);
extern int zfcp_fsf_status_read(struct zfcp_qdio *);
extern int zfcp_status_read_refill(struct zfcp_adapter *adapter);
extern int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *, struct zfcp_fsf_ct_els *,
- mempool_t *);
+ mempool_t *, unsigned int);
extern int zfcp_fsf_send_els(struct zfcp_adapter *, u32,
- struct zfcp_fsf_ct_els *);
+ struct zfcp_fsf_ct_els *, unsigned int);
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *,
struct scsi_cmnd *);
extern void zfcp_fsf_req_free(struct zfcp_fsf_req *);
@@ -143,13 +143,9 @@ extern void zfcp_fsf_reqid_check(struct zfcp_qdio *, int);
/* zfcp_qdio.c */
extern int zfcp_qdio_setup(struct zfcp_adapter *);
extern void zfcp_qdio_destroy(struct zfcp_qdio *);
-extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_queue_req *);
-extern struct qdio_buffer_element
- *zfcp_qdio_sbale_req(struct zfcp_qdio *, struct zfcp_queue_req *);
-extern struct qdio_buffer_element
- *zfcp_qdio_sbale_curr(struct zfcp_qdio *, struct zfcp_queue_req *);
+extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_qdio_req *);
extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *,
- struct zfcp_queue_req *, unsigned long,
+ struct zfcp_qdio_req *, unsigned long,
struct scatterlist *, int);
extern int zfcp_qdio_open(struct zfcp_qdio *);
extern void zfcp_qdio_close(struct zfcp_qdio *);
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index ac5e3b7a3576..5219670f0c99 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -3,7 +3,7 @@
*
* Fibre Channel related functions for the zfcp device driver.
*
- * Copyright IBM Corporation 2008, 2009
+ * Copyright IBM Corporation 2008, 2010
*/
#define KMSG_COMPONENT "zfcp"
@@ -258,7 +258,8 @@ static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port,
gid_pn->gid_pn_req.gid_pn.fn_wwpn = port->wwpn;
ret = zfcp_fsf_send_ct(&adapter->gs->ds, &gid_pn->ct,
- adapter->pool.gid_pn_req);
+ adapter->pool.gid_pn_req,
+ ZFCP_FC_CTELS_TMO);
if (!ret) {
wait_for_completion(&completion);
zfcp_fc_ns_gid_pn_eval(gid_pn);
@@ -315,7 +316,7 @@ void zfcp_fc_port_did_lookup(struct work_struct *work)
zfcp_erp_port_reopen(port, 0, "fcgpn_3", NULL);
out:
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
}
/**
@@ -324,9 +325,9 @@ out:
*/
void zfcp_fc_trigger_did_lookup(struct zfcp_port *port)
{
- get_device(&port->sysfs_device);
+ get_device(&port->dev);
if (!queue_work(port->adapter->work_queue, &port->gid_pn_work))
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
}
/**
@@ -388,7 +389,7 @@ static void zfcp_fc_adisc_handler(void *data)
zfcp_scsi_schedule_rport_register(port);
out:
atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status);
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
kmem_cache_free(zfcp_data.adisc_cache, adisc);
}
@@ -421,7 +422,8 @@ static int zfcp_fc_adisc(struct zfcp_port *port)
hton24(adisc->adisc_req.adisc_port_id,
fc_host_port_id(adapter->scsi_host));
- ret = zfcp_fsf_send_els(adapter, port->d_id, &adisc->els);
+ ret = zfcp_fsf_send_els(adapter, port->d_id, &adisc->els,
+ ZFCP_FC_CTELS_TMO);
if (ret)
kmem_cache_free(zfcp_data.adisc_cache, adisc);
@@ -434,7 +436,7 @@ void zfcp_fc_link_test_work(struct work_struct *work)
container_of(work, struct zfcp_port, test_link_work);
int retval;
- get_device(&port->sysfs_device);
+ get_device(&port->dev);
port->rport_task = RPORT_DEL;
zfcp_scsi_rport_work(&port->rport_work);
@@ -453,7 +455,7 @@ void zfcp_fc_link_test_work(struct work_struct *work)
zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL);
out:
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
}
/**
@@ -466,9 +468,9 @@ out:
*/
void zfcp_fc_test_link(struct zfcp_port *port)
{
- get_device(&port->sysfs_device);
+ get_device(&port->dev);
if (!queue_work(port->adapter->work_queue, &port->test_link_work))
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
}
static void zfcp_free_sg_env(struct zfcp_fc_gpn_ft *gpn_ft, int buf_num)
@@ -532,7 +534,8 @@ static int zfcp_fc_send_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft,
ct->req = &gpn_ft->sg_req;
ct->resp = gpn_ft->sg_resp;
- ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct, NULL);
+ ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct, NULL,
+ ZFCP_FC_CTELS_TMO);
if (!ret)
wait_for_completion(&completion);
return ret;
@@ -614,8 +617,7 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft,
list_for_each_entry_safe(port, tmp, &remove_lh, list) {
zfcp_erp_port_shutdown(port, 0, "fcegpf2", NULL);
- zfcp_device_unregister(&port->sysfs_device,
- &zfcp_sysfs_port_attrs);
+ zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs);
}
return ret;
@@ -668,15 +670,52 @@ static void zfcp_fc_ct_els_job_handler(void *data)
{
struct fc_bsg_job *job = data;
struct zfcp_fsf_ct_els *zfcp_ct_els = job->dd_data;
- int status = zfcp_ct_els->status;
- int reply_status;
+ struct fc_bsg_reply *jr = job->reply;
- reply_status = status ? FC_CTELS_STATUS_REJECT : FC_CTELS_STATUS_OK;
- job->reply->reply_data.ctels_reply.status = reply_status;
- job->reply->reply_payload_rcv_len = job->reply_payload.payload_len;
+ jr->reply_payload_rcv_len = job->reply_payload.payload_len;
+ jr->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
+ jr->result = zfcp_ct_els->status ? -EIO : 0;
job->job_done(job);
}
+static struct zfcp_fc_wka_port *zfcp_fc_job_wka_port(struct fc_bsg_job *job)
+{
+ u32 preamble_word1;
+ u8 gs_type;
+ struct zfcp_adapter *adapter;
+
+ preamble_word1 = job->request->rqst_data.r_ct.preamble_word1;
+ gs_type = (preamble_word1 & 0xff000000) >> 24;
+
+ adapter = (struct zfcp_adapter *) job->shost->hostdata[0];
+
+ switch (gs_type) {
+ case FC_FST_ALIAS:
+ return &adapter->gs->as;
+ case FC_FST_MGMT:
+ return &adapter->gs->ms;
+ case FC_FST_TIME:
+ return &adapter->gs->ts;
+ break;
+ case FC_FST_DIR:
+ return &adapter->gs->ds;
+ break;
+ default:
+ return NULL;
+ }
+}
+
+static void zfcp_fc_ct_job_handler(void *data)
+{
+ struct fc_bsg_job *job = data;
+ struct zfcp_fc_wka_port *wka_port;
+
+ wka_port = zfcp_fc_job_wka_port(job);
+ zfcp_fc_wka_port_put(wka_port);
+
+ zfcp_fc_ct_els_job_handler(data);
+}
+
static int zfcp_fc_exec_els_job(struct fc_bsg_job *job,
struct zfcp_adapter *adapter)
{
@@ -691,47 +730,31 @@ static int zfcp_fc_exec_els_job(struct fc_bsg_job *job,
return -EINVAL;
d_id = port->d_id;
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
} else
d_id = ntoh24(job->request->rqst_data.h_els.port_id);
- return zfcp_fsf_send_els(adapter, d_id, els);
+ els->handler = zfcp_fc_ct_els_job_handler;
+ return zfcp_fsf_send_els(adapter, d_id, els, job->req->timeout / HZ);
}
static int zfcp_fc_exec_ct_job(struct fc_bsg_job *job,
struct zfcp_adapter *adapter)
{
int ret;
- u8 gs_type;
struct zfcp_fsf_ct_els *ct = job->dd_data;
struct zfcp_fc_wka_port *wka_port;
- u32 preamble_word1;
- preamble_word1 = job->request->rqst_data.r_ct.preamble_word1;
- gs_type = (preamble_word1 & 0xff000000) >> 24;
-
- switch (gs_type) {
- case FC_FST_ALIAS:
- wka_port = &adapter->gs->as;
- break;
- case FC_FST_MGMT:
- wka_port = &adapter->gs->ms;
- break;
- case FC_FST_TIME:
- wka_port = &adapter->gs->ts;
- break;
- case FC_FST_DIR:
- wka_port = &adapter->gs->ds;
- break;
- default:
- return -EINVAL; /* no such service */
- }
+ wka_port = zfcp_fc_job_wka_port(job);
+ if (!wka_port)
+ return -EINVAL;
ret = zfcp_fc_wka_port_get(wka_port);
if (ret)
return ret;
- ret = zfcp_fsf_send_ct(wka_port, ct, NULL);
+ ct->handler = zfcp_fc_ct_job_handler;
+ ret = zfcp_fsf_send_ct(wka_port, ct, NULL, job->req->timeout / HZ);
if (ret)
zfcp_fc_wka_port_put(wka_port);
@@ -752,7 +775,6 @@ int zfcp_fc_exec_bsg_job(struct fc_bsg_job *job)
ct_els->req = job->request_payload.sg_list;
ct_els->resp = job->reply_payload.sg_list;
- ct_els->handler = zfcp_fc_ct_els_job_handler;
ct_els->handler_data = job;
switch (job->request->msgcode) {
@@ -767,6 +789,12 @@ int zfcp_fc_exec_bsg_job(struct fc_bsg_job *job)
}
}
+int zfcp_fc_timeout_bsg_job(struct fc_bsg_job *job)
+{
+ /* hardware tracks timeout, reset bsg timeout to not interfere */
+ return -EAGAIN;
+}
+
int zfcp_fc_gs_setup(struct zfcp_adapter *adapter)
{
struct zfcp_fc_wka_ports *wka_ports;
diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h
index cb2a3669a384..0747b087390d 100644
--- a/drivers/s390/scsi/zfcp_fc.h
+++ b/drivers/s390/scsi/zfcp_fc.h
@@ -27,6 +27,8 @@
#define ZFCP_FC_GPN_FT_MAX_ENT (ZFCP_FC_GPN_FT_NUM_BUFS * \
(ZFCP_FC_GPN_FT_ENT_PAGE + 1))
+#define ZFCP_FC_CTELS_TMO (2 * FC_DEF_R_A_TOV / 1000)
+
/**
* struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request
* @ct_hdr: FC GS common transport header
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 482dcd97aa5d..6538742b421a 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -3,7 +3,7 @@
*
* Implementation of FSF commands.
*
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
*/
#define KMSG_COMPONENT "zfcp"
@@ -14,6 +14,8 @@
#include "zfcp_ext.h"
#include "zfcp_fc.h"
#include "zfcp_dbf.h"
+#include "zfcp_qdio.h"
+#include "zfcp_reqlist.h"
static void zfcp_fsf_request_timeout_handler(unsigned long data)
{
@@ -393,7 +395,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
case FSF_PROT_LINK_DOWN:
zfcp_fsf_link_down_info_eval(req, "fspse_5",
&psq->link_down_info);
- /* FIXME: reopening adapter now? better wait for link up */
+ /* go through reopen to flush pending requests */
zfcp_erp_adapter_reopen(adapter, 0, "fspse_6", req);
break;
case FSF_PROT_REEST_QUEUE:
@@ -457,15 +459,10 @@ static void zfcp_fsf_req_complete(struct zfcp_fsf_req *req)
void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
{
struct zfcp_fsf_req *req, *tmp;
- unsigned long flags;
LIST_HEAD(remove_queue);
- unsigned int i;
BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP);
- spin_lock_irqsave(&adapter->req_list_lock, flags);
- for (i = 0; i < REQUEST_LIST_SIZE; i++)
- list_splice_init(&adapter->req_list[i], &remove_queue);
- spin_unlock_irqrestore(&adapter->req_list_lock, flags);
+ zfcp_reqlist_move(adapter->req_list, &remove_queue);
list_for_each_entry_safe(req, tmp, &remove_queue, list) {
list_del(&req->list);
@@ -495,8 +492,6 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
fc_host_port_id(shost) = ntoh24(bottom->s_id);
fc_host_speed(shost) = bottom->fc_link_speed;
fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
- fc_host_supported_fc4s(shost)[2] = 1; /* FCP */
- fc_host_active_fc4s(shost)[2] = 1; /* FCP */
adapter->hydra_version = bottom->adapter_type;
adapter->timer_ticks = bottom->timer_interval;
@@ -619,6 +614,10 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
fc_host_supported_speeds(shost) = bottom->supported_speed;
+ memcpy(fc_host_supported_fc4s(shost), bottom->supported_fc4_types,
+ FC_FC4_LIST_SIZE);
+ memcpy(fc_host_active_fc4s(shost), bottom->active_fc4_types,
+ FC_FC4_LIST_SIZE);
}
static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
@@ -725,12 +724,12 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
req->adapter = adapter;
req->fsf_command = fsf_cmd;
req->req_id = adapter->req_no;
- req->queue_req.sbal_number = 1;
- req->queue_req.sbal_first = req_q->first;
- req->queue_req.sbal_last = req_q->first;
- req->queue_req.sbale_curr = 1;
+ req->qdio_req.sbal_number = 1;
+ req->qdio_req.sbal_first = req_q->first;
+ req->qdio_req.sbal_last = req_q->first;
+ req->qdio_req.sbale_curr = 1;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].addr = (void *) req->req_id;
sbale[0].flags |= SBAL_FLAGS0_COMMAND;
@@ -745,6 +744,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
return ERR_PTR(-ENOMEM);
}
+ req->seq_no = adapter->fsf_req_seq_no;
req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
req->qtcb->prefix.req_id = req->req_id;
req->qtcb->prefix.ulp_info = 26;
@@ -752,8 +752,6 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION;
req->qtcb->header.req_handle = req->req_id;
req->qtcb->header.fsf_command = req->fsf_command;
- req->seq_no = adapter->fsf_req_seq_no;
- req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
sbale[1].addr = (void *) req->qtcb;
sbale[1].length = sizeof(struct fsf_qtcb);
}
@@ -770,25 +768,17 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
{
struct zfcp_adapter *adapter = req->adapter;
struct zfcp_qdio *qdio = adapter->qdio;
- unsigned long flags;
- int idx;
- int with_qtcb = (req->qtcb != NULL);
+ int with_qtcb = (req->qtcb != NULL);
+ int req_id = req->req_id;
- /* put allocated FSF request into hash table */
- spin_lock_irqsave(&adapter->req_list_lock, flags);
- idx = zfcp_reqlist_hash(req->req_id);
- list_add_tail(&req->list, &adapter->req_list[idx]);
- spin_unlock_irqrestore(&adapter->req_list_lock, flags);
+ zfcp_reqlist_add(adapter->req_list, req);
- req->queue_req.qdio_outb_usage = atomic_read(&qdio->req_q.count);
+ req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q.count);
req->issued = get_clock();
- if (zfcp_qdio_send(qdio, &req->queue_req)) {
+ if (zfcp_qdio_send(qdio, &req->qdio_req)) {
del_timer(&req->timer);
- spin_lock_irqsave(&adapter->req_list_lock, flags);
/* lookup request again, list might have changed */
- if (zfcp_reqlist_find_safe(adapter, req))
- zfcp_reqlist_remove(adapter, req);
- spin_unlock_irqrestore(&adapter->req_list_lock, flags);
+ zfcp_reqlist_find_rm(adapter->req_list, req_id);
zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1", req);
return -EIO;
}
@@ -826,9 +816,9 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
goto out;
}
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
- req->queue_req.sbale_curr = 2;
+ req->qdio_req.sbale_curr = 2;
sr_buf = mempool_alloc(adapter->pool.status_read_data, GFP_ATOMIC);
if (!sr_buf) {
@@ -837,7 +827,7 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
}
memset(sr_buf, 0, sizeof(*sr_buf));
req->data = sr_buf;
- sbale = zfcp_qdio_sbale_curr(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_curr(qdio, &req->qdio_req);
sbale->addr = (void *) sr_buf;
sbale->length = sizeof(*sr_buf);
@@ -934,7 +924,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
ZFCP_STATUS_COMMON_UNBLOCKED)))
goto out_error_free;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -1029,7 +1019,7 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
{
struct zfcp_adapter *adapter = req->adapter;
struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(adapter->qdio,
- &req->queue_req);
+ &req->qdio_req);
u32 feat = adapter->adapter_features;
int bytes;
@@ -1047,15 +1037,15 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
return 0;
}
- bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->queue_req,
+ bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
SBAL_FLAGS0_TYPE_WRITE_READ,
sg_req, max_sbals);
if (bytes <= 0)
return -EIO;
req->qtcb->bottom.support.req_buf_length = bytes;
- req->queue_req.sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
+ req->qdio_req.sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
- bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->queue_req,
+ bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
SBAL_FLAGS0_TYPE_WRITE_READ,
sg_resp, max_sbals);
req->qtcb->bottom.support.resp_buf_length = bytes;
@@ -1068,20 +1058,20 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
struct scatterlist *sg_req,
struct scatterlist *sg_resp,
- int max_sbals)
+ int max_sbals, unsigned int timeout)
{
int ret;
- unsigned int fcp_chan_timeout;
ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals);
if (ret)
return ret;
/* common settings for ct/gs and els requests */
- fcp_chan_timeout = 2 * FC_DEF_R_A_TOV / 1000;
+ if (timeout > 255)
+ timeout = 255; /* max value accepted by hardware */
req->qtcb->bottom.support.service_class = FSF_CLASS_3;
- req->qtcb->bottom.support.timeout = fcp_chan_timeout;
- zfcp_fsf_start_timer(req, (fcp_chan_timeout + 10) * HZ);
+ req->qtcb->bottom.support.timeout = timeout;
+ zfcp_fsf_start_timer(req, (timeout + 10) * HZ);
return 0;
}
@@ -1092,7 +1082,8 @@ static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
* @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req
*/
int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
- struct zfcp_fsf_ct_els *ct, mempool_t *pool)
+ struct zfcp_fsf_ct_els *ct, mempool_t *pool,
+ unsigned int timeout)
{
struct zfcp_qdio *qdio = wka_port->adapter->qdio;
struct zfcp_fsf_req *req;
@@ -1111,7 +1102,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp,
- FSF_MAX_SBALS_PER_REQ);
+ FSF_MAX_SBALS_PER_REQ, timeout);
if (ret)
goto failed_send;
@@ -1188,7 +1179,7 @@ skip_fsfstatus:
* @els: pointer to struct zfcp_send_els with data for the command
*/
int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
- struct zfcp_fsf_ct_els *els)
+ struct zfcp_fsf_ct_els *els, unsigned int timeout)
{
struct zfcp_fsf_req *req;
struct zfcp_qdio *qdio = adapter->qdio;
@@ -1206,7 +1197,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, 2);
+ ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, 2, timeout);
if (ret)
goto failed_send;
@@ -1250,7 +1241,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -1261,13 +1252,13 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
FSF_FEATURE_UPDATE_ALERT;
req->erp_action = erp_action;
req->handler = zfcp_fsf_exchange_config_data_handler;
- erp_action->fsf_req = req;
+ erp_action->fsf_req_id = req->req_id;
zfcp_fsf_start_erp_timer(req);
retval = zfcp_fsf_req_send(req);
if (retval) {
zfcp_fsf_req_free(req);
- erp_action->fsf_req = NULL;
+ erp_action->fsf_req_id = 0;
}
out:
spin_unlock_bh(&qdio->req_q_lock);
@@ -1292,7 +1283,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
goto out_unlock;
}
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
req->handler = zfcp_fsf_exchange_config_data_handler;
@@ -1348,19 +1339,19 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
req->handler = zfcp_fsf_exchange_port_data_handler;
req->erp_action = erp_action;
- erp_action->fsf_req = req;
+ erp_action->fsf_req_id = req->req_id;
zfcp_fsf_start_erp_timer(req);
retval = zfcp_fsf_req_send(req);
if (retval) {
zfcp_fsf_req_free(req);
- erp_action->fsf_req = NULL;
+ erp_action->fsf_req_id = 0;
}
out:
spin_unlock_bh(&qdio->req_q_lock);
@@ -1397,7 +1388,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
if (data)
req->data = data;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -1483,7 +1474,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
}
out:
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
}
/**
@@ -1512,7 +1503,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -1520,15 +1511,15 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
hton24(req->qtcb->bottom.support.d_id, port->d_id);
req->data = port;
req->erp_action = erp_action;
- erp_action->fsf_req = req;
- get_device(&port->sysfs_device);
+ erp_action->fsf_req_id = req->req_id;
+ get_device(&port->dev);
zfcp_fsf_start_erp_timer(req);
retval = zfcp_fsf_req_send(req);
if (retval) {
zfcp_fsf_req_free(req);
- erp_action->fsf_req = NULL;
- put_device(&port->sysfs_device);
+ erp_action->fsf_req_id = 0;
+ put_device(&port->dev);
}
out:
spin_unlock_bh(&qdio->req_q_lock);
@@ -1582,7 +1573,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -1590,13 +1581,13 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
req->data = erp_action->port;
req->erp_action = erp_action;
req->qtcb->header.port_handle = erp_action->port->handle;
- erp_action->fsf_req = req;
+ erp_action->fsf_req_id = req->req_id;
zfcp_fsf_start_erp_timer(req);
retval = zfcp_fsf_req_send(req);
if (retval) {
zfcp_fsf_req_free(req);
- erp_action->fsf_req = NULL;
+ erp_action->fsf_req_id = 0;
}
out:
spin_unlock_bh(&qdio->req_q_lock);
@@ -1659,7 +1650,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -1714,7 +1705,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -1808,7 +1799,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -1816,13 +1807,13 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
req->qtcb->header.port_handle = erp_action->port->handle;
req->erp_action = erp_action;
req->handler = zfcp_fsf_close_physical_port_handler;
- erp_action->fsf_req = req;
+ erp_action->fsf_req_id = req->req_id;
zfcp_fsf_start_erp_timer(req);
retval = zfcp_fsf_req_send(req);
if (retval) {
zfcp_fsf_req_free(req);
- erp_action->fsf_req = NULL;
+ erp_action->fsf_req_id = 0;
}
out:
spin_unlock_bh(&qdio->req_q_lock);
@@ -1981,7 +1972,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -1990,7 +1981,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
req->handler = zfcp_fsf_open_unit_handler;
req->data = erp_action->unit;
req->erp_action = erp_action;
- erp_action->fsf_req = req;
+ erp_action->fsf_req_id = req->req_id;
if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE))
req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING;
@@ -1999,7 +1990,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
retval = zfcp_fsf_req_send(req);
if (retval) {
zfcp_fsf_req_free(req);
- erp_action->fsf_req = NULL;
+ erp_action->fsf_req_id = 0;
}
out:
spin_unlock_bh(&qdio->req_q_lock);
@@ -2067,7 +2058,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -2076,13 +2067,13 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
req->handler = zfcp_fsf_close_unit_handler;
req->data = erp_action->unit;
req->erp_action = erp_action;
- erp_action->fsf_req = req;
+ erp_action->fsf_req_id = req->req_id;
zfcp_fsf_start_erp_timer(req);
retval = zfcp_fsf_req_send(req);
if (retval) {
zfcp_fsf_req_free(req);
- erp_action->fsf_req = NULL;
+ erp_action->fsf_req_id = 0;
}
out:
spin_unlock_bh(&qdio->req_q_lock);
@@ -2110,8 +2101,8 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
blktrc.magic = ZFCP_BLK_DRV_DATA_MAGIC;
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
blktrc.flags |= ZFCP_BLK_REQ_ERROR;
- blktrc.inb_usage = req->queue_req.qdio_inb_usage;
- blktrc.outb_usage = req->queue_req.qdio_outb_usage;
+ blktrc.inb_usage = req->qdio_req.qdio_inb_usage;
+ blktrc.outb_usage = req->qdio_req.qdio_outb_usage;
if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) {
blktrc.flags |= ZFCP_BLK_LAT_VALID;
@@ -2168,12 +2159,7 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
zfcp_fsf_req_trace(req, scpnt);
skip_fsfstatus:
- if (scpnt->result != 0)
- zfcp_dbf_scsi_result("erro", 3, req->adapter->dbf, scpnt, req);
- else if (scpnt->retries > 0)
- zfcp_dbf_scsi_result("retr", 4, req->adapter->dbf, scpnt, req);
- else
- zfcp_dbf_scsi_result("norm", 6, req->adapter->dbf, scpnt, req);
+ zfcp_dbf_scsi_result(req->adapter->dbf, scpnt, req);
scpnt->host_scribble = NULL;
(scpnt->scsi_done) (scpnt);
@@ -2273,7 +2259,7 @@ skip_fsfstatus:
else {
zfcp_fsf_send_fcp_command_task_handler(req);
req->unit = NULL;
- put_device(&unit->sysfs_device);
+ put_device(&unit->dev);
}
}
@@ -2311,7 +2297,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- get_device(&unit->sysfs_device);
+ get_device(&unit->dev);
req->unit = unit;
req->data = scsi_cmnd;
req->handler = zfcp_fsf_send_fcp_command_handler;
@@ -2345,11 +2331,11 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
- real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->queue_req, sbtype,
+ real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sbtype,
scsi_sglist(scsi_cmnd),
FSF_MAX_SBALS_PER_REQ);
if (unlikely(real_bytes < 0)) {
- if (req->queue_req.sbal_number >= FSF_MAX_SBALS_PER_REQ) {
+ if (req->qdio_req.sbal_number >= FSF_MAX_SBALS_PER_REQ) {
dev_err(&adapter->ccw_device->dev,
"Oversize data package, unit 0x%016Lx "
"on port 0x%016Lx closed\n",
@@ -2368,7 +2354,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
goto out;
failed_scsi_cmnd:
- put_device(&unit->sysfs_device);
+ put_device(&unit->dev);
zfcp_fsf_req_free(req);
scsi_cmnd->host_scribble = NULL;
out:
@@ -2414,7 +2400,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
req->qtcb->bottom.io.service_class = FSF_CLASS_3;
req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -2477,14 +2463,14 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
req->handler = zfcp_fsf_control_file_handler;
- sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req);
+ sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
sbale[0].flags |= direction;
bottom = &req->qtcb->bottom.support;
bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
bottom->option = fsf_cfdc->option;
- bytes = zfcp_qdio_sbals_from_sg(qdio, &req->queue_req,
+ bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
direction, fsf_cfdc->sg,
FSF_MAX_SBALS_PER_REQ);
if (bytes != ZFCP_CFDC_MAX_SIZE) {
@@ -2515,15 +2501,14 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
struct qdio_buffer *sbal = qdio->resp_q.sbal[sbal_idx];
struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *fsf_req;
- unsigned long flags, req_id;
+ unsigned long req_id;
int idx;
for (idx = 0; idx < QDIO_MAX_ELEMENTS_PER_BUFFER; idx++) {
sbale = &sbal->element[idx];
req_id = (unsigned long) sbale->addr;
- spin_lock_irqsave(&adapter->req_list_lock, flags);
- fsf_req = zfcp_reqlist_find(adapter, req_id);
+ fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id);
if (!fsf_req)
/*
@@ -2533,11 +2518,8 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
panic("error: unknown req_id (%lx) on adapter %s.\n",
req_id, dev_name(&adapter->ccw_device->dev));
- list_del(&fsf_req->list);
- spin_unlock_irqrestore(&adapter->req_list_lock, flags);
-
- fsf_req->queue_req.sbal_response = sbal_idx;
- fsf_req->queue_req.qdio_inb_usage =
+ fsf_req->qdio_req.sbal_response = sbal_idx;
+ fsf_req->qdio_req.qdio_inb_usage =
atomic_read(&qdio->resp_q.count);
zfcp_fsf_req_complete(fsf_req);
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 6c5228b627fc..6479273a3094 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -10,6 +10,7 @@
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include "zfcp_ext.h"
+#include "zfcp_qdio.h"
#define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer))
@@ -28,12 +29,6 @@ static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
return 0;
}
-static struct qdio_buffer_element *
-zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
-{
- return &q->sbal[sbal_idx]->element[sbale_idx];
-}
-
static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id)
{
struct zfcp_adapter *adapter = qdio->adapter;
@@ -106,7 +101,7 @@ static void zfcp_qdio_resp_put_back(struct zfcp_qdio *qdio, int processed)
if (unlikely(retval)) {
atomic_set(&queue->count, count);
- /* FIXME: Recover this with an adapter reopen? */
+ zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdrpb_1", NULL);
} else {
queue->first += count;
queue->first %= QDIO_MAX_BUFFERS_PER_Q;
@@ -145,32 +140,8 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
zfcp_qdio_resp_put_back(qdio, count);
}
-/**
- * zfcp_qdio_sbale_req - return ptr to SBALE of req_q for a struct zfcp_fsf_req
- * @qdio: pointer to struct zfcp_qdio
- * @q_rec: pointer to struct zfcp_queue_rec
- * Returns: pointer to qdio_buffer_element (SBALE) structure
- */
-struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_qdio *qdio,
- struct zfcp_queue_req *q_req)
-{
- return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last, 0);
-}
-
-/**
- * zfcp_qdio_sbale_curr - return curr SBALE on req_q for a struct zfcp_fsf_req
- * @fsf_req: pointer to struct fsf_req
- * Returns: pointer to qdio_buffer_element (SBALE) structure
- */
-struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio,
- struct zfcp_queue_req *q_req)
-{
- return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last,
- q_req->sbale_curr);
-}
-
static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
- struct zfcp_queue_req *q_req, int max_sbals)
+ struct zfcp_qdio_req *q_req, int max_sbals)
{
int count = atomic_read(&qdio->req_q.count);
count = min(count, max_sbals);
@@ -179,7 +150,7 @@ static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
}
static struct qdio_buffer_element *
-zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req,
+zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
unsigned long sbtype)
{
struct qdio_buffer_element *sbale;
@@ -214,7 +185,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req,
}
static struct qdio_buffer_element *
-zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req,
+zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
unsigned int sbtype)
{
if (q_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
@@ -224,7 +195,7 @@ zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req,
}
static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
- struct zfcp_queue_req *q_req)
+ struct zfcp_qdio_req *q_req)
{
struct qdio_buffer **sbal = qdio->req_q.sbal;
int first = q_req->sbal_first;
@@ -235,7 +206,7 @@ static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
}
static int zfcp_qdio_fill_sbals(struct zfcp_qdio *qdio,
- struct zfcp_queue_req *q_req,
+ struct zfcp_qdio_req *q_req,
unsigned int sbtype, void *start_addr,
unsigned int total_length)
{
@@ -271,8 +242,7 @@ static int zfcp_qdio_fill_sbals(struct zfcp_qdio *qdio,
* @max_sbals: upper bound for number of SBALs to be used
* Returns: number of bytes, or error (negativ)
*/
-int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio,
- struct zfcp_queue_req *q_req,
+int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
unsigned long sbtype, struct scatterlist *sg,
int max_sbals)
{
@@ -304,10 +274,10 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio,
/**
* zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO
* @qdio: pointer to struct zfcp_qdio
- * @q_req: pointer to struct zfcp_queue_req
+ * @q_req: pointer to struct zfcp_qdio_req
* Returns: 0 on success, error otherwise
*/
-int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req)
+int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
{
struct zfcp_qdio_queue *req_q = &qdio->req_q;
int first = q_req->sbal_first;
@@ -349,8 +319,6 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
id->input_handler = zfcp_qdio_int_resp;
id->output_handler = zfcp_qdio_int_req;
id->int_parm = (unsigned long) qdio;
- id->flags = QDIO_INBOUND_0COPY_SBALS |
- QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS;
id->input_sbal_addr_array = (void **) (qdio->resp_q.sbal);
id->output_sbal_addr_array = (void **) (qdio->req_q.sbal);
diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h
new file mode 100644
index 000000000000..8cca54631e1e
--- /dev/null
+++ b/drivers/s390/scsi/zfcp_qdio.h
@@ -0,0 +1,109 @@
+/*
+ * zfcp device driver
+ *
+ * Header file for zfcp qdio interface
+ *
+ * Copyright IBM Corporation 2010
+ */
+
+#ifndef ZFCP_QDIO_H
+#define ZFCP_QDIO_H
+
+#include <asm/qdio.h>
+
+/**
+ * struct zfcp_qdio_queue - qdio queue buffer, zfcp index and free count
+ * @sbal: qdio buffers
+ * @first: index of next free buffer in queue
+ * @count: number of free buffers in queue
+ */
+struct zfcp_qdio_queue {
+ struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q];
+ u8 first;
+ atomic_t count;
+};
+
+/**
+ * struct zfcp_qdio - basic qdio data structure
+ * @resp_q: response queue
+ * @req_q: request queue
+ * @stat_lock: lock to protect req_q_util and req_q_time
+ * @req_q_lock: lock to serialize access to request queue
+ * @req_q_time: time of last fill level change
+ * @req_q_util: used for accounting
+ * @req_q_full: queue full incidents
+ * @req_q_wq: used to wait for SBAL availability
+ * @adapter: adapter used in conjunction with this qdio structure
+ */
+struct zfcp_qdio {
+ struct zfcp_qdio_queue resp_q;
+ struct zfcp_qdio_queue req_q;
+ spinlock_t stat_lock;
+ spinlock_t req_q_lock;
+ unsigned long long req_q_time;
+ u64 req_q_util;
+ atomic_t req_q_full;
+ wait_queue_head_t req_q_wq;
+ struct zfcp_adapter *adapter;
+};
+
+/**
+ * struct zfcp_qdio_req - qdio queue related values for a request
+ * @sbal_number: number of free sbals
+ * @sbal_first: first sbal for this request
+ * @sbal_last: last sbal for this request
+ * @sbal_limit: last possible sbal for this request
+ * @sbale_curr: current sbale at creation of this request
+ * @sbal_response: sbal used in interrupt
+ * @qdio_outb_usage: usage of outbound queue
+ * @qdio_inb_usage: usage of inbound queue
+ */
+struct zfcp_qdio_req {
+ u8 sbal_number;
+ u8 sbal_first;
+ u8 sbal_last;
+ u8 sbal_limit;
+ u8 sbale_curr;
+ u8 sbal_response;
+ u16 qdio_outb_usage;
+ u16 qdio_inb_usage;
+};
+
+/**
+ * zfcp_qdio_sbale - return pointer to sbale in qdio queue
+ * @q: queue where to find sbal
+ * @sbal_idx: sbal index in queue
+ * @sbale_idx: sbale index in sbal
+ */
+static inline struct qdio_buffer_element *
+zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
+{
+ return &q->sbal[sbal_idx]->element[sbale_idx];
+}
+
+/**
+ * zfcp_qdio_sbale_req - return pointer to sbale on req_q for a request
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_rec: pointer to struct zfcp_qdio_req
+ * Returns: pointer to qdio_buffer_element (sbale) structure
+ */
+static inline struct qdio_buffer_element *
+zfcp_qdio_sbale_req(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
+{
+ return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last, 0);
+}
+
+/**
+ * zfcp_qdio_sbale_curr - return current sbale on req_q for a request
+ * @qdio: pointer to struct zfcp_qdio
+ * @fsf_req: pointer to struct zfcp_fsf_req
+ * Returns: pointer to qdio_buffer_element (sbale) structure
+ */
+static inline struct qdio_buffer_element *
+zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
+{
+ return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last,
+ q_req->sbale_curr);
+}
+
+#endif /* ZFCP_QDIO_H */
diff --git a/drivers/s390/scsi/zfcp_reqlist.h b/drivers/s390/scsi/zfcp_reqlist.h
new file mode 100644
index 000000000000..a72d1b730aba
--- /dev/null
+++ b/drivers/s390/scsi/zfcp_reqlist.h
@@ -0,0 +1,183 @@
+/*
+ * zfcp device driver
+ *
+ * Data structure and helper functions for tracking pending FSF
+ * requests.
+ *
+ * Copyright IBM Corporation 2009
+ */
+
+#ifndef ZFCP_REQLIST_H
+#define ZFCP_REQLIST_H
+
+/* number of hash buckets */
+#define ZFCP_REQ_LIST_BUCKETS 128
+
+/**
+ * struct zfcp_reqlist - Container for request list (reqlist)
+ * @lock: Spinlock for protecting the hash list
+ * @list: Array of hashbuckets, each is a list of requests in this bucket
+ */
+struct zfcp_reqlist {
+ spinlock_t lock;
+ struct list_head buckets[ZFCP_REQ_LIST_BUCKETS];
+};
+
+static inline int zfcp_reqlist_hash(unsigned long req_id)
+{
+ return req_id % ZFCP_REQ_LIST_BUCKETS;
+}
+
+/**
+ * zfcp_reqlist_alloc - Allocate and initialize reqlist
+ *
+ * Returns pointer to allocated reqlist on success, or NULL on
+ * allocation failure.
+ */
+static inline struct zfcp_reqlist *zfcp_reqlist_alloc(void)
+{
+ unsigned int i;
+ struct zfcp_reqlist *rl;
+
+ rl = kzalloc(sizeof(struct zfcp_reqlist), GFP_KERNEL);
+ if (!rl)
+ return NULL;
+
+ spin_lock_init(&rl->lock);
+
+ for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
+ INIT_LIST_HEAD(&rl->buckets[i]);
+
+ return rl;
+}
+
+/**
+ * zfcp_reqlist_isempty - Check whether the request list empty
+ * @rl: pointer to reqlist
+ *
+ * Returns: 1 if list is empty, 0 if not
+ */
+static inline int zfcp_reqlist_isempty(struct zfcp_reqlist *rl)
+{
+ unsigned int i;
+
+ for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
+ if (!list_empty(&rl->buckets[i]))
+ return 0;
+ return 1;
+}
+
+/**
+ * zfcp_reqlist_free - Free allocated memory for reqlist
+ * @rl: The reqlist where to free memory
+ */
+static inline void zfcp_reqlist_free(struct zfcp_reqlist *rl)
+{
+ /* sanity check */
+ BUG_ON(!zfcp_reqlist_isempty(rl));
+
+ kfree(rl);
+}
+
+static inline struct zfcp_fsf_req *
+_zfcp_reqlist_find(struct zfcp_reqlist *rl, unsigned long req_id)
+{
+ struct zfcp_fsf_req *req;
+ unsigned int i;
+
+ i = zfcp_reqlist_hash(req_id);
+ list_for_each_entry(req, &rl->buckets[i], list)
+ if (req->req_id == req_id)
+ return req;
+ return NULL;
+}
+
+/**
+ * zfcp_reqlist_find - Lookup FSF request by its request id
+ * @rl: The reqlist where to lookup the FSF request
+ * @req_id: The request id to look for
+ *
+ * Returns a pointer to the FSF request with the specified request id
+ * or NULL if there is no known FSF request with this id.
+ */
+static inline struct zfcp_fsf_req *
+zfcp_reqlist_find(struct zfcp_reqlist *rl, unsigned long req_id)
+{
+ unsigned long flags;
+ struct zfcp_fsf_req *req;
+
+ spin_lock_irqsave(&rl->lock, flags);
+ req = _zfcp_reqlist_find(rl, req_id);
+ spin_unlock_irqrestore(&rl->lock, flags);
+
+ return req;
+}
+
+/**
+ * zfcp_reqlist_find_rm - Lookup request by id and remove it from reqlist
+ * @rl: reqlist where to search and remove entry
+ * @req_id: The request id of the request to look for
+ *
+ * This functions tries to find the FSF request with the specified
+ * id and then removes it from the reqlist. The reqlist lock is held
+ * during both steps of the operation.
+ *
+ * Returns: Pointer to the FSF request if the request has been found,
+ * NULL if it has not been found.
+ */
+static inline struct zfcp_fsf_req *
+zfcp_reqlist_find_rm(struct zfcp_reqlist *rl, unsigned long req_id)
+{
+ unsigned long flags;
+ struct zfcp_fsf_req *req;
+
+ spin_lock_irqsave(&rl->lock, flags);
+ req = _zfcp_reqlist_find(rl, req_id);
+ if (req)
+ list_del(&req->list);
+ spin_unlock_irqrestore(&rl->lock, flags);
+
+ return req;
+}
+
+/**
+ * zfcp_reqlist_add - Add entry to reqlist
+ * @rl: reqlist where to add the entry
+ * @req: The entry to add
+ *
+ * The request id always increases. As an optimization new requests
+ * are added here with list_add_tail at the end of the bucket lists
+ * while old requests are looked up starting at the beginning of the
+ * lists.
+ */
+static inline void zfcp_reqlist_add(struct zfcp_reqlist *rl,
+ struct zfcp_fsf_req *req)
+{
+ unsigned int i;
+ unsigned long flags;
+
+ i = zfcp_reqlist_hash(req->req_id);
+
+ spin_lock_irqsave(&rl->lock, flags);
+ list_add_tail(&req->list, &rl->buckets[i]);
+ spin_unlock_irqrestore(&rl->lock, flags);
+}
+
+/**
+ * zfcp_reqlist_move - Move all entries from reqlist to simple list
+ * @rl: The zfcp_reqlist where to remove all entries
+ * @list: The list where to move all entries
+ */
+static inline void zfcp_reqlist_move(struct zfcp_reqlist *rl,
+ struct list_head *list)
+{
+ unsigned int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rl->lock, flags);
+ for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
+ list_splice_init(&rl->buckets[i], list);
+ spin_unlock_irqrestore(&rl->lock, flags);
+}
+
+#endif /* ZFCP_REQLIST_H */
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 771cc536a989..c3c4178888af 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -3,7 +3,7 @@
*
* Interface to Linux SCSI midlayer.
*
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
*/
#define KMSG_COMPONENT "zfcp"
@@ -15,6 +15,7 @@
#include "zfcp_ext.h"
#include "zfcp_dbf.h"
#include "zfcp_fc.h"
+#include "zfcp_reqlist.h"
static unsigned int default_depth = 32;
module_param_named(queue_depth, default_depth, uint, 0600);
@@ -43,7 +44,7 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
{
struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
unit->device = NULL;
- put_device(&unit->sysfs_device);
+ put_device(&unit->dev);
}
static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
@@ -59,10 +60,9 @@ static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
{
struct zfcp_adapter *adapter =
(struct zfcp_adapter *) scpnt->device->host->hostdata[0];
+
set_host_byte(scpnt, result);
- if ((scpnt->device != NULL) && (scpnt->device->host != NULL))
- zfcp_dbf_scsi_result("fail", 4, adapter->dbf, scpnt, NULL);
- /* return directly */
+ zfcp_dbf_scsi_fail_send(adapter->dbf, scpnt);
scpnt->scsi_done(scpnt);
}
@@ -86,18 +86,10 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
unit = scpnt->device->hostdata;
- BUG_ON(!adapter || (adapter != unit->port->adapter));
- BUG_ON(!scpnt->scsi_done);
-
- if (unlikely(!unit)) {
- zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT);
- return 0;
- }
-
scsi_result = fc_remote_port_chkready(rport);
if (unlikely(scsi_result)) {
scpnt->result = scsi_result;
- zfcp_dbf_scsi_result("fail", 4, adapter->dbf, scpnt, NULL);
+ zfcp_dbf_scsi_fail_send(adapter->dbf, scpnt);
scpnt->scsi_done(scpnt);
return 0;
}
@@ -189,9 +181,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
/* avoid race condition between late normal completion and abort */
write_lock_irqsave(&adapter->abort_lock, flags);
- spin_lock(&adapter->req_list_lock);
- old_req = zfcp_reqlist_find(adapter, old_reqid);
- spin_unlock(&adapter->req_list_lock);
+ old_req = zfcp_reqlist_find(adapter->req_list, old_reqid);
if (!old_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags);
zfcp_dbf_scsi_abort("lte1", adapter->dbf, scpnt, NULL,
@@ -521,7 +511,7 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
if (port) {
zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL);
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
}
}
@@ -563,23 +553,23 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port)
void zfcp_scsi_schedule_rport_register(struct zfcp_port *port)
{
- get_device(&port->sysfs_device);
+ get_device(&port->dev);
port->rport_task = RPORT_ADD;
if (!queue_work(port->adapter->work_queue, &port->rport_work))
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
}
void zfcp_scsi_schedule_rport_block(struct zfcp_port *port)
{
- get_device(&port->sysfs_device);
+ get_device(&port->dev);
port->rport_task = RPORT_DEL;
if (port->rport && queue_work(port->adapter->work_queue,
&port->rport_work))
return;
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
}
void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter)
@@ -608,7 +598,7 @@ void zfcp_scsi_rport_work(struct work_struct *work)
}
}
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
}
@@ -626,7 +616,7 @@ void zfcp_scsi_scan(struct work_struct *work)
scsilun_to_int((struct scsi_lun *)
&unit->fcp_lun), 0);
- put_device(&unit->sysfs_device);
+ put_device(&unit->dev);
}
struct fc_function_template zfcp_transport_functions = {
@@ -652,6 +642,7 @@ struct fc_function_template zfcp_transport_functions = {
.show_host_port_state = 1,
.show_host_active_fc4s = 1,
.bsg_request = zfcp_fc_exec_bsg_job,
+ .bsg_timeout = zfcp_fc_timeout_bsg_job,
/* no functions registered for following dynamic attributes but
directly set by LLDD */
.show_host_port_type = 1,
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index f539e006683c..a43035d4bd70 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -3,7 +3,7 @@
*
* sysfs attributes.
*
- * Copyright IBM Corporation 2008, 2009
+ * Copyright IBM Corporation 2008, 2010
*/
#define KMSG_COMPONENT "zfcp"
@@ -19,8 +19,7 @@ static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \
struct device_attribute *at,\
char *buf) \
{ \
- struct _feat_def *_feat = container_of(dev, struct _feat_def, \
- sysfs_device); \
+ struct _feat_def *_feat = container_of(dev, struct _feat_def, dev); \
\
return sprintf(buf, _format, _value); \
} \
@@ -87,8 +86,7 @@ static ssize_t zfcp_sysfs_##_feat##_failed_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
- struct _feat_def *_feat = container_of(dev, struct _feat_def, \
- sysfs_device); \
+ struct _feat_def *_feat = container_of(dev, struct _feat_def, dev); \
\
if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_ERP_FAILED) \
return sprintf(buf, "1\n"); \
@@ -99,12 +97,11 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \
struct device_attribute *attr,\
const char *buf, size_t count)\
{ \
- struct _feat_def *_feat = container_of(dev, struct _feat_def, \
- sysfs_device); \
+ struct _feat_def *_feat = container_of(dev, struct _feat_def, dev); \
unsigned long val; \
int retval = 0; \
\
- if (!(_feat && get_device(&_feat->sysfs_device))) \
+ if (!(_feat && get_device(&_feat->dev))) \
return -EBUSY; \
\
if (strict_strtoul(buf, 0, &val) || val != 0) { \
@@ -118,7 +115,7 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \
_reopen_id, NULL); \
zfcp_erp_wait(_adapter); \
out: \
- put_device(&_feat->sysfs_device); \
+ put_device(&_feat->dev); \
return retval ? retval : (ssize_t) count; \
} \
static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \
@@ -224,10 +221,10 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
list_del(&port->list);
write_unlock_irq(&adapter->port_list_lock);
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL);
- zfcp_device_unregister(&port->sysfs_device, &zfcp_sysfs_port_attrs);
+ zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs);
out:
zfcp_ccw_adapter_put(adapter);
return retval ? retval : (ssize_t) count;
@@ -258,13 +255,12 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct zfcp_port *port = container_of(dev, struct zfcp_port,
- sysfs_device);
+ struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
struct zfcp_unit *unit;
u64 fcp_lun;
int retval = -EINVAL;
- if (!(port && get_device(&port->sysfs_device)))
+ if (!(port && get_device(&port->dev)))
return -EBUSY;
if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
@@ -280,7 +276,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
zfcp_erp_wait(unit->port->adapter);
flush_work(&unit->scsi_work);
out:
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
return retval ? retval : (ssize_t) count;
}
static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store);
@@ -289,13 +285,12 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct zfcp_port *port = container_of(dev, struct zfcp_port,
- sysfs_device);
+ struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
struct zfcp_unit *unit;
u64 fcp_lun;
int retval = -EINVAL;
- if (!(port && get_device(&port->sysfs_device)))
+ if (!(port && get_device(&port->dev)))
return -EBUSY;
if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
@@ -314,12 +309,12 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
list_del(&unit->list);
write_unlock_irq(&port->unit_list_lock);
- put_device(&unit->sysfs_device);
+ put_device(&unit->dev);
zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL);
- zfcp_device_unregister(&unit->sysfs_device, &zfcp_sysfs_unit_attrs);
+ zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs);
out:
- put_device(&port->sysfs_device);
+ put_device(&port->dev);
return retval ? retval : (ssize_t) count;
}
static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store);
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 75ac19b1192f..fc2f676e984d 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -233,7 +233,7 @@ static int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp
ph = 0;
if (dp)
- ph = dp->node;
+ ph = dp->phandle;
data->current_node = dp;
*((int *) op->oprom_array) = ph;
@@ -256,7 +256,7 @@ static int oprompci2node(void __user *argp, struct device_node *dp, struct openp
dp = pci_device_to_OF_node(pdev);
data->current_node = dp;
- *((int *)op->oprom_array) = dp->node;
+ *((int *)op->oprom_array) = dp->phandle;
op->oprom_size = sizeof(int);
err = copyout(argp, op, bufsize + sizeof(int));
@@ -273,7 +273,7 @@ static int oprompath2node(void __user *argp, struct device_node *dp, struct open
dp = of_find_node_by_path(op->oprom_array);
if (dp)
- ph = dp->node;
+ ph = dp->phandle;
data->current_node = dp;
*((int *)op->oprom_array) = ph;
op->oprom_size = sizeof(int);
@@ -540,7 +540,7 @@ static int opiocgetnext(unsigned int cmd, void __user *argp)
}
}
if (dp)
- nd = dp->node;
+ nd = dp->phandle;
if (copy_to_user(argp, &nd, sizeof(phandle)))
return -EFAULT;
@@ -570,7 +570,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
case OPIOCGETOPTNODE:
BUILD_BUG_ON(sizeof(phandle) != sizeof(int));
- if (copy_to_user(argp, &options_node->node, sizeof(phandle)))
+ if (copy_to_user(argp, &options_node->phandle, sizeof(phandle)))
return -EFAULT;
return 0;
diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c
index b898d382b7b0..e40cdfb7541f 100644
--- a/drivers/scsi/FlashPoint.c
+++ b/drivers/scsi/FlashPoint.c
@@ -3924,7 +3924,7 @@ static void FPT_sinits(struct sccb *p_sccb, unsigned char p_card)
{
struct sccb_mgr_tar_info *currTar_Info;
- if ((p_sccb->TargID > MAX_SCSI_TAR) || (p_sccb->Lun > MAX_LUN)) {
+ if ((p_sccb->TargID >= MAX_SCSI_TAR) || (p_sccb->Lun >= MAX_LUN)) {
return;
}
currTar_Info = &FPT_sccbMgrTbl[p_card][p_sccb->TargID];
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index 208d6df9ed59..ff5716d5f044 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -492,7 +492,7 @@ static void init_alloc_map(struct orc_host * host)
* init_orchid - initialise the host adapter
* @host:host adapter to initialise
*
- * Initialise the controller and if neccessary load the firmware.
+ * Initialise the controller and if necessary load the firmware.
*
* Returns -1 if the initialisation fails.
*/
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 2a889853a106..7e26ebc26661 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -293,7 +293,10 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
status = -EINVAL;
}
}
- aac_fib_complete(fibptr);
+ /* Do not set XferState to zero unless receives a response from F/W */
+ if (status >= 0)
+ aac_fib_complete(fibptr);
+
/* Send a CT_COMMIT_CONFIG to enable discovery of devices */
if (status >= 0) {
if ((aac_commit == 1) || commit_flag) {
@@ -310,13 +313,18 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
FsaNormal,
1, 1,
NULL, NULL);
- aac_fib_complete(fibptr);
+ /* Do not set XferState to zero unless
+ * receives a response from F/W */
+ if (status >= 0)
+ aac_fib_complete(fibptr);
} else if (aac_commit == 0) {
printk(KERN_WARNING
"aac_get_config_status: Foreign device configurations are being ignored\n");
}
}
- aac_fib_free(fibptr);
+ /* FIB should be freed only after getting the response from the F/W */
+ if (status != -ERESTARTSYS)
+ aac_fib_free(fibptr);
return status;
}
@@ -355,7 +363,9 @@ int aac_get_containers(struct aac_dev *dev)
maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries);
aac_fib_complete(fibptr);
}
- aac_fib_free(fibptr);
+ /* FIB should be freed only after getting the response from the F/W */
+ if (status != -ERESTARTSYS)
+ aac_fib_free(fibptr);
if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
@@ -1245,8 +1255,12 @@ int aac_get_adapter_info(struct aac_dev* dev)
NULL);
if (rcode < 0) {
- aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
+ /* FIB should be freed only after
+ * getting the response from the F/W */
+ if (rcode != -ERESTARTSYS) {
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ }
return rcode;
}
memcpy(&dev->adapter_info, info, sizeof(*info));
@@ -1270,6 +1284,12 @@ int aac_get_adapter_info(struct aac_dev* dev)
if (rcode >= 0)
memcpy(&dev->supplement_adapter_info, sinfo, sizeof(*sinfo));
+ if (rcode == -ERESTARTSYS) {
+ fibptr = aac_fib_alloc(dev);
+ if (!fibptr)
+ return -ENOMEM;
+ }
+
}
@@ -1470,9 +1490,11 @@ int aac_get_adapter_info(struct aac_dev* dev)
(dev->scsi_host_ptr->sg_tablesize * 8) + 112;
}
}
-
- aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
+ /* FIB should be freed only after getting the response from the F/W */
+ if (rcode != -ERESTARTSYS) {
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ }
return rcode;
}
@@ -1633,6 +1655,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)
* Alocate and initialize a Fib
*/
if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
+ printk(KERN_WARNING "aac_read: fib allocation failed\n");
return -1;
}
@@ -1712,9 +1735,14 @@ static int aac_write(struct scsi_cmnd * scsicmd)
* Allocate and initialize a Fib then setup a BlockWrite command
*/
if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
- scsicmd->result = DID_ERROR << 16;
- scsicmd->scsi_done(scsicmd);
- return 0;
+ /* FIB temporarily unavailable,not catastrophic failure */
+
+ /* scsicmd->result = DID_ERROR << 16;
+ * scsicmd->scsi_done(scsicmd);
+ * return 0;
+ */
+ printk(KERN_WARNING "aac_write: fib allocation failed\n");
+ return -1;
}
status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count, fua);
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 83986ed86556..619c02d9c862 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,7 +12,7 @@
*----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2461
+# define AAC_DRIVER_BUILD 24702
# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -1036,6 +1036,9 @@ struct aac_dev
u8 printf_enabled;
u8 in_reset;
u8 msi;
+ int management_fib_count;
+ spinlock_t manage_lock;
+
};
#define aac_adapter_interrupt(dev) \
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index 0391d759dfdb..9c0c91178538 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -153,7 +153,7 @@ cleanup:
fibptr->hw_fib_pa = hw_fib_pa;
fibptr->hw_fib_va = hw_fib;
}
- if (retval != -EINTR)
+ if (retval != -ERESTARTSYS)
aac_fib_free(fibptr);
return retval;
}
@@ -322,7 +322,7 @@ return_fib:
}
if (f.wait) {
if(down_interruptible(&fibctx->wait_sem) < 0) {
- status = -EINTR;
+ status = -ERESTARTSYS;
} else {
/* Lock again and retry */
spin_lock_irqsave(&dev->fib_lock, flags);
@@ -593,10 +593,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
u64 addr;
void* p;
if (upsg->sg[i].count >
- (dev->adapter_info.options &
+ ((dev->adapter_info.options &
AAC_OPT_NEW_COMM) ?
(dev->scsi_host_ptr->max_sectors << 9) :
- 65536) {
+ 65536)) {
rcode = -EINVAL;
goto cleanup;
}
@@ -645,10 +645,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
u64 addr;
void* p;
if (usg->sg[i].count >
- (dev->adapter_info.options &
+ ((dev->adapter_info.options &
AAC_OPT_NEW_COMM) ?
(dev->scsi_host_ptr->max_sectors << 9) :
- 65536) {
+ 65536)) {
rcode = -EINVAL;
goto cleanup;
}
@@ -695,10 +695,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
uintptr_t addr;
void* p;
if (usg->sg[i].count >
- (dev->adapter_info.options &
+ ((dev->adapter_info.options &
AAC_OPT_NEW_COMM) ?
(dev->scsi_host_ptr->max_sectors << 9) :
- 65536) {
+ 65536)) {
rcode = -EINVAL;
goto cleanup;
}
@@ -734,10 +734,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
dma_addr_t addr;
void* p;
if (upsg->sg[i].count >
- (dev->adapter_info.options &
+ ((dev->adapter_info.options &
AAC_OPT_NEW_COMM) ?
(dev->scsi_host_ptr->max_sectors << 9) :
- 65536) {
+ 65536)) {
rcode = -EINVAL;
goto cleanup;
}
@@ -772,8 +772,8 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
psg->count = cpu_to_le32(sg_indx+1);
status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL);
}
- if (status == -EINTR) {
- rcode = -EINTR;
+ if (status == -ERESTARTSYS) {
+ rcode = -ERESTARTSYS;
goto cleanup;
}
@@ -810,7 +810,7 @@ cleanup:
for(i=0; i <= sg_indx; i++){
kfree(sg_list[i]);
}
- if (rcode != -EINTR) {
+ if (rcode != -ERESTARTSYS) {
aac_fib_complete(srbfib);
aac_fib_free(srbfib);
}
@@ -848,7 +848,7 @@ int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
*/
status = aac_dev_ioctl(dev, cmd, arg);
- if(status != -ENOTTY)
+ if (status != -ENOTTY)
return status;
switch (cmd) {
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 666d5151d628..a7261486ccd4 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -194,7 +194,9 @@ int aac_send_shutdown(struct aac_dev * dev)
if (status >= 0)
aac_fib_complete(fibctx);
- aac_fib_free(fibctx);
+ /* FIB should be freed only after getting the response from the F/W */
+ if (status != -ERESTARTSYS)
+ aac_fib_free(fibctx);
return status;
}
@@ -304,6 +306,8 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
/*
* Check the preferred comm settings, defaults from template.
*/
+ dev->management_fib_count = 0;
+ spin_lock_init(&dev->manage_lock);
dev->max_fib_size = sizeof(struct hw_fib);
dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size
- sizeof(struct aac_fibhdr)
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 956261f25181..94d2954d79ae 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -189,7 +189,14 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
void aac_fib_free(struct fib *fibptr)
{
- unsigned long flags;
+ unsigned long flags, flagsv;
+
+ spin_lock_irqsave(&fibptr->event_lock, flagsv);
+ if (fibptr->done == 2) {
+ spin_unlock_irqrestore(&fibptr->event_lock, flagsv);
+ return;
+ }
+ spin_unlock_irqrestore(&fibptr->event_lock, flagsv);
spin_lock_irqsave(&fibptr->dev->fib_lock, flags);
if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
@@ -390,6 +397,8 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
struct hw_fib * hw_fib = fibptr->hw_fib_va;
unsigned long flags = 0;
unsigned long qflags;
+ unsigned long mflags = 0;
+
if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
return -EBUSY;
@@ -471,9 +480,31 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
if (!dev->queues)
return -EBUSY;
- if(wait)
+ if (wait) {
+
+ spin_lock_irqsave(&dev->manage_lock, mflags);
+ if (dev->management_fib_count >= AAC_NUM_MGT_FIB) {
+ printk(KERN_INFO "No management Fibs Available:%d\n",
+ dev->management_fib_count);
+ spin_unlock_irqrestore(&dev->manage_lock, mflags);
+ return -EBUSY;
+ }
+ dev->management_fib_count++;
+ spin_unlock_irqrestore(&dev->manage_lock, mflags);
spin_lock_irqsave(&fibptr->event_lock, flags);
- aac_adapter_deliver(fibptr);
+ }
+
+ if (aac_adapter_deliver(fibptr) != 0) {
+ printk(KERN_ERR "aac_fib_send: returned -EBUSY\n");
+ if (wait) {
+ spin_unlock_irqrestore(&fibptr->event_lock, flags);
+ spin_lock_irqsave(&dev->manage_lock, mflags);
+ dev->management_fib_count--;
+ spin_unlock_irqrestore(&dev->manage_lock, mflags);
+ }
+ return -EBUSY;
+ }
+
/*
* If the caller wanted us to wait for response wait now.
@@ -516,14 +547,15 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
udelay(5);
}
} else if (down_interruptible(&fibptr->event_wait)) {
- fibptr->done = 2;
- up(&fibptr->event_wait);
+ /* Do nothing ... satisfy
+ * down_interruptible must_check */
}
+
spin_lock_irqsave(&fibptr->event_lock, flags);
- if ((fibptr->done == 0) || (fibptr->done == 2)) {
+ if (fibptr->done == 0) {
fibptr->done = 2; /* Tell interrupt we aborted */
spin_unlock_irqrestore(&fibptr->event_lock, flags);
- return -EINTR;
+ return -ERESTARTSYS;
}
spin_unlock_irqrestore(&fibptr->event_lock, flags);
BUG_ON(fibptr->done == 0);
@@ -689,6 +721,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
int aac_fib_complete(struct fib *fibptr)
{
+ unsigned long flags;
struct hw_fib * hw_fib = fibptr->hw_fib_va;
/*
@@ -709,6 +742,13 @@ int aac_fib_complete(struct fib *fibptr)
* command is complete that we had sent to the adapter and this
* cdb could be reused.
*/
+ spin_lock_irqsave(&fibptr->event_lock, flags);
+ if (fibptr->done == 2) {
+ spin_unlock_irqrestore(&fibptr->event_lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&fibptr->event_lock, flags);
+
if((hw_fib->header.XferState & cpu_to_le32(SentFromHost)) &&
(hw_fib->header.XferState & cpu_to_le32(AdapterProcessed)))
{
@@ -1355,7 +1395,10 @@ int aac_reset_adapter(struct aac_dev * aac, int forced)
if (status >= 0)
aac_fib_complete(fibctx);
- aac_fib_free(fibctx);
+ /* FIB should be freed only after getting
+ * the response from the F/W */
+ if (status != -ERESTARTSYS)
+ aac_fib_free(fibctx);
}
}
@@ -1759,6 +1802,7 @@ int aac_command_thread(void *data)
struct fib *fibptr;
if ((fibptr = aac_fib_alloc(dev))) {
+ int status;
__le32 *info;
aac_fib_init(fibptr);
@@ -1769,15 +1813,21 @@ int aac_command_thread(void *data)
*info = cpu_to_le32(now.tv_sec);
- (void)aac_fib_send(SendHostTime,
+ status = aac_fib_send(SendHostTime,
fibptr,
sizeof(*info),
FsaNormal,
1, 1,
NULL,
NULL);
- aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
+ /* Do not set XferState to zero unless
+ * receives a response from F/W */
+ if (status >= 0)
+ aac_fib_complete(fibptr);
+ /* FIB should be freed only after
+ * getting the response from the F/W */
+ if (status != -ERESTARTSYS)
+ aac_fib_free(fibptr);
}
difference = (long)(unsigned)update_interval*HZ;
} else {
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index abc9ef5d1b10..9c7408fe8c7d 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -57,9 +57,9 @@ unsigned int aac_response_normal(struct aac_queue * q)
struct hw_fib * hwfib;
struct fib * fib;
int consumed = 0;
- unsigned long flags;
+ unsigned long flags, mflags;
- spin_lock_irqsave(q->lock, flags);
+ spin_lock_irqsave(q->lock, flags);
/*
* Keep pulling response QEs off the response queue and waking
* up the waiters until there are no more QEs. We then return
@@ -125,12 +125,21 @@ unsigned int aac_response_normal(struct aac_queue * q)
} else {
unsigned long flagv;
spin_lock_irqsave(&fib->event_lock, flagv);
- if (!fib->done)
+ if (!fib->done) {
fib->done = 1;
- up(&fib->event_wait);
+ up(&fib->event_wait);
+ }
spin_unlock_irqrestore(&fib->event_lock, flagv);
+
+ spin_lock_irqsave(&dev->manage_lock, mflags);
+ dev->management_fib_count--;
+ spin_unlock_irqrestore(&dev->manage_lock, mflags);
+
FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
if (fib->done == 2) {
+ spin_lock_irqsave(&fib->event_lock, flagv);
+ fib->done = 0;
+ spin_unlock_irqrestore(&fib->event_lock, flagv);
aac_fib_complete(fib);
aac_fib_free(fib);
}
@@ -232,6 +241,7 @@ unsigned int aac_command_normal(struct aac_queue *q)
unsigned int aac_intr_normal(struct aac_dev * dev, u32 index)
{
+ unsigned long mflags;
dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index));
if ((index & 0x00000002L)) {
struct hw_fib * hw_fib;
@@ -320,11 +330,25 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 index)
unsigned long flagv;
dprintk((KERN_INFO "event_wait up\n"));
spin_lock_irqsave(&fib->event_lock, flagv);
- if (!fib->done)
+ if (!fib->done) {
fib->done = 1;
- up(&fib->event_wait);
+ up(&fib->event_wait);
+ }
spin_unlock_irqrestore(&fib->event_lock, flagv);
+
+ spin_lock_irqsave(&dev->manage_lock, mflags);
+ dev->management_fib_count--;
+ spin_unlock_irqrestore(&dev->manage_lock, mflags);
+
FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
+ if (fib->done == 2) {
+ spin_lock_irqsave(&fib->event_lock, flagv);
+ fib->done = 0;
+ spin_unlock_irqrestore(&fib->event_lock, flagv);
+ aac_fib_complete(fib);
+ aac_fib_free(fib);
+ }
+
}
return 0;
}
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 4d419c155ce9..78971db5b60e 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -3171,13 +3171,16 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
tinfo->curr.transport_version = 2;
tinfo->goal.transport_version = 2;
tinfo->goal.ppr_options = 0;
- /*
- * Remove any SCBs in the waiting for selection
- * queue that may also be for this target so
- * that command ordering is preserved.
- */
- ahd_freeze_devq(ahd, scb);
- ahd_qinfifo_requeue_tail(ahd, scb);
+ if (scb != NULL) {
+ /*
+ * Remove any SCBs in the waiting
+ * for selection queue that may
+ * also be for this target so that
+ * command ordering is preserved.
+ */
+ ahd_freeze_devq(ahd, scb);
+ ahd_qinfifo_requeue_tail(ahd, scb);
+ }
printerror = 0;
}
} else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE)
@@ -3194,13 +3197,16 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
MSG_EXT_WDTR_BUS_8_BIT,
AHD_TRANS_CUR|AHD_TRANS_GOAL,
/*paused*/TRUE);
- /*
- * Remove any SCBs in the waiting for selection
- * queue that may also be for this target so that
- * command ordering is preserved.
- */
- ahd_freeze_devq(ahd, scb);
- ahd_qinfifo_requeue_tail(ahd, scb);
+ if (scb != NULL) {
+ /*
+ * Remove any SCBs in the waiting for
+ * selection queue that may also be for
+ * this target so that command ordering
+ * is preserved.
+ */
+ ahd_freeze_devq(ahd, scb);
+ ahd_qinfifo_requeue_tail(ahd, scb);
+ }
printerror = 0;
} else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE)
&& ppr_busfree == 0) {
@@ -3217,13 +3223,16 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
/*ppr_options*/0,
AHD_TRANS_CUR|AHD_TRANS_GOAL,
/*paused*/TRUE);
- /*
- * Remove any SCBs in the waiting for selection
- * queue that may also be for this target so that
- * command ordering is preserved.
- */
- ahd_freeze_devq(ahd, scb);
- ahd_qinfifo_requeue_tail(ahd, scb);
+ if (scb != NULL) {
+ /*
+ * Remove any SCBs in the waiting for
+ * selection queue that may also be for
+ * this target so that command ordering
+ * is preserved.
+ */
+ ahd_freeze_devq(ahd, scb);
+ ahd_qinfifo_requeue_tail(ahd, scb);
+ }
printerror = 0;
} else if ((ahd->msg_flags & MSG_FLAG_EXPECT_IDE_BUSFREE) != 0
&& ahd_sent_msg(ahd, AHDMSG_1B,
@@ -3251,7 +3260,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
* the message phases. We check it last in case we
* had to send some other message that caused a busfree.
*/
- if (printerror != 0
+ if (scb != NULL && printerror != 0
&& (lastphase == P_MESGIN || lastphase == P_MESGOUT)
&& ((ahd->msg_flags & MSG_FLAG_EXPECT_PPR_BUSFREE) != 0)) {
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 477542602284..9e71ac611146 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -2516,7 +2516,7 @@ int fas216_eh_device_reset(struct scsi_cmnd *SCpnt)
if (info->scsi.phase == PHASE_IDLE)
fas216_kick(info);
- mod_timer(&info->eh_timer, 30 * HZ);
+ mod_timer(&info->eh_timer, jiffies + 30 * HZ);
spin_unlock_irqrestore(&info->host_lock, flags);
/*
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index a93a5040f087..136b49cea791 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -24,6 +24,10 @@
#define FW_VER_LEN 32
#define MCC_Q_LEN 128
#define MCC_CQ_LEN 256
+#define MAX_MCC_CMD 16
+/* BladeEngine Generation numbers */
+#define BE_GEN2 2
+#define BE_GEN3 3
struct be_dma_mem {
void *va;
@@ -57,6 +61,11 @@ static inline void *queue_head_node(struct be_queue_info *q)
return q->dma_mem.va + q->head * q->entry_size;
}
+static inline void *queue_get_wrb(struct be_queue_info *q, unsigned int wrb_num)
+{
+ return q->dma_mem.va + wrb_num * q->entry_size;
+}
+
static inline void *queue_tail_node(struct be_queue_info *q)
{
return q->dma_mem.va + q->tail * q->entry_size;
@@ -104,15 +113,19 @@ struct be_ctrl_info {
spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */
spinlock_t mcc_cq_lock;
- /* MCC Async callback */
- void (*async_cb) (void *adapter, bool link_up);
- void *adapter_ctxt;
+ wait_queue_head_t mcc_wait[MAX_MCC_CMD + 1];
+ unsigned int mcc_tag[MAX_MCC_CMD];
+ unsigned int mcc_numtag[MAX_MCC_CMD + 1];
+ unsigned short mcc_alloc_index;
+ unsigned short mcc_free_index;
+ unsigned int mcc_tag_available;
};
#include "be_cmds.h"
#define PAGE_SHIFT_4K 12
#define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K)
+#define mcc_timeout 120000 /* 5s timeout */
/* Returns number of pages spanned by the data starting at the given addr */
#define PAGES_4K_SPANNED(_address, size) \
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index f008708f1b08..67098578fba4 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -19,7 +19,7 @@
#include "be_mgmt.h"
#include "be_main.h"
-static void be_mcc_notify(struct beiscsi_hba *phba)
+void be_mcc_notify(struct beiscsi_hba *phba)
{
struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
u32 val = 0;
@@ -29,6 +29,52 @@ static void be_mcc_notify(struct beiscsi_hba *phba)
iowrite32(val, phba->db_va + DB_MCCQ_OFFSET);
}
+unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
+{
+ unsigned int tag = 0;
+ unsigned int num = 0;
+
+mcc_tag_rdy:
+ if (phba->ctrl.mcc_tag_available) {
+ tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index];
+ phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0;
+ phba->ctrl.mcc_numtag[tag] = 0;
+ } else {
+ udelay(100);
+ num++;
+ if (num < mcc_timeout)
+ goto mcc_tag_rdy;
+ }
+ if (tag) {
+ phba->ctrl.mcc_tag_available--;
+ if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1))
+ phba->ctrl.mcc_alloc_index = 0;
+ else
+ phba->ctrl.mcc_alloc_index++;
+ }
+ return tag;
+}
+
+void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag)
+{
+ spin_lock(&ctrl->mbox_lock);
+ tag = tag & 0x000000FF;
+ ctrl->mcc_tag[ctrl->mcc_free_index] = tag;
+ if (ctrl->mcc_free_index == (MAX_MCC_CMD - 1))
+ ctrl->mcc_free_index = 0;
+ else
+ ctrl->mcc_free_index++;
+ ctrl->mcc_tag_available++;
+ spin_unlock(&ctrl->mbox_lock);
+}
+
+bool is_link_state_evt(u32 trailer)
+{
+ return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
+ ASYNC_TRAILER_EVENT_CODE_MASK) ==
+ ASYNC_EVENT_CODE_LINK_STATE);
+}
+
static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl)
{
if (compl->flags != 0) {
@@ -64,12 +110,30 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
return 0;
}
-
-static inline bool is_link_state_evt(u32 trailer)
+int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl,
+ struct be_mcc_compl *compl)
{
- return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
- ASYNC_TRAILER_EVENT_CODE_MASK) ==
- ASYNC_EVENT_CODE_LINK_STATE);
+ u16 compl_status, extd_status;
+ unsigned short tag;
+
+ be_dws_le_to_cpu(compl, 4);
+
+ compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
+ CQE_STATUS_COMPL_MASK;
+ /* The ctrl.mcc_numtag[tag] is filled with
+ * [31] = valid, [30:24] = Rsvd, [23:16] = wrb, [15:8] = extd_status,
+ * [7:0] = compl_status
+ */
+ tag = (compl->tag0 & 0x000000FF);
+ extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
+ CQE_STATUS_EXTD_MASK;
+
+ ctrl->mcc_numtag[tag] = 0x80000000;
+ ctrl->mcc_numtag[tag] |= (compl->tag0 & 0x00FF0000);
+ ctrl->mcc_numtag[tag] |= (extd_status & 0x000000FF) << 8;
+ ctrl->mcc_numtag[tag] |= (compl_status & 0x000000FF);
+ wake_up_interruptible(&ctrl->mcc_wait[tag]);
+ return 0;
}
static struct be_mcc_compl *be_mcc_compl_get(struct beiscsi_hba *phba)
@@ -89,7 +153,7 @@ static void be2iscsi_fail_session(struct iscsi_cls_session *cls_session)
iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
}
-static void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
+void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
struct be_async_event_link_state *evt)
{
switch (evt->port_link_status) {
@@ -97,13 +161,13 @@ static void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d \n",
evt->physical_port);
phba->state |= BE_ADAPTER_LINK_DOWN;
+ iscsi_host_for_each_session(phba->shost,
+ be2iscsi_fail_session);
break;
case ASYNC_EVENT_LINK_UP:
phba->state = BE_ADAPTER_UP;
SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d \n",
evt->physical_port);
- iscsi_host_for_each_session(phba->shost,
- be2iscsi_fail_session);
break;
default:
SE_DEBUG(DBG_LVL_1, "Unexpected Async Notification %d on"
@@ -162,7 +226,6 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba)
/* Wait till no more pending mcc requests are present */
static int be_mcc_wait_compl(struct beiscsi_hba *phba)
{
-#define mcc_timeout 120000 /* 5s timeout */
int i, status;
for (i = 0; i < mcc_timeout; i++) {
status = beiscsi_process_mcc(phba);
@@ -372,9 +435,10 @@ struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba)
BUG_ON(atomic_read(&mccq->used) >= mccq->len);
wrb = queue_head_node(mccq);
+ memset(wrb, 0, sizeof(*wrb));
+ wrb->tag0 = (mccq->head & 0x000000FF) << 16;
queue_head_inc(mccq);
atomic_inc(&mccq->used);
- memset(wrb, 0, sizeof(*wrb));
return wrb;
}
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index 5de8acb924cb..49fcc787ee8b 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -425,14 +425,20 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
int be_poll_mcc(struct be_ctrl_info *ctrl);
unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba);
-int be_cmd_get_mac_addr(struct beiscsi_hba *phba, u8 *mac_addr);
-
+unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba);
+void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag);
/*ISCSI Functuions */
int be_cmd_fw_initialize(struct be_ctrl_info *ctrl);
struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem);
struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba);
int be_mcc_notify_wait(struct beiscsi_hba *phba);
+void be_mcc_notify(struct beiscsi_hba *phba);
+unsigned int alloc_mcc_tag(struct beiscsi_hba *phba);
+void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
+ struct be_async_event_link_state *evt);
+int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl,
+ struct be_mcc_compl *compl);
int be_mbox_notify(struct be_ctrl_info *ctrl);
@@ -448,6 +454,8 @@ int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl,
int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
struct be_queue_info *wrbq);
+bool is_link_state_evt(u32 trailer);
+
struct be_default_pdu_context {
u32 dw[4];
} __packed;
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index d587b0362f18..29a3aaf35f9f 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -101,6 +101,7 @@ void beiscsi_session_destroy(struct iscsi_cls_session *cls_session)
struct iscsi_session *sess = cls_session->dd_data;
struct beiscsi_session *beiscsi_sess = sess->dd_data;
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_session_destroy\n");
pci_pool_destroy(beiscsi_sess->bhs_pool);
iscsi_session_teardown(cls_session);
}
@@ -224,6 +225,7 @@ int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
struct beiscsi_conn *beiscsi_conn = conn->dd_data;
int len = 0;
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_param, param= %d\n", param);
beiscsi_ep = beiscsi_conn->ep;
if (!beiscsi_ep) {
SE_DEBUG(DBG_LVL_1,
@@ -254,6 +256,7 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
struct iscsi_session *session = conn->session;
int ret;
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_set_param, param= %d\n", param);
ret = iscsi_set_param(cls_conn, param, buf, buflen);
if (ret)
return ret;
@@ -271,8 +274,8 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
conn->max_recv_dlength = 65536;
break;
case ISCSI_PARAM_MAX_BURST:
- if (session->first_burst > 262144)
- session->first_burst = 262144;
+ if (session->max_burst > 262144)
+ session->max_burst = 262144;
break;
default:
return 0;
@@ -293,12 +296,41 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
enum iscsi_host_param param, char *buf)
{
struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost);
+ struct be_cmd_resp_get_mac_addr *resp;
+ struct be_mcc_wrb *wrb;
+ unsigned int tag, wrb_num;
int len = 0;
+ unsigned short status, extd_status;
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_get_host_param, param= %d\n", param);
switch (param) {
case ISCSI_HOST_PARAM_HWADDRESS:
- be_cmd_get_mac_addr(phba, phba->mac_address);
- len = sysfs_format_mac(buf, phba->mac_address, ETH_ALEN);
+ tag = be_cmd_get_mac_addr(phba);
+ if (!tag) {
+ SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed \n");
+ return -1;
+ } else
+ wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_numtag[tag]);
+
+ wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
+ extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
+ status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+ if (status || extd_status) {
+ SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed"
+ " status = %d extd_status = %d \n",
+ status, extd_status);
+ free_mcc_tag(&phba->ctrl, tag);
+ return -1;
+ } else {
+ wrb = queue_get_wrb(mccq, wrb_num);
+ free_mcc_tag(&phba->ctrl, tag);
+ resp = embedded_payload(wrb);
+ memcpy(phba->mac_address, resp->mac_address, ETH_ALEN);
+ len = sysfs_format_mac(buf, phba->mac_address,
+ ETH_ALEN);
+ }
break;
default:
return iscsi_host_get_param(shost, param, buf);
@@ -378,6 +410,7 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn)
struct beiscsi_endpoint *beiscsi_ep;
struct beiscsi_offload_params params;
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_start\n");
memset(&params, 0, sizeof(struct beiscsi_offload_params));
beiscsi_ep = beiscsi_conn->ep;
if (!beiscsi_ep)
@@ -422,8 +455,14 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
{
struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
struct beiscsi_hba *phba = beiscsi_ep->phba;
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+ struct be_mcc_wrb *wrb;
+ struct tcp_connect_and_offload_out *ptcpcnct_out;
+ unsigned short status, extd_status;
+ unsigned int tag, wrb_num;
int ret = -1;
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn\n");
beiscsi_ep->ep_cid = beiscsi_get_cid(phba);
if (beiscsi_ep->ep_cid == 0xFFFF) {
SE_DEBUG(DBG_LVL_1, "No free cid available\n");
@@ -431,15 +470,44 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
}
SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d ",
beiscsi_ep->ep_cid);
- phba->ep_array[beiscsi_ep->ep_cid] = ep;
- if (beiscsi_ep->ep_cid >
- (phba->fw_config.iscsi_cid_start + phba->params.cxns_per_ctrl)) {
+ phba->ep_array[beiscsi_ep->ep_cid -
+ phba->fw_config.iscsi_cid_start] = ep;
+ if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start +
+ phba->params.cxns_per_ctrl * 2)) {
SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
return ret;
}
beiscsi_ep->cid_vld = 0;
- return mgmt_open_connection(phba, dst_addr, beiscsi_ep);
+ tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep);
+ if (!tag) {
+ SE_DEBUG(DBG_LVL_1,
+ "mgmt_invalidate_connection Failed for cid=%d \n",
+ beiscsi_ep->ep_cid);
+ } else {
+ wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_numtag[tag]);
+ }
+ wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
+ extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
+ status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+ if (status || extd_status) {
+ SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed"
+ " status = %d extd_status = %d \n",
+ status, extd_status);
+ free_mcc_tag(&phba->ctrl, tag);
+ return -1;
+ } else {
+ wrb = queue_get_wrb(mccq, wrb_num);
+ free_mcc_tag(&phba->ctrl, tag);
+
+ ptcpcnct_out = embedded_payload(wrb);
+ beiscsi_ep = ep->dd_data;
+ beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle;
+ beiscsi_ep->cid_vld = 1;
+ SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n");
+ }
+ return 0;
}
/**
@@ -459,14 +527,12 @@ static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid)
* beiscsi_free_ep - free endpoint
* @ep: pointer to iscsi endpoint structure
*/
-static void beiscsi_free_ep(struct iscsi_endpoint *ep)
+static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep)
{
- struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
struct beiscsi_hba *phba = beiscsi_ep->phba;
beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
beiscsi_ep->phba = NULL;
- iscsi_destroy_endpoint(ep);
}
/**
@@ -495,9 +561,9 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
return ERR_PTR(ret);
}
- if (phba->state) {
+ if (phba->state != BE_ADAPTER_UP) {
ret = -EBUSY;
- SE_DEBUG(DBG_LVL_1, "The Adapet state is Not UP \n");
+ SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP \n");
return ERR_PTR(ret);
}
@@ -509,9 +575,9 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
beiscsi_ep = ep->dd_data;
beiscsi_ep->phba = phba;
-
+ beiscsi_ep->openiscsi_ep = ep;
if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) {
- SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
+ SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn \n");
ret = -ENOMEM;
goto free_ep;
}
@@ -519,7 +585,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
return ep;
free_ep:
- beiscsi_free_ep(ep);
+ beiscsi_free_ep(beiscsi_ep);
return ERR_PTR(ret);
}
@@ -546,20 +612,22 @@ int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
* @ep: The iscsi endpoint
* @flag: The type of connection closure
*/
-static int beiscsi_close_conn(struct iscsi_endpoint *ep, int flag)
+static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag)
{
int ret = 0;
- struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
+ unsigned int tag;
struct beiscsi_hba *phba = beiscsi_ep->phba;
- if (MGMT_STATUS_SUCCESS !=
- mgmt_upload_connection(phba, beiscsi_ep->ep_cid,
- CONNECTION_UPLOAD_GRACEFUL)) {
+ tag = mgmt_upload_connection(phba, beiscsi_ep->ep_cid, flag);
+ if (!tag) {
SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x",
beiscsi_ep->ep_cid);
ret = -1;
+ } else {
+ wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_numtag[tag]);
+ free_mcc_tag(&phba->ctrl, tag);
}
-
return ret;
}
@@ -574,19 +642,17 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
struct beiscsi_conn *beiscsi_conn;
struct beiscsi_endpoint *beiscsi_ep;
struct beiscsi_hba *phba;
- int flag = 0;
beiscsi_ep = ep->dd_data;
phba = beiscsi_ep->phba;
- SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect\n");
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n",
+ beiscsi_ep->ep_cid);
if (beiscsi_ep->conn) {
beiscsi_conn = beiscsi_ep->conn;
iscsi_suspend_queue(beiscsi_conn->conn);
- beiscsi_close_conn(ep, flag);
}
- beiscsi_free_ep(ep);
}
/**
@@ -619,23 +685,31 @@ void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
struct iscsi_session *session = conn->session;
struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
struct beiscsi_hba *phba = iscsi_host_priv(shost);
- unsigned int status;
+ unsigned int tag;
unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH;
- SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop\n");
beiscsi_ep = beiscsi_conn->ep;
if (!beiscsi_ep) {
SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n");
return;
}
- status = mgmt_invalidate_connection(phba, beiscsi_ep,
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop ep_cid = %d\n",
+ beiscsi_ep->ep_cid);
+ tag = mgmt_invalidate_connection(phba, beiscsi_ep,
beiscsi_ep->ep_cid, 1,
savecfg_flag);
- if (status != MGMT_STATUS_SUCCESS) {
+ if (!tag) {
SE_DEBUG(DBG_LVL_1,
"mgmt_invalidate_connection Failed for cid=%d \n",
beiscsi_ep->ep_cid);
+ } else {
+ wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_numtag[tag]);
+ free_mcc_tag(&phba->ctrl, tag);
}
+ beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL);
+ beiscsi_free_ep(beiscsi_ep);
+ iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
iscsi_conn_stop(cls_conn, flag);
}
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
index f92ffc5349fb..1f512c28cbf9 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.h
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 1a557fa77888..7c22616ab141 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -40,7 +40,6 @@
static unsigned int be_iopoll_budget = 10;
static unsigned int be_max_phys_size = 64;
static unsigned int enable_msix = 1;
-static unsigned int ring_mode;
MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR);
@@ -62,10 +61,10 @@ static int beiscsi_slave_configure(struct scsi_device *sdev)
/*------------------- PCI Driver operations and data ----------------- */
static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = {
{ PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
+ { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) },
{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },
{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID3) },
- { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID4) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
@@ -112,6 +111,7 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev)
memset(phba, 0, sizeof(*phba));
phba->shost = shost;
phba->pcidev = pci_dev_get(pcidev);
+ pci_set_drvdata(pcidev, phba);
if (iscsi_host_add(shost, &phba->pcidev->dev))
goto free_devices;
@@ -143,6 +143,7 @@ static int beiscsi_map_pci_bars(struct beiscsi_hba *phba,
struct pci_dev *pcidev)
{
u8 __iomem *addr;
+ int pcicfg_reg;
addr = ioremap_nocache(pci_resource_start(pcidev, 2),
pci_resource_len(pcidev, 2));
@@ -159,13 +160,19 @@ static int beiscsi_map_pci_bars(struct beiscsi_hba *phba,
phba->db_va = addr;
phba->db_pa.u.a64.address = pci_resource_start(pcidev, 4);
- addr = ioremap_nocache(pci_resource_start(pcidev, 1),
- pci_resource_len(pcidev, 1));
+ if (phba->generation == BE_GEN2)
+ pcicfg_reg = 1;
+ else
+ pcicfg_reg = 0;
+
+ addr = ioremap_nocache(pci_resource_start(pcidev, pcicfg_reg),
+ pci_resource_len(pcidev, pcicfg_reg));
+
if (addr == NULL)
goto pci_map_err;
phba->ctrl.pcicfg = addr;
phba->pci_va = addr;
- phba->pci_pa.u.a64.address = pci_resource_start(pcidev, 1);
+ phba->pci_pa.u.a64.address = pci_resource_start(pcidev, pcicfg_reg);
return 0;
pci_map_err:
@@ -230,29 +237,27 @@ static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev)
static void beiscsi_get_params(struct beiscsi_hba *phba)
{
- phba->params.ios_per_ctrl = BE2_IO_DEPTH;
- phba->params.cxns_per_ctrl = BE2_MAX_SESSIONS;
- phba->params.asyncpdus_per_ctrl = BE2_ASYNCPDUS;
- phba->params.icds_per_ctrl = BE2_MAX_ICDS / 2;
+ phba->params.ios_per_ctrl = (phba->fw_config.iscsi_icd_count
+ - (phba->fw_config.iscsi_cid_count
+ + BE2_TMFS
+ + BE2_NOPOUT_REQ));
+ phba->params.cxns_per_ctrl = phba->fw_config.iscsi_cid_count;
+ phba->params.asyncpdus_per_ctrl = phba->fw_config.iscsi_cid_count;;
+ phba->params.icds_per_ctrl = phba->fw_config.iscsi_icd_count;;
phba->params.num_sge_per_io = BE2_SGE;
phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ;
phba->params.defpdu_data_sz = BE2_DEFPDU_DATA_SZ;
phba->params.eq_timer = 64;
phba->params.num_eq_entries =
- (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) /
- 512) + 1) * 512;
+ (((BE2_CMDS_PER_CXN * 2 + phba->fw_config.iscsi_cid_count * 2
+ + BE2_TMFS) / 512) + 1) * 512;
phba->params.num_eq_entries = (phba->params.num_eq_entries < 1024)
? 1024 : phba->params.num_eq_entries;
SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d \n",
- phba->params.num_eq_entries);
+ phba->params.num_eq_entries);
phba->params.num_cq_entries =
- (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) /
- 512) + 1) * 512;
- SE_DEBUG(DBG_LVL_8,
- "phba->params.num_cq_entries=%d BE2_CMDS_PER_CXN=%d"
- "BE2_LOGOUTS=%d BE2_TMFS=%d BE2_ASYNCPDUS=%d \n",
- phba->params.num_cq_entries, BE2_CMDS_PER_CXN,
- BE2_LOGOUTS, BE2_TMFS, BE2_ASYNCPDUS);
+ (((BE2_CMDS_PER_CXN * 2 + phba->fw_config.iscsi_cid_count * 2
+ + BE2_TMFS) / 512) + 1) * 512;
phba->params.wrbs_per_cxn = 256;
}
@@ -443,7 +448,7 @@ static irqreturn_t be_isr(int irq, void *dev_id)
if (phba->todo_mcc_cq)
queue_work(phba->wq, &phba->work_cqs);
- if ((num_mcceq_processed) && (!num_ioeq_processed))
+ if ((num_mcceq_processed) && (!num_ioeq_processed))
hwi_ring_eq_db(phba, eq->id, 0,
(num_ioeq_processed +
num_mcceq_processed) , 1, 1);
@@ -561,6 +566,7 @@ beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn,
SE_DEBUG(DBG_LVL_1, "In ISCSI_OP_REJECT\n");
break;
case ISCSI_OP_LOGIN_RSP:
+ case ISCSI_OP_TEXT_RSP:
task = conn->login_task;
io_task = task->dd_data;
login_hdr = (struct iscsi_hdr *)ppdu;
@@ -631,29 +637,29 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
* alloc_wrb_handle - To allocate a wrb handle
* @phba: The hba pointer
* @cid: The cid to use for allocation
- * @index: index allocation and wrb index
*
* This happens under session_lock until submission to chip
*/
-struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
- int index)
+struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid)
{
struct hwi_wrb_context *pwrb_context;
struct hwi_controller *phwi_ctrlr;
- struct wrb_handle *pwrb_handle;
+ struct wrb_handle *pwrb_handle, *pwrb_handle_tmp;
phwi_ctrlr = phba->phwi_ctrlr;
pwrb_context = &phwi_ctrlr->wrb_context[cid];
- if (pwrb_context->wrb_handles_available) {
+ if (pwrb_context->wrb_handles_available >= 2) {
pwrb_handle = pwrb_context->pwrb_handle_base[
pwrb_context->alloc_index];
pwrb_context->wrb_handles_available--;
- pwrb_handle->nxt_wrb_index = pwrb_handle->wrb_index;
if (pwrb_context->alloc_index ==
(phba->params.wrbs_per_cxn - 1))
pwrb_context->alloc_index = 0;
else
pwrb_context->alloc_index++;
+ pwrb_handle_tmp = pwrb_context->pwrb_handle_base[
+ pwrb_context->alloc_index];
+ pwrb_handle->nxt_wrb_index = pwrb_handle_tmp->wrb_index;
} else
pwrb_handle = NULL;
return pwrb_handle;
@@ -671,9 +677,7 @@ static void
free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context,
struct wrb_handle *pwrb_handle)
{
- if (!ring_mode)
- pwrb_context->pwrb_handle_base[pwrb_context->free_index] =
- pwrb_handle;
+ pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle;
pwrb_context->wrb_handles_available++;
if (pwrb_context->free_index == (phba->params.wrbs_per_cxn - 1))
pwrb_context->free_index = 0;
@@ -790,6 +794,7 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn,
memcpy(task->sc->sense_buffer, sense,
min_t(u16, sense_len, SCSI_SENSE_BUFFERSIZE));
}
+
if (io_task->cmd_bhs->iscsi_hdr.flags & ISCSI_FLAG_CMD_READ) {
if (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32]
& SOL_RES_CNT_MASK)
@@ -811,6 +816,7 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn,
struct iscsi_conn *conn = beiscsi_conn->conn;
hdr = (struct iscsi_logout_rsp *)task->hdr;
+ hdr->opcode = ISCSI_OP_LOGOUT_RSP;
hdr->t2wait = 5;
hdr->t2retain = 0;
hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
@@ -825,6 +831,9 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn,
& SOL_EXP_CMD_SN_MASK) +
((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
/ 32] & SOL_CMD_WND_MASK) >> 24) - 1);
+ hdr->dlength[0] = 0;
+ hdr->dlength[1] = 0;
+ hdr->dlength[2] = 0;
hdr->hlength = 0;
hdr->itt = io_task->libiscsi_itt;
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
@@ -839,6 +848,7 @@ be_complete_tmf(struct beiscsi_conn *beiscsi_conn,
struct beiscsi_io_task *io_task = task->dd_data;
hdr = (struct iscsi_tm_rsp *)task->hdr;
+ hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP;
hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
& SOL_FLAGS_MASK) >> 24) | 0x80;
hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) /
@@ -859,7 +869,6 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
{
struct hwi_wrb_context *pwrb_context;
struct wrb_handle *pwrb_handle = NULL;
- struct sgl_handle *psgl_handle = NULL;
struct hwi_controller *phwi_ctrlr;
struct iscsi_task *task;
struct beiscsi_io_task *io_task;
@@ -867,22 +876,14 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
struct iscsi_session *session = conn->session;
phwi_ctrlr = phba->phwi_ctrlr;
- if (ring_mode) {
- psgl_handle = phba->sgl_hndl_array[((psol->
- dw[offsetof(struct amap_sol_cqe_ring, icd_index) /
- 32] & SOL_ICD_INDEX_MASK) >> 6)];
- pwrb_context = &phwi_ctrlr->wrb_context[psgl_handle->cid];
- task = psgl_handle->task;
- pwrb_handle = NULL;
- } else {
- pwrb_context = &phwi_ctrlr->wrb_context[((psol->
+ pwrb_context = &phwi_ctrlr->wrb_context[((psol->
dw[offsetof(struct amap_sol_cqe, cid) / 32] &
- SOL_CID_MASK) >> 6)];
- pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
+ SOL_CID_MASK) >> 6) -
+ phba->fw_config.iscsi_cid_start];
+ pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
dw[offsetof(struct amap_sol_cqe, wrb_index) /
32] & SOL_WRB_INDEX_MASK) >> 16)];
- task = pwrb_handle->pio_handle;
- }
+ task = pwrb_handle->pio_handle;
io_task = task->dd_data;
spin_lock(&phba->mgmt_sgl_lock);
@@ -923,31 +924,23 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
struct iscsi_wrb *pwrb = NULL;
struct hwi_controller *phwi_ctrlr;
struct iscsi_task *task;
- struct sgl_handle *psgl_handle = NULL;
unsigned int type;
struct iscsi_conn *conn = beiscsi_conn->conn;
struct iscsi_session *session = conn->session;
phwi_ctrlr = phba->phwi_ctrlr;
- if (ring_mode) {
- psgl_handle = phba->sgl_hndl_array[((psol->
- dw[offsetof(struct amap_sol_cqe_ring, icd_index) /
- 32] & SOL_ICD_INDEX_MASK) >> 6)];
- task = psgl_handle->task;
- type = psgl_handle->type;
- } else {
- pwrb_context = &phwi_ctrlr->
- wrb_context[((psol->dw[offsetof
+ pwrb_context = &phwi_ctrlr->wrb_context[((psol->dw[offsetof
(struct amap_sol_cqe, cid) / 32]
- & SOL_CID_MASK) >> 6)];
- pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
+ & SOL_CID_MASK) >> 6) -
+ phba->fw_config.iscsi_cid_start];
+ pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
dw[offsetof(struct amap_sol_cqe, wrb_index) /
32] & SOL_WRB_INDEX_MASK) >> 16)];
- task = pwrb_handle->pio_handle;
- pwrb = pwrb_handle->pwrb;
- type = (pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] &
- WRB_TYPE_MASK) >> 28;
- }
+ task = pwrb_handle->pio_handle;
+ pwrb = pwrb_handle->pwrb;
+ type = (pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] &
+ WRB_TYPE_MASK) >> 28;
+
spin_lock_bh(&session->lock);
switch (type) {
case HWH_TYPE_IO:
@@ -978,15 +971,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
break;
default:
- if (ring_mode)
- shost_printk(KERN_WARNING, phba->shost,
- "In hwi_complete_cmd, unknown type = %d"
- "icd_index 0x%x CID 0x%x\n", type,
- ((psol->dw[offsetof(struct amap_sol_cqe_ring,
- icd_index) / 32] & SOL_ICD_INDEX_MASK) >> 6),
- psgl_handle->cid);
- else
- shost_printk(KERN_WARNING, phba->shost,
+ shost_printk(KERN_WARNING, phba->shost,
"In hwi_complete_cmd, unknown type = %d"
"wrb_index 0x%x CID 0x%x\n", type,
((psol->dw[offsetof(struct amap_iscsi_wrb,
@@ -1077,7 +1062,8 @@ hwi_get_async_handle(struct beiscsi_hba *phba,
WARN_ON(!pasync_handle);
- pasync_handle->cri = (unsigned short)beiscsi_conn->beiscsi_conn_cid;
+ pasync_handle->cri = (unsigned short)beiscsi_conn->beiscsi_conn_cid -
+ phba->fw_config.iscsi_cid_start;
pasync_handle->is_header = is_header;
pasync_handle->buffer_len = ((pdpdu_cqe->
dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32]
@@ -1327,9 +1313,10 @@ hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn,
}
status = beiscsi_process_async_pdu(beiscsi_conn, phba,
- beiscsi_conn->beiscsi_conn_cid,
- phdr, hdr_len, pfirst_buffer,
- buf_len);
+ (beiscsi_conn->beiscsi_conn_cid -
+ phba->fw_config.iscsi_cid_start),
+ phdr, hdr_len, pfirst_buffer,
+ buf_len);
if (status == 0)
hwi_free_async_msg(phba, cri);
@@ -1422,6 +1409,48 @@ static void hwi_process_default_pdu_ring(struct beiscsi_conn *beiscsi_conn,
hwi_post_async_buffers(phba, pasync_handle->is_header);
}
+static void beiscsi_process_mcc_isr(struct beiscsi_hba *phba)
+{
+ struct be_queue_info *mcc_cq;
+ struct be_mcc_compl *mcc_compl;
+ unsigned int num_processed = 0;
+
+ mcc_cq = &phba->ctrl.mcc_obj.cq;
+ mcc_compl = queue_tail_node(mcc_cq);
+ mcc_compl->flags = le32_to_cpu(mcc_compl->flags);
+ while (mcc_compl->flags & CQE_FLAGS_VALID_MASK) {
+
+ if (num_processed >= 32) {
+ hwi_ring_cq_db(phba, mcc_cq->id,
+ num_processed, 0, 0);
+ num_processed = 0;
+ }
+ if (mcc_compl->flags & CQE_FLAGS_ASYNC_MASK) {
+ /* Interpret flags as an async trailer */
+ if (is_link_state_evt(mcc_compl->flags))
+ /* Interpret compl as a async link evt */
+ beiscsi_async_link_state_process(phba,
+ (struct be_async_event_link_state *) mcc_compl);
+ else
+ SE_DEBUG(DBG_LVL_1,
+ " Unsupported Async Event, flags"
+ " = 0x%08x \n", mcc_compl->flags);
+ } else if (mcc_compl->flags & CQE_FLAGS_COMPLETED_MASK) {
+ be_mcc_compl_process_isr(&phba->ctrl, mcc_compl);
+ atomic_dec(&phba->ctrl.mcc_obj.q.used);
+ }
+
+ mcc_compl->flags = 0;
+ queue_tail_inc(mcc_cq);
+ mcc_compl = queue_tail_node(mcc_cq);
+ mcc_compl->flags = le32_to_cpu(mcc_compl->flags);
+ num_processed++;
+ }
+
+ if (num_processed > 0)
+ hwi_ring_cq_db(phba, mcc_cq->id, num_processed, 1, 0);
+
+}
static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
{
@@ -1431,7 +1460,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
unsigned int num_processed = 0;
unsigned int tot_nump = 0;
struct beiscsi_conn *beiscsi_conn;
- struct sgl_handle *psgl_handle = NULL;
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct iscsi_endpoint *ep;
struct beiscsi_hba *phba;
cq = pbe_eq->cq;
@@ -1442,32 +1472,13 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
CQE_VALID_MASK) {
be_dws_le_to_cpu(sol, sizeof(struct sol_cqe));
- if (ring_mode) {
- psgl_handle = phba->sgl_hndl_array[((sol->
- dw[offsetof(struct amap_sol_cqe_ring,
- icd_index) / 32] & SOL_ICD_INDEX_MASK)
- >> 6)];
- beiscsi_conn = phba->conn_table[psgl_handle->cid];
- if (!beiscsi_conn || !beiscsi_conn->ep) {
- shost_printk(KERN_WARNING, phba->shost,
- "Connection table empty for cid = %d\n",
- psgl_handle->cid);
- return 0;
- }
+ ep = phba->ep_array[(u32) ((sol->
+ dw[offsetof(struct amap_sol_cqe, cid) / 32] &
+ SOL_CID_MASK) >> 6) -
+ phba->fw_config.iscsi_cid_start];
- } else {
- beiscsi_conn = phba->conn_table[(u32) (sol->
- dw[offsetof(struct amap_sol_cqe, cid) / 32] &
- SOL_CID_MASK) >> 6];
-
- if (!beiscsi_conn || !beiscsi_conn->ep) {
- shost_printk(KERN_WARNING, phba->shost,
- "Connection table empty for cid = %d\n",
- (u32)(sol->dw[offsetof(struct amap_sol_cqe,
- cid) / 32] & SOL_CID_MASK) >> 6);
- return 0;
- }
- }
+ beiscsi_ep = ep->dd_data;
+ beiscsi_conn = beiscsi_ep->conn;
if (num_processed >= 32) {
hwi_ring_cq_db(phba, cq->id,
@@ -1511,21 +1522,13 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
case CMD_CXN_KILLED_ITT_INVALID:
case CMD_CXN_KILLED_SEQ_OUTOFORDER:
case CMD_CXN_KILLED_INVALID_DATASN_RCVD:
- if (ring_mode) {
- SE_DEBUG(DBG_LVL_1,
- "CQ Error notification for cmd.. "
- "code %d cid 0x%x\n",
- sol->dw[offsetof(struct amap_sol_cqe, code) /
- 32] & CQE_CODE_MASK, psgl_handle->cid);
- } else {
- SE_DEBUG(DBG_LVL_1,
+ SE_DEBUG(DBG_LVL_1,
"CQ Error notification for cmd.. "
"code %d cid 0x%x\n",
sol->dw[offsetof(struct amap_sol_cqe, code) /
32] & CQE_CODE_MASK,
(sol->dw[offsetof(struct amap_sol_cqe, cid) /
32] & SOL_CID_MASK));
- }
break;
case UNSOL_DATA_DIGEST_ERROR_NOTIFY:
SE_DEBUG(DBG_LVL_1,
@@ -1547,37 +1550,23 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
case CXN_KILLED_OVER_RUN_RESIDUAL:
case CXN_KILLED_UNDER_RUN_RESIDUAL:
case CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN:
- if (ring_mode) {
- SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID "
- "0x%x...\n",
- sol->dw[offsetof(struct amap_sol_cqe, code) /
- 32] & CQE_CODE_MASK, psgl_handle->cid);
- } else {
- SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID "
+ SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID "
"0x%x...\n",
sol->dw[offsetof(struct amap_sol_cqe, code) /
32] & CQE_CODE_MASK,
- sol->dw[offsetof(struct amap_sol_cqe, cid) /
- 32] & CQE_CID_MASK);
- }
+ (sol->dw[offsetof(struct amap_sol_cqe, cid) /
+ 32] & CQE_CID_MASK));
iscsi_conn_failure(beiscsi_conn->conn,
ISCSI_ERR_CONN_FAILED);
break;
case CXN_KILLED_RST_SENT:
case CXN_KILLED_RST_RCVD:
- if (ring_mode) {
- SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset"
- "received/sent on CID 0x%x...\n",
- sol->dw[offsetof(struct amap_sol_cqe, code) /
- 32] & CQE_CODE_MASK, psgl_handle->cid);
- } else {
- SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset"
+ SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset"
"received/sent on CID 0x%x...\n",
sol->dw[offsetof(struct amap_sol_cqe, code) /
32] & CQE_CODE_MASK,
- sol->dw[offsetof(struct amap_sol_cqe, cid) /
- 32] & CQE_CID_MASK);
- }
+ (sol->dw[offsetof(struct amap_sol_cqe, cid) /
+ 32] & CQE_CID_MASK));
iscsi_conn_failure(beiscsi_conn->conn,
ISCSI_ERR_CONN_FAILED);
break;
@@ -1586,8 +1575,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
"received on CID 0x%x...\n",
sol->dw[offsetof(struct amap_sol_cqe, code) /
32] & CQE_CODE_MASK,
- sol->dw[offsetof(struct amap_sol_cqe, cid) /
- 32] & CQE_CID_MASK);
+ (sol->dw[offsetof(struct amap_sol_cqe, cid) /
+ 32] & CQE_CID_MASK));
break;
}
@@ -1604,7 +1593,7 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
return tot_nump;
}
-static void beiscsi_process_all_cqs(struct work_struct *work)
+void beiscsi_process_all_cqs(struct work_struct *work)
{
unsigned long flags;
struct hwi_controller *phwi_ctrlr;
@@ -1624,6 +1613,7 @@ static void beiscsi_process_all_cqs(struct work_struct *work)
spin_lock_irqsave(&phba->isr_lock, flags);
phba->todo_mcc_cq = 0;
spin_unlock_irqrestore(&phba->isr_lock, flags);
+ beiscsi_process_mcc_isr(phba);
}
if (phba->todo_cq) {
@@ -1668,7 +1658,8 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg,
io_task->bhs_pa.u.a32.address_hi);
l_sg = sg;
- for (index = 0; (index < num_sg) && (index < 2); index++, sg_next(sg)) {
+ for (index = 0; (index < num_sg) && (index < 2); index++,
+ sg = sg_next(sg)) {
if (index == 0) {
sg_len = sg_dma_len(sg);
addr = (u64) sg_dma_address(sg);
@@ -1679,11 +1670,7 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg,
AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb,
sg_len);
sge_len = sg_len;
- AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb,
- 1);
} else {
- AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb,
- 0);
AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_r2t_offset,
pwrb, sge_len);
sg_len = sg_dma_len(sg);
@@ -1706,13 +1693,27 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg,
AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
io_task->bhs_pa.u.a32.address_lo);
- if (num_sg == 2)
- AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, 1);
+ if (num_sg == 1) {
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb,
+ 1);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb,
+ 0);
+ } else if (num_sg == 2) {
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb,
+ 0);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb,
+ 1);
+ } else {
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb,
+ 0);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb,
+ 0);
+ }
sg = l_sg;
psgl++;
psgl++;
offset = 0;
- for (index = 0; index < num_sg; index++, sg_next(sg), psgl++) {
+ for (index = 0; index < num_sg; index++, sg = sg_next(sg), psgl++) {
sg_len = sg_dma_len(sg);
addr = (u64) sg_dma_address(sg);
AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
@@ -2048,10 +2049,9 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
}
idx = 0;
pwrb = mem_descr_wrb->mem_array[idx].virtual_address;
- num_cxn_wrb =
- ((mem_descr_wrb->mem_array[idx].size) / (sizeof(struct iscsi_wrb)) *
- phba->params.wrbs_per_cxn);
-
+ num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) /
+ ((sizeof(struct iscsi_wrb) *
+ phba->params.wrbs_per_cxn));
for (index = 0; index < phba->params.cxns_per_ctrl; index += 2) {
pwrb_context = &phwi_ctrlr->wrb_context[index];
if (num_cxn_wrb) {
@@ -2064,9 +2064,9 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
} else {
idx++;
pwrb = mem_descr_wrb->mem_array[idx].virtual_address;
- num_cxn_wrb = ((mem_descr_wrb->mem_array[idx].size) /
- (sizeof(struct iscsi_wrb)) *
- phba->params.wrbs_per_cxn);
+ num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) /
+ ((sizeof(struct iscsi_wrb) *
+ phba->params.wrbs_per_cxn));
for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
pwrb_handle = pwrb_context->pwrb_handle_base[j];
pwrb_handle->pwrb = pwrb;
@@ -2383,7 +2383,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba,
&paddr);
if (!cq_vaddress)
goto create_cq_error;
- ret = be_fill_queue(cq, phba->params.icds_per_ctrl / 2,
+ ret = be_fill_queue(cq, phba->params.num_cq_entries,
sizeof(struct sol_cqe), cq_vaddress);
if (ret) {
shost_printk(KERN_ERR, phba->shost,
@@ -2634,7 +2634,8 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba,
"wrbq create failed.");
return status;
}
- phwi_ctrlr->wrb_context[i].cid = phwi_context->be_wrbq[i].id;
+ phwi_ctrlr->wrb_context[i * 2].cid = phwi_context->be_wrbq[i].
+ id;
}
kfree(pwrb_arr);
return 0;
@@ -2803,17 +2804,6 @@ static int hwi_init_port(struct beiscsi_hba *phba)
goto error;
}
- if (phba->fw_config.iscsi_features == 0x1)
- ring_mode = 1;
- else
- ring_mode = 0;
- status = mgmt_get_fw_config(ctrl, phba);
- if (status != 0) {
- shost_printk(KERN_ERR, phba->shost,
- "Error getting fw config\n");
- goto error;
- }
-
status = beiscsi_create_cqs(phba, phwi_context);
if (status != 0) {
shost_printk(KERN_ERR, phba->shost, "CQ not created\n");
@@ -2941,17 +2931,6 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba)
phba->io_sgl_hndl_avbl = 0;
phba->eh_sgl_hndl_avbl = 0;
- if (ring_mode) {
- phba->sgl_hndl_array = kzalloc(sizeof(struct sgl_handle *) *
- phba->params.icds_per_ctrl,
- GFP_KERNEL);
- if (!phba->sgl_hndl_array) {
- shost_printk(KERN_ERR, phba->shost,
- "Mem Alloc Failed. Failing to load\n");
- return -ENOMEM;
- }
- }
-
mem_descr_sglh = phba->init_mem;
mem_descr_sglh += HWI_MEM_SGLH;
if (1 == mem_descr_sglh->num_elements) {
@@ -2959,8 +2938,6 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba)
phba->params.ios_per_ctrl,
GFP_KERNEL);
if (!phba->io_sgl_hndl_base) {
- if (ring_mode)
- kfree(phba->sgl_hndl_array);
shost_printk(KERN_ERR, phba->shost,
"Mem Alloc Failed. Failing to load\n");
return -ENOMEM;
@@ -3032,7 +3009,7 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba)
AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, pfrag, 0);
pfrag += phba->params.num_sge_per_io;
psgl_handle->sgl_index =
- phba->fw_config.iscsi_cid_start + arr_index++;
+ phba->fw_config.iscsi_icd_start + arr_index++;
}
idx++;
}
@@ -3047,7 +3024,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba)
{
int i, new_cid;
- phba->cid_array = kmalloc(sizeof(void *) * phba->params.cxns_per_ctrl,
+ phba->cid_array = kzalloc(sizeof(void *) * phba->params.cxns_per_ctrl,
GFP_KERNEL);
if (!phba->cid_array) {
shost_printk(KERN_ERR, phba->shost,
@@ -3055,7 +3032,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba)
"hba_setup_cid_tbls\n");
return -ENOMEM;
}
- phba->ep_array = kmalloc(sizeof(struct iscsi_endpoint *) *
+ phba->ep_array = kzalloc(sizeof(struct iscsi_endpoint *) *
phba->params.cxns_per_ctrl * 2, GFP_KERNEL);
if (!phba->ep_array) {
shost_printk(KERN_ERR, phba->shost,
@@ -3064,7 +3041,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba)
kfree(phba->cid_array);
return -ENOMEM;
}
- new_cid = phba->fw_config.iscsi_icd_start;
+ new_cid = phba->fw_config.iscsi_cid_start;
for (i = 0; i < phba->params.cxns_per_ctrl; i++) {
phba->cid_array[i] = new_cid;
new_cid += 2;
@@ -3145,8 +3122,6 @@ static int beiscsi_init_port(struct beiscsi_hba *phba)
if (hba_setup_cid_tbls(phba)) {
shost_printk(KERN_ERR, phba->shost,
"Failed in hba_setup_cid_tbls\n");
- if (ring_mode)
- kfree(phba->sgl_hndl_array);
kfree(phba->io_sgl_hndl_base);
kfree(phba->eh_sgl_hndl_base);
goto do_cleanup_ctrlr;
@@ -3166,6 +3141,7 @@ static void hwi_purge_eq(struct beiscsi_hba *phba)
struct be_queue_info *eq;
struct be_eq_entry *eqe = NULL;
int i, eq_msix;
+ unsigned int num_processed;
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
@@ -3177,13 +3153,17 @@ static void hwi_purge_eq(struct beiscsi_hba *phba)
for (i = 0; i < (phba->num_cpus + eq_msix); i++) {
eq = &phwi_context->be_eq[i].q;
eqe = queue_tail_node(eq);
-
+ num_processed = 0;
while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
& EQE_VALID_MASK) {
AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
queue_tail_inc(eq);
eqe = queue_tail_node(eq);
+ num_processed++;
}
+
+ if (num_processed)
+ hwi_ring_eq_db(phba, eq->id, 1, num_processed, 1, 1);
}
}
@@ -3195,10 +3175,9 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba)
if (mgmt_status)
shost_printk(KERN_WARNING, phba->shost,
"mgmt_epfw_cleanup FAILED \n");
- hwi_cleanup(phba);
+
hwi_purge_eq(phba);
- if (ring_mode)
- kfree(phba->sgl_hndl_array);
+ hwi_cleanup(phba);
kfree(phba->io_sgl_hndl_base);
kfree(phba->eh_sgl_hndl_base);
kfree(phba->cid_array);
@@ -3219,7 +3198,8 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
* We can always use 0 here because it is reserved by libiscsi for
* login/startup related tasks.
*/
- pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid, 0);
+ pwrb_handle = alloc_wrb_handle(phba, (beiscsi_conn->beiscsi_conn_cid -
+ phba->fw_config.iscsi_cid_start));
pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb;
memset(pwrb, 0, sizeof(*pwrb));
AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
@@ -3283,8 +3263,7 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_target_context_update_wrb));
doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
- if (!ring_mode)
- doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK)
+ doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK)
<< DB_DEF_PDU_WRB_INDEX_SHIFT;
doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
@@ -3328,8 +3307,9 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
io_task->bhs_pa.u.a64.address = paddr;
io_task->libiscsi_itt = (itt_t)task->itt;
io_task->pwrb_handle = alloc_wrb_handle(phba,
- beiscsi_conn->beiscsi_conn_cid,
- task->itt);
+ beiscsi_conn->beiscsi_conn_cid -
+ phba->fw_config.iscsi_cid_start
+ );
io_task->conn = beiscsi_conn;
task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr;
@@ -3343,7 +3323,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
goto free_hndls;
} else {
io_task->scsi_cmnd = NULL;
- if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) {
+ if ((opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) {
if (!beiscsi_conn->login_in_progress) {
spin_lock(&phba->mgmt_sgl_lock);
io_task->psgl_handle = (struct sgl_handle *)
@@ -3370,21 +3350,16 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
itt = (itt_t) cpu_to_be32(((unsigned int)io_task->pwrb_handle->
wrb_index << 16) | (unsigned int)
(io_task->psgl_handle->sgl_index));
- if (ring_mode) {
- phba->sgl_hndl_array[io_task->psgl_handle->sgl_index -
- phba->fw_config.iscsi_cid_start] =
- io_task->psgl_handle;
- io_task->psgl_handle->task = task;
- io_task->psgl_handle->cid = beiscsi_conn->beiscsi_conn_cid;
- } else
- io_task->pwrb_handle->pio_handle = task;
+ io_task->pwrb_handle->pio_handle = task;
io_task->cmd_bhs->iscsi_hdr.itt = itt;
return 0;
free_hndls:
phwi_ctrlr = phba->phwi_ctrlr;
- pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid];
+ pwrb_context = &phwi_ctrlr->wrb_context[
+ beiscsi_conn->beiscsi_conn_cid -
+ phba->fw_config.iscsi_cid_start];
free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle);
io_task->pwrb_handle = NULL;
pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
@@ -3404,7 +3379,8 @@ static void beiscsi_cleanup_task(struct iscsi_task *task)
struct hwi_controller *phwi_ctrlr;
phwi_ctrlr = phba->phwi_ctrlr;
- pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid];
+ pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid
+ - phba->fw_config.iscsi_cid_start];
if (io_task->pwrb_handle) {
free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle);
io_task->pwrb_handle = NULL;
@@ -3460,18 +3436,12 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
ISCSI_OPCODE_SCSI_DATA_OUT);
AMAP_SET_BITS(struct amap_pdu_data_out, final_bit,
&io_task->cmd_bhs->iscsi_data_pdu, 1);
- if (ring_mode)
- io_task->psgl_handle->type = INI_WR_CMD;
- else
- AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
- INI_WR_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ INI_WR_CMD);
AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1);
} else {
- if (ring_mode)
- io_task->psgl_handle->type = INI_RD_CMD;
- else
- AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
- INI_RD_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ INI_RD_CMD);
AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0);
}
memcpy(&io_task->cmd_bhs->iscsi_data_pdu.
@@ -3496,8 +3466,7 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
- if (!ring_mode)
- doorbell |= (io_task->pwrb_handle->wrb_index &
+ doorbell |= (io_task->pwrb_handle->wrb_index &
DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT;
doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
@@ -3519,49 +3488,46 @@ static int beiscsi_mtask(struct iscsi_task *task)
unsigned int doorbell = 0;
unsigned int i, cid;
struct iscsi_task *aborted_task;
+ unsigned int tag;
cid = beiscsi_conn->beiscsi_conn_cid;
pwrb = io_task->pwrb_handle->pwrb;
+ memset(pwrb, 0, sizeof(*pwrb));
AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb,
be32_to_cpu(task->cmdsn));
AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb,
io_task->pwrb_handle->wrb_index);
AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb,
io_task->psgl_handle->sgl_index);
-
switch (task->hdr->opcode & ISCSI_OPCODE_MASK) {
case ISCSI_OP_LOGIN:
- if (ring_mode)
- io_task->psgl_handle->type = TGT_DM_CMD;
- else
- AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
- TGT_DM_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ TGT_DM_CMD);
AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 1);
hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_NOOP_OUT:
- if (ring_mode)
- io_task->psgl_handle->type = INI_RD_CMD;
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ INI_RD_CMD);
+ if (task->hdr->ttt == ISCSI_RESERVED_TAG)
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
else
- AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
- INI_RD_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 1);
hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_TEXT:
- if (ring_mode)
- io_task->psgl_handle->type = INI_WR_CMD;
- else
- AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
- INI_WR_CMD);
- AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ TGT_DM_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_SCSI_TMFUNC:
session = conn->session;
i = ((struct iscsi_tm *)task->hdr)->rtt;
phwi_ctrlr = phba->phwi_ctrlr;
- pwrb_context = &phwi_ctrlr->wrb_context[cid];
+ pwrb_context = &phwi_ctrlr->wrb_context[cid -
+ phba->fw_config.iscsi_cid_start];
pwrb_handle = pwrb_context->pwrb_handle_basestd[be32_to_cpu(i)
>> 16];
aborted_task = pwrb_handle->pio_handle;
@@ -3572,22 +3538,25 @@ static int beiscsi_mtask(struct iscsi_task *task)
if (!aborted_io_task->scsi_cmnd)
return 0;
- mgmt_invalidate_icds(phba,
+ tag = mgmt_invalidate_icds(phba,
aborted_io_task->psgl_handle->sgl_index,
cid);
- if (ring_mode)
- io_task->psgl_handle->type = INI_TMF_CMD;
- else
- AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
- INI_TMF_CMD);
+ if (!tag) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "mgmt_invalidate_icds could not be"
+ " submitted\n");
+ } else {
+ wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+ phba->ctrl.mcc_numtag[tag]);
+ free_mcc_tag(&phba->ctrl, tag);
+ }
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ INI_TMF_CMD);
AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_LOGOUT:
AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
- if (ring_mode)
- io_task->psgl_handle->type = HWH_TYPE_LOGOUT;
- else
AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
HWH_TYPE_LOGOUT);
hwi_write_buffer(pwrb, task);
@@ -3600,14 +3569,13 @@ static int beiscsi_mtask(struct iscsi_task *task)
}
AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb,
- be32_to_cpu(task->data_count));
+ task->data_count);
AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb,
io_task->pwrb_handle->nxt_wrb_index);
be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
doorbell |= cid & DB_WRB_POST_CID_MASK;
- if (!ring_mode)
- doorbell |= (io_task->pwrb_handle->wrb_index &
+ doorbell |= (io_task->pwrb_handle->wrb_index &
DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT;
doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET);
@@ -3649,7 +3617,6 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
return beiscsi_iotask(task, sg, num_sg, xferlen, writedir);
}
-
static void beiscsi_remove(struct pci_dev *pcidev)
{
struct beiscsi_hba *phba = NULL;
@@ -3734,7 +3701,20 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
}
SE_DEBUG(DBG_LVL_8, " phba = %p \n", phba);
- pci_set_drvdata(pcidev, phba);
+ switch (pcidev->device) {
+ case BE_DEVICE_ID1:
+ case OC_DEVICE_ID1:
+ case OC_DEVICE_ID2:
+ phba->generation = BE_GEN2;
+ break;
+ case BE_DEVICE_ID2:
+ case OC_DEVICE_ID3:
+ phba->generation = BE_GEN3;
+ break;
+ default:
+ phba->generation = 0;
+ }
+
if (enable_msix)
num_cpus = find_num_cpus();
else
@@ -3754,7 +3734,15 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
spin_lock_init(&phba->io_sgl_lock);
spin_lock_init(&phba->mgmt_sgl_lock);
spin_lock_init(&phba->isr_lock);
+ ret = mgmt_get_fw_config(&phba->ctrl, phba);
+ if (ret != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Error getting fw config\n");
+ goto free_port;
+ }
+ phba->shost->max_id = phba->fw_config.iscsi_cid_count;
beiscsi_get_params(phba);
+ phba->shost->can_queue = phba->params.ios_per_ctrl;
ret = beiscsi_init_port(phba);
if (ret < 0) {
shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
@@ -3762,6 +3750,15 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
goto free_port;
}
+ for (i = 0; i < MAX_MCC_CMD ; i++) {
+ init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]);
+ phba->ctrl.mcc_tag[i] = i + 1;
+ phba->ctrl.mcc_numtag[i + 1] = 0;
+ phba->ctrl.mcc_tag_available++;
+ }
+
+ phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0;
+
snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_q_irq%u",
phba->shost->host_no);
phba->wq = create_workqueue(phba->wq_name);
@@ -3836,7 +3833,7 @@ disable_pci:
struct iscsi_transport beiscsi_iscsi_transport = {
.owner = THIS_MODULE,
.name = DRV_NAME,
- .caps = CAP_RECOVERY_L0 | CAP_HDRDGST |
+ .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | CAP_TEXT_NEGO |
CAP_MULTI_R2T | CAP_DATADGST | CAP_DATA_PATH_OFFLOAD,
.param_mask = ISCSI_MAX_RECV_DLENGTH |
ISCSI_MAX_XMIT_DLENGTH |
@@ -3859,7 +3856,7 @@ struct iscsi_transport beiscsi_iscsi_transport = {
ISCSI_USERNAME | ISCSI_PASSWORD |
ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
- ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
+ ISCSI_LU_RESET_TMO |
ISCSI_PING_TMO | ISCSI_RECV_TMO |
ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
.host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
@@ -3905,7 +3902,7 @@ static int __init beiscsi_module_init(void)
SE_DEBUG(DBG_LVL_1,
"beiscsi_module_init - Unable to register beiscsi"
"transport.\n");
- ret = -ENOMEM;
+ return -ENOMEM;
}
SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p \n",
&beiscsi_iscsi_transport);
@@ -3917,7 +3914,6 @@ static int __init beiscsi_module_init(void)
"beiscsi pci driver.\n");
goto unregister_iscsi_transport;
}
- ring_mode = 0;
return 0;
unregister_iscsi_transport:
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index 25e6b208b771..c53a80ab796c 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -40,31 +40,29 @@
#define DRV_DESC BE_NAME " " "Driver"
#define BE_VENDOR_ID 0x19A2
+/* DEVICE ID's for BE2 */
#define BE_DEVICE_ID1 0x212
#define OC_DEVICE_ID1 0x702
#define OC_DEVICE_ID2 0x703
+
+/* DEVICE ID's for BE3 */
+#define BE_DEVICE_ID2 0x222
#define OC_DEVICE_ID3 0x712
-#define OC_DEVICE_ID4 0x222
-#define BE2_MAX_SESSIONS 64
+#define BE2_IO_DEPTH 1024
+#define BE2_MAX_SESSIONS 256
#define BE2_CMDS_PER_CXN 128
-#define BE2_LOGOUTS BE2_MAX_SESSIONS
#define BE2_TMFS 16
#define BE2_NOPOUT_REQ 16
-#define BE2_ASYNCPDUS BE2_MAX_SESSIONS
-#define BE2_MAX_ICDS 2048
#define BE2_SGE 32
#define BE2_DEFPDU_HDR_SZ 64
#define BE2_DEFPDU_DATA_SZ 8192
-#define BE2_IO_DEPTH \
- (BE2_MAX_ICDS / 2 - (BE2_LOGOUTS + BE2_TMFS + BE2_NOPOUT_REQ))
#define MAX_CPUS 31
-#define BEISCSI_SGLIST_ELEMENTS BE2_SGE
+#define BEISCSI_SGLIST_ELEMENTS 30
-#define BEISCSI_MAX_CMNDS 1024 /* Max IO's per Ctrlr sht->can_queue */
#define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */
-#define BEISCSI_MAX_SECTORS 2048 /* scsi_host->max_sectors */
+#define BEISCSI_MAX_SECTORS 256 /* scsi_host->max_sectors */
#define BEISCSI_MAX_CMD_LEN 16 /* scsi_host->max_cmd_len */
#define BEISCSI_NUM_MAX_LUN 256 /* scsi_host->max_lun */
@@ -330,6 +328,7 @@ struct beiscsi_hba {
struct workqueue_struct *wq; /* The actuak work queue */
struct work_struct work_cqs; /* The work being queued */
struct be_ctrl_info ctrl;
+ unsigned int generation;
};
struct beiscsi_session {
@@ -656,11 +655,12 @@ struct amap_iscsi_wrb {
} __packed;
-struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
- int index);
+struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid);
void
free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle);
+void beiscsi_process_all_cqs(struct work_struct *work);
+
struct pdu_nop_out {
u32 dw[12];
};
@@ -802,7 +802,6 @@ struct hwi_controller {
struct be_ring default_pdu_hdr;
struct be_ring default_pdu_data;
struct hwi_context_memory *phwi_ctxt;
- unsigned short cq_errors[CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN];
};
enum hwh_type_enum {
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index 79c2bd525a84..317bcd042ced 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -48,6 +48,14 @@ unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl,
pfw_cfg->ulp[0].sq_base;
phba->fw_config.iscsi_cid_count =
pfw_cfg->ulp[0].sq_count;
+ if (phba->fw_config.iscsi_cid_count > (BE2_MAX_SESSIONS / 2)) {
+ SE_DEBUG(DBG_LVL_8,
+ "FW reported MAX CXNS as %d \t"
+ "Max Supported = %d.\n",
+ phba->fw_config.iscsi_cid_count,
+ BE2_MAX_SESSIONS);
+ phba->fw_config.iscsi_cid_count = BE2_MAX_SESSIONS / 2;
+ }
} else {
shost_printk(KERN_WARNING, phba->shost,
"Failed in mgmt_get_fw_config \n");
@@ -77,6 +85,7 @@ unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
}
nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes);
req = nonemb_cmd.va;
+ memset(req, 0, sizeof(*req));
spin_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
@@ -140,10 +149,17 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
{
struct be_dma_mem nonemb_cmd;
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
- struct be_sge *sge = nonembedded_sgl(wrb);
+ struct be_mcc_wrb *wrb;
+ struct be_sge *sge;
struct invalidate_commands_params_in *req;
- int status = 0;
+ unsigned int tag = 0;
+
+ spin_lock(&ctrl->mbox_lock);
+ tag = alloc_mcc_tag(phba);
+ if (!tag) {
+ spin_unlock(&ctrl->mbox_lock);
+ return tag;
+ }
nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev,
sizeof(struct invalidate_commands_params_in),
@@ -156,8 +172,10 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
}
nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
req = nonemb_cmd.va;
- spin_lock(&ctrl->mbox_lock);
- memset(wrb, 0, sizeof(*wrb));
+ memset(req, 0, sizeof(*req));
+ wrb = wrb_from_mccq(phba);
+ sge = nonembedded_sgl(wrb);
+ wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
@@ -172,14 +190,12 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF);
sge->len = cpu_to_le32(nonemb_cmd.size);
- status = be_mcc_notify_wait(phba);
- if (status)
- SE_DEBUG(DBG_LVL_1, "ICDS Invalidation Failed\n");
+ be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
if (nonemb_cmd.va)
pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
- return status;
+ return tag;
}
unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
@@ -189,13 +205,19 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
unsigned short savecfg_flag)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
- struct iscsi_invalidate_connection_params_in *req =
- embedded_payload(wrb);
- int status = 0;
+ struct be_mcc_wrb *wrb;
+ struct iscsi_invalidate_connection_params_in *req;
+ unsigned int tag = 0;
spin_lock(&ctrl->mbox_lock);
- memset(wrb, 0, sizeof(*wrb));
+ tag = alloc_mcc_tag(phba);
+ if (!tag) {
+ spin_unlock(&ctrl->mbox_lock);
+ return tag;
+ }
+ wrb = wrb_from_mccq(phba);
+ wrb->tag0 |= tag;
+ req = embedded_payload(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
@@ -208,35 +230,37 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
else
req->cleanup_type = CMD_ISCSI_CONNECTION_INVALIDATE;
req->save_cfg = savecfg_flag;
- status = be_mcc_notify_wait(phba);
- if (status)
- SE_DEBUG(DBG_LVL_1, "Invalidation Failed\n");
-
+ be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
- return status;
+ return tag;
}
unsigned char mgmt_upload_connection(struct beiscsi_hba *phba,
unsigned short cid, unsigned int upload_flag)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
- struct tcp_upload_params_in *req = embedded_payload(wrb);
- int status = 0;
+ struct be_mcc_wrb *wrb;
+ struct tcp_upload_params_in *req;
+ unsigned int tag = 0;
spin_lock(&ctrl->mbox_lock);
- memset(wrb, 0, sizeof(*wrb));
+ tag = alloc_mcc_tag(phba);
+ if (!tag) {
+ spin_unlock(&ctrl->mbox_lock);
+ return tag;
+ }
+ wrb = wrb_from_mccq(phba);
+ req = embedded_payload(wrb);
+ wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_COMMON_TCP_UPLOAD,
OPCODE_COMMON_TCP_UPLOAD, sizeof(*req));
req->id = (unsigned short)cid;
req->upload_type = (unsigned char)upload_flag;
- status = be_mcc_notify_wait(phba);
- if (status)
- SE_DEBUG(DBG_LVL_1, "mgmt_upload_connection Failed\n");
+ be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
- return status;
+ return tag;
}
int mgmt_open_connection(struct beiscsi_hba *phba,
@@ -248,13 +272,13 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
struct sockaddr_in *daddr_in = (struct sockaddr_in *)dst_addr;
struct sockaddr_in6 *daddr_in6 = (struct sockaddr_in6 *)dst_addr;
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
- struct tcp_connect_and_offload_in *req = embedded_payload(wrb);
+ struct be_mcc_wrb *wrb;
+ struct tcp_connect_and_offload_in *req;
unsigned short def_hdr_id;
unsigned short def_data_id;
struct phys_addr template_address = { 0, 0 };
struct phys_addr *ptemplate_address;
- int status = 0;
+ unsigned int tag = 0;
unsigned int i;
unsigned short cid = beiscsi_ep->ep_cid;
@@ -266,7 +290,14 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
ptemplate_address = &template_address;
ISCSI_GET_PDU_TEMPLATE_ADDRESS(phba, ptemplate_address);
spin_lock(&ctrl->mbox_lock);
- memset(wrb, 0, sizeof(*wrb));
+ tag = alloc_mcc_tag(phba);
+ if (!tag) {
+ spin_unlock(&ctrl->mbox_lock);
+ return tag;
+ }
+ wrb = wrb_from_mccq(phba);
+ req = embedded_payload(wrb);
+ wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
@@ -311,46 +342,36 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
req->do_offload = 1;
req->dataout_template_pa.lo = ptemplate_address->lo;
req->dataout_template_pa.hi = ptemplate_address->hi;
- status = be_mcc_notify_wait(phba);
- if (!status) {
- struct iscsi_endpoint *ep;
- struct tcp_connect_and_offload_out *ptcpcnct_out =
- embedded_payload(wrb);
-
- ep = phba->ep_array[ptcpcnct_out->cid];
- beiscsi_ep = ep->dd_data;
- beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle;
- beiscsi_ep->cid_vld = 1;
- SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n");
- } else
- SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed\n");
+ be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
- return status;
+ return tag;
}
-int be_cmd_get_mac_addr(struct beiscsi_hba *phba, u8 *mac_addr)
+unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
- struct be_cmd_req_get_mac_addr *req = embedded_payload(wrb);
- int status;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_get_mac_addr *req;
+ unsigned int tag = 0;
SE_DEBUG(DBG_LVL_8, "In be_cmd_get_mac_addr\n");
spin_lock(&ctrl->mbox_lock);
- memset(wrb, 0, sizeof(*wrb));
+ tag = alloc_mcc_tag(phba);
+ if (!tag) {
+ spin_unlock(&ctrl->mbox_lock);
+ return tag;
+ }
+
+ wrb = wrb_from_mccq(phba);
+ req = embedded_payload(wrb);
+ wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG,
sizeof(*req));
- status = be_mcc_notify_wait(phba);
- if (!status) {
- struct be_cmd_resp_get_mac_addr *resp = embedded_payload(wrb);
-
- memcpy(mac_addr, resp->mac_address, ETH_ALEN);
- }
-
+ be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
- return status;
+ return tag;
}
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index 24eaff923f85..ecead6a5aa56 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -231,6 +231,7 @@ struct beiscsi_endpoint {
struct beiscsi_hba *phba;
struct beiscsi_sess *sess;
struct beiscsi_conn *conn;
+ struct iscsi_endpoint *openiscsi_ep;
unsigned short ip_type;
char dst6_addr[ISCSI_ADDRESS_BUF_LEN];
unsigned long dst_addr;
@@ -249,7 +250,4 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
unsigned short issue_reset,
unsigned short savecfg_flag);
-unsigned char mgmt_fw_cmd(struct be_ctrl_info *ctrl,
- struct beiscsi_hba *phba,
- char *buf, unsigned int len);
#endif
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 33b2294625bb..1c4d1215769d 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1426,8 +1426,8 @@ static int bnx2i_conn_get_param(struct iscsi_cls_conn *cls_conn,
break;
case ISCSI_PARAM_CONN_ADDRESS:
if (bnx2i_conn->ep)
- len = sprintf(buf, NIPQUAD_FMT "\n",
- NIPQUAD(bnx2i_conn->ep->cm_sk->dst_ip));
+ len = sprintf(buf, "%pI4\n",
+ &bnx2i_conn->ep->cm_sk->dst_ip);
break;
default:
return iscsi_conn_get_param(cls_conn, param, buf);
@@ -1990,6 +1990,7 @@ static struct scsi_host_template bnx2i_host_template = {
.eh_abort_handler = iscsi_eh_abort,
.eh_device_reset_handler = iscsi_eh_device_reset,
.eh_target_reset_handler = iscsi_eh_target_reset,
+ .change_queue_depth = iscsi_change_queue_depth,
.can_queue = 1024,
.max_sectors = 127,
.cmd_per_lun = 32,
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 9129bcf117cf..cd05e049d5f6 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -219,18 +219,15 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
break;
}
sa = (cdbp[8] << 8) + cdbp[9];
- name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
- if (name) {
+ name = get_sa_name(variable_length_arr, VARIABLE_LENGTH_SZ, sa);
+ if (name)
printk("%s", name);
- if ((cdb_len > 0) && (len != cdb_len))
- printk(", in_cdb_len=%d, ext_len=%d",
- len, cdb_len);
- } else {
+ else
printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
- if ((cdb_len > 0) && (len != cdb_len))
- printk(", in_cdb_len=%d, ext_len=%d",
- len, cdb_len);
- }
+
+ if ((cdb_len > 0) && (len != cdb_len))
+ printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len);
+
break;
case MAINTENANCE_IN:
sa = cdbp[1] & 0x1f;
@@ -349,6 +346,9 @@ void scsi_print_command(struct scsi_cmnd *cmd)
{
int k;
+ if (cmd->cmnd == NULL)
+ return;
+
scmd_printk(KERN_INFO, cmd, "CDB: ");
print_opcode_name(cmd->cmnd, cmd->cmd_len);
diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
index 969c83162cc4..412853c65372 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
@@ -591,8 +591,7 @@ static int cxgb3i_conn_bind(struct iscsi_cls_session *cls_session,
cxgb3i_conn_max_recv_dlength(conn);
spin_lock_bh(&conn->session->lock);
- sprintf(conn->portal_address, NIPQUAD_FMT,
- NIPQUAD(c3cn->daddr.sin_addr.s_addr));
+ sprintf(conn->portal_address, "%pI4", &c3cn->daddr.sin_addr.s_addr);
conn->portal_port = ntohs(c3cn->daddr.sin_port);
spin_unlock_bh(&conn->session->lock);
@@ -709,6 +708,12 @@ static int cxgb3i_host_set_param(struct Scsi_Host *shost,
{
struct cxgb3i_hba *hba = iscsi_host_priv(shost);
+ if (!hba->ndev) {
+ shost_printk(KERN_ERR, shost, "Could not set host param. "
+ "Netdev for host not set.\n");
+ return -ENODEV;
+ }
+
cxgb3i_api_debug("param %d, buf %s.\n", param, buf);
switch (param) {
@@ -739,6 +744,12 @@ static int cxgb3i_host_get_param(struct Scsi_Host *shost,
struct cxgb3i_hba *hba = iscsi_host_priv(shost);
int len = 0;
+ if (!hba->ndev) {
+ shost_printk(KERN_ERR, shost, "Could not set host param. "
+ "Netdev for host not set.\n");
+ return -ENODEV;
+ }
+
cxgb3i_api_debug("hba %s, param %d.\n", hba->ndev->name, param);
switch (param) {
@@ -753,7 +764,7 @@ static int cxgb3i_host_get_param(struct Scsi_Host *shost,
__be32 addr;
addr = cxgb3i_get_private_ipv4addr(hba->ndev);
- len = sprintf(buf, NIPQUAD_FMT, NIPQUAD(addr));
+ len = sprintf(buf, "%pI4", &addr);
break;
}
default:
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c
index 15a00e8b7122..3e08c430ff29 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_offload.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c
@@ -1675,10 +1675,11 @@ int cxgb3i_c3cn_connect(struct net_device *dev, struct s3_conn *c3cn,
} else
c3cn->saddr.sin_addr.s_addr = sipv4;
- c3cn_conn_debug("c3cn 0x%p, %u.%u.%u.%u,%u-%u.%u.%u.%u,%u SYN_SENT.\n",
- c3cn, NIPQUAD(c3cn->saddr.sin_addr.s_addr),
+ c3cn_conn_debug("c3cn 0x%p, %pI4,%u-%pI4,%u SYN_SENT.\n",
+ c3cn,
+ &c3cn->saddr.sin_addr.s_addr,
ntohs(c3cn->saddr.sin_port),
- NIPQUAD(c3cn->daddr.sin_addr.s_addr),
+ &c3cn->daddr.sin_addr.s_addr,
ntohs(c3cn->daddr.sin_port));
c3cn_set_state(c3cn, C3CN_STATE_CONNECTING);
diff --git a/drivers/scsi/cxgb3i/cxgb3i_pdu.c b/drivers/scsi/cxgb3i/cxgb3i_pdu.c
index 1fe3b0f1f3c9..9c38539557fc 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_pdu.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_pdu.c
@@ -461,10 +461,8 @@ void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn)
skb = skb_peek(&c3cn->receive_queue);
}
read_unlock(&c3cn->callback_lock);
- if (c3cn) {
- c3cn->copied_seq += read;
- cxgb3i_c3cn_rx_credits(c3cn, read);
- }
+ c3cn->copied_seq += read;
+ cxgb3i_c3cn_rx_credits(c3cn, read);
conn->rxdata_octets += read;
if (err) {
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 4f0d0138f48b..bc9e94f5915e 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -717,6 +717,8 @@ static const struct scsi_dh_devlist alua_dev_list[] = {
{"IBM", "2145" },
{"Pillar", "Axiom" },
{"Intel", "Multi-Flex"},
+ {"NETAPP", "LUN"},
+ {"AIX", "NVDISK"},
{NULL, NULL}
};
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index c7076ce25e21..3c5abf7cd762 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -1509,7 +1509,7 @@ static int option_setup(char *str)
char *cur = str;
int i = 1;
- while (cur && isdigit(*cur) && i <= MAX_INT_PARAM) {
+ while (cur && isdigit(*cur) && i < MAX_INT_PARAM) {
ints[i++] = simple_strtoul(cur, NULL, 0);
if ((cur = strchr(cur, ',')) != NULL)
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index a680e18b5f3b..e2bc779f86c1 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -1449,9 +1449,6 @@ static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp)
if (offset > 15)
goto do_reject;
- if (esp->flags & ESP_FLAG_DISABLE_SYNC)
- offset = 0;
-
if (offset) {
int one_clock;
@@ -2405,12 +2402,6 @@ static int esp_slave_configure(struct scsi_device *dev)
struct esp_target_data *tp = &esp->target[dev->id];
int goal_tags, queue_depth;
- if (esp->flags & ESP_FLAG_DISABLE_SYNC) {
- /* Bypass async domain validation */
- dev->ppr = 0;
- dev->sdtr = 0;
- }
-
goal_tags = 0;
if (dev->tagged_supported) {
@@ -2660,7 +2651,10 @@ static void esp_set_offset(struct scsi_target *target, int offset)
struct esp *esp = shost_priv(host);
struct esp_target_data *tp = &esp->target[target->id];
- tp->nego_goal_offset = offset;
+ if (esp->flags & ESP_FLAG_DISABLE_SYNC)
+ tp->nego_goal_offset = 0;
+ else
+ tp->nego_goal_offset = offset;
tp->flags |= ESP_TGT_CHECK_NEGO;
}
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 10be9f36a4cc..2f47ae7cce91 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -2009,6 +2009,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
fcoe_interface_cleanup(fcoe);
rtnl_unlock();
fcoe_if_destroy(fcoe->ctlr.lp);
+ module_put(THIS_MODULE);
+
out_putdev:
dev_put(netdev);
out_nodev:
@@ -2059,6 +2061,11 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
}
#endif
+ if (!try_module_get(THIS_MODULE)) {
+ rc = -EINVAL;
+ goto out_nomod;
+ }
+
rtnl_lock();
netdev = fcoe_if_to_netdev(buffer);
if (!netdev) {
@@ -2099,17 +2106,24 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
if (!fcoe_link_ok(lport))
fcoe_ctlr_link_up(&fcoe->ctlr);
- rc = 0;
-out_free:
/*
* Release from init in fcoe_interface_create(), on success lport
* should be holding a reference taken in fcoe_if_create().
*/
fcoe_interface_put(fcoe);
+ dev_put(netdev);
+ rtnl_unlock();
+ mutex_unlock(&fcoe_config_mutex);
+
+ return 0;
+out_free:
+ fcoe_interface_put(fcoe);
out_putdev:
dev_put(netdev);
out_nodev:
rtnl_unlock();
+ module_put(THIS_MODULE);
+out_nomod:
mutex_unlock(&fcoe_config_mutex);
return rc;
}
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index 9823291395ad..511cb6b371ee 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -1187,7 +1187,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)
next_timer = fip->ctlr_ka_time;
if (time_after_eq(jiffies, fip->port_ka_time)) {
- fip->port_ka_time += jiffies +
+ fip->port_ka_time = jiffies +
msecs_to_jiffies(FIP_VN_KA_PERIOD);
fip->send_port_ka = 1;
}
diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h
index bb208a6091e7..3966c71d0095 100644
--- a/drivers/scsi/fnic/fnic.h
+++ b/drivers/scsi/fnic/fnic.h
@@ -36,7 +36,7 @@
#define DRV_NAME "fnic"
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
-#define DRV_VERSION "1.0.0.1121"
+#define DRV_VERSION "1.4.0.98"
#define PFX DRV_NAME ": "
#define DFX DRV_NAME "%d: "
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index fe1b1031f7ab..507e26c1c29f 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -620,6 +620,8 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
if (fnic->config.flags & VFCF_FIP_CAPABLE) {
shost_printk(KERN_INFO, fnic->lport->host,
"firmware supports FIP\n");
+ /* enable directed and multicast */
+ vnic_dev_packet_filter(fnic->vdev, 1, 1, 0, 0, 0);
vnic_dev_add_addr(fnic->vdev, FIP_ALL_ENODE_MACS);
vnic_dev_add_addr(fnic->vdev, fnic->ctlr.ctl_src_addr);
} else {
@@ -698,6 +700,8 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
goto err_out_remove_scsi_host;
}
+ fc_lport_init_stats(lp);
+
fc_lport_config(lp);
if (fc_set_mfs(lp, fnic->config.maxdatafieldsize +
diff --git a/drivers/scsi/fnic/vnic_devcmd.h b/drivers/scsi/fnic/vnic_devcmd.h
index d62b9061bf12..7c9ccbd4134b 100644
--- a/drivers/scsi/fnic/vnic_devcmd.h
+++ b/drivers/scsi/fnic/vnic_devcmd.h
@@ -94,7 +94,7 @@ enum vnic_devcmd_cmd {
CMD_STATS_DUMP = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 4),
/* set Rx packet filter: (u32)a0=filters (see CMD_PFILTER_*) */
- CMD_PACKET_FILTER = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 7),
+ CMD_PACKET_FILTER = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 7),
/* hang detection notification */
CMD_HANG_NOTIFY = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 8),
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 9e8fce0f0c1b..ba3c94c9c25f 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -140,40 +140,40 @@
#include "gdth.h"
static void gdth_delay(int milliseconds);
-static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
+static void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs);
static irqreturn_t gdth_interrupt(int irq, void *dev_id);
static irqreturn_t __gdth_interrupt(gdth_ha_str *ha,
int gdth_from_wait, int* pIndex);
-static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
+static int gdth_sync_event(gdth_ha_str *ha, int service, u8 index,
Scsi_Cmnd *scp);
static int gdth_async_event(gdth_ha_str *ha);
static void gdth_log_event(gdth_evt_data *dvr, char *buffer);
-static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority);
+static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 priority);
static void gdth_next(gdth_ha_str *ha);
-static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b);
+static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 b);
static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
-static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source,
- ushort idx, gdth_evt_data *evt);
+static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source,
+ u16 idx, gdth_evt_data *evt);
static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr);
-static void gdth_readapp_event(gdth_ha_str *ha, unchar application,
+static void gdth_readapp_event(gdth_ha_str *ha, u8 application,
gdth_evt_str *estr);
static void gdth_clear_events(void);
static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
- char *buffer, ushort count);
+ char *buffer, u16 count);
static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
-static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive);
+static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u16 hdrive);
static void gdth_enable_int(gdth_ha_str *ha);
static int gdth_test_busy(gdth_ha_str *ha);
static int gdth_get_cmd_index(gdth_ha_str *ha);
static void gdth_release_event(gdth_ha_str *ha);
-static int gdth_wait(gdth_ha_str *ha, int index,ulong32 time);
-static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode,
- ulong32 p1, ulong64 p2,ulong64 p3);
+static int gdth_wait(gdth_ha_str *ha, int index,u32 time);
+static int gdth_internal_cmd(gdth_ha_str *ha, u8 service, u16 opcode,
+ u32 p1, u64 p2,u64 p3);
static int gdth_search_drives(gdth_ha_str *ha);
-static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive);
+static int gdth_analyse_hdrive(gdth_ha_str *ha, u16 hdrive);
static const char *gdth_ctr_name(gdth_ha_str *ha);
@@ -189,7 +189,7 @@ static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
static void gdth_scsi_done(struct scsi_cmnd *scp);
#ifdef DEBUG_GDTH
-static unchar DebugState = DEBUG_GDTH;
+static u8 DebugState = DEBUG_GDTH;
#ifdef __SERIAL__
#define MAX_SERBUF 160
@@ -270,30 +270,30 @@ static int ser_printk(const char *fmt, ...)
#endif
#ifdef GDTH_STATISTICS
-static ulong32 max_rq=0, max_index=0, max_sg=0;
+static u32 max_rq=0, max_index=0, max_sg=0;
#ifdef INT_COAL
-static ulong32 max_int_coal=0;
+static u32 max_int_coal=0;
#endif
-static ulong32 act_ints=0, act_ios=0, act_stats=0, act_rq=0;
+static u32 act_ints=0, act_ios=0, act_stats=0, act_rq=0;
static struct timer_list gdth_timer;
#endif
-#define PTR2USHORT(a) (ushort)(ulong)(a)
+#define PTR2USHORT(a) (u16)(unsigned long)(a)
#define GDTOFFSOF(a,b) (size_t)&(((a*)0)->b)
#define INDEX_OK(i,t) ((i)<ARRAY_SIZE(t))
#define BUS_L2P(a,b) ((b)>(a)->virt_bus ? (b-1):(b))
#ifdef CONFIG_ISA
-static unchar gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */
+static u8 gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */
#endif
#if defined(CONFIG_EISA) || defined(CONFIG_ISA)
-static unchar gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */
+static u8 gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */
#endif
-static unchar gdth_polling; /* polling if TRUE */
+static u8 gdth_polling; /* polling if TRUE */
static int gdth_ctr_count = 0; /* controller count */
static LIST_HEAD(gdth_instances); /* controller list */
-static unchar gdth_write_through = FALSE; /* write through */
+static u8 gdth_write_through = FALSE; /* write through */
static gdth_evt_str ebuffer[MAX_EVENTS]; /* event buffer */
static int elastidx;
static int eoldidx;
@@ -303,7 +303,7 @@ static int major;
#define DOU 2 /* OUT data direction */
#define DNO DIN /* no data transfer */
#define DUN DIN /* unknown data direction */
-static unchar gdth_direction_tab[0x100] = {
+static u8 gdth_direction_tab[0x100] = {
DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN,
DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN,
DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DOU,DNO,DUN,DIN,DOU,DOU,
@@ -390,7 +390,7 @@ static gdth_ha_str *gdth_find_ha(int hanum)
static struct gdth_cmndinfo *gdth_get_cmndinfo(gdth_ha_str *ha)
{
struct gdth_cmndinfo *priv = NULL;
- ulong flags;
+ unsigned long flags;
int i;
spin_lock_irqsave(&ha->smp_lock, flags);
@@ -493,7 +493,7 @@ int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd,
return rval;
}
-static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs)
+static void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs)
{
*cyls = size /HEADS/SECS;
if (*cyls <= MAXCYLS) {
@@ -514,9 +514,9 @@ static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs
/* controller search and initialization functions */
#ifdef CONFIG_EISA
-static int __init gdth_search_eisa(ushort eisa_adr)
+static int __init gdth_search_eisa(u16 eisa_adr)
{
- ulong32 id;
+ u32 id;
TRACE(("gdth_search_eisa() adr. %x\n",eisa_adr));
id = inl(eisa_adr+ID0REG);
@@ -533,13 +533,13 @@ static int __init gdth_search_eisa(ushort eisa_adr)
#endif /* CONFIG_EISA */
#ifdef CONFIG_ISA
-static int __init gdth_search_isa(ulong32 bios_adr)
+static int __init gdth_search_isa(u32 bios_adr)
{
void __iomem *addr;
- ulong32 id;
+ u32 id;
TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr));
- if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) {
+ if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(u32))) != NULL) {
id = readl(addr);
iounmap(addr);
if (id == GDT2_ID) /* GDT2000 */
@@ -551,7 +551,7 @@ static int __init gdth_search_isa(ulong32 bios_adr)
#ifdef CONFIG_PCI
-static bool gdth_search_vortex(ushort device)
+static bool gdth_search_vortex(u16 device)
{
if (device <= PCI_DEVICE_ID_VORTEX_GDT6555)
return true;
@@ -603,9 +603,9 @@ static void __devexit gdth_pci_remove_one(struct pci_dev *pdev)
static int __devinit gdth_pci_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- ushort vendor = pdev->vendor;
- ushort device = pdev->device;
- ulong base0, base1, base2;
+ u16 vendor = pdev->vendor;
+ u16 device = pdev->device;
+ unsigned long base0, base1, base2;
int rc;
gdth_pci_str gdth_pcistr;
gdth_ha_str *ha = NULL;
@@ -658,10 +658,10 @@ static int __devinit gdth_pci_init_one(struct pci_dev *pdev,
#endif /* CONFIG_PCI */
#ifdef CONFIG_EISA
-static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)
+static int __init gdth_init_eisa(u16 eisa_adr,gdth_ha_str *ha)
{
- ulong32 retries,id;
- unchar prot_ver,eisacf,i,irq_found;
+ u32 retries,id;
+ u8 prot_ver,eisacf,i,irq_found;
TRACE(("gdth_init_eisa() adr. %x\n",eisa_adr));
@@ -688,7 +688,7 @@ static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)
return 0;
}
ha->bmic = eisa_adr;
- ha->brd_phys = (ulong32)eisa_adr >> 12;
+ ha->brd_phys = (u32)eisa_adr >> 12;
outl(0,eisa_adr+MAILBOXREG);
outl(0,eisa_adr+MAILBOXREG+4);
@@ -752,12 +752,12 @@ static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)
#endif /* CONFIG_EISA */
#ifdef CONFIG_ISA
-static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
+static int __init gdth_init_isa(u32 bios_adr,gdth_ha_str *ha)
{
register gdt2_dpram_str __iomem *dp2_ptr;
int i;
- unchar irq_drq,prot_ver;
- ulong32 retries;
+ u8 irq_drq,prot_ver;
+ u32 retries;
TRACE(("gdth_init_isa() bios adr. %x\n",bios_adr));
@@ -812,7 +812,7 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- prot_ver = (unchar)readl(&dp2_ptr->u.ic.S_Info[0]);
+ prot_ver = (u8)readl(&dp2_ptr->u.ic.S_Info[0]);
writeb(0, &dp2_ptr->u.ic.Status);
writeb(0xff, &dp2_ptr->io.irqdel);
if (prot_ver != PROTOCOL_VERSION) {
@@ -859,9 +859,9 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
register gdt6_dpram_str __iomem *dp6_ptr;
register gdt6c_dpram_str __iomem *dp6c_ptr;
register gdt6m_dpram_str __iomem *dp6m_ptr;
- ulong32 retries;
- unchar prot_ver;
- ushort command;
+ u32 retries;
+ u8 prot_ver;
+ u16 command;
int i, found = FALSE;
TRACE(("gdth_init_pci()\n"));
@@ -871,7 +871,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
else
ha->oem_id = OEM_ID_ICP;
ha->brd_phys = (pdev->bus->number << 8) | (pdev->devfn & 0xf8);
- ha->stype = (ulong32)pdev->device;
+ ha->stype = (u32)pdev->device;
ha->irq = pdev->irq;
ha->pdev = pdev;
@@ -891,7 +891,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
found = FALSE;
for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
iounmap(ha->brd);
- ha->brd = ioremap(i, sizeof(ushort));
+ ha->brd = ioremap(i, sizeof(u16));
if (ha->brd == NULL) {
printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
return 0;
@@ -947,7 +947,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
}
gdth_delay(1);
}
- prot_ver = (unchar)readl(&dp6_ptr->u.ic.S_Info[0]);
+ prot_ver = (u8)readl(&dp6_ptr->u.ic.S_Info[0]);
writeb(0, &dp6_ptr->u.ic.S_Status);
writeb(0xff, &dp6_ptr->io.irqdel);
if (prot_ver != PROTOCOL_VERSION) {
@@ -1000,7 +1000,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
found = FALSE;
for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
iounmap(ha->brd);
- ha->brd = ioremap(i, sizeof(ushort));
+ ha->brd = ioremap(i, sizeof(u16));
if (ha->brd == NULL) {
printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
return 0;
@@ -1059,7 +1059,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
}
gdth_delay(1);
}
- prot_ver = (unchar)readl(&dp6c_ptr->u.ic.S_Info[0]);
+ prot_ver = (u8)readl(&dp6c_ptr->u.ic.S_Info[0]);
writeb(0, &dp6c_ptr->u.ic.Status);
if (prot_ver != PROTOCOL_VERSION) {
printk("GDT-PCI: Illegal protocol version\n");
@@ -1128,7 +1128,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
found = FALSE;
for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
iounmap(ha->brd);
- ha->brd = ioremap(i, sizeof(ushort));
+ ha->brd = ioremap(i, sizeof(u16));
if (ha->brd == NULL) {
printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
return 0;
@@ -1180,7 +1180,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
}
gdth_delay(1);
}
- prot_ver = (unchar)readl(&dp6m_ptr->u.ic.S_Info[0]);
+ prot_ver = (u8)readl(&dp6m_ptr->u.ic.S_Info[0]);
writeb(0, &dp6m_ptr->u.ic.S_Status);
if (prot_ver != PROTOCOL_VERSION) {
printk("GDT-PCI: Illegal protocol version\n");
@@ -1223,7 +1223,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
}
gdth_delay(1);
}
- prot_ver = (unchar)(readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16);
+ prot_ver = (u8)(readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16);
writeb(0, &dp6m_ptr->u.ic.S_Status);
if (prot_ver < 0x2b) /* FW < x.43: no 64-bit DMA support */
ha->dma64_support = 0;
@@ -1239,7 +1239,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
static void __devinit gdth_enable_int(gdth_ha_str *ha)
{
- ulong flags;
+ unsigned long flags;
gdt2_dpram_str __iomem *dp2_ptr;
gdt6_dpram_str __iomem *dp6_ptr;
gdt6m_dpram_str __iomem *dp6m_ptr;
@@ -1274,14 +1274,14 @@ static void __devinit gdth_enable_int(gdth_ha_str *ha)
}
/* return IStatus if interrupt was from this card else 0 */
-static unchar gdth_get_status(gdth_ha_str *ha)
+static u8 gdth_get_status(gdth_ha_str *ha)
{
- unchar IStatus = 0;
+ u8 IStatus = 0;
TRACE(("gdth_get_status() irq %d ctr_count %d\n", ha->irq, gdth_ctr_count));
if (ha->type == GDT_EISA)
- IStatus = inb((ushort)ha->bmic + EDOORREG);
+ IStatus = inb((u16)ha->bmic + EDOORREG);
else if (ha->type == GDT_ISA)
IStatus =
readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
@@ -1329,7 +1329,7 @@ static int gdth_get_cmd_index(gdth_ha_str *ha)
if (ha->cmd_tab[i].cmnd == UNUSED_CMND) {
ha->cmd_tab[i].cmnd = ha->pccb->RequestBuffer;
ha->cmd_tab[i].service = ha->pccb->Service;
- ha->pccb->CommandIndex = (ulong32)i+2;
+ ha->pccb->CommandIndex = (u32)i+2;
return (i+2);
}
}
@@ -1362,7 +1362,7 @@ static void gdth_copy_command(gdth_ha_str *ha)
register gdt6c_dpram_str __iomem *dp6c_ptr;
gdt6_dpram_str __iomem *dp6_ptr;
gdt2_dpram_str __iomem *dp2_ptr;
- ushort cp_count,dp_offset,cmd_no;
+ u16 cp_count,dp_offset,cmd_no;
TRACE(("gdth_copy_command() hanum %d\n", ha->hanum));
@@ -1386,28 +1386,28 @@ static void gdth_copy_command(gdth_ha_str *ha)
dp2_ptr = ha->brd;
writew(dp_offset + DPMEM_COMMAND_OFFSET,
&dp2_ptr->u.ic.comm_queue[cmd_no].offset);
- writew((ushort)cmd_ptr->Service,
+ writew((u16)cmd_ptr->Service,
&dp2_ptr->u.ic.comm_queue[cmd_no].serv_id);
memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
} else if (ha->type == GDT_PCI) {
dp6_ptr = ha->brd;
writew(dp_offset + DPMEM_COMMAND_OFFSET,
&dp6_ptr->u.ic.comm_queue[cmd_no].offset);
- writew((ushort)cmd_ptr->Service,
+ writew((u16)cmd_ptr->Service,
&dp6_ptr->u.ic.comm_queue[cmd_no].serv_id);
memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
} else if (ha->type == GDT_PCINEW) {
dp6c_ptr = ha->brd;
writew(dp_offset + DPMEM_COMMAND_OFFSET,
&dp6c_ptr->u.ic.comm_queue[cmd_no].offset);
- writew((ushort)cmd_ptr->Service,
+ writew((u16)cmd_ptr->Service,
&dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id);
memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
} else if (ha->type == GDT_PCIMPR) {
dp6m_ptr = ha->brd;
writew(dp_offset + DPMEM_COMMAND_OFFSET,
&dp6m_ptr->u.ic.comm_queue[cmd_no].offset);
- writew((ushort)cmd_ptr->Service,
+ writew((u16)cmd_ptr->Service,
&dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id);
memcpy_toio(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
}
@@ -1420,14 +1420,14 @@ static void gdth_release_event(gdth_ha_str *ha)
#ifdef GDTH_STATISTICS
{
- ulong32 i,j;
+ u32 i,j;
for (i=0,j=0; j<GDTH_MAXCMDS; ++j) {
if (ha->cmd_tab[j].cmnd != UNUSED_CMND)
++i;
}
if (max_index < i) {
max_index = i;
- TRACE3(("GDT: max_index = %d\n",(ushort)i));
+ TRACE3(("GDT: max_index = %d\n",(u16)i));
}
}
#endif
@@ -1450,7 +1450,7 @@ static void gdth_release_event(gdth_ha_str *ha)
}
}
-static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time)
+static int gdth_wait(gdth_ha_str *ha, int index, u32 time)
{
int answer_found = FALSE;
int wait_index = 0;
@@ -1476,8 +1476,8 @@ static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time)
}
-static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode,
- ulong32 p1, ulong64 p2, ulong64 p3)
+static int gdth_internal_cmd(gdth_ha_str *ha, u8 service, u16 opcode,
+ u32 p1, u64 p2, u64 p3)
{
register gdth_cmd_str *cmd_ptr;
int retries,index;
@@ -1501,35 +1501,35 @@ static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode,
if (service == CACHESERVICE) {
if (opcode == GDT_IOCTL) {
cmd_ptr->u.ioctl.subfunc = p1;
- cmd_ptr->u.ioctl.channel = (ulong32)p2;
- cmd_ptr->u.ioctl.param_size = (ushort)p3;
+ cmd_ptr->u.ioctl.channel = (u32)p2;
+ cmd_ptr->u.ioctl.param_size = (u16)p3;
cmd_ptr->u.ioctl.p_param = ha->scratch_phys;
} else {
if (ha->cache_feat & GDT_64BIT) {
- cmd_ptr->u.cache64.DeviceNo = (ushort)p1;
+ cmd_ptr->u.cache64.DeviceNo = (u16)p1;
cmd_ptr->u.cache64.BlockNo = p2;
} else {
- cmd_ptr->u.cache.DeviceNo = (ushort)p1;
- cmd_ptr->u.cache.BlockNo = (ulong32)p2;
+ cmd_ptr->u.cache.DeviceNo = (u16)p1;
+ cmd_ptr->u.cache.BlockNo = (u32)p2;
}
}
} else if (service == SCSIRAWSERVICE) {
if (ha->raw_feat & GDT_64BIT) {
cmd_ptr->u.raw64.direction = p1;
- cmd_ptr->u.raw64.bus = (unchar)p2;
- cmd_ptr->u.raw64.target = (unchar)p3;
- cmd_ptr->u.raw64.lun = (unchar)(p3 >> 8);
+ cmd_ptr->u.raw64.bus = (u8)p2;
+ cmd_ptr->u.raw64.target = (u8)p3;
+ cmd_ptr->u.raw64.lun = (u8)(p3 >> 8);
} else {
cmd_ptr->u.raw.direction = p1;
- cmd_ptr->u.raw.bus = (unchar)p2;
- cmd_ptr->u.raw.target = (unchar)p3;
- cmd_ptr->u.raw.lun = (unchar)(p3 >> 8);
+ cmd_ptr->u.raw.bus = (u8)p2;
+ cmd_ptr->u.raw.target = (u8)p3;
+ cmd_ptr->u.raw.lun = (u8)(p3 >> 8);
}
} else if (service == SCREENSERVICE) {
if (opcode == GDT_REALTIME) {
- *(ulong32 *)&cmd_ptr->u.screen.su.data[0] = p1;
- *(ulong32 *)&cmd_ptr->u.screen.su.data[4] = (ulong32)p2;
- *(ulong32 *)&cmd_ptr->u.screen.su.data[8] = (ulong32)p3;
+ *(u32 *)&cmd_ptr->u.screen.su.data[0] = p1;
+ *(u32 *)&cmd_ptr->u.screen.su.data[4] = (u32)p2;
+ *(u32 *)&cmd_ptr->u.screen.su.data[8] = (u32)p3;
}
}
ha->cmd_len = sizeof(gdth_cmd_str);
@@ -1555,9 +1555,9 @@ static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode,
static int __devinit gdth_search_drives(gdth_ha_str *ha)
{
- ushort cdev_cnt, i;
+ u16 cdev_cnt, i;
int ok;
- ulong32 bus_no, drv_cnt, drv_no, j;
+ u32 bus_no, drv_cnt, drv_no, j;
gdth_getch_str *chn;
gdth_drlist_str *drl;
gdth_iochan_str *ioc;
@@ -1570,8 +1570,8 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha)
#endif
#ifdef GDTH_RTC
- unchar rtc[12];
- ulong flags;
+ u8 rtc[12];
+ unsigned long flags;
#endif
TRACE(("gdth_search_drives() hanum %d\n", ha->hanum));
@@ -1584,7 +1584,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha)
if (ok)
ha->screen_feat = GDT_64BIT;
}
- if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
+ if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC))
ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_INIT, 0, 0, 0);
if (!ok) {
printk("GDT-HA %d: Initialization error screen service (code %d)\n",
@@ -1609,11 +1609,11 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha)
rtc[j] = CMOS_READ(j);
} while (rtc[0] != CMOS_READ(0));
spin_unlock_irqrestore(&rtc_lock, flags);
- TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0],
- *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]));
+ TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(u32 *)&rtc[0],
+ *(u32 *)&rtc[4], *(u32 *)&rtc[8]));
/* 3. send to controller firmware */
- gdth_internal_cmd(ha, SCREENSERVICE, GDT_REALTIME, *(ulong32 *)&rtc[0],
- *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]);
+ gdth_internal_cmd(ha, SCREENSERVICE, GDT_REALTIME, *(u32 *)&rtc[0],
+ *(u32 *)&rtc[4], *(u32 *)&rtc[8]);
#endif
/* unfreeze all IOs */
@@ -1627,7 +1627,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha)
if (ok)
ha->cache_feat = GDT_64BIT;
}
- if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
+ if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC))
ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_INIT, LINUX_OS, 0, 0);
if (!ok) {
printk("GDT-HA %d: Initialization error cache service (code %d)\n",
@@ -1635,7 +1635,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha)
return 0;
}
TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
- cdev_cnt = (ushort)ha->info;
+ cdev_cnt = (u16)ha->info;
ha->fw_vers = ha->service;
#ifdef INT_COAL
@@ -1644,7 +1644,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha)
pmod = (gdth_perf_modes *)ha->pscratch;
pmod->version = 1;
pmod->st_mode = 1; /* enable one status buffer */
- *((ulong64 *)&pmod->st_buff_addr1) = ha->coal_stat_phys;
+ *((u64 *)&pmod->st_buff_addr1) = ha->coal_stat_phys;
pmod->st_buff_indx1 = COALINDEX;
pmod->st_buff_addr2 = 0;
pmod->st_buff_u_addr2 = 0;
@@ -1705,7 +1705,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha)
else
ha->bus_id[bus_no] = 0xff;
}
- ha->bus_cnt = (unchar)bus_no;
+ ha->bus_cnt = (u8)bus_no;
}
TRACE2(("gdth_search_drives() %d channels\n",ha->bus_cnt));
@@ -1789,12 +1789,12 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha)
/* logical drives */
if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_CNT,
- INVALID_CHANNEL,sizeof(ulong32))) {
- drv_cnt = *(ulong32 *)ha->pscratch;
+ INVALID_CHANNEL,sizeof(u32))) {
+ drv_cnt = *(u32 *)ha->pscratch;
if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_LIST,
- INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) {
+ INVALID_CHANNEL,drv_cnt * sizeof(u32))) {
for (j = 0; j < drv_cnt; ++j) {
- drv_no = ((ulong32 *)ha->pscratch)[j];
+ drv_no = ((u32 *)ha->pscratch)[j];
if (drv_no < MAX_LDRIVES) {
ha->hdr[drv_no].is_logdrv = TRUE;
TRACE2(("Drive %d is log. drive\n",drv_no));
@@ -1838,7 +1838,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha)
if (ok)
ha->raw_feat = GDT_64BIT;
}
- if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
+ if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC))
ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_INIT, 0, 0, 0);
if (!ok) {
printk("GDT-HA %d: Initialization error raw service (code %d)\n",
@@ -1854,7 +1854,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha)
if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_GET_FEAT, 0, 0, 0)) {
TRACE2(("gdth_search_dr(): get feat RAWSERVICE %d\n",
ha->info));
- ha->raw_feat |= (ushort)ha->info;
+ ha->raw_feat |= (u16)ha->info;
}
}
@@ -1865,7 +1865,7 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha)
if (gdth_internal_cmd(ha, CACHESERVICE, GDT_GET_FEAT, 0, 0, 0)) {
TRACE2(("gdth_search_dr(): get feat CACHESERV. %d\n",
ha->info));
- ha->cache_feat |= (ushort)ha->info;
+ ha->cache_feat |= (u16)ha->info;
}
}
@@ -1923,9 +1923,9 @@ static int __devinit gdth_search_drives(gdth_ha_str *ha)
return 1;
}
-static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive)
+static int gdth_analyse_hdrive(gdth_ha_str *ha, u16 hdrive)
{
- ulong32 drv_cyls;
+ u32 drv_cyls;
int drv_hds, drv_secs;
TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n", ha->hanum, hdrive));
@@ -1944,17 +1944,17 @@ static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive)
} else {
drv_hds = ha->info2 & 0xff;
drv_secs = (ha->info2 >> 8) & 0xff;
- drv_cyls = (ulong32)ha->hdr[hdrive].size / drv_hds / drv_secs;
+ drv_cyls = (u32)ha->hdr[hdrive].size / drv_hds / drv_secs;
}
- ha->hdr[hdrive].heads = (unchar)drv_hds;
- ha->hdr[hdrive].secs = (unchar)drv_secs;
+ ha->hdr[hdrive].heads = (u8)drv_hds;
+ ha->hdr[hdrive].secs = (u8)drv_secs;
/* round size */
ha->hdr[hdrive].size = drv_cyls * drv_hds * drv_secs;
if (ha->cache_feat & GDT_64BIT) {
if (gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INFO, hdrive, 0, 0)
&& ha->info2 != 0) {
- ha->hdr[hdrive].size = ((ulong64)ha->info2 << 32) | ha->info;
+ ha->hdr[hdrive].size = ((u64)ha->info2 << 32) | ha->info;
}
}
TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n",
@@ -1964,7 +1964,7 @@ static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive)
if (gdth_internal_cmd(ha, CACHESERVICE, GDT_DEVTYPE, hdrive, 0, 0)) {
TRACE2(("gdth_search_dr() cache drive %d devtype %d\n",
hdrive,ha->info));
- ha->hdr[hdrive].devtype = (ushort)ha->info;
+ ha->hdr[hdrive].devtype = (u16)ha->info;
}
/* cluster info */
@@ -1972,14 +1972,14 @@ static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive)
TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n",
hdrive,ha->info));
if (!shared_access)
- ha->hdr[hdrive].cluster_type = (unchar)ha->info;
+ ha->hdr[hdrive].cluster_type = (u8)ha->info;
}
/* R/W attributes */
if (gdth_internal_cmd(ha, CACHESERVICE, GDT_RW_ATTRIBS, hdrive, 0, 0)) {
TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n",
hdrive,ha->info));
- ha->hdr[hdrive].rw_attribs = (unchar)ha->info;
+ ha->hdr[hdrive].rw_attribs = (u8)ha->info;
}
return 1;
@@ -1988,12 +1988,12 @@ static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive)
/* command queueing/sending functions */
-static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority)
+static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 priority)
{
struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
register Scsi_Cmnd *pscp;
register Scsi_Cmnd *nscp;
- ulong flags;
+ unsigned long flags;
TRACE(("gdth_putq() priority %d\n",priority));
spin_lock_irqsave(&ha->smp_lock, flags);
@@ -2023,7 +2023,7 @@ static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority)
++flags;
if (max_rq < flags) {
max_rq = flags;
- TRACE3(("GDT: max_rq = %d\n",(ushort)max_rq));
+ TRACE3(("GDT: max_rq = %d\n",(u16)max_rq));
}
#endif
}
@@ -2032,9 +2032,9 @@ static void gdth_next(gdth_ha_str *ha)
{
register Scsi_Cmnd *pscp;
register Scsi_Cmnd *nscp;
- unchar b, t, l, firsttime;
- unchar this_cmd, next_cmd;
- ulong flags = 0;
+ u8 b, t, l, firsttime;
+ u8 this_cmd, next_cmd;
+ unsigned long flags = 0;
int cmd_index;
TRACE(("gdth_next() hanum %d\n", ha->hanum));
@@ -2282,20 +2282,20 @@ static void gdth_next(gdth_ha_str *ha)
* buffers, kmap_atomic() as needed.
*/
static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
- char *buffer, ushort count)
+ char *buffer, u16 count)
{
- ushort cpcount,i, max_sg = scsi_sg_count(scp);
- ushort cpsum,cpnow;
+ u16 cpcount,i, max_sg = scsi_sg_count(scp);
+ u16 cpsum,cpnow;
struct scatterlist *sl;
char *address;
- cpcount = min_t(ushort, count, scsi_bufflen(scp));
+ cpcount = min_t(u16, count, scsi_bufflen(scp));
if (cpcount) {
cpsum=0;
scsi_for_each_sg(scp, sl, max_sg, i) {
unsigned long flags;
- cpnow = (ushort)sl->length;
+ cpnow = (u16)sl->length;
TRACE(("copy_internal() now %d sum %d count %d %d\n",
cpnow, cpsum, cpcount, scsi_bufflen(scp)));
if (cpsum+cpnow > cpcount)
@@ -2325,7 +2325,7 @@ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
{
- unchar t;
+ u8 t;
gdth_inq_data inq;
gdth_rdcap_data rdc;
gdth_sense_data sd;
@@ -2389,7 +2389,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
case READ_CAPACITY:
TRACE2(("Read capacity hdrive %d\n",t));
- if (ha->hdr[t].size > (ulong64)0xffffffff)
+ if (ha->hdr[t].size > (u64)0xffffffff)
rdc.last_block_no = 0xffffffff;
else
rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1);
@@ -2425,12 +2425,12 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
return 0;
}
-static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive)
+static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u16 hdrive)
{
register gdth_cmd_str *cmdp;
struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
- ulong32 cnt, blockcnt;
- ulong64 no, blockno;
+ u32 cnt, blockcnt;
+ u64 no, blockno;
int i, cmd_index, read_write, sgcnt, mode64;
cmdp = ha->pccb;
@@ -2498,17 +2498,17 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive)
if (read_write) {
if (scp->cmd_len == 16) {
- memcpy(&no, &scp->cmnd[2], sizeof(ulong64));
+ memcpy(&no, &scp->cmnd[2], sizeof(u64));
blockno = be64_to_cpu(no);
- memcpy(&cnt, &scp->cmnd[10], sizeof(ulong32));
+ memcpy(&cnt, &scp->cmnd[10], sizeof(u32));
blockcnt = be32_to_cpu(cnt);
} else if (scp->cmd_len == 10) {
- memcpy(&no, &scp->cmnd[2], sizeof(ulong32));
+ memcpy(&no, &scp->cmnd[2], sizeof(u32));
blockno = be32_to_cpu(no);
- memcpy(&cnt, &scp->cmnd[7], sizeof(ushort));
+ memcpy(&cnt, &scp->cmnd[7], sizeof(u16));
blockcnt = be16_to_cpu(cnt);
} else {
- memcpy(&no, &scp->cmnd[0], sizeof(ulong32));
+ memcpy(&no, &scp->cmnd[0], sizeof(u32));
blockno = be32_to_cpu(no) & 0x001fffffUL;
blockcnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4];
}
@@ -2516,7 +2516,7 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive)
cmdp->u.cache64.BlockNo = blockno;
cmdp->u.cache64.BlockCnt = blockcnt;
} else {
- cmdp->u.cache.BlockNo = (ulong32)blockno;
+ cmdp->u.cache.BlockNo = (u32)blockno;
cmdp->u.cache.BlockCnt = blockcnt;
}
@@ -2528,12 +2528,12 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive)
if (mode64) {
struct scatterlist *sl;
- cmdp->u.cache64.DestAddr= (ulong64)-1;
+ cmdp->u.cache64.DestAddr= (u64)-1;
cmdp->u.cache64.sg_canz = sgcnt;
scsi_for_each_sg(scp, sl, sgcnt, i) {
cmdp->u.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl);
#ifdef GDTH_DMA_STATISTICS
- if (cmdp->u.cache64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
+ if (cmdp->u.cache64.sg_lst[i].sg_ptr > (u64)0xffffffff)
ha->dma64_cnt++;
else
ha->dma32_cnt++;
@@ -2555,8 +2555,8 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive)
}
#ifdef GDTH_STATISTICS
- if (max_sg < (ulong32)sgcnt) {
- max_sg = (ulong32)sgcnt;
+ if (max_sg < (u32)sgcnt) {
+ max_sg = (u32)sgcnt;
TRACE3(("GDT: max_sg = %d\n",max_sg));
}
#endif
@@ -2572,7 +2572,7 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive)
TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n",
cmdp->OpCode,cmdp->u.cache64.BlockNo,cmdp->u.cache64.BlockCnt));
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) +
- (ushort)cmdp->u.cache64.sg_canz * sizeof(gdth_sg64_str);
+ (u16)cmdp->u.cache64.sg_canz * sizeof(gdth_sg64_str);
} else {
TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz,
@@ -2581,7 +2581,7 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive)
TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n",
cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt));
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) +
- (ushort)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str);
+ (u16)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str);
}
if (ha->cmd_len & 3)
ha->cmd_len += (4 - (ha->cmd_len & 3));
@@ -2600,15 +2600,15 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive)
return cmd_index;
}
-static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b)
+static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 b)
{
register gdth_cmd_str *cmdp;
- ushort i;
+ u16 i;
dma_addr_t sense_paddr;
int cmd_index, sgcnt, mode64;
- unchar t,l;
+ u8 t,l;
struct page *page;
- ulong offset;
+ unsigned long offset;
struct gdth_cmndinfo *cmndinfo;
t = scp->device->id;
@@ -2654,7 +2654,7 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b)
} else {
page = virt_to_page(scp->sense_buffer);
- offset = (ulong)scp->sense_buffer & ~PAGE_MASK;
+ offset = (unsigned long)scp->sense_buffer & ~PAGE_MASK;
sense_paddr = pci_map_page(ha->pdev,page,offset,
16,PCI_DMA_FROMDEVICE);
@@ -2703,12 +2703,12 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b)
if (mode64) {
struct scatterlist *sl;
- cmdp->u.raw64.sdata = (ulong64)-1;
+ cmdp->u.raw64.sdata = (u64)-1;
cmdp->u.raw64.sg_ranz = sgcnt;
scsi_for_each_sg(scp, sl, sgcnt, i) {
cmdp->u.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl);
#ifdef GDTH_DMA_STATISTICS
- if (cmdp->u.raw64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
+ if (cmdp->u.raw64.sg_lst[i].sg_ptr > (u64)0xffffffff)
ha->dma64_cnt++;
else
ha->dma32_cnt++;
@@ -2744,7 +2744,7 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b)
cmdp->u.raw64.sg_lst[0].sg_len));
/* evaluate command size */
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) +
- (ushort)cmdp->u.raw64.sg_ranz * sizeof(gdth_sg64_str);
+ (u16)cmdp->u.raw64.sg_ranz * sizeof(gdth_sg64_str);
} else {
TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz,
@@ -2752,7 +2752,7 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b)
cmdp->u.raw.sg_lst[0].sg_len));
/* evaluate command size */
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) +
- (ushort)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str);
+ (u16)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str);
}
}
/* check space */
@@ -2802,7 +2802,7 @@ static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
if (cmdp->OpCode == GDT_IOCTL) {
TRACE2(("IOCTL\n"));
ha->cmd_len =
- GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(ulong64);
+ GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(u64);
} else if (cmdp->Service == CACHESERVICE) {
TRACE2(("cache command %d\n",cmdp->OpCode));
if (ha->cache_feat & GDT_64BIT)
@@ -2840,8 +2840,8 @@ static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
/* Controller event handling functions */
-static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source,
- ushort idx, gdth_evt_data *evt)
+static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source,
+ u16 idx, gdth_evt_data *evt)
{
gdth_evt_str *e;
struct timeval tv;
@@ -2890,7 +2890,7 @@ static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr)
{
gdth_evt_str *e;
int eindex;
- ulong flags;
+ unsigned long flags;
TRACE2(("gdth_read_event() handle %d\n", handle));
spin_lock_irqsave(&ha->smp_lock, flags);
@@ -2919,12 +2919,12 @@ static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr)
}
static void gdth_readapp_event(gdth_ha_str *ha,
- unchar application, gdth_evt_str *estr)
+ u8 application, gdth_evt_str *estr)
{
gdth_evt_str *e;
int eindex;
- ulong flags;
- unchar found = FALSE;
+ unsigned long flags;
+ u8 found = FALSE;
TRACE2(("gdth_readapp_event() app. %d\n", application));
spin_lock_irqsave(&ha->smp_lock, flags);
@@ -2969,9 +2969,9 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha,
gdt2_dpram_str __iomem *dp2_ptr;
Scsi_Cmnd *scp;
int rval, i;
- unchar IStatus;
- ushort Service;
- ulong flags = 0;
+ u8 IStatus;
+ u16 Service;
+ unsigned long flags = 0;
#ifdef INT_COAL
int coalesced = FALSE;
int next = FALSE;
@@ -3018,7 +3018,7 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha,
if (coalesced) {
/* For coalesced requests all status
information is found in the status buffer */
- IStatus = (unchar)(pcs->status & 0xff);
+ IStatus = (u8)(pcs->status & 0xff);
}
#endif
@@ -3197,7 +3197,7 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha,
++act_int_coal;
if (act_int_coal > max_int_coal) {
max_int_coal = act_int_coal;
- printk("GDT: max_int_coal = %d\n",(ushort)max_int_coal);
+ printk("GDT: max_int_coal = %d\n",(u16)max_int_coal);
}
#endif
/* see if there is another status */
@@ -3225,12 +3225,12 @@ static irqreturn_t gdth_interrupt(int irq, void *dev_id)
return __gdth_interrupt(ha, false, NULL);
}
-static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
+static int gdth_sync_event(gdth_ha_str *ha, int service, u8 index,
Scsi_Cmnd *scp)
{
gdth_msg_str *msg;
gdth_cmd_str *cmdp;
- unchar b, t;
+ u8 b, t;
struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
cmdp = ha->pccb;
@@ -3263,7 +3263,7 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
cmdp->u.screen.su.msg.msg_addr = ha->msg_phys;
ha->cmd_offs_dpmem = 0;
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr)
- + sizeof(ulong64);
+ + sizeof(u64);
ha->cmd_cnt = 0;
gdth_copy_command(ha);
gdth_release_event(ha);
@@ -3297,7 +3297,7 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
cmdp->u.screen.su.msg.msg_addr = ha->msg_phys;
ha->cmd_offs_dpmem = 0;
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr)
- + sizeof(ulong64);
+ + sizeof(u64);
ha->cmd_cnt = 0;
gdth_copy_command(ha);
gdth_release_event(ha);
@@ -3335,7 +3335,7 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
cmndinfo->OpCode));
/* special commands GDT_CLUST_INFO/GDT_MOUNT ? */
if (cmndinfo->OpCode == GDT_CLUST_INFO) {
- ha->hdr[t].cluster_type = (unchar)ha->info;
+ ha->hdr[t].cluster_type = (u8)ha->info;
if (!(ha->hdr[t].cluster_type &
CLUSTER_MOUNTED)) {
/* NOT MOUNTED -> MOUNT */
@@ -3397,7 +3397,7 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
ha->hdr[t].cluster_type &= ~CLUSTER_RESERVED;
}
memset((char*)scp->sense_buffer,0,16);
- if (ha->status == (ushort)S_CACHE_RESERV) {
+ if (ha->status == (u16)S_CACHE_RESERV) {
scp->result = (DID_OK << 16) | (RESERVATION_CONFLICT << 1);
} else {
scp->sense_buffer[0] = 0x70;
@@ -3614,16 +3614,16 @@ static int gdth_async_event(gdth_ha_str *ha)
cmdp->u.screen.su.msg.msg_addr = ha->msg_phys;
ha->cmd_offs_dpmem = 0;
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr)
- + sizeof(ulong64);
+ + sizeof(u64);
ha->cmd_cnt = 0;
gdth_copy_command(ha);
if (ha->type == GDT_EISA)
- printk("[EISA slot %d] ",(ushort)ha->brd_phys);
+ printk("[EISA slot %d] ",(u16)ha->brd_phys);
else if (ha->type == GDT_ISA)
- printk("[DPMEM 0x%4X] ",(ushort)ha->brd_phys);
+ printk("[DPMEM 0x%4X] ",(u16)ha->brd_phys);
else
- printk("[PCI %d/%d] ",(ushort)(ha->brd_phys>>8),
- (ushort)((ha->brd_phys>>3)&0x1f));
+ printk("[PCI %d/%d] ",(u16)(ha->brd_phys>>8),
+ (u16)((ha->brd_phys>>3)&0x1f));
gdth_release_event(ha);
}
@@ -3640,7 +3640,7 @@ static int gdth_async_event(gdth_ha_str *ha)
ha->dvr.eu.async.service = ha->service;
ha->dvr.eu.async.status = ha->status;
ha->dvr.eu.async.info = ha->info;
- *(ulong32 *)ha->dvr.eu.async.scsi_coord = ha->info2;
+ *(u32 *)ha->dvr.eu.async.scsi_coord = ha->info2;
}
gdth_store_event( ha, ES_ASYNC, ha->service, &ha->dvr );
gdth_log_event( &ha->dvr, NULL );
@@ -3648,8 +3648,8 @@ static int gdth_async_event(gdth_ha_str *ha)
/* new host drive from expand? */
if (ha->service == CACHESERVICE && ha->status == 56) {
TRACE2(("gdth_async_event(): new host drive %d created\n",
- (ushort)ha->info));
- /* gdth_analyse_hdrive(hanum, (ushort)ha->info); */
+ (u16)ha->info));
+ /* gdth_analyse_hdrive(hanum, (u16)ha->info); */
}
}
return 1;
@@ -3680,13 +3680,13 @@ static void gdth_log_event(gdth_evt_data *dvr, char *buffer)
for (j=0,i=1; i < f[0]; i+=2) {
switch (f[i+1]) {
case 4:
- stack.b[j++] = *(ulong32*)&dvr->eu.stream[(int)f[i]];
+ stack.b[j++] = *(u32*)&dvr->eu.stream[(int)f[i]];
break;
case 2:
- stack.b[j++] = *(ushort*)&dvr->eu.stream[(int)f[i]];
+ stack.b[j++] = *(u16*)&dvr->eu.stream[(int)f[i]];
break;
case 1:
- stack.b[j++] = *(unchar*)&dvr->eu.stream[(int)f[i]];
+ stack.b[j++] = *(u8*)&dvr->eu.stream[(int)f[i]];
break;
default:
break;
@@ -3712,14 +3712,14 @@ static void gdth_log_event(gdth_evt_data *dvr, char *buffer)
}
#ifdef GDTH_STATISTICS
-static unchar gdth_timer_running;
+static u8 gdth_timer_running;
-static void gdth_timeout(ulong data)
+static void gdth_timeout(unsigned long data)
{
- ulong32 i;
+ u32 i;
Scsi_Cmnd *nscp;
gdth_ha_str *ha;
- ulong flags;
+ unsigned long flags;
if(unlikely(list_empty(&gdth_instances))) {
gdth_timer_running = 0;
@@ -3891,8 +3891,8 @@ static enum blk_eh_timer_return gdth_timed_out(struct scsi_cmnd *scp)
{
gdth_ha_str *ha = shost_priv(scp->device->host);
struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
- unchar b, t;
- ulong flags;
+ u8 b, t;
+ unsigned long flags;
enum blk_eh_timer_return retval = BLK_EH_NOT_HANDLED;
TRACE(("%s() cmd 0x%x\n", scp->cmnd[0], __func__));
@@ -3924,9 +3924,9 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
{
gdth_ha_str *ha = shost_priv(scp->device->host);
int i;
- ulong flags;
+ unsigned long flags;
Scsi_Cmnd *cmnd;
- unchar b;
+ u8 b;
TRACE2(("gdth_eh_bus_reset()\n"));
@@ -3974,7 +3974,7 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
static int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip)
{
- unchar b, t;
+ u8 b, t;
gdth_ha_str *ha = shost_priv(sdev->host);
struct scsi_device *sd;
unsigned capacity;
@@ -4062,7 +4062,7 @@ static int ioc_event(void __user *arg)
{
gdth_ioctl_event evt;
gdth_ha_str *ha;
- ulong flags;
+ unsigned long flags;
if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event)))
return -EFAULT;
@@ -4098,8 +4098,8 @@ static int ioc_event(void __user *arg)
static int ioc_lockdrv(void __user *arg)
{
gdth_ioctl_lockdrv ldrv;
- unchar i, j;
- ulong flags;
+ u8 i, j;
+ unsigned long flags;
gdth_ha_str *ha;
if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv)))
@@ -4165,7 +4165,7 @@ static int ioc_general(void __user *arg, char *cmnd)
{
gdth_ioctl_general gen;
char *buf = NULL;
- ulong64 paddr;
+ u64 paddr;
gdth_ha_str *ha;
int rval;
@@ -4194,7 +4194,7 @@ static int ioc_general(void __user *arg, char *cmnd)
gen.command.u.cache64.DeviceNo = gen.command.u.cache.DeviceNo;
/* addresses */
if (ha->cache_feat & SCATTER_GATHER) {
- gen.command.u.cache64.DestAddr = (ulong64)-1;
+ gen.command.u.cache64.DestAddr = (u64)-1;
gen.command.u.cache64.sg_canz = 1;
gen.command.u.cache64.sg_lst[0].sg_ptr = paddr;
gen.command.u.cache64.sg_lst[0].sg_len = gen.data_len;
@@ -4207,7 +4207,7 @@ static int ioc_general(void __user *arg, char *cmnd)
if (ha->cache_feat & SCATTER_GATHER) {
gen.command.u.cache.DestAddr = 0xffffffff;
gen.command.u.cache.sg_canz = 1;
- gen.command.u.cache.sg_lst[0].sg_ptr = (ulong32)paddr;
+ gen.command.u.cache.sg_lst[0].sg_ptr = (u32)paddr;
gen.command.u.cache.sg_lst[0].sg_len = gen.data_len;
gen.command.u.cache.sg_lst[1].sg_len = 0;
} else {
@@ -4230,7 +4230,7 @@ static int ioc_general(void __user *arg, char *cmnd)
gen.command.u.raw64.direction = gen.command.u.raw.direction;
/* addresses */
if (ha->raw_feat & SCATTER_GATHER) {
- gen.command.u.raw64.sdata = (ulong64)-1;
+ gen.command.u.raw64.sdata = (u64)-1;
gen.command.u.raw64.sg_ranz = 1;
gen.command.u.raw64.sg_lst[0].sg_ptr = paddr;
gen.command.u.raw64.sg_lst[0].sg_len = gen.data_len;
@@ -4244,14 +4244,14 @@ static int ioc_general(void __user *arg, char *cmnd)
if (ha->raw_feat & SCATTER_GATHER) {
gen.command.u.raw.sdata = 0xffffffff;
gen.command.u.raw.sg_ranz = 1;
- gen.command.u.raw.sg_lst[0].sg_ptr = (ulong32)paddr;
+ gen.command.u.raw.sg_lst[0].sg_ptr = (u32)paddr;
gen.command.u.raw.sg_lst[0].sg_len = gen.data_len;
gen.command.u.raw.sg_lst[1].sg_len = 0;
} else {
gen.command.u.raw.sdata = paddr;
gen.command.u.raw.sg_ranz = 0;
}
- gen.command.u.raw.sense_data = (ulong32)paddr + gen.data_len;
+ gen.command.u.raw.sense_data = (u32)paddr + gen.data_len;
}
} else {
gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
@@ -4283,7 +4283,7 @@ static int ioc_hdrlist(void __user *arg, char *cmnd)
gdth_ioctl_rescan *rsc;
gdth_cmd_str *cmd;
gdth_ha_str *ha;
- unchar i;
+ u8 i;
int rc = -ENOMEM;
u32 cluster_type = 0;
@@ -4335,11 +4335,11 @@ static int ioc_rescan(void __user *arg, char *cmnd)
{
gdth_ioctl_rescan *rsc;
gdth_cmd_str *cmd;
- ushort i, status, hdr_cnt;
- ulong32 info;
+ u16 i, status, hdr_cnt;
+ u32 info;
int cyls, hds, secs;
int rc = -ENOMEM;
- ulong flags;
+ unsigned long flags;
gdth_ha_str *ha;
rsc = kmalloc(sizeof(*rsc), GFP_KERNEL);
@@ -4367,7 +4367,7 @@ static int ioc_rescan(void __user *arg, char *cmnd)
status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info);
i = 0;
- hdr_cnt = (status == S_OK ? (ushort)info : 0);
+ hdr_cnt = (status == S_OK ? (u16)info : 0);
} else {
i = rsc->hdr_no;
hdr_cnt = i + 1;
@@ -4418,7 +4418,7 @@ static int ioc_rescan(void __user *arg, char *cmnd)
status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info);
spin_lock_irqsave(&ha->smp_lock, flags);
- ha->hdr[i].devtype = (status == S_OK ? (ushort)info : 0);
+ ha->hdr[i].devtype = (status == S_OK ? (u16)info : 0);
spin_unlock_irqrestore(&ha->smp_lock, flags);
cmd->Service = CACHESERVICE;
@@ -4432,7 +4432,7 @@ static int ioc_rescan(void __user *arg, char *cmnd)
spin_lock_irqsave(&ha->smp_lock, flags);
ha->hdr[i].cluster_type =
- ((status == S_OK && !shared_access) ? (ushort)info : 0);
+ ((status == S_OK && !shared_access) ? (u16)info : 0);
spin_unlock_irqrestore(&ha->smp_lock, flags);
rsc->hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
@@ -4446,7 +4446,7 @@ static int ioc_rescan(void __user *arg, char *cmnd)
status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info);
spin_lock_irqsave(&ha->smp_lock, flags);
- ha->hdr[i].rw_attribs = (status == S_OK ? (ushort)info : 0);
+ ha->hdr[i].rw_attribs = (status == S_OK ? (u16)info : 0);
spin_unlock_irqrestore(&ha->smp_lock, flags);
}
@@ -4466,7 +4466,7 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
{
gdth_ha_str *ha;
Scsi_Cmnd *scp;
- ulong flags;
+ unsigned long flags;
char cmnd[MAX_COMMAND_SIZE];
void __user *argp = (void __user *)arg;
@@ -4495,9 +4495,9 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
{
gdth_ioctl_osvers osv;
- osv.version = (unchar)(LINUX_VERSION_CODE >> 16);
- osv.subversion = (unchar)(LINUX_VERSION_CODE >> 8);
- osv.revision = (ushort)(LINUX_VERSION_CODE & 0xff);
+ osv.version = (u8)(LINUX_VERSION_CODE >> 16);
+ osv.subversion = (u8)(LINUX_VERSION_CODE >> 8);
+ osv.revision = (u16)(LINUX_VERSION_CODE & 0xff);
if (copy_to_user(argp, &osv, sizeof(gdth_ioctl_osvers)))
return -EFAULT;
break;
@@ -4512,10 +4512,10 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
return -EFAULT;
if (ha->type == GDT_ISA || ha->type == GDT_EISA) {
- ctrt.type = (unchar)((ha->stype>>20) - 0x10);
+ ctrt.type = (u8)((ha->stype>>20) - 0x10);
} else {
if (ha->type != GDT_PCIMPR) {
- ctrt.type = (unchar)((ha->stype<<4) + 6);
+ ctrt.type = (u8)((ha->stype<<4) + 6);
} else {
ctrt.type =
(ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe);
@@ -4546,7 +4546,7 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
case GDTIOCTL_LOCKCHN:
{
gdth_ioctl_lockchn lchn;
- unchar i, j;
+ u8 i, j;
if (copy_from_user(&lchn, argp, sizeof(gdth_ioctl_lockchn)) ||
(NULL == (ha = gdth_find_ha(lchn.ionode))))
@@ -4670,7 +4670,7 @@ static struct scsi_host_template gdth_template = {
};
#ifdef CONFIG_ISA
-static int __init gdth_isa_probe_one(ulong32 isa_bios)
+static int __init gdth_isa_probe_one(u32 isa_bios)
{
struct Scsi_Host *shp;
gdth_ha_str *ha;
@@ -4802,7 +4802,7 @@ static int __init gdth_isa_probe_one(ulong32 isa_bios)
#endif /* CONFIG_ISA */
#ifdef CONFIG_EISA
-static int __init gdth_eisa_probe_one(ushort eisa_slot)
+static int __init gdth_eisa_probe_one(u16 eisa_slot)
{
struct Scsi_Host *shp;
gdth_ha_str *ha;
@@ -5120,7 +5120,7 @@ static void gdth_remove_one(gdth_ha_str *ha)
scsi_host_put(shp);
}
-static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
+static int gdth_halt(struct notifier_block *nb, unsigned long event, void *buf)
{
gdth_ha_str *ha;
@@ -5158,14 +5158,14 @@ static int __init gdth_init(void)
if (probe_eisa_isa) {
/* scanning for controllers, at first: ISA controller */
#ifdef CONFIG_ISA
- ulong32 isa_bios;
+ u32 isa_bios;
for (isa_bios = 0xc8000UL; isa_bios <= 0xd8000UL;
isa_bios += 0x8000UL)
gdth_isa_probe_one(isa_bios);
#endif
#ifdef CONFIG_EISA
{
- ushort eisa_slot;
+ u16 eisa_slot;
for (eisa_slot = 0x1000; eisa_slot <= 0x8000;
eisa_slot += 0x1000)
gdth_eisa_probe_one(eisa_slot);
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index 1646444e9bd5..120a0625a7b5 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -321,524 +321,524 @@
/* screenservice message */
typedef struct {
- ulong32 msg_handle; /* message handle */
- ulong32 msg_len; /* size of message */
- ulong32 msg_alen; /* answer length */
- unchar msg_answer; /* answer flag */
- unchar msg_ext; /* more messages */
- unchar msg_reserved[2];
+ u32 msg_handle; /* message handle */
+ u32 msg_len; /* size of message */
+ u32 msg_alen; /* answer length */
+ u8 msg_answer; /* answer flag */
+ u8 msg_ext; /* more messages */
+ u8 msg_reserved[2];
char msg_text[MSGLEN+2]; /* the message text */
-} PACKED gdth_msg_str;
+} __attribute__((packed)) gdth_msg_str;
/* IOCTL data structures */
/* Status coalescing buffer for returning multiple requests per interrupt */
typedef struct {
- ulong32 status;
- ulong32 ext_status;
- ulong32 info0;
- ulong32 info1;
-} PACKED gdth_coal_status;
+ u32 status;
+ u32 ext_status;
+ u32 info0;
+ u32 info1;
+} __attribute__((packed)) gdth_coal_status;
/* performance mode data structure */
typedef struct {
- ulong32 version; /* The version of this IOCTL structure. */
- ulong32 st_mode; /* 0=dis., 1=st_buf_addr1 valid, 2=both */
- ulong32 st_buff_addr1; /* physical address of status buffer 1 */
- ulong32 st_buff_u_addr1; /* reserved for 64 bit addressing */
- ulong32 st_buff_indx1; /* reserved command idx. for this buffer */
- ulong32 st_buff_addr2; /* physical address of status buffer 1 */
- ulong32 st_buff_u_addr2; /* reserved for 64 bit addressing */
- ulong32 st_buff_indx2; /* reserved command idx. for this buffer */
- ulong32 st_buff_size; /* size of each buffer in bytes */
- ulong32 cmd_mode; /* 0 = mode disabled, 1 = cmd_buff_addr1 */
- ulong32 cmd_buff_addr1; /* physical address of cmd buffer 1 */
- ulong32 cmd_buff_u_addr1; /* reserved for 64 bit addressing */
- ulong32 cmd_buff_indx1; /* cmd buf addr1 unique identifier */
- ulong32 cmd_buff_addr2; /* physical address of cmd buffer 1 */
- ulong32 cmd_buff_u_addr2; /* reserved for 64 bit addressing */
- ulong32 cmd_buff_indx2; /* cmd buf addr1 unique identifier */
- ulong32 cmd_buff_size; /* size of each cmd bufer in bytes */
- ulong32 reserved1;
- ulong32 reserved2;
-} PACKED gdth_perf_modes;
+ u32 version; /* The version of this IOCTL structure. */
+ u32 st_mode; /* 0=dis., 1=st_buf_addr1 valid, 2=both */
+ u32 st_buff_addr1; /* physical address of status buffer 1 */
+ u32 st_buff_u_addr1; /* reserved for 64 bit addressing */
+ u32 st_buff_indx1; /* reserved command idx. for this buffer */
+ u32 st_buff_addr2; /* physical address of status buffer 1 */
+ u32 st_buff_u_addr2; /* reserved for 64 bit addressing */
+ u32 st_buff_indx2; /* reserved command idx. for this buffer */
+ u32 st_buff_size; /* size of each buffer in bytes */
+ u32 cmd_mode; /* 0 = mode disabled, 1 = cmd_buff_addr1 */
+ u32 cmd_buff_addr1; /* physical address of cmd buffer 1 */
+ u32 cmd_buff_u_addr1; /* reserved for 64 bit addressing */
+ u32 cmd_buff_indx1; /* cmd buf addr1 unique identifier */
+ u32 cmd_buff_addr2; /* physical address of cmd buffer 1 */
+ u32 cmd_buff_u_addr2; /* reserved for 64 bit addressing */
+ u32 cmd_buff_indx2; /* cmd buf addr1 unique identifier */
+ u32 cmd_buff_size; /* size of each cmd bufer in bytes */
+ u32 reserved1;
+ u32 reserved2;
+} __attribute__((packed)) gdth_perf_modes;
/* SCSI drive info */
typedef struct {
- unchar vendor[8]; /* vendor string */
- unchar product[16]; /* product string */
- unchar revision[4]; /* revision */
- ulong32 sy_rate; /* current rate for sync. tr. */
- ulong32 sy_max_rate; /* max. rate for sync. tr. */
- ulong32 no_ldrive; /* belongs to this log. drv.*/
- ulong32 blkcnt; /* number of blocks */
- ushort blksize; /* size of block in bytes */
- unchar available; /* flag: access is available */
- unchar init; /* medium is initialized */
- unchar devtype; /* SCSI devicetype */
- unchar rm_medium; /* medium is removable */
- unchar wp_medium; /* medium is write protected */
- unchar ansi; /* SCSI I/II or III? */
- unchar protocol; /* same as ansi */
- unchar sync; /* flag: sync. transfer enab. */
- unchar disc; /* flag: disconnect enabled */
- unchar queueing; /* flag: command queing enab. */
- unchar cached; /* flag: caching enabled */
- unchar target_id; /* target ID of device */
- unchar lun; /* LUN id of device */
- unchar orphan; /* flag: drive fragment */
- ulong32 last_error; /* sense key or drive state */
- ulong32 last_result; /* result of last command */
- ulong32 check_errors; /* err. in last surface check */
- unchar percent; /* progress for surface check */
- unchar last_check; /* IOCTRL operation */
- unchar res[2];
- ulong32 flags; /* from 1.19/2.19: raw reserv.*/
- unchar multi_bus; /* multi bus dev? (fibre ch.) */
- unchar mb_status; /* status: available? */
- unchar res2[2];
- unchar mb_alt_status; /* status on second bus */
- unchar mb_alt_bid; /* number of second bus */
- unchar mb_alt_tid; /* target id on second bus */
- unchar res3;
- unchar fc_flag; /* from 1.22/2.22: info valid?*/
- unchar res4;
- ushort fc_frame_size; /* frame size (bytes) */
+ u8 vendor[8]; /* vendor string */
+ u8 product[16]; /* product string */
+ u8 revision[4]; /* revision */
+ u32 sy_rate; /* current rate for sync. tr. */
+ u32 sy_max_rate; /* max. rate for sync. tr. */
+ u32 no_ldrive; /* belongs to this log. drv.*/
+ u32 blkcnt; /* number of blocks */
+ u16 blksize; /* size of block in bytes */
+ u8 available; /* flag: access is available */
+ u8 init; /* medium is initialized */
+ u8 devtype; /* SCSI devicetype */
+ u8 rm_medium; /* medium is removable */
+ u8 wp_medium; /* medium is write protected */
+ u8 ansi; /* SCSI I/II or III? */
+ u8 protocol; /* same as ansi */
+ u8 sync; /* flag: sync. transfer enab. */
+ u8 disc; /* flag: disconnect enabled */
+ u8 queueing; /* flag: command queing enab. */
+ u8 cached; /* flag: caching enabled */
+ u8 target_id; /* target ID of device */
+ u8 lun; /* LUN id of device */
+ u8 orphan; /* flag: drive fragment */
+ u32 last_error; /* sense key or drive state */
+ u32 last_result; /* result of last command */
+ u32 check_errors; /* err. in last surface check */
+ u8 percent; /* progress for surface check */
+ u8 last_check; /* IOCTRL operation */
+ u8 res[2];
+ u32 flags; /* from 1.19/2.19: raw reserv.*/
+ u8 multi_bus; /* multi bus dev? (fibre ch.) */
+ u8 mb_status; /* status: available? */
+ u8 res2[2];
+ u8 mb_alt_status; /* status on second bus */
+ u8 mb_alt_bid; /* number of second bus */
+ u8 mb_alt_tid; /* target id on second bus */
+ u8 res3;
+ u8 fc_flag; /* from 1.22/2.22: info valid?*/
+ u8 res4;
+ u16 fc_frame_size; /* frame size (bytes) */
char wwn[8]; /* world wide name */
-} PACKED gdth_diskinfo_str;
+} __attribute__((packed)) gdth_diskinfo_str;
/* get SCSI channel count */
typedef struct {
- ulong32 channel_no; /* number of channel */
- ulong32 drive_cnt; /* drive count */
- unchar siop_id; /* SCSI processor ID */
- unchar siop_state; /* SCSI processor state */
-} PACKED gdth_getch_str;
+ u32 channel_no; /* number of channel */
+ u32 drive_cnt; /* drive count */
+ u8 siop_id; /* SCSI processor ID */
+ u8 siop_state; /* SCSI processor state */
+} __attribute__((packed)) gdth_getch_str;
/* get SCSI drive numbers */
typedef struct {
- ulong32 sc_no; /* SCSI channel */
- ulong32 sc_cnt; /* sc_list[] elements */
- ulong32 sc_list[MAXID]; /* minor device numbers */
-} PACKED gdth_drlist_str;
+ u32 sc_no; /* SCSI channel */
+ u32 sc_cnt; /* sc_list[] elements */
+ u32 sc_list[MAXID]; /* minor device numbers */
+} __attribute__((packed)) gdth_drlist_str;
/* get grown/primary defect count */
typedef struct {
- unchar sddc_type; /* 0x08: grown, 0x10: prim. */
- unchar sddc_format; /* list entry format */
- unchar sddc_len; /* list entry length */
- unchar sddc_res;
- ulong32 sddc_cnt; /* entry count */
-} PACKED gdth_defcnt_str;
+ u8 sddc_type; /* 0x08: grown, 0x10: prim. */
+ u8 sddc_format; /* list entry format */
+ u8 sddc_len; /* list entry length */
+ u8 sddc_res;
+ u32 sddc_cnt; /* entry count */
+} __attribute__((packed)) gdth_defcnt_str;
/* disk statistics */
typedef struct {
- ulong32 bid; /* SCSI channel */
- ulong32 first; /* first SCSI disk */
- ulong32 entries; /* number of elements */
- ulong32 count; /* (R) number of init. el. */
- ulong32 mon_time; /* time stamp */
+ u32 bid; /* SCSI channel */
+ u32 first; /* first SCSI disk */
+ u32 entries; /* number of elements */
+ u32 count; /* (R) number of init. el. */
+ u32 mon_time; /* time stamp */
struct {
- unchar tid; /* target ID */
- unchar lun; /* LUN */
- unchar res[2];
- ulong32 blk_size; /* block size in bytes */
- ulong32 rd_count; /* bytes read */
- ulong32 wr_count; /* bytes written */
- ulong32 rd_blk_count; /* blocks read */
- ulong32 wr_blk_count; /* blocks written */
- ulong32 retries; /* retries */
- ulong32 reassigns; /* reassigns */
- } PACKED list[1];
-} PACKED gdth_dskstat_str;
+ u8 tid; /* target ID */
+ u8 lun; /* LUN */
+ u8 res[2];
+ u32 blk_size; /* block size in bytes */
+ u32 rd_count; /* bytes read */
+ u32 wr_count; /* bytes written */
+ u32 rd_blk_count; /* blocks read */
+ u32 wr_blk_count; /* blocks written */
+ u32 retries; /* retries */
+ u32 reassigns; /* reassigns */
+ } __attribute__((packed)) list[1];
+} __attribute__((packed)) gdth_dskstat_str;
/* IO channel header */
typedef struct {
- ulong32 version; /* version (-1UL: newest) */
- unchar list_entries; /* list entry count */
- unchar first_chan; /* first channel number */
- unchar last_chan; /* last channel number */
- unchar chan_count; /* (R) channel count */
- ulong32 list_offset; /* offset of list[0] */
-} PACKED gdth_iochan_header;
+ u32 version; /* version (-1UL: newest) */
+ u8 list_entries; /* list entry count */
+ u8 first_chan; /* first channel number */
+ u8 last_chan; /* last channel number */
+ u8 chan_count; /* (R) channel count */
+ u32 list_offset; /* offset of list[0] */
+} __attribute__((packed)) gdth_iochan_header;
/* get IO channel description */
typedef struct {
gdth_iochan_header hdr;
struct {
- ulong32 address; /* channel address */
- unchar type; /* type (SCSI, FCAL) */
- unchar local_no; /* local number */
- ushort features; /* channel features */
- } PACKED list[MAXBUS];
-} PACKED gdth_iochan_str;
+ u32 address; /* channel address */
+ u8 type; /* type (SCSI, FCAL) */
+ u8 local_no; /* local number */
+ u16 features; /* channel features */
+ } __attribute__((packed)) list[MAXBUS];
+} __attribute__((packed)) gdth_iochan_str;
/* get raw IO channel description */
typedef struct {
gdth_iochan_header hdr;
struct {
- unchar proc_id; /* processor id */
- unchar proc_defect; /* defect ? */
- unchar reserved[2];
- } PACKED list[MAXBUS];
-} PACKED gdth_raw_iochan_str;
+ u8 proc_id; /* processor id */
+ u8 proc_defect; /* defect ? */
+ u8 reserved[2];
+ } __attribute__((packed)) list[MAXBUS];
+} __attribute__((packed)) gdth_raw_iochan_str;
/* array drive component */
typedef struct {
- ulong32 al_controller; /* controller ID */
- unchar al_cache_drive; /* cache drive number */
- unchar al_status; /* cache drive state */
- unchar al_res[2];
-} PACKED gdth_arraycomp_str;
+ u32 al_controller; /* controller ID */
+ u8 al_cache_drive; /* cache drive number */
+ u8 al_status; /* cache drive state */
+ u8 al_res[2];
+} __attribute__((packed)) gdth_arraycomp_str;
/* array drive information */
typedef struct {
- unchar ai_type; /* array type (RAID0,4,5) */
- unchar ai_cache_drive_cnt; /* active cachedrives */
- unchar ai_state; /* array drive state */
- unchar ai_master_cd; /* master cachedrive */
- ulong32 ai_master_controller; /* ID of master controller */
- ulong32 ai_size; /* user capacity [sectors] */
- ulong32 ai_striping_size; /* striping size [sectors] */
- ulong32 ai_secsize; /* sector size [bytes] */
- ulong32 ai_err_info; /* failed cache drive */
- unchar ai_name[8]; /* name of the array drive */
- unchar ai_controller_cnt; /* number of controllers */
- unchar ai_removable; /* flag: removable */
- unchar ai_write_protected; /* flag: write protected */
- unchar ai_devtype; /* type: always direct access */
+ u8 ai_type; /* array type (RAID0,4,5) */
+ u8 ai_cache_drive_cnt; /* active cachedrives */
+ u8 ai_state; /* array drive state */
+ u8 ai_master_cd; /* master cachedrive */
+ u32 ai_master_controller; /* ID of master controller */
+ u32 ai_size; /* user capacity [sectors] */
+ u32 ai_striping_size; /* striping size [sectors] */
+ u32 ai_secsize; /* sector size [bytes] */
+ u32 ai_err_info; /* failed cache drive */
+ u8 ai_name[8]; /* name of the array drive */
+ u8 ai_controller_cnt; /* number of controllers */
+ u8 ai_removable; /* flag: removable */
+ u8 ai_write_protected; /* flag: write protected */
+ u8 ai_devtype; /* type: always direct access */
gdth_arraycomp_str ai_drives[35]; /* drive components: */
- unchar ai_drive_entries; /* number of drive components */
- unchar ai_protected; /* protection flag */
- unchar ai_verify_state; /* state of a parity verify */
- unchar ai_ext_state; /* extended array drive state */
- unchar ai_expand_state; /* array expand state (>=2.18)*/
- unchar ai_reserved[3];
-} PACKED gdth_arrayinf_str;
+ u8 ai_drive_entries; /* number of drive components */
+ u8 ai_protected; /* protection flag */
+ u8 ai_verify_state; /* state of a parity verify */
+ u8 ai_ext_state; /* extended array drive state */
+ u8 ai_expand_state; /* array expand state (>=2.18)*/
+ u8 ai_reserved[3];
+} __attribute__((packed)) gdth_arrayinf_str;
/* get array drive list */
typedef struct {
- ulong32 controller_no; /* controller no. */
- unchar cd_handle; /* master cachedrive */
- unchar is_arrayd; /* Flag: is array drive? */
- unchar is_master; /* Flag: is array master? */
- unchar is_parity; /* Flag: is parity drive? */
- unchar is_hotfix; /* Flag: is hotfix drive? */
- unchar res[3];
-} PACKED gdth_alist_str;
+ u32 controller_no; /* controller no. */
+ u8 cd_handle; /* master cachedrive */
+ u8 is_arrayd; /* Flag: is array drive? */
+ u8 is_master; /* Flag: is array master? */
+ u8 is_parity; /* Flag: is parity drive? */
+ u8 is_hotfix; /* Flag: is hotfix drive? */
+ u8 res[3];
+} __attribute__((packed)) gdth_alist_str;
typedef struct {
- ulong32 entries_avail; /* allocated entries */
- ulong32 entries_init; /* returned entries */
- ulong32 first_entry; /* first entry number */
- ulong32 list_offset; /* offset of following list */
+ u32 entries_avail; /* allocated entries */
+ u32 entries_init; /* returned entries */
+ u32 first_entry; /* first entry number */
+ u32 list_offset; /* offset of following list */
gdth_alist_str list[1]; /* list */
-} PACKED gdth_arcdl_str;
+} __attribute__((packed)) gdth_arcdl_str;
/* cache info/config IOCTL */
typedef struct {
- ulong32 version; /* firmware version */
- ushort state; /* cache state (on/off) */
- ushort strategy; /* cache strategy */
- ushort write_back; /* write back state (on/off) */
- ushort block_size; /* cache block size */
-} PACKED gdth_cpar_str;
+ u32 version; /* firmware version */
+ u16 state; /* cache state (on/off) */
+ u16 strategy; /* cache strategy */
+ u16 write_back; /* write back state (on/off) */
+ u16 block_size; /* cache block size */
+} __attribute__((packed)) gdth_cpar_str;
typedef struct {
- ulong32 csize; /* cache size */
- ulong32 read_cnt; /* read/write counter */
- ulong32 write_cnt;
- ulong32 tr_hits; /* hits */
- ulong32 sec_hits;
- ulong32 sec_miss; /* misses */
-} PACKED gdth_cstat_str;
+ u32 csize; /* cache size */
+ u32 read_cnt; /* read/write counter */
+ u32 write_cnt;
+ u32 tr_hits; /* hits */
+ u32 sec_hits;
+ u32 sec_miss; /* misses */
+} __attribute__((packed)) gdth_cstat_str;
typedef struct {
gdth_cpar_str cpar;
gdth_cstat_str cstat;
-} PACKED gdth_cinfo_str;
+} __attribute__((packed)) gdth_cinfo_str;
/* cache drive info */
typedef struct {
- unchar cd_name[8]; /* cache drive name */
- ulong32 cd_devtype; /* SCSI devicetype */
- ulong32 cd_ldcnt; /* number of log. drives */
- ulong32 cd_last_error; /* last error */
- unchar cd_initialized; /* drive is initialized */
- unchar cd_removable; /* media is removable */
- unchar cd_write_protected; /* write protected */
- unchar cd_flags; /* Pool Hot Fix? */
- ulong32 ld_blkcnt; /* number of blocks */
- ulong32 ld_blksize; /* blocksize */
- ulong32 ld_dcnt; /* number of disks */
- ulong32 ld_slave; /* log. drive index */
- ulong32 ld_dtype; /* type of logical drive */
- ulong32 ld_last_error; /* last error */
- unchar ld_name[8]; /* log. drive name */
- unchar ld_error; /* error */
-} PACKED gdth_cdrinfo_str;
+ u8 cd_name[8]; /* cache drive name */
+ u32 cd_devtype; /* SCSI devicetype */
+ u32 cd_ldcnt; /* number of log. drives */
+ u32 cd_last_error; /* last error */
+ u8 cd_initialized; /* drive is initialized */
+ u8 cd_removable; /* media is removable */
+ u8 cd_write_protected; /* write protected */
+ u8 cd_flags; /* Pool Hot Fix? */
+ u32 ld_blkcnt; /* number of blocks */
+ u32 ld_blksize; /* blocksize */
+ u32 ld_dcnt; /* number of disks */
+ u32 ld_slave; /* log. drive index */
+ u32 ld_dtype; /* type of logical drive */
+ u32 ld_last_error; /* last error */
+ u8 ld_name[8]; /* log. drive name */
+ u8 ld_error; /* error */
+} __attribute__((packed)) gdth_cdrinfo_str;
/* OEM string */
typedef struct {
- ulong32 ctl_version;
- ulong32 file_major_version;
- ulong32 file_minor_version;
- ulong32 buffer_size;
- ulong32 cpy_count;
- ulong32 ext_error;
- ulong32 oem_id;
- ulong32 board_id;
-} PACKED gdth_oem_str_params;
-
-typedef struct {
- unchar product_0_1_name[16];
- unchar product_4_5_name[16];
- unchar product_cluster_name[16];
- unchar product_reserved[16];
- unchar scsi_cluster_target_vendor_id[16];
- unchar cluster_raid_fw_name[16];
- unchar oem_brand_name[16];
- unchar oem_raid_type[16];
- unchar bios_type[13];
- unchar bios_title[50];
- unchar oem_company_name[37];
- ulong32 pci_id_1;
- ulong32 pci_id_2;
- unchar validation_status[80];
- unchar reserved_1[4];
- unchar scsi_host_drive_inquiry_vendor_id[16];
- unchar library_file_template[16];
- unchar reserved_2[16];
- unchar tool_name_1[32];
- unchar tool_name_2[32];
- unchar tool_name_3[32];
- unchar oem_contact_1[84];
- unchar oem_contact_2[84];
- unchar oem_contact_3[84];
-} PACKED gdth_oem_str;
+ u32 ctl_version;
+ u32 file_major_version;
+ u32 file_minor_version;
+ u32 buffer_size;
+ u32 cpy_count;
+ u32 ext_error;
+ u32 oem_id;
+ u32 board_id;
+} __attribute__((packed)) gdth_oem_str_params;
+
+typedef struct {
+ u8 product_0_1_name[16];
+ u8 product_4_5_name[16];
+ u8 product_cluster_name[16];
+ u8 product_reserved[16];
+ u8 scsi_cluster_target_vendor_id[16];
+ u8 cluster_raid_fw_name[16];
+ u8 oem_brand_name[16];
+ u8 oem_raid_type[16];
+ u8 bios_type[13];
+ u8 bios_title[50];
+ u8 oem_company_name[37];
+ u32 pci_id_1;
+ u32 pci_id_2;
+ u8 validation_status[80];
+ u8 reserved_1[4];
+ u8 scsi_host_drive_inquiry_vendor_id[16];
+ u8 library_file_template[16];
+ u8 reserved_2[16];
+ u8 tool_name_1[32];
+ u8 tool_name_2[32];
+ u8 tool_name_3[32];
+ u8 oem_contact_1[84];
+ u8 oem_contact_2[84];
+ u8 oem_contact_3[84];
+} __attribute__((packed)) gdth_oem_str;
typedef struct {
gdth_oem_str_params params;
gdth_oem_str text;
-} PACKED gdth_oem_str_ioctl;
+} __attribute__((packed)) gdth_oem_str_ioctl;
/* board features */
typedef struct {
- unchar chaining; /* Chaining supported */
- unchar striping; /* Striping (RAID-0) supp. */
- unchar mirroring; /* Mirroring (RAID-1) supp. */
- unchar raid; /* RAID-4/5/10 supported */
-} PACKED gdth_bfeat_str;
+ u8 chaining; /* Chaining supported */
+ u8 striping; /* Striping (RAID-0) supp. */
+ u8 mirroring; /* Mirroring (RAID-1) supp. */
+ u8 raid; /* RAID-4/5/10 supported */
+} __attribute__((packed)) gdth_bfeat_str;
/* board info IOCTL */
typedef struct {
- ulong32 ser_no; /* serial no. */
- unchar oem_id[2]; /* OEM ID */
- ushort ep_flags; /* eprom flags */
- ulong32 proc_id; /* processor ID */
- ulong32 memsize; /* memory size (bytes) */
- unchar mem_banks; /* memory banks */
- unchar chan_type; /* channel type */
- unchar chan_count; /* channel count */
- unchar rdongle_pres; /* dongle present? */
- ulong32 epr_fw_ver; /* (eprom) firmware version */
- ulong32 upd_fw_ver; /* (update) firmware version */
- ulong32 upd_revision; /* update revision */
+ u32 ser_no; /* serial no. */
+ u8 oem_id[2]; /* OEM ID */
+ u16 ep_flags; /* eprom flags */
+ u32 proc_id; /* processor ID */
+ u32 memsize; /* memory size (bytes) */
+ u8 mem_banks; /* memory banks */
+ u8 chan_type; /* channel type */
+ u8 chan_count; /* channel count */
+ u8 rdongle_pres; /* dongle present? */
+ u32 epr_fw_ver; /* (eprom) firmware version */
+ u32 upd_fw_ver; /* (update) firmware version */
+ u32 upd_revision; /* update revision */
char type_string[16]; /* controller name */
char raid_string[16]; /* RAID firmware name */
- unchar update_pres; /* update present? */
- unchar xor_pres; /* XOR engine present? */
- unchar prom_type; /* ROM type (eprom/flash) */
- unchar prom_count; /* number of ROM devices */
- ulong32 dup_pres; /* duplexing module present? */
- ulong32 chan_pres; /* number of expansion chn. */
- ulong32 mem_pres; /* memory expansion inst. ? */
- unchar ft_bus_system; /* fault bus supported? */
- unchar subtype_valid; /* board_subtype valid? */
- unchar board_subtype; /* subtype/hardware level */
- unchar ramparity_pres; /* RAM parity check hardware? */
-} PACKED gdth_binfo_str;
+ u8 update_pres; /* update present? */
+ u8 xor_pres; /* XOR engine present? */
+ u8 prom_type; /* ROM type (eprom/flash) */
+ u8 prom_count; /* number of ROM devices */
+ u32 dup_pres; /* duplexing module present? */
+ u32 chan_pres; /* number of expansion chn. */
+ u32 mem_pres; /* memory expansion inst. ? */
+ u8 ft_bus_system; /* fault bus supported? */
+ u8 subtype_valid; /* board_subtype valid? */
+ u8 board_subtype; /* subtype/hardware level */
+ u8 ramparity_pres; /* RAM parity check hardware? */
+} __attribute__((packed)) gdth_binfo_str;
/* get host drive info */
typedef struct {
char name[8]; /* host drive name */
- ulong32 size; /* size (sectors) */
- unchar host_drive; /* host drive number */
- unchar log_drive; /* log. drive (master) */
- unchar reserved;
- unchar rw_attribs; /* r/w attribs */
- ulong32 start_sec; /* start sector */
-} PACKED gdth_hentry_str;
-
-typedef struct {
- ulong32 entries; /* entry count */
- ulong32 offset; /* offset of entries */
- unchar secs_p_head; /* sectors/head */
- unchar heads_p_cyl; /* heads/cylinder */
- unchar reserved;
- unchar clust_drvtype; /* cluster drive type */
- ulong32 location; /* controller number */
+ u32 size; /* size (sectors) */
+ u8 host_drive; /* host drive number */
+ u8 log_drive; /* log. drive (master) */
+ u8 reserved;
+ u8 rw_attribs; /* r/w attribs */
+ u32 start_sec; /* start sector */
+} __attribute__((packed)) gdth_hentry_str;
+
+typedef struct {
+ u32 entries; /* entry count */
+ u32 offset; /* offset of entries */
+ u8 secs_p_head; /* sectors/head */
+ u8 heads_p_cyl; /* heads/cylinder */
+ u8 reserved;
+ u8 clust_drvtype; /* cluster drive type */
+ u32 location; /* controller number */
gdth_hentry_str entry[MAX_HDRIVES]; /* entries */
-} PACKED gdth_hget_str;
+} __attribute__((packed)) gdth_hget_str;
/* DPRAM structures */
/* interface area ISA/PCI */
typedef struct {
- unchar S_Cmd_Indx; /* special command */
- unchar volatile S_Status; /* status special command */
- ushort reserved1;
- ulong32 S_Info[4]; /* add. info special command */
- unchar volatile Sema0; /* command semaphore */
- unchar reserved2[3];
- unchar Cmd_Index; /* command number */
- unchar reserved3[3];
- ushort volatile Status; /* command status */
- ushort Service; /* service(for async.events) */
- ulong32 Info[2]; /* additional info */
+ u8 S_Cmd_Indx; /* special command */
+ u8 volatile S_Status; /* status special command */
+ u16 reserved1;
+ u32 S_Info[4]; /* add. info special command */
+ u8 volatile Sema0; /* command semaphore */
+ u8 reserved2[3];
+ u8 Cmd_Index; /* command number */
+ u8 reserved3[3];
+ u16 volatile Status; /* command status */
+ u16 Service; /* service(for async.events) */
+ u32 Info[2]; /* additional info */
struct {
- ushort offset; /* command offs. in the DPRAM*/
- ushort serv_id; /* service */
- } PACKED comm_queue[MAXOFFSETS]; /* command queue */
- ulong32 bios_reserved[2];
- unchar gdt_dpr_cmd[1]; /* commands */
-} PACKED gdt_dpr_if;
+ u16 offset; /* command offs. in the DPRAM*/
+ u16 serv_id; /* service */
+ } __attribute__((packed)) comm_queue[MAXOFFSETS]; /* command queue */
+ u32 bios_reserved[2];
+ u8 gdt_dpr_cmd[1]; /* commands */
+} __attribute__((packed)) gdt_dpr_if;
/* SRAM structure PCI controllers */
typedef struct {
- ulong32 magic; /* controller ID from BIOS */
- ushort need_deinit; /* switch betw. BIOS/driver */
- unchar switch_support; /* see need_deinit */
- unchar padding[9];
- unchar os_used[16]; /* OS code per service */
- unchar unused[28];
- unchar fw_magic; /* contr. ID from firmware */
-} PACKED gdt_pci_sram;
+ u32 magic; /* controller ID from BIOS */
+ u16 need_deinit; /* switch betw. BIOS/driver */
+ u8 switch_support; /* see need_deinit */
+ u8 padding[9];
+ u8 os_used[16]; /* OS code per service */
+ u8 unused[28];
+ u8 fw_magic; /* contr. ID from firmware */
+} __attribute__((packed)) gdt_pci_sram;
/* SRAM structure EISA controllers (but NOT GDT3000/3020) */
typedef struct {
- unchar os_used[16]; /* OS code per service */
- ushort need_deinit; /* switch betw. BIOS/driver */
- unchar switch_support; /* see need_deinit */
- unchar padding;
-} PACKED gdt_eisa_sram;
+ u8 os_used[16]; /* OS code per service */
+ u16 need_deinit; /* switch betw. BIOS/driver */
+ u8 switch_support; /* see need_deinit */
+ u8 padding;
+} __attribute__((packed)) gdt_eisa_sram;
/* DPRAM ISA controllers */
typedef struct {
union {
struct {
- unchar bios_used[0x3c00-32]; /* 15KB - 32Bytes BIOS */
- ulong32 magic; /* controller (EISA) ID */
- ushort need_deinit; /* switch betw. BIOS/driver */
- unchar switch_support; /* see need_deinit */
- unchar padding[9];
- unchar os_used[16]; /* OS code per service */
- } PACKED dp_sram;
- unchar bios_area[0x4000]; /* 16KB reserved for BIOS */
+ u8 bios_used[0x3c00-32]; /* 15KB - 32Bytes BIOS */
+ u32 magic; /* controller (EISA) ID */
+ u16 need_deinit; /* switch betw. BIOS/driver */
+ u8 switch_support; /* see need_deinit */
+ u8 padding[9];
+ u8 os_used[16]; /* OS code per service */
+ } __attribute__((packed)) dp_sram;
+ u8 bios_area[0x4000]; /* 16KB reserved for BIOS */
} bu;
union {
gdt_dpr_if ic; /* interface area */
- unchar if_area[0x3000]; /* 12KB for interface */
+ u8 if_area[0x3000]; /* 12KB for interface */
} u;
struct {
- unchar memlock; /* write protection DPRAM */
- unchar event; /* release event */
- unchar irqen; /* board interrupts enable */
- unchar irqdel; /* acknowledge board int. */
- unchar volatile Sema1; /* status semaphore */
- unchar rq; /* IRQ/DRQ configuration */
- } PACKED io;
-} PACKED gdt2_dpram_str;
+ u8 memlock; /* write protection DPRAM */
+ u8 event; /* release event */
+ u8 irqen; /* board interrupts enable */
+ u8 irqdel; /* acknowledge board int. */
+ u8 volatile Sema1; /* status semaphore */
+ u8 rq; /* IRQ/DRQ configuration */
+ } __attribute__((packed)) io;
+} __attribute__((packed)) gdt2_dpram_str;
/* DPRAM PCI controllers */
typedef struct {
union {
gdt_dpr_if ic; /* interface area */
- unchar if_area[0xff0-sizeof(gdt_pci_sram)];
+ u8 if_area[0xff0-sizeof(gdt_pci_sram)];
} u;
gdt_pci_sram gdt6sr; /* SRAM structure */
struct {
- unchar unused0[1];
- unchar volatile Sema1; /* command semaphore */
- unchar unused1[3];
- unchar irqen; /* board interrupts enable */
- unchar unused2[2];
- unchar event; /* release event */
- unchar unused3[3];
- unchar irqdel; /* acknowledge board int. */
- unchar unused4[3];
- } PACKED io;
-} PACKED gdt6_dpram_str;
+ u8 unused0[1];
+ u8 volatile Sema1; /* command semaphore */
+ u8 unused1[3];
+ u8 irqen; /* board interrupts enable */
+ u8 unused2[2];
+ u8 event; /* release event */
+ u8 unused3[3];
+ u8 irqdel; /* acknowledge board int. */
+ u8 unused4[3];
+ } __attribute__((packed)) io;
+} __attribute__((packed)) gdt6_dpram_str;
/* PLX register structure (new PCI controllers) */
typedef struct {
- unchar cfg_reg; /* DPRAM cfg.(2:below 1MB,0:anywhere)*/
- unchar unused1[0x3f];
- unchar volatile sema0_reg; /* command semaphore */
- unchar volatile sema1_reg; /* status semaphore */
- unchar unused2[2];
- ushort volatile status; /* command status */
- ushort service; /* service */
- ulong32 info[2]; /* additional info */
- unchar unused3[0x10];
- unchar ldoor_reg; /* PCI to local doorbell */
- unchar unused4[3];
- unchar volatile edoor_reg; /* local to PCI doorbell */
- unchar unused5[3];
- unchar control0; /* control0 register(unused) */
- unchar control1; /* board interrupts enable */
- unchar unused6[0x16];
-} PACKED gdt6c_plx_regs;
+ u8 cfg_reg; /* DPRAM cfg.(2:below 1MB,0:anywhere)*/
+ u8 unused1[0x3f];
+ u8 volatile sema0_reg; /* command semaphore */
+ u8 volatile sema1_reg; /* status semaphore */
+ u8 unused2[2];
+ u16 volatile status; /* command status */
+ u16 service; /* service */
+ u32 info[2]; /* additional info */
+ u8 unused3[0x10];
+ u8 ldoor_reg; /* PCI to local doorbell */
+ u8 unused4[3];
+ u8 volatile edoor_reg; /* local to PCI doorbell */
+ u8 unused5[3];
+ u8 control0; /* control0 register(unused) */
+ u8 control1; /* board interrupts enable */
+ u8 unused6[0x16];
+} __attribute__((packed)) gdt6c_plx_regs;
/* DPRAM new PCI controllers */
typedef struct {
union {
gdt_dpr_if ic; /* interface area */
- unchar if_area[0x4000-sizeof(gdt_pci_sram)];
+ u8 if_area[0x4000-sizeof(gdt_pci_sram)];
} u;
gdt_pci_sram gdt6sr; /* SRAM structure */
-} PACKED gdt6c_dpram_str;
+} __attribute__((packed)) gdt6c_dpram_str;
/* i960 register structure (PCI MPR controllers) */
typedef struct {
- unchar unused1[16];
- unchar volatile sema0_reg; /* command semaphore */
- unchar unused2;
- unchar volatile sema1_reg; /* status semaphore */
- unchar unused3;
- ushort volatile status; /* command status */
- ushort service; /* service */
- ulong32 info[2]; /* additional info */
- unchar ldoor_reg; /* PCI to local doorbell */
- unchar unused4[11];
- unchar volatile edoor_reg; /* local to PCI doorbell */
- unchar unused5[7];
- unchar edoor_en_reg; /* board interrupts enable */
- unchar unused6[27];
- ulong32 unused7[939];
- ulong32 severity;
+ u8 unused1[16];
+ u8 volatile sema0_reg; /* command semaphore */
+ u8 unused2;
+ u8 volatile sema1_reg; /* status semaphore */
+ u8 unused3;
+ u16 volatile status; /* command status */
+ u16 service; /* service */
+ u32 info[2]; /* additional info */
+ u8 ldoor_reg; /* PCI to local doorbell */
+ u8 unused4[11];
+ u8 volatile edoor_reg; /* local to PCI doorbell */
+ u8 unused5[7];
+ u8 edoor_en_reg; /* board interrupts enable */
+ u8 unused6[27];
+ u32 unused7[939];
+ u32 severity;
char evt_str[256]; /* event string */
-} PACKED gdt6m_i960_regs;
+} __attribute__((packed)) gdt6m_i960_regs;
/* DPRAM PCI MPR controllers */
typedef struct {
gdt6m_i960_regs i960r; /* 4KB i960 registers */
union {
gdt_dpr_if ic; /* interface area */
- unchar if_area[0x3000-sizeof(gdt_pci_sram)];
+ u8 if_area[0x3000-sizeof(gdt_pci_sram)];
} u;
gdt_pci_sram gdt6sr; /* SRAM structure */
-} PACKED gdt6m_dpram_str;
+} __attribute__((packed)) gdt6m_dpram_str;
/* PCI resources */
typedef struct {
struct pci_dev *pdev;
- ulong dpmem; /* DPRAM address */
- ulong io; /* IO address */
+ unsigned long dpmem; /* DPRAM address */
+ unsigned long io; /* IO address */
} gdth_pci_str;
@@ -846,93 +846,93 @@ typedef struct {
typedef struct {
struct Scsi_Host *shost;
struct list_head list;
- ushort hanum;
- ushort oem_id; /* OEM */
- ushort type; /* controller class */
- ulong32 stype; /* subtype (PCI: device ID) */
- ushort fw_vers; /* firmware version */
- ushort cache_feat; /* feat. cache serv. (s/g,..)*/
- ushort raw_feat; /* feat. raw service (s/g,..)*/
- ushort screen_feat; /* feat. raw service (s/g,..)*/
- ushort bmic; /* BMIC address (EISA) */
+ u16 hanum;
+ u16 oem_id; /* OEM */
+ u16 type; /* controller class */
+ u32 stype; /* subtype (PCI: device ID) */
+ u16 fw_vers; /* firmware version */
+ u16 cache_feat; /* feat. cache serv. (s/g,..)*/
+ u16 raw_feat; /* feat. raw service (s/g,..)*/
+ u16 screen_feat; /* feat. raw service (s/g,..)*/
+ u16 bmic; /* BMIC address (EISA) */
void __iomem *brd; /* DPRAM address */
- ulong32 brd_phys; /* slot number/BIOS address */
+ u32 brd_phys; /* slot number/BIOS address */
gdt6c_plx_regs *plx; /* PLX regs (new PCI contr.) */
gdth_cmd_str cmdext;
gdth_cmd_str *pccb; /* address command structure */
- ulong32 ccb_phys; /* phys. address */
+ u32 ccb_phys; /* phys. address */
#ifdef INT_COAL
gdth_coal_status *coal_stat; /* buffer for coalescing int.*/
- ulong64 coal_stat_phys; /* phys. address */
+ u64 coal_stat_phys; /* phys. address */
#endif
char *pscratch; /* scratch (DMA) buffer */
- ulong64 scratch_phys; /* phys. address */
- unchar scratch_busy; /* in use? */
- unchar dma64_support; /* 64-bit DMA supported? */
+ u64 scratch_phys; /* phys. address */
+ u8 scratch_busy; /* in use? */
+ u8 dma64_support; /* 64-bit DMA supported? */
gdth_msg_str *pmsg; /* message buffer */
- ulong64 msg_phys; /* phys. address */
- unchar scan_mode; /* current scan mode */
- unchar irq; /* IRQ */
- unchar drq; /* DRQ (ISA controllers) */
- ushort status; /* command status */
- ushort service; /* service/firmware ver./.. */
- ulong32 info;
- ulong32 info2; /* additional info */
+ u64 msg_phys; /* phys. address */
+ u8 scan_mode; /* current scan mode */
+ u8 irq; /* IRQ */
+ u8 drq; /* DRQ (ISA controllers) */
+ u16 status; /* command status */
+ u16 service; /* service/firmware ver./.. */
+ u32 info;
+ u32 info2; /* additional info */
Scsi_Cmnd *req_first; /* top of request queue */
struct {
- unchar present; /* Flag: host drive present? */
- unchar is_logdrv; /* Flag: log. drive (master)? */
- unchar is_arraydrv; /* Flag: array drive? */
- unchar is_master; /* Flag: array drive master? */
- unchar is_parity; /* Flag: parity drive? */
- unchar is_hotfix; /* Flag: hotfix drive? */
- unchar master_no; /* number of master drive */
- unchar lock; /* drive locked? (hot plug) */
- unchar heads; /* mapping */
- unchar secs;
- ushort devtype; /* further information */
- ulong64 size; /* capacity */
- unchar ldr_no; /* log. drive no. */
- unchar rw_attribs; /* r/w attributes */
- unchar cluster_type; /* cluster properties */
- unchar media_changed; /* Flag:MOUNT/UNMOUNT occured */
- ulong32 start_sec; /* start sector */
+ u8 present; /* Flag: host drive present? */
+ u8 is_logdrv; /* Flag: log. drive (master)? */
+ u8 is_arraydrv; /* Flag: array drive? */
+ u8 is_master; /* Flag: array drive master? */
+ u8 is_parity; /* Flag: parity drive? */
+ u8 is_hotfix; /* Flag: hotfix drive? */
+ u8 master_no; /* number of master drive */
+ u8 lock; /* drive locked? (hot plug) */
+ u8 heads; /* mapping */
+ u8 secs;
+ u16 devtype; /* further information */
+ u64 size; /* capacity */
+ u8 ldr_no; /* log. drive no. */
+ u8 rw_attribs; /* r/w attributes */
+ u8 cluster_type; /* cluster properties */
+ u8 media_changed; /* Flag:MOUNT/UNMOUNT occured */
+ u32 start_sec; /* start sector */
} hdr[MAX_LDRIVES]; /* host drives */
struct {
- unchar lock; /* channel locked? (hot plug) */
- unchar pdev_cnt; /* physical device count */
- unchar local_no; /* local channel number */
- unchar io_cnt[MAXID]; /* current IO count */
- ulong32 address; /* channel address */
- ulong32 id_list[MAXID]; /* IDs of the phys. devices */
+ u8 lock; /* channel locked? (hot plug) */
+ u8 pdev_cnt; /* physical device count */
+ u8 local_no; /* local channel number */
+ u8 io_cnt[MAXID]; /* current IO count */
+ u32 address; /* channel address */
+ u32 id_list[MAXID]; /* IDs of the phys. devices */
} raw[MAXBUS]; /* SCSI channels */
struct {
Scsi_Cmnd *cmnd; /* pending request */
- ushort service; /* service */
+ u16 service; /* service */
} cmd_tab[GDTH_MAXCMDS]; /* table of pend. requests */
struct gdth_cmndinfo { /* per-command private info */
int index;
int internal_command; /* don't call scsi_done */
gdth_cmd_str *internal_cmd_str; /* crier for internal messages*/
dma_addr_t sense_paddr; /* sense dma-addr */
- unchar priority;
+ u8 priority;
int timeout_count; /* # of timeout calls */
volatile int wait_for_completion;
- ushort status;
- ulong32 info;
+ u16 status;
+ u32 info;
enum dma_data_direction dma_dir;
int phase; /* ???? */
int OpCode;
} cmndinfo[GDTH_MAXCMDS]; /* index==0 is free */
- unchar bus_cnt; /* SCSI bus count */
- unchar tid_cnt; /* Target ID count */
- unchar bus_id[MAXBUS]; /* IOP IDs */
- unchar virt_bus; /* number of virtual bus */
- unchar more_proc; /* more /proc info supported */
- ushort cmd_cnt; /* command count in DPRAM */
- ushort cmd_len; /* length of actual command */
- ushort cmd_offs_dpmem; /* actual offset in DPRAM */
- ushort ic_all_size; /* sizeof DPRAM interf. area */
+ u8 bus_cnt; /* SCSI bus count */
+ u8 tid_cnt; /* Target ID count */
+ u8 bus_id[MAXBUS]; /* IOP IDs */
+ u8 virt_bus; /* number of virtual bus */
+ u8 more_proc; /* more /proc info supported */
+ u16 cmd_cnt; /* command count in DPRAM */
+ u16 cmd_len; /* length of actual command */
+ u16 cmd_offs_dpmem; /* actual offset in DPRAM */
+ u16 ic_all_size; /* sizeof DPRAM interf. area */
gdth_cpar_str cpar; /* controller cache par. */
gdth_bfeat_str bfeat; /* controller features */
gdth_binfo_str binfo; /* controller info */
@@ -941,7 +941,7 @@ typedef struct {
struct pci_dev *pdev;
char oem_name[8];
#ifdef GDTH_DMA_STATISTICS
- ulong dma32_cnt, dma64_cnt; /* statistics: DMA buffer */
+ unsigned long dma32_cnt, dma64_cnt; /* statistics: DMA buffer */
#endif
struct scsi_device *sdev;
} gdth_ha_str;
@@ -953,65 +953,65 @@ static inline struct gdth_cmndinfo *gdth_cmnd_priv(struct scsi_cmnd* cmd)
/* INQUIRY data format */
typedef struct {
- unchar type_qual;
- unchar modif_rmb;
- unchar version;
- unchar resp_aenc;
- unchar add_length;
- unchar reserved1;
- unchar reserved2;
- unchar misc;
- unchar vendor[8];
- unchar product[16];
- unchar revision[4];
-} PACKED gdth_inq_data;
+ u8 type_qual;
+ u8 modif_rmb;
+ u8 version;
+ u8 resp_aenc;
+ u8 add_length;
+ u8 reserved1;
+ u8 reserved2;
+ u8 misc;
+ u8 vendor[8];
+ u8 product[16];
+ u8 revision[4];
+} __attribute__((packed)) gdth_inq_data;
/* READ_CAPACITY data format */
typedef struct {
- ulong32 last_block_no;
- ulong32 block_length;
-} PACKED gdth_rdcap_data;
+ u32 last_block_no;
+ u32 block_length;
+} __attribute__((packed)) gdth_rdcap_data;
/* READ_CAPACITY (16) data format */
typedef struct {
- ulong64 last_block_no;
- ulong32 block_length;
-} PACKED gdth_rdcap16_data;
+ u64 last_block_no;
+ u32 block_length;
+} __attribute__((packed)) gdth_rdcap16_data;
/* REQUEST_SENSE data format */
typedef struct {
- unchar errorcode;
- unchar segno;
- unchar key;
- ulong32 info;
- unchar add_length;
- ulong32 cmd_info;
- unchar adsc;
- unchar adsq;
- unchar fruc;
- unchar key_spec[3];
-} PACKED gdth_sense_data;
+ u8 errorcode;
+ u8 segno;
+ u8 key;
+ u32 info;
+ u8 add_length;
+ u32 cmd_info;
+ u8 adsc;
+ u8 adsq;
+ u8 fruc;
+ u8 key_spec[3];
+} __attribute__((packed)) gdth_sense_data;
/* MODE_SENSE data format */
typedef struct {
struct {
- unchar data_length;
- unchar med_type;
- unchar dev_par;
- unchar bd_length;
- } PACKED hd;
+ u8 data_length;
+ u8 med_type;
+ u8 dev_par;
+ u8 bd_length;
+ } __attribute__((packed)) hd;
struct {
- unchar dens_code;
- unchar block_count[3];
- unchar reserved;
- unchar block_length[3];
- } PACKED bd;
-} PACKED gdth_modep_data;
+ u8 dens_code;
+ u8 block_count[3];
+ u8 reserved;
+ u8 block_length[3];
+ } __attribute__((packed)) bd;
+} __attribute__((packed)) gdth_modep_data;
/* stack frame */
typedef struct {
- ulong b[10]; /* 32/64 bit compiler ! */
-} PACKED gdth_stackframe;
+ unsigned long b[10]; /* 32/64 bit compiler ! */
+} __attribute__((packed)) gdth_stackframe;
/* function prototyping */
diff --git a/drivers/scsi/gdth_ioctl.h b/drivers/scsi/gdth_ioctl.h
index 783fae737f17..b004c6165887 100644
--- a/drivers/scsi/gdth_ioctl.h
+++ b/drivers/scsi/gdth_ioctl.h
@@ -32,109 +32,101 @@
#define MAX_HDRIVES MAX_LDRIVES /* max. host drive count */
#endif
-/* typedefs */
-#ifdef __KERNEL__
-typedef u32 ulong32;
-typedef u64 ulong64;
-#endif
-
-#define PACKED __attribute__((packed))
-
/* scatter/gather element */
typedef struct {
- ulong32 sg_ptr; /* address */
- ulong32 sg_len; /* length */
-} PACKED gdth_sg_str;
+ u32 sg_ptr; /* address */
+ u32 sg_len; /* length */
+} __attribute__((packed)) gdth_sg_str;
/* scatter/gather element - 64bit addresses */
typedef struct {
- ulong64 sg_ptr; /* address */
- ulong32 sg_len; /* length */
-} PACKED gdth_sg64_str;
+ u64 sg_ptr; /* address */
+ u32 sg_len; /* length */
+} __attribute__((packed)) gdth_sg64_str;
/* command structure */
typedef struct {
- ulong32 BoardNode; /* board node (always 0) */
- ulong32 CommandIndex; /* command number */
- ushort OpCode; /* the command (READ,..) */
+ u32 BoardNode; /* board node (always 0) */
+ u32 CommandIndex; /* command number */
+ u16 OpCode; /* the command (READ,..) */
union {
struct {
- ushort DeviceNo; /* number of cache drive */
- ulong32 BlockNo; /* block number */
- ulong32 BlockCnt; /* block count */
- ulong32 DestAddr; /* dest. addr. (if s/g: -1) */
- ulong32 sg_canz; /* s/g element count */
+ u16 DeviceNo; /* number of cache drive */
+ u32 BlockNo; /* block number */
+ u32 BlockCnt; /* block count */
+ u32 DestAddr; /* dest. addr. (if s/g: -1) */
+ u32 sg_canz; /* s/g element count */
gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */
- } PACKED cache; /* cache service cmd. str. */
+ } __attribute__((packed)) cache; /* cache service cmd. str. */
struct {
- ushort DeviceNo; /* number of cache drive */
- ulong64 BlockNo; /* block number */
- ulong32 BlockCnt; /* block count */
- ulong64 DestAddr; /* dest. addr. (if s/g: -1) */
- ulong32 sg_canz; /* s/g element count */
+ u16 DeviceNo; /* number of cache drive */
+ u64 BlockNo; /* block number */
+ u32 BlockCnt; /* block count */
+ u64 DestAddr; /* dest. addr. (if s/g: -1) */
+ u32 sg_canz; /* s/g element count */
gdth_sg64_str sg_lst[GDTH_MAXSG]; /* s/g list */
- } PACKED cache64; /* cache service cmd. str. */
+ } __attribute__((packed)) cache64; /* cache service cmd. str. */
struct {
- ushort param_size; /* size of p_param buffer */
- ulong32 subfunc; /* IOCTL function */
- ulong32 channel; /* device */
- ulong64 p_param; /* buffer */
- } PACKED ioctl; /* IOCTL command structure */
+ u16 param_size; /* size of p_param buffer */
+ u32 subfunc; /* IOCTL function */
+ u32 channel; /* device */
+ u64 p_param; /* buffer */
+ } __attribute__((packed)) ioctl; /* IOCTL command structure */
struct {
- ushort reserved;
+ u16 reserved;
union {
struct {
- ulong32 msg_handle; /* message handle */
- ulong64 msg_addr; /* message buffer address */
- } PACKED msg;
- unchar data[12]; /* buffer for rtc data, ... */
+ u32 msg_handle; /* message handle */
+ u64 msg_addr; /* message buffer address */
+ } __attribute__((packed)) msg;
+ u8 data[12]; /* buffer for rtc data, ... */
} su;
- } PACKED screen; /* screen service cmd. str. */
+ } __attribute__((packed)) screen; /* screen service cmd. str. */
struct {
- ushort reserved;
- ulong32 direction; /* data direction */
- ulong32 mdisc_time; /* disc. time (0: no timeout)*/
- ulong32 mcon_time; /* connect time(0: no to.) */
- ulong32 sdata; /* dest. addr. (if s/g: -1) */
- ulong32 sdlen; /* data length (bytes) */
- ulong32 clen; /* SCSI cmd. length(6,10,12) */
- unchar cmd[12]; /* SCSI command */
- unchar target; /* target ID */
- unchar lun; /* LUN */
- unchar bus; /* SCSI bus number */
- unchar priority; /* only 0 used */
- ulong32 sense_len; /* sense data length */
- ulong32 sense_data; /* sense data addr. */
- ulong32 link_p; /* linked cmds (not supp.) */
- ulong32 sg_ranz; /* s/g element count */
+ u16 reserved;
+ u32 direction; /* data direction */
+ u32 mdisc_time; /* disc. time (0: no timeout)*/
+ u32 mcon_time; /* connect time(0: no to.) */
+ u32 sdata; /* dest. addr. (if s/g: -1) */
+ u32 sdlen; /* data length (bytes) */
+ u32 clen; /* SCSI cmd. length(6,10,12) */
+ u8 cmd[12]; /* SCSI command */
+ u8 target; /* target ID */
+ u8 lun; /* LUN */
+ u8 bus; /* SCSI bus number */
+ u8 priority; /* only 0 used */
+ u32 sense_len; /* sense data length */
+ u32 sense_data; /* sense data addr. */
+ u32 link_p; /* linked cmds (not supp.) */
+ u32 sg_ranz; /* s/g element count */
gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */
- } PACKED raw; /* raw service cmd. struct. */
+ } __attribute__((packed)) raw; /* raw service cmd. struct. */
struct {
- ushort reserved;
- ulong32 direction; /* data direction */
- ulong32 mdisc_time; /* disc. time (0: no timeout)*/
- ulong32 mcon_time; /* connect time(0: no to.) */
- ulong64 sdata; /* dest. addr. (if s/g: -1) */
- ulong32 sdlen; /* data length (bytes) */
- ulong32 clen; /* SCSI cmd. length(6,..,16) */
- unchar cmd[16]; /* SCSI command */
- unchar target; /* target ID */
- unchar lun; /* LUN */
- unchar bus; /* SCSI bus number */
- unchar priority; /* only 0 used */
- ulong32 sense_len; /* sense data length */
- ulong64 sense_data; /* sense data addr. */
- ulong32 sg_ranz; /* s/g element count */
+ u16 reserved;
+ u32 direction; /* data direction */
+ u32 mdisc_time; /* disc. time (0: no timeout)*/
+ u32 mcon_time; /* connect time(0: no to.) */
+ u64 sdata; /* dest. addr. (if s/g: -1) */
+ u32 sdlen; /* data length (bytes) */
+ u32 clen; /* SCSI cmd. length(6,..,16) */
+ u8 cmd[16]; /* SCSI command */
+ u8 target; /* target ID */
+ u8 lun; /* LUN */
+ u8 bus; /* SCSI bus number */
+ u8 priority; /* only 0 used */
+ u32 sense_len; /* sense data length */
+ u64 sense_data; /* sense data addr. */
+ u32 sg_ranz; /* s/g element count */
gdth_sg64_str sg_lst[GDTH_MAXSG]; /* s/g list */
- } PACKED raw64; /* raw service cmd. struct. */
+ } __attribute__((packed)) raw64; /* raw service cmd. struct. */
} u;
/* additional variables */
- unchar Service; /* controller service */
- unchar reserved;
- ushort Status; /* command result */
- ulong32 Info; /* additional information */
+ u8 Service; /* controller service */
+ u8 reserved;
+ u16 Status; /* command result */
+ u32 Info; /* additional information */
void *RequestBuffer; /* request buffer */
-} PACKED gdth_cmd_str;
+} __attribute__((packed)) gdth_cmd_str;
/* controller event structure */
#define ES_ASYNC 1
@@ -142,129 +134,129 @@ typedef struct {
#define ES_TEST 3
#define ES_SYNC 4
typedef struct {
- ushort size; /* size of structure */
+ u16 size; /* size of structure */
union {
char stream[16];
struct {
- ushort ionode;
- ushort service;
- ulong32 index;
- } PACKED driver;
+ u16 ionode;
+ u16 service;
+ u32 index;
+ } __attribute__((packed)) driver;
struct {
- ushort ionode;
- ushort service;
- ushort status;
- ulong32 info;
- unchar scsi_coord[3];
- } PACKED async;
+ u16 ionode;
+ u16 service;
+ u16 status;
+ u32 info;
+ u8 scsi_coord[3];
+ } __attribute__((packed)) async;
struct {
- ushort ionode;
- ushort service;
- ushort status;
- ulong32 info;
- ushort hostdrive;
- unchar scsi_coord[3];
- unchar sense_key;
- } PACKED sync;
+ u16 ionode;
+ u16 service;
+ u16 status;
+ u32 info;
+ u16 hostdrive;
+ u8 scsi_coord[3];
+ u8 sense_key;
+ } __attribute__((packed)) sync;
struct {
- ulong32 l1, l2, l3, l4;
- } PACKED test;
+ u32 l1, l2, l3, l4;
+ } __attribute__((packed)) test;
} eu;
- ulong32 severity;
- unchar event_string[256];
-} PACKED gdth_evt_data;
+ u32 severity;
+ u8 event_string[256];
+} __attribute__((packed)) gdth_evt_data;
typedef struct {
- ulong32 first_stamp;
- ulong32 last_stamp;
- ushort same_count;
- ushort event_source;
- ushort event_idx;
- unchar application;
- unchar reserved;
+ u32 first_stamp;
+ u32 last_stamp;
+ u16 same_count;
+ u16 event_source;
+ u16 event_idx;
+ u8 application;
+ u8 reserved;
gdth_evt_data event_data;
-} PACKED gdth_evt_str;
+} __attribute__((packed)) gdth_evt_str;
#ifdef GDTH_IOCTL_PROC
/* IOCTL structure (write) */
typedef struct {
- ulong32 magic; /* IOCTL magic */
- ushort ioctl; /* IOCTL */
- ushort ionode; /* controller number */
- ushort service; /* controller service */
- ushort timeout; /* timeout */
+ u32 magic; /* IOCTL magic */
+ u16 ioctl; /* IOCTL */
+ u16 ionode; /* controller number */
+ u16 service; /* controller service */
+ u16 timeout; /* timeout */
union {
struct {
- unchar command[512]; /* controller command */
- unchar data[1]; /* add. data */
+ u8 command[512]; /* controller command */
+ u8 data[1]; /* add. data */
} general;
struct {
- unchar lock; /* lock/unlock */
- unchar drive_cnt; /* drive count */
- ushort drives[MAX_HDRIVES];/* drives */
+ u8 lock; /* lock/unlock */
+ u8 drive_cnt; /* drive count */
+ u16 drives[MAX_HDRIVES];/* drives */
} lockdrv;
struct {
- unchar lock; /* lock/unlock */
- unchar channel; /* channel */
+ u8 lock; /* lock/unlock */
+ u8 channel; /* channel */
} lockchn;
struct {
int erase; /* erase event ? */
int handle;
- unchar evt[EVENT_SIZE]; /* event structure */
+ u8 evt[EVENT_SIZE]; /* event structure */
} event;
struct {
- unchar bus; /* SCSI bus */
- unchar target; /* target ID */
- unchar lun; /* LUN */
- unchar cmd_len; /* command length */
- unchar cmd[12]; /* SCSI command */
+ u8 bus; /* SCSI bus */
+ u8 target; /* target ID */
+ u8 lun; /* LUN */
+ u8 cmd_len; /* command length */
+ u8 cmd[12]; /* SCSI command */
} scsi;
struct {
- ushort hdr_no; /* host drive number */
- unchar flag; /* old meth./add/remove */
+ u16 hdr_no; /* host drive number */
+ u8 flag; /* old meth./add/remove */
} rescan;
} iu;
} gdth_iowr_str;
/* IOCTL structure (read) */
typedef struct {
- ulong32 size; /* buffer size */
- ulong32 status; /* IOCTL error code */
+ u32 size; /* buffer size */
+ u32 status; /* IOCTL error code */
union {
struct {
- unchar data[1]; /* data */
+ u8 data[1]; /* data */
} general;
struct {
- ushort version; /* driver version */
+ u16 version; /* driver version */
} drvers;
struct {
- unchar type; /* controller type */
- ushort info; /* slot etc. */
- ushort oem_id; /* OEM ID */
- ushort bios_ver; /* not used */
- ushort access; /* not used */
- ushort ext_type; /* extended type */
- ushort device_id; /* device ID */
- ushort sub_device_id; /* sub device ID */
+ u8 type; /* controller type */
+ u16 info; /* slot etc. */
+ u16 oem_id; /* OEM ID */
+ u16 bios_ver; /* not used */
+ u16 access; /* not used */
+ u16 ext_type; /* extended type */
+ u16 device_id; /* device ID */
+ u16 sub_device_id; /* sub device ID */
} ctrtype;
struct {
- unchar version; /* OS version */
- unchar subversion; /* OS subversion */
- ushort revision; /* revision */
+ u8 version; /* OS version */
+ u8 subversion; /* OS subversion */
+ u16 revision; /* revision */
} osvers;
struct {
- ushort count; /* controller count */
+ u16 count; /* controller count */
} ctrcnt;
struct {
int handle;
- unchar evt[EVENT_SIZE]; /* event structure */
+ u8 evt[EVENT_SIZE]; /* event structure */
} event;
struct {
- unchar bus; /* SCSI bus, 0xff: invalid */
- unchar target; /* target ID */
- unchar lun; /* LUN */
- unchar cluster_type; /* cluster properties */
+ u8 bus; /* SCSI bus, 0xff: invalid */
+ u8 target; /* target ID */
+ u8 lun; /* LUN */
+ u8 cluster_type; /* cluster properties */
} hdr_list[MAX_HDRIVES]; /* index is host drive number */
} iu;
} gdth_iord_str;
@@ -272,53 +264,53 @@ typedef struct {
/* GDTIOCTL_GENERAL */
typedef struct {
- ushort ionode; /* controller number */
- ushort timeout; /* timeout */
- ulong32 info; /* error info */
- ushort status; /* status */
- ulong data_len; /* data buffer size */
- ulong sense_len; /* sense buffer size */
+ u16 ionode; /* controller number */
+ u16 timeout; /* timeout */
+ u32 info; /* error info */
+ u16 status; /* status */
+ unsigned long data_len; /* data buffer size */
+ unsigned long sense_len; /* sense buffer size */
gdth_cmd_str command; /* command */
} gdth_ioctl_general;
/* GDTIOCTL_LOCKDRV */
typedef struct {
- ushort ionode; /* controller number */
- unchar lock; /* lock/unlock */
- unchar drive_cnt; /* drive count */
- ushort drives[MAX_HDRIVES]; /* drives */
+ u16 ionode; /* controller number */
+ u8 lock; /* lock/unlock */
+ u8 drive_cnt; /* drive count */
+ u16 drives[MAX_HDRIVES]; /* drives */
} gdth_ioctl_lockdrv;
/* GDTIOCTL_LOCKCHN */
typedef struct {
- ushort ionode; /* controller number */
- unchar lock; /* lock/unlock */
- unchar channel; /* channel */
+ u16 ionode; /* controller number */
+ u8 lock; /* lock/unlock */
+ u8 channel; /* channel */
} gdth_ioctl_lockchn;
/* GDTIOCTL_OSVERS */
typedef struct {
- unchar version; /* OS version */
- unchar subversion; /* OS subversion */
- ushort revision; /* revision */
+ u8 version; /* OS version */
+ u8 subversion; /* OS subversion */
+ u16 revision; /* revision */
} gdth_ioctl_osvers;
/* GDTIOCTL_CTRTYPE */
typedef struct {
- ushort ionode; /* controller number */
- unchar type; /* controller type */
- ushort info; /* slot etc. */
- ushort oem_id; /* OEM ID */
- ushort bios_ver; /* not used */
- ushort access; /* not used */
- ushort ext_type; /* extended type */
- ushort device_id; /* device ID */
- ushort sub_device_id; /* sub device ID */
+ u16 ionode; /* controller number */
+ u8 type; /* controller type */
+ u16 info; /* slot etc. */
+ u16 oem_id; /* OEM ID */
+ u16 bios_ver; /* not used */
+ u16 access; /* not used */
+ u16 ext_type; /* extended type */
+ u16 device_id; /* device ID */
+ u16 sub_device_id; /* sub device ID */
} gdth_ioctl_ctrtype;
/* GDTIOCTL_EVENT */
typedef struct {
- ushort ionode;
+ u16 ionode;
int erase; /* erase event? */
int handle; /* event handle */
gdth_evt_str event;
@@ -326,22 +318,22 @@ typedef struct {
/* GDTIOCTL_RESCAN/GDTIOCTL_HDRLIST */
typedef struct {
- ushort ionode; /* controller number */
- unchar flag; /* add/remove */
- ushort hdr_no; /* drive no. */
+ u16 ionode; /* controller number */
+ u8 flag; /* add/remove */
+ u16 hdr_no; /* drive no. */
struct {
- unchar bus; /* SCSI bus */
- unchar target; /* target ID */
- unchar lun; /* LUN */
- unchar cluster_type; /* cluster properties */
+ u8 bus; /* SCSI bus */
+ u8 target; /* target ID */
+ u8 lun; /* LUN */
+ u8 cluster_type; /* cluster properties */
} hdr_list[MAX_HDRIVES]; /* index is host drive number */
} gdth_ioctl_rescan;
/* GDTIOCTL_RESET_BUS/GDTIOCTL_RESET_DRV */
typedef struct {
- ushort ionode; /* controller number */
- ushort number; /* bus/host drive number */
- ushort status; /* status */
+ u16 ionode; /* controller number */
+ u16 number; /* bus/host drive number */
+ u16 status; /* status */
} gdth_ioctl_reset;
#endif
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index 1258da34fbc2..ffb2b21992ba 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -43,7 +43,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
int i, found;
gdth_cmd_str gdtcmd;
gdth_cpar_str *pcpar;
- ulong64 paddr;
+ u64 paddr;
char cmnd[MAX_COMMAND_SIZE];
memset(cmnd, 0xff, 12);
@@ -156,8 +156,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
off_t begin = 0,pos = 0;
int id, i, j, k, sec, flag;
int no_mdrv = 0, drv_no, is_mirr;
- ulong32 cnt;
- ulong64 paddr;
+ u32 cnt;
+ u64 paddr;
int rc = -ENOMEM;
gdth_cmd_str *gdtcmd;
@@ -220,14 +220,14 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
if (ha->more_proc)
sprintf(hrec, "%d.%02d.%02d-%c%03X",
- (unchar)(ha->binfo.upd_fw_ver>>24),
- (unchar)(ha->binfo.upd_fw_ver>>16),
- (unchar)(ha->binfo.upd_fw_ver),
+ (u8)(ha->binfo.upd_fw_ver>>24),
+ (u8)(ha->binfo.upd_fw_ver>>16),
+ (u8)(ha->binfo.upd_fw_ver),
ha->bfeat.raid ? 'R':'N',
ha->binfo.upd_revision);
else
- sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8),
- (unchar)(ha->cpar.version));
+ sprintf(hrec, "%d.%02d", (u8)(ha->cpar.version>>8),
+ (u8)(ha->cpar.version));
size = sprintf(buffer+len,
" Driver Ver.: \t%-10s\tFirmware Ver.: \t%s\n",
@@ -281,7 +281,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
pds->bid = ha->raw[i].local_no;
pds->first = 0;
pds->entries = ha->raw[i].pdev_cnt;
- cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) /
+ cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(u32)) /
sizeof(pds->list[0]);
if (pds->entries > cnt)
pds->entries = cnt;
@@ -604,7 +604,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
size = sprintf(buffer+len,
" Capacity [MB]:\t%-6d \tStart Sector: \t%d\n",
- (ulong32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec);
+ (u32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec);
len += size; pos = begin + len;
if (pos < offset) {
len = 0;
@@ -664,9 +664,9 @@ free_fail:
}
static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch,
- ulong64 *paddr)
+ u64 *paddr)
{
- ulong flags;
+ unsigned long flags;
char *ret_val;
if (size == 0)
@@ -691,9 +691,9 @@ static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch,
return ret_val;
}
-static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr)
+static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, u64 paddr)
{
- ulong flags;
+ unsigned long flags;
if (buf == ha->pscratch) {
spin_lock_irqsave(&ha->smp_lock, flags);
@@ -705,16 +705,16 @@ static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr)
}
#ifdef GDTH_IOCTL_PROC
-static int gdth_ioctl_check_bin(gdth_ha_str *ha, ushort size)
+static int gdth_ioctl_check_bin(gdth_ha_str *ha, u16 size)
{
- ulong flags;
+ unsigned long flags;
int ret_val;
spin_lock_irqsave(&ha->smp_lock, flags);
ret_val = FALSE;
if (ha->scratch_busy) {
- if (((gdth_iord_str *)ha->pscratch)->size == (ulong32)size)
+ if (((gdth_iord_str *)ha->pscratch)->size == (u32)size)
ret_val = TRUE;
}
spin_unlock_irqrestore(&ha->smp_lock, flags);
@@ -724,11 +724,11 @@ static int gdth_ioctl_check_bin(gdth_ha_str *ha, ushort size)
static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id)
{
- ulong flags;
+ unsigned long flags;
int i;
Scsi_Cmnd *scp;
struct gdth_cmndinfo *cmndinfo;
- unchar b, t;
+ u8 b, t;
spin_lock_irqsave(&ha->smp_lock, flags);
@@ -738,8 +738,8 @@ static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id)
b = scp->device->channel;
t = scp->device->id;
- if (!SPECIAL_SCP(scp) && t == (unchar)id &&
- b == (unchar)busnum) {
+ if (!SPECIAL_SCP(scp) && t == (u8)id &&
+ b == (u8)busnum) {
cmndinfo->wait_for_completion = 0;
spin_unlock_irqrestore(&ha->smp_lock, flags);
while (!cmndinfo->wait_for_completion)
diff --git a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h
index 9b900cc9ebe8..dab15f59f2cc 100644
--- a/drivers/scsi/gdth_proc.h
+++ b/drivers/scsi/gdth_proc.h
@@ -17,8 +17,8 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
int length, gdth_ha_str *ha);
static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch,
- ulong64 *paddr);
-static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr);
+ u64 *paddr);
+static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, u64 paddr);
static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id);
#endif
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 554626e18062..09dbcb847b73 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -215,6 +215,8 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
shost->shost_gendev.parent = dev ? dev : &platform_bus;
shost->dma_dev = dma_dev;
+ device_enable_async_suspend(&shost->shost_gendev);
+
error = device_add(&shost->shost_gendev);
if (error)
goto out;
@@ -222,6 +224,8 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
scsi_host_set_state(shost, SHOST_RUNNING);
get_device(shost->shost_gendev.parent);
+ device_enable_async_suspend(&shost->shost_dev);
+
error = device_add(&shost->shost_dev);
if (error)
goto out_del_gendev;
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index bb96fdd58e23..03697ba94251 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -52,7 +52,7 @@
#include "hpsa.h"
/* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */
-#define HPSA_DRIVER_VERSION "1.0.0"
+#define HPSA_DRIVER_VERSION "2.0.1-3"
#define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
/* How long to wait (in milliseconds) for board to go into simple mode */
@@ -77,9 +77,6 @@ MODULE_PARM_DESC(hpsa_allow_any,
/* define the PCI info for the cards we can control */
static const struct pci_device_id hpsa_pci_device_id[] = {
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3223},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3234},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x323D},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3241},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3243},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3245},
@@ -87,6 +84,9 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324a},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324b},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3233},
+#define PCI_DEVICE_ID_HP_CISSF 0x333f
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x333F},
{PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
{0,}
@@ -99,9 +99,6 @@ MODULE_DEVICE_TABLE(pci, hpsa_pci_device_id);
* access = Address of the struct of function pointers
*/
static struct board_type products[] = {
- {0x3223103C, "Smart Array P800", &SA5_access},
- {0x3234103C, "Smart Array P400", &SA5_access},
- {0x323d103c, "Smart Array P700M", &SA5_access},
{0x3241103C, "Smart Array P212", &SA5_access},
{0x3243103C, "Smart Array P410", &SA5_access},
{0x3245103C, "Smart Array P410i", &SA5_access},
@@ -109,6 +106,8 @@ static struct board_type products[] = {
{0x3249103C, "Smart Array P812", &SA5_access},
{0x324a103C, "Smart Array P712m", &SA5_access},
{0x324b103C, "Smart Array P711m", &SA5_access},
+ {0x3233103C, "StorageWorks P1210m", &SA5_access},
+ {0x333F103C, "StorageWorks P1210m", &SA5_access},
{0xFFFF103C, "Unknown Smart Array", &SA5_access},
};
@@ -126,12 +125,15 @@ static void cmd_free(struct ctlr_info *h, struct CommandList *c);
static void cmd_special_free(struct ctlr_info *h, struct CommandList *c);
static struct CommandList *cmd_alloc(struct ctlr_info *h);
static struct CommandList *cmd_special_alloc(struct ctlr_info *h);
-static void fill_cmd(struct CommandList *c, __u8 cmd, struct ctlr_info *h,
- void *buff, size_t size, __u8 page_code, unsigned char *scsi3addr,
+static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
+ void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
int cmd_type);
static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *));
+static void hpsa_scan_start(struct Scsi_Host *);
+static int hpsa_scan_finished(struct Scsi_Host *sh,
+ unsigned long elapsed_time);
static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
static int hpsa_slave_alloc(struct scsi_device *sdev);
@@ -150,6 +152,11 @@ static int check_for_unit_attention(struct ctlr_info *h,
struct CommandList *c);
static void check_ioctl_unit_attention(struct ctlr_info *h,
struct CommandList *c);
+/* performant mode helper functions */
+static void calc_bucket_map(int *bucket, int num_buckets,
+ int nsgs, int *bucket_map);
+static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
+static inline u32 next_command(struct ctlr_info *h);
static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
@@ -173,10 +180,10 @@ static struct scsi_host_template hpsa_driver_template = {
.name = "hpsa",
.proc_name = "hpsa",
.queuecommand = hpsa_scsi_queue_command,
- .can_queue = 512,
+ .scan_start = hpsa_scan_start,
+ .scan_finished = hpsa_scan_finished,
.this_id = -1,
.sg_tablesize = MAXSGENTRIES,
- .cmd_per_lun = 512,
.use_clustering = ENABLE_CLUSTERING,
.eh_device_reset_handler = hpsa_eh_device_reset_handler,
.ioctl = hpsa_ioctl,
@@ -195,6 +202,12 @@ static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
return (struct ctlr_info *) *priv;
}
+static inline struct ctlr_info *shost_to_hba(struct Scsi_Host *sh)
+{
+ unsigned long *priv = shost_priv(sh);
+ return (struct ctlr_info *) *priv;
+}
+
static struct task_struct *hpsa_scan_thread;
static DEFINE_MUTEX(hpsa_scan_mutex);
static LIST_HEAD(hpsa_scan_q);
@@ -312,7 +325,7 @@ static int hpsa_scan_func(__attribute__((unused)) void *data)
h->busy_scanning = 1;
mutex_unlock(&hpsa_scan_mutex);
host_no = h->scsi_host ? h->scsi_host->host_no : -1;
- hpsa_update_scsi_devices(h, host_no);
+ hpsa_scan_start(h->scsi_host);
complete_all(&h->scan_wait);
mutex_lock(&hpsa_scan_mutex);
h->busy_scanning = 0;
@@ -379,8 +392,7 @@ static ssize_t host_store_rescan(struct device *dev,
{
struct ctlr_info *h;
struct Scsi_Host *shost = class_to_shost(dev);
- unsigned long *priv = shost_priv(shost);
- h = (struct ctlr_info *) *priv;
+ h = shost_to_hba(shost);
if (add_to_scan_list(h)) {
wake_up_process(hpsa_scan_thread);
wait_for_completion_interruptible(&h->scan_wait);
@@ -394,10 +406,44 @@ static inline void addQ(struct hlist_head *list, struct CommandList *c)
hlist_add_head(&c->list, list);
}
+static inline u32 next_command(struct ctlr_info *h)
+{
+ u32 a;
+
+ if (unlikely(h->transMethod != CFGTBL_Trans_Performant))
+ return h->access.command_completed(h);
+
+ if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) {
+ a = *(h->reply_pool_head); /* Next cmd in ring buffer */
+ (h->reply_pool_head)++;
+ h->commands_outstanding--;
+ } else {
+ a = FIFO_EMPTY;
+ }
+ /* Check for wraparound */
+ if (h->reply_pool_head == (h->reply_pool + h->max_commands)) {
+ h->reply_pool_head = h->reply_pool;
+ h->reply_pool_wraparound ^= 1;
+ }
+ return a;
+}
+
+/* set_performant_mode: Modify the tag for cciss performant
+ * set bit 0 for pull model, bits 3-1 for block fetch
+ * register number
+ */
+static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
+{
+ if (likely(h->transMethod == CFGTBL_Trans_Performant))
+ c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
+}
+
static void enqueue_cmd_and_start_io(struct ctlr_info *h,
struct CommandList *c)
{
unsigned long flags;
+
+ set_performant_mode(h, c);
spin_lock_irqsave(&h->lock, flags);
addQ(&h->reqQ, c);
h->Qdepth++;
@@ -422,6 +468,15 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
return (scsi3addr[3] & 0xC0) == 0x40;
}
+static inline int is_scsi_rev_5(struct ctlr_info *h)
+{
+ if (!h->hba_inquiry_data)
+ return 0;
+ if ((h->hba_inquiry_data[2] & 0x07) == 5)
+ return 1;
+ return 0;
+}
+
static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
"UNKNOWN"
};
@@ -431,7 +486,7 @@ static ssize_t raid_level_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t l = 0;
- int rlevel;
+ unsigned char rlevel;
struct ctlr_info *h;
struct scsi_device *sdev;
struct hpsa_scsi_dev_t *hdev;
@@ -455,7 +510,7 @@ static ssize_t raid_level_show(struct device *dev,
rlevel = hdev->raid_level;
spin_unlock_irqrestore(&h->lock, flags);
- if (rlevel < 0 || rlevel > RAID_UNKNOWN)
+ if (rlevel > RAID_UNKNOWN)
rlevel = RAID_UNKNOWN;
l = snprintf(buf, PAGE_SIZE, "RAID %s\n", raid_label[rlevel]);
return l;
@@ -620,6 +675,24 @@ lun_assigned:
return 0;
}
+/* Replace an entry from h->dev[] array. */
+static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno,
+ int entry, struct hpsa_scsi_dev_t *new_entry,
+ struct hpsa_scsi_dev_t *added[], int *nadded,
+ struct hpsa_scsi_dev_t *removed[], int *nremoved)
+{
+ /* assumes h->devlock is held */
+ BUG_ON(entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA);
+ removed[*nremoved] = h->dev[entry];
+ (*nremoved)++;
+ h->dev[entry] = new_entry;
+ added[*nadded] = new_entry;
+ (*nadded)++;
+ dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d changed.\n",
+ scsi_device_type(new_entry->devtype), hostno, new_entry->bus,
+ new_entry->target, new_entry->lun);
+}
+
/* Remove an entry from h->dev[] array. */
static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry,
struct hpsa_scsi_dev_t *removed[], int *nremoved)
@@ -628,8 +701,7 @@ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry,
int i;
struct hpsa_scsi_dev_t *sd;
- if (entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA)
- BUG();
+ BUG_ON(entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA);
sd = h->dev[entry];
removed[*nremoved] = h->dev[entry];
@@ -722,6 +794,8 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
#define DEVICE_CHANGED 1
#define DEVICE_SAME 2
for (i = 0; i < haystack_size; i++) {
+ if (haystack[i] == NULL) /* previously removed. */
+ continue;
if (SCSI3ADDR_EQ(needle->scsi3addr, haystack[i]->scsi3addr)) {
*index = i;
if (device_is_the_same(needle, haystack[i]))
@@ -734,7 +808,7 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
return DEVICE_NOT_FOUND;
}
-static int adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
+static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
struct hpsa_scsi_dev_t *sd[], int nsds)
{
/* sd contains scsi3 addresses and devtypes, and inquiry
@@ -779,12 +853,12 @@ static int adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
continue; /* remove ^^^, hence i not incremented */
} else if (device_change == DEVICE_CHANGED) {
changes++;
- hpsa_scsi_remove_entry(h, hostno, i,
- removed, &nremoved);
- (void) hpsa_scsi_add_entry(h, hostno, sd[entry],
- added, &nadded);
- /* add can't fail, we just removed one. */
- sd[entry] = NULL; /* prevent it from being freed */
+ hpsa_scsi_replace_entry(h, hostno, i, sd[entry],
+ added, &nadded, removed, &nremoved);
+ /* Set it to NULL to prevent it from being freed
+ * at the bottom of hpsa_update_scsi_devices()
+ */
+ sd[entry] = NULL;
}
i++;
}
@@ -860,7 +934,6 @@ static int adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
free_and_out:
kfree(added);
kfree(removed);
- return 0;
}
/*
@@ -900,7 +973,7 @@ static int hpsa_slave_alloc(struct scsi_device *sdev)
static void hpsa_slave_destroy(struct scsi_device *sdev)
{
- return; /* nothing to do. */
+ /* nothing to do. */
}
static void hpsa_scsi_setup(struct ctlr_info *h)
@@ -908,11 +981,10 @@ static void hpsa_scsi_setup(struct ctlr_info *h)
h->ndevices = 0;
h->scsi_host = NULL;
spin_lock_init(&h->devlock);
- return;
}
static void complete_scsi_command(struct CommandList *cp,
- int timeout, __u32 tag)
+ int timeout, u32 tag)
{
struct scsi_cmnd *cmd;
struct ctlr_info *h;
@@ -987,7 +1059,6 @@ static void complete_scsi_command(struct CommandList *cp,
* required
*/
if ((asc == 0x04) && (ascq == 0x03)) {
- cmd->result = DID_NO_CONNECT << 16;
dev_warn(&h->pdev->dev, "cp %p "
"has check condition: unit "
"not ready, manual "
@@ -995,14 +1066,22 @@ static void complete_scsi_command(struct CommandList *cp,
break;
}
}
-
-
+ if (sense_key == ABORTED_COMMAND) {
+ /* Aborted command is retryable */
+ dev_warn(&h->pdev->dev, "cp %p "
+ "has check condition: aborted command: "
+ "ASC: 0x%x, ASCQ: 0x%x\n",
+ cp, asc, ascq);
+ cmd->result = DID_SOFT_ERROR << 16;
+ break;
+ }
/* Must be some other type of check condition */
dev_warn(&h->pdev->dev, "cp %p has check condition: "
"unknown type: "
"Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, "
"Returning result: 0x%x, "
"cmd=[%02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x]\n",
cp, sense_key, asc, ascq,
cmd->result,
@@ -1010,7 +1089,10 @@ static void complete_scsi_command(struct CommandList *cp,
cmd->cmnd[2], cmd->cmnd[3],
cmd->cmnd[4], cmd->cmnd[5],
cmd->cmnd[6], cmd->cmnd[7],
- cmd->cmnd[8], cmd->cmnd[9]);
+ cmd->cmnd[8], cmd->cmnd[9],
+ cmd->cmnd[10], cmd->cmnd[11],
+ cmd->cmnd[12], cmd->cmnd[13],
+ cmd->cmnd[14], cmd->cmnd[15]);
break;
}
@@ -1086,7 +1168,7 @@ static void complete_scsi_command(struct CommandList *cp,
dev_warn(&h->pdev->dev, "cp %p reports abort failed\n", cp);
break;
case CMD_UNSOLICITED_ABORT:
- cmd->result = DID_ABORT << 16;
+ cmd->result = DID_RESET << 16;
dev_warn(&h->pdev->dev, "cp %p aborted do to an unsolicited "
"abort\n", cp);
break;
@@ -1119,9 +1201,11 @@ static int hpsa_scsi_detect(struct ctlr_info *h)
sh->max_cmd_len = MAX_COMMAND_SIZE;
sh->max_lun = HPSA_MAX_LUN;
sh->max_id = HPSA_MAX_LUN;
+ sh->can_queue = h->nr_cmds;
+ sh->cmd_per_lun = h->nr_cmds;
h->scsi_host = sh;
sh->hostdata[0] = (unsigned long) h;
- sh->irq = h->intr[SIMPLE_MODE_INT];
+ sh->irq = h->intr[PERF_MODE_INT];
sh->unique_id = sh->irq;
error = scsi_add_host(sh, &h->pdev->dev);
if (error)
@@ -1133,11 +1217,11 @@ static int hpsa_scsi_detect(struct ctlr_info *h)
dev_err(&h->pdev->dev, "hpsa_scsi_detect: scsi_add_host"
" failed for controller %d\n", h->ctlr);
scsi_host_put(sh);
- return -1;
+ return error;
fail:
dev_err(&h->pdev->dev, "hpsa_scsi_detect: scsi_host_alloc"
" failed for controller %d\n", h->ctlr);
- return -1;
+ return -ENOMEM;
}
static void hpsa_pci_unmap(struct pci_dev *pdev,
@@ -1160,7 +1244,7 @@ static void hpsa_map_one(struct pci_dev *pdev,
size_t buflen,
int data_direction)
{
- __u64 addr64;
+ u64 addr64;
if (buflen == 0 || data_direction == PCI_DMA_NONE) {
cp->Header.SGList = 0;
@@ -1168,14 +1252,14 @@ static void hpsa_map_one(struct pci_dev *pdev,
return;
}
- addr64 = (__u64) pci_map_single(pdev, buf, buflen, data_direction);
+ addr64 = (u64) pci_map_single(pdev, buf, buflen, data_direction);
cp->SG[0].Addr.lower =
- (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+ (u32) (addr64 & (u64) 0x00000000FFFFFFFF);
cp->SG[0].Addr.upper =
- (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+ (u32) ((addr64 >> 32) & (u64) 0x00000000FFFFFFFF);
cp->SG[0].Len = buflen;
- cp->Header.SGList = (__u8) 1; /* no. SGs contig in this cmd */
- cp->Header.SGTotal = (__u16) 1; /* total sgs in this cmd list */
+ cp->Header.SGList = (u8) 1; /* no. SGs contig in this cmd */
+ cp->Header.SGTotal = (u16) 1; /* total sgs in this cmd list */
}
static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h,
@@ -1274,7 +1358,7 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
if (c == NULL) { /* trouble... */
dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
- return -1;
+ return -ENOMEM;
}
fill_cmd(c, HPSA_INQUIRY, h, buf, bufsize, page, scsi3addr, TYPE_CMD);
@@ -1366,9 +1450,8 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
dev_err(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
return -1;
}
-
- memset(&scsi3addr[0], 0, 8); /* address the controller */
-
+ /* address the controller */
+ memset(scsi3addr, 0, sizeof(scsi3addr));
fill_cmd(c, logical ? HPSA_REPORT_LOG : HPSA_REPORT_PHYS, h,
buf, bufsize, 0, scsi3addr, TYPE_CMD);
if (extended_response)
@@ -1409,13 +1492,12 @@ static int hpsa_update_device_info(struct ctlr_info *h,
unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device)
{
#define OBDR_TAPE_INQ_SIZE 49
- unsigned char *inq_buff = NULL;
+ unsigned char *inq_buff;
- inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
+ inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
if (!inq_buff)
goto bail_out;
- memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE);
/* Do an inquiry to the device to see what it is. */
if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff,
(unsigned char) OBDR_TAPE_INQ_SIZE) != 0) {
@@ -1485,32 +1567,51 @@ static int is_msa2xxx(struct ctlr_info *h, struct hpsa_scsi_dev_t *device)
* in hpsa_find_target_lun, called by hpsa_scsi_add_entry.)
*/
static void figure_bus_target_lun(struct ctlr_info *h,
- __u8 *lunaddrbytes, int *bus, int *target, int *lun,
+ u8 *lunaddrbytes, int *bus, int *target, int *lun,
struct hpsa_scsi_dev_t *device)
{
-
- __u32 lunid;
+ u32 lunid;
if (is_logical_dev_addr_mode(lunaddrbytes)) {
/* logical device */
- memcpy(&lunid, lunaddrbytes, sizeof(lunid));
- lunid = le32_to_cpu(lunid);
-
- if (is_msa2xxx(h, device)) {
- *bus = 1;
- *target = (lunid >> 16) & 0x3fff;
- *lun = lunid & 0x00ff;
- } else {
+ if (unlikely(is_scsi_rev_5(h))) {
+ /* p1210m, logical drives lun assignments
+ * match SCSI REPORT LUNS data.
+ */
+ lunid = le32_to_cpu(*((__le32 *) lunaddrbytes));
*bus = 0;
- *lun = 0;
- *target = lunid & 0x3fff;
+ *target = 0;
+ *lun = (lunid & 0x3fff) + 1;
+ } else {
+ /* not p1210m... */
+ lunid = le32_to_cpu(*((__le32 *) lunaddrbytes));
+ if (is_msa2xxx(h, device)) {
+ /* msa2xxx way, put logicals on bus 1
+ * and match target/lun numbers box
+ * reports.
+ */
+ *bus = 1;
+ *target = (lunid >> 16) & 0x3fff;
+ *lun = lunid & 0x00ff;
+ } else {
+ /* Traditional smart array way. */
+ *bus = 0;
+ *lun = 0;
+ *target = lunid & 0x3fff;
+ }
}
} else {
/* physical device */
if (is_hba_lunid(lunaddrbytes))
- *bus = 3;
+ if (unlikely(is_scsi_rev_5(h))) {
+ *bus = 0; /* put p1210m ctlr at 0,0,0 */
+ *target = 0;
+ *lun = 0;
+ return;
+ } else
+ *bus = 3; /* traditional smartarray */
else
- *bus = 2;
+ *bus = 2; /* physical disk */
*target = -1;
*lun = -1; /* we will fill these in later. */
}
@@ -1529,7 +1630,7 @@ static void figure_bus_target_lun(struct ctlr_info *h,
*/
static int add_msa2xxx_enclosure_device(struct ctlr_info *h,
struct hpsa_scsi_dev_t *tmpdevice,
- struct hpsa_scsi_dev_t *this_device, __u8 *lunaddrbytes,
+ struct hpsa_scsi_dev_t *this_device, u8 *lunaddrbytes,
int bus, int target, int lun, unsigned long lunzerobits[],
int *nmsa2xxx_enclosures)
{
@@ -1550,6 +1651,9 @@ static int add_msa2xxx_enclosure_device(struct ctlr_info *h,
if (is_hba_lunid(scsi3addr))
return 0; /* Don't add the RAID controller here. */
+ if (is_scsi_rev_5(h))
+ return 0; /* p1210m doesn't need to do this. */
+
#define MAX_MSA2XXX_ENCLOSURES 32
if (*nmsa2xxx_enclosures >= MAX_MSA2XXX_ENCLOSURES) {
dev_warn(&h->pdev->dev, "Maximum number of MSA2XXX "
@@ -1576,18 +1680,14 @@ static int add_msa2xxx_enclosure_device(struct ctlr_info *h,
*/
static int hpsa_gather_lun_info(struct ctlr_info *h,
int reportlunsize,
- struct ReportLUNdata *physdev, __u32 *nphysicals,
- struct ReportLUNdata *logdev, __u32 *nlogicals)
+ struct ReportLUNdata *physdev, u32 *nphysicals,
+ struct ReportLUNdata *logdev, u32 *nlogicals)
{
if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize, 0)) {
dev_err(&h->pdev->dev, "report physical LUNs failed.\n");
return -1;
}
- memcpy(nphysicals, &physdev->LUNListLength[0], sizeof(*nphysicals));
- *nphysicals = be32_to_cpu(*nphysicals) / 8;
-#ifdef DEBUG
- dev_info(&h->pdev->dev, "number of physical luns is %d\n", *nphysicals);
-#endif
+ *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 8;
if (*nphysicals > HPSA_MAX_PHYS_LUN) {
dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded."
" %d LUNs ignored.\n", HPSA_MAX_PHYS_LUN,
@@ -1598,11 +1698,7 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
dev_err(&h->pdev->dev, "report logical LUNs failed.\n");
return -1;
}
- memcpy(nlogicals, &logdev->LUNListLength[0], sizeof(*nlogicals));
- *nlogicals = be32_to_cpu(*nlogicals) / 8;
-#ifdef DEBUG
- dev_info(&h->pdev->dev, "number of logical luns is %d\n", *nlogicals);
-#endif
+ *nlogicals = be32_to_cpu(*((__be32 *) logdev->LUNListLength)) / 8;
/* Reject Logicals in excess of our max capability. */
if (*nlogicals > HPSA_MAX_LUN) {
dev_warn(&h->pdev->dev,
@@ -1621,6 +1717,31 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
return 0;
}
+u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i,
+ int nphysicals, int nlogicals, struct ReportLUNdata *physdev_list,
+ struct ReportLUNdata *logdev_list)
+{
+ /* Helper function, figure out where the LUN ID info is coming from
+ * given index i, lists of physical and logical devices, where in
+ * the list the raid controller is supposed to appear (first or last)
+ */
+
+ int logicals_start = nphysicals + (raid_ctlr_position == 0);
+ int last_device = nphysicals + nlogicals + (raid_ctlr_position == 0);
+
+ if (i == raid_ctlr_position)
+ return RAID_CTLR_LUNID;
+
+ if (i < logicals_start)
+ return &physdev_list->LUN[i - (raid_ctlr_position == 0)][0];
+
+ if (i < last_device)
+ return &logdev_list->LUN[i - nphysicals -
+ (raid_ctlr_position == 0)][0];
+ BUG();
+ return NULL;
+}
+
static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
{
/* the idea here is we could get notified
@@ -1636,14 +1757,15 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
struct ReportLUNdata *physdev_list = NULL;
struct ReportLUNdata *logdev_list = NULL;
unsigned char *inq_buff = NULL;
- __u32 nphysicals = 0;
- __u32 nlogicals = 0;
- __u32 ndev_allocated = 0;
+ u32 nphysicals = 0;
+ u32 nlogicals = 0;
+ u32 ndev_allocated = 0;
struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice;
int ncurrent = 0;
int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 8;
int i, nmsa2xxx_enclosures, ndevs_to_allocate;
int bus, target, lun;
+ int raid_ctlr_position;
DECLARE_BITMAP(lunzerobits, HPSA_MAX_TARGETS_PER_CTLR);
currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_SCSI_DEVS_PER_HBA,
@@ -1681,23 +1803,22 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
ndev_allocated++;
}
+ if (unlikely(is_scsi_rev_5(h)))
+ raid_ctlr_position = 0;
+ else
+ raid_ctlr_position = nphysicals + nlogicals;
+
/* adjust our table of devices */
nmsa2xxx_enclosures = 0;
for (i = 0; i < nphysicals + nlogicals + 1; i++) {
- __u8 *lunaddrbytes;
+ u8 *lunaddrbytes;
/* Figure out where the LUN ID info is coming from */
- if (i < nphysicals)
- lunaddrbytes = &physdev_list->LUN[i][0];
- else
- if (i < nphysicals + nlogicals)
- lunaddrbytes =
- &logdev_list->LUN[i-nphysicals][0];
- else /* jam in the RAID controller at the end */
- lunaddrbytes = RAID_CTLR_LUNID;
-
+ lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position,
+ i, nphysicals, nlogicals, physdev_list, logdev_list);
/* skip masked physical devices. */
- if (lunaddrbytes[3] & 0xC0 && i < nphysicals)
+ if (lunaddrbytes[3] & 0xC0 &&
+ i < nphysicals + (raid_ctlr_position == 0))
continue;
/* Get device type, vendor, model, device id */
@@ -1777,7 +1898,6 @@ out:
kfree(inq_buff);
kfree(physdev_list);
kfree(logdev_list);
- return;
}
/* hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci
@@ -1790,7 +1910,7 @@ static int hpsa_scatter_gather(struct pci_dev *pdev,
{
unsigned int len;
struct scatterlist *sg;
- __u64 addr64;
+ u64 addr64;
int use_sg, i;
BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES);
@@ -1803,20 +1923,20 @@ static int hpsa_scatter_gather(struct pci_dev *pdev,
goto sglist_finished;
scsi_for_each_sg(cmd, sg, use_sg, i) {
- addr64 = (__u64) sg_dma_address(sg);
+ addr64 = (u64) sg_dma_address(sg);
len = sg_dma_len(sg);
cp->SG[i].Addr.lower =
- (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+ (u32) (addr64 & (u64) 0x00000000FFFFFFFF);
cp->SG[i].Addr.upper =
- (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+ (u32) ((addr64 >> 32) & (u64) 0x00000000FFFFFFFF);
cp->SG[i].Len = len;
cp->SG[i].Ext = 0; /* we are not chaining */
}
sglist_finished:
- cp->Header.SGList = (__u8) use_sg; /* no. SGs contig in this cmd */
- cp->Header.SGTotal = (__u16) use_sg; /* total sgs in this cmd list */
+ cp->Header.SGList = (u8) use_sg; /* no. SGs contig in this cmd */
+ cp->Header.SGTotal = (u16) use_sg; /* total sgs in this cmd list */
return 0;
}
@@ -1860,7 +1980,8 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
c->scsi_cmd = cmd;
c->Header.ReplyQueue = 0; /* unused in simple mode */
memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
- c->Header.Tag.lower = c->busaddr; /* Use k. address of cmd as tag */
+ c->Header.Tag.lower = (c->cmdindex << DIRECT_LOOKUP_SHIFT);
+ c->Header.Tag.lower |= DIRECT_LOOKUP_BIT;
/* Fill in the request block... */
@@ -1914,6 +2035,48 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
return 0;
}
+static void hpsa_scan_start(struct Scsi_Host *sh)
+{
+ struct ctlr_info *h = shost_to_hba(sh);
+ unsigned long flags;
+
+ /* wait until any scan already in progress is finished. */
+ while (1) {
+ spin_lock_irqsave(&h->scan_lock, flags);
+ if (h->scan_finished)
+ break;
+ spin_unlock_irqrestore(&h->scan_lock, flags);
+ wait_event(h->scan_wait_queue, h->scan_finished);
+ /* Note: We don't need to worry about a race between this
+ * thread and driver unload because the midlayer will
+ * have incremented the reference count, so unload won't
+ * happen if we're in here.
+ */
+ }
+ h->scan_finished = 0; /* mark scan as in progress */
+ spin_unlock_irqrestore(&h->scan_lock, flags);
+
+ hpsa_update_scsi_devices(h, h->scsi_host->host_no);
+
+ spin_lock_irqsave(&h->scan_lock, flags);
+ h->scan_finished = 1; /* mark scan as finished. */
+ wake_up_all(&h->scan_wait_queue);
+ spin_unlock_irqrestore(&h->scan_lock, flags);
+}
+
+static int hpsa_scan_finished(struct Scsi_Host *sh,
+ unsigned long elapsed_time)
+{
+ struct ctlr_info *h = shost_to_hba(sh);
+ unsigned long flags;
+ int finished;
+
+ spin_lock_irqsave(&h->scan_lock, flags);
+ finished = h->scan_finished;
+ spin_unlock_irqrestore(&h->scan_lock, flags);
+ return finished;
+}
+
static void hpsa_unregister_scsi(struct ctlr_info *h)
{
/* we are being forcibly unloaded, and may not refuse. */
@@ -1926,7 +2089,6 @@ static int hpsa_register_scsi(struct ctlr_info *h)
{
int rc;
- hpsa_update_scsi_devices(h, -1);
rc = hpsa_scsi_detect(h);
if (rc != 0)
dev_err(&h->pdev->dev, "hpsa_register_scsi: failed"
@@ -2003,14 +2165,14 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
h = sdev_to_hba(scsicmd->device);
if (h == NULL) /* paranoia */
return FAILED;
- dev_warn(&h->pdev->dev, "resetting drive\n");
-
dev = scsicmd->device->hostdata;
if (!dev) {
dev_err(&h->pdev->dev, "hpsa_eh_device_reset_handler: "
"device lookup failed.\n");
return FAILED;
}
+ dev_warn(&h->pdev->dev, "resetting device %d:%d:%d:%d\n",
+ h->scsi_host->host_no, dev->bus, dev->target, dev->lun);
/* send a reset to the SCSI LUN which the command was sent to */
rc = hpsa_send_reset(h, dev->scsi3addr);
if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0)
@@ -2053,8 +2215,8 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
c->cmdindex = i;
INIT_HLIST_NODE(&c->list);
- c->busaddr = (__u32) cmd_dma_handle;
- temp64.val = (__u64) err_dma_handle;
+ c->busaddr = (u32) cmd_dma_handle;
+ temp64.val = (u64) err_dma_handle;
c->ErrDesc.Addr.lower = temp64.val32.lower;
c->ErrDesc.Addr.upper = temp64.val32.upper;
c->ErrDesc.Len = sizeof(*c->err_info);
@@ -2091,8 +2253,8 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
memset(c->err_info, 0, sizeof(*c->err_info));
INIT_HLIST_NODE(&c->list);
- c->busaddr = (__u32) cmd_dma_handle;
- temp64.val = (__u64) err_dma_handle;
+ c->busaddr = (u32) cmd_dma_handle;
+ temp64.val = (u64) err_dma_handle;
c->ErrDesc.Addr.lower = temp64.val32.lower;
c->ErrDesc.Addr.upper = temp64.val32.upper;
c->ErrDesc.Len = sizeof(*c->err_info);
@@ -2125,50 +2287,6 @@ static void cmd_special_free(struct ctlr_info *h, struct CommandList *c)
#ifdef CONFIG_COMPAT
-static int do_ioctl(struct scsi_device *dev, int cmd, void *arg)
-{
- int ret;
-
- lock_kernel();
- ret = hpsa_ioctl(dev, cmd, arg);
- unlock_kernel();
- return ret;
-}
-
-static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg);
-static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
- int cmd, void *arg);
-
-static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg)
-{
- switch (cmd) {
- case CCISS_GETPCIINFO:
- case CCISS_GETINTINFO:
- case CCISS_SETINTINFO:
- case CCISS_GETNODENAME:
- case CCISS_SETNODENAME:
- case CCISS_GETHEARTBEAT:
- case CCISS_GETBUSTYPES:
- case CCISS_GETFIRMVER:
- case CCISS_GETDRIVVER:
- case CCISS_REVALIDVOLS:
- case CCISS_DEREGDISK:
- case CCISS_REGNEWDISK:
- case CCISS_REGNEWD:
- case CCISS_RESCANDISK:
- case CCISS_GETLUNINFO:
- return do_ioctl(dev, cmd, arg);
-
- case CCISS_PASSTHRU32:
- return hpsa_ioctl32_passthru(dev, cmd, arg);
- case CCISS_BIG_PASSTHRU32:
- return hpsa_ioctl32_big_passthru(dev, cmd, arg);
-
- default:
- return -ENOIOCTLCMD;
- }
-}
-
static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg)
{
IOCTL32_Command_struct __user *arg32 =
@@ -2193,7 +2311,7 @@ static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg)
if (err)
return -EFAULT;
- err = do_ioctl(dev, CCISS_PASSTHRU, (void *)p);
+ err = hpsa_ioctl(dev, CCISS_PASSTHRU, (void *)p);
if (err)
return err;
err |= copy_in_user(&arg32->error_info, &p->error_info,
@@ -2230,7 +2348,7 @@ static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
if (err)
return -EFAULT;
- err = do_ioctl(dev, CCISS_BIG_PASSTHRU, (void *)p);
+ err = hpsa_ioctl(dev, CCISS_BIG_PASSTHRU, (void *)p);
if (err)
return err;
err |= copy_in_user(&arg32->error_info, &p->error_info,
@@ -2239,6 +2357,36 @@ static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
return -EFAULT;
return err;
}
+
+static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg)
+{
+ switch (cmd) {
+ case CCISS_GETPCIINFO:
+ case CCISS_GETINTINFO:
+ case CCISS_SETINTINFO:
+ case CCISS_GETNODENAME:
+ case CCISS_SETNODENAME:
+ case CCISS_GETHEARTBEAT:
+ case CCISS_GETBUSTYPES:
+ case CCISS_GETFIRMVER:
+ case CCISS_GETDRIVVER:
+ case CCISS_REVALIDVOLS:
+ case CCISS_DEREGDISK:
+ case CCISS_REGNEWDISK:
+ case CCISS_REGNEWD:
+ case CCISS_RESCANDISK:
+ case CCISS_GETLUNINFO:
+ return hpsa_ioctl(dev, cmd, arg);
+
+ case CCISS_PASSTHRU32:
+ return hpsa_ioctl32_passthru(dev, cmd, arg);
+ case CCISS_BIG_PASSTHRU32:
+ return hpsa_ioctl32_big_passthru(dev, cmd, arg);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
#endif
static int hpsa_getpciinfo_ioctl(struct ctlr_info *h, void __user *argp)
@@ -2378,8 +2526,8 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
BYTE sg_used = 0;
int status = 0;
int i;
- __u32 left;
- __u32 sz;
+ u32 left;
+ u32 sz;
BYTE __user *data_ptr;
if (!argp)
@@ -2527,7 +2675,7 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg)
case CCISS_DEREGDISK:
case CCISS_REGNEWDISK:
case CCISS_REGNEWD:
- hpsa_update_scsi_devices(h, dev->host->host_no);
+ hpsa_scan_start(h->scsi_host);
return 0;
case CCISS_GETPCIINFO:
return hpsa_getpciinfo_ioctl(h, argp);
@@ -2542,8 +2690,8 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg)
}
}
-static void fill_cmd(struct CommandList *c, __u8 cmd, struct ctlr_info *h,
- void *buff, size_t size, __u8 page_code, unsigned char *scsi3addr,
+static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
+ void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
int cmd_type)
{
int pci_dir = XFER_NONE;
@@ -2710,19 +2858,20 @@ static inline unsigned long get_next_completion(struct ctlr_info *h)
return h->access.command_completed(h);
}
-static inline int interrupt_pending(struct ctlr_info *h)
+static inline bool interrupt_pending(struct ctlr_info *h)
{
return h->access.intr_pending(h);
}
static inline long interrupt_not_for_us(struct ctlr_info *h)
{
- return ((h->access.intr_pending(h) == 0) ||
- (h->interrupts_enabled == 0));
+ return !(h->msi_vector || h->msix_vector) &&
+ ((h->access.intr_pending(h) == 0) ||
+ (h->interrupts_enabled == 0));
}
-static inline int bad_tag(struct ctlr_info *h, __u32 tag_index,
- __u32 raw_tag)
+static inline int bad_tag(struct ctlr_info *h, u32 tag_index,
+ u32 raw_tag)
{
if (unlikely(tag_index >= h->nr_cmds)) {
dev_warn(&h->pdev->dev, "bad tag 0x%08x ignored.\n", raw_tag);
@@ -2731,7 +2880,7 @@ static inline int bad_tag(struct ctlr_info *h, __u32 tag_index,
return 0;
}
-static inline void finish_cmd(struct CommandList *c, __u32 raw_tag)
+static inline void finish_cmd(struct CommandList *c, u32 raw_tag)
{
removeQ(c);
if (likely(c->cmd_type == CMD_SCSI))
@@ -2740,42 +2889,79 @@ static inline void finish_cmd(struct CommandList *c, __u32 raw_tag)
complete(c->waiting);
}
+static inline u32 hpsa_tag_contains_index(u32 tag)
+{
+#define DIRECT_LOOKUP_BIT 0x10
+ return tag & DIRECT_LOOKUP_BIT;
+}
+
+static inline u32 hpsa_tag_to_index(u32 tag)
+{
+#define DIRECT_LOOKUP_SHIFT 5
+ return tag >> DIRECT_LOOKUP_SHIFT;
+}
+
+static inline u32 hpsa_tag_discard_error_bits(u32 tag)
+{
+#define HPSA_ERROR_BITS 0x03
+ return tag & ~HPSA_ERROR_BITS;
+}
+
+/* process completion of an indexed ("direct lookup") command */
+static inline u32 process_indexed_cmd(struct ctlr_info *h,
+ u32 raw_tag)
+{
+ u32 tag_index;
+ struct CommandList *c;
+
+ tag_index = hpsa_tag_to_index(raw_tag);
+ if (bad_tag(h, tag_index, raw_tag))
+ return next_command(h);
+ c = h->cmd_pool + tag_index;
+ finish_cmd(c, raw_tag);
+ return next_command(h);
+}
+
+/* process completion of a non-indexed command */
+static inline u32 process_nonindexed_cmd(struct ctlr_info *h,
+ u32 raw_tag)
+{
+ u32 tag;
+ struct CommandList *c = NULL;
+ struct hlist_node *tmp;
+
+ tag = hpsa_tag_discard_error_bits(raw_tag);
+ hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
+ if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) {
+ finish_cmd(c, raw_tag);
+ return next_command(h);
+ }
+ }
+ bad_tag(h, h->nr_cmds + 1, raw_tag);
+ return next_command(h);
+}
+
static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
{
struct ctlr_info *h = dev_id;
- struct CommandList *c;
unsigned long flags;
- __u32 raw_tag, tag, tag_index;
- struct hlist_node *tmp;
+ u32 raw_tag;
if (interrupt_not_for_us(h))
return IRQ_NONE;
spin_lock_irqsave(&h->lock, flags);
- while (interrupt_pending(h)) {
- while ((raw_tag = get_next_completion(h)) != FIFO_EMPTY) {
- if (likely(HPSA_TAG_CONTAINS_INDEX(raw_tag))) {
- tag_index = HPSA_TAG_TO_INDEX(raw_tag);
- if (bad_tag(h, tag_index, raw_tag))
- return IRQ_HANDLED;
- c = h->cmd_pool + tag_index;
- finish_cmd(c, raw_tag);
- continue;
- }
- tag = HPSA_TAG_DISCARD_ERROR_BITS(raw_tag);
- c = NULL;
- hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
- if (c->busaddr == tag) {
- finish_cmd(c, raw_tag);
- break;
- }
- }
- }
+ raw_tag = get_next_completion(h);
+ while (raw_tag != FIFO_EMPTY) {
+ if (hpsa_tag_contains_index(raw_tag))
+ raw_tag = process_indexed_cmd(h, raw_tag);
+ else
+ raw_tag = process_nonindexed_cmd(h, raw_tag);
}
spin_unlock_irqrestore(&h->lock, flags);
return IRQ_HANDLED;
}
-/* Send a message CDB to the firmware. */
+/* Send a message CDB to the firmwart. */
static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
unsigned char type)
{
@@ -2841,7 +3027,7 @@ static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
for (i = 0; i < HPSA_MSG_SEND_RETRY_LIMIT; i++) {
tag = readl(vaddr + SA5_REPLY_PORT_OFFSET);
- if (HPSA_TAG_DISCARD_ERROR_BITS(tag) == paddr32)
+ if (hpsa_tag_discard_error_bits(tag) == paddr32)
break;
msleep(HPSA_MSG_SEND_RETRY_INTERVAL_MSECS);
}
@@ -3063,7 +3249,7 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
*/
static void __devinit hpsa_interrupt_mode(struct ctlr_info *h,
- struct pci_dev *pdev, __u32 board_id)
+ struct pci_dev *pdev, u32 board_id)
{
#ifdef CONFIG_PCI_MSI
int err;
@@ -3107,22 +3293,22 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h,
default_int_mode:
#endif /* CONFIG_PCI_MSI */
/* if we get here we're going to use the default interrupt mode */
- h->intr[SIMPLE_MODE_INT] = pdev->irq;
- return;
+ h->intr[PERF_MODE_INT] = pdev->irq;
}
static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
{
ushort subsystem_vendor_id, subsystem_device_id, command;
- __u32 board_id, scratchpad = 0;
- __u64 cfg_offset;
- __u32 cfg_base_addr;
- __u64 cfg_base_addr_index;
+ u32 board_id, scratchpad = 0;
+ u64 cfg_offset;
+ u32 cfg_base_addr;
+ u64 cfg_base_addr_index;
+ u32 trans_offset;
int i, prod_index, err;
subsystem_vendor_id = pdev->subsystem_vendor;
subsystem_device_id = pdev->subsystem_device;
- board_id = (((__u32) (subsystem_device_id << 16) & 0xffff0000) |
+ board_id = (((u32) (subsystem_device_id << 16) & 0xffff0000) |
subsystem_vendor_id);
for (i = 0; i < ARRAY_SIZE(products); i++)
@@ -3199,7 +3385,7 @@ static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
/* get the address index number */
cfg_base_addr = readl(h->vaddr + SA5_CTCFG_OFFSET);
- cfg_base_addr &= (__u32) 0x0000ffff;
+ cfg_base_addr &= (u32) 0x0000ffff;
cfg_base_addr_index = find_PCI_BAR_index(pdev, cfg_base_addr);
if (cfg_base_addr_index == -1) {
dev_warn(&pdev->dev, "cannot find cfg_base_addr_index\n");
@@ -3211,11 +3397,14 @@ static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
h->cfgtable = remap_pci_mem(pci_resource_start(pdev,
cfg_base_addr_index) + cfg_offset,
sizeof(h->cfgtable));
- h->board_id = board_id;
-
- /* Query controller for max supported commands: */
- h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
+ /* Find performant mode table. */
+ trans_offset = readl(&(h->cfgtable->TransMethodOffset));
+ h->transtable = remap_pci_mem(pci_resource_start(pdev,
+ cfg_base_addr_index)+cfg_offset+trans_offset,
+ sizeof(*h->transtable));
+ h->board_id = board_id;
+ h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
h->product_name = products[prod_index].product_name;
h->access = *(products[prod_index].access);
/* Allow room for some ioctls */
@@ -3232,7 +3421,7 @@ static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
#ifdef CONFIG_X86
{
/* Need to enable prefetch in the SCSI core for 6400 in x86 */
- __u32 prefetch;
+ u32 prefetch;
prefetch = readl(&(h->cfgtable->SCSI_Prefetch));
prefetch |= 0x100;
writel(prefetch, &(h->cfgtable->SCSI_Prefetch));
@@ -3244,7 +3433,7 @@ static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
* physical memory.
*/
if (board_id == 0x3225103C) {
- __u32 dma_prefetch;
+ u32 dma_prefetch;
dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG);
dma_prefetch |= 0x8000;
writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
@@ -3286,10 +3475,26 @@ err_out_free_res:
return err;
}
+static void __devinit hpsa_hba_inquiry(struct ctlr_info *h)
+{
+ int rc;
+
+#define HBA_INQUIRY_BYTE_COUNT 64
+ h->hba_inquiry_data = kmalloc(HBA_INQUIRY_BYTE_COUNT, GFP_KERNEL);
+ if (!h->hba_inquiry_data)
+ return;
+ rc = hpsa_scsi_do_inquiry(h, RAID_CTLR_LUNID, 0,
+ h->hba_inquiry_data, HBA_INQUIRY_BYTE_COUNT);
+ if (rc != 0) {
+ kfree(h->hba_inquiry_data);
+ h->hba_inquiry_data = NULL;
+ }
+}
+
static int __devinit hpsa_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- int i;
+ int i, rc;
int dac;
struct ctlr_info *h;
@@ -3314,17 +3519,23 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
}
}
- BUILD_BUG_ON(sizeof(struct CommandList) % 8);
+ /* Command structures must be aligned on a 32-byte boundary because
+ * the 5 lower bits of the address are used by the hardware. and by
+ * the driver. See comments in hpsa.h for more info.
+ */
+#define COMMANDLIST_ALIGNMENT 32
+ BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT);
h = kzalloc(sizeof(*h), GFP_KERNEL);
if (!h)
- return -1;
+ return -ENOMEM;
h->busy_initializing = 1;
INIT_HLIST_HEAD(&h->cmpQ);
INIT_HLIST_HEAD(&h->reqQ);
mutex_init(&h->busy_shutting_down);
init_completion(&h->scan_wait);
- if (hpsa_pci_init(h, pdev) != 0)
+ rc = hpsa_pci_init(h, pdev);
+ if (rc != 0)
goto clean1;
sprintf(h->devname, "hpsa%d", number_of_controllers);
@@ -3333,27 +3544,32 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
h->pdev = pdev;
/* configure PCI DMA stuff */
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (rc == 0) {
dac = 1;
- else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
- dac = 0;
- else {
- dev_err(&pdev->dev, "no suitable DMA available\n");
- goto clean1;
+ } else {
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc == 0) {
+ dac = 0;
+ } else {
+ dev_err(&pdev->dev, "no suitable DMA available\n");
+ goto clean1;
+ }
}
/* make sure the board interrupts are off */
h->access.set_intr_mask(h, HPSA_INTR_OFF);
- if (request_irq(h->intr[SIMPLE_MODE_INT], do_hpsa_intr,
- IRQF_DISABLED | IRQF_SHARED, h->devname, h)) {
+ rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr,
+ IRQF_DISABLED, h->devname, h);
+ if (rc) {
dev_err(&pdev->dev, "unable to get irq %d for %s\n",
- h->intr[SIMPLE_MODE_INT], h->devname);
+ h->intr[PERF_MODE_INT], h->devname);
goto clean2;
}
- dev_info(&pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
- h->devname, pdev->device, pci_name(pdev),
- h->intr[SIMPLE_MODE_INT], dac ? "" : " not");
+ dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n",
+ h->devname, pdev->device,
+ h->intr[PERF_MODE_INT], dac ? "" : " not");
h->cmd_pool_bits =
kmalloc(((h->nr_cmds + BITS_PER_LONG -
@@ -3368,9 +3584,13 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
|| (h->cmd_pool == NULL)
|| (h->errinfo_pool == NULL)) {
dev_err(&pdev->dev, "out of memory");
+ rc = -ENOMEM;
goto clean4;
}
spin_lock_init(&h->lock);
+ spin_lock_init(&h->scan_lock);
+ init_waitqueue_head(&h->scan_wait_queue);
+ h->scan_finished = 1; /* no scan currently in progress */
pci_set_drvdata(pdev, h);
memset(h->cmd_pool_bits, 0,
@@ -3382,6 +3602,8 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
/* Turn the interrupts on so we can service requests */
h->access.set_intr_mask(h, HPSA_INTR_ON);
+ hpsa_put_ctlr_into_performant_mode(h);
+ hpsa_hba_inquiry(h);
hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */
h->busy_initializing = 0;
return 1;
@@ -3397,12 +3619,12 @@ clean4:
h->nr_cmds * sizeof(struct ErrorInfo),
h->errinfo_pool,
h->errinfo_pool_dhandle);
- free_irq(h->intr[SIMPLE_MODE_INT], h);
+ free_irq(h->intr[PERF_MODE_INT], h);
clean2:
clean1:
h->busy_initializing = 0;
kfree(h);
- return -1;
+ return rc;
}
static void hpsa_flush_cache(struct ctlr_info *h)
@@ -3441,7 +3663,7 @@ static void hpsa_shutdown(struct pci_dev *pdev)
*/
hpsa_flush_cache(h);
h->access.set_intr_mask(h, HPSA_INTR_OFF);
- free_irq(h->intr[2], h);
+ free_irq(h->intr[PERF_MODE_INT], h);
#ifdef CONFIG_PCI_MSI
if (h->msix_vector)
pci_disable_msix(h->pdev);
@@ -3470,7 +3692,11 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev)
pci_free_consistent(h->pdev,
h->nr_cmds * sizeof(struct ErrorInfo),
h->errinfo_pool, h->errinfo_pool_dhandle);
+ pci_free_consistent(h->pdev, h->reply_pool_size,
+ h->reply_pool, h->reply_pool_dhandle);
kfree(h->cmd_pool_bits);
+ kfree(h->blockFetchTable);
+ kfree(h->hba_inquiry_data);
/*
* Deliberately omit pci_disable_device(): it does something nasty to
* Smart Array controllers that pci_enable_device does not undo
@@ -3502,6 +3728,129 @@ static struct pci_driver hpsa_pci_driver = {
.resume = hpsa_resume,
};
+/* Fill in bucket_map[], given nsgs (the max number of
+ * scatter gather elements supported) and bucket[],
+ * which is an array of 8 integers. The bucket[] array
+ * contains 8 different DMA transfer sizes (in 16
+ * byte increments) which the controller uses to fetch
+ * commands. This function fills in bucket_map[], which
+ * maps a given number of scatter gather elements to one of
+ * the 8 DMA transfer sizes. The point of it is to allow the
+ * controller to only do as much DMA as needed to fetch the
+ * command, with the DMA transfer size encoded in the lower
+ * bits of the command address.
+ */
+static void calc_bucket_map(int bucket[], int num_buckets,
+ int nsgs, int *bucket_map)
+{
+ int i, j, b, size;
+
+ /* even a command with 0 SGs requires 4 blocks */
+#define MINIMUM_TRANSFER_BLOCKS 4
+#define NUM_BUCKETS 8
+ /* Note, bucket_map must have nsgs+1 entries. */
+ for (i = 0; i <= nsgs; i++) {
+ /* Compute size of a command with i SG entries */
+ size = i + MINIMUM_TRANSFER_BLOCKS;
+ b = num_buckets; /* Assume the biggest bucket */
+ /* Find the bucket that is just big enough */
+ for (j = 0; j < 8; j++) {
+ if (bucket[j] >= size) {
+ b = j;
+ break;
+ }
+ }
+ /* for a command with i SG entries, use bucket b. */
+ bucket_map[i] = b;
+ }
+}
+
+static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
+{
+ u32 trans_support;
+ u64 trans_offset;
+ /* 5 = 1 s/g entry or 4k
+ * 6 = 2 s/g entry or 8k
+ * 8 = 4 s/g entry or 16k
+ * 10 = 6 s/g entry or 24k
+ */
+ int bft[8] = {5, 6, 8, 10, 12, 20, 28, 35}; /* for scatter/gathers */
+ int i = 0;
+ int l = 0;
+ unsigned long register_value;
+
+ trans_support = readl(&(h->cfgtable->TransportSupport));
+ if (!(trans_support & PERFORMANT_MODE))
+ return;
+
+ h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
+ h->max_sg_entries = 32;
+ /* Performant mode ring buffer and supporting data structures */
+ h->reply_pool_size = h->max_commands * sizeof(u64);
+ h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size,
+ &(h->reply_pool_dhandle));
+
+ /* Need a block fetch table for performant mode */
+ h->blockFetchTable = kmalloc(((h->max_sg_entries+1) *
+ sizeof(u32)), GFP_KERNEL);
+
+ if ((h->reply_pool == NULL)
+ || (h->blockFetchTable == NULL))
+ goto clean_up;
+
+ h->reply_pool_wraparound = 1; /* spec: init to 1 */
+
+ /* Controller spec: zero out this buffer. */
+ memset(h->reply_pool, 0, h->reply_pool_size);
+ h->reply_pool_head = h->reply_pool;
+
+ trans_offset = readl(&(h->cfgtable->TransMethodOffset));
+ bft[7] = h->max_sg_entries + 4;
+ calc_bucket_map(bft, ARRAY_SIZE(bft), 32, h->blockFetchTable);
+ for (i = 0; i < 8; i++)
+ writel(bft[i], &h->transtable->BlockFetch[i]);
+
+ /* size of controller ring buffer */
+ writel(h->max_commands, &h->transtable->RepQSize);
+ writel(1, &h->transtable->RepQCount);
+ writel(0, &h->transtable->RepQCtrAddrLow32);
+ writel(0, &h->transtable->RepQCtrAddrHigh32);
+ writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32);
+ writel(0, &h->transtable->RepQAddr0High32);
+ writel(CFGTBL_Trans_Performant,
+ &(h->cfgtable->HostWrite.TransportRequest));
+ writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+ /* under certain very rare conditions, this can take awhile.
+ * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
+ * as we enter this code.) */
+ for (l = 0; l < MAX_CONFIG_WAIT; l++) {
+ register_value = readl(h->vaddr + SA5_DOORBELL);
+ if (!(register_value & CFGTBL_ChangeReq))
+ break;
+ /* delay and try again */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(10);
+ }
+ register_value = readl(&(h->cfgtable->TransportActive));
+ if (!(register_value & CFGTBL_Trans_Performant)) {
+ dev_warn(&h->pdev->dev, "unable to get board into"
+ " performant mode\n");
+ return;
+ }
+
+ /* Change the access methods to the performant access methods */
+ h->access = SA5_performant_access;
+ h->transMethod = CFGTBL_Trans_Performant;
+
+ return;
+
+clean_up:
+ if (h->reply_pool)
+ pci_free_consistent(h->pdev, h->reply_pool_size,
+ h->reply_pool, h->reply_pool_dhandle);
+ kfree(h->blockFetchTable);
+}
+
/*
* This is it. Register the PCI driver information for the cards we control
* the OS will call our registered routines when it finds one of our cards.
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 6bd1949144b5..a0502b3ac17e 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -33,7 +33,7 @@ struct access_method {
struct CommandList *c);
void (*set_intr_mask)(struct ctlr_info *h, unsigned long val);
unsigned long (*fifo_full)(struct ctlr_info *h);
- unsigned long (*intr_pending)(struct ctlr_info *h);
+ bool (*intr_pending)(struct ctlr_info *h);
unsigned long (*command_completed)(struct ctlr_info *h);
};
@@ -55,19 +55,20 @@ struct ctlr_info {
char *product_name;
char firm_ver[4]; /* Firmware version */
struct pci_dev *pdev;
- __u32 board_id;
+ u32 board_id;
void __iomem *vaddr;
unsigned long paddr;
int nr_cmds; /* Number of commands allowed on this controller */
struct CfgTable __iomem *cfgtable;
+ int max_sg_entries;
int interrupts_enabled;
int major;
int max_commands;
int commands_outstanding;
int max_outstanding; /* Debug */
int usage_count; /* number of opens all all minor devices */
-# define DOORBELL_INT 0
-# define PERF_MODE_INT 1
+# define PERF_MODE_INT 0
+# define DOORBELL_INT 1
# define SIMPLE_MODE_INT 2
# define MEMQ_MODE_INT 3
unsigned int intr[4];
@@ -93,6 +94,9 @@ struct ctlr_info {
int nr_frees;
int busy_initializing;
int busy_scanning;
+ int scan_finished;
+ spinlock_t scan_lock;
+ wait_queue_head_t scan_wait_queue;
struct mutex busy_shutting_down;
struct list_head scan_list;
struct completion scan_wait;
@@ -102,6 +106,24 @@ struct ctlr_info {
int ndevices; /* number of used elements in .dev[] array. */
#define HPSA_MAX_SCSI_DEVS_PER_HBA 256
struct hpsa_scsi_dev_t *dev[HPSA_MAX_SCSI_DEVS_PER_HBA];
+ /*
+ * Performant mode tables.
+ */
+ u32 trans_support;
+ u32 trans_offset;
+ struct TransTable_struct *transtable;
+ unsigned long transMethod;
+
+ /*
+ * Performant mode completion buffer
+ */
+ u64 *reply_pool;
+ dma_addr_t reply_pool_dhandle;
+ u64 *reply_pool_head;
+ size_t reply_pool_size;
+ unsigned char reply_pool_wraparound;
+ u32 *blockFetchTable;
+ unsigned char *hba_inquiry_data;
};
#define HPSA_ABORT_MSG 0
#define HPSA_DEVICE_RESET_MSG 1
@@ -164,9 +186,16 @@ struct ctlr_info {
#define HPSA_FIRMWARE_READY 0xffff0000 /* value in scratchpad register */
#define HPSA_ERROR_BIT 0x02
-#define HPSA_TAG_CONTAINS_INDEX(tag) ((tag) & 0x04)
-#define HPSA_TAG_TO_INDEX(tag) ((tag) >> 3)
-#define HPSA_TAG_DISCARD_ERROR_BITS(tag) ((tag) & ~3)
+
+/* Performant mode flags */
+#define SA5_PERF_INTR_PENDING 0x04
+#define SA5_PERF_INTR_OFF 0x05
+#define SA5_OUTDB_STATUS_PERF_BIT 0x01
+#define SA5_OUTDB_CLEAR_PERF_BIT 0x01
+#define SA5_OUTDB_CLEAR 0xA0
+#define SA5_OUTDB_CLEAR_PERF_BIT 0x01
+#define SA5_OUTDB_STATUS 0x9C
+
#define HPSA_INTR_ON 1
#define HPSA_INTR_OFF 0
@@ -176,10 +205,8 @@ struct ctlr_info {
static void SA5_submit_command(struct ctlr_info *h,
struct CommandList *c)
{
-#ifdef HPSA_DEBUG
- printk(KERN_WARNING "hpsa: Sending %x - down to controller\n",
- c->busaddr);
-#endif /* HPSA_DEBUG */
+ dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr,
+ c->Header.Tag.lower);
writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
h->commands_outstanding++;
if (h->commands_outstanding > h->max_outstanding)
@@ -202,6 +229,52 @@ static void SA5_intr_mask(struct ctlr_info *h, unsigned long val)
h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
}
}
+
+static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val)
+{
+ if (val) { /* turn on interrupts */
+ h->interrupts_enabled = 1;
+ writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ } else {
+ h->interrupts_enabled = 0;
+ writel(SA5_PERF_INTR_OFF,
+ h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ }
+}
+
+static unsigned long SA5_performant_completed(struct ctlr_info *h)
+{
+ unsigned long register_value = FIFO_EMPTY;
+
+ /* flush the controller write of the reply queue by reading
+ * outbound doorbell status register.
+ */
+ register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
+ /* msi auto clears the interrupt pending bit. */
+ if (!(h->msi_vector || h->msix_vector)) {
+ writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR);
+ /* Do a read in order to flush the write to the controller
+ * (as per spec.)
+ */
+ register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
+ }
+
+ if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) {
+ register_value = *(h->reply_pool_head);
+ (h->reply_pool_head)++;
+ h->commands_outstanding--;
+ } else {
+ register_value = FIFO_EMPTY;
+ }
+ /* Check for wraparound */
+ if (h->reply_pool_head == (h->reply_pool + h->max_commands)) {
+ h->reply_pool_head = h->reply_pool;
+ h->reply_pool_wraparound ^= 1;
+ }
+
+ return register_value;
+}
+
/*
* Returns true if fifo is full.
*
@@ -228,10 +301,10 @@ static unsigned long SA5_completed(struct ctlr_info *h)
#ifdef HPSA_DEBUG
if (register_value != FIFO_EMPTY)
- printk(KERN_INFO "hpsa: Read %lx back from board\n",
+ dev_dbg(&h->pdev->dev, "Read %lx back from board\n",
register_value);
else
- printk(KERN_INFO "hpsa: FIFO Empty read\n");
+ dev_dbg(&h->pdev->dev, "hpsa: FIFO Empty read\n");
#endif
return register_value;
@@ -239,18 +312,28 @@ static unsigned long SA5_completed(struct ctlr_info *h)
/*
* Returns true if an interrupt is pending..
*/
-static unsigned long SA5_intr_pending(struct ctlr_info *h)
+static bool SA5_intr_pending(struct ctlr_info *h)
{
unsigned long register_value =
readl(h->vaddr + SA5_INTR_STATUS);
-#ifdef HPSA_DEBUG
- printk(KERN_INFO "hpsa: intr_pending %lx\n", register_value);
-#endif /* HPSA_DEBUG */
- if (register_value & SA5_INTR_PENDING)
- return 1;
- return 0 ;
+ dev_dbg(&h->pdev->dev, "intr_pending %lx\n", register_value);
+ return register_value & SA5_INTR_PENDING;
}
+static bool SA5_performant_intr_pending(struct ctlr_info *h)
+{
+ unsigned long register_value = readl(h->vaddr + SA5_INTR_STATUS);
+
+ if (!register_value)
+ return false;
+
+ if (h->msi_vector || h->msix_vector)
+ return true;
+
+ /* Read outbound doorbell to flush */
+ register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
+ return register_value & SA5_OUTDB_STATUS_PERF_BIT;
+}
static struct access_method SA5_access = {
SA5_submit_command,
@@ -260,14 +343,19 @@ static struct access_method SA5_access = {
SA5_completed,
};
+static struct access_method SA5_performant_access = {
+ SA5_submit_command,
+ SA5_performant_intr_mask,
+ SA5_fifo_full,
+ SA5_performant_intr_pending,
+ SA5_performant_completed,
+};
+
struct board_type {
- __u32 board_id;
+ u32 board_id;
char *product_name;
struct access_method *access;
};
-
-/* end of old hpsa_scsi.h file */
-
#endif /* HPSA_H */
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 12d71387ed9a..3e0abdf76689 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -101,19 +101,20 @@
#define CFGTBL_AccCmds 0x00000001l
#define CFGTBL_Trans_Simple 0x00000002l
+#define CFGTBL_Trans_Performant 0x00000004l
#define CFGTBL_BusType_Ultra2 0x00000001l
#define CFGTBL_BusType_Ultra3 0x00000002l
#define CFGTBL_BusType_Fibre1G 0x00000100l
#define CFGTBL_BusType_Fibre2G 0x00000200l
struct vals32 {
- __u32 lower;
- __u32 upper;
+ u32 lower;
+ u32 upper;
};
union u64bit {
struct vals32 val32;
- __u64 val;
+ u64 val;
};
/* FIXME this is a per controller value (barf!) */
@@ -126,34 +127,34 @@ union u64bit {
#define HPSA_INQUIRY 0x12
struct InquiryData {
- __u8 data_byte[36];
+ u8 data_byte[36];
};
#define HPSA_REPORT_LOG 0xc2 /* Report Logical LUNs */
#define HPSA_REPORT_PHYS 0xc3 /* Report Physical LUNs */
struct ReportLUNdata {
- __u8 LUNListLength[4];
- __u32 reserved;
- __u8 LUN[HPSA_MAX_LUN][8];
+ u8 LUNListLength[4];
+ u32 reserved;
+ u8 LUN[HPSA_MAX_LUN][8];
};
struct ReportExtendedLUNdata {
- __u8 LUNListLength[4];
- __u8 extended_response_flag;
- __u8 reserved[3];
- __u8 LUN[HPSA_MAX_LUN][24];
+ u8 LUNListLength[4];
+ u8 extended_response_flag;
+ u8 reserved[3];
+ u8 LUN[HPSA_MAX_LUN][24];
};
struct SenseSubsystem_info {
- __u8 reserved[36];
- __u8 portname[8];
- __u8 reserved1[1108];
+ u8 reserved[36];
+ u8 portname[8];
+ u8 reserved1[1108];
};
#define HPSA_READ_CAPACITY 0x25 /* Read Capacity */
struct ReadCapdata {
- __u8 total_size[4]; /* Total size in blocks */
- __u8 block_size[4]; /* Size of blocks in bytes */
+ u8 total_size[4]; /* Total size in blocks */
+ u8 block_size[4]; /* Size of blocks in bytes */
};
#if 0
@@ -174,112 +175,131 @@ struct ReadCapdata {
/* Command List Structure */
union SCSI3Addr {
struct {
- __u8 Dev;
- __u8 Bus:6;
- __u8 Mode:2; /* b00 */
+ u8 Dev;
+ u8 Bus:6;
+ u8 Mode:2; /* b00 */
} PeripDev;
struct {
- __u8 DevLSB;
- __u8 DevMSB:6;
- __u8 Mode:2; /* b01 */
+ u8 DevLSB;
+ u8 DevMSB:6;
+ u8 Mode:2; /* b01 */
} LogDev;
struct {
- __u8 Dev:5;
- __u8 Bus:3;
- __u8 Targ:6;
- __u8 Mode:2; /* b10 */
+ u8 Dev:5;
+ u8 Bus:3;
+ u8 Targ:6;
+ u8 Mode:2; /* b10 */
} LogUnit;
};
struct PhysDevAddr {
- __u32 TargetId:24;
- __u32 Bus:6;
- __u32 Mode:2;
+ u32 TargetId:24;
+ u32 Bus:6;
+ u32 Mode:2;
/* 2 level target device addr */
union SCSI3Addr Target[2];
};
struct LogDevAddr {
- __u32 VolId:30;
- __u32 Mode:2;
- __u8 reserved[4];
+ u32 VolId:30;
+ u32 Mode:2;
+ u8 reserved[4];
};
union LUNAddr {
- __u8 LunAddrBytes[8];
+ u8 LunAddrBytes[8];
union SCSI3Addr SCSI3Lun[4];
struct PhysDevAddr PhysDev;
struct LogDevAddr LogDev;
};
struct CommandListHeader {
- __u8 ReplyQueue;
- __u8 SGList;
- __u16 SGTotal;
+ u8 ReplyQueue;
+ u8 SGList;
+ u16 SGTotal;
struct vals32 Tag;
union LUNAddr LUN;
};
struct RequestBlock {
- __u8 CDBLen;
+ u8 CDBLen;
struct {
- __u8 Type:3;
- __u8 Attribute:3;
- __u8 Direction:2;
+ u8 Type:3;
+ u8 Attribute:3;
+ u8 Direction:2;
} Type;
- __u16 Timeout;
- __u8 CDB[16];
+ u16 Timeout;
+ u8 CDB[16];
};
struct ErrDescriptor {
struct vals32 Addr;
- __u32 Len;
+ u32 Len;
};
struct SGDescriptor {
struct vals32 Addr;
- __u32 Len;
- __u32 Ext;
+ u32 Len;
+ u32 Ext;
};
union MoreErrInfo {
struct {
- __u8 Reserved[3];
- __u8 Type;
- __u32 ErrorInfo;
+ u8 Reserved[3];
+ u8 Type;
+ u32 ErrorInfo;
} Common_Info;
struct {
- __u8 Reserved[2];
- __u8 offense_size; /* size of offending entry */
- __u8 offense_num; /* byte # of offense 0-base */
- __u32 offense_value;
+ u8 Reserved[2];
+ u8 offense_size; /* size of offending entry */
+ u8 offense_num; /* byte # of offense 0-base */
+ u32 offense_value;
} Invalid_Cmd;
};
struct ErrorInfo {
- __u8 ScsiStatus;
- __u8 SenseLen;
- __u16 CommandStatus;
- __u32 ResidualCnt;
+ u8 ScsiStatus;
+ u8 SenseLen;
+ u16 CommandStatus;
+ u32 ResidualCnt;
union MoreErrInfo MoreErrInfo;
- __u8 SenseInfo[SENSEINFOBYTES];
+ u8 SenseInfo[SENSEINFOBYTES];
};
/* Command types */
#define CMD_IOCTL_PEND 0x01
#define CMD_SCSI 0x03
+/* This structure needs to be divisible by 32 for new
+ * indexing method and performant mode.
+ */
+#define PAD32 32
+#define PAD64DIFF 0
+#define USEEXTRA ((sizeof(void *) - 4)/4)
+#define PADSIZE (PAD32 + PAD64DIFF * USEEXTRA)
+
+#define DIRECT_LOOKUP_SHIFT 5
+#define DIRECT_LOOKUP_BIT 0x10
+
+#define HPSA_ERROR_BIT 0x02
struct ctlr_info; /* defined in hpsa.h */
-/* The size of this structure needs to be divisible by 8
- * od on all architectures, because the controller uses 2
- * lower bits of the address, and the driver uses 1 lower
- * bit (3 bits total.)
+/* The size of this structure needs to be divisible by 32
+ * on all architectures because low 5 bits of the addresses
+ * are used as follows:
+ *
+ * bit 0: to device, used to indicate "performant mode" command
+ * from device, indidcates error status.
+ * bit 1-3: to device, indicates block fetch table entry for
+ * reducing DMA in fetching commands from host memory.
+ * bit 4: used to indicate whether tag is "direct lookup" (index),
+ * or a bus address.
*/
+
struct CommandList {
struct CommandListHeader Header;
struct RequestBlock Request;
struct ErrDescriptor ErrDesc;
struct SGDescriptor SG[MAXSGENTRIES];
/* information associated with the command */
- __u32 busaddr; /* physical addr of this record */
+ u32 busaddr; /* physical addr of this record */
struct ErrorInfo *err_info; /* pointer to the allocated mem */
struct ctlr_info *h;
int cmd_type;
@@ -291,35 +311,63 @@ struct CommandList {
struct completion *waiting;
int retry_count;
void *scsi_cmd;
+
+/* on 64 bit architectures, to get this to be 32-byte-aligned
+ * it so happens we need no padding, on 32 bit systems,
+ * we need 8 bytes of padding. This does that.
+ */
+#define COMMANDLIST_PAD ((8 - sizeof(long))/4 * 8)
+ u8 pad[COMMANDLIST_PAD];
+
};
/* Configuration Table Structure */
struct HostWrite {
- __u32 TransportRequest;
- __u32 Reserved;
- __u32 CoalIntDelay;
- __u32 CoalIntCount;
+ u32 TransportRequest;
+ u32 Reserved;
+ u32 CoalIntDelay;
+ u32 CoalIntCount;
};
+#define SIMPLE_MODE 0x02
+#define PERFORMANT_MODE 0x04
+#define MEMQ_MODE 0x08
+
struct CfgTable {
- __u8 Signature[4];
- __u32 SpecValence;
- __u32 TransportSupport;
- __u32 TransportActive;
- struct HostWrite HostWrite;
- __u32 CmdsOutMax;
- __u32 BusTypes;
- __u32 Reserved;
- __u8 ServerName[16];
- __u32 HeartBeat;
- __u32 SCSI_Prefetch;
+ u8 Signature[4];
+ u32 SpecValence;
+ u32 TransportSupport;
+ u32 TransportActive;
+ struct HostWrite HostWrite;
+ u32 CmdsOutMax;
+ u32 BusTypes;
+ u32 TransMethodOffset;
+ u8 ServerName[16];
+ u32 HeartBeat;
+ u32 SCSI_Prefetch;
+ u32 MaxScatterGatherElements;
+ u32 MaxLogicalUnits;
+ u32 MaxPhysicalDevices;
+ u32 MaxPhysicalDrivesPerLogicalUnit;
+ u32 MaxPerformantModeCommands;
+};
+
+#define NUM_BLOCKFETCH_ENTRIES 8
+struct TransTable_struct {
+ u32 BlockFetch[NUM_BLOCKFETCH_ENTRIES];
+ u32 RepQSize;
+ u32 RepQCount;
+ u32 RepQCtrAddrLow32;
+ u32 RepQCtrAddrHigh32;
+ u32 RepQAddr0Low32;
+ u32 RepQAddr0High32;
};
struct hpsa_pci_info {
unsigned char bus;
unsigned char dev_fn;
unsigned short domain;
- __u32 board_id;
+ u32 board_id;
};
#pragma pack()
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 9c1e6a5b5af0..9a4b69d4f4eb 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -2336,7 +2336,7 @@ static int option_setup(char *str)
char *cur = str;
int i = 1;
- while (cur && isdigit(*cur) && i <= IM_MAX_HOSTS) {
+ while (cur && isdigit(*cur) && i < IM_MAX_HOSTS) {
ints[i++] = simple_strtoul(cur, NULL, 0);
if ((cur = strchr(cur, ',')) != NULL)
cur++;
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 87b536a97cb4..732f6d35b4a8 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -4195,7 +4195,7 @@ static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
if (tgt->service_parms.class3_parms[0] & 0x80000000)
rport->supported_classes |= FC_COS_CLASS3;
if (rport->rqst_q)
- blk_queue_max_hw_segments(rport->rqst_q, 1);
+ blk_queue_max_segments(rport->rqst_q, 1);
} else
tgt_dbg(tgt, "rport add failed\n");
spin_unlock_irqrestore(vhost->host->host_lock, flags);
@@ -4669,7 +4669,7 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
}
if (shost_to_fc_host(shost)->rqst_q)
- blk_queue_max_hw_segments(shost_to_fc_host(shost)->rqst_q, 1);
+ blk_queue_max_segments(shost_to_fc_host(shost)->rqst_q, 1);
dev_set_drvdata(dev, vhost);
spin_lock(&ibmvfc_driver_lock);
list_add_tail(&vhost->queue, &ibmvfc_head);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index e475b7957c2d..e3a18e0ef276 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -40,7 +40,7 @@
* (CRQ), which is just a buffer of 16 byte entries in the receiver's
* Senders cannot access the buffer directly, but send messages by
* making a hypervisor call and passing in the 16 bytes. The hypervisor
- * puts the message in the next 16 byte space in round-robbin fashion,
+ * puts the message in the next 16 byte space in round-robin fashion,
* turns on the high order bit of the message (the valid bit), and
* generates an interrupt to the receiver (if interrupts are turned on.)
* The receiver just turns off the valid bit when they have copied out
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 89a59484be02..a7714160fbc3 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -531,7 +531,7 @@ static void initio_read_eeprom(unsigned long base)
* initio_stop_bm - stop bus master
* @host: InitIO we are stopping
*
- * Stop any pending DMA operation, aborting the DMA if neccessary
+ * Stop any pending DMA operation, aborting the DMA if necessary
*/
static void initio_stop_bm(struct initio_host * host)
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 9e52d16c7c39..032f0d0e6cb4 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3674,7 +3674,7 @@ static int ipr_slave_configure(struct scsi_device *sdev)
if (ipr_is_vset_device(res)) {
blk_queue_rq_timeout(sdev->request_queue,
IPR_VSET_RW_TIMEOUT);
- blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
+ blk_queue_max_hw_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
}
if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
sdev->allow_restart = 1;
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 517da3fd89d3..8a89ba900588 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -584,9 +584,10 @@ static void iscsi_sw_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
+ struct socket *sock = tcp_sw_conn->sock;
/* userspace may have goofed up and not bound us */
- if (!tcp_sw_conn->sock)
+ if (!sock)
return;
/*
* Make sure our recv side is stopped.
@@ -597,6 +598,11 @@ static void iscsi_sw_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
write_unlock_bh(&tcp_sw_conn->sock->sk->sk_callback_lock);
+ if (sock->sk->sk_sleep && waitqueue_active(sock->sk->sk_sleep)) {
+ sock->sk->sk_err = EIO;
+ wake_up_interruptible(sock->sk->sk_sleep);
+ }
+
iscsi_conn_stop(cls_conn, flag);
iscsi_sw_tcp_release_conn(conn);
}
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 19d711cb938c..7f4364770e4a 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -1890,7 +1890,7 @@ static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport,
fc_exch_setup_hdr(ep, fp, ep->f_ctl);
sp->cnt++;
- if (ep->xid <= lport->lro_xid)
+ if (ep->xid <= lport->lro_xid && fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD)
fc_fcp_ddp_setup(fr_fsp(fp), ep->xid);
if (unlikely(lport->tt.frame_send(lport, fp)))
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index 881d5dfe8c74..774e7ac837a5 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -48,7 +48,7 @@ struct kmem_cache *scsi_pkt_cachep;
#define FC_SRB_CMD_SENT (1 << 0) /* cmd has been sent */
#define FC_SRB_RCV_STATUS (1 << 1) /* response has arrived */
#define FC_SRB_ABORT_PENDING (1 << 2) /* cmd abort sent to device */
-#define FC_SRB_ABORTED (1 << 3) /* abort acknowleged */
+#define FC_SRB_ABORTED (1 << 3) /* abort acknowledged */
#define FC_SRB_DISCONTIG (1 << 4) /* non-sequential data recvd */
#define FC_SRB_COMPL (1 << 5) /* fc_io_compl has been run */
#define FC_SRB_FCP_PROCESSING_TMO (1 << 6) /* timer function processing */
@@ -298,9 +298,6 @@ void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid)
{
struct fc_lport *lport;
- if (!fsp)
- return;
-
lport = fsp->lp;
if ((fsp->req_flags & FC_SRB_READ) &&
(lport->lro_enabled) && (lport->tt.ddp_setup)) {
@@ -522,7 +519,7 @@ crc_err:
*
* Called after receiving a Transfer Ready data descriptor.
* If the LLD is capable of sequence offload then send down the
- * seq_blen ammount of data in single frame, otherwise send
+ * seq_blen amount of data in single frame, otherwise send
* multiple frames of the maximum frame payload supported by
* the target port.
*/
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index 0b165024a219..7ec8ce75007c 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -1800,7 +1800,8 @@ int fc_lport_bsg_request(struct fc_bsg_job *job)
u32 did;
job->reply->reply_payload_rcv_len = 0;
- rsp->resid_len = job->reply_payload.payload_len;
+ if (rsp)
+ rsp->resid_len = job->reply_payload.payload_len;
mutex_lock(&lport->lp_mutex);
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 02300523b234..97923bb07765 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -623,7 +623,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
tov = ntohl(plp->fl_csp.sp_e_d_tov);
if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR)
- tov /= 1000;
+ tov /= 1000000;
if (tov > rdata->e_d_tov)
rdata->e_d_tov = tov;
csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index c28a712fd4db..703eb6a88790 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1919,10 +1919,11 @@ static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
{
enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
- struct iscsi_task *task = NULL;
+ struct iscsi_task *task = NULL, *running_task;
struct iscsi_cls_session *cls_session;
struct iscsi_session *session;
struct iscsi_conn *conn;
+ int i;
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
@@ -1947,8 +1948,15 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
}
task = (struct iscsi_task *)sc->SCp.ptr;
- if (!task)
+ if (!task) {
+ /*
+ * Raced with completion. Just reset timer, and let it
+ * complete normally
+ */
+ rc = BLK_EH_RESET_TIMER;
goto done;
+ }
+
/*
* If we have sent (at least queued to the network layer) a pdu or
* recvd one for the task since the last timeout ask for
@@ -1956,10 +1964,10 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
* we can check if it is the task or connection when we send the
* nop as a ping.
*/
- if (time_after_eq(task->last_xfer, task->last_timeout)) {
+ if (time_after(task->last_xfer, task->last_timeout)) {
ISCSI_DBG_EH(session, "Command making progress. Asking "
"scsi-ml for more time to complete. "
- "Last data recv at %lu. Last timeout was at "
+ "Last data xfer at %lu. Last timeout was at "
"%lu\n.", task->last_xfer, task->last_timeout);
task->have_checked_conn = false;
rc = BLK_EH_RESET_TIMER;
@@ -1977,6 +1985,43 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
goto done;
}
+ for (i = 0; i < conn->session->cmds_max; i++) {
+ running_task = conn->session->cmds[i];
+ if (!running_task->sc || running_task == task ||
+ running_task->state != ISCSI_TASK_RUNNING)
+ continue;
+
+ /*
+ * Only check if cmds started before this one have made
+ * progress, or this could never fail
+ */
+ if (time_after(running_task->sc->jiffies_at_alloc,
+ task->sc->jiffies_at_alloc))
+ continue;
+
+ if (time_after(running_task->last_xfer, task->last_timeout)) {
+ /*
+ * This task has not made progress, but a task
+ * started before us has transferred data since
+ * we started/last-checked. We could be queueing
+ * too many tasks or the LU is bad.
+ *
+ * If the device is bad the cmds ahead of us on
+ * other devs will complete, and this loop will
+ * eventually fail starting the scsi eh.
+ */
+ ISCSI_DBG_EH(session, "Command has not made progress "
+ "but commands ahead of it have. "
+ "Asking scsi-ml for more time to "
+ "complete. Our last xfer vs running task "
+ "last xfer %lu/%lu. Last check %lu.\n",
+ task->last_xfer, running_task->last_xfer,
+ task->last_timeout);
+ rc = BLK_EH_RESET_TIMER;
+ goto done;
+ }
+ }
+
/* Assumes nop timeout is shorter than scsi cmd timeout */
if (task->have_checked_conn)
goto done;
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index db6856c138fc..4ad87fd74ddd 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -992,12 +992,10 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
if (r2t == NULL) {
if (kfifo_out(&tcp_task->r2tqueue,
(void *)&tcp_task->r2t, sizeof(void *)) !=
- sizeof(void *)) {
- WARN_ONCE(1, "unexpected fifo state");
+ sizeof(void *))
r2t = NULL;
- }
-
- r2t = tcp_task->r2t;
+ else
+ r2t = tcp_task->r2t;
}
spin_unlock_bh(&session->lock);
}
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
index ab19b3b4be52..22775165bf6a 100644
--- a/drivers/scsi/libsrp.c
+++ b/drivers/scsi/libsrp.c
@@ -1,5 +1,5 @@
/*
- * SCSI RDAM Protocol lib functions
+ * SCSI RDMA Protocol lib functions
*
* Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org>
*
@@ -328,7 +328,7 @@ int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
int offset, err = 0;
u8 format;
- offset = cmd->add_cdb_len * 4;
+ offset = cmd->add_cdb_len & ~3;
dir = srp_cmd_direction(cmd);
if (dir == DMA_FROM_DEVICE)
@@ -366,7 +366,7 @@ static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
{
struct srp_direct_buf *md;
struct srp_indirect_buf *id;
- int len = 0, offset = cmd->add_cdb_len * 4;
+ int len = 0, offset = cmd->add_cdb_len & ~3;
u8 fmt;
if (dir == DMA_TO_DEVICE)
@@ -440,6 +440,6 @@ int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info,
}
EXPORT_SYMBOL_GPL(srp_cmd_queue);
-MODULE_DESCRIPTION("SCSI RDAM Protocol lib functions");
+MODULE_DESCRIPTION("SCSI RDMA Protocol lib functions");
MODULE_AUTHOR("FUJITA Tomonori");
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 1cc23a69db5e..84b696463a58 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2009 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2010 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -315,6 +315,9 @@ struct lpfc_vport {
#define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */
#define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */
#define FC_VPORT_NEEDS_INIT_VPI 0x200000 /* Need to INIT_VPI before FDISC */
+#define FC_VPORT_CVL_RCVD 0x400000 /* VLink failed due to CVL */
+#define FC_VFI_REGISTERED 0x800000 /* VFI is registered */
+#define FC_FDISC_COMPLETED 0x1000000/* FDISC completed */
uint32_t ct_flags;
#define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */
@@ -448,6 +451,8 @@ struct unsol_rcv_ct_ctx {
uint32_t ctxt_id;
uint32_t SID;
uint32_t oxid;
+ uint32_t flags;
+#define UNSOL_VALID 0x00000001
};
struct lpfc_hba {
@@ -499,6 +504,10 @@ struct lpfc_hba {
(struct lpfc_hba *);
void (*lpfc_stop_port)
(struct lpfc_hba *);
+ int (*lpfc_hba_init_link)
+ (struct lpfc_hba *);
+ int (*lpfc_hba_down_link)
+ (struct lpfc_hba *);
/* SLI4 specific HBA data structure */
@@ -613,6 +622,7 @@ struct lpfc_hba {
uint32_t cfg_enable_bg;
uint32_t cfg_log_verbose;
uint32_t cfg_aer_support;
+ uint32_t cfg_suppress_link_up;
lpfc_vpd_t vpd; /* vital product data */
@@ -790,7 +800,7 @@ struct lpfc_hba {
uint16_t vlan_id;
struct list_head fcf_conn_rec_list;
- struct mutex ct_event_mutex; /* synchronize access to ct_ev_waiters */
+ spinlock_t ct_ev_lock; /* synchronize access to ct_ev_waiters */
struct list_head ct_ev_waiters;
struct unsol_rcv_ct_ctx ct_ctx[64];
uint32_t ctx_idx;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 91542f786edf..c992e8328f9e 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -482,6 +482,41 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr,
}
/**
+ * lpfc_link_state_store - Transition the link_state on an HBA port
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: one or more lpfc_polling_flags values.
+ * @count: not used.
+ *
+ * Returns:
+ * -EINVAL if the buffer is not "up" or "down"
+ * return from link state change function if non-zero
+ * length of the buf on success
+ **/
+static ssize_t
+lpfc_link_state_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
+ int status = -EINVAL;
+
+ if ((strncmp(buf, "up", sizeof("up") - 1) == 0) &&
+ (phba->link_state == LPFC_LINK_DOWN))
+ status = phba->lpfc_hba_init_link(phba);
+ else if ((strncmp(buf, "down", sizeof("down") - 1) == 0) &&
+ (phba->link_state >= LPFC_LINK_UP))
+ status = phba->lpfc_hba_down_link(phba);
+
+ if (status == 0)
+ return strlen(buf);
+ else
+ return status;
+}
+
+/**
* lpfc_num_discovered_ports_show - Return sum of mapped and unmapped vports
* @dev: class device that is converted into a Scsi_host.
* @attr: device attribute, not used.
@@ -1219,7 +1254,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \
struct Scsi_Host *shost = class_to_shost(dev);\
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
struct lpfc_hba *phba = vport->phba;\
- int val = 0;\
+ uint val = 0;\
val = phba->cfg_##attr;\
return snprintf(buf, PAGE_SIZE, "%d\n",\
phba->cfg_##attr);\
@@ -1247,7 +1282,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \
struct Scsi_Host *shost = class_to_shost(dev);\
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
struct lpfc_hba *phba = vport->phba;\
- int val = 0;\
+ uint val = 0;\
val = phba->cfg_##attr;\
return snprintf(buf, PAGE_SIZE, "%#x\n",\
phba->cfg_##attr);\
@@ -1274,7 +1309,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \
**/
#define lpfc_param_init(attr, default, minval, maxval) \
static int \
-lpfc_##attr##_init(struct lpfc_hba *phba, int val) \
+lpfc_##attr##_init(struct lpfc_hba *phba, uint val) \
{ \
if (val >= minval && val <= maxval) {\
phba->cfg_##attr = val;\
@@ -1309,7 +1344,7 @@ lpfc_##attr##_init(struct lpfc_hba *phba, int val) \
**/
#define lpfc_param_set(attr, default, minval, maxval) \
static int \
-lpfc_##attr##_set(struct lpfc_hba *phba, int val) \
+lpfc_##attr##_set(struct lpfc_hba *phba, uint val) \
{ \
if (val >= minval && val <= maxval) {\
phba->cfg_##attr = val;\
@@ -1350,7 +1385,7 @@ lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \
struct Scsi_Host *shost = class_to_shost(dev);\
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
struct lpfc_hba *phba = vport->phba;\
- int val=0;\
+ uint val = 0;\
if (!isdigit(buf[0]))\
return -EINVAL;\
if (sscanf(buf, "%i", &val) != 1)\
@@ -1382,7 +1417,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \
{ \
struct Scsi_Host *shost = class_to_shost(dev);\
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
- int val = 0;\
+ uint val = 0;\
val = vport->cfg_##attr;\
return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\
}
@@ -1409,7 +1444,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \
{ \
struct Scsi_Host *shost = class_to_shost(dev);\
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
- int val = 0;\
+ uint val = 0;\
val = vport->cfg_##attr;\
return snprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\
}
@@ -1434,7 +1469,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \
**/
#define lpfc_vport_param_init(attr, default, minval, maxval) \
static int \
-lpfc_##attr##_init(struct lpfc_vport *vport, int val) \
+lpfc_##attr##_init(struct lpfc_vport *vport, uint val) \
{ \
if (val >= minval && val <= maxval) {\
vport->cfg_##attr = val;\
@@ -1466,7 +1501,7 @@ lpfc_##attr##_init(struct lpfc_vport *vport, int val) \
**/
#define lpfc_vport_param_set(attr, default, minval, maxval) \
static int \
-lpfc_##attr##_set(struct lpfc_vport *vport, int val) \
+lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \
{ \
if (val >= minval && val <= maxval) {\
vport->cfg_##attr = val;\
@@ -1502,7 +1537,7 @@ lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \
{ \
struct Scsi_Host *shost = class_to_shost(dev);\
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
- int val=0;\
+ uint val = 0;\
if (!isdigit(buf[0]))\
return -EINVAL;\
if (sscanf(buf, "%i", &val) != 1)\
@@ -1515,22 +1550,22 @@ lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \
#define LPFC_ATTR(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_param_init(name, defval, minval, maxval)
#define LPFC_ATTR_R(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_param_show(name)\
lpfc_param_init(name, defval, minval, maxval)\
static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
#define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_param_show(name)\
lpfc_param_init(name, defval, minval, maxval)\
@@ -1540,16 +1575,16 @@ static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
lpfc_##name##_show, lpfc_##name##_store)
#define LPFC_ATTR_HEX_R(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_param_hex_show(name)\
lpfc_param_init(name, defval, minval, maxval)\
static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
#define LPFC_ATTR_HEX_RW(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_param_hex_show(name)\
lpfc_param_init(name, defval, minval, maxval)\
@@ -1559,22 +1594,22 @@ static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
lpfc_##name##_show, lpfc_##name##_store)
#define LPFC_VPORT_ATTR(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_vport_param_init(name, defval, minval, maxval)
#define LPFC_VPORT_ATTR_R(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_vport_param_show(name)\
lpfc_vport_param_init(name, defval, minval, maxval)\
static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
#define LPFC_VPORT_ATTR_RW(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_vport_param_show(name)\
lpfc_vport_param_init(name, defval, minval, maxval)\
@@ -1584,16 +1619,16 @@ static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
lpfc_##name##_show, lpfc_##name##_store)
#define LPFC_VPORT_ATTR_HEX_R(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_vport_param_hex_show(name)\
lpfc_vport_param_init(name, defval, minval, maxval)\
static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
#define LPFC_VPORT_ATTR_HEX_RW(name, defval, minval, maxval, desc) \
-static int lpfc_##name = defval;\
-module_param(lpfc_##name, int, 0);\
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, 0);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_vport_param_hex_show(name)\
lpfc_vport_param_init(name, defval, minval, maxval)\
@@ -1614,7 +1649,8 @@ static DEVICE_ATTR(programtype, S_IRUGO, lpfc_programtype_show, NULL);
static DEVICE_ATTR(portnum, S_IRUGO, lpfc_vportnum_show, NULL);
static DEVICE_ATTR(fwrev, S_IRUGO, lpfc_fwrev_show, NULL);
static DEVICE_ATTR(hdw, S_IRUGO, lpfc_hdw_show, NULL);
-static DEVICE_ATTR(link_state, S_IRUGO, lpfc_link_state_show, NULL);
+static DEVICE_ATTR(link_state, S_IRUGO | S_IWUSR, lpfc_link_state_show,
+ lpfc_link_state_store);
static DEVICE_ATTR(option_rom_version, S_IRUGO,
lpfc_option_rom_version_show, NULL);
static DEVICE_ATTR(num_discovered_ports, S_IRUGO,
@@ -1897,6 +1933,15 @@ static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO,
lpfc_enable_npiv_show, NULL);
/*
+# lpfc_suppress_link_up: Bring link up at initialization
+# 0x0 = bring link up (issue MBX_INIT_LINK)
+# 0x1 = do NOT bring link up at initialization(MBX_INIT_LINK)
+# 0x2 = never bring up link
+# Default value is 0.
+*/
+LPFC_ATTR_R(suppress_link_up, 0, 0, 2, "Suppress Link Up at initialization");
+
+/*
# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
# until the timer expires. Value range is [0,255]. Default value is 30.
*/
@@ -3114,12 +3159,12 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
/*
# lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that
# support this feature
-# 0 = MSI disabled (default)
+# 0 = MSI disabled
# 1 = MSI enabled
-# 2 = MSI-X enabled
-# Value range is [0,2]. Default value is 0.
+# 2 = MSI-X enabled (default)
+# Value range is [0,2]. Default value is 2.
*/
-LPFC_ATTR_R(use_msi, 0, 0, 2, "Use Message Signaled Interrupts (1) or "
+LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or "
"MSI-X (2), if possible");
/*
@@ -3278,6 +3323,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_prot_sg_seg_cnt,
&dev_attr_lpfc_aer_support,
&dev_attr_lpfc_aer_state_cleanup,
+ &dev_attr_lpfc_suppress_link_up,
NULL,
};
@@ -4456,7 +4502,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
lpfc_aer_support_init(phba, lpfc_aer_support);
-
+ lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index a5d9048235d9..f3f1bf1a0a71 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2009 Emulex. All rights reserved. *
+ * Copyright (C) 2009-2010 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -21,6 +21,7 @@
#include <linux/interrupt.h>
#include <linux/mempool.h>
#include <linux/pci.h>
+#include <linux/delay.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
@@ -33,6 +34,7 @@
#include "lpfc_sli.h"
#include "lpfc_sli4.h"
#include "lpfc_nl.h"
+#include "lpfc_bsg.h"
#include "lpfc_disc.h"
#include "lpfc_scsi.h"
#include "lpfc.h"
@@ -41,14 +43,183 @@
#include "lpfc_vport.h"
#include "lpfc_version.h"
+struct lpfc_bsg_event {
+ struct list_head node;
+ struct kref kref;
+ wait_queue_head_t wq;
+
+ /* Event type and waiter identifiers */
+ uint32_t type_mask;
+ uint32_t req_id;
+ uint32_t reg_id;
+
+ /* next two flags are here for the auto-delete logic */
+ unsigned long wait_time_stamp;
+ int waiting;
+
+ /* seen and not seen events */
+ struct list_head events_to_get;
+ struct list_head events_to_see;
+
+ /* job waiting for this event to finish */
+ struct fc_bsg_job *set_job;
+};
+
+struct lpfc_bsg_iocb {
+ struct lpfc_iocbq *cmdiocbq;
+ struct lpfc_iocbq *rspiocbq;
+ struct lpfc_dmabuf *bmp;
+ struct lpfc_nodelist *ndlp;
+
+ /* job waiting for this iocb to finish */
+ struct fc_bsg_job *set_job;
+};
+
+struct lpfc_bsg_mbox {
+ LPFC_MBOXQ_t *pmboxq;
+ MAILBOX_t *mb;
+
+ /* job waiting for this mbox command to finish */
+ struct fc_bsg_job *set_job;
+};
+
+#define TYPE_EVT 1
+#define TYPE_IOCB 2
+#define TYPE_MBOX 3
+struct bsg_job_data {
+ uint32_t type;
+ union {
+ struct lpfc_bsg_event *evt;
+ struct lpfc_bsg_iocb iocb;
+ struct lpfc_bsg_mbox mbox;
+ } context_un;
+};
+
+struct event_data {
+ struct list_head node;
+ uint32_t type;
+ uint32_t immed_dat;
+ void *data;
+ uint32_t len;
+};
+
+#define BUF_SZ_4K 4096
+#define SLI_CT_ELX_LOOPBACK 0x10
+
+enum ELX_LOOPBACK_CMD {
+ ELX_LOOPBACK_XRI_SETUP,
+ ELX_LOOPBACK_DATA,
+};
+
+#define ELX_LOOPBACK_HEADER_SZ \
+ (size_t)(&((struct lpfc_sli_ct_request *)NULL)->un)
+
+struct lpfc_dmabufext {
+ struct lpfc_dmabuf dma;
+ uint32_t size;
+ uint32_t flag;
+};
+
+/**
+ * lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler
+ * @phba: Pointer to HBA context object.
+ * @cmdiocbq: Pointer to command iocb.
+ * @rspiocbq: Pointer to response iocb.
+ *
+ * This function is the completion handler for iocbs issued using
+ * lpfc_bsg_send_mgmt_cmd function. This function is called by the
+ * ring event handler function without any lock held. This function
+ * can be called from both worker thread context and interrupt
+ * context. This function also can be called from another thread which
+ * cleans up the SLI layer objects.
+ * This function copies the contents of the response iocb to the
+ * response iocb memory object provided by the caller of
+ * lpfc_sli_issue_iocb_wait and then wakes up the thread which
+ * sleeps for the iocb completion.
+ **/
+static void
+lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba,
+ struct lpfc_iocbq *cmdiocbq,
+ struct lpfc_iocbq *rspiocbq)
+{
+ unsigned long iflags;
+ struct bsg_job_data *dd_data;
+ struct fc_bsg_job *job;
+ IOCB_t *rsp;
+ struct lpfc_dmabuf *bmp;
+ struct lpfc_nodelist *ndlp;
+ struct lpfc_bsg_iocb *iocb;
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ dd_data = cmdiocbq->context1;
+ if (!dd_data) {
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ return;
+ }
+
+ iocb = &dd_data->context_un.iocb;
+ job = iocb->set_job;
+ job->dd_data = NULL; /* so timeout handler does not reply */
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
+ if (cmdiocbq->context2 && rspiocbq)
+ memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
+ &rspiocbq->iocb, sizeof(IOCB_t));
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+ bmp = iocb->bmp;
+ rspiocbq = iocb->rspiocbq;
+ rsp = &rspiocbq->iocb;
+ ndlp = iocb->ndlp;
+
+ pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+
+ if (rsp->ulpStatus) {
+ if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+ switch (rsp->un.ulpWord[4] & 0xff) {
+ case IOERR_SEQUENCE_TIMEOUT:
+ rc = -ETIMEDOUT;
+ break;
+ case IOERR_INVALID_RPI:
+ rc = -EFAULT;
+ break;
+ default:
+ rc = -EACCES;
+ break;
+ }
+ } else
+ rc = -EACCES;
+ } else
+ job->reply->reply_payload_rcv_len =
+ rsp->un.genreq64.bdl.bdeSize;
+
+ lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+ lpfc_sli_release_iocbq(phba, rspiocbq);
+ lpfc_sli_release_iocbq(phba, cmdiocbq);
+ lpfc_nlp_put(ndlp);
+ kfree(bmp);
+ kfree(dd_data);
+ /* make error code available to userspace */
+ job->reply->result = rc;
+ /* complete the job back to userspace */
+ job->job_done(job);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ return;
+}
+
/**
- * lpfc_bsg_rport_ct - send a CT command from a bsg request
+ * lpfc_bsg_send_mgmt_cmd - send a CT command from a bsg request
* @job: fc_bsg_job to handle
- */
+ **/
static int
-lpfc_bsg_rport_ct(struct fc_bsg_job *job)
+lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
{
- struct Scsi_Host *shost = job->shost;
struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct lpfc_rport_data *rdata = job->rport->dd_data;
@@ -65,57 +236,60 @@ lpfc_bsg_rport_ct(struct fc_bsg_job *job)
struct scatterlist *sgel = NULL;
int numbde;
dma_addr_t busaddr;
+ struct bsg_job_data *dd_data;
+ uint32_t creg_val;
int rc = 0;
/* in case no data is transferred */
job->reply->reply_payload_rcv_len = 0;
+ /* allocate our bsg tracking structure */
+ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
+ if (!dd_data) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2733 Failed allocation of dd_data\n");
+ rc = -ENOMEM;
+ goto no_dd_data;
+ }
+
if (!lpfc_nlp_get(ndlp)) {
- job->reply->result = -ENODEV;
- return 0;
+ rc = -ENODEV;
+ goto no_ndlp;
+ }
+
+ bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (!bmp) {
+ rc = -ENOMEM;
+ goto free_ndlp;
}
if (ndlp->nlp_flag & NLP_ELS_SND_MASK) {
rc = -ENODEV;
- goto free_ndlp_exit;
+ goto free_bmp;
}
- spin_lock_irq(shost->host_lock);
cmdiocbq = lpfc_sli_get_iocbq(phba);
if (!cmdiocbq) {
rc = -ENOMEM;
- spin_unlock_irq(shost->host_lock);
- goto free_ndlp_exit;
+ goto free_bmp;
}
- cmd = &cmdiocbq->iocb;
+ cmd = &cmdiocbq->iocb;
rspiocbq = lpfc_sli_get_iocbq(phba);
if (!rspiocbq) {
rc = -ENOMEM;
goto free_cmdiocbq;
}
- spin_unlock_irq(shost->host_lock);
rsp = &rspiocbq->iocb;
-
- bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
- if (!bmp) {
- rc = -ENOMEM;
- spin_lock_irq(shost->host_lock);
- goto free_rspiocbq;
- }
-
- spin_lock_irq(shost->host_lock);
bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
if (!bmp->virt) {
rc = -ENOMEM;
- goto free_bmp;
+ goto free_rspiocbq;
}
- spin_unlock_irq(shost->host_lock);
INIT_LIST_HEAD(&bmp->list);
bpl = (struct ulp_bde64 *) bmp->virt;
-
request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
job->request_payload.sg_cnt, DMA_TO_DEVICE);
for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
@@ -157,78 +331,152 @@ lpfc_bsg_rport_ct(struct fc_bsg_job *job)
cmd->ulpContext = ndlp->nlp_rpi;
cmd->ulpOwner = OWN_CHIP;
cmdiocbq->vport = phba->pport;
- cmdiocbq->context1 = NULL;
- cmdiocbq->context2 = NULL;
+ cmdiocbq->context3 = bmp;
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
-
timeout = phba->fc_ratov * 2;
- job->dd_data = cmdiocbq;
-
- rc = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq,
- timeout + LPFC_DRVR_TIMEOUT);
-
- if (rc != IOCB_TIMEDOUT) {
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ cmd->ulpTimeout = timeout;
+
+ cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp;
+ cmdiocbq->context1 = dd_data;
+ cmdiocbq->context2 = rspiocbq;
+ dd_data->type = TYPE_IOCB;
+ dd_data->context_un.iocb.cmdiocbq = cmdiocbq;
+ dd_data->context_un.iocb.rspiocbq = rspiocbq;
+ dd_data->context_un.iocb.set_job = job;
+ dd_data->context_un.iocb.bmp = bmp;
+ dd_data->context_un.iocb.ndlp = ndlp;
+
+ if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
+ creg_val = readl(phba->HCregaddr);
+ creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING);
+ writel(creg_val, phba->HCregaddr);
+ readl(phba->HCregaddr); /* flush */
}
- if (rc == IOCB_TIMEDOUT) {
- lpfc_sli_release_iocbq(phba, rspiocbq);
- rc = -EACCES;
- goto free_ndlp_exit;
- }
+ rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0);
- if (rc != IOCB_SUCCESS) {
- rc = -EACCES;
- goto free_outdmp;
- }
+ if (rc == IOCB_SUCCESS)
+ return 0; /* done for now */
- if (rsp->ulpStatus) {
- if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
- switch (rsp->un.ulpWord[4] & 0xff) {
- case IOERR_SEQUENCE_TIMEOUT:
- rc = -ETIMEDOUT;
- break;
- case IOERR_INVALID_RPI:
- rc = -EFAULT;
- break;
- default:
- rc = -EACCES;
- break;
- }
- goto free_outdmp;
- }
- } else
- job->reply->reply_payload_rcv_len =
- rsp->un.genreq64.bdl.bdeSize;
+ /* iocb failed so cleanup */
+ pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
-free_outdmp:
- spin_lock_irq(shost->host_lock);
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-free_bmp:
- kfree(bmp);
+
free_rspiocbq:
lpfc_sli_release_iocbq(phba, rspiocbq);
free_cmdiocbq:
lpfc_sli_release_iocbq(phba, cmdiocbq);
- spin_unlock_irq(shost->host_lock);
-free_ndlp_exit:
+free_bmp:
+ kfree(bmp);
+free_ndlp:
lpfc_nlp_put(ndlp);
+no_ndlp:
+ kfree(dd_data);
+no_dd_data:
+ /* make error code available to userspace */
+ job->reply->result = rc;
+ job->dd_data = NULL;
+ return rc;
+}
+
+/**
+ * lpfc_bsg_rport_els_cmp - lpfc_bsg_rport_els's completion handler
+ * @phba: Pointer to HBA context object.
+ * @cmdiocbq: Pointer to command iocb.
+ * @rspiocbq: Pointer to response iocb.
+ *
+ * This function is the completion handler for iocbs issued using
+ * lpfc_bsg_rport_els_cmp function. This function is called by the
+ * ring event handler function without any lock held. This function
+ * can be called from both worker thread context and interrupt
+ * context. This function also can be called from other thread which
+ * cleans up the SLI layer objects.
+ * This function copies the contents of the response iocb to the
+ * response iocb memory object provided by the caller of
+ * lpfc_sli_issue_iocb_wait and then wakes up the thread which
+ * sleeps for the iocb completion.
+ **/
+static void
+lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba,
+ struct lpfc_iocbq *cmdiocbq,
+ struct lpfc_iocbq *rspiocbq)
+{
+ struct bsg_job_data *dd_data;
+ struct fc_bsg_job *job;
+ IOCB_t *rsp;
+ struct lpfc_nodelist *ndlp;
+ struct lpfc_dmabuf *pbuflist = NULL;
+ struct fc_bsg_ctels_reply *els_reply;
+ uint8_t *rjt_data;
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ dd_data = cmdiocbq->context1;
+ /* normal completion and timeout crossed paths, already done */
+ if (!dd_data) {
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+ return;
+ }
+
+ cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
+ if (cmdiocbq->context2 && rspiocbq)
+ memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
+ &rspiocbq->iocb, sizeof(IOCB_t));
+
+ job = dd_data->context_un.iocb.set_job;
+ cmdiocbq = dd_data->context_un.iocb.cmdiocbq;
+ rspiocbq = dd_data->context_un.iocb.rspiocbq;
+ rsp = &rspiocbq->iocb;
+ ndlp = dd_data->context_un.iocb.ndlp;
+
+ pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ if (job->reply->result == -EAGAIN)
+ rc = -EAGAIN;
+ else if (rsp->ulpStatus == IOSTAT_SUCCESS)
+ job->reply->reply_payload_rcv_len =
+ rsp->un.elsreq64.bdl.bdeSize;
+ else if (rsp->ulpStatus == IOSTAT_LS_RJT) {
+ job->reply->reply_payload_rcv_len =
+ sizeof(struct fc_bsg_ctels_reply);
+ /* LS_RJT data returned in word 4 */
+ rjt_data = (uint8_t *)&rsp->un.ulpWord[4];
+ els_reply = &job->reply->reply_data.ctels_reply;
+ els_reply->status = FC_CTELS_STATUS_REJECT;
+ els_reply->rjt_data.action = rjt_data[3];
+ els_reply->rjt_data.reason_code = rjt_data[2];
+ els_reply->rjt_data.reason_explanation = rjt_data[1];
+ els_reply->rjt_data.vendor_unique = rjt_data[0];
+ } else
+ rc = -EIO;
+
+ pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3;
+ lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys);
+ lpfc_sli_release_iocbq(phba, rspiocbq);
+ lpfc_sli_release_iocbq(phba, cmdiocbq);
+ lpfc_nlp_put(ndlp);
+ kfree(dd_data);
/* make error code available to userspace */
job->reply->result = rc;
+ job->dd_data = NULL;
/* complete the job back to userspace */
job->job_done(job);
-
- return 0;
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ return;
}
/**
* lpfc_bsg_rport_els - send an ELS command from a bsg request
* @job: fc_bsg_job to handle
- */
+ **/
static int
lpfc_bsg_rport_els(struct fc_bsg_job *job)
{
@@ -236,7 +484,6 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
struct lpfc_hba *phba = vport->phba;
struct lpfc_rport_data *rdata = job->rport->dd_data;
struct lpfc_nodelist *ndlp = rdata->pnode;
-
uint32_t elscmd;
uint32_t cmdsize;
uint32_t rspsize;
@@ -248,20 +495,30 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
struct lpfc_dmabuf *prsp;
struct lpfc_dmabuf *pbuflist = NULL;
struct ulp_bde64 *bpl;
- int iocb_status;
int request_nseg;
int reply_nseg;
struct scatterlist *sgel = NULL;
int numbde;
dma_addr_t busaddr;
+ struct bsg_job_data *dd_data;
+ uint32_t creg_val;
int rc = 0;
/* in case no data is transferred */
job->reply->reply_payload_rcv_len = 0;
+ /* allocate our bsg tracking structure */
+ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
+ if (!dd_data) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2735 Failed allocation of dd_data\n");
+ rc = -ENOMEM;
+ goto no_dd_data;
+ }
+
if (!lpfc_nlp_get(ndlp)) {
rc = -ENODEV;
- goto out;
+ goto free_dd_data;
}
elscmd = job->request->rqst_data.r_els.els_code;
@@ -271,24 +528,24 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
if (!rspiocbq) {
lpfc_nlp_put(ndlp);
rc = -ENOMEM;
- goto out;
+ goto free_dd_data;
}
rsp = &rspiocbq->iocb;
rpi = ndlp->nlp_rpi;
- cmdiocbq = lpfc_prep_els_iocb(phba->pport, 1, cmdsize, 0, ndlp,
+ cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp,
ndlp->nlp_DID, elscmd);
-
if (!cmdiocbq) {
- lpfc_sli_release_iocbq(phba, rspiocbq);
- return -EIO;
+ rc = -EIO;
+ goto free_rspiocbq;
}
- job->dd_data = cmdiocbq;
+ /* prep els iocb set context1 to the ndlp, context2 to the command
+ * dmabuf, context3 holds the data dmabuf
+ */
pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2;
prsp = (struct lpfc_dmabuf *) pcmd->list.next;
-
lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
kfree(pcmd);
lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
@@ -300,7 +557,6 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
job->request_payload.sg_cnt, DMA_TO_DEVICE);
-
for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
busaddr = sg_dma_address(sgel);
bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
@@ -322,7 +578,6 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
bpl++;
}
-
cmdiocbq->iocb.un.elsreq64.bdl.bdeSize =
(request_nseg + reply_nseg) * sizeof(struct ulp_bde64);
cmdiocbq->iocb.ulpContext = rpi;
@@ -330,102 +585,62 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
cmdiocbq->context1 = NULL;
cmdiocbq->context2 = NULL;
- iocb_status = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
- rspiocbq, (phba->fc_ratov * 2)
- + LPFC_DRVR_TIMEOUT);
-
- /* release the new ndlp once the iocb completes */
- lpfc_nlp_put(ndlp);
- if (iocb_status != IOCB_TIMEDOUT) {
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp;
+ cmdiocbq->context1 = dd_data;
+ cmdiocbq->context2 = rspiocbq;
+ dd_data->type = TYPE_IOCB;
+ dd_data->context_un.iocb.cmdiocbq = cmdiocbq;
+ dd_data->context_un.iocb.rspiocbq = rspiocbq;
+ dd_data->context_un.iocb.set_job = job;
+ dd_data->context_un.iocb.bmp = NULL;;
+ dd_data->context_un.iocb.ndlp = ndlp;
+
+ if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
+ creg_val = readl(phba->HCregaddr);
+ creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING);
+ writel(creg_val, phba->HCregaddr);
+ readl(phba->HCregaddr); /* flush */
}
+ rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0);
+ lpfc_nlp_put(ndlp);
+ if (rc == IOCB_SUCCESS)
+ return 0; /* done for now */
- if (iocb_status == IOCB_SUCCESS) {
- if (rsp->ulpStatus == IOSTAT_SUCCESS) {
- job->reply->reply_payload_rcv_len =
- rsp->un.elsreq64.bdl.bdeSize;
- rc = 0;
- } else if (rsp->ulpStatus == IOSTAT_LS_RJT) {
- struct fc_bsg_ctels_reply *els_reply;
- /* LS_RJT data returned in word 4 */
- uint8_t *rjt_data = (uint8_t *)&rsp->un.ulpWord[4];
-
- els_reply = &job->reply->reply_data.ctels_reply;
- job->reply->result = 0;
- els_reply->status = FC_CTELS_STATUS_REJECT;
- els_reply->rjt_data.action = rjt_data[0];
- els_reply->rjt_data.reason_code = rjt_data[1];
- els_reply->rjt_data.reason_explanation = rjt_data[2];
- els_reply->rjt_data.vendor_unique = rjt_data[3];
- } else
- rc = -EIO;
- } else
- rc = -EIO;
+ pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+
+ lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys);
- if (iocb_status != IOCB_TIMEDOUT)
- lpfc_els_free_iocb(phba, cmdiocbq);
+ lpfc_sli_release_iocbq(phba, cmdiocbq);
+free_rspiocbq:
lpfc_sli_release_iocbq(phba, rspiocbq);
-out:
+free_dd_data:
+ kfree(dd_data);
+
+no_dd_data:
/* make error code available to userspace */
job->reply->result = rc;
- /* complete the job back to userspace */
- job->job_done(job);
-
- return 0;
-}
-
-struct lpfc_ct_event {
- struct list_head node;
- int ref;
- wait_queue_head_t wq;
-
- /* Event type and waiter identifiers */
- uint32_t type_mask;
- uint32_t req_id;
- uint32_t reg_id;
-
- /* next two flags are here for the auto-delete logic */
- unsigned long wait_time_stamp;
- int waiting;
-
- /* seen and not seen events */
- struct list_head events_to_get;
- struct list_head events_to_see;
-};
-
-struct event_data {
- struct list_head node;
- uint32_t type;
- uint32_t immed_dat;
- void *data;
- uint32_t len;
-};
-
-static struct lpfc_ct_event *
-lpfc_ct_event_new(int ev_reg_id, uint32_t ev_req_id)
-{
- struct lpfc_ct_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL);
- if (!evt)
- return NULL;
-
- INIT_LIST_HEAD(&evt->events_to_get);
- INIT_LIST_HEAD(&evt->events_to_see);
- evt->req_id = ev_req_id;
- evt->reg_id = ev_reg_id;
- evt->wait_time_stamp = jiffies;
- init_waitqueue_head(&evt->wq);
-
- return evt;
+ job->dd_data = NULL;
+ return rc;
}
+/**
+ * lpfc_bsg_event_free - frees an allocated event structure
+ * @kref: Pointer to a kref.
+ *
+ * Called from kref_put. Back cast the kref into an event structure address.
+ * Free any events to get, delete associated nodes, free any events to see,
+ * free any data then free the event itself.
+ **/
static void
-lpfc_ct_event_free(struct lpfc_ct_event *evt)
+lpfc_bsg_event_free(struct kref *kref)
{
+ struct lpfc_bsg_event *evt = container_of(kref, struct lpfc_bsg_event,
+ kref);
struct event_data *ed;
list_del(&evt->node);
@@ -447,25 +662,82 @@ lpfc_ct_event_free(struct lpfc_ct_event *evt)
kfree(evt);
}
+/**
+ * lpfc_bsg_event_ref - increments the kref for an event
+ * @evt: Pointer to an event structure.
+ **/
static inline void
-lpfc_ct_event_ref(struct lpfc_ct_event *evt)
+lpfc_bsg_event_ref(struct lpfc_bsg_event *evt)
{
- evt->ref++;
+ kref_get(&evt->kref);
}
+/**
+ * lpfc_bsg_event_unref - Uses kref_put to free an event structure
+ * @evt: Pointer to an event structure.
+ **/
static inline void
-lpfc_ct_event_unref(struct lpfc_ct_event *evt)
+lpfc_bsg_event_unref(struct lpfc_bsg_event *evt)
{
- if (--evt->ref < 0)
- lpfc_ct_event_free(evt);
+ kref_put(&evt->kref, lpfc_bsg_event_free);
}
-#define SLI_CT_ELX_LOOPBACK 0x10
+/**
+ * lpfc_bsg_event_new - allocate and initialize a event structure
+ * @ev_mask: Mask of events.
+ * @ev_reg_id: Event reg id.
+ * @ev_req_id: Event request id.
+ **/
+static struct lpfc_bsg_event *
+lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id)
+{
+ struct lpfc_bsg_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL);
-enum ELX_LOOPBACK_CMD {
- ELX_LOOPBACK_XRI_SETUP,
- ELX_LOOPBACK_DATA,
-};
+ if (!evt)
+ return NULL;
+
+ INIT_LIST_HEAD(&evt->events_to_get);
+ INIT_LIST_HEAD(&evt->events_to_see);
+ evt->type_mask = ev_mask;
+ evt->req_id = ev_req_id;
+ evt->reg_id = ev_reg_id;
+ evt->wait_time_stamp = jiffies;
+ init_waitqueue_head(&evt->wq);
+ kref_init(&evt->kref);
+ return evt;
+}
+
+/**
+ * diag_cmd_data_free - Frees an lpfc dma buffer extension
+ * @phba: Pointer to HBA context object.
+ * @mlist: Pointer to an lpfc dma buffer extension.
+ **/
+static int
+diag_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist)
+{
+ struct lpfc_dmabufext *mlast;
+ struct pci_dev *pcidev;
+ struct list_head head, *curr, *next;
+
+ if ((!mlist) || (!lpfc_is_link_up(phba) &&
+ (phba->link_flag & LS_LOOPBACK_MODE))) {
+ return 0;
+ }
+
+ pcidev = phba->pcidev;
+ list_add_tail(&head, &mlist->dma.list);
+
+ list_for_each_safe(curr, next, &head) {
+ mlast = list_entry(curr, struct lpfc_dmabufext , dma.list);
+ if (mlast->dma.virt)
+ dma_free_coherent(&pcidev->dev,
+ mlast->size,
+ mlast->dma.virt,
+ mlast->dma.phys);
+ kfree(mlast);
+ }
+ return 0;
+}
/**
* lpfc_bsg_ct_unsol_event - process an unsolicited CT command
@@ -474,9 +746,9 @@ enum ELX_LOOPBACK_CMD {
* @piocbq:
*
* This function is called when an unsolicited CT command is received. It
- * forwards the event to any processes registerd to receive CT events.
- */
-void
+ * forwards the event to any processes registered to receive CT events.
+ **/
+int
lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocbq)
{
@@ -484,7 +756,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
uint32_t cmd;
uint32_t len;
struct lpfc_dmabuf *dmabuf = NULL;
- struct lpfc_ct_event *evt;
+ struct lpfc_bsg_event *evt;
struct event_data *evt_dat = NULL;
struct lpfc_iocbq *iocbq;
size_t offset = 0;
@@ -496,6 +768,9 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;
struct lpfc_hbq_entry *hbqe;
struct lpfc_sli_ct_request *ct_req;
+ struct fc_bsg_job *job = NULL;
+ unsigned long flags;
+ int size = 0;
INIT_LIST_HEAD(&head);
list_add_tail(&head, &piocbq->list);
@@ -504,6 +779,10 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0)
goto error_ct_unsol_exit;
+ if (phba->link_state == LPFC_HBA_ERROR ||
+ (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)))
+ goto error_ct_unsol_exit;
+
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
dmabuf = bdeBuf1;
else {
@@ -511,7 +790,8 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
piocbq->iocb.un.cont64[0].addrLow);
dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr);
}
-
+ if (dmabuf == NULL)
+ goto error_ct_unsol_exit;
ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt;
evt_req_id = ct_req->FsType;
cmd = ct_req->CommandResponse.bits.CmdRsp;
@@ -519,24 +799,24 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
lpfc_sli_ringpostbuf_put(phba, pring, dmabuf);
- mutex_lock(&phba->ct_event_mutex);
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
- if (evt->req_id != evt_req_id)
+ if (!(evt->type_mask & FC_REG_CT_EVENT) ||
+ evt->req_id != evt_req_id)
continue;
- lpfc_ct_event_ref(evt);
-
+ lpfc_bsg_event_ref(evt);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL);
- if (!evt_dat) {
- lpfc_ct_event_unref(evt);
+ if (evt_dat == NULL) {
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ lpfc_bsg_event_unref(evt);
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
"2614 Memory allocation failed for "
"CT event\n");
break;
}
- mutex_unlock(&phba->ct_event_mutex);
-
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
/* take accumulated byte count from the last iocbq */
iocbq = list_entry(head.prev, typeof(*iocbq), list);
@@ -550,25 +830,25 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL);
- if (!evt_dat->data) {
+ if (evt_dat->data == NULL) {
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
"2615 Memory allocation failed for "
"CT event data, size %d\n",
evt_dat->len);
kfree(evt_dat);
- mutex_lock(&phba->ct_event_mutex);
- lpfc_ct_event_unref(evt);
- mutex_unlock(&phba->ct_event_mutex);
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ lpfc_bsg_event_unref(evt);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
goto error_ct_unsol_exit;
}
list_for_each_entry(iocbq, &head, list) {
+ size = 0;
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
bdeBuf1 = iocbq->context2;
bdeBuf2 = iocbq->context3;
}
for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) {
- int size = 0;
if (phba->sli3_options &
LPFC_SLI3_HBQ_ENABLED) {
if (i == 0) {
@@ -601,9 +881,11 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
iocbq);
kfree(evt_dat->data);
kfree(evt_dat);
- mutex_lock(&phba->ct_event_mutex);
- lpfc_ct_event_unref(evt);
- mutex_unlock(&phba->ct_event_mutex);
+ spin_lock_irqsave(&phba->ct_ev_lock,
+ flags);
+ lpfc_bsg_event_unref(evt);
+ spin_unlock_irqrestore(
+ &phba->ct_ev_lock, flags);
goto error_ct_unsol_exit;
}
memcpy((char *)(evt_dat->data) + offset,
@@ -616,15 +898,24 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
dmabuf);
} else {
switch (cmd) {
+ case ELX_LOOPBACK_DATA:
+ diag_cmd_data_free(phba,
+ (struct lpfc_dmabufext *)
+ dmabuf);
+ break;
case ELX_LOOPBACK_XRI_SETUP:
- if (!(phba->sli3_options &
- LPFC_SLI3_HBQ_ENABLED))
+ if ((phba->sli_rev ==
+ LPFC_SLI_REV2) ||
+ (phba->sli3_options &
+ LPFC_SLI3_HBQ_ENABLED
+ )) {
+ lpfc_in_buf_free(phba,
+ dmabuf);
+ } else {
lpfc_post_buffer(phba,
pring,
1);
- else
- lpfc_in_buf_free(phba,
- dmabuf);
+ }
break;
default:
if (!(phba->sli3_options &
@@ -638,7 +929,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
}
- mutex_lock(&phba->ct_event_mutex);
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
if (phba->sli_rev == LPFC_SLI_REV4) {
evt_dat->immed_dat = phba->ctx_idx;
phba->ctx_idx = (phba->ctx_idx + 1) % 64;
@@ -651,122 +942,144 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
evt_dat->type = FC_REG_CT_EVENT;
list_add(&evt_dat->node, &evt->events_to_see);
- wake_up_interruptible(&evt->wq);
- lpfc_ct_event_unref(evt);
- if (evt_req_id == SLI_CT_ELX_LOOPBACK)
+ if (evt_req_id == SLI_CT_ELX_LOOPBACK) {
+ wake_up_interruptible(&evt->wq);
+ lpfc_bsg_event_unref(evt);
break;
+ }
+
+ list_move(evt->events_to_see.prev, &evt->events_to_get);
+ lpfc_bsg_event_unref(evt);
+
+ job = evt->set_job;
+ evt->set_job = NULL;
+ if (job) {
+ job->reply->reply_payload_rcv_len = size;
+ /* make error code available to userspace */
+ job->reply->result = 0;
+ job->dd_data = NULL;
+ /* complete the job back to userspace */
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ job->job_done(job);
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ }
}
- mutex_unlock(&phba->ct_event_mutex);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
error_ct_unsol_exit:
if (!list_empty(&head))
list_del(&head);
-
- return;
+ if (evt_req_id == SLI_CT_ELX_LOOPBACK)
+ return 0;
+ return 1;
}
/**
- * lpfc_bsg_set_event - process a SET_EVENT bsg vendor command
+ * lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command
* @job: SET_EVENT fc_bsg_job
- */
+ **/
static int
-lpfc_bsg_set_event(struct fc_bsg_job *job)
+lpfc_bsg_hba_set_event(struct fc_bsg_job *job)
{
struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct set_ct_event *event_req;
- struct lpfc_ct_event *evt;
+ struct lpfc_bsg_event *evt;
int rc = 0;
+ struct bsg_job_data *dd_data = NULL;
+ uint32_t ev_mask;
+ unsigned long flags;
if (job->request_len <
sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
"2612 Received SET_CT_EVENT below minimum "
"size\n");
- return -EINVAL;
+ rc = -EINVAL;
+ goto job_error;
+ }
+
+ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
+ if (dd_data == NULL) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2734 Failed allocation of dd_data\n");
+ rc = -ENOMEM;
+ goto job_error;
}
event_req = (struct set_ct_event *)
job->request->rqst_data.h_vendor.vendor_cmd;
-
- mutex_lock(&phba->ct_event_mutex);
+ ev_mask = ((uint32_t)(unsigned long)event_req->type_mask &
+ FC_REG_EVENT_MASK);
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
if (evt->reg_id == event_req->ev_reg_id) {
- lpfc_ct_event_ref(evt);
+ lpfc_bsg_event_ref(evt);
evt->wait_time_stamp = jiffies;
break;
}
}
- mutex_unlock(&phba->ct_event_mutex);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
if (&evt->node == &phba->ct_ev_waiters) {
/* no event waiting struct yet - first call */
- evt = lpfc_ct_event_new(event_req->ev_reg_id,
+ evt = lpfc_bsg_event_new(ev_mask, event_req->ev_reg_id,
event_req->ev_req_id);
if (!evt) {
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
"2617 Failed allocation of event "
"waiter\n");
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto job_error;
}
- mutex_lock(&phba->ct_event_mutex);
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
list_add(&evt->node, &phba->ct_ev_waiters);
- lpfc_ct_event_ref(evt);
- mutex_unlock(&phba->ct_event_mutex);
+ lpfc_bsg_event_ref(evt);
+ evt->wait_time_stamp = jiffies;
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
}
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
evt->waiting = 1;
- if (wait_event_interruptible(evt->wq,
- !list_empty(&evt->events_to_see))) {
- mutex_lock(&phba->ct_event_mutex);
- lpfc_ct_event_unref(evt); /* release ref */
- lpfc_ct_event_unref(evt); /* delete */
- mutex_unlock(&phba->ct_event_mutex);
- rc = -EINTR;
- goto set_event_out;
- }
-
- evt->wait_time_stamp = jiffies;
- evt->waiting = 0;
-
- mutex_lock(&phba->ct_event_mutex);
- list_move(evt->events_to_see.prev, &evt->events_to_get);
- lpfc_ct_event_unref(evt); /* release ref */
- mutex_unlock(&phba->ct_event_mutex);
-
-set_event_out:
- /* set_event carries no reply payload */
- job->reply->reply_payload_rcv_len = 0;
- /* make error code available to userspace */
- job->reply->result = rc;
- /* complete the job back to userspace */
- job->job_done(job);
-
- return 0;
+ dd_data->type = TYPE_EVT;
+ dd_data->context_un.evt = evt;
+ evt->set_job = job; /* for unsolicited command */
+ job->dd_data = dd_data; /* for fc transport timeout callback*/
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ return 0; /* call job done later */
+
+job_error:
+ if (dd_data != NULL)
+ kfree(dd_data);
+
+ job->dd_data = NULL;
+ return rc;
}
/**
- * lpfc_bsg_get_event - process a GET_EVENT bsg vendor command
+ * lpfc_bsg_hba_get_event - process a GET_EVENT bsg vendor command
* @job: GET_EVENT fc_bsg_job
- */
+ **/
static int
-lpfc_bsg_get_event(struct fc_bsg_job *job)
+lpfc_bsg_hba_get_event(struct fc_bsg_job *job)
{
struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct get_ct_event *event_req;
struct get_ct_event_reply *event_reply;
- struct lpfc_ct_event *evt;
+ struct lpfc_bsg_event *evt;
struct event_data *evt_dat = NULL;
- int rc = 0;
+ unsigned long flags;
+ uint32_t rc = 0;
if (job->request_len <
sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
"2613 Received GET_CT_EVENT request below "
"minimum size\n");
- return -EINVAL;
+ rc = -EINVAL;
+ goto job_error;
}
event_req = (struct get_ct_event *)
@@ -774,13 +1087,12 @@ lpfc_bsg_get_event(struct fc_bsg_job *job)
event_reply = (struct get_ct_event_reply *)
job->reply->reply_data.vendor_reply.vendor_rsp;
-
- mutex_lock(&phba->ct_event_mutex);
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
if (evt->reg_id == event_req->ev_reg_id) {
if (list_empty(&evt->events_to_get))
break;
- lpfc_ct_event_ref(evt);
+ lpfc_bsg_event_ref(evt);
evt->wait_time_stamp = jiffies;
evt_dat = list_entry(evt->events_to_get.prev,
struct event_data, node);
@@ -788,45 +1100,1539 @@ lpfc_bsg_get_event(struct fc_bsg_job *job)
break;
}
}
- mutex_unlock(&phba->ct_event_mutex);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- if (!evt_dat) {
+ /* The app may continue to ask for event data until it gets
+ * an error indicating that there isn't anymore
+ */
+ if (evt_dat == NULL) {
job->reply->reply_payload_rcv_len = 0;
rc = -ENOENT;
- goto error_get_event_exit;
+ goto job_error;
}
- if (evt_dat->len > job->reply_payload.payload_len) {
- evt_dat->len = job->reply_payload.payload_len;
- lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
- "2618 Truncated event data at %d "
- "bytes\n",
- job->reply_payload.payload_len);
+ if (evt_dat->len > job->request_payload.payload_len) {
+ evt_dat->len = job->request_payload.payload_len;
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2618 Truncated event data at %d "
+ "bytes\n",
+ job->request_payload.payload_len);
}
+ event_reply->type = evt_dat->type;
event_reply->immed_data = evt_dat->immed_dat;
-
if (evt_dat->len > 0)
job->reply->reply_payload_rcv_len =
- sg_copy_from_buffer(job->reply_payload.sg_list,
- job->reply_payload.sg_cnt,
+ sg_copy_from_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
evt_dat->data, evt_dat->len);
else
job->reply->reply_payload_rcv_len = 0;
- rc = 0;
- if (evt_dat)
+ if (evt_dat) {
kfree(evt_dat->data);
- kfree(evt_dat);
- mutex_lock(&phba->ct_event_mutex);
- lpfc_ct_event_unref(evt);
- mutex_unlock(&phba->ct_event_mutex);
+ kfree(evt_dat);
+ }
+
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ lpfc_bsg_event_unref(evt);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ job->dd_data = NULL;
+ job->reply->result = 0;
+ job->job_done(job);
+ return 0;
+
+job_error:
+ job->dd_data = NULL;
+ job->reply->result = rc;
+ return rc;
+}
+
+/**
+ * lpfc_issue_ct_rsp_cmp - lpfc_issue_ct_rsp's completion handler
+ * @phba: Pointer to HBA context object.
+ * @cmdiocbq: Pointer to command iocb.
+ * @rspiocbq: Pointer to response iocb.
+ *
+ * This function is the completion handler for iocbs issued using
+ * lpfc_issue_ct_rsp_cmp function. This function is called by the
+ * ring event handler function without any lock held. This function
+ * can be called from both worker thread context and interrupt
+ * context. This function also can be called from other thread which
+ * cleans up the SLI layer objects.
+ * This function copy the contents of the response iocb to the
+ * response iocb memory object provided by the caller of
+ * lpfc_sli_issue_iocb_wait and then wakes up the thread which
+ * sleeps for the iocb completion.
+ **/
+static void
+lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba,
+ struct lpfc_iocbq *cmdiocbq,
+ struct lpfc_iocbq *rspiocbq)
+{
+ struct bsg_job_data *dd_data;
+ struct fc_bsg_job *job;
+ IOCB_t *rsp;
+ struct lpfc_dmabuf *bmp;
+ struct lpfc_nodelist *ndlp;
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ dd_data = cmdiocbq->context1;
+ /* normal completion and timeout crossed paths, already done */
+ if (!dd_data) {
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+ return;
+ }
-error_get_event_exit:
+ job = dd_data->context_un.iocb.set_job;
+ bmp = dd_data->context_un.iocb.bmp;
+ rsp = &rspiocbq->iocb;
+ ndlp = dd_data->context_un.iocb.ndlp;
+
+ pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+ if (rsp->ulpStatus) {
+ if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+ switch (rsp->un.ulpWord[4] & 0xff) {
+ case IOERR_SEQUENCE_TIMEOUT:
+ rc = -ETIMEDOUT;
+ break;
+ case IOERR_INVALID_RPI:
+ rc = -EFAULT;
+ break;
+ default:
+ rc = -EACCES;
+ break;
+ }
+ } else
+ rc = -EACCES;
+ } else
+ job->reply->reply_payload_rcv_len =
+ rsp->un.genreq64.bdl.bdeSize;
+
+ lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+ lpfc_sli_release_iocbq(phba, cmdiocbq);
+ lpfc_nlp_put(ndlp);
+ kfree(bmp);
+ kfree(dd_data);
/* make error code available to userspace */
job->reply->result = rc;
+ job->dd_data = NULL;
/* complete the job back to userspace */
job->job_done(job);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ return;
+}
+
+/**
+ * lpfc_issue_ct_rsp - issue a ct response
+ * @phba: Pointer to HBA context object.
+ * @job: Pointer to the job object.
+ * @tag: tag index value into the ports context exchange array.
+ * @bmp: Pointer to a dma buffer descriptor.
+ * @num_entry: Number of enties in the bde.
+ **/
+static int
+lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
+ struct lpfc_dmabuf *bmp, int num_entry)
+{
+ IOCB_t *icmd;
+ struct lpfc_iocbq *ctiocb = NULL;
+ int rc = 0;
+ struct lpfc_nodelist *ndlp = NULL;
+ struct bsg_job_data *dd_data;
+ uint32_t creg_val;
+
+ /* allocate our bsg tracking structure */
+ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
+ if (!dd_data) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2736 Failed allocation of dd_data\n");
+ rc = -ENOMEM;
+ goto no_dd_data;
+ }
+
+ /* Allocate buffer for command iocb */
+ ctiocb = lpfc_sli_get_iocbq(phba);
+ if (!ctiocb) {
+ rc = ENOMEM;
+ goto no_ctiocb;
+ }
+
+ icmd = &ctiocb->iocb;
+ icmd->un.xseq64.bdl.ulpIoTag32 = 0;
+ icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
+ icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys);
+ icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
+ icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64));
+ icmd->un.xseq64.w5.hcsw.Fctl = (LS | LA);
+ icmd->un.xseq64.w5.hcsw.Dfctl = 0;
+ icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL;
+ icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT;
+
+ /* Fill in rest of iocb */
+ icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX;
+ icmd->ulpBdeCount = 1;
+ icmd->ulpLe = 1;
+ icmd->ulpClass = CLASS3;
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ /* Do not issue unsol response if oxid not marked as valid */
+ if (!(phba->ct_ctx[tag].flags & UNSOL_VALID)) {
+ rc = IOCB_ERROR;
+ goto issue_ct_rsp_exit;
+ }
+ icmd->ulpContext = phba->ct_ctx[tag].oxid;
+ ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID);
+ if (!ndlp) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
+ "2721 ndlp null for oxid %x SID %x\n",
+ icmd->ulpContext,
+ phba->ct_ctx[tag].SID);
+ rc = IOCB_ERROR;
+ goto issue_ct_rsp_exit;
+ }
+ icmd->un.ulpWord[3] = ndlp->nlp_rpi;
+ /* The exchange is done, mark the entry as invalid */
+ phba->ct_ctx[tag].flags &= ~UNSOL_VALID;
+ } else
+ icmd->ulpContext = (ushort) tag;
+
+ icmd->ulpTimeout = phba->fc_ratov * 2;
+
+ /* Xmit CT response on exchange <xid> */
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "2722 Xmit CT response on exchange x%x Data: x%x x%x\n",
+ icmd->ulpContext, icmd->ulpIoTag, phba->link_state);
+
+ ctiocb->iocb_cmpl = NULL;
+ ctiocb->iocb_flag |= LPFC_IO_LIBDFC;
+ ctiocb->vport = phba->pport;
+ ctiocb->context3 = bmp;
+
+ ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp;
+ ctiocb->context1 = dd_data;
+ ctiocb->context2 = NULL;
+ dd_data->type = TYPE_IOCB;
+ dd_data->context_un.iocb.cmdiocbq = ctiocb;
+ dd_data->context_un.iocb.rspiocbq = NULL;
+ dd_data->context_un.iocb.set_job = job;
+ dd_data->context_un.iocb.bmp = bmp;
+ dd_data->context_un.iocb.ndlp = ndlp;
+
+ if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
+ creg_val = readl(phba->HCregaddr);
+ creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING);
+ writel(creg_val, phba->HCregaddr);
+ readl(phba->HCregaddr); /* flush */
+ }
+
+ rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0);
+
+ if (rc == IOCB_SUCCESS)
+ return 0; /* done for now */
+
+issue_ct_rsp_exit:
+ lpfc_sli_release_iocbq(phba, ctiocb);
+no_ctiocb:
+ kfree(dd_data);
+no_dd_data:
+ return rc;
+}
+
+/**
+ * lpfc_bsg_send_mgmt_rsp - process a SEND_MGMT_RESP bsg vendor command
+ * @job: SEND_MGMT_RESP fc_bsg_job
+ **/
+static int
+lpfc_bsg_send_mgmt_rsp(struct fc_bsg_job *job)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct send_mgmt_resp *mgmt_resp = (struct send_mgmt_resp *)
+ job->request->rqst_data.h_vendor.vendor_cmd;
+ struct ulp_bde64 *bpl;
+ struct lpfc_dmabuf *bmp = NULL;
+ struct scatterlist *sgel = NULL;
+ int request_nseg;
+ int numbde;
+ dma_addr_t busaddr;
+ uint32_t tag = mgmt_resp->tag;
+ unsigned long reqbfrcnt =
+ (unsigned long)job->request_payload.payload_len;
+ int rc = 0;
+
+ /* in case no data is transferred */
+ job->reply->reply_payload_rcv_len = 0;
+
+ if (!reqbfrcnt || (reqbfrcnt > (80 * BUF_SZ_4K))) {
+ rc = -ERANGE;
+ goto send_mgmt_rsp_exit;
+ }
+
+ bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (!bmp) {
+ rc = -ENOMEM;
+ goto send_mgmt_rsp_exit;
+ }
+
+ bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
+ if (!bmp->virt) {
+ rc = -ENOMEM;
+ goto send_mgmt_rsp_free_bmp;
+ }
+
+ INIT_LIST_HEAD(&bmp->list);
+ bpl = (struct ulp_bde64 *) bmp->virt;
+ request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
+ busaddr = sg_dma_address(sgel);
+ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+ bpl->tus.f.bdeSize = sg_dma_len(sgel);
+ bpl->tus.w = cpu_to_le32(bpl->tus.w);
+ bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
+ bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
+ bpl++;
+ }
+
+ rc = lpfc_issue_ct_rsp(phba, job, tag, bmp, request_nseg);
+
+ if (rc == IOCB_SUCCESS)
+ return 0; /* done for now */
+
+ /* TBD need to handle a timeout */
+ pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ rc = -EACCES;
+ lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+
+send_mgmt_rsp_free_bmp:
+ kfree(bmp);
+send_mgmt_rsp_exit:
+ /* make error code available to userspace */
+ job->reply->result = rc;
+ job->dd_data = NULL;
+ return rc;
+}
+
+/**
+ * lpfc_bsg_diag_mode - process a LPFC_BSG_VENDOR_DIAG_MODE bsg vendor command
+ * @job: LPFC_BSG_VENDOR_DIAG_MODE
+ *
+ * This function is responsible for placing a port into diagnostic loopback
+ * mode in order to perform a diagnostic loopback test.
+ * All new scsi requests are blocked, a small delay is used to allow the
+ * scsi requests to complete then the link is brought down. If the link is
+ * is placed in loopback mode then scsi requests are again allowed
+ * so the scsi mid-layer doesn't give up on the port.
+ * All of this is done in-line.
+ */
+static int
+lpfc_bsg_diag_mode(struct fc_bsg_job *job)
+{
+ struct Scsi_Host *shost = job->shost;
+ struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct diag_mode_set *loopback_mode;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING];
+ uint32_t link_flags;
+ uint32_t timeout;
+ struct lpfc_vport **vports;
+ LPFC_MBOXQ_t *pmboxq;
+ int mbxstatus;
+ int i = 0;
+ int rc = 0;
+
+ /* no data to return just the return code */
+ job->reply->reply_payload_rcv_len = 0;
+
+ if (job->request_len <
+ sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_set)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2738 Received DIAG MODE request below minimum "
+ "size\n");
+ rc = -EINVAL;
+ goto job_error;
+ }
+
+ loopback_mode = (struct diag_mode_set *)
+ job->request->rqst_data.h_vendor.vendor_cmd;
+ link_flags = loopback_mode->type;
+ timeout = loopback_mode->timeout;
+
+ if ((phba->link_state == LPFC_HBA_ERROR) ||
+ (psli->sli_flag & LPFC_BLOCK_MGMT_IO) ||
+ (!(psli->sli_flag & LPFC_SLI_ACTIVE))) {
+ rc = -EACCES;
+ goto job_error;
+ }
+
+ pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmboxq) {
+ rc = -ENOMEM;
+ goto job_error;
+ }
+
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports) {
+ for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+ shost = lpfc_shost_from_vport(vports[i]);
+ scsi_block_requests(shost);
+ }
+
+ lpfc_destroy_vport_work_array(phba, vports);
+ } else {
+ shost = lpfc_shost_from_vport(phba->pport);
+ scsi_block_requests(shost);
+ }
+
+ while (pring->txcmplq_cnt) {
+ if (i++ > 500) /* wait up to 5 seconds */
+ break;
+
+ msleep(10);
+ }
+
+ memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t));
+ pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK;
+ pmboxq->u.mb.mbxOwner = OWN_HOST;
+
+ mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO);
+
+ if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) {
+ /* wait for link down before proceeding */
+ i = 0;
+ while (phba->link_state != LPFC_LINK_DOWN) {
+ if (i++ > timeout) {
+ rc = -ETIMEDOUT;
+ goto loopback_mode_exit;
+ }
+
+ msleep(10);
+ }
+
+ memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t));
+ if (link_flags == INTERNAL_LOOP_BACK)
+ pmboxq->u.mb.un.varInitLnk.link_flags = FLAGS_LOCAL_LB;
+ else
+ pmboxq->u.mb.un.varInitLnk.link_flags =
+ FLAGS_TOPOLOGY_MODE_LOOP;
+
+ pmboxq->u.mb.mbxCommand = MBX_INIT_LINK;
+ pmboxq->u.mb.mbxOwner = OWN_HOST;
+
+ mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq,
+ LPFC_MBOX_TMO);
+
+ if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus))
+ rc = -ENODEV;
+ else {
+ phba->link_flag |= LS_LOOPBACK_MODE;
+ /* wait for the link attention interrupt */
+ msleep(100);
+
+ i = 0;
+ while (phba->link_state != LPFC_HBA_READY) {
+ if (i++ > timeout) {
+ rc = -ETIMEDOUT;
+ break;
+ }
+
+ msleep(10);
+ }
+ }
+
+ } else
+ rc = -ENODEV;
+
+loopback_mode_exit:
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports) {
+ for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+ shost = lpfc_shost_from_vport(vports[i]);
+ scsi_unblock_requests(shost);
+ }
+ lpfc_destroy_vport_work_array(phba, vports);
+ } else {
+ shost = lpfc_shost_from_vport(phba->pport);
+ scsi_unblock_requests(shost);
+ }
+
+ /*
+ * Let SLI layer release mboxq if mbox command completed after timeout.
+ */
+ if (mbxstatus != MBX_TIMEOUT)
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+
+job_error:
+ /* make error code available to userspace */
+ job->reply->result = rc;
+ /* complete the job back to userspace if no error */
+ if (rc == 0)
+ job->job_done(job);
+ return rc;
+}
+
+/**
+ * lpfcdiag_loop_self_reg - obtains a remote port login id
+ * @phba: Pointer to HBA context object
+ * @rpi: Pointer to a remote port login id
+ *
+ * This function obtains a remote port login id so the diag loopback test
+ * can send and receive its own unsolicited CT command.
+ **/
+static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t * rpi)
+{
+ LPFC_MBOXQ_t *mbox;
+ struct lpfc_dmabuf *dmabuff;
+ int status;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ return ENOMEM;
+
+ status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID,
+ (uint8_t *)&phba->pport->fc_sparam, mbox, 0);
+ if (status) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ return ENOMEM;
+ }
+
+ dmabuff = (struct lpfc_dmabuf *) mbox->context1;
+ mbox->context1 = NULL;
+ status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
+
+ if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) {
+ lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys);
+ kfree(dmabuff);
+ if (status != MBX_TIMEOUT)
+ mempool_free(mbox, phba->mbox_mem_pool);
+ return ENODEV;
+ }
+
+ *rpi = mbox->u.mb.un.varWords[0];
+
+ lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys);
+ kfree(dmabuff);
+ mempool_free(mbox, phba->mbox_mem_pool);
+ return 0;
+}
+
+/**
+ * lpfcdiag_loop_self_unreg - unregs from the rpi
+ * @phba: Pointer to HBA context object
+ * @rpi: Remote port login id
+ *
+ * This function unregisters the rpi obtained in lpfcdiag_loop_self_reg
+ **/
+static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi)
+{
+ LPFC_MBOXQ_t *mbox;
+ int status;
+
+ /* Allocate mboxq structure */
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox == NULL)
+ return ENOMEM;
+
+ lpfc_unreg_login(phba, 0, rpi, mbox);
+ status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
+
+ if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) {
+ if (status != MBX_TIMEOUT)
+ mempool_free(mbox, phba->mbox_mem_pool);
+ return EIO;
+ }
+
+ mempool_free(mbox, phba->mbox_mem_pool);
+ return 0;
+}
+
+/**
+ * lpfcdiag_loop_get_xri - obtains the transmit and receive ids
+ * @phba: Pointer to HBA context object
+ * @rpi: Remote port login id
+ * @txxri: Pointer to transmit exchange id
+ * @rxxri: Pointer to response exchabge id
+ *
+ * This function obtains the transmit and receive ids required to send
+ * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp
+ * flags are used to the unsolicted response handler is able to process
+ * the ct command sent on the same port.
+ **/
+static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
+ uint16_t *txxri, uint16_t * rxxri)
+{
+ struct lpfc_bsg_event *evt;
+ struct lpfc_iocbq *cmdiocbq, *rspiocbq;
+ IOCB_t *cmd, *rsp;
+ struct lpfc_dmabuf *dmabuf;
+ struct ulp_bde64 *bpl = NULL;
+ struct lpfc_sli_ct_request *ctreq = NULL;
+ int ret_val = 0;
+ unsigned long flags;
+
+ *txxri = 0;
+ *rxxri = 0;
+ evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid,
+ SLI_CT_ELX_LOOPBACK);
+ if (!evt)
+ return ENOMEM;
+
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ list_add(&evt->node, &phba->ct_ev_waiters);
+ lpfc_bsg_event_ref(evt);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ cmdiocbq = lpfc_sli_get_iocbq(phba);
+ rspiocbq = lpfc_sli_get_iocbq(phba);
+
+ dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (dmabuf) {
+ dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys);
+ INIT_LIST_HEAD(&dmabuf->list);
+ bpl = (struct ulp_bde64 *) dmabuf->virt;
+ memset(bpl, 0, sizeof(*bpl));
+ ctreq = (struct lpfc_sli_ct_request *)(bpl + 1);
+ bpl->addrHigh =
+ le32_to_cpu(putPaddrHigh(dmabuf->phys + sizeof(*bpl)));
+ bpl->addrLow =
+ le32_to_cpu(putPaddrLow(dmabuf->phys + sizeof(*bpl)));
+ bpl->tus.f.bdeFlags = 0;
+ bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ;
+ bpl->tus.w = le32_to_cpu(bpl->tus.w);
+ }
+
+ if (cmdiocbq == NULL || rspiocbq == NULL ||
+ dmabuf == NULL || bpl == NULL || ctreq == NULL) {
+ ret_val = ENOMEM;
+ goto err_get_xri_exit;
+ }
+
+ cmd = &cmdiocbq->iocb;
+ rsp = &rspiocbq->iocb;
+
+ memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ);
+
+ ctreq->RevisionId.bits.Revision = SLI_CT_REVISION;
+ ctreq->RevisionId.bits.InId = 0;
+ ctreq->FsType = SLI_CT_ELX_LOOPBACK;
+ ctreq->FsSubType = 0;
+ ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP;
+ ctreq->CommandResponse.bits.Size = 0;
+
+
+ cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys);
+ cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys);
+ cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
+ cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl);
+
+ cmd->un.xseq64.w5.hcsw.Fctl = LA;
+ cmd->un.xseq64.w5.hcsw.Dfctl = 0;
+ cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
+ cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT;
+
+ cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR;
+ cmd->ulpBdeCount = 1;
+ cmd->ulpLe = 1;
+ cmd->ulpClass = CLASS3;
+ cmd->ulpContext = rpi;
+
+ cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
+ cmdiocbq->vport = phba->pport;
+
+ ret_val = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
+ rspiocbq,
+ (phba->fc_ratov * 2)
+ + LPFC_DRVR_TIMEOUT);
+ if (ret_val)
+ goto err_get_xri_exit;
+
+ *txxri = rsp->ulpContext;
+
+ evt->waiting = 1;
+ evt->wait_time_stamp = jiffies;
+ ret_val = wait_event_interruptible_timeout(
+ evt->wq, !list_empty(&evt->events_to_see),
+ ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ);
+ if (list_empty(&evt->events_to_see))
+ ret_val = (ret_val) ? EINTR : ETIMEDOUT;
+ else {
+ ret_val = IOCB_SUCCESS;
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ list_move(evt->events_to_see.prev, &evt->events_to_get);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ *rxxri = (list_entry(evt->events_to_get.prev,
+ typeof(struct event_data),
+ node))->immed_dat;
+ }
+ evt->waiting = 0;
+
+err_get_xri_exit:
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ lpfc_bsg_event_unref(evt); /* release ref */
+ lpfc_bsg_event_unref(evt); /* delete */
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ if (dmabuf) {
+ if (dmabuf->virt)
+ lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+ kfree(dmabuf);
+ }
+
+ if (cmdiocbq && (ret_val != IOCB_TIMEDOUT))
+ lpfc_sli_release_iocbq(phba, cmdiocbq);
+ if (rspiocbq)
+ lpfc_sli_release_iocbq(phba, rspiocbq);
+ return ret_val;
+}
+
+/**
+ * diag_cmd_data_alloc - fills in a bde struct with dma buffers
+ * @phba: Pointer to HBA context object
+ * @bpl: Pointer to 64 bit bde structure
+ * @size: Number of bytes to process
+ * @nocopydata: Flag to copy user data into the allocated buffer
+ *
+ * This function allocates page size buffers and populates an lpfc_dmabufext.
+ * If allowed the user data pointed to with indataptr is copied into the kernel
+ * memory. The chained list of page size buffers is returned.
+ **/
+static struct lpfc_dmabufext *
+diag_cmd_data_alloc(struct lpfc_hba *phba,
+ struct ulp_bde64 *bpl, uint32_t size,
+ int nocopydata)
+{
+ struct lpfc_dmabufext *mlist = NULL;
+ struct lpfc_dmabufext *dmp;
+ int cnt, offset = 0, i = 0;
+ struct pci_dev *pcidev;
+
+ pcidev = phba->pcidev;
+
+ while (size) {
+ /* We get chunks of 4K */
+ if (size > BUF_SZ_4K)
+ cnt = BUF_SZ_4K;
+ else
+ cnt = size;
+
+ /* allocate struct lpfc_dmabufext buffer header */
+ dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL);
+ if (!dmp)
+ goto out;
+
+ INIT_LIST_HEAD(&dmp->dma.list);
+
+ /* Queue it to a linked list */
+ if (mlist)
+ list_add_tail(&dmp->dma.list, &mlist->dma.list);
+ else
+ mlist = dmp;
+
+ /* allocate buffer */
+ dmp->dma.virt = dma_alloc_coherent(&pcidev->dev,
+ cnt,
+ &(dmp->dma.phys),
+ GFP_KERNEL);
+
+ if (!dmp->dma.virt)
+ goto out;
+
+ dmp->size = cnt;
+
+ if (nocopydata) {
+ bpl->tus.f.bdeFlags = 0;
+ pci_dma_sync_single_for_device(phba->pcidev,
+ dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
+
+ } else {
+ memset((uint8_t *)dmp->dma.virt, 0, cnt);
+ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
+ }
+
+ /* build buffer ptr list for IOCB */
+ bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys));
+ bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys));
+ bpl->tus.f.bdeSize = (ushort) cnt;
+ bpl->tus.w = le32_to_cpu(bpl->tus.w);
+ bpl++;
+
+ i++;
+ offset += cnt;
+ size -= cnt;
+ }
+
+ mlist->flag = i;
+ return mlist;
+out:
+ diag_cmd_data_free(phba, mlist);
+ return NULL;
+}
+
+/**
+ * lpfcdiag_loop_post_rxbufs - post the receive buffers for an unsol CT cmd
+ * @phba: Pointer to HBA context object
+ * @rxxri: Receive exchange id
+ * @len: Number of data bytes
+ *
+ * This function allocates and posts a data buffer of sufficient size to recieve
+ * an unsolicted CT command.
+ **/
+static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri,
+ size_t len)
+{
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
+ struct lpfc_iocbq *cmdiocbq;
+ IOCB_t *cmd = NULL;
+ struct list_head head, *curr, *next;
+ struct lpfc_dmabuf *rxbmp;
+ struct lpfc_dmabuf *dmp;
+ struct lpfc_dmabuf *mp[2] = {NULL, NULL};
+ struct ulp_bde64 *rxbpl = NULL;
+ uint32_t num_bde;
+ struct lpfc_dmabufext *rxbuffer = NULL;
+ int ret_val = 0;
+ int i = 0;
+
+ cmdiocbq = lpfc_sli_get_iocbq(phba);
+ rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (rxbmp != NULL) {
+ rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
+ INIT_LIST_HEAD(&rxbmp->list);
+ rxbpl = (struct ulp_bde64 *) rxbmp->virt;
+ rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0);
+ }
+
+ if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) {
+ ret_val = ENOMEM;
+ goto err_post_rxbufs_exit;
+ }
+
+ /* Queue buffers for the receive exchange */
+ num_bde = (uint32_t)rxbuffer->flag;
+ dmp = &rxbuffer->dma;
+
+ cmd = &cmdiocbq->iocb;
+ i = 0;
+
+ INIT_LIST_HEAD(&head);
+ list_add_tail(&head, &dmp->list);
+ list_for_each_safe(curr, next, &head) {
+ mp[i] = list_entry(curr, struct lpfc_dmabuf, list);
+ list_del(curr);
+
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+ mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba);
+ cmd->un.quexri64cx.buff.bde.addrHigh =
+ putPaddrHigh(mp[i]->phys);
+ cmd->un.quexri64cx.buff.bde.addrLow =
+ putPaddrLow(mp[i]->phys);
+ cmd->un.quexri64cx.buff.bde.tus.f.bdeSize =
+ ((struct lpfc_dmabufext *)mp[i])->size;
+ cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag;
+ cmd->ulpCommand = CMD_QUE_XRI64_CX;
+ cmd->ulpPU = 0;
+ cmd->ulpLe = 1;
+ cmd->ulpBdeCount = 1;
+ cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0;
+
+ } else {
+ cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys);
+ cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys);
+ cmd->un.cont64[i].tus.f.bdeSize =
+ ((struct lpfc_dmabufext *)mp[i])->size;
+ cmd->ulpBdeCount = ++i;
+
+ if ((--num_bde > 0) && (i < 2))
+ continue;
+
+ cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX;
+ cmd->ulpLe = 1;
+ }
+
+ cmd->ulpClass = CLASS3;
+ cmd->ulpContext = rxxri;
+
+ ret_val = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0);
+
+ if (ret_val == IOCB_ERROR) {
+ diag_cmd_data_free(phba,
+ (struct lpfc_dmabufext *)mp[0]);
+ if (mp[1])
+ diag_cmd_data_free(phba,
+ (struct lpfc_dmabufext *)mp[1]);
+ dmp = list_entry(next, struct lpfc_dmabuf, list);
+ ret_val = EIO;
+ goto err_post_rxbufs_exit;
+ }
+
+ lpfc_sli_ringpostbuf_put(phba, pring, mp[0]);
+ if (mp[1]) {
+ lpfc_sli_ringpostbuf_put(phba, pring, mp[1]);
+ mp[1] = NULL;
+ }
+
+ /* The iocb was freed by lpfc_sli_issue_iocb */
+ cmdiocbq = lpfc_sli_get_iocbq(phba);
+ if (!cmdiocbq) {
+ dmp = list_entry(next, struct lpfc_dmabuf, list);
+ ret_val = EIO;
+ goto err_post_rxbufs_exit;
+ }
+
+ cmd = &cmdiocbq->iocb;
+ i = 0;
+ }
+ list_del(&head);
+
+err_post_rxbufs_exit:
+
+ if (rxbmp) {
+ if (rxbmp->virt)
+ lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys);
+ kfree(rxbmp);
+ }
+
+ if (cmdiocbq)
+ lpfc_sli_release_iocbq(phba, cmdiocbq);
+ return ret_val;
+}
+
+/**
+ * lpfc_bsg_diag_test - with a port in loopback issues a Ct cmd to itself
+ * @job: LPFC_BSG_VENDOR_DIAG_TEST fc_bsg_job
+ *
+ * This function receives a user data buffer to be transmitted and received on
+ * the same port, the link must be up and in loopback mode prior
+ * to being called.
+ * 1. A kernel buffer is allocated to copy the user data into.
+ * 2. The port registers with "itself".
+ * 3. The transmit and receive exchange ids are obtained.
+ * 4. The receive exchange id is posted.
+ * 5. A new els loopback event is created.
+ * 6. The command and response iocbs are allocated.
+ * 7. The cmd iocb FsType is set to elx loopback and the CmdRsp to looppback.
+ *
+ * This function is meant to be called n times while the port is in loopback
+ * so it is the apps responsibility to issue a reset to take the port out
+ * of loopback mode.
+ **/
+static int
+lpfc_bsg_diag_test(struct fc_bsg_job *job)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct diag_mode_test *diag_mode;
+ struct lpfc_bsg_event *evt;
+ struct event_data *evdat;
+ struct lpfc_sli *psli = &phba->sli;
+ uint32_t size;
+ uint32_t full_size;
+ size_t segment_len = 0, segment_offset = 0, current_offset = 0;
+ uint16_t rpi;
+ struct lpfc_iocbq *cmdiocbq, *rspiocbq;
+ IOCB_t *cmd, *rsp;
+ struct lpfc_sli_ct_request *ctreq;
+ struct lpfc_dmabuf *txbmp;
+ struct ulp_bde64 *txbpl = NULL;
+ struct lpfc_dmabufext *txbuffer = NULL;
+ struct list_head head;
+ struct lpfc_dmabuf *curr;
+ uint16_t txxri, rxxri;
+ uint32_t num_bde;
+ uint8_t *ptr = NULL, *rx_databuf = NULL;
+ int rc = 0;
+ unsigned long flags;
+ void *dataout = NULL;
+ uint32_t total_mem;
+
+ /* in case no data is returned return just the return code */
+ job->reply->reply_payload_rcv_len = 0;
+
+ if (job->request_len <
+ sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_test)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2739 Received DIAG TEST request below minimum "
+ "size\n");
+ rc = -EINVAL;
+ goto loopback_test_exit;
+ }
+
+ if (job->request_payload.payload_len !=
+ job->reply_payload.payload_len) {
+ rc = -EINVAL;
+ goto loopback_test_exit;
+ }
+
+ diag_mode = (struct diag_mode_test *)
+ job->request->rqst_data.h_vendor.vendor_cmd;
+
+ if ((phba->link_state == LPFC_HBA_ERROR) ||
+ (psli->sli_flag & LPFC_BLOCK_MGMT_IO) ||
+ (!(psli->sli_flag & LPFC_SLI_ACTIVE))) {
+ rc = -EACCES;
+ goto loopback_test_exit;
+ }
+
+ if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) {
+ rc = -EACCES;
+ goto loopback_test_exit;
+ }
+
+ size = job->request_payload.payload_len;
+ full_size = size + ELX_LOOPBACK_HEADER_SZ; /* plus the header */
+
+ if ((size == 0) || (size > 80 * BUF_SZ_4K)) {
+ rc = -ERANGE;
+ goto loopback_test_exit;
+ }
+
+ if (size >= BUF_SZ_4K) {
+ /*
+ * Allocate memory for ioctl data. If buffer is bigger than 64k,
+ * then we allocate 64k and re-use that buffer over and over to
+ * xfer the whole block. This is because Linux kernel has a
+ * problem allocating more than 120k of kernel space memory. Saw
+ * problem with GET_FCPTARGETMAPPING...
+ */
+ if (size <= (64 * 1024))
+ total_mem = size;
+ else
+ total_mem = 64 * 1024;
+ } else
+ /* Allocate memory for ioctl data */
+ total_mem = BUF_SZ_4K;
+
+ dataout = kmalloc(total_mem, GFP_KERNEL);
+ if (dataout == NULL) {
+ rc = -ENOMEM;
+ goto loopback_test_exit;
+ }
+
+ ptr = dataout;
+ ptr += ELX_LOOPBACK_HEADER_SZ;
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ ptr, size);
+
+ rc = lpfcdiag_loop_self_reg(phba, &rpi);
+ if (rc) {
+ rc = -ENOMEM;
+ goto loopback_test_exit;
+ }
+
+ rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri);
+ if (rc) {
+ lpfcdiag_loop_self_unreg(phba, rpi);
+ rc = -ENOMEM;
+ goto loopback_test_exit;
+ }
+
+ rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size);
+ if (rc) {
+ lpfcdiag_loop_self_unreg(phba, rpi);
+ rc = -ENOMEM;
+ goto loopback_test_exit;
+ }
+
+ evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid,
+ SLI_CT_ELX_LOOPBACK);
+ if (!evt) {
+ lpfcdiag_loop_self_unreg(phba, rpi);
+ rc = -ENOMEM;
+ goto loopback_test_exit;
+ }
+
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ list_add(&evt->node, &phba->ct_ev_waiters);
+ lpfc_bsg_event_ref(evt);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ cmdiocbq = lpfc_sli_get_iocbq(phba);
+ rspiocbq = lpfc_sli_get_iocbq(phba);
+ txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+
+ if (txbmp) {
+ txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys);
+ INIT_LIST_HEAD(&txbmp->list);
+ txbpl = (struct ulp_bde64 *) txbmp->virt;
+ if (txbpl)
+ txbuffer = diag_cmd_data_alloc(phba,
+ txbpl, full_size, 0);
+ }
+
+ if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer) {
+ rc = -ENOMEM;
+ goto err_loopback_test_exit;
+ }
+
+ cmd = &cmdiocbq->iocb;
+ rsp = &rspiocbq->iocb;
+
+ INIT_LIST_HEAD(&head);
+ list_add_tail(&head, &txbuffer->dma.list);
+ list_for_each_entry(curr, &head, list) {
+ segment_len = ((struct lpfc_dmabufext *)curr)->size;
+ if (current_offset == 0) {
+ ctreq = curr->virt;
+ memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ);
+ ctreq->RevisionId.bits.Revision = SLI_CT_REVISION;
+ ctreq->RevisionId.bits.InId = 0;
+ ctreq->FsType = SLI_CT_ELX_LOOPBACK;
+ ctreq->FsSubType = 0;
+ ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA;
+ ctreq->CommandResponse.bits.Size = size;
+ segment_offset = ELX_LOOPBACK_HEADER_SZ;
+ } else
+ segment_offset = 0;
+
+ BUG_ON(segment_offset >= segment_len);
+ memcpy(curr->virt + segment_offset,
+ ptr + current_offset,
+ segment_len - segment_offset);
+
+ current_offset += segment_len - segment_offset;
+ BUG_ON(current_offset > size);
+ }
+ list_del(&head);
+
+ /* Build the XMIT_SEQUENCE iocb */
+
+ num_bde = (uint32_t)txbuffer->flag;
+
+ cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys);
+ cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys);
+ cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
+ cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64));
+
+ cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA);
+ cmd->un.xseq64.w5.hcsw.Dfctl = 0;
+ cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
+ cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT;
+
+ cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX;
+ cmd->ulpBdeCount = 1;
+ cmd->ulpLe = 1;
+ cmd->ulpClass = CLASS3;
+ cmd->ulpContext = txxri;
+
+ cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
+ cmdiocbq->vport = phba->pport;
+
+ rc = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq,
+ (phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT);
+
+ if ((rc != IOCB_SUCCESS) || (rsp->ulpStatus != IOCB_SUCCESS)) {
+ rc = -EIO;
+ goto err_loopback_test_exit;
+ }
+
+ evt->waiting = 1;
+ rc = wait_event_interruptible_timeout(
+ evt->wq, !list_empty(&evt->events_to_see),
+ ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ);
+ evt->waiting = 0;
+ if (list_empty(&evt->events_to_see))
+ rc = (rc) ? -EINTR : -ETIMEDOUT;
+ else {
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ list_move(evt->events_to_see.prev, &evt->events_to_get);
+ evdat = list_entry(evt->events_to_get.prev,
+ typeof(*evdat), node);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ rx_databuf = evdat->data;
+ if (evdat->len != full_size) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+ "1603 Loopback test did not receive expected "
+ "data length. actual length 0x%x expected "
+ "length 0x%x\n",
+ evdat->len, full_size);
+ rc = -EIO;
+ } else if (rx_databuf == NULL)
+ rc = -EIO;
+ else {
+ rc = IOCB_SUCCESS;
+ /* skip over elx loopback header */
+ rx_databuf += ELX_LOOPBACK_HEADER_SZ;
+ job->reply->reply_payload_rcv_len =
+ sg_copy_from_buffer(job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt,
+ rx_databuf, size);
+ job->reply->reply_payload_rcv_len = size;
+ }
+ }
+
+err_loopback_test_exit:
+ lpfcdiag_loop_self_unreg(phba, rpi);
+
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ lpfc_bsg_event_unref(evt); /* release ref */
+ lpfc_bsg_event_unref(evt); /* delete */
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ if (cmdiocbq != NULL)
+ lpfc_sli_release_iocbq(phba, cmdiocbq);
+
+ if (rspiocbq != NULL)
+ lpfc_sli_release_iocbq(phba, rspiocbq);
+
+ if (txbmp != NULL) {
+ if (txbpl != NULL) {
+ if (txbuffer != NULL)
+ diag_cmd_data_free(phba, txbuffer);
+ lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys);
+ }
+ kfree(txbmp);
+ }
+
+loopback_test_exit:
+ kfree(dataout);
+ /* make error code available to userspace */
+ job->reply->result = rc;
+ job->dd_data = NULL;
+ /* complete the job back to userspace if no error */
+ if (rc == 0)
+ job->job_done(job);
+ return rc;
+}
+
+/**
+ * lpfc_bsg_get_dfc_rev - process a GET_DFC_REV bsg vendor command
+ * @job: GET_DFC_REV fc_bsg_job
+ **/
+static int
+lpfc_bsg_get_dfc_rev(struct fc_bsg_job *job)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct get_mgmt_rev *event_req;
+ struct get_mgmt_rev_reply *event_reply;
+ int rc = 0;
+
+ if (job->request_len <
+ sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2740 Received GET_DFC_REV request below "
+ "minimum size\n");
+ rc = -EINVAL;
+ goto job_error;
+ }
+
+ event_req = (struct get_mgmt_rev *)
+ job->request->rqst_data.h_vendor.vendor_cmd;
+
+ event_reply = (struct get_mgmt_rev_reply *)
+ job->reply->reply_data.vendor_reply.vendor_rsp;
+
+ if (job->reply_len <
+ sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev_reply)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2741 Received GET_DFC_REV reply below "
+ "minimum size\n");
+ rc = -EINVAL;
+ goto job_error;
+ }
+
+ event_reply->info.a_Major = MANAGEMENT_MAJOR_REV;
+ event_reply->info.a_Minor = MANAGEMENT_MINOR_REV;
+job_error:
+ job->reply->result = rc;
+ if (rc == 0)
+ job->job_done(job);
+ return rc;
+}
+
+/**
+ * lpfc_bsg_wake_mbox_wait - lpfc_bsg_issue_mbox mbox completion handler
+ * @phba: Pointer to HBA context object.
+ * @pmboxq: Pointer to mailbox command.
+ *
+ * This is completion handler function for mailbox commands issued from
+ * lpfc_bsg_issue_mbox function. This function is called by the
+ * mailbox event handler function with no lock held. This function
+ * will wake up thread waiting on the wait queue pointed by context1
+ * of the mailbox.
+ **/
+void
+lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
+{
+ struct bsg_job_data *dd_data;
+ MAILBOX_t *pmb;
+ MAILBOX_t *mb;
+ struct fc_bsg_job *job;
+ uint32_t size;
+ unsigned long flags;
+
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ dd_data = pmboxq->context1;
+ if (!dd_data) {
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ return;
+ }
+
+ pmb = &dd_data->context_un.mbox.pmboxq->u.mb;
+ mb = dd_data->context_un.mbox.mb;
+ job = dd_data->context_un.mbox.set_job;
+ memcpy(mb, pmb, sizeof(*pmb));
+ size = job->request_payload.payload_len;
+ job->reply->reply_payload_rcv_len =
+ sg_copy_from_buffer(job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt,
+ mb, size);
+ job->reply->result = 0;
+ dd_data->context_un.mbox.set_job = NULL;
+ job->dd_data = NULL;
+ job->job_done(job);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool);
+ kfree(mb);
+ kfree(dd_data);
+ return;
+}
+
+/**
+ * lpfc_bsg_check_cmd_access - test for a supported mailbox command
+ * @phba: Pointer to HBA context object.
+ * @mb: Pointer to a mailbox object.
+ * @vport: Pointer to a vport object.
+ *
+ * Some commands require the port to be offline, some may not be called from
+ * the application.
+ **/
+static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
+ MAILBOX_t *mb, struct lpfc_vport *vport)
+{
+ /* return negative error values for bsg job */
+ switch (mb->mbxCommand) {
+ /* Offline only */
+ case MBX_INIT_LINK:
+ case MBX_DOWN_LINK:
+ case MBX_CONFIG_LINK:
+ case MBX_CONFIG_RING:
+ case MBX_RESET_RING:
+ case MBX_UNREG_LOGIN:
+ case MBX_CLEAR_LA:
+ case MBX_DUMP_CONTEXT:
+ case MBX_RUN_DIAGS:
+ case MBX_RESTART:
+ case MBX_SET_MASK:
+ if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2743 Command 0x%x is illegal in on-line "
+ "state\n",
+ mb->mbxCommand);
+ return -EPERM;
+ }
+ case MBX_WRITE_NV:
+ case MBX_WRITE_VPARMS:
+ case MBX_LOAD_SM:
+ case MBX_READ_NV:
+ case MBX_READ_CONFIG:
+ case MBX_READ_RCONFIG:
+ case MBX_READ_STATUS:
+ case MBX_READ_XRI:
+ case MBX_READ_REV:
+ case MBX_READ_LNK_STAT:
+ case MBX_DUMP_MEMORY:
+ case MBX_DOWN_LOAD:
+ case MBX_UPDATE_CFG:
+ case MBX_KILL_BOARD:
+ case MBX_LOAD_AREA:
+ case MBX_LOAD_EXP_ROM:
+ case MBX_BEACON:
+ case MBX_DEL_LD_ENTRY:
+ case MBX_SET_DEBUG:
+ case MBX_WRITE_WWN:
+ case MBX_SLI4_CONFIG:
+ case MBX_READ_EVENT_LOG_STATUS:
+ case MBX_WRITE_EVENT_LOG:
+ case MBX_PORT_CAPABILITIES:
+ case MBX_PORT_IOV_CONTROL:
+ break;
+ case MBX_SET_VARIABLE:
+ case MBX_RUN_BIU_DIAG64:
+ case MBX_READ_EVENT_LOG:
+ case MBX_READ_SPARM64:
+ case MBX_READ_LA:
+ case MBX_READ_LA64:
+ case MBX_REG_LOGIN:
+ case MBX_REG_LOGIN64:
+ case MBX_CONFIG_PORT:
+ case MBX_RUN_BIU_DIAG:
+ default:
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2742 Unknown Command 0x%x\n",
+ mb->mbxCommand);
+ return -EPERM;
+ }
+
+ return 0; /* ok */
+}
+
+/**
+ * lpfc_bsg_issue_mbox - issues a mailbox command on behalf of an app
+ * @phba: Pointer to HBA context object.
+ * @mb: Pointer to a mailbox object.
+ * @vport: Pointer to a vport object.
+ *
+ * Allocate a tracking object, mailbox command memory, get a mailbox
+ * from the mailbox pool, copy the caller mailbox command.
+ *
+ * If offline and the sli is active we need to poll for the command (port is
+ * being reset) and com-plete the job, otherwise issue the mailbox command and
+ * let our completion handler finish the command.
+ **/
+static uint32_t
+lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
+ struct lpfc_vport *vport)
+{
+ LPFC_MBOXQ_t *pmboxq;
+ MAILBOX_t *pmb;
+ MAILBOX_t *mb;
+ struct bsg_job_data *dd_data;
+ uint32_t size;
+ int rc = 0;
+
+ /* allocate our bsg tracking structure */
+ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
+ if (!dd_data) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2727 Failed allocation of dd_data\n");
+ return -ENOMEM;
+ }
+
+ mb = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!mb) {
+ kfree(dd_data);
+ return -ENOMEM;
+ }
+
+ pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmboxq) {
+ kfree(dd_data);
+ kfree(mb);
+ return -ENOMEM;
+ }
+
+ size = job->request_payload.payload_len;
+ job->reply->reply_payload_rcv_len =
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ mb, size);
+
+ rc = lpfc_bsg_check_cmd_access(phba, mb, vport);
+ if (rc != 0) {
+ kfree(dd_data);
+ kfree(mb);
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ return rc; /* must be negative */
+ }
+
+ memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
+ pmb = &pmboxq->u.mb;
+ memcpy(pmb, mb, sizeof(*pmb));
+ pmb->mbxOwner = OWN_HOST;
+ pmboxq->context1 = NULL;
+ pmboxq->vport = vport;
+
+ if ((vport->fc_flag & FC_OFFLINE_MODE) ||
+ (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) {
+ rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
+ if (rc != MBX_SUCCESS) {
+ if (rc != MBX_TIMEOUT) {
+ kfree(dd_data);
+ kfree(mb);
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ }
+ return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
+ }
+
+ memcpy(mb, pmb, sizeof(*pmb));
+ job->reply->reply_payload_rcv_len =
+ sg_copy_from_buffer(job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt,
+ mb, size);
+ kfree(dd_data);
+ kfree(mb);
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ /* not waiting mbox already done */
+ return 0;
+ }
+
+ /* setup wake call as IOCB callback */
+ pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait;
+ /* setup context field to pass wait_queue pointer to wake function */
+ pmboxq->context1 = dd_data;
+ dd_data->type = TYPE_MBOX;
+ dd_data->context_un.mbox.pmboxq = pmboxq;
+ dd_data->context_un.mbox.mb = mb;
+ dd_data->context_un.mbox.set_job = job;
+ job->dd_data = dd_data;
+ rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
+ if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
+ kfree(dd_data);
+ kfree(mb);
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ return -EIO;
+ }
+
+ return 1;
+}
+
+/**
+ * lpfc_bsg_mbox_cmd - process an fc bsg LPFC_BSG_VENDOR_MBOX command
+ * @job: MBOX fc_bsg_job for LPFC_BSG_VENDOR_MBOX.
+ **/
+static int
+lpfc_bsg_mbox_cmd(struct fc_bsg_job *job)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ int rc = 0;
+
+ /* in case no data is transferred */
+ job->reply->reply_payload_rcv_len = 0;
+ if (job->request_len <
+ sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2737 Received MBOX_REQ request below "
+ "minimum size\n");
+ rc = -EINVAL;
+ goto job_error;
+ }
+
+ if (job->request_payload.payload_len != PAGE_SIZE) {
+ rc = -EINVAL;
+ goto job_error;
+ }
+
+ if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
+ rc = -EAGAIN;
+ goto job_error;
+ }
+
+ rc = lpfc_bsg_issue_mbox(phba, job, vport);
+
+job_error:
+ if (rc == 0) {
+ /* job done */
+ job->reply->result = 0;
+ job->dd_data = NULL;
+ job->job_done(job);
+ } else if (rc == 1)
+ /* job submitted, will complete later*/
+ rc = 0; /* return zero, no error */
+ else {
+ /* some error occurred */
+ job->reply->result = rc;
+ job->dd_data = NULL;
+ }
return rc;
}
@@ -834,38 +2640,57 @@ error_get_event_exit:
/**
* lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job
* @job: fc_bsg_job to handle
- */
+ **/
static int
lpfc_bsg_hst_vendor(struct fc_bsg_job *job)
{
int command = job->request->rqst_data.h_vendor.vendor_cmd[0];
+ int rc;
switch (command) {
case LPFC_BSG_VENDOR_SET_CT_EVENT:
- return lpfc_bsg_set_event(job);
+ rc = lpfc_bsg_hba_set_event(job);
break;
-
case LPFC_BSG_VENDOR_GET_CT_EVENT:
- return lpfc_bsg_get_event(job);
+ rc = lpfc_bsg_hba_get_event(job);
+ break;
+ case LPFC_BSG_VENDOR_SEND_MGMT_RESP:
+ rc = lpfc_bsg_send_mgmt_rsp(job);
+ break;
+ case LPFC_BSG_VENDOR_DIAG_MODE:
+ rc = lpfc_bsg_diag_mode(job);
+ break;
+ case LPFC_BSG_VENDOR_DIAG_TEST:
+ rc = lpfc_bsg_diag_test(job);
+ break;
+ case LPFC_BSG_VENDOR_GET_MGMT_REV:
+ rc = lpfc_bsg_get_dfc_rev(job);
+ break;
+ case LPFC_BSG_VENDOR_MBOX:
+ rc = lpfc_bsg_mbox_cmd(job);
break;
-
default:
- return -EINVAL;
+ rc = -EINVAL;
+ job->reply->reply_payload_rcv_len = 0;
+ /* make error code available to userspace */
+ job->reply->result = rc;
+ break;
}
+
+ return rc;
}
/**
* lpfc_bsg_request - handle a bsg request from the FC transport
* @job: fc_bsg_job to handle
- */
+ **/
int
lpfc_bsg_request(struct fc_bsg_job *job)
{
uint32_t msgcode;
- int rc = -EINVAL;
+ int rc;
msgcode = job->request->msgcode;
-
switch (msgcode) {
case FC_BSG_HST_VENDOR:
rc = lpfc_bsg_hst_vendor(job);
@@ -874,9 +2699,13 @@ lpfc_bsg_request(struct fc_bsg_job *job)
rc = lpfc_bsg_rport_els(job);
break;
case FC_BSG_RPT_CT:
- rc = lpfc_bsg_rport_ct(job);
+ rc = lpfc_bsg_send_mgmt_cmd(job);
break;
default:
+ rc = -EINVAL;
+ job->reply->reply_payload_rcv_len = 0;
+ /* make error code available to userspace */
+ job->reply->result = rc;
break;
}
@@ -889,17 +2718,71 @@ lpfc_bsg_request(struct fc_bsg_job *job)
*
* This function just aborts the job's IOCB. The aborted IOCB will return to
* the waiting function which will handle passing the error back to userspace
- */
+ **/
int
lpfc_bsg_timeout(struct fc_bsg_job *job)
{
struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)job->dd_data;
+ struct lpfc_iocbq *cmdiocb;
+ struct lpfc_bsg_event *evt;
+ struct lpfc_bsg_iocb *iocb;
+ struct lpfc_bsg_mbox *mbox;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ struct bsg_job_data *dd_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ dd_data = (struct bsg_job_data *)job->dd_data;
+ /* timeout and completion crossed paths if no dd_data */
+ if (!dd_data) {
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ return 0;
+ }
- if (cmdiocb)
+ switch (dd_data->type) {
+ case TYPE_IOCB:
+ iocb = &dd_data->context_un.iocb;
+ cmdiocb = iocb->cmdiocbq;
+ /* hint to completion handler that the job timed out */
+ job->reply->result = -EAGAIN;
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ /* this will call our completion handler */
+ spin_lock_irq(&phba->hbalock);
lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
+ spin_unlock_irq(&phba->hbalock);
+ break;
+ case TYPE_EVT:
+ evt = dd_data->context_un.evt;
+ /* this event has no job anymore */
+ evt->set_job = NULL;
+ job->dd_data = NULL;
+ job->reply->reply_payload_rcv_len = 0;
+ /* Return -EAGAIN which is our way of signallying the
+ * app to retry.
+ */
+ job->reply->result = -EAGAIN;
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ job->job_done(job);
+ break;
+ case TYPE_MBOX:
+ mbox = &dd_data->context_un.mbox;
+ /* this mbox has no job anymore */
+ mbox->set_job = NULL;
+ job->dd_data = NULL;
+ job->reply->reply_payload_rcv_len = 0;
+ job->reply->result = -EAGAIN;
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ job->job_done(job);
+ break;
+ default:
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ break;
+ }
+ /* scsi transport fc fc_bsg_job_timeout expects a zero return code,
+ * otherwise an error message will be displayed on the console
+ * so always return success (zero)
+ */
return 0;
}
diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h
new file mode 100644
index 000000000000..6c8f87e39b98
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_bsg.h
@@ -0,0 +1,98 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for *
+ * Fibre Channel Host Bus Adapters. *
+ * Copyright (C) 2010 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *******************************************************************/
+/* bsg definitions
+ * No pointers to user data are allowed, all application buffers and sizes will
+ * derived through the bsg interface.
+ *
+ * These are the vendor unique structures passed in using the bsg
+ * FC_BSG_HST_VENDOR message code type.
+ */
+#define LPFC_BSG_VENDOR_SET_CT_EVENT 1
+#define LPFC_BSG_VENDOR_GET_CT_EVENT 2
+#define LPFC_BSG_VENDOR_SEND_MGMT_RESP 3
+#define LPFC_BSG_VENDOR_DIAG_MODE 4
+#define LPFC_BSG_VENDOR_DIAG_TEST 5
+#define LPFC_BSG_VENDOR_GET_MGMT_REV 6
+#define LPFC_BSG_VENDOR_MBOX 7
+
+struct set_ct_event {
+ uint32_t command;
+ uint32_t type_mask;
+ uint32_t ev_req_id;
+ uint32_t ev_reg_id;
+};
+
+struct get_ct_event {
+ uint32_t command;
+ uint32_t ev_reg_id;
+ uint32_t ev_req_id;
+};
+
+struct get_ct_event_reply {
+ uint32_t immed_data;
+ uint32_t type;
+};
+
+struct send_mgmt_resp {
+ uint32_t command;
+ uint32_t tag;
+};
+
+
+#define INTERNAL_LOOP_BACK 0x1 /* adapter short cuts the loop internally */
+#define EXTERNAL_LOOP_BACK 0x2 /* requires an external loopback plug */
+
+struct diag_mode_set {
+ uint32_t command;
+ uint32_t type;
+ uint32_t timeout;
+};
+
+struct diag_mode_test {
+ uint32_t command;
+};
+
+#define LPFC_WWNN_TYPE 0
+#define LPFC_WWPN_TYPE 1
+
+struct get_mgmt_rev {
+ uint32_t command;
+};
+
+#define MANAGEMENT_MAJOR_REV 1
+#define MANAGEMENT_MINOR_REV 0
+
+/* the MgmtRevInfo structure */
+struct MgmtRevInfo {
+ uint32_t a_Major;
+ uint32_t a_Minor;
+};
+
+struct get_mgmt_rev_reply {
+ struct MgmtRevInfo info;
+};
+
+struct dfc_mbox_req {
+ uint32_t command;
+ uint32_t inExtWLen;
+ uint32_t outExtWLen;
+ uint8_t mbOffset;
+};
+
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 650494d622c1..6f0fb51eb461 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2008 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2010 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -44,18 +44,26 @@ int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *);
+void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *,
+ struct lpfc_nodelist *);
void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *);
void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *);
+void lpfc_supported_pages(struct lpfcMboxq *);
+void lpfc_sli4_params(struct lpfcMboxq *);
+int lpfc_pc_sli4_params_get(struct lpfc_hba *, LPFC_MBOXQ_t *);
struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
void lpfc_cleanup_rcv_buffers(struct lpfc_vport *);
void lpfc_rcv_seq_check_edtov(struct lpfc_vport *);
void lpfc_cleanup_rpis(struct lpfc_vport *, int);
+void lpfc_cleanup_pending_mbox(struct lpfc_vport *);
int lpfc_linkdown(struct lpfc_hba *);
void lpfc_linkdown_port(struct lpfc_vport *);
void lpfc_port_link_failure(struct lpfc_vport *);
void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_retry_pport_discovery(struct lpfc_hba *);
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -73,6 +81,7 @@ void lpfc_set_disctmo(struct lpfc_vport *);
int lpfc_can_disctmo(struct lpfc_vport *);
int lpfc_unreg_rpi(struct lpfc_vport *, struct lpfc_nodelist *);
void lpfc_unreg_all_rpis(struct lpfc_vport *);
+void lpfc_unreg_hba_rpis(struct lpfc_hba *);
void lpfc_unreg_default_rpis(struct lpfc_vport *);
void lpfc_issue_reg_vpi(struct lpfc_hba *, struct lpfc_vport *);
@@ -99,7 +108,7 @@ int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *,
void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
- struct serv_parm *, uint32_t);
+ struct serv_parm *, uint32_t, int);
int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
void lpfc_more_plogi(struct lpfc_vport *);
void lpfc_more_adisc(struct lpfc_vport *);
@@ -197,6 +206,7 @@ void lpfc_reg_fcfi(struct lpfc_hba *, struct lpfcMboxq *);
void lpfc_unreg_fcfi(struct lpfcMboxq *, uint16_t);
void lpfc_resume_rpi(struct lpfcMboxq *, struct lpfc_nodelist *);
int lpfc_check_pending_fcoe_event(struct lpfc_hba *, uint8_t);
+void lpfc_issue_init_vpi(struct lpfc_vport *);
void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *,
uint32_t , LPFC_MBOXQ_t *);
@@ -206,7 +216,11 @@ struct hbq_dmabuf *lpfc_sli4_rb_alloc(struct lpfc_hba *);
void lpfc_sli4_rb_free(struct lpfc_hba *, struct hbq_dmabuf *);
void lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *, struct fcf_record *,
uint16_t);
+void lpfc_unregister_fcf(struct lpfc_hba *);
+void lpfc_unregister_fcf_rescan(struct lpfc_hba *);
void lpfc_unregister_unused_fcf(struct lpfc_hba *);
+int lpfc_sli4_redisc_fcf_table(struct lpfc_hba *);
+void lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *);
int lpfc_mem_alloc(struct lpfc_hba *, int align);
void lpfc_mem_free(struct lpfc_hba *);
@@ -365,6 +379,8 @@ void lpfc_free_fast_evt(struct lpfc_hba *, struct lpfc_fast_path_event *);
void lpfc_create_static_vport(struct lpfc_hba *);
void lpfc_stop_hba_timers(struct lpfc_hba *);
void lpfc_stop_port(struct lpfc_hba *);
+void __lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *);
+void lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *);
void lpfc_parse_fcoe_conf(struct lpfc_hba *, uint8_t *, uint32_t);
int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
void lpfc_start_fdiscs(struct lpfc_hba *phba);
@@ -378,5 +394,5 @@ struct lpfc_vport *lpfc_find_vport_by_vpid(struct lpfc_hba *, uint16_t);
/* functions to support SGIOv4/bsg interface */
int lpfc_bsg_request(struct fc_bsg_job *);
int lpfc_bsg_timeout(struct fc_bsg_job *);
-void lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
+int lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 0ebcd9baca79..c7e921973f66 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2009 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2010 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -97,7 +97,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct list_head head;
struct lpfc_dmabuf *bdeBuf;
- lpfc_bsg_ct_unsol_event(phba, pring, piocbq);
+ if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0)
+ return;
if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
@@ -181,7 +182,8 @@ lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *phba,
uint32_t size;
/* Forward abort event to any process registered to receive ct event */
- lpfc_bsg_ct_unsol_event(phba, pring, piocbq);
+ if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0)
+ return;
/* If there is no BDE associated with IOCB, there is nothing to do */
if (icmd->ulpBdeCount == 0)
@@ -1843,12 +1845,7 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
c = (rev & 0x0000ff00) >> 8;
b4 = (rev & 0x000000ff);
- if (flag)
- sprintf(fwrevision, "%d.%d%d%c%d ", b1,
- b2, b3, c, b4);
- else
- sprintf(fwrevision, "%d.%d%d%c%d ", b1,
- b2, b3, c, b4);
+ sprintf(fwrevision, "%d.%d%d%c%d", b1, b2, b3, c, b4);
}
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 2cc39684ce97..2a40a6eabf4d 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -50,9 +50,6 @@ static int lpfc_issue_els_fdisc(struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp, uint8_t retry);
static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba,
struct lpfc_iocbq *iocb);
-static void lpfc_register_new_vport(struct lpfc_hba *phba,
- struct lpfc_vport *vport,
- struct lpfc_nodelist *ndlp);
static int lpfc_max_els_tries = 3;
@@ -592,6 +589,15 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
spin_unlock_irq(shost->host_lock);
}
+ /*
+ * If VPI is unreged, driver need to do INIT_VPI
+ * before re-registering
+ */
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
+ spin_unlock_irq(shost->host_lock);
+ }
}
if (phba->sli_rev < LPFC_SLI_REV4) {
@@ -604,10 +610,13 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
} else {
ndlp->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
- if (vport->vpi_state & LPFC_VPI_REGISTERED) {
+ if ((!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) &&
+ (vport->vpi_state & LPFC_VPI_REGISTERED)) {
lpfc_start_fdiscs(phba);
lpfc_do_scr_ns_plogi(phba, vport);
- } else
+ } else if (vport->fc_flag & FC_VFI_REGISTERED)
+ lpfc_issue_init_vpi(vport);
+ else
lpfc_issue_reg_vfi(vport);
}
return 0;
@@ -804,6 +813,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
irsp->ulpTimeout);
goto flogifail;
}
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
+ spin_unlock_irq(shost->host_lock);
/*
* The FLogI succeeded. Sync the data for the CPU before
@@ -969,7 +981,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
* function returns, it does not guarantee all the IOCBs are actually aborted.
*
* Return code
- * 0 - Sucessfully issued abort iocb on all outstanding flogis (Always 0)
+ * 0 - Successfully issued abort iocb on all outstanding flogis (Always 0)
**/
int
lpfc_els_abort_flogi(struct lpfc_hba *phba)
@@ -2720,7 +2732,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (did == FDMI_DID)
retry = 1;
- if ((cmd == ELS_CMD_FLOGI) &&
+ if (((cmd == ELS_CMD_FLOGI) || (cmd == ELS_CMD_FDISC)) &&
(phba->fc_topology != TOPOLOGY_LOOP) &&
!lpfc_error_lost_link(irsp)) {
/* FLOGI retry policy */
@@ -3117,7 +3129,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (ndlp && NLP_CHK_NODE_ACT(ndlp) &&
(*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) {
/* A LS_RJT associated with Default RPI cleanup has its own
- * seperate code path.
+ * separate code path.
*/
if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI))
ls_rjt = 1;
@@ -4385,7 +4397,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
did = Fabric_DID;
- if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) {
+ if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) {
/* For a FLOGI we accept, then if our portname is greater
* then the remote portname we initiate Nport login.
*/
@@ -5915,6 +5927,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
MAILBOX_t *mb = &pmb->u.mb;
+ int rc;
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
@@ -5936,6 +5949,26 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
spin_unlock_irq(shost->host_lock);
lpfc_can_disctmo(vport);
break;
+ /* If reg_vpi fail with invalid VPI status, re-init VPI */
+ case 0x20:
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_init_vpi(phba, pmb, vport->vpi);
+ pmb->vport = vport;
+ pmb->mbox_cmpl = lpfc_init_vpi_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, pmb,
+ MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_printf_vlog(vport,
+ KERN_ERR, LOG_MBOX,
+ "2732 Failed to issue INIT_VPI"
+ " mailbox command\n");
+ } else {
+ lpfc_nlp_put(ndlp);
+ return;
+ }
+
default:
/* Try to recover from this error */
lpfc_mbx_unreg_vpi(vport);
@@ -5949,13 +5982,17 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
break;
}
} else {
+ spin_lock_irq(shost->host_lock);
vport->vpi_state |= LPFC_VPI_REGISTERED;
- if (vport == phba->pport)
+ spin_unlock_irq(shost->host_lock);
+ if (vport == phba->pport) {
if (phba->sli_rev < LPFC_SLI_REV4)
lpfc_issue_fabric_reglogin(vport);
- else
- lpfc_issue_reg_vfi(vport);
- else
+ else {
+ lpfc_start_fdiscs(phba);
+ lpfc_do_scr_ns_plogi(phba, vport);
+ }
+ } else
lpfc_do_scr_ns_plogi(phba, vport);
}
@@ -5977,7 +6014,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
* This routine registers the @vport as a new virtual port with a HBA.
* It is done through a registering vpi mailbox command.
**/
-static void
+void
lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp)
{
@@ -6018,6 +6055,78 @@ mbox_err_exit:
}
/**
+ * lpfc_retry_pport_discovery - Start timer to retry FLOGI.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine abort all pending discovery commands and
+ * start a timer to retry FLOGI for the physical port
+ * discovery.
+ **/
+void
+lpfc_retry_pport_discovery(struct lpfc_hba *phba)
+{
+ struct lpfc_vport **vports;
+ struct lpfc_nodelist *ndlp;
+ struct Scsi_Host *shost;
+ int i;
+ uint32_t link_state;
+
+ /* Treat this failure as linkdown for all vports */
+ link_state = phba->link_state;
+ lpfc_linkdown(phba);
+ phba->link_state = link_state;
+
+ vports = lpfc_create_vport_work_array(phba);
+
+ if (vports) {
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+ ndlp = lpfc_findnode_did(vports[i], Fabric_DID);
+ if (ndlp)
+ lpfc_cancel_retry_delay_tmo(vports[i], ndlp);
+ lpfc_els_flush_cmd(vports[i]);
+ }
+ lpfc_destroy_vport_work_array(phba, vports);
+ }
+
+ /* If fabric require FLOGI, then re-instantiate physical login */
+ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+ if (!ndlp)
+ return;
+
+
+ shost = lpfc_shost_from_vport(phba->pport);
+ mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_DELAY_TMO;
+ spin_unlock_irq(shost->host_lock);
+ ndlp->nlp_last_elscmd = ELS_CMD_FLOGI;
+ phba->pport->port_state = LPFC_FLOGI;
+ return;
+}
+
+/**
+ * lpfc_fabric_login_reqd - Check if FLOGI required.
+ * @phba: pointer to lpfc hba data structure.
+ * @cmdiocb: pointer to FDISC command iocb.
+ * @rspiocb: pointer to FDISC response iocb.
+ *
+ * This routine checks if a FLOGI is reguired for FDISC
+ * to succeed.
+ **/
+static int
+lpfc_fabric_login_reqd(struct lpfc_hba *phba,
+ struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+
+ if ((rspiocb->iocb.ulpStatus != IOSTAT_FABRIC_RJT) ||
+ (rspiocb->iocb.un.ulpWord[4] != RJT_LOGIN_REQUIRED))
+ return 0;
+ else
+ return 1;
+}
+
+/**
* lpfc_cmpl_els_fdisc - Completion function for fdisc iocb command
* @phba: pointer to lpfc hba data structure.
* @cmdiocb: pointer to lpfc command iocb data structure.
@@ -6066,6 +6175,12 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
if (irsp->ulpStatus) {
+
+ if (lpfc_fabric_login_reqd(phba, cmdiocb, rspiocb)) {
+ lpfc_retry_pport_discovery(phba);
+ goto out;
+ }
+
/* Check for retry */
if (lpfc_els_retry(phba, cmdiocb, rspiocb))
goto out;
@@ -6076,6 +6191,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
goto fdisc_failed;
}
spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
vport->fc_flag |= FC_FABRIC;
if (vport->phba->fc_topology == TOPOLOGY_LOOP)
vport->fc_flag |= FC_PUBLIC_LOOP;
@@ -6103,10 +6219,13 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_mbx_unreg_vpi(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
spin_unlock_irq(shost->host_lock);
}
- if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
+ if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI)
+ lpfc_issue_init_vpi(vport);
+ else if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
lpfc_register_new_vport(phba, vport, ndlp);
else
lpfc_do_scr_ns_plogi(phba, vport);
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 2445e399fd60..2359d0bfb734 100755..100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -525,6 +525,8 @@ lpfc_work_done(struct lpfc_hba *phba)
spin_unlock_irq(&phba->hbalock);
lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
}
+ if (phba->fcf.fcf_flag & FCF_REDISC_EVT)
+ lpfc_sli4_fcf_redisc_event_proc(phba);
}
vports = lpfc_create_vport_work_array(phba);
@@ -706,6 +708,8 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
void
lpfc_port_link_failure(struct lpfc_vport *vport)
{
+ lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
+
/* Cleanup any outstanding received buffers */
lpfc_cleanup_rcv_buffers(vport);
@@ -752,12 +756,14 @@ lpfc_linkdown(struct lpfc_hba *phba)
lpfc_scsi_dev_block(phba);
spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_DISCOVERED);
+ phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE);
+ spin_unlock_irq(&phba->hbalock);
if (phba->link_state > LPFC_LINK_DOWN) {
phba->link_state = LPFC_LINK_DOWN;
+ spin_lock_irq(shost->host_lock);
phba->pport->fc_flag &= ~FC_LBIT;
+ spin_unlock_irq(shost->host_lock);
}
- spin_unlock_irq(&phba->hbalock);
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
@@ -1023,7 +1029,7 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
return;
}
spin_lock_irqsave(&phba->hbalock, flags);
- phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
+ phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE);
phba->hba_flag &= ~FCF_DISC_INPROGRESS;
spin_unlock_irqrestore(&phba->hbalock, flags);
if (vport->port_state != LPFC_FLOGI)
@@ -1045,25 +1051,23 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
static uint32_t
lpfc_fab_name_match(uint8_t *fab_name, struct fcf_record *new_fcf_record)
{
- if ((fab_name[0] ==
- bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record)) &&
- (fab_name[1] ==
- bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record)) &&
- (fab_name[2] ==
- bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record)) &&
- (fab_name[3] ==
- bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record)) &&
- (fab_name[4] ==
- bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record)) &&
- (fab_name[5] ==
- bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record)) &&
- (fab_name[6] ==
- bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record)) &&
- (fab_name[7] ==
- bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record)))
- return 1;
- else
+ if (fab_name[0] != bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record))
+ return 0;
+ if (fab_name[1] != bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record))
+ return 0;
+ if (fab_name[2] != bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record))
return 0;
+ if (fab_name[3] != bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record))
+ return 0;
+ if (fab_name[4] != bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record))
+ return 0;
+ if (fab_name[5] != bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record))
+ return 0;
+ if (fab_name[6] != bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record))
+ return 0;
+ if (fab_name[7] != bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record))
+ return 0;
+ return 1;
}
/**
@@ -1078,30 +1082,28 @@ lpfc_fab_name_match(uint8_t *fab_name, struct fcf_record *new_fcf_record)
static uint32_t
lpfc_sw_name_match(uint8_t *sw_name, struct fcf_record *new_fcf_record)
{
- if ((sw_name[0] ==
- bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record)) &&
- (sw_name[1] ==
- bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record)) &&
- (sw_name[2] ==
- bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record)) &&
- (sw_name[3] ==
- bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record)) &&
- (sw_name[4] ==
- bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record)) &&
- (sw_name[5] ==
- bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record)) &&
- (sw_name[6] ==
- bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record)) &&
- (sw_name[7] ==
- bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record)))
- return 1;
- else
+ if (sw_name[0] != bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record))
return 0;
+ if (sw_name[1] != bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record))
+ return 0;
+ if (sw_name[2] != bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record))
+ return 0;
+ if (sw_name[3] != bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record))
+ return 0;
+ if (sw_name[4] != bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record))
+ return 0;
+ if (sw_name[5] != bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record))
+ return 0;
+ if (sw_name[6] != bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record))
+ return 0;
+ if (sw_name[7] != bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record))
+ return 0;
+ return 1;
}
/**
* lpfc_mac_addr_match - Check if the fcf mac address match.
- * @phba: pointer to lpfc hba data structure.
+ * @mac_addr: pointer to mac address.
* @new_fcf_record: pointer to fcf record.
*
* This routine compare the fcf record's mac address with HBA's
@@ -1109,85 +1111,115 @@ lpfc_sw_name_match(uint8_t *sw_name, struct fcf_record *new_fcf_record)
* returns 1 else return 0.
**/
static uint32_t
-lpfc_mac_addr_match(struct lpfc_hba *phba, struct fcf_record *new_fcf_record)
+lpfc_mac_addr_match(uint8_t *mac_addr, struct fcf_record *new_fcf_record)
{
- if ((phba->fcf.mac_addr[0] ==
- bf_get(lpfc_fcf_record_mac_0, new_fcf_record)) &&
- (phba->fcf.mac_addr[1] ==
- bf_get(lpfc_fcf_record_mac_1, new_fcf_record)) &&
- (phba->fcf.mac_addr[2] ==
- bf_get(lpfc_fcf_record_mac_2, new_fcf_record)) &&
- (phba->fcf.mac_addr[3] ==
- bf_get(lpfc_fcf_record_mac_3, new_fcf_record)) &&
- (phba->fcf.mac_addr[4] ==
- bf_get(lpfc_fcf_record_mac_4, new_fcf_record)) &&
- (phba->fcf.mac_addr[5] ==
- bf_get(lpfc_fcf_record_mac_5, new_fcf_record)))
- return 1;
- else
+ if (mac_addr[0] != bf_get(lpfc_fcf_record_mac_0, new_fcf_record))
+ return 0;
+ if (mac_addr[1] != bf_get(lpfc_fcf_record_mac_1, new_fcf_record))
+ return 0;
+ if (mac_addr[2] != bf_get(lpfc_fcf_record_mac_2, new_fcf_record))
return 0;
+ if (mac_addr[3] != bf_get(lpfc_fcf_record_mac_3, new_fcf_record))
+ return 0;
+ if (mac_addr[4] != bf_get(lpfc_fcf_record_mac_4, new_fcf_record))
+ return 0;
+ if (mac_addr[5] != bf_get(lpfc_fcf_record_mac_5, new_fcf_record))
+ return 0;
+ return 1;
+}
+
+static bool
+lpfc_vlan_id_match(uint16_t curr_vlan_id, uint16_t new_vlan_id)
+{
+ return (curr_vlan_id == new_vlan_id);
}
/**
* lpfc_copy_fcf_record - Copy fcf information to lpfc_hba.
- * @phba: pointer to lpfc hba data structure.
+ * @fcf: pointer to driver fcf record.
* @new_fcf_record: pointer to fcf record.
*
* This routine copies the FCF information from the FCF
* record to lpfc_hba data structure.
**/
static void
-lpfc_copy_fcf_record(struct lpfc_hba *phba, struct fcf_record *new_fcf_record)
+lpfc_copy_fcf_record(struct lpfc_fcf_rec *fcf_rec,
+ struct fcf_record *new_fcf_record)
{
- phba->fcf.fabric_name[0] =
+ /* Fabric name */
+ fcf_rec->fabric_name[0] =
bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record);
- phba->fcf.fabric_name[1] =
+ fcf_rec->fabric_name[1] =
bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record);
- phba->fcf.fabric_name[2] =
+ fcf_rec->fabric_name[2] =
bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record);
- phba->fcf.fabric_name[3] =
+ fcf_rec->fabric_name[3] =
bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record);
- phba->fcf.fabric_name[4] =
+ fcf_rec->fabric_name[4] =
bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record);
- phba->fcf.fabric_name[5] =
+ fcf_rec->fabric_name[5] =
bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record);
- phba->fcf.fabric_name[6] =
+ fcf_rec->fabric_name[6] =
bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record);
- phba->fcf.fabric_name[7] =
+ fcf_rec->fabric_name[7] =
bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record);
- phba->fcf.mac_addr[0] =
- bf_get(lpfc_fcf_record_mac_0, new_fcf_record);
- phba->fcf.mac_addr[1] =
- bf_get(lpfc_fcf_record_mac_1, new_fcf_record);
- phba->fcf.mac_addr[2] =
- bf_get(lpfc_fcf_record_mac_2, new_fcf_record);
- phba->fcf.mac_addr[3] =
- bf_get(lpfc_fcf_record_mac_3, new_fcf_record);
- phba->fcf.mac_addr[4] =
- bf_get(lpfc_fcf_record_mac_4, new_fcf_record);
- phba->fcf.mac_addr[5] =
- bf_get(lpfc_fcf_record_mac_5, new_fcf_record);
- phba->fcf.fcf_indx = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
- phba->fcf.priority = new_fcf_record->fip_priority;
- phba->fcf.switch_name[0] =
+ /* Mac address */
+ fcf_rec->mac_addr[0] = bf_get(lpfc_fcf_record_mac_0, new_fcf_record);
+ fcf_rec->mac_addr[1] = bf_get(lpfc_fcf_record_mac_1, new_fcf_record);
+ fcf_rec->mac_addr[2] = bf_get(lpfc_fcf_record_mac_2, new_fcf_record);
+ fcf_rec->mac_addr[3] = bf_get(lpfc_fcf_record_mac_3, new_fcf_record);
+ fcf_rec->mac_addr[4] = bf_get(lpfc_fcf_record_mac_4, new_fcf_record);
+ fcf_rec->mac_addr[5] = bf_get(lpfc_fcf_record_mac_5, new_fcf_record);
+ /* FCF record index */
+ fcf_rec->fcf_indx = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
+ /* FCF record priority */
+ fcf_rec->priority = new_fcf_record->fip_priority;
+ /* Switch name */
+ fcf_rec->switch_name[0] =
bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record);
- phba->fcf.switch_name[1] =
+ fcf_rec->switch_name[1] =
bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record);
- phba->fcf.switch_name[2] =
+ fcf_rec->switch_name[2] =
bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record);
- phba->fcf.switch_name[3] =
+ fcf_rec->switch_name[3] =
bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record);
- phba->fcf.switch_name[4] =
+ fcf_rec->switch_name[4] =
bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record);
- phba->fcf.switch_name[5] =
+ fcf_rec->switch_name[5] =
bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record);
- phba->fcf.switch_name[6] =
+ fcf_rec->switch_name[6] =
bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record);
- phba->fcf.switch_name[7] =
+ fcf_rec->switch_name[7] =
bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record);
}
/**
+ * lpfc_update_fcf_record - Update driver fcf record
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_rec: pointer to driver fcf record.
+ * @new_fcf_record: pointer to hba fcf record.
+ * @addr_mode: address mode to be set to the driver fcf record.
+ * @vlan_id: vlan tag to be set to the driver fcf record.
+ * @flag: flag bits to be set to the driver fcf record.
+ *
+ * This routine updates the driver FCF record from the new HBA FCF record
+ * together with the address mode, vlan_id, and other informations. This
+ * routine is called with the host lock held.
+ **/
+static void
+__lpfc_update_fcf_record(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec,
+ struct fcf_record *new_fcf_record, uint32_t addr_mode,
+ uint16_t vlan_id, uint32_t flag)
+{
+ /* Copy the fields from the HBA's FCF record */
+ lpfc_copy_fcf_record(fcf_rec, new_fcf_record);
+ /* Update other fields of driver FCF record */
+ fcf_rec->addr_mode = addr_mode;
+ fcf_rec->vlan_id = vlan_id;
+ fcf_rec->flag |= (flag | RECORD_VALID);
+}
+
+/**
* lpfc_register_fcf - Register the FCF with hba.
* @phba: pointer to lpfc hba data structure.
*
@@ -1212,7 +1244,7 @@ lpfc_register_fcf(struct lpfc_hba *phba)
/* The FCF is already registered, start discovery */
if (phba->fcf.fcf_flag & FCF_REGISTERED) {
- phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
+ phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE);
phba->hba_flag &= ~FCF_DISC_INPROGRESS;
spin_unlock_irqrestore(&phba->hbalock, flags);
if (phba->pport->port_state != LPFC_FLOGI)
@@ -1250,6 +1282,7 @@ lpfc_register_fcf(struct lpfc_hba *phba)
* @new_fcf_record: pointer to fcf record.
* @boot_flag: Indicates if this record used by boot bios.
* @addr_mode: The address mode to be used by this FCF
+ * @vlan_id: The vlan id to be used as vlan tagging by this FCF.
*
* This routine compare the fcf record with connect list obtained from the
* config region to decide if this FCF can be used for SAN discovery. It returns
@@ -1323,7 +1356,8 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
return 1;
}
- list_for_each_entry(conn_entry, &phba->fcf_conn_rec_list, list) {
+ list_for_each_entry(conn_entry,
+ &phba->fcf_conn_rec_list, list) {
if (!(conn_entry->conn_rec.flags & FCFCNCT_VALID))
continue;
@@ -1470,6 +1504,7 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
*/
spin_lock_irq(&phba->hbalock);
phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
spin_unlock_irq(&phba->hbalock);
}
@@ -1524,11 +1559,12 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
uint32_t shdr_status, shdr_add_status;
union lpfc_sli4_cfg_shdr *shdr;
struct fcf_record *new_fcf_record;
- int rc;
uint32_t boot_flag, addr_mode;
uint32_t next_fcf_index;
- unsigned long flags;
+ struct lpfc_fcf_rec *fcf_rec = NULL;
+ unsigned long iflags;
uint16_t vlan_id;
+ int rc;
/* If there is pending FCoE event restart FCF table scan */
if (lpfc_check_pending_fcoe_event(phba, 0)) {
@@ -1583,9 +1619,8 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
sizeof(struct fcf_record));
bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr);
- rc = lpfc_match_fcf_conn_list(phba, new_fcf_record,
- &boot_flag, &addr_mode,
- &vlan_id);
+ rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag,
+ &addr_mode, &vlan_id);
/*
* If the fcf record does not match with connect list entries
* read the next entry.
@@ -1594,90 +1629,159 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
goto read_next_fcf;
/*
* If this is not the first FCF discovery of the HBA, use last
- * FCF record for the discovery.
+ * FCF record for the discovery. The condition that a rescan
+ * matches the in-use FCF record: fabric name, switch name, mac
+ * address, and vlan_id.
*/
- spin_lock_irqsave(&phba->hbalock, flags);
+ spin_lock_irqsave(&phba->hbalock, iflags);
if (phba->fcf.fcf_flag & FCF_IN_USE) {
- if (lpfc_fab_name_match(phba->fcf.fabric_name,
+ if (lpfc_fab_name_match(phba->fcf.current_rec.fabric_name,
new_fcf_record) &&
- lpfc_sw_name_match(phba->fcf.switch_name,
+ lpfc_sw_name_match(phba->fcf.current_rec.switch_name,
new_fcf_record) &&
- lpfc_mac_addr_match(phba, new_fcf_record)) {
+ lpfc_mac_addr_match(phba->fcf.current_rec.mac_addr,
+ new_fcf_record) &&
+ lpfc_vlan_id_match(phba->fcf.current_rec.vlan_id,
+ vlan_id)) {
phba->fcf.fcf_flag |= FCF_AVAILABLE;
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ if (phba->fcf.fcf_flag & FCF_REDISC_PEND)
+ /* Stop FCF redisc wait timer if pending */
+ __lpfc_sli4_stop_fcf_redisc_wait_timer(phba);
+ else if (phba->fcf.fcf_flag & FCF_REDISC_FOV)
+ /* If in fast failover, mark it's completed */
+ phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
goto out;
}
- spin_unlock_irqrestore(&phba->hbalock, flags);
- goto read_next_fcf;
+ /*
+ * Read next FCF record from HBA searching for the matching
+ * with in-use record only if not during the fast failover
+ * period. In case of fast failover period, it shall try to
+ * determine whether the FCF record just read should be the
+ * next candidate.
+ */
+ if (!(phba->fcf.fcf_flag & FCF_REDISC_FOV)) {
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ goto read_next_fcf;
+ }
}
+ /*
+ * Update on failover FCF record only if it's in FCF fast-failover
+ * period; otherwise, update on current FCF record.
+ */
+ if (phba->fcf.fcf_flag & FCF_REDISC_FOV) {
+ /* Fast FCF failover only to the same fabric name */
+ if (lpfc_fab_name_match(phba->fcf.current_rec.fabric_name,
+ new_fcf_record))
+ fcf_rec = &phba->fcf.failover_rec;
+ else
+ goto read_next_fcf;
+ } else
+ fcf_rec = &phba->fcf.current_rec;
+
if (phba->fcf.fcf_flag & FCF_AVAILABLE) {
/*
- * If the current FCF record does not have boot flag
- * set and new fcf record has boot flag set, use the
- * new fcf record.
+ * If the driver FCF record does not have boot flag
+ * set and new hba fcf record has boot flag set, use
+ * the new hba fcf record.
*/
- if (boot_flag && !(phba->fcf.fcf_flag & FCF_BOOT_ENABLE)) {
- /* Use this FCF record */
- lpfc_copy_fcf_record(phba, new_fcf_record);
- phba->fcf.addr_mode = addr_mode;
- phba->fcf.fcf_flag |= FCF_BOOT_ENABLE;
- if (vlan_id != 0xFFFF) {
- phba->fcf.fcf_flag |= FCF_VALID_VLAN;
- phba->fcf.vlan_id = vlan_id;
- }
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ if (boot_flag && !(fcf_rec->flag & BOOT_ENABLE)) {
+ /* Choose this FCF record */
+ __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
+ addr_mode, vlan_id, BOOT_ENABLE);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
goto read_next_fcf;
}
/*
- * If the current FCF record has boot flag set and the
- * new FCF record does not have boot flag, read the next
- * FCF record.
+ * If the driver FCF record has boot flag set and the
+ * new hba FCF record does not have boot flag, read
+ * the next FCF record.
*/
- if (!boot_flag && (phba->fcf.fcf_flag & FCF_BOOT_ENABLE)) {
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ if (!boot_flag && (fcf_rec->flag & BOOT_ENABLE)) {
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
goto read_next_fcf;
}
/*
- * If there is a record with lower priority value for
- * the current FCF, use that record.
+ * If the new hba FCF record has lower priority value
+ * than the driver FCF record, use the new record.
*/
- if (lpfc_fab_name_match(phba->fcf.fabric_name,
- new_fcf_record) &&
- (new_fcf_record->fip_priority < phba->fcf.priority)) {
- /* Use this FCF record */
- lpfc_copy_fcf_record(phba, new_fcf_record);
- phba->fcf.addr_mode = addr_mode;
- if (vlan_id != 0xFFFF) {
- phba->fcf.fcf_flag |= FCF_VALID_VLAN;
- phba->fcf.vlan_id = vlan_id;
- }
- spin_unlock_irqrestore(&phba->hbalock, flags);
- goto read_next_fcf;
+ if (lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record) &&
+ (new_fcf_record->fip_priority < fcf_rec->priority)) {
+ /* Choose this FCF record */
+ __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
+ addr_mode, vlan_id, 0);
}
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
goto read_next_fcf;
}
/*
- * This is the first available FCF record, use this
- * record.
+ * This is the first suitable FCF record, choose this record for
+ * initial best-fit FCF.
*/
- lpfc_copy_fcf_record(phba, new_fcf_record);
- phba->fcf.addr_mode = addr_mode;
- if (boot_flag)
- phba->fcf.fcf_flag |= FCF_BOOT_ENABLE;
- phba->fcf.fcf_flag |= FCF_AVAILABLE;
- if (vlan_id != 0xFFFF) {
- phba->fcf.fcf_flag |= FCF_VALID_VLAN;
- phba->fcf.vlan_id = vlan_id;
+ if (fcf_rec) {
+ __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
+ addr_mode, vlan_id, (boot_flag ?
+ BOOT_ENABLE : 0));
+ phba->fcf.fcf_flag |= FCF_AVAILABLE;
}
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
goto read_next_fcf;
read_next_fcf:
lpfc_sli4_mbox_cmd_free(phba, mboxq);
- if (next_fcf_index == LPFC_FCOE_FCF_NEXT_NONE || next_fcf_index == 0)
- lpfc_register_fcf(phba);
- else
+ if (next_fcf_index == LPFC_FCOE_FCF_NEXT_NONE || next_fcf_index == 0) {
+ if (phba->fcf.fcf_flag & FCF_REDISC_FOV) {
+ /*
+ * Case of FCF fast failover scan
+ */
+
+ /*
+ * It has not found any suitable FCF record, cancel
+ * FCF scan inprogress, and do nothing
+ */
+ if (!(phba->fcf.failover_rec.flag & RECORD_VALID)) {
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return;
+ }
+ /*
+ * It has found a suitable FCF record that is not
+ * the same as in-use FCF record, unregister the
+ * in-use FCF record, replace the in-use FCF record
+ * with the new FCF record, mark FCF fast failover
+ * completed, and then start register the new FCF
+ * record.
+ */
+
+ /* unregister the current in-use FCF record */
+ lpfc_unregister_fcf(phba);
+ /* replace in-use record with the new record */
+ memcpy(&phba->fcf.current_rec,
+ &phba->fcf.failover_rec,
+ sizeof(struct lpfc_fcf_rec));
+ /* mark the FCF fast failover completed */
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ /* Register to the new FCF record */
+ lpfc_register_fcf(phba);
+ } else {
+ /*
+ * In case of transaction period to fast FCF failover,
+ * do nothing when search to the end of the FCF table.
+ */
+ if ((phba->fcf.fcf_flag & FCF_REDISC_EVT) ||
+ (phba->fcf.fcf_flag & FCF_REDISC_PEND))
+ return;
+ /*
+ * Otherwise, initial scan or post linkdown rescan,
+ * register with the best fit FCF record found so
+ * far through the scanning process.
+ */
+ lpfc_register_fcf(phba);
+ }
+ } else
lpfc_sli4_read_fcf_record(phba, next_fcf_index);
return;
@@ -1695,10 +1799,13 @@ out:
*
* This function handles completion of init vpi mailbox command.
*/
-static void
+void
lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
{
struct lpfc_vport *vport = mboxq->vport;
+ struct lpfc_nodelist *ndlp;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
if (mboxq->u.mb.mbxStatus) {
lpfc_printf_vlog(vport, KERN_ERR,
LOG_MBOX,
@@ -1708,9 +1815,23 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
return;
}
- spin_lock_irq(&phba->hbalock);
+ spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI;
- spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irq(shost->host_lock);
+
+ /* If this port is physical port or FDISC is done, do reg_vpi */
+ if ((phba->pport == vport) || (vport->port_state == LPFC_FDISC)) {
+ ndlp = lpfc_findnode_did(vport, Fabric_DID);
+ if (!ndlp)
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_DISCOVERY,
+ "2731 Cannot find fabric "
+ "controller node\n");
+ else
+ lpfc_register_new_vport(phba, vport, ndlp);
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ return;
+ }
if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
lpfc_initial_fdisc(vport);
@@ -1719,10 +1840,42 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"2606 No NPIV Fabric support\n");
}
+ mempool_free(mboxq, phba->mbox_mem_pool);
return;
}
/**
+ * lpfc_issue_init_vpi - Issue init_vpi mailbox command.
+ * @vport: pointer to lpfc_vport data structure.
+ *
+ * This function issue a init_vpi mailbox command to initialize
+ * VPI for the vport.
+ */
+void
+lpfc_issue_init_vpi(struct lpfc_vport *vport)
+{
+ LPFC_MBOXQ_t *mboxq;
+ int rc;
+
+ mboxq = mempool_alloc(vport->phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mboxq) {
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_MBOX, "2607 Failed to allocate "
+ "init_vpi mailbox\n");
+ return;
+ }
+ lpfc_init_vpi(vport->phba, mboxq, vport->vpi);
+ mboxq->vport = vport;
+ mboxq->mbox_cmpl = lpfc_init_vpi_cmpl;
+ rc = lpfc_sli_issue_mbox(vport->phba, mboxq, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_MBOX, "2608 Failed to issue init_vpi mailbox\n");
+ mempool_free(mboxq, vport->phba->mbox_mem_pool);
+ }
+}
+
+/**
* lpfc_start_fdiscs - send fdiscs for each vports on this port.
* @phba: pointer to lpfc hba data structure.
*
@@ -1734,8 +1887,6 @@ lpfc_start_fdiscs(struct lpfc_hba *phba)
{
struct lpfc_vport **vports;
int i;
- LPFC_MBOXQ_t *mboxq;
- int rc;
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL) {
@@ -1754,26 +1905,7 @@ lpfc_start_fdiscs(struct lpfc_hba *phba)
continue;
}
if (vports[i]->fc_flag & FC_VPORT_NEEDS_INIT_VPI) {
- mboxq = mempool_alloc(phba->mbox_mem_pool,
- GFP_KERNEL);
- if (!mboxq) {
- lpfc_printf_vlog(vports[i], KERN_ERR,
- LOG_MBOX, "2607 Failed to allocate "
- "init_vpi mailbox\n");
- continue;
- }
- lpfc_init_vpi(phba, mboxq, vports[i]->vpi);
- mboxq->vport = vports[i];
- mboxq->mbox_cmpl = lpfc_init_vpi_cmpl;
- rc = lpfc_sli_issue_mbox(phba, mboxq,
- MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- lpfc_printf_vlog(vports[i], KERN_ERR,
- LOG_MBOX, "2608 Failed to issue "
- "init_vpi mailbox\n");
- mempool_free(mboxq,
- phba->mbox_mem_pool);
- }
+ lpfc_issue_init_vpi(vports[i]);
continue;
}
if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
@@ -1796,6 +1928,7 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
{
struct lpfc_dmabuf *dmabuf = mboxq->context1;
struct lpfc_vport *vport = mboxq->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
if (mboxq->u.mb.mbxStatus) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
@@ -1813,7 +1946,11 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
goto fail_free_mem;
}
/* The VPI is implicitly registered when the VFI is registered */
+ spin_lock_irq(shost->host_lock);
vport->vpi_state |= LPFC_VPI_REGISTERED;
+ vport->fc_flag |= FC_VFI_REGISTERED;
+ vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+ spin_unlock_irq(shost->host_lock);
if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
lpfc_start_fdiscs(phba);
@@ -2050,8 +2187,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
return;
}
spin_unlock_irq(&phba->hbalock);
- rc = lpfc_sli4_read_fcf_record(phba,
- LPFC_FCOE_FCF_GET_FIRST);
+ rc = lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
if (rc)
goto out;
}
@@ -2139,10 +2275,12 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
}
phba->fc_eventTag = la->eventTag;
+ spin_lock_irq(&phba->hbalock);
if (la->mm)
phba->sli.sli_flag |= LPFC_MENLO_MAINT;
else
phba->sli.sli_flag &= ~LPFC_MENLO_MAINT;
+ spin_unlock_irq(&phba->hbalock);
phba->link_events++;
if (la->attType == AT_LINK_UP && (!la->mm)) {
@@ -2271,10 +2409,10 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
mb->mbxStatus);
break;
}
- spin_lock_irq(&phba->hbalock);
+ spin_lock_irq(shost->host_lock);
vport->vpi_state &= ~LPFC_VPI_REGISTERED;
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
- spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irq(shost->host_lock);
vport->unreg_vpi_cmpl = VPORT_OK;
mempool_free(pmb, phba->mbox_mem_pool);
/*
@@ -2332,7 +2470,10 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
goto out;
}
+ spin_lock_irq(shost->host_lock);
vport->vpi_state |= LPFC_VPI_REGISTERED;
+ vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+ spin_unlock_irq(shost->host_lock);
vport->num_disc_nodes = 0;
/* go thru NPR list and issue ELS PLOGIs */
if (vport->fc_npr_cnt)
@@ -3218,6 +3359,34 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
return 0;
}
+/**
+ * lpfc_unreg_hba_rpis - Unregister rpis registered to the hba.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unregister all the currently registered RPIs
+ * to the HBA.
+ **/
+void
+lpfc_unreg_hba_rpis(struct lpfc_hba *phba)
+{
+ struct lpfc_vport **vports;
+ struct lpfc_nodelist *ndlp;
+ struct Scsi_Host *shost;
+ int i;
+
+ vports = lpfc_create_vport_work_array(phba);
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+ shost = lpfc_shost_from_vport(vports[i]);
+ spin_lock_irq(shost->host_lock);
+ list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_flag & NLP_RPI_VALID)
+ lpfc_unreg_rpi(vports[i], ndlp);
+ }
+ spin_unlock_irq(shost->host_lock);
+ }
+ lpfc_destroy_vport_work_array(phba, vports);
+}
+
void
lpfc_unreg_all_rpis(struct lpfc_vport *vport)
{
@@ -4448,63 +4617,56 @@ lpfc_unregister_fcfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
}
/**
- * lpfc_unregister_unused_fcf - Unregister FCF if all devices are disconnected.
+ * lpfc_unregister_fcf_prep - Unregister fcf record preparation
* @phba: Pointer to hba context object.
*
- * This function check if there are any connected remote port for the FCF and
- * if all the devices are disconnected, this function unregister FCFI.
- * This function also tries to use another FCF for discovery.
+ * This function prepare the HBA for unregistering the currently registered
+ * FCF from the HBA. It performs unregistering, in order, RPIs, VPIs, and
+ * VFIs.
*/
-void
-lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
+int
+lpfc_unregister_fcf_prep(struct lpfc_hba *phba)
{
LPFC_MBOXQ_t *mbox;
- int rc;
struct lpfc_vport **vports;
- int i;
-
- spin_lock_irq(&phba->hbalock);
- /*
- * If HBA is not running in FIP mode or
- * If HBA does not support FCoE or
- * If FCF is not registered.
- * do nothing.
- */
- if (!(phba->hba_flag & HBA_FCOE_SUPPORT) ||
- !(phba->fcf.fcf_flag & FCF_REGISTERED) ||
- (!(phba->hba_flag & HBA_FIP_SUPPORT))) {
- spin_unlock_irq(&phba->hbalock);
- return;
- }
- spin_unlock_irq(&phba->hbalock);
+ struct lpfc_nodelist *ndlp;
+ struct Scsi_Host *shost;
+ int i, rc;
+ /* Unregister RPIs */
if (lpfc_fcf_inuse(phba))
- return;
+ lpfc_unreg_hba_rpis(phba);
/* At this point, all discovery is aborted */
phba->pport->port_state = LPFC_VPORT_UNKNOWN;
/* Unregister VPIs */
vports = lpfc_create_vport_work_array(phba);
- if (vports &&
- (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED))
+ if (vports && (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED))
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+ /* Stop FLOGI/FDISC retries */
+ ndlp = lpfc_findnode_did(vports[i], Fabric_DID);
+ if (ndlp)
+ lpfc_cancel_retry_delay_tmo(vports[i], ndlp);
lpfc_mbx_unreg_vpi(vports[i]);
- spin_lock_irq(&phba->hbalock);
+ shost = lpfc_shost_from_vport(vports[i]);
+ spin_lock_irq(shost->host_lock);
vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED;
- spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irq(shost->host_lock);
}
lpfc_destroy_vport_work_array(phba, vports);
+ /* Cleanup any outstanding ELS commands */
+ lpfc_els_flush_all_cmd(phba);
+
/* Unregister VFI */
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox) {
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
- "2556 UNREG_VFI mbox allocation failed"
- "HBA state x%x\n",
- phba->pport->port_state);
- return;
+ "2556 UNREG_VFI mbox allocation failed"
+ "HBA state x%x\n", phba->pport->port_state);
+ return -ENOMEM;
}
lpfc_unreg_vfi(mbox, phba->pport);
@@ -4514,58 +4676,163 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
- "2557 UNREG_VFI issue mbox failed rc x%x "
- "HBA state x%x\n",
- rc, phba->pport->port_state);
+ "2557 UNREG_VFI issue mbox failed rc x%x "
+ "HBA state x%x\n",
+ rc, phba->pport->port_state);
mempool_free(mbox, phba->mbox_mem_pool);
- return;
+ return -EIO;
}
- /* Unregister FCF */
+ shost = lpfc_shost_from_vport(phba->pport);
+ spin_lock_irq(shost->host_lock);
+ phba->pport->fc_flag &= ~FC_VFI_REGISTERED;
+ spin_unlock_irq(shost->host_lock);
+
+ return 0;
+}
+
+/**
+ * lpfc_sli4_unregister_fcf - Unregister currently registered FCF record
+ * @phba: Pointer to hba context object.
+ *
+ * This function issues synchronous unregister FCF mailbox command to HBA to
+ * unregister the currently registered FCF record. The driver does not reset
+ * the driver FCF usage state flags.
+ *
+ * Return 0 if successfully issued, none-zero otherwise.
+ */
+int
+lpfc_sli4_unregister_fcf(struct lpfc_hba *phba)
+{
+ LPFC_MBOXQ_t *mbox;
+ int rc;
+
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox) {
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
- "2551 UNREG_FCFI mbox allocation failed"
- "HBA state x%x\n",
- phba->pport->port_state);
- return;
+ "2551 UNREG_FCFI mbox allocation failed"
+ "HBA state x%x\n", phba->pport->port_state);
+ return -ENOMEM;
}
-
lpfc_unreg_fcfi(mbox, phba->fcf.fcfi);
mbox->vport = phba->pport;
mbox->mbox_cmpl = lpfc_unregister_fcfi_cmpl;
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
- "2552 UNREG_FCFI issue mbox failed rc x%x "
- "HBA state x%x\n",
- rc, phba->pport->port_state);
- mempool_free(mbox, phba->mbox_mem_pool);
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2552 Unregister FCFI command failed rc x%x "
+ "HBA state x%x\n",
+ rc, phba->pport->port_state);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * lpfc_unregister_fcf_rescan - Unregister currently registered fcf and rescan
+ * @phba: Pointer to hba context object.
+ *
+ * This function unregisters the currently reigstered FCF. This function
+ * also tries to find another FCF for discovery by rescan the HBA FCF table.
+ */
+void
+lpfc_unregister_fcf_rescan(struct lpfc_hba *phba)
+{
+ int rc;
+
+ /* Preparation for unregistering fcf */
+ rc = lpfc_unregister_fcf_prep(phba);
+ if (rc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "2748 Failed to prepare for unregistering "
+ "HBA's FCF record: rc=%d\n", rc);
return;
}
- spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_REGISTERED |
- FCF_DISCOVERED | FCF_BOOT_ENABLE | FCF_IN_USE |
- FCF_VALID_VLAN);
- spin_unlock_irq(&phba->hbalock);
+ /* Now, unregister FCF record and reset HBA FCF state */
+ rc = lpfc_sli4_unregister_fcf(phba);
+ if (rc)
+ return;
+ /* Reset HBA FCF states after successful unregister FCF */
+ phba->fcf.fcf_flag = 0;
/*
* If driver is not unloading, check if there is any other
* FCF record that can be used for discovery.
*/
if ((phba->pport->load_flag & FC_UNLOADING) ||
- (phba->link_state < LPFC_LINK_UP))
+ (phba->link_state < LPFC_LINK_UP))
return;
rc = lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
if (rc)
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
- "2553 lpfc_unregister_unused_fcf failed to read FCF"
- " record HBA state x%x\n",
- phba->pport->port_state);
+ "2553 lpfc_unregister_unused_fcf failed "
+ "to read FCF record HBA state x%x\n",
+ phba->pport->port_state);
+}
+
+/**
+ * lpfc_unregister_fcf - Unregister the currently registered fcf record
+ * @phba: Pointer to hba context object.
+ *
+ * This function just unregisters the currently reigstered FCF. It does not
+ * try to find another FCF for discovery.
+ */
+void
+lpfc_unregister_fcf(struct lpfc_hba *phba)
+{
+ int rc;
+
+ /* Preparation for unregistering fcf */
+ rc = lpfc_unregister_fcf_prep(phba);
+ if (rc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "2749 Failed to prepare for unregistering "
+ "HBA's FCF record: rc=%d\n", rc);
+ return;
+ }
+
+ /* Now, unregister FCF record and reset HBA FCF state */
+ rc = lpfc_sli4_unregister_fcf(phba);
+ if (rc)
+ return;
+ /* Set proper HBA FCF states after successful unregister FCF */
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag &= ~FCF_REGISTERED;
+ spin_unlock_irq(&phba->hbalock);
+}
+
+/**
+ * lpfc_unregister_unused_fcf - Unregister FCF if all devices are disconnected.
+ * @phba: Pointer to hba context object.
+ *
+ * This function check if there are any connected remote port for the FCF and
+ * if all the devices are disconnected, this function unregister FCFI.
+ * This function also tries to use another FCF for discovery.
+ */
+void
+lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
+{
+ /*
+ * If HBA is not running in FIP mode or if HBA does not support
+ * FCoE or if FCF is not registered, do nothing.
+ */
+ spin_lock_irq(&phba->hbalock);
+ if (!(phba->hba_flag & HBA_FCOE_SUPPORT) ||
+ !(phba->fcf.fcf_flag & FCF_REGISTERED) ||
+ !(phba->hba_flag & HBA_FIP_SUPPORT)) {
+ spin_unlock_irq(&phba->hbalock);
+ return;
+ }
+ spin_unlock_irq(&phba->hbalock);
+
+ if (lpfc_fcf_inuse(phba))
+ return;
+
+ lpfc_unregister_fcf_rescan(phba);
}
/**
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index c9faa1d8c3c8..89ff7c09e298 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2009 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2010 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -1346,6 +1346,9 @@ typedef struct { /* FireFly BIU registers */
#define MBX_HEARTBEAT 0x31
#define MBX_WRITE_VPARMS 0x32
#define MBX_ASYNCEVT_ENABLE 0x33
+#define MBX_READ_EVENT_LOG_STATUS 0x37
+#define MBX_READ_EVENT_LOG 0x38
+#define MBX_WRITE_EVENT_LOG 0x39
#define MBX_PORT_CAPABILITIES 0x3B
#define MBX_PORT_IOV_CONTROL 0x3C
@@ -1465,17 +1468,13 @@ typedef struct { /* FireFly BIU registers */
#define CMD_IOCB_LOGENTRY_CN 0x94
#define CMD_IOCB_LOGENTRY_ASYNC_CN 0x96
-/* Unhandled Data Security SLI Commands */
-#define DSSCMD_IWRITE64_CR 0xD8
-#define DSSCMD_IWRITE64_CX 0xD9
-#define DSSCMD_IREAD64_CR 0xDA
-#define DSSCMD_IREAD64_CX 0xDB
-#define DSSCMD_INVALIDATE_DEK 0xDC
-#define DSSCMD_SET_KEK 0xDD
-#define DSSCMD_GET_KEK_ID 0xDE
-#define DSSCMD_GEN_XFER 0xDF
-
-#define CMD_MAX_IOCB_CMD 0xE6
+/* Data Security SLI Commands */
+#define DSSCMD_IWRITE64_CR 0xF8
+#define DSSCMD_IWRITE64_CX 0xF9
+#define DSSCMD_IREAD64_CR 0xFA
+#define DSSCMD_IREAD64_CX 0xFB
+
+#define CMD_MAX_IOCB_CMD 0xFB
#define CMD_IOCB_MASK 0xff
#define MAX_MSG_DATA 28 /* max msg data in CMD_ADAPTER_MSG
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 8a2a1c5935c6..820015fbc4d6 100755..100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -52,35 +52,37 @@ struct dma_address {
uint32_t addr_hi;
};
-#define LPFC_SLIREV_CONF_WORD 0x58
struct lpfc_sli_intf {
uint32_t word0;
-#define lpfc_sli_intf_iftype_MASK 0x00000007
-#define lpfc_sli_intf_iftype_SHIFT 0
-#define lpfc_sli_intf_iftype_WORD word0
-#define lpfc_sli_intf_rev_MASK 0x0000000f
-#define lpfc_sli_intf_rev_SHIFT 4
-#define lpfc_sli_intf_rev_WORD word0
-#define LPFC_SLIREV_CONF_SLI4 4
-#define lpfc_sli_intf_family_MASK 0x000000ff
-#define lpfc_sli_intf_family_SHIFT 8
-#define lpfc_sli_intf_family_WORD word0
-#define lpfc_sli_intf_feat1_MASK 0x000000ff
-#define lpfc_sli_intf_feat1_SHIFT 16
-#define lpfc_sli_intf_feat1_WORD word0
-#define lpfc_sli_intf_feat2_MASK 0x0000001f
-#define lpfc_sli_intf_feat2_SHIFT 24
-#define lpfc_sli_intf_feat2_WORD word0
-#define lpfc_sli_intf_valid_MASK 0x00000007
-#define lpfc_sli_intf_valid_SHIFT 29
-#define lpfc_sli_intf_valid_WORD word0
+#define lpfc_sli_intf_valid_SHIFT 29
+#define lpfc_sli_intf_valid_MASK 0x00000007
+#define lpfc_sli_intf_valid_WORD word0
#define LPFC_SLI_INTF_VALID 6
+#define lpfc_sli_intf_featurelevel2_SHIFT 24
+#define lpfc_sli_intf_featurelevel2_MASK 0x0000001F
+#define lpfc_sli_intf_featurelevel2_WORD word0
+#define lpfc_sli_intf_featurelevel1_SHIFT 16
+#define lpfc_sli_intf_featurelevel1_MASK 0x000000FF
+#define lpfc_sli_intf_featurelevel1_WORD word0
+#define LPFC_SLI_INTF_FEATURELEVEL1_1 1
+#define LPFC_SLI_INTF_FEATURELEVEL1_2 2
+#define lpfc_sli_intf_sli_family_SHIFT 8
+#define lpfc_sli_intf_sli_family_MASK 0x000000FF
+#define lpfc_sli_intf_sli_family_WORD word0
+#define LPFC_SLI_INTF_FAMILY_BE2 0
+#define LPFC_SLI_INTF_FAMILY_BE3 1
+#define lpfc_sli_intf_slirev_SHIFT 4
+#define lpfc_sli_intf_slirev_MASK 0x0000000F
+#define lpfc_sli_intf_slirev_WORD word0
+#define LPFC_SLI_INTF_REV_SLI3 3
+#define LPFC_SLI_INTF_REV_SLI4 4
+#define lpfc_sli_intf_if_type_SHIFT 0
+#define lpfc_sli_intf_if_type_MASK 0x00000007
+#define lpfc_sli_intf_if_type_WORD word0
+#define LPFC_SLI_INTF_IF_TYPE_0 0
+#define LPFC_SLI_INTF_IF_TYPE_1 1
};
-#define LPFC_SLI4_BAR0 1
-#define LPFC_SLI4_BAR1 2
-#define LPFC_SLI4_BAR2 4
-
#define LPFC_SLI4_MBX_EMBED true
#define LPFC_SLI4_MBX_NEMBED false
@@ -161,6 +163,9 @@ struct lpfc_sli_intf {
#define LPFC_FP_DEF_IMAX 10000
#define LPFC_SP_DEF_IMAX 10000
+/* PORT_CAPABILITIES constants. */
+#define LPFC_MAX_SUPPORTED_PAGES 8
+
struct ulp_bde64 {
union ULP_BDE_TUS {
uint32_t w;
@@ -516,7 +521,7 @@ struct lpfc_register {
#define LPFC_UERR_STATUS_LO 0x00A0
#define LPFC_UE_MASK_HI 0x00AC
#define LPFC_UE_MASK_LO 0x00A8
-#define LPFC_SCRATCHPAD 0x0058
+#define LPFC_SLI_INTF 0x0058
/* BAR0 Registers */
#define LPFC_HST_STATE 0x00AC
@@ -576,19 +581,6 @@ struct lpfc_register {
#define LPFC_POST_STAGE_ARMFW_READY 0xC000
#define LPFC_POST_STAGE_ARMFW_UE 0xF000
-#define lpfc_scratchpad_slirev_SHIFT 4
-#define lpfc_scratchpad_slirev_MASK 0xF
-#define lpfc_scratchpad_slirev_WORD word0
-#define lpfc_scratchpad_chiptype_SHIFT 8
-#define lpfc_scratchpad_chiptype_MASK 0xFF
-#define lpfc_scratchpad_chiptype_WORD word0
-#define lpfc_scratchpad_featurelevel1_SHIFT 16
-#define lpfc_scratchpad_featurelevel1_MASK 0xFF
-#define lpfc_scratchpad_featurelevel1_WORD word0
-#define lpfc_scratchpad_featurelevel2_SHIFT 24
-#define lpfc_scratchpad_featurelevel2_MASK 0xFF
-#define lpfc_scratchpad_featurelevel2_WORD word0
-
/* BAR1 Registers */
#define LPFC_IMR_MASK_ALL 0xFFFFFFFF
#define LPFC_ISCR_CLEAR_ALL 0xFFFFFFFF
@@ -801,6 +793,7 @@ struct mbox_header {
#define LPFC_MBOX_OPCODE_FCOE_ADD_FCF 0x09
#define LPFC_MBOX_OPCODE_FCOE_DELETE_FCF 0x0A
#define LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE 0x0B
+#define LPFC_MBOX_OPCODE_FCOE_REDISCOVER_FCF 0x10
/* Mailbox command structures */
struct eq_context {
@@ -1149,10 +1142,7 @@ struct sli4_sge { /* SLI-4 */
this flag !! */
#define lpfc_sli4_sge_last_MASK 0x00000001
#define lpfc_sli4_sge_last_WORD word2
- uint32_t word3;
-#define lpfc_sli4_sge_len_SHIFT 0
-#define lpfc_sli4_sge_len_MASK 0x0001FFFF
-#define lpfc_sli4_sge_len_WORD word3
+ uint32_t sge_len;
};
struct fcf_record {
@@ -1301,6 +1291,19 @@ struct lpfc_mbx_del_fcf_tbl_entry {
#define lpfc_mbx_del_fcf_tbl_index_WORD word10
};
+struct lpfc_mbx_redisc_fcf_tbl {
+ struct mbox_header header;
+ uint32_t word10;
+#define lpfc_mbx_redisc_fcf_count_SHIFT 0
+#define lpfc_mbx_redisc_fcf_count_MASK 0x0000FFFF
+#define lpfc_mbx_redisc_fcf_count_WORD word10
+ uint32_t resvd;
+ uint32_t word12;
+#define lpfc_mbx_redisc_fcf_index_SHIFT 0
+#define lpfc_mbx_redisc_fcf_index_MASK 0x0000FFFF
+#define lpfc_mbx_redisc_fcf_index_WORD word12
+};
+
struct lpfc_mbx_query_fw_cfg {
struct mbox_header header;
uint32_t config_number;
@@ -1834,6 +1837,177 @@ struct lpfc_mbx_request_features {
#define lpfc_mbx_rq_ftr_rsp_ifip_WORD word3
};
+struct lpfc_mbx_supp_pages {
+ uint32_t word1;
+#define qs_SHIFT 0
+#define qs_MASK 0x00000001
+#define qs_WORD word1
+#define wr_SHIFT 1
+#define wr_MASK 0x00000001
+#define wr_WORD word1
+#define pf_SHIFT 8
+#define pf_MASK 0x000000ff
+#define pf_WORD word1
+#define cpn_SHIFT 16
+#define cpn_MASK 0x000000ff
+#define cpn_WORD word1
+ uint32_t word2;
+#define list_offset_SHIFT 0
+#define list_offset_MASK 0x000000ff
+#define list_offset_WORD word2
+#define next_offset_SHIFT 8
+#define next_offset_MASK 0x000000ff
+#define next_offset_WORD word2
+#define elem_cnt_SHIFT 16
+#define elem_cnt_MASK 0x000000ff
+#define elem_cnt_WORD word2
+ uint32_t word3;
+#define pn_0_SHIFT 24
+#define pn_0_MASK 0x000000ff
+#define pn_0_WORD word3
+#define pn_1_SHIFT 16
+#define pn_1_MASK 0x000000ff
+#define pn_1_WORD word3
+#define pn_2_SHIFT 8
+#define pn_2_MASK 0x000000ff
+#define pn_2_WORD word3
+#define pn_3_SHIFT 0
+#define pn_3_MASK 0x000000ff
+#define pn_3_WORD word3
+ uint32_t word4;
+#define pn_4_SHIFT 24
+#define pn_4_MASK 0x000000ff
+#define pn_4_WORD word4
+#define pn_5_SHIFT 16
+#define pn_5_MASK 0x000000ff
+#define pn_5_WORD word4
+#define pn_6_SHIFT 8
+#define pn_6_MASK 0x000000ff
+#define pn_6_WORD word4
+#define pn_7_SHIFT 0
+#define pn_7_MASK 0x000000ff
+#define pn_7_WORD word4
+ uint32_t rsvd[27];
+#define LPFC_SUPP_PAGES 0
+#define LPFC_BLOCK_GUARD_PROFILES 1
+#define LPFC_SLI4_PARAMETERS 2
+};
+
+struct lpfc_mbx_sli4_params {
+ uint32_t word1;
+#define qs_SHIFT 0
+#define qs_MASK 0x00000001
+#define qs_WORD word1
+#define wr_SHIFT 1
+#define wr_MASK 0x00000001
+#define wr_WORD word1
+#define pf_SHIFT 8
+#define pf_MASK 0x000000ff
+#define pf_WORD word1
+#define cpn_SHIFT 16
+#define cpn_MASK 0x000000ff
+#define cpn_WORD word1
+ uint32_t word2;
+#define if_type_SHIFT 0
+#define if_type_MASK 0x00000007
+#define if_type_WORD word2
+#define sli_rev_SHIFT 4
+#define sli_rev_MASK 0x0000000f
+#define sli_rev_WORD word2
+#define sli_family_SHIFT 8
+#define sli_family_MASK 0x000000ff
+#define sli_family_WORD word2
+#define featurelevel_1_SHIFT 16
+#define featurelevel_1_MASK 0x000000ff
+#define featurelevel_1_WORD word2
+#define featurelevel_2_SHIFT 24
+#define featurelevel_2_MASK 0x0000001f
+#define featurelevel_2_WORD word2
+ uint32_t word3;
+#define fcoe_SHIFT 0
+#define fcoe_MASK 0x00000001
+#define fcoe_WORD word3
+#define fc_SHIFT 1
+#define fc_MASK 0x00000001
+#define fc_WORD word3
+#define nic_SHIFT 2
+#define nic_MASK 0x00000001
+#define nic_WORD word3
+#define iscsi_SHIFT 3
+#define iscsi_MASK 0x00000001
+#define iscsi_WORD word3
+#define rdma_SHIFT 4
+#define rdma_MASK 0x00000001
+#define rdma_WORD word3
+ uint32_t sge_supp_len;
+ uint32_t word5;
+#define if_page_sz_SHIFT 0
+#define if_page_sz_MASK 0x0000ffff
+#define if_page_sz_WORD word5
+#define loopbk_scope_SHIFT 24
+#define loopbk_scope_MASK 0x0000000f
+#define loopbk_scope_WORD word5
+#define rq_db_window_SHIFT 28
+#define rq_db_window_MASK 0x0000000f
+#define rq_db_window_WORD word5
+ uint32_t word6;
+#define eq_pages_SHIFT 0
+#define eq_pages_MASK 0x0000000f
+#define eq_pages_WORD word6
+#define eqe_size_SHIFT 8
+#define eqe_size_MASK 0x000000ff
+#define eqe_size_WORD word6
+ uint32_t word7;
+#define cq_pages_SHIFT 0
+#define cq_pages_MASK 0x0000000f
+#define cq_pages_WORD word7
+#define cqe_size_SHIFT 8
+#define cqe_size_MASK 0x000000ff
+#define cqe_size_WORD word7
+ uint32_t word8;
+#define mq_pages_SHIFT 0
+#define mq_pages_MASK 0x0000000f
+#define mq_pages_WORD word8
+#define mqe_size_SHIFT 8
+#define mqe_size_MASK 0x000000ff
+#define mqe_size_WORD word8
+#define mq_elem_cnt_SHIFT 16
+#define mq_elem_cnt_MASK 0x000000ff
+#define mq_elem_cnt_WORD word8
+ uint32_t word9;
+#define wq_pages_SHIFT 0
+#define wq_pages_MASK 0x0000ffff
+#define wq_pages_WORD word9
+#define wqe_size_SHIFT 8
+#define wqe_size_MASK 0x000000ff
+#define wqe_size_WORD word9
+ uint32_t word10;
+#define rq_pages_SHIFT 0
+#define rq_pages_MASK 0x0000ffff
+#define rq_pages_WORD word10
+#define rqe_size_SHIFT 8
+#define rqe_size_MASK 0x000000ff
+#define rqe_size_WORD word10
+ uint32_t word11;
+#define hdr_pages_SHIFT 0
+#define hdr_pages_MASK 0x0000000f
+#define hdr_pages_WORD word11
+#define hdr_size_SHIFT 8
+#define hdr_size_MASK 0x0000000f
+#define hdr_size_WORD word11
+#define hdr_pp_align_SHIFT 16
+#define hdr_pp_align_MASK 0x0000ffff
+#define hdr_pp_align_WORD word11
+ uint32_t word12;
+#define sgl_pages_SHIFT 0
+#define sgl_pages_MASK 0x0000000f
+#define sgl_pages_WORD word12
+#define sgl_pp_align_SHIFT 16
+#define sgl_pp_align_MASK 0x0000ffff
+#define sgl_pp_align_WORD word12
+ uint32_t rsvd_13_63[51];
+};
+
/* Mailbox Completion Queue Error Messages */
#define MB_CQE_STATUS_SUCCESS 0x0
#define MB_CQE_STATUS_INSUFFICIENT_PRIVILEGES 0x1
@@ -1863,6 +2037,7 @@ struct lpfc_mqe {
struct lpfc_mbx_read_fcf_tbl read_fcf_tbl;
struct lpfc_mbx_add_fcf_tbl_entry add_fcf_entry;
struct lpfc_mbx_del_fcf_tbl_entry del_fcf_entry;
+ struct lpfc_mbx_redisc_fcf_tbl redisc_fcf_tbl;
struct lpfc_mbx_reg_fcfi reg_fcfi;
struct lpfc_mbx_unreg_fcfi unreg_fcfi;
struct lpfc_mbx_mq_create mq_create;
@@ -1883,6 +2058,8 @@ struct lpfc_mqe {
struct lpfc_mbx_request_features req_ftrs;
struct lpfc_mbx_post_hdr_tmpl hdr_tmpl;
struct lpfc_mbx_query_fw_cfg query_fw_cfg;
+ struct lpfc_mbx_supp_pages supp_pages;
+ struct lpfc_mbx_sli4_params sli4_params;
struct lpfc_mbx_nop nop;
} un;
};
@@ -1959,6 +2136,9 @@ struct lpfc_acqe_link {
#define LPFC_ASYNC_LINK_FAULT_NONE 0x0
#define LPFC_ASYNC_LINK_FAULT_LOCAL 0x1
#define LPFC_ASYNC_LINK_FAULT_REMOTE 0x2
+#define lpfc_acqe_qos_link_speed_SHIFT 16
+#define lpfc_acqe_qos_link_speed_MASK 0x0000FFFF
+#define lpfc_acqe_qos_link_speed_WORD word1
uint32_t event_tag;
uint32_t trailer;
};
@@ -1976,6 +2156,7 @@ struct lpfc_acqe_fcoe {
#define LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL 0x2
#define LPFC_FCOE_EVENT_TYPE_FCF_DEAD 0x3
#define LPFC_FCOE_EVENT_TYPE_CVL 0x4
+#define LPFC_FCOE_EVENT_TYPE_FCF_PARAM_MOD 0x5
uint32_t event_tag;
uint32_t trailer;
};
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index b8eb1b6e5e77..d29ac7c317d9 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2009 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2010 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -544,7 +544,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
}
- } else {
+ } else if (phba->cfg_suppress_link_up == 0) {
lpfc_init_link(phba, pmb, phba->cfg_topology,
phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
@@ -603,6 +603,102 @@ lpfc_config_port_post(struct lpfc_hba *phba)
}
/**
+ * lpfc_hba_init_link - Initialize the FC link
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine will issue the INIT_LINK mailbox command call.
+ * It is available to other drivers through the lpfc_hba data
+ * structure for use as a delayed link up mechanism with the
+ * module parameter lpfc_suppress_link_up.
+ *
+ * Return code
+ * 0 - success
+ * Any other value - error
+ **/
+int
+lpfc_hba_init_link(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *vport = phba->pport;
+ LPFC_MBOXQ_t *pmb;
+ MAILBOX_t *mb;
+ int rc;
+
+ pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmb) {
+ phba->link_state = LPFC_HBA_ERROR;
+ return -ENOMEM;
+ }
+ mb = &pmb->u.mb;
+ pmb->vport = vport;
+
+ lpfc_init_link(phba, pmb, phba->cfg_topology,
+ phba->cfg_link_speed);
+ pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ lpfc_set_loopback_flag(phba);
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if (rc != MBX_SUCCESS) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0498 Adapter failed to init, mbxCmd x%x "
+ "INIT_LINK, mbxStatus x%x\n",
+ mb->mbxCommand, mb->mbxStatus);
+ /* Clear all interrupt enable conditions */
+ writel(0, phba->HCregaddr);
+ readl(phba->HCregaddr); /* flush */
+ /* Clear all pending interrupts */
+ writel(0xffffffff, phba->HAregaddr);
+ readl(phba->HAregaddr); /* flush */
+ phba->link_state = LPFC_HBA_ERROR;
+ if (rc != MBX_BUSY)
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return -EIO;
+ }
+ phba->cfg_suppress_link_up = 0;
+
+ return 0;
+}
+
+/**
+ * lpfc_hba_down_link - this routine downs the FC link
+ *
+ * This routine will issue the DOWN_LINK mailbox command call.
+ * It is available to other drivers through the lpfc_hba data
+ * structure for use to stop the link.
+ *
+ * Return code
+ * 0 - success
+ * Any other value - error
+ **/
+int
+lpfc_hba_down_link(struct lpfc_hba *phba)
+{
+ LPFC_MBOXQ_t *pmb;
+ int rc;
+
+ pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmb) {
+ phba->link_state = LPFC_HBA_ERROR;
+ return -ENOMEM;
+ }
+
+ lpfc_printf_log(phba,
+ KERN_ERR, LOG_INIT,
+ "0491 Adapter Link is disabled.\n");
+ lpfc_down_link(phba, pmb);
+ pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
+ lpfc_printf_log(phba,
+ KERN_ERR, LOG_INIT,
+ "2522 Adapter failed to issue DOWN_LINK"
+ " mbox command rc 0x%x\n", rc);
+
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
* lpfc_hba_down_prep - Perform lpfc uninitialization prior to HBA reset
* @phba: pointer to lpfc HBA data structure.
*
@@ -2073,6 +2169,44 @@ lpfc_stop_vport_timers(struct lpfc_vport *vport)
}
/**
+ * __lpfc_sli4_stop_fcf_redisc_wait_timer - Stop FCF rediscovery wait timer
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine stops the SLI4 FCF rediscover wait timer if it's on. The
+ * caller of this routine should already hold the host lock.
+ **/
+void
+__lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba)
+{
+ /* Clear pending FCF rediscovery wait timer */
+ phba->fcf.fcf_flag &= ~FCF_REDISC_PEND;
+ /* Now, try to stop the timer */
+ del_timer(&phba->fcf.redisc_wait);
+}
+
+/**
+ * lpfc_sli4_stop_fcf_redisc_wait_timer - Stop FCF rediscovery wait timer
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine stops the SLI4 FCF rediscover wait timer if it's on. It
+ * checks whether the FCF rediscovery wait timer is pending with the host
+ * lock held before proceeding with disabling the timer and clearing the
+ * wait timer pendig flag.
+ **/
+void
+lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba)
+{
+ spin_lock_irq(&phba->hbalock);
+ if (!(phba->fcf.fcf_flag & FCF_REDISC_PEND)) {
+ /* FCF rediscovery timer already fired or stopped */
+ spin_unlock_irq(&phba->hbalock);
+ return;
+ }
+ __lpfc_sli4_stop_fcf_redisc_wait_timer(phba);
+ spin_unlock_irq(&phba->hbalock);
+}
+
+/**
* lpfc_stop_hba_timers - Stop all the timers associated with an HBA
* @phba: pointer to lpfc hba data structure.
*
@@ -2096,6 +2230,7 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba)
break;
case LPFC_PCI_DEV_OC:
/* Stop any OneConnect device sepcific driver timers */
+ lpfc_sli4_stop_fcf_redisc_wait_timer(phba);
break;
default:
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -2228,6 +2363,7 @@ lpfc_offline_prep(struct lpfc_hba * phba)
struct lpfc_vport *vport = phba->pport;
struct lpfc_nodelist *ndlp, *next_ndlp;
struct lpfc_vport **vports;
+ struct Scsi_Host *shost;
int i;
if (vport->fc_flag & FC_OFFLINE_MODE)
@@ -2241,11 +2377,15 @@ lpfc_offline_prep(struct lpfc_hba * phba)
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL) {
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
- struct Scsi_Host *shost;
-
if (vports[i]->load_flag & FC_UNLOADING)
continue;
+ shost = lpfc_shost_from_vport(vports[i]);
+ spin_lock_irq(shost->host_lock);
vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED;
+ vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ vports[i]->fc_flag &= ~FC_VFI_REGISTERED;
+ spin_unlock_irq(shost->host_lock);
+
shost = lpfc_shost_from_vport(vports[i]);
list_for_each_entry_safe(ndlp, next_ndlp,
&vports[i]->fc_nodes,
@@ -2401,7 +2541,8 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
shost->this_id = -1;
shost->max_cmd_len = 16;
if (phba->sli_rev == LPFC_SLI_REV4) {
- shost->dma_boundary = LPFC_SLI4_MAX_SEGMENT_SIZE;
+ shost->dma_boundary =
+ phba->sli4_hba.pc_sli4_params.sge_supp_len;
shost->sg_tablesize = phba->cfg_sg_seg_cnt;
}
@@ -2650,8 +2791,6 @@ lpfc_stop_port_s4(struct lpfc_hba *phba)
lpfc_stop_hba_timers(phba);
phba->pport->work_port_events = 0;
phba->sli4_hba.intr_enable = 0;
- /* Hard clear it for now, shall have more graceful way to wait later */
- phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
}
/**
@@ -2703,7 +2842,7 @@ lpfc_sli_remove_dflt_fcf(struct lpfc_hba *phba)
del_fcf_record = &mboxq->u.mqe.un.del_fcf_entry;
bf_set(lpfc_mbx_del_fcf_tbl_count, del_fcf_record, 1);
bf_set(lpfc_mbx_del_fcf_tbl_index, del_fcf_record,
- phba->fcf.fcf_indx);
+ phba->fcf.current_rec.fcf_indx);
if (!phba->sli4_hba.intr_enable)
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
@@ -2727,6 +2866,57 @@ lpfc_sli_remove_dflt_fcf(struct lpfc_hba *phba)
}
/**
+ * lpfc_fcf_redisc_wait_start_timer - Start fcf rediscover wait timer
+ * @phba: Pointer to hba for which this call is being executed.
+ *
+ * This routine starts the timer waiting for the FCF rediscovery to complete.
+ **/
+void
+lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *phba)
+{
+ unsigned long fcf_redisc_wait_tmo =
+ (jiffies + msecs_to_jiffies(LPFC_FCF_REDISCOVER_WAIT_TMO));
+ /* Start fcf rediscovery wait period timer */
+ mod_timer(&phba->fcf.redisc_wait, fcf_redisc_wait_tmo);
+ spin_lock_irq(&phba->hbalock);
+ /* Allow action to new fcf asynchronous event */
+ phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE);
+ /* Mark the FCF rediscovery pending state */
+ phba->fcf.fcf_flag |= FCF_REDISC_PEND;
+ spin_unlock_irq(&phba->hbalock);
+}
+
+/**
+ * lpfc_sli4_fcf_redisc_wait_tmo - FCF table rediscover wait timeout
+ * @ptr: Map to lpfc_hba data structure pointer.
+ *
+ * This routine is invoked when waiting for FCF table rediscover has been
+ * timed out. If new FCF record(s) has (have) been discovered during the
+ * wait period, a new FCF event shall be added to the FCOE async event
+ * list, and then worker thread shall be waked up for processing from the
+ * worker thread context.
+ **/
+void
+lpfc_sli4_fcf_redisc_wait_tmo(unsigned long ptr)
+{
+ struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
+
+ /* Don't send FCF rediscovery event if timer cancelled */
+ spin_lock_irq(&phba->hbalock);
+ if (!(phba->fcf.fcf_flag & FCF_REDISC_PEND)) {
+ spin_unlock_irq(&phba->hbalock);
+ return;
+ }
+ /* Clear FCF rediscovery timer pending flag */
+ phba->fcf.fcf_flag &= ~FCF_REDISC_PEND;
+ /* FCF rediscovery event to worker thread */
+ phba->fcf.fcf_flag |= FCF_REDISC_EVT;
+ spin_unlock_irq(&phba->hbalock);
+ /* wake up worker thread */
+ lpfc_worker_wake_up(phba);
+}
+
+/**
* lpfc_sli4_fw_cfg_check - Read the firmware config and verify FCoE support
* @phba: pointer to lpfc hba data structure.
*
@@ -2978,6 +3168,8 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
bf_get(lpfc_acqe_link_physical, acqe_link);
phba->sli4_hba.link_state.fault =
bf_get(lpfc_acqe_link_fault, acqe_link);
+ phba->sli4_hba.link_state.logical_speed =
+ bf_get(lpfc_acqe_qos_link_speed, acqe_link);
/* Invoke the lpfc_handle_latt mailbox command callback function */
lpfc_mbx_cmpl_read_la(phba, pmb);
@@ -3007,22 +3199,34 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
struct lpfc_nodelist *ndlp;
struct Scsi_Host *shost;
uint32_t link_state;
+ int active_vlink_present;
+ struct lpfc_vport **vports;
+ int i;
phba->fc_eventTag = acqe_fcoe->event_tag;
phba->fcoe_eventtag = acqe_fcoe->event_tag;
switch (event_type) {
case LPFC_FCOE_EVENT_TYPE_NEW_FCF:
+ case LPFC_FCOE_EVENT_TYPE_FCF_PARAM_MOD:
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
"2546 New FCF found index 0x%x tag 0x%x\n",
acqe_fcoe->index,
acqe_fcoe->event_tag);
- /*
- * If the current FCF is in discovered state, or
- * FCF discovery is in progress do nothing.
- */
spin_lock_irq(&phba->hbalock);
- if ((phba->fcf.fcf_flag & FCF_DISCOVERED) ||
- (phba->hba_flag & FCF_DISC_INPROGRESS)) {
+ if ((phba->fcf.fcf_flag & FCF_SCAN_DONE) ||
+ (phba->hba_flag & FCF_DISC_INPROGRESS)) {
+ /*
+ * If the current FCF is in discovered state or
+ * FCF discovery is in progress, do nothing.
+ */
+ spin_unlock_irq(&phba->hbalock);
+ break;
+ }
+ if (phba->fcf.fcf_flag & FCF_REDISC_EVT) {
+ /*
+ * If fast FCF failover rescan event is pending,
+ * do nothing.
+ */
spin_unlock_irq(&phba->hbalock);
break;
}
@@ -3049,7 +3253,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
" tag 0x%x\n", acqe_fcoe->index,
acqe_fcoe->event_tag);
/* If the event is not for currently used fcf do nothing */
- if (phba->fcf.fcf_indx != acqe_fcoe->index)
+ if (phba->fcf.current_rec.fcf_indx != acqe_fcoe->index)
break;
/*
* Currently, driver support only one FCF - so treat this as
@@ -3074,14 +3278,58 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
if (!ndlp)
break;
shost = lpfc_shost_from_vport(vport);
+ if (phba->pport->port_state <= LPFC_FLOGI)
+ break;
+ /* If virtual link is not yet instantiated ignore CVL */
+ if (vport->port_state <= LPFC_FDISC)
+ break;
+
lpfc_linkdown_port(vport);
- if (vport->port_type != LPFC_NPIV_PORT) {
+ lpfc_cleanup_pending_mbox(vport);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_VPORT_CVL_RCVD;
+ spin_unlock_irq(shost->host_lock);
+ active_vlink_present = 0;
+
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports) {
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL;
+ i++) {
+ if ((!(vports[i]->fc_flag &
+ FC_VPORT_CVL_RCVD)) &&
+ (vports[i]->port_state > LPFC_FDISC)) {
+ active_vlink_present = 1;
+ break;
+ }
+ }
+ lpfc_destroy_vport_work_array(phba, vports);
+ }
+
+ if (active_vlink_present) {
+ /*
+ * If there are other active VLinks present,
+ * re-instantiate the Vlink using FDISC.
+ */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
spin_unlock_irq(shost->host_lock);
- ndlp->nlp_last_elscmd = ELS_CMD_FLOGI;
- vport->port_state = LPFC_FLOGI;
+ ndlp->nlp_last_elscmd = ELS_CMD_FDISC;
+ vport->port_state = LPFC_FDISC;
+ } else {
+ /*
+ * Otherwise, we request port to rediscover
+ * the entire FCF table for a fast recovery
+ * from possible case that the current FCF
+ * is no longer valid.
+ */
+ rc = lpfc_sli4_redisc_fcf_table(phba);
+ if (rc)
+ /*
+ * Last resort will be re-try on the
+ * the current registered FCF entry.
+ */
+ lpfc_retry_pport_discovery(phba);
}
break;
default:
@@ -3158,6 +3406,34 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *phba)
}
/**
+ * lpfc_sli4_fcf_redisc_event_proc - Process fcf table rediscovery event
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked by the worker thread to process FCF table
+ * rediscovery pending completion event.
+ **/
+void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *phba)
+{
+ int rc;
+
+ spin_lock_irq(&phba->hbalock);
+ /* Clear FCF rediscovery timeout event */
+ phba->fcf.fcf_flag &= ~FCF_REDISC_EVT;
+ /* Clear driver fast failover FCF record flag */
+ phba->fcf.failover_rec.flag = 0;
+ /* Set state for FCF fast failover */
+ phba->fcf.fcf_flag |= FCF_REDISC_FOV;
+ spin_unlock_irq(&phba->hbalock);
+
+ /* Scan FCF table from the first entry to re-discover SAN */
+ rc = lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
+ if (rc)
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "2747 Post FCF rediscovery read FCF record "
+ "failed 0x%x\n", rc);
+}
+
+/**
* lpfc_api_table_setup - Set up per hba pci-device group func api jump table
* @phba: pointer to lpfc hba data structure.
* @dev_grp: The HBA PCI-Device group number.
@@ -3442,8 +3718,10 @@ static int
lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
{
struct lpfc_sli *psli;
- int rc;
- int i, hbq_count;
+ LPFC_MBOXQ_t *mboxq;
+ int rc, i, hbq_count, buf_size, dma_buf_size, max_buf_size;
+ uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0};
+ struct lpfc_mqe *mqe;
/* Before proceed, wait for POST done and device ready */
rc = lpfc_sli4_post_status_check(phba);
@@ -3472,6 +3750,11 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
init_timer(&phba->eratt_poll);
phba->eratt_poll.function = lpfc_poll_eratt;
phba->eratt_poll.data = (unsigned long) phba;
+ /* FCF rediscover timer */
+ init_timer(&phba->fcf.redisc_wait);
+ phba->fcf.redisc_wait.function = lpfc_sli4_fcf_redisc_wait_tmo;
+ phba->fcf.redisc_wait.data = (unsigned long)phba;
+
/*
* We need to do a READ_CONFIG mailbox command here before
* calling lpfc_get_cfgparam. For VFs this will report the
@@ -3496,31 +3779,26 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
* used to create the sg_dma_buf_pool must be dynamically calculated.
* 2 segments are added since the IOCB needs a command and response bde.
* To insure that the scsi sgl does not cross a 4k page boundary only
- * sgl sizes of 1k, 2k, 4k, and 8k are supported.
- * Table of sgl sizes and seg_cnt:
- * sgl size, sg_seg_cnt total seg
- * 1k 50 52
- * 2k 114 116
- * 4k 242 244
- * 8k 498 500
- * cmd(32) + rsp(160) + (52 * sizeof(sli4_sge)) = 1024
- * cmd(32) + rsp(160) + (116 * sizeof(sli4_sge)) = 2048
- * cmd(32) + rsp(160) + (244 * sizeof(sli4_sge)) = 4096
- * cmd(32) + rsp(160) + (500 * sizeof(sli4_sge)) = 8192
+ * sgl sizes of must be a power of 2.
*/
- if (phba->cfg_sg_seg_cnt <= LPFC_DEFAULT_SG_SEG_CNT)
- phba->cfg_sg_seg_cnt = 50;
- else if (phba->cfg_sg_seg_cnt <= 114)
- phba->cfg_sg_seg_cnt = 114;
- else if (phba->cfg_sg_seg_cnt <= 242)
- phba->cfg_sg_seg_cnt = 242;
+ buf_size = (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp) +
+ ((phba->cfg_sg_seg_cnt + 2) * sizeof(struct sli4_sge)));
+ /* Feature Level 1 hardware is limited to 2 pages */
+ if ((bf_get(lpfc_sli_intf_featurelevel1, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_FEATURELEVEL1_1))
+ max_buf_size = LPFC_SLI4_FL1_MAX_BUF_SIZE;
else
- phba->cfg_sg_seg_cnt = 498;
-
- phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd)
- + sizeof(struct fcp_rsp);
- phba->cfg_sg_dma_buf_size +=
- ((phba->cfg_sg_seg_cnt + 2) * sizeof(struct sli4_sge));
+ max_buf_size = LPFC_SLI4_MAX_BUF_SIZE;
+ for (dma_buf_size = LPFC_SLI4_MIN_BUF_SIZE;
+ dma_buf_size < max_buf_size && buf_size > dma_buf_size;
+ dma_buf_size = dma_buf_size << 1)
+ ;
+ if (dma_buf_size == max_buf_size)
+ phba->cfg_sg_seg_cnt = (dma_buf_size -
+ sizeof(struct fcp_cmnd) - sizeof(struct fcp_rsp) -
+ (2 * sizeof(struct sli4_sge))) /
+ sizeof(struct sli4_sge);
+ phba->cfg_sg_dma_buf_size = dma_buf_size;
/* Initialize buffer queue management fields */
hbq_count = lpfc_sli_hbq_count();
@@ -3638,6 +3916,43 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
goto out_free_fcp_eq_hdl;
}
+ mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
+ GFP_KERNEL);
+ if (!mboxq) {
+ rc = -ENOMEM;
+ goto out_free_fcp_eq_hdl;
+ }
+
+ /* Get the Supported Pages. It is always available. */
+ lpfc_supported_pages(mboxq);
+ rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+ if (unlikely(rc)) {
+ rc = -EIO;
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ goto out_free_fcp_eq_hdl;
+ }
+
+ mqe = &mboxq->u.mqe;
+ memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3),
+ LPFC_MAX_SUPPORTED_PAGES);
+ for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) {
+ switch (pn_page[i]) {
+ case LPFC_SLI4_PARAMETERS:
+ phba->sli4_hba.pc_sli4_params.supported = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Read the port's SLI4 Parameters capabilities if supported. */
+ if (phba->sli4_hba.pc_sli4_params.supported)
+ rc = lpfc_pc_sli4_params_get(phba, mboxq);
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ if (rc) {
+ rc = -EIO;
+ goto out_free_fcp_eq_hdl;
+ }
return rc;
out_free_fcp_eq_hdl:
@@ -3733,6 +4048,8 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
int
lpfc_init_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
{
+ phba->lpfc_hba_init_link = lpfc_hba_init_link;
+ phba->lpfc_hba_down_link = lpfc_hba_down_link;
switch (dev_grp) {
case LPFC_PCI_DEV_LP:
phba->lpfc_hba_down_post = lpfc_hba_down_post_s3;
@@ -4291,7 +4608,7 @@ lpfc_hba_alloc(struct pci_dev *pdev)
return NULL;
}
- mutex_init(&phba->ct_event_mutex);
+ spin_lock_init(&phba->ct_ev_lock);
INIT_LIST_HEAD(&phba->ct_ev_waiters);
return phba;
@@ -4641,7 +4958,7 @@ lpfc_sli_pci_mem_unset(struct lpfc_hba *phba)
int
lpfc_sli4_post_status_check(struct lpfc_hba *phba)
{
- struct lpfc_register sta_reg, uerrlo_reg, uerrhi_reg, scratchpad;
+ struct lpfc_register sta_reg, uerrlo_reg, uerrhi_reg;
int i, port_error = -ENODEV;
if (!phba->sli4_hba.STAregaddr)
@@ -4677,14 +4994,21 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba)
bf_get(lpfc_hst_state_port_status, &sta_reg));
/* Log device information */
- scratchpad.word0 = readl(phba->sli4_hba.SCRATCHPADregaddr);
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "2534 Device Info: ChipType=0x%x, SliRev=0x%x, "
- "FeatureL1=0x%x, FeatureL2=0x%x\n",
- bf_get(lpfc_scratchpad_chiptype, &scratchpad),
- bf_get(lpfc_scratchpad_slirev, &scratchpad),
- bf_get(lpfc_scratchpad_featurelevel1, &scratchpad),
- bf_get(lpfc_scratchpad_featurelevel2, &scratchpad));
+ phba->sli4_hba.sli_intf.word0 = readl(phba->sli4_hba.SLIINTFregaddr);
+ if (bf_get(lpfc_sli_intf_valid,
+ &phba->sli4_hba.sli_intf) == LPFC_SLI_INTF_VALID) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2534 Device Info: ChipType=0x%x, SliRev=0x%x, "
+ "FeatureL1=0x%x, FeatureL2=0x%x\n",
+ bf_get(lpfc_sli_intf_sli_family,
+ &phba->sli4_hba.sli_intf),
+ bf_get(lpfc_sli_intf_slirev,
+ &phba->sli4_hba.sli_intf),
+ bf_get(lpfc_sli_intf_featurelevel1,
+ &phba->sli4_hba.sli_intf),
+ bf_get(lpfc_sli_intf_featurelevel2,
+ &phba->sli4_hba.sli_intf));
+ }
phba->sli4_hba.ue_mask_lo = readl(phba->sli4_hba.UEMASKLOregaddr);
phba->sli4_hba.ue_mask_hi = readl(phba->sli4_hba.UEMASKHIregaddr);
/* With uncoverable error, log the error message and return error */
@@ -4723,8 +5047,8 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba)
LPFC_UE_MASK_LO;
phba->sli4_hba.UEMASKHIregaddr = phba->sli4_hba.conf_regs_memmap_p +
LPFC_UE_MASK_HI;
- phba->sli4_hba.SCRATCHPADregaddr = phba->sli4_hba.conf_regs_memmap_p +
- LPFC_SCRATCHPAD;
+ phba->sli4_hba.SLIINTFregaddr = phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_SLI_INTF;
}
/**
@@ -5999,7 +6323,7 @@ lpfc_sli4_fcfi_unreg(struct lpfc_hba *phba, uint16_t fcfi)
spin_lock_irqsave(&phba->hbalock, flags);
/* Mark the FCFI is no longer registered */
phba->fcf.fcf_flag &=
- ~(FCF_AVAILABLE | FCF_REGISTERED | FCF_DISCOVERED);
+ ~(FCF_AVAILABLE | FCF_REGISTERED | FCF_SCAN_DONE);
spin_unlock_irqrestore(&phba->hbalock, flags);
}
}
@@ -6039,16 +6363,20 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
/* Get the bus address of SLI4 device Bar0, Bar1, and Bar2 and the
* number of bytes required by each mapping. They are actually
- * mapping to the PCI BAR regions 1, 2, and 4 by the SLI4 device.
+ * mapping to the PCI BAR regions 0 or 1, 2, and 4 by the SLI4 device.
*/
- phba->pci_bar0_map = pci_resource_start(pdev, LPFC_SLI4_BAR0);
- bar0map_len = pci_resource_len(pdev, LPFC_SLI4_BAR0);
-
- phba->pci_bar1_map = pci_resource_start(pdev, LPFC_SLI4_BAR1);
- bar1map_len = pci_resource_len(pdev, LPFC_SLI4_BAR1);
+ if (pci_resource_start(pdev, 0)) {
+ phba->pci_bar0_map = pci_resource_start(pdev, 0);
+ bar0map_len = pci_resource_len(pdev, 0);
+ } else {
+ phba->pci_bar0_map = pci_resource_start(pdev, 1);
+ bar0map_len = pci_resource_len(pdev, 1);
+ }
+ phba->pci_bar1_map = pci_resource_start(pdev, 2);
+ bar1map_len = pci_resource_len(pdev, 2);
- phba->pci_bar2_map = pci_resource_start(pdev, LPFC_SLI4_BAR2);
- bar2map_len = pci_resource_len(pdev, LPFC_SLI4_BAR2);
+ phba->pci_bar2_map = pci_resource_start(pdev, 4);
+ bar2map_len = pci_resource_len(pdev, 4);
/* Map SLI4 PCI Config Space Register base to a kernel virtual addr */
phba->sli4_hba.conf_regs_memmap_p =
@@ -6793,6 +7121,73 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
phba->pport->work_port_events = 0;
}
+ /**
+ * lpfc_pc_sli4_params_get - Get the SLI4_PARAMS port capabilities.
+ * @phba: Pointer to HBA context object.
+ * @mboxq: Pointer to the mailboxq memory for the mailbox command response.
+ *
+ * This function is called in the SLI4 code path to read the port's
+ * sli4 capabilities.
+ *
+ * This function may be be called from any context that can block-wait
+ * for the completion. The expectation is that this routine is called
+ * typically from probe_one or from the online routine.
+ **/
+int
+lpfc_pc_sli4_params_get(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+ int rc;
+ struct lpfc_mqe *mqe;
+ struct lpfc_pc_sli4_params *sli4_params;
+ uint32_t mbox_tmo;
+
+ rc = 0;
+ mqe = &mboxq->u.mqe;
+
+ /* Read the port's SLI4 Parameters port capabilities */
+ lpfc_sli4_params(mboxq);
+ if (!phba->sli4_hba.intr_enable)
+ rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+ else {
+ mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_PORT_CAPABILITIES);
+ rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
+ }
+
+ if (unlikely(rc))
+ return 1;
+
+ sli4_params = &phba->sli4_hba.pc_sli4_params;
+ sli4_params->if_type = bf_get(if_type, &mqe->un.sli4_params);
+ sli4_params->sli_rev = bf_get(sli_rev, &mqe->un.sli4_params);
+ sli4_params->sli_family = bf_get(sli_family, &mqe->un.sli4_params);
+ sli4_params->featurelevel_1 = bf_get(featurelevel_1,
+ &mqe->un.sli4_params);
+ sli4_params->featurelevel_2 = bf_get(featurelevel_2,
+ &mqe->un.sli4_params);
+ sli4_params->proto_types = mqe->un.sli4_params.word3;
+ sli4_params->sge_supp_len = mqe->un.sli4_params.sge_supp_len;
+ sli4_params->if_page_sz = bf_get(if_page_sz, &mqe->un.sli4_params);
+ sli4_params->rq_db_window = bf_get(rq_db_window, &mqe->un.sli4_params);
+ sli4_params->loopbk_scope = bf_get(loopbk_scope, &mqe->un.sli4_params);
+ sli4_params->eq_pages_max = bf_get(eq_pages, &mqe->un.sli4_params);
+ sli4_params->eqe_size = bf_get(eqe_size, &mqe->un.sli4_params);
+ sli4_params->cq_pages_max = bf_get(cq_pages, &mqe->un.sli4_params);
+ sli4_params->cqe_size = bf_get(cqe_size, &mqe->un.sli4_params);
+ sli4_params->mq_pages_max = bf_get(mq_pages, &mqe->un.sli4_params);
+ sli4_params->mqe_size = bf_get(mqe_size, &mqe->un.sli4_params);
+ sli4_params->mq_elem_cnt = bf_get(mq_elem_cnt, &mqe->un.sli4_params);
+ sli4_params->wq_pages_max = bf_get(wq_pages, &mqe->un.sli4_params);
+ sli4_params->wqe_size = bf_get(wqe_size, &mqe->un.sli4_params);
+ sli4_params->rq_pages_max = bf_get(rq_pages, &mqe->un.sli4_params);
+ sli4_params->rqe_size = bf_get(rqe_size, &mqe->un.sli4_params);
+ sli4_params->hdr_pages_max = bf_get(hdr_pages, &mqe->un.sli4_params);
+ sli4_params->hdr_size = bf_get(hdr_size, &mqe->un.sli4_params);
+ sli4_params->hdr_pp_align = bf_get(hdr_pp_align, &mqe->un.sli4_params);
+ sli4_params->sgl_pages_max = bf_get(sgl_pages, &mqe->un.sli4_params);
+ sli4_params->sgl_pp_align = bf_get(sgl_pp_align, &mqe->un.sli4_params);
+ return rc;
+}
+
/**
* lpfc_pci_probe_one_s3 - PCI probe func to reg SLI-3 device to PCI subsystem.
* @pdev: pointer to PCI device
@@ -7134,6 +7529,12 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
+ /*
+ * As the new kernel behavior of pci_restore_state() API call clears
+ * device saved_state flag, need to save the restored state again.
+ */
+ pci_save_state(pdev);
+
if (pdev->is_busmaster)
pci_set_master(pdev);
@@ -7317,6 +7718,13 @@ lpfc_io_slot_reset_s3(struct pci_dev *pdev)
}
pci_restore_state(pdev);
+
+ /*
+ * As the new kernel behavior of pci_restore_state() API call clears
+ * device saved_state flag, need to save the restored state again.
+ */
+ pci_save_state(pdev);
+
if (pdev->is_busmaster)
pci_set_master(pdev);
@@ -7726,6 +8134,13 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev)
/* Restore device state from PCI config space */
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
+
+ /*
+ * As the new kernel behavior of pci_restore_state() API call clears
+ * device saved_state flag, need to save the restored state again.
+ */
+ pci_save_state(pdev);
+
if (pdev->is_busmaster)
pci_set_master(pdev);
@@ -7845,11 +8260,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
int rc;
struct lpfc_sli_intf intf;
- if (pci_read_config_dword(pdev, LPFC_SLIREV_CONF_WORD, &intf.word0))
+ if (pci_read_config_dword(pdev, LPFC_SLI_INTF, &intf.word0))
return -ENODEV;
if ((bf_get(lpfc_sli_intf_valid, &intf) == LPFC_SLI_INTF_VALID) &&
- (bf_get(lpfc_sli_intf_rev, &intf) == LPFC_SLIREV_CONF_SLI4))
+ (bf_get(lpfc_sli_intf_slirev, &intf) == LPFC_SLI_INTF_REV_SLI4))
rc = lpfc_pci_probe_one_s4(pdev, pid);
else
rc = lpfc_pci_probe_one_s3(pdev, pid);
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index a9afd8b94b6a..6c4dce1a30ca 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -1707,7 +1707,8 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
alloc_len - sizeof(union lpfc_sli4_cfg_shdr);
}
/* The sub-header is in DMA memory, which needs endian converstion */
- lpfc_sli_pcimem_bcopy(cfg_shdr, cfg_shdr,
+ if (cfg_shdr)
+ lpfc_sli_pcimem_bcopy(cfg_shdr, cfg_shdr,
sizeof(union lpfc_sli4_cfg_shdr));
return alloc_len;
@@ -1747,6 +1748,65 @@ lpfc_sli4_mbox_opcode_get(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
}
/**
+ * lpfc_sli4_mbx_read_fcf_record - Allocate and construct read fcf mbox cmd
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index: index to fcf table.
+ *
+ * This routine routine allocates and constructs non-embedded mailbox command
+ * for reading a FCF table entry refered by @fcf_index.
+ *
+ * Return: pointer to the mailbox command constructed if successful, otherwise
+ * NULL.
+ **/
+int
+lpfc_sli4_mbx_read_fcf_record(struct lpfc_hba *phba,
+ struct lpfcMboxq *mboxq,
+ uint16_t fcf_index)
+{
+ void *virt_addr;
+ dma_addr_t phys_addr;
+ uint8_t *bytep;
+ struct lpfc_mbx_sge sge;
+ uint32_t alloc_len, req_len;
+ struct lpfc_mbx_read_fcf_tbl *read_fcf;
+
+ if (!mboxq)
+ return -ENOMEM;
+
+ req_len = sizeof(struct fcf_record) +
+ sizeof(union lpfc_sli4_cfg_shdr) + 2 * sizeof(uint32_t);
+
+ /* Set up READ_FCF SLI4_CONFIG mailbox-ioctl command */
+ alloc_len = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
+ LPFC_MBOX_OPCODE_FCOE_READ_FCF_TABLE, req_len,
+ LPFC_SLI4_MBX_NEMBED);
+
+ if (alloc_len < req_len) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+ "0291 Allocated DMA memory size (x%x) is "
+ "less than the requested DMA memory "
+ "size (x%x)\n", alloc_len, req_len);
+ return -ENOMEM;
+ }
+
+ /* Get the first SGE entry from the non-embedded DMA memory. This
+ * routine only uses a single SGE.
+ */
+ lpfc_sli4_mbx_sge_get(mboxq, 0, &sge);
+ phys_addr = getPaddr(sge.pa_hi, sge.pa_lo);
+ virt_addr = mboxq->sge_array->addr[0];
+ read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr;
+
+ /* Set up command fields */
+ bf_set(lpfc_mbx_read_fcf_tbl_indx, &read_fcf->u.request, fcf_index);
+ /* Perform necessary endian conversion */
+ bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr);
+ lpfc_sli_pcimem_bcopy(bytep, bytep, sizeof(uint32_t));
+
+ return 0;
+}
+
+/**
* lpfc_request_features: Configure SLI4 REQUEST_FEATURES mailbox
* @mboxq: pointer to lpfc mbox command.
*
@@ -1946,13 +2006,14 @@ lpfc_reg_fcfi(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
bf_set(lpfc_reg_fcfi_rq_id1, reg_fcfi, REG_FCF_INVALID_QID);
bf_set(lpfc_reg_fcfi_rq_id2, reg_fcfi, REG_FCF_INVALID_QID);
bf_set(lpfc_reg_fcfi_rq_id3, reg_fcfi, REG_FCF_INVALID_QID);
- bf_set(lpfc_reg_fcfi_info_index, reg_fcfi, phba->fcf.fcf_indx);
+ bf_set(lpfc_reg_fcfi_info_index, reg_fcfi,
+ phba->fcf.current_rec.fcf_indx);
/* reg_fcf addr mode is bit wise inverted value of fcf addr_mode */
- bf_set(lpfc_reg_fcfi_mam, reg_fcfi,
- (~phba->fcf.addr_mode) & 0x3);
- if (phba->fcf.fcf_flag & FCF_VALID_VLAN) {
+ bf_set(lpfc_reg_fcfi_mam, reg_fcfi, (~phba->fcf.addr_mode) & 0x3);
+ if (phba->fcf.current_rec.vlan_id != 0xFFFF) {
bf_set(lpfc_reg_fcfi_vv, reg_fcfi, 1);
- bf_set(lpfc_reg_fcfi_vlan_tag, reg_fcfi, phba->fcf.vlan_id);
+ bf_set(lpfc_reg_fcfi_vlan_tag, reg_fcfi,
+ phba->fcf.current_rec.vlan_id);
}
}
@@ -1992,3 +2053,41 @@ lpfc_resume_rpi(struct lpfcMboxq *mbox, struct lpfc_nodelist *ndlp)
bf_set(lpfc_resume_rpi_ii, resume_rpi, RESUME_INDEX_RPI);
resume_rpi->event_tag = ndlp->phba->fc_eventTag;
}
+
+/**
+ * lpfc_supported_pages - Initialize the PORT_CAPABILITIES supported pages
+ * mailbox command.
+ * @mbox: pointer to lpfc mbox command to initialize.
+ *
+ * The PORT_CAPABILITIES supported pages mailbox command is issued to
+ * retrieve the particular feature pages supported by the port.
+ **/
+void
+lpfc_supported_pages(struct lpfcMboxq *mbox)
+{
+ struct lpfc_mbx_supp_pages *supp_pages;
+
+ memset(mbox, 0, sizeof(*mbox));
+ supp_pages = &mbox->u.mqe.un.supp_pages;
+ bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_PORT_CAPABILITIES);
+ bf_set(cpn, supp_pages, LPFC_SUPP_PAGES);
+}
+
+/**
+ * lpfc_sli4_params - Initialize the PORT_CAPABILITIES SLI4 Params
+ * mailbox command.
+ * @mbox: pointer to lpfc mbox command to initialize.
+ *
+ * The PORT_CAPABILITIES SLI4 parameters mailbox command is issued to
+ * retrieve the particular SLI4 features supported by the port.
+ **/
+void
+lpfc_sli4_params(struct lpfcMboxq *mbox)
+{
+ struct lpfc_mbx_sli4_params *sli4_params;
+
+ memset(mbox, 0, sizeof(*mbox));
+ sli4_params = &mbox->u.mqe.un.sli4_params;
+ bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_PORT_CAPABILITIES);
+ bf_set(cpn, sli4_params, LPFC_SLI4_PARAMETERS);
+}
diff --git a/drivers/scsi/lpfc/lpfc_nl.h b/drivers/scsi/lpfc/lpfc_nl.h
index d655ed3eebef..f3cfbe2ce986 100644
--- a/drivers/scsi/lpfc/lpfc_nl.h
+++ b/drivers/scsi/lpfc/lpfc_nl.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2008 Emulex. All rights reserved. *
+ * Copyright (C) 2010 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -177,23 +177,3 @@ struct temp_event {
uint32_t data;
};
-/* bsg definitions */
-#define LPFC_BSG_VENDOR_SET_CT_EVENT 1
-#define LPFC_BSG_VENDOR_GET_CT_EVENT 2
-
-struct set_ct_event {
- uint32_t command;
- uint32_t ev_req_id;
- uint32_t ev_reg_id;
-};
-
-struct get_ct_event {
- uint32_t command;
- uint32_t ev_reg_id;
- uint32_t ev_req_id;
-};
-
-struct get_ct_event_reply {
- uint32_t immed_data;
- uint32_t type;
-};
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 2ed6af194932..d20ae6b3b3cf 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -62,7 +62,7 @@ lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
int
lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- struct serv_parm * sp, uint32_t class)
+ struct serv_parm *sp, uint32_t class, int flogi)
{
volatile struct serv_parm *hsp = &vport->fc_sparam;
uint16_t hsp_value, ssp_value = 0;
@@ -75,49 +75,56 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
* correcting the byte values.
*/
if (sp->cls1.classValid) {
- hsp_value = (hsp->cls1.rcvDataSizeMsb << 8) |
- hsp->cls1.rcvDataSizeLsb;
- ssp_value = (sp->cls1.rcvDataSizeMsb << 8) |
- sp->cls1.rcvDataSizeLsb;
- if (!ssp_value)
- goto bad_service_param;
- if (ssp_value > hsp_value) {
- sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb;
- sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb;
+ if (!flogi) {
+ hsp_value = ((hsp->cls1.rcvDataSizeMsb << 8) |
+ hsp->cls1.rcvDataSizeLsb);
+ ssp_value = ((sp->cls1.rcvDataSizeMsb << 8) |
+ sp->cls1.rcvDataSizeLsb);
+ if (!ssp_value)
+ goto bad_service_param;
+ if (ssp_value > hsp_value) {
+ sp->cls1.rcvDataSizeLsb =
+ hsp->cls1.rcvDataSizeLsb;
+ sp->cls1.rcvDataSizeMsb =
+ hsp->cls1.rcvDataSizeMsb;
+ }
}
- } else if (class == CLASS1) {
+ } else if (class == CLASS1)
goto bad_service_param;
- }
-
if (sp->cls2.classValid) {
- hsp_value = (hsp->cls2.rcvDataSizeMsb << 8) |
- hsp->cls2.rcvDataSizeLsb;
- ssp_value = (sp->cls2.rcvDataSizeMsb << 8) |
- sp->cls2.rcvDataSizeLsb;
- if (!ssp_value)
- goto bad_service_param;
- if (ssp_value > hsp_value) {
- sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb;
- sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb;
+ if (!flogi) {
+ hsp_value = ((hsp->cls2.rcvDataSizeMsb << 8) |
+ hsp->cls2.rcvDataSizeLsb);
+ ssp_value = ((sp->cls2.rcvDataSizeMsb << 8) |
+ sp->cls2.rcvDataSizeLsb);
+ if (!ssp_value)
+ goto bad_service_param;
+ if (ssp_value > hsp_value) {
+ sp->cls2.rcvDataSizeLsb =
+ hsp->cls2.rcvDataSizeLsb;
+ sp->cls2.rcvDataSizeMsb =
+ hsp->cls2.rcvDataSizeMsb;
+ }
}
- } else if (class == CLASS2) {
+ } else if (class == CLASS2)
goto bad_service_param;
- }
-
if (sp->cls3.classValid) {
- hsp_value = (hsp->cls3.rcvDataSizeMsb << 8) |
- hsp->cls3.rcvDataSizeLsb;
- ssp_value = (sp->cls3.rcvDataSizeMsb << 8) |
- sp->cls3.rcvDataSizeLsb;
- if (!ssp_value)
- goto bad_service_param;
- if (ssp_value > hsp_value) {
- sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb;
- sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb;
+ if (!flogi) {
+ hsp_value = ((hsp->cls3.rcvDataSizeMsb << 8) |
+ hsp->cls3.rcvDataSizeLsb);
+ ssp_value = ((sp->cls3.rcvDataSizeMsb << 8) |
+ sp->cls3.rcvDataSizeLsb);
+ if (!ssp_value)
+ goto bad_service_param;
+ if (ssp_value > hsp_value) {
+ sp->cls3.rcvDataSizeLsb =
+ hsp->cls3.rcvDataSizeLsb;
+ sp->cls3.rcvDataSizeMsb =
+ hsp->cls3.rcvDataSizeMsb;
+ }
}
- } else if (class == CLASS3) {
+ } else if (class == CLASS3)
goto bad_service_param;
- }
/*
* Preserve the upper four bits of the MSB from the PLOGI response.
@@ -247,7 +254,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
int rc;
memset(&stat, 0, sizeof (struct ls_rjt));
- if (vport->port_state <= LPFC_FLOGI) {
+ if (vport->port_state <= LPFC_FDISC) {
/* Before responding to PLOGI, check for pt2pt mode.
* If we are pt2pt, with an outstanding FLOGI, abort
* the FLOGI and resend it first.
@@ -295,7 +302,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
NULL);
return 0;
}
- if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) {
+ if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0) == 0)) {
/* Reject this request because invalid parameters */
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
@@ -831,7 +838,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
"0142 PLOGI RSP: Invalid WWN.\n");
goto out;
}
- if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3))
+ if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0))
goto out;
/* PLOGI chkparm OK */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index a246410ce9df..483fb74bc592 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -626,6 +626,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
&phba->sli4_hba.lpfc_abts_scsi_buf_list, list) {
if (psb->cur_iocbq.sli4_xritag == xri) {
list_del(&psb->list);
+ psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
spin_unlock_irqrestore(
&phba->sli4_hba.abts_scsi_buf_list_lock,
@@ -688,11 +689,12 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
list);
if (status) {
/* Put this back on the abort scsi list */
- psb->status = IOSTAT_LOCAL_REJECT;
- psb->result = IOERR_ABORT_REQUESTED;
+ psb->exch_busy = 1;
rc++;
- } else
+ } else {
+ psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
+ }
/* Put it back into the SCSI buffer list */
lpfc_release_scsi_buf_s4(phba, psb);
}
@@ -796,19 +798,17 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
*/
sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd));
sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd));
- bf_set(lpfc_sli4_sge_len, sgl, sizeof(struct fcp_cmnd));
bf_set(lpfc_sli4_sge_last, sgl, 0);
sgl->word2 = cpu_to_le32(sgl->word2);
- sgl->word3 = cpu_to_le32(sgl->word3);
+ sgl->sge_len = cpu_to_le32(sizeof(struct fcp_cmnd));
sgl++;
/* Setup the physical region for the FCP RSP */
sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_rsp));
sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_rsp));
- bf_set(lpfc_sli4_sge_len, sgl, sizeof(struct fcp_rsp));
bf_set(lpfc_sli4_sge_last, sgl, 1);
sgl->word2 = cpu_to_le32(sgl->word2);
- sgl->word3 = cpu_to_le32(sgl->word3);
+ sgl->sge_len = cpu_to_le32(sizeof(struct fcp_rsp));
/*
* Since the IOCB for the FCP I/O is built into this
@@ -839,11 +839,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
psb->cur_iocbq.sli4_xritag);
if (status) {
/* Put this back on the abort scsi list */
- psb->status = IOSTAT_LOCAL_REJECT;
- psb->result = IOERR_ABORT_REQUESTED;
+ psb->exch_busy = 1;
rc++;
- } else
+ } else {
+ psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
+ }
/* Put it back into the SCSI buffer list */
lpfc_release_scsi_buf_s4(phba, psb);
break;
@@ -857,11 +858,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
list);
if (status) {
/* Put this back on the abort scsi list */
- psb->status = IOSTAT_LOCAL_REJECT;
- psb->result = IOERR_ABORT_REQUESTED;
+ psb->exch_busy = 1;
rc++;
- } else
+ } else {
+ psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
+ }
/* Put it back into the SCSI buffer list */
lpfc_release_scsi_buf_s4(phba, psb);
}
@@ -951,8 +953,7 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
{
unsigned long iflag = 0;
- if (psb->status == IOSTAT_LOCAL_REJECT
- && psb->result == IOERR_ABORT_REQUESTED) {
+ if (psb->exch_busy) {
spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock,
iflag);
psb->pCmd = NULL;
@@ -1574,7 +1575,7 @@ lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba,
case LPFC_PG_TYPE_NO_DIF:
num_bde = lpfc_bg_setup_bpl(phba, scsi_cmnd, bpl,
datasegcnt);
- /* we shoud have 2 or more entries in buffer list */
+ /* we should have 2 or more entries in buffer list */
if (num_bde < 2)
goto err;
break;
@@ -1611,7 +1612,7 @@ lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba,
num_bde = lpfc_bg_setup_bpl_prot(phba, scsi_cmnd, bpl,
datasegcnt, protsegcnt);
- /* we shoud have 3 or more entries in buffer list */
+ /* we should have 3 or more entries in buffer list */
if (num_bde < 3)
goto err;
break;
@@ -1869,7 +1870,6 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
scsi_for_each_sg(scsi_cmnd, sgel, nseg, num_bde) {
physaddr = sg_dma_address(sgel);
dma_len = sg_dma_len(sgel);
- bf_set(lpfc_sli4_sge_len, sgl, sg_dma_len(sgel));
sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr));
sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr));
if ((num_bde + 1) == nseg)
@@ -1878,7 +1878,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
bf_set(lpfc_sli4_sge_last, sgl, 0);
bf_set(lpfc_sli4_sge_offset, sgl, dma_offset);
sgl->word2 = cpu_to_le32(sgl->word2);
- sgl->word3 = cpu_to_le32(sgl->word3);
+ sgl->sge_len = cpu_to_le32(dma_len);
dma_offset += dma_len;
sgl++;
}
@@ -2221,6 +2221,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
+ /* pick up SLI4 exhange busy status from HBA */
+ lpfc_cmd->exch_busy = pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY;
+
if (pnode && NLP_CHK_NODE_ACT(pnode))
atomic_dec(&pnode->cmd_pending);
@@ -2637,6 +2640,7 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
}
phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf;
phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth;
+ phba->lpfc_scsi_cmd_iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl;
return 0;
}
@@ -2695,6 +2699,13 @@ lpfc_info(struct Scsi_Host *host)
" port %s",
phba->Port);
}
+ len = strlen(lpfcinfobuf);
+ if (phba->sli4_hba.link_state.logical_speed) {
+ snprintf(lpfcinfobuf + len,
+ 384-len,
+ " Logical Link Speed: %d Mbps",
+ phba->sli4_hba.link_state.logical_speed * 10);
+ }
}
return lpfcinfobuf;
}
@@ -2990,6 +3001,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
/* ABTS WQE must go to the same WQ as the WQE to be aborted */
abtsiocb->fcp_wqidx = iocb->fcp_wqidx;
+ abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX;
if (lpfc_is_link_up(phba))
icmd->ulpCommand = CMD_ABORT_XRI_CN;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index 65dfc8bd5b49..5932273870a5 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -118,6 +118,7 @@ struct lpfc_scsi_buf {
uint32_t timeout;
+ uint16_t exch_busy; /* SLI4 hba reported XB on complete WCQE */
uint16_t status; /* From IOCB Word 7- ulpStatus */
uint32_t result; /* From IOCB Word 4. */
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 589549b2bf0e..35e3b96d4e07 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -580,10 +580,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
else
sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag);
if (sglq) {
- if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED
- && ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT)
- && (iocbq->iocb.un.ulpWord[4]
- == IOERR_ABORT_REQUESTED))) {
+ if (iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) {
spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock,
iflag);
list_add(&sglq->list,
@@ -764,10 +761,6 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
case DSSCMD_IWRITE64_CX:
case DSSCMD_IREAD64_CR:
case DSSCMD_IREAD64_CX:
- case DSSCMD_INVALIDATE_DEK:
- case DSSCMD_SET_KEK:
- case DSSCMD_GET_KEK_ID:
- case DSSCMD_GEN_XFER:
type = LPFC_SOL_IOCB;
break;
case CMD_ABORT_XRI_CN:
@@ -1717,6 +1710,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
struct lpfc_dmabuf *mp;
uint16_t rpi, vpi;
int rc;
+ struct lpfc_vport *vport = pmb->vport;
mp = (struct lpfc_dmabuf *) (pmb->context1);
@@ -1745,6 +1739,18 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
return;
}
+ /* Unreg VPI, if the REG_VPI succeed after VLink failure */
+ if ((pmb->u.mb.mbxCommand == MBX_REG_VPI) &&
+ !(phba->pport->load_flag & FC_UNLOADING) &&
+ !pmb->u.mb.mbxStatus) {
+ lpfc_unreg_vpi(phba, pmb->u.mb.un.varRegVpi.vpi, pmb);
+ pmb->vport = vport;
+ pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if (rc != MBX_NOT_FINISHED)
+ return;
+ }
+
if (bf_get(lpfc_mqe_command, &pmb->u.mqe) == MBX_SLI4_CONFIG)
lpfc_sli4_mbox_cmd_free(phba, pmb);
else
@@ -2228,9 +2234,15 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
* All other are passed to the completion callback.
*/
if (pring->ringno == LPFC_ELS_RING) {
- if (cmdiocbp->iocb_flag & LPFC_DRIVER_ABORTED) {
+ if ((phba->sli_rev < LPFC_SLI_REV4) &&
+ (cmdiocbp->iocb_flag &
+ LPFC_DRIVER_ABORTED)) {
+ spin_lock_irqsave(&phba->hbalock,
+ iflag);
cmdiocbp->iocb_flag &=
~LPFC_DRIVER_ABORTED;
+ spin_unlock_irqrestore(&phba->hbalock,
+ iflag);
saveq->iocb.ulpStatus =
IOSTAT_LOCAL_REJECT;
saveq->iocb.un.ulpWord[4] =
@@ -2240,7 +2252,47 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
* of DMAing payload, so don't free data
* buffer till after a hbeat.
*/
+ spin_lock_irqsave(&phba->hbalock,
+ iflag);
saveq->iocb_flag |= LPFC_DELAY_MEM_FREE;
+ spin_unlock_irqrestore(&phba->hbalock,
+ iflag);
+ }
+ if ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (saveq->iocb_flag & LPFC_EXCHANGE_BUSY)) {
+ /* Set cmdiocb flag for the exchange
+ * busy so sgl (xri) will not be
+ * released until the abort xri is
+ * received from hba, clear the
+ * LPFC_DRIVER_ABORTED bit in case
+ * it was driver initiated abort.
+ */
+ spin_lock_irqsave(&phba->hbalock,
+ iflag);
+ cmdiocbp->iocb_flag &=
+ ~LPFC_DRIVER_ABORTED;
+ cmdiocbp->iocb_flag |=
+ LPFC_EXCHANGE_BUSY;
+ spin_unlock_irqrestore(&phba->hbalock,
+ iflag);
+ cmdiocbp->iocb.ulpStatus =
+ IOSTAT_LOCAL_REJECT;
+ cmdiocbp->iocb.un.ulpWord[4] =
+ IOERR_ABORT_REQUESTED;
+ /*
+ * For SLI4, irsiocb contains NO_XRI
+ * in sli_xritag, it shall not affect
+ * releasing sgl (xri) process.
+ */
+ saveq->iocb.ulpStatus =
+ IOSTAT_LOCAL_REJECT;
+ saveq->iocb.un.ulpWord[4] =
+ IOERR_SLI_ABORTED;
+ spin_lock_irqsave(&phba->hbalock,
+ iflag);
+ saveq->iocb_flag |= LPFC_DELAY_MEM_FREE;
+ spin_unlock_irqrestore(&phba->hbalock,
+ iflag);
}
}
(cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
@@ -5687,19 +5739,19 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
for (i = 0; i < numBdes; i++) {
/* Should already be byte swapped. */
- sgl->addr_hi = bpl->addrHigh;
- sgl->addr_lo = bpl->addrLow;
- /* swap the size field back to the cpu so we
- * can assign it to the sgl.
- */
- bde.tus.w = le32_to_cpu(bpl->tus.w);
- bf_set(lpfc_sli4_sge_len, sgl, bde.tus.f.bdeSize);
+ sgl->addr_hi = bpl->addrHigh;
+ sgl->addr_lo = bpl->addrLow;
+
if ((i+1) == numBdes)
bf_set(lpfc_sli4_sge_last, sgl, 1);
else
bf_set(lpfc_sli4_sge_last, sgl, 0);
sgl->word2 = cpu_to_le32(sgl->word2);
- sgl->word3 = cpu_to_le32(sgl->word3);
+ /* swap the size field back to the cpu so we
+ * can assign it to the sgl.
+ */
+ bde.tus.w = le32_to_cpu(bpl->tus.w);
+ sgl->sge_len = cpu_to_le32(bde.tus.f.bdeSize);
bpl++;
sgl++;
}
@@ -5712,11 +5764,10 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
cpu_to_le32(icmd->un.genreq64.bdl.addrHigh);
sgl->addr_lo =
cpu_to_le32(icmd->un.genreq64.bdl.addrLow);
- bf_set(lpfc_sli4_sge_len, sgl,
- icmd->un.genreq64.bdl.bdeSize);
bf_set(lpfc_sli4_sge_last, sgl, 1);
sgl->word2 = cpu_to_le32(sgl->word2);
- sgl->word3 = cpu_to_le32(sgl->word3);
+ sgl->sge_len =
+ cpu_to_le32(icmd->un.genreq64.bdl.bdeSize);
}
return sglq->sli4_xritag;
}
@@ -5987,12 +6038,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
else
bf_set(abort_cmd_ia, &wqe->abort_cmd, 0);
bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG);
- abort_tag = iocbq->iocb.un.acxri.abortIoTag;
wqe->words[5] = 0;
bf_set(lpfc_wqe_gen_ct, &wqe->generic,
((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
abort_tag = iocbq->iocb.un.acxri.abortIoTag;
- wqe->generic.abort_tag = abort_tag;
/*
* The abort handler will send us CMD_ABORT_XRI_CN or
* CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX
@@ -6121,15 +6170,15 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe))
return IOCB_ERROR;
- if (piocb->iocb_flag & LPFC_IO_FCP) {
+ if ((piocb->iocb_flag & LPFC_IO_FCP) ||
+ (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) {
/*
* For FCP command IOCB, get a new WQ index to distribute
* WQE across the WQsr. On the other hand, for abort IOCB,
* it carries the same WQ index to the original command
* IOCB.
*/
- if ((piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
- (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN))
+ if (piocb->iocb_flag & LPFC_IO_FCP)
piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba);
if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx],
&wqe))
@@ -7004,7 +7053,14 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
abort_iocb->iocb.ulpContext != abort_context ||
(abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) == 0)
spin_unlock_irq(&phba->hbalock);
- else {
+ else if (phba->sli_rev < LPFC_SLI_REV4) {
+ /*
+ * leave the SLI4 aborted command on the txcmplq
+ * list and the command complete WCQE's XB bit
+ * will tell whether the SGL (XRI) can be released
+ * immediately or to the aborted SGL list for the
+ * following abort XRI from the HBA.
+ */
list_del_init(&abort_iocb->list);
pring->txcmplq_cnt--;
spin_unlock_irq(&phba->hbalock);
@@ -7013,11 +7069,13 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* payload, so don't free data buffer till after
* a hbeat.
*/
+ spin_lock_irq(&phba->hbalock);
abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE;
-
abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;
+ spin_unlock_irq(&phba->hbalock);
+
abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
- abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED;
+ abort_iocb->iocb.un.ulpWord[4] = IOERR_ABORT_REQUESTED;
(abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb);
}
}
@@ -7106,7 +7164,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
return 0;
/* This signals the response to set the correct status
- * before calling the completion handler.
+ * before calling the completion handler
*/
cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED;
@@ -7124,6 +7182,8 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/* ABTS WQE must go to the same WQ as the WQE to be aborted */
abtsiocbp->fcp_wqidx = cmdiocb->fcp_wqidx;
+ if (cmdiocb->iocb_flag & LPFC_IO_FCP)
+ abtsiocbp->iocb_flag |= LPFC_USE_FCPWQIDX;
if (phba->link_state >= LPFC_LINK_UP)
iabt->ulpCommand = CMD_ABORT_XRI_CN;
@@ -7330,6 +7390,8 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
/* ABTS WQE must go to the same WQ as the WQE to be aborted */
abtsiocb->fcp_wqidx = iocbq->fcp_wqidx;
+ if (iocbq->iocb_flag & LPFC_IO_FCP)
+ abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX;
if (lpfc_is_link_up(phba))
abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN;
@@ -8359,11 +8421,24 @@ void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba)
}
}
+/**
+ * lpfc_sli4_iocb_param_transfer - Transfer pIocbOut and cmpl status to pIocbIn
+ * @phba: pointer to lpfc hba data structure
+ * @pIocbIn: pointer to the rspiocbq
+ * @pIocbOut: pointer to the cmdiocbq
+ * @wcqe: pointer to the complete wcqe
+ *
+ * This routine transfers the fields of a command iocbq to a response iocbq
+ * by copying all the IOCB fields from command iocbq and transferring the
+ * completion status information from the complete wcqe.
+ **/
static void
-lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn,
+lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba,
+ struct lpfc_iocbq *pIocbIn,
struct lpfc_iocbq *pIocbOut,
struct lpfc_wcqe_complete *wcqe)
{
+ unsigned long iflags;
size_t offset = offsetof(struct lpfc_iocbq, iocb);
memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset,
@@ -8377,8 +8452,17 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn,
wcqe->total_data_placed;
else
pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
- else
+ else {
pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
+ pIocbIn->iocb.un.genreq64.bdl.bdeSize = wcqe->total_data_placed;
+ }
+
+ /* Pick up HBA exchange busy condition */
+ if (bf_get(lpfc_wcqe_c_xb, wcqe)) {
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ pIocbIn->iocb_flag |= LPFC_EXCHANGE_BUSY;
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ }
}
/**
@@ -8419,7 +8503,7 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba,
}
/* Fake the irspiocbq and copy necessary response information */
- lpfc_sli4_iocb_param_transfer(irspiocbq, cmdiocbq, wcqe);
+ lpfc_sli4_iocb_param_transfer(phba, irspiocbq, cmdiocbq, wcqe);
return irspiocbq;
}
@@ -8849,8 +8933,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)
int ecount = 0;
uint16_t cqid;
- if (bf_get(lpfc_eqe_major_code, eqe) != 0 ||
- bf_get(lpfc_eqe_minor_code, eqe) != 0) {
+ if (bf_get(lpfc_eqe_major_code, eqe) != 0) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0359 Not a valid slow-path completion "
"event: majorcode=x%x, minorcode=x%x\n",
@@ -8976,7 +9059,7 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba,
}
/* Fake the irspiocb and copy necessary response information */
- lpfc_sli4_iocb_param_transfer(&irspiocbq, cmdiocbq, wcqe);
+ lpfc_sli4_iocb_param_transfer(phba, &irspiocbq, cmdiocbq, wcqe);
/* Pass the cmd_iocb and the rsp state to the upper layer */
(cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq);
@@ -9082,8 +9165,7 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
uint16_t cqid;
int ecount = 0;
- if (unlikely(bf_get(lpfc_eqe_major_code, eqe) != 0) ||
- unlikely(bf_get(lpfc_eqe_minor_code, eqe) != 0)) {
+ if (unlikely(bf_get(lpfc_eqe_major_code, eqe) != 0)) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0366 Not a valid fast-path completion "
"event: majorcode=x%x, minorcode=x%x\n",
@@ -11871,12 +11953,6 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
{
int rc = 0, error;
LPFC_MBOXQ_t *mboxq;
- void *virt_addr;
- dma_addr_t phys_addr;
- uint8_t *bytep;
- struct lpfc_mbx_sge sge;
- uint32_t alloc_len, req_len;
- struct lpfc_mbx_read_fcf_tbl *read_fcf;
phba->fcoe_eventtag_at_fcf_scan = phba->fcoe_eventtag;
mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -11887,43 +11963,19 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
error = -ENOMEM;
goto fail_fcfscan;
}
-
- req_len = sizeof(struct fcf_record) +
- sizeof(union lpfc_sli4_cfg_shdr) + 2 * sizeof(uint32_t);
-
- /* Set up READ_FCF SLI4_CONFIG mailbox-ioctl command */
- alloc_len = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
- LPFC_MBOX_OPCODE_FCOE_READ_FCF_TABLE, req_len,
- LPFC_SLI4_MBX_NEMBED);
-
- if (alloc_len < req_len) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0291 Allocated DMA memory size (x%x) is "
- "less than the requested DMA memory "
- "size (x%x)\n", alloc_len, req_len);
- error = -ENOMEM;
+ /* Construct the read FCF record mailbox command */
+ rc = lpfc_sli4_mbx_read_fcf_record(phba, mboxq, fcf_index);
+ if (rc) {
+ error = -EINVAL;
goto fail_fcfscan;
}
-
- /* Get the first SGE entry from the non-embedded DMA memory. This
- * routine only uses a single SGE.
- */
- lpfc_sli4_mbx_sge_get(mboxq, 0, &sge);
- phys_addr = getPaddr(sge.pa_hi, sge.pa_lo);
- virt_addr = mboxq->sge_array->addr[0];
- read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr;
-
- /* Set up command fields */
- bf_set(lpfc_mbx_read_fcf_tbl_indx, &read_fcf->u.request, fcf_index);
- /* Perform necessary endian conversion */
- bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr);
- lpfc_sli_pcimem_bcopy(bytep, bytep, sizeof(uint32_t));
+ /* Issue the mailbox command asynchronously */
mboxq->vport = phba->pport;
mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_fcf_record;
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
+ if (rc == MBX_NOT_FINISHED)
error = -EIO;
- } else {
+ else {
spin_lock_irq(&phba->hbalock);
phba->hba_flag |= FCF_DISC_INPROGRESS;
spin_unlock_irq(&phba->hbalock);
@@ -11942,6 +11994,90 @@ fail_fcfscan:
}
/**
+ * lpfc_mbx_cmpl_redisc_fcf_table - completion routine for rediscover FCF table
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is the completion routine for the rediscover FCF table mailbox
+ * command. If the mailbox command returned failure, it will try to stop the
+ * FCF rediscover wait timer.
+ **/
+void
+lpfc_mbx_cmpl_redisc_fcf_table(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
+{
+ struct lpfc_mbx_redisc_fcf_tbl *redisc_fcf;
+ uint32_t shdr_status, shdr_add_status;
+
+ redisc_fcf = &mbox->u.mqe.un.redisc_fcf_tbl;
+
+ shdr_status = bf_get(lpfc_mbox_hdr_status,
+ &redisc_fcf->header.cfg_shdr.response);
+ shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+ &redisc_fcf->header.cfg_shdr.response);
+ if (shdr_status || shdr_add_status) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2746 Requesting for FCF rediscovery failed "
+ "status x%x add_status x%x\n",
+ shdr_status, shdr_add_status);
+ /*
+ * Request failed, last resort to re-try current
+ * registered FCF entry
+ */
+ lpfc_retry_pport_discovery(phba);
+ } else
+ /*
+ * Start FCF rediscovery wait timer for pending FCF
+ * before rescan FCF record table.
+ */
+ lpfc_fcf_redisc_wait_start_timer(phba);
+
+ mempool_free(mbox, phba->mbox_mem_pool);
+}
+
+/**
+ * lpfc_sli4_redisc_all_fcf - Request to rediscover entire FCF table by port.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to request for rediscovery of the entire FCF table
+ * by the port.
+ **/
+int
+lpfc_sli4_redisc_fcf_table(struct lpfc_hba *phba)
+{
+ LPFC_MBOXQ_t *mbox;
+ struct lpfc_mbx_redisc_fcf_tbl *redisc_fcf;
+ int rc, length;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2745 Failed to allocate mbox for "
+ "requesting FCF rediscover.\n");
+ return -ENOMEM;
+ }
+
+ length = (sizeof(struct lpfc_mbx_redisc_fcf_tbl) -
+ sizeof(struct lpfc_sli4_cfg_mhdr));
+ lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+ LPFC_MBOX_OPCODE_FCOE_REDISCOVER_FCF,
+ length, LPFC_SLI4_MBX_EMBED);
+
+ redisc_fcf = &mbox->u.mqe.un.redisc_fcf_tbl;
+ /* Set count to 0 for invalidating the entire FCF database */
+ bf_set(lpfc_mbx_redisc_fcf_count, redisc_fcf, 0);
+
+ /* Issue the mailbox command asynchronously */
+ mbox->vport = phba->pport;
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_redisc_fcf_table;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
* lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled.
* @phba: pointer to lpfc hba data structure.
*
@@ -12069,3 +12205,48 @@ out:
kfree(rgn23_data);
return;
}
+
+/**
+ * lpfc_cleanup_pending_mbox - Free up vport discovery mailbox commands.
+ * @vport: pointer to vport data structure.
+ *
+ * This function iterate through the mailboxq and clean up all REG_LOGIN
+ * and REG_VPI mailbox commands associated with the vport. This function
+ * is called when driver want to restart discovery of the vport due to
+ * a Clear Virtual Link event.
+ **/
+void
+lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mb, *nextmb;
+ struct lpfc_dmabuf *mp;
+
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
+ if (mb->vport != vport)
+ continue;
+
+ if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) &&
+ (mb->u.mb.mbxCommand != MBX_REG_VPI))
+ continue;
+
+ if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
+ mp = (struct lpfc_dmabuf *) (mb->context1);
+ if (mp) {
+ __lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ }
+ }
+ list_del(&mb->list);
+ mempool_free(mb, phba->mbox_mem_pool);
+ }
+ mb = phba->sli.mbox_active;
+ if (mb && (mb->vport == vport)) {
+ if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) ||
+ (mb->u.mb.mbxCommand == MBX_REG_VPI))
+ mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ }
+ spin_unlock_irq(&phba->hbalock);
+}
+
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index ba38de3c28f1..dfcf5437d1f5 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -53,17 +53,19 @@ struct lpfc_iocbq {
IOCB_t iocb; /* IOCB cmd */
uint8_t retry; /* retry counter for IOCB cmd - if needed */
- uint8_t iocb_flag;
+ uint16_t iocb_flag;
#define LPFC_IO_LIBDFC 1 /* libdfc iocb */
#define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */
#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */
#define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */
#define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */
#define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */
-#define LPFC_FIP_ELS_ID_MASK 0xc0 /* ELS_ID range 0-3 */
-#define LPFC_FIP_ELS_ID_SHIFT 6
+#define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */
+#define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */
+
+#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */
+#define LPFC_FIP_ELS_ID_SHIFT 14
- uint8_t abort_count;
uint8_t rsvd2;
uint32_t drvrTimeout; /* driver timeout in seconds */
uint32_t fcp_wqidx; /* index to FCP work queue */
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 44e5f574236b..86308836600f 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -22,6 +22,10 @@
#define LPFC_RELEASE_NOTIFICATION_INTERVAL 32
#define LPFC_GET_QE_REL_INT 32
#define LPFC_RPI_LOW_WATER_MARK 10
+
+/* Amount of time in seconds for waiting FCF rediscovery to complete */
+#define LPFC_FCF_REDISCOVER_WAIT_TMO 2000 /* msec */
+
/* Number of SGL entries can be posted in a 4KB nonembedded mbox command */
#define LPFC_NEMBED_MBOX_SGL_CNT 254
@@ -126,24 +130,36 @@ struct lpfc_sli4_link {
uint8_t status;
uint8_t physical;
uint8_t fault;
+ uint16_t logical_speed;
};
-struct lpfc_fcf {
- uint8_t fabric_name[8];
- uint8_t switch_name[8];
+struct lpfc_fcf_rec {
+ uint8_t fabric_name[8];
+ uint8_t switch_name[8];
uint8_t mac_addr[6];
uint16_t fcf_indx;
+ uint32_t priority;
+ uint16_t vlan_id;
+ uint32_t addr_mode;
+ uint32_t flag;
+#define BOOT_ENABLE 0x01
+#define RECORD_VALID 0x02
+};
+
+struct lpfc_fcf {
uint16_t fcfi;
uint32_t fcf_flag;
#define FCF_AVAILABLE 0x01 /* FCF available for discovery */
#define FCF_REGISTERED 0x02 /* FCF registered with FW */
-#define FCF_DISCOVERED 0x04 /* FCF discovery started */
-#define FCF_BOOT_ENABLE 0x08 /* Boot bios use this FCF */
-#define FCF_IN_USE 0x10 /* Atleast one discovery completed */
-#define FCF_VALID_VLAN 0x20 /* Use the vlan id specified */
- uint32_t priority;
+#define FCF_SCAN_DONE 0x04 /* FCF table scan done */
+#define FCF_IN_USE 0x08 /* Atleast one discovery completed */
+#define FCF_REDISC_PEND 0x10 /* FCF rediscovery pending */
+#define FCF_REDISC_EVT 0x20 /* FCF rediscovery event to worker thread */
+#define FCF_REDISC_FOV 0x40 /* Post FCF rediscovery fast failover */
uint32_t addr_mode;
- uint16_t vlan_id;
+ struct lpfc_fcf_rec current_rec;
+ struct lpfc_fcf_rec failover_rec;
+ struct timer_list redisc_wait;
};
#define LPFC_REGION23_SIGNATURE "RG23"
@@ -248,7 +264,10 @@ struct lpfc_bmbx {
#define SLI4_CT_VFI 2
#define SLI4_CT_FCFI 3
-#define LPFC_SLI4_MAX_SEGMENT_SIZE 0x10000
+#define LPFC_SLI4_FL1_MAX_SEGMENT_SIZE 0x10000
+#define LPFC_SLI4_FL1_MAX_BUF_SIZE 0X2000
+#define LPFC_SLI4_MIN_BUF_SIZE 0x400
+#define LPFC_SLI4_MAX_BUF_SIZE 0x20000
/*
* SLI4 specific data structures
@@ -282,6 +301,42 @@ struct lpfc_fcp_eq_hdl {
struct lpfc_hba *phba;
};
+/* Port Capabilities for SLI4 Parameters */
+struct lpfc_pc_sli4_params {
+ uint32_t supported;
+ uint32_t if_type;
+ uint32_t sli_rev;
+ uint32_t sli_family;
+ uint32_t featurelevel_1;
+ uint32_t featurelevel_2;
+ uint32_t proto_types;
+#define LPFC_SLI4_PROTO_FCOE 0x0000001
+#define LPFC_SLI4_PROTO_FC 0x0000002
+#define LPFC_SLI4_PROTO_NIC 0x0000004
+#define LPFC_SLI4_PROTO_ISCSI 0x0000008
+#define LPFC_SLI4_PROTO_RDMA 0x0000010
+ uint32_t sge_supp_len;
+ uint32_t if_page_sz;
+ uint32_t rq_db_window;
+ uint32_t loopbk_scope;
+ uint32_t eq_pages_max;
+ uint32_t eqe_size;
+ uint32_t cq_pages_max;
+ uint32_t cqe_size;
+ uint32_t mq_pages_max;
+ uint32_t mqe_size;
+ uint32_t mq_elem_cnt;
+ uint32_t wq_pages_max;
+ uint32_t wqe_size;
+ uint32_t rq_pages_max;
+ uint32_t rqe_size;
+ uint32_t hdr_pages_max;
+ uint32_t hdr_size;
+ uint32_t hdr_pp_align;
+ uint32_t sgl_pages_max;
+ uint32_t sgl_pp_align;
+};
+
/* SLI4 HBA data structure entries */
struct lpfc_sli4_hba {
void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for
@@ -295,7 +350,7 @@ struct lpfc_sli4_hba {
void __iomem *UERRHIregaddr; /* Address to UERR_STATUS_HI register */
void __iomem *UEMASKLOregaddr; /* Address to UE_MASK_LO register */
void __iomem *UEMASKHIregaddr; /* Address to UE_MASK_HI register */
- void __iomem *SCRATCHPADregaddr; /* Address to scratchpad register */
+ void __iomem *SLIINTFregaddr; /* Address to SLI_INTF register */
/* BAR1 FCoE function CSR register memory map */
void __iomem *STAregaddr; /* Address to HST_STATE register */
void __iomem *ISRregaddr; /* Address to HST_ISR register */
@@ -310,6 +365,8 @@ struct lpfc_sli4_hba {
uint32_t ue_mask_lo;
uint32_t ue_mask_hi;
+ struct lpfc_register sli_intf;
+ struct lpfc_pc_sli4_params pc_sli4_params;
struct msix_entry *msix_entries;
uint32_t cfg_eqn;
struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */
@@ -406,6 +463,8 @@ void lpfc_sli4_mbox_cmd_free(struct lpfc_hba *, struct lpfcMboxq *);
void lpfc_sli4_mbx_sge_set(struct lpfcMboxq *, uint32_t, dma_addr_t, uint32_t);
void lpfc_sli4_mbx_sge_get(struct lpfcMboxq *, uint32_t,
struct lpfc_mbx_sge *);
+int lpfc_sli4_mbx_read_fcf_record(struct lpfc_hba *, struct lpfcMboxq *,
+ uint16_t);
void lpfc_sli4_hba_reset(struct lpfc_hba *);
struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *, uint32_t,
@@ -448,6 +507,7 @@ int lpfc_sli4_alloc_rpi(struct lpfc_hba *);
void lpfc_sli4_free_rpi(struct lpfc_hba *, int);
void lpfc_sli4_remove_rpis(struct lpfc_hba *);
void lpfc_sli4_async_event_proc(struct lpfc_hba *);
+void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *);
int lpfc_sli4_resume_rpi(struct lpfc_nodelist *);
void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *);
void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 792f72263f1a..ac276aa46fba 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2009 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2010 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.7"
+#define LPFC_DRIVER_VERSION "8.3.9"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"
#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index e3c7fa642306..dc86e873102a 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -389,7 +389,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
* by the port.
*/
if ((phba->sli_rev == LPFC_SLI_REV4) &&
- (pport->vpi_state & LPFC_VPI_REGISTERED)) {
+ (pport->fc_flag & FC_VFI_REGISTERED)) {
rc = lpfc_sli4_init_vpi(phba, vpi);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
@@ -505,6 +505,7 @@ enable_vport(struct fc_vport *fc_vport)
struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp = NULL;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
if ((phba->link_state < LPFC_LINK_UP) ||
(phba->fc_topology == TOPOLOGY_LOOP)) {
@@ -512,10 +513,10 @@ enable_vport(struct fc_vport *fc_vport)
return VPORT_OK;
}
- spin_lock_irq(&phba->hbalock);
+ spin_lock_irq(shost->host_lock);
vport->load_flag |= FC_LOADING;
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
- spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irq(shost->host_lock);
/* Use the Physical nodes Fabric NDLP to determine if the link is
* up and ready to FDISC.
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index c24e86f07804..4a90eaf7cb63 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -22,7 +22,6 @@
#include <asm/irq.h>
#include <asm/dma.h>
-
#include <asm/macints.h>
#include <asm/macintosh.h>
@@ -53,7 +52,6 @@ struct mac_esp_priv {
void __iomem *pdma_io;
int error;
};
-static struct platform_device *internal_pdev, *external_pdev;
static struct esp *esp_chips[2];
#define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \
@@ -279,24 +277,27 @@ static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count,
* Programmed IO routines follow.
*/
-static inline int mac_esp_wait_for_fifo(struct esp *esp)
+static inline unsigned int mac_esp_wait_for_fifo(struct esp *esp)
{
int i = 500000;
do {
- if (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES)
- return 0;
+ unsigned int fbytes = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
+
+ if (fbytes)
+ return fbytes;
udelay(2);
} while (--i);
printk(KERN_ERR PFX "FIFO is empty (sreg %02x)\n",
esp_read8(ESP_STATUS));
- return 1;
+ return 0;
}
static inline int mac_esp_wait_for_intr(struct esp *esp)
{
+ struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
int i = 500000;
do {
@@ -308,6 +309,7 @@ static inline int mac_esp_wait_for_intr(struct esp *esp)
} while (--i);
printk(KERN_ERR PFX "IRQ timeout (sreg %02x)\n", esp->sreg);
+ mep->error = 1;
return 1;
}
@@ -347,11 +349,10 @@ static inline int mac_esp_wait_for_intr(struct esp *esp)
static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
u32 dma_count, int write, u8 cmd)
{
- unsigned long flags;
struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
u8 *fifo = esp->regs + ESP_FDATA * 16;
- local_irq_save(flags);
+ disable_irq(esp->host->irq);
cmd &= ~ESP_CMD_DMA;
mep->error = 0;
@@ -359,11 +360,35 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
if (write) {
scsi_esp_cmd(esp, cmd);
- if (!mac_esp_wait_for_intr(esp)) {
- if (mac_esp_wait_for_fifo(esp))
- esp_count = 0;
- } else {
- esp_count = 0;
+ while (1) {
+ unsigned int n;
+
+ n = mac_esp_wait_for_fifo(esp);
+ if (!n)
+ break;
+
+ if (n > esp_count)
+ n = esp_count;
+ esp_count -= n;
+
+ MAC_ESP_PIO_LOOP("%2@,%0@+", n);
+
+ if (!esp_count)
+ break;
+
+ if (mac_esp_wait_for_intr(esp))
+ break;
+
+ if (((esp->sreg & ESP_STAT_PMASK) != ESP_DIP) &&
+ ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP))
+ break;
+
+ esp->ireg = esp_read8(ESP_INTRPT);
+ if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) !=
+ ESP_INTR_BSERV)
+ break;
+
+ scsi_esp_cmd(esp, ESP_CMD_TI);
}
} else {
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
@@ -374,47 +399,24 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
MAC_ESP_PIO_LOOP("%0@+,%2@", esp_count);
scsi_esp_cmd(esp, cmd);
- }
-
- while (esp_count) {
- unsigned int n;
- if (mac_esp_wait_for_intr(esp)) {
- mep->error = 1;
- break;
- }
-
- if (esp->sreg & ESP_STAT_SPAM) {
- printk(KERN_ERR PFX "gross error\n");
- mep->error = 1;
- break;
- }
-
- n = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
-
- if (write) {
- if (n > esp_count)
- n = esp_count;
- esp_count -= n;
-
- MAC_ESP_PIO_LOOP("%2@,%0@+", n);
+ while (esp_count) {
+ unsigned int n;
- if ((esp->sreg & ESP_STAT_PMASK) == ESP_STATP)
+ if (mac_esp_wait_for_intr(esp))
break;
- if (esp_count) {
- esp->ireg = esp_read8(ESP_INTRPT);
- if (esp->ireg & ESP_INTR_DC)
- break;
+ if (((esp->sreg & ESP_STAT_PMASK) != ESP_DOP) &&
+ ((esp->sreg & ESP_STAT_PMASK) != ESP_MOP))
+ break;
- scsi_esp_cmd(esp, ESP_CMD_TI);
- }
- } else {
esp->ireg = esp_read8(ESP_INTRPT);
- if (esp->ireg & ESP_INTR_DC)
+ if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) !=
+ ESP_INTR_BSERV)
break;
- n = MAC_ESP_FIFO_SIZE - n;
+ n = MAC_ESP_FIFO_SIZE -
+ (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES);
if (n > esp_count)
n = esp_count;
@@ -429,7 +431,7 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
}
}
- local_irq_restore(flags);
+ enable_irq(esp->host->irq);
}
static int mac_esp_irq_pending(struct esp *esp)
@@ -492,29 +494,12 @@ static int __devinit esp_mac_probe(struct platform_device *dev)
struct Scsi_Host *host;
struct esp *esp;
int err;
- int chips_present;
struct mac_esp_priv *mep;
if (!MACH_IS_MAC)
return -ENODEV;
- switch (macintosh_config->scsi_type) {
- case MAC_SCSI_QUADRA:
- case MAC_SCSI_QUADRA3:
- chips_present = 1;
- break;
- case MAC_SCSI_QUADRA2:
- if ((macintosh_config->ident == MAC_MODEL_Q900) ||
- (macintosh_config->ident == MAC_MODEL_Q950))
- chips_present = 2;
- else
- chips_present = 1;
- break;
- default:
- chips_present = 0;
- }
-
- if (dev->id + 1 > chips_present)
+ if (dev->id > 1)
return -ENODEV;
host = scsi_host_alloc(tpnt, sizeof(struct esp));
@@ -639,55 +624,26 @@ static struct platform_driver esp_mac_driver = {
.probe = esp_mac_probe,
.remove = __devexit_p(esp_mac_remove),
.driver = {
- .name = DRV_MODULE_NAME,
+ .name = DRV_MODULE_NAME,
+ .owner = THIS_MODULE,
},
};
static int __init mac_esp_init(void)
{
- int err;
-
- err = platform_driver_register(&esp_mac_driver);
- if (err)
- return err;
-
- internal_pdev = platform_device_alloc(DRV_MODULE_NAME, 0);
- if (internal_pdev && platform_device_add(internal_pdev)) {
- platform_device_put(internal_pdev);
- internal_pdev = NULL;
- }
- external_pdev = platform_device_alloc(DRV_MODULE_NAME, 1);
- if (external_pdev && platform_device_add(external_pdev)) {
- platform_device_put(external_pdev);
- external_pdev = NULL;
- }
-
- if (internal_pdev || external_pdev) {
- return 0;
- } else {
- platform_driver_unregister(&esp_mac_driver);
- return -ENOMEM;
- }
+ return platform_driver_register(&esp_mac_driver);
}
static void __exit mac_esp_exit(void)
{
platform_driver_unregister(&esp_mac_driver);
-
- if (internal_pdev) {
- platform_device_unregister(internal_pdev);
- internal_pdev = NULL;
- }
- if (external_pdev) {
- platform_device_unregister(external_pdev);
- external_pdev = NULL;
- }
}
MODULE_DESCRIPTION("Mac ESP SCSI driver");
MODULE_AUTHOR("Finn Thain <fthain@telegraphics.com.au>");
MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_MODULE_NAME);
module_init(mac_esp_init);
module_exit(mac_esp_exit);
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 708ea3157b60..409648f5845f 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_sas.c
- * Version : v00.00.04.12-rc1
+ * Version : v00.00.04.17.1-rc1
*
* Authors:
* (email-id : megaraidlinux@lsi.com)
@@ -843,6 +843,7 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
pthru->lun = scp->device->lun;
pthru->cdb_len = scp->cmd_len;
pthru->timeout = 0;
+ pthru->pad_0 = 0;
pthru->flags = flags;
pthru->data_xfer_len = scsi_bufflen(scp);
@@ -874,6 +875,12 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
pthru->sge_count = megasas_make_sgl32(instance, scp,
&pthru->sgl);
+ if (pthru->sge_count > instance->max_num_sge) {
+ printk(KERN_ERR "megasas: DCDB two many SGE NUM=%x\n",
+ pthru->sge_count);
+ return 0;
+ }
+
/*
* Sense info specific
*/
@@ -1000,6 +1007,12 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
} else
ldio->sge_count = megasas_make_sgl32(instance, scp, &ldio->sgl);
+ if (ldio->sge_count > instance->max_num_sge) {
+ printk(KERN_ERR "megasas: build_ld_io: sge_count = %x\n",
+ ldio->sge_count);
+ return 0;
+ }
+
/*
* Sense info specific
*/
@@ -2250,6 +2263,7 @@ megasas_get_pd_list(struct megasas_instance *instance)
dcmd->sge_count = 1;
dcmd->flags = MFI_FRAME_DIR_READ;
dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
dcmd->data_xfer_len = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
dcmd->opcode = MR_DCMD_PD_LIST_QUERY;
dcmd->sgl.sge32[0].phys_addr = ci_h;
@@ -2294,6 +2308,86 @@ megasas_get_pd_list(struct megasas_instance *instance)
return ret;
}
+/*
+ * megasas_get_ld_list_info - Returns FW's ld_list structure
+ * @instance: Adapter soft state
+ * @ld_list: ld_list structure
+ *
+ * Issues an internal command (DCMD) to get the FW's controller PD
+ * list structure. This information is mainly used to find out SYSTEM
+ * supported by the FW.
+ */
+static int
+megasas_get_ld_list(struct megasas_instance *instance)
+{
+ int ret = 0, ld_index = 0, ids = 0;
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+ struct MR_LD_LIST *ci;
+ dma_addr_t ci_h = 0;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ printk(KERN_DEBUG "megasas_get_ld_list: Failed to get cmd\n");
+ return -ENOMEM;
+ }
+
+ dcmd = &cmd->frame->dcmd;
+
+ ci = pci_alloc_consistent(instance->pdev,
+ sizeof(struct MR_LD_LIST),
+ &ci_h);
+
+ if (!ci) {
+ printk(KERN_DEBUG "Failed to alloc mem in get_ld_list\n");
+ megasas_return_cmd(instance, cmd);
+ return -ENOMEM;
+ }
+
+ memset(ci, 0, sizeof(*ci));
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_READ;
+ dcmd->timeout = 0;
+ dcmd->data_xfer_len = sizeof(struct MR_LD_LIST);
+ dcmd->opcode = MR_DCMD_LD_GET_LIST;
+ dcmd->sgl.sge32[0].phys_addr = ci_h;
+ dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_LIST);
+ dcmd->pad_0 = 0;
+
+ if (!megasas_issue_polled(instance, cmd)) {
+ ret = 0;
+ } else {
+ ret = -1;
+ }
+
+ /* the following function will get the instance PD LIST */
+
+ if ((ret == 0) && (ci->ldCount < MAX_LOGICAL_DRIVES)) {
+ memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
+
+ for (ld_index = 0; ld_index < ci->ldCount; ld_index++) {
+ if (ci->ldList[ld_index].state != 0) {
+ ids = ci->ldList[ld_index].ref.targetId;
+ instance->ld_ids[ids] =
+ ci->ldList[ld_index].ref.targetId;
+ }
+ }
+ }
+
+ pci_free_consistent(instance->pdev,
+ sizeof(struct MR_LD_LIST),
+ ci,
+ ci_h);
+
+ megasas_return_cmd(instance, cmd);
+ return ret;
+}
+
/**
* megasas_get_controller_info - Returns FW's controller structure
* @instance: Adapter soft state
@@ -2339,6 +2433,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
dcmd->sge_count = 1;
dcmd->flags = MFI_FRAME_DIR_READ;
dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
dcmd->data_xfer_len = sizeof(struct megasas_ctrl_info);
dcmd->opcode = MR_DCMD_CTRL_GET_INFO;
dcmd->sgl.sge32[0].phys_addr = ci_h;
@@ -2590,6 +2685,9 @@ static int megasas_init_mfi(struct megasas_instance *instance)
(MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
megasas_get_pd_list(instance);
+ memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
+ megasas_get_ld_list(instance);
+
ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
/*
@@ -2714,6 +2812,7 @@ megasas_get_seq_num(struct megasas_instance *instance,
dcmd->sge_count = 1;
dcmd->flags = MFI_FRAME_DIR_READ;
dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
dcmd->data_xfer_len = sizeof(struct megasas_evt_log_info);
dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO;
dcmd->sgl.sge32[0].phys_addr = el_info_h;
@@ -2828,6 +2927,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
dcmd->sge_count = 1;
dcmd->flags = MFI_FRAME_DIR_READ;
dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
dcmd->data_xfer_len = sizeof(struct megasas_evt_detail);
dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
dcmd->mbox.w[0] = seq_num;
@@ -3166,6 +3266,7 @@ static void megasas_flush_cache(struct megasas_instance *instance)
dcmd->sge_count = 0;
dcmd->flags = MFI_FRAME_DIR_NONE;
dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
dcmd->data_xfer_len = 0;
dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH;
dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
@@ -3205,6 +3306,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
dcmd->sge_count = 0;
dcmd->flags = MFI_FRAME_DIR_NONE;
dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
dcmd->data_xfer_len = 0;
dcmd->opcode = opcode;
@@ -3781,6 +3883,7 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
compat_alloc_user_space(sizeof(struct megasas_iocpacket));
int i;
int error = 0;
+ compat_uptr_t ptr;
if (clear_user(ioc, sizeof(*ioc)))
return -EFAULT;
@@ -3793,9 +3896,22 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
copy_in_user(&ioc->sge_count, &cioc->sge_count, sizeof(u32)))
return -EFAULT;
- for (i = 0; i < MAX_IOCTL_SGE; i++) {
- compat_uptr_t ptr;
+ /*
+ * The sense_ptr is used in megasas_mgmt_fw_ioctl only when
+ * sense_len is not null, so prepare the 64bit value under
+ * the same condition.
+ */
+ if (ioc->sense_len) {
+ void __user **sense_ioc_ptr =
+ (void __user **)(ioc->frame.raw + ioc->sense_off);
+ compat_uptr_t *sense_cioc_ptr =
+ (compat_uptr_t *)(cioc->frame.raw + cioc->sense_off);
+ if (get_user(ptr, sense_cioc_ptr) ||
+ put_user(compat_ptr(ptr), sense_ioc_ptr))
+ return -EFAULT;
+ }
+ for (i = 0; i < MAX_IOCTL_SGE; i++) {
if (get_user(ptr, &cioc->sgl[i].iov_base) ||
put_user(compat_ptr(ptr), &ioc->sgl[i].iov_base) ||
copy_in_user(&ioc->sgl[i].iov_len,
@@ -3970,6 +4086,7 @@ megasas_aen_polling(struct work_struct *work)
struct Scsi_Host *host;
struct scsi_device *sdev1;
u16 pd_index = 0;
+ u16 ld_index = 0;
int i, j, doscan = 0;
u32 seq_num;
int error;
@@ -3985,8 +4102,124 @@ megasas_aen_polling(struct work_struct *work)
switch (instance->evt_detail->code) {
case MR_EVT_PD_INSERTED:
+ if (megasas_get_pd_list(instance) == 0) {
+ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+ for (j = 0;
+ j < MEGASAS_MAX_DEV_PER_CHANNEL;
+ j++) {
+
+ pd_index =
+ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+
+ sdev1 =
+ scsi_device_lookup(host, i, j, 0);
+
+ if (instance->pd_list[pd_index].driveState
+ == MR_PD_STATE_SYSTEM) {
+ if (!sdev1) {
+ scsi_add_device(host, i, j, 0);
+ }
+
+ if (sdev1)
+ scsi_device_put(sdev1);
+ }
+ }
+ }
+ }
+ doscan = 0;
+ break;
+
case MR_EVT_PD_REMOVED:
+ if (megasas_get_pd_list(instance) == 0) {
+ megasas_get_pd_list(instance);
+ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+ for (j = 0;
+ j < MEGASAS_MAX_DEV_PER_CHANNEL;
+ j++) {
+
+ pd_index =
+ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+
+ sdev1 =
+ scsi_device_lookup(host, i, j, 0);
+
+ if (instance->pd_list[pd_index].driveState
+ == MR_PD_STATE_SYSTEM) {
+ if (sdev1) {
+ scsi_device_put(sdev1);
+ }
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
+ }
+ }
+ }
+ }
+ }
+ doscan = 0;
+ break;
+
+ case MR_EVT_LD_OFFLINE:
+ case MR_EVT_LD_DELETED:
+ megasas_get_ld_list(instance);
+ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+ for (j = 0;
+ j < MEGASAS_MAX_DEV_PER_CHANNEL;
+ j++) {
+
+ ld_index =
+ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+
+ sdev1 = scsi_device_lookup(host,
+ i + MEGASAS_MAX_LD_CHANNELS,
+ j,
+ 0);
+
+ if (instance->ld_ids[ld_index] != 0xff) {
+ if (sdev1) {
+ scsi_device_put(sdev1);
+ }
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
+ }
+ }
+ }
+ }
+ doscan = 0;
+ break;
+ case MR_EVT_LD_CREATED:
+ megasas_get_ld_list(instance);
+ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+ for (j = 0;
+ j < MEGASAS_MAX_DEV_PER_CHANNEL;
+ j++) {
+ ld_index =
+ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+
+ sdev1 = scsi_device_lookup(host,
+ i+MEGASAS_MAX_LD_CHANNELS,
+ j, 0);
+
+ if (instance->ld_ids[ld_index] !=
+ 0xff) {
+ if (!sdev1) {
+ scsi_add_device(host,
+ i + 2,
+ j, 0);
+ }
+ }
+ if (sdev1) {
+ scsi_device_put(sdev1);
+ }
+ }
+ }
+ doscan = 0;
+ break;
case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
+ case MR_EVT_FOREIGN_CFG_IMPORTED:
doscan = 1;
break;
default:
@@ -4021,6 +4254,31 @@ megasas_aen_polling(struct work_struct *work)
}
}
}
+
+ megasas_get_ld_list(instance);
+ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+ ld_index =
+ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+
+ sdev1 = scsi_device_lookup(host,
+ i+MEGASAS_MAX_LD_CHANNELS, j, 0);
+ if (instance->ld_ids[ld_index] != 0xff) {
+ if (!sdev1) {
+ scsi_add_device(host,
+ i+2,
+ j, 0);
+ } else {
+ scsi_device_put(sdev1);
+ }
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
+ }
+ }
+ }
+ }
}
if ( instance->aen_cmd != NULL ) {
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 72b28e436e32..9d8b6bf605aa 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -18,9 +18,9 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.04.12-rc1"
-#define MEGASAS_RELDATE "Sep. 17, 2009"
-#define MEGASAS_EXT_VERSION "Thu Sep. 17 11:41:51 PST 2009"
+#define MEGASAS_VERSION "00.00.04.17.1-rc1"
+#define MEGASAS_RELDATE "Oct. 29, 2009"
+#define MEGASAS_EXT_VERSION "Thu. Oct. 29, 11:41:51 PST 2009"
/*
* Device IDs
@@ -117,6 +117,7 @@
#define MFI_CMD_STP 0x08
#define MR_DCMD_CTRL_GET_INFO 0x01010000
+#define MR_DCMD_LD_GET_LIST 0x03010000
#define MR_DCMD_CTRL_CACHE_FLUSH 0x01101000
#define MR_FLUSH_CTRL_CACHE 0x01
@@ -349,6 +350,32 @@ struct megasas_pd_list {
u8 driveState;
} __packed;
+ /*
+ * defines the logical drive reference structure
+ */
+union MR_LD_REF {
+ struct {
+ u8 targetId;
+ u8 reserved;
+ u16 seqNum;
+ };
+ u32 ref;
+} __packed;
+
+/*
+ * defines the logical drive list structure
+ */
+struct MR_LD_LIST {
+ u32 ldCount;
+ u32 reserved;
+ struct {
+ union MR_LD_REF ref;
+ u8 state;
+ u8 reserved[3];
+ u64 size;
+ } ldList[MAX_LOGICAL_DRIVES];
+} __packed;
+
/*
* SAS controller properties
*/
@@ -637,6 +664,8 @@ struct megasas_ctrl_info {
#define MEGASAS_MAX_LD 64
#define MEGASAS_MAX_PD (MEGASAS_MAX_PD_CHANNELS * \
MEGASAS_MAX_DEV_PER_CHANNEL)
+#define MEGASAS_MAX_LD_IDS (MEGASAS_MAX_LD_CHANNELS * \
+ MEGASAS_MAX_DEV_PER_CHANNEL)
#define MEGASAS_DBG_LVL 1
@@ -1187,6 +1216,7 @@ struct megasas_instance {
struct megasas_register_set __iomem *reg_set;
struct megasas_pd_list pd_list[MEGASAS_MAX_PD];
+ u8 ld_ids[MEGASAS_MAX_LD_IDS];
s8 init_id;
u16 max_num_sge;
diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig
index 70c4c2467dd8..ba8e128de238 100644
--- a/drivers/scsi/mpt2sas/Kconfig
+++ b/drivers/scsi/mpt2sas/Kconfig
@@ -44,6 +44,7 @@ config SCSI_MPT2SAS
tristate "LSI MPT Fusion SAS 2.0 Device Driver"
depends on PCI && SCSI
select SCSI_SAS_ATTRS
+ select RAID_ATTRS
---help---
This driver supports PCI-Express SAS 6Gb/s Host Adapters.
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index 914168105297..9958d847a88d 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.13
+ * mpi2.h Version: 02.00.14
*
* Version History
* ---------------
@@ -53,6 +53,10 @@
* bytes reserved.
* Added RAID Accelerator functionality.
* 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added MSI-x index mask and shift for Reply Post Host
+ * Index register.
+ * Added function code for Host Based Discovery Action.
* --------------------------------------------------------------------------
*/
@@ -78,7 +82,7 @@
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x0D)
+#define MPI2_HEADER_VERSION_UNIT (0x0E)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
@@ -232,9 +236,12 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS
#define MPI2_REPLY_FREE_HOST_INDEX_OFFSET (0x00000048)
/*
- * Offset for the Reply Descriptor Post Queue
+ * Defines for the Reply Descriptor Post Queue
*/
#define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C)
+#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF)
+#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000)
+#define MPI2_RPHI_MSIX_INDEX_SHIFT (24)
/*
* Defines for the HCBSize and address
@@ -497,12 +504,13 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */
#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */
#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator*/
+/* Host Based Discovery Action */
+#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F)
/* Doorbell functions */
#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40)
-/* #define MPI2_FUNCTION_IO_UNIT_RESET (0x41) */
#define MPI2_FUNCTION_HANDSHAKE (0x42)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index 1611c57a6fdf..cf0ac9f40c97 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.12
+ * mpi2_cnfg.h Version: 02.00.13
*
* Version History
* ---------------
@@ -107,6 +107,8 @@
* to SAS Device Page 0 Flags field.
* Added PhyInfo defines for power condition.
* Added Ethernet configuration pages.
+ * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
+ * Added SAS PHY Page 4 structure and defines.
* --------------------------------------------------------------------------
*/
@@ -712,6 +714,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1
#define MPI2_IOUNITPAGE1_PAGEVERSION (0x04)
/* IO Unit Page 1 Flags defines */
+#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800)
#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600)
#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000)
#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200)
@@ -2291,6 +2294,26 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 {
#define MPI2_SASPHY3_PAGEVERSION (0x00)
+/* SAS PHY Page 4 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U16 Reserved1; /* 0x08 */
+ U8 Reserved2; /* 0x0A */
+ U8 Flags; /* 0x0B */
+ U8 InitialFrame[28]; /* 0x0C */
+} MPI2_CONFIG_PAGE_SAS_PHY_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_4,
+ Mpi2SasPhyPage4_t, MPI2_POINTER pMpi2SasPhyPage4_t;
+
+#define MPI2_SASPHY4_PAGEVERSION (0x00)
+
+/* values for the Flags field */
+#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02)
+#define MPI2_SASPHY4_FLAGS_SATA_FRAME (0x01)
+
+
+
+
/****************************************************************************
* SAS Port Config Pages
****************************************************************************/
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt
index 65fcaa31cb30..c4adf76b49d9 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt
@@ -5,23 +5,24 @@
Copyright (c) 2000-2009 LSI Corporation.
---------------------------------------
- Header Set Release Version: 02.00.12
- Header Set Release Date: 05-06-09
+ Header Set Release Version: 02.00.14
+ Header Set Release Date: 10-28-09
---------------------------------------
Filename Current version Prior version
---------- --------------- -------------
- mpi2.h 02.00.12 02.00.11
- mpi2_cnfg.h 02.00.11 02.00.10
- mpi2_init.h 02.00.07 02.00.06
- mpi2_ioc.h 02.00.11 02.00.10
- mpi2_raid.h 02.00.03 02.00.03
- mpi2_sas.h 02.00.02 02.00.02
+ mpi2.h 02.00.14 02.00.13
+ mpi2_cnfg.h 02.00.13 02.00.12
+ mpi2_init.h 02.00.08 02.00.07
+ mpi2_ioc.h 02.00.13 02.00.12
+ mpi2_raid.h 02.00.04 02.00.04
+ mpi2_sas.h 02.00.03 02.00.02
mpi2_targ.h 02.00.03 02.00.03
- mpi2_tool.h 02.00.03 02.00.02
+ mpi2_tool.h 02.00.04 02.00.04
mpi2_type.h 02.00.00 02.00.00
- mpi2_ra.h 02.00.00
- mpi2_history.txt 02.00.11 02.00.12
+ mpi2_ra.h 02.00.00 02.00.00
+ mpi2_hbd.h 02.00.00
+ mpi2_history.txt 02.00.14 02.00.13
* Date Version Description
@@ -65,6 +66,11 @@ mpi2.h
* MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those
* bytes reserved.
* Added RAID Accelerator functionality.
+ * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added MSI-x index mask and shift for Reply Post Host
+ * Index register.
+ * Added function code for Host Based Discovery Action.
* --------------------------------------------------------------------------
mpi2_cnfg.h
@@ -155,6 +161,15 @@ mpi2_cnfg.h
* Added expander reduced functionality data to SAS
* Expander Page 0.
* Added SAS PHY Page 2 and SAS PHY Page 3.
+ * 07-30-09 02.00.12 Added IO Unit Page 7.
+ * Added new device ids.
+ * Added SAS IO Unit Page 5.
+ * Added partial and slumber power management capable flags
+ * to SAS Device Page 0 Flags field.
+ * Added PhyInfo defines for power condition.
+ * Added Ethernet configuration pages.
+ * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
+ * Added SAS PHY Page 4 structure and defines.
* --------------------------------------------------------------------------
mpi2_init.h
@@ -172,6 +187,10 @@ mpi2_init.h
* Query Asynchronous Event.
* Defined two new bits in the SlotStatus field of the SCSI
* Enclosure Processor Request and Reply.
+ * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for
+ * both SCSI IO Error Reply and SCSI Task Management Reply.
+ * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
+ * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
* --------------------------------------------------------------------------
mpi2_ioc.h
@@ -246,6 +265,20 @@ mpi2_ioc.h
* Added two new reason codes for SAS Device Status Change
* Event.
* Added new event: SAS PHY Counter.
+ * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure.
+ * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
+ * Added new product id family for 2208.
+ * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST.
+ * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY.
+ * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY.
+ * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY.
+ * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define.
+ * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define.
+ * Added Host Based Discovery Phy Event data.
+ * Added defines for ProductID Product field
+ * (MPI2_FW_HEADER_PID_).
+ * Modified values for SAS ProductID Family
+ * (MPI2_FW_HEADER_PID_FAMILY_).
* --------------------------------------------------------------------------
mpi2_raid.h
@@ -256,6 +289,8 @@ mpi2_raid.h
* 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that
* the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT
* can be sized by the build environment.
+ * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
+ * VolumeCreationFlags and marked the old one as obsolete.
* --------------------------------------------------------------------------
mpi2_sas.h
@@ -264,6 +299,8 @@ mpi2_sas.h
* Control Request.
* 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control
* Request.
+ * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
+ * to MPI2_SGE_IO_UNION since it supports chained SGLs.
* --------------------------------------------------------------------------
mpi2_targ.h
@@ -283,6 +320,10 @@ mpi2_tool.h
* structures and defines.
* 02-29-08 02.00.02 Modified various names to make them 32-character unique.
* 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool.
+ * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request
+ * and reply messages.
+ * Added MPI2_DIAG_BUF_TYPE_EXTENDED.
+ * Incremented MPI2_DIAG_BUF_TYPE_COUNT.
* --------------------------------------------------------------------------
mpi2_type.h
@@ -293,20 +334,26 @@ mpi2_ra.h
* 05-06-09 02.00.00 Initial version.
* --------------------------------------------------------------------------
+mpi2_hbd.h
+ * 10-28-09 02.00.00 Initial version.
+ * --------------------------------------------------------------------------
+
+
mpi2_history.txt Parts list history
-Filename 02.00.12
----------- --------
-mpi2.h 02.00.12
-mpi2_cnfg.h 02.00.11
-mpi2_init.h 02.00.07
-mpi2_ioc.h 02.00.11
-mpi2_raid.h 02.00.03
-mpi2_sas.h 02.00.02
-mpi2_targ.h 02.00.03
-mpi2_tool.h 02.00.03
-mpi2_type.h 02.00.00
-mpi2_ra.h 02.00.00
+Filename 02.00.14 02.00.13 02.00.12
+---------- -------- -------- --------
+mpi2.h 02.00.14 02.00.13 02.00.12
+mpi2_cnfg.h 02.00.13 02.00.12 02.00.11
+mpi2_init.h 02.00.08 02.00.07 02.00.07
+mpi2_ioc.h 02.00.13 02.00.12 02.00.11
+mpi2_raid.h 02.00.04 02.00.04 02.00.03
+mpi2_sas.h 02.00.03 02.00.02 02.00.02
+mpi2_targ.h 02.00.03 02.00.03 02.00.03
+mpi2_tool.h 02.00.04 02.00.04 02.00.03
+mpi2_type.h 02.00.00 02.00.00 02.00.00
+mpi2_ra.h 02.00.00 02.00.00 02.00.00
+mpi2_hbd.h 02.00.00
Filename 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06
---------- -------- -------- -------- -------- -------- --------
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
index 563e56d2e945..6541945e97c3 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
@@ -6,7 +6,7 @@
* Title: MPI SCSI initiator mode messages and structures
* Creation Date: June 23, 2006
*
- * mpi2_init.h Version: 02.00.07
+ * mpi2_init.h Version: 02.00.08
*
* Version History
* ---------------
@@ -27,6 +27,10 @@
* Query Asynchronous Event.
* Defined two new bits in the SlotStatus field of the SCSI
* Enclosure Processor Request and Reply.
+ * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for
+ * both SCSI IO Error Reply and SCSI Task Management Reply.
+ * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
+ * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
* --------------------------------------------------------------------------
*/
@@ -254,6 +258,11 @@ typedef struct _MPI2_SCSI_IO_REPLY
#define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02)
#define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01)
+/* masks and shifts for the ResponseInfo field */
+
+#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF)
+#define MPI2_SCSI_RI_SHIFT_REASONCODE (0)
+
#define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF)
@@ -327,6 +336,7 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY
U16 IOCStatus; /* 0x0E */
U32 IOCLogInfo; /* 0x10 */
U32 TerminationCount; /* 0x14 */
+ U32 ResponseInfo; /* 0x18 */
} MPI2_SCSI_TASK_MANAGE_REPLY,
MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY,
Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t;
@@ -339,8 +349,20 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY
#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05)
#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08)
#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09)
+#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A)
#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80)
+/* masks and shifts for the ResponseInfo field */
+
+#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF)
+#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0)
+#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00)
+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8)
+#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000)
+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16)
+#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000)
+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24)
+
/****************************************************************************
* SCSI Enclosure Processor messages
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
index ea51ce868690..754938422f6a 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
@@ -6,7 +6,7 @@
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.12
+ * mpi2_ioc.h Version: 02.00.13
*
* Version History
* ---------------
@@ -87,6 +87,17 @@
* 07-30-09 02.00.12 Added GPIO Interrupt event define and structure.
* Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
* Added new product id family for 2208.
+ * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST.
+ * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY.
+ * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY.
+ * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY.
+ * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define.
+ * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define.
+ * Added Host Based Discovery Phy Event data.
+ * Added defines for ProductID Product field
+ * (MPI2_FW_HEADER_PID_).
+ * Modified values for SAS ProductID Family
+ * (MPI2_FW_HEADER_PID_FAMILY_).
* --------------------------------------------------------------------------
*/
@@ -119,8 +130,10 @@ typedef struct _MPI2_IOC_INIT_REQUEST
U16 MsgVersion; /* 0x0C */
U16 HeaderVersion; /* 0x0E */
U32 Reserved5; /* 0x10 */
- U32 Reserved6; /* 0x14 */
- U16 Reserved7; /* 0x18 */
+ U16 Reserved6; /* 0x14 */
+ U8 Reserved7; /* 0x16 */
+ U8 HostMSIxVectors; /* 0x17 */
+ U16 Reserved8; /* 0x18 */
U16 SystemRequestFrameSize; /* 0x1A */
U16 ReplyDescriptorPostQueueDepth; /* 0x1C */
U16 ReplyFreeQueueDepth; /* 0x1E */
@@ -215,7 +228,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY
U8 MaxChainDepth; /* 0x14 */
U8 WhoInit; /* 0x15 */
U8 NumberOfPorts; /* 0x16 */
- U8 Reserved2; /* 0x17 */
+ U8 MaxMSIxVectors; /* 0x17 */
U16 RequestCredit; /* 0x18 */
U16 ProductID; /* 0x1A */
U32 IOCCapabilities; /* 0x1C */
@@ -233,7 +246,8 @@ typedef struct _MPI2_IOC_FACTS_REPLY
U8 MaxVolumes; /* 0x37 */
U16 MaxDevHandle; /* 0x38 */
U16 MaxPersistentEntries; /* 0x3A */
- U32 Reserved4; /* 0x3C */
+ U16 MinDevHandle; /* 0x3C */
+ U16 Reserved4; /* 0x3E */
} MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY,
Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t;
@@ -269,6 +283,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY
/* ProductID field uses MPI2_FW_HEADER_PID_ */
/* IOCCapabilities */
+#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000)
#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000)
#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000)
#define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000)
@@ -453,6 +468,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
#define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021)
#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022)
#define MPI2_EVENT_GPIO_INTERRUPT (0x0023)
+#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024)
/* Log Entry Added Event data */
@@ -793,6 +809,7 @@ typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST
MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t;
/* values for the ExpStatus field */
+#define MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00)
#define MPI2_EVENT_SAS_TOPO_ES_ADDED (0x01)
#define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02)
#define MPI2_EVENT_SAS_TOPO_ES_RESPONDING (0x03)
@@ -878,6 +895,44 @@ typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER {
* */
+/* Host Based Discovery Phy Event data */
+
+typedef struct _MPI2_EVENT_HBD_PHY_SAS {
+ U8 Flags; /* 0x00 */
+ U8 NegotiatedLinkRate; /* 0x01 */
+ U8 PhyNum; /* 0x02 */
+ U8 PhysicalPort; /* 0x03 */
+ U32 Reserved1; /* 0x04 */
+ U8 InitialFrame[28]; /* 0x08 */
+} MPI2_EVENT_HBD_PHY_SAS, MPI2_POINTER PTR_MPI2_EVENT_HBD_PHY_SAS,
+ Mpi2EventHbdPhySas_t, MPI2_POINTER pMpi2EventHbdPhySas_t;
+
+/* values for the Flags field */
+#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02)
+#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01)
+
+/* use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h for
+ * the NegotiatedLinkRate field */
+
+typedef union _MPI2_EVENT_HBD_DESCRIPTOR {
+ MPI2_EVENT_HBD_PHY_SAS Sas;
+} MPI2_EVENT_HBD_DESCRIPTOR, MPI2_POINTER PTR_MPI2_EVENT_HBD_DESCRIPTOR,
+ Mpi2EventHbdDescriptor_t, MPI2_POINTER pMpi2EventHbdDescriptor_t;
+
+typedef struct _MPI2_EVENT_DATA_HBD_PHY {
+ U8 DescriptorType; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U32 Reserved3; /* 0x04 */
+ MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /* 0x08 */
+} MPI2_EVENT_DATA_HBD_PHY, MPI2_POINTER PTR_MPI2_EVENT_DATA_HBD_PHY,
+ Mpi2EventDataHbdPhy_t, MPI2_POINTER pMpi2EventDataMpi2EventDataHbdPhy_t;
+
+/* values for the DescriptorType field */
+#define MPI2_EVENT_HBD_DT_SAS (0x01)
+
+
+
/****************************************************************************
* EventAck message
****************************************************************************/
@@ -1126,13 +1181,17 @@ typedef struct _MPI2_FW_IMAGE_HEADER
#define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000)
#define MPI2_FW_HEADER_PID_TYPE_SAS (0x2000)
-#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00)
-#define MPI2_FW_HEADER_PID_PROD_A (0x0000)
+#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00)
+#define MPI2_FW_HEADER_PID_PROD_A (0x0000)
+#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00)
+#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200)
+#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700)
+
#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF)
/* SAS */
-#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0010)
-#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0011)
+#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013)
+#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014)
/* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
index 8a42b136cf53..2d8aeed51392 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
@@ -6,7 +6,7 @@
* Title: MPI Serial Attached SCSI structures and definitions
* Creation Date: February 9, 2007
*
- * mpi2.h Version: 02.00.02
+ * mpi2.h Version: 02.00.03
*
* Version History
* ---------------
@@ -18,6 +18,8 @@
* Control Request.
* 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control
* Request.
+ * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
+ * to MPI2_SGE_IO_UNION since it supports chained SGLs.
* --------------------------------------------------------------------------
*/
@@ -160,7 +162,7 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST
U32 Reserved4; /* 0x14 */
U32 DataLength; /* 0x18 */
U8 CommandFIS[20]; /* 0x1C */
- MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */
+ MPI2_SGE_IO_UNION SGL; /* 0x20 */
} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST,
Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t;
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 89d02401b9ec..88e6eebc3159 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -107,8 +107,7 @@ _scsih_set_fwfault_debug(const char *val, struct kernel_param *kp)
if (ret)
return ret;
- printk(KERN_INFO "setting logging_level(0x%08x)\n",
- mpt2sas_fwfault_debug);
+ printk(KERN_INFO "setting fwfault_debug(%d)\n", mpt2sas_fwfault_debug);
list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
ioc->fwfault_debug = mpt2sas_fwfault_debug;
return 0;
@@ -1222,6 +1221,8 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
u32 memap_sz;
u32 pio_sz;
int i, r = 0;
+ u64 pio_chip = 0;
+ u64 chip_phys = 0;
dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n",
ioc->name, __func__));
@@ -1255,12 +1256,13 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) {
if (pio_sz)
continue;
- ioc->pio_chip = pci_resource_start(pdev, i);
+ pio_chip = (u64)pci_resource_start(pdev, i);
pio_sz = pci_resource_len(pdev, i);
} else {
if (memap_sz)
continue;
ioc->chip_phys = pci_resource_start(pdev, i);
+ chip_phys = (u64)ioc->chip_phys;
memap_sz = pci_resource_len(pdev, i);
ioc->chip = ioremap(ioc->chip_phys, memap_sz);
if (ioc->chip == NULL) {
@@ -1280,10 +1282,10 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n",
ioc->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
"IO-APIC enabled"), ioc->pci_irq);
- printk(MPT2SAS_INFO_FMT "iomem(0x%lx), mapped(0x%p), size(%d)\n",
- ioc->name, ioc->chip_phys, ioc->chip, memap_sz);
- printk(MPT2SAS_INFO_FMT "ioport(0x%lx), size(%d)\n",
- ioc->name, ioc->pio_chip, pio_sz);
+ printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
+ ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz);
+ printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n",
+ ioc->name, (unsigned long long)pio_chip, pio_sz);
return 0;
@@ -3573,6 +3575,8 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
init_waitqueue_head(&ioc->reset_wq);
+ ioc->fwfault_debug = mpt2sas_fwfault_debug;
+
/* base internal command bits */
mutex_init(&ioc->base_cmds.mutex);
ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index bb4f14656afa..e18b0544c38f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -69,10 +69,10 @@
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "03.100.03.00"
-#define MPT2SAS_MAJOR_VERSION 03
+#define MPT2SAS_DRIVER_VERSION "04.100.01.00"
+#define MPT2SAS_MAJOR_VERSION 04
#define MPT2SAS_MINOR_VERSION 100
-#define MPT2SAS_BUILD_VERSION 03
+#define MPT2SAS_BUILD_VERSION 01
#define MPT2SAS_RELEASE_VERSION 00
/*
@@ -323,6 +323,7 @@ struct _sas_device {
* @device_info: bitfield provides detailed info about the hidden components
* @num_pds: number of hidden raid components
* @responding: used in _scsih_raid_device_mark_responding
+ * @percent_complete: resync percent complete
*/
struct _raid_device {
struct list_head list;
@@ -336,6 +337,7 @@ struct _raid_device {
u32 device_info;
u8 num_pds;
u8 responding;
+ u8 percent_complete;
};
/**
@@ -464,7 +466,6 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @pdev: pci pdev object
* @chip: memory mapped register space
* @chip_phys: physical addrss prior to mapping
- * @pio_chip: I/O mapped register space
* @logging_level: see mpt2sas_debug.h
* @fwfault_debug: debuging FW timeouts
* @ir_firmware: IR firmware present
@@ -587,8 +588,7 @@ struct MPT2SAS_ADAPTER {
char tmp_string[MPT_STRING_LENGTH];
struct pci_dev *pdev;
Mpi2SystemInterfaceRegs_t __iomem *chip;
- unsigned long chip_phys;
- unsigned long pio_chip;
+ resource_size_t chip_phys;
int logging_level;
int fwfault_debug;
u8 ir_firmware;
@@ -853,6 +853,8 @@ int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz);
+int mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz);
int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOCPage8_t *config_page);
int mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c
index 594a389c6526..411c27d7f787 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_config.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_config.c
@@ -324,7 +324,9 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
if (r != 0)
goto out;
if (mpi_request->Action ==
- MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT) {
+ MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT ||
+ mpi_request->Action ==
+ MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
ioc->base_add_sg_single(&mpi_request->PageBufferSGE,
MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz,
mem.page_dma);
@@ -882,7 +884,7 @@ mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
}
/**
- * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 0
+ * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 1
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
@@ -907,7 +909,7 @@ mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION;
+ mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
@@ -922,6 +924,49 @@ mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
}
/**
+ * mpt2sas_config_set_sas_iounit_pg1 - send sas iounit page 1
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @sz: size of buffer passed in config_page
+ * Context: sleep.
+ *
+ * Calling function should call config_get_number_hba_phys prior to
+ * this function, so enough memory is allocated for config_page.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz)
+{
+ Mpi2ConfigRequest_t mpi_request;
+ int r;
+
+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+ mpi_request.Function = MPI2_FUNCTION_CONFIG;
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+ mpi_request.Header.PageNumber = 1;
+ mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION;
+ mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
+ if (r)
+ goto out;
+
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+ _config_request(ioc, &mpi_request, mpi_reply,
+ MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
+ out:
+ return r;
+}
+
+/**
* mpt2sas_config_get_expander_pg0 - obtain expander page 0
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index 84a124f8e21f..fa9bf83819d5 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -891,6 +891,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
issue_host_reset:
if (issue_reset) {
+ ret = -ENODATA;
if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
mpi_request->Function ==
MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
@@ -2202,14 +2203,10 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg)
karg.data_out_size = karg32.data_out_size;
karg.max_sense_bytes = karg32.max_sense_bytes;
karg.data_sge_offset = karg32.data_sge_offset;
- memcpy(&karg.reply_frame_buf_ptr, &karg32.reply_frame_buf_ptr,
- sizeof(uint32_t));
- memcpy(&karg.data_in_buf_ptr, &karg32.data_in_buf_ptr,
- sizeof(uint32_t));
- memcpy(&karg.data_out_buf_ptr, &karg32.data_out_buf_ptr,
- sizeof(uint32_t));
- memcpy(&karg.sense_data_ptr, &karg32.sense_data_ptr,
- sizeof(uint32_t));
+ karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr);
+ karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr);
+ karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr);
+ karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr);
state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING;
return _ctl_do_mpt_command(ioc, karg, &uarg->mf, state);
}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index efabea1a3ce4..c7ec3f174782 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -52,6 +52,7 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/raid_class.h>
#include "mpt2sas_base.h"
@@ -133,6 +134,9 @@ struct fw_event_work {
void *event_data;
};
+/* raid transport support */
+static struct raid_template *mpt2sas_raid_template;
+
/**
* struct _scsi_io_transfer - scsi io transfer
* @handle: sas device handle (assigned by firmware)
@@ -1305,7 +1309,6 @@ _scsih_slave_alloc(struct scsi_device *sdev)
struct MPT2SAS_DEVICE *sas_device_priv_data;
struct scsi_target *starget;
struct _raid_device *raid_device;
- struct _sas_device *sas_device;
unsigned long flags;
sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
@@ -1332,21 +1335,8 @@ _scsih_slave_alloc(struct scsi_device *sdev)
if (raid_device)
raid_device->sdev = sdev; /* raid is single lun */
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- } else {
- /* set TLR bit for SSP devices */
- if (!(ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_TLR))
- goto out;
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
- sas_device_priv_data->sas_target->sas_address);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device && sas_device->device_info &
- MPI2_SAS_DEVICE_INFO_SSP_TARGET)
- sas_device_priv_data->flags |= MPT_DEVICE_TLR_ON;
}
- out:
return 0;
}
@@ -1419,6 +1409,140 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
}
/**
+ * _scsih_is_raid - return boolean indicating device is raid volume
+ * @dev the device struct object
+ */
+static int
+_scsih_is_raid(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ return (sdev->channel == RAID_CHANNEL) ? 1 : 0;
+}
+
+/**
+ * _scsih_get_resync - get raid volume resync percent complete
+ * @dev the device struct object
+ */
+static void
+_scsih_get_resync(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
+ static struct _raid_device *raid_device;
+ unsigned long flags;
+ Mpi2RaidVolPage0_t vol_pg0;
+ Mpi2ConfigReply_t mpi_reply;
+ u32 volume_status_flags;
+ u8 percent_complete = 0;
+
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
+ raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
+ sdev->channel);
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+
+ if (!raid_device)
+ goto out;
+
+ if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
+ sizeof(Mpi2RaidVolPage0_t))) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ goto out;
+ }
+
+ volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags);
+ if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
+ percent_complete = raid_device->percent_complete;
+ out:
+ raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
+}
+
+/**
+ * _scsih_get_state - get raid volume level
+ * @dev the device struct object
+ */
+static void
+_scsih_get_state(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
+ static struct _raid_device *raid_device;
+ unsigned long flags;
+ Mpi2RaidVolPage0_t vol_pg0;
+ Mpi2ConfigReply_t mpi_reply;
+ u32 volstate;
+ enum raid_state state = RAID_STATE_UNKNOWN;
+
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
+ raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
+ sdev->channel);
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+
+ if (!raid_device)
+ goto out;
+
+ if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
+ sizeof(Mpi2RaidVolPage0_t))) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ goto out;
+ }
+
+ volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags);
+ if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
+ state = RAID_STATE_RESYNCING;
+ goto out;
+ }
+
+ switch (vol_pg0.VolumeState) {
+ case MPI2_RAID_VOL_STATE_OPTIMAL:
+ case MPI2_RAID_VOL_STATE_ONLINE:
+ state = RAID_STATE_ACTIVE;
+ break;
+ case MPI2_RAID_VOL_STATE_DEGRADED:
+ state = RAID_STATE_DEGRADED;
+ break;
+ case MPI2_RAID_VOL_STATE_FAILED:
+ case MPI2_RAID_VOL_STATE_MISSING:
+ state = RAID_STATE_OFFLINE;
+ break;
+ }
+ out:
+ raid_set_state(mpt2sas_raid_template, dev, state);
+}
+
+/**
+ * _scsih_set_level - set raid level
+ * @sdev: scsi device struct
+ * @raid_device: raid_device object
+ */
+static void
+_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device)
+{
+ enum raid_level level = RAID_LEVEL_UNKNOWN;
+
+ switch (raid_device->volume_type) {
+ case MPI2_RAID_VOL_TYPE_RAID0:
+ level = RAID_LEVEL_0;
+ break;
+ case MPI2_RAID_VOL_TYPE_RAID10:
+ level = RAID_LEVEL_10;
+ break;
+ case MPI2_RAID_VOL_TYPE_RAID1E:
+ level = RAID_LEVEL_1E;
+ break;
+ case MPI2_RAID_VOL_TYPE_RAID1:
+ level = RAID_LEVEL_1;
+ break;
+ }
+
+ raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level);
+}
+
+/**
* _scsih_get_volume_capabilities - volume capabilities
* @ioc: per adapter object
* @sas_device: the raid_device object
@@ -1479,6 +1603,32 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
}
/**
+ * _scsih_enable_tlr - setting TLR flags
+ * @ioc: per adapter object
+ * @sdev: scsi device struct
+ *
+ * Enabling Transaction Layer Retries for tape devices when
+ * vpd page 0x90 is present
+ *
+ */
+static void
+_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev)
+{
+ /* only for TAPE */
+ if (sdev->type != TYPE_TAPE)
+ return;
+
+ if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR))
+ return;
+
+ sas_enable_tlr(sdev);
+ sdev_printk(KERN_INFO, sdev, "TLR %s\n",
+ sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled");
+ return;
+
+}
+
+/**
* _scsih_slave_configure - device configure routine.
* @sdev: scsi device struct
*
@@ -1574,6 +1724,8 @@ _scsih_slave_configure(struct scsi_device *sdev)
(unsigned long long)raid_device->wwid,
raid_device->num_pds, ds);
_scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
+ /* raid transport support */
+ _scsih_set_level(sdev, raid_device);
return 0;
}
@@ -1621,8 +1773,10 @@ _scsih_slave_configure(struct scsi_device *sdev)
_scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
- if (ssp_target)
+ if (ssp_target) {
sas_read_port_mode_page(sdev);
+ _scsih_enable_tlr(ioc, sdev);
+ }
return 0;
}
@@ -2908,8 +3062,9 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
} else
mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
-
- if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON))
+ /* Make sure Device is not raid volume */
+ if (!_scsih_is_raid(&scmd->device->sdev_gendev) &&
+ sas_is_tlr_enabled(scmd->device))
mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
@@ -3298,10 +3453,12 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
if (!sas_device_priv_data->tlr_snoop_check) {
sas_device_priv_data->tlr_snoop_check++;
- if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) &&
- response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
- sas_device_priv_data->flags &=
- ~MPT_DEVICE_TLR_ON;
+ if (!_scsih_is_raid(&scmd->device->sdev_gendev) &&
+ sas_is_tlr_enabled(scmd->device) &&
+ response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {
+ sas_disable_tlr(scmd->device);
+ sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n");
+ }
}
xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
@@ -5170,11 +5327,33 @@ static void
_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
struct fw_event_work *fw_event)
{
+ Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data;
+ static struct _raid_device *raid_device;
+ unsigned long flags;
+ u16 handle;
+
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
_scsih_sas_ir_operation_status_event_debug(ioc,
- fw_event->event_data);
+ event_data);
#endif
+
+ /* code added for raid transport support */
+ if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
+
+ handle = le16_to_cpu(event_data->VolDevHandle);
+
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
+ raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+
+ if (!raid_device)
+ return;
+
+ if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC)
+ raid_device->percent_complete =
+ event_data->PercentComplete;
+ }
}
/**
@@ -5998,6 +6177,8 @@ _scsih_remove(struct pci_dev *pdev)
struct _sas_port *mpt2sas_port;
struct _sas_device *sas_device;
struct _sas_node *expander_sibling;
+ struct _raid_device *raid_device, *next;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
struct workqueue_struct *wq;
unsigned long flags;
@@ -6011,6 +6192,21 @@ _scsih_remove(struct pci_dev *pdev)
if (wq)
destroy_workqueue(wq);
+ /* release all the volumes */
+ list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
+ list) {
+ if (raid_device->starget) {
+ sas_target_priv_data =
+ raid_device->starget->hostdata;
+ sas_target_priv_data->deleted = 1;
+ scsi_remove_target(&raid_device->starget->dev);
+ }
+ printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
+ "(0x%016llx)\n", ioc->name, raid_device->handle,
+ (unsigned long long) raid_device->wwid);
+ _scsih_raid_device_remove(ioc, raid_device);
+ }
+
/* free ports attached to the sas_host */
retry_again:
list_for_each_entry(mpt2sas_port,
@@ -6373,6 +6569,13 @@ static struct pci_driver scsih_driver = {
#endif
};
+/* raid transport support */
+static struct raid_function_template mpt2sas_raid_functions = {
+ .cookie = &scsih_driver_template,
+ .is_raid = _scsih_is_raid,
+ .get_resync = _scsih_get_resync,
+ .get_state = _scsih_get_state,
+};
/**
* _scsih_init - main entry point for this driver.
@@ -6392,6 +6595,12 @@ _scsih_init(void)
sas_attach_transport(&mpt2sas_transport_functions);
if (!mpt2sas_transport_template)
return -ENODEV;
+ /* raid transport support */
+ mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions);
+ if (!mpt2sas_raid_template) {
+ sas_release_transport(mpt2sas_transport_template);
+ return -ENODEV;
+ }
mpt2sas_base_initialize_callback_handler();
@@ -6426,8 +6635,11 @@ _scsih_init(void)
mpt2sas_ctl_init();
error = pci_register_driver(&scsih_driver);
- if (error)
+ if (error) {
+ /* raid transport support */
+ raid_class_release(mpt2sas_raid_template);
sas_release_transport(mpt2sas_transport_template);
+ }
return error;
}
@@ -6445,7 +6657,8 @@ _scsih_exit(void)
pci_unregister_driver(&scsih_driver);
- sas_release_transport(mpt2sas_transport_template);
+ mpt2sas_ctl_exit();
+
mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
mpt2sas_base_release_callback_handler(tm_cb_idx);
mpt2sas_base_release_callback_handler(base_cb_idx);
@@ -6457,7 +6670,10 @@ _scsih_exit(void)
mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
- mpt2sas_ctl_exit();
+ /* raid transport support */
+ raid_class_release(mpt2sas_raid_template);
+ sas_release_transport(mpt2sas_transport_template);
+
}
module_init(_scsih_init);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index 3a82872bad44..789f9ee7f001 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -855,6 +855,17 @@ rphy_to_ioc(struct sas_rphy *rphy)
return shost_priv(shost);
}
+static struct _sas_phy *
+_transport_find_local_phy(struct MPT2SAS_ADAPTER *ioc, struct sas_phy *phy)
+{
+ int i;
+
+ for (i = 0; i < ioc->sas_hba.num_phys; i++)
+ if (ioc->sas_hba.phy[i].phy == phy)
+ return(&ioc->sas_hba.phy[i]);
+ return NULL;
+}
+
/**
* _transport_get_linkerrors -
* @phy: The sas phy object
@@ -870,14 +881,8 @@ _transport_get_linkerrors(struct sas_phy *phy)
struct _sas_phy *mpt2sas_phy;
Mpi2ConfigReply_t mpi_reply;
Mpi2SasPhyPage1_t phy_pg1;
- int i;
- for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
- !mpt2sas_phy; i++) {
- if (ioc->sas_hba.phy[i].phy != phy)
- continue;
- mpt2sas_phy = &ioc->sas_hba.phy[i];
- }
+ mpt2sas_phy = _transport_find_local_phy(ioc, phy);
if (!mpt2sas_phy) /* this phy not on sas_host */
return -EINVAL;
@@ -971,14 +976,8 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset)
struct _sas_phy *mpt2sas_phy;
Mpi2SasIoUnitControlReply_t mpi_reply;
Mpi2SasIoUnitControlRequest_t mpi_request;
- int i;
- for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
- !mpt2sas_phy; i++) {
- if (ioc->sas_hba.phy[i].phy != phy)
- continue;
- mpt2sas_phy = &ioc->sas_hba.phy[i];
- }
+ mpt2sas_phy = _transport_find_local_phy(ioc, phy);
if (!mpt2sas_phy) /* this phy not on sas_host */
return -EINVAL;
@@ -1006,6 +1005,173 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset)
}
/**
+ * _transport_phy_enable - enable/disable phys
+ * @phy: The sas phy object
+ * @enable: enable phy when true
+ *
+ * Only support sas_host direct attached phys.
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_transport_phy_enable(struct sas_phy *phy, int enable)
+{
+ struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
+ struct _sas_phy *mpt2sas_phy;
+ Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
+ Mpi2ConfigReply_t mpi_reply;
+ u16 ioc_status;
+ u16 sz;
+ int rc = 0;
+
+ mpt2sas_phy = _transport_find_local_phy(ioc, phy);
+
+ if (!mpt2sas_phy) /* this phy not on sas_host */
+ return -EINVAL;
+
+ /* sas_iounit page 1 */
+ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
+ sizeof(Mpi2SasIOUnit1PhyData_t));
+ sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
+ if (!sas_iounit_pg1) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+ if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
+ sas_iounit_pg1, sz))) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ rc = -ENXIO;
+ goto out;
+ }
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ rc = -EIO;
+ goto out;
+ }
+
+ if (enable)
+ sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
+ &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
+ else
+ sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
+ |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
+
+ mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz);
+
+ out:
+ kfree(sas_iounit_pg1);
+ return rc;
+}
+
+/**
+ * _transport_phy_speed - set phy min/max link rates
+ * @phy: The sas phy object
+ * @rates: rates defined in sas_phy_linkrates
+ *
+ * Only support sas_host direct attached phys.
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
+{
+ struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
+ struct _sas_phy *mpt2sas_phy;
+ Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
+ Mpi2SasPhyPage0_t phy_pg0;
+ Mpi2ConfigReply_t mpi_reply;
+ u16 ioc_status;
+ u16 sz;
+ int i;
+ int rc = 0;
+
+ mpt2sas_phy = _transport_find_local_phy(ioc, phy);
+
+ if (!mpt2sas_phy) /* this phy not on sas_host */
+ return -EINVAL;
+
+ if (!rates->minimum_linkrate)
+ rates->minimum_linkrate = phy->minimum_linkrate;
+ else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
+ rates->minimum_linkrate = phy->minimum_linkrate_hw;
+
+ if (!rates->maximum_linkrate)
+ rates->maximum_linkrate = phy->maximum_linkrate;
+ else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
+ rates->maximum_linkrate = phy->maximum_linkrate_hw;
+
+ /* sas_iounit page 1 */
+ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
+ sizeof(Mpi2SasIOUnit1PhyData_t));
+ sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
+ if (!sas_iounit_pg1) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+ if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
+ sas_iounit_pg1, sz))) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ rc = -ENXIO;
+ goto out;
+ }
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ rc = -EIO;
+ goto out;
+ }
+
+ for (i = 0; i < ioc->sas_hba.num_phys; i++) {
+ if (mpt2sas_phy->phy_id != i) {
+ sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
+ (ioc->sas_hba.phy[i].phy->minimum_linkrate +
+ (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4));
+ } else {
+ sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
+ (rates->minimum_linkrate +
+ (rates->maximum_linkrate << 4));
+ }
+ }
+
+ if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
+ sz)) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ rc = -ENXIO;
+ goto out;
+ }
+
+ /* link reset */
+ _transport_phy_reset(phy, 0);
+
+ /* read phy page 0, then update the rates in the sas transport phy */
+ if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
+ mpt2sas_phy->phy_id)) {
+ phy->minimum_linkrate = _transport_convert_phy_link_rate(
+ phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
+ phy->maximum_linkrate = _transport_convert_phy_link_rate(
+ phy_pg0.ProgrammedLinkRate >> 4);
+ phy->negotiated_linkrate = _transport_convert_phy_link_rate(
+ phy_pg0.NegotiatedLinkRate &
+ MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
+ }
+
+ out:
+ kfree(sas_iounit_pg1);
+ return rc;
+}
+
+
+/**
* _transport_smp_handler - transport portal for smp passthru
* @shost: shost object
* @rphy: sas transport rphy object
@@ -1207,6 +1373,8 @@ struct sas_function_template mpt2sas_transport_functions = {
.get_enclosure_identifier = _transport_get_enclosure_identifier,
.get_bay_identifier = _transport_get_bay_identifier,
.phy_reset = _transport_phy_reset,
+ .phy_enable = _transport_phy_enable,
+ .set_phy_speed = _transport_phy_speed,
.smp_handler = _transport_smp_handler,
};
diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
index 7db28cd49446..8c61a4fe1db9 100644
--- a/drivers/scsi/pcmcia/nsp_cs.h
+++ b/drivers/scsi/pcmcia/nsp_cs.h
@@ -187,7 +187,7 @@
#define S_IO BIT(1) /* Input/Output line from SCSI bus */
#define S_CD BIT(2) /* Command/Data line from SCSI bus */
#define S_BUSY BIT(3) /* Busy line from SCSI bus */
-#define S_ACK BIT(4) /* Acknowlege line from SCSI bus */
+#define S_ACK BIT(4) /* Acknowledge line from SCSI bus */
#define S_REQUEST BIT(5) /* Request line from SCSI bus */
#define S_SELECT BIT(6) /* */
#define S_ATN BIT(7) /* */
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 9b44c6f1b10e..7985ae45d688 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -2924,7 +2924,7 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
break;
default:
PM8001_MSG_DBG(pm8001_ha,
- pm8001_printk("unkown device type(%x)\n", deviceType));
+ pm8001_printk("unknown device type(%x)\n", deviceType));
break;
}
phy->phy_type |= PORT_TYPE_SAS;
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index c2f1032496cb..f80c1da8f6ca 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -654,7 +654,7 @@ static int __devinit pm8001_pci_probe(struct pci_dev *pdev,
}
chip = &pm8001_chips[ent->driver_data];
SHOST_TO_SAS_HA(shost) =
- kcalloc(1, sizeof(struct sas_ha_struct), GFP_KERNEL);
+ kzalloc(sizeof(struct sas_ha_struct), GFP_KERNEL);
if (!SHOST_TO_SAS_HA(shost)) {
rc = -ENOMEM;
goto err_out_free_host;
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index 7f9c83a76390..3b2c98fba834 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -600,7 +600,7 @@ static void pm8001_free_dev(struct pm8001_device *pm8001_dev)
* by the command "OPC_INB_REG_DEV", after that the HBA will assign a
* device ID(according to device's sas address) and returned it to LLDD. From
* now on, we communicate with HBA FW with the device ID which HBA assigned
- * rather than sas address. it is the neccessary step for our HBA but it is
+ * rather than sas address. it is the necessary step for our HBA but it is
* the optional for other HBA driver.
*/
static int pm8001_dev_found_notify(struct domain_device *dev)
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index b6f1ef954af1..9b1c1433c26b 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -235,7 +235,7 @@ static int pmcraid_slave_configure(struct scsi_device *scsi_dev)
scsi_dev->allow_restart = 1;
blk_queue_rq_timeout(scsi_dev->request_queue,
PMCRAID_VSET_IO_TIMEOUT);
- blk_queue_max_sectors(scsi_dev->request_queue,
+ blk_queue_max_hw_sectors(scsi_dev->request_queue,
PMCRAID_VSET_MAX_SECTORS);
}
diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h
index 92f89d50850c..b8ad07c3449e 100644
--- a/drivers/scsi/pmcraid.h
+++ b/drivers/scsi/pmcraid.h
@@ -938,7 +938,7 @@ static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = {
/*
* pmcraid_ioctl_header - definition of header structure that preceeds all the
- * buffers given as ioctl arguements.
+ * buffers given as ioctl arguments.
*
* .signature : always ASCII string, "PMCRAID"
* .reserved : not used
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 8371d917a9a2..49ac4148493b 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -1640,8 +1640,10 @@ qla1280_load_firmware_pio(struct scsi_qla_host *ha)
uint16_t mb[MAILBOX_REGISTER_COUNT], i;
int err;
+ spin_unlock_irq(ha->host->host_lock);
err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname,
&ha->pdev->dev);
+ spin_lock_irq(ha->host->host_lock);
if (err) {
printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
ql1280_board_tbl[ha->devnum].fwname, err);
@@ -1699,8 +1701,10 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
return -ENOMEM;
#endif
+ spin_unlock_irq(ha->host->host_lock);
err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname,
&ha->pdev->dev);
+ spin_lock_irq(ha->host->host_lock);
if (err) {
printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
ql1280_board_tbl[ha->devnum].fwname, err);
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 3a9f5b288aee..90d1e062ec4f 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -11,7 +11,9 @@
#include <linux/delay.h>
static int qla24xx_vport_disable(struct fc_vport *, bool);
-
+static int qla84xx_reset(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *);
+int qla84xx_reset_chip(scsi_qla_host_t *, uint16_t, uint16_t *);
+static int qla84xx_mgmt_cmd(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *);
/* SYSFS attributes --------------------------------------------------------- */
static ssize_t
@@ -1168,6 +1170,28 @@ qla2x00_total_isp_aborts_show(struct device *dev,
}
static ssize_t
+qla24xx_84xx_fw_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int rval = QLA_SUCCESS;
+ uint16_t status[2] = {0, 0};
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ struct qla_hw_data *ha = vha->hw;
+
+ if (IS_QLA84XX(ha) && ha->cs84xx) {
+ if (ha->cs84xx->op_fw_version == 0) {
+ rval = qla84xx_verify_chip(vha, status);
+ }
+
+ if ((rval == QLA_SUCCESS) && (status[0] == 0))
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ (uint32_t)ha->cs84xx->op_fw_version);
+ }
+
+ return snprintf(buf, PAGE_SIZE, "\n");
+}
+
+static ssize_t
qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -1281,6 +1305,8 @@ static DEVICE_ATTR(optrom_fcode_version, S_IRUGO,
qla2x00_optrom_fcode_version_show, NULL);
static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show,
NULL);
+static DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show,
+ NULL);
static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show,
NULL);
static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL);
@@ -1310,6 +1336,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_optrom_efi_version,
&dev_attr_optrom_fcode_version,
&dev_attr_optrom_fw_version,
+ &dev_attr_84xx_fw_version,
&dev_attr_total_isp_aborts,
&dev_attr_mpi_version,
&dev_attr_phy_version,
@@ -1504,8 +1531,6 @@ qla2x00_terminate_rport_io(struct fc_rport *rport)
fcport->vha->hw->isp_ops->fabric_logout(fcport->vha,
fcport->loop_id, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa);
-
- qla2x00_abort_fcport_cmds(fcport);
}
static int
@@ -1795,6 +1820,581 @@ qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable)
return 0;
}
+/* BSG support for ELS/CT pass through */
+inline srb_t *
+qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size)
+{
+ srb_t *sp;
+ struct qla_hw_data *ha = vha->hw;
+ struct srb_bsg_ctx *ctx;
+
+ sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL);
+ if (!sp)
+ goto done;
+ ctx = kzalloc(size, GFP_KERNEL);
+ if (!ctx) {
+ mempool_free(sp, ha->srb_mempool);
+ goto done;
+ }
+
+ memset(sp, 0, sizeof(*sp));
+ sp->fcport = fcport;
+ sp->ctx = ctx;
+done:
+ return sp;
+}
+
+static int
+qla2x00_process_els(struct fc_bsg_job *bsg_job)
+{
+ struct fc_rport *rport;
+ fc_port_t *fcport;
+ struct Scsi_Host *host;
+ scsi_qla_host_t *vha;
+ struct qla_hw_data *ha;
+ srb_t *sp;
+ const char *type;
+ int req_sg_cnt, rsp_sg_cnt;
+ int rval = (DRIVER_ERROR << 16);
+ uint16_t nextlid = 0;
+ struct srb_bsg *els;
+
+ /* Multiple SG's are not supported for ELS requests */
+ if (bsg_job->request_payload.sg_cnt > 1 ||
+ bsg_job->reply_payload.sg_cnt > 1) {
+ DEBUG2(printk(KERN_INFO
+ "multiple SG's are not supported for ELS requests"
+ " [request_sg_cnt: %x reply_sg_cnt: %x]\n",
+ bsg_job->request_payload.sg_cnt,
+ bsg_job->reply_payload.sg_cnt));
+ rval = -EPERM;
+ goto done;
+ }
+
+ /* ELS request for rport */
+ if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
+ rport = bsg_job->rport;
+ fcport = *(fc_port_t **) rport->dd_data;
+ host = rport_to_shost(rport);
+ vha = shost_priv(host);
+ ha = vha->hw;
+ type = "FC_BSG_RPT_ELS";
+
+ /* make sure the rport is logged in,
+ * if not perform fabric login
+ */
+ if (qla2x00_fabric_login(vha, fcport, &nextlid)) {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "failed to login port %06X for ELS passthru\n",
+ fcport->d_id.b24));
+ rval = -EIO;
+ goto done;
+ }
+ } else {
+ host = bsg_job->shost;
+ vha = shost_priv(host);
+ ha = vha->hw;
+ type = "FC_BSG_HST_ELS_NOLOGIN";
+
+ /* Allocate a dummy fcport structure, since functions
+ * preparing the IOCB and mailbox command retrieves port
+ * specific information from fcport structure. For Host based
+ * ELS commands there will be no fcport structure allocated
+ */
+ fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+ if (!fcport) {
+ rval = -ENOMEM;
+ goto done;
+ }
+
+ /* Initialize all required fields of fcport */
+ fcport->vha = vha;
+ fcport->vp_idx = vha->vp_idx;
+ fcport->d_id.b.al_pa =
+ bsg_job->request->rqst_data.h_els.port_id[0];
+ fcport->d_id.b.area =
+ bsg_job->request->rqst_data.h_els.port_id[1];
+ fcport->d_id.b.domain =
+ bsg_job->request->rqst_data.h_els.port_id[2];
+ fcport->loop_id =
+ (fcport->d_id.b.al_pa == 0xFD) ?
+ NPH_FABRIC_CONTROLLER : NPH_F_PORT;
+ }
+
+ if (!vha->flags.online) {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "host not online\n"));
+ rval = -EIO;
+ goto done;
+ }
+
+ req_sg_cnt =
+ dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ if (!req_sg_cnt) {
+ rval = -ENOMEM;
+ goto done_free_fcport;
+ }
+ rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ if (!rsp_sg_cnt) {
+ rval = -ENOMEM;
+ goto done_free_fcport;
+ }
+
+ if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) ||
+ (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt))
+ {
+ DEBUG2(printk(KERN_INFO
+ "dma mapping resulted in different sg counts \
+ [request_sg_cnt: %x dma_request_sg_cnt: %x\
+ reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
+ bsg_job->request_payload.sg_cnt, req_sg_cnt,
+ bsg_job->reply_payload.sg_cnt, rsp_sg_cnt));
+ rval = -EAGAIN;
+ goto done_unmap_sg;
+ }
+
+ /* Alloc SRB structure */
+ sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg));
+ if (!sp) {
+ rval = -ENOMEM;
+ goto done_unmap_sg;
+ }
+
+ els = sp->ctx;
+ els->ctx.type =
+ (bsg_job->request->msgcode == FC_BSG_RPT_ELS ?
+ SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST);
+ els->bsg_job = bsg_job;
+
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x "
+ "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type,
+ bsg_job->request->rqst_data.h_els.command_code,
+ fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa));
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS) {
+ kfree(sp->ctx);
+ mempool_free(sp, ha->srb_mempool);
+ rval = -EIO;
+ goto done_unmap_sg;
+ }
+ return rval;
+
+done_unmap_sg:
+ dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ goto done_free_fcport;
+
+done_free_fcport:
+ if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN)
+ kfree(fcport);
+done:
+ return rval;
+}
+
+static int
+qla2x00_process_ct(struct fc_bsg_job *bsg_job)
+{
+ srb_t *sp;
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ int rval = (DRIVER_ERROR << 16);
+ int req_sg_cnt, rsp_sg_cnt;
+ uint16_t loop_id;
+ struct fc_port *fcport;
+ char *type = "FC_BSG_HST_CT";
+ struct srb_bsg *ct;
+
+ /* pass through is supported only for ISP 4Gb or higher */
+ if (!IS_FWI2_CAPABLE(ha)) {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld):Firmware is not capable to support FC "
+ "CT pass thru\n", vha->host_no));
+ rval = -EPERM;
+ goto done;
+ }
+
+ req_sg_cnt =
+ dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ if (!req_sg_cnt) {
+ rval = -ENOMEM;
+ goto done;
+ }
+
+ rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ if (!rsp_sg_cnt) {
+ rval = -ENOMEM;
+ goto done;
+ }
+
+ if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) ||
+ (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt))
+ {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "dma mapping resulted in different sg counts \
+ [request_sg_cnt: %x dma_request_sg_cnt: %x\
+ reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
+ bsg_job->request_payload.sg_cnt, req_sg_cnt,
+ bsg_job->reply_payload.sg_cnt, rsp_sg_cnt));
+ rval = -EAGAIN;
+ goto done_unmap_sg;
+ }
+
+ if (!vha->flags.online) {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "host not online\n"));
+ rval = -EIO;
+ goto done_unmap_sg;
+ }
+
+ loop_id =
+ (bsg_job->request->rqst_data.h_ct.preamble_word1 & 0xFF000000)
+ >> 24;
+ switch (loop_id) {
+ case 0xFC:
+ loop_id = cpu_to_le16(NPH_SNS);
+ break;
+ case 0xFA:
+ loop_id = vha->mgmt_svr_loop_id;
+ break;
+ default:
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "Unknown loop id: %x\n", loop_id));
+ rval = -EINVAL;
+ goto done_unmap_sg;
+ }
+
+ /* Allocate a dummy fcport structure, since functions preparing the
+ * IOCB and mailbox command retrieves port specific information
+ * from fcport structure. For Host based ELS commands there will be
+ * no fcport structure allocated
+ */
+ fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+ if (!fcport)
+ {
+ rval = -ENOMEM;
+ goto done_unmap_sg;
+ }
+
+ /* Initialize all required fields of fcport */
+ fcport->vha = vha;
+ fcport->vp_idx = vha->vp_idx;
+ fcport->d_id.b.al_pa = bsg_job->request->rqst_data.h_ct.port_id[0];
+ fcport->d_id.b.area = bsg_job->request->rqst_data.h_ct.port_id[1];
+ fcport->d_id.b.domain = bsg_job->request->rqst_data.h_ct.port_id[2];
+ fcport->loop_id = loop_id;
+
+ /* Alloc SRB structure */
+ sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg));
+ if (!sp) {
+ rval = -ENOMEM;
+ goto done_free_fcport;
+ }
+
+ ct = sp->ctx;
+ ct->ctx.type = SRB_CT_CMD;
+ ct->bsg_job = bsg_job;
+
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x "
+ "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type,
+ (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16),
+ fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa));
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS) {
+ kfree(sp->ctx);
+ mempool_free(sp, ha->srb_mempool);
+ rval = -EIO;
+ goto done_free_fcport;
+ }
+ return rval;
+
+done_free_fcport:
+ kfree(fcport);
+done_unmap_sg:
+ dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+done:
+ return rval;
+}
+
+static int
+qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ int rval;
+ uint8_t command_sent;
+ uint32_t vendor_cmd;
+ char *type;
+ struct msg_echo_lb elreq;
+ uint16_t response[MAILBOX_REGISTER_COUNT];
+ uint8_t* fw_sts_ptr;
+ uint8_t *req_data;
+ dma_addr_t req_data_dma;
+ uint32_t req_data_len;
+ uint8_t *rsp_data;
+ dma_addr_t rsp_data_dma;
+ uint32_t rsp_data_len;
+
+ if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
+ test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
+ test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+ rval = -EBUSY;
+ goto done;
+ }
+
+ if (!vha->flags.online) {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "host not online\n"));
+ rval = -EIO;
+ goto done;
+ }
+
+ elreq.req_sg_cnt =
+ dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ if (!elreq.req_sg_cnt) {
+ rval = -ENOMEM;
+ goto done;
+ }
+ elreq.rsp_sg_cnt =
+ dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ if (!elreq.rsp_sg_cnt) {
+ rval = -ENOMEM;
+ goto done;
+ }
+
+ if ((elreq.req_sg_cnt != bsg_job->request_payload.sg_cnt) ||
+ (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt))
+ {
+ DEBUG2(printk(KERN_INFO
+ "dma mapping resulted in different sg counts \
+ [request_sg_cnt: %x dma_request_sg_cnt: %x\
+ reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
+ bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt,
+ bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt));
+ rval = -EAGAIN;
+ goto done_unmap_sg;
+ }
+ req_data_len = rsp_data_len = bsg_job->request_payload.payload_len;
+ req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len,
+ &req_data_dma, GFP_KERNEL);
+
+ rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len,
+ &rsp_data_dma, GFP_KERNEL);
+
+ /* Copy the request buffer in req_data now */
+ sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, req_data,
+ req_data_len);
+
+ elreq.send_dma = req_data_dma;
+ elreq.rcv_dma = rsp_data_dma;
+ elreq.transfer_size = req_data_len;
+
+ /* Vendor cmd : loopback or ECHO diagnostic
+ * Options:
+ * Loopback : Either internal or external loopback
+ * ECHO: ECHO ELS or Vendor specific FC4 link data
+ */
+ vendor_cmd = bsg_job->request->rqst_data.h_vendor.vendor_cmd[0];
+ elreq.options =
+ *(((uint32_t *)bsg_job->request->rqst_data.h_vendor.vendor_cmd)
+ + 1);
+
+ switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) {
+ case QL_VND_LOOPBACK:
+ if (ha->current_topology != ISP_CFG_F) {
+ type = "FC_BSG_HST_VENDOR_LOOPBACK";
+
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n",
+ vha->host_no, type, vendor_cmd, elreq.options));
+
+ command_sent = INT_DEF_LB_LOOPBACK_CMD;
+ rval = qla2x00_loopback_test(vha, &elreq, response);
+ if (IS_QLA81XX(ha)) {
+ if (response[0] == MBS_COMMAND_ERROR && response[1] == MBS_LB_RESET) {
+ DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing "
+ "ISP\n", __func__, vha->host_no));
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ }
+ }
+ } else {
+ type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n",
+ vha->host_no, type, vendor_cmd, elreq.options));
+
+ command_sent = INT_DEF_LB_ECHO_CMD;
+ rval = qla2x00_echo_test(vha, &elreq, response);
+ }
+ break;
+ case QLA84_RESET:
+ if (!IS_QLA84XX(vha->hw)) {
+ rval = -EINVAL;
+ DEBUG16(printk(
+ "%s(%ld): 8xxx exiting.\n",
+ __func__, vha->host_no));
+ return rval;
+ }
+ rval = qla84xx_reset(vha, &elreq, bsg_job);
+ break;
+ case QLA84_MGMT_CMD:
+ if (!IS_QLA84XX(vha->hw)) {
+ rval = -EINVAL;
+ DEBUG16(printk(
+ "%s(%ld): 8xxx exiting.\n",
+ __func__, vha->host_no));
+ return rval;
+ }
+ rval = qla84xx_mgmt_cmd(vha, &elreq, bsg_job);
+ break;
+ default:
+ rval = -ENOSYS;
+ }
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "scsi(%ld) Vendor request %s failed\n", vha->host_no, type));
+ rval = 0;
+ bsg_job->reply->result = (DID_ERROR << 16);
+ bsg_job->reply->reply_payload_rcv_len = 0;
+ fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
+ memcpy( fw_sts_ptr, response, sizeof(response));
+ fw_sts_ptr += sizeof(response);
+ *fw_sts_ptr = command_sent;
+ } else {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "scsi(%ld) Vendor request %s completed\n", vha->host_no, type));
+ rval = bsg_job->reply->result = 0;
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(response) + sizeof(uint8_t);
+ bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
+ fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
+ memcpy(fw_sts_ptr, response, sizeof(response));
+ fw_sts_ptr += sizeof(response);
+ *fw_sts_ptr = command_sent;
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, rsp_data,
+ rsp_data_len);
+ }
+ bsg_job->job_done(bsg_job);
+
+done_unmap_sg:
+
+ if(req_data)
+ dma_free_coherent(&ha->pdev->dev, req_data_len,
+ req_data, req_data_dma);
+ dma_unmap_sg(&ha->pdev->dev,
+ bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ dma_unmap_sg(&ha->pdev->dev,
+ bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+
+done:
+ return rval;
+}
+
+static int
+qla24xx_bsg_request(struct fc_bsg_job *bsg_job)
+{
+ int ret = -EINVAL;
+
+ switch (bsg_job->request->msgcode) {
+ case FC_BSG_RPT_ELS:
+ case FC_BSG_HST_ELS_NOLOGIN:
+ ret = qla2x00_process_els(bsg_job);
+ break;
+ case FC_BSG_HST_CT:
+ ret = qla2x00_process_ct(bsg_job);
+ break;
+ case FC_BSG_HST_VENDOR:
+ ret = qla2x00_process_vendor_specific(bsg_job);
+ break;
+ case FC_BSG_HST_ADD_RPORT:
+ case FC_BSG_HST_DEL_RPORT:
+ case FC_BSG_RPT_CT:
+ default:
+ DEBUG2(printk("qla2xxx: unsupported BSG request\n"));
+ break;
+ }
+ return ret;
+}
+
+static int
+qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
+{
+ scsi_qla_host_t *vha = shost_priv(bsg_job->shost);
+ struct qla_hw_data *ha = vha->hw;
+ srb_t *sp;
+ int cnt, que;
+ unsigned long flags;
+ struct req_que *req;
+ struct srb_bsg *sp_bsg;
+
+ /* find the bsg job from the active list of commands */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (que = 0; que < ha->max_req_queues; que++) {
+ req = ha->req_q_map[que];
+ if (!req)
+ continue;
+
+ for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++ ) {
+ sp = req->outstanding_cmds[cnt];
+
+ if (sp) {
+ sp_bsg = (struct srb_bsg*)sp->ctx;
+
+ if (((sp_bsg->ctx.type == SRB_CT_CMD) ||
+ (sp_bsg->ctx.type == SRB_ELS_CMD_RPT)
+ || ( sp_bsg->ctx.type == SRB_ELS_CMD_HST)) &&
+ (sp_bsg->bsg_job == bsg_job)) {
+ if (ha->isp_ops->abort_command(sp)) {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld): mbx abort_command failed\n", vha->host_no));
+ bsg_job->req->errors = bsg_job->reply->result = -EIO;
+ } else {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld): mbx abort_command success\n", vha->host_no));
+ bsg_job->req->errors = bsg_job->reply->result = 0;
+ }
+ goto done;
+ }
+ }
+ }
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld) SRB not found to abort\n", vha->host_no));
+ bsg_job->req->errors = bsg_job->reply->result = -ENXIO;
+ return 0;
+
+done:
+ if (bsg_job->request->msgcode == FC_BSG_HST_CT)
+ kfree(sp->fcport);
+ kfree(sp->ctx);
+ mempool_free(sp, ha->srb_mempool);
+ return 0;
+}
+
struct fc_function_template qla2xxx_transport_functions = {
.show_host_node_name = 1,
@@ -1838,6 +2438,8 @@ struct fc_function_template qla2xxx_transport_functions = {
.vport_create = qla24xx_vport_create,
.vport_disable = qla24xx_vport_disable,
.vport_delete = qla24xx_vport_delete,
+ .bsg_request = qla24xx_bsg_request,
+ .bsg_timeout = qla24xx_bsg_timeout,
};
struct fc_function_template qla2xxx_transport_vport_functions = {
@@ -1878,6 +2480,8 @@ struct fc_function_template qla2xxx_transport_vport_functions = {
.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
.terminate_rport_io = qla2x00_terminate_rport_io,
.get_fc_host_stats = qla2x00_get_fc_host_stats,
+ .bsg_request = qla24xx_bsg_request,
+ .bsg_timeout = qla24xx_bsg_timeout,
};
void
@@ -1906,3 +2510,125 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha)
speed = FC_PORTSPEED_1GBIT;
fc_host_supported_speeds(vha->host) = speed;
}
+static int
+qla84xx_reset(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job)
+{
+ int ret = 0;
+ int cmd;
+ uint16_t cmd_status;
+
+ DEBUG16(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ cmd = (*((bsg_job->request->rqst_data.h_vendor.vendor_cmd) + 2))
+ == A84_RESET_FLAG_ENABLE_DIAG_FW ?
+ A84_ISSUE_RESET_DIAG_FW : A84_ISSUE_RESET_OP_FW;
+ ret = qla84xx_reset_chip(ha, cmd == A84_ISSUE_RESET_DIAG_FW,
+ &cmd_status);
+ return ret;
+}
+
+static int
+qla84xx_mgmt_cmd(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job)
+{
+ struct access_chip_84xx *mn;
+ dma_addr_t mn_dma, mgmt_dma;
+ void *mgmt_b = NULL;
+ int ret = 0;
+ int rsp_hdr_len, len = 0;
+ struct qla84_msg_mgmt *ql84_mgmt;
+
+ ql84_mgmt = (struct qla84_msg_mgmt *) vmalloc(sizeof(struct qla84_msg_mgmt));
+ ql84_mgmt->cmd =
+ *((uint16_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 2));
+ ql84_mgmt->mgmtp.u.mem.start_addr =
+ *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 3));
+ ql84_mgmt->len =
+ *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 4));
+ ql84_mgmt->mgmtp.u.config.id =
+ *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 5));
+ ql84_mgmt->mgmtp.u.config.param0 =
+ *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 6));
+ ql84_mgmt->mgmtp.u.config.param1 =
+ *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 7));
+ ql84_mgmt->mgmtp.u.info.type =
+ *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 8));
+ ql84_mgmt->mgmtp.u.info.context =
+ *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 9));
+
+ rsp_hdr_len = bsg_job->request_payload.payload_len;
+
+ mn = dma_pool_alloc(ha->hw->s_dma_pool, GFP_KERNEL, &mn_dma);
+ if (mn == NULL) {
+ DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer "
+ "failed%lu\n", __func__, ha->host_no));
+ return -ENOMEM;
+ }
+
+ memset(mn, 0, sizeof (struct access_chip_84xx));
+
+ mn->entry_type = ACCESS_CHIP_IOCB_TYPE;
+ mn->entry_count = 1;
+
+ switch (ql84_mgmt->cmd) {
+ case QLA84_MGMT_READ_MEM:
+ mn->options = cpu_to_le16(ACO_DUMP_MEMORY);
+ mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr);
+ break;
+ case QLA84_MGMT_WRITE_MEM:
+ mn->options = cpu_to_le16(ACO_LOAD_MEMORY);
+ mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr);
+ break;
+ case QLA84_MGMT_CHNG_CONFIG:
+ mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM);
+ mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.id);
+ mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param0);
+ mn->parameter3 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param1);
+ break;
+ case QLA84_MGMT_GET_INFO:
+ mn->options = cpu_to_le16(ACO_REQUEST_INFO);
+ mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.type);
+ mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.context);
+ break;
+ default:
+ ret = -EIO;
+ goto exit_mgmt0;
+ }
+
+ if ((len == ql84_mgmt->len) &&
+ ql84_mgmt->cmd != QLA84_MGMT_CHNG_CONFIG) {
+ mgmt_b = dma_alloc_coherent(&ha->hw->pdev->dev, len,
+ &mgmt_dma, GFP_KERNEL);
+ if (mgmt_b == NULL) {
+ DEBUG2(printk(KERN_ERR "%s: dma alloc mgmt_b "
+ "failed%lu\n", __func__, ha->host_no));
+ ret = -ENOMEM;
+ goto exit_mgmt0;
+ }
+ mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->len);
+ mn->dseg_count = cpu_to_le16(1);
+ mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma));
+ mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma));
+ mn->dseg_length = cpu_to_le32(len);
+
+ if (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) {
+ memcpy(mgmt_b, ql84_mgmt->payload, len);
+ }
+ }
+
+ ret = qla2x00_issue_iocb(ha, mn, mn_dma, 0);
+ if ((ret != QLA_SUCCESS) || (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM)
+ || (ql84_mgmt->cmd == QLA84_MGMT_CHNG_CONFIG)) {
+ if (ret != QLA_SUCCESS)
+ DEBUG2(printk(KERN_ERR "%s(%lu): failed\n",
+ __func__, ha->host_no));
+ } else if ((ql84_mgmt->cmd == QLA84_MGMT_READ_MEM) ||
+ (ql84_mgmt->cmd == QLA84_MGMT_GET_INFO)) {
+ }
+
+ if (mgmt_b)
+ dma_free_coherent(&ha->hw->pdev->dev, len, mgmt_b, mgmt_dma);
+
+exit_mgmt0:
+ dma_pool_free(ha->hw->s_dma_pool, mn, mn_dma);
+ return ret;
+}
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 608e675f68c8..afa95614aaf8 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -31,6 +31,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_transport_fc.h>
+#include <scsi/scsi_bsg_fc.h>
#define QLA2XXX_DRIVER_NAME "qla2xxx"
@@ -228,6 +229,27 @@ struct srb_logio {
uint16_t flags;
};
+struct srb_bsg_ctx {
+#define SRB_ELS_CMD_RPT 3
+#define SRB_ELS_CMD_HST 4
+#define SRB_CT_CMD 5
+ uint16_t type;
+};
+
+struct srb_bsg {
+ struct srb_bsg_ctx ctx;
+ struct fc_bsg_job *bsg_job;
+};
+
+struct msg_echo_lb {
+ dma_addr_t send_dma;
+ dma_addr_t rcv_dma;
+ uint16_t req_sg_cnt;
+ uint16_t rsp_sg_cnt;
+ uint16_t options;
+ uint32_t transfer_size;
+};
+
/*
* ISP I/O Register Set structure definitions.
*/
@@ -522,6 +544,8 @@ typedef struct {
#define MBA_DISCARD_RND_FRAME 0x8048 /* discard RND frame due to error. */
#define MBA_REJECTED_FCP_CMD 0x8049 /* rejected FCP_CMD. */
+/* ISP mailbox loopback echo diagnostic error code */
+#define MBS_LB_RESET 0x17
/*
* Firmware options 1, 2, 3.
*/
@@ -1586,8 +1610,7 @@ typedef struct fc_port {
*/
#define FCF_FABRIC_DEVICE BIT_0
#define FCF_LOGIN_NEEDED BIT_1
-#define FCF_TAPE_PRESENT BIT_2
-#define FCF_FCP2_DEVICE BIT_3
+#define FCF_FCP2_DEVICE BIT_2
/* No loop ID flag. */
#define FC_NO_LOOP_ID 0x1000
@@ -2231,6 +2254,13 @@ struct req_que {
int max_q_depth;
};
+/* Place holder for FW buffer parameters */
+struct qlfc_fw {
+ void *fw_buf;
+ dma_addr_t fw_dma;
+ uint32_t len;
+};
+
/*
* Qlogic host adapter specific data structure.
*/
@@ -2595,6 +2625,7 @@ struct qla_hw_data {
struct qla_statistics qla_stats;
struct isp_operations *isp_ops;
struct workqueue_struct *wq;
+ struct qlfc_fw fw_buf;
};
/*
@@ -2767,4 +2798,127 @@ typedef struct scsi_qla_host {
#define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr)
+/*
+ * BSG Vendor specific commands
+ */
+
+#define QL_VND_LOOPBACK 0x01
+#define QLA84_RESET 0x02
+#define QLA84_UPDATE_FW 0x03
+#define QLA84_MGMT_CMD 0x04
+
+/* BSG definations for interpreting CommandSent field */
+#define INT_DEF_LB_LOOPBACK_CMD 0
+#define INT_DEF_LB_ECHO_CMD 1
+
+/* BSG Vendor specific definations */
+typedef struct _A84_RESET {
+ uint16_t Flags;
+ uint16_t Reserved;
+#define A84_RESET_FLAG_ENABLE_DIAG_FW 1
+} __attribute__((packed)) A84_RESET, *PA84_RESET;
+
+#define A84_ISSUE_WRITE_TYPE_CMD 0
+#define A84_ISSUE_READ_TYPE_CMD 1
+#define A84_CLEANUP_CMD 2
+#define A84_ISSUE_RESET_OP_FW 3
+#define A84_ISSUE_RESET_DIAG_FW 4
+#define A84_ISSUE_UPDATE_OPFW_CMD 5
+#define A84_ISSUE_UPDATE_DIAGFW_CMD 6
+
+struct qla84_mgmt_param {
+ union {
+ struct {
+ uint32_t start_addr;
+ } mem; /* for QLA84_MGMT_READ/WRITE_MEM */
+ struct {
+ uint32_t id;
+#define QLA84_MGMT_CONFIG_ID_UIF 1
+#define QLA84_MGMT_CONFIG_ID_FCOE_COS 2
+#define QLA84_MGMT_CONFIG_ID_PAUSE 3
+#define QLA84_MGMT_CONFIG_ID_TIMEOUTS 4
+
+ uint32_t param0;
+ uint32_t param1;
+ } config; /* for QLA84_MGMT_CHNG_CONFIG */
+
+ struct {
+ uint32_t type;
+#define QLA84_MGMT_INFO_CONFIG_LOG_DATA 1 /* Get Config Log Data */
+#define QLA84_MGMT_INFO_LOG_DATA 2 /* Get Log Data */
+#define QLA84_MGMT_INFO_PORT_STAT 3 /* Get Port Statistics */
+#define QLA84_MGMT_INFO_LIF_STAT 4 /* Get LIF Statistics */
+#define QLA84_MGMT_INFO_ASIC_STAT 5 /* Get ASIC Statistics */
+#define QLA84_MGMT_INFO_CONFIG_PARAMS 6 /* Get Config Parameters */
+#define QLA84_MGMT_INFO_PANIC_LOG 7 /* Get Panic Log */
+
+ uint32_t context;
+/*
+* context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA
+*/
+#define IC_LOG_DATA_LOG_ID_DEBUG_LOG 0
+#define IC_LOG_DATA_LOG_ID_LEARN_LOG 1
+#define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG 2
+#define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG 3
+#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG 4
+#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG 5
+#define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG 6
+#define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG 7
+#define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG 8
+#define IC_LOG_DATA_LOG_ID_DCX_LOG 9
+
+/*
+* context definitions for QLA84_MGMT_INFO_PORT_STAT
+*/
+#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0 0
+#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1 1
+#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0 2
+#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1 3
+#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0 4
+#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1 5
+
+
+/*
+* context definitions for QLA84_MGMT_INFO_LIF_STAT
+*/
+#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0 0
+#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1 1
+#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0 2
+#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1 3
+#define IC_LIF_STATISTICS_LIF_NUMBER_CPU 6
+
+ } info; /* for QLA84_MGMT_GET_INFO */
+ } u;
+};
+
+struct qla84_msg_mgmt {
+ uint16_t cmd;
+#define QLA84_MGMT_READ_MEM 0x00
+#define QLA84_MGMT_WRITE_MEM 0x01
+#define QLA84_MGMT_CHNG_CONFIG 0x02
+#define QLA84_MGMT_GET_INFO 0x03
+ uint16_t rsrvd;
+ struct qla84_mgmt_param mgmtp;/* parameters for cmd */
+ uint32_t len; /* bytes in payload following this struct */
+ uint8_t payload[0]; /* payload for cmd */
+};
+
+struct msg_update_fw {
+ /*
+ * diag_fw = 0 operational fw
+ * otherwise diagnostic fw
+ * offset, len, fw_len are present to overcome the current limitation
+ * of 128Kb xfer size. The fw is sent in smaller chunks. Each chunk
+ * specifies the byte "offset" where it fits in the fw buffer. The
+ * number of bytes in each chunk is specified in "len". "fw_len"
+ * is the total size of fw. The first chunk should start at offset = 0.
+ * When offset+len == fw_len, the fw is written to the HBA.
+ */
+ uint32_t diag_fw;
+ uint32_t offset;/* start offset */
+ uint32_t len; /* num bytes in cur xfer */
+ uint32_t fw_len; /* size of fw in bytes */
+ uint8_t fw_bytes[0];
+};
+
#endif
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 66a8da5d7d08..cebf4f1bb7d9 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -627,6 +627,39 @@ struct els_entry_24xx {
uint32_t rx_len; /* Data segment 1 length. */
};
+struct els_sts_entry_24xx {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define; /* System Defined. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+
+ uint16_t comp_status;
+
+ uint16_t nport_handle; /* N_PORT handle. */
+
+ uint16_t reserved_1;
+
+ uint8_t vp_index;
+ uint8_t sof_type;
+
+ uint32_t rx_xchg_address; /* Receive exchange address. */
+ uint16_t reserved_2;
+
+ uint8_t opcode;
+ uint8_t reserved_3;
+
+ uint8_t port_id[3];
+ uint8_t reserved_4;
+
+ uint16_t reserved_5;
+
+ uint16_t control_flags; /* Control flags. */
+ uint32_t total_byte_count;
+ uint32_t error_subcode_1;
+ uint32_t error_subcode_2;
+};
/*
* ISP queue - Mailbox Command entry structure definition.
*/
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index f61fb8d01330..3a89bc514e2b 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -60,6 +60,8 @@ extern int qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,
extern int qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
+extern fc_port_t *
+qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t );
/*
* Global Data in qla_os.c source file.
*/
@@ -76,6 +78,7 @@ extern int ql2xiidmaenable;
extern int ql2xmaxqueues;
extern int ql2xmultique_tag;
extern int ql2xfwloadbin;
+extern int ql2xetsenable;
extern int qla2x00_loop_reset(scsi_qla_host_t *);
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -94,7 +97,6 @@ extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
-extern void qla2x00_abort_fcport_cmds(fc_port_t *);
extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *,
struct qla_hw_data *);
extern void qla2x00_free_host(struct scsi_qla_host *);
@@ -154,6 +156,7 @@ int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
uint16_t, uint16_t, uint8_t);
extern int qla2x00_start_sp(srb_t *);
+extern void qla2x00_ctx_sp_free(srb_t *);
/*
* Global Function Prototypes in qla_mbx.c source file.
@@ -426,6 +429,8 @@ extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
extern void qla2x00_init_host_attr(scsi_qla_host_t *);
extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
+extern int qla2x00_loopback_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *);
+extern int qla2x00_echo_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *);
/*
* Global Function Prototypes in qla_dfs.c source file.
@@ -453,6 +458,5 @@ extern void qla24xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);
extern void qla25xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);
extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
-extern struct scsi_qla_host * qla25xx_get_host(struct rsp_que *);
#endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index b4a0eac8f96d..a67b2bafb882 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -62,7 +62,7 @@ qla2x00_ctx_sp_timeout(unsigned long __data)
ctx->free(sp);
}
-static void
+void
qla2x00_ctx_sp_free(srb_t *sp)
{
struct srb_ctx *ctx = sp->ctx;
@@ -205,7 +205,7 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
switch (data[0]) {
case MBS_COMMAND_COMPLETE:
- if (fcport->flags & FCF_TAPE_PRESENT)
+ if (fcport->flags & FCF_FCP2_DEVICE)
opts |= BIT_1;
rval = qla2x00_get_port_database(vha, fcport, opts);
if (rval != QLA_SUCCESS)
@@ -338,6 +338,16 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
rval = qla2x00_init_rings(vha);
ha->flags.chip_reset_done = 1;
+ if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) {
+ /* Issue verify 84xx FW IOCB to complete 84xx initialization */
+ rval = qla84xx_init_chip(vha);
+ if (rval != QLA_SUCCESS) {
+ qla_printk(KERN_ERR, ha,
+ "Unable to initialize ISP84XX.\n");
+ qla84xx_put_chip(vha);
+ }
+ }
+
return (rval);
}
@@ -2216,7 +2226,7 @@ qla2x00_rport_del(void *data)
*
* Returns a pointer to the allocated fcport, or NULL, if none available.
*/
-static fc_port_t *
+fc_port_t *
qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
{
fc_port_t *fcport;
@@ -2726,7 +2736,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
/*
* Logout all previous fabric devices marked lost, except
- * tape devices.
+ * FCP2 devices.
*/
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
@@ -2739,7 +2749,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
qla2x00_mark_device_lost(vha, fcport,
ql2xplogiabsentdevice, 0);
if (fcport->loop_id != FC_NO_LOOP_ID &&
- (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
+ (fcport->flags & FCF_FCP2_DEVICE) == 0 &&
fcport->port_type != FCT_INITIATOR &&
fcport->port_type != FCT_BROADCAST) {
ha->isp_ops->fabric_logout(vha,
@@ -2900,8 +2910,13 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
if (qla2x00_is_reserved_id(vha, loop_id))
continue;
- if (atomic_read(&vha->loop_down_timer) || LOOP_TRANSITION(vha))
+ if (atomic_read(&vha->loop_down_timer) ||
+ LOOP_TRANSITION(vha)) {
+ atomic_set(&vha->loop_down_timer, 0);
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
break;
+ }
if (swl != NULL) {
if (last_dev) {
@@ -3018,7 +3033,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
fcport->d_id.b24 = new_fcport->d_id.b24;
fcport->flags |= FCF_LOGIN_NEEDED;
if (fcport->loop_id != FC_NO_LOOP_ID &&
- (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
+ (fcport->flags & FCF_FCP2_DEVICE) == 0 &&
fcport->port_type != FCT_INITIATOR &&
fcport->port_type != FCT_BROADCAST) {
ha->isp_ops->fabric_logout(vha, fcport->loop_id,
@@ -3272,9 +3287,9 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport,
rval = qla2x00_fabric_login(vha, fcport, next_loopid);
if (rval == QLA_SUCCESS) {
- /* Send an ADISC to tape devices.*/
+ /* Send an ADISC to FCP2 devices.*/
opts = 0;
- if (fcport->flags & FCF_TAPE_PRESENT)
+ if (fcport->flags & FCF_FCP2_DEVICE)
opts |= BIT_1;
rval = qla2x00_get_port_database(vha, fcport, opts);
if (rval != QLA_SUCCESS) {
@@ -4877,6 +4892,15 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
}
void
-qla81xx_update_fw_options(scsi_qla_host_t *ha)
+qla81xx_update_fw_options(scsi_qla_host_t *vha)
{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!ql2xetsenable)
+ return;
+
+ /* Enable ETS Burst. */
+ memset(ha->fw_options, 0, sizeof(ha->fw_options));
+ ha->fw_options[2] |= BIT_9;
+ qla2x00_set_fw_options(vha, ha->fw_options);
}
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c5ccac0bef76..8299a9891bfe 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -1025,6 +1025,119 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx)
/* Implicit: mbx->mbx10 = 0. */
}
+static void
+qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
+{
+ struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job;
+
+ els_iocb->entry_type = ELS_IOCB_TYPE;
+ els_iocb->entry_count = 1;
+ els_iocb->sys_define = 0;
+ els_iocb->entry_status = 0;
+ els_iocb->handle = sp->handle;
+ els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+ els_iocb->tx_dsd_count = __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt);
+ els_iocb->vp_index = sp->fcport->vp_idx;
+ els_iocb->sof_type = EST_SOFI3;
+ els_iocb->rx_dsd_count = __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt);
+
+ els_iocb->opcode =(((struct srb_bsg*)sp->ctx)->ctx.type == SRB_ELS_CMD_RPT) ?
+ bsg_job->request->rqst_data.r_els.els_code : bsg_job->request->rqst_data.h_els.command_code;
+ els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
+ els_iocb->port_id[1] = sp->fcport->d_id.b.area;
+ els_iocb->port_id[2] = sp->fcport->d_id.b.domain;
+ els_iocb->control_flags = 0;
+ els_iocb->rx_byte_count =
+ cpu_to_le32(bsg_job->reply_payload.payload_len);
+ els_iocb->tx_byte_count =
+ cpu_to_le32(bsg_job->request_payload.payload_len);
+
+ els_iocb->tx_address[0] = cpu_to_le32(LSD(sg_dma_address
+ (bsg_job->request_payload.sg_list)));
+ els_iocb->tx_address[1] = cpu_to_le32(MSD(sg_dma_address
+ (bsg_job->request_payload.sg_list)));
+ els_iocb->tx_len = cpu_to_le32(sg_dma_len
+ (bsg_job->request_payload.sg_list));
+
+ els_iocb->rx_address[0] = cpu_to_le32(LSD(sg_dma_address
+ (bsg_job->reply_payload.sg_list)));
+ els_iocb->rx_address[1] = cpu_to_le32(MSD(sg_dma_address
+ (bsg_job->reply_payload.sg_list)));
+ els_iocb->rx_len = cpu_to_le32(sg_dma_len
+ (bsg_job->reply_payload.sg_list));
+}
+
+static void
+qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
+{
+ uint16_t avail_dsds;
+ uint32_t *cur_dsd;
+ struct scatterlist *sg;
+ int index;
+ uint16_t tot_dsds;
+ scsi_qla_host_t *vha = sp->fcport->vha;
+ struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job;
+ int loop_iterartion = 0;
+ int cont_iocb_prsnt = 0;
+ int entry_count = 1;
+
+ ct_iocb->entry_type = CT_IOCB_TYPE;
+ ct_iocb->entry_status = 0;
+ ct_iocb->sys_define = 0;
+ ct_iocb->handle = sp->handle;
+
+ ct_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+ ct_iocb->vp_index = sp->fcport->vp_idx;
+ ct_iocb->comp_status = __constant_cpu_to_le16(0);
+
+ ct_iocb->cmd_dsd_count =
+ __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt);
+ ct_iocb->timeout = 0;
+ ct_iocb->rsp_dsd_count =
+ __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt);
+ ct_iocb->rsp_byte_count =
+ cpu_to_le32(bsg_job->reply_payload.payload_len);
+ ct_iocb->cmd_byte_count =
+ cpu_to_le32(bsg_job->request_payload.payload_len);
+ ct_iocb->dseg_0_address[0] = cpu_to_le32(LSD(sg_dma_address
+ (bsg_job->request_payload.sg_list)));
+ ct_iocb->dseg_0_address[1] = cpu_to_le32(MSD(sg_dma_address
+ (bsg_job->request_payload.sg_list)));
+ ct_iocb->dseg_0_len = cpu_to_le32(sg_dma_len
+ (bsg_job->request_payload.sg_list));
+
+ avail_dsds = 1;
+ cur_dsd = (uint32_t *)ct_iocb->dseg_1_address;
+ index = 0;
+ tot_dsds = bsg_job->reply_payload.sg_cnt;
+
+ for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) {
+ dma_addr_t sle_dma;
+ cont_a64_entry_t *cont_pkt;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Five DSDs are available in the Cont.
+ * Type 1 IOCB.
+ */
+ cont_pkt = qla2x00_prep_cont_type1_iocb(vha);
+ cur_dsd = (uint32_t *) cont_pkt->dseg_0_address;
+ avail_dsds = 5;
+ cont_iocb_prsnt = 1;
+ entry_count++;
+ }
+
+ sle_dma = sg_dma_address(sg);
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ loop_iterartion++;
+ avail_dsds--;
+ }
+ ct_iocb->entry_count = entry_count;
+}
+
int
qla2x00_start_sp(srb_t *sp)
{
@@ -1052,6 +1165,13 @@ qla2x00_start_sp(srb_t *sp)
qla24xx_logout_iocb(sp, pkt):
qla2x00_logout_iocb(sp, pkt);
break;
+ case SRB_ELS_CMD_RPT:
+ case SRB_ELS_CMD_HST:
+ qla24xx_els_iocb(sp, pkt);
+ break;
+ case SRB_CT_CMD:
+ qla24xx_ct_iocb(sp, pkt);
+ break;
default:
break;
}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index ffd0efdff40e..ab90329ff2e4 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -8,6 +8,7 @@
#include <linux/delay.h>
#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_bsg_fc.h>
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
static void qla2x00_process_completed_request(struct scsi_qla_host *,
@@ -881,7 +882,9 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
index);
return NULL;
}
+
req->outstanding_cmds[index] = NULL;
+
done:
return sp;
}
@@ -982,6 +985,100 @@ done_post_logio_done_work:
}
static void
+qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
+ struct sts_entry_24xx *pkt, int iocb_type)
+{
+ const char func[] = "ELS_CT_IOCB";
+ const char *type;
+ struct qla_hw_data *ha = vha->hw;
+ srb_t *sp;
+ struct srb_bsg *sp_bsg;
+ struct fc_bsg_job *bsg_job;
+ uint16_t comp_status;
+ uint32_t fw_status[3];
+ uint8_t* fw_sts_ptr;
+
+ sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
+ if (!sp)
+ return;
+ sp_bsg = (struct srb_bsg*)sp->ctx;
+ bsg_job = sp_bsg->bsg_job;
+
+ type = NULL;
+ switch (sp_bsg->ctx.type) {
+ case SRB_ELS_CMD_RPT:
+ case SRB_ELS_CMD_HST:
+ type = "els";
+ break;
+ case SRB_CT_CMD:
+ type = "ct pass-through";
+ break;
+ default:
+ qla_printk(KERN_WARNING, ha,
+ "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
+ sp_bsg->ctx.type);
+ return;
+ }
+
+ comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status);
+ fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1);
+ fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2);
+
+ /* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
+ * fc payload to the caller
+ */
+ bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status);
+
+ if (comp_status != CS_COMPLETE) {
+ if (comp_status == CS_DATA_UNDERRUN) {
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->reply->reply_payload_rcv_len =
+ le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count);
+
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
+ "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
+ vha->host_no, sp->handle, type, comp_status, fw_status[1], fw_status[2],
+ le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count)));
+ fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
+ memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
+ }
+ else {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
+ "error subcode 1=0x%x error subcode 2=0x%x.\n",
+ vha->host_no, sp->handle, type, comp_status,
+ le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1),
+ le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2)));
+ bsg_job->reply->result = DID_ERROR << 16;
+ bsg_job->reply->reply_payload_rcv_len = 0;
+ fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
+ memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
+ }
+ DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt)));
+ }
+ else {
+ bsg_job->reply->result = DID_OK << 16;;
+ bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
+ bsg_job->reply_len = 0;
+ }
+
+ dma_unmap_sg(&ha->pdev->dev,
+ bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ dma_unmap_sg(&ha->pdev->dev,
+ bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ if ((sp_bsg->ctx.type == SRB_ELS_CMD_HST) ||
+ (sp_bsg->ctx.type == SRB_CT_CMD))
+ kfree(sp->fcport);
+ kfree(sp->ctx);
+ mempool_free(sp, ha->srb_mempool);
+ bsg_job->job_done(bsg_job);
+}
+
+static void
qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
struct logio_entry_24xx *logio)
{
@@ -1749,6 +1846,13 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
qla24xx_logio_entry(vha, rsp->req,
(struct logio_entry_24xx *)pkt);
break;
+ case CT_IOCB_TYPE:
+ qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
+ clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags);
+ break;
+ case ELS_IOCB_TYPE:
+ qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
+ break;
default:
/* Type Not Supported. */
DEBUG4(printk(KERN_WARNING
@@ -1917,6 +2021,7 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
struct rsp_que *rsp;
struct device_reg_24xx __iomem *reg;
struct scsi_qla_host *vha;
+ unsigned long flags;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -1927,15 +2032,15 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
ha = rsp->hw;
reg = &ha->iobase->isp24;
- spin_lock_irq(&ha->hardware_lock);
+ spin_lock_irqsave(&ha->hardware_lock, flags);
- vha = qla25xx_get_host(rsp);
+ vha = pci_get_drvdata(ha->pdev);
qla24xx_process_response_queue(vha, rsp);
if (!ha->flags.disable_msix_handshake) {
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
RD_REG_DWORD_RELAXED(&reg->hccr);
}
- spin_unlock_irq(&ha->hardware_lock);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
return IRQ_HANDLED;
}
@@ -1946,6 +2051,7 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
struct qla_hw_data *ha;
struct rsp_que *rsp;
struct device_reg_24xx __iomem *reg;
+ unsigned long flags;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -1958,10 +2064,10 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
/* Clear the interrupt, if enabled, for this response queue */
if (rsp->options & ~BIT_6) {
reg = &ha->iobase->isp24;
- spin_lock_irq(&ha->hardware_lock);
+ spin_lock_irqsave(&ha->hardware_lock, flags);
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
RD_REG_DWORD_RELAXED(&reg->hccr);
- spin_unlock_irq(&ha->hardware_lock);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work);
@@ -1979,6 +2085,7 @@ qla24xx_msix_default(int irq, void *dev_id)
uint32_t stat;
uint32_t hccr;
uint16_t mb[4];
+ unsigned long flags;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -1990,7 +2097,7 @@ qla24xx_msix_default(int irq, void *dev_id)
reg = &ha->iobase->isp24;
status = 0;
- spin_lock_irq(&ha->hardware_lock);
+ spin_lock_irqsave(&ha->hardware_lock, flags);
vha = pci_get_drvdata(ha->pdev);
do {
stat = RD_REG_DWORD(&reg->host_status);
@@ -2039,14 +2146,13 @@ qla24xx_msix_default(int irq, void *dev_id)
}
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
} while (0);
- spin_unlock_irq(&ha->hardware_lock);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
(status & MBX_INTERRUPT) && ha->flags.mbox_int) {
set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
complete(&ha->mbx_intr_comp);
}
-
return IRQ_HANDLED;
}
@@ -2252,10 +2358,11 @@ qla2x00_free_irqs(scsi_qla_host_t *vha)
if (ha->flags.msix_enabled)
qla24xx_disable_msix(ha);
- else if (ha->flags.inta_enabled) {
+ else if (ha->flags.msi_enabled) {
free_irq(ha->pdev->irq, rsp);
pci_disable_msi(ha->pdev);
- }
+ } else
+ free_irq(ha->pdev->irq, rsp);
}
@@ -2277,30 +2384,3 @@ int qla25xx_request_irq(struct rsp_que *rsp)
msix->rsp = rsp;
return ret;
}
-
-struct scsi_qla_host *
-qla25xx_get_host(struct rsp_que *rsp)
-{
- srb_t *sp;
- struct qla_hw_data *ha = rsp->hw;
- struct scsi_qla_host *vha = NULL;
- struct sts_entry_24xx *pkt;
- struct req_que *req;
- uint16_t que;
- uint32_t handle;
-
- pkt = (struct sts_entry_24xx *) rsp->ring_ptr;
- que = MSW(pkt->handle);
- handle = (uint32_t) LSW(pkt->handle);
- req = ha->req_q_map[que];
- if (handle < MAX_OUTSTANDING_COMMANDS) {
- sp = req->outstanding_cmds[handle];
- if (sp)
- return sp->fcport->vha;
- else
- goto base_que;
- }
-base_que:
- vha = pci_get_drvdata(ha->pdev);
- return vha;
-}
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 056e4d4505f3..6e53bdbb1da8 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -3636,6 +3636,157 @@ qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data)
}
int
+qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mresp)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ uint32_t iter_cnt = 0x1;
+
+ DEBUG11(printk("scsi(%ld): entered.\n", vha->host_no));
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_DIAGNOSTIC_LOOP_BACK;
+ mcp->mb[1] = mreq->options | BIT_6; // BIT_6 specifies 64 bit addressing
+
+ /* transfer count */
+ mcp->mb[10] = LSW(mreq->transfer_size);
+ mcp->mb[11] = MSW(mreq->transfer_size);
+
+ /* send data address */
+ mcp->mb[14] = LSW(mreq->send_dma);
+ mcp->mb[15] = MSW(mreq->send_dma);
+ mcp->mb[20] = LSW(MSD(mreq->send_dma));
+ mcp->mb[21] = MSW(MSD(mreq->send_dma));
+
+ /* recieve data address */
+ mcp->mb[16] = LSW(mreq->rcv_dma);
+ mcp->mb[17] = MSW(mreq->rcv_dma);
+ mcp->mb[6] = LSW(MSD(mreq->rcv_dma));
+ mcp->mb[7] = MSW(MSD(mreq->rcv_dma));
+
+ /* Iteration count */
+ mcp->mb[18] = LSW(iter_cnt);
+ mcp->mb[19] = MSW(iter_cnt);
+
+ mcp->out_mb = MBX_21|MBX_20|MBX_19|MBX_18|MBX_17|MBX_16|MBX_15|
+ MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0;
+ if (IS_QLA81XX(vha->hw))
+ mcp->out_mb |= MBX_2;
+ mcp->in_mb = MBX_19|MBX_18|MBX_3|MBX_2|MBX_1|MBX_0;
+
+ mcp->buf_size = mreq->transfer_size;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD;
+
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2(printk(KERN_WARNING
+ "(%ld): failed=%x mb[0]=0x%x "
+ "mb[1]=0x%x mb[2]=0x%x mb[3]=0x%x mb[18]=0x%x mb[19]=0x%x. \n", vha->host_no, rval,
+ mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[18], mcp->mb[19]));
+ } else {
+ DEBUG2(printk(KERN_WARNING
+ "scsi(%ld): done.\n", vha->host_no));
+ }
+
+ /* Copy mailbox information */
+ memcpy( mresp, mcp->mb, 64);
+ mresp[3] = mcp->mb[18];
+ mresp[4] = mcp->mb[19];
+ return rval;
+}
+
+int
+qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mresp)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
+
+ DEBUG11(printk("scsi(%ld): entered.\n", vha->host_no));
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_DIAGNOSTIC_ECHO;
+ mcp->mb[1] = mreq->options | BIT_6; /* BIT_6 specifies 64bit address */
+ if (IS_QLA81XX(ha))
+ mcp->mb[1] |= BIT_15;
+ mcp->mb[2] = IS_QLA81XX(ha) ? vha->fcoe_fcf_idx : 0;
+ mcp->mb[16] = LSW(mreq->rcv_dma);
+ mcp->mb[17] = MSW(mreq->rcv_dma);
+ mcp->mb[6] = LSW(MSD(mreq->rcv_dma));
+ mcp->mb[7] = MSW(MSD(mreq->rcv_dma));
+
+ mcp->mb[10] = LSW(mreq->transfer_size);
+
+ mcp->mb[14] = LSW(mreq->send_dma);
+ mcp->mb[15] = MSW(mreq->send_dma);
+ mcp->mb[20] = LSW(MSD(mreq->send_dma));
+ mcp->mb[21] = MSW(MSD(mreq->send_dma));
+
+ mcp->out_mb = MBX_21|MBX_20|MBX_17|MBX_16|MBX_15|
+ MBX_14|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0;
+ if (IS_QLA81XX(ha))
+ mcp->out_mb |= MBX_2;
+
+ mcp->in_mb = MBX_0;
+ if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha))
+ mcp->in_mb |= MBX_1;
+ if (IS_QLA81XX(ha))
+ mcp->in_mb |= MBX_3;
+
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD;
+ mcp->buf_size = mreq->transfer_size;
+
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2(printk(KERN_WARNING
+ "(%ld): failed=%x mb[0]=0x%x mb[1]=0x%x.\n",
+ vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+ } else {
+ DEBUG2(printk(KERN_WARNING
+ "scsi(%ld): done.\n", vha->host_no));
+ }
+
+ /* Copy mailbox information */
+ memcpy( mresp, mcp->mb, 32);
+ return rval;
+}
+int
+qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic,
+ uint16_t *cmd_status)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ DEBUG16(printk("%s(%ld): enable_diag=%d entered.\n", __func__,
+ ha->host_no, enable_diagnostic));
+
+ mcp->mb[0] = MBC_ISP84XX_RESET;
+ mcp->mb[1] = enable_diagnostic;
+ mcp->out_mb = MBX_1|MBX_0;
+ mcp->in_mb = MBX_1|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ /* Return mailbox statuses. */
+ *cmd_status = mcp->mb[0];
+ if (rval != QLA_SUCCESS)
+ DEBUG16(printk("%s(%ld): failed=%x.\n", __func__, ha->host_no,
+ rval));
+ else
+ DEBUG16(printk("%s(%ld): done.\n", __func__, ha->host_no));
+
+ return rval;
+}
+
+int
qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data)
{
int rval;
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index b901aa267e7d..ff17dee28613 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -636,13 +636,15 @@ failed:
static void qla_do_work(struct work_struct *work)
{
+ unsigned long flags;
struct rsp_que *rsp = container_of(work, struct rsp_que, q_work);
struct scsi_qla_host *vha;
+ struct qla_hw_data *ha = rsp->hw;
- spin_lock_irq(&rsp->hw->hardware_lock);
- vha = qla25xx_get_host(rsp);
+ spin_lock_irqsave(&rsp->hw->hardware_lock, flags);
+ vha = pci_get_drvdata(ha->pdev);
qla24xx_process_response_queue(vha, rsp);
- spin_unlock_irq(&rsp->hw->hardware_lock);
+ spin_unlock_irqrestore(&rsp->hw->hardware_lock, flags);
}
/* create response queue */
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 209f50e788a1..46720b23028f 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -107,6 +107,12 @@ MODULE_PARM_DESC(ql2xfwloadbin,
" 1 -- load firmware from flash.\n"
" 0 -- use default semantics.\n");
+int ql2xetsenable;
+module_param(ql2xetsenable, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xetsenable,
+ "Enables firmware ETS burst."
+ "Default is 0 - skip ETS enablement.");
+
/*
* SCSI host template entry points
*/
@@ -682,44 +688,6 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha)
return (return_status);
}
-void
-qla2x00_abort_fcport_cmds(fc_port_t *fcport)
-{
- int cnt;
- unsigned long flags;
- srb_t *sp;
- scsi_qla_host_t *vha = fcport->vha;
- struct qla_hw_data *ha = vha->hw;
- struct req_que *req;
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- req = vha->req;
- for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
- sp = req->outstanding_cmds[cnt];
- if (!sp)
- continue;
- if (sp->fcport != fcport)
- continue;
- if (sp->ctx)
- continue;
-
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (ha->isp_ops->abort_command(sp)) {
- DEBUG2(qla_printk(KERN_WARNING, ha,
- "Abort failed -- %lx\n",
- sp->cmd->serial_number));
- } else {
- if (qla2x00_eh_wait_on_command(sp->cmd) !=
- QLA_SUCCESS)
- DEBUG2(qla_printk(KERN_WARNING, ha,
- "Abort failed while waiting -- %lx\n",
- sp->cmd->serial_number));
- }
- spin_lock_irqsave(&ha->hardware_lock, flags);
- }
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
/**************************************************************************
* qla2xxx_eh_abort
*
@@ -1095,6 +1063,20 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
struct fc_port *fcport;
struct qla_hw_data *ha = vha->hw;
+ if (ha->flags.enable_target_reset) {
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ if (fcport->port_type != FCT_TARGET)
+ continue;
+
+ ret = ha->isp_ops->target_reset(fcport, 0, 0);
+ if (ret != QLA_SUCCESS) {
+ DEBUG2_3(printk("%s(%ld): bus_reset failed: "
+ "target_reset=%d d_id=%x.\n", __func__,
+ vha->host_no, ret, fcport->d_id.b24));
+ }
+ }
+ }
+
if (ha->flags.enable_lip_full_login && !IS_QLA81XX(ha)) {
ret = qla2x00_full_login_lip(vha);
if (ret != QLA_SUCCESS) {
@@ -1117,19 +1099,6 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
qla2x00_wait_for_loop_ready(vha);
}
- if (ha->flags.enable_target_reset) {
- list_for_each_entry(fcport, &vha->vp_fcports, list) {
- if (fcport->port_type != FCT_TARGET)
- continue;
-
- ret = ha->isp_ops->target_reset(fcport, 0, 0);
- if (ret != QLA_SUCCESS) {
- DEBUG2_3(printk("%s(%ld): bus_reset failed: "
- "target_reset=%d d_id=%x.\n", __func__,
- vha->host_no, ret, fcport->d_id.b24));
- }
- }
- }
/* Issue marker command only when we are going to start the I/O */
vha->marker_needed = 1;
@@ -1160,8 +1129,19 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
qla2x00_sp_compl(ha, sp);
} else {
ctx = sp->ctx;
- del_timer_sync(&ctx->timer);
- ctx->free(sp);
+ if (ctx->type == SRB_LOGIN_CMD || ctx->type == SRB_LOGOUT_CMD) {
+ del_timer_sync(&ctx->timer);
+ ctx->free(sp);
+ } else {
+ struct srb_bsg* sp_bsg = (struct srb_bsg*)sp->ctx;
+ if (sp_bsg->bsg_job->request->msgcode == FC_BSG_HST_CT)
+ kfree(sp->fcport);
+ sp_bsg->bsg_job->req->errors = 0;
+ sp_bsg->bsg_job->reply->result = res;
+ sp_bsg->bsg_job->job_done(sp_bsg->bsg_job);
+ kfree(sp->ctx);
+ mempool_free(sp, ha->srb_mempool);
+ }
}
}
}
@@ -1188,7 +1168,6 @@ qla2xxx_slave_configure(struct scsi_device *sdev)
scsi_qla_host_t *vha = shost_priv(sdev->host);
struct qla_hw_data *ha = vha->hw;
struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
- fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
struct req_que *req = vha->req;
if (sdev->tagged_supported)
@@ -1197,8 +1176,6 @@ qla2xxx_slave_configure(struct scsi_device *sdev)
scsi_deactivate_tcq(sdev, req->max_q_depth);
rport->dev_loss_tmo = ha->port_down_retry_count;
- if (sdev->type == TYPE_TAPE)
- fcport->flags |= FCF_TAPE_PRESENT;
return 0;
}
@@ -1261,7 +1238,7 @@ qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
qla2x00_adjust_sdev_qdepth_up(sdev, qdepth);
break;
default:
- return EOPNOTSUPP;
+ return -EOPNOTSUPP;
}
return sdev->queue_depth;
@@ -1821,7 +1798,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
/* Set EEH reset type to fundamental if required by hba */
if ( IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha)) {
pdev->needs_freset = 1;
- pci_save_state(pdev);
}
/* Configure PCI I/O space */
@@ -1973,11 +1949,15 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
host->max_channel = MAX_BUSES - 1;
host->max_lun = MAX_LUNS;
host->transportt = qla2xxx_transport_template;
+ sht->vendor_id = (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC);
/* Set up the irqs */
ret = qla2x00_request_irqs(ha, rsp);
if (ret)
goto probe_init_failed;
+
+ pci_save_state(pdev);
+
/* Alloc arrays of request and response ring ptrs */
que_init:
if (!qla2x00_alloc_queues(ha)) {
@@ -2179,6 +2159,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
kfree(ha);
ha = NULL;
+ pci_disable_pcie_error_reporting(pdev);
+
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
@@ -2805,7 +2787,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
fcport->login_retry--;
if (fcport->flags & FCF_FABRIC_DEVICE) {
- if (fcport->flags & FCF_TAPE_PRESENT)
+ if (fcport->flags & FCF_FCP2_DEVICE)
ha->isp_ops->fabric_logout(vha,
fcport->loop_id,
fcport->d_id.b.domain,
@@ -3141,7 +3123,10 @@ qla2x00_timer(scsi_qla_host_t *vha)
if (!IS_QLA2100(ha) && vha->link_down_timeout)
atomic_set(&vha->loop_state, LOOP_DEAD);
- /* Schedule an ISP abort to return any tape commands. */
+ /*
+ * Schedule an ISP abort to return any FCP2-device
+ * commands.
+ */
/* NPIV - scan physical port only */
if (!vha->vp_idx) {
spin_lock_irqsave(&ha->hardware_lock,
@@ -3158,7 +3143,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
if (sp->ctx)
continue;
sfcp = sp->fcport;
- if (!(sfcp->flags & FCF_TAPE_PRESENT))
+ if (!(sfcp->flags & FCF_FCP2_DEVICE))
continue;
set_bit(ISP_ABORT_NEEDED,
@@ -3310,6 +3295,7 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
return PCI_ERS_RESULT_CAN_RECOVER;
case pci_channel_io_frozen:
ha->flags.eeh_busy = 1;
+ qla2x00_free_irqs(vha);
pci_disable_device(pdev);
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
@@ -3363,10 +3349,24 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
scsi_qla_host_t *base_vha = pci_get_drvdata(pdev);
struct qla_hw_data *ha = base_vha->hw;
- int rc;
+ struct rsp_que *rsp;
+ int rc, retries = 10;
DEBUG17(qla_printk(KERN_WARNING, ha, "slot_reset\n"));
+ /* Workaround: qla2xxx driver which access hardware earlier
+ * needs error state to be pci_channel_io_online.
+ * Otherwise mailbox command timesout.
+ */
+ pdev->error_state = pci_channel_io_normal;
+
+ pci_restore_state(pdev);
+
+ /* pci_restore_state() clears the saved_state flag of the device
+ * save restored state which resets saved_state flag
+ */
+ pci_save_state(pdev);
+
if (ha->mem_only)
rc = pci_enable_device_mem(pdev);
else
@@ -3378,27 +3378,23 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
return ret;
}
+ rsp = ha->rsp_q_map[0];
+ if (qla2x00_request_irqs(ha, rsp))
+ return ret;
+
if (ha->isp_ops->pci_config(base_vha))
return ret;
-#ifdef QL_DEBUG_LEVEL_17
- {
- uint8_t b;
- uint32_t i;
+ while (ha->flags.mbox_busy && retries--)
+ msleep(1000);
- printk("slot_reset_1: ");
- for (i = 0; i < 256; i++) {
- pci_read_config_byte(ha->pdev, i, &b);
- printk("%s%02x", (i%16) ? " " : "\n", b);
- }
- printk("\n");
- }
-#endif
set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
if (qla2x00_abort_isp(base_vha) == QLA_SUCCESS)
ret = PCI_ERS_RESULT_RECOVERED;
clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+
DEBUG17(qla_printk(KERN_WARNING, ha,
"slot_reset-return:ret=%x\n", ret));
@@ -3422,8 +3418,6 @@ qla2xxx_pci_resume(struct pci_dev *pdev)
}
ha->flags.eeh_busy = 0;
-
- pci_cleanup_aer_uncorrect_error_status(pdev);
}
static struct pci_error_handlers qla2xxx_err_handler = {
@@ -3536,4 +3530,3 @@ MODULE_FIRMWARE(FW_FILE_ISP2300);
MODULE_FIRMWARE(FW_FILE_ISP2322);
MODULE_FIRMWARE(FW_FILE_ISP24XX);
MODULE_FIRMWARE(FW_FILE_ISP25XX);
-MODULE_FIRMWARE(FW_FILE_ISP81XX);
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 010e69b29afe..371dc895972a 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -2292,11 +2292,14 @@ qla25xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
uint32_t faddr, left, burst;
struct qla_hw_data *ha = vha->hw;
+ if (IS_QLA25XX(ha) || IS_QLA81XX(ha))
+ goto try_fast;
if (offset & 0xfff)
goto slow_read;
if (length < OPTROM_BURST_SIZE)
goto slow_read;
+try_fast:
optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
&optrom_dma, GFP_KERNEL);
if (!optrom) {
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index a65dd95507c6..8d2fc2fa7a6b 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.03.01-k9"
+#define QLA2XXX_VERSION "8.03.02-k1"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 3
-#define QLA_DRIVER_PATCH_VER 1
-#define QLA_DRIVER_BETA_VER 0
+#define QLA_DRIVER_PATCH_VER 2
+#define QLA_DRIVER_BETA_VER 1
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index af8c3233e8ae..92329a461c68 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -844,10 +844,10 @@ static int qla4xxx_config_nvram(struct scsi_qla_host *ha)
DEBUG2(printk("scsi%ld: %s: Get EEProm parameters \n", ha->host_no,
__func__));
if (ql4xxx_lock_flash(ha) != QLA_SUCCESS)
- return (QLA_ERROR);
+ return QLA_ERROR;
if (ql4xxx_lock_nvram(ha) != QLA_SUCCESS) {
ql4xxx_unlock_flash(ha);
- return (QLA_ERROR);
+ return QLA_ERROR;
}
/* Get EEPRom Parameters from NVRAM and validate */
@@ -858,20 +858,18 @@ static int qla4xxx_config_nvram(struct scsi_qla_host *ha)
rd_nvram_word(ha, eeprom_ext_hw_conf_offset(ha));
spin_unlock_irqrestore(&ha->hardware_lock, flags);
} else {
- /*
- * QLogic adapters should always have a valid NVRAM.
- * If not valid, do not load.
- */
dev_warn(&ha->pdev->dev,
"scsi%ld: %s: EEProm checksum invalid. "
"Please update your EEPROM\n", ha->host_no,
__func__);
- /* set defaults */
+ /* Attempt to set defaults */
if (is_qla4010(ha))
extHwConfig.Asuint32_t = 0x1912;
else if (is_qla4022(ha) | is_qla4032(ha))
extHwConfig.Asuint32_t = 0x0023;
+ else
+ return QLA_ERROR;
}
DEBUG(printk("scsi%ld: %s: Setting extHwConfig to 0xFFFF%04x\n",
ha->host_no, __func__, extHwConfig.Asuint32_t));
@@ -884,7 +882,7 @@ static int qla4xxx_config_nvram(struct scsi_qla_host *ha)
ql4xxx_unlock_nvram(ha);
ql4xxx_unlock_flash(ha);
- return (QLA_SUCCESS);
+ return QLA_SUCCESS;
}
static void qla4x00_pci_config(struct scsi_qla_host *ha)
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index fa34b92850a6..1b8217076b0e 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -738,7 +738,7 @@ static int __devinit qpti_register_irq(struct qlogicpti *qpti)
* sanely maintain.
*/
if (request_irq(qpti->irq, qpti_intr,
- IRQF_SHARED, "Qlogic/PTI", qpti))
+ IRQF_SHARED, "QlogicPTI", qpti))
goto fail;
printk("qlogicpti%d: IRQ %d ", qpti->qpti_id, qpti->irq);
diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c
index 8e5c169b03fb..bd88349b8526 100644
--- a/drivers/scsi/raid_class.c
+++ b/drivers/scsi/raid_class.c
@@ -149,6 +149,7 @@ static struct {
{ RAID_LEVEL_0, "raid0" },
{ RAID_LEVEL_1, "raid1" },
{ RAID_LEVEL_10, "raid10" },
+ { RAID_LEVEL_1E, "raid1e" },
{ RAID_LEVEL_3, "raid3" },
{ RAID_LEVEL_4, "raid4" },
{ RAID_LEVEL_5, "raid5" },
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index a60da5555577..1c08f6164658 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1018,6 +1018,8 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
* scsi_get_vpd_page - Get Vital Product Data from a SCSI device
* @sdev: The device to ask
* @page: Which Vital Product Data to return
+ * @buf: where to store the VPD
+ * @buf_len: number of bytes in the VPD buffer area
*
* SCSI devices may optionally supply Vital Product Data. Each 'page'
* of VPD is defined in the appropriate SCSI document (eg SPC, SBC).
@@ -1026,55 +1028,39 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
* responsible for calling kfree() on this pointer when it is no longer
* needed. If we cannot retrieve the VPD page this routine returns %NULL.
*/
-unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page)
+int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
+ int buf_len)
{
int i, result;
- unsigned int len;
- const unsigned int init_vpd_len = 255;
- unsigned char *buf = kmalloc(init_vpd_len, GFP_KERNEL);
-
- if (!buf)
- return NULL;
/* Ask for all the pages supported by this device */
- result = scsi_vpd_inquiry(sdev, buf, 0, init_vpd_len);
+ result = scsi_vpd_inquiry(sdev, buf, 0, buf_len);
if (result)
goto fail;
/* If the user actually wanted this page, we can skip the rest */
if (page == 0)
- return buf;
+ return -EINVAL;
- for (i = 0; i < buf[3]; i++)
+ for (i = 0; i < min((int)buf[3], buf_len - 4); i++)
if (buf[i + 4] == page)
goto found;
+
+ if (i < buf[3] && i > buf_len)
+ /* ran off the end of the buffer, give us benefit of doubt */
+ goto found;
/* The device claims it doesn't support the requested page */
goto fail;
found:
- result = scsi_vpd_inquiry(sdev, buf, page, 255);
+ result = scsi_vpd_inquiry(sdev, buf, page, buf_len);
if (result)
goto fail;
- /*
- * Some pages are longer than 255 bytes. The actual length of
- * the page is returned in the header.
- */
- len = ((buf[2] << 8) | buf[3]) + 4;
- if (len <= init_vpd_len)
- return buf;
-
- kfree(buf);
- buf = kmalloc(len, GFP_KERNEL);
- result = scsi_vpd_inquiry(sdev, buf, page, len);
- if (result)
- goto fail;
-
- return buf;
+ return 0;
fail:
- kfree(buf);
- return NULL;
+ return -EINVAL;
}
EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index d8927681ec88..1646fe7cbd4b 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -749,9 +749,9 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
*/
req->next_rq->resid_len = scsi_in(cmd)->resid;
+ scsi_release_buffers(cmd);
blk_end_request_all(req, 0);
- scsi_release_buffers(cmd);
scsi_next_command(cmd);
return;
}
@@ -773,8 +773,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
* we already took a copy of the original into rq->errors which
* is what gets returned to the user
*/
- if (sense_valid && sshdr.sense_key == RECOVERED_ERROR) {
- if (!(req->cmd_flags & REQ_QUIET))
+ if (sense_valid && (sshdr.sense_key == RECOVERED_ERROR)) {
+ /* if ATA PASS-THROUGH INFORMATION AVAILABLE skip
+ * print since caller wants ATA registers. Only occurs on
+ * SCSI ATA PASS_THROUGH commands when CK_COND=1
+ */
+ if ((sshdr.asc == 0x0) && (sshdr.ascq == 0x1d))
+ ;
+ else if (!(req->cmd_flags & REQ_QUIET))
scsi_print_sense("", cmd);
result = 0;
/* BLOCK_PC may have set error */
@@ -1624,10 +1630,10 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
/*
* this limit is imposed by hardware restrictions
*/
- blk_queue_max_hw_segments(q, shost->sg_tablesize);
- blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS);
+ blk_queue_max_segments(q, min_t(unsigned short, shost->sg_tablesize,
+ SCSI_MAX_SG_CHAIN_SEGMENTS));
- blk_queue_max_sectors(q, shost->max_sectors);
+ blk_queue_max_hw_sectors(q, shost->max_sectors);
blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
blk_queue_segment_boundary(q, shost->dma_boundary);
dma_set_seg_boundary(dev, shost->dma_boundary);
diff --git a/drivers/scsi/scsi_sas_internal.h b/drivers/scsi/scsi_sas_internal.h
index 998cb5be6833..6266a5d73d0f 100644
--- a/drivers/scsi/scsi_sas_internal.h
+++ b/drivers/scsi/scsi_sas_internal.h
@@ -5,7 +5,7 @@
#define SAS_PHY_ATTRS 17
#define SAS_PORT_ATTRS 1
#define SAS_RPORT_ATTRS 7
-#define SAS_END_DEV_ATTRS 3
+#define SAS_END_DEV_ATTRS 5
#define SAS_EXPANDER_ATTRS 7
struct sas_internal {
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 012f73a96880..4bc8b77a2ef3 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -879,7 +879,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
* broken RA4x00 Compaq Disk Array
*/
if (*bflags & BLIST_MAX_512)
- blk_queue_max_sectors(sdev->request_queue, 512);
+ blk_queue_max_hw_sectors(sdev->request_queue, 512);
/*
* Some devices may not want to have a start command automatically
@@ -1339,8 +1339,10 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
sdev = scsi_alloc_sdev(starget, 0, NULL);
if (!sdev)
return 0;
- if (scsi_device_get(sdev))
+ if (scsi_device_get(sdev)) {
+ __scsi_remove_device(sdev);
return 0;
+ }
}
sprintf(devname, "host %d channel %d id %d",
@@ -1907,10 +1909,9 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
goto out;
sdev = scsi_alloc_sdev(starget, 0, NULL);
- if (sdev) {
- sdev->sdev_gendev.parent = get_device(&starget->dev);
+ if (sdev)
sdev->borken = 0;
- } else
+ else
scsi_target_reap(starget);
put_device(&starget->dev);
out:
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 5a065055e68a..19ec9e2d3f39 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -847,6 +847,8 @@ static int scsi_target_add(struct scsi_target *starget)
if (starget->state != STARGET_CREATED)
return 0;
+ device_enable_async_suspend(&starget->dev);
+
error = device_add(&starget->dev);
if (error) {
dev_err(&starget->dev, "target device_add failed, error %d\n", error);
@@ -878,7 +880,8 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
struct request_queue *rq = sdev->request_queue;
struct scsi_target *starget = sdev->sdev_target;
- if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0)
+ error = scsi_device_set_state(sdev, SDEV_RUNNING);
+ if (error)
return error;
error = scsi_target_add(starget);
@@ -886,16 +889,18 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
return error;
transport_configure_device(&starget->dev);
+ device_enable_async_suspend(&sdev->sdev_gendev);
error = device_add(&sdev->sdev_gendev);
if (error) {
printk(KERN_INFO "error 1\n");
- goto out_remove;
+ return error;
}
+ device_enable_async_suspend(&sdev->sdev_dev);
error = device_add(&sdev->sdev_dev);
if (error) {
printk(KERN_INFO "error 2\n");
device_del(&sdev->sdev_gendev);
- goto out_remove;
+ return error;
}
transport_add_device(&sdev->sdev_gendev);
sdev->is_visible = 1;
@@ -910,14 +915,14 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
else
error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth);
if (error)
- goto out_remove;
+ return error;
if (sdev->host->hostt->change_queue_type)
error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw);
else
error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type);
if (error)
- goto out_remove;
+ return error;
error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL);
@@ -933,16 +938,11 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
error = device_create_file(&sdev->sdev_gendev,
sdev->host->hostt->sdev_attrs[i]);
if (error)
- goto out_remove;
+ return error;
}
}
- return 0;
-
- out_remove:
- __scsi_remove_device(sdev);
return error;
-
}
void __scsi_remove_device(struct scsi_device *sdev)
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index ddfcecd5099f..79660ee3e211 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -475,7 +475,8 @@ MODULE_PARM_DESC(dev_loss_tmo,
"Maximum number of seconds that the FC transport should"
" insulate the loss of a remote port. Once this value is"
" exceeded, the scsi target is removed. Value should be"
- " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT.");
+ " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT if"
+ " fast_io_fail_tmo is not set.");
/*
* Netlink Infrastructure
@@ -842,9 +843,17 @@ store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr,
(rport->port_state == FC_PORTSTATE_NOTPRESENT))
return -EBUSY;
val = simple_strtoul(buf, &cp, 0);
- if ((*cp && (*cp != '\n')) ||
- (val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT))
+ if ((*cp && (*cp != '\n')) || (val < 0))
return -EINVAL;
+
+ /*
+ * If fast_io_fail is off we have to cap
+ * dev_loss_tmo at SCSI_DEVICE_BLOCK_MAX_TIMEOUT
+ */
+ if (rport->fast_io_fail_tmo == -1 &&
+ val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
+ return -EINVAL;
+
i->f->set_rport_dev_loss_tmo(rport, val);
return count;
}
@@ -925,9 +934,16 @@ store_fc_rport_fast_io_fail_tmo(struct device *dev,
rport->fast_io_fail_tmo = -1;
else {
val = simple_strtoul(buf, &cp, 0);
- if ((*cp && (*cp != '\n')) ||
- (val < 0) || (val >= rport->dev_loss_tmo))
+ if ((*cp && (*cp != '\n')) || (val < 0))
return -EINVAL;
+ /*
+ * Cap fast_io_fail by dev_loss_tmo or
+ * SCSI_DEVICE_BLOCK_MAX_TIMEOUT.
+ */
+ if ((val >= rport->dev_loss_tmo) ||
+ (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT))
+ return -EINVAL;
+
rport->fast_io_fail_tmo = val;
}
return count;
@@ -3527,7 +3543,10 @@ fc_bsg_job_timeout(struct request *req)
if (!done && i->f->bsg_timeout) {
/* call LLDD to abort the i/o as it has timed out */
err = i->f->bsg_timeout(job);
- if (err)
+ if (err == -EAGAIN) {
+ job->ref_cnt--;
+ return BLK_EH_RESET_TIMER;
+ } else if (err)
printk(KERN_ERR "ERROR: FC BSG request timeout - LLD "
"abort failed with status %d\n", err);
}
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index f27e52d963d3..927e99cb7225 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -155,6 +155,17 @@ static struct {
sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
sas_bitfield_name_set(linkspeed, sas_linkspeed_names)
+static struct sas_end_device *sas_sdev_to_rdev(struct scsi_device *sdev)
+{
+ struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target);
+ struct sas_end_device *rdev;
+
+ BUG_ON(rphy->identify.device_type != SAS_END_DEVICE);
+
+ rdev = rphy_to_end_device(rphy);
+ return rdev;
+}
+
static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
struct sas_rphy *rphy)
{
@@ -358,6 +369,85 @@ void sas_remove_host(struct Scsi_Host *shost)
}
EXPORT_SYMBOL(sas_remove_host);
+/**
+ * sas_tlr_supported - checking TLR bit in vpd 0x90
+ * @sdev: scsi device struct
+ *
+ * Check Transport Layer Retries are supported or not.
+ * If vpd page 0x90 is present, TRL is supported.
+ *
+ */
+unsigned int
+sas_tlr_supported(struct scsi_device *sdev)
+{
+ const int vpd_len = 32;
+ struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
+ char *buffer = kzalloc(vpd_len, GFP_KERNEL);
+ int ret = 0;
+
+ if (scsi_get_vpd_page(sdev, 0x90, buffer, vpd_len))
+ goto out;
+
+ /*
+ * Magic numbers: the VPD Protocol page (0x90)
+ * has a 4 byte header and then one entry per device port
+ * the TLR bit is at offset 8 on each port entry
+ * if we take the first port, that's at total offset 12
+ */
+ ret = buffer[12] & 0x01;
+
+ out:
+ kfree(buffer);
+ rdev->tlr_supported = ret;
+ return ret;
+
+}
+EXPORT_SYMBOL_GPL(sas_tlr_supported);
+
+/**
+ * sas_disable_tlr - setting TLR flags
+ * @sdev: scsi device struct
+ *
+ * Seting tlr_enabled flag to 0.
+ *
+ */
+void
+sas_disable_tlr(struct scsi_device *sdev)
+{
+ struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
+
+ rdev->tlr_enabled = 0;
+}
+EXPORT_SYMBOL_GPL(sas_disable_tlr);
+
+/**
+ * sas_enable_tlr - setting TLR flags
+ * @sdev: scsi device struct
+ *
+ * Seting tlr_enabled flag 1.
+ *
+ */
+void sas_enable_tlr(struct scsi_device *sdev)
+{
+ unsigned int tlr_supported = 0;
+ tlr_supported = sas_tlr_supported(sdev);
+
+ if (tlr_supported) {
+ struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
+
+ rdev->tlr_enabled = 1;
+ }
+
+ return;
+}
+EXPORT_SYMBOL_GPL(sas_enable_tlr);
+
+unsigned int sas_is_tlr_enabled(struct scsi_device *sdev)
+{
+ struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
+ return rdev->tlr_enabled;
+}
+EXPORT_SYMBOL_GPL(sas_is_tlr_enabled);
/*
* SAS Phy attributes
@@ -1146,15 +1236,10 @@ sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
int sas_read_port_mode_page(struct scsi_device *sdev)
{
char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata;
- struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target);
- struct sas_end_device *rdev;
+ struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
struct scsi_mode_data mode_data;
int res, error;
- BUG_ON(rphy->identify.device_type != SAS_END_DEVICE);
-
- rdev = rphy_to_end_device(rphy);
-
if (!buffer)
return -ENOMEM;
@@ -1207,6 +1292,10 @@ sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout,
"%d\n", int);
sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout,
"%d\n", int);
+sas_end_dev_simple_attr(tlr_supported, tlr_supported,
+ "%d\n", int);
+sas_end_dev_simple_attr(tlr_enabled, tlr_enabled,
+ "%d\n", int);
static DECLARE_TRANSPORT_CLASS(sas_expander_class,
"sas_expander", NULL, NULL, NULL);
@@ -1733,6 +1822,8 @@ sas_attach_transport(struct sas_function_template *ft)
SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning);
SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout);
SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout);
+ SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_supported);
+ SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_enabled);
i->end_dev_attrs[count] = NULL;
count = 0;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 255da53e5a01..83881dfb33c0 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1196,19 +1196,10 @@ static int sd_done(struct scsi_cmnd *SCpnt)
SCpnt->result = 0;
memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
break;
- case ABORTED_COMMAND:
- if (sshdr.asc == 0x10) { /* DIF: Disk detected corruption */
- scsi_print_result(SCpnt);
- scsi_print_sense("sd", SCpnt);
+ case ABORTED_COMMAND: /* DIF: Target detected corruption */
+ case ILLEGAL_REQUEST: /* DIX: Host detected corruption */
+ if (sshdr.asc == 0x10)
good_bytes = sd_completed_bytes(SCpnt);
- }
- break;
- case ILLEGAL_REQUEST:
- if (sshdr.asc == 0x10) { /* DIX: HBA detected corruption */
- scsi_print_result(SCpnt);
- scsi_print_sense("sd", SCpnt);
- good_bytes = sd_completed_bytes(SCpnt);
- }
break;
default:
break;
@@ -1218,8 +1209,19 @@ static int sd_done(struct scsi_cmnd *SCpnt)
sd_dif_complete(SCpnt, good_bytes);
if (scsi_host_dif_capable(sdkp->device->host, sdkp->protection_type)
- == SD_DIF_TYPE2_PROTECTION && SCpnt->cmnd != SCpnt->request->cmd)
+ == SD_DIF_TYPE2_PROTECTION && SCpnt->cmnd != SCpnt->request->cmd) {
+
+ /* We have to print a failed command here as the
+ * extended CDB gets freed before scsi_io_completion()
+ * is called.
+ */
+ if (result)
+ scsi_print_command(SCpnt);
+
mempool_free(SCpnt->cmnd, sd_cdb_pool);
+ SCpnt->cmnd = NULL;
+ SCpnt->cmd_len = 0;
+ }
return good_bytes;
}
@@ -1946,13 +1948,13 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
{
struct request_queue *q = sdkp->disk->queue;
unsigned int sector_sz = sdkp->device->sector_size;
- char *buffer;
+ const int vpd_len = 32;
+ unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL);
- /* Block Limits VPD */
- buffer = scsi_get_vpd_page(sdkp->device, 0xb0);
-
- if (buffer == NULL)
- return;
+ if (!buffer ||
+ /* Block Limits VPD */
+ scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len))
+ goto out;
blk_queue_io_min(sdkp->disk->queue,
get_unaligned_be16(&buffer[6]) * sector_sz);
@@ -1984,6 +1986,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
get_unaligned_be32(&buffer[32]) & ~(1 << 31);
}
+ out:
kfree(buffer);
}
@@ -1993,20 +1996,23 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
*/
static void sd_read_block_characteristics(struct scsi_disk *sdkp)
{
- char *buffer;
+ unsigned char *buffer;
u16 rot;
+ const int vpd_len = 32;
- /* Block Device Characteristics VPD */
- buffer = scsi_get_vpd_page(sdkp->device, 0xb1);
+ buffer = kmalloc(vpd_len, GFP_KERNEL);
- if (buffer == NULL)
- return;
+ if (!buffer ||
+ /* Block Device Characteristics VPD */
+ scsi_get_vpd_page(sdkp->device, 0xb1, buffer, vpd_len))
+ goto out;
rot = get_unaligned_be16(&buffer[4]);
if (rot == 1)
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, sdkp->disk->queue);
+ out:
kfree(buffer);
}
@@ -2105,7 +2111,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
* which is followed by sdaaa.
*
* This is basically 26 base counting with one extra 'nil' entry
- * at the beggining from the second digit on and can be
+ * at the beginning from the second digit on and can be
* determined using similar method as 26 base conversion with the
* index shifted -1 after each digit is computed.
*
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 55b034b72708..0d9d6f7567f5 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -448,13 +448,17 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
.addr = 0,
};
- buf = scsi_get_vpd_page(sdev, 0x83);
- if (!buf)
- return;
+ buf = kmalloc(INIT_ALLOC_SIZE, GFP_KERNEL);
+ if (!buf || scsi_get_vpd_page(sdev, 0x83, buf, INIT_ALLOC_SIZE))
+ goto free;
ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
vpd_len = ((buf[2] << 8) | buf[3]) + 4;
+ kfree(buf);
+ buf = kmalloc(vpd_len, GFP_KERNEL);
+ if (!buf ||scsi_get_vpd_page(sdev, 0x83, buf, vpd_len))
+ goto free;
desc = buf + 4;
while (desc < buf + vpd_len) {
@@ -591,8 +595,6 @@ static int ses_intf_add(struct device *cdev,
ses_dev->page10_len = len;
buf = NULL;
}
- kfree(hdr_buf);
-
scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL);
if (!scomp)
goto err_free;
@@ -604,6 +606,8 @@ static int ses_intf_add(struct device *cdev,
goto err_free;
}
+ kfree(hdr_buf);
+
edev->scratch = ses_dev;
for (i = 0; i < components; i++)
edev->component[i].scratch = scomp + i;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 040f751809ea..c996d98636f3 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -287,8 +287,7 @@ sg_open(struct inode *inode, struct file *filp)
if (list_empty(&sdp->sfds)) { /* no existing opens on this device */
sdp->sgdebug = 0;
q = sdp->device->request_queue;
- sdp->sg_tablesize = min(queue_max_hw_segments(q),
- queue_max_phys_segments(q));
+ sdp->sg_tablesize = queue_max_segments(q);
}
if ((sfp = sg_add_sfp(sdp, dev)))
filp->private_data = sfp;
@@ -1376,8 +1375,7 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
sdp->device = scsidp;
INIT_LIST_HEAD(&sdp->sfds);
init_waitqueue_head(&sdp->o_excl_wait);
- sdp->sg_tablesize = min(queue_max_hw_segments(q),
- queue_max_phys_segments(q));
+ sdp->sg_tablesize = queue_max_segments(q);
sdp->index = k;
kref_init(&sdp->d_ref);
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index 0807b260268b..fef0e3c75b16 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -226,7 +226,7 @@ static struct scsi_host_template sgiwd93_template = {
.use_clustering = DISABLE_CLUSTERING,
};
-static int __init sgiwd93_probe(struct platform_device *pdev)
+static int __devinit sgiwd93_probe(struct platform_device *pdev)
{
struct sgiwd93_platform_data *pd = pdev->dev.platform_data;
unsigned char *wdregs = pd->wdregs;
diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c
index 37b3359e863e..56cf0bb4ed1f 100644
--- a/drivers/scsi/sni_53c710.c
+++ b/drivers/scsi/sni_53c710.c
@@ -64,7 +64,7 @@ static struct scsi_host_template snirm710_template = {
.module = THIS_MODULE,
};
-static int __init snirm710_probe(struct platform_device *dev)
+static int __devinit snirm710_probe(struct platform_device *dev)
{
unsigned long base;
struct NCR_700_Host_Parameters *hostdata;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index d04ea9a6f673..f67d1a159aad 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -3983,8 +3983,7 @@ static int st_probe(struct device *dev)
return -ENODEV;
}
- i = min(queue_max_hw_segments(SDp->request_queue),
- queue_max_phys_segments(SDp->request_queue));
+ i = queue_max_segments(SDp->request_queue);
if (st_max_sg_segs < i)
i = st_max_sg_segs;
buffer = new_tape_buffer((SDp->host)->unchecked_isa_dma, i);
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 54023d41fd15..26e8e0e6b8dd 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -1070,7 +1070,7 @@ static int option_setup(char *str) {
char *cur = str;
int i = 1;
- while (cur && isdigit(*cur) && i <= MAX_INT_PARAM) {
+ while (cur && isdigit(*cur) && i < MAX_INT_PARAM) {
ints[i++] = simple_strtoul(cur, NULL, 0);
if ((cur = strchr(cur, ',')) != NULL) cur++;
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index d2604c813a20..e4ac5829b637 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -1069,7 +1069,8 @@ static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter)
free_pages((unsigned long)ctx->sgl, get_order(SGL_SIZE));
}
-static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter, int *irq)
+static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter,
+ unsigned int *irq)
{
struct msix_entry entry = { 0, PVSCSI_VECTOR_COMPLETION };
int ret;
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index d935b2d04f93..ae0251ef6f4e 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -153,8 +153,6 @@ static int baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
9600, 19200, 38400, 57600, 115200, 0 };
-#define BAUD_TABLE_SIZE (sizeof(baud_table)/sizeof(baud_table[0]))
-
/* Sets or clears DTR/RTS on the requested line */
static inline void m68k_rtsdtr(struct m68k_serial *ss, int set)
{
@@ -1406,10 +1404,10 @@ static void m68328_set_baud(void)
USTCNT = ustcnt & ~USTCNT_TXEN;
again:
- for (i = 0; i < sizeof(baud_table) / sizeof(baud_table[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(baud_table); i++)
if (baud_table[i] == m68328_console_baud)
break;
- if (i >= sizeof(baud_table) / sizeof(baud_table[0])) {
+ if (i >= ARRAY_SIZE(baud_table)) {
m68328_console_baud = 9600;
goto again;
}
@@ -1435,7 +1433,7 @@ int m68328_console_setup(struct console *cp, char *arg)
if (arg)
n = simple_strtoul(arg,NULL,0);
- for (i = 0; i < BAUD_TABLE_SIZE; i++)
+ for (i = 0; i < ARRAY_SIZE(baud_table); i++)
if (baud_table[i] == n)
break;
if (i < BAUD_TABLE_SIZE) {
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index c3e37c8e7e26..c3db16b7afa1 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -83,6 +83,9 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */
#define PASS_LIMIT 256
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+
/*
* We default to IRQ0 for the "no irq" hack. Some
* machine types want others as well - they're free
@@ -1214,12 +1217,6 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
}
#endif
-#ifdef CONFIG_SERIAL_8250_AU1X00
- /* if access method is AU, it is a 16550 with a quirk */
- if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU)
- up->bugs |= UART_BUG_NOMSR;
-#endif
-
serial_outp(up, UART_LCR, save_lcr);
if (up->capabilities != uart_config[up->port.type].flags) {
@@ -1792,7 +1789,7 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
spin_unlock_irqrestore(&up->port.lock, flags);
- return lsr & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+ return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
}
static unsigned int serial8250_get_mctrl(struct uart_port *port)
@@ -1850,8 +1847,6 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&up->port.lock, flags);
}
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
/*
* Wait for transmitter & holding register to empty
*/
@@ -2413,6 +2408,21 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
}
static void
+serial8250_set_ldisc(struct uart_port *port)
+{
+ int line = port->line;
+
+ if (line >= port->state->port.tty->driver->num)
+ return;
+
+ if (port->state->port.tty->ldisc->ops->num == N_PPS) {
+ port->flags |= UPF_HARDPPS_CD;
+ serial8250_enable_ms(port);
+ } else
+ port->flags &= ~UPF_HARDPPS_CD;
+}
+
+static void
serial8250_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
@@ -2427,7 +2437,7 @@ serial8250_pm(struct uart_port *port, unsigned int state,
static unsigned int serial8250_port_size(struct uart_8250_port *pt)
{
if (pt->port.iotype == UPIO_AU)
- return 0x100000;
+ return 0x1000;
#ifdef CONFIG_ARCH_OMAP
if (is_omap_port(pt))
return 0x16 << pt->port.regshift;
@@ -2584,6 +2594,13 @@ static void serial8250_config_port(struct uart_port *port, int flags)
if (flags & UART_CONFIG_TYPE)
autoconfig(up, probeflags);
+
+#ifdef CONFIG_SERIAL_8250_AU1X00
+ /* if access method is AU, it is a 16550 with a quirk */
+ if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU)
+ up->bugs |= UART_BUG_NOMSR;
+#endif
+
if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
autoconfig_irq(up);
@@ -2626,6 +2643,7 @@ static struct uart_ops serial8250_pops = {
.startup = serial8250_startup,
.shutdown = serial8250_shutdown,
.set_termios = serial8250_set_termios,
+ .set_ldisc = serial8250_set_ldisc,
.pm = serial8250_pm,
.type = serial8250_type,
.release_port = serial8250_release_port,
@@ -2688,6 +2706,15 @@ static void __init serial8250_isa_init_ports(void)
}
}
+static void
+serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type)
+{
+ up->port.type = type;
+ up->port.fifosize = uart_config[type].fifo_size;
+ up->capabilities = uart_config[type].flags;
+ up->tx_loadsz = uart_config[type].tx_loadsz;
+}
+
static void __init
serial8250_register_ports(struct uart_driver *drv, struct device *dev)
{
@@ -2704,6 +2731,10 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
struct uart_8250_port *up = &serial8250_ports[i];
up->port.dev = dev;
+
+ if (up->port.flags & UPF_FIXED_TYPE)
+ serial8250_init_fixed_type_port(up, up->port.type);
+
uart_add_one_port(drv, &up->port);
}
}
@@ -3116,12 +3147,8 @@ int serial8250_register_port(struct uart_port *port)
if (port->dev)
uart->port.dev = port->dev;
- if (port->flags & UPF_FIXED_TYPE) {
- uart->port.type = port->type;
- uart->port.fifosize = uart_config[port->type].fifo_size;
- uart->capabilities = uart_config[port->type].flags;
- uart->tx_loadsz = uart_config[port->type].tx_loadsz;
- }
+ if (port->flags & UPF_FIXED_TYPE)
+ serial8250_init_fixed_type_port(uart, port->type);
set_io_from_upio(&uart->port);
/* Possibly override default I/O functions. */
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index b28af13c45a1..01c012da4e26 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -760,7 +760,8 @@ static int pci_netmos_init(struct pci_dev *dev)
/* subdevice 0x00PS means <P> parallel, <S> serial */
unsigned int num_serial = dev->subsystem_device & 0xf;
- if (dev->device == PCI_DEVICE_ID_NETMOS_9901)
+ if ((dev->device == PCI_DEVICE_ID_NETMOS_9901) ||
+ (dev->device == PCI_DEVICE_ID_NETMOS_9865))
return 0;
if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
dev->subsystem_device == 0x0299)
@@ -1479,6 +1480,7 @@ enum pci_board_num_t {
pbn_b0_bt_1_115200,
pbn_b0_bt_2_115200,
+ pbn_b0_bt_4_115200,
pbn_b0_bt_8_115200,
pbn_b0_bt_1_460800,
@@ -1703,6 +1705,12 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.base_baud = 115200,
.uart_offset = 8,
},
+ [pbn_b0_bt_4_115200] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
[pbn_b0_bt_8_115200] = {
.flags = FL_BASE0|FL_BASE_BARS,
.num_ports = 8,
@@ -3191,6 +3199,15 @@ static struct pci_device_id serial_pci_tbl[] = {
0x1208, 0x0004, 0, 0,
pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
+ 0x1204, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
+ 0x1208, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF3,
+ 0x1208, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
/*
* Dell Remote Access Card 4 - Tim_T_Murphy@Dell.com
*/
@@ -3649,6 +3666,18 @@ static struct pci_device_id serial_pci_tbl[] = {
0, 0, pbn_b0_1_115200 },
/*
+ * Best Connectivity PCI Multi I/O cards
+ */
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+ 0xA000, 0x3004,
+ 0, 0, pbn_b0_bt_4_115200 },
+
+ /*
* These entries match devices with class COMMUNICATION_SERIAL,
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
*/
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index 36ede02ceacf..24485cc62ff8 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -328,15 +328,7 @@ static const struct pnp_device_id pnp_dev_table[] = {
/* U.S. Robotics 56K Voice INT PnP*/
{ "USR9190", 0 },
/* Wacom tablets */
- { "WACF004", 0 },
- { "WACF005", 0 },
- { "WACF006", 0 },
- { "WACF007", 0 },
- { "WACF008", 0 },
- { "WACF009", 0 },
- { "WACF00A", 0 },
- { "WACF00B", 0 },
- { "WACF00C", 0 },
+ { "WACFXXX", 0 },
/* Compaq touchscreen */
{ "FPI2002", 0 },
/* Fujitsu Stylistic touchscreens */
@@ -354,6 +346,8 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "FUJ02E5", 0 },
/* Fujitsu P-series tablet PC device */
{ "FUJ02E6", 0 },
+ /* Fujitsu Wacom 2FGT Tablet PC device */
+ { "FUJ02E7", 0 },
/*
* LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in
* disguise)
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 9ff47db0b2ce..f55c49475a8c 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -447,7 +447,7 @@ config SERIAL_CLPS711X_CONSOLE
config SERIAL_SAMSUNG
tristate "Samsung SoC serial support"
- depends on ARM && PLAT_S3C
+ depends on ARM && PLAT_SAMSUNG
select SERIAL_CORE
help
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
@@ -455,11 +455,18 @@ config SERIAL_SAMSUNG
provide all of these ports, depending on how the serial port
pins are configured.
+config SERIAL_SAMSUNG_UARTS_4
+ bool
+ depends on ARM && PLAT_SAMSUNG
+ default y if CPU_S3C2443
+ help
+ Internal node for the common case of 4 Samsung compatible UARTs
+
config SERIAL_SAMSUNG_UARTS
int
- depends on ARM && PLAT_S3C
+ depends on ARM && PLAT_SAMSUNG
default 2 if ARCH_S3C2400
- default 4 if ARCH_S5PC1XX || ARCH_S3C64XX || CPU_S3C2443
+ default 4 if SERIAL_SAMSUNG_UARTS_4
default 3
help
Select the number of available UART ports for the Samsung S3C
@@ -526,20 +533,30 @@ config SERIAL_S3C24A0
Serial port support for the Samsung S3C24A0 SoC
config SERIAL_S3C6400
- tristate "Samsung S3C6400/S3C6410 Serial port support"
- depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410)
+ tristate "Samsung S3C6400/S3C6410/S5P6440 Seria port support"
+ depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440)
+ select SERIAL_SAMSUNG_UARTS_4
default y
help
- Serial port support for the Samsung S3C6400 and S3C6410
+ Serial port support for the Samsung S3C6400, S3C6410 and S5P6440
SoCs
config SERIAL_S5PC100
tristate "Samsung S5PC100 Serial port support"
depends on SERIAL_SAMSUNG && CPU_S5PC100
+ select SERIAL_SAMSUNG_UARTS_4
default y
help
Serial port support for the Samsung S5PC100 SoCs
+config SERIAL_S5PV210
+ tristate "Samsung S5PV210 Serial port support"
+ depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442)
+ select SERIAL_SAMSUNG_UARTS_4 if CPU_S5PV210
+ default y
+ help
+ Serial port support for Samsung's S5P Family of SoC's
+
config SERIAL_MAX3100
tristate "MAX3100 support"
depends on SPI
@@ -996,7 +1013,7 @@ config SERIAL_IP22_ZILOG_CONSOLE
config SERIAL_SH_SCI
tristate "SuperH SCI(F) serial port support"
- depends on HAVE_CLK && (SUPERH || H8300)
+ depends on HAVE_CLK && (SUPERH || H8300 || ARCH_SHMOBILE)
select SERIAL_CORE
config SERIAL_SH_SCI_NR_UARTS
@@ -1009,6 +1026,10 @@ config SERIAL_SH_SCI_CONSOLE
depends on SERIAL_SH_SCI=y
select SERIAL_CORE_CONSOLE
+config SERIAL_SH_SCI_DMA
+ bool "DMA support"
+ depends on SERIAL_SH_SCI && SH_DMAE && EXPERIMENTAL
+
config SERIAL_PNX8XXX
bool "Enable PNX8XXX SoCs' UART Support"
depends on MIPS && (SOC_PNX8550 || SOC_PNX833X)
@@ -1086,12 +1107,12 @@ config SERIAL_68360
default y
config SERIAL_PMACZILOG
- tristate "PowerMac z85c30 ESCC support"
- depends on PPC_OF && PPC_PMAC
+ tristate "Mac or PowerMac z85c30 ESCC support"
+ depends on (M68K && MAC) || (PPC_OF && PPC_PMAC)
select SERIAL_CORE
help
This driver supports the Zilog z85C30 serial ports found on
- PowerMac machines.
+ (Power)Mac machines.
Say Y or M if you want to be able to these serial ports.
config SERIAL_PMACZILOG_TTYS
@@ -1116,16 +1137,16 @@ config SERIAL_PMACZILOG_TTYS
unable to use the 8250 module for PCMCIA or other 16C550-style
UARTs.
- Say N unless you need the z85c30 ports on your powermac
+ Say N unless you need the z85c30 ports on your (Power)Mac
to appear as /dev/ttySn.
config SERIAL_PMACZILOG_CONSOLE
- bool "Console on PowerMac z85c30 serial port"
+ bool "Console on Mac or PowerMac z85c30 serial port"
depends on SERIAL_PMACZILOG=y
select SERIAL_CORE_CONSOLE
help
If you would like to be able to use the z85c30 serial port
- on your PowerMac as the console, you can do so by answering
+ on your (Power)Mac as the console, you can do so by answering
Y to this option.
config SERIAL_LH7A40X
@@ -1418,42 +1439,37 @@ config SERIAL_BFIN_SPORT
To compile this driver as a module, choose M here: the
module will be called bfin_sport_uart.
-choice
- prompt "Baud rate for Blackfin SPORT UART"
- depends on SERIAL_BFIN_SPORT
- default SERIAL_SPORT_BAUD_RATE_57600
- help
- Choose a baud rate for the SPORT UART, other uart settings are
- 8 bit, 1 stop bit, no parity, no flow control.
-
-config SERIAL_SPORT_BAUD_RATE_115200
- bool "115200"
-
-config SERIAL_SPORT_BAUD_RATE_57600
- bool "57600"
+config SERIAL_BFIN_SPORT_CONSOLE
+ bool "Console on Blackfin sport emulated uart"
+ depends on SERIAL_BFIN_SPORT=y
+ select SERIAL_CORE_CONSOLE
-config SERIAL_SPORT_BAUD_RATE_38400
- bool "38400"
+config SERIAL_BFIN_SPORT0_UART
+ bool "Enable UART over SPORT0"
+ depends on SERIAL_BFIN_SPORT && !(BF542 || BF542M || BF544 || BF544M)
+ help
+ Enable UART over SPORT0
-config SERIAL_SPORT_BAUD_RATE_19200
- bool "19200"
+config SERIAL_BFIN_SPORT1_UART
+ bool "Enable UART over SPORT1"
+ depends on SERIAL_BFIN_SPORT
+ help
+ Enable UART over SPORT1
-config SERIAL_SPORT_BAUD_RATE_9600
- bool "9600"
-endchoice
+config SERIAL_BFIN_SPORT2_UART
+ bool "Enable UART over SPORT2"
+ depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
+ help
+ Enable UART over SPORT2
-config SPORT_BAUD_RATE
- int
- depends on SERIAL_BFIN_SPORT
- default 115200 if (SERIAL_SPORT_BAUD_RATE_115200)
- default 57600 if (SERIAL_SPORT_BAUD_RATE_57600)
- default 38400 if (SERIAL_SPORT_BAUD_RATE_38400)
- default 19200 if (SERIAL_SPORT_BAUD_RATE_19200)
- default 9600 if (SERIAL_SPORT_BAUD_RATE_9600)
+config SERIAL_BFIN_SPORT3_UART
+ bool "Enable UART over SPORT3"
+ depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
+ help
+ Enable UART over SPORT3
config SERIAL_TIMBERDALE
tristate "Support for timberdale UART"
- depends on MFD_TIMBERDALE
select SERIAL_CORE
---help---
Add support for UART controller on timberdale.
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 5548fe7df61d..6aa4723b74ee 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o
obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o
obj-$(CONFIG_SERIAL_S5PC100) += s3c6400.o
+obj-$(CONFIG_SERIAL_S5PV210) += s5pv210.o
obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
obj-$(CONFIG_SERIAL_MUX) += mux.o
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index 429a8ae86933..e4b3c2c88bb6 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -471,6 +471,20 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios,
spin_unlock_irqrestore(&uap->port.lock, flags);
}
+static void pl010_set_ldisc(struct uart_port *port)
+{
+ int line = port->line;
+
+ if (line >= port->state->port.tty->driver->num)
+ return;
+
+ if (port->state->port.tty->ldisc->ops->num == N_PPS) {
+ port->flags |= UPF_HARDPPS_CD;
+ pl010_enable_ms(port);
+ } else
+ port->flags &= ~UPF_HARDPPS_CD;
+}
+
static const char *pl010_type(struct uart_port *port)
{
return port->type == PORT_AMBA ? "AMBA" : NULL;
@@ -531,6 +545,7 @@ static struct uart_ops amba_pl010_pops = {
.startup = pl010_startup,
.shutdown = pl010_shutdown,
.set_termios = pl010_set_termios,
+ .set_ldisc = pl010_set_ldisc,
.type = pl010_type,
.release_port = pl010_release_port,
.request_port = pl010_request_port,
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index ef7adc8135dd..ce6c35333ff7 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -71,6 +71,7 @@ struct uart_amba_port {
unsigned int im; /* interrupt mask */
unsigned int old_status;
unsigned int ifls; /* vendor-specific */
+ bool autorts;
};
/* There is by now at least one vendor with differing details, so handle it */
@@ -308,6 +309,11 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1);
TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2);
TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE);
+
+ if (uap->autorts) {
+ /* We need to disable auto-RTS if we want to turn RTS off */
+ TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN);
+ }
#undef TIOCMBIT
writew(cr, uap->port.membase + UART011_CR);
@@ -437,6 +443,7 @@ static void pl011_shutdown(struct uart_port *port)
/*
* disable the port
*/
+ uap->autorts = false;
writew(UART01x_CR_UARTEN | UART011_CR_TXE, uap->port.membase + UART011_CR);
/*
@@ -456,6 +463,7 @@ static void
pl011_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int lcr_h, old_cr;
unsigned long flags;
unsigned int baud, quot;
@@ -532,6 +540,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
old_cr = readw(port->membase + UART011_CR);
writew(0, port->membase + UART011_CR);
+ if (termios->c_cflag & CRTSCTS) {
+ if (old_cr & UART011_CR_RTS)
+ old_cr |= UART011_CR_RTSEN;
+
+ old_cr |= UART011_CR_CTSEN;
+ uap->autorts = true;
+ } else {
+ old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN);
+ uap->autorts = false;
+ }
+
/* Set baud rate */
writew(quot & 0x3f, port->membase + UART011_FBRD);
writew(quot >> 6, port->membase + UART011_IBRD);
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 9d948bccafaf..2c9bf9b68327 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -1213,6 +1213,24 @@ static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser)
return ret;
}
+#ifdef CONFIG_CONSOLE_POLL
+static int atmel_poll_get_char(struct uart_port *port)
+{
+ while (!(UART_GET_CSR(port) & ATMEL_US_RXRDY))
+ cpu_relax();
+
+ return UART_GET_CHAR(port);
+}
+
+static void atmel_poll_put_char(struct uart_port *port, unsigned char ch)
+{
+ while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
+ cpu_relax();
+
+ UART_PUT_CHAR(port, ch);
+}
+#endif
+
static struct uart_ops atmel_pops = {
.tx_empty = atmel_tx_empty,
.set_mctrl = atmel_set_mctrl,
@@ -1232,6 +1250,10 @@ static struct uart_ops atmel_pops = {
.config_port = atmel_config_port,
.verify_port = atmel_verify_port,
.pm = atmel_serial_pm,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = atmel_poll_get_char,
+ .poll_put_char = atmel_poll_put_char,
+#endif
};
/*
diff --git a/drivers/serial/bcm63xx_uart.c b/drivers/serial/bcm63xx_uart.c
index 37ad0c449937..a1a0e55d0807 100644
--- a/drivers/serial/bcm63xx_uart.c
+++ b/drivers/serial/bcm63xx_uart.c
@@ -35,7 +35,7 @@
#include <bcm63xx_regs.h>
#include <bcm63xx_io.h>
-#define BCM63XX_NR_UARTS 1
+#define BCM63XX_NR_UARTS 2
static struct uart_port ports[BCM63XX_NR_UARTS];
@@ -784,7 +784,7 @@ static struct uart_driver bcm_uart_driver = {
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
- .nr = 1,
+ .nr = BCM63XX_NR_UARTS,
.cons = BCM63XX_CONSOLE,
};
@@ -826,11 +826,12 @@ static int __devinit bcm_uart_probe(struct platform_device *pdev)
port->dev = &pdev->dev;
port->fifosize = 16;
port->uartclk = clk_get_rate(clk) / 2;
+ port->line = pdev->id;
clk_put(clk);
ret = uart_add_one_port(&bcm_uart_driver, port);
if (ret) {
- kfree(port);
+ ports[pdev->id].membase = 0;
return ret;
}
platform_set_drvdata(pdev, port);
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 50abb7e557f4..fcf273e3f48c 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/ioport.h>
+#include <linux/io.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
@@ -237,7 +238,8 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
- if (kgdb_connected && kgdboc_port_line == uart->port.line)
+ if (kgdb_connected && kgdboc_port_line == uart->port.line
+ && kgdboc_break_enabled)
if (ch == 0x3) {/* Ctrl + C */
kgdb_breakpoint();
return;
@@ -488,6 +490,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
{
int x_pos, pos;
+ dma_disable_irq(uart->tx_dma_channel);
dma_disable_irq(uart->rx_dma_channel);
spin_lock_bh(&uart->port.lock);
@@ -521,6 +524,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
}
spin_unlock_bh(&uart->port.lock);
+ dma_enable_irq(uart->tx_dma_channel);
dma_enable_irq(uart->rx_dma_channel);
mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
@@ -746,15 +750,6 @@ static int bfin_serial_startup(struct uart_port *port)
Status interrupt.\n");
}
- if (uart->cts_pin >= 0) {
- gpio_request(uart->cts_pin, DRIVER_NAME);
- gpio_direction_output(uart->cts_pin, 1);
- }
- if (uart->rts_pin >= 0) {
- gpio_request(uart->rts_pin, DRIVER_NAME);
- gpio_direction_output(uart->rts_pin, 0);
- }
-
/* CTS RTS PINs are negative assertive. */
UART_PUT_MCR(uart, ACTS);
UART_SET_IER(uart, EDSSI);
@@ -801,10 +796,6 @@ static void bfin_serial_shutdown(struct uart_port *port)
gpio_free(uart->rts_pin);
#endif
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
- if (uart->cts_pin >= 0)
- gpio_free(uart->cts_pin);
- if (uart->rts_pin >= 0)
- gpio_free(uart->rts_pin);
if (UART_GET_IER(uart) && EDSSI)
free_irq(uart->status_irq, uart);
#endif
@@ -1409,8 +1400,7 @@ static int bfin_serial_remove(struct platform_device *dev)
continue;
uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
bfin_serial_ports[i].port.dev = NULL;
-#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
- defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+#if defined(CONFIG_SERIAL_BFIN_CTSRTS)
gpio_free(bfin_serial_ports[i].cts_pin);
gpio_free(bfin_serial_ports[i].rts_pin);
#endif
diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c
index 088bb35475f1..7c72888fbf94 100644
--- a/drivers/serial/bfin_sport_uart.c
+++ b/drivers/serial/bfin_sport_uart.c
@@ -1,27 +1,11 @@
/*
- * File: linux/drivers/serial/bfin_sport_uart.c
+ * Blackfin On-Chip Sport Emulated UART Driver
*
- * Based on: drivers/serial/bfin_5xx.c by Aubrey Li.
- * Author: Roy Huang <roy.huang@analog.com>
+ * Copyright 2006-2009 Analog Devices Inc.
*
- * Created: Nov 22, 2006
- * Copyright: (c) 2006-2007 Analog Devices Inc.
- * Description: this driver enable SPORTs on Blackfin emulate UART.
+ * Enter bugs at http://blackfin.uclinux.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.
- *
- * 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, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
/*
@@ -29,39 +13,18 @@
* http://www.analog.com/UploadedFiles/Application_Notes/399447663EE191.pdf
* This application note describe how to implement a UART on a Sharc DSP,
* but this driver is implemented on Blackfin Processor.
+ * Transmit Frame Sync is not used by this driver to transfer data out.
*/
-/* After reset, there is a prelude of low level pulse when transmit data first
- * time. No addtional pulse in following transmit.
- * According to document:
- * The SPORTs are ready to start transmitting or receiving data no later than
- * three serial clock cycles after they are enabled in the SPORTx_TCR1 or
- * SPORTx_RCR1 register. No serial clock cycles are lost from this point on.
- * The first internal frame sync will occur one frame sync delay after the
- * SPORTs are ready. External frame syncs can occur as soon as the SPORT is
- * ready.
- */
+/* #define DEBUG */
-/* Thanks to Axel Alatalo <axel@rubico.se> for fixing sport rx bug. Sometimes
- * sport receives data incorrectly. The following is Axel's words.
- * As EE-191, sport rx samples 3 times of the UART baudrate and takes the
- * middle smaple of every 3 samples as the data bit. For a 8-N-1 UART setting,
- * 30 samples will be required for a byte. If transmitter sends a 1/3 bit short
- * byte due to buadrate drift, then the 30th sample of a byte, this sample is
- * also the third sample of the stop bit, will happens on the immediately
- * following start bit which will be thrown away and missed. Thus since parts
- * of the startbit will be missed and the receiver will begin to drift, the
- * effect accumulates over time until synchronization is lost.
- * If only require 2 samples of the stopbit (by sampling in total 29 samples),
- * then a to short byte as in the case above will be tolerated. Then the 1/3
- * early startbit will trigger a framesync since the last read is complete
- * after only 2/3 stopbit and framesync is active during the last 1/3 looking
- * for a possible early startbit. */
-
-//#define DEBUG
+#define DRV_NAME "bfin-sport-uart"
+#define DEVICE_NAME "ttySS"
+#define pr_fmt(fmt) DRV_NAME ": " fmt
#include <linux/module.h>
#include <linux/ioport.h>
+#include <linux/io.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
@@ -75,23 +38,36 @@
#include "bfin_sport_uart.h"
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
unsigned short bfin_uart_pin_req_sport0[] =
{P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \
P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0};
-
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
unsigned short bfin_uart_pin_req_sport1[] =
{P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \
P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0};
-
-#define DRV_NAME "bfin-sport-uart"
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT2_UART
+unsigned short bfin_uart_pin_req_sport2[] =
+ {P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, P_SPORT2_RFS, \
+ P_SPORT2_DRPRI, P_SPORT2_RSCLK, P_SPORT2_DRSEC, P_SPORT2_DTSEC, 0};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT3_UART
+unsigned short bfin_uart_pin_req_sport3[] =
+ {P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, P_SPORT3_RFS, \
+ P_SPORT3_DRPRI, P_SPORT3_RSCLK, P_SPORT3_DRSEC, P_SPORT3_DTSEC, 0};
+#endif
struct sport_uart_port {
struct uart_port port;
- char *name;
-
- int tx_irq;
- int rx_irq;
int err_irq;
+ unsigned short csize;
+ unsigned short rxmask;
+ unsigned short txmask1;
+ unsigned short txmask2;
+ unsigned char stopb;
+/* unsigned char parib; */
};
static void sport_uart_tx_chars(struct sport_uart_port *up);
@@ -99,36 +75,42 @@ static void sport_stop_tx(struct uart_port *port);
static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
{
- pr_debug("%s value:%x\n", __func__, value);
- /* Place a Start and Stop bit */
+ pr_debug("%s value:%x, mask1=0x%x, mask2=0x%x\n", __func__, value,
+ up->txmask1, up->txmask2);
+
+ /* Place Start and Stop bits */
__asm__ __volatile__ (
- "R2 = b#01111111100;"
- "R3 = b#10000000001;"
- "%0 <<= 2;"
- "%0 = %0 & R2;"
- "%0 = %0 | R3;"
- : "=d"(value)
- : "d"(value)
- : "ASTAT", "R2", "R3"
+ "%[val] <<= 1;"
+ "%[val] = %[val] & %[mask1];"
+ "%[val] = %[val] | %[mask2];"
+ : [val]"+d"(value)
+ : [mask1]"d"(up->txmask1), [mask2]"d"(up->txmask2)
+ : "ASTAT"
);
pr_debug("%s value:%x\n", __func__, value);
SPORT_PUT_TX(up, value);
}
-static inline unsigned int rx_one_byte(struct sport_uart_port *up)
+static inline unsigned char rx_one_byte(struct sport_uart_port *up)
{
- unsigned int value, extract;
+ unsigned int value;
+ unsigned char extract;
u32 tmp_mask1, tmp_mask2, tmp_shift, tmp;
- value = SPORT_GET_RX32(up);
- pr_debug("%s value:%x\n", __func__, value);
+ if ((up->csize + up->stopb) > 7)
+ value = SPORT_GET_RX32(up);
+ else
+ value = SPORT_GET_RX(up);
+
+ pr_debug("%s value:%x, cs=%d, mask=0x%x\n", __func__, value,
+ up->csize, up->rxmask);
- /* Extract 8 bits data */
+ /* Extract data */
__asm__ __volatile__ (
"%[extr] = 0;"
- "%[mask1] = 0x1801(Z);"
- "%[mask2] = 0x0300(Z);"
+ "%[mask1] = %[rxmask];"
+ "%[mask2] = 0x0200(Z);"
"%[shift] = 0;"
"LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];"
".Lloop_s:"
@@ -138,9 +120,9 @@ static inline unsigned int rx_one_byte(struct sport_uart_port *up)
"%[mask1] = %[mask1] - %[mask2];"
".Lloop_e:"
"%[shift] += 1;"
- : [val]"=d"(value), [extr]"=d"(extract), [shift]"=d"(tmp_shift), [tmp]"=d"(tmp),
- [mask1]"=d"(tmp_mask1), [mask2]"=d"(tmp_mask2)
- : "d"(value), [lc]"a"(8)
+ : [extr]"=&d"(extract), [shift]"=&d"(tmp_shift), [tmp]"=&d"(tmp),
+ [mask1]"=&d"(tmp_mask1), [mask2]"=&d"(tmp_mask2)
+ : [val]"d"(value), [rxmask]"d"(up->rxmask), [lc]"a"(up->csize)
: "ASTAT", "LB0", "LC0", "LT0"
);
@@ -148,29 +130,28 @@ static inline unsigned int rx_one_byte(struct sport_uart_port *up)
return extract;
}
-static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
+static int sport_uart_setup(struct sport_uart_port *up, int size, int baud_rate)
{
- int tclkdiv, tfsdiv, rclkdiv;
+ int tclkdiv, rclkdiv;
+ unsigned int sclk = get_sclk();
- /* Set TCR1 and TCR2 */
- SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK));
- SPORT_PUT_TCR2(up, 10);
+ /* Set TCR1 and TCR2, TFSR is not enabled for uart */
+ SPORT_PUT_TCR1(up, (ITFS | TLSBIT | ITCLK));
+ SPORT_PUT_TCR2(up, size + 1);
pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
/* Set RCR1 and RCR2 */
SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK));
- SPORT_PUT_RCR2(up, 28);
+ SPORT_PUT_RCR2(up, (size + 1) * 2 - 1);
pr_debug("%s RCR1:%x, RCR2:%x\n", __func__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
- tclkdiv = sclk/(2 * baud_rate) - 1;
- tfsdiv = 12;
- rclkdiv = sclk/(2 * baud_rate * 3) - 1;
+ tclkdiv = sclk / (2 * baud_rate) - 1;
+ rclkdiv = sclk / (2 * baud_rate * 2) - 1;
SPORT_PUT_TCLKDIV(up, tclkdiv);
- SPORT_PUT_TFSDIV(up, tfsdiv);
SPORT_PUT_RCLKDIV(up, rclkdiv);
SSYNC();
- pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, tfsdiv:%d, rclkdiv:%d\n",
- __func__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv);
+ pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, rclkdiv:%d\n",
+ __func__, sclk, baud_rate, tclkdiv, rclkdiv);
return 0;
}
@@ -181,23 +162,29 @@ static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id)
struct tty_struct *tty = up->port.state->port.tty;
unsigned int ch;
- do {
+ spin_lock(&up->port.lock);
+
+ while (SPORT_GET_STAT(up) & RXNE) {
ch = rx_one_byte(up);
up->port.icount.rx++;
- if (uart_handle_sysrq_char(&up->port, ch))
- ;
- else
+ if (!uart_handle_sysrq_char(&up->port, ch))
tty_insert_flip_char(tty, ch, TTY_NORMAL);
- } while (SPORT_GET_STAT(up) & RXNE);
+ }
tty_flip_buffer_push(tty);
+ spin_unlock(&up->port.lock);
+
return IRQ_HANDLED;
}
static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id)
{
- sport_uart_tx_chars(dev_id);
+ struct sport_uart_port *up = dev_id;
+
+ spin_lock(&up->port.lock);
+ sport_uart_tx_chars(up);
+ spin_unlock(&up->port.lock);
return IRQ_HANDLED;
}
@@ -208,6 +195,8 @@ static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
struct tty_struct *tty = up->port.state->port.tty;
unsigned int stat = SPORT_GET_STAT(up);
+ spin_lock(&up->port.lock);
+
/* Overflow in RX FIFO */
if (stat & ROVF) {
up->port.icount.overrun++;
@@ -216,15 +205,16 @@ static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
}
/* These should not happen */
if (stat & (TOVF | TUVF | RUVF)) {
- printk(KERN_ERR "SPORT Error:%s %s %s\n",
- (stat & TOVF)?"TX overflow":"",
- (stat & TUVF)?"TX underflow":"",
- (stat & RUVF)?"RX underflow":"");
+ pr_err("SPORT Error:%s %s %s\n",
+ (stat & TOVF) ? "TX overflow" : "",
+ (stat & TUVF) ? "TX underflow" : "",
+ (stat & RUVF) ? "RX underflow" : "");
SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
}
SSYNC();
+ spin_unlock(&up->port.lock);
return IRQ_HANDLED;
}
@@ -232,60 +222,37 @@ static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
static int sport_startup(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
- char buffer[20];
- int retval;
+ int ret;
pr_debug("%s enter\n", __func__);
- snprintf(buffer, 20, "%s rx", up->name);
- retval = request_irq(up->rx_irq, sport_uart_rx_irq, IRQF_SAMPLE_RANDOM, buffer, up);
- if (retval) {
- printk(KERN_ERR "Unable to request interrupt %s\n", buffer);
- return retval;
+ ret = request_irq(up->port.irq, sport_uart_rx_irq, 0,
+ "SPORT_UART_RX", up);
+ if (ret) {
+ dev_err(port->dev, "unable to request SPORT RX interrupt\n");
+ return ret;
}
- snprintf(buffer, 20, "%s tx", up->name);
- retval = request_irq(up->tx_irq, sport_uart_tx_irq, IRQF_SAMPLE_RANDOM, buffer, up);
- if (retval) {
- printk(KERN_ERR "Unable to request interrupt %s\n", buffer);
+ ret = request_irq(up->port.irq+1, sport_uart_tx_irq, 0,
+ "SPORT_UART_TX", up);
+ if (ret) {
+ dev_err(port->dev, "unable to request SPORT TX interrupt\n");
goto fail1;
}
- snprintf(buffer, 20, "%s err", up->name);
- retval = request_irq(up->err_irq, sport_uart_err_irq, IRQF_SAMPLE_RANDOM, buffer, up);
- if (retval) {
- printk(KERN_ERR "Unable to request interrupt %s\n", buffer);
+ ret = request_irq(up->err_irq, sport_uart_err_irq, 0,
+ "SPORT_UART_STATUS", up);
+ if (ret) {
+ dev_err(port->dev, "unable to request SPORT status interrupt\n");
goto fail2;
}
- if (port->line) {
- if (peripheral_request_list(bfin_uart_pin_req_sport1, DRV_NAME))
- goto fail3;
- } else {
- if (peripheral_request_list(bfin_uart_pin_req_sport0, DRV_NAME))
- goto fail3;
- }
-
- sport_uart_setup(up, get_sclk(), port->uartclk);
-
- /* Enable receive interrupt */
- SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) | RSPEN));
- SSYNC();
-
return 0;
+ fail2:
+ free_irq(up->port.irq+1, up);
+ fail1:
+ free_irq(up->port.irq, up);
-
-fail3:
- printk(KERN_ERR DRV_NAME
- ": Requesting Peripherals failed\n");
-
- free_irq(up->err_irq, up);
-fail2:
- free_irq(up->tx_irq, up);
-fail1:
- free_irq(up->rx_irq, up);
-
- return retval;
-
+ return ret;
}
static void sport_uart_tx_chars(struct sport_uart_port *up)
@@ -344,20 +311,17 @@ static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void sport_stop_tx(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
- unsigned int stat;
pr_debug("%s enter\n", __func__);
- stat = SPORT_GET_STAT(up);
- while(!(stat & TXHRE)) {
- udelay(1);
- stat = SPORT_GET_STAT(up);
- }
/* Although the hold register is empty, last byte is still in shift
- * register and not sent out yet. If baud rate is lower than default,
- * delay should be longer. For example, if the baud rate is 9600,
- * the delay must be at least 2ms by experience */
- udelay(500);
+ * register and not sent out yet. So, put a dummy data into TX FIFO.
+ * Then, sport tx stops when last byte is shift out and the dummy
+ * data is moved into the shift register.
+ */
+ SPORT_PUT_TX(up, 0xffff);
+ while (!(SPORT_GET_STAT(up) & TXHRE))
+ cpu_relax();
SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
SSYNC();
@@ -370,6 +334,7 @@ static void sport_start_tx(struct uart_port *port)
struct sport_uart_port *up = (struct sport_uart_port *)port;
pr_debug("%s enter\n", __func__);
+
/* Write data into SPORT FIFO before enable SPROT to transmit */
sport_uart_tx_chars(up);
@@ -403,37 +368,24 @@ static void sport_shutdown(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
- pr_debug("%s enter\n", __func__);
+ dev_dbg(port->dev, "%s enter\n", __func__);
/* Disable sport */
SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
SSYNC();
- if (port->line) {
- peripheral_free_list(bfin_uart_pin_req_sport1);
- } else {
- peripheral_free_list(bfin_uart_pin_req_sport0);
- }
-
- free_irq(up->rx_irq, up);
- free_irq(up->tx_irq, up);
+ free_irq(up->port.irq, up);
+ free_irq(up->port.irq+1, up);
free_irq(up->err_irq, up);
}
-static void sport_set_termios(struct uart_port *port,
- struct ktermios *termios, struct ktermios *old)
-{
- pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag);
- uart_update_timeout(port, CS8 ,port->uartclk);
-}
-
static const char *sport_type(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
pr_debug("%s enter\n", __func__);
- return up->name;
+ return up->port.type == PORT_BFIN_SPORT ? "BFIN-SPORT-UART" : NULL;
}
static void sport_release_port(struct uart_port *port)
@@ -461,6 +413,110 @@ static int sport_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
+static void sport_set_termios(struct uart_port *port,
+ struct ktermios *termios, struct ktermios *old)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+ unsigned long flags;
+ int i;
+
+ pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag);
+
+ switch (termios->c_cflag & CSIZE) {
+ case CS8:
+ up->csize = 8;
+ break;
+ case CS7:
+ up->csize = 7;
+ break;
+ case CS6:
+ up->csize = 6;
+ break;
+ case CS5:
+ up->csize = 5;
+ break;
+ default:
+ pr_warning("requested word length not supported\n");
+ }
+
+ if (termios->c_cflag & CSTOPB) {
+ up->stopb = 1;
+ }
+ if (termios->c_cflag & PARENB) {
+ pr_warning("PAREN bits is not supported yet\n");
+ /* up->parib = 1; */
+ }
+
+ port->read_status_mask = OE;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= (FE | PE);
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= BI;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= FE | PE;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= BI;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= OE;
+ }
+
+ /* RX extract mask */
+ up->rxmask = 0x01 | (((up->csize + up->stopb) * 2 - 1) << 0x8);
+ /* TX masks, 8 bit data and 1 bit stop for example:
+ * mask1 = b#0111111110
+ * mask2 = b#1000000000
+ */
+ for (i = 0, up->txmask1 = 0; i < up->csize; i++)
+ up->txmask1 |= (1<<i);
+ up->txmask2 = (1<<i);
+ if (up->stopb) {
+ ++i;
+ up->txmask2 |= (1<<i);
+ }
+ up->txmask1 <<= 1;
+ up->txmask2 <<= 1;
+ /* uart baud rate */
+ port->uartclk = uart_get_baud_rate(port, termios, old, 0, get_sclk()/16);
+
+ spin_lock_irqsave(&up->port.lock, flags);
+
+ /* Disable UART */
+ SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
+ SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
+
+ sport_uart_setup(up, up->csize + up->stopb, port->uartclk);
+
+ /* driver TX line high after config, one dummy data is
+ * necessary to stop sport after shift one byte
+ */
+ SPORT_PUT_TX(up, 0xffff);
+ SPORT_PUT_TX(up, 0xffff);
+ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
+ SSYNC();
+ while (!(SPORT_GET_STAT(up) & TXHRE))
+ cpu_relax();
+ SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
+ SSYNC();
+
+ /* Port speed changed, update the per-port timeout. */
+ uart_update_timeout(port, termios->c_cflag, port->uartclk);
+
+ /* Enable sport rx */
+ SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) | RSPEN);
+ SSYNC();
+
+ spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
struct uart_ops sport_uart_ops = {
.tx_empty = sport_tx_empty,
.set_mctrl = sport_set_mctrl,
@@ -480,138 +536,319 @@ struct uart_ops sport_uart_ops = {
.verify_port = sport_verify_port,
};
-static struct sport_uart_port sport_uart_ports[] = {
- { /* SPORT 0 */
- .name = "SPORT0",
- .tx_irq = IRQ_SPORT0_TX,
- .rx_irq = IRQ_SPORT0_RX,
- .err_irq= IRQ_SPORT0_ERROR,
- .port = {
- .type = PORT_BFIN_SPORT,
- .iotype = UPIO_MEM,
- .membase = (void __iomem *)SPORT0_TCR1,
- .mapbase = SPORT0_TCR1,
- .irq = IRQ_SPORT0_RX,
- .uartclk = CONFIG_SPORT_BAUD_RATE,
- .fifosize = 8,
- .ops = &sport_uart_ops,
- .line = 0,
- },
- }, { /* SPORT 1 */
- .name = "SPORT1",
- .tx_irq = IRQ_SPORT1_TX,
- .rx_irq = IRQ_SPORT1_RX,
- .err_irq= IRQ_SPORT1_ERROR,
- .port = {
- .type = PORT_BFIN_SPORT,
- .iotype = UPIO_MEM,
- .membase = (void __iomem *)SPORT1_TCR1,
- .mapbase = SPORT1_TCR1,
- .irq = IRQ_SPORT1_RX,
- .uartclk = CONFIG_SPORT_BAUD_RATE,
- .fifosize = 8,
- .ops = &sport_uart_ops,
- .line = 1,
- },
+#define BFIN_SPORT_UART_MAX_PORTS 4
+
+static struct sport_uart_port *bfin_sport_uart_ports[BFIN_SPORT_UART_MAX_PORTS];
+
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+static int __init
+sport_uart_console_setup(struct console *co, char *options)
+{
+ struct sport_uart_port *up;
+ int baud = 57600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ /* Check whether an invalid uart number has been specified */
+ if (co->index < 0 || co->index >= BFIN_SPORT_UART_MAX_PORTS)
+ return -ENODEV;
+
+ up = bfin_sport_uart_ports[co->index];
+ if (!up)
+ return -ENODEV;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(&up->port, co, baud, parity, bits, flow);
+}
+
+static void sport_uart_console_putchar(struct uart_port *port, int ch)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ while (SPORT_GET_STAT(up) & TXF)
+ barrier();
+
+ tx_one_byte(up, ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+sport_uart_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct sport_uart_port *up = bfin_sport_uart_ports[co->index];
+ unsigned long flags;
+
+ spin_lock_irqsave(&up->port.lock, flags);
+
+ if (SPORT_GET_TCR1(up) & TSPEN)
+ uart_console_write(&up->port, s, count, sport_uart_console_putchar);
+ else {
+ /* dummy data to start sport */
+ while (SPORT_GET_STAT(up) & TXF)
+ barrier();
+ SPORT_PUT_TX(up, 0xffff);
+ /* Enable transmit, then an interrupt will generated */
+ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
+ SSYNC();
+
+ uart_console_write(&up->port, s, count, sport_uart_console_putchar);
+
+ /* Although the hold register is empty, last byte is still in shift
+ * register and not sent out yet. So, put a dummy data into TX FIFO.
+ * Then, sport tx stops when last byte is shift out and the dummy
+ * data is moved into the shift register.
+ */
+ while (SPORT_GET_STAT(up) & TXF)
+ barrier();
+ SPORT_PUT_TX(up, 0xffff);
+ while (!(SPORT_GET_STAT(up) & TXHRE))
+ barrier();
+
+ /* Stop sport tx transfer */
+ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
+ SSYNC();
}
+
+ spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static struct uart_driver sport_uart_reg;
+
+static struct console sport_uart_console = {
+ .name = DEVICE_NAME,
+ .write = sport_uart_console_write,
+ .device = uart_console_device,
+ .setup = sport_uart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &sport_uart_reg,
};
+#define SPORT_UART_CONSOLE (&sport_uart_console)
+#else
+#define SPORT_UART_CONSOLE NULL
+#endif /* CONFIG_SERIAL_BFIN_SPORT_CONSOLE */
+
+
static struct uart_driver sport_uart_reg = {
.owner = THIS_MODULE,
- .driver_name = "SPORT-UART",
- .dev_name = "ttySS",
+ .driver_name = DRV_NAME,
+ .dev_name = DEVICE_NAME,
.major = 204,
.minor = 84,
- .nr = ARRAY_SIZE(sport_uart_ports),
- .cons = NULL,
+ .nr = BFIN_SPORT_UART_MAX_PORTS,
+ .cons = SPORT_UART_CONSOLE,
};
-static int sport_uart_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_PM
+static int sport_uart_suspend(struct device *dev)
{
- struct sport_uart_port *sport = platform_get_drvdata(dev);
+ struct sport_uart_port *sport = dev_get_drvdata(dev);
- pr_debug("%s enter\n", __func__);
+ dev_dbg(dev, "%s enter\n", __func__);
if (sport)
uart_suspend_port(&sport_uart_reg, &sport->port);
return 0;
}
-static int sport_uart_resume(struct platform_device *dev)
+static int sport_uart_resume(struct device *dev)
{
- struct sport_uart_port *sport = platform_get_drvdata(dev);
+ struct sport_uart_port *sport = dev_get_drvdata(dev);
- pr_debug("%s enter\n", __func__);
+ dev_dbg(dev, "%s enter\n", __func__);
if (sport)
uart_resume_port(&sport_uart_reg, &sport->port);
return 0;
}
-static int sport_uart_probe(struct platform_device *dev)
+static struct dev_pm_ops bfin_sport_uart_dev_pm_ops = {
+ .suspend = sport_uart_suspend,
+ .resume = sport_uart_resume,
+};
+#endif
+
+static int __devinit sport_uart_probe(struct platform_device *pdev)
{
- pr_debug("%s enter\n", __func__);
- sport_uart_ports[dev->id].port.dev = &dev->dev;
- uart_add_one_port(&sport_uart_reg, &sport_uart_ports[dev->id].port);
- platform_set_drvdata(dev, &sport_uart_ports[dev->id]);
+ struct resource *res;
+ struct sport_uart_port *sport;
+ int ret = 0;
- return 0;
+ dev_dbg(&pdev->dev, "%s enter\n", __func__);
+
+ if (pdev->id < 0 || pdev->id >= BFIN_SPORT_UART_MAX_PORTS) {
+ dev_err(&pdev->dev, "Wrong sport uart platform device id.\n");
+ return -ENOENT;
+ }
+
+ if (bfin_sport_uart_ports[pdev->id] == NULL) {
+ bfin_sport_uart_ports[pdev->id] =
+ kmalloc(sizeof(struct sport_uart_port), GFP_KERNEL);
+ sport = bfin_sport_uart_ports[pdev->id];
+ if (!sport) {
+ dev_err(&pdev->dev,
+ "Fail to kmalloc sport_uart_port\n");
+ return -ENOMEM;
+ }
+
+ ret = peripheral_request_list(
+ (unsigned short *)pdev->dev.platform_data, DRV_NAME);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Fail to request SPORT peripherals\n");
+ goto out_error_free_mem;
+ }
+
+ spin_lock_init(&sport->port.lock);
+ sport->port.fifosize = SPORT_TX_FIFO_SIZE,
+ sport->port.ops = &sport_uart_ops;
+ sport->port.line = pdev->id;
+ sport->port.iotype = UPIO_MEM;
+ sport->port.flags = UPF_BOOT_AUTOCONF;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+ ret = -ENOENT;
+ goto out_error_free_peripherals;
+ }
+
+ sport->port.membase = ioremap(res->start,
+ res->end - res->start);
+ if (!sport->port.membase) {
+ dev_err(&pdev->dev, "Cannot map sport IO\n");
+ ret = -ENXIO;
+ goto out_error_free_peripherals;
+ }
+
+ sport->port.irq = platform_get_irq(pdev, 0);
+ if (sport->port.irq < 0) {
+ dev_err(&pdev->dev, "No sport RX/TX IRQ specified\n");
+ ret = -ENOENT;
+ goto out_error_unmap;
+ }
+
+ sport->err_irq = platform_get_irq(pdev, 1);
+ if (sport->err_irq < 0) {
+ dev_err(&pdev->dev, "No sport status IRQ specified\n");
+ ret = -ENOENT;
+ goto out_error_unmap;
+ }
+ }
+
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+ if (!is_early_platform_device(pdev)) {
+#endif
+ sport = bfin_sport_uart_ports[pdev->id];
+ sport->port.dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, sport);
+ ret = uart_add_one_port(&sport_uart_reg, &sport->port);
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+ }
+#endif
+ if (!ret)
+ return 0;
+
+ if (sport) {
+out_error_unmap:
+ iounmap(sport->port.membase);
+out_error_free_peripherals:
+ peripheral_free_list(
+ (unsigned short *)pdev->dev.platform_data);
+out_error_free_mem:
+ kfree(sport);
+ bfin_sport_uart_ports[pdev->id] = NULL;
+ }
+
+ return ret;
}
-static int sport_uart_remove(struct platform_device *dev)
+static int __devexit sport_uart_remove(struct platform_device *pdev)
{
- struct sport_uart_port *sport = platform_get_drvdata(dev);
+ struct sport_uart_port *sport = platform_get_drvdata(pdev);
- pr_debug("%s enter\n", __func__);
- platform_set_drvdata(dev, NULL);
+ dev_dbg(&pdev->dev, "%s enter\n", __func__);
+ dev_set_drvdata(&pdev->dev, NULL);
- if (sport)
+ if (sport) {
uart_remove_one_port(&sport_uart_reg, &sport->port);
+ iounmap(sport->port.membase);
+ peripheral_free_list(
+ (unsigned short *)pdev->dev.platform_data);
+ kfree(sport);
+ bfin_sport_uart_ports[pdev->id] = NULL;
+ }
return 0;
}
static struct platform_driver sport_uart_driver = {
.probe = sport_uart_probe,
- .remove = sport_uart_remove,
- .suspend = sport_uart_suspend,
- .resume = sport_uart_resume,
+ .remove = __devexit_p(sport_uart_remove),
.driver = {
.name = DRV_NAME,
+#ifdef CONFIG_PM
+ .pm = &bfin_sport_uart_dev_pm_ops,
+#endif
},
};
+#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+static __initdata struct early_platform_driver early_sport_uart_driver = {
+ .class_str = DRV_NAME,
+ .pdrv = &sport_uart_driver,
+ .requested_id = EARLY_PLATFORM_ID_UNSET,
+};
+
+static int __init sport_uart_rs_console_init(void)
+{
+ early_platform_driver_register(&early_sport_uart_driver, DRV_NAME);
+
+ early_platform_driver_probe(DRV_NAME, BFIN_SPORT_UART_MAX_PORTS, 0);
+
+ register_console(&sport_uart_console);
+
+ return 0;
+}
+console_initcall(sport_uart_rs_console_init);
+#endif
+
static int __init sport_uart_init(void)
{
int ret;
- pr_debug("%s enter\n", __func__);
+ pr_info("Serial: Blackfin uart over sport driver\n");
+
ret = uart_register_driver(&sport_uart_reg);
- if (ret != 0) {
- printk(KERN_ERR "Failed to register %s:%d\n",
+ if (ret) {
+ pr_err("failed to register %s:%d\n",
sport_uart_reg.driver_name, ret);
return ret;
}
ret = platform_driver_register(&sport_uart_driver);
- if (ret != 0) {
- printk(KERN_ERR "Failed to register sport uart driver:%d\n", ret);
+ if (ret) {
+ pr_err("failed to register sport uart driver:%d\n", ret);
uart_unregister_driver(&sport_uart_reg);
}
-
- pr_debug("%s exit\n", __func__);
return ret;
}
+module_init(sport_uart_init);
static void __exit sport_uart_exit(void)
{
- pr_debug("%s enter\n", __func__);
platform_driver_unregister(&sport_uart_driver);
uart_unregister_driver(&sport_uart_reg);
}
-
-module_init(sport_uart_init);
module_exit(sport_uart_exit);
+MODULE_AUTHOR("Sonic Zhang, Roy Huang");
+MODULE_DESCRIPTION("Blackfin serial over SPORT driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/serial/bfin_sport_uart.h b/drivers/serial/bfin_sport_uart.h
index 671d41cc1a3f..abe03614e4df 100644
--- a/drivers/serial/bfin_sport_uart.h
+++ b/drivers/serial/bfin_sport_uart.h
@@ -1,29 +1,23 @@
/*
- * File: linux/drivers/serial/bfin_sport_uart.h
+ * Blackfin On-Chip Sport Emulated UART Driver
*
- * Based on: include/asm-blackfin/mach-533/bfin_serial_5xx.h
- * Author: Roy Huang <roy.huang>analog.com>
+ * Copyright 2006-2008 Analog Devices Inc.
*
- * Created: Nov 22, 2006
- * Copyright: (C) Analog Device Inc.
- * Description: this driver enable SPORTs on Blackfin emulate UART.
+ * Enter bugs at http://blackfin.uclinux.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.
- *
- * 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, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
+/*
+ * This driver and the hardware supported are in term of EE-191 of ADI.
+ * http://www.analog.com/UploadedFiles/Application_Notes/399447663EE191.pdf
+ * This application note describe how to implement a UART on a Sharc DSP,
+ * but this driver is implemented on Blackfin Processor.
+ * Transmit Frame Sync is not used by this driver to transfer data out.
+ */
+
+#ifndef _BFIN_SPORT_UART_H
+#define _BFIN_SPORT_UART_H
#define OFFSET_TCR1 0x00 /* Transmit Configuration 1 Register */
#define OFFSET_TCR2 0x04 /* Transmit Configuration 2 Register */
@@ -61,3 +55,7 @@
#define SPORT_PUT_RCLKDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCLKDIV), v)
#define SPORT_PUT_RFSDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RFSDIV), v)
#define SPORT_PUT_STAT(sport, v) bfin_write16(((sport)->port.membase + OFFSET_STAT), v)
+
+#define SPORT_TX_FIFO_SIZE 8
+
+#endif /* _BFIN_SPORT_UART_H */
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
index 0028b6f89ce6..53a468227056 100644
--- a/drivers/serial/icom.c
+++ b/drivers/serial/icom.c
@@ -751,7 +751,6 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
trace(icom_port, "FID_STATUS", status);
count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength);
- count = tty_buffer_request_room(tty, count);
trace(icom_port, "RCV_COUNT", count);
trace(icom_port, "REAL_COUNT", count);
@@ -1654,4 +1653,6 @@ MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");
MODULE_SUPPORTED_DEVICE
("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters");
MODULE_LICENSE("GPL");
-
+MODULE_FIRMWARE("icom_call_setup.bin");
+MODULE_FIRMWARE("icom_res_dce.bin");
+MODULE_FIRMWARE("icom_asc.bin");
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 18130f11238e..e579d7a1807a 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -440,7 +440,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
temp = readl(sport->port.membase + USR2);
if (temp & USR2_BRCD) {
- writel(temp | USR2_BRCD, sport->port.membase + USR2);
+ writel(USR2_BRCD, sport->port.membase + USR2);
if (uart_handle_break(&sport->port))
continue;
}
@@ -1088,7 +1088,7 @@ imx_console_get_options(struct imx_port *sport, int *baud,
int *parity, int *bits)
{
- if ( readl(sport->port.membase + UCR1) | UCR1_UARTEN ) {
+ if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) {
/* ok, the port was enabled */
unsigned int ucr2, ubir,ubmr, uartclk;
unsigned int baud_raw;
@@ -1279,7 +1279,7 @@ static int serial_imx_probe(struct platform_device *pdev)
sport->use_irda = 1;
#endif
- if (pdata->init) {
+ if (pdata && pdata->init) {
ret = pdata->init(pdev);
if (ret)
goto clkput;
@@ -1292,7 +1292,7 @@ static int serial_imx_probe(struct platform_device *pdev)
return 0;
deinit:
- if (pdata->exit)
+ if (pdata && pdata->exit)
pdata->exit(pdev);
clkput:
clk_put(sport->clk);
@@ -1321,7 +1321,7 @@ static int serial_imx_remove(struct platform_device *pdev)
clk_disable(sport->clk);
- if (pdata->exit)
+ if (pdata && pdata->exit)
pdata->exit(pdev);
iounmap(sport->port.membase);
diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
index 85dc0410ac1a..23ba6b40b3ac 100644
--- a/drivers/serial/ioc3_serial.c
+++ b/drivers/serial/ioc3_serial.c
@@ -1411,8 +1411,7 @@ static int receive_chars(struct uart_port *the_port)
read_count = do_read(the_port, ch, MAX_CHARS);
if (read_count > 0) {
flip = 1;
- read_room = tty_buffer_request_room(tty, read_count);
- tty_insert_flip_string(tty, ch, read_room);
+ read_room = tty_insert_flip_string(tty, ch, read_count);
the_port->icount.rx += read_count;
}
spin_unlock_irqrestore(&the_port->lock, pflags);
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
index 108c3e0471fd..12cb5e446a4f 100644
--- a/drivers/serial/jsm/jsm_driver.c
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -179,6 +179,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device
return 0;
out_free_irq:
+ jsm_remove_uart_port(brd);
free_irq(brd->irq, brd);
out_iounmap:
iounmap(brd->re_map_membase);
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index cd95e215550d..5673ca9dfdc8 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -432,7 +432,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd)
int jsm_uart_port_init(struct jsm_board *brd)
{
- int i;
+ int i, rc;
unsigned int line;
struct jsm_channel *ch;
@@ -467,8 +467,11 @@ int jsm_uart_port_init(struct jsm_board *brd)
} else
set_bit(line, linemap);
brd->channels[i]->uart_port.line = line;
- if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port))
- printk(KERN_INFO "jsm: add device failed\n");
+ rc = uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port);
+ if (rc){
+ printk(KERN_INFO "jsm: Port %d failed. Aborting...\n", i);
+ return rc;
+ }
else
printk(KERN_INFO "jsm: Port %d added\n", i);
}
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 7ce9e9f567a3..3119fddaedb5 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -74,6 +74,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/clk.h>
#include <asm/mpc52xx.h>
#include <asm/mpc52xx_psc.h>
@@ -113,6 +114,7 @@ static void mpc52xx_uart_of_enumerate(void);
/* Forward declaration of the interruption handling routine */
static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id);
+static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port);
/* Simple macro to test if a port is console or not. This one is taken
@@ -145,6 +147,11 @@ struct psc_ops {
void (*cw_disable_ints)(struct uart_port *port);
void (*cw_restore_ints)(struct uart_port *port);
unsigned long (*getuartclk)(void *p);
+ int (*clock)(struct uart_port *port, int enable);
+ int (*fifoc_init)(void);
+ void (*fifoc_uninit)(void);
+ void (*get_irq)(struct uart_port *, struct device_node *);
+ irqreturn_t (*handle_irq)(struct uart_port *port);
};
#ifdef CONFIG_PPC_MPC52xx
@@ -256,6 +263,18 @@ static unsigned long mpc52xx_getuartclk(void *p)
return mpc5xxx_get_bus_frequency(p) / 2;
}
+static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
+{
+ port->irqflags = IRQF_DISABLED;
+ port->irq = irq_of_parse_and_map(np, 0);
+}
+
+/* 52xx specific interrupt handler. The caller holds the port lock */
+static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port)
+{
+ return mpc5xxx_uart_process_int(port);
+}
+
static struct psc_ops mpc52xx_psc_ops = {
.fifo_init = mpc52xx_psc_fifo_init,
.raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
@@ -273,14 +292,32 @@ static struct psc_ops mpc52xx_psc_ops = {
.cw_disable_ints = mpc52xx_psc_cw_disable_ints,
.cw_restore_ints = mpc52xx_psc_cw_restore_ints,
.getuartclk = mpc52xx_getuartclk,
+ .get_irq = mpc52xx_psc_get_irq,
+ .handle_irq = mpc52xx_psc_handle_irq,
};
#endif /* CONFIG_MPC52xx */
#ifdef CONFIG_PPC_MPC512x
#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
+
+/* PSC FIFO Controller for mpc512x */
+struct psc_fifoc {
+ u32 fifoc_cmd;
+ u32 fifoc_int;
+ u32 fifoc_dma;
+ u32 fifoc_axe;
+ u32 fifoc_debug;
+};
+
+static struct psc_fifoc __iomem *psc_fifoc;
+static unsigned int psc_fifoc_irq;
+
static void mpc512x_psc_fifo_init(struct uart_port *port)
{
+ /* /32 prescaler */
+ out_be16(&PSC(port)->mpc52xx_psc_clock_select, 0xdd00);
+
out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
out_be32(&FIFO_512x(port)->txalarm, 1);
@@ -393,6 +430,160 @@ static unsigned long mpc512x_getuartclk(void *p)
return mpc5xxx_get_bus_frequency(p);
}
+#define DEFAULT_FIFO_SIZE 16
+
+static unsigned int __init get_fifo_size(struct device_node *np,
+ char *fifo_name)
+{
+ const unsigned int *fp;
+
+ fp = of_get_property(np, fifo_name, NULL);
+ if (fp)
+ return *fp;
+
+ pr_warning("no %s property in %s node, defaulting to %d\n",
+ fifo_name, np->full_name, DEFAULT_FIFO_SIZE);
+
+ return DEFAULT_FIFO_SIZE;
+}
+
+#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
+ ((u32)(_base) + sizeof(struct mpc52xx_psc)))
+
+/* Init PSC FIFO Controller */
+static int __init mpc512x_psc_fifoc_init(void)
+{
+ struct device_node *np;
+ void __iomem *psc;
+ unsigned int tx_fifo_size;
+ unsigned int rx_fifo_size;
+ int fifobase = 0; /* current fifo address in 32 bit words */
+
+ np = of_find_compatible_node(NULL, NULL,
+ "fsl,mpc5121-psc-fifo");
+ if (!np) {
+ pr_err("%s: Can't find FIFOC node\n", __func__);
+ return -ENODEV;
+ }
+
+ psc_fifoc = of_iomap(np, 0);
+ if (!psc_fifoc) {
+ pr_err("%s: Can't map FIFOC\n", __func__);
+ return -ENODEV;
+ }
+
+ psc_fifoc_irq = irq_of_parse_and_map(np, 0);
+ of_node_put(np);
+ if (psc_fifoc_irq == NO_IRQ) {
+ pr_err("%s: Can't get FIFOC irq\n", __func__);
+ iounmap(psc_fifoc);
+ return -ENODEV;
+ }
+
+ for_each_compatible_node(np, NULL, "fsl,mpc5121-psc-uart") {
+ tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size");
+ rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size");
+
+ /* size in register is in 4 byte units */
+ tx_fifo_size /= 4;
+ rx_fifo_size /= 4;
+ if (!tx_fifo_size)
+ tx_fifo_size = 1;
+ if (!rx_fifo_size)
+ rx_fifo_size = 1;
+
+ psc = of_iomap(np, 0);
+ if (!psc) {
+ pr_err("%s: Can't map %s device\n",
+ __func__, np->full_name);
+ continue;
+ }
+
+ /* FIFO space is 4KiB, check if requested size is available */
+ if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) {
+ pr_err("%s: no fifo space available for %s\n",
+ __func__, np->full_name);
+ iounmap(psc);
+ /*
+ * chances are that another device requests less
+ * fifo space, so we continue.
+ */
+ continue;
+ }
+ /* set tx and rx fifo size registers */
+ out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size);
+ fifobase += tx_fifo_size;
+ out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size);
+ fifobase += rx_fifo_size;
+
+ /* reset and enable the slices */
+ out_be32(&FIFOC(psc)->txcmd, 0x80);
+ out_be32(&FIFOC(psc)->txcmd, 0x01);
+ out_be32(&FIFOC(psc)->rxcmd, 0x80);
+ out_be32(&FIFOC(psc)->rxcmd, 0x01);
+
+ iounmap(psc);
+ }
+
+ return 0;
+}
+
+static void __exit mpc512x_psc_fifoc_uninit(void)
+{
+ iounmap(psc_fifoc);
+}
+
+/* 512x specific interrupt handler. The caller holds the port lock */
+static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
+{
+ unsigned long fifoc_int;
+ int psc_num;
+
+ /* Read pending PSC FIFOC interrupts */
+ fifoc_int = in_be32(&psc_fifoc->fifoc_int);
+
+ /* Check if it is an interrupt for this port */
+ psc_num = (port->mapbase & 0xf00) >> 8;
+ if (test_bit(psc_num, &fifoc_int) ||
+ test_bit(psc_num + 16, &fifoc_int))
+ return mpc5xxx_uart_process_int(port);
+
+ return IRQ_NONE;
+}
+
+static int mpc512x_psc_clock(struct uart_port *port, int enable)
+{
+ struct clk *psc_clk;
+ int psc_num;
+ char clk_name[10];
+
+ if (uart_console(port))
+ return 0;
+
+ psc_num = (port->mapbase & 0xf00) >> 8;
+ snprintf(clk_name, sizeof(clk_name), "psc%d_clk", psc_num);
+ psc_clk = clk_get(port->dev, clk_name);
+ if (IS_ERR(psc_clk)) {
+ dev_err(port->dev, "Failed to get PSC clock entry!\n");
+ return -ENODEV;
+ }
+
+ dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis");
+
+ if (enable)
+ clk_enable(psc_clk);
+ else
+ clk_disable(psc_clk);
+
+ return 0;
+}
+
+static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np)
+{
+ port->irqflags = IRQF_SHARED;
+ port->irq = psc_fifoc_irq;
+}
+
static struct psc_ops mpc512x_psc_ops = {
.fifo_init = mpc512x_psc_fifo_init,
.raw_rx_rdy = mpc512x_psc_raw_rx_rdy,
@@ -410,6 +601,11 @@ static struct psc_ops mpc512x_psc_ops = {
.cw_disable_ints = mpc512x_psc_cw_disable_ints,
.cw_restore_ints = mpc512x_psc_cw_restore_ints,
.getuartclk = mpc512x_getuartclk,
+ .clock = mpc512x_psc_clock,
+ .fifoc_init = mpc512x_psc_fifoc_init,
+ .fifoc_uninit = mpc512x_psc_fifoc_uninit,
+ .get_irq = mpc512x_psc_get_irq,
+ .handle_irq = mpc512x_psc_handle_irq,
};
#endif
@@ -519,10 +715,15 @@ mpc52xx_uart_startup(struct uart_port *port)
struct mpc52xx_psc __iomem *psc = PSC(port);
int ret;
+ if (psc_ops->clock) {
+ ret = psc_ops->clock(port, 1);
+ if (ret)
+ return ret;
+ }
+
/* Request IRQ */
ret = request_irq(port->irq, mpc52xx_uart_int,
- IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
- "mpc52xx_psc_uart", port);
+ port->irqflags, "mpc52xx_psc_uart", port);
if (ret)
return ret;
@@ -553,6 +754,9 @@ mpc52xx_uart_shutdown(struct uart_port *port)
port->read_status_mask = 0;
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+ if (psc_ops->clock)
+ psc_ops->clock(port, 0);
+
/* Release interrupt */
free_irq(port->irq, port);
}
@@ -851,15 +1055,12 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
}
static irqreturn_t
-mpc52xx_uart_int(int irq, void *dev_id)
+mpc5xxx_uart_process_int(struct uart_port *port)
{
- struct uart_port *port = dev_id;
unsigned long pass = ISR_PASS_LIMIT;
unsigned int keepgoing;
u8 status;
- spin_lock(&port->lock);
-
/* While we have stuff to do, we continue */
do {
/* If we don't find anything to do, we stop */
@@ -886,11 +1087,23 @@ mpc52xx_uart_int(int irq, void *dev_id)
} while (keepgoing);
- spin_unlock(&port->lock);
-
return IRQ_HANDLED;
}
+static irqreturn_t
+mpc52xx_uart_int(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ irqreturn_t ret;
+
+ spin_lock(&port->lock);
+
+ ret = psc_ops->handle_irq(port);
+
+ spin_unlock(&port->lock);
+
+ return ret;
+}
/* ======================================================================== */
/* Console ( if applicable ) */
@@ -1152,7 +1365,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
return -EINVAL;
}
- port->irq = irq_of_parse_and_map(op->node, 0);
+ psc_ops->get_irq(port, op->node);
if (port->irq == NO_IRQ) {
dev_dbg(&op->dev, "Could not get irq\n");
return -EINVAL;
@@ -1163,10 +1376,8 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
/* Add the port to the uart sub-system */
ret = uart_add_one_port(&mpc52xx_uart_driver, port);
- if (ret) {
- irq_dispose_mapping(port->irq);
+ if (ret)
return ret;
- }
dev_set_drvdata(&op->dev, (void *)port);
return 0;
@@ -1178,10 +1389,8 @@ mpc52xx_uart_of_remove(struct of_device *op)
struct uart_port *port = dev_get_drvdata(&op->dev);
dev_set_drvdata(&op->dev, NULL);
- if (port) {
+ if (port)
uart_remove_one_port(&mpc52xx_uart_driver, port);
- irq_dispose_mapping(port->irq);
- }
return 0;
}
@@ -1288,6 +1497,15 @@ mpc52xx_uart_init(void)
mpc52xx_uart_of_enumerate();
+ /*
+ * Map the PSC FIFO Controller and init if on MPC512x.
+ */
+ if (psc_ops->fifoc_init) {
+ ret = psc_ops->fifoc_init();
+ if (ret)
+ return ret;
+ }
+
ret = of_register_platform_driver(&mpc52xx_uart_of_driver);
if (ret) {
printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n",
@@ -1302,6 +1520,9 @@ mpc52xx_uart_init(void)
static void __exit
mpc52xx_uart_exit(void)
{
+ if (psc_ops->fifoc_uninit)
+ psc_ops->fifoc_uninit();
+
of_unregister_platform_driver(&mpc52xx_uart_of_driver);
uart_unregister_driver(&mpc52xx_uart_driver);
}
diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
index b05c5aa02cb4..ecdc0facf7ee 100644
--- a/drivers/serial/msm_serial.c
+++ b/drivers/serial/msm_serial.c
@@ -691,6 +691,7 @@ static int __init msm_serial_probe(struct platform_device *pdev)
struct msm_port *msm_port;
struct resource *resource;
struct uart_port *port;
+ int irq;
if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
return -ENXIO;
@@ -711,9 +712,10 @@ static int __init msm_serial_probe(struct platform_device *pdev)
return -ENXIO;
port->mapbase = resource->start;
- port->irq = platform_get_irq(pdev, 0);
- if (unlikely(port->irq < 0))
+ irq = platform_get_irq(pdev, 0);
+ if (unlikely(irq < 0))
return -ENXIO;
+ port->irq = irq;
platform_set_drvdata(pdev, port);
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 0700cd10b97c..f020de1cdd50 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -63,11 +63,17 @@
#include <asm/sections.h>
#include <asm/io.h>
#include <asm/irq.h>
+
+#ifdef CONFIG_PPC_PMAC
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/dbdma.h>
#include <asm/macio.h>
+#else
+#include <linux/platform_device.h>
+#define of_machine_is_compatible(x) (0)
+#endif
#if defined (CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -83,11 +89,9 @@
static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("Driver for the PowerMac serial ports.");
+MODULE_DESCRIPTION("Driver for the Mac and PowerMac serial ports.");
MODULE_LICENSE("GPL");
-#define PWRDBG(fmt, arg...) printk(KERN_DEBUG fmt , ## arg)
-
#ifdef CONFIG_SERIAL_PMACZILOG_TTYS
#define PMACZILOG_MAJOR TTY_MAJOR
#define PMACZILOG_MINOR 64
@@ -153,8 +157,8 @@ static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 *regs)
write_zsreg(uap, R10, regs[R10]);
/* Set TX/RX controls sans the enable bits. */
- write_zsreg(uap, R3, regs[R3] & ~RxENABLE);
- write_zsreg(uap, R5, regs[R5] & ~TxENABLE);
+ write_zsreg(uap, R3, regs[R3] & ~RxENABLE);
+ write_zsreg(uap, R5, regs[R5] & ~TxENABLE);
/* now set R7 "prime" on ESCC */
write_zsreg(uap, R15, regs[R15] | EN85C30);
@@ -205,7 +209,7 @@ static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 *regs)
*/
static void pmz_maybe_update_regs(struct uart_pmac_port *uap)
{
- if (!ZS_REGS_HELD(uap)) {
+ if (!ZS_REGS_HELD(uap)) {
if (ZS_TX_ACTIVE(uap)) {
uap->flags |= PMACZILOG_FLAG_REGS_HELD;
} else {
@@ -281,7 +285,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
spin_lock(&uap->port.lock);
if (swallow)
goto next_char;
- }
+ }
#endif /* CONFIG_MAGIC_SYSRQ && CONFIG_SERIAL_CORE_CONSOLE */
/* A real serial line, record the character and status. */
@@ -317,7 +321,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
if (uap->port.ignore_status_mask == 0xff ||
(r1 & uap->port.ignore_status_mask) == 0) {
- tty_insert_flip_char(tty, ch, flag);
+ tty_insert_flip_char(tty, ch, flag);
}
if (r1 & Rx_OVR)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
@@ -341,7 +345,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
write_zsreg(uap, R1, uap->curregs[R1]);
zssync(uap);
- dev_err(&uap->dev->ofdev.dev, "pmz: rx irq flood !\n");
+ pmz_error("pmz: rx irq flood !\n");
return tty;
}
@@ -411,6 +415,17 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap)
goto ack_tx_int;
}
+ /* Under some circumstances, we see interrupts reported for
+ * a closed channel. The interrupt mask in R1 is clear, but
+ * R3 still signals the interrupts and we see them when taking
+ * an interrupt for the other channel (this could be a qemu
+ * bug but since the ESCC doc doesn't specify precsiely whether
+ * R3 interrup status bits are masked by R1 interrupt enable
+ * bits, better safe than sorry). --BenH.
+ */
+ if (!ZS_IS_OPEN(uap))
+ goto ack_tx_int;
+
if (uap->port.x_char) {
uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
write_zsdata(uap, uap->port.x_char);
@@ -459,47 +474,47 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
uap_a = pmz_get_port_A(uap);
uap_b = uap_a->mate;
-
- spin_lock(&uap_a->port.lock);
+
+ spin_lock(&uap_a->port.lock);
r3 = read_zsreg(uap_a, R3);
#ifdef DEBUG_HARD
pmz_debug("irq, r3: %x\n", r3);
#endif
- /* Channel A */
+ /* Channel A */
tty = NULL;
- if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
+ if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
write_zsreg(uap_a, R0, RES_H_IUS);
zssync(uap_a);
- if (r3 & CHAEXT)
- pmz_status_handle(uap_a);
+ if (r3 & CHAEXT)
+ pmz_status_handle(uap_a);
if (r3 & CHARxIP)
tty = pmz_receive_chars(uap_a);
- if (r3 & CHATxIP)
- pmz_transmit_chars(uap_a);
- rc = IRQ_HANDLED;
- }
- spin_unlock(&uap_a->port.lock);
+ if (r3 & CHATxIP)
+ pmz_transmit_chars(uap_a);
+ rc = IRQ_HANDLED;
+ }
+ spin_unlock(&uap_a->port.lock);
if (tty != NULL)
tty_flip_buffer_push(tty);
if (uap_b->node == NULL)
goto out;
- spin_lock(&uap_b->port.lock);
+ spin_lock(&uap_b->port.lock);
tty = NULL;
if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
write_zsreg(uap_b, R0, RES_H_IUS);
zssync(uap_b);
- if (r3 & CHBEXT)
- pmz_status_handle(uap_b);
- if (r3 & CHBRxIP)
- tty = pmz_receive_chars(uap_b);
- if (r3 & CHBTxIP)
- pmz_transmit_chars(uap_b);
- rc = IRQ_HANDLED;
- }
- spin_unlock(&uap_b->port.lock);
+ if (r3 & CHBEXT)
+ pmz_status_handle(uap_b);
+ if (r3 & CHBRxIP)
+ tty = pmz_receive_chars(uap_b);
+ if (r3 & CHBTxIP)
+ pmz_transmit_chars(uap_b);
+ rc = IRQ_HANDLED;
+ }
+ spin_unlock(&uap_b->port.lock);
if (tty != NULL)
tty_flip_buffer_push(tty);
@@ -707,7 +722,7 @@ static void pmz_enable_ms(struct uart_port *port)
if (ZS_IS_ASLEEP(uap))
return;
- /* NOTE: Not subject to 'transmitter active' rule. */
+ /* NOTE: Not subject to 'transmitter active' rule. */
write_zsreg(uap, R15, uap->curregs[R15]);
}
}
@@ -737,7 +752,7 @@ static void pmz_break_ctl(struct uart_port *port, int break_state)
if (new_reg != uap->curregs[R5]) {
uap->curregs[R5] = new_reg;
- /* NOTE: Not subject to 'transmitter active' rule. */
+ /* NOTE: Not subject to 'transmitter active' rule. */
if (ZS_IS_ASLEEP(uap))
return;
write_zsreg(uap, R5, uap->curregs[R5]);
@@ -746,6 +761,8 @@ static void pmz_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&port->lock, flags);
}
+#ifdef CONFIG_PPC_PMAC
+
/*
* Turn power on or off to the SCC and associated stuff
* (port drivers, modem, IR port, etc.)
@@ -781,6 +798,15 @@ static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
return delay;
}
+#else
+
+static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
+{
+ return 0;
+}
+
+#endif /* !CONFIG_PPC_PMAC */
+
/*
* FixZeroBug....Works around a bug in the SCC receving channel.
* Inspired from Darwin code, 15 Sept. 2000 -DanM
@@ -897,7 +923,6 @@ static int __pmz_startup(struct uart_pmac_port *uap)
/* Remember status for DCD/CTS changes */
uap->prev_status = read_zsreg(uap, R0);
-
return pwr_delay;
}
@@ -944,9 +969,9 @@ static int pmz_startup(struct uart_port *port)
}
pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
- if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, "PowerMac Zilog", uap)) {
- dev_err(&uap->dev->ofdev.dev,
- "Unable to register zs interrupt handler.\n");
+ if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED,
+ "SCC", uap)) {
+ pmz_error("Unable to register zs interrupt handler.\n");
pmz_set_scc_power(uap, 0);
mutex_unlock(&pmz_irq_mutex);
return -ENXIO;
@@ -972,7 +997,7 @@ static int pmz_startup(struct uart_port *port)
if (!ZS_IS_EXTCLK(uap))
uap->curregs[R1] |= EXT_INT_ENAB;
write_zsreg(uap, R1, uap->curregs[R1]);
- spin_unlock_irqrestore(&port->lock, flags);
+ spin_unlock_irqrestore(&port->lock, flags);
pmz_debug("pmz: startup() done.\n");
@@ -992,7 +1017,7 @@ static void pmz_shutdown(struct uart_port *port)
mutex_lock(&pmz_irq_mutex);
/* Release interrupt handler */
- free_irq(uap->port.irq, uap);
+ free_irq(uap->port.irq, uap);
spin_lock_irqsave(&port->lock, flags);
@@ -1040,7 +1065,6 @@ static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag,
{
int brg;
-
/* Switch to external clocking for IrDA high clock rates. That
* code could be re-used for Midi interfaces with different
* multipliers
@@ -1187,7 +1211,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0
|| (read_zsreg(uap, R1) & ALL_SNT) == 0) {
if (--t <= 0) {
- dev_err(&uap->dev->ofdev.dev, "transmitter didn't drain\n");
+ pmz_error("transmitter didn't drain\n");
return;
}
udelay(10);
@@ -1203,7 +1227,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
read_zsdata(uap);
mdelay(10);
if (--t <= 0) {
- dev_err(&uap->dev->ofdev.dev, "receiver didn't drain\n");
+ pmz_error("receiver didn't drain\n");
return;
}
}
@@ -1212,20 +1236,19 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
uap->curregs[R5] |= DTR;
write_zsreg(uap, R5, uap->curregs[R5]);
zssync(uap);
- mdelay(1);
+ mdelay(1);
/* Switch SCC to 19200 */
pmz_convert_to_zs(uap, CS8, 0, 19200);
pmz_load_zsregs(uap, uap->curregs);
- mdelay(1);
+ mdelay(1);
/* Write get_version command byte */
write_zsdata(uap, 1);
t = 5000;
while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
if (--t <= 0) {
- dev_err(&uap->dev->ofdev.dev,
- "irda_setup timed out on get_version byte\n");
+ pmz_error("irda_setup timed out on get_version byte\n");
goto out;
}
udelay(10);
@@ -1233,8 +1256,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
version = read_zsdata(uap);
if (version < 4) {
- dev_info(&uap->dev->ofdev.dev, "IrDA: dongle version %d not supported\n",
- version);
+ pmz_info("IrDA: dongle version %d not supported\n", version);
goto out;
}
@@ -1243,18 +1265,16 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
t = 5000;
while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
if (--t <= 0) {
- dev_err(&uap->dev->ofdev.dev,
- "irda_setup timed out on speed mode byte\n");
+ pmz_error("irda_setup timed out on speed mode byte\n");
goto out;
}
udelay(10);
}
t = read_zsdata(uap);
if (t != cmdbyte)
- dev_err(&uap->dev->ofdev.dev,
- "irda_setup speed mode byte = %x (%x)\n", t, cmdbyte);
+ pmz_error("irda_setup speed mode byte = %x (%x)\n", t, cmdbyte);
- dev_info(&uap->dev->ofdev.dev, "IrDA setup for %ld bps, dongle version: %d\n",
+ pmz_info("IrDA setup for %ld bps, dongle version: %d\n",
*baud, version);
(void)read_zsdata(uap);
@@ -1404,7 +1424,7 @@ static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
write_zsdata(uap, c);
}
-#endif
+#endif /* CONFIG_CONSOLE_POLL */
static struct uart_ops pmz_pops = {
.tx_empty = pmz_tx_empty,
@@ -1429,6 +1449,8 @@ static struct uart_ops pmz_pops = {
#endif
};
+#ifdef CONFIG_PPC_PMAC
+
/*
* Setup one port structure after probing, HW is down at this point,
* Unlike sunzilog, we don't need to pre-init the spinlock as we don't
@@ -1452,7 +1474,7 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
return -ENODEV;
uap->port.mapbase = r_ports.start;
uap->port.membase = ioremap(uap->port.mapbase, 0x1000);
-
+
uap->control_reg = uap->port.membase;
uap->data_reg = uap->control_reg + 0x10;
@@ -1579,7 +1601,7 @@ static void pmz_dispose_port(struct uart_pmac_port *uap)
}
/*
- * Called upon match with an escc node in the devive-tree.
+ * Called upon match with an escc node in the device-tree.
*/
static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
{
@@ -1801,7 +1823,7 @@ static int __init pmz_probe(void)
pmz_ports[count].node = node_a;
pmz_ports[count+1].node = node_b;
pmz_ports[count].port.line = count;
- pmz_ports[count+1].port.line = count+1;
+ pmz_ports[count+1].port.line = count+1;
/*
* Setup the ports for real
@@ -1825,6 +1847,88 @@ next:
return 0;
}
+#else
+
+extern struct platform_device scc_a_pdev, scc_b_pdev;
+
+static int __init pmz_init_port(struct uart_pmac_port *uap)
+{
+ struct resource *r_ports;
+ int irq;
+
+ r_ports = platform_get_resource(uap->node, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(uap->node, 0);
+ if (!r_ports || !irq)
+ return -ENODEV;
+
+ uap->port.mapbase = r_ports->start;
+ uap->port.membase = (unsigned char __iomem *) r_ports->start;
+ uap->port.iotype = UPIO_MEM;
+ uap->port.irq = irq;
+ uap->port.uartclk = ZS_CLOCK;
+ uap->port.fifosize = 1;
+ uap->port.ops = &pmz_pops;
+ uap->port.type = PORT_PMAC_ZILOG;
+ uap->port.flags = 0;
+
+ uap->control_reg = uap->port.membase;
+ uap->data_reg = uap->control_reg + 4;
+ uap->port_type = 0;
+
+ pmz_convert_to_zs(uap, CS8, 0, 9600);
+
+ return 0;
+}
+
+static int __init pmz_probe(void)
+{
+ int err;
+
+ pmz_ports_count = 0;
+
+ pmz_ports[0].mate = &pmz_ports[1];
+ pmz_ports[0].port.line = 0;
+ pmz_ports[0].flags = PMACZILOG_FLAG_IS_CHANNEL_A;
+ pmz_ports[0].node = &scc_a_pdev;
+ err = pmz_init_port(&pmz_ports[0]);
+ if (err)
+ return err;
+ pmz_ports_count++;
+
+ pmz_ports[1].mate = &pmz_ports[0];
+ pmz_ports[1].port.line = 1;
+ pmz_ports[1].flags = 0;
+ pmz_ports[1].node = &scc_b_pdev;
+ err = pmz_init_port(&pmz_ports[1]);
+ if (err)
+ return err;
+ pmz_ports_count++;
+
+ return 0;
+}
+
+static void pmz_dispose_port(struct uart_pmac_port *uap)
+{
+ memset(uap, 0, sizeof(struct uart_pmac_port));
+}
+
+static int __init pmz_attach(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < pmz_ports_count; i++)
+ if (pmz_ports[i].node == pdev)
+ return 0;
+ return -ENODEV;
+}
+
+static int __exit pmz_detach(struct platform_device *pdev)
+{
+ return 0;
+}
+
+#endif /* !CONFIG_PPC_PMAC */
+
#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
static void pmz_console_write(struct console *con, const char *s, unsigned int count);
@@ -1885,28 +1989,41 @@ err_out:
return rc;
}
+#ifdef CONFIG_PPC_PMAC
+
static struct of_device_id pmz_match[] =
{
{
- .name = "ch-a",
+ .name = "ch-a",
},
{
- .name = "ch-b",
+ .name = "ch-b",
},
{},
};
MODULE_DEVICE_TABLE (of, pmz_match);
-static struct macio_driver pmz_driver =
-{
+static struct macio_driver pmz_driver = {
.name = "pmac_zilog",
.match_table = pmz_match,
.probe = pmz_attach,
.remove = pmz_detach,
.suspend = pmz_suspend,
- .resume = pmz_resume,
+ .resume = pmz_resume,
};
+#else
+
+static struct platform_driver pmz_driver = {
+ .remove = __exit_p(pmz_detach),
+ .driver = {
+ .name = "scc",
+ .owner = THIS_MODULE,
+ },
+};
+
+#endif /* !CONFIG_PPC_PMAC */
+
static int __init init_pmz(void)
{
int rc, i;
@@ -1941,19 +2058,27 @@ static int __init init_pmz(void)
pmz_dispose_port(&pmz_ports[i]);
return rc;
}
-
+
/*
* Then we register the macio driver itself
*/
+#ifdef CONFIG_PPC_PMAC
return macio_register_driver(&pmz_driver);
+#else
+ return platform_driver_probe(&pmz_driver, pmz_attach);
+#endif
}
static void __exit exit_pmz(void)
{
int i;
+#ifdef CONFIG_PPC_PMAC
/* Get rid of macio-driver (detach from macio) */
macio_unregister_driver(&pmz_driver);
+#else
+ platform_driver_unregister(&pmz_driver);
+#endif
for (i = 0; i < pmz_ports_count; i++) {
struct uart_pmac_port *uport = &pmz_ports[i];
@@ -2020,10 +2145,10 @@ static int __init pmz_console_setup(struct console *co, char *options)
/*
* XServe's default to 57600 bps
*/
- if (machine_is_compatible("RackMac1,1")
- || machine_is_compatible("RackMac1,2")
- || machine_is_compatible("MacRISC4"))
- baud = 57600;
+ if (of_machine_is_compatible("RackMac1,1")
+ || of_machine_is_compatible("RackMac1,2")
+ || of_machine_is_compatible("MacRISC4"))
+ baud = 57600;
/*
* Check whether an invalid uart number has been specified, and
diff --git a/drivers/serial/pmac_zilog.h b/drivers/serial/pmac_zilog.h
index f6e77f12acd5..cbc34fbb1b20 100644
--- a/drivers/serial/pmac_zilog.h
+++ b/drivers/serial/pmac_zilog.h
@@ -1,7 +1,15 @@
#ifndef __PMAC_ZILOG_H__
#define __PMAC_ZILOG_H__
-#define pmz_debug(fmt,arg...) dev_dbg(&uap->dev->ofdev.dev, fmt, ## arg)
+#ifdef CONFIG_PPC_PMAC
+#define pmz_debug(fmt, arg...) dev_dbg(&uap->dev->ofdev.dev, fmt, ## arg)
+#define pmz_error(fmt, arg...) dev_err(&uap->dev->ofdev.dev, fmt, ## arg)
+#define pmz_info(fmt, arg...) dev_info(&uap->dev->ofdev.dev, fmt, ## arg)
+#else
+#define pmz_debug(fmt, arg...) dev_dbg(&uap->node->dev, fmt, ## arg)
+#define pmz_error(fmt, arg...) dev_err(&uap->node->dev, fmt, ## arg)
+#define pmz_info(fmt, arg...) dev_info(&uap->node->dev, fmt, ## arg)
+#endif
/*
* At most 2 ESCCs with 2 ports each
@@ -17,6 +25,7 @@ struct uart_pmac_port {
struct uart_port port;
struct uart_pmac_port *mate;
+#ifdef CONFIG_PPC_PMAC
/* macio_dev for the escc holding this port (maybe be null on
* early inited port)
*/
@@ -25,6 +34,9 @@ struct uart_pmac_port {
* of "escc" node (ie. ch-a or ch-b)
*/
struct device_node *node;
+#else
+ struct platform_device *node;
+#endif
/* Port type as obtained from device tree (IRDA, modem, ...) */
int port_type;
@@ -55,10 +67,12 @@ struct uart_pmac_port {
volatile u8 __iomem *control_reg;
volatile u8 __iomem *data_reg;
+#ifdef CONFIG_PPC_PMAC
unsigned int tx_dma_irq;
unsigned int rx_dma_irq;
volatile struct dbdma_regs __iomem *tx_dma_regs;
volatile struct dbdma_regs __iomem *rx_dma_regs;
+#endif
struct ktermios termios_cache;
};
@@ -113,7 +127,7 @@ static inline void zssync(struct uart_pmac_port *port)
#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */
+#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */
/* The Zilog register set */
@@ -171,7 +185,7 @@ static inline void zssync(struct uart_pmac_port *port)
/* Write Register 3 */
-#define RxENABLE 0x1 /* Rx Enable */
+#define RxENABLE 0x1 /* Rx Enable */
#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
@@ -185,7 +199,7 @@ static inline void zssync(struct uart_pmac_port *port)
/* Write Register 4 */
-#define PAR_ENAB 0x1 /* Parity Enable */
+#define PAR_ENAB 0x1 /* Parity Enable */
#define PAR_EVEN 0x2 /* Parity Even/Odd* */
#define SYNC_ENAB 0 /* Sync Modes Enable */
@@ -210,7 +224,7 @@ static inline void zssync(struct uart_pmac_port *port)
#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
#define RTS 0x2 /* RTS */
#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
-#define TxENABLE 0x8 /* Tx Enable */
+#define TxENABLE 0x8 /* Tx Enable */
#define SND_BRK 0x10 /* Send Break */
#define Tx5 0x0 /* Tx 5 bits (or less)/character */
#define Tx7 0x20 /* Tx 7 bits/character */
@@ -372,11 +386,11 @@ static inline void zssync(struct uart_pmac_port *port)
#define ZS_TX_ACTIVE(UP) ((UP)->flags & PMACZILOG_FLAG_TX_ACTIVE)
#define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & PMACZILOG_FLAG_MODEM_STATUS)
#define ZS_IS_IRDA(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRDA)
-#define ZS_IS_INTMODEM(UP) ((UP)->flags & PMACZILOG_FLAG_IS_INTMODEM)
+#define ZS_IS_INTMODEM(UP) ((UP)->flags & PMACZILOG_FLAG_IS_INTMODEM)
#define ZS_HAS_DMA(UP) ((UP)->flags & PMACZILOG_FLAG_HAS_DMA)
-#define ZS_IS_ASLEEP(UP) ((UP)->flags & PMACZILOG_FLAG_IS_ASLEEP)
-#define ZS_IS_OPEN(UP) ((UP)->flags & PMACZILOG_FLAG_IS_OPEN)
-#define ZS_IS_IRQ_ON(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRQ_ON)
-#define ZS_IS_EXTCLK(UP) ((UP)->flags & PMACZILOG_FLAG_IS_EXTCLK)
+#define ZS_IS_ASLEEP(UP) ((UP)->flags & PMACZILOG_FLAG_IS_ASLEEP)
+#define ZS_IS_OPEN(UP) ((UP)->flags & PMACZILOG_FLAG_IS_OPEN)
+#define ZS_IS_IRQ_ON(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRQ_ON)
+#define ZS_IS_EXTCLK(UP) ((UP)->flags & PMACZILOG_FLAG_IS_EXTCLK)
#endif /* __PMAC_ZILOG_H__ */
diff --git a/drivers/serial/s3c2412.c b/drivers/serial/s3c2412.c
index ce75e28e36ef..1700b1a2fb7e 100644
--- a/drivers/serial/s3c2412.c
+++ b/drivers/serial/s3c2412.c
@@ -102,6 +102,7 @@ static struct s3c24xx_uart_info s3c2412_uart_inf = {
.name = "Samsung S3C2412 UART",
.type = PORT_S3C2412,
.fifosize = 64,
+ .has_divslot = 1,
.rx_fifomask = S3C2440_UFSTAT_RXMASK,
.rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
.rx_fifofull = S3C2440_UFSTAT_RXFULL,
diff --git a/drivers/serial/s5pv210.c b/drivers/serial/s5pv210.c
new file mode 100644
index 000000000000..8dc03837617b
--- /dev/null
+++ b/drivers/serial/s5pv210.c
@@ -0,0 +1,154 @@
+/* linux/drivers/serial/s5pv210.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Based on drivers/serial/s3c6400.c
+ *
+ * Driver for Samsung S5PV210 SoC UARTs.
+ *
+ * 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/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <plat/regs-serial.h>
+#include "samsung.h"
+
+static int s5pv210_serial_setsource(struct uart_port *port,
+ struct s3c24xx_uart_clksrc *clk)
+{
+ unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+ if (strcmp(clk->name, "pclk") == 0)
+ ucon &= ~S5PV210_UCON_CLKMASK;
+ else if (strcmp(clk->name, "uclk1") == 0)
+ ucon |= S5PV210_UCON_CLKMASK;
+ else {
+ printk(KERN_ERR "unknown clock source %s\n", clk->name);
+ return -EINVAL;
+ }
+
+ wr_regl(port, S3C2410_UCON, ucon);
+ return 0;
+}
+
+
+static int s5pv210_serial_getsource(struct uart_port *port,
+ struct s3c24xx_uart_clksrc *clk)
+{
+ u32 ucon = rd_regl(port, S3C2410_UCON);
+
+ clk->divisor = 1;
+
+ switch (ucon & S5PV210_UCON_CLKMASK) {
+ case S5PV210_UCON_PCLK:
+ clk->name = "pclk";
+ break;
+ case S5PV210_UCON_UCLK:
+ clk->name = "uclk1";
+ break;
+ }
+
+ return 0;
+}
+
+static int s5pv210_serial_resetport(struct uart_port *port,
+ struct s3c2410_uartcfg *cfg)
+{
+ unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+ ucon &= S5PV210_UCON_CLKMASK;
+ wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
+ wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+ /* reset both fifos */
+ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+ wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+ return 0;
+}
+
+#define S5PV210_UART_DEFAULT_INFO(fifo_size) \
+ .name = "Samsung S5PV210 UART0", \
+ .type = PORT_S3C6400, \
+ .fifosize = fifo_size, \
+ .has_divslot = 1, \
+ .rx_fifomask = S5PV210_UFSTAT_RXMASK, \
+ .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, \
+ .rx_fifofull = S5PV210_UFSTAT_RXFULL, \
+ .tx_fifofull = S5PV210_UFSTAT_TXFULL, \
+ .tx_fifomask = S5PV210_UFSTAT_TXMASK, \
+ .tx_fifoshift = S5PV210_UFSTAT_TXSHIFT, \
+ .get_clksrc = s5pv210_serial_getsource, \
+ .set_clksrc = s5pv210_serial_setsource, \
+ .reset_port = s5pv210_serial_resetport
+
+static struct s3c24xx_uart_info s5p_port_fifo256 = {
+ S5PV210_UART_DEFAULT_INFO(256),
+};
+
+static struct s3c24xx_uart_info s5p_port_fifo64 = {
+ S5PV210_UART_DEFAULT_INFO(64),
+};
+
+static struct s3c24xx_uart_info s5p_port_fifo16 = {
+ S5PV210_UART_DEFAULT_INFO(16),
+};
+
+static struct s3c24xx_uart_info *s5p_uart_inf[] = {
+ [0] = &s5p_port_fifo256,
+ [1] = &s5p_port_fifo64,
+ [2] = &s5p_port_fifo16,
+ [3] = &s5p_port_fifo16,
+};
+
+/* device management */
+static int s5p_serial_probe(struct platform_device *pdev)
+{
+ return s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id]);
+}
+
+static struct platform_driver s5p_serial_drv = {
+ .probe = s5p_serial_probe,
+ .remove = __devexit_p(s3c24xx_serial_remove),
+ .driver = {
+ .name = "s5pv210-uart",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s5pv210_serial_console_init(void)
+{
+ return s3c24xx_serial_initconsole(&s5p_serial_drv, s5p_uart_inf);
+}
+
+console_initcall(s5pv210_serial_console_init);
+
+static int __init s5p_serial_init(void)
+{
+ return s3c24xx_serial_init(&s5p_serial_drv, *s5p_uart_inf);
+}
+
+static void __exit s5p_serial_exit(void)
+{
+ platform_driver_unregister(&s5p_serial_drv);
+}
+
+module_init(s5p_serial_init);
+module_exit(s5p_serial_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s5pv210-uart");
+MODULE_DESCRIPTION("Samsung S5PV210 UART Driver support");
+MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c
index 52e3df113ec0..a9d6c5626a0a 100644
--- a/drivers/serial/samsung.c
+++ b/drivers/serial/samsung.c
@@ -1271,7 +1271,7 @@ s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
unsigned long ufstat, utrstat;
if (ufcon & S3C2410_UFCON_FIFOMODE) {
- /* fifo mode - check ammount of data in fifo registers... */
+ /* fifo mode - check amount of data in fifo registers... */
ufstat = rd_regl(port, S3C2410_UFSTAT);
return (ufstat & info->tx_fifofull) ? 0 : 1;
@@ -1374,7 +1374,7 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
* data.
*/
-static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info *info)
+static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
{
struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
struct platform_device **platdev_ptr;
@@ -1385,7 +1385,7 @@ static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info *info)
platdev_ptr = s3c24xx_uart_devs;
for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
- s3c24xx_serial_init_port(ptr, info, *platdev_ptr);
+ s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
}
return 0;
@@ -1451,7 +1451,7 @@ static struct console s3c24xx_serial_console = {
};
int s3c24xx_serial_initconsole(struct platform_driver *drv,
- struct s3c24xx_uart_info *info)
+ struct s3c24xx_uart_info **info)
{
struct platform_device *dev = s3c24xx_uart_devs[0];
diff --git a/drivers/serial/samsung.h b/drivers/serial/samsung.h
index 1fb22343df42..0ac06a07d25f 100644
--- a/drivers/serial/samsung.h
+++ b/drivers/serial/samsung.h
@@ -75,19 +75,24 @@ extern int s3c24xx_serial_probe(struct platform_device *dev,
extern int __devexit s3c24xx_serial_remove(struct platform_device *dev);
extern int s3c24xx_serial_initconsole(struct platform_driver *drv,
- struct s3c24xx_uart_info *uart);
+ struct s3c24xx_uart_info **uart);
extern int s3c24xx_serial_init(struct platform_driver *drv,
struct s3c24xx_uart_info *info);
#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
-#define s3c24xx_console_init(__drv, __inf) \
-static int __init s3c_serial_console_init(void) \
-{ \
- return s3c24xx_serial_initconsole(__drv, __inf); \
-} \
- \
+#define s3c24xx_console_init(__drv, __inf) \
+static int __init s3c_serial_console_init(void) \
+{ \
+ struct s3c24xx_uart_info *uinfo[CONFIG_SERIAL_SAMSUNG_UARTS]; \
+ int i; \
+ \
+ for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++) \
+ uinfo[i] = __inf; \
+ return s3c24xx_serial_initconsole(__drv, uinfo); \
+} \
+ \
console_initcall(s3c_serial_console_init)
#else
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 047530b285bb..7f2830709512 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -385,13 +385,20 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
}
/*
- * As a last resort, if the quotient is zero,
- * default to 9600 bps
+ * As a last resort, if the range cannot be met then clip to
+ * the nearest chip supported rate.
*/
- if (!hung_up)
- tty_termios_encode_baud_rate(termios, 9600, 9600);
+ if (!hung_up) {
+ if (baud <= min)
+ tty_termios_encode_baud_rate(termios,
+ min + 1, min + 1);
+ else
+ tty_termios_encode_baud_rate(termios,
+ max - 1, max - 1);
+ }
}
-
+ /* Should never happen */
+ WARN_ON(1);
return 0;
}
@@ -2006,12 +2013,6 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
mutex_lock(&port->mutex);
- if (!console_suspend_enabled && uart_console(uport)) {
- /* we're going to avoid suspending serial console */
- mutex_unlock(&port->mutex);
- return 0;
- }
-
tty_dev = device_find_child(uport->dev, &match, serial_match_port);
if (device_may_wakeup(tty_dev)) {
enable_irq_wake(uport->irq);
@@ -2019,20 +2020,23 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
mutex_unlock(&port->mutex);
return 0;
}
- uport->suspended = 1;
+ if (console_suspend_enabled || !uart_console(uport))
+ uport->suspended = 1;
if (port->flags & ASYNC_INITIALIZED) {
const struct uart_ops *ops = uport->ops;
int tries;
- set_bit(ASYNCB_SUSPENDED, &port->flags);
- clear_bit(ASYNCB_INITIALIZED, &port->flags);
+ if (console_suspend_enabled || !uart_console(uport)) {
+ set_bit(ASYNCB_SUSPENDED, &port->flags);
+ clear_bit(ASYNCB_INITIALIZED, &port->flags);
- spin_lock_irq(&uport->lock);
- ops->stop_tx(uport);
- ops->set_mctrl(uport, 0);
- ops->stop_rx(uport);
- spin_unlock_irq(&uport->lock);
+ spin_lock_irq(&uport->lock);
+ ops->stop_tx(uport);
+ ops->set_mctrl(uport, 0);
+ ops->stop_rx(uport);
+ spin_unlock_irq(&uport->lock);
+ }
/*
* Wait for the transmitter to empty.
@@ -2047,16 +2051,18 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
drv->dev_name,
drv->tty_driver->name_base + uport->line);
- ops->shutdown(uport);
+ if (console_suspend_enabled || !uart_console(uport))
+ ops->shutdown(uport);
}
/*
* Disable the console device before suspending.
*/
- if (uart_console(uport))
+ if (console_suspend_enabled && uart_console(uport))
console_stop(uport->cons);
- uart_change_pm(state, 3);
+ if (console_suspend_enabled || !uart_console(uport))
+ uart_change_pm(state, 3);
mutex_unlock(&port->mutex);
@@ -2073,29 +2079,6 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
mutex_lock(&port->mutex);
- if (!console_suspend_enabled && uart_console(uport)) {
- /* no need to resume serial console, it wasn't suspended */
- /*
- * First try to use the console cflag setting.
- */
- memset(&termios, 0, sizeof(struct ktermios));
- termios.c_cflag = uport->cons->cflag;
- /*
- * If that's unset, use the tty termios setting.
- */
- if (termios.c_cflag == 0)
- termios = *state->port.tty->termios;
- else {
- termios.c_ispeed = termios.c_ospeed =
- tty_termios_input_baud_rate(&termios);
- termios.c_ispeed = termios.c_ospeed =
- tty_termios_baud_rate(&termios);
- }
- uport->ops->set_termios(uport, &termios, NULL);
- mutex_unlock(&port->mutex);
- return 0;
- }
-
tty_dev = device_find_child(uport->dev, &match, serial_match_port);
if (!uport->suspended && device_may_wakeup(tty_dev)) {
disable_irq_wake(uport->irq);
@@ -2121,21 +2104,23 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
spin_lock_irq(&uport->lock);
ops->set_mctrl(uport, 0);
spin_unlock_irq(&uport->lock);
- ret = ops->startup(uport);
- if (ret == 0) {
- uart_change_speed(state, NULL);
- spin_lock_irq(&uport->lock);
- ops->set_mctrl(uport, uport->mctrl);
- ops->start_tx(uport);
- spin_unlock_irq(&uport->lock);
- set_bit(ASYNCB_INITIALIZED, &port->flags);
- } else {
- /*
- * Failed to resume - maybe hardware went away?
- * Clear the "initialized" flag so we won't try
- * to call the low level drivers shutdown method.
- */
- uart_shutdown(state);
+ if (console_suspend_enabled || !uart_console(uport)) {
+ ret = ops->startup(uport);
+ if (ret == 0) {
+ uart_change_speed(state, NULL);
+ spin_lock_irq(&uport->lock);
+ ops->set_mctrl(uport, uport->mctrl);
+ ops->start_tx(uport);
+ spin_unlock_irq(&uport->lock);
+ set_bit(ASYNCB_INITIALIZED, &port->flags);
+ } else {
+ /*
+ * Failed to resume - maybe hardware went away?
+ * Clear the "initialized" flag so we won't try
+ * to call the low level drivers shutdown method.
+ */
+ uart_shutdown(state);
+ }
}
clear_bit(ASYNCB_SUSPENDED, &port->flags);
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 0ee7239c5d69..e91db4b38012 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -146,7 +146,8 @@ static void quirk_wakeup_oxsemi(struct pcmcia_device *link)
{
struct serial_info *info = link->priv;
- outb(12, info->c950ctrl + 1);
+ if (info->c950ctrl)
+ outb(12, info->c950ctrl + 1);
}
/* request_region? oxsemi branch does no request_region too... */
@@ -695,11 +696,11 @@ static int serial_config(struct pcmcia_device * link)
info->multi = info->quirk->multi;
if (info->multi > 1)
- multi_config(link);
+ i = multi_config(link);
else
- simple_config(link);
+ i = simple_config(link);
- if (info->ndev == 0)
+ if (i || info->ndev == 0)
goto failed;
/*
@@ -714,6 +715,7 @@ static int serial_config(struct pcmcia_device * link)
return 0;
failed:
+ dev_warn(&link->dev, "serial_cs: failed to initialize\n");
serial_remove(link);
return -ENODEV;
}
@@ -757,6 +759,7 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0e01),
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05),
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101),
PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 37f0de9dd9ce..980f39449ee5 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -48,6 +48,9 @@
#include <linux/ctype.h>
#include <linux/err.h>
#include <linux/list.h>
+#include <linux/dmaengine.h>
+#include <linux/scatterlist.h>
+#include <linux/timer.h>
#ifdef CONFIG_SUPERH
#include <asm/sh_bios.h>
@@ -84,6 +87,27 @@ struct sci_port {
struct clk *dclk;
struct list_head node;
+ struct dma_chan *chan_tx;
+ struct dma_chan *chan_rx;
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+ struct device *dma_dev;
+ enum sh_dmae_slave_chan_id slave_tx;
+ enum sh_dmae_slave_chan_id slave_rx;
+ struct dma_async_tx_descriptor *desc_tx;
+ struct dma_async_tx_descriptor *desc_rx[2];
+ dma_cookie_t cookie_tx;
+ dma_cookie_t cookie_rx[2];
+ dma_cookie_t active_rx;
+ struct scatterlist sg_tx;
+ unsigned int sg_len_tx;
+ struct scatterlist sg_rx[2];
+ size_t buf_len_rx;
+ struct sh_dmae_slave param_tx;
+ struct sh_dmae_slave param_rx;
+ struct work_struct work_tx;
+ struct work_struct work_rx;
+ struct timer_list rx_timer;
+#endif
};
struct sh_sci_priv {
@@ -269,29 +293,44 @@ static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
defined(CONFIG_CPU_SUBTYPE_SH7780) || \
defined(CONFIG_CPU_SUBTYPE_SH7785) || \
defined(CONFIG_CPU_SUBTYPE_SH7786)
-static inline int scif_txroom(struct uart_port *port)
+static int scif_txfill(struct uart_port *port)
{
- return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0xff);
+ return sci_in(port, SCTFDR) & 0xff;
}
-static inline int scif_rxroom(struct uart_port *port)
+static int scif_txroom(struct uart_port *port)
+{
+ return SCIF_TXROOM_MAX - scif_txfill(port);
+}
+
+static int scif_rxfill(struct uart_port *port)
{
return sci_in(port, SCRFDR) & 0xff;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-static inline int scif_txroom(struct uart_port *port)
+static int scif_txfill(struct uart_port *port)
{
- if ((port->mapbase == 0xffe00000) ||
- (port->mapbase == 0xffe08000)) {
+ if (port->mapbase == 0xffe00000 ||
+ port->mapbase == 0xffe08000)
/* SCIF0/1*/
- return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0xff);
- } else {
+ return sci_in(port, SCTFDR) & 0xff;
+ else
/* SCIF2 */
- return SCIF2_TXROOM_MAX - (sci_in(port, SCFDR) >> 8);
- }
+ return sci_in(port, SCFDR) >> 8;
+}
+
+static int scif_txroom(struct uart_port *port)
+{
+ if (port->mapbase == 0xffe00000 ||
+ port->mapbase == 0xffe08000)
+ /* SCIF0/1*/
+ return SCIF_TXROOM_MAX - scif_txfill(port);
+ else
+ /* SCIF2 */
+ return SCIF2_TXROOM_MAX - scif_txfill(port);
}
-static inline int scif_rxroom(struct uart_port *port)
+static int scif_rxfill(struct uart_port *port)
{
if ((port->mapbase == 0xffe00000) ||
(port->mapbase == 0xffe08000)) {
@@ -303,23 +342,33 @@ static inline int scif_rxroom(struct uart_port *port)
}
}
#else
-static inline int scif_txroom(struct uart_port *port)
+static int scif_txfill(struct uart_port *port)
{
- return SCIF_TXROOM_MAX - (sci_in(port, SCFDR) >> 8);
+ return sci_in(port, SCFDR) >> 8;
}
-static inline int scif_rxroom(struct uart_port *port)
+static int scif_txroom(struct uart_port *port)
+{
+ return SCIF_TXROOM_MAX - scif_txfill(port);
+}
+
+static int scif_rxfill(struct uart_port *port)
{
return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
}
#endif
-static inline int sci_txroom(struct uart_port *port)
+static int sci_txfill(struct uart_port *port)
{
- return (sci_in(port, SCxSR) & SCI_TDRE) != 0;
+ return !(sci_in(port, SCxSR) & SCI_TDRE);
}
-static inline int sci_rxroom(struct uart_port *port)
+static int sci_txroom(struct uart_port *port)
+{
+ return !sci_txfill(port);
+}
+
+static int sci_rxfill(struct uart_port *port)
{
return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
}
@@ -406,9 +455,9 @@ static inline void sci_receive_chars(struct uart_port *port)
while (1) {
if (port->type == PORT_SCI)
- count = sci_rxroom(port);
+ count = sci_rxfill(port);
else
- count = scif_rxroom(port);
+ count = scif_rxfill(port);
/* Don't copy more bytes than there is room for in the buffer */
count = tty_buffer_request_room(tty, count);
@@ -453,10 +502,10 @@ static inline void sci_receive_chars(struct uart_port *port)
}
/* Store data and status */
- if (status&SCxSR_FER(port)) {
+ if (status & SCxSR_FER(port)) {
flag = TTY_FRAME;
dev_notice(port->dev, "frame error\n");
- } else if (status&SCxSR_PER(port)) {
+ } else if (status & SCxSR_PER(port)) {
flag = TTY_PARITY;
dev_notice(port->dev, "parity error\n");
} else
@@ -618,13 +667,39 @@ static inline int sci_handle_breaks(struct uart_port *port)
return copied;
}
-static irqreturn_t sci_rx_interrupt(int irq, void *port)
+static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
{
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+ struct uart_port *port = ptr;
+ struct sci_port *s = to_sci_port(port);
+
+ if (s->chan_rx) {
+ unsigned long tout;
+ u16 scr = sci_in(port, SCSCR);
+ u16 ssr = sci_in(port, SCxSR);
+
+ /* Disable future Rx interrupts */
+ sci_out(port, SCSCR, scr & ~SCI_CTRL_FLAGS_RIE);
+ /* Clear current interrupt */
+ sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port)));
+ /* Calculate delay for 1.5 DMA buffers */
+ tout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
+ port->fifosize / 2;
+ dev_dbg(port->dev, "Rx IRQ: setup timeout in %lu ms\n",
+ tout * 1000 / HZ);
+ if (tout < 2)
+ tout = 2;
+ mod_timer(&s->rx_timer, jiffies + tout);
+
+ return IRQ_HANDLED;
+ }
+#endif
+
/* I think sci_receive_chars has to be called irrespective
* of whether the I_IXOFF is set, otherwise, how is the interrupt
* to be disabled?
*/
- sci_receive_chars(port);
+ sci_receive_chars(ptr);
return IRQ_HANDLED;
}
@@ -680,6 +755,7 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
{
unsigned short ssr_status, scr_status, err_enabled;
struct uart_port *port = ptr;
+ struct sci_port *s = to_sci_port(port);
irqreturn_t ret = IRQ_NONE;
ssr_status = sci_in(port, SCxSR);
@@ -687,10 +763,15 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
err_enabled = scr_status & (SCI_CTRL_FLAGS_REIE | SCI_CTRL_FLAGS_RIE);
/* Tx Interrupt */
- if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCI_CTRL_FLAGS_TIE))
+ if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCI_CTRL_FLAGS_TIE) &&
+ !s->chan_tx)
ret = sci_tx_interrupt(irq, ptr);
- /* Rx Interrupt */
- if ((ssr_status & SCxSR_RDxF(port)) && (scr_status & SCI_CTRL_FLAGS_RIE))
+ /*
+ * Rx Interrupt: if we're using DMA, the DMA controller clears RDF /
+ * DR flags
+ */
+ if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
+ (scr_status & SCI_CTRL_FLAGS_RIE))
ret = sci_rx_interrupt(irq, ptr);
/* Error Interrupt */
if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
@@ -699,6 +780,10 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
ret = sci_br_interrupt(irq, ptr);
+ WARN_ONCE(ret == IRQ_NONE,
+ "%s: %d IRQ %d, status %x, control %x\n", __func__,
+ irq, port->line, ssr_status, scr_status);
+
return ret;
}
@@ -800,7 +885,9 @@ static void sci_free_irq(struct sci_port *port)
static unsigned int sci_tx_empty(struct uart_port *port)
{
unsigned short status = sci_in(port, SCxSR);
- return status & SCxSR_TEND(port) ? TIOCSER_TEMT : 0;
+ unsigned short in_tx_fifo = scif_txfill(port);
+
+ return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
}
static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
@@ -812,16 +899,297 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
static unsigned int sci_get_mctrl(struct uart_port *port)
{
- /* This routine is used for geting signals of: DTR, DCD, DSR, RI,
+ /* This routine is used for getting signals of: DTR, DCD, DSR, RI,
and CTS/RTS */
return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR;
}
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+static void sci_dma_tx_complete(void *arg)
+{
+ struct sci_port *s = arg;
+ struct uart_port *port = &s->port;
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned long flags;
+
+ dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ xmit->tail += s->sg_tx.length;
+ xmit->tail &= UART_XMIT_SIZE - 1;
+
+ port->icount.tx += s->sg_tx.length;
+
+ async_tx_ack(s->desc_tx);
+ s->cookie_tx = -EINVAL;
+ s->desc_tx = NULL;
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_chars_pending(xmit))
+ schedule_work(&s->work_tx);
+}
+
+/* Locking: called with port lock held */
+static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty,
+ size_t count)
+{
+ struct uart_port *port = &s->port;
+ int i, active, room;
+
+ room = tty_buffer_request_room(tty, count);
+
+ if (s->active_rx == s->cookie_rx[0]) {
+ active = 0;
+ } else if (s->active_rx == s->cookie_rx[1]) {
+ active = 1;
+ } else {
+ dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
+ return 0;
+ }
+
+ if (room < count)
+ dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
+ count - room);
+ if (!room)
+ return room;
+
+ for (i = 0; i < room; i++)
+ tty_insert_flip_char(tty, ((u8 *)sg_virt(&s->sg_rx[active]))[i],
+ TTY_NORMAL);
+
+ port->icount.rx += room;
+
+ return room;
+}
+
+static void sci_dma_rx_complete(void *arg)
+{
+ struct sci_port *s = arg;
+ struct uart_port *port = &s->port;
+ struct tty_struct *tty = port->state->port.tty;
+ unsigned long flags;
+ int count;
+
+ dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ count = sci_dma_rx_push(s, tty, s->buf_len_rx);
+
+ mod_timer(&s->rx_timer, jiffies + msecs_to_jiffies(5));
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ if (count)
+ tty_flip_buffer_push(tty);
+
+ schedule_work(&s->work_rx);
+}
+
+static void sci_start_rx(struct uart_port *port);
+static void sci_start_tx(struct uart_port *port);
+
+static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
+{
+ struct dma_chan *chan = s->chan_rx;
+ struct uart_port *port = &s->port;
+
+ s->chan_rx = NULL;
+ s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
+ dma_release_channel(chan);
+ dma_free_coherent(port->dev, s->buf_len_rx * 2,
+ sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0]));
+ if (enable_pio)
+ sci_start_rx(port);
+}
+
+static void sci_tx_dma_release(struct sci_port *s, bool enable_pio)
+{
+ struct dma_chan *chan = s->chan_tx;
+ struct uart_port *port = &s->port;
+
+ s->chan_tx = NULL;
+ s->cookie_tx = -EINVAL;
+ dma_release_channel(chan);
+ if (enable_pio)
+ sci_start_tx(port);
+}
+
+static void sci_submit_rx(struct sci_port *s)
+{
+ struct dma_chan *chan = s->chan_rx;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ struct scatterlist *sg = &s->sg_rx[i];
+ struct dma_async_tx_descriptor *desc;
+
+ desc = chan->device->device_prep_slave_sg(chan,
+ sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT);
+
+ if (desc) {
+ s->desc_rx[i] = desc;
+ desc->callback = sci_dma_rx_complete;
+ desc->callback_param = s;
+ s->cookie_rx[i] = desc->tx_submit(desc);
+ }
+
+ if (!desc || s->cookie_rx[i] < 0) {
+ if (i) {
+ async_tx_ack(s->desc_rx[0]);
+ s->cookie_rx[0] = -EINVAL;
+ }
+ if (desc) {
+ async_tx_ack(desc);
+ s->cookie_rx[i] = -EINVAL;
+ }
+ dev_warn(s->port.dev,
+ "failed to re-start DMA, using PIO\n");
+ sci_rx_dma_release(s, true);
+ return;
+ }
+ }
+
+ s->active_rx = s->cookie_rx[0];
+
+ dma_async_issue_pending(chan);
+}
+
+static void work_fn_rx(struct work_struct *work)
+{
+ struct sci_port *s = container_of(work, struct sci_port, work_rx);
+ struct uart_port *port = &s->port;
+ struct dma_async_tx_descriptor *desc;
+ int new;
+
+ if (s->active_rx == s->cookie_rx[0]) {
+ new = 0;
+ } else if (s->active_rx == s->cookie_rx[1]) {
+ new = 1;
+ } else {
+ dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
+ return;
+ }
+ desc = s->desc_rx[new];
+
+ if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) !=
+ DMA_SUCCESS) {
+ /* Handle incomplete DMA receive */
+ struct tty_struct *tty = port->state->port.tty;
+ struct dma_chan *chan = s->chan_rx;
+ struct sh_desc *sh_desc = container_of(desc, struct sh_desc,
+ async_tx);
+ unsigned long flags;
+ int count;
+
+ chan->device->device_terminate_all(chan);
+ dev_dbg(port->dev, "Read %u bytes with cookie %d\n",
+ sh_desc->partial, sh_desc->cookie);
+
+ spin_lock_irqsave(&port->lock, flags);
+ count = sci_dma_rx_push(s, tty, sh_desc->partial);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ if (count)
+ tty_flip_buffer_push(tty);
+
+ sci_submit_rx(s);
+
+ return;
+ }
+
+ s->cookie_rx[new] = desc->tx_submit(desc);
+ if (s->cookie_rx[new] < 0) {
+ dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
+ sci_rx_dma_release(s, true);
+ return;
+ }
+
+ dev_dbg(port->dev, "%s: cookie %d #%d\n", __func__,
+ s->cookie_rx[new], new);
+
+ s->active_rx = s->cookie_rx[!new];
+}
+
+static void work_fn_tx(struct work_struct *work)
+{
+ struct sci_port *s = container_of(work, struct sci_port, work_tx);
+ struct dma_async_tx_descriptor *desc;
+ struct dma_chan *chan = s->chan_tx;
+ struct uart_port *port = &s->port;
+ struct circ_buf *xmit = &port->state->xmit;
+ struct scatterlist *sg = &s->sg_tx;
+
+ /*
+ * DMA is idle now.
+ * Port xmit buffer is already mapped, and it is one page... Just adjust
+ * offsets and lengths. Since it is a circular buffer, we have to
+ * transmit till the end, and then the rest. Take the port lock to get a
+ * consistent xmit buffer state.
+ */
+ spin_lock_irq(&port->lock);
+ sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
+ sg->dma_address = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
+ sg->offset;
+ sg->length = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
+ CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
+ sg->dma_length = sg->length;
+ spin_unlock_irq(&port->lock);
+
+ BUG_ON(!sg->length);
+
+ desc = chan->device->device_prep_slave_sg(chan,
+ sg, s->sg_len_tx, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ /* switch to PIO */
+ sci_tx_dma_release(s, true);
+ return;
+ }
+
+ dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
+
+ spin_lock_irq(&port->lock);
+ s->desc_tx = desc;
+ desc->callback = sci_dma_tx_complete;
+ desc->callback_param = s;
+ spin_unlock_irq(&port->lock);
+ s->cookie_tx = desc->tx_submit(desc);
+ if (s->cookie_tx < 0) {
+ dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
+ /* switch to PIO */
+ sci_tx_dma_release(s, true);
+ return;
+ }
+
+ dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__,
+ xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
+
+ dma_async_issue_pending(chan);
+}
+#endif
+
static void sci_start_tx(struct uart_port *port)
{
unsigned short ctrl;
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+ struct sci_port *s = to_sci_port(port);
+
+ if (s->chan_tx) {
+ if (!uart_circ_empty(&s->port.state->xmit) && s->cookie_tx < 0)
+ schedule_work(&s->work_tx);
+
+ return;
+ }
+#endif
+
/* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
ctrl = sci_in(port, SCSCR);
ctrl |= SCI_CTRL_FLAGS_TIE;
@@ -838,13 +1206,12 @@ static void sci_stop_tx(struct uart_port *port)
sci_out(port, SCSCR, ctrl);
}
-static void sci_start_rx(struct uart_port *port, unsigned int tty_start)
+static void sci_start_rx(struct uart_port *port)
{
- unsigned short ctrl;
+ unsigned short ctrl = SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE;
/* Set RIE (Receive Interrupt Enable) bit in SCSCR */
- ctrl = sci_in(port, SCSCR);
- ctrl |= SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE;
+ ctrl |= sci_in(port, SCSCR);
sci_out(port, SCSCR, ctrl);
}
@@ -868,16 +1235,154 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
/* Nothing here yet .. */
}
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+static bool filter(struct dma_chan *chan, void *slave)
+{
+ struct sh_dmae_slave *param = slave;
+
+ dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__,
+ param->slave_id);
+
+ if (param->dma_dev == chan->device->dev) {
+ chan->private = param;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static void rx_timer_fn(unsigned long arg)
+{
+ struct sci_port *s = (struct sci_port *)arg;
+ struct uart_port *port = &s->port;
+
+ u16 scr = sci_in(port, SCSCR);
+ sci_out(port, SCSCR, scr | SCI_CTRL_FLAGS_RIE);
+ dev_dbg(port->dev, "DMA Rx timed out\n");
+ schedule_work(&s->work_rx);
+}
+
+static void sci_request_dma(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+ struct sh_dmae_slave *param;
+ struct dma_chan *chan;
+ dma_cap_mask_t mask;
+ int nent;
+
+ dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__,
+ port->line, s->dma_dev);
+
+ if (!s->dma_dev)
+ return;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ param = &s->param_tx;
+
+ /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */
+ param->slave_id = s->slave_tx;
+ param->dma_dev = s->dma_dev;
+
+ s->cookie_tx = -EINVAL;
+ chan = dma_request_channel(mask, filter, param);
+ dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
+ if (chan) {
+ s->chan_tx = chan;
+ sg_init_table(&s->sg_tx, 1);
+ /* UART circular tx buffer is an aligned page. */
+ BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
+ sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf),
+ UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK);
+ nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE);
+ if (!nent)
+ sci_tx_dma_release(s, false);
+ else
+ dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+ sg_dma_len(&s->sg_tx),
+ port->state->xmit.buf, sg_dma_address(&s->sg_tx));
+
+ s->sg_len_tx = nent;
+
+ INIT_WORK(&s->work_tx, work_fn_tx);
+ }
+
+ param = &s->param_rx;
+
+ /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */
+ param->slave_id = s->slave_rx;
+ param->dma_dev = s->dma_dev;
+
+ chan = dma_request_channel(mask, filter, param);
+ dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
+ if (chan) {
+ dma_addr_t dma[2];
+ void *buf[2];
+ int i;
+
+ s->chan_rx = chan;
+
+ s->buf_len_rx = 2 * max(16, (int)port->fifosize);
+ buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2,
+ &dma[0], GFP_KERNEL);
+
+ if (!buf[0]) {
+ dev_warn(port->dev,
+ "failed to allocate dma buffer, using PIO\n");
+ sci_rx_dma_release(s, true);
+ return;
+ }
+
+ buf[1] = buf[0] + s->buf_len_rx;
+ dma[1] = dma[0] + s->buf_len_rx;
+
+ for (i = 0; i < 2; i++) {
+ struct scatterlist *sg = &s->sg_rx[i];
+
+ sg_init_table(sg, 1);
+ sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx,
+ (int)buf[i] & ~PAGE_MASK);
+ sg->dma_address = dma[i];
+ sg->dma_length = sg->length;
+ }
+
+ INIT_WORK(&s->work_rx, work_fn_rx);
+ setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s);
+
+ sci_submit_rx(s);
+ }
+}
+
+static void sci_free_dma(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+
+ if (!s->dma_dev)
+ return;
+
+ if (s->chan_tx)
+ sci_tx_dma_release(s, false);
+ if (s->chan_rx)
+ sci_rx_dma_release(s, false);
+}
+#endif
+
static int sci_startup(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
+ dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+
if (s->enable)
s->enable(port);
sci_request_irq(s);
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+ sci_request_dma(port);
+#endif
sci_start_tx(port);
- sci_start_rx(port, 1);
+ sci_start_rx(port);
return 0;
}
@@ -886,8 +1391,13 @@ static void sci_shutdown(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
+ dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+
sci_stop_rx(port);
sci_stop_tx(port);
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+ sci_free_dma(port);
+#endif
sci_free_irq(s);
if (s->disable)
@@ -937,6 +1447,9 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
sci_out(port, SCSMR, smr_val);
+ dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t,
+ SCSCR_INIT(port));
+
if (t > 0) {
if (t >= 256) {
sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
@@ -954,7 +1467,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
sci_out(port, SCSCR, SCSCR_INIT(port));
if ((termios->c_cflag & CREAD) != 0)
- sci_start_rx(port, 0);
+ sci_start_rx(port);
}
static const char *sci_type(struct uart_port *port)
@@ -1049,29 +1562,51 @@ static void __devinit sci_init_single(struct platform_device *dev,
unsigned int index,
struct plat_sci_port *p)
{
- sci_port->port.ops = &sci_uart_ops;
- sci_port->port.iotype = UPIO_MEM;
- sci_port->port.line = index;
- sci_port->port.fifosize = 1;
+ struct uart_port *port = &sci_port->port;
+
+ port->ops = &sci_uart_ops;
+ port->iotype = UPIO_MEM;
+ port->line = index;
+
+ switch (p->type) {
+ case PORT_SCIFA:
+ port->fifosize = 64;
+ break;
+ case PORT_SCIF:
+ port->fifosize = 16;
+ break;
+ default:
+ port->fifosize = 1;
+ break;
+ }
if (dev) {
sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL;
sci_port->dclk = clk_get(&dev->dev, "peripheral_clk");
sci_port->enable = sci_clk_enable;
sci_port->disable = sci_clk_disable;
- sci_port->port.dev = &dev->dev;
+ port->dev = &dev->dev;
}
sci_port->break_timer.data = (unsigned long)sci_port;
sci_port->break_timer.function = sci_break_timer;
init_timer(&sci_port->break_timer);
- sci_port->port.mapbase = p->mapbase;
- sci_port->port.membase = p->membase;
+ port->mapbase = p->mapbase;
+ port->membase = p->membase;
- sci_port->port.irq = p->irqs[SCIx_TXI_IRQ];
- sci_port->port.flags = p->flags;
- sci_port->type = sci_port->port.type = p->type;
+ port->irq = p->irqs[SCIx_TXI_IRQ];
+ port->flags = p->flags;
+ sci_port->type = port->type = p->type;
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+ sci_port->dma_dev = p->dma_dev;
+ sci_port->slave_tx = p->dma_slave_tx;
+ sci_port->slave_rx = p->dma_slave_rx;
+
+ dev_dbg(port->dev, "%s: DMA device %p, tx %d, rx %d\n", __func__,
+ p->dma_dev, p->dma_slave_tx, p->dma_slave_rx);
+#endif
memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));
}
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index 0efcded59ae6..fad67d33b0bd 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -30,7 +30,8 @@
*/
# define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0
#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
- defined(CONFIG_CPU_SUBTYPE_SH7721)
+ defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+ defined(CONFIG_ARCH_SHMOBILE)
# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
# define PORT_PTCR 0xA405011EUL
# define PORT_PVCR 0xA4050122UL
@@ -228,7 +229,8 @@
#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
- defined(CONFIG_CPU_SUBTYPE_SH7721)
+ defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+ defined(CONFIG_ARCH_SHMOBILE)
# define SCIF_ORER 0x0200
# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
# define SCIF_RFDC_MASK 0x007f
@@ -261,7 +263,8 @@
#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
- defined(CONFIG_CPU_SUBTYPE_SH7721)
+ defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+ defined(CONFIG_ARCH_SHMOBILE)
# define SCxSR_RDxF_CLEAR(port) (sci_in(port, SCxSR) & 0xfffc)
# define SCxSR_ERROR_CLEAR(port) (sci_in(port, SCxSR) & 0xfd73)
# define SCxSR_TDxE_CLEAR(port) (sci_in(port, SCxSR) & 0xffdf)
@@ -356,7 +359,7 @@
SCI_OUT(sci_size, sci_offset, value); \
}
-#ifdef CONFIG_CPU_SH3
+#if defined(CONFIG_CPU_SH3) || defined(CONFIG_ARCH_SHMOBILE)
#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
@@ -366,7 +369,8 @@
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
- defined(CONFIG_CPU_SUBTYPE_SH7721)
+ defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+ defined(CONFIG_ARCH_SHMOBILE)
#define SCIF_FNS(name, scif_offset, scif_size) \
CPU_SCIF_FNS(name, scif_offset, scif_size)
#else
@@ -401,7 +405,8 @@
#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
- defined(CONFIG_CPU_SUBTYPE_SH7721)
+ defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+ defined(CONFIG_ARCH_SHMOBILE)
SCIF_FNS(SCSMR, 0x00, 16)
SCIF_FNS(SCBRR, 0x04, 8)
@@ -413,7 +418,7 @@ SCIF_FNS(SCFCR, 0x18, 16)
SCIF_FNS(SCFDR, 0x1c, 16)
SCIF_FNS(SCxTDR, 0x20, 8)
SCIF_FNS(SCxRDR, 0x24, 8)
-SCIF_FNS(SCLSR, 0x24, 16)
+SCIF_FNS(SCLSR, 0x00, 0)
#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
defined(CONFIG_CPU_SUBTYPE_SH7724)
SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16)
@@ -518,34 +523,6 @@ static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xfffffe80)
return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */
- if (port->mapbase == 0xa4000150)
- return __raw_readb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xa4000140)
- return __raw_readb(SCPDR)&0x04 ? 1 : 0; /* IRDA */
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == SCIF0)
- return __raw_readb(SCPDR)&0x04 ? 1 : 0; /* IRDA */
- if (port->mapbase == SCIF2)
- return __raw_readb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- return sci_in(port,SCxSR)&0x0010 ? 1 : 0;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
- defined(CONFIG_CPU_SUBTYPE_SH7721)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xa4430000)
- return sci_in(port, SCxSR) & 0x0003 ? 1 : 0;
- else if (port->mapbase == 0xa4438000)
- return sci_in(port, SCxSR) & 0x0003 ? 1 : 0;
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
@@ -558,207 +535,17 @@ static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffe00000)
return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
- if (port->mapbase == 0xffe80000)
- return __raw_readw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xffe80000)
- return __raw_readw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
return 1;
}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7757)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xfe4b0000)
- return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0;
- if (port->mapbase == 0xfe4c0000)
- return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0;
- if (port->mapbase == 0xfe4d0000)
- return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xfe600000)
- return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xfe610000)
- return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xfe620000)
- return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xffe00000)
- return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffe10000)
- return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffe20000)
- return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffe30000)
- return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7366)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xffe00000)
- return __raw_readb(SCPDR0) & 0x0001 ? 1 : 0; /* SCIF0 */
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xffe00000)
- return __raw_readb(PSDR) & 0x02 ? 1 : 0; /* SCIF0 */
- if (port->mapbase == 0xffe10000)
- return __raw_readb(PADR) & 0x40 ? 1 : 0; /* SCIF1 */
- if (port->mapbase == 0xffe20000)
- return __raw_readb(PWDR) & 0x04 ? 1 : 0; /* SCIF2 */
-
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xffe00000)
- return __raw_readb(SCSPTR0) & 0x0008 ? 1 : 0; /* SCIF0 */
- if (port->mapbase == 0xffe10000)
- return __raw_readb(SCSPTR1) & 0x0020 ? 1 : 0; /* SCIF1 */
- if (port->mapbase == 0xffe20000)
- return __raw_readb(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF2 */
- if (port->mapbase == 0xa4e30000)
- return __raw_readb(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF3 */
- if (port->mapbase == 0xa4e40000)
- return __raw_readb(SCSPTR4) & 0x0001 ? 1 : 0; /* SCIF4 */
- if (port->mapbase == 0xa4e50000)
- return __raw_readb(SCSPTR5) & 0x0008 ? 1 : 0; /* SCIF5 */
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
-# define SCFSR 0x0010
-# define SCASSR 0x0014
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->type == PORT_SCIF)
- return __raw_readw((port->mapbase + SCFSR)) & SCIF_BRK ? 1 : 0;
- if (port->type == PORT_SCIFA)
- return __raw_readw((port->mapbase + SCASSR)) & SCIF_BRK ? 1 : 0;
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- return sci_in(port, SCSPTR)&0x0001 ? 1 : 0; /* SCIF */
-}
#elif defined(__H8300H__) || defined(__H8300S__)
static inline int sci_rxd_in(struct uart_port *port)
{
int ch = (port->mapbase - SMR0) >> 3;
return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xffe00000)
- return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffe08000)
- return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffe10000)
- return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF/IRDA */
-
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xff923000)
- return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xff924000)
- return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xff925000)
- return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xffe00000)
- return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffe10000)
- return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
- defined(CONFIG_CPU_SUBTYPE_SH7786)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xffea0000)
- return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffeb0000)
- return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffec0000)
- return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffed0000)
- return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffee0000)
- return __raw_readw(SCSPTR4) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffef0000)
- return __raw_readw(SCSPTR5) & 0x0001 ? 1 : 0; /* SCIF */
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
- defined(CONFIG_CPU_SUBTYPE_SH7203) || \
- defined(CONFIG_CPU_SUBTYPE_SH7206) || \
- defined(CONFIG_CPU_SUBTYPE_SH7263)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xfffe8000)
- return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xfffe8800)
- return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xfffe9000)
- return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xfffe9800)
- return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
-#if defined(CONFIG_CPU_SUBTYPE_SH7201)
- if (port->mapbase == 0xfffeA000)
- return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xfffeA800)
- return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xfffeB000)
- return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xfffeB800)
- return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
-#endif
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xf8400000)
- return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xf8410000)
- return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xf8420000)
- return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
+#else /* default case for non-SCI processors */
static inline int sci_rxd_in(struct uart_port *port)
{
- if (port->mapbase == 0xffc30000)
- return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffc40000)
- return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffc50000)
- return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
- if (port->mapbase == 0xffc60000)
- return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
return 1;
}
#endif
@@ -801,7 +588,8 @@ static inline int sci_rxd_in(struct uart_port *port)
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
- defined(CONFIG_CPU_SUBTYPE_SH7721)
+ defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+ defined(CONFIG_ARCH_SHMOBILE)
#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
defined(CONFIG_CPU_SUBTYPE_SH7724)
diff --git a/drivers/serial/timbuart.c b/drivers/serial/timbuart.c
index 34b31da01d09..7bf10264a6ac 100644
--- a/drivers/serial/timbuart.c
+++ b/drivers/serial/timbuart.c
@@ -421,7 +421,7 @@ static struct uart_driver timbuart_driver = {
static int timbuart_probe(struct platform_device *dev)
{
- int err;
+ int err, irq;
struct timbuart_port *uart;
struct resource *iomem;
@@ -453,11 +453,12 @@ static int timbuart_probe(struct platform_device *dev)
uart->port.mapbase = iomem->start;
uart->port.membase = NULL;
- uart->port.irq = platform_get_irq(dev, 0);
- if (uart->port.irq < 0) {
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
err = -EINVAL;
goto err_register;
}
+ uart->port.irq = irq;
tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart);
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index 377f2712289e..ab2ab3c81834 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -394,7 +394,7 @@ static void ulite_console_write(struct console *co, const char *s,
spin_unlock_irqrestore(&port->lock, flags);
}
-static int __init ulite_console_setup(struct console *co, char *options)
+static int __devinit ulite_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 9600;
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index d5d7f23c19a5..c2750391fd34 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -259,6 +259,43 @@ static void intc_disable(unsigned int irq)
}
}
+static void (*intc_enable_noprio_fns[])(unsigned long addr,
+ unsigned long handle,
+ void (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq) = {
+ [MODE_ENABLE_REG] = intc_mode_field,
+ [MODE_MASK_REG] = intc_mode_zero,
+ [MODE_DUAL_REG] = intc_mode_field,
+ [MODE_PRIO_REG] = intc_mode_field,
+ [MODE_PCLR_REG] = intc_mode_field,
+};
+
+static void intc_enable_disable(struct intc_desc_int *d,
+ unsigned long handle, int do_enable)
+{
+ unsigned long addr;
+ unsigned int cpu;
+ void (*fn)(unsigned long, unsigned long,
+ void (*)(unsigned long, unsigned long, unsigned long),
+ unsigned int);
+
+ if (do_enable) {
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
+ addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
+ fn = intc_enable_noprio_fns[_INTC_MODE(handle)];
+ fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
+ }
+ } else {
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
+ fn = intc_disable_fns[_INTC_MODE(handle)];
+ fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
+ }
+ }
+}
+
static int intc_set_wake(unsigned int irq, unsigned int on)
{
return 0; /* allow wakeup, but setup hardware in intc_suspend() */
@@ -400,11 +437,11 @@ static unsigned int __init intc_get_reg(struct intc_desc_int *d,
static intc_enum __init intc_grp_id(struct intc_desc *desc,
intc_enum enum_id)
{
- struct intc_group *g = desc->groups;
+ struct intc_group *g = desc->hw.groups;
unsigned int i, j;
- for (i = 0; g && enum_id && i < desc->nr_groups; i++) {
- g = desc->groups + i;
+ for (i = 0; g && enum_id && i < desc->hw.nr_groups; i++) {
+ g = desc->hw.groups + i;
for (j = 0; g->enum_ids[j]; j++) {
if (g->enum_ids[j] != enum_id)
@@ -417,19 +454,21 @@ static intc_enum __init intc_grp_id(struct intc_desc *desc,
return 0;
}
-static unsigned int __init intc_mask_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id, int do_grps)
+static unsigned int __init _intc_mask_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id,
+ unsigned int *reg_idx,
+ unsigned int *fld_idx)
{
- struct intc_mask_reg *mr = desc->mask_regs;
- unsigned int i, j, fn, mode;
+ struct intc_mask_reg *mr = desc->hw.mask_regs;
+ unsigned int fn, mode;
unsigned long reg_e, reg_d;
- for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) {
- mr = desc->mask_regs + i;
+ while (mr && enum_id && *reg_idx < desc->hw.nr_mask_regs) {
+ mr = desc->hw.mask_regs + *reg_idx;
- for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
- if (mr->enum_ids[j] != enum_id)
+ for (; *fld_idx < ARRAY_SIZE(mr->enum_ids); (*fld_idx)++) {
+ if (mr->enum_ids[*fld_idx] != enum_id)
continue;
if (mr->set_reg && mr->clr_reg) {
@@ -455,29 +494,49 @@ static unsigned int __init intc_mask_data(struct intc_desc *desc,
intc_get_reg(d, reg_e),
intc_get_reg(d, reg_d),
1,
- (mr->reg_width - 1) - j);
+ (mr->reg_width - 1) - *fld_idx);
}
+
+ *fld_idx = 0;
+ (*reg_idx)++;
}
+ return 0;
+}
+
+static unsigned int __init intc_mask_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id, int do_grps)
+{
+ unsigned int i = 0;
+ unsigned int j = 0;
+ unsigned int ret;
+
+ ret = _intc_mask_data(desc, d, enum_id, &i, &j);
+ if (ret)
+ return ret;
+
if (do_grps)
return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0);
return 0;
}
-static unsigned int __init intc_prio_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id, int do_grps)
+static unsigned int __init _intc_prio_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id,
+ unsigned int *reg_idx,
+ unsigned int *fld_idx)
{
- struct intc_prio_reg *pr = desc->prio_regs;
- unsigned int i, j, fn, mode, bit;
+ struct intc_prio_reg *pr = desc->hw.prio_regs;
+ unsigned int fn, n, mode, bit;
unsigned long reg_e, reg_d;
- for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) {
- pr = desc->prio_regs + i;
+ while (pr && enum_id && *reg_idx < desc->hw.nr_prio_regs) {
+ pr = desc->hw.prio_regs + *reg_idx;
- for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) {
- if (pr->enum_ids[j] != enum_id)
+ for (; *fld_idx < ARRAY_SIZE(pr->enum_ids); (*fld_idx)++) {
+ if (pr->enum_ids[*fld_idx] != enum_id)
continue;
if (pr->set_reg && pr->clr_reg) {
@@ -495,34 +554,79 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc,
}
fn += (pr->reg_width >> 3) - 1;
+ n = *fld_idx + 1;
- BUG_ON((j + 1) * pr->field_width > pr->reg_width);
+ BUG_ON(n * pr->field_width > pr->reg_width);
- bit = pr->reg_width - ((j + 1) * pr->field_width);
+ bit = pr->reg_width - (n * pr->field_width);
return _INTC_MK(fn, mode,
intc_get_reg(d, reg_e),
intc_get_reg(d, reg_d),
pr->field_width, bit);
}
+
+ *fld_idx = 0;
+ (*reg_idx)++;
}
+ return 0;
+}
+
+static unsigned int __init intc_prio_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id, int do_grps)
+{
+ unsigned int i = 0;
+ unsigned int j = 0;
+ unsigned int ret;
+
+ ret = _intc_prio_data(desc, d, enum_id, &i, &j);
+ if (ret)
+ return ret;
+
if (do_grps)
return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0);
return 0;
}
+static void __init intc_enable_disable_enum(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id, int enable)
+{
+ unsigned int i, j, data;
+
+ /* go through and enable/disable all mask bits */
+ i = j = 0;
+ do {
+ data = _intc_mask_data(desc, d, enum_id, &i, &j);
+ if (data)
+ intc_enable_disable(d, data, enable);
+ j++;
+ } while (data);
+
+ /* go through and enable/disable all priority fields */
+ i = j = 0;
+ do {
+ data = _intc_prio_data(desc, d, enum_id, &i, &j);
+ if (data)
+ intc_enable_disable(d, data, enable);
+
+ j++;
+ } while (data);
+}
+
static unsigned int __init intc_ack_data(struct intc_desc *desc,
struct intc_desc_int *d,
intc_enum enum_id)
{
- struct intc_mask_reg *mr = desc->ack_regs;
+ struct intc_mask_reg *mr = desc->hw.ack_regs;
unsigned int i, j, fn, mode;
unsigned long reg_e, reg_d;
- for (i = 0; mr && enum_id && i < desc->nr_ack_regs; i++) {
- mr = desc->ack_regs + i;
+ for (i = 0; mr && enum_id && i < desc->hw.nr_ack_regs; i++) {
+ mr = desc->hw.ack_regs + i;
for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
if (mr->enum_ids[j] != enum_id)
@@ -549,11 +653,11 @@ static unsigned int __init intc_sense_data(struct intc_desc *desc,
struct intc_desc_int *d,
intc_enum enum_id)
{
- struct intc_sense_reg *sr = desc->sense_regs;
+ struct intc_sense_reg *sr = desc->hw.sense_regs;
unsigned int i, j, fn, bit;
- for (i = 0; sr && enum_id && i < desc->nr_sense_regs; i++) {
- sr = desc->sense_regs + i;
+ for (i = 0; sr && enum_id && i < desc->hw.nr_sense_regs; i++) {
+ sr = desc->hw.sense_regs + i;
for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
if (sr->enum_ids[j] != enum_id)
@@ -656,8 +760,12 @@ static void __init intc_register_irq(struct intc_desc *desc,
/* irq should be disabled by default */
d->chip.mask(irq);
- if (desc->ack_regs)
+ if (desc->hw.ack_regs)
ack_handle[irq] = intc_ack_data(desc, d, enum_id);
+
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
+#endif
}
static unsigned int __init save_reg(struct intc_desc_int *d,
@@ -684,6 +792,7 @@ static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc)
void __init register_intc_controller(struct intc_desc *desc)
{
unsigned int i, k, smp;
+ struct intc_hw_desc *hw = &desc->hw;
struct intc_desc_int *d;
d = kzalloc(sizeof(*d), GFP_NOWAIT);
@@ -691,10 +800,10 @@ void __init register_intc_controller(struct intc_desc *desc)
INIT_LIST_HEAD(&d->list);
list_add(&d->list, &intc_list);
- d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0;
- d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0;
- d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0;
- d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0;
+ d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
+ d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
+ d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
+ d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
#ifdef CONFIG_SMP
@@ -702,30 +811,31 @@ void __init register_intc_controller(struct intc_desc *desc)
#endif
k = 0;
- if (desc->mask_regs) {
- for (i = 0; i < desc->nr_mask_regs; i++) {
- smp = IS_SMP(desc->mask_regs[i]);
- k += save_reg(d, k, desc->mask_regs[i].set_reg, smp);
- k += save_reg(d, k, desc->mask_regs[i].clr_reg, smp);
+ if (hw->mask_regs) {
+ for (i = 0; i < hw->nr_mask_regs; i++) {
+ smp = IS_SMP(hw->mask_regs[i]);
+ k += save_reg(d, k, hw->mask_regs[i].set_reg, smp);
+ k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp);
}
}
- if (desc->prio_regs) {
- d->prio = kzalloc(desc->nr_vectors * sizeof(*d->prio), GFP_NOWAIT);
+ if (hw->prio_regs) {
+ d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio),
+ GFP_NOWAIT);
- for (i = 0; i < desc->nr_prio_regs; i++) {
- smp = IS_SMP(desc->prio_regs[i]);
- k += save_reg(d, k, desc->prio_regs[i].set_reg, smp);
- k += save_reg(d, k, desc->prio_regs[i].clr_reg, smp);
+ for (i = 0; i < hw->nr_prio_regs; i++) {
+ smp = IS_SMP(hw->prio_regs[i]);
+ k += save_reg(d, k, hw->prio_regs[i].set_reg, smp);
+ k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp);
}
}
- if (desc->sense_regs) {
- d->sense = kzalloc(desc->nr_vectors * sizeof(*d->sense), GFP_NOWAIT);
+ if (hw->sense_regs) {
+ d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense),
+ GFP_NOWAIT);
- for (i = 0; i < desc->nr_sense_regs; i++) {
- k += save_reg(d, k, desc->sense_regs[i].reg, 0);
- }
+ for (i = 0; i < hw->nr_sense_regs; i++)
+ k += save_reg(d, k, hw->sense_regs[i].reg, 0);
}
d->chip.name = desc->name;
@@ -738,18 +848,26 @@ void __init register_intc_controller(struct intc_desc *desc)
d->chip.set_type = intc_set_sense;
d->chip.set_wake = intc_set_wake;
- if (desc->ack_regs) {
- for (i = 0; i < desc->nr_ack_regs; i++)
- k += save_reg(d, k, desc->ack_regs[i].set_reg, 0);
+ if (hw->ack_regs) {
+ for (i = 0; i < hw->nr_ack_regs; i++)
+ k += save_reg(d, k, hw->ack_regs[i].set_reg, 0);
d->chip.mask_ack = intc_mask_ack;
}
+ /* disable bits matching force_disable before registering irqs */
+ if (desc->force_disable)
+ intc_enable_disable_enum(desc, d, desc->force_disable, 0);
+
+ /* disable bits matching force_enable before registering irqs */
+ if (desc->force_enable)
+ intc_enable_disable_enum(desc, d, desc->force_enable, 0);
+
BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
/* register the vectors one by one */
- for (i = 0; i < desc->nr_vectors; i++) {
- struct intc_vect *vect = desc->vectors + i;
+ for (i = 0; i < hw->nr_vectors; i++) {
+ struct intc_vect *vect = hw->vectors + i;
unsigned int irq = evt2irq(vect->vect);
struct irq_desc *irq_desc;
@@ -764,8 +882,8 @@ void __init register_intc_controller(struct intc_desc *desc)
intc_register_irq(desc, d, vect->enum_id, irq);
- for (k = i + 1; k < desc->nr_vectors; k++) {
- struct intc_vect *vect2 = desc->vectors + k;
+ for (k = i + 1; k < hw->nr_vectors; k++) {
+ struct intc_vect *vect2 = hw->vectors + k;
unsigned int irq2 = evt2irq(vect2->vect);
if (vect->enum_id != vect2->enum_id)
@@ -785,11 +903,15 @@ void __init register_intc_controller(struct intc_desc *desc)
vect2->enum_id = 0;
/* redirect this interrupts to the first one */
- set_irq_chip_and_handler_name(irq2, &d->chip,
- intc_redirect_irq, "redirect");
+ set_irq_chip(irq2, &dummy_irq_chip);
+ set_irq_chained_handler(irq2, intc_redirect_irq);
set_irq_data(irq2, (void *)irq);
}
}
+
+ /* enable bits matching force_enable after registering irqs */
+ if (desc->force_enable)
+ intc_enable_disable_enum(desc, d, desc->force_enable, 1);
}
static int intc_suspend(struct sys_device *dev, pm_message_t state)
@@ -872,7 +994,7 @@ device_initcall(register_intc_sysdevs);
/*
* Dynamic IRQ allocation and deallocation
*/
-static unsigned int create_irq_on_node(unsigned int irq_want, int node)
+unsigned int create_irq_nr(unsigned int irq_want, int node)
{
unsigned int irq = 0, new;
unsigned long flags;
@@ -881,29 +1003,37 @@ static unsigned int create_irq_on_node(unsigned int irq_want, int node)
spin_lock_irqsave(&vector_lock, flags);
/*
- * First try the wanted IRQ, then scan.
+ * First try the wanted IRQ
*/
- if (test_and_set_bit(irq_want, intc_irq_map)) {
+ if (test_and_set_bit(irq_want, intc_irq_map) == 0) {
+ new = irq_want;
+ } else {
+ /* .. then fall back to scanning. */
new = find_first_zero_bit(intc_irq_map, nr_irqs);
if (unlikely(new == nr_irqs))
goto out_unlock;
- desc = irq_to_desc_alloc_node(new, node);
- if (unlikely(!desc)) {
- pr_info("can't get irq_desc for %d\n", new);
- goto out_unlock;
- }
-
- desc = move_irq_desc(desc, node);
__set_bit(new, intc_irq_map);
- irq = new;
}
+ desc = irq_to_desc_alloc_node(new, node);
+ if (unlikely(!desc)) {
+ pr_info("can't get irq_desc for %d\n", new);
+ goto out_unlock;
+ }
+
+ desc = move_irq_desc(desc, node);
+ irq = new;
+
out_unlock:
spin_unlock_irqrestore(&vector_lock, flags);
- if (irq > 0)
+ if (irq > 0) {
dynamic_irq_init(irq);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
+#endif
+ }
return irq;
}
@@ -913,7 +1043,7 @@ int create_irq(void)
int nid = cpu_to_node(smp_processor_id());
int irq;
- irq = create_irq_on_node(NR_IRQS_LEGACY, nid);
+ irq = create_irq_nr(NR_IRQS_LEGACY, nid);
if (irq == 0)
irq = -1;
diff --git a/drivers/sh/pfc.c b/drivers/sh/pfc.c
index 082604edc4c2..cf0303acab8e 100644
--- a/drivers/sh/pfc.c
+++ b/drivers/sh/pfc.c
@@ -337,12 +337,39 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
if (!enum_id)
break;
+ /* first check if this is a function enum */
in_range = enum_in_range(enum_id, &gpioc->function);
- if (!in_range && range) {
- in_range = enum_in_range(enum_id, range);
-
- if (in_range && enum_id == range->force)
- continue;
+ if (!in_range) {
+ /* not a function enum */
+ if (range) {
+ /*
+ * other range exists, so this pin is
+ * a regular GPIO pin that now is being
+ * bound to a specific direction.
+ *
+ * for this case we only allow function enums
+ * and the enums that match the other range.
+ */
+ in_range = enum_in_range(enum_id, range);
+
+ /*
+ * special case pass through for fixed
+ * input-only or output-only pins without
+ * function enum register association.
+ */
+ if (in_range && enum_id == range->force)
+ continue;
+ } else {
+ /*
+ * no other range exists, so this pin
+ * must then be of the function type.
+ *
+ * allow function type pins to select
+ * any combination of function/in/out
+ * in their MARK lists.
+ */
+ in_range = 1;
+ }
}
if (!in_range)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index f55eb0107336..a191fa2be7c5 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -100,6 +100,23 @@ config SPI_BUTTERFLY
inexpensive battery powered microcontroller evaluation board.
This same cable can be used to flash new firmware.
+config SPI_COLDFIRE_QSPI
+ tristate "Freescale Coldfire QSPI controller"
+ depends on (M520x || M523x || M5249 || M527x || M528x || M532x)
+ help
+ This enables support for the Coldfire QSPI controller in master
+ mode.
+
+ This driver can also be built as a module. If so, the module
+ will be called coldfire_qspi.
+
+config SPI_DAVINCI
+ tristate "SPI controller driver for DaVinci/DA8xx SoC's"
+ depends on SPI_MASTER && ARCH_DAVINCI
+ select SPI_BITBANG
+ help
+ SPI master controller for DaVinci and DA8xx SPI modules.
+
config SPI_GPIO
tristate "GPIO-based bitbanging SPI Master"
depends on GENERIC_GPIO
@@ -164,7 +181,7 @@ config SPI_OMAP_UWIRE
config SPI_OMAP24XX
tristate "McSPI driver for OMAP24xx/OMAP34xx"
- depends on ARCH_OMAP24XX || ARCH_OMAP34XX
+ depends on ARCH_OMAP2 || ARCH_OMAP3
help
SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI
(McSPI) modules.
@@ -308,7 +325,7 @@ config SPI_NUC900
#
config SPI_DESIGNWARE
- bool "DesignWare SPI controller core support"
+ tristate "DesignWare SPI controller core support"
depends on SPI_MASTER
help
general driver for SPI controller core from DesignWare
@@ -317,6 +334,10 @@ config SPI_DW_PCI
tristate "PCI interface driver for DW SPI core"
depends on SPI_DESIGNWARE && PCI
+config SPI_DW_MMIO
+ tristate "Memory-mapped io interface driver for DW SPI core"
+ depends on SPI_DESIGNWARE && HAVE_CLK
+
#
# 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 f3d2810ba11c..d7d0f89b797b 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -16,8 +16,11 @@ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
+obj-$(CONFIG_SPI_COLDFIRE_QSPI) += coldfire_qspi.o
+obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o
obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o
obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o
+obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o
obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
obj-$(CONFIG_SPI_IMX) += spi_imx.o
obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
index ff5bbb9c43c9..9aeb68113100 100644
--- a/drivers/spi/amba-pl022.c
+++ b/drivers/spi/amba-pl022.c
@@ -363,6 +363,7 @@ struct pl022 {
void *rx_end;
enum ssp_reading read;
enum ssp_writing write;
+ u32 exp_fifo_level;
};
/**
@@ -501,6 +502,9 @@ static int flush(struct pl022 *pl022)
while (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
readw(SSP_DR(pl022->virtbase));
} while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_BSY) && limit--);
+
+ pl022->exp_fifo_level = 0;
+
return limit;
}
@@ -583,10 +587,9 @@ static void readwriter(struct pl022 *pl022)
* errons in 8bit wide transfers on ARM variants (just 8 words
* FIFO, means only 8x8 = 64 bits in FIFO) at least.
*
- * FIXME: currently we have no logic to account for this.
- * perhaps there is even something broken in HW regarding
- * 8bit transfers (it doesn't fail on 16bit) so this needs
- * more investigation...
+ * To prevent this issue, the TX FIFO is only filled to the
+ * unused RX FIFO fill length, regardless of what the TX
+ * FIFO status flag indicates.
*/
dev_dbg(&pl022->adev->dev,
"%s, rx: %p, rxend: %p, tx: %p, txend: %p\n",
@@ -613,11 +616,12 @@ static void readwriter(struct pl022 *pl022)
break;
}
pl022->rx += (pl022->cur_chip->n_bytes);
+ pl022->exp_fifo_level--;
}
/*
- * Write as much as you can, while keeping an eye on the RX FIFO!
+ * Write as much as possible up to the RX FIFO size
*/
- while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
+ while ((pl022->exp_fifo_level < pl022->vendor->fifodepth)
&& (pl022->tx < pl022->tx_end)) {
switch (pl022->write) {
case WRITING_NULL:
@@ -634,6 +638,7 @@ static void readwriter(struct pl022 *pl022)
break;
}
pl022->tx += (pl022->cur_chip->n_bytes);
+ pl022->exp_fifo_level++;
/*
* This inner reader takes care of things appearing in the RX
* FIFO as we're transmitting. This will happen a lot since the
@@ -660,6 +665,7 @@ static void readwriter(struct pl022 *pl022)
break;
}
pl022->rx += (pl022->cur_chip->n_bytes);
+ pl022->exp_fifo_level--;
}
}
/*
diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c
index cfd5ff9508fa..ba8ac4f599d3 100644
--- a/drivers/spi/au1550_spi.c
+++ b/drivers/spi/au1550_spi.c
@@ -412,11 +412,13 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
}
/* put buffers on the ring */
- res = au1xxx_dbdma_put_dest(hw->dma_rx_ch, hw->rx, t->len);
+ res = au1xxx_dbdma_put_dest(hw->dma_rx_ch, virt_to_phys(hw->rx),
+ t->len, DDMA_FLAGS_IE);
if (!res)
dev_err(hw->dev, "rx dma put dest error\n");
- res = au1xxx_dbdma_put_source(hw->dma_tx_ch, (void *)hw->tx, t->len);
+ res = au1xxx_dbdma_put_source(hw->dma_tx_ch, virt_to_phys(hw->tx),
+ t->len, DDMA_FLAGS_IE);
if (!res)
dev_err(hw->dev, "tx dma put source error\n");
diff --git a/drivers/spi/coldfire_qspi.c b/drivers/spi/coldfire_qspi.c
new file mode 100644
index 000000000000..59be3efe0636
--- /dev/null
+++ b/drivers/spi/coldfire_qspi.c
@@ -0,0 +1,640 @@
+/*
+ * Freescale/Motorola Coldfire Queued SPI driver
+ *
+ * Copyright 2010 Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
+ *
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/spi/spi.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfqspi.h>
+
+#define DRIVER_NAME "mcfqspi"
+
+#define MCFQSPI_BUSCLK (MCF_BUSCLK / 2)
+
+#define MCFQSPI_QMR 0x00
+#define MCFQSPI_QMR_MSTR 0x8000
+#define MCFQSPI_QMR_CPOL 0x0200
+#define MCFQSPI_QMR_CPHA 0x0100
+#define MCFQSPI_QDLYR 0x04
+#define MCFQSPI_QDLYR_SPE 0x8000
+#define MCFQSPI_QWR 0x08
+#define MCFQSPI_QWR_HALT 0x8000
+#define MCFQSPI_QWR_WREN 0x4000
+#define MCFQSPI_QWR_CSIV 0x1000
+#define MCFQSPI_QIR 0x0C
+#define MCFQSPI_QIR_WCEFB 0x8000
+#define MCFQSPI_QIR_ABRTB 0x4000
+#define MCFQSPI_QIR_ABRTL 0x1000
+#define MCFQSPI_QIR_WCEFE 0x0800
+#define MCFQSPI_QIR_ABRTE 0x0400
+#define MCFQSPI_QIR_SPIFE 0x0100
+#define MCFQSPI_QIR_WCEF 0x0008
+#define MCFQSPI_QIR_ABRT 0x0004
+#define MCFQSPI_QIR_SPIF 0x0001
+#define MCFQSPI_QAR 0x010
+#define MCFQSPI_QAR_TXBUF 0x00
+#define MCFQSPI_QAR_RXBUF 0x10
+#define MCFQSPI_QAR_CMDBUF 0x20
+#define MCFQSPI_QDR 0x014
+#define MCFQSPI_QCR 0x014
+#define MCFQSPI_QCR_CONT 0x8000
+#define MCFQSPI_QCR_BITSE 0x4000
+#define MCFQSPI_QCR_DT 0x2000
+
+struct mcfqspi {
+ void __iomem *iobase;
+ int irq;
+ struct clk *clk;
+ struct mcfqspi_cs_control *cs_control;
+
+ wait_queue_head_t waitq;
+
+ struct work_struct work;
+ struct workqueue_struct *workq;
+ spinlock_t lock;
+ struct list_head msgq;
+};
+
+static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val)
+{
+ writew(val, mcfqspi->iobase + MCFQSPI_QMR);
+}
+
+static void mcfqspi_wr_qdlyr(struct mcfqspi *mcfqspi, u16 val)
+{
+ writew(val, mcfqspi->iobase + MCFQSPI_QDLYR);
+}
+
+static u16 mcfqspi_rd_qdlyr(struct mcfqspi *mcfqspi)
+{
+ return readw(mcfqspi->iobase + MCFQSPI_QDLYR);
+}
+
+static void mcfqspi_wr_qwr(struct mcfqspi *mcfqspi, u16 val)
+{
+ writew(val, mcfqspi->iobase + MCFQSPI_QWR);
+}
+
+static void mcfqspi_wr_qir(struct mcfqspi *mcfqspi, u16 val)
+{
+ writew(val, mcfqspi->iobase + MCFQSPI_QIR);
+}
+
+static void mcfqspi_wr_qar(struct mcfqspi *mcfqspi, u16 val)
+{
+ writew(val, mcfqspi->iobase + MCFQSPI_QAR);
+}
+
+static void mcfqspi_wr_qdr(struct mcfqspi *mcfqspi, u16 val)
+{
+ writew(val, mcfqspi->iobase + MCFQSPI_QDR);
+}
+
+static u16 mcfqspi_rd_qdr(struct mcfqspi *mcfqspi)
+{
+ return readw(mcfqspi->iobase + MCFQSPI_QDR);
+}
+
+static void mcfqspi_cs_select(struct mcfqspi *mcfqspi, u8 chip_select,
+ bool cs_high)
+{
+ mcfqspi->cs_control->select(mcfqspi->cs_control, chip_select, cs_high);
+}
+
+static void mcfqspi_cs_deselect(struct mcfqspi *mcfqspi, u8 chip_select,
+ bool cs_high)
+{
+ mcfqspi->cs_control->deselect(mcfqspi->cs_control, chip_select, cs_high);
+}
+
+static int mcfqspi_cs_setup(struct mcfqspi *mcfqspi)
+{
+ return (mcfqspi->cs_control && mcfqspi->cs_control->setup) ?
+ mcfqspi->cs_control->setup(mcfqspi->cs_control) : 0;
+}
+
+static void mcfqspi_cs_teardown(struct mcfqspi *mcfqspi)
+{
+ if (mcfqspi->cs_control && mcfqspi->cs_control->teardown)
+ mcfqspi->cs_control->teardown(mcfqspi->cs_control);
+}
+
+static u8 mcfqspi_qmr_baud(u32 speed_hz)
+{
+ return clamp((MCFQSPI_BUSCLK + speed_hz - 1) / speed_hz, 2u, 255u);
+}
+
+static bool mcfqspi_qdlyr_spe(struct mcfqspi *mcfqspi)
+{
+ return mcfqspi_rd_qdlyr(mcfqspi) & MCFQSPI_QDLYR_SPE;
+}
+
+static irqreturn_t mcfqspi_irq_handler(int this_irq, void *dev_id)
+{
+ struct mcfqspi *mcfqspi = dev_id;
+
+ /* clear interrupt */
+ mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE | MCFQSPI_QIR_SPIF);
+ wake_up(&mcfqspi->waitq);
+
+ return IRQ_HANDLED;
+}
+
+static void mcfqspi_transfer_msg8(struct mcfqspi *mcfqspi, unsigned count,
+ const u8 *txbuf, u8 *rxbuf)
+{
+ unsigned i, n, offset = 0;
+
+ n = min(count, 16u);
+
+ mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_CMDBUF);
+ for (i = 0; i < n; ++i)
+ mcfqspi_wr_qdr(mcfqspi, MCFQSPI_QCR_BITSE);
+
+ mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_TXBUF);
+ if (txbuf)
+ for (i = 0; i < n; ++i)
+ mcfqspi_wr_qdr(mcfqspi, *txbuf++);
+ else
+ for (i = 0; i < count; ++i)
+ mcfqspi_wr_qdr(mcfqspi, 0);
+
+ count -= n;
+ if (count) {
+ u16 qwr = 0xf08;
+ mcfqspi_wr_qwr(mcfqspi, 0x700);
+ mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+
+ do {
+ wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
+ mcfqspi_wr_qwr(mcfqspi, qwr);
+ mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+ if (rxbuf) {
+ mcfqspi_wr_qar(mcfqspi,
+ MCFQSPI_QAR_RXBUF + offset);
+ for (i = 0; i < 8; ++i)
+ *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
+ }
+ n = min(count, 8u);
+ if (txbuf) {
+ mcfqspi_wr_qar(mcfqspi,
+ MCFQSPI_QAR_TXBUF + offset);
+ for (i = 0; i < n; ++i)
+ mcfqspi_wr_qdr(mcfqspi, *txbuf++);
+ }
+ qwr = (offset ? 0x808 : 0) + ((n - 1) << 8);
+ offset ^= 8;
+ count -= n;
+ } while (count);
+ wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
+ mcfqspi_wr_qwr(mcfqspi, qwr);
+ mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+ if (rxbuf) {
+ mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);
+ for (i = 0; i < 8; ++i)
+ *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
+ offset ^= 8;
+ }
+ } else {
+ mcfqspi_wr_qwr(mcfqspi, (n - 1) << 8);
+ mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+ }
+ wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
+ if (rxbuf) {
+ mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);
+ for (i = 0; i < n; ++i)
+ *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
+ }
+}
+
+static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count,
+ const u16 *txbuf, u16 *rxbuf)
+{
+ unsigned i, n, offset = 0;
+
+ n = min(count, 16u);
+
+ mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_CMDBUF);
+ for (i = 0; i < n; ++i)
+ mcfqspi_wr_qdr(mcfqspi, MCFQSPI_QCR_BITSE);
+
+ mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_TXBUF);
+ if (txbuf)
+ for (i = 0; i < n; ++i)
+ mcfqspi_wr_qdr(mcfqspi, *txbuf++);
+ else
+ for (i = 0; i < count; ++i)
+ mcfqspi_wr_qdr(mcfqspi, 0);
+
+ count -= n;
+ if (count) {
+ u16 qwr = 0xf08;
+ mcfqspi_wr_qwr(mcfqspi, 0x700);
+ mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+
+ do {
+ wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
+ mcfqspi_wr_qwr(mcfqspi, qwr);
+ mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+ if (rxbuf) {
+ mcfqspi_wr_qar(mcfqspi,
+ MCFQSPI_QAR_RXBUF + offset);
+ for (i = 0; i < 8; ++i)
+ *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
+ }
+ n = min(count, 8u);
+ if (txbuf) {
+ mcfqspi_wr_qar(mcfqspi,
+ MCFQSPI_QAR_TXBUF + offset);
+ for (i = 0; i < n; ++i)
+ mcfqspi_wr_qdr(mcfqspi, *txbuf++);
+ }
+ qwr = (offset ? 0x808 : 0x000) + ((n - 1) << 8);
+ offset ^= 8;
+ count -= n;
+ } while (count);
+ wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
+ mcfqspi_wr_qwr(mcfqspi, qwr);
+ mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+ if (rxbuf) {
+ mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);
+ for (i = 0; i < 8; ++i)
+ *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
+ offset ^= 8;
+ }
+ } else {
+ mcfqspi_wr_qwr(mcfqspi, (n - 1) << 8);
+ mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+ }
+ wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
+ if (rxbuf) {
+ mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);
+ for (i = 0; i < n; ++i)
+ *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
+ }
+}
+
+static void mcfqspi_work(struct work_struct *work)
+{
+ struct mcfqspi *mcfqspi = container_of(work, struct mcfqspi, work);
+ unsigned long flags;
+
+ spin_lock_irqsave(&mcfqspi->lock, flags);
+ while (!list_empty(&mcfqspi->msgq)) {
+ struct spi_message *msg;
+ struct spi_device *spi;
+ struct spi_transfer *xfer;
+ int status = 0;
+
+ msg = container_of(mcfqspi->msgq.next, struct spi_message,
+ queue);
+
+ list_del_init(&mcfqspi->msgq);
+ spin_unlock_irqrestore(&mcfqspi->lock, flags);
+
+ spi = msg->spi;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ bool cs_high = spi->mode & SPI_CS_HIGH;
+ u16 qmr = MCFQSPI_QMR_MSTR;
+
+ if (xfer->bits_per_word)
+ qmr |= xfer->bits_per_word << 10;
+ else
+ qmr |= spi->bits_per_word << 10;
+ if (spi->mode & SPI_CPHA)
+ qmr |= MCFQSPI_QMR_CPHA;
+ if (spi->mode & SPI_CPOL)
+ qmr |= MCFQSPI_QMR_CPOL;
+ if (xfer->speed_hz)
+ qmr |= mcfqspi_qmr_baud(xfer->speed_hz);
+ else
+ qmr |= mcfqspi_qmr_baud(spi->max_speed_hz);
+ mcfqspi_wr_qmr(mcfqspi, qmr);
+
+ mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
+
+ mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
+ if ((xfer->bits_per_word ? xfer->bits_per_word :
+ spi->bits_per_word) == 8)
+ mcfqspi_transfer_msg8(mcfqspi, xfer->len,
+ xfer->tx_buf,
+ xfer->rx_buf);
+ else
+ mcfqspi_transfer_msg16(mcfqspi, xfer->len / 2,
+ xfer->tx_buf,
+ xfer->rx_buf);
+ mcfqspi_wr_qir(mcfqspi, 0);
+
+ if (xfer->delay_usecs)
+ udelay(xfer->delay_usecs);
+ if (xfer->cs_change) {
+ if (!list_is_last(&xfer->transfer_list,
+ &msg->transfers))
+ mcfqspi_cs_deselect(mcfqspi,
+ spi->chip_select,
+ cs_high);
+ } else {
+ if (list_is_last(&xfer->transfer_list,
+ &msg->transfers))
+ mcfqspi_cs_deselect(mcfqspi,
+ spi->chip_select,
+ cs_high);
+ }
+ msg->actual_length += xfer->len;
+ }
+ msg->status = status;
+ msg->complete(msg->context);
+
+ spin_lock_irqsave(&mcfqspi->lock, flags);
+ }
+ spin_unlock_irqrestore(&mcfqspi->lock, flags);
+}
+
+static int mcfqspi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+ struct mcfqspi *mcfqspi;
+ struct spi_transfer *xfer;
+ unsigned long flags;
+
+ mcfqspi = spi_master_get_devdata(spi->master);
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (xfer->bits_per_word && ((xfer->bits_per_word < 8)
+ || (xfer->bits_per_word > 16))) {
+ dev_dbg(&spi->dev,
+ "%d bits per word is not supported\n",
+ xfer->bits_per_word);
+ goto fail;
+ }
+ if (xfer->speed_hz) {
+ u32 real_speed = MCFQSPI_BUSCLK /
+ mcfqspi_qmr_baud(xfer->speed_hz);
+ if (real_speed != xfer->speed_hz)
+ dev_dbg(&spi->dev,
+ "using speed %d instead of %d\n",
+ real_speed, xfer->speed_hz);
+ }
+ }
+ msg->status = -EINPROGRESS;
+ msg->actual_length = 0;
+
+ spin_lock_irqsave(&mcfqspi->lock, flags);
+ list_add_tail(&msg->queue, &mcfqspi->msgq);
+ queue_work(mcfqspi->workq, &mcfqspi->work);
+ spin_unlock_irqrestore(&mcfqspi->lock, flags);
+
+ return 0;
+fail:
+ msg->status = -EINVAL;
+ return -EINVAL;
+}
+
+static int mcfqspi_setup(struct spi_device *spi)
+{
+ if ((spi->bits_per_word < 8) || (spi->bits_per_word > 16)) {
+ dev_dbg(&spi->dev, "%d bits per word is not supported\n",
+ spi->bits_per_word);
+ return -EINVAL;
+ }
+ if (spi->chip_select >= spi->master->num_chipselect) {
+ dev_dbg(&spi->dev, "%d chip select is out of range\n",
+ spi->chip_select);
+ return -EINVAL;
+ }
+
+ mcfqspi_cs_deselect(spi_master_get_devdata(spi->master),
+ spi->chip_select, spi->mode & SPI_CS_HIGH);
+
+ dev_dbg(&spi->dev,
+ "bits per word %d, chip select %d, speed %d KHz\n",
+ spi->bits_per_word, spi->chip_select,
+ (MCFQSPI_BUSCLK / mcfqspi_qmr_baud(spi->max_speed_hz))
+ / 1000);
+
+ return 0;
+}
+
+static int __devinit mcfqspi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct mcfqspi *mcfqspi;
+ struct resource *res;
+ struct mcfqspi_platform_data *pdata;
+ int status;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
+ if (master == NULL) {
+ dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
+ return -ENOMEM;
+ }
+
+ mcfqspi = spi_master_get_devdata(master);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "platform_get_resource failed\n");
+ status = -ENXIO;
+ goto fail0;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+ dev_dbg(&pdev->dev, "request_mem_region failed\n");
+ status = -EBUSY;
+ goto fail0;
+ }
+
+ mcfqspi->iobase = ioremap(res->start, resource_size(res));
+ if (!mcfqspi->iobase) {
+ dev_dbg(&pdev->dev, "ioremap failed\n");
+ status = -ENOMEM;
+ goto fail1;
+ }
+
+ mcfqspi->irq = platform_get_irq(pdev, 0);
+ if (mcfqspi->irq < 0) {
+ dev_dbg(&pdev->dev, "platform_get_irq failed\n");
+ status = -ENXIO;
+ goto fail2;
+ }
+
+ status = request_irq(mcfqspi->irq, mcfqspi_irq_handler, IRQF_DISABLED,
+ pdev->name, mcfqspi);
+ if (status) {
+ dev_dbg(&pdev->dev, "request_irq failed\n");
+ goto fail2;
+ }
+
+ mcfqspi->clk = clk_get(&pdev->dev, "qspi_clk");
+ if (IS_ERR(mcfqspi->clk)) {
+ dev_dbg(&pdev->dev, "clk_get failed\n");
+ status = PTR_ERR(mcfqspi->clk);
+ goto fail3;
+ }
+ clk_enable(mcfqspi->clk);
+
+ mcfqspi->workq = create_singlethread_workqueue(dev_name(master->dev.parent));
+ if (!mcfqspi->workq) {
+ dev_dbg(&pdev->dev, "create_workqueue failed\n");
+ status = -ENOMEM;
+ goto fail4;
+ }
+ INIT_WORK(&mcfqspi->work, mcfqspi_work);
+ spin_lock_init(&mcfqspi->lock);
+ INIT_LIST_HEAD(&mcfqspi->msgq);
+ init_waitqueue_head(&mcfqspi->waitq);
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_dbg(&pdev->dev, "platform data is missing\n");
+ goto fail5;
+ }
+ master->bus_num = pdata->bus_num;
+ master->num_chipselect = pdata->num_chipselect;
+
+ mcfqspi->cs_control = pdata->cs_control;
+ status = mcfqspi_cs_setup(mcfqspi);
+ if (status) {
+ dev_dbg(&pdev->dev, "error initializing cs_control\n");
+ goto fail5;
+ }
+
+ master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
+ master->setup = mcfqspi_setup;
+ master->transfer = mcfqspi_transfer;
+
+ platform_set_drvdata(pdev, master);
+
+ status = spi_register_master(master);
+ if (status) {
+ dev_dbg(&pdev->dev, "spi_register_master failed\n");
+ goto fail6;
+ }
+ dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");
+
+ return 0;
+
+fail6:
+ mcfqspi_cs_teardown(mcfqspi);
+fail5:
+ destroy_workqueue(mcfqspi->workq);
+fail4:
+ clk_disable(mcfqspi->clk);
+ clk_put(mcfqspi->clk);
+fail3:
+ free_irq(mcfqspi->irq, mcfqspi);
+fail2:
+ iounmap(mcfqspi->iobase);
+fail1:
+ release_mem_region(res->start, resource_size(res));
+fail0:
+ spi_master_put(master);
+
+ dev_dbg(&pdev->dev, "Coldfire QSPI probe failed\n");
+
+ return status;
+}
+
+static int __devexit mcfqspi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ /* disable the hardware (set the baud rate to 0) */
+ mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
+
+ platform_set_drvdata(pdev, NULL);
+ mcfqspi_cs_teardown(mcfqspi);
+ destroy_workqueue(mcfqspi->workq);
+ clk_disable(mcfqspi->clk);
+ clk_put(mcfqspi->clk);
+ free_irq(mcfqspi->irq, mcfqspi);
+ iounmap(mcfqspi->iobase);
+ release_mem_region(res->start, resource_size(res));
+ spi_unregister_master(master);
+ spi_master_put(master);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int mcfqspi_suspend(struct device *dev)
+{
+ struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
+
+ clk_disable(mcfqspi->clk);
+
+ return 0;
+}
+
+static int mcfqspi_resume(struct device *dev)
+{
+ struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
+
+ clk_enable(mcfqspi->clk);
+
+ return 0;
+}
+
+static struct dev_pm_ops mcfqspi_dev_pm_ops = {
+ .suspend = mcfqspi_suspend,
+ .resume = mcfqspi_resume,
+};
+
+#define MCFQSPI_DEV_PM_OPS (&mcfqspi_dev_pm_ops)
+#else
+#define MCFQSPI_DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver mcfqspi_driver = {
+ .driver.name = DRIVER_NAME,
+ .driver.owner = THIS_MODULE,
+ .driver.pm = MCFQSPI_DEV_PM_OPS,
+ .remove = __devexit_p(mcfqspi_remove),
+};
+
+static int __init mcfqspi_init(void)
+{
+ return platform_driver_probe(&mcfqspi_driver, mcfqspi_probe);
+}
+module_init(mcfqspi_init);
+
+static void __exit mcfqspi_exit(void)
+{
+ platform_driver_unregister(&mcfqspi_driver);
+}
+module_exit(mcfqspi_exit);
+
+MODULE_AUTHOR("Steven King <sfking@fdwdc.com>");
+MODULE_DESCRIPTION("Coldfire QSPI Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
new file mode 100644
index 000000000000..225ab60b02c4
--- /dev/null
+++ b/drivers/spi/davinci_spi.c
@@ -0,0 +1,1255 @@
+/*
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <mach/spi.h>
+#include <mach/edma.h>
+
+#define SPI_NO_RESOURCE ((resource_size_t)-1)
+
+#define SPI_MAX_CHIPSELECT 2
+
+#define CS_DEFAULT 0xFF
+
+#define SPI_BUFSIZ (SMP_CACHE_BYTES + 1)
+#define DAVINCI_DMA_DATA_TYPE_S8 0x01
+#define DAVINCI_DMA_DATA_TYPE_S16 0x02
+#define DAVINCI_DMA_DATA_TYPE_S32 0x04
+
+#define SPIFMT_PHASE_MASK BIT(16)
+#define SPIFMT_POLARITY_MASK BIT(17)
+#define SPIFMT_DISTIMER_MASK BIT(18)
+#define SPIFMT_SHIFTDIR_MASK BIT(20)
+#define SPIFMT_WAITENA_MASK BIT(21)
+#define SPIFMT_PARITYENA_MASK BIT(22)
+#define SPIFMT_ODD_PARITY_MASK BIT(23)
+#define SPIFMT_WDELAY_MASK 0x3f000000u
+#define SPIFMT_WDELAY_SHIFT 24
+#define SPIFMT_CHARLEN_MASK 0x0000001Fu
+
+/* SPIGCR1 */
+#define SPIGCR1_SPIENA_MASK 0x01000000u
+
+/* SPIPC0 */
+#define SPIPC0_DIFUN_MASK BIT(11) /* MISO */
+#define SPIPC0_DOFUN_MASK BIT(10) /* MOSI */
+#define SPIPC0_CLKFUN_MASK BIT(9) /* CLK */
+#define SPIPC0_SPIENA_MASK BIT(8) /* nREADY */
+#define SPIPC0_EN1FUN_MASK BIT(1)
+#define SPIPC0_EN0FUN_MASK BIT(0)
+
+#define SPIINT_MASKALL 0x0101035F
+#define SPI_INTLVL_1 0x000001FFu
+#define SPI_INTLVL_0 0x00000000u
+
+/* SPIDAT1 */
+#define SPIDAT1_CSHOLD_SHIFT 28
+#define SPIDAT1_CSNR_SHIFT 16
+#define SPIGCR1_CLKMOD_MASK BIT(1)
+#define SPIGCR1_MASTER_MASK BIT(0)
+#define SPIGCR1_LOOPBACK_MASK BIT(16)
+
+/* SPIBUF */
+#define SPIBUF_TXFULL_MASK BIT(29)
+#define SPIBUF_RXEMPTY_MASK BIT(31)
+
+/* Error Masks */
+#define SPIFLG_DLEN_ERR_MASK BIT(0)
+#define SPIFLG_TIMEOUT_MASK BIT(1)
+#define SPIFLG_PARERR_MASK BIT(2)
+#define SPIFLG_DESYNC_MASK BIT(3)
+#define SPIFLG_BITERR_MASK BIT(4)
+#define SPIFLG_OVRRUN_MASK BIT(6)
+#define SPIFLG_RX_INTR_MASK BIT(8)
+#define SPIFLG_TX_INTR_MASK BIT(9)
+#define SPIFLG_BUF_INIT_ACTIVE_MASK BIT(24)
+#define SPIFLG_MASK (SPIFLG_DLEN_ERR_MASK \
+ | SPIFLG_TIMEOUT_MASK | SPIFLG_PARERR_MASK \
+ | SPIFLG_DESYNC_MASK | SPIFLG_BITERR_MASK \
+ | SPIFLG_OVRRUN_MASK | SPIFLG_RX_INTR_MASK \
+ | SPIFLG_TX_INTR_MASK \
+ | SPIFLG_BUF_INIT_ACTIVE_MASK)
+
+#define SPIINT_DLEN_ERR_INTR BIT(0)
+#define SPIINT_TIMEOUT_INTR BIT(1)
+#define SPIINT_PARERR_INTR BIT(2)
+#define SPIINT_DESYNC_INTR BIT(3)
+#define SPIINT_BITERR_INTR BIT(4)
+#define SPIINT_OVRRUN_INTR BIT(6)
+#define SPIINT_RX_INTR BIT(8)
+#define SPIINT_TX_INTR BIT(9)
+#define SPIINT_DMA_REQ_EN BIT(16)
+#define SPIINT_ENABLE_HIGHZ BIT(24)
+
+#define SPI_T2CDELAY_SHIFT 16
+#define SPI_C2TDELAY_SHIFT 24
+
+/* SPI Controller registers */
+#define SPIGCR0 0x00
+#define SPIGCR1 0x04
+#define SPIINT 0x08
+#define SPILVL 0x0c
+#define SPIFLG 0x10
+#define SPIPC0 0x14
+#define SPIPC1 0x18
+#define SPIPC2 0x1c
+#define SPIPC3 0x20
+#define SPIPC4 0x24
+#define SPIPC5 0x28
+#define SPIPC6 0x2c
+#define SPIPC7 0x30
+#define SPIPC8 0x34
+#define SPIDAT0 0x38
+#define SPIDAT1 0x3c
+#define SPIBUF 0x40
+#define SPIEMU 0x44
+#define SPIDELAY 0x48
+#define SPIDEF 0x4c
+#define SPIFMT0 0x50
+#define SPIFMT1 0x54
+#define SPIFMT2 0x58
+#define SPIFMT3 0x5c
+#define TGINTVEC0 0x60
+#define TGINTVEC1 0x64
+
+struct davinci_spi_slave {
+ u32 cmd_to_write;
+ u32 clk_ctrl_to_write;
+ u32 bytes_per_word;
+ u8 active_cs;
+};
+
+/* We have 2 DMA channels per CS, one for RX and one for TX */
+struct davinci_spi_dma {
+ int dma_tx_channel;
+ int dma_rx_channel;
+ int dma_tx_sync_dev;
+ int dma_rx_sync_dev;
+ enum dma_event_q eventq;
+
+ struct completion dma_tx_completion;
+ struct completion dma_rx_completion;
+};
+
+/* SPI Controller driver's private data. */
+struct davinci_spi {
+ struct spi_bitbang bitbang;
+ struct clk *clk;
+
+ u8 version;
+ resource_size_t pbase;
+ void __iomem *base;
+ size_t region_size;
+ u32 irq;
+ struct completion done;
+
+ const void *tx;
+ void *rx;
+ u8 *tmp_buf;
+ int count;
+ struct davinci_spi_dma *dma_channels;
+ struct davinci_spi_platform_data *pdata;
+
+ void (*get_rx)(u32 rx_data, struct davinci_spi *);
+ u32 (*get_tx)(struct davinci_spi *);
+
+ struct davinci_spi_slave slave[SPI_MAX_CHIPSELECT];
+};
+
+static unsigned use_dma;
+
+static void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *davinci_spi)
+{
+ u8 *rx = davinci_spi->rx;
+
+ *rx++ = (u8)data;
+ davinci_spi->rx = rx;
+}
+
+static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *davinci_spi)
+{
+ u16 *rx = davinci_spi->rx;
+
+ *rx++ = (u16)data;
+ davinci_spi->rx = rx;
+}
+
+static u32 davinci_spi_tx_buf_u8(struct davinci_spi *davinci_spi)
+{
+ u32 data;
+ const u8 *tx = davinci_spi->tx;
+
+ data = *tx++;
+ davinci_spi->tx = tx;
+ return data;
+}
+
+static u32 davinci_spi_tx_buf_u16(struct davinci_spi *davinci_spi)
+{
+ u32 data;
+ const u16 *tx = davinci_spi->tx;
+
+ data = *tx++;
+ davinci_spi->tx = tx;
+ return data;
+}
+
+static inline void set_io_bits(void __iomem *addr, u32 bits)
+{
+ u32 v = ioread32(addr);
+
+ v |= bits;
+ iowrite32(v, addr);
+}
+
+static inline void clear_io_bits(void __iomem *addr, u32 bits)
+{
+ u32 v = ioread32(addr);
+
+ v &= ~bits;
+ iowrite32(v, addr);
+}
+
+static inline void set_fmt_bits(void __iomem *addr, u32 bits, int cs_num)
+{
+ set_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits);
+}
+
+static inline void clear_fmt_bits(void __iomem *addr, u32 bits, int cs_num)
+{
+ clear_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits);
+}
+
+static void davinci_spi_set_dma_req(const struct spi_device *spi, int enable)
+{
+ struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master);
+
+ if (enable)
+ set_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN);
+ else
+ clear_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN);
+}
+
+/*
+ * Interface to control the chip select signal
+ */
+static void davinci_spi_chipselect(struct spi_device *spi, int value)
+{
+ struct davinci_spi *davinci_spi;
+ struct davinci_spi_platform_data *pdata;
+ u32 data1_reg_val = 0;
+
+ davinci_spi = spi_master_get_devdata(spi->master);
+ pdata = davinci_spi->pdata;
+
+ /*
+ * Board specific chip select logic decides the polarity and cs
+ * line for the controller
+ */
+ if (value == BITBANG_CS_INACTIVE) {
+ set_io_bits(davinci_spi->base + SPIDEF, CS_DEFAULT);
+
+ data1_reg_val |= CS_DEFAULT << SPIDAT1_CSNR_SHIFT;
+ iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
+
+ while ((ioread32(davinci_spi->base + SPIBUF)
+ & SPIBUF_RXEMPTY_MASK) == 0)
+ cpu_relax();
+ }
+}
+
+/**
+ * davinci_spi_setup_transfer - This functions will determine transfer method
+ * @spi: spi device on which data transfer to be done
+ * @t: spi transfer in which transfer info is filled
+ *
+ * This function determines data transfer method (8/16/32 bit transfer).
+ * It will also set the SPI Clock Control register according to
+ * SPI slave device freq.
+ */
+static int davinci_spi_setup_transfer(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+
+ struct davinci_spi *davinci_spi;
+ struct davinci_spi_platform_data *pdata;
+ u8 bits_per_word = 0;
+ u32 hz = 0, prescale;
+
+ davinci_spi = spi_master_get_devdata(spi->master);
+ pdata = davinci_spi->pdata;
+
+ if (t) {
+ bits_per_word = t->bits_per_word;
+ hz = t->speed_hz;
+ }
+
+ /* if bits_per_word is not set then set it default */
+ if (!bits_per_word)
+ bits_per_word = spi->bits_per_word;
+
+ /*
+ * Assign function pointer to appropriate transfer method
+ * 8bit, 16bit or 32bit transfer
+ */
+ if (bits_per_word <= 8 && bits_per_word >= 2) {
+ davinci_spi->get_rx = davinci_spi_rx_buf_u8;
+ davinci_spi->get_tx = davinci_spi_tx_buf_u8;
+ davinci_spi->slave[spi->chip_select].bytes_per_word = 1;
+ } else if (bits_per_word <= 16 && bits_per_word >= 2) {
+ davinci_spi->get_rx = davinci_spi_rx_buf_u16;
+ davinci_spi->get_tx = davinci_spi_tx_buf_u16;
+ davinci_spi->slave[spi->chip_select].bytes_per_word = 2;
+ } else
+ return -EINVAL;
+
+ if (!hz)
+ hz = spi->max_speed_hz;
+
+ clear_fmt_bits(davinci_spi->base, SPIFMT_CHARLEN_MASK,
+ spi->chip_select);
+ set_fmt_bits(davinci_spi->base, bits_per_word & 0x1f,
+ spi->chip_select);
+
+ prescale = ((clk_get_rate(davinci_spi->clk) / hz) - 1) & 0xff;
+
+ clear_fmt_bits(davinci_spi->base, 0x0000ff00, spi->chip_select);
+ set_fmt_bits(davinci_spi->base, prescale << 8, spi->chip_select);
+
+ return 0;
+}
+
+static void davinci_spi_dma_rx_callback(unsigned lch, u16 ch_status, void *data)
+{
+ struct spi_device *spi = (struct spi_device *)data;
+ struct davinci_spi *davinci_spi;
+ struct davinci_spi_dma *davinci_spi_dma;
+ struct davinci_spi_platform_data *pdata;
+
+ davinci_spi = spi_master_get_devdata(spi->master);
+ davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]);
+ pdata = davinci_spi->pdata;
+
+ if (ch_status == DMA_COMPLETE)
+ edma_stop(davinci_spi_dma->dma_rx_channel);
+ else
+ edma_clean_channel(davinci_spi_dma->dma_rx_channel);
+
+ complete(&davinci_spi_dma->dma_rx_completion);
+ /* We must disable the DMA RX request */
+ davinci_spi_set_dma_req(spi, 0);
+}
+
+static void davinci_spi_dma_tx_callback(unsigned lch, u16 ch_status, void *data)
+{
+ struct spi_device *spi = (struct spi_device *)data;
+ struct davinci_spi *davinci_spi;
+ struct davinci_spi_dma *davinci_spi_dma;
+ struct davinci_spi_platform_data *pdata;
+
+ davinci_spi = spi_master_get_devdata(spi->master);
+ davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]);
+ pdata = davinci_spi->pdata;
+
+ if (ch_status == DMA_COMPLETE)
+ edma_stop(davinci_spi_dma->dma_tx_channel);
+ else
+ edma_clean_channel(davinci_spi_dma->dma_tx_channel);
+
+ complete(&davinci_spi_dma->dma_tx_completion);
+ /* We must disable the DMA TX request */
+ davinci_spi_set_dma_req(spi, 0);
+}
+
+static int davinci_spi_request_dma(struct spi_device *spi)
+{
+ struct davinci_spi *davinci_spi;
+ struct davinci_spi_dma *davinci_spi_dma;
+ struct davinci_spi_platform_data *pdata;
+ struct device *sdev;
+ int r;
+
+ davinci_spi = spi_master_get_devdata(spi->master);
+ davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
+ pdata = davinci_spi->pdata;
+ sdev = davinci_spi->bitbang.master->dev.parent;
+
+ r = edma_alloc_channel(davinci_spi_dma->dma_rx_sync_dev,
+ davinci_spi_dma_rx_callback, spi,
+ davinci_spi_dma->eventq);
+ if (r < 0) {
+ dev_dbg(sdev, "Unable to request DMA channel for SPI RX\n");
+ return -EAGAIN;
+ }
+ davinci_spi_dma->dma_rx_channel = r;
+ r = edma_alloc_channel(davinci_spi_dma->dma_tx_sync_dev,
+ davinci_spi_dma_tx_callback, spi,
+ davinci_spi_dma->eventq);
+ if (r < 0) {
+ edma_free_channel(davinci_spi_dma->dma_rx_channel);
+ davinci_spi_dma->dma_rx_channel = -1;
+ dev_dbg(sdev, "Unable to request DMA channel for SPI TX\n");
+ return -EAGAIN;
+ }
+ davinci_spi_dma->dma_tx_channel = r;
+
+ return 0;
+}
+
+/**
+ * davinci_spi_setup - This functions will set default transfer method
+ * @spi: spi device on which data transfer to be done
+ *
+ * This functions sets the default transfer method.
+ */
+
+static int davinci_spi_setup(struct spi_device *spi)
+{
+ int retval;
+ struct davinci_spi *davinci_spi;
+ struct davinci_spi_dma *davinci_spi_dma;
+ struct device *sdev;
+
+ davinci_spi = spi_master_get_devdata(spi->master);
+ sdev = davinci_spi->bitbang.master->dev.parent;
+
+ /* if bits per word length is zero then set it default 8 */
+ if (!spi->bits_per_word)
+ spi->bits_per_word = 8;
+
+ davinci_spi->slave[spi->chip_select].cmd_to_write = 0;
+
+ if (use_dma && davinci_spi->dma_channels) {
+ davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
+
+ if ((davinci_spi_dma->dma_rx_channel == -1)
+ || (davinci_spi_dma->dma_tx_channel == -1)) {
+ retval = davinci_spi_request_dma(spi);
+ if (retval < 0)
+ return retval;
+ }
+ }
+
+ /*
+ * SPI in DaVinci and DA8xx operate between
+ * 600 KHz and 50 MHz
+ */
+ if (spi->max_speed_hz < 600000 || spi->max_speed_hz > 50000000) {
+ dev_dbg(sdev, "Operating frequency is not in acceptable "
+ "range\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Set up SPIFMTn register, unique to this chipselect.
+ *
+ * NOTE: we could do all of these with one write. Also, some
+ * of the "version 2" features are found in chips that don't
+ * support all of them...
+ */
+ if (spi->mode & SPI_LSB_FIRST)
+ set_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK,
+ spi->chip_select);
+ else
+ clear_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK,
+ spi->chip_select);
+
+ if (spi->mode & SPI_CPOL)
+ set_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK,
+ spi->chip_select);
+ else
+ clear_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK,
+ spi->chip_select);
+
+ if (!(spi->mode & SPI_CPHA))
+ set_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK,
+ spi->chip_select);
+ else
+ clear_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK,
+ spi->chip_select);
+
+ /*
+ * Version 1 hardware supports two basic SPI modes:
+ * - Standard SPI mode uses 4 pins, with chipselect
+ * - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS)
+ * (distinct from SPI_3WIRE, with just one data wire;
+ * or similar variants without MOSI or without MISO)
+ *
+ * Version 2 hardware supports an optional handshaking signal,
+ * so it can support two more modes:
+ * - 5 pin SPI variant is standard SPI plus SPI_READY
+ * - 4 pin with enable is (SPI_READY | SPI_NO_CS)
+ */
+
+ if (davinci_spi->version == SPI_VERSION_2) {
+ clear_fmt_bits(davinci_spi->base, SPIFMT_WDELAY_MASK,
+ spi->chip_select);
+ set_fmt_bits(davinci_spi->base,
+ (davinci_spi->pdata->wdelay
+ << SPIFMT_WDELAY_SHIFT)
+ & SPIFMT_WDELAY_MASK,
+ spi->chip_select);
+
+ if (davinci_spi->pdata->odd_parity)
+ set_fmt_bits(davinci_spi->base,
+ SPIFMT_ODD_PARITY_MASK,
+ spi->chip_select);
+ else
+ clear_fmt_bits(davinci_spi->base,
+ SPIFMT_ODD_PARITY_MASK,
+ spi->chip_select);
+
+ if (davinci_spi->pdata->parity_enable)
+ set_fmt_bits(davinci_spi->base,
+ SPIFMT_PARITYENA_MASK,
+ spi->chip_select);
+ else
+ clear_fmt_bits(davinci_spi->base,
+ SPIFMT_PARITYENA_MASK,
+ spi->chip_select);
+
+ if (davinci_spi->pdata->wait_enable)
+ set_fmt_bits(davinci_spi->base,
+ SPIFMT_WAITENA_MASK,
+ spi->chip_select);
+ else
+ clear_fmt_bits(davinci_spi->base,
+ SPIFMT_WAITENA_MASK,
+ spi->chip_select);
+
+ if (davinci_spi->pdata->timer_disable)
+ set_fmt_bits(davinci_spi->base,
+ SPIFMT_DISTIMER_MASK,
+ spi->chip_select);
+ else
+ clear_fmt_bits(davinci_spi->base,
+ SPIFMT_DISTIMER_MASK,
+ spi->chip_select);
+ }
+
+ retval = davinci_spi_setup_transfer(spi, NULL);
+
+ return retval;
+}
+
+static void davinci_spi_cleanup(struct spi_device *spi)
+{
+ struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master);
+ struct davinci_spi_dma *davinci_spi_dma;
+
+ davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
+
+ if (use_dma && davinci_spi->dma_channels) {
+ davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
+
+ if ((davinci_spi_dma->dma_rx_channel != -1)
+ && (davinci_spi_dma->dma_tx_channel != -1)) {
+ edma_free_channel(davinci_spi_dma->dma_tx_channel);
+ edma_free_channel(davinci_spi_dma->dma_rx_channel);
+ }
+ }
+}
+
+static int davinci_spi_bufs_prep(struct spi_device *spi,
+ struct davinci_spi *davinci_spi)
+{
+ int op_mode = 0;
+
+ /*
+ * REVISIT unless devices disagree about SPI_LOOP or
+ * SPI_READY (SPI_NO_CS only allows one device!), this
+ * should not need to be done before each message...
+ * optimize for both flags staying cleared.
+ */
+
+ op_mode = SPIPC0_DIFUN_MASK
+ | SPIPC0_DOFUN_MASK
+ | SPIPC0_CLKFUN_MASK;
+ if (!(spi->mode & SPI_NO_CS))
+ op_mode |= 1 << spi->chip_select;
+ if (spi->mode & SPI_READY)
+ op_mode |= SPIPC0_SPIENA_MASK;
+
+ iowrite32(op_mode, davinci_spi->base + SPIPC0);
+
+ if (spi->mode & SPI_LOOP)
+ set_io_bits(davinci_spi->base + SPIGCR1,
+ SPIGCR1_LOOPBACK_MASK);
+ else
+ clear_io_bits(davinci_spi->base + SPIGCR1,
+ SPIGCR1_LOOPBACK_MASK);
+
+ return 0;
+}
+
+static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
+ int int_status)
+{
+ struct device *sdev = davinci_spi->bitbang.master->dev.parent;
+
+ if (int_status & SPIFLG_TIMEOUT_MASK) {
+ dev_dbg(sdev, "SPI Time-out Error\n");
+ return -ETIMEDOUT;
+ }
+ if (int_status & SPIFLG_DESYNC_MASK) {
+ dev_dbg(sdev, "SPI Desynchronization Error\n");
+ return -EIO;
+ }
+ if (int_status & SPIFLG_BITERR_MASK) {
+ dev_dbg(sdev, "SPI Bit error\n");
+ return -EIO;
+ }
+
+ if (davinci_spi->version == SPI_VERSION_2) {
+ if (int_status & SPIFLG_DLEN_ERR_MASK) {
+ dev_dbg(sdev, "SPI Data Length Error\n");
+ return -EIO;
+ }
+ if (int_status & SPIFLG_PARERR_MASK) {
+ dev_dbg(sdev, "SPI Parity Error\n");
+ return -EIO;
+ }
+ if (int_status & SPIFLG_OVRRUN_MASK) {
+ dev_dbg(sdev, "SPI Data Overrun error\n");
+ return -EIO;
+ }
+ if (int_status & SPIFLG_TX_INTR_MASK) {
+ dev_dbg(sdev, "SPI TX intr bit set\n");
+ return -EIO;
+ }
+ if (int_status & SPIFLG_BUF_INIT_ACTIVE_MASK) {
+ dev_dbg(sdev, "SPI Buffer Init Active\n");
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * davinci_spi_bufs - functions which will handle transfer data
+ * @spi: spi device on which data transfer to be done
+ * @t: spi transfer in which transfer info is filled
+ *
+ * This function will put data to be transferred into data register
+ * of SPI controller and then wait until the completion will be marked
+ * by the IRQ Handler.
+ */
+static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct davinci_spi *davinci_spi;
+ int int_status, count, ret;
+ u8 conv, tmp;
+ u32 tx_data, data1_reg_val;
+ u32 buf_val, flg_val;
+ struct davinci_spi_platform_data *pdata;
+
+ davinci_spi = spi_master_get_devdata(spi->master);
+ pdata = davinci_spi->pdata;
+
+ davinci_spi->tx = t->tx_buf;
+ davinci_spi->rx = t->rx_buf;
+
+ /* convert len to words based on bits_per_word */
+ conv = davinci_spi->slave[spi->chip_select].bytes_per_word;
+ davinci_spi->count = t->len / conv;
+
+ INIT_COMPLETION(davinci_spi->done);
+
+ ret = davinci_spi_bufs_prep(spi, davinci_spi);
+ if (ret)
+ return ret;
+
+ /* Enable SPI */
+ set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
+
+ iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) |
+ (pdata->t2cdelay << SPI_T2CDELAY_SHIFT),
+ davinci_spi->base + SPIDELAY);
+
+ count = davinci_spi->count;
+ data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT;
+ tmp = ~(0x1 << spi->chip_select);
+
+ clear_io_bits(davinci_spi->base + SPIDEF, ~tmp);
+
+ data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT;
+
+ while ((ioread32(davinci_spi->base + SPIBUF)
+ & SPIBUF_RXEMPTY_MASK) == 0)
+ cpu_relax();
+
+ /* Determine the command to execute READ or WRITE */
+ if (t->tx_buf) {
+ clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL);
+
+ while (1) {
+ tx_data = davinci_spi->get_tx(davinci_spi);
+
+ data1_reg_val &= ~(0xFFFF);
+ data1_reg_val |= (0xFFFF & tx_data);
+
+ buf_val = ioread32(davinci_spi->base + SPIBUF);
+ if ((buf_val & SPIBUF_TXFULL_MASK) == 0) {
+ iowrite32(data1_reg_val,
+ davinci_spi->base + SPIDAT1);
+
+ count--;
+ }
+ while (ioread32(davinci_spi->base + SPIBUF)
+ & SPIBUF_RXEMPTY_MASK)
+ cpu_relax();
+
+ /* getting the returned byte */
+ if (t->rx_buf) {
+ buf_val = ioread32(davinci_spi->base + SPIBUF);
+ davinci_spi->get_rx(buf_val, davinci_spi);
+ }
+ if (count <= 0)
+ break;
+ }
+ } else {
+ if (pdata->poll_mode) {
+ while (1) {
+ /* keeps the serial clock going */
+ if ((ioread32(davinci_spi->base + SPIBUF)
+ & SPIBUF_TXFULL_MASK) == 0)
+ iowrite32(data1_reg_val,
+ davinci_spi->base + SPIDAT1);
+
+ while (ioread32(davinci_spi->base + SPIBUF) &
+ SPIBUF_RXEMPTY_MASK)
+ cpu_relax();
+
+ flg_val = ioread32(davinci_spi->base + SPIFLG);
+ buf_val = ioread32(davinci_spi->base + SPIBUF);
+
+ davinci_spi->get_rx(buf_val, davinci_spi);
+
+ count--;
+ if (count <= 0)
+ break;
+ }
+ } else { /* Receive in Interrupt mode */
+ int i;
+
+ for (i = 0; i < davinci_spi->count; i++) {
+ set_io_bits(davinci_spi->base + SPIINT,
+ SPIINT_BITERR_INTR
+ | SPIINT_OVRRUN_INTR
+ | SPIINT_RX_INTR);
+
+ iowrite32(data1_reg_val,
+ davinci_spi->base + SPIDAT1);
+
+ while (ioread32(davinci_spi->base + SPIINT) &
+ SPIINT_RX_INTR)
+ cpu_relax();
+ }
+ iowrite32((data1_reg_val & 0x0ffcffff),
+ davinci_spi->base + SPIDAT1);
+ }
+ }
+
+ /*
+ * Check for bit error, desync error,parity error,timeout error and
+ * receive overflow errors
+ */
+ int_status = ioread32(davinci_spi->base + SPIFLG);
+
+ ret = davinci_spi_check_error(davinci_spi, int_status);
+ if (ret != 0)
+ return ret;
+
+ /* SPI Framework maintains the count only in bytes so convert back */
+ davinci_spi->count *= conv;
+
+ return t->len;
+}
+
+#define DAVINCI_DMA_DATA_TYPE_S8 0x01
+#define DAVINCI_DMA_DATA_TYPE_S16 0x02
+#define DAVINCI_DMA_DATA_TYPE_S32 0x04
+
+static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct davinci_spi *davinci_spi;
+ int int_status = 0;
+ int count, temp_count;
+ u8 conv = 1;
+ u8 tmp;
+ u32 data1_reg_val;
+ struct davinci_spi_dma *davinci_spi_dma;
+ int word_len, data_type, ret;
+ unsigned long tx_reg, rx_reg;
+ struct davinci_spi_platform_data *pdata;
+ struct device *sdev;
+
+ davinci_spi = spi_master_get_devdata(spi->master);
+ pdata = davinci_spi->pdata;
+ sdev = davinci_spi->bitbang.master->dev.parent;
+
+ davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
+
+ tx_reg = (unsigned long)davinci_spi->pbase + SPIDAT1;
+ rx_reg = (unsigned long)davinci_spi->pbase + SPIBUF;
+
+ davinci_spi->tx = t->tx_buf;
+ davinci_spi->rx = t->rx_buf;
+
+ /* convert len to words based on bits_per_word */
+ conv = davinci_spi->slave[spi->chip_select].bytes_per_word;
+ davinci_spi->count = t->len / conv;
+
+ INIT_COMPLETION(davinci_spi->done);
+
+ init_completion(&davinci_spi_dma->dma_rx_completion);
+ init_completion(&davinci_spi_dma->dma_tx_completion);
+
+ word_len = conv * 8;
+
+ if (word_len <= 8)
+ data_type = DAVINCI_DMA_DATA_TYPE_S8;
+ else if (word_len <= 16)
+ data_type = DAVINCI_DMA_DATA_TYPE_S16;
+ else if (word_len <= 32)
+ data_type = DAVINCI_DMA_DATA_TYPE_S32;
+ else
+ return -EINVAL;
+
+ ret = davinci_spi_bufs_prep(spi, davinci_spi);
+ if (ret)
+ return ret;
+
+ /* Put delay val if required */
+ iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) |
+ (pdata->t2cdelay << SPI_T2CDELAY_SHIFT),
+ davinci_spi->base + SPIDELAY);
+
+ count = davinci_spi->count; /* the number of elements */
+ data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT;
+
+ /* CS default = 0xFF */
+ tmp = ~(0x1 << spi->chip_select);
+
+ clear_io_bits(davinci_spi->base + SPIDEF, ~tmp);
+
+ data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT;
+
+ /* disable all interrupts for dma transfers */
+ clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL);
+ /* Disable SPI to write configuration bits in SPIDAT */
+ clear_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
+ iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
+ /* Enable SPI */
+ set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
+
+ while ((ioread32(davinci_spi->base + SPIBUF)
+ & SPIBUF_RXEMPTY_MASK) == 0)
+ cpu_relax();
+
+
+ if (t->tx_buf) {
+ t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf, count,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&spi->dev, t->tx_dma)) {
+ dev_dbg(sdev, "Unable to DMA map a %d bytes"
+ " TX buffer\n", count);
+ return -ENOMEM;
+ }
+ temp_count = count;
+ } else {
+ /* We need TX clocking for RX transaction */
+ t->tx_dma = dma_map_single(&spi->dev,
+ (void *)davinci_spi->tmp_buf, count + 1,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&spi->dev, t->tx_dma)) {
+ dev_dbg(sdev, "Unable to DMA map a %d bytes"
+ " TX tmp buffer\n", count);
+ return -ENOMEM;
+ }
+ temp_count = count + 1;
+ }
+
+ edma_set_transfer_params(davinci_spi_dma->dma_tx_channel,
+ data_type, temp_count, 1, 0, ASYNC);
+ edma_set_dest(davinci_spi_dma->dma_tx_channel, tx_reg, INCR, W8BIT);
+ edma_set_src(davinci_spi_dma->dma_tx_channel, t->tx_dma, INCR, W8BIT);
+ edma_set_src_index(davinci_spi_dma->dma_tx_channel, data_type, 0);
+ edma_set_dest_index(davinci_spi_dma->dma_tx_channel, 0, 0);
+
+ if (t->rx_buf) {
+ /* initiate transaction */
+ iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
+
+ t->rx_dma = dma_map_single(&spi->dev, (void *)t->rx_buf, count,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&spi->dev, t->rx_dma)) {
+ dev_dbg(sdev, "Couldn't DMA map a %d bytes RX buffer\n",
+ count);
+ if (t->tx_buf != NULL)
+ dma_unmap_single(NULL, t->tx_dma,
+ count, DMA_TO_DEVICE);
+ return -ENOMEM;
+ }
+ edma_set_transfer_params(davinci_spi_dma->dma_rx_channel,
+ data_type, count, 1, 0, ASYNC);
+ edma_set_src(davinci_spi_dma->dma_rx_channel,
+ rx_reg, INCR, W8BIT);
+ edma_set_dest(davinci_spi_dma->dma_rx_channel,
+ t->rx_dma, INCR, W8BIT);
+ edma_set_src_index(davinci_spi_dma->dma_rx_channel, 0, 0);
+ edma_set_dest_index(davinci_spi_dma->dma_rx_channel,
+ data_type, 0);
+ }
+
+ if ((t->tx_buf) || (t->rx_buf))
+ edma_start(davinci_spi_dma->dma_tx_channel);
+
+ if (t->rx_buf)
+ edma_start(davinci_spi_dma->dma_rx_channel);
+
+ if ((t->rx_buf) || (t->tx_buf))
+ davinci_spi_set_dma_req(spi, 1);
+
+ if (t->tx_buf)
+ wait_for_completion_interruptible(
+ &davinci_spi_dma->dma_tx_completion);
+
+ if (t->rx_buf)
+ wait_for_completion_interruptible(
+ &davinci_spi_dma->dma_rx_completion);
+
+ dma_unmap_single(NULL, t->tx_dma, temp_count, DMA_TO_DEVICE);
+
+ if (t->rx_buf)
+ dma_unmap_single(NULL, t->rx_dma, count, DMA_FROM_DEVICE);
+
+ /*
+ * Check for bit error, desync error,parity error,timeout error and
+ * receive overflow errors
+ */
+ int_status = ioread32(davinci_spi->base + SPIFLG);
+
+ ret = davinci_spi_check_error(davinci_spi, int_status);
+ if (ret != 0)
+ return ret;
+
+ /* SPI Framework maintains the count only in bytes so convert back */
+ davinci_spi->count *= conv;
+
+ return t->len;
+}
+
+/**
+ * davinci_spi_irq - IRQ handler for DaVinci SPI
+ * @irq: IRQ number for this SPI Master
+ * @context_data: structure for SPI Master controller davinci_spi
+ */
+static irqreturn_t davinci_spi_irq(s32 irq, void *context_data)
+{
+ struct davinci_spi *davinci_spi = context_data;
+ u32 int_status, rx_data = 0;
+ irqreturn_t ret = IRQ_NONE;
+
+ int_status = ioread32(davinci_spi->base + SPIFLG);
+
+ while ((int_status & SPIFLG_RX_INTR_MASK)) {
+ if (likely(int_status & SPIFLG_RX_INTR_MASK)) {
+ ret = IRQ_HANDLED;
+
+ rx_data = ioread32(davinci_spi->base + SPIBUF);
+ davinci_spi->get_rx(rx_data, davinci_spi);
+
+ /* Disable Receive Interrupt */
+ iowrite32(~(SPIINT_RX_INTR | SPIINT_TX_INTR),
+ davinci_spi->base + SPIINT);
+ } else
+ (void)davinci_spi_check_error(davinci_spi, int_status);
+
+ int_status = ioread32(davinci_spi->base + SPIFLG);
+ }
+
+ return ret;
+}
+
+/**
+ * davinci_spi_probe - probe function for SPI Master Controller
+ * @pdev: platform_device structure which contains plateform specific data
+ */
+static int davinci_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct davinci_spi *davinci_spi;
+ struct davinci_spi_platform_data *pdata;
+ struct resource *r, *mem;
+ resource_size_t dma_rx_chan = SPI_NO_RESOURCE;
+ resource_size_t dma_tx_chan = SPI_NO_RESOURCE;
+ resource_size_t dma_eventq = SPI_NO_RESOURCE;
+ int i = 0, ret = 0;
+
+ pdata = pdev->dev.platform_data;
+ if (pdata == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi));
+ if (master == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ dev_set_drvdata(&pdev->dev, master);
+
+ davinci_spi = spi_master_get_devdata(master);
+ if (davinci_spi == NULL) {
+ ret = -ENOENT;
+ goto free_master;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ ret = -ENOENT;
+ goto free_master;
+ }
+
+ davinci_spi->pbase = r->start;
+ davinci_spi->region_size = resource_size(r);
+ davinci_spi->pdata = pdata;
+
+ mem = request_mem_region(r->start, davinci_spi->region_size,
+ pdev->name);
+ if (mem == NULL) {
+ ret = -EBUSY;
+ goto free_master;
+ }
+
+ davinci_spi->base = (struct davinci_spi_reg __iomem *)
+ ioremap(r->start, davinci_spi->region_size);
+ if (davinci_spi->base == NULL) {
+ ret = -ENOMEM;
+ goto release_region;
+ }
+
+ davinci_spi->irq = platform_get_irq(pdev, 0);
+ if (davinci_spi->irq <= 0) {
+ ret = -EINVAL;
+ goto unmap_io;
+ }
+
+ ret = request_irq(davinci_spi->irq, davinci_spi_irq, IRQF_DISABLED,
+ dev_name(&pdev->dev), davinci_spi);
+ if (ret)
+ goto unmap_io;
+
+ /* Allocate tmp_buf for tx_buf */
+ davinci_spi->tmp_buf = kzalloc(SPI_BUFSIZ, GFP_KERNEL);
+ if (davinci_spi->tmp_buf == NULL) {
+ ret = -ENOMEM;
+ goto irq_free;
+ }
+
+ davinci_spi->bitbang.master = spi_master_get(master);
+ if (davinci_spi->bitbang.master == NULL) {
+ ret = -ENODEV;
+ goto free_tmp_buf;
+ }
+
+ davinci_spi->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(davinci_spi->clk)) {
+ ret = -ENODEV;
+ goto put_master;
+ }
+ clk_enable(davinci_spi->clk);
+
+
+ master->bus_num = pdev->id;
+ master->num_chipselect = pdata->num_chipselect;
+ master->setup = davinci_spi_setup;
+ master->cleanup = davinci_spi_cleanup;
+
+ davinci_spi->bitbang.chipselect = davinci_spi_chipselect;
+ davinci_spi->bitbang.setup_transfer = davinci_spi_setup_transfer;
+
+ davinci_spi->version = pdata->version;
+ use_dma = pdata->use_dma;
+
+ davinci_spi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP;
+ if (davinci_spi->version == SPI_VERSION_2)
+ davinci_spi->bitbang.flags |= SPI_READY;
+
+ if (use_dma) {
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (r)
+ dma_rx_chan = r->start;
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (r)
+ dma_tx_chan = r->start;
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 2);
+ if (r)
+ dma_eventq = r->start;
+ }
+
+ if (!use_dma ||
+ dma_rx_chan == SPI_NO_RESOURCE ||
+ dma_tx_chan == SPI_NO_RESOURCE ||
+ dma_eventq == SPI_NO_RESOURCE) {
+ davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_pio;
+ use_dma = 0;
+ } else {
+ davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_dma;
+ davinci_spi->dma_channels = kzalloc(master->num_chipselect
+ * sizeof(struct davinci_spi_dma), GFP_KERNEL);
+ if (davinci_spi->dma_channels == NULL) {
+ ret = -ENOMEM;
+ goto free_clk;
+ }
+
+ for (i = 0; i < master->num_chipselect; i++) {
+ davinci_spi->dma_channels[i].dma_rx_channel = -1;
+ davinci_spi->dma_channels[i].dma_rx_sync_dev =
+ dma_rx_chan;
+ davinci_spi->dma_channels[i].dma_tx_channel = -1;
+ davinci_spi->dma_channels[i].dma_tx_sync_dev =
+ dma_tx_chan;
+ davinci_spi->dma_channels[i].eventq = dma_eventq;
+ }
+ dev_info(&pdev->dev, "DaVinci SPI driver in EDMA mode\n"
+ "Using RX channel = %d , TX channel = %d and "
+ "event queue = %d", dma_rx_chan, dma_tx_chan,
+ dma_eventq);
+ }
+
+ davinci_spi->get_rx = davinci_spi_rx_buf_u8;
+ davinci_spi->get_tx = davinci_spi_tx_buf_u8;
+
+ init_completion(&davinci_spi->done);
+
+ /* Reset In/OUT SPI module */
+ iowrite32(0, davinci_spi->base + SPIGCR0);
+ udelay(100);
+ iowrite32(1, davinci_spi->base + SPIGCR0);
+
+ /* Clock internal */
+ if (davinci_spi->pdata->clk_internal)
+ set_io_bits(davinci_spi->base + SPIGCR1,
+ SPIGCR1_CLKMOD_MASK);
+ else
+ clear_io_bits(davinci_spi->base + SPIGCR1,
+ SPIGCR1_CLKMOD_MASK);
+
+ /* master mode default */
+ set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_MASTER_MASK);
+
+ if (davinci_spi->pdata->intr_level)
+ iowrite32(SPI_INTLVL_1, davinci_spi->base + SPILVL);
+ else
+ iowrite32(SPI_INTLVL_0, davinci_spi->base + SPILVL);
+
+ ret = spi_bitbang_start(&davinci_spi->bitbang);
+ if (ret)
+ goto free_clk;
+
+ dev_info(&pdev->dev, "Controller at 0x%p \n", davinci_spi->base);
+
+ if (!pdata->poll_mode)
+ dev_info(&pdev->dev, "Operating in interrupt mode"
+ " using IRQ %d\n", davinci_spi->irq);
+
+ return ret;
+
+free_clk:
+ clk_disable(davinci_spi->clk);
+ clk_put(davinci_spi->clk);
+put_master:
+ spi_master_put(master);
+free_tmp_buf:
+ kfree(davinci_spi->tmp_buf);
+irq_free:
+ free_irq(davinci_spi->irq, davinci_spi);
+unmap_io:
+ iounmap(davinci_spi->base);
+release_region:
+ release_mem_region(davinci_spi->pbase, davinci_spi->region_size);
+free_master:
+ kfree(master);
+err:
+ return ret;
+}
+
+/**
+ * davinci_spi_remove - remove function for SPI Master Controller
+ * @pdev: platform_device structure which contains plateform specific data
+ *
+ * This function will do the reverse action of davinci_spi_probe function
+ * It will free the IRQ and SPI controller's memory region.
+ * It will also call spi_bitbang_stop to destroy the work queue which was
+ * created by spi_bitbang_start.
+ */
+static int __exit davinci_spi_remove(struct platform_device *pdev)
+{
+ struct davinci_spi *davinci_spi;
+ struct spi_master *master;
+
+ master = dev_get_drvdata(&pdev->dev);
+ davinci_spi = spi_master_get_devdata(master);
+
+ spi_bitbang_stop(&davinci_spi->bitbang);
+
+ clk_disable(davinci_spi->clk);
+ clk_put(davinci_spi->clk);
+ spi_master_put(master);
+ kfree(davinci_spi->tmp_buf);
+ free_irq(davinci_spi->irq, davinci_spi);
+ iounmap(davinci_spi->base);
+ release_mem_region(davinci_spi->pbase, davinci_spi->region_size);
+
+ return 0;
+}
+
+static struct platform_driver davinci_spi_driver = {
+ .driver.name = "spi_davinci",
+ .remove = __exit_p(davinci_spi_remove),
+};
+
+static int __init davinci_spi_init(void)
+{
+ return platform_driver_probe(&davinci_spi_driver, davinci_spi_probe);
+}
+module_init(davinci_spi_init);
+
+static void __exit davinci_spi_exit(void)
+{
+ platform_driver_unregister(&davinci_spi_driver);
+}
+module_exit(davinci_spi_exit);
+
+MODULE_DESCRIPTION("TI DaVinci SPI Master Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c
index 31620fae77be..8ed38f1d6c18 100644
--- a/drivers/spi/dw_spi.c
+++ b/drivers/spi/dw_spi.c
@@ -152,6 +152,7 @@ static void mrst_spi_debugfs_remove(struct dw_spi *dws)
#else
static inline int mrst_spi_debugfs_init(struct dw_spi *dws)
{
+ return 0;
}
static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
@@ -161,14 +162,14 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
static void wait_till_not_busy(struct dw_spi *dws)
{
- unsigned long end = jiffies + usecs_to_jiffies(1000);
+ unsigned long end = jiffies + 1 + usecs_to_jiffies(1000);
while (time_before(jiffies, end)) {
if (!(dw_readw(dws, sr) & SR_BUSY))
return;
}
dev_err(&dws->master->dev,
- "DW SPI: Stutus keeps busy for 1000us after a read/write!\n");
+ "DW SPI: Status keeps busy for 1000us after a read/write!\n");
}
static void flush(struct dw_spi *dws)
@@ -358,6 +359,8 @@ static void transfer_complete(struct dw_spi *dws)
static irqreturn_t interrupt_transfer(struct dw_spi *dws)
{
u16 irq_status, irq_mask = 0x3f;
+ u32 int_level = dws->fifo_len / 2;
+ u32 left;
irq_status = dw_readw(dws, isr) & irq_mask;
/* Error handling */
@@ -369,22 +372,23 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
return IRQ_HANDLED;
}
- /* INT comes from tx */
- if (dws->tx && (irq_status & SPI_INT_TXEI)) {
- while (dws->tx < dws->tx_end)
+ if (irq_status & SPI_INT_TXEI) {
+ spi_mask_intr(dws, SPI_INT_TXEI);
+
+ left = (dws->tx_end - dws->tx) / dws->n_bytes;
+ left = (left > int_level) ? int_level : left;
+
+ while (left--)
dws->write(dws);
+ dws->read(dws);
- if (dws->tx == dws->tx_end) {
- spi_mask_intr(dws, SPI_INT_TXEI);
+ /* Re-enable the IRQ if there is still data left to tx */
+ if (dws->tx_end > dws->tx)
+ spi_umask_intr(dws, SPI_INT_TXEI);
+ else
transfer_complete(dws);
- }
}
- /* INT comes from rx */
- if (dws->rx && (irq_status & SPI_INT_RXFI)) {
- if (dws->read(dws))
- transfer_complete(dws);
- }
return IRQ_HANDLED;
}
@@ -404,12 +408,9 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
/* Must be called inside pump_transfers() */
static void poll_transfer(struct dw_spi *dws)
{
- if (dws->tx) {
- while (dws->write(dws))
- dws->read(dws);
- }
+ while (dws->write(dws))
+ dws->read(dws);
- dws->read(dws);
transfer_complete(dws);
}
@@ -428,6 +429,7 @@ static void pump_transfers(unsigned long data)
u8 bits = 0;
u8 imask = 0;
u8 cs_change = 0;
+ u16 txint_level = 0;
u16 clk_div = 0;
u32 speed = 0;
u32 cr0 = 0;
@@ -438,6 +440,9 @@ static void pump_transfers(unsigned long data)
chip = dws->cur_chip;
spi = message->spi;
+ if (unlikely(!chip->clk_div))
+ chip->clk_div = dws->max_freq / chip->speed_hz;
+
if (message->state == ERROR_STATE) {
message->status = -EIO;
goto early_exit;
@@ -492,7 +497,7 @@ static void pump_transfers(unsigned long data)
/* clk_div doesn't support odd number */
clk_div = dws->max_freq / speed;
- clk_div = (clk_div >> 1) << 1;
+ clk_div = (clk_div + 1) & 0xfffe;
chip->speed_hz = speed;
chip->clk_div = clk_div;
@@ -532,14 +537,35 @@ static void pump_transfers(unsigned long data)
}
message->state = RUNNING_STATE;
+ /*
+ * Adjust transfer mode if necessary. Requires platform dependent
+ * chipselect mechanism.
+ */
+ if (dws->cs_control) {
+ if (dws->rx && dws->tx)
+ chip->tmode = 0x00;
+ else if (dws->rx)
+ chip->tmode = 0x02;
+ else
+ chip->tmode = 0x01;
+
+ cr0 &= ~(0x3 << SPI_MODE_OFFSET);
+ cr0 |= (chip->tmode << SPI_TMOD_OFFSET);
+ }
+
/* Check if current transfer is a DMA transaction */
dws->dma_mapped = map_dma_buffers(dws);
+ /*
+ * Interrupt mode
+ * we only need set the TXEI IRQ, as TX/RX always happen syncronizely
+ */
if (!dws->dma_mapped && !chip->poll_mode) {
- if (dws->rx)
- imask |= SPI_INT_RXFI;
- if (dws->tx)
- imask |= SPI_INT_TXEI;
+ int templen = dws->len / dws->n_bytes;
+ txint_level = dws->fifo_len / 2;
+ txint_level = (templen > txint_level) ? txint_level : templen;
+
+ imask |= SPI_INT_TXEI;
dws->transfer_handler = interrupt_transfer;
}
@@ -549,21 +575,23 @@ static void pump_transfers(unsigned long data)
* 2. clk_div is changed
* 3. control value changes
*/
- if (dw_readw(dws, ctrl0) != cr0 || cs_change || clk_div) {
+ if (dw_readw(dws, ctrl0) != cr0 || cs_change || clk_div || imask) {
spi_enable_chip(dws, 0);
if (dw_readw(dws, ctrl0) != cr0)
dw_writew(dws, ctrl0, cr0);
+ spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);
+ spi_chip_sel(dws, spi->chip_select);
+
/* Set the interrupt mask, for poll mode just diable all int */
spi_mask_intr(dws, 0xff);
- if (!chip->poll_mode)
+ if (imask)
spi_umask_intr(dws, imask);
+ if (txint_level)
+ dw_writew(dws, txfltr, txint_level);
- spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);
- spi_chip_sel(dws, spi->chip_select);
spi_enable_chip(dws, 1);
-
if (cs_change)
dws->prev_chip = chip;
}
@@ -712,11 +740,11 @@ static int dw_spi_setup(struct spi_device *spi)
}
chip->bits_per_word = spi->bits_per_word;
+ if (!spi->max_speed_hz) {
+ dev_err(&spi->dev, "No max speed HZ parameter\n");
+ return -EINVAL;
+ }
chip->speed_hz = spi->max_speed_hz;
- if (chip->speed_hz)
- chip->clk_div = 25000000 / chip->speed_hz;
- else
- chip->clk_div = 8; /* default value */
chip->tmode = 0; /* Tx & Rx */
/* Default SPI mode is SCPOL = 0, SCPH = 0 */
@@ -735,7 +763,7 @@ static void dw_spi_cleanup(struct spi_device *spi)
kfree(chip);
}
-static int __init init_queue(struct dw_spi *dws)
+static int __devinit init_queue(struct dw_spi *dws)
{
INIT_LIST_HEAD(&dws->queue);
spin_lock_init(&dws->lock);
@@ -817,6 +845,22 @@ static void spi_hw_init(struct dw_spi *dws)
spi_mask_intr(dws, 0xff);
spi_enable_chip(dws, 1);
flush(dws);
+
+ /*
+ * Try to detect the FIFO depth if not set by interface driver,
+ * the depth could be from 2 to 256 from HW spec
+ */
+ if (!dws->fifo_len) {
+ u32 fifo;
+ for (fifo = 2; fifo <= 257; fifo++) {
+ dw_writew(dws, txfltr, fifo);
+ if (fifo != dw_readw(dws, txfltr))
+ break;
+ }
+
+ dws->fifo_len = (fifo == 257) ? 0 : fifo;
+ dw_writew(dws, txfltr, 0);
+ }
}
int __devinit dw_spi_add_host(struct dw_spi *dws)
@@ -913,6 +957,7 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws)
/* Disconnect from the SPI framework */
spi_unregister_master(dws->master);
}
+EXPORT_SYMBOL(dw_spi_remove_host);
int dw_spi_suspend_host(struct dw_spi *dws)
{
diff --git a/drivers/spi/dw_spi_mmio.c b/drivers/spi/dw_spi_mmio.c
new file mode 100644
index 000000000000..e35b45ac5174
--- /dev/null
+++ b/drivers/spi/dw_spi_mmio.c
@@ -0,0 +1,147 @@
+/*
+ * dw_spi_mmio.c - Memory-mapped interface driver for DW SPI Core
+ *
+ * Copyright (c) 2010, Octasic semiconductor.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/spi/dw_spi.h>
+#include <linux/spi/spi.h>
+
+#define DRIVER_NAME "dw_spi_mmio"
+
+struct dw_spi_mmio {
+ struct dw_spi dws;
+ struct clk *clk;
+};
+
+static int __devinit dw_spi_mmio_probe(struct platform_device *pdev)
+{
+ struct dw_spi_mmio *dwsmmio;
+ struct dw_spi *dws;
+ struct resource *mem, *ioarea;
+ int ret;
+
+ dwsmmio = kzalloc(sizeof(struct dw_spi_mmio), GFP_KERNEL);
+ if (!dwsmmio) {
+ ret = -ENOMEM;
+ goto err_end;
+ }
+
+ dws = &dwsmmio->dws;
+
+ /* Get basic io resource and map it */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ ret = -EINVAL;
+ goto err_kfree;
+ }
+
+ ioarea = request_mem_region(mem->start, resource_size(mem),
+ pdev->name);
+ if (!ioarea) {
+ dev_err(&pdev->dev, "SPI region already claimed\n");
+ ret = -EBUSY;
+ goto err_kfree;
+ }
+
+ dws->regs = ioremap_nocache(mem->start, resource_size(mem));
+ if (!dws->regs) {
+ dev_err(&pdev->dev, "SPI region already mapped\n");
+ ret = -ENOMEM;
+ goto err_release_reg;
+ }
+
+ dws->irq = platform_get_irq(pdev, 0);
+ if (dws->irq < 0) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ ret = dws->irq; /* -ENXIO */
+ goto err_unmap;
+ }
+
+ dwsmmio->clk = clk_get(&pdev->dev, NULL);
+ if (!dwsmmio->clk) {
+ ret = -ENODEV;
+ goto err_irq;
+ }
+ clk_enable(dwsmmio->clk);
+
+ dws->parent_dev = &pdev->dev;
+ dws->bus_num = 0;
+ dws->num_cs = 4;
+ dws->max_freq = clk_get_rate(dwsmmio->clk);
+
+ ret = dw_spi_add_host(dws);
+ if (ret)
+ goto err_clk;
+
+ platform_set_drvdata(pdev, dwsmmio);
+ return 0;
+
+err_clk:
+ clk_disable(dwsmmio->clk);
+ clk_put(dwsmmio->clk);
+ dwsmmio->clk = NULL;
+err_irq:
+ free_irq(dws->irq, dws);
+err_unmap:
+ iounmap(dws->regs);
+err_release_reg:
+ release_mem_region(mem->start, resource_size(mem));
+err_kfree:
+ kfree(dwsmmio);
+err_end:
+ return ret;
+}
+
+static int __devexit dw_spi_mmio_remove(struct platform_device *pdev)
+{
+ struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ platform_set_drvdata(pdev, NULL);
+
+ clk_disable(dwsmmio->clk);
+ clk_put(dwsmmio->clk);
+ dwsmmio->clk = NULL;
+
+ free_irq(dwsmmio->dws.irq, &dwsmmio->dws);
+ dw_spi_remove_host(&dwsmmio->dws);
+ iounmap(dwsmmio->dws.regs);
+ kfree(dwsmmio);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+ return 0;
+}
+
+static struct platform_driver dw_spi_mmio_driver = {
+ .remove = __devexit_p(dw_spi_mmio_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init dw_spi_mmio_init(void)
+{
+ return platform_driver_probe(&dw_spi_mmio_driver, dw_spi_mmio_probe);
+}
+module_init(dw_spi_mmio_init);
+
+static void __exit dw_spi_mmio_exit(void)
+{
+ platform_driver_unregister(&dw_spi_mmio_driver);
+}
+module_exit(dw_spi_mmio_exit);
+
+MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>");
+MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/dw_spi_pci.c b/drivers/spi/dw_spi_pci.c
index 34ba69161734..1f0735f9cc76 100644
--- a/drivers/spi/dw_spi_pci.c
+++ b/drivers/spi/dw_spi_pci.c
@@ -73,6 +73,7 @@ static int __devinit spi_pci_probe(struct pci_dev *pdev,
dws->num_cs = 4;
dws->max_freq = 25000000; /* for Moorestwon */
dws->irq = pdev->irq;
+ dws->fifo_len = 40; /* FIFO has 40 words buffer */
ret = dw_spi_add_host(dws);
if (ret)
@@ -98,6 +99,7 @@ static void __devexit spi_pci_remove(struct pci_dev *pdev)
struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
pci_set_drvdata(pdev, NULL);
+ dw_spi_remove_host(&dwpci->dws);
iounmap(dwpci->dws.regs);
pci_release_region(pdev, 0);
kfree(dwpci);
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
index f50c81df336a..04747868d6c4 100644
--- a/drivers/spi/mpc52xx_psc_spi.c
+++ b/drivers/spi/mpc52xx_psc_spi.c
@@ -503,7 +503,7 @@ static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op)
return mpc52xx_psc_spi_do_remove(&op->dev);
}
-static struct of_device_id mpc52xx_psc_spi_of_match[] = {
+static const struct of_device_id mpc52xx_psc_spi_of_match[] = {
{ .compatible = "fsl,mpc5200-psc-spi", },
{ .compatible = "mpc5200-psc-spi", }, /* old */
{}
diff --git a/drivers/spi/mpc52xx_spi.c b/drivers/spi/mpc52xx_spi.c
index 45bfe6458173..6eab46537a0a 100644
--- a/drivers/spi/mpc52xx_spi.c
+++ b/drivers/spi/mpc52xx_spi.c
@@ -550,7 +550,7 @@ static int __devexit mpc52xx_spi_remove(struct of_device *op)
return 0;
}
-static struct of_device_id mpc52xx_spi_match[] __devinitdata = {
+static const struct of_device_id mpc52xx_spi_match[] __devinitconst = {
{ .compatible = "fsl,mpc5200-spi", },
{}
};
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index bf5f95a19413..715c518b1b68 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -1014,7 +1014,7 @@ static u8 __initdata spi2_txdma_id[] = {
OMAP24XX_DMA_SPI2_TX1,
};
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) \
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \
|| defined(CONFIG_ARCH_OMAP4)
static u8 __initdata spi3_rxdma_id[] = {
OMAP24XX_DMA_SPI3_RX0,
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index 1893f1e96dc4..0ddbbe45e834 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -469,7 +469,7 @@ static int spi_imx_setup(struct spi_device *spi)
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
int gpio = spi_imx->chipselect[spi->chip_select];
- pr_debug("%s: mode %d, %u bpw, %d hz\n", __func__,
+ dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__,
spi->mode, spi->bits_per_word, spi->max_speed_hz);
if (gpio >= 0)
diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c
index 1fb2a6ea328c..4f0cc9d457e0 100644
--- a/drivers/spi/spi_mpc8xxx.c
+++ b/drivers/spi/spi_mpc8xxx.c
@@ -365,7 +365,7 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
if ((mpc8xxx_spi->spibrg / hz) > 64) {
cs->hw_mode |= SPMODE_DIV16;
- pm = mpc8xxx_spi->spibrg / (hz * 64);
+ pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
"Will use %d Hz instead.\n", dev_name(&spi->dev),
@@ -373,7 +373,7 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
if (pm > 16)
pm = 16;
} else
- pm = mpc8xxx_spi->spibrg / (hz * 4);
+ pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
if (pm)
pm--;
@@ -1328,7 +1328,7 @@ static struct of_platform_driver of_mpc8xxx_spi_driver = {
static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
{
struct resource *mem;
- unsigned int irq;
+ int irq;
struct spi_master *master;
if (!pdev->dev.platform_data)
@@ -1339,7 +1339,7 @@ static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
return -EINVAL;
irq = platform_get_irq(pdev, 0);
- if (!irq)
+ if (irq <= 0)
return -EINVAL;
master = mpc8xxx_spi_probe(&pdev->dev, mem, irq);
diff --git a/drivers/spi/spi_ppc4xx.c b/drivers/spi/spi_ppc4xx.c
index 140a18d6cf3e..6d8d4026a07a 100644
--- a/drivers/spi/spi_ppc4xx.c
+++ b/drivers/spi/spi_ppc4xx.c
@@ -578,7 +578,7 @@ static int __exit spi_ppc4xx_of_remove(struct of_device *op)
return 0;
}
-static struct of_device_id spi_ppc4xx_of_match[] = {
+static const struct of_device_id spi_ppc4xx_of_match[] = {
{ .compatible = "ibm,ppc4xx-spi", },
{},
};
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index c010733877ae..1fabede9e061 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -275,7 +275,7 @@ static inline u32 ack_bit(unsigned int irq)
* Claim the FIQ handler (only one can be active at any one time) and
* then setup the correct transfer code for this transfer.
*
- * This call updates all the necessary state information if sucessful,
+ * This call updates all the necessary state information if successful,
* so the caller does not need to do anything more than start the transfer
* as normal, since the IRQ will have been re-routed to the FIQ handler.
*/
diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c
index 88a456dba967..97365815a729 100644
--- a/drivers/spi/spi_s3c64xx.c
+++ b/drivers/spi/spi_s3c64xx.c
@@ -28,7 +28,7 @@
#include <linux/spi/spi.h>
#include <mach/dma.h>
-#include <plat/spi.h>
+#include <plat/s3c64xx-spi.h>
/* Registers and bit-fields */
@@ -137,6 +137,7 @@
/**
* struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver.
* @clk: Pointer to the spi clock.
+ * @src_clk: Pointer to the clock used to generate SPI signals.
* @master: Pointer to the SPI Protocol master.
* @workqueue: Work queue for the SPI xfer requests.
* @cntrlr_info: Platform specific data for the controller this driver manages.
@@ -157,10 +158,11 @@
struct s3c64xx_spi_driver_data {
void __iomem *regs;
struct clk *clk;
+ struct clk *src_clk;
struct platform_device *pdev;
struct spi_master *master;
struct workqueue_struct *workqueue;
- struct s3c64xx_spi_cntrlr_info *cntrlr_info;
+ struct s3c64xx_spi_info *cntrlr_info;
struct spi_device *tgl_spi;
struct work_struct work;
struct list_head queue;
@@ -180,7 +182,7 @@ static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
{
- struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
void __iomem *regs = sdd->regs;
unsigned long loops;
u32 val;
@@ -225,7 +227,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
struct spi_device *spi,
struct spi_transfer *xfer, int dma_mode)
{
- struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
void __iomem *regs = sdd->regs;
u32 modecfg, chcfg;
@@ -298,19 +300,20 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
/* Deselect the last toggled device */
cs = sdd->tgl_spi->controller_data;
- cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1);
+ cs->set_level(cs->line,
+ spi->mode & SPI_CS_HIGH ? 0 : 1);
}
sdd->tgl_spi = NULL;
}
cs = spi->controller_data;
- cs->set_level(spi->mode & SPI_CS_HIGH ? 1 : 0);
+ cs->set_level(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0);
}
static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
struct spi_transfer *xfer, int dma_mode)
{
- struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
void __iomem *regs = sdd->regs;
unsigned long val;
int ms;
@@ -384,12 +387,11 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
if (sdd->tgl_spi == spi)
sdd->tgl_spi = NULL;
- cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1);
+ cs->set_level(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1);
}
static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
{
- struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
void __iomem *regs = sdd->regs;
u32 val;
@@ -435,7 +437,7 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
/* Configure Clock */
val = readl(regs + S3C64XX_SPI_CLK_CFG);
val &= ~S3C64XX_SPI_PSR_MASK;
- val |= ((clk_get_rate(sci->src_clk) / sdd->cur_speed / 2 - 1)
+ val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1)
& S3C64XX_SPI_PSR_MASK);
writel(val, regs + S3C64XX_SPI_CLK_CFG);
@@ -558,7 +560,7 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
struct spi_message *msg)
{
- struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
struct spi_device *spi = msg->spi;
struct s3c64xx_spi_csinfo *cs = spi->controller_data;
struct spi_transfer *xfer;
@@ -632,8 +634,8 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
S3C64XX_SPI_DEACT(sdd);
if (status) {
- dev_err(&spi->dev, "I/O Error: \
- rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
+ dev_err(&spi->dev, "I/O Error: "
+ "rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
(sdd->state & RXBUSY) ? 'f' : 'p',
(sdd->state & TXBUSY) ? 'f' : 'p',
@@ -786,7 +788,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
{
struct s3c64xx_spi_csinfo *cs = spi->controller_data;
struct s3c64xx_spi_driver_data *sdd;
- struct s3c64xx_spi_cntrlr_info *sci;
+ struct s3c64xx_spi_info *sci;
struct spi_message *msg;
u32 psr, speed;
unsigned long flags;
@@ -831,17 +833,17 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
}
/* Check if we can provide the requested rate */
- speed = clk_get_rate(sci->src_clk) / 2 / (0 + 1); /* Max possible */
+ speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1); /* Max possible */
if (spi->max_speed_hz > speed)
spi->max_speed_hz = speed;
- psr = clk_get_rate(sci->src_clk) / 2 / spi->max_speed_hz - 1;
+ psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1;
psr &= S3C64XX_SPI_PSR_MASK;
if (psr == S3C64XX_SPI_PSR_MASK)
psr--;
- speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1);
+ speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
if (spi->max_speed_hz < speed) {
if (psr+1 < S3C64XX_SPI_PSR_MASK) {
psr++;
@@ -851,7 +853,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
}
}
- speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1);
+ speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
if (spi->max_speed_hz >= speed)
spi->max_speed_hz = speed;
else
@@ -867,7 +869,7 @@ setup_exit:
static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
{
- struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
void __iomem *regs = sdd->regs;
unsigned int val;
@@ -902,7 +904,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
{
struct resource *mem_res, *dmatx_res, *dmarx_res;
struct s3c64xx_spi_driver_data *sdd;
- struct s3c64xx_spi_cntrlr_info *sci;
+ struct s3c64xx_spi_info *sci;
struct spi_master *master;
int ret;
@@ -1000,18 +1002,15 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
goto err4;
}
- if (sci->src_clk_nr == S3C64XX_SPI_SRCCLK_PCLK)
- sci->src_clk = sdd->clk;
- else
- sci->src_clk = clk_get(&pdev->dev, sci->src_clk_name);
- if (IS_ERR(sci->src_clk)) {
+ sdd->src_clk = clk_get(&pdev->dev, sci->src_clk_name);
+ if (IS_ERR(sdd->src_clk)) {
dev_err(&pdev->dev,
"Unable to acquire clock '%s'\n", sci->src_clk_name);
- ret = PTR_ERR(sci->src_clk);
+ ret = PTR_ERR(sdd->src_clk);
goto err5;
}
- if (sci->src_clk != sdd->clk && clk_enable(sci->src_clk)) {
+ if (clk_enable(sdd->src_clk)) {
dev_err(&pdev->dev, "Couldn't enable clock '%s'\n",
sci->src_clk_name);
ret = -EBUSY;
@@ -1040,11 +1039,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
goto err8;
}
- dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d \
- with %d Slaves attached\n",
+ dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d "
+ "with %d Slaves attached\n",
pdev->id, master->num_chipselect);
- dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\
- \tDMA=[Rx-%d, Tx-%d]\n",
+ dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
mem_res->end, mem_res->start,
sdd->rx_dmach, sdd->tx_dmach);
@@ -1053,11 +1051,9 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
err8:
destroy_workqueue(sdd->workqueue);
err7:
- if (sci->src_clk != sdd->clk)
- clk_disable(sci->src_clk);
+ clk_disable(sdd->src_clk);
err6:
- if (sci->src_clk != sdd->clk)
- clk_put(sci->src_clk);
+ clk_put(sdd->src_clk);
err5:
clk_disable(sdd->clk);
err4:
@@ -1078,7 +1074,6 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
- struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
struct resource *mem_res;
unsigned long flags;
@@ -1093,11 +1088,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
destroy_workqueue(sdd->workqueue);
- if (sci->src_clk != sdd->clk)
- clk_disable(sci->src_clk);
-
- if (sci->src_clk != sdd->clk)
- clk_put(sci->src_clk);
+ clk_disable(sdd->src_clk);
+ clk_put(sdd->src_clk);
clk_disable(sdd->clk);
clk_put(sdd->clk);
@@ -1105,7 +1097,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
iounmap((void *) sdd->regs);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(mem_res->start, resource_size(mem_res));
+ if (mem_res != NULL)
+ release_mem_region(mem_res->start, resource_size(mem_res));
platform_set_drvdata(pdev, NULL);
spi_master_put(master);
@@ -1118,8 +1111,6 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
{
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
- struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
- struct s3c64xx_spi_csinfo *cs;
unsigned long flags;
spin_lock_irqsave(&sdd->lock, flags);
@@ -1130,9 +1121,7 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
msleep(10);
/* Disable the clock */
- if (sci->src_clk != sdd->clk)
- clk_disable(sci->src_clk);
-
+ clk_disable(sdd->src_clk);
clk_disable(sdd->clk);
sdd->cur_speed = 0; /* Output Clock is stopped */
@@ -1144,15 +1133,13 @@ static int s3c64xx_spi_resume(struct platform_device *pdev)
{
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
- struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
unsigned long flags;
sci->cfg_gpio(pdev);
/* Enable the clock */
- if (sci->src_clk != sdd->clk)
- clk_enable(sci->src_clk);
-
+ clk_enable(sdd->src_clk);
clk_enable(sdd->clk);
s3c64xx_spi_hwinit(sdd, pdev->id);
diff --git a/drivers/spi/spi_sh_msiof.c b/drivers/spi/spi_sh_msiof.c
index 51e5e1dfa6e5..d93b66743ba7 100644
--- a/drivers/spi/spi_sh_msiof.c
+++ b/drivers/spi/spi_sh_msiof.c
@@ -20,12 +20,12 @@
#include <linux/bitmap.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/spi/sh_msiof.h>
-#include <asm/spi.h>
#include <asm/unaligned.h>
struct sh_msiof_spi_priv {
@@ -173,15 +173,12 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
int edge;
/*
- * CPOL CPHA TSCKIZ RSCKIZ TEDG REDG(!)
- * 0 0 10 10 1 0
- * 0 1 10 10 0 1
- * 1 0 11 11 0 1
- * 1 1 11 11 1 0
- *
- * (!) Note: REDG is inverted recommended data sheet setting
+ * CPOL CPHA TSCKIZ RSCKIZ TEDG REDG
+ * 0 0 10 10 1 1
+ * 0 1 10 10 0 0
+ * 1 0 11 11 0 0
+ * 1 1 11 11 1 1
*/
-
sh_msiof_write(p, FCTR, 0);
sh_msiof_write(p, TMDR1, 0xe2000005 | (lsb_first << 24));
sh_msiof_write(p, RMDR1, 0x22000005 | (lsb_first << 24));
@@ -193,7 +190,7 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
edge = cpol ? cpha : !cpha;
tmp |= edge << 27; /* TEDG */
- tmp |= !edge << 26; /* REDG */
+ tmp |= edge << 26; /* REDG */
tmp |= (tx_hi_z ? 2 : 0) << 22; /* TXDIZ */
sh_msiof_write(p, CTR, tmp);
}
diff --git a/drivers/spi/spi_stmp.c b/drivers/spi/spi_stmp.c
index 2552bb364005..fadff76eb7e0 100644
--- a/drivers/spi/spi_stmp.c
+++ b/drivers/spi/spi_stmp.c
@@ -76,7 +76,7 @@ struct stmp_spi {
break; \
} \
cpu_relax(); \
- } while (time_before(end_jiffies, jiffies)); \
+ } while (time_before(jiffies, end_jiffies)); \
succeeded; \
})
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 9f386379c169..1b47363cb73f 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -93,6 +93,26 @@ struct xilinx_spi {
void (*rx_fn) (struct xilinx_spi *);
};
+static void xspi_write32(u32 val, void __iomem *addr)
+{
+ iowrite32(val, addr);
+}
+
+static unsigned int xspi_read32(void __iomem *addr)
+{
+ return ioread32(addr);
+}
+
+static void xspi_write32_be(u32 val, void __iomem *addr)
+{
+ iowrite32be(val, addr);
+}
+
+static unsigned int xspi_read32_be(void __iomem *addr)
+{
+ return ioread32be(addr);
+}
+
static void xspi_tx8(struct xilinx_spi *xspi)
{
xspi->write_fn(*xspi->tx_ptr, xspi->regs + XSPI_TXD_OFFSET);
@@ -374,11 +394,11 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
xspi->mem = *mem;
xspi->irq = irq;
if (pdata->little_endian) {
- xspi->read_fn = ioread32;
- xspi->write_fn = iowrite32;
+ xspi->read_fn = xspi_read32;
+ xspi->write_fn = xspi_write32;
} else {
- xspi->read_fn = ioread32be;
- xspi->write_fn = iowrite32be;
+ xspi->read_fn = xspi_read32_be;
+ xspi->write_fn = xspi_write32_be;
}
xspi->bits_per_word = pdata->bits_per_word;
if (xspi->bits_per_word == 8) {
diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c
index 71dc3adc0495..ed34a8d419c7 100644
--- a/drivers/spi/xilinx_spi_of.c
+++ b/drivers/spi/xilinx_spi_of.c
@@ -99,7 +99,7 @@ static int __exit xilinx_spi_of_remove(struct of_device *op)
return xilinx_spi_remove(op);
}
-static struct of_device_id xilinx_spi_of_match[] = {
+static const struct of_device_id xilinx_spi_of_match[] = {
{ .compatible = "xlnx,xps-spi-2.00.a", },
{ .compatible = "xlnx,xps-spi-2.00.b", },
{}
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 64abd11f6fbb..3d551245a4e2 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -332,6 +332,12 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
case 0x5354:
ssb_pmu0_pllinit_r0(cc, crystalfreq);
break;
+ case 0x4322:
+ if (cc->pmu.rev == 2) {
+ chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, 0x0000000A);
+ chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, 0x380005C0);
+ }
+ break;
default:
ssb_printk(KERN_ERR PFX
"ERROR: PLL init unknown for device %04X\n",
@@ -417,6 +423,7 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
switch (bus->chip_id) {
case 0x4312:
+ case 0x4322:
/* We keep the default settings:
* min_msk = 0xCBB
* max_msk = 0x7FFFF
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c
index 3c6feed46f6e..97efce184a8f 100644
--- a/drivers/ssb/driver_mipscore.c
+++ b/drivers/ssb/driver_mipscore.c
@@ -270,7 +270,6 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
set_irq(dev, irq++);
}
break;
- /* fallthrough */
case SSB_DEV_PCI:
case SSB_DEV_ETHERNET:
case SSB_DEV_ETHERNET_GBIT:
@@ -281,6 +280,10 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
set_irq(dev, irq++);
break;
}
+ /* fallthrough */
+ case SSB_DEV_EXTIF:
+ set_irq(dev, 0);
+ break;
}
}
ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 5681ebed9c65..03dfd27c4bfb 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -494,8 +494,7 @@ static int ssb_devices_register(struct ssb_bus *bus)
#endif
break;
case SSB_BUSTYPE_SDIO:
-#ifdef CONFIG_SSB_SDIO
- sdev->irq = bus->host_sdio->dev.irq;
+#ifdef CONFIG_SSB_SDIOHOST
dev->parent = &bus->host_sdio->dev;
#endif
break;
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
index 56054be4d113..0331139a726f 100644
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -196,7 +196,7 @@ extern int ssb_devices_thaw(struct ssb_freeze_context *ctx);
#ifdef CONFIG_SSB_B43_PCI_BRIDGE
extern int __init b43_pci_ssb_bridge_init(void);
extern void __exit b43_pci_ssb_bridge_exit(void);
-#else /* CONFIG_SSB_B43_PCI_BRIDGR */
+#else /* CONFIG_SSB_B43_PCI_BRIDGE */
static inline int b43_pci_ssb_bridge_init(void)
{
return 0;
@@ -204,6 +204,6 @@ static inline int b43_pci_ssb_bridge_init(void)
static inline void b43_pci_ssb_bridge_exit(void)
{
}
-#endif /* CONFIG_SSB_PCIHOST */
+#endif /* CONFIG_SSB_B43_PCI_BRIDGE */
#endif /* LINUX_SSB_PRIVATE_H_ */
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 94eb86319ff3..7696a664f8a5 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -71,8 +71,6 @@ source "drivers/staging/asus_oled/Kconfig"
source "drivers/staging/panel/Kconfig"
-source "drivers/staging/altpciechdma/Kconfig"
-
source "drivers/staging/rtl8187se/Kconfig"
source "drivers/staging/rtl8192su/Kconfig"
@@ -81,26 +79,18 @@ source "drivers/staging/rtl8192u/Kconfig"
source "drivers/staging/rtl8192e/Kconfig"
-source "drivers/staging/mimio/Kconfig"
-
source "drivers/staging/frontier/Kconfig"
source "drivers/staging/dream/Kconfig"
source "drivers/staging/pohmelfs/Kconfig"
-source "drivers/staging/b3dfg/Kconfig"
-
source "drivers/staging/phison/Kconfig"
-source "drivers/staging/p9auth/Kconfig"
-
source "drivers/staging/line6/Kconfig"
source "drivers/gpu/drm/vmwgfx/Kconfig"
-source "drivers/gpu/drm/radeon/Kconfig"
-
source "drivers/gpu/drm/nouveau/Kconfig"
source "drivers/staging/octeon/Kconfig"
@@ -119,7 +109,7 @@ source "drivers/staging/hv/Kconfig"
source "drivers/staging/vme/Kconfig"
-source "drivers/staging/rar/Kconfig"
+source "drivers/staging/rar_register/Kconfig"
source "drivers/staging/sep/Kconfig"
@@ -145,5 +135,9 @@ source "drivers/staging/netwave/Kconfig"
source "drivers/staging/sm7xx/Kconfig"
+source "drivers/staging/dt3155/Kconfig"
+
+source "drivers/staging/crystalhd/Kconfig"
+
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index b5e67b889f60..ea2e70e2fed4 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -18,18 +18,14 @@ obj-$(CONFIG_RT2870) += rt2870/
obj-$(CONFIG_COMEDI) += comedi/
obj-$(CONFIG_ASUS_OLED) += asus_oled/
obj-$(CONFIG_PANEL) += panel/
-obj-$(CONFIG_ALTERA_PCIE_CHDMA) += altpciechdma/
obj-$(CONFIG_R8187SE) += rtl8187se/
obj-$(CONFIG_RTL8192SU) += rtl8192su/
obj-$(CONFIG_RTL8192U) += rtl8192u/
obj-$(CONFIG_RTL8192E) += rtl8192e/
-obj-$(CONFIG_INPUT_MIMIO) += mimio/
obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_DREAM) += dream/
obj-$(CONFIG_POHMELFS) += pohmelfs/
-obj-$(CONFIG_B3DFG) += b3dfg/
obj-$(CONFIG_IDE_PHISON) += phison/
-obj-$(CONFIG_PLAN9AUTH) += p9auth/
obj-$(CONFIG_LINE6_USB) += line6/
obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/
obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2/
@@ -39,7 +35,7 @@ obj-$(CONFIG_VT6656) += vt6656/
obj-$(CONFIG_FB_UDL) += udlfb/
obj-$(CONFIG_HYPERV) += hv/
obj-$(CONFIG_VME_BUS) += vme/
-obj-$(CONFIG_RAR_REGISTER) += rar/
+obj-$(CONFIG_RAR_REGISTER) += rar_register/
obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_RAMZSWAP) += ramzswap/
@@ -53,3 +49,5 @@ obj-$(CONFIG_WAVELAN) += wavelan/
obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan/
obj-$(CONFIG_PCMCIA_NETWAVE) += netwave/
obj-$(CONFIG_FB_SM7XX) += sm7xx/
+obj-$(CONFIG_DT3155) += dt3155/
+obj-$(CONFIG_CRYSTALHD) += crystalhd/
diff --git a/drivers/staging/altpciechdma/Kconfig b/drivers/staging/altpciechdma/Kconfig
deleted file mode 100644
index 0f4bf92cbbfb..000000000000
--- a/drivers/staging/altpciechdma/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-config ALTERA_PCIE_CHDMA
- tristate "Altera PCI Express Chaining DMA driver"
- depends on PCI
- default N
- ---help---
- A reference driver that exercises the Chaining DMA logic reference
- design generated along the Altera FPGA PCI Express soft or hard core,
- only if instantiated using the MegaWizard, not the SOPC builder, of
- Quartus 8.1.
-
diff --git a/drivers/staging/altpciechdma/Makefile b/drivers/staging/altpciechdma/Makefile
deleted file mode 100644
index c08c8437f4db..000000000000
--- a/drivers/staging/altpciechdma/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_ALTERA_PCIE_CHDMA) += altpciechdma.o
-
diff --git a/drivers/staging/altpciechdma/TODO b/drivers/staging/altpciechdma/TODO
deleted file mode 100644
index 12c945fd61e1..000000000000
--- a/drivers/staging/altpciechdma/TODO
+++ /dev/null
@@ -1,15 +0,0 @@
-DONE:
- - functionality similar to logic testbench
-
-TODO:
- - checkpatch.pl cleanups.
- - keep state of DMA engines.
- - keep data structure that keeps state of each transfer.
- - interrupt handler should iterate over outstanding descriptor tables.
- - complete userspace cdev to read/write using the DMA engines.
- - split off the DMA support functions in a module, re-usable by custom
- drivers.
-
-Please coordinate work with, and send patches to
-Leon Woestenberg <leon@sidebranch.com>
-
diff --git a/drivers/staging/altpciechdma/altpciechdma.c b/drivers/staging/altpciechdma/altpciechdma.c
deleted file mode 100644
index 2f07dd4563ac..000000000000
--- a/drivers/staging/altpciechdma/altpciechdma.c
+++ /dev/null
@@ -1,1182 +0,0 @@
-/**
- * Driver for Altera PCIe core chaining DMA reference design.
- *
- * Copyright (C) 2008 Leon Woestenberg <leon.woestenberg@axon.tv>
- * Copyright (C) 2008 Nickolas Heppermann <heppermannwdt@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *
- * Rationale: This driver exercises the chaining DMA read and write engine
- * in the reference design. It is meant as a complementary reference
- * driver that can be used for testing early designs as well as a basis to
- * write your custom driver.
- *
- * Status: Test results from Leon Woestenberg <leon.woestenberg@axon.tv>:
- *
- * Sendero Board w/ Cyclone II EP2C35F672C6N, PX1011A PCIe x1 PHY on a
- * Dell Precision 370 PC, x86, kernel 2.6.20 from Ubuntu 7.04.
- *
- * Sendero Board w/ Cyclone II EP2C35F672C6N, PX1011A PCIe x1 PHY on a
- * Freescale MPC8313E-RDB board, PowerPC, 2.6.24 w/ Freescale patches.
- *
- * Driver tests passed with PCIe Compiler 8.1. With PCIe 8.0 the DMA
- * loopback test had reproducable compare errors. I assume a change
- * in the compiler or reference design, but could not find evidence nor
- * documentation on a change or fix in that direction.
- *
- * The reference design does not have readable locations and thus a
- * dummy read, used to flush PCI posted writes, cannot be performed.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/cdev.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-
-
-/* by default do not build the character device interface */
-/* XXX It is non-functional yet */
-#ifndef ALTPCIECHDMA_CDEV
-# define ALTPCIECHDMA_CDEV 0
-#endif
-
-/* build the character device interface? */
-#if ALTPCIECHDMA_CDEV
-# define MAX_CHDMA_SIZE (8 * 1024 * 1024)
-# include "mapper_user_to_sg.h"
-#endif
-
-/** driver name, mimicks Altera naming of the reference design */
-#define DRV_NAME "altpciechdma"
-/** number of BARs on the device */
-#define APE_BAR_NUM (6)
-/** BAR number where the RCSLAVE memory sits */
-#define APE_BAR_RCSLAVE (0)
-/** BAR number where the Descriptor Header sits */
-#define APE_BAR_HEADER (2)
-
-/** maximum size in bytes of the descriptor table, chdma logic limit */
-#define APE_CHDMA_TABLE_SIZE (4096)
-/* single transfer must not exceed 255 table entries. worst case this can be
- * achieved by 255 scattered pages, with only a single byte in the head and
- * tail pages. 253 * PAGE_SIZE is a safe upper bound for the transfer size.
- */
-#define APE_CHDMA_MAX_TRANSFER_LEN (253 * PAGE_SIZE)
-
-/**
- * Specifies those BARs to be mapped and the length of each mapping.
- *
- * Zero (0) means do not map, otherwise specifies the BAR lengths to be mapped.
- * If the actual BAR length is less, this is considered an error; then
- * reconfigure your PCIe core.
- *
- * @see ug_pci_express 8.0, table 7-2 at page 7-13.
- */
-static const unsigned long bar_min_len[APE_BAR_NUM] =
- { 32768, 0, 256, 0, 32768, 0 };
-
-/**
- * Descriptor Header, controls the DMA read engine or write engine.
- *
- * The descriptor header is the main data structure for starting DMA transfers.
- *
- * It sits in End Point (FPGA) memory BAR[2] for 32-bit or BAR[3:2] for 64-bit.
- * It references a descriptor table which exists in Root Complex (PC) memory.
- * Writing the rclast field starts the DMA operation, thus all other structures
- * and fields must be setup before doing so.
- *
- * @see ug_pci_express 8.0, tables 7-3, 7-4 and 7-5 at page 7-14.
- * @note This header must be written in four 32-bit (PCI DWORD) writes.
- */
-struct ape_chdma_header {
- /**
- * w0 consists of two 16-bit fields:
- * lsb u16 number; number of descriptors in ape_chdma_table
- * msb u16 control; global control flags
- */
- u32 w0;
- /* bus address to ape_chdma_table in Root Complex memory */
- u32 bdt_addr_h;
- u32 bdt_addr_l;
- /**
- * w3 consists of two 16-bit fields:
- * - lsb u16 rclast; last descriptor number available in Root Complex
- * - zero (0) means the first descriptor is ready,
- * - one (1) means two descriptors are ready, etc.
- * - msb u16 reserved;
- *
- * @note writing to this memory location starts the DMA operation!
- */
- u32 w3;
-} __attribute__ ((packed));
-
-/**
- * Descriptor Entry, describing a (non-scattered) single memory block transfer.
- *
- * There is one descriptor for each memory block involved in the transfer, a
- * block being a contiguous address range on the bus.
- *
- * Multiple descriptors are chained by means of the ape_chdma_table data
- * structure.
- *
- * @see ug_pci_express 8.0, tables 7-6, 7-7 and 7-8 at page 7-14 and page 7-15.
- */
-struct ape_chdma_desc {
- /**
- * w0 consists of two 16-bit fields:
- * number of DWORDS to transfer
- * - lsb u16 length;
- * global control
- * - msb u16 control;
- */
- u32 w0;
- /* address of memory in the End Point */
- u32 ep_addr;
- /* bus address of source or destination memory in the Root Complex */
- u32 rc_addr_h;
- u32 rc_addr_l;
-} __attribute__ ((packed));
-
-/**
- * Descriptor Table, an array of descriptors describing a chained transfer.
- *
- * An array of descriptors, preceded by workspace for the End Point.
- * It exists in Root Complex memory.
- *
- * The End Point can update its last completed descriptor number in the
- * eplast field if requested by setting the EPLAST_ENA bit either
- * globally in the header's or locally in any descriptor's control field.
- *
- * @note this structure may not exceed 4096 bytes. This results in a
- * maximum of 4096 / (4 * 4) - 1 = 255 descriptors per chained transfer.
- *
- * @see ug_pci_express 8.0, tables 7-9, 7-10 and 7-11 at page 7-17 and page 7-18.
- */
-struct ape_chdma_table {
- /* workspace 0x00-0x0b, reserved */
- u32 reserved1[3];
- /* workspace 0x0c-0x0f, last descriptor handled by End Point */
- u32 w3;
- /* the actual array of descriptors
- * 0x10-0x1f, 0x20-0x2f, ... 0xff0-0xfff (255 entries)
- */
- struct ape_chdma_desc desc[255];
-} __attribute__ ((packed));
-
-/**
- * Altera PCI Express ('ape') board specific book keeping data
- *
- * Keeps state of the PCIe core and the Chaining DMA controller
- * application.
- */
-struct ape_dev {
- /** the kernel pci device data structure provided by probe() */
- struct pci_dev *pci_dev;
- /**
- * kernel virtual address of the mapped BAR memory and IO regions of
- * the End Point. Used by map_bars()/unmap_bars().
- */
- void * __iomem bar[APE_BAR_NUM];
- /** kernel virtual address for Descriptor Table in Root Complex memory */
- struct ape_chdma_table *table_virt;
- /**
- * bus address for the Descriptor Table in Root Complex memory, in
- * CPU-native endianess
- */
- dma_addr_t table_bus;
- /* if the device regions could not be allocated, assume and remember it
- * is in use by another driver; this driver must not disable the device.
- */
- int in_use;
- /* whether this driver enabled msi for the device */
- int msi_enabled;
- /* whether this driver could obtain the regions */
- int got_regions;
- /* irq line successfully requested by this driver, -1 otherwise */
- int irq_line;
- /* board revision */
- u8 revision;
- /* interrupt count, incremented by the interrupt handler */
- int irq_count;
-#if ALTPCIECHDMA_CDEV
- /* character device */
- dev_t cdevno;
- struct cdev cdev;
- /* user space scatter gather mapper */
- struct sg_mapping_t *sgm;
-#endif
-};
-
-/**
- * Using the subsystem vendor id and subsystem id, it is possible to
- * distinguish between different cards bases around the same
- * (third-party) logic core.
- *
- * Default Altera vendor and device ID's, and some (non-reserved)
- * ID's are now used here that are used amongst the testers/developers.
- */
-static const struct pci_device_id ids[] = {
- { PCI_DEVICE(0x1172, 0xE001), },
- { PCI_DEVICE(0x2071, 0x2071), },
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci, ids);
-
-#if ALTPCIECHDMA_CDEV
-/* prototypes for character device */
-static int sg_init(struct ape_dev *ape);
-static void sg_exit(struct ape_dev *ape);
-#endif
-
-/**
- * altpciechdma_isr() - Interrupt handler
- *
- */
-static irqreturn_t altpciechdma_isr(int irq, void *dev_id)
-{
- struct ape_dev *ape = (struct ape_dev *)dev_id;
- if (!ape)
- return IRQ_NONE;
- ape->irq_count++;
- return IRQ_HANDLED;
-}
-
-static int __devinit scan_bars(struct ape_dev *ape, struct pci_dev *dev)
-{
- int i;
- for (i = 0; i < APE_BAR_NUM; i++) {
- unsigned long bar_start = pci_resource_start(dev, i);
- if (bar_start) {
- unsigned long bar_end = pci_resource_end(dev, i);
- unsigned long bar_flags = pci_resource_flags(dev, i);
- printk(KERN_DEBUG "BAR%d 0x%08lx-0x%08lx flags 0x%08lx\n",
- i, bar_start, bar_end, bar_flags);
- }
- }
- return 0;
-}
-
-/**
- * Unmap the BAR regions that had been mapped earlier using map_bars()
- */
-static void unmap_bars(struct ape_dev *ape, struct pci_dev *dev)
-{
- int i;
- for (i = 0; i < APE_BAR_NUM; i++) {
- /* is this BAR mapped? */
- if (ape->bar[i]) {
- /* unmap BAR */
- pci_iounmap(dev, ape->bar[i]);
- ape->bar[i] = NULL;
- }
- }
-}
-
-/**
- * Map the device memory regions into kernel virtual address space after
- * verifying their sizes respect the minimum sizes needed, given by the
- * bar_min_len[] array.
- */
-static int __devinit map_bars(struct ape_dev *ape, struct pci_dev *dev)
-{
- int rc;
- int i;
- /* iterate through all the BARs */
- for (i = 0; i < APE_BAR_NUM; i++) {
- unsigned long bar_start = pci_resource_start(dev, i);
- unsigned long bar_end = pci_resource_end(dev, i);
- unsigned long bar_length = bar_end - bar_start + 1;
- ape->bar[i] = NULL;
- /* do not map, and skip, BARs with length 0 */
- if (!bar_min_len[i])
- continue;
- /* do not map BARs with address 0 */
- if (!bar_start || !bar_end) {
- printk(KERN_DEBUG "BAR #%d is not present?!\n", i);
- rc = -1;
- goto fail;
- }
- bar_length = bar_end - bar_start + 1;
- /* BAR length is less than driver requires? */
- if (bar_length < bar_min_len[i]) {
- printk(KERN_DEBUG "BAR #%d length = %lu bytes but driver "
- "requires at least %lu bytes\n",
- i, bar_length, bar_min_len[i]);
- rc = -1;
- goto fail;
- }
- /* map the device memory or IO region into kernel virtual
- * address space */
- ape->bar[i] = pci_iomap(dev, i, bar_min_len[i]);
- if (!ape->bar[i]) {
- printk(KERN_DEBUG "Could not map BAR #%d.\n", i);
- rc = -1;
- goto fail;
- }
- printk(KERN_DEBUG "BAR[%d] mapped at 0x%p with length %lu(/%lu).\n", i,
- ape->bar[i], bar_min_len[i], bar_length);
- }
- /* successfully mapped all required BAR regions */
- rc = 0;
- goto success;
-fail:
- /* unmap any BARs that we did map */
- unmap_bars(ape, dev);
-success:
- return rc;
-}
-
-#if 0 /* not yet implemented fully FIXME add opcode */
-static void __devinit rcslave_test(struct ape_dev *ape, struct pci_dev *dev)
-{
- u32 *rcslave_mem = (u32 *)ape->bar[APE_BAR_RCSLAVE];
- u32 result = 0;
- /** this number is assumed to be different each time this test runs */
- u32 seed = (u32)jiffies;
- u32 value = seed;
- int i;
-
- /* write loop */
- value = seed;
- for (i = 1024; i < 32768 / 4 ; i++) {
- printk(KERN_DEBUG "Writing 0x%08x to 0x%p.\n",
- (u32)value, (void *)rcslave_mem + i);
- iowrite32(value, rcslave_mem + i);
- value++;
- }
- /* read-back loop */
- value = seed;
- for (i = 1024; i < 32768 / 4; i++) {
- result = ioread32(rcslave_mem + i);
- if (result != value) {
- printk(KERN_DEBUG "Wrote 0x%08x to 0x%p, but read back 0x%08x.\n",
- (u32)value, (void *)rcslave_mem + i, (u32)result);
- break;
- }
- value++;
- }
-}
-#endif
-
-/* obtain the 32 most significant (high) bits of a 32-bit or 64-bit address */
-#define pci_dma_h(addr) ((addr >> 16) >> 16)
-/* obtain the 32 least significant (low) bits of a 32-bit or 64-bit address */
-#define pci_dma_l(addr) (addr & 0xffffffffUL)
-
-/* ape_fill_chdma_desc() - Fill a Altera PCI Express Chaining DMA descriptor
- *
- * @desc pointer to descriptor to be filled
- * @addr root complex address
- * @ep_addr end point address
- * @len number of bytes, must be a multiple of 4.
- */
-static inline void ape_chdma_desc_set(struct ape_chdma_desc *desc, dma_addr_t addr, u32 ep_addr, int len)
-{
- BUG_ON(len & 3);
- desc->w0 = cpu_to_le32(len / 4);
- desc->ep_addr = cpu_to_le32(ep_addr);
- desc->rc_addr_h = cpu_to_le32(pci_dma_h(addr));
- desc->rc_addr_l = cpu_to_le32(pci_dma_l(addr));
-}
-
-#if ALTPCIECHDMA_CDEV
-/*
- * ape_sg_to_chdma_table() - Create a device descriptor table from a scatterlist.
- *
- * The scatterlist must have been mapped by pci_map_sg(sgm->sgl).
- *
- * @sgl scatterlist.
- * @nents Number of entries in the scatterlist.
- * @first Start index in the scatterlist sgm->sgl.
- * @ep_addr End Point address for the scatter/gather transfer.
- * @desc pointer to first descriptor
- *
- * Returns Number of entries in the table on success, -1 on error.
- */
-static int ape_sg_to_chdma_table(struct scatterlist *sgl, int nents, int first, struct ape_chdma_desc *desc, u32 ep_addr)
-{
- int i = first, j = 0;
- /* inspect first entry */
- dma_addr_t addr = sg_dma_address(&sgl[i]);
- unsigned int len = sg_dma_len(&sgl[i]);
- /* contiguous block */
- dma_addr_t cont_addr = addr;
- unsigned int cont_len = len;
- /* iterate over remaining entries */
- for (; j < 25 && i < nents - 1; i++) {
- /* bus address of next entry i + 1 */
- dma_addr_t next = sg_dma_address(&sgl[i + 1]);
- /* length of this entry i */
- len = sg_dma_len(&sgl[i]);
- printk(KERN_DEBUG "%04d: addr=0x%Lx length=0x%08x\n", i,
- (unsigned long long)addr, len);
- /* entry i + 1 is non-contiguous with entry i? */
- if (next != addr + len) {
- /* TODO create entry here (we could overwrite i) */
- printk(KERN_DEBUG "%4d: cont_addr=0x%Lx cont_len=0x%08x\n", j,
- (unsigned long long)cont_addr, cont_len);
- /* set descriptor for contiguous transfer */
- ape_chdma_desc_set(&desc[j], cont_addr, ep_addr, cont_len);
- /* next end point memory address */
- ep_addr += cont_len;
- /* start new contiguous block */
- cont_addr = next;
- cont_len = 0;
- j++;
- }
- /* add entry i + 1 to current contiguous block */
- cont_len += len;
- /* goto entry i + 1 */
- addr = next;
- }
- /* TODO create entry here (we could overwrite i) */
- printk(KERN_DEBUG "%04d: addr=0x%Lx length=0x%08x\n", i,
- (unsigned long long)addr, len);
- printk(KERN_DEBUG "%4d: cont_addr=0x%Lx length=0x%08x\n", j,
- (unsigned long long)cont_addr, cont_len);
- j++;
- return j;
-}
-#endif
-
-/* compare buffers */
-static inline int compare(u32 *p, u32 *q, int len)
-{
- int result = -1;
- int fail = 0;
- int i;
- for (i = 0; i < len / 4; i++) {
- if (*p == *q) {
- /* every so many u32 words, show equals */
- if ((i & 255) == 0)
- printk(KERN_DEBUG "[%p] = 0x%08x [%p] = 0x%08x\n", p, *p, q, *q);
- } else {
- fail++;
- /* show the first few miscompares */
- if (fail < 10)
- printk(KERN_DEBUG "[%p] = 0x%08x != [%p] = 0x%08x ?!\n", p, *p, q, *q);
- /* but stop after a while */
- else if (fail == 10)
- printk(KERN_DEBUG "---more errors follow! not printed---\n");
- else
- /* stop compare after this many errors */
- break;
- }
- p++;
- q++;
- }
- if (!fail)
- result = 0;
- return result;
-}
-
-/* dma_test() - Perform DMA loop back test to end point and back to root complex.
- *
- * Allocate a cache-coherent buffer in host memory, consisting of four pages.
- *
- * Fill the four memory pages such that each 32-bit word contains its own address.
- *
- * Now perform a loop back test, have the end point device copy the first buffer
- * half to end point memory, then have it copy back into the second half.
- *
- * Create a descriptor table to copy the first buffer half into End Point
- * memory. Instruct the End Point to do a DMA read using that table.
- *
- * Create a descriptor table to copy End Point memory to the second buffer
- * half. Instruct the End Point to do a DMA write using that table.
- *
- * Compare results, fail or pass.
- *
- */
-static int __devinit dma_test(struct ape_dev *ape, struct pci_dev *dev)
-{
- /* test result; guilty until proven innocent */
- int result = -1;
- /* the DMA read header sits at address 0x00 of the DMA engine BAR */
- struct ape_chdma_header *write_header = (struct ape_chdma_header *)ape->bar[APE_BAR_HEADER];
- /* the write DMA header sits after the read header at address 0x10 */
- struct ape_chdma_header *read_header = write_header + 1;
- /* virtual address of the allocated buffer */
- u8 *buffer_virt = 0;
- /* bus address of the allocated buffer */
- dma_addr_t buffer_bus = 0;
- int i, n = 0, irq_count;
-
- /* temporary value used to construct 32-bit data words */
- u32 w;
-
- printk(KERN_DEBUG "bar_tests(), PAGE_SIZE = 0x%0x\n", (int)PAGE_SIZE);
- printk(KERN_DEBUG "write_header = 0x%p.\n", write_header);
- printk(KERN_DEBUG "read_header = 0x%p.\n", read_header);
- printk(KERN_DEBUG "&write_header->w3 = 0x%p\n", &write_header->w3);
- printk(KERN_DEBUG "&read_header->w3 = 0x%p\n", &read_header->w3);
- printk(KERN_DEBUG "ape->table_virt = 0x%p.\n", ape->table_virt);
-
- if (!write_header || !read_header || !ape->table_virt)
- goto fail;
-
- /* allocate and map coherently-cached memory for a DMA-able buffer */
- /* @see Documentation/PCI/PCI-DMA-mapping.txt, near line 318 */
- buffer_virt = (u8 *)pci_alloc_consistent(dev, PAGE_SIZE * 4, &buffer_bus);
- if (!buffer_virt) {
- printk(KERN_DEBUG "Could not allocate coherent DMA buffer.\n");
- goto fail;
- }
- printk(KERN_DEBUG "Allocated cache-coherent DMA buffer (virtual address = %p, bus address = 0x%016llx).\n",
- buffer_virt, (u64)buffer_bus);
-
- /* fill first half of buffer with its virtual address as data */
- for (i = 0; i < 4 * PAGE_SIZE; i += 4)
-#if 0
- *(u32 *)(buffer_virt + i) = i / PAGE_SIZE + 1;
-#else
- *(u32 *)(buffer_virt + i) = (u32)(unsigned long)(buffer_virt + i);
-#endif
-#if 0
- compare((u32 *)buffer_virt, (u32 *)(buffer_virt + 2 * PAGE_SIZE), 8192);
-#endif
-
-#if 0
- /* fill second half of buffer with zeroes */
- for (i = 2 * PAGE_SIZE; i < 4 * PAGE_SIZE; i += 4)
- *(u32 *)(buffer_virt + i) = 0;
-#endif
-
- /* invalidate EPLAST, outside 0-255, 0xFADE is from the testbench */
- ape->table_virt->w3 = cpu_to_le32(0x0000FADE);
-
- /* fill in first descriptor */
- n = 0;
- /* read 8192 bytes from RC buffer to EP address 4096 */
- ape_chdma_desc_set(&ape->table_virt->desc[n], buffer_bus, 4096, 2 * PAGE_SIZE);
-#if 1
- for (i = 0; i < 255; i++)
- ape_chdma_desc_set(&ape->table_virt->desc[i], buffer_bus, 4096, 2 * PAGE_SIZE);
- /* index of last descriptor */
- n = i - 1;
-#endif
-#if 0
- /* fill in next descriptor */
- n++;
- /* read 1024 bytes from RC buffer to EP address 4096 + 1024 */
- ape_chdma_desc_set(&ape->table_virt->desc[n], buffer_bus + 1024, 4096 + 1024, 1024);
-#endif
-
-#if 1
- /* enable MSI after the last descriptor is completed */
- if (ape->msi_enabled)
- ape->table_virt->desc[n].w0 |= cpu_to_le32(1UL << 16)/*local MSI*/;
-#endif
-#if 0
- /* dump descriptor table for debugging */
- printk(KERN_DEBUG "Descriptor Table (Read, in Root Complex Memory, # = %d)\n", n + 1);
- for (i = 0; i < 4 + (n + 1) * 4; i += 4) {
- u32 *p = (u32 *)ape->table_virt;
- p += i;
- printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (LEN=0x%x)\n", (u32)p, (u32)p & 15, *p, 4 * le32_to_cpu(*p));
- p++;
- printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (EPA=0x%x)\n", (u32)p, (u32)p & 15, *p, le32_to_cpu(*p));
- p++;
- printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (RCH=0x%x)\n", (u32)p, (u32)p & 15, *p, le32_to_cpu(*p));
- p++;
- printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (RCL=0x%x)\n", (u32)p, (u32)p & 15, *p, le32_to_cpu(*p));
- }
-#endif
- /* set available number of descriptors in table */
- w = (u32)(n + 1);
- w |= (1UL << 18)/*global EPLAST_EN*/;
-#if 0
- if (ape->msi_enabled)
- w |= (1UL << 17)/*global MSI*/;
-#endif
- printk(KERN_DEBUG "writing 0x%08x to 0x%p\n", w, (void *)&read_header->w0);
- iowrite32(w, &read_header->w0);
-
- /* write table address (higher 32-bits) */
- printk(KERN_DEBUG "writing 0x%08x to 0x%p\n", (u32)((ape->table_bus >> 16) >> 16), (void *)&read_header->bdt_addr_h);
- iowrite32(pci_dma_h(ape->table_bus), &read_header->bdt_addr_h);
-
- /* write table address (lower 32-bits) */
- printk(KERN_DEBUG "writing 0x%08x to 0x%p\n", (u32)(ape->table_bus & 0xffffffffUL), (void *)&read_header->bdt_addr_l);
- iowrite32(pci_dma_l(ape->table_bus), &read_header->bdt_addr_l);
-
- /* memory write barrier */
- wmb();
- printk(KERN_DEBUG "Flush posted writes\n");
- /** FIXME Add dummy read to flush posted writes but need a readable location! */
-#if 0
- (void)ioread32();
-#endif
-
- /* remember IRQ count before the transfer */
- irq_count = ape->irq_count;
- /* write number of descriptors - this starts the DMA */
- printk(KERN_DEBUG "\nStart DMA read\n");
- printk(KERN_DEBUG "writing 0x%08x to 0x%p\n", (u32)n, (void *)&read_header->w3);
- iowrite32(n, &read_header->w3);
- printk(KERN_DEBUG "EPLAST = %lu\n", le32_to_cpu(*(u32 *)&ape->table_virt->w3) & 0xffffUL);
-
- /** memory write barrier */
- wmb();
- /* dummy read to flush posted writes */
- /* FIXME Need a readable location! */
-#if 0
- (void)ioread32();
-#endif
- printk(KERN_DEBUG "POLL FOR READ:\n");
- /* poll for chain completion, 1000 times 1 millisecond */
- for (i = 0; i < 100; i++) {
- volatile u32 *p = &ape->table_virt->w3;
- u32 eplast = le32_to_cpu(*p) & 0xffffUL;
- printk(KERN_DEBUG "EPLAST = %u, n = %d\n", eplast, n);
- if (eplast == n) {
- printk(KERN_DEBUG "DONE\n");
- /* print IRQ count before the transfer */
- printk(KERN_DEBUG "#IRQs during transfer: %d\n", ape->irq_count - irq_count);
- break;
- }
- udelay(100);
- }
-
- /* invalidate EPLAST, outside 0-255, 0xFADE is from the testbench */
- ape->table_virt->w3 = cpu_to_le32(0x0000FADE);
-
- /* setup first descriptor */
- n = 0;
- ape_chdma_desc_set(&ape->table_virt->desc[n], buffer_bus + 8192, 4096, 2 * PAGE_SIZE);
-#if 1
- for (i = 0; i < 255; i++)
- ape_chdma_desc_set(&ape->table_virt->desc[i], buffer_bus + 8192, 4096, 2 * PAGE_SIZE);
-
- /* index of last descriptor */
- n = i - 1;
-#endif
-#if 1 /* test variable, make a module option later */
- if (ape->msi_enabled)
- ape->table_virt->desc[n].w0 |= cpu_to_le32(1UL << 16)/*local MSI*/;
-#endif
-#if 0
- /* dump descriptor table for debugging */
- printk(KERN_DEBUG "Descriptor Table (Write, in Root Complex Memory, # = %d)\n", n + 1);
- for (i = 0; i < 4 + (n + 1) * 4; i += 4) {
- u32 *p = (u32 *)ape->table_virt;
- p += i;
- printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (LEN=0x%x)\n", (u32)p, (u32)p & 15, *p, 4 * le32_to_cpu(*p));
- p++;
- printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (EPA=0x%x)\n", (u32)p, (u32)p & 15, *p, le32_to_cpu(*p));
- p++;
- printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (RCH=0x%x)\n", (u32)p, (u32)p & 15, *p, le32_to_cpu(*p));
- p++;
- printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (RCL=0x%x)\n", (u32)p, (u32)p & 15, *p, le32_to_cpu(*p));
- }
-#endif
-
- /* set number of available descriptors in the table */
- w = (u32)(n + 1);
- /* enable updates of eplast for each descriptor completion */
- w |= (u32)(1UL << 18)/*global EPLAST_EN*/;
-#if 0 /* test variable, make a module option later */
- /* enable MSI for each descriptor completion */
- if (ape->msi_enabled)
- w |= (1UL << 17)/*global MSI*/;
-#endif
- iowrite32(w, &write_header->w0);
- iowrite32(pci_dma_h(ape->table_bus), &write_header->bdt_addr_h);
- iowrite32(pci_dma_l(ape->table_bus), &write_header->bdt_addr_l);
-
- /** memory write barrier and flush posted writes */
- wmb();
- /* dummy read to flush posted writes */
- /* FIXME Need a readable location! */
-#if 0
- (void)ioread32();
-#endif
- irq_count = ape->irq_count;
-
- printk(KERN_DEBUG "\nStart DMA write\n");
- iowrite32(n, &write_header->w3);
-
- /** memory write barrier */
- wmb();
- /** dummy read to flush posted writes */
- /* (void) ioread32(); */
-
- printk(KERN_DEBUG "POLL FOR WRITE:\n");
- /* poll for completion, 1000 times 1 millisecond */
- for (i = 0; i < 100; i++) {
- volatile u32 *p = &ape->table_virt->w3;
- u32 eplast = le32_to_cpu(*p) & 0xffffUL;
- printk(KERN_DEBUG "EPLAST = %u, n = %d\n", eplast, n);
- if (eplast == n) {
- printk(KERN_DEBUG "DONE\n");
- /* print IRQ count before the transfer */
- printk(KERN_DEBUG "#IRQs during transfer: %d\n", ape->irq_count - irq_count);
- break;
- }
- udelay(100);
- }
- /* soft-reset DMA write engine */
- iowrite32(0x0000ffffUL, &write_header->w0);
- /* soft-reset DMA read engine */
- iowrite32(0x0000ffffUL, &read_header->w0);
-
- /** memory write barrier */
- wmb();
- /* dummy read to flush posted writes */
- /* FIXME Need a readable location! */
-#if 0
- (void)ioread32();
-#endif
- /* compare first half of buffer with second half, should be identical */
- result = compare((u32 *)buffer_virt, (u32 *)(buffer_virt + 2 * PAGE_SIZE), 8192);
- printk(KERN_DEBUG "DMA loop back test %s.\n", result ? "FAILED" : "PASSED");
-
- pci_free_consistent(dev, 4 * PAGE_SIZE, buffer_virt, buffer_bus);
-fail:
- printk(KERN_DEBUG "bar_tests() end, result %d\n", result);
- return result;
-}
-
-/* Called when the PCI sub system thinks we can control the given device.
- * Inspect if we can support the device and if so take control of it.
- *
- * Return 0 when we have taken control of the given device.
- *
- * - allocate board specific bookkeeping
- * - allocate coherently-mapped memory for the descriptor table
- * - enable the board
- * - verify board revision
- * - request regions
- * - query DMA mask
- * - obtain and request irq
- * - map regions into kernel address space
- */
-static int __devinit probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
- int rc = 0;
- struct ape_dev *ape = NULL;
- u8 irq_pin, irq_line;
- printk(KERN_DEBUG "probe(dev = 0x%p, pciid = 0x%p)\n", dev, id);
-
- /* allocate memory for per-board book keeping */
- ape = kzalloc(sizeof(struct ape_dev), GFP_KERNEL);
- if (!ape) {
- printk(KERN_DEBUG "Could not kzalloc()ate memory.\n");
- goto err_ape;
- }
- ape->pci_dev = dev;
- dev_set_drvdata(&dev->dev, ape);
- printk(KERN_DEBUG "probe() ape = 0x%p\n", ape);
-
- printk(KERN_DEBUG "sizeof(struct ape_chdma_table) = %d.\n",
- (int)sizeof(struct ape_chdma_table));
- /* the reference design has a size restriction on the table size */
- BUG_ON(sizeof(struct ape_chdma_table) > APE_CHDMA_TABLE_SIZE);
-
- /* allocate and map coherently-cached memory for a descriptor table */
- /* @see LDD3 page 446 */
- ape->table_virt = (struct ape_chdma_table *)pci_alloc_consistent(dev,
- APE_CHDMA_TABLE_SIZE, &ape->table_bus);
- /* could not allocate table? */
- if (!ape->table_virt) {
- printk(KERN_DEBUG "Could not dma_alloc()ate_coherent memory.\n");
- goto err_table;
- }
-
- printk(KERN_DEBUG "table_virt = %p, table_bus = 0x%16llx.\n",
- ape->table_virt, (u64)ape->table_bus);
-
- /* enable device */
- rc = pci_enable_device(dev);
- if (rc) {
- printk(KERN_DEBUG "pci_enable_device() failed\n");
- goto err_enable;
- }
-
- /* enable bus master capability on device */
- pci_set_master(dev);
- /* enable message signaled interrupts */
- rc = pci_enable_msi(dev);
- /* could not use MSI? */
- if (rc) {
- /* resort to legacy interrupts */
- printk(KERN_DEBUG "Could not enable MSI interrupting.\n");
- ape->msi_enabled = 0;
- /* MSI enabled, remember for cleanup */
- } else {
- printk(KERN_DEBUG "Enabled MSI interrupting.\n");
- ape->msi_enabled = 1;
- }
-
- pci_read_config_byte(dev, PCI_REVISION_ID, &ape->revision);
-#if 0 /* example */
- /* (for example) this driver does not support revision 0x42 */
- if (ape->revision == 0x42) {
- printk(KERN_DEBUG "Revision 0x42 is not supported by this driver.\n");
- rc = -ENODEV;
- goto err_rev;
- }
-#endif
- /** XXX check for native or legacy PCIe endpoint? */
-
- rc = pci_request_regions(dev, DRV_NAME);
- /* could not request all regions? */
- if (rc) {
- /* assume device is in use (and do not disable it later!) */
- ape->in_use = 1;
- goto err_regions;
- }
- ape->got_regions = 1;
-
-#if 1 /* @todo For now, disable 64-bit, because I do not understand the implications (DAC!) */
- /* query for DMA transfer */
- /* @see Documentation/PCI/PCI-DMA-mapping.txt */
- if (!pci_set_dma_mask(dev, DMA_BIT_MASK(64))) {
- pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(64));
- /* use 64-bit DMA */
- printk(KERN_DEBUG "Using a 64-bit DMA mask.\n");
- } else
-#endif
- if (!pci_set_dma_mask(dev, DMA_BIT_MASK(32))) {
- printk(KERN_DEBUG "Could not set 64-bit DMA mask.\n");
- pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(32));
- /* use 32-bit DMA */
- printk(KERN_DEBUG "Using a 32-bit DMA mask.\n");
- } else {
- printk(KERN_DEBUG "No suitable DMA possible.\n");
- /** @todo Choose proper error return code */
- rc = -1;
- goto err_mask;
- }
-
- rc = pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
- /* could not read? */
- if (rc)
- goto err_irq;
- printk(KERN_DEBUG "IRQ pin #%d (0=none, 1=INTA#...4=INTD#).\n", irq_pin);
-
- /* @see LDD3, page 318 */
- rc = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq_line);
- /* could not read? */
- if (rc) {
- printk(KERN_DEBUG "Could not query PCI_INTERRUPT_LINE, error %d\n", rc);
- goto err_irq;
- }
- printk(KERN_DEBUG "IRQ line #%d.\n", irq_line);
-#if 1
- irq_line = dev->irq;
- /* @see LDD3, page 259 */
- rc = request_irq(irq_line, altpciechdma_isr, IRQF_SHARED, DRV_NAME, (void *)ape);
- if (rc) {
- printk(KERN_DEBUG "Could not request IRQ #%d, error %d\n", irq_line, rc);
- ape->irq_line = -1;
- goto err_irq;
- }
- /* remember which irq we allocated */
- ape->irq_line = (int)irq_line;
- printk(KERN_DEBUG "Succesfully requested IRQ #%d with dev_id 0x%p\n", irq_line, ape);
-#endif
- /* show BARs */
- scan_bars(ape, dev);
- /* map BARs */
- rc = map_bars(ape, dev);
- if (rc)
- goto err_map;
-#if ALTPCIECHDMA_CDEV
- /* initialize character device */
- rc = sg_init(ape);
- if (rc)
- goto err_cdev;
-#endif
- /* perform DMA engines loop back test */
- rc = dma_test(ape, dev);
- (void)rc;
- /* successfully took the device */
- rc = 0;
- printk(KERN_DEBUG "probe() successful.\n");
- goto end;
-#if ALTPCIECHDMA_CDEV
-err_cdev:
- /* unmap the BARs */
- unmap_bars(ape, dev);
-#endif
-err_map:
- /* free allocated irq */
- if (ape->irq_line >= 0)
- free_irq(ape->irq_line, (void *)ape);
-err_irq:
- if (ape->msi_enabled)
- pci_disable_msi(dev);
- /* disable the device iff it is not in use */
- if (!ape->in_use)
- pci_disable_device(dev);
- if (ape->got_regions)
- pci_release_regions(dev);
-err_mask:
-err_regions:
-/*err_rev:*/
-/* clean up everything before device enable() */
-err_enable:
- if (ape->table_virt)
- pci_free_consistent(dev, APE_CHDMA_TABLE_SIZE, ape->table_virt, ape->table_bus);
-/* clean up everything before allocating descriptor table */
-err_table:
- if (ape)
- kfree(ape);
-err_ape:
-end:
- return rc;
-}
-
-static void __devexit remove(struct pci_dev *dev)
-{
- struct ape_dev *ape = dev_get_drvdata(&dev->dev);
-
- printk(KERN_DEBUG "remove(0x%p)\n", dev);
- printk(KERN_DEBUG "remove(dev = 0x%p) where ape = 0x%p\n", dev, ape);
-
- /* remove character device */
-#if ALTPCIECHDMA_CDEV
- sg_exit(ape);
-#endif
-
- if (ape->table_virt)
- pci_free_consistent(dev, APE_CHDMA_TABLE_SIZE, ape->table_virt, ape->table_bus);
-
- /* free IRQ
- * @see LDD3 page 279
- */
- if (ape->irq_line >= 0) {
- printk(KERN_DEBUG "Freeing IRQ #%d for dev_id 0x%08lx.\n",
- ape->irq_line, (unsigned long)ape);
- free_irq(ape->irq_line, (void *)ape);
- }
- /* MSI was enabled? */
- if (ape->msi_enabled) {
- /* Disable MSI @see Documentation/MSI-HOWTO.txt */
- pci_disable_msi(dev);
- ape->msi_enabled = 0;
- }
- /* unmap the BARs */
- unmap_bars(ape, dev);
- if (!ape->in_use)
- pci_disable_device(dev);
- if (ape->got_regions)
- /* to be called after device disable */
- pci_release_regions(dev);
-}
-
-#if ALTPCIECHDMA_CDEV
-
-/*
- * Called when the device goes from unused to used.
- */
-static int sg_open(struct inode *inode, struct file *file)
-{
- struct ape_dev *ape;
- printk(KERN_DEBUG DRV_NAME "_open()\n");
- /* pointer to containing data structure of the character device inode */
- ape = container_of(inode->i_cdev, struct ape_dev, cdev);
- /* create a reference to our device state in the opened file */
- file->private_data = ape;
- /* create virtual memory mapper */
- ape->sgm = sg_create_mapper(MAX_CHDMA_SIZE);
- return 0;
-}
-
-/*
- * Called when the device goes from used to unused.
- */
-static int sg_close(struct inode *inode, struct file *file)
-{
- /* fetch device specific data stored earlier during open */
- struct ape_dev *ape = (struct ape_dev *)file->private_data;
- printk(KERN_DEBUG DRV_NAME "_close()\n");
- /* destroy virtual memory mapper */
- sg_destroy_mapper(ape->sgm);
- return 0;
-}
-
-static ssize_t sg_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
-{
- /* fetch device specific data stored earlier during open */
- struct ape_dev *ape = (struct ape_dev *)file->private_data;
- (void)ape;
- printk(KERN_DEBUG DRV_NAME "_read(buf=0x%p, count=%lld, pos=%llu)\n", buf, (s64)count, (u64)*pos);
- return count;
-}
-
-/* sg_write() - Write to the device
- *
- * @buf userspace buffer
- * @count number of bytes in the userspace buffer
- *
- * Iterate over the userspace buffer, taking at most 255 * PAGE_SIZE bytes for
- * each DMA transfer.
- * For each transfer, get the user pages, build a sglist, map, build a
- * descriptor table. submit the transfer. wait for the interrupt handler
- * to wake us on completion.
- */
-static ssize_t sg_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
-{
- int hwnents, tents;
- size_t transfer_len, remaining = count, done = 0;
- u64 transfer_addr = (u64)buf;
- /* fetch device specific data stored earlier during open */
- struct ape_dev *ape = (struct ape_dev *)file->private_data;
- printk(KERN_DEBUG DRV_NAME "_write(buf=0x%p, count=%lld, pos=%llu)\n",
- buf, (s64)count, (u64)*pos);
- /* TODO transfer boundaries at PAGE_SIZE granularity */
- while (remaining > 0) {
- /* limit DMA transfer size */
- transfer_len = (remaining < APE_CHDMA_MAX_TRANSFER_LEN) ? remaining :
- APE_CHDMA_MAX_TRANSFER_LEN;
- /* get all user space buffer pages and create a scattergather list */
- sgm_map_user_pages(ape->sgm, transfer_addr, transfer_len, 0/*read from userspace*/);
- printk(KERN_DEBUG DRV_NAME "mapped_pages=%d\n", ape->sgm->mapped_pages);
- /* map all entries in the scattergather list */
- hwnents = pci_map_sg(ape->pci_dev, ape->sgm->sgl, ape->sgm->mapped_pages, DMA_TO_DEVICE);
- printk(KERN_DEBUG DRV_NAME "hwnents=%d\n", hwnents);
- /* build device descriptor tables and submit them to the DMA engine */
- tents = ape_sg_to_chdma_table(ape->sgm->sgl, hwnents, 0, &ape->table_virt->desc[0], 4096);
- printk(KERN_DEBUG DRV_NAME "tents=%d\n", hwnents);
-#if 0
- while (tables) {
- /* TODO build table */
- /* TODO submit table to the device */
- /* if engine stopped and unfinished work then start engine */
- }
- put ourselves on wait queue
-#endif
-
- dma_unmap_sg(NULL, ape->sgm->sgl, ape->sgm->mapped_pages, DMA_TO_DEVICE);
- /* dirty and free the pages */
- sgm_unmap_user_pages(ape->sgm, 1/*dirtied*/);
- /* book keeping */
- transfer_addr += transfer_len;
- remaining -= transfer_len;
- done += transfer_len;
- }
- return done;
-}
-
-/*
- * character device file operations
- */
-static const struct file_operations sg_fops = {
- .owner = THIS_MODULE,
- .open = sg_open,
- .release = sg_close,
- .read = sg_read,
- .write = sg_write,
-};
-
-/* sg_init() - Initialize character device
- *
- * XXX Should ideally be tied to the device, on device probe, not module init.
- */
-static int sg_init(struct ape_dev *ape)
-{
- int rc;
- printk(KERN_DEBUG DRV_NAME " sg_init()\n");
- /* allocate a dynamically allocated character device node */
- rc = alloc_chrdev_region(&ape->cdevno, 0/*requested minor*/, 1/*count*/, DRV_NAME);
- /* allocation failed? */
- if (rc < 0) {
- printk("alloc_chrdev_region() = %d\n", rc);
- goto fail_alloc;
- }
- /* couple the device file operations to the character device */
- cdev_init(&ape->cdev, &sg_fops);
- ape->cdev.owner = THIS_MODULE;
- /* bring character device live */
- rc = cdev_add(&ape->cdev, ape->cdevno, 1/*count*/);
- if (rc < 0) {
- printk("cdev_add() = %d\n", rc);
- goto fail_add;
- }
- printk(KERN_DEBUG "altpciechdma = %d:%d\n", MAJOR(ape->cdevno), MINOR(ape->cdevno));
- return 0;
-fail_add:
- /* free the dynamically allocated character device node */
- unregister_chrdev_region(ape->cdevno, 1/*count*/);
-fail_alloc:
- return -1;
-}
-
-/* sg_exit() - Cleanup character device
- *
- * XXX Should ideally be tied to the device, on device remove, not module exit.
- */
-
-static void sg_exit(struct ape_dev *ape)
-{
- printk(KERN_DEBUG DRV_NAME " sg_exit()\n");
- /* remove the character device */
- cdev_del(&ape->cdev);
- /* free the dynamically allocated character device node */
- unregister_chrdev_region(ape->cdevno, 1/*count*/);
-}
-
-#endif /* ALTPCIECHDMA_CDEV */
-
-/* used to register the driver with the PCI kernel sub system
- * @see LDD3 page 311
- */
-static struct pci_driver pci_driver = {
- .name = DRV_NAME,
- .id_table = ids,
- .probe = probe,
- .remove = __devexit_p(remove),
- /* resume, suspend are optional */
-};
-
-/**
- * alterapciechdma_init() - Module initialization, registers devices.
- */
-static int __init alterapciechdma_init(void)
-{
- int rc = 0;
- printk(KERN_DEBUG DRV_NAME " init(), built at " __DATE__ " " __TIME__ "\n");
- /* register this driver with the PCI bus driver */
- rc = pci_register_driver(&pci_driver);
- if (rc < 0)
- return rc;
- return 0;
-}
-
-/**
- * alterapciechdma_init() - Module cleanup, unregisters devices.
- */
-static void __exit alterapciechdma_exit(void)
-{
- printk(KERN_DEBUG DRV_NAME " exit(), built at " __DATE__ " " __TIME__ "\n");
- /* unregister this driver from the PCI bus driver */
- pci_unregister_driver(&pci_driver);
-}
-
-MODULE_LICENSE("GPL");
-
-module_init(alterapciechdma_init);
-module_exit(alterapciechdma_exit);
-
diff --git a/drivers/staging/arlan/Makefile b/drivers/staging/arlan/Makefile
index 9e58e5fae7b9..5a84d4402f21 100644
--- a/drivers/staging/arlan/Makefile
+++ b/drivers/staging/arlan/Makefile
@@ -1,3 +1,3 @@
-obj-$(CONFIG_ARLAN) += arlan.o
+obj-$(CONFIG_ARLAN) += arlan.o
arlan-objs := arlan-main.o arlan-proc.o
diff --git a/drivers/staging/arlan/arlan-main.c b/drivers/staging/arlan/arlan-main.c
index 921a082487a1..88fdd53cf5d3 100644
--- a/drivers/staging/arlan/arlan-main.c
+++ b/drivers/staging/arlan/arlan-main.c
@@ -1455,10 +1455,10 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
#ifdef ARLAN_MULTICAST
if (!(dev->flags & IFF_ALLMULTI) &&
!(dev->flags & IFF_PROMISC) &&
- dev->mc_list)
+ !netdev_mc_empty(dev))
{
char hw_dst_addr[6];
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
int i;
memcpy_fromio(hw_dst_addr, arlan->ultimateDestAddress, 6);
@@ -1469,20 +1469,15 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
printk(KERN_ERR "%s mcast 0x0100 \n", dev->name);
else if (hw_dst_addr[1] == 0x40)
printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name);
- while (dmi)
- {
- if (dmi->dmi_addrlen == 6) {
- if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP)
- printk(KERN_ERR "%s mcl %pM\n",
- dev->name, dmi->dmi_addr);
- for (i = 0; i < 6; i++)
- if (dmi->dmi_addr[i] != hw_dst_addr[i])
- break;
- if (i == 6)
+ netdev_for_each_mc_entry(dmi, dev) {
+ if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP)
+ printk(KERN_ERR "%s mcl %pM\n",
+ dev->name, dmi->dmi_addr);
+ for (i = 0; i < 6; i++)
+ if (dmi->dmi_addr[i] != hw_dst_addr[i])
break;
- } else
- printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name);
- dmi = dmi->next;
+ if (i == 6)
+ break;
}
/* we reach here if multicast filtering is on and packet
* is multicast and not for receive */
diff --git a/drivers/staging/arlan/arlan.h b/drivers/staging/arlan/arlan.h
index fb3ad51a1caf..ffcd3ea048aa 100644
--- a/drivers/staging/arlan/arlan.h
+++ b/drivers/staging/arlan/arlan.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1997 Cullen Jennings
- * Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500
+ * Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500
* GNU General Public License applies
*/
@@ -20,14 +20,14 @@
#include <linux/init.h>
#include <linux/bitops.h>
#include <asm/system.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-//#define ARLAN_DEBUGGING 1
+/* #define ARLAN_DEBUGGING 1 */
#define ARLAN_PROC_INTERFACE
#define MAX_ARLANS 4 /* not more than 4 ! */
@@ -51,8 +51,8 @@ extern int arlan_debug;
extern int arlan_entry_debug;
extern int arlan_exit_debug;
extern int testMemory;
-extern int arlan_command(struct net_device * dev, int command);
-
+extern int arlan_command(struct net_device *dev, int command);
+
#define SIDUNKNOWN -1
#define radioNodeIdUNKNOWN -1
#define irqUNKNOWN 0
@@ -65,22 +65,21 @@ extern int arlan_command(struct net_device * dev, int command);
#define registrationModeUNKNOWN -1
-#define IFDEBUG( L ) if ( (L) & arlan_debug )
-#define ARLAN_FAKE_HDR_LEN 12
+#define IFDEBUG(L) if ((L) & arlan_debug)
+#define ARLAN_FAKE_HDR_LEN 12
#ifdef ARLAN_DEBUGGING
#define DEBUG 1
#define ARLAN_ENTRY_EXIT_DEBUGGING 1
- #define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b)
+ #define ARLAN_DEBUG(a, b) printk(KERN_DEBUG a, b)
#else
- #define ARLAN_DEBUG(a,b)
+ #define ARLAN_DEBUG(a, b)
#endif
#define ARLAN_SHMEM_SIZE 0x2000
-struct arlan_shmem
-{
- /* Header Signature */
+struct arlan_shmem {
+ /* Header Signature */
volatile char textRegion[48];
volatile u_char resetFlag;
volatile u_char diagnosticInfo;
@@ -91,10 +90,10 @@ struct arlan_shmem
volatile u_char hardwareType;
volatile u_char majorHardwareVersion;
volatile u_char minorHardwareVersion;
- volatile u_char radioModule;// shows EEPROM, can be overridden at 0x111
- volatile u_char defaultChannelSet; // shows EEProm, can be overriiden at 0x10A
+ volatile u_char radioModule;/* shows EEPROM, can be overridden at 0x111 */
+ volatile u_char defaultChannelSet; /* shows EEProm, can be overriiden at 0x10A */
volatile u_char _2[47];
-
+
/* Control/Status Block - 0x0080 */
volatile u_char interruptInProgress; /* not used by lancpu */
volatile u_char cntrlRegImage; /* not used by lancpu */
@@ -113,7 +112,7 @@ struct arlan_shmem
volatile u_char rxQuality;
volatile u_char scrambled;
volatile u_char _4[1];
-
+
/* Transmit Status - 0x00b0 */
volatile u_char txStatus;
volatile u_char txAckQuality;
@@ -151,7 +150,7 @@ struct arlan_shmem
volatile u_short routerId;
volatile u_char _10[9];
volatile u_char txAttenuation;
- volatile u_char systemId[4];
+ volatile u_char systemId[4];
volatile u_short globalChecksum;
volatile u_char _11[4];
volatile u_short maxDatagramSize;
@@ -207,19 +206,19 @@ struct arlan_shmem
volatile u_char hostcpuLock;
volatile u_char lancpuLock;
volatile u_char resetTime[18];
-
+
volatile u_char numDatagramsTransmitted[4];
volatile u_char numReTransmissions[4];
volatile u_char numFramesDiscarded[4];
volatile u_char numDatagramsReceived[4];
volatile u_char numDuplicateReceivedFrames[4];
volatile u_char numDatagramsDiscarded[4];
-
+
volatile u_short maxNumReTransmitDatagram;
volatile u_short maxNumReTransmitFrames;
volatile u_short maxNumConsecutiveDuplicateFrames;
/* misaligned here so we have to go to characters */
-
+
volatile u_char numBytesTransmitted[4];
volatile u_char numBytesReceived[4];
volatile u_char numCRCErrors[4];
@@ -259,7 +258,7 @@ struct arlan_conf_stru {
int channelNumber;
int scramblingDisable;
int txAttenuation;
- int systemId;
+ int systemId;
int maxDatagramSize;
int maxFrameSize;
int maxRetries;
@@ -316,8 +315,7 @@ struct arlan_conf_stru {
extern struct arlan_conf_stru arlan_conf[MAX_ARLANS];
-struct TxParam
-{
+struct TxParam {
volatile short offset;
volatile short length;
volatile u_char dest[6];
@@ -330,12 +328,12 @@ struct TxParam
#define TX_RING_SIZE 2
/* Information that need to be kept for each board. */
struct arlan_private {
- struct arlan_shmem __iomem * card;
- struct arlan_shmem * conf;
+ struct arlan_shmem __iomem *card;
+ struct arlan_shmem *conf;
- struct arlan_conf_stru * Conf;
+ struct arlan_conf_stru *Conf;
int bad;
- int reset;
+ int reset;
unsigned long lastReset;
struct timer_list timer;
struct timer_list tx_delay_timer;
@@ -407,38 +405,38 @@ struct arlan_private {
#define TXBuffStart(dev) offsetof(struct arlan_shmem, txBuffer)
#define TXBuffEnd(dev) offsetof(struct arlan_shmem, xxBuffer)
-
-#define READSHM(to,from,atype) {\
+
+#define READSHM(to, from, atype) {\
atype tmp;\
- memcpy_fromio(&(tmp),&(from),sizeof(atype));\
+ memcpy_fromio(&(tmp), &(from), sizeof(atype));\
to = tmp;\
}
-#define READSHMEM(from,atype)\
+#define READSHMEM(from, atype)\
atype from; \
READSHM(from, arlan->from, atype);
-#define WRITESHM(to,from,atype) \
+#define WRITESHM(to, from, atype) \
{ atype tmpSHM = from;\
- memcpy_toio(&(to),&tmpSHM,sizeof(atype));\
+ memcpy_toio(&(to), &tmpSHM, sizeof(atype));\
}
-#define DEBUGSHM(levelSHM,stringSHM,stuff,atype) \
+#define DEBUGSHM(levelSHM, stringSHM, stuff, atype) \
{ atype tmpSHM; \
- memcpy_fromio(&tmpSHM,&(stuff),sizeof(atype));\
- IFDEBUG(levelSHM) printk(stringSHM,tmpSHM);\
+ memcpy_fromio(&tmpSHM, &(stuff), sizeof(atype));\
+ IFDEBUG(levelSHM) printk(stringSHM, tmpSHM);\
}
#define WRITESHMB(to, val) \
- writeb(val,&(to))
+ writeb(val, &(to))
#define READSHMB(to) \
readb(&(to))
#define WRITESHMS(to, val) \
- writew(val,&(to))
+ writew(val, &(to))
#define READSHMS(to) \
readw(&(to))
#define WRITESHMI(to, val) \
- writel(val,&(to))
+ writel(val, &(to))
#define READSHMI(to) \
readl(&(to))
@@ -447,51 +445,51 @@ struct arlan_private {
#define registrationBad(dev)\
- ( ( READSHMB(((struct arlan_private *)netdev_priv(dev))->card->registrationMode) > 0) && \
- ( READSHMB(((struct arlan_private *)netdev_priv(dev))->card->registrationStatus) == 0) )
+ (( READSHMB(((struct arlan_private *)netdev_priv(dev))->card->registrationMode) > 0) && \
+ ( READSHMB(((struct arlan_private *)netdev_priv(dev))->card->registrationStatus) == 0))
#define readControlRegister(dev)\
- READSHMB(((struct arlan_private *)netdev_priv(dev))->card->cntrlRegImage)
+ READSHMB(((struct arlan_private *)netdev_priv(dev))->card->cntrlRegImage)
-#define writeControlRegister(dev, v){\
- WRITESHMB(((struct arlan_private *)netdev_priv(dev))->card->cntrlRegImage ,((v) &0xF) );\
- WRITESHMB(((struct arlan_private *)netdev_priv(dev))->card->controlRegister ,(v) );}
+#define writeControlRegister(dev, v) {\
+ WRITESHMB(((struct arlan_private *)netdev_priv(dev))->card->cntrlRegImage, ((v) & 0xF));\
+ WRITESHMB(((struct arlan_private *)netdev_priv(dev))->card->controlRegister, (v)); }
#define arlan_interrupt_lancpu(dev) {\
int cr; \
\
cr = readControlRegister(dev);\
- if (cr & ARLAN_CHANNEL_ATTENTION){ \
+ if (cr & ARLAN_CHANNEL_ATTENTION) { \
writeControlRegister(dev, (cr & ~ARLAN_CHANNEL_ATTENTION));\
- }else \
+ } else \
writeControlRegister(dev, (cr | ARLAN_CHANNEL_ATTENTION));\
}
-#define clearChannelAttention(dev){ \
- writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CHANNEL_ATTENTION);}
+#define clearChannelAttention(dev) { \
+ writeControlRegister(dev, readControlRegister(dev) & ~ARLAN_CHANNEL_ATTENTION); }
#define setHardwareReset(dev) {\
- writeControlRegister(dev,readControlRegister(dev) | ARLAN_RESET);}
+ writeControlRegister(dev, readControlRegister(dev) | ARLAN_RESET); }
#define clearHardwareReset(dev) {\
- writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_RESET);}
-#define setInterruptEnable(dev){\
- writeControlRegister(dev,readControlRegister(dev) | ARLAN_INTERRUPT_ENABLE) ;}
-#define clearInterruptEnable(dev){\
- writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_INTERRUPT_ENABLE) ;}
-#define setClearInterrupt(dev){\
- writeControlRegister(dev,readControlRegister(dev) | ARLAN_CLEAR_INTERRUPT) ;}
-#define clearClearInterrupt(dev){\
- writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CLEAR_INTERRUPT);}
-#define setPowerOff(dev){\
- writeControlRegister(dev,readControlRegister(dev) | (ARLAN_POWER && ARLAN_ACCESS));\
- writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);}
-#define setPowerOn(dev){\
- writeControlRegister(dev,readControlRegister(dev) & ~(ARLAN_POWER)); }
-#define arlan_lock_card_access(dev){\
- writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);}
-#define arlan_unlock_card_access(dev){\
- writeControlRegister(dev,readControlRegister(dev) | ARLAN_ACCESS ); }
+ writeControlRegister(dev, readControlRegister(dev) & ~ARLAN_RESET); }
+#define setInterruptEnable(dev) {\
+ writeControlRegister(dev, readControlRegister(dev) | ARLAN_INTERRUPT_ENABLE) ; }
+#define clearInterruptEnable(dev) {\
+ writeControlRegister(dev, readControlRegister(dev) & ~ARLAN_INTERRUPT_ENABLE) ; }
+#define setClearInterrupt(dev) {\
+ writeControlRegister(dev, readControlRegister(dev) | ARLAN_CLEAR_INTERRUPT) ; }
+#define clearClearInterrupt(dev) {\
+ writeControlRegister(dev, readControlRegister(dev) & ~ARLAN_CLEAR_INTERRUPT); }
+#define setPowerOff(dev) {\
+ writeControlRegister(dev, readControlRegister(dev) | (ARLAN_POWER && ARLAN_ACCESS));\
+ writeControlRegister(dev, readControlRegister(dev) & ~ARLAN_ACCESS); }
+#define setPowerOn(dev) {\
+ writeControlRegister(dev, readControlRegister(dev) & ~(ARLAN_POWER)); }
+#define arlan_lock_card_access(dev) {\
+ writeControlRegister(dev, readControlRegister(dev) & ~ARLAN_ACCESS); }
+#define arlan_unlock_card_access(dev) {\
+ writeControlRegister(dev, readControlRegister(dev) | ARLAN_ACCESS); }
@@ -525,7 +523,6 @@ struct arlan_private {
| ARLAN_COMMAND_RESET)
-
#define ARLAN_DEBUG_CHAIN_LOCKS 0x00001
#define ARLAN_DEBUG_RESET 0x00002
#define ARLAN_DEBUG_TIMING 0x00004
@@ -536,4 +533,3 @@ struct arlan_private {
#define ARLAN_DEBUG_INTERRUPT 0x00080
#define ARLAN_DEBUG_STARTUP 0x00100
#define ARLAN_DEBUG_SHUTDOWN 0x00200
-
diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c
index f4c26572c7df..7ebecc92c61b 100644
--- a/drivers/staging/asus_oled/asus_oled.c
+++ b/drivers/staging/asus_oled/asus_oled.c
@@ -52,6 +52,10 @@
#define ASUS_OLED_DISP_HEIGHT 32
#define ASUS_OLED_PACKET_BUF_SIZE 256
+#define USB_VENDOR_ID_ASUS 0x0b05
+#define USB_DEVICE_ID_ASUS_LCM 0x1726
+#define USB_DEVICE_ID_ASUS_LCM2 0x175b
+
MODULE_AUTHOR("Jakub Schmidtke, sjakub@gmail.com");
MODULE_DESCRIPTION("Asus OLED Driver v" ASUS_OLED_VERSION);
MODULE_LICENSE("GPL");
@@ -83,18 +87,20 @@ struct oled_dev_desc_str {
};
/* table of devices that work with this driver */
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
/* Asus G1/G2 (and variants)*/
- { USB_DEVICE(0x0b05, 0x1726) },
+ { USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM) },
/* Asus G50V (and possibly others - G70? G71?)*/
- { USB_DEVICE(0x0b05, 0x175b) },
+ { USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2) },
{ },
};
/* parameters of specific devices */
static struct oled_dev_desc_str oled_dev_desc_table[] = {
- { 0x0b05, 0x1726, 128, PACK_MODE_G1, "G1/G2" },
- { 0x0b05, 0x175b, 256, PACK_MODE_G50, "G50" },
+ { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, 128, PACK_MODE_G1,
+ "G1/G2" },
+ { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2, 256, PACK_MODE_G50,
+ "G50" },
{ },
};
@@ -194,9 +200,11 @@ static ssize_t set_enabled(struct device *dev, struct device_attribute *attr,
{
struct usb_interface *intf = to_usb_interface(dev);
struct asus_oled_dev *odev = usb_get_intfdata(intf);
- int temp = strict_strtoul(buf, 10, NULL);
+ unsigned long value;
+ if (strict_strtoul(buf, 10, &value))
+ return -EINVAL;
- enable_oled(odev, temp);
+ enable_oled(odev, value);
return count;
}
@@ -207,10 +215,12 @@ static ssize_t class_set_enabled(struct device *device,
{
struct asus_oled_dev *odev =
(struct asus_oled_dev *) dev_get_drvdata(device);
+ unsigned long value;
- int temp = strict_strtoul(buf, 10, NULL);
+ if (strict_strtoul(buf, 10, &value))
+ return -EINVAL;
- enable_oled(odev, temp);
+ enable_oled(odev, value);
return count;
}
@@ -420,6 +430,11 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev,
kfree(odev->buf);
odev->buf = kmalloc(odev->buf_size, GFP_KERNEL);
+ if (odev->buf == NULL) {
+ odev->buf_size = 0;
+ printk(ASUS_OLED_ERROR "Out of memory!\n");
+ return -ENOMEM;
+ }
memset(odev->buf, 0xff, odev->buf_size);
@@ -755,13 +770,8 @@ static struct usb_driver oled_driver = {
.id_table = id_table,
};
-static ssize_t version_show(struct class *dev, char *buf)
-{
- return sprintf(buf, ASUS_OLED_UNDERSCORE_NAME " %s\n",
- ASUS_OLED_VERSION);
-}
-
-static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
+static CLASS_ATTR_STRING(version, S_IRUGO,
+ ASUS_OLED_UNDERSCORE_NAME " " ASUS_OLED_VERSION);
static int __init asus_oled_init(void)
{
@@ -773,7 +783,7 @@ static int __init asus_oled_init(void)
return PTR_ERR(oled_class);
}
- retval = class_create_file(oled_class, &class_attr_version);
+ retval = class_create_file(oled_class, &class_attr_version.attr);
if (retval) {
err("Error creating class version file");
goto error;
@@ -795,7 +805,7 @@ error:
static void __exit asus_oled_exit(void)
{
- class_remove_file(oled_class, &class_attr_version);
+ class_remove_file(oled_class, &class_attr_version.attr);
class_destroy(oled_class);
usb_deregister(&oled_driver);
diff --git a/drivers/staging/b3dfg/Kconfig b/drivers/staging/b3dfg/Kconfig
deleted file mode 100644
index 9e6573cf97d3..000000000000
--- a/drivers/staging/b3dfg/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-config B3DFG
- tristate "Brontes 3d Frame Framegrabber"
- depends on PCI
- default n
- ---help---
- This driver provides support for the Brontes 3d Framegrabber
- PCI card.
-
- To compile this driver as a module, choose M here. The module
- will be called b3dfg.
diff --git a/drivers/staging/b3dfg/Makefile b/drivers/staging/b3dfg/Makefile
deleted file mode 100644
index 91f439ffc174..000000000000
--- a/drivers/staging/b3dfg/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_B3DFG) += b3dfg.o
diff --git a/drivers/staging/b3dfg/TODO b/drivers/staging/b3dfg/TODO
deleted file mode 100644
index f5a9298b9ac1..000000000000
--- a/drivers/staging/b3dfg/TODO
+++ /dev/null
@@ -1,4 +0,0 @@
-
- - queue/wait buffer presents filltime results for each frame?
- - counting of dropped frames
- - review endianness
diff --git a/drivers/staging/b3dfg/b3dfg.c b/drivers/staging/b3dfg/b3dfg.c
deleted file mode 100644
index 4a43c51c172a..000000000000
--- a/drivers/staging/b3dfg/b3dfg.c
+++ /dev/null
@@ -1,1100 +0,0 @@
- /*
- * Brontes PCI frame grabber driver
- *
- * Copyright (C) 2008 3M Company
- * Contact: Justin Bronder <jsbronder@brontes3d.com>
- * Original Authors: Daniel Drake <ddrake@brontes3d.com>
- * Duane Griffin <duaneg@dghda.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/ioctl.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/types.h>
-#include <linux/cdev.h>
-#include <linux/list.h>
-#include <linux/poll.h>
-#include <linux/wait.h>
-#include <linux/mm.h>
-#include <linux/uaccess.h>
-#include <linux/sched.h>
-
-static unsigned int b3dfg_nbuf = 2;
-
-module_param_named(buffer_count, b3dfg_nbuf, uint, 0444);
-
-MODULE_PARM_DESC(buffer_count, "Number of buffers (min 2, default 2)");
-
-MODULE_AUTHOR("Daniel Drake <ddrake@brontes3d.com>");
-MODULE_DESCRIPTION("Brontes frame grabber driver");
-MODULE_LICENSE("GPL");
-
-#define DRIVER_NAME "b3dfg"
-#define B3DFG_MAX_DEVS 4
-#define B3DFG_FRAMES_PER_BUFFER 3
-
-#define B3DFG_BAR_REGS 0
-#define B3DFG_REGS_LENGTH 0x10000
-
-#define B3DFG_IOC_MAGIC 0xb3 /* dfg :-) */
-#define B3DFG_IOCGFRMSZ _IOR(B3DFG_IOC_MAGIC, 1, int)
-#define B3DFG_IOCTNUMBUFS _IO(B3DFG_IOC_MAGIC, 2)
-#define B3DFG_IOCTTRANS _IO(B3DFG_IOC_MAGIC, 3)
-#define B3DFG_IOCTQUEUEBUF _IO(B3DFG_IOC_MAGIC, 4)
-#define B3DFG_IOCTPOLLBUF _IOWR(B3DFG_IOC_MAGIC, 5, struct b3dfg_poll)
-#define B3DFG_IOCTWAITBUF _IOWR(B3DFG_IOC_MAGIC, 6, struct b3dfg_wait)
-#define B3DFG_IOCGWANDSTAT _IOR(B3DFG_IOC_MAGIC, 7, int)
-
-enum {
- /* number of 4kb pages per frame */
- B3D_REG_FRM_SIZE = 0x0,
-
- /* bit 0: set to enable interrupts
- * bit 1: set to enable cable status change interrupts */
- B3D_REG_HW_CTRL = 0x4,
-
- /* bit 0-1 - 1-based ID of next pending frame transfer (0 = none)
- * bit 2 indicates the previous DMA transfer has completed
- * bit 3 indicates wand cable status change
- * bit 8:15 - counter of number of discarded triplets */
- B3D_REG_DMA_STS = 0x8,
-
- /* bit 0: wand status (1 = present, 0 = disconnected) */
- B3D_REG_WAND_STS = 0xc,
-
- /* bus address for DMA transfers. lower 2 bits must be zero because DMA
- * works with 32 bit word size. */
- B3D_REG_EC220_DMA_ADDR = 0x8000,
-
- /* bit 20:0 - number of 32 bit words to be transferred
- * bit 21:31 - reserved */
- B3D_REG_EC220_TRF_SIZE = 0x8004,
-
- /* bit 0 - error bit
- * bit 1 - interrupt bit (set to generate interrupt at end of transfer)
- * bit 2 - start bit (set to start transfer)
- * bit 3 - direction (0 = DMA_TO_DEVICE, 1 = DMA_FROM_DEVICE
- * bit 4:31 - reserved */
- B3D_REG_EC220_DMA_STS = 0x8008,
-};
-
-enum b3dfg_buffer_state {
- B3DFG_BUFFER_POLLED = 0,
- B3DFG_BUFFER_PENDING,
- B3DFG_BUFFER_POPULATED,
-};
-
-struct b3dfg_buffer {
- unsigned char *frame[B3DFG_FRAMES_PER_BUFFER];
- struct list_head list;
- u8 state;
-};
-
-struct b3dfg_dev {
-
- /* no protection needed: all finalized at initialization time */
- struct pci_dev *pdev;
- struct cdev chardev;
- struct device *dev;
- void __iomem *regs;
- unsigned int frame_size;
-
- /*
- * Protects buffer state, including buffer_queue, triplet_ready,
- * cur_dma_frame_idx & cur_dma_frame_addr.
- */
- spinlock_t buffer_lock;
- struct b3dfg_buffer *buffers;
- struct list_head buffer_queue;
-
- /* Last frame in triplet transferred (-1 if none). */
- int cur_dma_frame_idx;
-
- /* Current frame's address for DMA. */
- dma_addr_t cur_dma_frame_addr;
-
- /*
- * Protects cstate_tstamp.
- * Nests inside buffer_lock.
- */
- spinlock_t cstate_lock;
- unsigned long cstate_tstamp;
-
- /*
- * Protects triplets_dropped.
- * Nests inside buffers_lock.
- */
- spinlock_t triplets_dropped_lock;
- unsigned int triplets_dropped;
-
- wait_queue_head_t buffer_waitqueue;
-
- unsigned int transmission_enabled:1;
- unsigned int triplet_ready:1;
-};
-
-static u8 b3dfg_devices[B3DFG_MAX_DEVS];
-
-static struct class *b3dfg_class;
-static dev_t b3dfg_devt;
-
-static const struct pci_device_id b3dfg_ids[] __devinitdata = {
- { PCI_DEVICE(0x0b3d, 0x0001) },
- { },
-};
-
-MODULE_DEVICE_TABLE(pci, b3dfg_ids);
-
-/***** user-visible types *****/
-
-struct b3dfg_poll {
- int buffer_idx;
- unsigned int triplets_dropped;
-};
-
-struct b3dfg_wait {
- int buffer_idx;
- unsigned int timeout;
- unsigned int triplets_dropped;
-};
-
-/**** register I/O ****/
-
-static u32 b3dfg_read32(struct b3dfg_dev *fgdev, u16 reg)
-{
- return ioread32(fgdev->regs + reg);
-}
-
-static void b3dfg_write32(struct b3dfg_dev *fgdev, u16 reg, u32 value)
-{
- iowrite32(value, fgdev->regs + reg);
-}
-
-/**** buffer management ****/
-
-/*
- * Program EC220 for transfer of a specific frame.
- * Called with buffer_lock held.
- */
-static int setup_frame_transfer(struct b3dfg_dev *fgdev,
- struct b3dfg_buffer *buf, int frame)
-{
- unsigned char *frm_addr;
- dma_addr_t frm_addr_dma;
- unsigned int frm_size = fgdev->frame_size;
-
- frm_addr = buf->frame[frame];
- frm_addr_dma = pci_map_single(fgdev->pdev, frm_addr,
- frm_size, PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(fgdev->pdev, frm_addr_dma))
- return -ENOMEM;
-
- fgdev->cur_dma_frame_addr = frm_addr_dma;
- fgdev->cur_dma_frame_idx = frame;
-
- b3dfg_write32(fgdev, B3D_REG_EC220_DMA_ADDR,
- cpu_to_le32(frm_addr_dma));
- b3dfg_write32(fgdev, B3D_REG_EC220_TRF_SIZE,
- cpu_to_le32(frm_size >> 2));
- b3dfg_write32(fgdev, B3D_REG_EC220_DMA_STS, 0xf);
-
- return 0;
-}
-
-/* Caller should hold buffer lock */
-static void dequeue_all_buffers(struct b3dfg_dev *fgdev)
-{
- int i;
- for (i = 0; i < b3dfg_nbuf; i++) {
- struct b3dfg_buffer *buf = &fgdev->buffers[i];
- buf->state = B3DFG_BUFFER_POLLED;
- list_del_init(&buf->list);
- }
-}
-
-/* queue a buffer to receive data */
-static int queue_buffer(struct b3dfg_dev *fgdev, int bufidx)
-{
- struct device *dev = &fgdev->pdev->dev;
- struct b3dfg_buffer *buf;
- unsigned long flags;
- int r = 0;
-
- spin_lock_irqsave(&fgdev->buffer_lock, flags);
- if (bufidx < 0 || bufidx >= b3dfg_nbuf) {
- dev_dbg(dev, "Invalid buffer index, %d\n", bufidx);
- r = -ENOENT;
- goto out;
- }
- buf = &fgdev->buffers[bufidx];
-
- if (unlikely(buf->state == B3DFG_BUFFER_PENDING)) {
- dev_dbg(dev, "buffer %d is already queued\n", bufidx);
- r = -EINVAL;
- goto out;
- }
-
- buf->state = B3DFG_BUFFER_PENDING;
- list_add_tail(&buf->list, &fgdev->buffer_queue);
-
- if (fgdev->transmission_enabled && fgdev->triplet_ready) {
- dev_dbg(dev, "triplet is ready, pushing immediately\n");
- fgdev->triplet_ready = 0;
- r = setup_frame_transfer(fgdev, buf, 0);
- if (r)
- dev_err(dev, "unable to map DMA buffer\n");
- }
-
-out:
- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
- return r;
-}
-
-/* non-blocking buffer poll. returns 1 if data is present in the buffer,
- * 0 otherwise */
-static int poll_buffer(struct b3dfg_dev *fgdev, void __user *arg)
-{
- struct device *dev = &fgdev->pdev->dev;
- struct b3dfg_poll p;
- struct b3dfg_buffer *buf;
- unsigned long flags;
- int r = 1;
- int arg_out = 0;
-
- if (copy_from_user(&p, arg, sizeof(p)))
- return -EFAULT;
-
- if (unlikely(!fgdev->transmission_enabled)) {
- dev_dbg(dev, "cannot poll, transmission disabled\n");
- return -EINVAL;
- }
-
- if (p.buffer_idx < 0 || p.buffer_idx >= b3dfg_nbuf)
- return -ENOENT;
-
- buf = &fgdev->buffers[p.buffer_idx];
-
- spin_lock_irqsave(&fgdev->buffer_lock, flags);
-
- if (likely(buf->state == B3DFG_BUFFER_POPULATED)) {
- arg_out = 1;
- buf->state = B3DFG_BUFFER_POLLED;
-
- /* IRQs already disabled by spin_lock_irqsave above. */
- spin_lock(&fgdev->triplets_dropped_lock);
- p.triplets_dropped = fgdev->triplets_dropped;
- fgdev->triplets_dropped = 0;
- spin_unlock(&fgdev->triplets_dropped_lock);
- } else {
- r = 0;
- }
-
- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
-
- if (arg_out && copy_to_user(arg, &p, sizeof(p)))
- r = -EFAULT;
-
- return r;
-}
-
-static unsigned long get_cstate_change(struct b3dfg_dev *fgdev)
-{
- unsigned long flags, when;
-
- spin_lock_irqsave(&fgdev->cstate_lock, flags);
- when = fgdev->cstate_tstamp;
- spin_unlock_irqrestore(&fgdev->cstate_lock, flags);
- return when;
-}
-
-static int is_event_ready(struct b3dfg_dev *fgdev, struct b3dfg_buffer *buf,
- unsigned long when)
-{
- int result;
- unsigned long flags;
-
- spin_lock_irqsave(&fgdev->buffer_lock, flags);
- spin_lock(&fgdev->cstate_lock);
- result = (!fgdev->transmission_enabled ||
- buf->state == B3DFG_BUFFER_POPULATED ||
- when != fgdev->cstate_tstamp);
- spin_unlock(&fgdev->cstate_lock);
- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
-
- return result;
-}
-
-/* sleep until a specific buffer becomes populated */
-static int wait_buffer(struct b3dfg_dev *fgdev, void __user *arg)
-{
- struct device *dev = &fgdev->pdev->dev;
- struct b3dfg_wait w;
- struct b3dfg_buffer *buf;
- unsigned long flags, when;
- int r;
-
- if (copy_from_user(&w, arg, sizeof(w)))
- return -EFAULT;
-
- if (!fgdev->transmission_enabled) {
- dev_dbg(dev, "cannot wait, transmission disabled\n");
- return -EINVAL;
- }
-
- if (w.buffer_idx < 0 || w.buffer_idx >= b3dfg_nbuf)
- return -ENOENT;
-
- buf = &fgdev->buffers[w.buffer_idx];
-
- spin_lock_irqsave(&fgdev->buffer_lock, flags);
-
- if (buf->state == B3DFG_BUFFER_POPULATED) {
- r = w.timeout;
- goto out_triplets_dropped;
- }
-
- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
-
- when = get_cstate_change(fgdev);
- if (w.timeout > 0) {
- r = wait_event_interruptible_timeout(fgdev->buffer_waitqueue,
- is_event_ready(fgdev, buf, when),
- (w.timeout * HZ) / 1000);
-
- if (unlikely(r < 0))
- goto out;
-
- w.timeout = r * 1000 / HZ;
- } else {
- r = wait_event_interruptible(fgdev->buffer_waitqueue,
- is_event_ready(fgdev, buf, when));
-
- if (unlikely(r)) {
- r = -ERESTARTSYS;
- goto out;
- }
- }
-
- /* TODO: Inform the user via field(s) in w? */
- if (!fgdev->transmission_enabled || when != get_cstate_change(fgdev)) {
- r = -EINVAL;
- goto out;
- }
-
- spin_lock_irqsave(&fgdev->buffer_lock, flags);
-
- if (buf->state != B3DFG_BUFFER_POPULATED) {
- r = -ETIMEDOUT;
- goto out_unlock;
- }
-
- buf->state = B3DFG_BUFFER_POLLED;
-
-out_triplets_dropped:
-
- /* IRQs already disabled by spin_lock_irqsave above. */
- spin_lock(&fgdev->triplets_dropped_lock);
- w.triplets_dropped = fgdev->triplets_dropped;
- fgdev->triplets_dropped = 0;
- spin_unlock(&fgdev->triplets_dropped_lock);
-
-out_unlock:
- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
- if (copy_to_user(arg, &w, sizeof(w)))
- r = -EFAULT;
-out:
- return r;
-}
-
-/* mmap page fault handler */
-static int b3dfg_vma_fault(struct vm_area_struct *vma,
- struct vm_fault *vmf)
-{
- struct b3dfg_dev *fgdev = vma->vm_file->private_data;
- unsigned long off = vmf->pgoff << PAGE_SHIFT;
- unsigned int frame_size = fgdev->frame_size;
- unsigned int buf_size = frame_size * B3DFG_FRAMES_PER_BUFFER;
- unsigned char *addr;
-
- /* determine which buffer the offset lies within */
- unsigned int buf_idx = off / buf_size;
- /* and the offset into the buffer */
- unsigned int buf_off = off % buf_size;
-
- /* determine which frame inside the buffer the offset lies in */
- unsigned int frm_idx = buf_off / frame_size;
- /* and the offset into the frame */
- unsigned int frm_off = buf_off % frame_size;
-
- if (unlikely(buf_idx >= b3dfg_nbuf))
- return VM_FAULT_SIGBUS;
-
- addr = fgdev->buffers[buf_idx].frame[frm_idx] + frm_off;
- vm_insert_pfn(vma, (unsigned long)vmf->virtual_address,
- virt_to_phys(addr) >> PAGE_SHIFT);
-
- return VM_FAULT_NOPAGE;
-}
-
-static struct vm_operations_struct b3dfg_vm_ops = {
- .fault = b3dfg_vma_fault,
-};
-
-static int get_wand_status(struct b3dfg_dev *fgdev, int __user *arg)
-{
- u32 wndstat = b3dfg_read32(fgdev, B3D_REG_WAND_STS);
- dev_dbg(&fgdev->pdev->dev, "wand status %x\n", wndstat);
- return __put_user(wndstat & 0x1, arg);
-}
-
-static int enable_transmission(struct b3dfg_dev *fgdev)
-{
- unsigned long flags;
- struct device *dev = &fgdev->pdev->dev;
-
- dev_dbg(dev, "enable transmission\n");
-
- /* check the cable is plugged in. */
- if (!b3dfg_read32(fgdev, B3D_REG_WAND_STS)) {
- dev_dbg(dev, "cannot start transmission without wand\n");
- return -EINVAL;
- }
-
- spin_lock_irqsave(&fgdev->buffer_lock, flags);
-
- /* Handle racing enable_transmission calls. */
- if (fgdev->transmission_enabled) {
- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
- goto out;
- }
-
- spin_lock(&fgdev->triplets_dropped_lock);
- fgdev->triplets_dropped = 0;
- spin_unlock(&fgdev->triplets_dropped_lock);
-
- fgdev->triplet_ready = 0;
- fgdev->cur_dma_frame_idx = -1;
- fgdev->transmission_enabled = 1;
-
- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
-
- /* Enable DMA and cable status interrupts. */
- b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0x03);
-
-out:
- return 0;
-}
-
-static void disable_transmission(struct b3dfg_dev *fgdev)
-{
- struct device *dev = &fgdev->pdev->dev;
- unsigned long flags;
- u32 tmp;
-
- dev_dbg(dev, "disable transmission\n");
-
- /* guarantee that no more interrupts will be serviced */
- spin_lock_irqsave(&fgdev->buffer_lock, flags);
- fgdev->transmission_enabled = 0;
-
- b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0);
-
- /* FIXME: temporary debugging only. if the board stops transmitting,
- * hitting ctrl+c and seeing this message is useful for determining
- * the state of the board. */
- tmp = b3dfg_read32(fgdev, B3D_REG_DMA_STS);
- dev_dbg(dev, "DMA_STS reads %x after TX stopped\n", tmp);
-
- dequeue_all_buffers(fgdev);
- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
-
- wake_up_interruptible(&fgdev->buffer_waitqueue);
-}
-
-static int set_transmission(struct b3dfg_dev *fgdev, int enabled)
-{
- int res = 0;
-
- if (enabled && !fgdev->transmission_enabled)
- res = enable_transmission(fgdev);
- else if (!enabled && fgdev->transmission_enabled)
- disable_transmission(fgdev);
-
- return res;
-}
-
-/* Called in interrupt context. */
-static void handle_cstate_unplug(struct b3dfg_dev *fgdev)
-{
- /* Disable all interrupts. */
- b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0);
-
- /* Stop transmission. */
- spin_lock(&fgdev->buffer_lock);
- fgdev->transmission_enabled = 0;
-
- fgdev->cur_dma_frame_idx = -1;
- fgdev->triplet_ready = 0;
- if (fgdev->cur_dma_frame_addr) {
- pci_unmap_single(fgdev->pdev, fgdev->cur_dma_frame_addr,
- fgdev->frame_size, PCI_DMA_FROMDEVICE);
- fgdev->cur_dma_frame_addr = 0;
- }
- dequeue_all_buffers(fgdev);
- spin_unlock(&fgdev->buffer_lock);
-}
-
-/* Called in interrupt context. */
-static void handle_cstate_change(struct b3dfg_dev *fgdev)
-{
- u32 cstate = b3dfg_read32(fgdev, B3D_REG_WAND_STS);
- unsigned long when;
- struct device *dev = &fgdev->pdev->dev;
-
- dev_dbg(dev, "cable state change: %u\n", cstate);
-
- /*
- * When the wand is unplugged we reset our state. The hardware will
- * have done the same internally.
- *
- * Note we should never see a cable *plugged* event, as interrupts
- * should only be enabled when transmitting, which requires the cable
- * to be plugged. If we do see one it probably means the cable has been
- * unplugged and re-plugged very rapidly. Possibly because it has a
- * broken wire and is momentarily losing contact.
- *
- * TODO: At the moment if you plug in the cable then enable transmission
- * the hardware will raise a couple of spurious interrupts, so
- * just ignore them for now.
- *
- * Once the hardware is fixed we should complain and treat it as an
- * unplug. Or at least track how frequently it is happening and do
- * so if too many come in.
- */
- if (cstate) {
- dev_warn(dev, "ignoring unexpected plug event\n");
- return;
- }
- handle_cstate_unplug(fgdev);
-
- /*
- * Record cable state change timestamp & wake anyone waiting
- * on a cable state change. Be paranoid about ensuring events
- * are not missed if we somehow get two interrupts in a jiffy.
- */
- spin_lock(&fgdev->cstate_lock);
- when = jiffies_64;
- if (when <= fgdev->cstate_tstamp)
- when = fgdev->cstate_tstamp + 1;
- fgdev->cstate_tstamp = when;
- wake_up_interruptible(&fgdev->buffer_waitqueue);
- spin_unlock(&fgdev->cstate_lock);
-}
-
-/* Called with buffer_lock held. */
-static void transfer_complete(struct b3dfg_dev *fgdev)
-{
- struct b3dfg_buffer *buf;
- struct device *dev = &fgdev->pdev->dev;
-
- pci_unmap_single(fgdev->pdev, fgdev->cur_dma_frame_addr,
- fgdev->frame_size, PCI_DMA_FROMDEVICE);
- fgdev->cur_dma_frame_addr = 0;
-
- buf = list_entry(fgdev->buffer_queue.next, struct b3dfg_buffer, list);
-
- dev_dbg(dev, "handle frame completion\n");
- if (fgdev->cur_dma_frame_idx == B3DFG_FRAMES_PER_BUFFER - 1) {
-
- /* last frame of that triplet completed */
- dev_dbg(dev, "triplet completed\n");
- buf->state = B3DFG_BUFFER_POPULATED;
- list_del_init(&buf->list);
- wake_up_interruptible(&fgdev->buffer_waitqueue);
- }
-}
-
-/*
- * Called with buffer_lock held.
- *
- * Note that idx is the (1-based) *next* frame to be transferred, while
- * cur_dma_frame_idx is the (0-based) *last* frame to have been transferred (or
- * -1 if none). Thus there should be a difference of 2 between them.
- */
-static bool setup_next_frame_transfer(struct b3dfg_dev *fgdev, int idx)
-{
- struct b3dfg_buffer *buf;
- struct device *dev = &fgdev->pdev->dev;
- bool need_ack = 1;
-
- dev_dbg(dev, "program DMA transfer for next frame: %d\n", idx);
-
- buf = list_entry(fgdev->buffer_queue.next, struct b3dfg_buffer, list);
- if (idx == fgdev->cur_dma_frame_idx + 2) {
- if (setup_frame_transfer(fgdev, buf, idx - 1))
- dev_err(dev, "unable to map DMA buffer\n");
- need_ack = 0;
- } else {
- dev_err(dev, "frame mismatch, got %d, expected %d\n",
- idx, fgdev->cur_dma_frame_idx + 2);
-
- /* FIXME: handle dropped triplets here */
- }
-
- return need_ack;
-}
-
-static irqreturn_t b3dfg_intr(int irq, void *dev_id)
-{
- struct b3dfg_dev *fgdev = dev_id;
- struct device *dev = &fgdev->pdev->dev;
- u32 sts;
- u8 dropped;
- bool need_ack = 1;
- irqreturn_t res = IRQ_HANDLED;
-
- sts = b3dfg_read32(fgdev, B3D_REG_DMA_STS);
- if (unlikely(sts == 0)) {
- dev_warn(dev, "ignore interrupt, DMA status is 0\n");
- res = IRQ_NONE;
- goto out;
- }
-
- if (unlikely(!fgdev->transmission_enabled)) {
- dev_warn(dev, "ignore interrupt, TX disabled\n");
- res = IRQ_HANDLED;
- goto out;
- }
-
- /* Handle dropped frames, as reported by the hardware. */
- dropped = (sts >> 8) & 0xff;
- dev_dbg(dev, "intr: DMA_STS=%08x (drop=%d comp=%d next=%d)\n",
- sts, dropped, !!(sts & 0x4), sts & 0x3);
- if (unlikely(dropped > 0)) {
- spin_lock(&fgdev->triplets_dropped_lock);
- fgdev->triplets_dropped += dropped;
- spin_unlock(&fgdev->triplets_dropped_lock);
- }
-
- /* Handle a cable state change (i.e. the wand being unplugged). */
- if (sts & 0x08) {
- handle_cstate_change(fgdev);
- goto out;
- }
-
- spin_lock(&fgdev->buffer_lock);
- if (unlikely(list_empty(&fgdev->buffer_queue))) {
-
- /* FIXME need more sanity checking here */
- dev_info(dev, "buffer not ready for next transfer\n");
- fgdev->triplet_ready = 1;
- goto out_unlock;
- }
-
- /* Has a frame transfer been completed? */
- if (sts & 0x4) {
- u32 dma_status = b3dfg_read32(fgdev, B3D_REG_EC220_DMA_STS);
-
- /* Check for DMA errors reported by the hardware. */
- if (unlikely(dma_status & 0x1)) {
- dev_err(dev, "EC220 error: %08x\n", dma_status);
-
- /* FIXME flesh out error handling */
- goto out_unlock;
- }
-
- /* Sanity check, we should have a frame index at this point. */
- if (unlikely(fgdev->cur_dma_frame_idx == -1)) {
- dev_err(dev, "completed but no last idx?\n");
-
- /* FIXME flesh out error handling */
- goto out_unlock;
- }
-
- transfer_complete(fgdev);
- }
-
- /* Is there another frame transfer pending? */
- if (sts & 0x3)
- need_ack = setup_next_frame_transfer(fgdev, sts & 0x3);
- else
- fgdev->cur_dma_frame_idx = -1;
-
-out_unlock:
- spin_unlock(&fgdev->buffer_lock);
-out:
- if (need_ack) {
- dev_dbg(dev, "acknowledging interrupt\n");
- b3dfg_write32(fgdev, B3D_REG_EC220_DMA_STS, 0x0b);
- }
- return res;
-}
-
-static int b3dfg_open(struct inode *inode, struct file *filp)
-{
- struct b3dfg_dev *fgdev =
- container_of(inode->i_cdev, struct b3dfg_dev, chardev);
-
- dev_dbg(&fgdev->pdev->dev, "open\n");
- filp->private_data = fgdev;
- return 0;
-}
-
-static int b3dfg_release(struct inode *inode, struct file *filp)
-{
- struct b3dfg_dev *fgdev = filp->private_data;
- dev_dbg(&fgdev->pdev->dev, "release\n");
- disable_transmission(fgdev);
- return 0;
-}
-
-static long b3dfg_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- struct b3dfg_dev *fgdev = filp->private_data;
-
- switch (cmd) {
- case B3DFG_IOCGFRMSZ:
- return __put_user(fgdev->frame_size, (int __user *) arg);
- case B3DFG_IOCGWANDSTAT:
- return get_wand_status(fgdev, (int __user *) arg);
- case B3DFG_IOCTTRANS:
- return set_transmission(fgdev, (int) arg);
- case B3DFG_IOCTQUEUEBUF:
- return queue_buffer(fgdev, (int) arg);
- case B3DFG_IOCTPOLLBUF:
- return poll_buffer(fgdev, (void __user *) arg);
- case B3DFG_IOCTWAITBUF:
- return wait_buffer(fgdev, (void __user *) arg);
- default:
- dev_dbg(&fgdev->pdev->dev, "unrecognised ioctl %x\n", cmd);
- return -EINVAL;
- }
-}
-
-static unsigned int b3dfg_poll(struct file *filp, poll_table *poll_table)
-{
- struct b3dfg_dev *fgdev = filp->private_data;
- unsigned long flags, when;
- int i;
- int r = 0;
-
- when = get_cstate_change(fgdev);
- poll_wait(filp, &fgdev->buffer_waitqueue, poll_table);
-
- spin_lock_irqsave(&fgdev->buffer_lock, flags);
- for (i = 0; i < b3dfg_nbuf; i++) {
- if (fgdev->buffers[i].state == B3DFG_BUFFER_POPULATED) {
- r = POLLIN | POLLRDNORM;
- break;
- }
- }
- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
-
- /* TODO: Confirm this is how we want to communicate the change. */
- if (!fgdev->transmission_enabled || when != get_cstate_change(fgdev))
- r = POLLERR;
-
- return r;
-}
-
-static int b3dfg_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- struct b3dfg_dev *fgdev = filp->private_data;
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- unsigned long vsize = vma->vm_end - vma->vm_start;
- unsigned long bufdatalen = b3dfg_nbuf * fgdev->frame_size * 3;
- unsigned long psize = bufdatalen - offset;
- int r = 0;
-
- if (vsize <= psize) {
- vma->vm_flags |= VM_IO | VM_RESERVED | VM_CAN_NONLINEAR |
- VM_PFNMAP;
- vma->vm_ops = &b3dfg_vm_ops;
- } else {
- r = -EINVAL;
- }
-
- return r;
-}
-
-static struct file_operations b3dfg_fops = {
- .owner = THIS_MODULE,
- .open = b3dfg_open,
- .release = b3dfg_release,
- .unlocked_ioctl = b3dfg_ioctl,
- .poll = b3dfg_poll,
- .mmap = b3dfg_mmap,
-};
-
-static void free_all_frame_buffers(struct b3dfg_dev *fgdev)
-{
- int i, j;
- for (i = 0; i < b3dfg_nbuf; i++)
- for (j = 0; j < B3DFG_FRAMES_PER_BUFFER; j++)
- kfree(fgdev->buffers[i].frame[j]);
- kfree(fgdev->buffers);
-}
-
-/* initialize device and any data structures. called before any interrupts
- * are enabled. */
-static int b3dfg_init_dev(struct b3dfg_dev *fgdev)
-{
- int i, j;
- u32 frm_size = b3dfg_read32(fgdev, B3D_REG_FRM_SIZE);
-
- /* Disable interrupts. In abnormal circumstances (e.g. after a crash)
- * the board may still be transmitting from the previous session. If we
- * ensure that interrupts are disabled before we later enable them, we
- * are sure to capture a triplet from the start, rather than starting
- * from frame 2 or 3. Disabling interrupts causes the FG to throw away
- * all buffered data and stop buffering more until interrupts are
- * enabled again.
- */
- b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0);
-
- fgdev->frame_size = frm_size * 4096;
- fgdev->buffers = kzalloc(sizeof(struct b3dfg_buffer) * b3dfg_nbuf,
- GFP_KERNEL);
- if (!fgdev->buffers)
- goto err_no_buf;
- for (i = 0; i < b3dfg_nbuf; i++) {
- struct b3dfg_buffer *buf = &fgdev->buffers[i];
- for (j = 0; j < B3DFG_FRAMES_PER_BUFFER; j++) {
- buf->frame[j] = kmalloc(fgdev->frame_size, GFP_KERNEL);
- if (!buf->frame[j])
- goto err_no_mem;
- }
- INIT_LIST_HEAD(&buf->list);
- }
-
- INIT_LIST_HEAD(&fgdev->buffer_queue);
- init_waitqueue_head(&fgdev->buffer_waitqueue);
- spin_lock_init(&fgdev->buffer_lock);
- spin_lock_init(&fgdev->cstate_lock);
- spin_lock_init(&fgdev->triplets_dropped_lock);
- return 0;
-
-err_no_mem:
- free_all_frame_buffers(fgdev);
-err_no_buf:
- return -ENOMEM;
-}
-
-/* find next free minor number, returns -1 if none are availabile */
-static int get_free_minor(void)
-{
- int i;
- for (i = 0; i < B3DFG_MAX_DEVS; i++) {
- if (b3dfg_devices[i] == 0)
- return i;
- }
- return -1;
-}
-
-static int __devinit b3dfg_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- struct b3dfg_dev *fgdev = kzalloc(sizeof(*fgdev), GFP_KERNEL);
- int r = 0;
- int minor = get_free_minor();
- dev_t devno = MKDEV(MAJOR(b3dfg_devt), minor);
- unsigned long res_len;
- resource_size_t res_base;
-
- if (fgdev == NULL)
- return -ENOMEM;
-
- if (minor < 0) {
- dev_err(&pdev->dev, "too many devices found!\n");
- r = -EIO;
- goto err_free;
- }
-
- b3dfg_devices[minor] = 1;
- dev_info(&pdev->dev, "probe device with IRQ %d\n", pdev->irq);
-
- cdev_init(&fgdev->chardev, &b3dfg_fops);
- fgdev->chardev.owner = THIS_MODULE;
-
- r = cdev_add(&fgdev->chardev, devno, 1);
- if (r) {
- dev_err(&pdev->dev, "cannot add char device\n");
- goto err_release_minor;
- }
-
- fgdev->dev = device_create(
- b3dfg_class,
- &pdev->dev,
- devno,
- dev_get_drvdata(&pdev->dev),
- DRIVER_NAME "%d", minor);
-
- if (IS_ERR(fgdev->dev)) {
- dev_err(&pdev->dev, "cannot create device\n");
- r = PTR_ERR(fgdev->dev);
- goto err_del_cdev;
- }
-
- r = pci_enable_device(pdev);
- if (r) {
- dev_err(&pdev->dev, "cannot enable PCI device\n");
- goto err_dev_unreg;
- }
-
- res_len = pci_resource_len(pdev, B3DFG_BAR_REGS);
- if (res_len != B3DFG_REGS_LENGTH) {
- dev_err(&pdev->dev, "invalid register resource size\n");
- r = -EIO;
- goto err_disable;
- }
-
- if (pci_resource_flags(pdev, B3DFG_BAR_REGS)
- != (IORESOURCE_MEM | IORESOURCE_SIZEALIGN)) {
- dev_err(&pdev->dev, "invalid resource flags\n");
- r = -EIO;
- goto err_disable;
- }
- r = pci_request_regions(pdev, DRIVER_NAME);
- if (r) {
- dev_err(&pdev->dev, "cannot obtain PCI resources\n");
- goto err_disable;
- }
-
- pci_set_master(pdev);
-
- r = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (r) {
- dev_err(&pdev->dev, "no usable DMA configuration\n");
- goto err_free_res;
- }
-
- res_base = pci_resource_start(pdev, B3DFG_BAR_REGS);
- fgdev->regs = ioremap_nocache(res_base, res_len);
- if (!fgdev->regs) {
- dev_err(&pdev->dev, "regs ioremap failed\n");
- r = -EIO;
- goto err_free_res;
- }
-
- fgdev->pdev = pdev;
- pci_set_drvdata(pdev, fgdev);
- r = b3dfg_init_dev(fgdev);
- if (r < 0) {
- dev_err(&pdev->dev, "failed to initalize device\n");
- goto err_unmap;
- }
-
- r = request_irq(pdev->irq, b3dfg_intr, IRQF_SHARED, DRIVER_NAME, fgdev);
- if (r) {
- dev_err(&pdev->dev, "couldn't request irq %d\n", pdev->irq);
- goto err_free_bufs;
- }
-
- return 0;
-
-err_free_bufs:
- free_all_frame_buffers(fgdev);
-err_unmap:
- iounmap(fgdev->regs);
-err_free_res:
- pci_release_regions(pdev);
-err_disable:
- pci_disable_device(pdev);
-err_dev_unreg:
- device_destroy(b3dfg_class, devno);
-err_del_cdev:
- cdev_del(&fgdev->chardev);
-err_release_minor:
- b3dfg_devices[minor] = 0;
-err_free:
- kfree(fgdev);
- return r;
-}
-
-static void __devexit b3dfg_remove(struct pci_dev *pdev)
-{
- struct b3dfg_dev *fgdev = pci_get_drvdata(pdev);
- unsigned int minor = MINOR(fgdev->chardev.dev);
-
- dev_dbg(&pdev->dev, "remove\n");
-
- free_irq(pdev->irq, fgdev);
- iounmap(fgdev->regs);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- device_destroy(b3dfg_class, MKDEV(MAJOR(b3dfg_devt), minor));
- cdev_del(&fgdev->chardev);
- free_all_frame_buffers(fgdev);
- kfree(fgdev);
- b3dfg_devices[minor] = 0;
-}
-
-static struct pci_driver b3dfg_driver = {
- .name = DRIVER_NAME,
- .id_table = b3dfg_ids,
- .probe = b3dfg_probe,
- .remove = __devexit_p(b3dfg_remove),
-};
-
-static int __init b3dfg_module_init(void)
-{
- int r;
-
- if (b3dfg_nbuf < 2) {
- printk(KERN_ERR DRIVER_NAME
- ": buffer_count is out of range (must be >= 2)");
- return -EINVAL;
- }
-
- printk(KERN_INFO DRIVER_NAME ": loaded\n");
-
- b3dfg_class = class_create(THIS_MODULE, DRIVER_NAME);
- if (IS_ERR(b3dfg_class))
- return PTR_ERR(b3dfg_class);
-
- r = alloc_chrdev_region(&b3dfg_devt, 0, B3DFG_MAX_DEVS, DRIVER_NAME);
- if (r)
- goto err1;
-
- r = pci_register_driver(&b3dfg_driver);
- if (r)
- goto err2;
-
- return r;
-
-err2:
- unregister_chrdev_region(b3dfg_devt, B3DFG_MAX_DEVS);
-err1:
- class_destroy(b3dfg_class);
- return r;
-}
-
-static void __exit b3dfg_module_exit(void)
-{
- printk(KERN_INFO DRIVER_NAME ": unloaded\n");
- pci_unregister_driver(&b3dfg_driver);
- unregister_chrdev_region(b3dfg_devt, B3DFG_MAX_DEVS);
- class_destroy(b3dfg_class);
-}
-
-module_init(b3dfg_module_init);
-module_exit(b3dfg_module_exit);
diff --git a/drivers/staging/batman-adv/Kconfig b/drivers/staging/batman-adv/Kconfig
index 1d74dabf9511..1e7e0a8dbc8b 100644
--- a/drivers/staging/batman-adv/Kconfig
+++ b/drivers/staging/batman-adv/Kconfig
@@ -4,7 +4,7 @@
config BATMAN_ADV
tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
- depends on PROC_FS && PACKET
+ depends on PROC_FS && NET
default n
---help---
@@ -14,10 +14,10 @@ config BATMAN_ADV
http://www.open-mesh.org/ for more information and user space
tools.
-config BATMAN_DEBUG
+config BATMAN_ADV_DEBUG
bool "B.A.T.M.A.N. debugging"
depends on BATMAN_ADV != n
- help
+ ---help---
This is an option for use by developers; most people should
say N here. This enables compilation of support for
diff --git a/drivers/staging/batman-adv/Makefile b/drivers/staging/batman-adv/Makefile
index 02da87134fce..42b4e6370263 100644
--- a/drivers/staging/batman-adv/Makefile
+++ b/drivers/staging/batman-adv/Makefile
@@ -19,4 +19,4 @@
#
obj-m += batman-adv.o
-batman-adv-objs := main.o proc.o send.o routing.o soft-interface.o device.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o log.o
+batman-adv-objs := main.o proc.o send.o routing.o soft-interface.o device.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o
diff --git a/drivers/staging/batman-adv/README b/drivers/staging/batman-adv/README
index 3aaf393ebaa7..7d666ad04359 100644
--- a/drivers/staging/batman-adv/README
+++ b/drivers/staging/batman-adv/README
@@ -1,4 +1,4 @@
-[state: 07-11-2009]
+[state: 06-01-2010]
BATMAN-ADV
----------
@@ -15,19 +15,6 @@ above B.A.T.M.A.N. Advanced, prominent examples are: IPv4, IPv6, DHCP, IPX.
This is batman-advanced implemented as Linux kernel driver. It does not depend
on any network (other) driver, and can be used on wifi as well as ethernet,
vpn, etc ... (anything with ethernet-style layer 2).
-It compiles against and should work with Linux 2.6.20 - 2.6.31. Supporting older
-versions is not planned, but it's probably easy to backport it. If you work on a
-backport, feel free to contact us. :-)
-
-COMPILE
--------
-To compile against your currently installed kernel, just type:
-
-# make
-
-if you want to compile against some other kernel, use:
-
-# make KERNELPATH=/path/to/kernel
USAGE
-----
@@ -73,16 +60,9 @@ When configured as server, you can get a topology snapshot of your mesh:
# cat /proc/net/batman-adv/vis
-This output format is a graphviz formatted text file which can be
-processed with graphviz-tools like dot.
-The labels are similar/compatible to the ETX metric, 1.0 means perfect
-connection (100%), 2.0 means 50%, 3.0 means 33% and so on.
-
-Alternatively, a JSON output format is available. The format can be set
-using by writing either "dot_draw" or "json" into the vis_format file.
-"dot_draw" is selected by default.
-
-echo "json" > /proc/net/batman-adv/vis_format
+The output is in a generic raw format. Use the batctl tool (See below)
+to convert this to other formats more suitable for graphing, eg
+graphviz dot, or JSON data-interchange format.
In very mobile scenarios, you might want to adjust the originator
interval to a lower value. This will make the mesh more responsive to
@@ -96,15 +76,59 @@ To deactivate batman, do:
# echo "" > /proc/net/batman-adv/interfaces
+LOGGING/DEBUGGING
+-----------------
+
+All error messages, warnings and information messages are sent to the
+kernel log. Depending on your operating system distribution this can be
+read in one of a number of ways. Try using the commands: dmesg,
+logread, or looking in the files /var/log/kern.log or
+/var/log/syslog. All batman-adv messages are prefixed with
+"batman-adv:" So to see just these messages try
+
+dmesg | grep batman-adv
+
+When investigating problems with your mesh network it is sometimes
+necessary to see more detail debug messages. This must be enabled when
+compiling the batman-adv module. Use "make menuconfig" and enable the
+option "B.A.T.M.A.N. debugging".
+
+The additional debug output is by default disabled. It can be enabled
+either at kernel module load time or during run time. To enable debug
+output at module load time, add the module parameter debug=<value>.
+<value> can take one of four values.
+
+0 - All debug output disabled
+1 - Enable messages related to routing / flooding / broadcasting
+2 - Enable route or hna added / changed / deleted
+3 - Enable all messages
+
+e.g.
+
+modprobe batman-adv debug=2
+
+will load the module and enable debug messages for when routes or HNAs
+change.
+
+The debug output can also be changed at runtime using the file
+/sys/module/batman-adv/parameters/debug. e.g.
+
+echo 2 > /sys/module/batman-adv/parameters/debug
+
+enables debug messages for when routes or HNAs
+
+The debug output is sent to the kernel logs. So try dmesg, logread etc
+to see the debug messages.
+
BATCTL
------
-B.A.T.M.A.N. advanced operates on layer 2 and thus all hosts partici-
-pating in the virtual switch are completely transparent for all proto-
-cols above layer 2. Therefore the common diagnosis tools do not work as
-expected. To overcome these problems batctl was created. At the moment
-the batctl contains ping, traceroute, tcpdump and interfaces to the
-kernel module settings.
+B.A.T.M.A.N. advanced operates on layer 2 and thus all hosts
+participating in the virtual switch are completely transparent for all
+protocols above layer 2. Therefore the common diagnosis tools do not
+work as expected. To overcome these problems batctl was created. At
+the moment the batctl contains ping, traceroute, tcpdump and
+interfaces to the kernel module settings.
For more information, please see the manpage (man batctl).
diff --git a/drivers/staging/batman-adv/TODO b/drivers/staging/batman-adv/TODO
index ea6dcf94d661..2f15136b18e7 100644
--- a/drivers/staging/batman-adv/TODO
+++ b/drivers/staging/batman-adv/TODO
@@ -17,30 +17,6 @@
-> transtable_global (read-only) [outputs the global translation table]
-> transtable_local (read-only) [outputs the local translation table]
-=> vis "raw" data output
-* the raw format shall replace dot draw / json to offer a neutral that can
-* be converted
-* the format (comma seperated entries):
--> "mac" -> mac address of an originator (each line begins with it)
--> "TQ mac value" -> src mac's link quality towards mac address
--> "HNA mac" -> HNA announced by source mac
--> "PRIMARY" -> this is a primary interface
--> "SEC mac" -> secondary mac address of source (requires preceeding
--> PRIMARY)
-
-=> logging
-* the log level LOG_TYPE_CRIT, LOG_TYPE_WARN & LOG_TYPE_NOTICE will be
-* unified to use printk
-* LOG_TYPE_BATMAN & LOG_TYPE_ROUTES will also use printk but only after the
-* internal debug level has been raised
-* the internal debug level can be modified using a module parameter (debug)
-* or at run time via /sys/module/batman-adv/parameters/debug
-* make use of printk %pM support instead of converting mac addresses
-* manually
-
-=> strip out all backward compatibility support to older kernels
- (only found in compat.h)
-
=> fix checkpatch.pl errors
Please send all patches to:
diff --git a/drivers/staging/batman-adv/aggregation.c b/drivers/staging/batman-adv/aggregation.c
index 9c6e681f6fb6..7917322a7e2a 100644
--- a/drivers/staging/batman-adv/aggregation.c
+++ b/drivers/staging/batman-adv/aggregation.c
@@ -96,6 +96,7 @@ static void new_aggregated_packet(unsigned char *packet_buff,
int own_packet)
{
struct forw_packet *forw_packet_aggr;
+ unsigned long flags;
forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
if (!forw_packet_aggr)
@@ -115,6 +116,7 @@ static void new_aggregated_packet(unsigned char *packet_buff,
packet_buff,
forw_packet_aggr->packet_len);
+ forw_packet_aggr->skb = NULL;
forw_packet_aggr->own = own_packet;
forw_packet_aggr->if_incoming = if_incoming;
forw_packet_aggr->num_packets = 0;
@@ -126,9 +128,9 @@ static void new_aggregated_packet(unsigned char *packet_buff,
forw_packet_aggr->direct_link_flags |= 1;
/* add new packet to packet list */
- spin_lock(&forw_bat_list_lock);
+ spin_lock_irqsave(&forw_bat_list_lock, flags);
hlist_add_head(&forw_packet_aggr->list, &forw_bat_list);
- spin_unlock(&forw_bat_list_lock);
+ spin_unlock_irqrestore(&forw_bat_list_lock, flags);
/* start timer for this packet */
INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
@@ -168,9 +170,10 @@ void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len,
struct batman_packet *batman_packet =
(struct batman_packet *)packet_buff;
bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0;
+ unsigned long flags;
/* find position for the packet in the forward queue */
- spin_lock(&forw_bat_list_lock);
+ spin_lock_irqsave(&forw_bat_list_lock, flags);
/* own packets are not to be aggregated */
if ((atomic_read(&aggregation_enabled)) && (!own_packet)) {
hlist_for_each_entry(forw_packet_pos, tmp_node, &forw_bat_list,
@@ -191,7 +194,7 @@ void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len,
* suitable aggregation packet found */
if (forw_packet_aggr == NULL) {
/* the following section can run without the lock */
- spin_unlock(&forw_bat_list_lock);
+ spin_unlock_irqrestore(&forw_bat_list_lock, flags);
new_aggregated_packet(packet_buff, packet_len,
send_time, direct_link,
if_incoming, own_packet);
@@ -199,7 +202,7 @@ void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len,
aggregate(forw_packet_aggr,
packet_buff, packet_len,
direct_link);
- spin_unlock(&forw_bat_list_lock);
+ spin_unlock_irqrestore(&forw_bat_list_lock, flags);
}
}
diff --git a/drivers/staging/batman-adv/bitarray.c b/drivers/staging/batman-adv/bitarray.c
index 3c67f5f42b2b..212eef93afe4 100644
--- a/drivers/staging/batman-adv/bitarray.c
+++ b/drivers/staging/batman-adv/bitarray.c
@@ -21,7 +21,6 @@
#include "main.h"
#include "bitarray.h"
-#include "log.h"
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
@@ -80,8 +79,8 @@ void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n)
* from.
*
* left is high, right is low: FEDC BA98 7654 3210
- * ^^ ^^
- * vvvv
+ * ^^ ^^
+ * vvvv
* ^^^^ = from, vvvvv =to, we'd have word_num==1 and
* word_offset==WORD_BIT_SIZE/2 ????? in this example.
* (=24 bits)
@@ -133,13 +132,13 @@ char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff,
(seq_num_diff < -TQ_LOCAL_WINDOW_SIZE)) {
if (seq_num_diff > TQ_LOCAL_WINDOW_SIZE)
- debug_log(LOG_TYPE_BATMAN,
- "We missed a lot of packets (%i) !\n",
- seq_num_diff-1);
+ bat_dbg(DBG_BATMAN,
+ "We missed a lot of packets (%i) !\n",
+ seq_num_diff-1);
if (-seq_num_diff > TQ_LOCAL_WINDOW_SIZE)
- debug_log(LOG_TYPE_BATMAN,
- "Other host probably restarted !\n");
+ bat_dbg(DBG_BATMAN,
+ "Other host probably restarted !\n");
for (i = 0; i < NUM_WORDS; i++)
seq_bits[i] = 0;
diff --git a/drivers/staging/batman-adv/compat.h b/drivers/staging/batman-adv/compat.h
deleted file mode 100644
index f4e0a4564ba7..000000000000
--- a/drivers/staging/batman-adv/compat.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- *
- * This file contains macros for maintaining compatibility with older versions
- * of the Linux kernel.
- */
-
-#include <linux/version.h> /* LINUX_VERSION_CODE */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
-
-#define skb_set_network_header(_skb, _offset) \
- do { (_skb)->nh.raw = (_skb)->data + (_offset); } while (0)
-
-#define skb_reset_mac_header(_skb) \
- do { (_skb)->mac.raw = (_skb)->data; } while (0)
-
-#define list_first_entry(ptr, type, member) \
- list_entry((ptr)->next, type, member)
-
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) */
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
-
-#define device_create(_cls, _parent, _devt, _device, _fmt) \
- class_device_create(_cls, _parent, _devt, _device, _fmt)
-
-#define device_destroy(_cls, _device) \
- class_device_destroy(_cls, _device)
-
-#else
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
-
-#define device_create(_cls, _parent, _devt, _device, _fmt) \
- device_create_drvdata(_cls, _parent, _devt, _device, _fmt)
-
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) */
-
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
-
-#define cancel_delayed_work_sync(wq) cancel_rearming_delayed_work(wq)
-
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
-#define strict_strtoul(cp, base, res) \
- ({ \
- int ret = 0; \
- char *endp; \
- *res = simple_strtoul(cp, &endp, base); \
- if (cp == endp) \
- ret = -EINVAL; \
- ret; \
-})
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) */
diff --git a/drivers/staging/batman-adv/device.c b/drivers/staging/batman-adv/device.c
index 1e7d1f88674f..e7f44215b5f3 100644
--- a/drivers/staging/batman-adv/device.c
+++ b/drivers/staging/batman-adv/device.c
@@ -19,14 +19,13 @@
*
*/
+#include <linux/device.h>
#include "main.h"
#include "device.h"
-#include "log.h"
#include "send.h"
#include "types.h"
#include "hash.h"
-
-#include "compat.h"
+#include "hard-interface.h"
static struct class *batman_class;
@@ -60,7 +59,7 @@ int bat_device_setup(void)
/* register our device - kernel assigns a free major number */
tmp_major = register_chrdev(0, DRIVER_DEVICE, &fops);
if (tmp_major < 0) {
- debug_log(LOG_TYPE_WARN, "Registering the character device failed with %d\n",
+ printk(KERN_ERR "batman-adv:Registering the character device failed with %d\n",
tmp_major);
return 0;
}
@@ -68,7 +67,7 @@ int bat_device_setup(void)
batman_class = class_create(THIS_MODULE, "batman-adv");
if (IS_ERR(batman_class)) {
- debug_log(LOG_TYPE_WARN, "Could not register class 'batman-adv' \n");
+ printk(KERN_ERR "batman-adv:Could not register class 'batman-adv' \n");
return 0;
}
@@ -111,7 +110,7 @@ int bat_device_open(struct inode *inode, struct file *file)
}
if (device_client_hash[i] != device_client) {
- debug_log(LOG_TYPE_WARN, "Error - can't add another packet client: maximum number of clients reached \n");
+ printk(KERN_ERR "batman-adv:Error - can't add another packet client: maximum number of clients reached \n");
kfree(device_client);
return -EXFULL;
}
@@ -119,7 +118,7 @@ int bat_device_open(struct inode *inode, struct file *file)
INIT_LIST_HEAD(&device_client->queue_list);
device_client->queue_len = 0;
device_client->index = i;
- device_client->lock = __SPIN_LOCK_UNLOCKED(device_client->lock);
+ spin_lock_init(&device_client->lock);
init_waitqueue_head(&device_client->queue_wait);
file->private_data = device_client;
@@ -134,8 +133,9 @@ int bat_device_release(struct inode *inode, struct file *file)
(struct device_client *)file->private_data;
struct device_packet *device_packet;
struct list_head *list_pos, *list_pos_tmp;
+ unsigned long flags;
- spin_lock(&device_client->lock);
+ spin_lock_irqsave(&device_client->lock, flags);
/* for all packets in the queue ... */
list_for_each_safe(list_pos, list_pos_tmp, &device_client->queue_list) {
@@ -147,7 +147,7 @@ int bat_device_release(struct inode *inode, struct file *file)
}
device_client_hash[device_client->index] = NULL;
- spin_unlock(&device_client->lock);
+ spin_unlock_irqrestore(&device_client->lock, flags);
kfree(device_client);
dec_module_count();
@@ -162,6 +162,7 @@ ssize_t bat_device_read(struct file *file, char __user *buf, size_t count,
(struct device_client *)file->private_data;
struct device_packet *device_packet;
int error;
+ unsigned long flags;
if ((file->f_flags & O_NONBLOCK) && (device_client->queue_len == 0))
return -EAGAIN;
@@ -178,14 +179,14 @@ ssize_t bat_device_read(struct file *file, char __user *buf, size_t count,
if (error)
return error;
- spin_lock(&device_client->lock);
+ spin_lock_irqsave(&device_client->lock, flags);
device_packet = list_first_entry(&device_client->queue_list,
struct device_packet, list);
list_del(&device_packet->list);
device_client->queue_len--;
- spin_unlock(&device_client->lock);
+ spin_unlock_irqrestore(&device_client->lock, flags);
error = __copy_to_user(buf, &device_packet->icmp_packet,
sizeof(struct icmp_packet));
@@ -206,9 +207,11 @@ ssize_t bat_device_write(struct file *file, const char __user *buff,
struct icmp_packet icmp_packet;
struct orig_node *orig_node;
struct batman_if *batman_if;
+ uint8_t dstaddr[ETH_ALEN];
+ unsigned long flags;
if (len < sizeof(struct icmp_packet)) {
- debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: invalid packet size\n");
+ bat_dbg(DBG_BATMAN, "batman-adv:Error - can't send packet from char device: invalid packet size\n");
return -EINVAL;
}
@@ -219,12 +222,12 @@ ssize_t bat_device_write(struct file *file, const char __user *buff,
return -EFAULT;
if (icmp_packet.packet_type != BAT_ICMP) {
- debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n");
+ bat_dbg(DBG_BATMAN, "batman-adv:Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n");
return -EINVAL;
}
if (icmp_packet.msg_type != ECHO_REQUEST) {
- debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n");
+ bat_dbg(DBG_BATMAN, "batman-adv:Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n");
return -EINVAL;
}
@@ -240,7 +243,7 @@ ssize_t bat_device_write(struct file *file, const char __user *buff,
if (atomic_read(&module_state) != MODULE_ACTIVE)
goto dst_unreach;
- spin_lock(&orig_hash_lock);
+ spin_lock_irqsave(&orig_hash_lock, flags);
orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet.dst));
if (!orig_node)
@@ -250,9 +253,15 @@ ssize_t bat_device_write(struct file *file, const char __user *buff,
goto unlock;
batman_if = orig_node->batman_if;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
if (!batman_if)
- goto unlock;
+ goto dst_unreach;
+
+ if (batman_if->if_active != IF_ACTIVE)
+ goto dst_unreach;
memcpy(icmp_packet.orig,
batman_if->net_dev->dev_addr,
@@ -260,13 +269,12 @@ ssize_t bat_device_write(struct file *file, const char __user *buff,
send_raw_packet((unsigned char *)&icmp_packet,
sizeof(struct icmp_packet),
- batman_if, orig_node->router->addr);
+ batman_if, dstaddr);
- spin_unlock(&orig_hash_lock);
goto out;
unlock:
- spin_unlock(&orig_hash_lock);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
dst_unreach:
icmp_packet.msg_type = DESTINATION_UNREACHABLE;
bat_device_add_packet(device_client, &icmp_packet);
@@ -291,6 +299,7 @@ void bat_device_add_packet(struct device_client *device_client,
struct icmp_packet *icmp_packet)
{
struct device_packet *device_packet;
+ unsigned long flags;
device_packet = kmalloc(sizeof(struct device_packet), GFP_KERNEL);
@@ -301,12 +310,12 @@ void bat_device_add_packet(struct device_client *device_client,
memcpy(&device_packet->icmp_packet, icmp_packet,
sizeof(struct icmp_packet));
- spin_lock(&device_client->lock);
+ spin_lock_irqsave(&device_client->lock, flags);
/* while waiting for the lock the device_client could have been
* deleted */
if (!device_client_hash[icmp_packet->uid]) {
- spin_unlock(&device_client->lock);
+ spin_unlock_irqrestore(&device_client->lock, flags);
kfree(device_packet);
return;
}
@@ -323,7 +332,7 @@ void bat_device_add_packet(struct device_client *device_client,
device_client->queue_len--;
}
- spin_unlock(&device_client->lock);
+ spin_unlock_irqrestore(&device_client->lock, flags);
wake_up(&device_client->queue_wait);
}
diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c
index 5ea35da5ee7a..befd48839519 100644
--- a/drivers/staging/batman-adv/hard-interface.c
+++ b/drivers/staging/batman-adv/hard-interface.c
@@ -21,13 +21,11 @@
#include "main.h"
#include "hard-interface.h"
-#include "log.h"
#include "soft-interface.h"
#include "send.h"
#include "translation-table.h"
#include "routing.h"
#include "hash.h"
-#include "compat.h"
#define MIN(x, y) ((x) < (y) ? (x) : (y))
@@ -75,7 +73,6 @@ int hardif_min_mtu(void)
static void check_known_mac_addr(uint8_t *addr)
{
struct batman_if *batman_if;
- char mac_string[ETH_STR_LEN];
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
@@ -86,10 +83,9 @@ static void check_known_mac_addr(uint8_t *addr)
if (!compare_orig(batman_if->net_dev->dev_addr, addr))
continue;
- addr_to_string(mac_string, addr);
- debug_log(LOG_TYPE_WARN, "The newly added mac address (%s) already exists on: %s\n",
- mac_string, batman_if->dev);
- debug_log(LOG_TYPE_WARN, "It is strongly recommended to keep mac addresses unique to avoid problems!\n");
+ printk(KERN_WARNING "batman-adv:The newly added mac address (%pM) already exists on: %s\n",
+ addr, batman_if->dev);
+ printk(KERN_WARNING "batman-adv:It is strongly recommended to keep mac addresses unique to avoid problems!\n");
}
rcu_read_unlock();
}
@@ -154,9 +150,6 @@ void hardif_deactivate_interface(struct batman_if *batman_if)
if (batman_if->if_active != IF_ACTIVE)
return;
- if (batman_if->raw_sock)
- sock_release(batman_if->raw_sock);
-
/**
* batman_if->net_dev has been acquired by dev_get_by_name() in
* proc_interfaces_write() and has to be unreferenced.
@@ -165,22 +158,16 @@ void hardif_deactivate_interface(struct batman_if *batman_if)
if (batman_if->net_dev)
dev_put(batman_if->net_dev);
- batman_if->raw_sock = NULL;
- batman_if->net_dev = NULL;
-
batman_if->if_active = IF_INACTIVE;
active_ifs--;
- debug_log(LOG_TYPE_NOTICE, "Interface deactivated: %s\n",
- batman_if->dev);
+ printk(KERN_INFO "batman-adv:Interface deactivated: %s\n",
+ batman_if->dev);
}
/* (re)activate given interface. */
static void hardif_activate_interface(struct batman_if *batman_if)
{
- struct sockaddr_ll bind_addr;
- int retval;
-
if (batman_if->if_active != IF_INACTIVE)
return;
@@ -192,35 +179,8 @@ static void hardif_activate_interface(struct batman_if *batman_if)
if (!batman_if->net_dev)
goto dev_err;
- retval = sock_create_kern(PF_PACKET, SOCK_RAW,
- __constant_htons(ETH_P_BATMAN),
- &batman_if->raw_sock);
-
- if (retval < 0) {
- debug_log(LOG_TYPE_WARN, "Can't create raw socket: %i\n",
- retval);
- goto sock_err;
- }
-
- bind_addr.sll_family = AF_PACKET;
- bind_addr.sll_ifindex = batman_if->net_dev->ifindex;
- bind_addr.sll_protocol = 0; /* is set by the kernel */
-
- retval = kernel_bind(batman_if->raw_sock,
- (struct sockaddr *)&bind_addr, sizeof(bind_addr));
-
- if (retval < 0) {
- debug_log(LOG_TYPE_WARN, "Can't create bind raw socket: %i\n",
- retval);
- goto bind_err;
- }
-
check_known_mac_addr(batman_if->net_dev->dev_addr);
- batman_if->raw_sock->sk->sk_user_data =
- batman_if->raw_sock->sk->sk_data_ready;
- batman_if->raw_sock->sk->sk_data_ready = batman_data_ready;
-
addr_to_string(batman_if->addr_str, batman_if->net_dev->dev_addr);
memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig,
@@ -235,17 +195,12 @@ static void hardif_activate_interface(struct batman_if *batman_if)
if (batman_if->if_num == 0)
set_main_if_addr(batman_if->net_dev->dev_addr);
- debug_log(LOG_TYPE_NOTICE, "Interface activated: %s\n",
- batman_if->dev);
+ printk(KERN_INFO "batman-adv:Interface activated: %s\n",
+ batman_if->dev);
return;
-bind_err:
- sock_release(batman_if->raw_sock);
-sock_err:
- dev_put(batman_if->net_dev);
dev_err:
- batman_if->raw_sock = NULL;
batman_if->net_dev = NULL;
}
@@ -290,7 +245,7 @@ static int resize_orig(struct orig_node *orig_node, int if_num)
data_ptr = kmalloc((if_num + 1) * sizeof(TYPE_OF_WORD) * NUM_WORDS,
GFP_ATOMIC);
if (!data_ptr) {
- debug_log(LOG_TYPE_WARN, "Can't resize orig: out of memory\n");
+ printk(KERN_ERR "batman-adv:Can't resize orig: out of memory\n");
return -1;
}
@@ -301,7 +256,7 @@ static int resize_orig(struct orig_node *orig_node, int if_num)
data_ptr = kmalloc((if_num + 1) * sizeof(uint8_t), GFP_ATOMIC);
if (!data_ptr) {
- debug_log(LOG_TYPE_WARN, "Can't resize orig: out of memory\n");
+ printk(KERN_ERR "batman-adv:Can't resize orig: out of memory\n");
return -1;
}
@@ -319,16 +274,16 @@ int hardif_add_interface(char *dev, int if_num)
struct batman_if *batman_if;
struct batman_packet *batman_packet;
struct orig_node *orig_node;
- struct hash_it_t *hashit = NULL;
+ unsigned long flags;
+ HASHIT(hashit);
batman_if = kmalloc(sizeof(struct batman_if), GFP_KERNEL);
if (!batman_if) {
- debug_log(LOG_TYPE_WARN, "Can't add interface (%s): out of memory\n", dev);
+ printk(KERN_ERR "batman-adv:Can't add interface (%s): out of memory\n", dev);
return -1;
}
- batman_if->raw_sock = NULL;
batman_if->net_dev = NULL;
if ((if_num == 0) && (num_hna > 0))
@@ -339,7 +294,7 @@ int hardif_add_interface(char *dev, int if_num)
batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_KERNEL);
if (!batman_if->packet_buff) {
- debug_log(LOG_TYPE_WARN, "Can't add interface packet (%s): out of memory\n", dev);
+ printk(KERN_ERR "batman-adv:Can't add interface packet (%s): out of memory\n", dev);
goto out;
}
@@ -348,7 +303,7 @@ int hardif_add_interface(char *dev, int if_num)
batman_if->if_active = IF_INACTIVE;
INIT_RCU_HEAD(&batman_if->rcu);
- debug_log(LOG_TYPE_NOTICE, "Adding interface: %s\n", dev);
+ printk(KERN_INFO "batman-adv:Adding interface: %s\n", dev);
avail_ifs++;
INIT_LIST_HEAD(&batman_if->list);
@@ -376,20 +331,20 @@ int hardif_add_interface(char *dev, int if_num)
/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
* if_num */
- spin_lock(&orig_hash_lock);
+ spin_lock_irqsave(&orig_hash_lock, flags);
- while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
- orig_node = hashit->bucket->data;
+ while (hash_iterate(orig_hash, &hashit)) {
+ orig_node = hashit.bucket->data;
if (resize_orig(orig_node, if_num) == -1) {
- spin_unlock(&orig_hash_lock);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
goto out;
}
}
- spin_unlock(&orig_hash_lock);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
if (!hardif_is_interface_up(batman_if->dev))
- debug_log(LOG_TYPE_WARN, "Not using interface %s (retrying later): interface not active\n", batman_if->dev);
+ printk(KERN_ERR "batman-adv:Not using interface %s (retrying later): interface not active\n", batman_if->dev);
else
hardif_activate_interface(batman_if);
@@ -400,8 +355,7 @@ int hardif_add_interface(char *dev, int if_num)
return 1;
out:
- if (batman_if->packet_buff)
- kfree(batman_if->packet_buff);
+ kfree(batman_if->packet_buff);
kfree(batman_if);
kfree(dev);
return -1;
@@ -413,7 +367,7 @@ char hardif_get_active_if_num(void)
}
static int hard_if_event(struct notifier_block *this,
- unsigned long event, void *ptr)
+ unsigned long event, void *ptr)
{
struct net_device *dev = (struct net_device *)ptr;
struct batman_if *batman_if = get_batman_if_by_name(dev->name);
@@ -436,7 +390,6 @@ static int hard_if_event(struct notifier_block *this,
break;
/* NETDEV_CHANGEADDR - mac address change - what are we doing here ? */
default:
- /* debug_log(LOG_TYPE_CRIT, "hard_if_event: %s %i\n", dev->name, event); */
break;
};
@@ -446,6 +399,122 @@ out:
return NOTIFY_DONE;
}
+/* find batman interface by netdev. assumes rcu_read_lock on */
+static struct batman_if *find_batman_if(struct net_device *dev)
+{
+ struct batman_if *batman_if;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(batman_if, &if_list, list) {
+ if (batman_if->net_dev == dev) {
+ rcu_read_unlock();
+ return batman_if;
+ }
+ }
+ rcu_read_unlock();
+ return NULL;
+}
+
+
+/* receive a packet with the batman ethertype coming on a hard
+ * interface */
+int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *ptype, struct net_device *orig_dev)
+{
+ struct batman_packet *batman_packet;
+ struct batman_if *batman_if;
+ struct net_device_stats *stats;
+ int ret;
+
+ skb = skb_share_check(skb, GFP_ATOMIC);
+
+ /* skb was released by skb_share_check() */
+ if (!skb)
+ goto err_out;
+
+ if (atomic_read(&module_state) != MODULE_ACTIVE)
+ goto err_free;
+
+ /* packet should hold at least type and version */
+ if (unlikely(skb_headlen(skb) < 2))
+ goto err_free;
+
+ /* expect a valid ethernet header here. */
+ if (unlikely(skb->mac_len != sizeof(struct ethhdr)
+ || !skb_mac_header(skb)))
+ goto err_free;
+
+ batman_if = find_batman_if(skb->dev);
+ if (!batman_if)
+ goto err_free;
+
+ /* discard frames on not active interfaces */
+ if (batman_if->if_active != IF_ACTIVE)
+ goto err_free;
+
+ stats = (struct net_device_stats *)dev_get_stats(skb->dev);
+ if (stats) {
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+ }
+
+ batman_packet = (struct batman_packet *)skb->data;
+
+ if (batman_packet->version != COMPAT_VERSION) {
+ bat_dbg(DBG_BATMAN,
+ "Drop packet: incompatible batman version (%i)\n",
+ batman_packet->version);
+ goto err_free;
+ }
+
+ /* all receive handlers return whether they received or reused
+ * the supplied skb. if not, we have to free the skb. */
+
+ switch (batman_packet->packet_type) {
+ /* batman originator packet */
+ case BAT_PACKET:
+ ret = recv_bat_packet(skb, batman_if);
+ break;
+
+ /* batman icmp packet */
+ case BAT_ICMP:
+ ret = recv_icmp_packet(skb);
+ break;
+
+ /* unicast packet */
+ case BAT_UNICAST:
+ ret = recv_unicast_packet(skb);
+ break;
+
+ /* broadcast packet */
+ case BAT_BCAST:
+ ret = recv_bcast_packet(skb);
+ break;
+
+ /* vis packet */
+ case BAT_VIS:
+ ret = recv_vis_packet(skb);
+ break;
+ default:
+ ret = NET_RX_DROP;
+ }
+
+ if (ret == NET_RX_DROP)
+ kfree_skb(skb);
+
+ /* return NET_RX_SUCCESS in any case as we
+ * most probably dropped the packet for
+ * routing-logical reasons. */
+
+ return NET_RX_SUCCESS;
+
+err_free:
+ kfree_skb(skb);
+err_out:
+ return NET_RX_DROP;
+}
+
+
struct notifier_block hard_if_notifier = {
- .notifier_call = hard_if_event,
+ .notifier_call = hard_if_event,
};
diff --git a/drivers/staging/batman-adv/hard-interface.h b/drivers/staging/batman-adv/hard-interface.h
index 742358c00c0e..97c6ecb9e087 100644
--- a/drivers/staging/batman-adv/hard-interface.h
+++ b/drivers/staging/batman-adv/hard-interface.h
@@ -32,5 +32,9 @@ void hardif_deactivate_interface(struct batman_if *batman_if);
char hardif_get_active_if_num(void);
void hardif_check_interfaces_status(void);
void hardif_check_interfaces_status_wq(struct work_struct *work);
+int batman_skb_recv(struct sk_buff *skb,
+ struct net_device *dev,
+ struct packet_type *ptype,
+ struct net_device *orig_dev);
int hardif_min_mtu(void);
void update_min_mtu(void);
diff --git a/drivers/staging/batman-adv/hash.c b/drivers/staging/batman-adv/hash.c
index 61cb4a20ebca..5a2018de3ff2 100644
--- a/drivers/staging/batman-adv/hash.c
+++ b/drivers/staging/batman-adv/hash.c
@@ -64,24 +64,18 @@ void hash_destroy(struct hashtable_t *hash)
kfree(hash);
}
-/* iterate though the hash. first element is selected with iter_in NULL. use
- * the returned iterator to access the elements until hash_it_t returns NULL. */
+/* iterate though the hash. First element is selected if an iterator
+ * initialized with HASHIT() is supplied as iter. Use the returned
+ * (or supplied) iterator to access the elements until hash_iterate returns
+ * NULL. */
+
struct hash_it_t *hash_iterate(struct hashtable_t *hash,
- struct hash_it_t *iter_in)
+ struct hash_it_t *iter)
{
- struct hash_it_t *iter;
-
if (!hash)
return NULL;
-
- if (iter_in == NULL) {
- iter = kmalloc(sizeof(struct hash_it_t), GFP_ATOMIC);
- iter->index = -1;
- iter->bucket = NULL;
- iter->prev_bucket = NULL;
- } else {
- iter = iter_in;
- }
+ if (!iter)
+ return NULL;
/* sanity checks first (if our bucket got deleted in the last
* iteration): */
@@ -139,7 +133,6 @@ struct hash_it_t *hash_iterate(struct hashtable_t *hash,
}
/* nothing to iterate over anymore */
- kfree(iter);
return NULL;
}
diff --git a/drivers/staging/batman-adv/hash.h b/drivers/staging/batman-adv/hash.h
index bb60f082be6a..a70d6d6e1c7a 100644
--- a/drivers/staging/batman-adv/hash.h
+++ b/drivers/staging/batman-adv/hash.h
@@ -21,6 +21,11 @@
#ifndef _BATMAN_HASH_H
#define _BATMAN_HASH_H
+#define HASHIT(name) struct hash_it_t name = { \
+ .index = -1, .bucket = NULL, \
+ .prev_bucket = NULL, \
+ .first_bucket = NULL }
+
typedef int (*hashdata_compare_cb)(void *, void *);
typedef int (*hashdata_choose_cb)(void *, int);
diff --git a/drivers/staging/batman-adv/log.c b/drivers/staging/batman-adv/log.c
deleted file mode 100644
index f37c7f01a9f5..000000000000
--- a/drivers/staging/batman-adv/log.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "log.h"
-
-#define LOG_BUF_MASK (log_buf_len-1)
-#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
-
-static char log_buf[LOG_BUF_LEN];
-static int log_buf_len = LOG_BUF_LEN;
-static unsigned long log_start;
-static unsigned long log_end;
-uint8_t log_level;
-
-static DEFINE_SPINLOCK(logbuf_lock);
-
-const struct file_operations proc_log_operations = {
- .open = log_open,
- .release = log_release,
- .read = log_read,
- .write = log_write,
- .poll = log_poll,
-};
-
-static DECLARE_WAIT_QUEUE_HEAD(log_wait);
-
-static void emit_log_char(char c)
-{
- LOG_BUF(log_end) = c;
- log_end++;
-
- if (log_end - log_start > log_buf_len)
- log_start = log_end - log_buf_len;
-}
-
-static int fdebug_log(char *fmt, ...)
-{
- int printed_len;
- char *p;
- va_list args;
- static char debug_log_buf[256];
- unsigned long flags;
-
- spin_lock_irqsave(&logbuf_lock, flags);
- va_start(args, fmt);
- printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt,
- args);
- va_end(args);
-
- for (p = debug_log_buf; *p != 0; p++)
- emit_log_char(*p);
-
- spin_unlock_irqrestore(&logbuf_lock, flags);
-
- wake_up(&log_wait);
-
- return 0;
-}
-
-int debug_log(int type, char *fmt, ...)
-{
- va_list args;
- int retval = 0;
- char tmp_log_buf[256];
-
- /* only critical information get into the official kernel log */
- if (type == LOG_TYPE_CRIT) {
- va_start(args, fmt);
- vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
- printk(KERN_ERR "batman-adv: %s", tmp_log_buf);
- va_end(args);
- }
-
- if ((type == LOG_TYPE_CRIT) || (log_level & type)) {
- va_start(args, fmt);
- vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
- fdebug_log("[%10u] %s", (jiffies / HZ), tmp_log_buf);
- va_end(args);
- }
-
- return retval;
-}
-
-int log_open(struct inode *inode, struct file *file)
-{
- inc_module_count();
- return 0;
-}
-
-int log_release(struct inode *inode, struct file *file)
-{
- dec_module_count();
- return 0;
-}
-
-ssize_t log_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
-{
- int error, i = 0;
- char c;
- unsigned long flags;
-
- if ((file->f_flags & O_NONBLOCK) && !(log_end - log_start))
- return -EAGAIN;
-
- if ((!buf) || (count < 0))
- return -EINVAL;
-
- if (count == 0)
- return 0;
-
- if (!access_ok(VERIFY_WRITE, buf, count))
- return -EFAULT;
-
- error = wait_event_interruptible(log_wait, (log_start - log_end));
-
- if (error)
- return error;
-
- spin_lock_irqsave(&logbuf_lock, flags);
-
- while ((!error) && (log_start != log_end) && (i < count)) {
- c = LOG_BUF(log_start);
-
- log_start++;
-
- spin_unlock_irqrestore(&logbuf_lock, flags);
-
- error = __put_user(c, buf);
-
- spin_lock_irqsave(&logbuf_lock, flags);
-
- buf++;
- i++;
-
- }
-
- spin_unlock_irqrestore(&logbuf_lock, flags);
-
- if (!error)
- return i;
-
- return error;
-}
-
-ssize_t log_write(struct file *file, const char __user *buf, size_t count,
- loff_t *ppos)
-{
- return count;
-}
-
-unsigned int log_poll(struct file *file, poll_table *wait)
-{
- poll_wait(file, &log_wait, wait);
-
- if (log_end - log_start)
- return POLLIN | POLLRDNORM;
-
- return 0;
-}
diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c
index bb89bfc5dda6..2e0b482e710a 100644
--- a/drivers/staging/batman-adv/main.c
+++ b/drivers/staging/batman-adv/main.c
@@ -21,9 +21,9 @@
#include "main.h"
#include "proc.h"
-#include "log.h"
#include "routing.h"
#include "send.h"
+#include "originator.h"
#include "soft-interface.h"
#include "device.h"
#include "translation-table.h"
@@ -31,7 +31,6 @@
#include "types.h"
#include "vis.h"
#include "hash.h"
-#include "compat.h"
struct list_head if_list;
struct hlist_head forw_bat_list;
@@ -44,19 +43,34 @@ DEFINE_SPINLOCK(forw_bcast_list_lock);
atomic_t originator_interval;
atomic_t vis_interval;
+atomic_t vis_mode;
atomic_t aggregation_enabled;
int16_t num_hna;
int16_t num_ifs;
struct net_device *soft_device;
-static struct task_struct *kthread_task;
-
unsigned char broadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
atomic_t module_state;
+static struct packet_type batman_adv_packet_type __read_mostly = {
+ .type = __constant_htons(ETH_P_BATMAN),
+ .func = batman_skb_recv,
+};
+
struct workqueue_struct *bat_event_workqueue;
+#ifdef CONFIG_BATMAN_ADV_DEBUG
+int debug;
+
+module_param(debug, int, 0644);
+
+int bat_debug_type(int type)
+{
+ return debug & type;
+}
+#endif
+
int init_module(void)
{
int retval;
@@ -70,6 +84,7 @@ int init_module(void)
atomic_set(&originator_interval, 1000);
atomic_set(&vis_interval, 1000);/* TODO: raise this later, this is only
* for debugging now. */
+ atomic_set(&vis_mode, VIS_TYPE_CLIENT_UPDATE);
atomic_set(&aggregation_enabled, 1);
/* the name should not be longer than 10 chars - see
@@ -90,21 +105,22 @@ int init_module(void)
interface_setup);
if (!soft_device) {
- debug_log(LOG_TYPE_CRIT, "Unable to allocate the batman interface\n");
+ printk(KERN_ERR "batman-adv:Unable to allocate the batman interface\n");
goto end;
}
retval = register_netdev(soft_device);
if (retval < 0) {
- debug_log(LOG_TYPE_CRIT, "Unable to register the batman interface: %i\n", retval);
+ printk(KERN_ERR "batman-adv:Unable to register the batman interface: %i\n", retval);
goto free_soft_device;
}
register_netdevice_notifier(&hard_if_notifier);
+ dev_add_pack(&batman_adv_packet_type);
- debug_log(LOG_TYPE_CRIT, "B.A.T.M.A.N. advanced %s%s (compatibility version %i) loaded \n",
- SOURCE_VERSION, REVISION_VERSION_STR, COMPAT_VERSION);
+ printk(KERN_INFO "batman-adv:B.A.T.M.A.N. advanced %s%s (compatibility version %i) loaded \n",
+ SOURCE_VERSION, REVISION_VERSION_STR, COMPAT_VERSION);
return 0;
@@ -124,6 +140,8 @@ void cleanup_module(void)
soft_device = NULL;
}
+ dev_remove_pack(&batman_adv_packet_type);
+
unregister_netdevice_notifier(&hard_if_notifier);
cleanup_procfs();
@@ -151,22 +169,12 @@ void activate_module(void)
if (vis_init() < 1)
goto err;
- /* (re)start kernel thread for packet processing */
- if (!kthread_task) {
- kthread_task = kthread_run(packet_recv_thread, NULL, "batman-adv");
-
- if (IS_ERR(kthread_task)) {
- debug_log(LOG_TYPE_CRIT, "Unable to start packet receive thread\n");
- kthread_task = NULL;
- }
- }
-
update_min_mtu();
atomic_set(&module_state, MODULE_ACTIVE);
goto end;
err:
- debug_log(LOG_TYPE_CRIT, "Unable to allocate memory for mesh information structures: out of mem ?\n");
+ printk(KERN_ERR "batman-adv:Unable to allocate memory for mesh information structures: out of mem ?\n");
shutdown_module();
end:
return;
@@ -182,14 +190,7 @@ void shutdown_module(void)
vis_quit();
- /* deactivate kernel thread for packet processing (if running) */
- if (kthread_task) {
- atomic_set(&exit_cond, 1);
- wake_up_interruptible(&thread_wait);
- kthread_stop(kthread_task);
-
- kthread_task = NULL;
- }
+ /* TODO: unregister BATMAN pack */
originator_free();
diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h
index facb6b79ee52..deb41f5beda6 100644
--- a/drivers/staging/batman-adv/main.h
+++ b/drivers/staging/batman-adv/main.h
@@ -33,16 +33,16 @@
#define TQ_MAX_VALUE 255
#define JITTER 20
-#define TTL 50 /* Time To Live of broadcast messages */
-#define MAX_ADDR 16 /* number of interfaces which can be added to
+#define TTL 50 /* Time To Live of broadcast messages */
+#define MAX_ADDR 16 /* number of interfaces which can be added to
* batman. */
-#define PURGE_TIMEOUT 200000 /* purge originators after time in ms if no
+#define PURGE_TIMEOUT 200000 /* purge originators after time in ms if no
* valid packet comes in -> TODO: check
* influence on TQ_LOCAL_WINDOW_SIZE */
#define LOCAL_HNA_TIMEOUT 3600000
-#define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator
+#define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator
* messages in squence numbers (should be a
* multiple of our word size) */
#define TQ_GLOBAL_WINDOW_SIZE 5
@@ -69,24 +69,27 @@
/*
- * Logging
+ * Debug Messages
*/
-#define LOG_TYPE_CRIT 0 /* highest priority for fatal errors such as
- * blocked sockets / failed packet delivery /
- * programming errors */
-#define LOG_TYPE_WARN 1 /* warnings for small errors like wrong user
- * input / damaged packets / etc */
-#define LOG_TYPE_NOTICE 2 /* notice information for new interfaces /
- * changed settings / new originators / etc */
-#define LOG_TYPE_BATMAN 4 /* all messages related to routing / flooding /
- * broadcasting / etc */
-#define LOG_TYPE_ROUTES 8 /* route or hna added / changed / deleted */
-#define LOG_TYPE_CRIT_NAME "critical"
-#define LOG_TYPE_WARN_NAME "warnings"
-#define LOG_TYPE_NOTICE_NAME "notices"
-#define LOG_TYPE_BATMAN_NAME "batman"
-#define LOG_TYPE_ROUTES_NAME "routes"
+#define DBG_BATMAN 1 /* all messages related to routing / flooding /
+ * broadcasting / etc */
+#define DBG_ROUTES 2 /* route or hna added / changed / deleted */
+
+#ifdef CONFIG_BATMAN_ADV_DEBUG
+extern int debug;
+
+extern int bat_debug_type(int type);
+#define bat_dbg(type, fmt, arg...) do { \
+ if (bat_debug_type(type)) \
+ printk(KERN_DEBUG "batman-adv:" fmt, ## arg); \
+ } \
+ while (0)
+#else /* !CONFIG_BATMAN_ADV_DEBUG */
+#define bat_dbg(type, fmt, arg...) do { \
+ } \
+ while (0)
+#endif
/*
* Vis
@@ -127,6 +130,7 @@ extern spinlock_t forw_bcast_list_lock;
extern atomic_t originator_interval;
extern atomic_t vis_interval;
+extern atomic_t vis_mode;
extern atomic_t aggregation_enabled;
extern int16_t num_hna;
extern int16_t num_ifs;
@@ -147,5 +151,3 @@ int choose_orig(void *data, int32_t size);
int is_my_mac(uint8_t *addr);
int is_bcast(uint8_t *addr);
int is_mcast(uint8_t *addr);
-
-
diff --git a/drivers/staging/batman-adv/originator.c b/drivers/staging/batman-adv/originator.c
new file mode 100644
index 000000000000..29c241119a3b
--- /dev/null
+++ b/drivers/staging/batman-adv/originator.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2009 B.A.T.M.A.N. contributors:
+ *
+ * Marek Lindner, Simon Wunderlich
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+/* increase the reference counter for this originator */
+
+#include "main.h"
+#include "originator.h"
+#include "hash.h"
+#include "translation-table.h"
+#include "routing.h"
+
+static DECLARE_DELAYED_WORK(purge_orig_wq, purge_orig);
+
+static void start_purge_timer(void)
+{
+ queue_delayed_work(bat_event_workqueue, &purge_orig_wq, 1 * HZ);
+}
+
+int originator_init(void)
+{
+ unsigned long flags;
+ if (orig_hash)
+ return 1;
+
+ spin_lock_irqsave(&orig_hash_lock, flags);
+ orig_hash = hash_new(128, compare_orig, choose_orig);
+
+ if (!orig_hash)
+ goto err;
+
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+ start_purge_timer();
+ return 1;
+
+err:
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+ return 0;
+}
+
+void originator_free(void)
+{
+ unsigned long flags;
+
+ if (!orig_hash)
+ return;
+
+ cancel_delayed_work_sync(&purge_orig_wq);
+
+ spin_lock_irqsave(&orig_hash_lock, flags);
+ hash_delete(orig_hash, free_orig_node);
+ orig_hash = NULL;
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+}
+
+struct neigh_node *
+create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
+ uint8_t *neigh, struct batman_if *if_incoming)
+{
+ struct neigh_node *neigh_node;
+
+ bat_dbg(DBG_BATMAN, "Creating new last-hop neighbor of originator\n");
+
+ neigh_node = kzalloc(sizeof(struct neigh_node), GFP_ATOMIC);
+ if (!neigh_node)
+ return NULL;
+
+ INIT_LIST_HEAD(&neigh_node->list);
+
+ memcpy(neigh_node->addr, neigh, ETH_ALEN);
+ neigh_node->orig_node = orig_neigh_node;
+ neigh_node->if_incoming = if_incoming;
+
+ list_add_tail(&neigh_node->list, &orig_node->neigh_list);
+ return neigh_node;
+}
+
+void free_orig_node(void *data)
+{
+ struct list_head *list_pos, *list_pos_tmp;
+ struct neigh_node *neigh_node;
+ struct orig_node *orig_node = (struct orig_node *)data;
+
+ /* for all neighbors towards this originator ... */
+ list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
+ neigh_node = list_entry(list_pos, struct neigh_node, list);
+
+ list_del(list_pos);
+ kfree(neigh_node);
+ }
+
+ hna_global_del_orig(orig_node, "originator timed out");
+
+ kfree(orig_node->bcast_own);
+ kfree(orig_node->bcast_own_sum);
+ kfree(orig_node);
+}
+
+/* this function finds or creates an originator entry for the given
+ * address if it does not exits */
+struct orig_node *get_orig_node(uint8_t *addr)
+{
+ struct orig_node *orig_node;
+ struct hashtable_t *swaphash;
+ int size;
+
+ orig_node = ((struct orig_node *)hash_find(orig_hash, addr));
+
+ if (orig_node != NULL)
+ return orig_node;
+
+ bat_dbg(DBG_BATMAN, "Creating new originator: %pM \n", addr);
+
+ orig_node = kzalloc(sizeof(struct orig_node), GFP_ATOMIC);
+ if (!orig_node)
+ return NULL;
+
+ INIT_LIST_HEAD(&orig_node->neigh_list);
+
+ memcpy(orig_node->orig, addr, ETH_ALEN);
+ orig_node->router = NULL;
+ orig_node->batman_if = NULL;
+ orig_node->hna_buff = NULL;
+
+ size = num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS;
+
+ orig_node->bcast_own = kzalloc(size, GFP_ATOMIC);
+ if (!orig_node->bcast_own)
+ goto free_orig_node;
+
+ size = num_ifs * sizeof(uint8_t);
+ orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC);
+ if (!orig_node->bcast_own_sum)
+ goto free_bcast_own;
+
+ if (hash_add(orig_hash, orig_node) < 0)
+ goto free_bcast_own_sum;
+
+ if (orig_hash->elements * 4 > orig_hash->size) {
+ swaphash = hash_resize(orig_hash, orig_hash->size * 2);
+
+ if (swaphash == NULL)
+ printk(KERN_ERR
+ "batman-adv:Couldn't resize orig hash table \n");
+ else
+ orig_hash = swaphash;
+ }
+
+ return orig_node;
+free_bcast_own_sum:
+ kfree(orig_node->bcast_own_sum);
+free_bcast_own:
+ kfree(orig_node->bcast_own);
+free_orig_node:
+ kfree(orig_node);
+ return NULL;
+}
+
+static bool purge_orig_neighbors(struct orig_node *orig_node,
+ struct neigh_node **best_neigh_node)
+{
+ struct list_head *list_pos, *list_pos_tmp;
+ struct neigh_node *neigh_node;
+ bool neigh_purged = false;
+
+ *best_neigh_node = NULL;
+
+
+ /* for all neighbors towards this originator ... */
+ list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
+ neigh_node = list_entry(list_pos, struct neigh_node, list);
+
+ if (time_after(jiffies,
+ (neigh_node->last_valid +
+ ((PURGE_TIMEOUT * HZ) / 1000)))) {
+
+ bat_dbg(DBG_BATMAN, "neighbor timeout: originator %pM, neighbor: %pM, last_valid %lu\n", orig_node->orig, neigh_node->addr, (neigh_node->last_valid / HZ));
+
+ neigh_purged = true;
+ list_del(list_pos);
+ kfree(neigh_node);
+ } else {
+ if ((*best_neigh_node == NULL) ||
+ (neigh_node->tq_avg > (*best_neigh_node)->tq_avg))
+ *best_neigh_node = neigh_node;
+ }
+ }
+ return neigh_purged;
+}
+
+
+static bool purge_orig_node(struct orig_node *orig_node)
+{
+ struct neigh_node *best_neigh_node;
+
+ if (time_after(jiffies,
+ (orig_node->last_valid +
+ ((2 * PURGE_TIMEOUT * HZ) / 1000)))) {
+
+ bat_dbg(DBG_BATMAN,
+ "Originator timeout: originator %pM, last_valid %lu\n",
+ orig_node->orig, (orig_node->last_valid / HZ));
+ return true;
+ } else {
+ if (purge_orig_neighbors(orig_node, &best_neigh_node))
+ update_routes(orig_node, best_neigh_node,
+ orig_node->hna_buff,
+ orig_node->hna_buff_len);
+ }
+ return false;
+}
+
+void purge_orig(struct work_struct *work)
+{
+ HASHIT(hashit);
+ struct orig_node *orig_node;
+ unsigned long flags;
+
+ spin_lock_irqsave(&orig_hash_lock, flags);
+
+ /* for all origins... */
+ while (hash_iterate(orig_hash, &hashit)) {
+ orig_node = hashit.bucket->data;
+ if (purge_orig_node(orig_node)) {
+ hash_remove_bucket(orig_hash, &hashit);
+ free_orig_node(orig_node);
+ }
+ }
+
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ start_purge_timer();
+}
+
+
diff --git a/drivers/staging/batman-adv/log.h b/drivers/staging/batman-adv/originator.h
index 780e3abb48f9..6ef7a054a0a9 100644
--- a/drivers/staging/batman-adv/log.h
+++ b/drivers/staging/batman-adv/originator.h
@@ -19,14 +19,13 @@
*
*/
-extern const struct file_operations proc_log_operations;
-extern uint8_t log_level;
+int originator_init(void);
+void free_orig_node(void *data);
+void originator_free(void);
+void purge_orig(struct work_struct *work);
+struct orig_node *orig_find(char *mac);
+struct orig_node *get_orig_node(uint8_t *addr);
+struct neigh_node *
+create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
+ uint8_t *neigh, struct batman_if *if_incoming);
-int debug_log(int type, char *fmt, ...);
-int log_open(struct inode *inode, struct file *file);
-int log_release(struct inode *inode, struct file *file);
-ssize_t log_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos);
-ssize_t log_write(struct file *file, const char __user *buf, size_t count,
- loff_t *ppos);
-unsigned int log_poll(struct file *file, poll_table *wait);
diff --git a/drivers/staging/batman-adv/packet.h b/drivers/staging/batman-adv/packet.h
index 5627ca326018..ad006ce8b131 100644
--- a/drivers/staging/batman-adv/packet.h
+++ b/drivers/staging/batman-adv/packet.h
@@ -90,7 +90,7 @@ struct vis_packet {
uint8_t entries; /* number of entries behind this struct */
uint8_t ttl; /* TTL */
uint8_t vis_orig[6]; /* originator that informs about its
- * neighbours */
+ * neighbors */
uint8_t target_orig[6]; /* who should receive this packet */
uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
} __attribute__((packed));
diff --git a/drivers/staging/batman-adv/proc.c b/drivers/staging/batman-adv/proc.c
index aac3df7f13fb..7de60e84bc96 100644
--- a/drivers/staging/batman-adv/proc.c
+++ b/drivers/staging/batman-adv/proc.c
@@ -21,23 +21,18 @@
#include "main.h"
#include "proc.h"
-#include "log.h"
#include "routing.h"
#include "translation-table.h"
#include "hard-interface.h"
#include "types.h"
#include "hash.h"
#include "vis.h"
-#include "compat.h"
-
-static uint8_t vis_format = DOT_DRAW;
static struct proc_dir_entry *proc_batman_dir, *proc_interface_file;
static struct proc_dir_entry *proc_orig_interval_file, *proc_originators_file;
-static struct proc_dir_entry *proc_log_file, *proc_log_level_file;
static struct proc_dir_entry *proc_transt_local_file;
static struct proc_dir_entry *proc_transt_global_file;
-static struct proc_dir_entry *proc_vis_file, *proc_vis_format_file;
+static struct proc_dir_entry *proc_vis_srv_file, *proc_vis_data_file;
static struct proc_dir_entry *proc_aggr_file;
static int proc_interfaces_read(struct seq_file *seq, void *offset)
@@ -68,7 +63,7 @@ static ssize_t proc_interfaces_write(struct file *instance,
size_t count, loff_t *data)
{
char *if_string, *colon_ptr = NULL, *cr_ptr = NULL;
- int not_copied = 0, if_num = 0;
+ int not_copied = 0, if_num = 0, add_success;
struct batman_if *batman_if = NULL;
if_string = kmalloc(count, GFP_KERNEL);
@@ -77,8 +72,7 @@ static ssize_t proc_interfaces_write(struct file *instance,
return -ENOMEM;
if (count > IFNAMSIZ - 1) {
- debug_log(LOG_TYPE_WARN,
- "Can't add interface: device name is too long\n");
+ printk(KERN_WARNING "batman-adv:Can't add interface: device name is too long\n");
goto end;
}
@@ -105,7 +99,7 @@ static ssize_t proc_interfaces_write(struct file *instance,
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
if (strncmp(batman_if->dev, if_string, count) == 0) {
- debug_log(LOG_TYPE_WARN, "Given interface is already active: %s\n", if_string);
+ printk(KERN_ERR "batman-adv:Given interface is already active: %s\n", if_string);
rcu_read_unlock();
goto end;
@@ -115,22 +109,17 @@ static ssize_t proc_interfaces_write(struct file *instance,
}
rcu_read_unlock();
- hardif_add_interface(if_string, if_num);
+ add_success = hardif_add_interface(if_string, if_num);
+ if (add_success < 0)
+ goto end;
+
+ num_ifs = if_num + 1;
if ((atomic_read(&module_state) == MODULE_INACTIVE) &&
(hardif_get_active_if_num() > 0))
activate_module();
- rcu_read_lock();
- if (list_empty(&if_list)) {
- rcu_read_unlock();
- goto end;
- }
- rcu_read_unlock();
-
- num_ifs = if_num + 1;
return count;
-
end:
kfree(if_string);
return count;
@@ -162,20 +151,18 @@ static ssize_t proc_orig_interval_write(struct file *file,
retval = strict_strtoul(interval_string, 10, &originator_interval_tmp);
if (retval) {
- debug_log(LOG_TYPE_WARN, "New originator interval invalid\n");
+ printk(KERN_ERR "batman-adv:New originator interval invalid\n");
goto end;
}
if (originator_interval_tmp <= JITTER * 2) {
- debug_log(LOG_TYPE_WARN,
- "New originator interval too small: %i (min: %i)\n",
- originator_interval_tmp, JITTER * 2);
+ printk(KERN_WARNING "batman-adv:New originator interval too small: %li (min: %i)\n",
+ originator_interval_tmp, JITTER * 2);
goto end;
}
- debug_log(LOG_TYPE_NOTICE,
- "Changing originator interval from: %i to: %i\n",
- atomic_read(&originator_interval), originator_interval_tmp);
+ printk(KERN_INFO "batman-adv:Changing originator interval from: %i to: %li\n",
+ atomic_read(&originator_interval), originator_interval_tmp);
atomic_set(&originator_interval, originator_interval_tmp);
@@ -191,11 +178,12 @@ static int proc_orig_interval_open(struct inode *inode, struct file *file)
static int proc_originators_read(struct seq_file *seq, void *offset)
{
- struct hash_it_t *hashit = NULL;
+ HASHIT(hashit);
struct orig_node *orig_node;
struct neigh_node *neigh_node;
int batman_count = 0;
char orig_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
+ unsigned long flags;
rcu_read_lock();
if (list_empty(&if_list)) {
@@ -218,11 +206,11 @@ static int proc_originators_read(struct seq_file *seq, void *offset)
((struct batman_if *)if_list.next)->addr_str);
rcu_read_unlock();
- spin_lock(&orig_hash_lock);
+ spin_lock_irqsave(&orig_hash_lock, flags);
- while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
+ while (hash_iterate(orig_hash, &hashit)) {
- orig_node = hashit->bucket->data;
+ orig_node = hashit.bucket->data;
if (!orig_node->router)
continue;
@@ -249,7 +237,7 @@ static int proc_originators_read(struct seq_file *seq, void *offset)
}
- spin_unlock(&orig_hash_lock);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
if (batman_count == 0)
seq_printf(seq, "No batman nodes in range ... \n");
@@ -263,84 +251,6 @@ static int proc_originators_open(struct inode *inode, struct file *file)
return single_open(file, proc_originators_read, NULL);
}
-static int proc_log_level_read(struct seq_file *seq, void *offset)
-{
-
- seq_printf(seq, "[x] %s (%d)\n", LOG_TYPE_CRIT_NAME, LOG_TYPE_CRIT);
- seq_printf(seq, "[%c] %s (%d)\n",
- (LOG_TYPE_WARN & log_level) ? 'x' : ' ',
- LOG_TYPE_WARN_NAME, LOG_TYPE_WARN);
- seq_printf(seq, "[%c] %s (%d)\n",
- (LOG_TYPE_NOTICE & log_level) ? 'x' : ' ',
- LOG_TYPE_NOTICE_NAME, LOG_TYPE_NOTICE);
- seq_printf(seq, "[%c] %s (%d)\n",
- (LOG_TYPE_BATMAN & log_level) ? 'x' : ' ',
- LOG_TYPE_BATMAN_NAME, LOG_TYPE_BATMAN);
- seq_printf(seq, "[%c] %s (%d)\n",
- (LOG_TYPE_ROUTES & log_level) ? 'x' : ' ',
- LOG_TYPE_ROUTES_NAME, LOG_TYPE_ROUTES);
- return 0;
-}
-
-static int proc_log_level_open(struct inode *inode, struct file *file)
-{
- return single_open(file, proc_log_level_read, NULL);
-}
-
-static ssize_t proc_log_level_write(struct file *instance,
- const char __user *userbuffer,
- size_t count, loff_t *data)
-{
- char *log_level_string, *tokptr, *cp;
- int finished, not_copied = 0;
- unsigned long log_level_tmp = 0;
-
- log_level_string = kmalloc(count, GFP_KERNEL);
-
- if (!log_level_string)
- return -ENOMEM;
-
- not_copied = copy_from_user(log_level_string, userbuffer, count);
- log_level_string[count - not_copied - 1] = 0;
-
- if (strict_strtoul(log_level_string, 10, &log_level_tmp) < 0) {
- /* was not a number, doing textual parsing */
- log_level_tmp = 0;
- tokptr = log_level_string;
-
- for (cp = log_level_string, finished = 0; !finished; cp++) {
- switch (*cp) {
- case 0:
- finished = 1;
- case ' ':
- case '\n':
- case '\t':
- *cp = 0;
- /* compare */
- if (strcmp(tokptr, LOG_TYPE_WARN_NAME) == 0)
- log_level_tmp |= LOG_TYPE_WARN;
- if (strcmp(tokptr, LOG_TYPE_NOTICE_NAME) == 0)
- log_level_tmp |= LOG_TYPE_NOTICE;
- if (strcmp(tokptr, LOG_TYPE_BATMAN_NAME) == 0)
- log_level_tmp |= LOG_TYPE_BATMAN;
- if (strcmp(tokptr, LOG_TYPE_ROUTES_NAME) == 0)
- log_level_tmp |= LOG_TYPE_ROUTES;
- tokptr = cp + 1;
- break;
- default:
- ;
- }
- }
- }
-
- debug_log(LOG_TYPE_CRIT, "Changing log_level from: %i to: %i\n",
- log_level, log_level_tmp);
- log_level = log_level_tmp;
-
- kfree(log_level_string);
- return count;
-}
-
static int proc_transt_local_read(struct seq_file *seq, void *offset)
{
char *buf;
@@ -405,172 +315,8 @@ static int proc_transt_global_open(struct inode *inode, struct file *file)
return single_open(file, proc_transt_global_read, NULL);
}
-/* insert interface to the list of interfaces of one originator */
-
-static void proc_vis_insert_interface(const uint8_t *interface,
- struct vis_if_list **if_entry,
- bool primary)
-{
- /* Did we get an empty list? (then insert imediately) */
- if(*if_entry == NULL) {
- *if_entry = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL);
- if (*if_entry == NULL)
- return;
-
- (*if_entry)->primary = primary;
- (*if_entry)->next = NULL;
- memcpy((*if_entry)->addr, interface, ETH_ALEN);
- } else {
- struct vis_if_list *head_if_entry = *if_entry;
- /* Do we already have this interface in our list? */
- while (!compare_orig((*if_entry)->addr, (void *)interface)) {
-
- /* Or did we reach the end (then append the interface) */
- if ((*if_entry)->next == NULL) {
- (*if_entry)->next = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL);
- if ((*if_entry)->next == NULL)
- return;
-
- memcpy((*if_entry)->next->addr, interface, ETH_ALEN);
- (*if_entry)->next->primary = primary;
- (*if_entry)->next->next = NULL;
- break;
- }
- *if_entry = (*if_entry)->next;
- }
- /* Rewind the list to its head */
- *if_entry = head_if_entry;
- }
-}
-/* read an entry */
-
-static void proc_vis_read_entry(struct seq_file *seq,
- struct vis_info_entry *entry,
- struct vis_if_list **if_entry,
- uint8_t *vis_orig,
- uint8_t current_format,
- uint8_t first_line)
-{
- char from[40];
- char to[40];
- int int_part, frac_part;
-
- addr_to_string(to, entry->dest);
- if (entry->quality == 0) {
-#ifndef VIS_SUBCLUSTERS_DISABLED
- proc_vis_insert_interface(vis_orig, if_entry, true);
-#endif /* VIS_SUBCLUSTERS_DISABLED */
- addr_to_string(from, vis_orig);
- if (current_format == DOT_DRAW) {
- seq_printf(seq, "\t\"%s\" -> \"%s\" [label=\"HNA\"]\n",
- from, to);
- } else {
- seq_printf(seq,
- "%s\t{ router : \"%s\", gateway : \"%s\", label : \"HNA\" }",
- (first_line ? "" : ",\n"), from, to);
- }
- } else {
-#ifndef VIS_SUBCLUSTERS_DISABLED
- proc_vis_insert_interface(entry->src, if_entry, compare_orig(entry->src, vis_orig));
-#endif /* VIS_SUBCLUSTERS_DISABLED */
- addr_to_string(from, entry->src);
-
- /* kernel has no printf-support for %f? it'd be better to return
- * this in float. */
-
- int_part = TQ_MAX_VALUE / entry->quality;
- frac_part = 1000 * TQ_MAX_VALUE / entry->quality - int_part * 1000;
-
- if (current_format == DOT_DRAW) {
- seq_printf(seq,
- "\t\"%s\" -> \"%s\" [label=\"%d.%d\"]\n",
- from, to, int_part, frac_part);
- } else {
- seq_printf(seq,
- "%s\t{ router : \"%s\", neighbour : \"%s\", label : %d.%d }",
- (first_line ? "" : ",\n"), from, to, int_part, frac_part);
- }
- }
-}
-
-
-static int proc_vis_read(struct seq_file *seq, void *offset)
-{
- struct hash_it_t *hashit = NULL;
- struct vis_info *info;
- struct vis_info_entry *entries;
- struct vis_if_list *if_entries = NULL;
- int i;
- uint8_t current_format, first_line = 1;
-#ifndef VIS_SUBCLUSTERS_DISABLED
- char tmp_addr_str[ETH_STR_LEN];
- struct vis_if_list *tmp_if_next;
-#endif /* VIS_SUBCLUSTERS_DISABLED */
-
- current_format = vis_format;
-
- rcu_read_lock();
- if (list_empty(&if_list) || (!is_vis_server())) {
- rcu_read_unlock();
- if (current_format == DOT_DRAW)
- seq_printf(seq, "digraph {\n}\n");
- goto end;
- }
-
- rcu_read_unlock();
-
- if (current_format == DOT_DRAW)
- seq_printf(seq, "digraph {\n");
-
- spin_lock(&vis_hash_lock);
- while (NULL != (hashit = hash_iterate(vis_hash, hashit))) {
- info = hashit->bucket->data;
- entries = (struct vis_info_entry *)
- ((char *)info + sizeof(struct vis_info));
-
- for (i = 0; i < info->packet.entries; i++) {
- proc_vis_read_entry(seq, &entries[i], &if_entries,
- info->packet.vis_orig,
- current_format, first_line);
- if (first_line)
- first_line = 0;
- }
-
-#ifndef VIS_SUBCLUSTERS_DISABLED
- /* Generate subgraphs from the collected items */
- if (current_format == DOT_DRAW) {
-
- addr_to_string(tmp_addr_str, info->packet.vis_orig);
- seq_printf(seq, "\tsubgraph \"cluster_%s\" {\n", tmp_addr_str);
- while (if_entries != NULL) {
-
- addr_to_string(tmp_addr_str, if_entries->addr);
- if (if_entries->primary)
- seq_printf(seq, "\t\t\"%s\" [peripheries=2]\n", tmp_addr_str);
- else
- seq_printf(seq, "\t\t\"%s\"\n", tmp_addr_str);
-
- /* ... and empty the list while doing this */
- tmp_if_next = if_entries->next;
- kfree(if_entries);
- if_entries = tmp_if_next;
- }
- seq_printf(seq, "\t}\n");
- }
-#endif /* VIS_SUBCLUSTERS_DISABLED */
- }
- spin_unlock(&vis_hash_lock);
-
- if (current_format == DOT_DRAW)
- seq_printf(seq, "}\n");
- else
- seq_printf(seq, "\n");
-end:
- return 0;
-}
-
/* setting the mode of the vis server by the user */
-static ssize_t proc_vis_write(struct file *file, const char __user * buffer,
+static ssize_t proc_vis_srv_write(struct file *file, const char __user * buffer,
size_t count, loff_t *ppos)
{
char *vis_mode_string;
@@ -584,72 +330,84 @@ static ssize_t proc_vis_write(struct file *file, const char __user * buffer,
not_copied = copy_from_user(vis_mode_string, buffer, count);
vis_mode_string[count - not_copied - 1] = 0;
- if (strcmp(vis_mode_string, "client") == 0) {
- debug_log(LOG_TYPE_NOTICE, "Setting VIS mode to client\n");
- vis_set_mode(VIS_TYPE_CLIENT_UPDATE);
- } else if (strcmp(vis_mode_string, "server") == 0) {
- debug_log(LOG_TYPE_NOTICE, "Setting VIS mode to server\n");
- vis_set_mode(VIS_TYPE_SERVER_SYNC);
+ if ((strcmp(vis_mode_string, "client") == 0) ||
+ (strcmp(vis_mode_string, "disabled") == 0)) {
+ printk(KERN_INFO "batman-adv:Setting VIS mode to client (disabling vis server)\n");
+ atomic_set(&vis_mode, VIS_TYPE_CLIENT_UPDATE);
+ } else if ((strcmp(vis_mode_string, "server") == 0) ||
+ (strcmp(vis_mode_string, "enabled") == 0)) {
+ printk(KERN_INFO "batman-adv:Setting VIS mode to server (enabling vis server)\n");
+ atomic_set(&vis_mode, VIS_TYPE_SERVER_SYNC);
} else
- debug_log(LOG_TYPE_WARN, "Unknown VIS mode: %s\n",
- vis_mode_string);
+ printk(KERN_ERR "batman-adv:Unknown VIS mode: %s\n",
+ vis_mode_string);
kfree(vis_mode_string);
return count;
}
-static int proc_vis_open(struct inode *inode, struct file *file)
+static int proc_vis_srv_read(struct seq_file *seq, void *offset)
{
- return single_open(file, proc_vis_read, NULL);
-}
+ int vis_server = atomic_read(&vis_mode);
+
+ seq_printf(seq, "[%c] client mode (server disabled) \n",
+ (vis_server == VIS_TYPE_CLIENT_UPDATE) ? 'x' : ' ');
+ seq_printf(seq, "[%c] server mode (server enabled) \n",
+ (vis_server == VIS_TYPE_SERVER_SYNC) ? 'x' : ' ');
-static int proc_vis_format_read(struct seq_file *seq, void *offset)
-{
- uint8_t current_format = vis_format;
-
- seq_printf(seq, "[%c] %s\n",
- (current_format == DOT_DRAW) ? 'x' : ' ',
- VIS_FORMAT_DD_NAME);
- seq_printf(seq, "[%c] %s\n",
- (current_format == JSON) ? 'x' : ' ',
- VIS_FORMAT_JSON_NAME);
return 0;
}
-static int proc_vis_format_open(struct inode *inode, struct file *file)
+static int proc_vis_srv_open(struct inode *inode, struct file *file)
{
- return single_open(file, proc_vis_format_read, NULL);
+ return single_open(file, proc_vis_srv_read, NULL);
}
-static ssize_t proc_vis_format_write(struct file *file,
- const char __user *buffer,
- size_t count, loff_t *ppos)
+static int proc_vis_data_read(struct seq_file *seq, void *offset)
{
- char *vis_format_string;
- int not_copied = 0;
+ HASHIT(hashit);
+ struct vis_info *info;
+ struct vis_info_entry *entries;
+ HLIST_HEAD(vis_if_list);
+ int i;
+ char tmp_addr_str[ETH_STR_LEN];
+ unsigned long flags;
+ int vis_server = atomic_read(&vis_mode);
+
+ rcu_read_lock();
+ if (list_empty(&if_list) || (vis_server == VIS_TYPE_CLIENT_UPDATE)) {
+ rcu_read_unlock();
+ goto end;
+ }
- vis_format_string = kmalloc(count, GFP_KERNEL);
+ rcu_read_unlock();
- if (!vis_format_string)
- return -ENOMEM;
+ spin_lock_irqsave(&vis_hash_lock, flags);
+ while (hash_iterate(vis_hash, &hashit)) {
+ info = hashit.bucket->data;
+ entries = (struct vis_info_entry *)
+ ((char *)info + sizeof(struct vis_info));
+ addr_to_string(tmp_addr_str, info->packet.vis_orig);
+ seq_printf(seq, "%s,", tmp_addr_str);
- not_copied = copy_from_user(vis_format_string, buffer, count);
- vis_format_string[count - not_copied - 1] = 0;
-
- if (strcmp(vis_format_string, VIS_FORMAT_DD_NAME) == 0) {
- debug_log(LOG_TYPE_NOTICE, "Setting VIS output format to: %s\n",
- VIS_FORMAT_DD_NAME);
- vis_format = DOT_DRAW;
- } else if (strcmp(vis_format_string, VIS_FORMAT_JSON_NAME) == 0) {
- debug_log(LOG_TYPE_NOTICE, "Setting VIS output format to: %s\n",
- VIS_FORMAT_JSON_NAME);
- vis_format = JSON;
- } else
- debug_log(LOG_TYPE_WARN, "Unknown VIS output format: %s\n",
- vis_format_string);
+ for (i = 0; i < info->packet.entries; i++) {
+ proc_vis_read_entry(seq, &entries[i], &vis_if_list,
+ info->packet.vis_orig);
+ }
- kfree(vis_format_string);
- return count;
+ /* add primary/secondary records */
+ proc_vis_read_prim_sec(seq, &vis_if_list);
+ seq_printf(seq, "\n");
+ }
+ spin_unlock_irqrestore(&vis_hash_lock, flags);
+
+end:
+ return 0;
+}
+
+static int proc_vis_data_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_vis_data_read, NULL);
}
static int proc_aggr_read(struct seq_file *seq, void *offset)
@@ -665,6 +423,7 @@ static ssize_t proc_aggr_write(struct file *file, const char __user *buffer,
char *aggr_string;
int not_copied = 0;
unsigned long aggregation_enabled_tmp;
+ int retval;
aggr_string = kmalloc(count, GFP_KERNEL);
@@ -674,22 +433,21 @@ static ssize_t proc_aggr_write(struct file *file, const char __user *buffer,
not_copied = copy_from_user(aggr_string, buffer, count);
aggr_string[count - not_copied - 1] = 0;
- strict_strtoul(aggr_string, 10, &aggregation_enabled_tmp);
+ retval = strict_strtoul(aggr_string, 10, &aggregation_enabled_tmp);
- if ((aggregation_enabled_tmp != 0) && (aggregation_enabled_tmp != 1)) {
- debug_log(LOG_TYPE_WARN, "Aggregation can only be enabled (1) or disabled (0), given value: %li\n", aggregation_enabled_tmp);
- goto end;
+ if (retval || aggregation_enabled_tmp > 1) {
+ printk(KERN_ERR "batman-adv:Aggregation can only be enabled (1) or disabled (0), given value: %li\n", aggregation_enabled_tmp);
+ } else {
+ printk(KERN_INFO "batman-adv:Changing aggregation from: %s (%i) to: %s (%li)\n",
+ (atomic_read(&aggregation_enabled) == 1 ?
+ "enabled" : "disabled"),
+ atomic_read(&aggregation_enabled),
+ (aggregation_enabled_tmp == 1 ? "enabled" : "disabled"),
+ aggregation_enabled_tmp);
+ atomic_set(&aggregation_enabled,
+ (unsigned)aggregation_enabled_tmp);
}
- debug_log(LOG_TYPE_NOTICE, "Changing aggregation from: %s (%i) to: %s (%li)\n",
- (atomic_read(&aggregation_enabled) == 1 ?
- "enabled" : "disabled"),
- atomic_read(&aggregation_enabled),
- (aggregation_enabled_tmp == 1 ? "enabled" : "disabled"),
- aggregation_enabled_tmp);
-
- atomic_set(&aggregation_enabled, (unsigned)aggregation_enabled_tmp);
-end:
kfree(aggr_string);
return count;
}
@@ -715,20 +473,20 @@ static const struct file_operations proc_aggr_fops = {
.release = single_release,
};
-static const struct file_operations proc_vis_format_fops = {
+static const struct file_operations proc_vis_srv_fops = {
.owner = THIS_MODULE,
- .open = proc_vis_format_open,
+ .open = proc_vis_srv_open,
.read = seq_read,
- .write = proc_vis_format_write,
+ .write = proc_vis_srv_write,
.llseek = seq_lseek,
.release = single_release,
};
-static const struct file_operations proc_vis_fops = {
+static const struct file_operations proc_vis_data_fops = {
.owner = THIS_MODULE,
- .open = proc_vis_open,
+ .open = proc_vis_data_open,
.read = seq_read,
- .write = proc_vis_write,
+ .write = proc_dummy_write,
.llseek = seq_lseek,
.release = single_release,
};
@@ -760,15 +518,6 @@ static const struct file_operations proc_transt_global_fops = {
.release = single_release,
};
-static const struct file_operations proc_log_level_fops = {
- .owner = THIS_MODULE,
- .open = proc_log_level_open,
- .read = seq_read,
- .write = proc_log_level_write,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
static const struct file_operations proc_interfaces_fops = {
.owner = THIS_MODULE,
.open = proc_interfaces_open,
@@ -795,12 +544,6 @@ void cleanup_procfs(void)
if (proc_transt_local_file)
remove_proc_entry(PROC_FILE_TRANST_LOCAL, proc_batman_dir);
- if (proc_log_file)
- remove_proc_entry(PROC_FILE_LOG, proc_batman_dir);
-
- if (proc_log_level_file)
- remove_proc_entry(PROC_FILE_LOG_LEVEL, proc_batman_dir);
-
if (proc_originators_file)
remove_proc_entry(PROC_FILE_ORIGINATORS, proc_batman_dir);
@@ -810,11 +553,11 @@ void cleanup_procfs(void)
if (proc_interface_file)
remove_proc_entry(PROC_FILE_INTERFACES, proc_batman_dir);
- if (proc_vis_file)
- remove_proc_entry(PROC_FILE_VIS, proc_batman_dir);
+ if (proc_vis_data_file)
+ remove_proc_entry(PROC_FILE_VIS_DATA, proc_batman_dir);
- if (proc_vis_format_file)
- remove_proc_entry(PROC_FILE_VIS_FORMAT, proc_batman_dir);
+ if (proc_vis_srv_file)
+ remove_proc_entry(PROC_FILE_VIS_SRV, proc_batman_dir);
if (proc_aggr_file)
remove_proc_entry(PROC_FILE_AGGR, proc_batman_dir);
@@ -862,17 +605,6 @@ int setup_procfs(void)
return -EFAULT;
}
- proc_log_level_file = create_proc_entry(PROC_FILE_LOG_LEVEL,
- S_IWUSR | S_IRUGO,
- proc_batman_dir);
- if (proc_log_level_file) {
- proc_log_level_file->proc_fops = &proc_log_level_fops;
- } else {
- printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_LOG_LEVEL);
- cleanup_procfs();
- return -EFAULT;
- }
-
proc_originators_file = create_proc_entry(PROC_FILE_ORIGINATORS,
S_IRUGO, proc_batman_dir);
if (proc_originators_file) {
@@ -883,16 +615,6 @@ int setup_procfs(void)
return -EFAULT;
}
- proc_log_file = create_proc_entry(PROC_FILE_LOG,
- S_IRUGO, proc_batman_dir);
- if (proc_log_file) {
- proc_log_file->proc_fops = &proc_log_operations;
- } else {
- printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_FILE_LOG, PROC_FILE_GATEWAYS);
- cleanup_procfs();
- return -EFAULT;
- }
-
proc_transt_local_file = create_proc_entry(PROC_FILE_TRANST_LOCAL,
S_IRUGO, proc_batman_dir);
if (proc_transt_local_file) {
@@ -913,23 +635,23 @@ int setup_procfs(void)
return -EFAULT;
}
- proc_vis_file = create_proc_entry(PROC_FILE_VIS, S_IWUSR | S_IRUGO,
- proc_batman_dir);
- if (proc_vis_file) {
- proc_vis_file->proc_fops = &proc_vis_fops;
+ proc_vis_srv_file = create_proc_entry(PROC_FILE_VIS_SRV,
+ S_IWUSR | S_IRUGO,
+ proc_batman_dir);
+ if (proc_vis_srv_file) {
+ proc_vis_srv_file->proc_fops = &proc_vis_srv_fops;
} else {
- printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS);
+ printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_SRV);
cleanup_procfs();
return -EFAULT;
}
- proc_vis_format_file = create_proc_entry(PROC_FILE_VIS_FORMAT,
- S_IWUSR | S_IRUGO,
- proc_batman_dir);
- if (proc_vis_format_file) {
- proc_vis_format_file->proc_fops = &proc_vis_format_fops;
+ proc_vis_data_file = create_proc_entry(PROC_FILE_VIS_DATA, S_IRUGO,
+ proc_batman_dir);
+ if (proc_vis_data_file) {
+ proc_vis_data_file->proc_fops = &proc_vis_data_fops;
} else {
- printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_FORMAT);
+ printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_DATA);
cleanup_procfs();
return -EFAULT;
}
@@ -946,5 +668,3 @@ int setup_procfs(void)
return 0;
}
-
-
diff --git a/drivers/staging/batman-adv/proc.h b/drivers/staging/batman-adv/proc.h
index 16d3efdebe52..cd690e0f3e44 100644
--- a/drivers/staging/batman-adv/proc.h
+++ b/drivers/staging/batman-adv/proc.h
@@ -31,19 +31,10 @@
#define PROC_FILE_LOG_LEVEL "log_level"
#define PROC_FILE_TRANST_LOCAL "transtable_local"
#define PROC_FILE_TRANST_GLOBAL "transtable_global"
-#define PROC_FILE_VIS "vis"
-#define PROC_FILE_VIS_FORMAT "vis_format"
+#define PROC_FILE_VIS_SRV "vis_server"
+#define PROC_FILE_VIS_DATA "vis_data"
#define PROC_FILE_AGGR "aggregate_ogm"
void cleanup_procfs(void);
int setup_procfs(void);
-/* While scanning for vis-entries of a particular vis-originator
- * this list collects its interfaces to create a subgraph/cluster
- * out of them later
- */
-struct vis_if_list {
- uint8_t addr[ETH_ALEN];
- bool primary;
- struct vis_if_list *next;
-};
diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c
index 4a14c363ac2b..d89048beebe1 100644
--- a/drivers/staging/batman-adv/routing.c
+++ b/drivers/staging/batman-adv/routing.c
@@ -19,304 +19,226 @@
*
*/
-
-
-
-
#include "main.h"
#include "routing.h"
-#include "log.h"
#include "send.h"
+#include "hash.h"
#include "soft-interface.h"
#include "hard-interface.h"
#include "device.h"
#include "translation-table.h"
+#include "originator.h"
#include "types.h"
-#include "hash.h"
#include "ring_buffer.h"
#include "vis.h"
#include "aggregation.h"
-#include "compat.h"
-
-
DECLARE_WAIT_QUEUE_HEAD(thread_wait);
-static DECLARE_DELAYED_WORK(purge_orig_wq, purge_orig);
-
-static atomic_t data_ready_cond;
-atomic_t exit_cond;
-
-static void start_purge_timer(void)
-{
- queue_delayed_work(bat_event_workqueue, &purge_orig_wq, 1 * HZ);
-}
-
-int originator_init(void)
-{
- if (orig_hash)
- return 1;
-
- spin_lock(&orig_hash_lock);
- orig_hash = hash_new(128, compare_orig, choose_orig);
-
- if (!orig_hash)
- goto err;
-
- spin_unlock(&orig_hash_lock);
- start_purge_timer();
- return 1;
-
-err:
- spin_unlock(&orig_hash_lock);
- return 0;
-}
-
-void originator_free(void)
-{
- if (!orig_hash)
- return;
-
- cancel_delayed_work_sync(&purge_orig_wq);
-
- spin_lock(&orig_hash_lock);
- hash_delete(orig_hash, free_orig_node);
- orig_hash = NULL;
- spin_unlock(&orig_hash_lock);
-}
-static struct neigh_node *create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, uint8_t *neigh, struct batman_if *if_incoming)
+void slide_own_bcast_window(struct batman_if *batman_if)
{
- struct neigh_node *neigh_node;
+ HASHIT(hashit);
+ struct orig_node *orig_node;
+ TYPE_OF_WORD *word;
+ unsigned long flags;
- debug_log(LOG_TYPE_BATMAN, "Creating new last-hop neighbour of originator\n");
+ spin_lock_irqsave(&orig_hash_lock, flags);
- neigh_node = kmalloc(sizeof(struct neigh_node), GFP_ATOMIC);
- memset(neigh_node, 0, sizeof(struct neigh_node));
- INIT_LIST_HEAD(&neigh_node->list);
+ while (hash_iterate(orig_hash, &hashit)) {
+ orig_node = hashit.bucket->data;
+ word = &(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]);
- memcpy(neigh_node->addr, neigh, ETH_ALEN);
- neigh_node->orig_node = orig_neigh_node;
- neigh_node->if_incoming = if_incoming;
+ bit_get_packet(word, 1, 0);
+ orig_node->bcast_own_sum[batman_if->if_num] =
+ bit_packet_count(word);
+ }
- list_add_tail(&neigh_node->list, &orig_node->neigh_list);
- return neigh_node;
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
}
-void free_orig_node(void *data)
+static void update_HNA(struct orig_node *orig_node,
+ unsigned char *hna_buff, int hna_buff_len)
{
- struct list_head *list_pos, *list_pos_tmp;
- struct neigh_node *neigh_node;
- struct orig_node *orig_node = (struct orig_node *)data;
+ if ((hna_buff_len != orig_node->hna_buff_len) ||
+ ((hna_buff_len > 0) &&
+ (orig_node->hna_buff_len > 0) &&
+ (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) {
- /* for all neighbours towards this originator ... */
- list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
- neigh_node = list_entry(list_pos, struct neigh_node, list);
+ if (orig_node->hna_buff_len > 0)
+ hna_global_del_orig(orig_node,
+ "originator changed hna");
- list_del(list_pos);
- kfree(neigh_node);
+ if ((hna_buff_len > 0) && (hna_buff != NULL))
+ hna_global_add_orig(orig_node, hna_buff, hna_buff_len);
}
-
- hna_global_del_orig(orig_node, "originator timed out");
-
- kfree(orig_node->bcast_own);
- kfree(orig_node->bcast_own_sum);
- kfree(orig_node);
}
-/* this function finds or creates an originator entry for the given address if it does not exits */
-static struct orig_node *get_orig_node(uint8_t *addr)
+static void update_route(struct orig_node *orig_node,
+ struct neigh_node *neigh_node,
+ unsigned char *hna_buff, int hna_buff_len)
{
- struct orig_node *orig_node;
- struct hashtable_t *swaphash;
- char orig_str[ETH_STR_LEN];
-
- orig_node = ((struct orig_node *)hash_find(orig_hash, addr));
-
- if (orig_node != NULL)
- return orig_node;
-
- addr_to_string(orig_str, addr);
- debug_log(LOG_TYPE_BATMAN, "Creating new originator: %s \n", orig_str);
-
- orig_node = kmalloc(sizeof(struct orig_node), GFP_ATOMIC);
- memset(orig_node, 0, sizeof(struct orig_node));
- INIT_LIST_HEAD(&orig_node->neigh_list);
-
- memcpy(orig_node->orig, addr, ETH_ALEN);
- orig_node->router = NULL;
- orig_node->batman_if = NULL;
- orig_node->hna_buff = NULL;
+ /* route deleted */
+ if ((orig_node->router != NULL) && (neigh_node == NULL)) {
- orig_node->bcast_own = kmalloc(num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS, GFP_ATOMIC);
- memset(orig_node->bcast_own, 0, num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS);
+ bat_dbg(DBG_ROUTES, "Deleting route towards: %pM\n",
+ orig_node->orig);
+ hna_global_del_orig(orig_node, "originator timed out");
- orig_node->bcast_own_sum = kmalloc(num_ifs * sizeof(uint8_t), GFP_ATOMIC);
- memset(orig_node->bcast_own_sum, 0, num_ifs * sizeof(uint8_t));
-
- hash_add(orig_hash, orig_node);
+ /* route added */
+ } else if ((orig_node->router == NULL) && (neigh_node != NULL)) {
- if (orig_hash->elements * 4 > orig_hash->size) {
- swaphash = hash_resize(orig_hash, orig_hash->size * 2);
+ bat_dbg(DBG_ROUTES,
+ "Adding route towards: %pM (via %pM)\n",
+ orig_node->orig, neigh_node->addr);
+ hna_global_add_orig(orig_node, hna_buff, hna_buff_len);
- if (swaphash == NULL)
- debug_log(LOG_TYPE_CRIT, "Couldn't resize orig hash table \n");
- else
- orig_hash = swaphash;
+ /* route changed */
+ } else {
+ bat_dbg(DBG_ROUTES, "Changing route towards: %pM (now via %pM - was via %pM)\n", orig_node->orig, neigh_node->addr, orig_node->router->addr);
}
- return orig_node;
-}
-
-void slide_own_bcast_window(struct batman_if *batman_if)
-{
- struct hash_it_t *hashit = NULL;
- struct orig_node *orig_node;
-
- spin_lock(&orig_hash_lock);
-
- while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
- orig_node = hashit->bucket->data;
-
- bit_get_packet((TYPE_OF_WORD *)&(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]), 1, 0);
- orig_node->bcast_own_sum[batman_if->if_num] = bit_packet_count((TYPE_OF_WORD *)&(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]));
- }
+ if (neigh_node != NULL)
+ orig_node->batman_if = neigh_node->if_incoming;
+ else
+ orig_node->batman_if = NULL;
- spin_unlock(&orig_hash_lock);
+ orig_node->router = neigh_node;
}
-static void update_routes(struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len)
+
+void update_routes(struct orig_node *orig_node,
+ struct neigh_node *neigh_node,
+ unsigned char *hna_buff, int hna_buff_len)
{
- char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
if (orig_node == NULL)
return;
- if (orig_node->router != neigh_node) {
- addr_to_string(orig_str, orig_node->orig);
-
- /* route deleted */
- if ((orig_node->router != NULL) && (neigh_node == NULL)) {
-
- debug_log(LOG_TYPE_ROUTES, "Deleting route towards: %s\n", orig_str);
- hna_global_del_orig(orig_node, "originator timed out");
-
- /* route added */
- } else if ((orig_node->router == NULL) && (neigh_node != NULL)) {
-
- addr_to_string(neigh_str, neigh_node->addr);
- debug_log(LOG_TYPE_ROUTES, "Adding route towards: %s (via %s)\n", orig_str, neigh_str);
- hna_global_add_orig(orig_node, hna_buff, hna_buff_len);
-
- /* route changed */
- } else {
-
- addr_to_string(neigh_str, neigh_node->addr);
- addr_to_string(router_str, orig_node->router->addr);
- debug_log(LOG_TYPE_ROUTES, "Changing route towards: %s (now via %s - was via %s)\n", orig_str, neigh_str, router_str);
-
- }
-
- if (neigh_node != NULL)
- orig_node->batman_if = neigh_node->if_incoming;
- else
- orig_node->batman_if = NULL;
-
- orig_node->router = neigh_node;
-
+ if (orig_node->router != neigh_node)
+ update_route(orig_node, neigh_node, hna_buff, hna_buff_len);
/* may be just HNA changed */
- } else {
-
- if ((hna_buff_len != orig_node->hna_buff_len) || ((hna_buff_len > 0) && (orig_node->hna_buff_len > 0) && (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) {
-
- if (orig_node->hna_buff_len > 0)
- hna_global_del_orig(orig_node, "originator changed hna");
-
- if ((hna_buff_len > 0) && (hna_buff != NULL))
- hna_global_add_orig(orig_node, hna_buff, hna_buff_len);
-
- }
-
- }
+ else
+ update_HNA(orig_node, hna_buff, hna_buff_len);
}
-static int isBidirectionalNeigh(struct orig_node *orig_node, struct orig_node *orig_neigh_node, struct batman_packet *batman_packet, struct batman_if *if_incoming)
+static int isBidirectionalNeigh(struct orig_node *orig_node,
+ struct orig_node *orig_neigh_node,
+ struct batman_packet *batman_packet,
+ struct batman_if *if_incoming)
{
struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
- char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN];
unsigned char total_count;
- addr_to_string(orig_str, orig_node->orig);
- addr_to_string(neigh_str, orig_neigh_node->orig);
-
if (orig_node == orig_neigh_node) {
- list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
+ list_for_each_entry(tmp_neigh_node,
+ &orig_node->neigh_list,
+ list) {
- if (compare_orig(tmp_neigh_node->addr, orig_neigh_node->orig) && (tmp_neigh_node->if_incoming == if_incoming))
+ if (compare_orig(tmp_neigh_node->addr,
+ orig_neigh_node->orig) &&
+ (tmp_neigh_node->if_incoming == if_incoming))
neigh_node = tmp_neigh_node;
}
- if (neigh_node == NULL)
- neigh_node = create_neighbor(orig_node, orig_neigh_node, orig_neigh_node->orig, if_incoming);
+ if (!neigh_node)
+ neigh_node = create_neighbor(orig_node,
+ orig_neigh_node,
+ orig_neigh_node->orig,
+ if_incoming);
+ /* create_neighbor failed, return 0 */
+ if (!neigh_node)
+ return 0;
neigh_node->last_valid = jiffies;
} else {
/* find packet count of corresponding one hop neighbor */
- list_for_each_entry(tmp_neigh_node, &orig_neigh_node->neigh_list, list) {
+ list_for_each_entry(tmp_neigh_node,
+ &orig_neigh_node->neigh_list, list) {
- if (compare_orig(tmp_neigh_node->addr, orig_neigh_node->orig) && (tmp_neigh_node->if_incoming == if_incoming))
+ if (compare_orig(tmp_neigh_node->addr,
+ orig_neigh_node->orig) &&
+ (tmp_neigh_node->if_incoming == if_incoming))
neigh_node = tmp_neigh_node;
}
- if (neigh_node == NULL)
- neigh_node = create_neighbor(orig_neigh_node, orig_neigh_node, orig_neigh_node->orig, if_incoming);
+ if (!neigh_node)
+ neigh_node = create_neighbor(orig_neigh_node,
+ orig_neigh_node,
+ orig_neigh_node->orig,
+ if_incoming);
+ /* create_neighbor failed, return 0 */
+ if (!neigh_node)
+ return 0;
}
orig_node->last_valid = jiffies;
/* pay attention to not get a value bigger than 100 % */
- total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] > neigh_node->real_packet_count ? neigh_node->real_packet_count : orig_neigh_node->bcast_own_sum[if_incoming->if_num]);
+ total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] >
+ neigh_node->real_packet_count ?
+ neigh_node->real_packet_count :
+ orig_neigh_node->bcast_own_sum[if_incoming->if_num]);
/* if we have too few packets (too less data) we set tq_own to zero */
/* if we receive too few packets it is not considered bidirectional */
- if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) || (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
+ if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) ||
+ (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
orig_neigh_node->tq_own = 0;
else
- /* neigh_node->real_packet_count is never zero as we only purge old information when getting new information */
- orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) / neigh_node->real_packet_count;
+ /* neigh_node->real_packet_count is never zero as we
+ * only purge old information when getting new
+ * information */
+ orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) /
+ neigh_node->real_packet_count;
/*
- * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE
- * this does affect the nearly-symmetric links only a little,
- * but punishes asymmetric links more.
- * this will give a value between 0 and TQ_MAX_VALUE
+ * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
+ * affect the nearly-symmetric links only a little, but
+ * punishes asymmetric links more. This will give a value
+ * between 0 and TQ_MAX_VALUE
*/
- orig_neigh_node->tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE *
- (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
- (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
- (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) /
- (TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE);
-
- batman_packet->tq = ((batman_packet->tq * orig_neigh_node->tq_own * orig_neigh_node->tq_asym_penalty) / (TQ_MAX_VALUE * TQ_MAX_VALUE));
-
- debug_log(LOG_TYPE_BATMAN, "bidirectional: orig = %-15s neigh = %-15s => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i \n",
- orig_str, neigh_str, total_count, neigh_node->real_packet_count, orig_neigh_node->tq_own, orig_neigh_node->tq_asym_penalty, batman_packet->tq);
-
- /* if link has the minimum required transmission quality consider it bidirectional */
+ orig_neigh_node->tq_asym_penalty =
+ TQ_MAX_VALUE -
+ (TQ_MAX_VALUE *
+ (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
+ (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
+ (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) /
+ (TQ_LOCAL_WINDOW_SIZE *
+ TQ_LOCAL_WINDOW_SIZE *
+ TQ_LOCAL_WINDOW_SIZE);
+
+ batman_packet->tq = ((batman_packet->tq *
+ orig_neigh_node->tq_own *
+ orig_neigh_node->tq_asym_penalty) /
+ (TQ_MAX_VALUE * TQ_MAX_VALUE));
+
+ bat_dbg(DBG_BATMAN, "bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i \n",
+ orig_node->orig, orig_neigh_node->orig, total_count,
+ neigh_node->real_packet_count, orig_neigh_node->tq_own,
+ orig_neigh_node->tq_asym_penalty, batman_packet->tq);
+
+ /* if link has the minimum required transmission quality
+ * consider it bidirectional */
if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)
return 1;
return 0;
}
-static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, struct batman_packet *batman_packet, struct batman_if *if_incoming, unsigned char *hna_buff, int hna_buff_len, char is_duplicate)
+static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr,
+ struct batman_packet *batman_packet,
+ struct batman_if *if_incoming,
+ unsigned char *hna_buff, int hna_buff_len,
+ char is_duplicate)
{
struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
int tmp_hna_buff_len;
- debug_log(LOG_TYPE_BATMAN, "update_originator(): Searching and updating originator entry of received packet \n");
+ bat_dbg(DBG_BATMAN, "update_originator(): Searching and updating originator entry of received packet \n");
list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
- if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && (tmp_neigh_node->if_incoming == if_incoming)) {
+ if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) &&
+ (tmp_neigh_node->if_incoming == if_incoming)) {
neigh_node = tmp_neigh_node;
continue;
}
@@ -324,19 +246,34 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, stru
if (is_duplicate)
continue;
- ring_buffer_set(tmp_neigh_node->tq_recv, &tmp_neigh_node->tq_index, 0);
- tmp_neigh_node->tq_avg = ring_buffer_avg(tmp_neigh_node->tq_recv);
+ ring_buffer_set(tmp_neigh_node->tq_recv,
+ &tmp_neigh_node->tq_index, 0);
+ tmp_neigh_node->tq_avg =
+ ring_buffer_avg(tmp_neigh_node->tq_recv);
}
- if (neigh_node == NULL)
- neigh_node = create_neighbor(orig_node, get_orig_node(ethhdr->h_source), ethhdr->h_source, if_incoming);
- else
- debug_log(LOG_TYPE_BATMAN, "Updating existing last-hop neighbour of originator\n");
+ if (!neigh_node) {
+ struct orig_node *orig_tmp;
+
+ orig_tmp = get_orig_node(ethhdr->h_source);
+ if (!orig_tmp)
+ return;
+
+ neigh_node = create_neighbor(orig_node,
+ orig_tmp,
+ ethhdr->h_source, if_incoming);
+ if (!neigh_node)
+ return;
+ } else
+ bat_dbg(DBG_BATMAN,
+ "Updating existing last-hop neighbor of originator\n");
orig_node->flags = batman_packet->flags;
neigh_node->last_valid = jiffies;
- ring_buffer_set(neigh_node->tq_recv, &neigh_node->tq_index, batman_packet->tq);
+ ring_buffer_set(neigh_node->tq_recv,
+ &neigh_node->tq_index,
+ batman_packet->tq);
neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
if (!is_duplicate) {
@@ -344,9 +281,11 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, stru
neigh_node->last_ttl = batman_packet->ttl;
}
- tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ? batman_packet->num_hna * ETH_ALEN : hna_buff_len);
+ tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ?
+ batman_packet->num_hna * ETH_ALEN : hna_buff_len);
- /* if this neighbor already is our next hop there is nothing to change */
+ /* if this neighbor already is our next hop there is nothing
+ * to change */
if (orig_node->router == neigh_node)
goto update_hna;
@@ -355,11 +294,12 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, stru
(orig_node->router->tq_avg > neigh_node->tq_avg))
goto update_hna;
- /* if the TQ is the same and the link not more symetric we won't consider it either */
+ /* if the TQ is the same and the link not more symetric we
+ * won't consider it either */
if ((orig_node->router) &&
((neigh_node->tq_avg == orig_node->router->tq_avg) &&
- (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num] >=
- neigh_node->orig_node->bcast_own_sum[if_incoming->if_num])))
+ (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num]
+ >= neigh_node->orig_node->bcast_own_sum[if_incoming->if_num])))
goto update_hna;
update_routes(orig_node, neigh_node, hna_buff, tmp_hna_buff_len);
@@ -367,60 +307,72 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, stru
update_hna:
update_routes(orig_node, orig_node->router, hna_buff, tmp_hna_buff_len);
- return;
}
-static char count_real_packets(struct ethhdr *ethhdr, struct batman_packet *batman_packet, struct batman_if *if_incoming)
+static char count_real_packets(struct ethhdr *ethhdr,
+ struct batman_packet *batman_packet,
+ struct batman_if *if_incoming)
{
struct orig_node *orig_node;
struct neigh_node *tmp_neigh_node;
char is_duplicate = 0;
-
+ uint16_t seq_diff;
orig_node = get_orig_node(batman_packet->orig);
if (orig_node == NULL)
return 0;
-
list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
if (!is_duplicate)
- is_duplicate = get_bit_status(tmp_neigh_node->real_bits, orig_node->last_real_seqno, batman_packet->seqno);
-
- if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && (tmp_neigh_node->if_incoming == if_incoming))
- bit_get_packet(tmp_neigh_node->real_bits, batman_packet->seqno - orig_node->last_real_seqno, 1);
+ is_duplicate =
+ get_bit_status(tmp_neigh_node->real_bits,
+ orig_node->last_real_seqno,
+ batman_packet->seqno);
+ seq_diff = batman_packet->seqno - orig_node->last_real_seqno;
+ if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) &&
+ (tmp_neigh_node->if_incoming == if_incoming))
+ bit_get_packet(tmp_neigh_node->real_bits, seq_diff, 1);
else
- bit_get_packet(tmp_neigh_node->real_bits, batman_packet->seqno - orig_node->last_real_seqno, 0);
+ bit_get_packet(tmp_neigh_node->real_bits, seq_diff, 0);
- tmp_neigh_node->real_packet_count = bit_packet_count(tmp_neigh_node->real_bits);
+ tmp_neigh_node->real_packet_count =
+ bit_packet_count(tmp_neigh_node->real_bits);
}
if (!is_duplicate) {
- debug_log(LOG_TYPE_BATMAN, "updating last_seqno: old %d, new %d \n", orig_node->last_real_seqno, batman_packet->seqno);
+ bat_dbg(DBG_BATMAN, "updating last_seqno: old %d, new %d \n",
+ orig_node->last_real_seqno, batman_packet->seqno);
orig_node->last_real_seqno = batman_packet->seqno;
}
return is_duplicate;
}
-void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_packet, unsigned char *hna_buff, int hna_buff_len, struct batman_if *if_incoming)
+void receive_bat_packet(struct ethhdr *ethhdr,
+ struct batman_packet *batman_packet,
+ unsigned char *hna_buff, int hna_buff_len,
+ struct batman_if *if_incoming)
{
struct batman_if *batman_if;
struct orig_node *orig_neigh_node, *orig_node;
- char orig_str[ETH_STR_LEN], prev_sender_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN];
char has_directlink_flag;
- char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0, is_broadcast = 0, is_bidirectional, is_single_hop_neigh, is_duplicate;
+ char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
+ char is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
+ char is_duplicate;
unsigned short if_incoming_seqno;
- /* Silently drop when the batman packet is actually not a correct packet.
+ /* Silently drop when the batman packet is actually not a
+ * correct packet.
*
* This might happen if a packet is padded (e.g. Ethernet has a
* minimum frame length of 64 byte) and the aggregation interprets
* it as an additional length.
*
- * TODO: A more sane solution would be to have a bit in the batman_packet
- * to detect whether the packet is the last packet in an aggregation.
- * Here we expect that the padding is always zero (or not 0x01)
+ * TODO: A more sane solution would be to have a bit in the
+ * batman_packet to detect whether the packet is the last
+ * packet in an aggregation. Here we expect that the padding
+ * is always zero (or not 0x01)
*/
if (batman_packet->packet_type != BAT_PACKET)
return;
@@ -428,27 +380,31 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_pack
/* could be changed by schedule_own_packet() */
if_incoming_seqno = atomic_read(&if_incoming->seqno);
- addr_to_string(orig_str, batman_packet->orig);
- addr_to_string(prev_sender_str, batman_packet->prev_sender);
- addr_to_string(neigh_str, ethhdr->h_source);
-
has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0);
- is_single_hop_neigh = (compare_orig(ethhdr->h_source, batman_packet->orig) ? 1 : 0);
+ is_single_hop_neigh = (compare_orig(ethhdr->h_source,
+ batman_packet->orig) ? 1 : 0);
- debug_log(LOG_TYPE_BATMAN, "Received BATMAN packet via NB: %s, IF: %s [%s] (from OG: %s, via prev OG: %s, seqno %d, tq %d, TTL %d, V %d, IDF %d) \n", neigh_str, if_incoming->dev, if_incoming->addr_str, orig_str, prev_sender_str, batman_packet->seqno, batman_packet->tq, batman_packet->ttl, batman_packet->version, has_directlink_flag);
+ bat_dbg(DBG_BATMAN, "Received BATMAN packet via NB: %pM, IF: %s [%s] (from OG: %pM, via prev OG: %pM, seqno %d, tq %d, TTL %d, V %d, IDF %d) \n",
+ ethhdr->h_source, if_incoming->dev, if_incoming->addr_str,
+ batman_packet->orig, batman_packet->prev_sender,
+ batman_packet->seqno, batman_packet->tq, batman_packet->ttl,
+ batman_packet->version, has_directlink_flag);
list_for_each_entry_rcu(batman_if, &if_list, list) {
if (batman_if->if_active != IF_ACTIVE)
continue;
- if (compare_orig(ethhdr->h_source, batman_if->net_dev->dev_addr))
+ if (compare_orig(ethhdr->h_source,
+ batman_if->net_dev->dev_addr))
is_my_addr = 1;
- if (compare_orig(batman_packet->orig, batman_if->net_dev->dev_addr))
+ if (compare_orig(batman_packet->orig,
+ batman_if->net_dev->dev_addr))
is_my_orig = 1;
- if (compare_orig(batman_packet->prev_sender, batman_if->net_dev->dev_addr))
+ if (compare_orig(batman_packet->prev_sender,
+ batman_if->net_dev->dev_addr))
is_my_oldorig = 1;
if (compare_orig(ethhdr->h_source, broadcastAddr))
@@ -456,44 +412,61 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_pack
}
if (batman_packet->version != COMPAT_VERSION) {
- debug_log(LOG_TYPE_BATMAN, "Drop packet: incompatible batman version (%i) \n", batman_packet->version);
+ bat_dbg(DBG_BATMAN,
+ "Drop packet: incompatible batman version (%i)\n",
+ batman_packet->version);
return;
}
if (is_my_addr) {
- debug_log(LOG_TYPE_BATMAN, "Drop packet: received my own broadcast (sender: %s) \n", neigh_str);
+ bat_dbg(DBG_BATMAN,
+ "Drop packet: received my own broadcast (sender: %pM)\n",
+ ethhdr->h_source);
return;
}
if (is_broadcast) {
- debug_log(LOG_TYPE_BATMAN, "Drop packet: ignoring all packets with broadcast source addr (sender: %s) \n", neigh_str);
+ bat_dbg(DBG_BATMAN, "Drop packet: ignoring all packets with broadcast source addr (sender: %pM) \n", ethhdr->h_source);
return;
}
if (is_my_orig) {
+ TYPE_OF_WORD *word;
+ int offset;
+
orig_neigh_node = get_orig_node(ethhdr->h_source);
- /* neighbour has to indicate direct link and it has to come via the corresponding interface */
- /* if received seqno equals last send seqno save new seqno for bidirectional check */
- if (has_directlink_flag && compare_orig(if_incoming->net_dev->dev_addr, batman_packet->orig) &&
- (batman_packet->seqno - if_incoming_seqno + 2 == 0)) {
- bit_mark((TYPE_OF_WORD *)&(orig_neigh_node->bcast_own[if_incoming->if_num * NUM_WORDS]), 0);
- orig_neigh_node->bcast_own_sum[if_incoming->if_num] = bit_packet_count((TYPE_OF_WORD *)&(orig_neigh_node->bcast_own[if_incoming->if_num * NUM_WORDS]));
+ if (!orig_neigh_node)
+ return;
+
+ /* neighbor has to indicate direct link and it has to
+ * come via the corresponding interface */
+ /* if received seqno equals last send seqno save new
+ * seqno for bidirectional check */
+ if (has_directlink_flag &&
+ compare_orig(if_incoming->net_dev->dev_addr,
+ batman_packet->orig) &&
+ (batman_packet->seqno - if_incoming_seqno + 2 == 0)) {
+ offset = if_incoming->if_num * NUM_WORDS;
+ word = &(orig_neigh_node->bcast_own[offset]);
+ bit_mark(word, 0);
+ orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
+ bit_packet_count(word);
}
- debug_log(LOG_TYPE_BATMAN, "Drop packet: originator packet from myself (via neighbour) \n");
+ bat_dbg(DBG_BATMAN, "Drop packet: originator packet from myself (via neighbor) \n");
return;
}
if (batman_packet->tq == 0) {
count_real_packets(ethhdr, batman_packet, if_incoming);
- debug_log(LOG_TYPE_BATMAN, "Drop packet: originator packet with tq equal 0 \n");
+ bat_dbg(DBG_BATMAN, "Drop packet: originator packet with tq equal 0 \n");
return;
}
if (is_my_oldorig) {
- debug_log(LOG_TYPE_BATMAN, "Drop packet: ignoring all rebroadcast echos (sender: %s) \n", neigh_str);
+ bat_dbg(DBG_BATMAN, "Drop packet: ignoring all rebroadcast echos (sender: %pM) \n", ethhdr->h_source);
return;
}
@@ -504,507 +477,502 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_pack
return;
/* avoid temporary routing loops */
- if ((orig_node->router) && (orig_node->router->orig_node->router) &&
- (compare_orig(orig_node->router->addr, batman_packet->prev_sender)) &&
+ if ((orig_node->router) &&
+ (orig_node->router->orig_node->router) &&
+ (compare_orig(orig_node->router->addr,
+ batman_packet->prev_sender)) &&
!(compare_orig(batman_packet->orig, batman_packet->prev_sender)) &&
- (compare_orig(orig_node->router->addr, orig_node->router->orig_node->router->addr))) {
- debug_log(LOG_TYPE_BATMAN, "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %s) \n", neigh_str);
+ (compare_orig(orig_node->router->addr,
+ orig_node->router->orig_node->router->addr))) {
+ bat_dbg(DBG_BATMAN, "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM) \n", ethhdr->h_source);
return;
}
- /* if sender is a direct neighbor the sender mac equals originator mac */
- orig_neigh_node = (is_single_hop_neigh ? orig_node : get_orig_node(ethhdr->h_source));
+ /* if sender is a direct neighbor the sender mac equals
+ * originator mac */
+ orig_neigh_node = (is_single_hop_neigh ?
+ orig_node : get_orig_node(ethhdr->h_source));
if (orig_neigh_node == NULL)
return;
- /* drop packet if sender is not a direct neighbor and if we don't route towards it */
- if (!is_single_hop_neigh && (orig_neigh_node->router == NULL)) {
- debug_log(LOG_TYPE_BATMAN, "Drop packet: OGM via unknown neighbor! \n");
+ /* drop packet if sender is not a direct neighbor and if we
+ * don't route towards it */
+ if (!is_single_hop_neigh &&
+ (orig_neigh_node->router == NULL)) {
+ bat_dbg(DBG_BATMAN, "Drop packet: OGM via unknown neighbor!\n");
return;
}
- is_bidirectional = isBidirectionalNeigh(orig_node, orig_neigh_node, batman_packet, if_incoming);
+ is_bidirectional = isBidirectionalNeigh(orig_node, orig_neigh_node,
+ batman_packet, if_incoming);
- /* update ranking if it is not a duplicate or has the same seqno and similar ttl as the non-duplicate */
- if (is_bidirectional && (!is_duplicate ||
- ((orig_node->last_real_seqno == batman_packet->seqno) &&
- (orig_node->last_ttl - 3 <= batman_packet->ttl))))
- update_orig(orig_node, ethhdr, batman_packet, if_incoming, hna_buff, hna_buff_len, is_duplicate);
+ /* update ranking if it is not a duplicate or has the same
+ * seqno and similar ttl as the non-duplicate */
+ if (is_bidirectional &&
+ (!is_duplicate ||
+ ((orig_node->last_real_seqno == batman_packet->seqno) &&
+ (orig_node->last_ttl - 3 <= batman_packet->ttl))))
+ update_orig(orig_node, ethhdr, batman_packet,
+ if_incoming, hna_buff, hna_buff_len, is_duplicate);
- /* is single hop (direct) neighbour */
+ /* is single hop (direct) neighbor */
if (is_single_hop_neigh) {
/* mark direct link on incoming interface */
- schedule_forward_packet(orig_node, ethhdr, batman_packet, 1, hna_buff_len, if_incoming);
+ schedule_forward_packet(orig_node, ethhdr, batman_packet,
+ 1, hna_buff_len, if_incoming);
- debug_log(LOG_TYPE_BATMAN, "Forwarding packet: rebroadcast neighbour packet with direct link flag \n");
+ bat_dbg(DBG_BATMAN, "Forwarding packet: rebroadcast neighbor packet with direct link flag\n");
return;
}
/* multihop originator */
if (!is_bidirectional) {
- debug_log(LOG_TYPE_BATMAN, "Drop packet: not received via bidirectional link\n");
+ bat_dbg(DBG_BATMAN,
+ "Drop packet: not received via bidirectional link\n");
return;
}
if (is_duplicate) {
- debug_log(LOG_TYPE_BATMAN, "Drop packet: duplicate packet received\n");
+ bat_dbg(DBG_BATMAN, "Drop packet: duplicate packet received\n");
return;
}
- debug_log(LOG_TYPE_BATMAN, "Forwarding packet: rebroadcast originator packet \n");
- schedule_forward_packet(orig_node, ethhdr, batman_packet, 0, hna_buff_len, if_incoming);
+ bat_dbg(DBG_BATMAN,
+ "Forwarding packet: rebroadcast originator packet\n");
+ schedule_forward_packet(orig_node, ethhdr, batman_packet,
+ 0, hna_buff_len, if_incoming);
}
-void purge_orig(struct work_struct *work)
+int recv_bat_packet(struct sk_buff *skb,
+ struct batman_if *batman_if)
{
- struct list_head *list_pos, *list_pos_tmp;
- struct hash_it_t *hashit = NULL;
- struct orig_node *orig_node;
- struct neigh_node *neigh_node, *best_neigh_node;
- char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN], neigh_purged;
-
- spin_lock(&orig_hash_lock);
-
- /* for all origins... */
- while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
-
- orig_node = hashit->bucket->data;
- addr_to_string(orig_str, orig_node->orig);
-
- if (time_after(jiffies, orig_node->last_valid + ((2 * PURGE_TIMEOUT * HZ) / 1000))) {
-
- debug_log(LOG_TYPE_BATMAN, "Originator timeout: originator %s, last_valid %u \n", orig_str, (orig_node->last_valid / HZ));
-
- hash_remove_bucket(orig_hash, hashit);
- free_orig_node(orig_node);
-
- } else {
-
- best_neigh_node = NULL;
- neigh_purged = 0;
-
- /* for all neighbours towards this originator ... */
- list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
- neigh_node = list_entry(list_pos, struct neigh_node, list);
-
- if (time_after(jiffies, neigh_node->last_valid + ((PURGE_TIMEOUT * HZ) / 1000))) {
-
- addr_to_string(neigh_str, neigh_node->addr);
- debug_log(LOG_TYPE_BATMAN, "Neighbour timeout: originator %s, neighbour: %s, last_valid %u \n", orig_str, neigh_str, (neigh_node->last_valid / HZ));
-
- neigh_purged = 1;
- list_del(list_pos);
- kfree(neigh_node);
-
- } else {
-
- if ((best_neigh_node == NULL) || (neigh_node->tq_avg > best_neigh_node->tq_avg))
- best_neigh_node = neigh_node;
-
- }
-
- }
+ struct ethhdr *ethhdr;
+ unsigned long flags;
+
+ /* drop packet if it has not necessary minimum size */
+ if (skb_headlen(skb) < sizeof(struct batman_packet))
+ return NET_RX_DROP;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ /* packet with broadcast indication but unicast recipient */
+ if (!is_bcast(ethhdr->h_dest))
+ return NET_RX_DROP;
+
+ /* packet with broadcast sender address */
+ if (is_bcast(ethhdr->h_source))
+ return NET_RX_DROP;
+
+ spin_lock_irqsave(&orig_hash_lock, flags);
+ /* TODO: we use headlen instead of "length", because
+ * only this data is paged in. */
+ /* TODO: is another skb_copy needed here? there will be
+ * written on the data, but nobody (?) should further use
+ * this data */
+ receive_aggr_bat_packet(ethhdr,
+ skb->data,
+ skb_headlen(skb),
+ batman_if);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ kfree_skb(skb);
+ return NET_RX_SUCCESS;
+}
- if (neigh_purged)
- update_routes(orig_node, best_neigh_node, orig_node->hna_buff, orig_node->hna_buff_len);
+static int recv_my_icmp_packet(struct sk_buff *skb)
+{
+ struct orig_node *orig_node;
+ struct icmp_packet *icmp_packet;
+ struct ethhdr *ethhdr;
+ struct sk_buff *skb_old;
+ struct batman_if *batman_if;
+ int ret;
+ unsigned long flags;
+ uint8_t dstaddr[ETH_ALEN];
- }
+ icmp_packet = (struct icmp_packet *) skb->data;
+ ethhdr = (struct ethhdr *) skb_mac_header(skb);
+ /* add data to device queue */
+ if (icmp_packet->msg_type != ECHO_REQUEST) {
+ bat_device_receive_packet(icmp_packet);
+ return NET_RX_DROP;
}
- spin_unlock(&orig_hash_lock);
+ /* answer echo request (ping) */
+ /* get routing information */
+ spin_lock_irqsave(&orig_hash_lock, flags);
+ orig_node = ((struct orig_node *)hash_find(orig_hash,
+ icmp_packet->orig));
+ ret = NET_RX_DROP;
+
+ if ((orig_node != NULL) &&
+ (orig_node->batman_if != NULL) &&
+ (orig_node->router != NULL)) {
+
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
+ batman_if = orig_node->batman_if;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ /* create a copy of the skb, if needed, to modify it. */
+ skb_old = NULL;
+ if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) {
+ skb_old = skb;
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb)
+ return NET_RX_DROP;
+ icmp_packet = (struct icmp_packet *) skb->data;
+ kfree_skb(skb_old);
+ }
- start_purge_timer();
-}
+ memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
+ memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN);
+ icmp_packet->msg_type = ECHO_REPLY;
+ icmp_packet->ttl = TTL;
-static int receive_raw_packet(struct socket *raw_sock, unsigned char *packet_buff, int packet_buff_len)
-{
- struct kvec iov;
- struct msghdr msg;
+ send_skb_packet(skb, batman_if, dstaddr);
+ ret = NET_RX_SUCCESS;
- iov.iov_base = packet_buff;
- iov.iov_len = packet_buff_len;
+ } else
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
- msg.msg_flags = MSG_DONTWAIT; /* non-blocking */
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_control = NULL;
-
- return kernel_recvmsg(raw_sock, &msg, &iov, 1, packet_buff_len, MSG_DONTWAIT);
+ return ret;
}
-int packet_recv_thread(void *data)
+static int recv_icmp_ttl_exceeded(struct sk_buff *skb)
{
- struct batman_if *batman_if;
- struct ethhdr *ethhdr;
- struct batman_packet *batman_packet;
- struct unicast_packet *unicast_packet;
- struct bcast_packet *bcast_packet;
- struct icmp_packet *icmp_packet;
- struct vis_packet *vis_packet;
struct orig_node *orig_node;
- unsigned char *packet_buff, src_str[ETH_STR_LEN], dst_str[ETH_STR_LEN];
- int vis_info_len;
- int result;
-
- atomic_set(&data_ready_cond, 0);
- atomic_set(&exit_cond, 0);
- packet_buff = kmalloc(PACKBUFF_SIZE, GFP_KERNEL);
- if (!packet_buff) {
- debug_log(LOG_TYPE_CRIT, "Could allocate memory for the packet buffer. :(\n");
- return -1;
+ struct icmp_packet *icmp_packet;
+ struct ethhdr *ethhdr;
+ struct sk_buff *skb_old;
+ struct batman_if *batman_if;
+ int ret;
+ unsigned long flags;
+ uint8_t dstaddr[ETH_ALEN];
+
+ icmp_packet = (struct icmp_packet *)skb->data;
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ /* send TTL exceeded if packet is an echo request (traceroute) */
+ if (icmp_packet->msg_type != ECHO_REQUEST) {
+ printk(KERN_WARNING "batman-adv:Warning - can't forward icmp packet from %pM to %pM: ttl exceeded\n",
+ icmp_packet->orig, icmp_packet->dst);
+ return NET_RX_DROP;
}
- while ((!kthread_should_stop()) && (!atomic_read(&exit_cond))) {
-
- wait_event_interruptible(thread_wait, (atomic_read(&data_ready_cond) || atomic_read(&exit_cond)));
-
- atomic_set(&data_ready_cond, 0);
-
- if (kthread_should_stop() || atomic_read(&exit_cond))
- break;
-
- /* we only want to safely traverse the list, hard-interfaces
- * won't be deleted anyway as long as this thread runs. */
-
- rcu_read_lock();
- list_for_each_entry_rcu(batman_if, &if_list, list) {
- rcu_read_unlock();
-
- result = -1;
-
- while (1) {
- if (batman_if->if_active != IF_ACTIVE) {
- if (batman_if->if_active != IF_TO_BE_ACTIVATED)
- debug_log(LOG_TYPE_NOTICE,
- "Could not read from deactivated interface %s!\n",
- batman_if->dev);
-
- if (batman_if->raw_sock)
- receive_raw_packet(batman_if->raw_sock, packet_buff, PACKBUFF_SIZE);
- result = 0;
- break;
- }
-
- result = receive_raw_packet(batman_if->raw_sock, packet_buff, PACKBUFF_SIZE);
- if (result <= 0)
- break;
-
- if (result < sizeof(struct ethhdr) + 2)
- continue;
-
- ethhdr = (struct ethhdr *)packet_buff;
- batman_packet = (struct batman_packet *)(packet_buff + sizeof(struct ethhdr));
-
- if (batman_packet->version != COMPAT_VERSION) {
- debug_log(LOG_TYPE_BATMAN, "Drop packet: incompatible batman version (%i) \n", batman_packet->version);
- continue;
- }
-
- switch (batman_packet->packet_type) {
- /* batman originator packet */
- case BAT_PACKET:
- /* packet with broadcast indication but unicast recipient */
- if (!is_bcast(ethhdr->h_dest))
- continue;
-
- /* packet with broadcast sender address */
- if (is_bcast(ethhdr->h_source))
- continue;
-
- /* drop packet if it has not at least one batman packet as payload */
- if (result < sizeof(struct ethhdr) + sizeof(struct batman_packet))
- continue;
-
- spin_lock(&orig_hash_lock);
- receive_aggr_bat_packet(ethhdr,
- packet_buff + sizeof(struct ethhdr),
- result - sizeof(struct ethhdr),
- batman_if);
- spin_unlock(&orig_hash_lock);
-
- break;
-
- /* batman icmp packet */
- case BAT_ICMP:
- /* packet with unicast indication but broadcast recipient */
- if (is_bcast(ethhdr->h_dest))
- continue;
-
- /* packet with broadcast sender address */
- if (is_bcast(ethhdr->h_source))
- continue;
-
- /* not for me */
- if (!is_my_mac(ethhdr->h_dest))
- continue;
-
- /* drop packet if it has not necessary minimum size */
- if (result < sizeof(struct ethhdr) + sizeof(struct icmp_packet))
- continue;
-
- icmp_packet = (struct icmp_packet *)(packet_buff + sizeof(struct ethhdr));
-
- /* packet for me */
- if (is_my_mac(icmp_packet->dst)) {
-
- /* add data to device queue */
- if (icmp_packet->msg_type != ECHO_REQUEST) {
- bat_device_receive_packet(icmp_packet);
- continue;
- }
-
- /* answer echo request (ping) */
- /* get routing information */
- spin_lock(&orig_hash_lock);
- orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->orig));
-
- if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) {
-
- memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
- memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN);
- icmp_packet->msg_type = ECHO_REPLY;
- icmp_packet->ttl = TTL;
-
- send_raw_packet(packet_buff + sizeof(struct ethhdr),
- result - sizeof(struct ethhdr),
- orig_node->batman_if,
- orig_node->router->addr);
-
- }
-
- spin_unlock(&orig_hash_lock);
- continue;
-
- }
-
- /* TTL exceeded */
- if (icmp_packet->ttl < 2) {
-
- addr_to_string(src_str, icmp_packet->orig);
- addr_to_string(dst_str, icmp_packet->dst);
-
- debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str);
-
- /* send TTL exceeded if packet is an echo request (traceroute) */
- if (icmp_packet->msg_type != ECHO_REQUEST)
- continue;
-
- /* get routing information */
- spin_lock(&orig_hash_lock);
- orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->orig));
-
- if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) {
-
- memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
- memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN);
- icmp_packet->msg_type = TTL_EXCEEDED;
- icmp_packet->ttl = TTL;
-
- send_raw_packet(packet_buff + sizeof(struct ethhdr),
- result - sizeof(struct ethhdr),
- orig_node->batman_if,
- orig_node->router->addr);
+ /* get routing information */
+ spin_lock_irqsave(&orig_hash_lock, flags);
+ orig_node = ((struct orig_node *)
+ hash_find(orig_hash, icmp_packet->orig));
+ ret = NET_RX_DROP;
+
+ if ((orig_node != NULL) &&
+ (orig_node->batman_if != NULL) &&
+ (orig_node->router != NULL)) {
+
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
+ batman_if = orig_node->batman_if;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ /* create a copy of the skb, if needed, to modify it. */
+ if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) {
+ skb_old = skb;
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb)
+ return NET_RX_DROP;
+ icmp_packet = (struct icmp_packet *) skb->data;
+ kfree_skb(skb_old);
+ }
- }
+ memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
+ memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN);
+ icmp_packet->msg_type = TTL_EXCEEDED;
+ icmp_packet->ttl = TTL;
- spin_unlock(&orig_hash_lock);
- continue;
+ send_skb_packet(skb, batman_if, dstaddr);
+ ret = NET_RX_SUCCESS;
- }
+ } else
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
- /* get routing information */
- spin_lock(&orig_hash_lock);
- orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->dst));
+ return ret;
+}
- if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) {
- /* decrement ttl */
- icmp_packet->ttl--;
+int recv_icmp_packet(struct sk_buff *skb)
+{
+ struct icmp_packet *icmp_packet;
+ struct ethhdr *ethhdr;
+ struct orig_node *orig_node;
+ struct sk_buff *skb_old;
+ struct batman_if *batman_if;
+ int hdr_size = sizeof(struct icmp_packet);
+ int ret;
+ unsigned long flags;
+ uint8_t dstaddr[ETH_ALEN];
+
+ /* drop packet if it has not necessary minimum size */
+ if (skb_headlen(skb) < hdr_size)
+ return NET_RX_DROP;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ /* packet with unicast indication but broadcast recipient */
+ if (is_bcast(ethhdr->h_dest))
+ return NET_RX_DROP;
+
+ /* packet with broadcast sender address */
+ if (is_bcast(ethhdr->h_source))
+ return NET_RX_DROP;
+
+ /* not for me */
+ if (!is_my_mac(ethhdr->h_dest))
+ return NET_RX_DROP;
+
+ icmp_packet = (struct icmp_packet *) skb->data;
+
+ /* packet for me */
+ if (is_my_mac(icmp_packet->dst))
+ return recv_my_icmp_packet(skb);
+
+ /* TTL exceeded */
+ if (icmp_packet->ttl < 2)
+ return recv_icmp_ttl_exceeded(skb);
+
+ ret = NET_RX_DROP;
+
+ /* get routing information */
+ spin_lock_irqsave(&orig_hash_lock, flags);
+ orig_node = ((struct orig_node *)
+ hash_find(orig_hash, icmp_packet->dst));
+
+ if ((orig_node != NULL) &&
+ (orig_node->batman_if != NULL) &&
+ (orig_node->router != NULL)) {
+
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
+ batman_if = orig_node->batman_if;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ /* create a copy of the skb, if needed, to modify it. */
+ if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) {
+ skb_old = skb;
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb)
+ return NET_RX_DROP;
+ icmp_packet = (struct icmp_packet *) skb->data;
+ kfree_skb(skb_old);
+ }
- /* route it */
- send_raw_packet(packet_buff + sizeof(struct ethhdr),
- result - sizeof(struct ethhdr),
- orig_node->batman_if,
- orig_node->router->addr);
- }
+ /* decrement ttl */
+ icmp_packet->ttl--;
- spin_unlock(&orig_hash_lock);
- break;
+ /* route it */
+ send_skb_packet(skb, batman_if, dstaddr);
+ ret = NET_RX_SUCCESS;
- /* unicast packet */
- case BAT_UNICAST:
- /* packet with unicast indication but broadcast recipient */
- if (is_bcast(ethhdr->h_dest))
- continue;
+ } else
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
- /* packet with broadcast sender address */
- if (is_bcast(ethhdr->h_source))
- continue;
+ return ret;
+}
- /* not for me */
- if (!is_my_mac(ethhdr->h_dest))
- continue;
+int recv_unicast_packet(struct sk_buff *skb)
+{
+ struct unicast_packet *unicast_packet;
+ struct orig_node *orig_node;
+ struct ethhdr *ethhdr;
+ struct batman_if *batman_if;
+ struct sk_buff *skb_old;
+ uint8_t dstaddr[ETH_ALEN];
+ int hdr_size = sizeof(struct unicast_packet);
+ int ret;
+ unsigned long flags;
- /* drop packet if it has not necessary minimum size */
- if (result < sizeof(struct ethhdr) + sizeof(struct unicast_packet))
- continue;
+ /* drop packet if it has not necessary minimum size */
+ if (skb_headlen(skb) < hdr_size)
+ return NET_RX_DROP;
- unicast_packet = (struct unicast_packet *)(packet_buff + sizeof(struct ethhdr));
+ ethhdr = (struct ethhdr *) skb_mac_header(skb);
- /* packet for me */
- if (is_my_mac(unicast_packet->dest)) {
+ /* packet with unicast indication but broadcast recipient */
+ if (is_bcast(ethhdr->h_dest))
+ return NET_RX_DROP;
- interface_rx(soft_device, packet_buff + sizeof(struct ethhdr) + sizeof(struct unicast_packet), result - sizeof(struct ethhdr) - sizeof(struct unicast_packet));
- continue;
+ /* packet with broadcast sender address */
+ if (is_bcast(ethhdr->h_source))
+ return NET_RX_DROP;
- }
+ /* not for me */
+ if (!is_my_mac(ethhdr->h_dest))
+ return NET_RX_DROP;
- /* TTL exceeded */
- if (unicast_packet->ttl < 2) {
- addr_to_string(src_str, ((struct ethhdr *)(unicast_packet + 1))->h_source);
- addr_to_string(dst_str, unicast_packet->dest);
+ unicast_packet = (struct unicast_packet *) skb->data;
- debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str);
- continue;
- }
+ /* packet for me */
+ if (is_my_mac(unicast_packet->dest)) {
+ interface_rx(skb, hdr_size);
+ return NET_RX_SUCCESS;
+ }
- /* get routing information */
- spin_lock(&orig_hash_lock);
- orig_node = ((struct orig_node *)hash_find(orig_hash, unicast_packet->dest));
+ /* TTL exceeded */
+ if (unicast_packet->ttl < 2) {
+ printk(KERN_WARNING "batman-adv:Warning - can't forward unicast packet from %pM to %pM: ttl exceeded\n",
+ ethhdr->h_source, unicast_packet->dest);
+ return NET_RX_DROP;
+ }
- if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) {
- /* decrement ttl */
- unicast_packet->ttl--;
+ ret = NET_RX_DROP;
+ /* get routing information */
+ spin_lock_irqsave(&orig_hash_lock, flags);
+ orig_node = ((struct orig_node *)
+ hash_find(orig_hash, unicast_packet->dest));
+
+ if ((orig_node != NULL) &&
+ (orig_node->batman_if != NULL) &&
+ (orig_node->router != NULL)) {
+
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
+ batman_if = orig_node->batman_if;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ /* create a copy of the skb, if needed, to modify it. */
+ if (!skb_clone_writable(skb, sizeof(struct unicast_packet))) {
+ skb_old = skb;
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb)
+ return NET_RX_DROP;
+ unicast_packet = (struct unicast_packet *) skb->data;
+ kfree_skb(skb_old);
+ }
+ /* decrement ttl */
+ unicast_packet->ttl--;
- /* route it */
- send_raw_packet(packet_buff + sizeof(struct ethhdr),
- result - sizeof(struct ethhdr),
- orig_node->batman_if,
- orig_node->router->addr);
- }
+ /* route it */
+ send_skb_packet(skb, batman_if, dstaddr);
+ ret = NET_RX_SUCCESS;
- spin_unlock(&orig_hash_lock);
- break;
+ } else
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
- /* broadcast packet */
- case BAT_BCAST:
- /* packet with broadcast indication but unicast recipient */
- if (!is_bcast(ethhdr->h_dest))
- continue;
+ return ret;
+}
- /* packet with broadcast sender address */
- if (is_bcast(ethhdr->h_source))
- continue;
- /* drop packet if it has not necessary minimum size */
- if (result < sizeof(struct ethhdr) + sizeof(struct bcast_packet))
- continue;
+int recv_bcast_packet(struct sk_buff *skb)
+{
+ struct orig_node *orig_node;
+ struct bcast_packet *bcast_packet;
+ struct ethhdr *ethhdr;
+ int hdr_size = sizeof(struct bcast_packet);
+ unsigned long flags;
- /* ignore broadcasts sent by myself */
- if (is_my_mac(ethhdr->h_source))
- continue;
+ /* drop packet if it has not necessary minimum size */
+ if (skb_headlen(skb) < hdr_size)
+ return NET_RX_DROP;
- bcast_packet = (struct bcast_packet *)(packet_buff + sizeof(struct ethhdr));
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
- /* ignore broadcasts originated by myself */
- if (is_my_mac(bcast_packet->orig))
- continue;
+ /* packet with broadcast indication but unicast recipient */
+ if (!is_bcast(ethhdr->h_dest))
+ return NET_RX_DROP;
- spin_lock(&orig_hash_lock);
- orig_node = ((struct orig_node *)hash_find(orig_hash, bcast_packet->orig));
+ /* packet with broadcast sender address */
+ if (is_bcast(ethhdr->h_source))
+ return NET_RX_DROP;
- if (orig_node == NULL) {
- spin_unlock(&orig_hash_lock);
- continue;
- }
+ /* ignore broadcasts sent by myself */
+ if (is_my_mac(ethhdr->h_source))
+ return NET_RX_DROP;
- /* check flood history */
- if (get_bit_status(orig_node->bcast_bits, orig_node->last_bcast_seqno, ntohs(bcast_packet->seqno))) {
- spin_unlock(&orig_hash_lock);
- continue;
- }
+ bcast_packet = (struct bcast_packet *) skb->data;
- /* mark broadcast in flood history */
- if (bit_get_packet(orig_node->bcast_bits, ntohs(bcast_packet->seqno) - orig_node->last_bcast_seqno, 1))
- orig_node->last_bcast_seqno = ntohs(bcast_packet->seqno);
+ /* ignore broadcasts originated by myself */
+ if (is_my_mac(bcast_packet->orig))
+ return NET_RX_DROP;
- spin_unlock(&orig_hash_lock);
+ spin_lock_irqsave(&orig_hash_lock, flags);
+ orig_node = ((struct orig_node *)
+ hash_find(orig_hash, bcast_packet->orig));
- /* broadcast for me */
- interface_rx(soft_device, packet_buff + sizeof(struct ethhdr) + sizeof(struct bcast_packet), result - sizeof(struct ethhdr) - sizeof(struct bcast_packet));
+ if (orig_node == NULL) {
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+ return NET_RX_DROP;
+ }
- /* rebroadcast packet */
- add_bcast_packet_to_list(packet_buff + sizeof(struct ethhdr),
- result - sizeof(struct ethhdr));
+ /* check flood history */
+ if (get_bit_status(orig_node->bcast_bits,
+ orig_node->last_bcast_seqno,
+ ntohs(bcast_packet->seqno))) {
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+ return NET_RX_DROP;
+ }
- break;
+ /* mark broadcast in flood history */
+ if (bit_get_packet(orig_node->bcast_bits,
+ ntohs(bcast_packet->seqno) -
+ orig_node->last_bcast_seqno, 1))
+ orig_node->last_bcast_seqno = ntohs(bcast_packet->seqno);
- /* vis packet */
- case BAT_VIS:
- /* drop if too short. */
- if (result < sizeof(struct ethhdr) + sizeof(struct vis_packet))
- continue;
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
- /* not for me */
- if (!is_my_mac(ethhdr->h_dest))
- continue;
+ /* rebroadcast packet */
+ add_bcast_packet_to_list(skb);
- vis_packet = (struct vis_packet *)(packet_buff + sizeof(struct ethhdr));
- vis_info_len = result - sizeof(struct ethhdr) - sizeof(struct vis_packet);
+ /* broadcast for me */
+ interface_rx(skb, hdr_size);
- /* ignore own packets */
- if (is_my_mac(vis_packet->vis_orig))
- continue;
+ return NET_RX_SUCCESS;
+}
- if (is_my_mac(vis_packet->sender_orig))
- continue;
+int recv_vis_packet(struct sk_buff *skb)
+{
+ struct vis_packet *vis_packet;
+ struct ethhdr *ethhdr;
+ int hdr_size = sizeof(struct vis_packet);
- switch (vis_packet->vis_type) {
- case VIS_TYPE_SERVER_SYNC:
- receive_server_sync_packet(vis_packet, vis_info_len);
- break;
+ if (skb_headlen(skb) < hdr_size)
+ return NET_RX_DROP;
- case VIS_TYPE_CLIENT_UPDATE:
- receive_client_update_packet(vis_packet, vis_info_len);
- break;
+ vis_packet = (struct vis_packet *) skb->data;
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
- default: /* ignore unknown packet */
- break;
- }
+ /* not for me */
+ if (!is_my_mac(ethhdr->h_dest))
+ return NET_RX_DROP;
- break;
- }
+ /* ignore own packets */
+ if (is_my_mac(vis_packet->vis_orig))
+ return NET_RX_DROP;
- }
+ if (is_my_mac(vis_packet->sender_orig))
+ return NET_RX_DROP;
- if ((result < 0) && (result != -EAGAIN))
- debug_log(LOG_TYPE_CRIT, "Could not receive packet from interface %s: %i\n", batman_if->dev, result);
+ switch (vis_packet->vis_type) {
+ case VIS_TYPE_SERVER_SYNC:
+ /* TODO: handle fragmented skbs properly */
+ receive_server_sync_packet(vis_packet, skb_headlen(skb));
+ break;
- /* lock for the next iteration */
- rcu_read_lock();
- }
- rcu_read_unlock();
+ case VIS_TYPE_CLIENT_UPDATE:
+ /* TODO: handle fragmented skbs properly */
+ receive_client_update_packet(vis_packet, skb_headlen(skb));
+ break;
+ default: /* ignore unknown packet */
+ break;
}
- kfree(packet_buff);
-
- /* do not exit until kthread_stop() is actually called, otherwise it will wait for us
- * forever. */
- while (!kthread_should_stop())
- schedule();
-
- return 0;
-}
-
-void batman_data_ready(struct sock *sk, int len)
-{
- void (*data_ready)(struct sock *, int) = sk->sk_user_data;
-
- data_ready(sk, len);
- atomic_set(&data_ready_cond, 1);
- wake_up_interruptible(&thread_wait);
+ /* We take a copy of the data in the packet, so we should
+ always free the skbuf. */
+ return NET_RX_DROP;
}
-
diff --git a/drivers/staging/batman-adv/routing.h b/drivers/staging/batman-adv/routing.h
index 0123ea86debb..939b8d4f733c 100644
--- a/drivers/staging/batman-adv/routing.h
+++ b/drivers/staging/batman-adv/routing.h
@@ -22,13 +22,18 @@
#include "types.h"
extern wait_queue_head_t thread_wait;
-extern atomic_t exit_cond;
-int originator_init(void);
-void free_orig_node(void *data);
-void originator_free(void);
void slide_own_bcast_window(struct batman_if *batman_if);
-void batman_data_ready(struct sock *sk, int len);
-void purge_orig(struct work_struct *work);
-int packet_recv_thread(void *data);
-void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_packet, unsigned char *hna_buff, int hna_buff_len, struct batman_if *if_incoming);
+void receive_bat_packet(struct ethhdr *ethhdr,
+ struct batman_packet *batman_packet,
+ unsigned char *hna_buff, int hna_buff_len,
+ struct batman_if *if_incoming);
+void update_routes(struct orig_node *orig_node,
+ struct neigh_node *neigh_node,
+ unsigned char *hna_buff, int hna_buff_len);
+int recv_icmp_packet(struct sk_buff *skb);
+int recv_unicast_packet(struct sk_buff *skb);
+int recv_bcast_packet(struct sk_buff *skb);
+int recv_vis_packet(struct sk_buff *skb);
+int recv_bat_packet(struct sk_buff *skb,
+ struct batman_if *batman_if);
diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c
index eb617508cca4..2a9fac8c240e 100644
--- a/drivers/staging/batman-adv/send.c
+++ b/drivers/staging/batman-adv/send.c
@@ -21,16 +21,14 @@
#include "main.h"
#include "send.h"
-#include "log.h"
#include "routing.h"
#include "translation-table.h"
+#include "soft-interface.h"
#include "hard-interface.h"
#include "types.h"
#include "vis.h"
#include "aggregation.h"
-#include "compat.h"
-
/* apply hop penalty for a normal link */
static uint8_t hop_penalty(const uint8_t tq)
{
@@ -59,51 +57,69 @@ static unsigned long forward_send_time(void)
return send_time;
}
-/* sends a raw packet. */
-void send_raw_packet(unsigned char *pack_buff, int pack_buff_len,
- struct batman_if *batman_if, uint8_t *dst_addr)
+/* send out an already prepared packet to the given address via the
+ * specified batman interface */
+int send_skb_packet(struct sk_buff *skb,
+ struct batman_if *batman_if,
+ uint8_t *dst_addr)
{
struct ethhdr *ethhdr;
- struct sk_buff *skb;
- int retval;
- char *data;
if (batman_if->if_active != IF_ACTIVE)
- return;
+ goto send_skb_err;
+
+ if (unlikely(!batman_if->net_dev))
+ goto send_skb_err;
if (!(batman_if->net_dev->flags & IFF_UP)) {
- debug_log(LOG_TYPE_WARN,
- "Interface %s is not up - can't send packet via that interface (IF_TO_BE_DEACTIVATED was here) !\n",
- batman_if->dev);
- return;
+ printk(KERN_WARNING
+ "batman-adv:Interface %s is not up - can't send packet via that interface!\n",
+ batman_if->dev);
+ goto send_skb_err;
}
- skb = dev_alloc_skb(pack_buff_len + sizeof(struct ethhdr));
- if (!skb)
- return;
- data = skb_put(skb, pack_buff_len + sizeof(struct ethhdr));
+ /* push to the ethernet header. */
+ if (my_skb_push(skb, sizeof(struct ethhdr)) < 0)
+ goto send_skb_err;
- memcpy(data + sizeof(struct ethhdr), pack_buff, pack_buff_len);
+ skb_reset_mac_header(skb);
- ethhdr = (struct ethhdr *) data;
+ ethhdr = (struct ethhdr *) skb_mac_header(skb);
memcpy(ethhdr->h_source, batman_if->net_dev->dev_addr, ETH_ALEN);
memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
ethhdr->h_proto = __constant_htons(ETH_P_BATMAN);
- skb_reset_mac_header(skb);
skb_set_network_header(skb, ETH_HLEN);
skb->priority = TC_PRIO_CONTROL;
skb->protocol = __constant_htons(ETH_P_BATMAN);
+
skb->dev = batman_if->net_dev;
/* dev_queue_xmit() returns a negative result on error. However on
* congestion and traffic shaping, it drops and returns NET_XMIT_DROP
* (which is > 0). This will not be treated as an error. */
- retval = dev_queue_xmit(skb);
- if (retval < 0)
- debug_log(LOG_TYPE_CRIT,
- "Can't write to raw socket (IF_TO_BE_DEACTIVATED was here): %i\n",
- retval);
+
+ return dev_queue_xmit(skb);
+send_skb_err:
+ kfree_skb(skb);
+ return NET_XMIT_DROP;
+}
+
+/* sends a raw packet. */
+void send_raw_packet(unsigned char *pack_buff, int pack_buff_len,
+ struct batman_if *batman_if, uint8_t *dst_addr)
+{
+ struct sk_buff *skb;
+ char *data;
+
+ skb = dev_alloc_skb(pack_buff_len + sizeof(struct ethhdr));
+ if (!skb)
+ return;
+ data = skb_put(skb, pack_buff_len + sizeof(struct ethhdr));
+ memcpy(data + sizeof(struct ethhdr), pack_buff, pack_buff_len);
+ /* pull back to the batman "network header" */
+ skb_pull(skb, sizeof(struct ethhdr));
+ send_skb_packet(skb, batman_if, dst_addr);
}
/* Send a packet to a given interface */
@@ -114,7 +130,6 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
uint8_t packet_num;
int16_t buff_pos;
struct batman_packet *batman_packet;
- char orig_str[ETH_STR_LEN];
if (batman_if->if_active != IF_ACTIVE)
return;
@@ -136,19 +151,18 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
else
batman_packet->flags &= ~DIRECTLINK;
- addr_to_string(orig_str, batman_packet->orig);
fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ?
"Sending own" :
"Forwarding"));
- debug_log(LOG_TYPE_BATMAN,
- "%s %spacket (originator %s, seqno %d, TQ %d, TTL %d, IDF %s) on interface %s [%s]\n",
- fwd_str,
- (packet_num > 0 ? "aggregated " : ""),
- orig_str, ntohs(batman_packet->seqno),
- batman_packet->tq, batman_packet->ttl,
- (batman_packet->flags & DIRECTLINK ?
- "on" : "off"),
- batman_if->dev, batman_if->addr_str);
+ bat_dbg(DBG_BATMAN,
+ "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d, IDF %s) on interface %s [%s]\n",
+ fwd_str,
+ (packet_num > 0 ? "aggregated " : ""),
+ batman_packet->orig, ntohs(batman_packet->seqno),
+ batman_packet->tq, batman_packet->ttl,
+ (batman_packet->flags & DIRECTLINK ?
+ "on" : "off"),
+ batman_if->dev, batman_if->addr_str);
buff_pos += sizeof(struct batman_packet) +
(batman_packet->num_hna * ETH_ALEN);
@@ -168,32 +182,28 @@ static void send_packet(struct forw_packet *forw_packet)
struct batman_if *batman_if;
struct batman_packet *batman_packet =
(struct batman_packet *)(forw_packet->packet_buff);
- char orig_str[ETH_STR_LEN];
unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0);
if (!forw_packet->if_incoming) {
- debug_log(LOG_TYPE_CRIT,
- "Error - can't forward packet: incoming iface not specified\n");
+ printk(KERN_ERR "batman-adv: Error - can't forward packet: incoming iface not specified\n");
return;
}
if (forw_packet->if_incoming->if_active != IF_ACTIVE)
return;
- addr_to_string(orig_str, batman_packet->orig);
-
/* multihomed peer assumed */
/* non-primary OGMs are only broadcasted on their interface */
if ((directlink && (batman_packet->ttl == 1)) ||
(forw_packet->own && (forw_packet->if_incoming->if_num > 0))) {
/* FIXME: what about aggregated packets ? */
- debug_log(LOG_TYPE_BATMAN,
- "%s packet (originator %s, seqno %d, TTL %d) on interface %s [%s]\n",
- (forw_packet->own ? "Sending own" : "Forwarding"),
- orig_str, ntohs(batman_packet->seqno),
- batman_packet->ttl, forw_packet->if_incoming->dev,
- forw_packet->if_incoming->addr_str);
+ bat_dbg(DBG_BATMAN,
+ "%s packet (originator %pM, seqno %d, TTL %d) on interface %s [%s]\n",
+ (forw_packet->own ? "Sending own" : "Forwarding"),
+ batman_packet->orig, ntohs(batman_packet->seqno),
+ batman_packet->ttl, forw_packet->if_incoming->dev,
+ forw_packet->if_incoming->addr_str);
send_raw_packet(forw_packet->packet_buff,
forw_packet->packet_len,
@@ -238,6 +248,7 @@ void schedule_own_packet(struct batman_if *batman_if)
{
unsigned long send_time;
struct batman_packet *batman_packet;
+ int vis_server = atomic_read(&vis_mode);
/**
* the interface gets activated here to avoid race conditions between
@@ -262,7 +273,7 @@ void schedule_own_packet(struct batman_if *batman_if)
/* change sequence number to network order */
batman_packet->seqno = htons((uint16_t)atomic_read(&batman_if->seqno));
- if (is_vis_server())
+ if (vis_server == VIS_TYPE_SERVER_SYNC)
batman_packet->flags = VIS_SERVER;
else
batman_packet->flags = 0;
@@ -286,7 +297,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
unsigned long send_time;
if (batman_packet->ttl <= 1) {
- debug_log(LOG_TYPE_BATMAN, "ttl exceeded \n");
+ bat_dbg(DBG_BATMAN, "ttl exceeded \n");
return;
}
@@ -314,9 +325,9 @@ void schedule_forward_packet(struct orig_node *orig_node,
/* apply hop penalty */
batman_packet->tq = hop_penalty(batman_packet->tq);
- debug_log(LOG_TYPE_BATMAN, "Forwarding packet: tq_orig: %i, tq_avg: %i, tq_forw: %i, ttl_orig: %i, ttl_forw: %i \n",
- in_tq, tq_avg, batman_packet->tq, in_ttl - 1,
- batman_packet->ttl);
+ bat_dbg(DBG_BATMAN, "Forwarding packet: tq_orig: %i, tq_avg: %i, tq_forw: %i, ttl_orig: %i, ttl_forw: %i \n",
+ in_tq, tq_avg, batman_packet->tq, in_ttl - 1,
+ batman_packet->ttl);
batman_packet->seqno = htons(batman_packet->seqno);
@@ -333,6 +344,8 @@ void schedule_forward_packet(struct orig_node *orig_node,
static void forw_packet_free(struct forw_packet *forw_packet)
{
+ if (forw_packet->skb)
+ kfree_skb(forw_packet->skb);
kfree(forw_packet->packet_buff);
kfree(forw_packet);
}
@@ -340,12 +353,13 @@ static void forw_packet_free(struct forw_packet *forw_packet)
static void _add_bcast_packet_to_list(struct forw_packet *forw_packet,
unsigned long send_time)
{
+ unsigned long flags;
INIT_HLIST_NODE(&forw_packet->list);
/* add new packet to packet list */
- spin_lock(&forw_bcast_list_lock);
+ spin_lock_irqsave(&forw_bcast_list_lock, flags);
hlist_add_head(&forw_packet->list, &forw_bcast_list);
- spin_unlock(&forw_bcast_list_lock);
+ spin_unlock_irqrestore(&forw_bcast_list_lock, flags);
/* start timer for this packet */
INIT_DELAYED_WORK(&forw_packet->delayed_work,
@@ -354,7 +368,7 @@ static void _add_bcast_packet_to_list(struct forw_packet *forw_packet,
send_time);
}
-void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len)
+void add_bcast_packet_to_list(struct sk_buff *skb)
{
struct forw_packet *forw_packet;
@@ -362,14 +376,16 @@ void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len)
if (!forw_packet)
return;
- forw_packet->packet_buff = kmalloc(packet_len, GFP_ATOMIC);
- if (!forw_packet->packet_buff) {
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb) {
kfree(forw_packet);
return;
}
- forw_packet->packet_len = packet_len;
- memcpy(forw_packet->packet_buff, packet_buff, forw_packet->packet_len);
+ skb_reset_mac_header(skb);
+
+ forw_packet->skb = skb;
+ forw_packet->packet_buff = NULL;
/* how often did we send the bcast packet ? */
forw_packet->num_packets = 0;
@@ -384,16 +400,20 @@ void send_outstanding_bcast_packet(struct work_struct *work)
container_of(work, struct delayed_work, work);
struct forw_packet *forw_packet =
container_of(delayed_work, struct forw_packet, delayed_work);
+ unsigned long flags;
+ struct sk_buff *skb1;
- spin_lock(&forw_bcast_list_lock);
+ spin_lock_irqsave(&forw_bcast_list_lock, flags);
hlist_del(&forw_packet->list);
- spin_unlock(&forw_bcast_list_lock);
+ spin_unlock_irqrestore(&forw_bcast_list_lock, flags);
/* rebroadcast packet */
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
- send_raw_packet(forw_packet->packet_buff,
- forw_packet->packet_len,
+ /* send a copy of the saved skb */
+ skb1 = skb_copy(forw_packet->skb, GFP_ATOMIC);
+ if (skb1)
+ send_skb_packet(skb1,
batman_if, broadcastAddr);
}
rcu_read_unlock();
@@ -415,10 +435,11 @@ void send_outstanding_bat_packet(struct work_struct *work)
container_of(work, struct delayed_work, work);
struct forw_packet *forw_packet =
container_of(delayed_work, struct forw_packet, delayed_work);
+ unsigned long flags;
- spin_lock(&forw_bat_list_lock);
+ spin_lock_irqsave(&forw_bat_list_lock, flags);
hlist_del(&forw_packet->list);
- spin_unlock(&forw_bat_list_lock);
+ spin_unlock_irqrestore(&forw_bat_list_lock, flags);
send_packet(forw_packet);
@@ -438,38 +459,39 @@ void purge_outstanding_packets(void)
{
struct forw_packet *forw_packet;
struct hlist_node *tmp_node, *safe_tmp_node;
+ unsigned long flags;
- debug_log(LOG_TYPE_BATMAN, "purge_outstanding_packets()\n");
+ bat_dbg(DBG_BATMAN, "purge_outstanding_packets()\n");
/* free bcast list */
- spin_lock(&forw_bcast_list_lock);
+ spin_lock_irqsave(&forw_bcast_list_lock, flags);
hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
&forw_bcast_list, list) {
- spin_unlock(&forw_bcast_list_lock);
+ spin_unlock_irqrestore(&forw_bcast_list_lock, flags);
/**
* send_outstanding_bcast_packet() will lock the list to
* delete the item from the list
*/
cancel_delayed_work_sync(&forw_packet->delayed_work);
- spin_lock(&forw_bcast_list_lock);
+ spin_lock_irqsave(&forw_bcast_list_lock, flags);
}
- spin_unlock(&forw_bcast_list_lock);
+ spin_unlock_irqrestore(&forw_bcast_list_lock, flags);
/* free batman packet list */
- spin_lock(&forw_bat_list_lock);
+ spin_lock_irqsave(&forw_bat_list_lock, flags);
hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
&forw_bat_list, list) {
- spin_unlock(&forw_bat_list_lock);
+ spin_unlock_irqrestore(&forw_bat_list_lock, flags);
/**
* send_outstanding_bat_packet() will lock the list to
* delete the item from the list
*/
cancel_delayed_work_sync(&forw_packet->delayed_work);
- spin_lock(&forw_bat_list_lock);
+ spin_lock_irqsave(&forw_bat_list_lock, flags);
}
- spin_unlock(&forw_bat_list_lock);
+ spin_unlock_irqrestore(&forw_bat_list_lock, flags);
}
diff --git a/drivers/staging/batman-adv/send.h b/drivers/staging/batman-adv/send.h
index 59d500917a35..5fc6f3417cb6 100644
--- a/drivers/staging/batman-adv/send.h
+++ b/drivers/staging/batman-adv/send.h
@@ -22,6 +22,9 @@
#include "types.h"
void send_own_packet_work(struct work_struct *work);
+int send_skb_packet(struct sk_buff *skb,
+ struct batman_if *batman_if,
+ uint8_t *dst_addr);
void send_raw_packet(unsigned char *pack_buff, int pack_buff_len,
struct batman_if *batman_if, uint8_t *dst_addr);
void schedule_own_packet(struct batman_if *batman_if);
@@ -30,7 +33,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
struct batman_packet *batman_packet,
uint8_t directlink, int hna_buff_len,
struct batman_if *if_outgoing);
-void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len);
+void add_bcast_packet_to_list(struct sk_buff *skb);
void send_outstanding_bcast_packet(struct work_struct *work);
void send_outstanding_bat_packet(struct work_struct *work);
void purge_outstanding_packets(void);
diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c
index d543f50b647f..c9b35d9f7991 100644
--- a/drivers/staging/batman-adv/soft-interface.c
+++ b/drivers/staging/batman-adv/soft-interface.c
@@ -24,18 +24,15 @@
#include "hard-interface.h"
#include "send.h"
#include "translation-table.h"
-#include "log.h"
#include "types.h"
#include "hash.h"
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
-#include "compat.h"
static uint16_t bcast_seqno = 1; /* give own bcast messages seq numbers to avoid
* broadcast storms */
static int32_t skb_packets;
static int32_t skb_bad_packets;
-static int32_t lock_dropped;
unsigned char mainIfAddr[ETH_ALEN];
static unsigned char mainIfAddr_default[ETH_ALEN];
@@ -68,12 +65,12 @@ int main_if_was_up(void)
return (memcmp(mainIfAddr, mainIfAddr_default, ETH_ALEN) != 0 ? 1 : 0);
}
-static int my_skb_push(struct sk_buff *skb, unsigned int len)
+int my_skb_push(struct sk_buff *skb, unsigned int len)
{
int result = 0;
skb_packets++;
- if (skb->data - len < skb->head) {
+ if (skb_headroom(skb) < len) {
skb_bad_packets++;
result = pskb_expand_head(skb, len, 0, GFP_ATOMIC);
@@ -122,7 +119,7 @@ void interface_setup(struct net_device *dev)
/* generate random address */
random_ether_addr(dev_addr);
- memcpy(dev->dev_addr, dev_addr, sizeof(dev->dev_addr));
+ memcpy(dev->dev_addr, dev_addr, ETH_ALEN);
SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);
@@ -147,9 +144,18 @@ struct net_device_stats *interface_stats(struct net_device *dev)
return &priv->stats;
}
-int interface_set_mac_addr(struct net_device *dev, void *addr)
+int interface_set_mac_addr(struct net_device *dev, void *p)
{
- return -EBUSY;
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ hna_local_remove(dev->dev_addr, "mac address changed");
+ memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+ hna_local_add(dev->dev_addr);
+
+ return 0;
}
int interface_change_mtu(struct net_device *dev, int new_mtu)
@@ -170,7 +176,10 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
struct orig_node *orig_node;
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct bat_priv *priv = netdev_priv(dev);
+ struct batman_if *batman_if;
+ uint8_t dstaddr[6];
int data_len = skb->len;
+ unsigned long flags;
if (atomic_read(&module_state) != MODULE_ACTIVE)
goto dropped;
@@ -186,7 +195,6 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
goto dropped;
bcast_packet = (struct bcast_packet *)skb->data;
-
bcast_packet->version = COMPAT_VERSION;
/* batman packet type: broadcast */
@@ -195,27 +203,21 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
/* hw address of first interface is the orig mac because only
* this mac is known throughout the mesh */
memcpy(bcast_packet->orig, mainIfAddr, ETH_ALEN);
+
/* set broadcast sequence number */
bcast_packet->seqno = htons(bcast_seqno);
bcast_seqno++;
/* broadcast packet */
- add_bcast_packet_to_list(skb->data, skb->len);
+ add_bcast_packet_to_list(skb);
+ /* a copy is stored in the bcast list, therefore removing
+ * the original skb. */
+ kfree_skb(skb);
/* unicast packet */
} else {
-
- /* simply spin_lock()ing can deadlock when the lock is already
- * hold. */
- /* TODO: defer the work in a working queue instead of
- * dropping */
- if (!spin_trylock(&orig_hash_lock)) {
- lock_dropped++;
- debug_log(LOG_TYPE_NOTICE, "%d packets dropped because lock was hold\n", lock_dropped);
- goto dropped;
- }
-
+ spin_lock_irqsave(&orig_hash_lock, flags);
/* get routing information */
orig_node = ((struct orig_node *)hash_find(orig_hash,
ethhdr->h_dest));
@@ -244,14 +246,17 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
if (orig_node->batman_if->if_active != IF_ACTIVE)
goto unlock;
- send_raw_packet(skb->data, skb->len,
- orig_node->batman_if,
- orig_node->router->addr);
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
+
+ batman_if = orig_node->batman_if;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ send_skb_packet(skb, batman_if, dstaddr);
} else {
goto unlock;
}
-
- spin_unlock(&orig_hash_lock);
}
priv->stats.tx_packets++;
@@ -259,42 +264,44 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
goto end;
unlock:
- spin_unlock(&orig_hash_lock);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
dropped:
priv->stats.tx_dropped++;
end:
- kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
-void interface_rx(struct net_device *dev, void *packet, int packet_len)
+void interface_rx(struct sk_buff *skb, int hdr_size)
{
- struct sk_buff *skb;
+ struct net_device *dev = soft_device;
struct bat_priv *priv = netdev_priv(dev);
- skb = dev_alloc_skb(packet_len);
-
- if (!skb) {
- priv->stats.rx_dropped++;
- goto out;
+ /* check if enough space is available for pulling, and pull */
+ if (!pskb_may_pull(skb, hdr_size)) {
+ kfree_skb(skb);
+ return;
}
+ skb_pull_rcsum(skb, hdr_size);
+/* skb_set_mac_header(skb, -sizeof(struct ethhdr));*/
- memcpy(skb_put(skb, packet_len), packet, packet_len);
-
- /* Write metadata, and then pass to the receive level */
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ /* should not be neccesary anymore as we use skb_pull_rcsum()
+ * TODO: please verify this and remove this TODO
+ * -- Dec 21st 2009, Simon Wunderlich */
+
+/* skb->ip_summed = CHECKSUM_UNNECESSARY;*/
+
+ /* TODO: set skb->pkt_type to PACKET_BROADCAST, PACKET_MULTICAST,
+ * PACKET_OTHERHOST or PACKET_HOST */
priv->stats.rx_packets++;
- priv->stats.rx_bytes += packet_len;
+ priv->stats.rx_bytes += skb->len;
dev->last_rx = jiffies;
netif_rx(skb);
-
-out:
- return;
}
/* ethtool */
@@ -330,7 +337,6 @@ static u32 bat_get_msglevel(struct net_device *dev)
static void bat_set_msglevel(struct net_device *dev, u32 value)
{
- return;
}
static u32 bat_get_link(struct net_device *dev)
diff --git a/drivers/staging/batman-adv/soft-interface.h b/drivers/staging/batman-adv/soft-interface.h
index 515e276ef53d..c0cad8134b2b 100644
--- a/drivers/staging/batman-adv/soft-interface.h
+++ b/drivers/staging/batman-adv/soft-interface.h
@@ -28,6 +28,7 @@ struct net_device_stats *interface_stats(struct net_device *dev);
int interface_set_mac_addr(struct net_device *dev, void *addr);
int interface_change_mtu(struct net_device *dev, int new_mtu);
int interface_tx(struct sk_buff *skb, struct net_device *dev);
-void interface_rx(struct net_device *dev, void *packet, int packet_len);
+void interface_rx(struct sk_buff *skb, int hdr_size);
+int my_skb_push(struct sk_buff *skb, unsigned int len);
extern unsigned char mainIfAddr[];
diff --git a/drivers/staging/batman-adv/translation-table.c b/drivers/staging/batman-adv/translation-table.c
index c2190e177c56..d56f6654de0d 100644
--- a/drivers/staging/batman-adv/translation-table.c
+++ b/drivers/staging/batman-adv/translation-table.c
@@ -21,11 +21,9 @@
#include "main.h"
#include "translation-table.h"
-#include "log.h"
#include "soft-interface.h"
#include "types.h"
#include "hash.h"
-#include "compat.h"
struct hashtable_t *hna_local_hash;
static struct hashtable_t *hna_global_hash;
@@ -62,7 +60,6 @@ void hna_local_add(uint8_t *addr)
struct hna_local_entry *hna_local_entry;
struct hna_global_entry *hna_global_entry;
struct hashtable_t *swaphash;
- char hna_str[ETH_STR_LEN];
unsigned long flags;
spin_lock_irqsave(&hna_local_hash_lock, flags);
@@ -75,19 +72,17 @@ void hna_local_add(uint8_t *addr)
return;
}
- addr_to_string(hna_str, addr);
-
/* only announce as many hosts as possible in the batman-packet and
space in batman_packet->num_hna That also should give a limit to
MAC-flooding. */
if ((num_hna + 1 > (ETH_DATA_LEN - BAT_PACKET_LEN) / ETH_ALEN) ||
(num_hna + 1 > 255)) {
- debug_log(LOG_TYPE_ROUTES, "Can't add new local hna entry (%s): number of local hna entries exceeds packet size \n", hna_str);
+ bat_dbg(DBG_ROUTES, "Can't add new local hna entry (%pM): number of local hna entries exceeds packet size \n", addr);
return;
}
- debug_log(LOG_TYPE_ROUTES, "Creating new local hna entry: %s \n",
- hna_str);
+ bat_dbg(DBG_ROUTES, "Creating new local hna entry: %pM \n",
+ addr);
hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC);
if (!hna_local_entry)
@@ -113,7 +108,7 @@ void hna_local_add(uint8_t *addr)
hna_local_hash->size * 2);
if (swaphash == NULL)
- debug_log(LOG_TYPE_CRIT, "Couldn't resize local hna hash table \n");
+ printk(KERN_ERR "batman-adv:Couldn't resize local hna hash table \n");
else
hna_local_hash = swaphash;
}
@@ -135,18 +130,18 @@ void hna_local_add(uint8_t *addr)
int hna_local_fill_buffer(unsigned char *buff, int buff_len)
{
struct hna_local_entry *hna_local_entry;
- struct hash_it_t *hashit = NULL;
+ HASHIT(hashit);
int i = 0;
unsigned long flags;
spin_lock_irqsave(&hna_local_hash_lock, flags);
- while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) {
+ while (hash_iterate(hna_local_hash, &hashit)) {
if (buff_len < (i + 1) * ETH_ALEN)
break;
- hna_local_entry = hashit->bucket->data;
+ hna_local_entry = hashit.bucket->data;
memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN);
i++;
@@ -164,18 +159,18 @@ int hna_local_fill_buffer(unsigned char *buff, int buff_len)
int hna_local_fill_buffer_text(unsigned char *buff, int buff_len)
{
struct hna_local_entry *hna_local_entry;
- struct hash_it_t *hashit = NULL;
+ HASHIT(hashit);
int bytes_written = 0;
unsigned long flags;
spin_lock_irqsave(&hna_local_hash_lock, flags);
- while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) {
+ while (hash_iterate(hna_local_hash, &hashit)) {
if (buff_len < bytes_written + ETH_STR_LEN + 4)
break;
- hna_local_entry = hashit->bucket->data;
+ hna_local_entry = hashit.bucket->data;
bytes_written += snprintf(buff + bytes_written, ETH_STR_LEN + 4,
" * %02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -202,27 +197,39 @@ static void _hna_local_del(void *data)
static void hna_local_del(struct hna_local_entry *hna_local_entry,
char *message)
{
- char hna_str[ETH_STR_LEN];
-
- addr_to_string(hna_str, hna_local_entry->addr);
- debug_log(LOG_TYPE_ROUTES, "Deleting local hna entry (%s): %s \n",
- hna_str, message);
+ bat_dbg(DBG_ROUTES, "Deleting local hna entry (%pM): %s \n",
+ hna_local_entry->addr, message);
hash_remove(hna_local_hash, hna_local_entry->addr);
_hna_local_del(hna_local_entry);
}
+void hna_local_remove(uint8_t *addr, char *message)
+{
+ struct hna_local_entry *hna_local_entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hna_local_hash_lock, flags);
+
+ hna_local_entry = (struct hna_local_entry *)
+ hash_find(hna_local_hash, addr);
+ if (hna_local_entry)
+ hna_local_del(hna_local_entry, message);
+
+ spin_unlock_irqrestore(&hna_local_hash_lock, flags);
+}
+
void hna_local_purge(struct work_struct *work)
{
struct hna_local_entry *hna_local_entry;
- struct hash_it_t *hashit = NULL;
+ HASHIT(hashit);
unsigned long flags;
unsigned long timeout;
spin_lock_irqsave(&hna_local_hash_lock, flags);
- while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) {
- hna_local_entry = hashit->bucket->data;
+ while (hash_iterate(hna_local_hash, &hashit)) {
+ hna_local_entry = hashit.bucket->data;
timeout = hna_local_entry->last_seen +
((LOCAL_HNA_TIMEOUT / 1000) * HZ);
@@ -264,13 +271,10 @@ void hna_global_add_orig(struct orig_node *orig_node,
struct hna_global_entry *hna_global_entry;
struct hna_local_entry *hna_local_entry;
struct hashtable_t *swaphash;
- char hna_str[ETH_STR_LEN], orig_str[ETH_STR_LEN];
int hna_buff_count = 0;
unsigned long flags;
unsigned char *hna_ptr;
- addr_to_string(orig_str, orig_node->orig);
-
while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) {
spin_lock_irqsave(&hna_global_hash_lock, flags);
@@ -290,8 +294,9 @@ void hna_global_add_orig(struct orig_node *orig_node,
memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN);
- addr_to_string(hna_str, hna_global_entry->addr);
- debug_log(LOG_TYPE_ROUTES, "Creating new global hna entry: %s (via %s)\n", hna_str, orig_str);
+ bat_dbg(DBG_ROUTES,
+ "Creating new global hna entry: %pM (via %pM)\n",
+ hna_global_entry->addr, orig_node->orig);
spin_lock_irqsave(&hna_global_hash_lock, flags);
hash_add(hna_global_hash, hna_global_entry);
@@ -316,14 +321,16 @@ void hna_global_add_orig(struct orig_node *orig_node,
hna_buff_count++;
}
- orig_node->hna_buff_len = hna_buff_len;
+ /* initialize, and overwrite if malloc succeeds */
+ orig_node->hna_buff = NULL;
+ orig_node->hna_buff_len = 0;
- if (orig_node->hna_buff_len > 0) {
- orig_node->hna_buff = kmalloc(orig_node->hna_buff_len,
- GFP_ATOMIC);
- memcpy(orig_node->hna_buff, hna_buff, orig_node->hna_buff_len);
- } else {
- orig_node->hna_buff = NULL;
+ if (hna_buff_len > 0) {
+ orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC);
+ if (orig_node->hna_buff) {
+ memcpy(orig_node->hna_buff, hna_buff, hna_buff_len);
+ orig_node->hna_buff_len = hna_buff_len;
+ }
}
spin_lock_irqsave(&hna_global_hash_lock, flags);
@@ -333,7 +340,7 @@ void hna_global_add_orig(struct orig_node *orig_node,
hna_global_hash->size * 2);
if (swaphash == NULL)
- debug_log(LOG_TYPE_CRIT, "Couldn't resize global hna hash table \n");
+ printk(KERN_ERR "batman-adv:Couldn't resize global hna hash table \n");
else
hna_global_hash = swaphash;
}
@@ -344,17 +351,17 @@ void hna_global_add_orig(struct orig_node *orig_node,
int hna_global_fill_buffer_text(unsigned char *buff, int buff_len)
{
struct hna_global_entry *hna_global_entry;
- struct hash_it_t *hashit = NULL;
+ HASHIT(hashit);
int bytes_written = 0;
unsigned long flags;
spin_lock_irqsave(&hna_global_hash_lock, flags);
- while (NULL != (hashit = hash_iterate(hna_global_hash, hashit))) {
+ while (hash_iterate(hna_global_hash, &hashit)) {
if (buff_len < bytes_written + (2 * ETH_STR_LEN) + 10)
break;
- hna_global_entry = hashit->bucket->data;
+ hna_global_entry = hashit.bucket->data;
bytes_written += snprintf(buff + bytes_written,
(2 * ETH_STR_LEN) + 10,
@@ -381,12 +388,9 @@ int hna_global_fill_buffer_text(unsigned char *buff, int buff_len)
void _hna_global_del_orig(struct hna_global_entry *hna_global_entry,
char *message)
{
- char hna_str[ETH_STR_LEN], orig_str[ETH_STR_LEN];
-
- addr_to_string(orig_str, hna_global_entry->orig_node->orig);
- addr_to_string(hna_str, hna_global_entry->addr);
-
- debug_log(LOG_TYPE_ROUTES, "Deleting global hna entry %s (via %s): %s \n", hna_str, orig_str, message);
+ bat_dbg(DBG_ROUTES, "Deleting global hna entry %pM (via %pM): %s \n",
+ hna_global_entry->addr, hna_global_entry->orig_node->orig,
+ message);
hash_remove(hna_global_hash, hna_global_entry->addr);
kfree(hna_global_entry);
diff --git a/drivers/staging/batman-adv/translation-table.h b/drivers/staging/batman-adv/translation-table.h
index f7da81129318..281125b729fb 100644
--- a/drivers/staging/batman-adv/translation-table.h
+++ b/drivers/staging/batman-adv/translation-table.h
@@ -23,6 +23,7 @@
int hna_local_init(void);
void hna_local_add(uint8_t *addr);
+void hna_local_remove(uint8_t *addr, char *message);
int hna_local_fill_buffer(unsigned char *buff, int buff_len);
int hna_local_fill_buffer_text(unsigned char *buff, int buff_len);
void hna_local_purge(struct work_struct *work);
diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h
index 3a0ef0c38c93..dec1b54031b6 100644
--- a/drivers/staging/batman-adv/types.h
+++ b/drivers/staging/batman-adv/types.h
@@ -39,7 +39,6 @@ struct batman_if {
char if_active;
char addr_str[ETH_STR_LEN];
struct net_device *net_dev;
- struct socket *raw_sock;
atomic_t seqno;
unsigned char *packet_buff;
int packet_len;
@@ -75,7 +74,7 @@ struct neigh_node {
uint8_t tq_index;
uint8_t tq_avg;
uint8_t last_ttl;
- unsigned long last_valid; /* when last packet via this neighbour was received */
+ unsigned long last_valid; /* when last packet via this neighbor was received */
TYPE_OF_WORD real_bits[NUM_WORDS];
struct orig_node *orig_node;
struct batman_if *if_incoming;
@@ -113,6 +112,7 @@ struct forw_packet { /* structure for forw_list maintaining packet
struct hlist_node list;
unsigned long send_time;
uint8_t own;
+ struct sk_buff *skb;
unsigned char *packet_buff;
uint16_t packet_len;
uint32_t direct_link_flags;
@@ -121,4 +121,14 @@ struct forw_packet { /* structure for forw_list maintaining packet
struct batman_if *if_incoming;
};
+/* While scanning for vis-entries of a particular vis-originator
+ * this list collects its interfaces to create a subgraph/cluster
+ * out of them later
+ */
+struct if_list_entry {
+ uint8_t addr[ETH_ALEN];
+ bool primary;
+ struct hlist_node list;
+};
+
#endif
diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c
index f6c9acb289ed..fedec1bb3097 100644
--- a/drivers/staging/batman-adv/vis.c
+++ b/drivers/staging/batman-adv/vis.c
@@ -23,11 +23,9 @@
#include "send.h"
#include "translation-table.h"
#include "vis.h"
-#include "log.h"
#include "soft-interface.h"
#include "hard-interface.h"
#include "hash.h"
-#include "compat.h"
struct hashtable_t *vis_hash;
DEFINE_SPINLOCK(vis_hash_lock);
@@ -50,39 +48,6 @@ static void free_info(void *data)
kfree(info);
}
-/* set the mode of the visualization to client or server */
-void vis_set_mode(int mode)
-{
- spin_lock(&vis_hash_lock);
-
- if (my_vis_info != NULL)
- my_vis_info->packet.vis_type = mode;
-
- spin_unlock(&vis_hash_lock);
-}
-
-/* is_vis_server(), locked outside */
-static int is_vis_server_locked(void)
-{
- if (my_vis_info != NULL)
- if (my_vis_info->packet.vis_type == VIS_TYPE_SERVER_SYNC)
- return 1;
-
- return 0;
-}
-
-/* get the current set mode */
-int is_vis_server(void)
-{
- int ret = 0;
-
- spin_lock(&vis_hash_lock);
- ret = is_vis_server_locked();
- spin_unlock(&vis_hash_lock);
-
- return ret;
-}
-
/* Compare two vis packets, used by the hashing algorithm */
static int vis_info_cmp(void *data1, void *data2)
{
@@ -115,6 +80,68 @@ static int vis_info_choose(void *data, int size)
return hash % size;
}
+/* insert interface to the list of interfaces of one originator, if it
+ * does not already exist in the list */
+static void proc_vis_insert_interface(const uint8_t *interface,
+ struct hlist_head *if_list,
+ bool primary)
+{
+ struct if_list_entry *entry;
+ struct hlist_node *pos;
+
+ hlist_for_each_entry(entry, pos, if_list, list) {
+ if (compare_orig(entry->addr, (void *)interface))
+ return;
+ }
+
+ /* its a new address, add it to the list */
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return;
+ memcpy(entry->addr, interface, ETH_ALEN);
+ entry->primary = primary;
+ hlist_add_head(&entry->list, if_list);
+}
+
+void proc_vis_read_prim_sec(struct seq_file *seq,
+ struct hlist_head *if_list)
+{
+ struct if_list_entry *entry;
+ struct hlist_node *pos, *n;
+ char tmp_addr_str[ETH_STR_LEN];
+
+ hlist_for_each_entry_safe(entry, pos, n, if_list, list) {
+ if (entry->primary) {
+ seq_printf(seq, "PRIMARY, ");
+ } else {
+ addr_to_string(tmp_addr_str, entry->addr);
+ seq_printf(seq, "SEC %s, ", tmp_addr_str);
+ }
+
+ hlist_del(&entry->list);
+ kfree(entry);
+ }
+}
+
+/* read an entry */
+void proc_vis_read_entry(struct seq_file *seq,
+ struct vis_info_entry *entry,
+ struct hlist_head *if_list,
+ uint8_t *vis_orig)
+{
+ char to[40];
+
+ addr_to_string(to, entry->dest);
+ if (entry->quality == 0) {
+ proc_vis_insert_interface(vis_orig, if_list, true);
+ seq_printf(seq, "HNA %s, ", to);
+ } else {
+ proc_vis_insert_interface(entry->src, if_list,
+ compare_orig(entry->src, vis_orig));
+ seq_printf(seq, "TQ %s %d, ", to, entry->quality);
+ }
+}
+
/* tries to add one entry to the receive list. */
static void recv_list_add(struct list_head *recv_list, char *mac)
{
@@ -208,21 +235,23 @@ void receive_server_sync_packet(struct vis_packet *vis_packet, int vis_info_len)
{
struct vis_info *info;
int is_new;
+ unsigned long flags;
+ int vis_server = atomic_read(&vis_mode);
- spin_lock(&vis_hash_lock);
+ spin_lock_irqsave(&vis_hash_lock, flags);
info = add_packet(vis_packet, vis_info_len, &is_new);
if (info == NULL)
goto end;
/* only if we are server ourselves and packet is newer than the one in
* hash.*/
- if (is_vis_server_locked() && is_new) {
+ if (vis_server == VIS_TYPE_SERVER_SYNC && is_new) {
memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
if (list_empty(&info->send_list))
list_add_tail(&info->send_list, &send_list);
}
end:
- spin_unlock(&vis_hash_lock);
+ spin_unlock_irqrestore(&vis_hash_lock, flags);
}
/* handle an incoming client update packet and schedule forward if needed. */
@@ -231,12 +260,14 @@ void receive_client_update_packet(struct vis_packet *vis_packet,
{
struct vis_info *info;
int is_new;
+ unsigned long flags;
+ int vis_server = atomic_read(&vis_mode);
/* clients shall not broadcast. */
if (is_bcast(vis_packet->target_orig))
return;
- spin_lock(&vis_hash_lock);
+ spin_lock_irqsave(&vis_hash_lock, flags);
info = add_packet(vis_packet, vis_info_len, &is_new);
if (info == NULL)
goto end;
@@ -244,7 +275,7 @@ void receive_client_update_packet(struct vis_packet *vis_packet,
/* send only if we're the target server or ... */
- if (is_vis_server_locked() &&
+ if (vis_server == VIS_TYPE_SERVER_SYNC &&
is_my_mac(info->packet.target_orig) &&
is_new) {
info->packet.vis_type = VIS_TYPE_SERVER_SYNC; /* upgrade! */
@@ -258,7 +289,7 @@ void receive_client_update_packet(struct vis_packet *vis_packet,
list_add_tail(&info->send_list, &send_list);
}
end:
- spin_unlock(&vis_hash_lock);
+ spin_unlock_irqrestore(&vis_hash_lock, flags);
}
/* Walk the originators and find the VIS server with the best tq. Set the packet
@@ -267,12 +298,12 @@ end:
* Must be called with the originator hash locked */
static int find_best_vis_server(struct vis_info *info)
{
- struct hash_it_t *hashit = NULL;
+ HASHIT(hashit);
struct orig_node *orig_node;
int best_tq = -1;
- while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
- orig_node = hashit->bucket->data;
+ while (hash_iterate(orig_hash, &hashit)) {
+ orig_node = hashit.bucket->data;
if ((orig_node != NULL) &&
(orig_node->router != NULL) &&
(orig_node->flags & VIS_SERVER) &&
@@ -298,7 +329,8 @@ static bool vis_packet_full(struct vis_info *info)
* returns 0 on success, -1 if no packet could be generated */
static int generate_vis_packet(void)
{
- struct hash_it_t *hashit = NULL;
+ HASHIT(hashit_local);
+ HASHIT(hashit_global);
struct orig_node *orig_node;
struct vis_info *info = (struct vis_info *)my_vis_info;
struct vis_info_entry *entry, *entry_array;
@@ -307,27 +339,27 @@ static int generate_vis_packet(void)
unsigned long flags;
info->first_seen = jiffies;
+ info->packet.vis_type = atomic_read(&vis_mode);
- spin_lock(&orig_hash_lock);
+ spin_lock_irqsave(&orig_hash_lock, flags);
memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
info->packet.ttl = TTL;
info->packet.seqno++;
info->packet.entries = 0;
- if (!is_vis_server_locked()) {
+ if (info->packet.vis_type == VIS_TYPE_CLIENT_UPDATE) {
best_tq = find_best_vis_server(info);
if (best_tq < 0) {
- spin_unlock(&orig_hash_lock);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
return -1;
}
}
- hashit = NULL;
entry_array = (struct vis_info_entry *)
((char *)info + sizeof(struct vis_info));
- while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
- orig_node = hashit->bucket->data;
+ while (hash_iterate(orig_hash, &hashit_global)) {
+ orig_node = hashit_global.bucket->data;
if (orig_node->router != NULL
&& compare_orig(orig_node->router->addr, orig_node->orig)
&& orig_node->batman_if
@@ -342,18 +374,17 @@ static int generate_vis_packet(void)
info->packet.entries++;
if (vis_packet_full(info)) {
- spin_unlock(&orig_hash_lock);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
return 0;
}
}
}
- spin_unlock(&orig_hash_lock);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
- hashit = NULL;
spin_lock_irqsave(&hna_local_hash_lock, flags);
- while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) {
- hna_local_entry = hashit->bucket->data;
+ while (hash_iterate(hna_local_hash, &hashit_local)) {
+ hna_local_entry = hashit_local.bucket->data;
entry = &entry_array[info->packet.entries];
memset(entry->src, 0, ETH_ALEN);
memcpy(entry->dest, hna_local_entry->addr, ETH_ALEN);
@@ -371,16 +402,16 @@ static int generate_vis_packet(void)
static void purge_vis_packets(void)
{
- struct hash_it_t *hashit = NULL;
+ HASHIT(hashit);
struct vis_info *info;
- while (NULL != (hashit = hash_iterate(vis_hash, hashit))) {
- info = hashit->bucket->data;
+ while (hash_iterate(vis_hash, &hashit)) {
+ info = hashit.bucket->data;
if (info == my_vis_info) /* never purge own data. */
continue;
if (time_after(jiffies,
- info->first_seen + (VIS_TIMEOUT/1000)*HZ)) {
- hash_remove_bucket(vis_hash, hashit);
+ info->first_seen + (VIS_TIMEOUT*HZ)/1000)) {
+ hash_remove_bucket(vis_hash, &hashit);
free_info(info);
}
}
@@ -388,14 +419,15 @@ static void purge_vis_packets(void)
static void broadcast_vis_packet(struct vis_info *info, int packet_length)
{
- struct hash_it_t *hashit = NULL;
+ HASHIT(hashit);
struct orig_node *orig_node;
+ unsigned long flags;
- spin_lock(&orig_hash_lock);
+ spin_lock_irqsave(&orig_hash_lock, flags);
/* send to all routers in range. */
- while (NULL != (hashit = hash_iterate(orig_hash, hashit))) {
- orig_node = hashit->bucket->data;
+ while (hash_iterate(orig_hash, &hashit)) {
+ orig_node = hashit.bucket->data;
/* if it's a vis server and reachable, send it. */
if (orig_node &&
@@ -418,14 +450,15 @@ static void broadcast_vis_packet(struct vis_info *info, int packet_length)
}
}
memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
- spin_unlock(&orig_hash_lock);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
}
static void unicast_vis_packet(struct vis_info *info, int packet_length)
{
struct orig_node *orig_node;
+ unsigned long flags;
- spin_lock(&orig_hash_lock);
+ spin_lock_irqsave(&orig_hash_lock, flags);
orig_node = ((struct orig_node *)
hash_find(orig_hash, info->packet.target_orig));
@@ -436,7 +469,7 @@ static void unicast_vis_packet(struct vis_info *info, int packet_length)
orig_node->batman_if,
orig_node->router->addr);
}
- spin_unlock(&orig_hash_lock);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
}
/* only send one vis packet. called from send_vis_packets() */
@@ -445,8 +478,7 @@ static void send_vis_packet(struct vis_info *info)
int packet_length;
if (info->packet.ttl < 2) {
- debug_log(LOG_TYPE_NOTICE,
- "Error - can't send vis packet: ttl exceeded\n");
+ printk(KERN_WARNING "batman-adv: Error - can't send vis packet: ttl exceeded\n");
return;
}
@@ -467,8 +499,9 @@ static void send_vis_packet(struct vis_info *info)
static void send_vis_packets(struct work_struct *work)
{
struct vis_info *info, *temp;
+ unsigned long flags;
- spin_lock(&vis_hash_lock);
+ spin_lock_irqsave(&vis_hash_lock, flags);
purge_vis_packets();
if (generate_vis_packet() == 0)
@@ -479,7 +512,7 @@ static void send_vis_packets(struct work_struct *work)
list_del_init(&info->send_list);
send_vis_packet(info);
}
- spin_unlock(&vis_hash_lock);
+ spin_unlock_irqrestore(&vis_hash_lock, flags);
start_vis_timer();
}
static DECLARE_DELAYED_WORK(vis_timer_wq, send_vis_packets);
@@ -488,20 +521,21 @@ static DECLARE_DELAYED_WORK(vis_timer_wq, send_vis_packets);
* initialized (e.g. bat0 is initialized, interfaces have been added) */
int vis_init(void)
{
+ unsigned long flags;
if (vis_hash)
return 1;
- spin_lock(&vis_hash_lock);
+ spin_lock_irqsave(&vis_hash_lock, flags);
vis_hash = hash_new(256, vis_info_cmp, vis_info_choose);
if (!vis_hash) {
- debug_log(LOG_TYPE_CRIT, "Can't initialize vis_hash\n");
+ printk(KERN_ERR "batman-adv:Can't initialize vis_hash\n");
goto err;
}
my_vis_info = kmalloc(1000, GFP_ATOMIC);
if (!my_vis_info) {
- debug_log(LOG_TYPE_CRIT, "Can't initialize vis packet\n");
+ printk(KERN_ERR "batman-adv:Can't initialize vis packet\n");
goto err;
}
@@ -511,7 +545,6 @@ int vis_init(void)
INIT_LIST_HEAD(&my_vis_info->send_list);
my_vis_info->packet.version = COMPAT_VERSION;
my_vis_info->packet.packet_type = BAT_VIS;
- my_vis_info->packet.vis_type = VIS_TYPE_CLIENT_UPDATE;
my_vis_info->packet.ttl = TTL;
my_vis_info->packet.seqno = 0;
my_vis_info->packet.entries = 0;
@@ -522,19 +555,19 @@ int vis_init(void)
memcpy(my_vis_info->packet.sender_orig, mainIfAddr, ETH_ALEN);
if (hash_add(vis_hash, my_vis_info) < 0) {
- debug_log(LOG_TYPE_CRIT,
- "Can't add own vis packet into hash\n");
+ printk(KERN_ERR
+ "batman-adv:Can't add own vis packet into hash\n");
free_info(my_vis_info); /* not in hash, need to remove it
* manually. */
goto err;
}
- spin_unlock(&vis_hash_lock);
+ spin_unlock_irqrestore(&vis_hash_lock, flags);
start_vis_timer();
return 1;
err:
- spin_unlock(&vis_hash_lock);
+ spin_unlock_irqrestore(&vis_hash_lock, flags);
vis_quit();
return 0;
}
@@ -542,23 +575,23 @@ err:
/* shutdown vis-server */
void vis_quit(void)
{
+ unsigned long flags;
if (!vis_hash)
return;
cancel_delayed_work_sync(&vis_timer_wq);
- spin_lock(&vis_hash_lock);
+ spin_lock_irqsave(&vis_hash_lock, flags);
/* properly remove, kill timers ... */
hash_delete(vis_hash, free_info);
vis_hash = NULL;
my_vis_info = NULL;
- spin_unlock(&vis_hash_lock);
+ spin_unlock_irqrestore(&vis_hash_lock, flags);
}
/* schedule packets for (re)transmission */
static void start_vis_timer(void)
{
queue_delayed_work(bat_event_workqueue, &vis_timer_wq,
- (atomic_read(&vis_interval)/1000) * HZ);
+ (atomic_read(&vis_interval) * HZ) / 1000);
}
-
diff --git a/drivers/staging/batman-adv/vis.h b/drivers/staging/batman-adv/vis.h
index 276fabab4e88..0cdafde0ec3a 100644
--- a/drivers/staging/batman-adv/vis.h
+++ b/drivers/staging/batman-adv/vis.h
@@ -45,16 +45,15 @@ struct recvlist_node {
uint8_t mac[ETH_ALEN];
};
-enum vis_formats {
- DOT_DRAW,
- JSON,
-};
-
extern struct hashtable_t *vis_hash;
extern spinlock_t vis_hash_lock;
-void vis_set_mode(int mode);
-int is_vis_server(void);
+void proc_vis_read_entry(struct seq_file *seq,
+ struct vis_info_entry *entry,
+ struct hlist_head *if_list,
+ uint8_t *vis_orig);
+void proc_vis_read_prim_sec(struct seq_file *seq,
+ struct hlist_head *if_list);
void receive_server_sync_packet(struct vis_packet *vis_packet,
int vis_info_len);
void receive_client_update_packet(struct vis_packet *vis_packet,
diff --git a/drivers/staging/comedi/comedi_compat32.c b/drivers/staging/comedi/comedi_compat32.c
index a9fdcda5db7a..581aa5fee2e3 100644
--- a/drivers/staging/comedi/comedi_compat32.c
+++ b/drivers/staging/comedi/comedi_compat32.c
@@ -26,7 +26,6 @@
#define __NO_VERSION__
#include "comedi.h"
-#include <linux/smp_lock.h>
#include <linux/uaccess.h>
#include "comedi_compat32.h"
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 8117748ad5a5..aca96747e5e2 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -63,7 +63,7 @@ module_param(comedi_debug, int, 0644);
int comedi_autoconfig = 1;
module_param(comedi_autoconfig, bool, 0444);
-int comedi_num_legacy_minors = 0;
+int comedi_num_legacy_minors;
module_param(comedi_num_legacy_minors, int, 0444);
static DEFINE_SPINLOCK(comedi_file_info_table_lock);
@@ -1510,7 +1510,7 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait)
}
static ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes,
- loff_t * offset)
+ loff_t *offset)
{
struct comedi_subdevice *s;
struct comedi_async *async;
@@ -1612,7 +1612,7 @@ done:
}
static ssize_t comedi_read(struct file *file, char *buf, size_t nbytes,
- loff_t * offset)
+ loff_t *offset)
{
struct comedi_subdevice *s;
struct comedi_async *async;
@@ -2004,12 +2004,10 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
if (async->cb_mask & s->async->events) {
if (comedi_get_subdevice_runflags(s) & SRF_USER) {
wake_up_interruptible(&async->wait_head);
- if (s->subdev_flags & SDF_CMD_READ) {
+ if (s->subdev_flags & SDF_CMD_READ)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
- }
- if (s->subdev_flags & SDF_CMD_WRITE) {
+ if (s->subdev_flags & SDF_CMD_WRITE)
kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
- }
} else {
if (async->cb_func)
async->cb_func(s->async->events, async->cb_arg);
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index c2a632d31c61..44d6b62c230d 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -44,7 +44,7 @@
#include <linux/cdev.h>
#include <linux/dma-mapping.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/system.h>
static int postconfig(struct comedi_device *dev);
@@ -99,11 +99,10 @@ static void cleanup_device(struct comedi_device *dev)
static void __comedi_device_detach(struct comedi_device *dev)
{
dev->attached = 0;
- if (dev->driver) {
+ if (dev->driver)
dev->driver->detach(dev);
- } else {
+ else
printk("BUG: dev->driver=NULL in comedi_device_detach()\n");
- }
cleanup_device(dev);
}
@@ -380,9 +379,8 @@ static int insn_rw_emulate_bits(struct comedi_device *dev,
if (ret < 0)
return ret;
- if (insn->insn == INSN_READ) {
+ if (insn->insn == INSN_READ)
data[0] = (new_data[1] >> (chan - base_bitfield_channel)) & 1;
- }
return 1;
}
@@ -429,9 +427,9 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
/* if no change is required, do nothing */
- if (async->prealloc_buf && async->prealloc_bufsz == new_size) {
+ if (async->prealloc_buf && async->prealloc_bufsz == new_size)
return 0;
- }
+
/* deallocate old buffer */
if (async->prealloc_buf) {
vunmap(async->prealloc_buf);
@@ -494,9 +492,9 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
(void *)
get_zeroed_page(GFP_KERNEL);
}
- if (async->buf_page_list[i].virt_addr == NULL) {
+ if (async->buf_page_list[i].virt_addr == NULL)
break;
- }
+
mem_map_reserve(virt_to_page
(async->buf_page_list[i].
virt_addr));
@@ -619,9 +617,9 @@ unsigned int comedi_buf_write_alloc(struct comedi_async *async,
{
unsigned int free_end = async->buf_read_count + async->prealloc_bufsz;
- if ((int)(async->buf_write_alloc_count + nbytes - free_end) > 0) {
+ if ((int)(async->buf_write_alloc_count + nbytes - free_end) > 0)
nbytes = free_end - async->buf_write_alloc_count;
- }
+
async->buf_write_alloc_count += nbytes;
/* barrier insures the read of buf_read_count above occurs before
we write data to the write-alloc'ed buffer space */
@@ -635,9 +633,9 @@ unsigned int comedi_buf_write_alloc_strict(struct comedi_async *async,
{
unsigned int free_end = async->buf_read_count + async->prealloc_bufsz;
- if ((int)(async->buf_write_alloc_count + nbytes - free_end) > 0) {
+ if ((int)(async->buf_write_alloc_count + nbytes - free_end) > 0)
nbytes = 0;
- }
+
async->buf_write_alloc_count += nbytes;
/* barrier insures the read of buf_read_count above occurs before
we write data to the write-alloc'ed buffer space */
@@ -657,9 +655,9 @@ unsigned comedi_buf_write_free(struct comedi_async *async, unsigned int nbytes)
async->buf_write_count += nbytes;
async->buf_write_ptr += nbytes;
comedi_buf_munge(async, async->buf_write_count - async->munge_count);
- if (async->buf_write_ptr >= async->prealloc_bufsz) {
+ if (async->buf_write_ptr >= async->prealloc_bufsz)
async->buf_write_ptr %= async->prealloc_bufsz;
- }
+
return nbytes;
}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c
index 0af12fd2a40a..fbc26a027de4 100644
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c
+++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c
index f3e47e5791db..a6898e4bbb62 100644
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c
+++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c
index a15c952c0fab..0e498e9eb080 100644
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c
+++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c
index 0fc2285c9ef8..204d7987700a 100644
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c
+++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c
index 138a84f572c8..148ce6f67f0d 100644
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c
+++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c
index a445dab50eac..6360de59e0e9 100644
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c
+++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c
index 7e1254475792..344df9462198 100644
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c
+++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c
index d3d78d37de5c..de6f77246890 100644
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c
+++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c
index 6e9e7ed4dba9..97c10aaa691d 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
@@ -173,11 +173,10 @@ int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead,
} while (dw_eeprom_busy == EEPROM_BUSY);
/* Select the upper address part */
- if (i_Counter == 0) {
+ if (i_Counter == 0)
b_ReadLowByte = pb_ReadByte[0];
- } else {
+ else
b_ReadHighByte = pb_ReadByte[0];
- }
/* Sleep */
msleep(1);
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c
index a56535fbcd3e..8db5ab63e363 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h
index 3ab27cf0facc..caeb6fd2d9b1 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.h
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h
@@ -77,8 +77,8 @@ struct addi_board {
int i_NbrAoChannel; /* num of D/A chans */
int i_AiMaxdata; /* resolution of A/D */
int i_AoMaxdata; /* resolution of D/A */
- const struct comedi_lrange *pr_AiRangelist; /* rangelist for A/D */
- const struct comedi_lrange *pr_AoRangelist; /* rangelist for D/A */
+ const struct comedi_lrange *pr_AiRangelist; /* rangelist for A/D */
+ const struct comedi_lrange *pr_AoRangelist; /* rangelist for D/A */
int i_NbrDiChannel; /* Number of DI channels */
int i_NbrDoChannel; /* Number of DO channels */
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
index 69b427390e53..bea329f44d80 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
index 47517a938ec5..d7d768ee7c23 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c
index 016721efdbfb..791297266fc0 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c
index 723a97bab44c..fe06789699f3 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
@@ -54,7 +54,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc
#include "hwdrv_apci1032.h"
#include <linux/delay.h>
/* Global variables */
-unsigned int ui_InterruptStatus = 0;
+unsigned int ui_InterruptStatus;
/*
+----------------------------------------------------------------------------+
@@ -108,9 +108,9 @@ int i_APCI1032_ConfigDigitalInput(struct comedi_device *dev, struct comedi_subde
ui_TmpValue =
inl(devpriv->iobase + APCI1032_DIGITAL_IP_IRQ);
} /* if (data[1] == ADDIDATA_OR) */
- else {
+ else
outl(0x6, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ);
- } /* else if(data[1] == ADDIDATA_OR) */
+ /* else if(data[1] == ADDIDATA_OR) */
} /* if( data[0] == ADDIDATA_ENABLE) */
else {
ul_Command1 = ul_Command1 & 0xFFFF0000;
@@ -221,9 +221,9 @@ int i_APCI1032_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_sub
} /* switch(ui_NoOfChannels) */
} /* if(data[1]==0) */
else {
- if (data[1] == 1) {
+ if (data[1] == 1)
*data = ui_InterruptStatus;
- } /* if(data[1]==1) */
+ /* if(data[1]==1) */
} /* else if(data[1]==0) */
return insn->n;
}
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
index 36b929ffecbd..d5e06ad6acc2 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c
index 866eb8d75820..7948c41f60f5 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c
index 3ae663bc754e..4413279c880b 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c
index 988e3fc2b857..8bc88adfbb59 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c
index d348cd5687aa..89783b1eb0bd 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c
index ec817082d170..2d325163c169 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c
index aa159dccc36a..e01889c3c4fc 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
index 172fba8dbfe5..f93ddd4eb06c 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
@@ -45,7 +45,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc
*/
#include "hwdrv_apci3120.h"
-static unsigned int ui_Temp = 0;
+static unsigned int ui_Temp;
/* FUNCTION DEFINITIONS */
@@ -98,25 +98,22 @@ int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, struct comedi_su
devpriv->b_InterruptMode = APCI3120_EOS_MODE;
- if (data[1]) {
+ if (data[1])
devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
- } else
+ else
devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
/* Copy channel list and Range List to devpriv */
devpriv->ui_AiNbrofChannels = data[3];
- for (i = 0; i < devpriv->ui_AiNbrofChannels; i++) {
+ for (i = 0; i < devpriv->ui_AiNbrofChannels; i++)
devpriv->ui_AiChannelList[i] = data[4 + i];
- }
- } else /* EOC */
- {
+ } else { /* EOC */
devpriv->b_InterruptMode = APCI3120_EOC_MODE;
- if (data[1]) {
+ if (data[1])
devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
- } else {
+ else
devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
- }
}
return insn->n;
@@ -166,13 +163,9 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subd
devpriv->us_OutputRegister = 0;
/* devpriv->b_DigitalOutputRegister=0; */
- if (insn->unused[0] == 222) /* second insn read */
- {
-
- for (i = 0; i < insn->n; i++) {
+ if (insn->unused[0] == 222) { /* second insn read */
+ for (i = 0; i < insn->n; i++)
data[i] = devpriv->ui_AiReadData[i];
- }
-
} else {
devpriv->tsk_Current = current; /* Save the current process task structure */
/*
@@ -519,9 +512,8 @@ int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_s
/* step 2: make sure trigger sources are unique and mutually compatible */
- if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
+ if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
err++;
- }
if (cmd->scan_begin_src != TRIG_TIMER &&
cmd->scan_begin_src != TRIG_FOLLOW)
@@ -548,16 +540,14 @@ int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_s
err++;
}
- if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */
- {
+ if (cmd->scan_begin_src == TRIG_TIMER) { /* Test Delay timing */
if (cmd->scan_begin_arg < this_board->ui_MinDelaytimeNs) {
cmd->scan_begin_arg = this_board->ui_MinDelaytimeNs;
err++;
}
}
- if (cmd->convert_src == TRIG_TIMER) /* Test Acquisition timing */
- {
+ if (cmd->convert_src == TRIG_TIMER) { /* Test Acquisition timing */
if (cmd->scan_begin_src == TRIG_TIMER) {
if ((cmd->convert_arg)
&& (cmd->convert_arg <
@@ -653,11 +643,10 @@ int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subde
/* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */
devpriv->ui_AiDataLength = s->async->prealloc_bufsz;
- if (cmd->stop_src == TRIG_COUNT) {
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->ui_AiNbrofScans = cmd->stop_arg;
- } else {
+ else
devpriv->ui_AiNbrofScans = 0;
- }
devpriv->ui_AiTimer0 = 0; /* variables changed to timer0,timer1 */
devpriv->ui_AiTimer1 = 0;
@@ -849,9 +838,8 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev,
}
/*** EL241003 End ******************************************************************************/
- if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
+ if (devpriv->b_ExttrigEnable == APCI3120_ENABLE)
i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */
- }
switch (mode) {
case 1:
/* init timer0 in mode 2 */
@@ -1049,12 +1037,10 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev,
dmalen1 = 4;
}
} else { /* isn't output buff smaller that our DMA buff? */
- if (dmalen0 > (devpriv->ui_AiDataLength)) {
+ if (dmalen0 > (devpriv->ui_AiDataLength))
dmalen0 = devpriv->ui_AiDataLength;
- }
- if (dmalen1 > (devpriv->ui_AiDataLength)) {
+ if (dmalen1 > (devpriv->ui_AiDataLength))
dmalen1 = devpriv->ui_AiDataLength;
- }
}
devpriv->ui_DmaBufferUsesize[0] = dmalen0;
devpriv->ui_DmaBufferUsesize[1] = dmalen1;
@@ -1356,11 +1342,10 @@ int i_APCI3120_SetupChannelList(struct comedi_device *dev, struct comedi_subdevi
/* store range list to card */
us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number; */
- if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES) {
+ if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES)
us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */
- } else {
+ else
us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar...... */
- }
gain = CR_RANGE(chanlist[i]); /* get gain number */
us_TmpValue |= ((gain & 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */
@@ -1514,8 +1499,7 @@ void v_APCI3120_Interrupt(int irq, void *d)
/* Check If EOS interrupt */
if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
- if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) /* enable this in without DMA ??? */
- {
+ if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* enable this in without DMA ??? */
if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
ui_Check = 0;
@@ -1966,8 +1950,7 @@ int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevic
APCI3120_DISABLE_EOS_INT;
outb(devpriv->b_ModeSelectRegister,
devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
- if (data[0] == APCI3120_TIMER) /* initialize timer */
- {
+ if (data[0] == APCI3120_TIMER) { /* initialize timer */
/* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister |
* APCI3120_ENABLE_TIMER_INT; */
@@ -2006,8 +1989,7 @@ int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevic
/* timer2 in Timer mode enabled */
devpriv->b_Timer2Mode = APCI3120_TIMER;
- } else /* Initialize Watch dog */
- {
+ } else { /* Initialize Watch dog */
/* Set the Timer 2 in mode 5(Watchdog) */
@@ -2092,8 +2074,7 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice
return -EINVAL;
}
- if (data[0] == 2) /* write new value */
- {
+ if (data[0] == 2) { /* write new value */
if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
comedi_error(dev,
"write :timer2 not configured in TIMER MODE");
@@ -2113,13 +2094,11 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice
/* Reset FC_TIMER BIT */
inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
- if (devpriv->b_Timer2Mode == APCI3120_TIMER) /* start timer */
- {
+ if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
/* Enable Timer */
devpriv->b_ModeSelectRegister =
devpriv->b_ModeSelectRegister & 0x0B;
- } else /* start watch dog */
- {
+ } else { /* start watch dog */
/* Enable WatchDog */
devpriv->b_ModeSelectRegister =
(devpriv->
@@ -2146,8 +2125,7 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice
outb(devpriv->b_ModeSelectRegister,
devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
- if (devpriv->b_Timer2Mode == APCI3120_TIMER) /* start timer */
- {
+ if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
/* For Timer mode is Gate2 must be activated **timer started */
devpriv->us_OutputRegister =
devpriv->
@@ -2299,8 +2277,7 @@ int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice
/* combining both words */
data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16));
- } else /* Read watch dog status */
- {
+ } else { /* Read watch dog status */
us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
us_StatusValue =
@@ -2441,10 +2418,9 @@ int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device *dev,
devpriv->b_OutputMemoryStatus = APCI3120_DISABLE;
devpriv->b_DigitalOutputRegister = 0;
}
- if (!devpriv->b_OutputMemoryStatus) {
+ if (!devpriv->b_OutputMemoryStatus)
ui_Temp = 0;
-
- } /* if(!devpriv->b_OutputMemoryStatus ) */
+ /* if(!devpriv->b_OutputMemoryStatus ) */
return insn->n;
}
@@ -2504,23 +2480,23 @@ int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev,
/*
+----------------------------------------------------------------------------+
-| Function name :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,|
-|struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
-| |
+| Function name :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,|
+|struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
+| |
+----------------------------------------------------------------------------+
-| Task : Write digiatl output |
-| |
+| Task : Write digiatl output |
+| |
+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev |
-| struct comedi_subdevice *s |
-| struct comedi_insn *insn |
-| unsigned int *data |
- data[0] Value to be written
- data[1] :1 Set digital o/p ON
- data[1] 2 Set digital o/p OFF with memory ON
+| Input Parameters : struct comedi_device *dev |
+| struct comedi_subdevice *s |
+| struct comedi_insn *insn |
+| unsigned int *data |
+ data[0] Value to be written
+ data[1] :1 Set digital o/p ON
+ data[1] 2 Set digital o/p OFF with memory ON
+----------------------------------------------------------------------------+
-| Return Value : |
-| |
+| Return Value : |
+| |
+----------------------------------------------------------------------------+
*/
@@ -2615,8 +2591,7 @@ int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
ui_Channel = CR_CHAN(insn->chanspec);
/* this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); */
- if (ui_Range) /* if 1 then unipolar */
- {
+ if (ui_Range) { /* if 1 then unipolar */
if (data[0] != 0)
data[0] =
@@ -2627,8 +2602,7 @@ int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
13) | 8192);
- } else /* if 0 then bipolar */
- {
+ } else { /* if 0 then bipolar */
data[0] =
((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
data[0]);
@@ -2639,8 +2613,7 @@ int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
* out put n values at the given channel. printk("\nwaiting for
* DA_READY BIT");
*/
- do /* Waiting of DA_READY BIT */
- {
+ do { /* Waiting of DA_READY BIT */
us_TmpValue =
((unsigned short) inw(devpriv->iobase +
APCI3120_RD_STATUS)) & 0x0001;
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
index 98c23872e374..560c848f6258 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
index 7b38d177394b..4ed441a1adc8 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c
index 1d1e5fc2ea9a..3692326d474a 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c
@@ -17,7 +17,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
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
-You shoud also find the complete GPL in the COPYING file accompanying this source code.
+You should also find the complete GPL in the COPYING file accompanying this source code.
@endverbatim
*/
@@ -1206,7 +1206,7 @@ int i_APCI3XXX_InsnWriteTTLIO(struct comedi_device *dev,
if (b_Channel < 8) {
/*****************************************************************************/
- /* Read port 0 (first digital output port) and set/reset the selcted channel */
+ /* Read port 0 (first digital output port) and set/reset the selected channel */
/*****************************************************************************/
dw_Status = inl(devpriv->iobase + 80);
@@ -1228,7 +1228,7 @@ int i_APCI3XXX_InsnWriteTTLIO(struct comedi_device *dev,
if ((devpriv->ul_TTLPortConfiguration[0] & 0xFF)
== 0xFF) {
/*****************************************************************************/
- /* Read port 2 (first digital output port) and set/reset the selcted channel */
+ /* Read port 2 (first digital output port) and set/reset the selected channel */
/*****************************************************************************/
dw_Status = inl(devpriv->iobase + 112);
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index 791ea8334e1e..9934a3cf2548 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -88,9 +88,9 @@ Configuration options:
#define IORANGE_9118 64 /* I hope */
#define PCI9118_CHANLEN 255 /* len of chanlist, some source say 256, but reality looks like 255 :-( */
-#define PCI9118_CNT0 0x00 /* R/W: 8254 couter 0 */
-#define PCI9118_CNT1 0x04 /* R/W: 8254 couter 0 */
-#define PCI9118_CNT2 0x08 /* R/W: 8254 couter 0 */
+#define PCI9118_CNT0 0x00 /* R/W: 8254 counter 0 */
+#define PCI9118_CNT1 0x04 /* R/W: 8254 counter 0 */
+#define PCI9118_CNT2 0x08 /* R/W: 8254 counter 0 */
#define PCI9118_CNTCTRL 0x0c /* W: 8254 counter control */
#define PCI9118_AD_DATA 0x10 /* R: A/D data */
#define PCI9118_DA1 0x10 /* W: D/A registers */
diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c
index c5ed8bb97602..f3ba645bf63b 100644
--- a/drivers/staging/comedi/drivers/adq12b.c
+++ b/drivers/staging/comedi/drivers/adq12b.c
@@ -42,23 +42,23 @@ If you do not specify any options, they will default to
option 1: I/O base address. The following table is provided as a help
of the hardware jumpers.
- address jumper JADR
- 0x300 1 (factory default)
- 0x320 2
- 0x340 3
- 0x360 4
- 0x380 5
- 0x3A0 6
+ address jumper JADR
+ 0x300 1 (factory default)
+ 0x320 2
+ 0x340 3
+ 0x360 4
+ 0x380 5
+ 0x3A0 6
option 2: unipolar/bipolar ADC selection: 0 -> bipolar, 1 -> unipolar
- selection comedi_config option JUB
- bipolar 0 2-3 (factory default)
- unipolar 1 1-2
+ selection comedi_config option JUB
+ bipolar 0 2-3 (factory default)
+ unipolar 1 1-2
option 3: single-ended/differential AI selection: 0 -> SE, 1 -> differential
- selection comedi_config option JCHA JCHB
+ selection comedi_config option JCHA JCHB
single-ended 0 1-2 1-2 (factory default)
differential 1 2-3 2-3
@@ -140,7 +140,7 @@ static const struct adq12b_board adq12b_boards[] = {
.ai_bits = 12,
.di_chans = 8,
.do_chans = 5
- }*/
+ }*/
};
#define thisboard ((const struct adq12b_board *)dev->board_ptr)
@@ -164,14 +164,15 @@ struct adq12b_private {
static int adq12b_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
static int adq12b_detach(struct comedi_device *dev);
+
static struct comedi_driver driver_adq12b = {
-driver_name:"adq12b",
-module:THIS_MODULE,
-attach:adq12b_attach,
-detach:adq12b_detach,
-board_name:&adq12b_boards[0].name,
-offset:sizeof(struct adq12b_board),
-num_names:ARRAY_SIZE(adq12b_boards),
+ .driver_name = "adq12b",
+ .module = THIS_MODULE,
+ .attach = adq12b_attach,
+ .detach = adq12b_detach,
+ .board_name = &adq12b_boards[0].name,
+ .offset = sizeof(struct adq12b_board),
+ .num_names = ARRAY_SIZE(adq12b_boards),
};
static int adq12b_ai_rinsn(struct comedi_device *dev,
@@ -200,15 +201,16 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
unipolar = it->options[1];
differential = it->options[2];
- printk("comedi%d: adq12b called with options base=0x%03lx, %s and %s\n",
- dev->minor, iobase, (unipolar == 1) ? "unipolar" : "bipolar",
+ printk(KERN_INFO "comedi%d: adq12b called with options base=0x%03lx, "
+ "%s and %s\n", dev->minor, iobase,
+ (unipolar == 1) ? "unipolar" : "bipolar",
(differential == 1) ? "differential" : "single-ended");
/* if no address was specified, try the default 0x300 */
if (iobase == 0) {
- printk
- ("comedi%d: adq12b warning: I/O base address not specified. Trying the default 0x300.\n",
- dev->minor);
+ printk(KERN_WARNING "comedi%d: adq12b warning: I/O base "
+ "address not specified. Trying the default 0x300.\n",
+ dev->minor);
iobase = 0x300;
}
@@ -259,11 +261,10 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->n_chan = thisboard->ai_se_chans;
}
- if (unipolar) {
+ if (unipolar)
s->range_table = &range_adq12b_ai_unipolar;
- } else {
+ else
s->range_table = &range_adq12b_ai_bipolar;
- }
s->maxdata = (1 << thisboard->ai_bits) - 1;
@@ -289,7 +290,7 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->range_table = &range_digital;
s->insn_bits = adq12b_do_insn_bits;
- printk("attached\n");
+ printk(KERN_INFO "attached\n");
return 0;
}
@@ -309,7 +310,7 @@ static int adq12b_detach(struct comedi_device *dev)
kfree(devpriv);
- printk("comedi%d: adq12b: removed\n", dev->minor);
+ printk(KERN_INFO "comedi%d: adq12b: removed\n", dev->minor);
return 0;
}
@@ -344,17 +345,18 @@ static int adq12b_ai_rinsn(struct comedi_device *dev,
/* wait for end of convertion */
i = 0;
do {
-/* udelay(1); */
+ /* udelay(1); */
status = inb(dev->iobase + ADQ12B_STINR);
status = status & ADQ12B_EOC;
} while (status == 0 && ++i < TIMEOUT);
-/* } while (++i < 10); */
+ /* } while (++i < 10); */
/* read data */
hi = inb(dev->iobase + ADQ12B_ADHIG);
lo = inb(dev->iobase + ADQ12B_ADLOW);
- /* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n", channel, range, status, hi, lo); */
+ /* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n",
+ channel, range, status, hi, lo); */
data[n] = (hi << 8) | lo;
}
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index 951e57949f7f..394d2ea19c2e 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -84,9 +84,9 @@ Configuration options:
#define PCI171x_DAREF 14 /* W: D/A reference control */
#define PCI171x_DI 16 /* R: digi inputs */
#define PCI171x_DO 16 /* R: digi inputs */
-#define PCI171x_CNT0 24 /* R/W: 8254 couter 0 */
-#define PCI171x_CNT1 26 /* R/W: 8254 couter 1 */
-#define PCI171x_CNT2 28 /* R/W: 8254 couter 2 */
+#define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
+#define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
+#define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
#define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
/* upper bits from status register (PCI171x_STATUS) (lower is same woth control reg) */
@@ -724,6 +724,7 @@ static int move_block_from_fifo(struct comedi_device *dev,
devpriv->ai_act_scan++;
}
}
+ s->async->cur_chan = j;
DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
return 0;
}
@@ -1034,14 +1035,6 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
}
}
- if (!cmd->chanlist_len) {
- cmd->chanlist_len = 1;
- err++;
- }
- if (cmd->chanlist_len > this_board->n_aichan) {
- cmd->chanlist_len = this_board->n_aichan;
- err++;
- }
if (cmd->scan_end_arg != cmd->chanlist_len) {
cmd->scan_end_arg = cmd->chanlist_len;
err++;
@@ -1230,6 +1223,12 @@ static void setup_channel_list(struct comedi_device *dev,
DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
devpriv->act_chanlist[i]);
}
+#ifdef PCI171x_PARANOIDCHECK
+ for ( ; i < n_chan; i++) { /* store remainder of channel list */
+ devpriv->act_chanlist[i] =
+ (CR_CHAN(chanlist[i]) << 12) & 0xf000;
+ }
+#endif
devpriv->ai_et_MuxVal =
CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index 3857fd566d21..4baef9ff932a 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -98,7 +98,7 @@ static int aio_iiro_16_attach(struct comedi_device *dev,
int iobase;
struct comedi_subdevice *s;
- printk("comedi%d: aio_iiro_16: ", dev->minor);
+ printk(KERN_INFO "comedi%d: aio_iiro_16: ", dev->minor);
dev->board_name = thisboard->name;
@@ -140,7 +140,7 @@ static int aio_iiro_16_attach(struct comedi_device *dev,
static int aio_iiro_16_detach(struct comedi_device *dev)
{
- printk("comedi%d: aio_iiro_16: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: aio_iiro_16: remove\n", dev->minor);
if (dev->iobase)
release_region(dev->iobase, AIO_IIRO_16_SIZE);
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index 69ab2813dd2e..204f30ef6e96 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -48,8 +48,8 @@ Passing a zero for an option is the same as leaving it unspecified.
SUBDEVICES
- PC218E PC212E PC215E/PCI215
- ------------- ------------- -------------
+ PC218E PC212E PC215E/PCI215
+ ------------- ------------- -------------
Subdevices 7 6 5
0 CTR-X1 PPI-X PPI-X
1 CTR-X2 CTR-Y1 PPI-Y
@@ -59,8 +59,8 @@ SUBDEVICES
5 CTR-Z2 INTERRUPT
6 INTERRUPT
- PC214E PC272E/PCI272
- ------------- -------------
+ PC214E PC272E/PCI272
+ ------------- -------------
Subdevices 4 4
0 PPI-X PPI-X
1 PPI-Y PPI-Y
@@ -96,8 +96,8 @@ instructions are supported:
0 to 7 as follows:
0. CLK n, the counter channel's dedicated CLK input from the SK1
- connector. (N.B. for other values, the counter channel's CLKn
- pin on the SK1 connector is an output!)
+ connector. (N.B. for other values, the counter channel's CLKn
+ pin on the SK1 connector is an output!)
1. Internal 10 MHz clock.
2. Internal 1 MHz clock.
3. Internal 100 kHz clock.
@@ -105,8 +105,8 @@ instructions are supported:
5. Internal 1 kHz clock.
6. OUT n-1, the output of counter channel n-1 (see note 1 below).
7. Ext Clock, the counter chip's dedicated Ext Clock input from
- the SK1 connector. This pin is shared by all three counter
- channels on the chip.
+ the SK1 connector. This pin is shared by all three counter
+ channels on the chip.
INSN_CONFIG_GET_CLOCK_SRC. Returns the counter channel's current
clock source in data[1]. For internal clock sources, data[2] is set
@@ -120,10 +120,10 @@ instructions are supported:
0. VCC (internal +5V d.c.), i.e. gate permanently enabled.
1. GND (internal 0V d.c.), i.e. gate permanently disabled.
2. GAT n, the counter channel's dedicated GAT input from the SK1
- connector. (N.B. for other values, the counter channel's GATn
- pin on the SK1 connector is an output!)
+ connector. (N.B. for other values, the counter channel's GATn
+ pin on the SK1 connector is an output!)
3. /OUT n-2, the inverted output of counter channel n-2 (see note
- 2 below).
+ 2 below).
4. Reserved.
5. Reserved.
6. Reserved.
@@ -153,8 +153,8 @@ below.
INTERRUPT SOURCES
- PC218E PC212E PC215E/PCI215
- ------------- ------------- -------------
+ PC218E PC212E PC215E/PCI215
+ ------------- ------------- -------------
Sources 6 6 6
0 CTR-X1-OUT PPI-X-C0 PPI-X-C0
1 CTR-X2-OUT PPI-X-C3 PPI-X-C3
@@ -163,8 +163,8 @@ INTERRUPT SOURCES
4 CTR-Z1-OUT CTR-Z1-OUT CTR-Z1-OUT
5 CTR-Z2-OUT CTR-Z2-OUT CTR-Z2-OUT
- PC214E PC272E/PCI272
- ------------- -------------
+ PC214E PC272E/PCI272
+ ------------- -------------
Sources 1 6
0 JUMPER-J5 PPI-X-C0
1 PPI-X-C3
@@ -435,11 +435,13 @@ MODULE_DEVICE_TABLE(pci, dio200_pci_table);
* Useful for shorthand access to the particular board structure
*/
#define thisboard ((const struct dio200_board *)dev->board_ptr)
-#define thislayout (&dio200_layouts[((struct dio200_board *)dev->board_ptr)->layout])
+#define thislayout (&dio200_layouts[((struct dio200_board *) \
+ dev->board_ptr)->layout])
/* this structure is for data unique to this hardware driver. If
several hardware drivers keep similar information in this structure,
- feel free to suggest moving the variable to the struct comedi_device struct. */
+ feel free to suggest moving the variable to the struct comedi_device struct.
+ */
struct dio200_private {
#ifdef CONFIG_COMEDI_PCI
struct pci_dev *pci_dev; /* PCI device */
@@ -603,9 +605,8 @@ static void dio200_stop_intr(struct comedi_device *dev,
subpriv->active = 0;
subpriv->enabled_isns = 0;
- if (subpriv->has_int_sce) {
+ if (subpriv->has_int_sce)
outb(0, subpriv->iobase);
- }
}
/*
@@ -629,16 +630,14 @@ static int dio200_start_intr(struct comedi_device *dev,
/* Determine interrupt sources to enable. */
isn_bits = 0;
if (cmd->chanlist) {
- for (n = 0; n < cmd->chanlist_len; n++) {
+ for (n = 0; n < cmd->chanlist_len; n++)
isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
- }
}
isn_bits &= subpriv->valid_isns;
/* Enable interrupt sources. */
subpriv->enabled_isns = isn_bits;
- if (subpriv->has_int_sce) {
+ if (subpriv->has_int_sce)
outb(isn_bits, subpriv->iobase);
- }
}
return retval;
@@ -662,14 +661,13 @@ dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
spin_lock_irqsave(&subpriv->spinlock, flags);
s->async->inttrig = 0;
- if (subpriv->active) {
+ if (subpriv->active)
event = dio200_start_intr(dev, s);
- }
+
spin_unlock_irqrestore(&subpriv->spinlock, flags);
- if (event) {
+ if (event)
comedi_event(dev, s);
- }
return 1;
}
@@ -726,9 +724,8 @@ static int dio200_handle_read_intr(struct comedi_device *dev,
* Reenable them NOW to minimize the time they are disabled.
*/
cur_enabled = subpriv->enabled_isns;
- if (subpriv->has_int_sce) {
+ if (subpriv->has_int_sce)
outb(cur_enabled, subpriv->iobase);
- }
if (subpriv->active) {
/*
@@ -747,9 +744,8 @@ static int dio200_handle_read_intr(struct comedi_device *dev,
len = s->async->cmd.chanlist_len;
for (n = 0; n < len; n++) {
ch = CR_CHAN(s->async->cmd.chanlist[n]);
- if (triggered & (1U << ch)) {
+ if (triggered & (1U << ch))
val |= (1U << n);
- }
}
/* Write the scan to the buffer. */
if (comedi_buf_put(s->async, val)) {
@@ -781,9 +777,8 @@ static int dio200_handle_read_intr(struct comedi_device *dev,
}
spin_unlock_irqrestore(&subpriv->spinlock, flags);
- if (oldevents != s->async->events) {
+ if (oldevents != s->async->events)
comedi_event(dev, s);
- }
return (triggered != 0);
}
@@ -798,9 +793,9 @@ static int dio200_subdev_intr_cancel(struct comedi_device *dev,
unsigned long flags;
spin_lock_irqsave(&subpriv->spinlock, flags);
- if (subpriv->active) {
+ if (subpriv->active)
dio200_stop_intr(dev, s);
- }
+
spin_unlock_irqrestore(&subpriv->spinlock, flags);
return 0;
@@ -846,7 +841,8 @@ dio200_subdev_intr_cmdtest(struct comedi_device *dev,
if (err)
return 1;
- /* step 2: make sure trigger sources are unique and mutually compatible */
+ /* step 2: make sure trigger sources are unique and mutually
+ compatible */
/* these tests are true if more than one _src bit is set */
if ((cmd->start_src & (cmd->start_src - 1)) != 0)
@@ -952,9 +948,8 @@ static int dio200_subdev_intr_cmd(struct comedi_device *dev,
}
spin_unlock_irqrestore(&subpriv->spinlock, flags);
- if (event) {
+ if (event)
comedi_event(dev, s);
- }
return 0;
}
@@ -980,9 +975,8 @@ dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
subpriv->valid_isns = valid_isns;
spin_lock_init(&subpriv->spinlock);
- if (has_int_sce) {
+ if (has_int_sce)
outb(0, subpriv->iobase); /* Disable interrupt sources. */
- }
s->private = subpriv;
s->type = COMEDI_SUBD_DI;
@@ -1013,10 +1007,7 @@ dio200_subdev_intr_cleanup(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct dio200_subdev_intr *subpriv = s->private;
-
- if (subpriv) {
- kfree(subpriv);
- }
+ kfree(subpriv);
}
/*
@@ -1027,9 +1018,8 @@ static irqreturn_t dio200_interrupt(int irq, void *d)
struct comedi_device *dev = d;
int handled;
- if (!dev->attached) {
+ if (!dev->attached)
return IRQ_NONE;
- }
if (devpriv->intr_sd >= 0) {
handled = dio200_handle_read_intr(dev,
@@ -1266,10 +1256,7 @@ dio200_subdev_8254_cleanup(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct dio200_subdev_intr *subpriv = s->private;
-
- if (subpriv) {
- kfree(subpriv);
- }
+ kfree(subpriv);
}
/*
@@ -1348,9 +1335,8 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
#endif
{
ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE);
- if (ret < 0) {
+ if (ret < 0)
return ret;
- }
}
dev->iobase = iobase;
@@ -1371,17 +1357,17 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
ret = dio200_subdev_8254_init(dev, s, iobase,
layout->sdinfo[n],
layout->has_clk_gat_sce);
- if (ret < 0) {
+ if (ret < 0)
return ret;
- }
+
break;
case sd_8255:
/* digital i/o subdevice (8255) */
ret = subdev_8255_init(dev, s, 0,
iobase + layout->sdinfo[n]);
- if (ret < 0) {
+ if (ret < 0)
return ret;
- }
+
break;
case sd_intr:
/* 'INTERRUPT' subdevice */
@@ -1392,9 +1378,9 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
layout->sdinfo[n],
layout->
has_int_sce);
- if (ret < 0) {
+ if (ret < 0)
return ret;
- }
+
devpriv->intr_sd = n;
} else {
s->type = COMEDI_SUBD_UNUSED;
@@ -1407,9 +1393,8 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
sdx = devpriv->intr_sd;
- if (sdx >= 0 && sdx < dev->n_subdevices) {
+ if (sdx >= 0 && sdx < dev->n_subdevices)
dev->read_subdev = &dev->subdevices[sdx];
- }
dev->board_name = thisboard->name;
@@ -1434,11 +1419,10 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
printk("(pci %s) ", pci_name(pci_dev));
#endif
}
- if (irq) {
+ if (irq)
printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
- } else {
+ else
printk("(no irq) ");
- }
printk("attached\n");
@@ -1461,9 +1445,8 @@ static int dio200_detach(struct comedi_device *dev)
printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
DIO200_DRIVER_NAME);
- if (dev->irq) {
+ if (dev->irq)
free_irq(dev->irq, dev);
- }
if (dev->subdevices) {
layout = thislayout;
for (n = 0; n < dev->n_subdevices; n++) {
@@ -1486,22 +1469,19 @@ static int dio200_detach(struct comedi_device *dev)
if (devpriv) {
#ifdef CONFIG_COMEDI_PCI
if (devpriv->pci_dev) {
- if (dev->iobase) {
+ if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
- }
pci_dev_put(devpriv->pci_dev);
} else
#endif
{
- if (dev->iobase) {
+ if (dev->iobase)
release_region(dev->iobase, DIO200_IO_SIZE);
- }
}
}
- if (dev->board_name) {
+ if (dev->board_name)
printk(KERN_INFO "comedi%d: %s removed\n",
dev->minor, dev->board_name);
- }
return 0;
}
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index 1032a8110d6e..a307d68d79c6 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236.c
@@ -78,18 +78,18 @@ unused.
*/
/* Disable interrupt, also clear any interrupt there */
#define PCI236_INTR_DISABLE (PLX9052_INTCSR_LI1ENAB_DISABLED \
- | PLX9052_INTCSR_LI1POL_HIGH \
- | PLX9052_INTCSR_LI2POL_HIGH \
- | PLX9052_INTCSR_PCIENAB_DISABLED \
- | PLX9052_INTCSR_LI1SEL_EDGE \
- | PLX9052_INTCSR_LI1CLRINT_ASSERTED)
+ | PLX9052_INTCSR_LI1POL_HIGH \
+ | PLX9052_INTCSR_LI2POL_HIGH \
+ | PLX9052_INTCSR_PCIENAB_DISABLED \
+ | PLX9052_INTCSR_LI1SEL_EDGE \
+ | PLX9052_INTCSR_LI1CLRINT_ASSERTED)
/* Enable interrupt, also clear any interrupt there. */
#define PCI236_INTR_ENABLE (PLX9052_INTCSR_LI1ENAB_ENABLED \
- | PLX9052_INTCSR_LI1POL_HIGH \
- | PLX9052_INTCSR_LI2POL_HIGH \
- | PLX9052_INTCSR_PCIENAB_ENABLED \
- | PLX9052_INTCSR_LI1SEL_EDGE \
- | PLX9052_INTCSR_LI1CLRINT_ASSERTED)
+ | PLX9052_INTCSR_LI1POL_HIGH \
+ | PLX9052_INTCSR_LI2POL_HIGH \
+ | PLX9052_INTCSR_PCIENAB_ENABLED \
+ | PLX9052_INTCSR_LI1SEL_EDGE \
+ | PLX9052_INTCSR_LI1CLRINT_ASSERTED)
/*
* Board descriptions for Amplicon PC36AT and PCI236.
@@ -150,12 +150,13 @@ MODULE_DEVICE_TABLE(pci, pc236_pci_table);
/* this structure is for data unique to this hardware driver. If
several hardware drivers keep similar information in this structure,
- feel free to suggest moving the variable to the struct comedi_device struct. */
+ feel free to suggest moving the variable to the struct comedi_device struct.
+ */
struct pc236_private {
#ifdef CONFIG_COMEDI_PCI
/* PCI device */
struct pci_dev *pci_dev;
- unsigned long lcr_iobase; /* PLX PCI9052 config registers in PCIBAR1 */
+ unsigned long lcr_iobase; /* PLX PCI9052 config registers in PCIBAR1 */
#endif
int enable_irq;
};
@@ -345,9 +346,8 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
#endif
{
ret = pc236_request_region(dev->minor, iobase, PC236_IO_SIZE);
- if (ret < 0) {
+ if (ret < 0)
return ret;
- }
}
dev->iobase = iobase;
@@ -399,11 +399,10 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
printk("(pci %s) ", pci_name(pci_dev));
#endif
}
- if (irq) {
+ if (irq)
printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
- } else {
+ else
printk("(no irq) ");
- }
printk("attached\n");
@@ -422,27 +421,24 @@ static int pc236_detach(struct comedi_device *dev)
{
printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
PC236_DRIVER_NAME);
- if (devpriv) {
+ if (devpriv)
pc236_intr_disable(dev);
- }
+
if (dev->irq)
free_irq(dev->irq, dev);
- if (dev->subdevices) {
+ if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 0);
- }
if (devpriv) {
#ifdef CONFIG_COMEDI_PCI
if (devpriv->pci_dev) {
- if (dev->iobase) {
+ if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
- }
pci_dev_put(devpriv->pci_dev);
} else
#endif
{
- if (dev->iobase) {
+ if (dev->iobase)
release_region(dev->iobase, PC236_IO_SIZE);
- }
}
}
if (dev->board_name) {
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index d9836879355e..b41e5e5963aa 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -1536,20 +1536,12 @@ static int pci224_detach(struct comedi_device *dev)
s = dev->subdevices + 0;
/* AO subdevice */
- if (s->range_table_list) {
- kfree(s->range_table_list);
- }
+ kfree(s->range_table_list);
}
if (devpriv) {
- if (devpriv->ao_readback) {
- kfree(devpriv->ao_readback);
- }
- if (devpriv->ao_scan_vals) {
- kfree(devpriv->ao_scan_vals);
- }
- if (devpriv->ao_scan_order) {
- kfree(devpriv->ao_scan_order);
- }
+ kfree(devpriv->ao_readback);
+ kfree(devpriv->ao_scan_vals);
+ kfree(devpriv->ao_scan_order);
if (devpriv->pci_dev) {
if (dev->iobase) {
comedi_pci_disable(devpriv->pci_dev);
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index abb0532182ba..fb0d5fa71765 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -45,7 +45,7 @@ http://robot0.ge.uiuc.edu/~spong/mecha/
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/timer.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/pnp.h>
#include "../comedidev.h"
@@ -220,11 +220,11 @@ static int C6X_encInput(unsigned long baseAddr, unsigned channel)
/* printk("Inside C6X_encInput\n"); */
enc.value = 0;
- if (channel == 0) {
+ if (channel == 0)
ppcmd = 0x48;
- } else {
+ else
ppcmd = 0x50;
- }
+
WriteByteToHwPort(baseAddr, ppcmd);
tmp = ReadByteFromHwPort(baseAddr + 1);
while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
@@ -391,9 +391,8 @@ static int c6xdigio_ei_insn_read(struct comedi_device *dev,
int n;
int chan = CR_CHAN(insn->chanspec);
- for (n = 0; n < insn->n; n++) {
+ for (n = 0; n < insn->n; n++)
data[n] = (C6X_encInput(dev->iobase, chan) & 0xffffff);
- }
return n;
}
@@ -420,9 +419,9 @@ static void board_init(struct comedi_device *dev)
static const struct pnp_device_id c6xdigio_pnp_tbl[] = {
/* Standard LPT Printer Port */
- {.id = "PNP0400",.driver_data = 0},
+ {.id = "PNP0400", .driver_data = 0},
/* ECP Printer Port */
- {.id = "PNP0401",.driver_data = 0},
+ {.id = "PNP0401", .driver_data = 0},
{}
};
@@ -452,15 +451,14 @@ static int c6xdigio_attach(struct comedi_device *dev,
if (result < 0)
return result;
- /* Make sure that PnP ports gets activated */
+ /* Make sure that PnP ports get activated */
pnp_register_driver(&c6xdigio_pnp_driver);
irq = it->options[1];
- if (irq > 0) {
+ if (irq > 0)
printk("comedi%d: irq = %u ignored\n", dev->minor, irq);
- } else if (irq == 0) {
+ else if (irq == 0)
printk("comedi%d: no irq\n", dev->minor);
- }
s = dev->subdevices + 0;
/* pwm output subdevice */
@@ -483,19 +481,19 @@ static int c6xdigio_attach(struct comedi_device *dev,
s->maxdata = 0xffffff;
s->range_table = &range_unknown;
- /* s = dev->subdevices + 2; */
+ /* s = dev->subdevices + 2; */
/* pwm output subdevice */
- /* s->type = COMEDI_SUBD_COUNTER; // Not sure what to put here */
- /* s->subdev_flags = SDF_WRITEABLE; */
- /* s->n_chan = 1; */
- /* s->trig[0] = c6xdigio_ei_init; */
- /* s->insn_read = c6xdigio_ei_init_insn_read; */
- /* s->insn_write = c6xdigio_ei_init_insn_write; */
- /* s->maxdata = 0xFFFF; // Really just a don't care */
- /* s->range_table = &range_unknown; // Not sure what to put here */
-
- /* I will call this init anyway but more than likely the DSP board will not be connect */
- /* when device driver is loaded. */
+ /* s->type = COMEDI_SUBD_COUNTER; // Not sure what to put here */
+ /* s->subdev_flags = SDF_WRITEABLE; */
+ /* s->n_chan = 1; */
+ /* s->trig[0] = c6xdigio_ei_init; */
+ /* s->insn_read = c6xdigio_ei_init_insn_read; */
+ /* s->insn_write = c6xdigio_ei_init_insn_write; */
+ /* s->maxdata = 0xFFFF; // Really just a don't care */
+ /* s->range_table = &range_unknown; // Not sure what to put here */
+
+ /* I will call this init anyway but more than likely the DSP board */
+ /* will not be connected when device driver is loaded. */
board_init(dev);
return 0;
@@ -503,16 +501,17 @@ static int c6xdigio_attach(struct comedi_device *dev,
static int c6xdigio_detach(struct comedi_device *dev)
{
-/* board_halt(dev); may not need this */
+ /* board_halt(dev); may not need this */
printk("comedi%d: c6xdigio: remove\n", dev->minor);
- if (dev->iobase) {
+ if (dev->iobase)
release_region(dev->iobase, C6XDIGIO_SIZE);
- }
- if (dev->irq) {
+
+ /* Not using IRQ so I am not sure if I need this */
+ if (dev->irq)
free_irq(dev->irq, dev);
- } /* Not using IRQ so I am not sure if I need this */
+
pnp_unregister_driver(&c6xdigio_pnp_driver);
return 0;
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index f3e66c440a38..434591de37c5 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -518,7 +518,7 @@ static int trimpot_7376_write(struct comedi_device *dev, uint8_t value);
static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel,
uint8_t value);
static int nvram_read(struct comedi_device *dev, unsigned int address,
- uint8_t * data);
+ uint8_t *data);
static inline unsigned int cal_enable_bits(struct comedi_device *dev)
{
@@ -760,9 +760,8 @@ static int cb_pcidas_detach(struct comedi_device *dev)
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 2);
if (devpriv && devpriv->pci_dev) {
- if (devpriv->s5933_config) {
+ if (devpriv->s5933_config)
comedi_pci_disable(devpriv->pci_dev);
- }
pci_dev_put(devpriv->pci_dev);
}
@@ -1248,9 +1247,8 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev,
cmd->flags & TRIG_ROUND_MASK);
/* set number of conversions */
- if (cmd->stop_src == TRIG_COUNT) {
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->count = cmd->chanlist_len * cmd->stop_arg;
- }
/* enable interrupts */
spin_lock_irqsave(&dev->spinlock, flags);
devpriv->adc_fifo_bits |= INTE;
@@ -1449,9 +1447,8 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev,
devpriv->ao_divisor2, 2);
}
/* set number of conversions */
- if (cmd->stop_src == TRIG_COUNT) {
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg;
- }
/* set pacer source */
spin_lock_irqsave(&dev->spinlock, flags);
switch (cmd->scan_begin_src) {
@@ -1494,9 +1491,8 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
num_points * sizeof(short));
num_points = num_bytes / sizeof(short);
- if (cmd->stop_src == TRIG_COUNT) {
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->ao_count -= num_points;
- }
/* write data to board's fifo */
outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_bytes);
@@ -1534,9 +1530,8 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
static const int timeout = 10000;
unsigned long flags;
- if (dev->attached == 0) {
+ if (dev->attached == 0)
return IRQ_NONE;
- }
async = s->async;
async->events = 0;
@@ -1558,15 +1553,13 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
status = inw(devpriv->control_status + INT_ADCFIFO);
#ifdef CB_PCIDAS_DEBUG
- if ((status & (INT | EOAI | LADFUL | DAHFI | DAEMI)) == 0) {
+ if ((status & (INT | EOAI | LADFUL | DAHFI | DAEMI)) == 0)
comedi_error(dev, "spurious interrupt");
- }
#endif
/* check for analog output interrupt */
- if (status & (DAHFI | DAEMI)) {
+ if (status & (DAHFI | DAEMI))
handle_ao_interrupt(dev, status);
- }
/* check for analog input interrupts */
/* if fifo half-full */
if (status & ADHFI) {
@@ -1675,9 +1668,8 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
num_points * sizeof(short));
num_points = num_bytes / sizeof(short);
- if (async->cmd.stop_src == TRIG_COUNT) {
+ if (async->cmd.stop_src == TRIG_COUNT)
devpriv->ao_count -= num_points;
- }
/* write data to board's fifo */
outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer,
num_points);
@@ -1852,7 +1844,7 @@ static int wait_for_nvram_ready(unsigned long s5933_base_addr)
}
static int nvram_read(struct comedi_device *dev, unsigned int address,
- uint8_t * data)
+ uint8_t *data)
{
unsigned long iobase = devpriv->s5933_config;
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index 782357732eed..81829d6fd287 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -410,9 +410,8 @@ static int cb_pcidda_detach(struct comedi_device *dev)
*/
if (devpriv) {
if (devpriv->pci_dev) {
- if (devpriv->dac) {
+ if (devpriv->dac)
comedi_pci_disable(devpriv->pci_dev);
- }
pci_dev_put(devpriv->pci_dev);
}
}
@@ -677,9 +676,8 @@ static unsigned int cb_pcidda_serial_in(struct comedi_device *dev)
for (i = 1; i <= value_width; i++) {
/* read bits most significant bit first */
- if (inw_p(devpriv->dac + DACALIBRATION1) & SERIAL_OUT_BIT) {
+ if (inw_p(devpriv->dac + DACALIBRATION1) & SERIAL_OUT_BIT)
value |= 1 << (value_width - i);
- }
}
return value;
@@ -716,9 +714,8 @@ static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
/* send serial output stream to eeprom */
cal2_bits = SELECT_EEPROM_BIT | DESELECT_REF_DAC_BIT | DUMMY_BIT;
/* deactivate caldacs (one caldac for every two channels) */
- for (i = 0; i < max_num_caldacs; i++) {
+ for (i = 0; i < max_num_caldacs; i++)
cal2_bits |= DESELECT_CALDAC_BIT(i);
- }
outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);
/* tell eeprom we want to read */
@@ -756,9 +753,8 @@ static void cb_pcidda_write_caldac(struct comedi_device *dev,
*/
cal2_bits = DESELECT_REF_DAC_BIT | DUMMY_BIT;
/* deactivate caldacs (one caldac for every two channels) */
- for (i = 0; i < max_num_caldacs; i++) {
+ for (i = 0; i < max_num_caldacs; i++)
cal2_bits |= DESELECT_CALDAC_BIT(i);
- }
/* activate the caldac we want */
cal2_bits &= ~DESELECT_CALDAC_BIT(caldac);
outw_p(cal2_bits, devpriv->dac + DACALIBRATION2);
diff --git a/drivers/staging/comedi/drivers/cb_pcidio.c b/drivers/staging/comedi/drivers/cb_pcidio.c
index 7daad0a17fb1..38ccd105fa35 100644
--- a/drivers/staging/comedi/drivers/cb_pcidio.c
+++ b/drivers/staging/comedi/drivers/cb_pcidio.c
@@ -283,17 +283,15 @@ static int pcidio_detach(struct comedi_device *dev)
printk("comedi%d: cb_pcidio: remove\n", dev->minor);
if (devpriv) {
if (devpriv->pci_dev) {
- if (devpriv->dio_reg_base) {
+ if (devpriv->dio_reg_base)
comedi_pci_disable(devpriv->pci_dev);
- }
pci_dev_put(devpriv->pci_dev);
}
}
if (dev->subdevices) {
int i;
- for (i = 0; i < thisboard->n_8255; i++) {
+ for (i = 0; i < thisboard->n_8255; i++)
subdev_8255_cleanup(dev, dev->subdevices + i);
- }
}
return 0;
}
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index cbbca05acb96..2e61727fc9a0 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -330,11 +330,10 @@ found:
s = dev->subdevices + 2;
/* digital i/o subdevice */
- if (thisboard->has_dio) {
+ if (thisboard->has_dio)
subdev_8255_init(dev, s, NULL, devpriv->BADR4);
- } else {
+ else
s->type = COMEDI_SUBD_UNUSED;
- }
printk("attached\n");
@@ -365,9 +364,8 @@ static int cb_pcimdas_detach(struct comedi_device *dev)
free_irq(dev->irq, dev);
if (devpriv) {
if (devpriv->pci_dev) {
- if (devpriv->BADR0) {
+ if (devpriv->BADR0)
comedi_pci_disable(devpriv->pci_dev);
- }
pci_dev_put(devpriv->pci_dev);
}
}
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index 980fa0aacf92..e32a31763d50 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdda.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdda.c
@@ -284,11 +284,10 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->n_chan = thisboard->ao_chans;
s->maxdata = figure_out_maxdata(thisboard->ao_bits);
/* this is hard-coded here */
- if (it->options[2]) {
+ if (it->options[2])
s->range_table = &range_bipolar10;
- } else {
+ else
s->range_table = &range_bipolar5;
- }
s->insn_write = &ao_winsn;
s->insn_read = &ao_rinsn;
@@ -337,9 +336,8 @@ static int detach(struct comedi_device *dev)
}
if (devpriv->pci_dev) {
- if (devpriv->registers) {
+ if (devpriv->registers)
comedi_pci_disable(devpriv->pci_dev);
- }
pci_dev_put(devpriv->pci_dev);
}
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index cf39a24ddd4c..d7260cc86985 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -417,7 +417,7 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
int sdev = -1, nchans, tmp;
struct BondedDevice *bdev = NULL;
- if (minor < 0 || minor > COMEDI_NUM_BOARD_MINORS) {
+ if (minor < 0 || minor >= COMEDI_NUM_BOARD_MINORS) {
ERROR("Minor %d is invalid!\n", minor);
return 0;
}
diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c
index b16d652f7763..9511814e6413 100644
--- a/drivers/staging/comedi/drivers/contec_pci_dio.c
+++ b/drivers/staging/comedi/drivers/contec_pci_dio.c
@@ -173,9 +173,8 @@ static int contec_detach(struct comedi_device *dev)
printk("comedi%d: contec: remove\n", dev->minor);
if (devpriv && devpriv->pci_dev) {
- if (dev->iobase) {
+ if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
- }
pci_dev_put(devpriv->pci_dev);
}
diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c
index 9b945e5fdd32..f12ef1cd6f53 100644
--- a/drivers/staging/comedi/drivers/das08_cs.c
+++ b/drivers/staging/comedi/drivers/das08_cs.c
@@ -34,7 +34,7 @@ This is the PCMCIA-specific support split off from the
das08 driver.
Options (for pcm-das08):
- NONE
+ NONE
Command support does not exist, but could be added for this board.
*/
@@ -52,7 +52,7 @@ Command support does not exist, but could be added for this board.
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
-static struct pcmcia_device *cur_dev = NULL;
+static struct pcmcia_device *cur_dev;
#define thisboard ((const struct das08_board_struct *)dev->board_ptr)
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index 92487f58fd8b..a404a1831911 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -45,7 +45,7 @@ This driver has suffered bitrot.
#define DAS6402_SIZE 16
-#define N_WORDS 3000*64
+#define N_WORDS (3000*64)
#define STOP 0
#define START 1
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index ecb97cdbce26..aadc4971c909 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -399,9 +399,8 @@ static irqreturn_t das800_interrupt(int irq, void *d)
} else {
fifo_empty = 0; /* cio-das802/16 has no fifo empty status bit */
}
- if (fifo_empty) {
+ if (fifo_empty)
break;
- }
/* strip off extraneous bits for 12 bit cards */
if (thisboard->resolution == 12)
dataPoint = (dataPoint >> 4) & 0xfff;
@@ -457,9 +456,8 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
int board;
printk("comedi%d: das800: io 0x%lx", dev->minor, iobase);
- if (irq) {
+ if (irq)
printk(", irq %u", irq);
- }
printk("\n");
/* allocate and initialize dev->private */
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index 9db9a467c8f8..d5cbd515c370 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -1048,11 +1048,10 @@ static int dmm32at_dio_insn_config(struct comedi_device *dev,
* value COMEDI_INPUT or COMEDI_OUTPUT. */
/* if output clear the bit, otherwise set it */
- if (data[0] == COMEDI_OUTPUT) {
+ if (data[0] == COMEDI_OUTPUT)
devpriv->dio_config &= ~chanbit;
- } else {
+ else
devpriv->dio_config |= chanbit;
- }
/* get access to the DIO regs */
dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC);
/* set the DIO's to the new configuration setting */
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index 7b9af5d755e0..3f365aee4822 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -18,10 +18,10 @@ Configuration options:
[1] - unused
[2] - A/D reference 0=differential, 1=single-ended
[3] - A/D range
- 0 = [-10,10]
+ 0 = [-10, 10]
1 = [0,10]
[4] - D/A 0 range
- 0 = [-10,10]
+ 0 = [-10, 10]
1 = [-5,5]
2 = [-2.5,2.5]
3 = [0,10]
@@ -279,9 +279,8 @@ static int dt2801_readdata(struct comedi_device *dev, int *data)
do {
stat = inb_p(dev->iobase + DT2801_STATUS);
- if (stat & (DT_S_COMPOSITE_ERROR | DT_S_READY)) {
+ if (stat & (DT_S_COMPOSITE_ERROR | DT_S_READY))
return stat;
- }
if (stat & DT_S_DATA_OUT_READY) {
*data = inb_p(dev->iobase + DT2801_DATA);
return 0;
@@ -315,9 +314,8 @@ static int dt2801_writedata(struct comedi_device *dev, unsigned int data)
do {
stat = inb_p(dev->iobase + DT2801_STATUS);
- if (stat & DT_S_COMPOSITE_ERROR) {
+ if (stat & DT_S_COMPOSITE_ERROR)
return stat;
- }
if (!(stat & DT_S_DATA_IN_FULL)) {
outb_p(data & 0xff, dev->iobase + DT2801_DATA);
return 0;
@@ -354,18 +352,15 @@ static int dt2801_wait_for_ready(struct comedi_device *dev)
int stat;
stat = inb_p(dev->iobase + DT2801_STATUS);
- if (stat & DT_S_READY) {
+ if (stat & DT_S_READY)
return 0;
- }
do {
stat = inb_p(dev->iobase + DT2801_STATUS);
- if (stat & DT_S_COMPOSITE_ERROR) {
+ if (stat & DT_S_COMPOSITE_ERROR)
return stat;
- }
- if (stat & DT_S_READY) {
+ if (stat & DT_S_READY)
return 0;
- }
} while (--timeout > 0);
return -ETIME;
@@ -382,9 +377,8 @@ static int dt2801_writecmd(struct comedi_device *dev, int command)
printk
("dt2801: composite-error in dt2801_writecmd(), ignoring\n");
}
- if (!(stat & DT_S_READY)) {
+ if (!(stat & DT_S_READY))
printk("dt2801: !ready in dt2801_writecmd(), ignoring\n");
- }
outb_p(command, dev->iobase + DT2801_CMD);
return 0;
@@ -418,9 +412,8 @@ static int dt2801_reset(struct comedi_device *dev)
if (stat & DT_S_READY)
break;
} while (timeout--);
- if (!timeout) {
+ if (!timeout)
printk("dt2801: timeout 1 status=0x%02x\n", stat);
- }
/* printk("dt2801: reading dummy\n"); */
/* dt2801_readdata(dev,&board_code); */
@@ -436,9 +429,8 @@ static int dt2801_reset(struct comedi_device *dev)
if (stat & DT_S_READY)
break;
} while (timeout--);
- if (!timeout) {
+ if (!timeout)
printk("dt2801: timeout 2 status=0x%02x\n", stat);
- }
DPRINTK("dt2801: reading code\n");
dt2801_readdata(dev, &board_code);
@@ -623,11 +615,10 @@ static int dt2801_detach(struct comedi_device *dev)
static int dt2801_error(struct comedi_device *dev, int stat)
{
if (stat < 0) {
- if (stat == -ETIME) {
+ if (stat == -ETIME)
printk("dt2801: timeout\n");
- } else {
+ else
printk("dt2801: error %d\n", stat);
- }
return stat;
}
printk("dt2801: error status 0x%02x, resetting...\n", stat);
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index d1db93c043a8..d1a4f7822433 100644
--- a/drivers/staging/comedi/drivers/dt2815.c
+++ b/drivers/staging/comedi/drivers/dt2815.c
@@ -34,19 +34,19 @@ Configuration options:
[0] - I/O port base base address
[1] - IRQ (unused)
[2] - Voltage unipolar/bipolar configuration
- 0 == unipolar 5V (0V -- +5V)
- 1 == bipolar 5V (-5V -- +5V)
+ 0 == unipolar 5V (0V -- +5V)
+ 1 == bipolar 5V (-5V -- +5V)
[3] - Current offset configuration
- 0 == disabled (0mA -- +32mAV)
- 1 == enabled (+4mA -- +20mAV)
+ 0 == disabled (0mA -- +32mAV)
+ 1 == enabled (+4mA -- +20mAV)
[4] - Firmware program configuration
- 0 == program 1 (see manual table 5-4)
- 1 == program 2 (see manual table 5-4)
- 2 == program 3 (see manual table 5-4)
- 3 == program 4 (see manual table 5-4)
+ 0 == program 1 (see manual table 5-4)
+ 1 == program 2 (see manual table 5-4)
+ 2 == program 3 (see manual table 5-4)
+ 3 == program 4 (see manual table 5-4)
[5] - Analog output 0 range configuration
- 0 == voltage
- 1 == current
+ 0 == voltage
+ 1 == current
[6] - Analog output 1 range configuration (same options)
[7] - Analog output 2 range configuration (same options)
[8] - Analog output 3 range configuration (same options)
@@ -61,17 +61,11 @@ Configuration options:
#include <linux/ioport.h>
#include <linux/delay.h>
-static const struct comedi_lrange range_dt2815_ao_32_current = { 1, {
- RANGE_mA(0,
- 32)
- }
-};
+static const struct comedi_lrange
+ range_dt2815_ao_32_current = {1, {RANGE_mA(0, 32)} };
-static const struct comedi_lrange range_dt2815_ao_20_current = { 1, {
- RANGE_mA(4,
- 20)
- }
-};
+static const struct comedi_lrange
+ range_dt2815_ao_20_current = {1, {RANGE_mA(4, 20)} };
#define DT2815_SIZE 2
@@ -118,9 +112,8 @@ static int dt2815_ao_insn_read(struct comedi_device *dev,
int i;
int chan = CR_CHAN(insn->chanspec);
- for (i = 0; i < insn->n; i++) {
+ for (i = 0; i < insn->n; i++)
data[i] = devpriv->ao_readback[chan];
- }
return i;
}
@@ -139,9 +132,8 @@ static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
status = dt2815_wait_for_status(dev, 0x00);
if (status != 0) {
- printk
- ("dt2815: failed to write low byte on %d reason %x\n",
- chan, status);
+ printk(KERN_WARNING "dt2815: failed to write low byte "
+ "on %d reason %x\n", chan, status);
return -EBUSY;
}
@@ -149,9 +141,8 @@ static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
status = dt2815_wait_for_status(dev, 0x10);
if (status != 0x10) {
- printk
- ("dt2815: failed to write high byte on %d reason %x\n",
- chan, status);
+ printk(KERN_WARNING "dt2815: failed to write high byte "
+ "on %d reason %x\n", chan, status);
return -EBUSY;
}
devpriv->ao_readback[chan] = data[i];
@@ -163,24 +154,24 @@ static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
options[0] Board base address
options[1] IRQ (not applicable)
options[2] Voltage unipolar/bipolar configuration
- 0 == unipolar 5V (0V -- +5V)
- 1 == bipolar 5V (-5V -- +5V)
+ 0 == unipolar 5V (0V -- +5V)
+ 1 == bipolar 5V (-5V -- +5V)
options[3] Current offset configuration
- 0 == disabled (0mA -- +32mAV)
- 1 == enabled (+4mA -- +20mAV)
+ 0 == disabled (0mA -- +32mAV)
+ 1 == enabled (+4mA -- +20mAV)
options[4] Firmware program configuration
- 0 == program 1 (see manual table 5-4)
- 1 == program 2 (see manual table 5-4)
- 2 == program 3 (see manual table 5-4)
- 3 == program 4 (see manual table 5-4)
+ 0 == program 1 (see manual table 5-4)
+ 1 == program 2 (see manual table 5-4)
+ 2 == program 3 (see manual table 5-4)
+ 3 == program 4 (see manual table 5-4)
options[5] Analog output 0 range configuration
- 0 == voltage
- 1 == current
+ 0 == voltage
+ 1 == current
options[6] Analog output 1 range configuration
...
options[12] Analog output 7 range configuration
- 0 == voltage
- 1 == current
+ 0 == voltage
+ 1 == current
*/
static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -191,9 +182,9 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
unsigned long iobase;
iobase = it->options[0];
- printk("comedi%d: dt2815: 0x%04lx ", dev->minor, iobase);
+ printk(KERN_INFO "comedi%d: dt2815: 0x%04lx ", dev->minor, iobase);
if (!request_region(iobase, DT2815_SIZE, "dt2815")) {
- printk("I/O port conflict\n");
+ printk(KERN_WARNING "I/O port conflict\n");
return -EIO;
}
@@ -236,19 +227,17 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
unsigned int program;
program = (it->options[4] & 0x3) << 3 | 0x7;
outb(program, dev->iobase + DT2815_DATA);
- printk(", program: 0x%x (@t=%d)\n", program, i);
+ printk(KERN_INFO ", program: 0x%x (@t=%d)\n",
+ program, i);
break;
} else if (status != 0x00) {
- printk("dt2815: unexpected status 0x%x (@t=%d)\n",
- status, i);
- if (status & 0x60) {
+ printk(KERN_WARNING "dt2815: unexpected status 0x%x "
+ "(@t=%d)\n", status, i);
+ if (status & 0x60)
outb(0x00, dev->iobase + DT2815_STATUS);
- }
}
}
- printk("\n");
-
return 0;
}
@@ -260,7 +249,7 @@ static void dt2815_free_resources(struct comedi_device *dev)
static int dt2815_detach(struct comedi_device *dev)
{
- printk("comedi%d: dt2815: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: dt2815: remove\n", dev->minor);
dt2815_free_resources(dev);
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index 312f4f282bd7..96caae36279c 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -264,7 +264,7 @@ struct dt9812_usb_cmd {
static DECLARE_MUTEX(dt9812_mutex);
-static struct usb_device_id dt9812_table[] = {
+static const struct usb_device_id dt9812_table[] = {
{USB_DEVICE(0x0867, 0x9812)},
{} /* Terminating entry */
};
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index 8fca18043357..a10a2b070a24 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -76,14 +76,14 @@ static int fl512_ai_insn(struct comedi_device *dev,
unsigned long iobase = dev->iobase;
for (n = 0; n < insn->n; n++) { /* sample n times on selected channel */
- /* XXX probably can move next step out of for() loop -- will make
- * AI a little bit faster. */
+ /* XXX probably can move next step out of for() loop -- will
+ * make AI a little bit faster. */
outb(chan, iobase + 2); /* select chan */
outb(0, iobase + 3); /* start conversion */
/* XXX should test "done" flag instead of delay */
udelay(30); /* sleep 30 usec */
lo_byte = inb(iobase + 2); /* low 8 byte */
- hi_byte = inb(iobase + 3) & 0xf; /* high 4 bit and mask */
+ hi_byte = inb(iobase + 3) & 0xf; /* high 4 bit and mask */
data[n] = lo_byte + (hi_byte << 8);
}
return n;
@@ -101,8 +101,10 @@ static int fl512_ao_insn(struct comedi_device *dev,
unsigned long iobase = dev->iobase; /* get base address */
for (n = 0; n < insn->n; n++) { /* write n data set */
- outb(data[n] & 0x0ff, iobase + 4 + 2 * chan); /* write low byte */
- outb((data[n] & 0xf00) >> 8, iobase + 4 + 2 * chan); /* write high byte */
+ /* write low byte */
+ outb(data[n] & 0x0ff, iobase + 4 + 2 * chan);
+ /* write high byte */
+ outb((data[n] & 0xf00) >> 8, iobase + 4 + 2 * chan);
inb(iobase + 4 + 2 * chan); /* trig */
devpriv->ao_readback[chan] = data[n];
@@ -121,9 +123,8 @@ static int fl512_ao_insn_readback(struct comedi_device *dev,
int n;
int chan = CR_CHAN(insn->chanspec);
- for (n = 0; n < insn->n; n++) {
+ for (n = 0; n < insn->n; n++)
data[n] = devpriv->ao_readback[chan];
- }
return n;
}
@@ -134,13 +135,15 @@ static int fl512_ao_insn_readback(struct comedi_device *dev,
static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
unsigned long iobase;
- struct comedi_subdevice *s; /* pointer to the subdevice:
- Analog in, Analog out, ( not made ->and Digital IO) */
+
+ /* pointer to the subdevice: Analog in, Analog out,
+ (not made ->and Digital IO) */
+ struct comedi_subdevice *s;
iobase = it->options[0];
- printk("comedi:%d fl512: 0x%04lx", dev->minor, iobase);
+ printk(KERN_INFO "comedi:%d fl512: 0x%04lx", dev->minor, iobase);
if (!request_region(iobase, FL512_SIZE, "fl512")) {
- printk(" I/O port conflict\n");
+ printk(KERN_WARNING " I/O port conflict\n");
return -EIO;
}
dev->iobase = iobase;
@@ -149,7 +152,7 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -ENOMEM;
#if DEBUG
- printk("malloc ok\n");
+ printk(KERN_DEBUG "malloc ok\n");
#endif
if (alloc_subdevices(dev, 2) < 0)
@@ -160,24 +163,37 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
*/
/* Analog indput */
s = dev->subdevices + 0;
- s->type = COMEDI_SUBD_AI; /* define subdevice as Analog In */
- s->subdev_flags = SDF_READABLE | SDF_GROUND; /* you can read it from userspace */
- s->n_chan = 16; /* Number of Analog input channels */
- s->maxdata = 0x0fff; /* accept only 12 bits of data */
- s->range_table = &range_fl512; /* device use one of the ranges */
- s->insn_read = fl512_ai_insn; /* function to call when read AD */
- printk("comedi: fl512: subdevice 0 initialized\n");
+ /* define subdevice as Analog In */
+ s->type = COMEDI_SUBD_AI;
+ /* you can read it from userspace */
+ s->subdev_flags = SDF_READABLE | SDF_GROUND;
+ /* Number of Analog input channels */
+ s->n_chan = 16;
+ /* accept only 12 bits of data */
+ s->maxdata = 0x0fff;
+ /* device use one of the ranges */
+ s->range_table = &range_fl512;
+ /* function to call when read AD */
+ s->insn_read = fl512_ai_insn;
+ printk(KERN_INFO "comedi: fl512: subdevice 0 initialized\n");
/* Analog output */
s = dev->subdevices + 1;
- s->type = COMEDI_SUBD_AO; /* define subdevice as Analog OUT */
- s->subdev_flags = SDF_WRITABLE; /* you can write it from userspace */
- s->n_chan = 2; /* Number of Analog output channels */
- s->maxdata = 0x0fff; /* accept only 12 bits of data */
- s->range_table = &range_fl512; /* device use one of the ranges */
- s->insn_write = fl512_ao_insn; /* function to call when write DA */
- s->insn_read = fl512_ao_insn_readback; /* function to call when reading DA */
- printk("comedi: fl512: subdevice 1 initialized\n");
+ /* define subdevice as Analog OUT */
+ s->type = COMEDI_SUBD_AO;
+ /* you can write it from userspace */
+ s->subdev_flags = SDF_WRITABLE;
+ /* Number of Analog output channels */
+ s->n_chan = 2;
+ /* accept only 12 bits of data */
+ s->maxdata = 0x0fff;
+ /* device use one of the ranges */
+ s->range_table = &range_fl512;
+ /* function to call when write DA */
+ s->insn_write = fl512_ao_insn;
+ /* function to call when reading DA */
+ s->insn_read = fl512_ao_insn_readback;
+ printk(KERN_INFO "comedi: fl512: subdevice 1 initialized\n");
return 1;
}
@@ -186,6 +202,6 @@ static int fl512_detach(struct comedi_device *dev)
{
if (dev->iobase)
release_region(dev->iobase, FL512_SIZE);
- printk("comedi%d: fl512: dummy i detach\n", dev->minor);
+ printk(KERN_INFO "comedi%d: fl512: dummy i detach\n", dev->minor);
return 0;
}
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index bd397840dcba..fe5b4953f7ec 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -954,6 +954,8 @@ out:
return result;
}
+MODULE_FIRMWARE("comedi/jr3pci.idm");
+
static int jr3_pci_detach(struct comedi_device *dev)
{
int i;
diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c
index cb4da2ae8429..12e72c828157 100644
--- a/drivers/staging/comedi/drivers/mpc624.c
+++ b/drivers/staging/comedi/drivers/mpc624.c
@@ -284,7 +284,7 @@ static int mpc624_ai_rinsn(struct comedi_device *dev,
outb(insn->chanspec, dev->iobase + MPC624_GNMUXCH);
/* printk("Channel %d: \n", insn->chanspec); */
if (!insn->n) {
- printk("MPC624: Warning, no data to aquire\n");
+ printk("MPC624: Warning, no data to acquire\n");
return 0;
}
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index bbf75eb6d7f2..c223f76031f6 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -26,12 +26,13 @@
/*
Driver: ni_65xx
Description: National Instruments 65xx static dio boards
-Author: Jon Grierson <jd@renko.co.uk>, Frank Mori Hess <fmhess@users.sourceforge.net>
+Author: Jon Grierson <jd@renko.co.uk>,
+ Frank Mori Hess <fmhess@users.sourceforge.net>
Status: testing
-Devices: [National Instruments] PCI-6509 (ni_65xx), PXI-6509, PCI-6510, PCI-6511,
- PXI-6511, PCI-6512, PXI-6512, PCI-6513, PXI-6513, PCI-6514, PXI-6514, PCI-6515,
- PXI-6515, PCI-6516, PCI-6517, PCI-6518, PCI-6519, PCI-6520, PCI-6521, PXI-6521,
- PCI-6528, PXI-6528
+Devices: [National Instruments] PCI-6509 (ni_65xx), PXI-6509, PCI-6510,
+ PCI-6511, PXI-6511, PCI-6512, PXI-6512, PCI-6513, PXI-6513, PCI-6514,
+ PXI-6514, PCI-6515, PXI-6515, PCI-6516, PCI-6517, PCI-6518, PCI-6519,
+ PCI-6520, PCI-6521, PXI-6521, PCI-6528, PXI-6528
Updated: Wed Oct 18 08:59:11 EDT 2006
Based on the PCI-6527 driver by ds.
@@ -418,9 +419,10 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev,
return -EINVAL;
base_bitfield_channel = CR_CHAN(insn->chanspec);
for (j = 0; j < max_ports_per_bitfield; ++j) {
- const unsigned port_offset = ni_65xx_port_by_channel(base_bitfield_channel) + j;
+ const unsigned port_offset =
+ ni_65xx_port_by_channel(base_bitfield_channel) + j;
const unsigned port =
- sprivate(s)->base_port + port_offset;
+ sprivate(s)->base_port + port_offset;
unsigned base_port_channel;
unsigned port_mask, port_data, port_read_bits;
int bitshift;
@@ -463,11 +465,11 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev,
* subdevice.) */
port_read_bits ^= 0xFF;
}
- if (bitshift > 0) {
+ if (bitshift > 0)
port_read_bits <<= bitshift;
- } else {
+ else
port_read_bits >>= -bitshift;
- }
+
read_bits |= port_read_bits;
}
data[1] = read_bits;
@@ -532,7 +534,8 @@ static int ni_65xx_intr_cmdtest(struct comedi_device *dev,
if (err)
return 1;
- /* step 2: make sure trigger sources are unique and mutually compatible */
+ /* step 2: make sure trigger sources are unique and mutually
+ compatible */
if (err)
return 2;
@@ -652,7 +655,7 @@ static int ni_65xx_attach(struct comedi_device *dev,
unsigned i;
int ret;
- printk("comedi%d: ni_65xx:", dev->minor);
+ printk(KERN_INFO "comedi%d: ni_65xx:", dev->minor);
ret = alloc_private(dev, sizeof(struct ni_65xx_private));
if (ret < 0)
@@ -664,15 +667,15 @@ static int ni_65xx_attach(struct comedi_device *dev,
ret = mite_setup(private(dev)->mite);
if (ret < 0) {
- printk("error setting up mite\n");
+ printk(KERN_WARNING "error setting up mite\n");
return ret;
}
dev->board_name = board(dev)->name;
dev->irq = mite_irq(private(dev)->mite);
- printk(" %s", dev->board_name);
+ printk(KERN_INFO " %s", dev->board_name);
- printk(" ID=0x%02x",
+ printk(KERN_INFO " ID=0x%02x",
readb(private(dev)->mite->daq_io_addr + ID_Register));
ret = alloc_subdevices(dev, 4);
@@ -773,7 +776,7 @@ static int ni_65xx_attach(struct comedi_device *dev,
"ni_65xx", dev);
if (ret < 0) {
dev->irq = 0;
- printk(" irq not available");
+ printk(KERN_WARNING " irq not available");
}
printk("\n");
@@ -790,21 +793,17 @@ static int ni_65xx_detach(struct comedi_device *dev)
Master_Interrupt_Control);
}
- if (dev->irq) {
+ if (dev->irq)
free_irq(dev->irq, dev);
- }
if (private(dev)) {
unsigned i;
for (i = 0; i < dev->n_subdevices; ++i) {
- if (dev->subdevices[i].private) {
- kfree(dev->subdevices[i].private);
- dev->subdevices[i].private = NULL;
- }
+ kfree(dev->subdevices[i].private);
+ dev->subdevices[i].private = NULL;
}
- if (private(dev)->mite) {
+ if (private(dev)->mite)
mite_unsetup(private(dev)->mite);
- }
}
return 0;
}
@@ -830,7 +829,7 @@ static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot)
}
}
}
- printk("no device found\n");
+ printk(KERN_WARNING "no device found\n");
mite_list_devices();
return -EIO;
}
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index 404d3c516ed1..017630fb2424 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -52,7 +52,8 @@ enum ni_660x_constants {
};
#define NUM_PFI_CHANNELS 40
-/* really there are only up to 3 dma channels, but the register layout allows for 4 */
+/* really there are only up to 3 dma channels, but the register layout allows
+for 4 */
#define MAX_DMA_CHANNEL 4
/* See Register-Level Programmer Manual page 3.1 */
@@ -198,7 +199,7 @@ struct NI_660xRegisterData {
const char *name; /* Register Name */
int offset; /* Offset from base address from GPCT chip */
enum ni_660x_register_direction direction;
- enum ni_660x_register_width size; /* 1 byte, 2 bytes, or 4 bytes */
+ enum ni_660x_register_width size; /* 1 byte, 2 bytes, or 4 bytes */
};
static const struct NI_660xRegisterData registerData[NumRegisters] = {
@@ -382,8 +383,8 @@ enum global_interrupt_config_register_bits {
};
/* Offset of the GPCT chips from the base-adress of the card */
-static const unsigned GPCT_OFFSET[2] = { 0x0, 0x800 }; /* First chip is at base-address +
- 0x00, etc. */
+/* First chip is at base-address + 0x00, etc. */
+static const unsigned GPCT_OFFSET[2] = { 0x0, 0x800 };
/* Board description*/
struct ni_660x_board {
@@ -691,13 +692,13 @@ static enum NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg)
ni_660x_register = G0StatusRegister;
break;
case NITIO_G1_Status_Reg:
- ni_660x_register = G0StatusRegister;
+ ni_660x_register = G1StatusRegister;
break;
case NITIO_G2_Status_Reg:
- ni_660x_register = G0StatusRegister;
+ ni_660x_register = G2StatusRegister;
break;
case NITIO_G3_Status_Reg:
- ni_660x_register = G0StatusRegister;
+ ni_660x_register = G3StatusRegister;
break;
case NITIO_G0_Interrupt_Enable_Reg:
ni_660x_register = G0InterruptEnable;
@@ -712,7 +713,7 @@ static enum NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg)
ni_660x_register = G3InterruptEnable;
break;
default:
- printk("%s: unhandled register 0x%x in switch.\n",
+ printk(KERN_WARNING "%s: unhandled register 0x%x in switch.\n",
__func__, reg);
BUG();
return 0;
@@ -737,7 +738,7 @@ static inline void ni_660x_write_register(struct comedi_device *dev,
writel(bits, write_address);
break;
default:
- printk("%s: %s: bug! unhandled case (reg=0x%x) in switch.\n",
+ printk(KERN_WARNING "%s: %s: bug! unhandled case (reg=0x%x) in switch.\n",
__FILE__, __func__, reg);
BUG();
break;
@@ -760,7 +761,7 @@ static inline unsigned ni_660x_read_register(struct comedi_device *dev,
return readl(read_address);
break;
default:
- printk("%s: %s: bug! unhandled case (reg=0x%x) in switch.\n",
+ printk(KERN_WARNING "%s: %s: bug! unhandled case (reg=0x%x) in switch.\n",
__FILE__, __func__, reg);
BUG();
break;
@@ -993,9 +994,9 @@ static int ni_660x_allocate_private(struct comedi_device *dev)
spin_lock_init(&private(dev)->mite_channel_lock);
spin_lock_init(&private(dev)->interrupt_lock);
spin_lock_init(&private(dev)->soft_reg_copy_lock);
- for (i = 0; i < NUM_PFI_CHANNELS; ++i) {
+ for (i = 0; i < NUM_PFI_CHANNELS; ++i)
private(dev)->pfi_output_selects[i] = pfi_output_select_counter;
- }
+
return 0;
}
@@ -1008,9 +1009,8 @@ static int ni_660x_alloc_mite_rings(struct comedi_device *dev)
for (j = 0; j < counters_per_chip; ++j) {
private(dev)->mite_rings[i][j] =
mite_alloc_ring(private(dev)->mite);
- if (private(dev)->mite_rings[i][j] == NULL) {
+ if (private(dev)->mite_rings[i][j] == NULL)
return -ENOMEM;
- }
}
}
return 0;
@@ -1022,9 +1022,8 @@ static void ni_660x_free_mite_rings(struct comedi_device *dev)
unsigned j;
for (i = 0; i < board(dev)->n_chips; ++i) {
- for (j = 0; j < counters_per_chip; ++j) {
+ for (j = 0; j < counters_per_chip; ++j)
mite_free_ring(private(dev)->mite_rings[i][j]);
- }
}
}
@@ -1036,7 +1035,7 @@ static int ni_660x_attach(struct comedi_device *dev,
unsigned i;
unsigned global_interrupt_config_bits;
- printk("comedi%d: ni_660x: ", dev->minor);
+ printk(KERN_INFO "comedi%d: ni_660x: ", dev->minor);
ret = ni_660x_allocate_private(dev);
if (ret < 0)
@@ -1049,7 +1048,7 @@ static int ni_660x_attach(struct comedi_device *dev,
ret = mite_setup2(private(dev)->mite, 1);
if (ret < 0) {
- printk("error setting up mite\n");
+ printk(KERN_WARNING "error setting up mite\n");
return ret;
}
comedi_set_hw_dev(dev, &private(dev)->mite->pcidev->dev);
@@ -1057,7 +1056,7 @@ static int ni_660x_attach(struct comedi_device *dev,
if (ret < 0)
return ret;
- printk(" %s ", dev->board_name);
+ printk(KERN_INFO " %s ", dev->board_name);
dev->n_subdevices = 2 + NI_660X_MAX_NUM_COUNTERS;
@@ -1078,15 +1077,16 @@ static int ni_660x_attach(struct comedi_device *dev,
s->insn_bits = ni_660x_dio_insn_bits;
s->insn_config = ni_660x_dio_insn_config;
s->io_bits = 0; /* all bits default to input */
- /* we use the ioconfig registers to control dio direction, so zero output enables in stc dio control reg */
+ /* we use the ioconfig registers to control dio direction, so zero
+ output enables in stc dio control reg */
ni_660x_write_register(dev, 0, 0, STCDIOControl);
private(dev)->counter_dev = ni_gpct_device_construct(dev,
- &ni_gpct_write_register,
- &ni_gpct_read_register,
- ni_gpct_variant_660x,
- ni_660x_num_counters
- (dev));
+ &ni_gpct_write_register,
+ &ni_gpct_read_register,
+ ni_gpct_variant_660x,
+ ni_660x_num_counters
+ (dev));
if (private(dev)->counter_dev == NULL)
return -ENOMEM;
for (i = 0; i < NI_660X_MAX_NUM_COUNTERS; ++i) {
@@ -1118,12 +1118,12 @@ static int ni_660x_attach(struct comedi_device *dev,
s->type = COMEDI_SUBD_UNUSED;
}
}
- for (i = 0; i < board(dev)->n_chips; ++i) {
+ for (i = 0; i < board(dev)->n_chips; ++i)
init_tio_chip(dev, i);
- }
- for (i = 0; i < ni_660x_num_counters(dev); ++i) {
+
+ for (i = 0; i < ni_660x_num_counters(dev); ++i)
ni_tio_init_counter(&private(dev)->counter_dev->counters[i]);
- }
+
for (i = 0; i < NUM_PFI_CHANNELS; ++i) {
if (i < min_counter_pfi_chan)
ni_660x_set_pfi_routing(dev, i, pfi_output_select_do);
@@ -1134,13 +1134,13 @@ static int ni_660x_attach(struct comedi_device *dev,
}
/* to be safe, set counterswap bits on tio chips after all the counter
outputs have been set to high impedance mode */
- for (i = 0; i < board(dev)->n_chips; ++i) {
+ for (i = 0; i < board(dev)->n_chips; ++i)
set_tio_counterswap(dev, i);
- }
+
ret = request_irq(mite_irq(private(dev)->mite), ni_660x_interrupt,
IRQF_SHARED, "ni_660x", dev);
if (ret < 0) {
- printk(" irq not available\n");
+ printk(KERN_WARNING " irq not available\n");
return ret;
}
dev->irq = mite_irq(private(dev)->mite);
@@ -1149,13 +1149,13 @@ static int ni_660x_attach(struct comedi_device *dev,
global_interrupt_config_bits |= Cascade_Int_Enable_Bit;
ni_660x_write_register(dev, 0, global_interrupt_config_bits,
GlobalInterruptConfigRegister);
- printk("attached\n");
+ printk(KERN_INFO "attached\n");
return 0;
}
static int ni_660x_detach(struct comedi_device *dev)
{
- printk("comedi%d: ni_660x: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: ni_660x: remove\n", dev->minor);
/* Free irq */
if (dev->irq)
@@ -1193,9 +1193,8 @@ static void init_tio_chip(struct comedi_device *dev, int chipset)
private(dev)->
dma_configuration_soft_copies[chipset],
DMAConfigRegister);
- for (i = 0; i < NUM_PFI_CHANNELS; ++i) {
+ for (i = 0; i < NUM_PFI_CHANNELS; ++i)
ni_660x_write_register(dev, chipset, 0, IOConfigReg(i));
- }
}
static int
@@ -1234,7 +1233,7 @@ static int ni_660x_find_device(struct comedi_device *dev, int bus, int slot)
}
}
}
- printk("no device found\n");
+ printk(KERN_WARNING "no device found\n");
mite_list_devices();
return -EIO;
}
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index 9b43547e80a1..1e792d592f73 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -93,7 +93,7 @@ static DEFINE_PCI_DEVICE_TABLE(ni_670x_pci_table) = {
{
PCI_VENDOR_ID_NATINST, 0x2c90, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_NATINST, 0x1920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- /* { PCI_VENDOR_ID_NATINST, 0x0000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
+ /*{ PCI_VENDOR_ID_NATINST, 0x0000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },*/
{
0}
};
@@ -151,7 +151,7 @@ static int ni_670x_attach(struct comedi_device *dev,
int ret;
int i;
- printk("comedi%d: ni_670x: ", dev->minor);
+ printk(KERN_INFO "comedi%d: ni_670x: ", dev->minor);
ret = alloc_private(dev, sizeof(struct ni_670x_private));
if (ret < 0)
@@ -163,12 +163,12 @@ static int ni_670x_attach(struct comedi_device *dev,
ret = mite_setup(devpriv->mite);
if (ret < 0) {
- printk("error setting up mite\n");
+ printk(KERN_WARNING "error setting up mite\n");
return ret;
}
dev->board_name = thisboard->name;
dev->irq = mite_irq(devpriv->mite);
- printk(" %s", dev->board_name);
+ printk(KERN_INFO " %s", dev->board_name);
if (alloc_subdevices(dev, 2) < 0)
return -ENOMEM;
@@ -207,21 +207,22 @@ static int ni_670x_attach(struct comedi_device *dev,
s->insn_bits = ni_670x_dio_insn_bits;
s->insn_config = ni_670x_dio_insn_config;
- writel(0x10, devpriv->mite->daq_io_addr + MISC_CONTROL_OFFSET); /* Config of misc registers */
- writel(0x00, devpriv->mite->daq_io_addr + AO_CONTROL_OFFSET); /* Config of ao registers */
+ /* Config of misc registers */
+ writel(0x10, devpriv->mite->daq_io_addr + MISC_CONTROL_OFFSET);
+ /* Config of ao registers */
+ writel(0x00, devpriv->mite->daq_io_addr + AO_CONTROL_OFFSET);
- printk("attached\n");
+ printk(KERN_INFO "attached\n");
return 1;
}
static int ni_670x_detach(struct comedi_device *dev)
{
- printk("comedi%d: ni_670x: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: ni_670x: remove\n", dev->minor);
+
+ kfree(dev->subdevices[0].range_table_list);
- if (dev->subdevices[0].range_table_list) {
- kfree(dev->subdevices[0].range_table_list);
- }
if (dev->private && devpriv->mite)
mite_unsetup(devpriv->mite);
@@ -250,8 +251,11 @@ static int ni_670x_ao_winsn(struct comedi_device *dev,
vch(15) : 30 | ich(31) : 31 */
for (i = 0; i < insn->n; i++) {
- writel(((chan & 15) << 1) | ((chan & 16) >> 4), devpriv->mite->daq_io_addr + AO_CHAN_OFFSET); /* First write in channel register which channel to use */
- writel(data[i], devpriv->mite->daq_io_addr + AO_VALUE_OFFSET); /* write channel value */
+ /* First write in channel register which channel to use */
+ writel(((chan & 15) << 1) | ((chan & 16) >> 4),
+ devpriv->mite->daq_io_addr + AO_CHAN_OFFSET);
+ /* write channel value */
+ writel(data[i], devpriv->mite->daq_io_addr + AO_VALUE_OFFSET);
devpriv->ao_readback[chan] = data[i];
}
@@ -344,7 +348,7 @@ static int ni_670x_find_device(struct comedi_device *dev, int bus, int slot)
}
}
}
- printk("no device found\n");
+ printk(KERN_INFO "no device found\n");
mite_list_devices();
return -EIO;
}
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index 8ead31164d5c..003d00b595b0 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -329,11 +329,11 @@ static uint16_t ni_atmio_win_in(struct comedi_device *dev, int addr)
}
static struct pnp_device_id device_ids[] = {
- {.id = "NIC1900",.driver_data = 0},
- {.id = "NIC2400",.driver_data = 0},
- {.id = "NIC2500",.driver_data = 0},
- {.id = "NIC2600",.driver_data = 0},
- {.id = "NIC2700",.driver_data = 0},
+ {.id = "NIC1900", .driver_data = 0},
+ {.id = "NIC2400", .driver_data = 0},
+ {.id = "NIC2500", .driver_data = 0},
+ {.id = "NIC2600", .driver_data = 0},
+ {.id = "NIC2700", .driver_data = 0},
{.id = ""}
};
@@ -362,9 +362,9 @@ static int ni_atmio_detach(struct comedi_device *dev)
if (dev->iobase)
release_region(dev->iobase, NI_SIZE);
- if (dev->irq) {
+ if (dev->irq)
free_irq(dev->irq, dev);
- }
+
if (devpriv->isapnp_dev)
pnp_device_detach(devpriv->isapnp_dev);
@@ -387,8 +387,8 @@ static int ni_isapnp_find_board(struct pnp_dev **dev)
if (pnp_device_attach(isapnp_dev) < 0) {
printk
- ("ni_atmio: %s found but already active, skipping.\n",
- ni_boards[i].name);
+ ("ni_atmio: %s found but already active, skipping.\n",
+ ni_boards[i].name);
continue;
}
if (pnp_activate_dev(isapnp_dev) < 0) {
@@ -496,9 +496,9 @@ static int ni_atmio_attach(struct comedi_device *dev,
/* generic E series stuff in ni_mio_common.c */
ret = ni_E_init(dev, it);
- if (ret < 0) {
+ if (ret < 0)
return ret;
- }
+
return 0;
}
@@ -509,16 +509,16 @@ static int ni_getboardtype(struct comedi_device *dev)
int i;
for (i = 0; i < n_ni_boards; i++) {
- if (ni_boards[i].device_id == device_id) {
+ if (ni_boards[i].device_id == device_id)
return i;
- }
+
}
- if (device_id == 255) {
+ if (device_id == 255)
printk(" can't find board\n");
- } else if (device_id == 0) {
+ else if (device_id == 0)
printk(" EEPROM read error (?) or device not found\n");
- } else {
+ else
printk(" unknown device ID %d -- contact author\n", device_id);
- }
+
return -1;
}
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index ef5e1183d47d..c9b0395a6103 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -76,13 +76,15 @@ struct dio700_board {
static const struct dio700_board dio700_boards[] = {
{
.name = "daqcard-700",
- .device_id = 0x4743, /* 0x10b is manufacturer id, 0x4743 is device id */
+ /* 0x10b is manufacturer id, 0x4743 is device id */
+ .device_id = 0x4743,
.bustype = pcmcia_bustype,
.have_dio = 1,
},
{
.name = "ni_daq_700",
- .device_id = 0x4743, /* 0x10b is manufacturer id, 0x4743 is device id */
+ /* 0x10b is manufacturer id, 0x4743 is device id */
+ .device_id = 0x4743,
.bustype = pcmcia_bustype,
.have_dio = 1,
},
@@ -309,11 +311,11 @@ int subdev_700_init(struct comedi_device *dev, struct comedi_subdevice *s,
return -ENOMEM;
CALLBACK_ARG = arg;
- if (cb == NULL) {
+ if (cb == NULL)
CALLBACK_FUNC = subdev_700_cb;
- } else {
+ else
CALLBACK_FUNC = cb;
- }
+
s->insn_bits = subdev_700_insn;
s->insn_config = subdev_700_insn_config;
@@ -345,12 +347,10 @@ int subdev_700_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
void subdev_700_cleanup(struct comedi_device *dev, struct comedi_subdevice *s)
{
- if (s->private) {
- if (subdevpriv->have_irq) {
- }
+ if (s->private)
+ if (subdevpriv->have_irq)
- kfree(s->private);
- }
+ kfree(s->private);
}
EXPORT_SYMBOL(subdev_700_init);
@@ -390,9 +390,9 @@ static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it)
printk("comedi%d: ni_daq_700: %s, io 0x%lx", dev->minor,
thisboard->name, iobase);
#ifdef incomplete
- if (irq) {
+ if (irq)
printk(", irq %u", irq);
- }
+
#endif
printk("\n");
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index dc3f398cb3ed..3c88caaa9dab 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -90,8 +90,10 @@ NI manuals:
#define DRV_NAME "ni_labpc"
-#define LABPC_SIZE 32 /* size of io region used by board */
-#define LABPC_TIMER_BASE 500 /* 2 MHz master clock */
+/* size of io region used by board */
+#define LABPC_SIZE 32
+/* 2 MHz master clock */
+#define LABPC_TIMER_BASE 500
/* Registers for the lab-pc+ */
@@ -99,69 +101,110 @@ NI manuals:
#define COMMAND1_REG 0x0
#define ADC_GAIN_MASK (0x7 << 4)
#define ADC_CHAN_BITS(x) ((x) & 0x7)
-#define ADC_SCAN_EN_BIT 0x80 /* enables multi channel scans */
+/* enables multi channel scans */
+#define ADC_SCAN_EN_BIT 0x80
#define COMMAND2_REG 0x1
-#define PRETRIG_BIT 0x1 /* enable pretriggering (used in conjunction with SWTRIG) */
-#define HWTRIG_BIT 0x2 /* enable paced conversions on external trigger */
-#define SWTRIG_BIT 0x4 /* enable paced conversions */
-#define CASCADE_BIT 0x8 /* use two cascaded counters for pacing */
+/* enable pretriggering (used in conjunction with SWTRIG) */
+#define PRETRIG_BIT 0x1
+/* enable paced conversions on external trigger */
+#define HWTRIG_BIT 0x2
+/* enable paced conversions */
+#define SWTRIG_BIT 0x4
+/* use two cascaded counters for pacing */
+#define CASCADE_BIT 0x8
#define DAC_PACED_BIT(channel) (0x40 << ((channel) & 0x1))
#define COMMAND3_REG 0x2
-#define DMA_EN_BIT 0x1 /* enable dma transfers */
-#define DIO_INTR_EN_BIT 0x2 /* enable interrupts for 8255 */
-#define DMATC_INTR_EN_BIT 0x4 /* enable dma terminal count interrupt */
-#define TIMER_INTR_EN_BIT 0x8 /* enable timer interrupt */
-#define ERR_INTR_EN_BIT 0x10 /* enable error interrupt */
-#define ADC_FNE_INTR_EN_BIT 0x20 /* enable fifo not empty interrupt */
+/* enable dma transfers */
+#define DMA_EN_BIT 0x1
+/* enable interrupts for 8255 */
+#define DIO_INTR_EN_BIT 0x2
+/* enable dma terminal count interrupt */
+#define DMATC_INTR_EN_BIT 0x4
+/* enable timer interrupt */
+#define TIMER_INTR_EN_BIT 0x8
+/* enable error interrupt */
+#define ERR_INTR_EN_BIT 0x10
+/* enable fifo not empty interrupt */
+#define ADC_FNE_INTR_EN_BIT 0x20
#define ADC_CONVERT_REG 0x3
#define DAC_LSB_REG(channel) (0x4 + 2 * ((channel) & 0x1))
#define DAC_MSB_REG(channel) (0x5 + 2 * ((channel) & 0x1))
#define ADC_CLEAR_REG 0x8
#define DMATC_CLEAR_REG 0xa
#define TIMER_CLEAR_REG 0xc
-#define COMMAND6_REG 0xe /* 1200 boards only */
-#define ADC_COMMON_BIT 0x1 /* select ground or common-mode reference */
-#define ADC_UNIP_BIT 0x2 /* adc unipolar */
-#define DAC_UNIP_BIT(channel) (0x4 << ((channel) & 0x1)) /* dac unipolar */
-#define ADC_FHF_INTR_EN_BIT 0x20 /* enable fifo half full interrupt */
-#define A1_INTR_EN_BIT 0x40 /* enable interrupt on end of hardware count */
-#define ADC_SCAN_UP_BIT 0x80 /* scan up from channel zero instead of down to zero */
+/* 1200 boards only */
+#define COMMAND6_REG 0xe
+/* select ground or common-mode reference */
+#define ADC_COMMON_BIT 0x1
+/* adc unipolar */
+#define ADC_UNIP_BIT 0x2
+/* dac unipolar */
+#define DAC_UNIP_BIT(channel) (0x4 << ((channel) & 0x1))
+/* enable fifo half full interrupt */
+#define ADC_FHF_INTR_EN_BIT 0x20
+/* enable interrupt on end of hardware count */
+#define A1_INTR_EN_BIT 0x40
+/* scan up from channel zero instead of down to zero */
+#define ADC_SCAN_UP_BIT 0x80
#define COMMAND4_REG 0xf
-#define INTERVAL_SCAN_EN_BIT 0x1 /* enables 'interval' scanning */
-#define EXT_SCAN_EN_BIT 0x2 /* enables external signal on counter b1 output to trigger scan */
-#define EXT_CONVERT_OUT_BIT 0x4 /* chooses direction (output or input) for EXTCONV* line */
-#define ADC_DIFF_BIT 0x8 /* chooses differential inputs for adc (in conjunction with board jumper) */
+/* enables 'interval' scanning */
+#define INTERVAL_SCAN_EN_BIT 0x1
+/* enables external signal on counter b1 output to trigger scan */
+#define EXT_SCAN_EN_BIT 0x2
+/* chooses direction (output or input) for EXTCONV* line */
+#define EXT_CONVERT_OUT_BIT 0x4
+/* chooses differential inputs for adc (in conjunction with board jumper) */
+#define ADC_DIFF_BIT 0x8
#define EXT_CONVERT_DISABLE_BIT 0x10
-#define COMMAND5_REG 0x1c /* 1200 boards only, calibration stuff */
-#define EEPROM_WRITE_UNPROTECT_BIT 0x4 /* enable eeprom for write */
-#define DITHER_EN_BIT 0x8 /* enable dithering */
-#define CALDAC_LOAD_BIT 0x10 /* load calibration dac */
-#define SCLOCK_BIT 0x20 /* serial clock - rising edge writes, falling edge reads */
-#define SDATA_BIT 0x40 /* serial data bit for writing to eeprom or calibration dacs */
-#define EEPROM_EN_BIT 0x80 /* enable eeprom for read/write */
+/* 1200 boards only, calibration stuff */
+#define COMMAND5_REG 0x1c
+/* enable eeprom for write */
+#define EEPROM_WRITE_UNPROTECT_BIT 0x4
+/* enable dithering */
+#define DITHER_EN_BIT 0x8
+/* load calibration dac */
+#define CALDAC_LOAD_BIT 0x10
+/* serial clock - rising edge writes, falling edge reads */
+#define SCLOCK_BIT 0x20
+/* serial data bit for writing to eeprom or calibration dacs */
+#define SDATA_BIT 0x40
+/* enable eeprom for read/write */
+#define EEPROM_EN_BIT 0x80
#define INTERVAL_COUNT_REG 0x1e
#define INTERVAL_LOAD_REG 0x1f
#define INTERVAL_LOAD_BITS 0x1
/* read-only registers */
#define STATUS1_REG 0x0
-#define DATA_AVAIL_BIT 0x1 /* data is available in fifo */
-#define OVERRUN_BIT 0x2 /* overrun has occurred */
-#define OVERFLOW_BIT 0x4 /* fifo overflow */
-#define TIMER_BIT 0x8 /* timer interrupt has occured */
-#define DMATC_BIT 0x10 /* dma terminal count has occured */
-#define EXT_TRIG_BIT 0x40 /* external trigger has occured */
-#define STATUS2_REG 0x1d /* 1200 boards only */
-#define EEPROM_OUT_BIT 0x1 /* programmable eeprom serial output */
-#define A1_TC_BIT 0x2 /* counter A1 terminal count */
-#define FNHF_BIT 0x4 /* fifo not half full */
+/* data is available in fifo */
+#define DATA_AVAIL_BIT 0x1
+/* overrun has occurred */
+#define OVERRUN_BIT 0x2
+/* fifo overflow */
+#define OVERFLOW_BIT 0x4
+/* timer interrupt has occured */
+#define TIMER_BIT 0x8
+/* dma terminal count has occured */
+#define DMATC_BIT 0x10
+/* external trigger has occured */
+#define EXT_TRIG_BIT 0x40
+/* 1200 boards only */
+#define STATUS2_REG 0x1d
+/* programmable eeprom serial output */
+#define EEPROM_OUT_BIT 0x1
+/* counter A1 terminal count */
+#define A1_TC_BIT 0x2
+/* fifo not half full */
+#define FNHF_BIT 0x4
#define ADC_FIFO_REG 0xa
#define DIO_BASE_REG 0x10
#define COUNTER_A_BASE_REG 0x14
#define COUNTER_A_CONTROL_REG (COUNTER_A_BASE_REG + 0x3)
-#define INIT_A0_BITS 0x14 /* check modes put conversion pacer output in harmless state (a0 mode 2) */
-#define INIT_A1_BITS 0x70 /* put hardware conversion counter output in harmless state (a1 mode 0) */
+/* check modes put conversion pacer output in harmless state (a0 mode 2) */
+#define INIT_A0_BITS 0x14
+/* put hardware conversion counter output in harmless state (a1 mode 0) */
+#define INIT_A1_BITS 0x70
#define COUNTER_B_BASE_REG 0x18
static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it);
@@ -423,7 +466,7 @@ static const struct labpc_board_struct labpc_boards[] = {
.ai_scan_up = 1,
.memory_mapped_io = 1,
},
- /* dummy entry so pci board works when comedi_config is passed driver name */
+/* dummy entry so pci board works when comedi_config is passed driver name */
{
.name = DRV_NAME,
.bustype = pci_bustype,
@@ -436,8 +479,10 @@ static const struct labpc_board_struct labpc_boards[] = {
*/
#define thisboard ((struct labpc_board_struct *)dev->board_ptr)
-static const int dma_buffer_size = 0xff00; /* size in bytes of dma buffer */
-static const int sample_size = 2; /* 2 bytes per sample */
+/* size in bytes of dma buffer */
+static const int dma_buffer_size = 0xff00;
+/* 2 bytes per sample */
+static const int sample_size = 2;
#define devpriv ((struct labpc_private *)dev->private)
@@ -483,12 +528,10 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
printk("comedi%d: ni_labpc: %s, io 0x%lx", dev->minor, thisboard->name,
iobase);
- if (irq) {
+ if (irq)
printk(", irq %u", irq);
- }
- if (dma_chan) {
+ if (dma_chan)
printk(", dma %u", dma_chan);
- }
printk("\n");
if (iobase == 0) {
@@ -513,7 +556,7 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
devpriv->read_byte = labpc_inb;
devpriv->write_byte = labpc_outb;
}
- /* initialize board's command registers */
+ /* initialize board's command registers */
devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
@@ -538,12 +581,12 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
}
dev->irq = irq;
- /* grab dma channel */
+ /* grab dma channel */
if (dma_chan > 3) {
printk(" invalid dma channel %u\n", dma_chan);
return -EINVAL;
} else if (dma_chan) {
- /* allocate dma buffer */
+ /* allocate dma buffer */
devpriv->dma_buffer =
kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA);
if (devpriv->dma_buffer == NULL) {
@@ -575,7 +618,7 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ;
s->n_chan = 8;
s->len_chanlist = 8;
- s->maxdata = (1 << 12) - 1; /* 12 bit resolution */
+ s->maxdata = (1 << 12) - 1; /* 12 bit resolution */
s->range_table = thisboard->ai_range_table;
s->do_cmd = labpc_ai_cmd;
s->do_cmdtest = labpc_ai_cmdtest;
@@ -585,8 +628,11 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
/* analog output */
s = dev->subdevices + 1;
if (thisboard->has_ao) {
-/* Could provide command support, except it only has a one sample
- * hardware buffer for analog output and no underrun flag. */
+ /*
+ * Could provide command support, except it only has a
+ * one sample hardware buffer for analog output and no
+ * underrun flag.
+ */
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
s->n_chan = NUM_AO_CHAN;
@@ -608,7 +654,8 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
/* 8255 dio */
s = dev->subdevices + 2;
- /* if board uses io memory we have to give a custom callback function to the 8255 driver */
+ /* if board uses io memory we have to give a custom callback
+ * function to the 8255 driver */
if (thisboard->memory_mapped_io)
subdev_8255_init(dev, s, labpc_dio_mem_callback,
(unsigned long)(dev->iobase + DIO_BASE_REG));
@@ -640,14 +687,12 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
s->insn_read = labpc_eeprom_read_insn;
s->insn_write = labpc_eeprom_write_insn;
- for (i = 0; i < EEPROM_SIZE; i++) {
+ for (i = 0; i < EEPROM_SIZE; i++)
devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
- }
#ifdef LABPC_DEBUG
printk(" eeprom:");
- for (i = 0; i < EEPROM_SIZE; i++) {
+ for (i = 0; i < EEPROM_SIZE; i++)
printk(" %i:0x%x ", i, devpriv->eeprom_data[i]);
- }
printk("\n");
#endif
} else
@@ -669,7 +714,7 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (alloc_private(dev, sizeof(struct labpc_private)) < 0)
return -ENOMEM;
- /* get base address, irq etc. based on bustype */
+ /* get base address, irq etc. based on bustype */
switch (thisboard->bustype) {
case isa_bustype:
iobase = it->options[0];
@@ -679,9 +724,8 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
case pci_bustype:
#ifdef CONFIG_COMEDI_PCI
retval = labpc_find_device(dev, it->options[0], it->options[1]);
- if (retval < 0) {
+ if (retval < 0)
return retval;
- }
retval = mite_setup(devpriv->mite);
if (retval < 0)
return retval;
@@ -715,7 +759,7 @@ static int labpc_find_device(struct comedi_device *dev, int bus, int slot)
for (mite = mite_devices; mite; mite = mite->next) {
if (mite->used)
continue;
- /* if bus/slot are specified then make sure we have the right bus/slot */
+/* if bus/slot are specified then make sure we have the right bus/slot */
if (bus || slot) {
if (bus != mite->pcidev->bus->number
|| slot != PCI_SLOT(mite->pcidev->devfn))
@@ -726,7 +770,7 @@ static int labpc_find_device(struct comedi_device *dev, int bus, int slot)
continue;
if (mite_device_id(mite) == labpc_boards[i].device_id) {
devpriv->mite = mite;
- /* fixup board pointer, in case we were using the dummy "ni_labpc" entry */
+/* fixup board pointer, in case we were using the dummy "ni_labpc" entry */
dev->board_ptr = &labpc_boards[i];
return 0;
}
@@ -994,7 +1038,7 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE)
err++;
- /* can't have external stop and start triggers at once */
+ /* can't have external stop and start triggers at once */
if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT)
err++;
@@ -1008,9 +1052,9 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
err++;
}
- if (!cmd->chanlist_len) {
+ if (!cmd->chanlist_len)
err++;
- }
+
if (cmd->scan_end_arg != cmd->chanlist_len) {
cmd->scan_end_arg = cmd->chanlist_len;
err++;
@@ -1022,7 +1066,7 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
err++;
}
}
- /* make sure scan timing is not too fast */
+ /* make sure scan timing is not too fast */
if (cmd->scan_begin_src == TRIG_TIMER) {
if (cmd->convert_src == TRIG_TIMER &&
cmd->scan_begin_arg <
@@ -1038,7 +1082,7 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
err++;
}
}
- /* stop source */
+ /* stop source */
switch (cmd->stop_src) {
case TRIG_COUNT:
if (!cmd->stop_arg) {
@@ -1095,7 +1139,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
range = CR_RANGE(cmd->chanlist[0]);
aref = CR_AREF(cmd->chanlist[0]);
- /* make sure board is disabled before setting up aquisition */
+ /* make sure board is disabled before setting up aquisition */
spin_lock_irqsave(&dev->spinlock, flags);
devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
@@ -1105,9 +1149,9 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
/* initialize software conversion count */
- if (cmd->stop_src == TRIG_COUNT) {
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->count = cmd->stop_arg * cmd->chanlist_len;
- }
+
/* setup hardware conversion counter */
if (cmd->stop_src == TRIG_EXT) {
/* load counter a1 with count of 3 (pc+ manual says this is minimum allowed) using mode 0 */
@@ -1176,17 +1220,18 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
channel = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]);
else
channel = CR_CHAN(cmd->chanlist[0]);
- /* munge channel bits for differential / scan disabled mode */
+ /* munge channel bits for differential / scan disabled mode */
if (labpc_ai_scan_mode(cmd) != MODE_SINGLE_CHAN && aref == AREF_DIFF)
channel *= 2;
devpriv->command1_bits |= ADC_CHAN_BITS(channel);
devpriv->command1_bits |= thisboard->ai_range_code[range];
devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
- /* manual says to set scan enable bit on second pass */
+ /* manual says to set scan enable bit on second pass */
if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP ||
labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_DOWN) {
devpriv->command1_bits |= ADC_SCAN_EN_BIT;
- /* need a brief delay before enabling scan, or scan list will get screwed when you switch
+ /* need a brief delay before enabling scan, or scan
+ * list will get screwed when you switch
* between scan up to scan down mode - dunno why */
udelay(1);
devpriv->write_byte(devpriv->command1_bits,
@@ -1338,7 +1383,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
cmd = &async->cmd;
async->events = 0;
- /* read board status */
+ /* read board status */
devpriv->status1_bits = devpriv->read_byte(dev->iobase + STATUS1_REG);
if (thisboard->register_layout == labpc_1200_layout)
devpriv->status2_bits =
@@ -1352,7 +1397,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
}
if (devpriv->status1_bits & OVERRUN_BIT) {
- /* clear error interrupt */
+ /* clear error interrupt */
devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
comedi_event(dev, s);
@@ -1361,7 +1406,10 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
}
if (devpriv->current_transfer == isa_dma_transfer) {
- /* if a dma terminal count of external stop trigger has occurred */
+ /*
+ * if a dma terminal count of external stop trigger
+ * has occurred
+ */
if (devpriv->status1_bits & DMATC_BIT ||
(thisboard->register_layout == labpc_1200_layout
&& devpriv->status2_bits & A1_TC_BIT)) {
@@ -1479,9 +1527,9 @@ static void labpc_drain_dma(struct comedi_device *dev)
}
/* write data to comedi buffer */
- for (i = 0; i < num_points; i++) {
+ for (i = 0; i < num_points; i++)
cfc_write_to_buffer(s, devpriv->dma_buffer[i]);
- }
+
if (async->cmd.stop_src == TRIG_COUNT)
devpriv->count -= num_points;
@@ -1503,7 +1551,7 @@ static void handle_isa_dma(struct comedi_device *dev)
devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG);
}
-/* makes sure all data aquired by board is transfered to comedi (used
+/* makes sure all data acquired by board is transfered to comedi (used
* when aquisition is terminated by stop_src == TRIG_EXT). */
static void labpc_drain_dregs(struct comedi_device *dev)
{
@@ -1537,41 +1585,41 @@ static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
chan = CR_CHAN(insn->chanspec);
range = CR_RANGE(insn->chanspec);
devpriv->command1_bits |= thisboard->ai_range_code[range];
- /* munge channel bits for differential/scan disabled mode */
+ /* munge channel bits for differential/scan disabled mode */
if (CR_AREF(insn->chanspec) == AREF_DIFF)
chan *= 2;
devpriv->command1_bits |= ADC_CHAN_BITS(chan);
devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
- /* setup command6 register for 1200 boards */
+ /* setup command6 register for 1200 boards */
if (thisboard->register_layout == labpc_1200_layout) {
/* reference inputs to ground or common? */
if (CR_AREF(insn->chanspec) != AREF_GROUND)
devpriv->command6_bits |= ADC_COMMON_BIT;
else
devpriv->command6_bits &= ~ADC_COMMON_BIT;
- /* bipolar or unipolar range? */
+ /* bipolar or unipolar range? */
if (thisboard->ai_range_is_unipolar[range])
devpriv->command6_bits |= ADC_UNIP_BIT;
else
devpriv->command6_bits &= ~ADC_UNIP_BIT;
- /* don't interrupt on fifo half full */
+ /* don't interrupt on fifo half full */
devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT;
- /* don't enable interrupt on counter a1 terminal count? */
+ /* don't enable interrupt on counter a1 terminal count? */
devpriv->command6_bits &= ~A1_INTR_EN_BIT;
- /* write to register */
+ /* write to register */
devpriv->write_byte(devpriv->command6_bits,
dev->iobase + COMMAND6_REG);
}
- /* setup command4 register */
+ /* setup command4 register */
devpriv->command4_bits = 0;
devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT;
- /* single-ended/differential */
+ /* single-ended/differential */
if (CR_AREF(insn->chanspec) == AREF_DIFF)
devpriv->command4_bits |= ADC_DIFF_BIT;
devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
- /* initialize pacer counter output to make sure it doesn't cause any problems */
+ /* initialize pacer counter output to make sure it doesn't cause any problems */
devpriv->write_byte(INIT_A0_BITS, dev->iobase + COUNTER_A_CONTROL_REG);
labpc_clear_adc_fifo(dev);
@@ -1608,7 +1656,7 @@ static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
channel = CR_CHAN(insn->chanspec);
- /* turn off pacing of analog output channel */
+ /* turn off pacing of analog output channel */
/* note: hardware bug in daqcard-1200 means pacing cannot
* be independently enabled/disabled for its the two channels */
spin_lock_irqsave(&dev->spinlock, flags);
@@ -1616,7 +1664,7 @@ static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
spin_unlock_irqrestore(&dev->spinlock, flags);
- /* set range */
+ /* set range */
if (thisboard->register_layout == labpc_1200_layout) {
range = CR_RANGE(insn->chanspec);
if (range & AO_RANGE_IS_UNIPOLAR)
@@ -1627,13 +1675,13 @@ static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
devpriv->write_byte(devpriv->command6_bits,
dev->iobase + COMMAND6_REG);
}
- /* send data */
+ /* send data */
lsb = data[0] & 0xff;
msb = (data[0] >> 8) & 0xff;
devpriv->write_byte(lsb, dev->iobase + DAC_LSB_REG(channel));
devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(channel));
- /* remember value for readback */
+ /* remember value for readback */
devpriv->ao_value[channel] = data[0];
return 1;
@@ -1705,14 +1753,14 @@ static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd)
if (cmd.convert_src == TRIG_TIMER)
freq = 1000000000 / cmd.convert_arg;
- /* return some default value */
+ /* return some default value */
else
freq = 0xffffffff;
- /* make buffer fill in no more than 1/3 second */
+ /* make buffer fill in no more than 1/3 second */
size = (freq / 3) * sample_size;
- /* set a minimum and maximum size allowed */
+ /* set a minimum and maximum size allowed */
if (size > dma_buffer_size)
size = dma_buffer_size - dma_buffer_size % sample_size;
else if (size < sample_size)
@@ -1724,13 +1772,21 @@ static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd)
/* figures out what counter values to use based on command */
static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
{
- const int max_counter_value = 0x10000; /* max value for 16 bit counter in mode 2 */
- const int min_counter_value = 2; /* min value for 16 bit counter in mode 2 */
+ /* max value for 16 bit counter in mode 2 */
+ const int max_counter_value = 0x10000;
+ /* min value for 16 bit counter in mode 2 */
+ const int min_counter_value = 2;
unsigned int base_period;
- /* if both convert and scan triggers are TRIG_TIMER, then they both rely on counter b0 */
+ /*
+ * if both convert and scan triggers are TRIG_TIMER, then they
+ * both rely on counter b0
+ */
if (labpc_ai_convert_period(cmd) && labpc_ai_scan_period(cmd)) {
- /* pick the lowest b0 divisor value we can (for maximum input clock speed on convert and scan counters) */
+ /*
+ * pick the lowest b0 divisor value we can (for maximum input
+ * clock speed on convert and scan counters)
+ */
devpriv->divisor_b0 = (labpc_ai_scan_period(cmd) - 1) /
(LABPC_TIMER_BASE * max_counter_value) + 1;
if (devpriv->divisor_b0 < min_counter_value)
@@ -1780,7 +1836,10 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
base_period * devpriv->divisor_a0);
labpc_set_ai_scan_period(cmd,
base_period * devpriv->divisor_b1);
- /* if only one TRIG_TIMER is used, we can employ the generic cascaded timing functions */
+ /*
+ * if only one TRIG_TIMER is used, we can employ the generic
+ * cascaded timing functions
+ */
} else if (labpc_ai_scan_period(cmd)) {
unsigned int scan_period;
@@ -1864,9 +1923,8 @@ static unsigned int labpc_serial_in(struct comedi_device *dev)
udelay(1);
devpriv->status2_bits =
devpriv->read_byte(dev->iobase + STATUS2_REG);
- if (devpriv->status2_bits & EEPROM_OUT_BIT) {
+ if (devpriv->status2_bits & EEPROM_OUT_BIT)
value |= 1 << (value_width - i);
- }
}
return value;
@@ -1876,8 +1934,10 @@ static unsigned int labpc_eeprom_read(struct comedi_device *dev,
unsigned int address)
{
unsigned int value;
- const int read_instruction = 0x3; /* bits to tell eeprom to expect a read */
- const int write_length = 8; /* 8 bit write lengths to eeprom */
+ /* bits to tell eeprom to expect a read */
+ const int read_instruction = 0x3;
+ /* 8 bit write lengths to eeprom */
+ const int write_length = 8;
/* enable read/write to eeprom */
devpriv->command5_bits &= ~EEPROM_EN_BIT;
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index d6d49c3bbf1c..bd16f913af23 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -3795,7 +3795,7 @@ static int ni_cdo_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
#endif
int retval = 0;
unsigned i;
- const unsigned timeout = 100;
+ const unsigned timeout = 1000;
s->async->inttrig = NULL;
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 2d88a5be65ff..9d337516409d 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -1,8 +1,8 @@
/*
comedi/drivers/ni_pcidio.c
driver for National Instruments PCI-DIO-96/PCI-6508
- National Instruments PCI-DIO-32HS
- National Instruments PCI-6503
+ National Instruments PCI-DIO-32HS
+ National Instruments PCI-6503
COMEDI - Linux Control and Measurement Device Interface
Copyright (C) 1999,2002 David A. Schleef <ds@schleef.org>
@@ -518,7 +518,8 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
ni_pcidio_print_status(status);
/* printk("buf[0]=%08x\n",*(unsigned int *)async->prealloc_buf); */
- /* printk("buf[4096]=%08x\n",*(unsigned int *)(async->prealloc_buf+4096)); */
+ /* printk("buf[4096]=%08x\n",
+ *(unsigned int *)(async->prealloc_buf+4096)); */
spin_lock_irqsave(&devpriv->mite_channel_lock, irq_flags);
if (devpriv->di_mite_chan)
@@ -526,7 +527,9 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
#ifdef MITE_DEBUG
mite_print_chsr(m_status);
#endif
- /* printk("mite_bytes_transferred: %d\n",mite_bytes_transferred(mite,DI_DMA_CHAN)); */
+ /* printk("mite_bytes_transferred: %d\n",
+ mite_bytes_transferred(mite,DI_DMA_CHAN)); */
+
/* mite_dump_regs(mite); */
if (m_status & CHSR_INT) {
if (m_status & CHSR_LINKC) {
@@ -565,7 +568,8 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
DPRINTK("too much work in interrupt\n");
writeb(0x00,
devpriv->mite->daq_io_addr +
- Master_DMA_And_Interrupt_Control);
+ Master_DMA_And_Interrupt_Control
+ );
goto out;
}
AuxData =
@@ -579,8 +583,10 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
flags = readb(devpriv->mite->daq_io_addr +
Group_1_Flags);
}
- /* DPRINTK("buf_int_count: %d\n",async->buf_int_count); */
- /* DPRINTK("1) IntEn=%d,flags=%d,status=%d\n",IntEn,flags,status); */
+ /* DPRINTK("buf_int_count: %d\n",
+ async->buf_int_count); */
+ /* DPRINTK("1) IntEn=%d,flags=%d,status=%d\n",
+ IntEn,flags,status); */
/* ni_pcidio_print_flags(flags); */
/* ni_pcidio_print_status(status); */
async->events |= COMEDI_CB_BLOCK;
@@ -627,8 +633,8 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags);
status = readb(devpriv->mite->daq_io_addr +
Interrupt_And_Window_Status);
- /* DPRINTK("loop end: IntEn=0x%02x,flags=0x%02x,status=0x%02x\n", */
- /* IntEn,flags,status); */
+ /* DPRINTK("loop end: IntEn=0x%02x,flags=0x%02x,"
+ "status=0x%02x\n", IntEn, flags, status); */
/* ni_pcidio_print_flags(flags); */
/* ni_pcidio_print_status(status); */
}
@@ -655,11 +661,10 @@ static void ni_pcidio_print_flags(unsigned int flags)
{
int i;
- printk("group_1_flags:");
+ printk(KERN_INFO "group_1_flags:");
for (i = 7; i >= 0; i--) {
- if (flags & (1 << i)) {
+ if (flags & (1 << i))
printk(" %s", flags_strings[i]);
- }
}
printk("\n");
}
@@ -673,11 +678,10 @@ static void ni_pcidio_print_status(unsigned int flags)
{
int i;
- printk("group_status:");
+ printk(KERN_INFO "group_status:");
for (i = 7; i >= 0; i--) {
- if (flags & (1 << i)) {
+ if (flags & (1 << i))
printk(" %s", status_strings[i]);
- }
}
printk("\n");
}
@@ -793,7 +797,8 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev,
if (err)
return 1;
- /* step 2: make sure trigger sources are unique and mutually compatible */
+ /* step 2: make sure trigger sources are unique and mutually
+ compatible */
/* note that mutual compatibility is not an issue here */
if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_INT)
@@ -974,7 +979,8 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* clear and enable interrupts */
writeb(0xff, devpriv->mite->daq_io_addr + Group_1_First_Clear);
- /* writeb(ClearExpired,devpriv->mite->daq_io_addr+Group_1_Second_Clear); */
+ /* writeb(ClearExpired,
+ devpriv->mite->daq_io_addr+Group_1_Second_Clear); */
writeb(IntEn, devpriv->mite->daq_io_addr + Interrupt_Control);
writeb(0x03,
@@ -1052,7 +1058,7 @@ static int ni_pcidio_change(struct comedi_device *dev,
}
static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index,
- u8 * data, int data_len)
+ u8 *data, int data_len)
{
static const int timeout = 1000;
int i, j;
@@ -1066,9 +1072,8 @@ static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index,
udelay(1);
}
if (i == timeout) {
- printk
- ("ni_pcidio: failed to load fpga %i, waiting for status 0x2\n",
- fpga_index);
+ printk(KERN_WARNING "ni_pcidio: failed to load fpga %i, "
+ "waiting for status 0x2\n", fpga_index);
return -EIO;
}
writew(0x80 | fpga_index,
@@ -1079,9 +1084,8 @@ static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index,
udelay(1);
}
if (i == timeout) {
- printk
- ("ni_pcidio: failed to load fpga %i, waiting for status 0x3\n",
- fpga_index);
+ printk(KERN_WARNING "ni_pcidio: failed to load fpga %i, "
+ "waiting for status 0x3\n", fpga_index);
return -EIO;
}
for (j = 0; j + 1 < data_len;) {
@@ -1174,9 +1178,10 @@ static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
int n_subdevices;
unsigned int irq;
- printk("comedi%d: nidio:", dev->minor);
+ printk(KERN_INFO "comedi%d: nidio:", dev->minor);
- if ((ret = alloc_private(dev, sizeof(struct nidio96_private))) < 0)
+ ret = alloc_private(dev, sizeof(struct nidio96_private));
+ if (ret < 0)
return ret;
spin_lock_init(&devpriv->mite_channel_lock);
@@ -1186,7 +1191,7 @@ static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
ret = mite_setup(devpriv->mite);
if (ret < 0) {
- printk("error setting up mite\n");
+ printk(KERN_WARNING "error setting up mite\n");
return ret;
}
comedi_set_hw_dev(dev, &devpriv->mite->pcidev->dev);
@@ -1196,18 +1201,19 @@ static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev->board_name = this_board->name;
irq = mite_irq(devpriv->mite);
- printk(" %s", dev->board_name);
+ printk(KERN_INFO " %s", dev->board_name);
if (this_board->uses_firmware) {
ret = pci_6534_upload_firmware(dev, it->options);
if (ret < 0)
return ret;
}
- if (!this_board->is_diodaq) {
+ if (!this_board->is_diodaq)
n_subdevices = this_board->n_8255;
- } else {
+ else
n_subdevices = 1;
- }
- if ((ret = alloc_subdevices(dev, n_subdevices)) < 0)
+
+ ret = alloc_subdevices(dev, n_subdevices);
+ if (ret < 0)
return ret;
if (!this_board->is_diodaq) {
@@ -1220,7 +1226,7 @@ static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
} else {
- printk(" rev=%d",
+ printk(KERN_INFO " rev=%d",
readb(devpriv->mite->daq_io_addr + Chip_Version));
s = dev->subdevices + 0;
@@ -1253,9 +1259,9 @@ static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
ret = request_irq(irq, nidio_interrupt, IRQF_SHARED,
"ni_pcidio", dev);
- if (ret < 0) {
- printk(" irq not available");
- }
+ if (ret < 0)
+ printk(KERN_WARNING " irq not available");
+
dev->irq = irq;
}
@@ -1269,9 +1275,8 @@ static int nidio_detach(struct comedi_device *dev)
int i;
if (this_board && !this_board->is_diodaq) {
- for (i = 0; i < this_board->n_8255; i++) {
+ for (i = 0; i < this_board->n_8255; i++)
subdev_8255_cleanup(dev, dev->subdevices + i);
- }
}
if (dev->irq)
@@ -1310,7 +1315,7 @@ static int nidio_find_device(struct comedi_device *dev, int bus, int slot)
}
}
}
- printk("no device found\n");
+ printk(KERN_WARNING "no device found\n");
mite_list_devices();
return -EIO;
}
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index 4914784f6995..a499f7070f72 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -207,11 +207,10 @@ static irqreturn_t pcl711_interrupt(int irq, void *d)
/* FIXME! Nothing else sets ntrig! */
if (!(--devpriv->ntrig)) {
- if (this_board->is_8112) {
+ if (this_board->is_8112)
outb(1, dev->iobase + PCL711_MODE);
- } else {
+ else
outb(0, dev->iobase + PCL711_MODE);
- }
s->async->events |= COMEDI_CB_EOA;
}
@@ -232,15 +231,15 @@ static void pcl711_set_changain(struct comedi_device *dev, int chan)
/*
* Set the correct channel. The two channel banks are switched
* using the mask value.
- * NB: To use differential channels, you should use mask = 0x30,
- * but I haven't written the support for this yet. /JJ
+ * NB: To use differential channels, you should use
+ * mask = 0x30, but I haven't written the support for this
+ * yet. /JJ
*/
- if (chan_register >= 8) {
+ if (chan_register >= 8)
chan_register = 0x20 | (chan_register & 0x7);
- } else {
+ else
chan_register |= 0x10;
- }
} else {
outb(chan_register, dev->iobase + PCL711_MUX);
}
@@ -256,15 +255,13 @@ static int pcl711_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
for (n = 0; n < insn->n; n++) {
/*
- * Write the correct mode (software polling) and start polling by writing
- * to the trigger register
+ * Write the correct mode (software polling) and start polling
+ * by writing to the trigger register
*/
outb(1, dev->iobase + PCL711_MODE);
- if (this_board->is_8112) {
- } else {
+ if (!this_board->is_8112)
outb(0, dev->iobase + PCL711_SOFTTRIG);
- }
i = PCL711_TIMEOUT;
while (--i) {
@@ -462,9 +459,8 @@ static int pcl711_ao_insn_read(struct comedi_device *dev,
int n;
int chan = CR_CHAN(insn->chanspec);
- for (n = 0; n < insn->n; n++) {
+ for (n = 0; n < insn->n; n++)
data[n] = devpriv->ao_readback[chan];
- }
return n;
@@ -619,9 +615,8 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
this is the "base value" for the mode register, which is
used for the irq on the PCL711
*/
- if (this_board->is_pcl711b) {
+ if (this_board->is_pcl711b)
devpriv->mode = (dev->irq << 4);
- }
/* clear DAC */
outb(0, dev->iobase + PCL711_DA0_LO);
diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c
index df1f4ef14616..0f103c328064 100644
--- a/drivers/staging/comedi/drivers/pcl724.c
+++ b/drivers/staging/comedi/drivers/pcl724.c
@@ -17,7 +17,7 @@
[0] - IO Base
[1] - IRQ (0=disable IRQ) IRQ isn't supported at this time!
[2] -number of DIO:
- 0, 144: 144 DIO configuration
+ 0, 144: 144 DIO configuration
1, 96: 96 DIO configuration
*/
/*
@@ -137,8 +137,8 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it)
iorange = this_board->io_range;
if ((this_board->can_have96) && ((it->options[1] == 1)
|| (it->options[1] == 96)))
- iorange = PCL722_96_SIZE; /* PCL-724 in 96 DIO configuration */
- printk("comedi%d: pcl724: board=%s, 0x%03lx ", dev->minor,
+ iorange = PCL722_96_SIZE; /* PCL-724 in 96 DIO configuration */
+ printk(KERN_INFO "comedi%d: pcl724: board=%s, 0x%03lx ", dev->minor,
this_board->name, iobase);
if (!request_region(iobase, iorange, "pcl724")) {
printk("I/O port conflict\n");
@@ -155,16 +155,16 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it)
irq = it->options[1];
if (irq) { /* we want to use IRQ */
if (((1 << irq) & this_board->IRQbits) == 0) {
- printk
- (", IRQ %u is out of allowed range, DISABLING IT",
- irq);
+ printk(KERN_WARNING
+ ", IRQ %u is out of allowed range, "
+ "DISABLING IT", irq);
irq = 0; /* Bad IRQ */
} else {
if (request_irq
(irq, interrupt_pcl724, 0, "pcl724", dev)) {
- printk
- (", unable to allocate IRQ %u, DISABLING IT",
- irq);
+ printk(KERN_WARNING
+ ", unable to allocate IRQ %u, "
+ "DISABLING IT", irq);
irq = 0; /* Can't use IRQ */
} else {
printk(", irq=%u", irq);
@@ -207,16 +207,14 @@ static int pcl724_detach(struct comedi_device *dev)
{
int i;
-/* printk("comedi%d: pcl724: remove\n",dev->minor); */
+ /* printk("comedi%d: pcl724: remove\n",dev->minor); */
- for (i = 0; i < dev->n_subdevices; i++) {
+ for (i = 0; i < dev->n_subdevices; i++)
subdev_8255_cleanup(dev, dev->subdevices + i);
- }
#ifdef PCL724_IRQ
- if (dev->irq) {
+ if (dev->irq)
free_irq(dev->irq, dev);
- }
#endif
release_region(dev->iobase, this_board->io_range);
diff --git a/drivers/staging/comedi/drivers/pcl725.c b/drivers/staging/comedi/drivers/pcl725.c
index 1da4941fce49..60261f4ba5b4 100644
--- a/drivers/staging/comedi/drivers/pcl725.c
+++ b/drivers/staging/comedi/drivers/pcl725.c
@@ -66,7 +66,7 @@ static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it)
unsigned long iobase;
iobase = it->options[0];
- printk("comedi%d: pcl725: 0x%04lx ", dev->minor, iobase);
+ printk(KERN_INFO "comedi%d: pcl725: 0x%04lx ", dev->minor, iobase);
if (!request_region(iobase, PCL725_SIZE, "pcl725")) {
printk("I/O port conflict\n");
return -EIO;
@@ -96,14 +96,14 @@ static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->insn_bits = pcl725_di_insn;
s->range_table = &range_digital;
- printk("\n");
+ printk(KERN_INFO "\n");
return 0;
}
static int pcl725_detach(struct comedi_device *dev)
{
- printk("comedi%d: pcl725: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: pcl725: remove\n", dev->minor);
if (dev->iobase)
release_region(dev->iobase, PCL725_SIZE);
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index c9859c90c152..e5e7bed21de0 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -99,7 +99,7 @@ static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it)
iobase = it->options[0];
iorange = this_board->io_range;
- printk("comedi%d: pcl730: board=%s 0x%04lx ", dev->minor,
+ printk(KERN_INFO "comedi%d: pcl730: board=%s 0x%04lx ", dev->minor,
this_board->name, iobase);
if (!request_region(iobase, iorange, "pcl730")) {
printk("I/O port conflict\n");
@@ -152,14 +152,14 @@ static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->range_table = &range_digital;
s->private = (void *)PCL730_DIO_LO;
- printk("\n");
+ printk(KERN_INFO "\n");
return 0;
}
static int pcl730_detach(struct comedi_device *dev)
{
- printk("comedi%d: pcl730: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: pcl730: remove\n", dev->minor);
if (dev->iobase)
release_region(dev->iobase, this_board->io_range);
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index 0a5bc3d6da8c..d4634c4f02dc 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -955,6 +955,7 @@ static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d)
unsigned int mask, timeout;
struct comedi_device *dev = d;
struct comedi_subdevice *s = dev->subdevices + 0;
+ unsigned int next_chan;
s->async->events = 0;
@@ -993,9 +994,18 @@ static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d)
((inb(dev->iobase + PCL812_AD_HI) << 8) |
inb(dev->iobase + PCL812_AD_LO)) & mask);
+ /* Set up next channel. Added by abbotti 2010-01-20, but untested. */
+ next_chan = s->async->cur_chan + 1;
+ if (next_chan >= devpriv->ai_n_chan)
+ next_chan = 0;
+ if (devpriv->ai_chanlist[s->async->cur_chan] !=
+ devpriv->ai_chanlist[next_chan])
+ setup_range_channel(dev, s, devpriv->ai_chanlist[next_chan], 0);
+
outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
- if (s->async->cur_chan == 0) { /* one scan done */
+ s->async->cur_chan = next_chan;
+ if (next_chan == 0) { /* one scan done */
devpriv->ai_act_scan++;
if (!(devpriv->ai_neverending))
if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */
@@ -1021,7 +1031,9 @@ static void transfer_from_dma_buf(struct comedi_device *dev,
for (i = len; i; i--) {
comedi_buf_put(s->async, ptr[bufptr++]); /* get one sample */
- if (s->async->cur_chan == 0) {
+ s->async->cur_chan++;
+ if (s->async->cur_chan >= devpriv->ai_n_chan) {
+ s->async->cur_chan = 0;
devpriv->ai_act_scan++;
if (!devpriv->ai_neverending)
if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index 852fe2458fdc..9820759ec54f 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -202,6 +202,7 @@ struct pcl816_private {
unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */
unsigned int ai_act_chanlist_len; /* how long is actual MUX list */
unsigned int ai_act_chanlist_pos; /* actual position in MUX list */
+ unsigned int ai_n_chan; /* how many channels per scan */
unsigned int ai_poll_ptr; /* how many sampes transfer poll */
struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
#ifdef unused
@@ -213,9 +214,12 @@ struct pcl816_private {
/*
==============================================================================
*/
-static int check_and_setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, int chanlen);
+static int check_channel_list(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int *chanlist, unsigned int chanlen);
+static void setup_channel_list(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int *chanlist, unsigned int seglen);
static int pcl816_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s);
static void start_pacer(struct comedi_device *dev, int mode,
@@ -320,7 +324,9 @@ static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d)
if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len)
devpriv->ai_act_chanlist_pos = 0;
- if (s->async->cur_chan == 0) {
+ s->async->cur_chan++;
+ if (s->async->cur_chan >= devpriv->ai_n_chan) {
+ s->async->cur_chan = 0;
devpriv->ai_act_scan++;
}
@@ -353,6 +359,11 @@ static void transfer_from_dma_buf(struct comedi_device *dev,
if (++devpriv->ai_act_chanlist_pos >=
devpriv->ai_act_chanlist_len) {
devpriv->ai_act_chanlist_pos = 0;
+ }
+
+ s->async->cur_chan++;
+ if (s->async->cur_chan >= devpriv->ai_n_chan) {
+ s->async->cur_chan = 0;
devpriv->ai_act_scan++;
}
@@ -558,14 +569,6 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
}
}
- if (!cmd->chanlist_len) {
- cmd->chanlist_len = 1;
- err++;
- }
- if (cmd->chanlist_len > this_board->n_aichan) {
- cmd->chanlist_len = this_board->n_aichan;
- err++;
- }
if (cmd->scan_end_arg != cmd->chanlist_len) {
cmd->scan_end_arg = cmd->chanlist_len;
err++;
@@ -603,6 +606,14 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
return 4;
}
+ /* step 5: complain about special chanlist considerations */
+
+ if (cmd->chanlist) {
+ if (!check_channel_list(dev, s, cmd->chanlist,
+ cmd->chanlist_len))
+ return 5; /* incorrect channels list */
+ }
+
return 0;
}
@@ -610,6 +621,7 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq;
struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int seglen;
if (cmd->start_src != TRIG_NOW)
return -EINVAL;
@@ -642,11 +654,13 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
start_pacer(dev, -1, 0, 0); /* stop pacer */
- if (!check_and_setup_channel_list(dev, s, cmd->chanlist,
- cmd->chanlist_len))
+ seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
+ if (seglen < 1)
return -EINVAL;
+ setup_channel_list(dev, s, cmd->chanlist, seglen);
udelay(1);
+ devpriv->ai_n_chan = cmd->chanlist_len;
devpriv->ai_act_scan = 0;
s->async->cur_chan = 0;
devpriv->irq_blocked = 1;
@@ -871,12 +885,12 @@ start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
/*
==============================================================================
Check if channel list from user is builded correctly
- If it's ok, then program scan/gain logic
+ If it's ok, then return non-zero length of repeated segment of channel list
*/
static int
-check_and_setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int *chanlist,
- int chanlen)
+check_channel_list(struct comedi_device *dev,
+ struct comedi_subdevice *s, unsigned int *chanlist,
+ unsigned int chanlen)
{
unsigned int chansegment[16];
unsigned int i, nowmustbechan, seglen, segpos;
@@ -930,6 +944,20 @@ check_and_setup_channel_list(struct comedi_device *dev,
seglen = 1;
}
+ return seglen; /* we can serve this with MUX logic */
+}
+
+/*
+==============================================================================
+ Program scan/gain logic with channel list.
+*/
+static void
+setup_channel_list(struct comedi_device *dev,
+ struct comedi_subdevice *s, unsigned int *chanlist,
+ unsigned int seglen)
+{
+ unsigned int i;
+
devpriv->ai_act_chanlist_len = seglen;
devpriv->ai_act_chanlist_pos = 0;
@@ -942,8 +970,6 @@ check_and_setup_channel_list(struct comedi_device *dev,
udelay(1);
outb(devpriv->ai_act_chanlist[0] | (devpriv->ai_act_chanlist[seglen - 1] << 4), dev->iobase + PCL816_MUX); /* select channel interval to scan */
-
- return 1; /* we can serve this with MUX logic */
}
#ifdef unused
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index d0481013a837..c9d75385755d 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -557,8 +557,14 @@ conv_finish:
comedi_event(dev, s);
return IRQ_HANDLED;
}
- if (s->async->cur_chan == 0) {
+ devpriv->act_chanlist_pos++;
+ if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
+ devpriv->act_chanlist_pos = 0;
+ }
+ s->async->cur_chan++;
+ if (s->async->cur_chan >= devpriv->ai_n_chan) {
/* printk("E"); */
+ s->async->cur_chan = 0;
devpriv->ai_act_scan--;
}
@@ -627,9 +633,13 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
devpriv->act_chanlist_pos++;
if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
- devpriv->ai_act_scan--;
devpriv->act_chanlist_pos = 0;
}
+ s->async->cur_chan++;
+ if (s->async->cur_chan >= devpriv->ai_n_chan) {
+ s->async->cur_chan = 0;
+ devpriv->ai_act_scan--;
+ }
if (!devpriv->neverending_ai)
if (devpriv->ai_act_scan == 0) { /* all data sampled */
@@ -717,7 +727,14 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); /* get one sample */
bufptr &= (devpriv->dmasamplsize - 1);
- if (s->async->cur_chan == 0) {
+ devpriv->act_chanlist_pos++;
+ if (devpriv->act_chanlist_pos >=
+ devpriv->act_chanlist_len) {
+ devpriv->act_chanlist_pos = 0;
+ }
+ s->async->cur_chan++;
+ if (s->async->cur_chan >= devpriv->ai_n_chan) {
+ s->async->cur_chan = 0;
devpriv->ai_act_scan--;
}
@@ -796,7 +813,13 @@ static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */
- if (s->async->cur_chan == 0) {
+ devpriv->act_chanlist_pos++;
+ if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
+ devpriv->act_chanlist_pos = 0;
+ }
+ s->async->cur_chan++;
+ if (s->async->cur_chan >= devpriv->ai_n_chan) {
+ s->async->cur_chan = 0;
devpriv->ai_act_scan--;
}
@@ -1369,14 +1392,6 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
}
}
- if (!cmd->chanlist_len) {
- cmd->chanlist_len = 1;
- err++;
- }
- if (cmd->chanlist_len > s->n_chan) {
- cmd->chanlist_len = s->n_chan;
- err++;
- }
if (cmd->scan_end_arg != cmd->chanlist_len) {
cmd->scan_end_arg = cmd->chanlist_len;
err++;
diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c
index 52811824b05a..ed6103079232 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -121,25 +121,22 @@ static int compute_buffer(int config, int devno, struct comedi_subdevice *s)
{
/* 1 in io_bits indicates output */
if (s->io_bits & 0x0000ff) {
- if (devno == 0) {
+ if (devno == 0)
config |= BUF_A0;
- } else {
+ else
config |= BUF_A1;
- }
}
if (s->io_bits & 0x00ff00) {
- if (devno == 0) {
+ if (devno == 0)
config |= BUF_B0;
- } else {
+ else
config |= BUF_B1;
- }
}
if (s->io_bits & 0xff0000) {
- if (devno == 0) {
+ if (devno == 0)
config |= BUF_C0;
- } else {
+ else
config |= BUF_C1;
- }
}
return config;
}
@@ -155,26 +152,27 @@ static void do_3724_config(struct comedi_device *dev,
buffer_config = 0;
/* 1 in io_bits indicates output, 1 in config indicates input */
- if (!(s->io_bits & 0x0000ff)) {
+ if (!(s->io_bits & 0x0000ff))
config |= CR_A_IO;
- }
- if (!(s->io_bits & 0x00ff00)) {
+
+ if (!(s->io_bits & 0x00ff00))
config |= CR_B_IO;
- }
- if (!(s->io_bits & 0xff0000)) {
+
+ if (!(s->io_bits & 0xff0000))
config |= CR_C_IO;
- }
buffer_config = compute_buffer(0, 0, dev->subdevices);
buffer_config = compute_buffer(buffer_config, 1, (dev->subdevices) + 1);
- if (s == dev->subdevices) {
+ if (s == dev->subdevices)
port_8255_cfg = dev->iobase + _8255_CR;
- } else {
+ else
port_8255_cfg = dev->iobase + SIZE_8255 + _8255_CR;
- }
+
outb(buffer_config, dev->iobase + 8); /* update buffer register */
- /* printk("pcm3724 buffer_config (%lx) %d, %x\n", dev->iobase + _8255_CR, chanspec, buffer_config); */
+ /* printk("pcm3724 buffer_config (%lx) %d, %x\n",
+ dev->iobase + _8255_CR, chanspec, buffer_config); */
+
outb(config, port_8255_cfg);
}
@@ -189,29 +187,29 @@ static void enable_chan(struct comedi_device *dev, struct comedi_subdevice *s,
priv = (struct priv_pcm3724 *)(dev->private);
mask = 1 << CR_CHAN(chanspec);
- if (s == dev->subdevices) { /* subdev 0 */
+ if (s == dev->subdevices) /* subdev 0 */
priv->dio_1 |= mask;
- } else { /* subdev 1 */
+ else /* subdev 1 */
priv->dio_2 |= mask;
- }
- if (priv->dio_1 & 0xff0000) {
+
+ if (priv->dio_1 & 0xff0000)
gatecfg |= GATE_C0;
- }
- if (priv->dio_1 & 0xff00) {
+
+ if (priv->dio_1 & 0xff00)
gatecfg |= GATE_B0;
- }
- if (priv->dio_1 & 0xff) {
+
+ if (priv->dio_1 & 0xff)
gatecfg |= GATE_A0;
- }
- if (priv->dio_2 & 0xff0000) {
+
+ if (priv->dio_2 & 0xff0000)
gatecfg |= GATE_C1;
- }
- if (priv->dio_2 & 0xff00) {
+
+ if (priv->dio_2 & 0xff00)
gatecfg |= GATE_B1;
- }
- if (priv->dio_2 & 0xff) {
+
+ if (priv->dio_2 & 0xff)
gatecfg |= GATE_A1;
- }
+
/* printk("gate control %x\n", gatecfg); */
outb(gatecfg, dev->iobase + 9);
}
@@ -225,15 +223,14 @@ static int subdev_3724_insn_config(struct comedi_device *dev,
unsigned int bits;
mask = 1 << CR_CHAN(insn->chanspec);
- if (mask & 0x0000ff) {
+ if (mask & 0x0000ff)
bits = 0x0000ff;
- } else if (mask & 0x00ff00) {
+ else if (mask & 0x00ff00)
bits = 0x00ff00;
- } else if (mask & 0x0f0000) {
+ else if (mask & 0x0f0000)
bits = 0x0f0000;
- } else {
+ else
bits = 0xf00000;
- }
switch (data[0]) {
case INSN_CONFIG_DIO_INPUT:
@@ -272,7 +269,7 @@ static int pcm3724_attach(struct comedi_device *dev,
((struct priv_pcm3724 *)(dev->private))->dio_1 = 0;
((struct priv_pcm3724 *)(dev->private))->dio_2 = 0;
- printk("comedi%d: pcm3724: board=%s, 0x%03lx ", dev->minor,
+ printk(KERN_INFO "comedi%d: pcm3724: board=%s, 0x%03lx ", dev->minor,
this_board->name, iobase);
if (!iobase || !request_region(iobase, iorange, "pcm3724")) {
printk("I/O port conflict\n");
@@ -281,7 +278,7 @@ static int pcm3724_attach(struct comedi_device *dev,
dev->iobase = iobase;
dev->board_name = this_board->name;
- printk("\n");
+ printk(KERN_INFO "\n");
n_subdevices = this_board->numofports;
@@ -302,13 +299,11 @@ static int pcm3724_detach(struct comedi_device *dev)
int i;
if (dev->subdevices) {
- for (i = 0; i < dev->n_subdevices; i++) {
+ for (i = 0; i < dev->n_subdevices; i++)
subdev_8255_cleanup(dev, dev->subdevices + i);
- }
}
- if (dev->iobase) {
+ if (dev->iobase)
release_region(dev->iobase, this_board->io_range);
- }
return 0;
}
diff --git a/drivers/staging/comedi/drivers/pcm3730.c b/drivers/staging/comedi/drivers/pcm3730.c
index 9e4adbd89dda..22b7aae63add 100644
--- a/drivers/staging/comedi/drivers/pcm3730.c
+++ b/drivers/staging/comedi/drivers/pcm3730.c
@@ -73,7 +73,7 @@ static int pcm3730_attach(struct comedi_device *dev,
unsigned long iobase;
iobase = it->options[0];
- printk("comedi%d: pcm3730: 0x%04lx ", dev->minor, iobase);
+ printk(KERN_INFO "comedi%d: pcm3730: 0x%04lx ", dev->minor, iobase);
if (!request_region(iobase, PCM3730_SIZE, "pcm3730")) {
printk("I/O port conflict\n");
return -EIO;
@@ -140,14 +140,14 @@ static int pcm3730_attach(struct comedi_device *dev,
s->range_table = &range_digital;
s->private = (void *)PCM3730_DIC;
- printk("\n");
+ printk(KERN_INFO "\n");
return 0;
}
static int pcm3730_detach(struct comedi_device *dev)
{
- printk("comedi%d: pcm3730: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: pcm3730: remove\n", dev->minor);
if (dev->iobase)
release_region(dev->iobase, PCM3730_SIZE);
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index acac67090810..fab8092bd7aa 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -34,11 +34,11 @@ Configuration options:
[0] - I/O port base
[1] - unused
[2] - Analog input reference
- 0 = single ended
- 1 = differential
+ 0 = single ended
+ 1 = differential
[3] - Analog input encoding (must match jumpers)
- 0 = straight binary
- 1 = two's complement
+ 0 = straight binary
+ 1 = two's complement
*/
#include <linux/interrupt.h>
@@ -113,9 +113,8 @@ static int pcmad_ai_insn_read(struct comedi_device *dev,
data[n] = inb(dev->iobase + PCMAD_LSB);
data[n] |= (inb(dev->iobase + PCMAD_MSB) << 8);
- if (devpriv->twos_comp) {
+ if (devpriv->twos_comp)
data[n] ^= (1 << (this_board->n_ai_bits - 1));
- }
}
return n;
@@ -135,11 +134,12 @@ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it)
unsigned long iobase;
iobase = it->options[0];
- printk("comedi%d: pcmad: 0x%04lx ", dev->minor, iobase);
+ printk(KERN_INFO "comedi%d: pcmad: 0x%04lx ", dev->minor, iobase);
if (!request_region(iobase, PCMAD_SIZE, "pcmad")) {
- printk("I/O port conflict\n");
+ printk(KERN_CONT "I/O port conflict\n");
return -EIO;
}
+ printk(KERN_CONT "\n");
dev->iobase = iobase;
ret = alloc_subdevices(dev, 1);
@@ -166,11 +166,11 @@ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it)
static int pcmad_detach(struct comedi_device *dev)
{
- printk("comedi%d: pcmad: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: pcmad: remove\n", dev->minor);
- if (dev->irq) {
+ if (dev->irq)
free_irq(dev->irq, dev);
- }
+
if (dev->iobase)
release_region(dev->iobase, PCMAD_SIZE);
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index 35ba93989a36..6ca4105610c1 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -550,7 +550,7 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (irq[0]) {
printk("irq: %u ", irq[0]);
- if (irq[1] && thisboard->dio_num_asics == 2)
+ if (thisboard->dio_num_asics == 2 && irq[1])
printk("second ASIC irq: %u ", irq[1]);
} else {
printk("(IRQ mode disabled) ");
diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c
index d23e588d0632..1ebc356ce40e 100644
--- a/drivers/staging/comedi/drivers/poc.c
+++ b/drivers/staging/comedi/drivers/poc.c
@@ -122,22 +122,21 @@ static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
unsigned int iosize;
iobase = it->options[0];
- printk("comedi%d: poc: using %s iobase 0x%lx\n", dev->minor,
+ printk(KERN_INFO "comedi%d: poc: using %s iobase 0x%lx\n", dev->minor,
this_board->name, iobase);
dev->board_name = this_board->name;
if (iobase == 0) {
- printk("io base address required\n");
+ printk(KERN_ERR "io base address required\n");
return -EINVAL;
}
iosize = this_board->iosize;
/* check if io addresses are available */
if (!request_region(iobase, iosize, "dac02")) {
- printk
- ("I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
- iobase, iobase + iosize - 1);
+ printk(KERN_ERR "I/O port conflict: failed to allocate ports "
+ "0x%lx to 0x%lx\n", iobase, iobase + iosize - 1);
return -EIO;
}
dev->iobase = iobase;
@@ -156,9 +155,8 @@ static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->insn_write = this_board->winsn;
s->insn_read = this_board->rinsn;
s->insn_bits = this_board->insnbits;
- if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) {
+ if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO)
s->subdev_flags = SDF_WRITABLE;
- }
return 0;
}
@@ -169,7 +167,7 @@ static int poc_detach(struct comedi_device *dev)
if (dev->iobase)
release_region(dev->iobase, this_board->iosize);
- printk("comedi%d: dac02: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: dac02: remove\n", dev->minor);
return 0;
}
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index 2c9d05bd288c..028ed6f89c4c 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -32,22 +32,22 @@ Configuration options:
[0] - I/O port base address
[1] - IRQ
[2] - A/D reference
- 0 = differential
- 1 = pseudodifferential (common)
- 2 = single-ended
+ 0 = differential
+ 1 = pseudodifferential (common)
+ 2 = single-ended
[3] - A/D range
- 0 = [-10,10]
- 1 = [-5,5]
- 2 = [0,10]
+ 0 = [-10,10]
+ 1 = [-5,5]
+ 2 = [0,10]
[4] - A/D encoding
- 0 = two's complement
- 1 = straight binary
+ 0 = two's complement
+ 1 = straight binary
[5] - DAC 0 range
- 0 = [-10,10]
- 1 = [0,10]
+ 0 = [-10,10]
+ 1 = [0,10]
[6] - DAC 0 encoding
- 0 = two's complement
- 1 = straight binary
+ 0 = two's complement
+ 1 = straight binary
[7] - DAC 1 range (same as DAC 0)
[8] - DAC 1 encoding (same as DAC 0)
*/
@@ -225,7 +225,7 @@ static int rti800_ai_insn_read(struct comedi_device *dev,
for (t = RTI800_TIMEOUT; t; t--) {
status = inb(dev->iobase + RTI800_CSR);
if (status & RTI800_OVERRUN) {
- printk("rti800: a/d overrun\n");
+ printk(KERN_WARNING "rti800: a/d overrun\n");
outb(0, dev->iobase + RTI800_CLRFLAGS);
return -EIO;
}
@@ -234,15 +234,14 @@ static int rti800_ai_insn_read(struct comedi_device *dev,
udelay(1);
}
if (t == 0) {
- printk("rti800: timeout\n");
+ printk(KERN_WARNING "rti800: timeout\n");
return -ETIME;
}
data[i] = inb(dev->iobase + RTI800_ADCLO);
data[i] |= (0xf & inb(dev->iobase + RTI800_ADCHI)) << 8;
- if (devpriv->adc_coding == adc_2comp) {
+ if (devpriv->adc_coding == adc_2comp)
data[i] ^= 0x800;
- }
}
return i;
@@ -271,9 +270,9 @@ static int rti800_ao_insn_write(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
devpriv->ao_readback[chan] = d = data[i];
- if (devpriv->dac0_coding == dac_2comp) {
+ if (devpriv->dac0_coding == dac_2comp)
d ^= 0x800;
- }
+
outb(d & 0xff,
dev->iobase + (chan ? RTI800_DAC1LO : RTI800_DAC0LO));
outb(d >> 8,
@@ -315,15 +314,15 @@ static int rti800_do_insn_bits(struct comedi_device *dev,
options[0] - I/O port
options[1] - irq
options[2] - a/d mux
- 0=differential, 1=pseudodiff, 2=single
+ 0=differential, 1=pseudodiff, 2=single
options[3] - a/d range
- 0=bipolar10, 1=bipolar5, 2=unipolar10
+ 0=bipolar10, 1=bipolar5, 2=unipolar10
options[4] - a/d coding
- 0=2's comp, 1=straight binary
+ 0=2's comp, 1=straight binary
options[5] - dac0 range
- 0=bipolar10, 1=unipolar10
+ 0=bipolar10, 1=unipolar10
options[6] - dac0 coding
- 0=2's comp, 1=straight binary
+ 0=2's comp, 1=straight binary
options[7] - dac1 range
options[8] - dac1 coding
*/
@@ -336,15 +335,15 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
iobase = it->options[0];
- printk("comedi%d: rti800: 0x%04lx ", dev->minor, iobase);
+ printk(KERN_INFO "comedi%d: rti800: 0x%04lx\n", dev->minor, iobase);
if (!request_region(iobase, RTI800_SIZE, "rti800")) {
- printk("I/O port conflict\n");
+ printk(KERN_WARNING "I/O port conflict\n");
return -EIO;
}
dev->iobase = iobase;
#ifdef DEBUG
- printk("fingerprint=%x,%x,%x,%x,%x ",
+ printk(KERN_DEBUG "fingerprint=%x,%x,%x,%x,%x ",
inb(dev->iobase + 0),
inb(dev->iobase + 1),
inb(dev->iobase + 2),
@@ -357,15 +356,15 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
irq = it->options[1];
if (irq) {
- printk("( irq = %u )", irq);
+ printk(KERN_INFO "( irq = %u )\n", irq);
ret = request_irq(irq, rti800_interrupt, 0, "rti800", dev);
if (ret < 0) {
- printk(" Failed to allocate IRQ\n");
+ printk(KERN_WARNING " Failed to allocate IRQ\n");
return ret;
}
dev->irq = irq;
} else {
- printk("( no irq )");
+ printk(KERN_INFO "( no irq )\n");
}
dev->board_name = this_board->name;
@@ -461,14 +460,12 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->type = COMEDI_SUBD_TIMER;
#endif
- printk("\n");
-
return 0;
}
static int rti800_detach(struct comedi_device *dev)
{
- printk("comedi%d: rti800: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: rti800: remove\n", dev->minor);
if (dev->iobase)
release_region(dev->iobase, RTI800_SIZE);
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index 2f75c737ea15..2157edcf7997 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -106,9 +106,9 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
unsigned long iobase;
iobase = it->options[0];
- printk("comedi%d: rti802: 0x%04lx ", dev->minor, iobase);
+ printk(KERN_INFO "comedi%d: rti802: 0x%04lx ", dev->minor, iobase);
if (!request_region(iobase, RTI802_SIZE, "rti802")) {
- printk("I/O port conflict\n");
+ printk(KERN_WARNING "I/O port conflict\n");
return -EIO;
}
dev->iobase = iobase;
@@ -138,14 +138,12 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
? &range_unipolar10 : &range_bipolar10;
}
- printk("\n");
-
return 0;
}
static int rti802_detach(struct comedi_device *dev)
{
- printk("comedi%d: rti802: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: rti802: remove\n", dev->minor);
if (dev->iobase)
release_region(dev->iobase, RTI802_SIZE);
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index fdd7ab954d8c..a3cc93362ec2 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -140,7 +140,7 @@ struct s626_private {
short allocatedBuf;
uint8_t ai_cmd_running; /* ai_cmd is running */
uint8_t ai_continous; /* continous aquisition */
- int ai_sample_count; /* number of samples to aquire */
+ int ai_sample_count; /* number of samples to acquire */
unsigned int ai_sample_timer;
/* time between samples in units of the timer */
int ai_convert_count; /* conversion counter */
diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c
index db37dcdd98b6..dd2b90372794 100644
--- a/drivers/staging/comedi/drivers/serial2002.c
+++ b/drivers/staging/comedi/drivers/serial2002.c
@@ -397,7 +397,7 @@ static void serial_2002_open(struct comedi_device *dev)
char port[20];
sprintf(port, "/dev/ttyS%d", devpriv->port);
- devpriv->tty = filp_open(port, 0, O_RDWR);
+ devpriv->tty = filp_open(port, O_RDWR, 0);
if (IS_ERR(devpriv->tty)) {
printk("serial_2002: file open error = %ld\n",
PTR_ERR(devpriv->tty));
diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c
index 4918fbfab5e8..17c92a57b0dd 100644
--- a/drivers/staging/comedi/drivers/ssv_dnp.c
+++ b/drivers/staging/comedi/drivers/ssv_dnp.c
@@ -300,11 +300,11 @@ static int dnp_dio_insn_config(struct comedi_device *dev,
/* read 'old' direction of the port and set bits (out=1, in=0) */
register_buffer = inb(CSCDR);
- if (data[0] == COMEDI_OUTPUT) {
+ if (data[0] == COMEDI_OUTPUT)
register_buffer |= (1 << chan);
- } else {
+ else
register_buffer &= ~(1 << chan);
- }
+
outb(register_buffer, CSCDR);
return 1;
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 9a1b559c4b0d..8942ae45708d 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -95,7 +95,6 @@ sampling rate. If you sample two channels you get 4kHz and so on.
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/usb.h>
-#include <linux/smp_lock.h>
#include <linux/fcntl.h>
#include <linux/compiler.h>
#include <linux/firmware.h>
@@ -289,7 +288,7 @@ struct usbduxsub {
/* continous aquisition */
short int ai_continous;
short int ao_continous;
- /* number of samples to aquire */
+ /* number of samples to acquire */
int ai_sample_count;
int ao_sample_count;
/* time between samples in units of the timer */
@@ -2833,7 +2832,7 @@ static struct comedi_driver driver_usbdux = {
};
/* Table with the USB-devices: just now only testing IDs */
-static struct usb_device_id usbduxsub_table[] = {
+static const struct usb_device_id usbduxsub_table[] = {
{USB_DEVICE(0x13d8, 0x0001)},
{USB_DEVICE(0x13d8, 0x0002)},
{} /* Terminating entry */
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index 2e675cce7dbf..e89b81812538 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -44,7 +44,6 @@
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/usb.h>
-#include <linux/smp_lock.h>
#include <linux/fcntl.h>
#include <linux/compiler.h>
#include "comedi_fc.h"
@@ -182,7 +181,7 @@ struct usbduxfastsub_s {
context */
short int ai_cmd_running; /* asynchronous command is running */
short int ai_continous; /* continous aquisition */
- long int ai_sample_count; /* number of samples to aquire */
+ long int ai_sample_count; /* number of samples to acquire */
uint8_t *dux_commands; /* commands */
int ignore; /* counter which ignores the first
buffers */
@@ -1769,7 +1768,7 @@ static struct comedi_driver driver_usbduxfast = {
/*
* Table with the USB-devices: just now only testing IDs
*/
-static struct usb_device_id usbduxfastsub_table[] = {
+static const struct usb_device_id usbduxfastsub_table[] = {
/* { USB_DEVICE(0x4b4, 0x8613) }, testing */
{USB_DEVICE(0x13d8, 0x0010)}, /* real ID */
{USB_DEVICE(0x13d8, 0x0011)}, /* real ID */
diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c
index c34a0b9141e2..6479c38d0278 100644
--- a/drivers/staging/comedi/drivers/vmk80xx.c
+++ b/drivers/staging/comedi/drivers/vmk80xx.c
@@ -75,7 +75,7 @@ enum {
DEVICE_VMK8061
};
-static struct usb_device_id vmk80xx_id_table[] = {
+static const struct usb_device_id vmk80xx_id_table[] = {
{USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055},
{USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055},
{USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055},
diff --git a/drivers/staging/crystalhd/Kconfig b/drivers/staging/crystalhd/Kconfig
new file mode 100644
index 000000000000..56b414bca1a1
--- /dev/null
+++ b/drivers/staging/crystalhd/Kconfig
@@ -0,0 +1,6 @@
+config CRYSTALHD
+ tristate "Broadcom Crystal HD video decoder support"
+ depends on PCI
+ default n
+ help
+ Support for the Broadcom Crystal HD video decoder chipset
diff --git a/drivers/staging/crystalhd/Makefile b/drivers/staging/crystalhd/Makefile
new file mode 100644
index 000000000000..e2af0ce2e792
--- /dev/null
+++ b/drivers/staging/crystalhd/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_CRYSTALHD) += crystalhd.o
+
+crystalhd-objs := crystalhd_cmds.o \
+ crystalhd_hw.o \
+ crystalhd_lnx.o \
+ crystalhd_misc.o
diff --git a/drivers/staging/crystalhd/TODO b/drivers/staging/crystalhd/TODO
new file mode 100644
index 000000000000..69be5d0cb80c
--- /dev/null
+++ b/drivers/staging/crystalhd/TODO
@@ -0,0 +1,16 @@
+- Testing
+- Cleanup return codes
+- Cleanup typedefs
+- Cleanup all WIN* references
+- Allocate an Accelerator device class specific Major number,
+ since we don't have any other open sourced accelerators, it is the only
+ one in that category for now.
+ A somewhat similar device is the DXR2/3
+
+Please send patches to:
+Greg Kroah-Hartman <greg@kroah.com>
+Naren Sankar <nsankar@broadcom.com>
+Jarod Wilson <jarod@wilsonet.com>
+Scott Davilla <davilla@4pi.com>
+Manu Abraham <abraham.manu@gmail.com>
+
diff --git a/drivers/staging/crystalhd/bc_dts_defs.h b/drivers/staging/crystalhd/bc_dts_defs.h
new file mode 100644
index 000000000000..c34cc07127b8
--- /dev/null
+++ b/drivers/staging/crystalhd/bc_dts_defs.h
@@ -0,0 +1,498 @@
+/********************************************************************
+ * Copyright(c) 2006-2009 Broadcom Corporation.
+ *
+ * Name: bc_dts_defs.h
+ *
+ * Description: Common definitions for all components. Only types
+ * is allowed to be included from this file.
+ *
+ * AU
+ *
+ * HISTORY:
+ *
+ ********************************************************************
+ * This header is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 2.1 of the License.
+ *
+ * This header is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this header. If not, see <http://www.gnu.org/licenses/>.
+ *******************************************************************/
+
+#ifndef _BC_DTS_DEFS_H_
+#define _BC_DTS_DEFS_H_
+
+#include "bc_dts_types.h"
+
+/* BIT Mask */
+#define BC_BIT(_x) (1 << (_x))
+
+typedef enum _BC_STATUS {
+ BC_STS_SUCCESS = 0,
+ BC_STS_INV_ARG = 1,
+ BC_STS_BUSY = 2,
+ BC_STS_NOT_IMPL = 3,
+ BC_STS_PGM_QUIT = 4,
+ BC_STS_NO_ACCESS = 5,
+ BC_STS_INSUFF_RES = 6,
+ BC_STS_IO_ERROR = 7,
+ BC_STS_NO_DATA = 8,
+ BC_STS_VER_MISMATCH = 9,
+ BC_STS_TIMEOUT = 10,
+ BC_STS_FW_CMD_ERR = 11,
+ BC_STS_DEC_NOT_OPEN = 12,
+ BC_STS_ERR_USAGE = 13,
+ BC_STS_IO_USER_ABORT = 14,
+ BC_STS_IO_XFR_ERROR = 15,
+ BC_STS_DEC_NOT_STARTED = 16,
+ BC_STS_FWHEX_NOT_FOUND = 17,
+ BC_STS_FMT_CHANGE = 18,
+ BC_STS_HIF_ACCESS = 19,
+ BC_STS_CMD_CANCELLED = 20,
+ BC_STS_FW_AUTH_FAILED = 21,
+ BC_STS_BOOTLOADER_FAILED = 22,
+ BC_STS_CERT_VERIFY_ERROR = 23,
+ BC_STS_DEC_EXIST_OPEN = 24,
+ BC_STS_PENDING = 25,
+ BC_STS_CLK_NOCHG = 26,
+
+ /* Must be the last one.*/
+ BC_STS_ERROR = -1
+} BC_STATUS;
+
+/*------------------------------------------------------*
+ * Registry Key Definitions *
+ *------------------------------------------------------*/
+#define BC_REG_KEY_MAIN_PATH "Software\\Broadcom\\MediaPC\\70010"
+#define BC_REG_KEY_FWPATH "FirmwareFilePath"
+#define BC_REG_KEY_SEC_OPT "DbgOptions"
+
+/*
+ * Options:
+ *
+ * b[5] = Enable RSA KEY in EEPROM Support
+ * b[6] = Enable Old PIB scheme. (0 = Use PIB with video scheme)
+ *
+ * b[12] = Enable send message to NotifyIcon
+ *
+ */
+
+typedef enum _BC_SW_OPTIONS {
+ BC_OPT_DOSER_OUT_ENCRYPT = BC_BIT(3),
+ BC_OPT_LINK_OUT_ENCRYPT = BC_BIT(29),
+} BC_SW_OPTIONS;
+
+typedef struct _BC_REG_CONFIG{
+ uint32_t DbgOptions;
+} BC_REG_CONFIG;
+
+#if defined(__KERNEL__) || defined(__LINUX_USER__)
+#else
+/* Align data structures */
+#define ALIGN(x) __declspec(align(x))
+#endif
+
+/* mode
+ * b[0]..b[7] = _DtsDeviceOpenMode
+ * b[8] = Load new FW
+ * b[9] = Load file play back FW
+ * b[10] = Disk format (0 for HD DVD and 1 for BLU ray)
+ * b[11]-b[15] = default output resolution
+ * b[16] = Skip TX CPB Buffer Check
+ * b[17] = Adaptive Output Encrypt/Scramble Scheme
+ * b[18]-b[31] = reserved for future use
+ */
+
+/* To allow multiple apps to open the device. */
+enum _DtsDeviceOpenMode {
+ DTS_PLAYBACK_MODE = 0,
+ DTS_DIAG_MODE,
+ DTS_MONITOR_MODE,
+ DTS_HWINIT_MODE
+};
+
+/* To enable the filter to selectively enable/disable fixes or erratas */
+enum _DtsDeviceFixMode {
+ DTS_LOAD_NEW_FW = BC_BIT(8),
+ DTS_LOAD_FILE_PLAY_FW = BC_BIT(9),
+ DTS_DISK_FMT_BD = BC_BIT(10),
+ /* b[11]-b[15] : Default output resolution */
+ DTS_SKIP_TX_CHK_CPB = BC_BIT(16),
+ DTS_ADAPTIVE_OUTPUT_PER = BC_BIT(17),
+ DTS_INTELLIMAP = BC_BIT(18),
+ /* b[19]-b[21] : select clock frequency */
+ DTS_PLAYBACK_DROP_RPT_MODE = BC_BIT(22)
+};
+
+#define DTS_DFLT_RESOLUTION(x) (x<<11)
+
+#define DTS_DFLT_CLOCK(x) (x<<19)
+
+/* F/W File Version corresponding to S/W Releases */
+enum _FW_FILE_VER {
+ /* S/W release: 02.04.02 F/W release 2.12.2.0 */
+ BC_FW_VER_020402 = ((12<<16) | (2<<8) | (0))
+};
+
+/*------------------------------------------------------*
+ * Stream Types for DtsOpenDecoder() *
+ *------------------------------------------------------*/
+enum _DtsOpenDecStreamTypes {
+ BC_STREAM_TYPE_ES = 0,
+ BC_STREAM_TYPE_PES = 1,
+ BC_STREAM_TYPE_TS = 2,
+ BC_STREAM_TYPE_ES_TSTAMP = 6,
+};
+
+/*------------------------------------------------------*
+ * Video Algorithms for DtsSetVideoParams() *
+ *------------------------------------------------------*/
+enum _DtsSetVideoParamsAlgo {
+ BC_VID_ALGO_H264 = 0,
+ BC_VID_ALGO_MPEG2 = 1,
+ BC_VID_ALGO_VC1 = 4,
+ BC_VID_ALGO_VC1MP = 7,
+};
+
+/*------------------------------------------------------*
+ * MPEG Extension to the PPB *
+ *------------------------------------------------------*/
+#define BC_MPEG_VALID_PANSCAN (1)
+
+typedef struct _BC_PIB_EXT_MPEG {
+ uint32_t valid;
+ /* Always valid, defaults to picture size if no
+ * sequence display extension in the stream. */
+ uint32_t display_horizontal_size;
+ uint32_t display_vertical_size;
+
+ /* MPEG_VALID_PANSCAN
+ * Offsets are a copy values from the MPEG stream. */
+ uint32_t offset_count;
+ int32_t horizontal_offset[3];
+ int32_t vertical_offset[3];
+
+} BC_PIB_EXT_MPEG;
+
+/*------------------------------------------------------*
+ * H.264 Extension to the PPB *
+ *------------------------------------------------------*/
+/* Bit definitions for 'other.h264.valid' field */
+#define H264_VALID_PANSCAN (1)
+#define H264_VALID_SPS_CROP (2)
+#define H264_VALID_VUI (4)
+
+typedef struct _BC_PIB_EXT_H264 {
+ /* 'valid' specifies which fields (or sets of
+ * fields) below are valid. If the corresponding
+ * bit in 'valid' is NOT set then that field(s)
+ * is (are) not initialized. */
+ uint32_t valid;
+
+ /* H264_VALID_PANSCAN */
+ uint32_t pan_scan_count;
+ int32_t pan_scan_left[3];
+ int32_t pan_scan_right[3];
+ int32_t pan_scan_top[3];
+ int32_t pan_scan_bottom[3];
+
+ /* H264_VALID_SPS_CROP */
+ int32_t sps_crop_left;
+ int32_t sps_crop_right;
+ int32_t sps_crop_top;
+ int32_t sps_crop_bottom;
+
+ /* H264_VALID_VUI */
+ uint32_t chroma_top;
+ uint32_t chroma_bottom;
+
+} BC_PIB_EXT_H264;
+
+/*------------------------------------------------------*
+ * VC1 Extension to the PPB *
+ *------------------------------------------------------*/
+#define VC1_VALID_PANSCAN (1)
+
+typedef struct _BC_PIB_EXT_VC1 {
+ uint32_t valid;
+
+ /* Always valid, defaults to picture size if no
+ * sequence display extension in the stream. */
+ uint32_t display_horizontal_size;
+ uint32_t display_vertical_size;
+
+ /* VC1 pan scan windows */
+ uint32_t num_panscan_windows;
+ int32_t ps_horiz_offset[4];
+ int32_t ps_vert_offset[4];
+ int32_t ps_width[4];
+ int32_t ps_height[4];
+
+} BC_PIB_EXT_VC1;
+
+
+/*------------------------------------------------------*
+ * Picture Information Block *
+ *------------------------------------------------------*/
+#if defined(_WIN32) || defined(_WIN64) || defined(__LINUX_USER__)
+/* Values for 'pulldown' field. '0' means no pulldown information
+ * was present for this picture. */
+enum {
+ vdecNoPulldownInfo = 0,
+ vdecTop = 1,
+ vdecBottom = 2,
+ vdecTopBottom = 3,
+ vdecBottomTop = 4,
+ vdecTopBottomTop = 5,
+ vdecBottomTopBottom = 6,
+ vdecFrame_X2 = 7,
+ vdecFrame_X3 = 8,
+ vdecFrame_X1 = 9,
+ vdecFrame_X4 = 10,
+};
+
+/* Values for the 'frame_rate' field. */
+enum {
+ vdecFrameRateUnknown = 0,
+ vdecFrameRate23_97,
+ vdecFrameRate24,
+ vdecFrameRate25,
+ vdecFrameRate29_97,
+ vdecFrameRate30,
+ vdecFrameRate50,
+ vdecFrameRate59_94,
+ vdecFrameRate60,
+};
+
+/* Values for the 'aspect_ratio' field. */
+enum {
+ vdecAspectRatioUnknown = 0,
+ vdecAspectRatioSquare,
+ vdecAspectRatio12_11,
+ vdecAspectRatio10_11,
+ vdecAspectRatio16_11,
+ vdecAspectRatio40_33,
+ vdecAspectRatio24_11,
+ vdecAspectRatio20_11,
+ vdecAspectRatio32_11,
+ vdecAspectRatio80_33,
+ vdecAspectRatio18_11,
+ vdecAspectRatio15_11,
+ vdecAspectRatio64_33,
+ vdecAspectRatio160_99,
+ vdecAspectRatio4_3,
+ vdecAspectRatio16_9,
+ vdecAspectRatio221_1,
+ vdecAspectRatioOther = 255,
+};
+
+/* Values for the 'colour_primaries' field. */
+enum {
+ vdecColourPrimariesUnknown = 0,
+ vdecColourPrimariesBT709,
+ vdecColourPrimariesUnspecified,
+ vdecColourPrimariesReserved,
+ vdecColourPrimariesBT470_2M = 4,
+ vdecColourPrimariesBT470_2BG,
+ vdecColourPrimariesSMPTE170M,
+ vdecColourPrimariesSMPTE240M,
+ vdecColourPrimariesGenericFilm,
+};
+
+enum {
+ vdecRESOLUTION_CUSTOM = 0x00000000, /* custom */
+ vdecRESOLUTION_480i = 0x00000001, /* 480i */
+ vdecRESOLUTION_1080i = 0x00000002, /* 1080i (1920x1080, 60i) */
+ vdecRESOLUTION_NTSC = 0x00000003, /* NTSC (720x483, 60i) */
+ vdecRESOLUTION_480p = 0x00000004, /* 480p (720x480, 60p) */
+ vdecRESOLUTION_720p = 0x00000005, /* 720p (1280x720, 60p) */
+ vdecRESOLUTION_PAL1 = 0x00000006, /* PAL_1 (720x576, 50i) */
+ vdecRESOLUTION_1080i25 = 0x00000007, /* 1080i25 (1920x1080, 50i) */
+ vdecRESOLUTION_720p50 = 0x00000008, /* 720p50 (1280x720, 50p) */
+ vdecRESOLUTION_576p = 0x00000009, /* 576p (720x576, 50p) */
+ vdecRESOLUTION_1080i29_97 = 0x0000000A, /* 1080i (1920x1080, 59.94i) */
+ vdecRESOLUTION_720p59_94 = 0x0000000B, /* 720p (1280x720, 59.94p) */
+ vdecRESOLUTION_SD_DVD = 0x0000000C, /* SD DVD (720x483, 60i) */
+ vdecRESOLUTION_480p656 = 0x0000000D, /* 480p (720x480, 60p), output bus width 8 bit, clock 74.25MHz */
+ vdecRESOLUTION_1080p23_976 = 0x0000000E, /* 1080p23_976 (1920x1080, 23.976p) */
+ vdecRESOLUTION_720p23_976 = 0x0000000F, /* 720p23_976 (1280x720p, 23.976p) */
+ vdecRESOLUTION_240p29_97 = 0x00000010, /* 240p (1440x240, 29.97p ) */
+ vdecRESOLUTION_240p30 = 0x00000011, /* 240p (1440x240, 30p) */
+ vdecRESOLUTION_288p25 = 0x00000012, /* 288p (1440x288p, 25p) */
+ vdecRESOLUTION_1080p29_97 = 0x00000013, /* 1080p29_97 (1920x1080, 29.97p) */
+ vdecRESOLUTION_1080p30 = 0x00000014, /* 1080p30 (1920x1080, 30p) */
+ vdecRESOLUTION_1080p24 = 0x00000015, /* 1080p24 (1920x1080, 24p) */
+ vdecRESOLUTION_1080p25 = 0x00000016, /* 1080p25 (1920x1080, 25p) */
+ vdecRESOLUTION_720p24 = 0x00000017, /* 720p24 (1280x720, 25p) */
+ vdecRESOLUTION_720p29_97 = 0x00000018, /* 720p29.97 (1280x720, 29.97p) */
+ vdecRESOLUTION_480p23_976 = 0x00000019, /* 480p23.976 (720*480, 23.976) */
+ vdecRESOLUTION_480p29_97 = 0x0000001A, /* 480p29.976 (720*480, 29.97p) */
+ vdecRESOLUTION_576p25 = 0x0000001B, /* 576p25 (720*576, 25p) */
+ /* For Zero Frame Rate */
+ vdecRESOLUTION_480p0 = 0x0000001C, /* 480p (720x480, 0p) */
+ vdecRESOLUTION_480i0 = 0x0000001D, /* 480i (720x480, 0i) */
+ vdecRESOLUTION_576p0 = 0x0000001E, /* 576p (720x576, 0p) */
+ vdecRESOLUTION_720p0 = 0x0000001F, /* 720p (1280x720, 0p) */
+ vdecRESOLUTION_1080p0 = 0x00000020, /* 1080p (1920x1080, 0p) */
+ vdecRESOLUTION_1080i0 = 0x00000021, /* 1080i (1920x1080, 0i) */
+};
+
+/* Bit definitions for 'flags' field */
+#define VDEC_FLAG_EOS (0x0004)
+
+#define VDEC_FLAG_FRAME (0x0000)
+#define VDEC_FLAG_FIELDPAIR (0x0008)
+#define VDEC_FLAG_TOPFIELD (0x0010)
+#define VDEC_FLAG_BOTTOMFIELD (0x0018)
+
+#define VDEC_FLAG_PROGRESSIVE_SRC (0x0000)
+#define VDEC_FLAG_INTERLACED_SRC (0x0020)
+#define VDEC_FLAG_UNKNOWN_SRC (0x0040)
+
+#define VDEC_FLAG_BOTTOM_FIRST (0x0080)
+#define VDEC_FLAG_LAST_PICTURE (0x0100)
+
+#define VDEC_FLAG_PICTURE_META_DATA_PRESENT (0x40000)
+
+#endif /* _WIN32 || _WIN64 */
+
+enum _BC_OUTPUT_FORMAT {
+ MODE420 = 0x0,
+ MODE422_YUY2 = 0x1,
+ MODE422_UYVY = 0x2,
+};
+
+typedef struct _BC_PIC_INFO_BLOCK {
+ /* Common fields. */
+ uint64_t timeStamp; /* Timestamp */
+ uint32_t picture_number; /* Ordinal display number */
+ uint32_t width; /* pixels */
+ uint32_t height; /* pixels */
+ uint32_t chroma_format; /* 0x420, 0x422 or 0x444 */
+ uint32_t pulldown;
+ uint32_t flags;
+ uint32_t frame_rate;
+ uint32_t aspect_ratio;
+ uint32_t colour_primaries;
+ uint32_t picture_meta_payload;
+ uint32_t sess_num;
+ uint32_t ycom;
+ uint32_t custom_aspect_ratio_width_height;
+ uint32_t n_drop; /* number of non-reference frames remaining to be dropped */
+
+ /* Protocol-specific extensions. */
+ union {
+ BC_PIB_EXT_H264 h264;
+ BC_PIB_EXT_MPEG mpeg;
+ BC_PIB_EXT_VC1 vc1;
+ } other;
+
+} BC_PIC_INFO_BLOCK, *PBC_PIC_INFO_BLOCK;
+
+/*------------------------------------------------------*
+ * ProcOut Info *
+ *------------------------------------------------------*/
+/* Optional flags for ProcOut Interface.*/
+enum _POUT_OPTIONAL_IN_FLAGS_{
+ /* Flags from App to Device */
+ BC_POUT_FLAGS_YV12 = 0x01, /* Copy Data in YV12 format */
+ BC_POUT_FLAGS_STRIDE = 0x02, /* Stride size is valid. */
+ BC_POUT_FLAGS_SIZE = 0x04, /* Take size information from Application */
+ BC_POUT_FLAGS_INTERLACED = 0x08, /* copy only half the bytes */
+ BC_POUT_FLAGS_INTERLEAVED = 0x10, /* interleaved frame */
+
+ /* Flags from Device to APP */
+ BC_POUT_FLAGS_FMT_CHANGE = 0x10000, /* Data is not VALID when this flag is set */
+ BC_POUT_FLAGS_PIB_VALID = 0x20000, /* PIB Information valid */
+ BC_POUT_FLAGS_ENCRYPTED = 0x40000, /* Data is encrypted. */
+ BC_POUT_FLAGS_FLD_BOT = 0x80000, /* Bottom Field data */
+};
+
+#if defined(__KERNEL__) || defined(__LINUX_USER__)
+typedef BC_STATUS(*dts_pout_callback)(void *shnd, uint32_t width, uint32_t height, uint32_t stride, void *pOut);
+#else
+typedef BC_STATUS(*dts_pout_callback)(void *shnd, uint32_t width, uint32_t height, uint32_t stride, struct _BC_DTS_PROC_OUT *pOut);
+#endif
+
+/* Line 21 Closed Caption */
+/* User Data */
+#define MAX_UD_SIZE 1792 /* 1920 - 128 */
+
+typedef struct _BC_DTS_PROC_OUT {
+ uint8_t *Ybuff; /* Caller Supplied buffer for Y data */
+ uint32_t YbuffSz; /* Caller Supplied Y buffer size */
+ uint32_t YBuffDoneSz; /* Transferred Y datasize */
+
+ uint8_t *UVbuff; /* Caller Supplied buffer for UV data */
+ uint32_t UVbuffSz; /* Caller Supplied UV buffer size */
+ uint32_t UVBuffDoneSz; /* Transferred UV data size */
+
+ uint32_t StrideSz; /* Caller supplied Stride Size */
+ uint32_t PoutFlags; /* Call IN Flags */
+
+ uint32_t discCnt; /* Picture discontinuity count */
+
+ BC_PIC_INFO_BLOCK PicInfo; /* Picture Information Block Data */
+
+ /* Line 21 Closed Caption */
+ /* User Data */
+ uint32_t UserDataSz;
+ uint8_t UserData[MAX_UD_SIZE];
+
+ void *hnd;
+ dts_pout_callback AppCallBack;
+ uint8_t DropFrames;
+ uint8_t b422Mode; /* Picture output Mode */
+ uint8_t bPibEnc; /* PIB encrypted */
+ uint8_t bRevertScramble;
+
+} BC_DTS_PROC_OUT;
+
+typedef struct _BC_DTS_STATUS {
+ uint8_t ReadyListCount; /* Number of frames in ready list (reported by driver) */
+ uint8_t FreeListCount; /* Number of frame buffers free. (reported by driver) */
+ uint8_t PowerStateChange; /* Number of active state power transitions (reported by driver) */
+ uint8_t reserved_[1];
+
+ uint32_t FramesDropped; /* Number of frames dropped. (reported by DIL) */
+ uint32_t FramesCaptured; /* Number of frames captured. (reported by DIL) */
+ uint32_t FramesRepeated; /* Number of frames repeated. (reported by DIL) */
+
+ uint32_t InputCount; /* Times compressed video has been sent to the HW.
+ * i.e. Successful DtsProcInput() calls (reported by DIL) */
+ uint64_t InputTotalSize; /* Amount of compressed video that has been sent to the HW.
+ * (reported by DIL) */
+ uint32_t InputBusyCount; /* Times compressed video has attempted to be sent to the HW
+ * but the input FIFO was full. (reported by DIL) */
+
+ uint32_t PIBMissCount; /* Amount of times a PIB is invalid. (reported by DIL) */
+
+ uint32_t cpbEmptySize; /* supported only for H.264, specifically changed for
+ * Adobe. Report size of CPB buffer available.
+ * Reported by DIL */
+ uint64_t NextTimeStamp; /* TimeStamp of the next picture that will be returned
+ * by a call to ProcOutput. Added for Adobe. Reported
+ * back from the driver */
+ uint8_t reserved__[16];
+
+} BC_DTS_STATUS;
+
+#define BC_SWAP32(_v) \
+ ((((_v) & 0xFF000000)>>24)| \
+ (((_v) & 0x00FF0000)>>8)| \
+ (((_v) & 0x0000FF00)<<8)| \
+ (((_v) & 0x000000FF)<<24))
+
+#define WM_AGENT_TRAYICON_DECODER_OPEN 10001
+#define WM_AGENT_TRAYICON_DECODER_CLOSE 10002
+#define WM_AGENT_TRAYICON_DECODER_START 10003
+#define WM_AGENT_TRAYICON_DECODER_STOP 10004
+#define WM_AGENT_TRAYICON_DECODER_RUN 10005
+#define WM_AGENT_TRAYICON_DECODER_PAUSE 10006
+
+
+#endif /* _BC_DTS_DEFS_H_ */
diff --git a/drivers/staging/crystalhd/bc_dts_glob_lnx.h b/drivers/staging/crystalhd/bc_dts_glob_lnx.h
new file mode 100644
index 000000000000..b3125e3e0372
--- /dev/null
+++ b/drivers/staging/crystalhd/bc_dts_glob_lnx.h
@@ -0,0 +1,299 @@
+/********************************************************************
+ * Copyright(c) 2006-2009 Broadcom Corporation.
+ *
+ * Name: bc_dts_glob_lnx.h
+ *
+ * Description: Wrapper to Windows dts_glob.h for Link-Linux usage.
+ * The idea is to define additional Linux related defs
+ * in this file to avoid changes to existing Windows
+ * glob file.
+ *
+ * AU
+ *
+ * HISTORY:
+ *
+ ********************************************************************
+ * This header is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 2.1 of the License.
+ *
+ * This header is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this header. If not, see <http://www.gnu.org/licenses/>.
+ *******************************************************************/
+
+#ifndef _BC_DTS_GLOB_LNX_H_
+#define _BC_DTS_GLOB_LNX_H_
+
+#ifdef __LINUX_USER__
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <asm/param.h>
+#include <linux/ioctl.h>
+#include <sys/select.h>
+
+#define DRVIFLIB_INT_API
+
+#endif
+
+#include "bc_dts_defs.h"
+#include "bcm_70012_regs.h" /* Link Register defs */
+
+#define CRYSTALHD_API_NAME "crystalhd"
+#define CRYSTALHD_API_DEV_NAME "/dev/crystalhd"
+
+/*
+ * These are SW stack tunable parameters shared
+ * between the driver and the application.
+ */
+enum _BC_DTS_GLOBALS {
+ BC_MAX_FW_CMD_BUFF_SZ = 0x40, /* FW passthrough cmd/rsp buffer size */
+ PCI_CFG_SIZE = 256, /* PCI config size buffer */
+ BC_IOCTL_DATA_POOL_SIZE = 8, /* BC_IOCTL_DATA Pool size */
+ BC_LINK_MAX_OPENS = 3, /* Maximum simultaneous opens*/
+ BC_LINK_MAX_SGLS = 1024, /* Maximum SG elements 4M/4K */
+ BC_TX_LIST_CNT = 2, /* Max Tx DMA Rings */
+ BC_RX_LIST_CNT = 8, /* Max Rx DMA Rings*/
+ BC_PROC_OUTPUT_TIMEOUT = 3000, /* Milliseconds */
+ BC_INFIFO_THRESHOLD = 0x10000,
+};
+
+typedef struct _BC_CMD_REG_ACC {
+ uint32_t Offset;
+ uint32_t Value;
+} BC_CMD_REG_ACC;
+
+typedef struct _BC_CMD_DEV_MEM {
+ uint32_t StartOff;
+ uint32_t NumDwords;
+ uint32_t Rsrd;
+} BC_CMD_DEV_MEM;
+
+/* FW Passthrough command structure */
+enum _bc_fw_cmd_flags {
+ BC_FW_CMD_FLAGS_NONE = 0,
+ BC_FW_CMD_PIB_QS = 0x01,
+};
+
+typedef struct _BC_FW_CMD {
+ uint32_t cmd[BC_MAX_FW_CMD_BUFF_SZ];
+ uint32_t rsp[BC_MAX_FW_CMD_BUFF_SZ];
+ uint32_t flags;
+ uint32_t add_data;
+} BC_FW_CMD, *PBC_FW_CMD;
+
+typedef struct _BC_HW_TYPE {
+ uint16_t PciDevId;
+ uint16_t PciVenId;
+ uint8_t HwRev;
+ uint8_t Align[3];
+} BC_HW_TYPE;
+
+typedef struct _BC_PCI_CFG {
+ uint32_t Size;
+ uint32_t Offset;
+ uint8_t pci_cfg_space[PCI_CFG_SIZE];
+} BC_PCI_CFG;
+
+typedef struct _BC_VERSION_INFO_ {
+ uint8_t DriverMajor;
+ uint8_t DriverMinor;
+ uint16_t DriverRevision;
+} BC_VERSION_INFO;
+
+typedef struct _BC_START_RX_CAP_ {
+ uint32_t Rsrd;
+ uint32_t StartDeliveryThsh;
+ uint32_t PauseThsh;
+ uint32_t ResumeThsh;
+} BC_START_RX_CAP;
+
+typedef struct _BC_FLUSH_RX_CAP_ {
+ uint32_t Rsrd;
+ uint32_t bDiscardOnly;
+} BC_FLUSH_RX_CAP;
+
+typedef struct _BC_DTS_STATS {
+ uint8_t drvRLL;
+ uint8_t drvFLL;
+ uint8_t eosDetected;
+ uint8_t pwr_state_change;
+
+ /* Stats from App */
+ uint32_t opFrameDropped;
+ uint32_t opFrameCaptured;
+ uint32_t ipSampleCnt;
+ uint64_t ipTotalSize;
+ uint32_t reptdFrames;
+ uint32_t pauseCount;
+ uint32_t pibMisses;
+ uint32_t discCounter;
+
+ /* Stats from Driver */
+ uint32_t TxFifoBsyCnt;
+ uint32_t intCount;
+ uint32_t DrvIgnIntrCnt;
+ uint32_t DrvTotalFrmDropped;
+ uint32_t DrvTotalHWErrs;
+ uint32_t DrvTotalPIBFlushCnt;
+ uint32_t DrvTotalFrmCaptured;
+ uint32_t DrvPIBMisses;
+ uint32_t DrvPauseTime;
+ uint32_t DrvRepeatedFrms;
+ uint32_t res1[13];
+
+} BC_DTS_STATS;
+
+typedef struct _BC_PROC_INPUT_ {
+ uint8_t *pDmaBuff;
+ uint32_t BuffSz;
+ uint8_t Mapped;
+ uint8_t Encrypted;
+ uint8_t Rsrd[2];
+ uint32_t DramOffset; /* For debug use only */
+} BC_PROC_INPUT, *PBC_PROC_INPUT;
+
+typedef struct _BC_DEC_YUV_BUFFS {
+ uint32_t b422Mode;
+ uint8_t *YuvBuff;
+ uint32_t YuvBuffSz;
+ uint32_t UVbuffOffset;
+ uint32_t YBuffDoneSz;
+ uint32_t UVBuffDoneSz;
+ uint32_t RefCnt;
+} BC_DEC_YUV_BUFFS;
+
+enum _DECOUT_COMPLETION_FLAGS{
+ COMP_FLAG_NO_INFO = 0x00,
+ COMP_FLAG_FMT_CHANGE = 0x01,
+ COMP_FLAG_PIB_VALID = 0x02,
+ COMP_FLAG_DATA_VALID = 0x04,
+ COMP_FLAG_DATA_ENC = 0x08,
+ COMP_FLAG_DATA_BOT = 0x10,
+};
+
+typedef struct _BC_DEC_OUT_BUFF{
+ BC_DEC_YUV_BUFFS OutPutBuffs;
+ BC_PIC_INFO_BLOCK PibInfo;
+ uint32_t Flags;
+ uint32_t BadFrCnt;
+} BC_DEC_OUT_BUFF;
+
+typedef struct _BC_NOTIFY_MODE {
+ uint32_t Mode;
+ uint32_t Rsvr[3];
+} BC_NOTIFY_MODE;
+
+typedef struct _BC_CLOCK {
+ uint32_t clk;
+ uint32_t Rsvr[3];
+} BC_CLOCK;
+
+typedef struct _BC_IOCTL_DATA {
+ BC_STATUS RetSts;
+ uint32_t IoctlDataSz;
+ uint32_t Timeout;
+ union {
+ BC_CMD_REG_ACC regAcc;
+ BC_CMD_DEV_MEM devMem;
+ BC_FW_CMD fwCmd;
+ BC_HW_TYPE hwType;
+ BC_PCI_CFG pciCfg;
+ BC_VERSION_INFO VerInfo;
+ BC_PROC_INPUT ProcInput;
+ BC_DEC_YUV_BUFFS RxBuffs;
+ BC_DEC_OUT_BUFF DecOutData;
+ BC_START_RX_CAP RxCap;
+ BC_FLUSH_RX_CAP FlushRxCap;
+ BC_DTS_STATS drvStat;
+ BC_NOTIFY_MODE NotifyMode;
+ BC_CLOCK clockValue;
+ } u;
+ struct _BC_IOCTL_DATA *next;
+} BC_IOCTL_DATA;
+
+typedef enum _BC_DRV_CMD{
+ DRV_CMD_VERSION = 0, /* Get SW version */
+ DRV_CMD_GET_HWTYPE, /* Get HW version and type Dozer/Tank */
+ DRV_CMD_REG_RD, /* Read Device Register */
+ DRV_CMD_REG_WR, /* Write Device Register */
+ DRV_CMD_FPGA_RD, /* Read FPGA Register */
+ DRV_CMD_FPGA_WR, /* Wrtie FPGA Reister */
+ DRV_CMD_MEM_RD, /* Read Device Memory */
+ DRV_CMD_MEM_WR, /* Write Device Memory */
+ DRV_CMD_RD_PCI_CFG, /* Read PCI Config Space */
+ DRV_CMD_WR_PCI_CFG, /* Write the PCI Configuration Space*/
+ DRV_CMD_FW_DOWNLOAD, /* Download Firmware */
+ DRV_ISSUE_FW_CMD, /* Issue FW Cmd (pass through mode) */
+ DRV_CMD_PROC_INPUT, /* Process Input Sample */
+ DRV_CMD_ADD_RXBUFFS, /* Add Rx side buffers to driver pool */
+ DRV_CMD_FETCH_RXBUFF, /* Get Rx DMAed buffer */
+ DRV_CMD_START_RX_CAP, /* Start Rx Buffer Capture */
+ DRV_CMD_FLUSH_RX_CAP, /* Stop the capture for now...we will enhance this later*/
+ DRV_CMD_GET_DRV_STAT, /* Get Driver Internal Statistics */
+ DRV_CMD_RST_DRV_STAT, /* Reset Driver Internal Statistics */
+ DRV_CMD_NOTIFY_MODE, /* Notify the Mode to driver in which the application is Operating*/
+ DRV_CMD_CHANGE_CLOCK, /* Change the core clock to either save power or improve performance */
+
+ /* MUST be the last one.. */
+ DRV_CMD_END, /* End of the List.. */
+} BC_DRV_CMD;
+
+#define BC_IOC_BASE 'b'
+#define BC_IOC_VOID _IOC_NONE
+#define BC_IOC_IOWR(nr, type) _IOWR(BC_IOC_BASE, nr, type)
+#define BC_IOCTL_MB BC_IOCTL_DATA
+
+#define BCM_IOC_GET_VERSION BC_IOC_IOWR(DRV_CMD_VERSION, BC_IOCTL_MB)
+#define BCM_IOC_GET_HWTYPE BC_IOC_IOWR(DRV_CMD_GET_HWTYPE, BC_IOCTL_MB)
+#define BCM_IOC_REG_RD BC_IOC_IOWR(DRV_CMD_REG_RD, BC_IOCTL_MB)
+#define BCM_IOC_REG_WR BC_IOC_IOWR(DRV_CMD_REG_WR, BC_IOCTL_MB)
+#define BCM_IOC_MEM_RD BC_IOC_IOWR(DRV_CMD_MEM_RD, BC_IOCTL_MB)
+#define BCM_IOC_MEM_WR BC_IOC_IOWR(DRV_CMD_MEM_WR, BC_IOCTL_MB)
+#define BCM_IOC_FPGA_RD BC_IOC_IOWR(DRV_CMD_FPGA_RD, BC_IOCTL_MB)
+#define BCM_IOC_FPGA_WR BC_IOC_IOWR(DRV_CMD_FPGA_WR, BC_IOCTL_MB)
+#define BCM_IOC_RD_PCI_CFG BC_IOC_IOWR(DRV_CMD_RD_PCI_CFG, BC_IOCTL_MB)
+#define BCM_IOC_WR_PCI_CFG BC_IOC_IOWR(DRV_CMD_WR_PCI_CFG, BC_IOCTL_MB)
+#define BCM_IOC_PROC_INPUT BC_IOC_IOWR(DRV_CMD_PROC_INPUT, BC_IOCTL_MB)
+#define BCM_IOC_ADD_RXBUFFS BC_IOC_IOWR(DRV_CMD_ADD_RXBUFFS, BC_IOCTL_MB)
+#define BCM_IOC_FETCH_RXBUFF BC_IOC_IOWR(DRV_CMD_FETCH_RXBUFF, BC_IOCTL_MB)
+#define BCM_IOC_FW_CMD BC_IOC_IOWR(DRV_ISSUE_FW_CMD, BC_IOCTL_MB)
+#define BCM_IOC_START_RX_CAP BC_IOC_IOWR(DRV_CMD_START_RX_CAP, BC_IOCTL_MB)
+#define BCM_IOC_FLUSH_RX_CAP BC_IOC_IOWR(DRV_CMD_FLUSH_RX_CAP, BC_IOCTL_MB)
+#define BCM_IOC_GET_DRV_STAT BC_IOC_IOWR(DRV_CMD_GET_DRV_STAT, BC_IOCTL_MB)
+#define BCM_IOC_RST_DRV_STAT BC_IOC_IOWR(DRV_CMD_RST_DRV_STAT, BC_IOCTL_MB)
+#define BCM_IOC_NOTIFY_MODE BC_IOC_IOWR(DRV_CMD_NOTIFY_MODE, BC_IOCTL_MB)
+#define BCM_IOC_FW_DOWNLOAD BC_IOC_IOWR(DRV_CMD_FW_DOWNLOAD, BC_IOCTL_MB)
+#define BCM_IOC_CHG_CLK BC_IOC_IOWR(DRV_CMD_CHANGE_CLOCK, BC_IOCTL_MB)
+#define BCM_IOC_END BC_IOC_VOID
+
+/* Wrapper for main IOCTL data */
+typedef struct _crystalhd_ioctl_data {
+ BC_IOCTL_DATA udata; /* IOCTL from App..*/
+ uint32_t u_id; /* Driver specific user ID */
+ uint32_t cmd; /* Cmd ID for driver's use. */
+ void *add_cdata; /* Additional command specific data..*/
+ uint32_t add_cdata_sz; /* Additional command specific data size */
+ struct _crystalhd_ioctl_data *next; /* List/Fifo management */
+} crystalhd_ioctl_data;
+
+
+enum _crystalhd_kmod_ver{
+ crystalhd_kmod_major = 0,
+ crystalhd_kmod_minor = 9,
+ crystalhd_kmod_rev = 27,
+};
+
+#endif
diff --git a/drivers/staging/crystalhd/bc_dts_types.h b/drivers/staging/crystalhd/bc_dts_types.h
new file mode 100644
index 000000000000..ac0c81717385
--- /dev/null
+++ b/drivers/staging/crystalhd/bc_dts_types.h
@@ -0,0 +1,121 @@
+/********************************************************************
+ * Copyright(c) 2006-2009 Broadcom Corporation.
+ *
+ * Name: bc_dts_types.h
+ *
+ * Description: Data types
+ *
+ * AU
+ *
+ * HISTORY:
+ *
+ ********************************************************************
+ * This header is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 2.1 of the License.
+ *
+ * This header is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this header. If not, see <http://www.gnu.org/licenses/>.
+ *******************************************************************/
+
+#ifndef _BC_DTS_TYPES_H_
+#define _BC_DTS_TYPES_H_
+
+#ifdef __LINUX_USER__ // Don't include these for KERNEL..
+#include <stdint.h>
+#endif
+
+#if defined(_WIN64) || defined(_WIN32)
+typedef uint32_t U32;
+typedef int32_t S32;
+typedef uint16_t U16;
+typedef int16_t S16;
+typedef unsigned char U8;
+typedef char S8;
+#endif
+
+#ifndef PVOID
+typedef void *PVOID;
+#endif
+
+#ifndef BOOL
+typedef int BOOL;
+#endif
+
+#ifdef WIN32
+ typedef unsigned __int64 U64;
+#elif defined(_WIN64)
+ typedef uint64_t U64;
+#endif
+
+#ifdef _WIN64
+#if !(defined(POINTER_32))
+#define POINTER_32 __ptr32
+#endif
+#else /* _WIN32 */
+#define POINTER_32
+#endif
+
+#if defined(__KERNEL__) || defined(__LINUX_USER__)
+
+#ifdef __LINUX_USER__ /* Don't include these for KERNEL */
+typedef uint32_t ULONG;
+typedef int32_t LONG;
+typedef void *HANDLE;
+#ifndef VOID
+typedef void VOID;
+#endif
+typedef void *LPVOID;
+typedef uint32_t DWORD;
+typedef uint32_t UINT32;
+typedef uint32_t *LPDWORD;
+typedef unsigned char *PUCHAR;
+
+#ifndef TRUE
+ #define TRUE 1
+#endif
+
+#ifndef FALSE
+ #define FALSE 0
+#endif
+
+#define TEXT
+
+#else
+
+/* For Kernel usage.. */
+typedef bool bc_bool_t;
+#endif
+
+#else
+
+#ifndef uint64_t
+typedef struct _uint64_t {
+ uint32_t low_dw;
+ uint32_t hi_dw;
+} uint64_t;
+#endif
+
+#ifndef int32_t
+typedef signed long int32_t;
+#endif
+
+#ifndef uint32_t
+typedef unsigned long uint32_t;
+#endif
+
+#ifndef uint16_t
+typedef unsigned short uint16_t;
+#endif
+
+#ifndef uint8_t
+typedef unsigned char uint8_t;
+#endif
+#endif
+
+#endif
+
diff --git a/drivers/staging/crystalhd/bcm_70012_regs.h b/drivers/staging/crystalhd/bcm_70012_regs.h
new file mode 100644
index 000000000000..6922f54e432f
--- /dev/null
+++ b/drivers/staging/crystalhd/bcm_70012_regs.h
@@ -0,0 +1,757 @@
+/***************************************************************************
+ * Copyright (c) 1999-2009, Broadcom Corporation.
+ *
+ * Name: bcm_70012_regs.h
+ *
+ * Description: BCM70012 registers
+ *
+ ********************************************************************
+ * This header is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 2.1 of the License.
+ *
+ * This header is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this header. If not, see <http://www.gnu.org/licenses/>.
+ ***************************************************************************/
+
+#ifndef MACFILE_H__
+#define MACFILE_H__
+
+/**
+ * m = memory, c = core, r = register, f = field, d = data.
+ */
+#if !defined(GET_FIELD) && !defined(SET_FIELD)
+#define BRCM_ALIGN(c,r,f) c##_##r##_##f##_ALIGN
+#define BRCM_BITS(c,r,f) c##_##r##_##f##_BITS
+#define BRCM_MASK(c,r,f) c##_##r##_##f##_MASK
+#define BRCM_SHIFT(c,r,f) c##_##r##_##f##_SHIFT
+
+#define GET_FIELD(m,c,r,f) \
+ ((((m) & BRCM_MASK(c,r,f)) >> BRCM_SHIFT(c,r,f)) << BRCM_ALIGN(c,r,f))
+
+#define SET_FIELD(m,c,r,f,d) \
+ ((m) = (((m) & ~BRCM_MASK(c,r,f)) | ((((d) >> BRCM_ALIGN(c,r,f)) << \
+ BRCM_SHIFT(c,r,f)) & BRCM_MASK(c,r,f))) \
+ )
+
+#define SET_TYPE_FIELD(m,c,r,f,d) SET_FIELD(m,c,r,f,c##_##d)
+#define SET_NAME_FIELD(m,c,r,f,d) SET_FIELD(m,c,r,f,c##_##r##_##f##_##d)
+#define SET_VALUE_FIELD(m,c,r,f,d) SET_FIELD(m,c,r,f,d)
+
+#endif /* GET & SET */
+
+/****************************************************************************
+ * Core Enums.
+ ***************************************************************************/
+/****************************************************************************
+ * Enums: AES_RGR_BRIDGE_RESET_CTRL
+ ***************************************************************************/
+#define AES_RGR_BRIDGE_RESET_CTRL_DEASSERT 0
+#define AES_RGR_BRIDGE_RESET_CTRL_ASSERT 1
+
+/****************************************************************************
+ * Enums: CCE_RGR_BRIDGE_RESET_CTRL
+ ***************************************************************************/
+#define CCE_RGR_BRIDGE_RESET_CTRL_DEASSERT 0
+#define CCE_RGR_BRIDGE_RESET_CTRL_ASSERT 1
+
+/****************************************************************************
+ * Enums: DBU_RGR_BRIDGE_RESET_CTRL
+ ***************************************************************************/
+#define DBU_RGR_BRIDGE_RESET_CTRL_DEASSERT 0
+#define DBU_RGR_BRIDGE_RESET_CTRL_ASSERT 1
+
+/****************************************************************************
+ * Enums: DCI_RGR_BRIDGE_RESET_CTRL
+ ***************************************************************************/
+#define DCI_RGR_BRIDGE_RESET_CTRL_DEASSERT 0
+#define DCI_RGR_BRIDGE_RESET_CTRL_ASSERT 1
+
+/****************************************************************************
+ * Enums: GISB_ARBITER_DEASSERT_ASSERT
+ ***************************************************************************/
+#define GISB_ARBITER_DEASSERT_ASSERT_DEASSERT 0
+#define GISB_ARBITER_DEASSERT_ASSERT_ASSERT 1
+
+/****************************************************************************
+ * Enums: GISB_ARBITER_UNMASK_MASK
+ ***************************************************************************/
+#define GISB_ARBITER_UNMASK_MASK_UNMASK 0
+#define GISB_ARBITER_UNMASK_MASK_MASK 1
+
+/****************************************************************************
+ * Enums: GISB_ARBITER_DISABLE_ENABLE
+ ***************************************************************************/
+#define GISB_ARBITER_DISABLE_ENABLE_DISABLE 0
+#define GISB_ARBITER_DISABLE_ENABLE_ENABLE 1
+
+/****************************************************************************
+ * Enums: I2C_GR_BRIDGE_RESET_CTRL
+ ***************************************************************************/
+#define I2C_GR_BRIDGE_RESET_CTRL_DEASSERT 0
+#define I2C_GR_BRIDGE_RESET_CTRL_ASSERT 1
+
+/****************************************************************************
+ * Enums: MISC_GR_BRIDGE_RESET_CTRL
+ ***************************************************************************/
+#define MISC_GR_BRIDGE_RESET_CTRL_DEASSERT 0
+#define MISC_GR_BRIDGE_RESET_CTRL_ASSERT 1
+
+/****************************************************************************
+ * Enums: OTP_GR_BRIDGE_RESET_CTRL
+ ***************************************************************************/
+#define OTP_GR_BRIDGE_RESET_CTRL_DEASSERT 0
+#define OTP_GR_BRIDGE_RESET_CTRL_ASSERT 1
+
+/****************************************************************************
+ * BCM70012_TGT_TOP_PCIE_CFG
+ ***************************************************************************/
+#define PCIE_CFG_DEVICE_VENDOR_ID 0x00000000 /* DEVICE_VENDOR_ID Register */
+#define PCIE_CFG_STATUS_COMMAND 0x00000004 /* STATUS_COMMAND Register */
+#define PCIE_CFG_PCI_CLASSCODE_AND_REVISION_ID 0x00000008 /* PCI_CLASSCODE_AND_REVISION_ID Register */
+#define PCIE_CFG_BIST_HEADER_TYPE_LATENCY_TIMER_CACHE_LINE_SIZE 0x0000000c /* BIST_HEADER_TYPE_LATENCY_TIMER_CACHE_LINE_SIZE Register */
+#define PCIE_CFG_BASE_ADDRESS_1 0x00000010 /* BASE_ADDRESS_1 Register */
+#define PCIE_CFG_BASE_ADDRESS_2 0x00000014 /* BASE_ADDRESS_2 Register */
+#define PCIE_CFG_BASE_ADDRESS_3 0x00000018 /* BASE_ADDRESS_3 Register */
+#define PCIE_CFG_BASE_ADDRESS_4 0x0000001c /* BASE_ADDRESS_4 Register */
+#define PCIE_CFG_CARDBUS_CIS_POINTER 0x00000028 /* CARDBUS_CIS_POINTER Register */
+#define PCIE_CFG_SUBSYSTEM_DEVICE_VENDOR_ID 0x0000002c /* SUBSYSTEM_DEVICE_VENDOR_ID Register */
+#define PCIE_CFG_EXPANSION_ROM_BASE_ADDRESS 0x00000030 /* EXPANSION_ROM_BASE_ADDRESS Register */
+#define PCIE_CFG_CAPABILITIES_POINTER 0x00000034 /* CAPABILITIES_POINTER Register */
+#define PCIE_CFG_INTERRUPT 0x0000003c /* INTERRUPT Register */
+#define PCIE_CFG_VPD_CAPABILITIES 0x00000040 /* VPD_CAPABILITIES Register */
+#define PCIE_CFG_VPD_DATA 0x00000044 /* VPD_DATA Register */
+#define PCIE_CFG_POWER_MANAGEMENT_CAPABILITY 0x00000048 /* POWER_MANAGEMENT_CAPABILITY Register */
+#define PCIE_CFG_POWER_MANAGEMENT_CONTROL_STATUS 0x0000004c /* POWER_MANAGEMENT_CONTROL_STATUS Register */
+#define PCIE_CFG_MSI_CAPABILITY_HEADER 0x00000050 /* MSI_CAPABILITY_HEADER Register */
+#define PCIE_CFG_MSI_LOWER_ADDRESS 0x00000054 /* MSI_LOWER_ADDRESS Register */
+#define PCIE_CFG_MSI_UPPER_ADDRESS_REGISTER 0x00000058 /* MSI_UPPER_ADDRESS_REGISTER Register */
+#define PCIE_CFG_MSI_DATA 0x0000005c /* MSI_DATA Register */
+#define PCIE_CFG_BROADCOM_VENDOR_SPECIFIC_CAPABILITY_HEADER 0x00000060 /* BROADCOM_VENDOR_SPECIFIC_CAPABILITY_HEADER Register */
+#define PCIE_CFG_RESET_COUNTERS_INITIAL_VALUES 0x00000064 /* RESET_COUNTERS_INITIAL_VALUES Register */
+#define PCIE_CFG_MISCELLANEOUS_HOST_CONTROL 0x00000068 /* MISCELLANEOUS_HOST_CONTROL Register */
+#define PCIE_CFG_SPARE 0x0000006c /* SPARE Register */
+#define PCIE_CFG_PCI_STATE 0x00000070 /* PCI_STATE Register */
+#define PCIE_CFG_CLOCK_CONTROL 0x00000074 /* CLOCK_CONTROL Register */
+#define PCIE_CFG_REGISTER_BASE 0x00000078 /* REGISTER_BASE Register */
+#define PCIE_CFG_MEMORY_BASE 0x0000007c /* MEMORY_BASE Register */
+#define PCIE_CFG_REGISTER_DATA 0x00000080 /* REGISTER_DATA Register */
+#define PCIE_CFG_MEMORY_DATA 0x00000084 /* MEMORY_DATA Register */
+#define PCIE_CFG_EXPANSION_ROM_BAR_SIZE 0x00000088 /* EXPANSION_ROM_BAR_SIZE Register */
+#define PCIE_CFG_EXPANSION_ROM_ADDRESS 0x0000008c /* EXPANSION_ROM_ADDRESS Register */
+#define PCIE_CFG_EXPANSION_ROM_DATA 0x00000090 /* EXPANSION_ROM_DATA Register */
+#define PCIE_CFG_VPD_INTERFACE 0x00000094 /* VPD_INTERFACE Register */
+#define PCIE_CFG_UNDI_RECEIVE_BD_STANDARD_PRODUCER_RING_PRODUCER_INDEX_MAILBOX_UPPER 0x00000098 /* UNDI_RECEIVE_BD_STANDARD_PRODUCER_RING_PRODUCER_INDEX_MAILBOX_UPPER Register */
+#define PCIE_CFG_UNDI_RECEIVE_BD_STANDARD_PRODUCER_RING_PRODUCER_INDEX_MAILBOX_LOWER 0x0000009c /* UNDI_RECEIVE_BD_STANDARD_PRODUCER_RING_PRODUCER_INDEX_MAILBOX_LOWER Register */
+#define PCIE_CFG_UNDI_RECEIVE_RETURN_RING_CONSUMER_INDEX_UPPER 0x000000a0 /* UNDI_RECEIVE_RETURN_RING_CONSUMER_INDEX_UPPER Register */
+#define PCIE_CFG_UNDI_RECEIVE_RETURN_RING_CONSUMER_INDEX_LOWER 0x000000a4 /* UNDI_RECEIVE_RETURN_RING_CONSUMER_INDEX_LOWER Register */
+#define PCIE_CFG_UNDI_SEND_BD_PRODUCER_INDEX_MAILBOX_UPPER 0x000000a8 /* UNDI_SEND_BD_PRODUCER_INDEX_MAILBOX_UPPER Register */
+#define PCIE_CFG_UNDI_SEND_BD_PRODUCER_INDEX_MAILBOX_LOWER 0x000000ac /* UNDI_SEND_BD_PRODUCER_INDEX_MAILBOX_LOWER Register */
+#define PCIE_CFG_INT_MAILBOX_UPPER 0x000000b0 /* INT_MAILBOX_UPPER Register */
+#define PCIE_CFG_INT_MAILBOX_LOWER 0x000000b4 /* INT_MAILBOX_LOWER Register */
+#define PCIE_CFG_PRODUCT_ID_AND_ASIC_REVISION 0x000000bc /* PRODUCT_ID_AND_ASIC_REVISION Register */
+#define PCIE_CFG_FUNCTION_EVENT 0x000000c0 /* FUNCTION_EVENT Register */
+#define PCIE_CFG_FUNCTION_EVENT_MASK 0x000000c4 /* FUNCTION_EVENT_MASK Register */
+#define PCIE_CFG_FUNCTION_PRESENT 0x000000c8 /* FUNCTION_PRESENT Register */
+#define PCIE_CFG_PCIE_CAPABILITIES 0x000000cc /* PCIE_CAPABILITIES Register */
+#define PCIE_CFG_DEVICE_CAPABILITIES 0x000000d0 /* DEVICE_CAPABILITIES Register */
+#define PCIE_CFG_DEVICE_STATUS_CONTROL 0x000000d4 /* DEVICE_STATUS_CONTROL Register */
+#define PCIE_CFG_LINK_CAPABILITY 0x000000d8 /* LINK_CAPABILITY Register */
+#define PCIE_CFG_LINK_STATUS_CONTROL 0x000000dc /* LINK_STATUS_CONTROL Register */
+#define PCIE_CFG_DEVICE_CAPABILITIES_2 0x000000f0 /* DEVICE_CAPABILITIES_2 Register */
+#define PCIE_CFG_DEVICE_STATUS_CONTROL_2 0x000000f4 /* DEVICE_STATUS_CONTROL_2 Register */
+#define PCIE_CFG_LINK_CAPABILITIES_2 0x000000f8 /* LINK_CAPABILITIES_2 Register */
+#define PCIE_CFG_LINK_STATUS_CONTROL_2 0x000000fc /* LINK_STATUS_CONTROL_2 Register */
+#define PCIE_CFG_ADVANCED_ERROR_REPORTING_ENHANCED_CAPABILITY_HEADER 0x00000100 /* ADVANCED_ERROR_REPORTING_ENHANCED_CAPABILITY_HEADER Register */
+#define PCIE_CFG_UNCORRECTABLE_ERROR_STATUS 0x00000104 /* UNCORRECTABLE_ERROR_STATUS Register */
+#define PCIE_CFG_UNCORRECTABLE_ERROR_MASK 0x00000108 /* UNCORRECTABLE_ERROR_MASK Register */
+#define PCIE_CFG_UNCORRECTABLE_ERROR_SEVERITY 0x0000010c /* UNCORRECTABLE_ERROR_SEVERITY Register */
+#define PCIE_CFG_CORRECTABLE_ERROR_STATUS 0x00000110 /* CORRECTABLE_ERROR_STATUS Register */
+#define PCIE_CFG_CORRECTABLE_ERROR_MASK 0x00000114 /* CORRECTABLE_ERROR_MASK Register */
+#define PCIE_CFG_ADVANCED_ERROR_CAPABILITIES_AND_CONTROL 0x00000118 /* ADVANCED_ERROR_CAPABILITIES_AND_CONTROL Register */
+#define PCIE_CFG_HEADER_LOG_1 0x0000011c /* HEADER_LOG_1 Register */
+#define PCIE_CFG_HEADER_LOG_2 0x00000120 /* HEADER_LOG_2 Register */
+#define PCIE_CFG_HEADER_LOG_3 0x00000124 /* HEADER_LOG_3 Register */
+#define PCIE_CFG_HEADER_LOG_4 0x00000128 /* HEADER_LOG_4 Register */
+#define PCIE_CFG_VIRTUAL_CHANNEL_ENHANCED_CAPABILITY_HEADER 0x0000013c /* VIRTUAL_CHANNEL_ENHANCED_CAPABILITY_HEADER Register */
+#define PCIE_CFG_PORT_VC_CAPABILITY 0x00000140 /* PORT_VC_CAPABILITY Register */
+#define PCIE_CFG_PORT_VC_CAPABILITY_2 0x00000144 /* PORT_VC_CAPABILITY_2 Register */
+#define PCIE_CFG_PORT_VC_STATUS_CONTROL 0x00000148 /* PORT_VC_STATUS_CONTROL Register */
+#define PCIE_CFG_VC_RESOURCE_CAPABILITY 0x0000014c /* VC_RESOURCE_CAPABILITY Register */
+#define PCIE_CFG_VC_RESOURCE_CONTROL 0x00000150 /* VC_RESOURCE_CONTROL Register */
+#define PCIE_CFG_VC_RESOURCE_STATUS 0x00000154 /* VC_RESOURCE_STATUS Register */
+#define PCIE_CFG_DEVICE_SERIAL_NO_ENHANCED_CAPABILITY_HEADER 0x00000160 /* DEVICE_SERIAL_NO_ENHANCED_CAPABILITY_HEADER Register */
+#define PCIE_CFG_DEVICE_SERIAL_NO_LOWER_DW 0x00000164 /* DEVICE_SERIAL_NO_LOWER_DW Register */
+#define PCIE_CFG_DEVICE_SERIAL_NO_UPPER_DW 0x00000168 /* DEVICE_SERIAL_NO_UPPER_DW Register */
+#define PCIE_CFG_POWER_BUDGETING_ENHANCED_CAPABILITY_HEADER 0x0000016c /* POWER_BUDGETING_ENHANCED_CAPABILITY_HEADER Register */
+#define PCIE_CFG_POWER_BUDGETING_DATA_SELECT 0x00000170 /* POWER_BUDGETING_DATA_SELECT Register */
+#define PCIE_CFG_POWER_BUDGETING_DATA 0x00000174 /* POWER_BUDGETING_DATA Register */
+#define PCIE_CFG_POWER_BUDGETING_CAPABILITY 0x00000178 /* POWER_BUDGETING_CAPABILITY Register */
+#define PCIE_CFG_FIRMWARE_POWER_BUDGETING_2_1 0x0000017c /* FIRMWARE_POWER_BUDGETING_2_1 Register */
+#define PCIE_CFG_FIRMWARE_POWER_BUDGETING_4_3 0x00000180 /* FIRMWARE_POWER_BUDGETING_4_3 Register */
+#define PCIE_CFG_FIRMWARE_POWER_BUDGETING_6_5 0x00000184 /* FIRMWARE_POWER_BUDGETING_6_5 Register */
+#define PCIE_CFG_FIRMWARE_POWER_BUDGETING_8_7 0x00000188 /* FIRMWARE_POWER_BUDGETING_8_7 Register */
+#define PCIE_CFG_PCIE_1_1_ADVISORY_NON_FATAL_ERROR_MASKING 0x0000018c /* PCIE_1_1_ADVISORY_NON_FATAL_ERROR_MASKING Register */
+
+
+/****************************************************************************
+ * BCM70012_TGT_TOP_PCIE_TL
+ ***************************************************************************/
+#define PCIE_TL_TL_CONTROL 0x00000400 /* TL_CONTROL Register */
+#define PCIE_TL_TRANSACTION_CONFIGURATION 0x00000404 /* TRANSACTION_CONFIGURATION Register */
+
+
+/****************************************************************************
+ * BCM70012_TGT_TOP_PCIE_DLL
+ ***************************************************************************/
+#define PCIE_DLL_DATA_LINK_CONTROL 0x00000500 /* DATA_LINK_CONTROL Register */
+#define PCIE_DLL_DATA_LINK_STATUS 0x00000504 /* DATA_LINK_STATUS Register */
+
+
+/****************************************************************************
+ * BCM70012_TGT_TOP_INTR
+ ***************************************************************************/
+#define INTR_INTR_STATUS 0x00000700 /* Interrupt Status Register */
+#define INTR_INTR_SET 0x00000704 /* Interrupt Set Register */
+#define INTR_INTR_CLR_REG 0x00000708 /* Interrupt Clear Register */
+#define INTR_INTR_MSK_STS_REG 0x0000070c /* Interrupt Mask Status Register */
+#define INTR_INTR_MSK_SET_REG 0x00000710 /* Interrupt Mask Set Register */
+#define INTR_INTR_MSK_CLR_REG 0x00000714 /* Interrupt Mask Clear Register */
+#define INTR_EOI_CTRL 0x00000720 /* End of interrupt control register */
+
+
+/****************************************************************************
+ * BCM70012_MISC_TOP_MISC1
+ ***************************************************************************/
+#define MISC1_TX_FIRST_DESC_L_ADDR_LIST0 0x00000c00 /* Tx DMA Descriptor List0 First Descriptor lower Address */
+#define MISC1_TX_FIRST_DESC_U_ADDR_LIST0 0x00000c04 /* Tx DMA Descriptor List0 First Descriptor Upper Address */
+#define MISC1_TX_FIRST_DESC_L_ADDR_LIST1 0x00000c08 /* Tx DMA Descriptor List1 First Descriptor Lower Address */
+#define MISC1_TX_FIRST_DESC_U_ADDR_LIST1 0x00000c0c /* Tx DMA Descriptor List1 First Descriptor Upper Address */
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS 0x00000c10 /* Tx DMA Software Descriptor List Control and Status */
+#define MISC1_TX_DMA_ERROR_STATUS 0x00000c18 /* Tx DMA Engine Error Status */
+#define MISC1_TX_DMA_LIST0_CUR_DESC_L_ADDR 0x00000c1c /* Tx DMA List0 Current Descriptor Lower Address */
+#define MISC1_TX_DMA_LIST0_CUR_DESC_U_ADDR 0x00000c20 /* Tx DMA List0 Current Descriptor Upper Address */
+#define MISC1_TX_DMA_LIST0_CUR_BYTE_CNT_REM 0x00000c24 /* Tx DMA List0 Current Descriptor Upper Address */
+#define MISC1_TX_DMA_LIST1_CUR_DESC_L_ADDR 0x00000c28 /* Tx DMA List1 Current Descriptor Lower Address */
+#define MISC1_TX_DMA_LIST1_CUR_DESC_U_ADDR 0x00000c2c /* Tx DMA List1 Current Descriptor Upper Address */
+#define MISC1_TX_DMA_LIST1_CUR_BYTE_CNT_REM 0x00000c30 /* Tx DMA List1 Current Descriptor Upper Address */
+#define MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST0 0x00000c34 /* Y Rx Descriptor List0 First Descriptor Lower Address */
+#define MISC1_Y_RX_FIRST_DESC_U_ADDR_LIST0 0x00000c38 /* Y Rx Descriptor List0 First Descriptor Upper Address */
+#define MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST1 0x00000c3c /* Y Rx Descriptor List1 First Descriptor Lower Address */
+#define MISC1_Y_RX_FIRST_DESC_U_ADDR_LIST1 0x00000c40 /* Y Rx Descriptor List1 First Descriptor Upper Address */
+#define MISC1_Y_RX_SW_DESC_LIST_CTRL_STS 0x00000c44 /* Y Rx Software Descriptor List Control and Status */
+#define MISC1_Y_RX_ERROR_STATUS 0x00000c4c /* Y Rx Engine Error Status */
+#define MISC1_Y_RX_LIST0_CUR_DESC_L_ADDR 0x00000c50 /* Y Rx List0 Current Descriptor Lower Address */
+#define MISC1_Y_RX_LIST0_CUR_DESC_U_ADDR 0x00000c54 /* Y Rx List0 Current Descriptor Upper Address */
+#define MISC1_Y_RX_LIST0_CUR_BYTE_CNT 0x00000c58 /* Y Rx List0 Current Descriptor Byte Count */
+#define MISC1_Y_RX_LIST1_CUR_DESC_L_ADDR 0x00000c5c /* Y Rx List1 Current Descriptor Lower address */
+#define MISC1_Y_RX_LIST1_CUR_DESC_U_ADDR 0x00000c60 /* Y Rx List1 Current Descriptor Upper address */
+#define MISC1_Y_RX_LIST1_CUR_BYTE_CNT 0x00000c64 /* Y Rx List1 Current Descriptor Byte Count */
+#define MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST0 0x00000c68 /* UV Rx Descriptor List0 First Descriptor lower Address */
+#define MISC1_UV_RX_FIRST_DESC_U_ADDR_LIST0 0x00000c6c /* UV Rx Descriptor List0 First Descriptor Upper Address */
+#define MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST1 0x00000c70 /* UV Rx Descriptor List1 First Descriptor Lower Address */
+#define MISC1_UV_RX_FIRST_DESC_U_ADDR_LIST1 0x00000c74 /* UV Rx Descriptor List1 First Descriptor Upper Address */
+#define MISC1_UV_RX_SW_DESC_LIST_CTRL_STS 0x00000c78 /* UV Rx Software Descriptor List Control and Status */
+#define MISC1_UV_RX_ERROR_STATUS 0x00000c7c /* UV Rx Engine Error Status */
+#define MISC1_UV_RX_LIST0_CUR_DESC_L_ADDR 0x00000c80 /* UV Rx List0 Current Descriptor Lower Address */
+#define MISC1_UV_RX_LIST0_CUR_DESC_U_ADDR 0x00000c84 /* UV Rx List0 Current Descriptor Upper Address */
+#define MISC1_UV_RX_LIST0_CUR_BYTE_CNT 0x00000c88 /* UV Rx List0 Current Descriptor Byte Count */
+#define MISC1_UV_RX_LIST1_CUR_DESC_L_ADDR 0x00000c8c /* UV Rx List1 Current Descriptor Lower Address */
+#define MISC1_UV_RX_LIST1_CUR_DESC_U_ADDR 0x00000c90 /* UV Rx List1 Current Descriptor Upper Address */
+#define MISC1_UV_RX_LIST1_CUR_BYTE_CNT 0x00000c94 /* UV Rx List1 Current Descriptor Byte Count */
+#define MISC1_DMA_DEBUG_OPTIONS_REG 0x00000c98 /* DMA Debug Options Register */
+#define MISC1_READ_CHANNEL_ERROR_STATUS 0x00000c9c /* Read Channel Error Status */
+#define MISC1_PCIE_DMA_CTRL 0x00000ca0 /* PCIE DMA Control Register */
+
+
+/****************************************************************************
+ * BCM70012_MISC_TOP_MISC2
+ ***************************************************************************/
+#define MISC2_GLOBAL_CTRL 0x00000d00 /* Global Control Register */
+#define MISC2_INTERNAL_STATUS 0x00000d04 /* Internal Status Register */
+#define MISC2_INTERNAL_STATUS_MUX_CTRL 0x00000d08 /* Internal Debug Mux Control */
+#define MISC2_DEBUG_FIFO_LENGTH 0x00000d0c /* Debug FIFO Length */
+
+
+/****************************************************************************
+ * BCM70012_MISC_TOP_MISC3
+ ***************************************************************************/
+#define MISC3_RESET_CTRL 0x00000e00 /* Reset Control Register */
+#define MISC3_BIST_CTRL 0x00000e04 /* BIST Control Register */
+#define MISC3_BIST_STATUS 0x00000e08 /* BIST Status Register */
+#define MISC3_RX_CHECKSUM 0x00000e0c /* Receive Checksum */
+#define MISC3_TX_CHECKSUM 0x00000e10 /* Transmit Checksum */
+#define MISC3_ECO_CTRL_CORE 0x00000e14 /* ECO Core Reset Control Register */
+#define MISC3_CSI_TEST_CTRL 0x00000e18 /* CSI Test Control Register */
+#define MISC3_HD_DVI_TEST_CTRL 0x00000e1c /* HD DVI Test Control Register */
+
+
+/****************************************************************************
+ * BCM70012_MISC_TOP_MISC_PERST
+ ***************************************************************************/
+#define MISC_PERST_ECO_CTRL_PERST 0x00000e80 /* ECO PCIE Reset Control Register */
+#define MISC_PERST_DECODER_CTRL 0x00000e84 /* Decoder Control Register */
+#define MISC_PERST_CCE_STATUS 0x00000e88 /* Config Copy Engine Status */
+#define MISC_PERST_PCIE_DEBUG 0x00000e8c /* PCIE Debug Control Register */
+#define MISC_PERST_PCIE_DEBUG_STATUS 0x00000e90 /* PCIE Debug Status Register */
+#define MISC_PERST_VREG_CTRL 0x00000e94 /* Voltage Regulator Control Register */
+#define MISC_PERST_MEM_CTRL 0x00000e98 /* Memory Control Register */
+#define MISC_PERST_CLOCK_CTRL 0x00000e9c /* Clock Control Register */
+
+
+/****************************************************************************
+ * BCM70012_MISC_TOP_GISB_ARBITER
+ ***************************************************************************/
+#define GISB_ARBITER_REVISION 0x00000f00 /* GISB ARBITER REVISION */
+#define GISB_ARBITER_SCRATCH 0x00000f04 /* GISB ARBITER Scratch Register */
+#define GISB_ARBITER_REQ_MASK 0x00000f08 /* GISB ARBITER Master Request Mask Register */
+#define GISB_ARBITER_TIMER 0x00000f0c /* GISB ARBITER Timer Value Register */
+
+
+/****************************************************************************
+ * BCM70012_OTP_TOP_OTP
+ ***************************************************************************/
+#define OTP_CONFIG_INFO 0x00001400 /* OTP Configuration Register */
+#define OTP_CMD 0x00001404 /* OTP Command Register */
+#define OTP_STATUS 0x00001408 /* OTP Status Register */
+#define OTP_CONTENT_MISC 0x0000140c /* Content : Miscellaneous Register */
+#define OTP_CONTENT_AES_0 0x00001410 /* Content : AES Key 0 Register */
+#define OTP_CONTENT_AES_1 0x00001414 /* Content : AES Key 1 Register */
+#define OTP_CONTENT_AES_2 0x00001418 /* Content : AES Key 2 Register */
+#define OTP_CONTENT_AES_3 0x0000141c /* Content : AES Key 3 Register */
+#define OTP_CONTENT_SHA_0 0x00001420 /* Content : SHA Key 0 Register */
+#define OTP_CONTENT_SHA_1 0x00001424 /* Content : SHA Key 1 Register */
+#define OTP_CONTENT_SHA_2 0x00001428 /* Content : SHA Key 2 Register */
+#define OTP_CONTENT_SHA_3 0x0000142c /* Content : SHA Key 3 Register */
+#define OTP_CONTENT_SHA_4 0x00001430 /* Content : SHA Key 4 Register */
+#define OTP_CONTENT_SHA_5 0x00001434 /* Content : SHA Key 5 Register */
+#define OTP_CONTENT_SHA_6 0x00001438 /* Content : SHA Key 6 Register */
+#define OTP_CONTENT_SHA_7 0x0000143c /* Content : SHA Key 7 Register */
+#define OTP_CONTENT_CHECKSUM 0x00001440 /* Content : Checksum Register */
+#define OTP_PROG_CTRL 0x00001444 /* Programming Control Register */
+#define OTP_PROG_STATUS 0x00001448 /* Programming Status Register */
+#define OTP_PROG_PULSE 0x0000144c /* Program Pulse Width Register */
+#define OTP_VERIFY_PULSE 0x00001450 /* Verify Pulse Width Register */
+#define OTP_PROG_MASK 0x00001454 /* Program Mask Register */
+#define OTP_DATA_INPUT 0x00001458 /* Data Input Register */
+#define OTP_DATA_OUTPUT 0x0000145c /* Data Output Register */
+
+
+/****************************************************************************
+ * BCM70012_AES_TOP_AES
+ ***************************************************************************/
+#define AES_CONFIG_INFO 0x00001800 /* AES Configuration Information Register */
+#define AES_CMD 0x00001804 /* AES Command Register */
+#define AES_STATUS 0x00001808 /* AES Status Register */
+#define AES_EEPROM_CONFIG 0x0000180c /* AES EEPROM Configuration Register */
+#define AES_EEPROM_DATA_0 0x00001810 /* AES EEPROM Data Register 0 */
+#define AES_EEPROM_DATA_1 0x00001814 /* AES EEPROM Data Register 1 */
+#define AES_EEPROM_DATA_2 0x00001818 /* AES EEPROM Data Register 2 */
+#define AES_EEPROM_DATA_3 0x0000181c /* AES EEPROM Data Register 3 */
+
+
+/****************************************************************************
+ * BCM70012_DCI_TOP_DCI
+ ***************************************************************************/
+#define DCI_CMD 0x00001c00 /* DCI Command Register */
+#define DCI_STATUS 0x00001c04 /* DCI Status Register */
+#define DCI_DRAM_BASE_ADDR 0x00001c08 /* DRAM Base Address Register */
+#define DCI_FIRMWARE_ADDR 0x00001c0c /* Firmware Address Register */
+#define DCI_FIRMWARE_DATA 0x00001c10 /* Firmware Data Register */
+#define DCI_SIGNATURE_DATA_0 0x00001c14 /* Signature Data Register 0 */
+#define DCI_SIGNATURE_DATA_1 0x00001c18 /* Signature Data Register 1 */
+#define DCI_SIGNATURE_DATA_2 0x00001c1c /* Signature Data Register 2 */
+#define DCI_SIGNATURE_DATA_3 0x00001c20 /* Signature Data Register 3 */
+#define DCI_SIGNATURE_DATA_4 0x00001c24 /* Signature Data Register 4 */
+#define DCI_SIGNATURE_DATA_5 0x00001c28 /* Signature Data Register 5 */
+#define DCI_SIGNATURE_DATA_6 0x00001c2c /* Signature Data Register 6 */
+#define DCI_SIGNATURE_DATA_7 0x00001c30 /* Signature Data Register 7 */
+
+
+/****************************************************************************
+ * BCM70012_TGT_TOP_INTR
+ ***************************************************************************/
+/****************************************************************************
+ * INTR :: INTR_STATUS
+ ***************************************************************************/
+/* INTR :: INTR_STATUS :: reserved0 [31:26] */
+#define INTR_INTR_STATUS_reserved0_MASK 0xfc000000
+#define INTR_INTR_STATUS_reserved0_ALIGN 0
+#define INTR_INTR_STATUS_reserved0_BITS 6
+#define INTR_INTR_STATUS_reserved0_SHIFT 26
+
+/* INTR :: INTR_STATUS :: PCIE_TGT_CA_ATTN [25:25] */
+#define INTR_INTR_STATUS_PCIE_TGT_CA_ATTN_MASK 0x02000000
+#define INTR_INTR_STATUS_PCIE_TGT_CA_ATTN_ALIGN 0
+#define INTR_INTR_STATUS_PCIE_TGT_CA_ATTN_BITS 1
+#define INTR_INTR_STATUS_PCIE_TGT_CA_ATTN_SHIFT 25
+
+/* INTR :: INTR_STATUS :: PCIE_TGT_UR_ATTN [24:24] */
+#define INTR_INTR_STATUS_PCIE_TGT_UR_ATTN_MASK 0x01000000
+#define INTR_INTR_STATUS_PCIE_TGT_UR_ATTN_ALIGN 0
+#define INTR_INTR_STATUS_PCIE_TGT_UR_ATTN_BITS 1
+#define INTR_INTR_STATUS_PCIE_TGT_UR_ATTN_SHIFT 24
+
+/* INTR :: INTR_STATUS :: reserved1 [23:14] */
+#define INTR_INTR_STATUS_reserved1_MASK 0x00ffc000
+#define INTR_INTR_STATUS_reserved1_ALIGN 0
+#define INTR_INTR_STATUS_reserved1_BITS 10
+#define INTR_INTR_STATUS_reserved1_SHIFT 14
+
+/* INTR :: INTR_STATUS :: L1_UV_RX_DMA_ERR_INTR [13:13] */
+#define INTR_INTR_STATUS_L1_UV_RX_DMA_ERR_INTR_MASK 0x00002000
+#define INTR_INTR_STATUS_L1_UV_RX_DMA_ERR_INTR_ALIGN 0
+#define INTR_INTR_STATUS_L1_UV_RX_DMA_ERR_INTR_BITS 1
+#define INTR_INTR_STATUS_L1_UV_RX_DMA_ERR_INTR_SHIFT 13
+
+/* INTR :: INTR_STATUS :: L1_UV_RX_DMA_DONE_INTR [12:12] */
+#define INTR_INTR_STATUS_L1_UV_RX_DMA_DONE_INTR_MASK 0x00001000
+#define INTR_INTR_STATUS_L1_UV_RX_DMA_DONE_INTR_ALIGN 0
+#define INTR_INTR_STATUS_L1_UV_RX_DMA_DONE_INTR_BITS 1
+#define INTR_INTR_STATUS_L1_UV_RX_DMA_DONE_INTR_SHIFT 12
+
+/* INTR :: INTR_STATUS :: L1_Y_RX_DMA_ERR_INTR [11:11] */
+#define INTR_INTR_STATUS_L1_Y_RX_DMA_ERR_INTR_MASK 0x00000800
+#define INTR_INTR_STATUS_L1_Y_RX_DMA_ERR_INTR_ALIGN 0
+#define INTR_INTR_STATUS_L1_Y_RX_DMA_ERR_INTR_BITS 1
+#define INTR_INTR_STATUS_L1_Y_RX_DMA_ERR_INTR_SHIFT 11
+
+/* INTR :: INTR_STATUS :: L1_Y_RX_DMA_DONE_INTR [10:10] */
+#define INTR_INTR_STATUS_L1_Y_RX_DMA_DONE_INTR_MASK 0x00000400
+#define INTR_INTR_STATUS_L1_Y_RX_DMA_DONE_INTR_ALIGN 0
+#define INTR_INTR_STATUS_L1_Y_RX_DMA_DONE_INTR_BITS 1
+#define INTR_INTR_STATUS_L1_Y_RX_DMA_DONE_INTR_SHIFT 10
+
+/* INTR :: INTR_STATUS :: L1_TX_DMA_ERR_INTR [09:09] */
+#define INTR_INTR_STATUS_L1_TX_DMA_ERR_INTR_MASK 0x00000200
+#define INTR_INTR_STATUS_L1_TX_DMA_ERR_INTR_ALIGN 0
+#define INTR_INTR_STATUS_L1_TX_DMA_ERR_INTR_BITS 1
+#define INTR_INTR_STATUS_L1_TX_DMA_ERR_INTR_SHIFT 9
+
+/* INTR :: INTR_STATUS :: L1_TX_DMA_DONE_INTR [08:08] */
+#define INTR_INTR_STATUS_L1_TX_DMA_DONE_INTR_MASK 0x00000100
+#define INTR_INTR_STATUS_L1_TX_DMA_DONE_INTR_ALIGN 0
+#define INTR_INTR_STATUS_L1_TX_DMA_DONE_INTR_BITS 1
+#define INTR_INTR_STATUS_L1_TX_DMA_DONE_INTR_SHIFT 8
+
+/* INTR :: INTR_STATUS :: reserved2 [07:06] */
+#define INTR_INTR_STATUS_reserved2_MASK 0x000000c0
+#define INTR_INTR_STATUS_reserved2_ALIGN 0
+#define INTR_INTR_STATUS_reserved2_BITS 2
+#define INTR_INTR_STATUS_reserved2_SHIFT 6
+
+/* INTR :: INTR_STATUS :: L0_UV_RX_DMA_ERR_INTR [05:05] */
+#define INTR_INTR_STATUS_L0_UV_RX_DMA_ERR_INTR_MASK 0x00000020
+#define INTR_INTR_STATUS_L0_UV_RX_DMA_ERR_INTR_ALIGN 0
+#define INTR_INTR_STATUS_L0_UV_RX_DMA_ERR_INTR_BITS 1
+#define INTR_INTR_STATUS_L0_UV_RX_DMA_ERR_INTR_SHIFT 5
+
+/* INTR :: INTR_STATUS :: L0_UV_RX_DMA_DONE_INTR [04:04] */
+#define INTR_INTR_STATUS_L0_UV_RX_DMA_DONE_INTR_MASK 0x00000010
+#define INTR_INTR_STATUS_L0_UV_RX_DMA_DONE_INTR_ALIGN 0
+#define INTR_INTR_STATUS_L0_UV_RX_DMA_DONE_INTR_BITS 1
+#define INTR_INTR_STATUS_L0_UV_RX_DMA_DONE_INTR_SHIFT 4
+
+/* INTR :: INTR_STATUS :: L0_Y_RX_DMA_ERR_INTR [03:03] */
+#define INTR_INTR_STATUS_L0_Y_RX_DMA_ERR_INTR_MASK 0x00000008
+#define INTR_INTR_STATUS_L0_Y_RX_DMA_ERR_INTR_ALIGN 0
+#define INTR_INTR_STATUS_L0_Y_RX_DMA_ERR_INTR_BITS 1
+#define INTR_INTR_STATUS_L0_Y_RX_DMA_ERR_INTR_SHIFT 3
+
+/* INTR :: INTR_STATUS :: L0_Y_RX_DMA_DONE_INTR [02:02] */
+#define INTR_INTR_STATUS_L0_Y_RX_DMA_DONE_INTR_MASK 0x00000004
+#define INTR_INTR_STATUS_L0_Y_RX_DMA_DONE_INTR_ALIGN 0
+#define INTR_INTR_STATUS_L0_Y_RX_DMA_DONE_INTR_BITS 1
+#define INTR_INTR_STATUS_L0_Y_RX_DMA_DONE_INTR_SHIFT 2
+
+/* INTR :: INTR_STATUS :: L0_TX_DMA_ERR_INTR [01:01] */
+#define INTR_INTR_STATUS_L0_TX_DMA_ERR_INTR_MASK 0x00000002
+#define INTR_INTR_STATUS_L0_TX_DMA_ERR_INTR_ALIGN 0
+#define INTR_INTR_STATUS_L0_TX_DMA_ERR_INTR_BITS 1
+#define INTR_INTR_STATUS_L0_TX_DMA_ERR_INTR_SHIFT 1
+
+/* INTR :: INTR_STATUS :: L0_TX_DMA_DONE_INTR [00:00] */
+#define INTR_INTR_STATUS_L0_TX_DMA_DONE_INTR_MASK 0x00000001
+#define INTR_INTR_STATUS_L0_TX_DMA_DONE_INTR_ALIGN 0
+#define INTR_INTR_STATUS_L0_TX_DMA_DONE_INTR_BITS 1
+#define INTR_INTR_STATUS_L0_TX_DMA_DONE_INTR_SHIFT 0
+
+
+/****************************************************************************
+ * MISC1 :: TX_SW_DESC_LIST_CTRL_STS
+ ***************************************************************************/
+/* MISC1 :: TX_SW_DESC_LIST_CTRL_STS :: reserved0 [31:04] */
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_reserved0_MASK 0xfffffff0
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_reserved0_ALIGN 0
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_reserved0_BITS 28
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_reserved0_SHIFT 4
+
+/* MISC1 :: TX_SW_DESC_LIST_CTRL_STS :: DMA_DATA_SERV_PTR [03:03] */
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_DMA_DATA_SERV_PTR_MASK 0x00000008
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_DMA_DATA_SERV_PTR_ALIGN 0
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_DMA_DATA_SERV_PTR_BITS 1
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_DMA_DATA_SERV_PTR_SHIFT 3
+
+/* MISC1 :: TX_SW_DESC_LIST_CTRL_STS :: DESC_SERV_PTR [02:02] */
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_DESC_SERV_PTR_MASK 0x00000004
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_DESC_SERV_PTR_ALIGN 0
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_DESC_SERV_PTR_BITS 1
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_DESC_SERV_PTR_SHIFT 2
+
+/* MISC1 :: TX_SW_DESC_LIST_CTRL_STS :: TX_DMA_HALT_ON_ERROR [01:01] */
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_HALT_ON_ERROR_MASK 0x00000002
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_HALT_ON_ERROR_ALIGN 0
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_HALT_ON_ERROR_BITS 1
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_HALT_ON_ERROR_SHIFT 1
+
+/* MISC1 :: TX_SW_DESC_LIST_CTRL_STS :: TX_DMA_RUN_STOP [00:00] */
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_RUN_STOP_MASK 0x00000001
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_RUN_STOP_ALIGN 0
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_RUN_STOP_BITS 1
+#define MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_RUN_STOP_SHIFT 0
+
+
+/****************************************************************************
+ * MISC1 :: TX_DMA_ERROR_STATUS
+ ***************************************************************************/
+/* MISC1 :: TX_DMA_ERROR_STATUS :: reserved0 [31:10] */
+#define MISC1_TX_DMA_ERROR_STATUS_reserved0_MASK 0xfffffc00
+#define MISC1_TX_DMA_ERROR_STATUS_reserved0_ALIGN 0
+#define MISC1_TX_DMA_ERROR_STATUS_reserved0_BITS 22
+#define MISC1_TX_DMA_ERROR_STATUS_reserved0_SHIFT 10
+
+/* MISC1 :: TX_DMA_ERROR_STATUS :: TX_L1_DESC_TX_ABORT_ERRORS [09:09] */
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L1_DESC_TX_ABORT_ERRORS_MASK 0x00000200
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L1_DESC_TX_ABORT_ERRORS_ALIGN 0
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L1_DESC_TX_ABORT_ERRORS_BITS 1
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L1_DESC_TX_ABORT_ERRORS_SHIFT 9
+
+/* MISC1 :: TX_DMA_ERROR_STATUS :: reserved1 [08:08] */
+#define MISC1_TX_DMA_ERROR_STATUS_reserved1_MASK 0x00000100
+#define MISC1_TX_DMA_ERROR_STATUS_reserved1_ALIGN 0
+#define MISC1_TX_DMA_ERROR_STATUS_reserved1_BITS 1
+#define MISC1_TX_DMA_ERROR_STATUS_reserved1_SHIFT 8
+
+/* MISC1 :: TX_DMA_ERROR_STATUS :: TX_L0_DESC_TX_ABORT_ERRORS [07:07] */
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L0_DESC_TX_ABORT_ERRORS_MASK 0x00000080
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L0_DESC_TX_ABORT_ERRORS_ALIGN 0
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L0_DESC_TX_ABORT_ERRORS_BITS 1
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L0_DESC_TX_ABORT_ERRORS_SHIFT 7
+
+/* MISC1 :: TX_DMA_ERROR_STATUS :: reserved2 [06:06] */
+#define MISC1_TX_DMA_ERROR_STATUS_reserved2_MASK 0x00000040
+#define MISC1_TX_DMA_ERROR_STATUS_reserved2_ALIGN 0
+#define MISC1_TX_DMA_ERROR_STATUS_reserved2_BITS 1
+#define MISC1_TX_DMA_ERROR_STATUS_reserved2_SHIFT 6
+
+/* MISC1 :: TX_DMA_ERROR_STATUS :: TX_L1_DMA_DATA_TX_ABORT_ERRORS [05:05] */
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L1_DMA_DATA_TX_ABORT_ERRORS_MASK 0x00000020
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L1_DMA_DATA_TX_ABORT_ERRORS_ALIGN 0
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L1_DMA_DATA_TX_ABORT_ERRORS_BITS 1
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L1_DMA_DATA_TX_ABORT_ERRORS_SHIFT 5
+
+/* MISC1 :: TX_DMA_ERROR_STATUS :: TX_L1_FIFO_FULL_ERRORS [04:04] */
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L1_FIFO_FULL_ERRORS_MASK 0x00000010
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L1_FIFO_FULL_ERRORS_ALIGN 0
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L1_FIFO_FULL_ERRORS_BITS 1
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L1_FIFO_FULL_ERRORS_SHIFT 4
+
+/* MISC1 :: TX_DMA_ERROR_STATUS :: reserved3 [03:03] */
+#define MISC1_TX_DMA_ERROR_STATUS_reserved3_MASK 0x00000008
+#define MISC1_TX_DMA_ERROR_STATUS_reserved3_ALIGN 0
+#define MISC1_TX_DMA_ERROR_STATUS_reserved3_BITS 1
+#define MISC1_TX_DMA_ERROR_STATUS_reserved3_SHIFT 3
+
+/* MISC1 :: TX_DMA_ERROR_STATUS :: TX_L0_DMA_DATA_TX_ABORT_ERRORS [02:02] */
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L0_DMA_DATA_TX_ABORT_ERRORS_MASK 0x00000004
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L0_DMA_DATA_TX_ABORT_ERRORS_ALIGN 0
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L0_DMA_DATA_TX_ABORT_ERRORS_BITS 1
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L0_DMA_DATA_TX_ABORT_ERRORS_SHIFT 2
+
+/* MISC1 :: TX_DMA_ERROR_STATUS :: TX_L0_FIFO_FULL_ERRORS [01:01] */
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L0_FIFO_FULL_ERRORS_MASK 0x00000002
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L0_FIFO_FULL_ERRORS_ALIGN 0
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L0_FIFO_FULL_ERRORS_BITS 1
+#define MISC1_TX_DMA_ERROR_STATUS_TX_L0_FIFO_FULL_ERRORS_SHIFT 1
+
+/* MISC1 :: TX_DMA_ERROR_STATUS :: reserved4 [00:00] */
+#define MISC1_TX_DMA_ERROR_STATUS_reserved4_MASK 0x00000001
+#define MISC1_TX_DMA_ERROR_STATUS_reserved4_ALIGN 0
+#define MISC1_TX_DMA_ERROR_STATUS_reserved4_BITS 1
+#define MISC1_TX_DMA_ERROR_STATUS_reserved4_SHIFT 0
+
+
+/****************************************************************************
+ * MISC1 :: Y_RX_ERROR_STATUS
+ ***************************************************************************/
+/* MISC1 :: Y_RX_ERROR_STATUS :: reserved0 [31:14] */
+#define MISC1_Y_RX_ERROR_STATUS_reserved0_MASK 0xffffc000
+#define MISC1_Y_RX_ERROR_STATUS_reserved0_ALIGN 0
+#define MISC1_Y_RX_ERROR_STATUS_reserved0_BITS 18
+#define MISC1_Y_RX_ERROR_STATUS_reserved0_SHIFT 14
+
+/* MISC1 :: Y_RX_ERROR_STATUS :: RX_L1_UNDERRUN_ERROR [13:13] */
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK 0x00002000
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_ALIGN 0
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_BITS 1
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_SHIFT 13
+
+/* MISC1 :: Y_RX_ERROR_STATUS :: RX_L1_OVERRUN_ERROR [12:12] */
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_OVERRUN_ERROR_MASK 0x00001000
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_OVERRUN_ERROR_ALIGN 0
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_OVERRUN_ERROR_BITS 1
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_OVERRUN_ERROR_SHIFT 12
+
+/* MISC1 :: Y_RX_ERROR_STATUS :: RX_L0_UNDERRUN_ERROR [11:11] */
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK 0x00000800
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_ALIGN 0
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_BITS 1
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_SHIFT 11
+
+/* MISC1 :: Y_RX_ERROR_STATUS :: RX_L0_OVERRUN_ERROR [10:10] */
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_OVERRUN_ERROR_MASK 0x00000400
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_OVERRUN_ERROR_ALIGN 0
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_OVERRUN_ERROR_BITS 1
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_OVERRUN_ERROR_SHIFT 10
+
+/* MISC1 :: Y_RX_ERROR_STATUS :: RX_L1_DESC_TX_ABORT_ERRORS [09:09] */
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_DESC_TX_ABORT_ERRORS_MASK 0x00000200
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_DESC_TX_ABORT_ERRORS_ALIGN 0
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_DESC_TX_ABORT_ERRORS_BITS 1
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_DESC_TX_ABORT_ERRORS_SHIFT 9
+
+/* MISC1 :: Y_RX_ERROR_STATUS :: reserved1 [08:08] */
+#define MISC1_Y_RX_ERROR_STATUS_reserved1_MASK 0x00000100
+#define MISC1_Y_RX_ERROR_STATUS_reserved1_ALIGN 0
+#define MISC1_Y_RX_ERROR_STATUS_reserved1_BITS 1
+#define MISC1_Y_RX_ERROR_STATUS_reserved1_SHIFT 8
+
+/* MISC1 :: Y_RX_ERROR_STATUS :: RX_L0_DESC_TX_ABORT_ERRORS [07:07] */
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_DESC_TX_ABORT_ERRORS_MASK 0x00000080
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_DESC_TX_ABORT_ERRORS_ALIGN 0
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_DESC_TX_ABORT_ERRORS_BITS 1
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_DESC_TX_ABORT_ERRORS_SHIFT 7
+
+/* MISC1 :: Y_RX_ERROR_STATUS :: reserved2 [06:05] */
+#define MISC1_Y_RX_ERROR_STATUS_reserved2_MASK 0x00000060
+#define MISC1_Y_RX_ERROR_STATUS_reserved2_ALIGN 0
+#define MISC1_Y_RX_ERROR_STATUS_reserved2_BITS 2
+#define MISC1_Y_RX_ERROR_STATUS_reserved2_SHIFT 5
+
+/* MISC1 :: Y_RX_ERROR_STATUS :: RX_L1_FIFO_FULL_ERRORS [04:04] */
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK 0x00000010
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_ALIGN 0
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_BITS 1
+#define MISC1_Y_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_SHIFT 4
+
+/* MISC1 :: Y_RX_ERROR_STATUS :: reserved3 [03:02] */
+#define MISC1_Y_RX_ERROR_STATUS_reserved3_MASK 0x0000000c
+#define MISC1_Y_RX_ERROR_STATUS_reserved3_ALIGN 0
+#define MISC1_Y_RX_ERROR_STATUS_reserved3_BITS 2
+#define MISC1_Y_RX_ERROR_STATUS_reserved3_SHIFT 2
+
+/* MISC1 :: Y_RX_ERROR_STATUS :: RX_L0_FIFO_FULL_ERRORS [01:01] */
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK 0x00000002
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_ALIGN 0
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_BITS 1
+#define MISC1_Y_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_SHIFT 1
+
+/* MISC1 :: Y_RX_ERROR_STATUS :: reserved4 [00:00] */
+#define MISC1_Y_RX_ERROR_STATUS_reserved4_MASK 0x00000001
+#define MISC1_Y_RX_ERROR_STATUS_reserved4_ALIGN 0
+#define MISC1_Y_RX_ERROR_STATUS_reserved4_BITS 1
+#define MISC1_Y_RX_ERROR_STATUS_reserved4_SHIFT 0
+
+
+/****************************************************************************
+ * MISC1 :: UV_RX_ERROR_STATUS
+ ***************************************************************************/
+/* MISC1 :: UV_RX_ERROR_STATUS :: reserved0 [31:14] */
+#define MISC1_UV_RX_ERROR_STATUS_reserved0_MASK 0xffffc000
+#define MISC1_UV_RX_ERROR_STATUS_reserved0_ALIGN 0
+#define MISC1_UV_RX_ERROR_STATUS_reserved0_BITS 18
+#define MISC1_UV_RX_ERROR_STATUS_reserved0_SHIFT 14
+
+/* MISC1 :: UV_RX_ERROR_STATUS :: RX_L1_UNDERRUN_ERROR [13:13] */
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK 0x00002000
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_ALIGN 0
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_BITS 1
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_SHIFT 13
+
+/* MISC1 :: UV_RX_ERROR_STATUS :: RX_L1_OVERRUN_ERROR [12:12] */
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_OVERRUN_ERROR_MASK 0x00001000
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_OVERRUN_ERROR_ALIGN 0
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_OVERRUN_ERROR_BITS 1
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_OVERRUN_ERROR_SHIFT 12
+
+/* MISC1 :: UV_RX_ERROR_STATUS :: RX_L0_UNDERRUN_ERROR [11:11] */
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK 0x00000800
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_ALIGN 0
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_BITS 1
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_SHIFT 11
+
+/* MISC1 :: UV_RX_ERROR_STATUS :: RX_L0_OVERRUN_ERROR [10:10] */
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_OVERRUN_ERROR_MASK 0x00000400
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_OVERRUN_ERROR_ALIGN 0
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_OVERRUN_ERROR_BITS 1
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_OVERRUN_ERROR_SHIFT 10
+
+/* MISC1 :: UV_RX_ERROR_STATUS :: RX_L1_DESC_TX_ABORT_ERRORS [09:09] */
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_DESC_TX_ABORT_ERRORS_MASK 0x00000200
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_DESC_TX_ABORT_ERRORS_ALIGN 0
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_DESC_TX_ABORT_ERRORS_BITS 1
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_DESC_TX_ABORT_ERRORS_SHIFT 9
+
+/* MISC1 :: UV_RX_ERROR_STATUS :: reserved1 [08:08] */
+#define MISC1_UV_RX_ERROR_STATUS_reserved1_MASK 0x00000100
+#define MISC1_UV_RX_ERROR_STATUS_reserved1_ALIGN 0
+#define MISC1_UV_RX_ERROR_STATUS_reserved1_BITS 1
+#define MISC1_UV_RX_ERROR_STATUS_reserved1_SHIFT 8
+
+/* MISC1 :: UV_RX_ERROR_STATUS :: RX_L0_DESC_TX_ABORT_ERRORS [07:07] */
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_DESC_TX_ABORT_ERRORS_MASK 0x00000080
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_DESC_TX_ABORT_ERRORS_ALIGN 0
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_DESC_TX_ABORT_ERRORS_BITS 1
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_DESC_TX_ABORT_ERRORS_SHIFT 7
+
+/* MISC1 :: UV_RX_ERROR_STATUS :: reserved2 [06:05] */
+#define MISC1_UV_RX_ERROR_STATUS_reserved2_MASK 0x00000060
+#define MISC1_UV_RX_ERROR_STATUS_reserved2_ALIGN 0
+#define MISC1_UV_RX_ERROR_STATUS_reserved2_BITS 2
+#define MISC1_UV_RX_ERROR_STATUS_reserved2_SHIFT 5
+
+/* MISC1 :: UV_RX_ERROR_STATUS :: RX_L1_FIFO_FULL_ERRORS [04:04] */
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK 0x00000010
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_ALIGN 0
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_BITS 1
+#define MISC1_UV_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_SHIFT 4
+
+/* MISC1 :: UV_RX_ERROR_STATUS :: reserved3 [03:02] */
+#define MISC1_UV_RX_ERROR_STATUS_reserved3_MASK 0x0000000c
+#define MISC1_UV_RX_ERROR_STATUS_reserved3_ALIGN 0
+#define MISC1_UV_RX_ERROR_STATUS_reserved3_BITS 2
+#define MISC1_UV_RX_ERROR_STATUS_reserved3_SHIFT 2
+
+/* MISC1 :: UV_RX_ERROR_STATUS :: RX_L0_FIFO_FULL_ERRORS [01:01] */
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK 0x00000002
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_ALIGN 0
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_BITS 1
+#define MISC1_UV_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_SHIFT 1
+
+/* MISC1 :: UV_RX_ERROR_STATUS :: reserved4 [00:00] */
+#define MISC1_UV_RX_ERROR_STATUS_reserved4_MASK 0x00000001
+#define MISC1_UV_RX_ERROR_STATUS_reserved4_ALIGN 0
+#define MISC1_UV_RX_ERROR_STATUS_reserved4_BITS 1
+#define MISC1_UV_RX_ERROR_STATUS_reserved4_SHIFT 0
+
+/****************************************************************************
+ * Datatype Definitions.
+ ***************************************************************************/
+#endif /* #ifndef MACFILE_H__ */
+
+/* End of File */
+
diff --git a/drivers/staging/crystalhd/crystalhd_cmds.c b/drivers/staging/crystalhd/crystalhd_cmds.c
new file mode 100644
index 000000000000..26145a8d0f78
--- /dev/null
+++ b/drivers/staging/crystalhd/crystalhd_cmds.c
@@ -0,0 +1,1058 @@
+/***************************************************************************
+ * Copyright (c) 2005-2009, Broadcom Corporation.
+ *
+ * Name: crystalhd_cmds . c
+ *
+ * Description:
+ * BCM70010 Linux driver user command interfaces.
+ *
+ * HISTORY:
+ *
+ **********************************************************************
+ * This file is part of the crystalhd device driver.
+ *
+ * This driver 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.
+ *
+ * This driver 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 driver. If not, see <http://www.gnu.org/licenses/>.
+ **********************************************************************/
+
+#include "crystalhd_cmds.h"
+#include "crystalhd_hw.h"
+
+static struct crystalhd_user *bc_cproc_get_uid(struct crystalhd_cmd *ctx)
+{
+ struct crystalhd_user *user = NULL;
+ int i;
+
+ for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
+ if (!ctx->user[i].in_use) {
+ user = &ctx->user[i];
+ break;
+ }
+ }
+
+ return user;
+}
+
+static int bc_cproc_get_user_count(struct crystalhd_cmd *ctx)
+{
+ int i, count = 0;
+
+ for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
+ if (ctx->user[i].in_use)
+ count++;
+ }
+
+ return count;
+}
+
+static void bc_cproc_mark_pwr_state(struct crystalhd_cmd *ctx)
+{
+ int i;
+
+ for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
+ if (!ctx->user[i].in_use)
+ continue;
+ if (ctx->user[i].mode == DTS_DIAG_MODE ||
+ ctx->user[i].mode == DTS_PLAYBACK_MODE) {
+ ctx->pwr_state_change = 1;
+ break;
+ }
+ }
+}
+
+static BC_STATUS bc_cproc_notify_mode(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ int rc = 0, i = 0;
+
+ if (!ctx || !idata) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ if (ctx->user[idata->u_id].mode != DTS_MODE_INV) {
+ BCMLOG_ERR("Close the handle first..\n");
+ return BC_STS_ERR_USAGE;
+ }
+ if (idata->udata.u.NotifyMode.Mode == DTS_MONITOR_MODE) {
+ ctx->user[idata->u_id].mode = idata->udata.u.NotifyMode.Mode;
+ return BC_STS_SUCCESS;
+ }
+ if (ctx->state != BC_LINK_INVALID) {
+ BCMLOG_ERR("Link invalid state %d \n", ctx->state);
+ return BC_STS_ERR_USAGE;
+ }
+ /* Check for duplicate playback sessions..*/
+ for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
+ if (ctx->user[i].mode == DTS_DIAG_MODE ||
+ ctx->user[i].mode == DTS_PLAYBACK_MODE) {
+ BCMLOG_ERR("multiple playback sessions are not "
+ "supported..\n");
+ return BC_STS_ERR_USAGE;
+ }
+ }
+ ctx->cin_wait_exit = 0;
+ ctx->user[idata->u_id].mode = idata->udata.u.NotifyMode.Mode;
+ /* Setup mmap pool for uaddr sgl mapping..*/
+ rc = crystalhd_create_dio_pool(ctx->adp, BC_LINK_MAX_SGLS);
+ if (rc)
+ return BC_STS_ERROR;
+
+ /* Setup Hardware DMA rings */
+ return crystalhd_hw_setup_dma_rings(&ctx->hw_ctx);
+}
+
+static BC_STATUS bc_cproc_get_version(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+
+ if (!ctx || !idata) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+ idata->udata.u.VerInfo.DriverMajor = crystalhd_kmod_major;
+ idata->udata.u.VerInfo.DriverMinor = crystalhd_kmod_minor;
+ idata->udata.u.VerInfo.DriverRevision = crystalhd_kmod_rev;
+ return BC_STS_SUCCESS;
+}
+
+
+static BC_STATUS bc_cproc_get_hwtype(struct crystalhd_cmd *ctx, crystalhd_ioctl_data *idata)
+{
+ if (!ctx || !idata) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ crystalhd_pci_cfg_rd(ctx->adp, 0, 2,
+ (uint32_t *)&idata->udata.u.hwType.PciVenId);
+ crystalhd_pci_cfg_rd(ctx->adp, 2, 2,
+ (uint32_t *)&idata->udata.u.hwType.PciDevId);
+ crystalhd_pci_cfg_rd(ctx->adp, 8, 1,
+ (uint32_t *)&idata->udata.u.hwType.HwRev);
+
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS bc_cproc_reg_rd(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ if (!ctx || !idata)
+ return BC_STS_INV_ARG;
+ idata->udata.u.regAcc.Value = bc_dec_reg_rd(ctx->adp,
+ idata->udata.u.regAcc.Offset);
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS bc_cproc_reg_wr(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ if (!ctx || !idata)
+ return BC_STS_INV_ARG;
+
+ bc_dec_reg_wr(ctx->adp, idata->udata.u.regAcc.Offset,
+ idata->udata.u.regAcc.Value);
+
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS bc_cproc_link_reg_rd(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ if (!ctx || !idata)
+ return BC_STS_INV_ARG;
+
+ idata->udata.u.regAcc.Value = crystalhd_reg_rd(ctx->adp,
+ idata->udata.u.regAcc.Offset);
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS bc_cproc_link_reg_wr(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ if (!ctx || !idata)
+ return BC_STS_INV_ARG;
+
+ crystalhd_reg_wr(ctx->adp, idata->udata.u.regAcc.Offset,
+ idata->udata.u.regAcc.Value);
+
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS bc_cproc_mem_rd(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ if (!ctx || !idata || !idata->add_cdata)
+ return BC_STS_INV_ARG;
+
+ if (idata->udata.u.devMem.NumDwords > (idata->add_cdata_sz / 4)) {
+ BCMLOG_ERR("insufficient buffer\n");
+ return BC_STS_INV_ARG;
+ }
+ sts = crystalhd_mem_rd(ctx->adp, idata->udata.u.devMem.StartOff,
+ idata->udata.u.devMem.NumDwords,
+ (uint32_t *)idata->add_cdata);
+ return sts;
+
+}
+
+static BC_STATUS bc_cproc_mem_wr(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ if (!ctx || !idata || !idata->add_cdata)
+ return BC_STS_INV_ARG;
+
+ if (idata->udata.u.devMem.NumDwords > (idata->add_cdata_sz / 4)) {
+ BCMLOG_ERR("insufficient buffer\n");
+ return BC_STS_INV_ARG;
+ }
+
+ sts = crystalhd_mem_wr(ctx->adp, idata->udata.u.devMem.StartOff,
+ idata->udata.u.devMem.NumDwords,
+ (uint32_t *)idata->add_cdata);
+ return sts;
+}
+
+static BC_STATUS bc_cproc_cfg_rd(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ uint32_t ix, cnt, off, len;
+ BC_STATUS sts = BC_STS_SUCCESS;
+ uint32_t *temp;
+
+ if (!ctx || !idata)
+ return BC_STS_INV_ARG;
+
+ temp = (uint32_t *) idata->udata.u.pciCfg.pci_cfg_space;
+ off = idata->udata.u.pciCfg.Offset;
+ len = idata->udata.u.pciCfg.Size;
+
+ if (len <= 4)
+ return crystalhd_pci_cfg_rd(ctx->adp, off, len, temp);
+
+ /* Truncate to dword alignment..*/
+ len = 4;
+ cnt = idata->udata.u.pciCfg.Size / len;
+ for (ix = 0; ix < cnt; ix++) {
+ sts = crystalhd_pci_cfg_rd(ctx->adp, off, len, &temp[ix]);
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG_ERR("config read : %d\n", sts);
+ return sts;
+ }
+ off += len;
+ }
+
+ return sts;
+}
+
+static BC_STATUS bc_cproc_cfg_wr(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ uint32_t ix, cnt, off, len;
+ BC_STATUS sts = BC_STS_SUCCESS;
+ uint32_t *temp;
+
+ if (!ctx || !idata)
+ return BC_STS_INV_ARG;
+
+ temp = (uint32_t *) idata->udata.u.pciCfg.pci_cfg_space;
+ off = idata->udata.u.pciCfg.Offset;
+ len = idata->udata.u.pciCfg.Size;
+
+ if (len <= 4)
+ return crystalhd_pci_cfg_wr(ctx->adp, off, len, temp[0]);
+
+ /* Truncate to dword alignment..*/
+ len = 4;
+ cnt = idata->udata.u.pciCfg.Size / len;
+ for (ix = 0; ix < cnt; ix++) {
+ sts = crystalhd_pci_cfg_wr(ctx->adp, off, len, temp[ix]);
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG_ERR("config write : %d\n", sts);
+ return sts;
+ }
+ off += len;
+ }
+
+ return sts;
+}
+
+static BC_STATUS bc_cproc_download_fw(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ if (!ctx || !idata || !idata->add_cdata || !idata->add_cdata_sz) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ if (ctx->state != BC_LINK_INVALID) {
+ BCMLOG_ERR("Link invalid state %d \n", ctx->state);
+ return BC_STS_ERR_USAGE;
+ }
+
+ sts = crystalhd_download_fw(ctx->adp, (uint8_t *)idata->add_cdata,
+ idata->add_cdata_sz);
+
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG_ERR("Firmware Download Failure!! - %d\n", sts);
+ } else
+ ctx->state |= BC_LINK_INIT;
+
+ return sts;
+}
+
+/*
+ * We use the FW_CMD interface to sync up playback state with application
+ * and firmware. This function will perform the required pre and post
+ * processing of the Firmware commands.
+ *
+ * Pause -
+ * Disable capture after decoder pause.
+ * Resume -
+ * First enable capture and issue decoder resume command.
+ * Flush -
+ * Abort pending input transfers and issue decoder flush command.
+ *
+ */
+static BC_STATUS bc_cproc_do_fw_cmd(struct crystalhd_cmd *ctx, crystalhd_ioctl_data *idata)
+{
+ BC_STATUS sts;
+ uint32_t *cmd;
+
+ if (!(ctx->state & BC_LINK_INIT)) {
+ BCMLOG_ERR("Link invalid state %d \n", ctx->state);
+ return BC_STS_ERR_USAGE;
+ }
+
+ cmd = idata->udata.u.fwCmd.cmd;
+
+ /* Pre-Process */
+ if (cmd[0] == eCMD_C011_DEC_CHAN_PAUSE) {
+ if (!cmd[3]) {
+ ctx->state &= ~BC_LINK_PAUSED;
+ crystalhd_hw_unpause(&ctx->hw_ctx);
+ }
+ } else if (cmd[0] == eCMD_C011_DEC_CHAN_FLUSH) {
+ BCMLOG(BCMLOG_INFO, "Flush issued\n");
+ if (cmd[3])
+ ctx->cin_wait_exit = 1;
+ }
+
+ sts = crystalhd_do_fw_cmd(&ctx->hw_ctx, &idata->udata.u.fwCmd);
+
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG(BCMLOG_INFO, "fw cmd %x failed\n", cmd[0]);
+ return sts;
+ }
+
+ /* Post-Process */
+ if (cmd[0] == eCMD_C011_DEC_CHAN_PAUSE) {
+ if (cmd[3]) {
+ ctx->state |= BC_LINK_PAUSED;
+ crystalhd_hw_pause(&ctx->hw_ctx);
+ }
+ }
+
+ return sts;
+}
+
+static void bc_proc_in_completion(crystalhd_dio_req *dio_hnd,
+ wait_queue_head_t *event, BC_STATUS sts)
+{
+ if (!dio_hnd || !event) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return;
+ }
+ if (sts == BC_STS_IO_USER_ABORT)
+ return;
+
+ dio_hnd->uinfo.comp_sts = sts;
+ dio_hnd->uinfo.ev_sts = 1;
+ crystalhd_set_event(event);
+}
+
+static BC_STATUS bc_cproc_codein_sleep(struct crystalhd_cmd *ctx)
+{
+ wait_queue_head_t sleep_ev;
+ int rc = 0;
+
+ if (ctx->state & BC_LINK_SUSPEND)
+ return BC_STS_IO_USER_ABORT;
+
+ if (ctx->cin_wait_exit) {
+ ctx->cin_wait_exit = 0;
+ return BC_STS_CMD_CANCELLED;
+ }
+ crystalhd_create_event(&sleep_ev);
+ crystalhd_wait_on_event(&sleep_ev, 0, 100, rc, 0);
+ if (rc == -EINTR)
+ return BC_STS_IO_USER_ABORT;
+
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS bc_cproc_hw_txdma(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata,
+ crystalhd_dio_req *dio)
+{
+ uint32_t tx_listid = 0;
+ BC_STATUS sts = BC_STS_SUCCESS;
+ wait_queue_head_t event;
+ int rc = 0;
+
+ if (!ctx || !idata || !dio) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ crystalhd_create_event(&event);
+
+ ctx->tx_list_id = 0;
+ /* msleep_interruptible(2000); */
+ sts = crystalhd_hw_post_tx(&ctx->hw_ctx, dio, bc_proc_in_completion,
+ &event, &tx_listid,
+ idata->udata.u.ProcInput.Encrypted);
+
+ while (sts == BC_STS_BUSY) {
+ sts = bc_cproc_codein_sleep(ctx);
+ if (sts != BC_STS_SUCCESS)
+ break;
+ sts = crystalhd_hw_post_tx(&ctx->hw_ctx, dio,
+ bc_proc_in_completion,
+ &event, &tx_listid,
+ idata->udata.u.ProcInput.Encrypted);
+ }
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG(BCMLOG_DBG, "_hw_txdma returning sts:%d\n", sts);
+ return sts;
+ }
+ if (ctx->cin_wait_exit)
+ ctx->cin_wait_exit = 0;
+
+ ctx->tx_list_id = tx_listid;
+
+ /* _post() succeeded.. wait for the completion. */
+ crystalhd_wait_on_event(&event, (dio->uinfo.ev_sts), 3000, rc, 0);
+ ctx->tx_list_id = 0;
+ if (!rc) {
+ return dio->uinfo.comp_sts;
+ } else if (rc == -EBUSY) {
+ BCMLOG(BCMLOG_DBG, "_tx_post() T/O \n");
+ sts = BC_STS_TIMEOUT;
+ } else if (rc == -EINTR) {
+ BCMLOG(BCMLOG_DBG, "Tx Wait Signal int.\n");
+ sts = BC_STS_IO_USER_ABORT;
+ } else {
+ sts = BC_STS_IO_ERROR;
+ }
+
+ /* We are cancelling the IO from the same context as the _post().
+ * so no need to wait on the event again.. the return itself
+ * ensures the release of our resources.
+ */
+ crystalhd_hw_cancel_tx(&ctx->hw_ctx, tx_listid);
+
+ return sts;
+}
+
+/* Helper function to check on user buffers */
+static BC_STATUS bc_cproc_check_inbuffs(bool pin, void *ubuff, uint32_t ub_sz,
+ uint32_t uv_off, bool en_422)
+{
+ if (!ubuff || !ub_sz) {
+ BCMLOG_ERR("%s->Invalid Arg %p %x\n",
+ ((pin) ? "TX" : "RX"), ubuff, ub_sz);
+ return BC_STS_INV_ARG;
+ }
+
+ /* Check for alignment */
+ if (((uintptr_t)ubuff) & 0x03) {
+ BCMLOG_ERR("%s-->Un-aligned address not implemented yet.. %p \n",
+ ((pin) ? "TX" : "RX"), ubuff);
+ return BC_STS_NOT_IMPL;
+ }
+ if (pin)
+ return BC_STS_SUCCESS;
+
+ if (!en_422 && !uv_off) {
+ BCMLOG_ERR("Need UV offset for 420 mode.\n");
+ return BC_STS_INV_ARG;
+ }
+
+ if (en_422 && uv_off) {
+ BCMLOG_ERR("UV offset in 422 mode ??\n");
+ return BC_STS_INV_ARG;
+ }
+
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS bc_cproc_proc_input(struct crystalhd_cmd *ctx, crystalhd_ioctl_data *idata)
+{
+ void *ubuff;
+ uint32_t ub_sz;
+ crystalhd_dio_req *dio_hnd = NULL;
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ if (!ctx || !idata) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ ubuff = idata->udata.u.ProcInput.pDmaBuff;
+ ub_sz = idata->udata.u.ProcInput.BuffSz;
+
+ sts = bc_cproc_check_inbuffs(1, ubuff, ub_sz, 0, 0);
+ if (sts != BC_STS_SUCCESS)
+ return sts;
+
+ sts = crystalhd_map_dio(ctx->adp, ubuff, ub_sz, 0, 0, 1, &dio_hnd);
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG_ERR("dio map - %d \n", sts);
+ return sts;
+ }
+
+ if (!dio_hnd)
+ return BC_STS_ERROR;
+
+ sts = bc_cproc_hw_txdma(ctx, idata, dio_hnd);
+
+ crystalhd_unmap_dio(ctx->adp, dio_hnd);
+
+ return sts;
+}
+
+static BC_STATUS bc_cproc_add_cap_buff(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ void *ubuff;
+ uint32_t ub_sz, uv_off;
+ bool en_422;
+ crystalhd_dio_req *dio_hnd = NULL;
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ if (!ctx || !idata) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ ubuff = idata->udata.u.RxBuffs.YuvBuff;
+ ub_sz = idata->udata.u.RxBuffs.YuvBuffSz;
+ uv_off = idata->udata.u.RxBuffs.UVbuffOffset;
+ en_422 = idata->udata.u.RxBuffs.b422Mode;
+
+ sts = bc_cproc_check_inbuffs(0, ubuff, ub_sz, uv_off, en_422);
+ if (sts != BC_STS_SUCCESS)
+ return sts;
+
+ sts = crystalhd_map_dio(ctx->adp, ubuff, ub_sz, uv_off,
+ en_422, 0, &dio_hnd);
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG_ERR("dio map - %d \n", sts);
+ return sts;
+ }
+
+ if (!dio_hnd)
+ return BC_STS_ERROR;
+
+ sts = crystalhd_hw_add_cap_buffer(&ctx->hw_ctx, dio_hnd, (ctx->state == BC_LINK_READY));
+ if ((sts != BC_STS_SUCCESS) && (sts != BC_STS_BUSY)) {
+ crystalhd_unmap_dio(ctx->adp, dio_hnd);
+ return sts;
+ }
+
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS bc_cproc_fmt_change(struct crystalhd_cmd *ctx,
+ crystalhd_dio_req *dio)
+{
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ sts = crystalhd_hw_add_cap_buffer(&ctx->hw_ctx, dio, 0);
+ if (sts != BC_STS_SUCCESS)
+ return sts;
+
+ ctx->state |= BC_LINK_FMT_CHG;
+ if (ctx->state == BC_LINK_READY)
+ sts = crystalhd_hw_start_capture(&ctx->hw_ctx);
+
+ return sts;
+}
+
+static BC_STATUS bc_cproc_fetch_frame(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ crystalhd_dio_req *dio = NULL;
+ BC_STATUS sts = BC_STS_SUCCESS;
+ BC_DEC_OUT_BUFF *frame;
+
+ if (!ctx || !idata) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ if (!(ctx->state & BC_LINK_CAP_EN)) {
+ BCMLOG(BCMLOG_DBG, "Capture not enabled..%x\n", ctx->state);
+ return BC_STS_ERR_USAGE;
+ }
+
+ frame = &idata->udata.u.DecOutData;
+
+ sts = crystalhd_hw_get_cap_buffer(&ctx->hw_ctx, &frame->PibInfo, &dio);
+ if (sts != BC_STS_SUCCESS)
+ return (ctx->state & BC_LINK_SUSPEND) ? BC_STS_IO_USER_ABORT : sts;
+
+ frame->Flags = dio->uinfo.comp_flags;
+
+ if (frame->Flags & COMP_FLAG_FMT_CHANGE)
+ return bc_cproc_fmt_change(ctx, dio);
+
+ frame->OutPutBuffs.YuvBuff = dio->uinfo.xfr_buff;
+ frame->OutPutBuffs.YuvBuffSz = dio->uinfo.xfr_len;
+ frame->OutPutBuffs.UVbuffOffset = dio->uinfo.uv_offset;
+ frame->OutPutBuffs.b422Mode = dio->uinfo.b422mode;
+
+ frame->OutPutBuffs.YBuffDoneSz = dio->uinfo.y_done_sz;
+ frame->OutPutBuffs.UVBuffDoneSz = dio->uinfo.uv_done_sz;
+
+ crystalhd_unmap_dio(ctx->adp, dio);
+
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS bc_cproc_start_capture(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ ctx->state |= BC_LINK_CAP_EN;
+ if (ctx->state == BC_LINK_READY)
+ return crystalhd_hw_start_capture(&ctx->hw_ctx);
+
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS bc_cproc_flush_cap_buffs(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ crystalhd_dio_req *dio = NULL;
+ BC_STATUS sts = BC_STS_SUCCESS;
+ BC_DEC_OUT_BUFF *frame;
+ uint32_t count;
+
+ if (!ctx || !idata) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ if (!(ctx->state & BC_LINK_CAP_EN))
+ return BC_STS_ERR_USAGE;
+
+ /* We should ack flush even when we are in paused/suspend state */
+ if (!(ctx->state & BC_LINK_READY))
+ return crystalhd_hw_stop_capture(&ctx->hw_ctx);
+
+ ctx->state &= ~(BC_LINK_CAP_EN|BC_LINK_FMT_CHG);
+
+ frame = &idata->udata.u.DecOutData;
+ for (count = 0; count < BC_RX_LIST_CNT; count++) {
+
+ sts = crystalhd_hw_get_cap_buffer(&ctx->hw_ctx, &frame->PibInfo, &dio);
+ if (sts != BC_STS_SUCCESS)
+ break;
+
+ crystalhd_unmap_dio(ctx->adp, dio);
+ }
+
+ return crystalhd_hw_stop_capture(&ctx->hw_ctx);
+}
+
+static BC_STATUS bc_cproc_get_stats(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ BC_DTS_STATS *stats;
+ struct crystalhd_hw_stats hw_stats;
+
+ if (!ctx || !idata) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ crystalhd_hw_stats(&ctx->hw_ctx, &hw_stats);
+
+ stats = &idata->udata.u.drvStat;
+ stats->drvRLL = hw_stats.rdyq_count;
+ stats->drvFLL = hw_stats.freeq_count;
+ stats->DrvTotalFrmDropped = hw_stats.rx_errors;
+ stats->DrvTotalHWErrs = hw_stats.rx_errors + hw_stats.tx_errors;
+ stats->intCount = hw_stats.num_interrupts;
+ stats->DrvIgnIntrCnt = hw_stats.num_interrupts -
+ hw_stats.dev_interrupts;
+ stats->TxFifoBsyCnt = hw_stats.cin_busy;
+ stats->pauseCount = hw_stats.pause_cnt;
+
+ if (ctx->pwr_state_change)
+ stats->pwr_state_change = 1;
+ if (ctx->state & BC_LINK_PAUSED)
+ stats->DrvPauseTime = 1;
+
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS bc_cproc_reset_stats(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ crystalhd_hw_stats(&ctx->hw_ctx, NULL);
+
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS bc_cproc_chg_clk(struct crystalhd_cmd *ctx,
+ crystalhd_ioctl_data *idata)
+{
+ BC_CLOCK *clock;
+ uint32_t oldClk;
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ if (!ctx || !idata) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ clock = &idata->udata.u.clockValue;
+ oldClk = ctx->hw_ctx.core_clock_mhz;
+ ctx->hw_ctx.core_clock_mhz = clock->clk;
+
+ if (ctx->state & BC_LINK_READY) {
+ sts = crystalhd_hw_set_core_clock(&ctx->hw_ctx);
+ if (sts == BC_STS_CLK_NOCHG)
+ ctx->hw_ctx.core_clock_mhz = oldClk;
+ }
+
+ clock->clk = ctx->hw_ctx.core_clock_mhz;
+
+ return sts;
+}
+
+/*=============== Cmd Proc Table.. ======================================*/
+static const crystalhd_cmd_tbl_t g_crystalhd_cproc_tbl[] = {
+ { BCM_IOC_GET_VERSION, bc_cproc_get_version, 0},
+ { BCM_IOC_GET_HWTYPE, bc_cproc_get_hwtype, 0},
+ { BCM_IOC_REG_RD, bc_cproc_reg_rd, 0},
+ { BCM_IOC_REG_WR, bc_cproc_reg_wr, 0},
+ { BCM_IOC_FPGA_RD, bc_cproc_link_reg_rd, 0},
+ { BCM_IOC_FPGA_WR, bc_cproc_link_reg_wr, 0},
+ { BCM_IOC_MEM_RD, bc_cproc_mem_rd, 0},
+ { BCM_IOC_MEM_WR, bc_cproc_mem_wr, 0},
+ { BCM_IOC_RD_PCI_CFG, bc_cproc_cfg_rd, 0},
+ { BCM_IOC_WR_PCI_CFG, bc_cproc_cfg_wr, 1},
+ { BCM_IOC_FW_DOWNLOAD, bc_cproc_download_fw, 1},
+ { BCM_IOC_FW_CMD, bc_cproc_do_fw_cmd, 1},
+ { BCM_IOC_PROC_INPUT, bc_cproc_proc_input, 1},
+ { BCM_IOC_ADD_RXBUFFS, bc_cproc_add_cap_buff, 1},
+ { BCM_IOC_FETCH_RXBUFF, bc_cproc_fetch_frame, 1},
+ { BCM_IOC_START_RX_CAP, bc_cproc_start_capture, 1},
+ { BCM_IOC_FLUSH_RX_CAP, bc_cproc_flush_cap_buffs, 1},
+ { BCM_IOC_GET_DRV_STAT, bc_cproc_get_stats, 0},
+ { BCM_IOC_RST_DRV_STAT, bc_cproc_reset_stats, 0},
+ { BCM_IOC_NOTIFY_MODE, bc_cproc_notify_mode, 0},
+ { BCM_IOC_CHG_CLK, bc_cproc_chg_clk, 0},
+ { BCM_IOC_END, NULL},
+};
+
+/*=============== Cmd Proc Functions.. ===================================*/
+
+/**
+ * crystalhd_suspend - Power management suspend request.
+ * @ctx: Command layer context.
+ * @idata: Iodata - required for internal use.
+ *
+ * Return:
+ * status
+ *
+ * 1. Set the state to Suspend.
+ * 2. Flush the Rx Buffers it will unmap all the buffers and
+ * stop the RxDMA engine.
+ * 3. Cancel The TX Io and Stop Dma Engine.
+ * 4. Put the DDR in to deep sleep.
+ * 5. Stop the hardware putting it in to Reset State.
+ *
+ * Current gstreamer frame work does not provide any power management
+ * related notification to user mode decoder plug-in. As a work-around
+ * we pass on the power mangement notification to our plug-in by completing
+ * all outstanding requests with BC_STS_IO_USER_ABORT return code.
+ */
+BC_STATUS crystalhd_suspend(struct crystalhd_cmd *ctx, crystalhd_ioctl_data *idata)
+{
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ if (!ctx || !idata) {
+ BCMLOG_ERR("Invalid Parameters\n");
+ return BC_STS_ERROR;
+ }
+
+ if (ctx->state & BC_LINK_SUSPEND)
+ return BC_STS_SUCCESS;
+
+ if (ctx->state == BC_LINK_INVALID) {
+ BCMLOG(BCMLOG_DBG, "Nothing To Do Suspend Success\n");
+ return BC_STS_SUCCESS;
+ }
+
+ ctx->state |= BC_LINK_SUSPEND;
+
+ bc_cproc_mark_pwr_state(ctx);
+
+ if (ctx->state & BC_LINK_CAP_EN) {
+ sts = bc_cproc_flush_cap_buffs(ctx, idata);
+ if (sts != BC_STS_SUCCESS)
+ return sts;
+ }
+
+ if (ctx->tx_list_id) {
+ sts = crystalhd_hw_cancel_tx(&ctx->hw_ctx, ctx->tx_list_id);
+ if (sts != BC_STS_SUCCESS)
+ return sts;
+ }
+
+ sts = crystalhd_hw_suspend(&ctx->hw_ctx);
+ if (sts != BC_STS_SUCCESS)
+ return sts;
+
+ BCMLOG(BCMLOG_DBG, "BCM70012 suspend success\n");
+
+ return BC_STS_SUCCESS;
+}
+
+/**
+ * crystalhd_resume - Resume frame capture.
+ * @ctx: Command layer contextx.
+ *
+ * Return:
+ * status
+ *
+ *
+ * Resume frame capture.
+ *
+ * PM_Resume can't resume the playback state back to pre-suspend state
+ * because we don't keep video clip related information within driver.
+ * To get back to the pre-suspend state App will re-open the device and
+ * start a new playback session from the pre-suspend clip position.
+ *
+ */
+BC_STATUS crystalhd_resume(struct crystalhd_cmd *ctx)
+{
+ BCMLOG(BCMLOG_DBG, "crystalhd_resume Success %x\n", ctx->state);
+
+ bc_cproc_mark_pwr_state(ctx);
+
+ return BC_STS_SUCCESS;
+}
+
+/**
+ * crystalhd_user_open - Create application handle.
+ * @ctx: Command layer contextx.
+ * @user_ctx: User ID context.
+ *
+ * Return:
+ * status
+ *
+ * Creates an application specific UID and allocates
+ * application specific resources. HW layer initialization
+ * is done for the first open request.
+ */
+BC_STATUS crystalhd_user_open(struct crystalhd_cmd *ctx,
+ struct crystalhd_user **user_ctx)
+{
+ struct crystalhd_user *uc;
+
+ if (!ctx || !user_ctx) {
+ BCMLOG_ERR("Invalid arg..\n");
+ return BC_STS_INV_ARG;
+ }
+
+ uc = bc_cproc_get_uid(ctx);
+ if (!uc) {
+ BCMLOG(BCMLOG_INFO, "No free user context...\n");
+ return BC_STS_BUSY;
+ }
+
+ BCMLOG(BCMLOG_INFO, "Opening new user[%x] handle\n", uc->uid);
+
+ crystalhd_hw_open(&ctx->hw_ctx, ctx->adp);
+
+ uc->in_use = 1;
+
+ *user_ctx = uc;
+
+ return BC_STS_SUCCESS;
+}
+
+/**
+ * crystalhd_user_close - Close application handle.
+ * @ctx: Command layer contextx.
+ * @uc: User ID context.
+ *
+ * Return:
+ * status
+ *
+ * Closer aplication handle and release app specific
+ * resources.
+ */
+BC_STATUS crystalhd_user_close(struct crystalhd_cmd *ctx, struct crystalhd_user *uc)
+{
+ uint32_t mode = uc->mode;
+
+ ctx->user[uc->uid].mode = DTS_MODE_INV;
+ ctx->user[uc->uid].in_use = 0;
+ ctx->cin_wait_exit = 1;
+ ctx->pwr_state_change = 0;
+
+ BCMLOG(BCMLOG_INFO, "Closing user[%x] handle\n", uc->uid);
+
+ if ((mode == DTS_DIAG_MODE) || (mode == DTS_PLAYBACK_MODE)) {
+ crystalhd_hw_free_dma_rings(&ctx->hw_ctx);
+ crystalhd_destroy_dio_pool(ctx->adp);
+ } else if (bc_cproc_get_user_count(ctx)) {
+ return BC_STS_SUCCESS;
+ }
+
+ crystalhd_hw_close(&ctx->hw_ctx);
+
+ ctx->state = BC_LINK_INVALID;
+
+ return BC_STS_SUCCESS;
+}
+
+/**
+ * crystalhd_setup_cmd_context - Setup Command layer resources.
+ * @ctx: Command layer contextx.
+ * @adp: Adapter context
+ *
+ * Return:
+ * status
+ *
+ * Called at the time of driver load.
+ */
+BC_STATUS __devinit crystalhd_setup_cmd_context(struct crystalhd_cmd *ctx,
+ struct crystalhd_adp *adp)
+{
+ int i = 0;
+
+ if (!ctx || !adp) {
+ BCMLOG_ERR("Invalid arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ if (ctx->adp)
+ BCMLOG(BCMLOG_DBG, "Resetting Cmd context delete missing..\n");
+
+ ctx->adp = adp;
+ for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
+ ctx->user[i].uid = i;
+ ctx->user[i].in_use = 0;
+ ctx->user[i].mode = DTS_MODE_INV;
+ }
+
+ /*Open and Close the Hardware to put it in to sleep state*/
+ crystalhd_hw_open(&ctx->hw_ctx, ctx->adp);
+ crystalhd_hw_close(&ctx->hw_ctx);
+ return BC_STS_SUCCESS;
+}
+
+/**
+ * crystalhd_delete_cmd_context - Release Command layer resources.
+ * @ctx: Command layer contextx.
+ *
+ * Return:
+ * status
+ *
+ * Called at the time of driver un-load.
+ */
+BC_STATUS __devexit crystalhd_delete_cmd_context(struct crystalhd_cmd *ctx)
+{
+ BCMLOG(BCMLOG_DBG, "Deleting Command context..\n");
+
+ ctx->adp = NULL;
+
+ return BC_STS_SUCCESS;
+}
+
+/**
+ * crystalhd_get_cmd_proc - Cproc table lookup.
+ * @ctx: Command layer contextx.
+ * @cmd: IOCTL command code.
+ * @uc: User ID context.
+ *
+ * Return:
+ * command proc function pointer
+ *
+ * This function checks the process context, application's
+ * mode of operation and returns the function pointer
+ * from the cproc table.
+ */
+crystalhd_cmd_proc crystalhd_get_cmd_proc(struct crystalhd_cmd *ctx, uint32_t cmd,
+ struct crystalhd_user *uc)
+{
+ crystalhd_cmd_proc cproc = NULL;
+ unsigned int i, tbl_sz;
+
+ if (!ctx) {
+ BCMLOG_ERR("Invalid arg.. Cmd[%d]\n", cmd);
+ return NULL;
+ }
+
+ if ((cmd != BCM_IOC_GET_DRV_STAT) && (ctx->state & BC_LINK_SUSPEND)) {
+ BCMLOG_ERR("Invalid State [suspend Set].. Cmd[%d]\n", cmd);
+ return NULL;
+ }
+
+ tbl_sz = sizeof(g_crystalhd_cproc_tbl) / sizeof(crystalhd_cmd_tbl_t);
+ for (i = 0; i < tbl_sz; i++) {
+ if (g_crystalhd_cproc_tbl[i].cmd_id == cmd) {
+ if ((uc->mode == DTS_MONITOR_MODE) &&
+ (g_crystalhd_cproc_tbl[i].block_mon)) {
+ BCMLOG(BCMLOG_INFO, "Blocking cmd %d \n", cmd);
+ break;
+ }
+ cproc = g_crystalhd_cproc_tbl[i].cmd_proc;
+ break;
+ }
+ }
+
+ return cproc;
+}
+
+/**
+ * crystalhd_cmd_interrupt - ISR entry point
+ * @ctx: Command layer contextx.
+ *
+ * Return:
+ * TRUE: If interrupt from bcm70012 device.
+ *
+ *
+ * ISR entry point from OS layer.
+ */
+bool crystalhd_cmd_interrupt(struct crystalhd_cmd *ctx)
+{
+ if (!ctx) {
+ BCMLOG_ERR("Invalid arg..\n");
+ return 0;
+ }
+
+ return crystalhd_hw_interrupt(ctx->adp, &ctx->hw_ctx);
+}
diff --git a/drivers/staging/crystalhd/crystalhd_cmds.h b/drivers/staging/crystalhd/crystalhd_cmds.h
new file mode 100644
index 000000000000..6b290aed8e0b
--- /dev/null
+++ b/drivers/staging/crystalhd/crystalhd_cmds.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+ * Copyright (c) 2005-2009, Broadcom Corporation.
+ *
+ * Name: crystalhd_cmds . h
+ *
+ * Description:
+ * BCM70010 Linux driver user command interfaces.
+ *
+ * HISTORY:
+ *
+ **********************************************************************
+ * This file is part of the crystalhd device driver.
+ *
+ * This driver 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.
+ *
+ * This driver 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 driver. If not, see <http://www.gnu.org/licenses/>.
+ **********************************************************************/
+
+#ifndef _CRYSTALHD_CMDS_H_
+#define _CRYSTALHD_CMDS_H_
+
+/*
+ * NOTE:: This is the main interface file between the Linux layer
+ * and the harware layer. This file will use the definitions
+ * from _dts_glob and dts_defs etc.. which are defined for
+ * windows.
+ */
+#include "crystalhd_misc.h"
+#include "crystalhd_hw.h"
+
+enum _crystalhd_state{
+ BC_LINK_INVALID = 0x00,
+ BC_LINK_INIT = 0x01,
+ BC_LINK_CAP_EN = 0x02,
+ BC_LINK_FMT_CHG = 0x04,
+ BC_LINK_SUSPEND = 0x10,
+ BC_LINK_PAUSED = 0x20,
+ BC_LINK_READY = (BC_LINK_INIT | BC_LINK_CAP_EN | BC_LINK_FMT_CHG),
+};
+
+struct crystalhd_user {
+ uint32_t uid;
+ uint32_t in_use;
+ uint32_t mode;
+};
+
+#define DTS_MODE_INV (-1)
+
+struct crystalhd_cmd {
+ uint32_t state;
+ struct crystalhd_adp *adp;
+ struct crystalhd_user user[BC_LINK_MAX_OPENS];
+
+ spinlock_t ctx_lock;
+ uint32_t tx_list_id;
+ uint32_t cin_wait_exit;
+ uint32_t pwr_state_change;
+ struct crystalhd_hw hw_ctx;
+};
+
+typedef BC_STATUS (*crystalhd_cmd_proc)(struct crystalhd_cmd *, crystalhd_ioctl_data *);
+
+typedef struct _crystalhd_cmd_tbl {
+ uint32_t cmd_id;
+ const crystalhd_cmd_proc cmd_proc;
+ uint32_t block_mon;
+} crystalhd_cmd_tbl_t;
+
+
+BC_STATUS crystalhd_suspend(struct crystalhd_cmd *ctx, crystalhd_ioctl_data *idata);
+BC_STATUS crystalhd_resume(struct crystalhd_cmd *ctx);
+crystalhd_cmd_proc crystalhd_get_cmd_proc(struct crystalhd_cmd *ctx, uint32_t cmd,
+ struct crystalhd_user *uc);
+BC_STATUS crystalhd_user_open(struct crystalhd_cmd *ctx, struct crystalhd_user **user_ctx);
+BC_STATUS crystalhd_user_close(struct crystalhd_cmd *ctx, struct crystalhd_user *uc);
+BC_STATUS crystalhd_setup_cmd_context(struct crystalhd_cmd *ctx, struct crystalhd_adp *adp);
+BC_STATUS crystalhd_delete_cmd_context(struct crystalhd_cmd *ctx);
+bool crystalhd_cmd_interrupt(struct crystalhd_cmd *ctx);
+
+#endif
diff --git a/drivers/staging/crystalhd/crystalhd_fw_if.h b/drivers/staging/crystalhd/crystalhd_fw_if.h
new file mode 100644
index 000000000000..261cd19a0ee7
--- /dev/null
+++ b/drivers/staging/crystalhd/crystalhd_fw_if.h
@@ -0,0 +1,369 @@
+/***************************************************************************
+ * Copyright (c) 2005-2009, Broadcom Corporation.
+ *
+ * Name: crystalhd_fw_if . h
+ *
+ * Description:
+ * BCM70012 Firmware interface definitions.
+ *
+ * HISTORY:
+ *
+ **********************************************************************
+ * This file is part of the crystalhd device driver.
+ *
+ * This driver 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.
+ *
+ * This driver 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 driver. If not, see <http://www.gnu.org/licenses/>.
+ **********************************************************************/
+
+#ifndef _CRYSTALHD_FW_IF_H_
+#define _CRYSTALHD_FW_IF_H_
+
+/* TBD: Pull in only required defs into this file.. */
+
+
+
+/* User Data Header */
+typedef struct user_data {
+ struct user_data *next;
+ uint32_t type;
+ uint32_t size;
+} UD_HDR;
+
+
+
+/*------------------------------------------------------*
+ * MPEG Extension to the PPB *
+ *------------------------------------------------------*/
+typedef struct {
+ uint32_t to_be_defined;
+ uint32_t valid;
+
+ /* Always valid, defaults to picture size if no
+ sequence display extension in the stream. */
+ uint32_t display_horizontal_size;
+ uint32_t display_vertical_size;
+
+ /* MPEG_VALID_PANSCAN
+ Offsets are a copy values from the MPEG stream. */
+ uint32_t offset_count;
+ int32_t horizontal_offset[3];
+ int32_t vertical_offset[3];
+
+ /* MPEG_VALID_USERDATA
+ User data is in the form of a linked list. */
+ int32_t userDataSize;
+ UD_HDR *userData;
+
+} PPB_MPEG;
+
+
+/*------------------------------------------------------*
+ * VC1 Extension to the PPB *
+ *------------------------------------------------------*/
+typedef struct {
+ uint32_t to_be_defined;
+ uint32_t valid;
+
+ /* Always valid, defaults to picture size if no
+ sequence display extension in the stream. */
+ uint32_t display_horizontal_size;
+ uint32_t display_vertical_size;
+
+ /* VC1 pan scan windows */
+ uint32_t num_panscan_windows;
+ int32_t ps_horiz_offset[4];
+ int32_t ps_vert_offset[4];
+ int32_t ps_width[4];
+ int32_t ps_height[4];
+
+ /* VC1_VALID_USERDATA
+ User data is in the form of a linked list. */
+ int32_t userDataSize;
+ UD_HDR *userData;
+
+} PPB_VC1;
+
+/*------------------------------------------------------*
+ * H.264 Extension to the PPB *
+ *------------------------------------------------------*/
+
+/**
+ * @brief Film grain SEI message.
+ *
+ * Content of the film grain SEI message.
+ */
+
+/* maximum number of model-values as for Thomson spec(standard says 5) */
+#define MAX_FGT_MODEL_VALUE (3)
+
+/* maximum number of intervals(as many as 256 intervals?) */
+#define MAX_FGT_VALUE_INTERVAL (256)
+
+typedef struct FGT_SEI {
+ struct FGT_SEI *next;
+ unsigned char model_values[3][MAX_FGT_VALUE_INTERVAL][MAX_FGT_MODEL_VALUE];
+ unsigned char upper_bound[3][MAX_FGT_VALUE_INTERVAL];
+ unsigned char lower_bound[3][MAX_FGT_VALUE_INTERVAL];
+
+ unsigned char cancel_flag; /* Cancel flag: 1 no film grain. */
+ unsigned char model_id; /* Model id. */
+
+ /* +unused SE based on Thomson spec */
+ unsigned char color_desc_flag; /* Separate color descrition flag. */
+ unsigned char bit_depth_luma; /* Bit depth luma minus 8. */
+ unsigned char bit_depth_chroma; /* Bit depth chroma minus 8. */
+ unsigned char full_range_flag; /* Full range flag. */
+ unsigned char color_primaries; /* Color primaries. */
+ unsigned char transfer_charact; /* Transfer characteristics. */
+ unsigned char matrix_coeff; /*< Matrix coefficients. */
+ /* -unused SE based on Thomson spec */
+
+ unsigned char blending_mode_id; /* Blending mode. */
+ unsigned char log2_scale_factor; /* Log2 scale factor (2-7). */
+ unsigned char comp_flag[3]; /* Components [0,2] parameters present flag. */
+ unsigned char num_intervals_minus1[3]; /* Number of intensity level intervals. */
+ unsigned char num_model_values[3]; /* Number of model values. */
+ uint16_t repetition_period; /* Repetition period (0-16384) */
+
+} FGT_SEI;
+
+typedef struct {
+ /* 'valid' specifies which fields (or sets of
+ * fields) below are valid. If the corresponding
+ * bit in 'valid' is NOT set then that field(s)
+ * is (are) not initialized. */
+ uint32_t valid;
+
+ int32_t poc_top; /* POC for Top Field/Frame */
+ int32_t poc_bottom; /* POC for Bottom Field */
+ uint32_t idr_pic_id;
+
+ /* H264_VALID_PANSCAN */
+ uint32_t pan_scan_count;
+ int32_t pan_scan_left[3];
+ int32_t pan_scan_right[3];
+ int32_t pan_scan_top[3];
+ int32_t pan_scan_bottom[3];
+
+ /* H264_VALID_CT_TYPE */
+ uint32_t ct_type_count;
+ uint32_t ct_type[3];
+
+ /* H264_VALID_SPS_CROP */
+ int32_t sps_crop_left;
+ int32_t sps_crop_right;
+ int32_t sps_crop_top;
+ int32_t sps_crop_bottom;
+
+ /* H264_VALID_VUI */
+ uint32_t chroma_top;
+ uint32_t chroma_bottom;
+
+ /* H264_VALID_USER */
+ uint32_t user_data_size;
+ UD_HDR *user_data;
+
+ /* H264 VALID FGT */
+ FGT_SEI *pfgt;
+
+} PPB_H264;
+
+typedef struct {
+ /* Common fields. */
+ uint32_t picture_number; /* Ordinal display number */
+ uint32_t video_buffer; /* Video (picbuf) number */
+ uint32_t video_address; /* Address of picbuf Y */
+ uint32_t video_address_uv; /* Address of picbuf UV */
+ uint32_t video_stripe; /* Picbuf stripe */
+ uint32_t video_width; /* Picbuf width */
+ uint32_t video_height; /* Picbuf height */
+
+ uint32_t channel_id; /* Decoder channel ID */
+ uint32_t status; /* reserved */
+ uint32_t width; /* pixels */
+ uint32_t height; /* pixels */
+ uint32_t chroma_format; /* see above */
+ uint32_t pulldown; /* see above */
+ uint32_t flags; /* see above */
+ uint32_t pts; /* 32 LSBs of PTS */
+ uint32_t protocol; /* protocolXXX (above) */
+
+ uint32_t frame_rate; /* see above */
+ uint32_t matrix_coeff; /* see above */
+ uint32_t aspect_ratio; /* see above */
+ uint32_t colour_primaries; /* see above */
+ uint32_t transfer_char; /* see above */
+ uint32_t pcr_offset; /* 45kHz if PCR type; else 27MHz */
+ uint32_t n_drop; /* Number of pictures to be dropped */
+
+ uint32_t custom_aspect_ratio_width_height;
+ /* upper 16-bits is Y and lower 16-bits is X */
+
+ uint32_t picture_tag; /* Indexing tag from BUD packets */
+ uint32_t picture_done_payload;
+ uint32_t picture_meta_payload;
+ uint32_t reserved[1];
+
+ /* Protocol-specific extensions. */
+ union {
+ PPB_H264 h264;
+ PPB_MPEG mpeg;
+ PPB_VC1 vc1;
+ } other;
+
+} PPB;
+
+typedef struct {
+ uint32_t bFormatChange;
+ uint32_t resolution;
+ uint32_t channelId;
+ uint32_t ppbPtr;
+ int32_t ptsStcOffset;
+ uint32_t zeroPanscanValid;
+ uint32_t dramOutBufAddr;
+ uint32_t yComponent;
+ PPB ppb;
+
+} C011_PIB;
+
+
+
+typedef struct {
+ uint32_t command;
+ uint32_t sequence;
+ uint32_t status;
+ uint32_t picBuf;
+ uint32_t picRelBuf;
+ uint32_t picInfoDeliveryQ;
+ uint32_t picInfoReleaseQ;
+ uint32_t channelStatus;
+ uint32_t userDataDeliveryQ;
+ uint32_t userDataReleaseQ;
+ uint32_t transportStreamCaptureAddr;
+ uint32_t asyncEventQ;
+
+} DecRspChannelStartVideo;
+
+#define eCMD_C011_CMD_BASE (0x73763000)
+
+/* host commands */
+typedef enum {
+ eCMD_TS_GET_NEXT_PIC = 0x7376F100, /* debug get next picture */
+ eCMD_TS_GET_LAST_PIC = 0x7376F102, /* debug get last pic status */
+ eCMD_TS_READ_WRITE_MEM = 0x7376F104, /* debug read write memory */
+
+ /* New API commands */
+ /* General commands */
+ eCMD_C011_INIT = eCMD_C011_CMD_BASE + 0x01,
+ eCMD_C011_RESET = eCMD_C011_CMD_BASE + 0x02,
+ eCMD_C011_SELF_TEST = eCMD_C011_CMD_BASE + 0x03,
+ eCMD_C011_GET_VERSION = eCMD_C011_CMD_BASE + 0x04,
+ eCMD_C011_GPIO = eCMD_C011_CMD_BASE + 0x05,
+ eCMD_C011_DEBUG_SETUP = eCMD_C011_CMD_BASE + 0x06,
+
+ /* Decoding commands */
+ eCMD_C011_DEC_CHAN_OPEN = eCMD_C011_CMD_BASE + 0x100,
+ eCMD_C011_DEC_CHAN_CLOSE = eCMD_C011_CMD_BASE + 0x101,
+ eCMD_C011_DEC_CHAN_ACTIVATE = eCMD_C011_CMD_BASE + 0x102,
+ eCMD_C011_DEC_CHAN_STATUS = eCMD_C011_CMD_BASE + 0x103,
+ eCMD_C011_DEC_CHAN_FLUSH = eCMD_C011_CMD_BASE + 0x104,
+ eCMD_C011_DEC_CHAN_TRICK_PLAY = eCMD_C011_CMD_BASE + 0x105,
+ eCMD_C011_DEC_CHAN_TS_PIDS = eCMD_C011_CMD_BASE + 0x106,
+ eCMD_C011_DEC_CHAN_PS_STREAM_ID = eCMD_C011_CMD_BASE + 0x107,
+ eCMD_C011_DEC_CHAN_INPUT_PARAMS = eCMD_C011_CMD_BASE + 0x108,
+ eCMD_C011_DEC_CHAN_VIDEO_OUTPUT = eCMD_C011_CMD_BASE + 0x109,
+ eCMD_C011_DEC_CHAN_OUTPUT_FORMAT = eCMD_C011_CMD_BASE + 0x10A,
+ eCMD_C011_DEC_CHAN_SCALING_FILTERS = eCMD_C011_CMD_BASE + 0x10B,
+ eCMD_C011_DEC_CHAN_OSD_MODE = eCMD_C011_CMD_BASE + 0x10D,
+ eCMD_C011_DEC_CHAN_DROP = eCMD_C011_CMD_BASE + 0x10E,
+ eCMD_C011_DEC_CHAN_RELEASE = eCMD_C011_CMD_BASE + 0x10F,
+ eCMD_C011_DEC_CHAN_STREAM_SETTINGS = eCMD_C011_CMD_BASE + 0x110,
+ eCMD_C011_DEC_CHAN_PAUSE_OUTPUT = eCMD_C011_CMD_BASE + 0x111,
+ eCMD_C011_DEC_CHAN_CHANGE = eCMD_C011_CMD_BASE + 0x112,
+ eCMD_C011_DEC_CHAN_SET_STC = eCMD_C011_CMD_BASE + 0x113,
+ eCMD_C011_DEC_CHAN_SET_PTS = eCMD_C011_CMD_BASE + 0x114,
+ eCMD_C011_DEC_CHAN_CC_MODE = eCMD_C011_CMD_BASE + 0x115,
+ eCMD_C011_DEC_CREATE_AUDIO_CONTEXT = eCMD_C011_CMD_BASE + 0x116,
+ eCMD_C011_DEC_COPY_AUDIO_CONTEXT = eCMD_C011_CMD_BASE + 0x117,
+ eCMD_C011_DEC_DELETE_AUDIO_CONTEXT = eCMD_C011_CMD_BASE + 0x118,
+ eCMD_C011_DEC_CHAN_SET_DECYPTION = eCMD_C011_CMD_BASE + 0x119,
+ eCMD_C011_DEC_CHAN_START_VIDEO = eCMD_C011_CMD_BASE + 0x11A,
+ eCMD_C011_DEC_CHAN_STOP_VIDEO = eCMD_C011_CMD_BASE + 0x11B,
+ eCMD_C011_DEC_CHAN_PIC_CAPTURE = eCMD_C011_CMD_BASE + 0x11C,
+ eCMD_C011_DEC_CHAN_PAUSE = eCMD_C011_CMD_BASE + 0x11D,
+ eCMD_C011_DEC_CHAN_PAUSE_STATE = eCMD_C011_CMD_BASE + 0x11E,
+ eCMD_C011_DEC_CHAN_SET_SLOWM_RATE = eCMD_C011_CMD_BASE + 0x11F,
+ eCMD_C011_DEC_CHAN_GET_SLOWM_RATE = eCMD_C011_CMD_BASE + 0x120,
+ eCMD_C011_DEC_CHAN_SET_FF_RATE = eCMD_C011_CMD_BASE + 0x121,
+ eCMD_C011_DEC_CHAN_GET_FF_RATE = eCMD_C011_CMD_BASE + 0x122,
+ eCMD_C011_DEC_CHAN_FRAME_ADVANCE = eCMD_C011_CMD_BASE + 0x123,
+ eCMD_C011_DEC_CHAN_SET_SKIP_PIC_MODE = eCMD_C011_CMD_BASE + 0x124,
+ eCMD_C011_DEC_CHAN_GET_SKIP_PIC_MODE = eCMD_C011_CMD_BASE + 0x125,
+ eCMD_C011_DEC_CHAN_FILL_PIC_BUF = eCMD_C011_CMD_BASE + 0x126,
+ eCMD_C011_DEC_CHAN_SET_CONTINUITY_CHECK = eCMD_C011_CMD_BASE + 0x127,
+ eCMD_C011_DEC_CHAN_GET_CONTINUITY_CHECK = eCMD_C011_CMD_BASE + 0x128,
+ eCMD_C011_DEC_CHAN_SET_BRCM_TRICK_MODE = eCMD_C011_CMD_BASE + 0x129,
+ eCMD_C011_DEC_CHAN_GET_BRCM_TRICK_MODE = eCMD_C011_CMD_BASE + 0x12A,
+ eCMD_C011_DEC_CHAN_REVERSE_FIELD_STATUS = eCMD_C011_CMD_BASE + 0x12B,
+ eCMD_C011_DEC_CHAN_I_PICTURE_FOUND = eCMD_C011_CMD_BASE + 0x12C,
+ eCMD_C011_DEC_CHAN_SET_PARAMETER = eCMD_C011_CMD_BASE + 0x12D,
+ eCMD_C011_DEC_CHAN_SET_USER_DATA_MODE = eCMD_C011_CMD_BASE + 0x12E,
+ eCMD_C011_DEC_CHAN_SET_PAUSE_DISPLAY_MODE = eCMD_C011_CMD_BASE + 0x12F,
+ eCMD_C011_DEC_CHAN_SET_SLOW_DISPLAY_MODE = eCMD_C011_CMD_BASE + 0x130,
+ eCMD_C011_DEC_CHAN_SET_FF_DISPLAY_MODE = eCMD_C011_CMD_BASE + 0x131,
+ eCMD_C011_DEC_CHAN_SET_DISPLAY_TIMING_MODE = eCMD_C011_CMD_BASE + 0x132,
+ eCMD_C011_DEC_CHAN_SET_DISPLAY_MODE = eCMD_C011_CMD_BASE + 0x133,
+ eCMD_C011_DEC_CHAN_GET_DISPLAY_MODE = eCMD_C011_CMD_BASE + 0x134,
+ eCMD_C011_DEC_CHAN_SET_REVERSE_FIELD = eCMD_C011_CMD_BASE + 0x135,
+ eCMD_C011_DEC_CHAN_STREAM_OPEN = eCMD_C011_CMD_BASE + 0x136,
+ eCMD_C011_DEC_CHAN_SET_PCR_PID = eCMD_C011_CMD_BASE + 0x137,
+ eCMD_C011_DEC_CHAN_SET_VID_PID = eCMD_C011_CMD_BASE + 0x138,
+ eCMD_C011_DEC_CHAN_SET_PAN_SCAN_MODE = eCMD_C011_CMD_BASE + 0x139,
+ eCMD_C011_DEC_CHAN_START_DISPLAY_AT_PTS = eCMD_C011_CMD_BASE + 0x140,
+ eCMD_C011_DEC_CHAN_STOP_DISPLAY_AT_PTS = eCMD_C011_CMD_BASE + 0x141,
+ eCMD_C011_DEC_CHAN_SET_DISPLAY_ORDER = eCMD_C011_CMD_BASE + 0x142,
+ eCMD_C011_DEC_CHAN_GET_DISPLAY_ORDER = eCMD_C011_CMD_BASE + 0x143,
+ eCMD_C011_DEC_CHAN_SET_HOST_TRICK_MODE = eCMD_C011_CMD_BASE + 0x144,
+ eCMD_C011_DEC_CHAN_SET_OPERATION_MODE = eCMD_C011_CMD_BASE + 0x145,
+ eCMD_C011_DEC_CHAN_DISPLAY_PAUSE_UNTO_PTS = eCMD_C011_CMD_BASE + 0x146,
+ eCMD_C011_DEC_CHAN_SET_PTS_STC_DIFF_THRESHOLD = eCMD_C011_CMD_BASE + 0x147,
+ eCMD_C011_DEC_CHAN_SEND_COMPRESSED_BUF = eCMD_C011_CMD_BASE + 0x148,
+ eCMD_C011_DEC_CHAN_SET_CLIPPING = eCMD_C011_CMD_BASE + 0x149,
+ eCMD_C011_DEC_CHAN_SET_PARAMETERS_FOR_HARD_RESET_INTERRUPT_TO_HOST
+ = eCMD_C011_CMD_BASE + 0x150,
+
+ /* Decoder RevD commands */
+ eCMD_C011_DEC_CHAN_SET_CSC = eCMD_C011_CMD_BASE + 0x180, /* color space conversion */
+ eCMD_C011_DEC_CHAN_SET_RANGE_REMAP = eCMD_C011_CMD_BASE + 0x181,
+ eCMD_C011_DEC_CHAN_SET_FGT = eCMD_C011_CMD_BASE + 0x182,
+ /* Note: 0x183 not implemented yet in Rev D main */
+ eCMD_C011_DEC_CHAN_SET_LASTPICTURE_PADDING = eCMD_C011_CMD_BASE + 0x183,
+
+ /* Decoder 7412 commands (7412-only) */
+ eCMD_C011_DEC_CHAN_SET_CONTENT_KEY = eCMD_C011_CMD_BASE + 0x190,
+ eCMD_C011_DEC_CHAN_SET_SESSION_KEY = eCMD_C011_CMD_BASE + 0x191,
+ eCMD_C011_DEC_CHAN_FMT_CHANGE_ACK = eCMD_C011_CMD_BASE + 0x192,
+
+ eCMD_C011_DEC_CHAN_CUSTOM_VIDOUT = eCMD_C011_CMD_BASE + 0x1FF,
+
+ /* Encoding commands */
+ eCMD_C011_ENC_CHAN_OPEN = eCMD_C011_CMD_BASE + 0x200,
+ eCMD_C011_ENC_CHAN_CLOSE = eCMD_C011_CMD_BASE + 0x201,
+ eCMD_C011_ENC_CHAN_ACTIVATE = eCMD_C011_CMD_BASE + 0x202,
+ eCMD_C011_ENC_CHAN_CONTROL = eCMD_C011_CMD_BASE + 0x203,
+ eCMD_C011_ENC_CHAN_STATISTICS = eCMD_C011_CMD_BASE + 0x204,
+
+ eNOTIFY_C011_ENC_CHAN_EVENT = eCMD_C011_CMD_BASE + 0x210,
+
+} eC011_TS_CMD;
+
+#endif
diff --git a/drivers/staging/crystalhd/crystalhd_hw.c b/drivers/staging/crystalhd/crystalhd_hw.c
new file mode 100644
index 000000000000..01819d34201a
--- /dev/null
+++ b/drivers/staging/crystalhd/crystalhd_hw.c
@@ -0,0 +1,2395 @@
+/***************************************************************************
+ * Copyright (c) 2005-2009, Broadcom Corporation.
+ *
+ * Name: crystalhd_hw . c
+ *
+ * Description:
+ * BCM70010 Linux driver HW layer.
+ *
+ **********************************************************************
+ * This file is part of the crystalhd device driver.
+ *
+ * This driver 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.
+ *
+ * This driver 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 driver. If not, see <http://www.gnu.org/licenses/>.
+ **********************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include "crystalhd_hw.h"
+
+/* Functions internal to this file */
+
+static void crystalhd_enable_uarts(struct crystalhd_adp *adp)
+{
+ bc_dec_reg_wr(adp, UartSelectA, BSVS_UART_STREAM);
+ bc_dec_reg_wr(adp, UartSelectB, BSVS_UART_DEC_OUTER);
+}
+
+
+static void crystalhd_start_dram(struct crystalhd_adp *adp)
+{
+ bc_dec_reg_wr(adp, SDRAM_PARAM, ((40 / 5 - 1) << 0) |
+ /* tras (40ns tras)/(5ns period) -1 ((15/5 - 1) << 4) | // trcd */
+ ((15 / 5 - 1) << 7) | /* trp */
+ ((10 / 5 - 1) << 10) | /* trrd */
+ ((15 / 5 + 1) << 12) | /* twr */
+ ((2 + 1) << 16) | /* twtr */
+ ((70 / 5 - 2) << 19) | /* trfc */
+ (0 << 23));
+
+ bc_dec_reg_wr(adp, SDRAM_PRECHARGE, 0);
+ bc_dec_reg_wr(adp, SDRAM_EXT_MODE, 2);
+ bc_dec_reg_wr(adp, SDRAM_MODE, 0x132);
+ bc_dec_reg_wr(adp, SDRAM_PRECHARGE, 0);
+ bc_dec_reg_wr(adp, SDRAM_REFRESH, 0);
+ bc_dec_reg_wr(adp, SDRAM_REFRESH, 0);
+ bc_dec_reg_wr(adp, SDRAM_MODE, 0x32);
+ /* setting the refresh rate here */
+ bc_dec_reg_wr(adp, SDRAM_REF_PARAM, ((1 << 12) | 96));
+}
+
+
+static bool crystalhd_bring_out_of_rst(struct crystalhd_adp *adp)
+{
+ link_misc_perst_deco_ctrl rst_deco_cntrl;
+ link_misc_perst_clk_ctrl rst_clk_cntrl;
+ uint32_t temp;
+
+ /*
+ * Link clocks: MISC_PERST_CLOCK_CTRL Clear PLL power down bit,
+ * delay to allow PLL to lock Clear alternate clock, stop clock bits
+ */
+ rst_clk_cntrl.whole_reg = crystalhd_reg_rd(adp, MISC_PERST_CLOCK_CTRL);
+ rst_clk_cntrl.pll_pwr_dn = 0;
+ crystalhd_reg_wr(adp, MISC_PERST_CLOCK_CTRL, rst_clk_cntrl.whole_reg);
+ msleep_interruptible(50);
+
+ rst_clk_cntrl.whole_reg = crystalhd_reg_rd(adp, MISC_PERST_CLOCK_CTRL);
+ rst_clk_cntrl.stop_core_clk = 0;
+ rst_clk_cntrl.sel_alt_clk = 0;
+
+ crystalhd_reg_wr(adp, MISC_PERST_CLOCK_CTRL, rst_clk_cntrl.whole_reg);
+ msleep_interruptible(50);
+
+ /*
+ * Bus Arbiter Timeout: GISB_ARBITER_TIMER
+ * Set internal bus arbiter timeout to 40us based on core clock speed
+ * (63MHz * 40us = 0x9D8)
+ */
+ crystalhd_reg_wr(adp, GISB_ARBITER_TIMER, 0x9D8);
+
+ /*
+ * Decoder clocks: MISC_PERST_DECODER_CTRL
+ * Enable clocks while 7412 reset is asserted, delay
+ * De-assert 7412 reset
+ */
+ rst_deco_cntrl.whole_reg = crystalhd_reg_rd(adp, MISC_PERST_DECODER_CTRL);
+ rst_deco_cntrl.stop_bcm_7412_clk = 0;
+ rst_deco_cntrl.bcm7412_rst = 1;
+ crystalhd_reg_wr(adp, MISC_PERST_DECODER_CTRL, rst_deco_cntrl.whole_reg);
+ msleep_interruptible(10);
+
+ rst_deco_cntrl.whole_reg = crystalhd_reg_rd(adp, MISC_PERST_DECODER_CTRL);
+ rst_deco_cntrl.bcm7412_rst = 0;
+ crystalhd_reg_wr(adp, MISC_PERST_DECODER_CTRL, rst_deco_cntrl.whole_reg);
+ msleep_interruptible(50);
+
+ /* Disable OTP_CONTENT_MISC to 0 to disable all secure modes */
+ crystalhd_reg_wr(adp, OTP_CONTENT_MISC, 0);
+
+ /* Clear bit 29 of 0x404 */
+ temp = crystalhd_reg_rd(adp, PCIE_TL_TRANSACTION_CONFIGURATION);
+ temp &= ~BC_BIT(29);
+ crystalhd_reg_wr(adp, PCIE_TL_TRANSACTION_CONFIGURATION, temp);
+
+ /* 2.5V regulator must be set to 2.6 volts (+6%) */
+ /* FIXME: jarod: what's the point of this reg read? */
+ temp = crystalhd_reg_rd(adp, MISC_PERST_VREG_CTRL);
+ crystalhd_reg_wr(adp, MISC_PERST_VREG_CTRL, 0xF3);
+
+ return true;
+}
+
+static bool crystalhd_put_in_reset(struct crystalhd_adp *adp)
+{
+ link_misc_perst_deco_ctrl rst_deco_cntrl;
+ link_misc_perst_clk_ctrl rst_clk_cntrl;
+ uint32_t temp;
+
+ /*
+ * Decoder clocks: MISC_PERST_DECODER_CTRL
+ * Assert 7412 reset, delay
+ * Assert 7412 stop clock
+ */
+ rst_deco_cntrl.whole_reg = crystalhd_reg_rd(adp, MISC_PERST_DECODER_CTRL);
+ rst_deco_cntrl.stop_bcm_7412_clk = 1;
+ crystalhd_reg_wr(adp, MISC_PERST_DECODER_CTRL, rst_deco_cntrl.whole_reg);
+ msleep_interruptible(50);
+
+ /* Bus Arbiter Timeout: GISB_ARBITER_TIMER
+ * Set internal bus arbiter timeout to 40us based on core clock speed
+ * (6.75MHZ * 40us = 0x10E)
+ */
+ crystalhd_reg_wr(adp, GISB_ARBITER_TIMER, 0x10E);
+
+ /* Link clocks: MISC_PERST_CLOCK_CTRL
+ * Stop core clk, delay
+ * Set alternate clk, delay, set PLL power down
+ */
+ rst_clk_cntrl.whole_reg = crystalhd_reg_rd(adp, MISC_PERST_CLOCK_CTRL);
+ rst_clk_cntrl.stop_core_clk = 1;
+ rst_clk_cntrl.sel_alt_clk = 1;
+ crystalhd_reg_wr(adp, MISC_PERST_CLOCK_CTRL, rst_clk_cntrl.whole_reg);
+ msleep_interruptible(50);
+
+ rst_clk_cntrl.whole_reg = crystalhd_reg_rd(adp, MISC_PERST_CLOCK_CTRL);
+ rst_clk_cntrl.pll_pwr_dn = 1;
+ crystalhd_reg_wr(adp, MISC_PERST_CLOCK_CTRL, rst_clk_cntrl.whole_reg);
+
+ /*
+ * Read and restore the Transaction Configuration Register
+ * after core reset
+ */
+ temp = crystalhd_reg_rd(adp, PCIE_TL_TRANSACTION_CONFIGURATION);
+
+ /*
+ * Link core soft reset: MISC3_RESET_CTRL
+ * - Write BIT[0]=1 and read it back for core reset to take place
+ */
+ crystalhd_reg_wr(adp, MISC3_RESET_CTRL, 1);
+ rst_deco_cntrl.whole_reg = crystalhd_reg_rd(adp, MISC3_RESET_CTRL);
+ msleep_interruptible(50);
+
+ /* restore the transaction configuration register */
+ crystalhd_reg_wr(adp, PCIE_TL_TRANSACTION_CONFIGURATION, temp);
+
+ return true;
+}
+
+static void crystalhd_disable_interrupts(struct crystalhd_adp *adp)
+{
+ intr_mask_reg intr_mask;
+ intr_mask.whole_reg = crystalhd_reg_rd(adp, INTR_INTR_MSK_STS_REG);
+ intr_mask.mask_pcie_err = 1;
+ intr_mask.mask_pcie_rbusmast_err = 1;
+ intr_mask.mask_pcie_rgr_bridge = 1;
+ intr_mask.mask_rx_done = 1;
+ intr_mask.mask_rx_err = 1;
+ intr_mask.mask_tx_done = 1;
+ intr_mask.mask_tx_err = 1;
+ crystalhd_reg_wr(adp, INTR_INTR_MSK_SET_REG, intr_mask.whole_reg);
+
+ return;
+}
+
+static void crystalhd_enable_interrupts(struct crystalhd_adp *adp)
+{
+ intr_mask_reg intr_mask;
+ intr_mask.whole_reg = crystalhd_reg_rd(adp, INTR_INTR_MSK_STS_REG);
+ intr_mask.mask_pcie_err = 1;
+ intr_mask.mask_pcie_rbusmast_err = 1;
+ intr_mask.mask_pcie_rgr_bridge = 1;
+ intr_mask.mask_rx_done = 1;
+ intr_mask.mask_rx_err = 1;
+ intr_mask.mask_tx_done = 1;
+ intr_mask.mask_tx_err = 1;
+ crystalhd_reg_wr(adp, INTR_INTR_MSK_CLR_REG, intr_mask.whole_reg);
+
+ return;
+}
+
+static void crystalhd_clear_errors(struct crystalhd_adp *adp)
+{
+ uint32_t reg;
+
+ /* FIXME: jarod: wouldn't we want to write a 0 to the reg? Or does the write clear the bits specified? */
+ reg = crystalhd_reg_rd(adp, MISC1_Y_RX_ERROR_STATUS);
+ if (reg)
+ crystalhd_reg_wr(adp, MISC1_Y_RX_ERROR_STATUS, reg);
+
+ reg = crystalhd_reg_rd(adp, MISC1_UV_RX_ERROR_STATUS);
+ if (reg)
+ crystalhd_reg_wr(adp, MISC1_UV_RX_ERROR_STATUS, reg);
+
+ reg = crystalhd_reg_rd(adp, MISC1_TX_DMA_ERROR_STATUS);
+ if (reg)
+ crystalhd_reg_wr(adp, MISC1_TX_DMA_ERROR_STATUS, reg);
+}
+
+static void crystalhd_clear_interrupts(struct crystalhd_adp *adp)
+{
+ uint32_t intr_sts = crystalhd_reg_rd(adp, INTR_INTR_STATUS);
+
+ if (intr_sts) {
+ crystalhd_reg_wr(adp, INTR_INTR_CLR_REG, intr_sts);
+
+ /* Write End Of Interrupt for PCIE */
+ crystalhd_reg_wr(adp, INTR_EOI_CTRL, 1);
+ }
+}
+
+static void crystalhd_soft_rst(struct crystalhd_adp *adp)
+{
+ uint32_t val;
+
+ /* Assert c011 soft reset*/
+ bc_dec_reg_wr(adp, DecHt_HostSwReset, 0x00000001);
+ msleep_interruptible(50);
+
+ /* Release c011 soft reset*/
+ bc_dec_reg_wr(adp, DecHt_HostSwReset, 0x00000000);
+
+ /* Disable Stuffing..*/
+ val = crystalhd_reg_rd(adp, MISC2_GLOBAL_CTRL);
+ val |= BC_BIT(8);
+ crystalhd_reg_wr(adp, MISC2_GLOBAL_CTRL, val);
+}
+
+static bool crystalhd_load_firmware_config(struct crystalhd_adp *adp)
+{
+ uint32_t i = 0, reg;
+
+ crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (BC_DRAM_FW_CFG_ADDR >> 19));
+
+ crystalhd_reg_wr(adp, AES_CMD, 0);
+ crystalhd_reg_wr(adp, AES_CONFIG_INFO, (BC_DRAM_FW_CFG_ADDR & 0x7FFFF));
+ crystalhd_reg_wr(adp, AES_CMD, 0x1);
+
+ /* FIXME: jarod: I've seen this fail, and introducing extra delays helps... */
+ for (i = 0; i < 100; ++i) {
+ reg = crystalhd_reg_rd(adp, AES_STATUS);
+ if (reg & 0x1)
+ return true;
+ msleep_interruptible(10);
+ }
+
+ return false;
+}
+
+
+static bool crystalhd_start_device(struct crystalhd_adp *adp)
+{
+ uint32_t dbg_options, glb_cntrl = 0, reg_pwrmgmt = 0;
+
+ BCMLOG(BCMLOG_INFO, "Starting BCM70012 Device\n");
+
+ reg_pwrmgmt = crystalhd_reg_rd(adp, PCIE_DLL_DATA_LINK_CONTROL);
+ reg_pwrmgmt &= ~ASPM_L1_ENABLE;
+
+ crystalhd_reg_wr(adp, PCIE_DLL_DATA_LINK_CONTROL, reg_pwrmgmt);
+
+ if (!crystalhd_bring_out_of_rst(adp)) {
+ BCMLOG_ERR("Failed To Bring Link Out Of Reset\n");
+ return false;
+ }
+
+ crystalhd_disable_interrupts(adp);
+
+ crystalhd_clear_errors(adp);
+
+ crystalhd_clear_interrupts(adp);
+
+ crystalhd_enable_interrupts(adp);
+
+ /* Enable the option for getting the total no. of DWORDS
+ * that have been transfered by the RXDMA engine
+ */
+ dbg_options = crystalhd_reg_rd(adp, MISC1_DMA_DEBUG_OPTIONS_REG);
+ dbg_options |= 0x10;
+ crystalhd_reg_wr(adp, MISC1_DMA_DEBUG_OPTIONS_REG, dbg_options);
+
+ /* Enable PCI Global Control options */
+ glb_cntrl = crystalhd_reg_rd(adp, MISC2_GLOBAL_CTRL);
+ glb_cntrl |= 0x100;
+ glb_cntrl |= 0x8000;
+ crystalhd_reg_wr(adp, MISC2_GLOBAL_CTRL, glb_cntrl);
+
+ crystalhd_enable_interrupts(adp);
+
+ crystalhd_soft_rst(adp);
+ crystalhd_start_dram(adp);
+ crystalhd_enable_uarts(adp);
+
+ return true;
+}
+
+static bool crystalhd_stop_device(struct crystalhd_adp *adp)
+{
+ uint32_t reg;
+
+ BCMLOG(BCMLOG_INFO, "Stopping BCM70012 Device\n");
+ /* Clear and disable interrupts */
+ crystalhd_disable_interrupts(adp);
+ crystalhd_clear_errors(adp);
+ crystalhd_clear_interrupts(adp);
+
+ if (!crystalhd_put_in_reset(adp))
+ BCMLOG_ERR("Failed to Put Link To Reset State\n");
+
+ reg = crystalhd_reg_rd(adp, PCIE_DLL_DATA_LINK_CONTROL);
+ reg |= ASPM_L1_ENABLE;
+ crystalhd_reg_wr(adp, PCIE_DLL_DATA_LINK_CONTROL, reg);
+
+ /* Set PCI Clk Req */
+ reg = crystalhd_reg_rd(adp, PCIE_CLK_REQ_REG);
+ reg |= PCI_CLK_REQ_ENABLE;
+ crystalhd_reg_wr(adp, PCIE_CLK_REQ_REG, reg);
+
+ return true;
+}
+
+static crystalhd_rx_dma_pkt *crystalhd_hw_alloc_rx_pkt(struct crystalhd_hw *hw)
+{
+ unsigned long flags = 0;
+ crystalhd_rx_dma_pkt *temp = NULL;
+
+ if (!hw)
+ return NULL;
+
+ spin_lock_irqsave(&hw->lock, flags);
+ temp = hw->rx_pkt_pool_head;
+ if (temp) {
+ hw->rx_pkt_pool_head = hw->rx_pkt_pool_head->next;
+ temp->dio_req = NULL;
+ temp->pkt_tag = 0;
+ temp->flags = 0;
+ }
+ spin_unlock_irqrestore(&hw->lock, flags);
+
+ return temp;
+}
+
+static void crystalhd_hw_free_rx_pkt(struct crystalhd_hw *hw,
+ crystalhd_rx_dma_pkt *pkt)
+{
+ unsigned long flags = 0;
+
+ if (!hw || !pkt)
+ return;
+
+ spin_lock_irqsave(&hw->lock, flags);
+ pkt->next = hw->rx_pkt_pool_head;
+ hw->rx_pkt_pool_head = pkt;
+ spin_unlock_irqrestore(&hw->lock, flags);
+}
+
+/*
+ * Call back from TX - IOQ deletion.
+ *
+ * This routine will release the TX DMA rings allocated
+ * druing setup_dma rings interface.
+ *
+ * Memory is allocated per DMA ring basis. This is just
+ * a place holder to be able to create the dio queues.
+ */
+static void crystalhd_tx_desc_rel_call_back(void *context, void *data)
+{
+}
+
+/*
+ * Rx Packet release callback..
+ *
+ * Release All user mapped capture buffers and Our DMA packets
+ * back to our free pool. The actual cleanup of the DMA
+ * ring descriptors happen during dma ring release.
+ */
+static void crystalhd_rx_pkt_rel_call_back(void *context, void *data)
+{
+ struct crystalhd_hw *hw = (struct crystalhd_hw *)context;
+ crystalhd_rx_dma_pkt *pkt = (crystalhd_rx_dma_pkt *)data;
+
+ if (!pkt || !hw) {
+ BCMLOG_ERR("Invalid arg - %p %p\n", hw, pkt);
+ return;
+ }
+
+ if (pkt->dio_req)
+ crystalhd_unmap_dio(hw->adp, pkt->dio_req);
+ else
+ BCMLOG_ERR("Missing dio_req: 0x%x\n", pkt->pkt_tag);
+
+ crystalhd_hw_free_rx_pkt(hw, pkt);
+}
+
+#define crystalhd_hw_delete_ioq(adp, q) \
+ if (q) { \
+ crystalhd_delete_dioq(adp, q); \
+ q = NULL; \
+ }
+
+static void crystalhd_hw_delete_ioqs(struct crystalhd_hw *hw)
+{
+ if (!hw)
+ return;
+
+ BCMLOG(BCMLOG_DBG, "Deleting IOQs \n");
+ crystalhd_hw_delete_ioq(hw->adp, hw->tx_actq);
+ crystalhd_hw_delete_ioq(hw->adp, hw->tx_freeq);
+ crystalhd_hw_delete_ioq(hw->adp, hw->rx_actq);
+ crystalhd_hw_delete_ioq(hw->adp, hw->rx_freeq);
+ crystalhd_hw_delete_ioq(hw->adp, hw->rx_rdyq);
+}
+
+#define crystalhd_hw_create_ioq(sts, hw, q, cb) \
+do { \
+ sts = crystalhd_create_dioq(hw->adp, &q, cb, hw); \
+ if (sts != BC_STS_SUCCESS) \
+ goto hw_create_ioq_err; \
+} while (0)
+
+/*
+ * Create IOQs..
+ *
+ * TX - Active & Free
+ * RX - Active, Ready and Free.
+ */
+static BC_STATUS crystalhd_hw_create_ioqs(struct crystalhd_hw *hw)
+{
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ if (!hw) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ crystalhd_hw_create_ioq(sts, hw, hw->tx_freeq,
+ crystalhd_tx_desc_rel_call_back);
+ crystalhd_hw_create_ioq(sts, hw, hw->tx_actq,
+ crystalhd_tx_desc_rel_call_back);
+
+ crystalhd_hw_create_ioq(sts, hw, hw->rx_freeq,
+ crystalhd_rx_pkt_rel_call_back);
+ crystalhd_hw_create_ioq(sts, hw, hw->rx_rdyq,
+ crystalhd_rx_pkt_rel_call_back);
+ crystalhd_hw_create_ioq(sts, hw, hw->rx_actq,
+ crystalhd_rx_pkt_rel_call_back);
+
+ return sts;
+
+hw_create_ioq_err:
+ crystalhd_hw_delete_ioqs(hw);
+
+ return sts;
+}
+
+
+static bool crystalhd_code_in_full(struct crystalhd_adp *adp, uint32_t needed_sz,
+ bool b_188_byte_pkts, uint8_t flags)
+{
+ uint32_t base, end, writep, readp;
+ uint32_t cpbSize, cpbFullness, fifoSize;
+
+ if (flags & 0x02) { /* ASF Bit is set */
+ base = bc_dec_reg_rd(adp, REG_Dec_TsAudCDB2Base);
+ end = bc_dec_reg_rd(adp, REG_Dec_TsAudCDB2End);
+ writep = bc_dec_reg_rd(adp, REG_Dec_TsAudCDB2Wrptr);
+ readp = bc_dec_reg_rd(adp, REG_Dec_TsAudCDB2Rdptr);
+ } else if (b_188_byte_pkts) { /*Encrypted 188 byte packets*/
+ base = bc_dec_reg_rd(adp, REG_Dec_TsUser0Base);
+ end = bc_dec_reg_rd(adp, REG_Dec_TsUser0End);
+ writep = bc_dec_reg_rd(adp, REG_Dec_TsUser0Wrptr);
+ readp = bc_dec_reg_rd(adp, REG_Dec_TsUser0Rdptr);
+ } else {
+ base = bc_dec_reg_rd(adp, REG_DecCA_RegCinBase);
+ end = bc_dec_reg_rd(adp, REG_DecCA_RegCinEnd);
+ writep = bc_dec_reg_rd(adp, REG_DecCA_RegCinWrPtr);
+ readp = bc_dec_reg_rd(adp, REG_DecCA_RegCinRdPtr);
+ }
+
+ cpbSize = end - base;
+ if (writep >= readp)
+ cpbFullness = writep - readp;
+ else
+ cpbFullness = (end - base) - (readp - writep);
+
+ fifoSize = cpbSize - cpbFullness;
+
+ if (fifoSize < BC_INFIFO_THRESHOLD)
+ return true;
+
+ if (needed_sz > (fifoSize - BC_INFIFO_THRESHOLD))
+ return true;
+
+ return false;
+}
+
+static BC_STATUS crystalhd_hw_tx_req_complete(struct crystalhd_hw *hw,
+ uint32_t list_id, BC_STATUS cs)
+{
+ tx_dma_pkt *tx_req;
+
+ if (!hw || !list_id) {
+ BCMLOG_ERR("Invalid Arg..\n");
+ return BC_STS_INV_ARG;
+ }
+
+ hw->pwr_lock--;
+
+ tx_req = (tx_dma_pkt *)crystalhd_dioq_find_and_fetch(hw->tx_actq, list_id);
+ if (!tx_req) {
+ if (cs != BC_STS_IO_USER_ABORT)
+ BCMLOG_ERR("Find and Fetch Did not find req\n");
+ return BC_STS_NO_DATA;
+ }
+
+ if (tx_req->call_back) {
+ tx_req->call_back(tx_req->dio_req, tx_req->cb_event, cs);
+ tx_req->dio_req = NULL;
+ tx_req->cb_event = NULL;
+ tx_req->call_back = NULL;
+ } else {
+ BCMLOG(BCMLOG_DBG, "Missing Tx Callback - %X\n",
+ tx_req->list_tag);
+ }
+
+ /* Now put back the tx_list back in FreeQ */
+ tx_req->list_tag = 0;
+
+ return crystalhd_dioq_add(hw->tx_freeq, tx_req, false, 0);
+}
+
+static bool crystalhd_tx_list0_handler(struct crystalhd_hw *hw, uint32_t err_sts)
+{
+ uint32_t err_mask, tmp;
+ unsigned long flags = 0;
+
+ err_mask = MISC1_TX_DMA_ERROR_STATUS_TX_L0_DESC_TX_ABORT_ERRORS_MASK |
+ MISC1_TX_DMA_ERROR_STATUS_TX_L0_DMA_DATA_TX_ABORT_ERRORS_MASK |
+ MISC1_TX_DMA_ERROR_STATUS_TX_L0_FIFO_FULL_ERRORS_MASK;
+
+ if (!(err_sts & err_mask))
+ return false;
+
+ BCMLOG_ERR("Error on Tx-L0 %x \n", err_sts);
+
+ tmp = err_mask;
+
+ if (err_sts & MISC1_TX_DMA_ERROR_STATUS_TX_L0_FIFO_FULL_ERRORS_MASK)
+ tmp &= ~MISC1_TX_DMA_ERROR_STATUS_TX_L0_FIFO_FULL_ERRORS_MASK;
+
+ if (tmp) {
+ spin_lock_irqsave(&hw->lock, flags);
+ /* reset list index.*/
+ hw->tx_list_post_index = 0;
+ spin_unlock_irqrestore(&hw->lock, flags);
+ }
+
+ tmp = err_sts & err_mask;
+ crystalhd_reg_wr(hw->adp, MISC1_TX_DMA_ERROR_STATUS, tmp);
+
+ return true;
+}
+
+static bool crystalhd_tx_list1_handler(struct crystalhd_hw *hw, uint32_t err_sts)
+{
+ uint32_t err_mask, tmp;
+ unsigned long flags = 0;
+
+ err_mask = MISC1_TX_DMA_ERROR_STATUS_TX_L1_DESC_TX_ABORT_ERRORS_MASK |
+ MISC1_TX_DMA_ERROR_STATUS_TX_L1_DMA_DATA_TX_ABORT_ERRORS_MASK |
+ MISC1_TX_DMA_ERROR_STATUS_TX_L1_FIFO_FULL_ERRORS_MASK;
+
+ if (!(err_sts & err_mask))
+ return false;
+
+ BCMLOG_ERR("Error on Tx-L1 %x \n", err_sts);
+
+ tmp = err_mask;
+
+ if (err_sts & MISC1_TX_DMA_ERROR_STATUS_TX_L1_FIFO_FULL_ERRORS_MASK)
+ tmp &= ~MISC1_TX_DMA_ERROR_STATUS_TX_L1_FIFO_FULL_ERRORS_MASK;
+
+ if (tmp) {
+ spin_lock_irqsave(&hw->lock, flags);
+ /* reset list index.*/
+ hw->tx_list_post_index = 0;
+ spin_unlock_irqrestore(&hw->lock, flags);
+ }
+
+ tmp = err_sts & err_mask;
+ crystalhd_reg_wr(hw->adp, MISC1_TX_DMA_ERROR_STATUS, tmp);
+
+ return true;
+}
+
+static void crystalhd_tx_isr(struct crystalhd_hw *hw, uint32_t int_sts)
+{
+ uint32_t err_sts;
+
+ if (int_sts & INTR_INTR_STATUS_L0_TX_DMA_DONE_INTR_MASK)
+ crystalhd_hw_tx_req_complete(hw, hw->tx_ioq_tag_seed + 0,
+ BC_STS_SUCCESS);
+
+ if (int_sts & INTR_INTR_STATUS_L1_TX_DMA_DONE_INTR_MASK)
+ crystalhd_hw_tx_req_complete(hw, hw->tx_ioq_tag_seed + 1,
+ BC_STS_SUCCESS);
+
+ if (!(int_sts & (INTR_INTR_STATUS_L0_TX_DMA_ERR_INTR_MASK |
+ INTR_INTR_STATUS_L1_TX_DMA_ERR_INTR_MASK))) {
+ /* No error mask set.. */
+ return;
+ }
+
+ /* Handle Tx errors. */
+ err_sts = crystalhd_reg_rd(hw->adp, MISC1_TX_DMA_ERROR_STATUS);
+
+ if (crystalhd_tx_list0_handler(hw, err_sts))
+ crystalhd_hw_tx_req_complete(hw, hw->tx_ioq_tag_seed + 0,
+ BC_STS_ERROR);
+
+ if (crystalhd_tx_list1_handler(hw, err_sts))
+ crystalhd_hw_tx_req_complete(hw, hw->tx_ioq_tag_seed + 1,
+ BC_STS_ERROR);
+
+ hw->stats.tx_errors++;
+}
+
+static void crystalhd_hw_dump_desc(pdma_descriptor p_dma_desc,
+ uint32_t ul_desc_index, uint32_t cnt)
+{
+ uint32_t ix, ll = 0;
+
+ if (!p_dma_desc || !cnt)
+ return;
+
+ /* FIXME: jarod: perhaps a modparam desc_debug to enable this, rather than
+ * setting ll (log level, I presume) to non-zero? */
+ if (!ll)
+ return;
+
+ for (ix = ul_desc_index; ix < (ul_desc_index + cnt); ix++) {
+ BCMLOG(ll, "%s[%d] Buff[%x:%x] Next:[%x:%x] XferSz:%x Intr:%x,Last:%x\n",
+ ((p_dma_desc[ul_desc_index].dma_dir) ? "TDesc" : "RDesc"),
+ ul_desc_index,
+ p_dma_desc[ul_desc_index].buff_addr_high,
+ p_dma_desc[ul_desc_index].buff_addr_low,
+ p_dma_desc[ul_desc_index].next_desc_addr_high,
+ p_dma_desc[ul_desc_index].next_desc_addr_low,
+ p_dma_desc[ul_desc_index].xfer_size,
+ p_dma_desc[ul_desc_index].intr_enable,
+ p_dma_desc[ul_desc_index].last_rec_indicator);
+ }
+
+}
+
+static BC_STATUS crystalhd_hw_fill_desc(crystalhd_dio_req *ioreq,
+ dma_descriptor *desc,
+ dma_addr_t desc_paddr_base,
+ uint32_t sg_cnt, uint32_t sg_st_ix,
+ uint32_t sg_st_off, uint32_t xfr_sz)
+{
+ uint32_t count = 0, ix = 0, sg_ix = 0, len = 0, last_desc_ix = 0;
+ dma_addr_t desc_phy_addr = desc_paddr_base;
+ addr_64 addr_temp;
+
+ if (!ioreq || !desc || !desc_paddr_base || !xfr_sz ||
+ (!sg_cnt && !ioreq->uinfo.dir_tx)) {
+ BCMLOG_ERR("Invalid Args\n");
+ return BC_STS_INV_ARG;
+ }
+
+ for (ix = 0; ix < sg_cnt; ix++) {
+
+ /* Setup SGLE index. */
+ sg_ix = ix + sg_st_ix;
+
+ /* Get SGLE length */
+ len = crystalhd_get_sgle_len(ioreq, sg_ix);
+ if (len % 4) {
+ BCMLOG_ERR(" len in sg %d %d %d\n", len, sg_ix, sg_cnt);
+ return BC_STS_NOT_IMPL;
+ }
+ /* Setup DMA desc with Phy addr & Length at current index. */
+ addr_temp.full_addr = crystalhd_get_sgle_paddr(ioreq, sg_ix);
+ if (sg_ix == sg_st_ix) {
+ addr_temp.full_addr += sg_st_off;
+ len -= sg_st_off;
+ }
+ memset(&desc[ix], 0, sizeof(desc[ix]));
+ desc[ix].buff_addr_low = addr_temp.low_part;
+ desc[ix].buff_addr_high = addr_temp.high_part;
+ desc[ix].dma_dir = ioreq->uinfo.dir_tx;
+
+ /* Chain DMA descriptor. */
+ addr_temp.full_addr = desc_phy_addr + sizeof(dma_descriptor);
+ desc[ix].next_desc_addr_low = addr_temp.low_part;
+ desc[ix].next_desc_addr_high = addr_temp.high_part;
+
+ if ((count + len) > xfr_sz)
+ len = xfr_sz - count;
+
+ /* Debug.. */
+ if ((!len) || (len > crystalhd_get_sgle_len(ioreq, sg_ix))) {
+ BCMLOG_ERR("inv-len(%x) Ix(%d) count:%x xfr_sz:%x sg_cnt:%d\n",
+ len, ix, count, xfr_sz, sg_cnt);
+ return BC_STS_ERROR;
+ }
+ /* Length expects Multiple of 4 */
+ desc[ix].xfer_size = (len / 4);
+
+ crystalhd_hw_dump_desc(desc, ix, 1);
+
+ count += len;
+ desc_phy_addr += sizeof(dma_descriptor);
+ }
+
+ last_desc_ix = ix - 1;
+
+ if (ioreq->fb_size) {
+ memset(&desc[ix], 0, sizeof(desc[ix]));
+ addr_temp.full_addr = ioreq->fb_pa;
+ desc[ix].buff_addr_low = addr_temp.low_part;
+ desc[ix].buff_addr_high = addr_temp.high_part;
+ desc[ix].dma_dir = ioreq->uinfo.dir_tx;
+ desc[ix].xfer_size = 1;
+ desc[ix].fill_bytes = 4 - ioreq->fb_size;
+ count += ioreq->fb_size;
+ last_desc_ix++;
+ }
+
+ /* setup last descriptor..*/
+ desc[last_desc_ix].last_rec_indicator = 1;
+ desc[last_desc_ix].next_desc_addr_low = 0;
+ desc[last_desc_ix].next_desc_addr_high = 0;
+ desc[last_desc_ix].intr_enable = 1;
+
+ crystalhd_hw_dump_desc(desc, last_desc_ix, 1);
+
+ if (count != xfr_sz) {
+ BCMLOG_ERR("interal error sz curr:%x exp:%x\n", count, xfr_sz);
+ return BC_STS_ERROR;
+ }
+
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS crystalhd_xlat_sgl_to_dma_desc(crystalhd_dio_req *ioreq,
+ pdma_desc_mem pdesc_mem,
+ uint32_t *uv_desc_index)
+{
+ dma_descriptor *desc = NULL;
+ dma_addr_t desc_paddr_base = 0;
+ uint32_t sg_cnt = 0, sg_st_ix = 0, sg_st_off = 0;
+ uint32_t xfr_sz = 0;
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ /* Check params.. */
+ if (!ioreq || !pdesc_mem || !uv_desc_index) {
+ BCMLOG_ERR("Invalid Args\n");
+ return BC_STS_INV_ARG;
+ }
+
+ if (!pdesc_mem->sz || !pdesc_mem->pdma_desc_start ||
+ !ioreq->sg || (!ioreq->sg_cnt && !ioreq->uinfo.dir_tx)) {
+ BCMLOG_ERR("Invalid Args\n");
+ return BC_STS_INV_ARG;
+ }
+
+ if ((ioreq->uinfo.dir_tx) && (ioreq->uinfo.uv_offset)) {
+ BCMLOG_ERR("UV offset for TX??\n");
+ return BC_STS_INV_ARG;
+
+ }
+
+ desc = pdesc_mem->pdma_desc_start;
+ desc_paddr_base = pdesc_mem->phy_addr;
+
+ if (ioreq->uinfo.dir_tx || (ioreq->uinfo.uv_offset == 0)) {
+ sg_cnt = ioreq->sg_cnt;
+ xfr_sz = ioreq->uinfo.xfr_len;
+ } else {
+ sg_cnt = ioreq->uinfo.uv_sg_ix + 1;
+ xfr_sz = ioreq->uinfo.uv_offset;
+ }
+
+ sts = crystalhd_hw_fill_desc(ioreq, desc, desc_paddr_base, sg_cnt,
+ sg_st_ix, sg_st_off, xfr_sz);
+
+ if ((sts != BC_STS_SUCCESS) || !ioreq->uinfo.uv_offset)
+ return sts;
+
+ /* Prepare for UV mapping.. */
+ desc = &pdesc_mem->pdma_desc_start[sg_cnt];
+ desc_paddr_base = pdesc_mem->phy_addr +
+ (sg_cnt * sizeof(dma_descriptor));
+
+ /* Done with desc addr.. now update sg stuff.*/
+ sg_cnt = ioreq->sg_cnt - ioreq->uinfo.uv_sg_ix;
+ xfr_sz = ioreq->uinfo.xfr_len - ioreq->uinfo.uv_offset;
+ sg_st_ix = ioreq->uinfo.uv_sg_ix;
+ sg_st_off = ioreq->uinfo.uv_sg_off;
+
+ sts = crystalhd_hw_fill_desc(ioreq, desc, desc_paddr_base, sg_cnt,
+ sg_st_ix, sg_st_off, xfr_sz);
+ if (sts != BC_STS_SUCCESS)
+ return sts;
+
+ *uv_desc_index = sg_st_ix;
+
+ return sts;
+}
+
+static void crystalhd_start_tx_dma_engine(struct crystalhd_hw *hw)
+{
+ uint32_t dma_cntrl;
+
+ dma_cntrl = crystalhd_reg_rd(hw->adp, MISC1_TX_SW_DESC_LIST_CTRL_STS);
+ if (!(dma_cntrl & DMA_START_BIT)) {
+ dma_cntrl |= DMA_START_BIT;
+ crystalhd_reg_wr(hw->adp, MISC1_TX_SW_DESC_LIST_CTRL_STS,
+ dma_cntrl);
+ }
+
+ return;
+}
+
+/* _CHECK_THIS_
+ *
+ * Verify if the Stop generates a completion interrupt or not.
+ * if it does not generate an interrupt, then add polling here.
+ */
+static BC_STATUS crystalhd_stop_tx_dma_engine(struct crystalhd_hw *hw)
+{
+ uint32_t dma_cntrl, cnt = 30;
+ uint32_t l1 = 1, l2 = 1;
+ unsigned long flags = 0;
+
+ dma_cntrl = crystalhd_reg_rd(hw->adp, MISC1_TX_SW_DESC_LIST_CTRL_STS);
+
+ BCMLOG(BCMLOG_DBG, "Stopping TX DMA Engine..\n");
+
+ /* FIXME: jarod: invert dma_ctrl and check bit? or are there missing parens? */
+ if (!dma_cntrl & DMA_START_BIT) {
+ BCMLOG(BCMLOG_DBG, "Already Stopped\n");
+ return BC_STS_SUCCESS;
+ }
+
+ crystalhd_disable_interrupts(hw->adp);
+
+ /* Issue stop to HW */
+ /* This bit when set gave problems. Please check*/
+ dma_cntrl &= ~DMA_START_BIT;
+ crystalhd_reg_wr(hw->adp, MISC1_TX_SW_DESC_LIST_CTRL_STS, dma_cntrl);
+
+ BCMLOG(BCMLOG_DBG, "Cleared the DMA Start bit\n");
+
+ /* Poll for 3seconds (30 * 100ms) on both the lists..*/
+ while ((l1 || l2) && cnt) {
+
+ if (l1) {
+ l1 = crystalhd_reg_rd(hw->adp, MISC1_TX_FIRST_DESC_L_ADDR_LIST0);
+ l1 &= DMA_START_BIT;
+ }
+
+ if (l2) {
+ l2 = crystalhd_reg_rd(hw->adp, MISC1_TX_FIRST_DESC_L_ADDR_LIST1);
+ l2 &= DMA_START_BIT;
+ }
+
+ msleep_interruptible(100);
+
+ cnt--;
+ }
+
+ if (!cnt) {
+ BCMLOG_ERR("Failed to stop TX DMA.. l1 %d, l2 %d\n", l1, l2);
+ crystalhd_enable_interrupts(hw->adp);
+ return BC_STS_ERROR;
+ }
+
+ spin_lock_irqsave(&hw->lock, flags);
+ hw->tx_list_post_index = 0;
+ spin_unlock_irqrestore(&hw->lock, flags);
+ BCMLOG(BCMLOG_DBG, "stopped TX DMA..\n");
+ crystalhd_enable_interrupts(hw->adp);
+
+ return BC_STS_SUCCESS;
+}
+
+static uint32_t crystalhd_get_pib_avail_cnt(struct crystalhd_hw *hw)
+{
+ /*
+ * Position of the PIB Entries can be found at
+ * 0th and the 1st location of the Circular list.
+ */
+ uint32_t Q_addr;
+ uint32_t pib_cnt, r_offset, w_offset;
+
+ Q_addr = hw->pib_del_Q_addr;
+
+ /* Get the Read Pointer */
+ crystalhd_mem_rd(hw->adp, Q_addr, 1, &r_offset);
+
+ /* Get the Write Pointer */
+ crystalhd_mem_rd(hw->adp, Q_addr + sizeof(uint32_t), 1, &w_offset);
+
+ if (r_offset == w_offset)
+ return 0; /* Queue is empty */
+
+ if (w_offset > r_offset)
+ pib_cnt = w_offset - r_offset;
+ else
+ pib_cnt = (w_offset + MAX_PIB_Q_DEPTH) -
+ (r_offset + MIN_PIB_Q_DEPTH);
+
+ if (pib_cnt > MAX_PIB_Q_DEPTH) {
+ BCMLOG_ERR("Invalid PIB Count (%u)\n", pib_cnt);
+ return 0;
+ }
+
+ return pib_cnt;
+}
+
+static uint32_t crystalhd_get_addr_from_pib_Q(struct crystalhd_hw *hw)
+{
+ uint32_t Q_addr;
+ uint32_t addr_entry, r_offset, w_offset;
+
+ Q_addr = hw->pib_del_Q_addr;
+
+ /* Get the Read Pointer 0Th Location is Read Pointer */
+ crystalhd_mem_rd(hw->adp, Q_addr, 1, &r_offset);
+
+ /* Get the Write Pointer 1st Location is Write pointer */
+ crystalhd_mem_rd(hw->adp, Q_addr + sizeof(uint32_t), 1, &w_offset);
+
+ /* Queue is empty */
+ if (r_offset == w_offset)
+ return 0;
+
+ if ((r_offset < MIN_PIB_Q_DEPTH) || (r_offset >= MAX_PIB_Q_DEPTH))
+ return 0;
+
+ /* Get the Actual Address of the PIB */
+ crystalhd_mem_rd(hw->adp, Q_addr + (r_offset * sizeof(uint32_t)),
+ 1, &addr_entry);
+
+ /* Increment the Read Pointer */
+ r_offset++;
+
+ if (MAX_PIB_Q_DEPTH == r_offset)
+ r_offset = MIN_PIB_Q_DEPTH;
+
+ /* Write back the read pointer to It's Location */
+ crystalhd_mem_wr(hw->adp, Q_addr, 1, &r_offset);
+
+ return addr_entry;
+}
+
+static bool crystalhd_rel_addr_to_pib_Q(struct crystalhd_hw *hw, uint32_t addr_to_rel)
+{
+ uint32_t Q_addr;
+ uint32_t r_offset, w_offset, n_offset;
+
+ Q_addr = hw->pib_rel_Q_addr;
+
+ /* Get the Read Pointer */
+ crystalhd_mem_rd(hw->adp, Q_addr, 1, &r_offset);
+
+ /* Get the Write Pointer */
+ crystalhd_mem_rd(hw->adp, Q_addr + sizeof(uint32_t), 1, &w_offset);
+
+ if ((r_offset < MIN_PIB_Q_DEPTH) ||
+ (r_offset >= MAX_PIB_Q_DEPTH))
+ return false;
+
+ n_offset = w_offset + 1;
+
+ if (MAX_PIB_Q_DEPTH == n_offset)
+ n_offset = MIN_PIB_Q_DEPTH;
+
+ if (r_offset == n_offset)
+ return false; /* should never happen */
+
+ /* Write the DRAM ADDR to the Queue at Next Offset */
+ crystalhd_mem_wr(hw->adp, Q_addr + (w_offset * sizeof(uint32_t)),
+ 1, &addr_to_rel);
+
+ /* Put the New value of the write pointer in Queue */
+ crystalhd_mem_wr(hw->adp, Q_addr + sizeof(uint32_t), 1, &n_offset);
+
+ return true;
+}
+
+static void cpy_pib_to_app(C011_PIB *src_pib, BC_PIC_INFO_BLOCK *dst_pib)
+{
+ if (!src_pib || !dst_pib) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return;
+ }
+
+ dst_pib->timeStamp = 0;
+ dst_pib->picture_number = src_pib->ppb.picture_number;
+ dst_pib->width = src_pib->ppb.width;
+ dst_pib->height = src_pib->ppb.height;
+ dst_pib->chroma_format = src_pib->ppb.chroma_format;
+ dst_pib->pulldown = src_pib->ppb.pulldown;
+ dst_pib->flags = src_pib->ppb.flags;
+ dst_pib->sess_num = src_pib->ptsStcOffset;
+ dst_pib->aspect_ratio = src_pib->ppb.aspect_ratio;
+ dst_pib->colour_primaries = src_pib->ppb.colour_primaries;
+ dst_pib->picture_meta_payload = src_pib->ppb.picture_meta_payload;
+ dst_pib->frame_rate = src_pib->resolution ;
+ return;
+}
+
+static void crystalhd_hw_proc_pib(struct crystalhd_hw *hw)
+{
+ unsigned int cnt;
+ C011_PIB src_pib;
+ uint32_t pib_addr, pib_cnt;
+ BC_PIC_INFO_BLOCK *AppPib;
+ crystalhd_rx_dma_pkt *rx_pkt = NULL;
+
+ pib_cnt = crystalhd_get_pib_avail_cnt(hw);
+
+ if (!pib_cnt)
+ return;
+
+ for (cnt = 0; cnt < pib_cnt; cnt++) {
+
+ pib_addr = crystalhd_get_addr_from_pib_Q(hw);
+ crystalhd_mem_rd(hw->adp, pib_addr, sizeof(C011_PIB) / 4,
+ (uint32_t *)&src_pib);
+
+ if (src_pib.bFormatChange) {
+ rx_pkt = (crystalhd_rx_dma_pkt *)crystalhd_dioq_fetch(hw->rx_freeq);
+ if (!rx_pkt)
+ return;
+ rx_pkt->flags = 0;
+ rx_pkt->flags |= COMP_FLAG_PIB_VALID | COMP_FLAG_FMT_CHANGE;
+ AppPib = &rx_pkt->pib;
+ cpy_pib_to_app(&src_pib, AppPib);
+
+ BCMLOG(BCMLOG_DBG,
+ "App PIB:%x %x %x %x %x %x %x %x %x %x\n",
+ rx_pkt->pib.picture_number,
+ rx_pkt->pib.aspect_ratio,
+ rx_pkt->pib.chroma_format,
+ rx_pkt->pib.colour_primaries,
+ rx_pkt->pib.frame_rate,
+ rx_pkt->pib.height,
+ rx_pkt->pib.height,
+ rx_pkt->pib.n_drop,
+ rx_pkt->pib.pulldown,
+ rx_pkt->pib.ycom);
+
+ crystalhd_dioq_add(hw->rx_rdyq, (void *)rx_pkt, true, rx_pkt->pkt_tag);
+
+ }
+
+ crystalhd_rel_addr_to_pib_Q(hw, pib_addr);
+ }
+}
+
+static void crystalhd_start_rx_dma_engine(struct crystalhd_hw *hw)
+{
+ uint32_t dma_cntrl;
+
+ dma_cntrl = crystalhd_reg_rd(hw->adp, MISC1_Y_RX_SW_DESC_LIST_CTRL_STS);
+ if (!(dma_cntrl & DMA_START_BIT)) {
+ dma_cntrl |= DMA_START_BIT;
+ crystalhd_reg_wr(hw->adp, MISC1_Y_RX_SW_DESC_LIST_CTRL_STS, dma_cntrl);
+ }
+
+ dma_cntrl = crystalhd_reg_rd(hw->adp, MISC1_UV_RX_SW_DESC_LIST_CTRL_STS);
+ if (!(dma_cntrl & DMA_START_BIT)) {
+ dma_cntrl |= DMA_START_BIT;
+ crystalhd_reg_wr(hw->adp, MISC1_UV_RX_SW_DESC_LIST_CTRL_STS, dma_cntrl);
+ }
+
+ return;
+}
+
+static void crystalhd_stop_rx_dma_engine(struct crystalhd_hw *hw)
+{
+ uint32_t dma_cntrl = 0, count = 30;
+ uint32_t l0y = 1, l0uv = 1, l1y = 1, l1uv = 1;
+
+ dma_cntrl = crystalhd_reg_rd(hw->adp, MISC1_Y_RX_SW_DESC_LIST_CTRL_STS);
+ if ((dma_cntrl & DMA_START_BIT)) {
+ dma_cntrl &= ~DMA_START_BIT;
+ crystalhd_reg_wr(hw->adp, MISC1_Y_RX_SW_DESC_LIST_CTRL_STS, dma_cntrl);
+ }
+
+ dma_cntrl = crystalhd_reg_rd(hw->adp, MISC1_UV_RX_SW_DESC_LIST_CTRL_STS);
+ if ((dma_cntrl & DMA_START_BIT)) {
+ dma_cntrl &= ~DMA_START_BIT;
+ crystalhd_reg_wr(hw->adp, MISC1_UV_RX_SW_DESC_LIST_CTRL_STS, dma_cntrl);
+ }
+
+ /* Poll for 3seconds (30 * 100ms) on both the lists..*/
+ while ((l0y || l0uv || l1y || l1uv) && count) {
+
+ if (l0y) {
+ l0y = crystalhd_reg_rd(hw->adp, MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST0);
+ l0y &= DMA_START_BIT;
+ if (!l0y) {
+ hw->rx_list_sts[0] &= ~rx_waiting_y_intr;
+ }
+ }
+
+ if (l1y) {
+ l1y = crystalhd_reg_rd(hw->adp, MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST1);
+ l1y &= DMA_START_BIT;
+ if (!l1y) {
+ hw->rx_list_sts[1] &= ~rx_waiting_y_intr;
+ }
+ }
+
+ if (l0uv) {
+ l0uv = crystalhd_reg_rd(hw->adp, MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST0);
+ l0uv &= DMA_START_BIT;
+ if (!l0uv) {
+ hw->rx_list_sts[0] &= ~rx_waiting_uv_intr;
+ }
+ }
+
+ if (l1uv) {
+ l1uv = crystalhd_reg_rd(hw->adp, MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST1);
+ l1uv &= DMA_START_BIT;
+ if (!l1uv) {
+ hw->rx_list_sts[1] &= ~rx_waiting_uv_intr;
+ }
+ }
+ msleep_interruptible(100);
+ count--;
+ }
+
+ hw->rx_list_post_index = 0;
+
+ BCMLOG(BCMLOG_SSTEP, "Capture Stop: %d List0:Sts:%x List1:Sts:%x\n",
+ count, hw->rx_list_sts[0], hw->rx_list_sts[1]);
+}
+
+static BC_STATUS crystalhd_hw_prog_rxdma(struct crystalhd_hw *hw, crystalhd_rx_dma_pkt *rx_pkt)
+{
+ uint32_t y_low_addr_reg, y_high_addr_reg;
+ uint32_t uv_low_addr_reg, uv_high_addr_reg;
+ addr_64 desc_addr;
+ unsigned long flags;
+
+ if (!hw || !rx_pkt) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ if (hw->rx_list_post_index >= DMA_ENGINE_CNT) {
+ BCMLOG_ERR("List Out Of bounds %x\n", hw->rx_list_post_index);
+ return BC_STS_INV_ARG;
+ }
+
+ spin_lock_irqsave(&hw->rx_lock, flags);
+ /* FIXME: jarod: sts_free is an enum for 0, in crystalhd_hw.h... yuk... */
+ if (sts_free != hw->rx_list_sts[hw->rx_list_post_index]) {
+ spin_unlock_irqrestore(&hw->rx_lock, flags);
+ return BC_STS_BUSY;
+ }
+
+ if (!hw->rx_list_post_index) {
+ y_low_addr_reg = MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST0;
+ y_high_addr_reg = MISC1_Y_RX_FIRST_DESC_U_ADDR_LIST0;
+ uv_low_addr_reg = MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST0;
+ uv_high_addr_reg = MISC1_UV_RX_FIRST_DESC_U_ADDR_LIST0;
+ } else {
+ y_low_addr_reg = MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST1;
+ y_high_addr_reg = MISC1_Y_RX_FIRST_DESC_U_ADDR_LIST1;
+ uv_low_addr_reg = MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST1;
+ uv_high_addr_reg = MISC1_UV_RX_FIRST_DESC_U_ADDR_LIST1;
+ }
+ rx_pkt->pkt_tag = hw->rx_pkt_tag_seed + hw->rx_list_post_index;
+ hw->rx_list_sts[hw->rx_list_post_index] |= rx_waiting_y_intr;
+ if (rx_pkt->uv_phy_addr)
+ hw->rx_list_sts[hw->rx_list_post_index] |= rx_waiting_uv_intr;
+ hw->rx_list_post_index = (hw->rx_list_post_index + 1) % DMA_ENGINE_CNT;
+ spin_unlock_irqrestore(&hw->rx_lock, flags);
+
+ crystalhd_dioq_add(hw->rx_actq, (void *)rx_pkt, false, rx_pkt->pkt_tag);
+
+ crystalhd_start_rx_dma_engine(hw);
+ /* Program the Y descriptor */
+ desc_addr.full_addr = rx_pkt->desc_mem.phy_addr;
+ crystalhd_reg_wr(hw->adp, y_high_addr_reg, desc_addr.high_part);
+ crystalhd_reg_wr(hw->adp, y_low_addr_reg, desc_addr.low_part | 0x01);
+
+ if (rx_pkt->uv_phy_addr) {
+ /* Program the UV descriptor */
+ desc_addr.full_addr = rx_pkt->uv_phy_addr;
+ crystalhd_reg_wr(hw->adp, uv_high_addr_reg, desc_addr.high_part);
+ crystalhd_reg_wr(hw->adp, uv_low_addr_reg, desc_addr.low_part | 0x01);
+ }
+
+ return BC_STS_SUCCESS;
+}
+
+static BC_STATUS crystalhd_hw_post_cap_buff(struct crystalhd_hw *hw,
+ crystalhd_rx_dma_pkt *rx_pkt)
+{
+ BC_STATUS sts = crystalhd_hw_prog_rxdma(hw, rx_pkt);
+
+ if (sts == BC_STS_BUSY)
+ crystalhd_dioq_add(hw->rx_freeq, (void *)rx_pkt,
+ false, rx_pkt->pkt_tag);
+
+ return sts;
+}
+
+static void crystalhd_get_dnsz(struct crystalhd_hw *hw, uint32_t list_index,
+ uint32_t *y_dw_dnsz, uint32_t *uv_dw_dnsz)
+{
+ uint32_t y_dn_sz_reg, uv_dn_sz_reg;
+
+ if (!list_index) {
+ y_dn_sz_reg = MISC1_Y_RX_LIST0_CUR_BYTE_CNT;
+ uv_dn_sz_reg = MISC1_UV_RX_LIST0_CUR_BYTE_CNT;
+ } else {
+ y_dn_sz_reg = MISC1_Y_RX_LIST1_CUR_BYTE_CNT;
+ uv_dn_sz_reg = MISC1_UV_RX_LIST1_CUR_BYTE_CNT;
+ }
+
+ *y_dw_dnsz = crystalhd_reg_rd(hw->adp, y_dn_sz_reg);
+ *uv_dw_dnsz = crystalhd_reg_rd(hw->adp, uv_dn_sz_reg);
+}
+
+/*
+ * This function should be called only after making sure that the two DMA
+ * lists are free. This function does not check if DMA's are active, before
+ * turning off the DMA.
+ */
+static void crystalhd_hw_finalize_pause(struct crystalhd_hw *hw)
+{
+ uint32_t dma_cntrl, aspm;
+
+ hw->stop_pending = 0;
+
+ dma_cntrl = crystalhd_reg_rd(hw->adp, MISC1_Y_RX_SW_DESC_LIST_CTRL_STS);
+ if (dma_cntrl & DMA_START_BIT) {
+ dma_cntrl &= ~DMA_START_BIT;
+ crystalhd_reg_wr(hw->adp, MISC1_Y_RX_SW_DESC_LIST_CTRL_STS, dma_cntrl);
+ }
+
+ dma_cntrl = crystalhd_reg_rd(hw->adp, MISC1_UV_RX_SW_DESC_LIST_CTRL_STS);
+ if (dma_cntrl & DMA_START_BIT) {
+ dma_cntrl &= ~DMA_START_BIT;
+ crystalhd_reg_wr(hw->adp, MISC1_UV_RX_SW_DESC_LIST_CTRL_STS, dma_cntrl);
+ }
+ hw->rx_list_post_index = 0;
+
+ aspm = crystalhd_reg_rd(hw->adp, PCIE_DLL_DATA_LINK_CONTROL);
+ aspm |= ASPM_L1_ENABLE;
+ /* NAREN BCMLOG(BCMLOG_INFO, "aspm on\n"); */
+ crystalhd_reg_wr(hw->adp, PCIE_DLL_DATA_LINK_CONTROL, aspm);
+}
+
+static BC_STATUS crystalhd_rx_pkt_done(struct crystalhd_hw *hw, uint32_t list_index,
+ BC_STATUS comp_sts)
+{
+ crystalhd_rx_dma_pkt *rx_pkt = NULL;
+ uint32_t y_dw_dnsz, uv_dw_dnsz;
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ if (!hw || list_index >= DMA_ENGINE_CNT) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ rx_pkt = crystalhd_dioq_find_and_fetch(hw->rx_actq,
+ hw->rx_pkt_tag_seed + list_index);
+ if (!rx_pkt) {
+ BCMLOG_ERR("Act-Q:PostIx:%x L0Sts:%x L1Sts:%x current L:%x tag:%x comp:%x\n",
+ hw->rx_list_post_index, hw->rx_list_sts[0],
+ hw->rx_list_sts[1], list_index,
+ hw->rx_pkt_tag_seed + list_index, comp_sts);
+ return BC_STS_INV_ARG;
+ }
+
+ if (comp_sts == BC_STS_SUCCESS) {
+ crystalhd_get_dnsz(hw, list_index, &y_dw_dnsz, &uv_dw_dnsz);
+ rx_pkt->dio_req->uinfo.y_done_sz = y_dw_dnsz;
+ rx_pkt->flags = COMP_FLAG_DATA_VALID;
+ if (rx_pkt->uv_phy_addr)
+ rx_pkt->dio_req->uinfo.uv_done_sz = uv_dw_dnsz;
+ crystalhd_dioq_add(hw->rx_rdyq, rx_pkt, true,
+ hw->rx_pkt_tag_seed + list_index);
+ return sts;
+ }
+
+ /* Check if we can post this DIO again. */
+ return crystalhd_hw_post_cap_buff(hw, rx_pkt);
+}
+
+static bool crystalhd_rx_list0_handler(struct crystalhd_hw *hw, uint32_t int_sts,
+ uint32_t y_err_sts, uint32_t uv_err_sts)
+{
+ uint32_t tmp;
+ list_sts tmp_lsts;
+
+ if (!(y_err_sts & GET_Y0_ERR_MSK) && !(uv_err_sts & GET_UV0_ERR_MSK))
+ return false;
+
+ tmp_lsts = hw->rx_list_sts[0];
+
+ /* Y0 - DMA */
+ tmp = y_err_sts & GET_Y0_ERR_MSK;
+ if (int_sts & INTR_INTR_STATUS_L0_Y_RX_DMA_DONE_INTR_MASK)
+ hw->rx_list_sts[0] &= ~rx_waiting_y_intr;
+
+ if (y_err_sts & MISC1_Y_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK) {
+ hw->rx_list_sts[0] &= ~rx_waiting_y_intr;
+ tmp &= ~MISC1_Y_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK;
+ }
+
+ if (y_err_sts & MISC1_Y_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK) {
+ hw->rx_list_sts[0] &= ~rx_y_mask;
+ hw->rx_list_sts[0] |= rx_y_error;
+ tmp &= ~MISC1_Y_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK;
+ }
+
+ if (tmp) {
+ hw->rx_list_sts[0] &= ~rx_y_mask;
+ hw->rx_list_sts[0] |= rx_y_error;
+ hw->rx_list_post_index = 0;
+ }
+
+ /* UV0 - DMA */
+ tmp = uv_err_sts & GET_UV0_ERR_MSK;
+ if (int_sts & INTR_INTR_STATUS_L0_UV_RX_DMA_DONE_INTR_MASK)
+ hw->rx_list_sts[0] &= ~rx_waiting_uv_intr;
+
+ if (uv_err_sts & MISC1_UV_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK) {
+ hw->rx_list_sts[0] &= ~rx_waiting_uv_intr;
+ tmp &= ~MISC1_UV_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK;
+ }
+
+ if (uv_err_sts & MISC1_UV_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK) {
+ hw->rx_list_sts[0] &= ~rx_uv_mask;
+ hw->rx_list_sts[0] |= rx_uv_error;
+ tmp &= ~MISC1_UV_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK;
+ }
+
+ if (tmp) {
+ hw->rx_list_sts[0] &= ~rx_uv_mask;
+ hw->rx_list_sts[0] |= rx_uv_error;
+ hw->rx_list_post_index = 0;
+ }
+
+ if (y_err_sts & GET_Y0_ERR_MSK) {
+ tmp = y_err_sts & GET_Y0_ERR_MSK;
+ crystalhd_reg_wr(hw->adp, MISC1_Y_RX_ERROR_STATUS, tmp);
+ }
+
+ if (uv_err_sts & GET_UV0_ERR_MSK) {
+ tmp = uv_err_sts & GET_UV0_ERR_MSK;
+ crystalhd_reg_wr(hw->adp, MISC1_UV_RX_ERROR_STATUS, tmp);
+ }
+
+ return (tmp_lsts != hw->rx_list_sts[0]);
+}
+
+static bool crystalhd_rx_list1_handler(struct crystalhd_hw *hw, uint32_t int_sts,
+ uint32_t y_err_sts, uint32_t uv_err_sts)
+{
+ uint32_t tmp;
+ list_sts tmp_lsts;
+
+ if (!(y_err_sts & GET_Y1_ERR_MSK) && !(uv_err_sts & GET_UV1_ERR_MSK))
+ return false;
+
+ tmp_lsts = hw->rx_list_sts[1];
+
+ /* Y1 - DMA */
+ tmp = y_err_sts & GET_Y1_ERR_MSK;
+ if (int_sts & INTR_INTR_STATUS_L1_Y_RX_DMA_DONE_INTR_MASK)
+ hw->rx_list_sts[1] &= ~rx_waiting_y_intr;
+
+ if (y_err_sts & MISC1_Y_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK) {
+ hw->rx_list_sts[1] &= ~rx_waiting_y_intr;
+ tmp &= ~MISC1_Y_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK;
+ }
+
+ if (y_err_sts & MISC1_Y_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK) {
+ /* Add retry-support..*/
+ hw->rx_list_sts[1] &= ~rx_y_mask;
+ hw->rx_list_sts[1] |= rx_y_error;
+ tmp &= ~MISC1_Y_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK;
+ }
+
+ if (tmp) {
+ hw->rx_list_sts[1] &= ~rx_y_mask;
+ hw->rx_list_sts[1] |= rx_y_error;
+ hw->rx_list_post_index = 0;
+ }
+
+ /* UV1 - DMA */
+ tmp = uv_err_sts & GET_UV1_ERR_MSK;
+ if (int_sts & INTR_INTR_STATUS_L1_UV_RX_DMA_DONE_INTR_MASK) {
+ hw->rx_list_sts[1] &= ~rx_waiting_uv_intr;
+ }
+
+ if (uv_err_sts & MISC1_UV_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK) {
+ hw->rx_list_sts[1] &= ~rx_waiting_uv_intr;
+ tmp &= ~MISC1_UV_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK;
+ }
+
+ if (uv_err_sts & MISC1_UV_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK) {
+ /* Add retry-support*/
+ hw->rx_list_sts[1] &= ~rx_uv_mask;
+ hw->rx_list_sts[1] |= rx_uv_error;
+ tmp &= ~MISC1_UV_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK;
+ }
+
+ if (tmp) {
+ hw->rx_list_sts[1] &= ~rx_uv_mask;
+ hw->rx_list_sts[1] |= rx_uv_error;
+ hw->rx_list_post_index = 0;
+ }
+
+ if (y_err_sts & GET_Y1_ERR_MSK) {
+ tmp = y_err_sts & GET_Y1_ERR_MSK;
+ crystalhd_reg_wr(hw->adp, MISC1_Y_RX_ERROR_STATUS, tmp);
+ }
+
+ if (uv_err_sts & GET_UV1_ERR_MSK) {
+ tmp = uv_err_sts & GET_UV1_ERR_MSK;
+ crystalhd_reg_wr(hw->adp, MISC1_UV_RX_ERROR_STATUS, tmp);
+ }
+
+ return (tmp_lsts != hw->rx_list_sts[1]);
+}
+
+
+static void crystalhd_rx_isr(struct crystalhd_hw *hw, uint32_t intr_sts)
+{
+ unsigned long flags;
+ uint32_t i, list_avail = 0;
+ BC_STATUS comp_sts = BC_STS_NO_DATA;
+ uint32_t y_err_sts, uv_err_sts, y_dn_sz = 0, uv_dn_sz = 0;
+ bool ret = 0;
+
+ if (!hw) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return;
+ }
+
+ if (!(intr_sts & GET_RX_INTR_MASK))
+ return;
+
+ y_err_sts = crystalhd_reg_rd(hw->adp, MISC1_Y_RX_ERROR_STATUS);
+ uv_err_sts = crystalhd_reg_rd(hw->adp, MISC1_UV_RX_ERROR_STATUS);
+
+ for (i = 0; i < DMA_ENGINE_CNT; i++) {
+ /* Update States..*/
+ spin_lock_irqsave(&hw->rx_lock, flags);
+ if (i == 0)
+ ret = crystalhd_rx_list0_handler(hw, intr_sts, y_err_sts, uv_err_sts);
+ else
+ ret = crystalhd_rx_list1_handler(hw, intr_sts, y_err_sts, uv_err_sts);
+ if (ret) {
+ switch (hw->rx_list_sts[i]) {
+ case sts_free:
+ comp_sts = BC_STS_SUCCESS;
+ list_avail = 1;
+ break;
+ case rx_y_error:
+ case rx_uv_error:
+ case rx_sts_error:
+ /* We got error on both or Y or uv. */
+ hw->stats.rx_errors++;
+ crystalhd_get_dnsz(hw, i, &y_dn_sz, &uv_dn_sz);
+ /* FIXME: jarod: this is where my mini pci-e card is tripping up */
+ BCMLOG(BCMLOG_DBG, "list_index:%x rx[%d] Y:%x "
+ "UV:%x Int:%x YDnSz:%x UVDnSz:%x\n",
+ i, hw->stats.rx_errors, y_err_sts,
+ uv_err_sts, intr_sts, y_dn_sz, uv_dn_sz);
+ hw->rx_list_sts[i] = sts_free;
+ comp_sts = BC_STS_ERROR;
+ break;
+ default:
+ /* Wait for completion..*/
+ comp_sts = BC_STS_NO_DATA;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&hw->rx_lock, flags);
+
+ /* handle completion...*/
+ if (comp_sts != BC_STS_NO_DATA) {
+ crystalhd_rx_pkt_done(hw, i, comp_sts);
+ comp_sts = BC_STS_NO_DATA;
+ }
+ }
+
+ if (list_avail) {
+ if (hw->stop_pending) {
+ if ((hw->rx_list_sts[0] == sts_free) &&
+ (hw->rx_list_sts[1] == sts_free))
+ crystalhd_hw_finalize_pause(hw);
+ } else {
+ crystalhd_hw_start_capture(hw);
+ }
+ }
+}
+
+static BC_STATUS crystalhd_fw_cmd_post_proc(struct crystalhd_hw *hw,
+ BC_FW_CMD *fw_cmd)
+{
+ BC_STATUS sts = BC_STS_SUCCESS;
+ DecRspChannelStartVideo *st_rsp = NULL;
+
+ switch (fw_cmd->cmd[0]) {
+ case eCMD_C011_DEC_CHAN_START_VIDEO:
+ st_rsp = (DecRspChannelStartVideo *)fw_cmd->rsp;
+ hw->pib_del_Q_addr = st_rsp->picInfoDeliveryQ;
+ hw->pib_rel_Q_addr = st_rsp->picInfoReleaseQ;
+ BCMLOG(BCMLOG_DBG, "DelQAddr:%x RelQAddr:%x\n",
+ hw->pib_del_Q_addr, hw->pib_rel_Q_addr);
+ break;
+ case eCMD_C011_INIT:
+ if (!(crystalhd_load_firmware_config(hw->adp))) {
+ BCMLOG_ERR("Invalid Params.\n");
+ sts = BC_STS_FW_AUTH_FAILED;
+ }
+ break;
+ default:
+ break;
+ }
+ return sts;
+}
+
+static BC_STATUS crystalhd_put_ddr2sleep(struct crystalhd_hw *hw)
+{
+ uint32_t reg;
+ link_misc_perst_decoder_ctrl rst_cntrl_reg;
+
+ /* Pulse reset pin of 7412 (MISC_PERST_DECODER_CTRL) */
+ rst_cntrl_reg.whole_reg = crystalhd_reg_rd(hw->adp, MISC_PERST_DECODER_CTRL);
+
+ rst_cntrl_reg.bcm_7412_rst = 1;
+ crystalhd_reg_wr(hw->adp, MISC_PERST_DECODER_CTRL, rst_cntrl_reg.whole_reg);
+ msleep_interruptible(50);
+
+ rst_cntrl_reg.bcm_7412_rst = 0;
+ crystalhd_reg_wr(hw->adp, MISC_PERST_DECODER_CTRL, rst_cntrl_reg.whole_reg);
+
+ /* Close all banks, put DDR in idle */
+ bc_dec_reg_wr(hw->adp, SDRAM_PRECHARGE, 0);
+
+ /* Set bit 25 (drop CKE pin of DDR) */
+ reg = bc_dec_reg_rd(hw->adp, SDRAM_PARAM);
+ reg |= 0x02000000;
+ bc_dec_reg_wr(hw->adp, SDRAM_PARAM, reg);
+
+ /* Reset the audio block */
+ bc_dec_reg_wr(hw->adp, AUD_DSP_MISC_SOFT_RESET, 0x1);
+
+ /* Power down Raptor PLL */
+ reg = bc_dec_reg_rd(hw->adp, DecHt_PllCCtl);
+ reg |= 0x00008000;
+ bc_dec_reg_wr(hw->adp, DecHt_PllCCtl, reg);
+
+ /* Power down all Audio PLL */
+ bc_dec_reg_wr(hw->adp, AIO_MISC_PLL_RESET, 0x1);
+
+ /* Power down video clock (75MHz) */
+ reg = bc_dec_reg_rd(hw->adp, DecHt_PllECtl);
+ reg |= 0x00008000;
+ bc_dec_reg_wr(hw->adp, DecHt_PllECtl, reg);
+
+ /* Power down video clock (75MHz) */
+ reg = bc_dec_reg_rd(hw->adp, DecHt_PllDCtl);
+ reg |= 0x00008000;
+ bc_dec_reg_wr(hw->adp, DecHt_PllDCtl, reg);
+
+ /* Power down core clock (200MHz) */
+ reg = bc_dec_reg_rd(hw->adp, DecHt_PllACtl);
+ reg |= 0x00008000;
+ bc_dec_reg_wr(hw->adp, DecHt_PllACtl, reg);
+
+ /* Power down core clock (200MHz) */
+ reg = bc_dec_reg_rd(hw->adp, DecHt_PllBCtl);
+ reg |= 0x00008000;
+ bc_dec_reg_wr(hw->adp, DecHt_PllBCtl, reg);
+
+ return BC_STS_SUCCESS;
+}
+
+/************************************************
+**
+*************************************************/
+
+BC_STATUS crystalhd_download_fw(struct crystalhd_adp *adp, void *buffer, uint32_t sz)
+{
+ uint32_t reg_data, cnt, *temp_buff;
+ uint32_t fw_sig_len = 36;
+ uint32_t dram_offset = BC_FWIMG_ST_ADDR, sig_reg;
+
+ BCMLOG_ENTER;
+
+ if (!adp || !buffer || !sz) {
+ BCMLOG_ERR("Invalid Params.\n");
+ return BC_STS_INV_ARG;
+ }
+
+ reg_data = crystalhd_reg_rd(adp, OTP_CMD);
+ if (!(reg_data & 0x02)) {
+ BCMLOG_ERR("Invalid hw config.. otp not programmed\n");
+ return BC_STS_ERROR;
+ }
+
+ reg_data = 0;
+ crystalhd_reg_wr(adp, DCI_CMD, 0);
+ reg_data |= BC_BIT(0);
+ crystalhd_reg_wr(adp, DCI_CMD, reg_data);
+
+ reg_data = 0;
+ cnt = 1000;
+ msleep_interruptible(10);
+
+ while (reg_data != BC_BIT(4)) {
+ reg_data = crystalhd_reg_rd(adp, DCI_STATUS);
+ reg_data &= BC_BIT(4);
+ if (--cnt == 0) {
+ BCMLOG_ERR("Firmware Download RDY Timeout.\n");
+ return BC_STS_TIMEOUT;
+ }
+ }
+
+ msleep_interruptible(10);
+ /* Load the FW to the FW_ADDR field in the DCI_FIRMWARE_ADDR */
+ crystalhd_reg_wr(adp, DCI_FIRMWARE_ADDR, dram_offset);
+ temp_buff = (uint32_t *)buffer;
+ for (cnt = 0; cnt < (sz - fw_sig_len); cnt += 4) {
+ crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (dram_offset >> 19));
+ crystalhd_reg_wr(adp, DCI_FIRMWARE_DATA, *temp_buff);
+ dram_offset += 4;
+ temp_buff++;
+ }
+ msleep_interruptible(10);
+
+ temp_buff++;
+
+ sig_reg = (uint32_t)DCI_SIGNATURE_DATA_7;
+ for (cnt = 0; cnt < 8; cnt++) {
+ uint32_t swapped_data = *temp_buff;
+ swapped_data = bswap_32_1(swapped_data);
+ crystalhd_reg_wr(adp, sig_reg, swapped_data);
+ sig_reg -= 4;
+ temp_buff++;
+ }
+ msleep_interruptible(10);
+
+ reg_data = 0;
+ reg_data |= BC_BIT(1);
+ crystalhd_reg_wr(adp, DCI_CMD, reg_data);
+ msleep_interruptible(10);
+
+ reg_data = 0;
+ reg_data = crystalhd_reg_rd(adp, DCI_STATUS);
+
+ if ((reg_data & BC_BIT(9)) == BC_BIT(9)) {
+ cnt = 1000;
+ while ((reg_data & BC_BIT(0)) != BC_BIT(0)) {
+ reg_data = crystalhd_reg_rd(adp, DCI_STATUS);
+ reg_data &= BC_BIT(0);
+ if (!(--cnt))
+ break;
+ msleep_interruptible(10);
+ }
+ reg_data = 0;
+ reg_data = crystalhd_reg_rd(adp, DCI_CMD);
+ reg_data |= BC_BIT(4);
+ crystalhd_reg_wr(adp, DCI_CMD, reg_data);
+
+ } else {
+ BCMLOG_ERR("F/w Signature mismatch\n");
+ return BC_STS_FW_AUTH_FAILED;
+ }
+
+ BCMLOG(BCMLOG_INFO, "Firmware Downloaded Successfully\n");
+ return BC_STS_SUCCESS;;
+}
+
+BC_STATUS crystalhd_do_fw_cmd(struct crystalhd_hw *hw, BC_FW_CMD *fw_cmd)
+{
+ uint32_t cnt = 0, cmd_res_addr;
+ uint32_t *cmd_buff, *res_buff;
+ wait_queue_head_t fw_cmd_event;
+ int rc = 0;
+ BC_STATUS sts;
+
+ crystalhd_create_event(&fw_cmd_event);
+
+ BCMLOG_ENTER;
+
+ if (!hw || !fw_cmd) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ cmd_buff = fw_cmd->cmd;
+ res_buff = fw_cmd->rsp;
+
+ if (!cmd_buff || !res_buff) {
+ BCMLOG_ERR("Invalid Parameters for F/W Command \n");
+ return BC_STS_INV_ARG;
+ }
+
+ hw->pwr_lock++;
+
+ hw->fwcmd_evt_sts = 0;
+ hw->pfw_cmd_event = &fw_cmd_event;
+
+ /*Write the command to the memory*/
+ crystalhd_mem_wr(hw->adp, TS_Host2CpuSnd, FW_CMD_BUFF_SZ, cmd_buff);
+
+ /*Memory Read for memory arbitrator flush*/
+ crystalhd_mem_rd(hw->adp, TS_Host2CpuSnd, 1, &cnt);
+
+ /* Write the command address to mailbox */
+ bc_dec_reg_wr(hw->adp, Hst2CpuMbx1, TS_Host2CpuSnd);
+ msleep_interruptible(50);
+
+ crystalhd_wait_on_event(&fw_cmd_event, hw->fwcmd_evt_sts, 20000, rc, 0);
+
+ if (!rc) {
+ sts = BC_STS_SUCCESS;
+ } else if (rc == -EBUSY) {
+ BCMLOG_ERR("Firmware command T/O\n");
+ sts = BC_STS_TIMEOUT;
+ } else if (rc == -EINTR) {
+ BCMLOG(BCMLOG_DBG, "FwCmd Wait Signal int.\n");
+ sts = BC_STS_IO_USER_ABORT;
+ } else {
+ BCMLOG_ERR("FwCmd IO Error.\n");
+ sts = BC_STS_IO_ERROR;
+ }
+
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG_ERR("FwCmd Failed.\n");
+ hw->pwr_lock--;
+ return sts;
+ }
+
+ /*Get the Responce Address*/
+ cmd_res_addr = bc_dec_reg_rd(hw->adp, Cpu2HstMbx1);
+
+ /*Read the Response*/
+ crystalhd_mem_rd(hw->adp, cmd_res_addr, FW_CMD_BUFF_SZ, res_buff);
+
+ hw->pwr_lock--;
+
+ if (res_buff[2] != C011_RET_SUCCESS) {
+ BCMLOG_ERR("res_buff[2] != C011_RET_SUCCESS\n");
+ return BC_STS_FW_CMD_ERR;
+ }
+
+ sts = crystalhd_fw_cmd_post_proc(hw, fw_cmd);
+ if (sts != BC_STS_SUCCESS)
+ BCMLOG_ERR("crystalhd_fw_cmd_post_proc Failed.\n");
+
+ return sts;
+}
+
+bool crystalhd_hw_interrupt(struct crystalhd_adp *adp, struct crystalhd_hw *hw)
+{
+ uint32_t intr_sts = 0;
+ uint32_t deco_intr = 0;
+ bool rc = 0;
+
+ if (!adp || !hw->dev_started)
+ return rc;
+
+ hw->stats.num_interrupts++;
+ hw->pwr_lock++;
+
+ deco_intr = bc_dec_reg_rd(adp, Stream2Host_Intr_Sts);
+ intr_sts = crystalhd_reg_rd(adp, INTR_INTR_STATUS);
+
+ if (intr_sts) {
+ /* let system know we processed interrupt..*/
+ rc = 1;
+ hw->stats.dev_interrupts++;
+ }
+
+ if (deco_intr && (deco_intr != 0xdeaddead)) {
+
+ if (deco_intr & 0x80000000) {
+ /*Set the Event and the status flag*/
+ if (hw->pfw_cmd_event) {
+ hw->fwcmd_evt_sts = 1;
+ crystalhd_set_event(hw->pfw_cmd_event);
+ }
+ }
+
+ if (deco_intr & BC_BIT(1))
+ crystalhd_hw_proc_pib(hw);
+
+ bc_dec_reg_wr(adp, Stream2Host_Intr_Sts, deco_intr);
+ /* FIXME: jarod: No udelay? might this be the real reason mini pci-e cards were stalling out? */
+ bc_dec_reg_wr(adp, Stream2Host_Intr_Sts, 0);
+ rc = 1;
+ }
+
+ /* Rx interrupts */
+ crystalhd_rx_isr(hw, intr_sts);
+
+ /* Tx interrupts*/
+ crystalhd_tx_isr(hw, intr_sts);
+
+ /* Clear interrupts */
+ if (rc) {
+ if (intr_sts)
+ crystalhd_reg_wr(adp, INTR_INTR_CLR_REG, intr_sts);
+
+ crystalhd_reg_wr(adp, INTR_EOI_CTRL, 1);
+ }
+
+ hw->pwr_lock--;
+
+ return rc;
+}
+
+BC_STATUS crystalhd_hw_open(struct crystalhd_hw *hw, struct crystalhd_adp *adp)
+{
+ if (!hw || !adp) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ if (hw->dev_started)
+ return BC_STS_SUCCESS;
+
+ memset(hw, 0, sizeof(struct crystalhd_hw));
+
+ hw->adp = adp;
+ spin_lock_init(&hw->lock);
+ spin_lock_init(&hw->rx_lock);
+ /* FIXME: jarod: what are these magic numbers?!? */
+ hw->tx_ioq_tag_seed = 0x70023070;
+ hw->rx_pkt_tag_seed = 0x70029070;
+
+ hw->stop_pending = 0;
+ crystalhd_start_device(hw->adp);
+ hw->dev_started = true;
+
+ /* set initial core clock */
+ hw->core_clock_mhz = CLOCK_PRESET;
+ hw->prev_n = 0;
+ hw->pwr_lock = 0;
+ crystalhd_hw_set_core_clock(hw);
+
+ return BC_STS_SUCCESS;
+}
+
+BC_STATUS crystalhd_hw_close(struct crystalhd_hw *hw)
+{
+ if (!hw) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ if (!hw->dev_started)
+ return BC_STS_SUCCESS;
+
+ /* Stop and DDR sleep will happen in here */
+ crystalhd_hw_suspend(hw);
+ hw->dev_started = false;
+
+ return BC_STS_SUCCESS;
+}
+
+BC_STATUS crystalhd_hw_setup_dma_rings(struct crystalhd_hw *hw)
+{
+ unsigned int i;
+ void *mem;
+ size_t mem_len;
+ dma_addr_t phy_addr;
+ BC_STATUS sts = BC_STS_SUCCESS;
+ crystalhd_rx_dma_pkt *rpkt;
+
+ if (!hw || !hw->adp) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ sts = crystalhd_hw_create_ioqs(hw);
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG_ERR("Failed to create IOQs..\n");
+ return sts;
+ }
+
+ mem_len = BC_LINK_MAX_SGLS * sizeof(dma_descriptor);
+
+ for (i = 0; i < BC_TX_LIST_CNT; i++) {
+ mem = bc_kern_dma_alloc(hw->adp, mem_len, &phy_addr);
+ if (mem) {
+ memset(mem, 0, mem_len);
+ } else {
+ BCMLOG_ERR("Insufficient Memory For TX\n");
+ crystalhd_hw_free_dma_rings(hw);
+ return BC_STS_INSUFF_RES;
+ }
+ /* rx_pkt_pool -- static memory allocation */
+ hw->tx_pkt_pool[i].desc_mem.pdma_desc_start = mem;
+ hw->tx_pkt_pool[i].desc_mem.phy_addr = phy_addr;
+ hw->tx_pkt_pool[i].desc_mem.sz = BC_LINK_MAX_SGLS *
+ sizeof(dma_descriptor);
+ hw->tx_pkt_pool[i].list_tag = 0;
+
+ /* Add TX dma requests to Free Queue..*/
+ sts = crystalhd_dioq_add(hw->tx_freeq,
+ &hw->tx_pkt_pool[i], false, 0);
+ if (sts != BC_STS_SUCCESS) {
+ crystalhd_hw_free_dma_rings(hw);
+ return sts;
+ }
+ }
+
+ for (i = 0; i < BC_RX_LIST_CNT; i++) {
+ rpkt = kzalloc(sizeof(*rpkt), GFP_KERNEL);
+ if (!rpkt) {
+ BCMLOG_ERR("Insufficient Memory For RX\n");
+ crystalhd_hw_free_dma_rings(hw);
+ return BC_STS_INSUFF_RES;
+ }
+
+ mem = bc_kern_dma_alloc(hw->adp, mem_len, &phy_addr);
+ if (mem) {
+ memset(mem, 0, mem_len);
+ } else {
+ BCMLOG_ERR("Insufficient Memory For RX\n");
+ crystalhd_hw_free_dma_rings(hw);
+ return BC_STS_INSUFF_RES;
+ }
+ rpkt->desc_mem.pdma_desc_start = mem;
+ rpkt->desc_mem.phy_addr = phy_addr;
+ rpkt->desc_mem.sz = BC_LINK_MAX_SGLS * sizeof(dma_descriptor);
+ rpkt->pkt_tag = hw->rx_pkt_tag_seed + i;
+ crystalhd_hw_free_rx_pkt(hw, rpkt);
+ }
+
+ return BC_STS_SUCCESS;
+}
+
+BC_STATUS crystalhd_hw_free_dma_rings(struct crystalhd_hw *hw)
+{
+ unsigned int i;
+ crystalhd_rx_dma_pkt *rpkt = NULL;
+
+ if (!hw || !hw->adp) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ /* Delete all IOQs.. */
+ crystalhd_hw_delete_ioqs(hw);
+
+ for (i = 0; i < BC_TX_LIST_CNT; i++) {
+ if (hw->tx_pkt_pool[i].desc_mem.pdma_desc_start) {
+ bc_kern_dma_free(hw->adp,
+ hw->tx_pkt_pool[i].desc_mem.sz,
+ hw->tx_pkt_pool[i].desc_mem.pdma_desc_start,
+ hw->tx_pkt_pool[i].desc_mem.phy_addr);
+
+ hw->tx_pkt_pool[i].desc_mem.pdma_desc_start = NULL;
+ }
+ }
+
+ BCMLOG(BCMLOG_DBG, "Releasing RX Pkt pool\n");
+ do {
+ rpkt = crystalhd_hw_alloc_rx_pkt(hw);
+ if (!rpkt)
+ break;
+ bc_kern_dma_free(hw->adp, rpkt->desc_mem.sz,
+ rpkt->desc_mem.pdma_desc_start,
+ rpkt->desc_mem.phy_addr);
+ kfree(rpkt);
+ } while (rpkt);
+
+ return BC_STS_SUCCESS;
+}
+
+BC_STATUS crystalhd_hw_post_tx(struct crystalhd_hw *hw, crystalhd_dio_req *ioreq,
+ hw_comp_callback call_back,
+ wait_queue_head_t *cb_event, uint32_t *list_id,
+ uint8_t data_flags)
+{
+ tx_dma_pkt *tx_dma_packet = NULL;
+ uint32_t first_desc_u_addr, first_desc_l_addr;
+ uint32_t low_addr, high_addr;
+ addr_64 desc_addr;
+ BC_STATUS sts, add_sts;
+ uint32_t dummy_index = 0;
+ unsigned long flags;
+ bool rc;
+
+ if (!hw || !ioreq || !call_back || !cb_event || !list_id) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ /*
+ * Since we hit code in busy condition very frequently,
+ * we will check the code in status first before
+ * checking the availability of free elem.
+ *
+ * This will avoid the Q fetch/add in normal condition.
+ */
+ rc = crystalhd_code_in_full(hw->adp, ioreq->uinfo.xfr_len,
+ false, data_flags);
+ if (rc) {
+ hw->stats.cin_busy++;
+ return BC_STS_BUSY;
+ }
+
+ /* Get a list from TxFreeQ */
+ tx_dma_packet = (tx_dma_pkt *)crystalhd_dioq_fetch(hw->tx_freeq);
+ if (!tx_dma_packet) {
+ BCMLOG_ERR("No empty elements..\n");
+ return BC_STS_ERR_USAGE;
+ }
+
+ sts = crystalhd_xlat_sgl_to_dma_desc(ioreq,
+ &tx_dma_packet->desc_mem,
+ &dummy_index);
+ if (sts != BC_STS_SUCCESS) {
+ add_sts = crystalhd_dioq_add(hw->tx_freeq, tx_dma_packet,
+ false, 0);
+ if (add_sts != BC_STS_SUCCESS)
+ BCMLOG_ERR("double fault..\n");
+
+ return sts;
+ }
+
+ hw->pwr_lock++;
+
+ desc_addr.full_addr = tx_dma_packet->desc_mem.phy_addr;
+ low_addr = desc_addr.low_part;
+ high_addr = desc_addr.high_part;
+
+ tx_dma_packet->call_back = call_back;
+ tx_dma_packet->cb_event = cb_event;
+ tx_dma_packet->dio_req = ioreq;
+
+ spin_lock_irqsave(&hw->lock, flags);
+
+ if (hw->tx_list_post_index == 0) {
+ first_desc_u_addr = MISC1_TX_FIRST_DESC_U_ADDR_LIST0;
+ first_desc_l_addr = MISC1_TX_FIRST_DESC_L_ADDR_LIST0;
+ } else {
+ first_desc_u_addr = MISC1_TX_FIRST_DESC_U_ADDR_LIST1;
+ first_desc_l_addr = MISC1_TX_FIRST_DESC_L_ADDR_LIST1;
+ }
+
+ *list_id = tx_dma_packet->list_tag = hw->tx_ioq_tag_seed +
+ hw->tx_list_post_index;
+
+ hw->tx_list_post_index = (hw->tx_list_post_index + 1) % DMA_ENGINE_CNT;
+
+ spin_unlock_irqrestore(&hw->lock, flags);
+
+
+ /* Insert in Active Q..*/
+ crystalhd_dioq_add(hw->tx_actq, tx_dma_packet, false,
+ tx_dma_packet->list_tag);
+
+ /*
+ * Interrupt will come as soon as you write
+ * the valid bit. So be ready for that. All
+ * the initialization should happen before that.
+ */
+ crystalhd_start_tx_dma_engine(hw);
+ crystalhd_reg_wr(hw->adp, first_desc_u_addr, desc_addr.high_part);
+
+ crystalhd_reg_wr(hw->adp, first_desc_l_addr, desc_addr.low_part | 0x01);
+ /* Be sure we set the valid bit ^^^^ */
+
+ return BC_STS_SUCCESS;
+}
+
+/*
+ * This is a force cancel and we are racing with ISR.
+ *
+ * Will try to remove the req from ActQ before ISR gets it.
+ * If ISR gets it first then the completion happens in the
+ * normal path and we will return _STS_NO_DATA from here.
+ *
+ * FIX_ME: Not Tested the actual condition..
+ */
+BC_STATUS crystalhd_hw_cancel_tx(struct crystalhd_hw *hw, uint32_t list_id)
+{
+ if (!hw || !list_id) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ crystalhd_stop_tx_dma_engine(hw);
+ crystalhd_hw_tx_req_complete(hw, list_id, BC_STS_IO_USER_ABORT);
+
+ return BC_STS_SUCCESS;
+}
+
+BC_STATUS crystalhd_hw_add_cap_buffer(struct crystalhd_hw *hw,
+ crystalhd_dio_req *ioreq, bool en_post)
+{
+ crystalhd_rx_dma_pkt *rpkt;
+ uint32_t tag, uv_desc_ix = 0;
+ BC_STATUS sts;
+
+ if (!hw || !ioreq) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ rpkt = crystalhd_hw_alloc_rx_pkt(hw);
+ if (!rpkt) {
+ BCMLOG_ERR("Insufficient resources\n");
+ return BC_STS_INSUFF_RES;
+ }
+
+ rpkt->dio_req = ioreq;
+ tag = rpkt->pkt_tag;
+
+ sts = crystalhd_xlat_sgl_to_dma_desc(ioreq, &rpkt->desc_mem, &uv_desc_ix);
+ if (sts != BC_STS_SUCCESS)
+ return sts;
+
+ rpkt->uv_phy_addr = 0;
+
+ /* Store the address of UV in the rx packet for post*/
+ if (uv_desc_ix)
+ rpkt->uv_phy_addr = rpkt->desc_mem.phy_addr +
+ (sizeof(dma_descriptor) * (uv_desc_ix + 1));
+
+ if (en_post)
+ sts = crystalhd_hw_post_cap_buff(hw, rpkt);
+ else
+ sts = crystalhd_dioq_add(hw->rx_freeq, rpkt, false, tag);
+
+ return sts;
+}
+
+BC_STATUS crystalhd_hw_get_cap_buffer(struct crystalhd_hw *hw,
+ BC_PIC_INFO_BLOCK *pib,
+ crystalhd_dio_req **ioreq)
+{
+ crystalhd_rx_dma_pkt *rpkt;
+ uint32_t timeout = BC_PROC_OUTPUT_TIMEOUT / 1000;
+ uint32_t sig_pending = 0;
+
+
+ if (!hw || !ioreq || !pib) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ rpkt = crystalhd_dioq_fetch_wait(hw->rx_rdyq, timeout, &sig_pending);
+ if (!rpkt) {
+ if (sig_pending) {
+ BCMLOG(BCMLOG_INFO, "wait on frame time out %d\n", sig_pending);
+ return BC_STS_IO_USER_ABORT;
+ } else {
+ return BC_STS_TIMEOUT;
+ }
+ }
+
+ rpkt->dio_req->uinfo.comp_flags = rpkt->flags;
+
+ if (rpkt->flags & COMP_FLAG_PIB_VALID)
+ memcpy(pib, &rpkt->pib, sizeof(*pib));
+
+ *ioreq = rpkt->dio_req;
+
+ crystalhd_hw_free_rx_pkt(hw, rpkt);
+
+ return BC_STS_SUCCESS;
+}
+
+BC_STATUS crystalhd_hw_start_capture(struct crystalhd_hw *hw)
+{
+ crystalhd_rx_dma_pkt *rx_pkt;
+ BC_STATUS sts;
+ uint32_t i;
+
+ if (!hw) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ /* This is start of capture.. Post to both the lists.. */
+ for (i = 0; i < DMA_ENGINE_CNT; i++) {
+ rx_pkt = crystalhd_dioq_fetch(hw->rx_freeq);
+ if (!rx_pkt)
+ return BC_STS_NO_DATA;
+ sts = crystalhd_hw_post_cap_buff(hw, rx_pkt);
+ if (BC_STS_SUCCESS != sts)
+ break;
+
+ }
+
+ return BC_STS_SUCCESS;
+}
+
+BC_STATUS crystalhd_hw_stop_capture(struct crystalhd_hw *hw)
+{
+ void *temp = NULL;
+
+ if (!hw) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ crystalhd_stop_rx_dma_engine(hw);
+
+ do {
+ temp = crystalhd_dioq_fetch(hw->rx_freeq);
+ if (temp)
+ crystalhd_rx_pkt_rel_call_back(hw, temp);
+ } while (temp);
+
+ return BC_STS_SUCCESS;
+}
+
+BC_STATUS crystalhd_hw_pause(struct crystalhd_hw *hw)
+{
+ hw->stats.pause_cnt++;
+ hw->stop_pending = 1;
+
+ if ((hw->rx_list_sts[0] == sts_free) &&
+ (hw->rx_list_sts[1] == sts_free))
+ crystalhd_hw_finalize_pause(hw);
+
+ return BC_STS_SUCCESS;
+}
+
+BC_STATUS crystalhd_hw_unpause(struct crystalhd_hw *hw)
+{
+ BC_STATUS sts;
+ uint32_t aspm;
+
+ hw->stop_pending = 0;
+
+ aspm = crystalhd_reg_rd(hw->adp, PCIE_DLL_DATA_LINK_CONTROL);
+ aspm &= ~ASPM_L1_ENABLE;
+/* NAREN BCMLOG(BCMLOG_INFO, "aspm off\n"); */
+ crystalhd_reg_wr(hw->adp, PCIE_DLL_DATA_LINK_CONTROL, aspm);
+
+ sts = crystalhd_hw_start_capture(hw);
+ return sts;
+}
+
+BC_STATUS crystalhd_hw_suspend(struct crystalhd_hw *hw)
+{
+ BC_STATUS sts;
+
+ if (!hw) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ sts = crystalhd_put_ddr2sleep(hw);
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG_ERR("Failed to Put DDR To Sleep!!\n");
+ return BC_STS_ERROR;
+ }
+
+ if (!crystalhd_stop_device(hw->adp)) {
+ BCMLOG_ERR("Failed to Stop Device!!\n");
+ return BC_STS_ERROR;
+ }
+
+ return BC_STS_SUCCESS;
+}
+
+void crystalhd_hw_stats(struct crystalhd_hw *hw, struct crystalhd_hw_stats *stats)
+{
+ if (!hw) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return;
+ }
+
+ /* if called w/NULL stats, its a req to zero out the stats */
+ if (!stats) {
+ memset(&hw->stats, 0, sizeof(hw->stats));
+ return;
+ }
+
+ hw->stats.freeq_count = crystalhd_dioq_count(hw->rx_freeq);
+ hw->stats.rdyq_count = crystalhd_dioq_count(hw->rx_rdyq);
+ memcpy(stats, &hw->stats, sizeof(*stats));
+}
+
+BC_STATUS crystalhd_hw_set_core_clock(struct crystalhd_hw *hw)
+{
+ uint32_t reg, n, i;
+ uint32_t vco_mg, refresh_reg;
+
+ if (!hw) {
+ BCMLOG_ERR("Invalid Arguments\n");
+ return BC_STS_INV_ARG;
+ }
+
+ /* FIXME: jarod: wha? */
+ /*n = (hw->core_clock_mhz * 3) / 20 + 1; */
+ n = hw->core_clock_mhz/5;
+
+ if (n == hw->prev_n)
+ return BC_STS_CLK_NOCHG;
+
+ if (hw->pwr_lock > 0) {
+ /* BCMLOG(BCMLOG_INFO,"pwr_lock is %u\n", hw->pwr_lock) */
+ return BC_STS_CLK_NOCHG;
+ }
+
+ i = n * 27;
+ if (i < 560)
+ vco_mg = 0;
+ else if (i < 900)
+ vco_mg = 1;
+ else if (i < 1030)
+ vco_mg = 2;
+ else
+ vco_mg = 3;
+
+ reg = bc_dec_reg_rd(hw->adp, DecHt_PllACtl);
+
+ reg &= 0xFFFFCFC0;
+ reg |= n;
+ reg |= vco_mg << 12;
+
+ BCMLOG(BCMLOG_INFO, "clock is moving to %d with n %d with vco_mg %d\n",
+ hw->core_clock_mhz, n, vco_mg);
+
+ /* Change the DRAM refresh rate to accomodate the new frequency */
+ /* refresh reg = ((refresh_rate * clock_rate)/16) - 1; rounding up*/
+ refresh_reg = (7 * hw->core_clock_mhz / 16);
+ bc_dec_reg_wr(hw->adp, SDRAM_REF_PARAM, ((1 << 12) | refresh_reg));
+
+ bc_dec_reg_wr(hw->adp, DecHt_PllACtl, reg);
+
+ i = 0;
+
+ for (i = 0; i < 10; i++) {
+ reg = bc_dec_reg_rd(hw->adp, DecHt_PllACtl);
+
+ if (reg & 0x00020000) {
+ hw->prev_n = n;
+ /* FIXME: jarod: outputting a random "C" is... confusing... */
+ BCMLOG(BCMLOG_INFO, "C");
+ return BC_STS_SUCCESS;
+ } else {
+ msleep_interruptible(10);
+ }
+ }
+ BCMLOG(BCMLOG_INFO, "clk change failed\n");
+ return BC_STS_CLK_NOCHG;
+}
diff --git a/drivers/staging/crystalhd/crystalhd_hw.h b/drivers/staging/crystalhd/crystalhd_hw.h
new file mode 100644
index 000000000000..1c6318e912ac
--- /dev/null
+++ b/drivers/staging/crystalhd/crystalhd_hw.h
@@ -0,0 +1,398 @@
+/***************************************************************************
+ * Copyright (c) 2005-2009, Broadcom Corporation.
+ *
+ * Name: crystalhd_hw . h
+ *
+ * Description:
+ * BCM70012 Linux driver hardware layer.
+ *
+ * HISTORY:
+ *
+ **********************************************************************
+ * This file is part of the crystalhd device driver.
+ *
+ * This driver 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.
+ *
+ * This driver 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 driver. If not, see <http://www.gnu.org/licenses/>.
+ **********************************************************************/
+
+#ifndef _CRYSTALHD_HW_H_
+#define _CRYSTALHD_HW_H_
+
+#include "crystalhd_misc.h"
+#include "crystalhd_fw_if.h"
+
+/* HW constants..*/
+#define DMA_ENGINE_CNT 2
+#define MAX_PIB_Q_DEPTH 64
+#define MIN_PIB_Q_DEPTH 2
+#define WR_POINTER_OFF 4
+
+#define ASPM_L1_ENABLE (BC_BIT(27))
+
+/*************************************************
+ 7412 Decoder Registers.
+**************************************************/
+#define FW_CMD_BUFF_SZ 64
+#define TS_Host2CpuSnd 0x00000100
+#define Hst2CpuMbx1 0x00100F00
+#define Cpu2HstMbx1 0x00100F04
+#define MbxStat1 0x00100F08
+#define Stream2Host_Intr_Sts 0x00100F24
+#define C011_RET_SUCCESS 0x0 /* Reutrn status of firmware command. */
+
+/* TS input status register */
+#define TS_StreamAFIFOStatus 0x0010044C
+#define TS_StreamBFIFOStatus 0x0010084C
+
+/*UART Selection definitions*/
+#define UartSelectA 0x00100300
+#define UartSelectB 0x00100304
+
+#define BSVS_UART_DEC_NONE 0x00
+#define BSVS_UART_DEC_OUTER 0x01
+#define BSVS_UART_DEC_INNER 0x02
+#define BSVS_UART_STREAM 0x03
+
+/* Code-In fifo */
+#define REG_DecCA_RegCinCTL 0xa00
+#define REG_DecCA_RegCinBase 0xa0c
+#define REG_DecCA_RegCinEnd 0xa10
+#define REG_DecCA_RegCinWrPtr 0xa04
+#define REG_DecCA_RegCinRdPtr 0xa08
+
+#define REG_Dec_TsUser0Base 0x100864
+#define REG_Dec_TsUser0Rdptr 0x100868
+#define REG_Dec_TsUser0Wrptr 0x10086C
+#define REG_Dec_TsUser0End 0x100874
+
+/* ASF Case ...*/
+#define REG_Dec_TsAudCDB2Base 0x10036c
+#define REG_Dec_TsAudCDB2Rdptr 0x100378
+#define REG_Dec_TsAudCDB2Wrptr 0x100374
+#define REG_Dec_TsAudCDB2End 0x100370
+
+/* DRAM bringup Registers */
+#define SDRAM_PARAM 0x00040804
+#define SDRAM_PRECHARGE 0x000408B0
+#define SDRAM_EXT_MODE 0x000408A4
+#define SDRAM_MODE 0x000408A0
+#define SDRAM_REFRESH 0x00040890
+#define SDRAM_REF_PARAM 0x00040808
+
+#define DecHt_PllACtl 0x34000C
+#define DecHt_PllBCtl 0x340010
+#define DecHt_PllCCtl 0x340014
+#define DecHt_PllDCtl 0x340034
+#define DecHt_PllECtl 0x340038
+#define AUD_DSP_MISC_SOFT_RESET 0x00240104
+#define AIO_MISC_PLL_RESET 0x0026000C
+#define PCIE_CLK_REQ_REG 0xDC
+#define PCI_CLK_REQ_ENABLE (BC_BIT(8))
+
+/*************************************************
+ F/W Copy engine definitions..
+**************************************************/
+#define BC_FWIMG_ST_ADDR 0x00000000
+/* FIXME: jarod: there's a kernel function that'll do this for us... */
+#define rotr32_1(x, n) (((x) >> n) | ((x) << (32 - n)))
+#define bswap_32_1(x) ((rotr32_1((x), 24) & 0x00ff00ff) | (rotr32_1((x), 8) & 0xff00ff00))
+
+#define DecHt_HostSwReset 0x340000
+#define BC_DRAM_FW_CFG_ADDR 0x001c2000
+
+typedef union _addr_64_ {
+ struct {
+ uint32_t low_part;
+ uint32_t high_part;
+ };
+
+ uint64_t full_addr;
+
+} addr_64;
+
+typedef union _intr_mask_reg_ {
+ struct {
+ uint32_t mask_tx_done:1;
+ uint32_t mask_tx_err:1;
+ uint32_t mask_rx_done:1;
+ uint32_t mask_rx_err:1;
+ uint32_t mask_pcie_err:1;
+ uint32_t mask_pcie_rbusmast_err:1;
+ uint32_t mask_pcie_rgr_bridge:1;
+ uint32_t reserved:25;
+ };
+
+ uint32_t whole_reg;
+
+} intr_mask_reg;
+
+typedef union _link_misc_perst_deco_ctrl_ {
+ struct {
+ uint32_t bcm7412_rst:1; /* 1 -> BCM7412 is held in reset. Reset value 1.*/
+ uint32_t reserved0:3; /* Reserved.No Effect*/
+ uint32_t stop_bcm_7412_clk:1; /* 1 ->Stops branch of 27MHz clk used to clk BCM7412*/
+ uint32_t reserved1:27; /* Reseved. No Effect*/
+ };
+
+ uint32_t whole_reg;
+
+} link_misc_perst_deco_ctrl;
+
+typedef union _link_misc_perst_clk_ctrl_ {
+ struct {
+ uint32_t sel_alt_clk:1; /* When set, selects a 6.75MHz clock as the source of core_clk */
+ uint32_t stop_core_clk:1; /* When set, stops the branch of core_clk that is not needed for low power operation */
+ uint32_t pll_pwr_dn:1; /* When set, powers down the main PLL. The alternate clock bit should be set
+ to select an alternate clock before setting this bit.*/
+ uint32_t reserved0:5; /* Reserved */
+ uint32_t pll_mult:8; /* This setting controls the multiplier for the PLL. */
+ uint32_t pll_div:4; /* This setting controls the divider for the PLL. */
+ uint32_t reserved1:12; /* Reserved */
+ };
+
+ uint32_t whole_reg;
+
+} link_misc_perst_clk_ctrl;
+
+
+typedef union _link_misc_perst_decoder_ctrl_ {
+ struct {
+ uint32_t bcm_7412_rst:1; /* 1 -> BCM7412 is held in reset. Reset value 1.*/
+ uint32_t res0:3; /* Reserved.No Effect*/
+ uint32_t stop_7412_clk:1; /* 1 ->Stops branch of 27MHz clk used to clk BCM7412*/
+ uint32_t res1:27; /* Reseved. No Effect */
+ };
+
+ uint32_t whole_reg;
+
+} link_misc_perst_decoder_ctrl;
+
+
+typedef union _desc_low_addr_reg_ {
+ struct {
+ uint32_t list_valid:1;
+ uint32_t reserved:4;
+ uint32_t low_addr:27;
+ };
+
+ uint32_t whole_reg;
+
+} desc_low_addr_reg;
+
+typedef struct _dma_descriptor_ { /* 8 32-bit values */
+ /* 0th u32 */
+ uint32_t sdram_buff_addr:28; /* bits 0-27: SDRAM Address */
+ uint32_t res0:4; /* bits 28-31: Reserved */
+
+ /* 1st u32 */
+ uint32_t buff_addr_low; /* 1 buffer address low */
+ uint32_t buff_addr_high; /* 2 buffer address high */
+
+ /* 3rd u32 */
+ uint32_t res2:2; /* 0-1 - Reserved */
+ uint32_t xfer_size:23; /* 2-24 = Xfer size in words */
+ uint32_t res3:6; /* 25-30 reserved */
+ uint32_t intr_enable:1; /* 31 - Interrupt After this desc */
+
+ /* 4th u32 */
+ uint32_t endian_xlat_align:2; /* 0-1 Endian Translation */
+ uint32_t next_desc_cont:1; /* 2 - Next desc is in contig memory */
+ uint32_t res4:25; /* 3 - 27 Reserved bits */
+ uint32_t fill_bytes:2; /* 28-29 Bits Fill Bytes */
+ uint32_t dma_dir:1; /* 30 bit DMA Direction */
+ uint32_t last_rec_indicator:1; /* 31 bit Last Record Indicator */
+
+ /* 5th u32 */
+ uint32_t next_desc_addr_low; /* 32-bits Next Desc Addr lower */
+
+ /* 6th u32 */
+ uint32_t next_desc_addr_high; /* 32-bits Next Desc Addr Higher */
+
+ /* 7th u32 */
+ uint32_t res8; /* Last 32bits reserved */
+
+} dma_descriptor, *pdma_descriptor;
+
+/*
+ * We will allocate the memory in 4K pages
+ * the linked list will be a list of 32 byte descriptors.
+ * The virtual address will determine what should be freed.
+ */
+typedef struct _dma_desc_mem_ {
+ pdma_descriptor pdma_desc_start; /* 32-bytes for dma descriptor. should be first element */
+ dma_addr_t phy_addr; /* physical address of each DMA desc */
+ uint32_t sz;
+ struct _dma_desc_mem_ *Next; /* points to Next Descriptor in chain */
+
+} dma_desc_mem, *pdma_desc_mem;
+
+
+
+typedef enum _list_sts_ {
+ sts_free = 0,
+
+ /* RX-Y Bits 0:7 */
+ rx_waiting_y_intr = 0x00000001,
+ rx_y_error = 0x00000004,
+
+ /* RX-UV Bits 8:16 */
+ rx_waiting_uv_intr = 0x0000100,
+ rx_uv_error = 0x0000400,
+
+ rx_sts_waiting = (rx_waiting_y_intr|rx_waiting_uv_intr),
+ rx_sts_error = (rx_y_error|rx_uv_error),
+
+ rx_y_mask = 0x000000FF,
+ rx_uv_mask = 0x0000FF00,
+
+} list_sts;
+
+typedef struct _tx_dma_pkt_ {
+ dma_desc_mem desc_mem;
+ hw_comp_callback call_back;
+ crystalhd_dio_req *dio_req;
+ wait_queue_head_t *cb_event;
+ uint32_t list_tag;
+
+} tx_dma_pkt;
+
+typedef struct _crystalhd_rx_dma_pkt {
+ dma_desc_mem desc_mem;
+ crystalhd_dio_req *dio_req;
+ uint32_t pkt_tag;
+ uint32_t flags;
+ BC_PIC_INFO_BLOCK pib;
+ dma_addr_t uv_phy_addr;
+ struct _crystalhd_rx_dma_pkt *next;
+
+} crystalhd_rx_dma_pkt;
+
+struct crystalhd_hw_stats{
+ uint32_t rx_errors;
+ uint32_t tx_errors;
+ uint32_t freeq_count;
+ uint32_t rdyq_count;
+ uint32_t num_interrupts;
+ uint32_t dev_interrupts;
+ uint32_t cin_busy;
+ uint32_t pause_cnt;
+};
+
+struct crystalhd_hw {
+ tx_dma_pkt tx_pkt_pool[DMA_ENGINE_CNT];
+ spinlock_t lock;
+
+ uint32_t tx_ioq_tag_seed;
+ uint32_t tx_list_post_index;
+
+ crystalhd_rx_dma_pkt *rx_pkt_pool_head;
+ uint32_t rx_pkt_tag_seed;
+
+ bool dev_started;
+ void *adp;
+
+ wait_queue_head_t *pfw_cmd_event;
+ int fwcmd_evt_sts;
+
+ uint32_t pib_del_Q_addr;
+ uint32_t pib_rel_Q_addr;
+
+ crystalhd_dioq_t *tx_freeq;
+ crystalhd_dioq_t *tx_actq;
+
+ /* Rx DMA Engine Specific Locks */
+ spinlock_t rx_lock;
+ uint32_t rx_list_post_index;
+ list_sts rx_list_sts[DMA_ENGINE_CNT];
+ crystalhd_dioq_t *rx_rdyq;
+ crystalhd_dioq_t *rx_freeq;
+ crystalhd_dioq_t *rx_actq;
+ uint32_t stop_pending;
+
+ /* HW counters.. */
+ struct crystalhd_hw_stats stats;
+
+ /* Core clock in MHz */
+ uint32_t core_clock_mhz;
+ uint32_t prev_n;
+ uint32_t pwr_lock;
+};
+
+/* Clock defines for power control */
+#define CLOCK_PRESET 175
+
+/* DMA engine register BIT mask wrappers.. */
+#define DMA_START_BIT MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_RUN_STOP_MASK
+
+#define GET_RX_INTR_MASK (INTR_INTR_STATUS_L1_UV_RX_DMA_ERR_INTR_MASK | \
+ INTR_INTR_STATUS_L1_UV_RX_DMA_DONE_INTR_MASK | \
+ INTR_INTR_STATUS_L1_Y_RX_DMA_ERR_INTR_MASK | \
+ INTR_INTR_STATUS_L1_Y_RX_DMA_DONE_INTR_MASK | \
+ INTR_INTR_STATUS_L0_UV_RX_DMA_ERR_INTR_MASK | \
+ INTR_INTR_STATUS_L0_UV_RX_DMA_DONE_INTR_MASK | \
+ INTR_INTR_STATUS_L0_Y_RX_DMA_ERR_INTR_MASK | \
+ INTR_INTR_STATUS_L0_Y_RX_DMA_DONE_INTR_MASK)
+
+#define GET_Y0_ERR_MSK (MISC1_Y_RX_ERROR_STATUS_RX_L0_OVERRUN_ERROR_MASK | \
+ MISC1_Y_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK | \
+ MISC1_Y_RX_ERROR_STATUS_RX_L0_DESC_TX_ABORT_ERRORS_MASK | \
+ MISC1_Y_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK)
+
+#define GET_UV0_ERR_MSK (MISC1_UV_RX_ERROR_STATUS_RX_L0_OVERRUN_ERROR_MASK | \
+ MISC1_UV_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK | \
+ MISC1_UV_RX_ERROR_STATUS_RX_L0_DESC_TX_ABORT_ERRORS_MASK | \
+ MISC1_UV_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK)
+
+#define GET_Y1_ERR_MSK (MISC1_Y_RX_ERROR_STATUS_RX_L1_OVERRUN_ERROR_MASK | \
+ MISC1_Y_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK | \
+ MISC1_Y_RX_ERROR_STATUS_RX_L1_DESC_TX_ABORT_ERRORS_MASK | \
+ MISC1_Y_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK)
+
+#define GET_UV1_ERR_MSK (MISC1_UV_RX_ERROR_STATUS_RX_L1_OVERRUN_ERROR_MASK | \
+ MISC1_UV_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK | \
+ MISC1_UV_RX_ERROR_STATUS_RX_L1_DESC_TX_ABORT_ERRORS_MASK | \
+ MISC1_UV_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK)
+
+
+/**** API Exposed to the other layers ****/
+BC_STATUS crystalhd_download_fw(struct crystalhd_adp *adp,
+ void *buffer, uint32_t sz);
+BC_STATUS crystalhd_do_fw_cmd(struct crystalhd_hw *hw, BC_FW_CMD *fw_cmd);
+bool crystalhd_hw_interrupt(struct crystalhd_adp *adp, struct crystalhd_hw *hw);
+BC_STATUS crystalhd_hw_open(struct crystalhd_hw *, struct crystalhd_adp *);
+BC_STATUS crystalhd_hw_close(struct crystalhd_hw *);
+BC_STATUS crystalhd_hw_setup_dma_rings(struct crystalhd_hw *);
+BC_STATUS crystalhd_hw_free_dma_rings(struct crystalhd_hw *);
+
+
+BC_STATUS crystalhd_hw_post_tx(struct crystalhd_hw *hw, crystalhd_dio_req *ioreq,
+ hw_comp_callback call_back,
+ wait_queue_head_t *cb_event,
+ uint32_t *list_id, uint8_t data_flags);
+
+BC_STATUS crystalhd_hw_pause(struct crystalhd_hw *hw);
+BC_STATUS crystalhd_hw_unpause(struct crystalhd_hw *hw);
+BC_STATUS crystalhd_hw_suspend(struct crystalhd_hw *hw);
+BC_STATUS crystalhd_hw_cancel_tx(struct crystalhd_hw *hw, uint32_t list_id);
+BC_STATUS crystalhd_hw_add_cap_buffer(struct crystalhd_hw *hw,
+ crystalhd_dio_req *ioreq, bool en_post);
+BC_STATUS crystalhd_hw_get_cap_buffer(struct crystalhd_hw *hw,
+ BC_PIC_INFO_BLOCK *pib,
+ crystalhd_dio_req **ioreq);
+BC_STATUS crystalhd_hw_stop_capture(struct crystalhd_hw *hw);
+BC_STATUS crystalhd_hw_start_capture(struct crystalhd_hw *hw);
+void crystalhd_hw_stats(struct crystalhd_hw *hw, struct crystalhd_hw_stats *stats);
+
+/* API to program the core clock on the decoder */
+BC_STATUS crystalhd_hw_set_core_clock(struct crystalhd_hw *);
+
+#endif
diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c
new file mode 100644
index 000000000000..3eac70aa213c
--- /dev/null
+++ b/drivers/staging/crystalhd/crystalhd_lnx.c
@@ -0,0 +1,765 @@
+/***************************************************************************
+ BCM70010 Linux driver
+ Copyright (c) 2005-2009, Broadcom Corporation.
+
+ This driver 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.
+
+ This driver 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 driver. If not, see <http://www.gnu.org/licenses/>.
+***************************************************************************/
+
+#include <linux/version.h>
+
+#include "crystalhd_lnx.h"
+
+static struct class *crystalhd_class;
+
+static struct crystalhd_adp *g_adp_info;
+
+static irqreturn_t chd_dec_isr(int irq, void *arg)
+{
+ struct crystalhd_adp *adp = (struct crystalhd_adp *) arg;
+ int rc = 0;
+ if (adp)
+ rc = crystalhd_cmd_interrupt(&adp->cmds);
+
+ return IRQ_RETVAL(rc);
+}
+
+static int chd_dec_enable_int(struct crystalhd_adp *adp)
+{
+ int rc = 0;
+
+ if (!adp || !adp->pdev) {
+ BCMLOG_ERR("Invalid arg!!\n");
+ return -EINVAL;
+ }
+
+ if (adp->pdev->msi_enabled)
+ adp->msi = 1;
+ else
+ adp->msi = pci_enable_msi(adp->pdev);
+
+ rc = request_irq(adp->pdev->irq, chd_dec_isr, IRQF_SHARED,
+ adp->name, (void *)adp);
+ if (rc) {
+ BCMLOG_ERR("Interrupt request failed.. \n");
+ pci_disable_msi(adp->pdev);
+ }
+
+ return rc;
+}
+
+static int chd_dec_disable_int(struct crystalhd_adp *adp)
+{
+ if (!adp || !adp->pdev) {
+ BCMLOG_ERR("Invalid arg!!\n");
+ return -EINVAL;
+ }
+
+ free_irq(adp->pdev->irq, adp);
+
+ if (adp->msi)
+ pci_disable_msi(adp->pdev);
+
+ return 0;
+}
+
+crystalhd_ioctl_data *chd_dec_alloc_iodata(struct crystalhd_adp *adp, bool isr)
+{
+ unsigned long flags = 0;
+ crystalhd_ioctl_data *temp;
+
+ if (!adp)
+ return NULL;
+
+ spin_lock_irqsave(&adp->lock, flags);
+
+ temp = adp->idata_free_head;
+ if (temp) {
+ adp->idata_free_head = adp->idata_free_head->next;
+ memset(temp, 0, sizeof(*temp));
+ }
+
+ spin_unlock_irqrestore(&adp->lock, flags);
+ return temp;
+}
+
+void chd_dec_free_iodata(struct crystalhd_adp *adp, crystalhd_ioctl_data *iodata,
+ bool isr)
+{
+ unsigned long flags = 0;
+
+ if (!adp || !iodata)
+ return;
+
+ spin_lock_irqsave(&adp->lock, flags);
+ iodata->next = adp->idata_free_head;
+ adp->idata_free_head = iodata;
+ spin_unlock_irqrestore(&adp->lock, flags);
+}
+
+static inline int crystalhd_user_data(unsigned long ud, void *dr, int size, int set)
+{
+ int rc;
+
+ if (!ud || !dr) {
+ BCMLOG_ERR("Invalid arg \n");
+ return -EINVAL;
+ }
+
+ if (set)
+ rc = copy_to_user((void *)ud, dr, size);
+ else
+ rc = copy_from_user(dr, (void *)ud, size);
+
+ if (rc) {
+ BCMLOG_ERR("Invalid args for command \n");
+ rc = -EFAULT;
+ }
+
+ return rc;
+}
+
+static int chd_dec_fetch_cdata(struct crystalhd_adp *adp, crystalhd_ioctl_data *io,
+ uint32_t m_sz, unsigned long ua)
+{
+ unsigned long ua_off;
+ int rc = 0;
+
+ if (!adp || !io || !ua || !m_sz) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return -EINVAL;
+ }
+
+ io->add_cdata = vmalloc(m_sz);
+ if (!io->add_cdata) {
+ BCMLOG_ERR("kalloc fail for sz:%x\n", m_sz);
+ return -ENOMEM;
+ }
+
+ io->add_cdata_sz = m_sz;
+ ua_off = ua + sizeof(io->udata);
+ rc = crystalhd_user_data(ua_off, io->add_cdata, io->add_cdata_sz, 0);
+ if (rc) {
+ BCMLOG_ERR("failed to pull add_cdata sz:%x ua_off:%x\n",
+ io->add_cdata_sz, (unsigned int)ua_off);
+ if (io->add_cdata) {
+ kfree(io->add_cdata);
+ io->add_cdata = NULL;
+ }
+ return -ENODATA;
+ }
+
+ return rc;
+}
+
+static int chd_dec_release_cdata(struct crystalhd_adp *adp,
+ crystalhd_ioctl_data *io, unsigned long ua)
+{
+ unsigned long ua_off;
+ int rc;
+
+ if (!adp || !io || !ua) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return -EINVAL;
+ }
+
+ if (io->cmd != BCM_IOC_FW_DOWNLOAD) {
+ ua_off = ua + sizeof(io->udata);
+ rc = crystalhd_user_data(ua_off, io->add_cdata,
+ io->add_cdata_sz, 1);
+ if (rc) {
+ BCMLOG_ERR("failed to push add_cdata sz:%x ua_off:%x\n",
+ io->add_cdata_sz, (unsigned int)ua_off);
+ return -ENODATA;
+ }
+ }
+
+ if (io->add_cdata) {
+ vfree(io->add_cdata);
+ io->add_cdata = NULL;
+ }
+
+ return 0;
+}
+
+static int chd_dec_proc_user_data(struct crystalhd_adp *adp,
+ crystalhd_ioctl_data *io,
+ unsigned long ua, int set)
+{
+ int rc;
+ uint32_t m_sz = 0;
+
+ if (!adp || !io || !ua) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return -EINVAL;
+ }
+
+ rc = crystalhd_user_data(ua, &io->udata, sizeof(io->udata), set);
+ if (rc) {
+ BCMLOG_ERR("failed to %s iodata \n", (set ? "set" : "get"));
+ return rc;
+ }
+
+ switch (io->cmd) {
+ case BCM_IOC_MEM_RD:
+ case BCM_IOC_MEM_WR:
+ case BCM_IOC_FW_DOWNLOAD:
+ m_sz = io->udata.u.devMem.NumDwords * 4;
+ if (set)
+ rc = chd_dec_release_cdata(adp, io, ua);
+ else
+ rc = chd_dec_fetch_cdata(adp, io, m_sz, ua);
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+static int chd_dec_api_cmd(struct crystalhd_adp *adp, unsigned long ua,
+ uint32_t uid, uint32_t cmd, crystalhd_cmd_proc func)
+{
+ int rc;
+ crystalhd_ioctl_data *temp;
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ temp = chd_dec_alloc_iodata(adp, 0);
+ if (!temp) {
+ BCMLOG_ERR("Failed to get iodata..\n");
+ return -EINVAL;
+ }
+
+ temp->u_id = uid;
+ temp->cmd = cmd;
+
+ rc = chd_dec_proc_user_data(adp, temp, ua, 0);
+ if (!rc) {
+ sts = func(&adp->cmds, temp);
+ if (sts == BC_STS_PENDING)
+ sts = BC_STS_NOT_IMPL;
+ temp->udata.RetSts = sts;
+ rc = chd_dec_proc_user_data(adp, temp, ua, 1);
+ }
+
+ if (temp) {
+ chd_dec_free_iodata(adp, temp, 0);
+ temp = NULL;
+ }
+
+ return rc;
+}
+
+/* API interfaces */
+static int chd_dec_ioctl(struct inode *in, struct file *fd,
+ unsigned int cmd, unsigned long ua)
+{
+ struct crystalhd_adp *adp = chd_get_adp();
+ crystalhd_cmd_proc cproc;
+ struct crystalhd_user *uc;
+
+ if (!adp || !fd) {
+ BCMLOG_ERR("Invalid adp\n");
+ return -EINVAL;
+ }
+
+ uc = (struct crystalhd_user *)fd->private_data;
+ if (!uc) {
+ BCMLOG_ERR("Failed to get uc\n");
+ return -ENODATA;
+ }
+
+ cproc = crystalhd_get_cmd_proc(&adp->cmds, cmd, uc);
+ if (!cproc) {
+ BCMLOG_ERR("Unhandled command: %d\n", cmd);
+ return -EINVAL;
+ }
+
+ return chd_dec_api_cmd(adp, ua, uc->uid, cmd, cproc);
+}
+
+static int chd_dec_open(struct inode *in, struct file *fd)
+{
+ struct crystalhd_adp *adp = chd_get_adp();
+ int rc = 0;
+ BC_STATUS sts = BC_STS_SUCCESS;
+ struct crystalhd_user *uc = NULL;
+
+ BCMLOG_ENTER;
+ if (!adp) {
+ BCMLOG_ERR("Invalid adp\n");
+ return -EINVAL;
+ }
+
+ if (adp->cfg_users >= BC_LINK_MAX_OPENS) {
+ BCMLOG(BCMLOG_INFO, "Already in use.%d\n", adp->cfg_users);
+ return -EBUSY;
+ }
+
+ sts = crystalhd_user_open(&adp->cmds, &uc);
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG_ERR("cmd_user_open - %d \n", sts);
+ rc = -EBUSY;
+ }
+
+ adp->cfg_users++;
+
+ fd->private_data = uc;
+
+ return rc;
+}
+
+static int chd_dec_close(struct inode *in, struct file *fd)
+{
+ struct crystalhd_adp *adp = chd_get_adp();
+ struct crystalhd_user *uc;
+
+ BCMLOG_ENTER;
+ if (!adp) {
+ BCMLOG_ERR("Invalid adp \n");
+ return -EINVAL;
+ }
+
+ uc = (struct crystalhd_user *)fd->private_data;
+ if (!uc) {
+ BCMLOG_ERR("Failed to get uc\n");
+ return -ENODATA;
+ }
+
+ crystalhd_user_close(&adp->cmds, uc);
+
+ adp->cfg_users--;
+
+ return 0;
+}
+
+static const struct file_operations chd_dec_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = chd_dec_ioctl,
+ .open = chd_dec_open,
+ .release = chd_dec_close,
+};
+
+static int __devinit chd_dec_init_chdev(struct crystalhd_adp *adp)
+{
+ crystalhd_ioctl_data *temp;
+ struct device *dev;
+ int rc = -ENODEV, i = 0;
+
+ if (!adp)
+ goto fail;
+
+ adp->chd_dec_major = register_chrdev(0, CRYSTALHD_API_NAME,
+ &chd_dec_fops);
+ if (adp->chd_dec_major < 0) {
+ BCMLOG_ERR("Failed to create config dev\n");
+ rc = adp->chd_dec_major;
+ goto fail;
+ }
+
+ /* register crystalhd class */
+ crystalhd_class = class_create(THIS_MODULE, "crystalhd");
+ if (IS_ERR(crystalhd_class)) {
+ BCMLOG_ERR("failed to create class\n");
+ goto fail;
+ }
+
+ dev = device_create(crystalhd_class, NULL, MKDEV(adp->chd_dec_major, 0),
+ NULL, "crystalhd");
+ if (!dev) {
+ BCMLOG_ERR("failed to create device\n");
+ goto device_create_fail;
+ }
+
+ rc = crystalhd_create_elem_pool(adp, BC_LINK_ELEM_POOL_SZ);
+ if (rc) {
+ BCMLOG_ERR("failed to create device\n");
+ goto elem_pool_fail;
+ }
+
+ /* Allocate general purpose ioctl pool. */
+ for (i = 0; i < CHD_IODATA_POOL_SZ; i++) {
+ /* FIXME: jarod: why atomic? */
+ temp = kzalloc(sizeof(crystalhd_ioctl_data), GFP_ATOMIC);
+ if (!temp) {
+ BCMLOG_ERR("ioctl data pool kzalloc failed\n");
+ rc = -ENOMEM;
+ goto kzalloc_fail;
+ }
+ /* Add to global pool.. */
+ chd_dec_free_iodata(adp, temp, 0);
+ }
+
+ return 0;
+
+kzalloc_fail:
+ crystalhd_delete_elem_pool(adp);
+elem_pool_fail:
+ device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
+device_create_fail:
+ class_destroy(crystalhd_class);
+fail:
+ return rc;
+}
+
+static void __devexit chd_dec_release_chdev(struct crystalhd_adp *adp)
+{
+ crystalhd_ioctl_data *temp = NULL;
+ if (!adp)
+ return;
+
+ if (adp->chd_dec_major > 0) {
+ /* unregister crystalhd class */
+ device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
+ unregister_chrdev(adp->chd_dec_major, CRYSTALHD_API_NAME);
+ BCMLOG(BCMLOG_INFO, "released api device - %d\n",
+ adp->chd_dec_major);
+ class_destroy(crystalhd_class);
+ }
+ adp->chd_dec_major = 0;
+
+ /* Clear iodata pool.. */
+ do {
+ temp = chd_dec_alloc_iodata(adp, 0);
+ if (temp)
+ kfree(temp);
+ } while (temp);
+
+ crystalhd_delete_elem_pool(adp);
+}
+
+static int __devinit chd_pci_reserve_mem(struct crystalhd_adp *pinfo)
+{
+ int rc;
+ unsigned long bar2 = pci_resource_start(pinfo->pdev, 2);
+ uint32_t mem_len = pci_resource_len(pinfo->pdev, 2);
+ unsigned long bar0 = pci_resource_start(pinfo->pdev, 0);
+ uint32_t i2o_len = pci_resource_len(pinfo->pdev, 0);
+
+ BCMLOG(BCMLOG_SSTEP, "bar2:0x%lx-0x%08x bar0:0x%lx-0x%08x\n",
+ bar2, mem_len, bar0, i2o_len);
+
+ rc = check_mem_region(bar2, mem_len);
+ if (rc) {
+ BCMLOG_ERR("No valid mem region...\n");
+ return -ENOMEM;
+ }
+
+ pinfo->addr = ioremap_nocache(bar2, mem_len);
+ if (!pinfo->addr) {
+ BCMLOG_ERR("Failed to remap mem region...\n");
+ return -ENOMEM;
+ }
+
+ pinfo->pci_mem_start = bar2;
+ pinfo->pci_mem_len = mem_len;
+
+ rc = check_mem_region(bar0, i2o_len);
+ if (rc) {
+ BCMLOG_ERR("No valid mem region...\n");
+ return -ENOMEM;
+ }
+
+ pinfo->i2o_addr = ioremap_nocache(bar0, i2o_len);
+ if (!pinfo->i2o_addr) {
+ BCMLOG_ERR("Failed to remap mem region...\n");
+ return -ENOMEM;
+ }
+
+ pinfo->pci_i2o_start = bar0;
+ pinfo->pci_i2o_len = i2o_len;
+
+ rc = pci_request_regions(pinfo->pdev, pinfo->name);
+ if (rc < 0) {
+ BCMLOG_ERR("Region request failed: %d\n", rc);
+ return rc;
+ }
+
+ BCMLOG(BCMLOG_SSTEP, "Mapped addr:0x%08lx i2o_addr:0x%08lx\n",
+ (unsigned long)pinfo->addr, (unsigned long)pinfo->i2o_addr);
+
+ return 0;
+}
+
+static void __devexit chd_pci_release_mem(struct crystalhd_adp *pinfo)
+{
+ if (!pinfo)
+ return;
+
+ if (pinfo->addr)
+ iounmap(pinfo->addr);
+
+ if (pinfo->i2o_addr)
+ iounmap(pinfo->i2o_addr);
+
+ pci_release_regions(pinfo->pdev);
+}
+
+
+static void __devexit chd_dec_pci_remove(struct pci_dev *pdev)
+{
+ struct crystalhd_adp *pinfo;
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ BCMLOG_ENTER;
+
+ pinfo = (struct crystalhd_adp *) pci_get_drvdata(pdev);
+ if (!pinfo) {
+ BCMLOG_ERR("could not get adp\n");
+ return;
+ }
+
+ sts = crystalhd_delete_cmd_context(&pinfo->cmds);
+ if (sts != BC_STS_SUCCESS)
+ BCMLOG_ERR("cmd delete :%d \n", sts);
+
+ chd_dec_release_chdev(pinfo);
+
+ chd_dec_disable_int(pinfo);
+
+ chd_pci_release_mem(pinfo);
+ pci_disable_device(pinfo->pdev);
+
+ kfree(pinfo);
+ g_adp_info = NULL;
+}
+
+static int __devinit chd_dec_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *entry)
+{
+ struct crystalhd_adp *pinfo;
+ int rc;
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ BCMLOG(BCMLOG_DBG, "PCI_INFO: Vendor:0x%04x Device:0x%04x "
+ "s_vendor:0x%04x s_device: 0x%04x\n",
+ pdev->vendor, pdev->device, pdev->subsystem_vendor,
+ pdev->subsystem_device);
+
+ /* FIXME: jarod: why atomic? */
+ pinfo = kzalloc(sizeof(struct crystalhd_adp), GFP_ATOMIC);
+ if (!pinfo) {
+ BCMLOG_ERR("Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ pinfo->pdev = pdev;
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ BCMLOG_ERR("Failed to enable PCI device\n");
+ return rc;
+ }
+
+ snprintf(pinfo->name, 31, "crystalhd_pci_e:%d:%d:%d",
+ pdev->bus->number, PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn));
+
+ rc = chd_pci_reserve_mem(pinfo);
+ if (rc) {
+ BCMLOG_ERR("Failed to setup memory regions.\n");
+ return -ENOMEM;
+ }
+
+ pinfo->present = 1;
+ pinfo->drv_data = entry->driver_data;
+
+ /* Setup adapter level lock.. */
+ spin_lock_init(&pinfo->lock);
+
+ /* setup api stuff.. */
+ chd_dec_init_chdev(pinfo);
+ rc = chd_dec_enable_int(pinfo);
+ if (rc) {
+ BCMLOG_ERR("_enable_int err:%d \n", rc);
+ pci_disable_device(pdev);
+ return -ENODEV;
+ }
+
+ /* Set dma mask... */
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ pinfo->dmabits = 64;
+ } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ pinfo->dmabits = 32;
+ } else {
+ BCMLOG_ERR("Unabled to setup DMA %d\n", rc);
+ pci_disable_device(pdev);
+ return -ENODEV;
+ }
+
+ sts = crystalhd_setup_cmd_context(&pinfo->cmds, pinfo);
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG_ERR("cmd setup :%d \n", sts);
+ pci_disable_device(pdev);
+ return -ENODEV;
+ }
+
+ pci_set_master(pdev);
+
+ pci_set_drvdata(pdev, pinfo);
+
+ g_adp_info = pinfo;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+int chd_dec_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct crystalhd_adp *adp;
+ crystalhd_ioctl_data *temp;
+ BC_STATUS sts = BC_STS_SUCCESS;
+
+ adp = (struct crystalhd_adp *)pci_get_drvdata(pdev);
+ if (!adp) {
+ BCMLOG_ERR("could not get adp\n");
+ return -ENODEV;
+ }
+
+ temp = chd_dec_alloc_iodata(adp, false);
+ if (!temp) {
+ BCMLOG_ERR("could not get ioctl data\n");
+ return -ENODEV;
+ }
+
+ sts = crystalhd_suspend(&adp->cmds, temp);
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG_ERR("BCM70012 Suspend %d\n", sts);
+ return -ENODEV;
+ }
+
+ chd_dec_free_iodata(adp, temp, false);
+ chd_dec_disable_int(adp);
+ pci_save_state(pdev);
+
+ /* Disable IO/bus master/irq router */
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
+}
+
+int chd_dec_pci_resume(struct pci_dev *pdev)
+{
+ struct crystalhd_adp *adp;
+ BC_STATUS sts = BC_STS_SUCCESS;
+ int rc;
+
+ adp = (struct crystalhd_adp *)pci_get_drvdata(pdev);
+ if (!adp) {
+ BCMLOG_ERR("could not get adp\n");
+ return -ENODEV;
+ }
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ /* device's irq possibly is changed, driver should take care */
+ if (pci_enable_device(pdev)) {
+ BCMLOG_ERR("Failed to enable PCI device\n");
+ return 1;
+ }
+
+ pci_set_master(pdev);
+
+ rc = chd_dec_enable_int(adp);
+ if (rc) {
+ BCMLOG_ERR("_enable_int err:%d \n", rc);
+ pci_disable_device(pdev);
+ return -ENODEV;
+ }
+
+ sts = crystalhd_resume(&adp->cmds);
+ if (sts != BC_STS_SUCCESS) {
+ BCMLOG_ERR("BCM70012 Resume %d\n", sts);
+ pci_disable_device(pdev);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(chd_dec_pci_id_table) = {
+ { PCI_VDEVICE(BROADCOM, 0x1612), 8 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, chd_dec_pci_id_table);
+
+static struct pci_driver bc_chd_70012_driver = {
+ .name = "Broadcom 70012 Decoder",
+ .probe = chd_dec_pci_probe,
+ .remove = __devexit_p(chd_dec_pci_remove),
+ .id_table = chd_dec_pci_id_table,
+#ifdef CONFIG_PM
+ .suspend = chd_dec_pci_suspend,
+ .resume = chd_dec_pci_resume
+#endif
+};
+
+void chd_set_log_level(struct crystalhd_adp *adp, char *arg)
+{
+ if ((!arg) || (strlen(arg) < 3))
+ g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA;
+ else if (!strncmp(arg, "sstep", 5))
+ g_linklog_level = BCMLOG_INFO | BCMLOG_DATA | BCMLOG_DBG |
+ BCMLOG_SSTEP | BCMLOG_ERROR;
+ else if (!strncmp(arg, "info", 4))
+ g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA | BCMLOG_INFO;
+ else if (!strncmp(arg, "debug", 5))
+ g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA | BCMLOG_INFO |
+ BCMLOG_DBG;
+ else if (!strncmp(arg, "pball", 5))
+ g_linklog_level = 0xFFFFFFFF & ~(BCMLOG_SPINLOCK);
+ else if (!strncmp(arg, "silent", 6))
+ g_linklog_level = 0;
+ else
+ g_linklog_level = 0;
+}
+
+struct crystalhd_adp *chd_get_adp(void)
+{
+ return g_adp_info;
+}
+
+static int __init chd_dec_module_init(void)
+{
+ int rc;
+
+ chd_set_log_level(NULL, "debug");
+ BCMLOG(BCMLOG_DATA, "Loading crystalhd %d.%d.%d \n",
+ crystalhd_kmod_major, crystalhd_kmod_minor, crystalhd_kmod_rev);
+
+ rc = pci_register_driver(&bc_chd_70012_driver);
+
+ if (rc < 0)
+ BCMLOG_ERR("Could not find any devices. err:%d \n", rc);
+
+ return rc;
+}
+module_init(chd_dec_module_init);
+
+static void __exit chd_dec_module_cleanup(void)
+{
+ BCMLOG(BCMLOG_DATA, "unloading crystalhd %d.%d.%d \n",
+ crystalhd_kmod_major, crystalhd_kmod_minor, crystalhd_kmod_rev);
+
+ pci_unregister_driver(&bc_chd_70012_driver);
+}
+module_exit(chd_dec_module_cleanup);
+
+MODULE_AUTHOR("Naren Sankar <nsankar@broadcom.com>");
+MODULE_AUTHOR("Prasad Bolisetty <prasadb@broadcom.com>");
+MODULE_DESCRIPTION(CRYSTAL_HD_NAME);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("bcm70012");
diff --git a/drivers/staging/crystalhd/crystalhd_lnx.h b/drivers/staging/crystalhd/crystalhd_lnx.h
new file mode 100644
index 000000000000..d338ae97a4cf
--- /dev/null
+++ b/drivers/staging/crystalhd/crystalhd_lnx.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * Copyright (c) 2005-2009, Broadcom Corporation.
+ *
+ * Name: crystalhd_lnx . c
+ *
+ * Description:
+ * BCM70012 Linux driver
+ *
+ * HISTORY:
+ *
+ **********************************************************************
+ * This file is part of the crystalhd device driver.
+ *
+ * This driver 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.
+ *
+ * This driver 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 driver. If not, see <http://www.gnu.org/licenses/>.
+ **********************************************************************/
+
+#ifndef _CRYSTALHD_LNX_H_
+#define _CRYSTALHD_LNX_H_
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "crystalhd_cmds.h"
+
+#define CRYSTAL_HD_NAME "Broadcom Crystal HD Decoder (BCM70012) Driver"
+
+
+/* OS specific PCI information structure and adapter information. */
+struct crystalhd_adp {
+ /* Hardware borad/PCI specifics */
+ char name[32];
+ struct pci_dev *pdev;
+
+ unsigned long pci_mem_start;
+ uint32_t pci_mem_len;
+ void *addr;
+
+ unsigned long pci_i2o_start;
+ uint32_t pci_i2o_len;
+ void *i2o_addr;
+
+ unsigned int drv_data;
+ unsigned int dmabits; /* 32 | 64 */
+ unsigned int registered;
+ unsigned int present;
+ unsigned int msi;
+
+ spinlock_t lock;
+
+ /* API Related */
+ unsigned int chd_dec_major;
+ unsigned int cfg_users;
+
+ crystalhd_ioctl_data *idata_free_head; /* ioctl data pool */
+ crystalhd_elem_t *elem_pool_head; /* Queue element pool */
+
+ struct crystalhd_cmd cmds;
+
+ crystalhd_dio_req *ua_map_free_head;
+ struct pci_pool *fill_byte_pool;
+};
+
+
+struct crystalhd_adp *chd_get_adp(void);
+void chd_set_log_level(struct crystalhd_adp *adp, char *arg);
+
+#endif
+
diff --git a/drivers/staging/crystalhd/crystalhd_misc.c b/drivers/staging/crystalhd/crystalhd_misc.c
new file mode 100644
index 000000000000..587dcc477865
--- /dev/null
+++ b/drivers/staging/crystalhd/crystalhd_misc.c
@@ -0,0 +1,1030 @@
+/***************************************************************************
+ * Copyright (c) 2005-2009, Broadcom Corporation.
+ *
+ * Name: crystalhd_misc . c
+ *
+ * Description:
+ * BCM70012 Linux driver misc routines.
+ *
+ * HISTORY:
+ *
+ **********************************************************************
+ * This file is part of the crystalhd device driver.
+ *
+ * This driver 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.
+ *
+ * This driver 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 driver. If not, see <http://www.gnu.org/licenses/>.
+ **********************************************************************/
+
+#include "crystalhd_misc.h"
+#include "crystalhd_lnx.h"
+
+uint32_t g_linklog_level;
+
+static inline uint32_t crystalhd_dram_rd(struct crystalhd_adp *adp, uint32_t mem_off)
+{
+ crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (mem_off >> 19));
+ return bc_dec_reg_rd(adp, (0x00380000 | (mem_off & 0x0007FFFF)));
+}
+
+static inline void crystalhd_dram_wr(struct crystalhd_adp *adp, uint32_t mem_off, uint32_t val)
+{
+ crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (mem_off >> 19));
+ bc_dec_reg_wr(adp, (0x00380000 | (mem_off & 0x0007FFFF)), val);
+}
+
+static inline BC_STATUS bc_chk_dram_range(struct crystalhd_adp *adp, uint32_t start_off, uint32_t cnt)
+{
+ return BC_STS_SUCCESS;
+}
+
+static crystalhd_dio_req *crystalhd_alloc_dio(struct crystalhd_adp *adp)
+{
+ unsigned long flags = 0;
+ crystalhd_dio_req *temp = NULL;
+
+ if (!adp) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return temp;
+ }
+
+ spin_lock_irqsave(&adp->lock, flags);
+ temp = adp->ua_map_free_head;
+ if (temp)
+ adp->ua_map_free_head = adp->ua_map_free_head->next;
+ spin_unlock_irqrestore(&adp->lock, flags);
+
+ return temp;
+}
+
+static void crystalhd_free_dio(struct crystalhd_adp *adp, crystalhd_dio_req *dio)
+{
+ unsigned long flags = 0;
+
+ if (!adp || !dio)
+ return;
+ spin_lock_irqsave(&adp->lock, flags);
+ dio->sig = crystalhd_dio_inv;
+ dio->page_cnt = 0;
+ dio->fb_size = 0;
+ memset(&dio->uinfo, 0, sizeof(dio->uinfo));
+ dio->next = adp->ua_map_free_head;
+ adp->ua_map_free_head = dio;
+ spin_unlock_irqrestore(&adp->lock, flags);
+}
+
+static crystalhd_elem_t *crystalhd_alloc_elem(struct crystalhd_adp *adp)
+{
+ unsigned long flags = 0;
+ crystalhd_elem_t *temp = NULL;
+
+ if (!adp)
+ return temp;
+ spin_lock_irqsave(&adp->lock, flags);
+ temp = adp->elem_pool_head;
+ if (temp) {
+ adp->elem_pool_head = adp->elem_pool_head->flink;
+ memset(temp, 0, sizeof(*temp));
+ }
+ spin_unlock_irqrestore(&adp->lock, flags);
+
+ return temp;
+}
+static void crystalhd_free_elem(struct crystalhd_adp *adp, crystalhd_elem_t *elem)
+{
+ unsigned long flags = 0;
+
+ if (!adp || !elem)
+ return;
+ spin_lock_irqsave(&adp->lock, flags);
+ elem->flink = adp->elem_pool_head;
+ adp->elem_pool_head = elem;
+ spin_unlock_irqrestore(&adp->lock, flags);
+}
+
+static inline void crystalhd_set_sg(struct scatterlist *sg, struct page *page,
+ unsigned int len, unsigned int offset)
+{
+ sg_set_page(sg, page, len, offset);
+#ifdef CONFIG_X86_64
+ sg->dma_length = len;
+#endif
+}
+
+static inline void crystalhd_init_sg(struct scatterlist *sg, unsigned int entries)
+{
+ /* http://lkml.org/lkml/2007/11/27/68 */
+ sg_init_table(sg, entries);
+}
+
+/*========================== Extern ========================================*/
+/**
+ * bc_dec_reg_rd - Read 7412's device register.
+ * @adp: Adapter instance
+ * @reg_off: Register offset.
+ *
+ * Return:
+ * 32bit value read
+ *
+ * 7412's device register read routine. This interface use
+ * 7412's device access range mapped from BAR-2 (4M) of PCIe
+ * configuration space.
+ */
+uint32_t bc_dec_reg_rd(struct crystalhd_adp *adp, uint32_t reg_off)
+{
+ if (!adp || (reg_off > adp->pci_mem_len)) {
+ BCMLOG_ERR("dec_rd_reg_off outof range: 0x%08x\n", reg_off);
+ return 0;
+ }
+
+ return readl(adp->addr + reg_off);
+}
+
+/**
+ * bc_dec_reg_wr - Write 7412's device register
+ * @adp: Adapter instance
+ * @reg_off: Register offset.
+ * @val: Dword value to be written.
+ *
+ * Return:
+ * none.
+ *
+ * 7412's device register write routine. This interface use
+ * 7412's device access range mapped from BAR-2 (4M) of PCIe
+ * configuration space.
+ */
+void bc_dec_reg_wr(struct crystalhd_adp *adp, uint32_t reg_off, uint32_t val)
+{
+ if (!adp || (reg_off > adp->pci_mem_len)) {
+ BCMLOG_ERR("dec_wr_reg_off outof range: 0x%08x\n", reg_off);
+ return;
+ }
+ writel(val, adp->addr + reg_off);
+ udelay(8);
+}
+
+/**
+ * crystalhd_reg_rd - Read Link's device register.
+ * @adp: Adapter instance
+ * @reg_off: Register offset.
+ *
+ * Return:
+ * 32bit value read
+ *
+ * Link device register read routine. This interface use
+ * Link's device access range mapped from BAR-1 (64K) of PCIe
+ * configuration space.
+ *
+ */
+uint32_t crystalhd_reg_rd(struct crystalhd_adp *adp, uint32_t reg_off)
+{
+ if (!adp || (reg_off > adp->pci_i2o_len)) {
+ BCMLOG_ERR("link_rd_reg_off outof range: 0x%08x\n", reg_off);
+ return 0;
+ }
+ return readl(adp->i2o_addr + reg_off);
+}
+
+/**
+ * crystalhd_reg_wr - Write Link's device register
+ * @adp: Adapter instance
+ * @reg_off: Register offset.
+ * @val: Dword value to be written.
+ *
+ * Return:
+ * none.
+ *
+ * Link device register write routine. This interface use
+ * Link's device access range mapped from BAR-1 (64K) of PCIe
+ * configuration space.
+ *
+ */
+void crystalhd_reg_wr(struct crystalhd_adp *adp, uint32_t reg_off, uint32_t val)
+{
+ if (!adp || (reg_off > adp->pci_i2o_len)) {
+ BCMLOG_ERR("link_wr_reg_off outof range: 0x%08x\n", reg_off);
+ return;
+ }
+ writel(val, adp->i2o_addr + reg_off);
+}
+
+/**
+ * crystalhd_mem_rd - Read data from 7412's DRAM area.
+ * @adp: Adapter instance
+ * @start_off: Start offset.
+ * @dw_cnt: Count in dwords.
+ * @rd_buff: Buffer to copy the data from dram.
+ *
+ * Return:
+ * Status.
+ *
+ * 7412's Dram read routine.
+ */
+BC_STATUS crystalhd_mem_rd(struct crystalhd_adp *adp, uint32_t start_off,
+ uint32_t dw_cnt, uint32_t *rd_buff)
+{
+ uint32_t ix = 0;
+
+ if (!adp || !rd_buff ||
+ (bc_chk_dram_range(adp, start_off, dw_cnt) != BC_STS_SUCCESS)) {
+ BCMLOG_ERR("Invalid arg \n");
+ return BC_STS_INV_ARG;
+ }
+ for (ix = 0; ix < dw_cnt; ix++)
+ rd_buff[ix] = crystalhd_dram_rd(adp, (start_off + (ix * 4)));
+
+ return BC_STS_SUCCESS;
+}
+
+/**
+ * crystalhd_mem_wr - Write data to 7412's DRAM area.
+ * @adp: Adapter instance
+ * @start_off: Start offset.
+ * @dw_cnt: Count in dwords.
+ * @wr_buff: Data Buffer to be written.
+ *
+ * Return:
+ * Status.
+ *
+ * 7412's Dram write routine.
+ */
+BC_STATUS crystalhd_mem_wr(struct crystalhd_adp *adp, uint32_t start_off,
+ uint32_t dw_cnt, uint32_t *wr_buff)
+{
+ uint32_t ix = 0;
+
+ if (!adp || !wr_buff ||
+ (bc_chk_dram_range(adp, start_off, dw_cnt) != BC_STS_SUCCESS)) {
+ BCMLOG_ERR("Invalid arg \n");
+ return BC_STS_INV_ARG;
+ }
+
+ for (ix = 0; ix < dw_cnt; ix++)
+ crystalhd_dram_wr(adp, (start_off + (ix * 4)), wr_buff[ix]);
+
+ return BC_STS_SUCCESS;
+}
+/**
+ * crystalhd_pci_cfg_rd - PCIe config read
+ * @adp: Adapter instance
+ * @off: PCI config space offset.
+ * @len: Size -- Byte, Word & dword.
+ * @val: Value read
+ *
+ * Return:
+ * Status.
+ *
+ * Get value from Link's PCIe config space.
+ */
+BC_STATUS crystalhd_pci_cfg_rd(struct crystalhd_adp *adp, uint32_t off,
+ uint32_t len, uint32_t *val)
+{
+ BC_STATUS sts = BC_STS_SUCCESS;
+ int rc = 0;
+
+ if (!adp || !val) {
+ BCMLOG_ERR("Invalid arg \n");
+ return BC_STS_INV_ARG;
+ }
+
+ switch (len) {
+ case 1:
+ rc = pci_read_config_byte(adp->pdev, off, (u8 *)val);
+ break;
+ case 2:
+ rc = pci_read_config_word(adp->pdev, off, (u16 *)val);
+ break;
+ case 4:
+ rc = pci_read_config_dword(adp->pdev, off, (u32 *)val);
+ break;
+ default:
+ rc = -EINVAL;
+ sts = BC_STS_INV_ARG;
+ BCMLOG_ERR("Invalid len:%d\n", len);
+ };
+
+ if (rc && (sts == BC_STS_SUCCESS))
+ sts = BC_STS_ERROR;
+
+ return sts;
+}
+
+/**
+ * crystalhd_pci_cfg_wr - PCIe config write
+ * @adp: Adapter instance
+ * @off: PCI config space offset.
+ * @len: Size -- Byte, Word & dword.
+ * @val: Value to be written
+ *
+ * Return:
+ * Status.
+ *
+ * Set value to Link's PCIe config space.
+ */
+BC_STATUS crystalhd_pci_cfg_wr(struct crystalhd_adp *adp, uint32_t off,
+ uint32_t len, uint32_t val)
+{
+ BC_STATUS sts = BC_STS_SUCCESS;
+ int rc = 0;
+
+ if (!adp || !val) {
+ BCMLOG_ERR("Invalid arg \n");
+ return BC_STS_INV_ARG;
+ }
+
+ switch (len) {
+ case 1:
+ rc = pci_write_config_byte(adp->pdev, off, (u8)val);
+ break;
+ case 2:
+ rc = pci_write_config_word(adp->pdev, off, (u16)val);
+ break;
+ case 4:
+ rc = pci_write_config_dword(adp->pdev, off, val);
+ break;
+ default:
+ rc = -EINVAL;
+ sts = BC_STS_INV_ARG;
+ BCMLOG_ERR("Invalid len:%d\n", len);
+ };
+
+ if (rc && (sts == BC_STS_SUCCESS))
+ sts = BC_STS_ERROR;
+
+ return sts;
+}
+
+/**
+ * bc_kern_dma_alloc - Allocate memory for Dma rings
+ * @adp: Adapter instance
+ * @sz: Size of the memory to allocate.
+ * @phy_addr: Physical address of the memory allocated.
+ * Typedef to system's dma_addr_t (u64)
+ *
+ * Return:
+ * Pointer to allocated memory..
+ *
+ * Wrapper to Linux kernel interface.
+ *
+ */
+void *bc_kern_dma_alloc(struct crystalhd_adp *adp, uint32_t sz,
+ dma_addr_t *phy_addr)
+{
+ void *temp = NULL;
+
+ if (!adp || !sz || !phy_addr) {
+ BCMLOG_ERR("Invalide Arg..\n");
+ return temp;
+ }
+
+ temp = pci_alloc_consistent(adp->pdev, sz, phy_addr);
+ if (temp)
+ memset(temp, 0, sz);
+
+ return temp;
+}
+
+/**
+ * bc_kern_dma_free - Release Dma ring memory.
+ * @adp: Adapter instance
+ * @sz: Size of the memory to allocate.
+ * @ka: Kernel virtual address returned during _dio_alloc()
+ * @phy_addr: Physical address of the memory allocated.
+ * Typedef to system's dma_addr_t (u64)
+ *
+ * Return:
+ * none.
+ */
+void bc_kern_dma_free(struct crystalhd_adp *adp, uint32_t sz, void *ka,
+ dma_addr_t phy_addr)
+{
+ if (!adp || !ka || !sz || !phy_addr) {
+ BCMLOG_ERR("Invalide Arg..\n");
+ return;
+ }
+
+ pci_free_consistent(adp->pdev, sz, ka, phy_addr);
+}
+
+/**
+ * crystalhd_create_dioq - Create Generic DIO queue
+ * @adp: Adapter instance
+ * @dioq_hnd: Handle to the dio queue created
+ * @cb : Optional - Call back To free the element.
+ * @cbctx: Context to pass to callback.
+ *
+ * Return:
+ * status
+ *
+ * Initialize Generic DIO queue to hold any data. Callback
+ * will be used to free elements while deleting the queue.
+ */
+BC_STATUS crystalhd_create_dioq(struct crystalhd_adp *adp,
+ crystalhd_dioq_t **dioq_hnd,
+ crystalhd_data_free_cb cb, void *cbctx)
+{
+ crystalhd_dioq_t *dioq = NULL;
+
+ if (!adp || !dioq_hnd) {
+ BCMLOG_ERR("Invalid arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ dioq = kzalloc(sizeof(*dioq), GFP_KERNEL);
+ if (!dioq)
+ return BC_STS_INSUFF_RES;
+
+ spin_lock_init(&dioq->lock);
+ dioq->sig = BC_LINK_DIOQ_SIG;
+ dioq->head = (crystalhd_elem_t *)&dioq->head;
+ dioq->tail = (crystalhd_elem_t *)&dioq->head;
+ crystalhd_create_event(&dioq->event);
+ dioq->adp = adp;
+ dioq->data_rel_cb = cb;
+ dioq->cb_context = cbctx;
+ *dioq_hnd = dioq;
+
+ return BC_STS_SUCCESS;
+}
+
+/**
+ * crystalhd_delete_dioq - Delete Generic DIO queue
+ * @adp: Adapter instance
+ * @dioq: DIOQ instance..
+ *
+ * Return:
+ * None.
+ *
+ * Release Generic DIO queue. This function will remove
+ * all the entries from the Queue and will release data
+ * by calling the call back provided during creation.
+ *
+ */
+void crystalhd_delete_dioq(struct crystalhd_adp *adp, crystalhd_dioq_t *dioq)
+{
+ void *temp;
+
+ if (!dioq || (dioq->sig != BC_LINK_DIOQ_SIG))
+ return;
+
+ do {
+ temp = crystalhd_dioq_fetch(dioq);
+ if (temp && dioq->data_rel_cb)
+ dioq->data_rel_cb(dioq->cb_context, temp);
+ } while (temp);
+ dioq->sig = 0;
+ kfree(dioq);
+}
+
+/**
+ * crystalhd_dioq_add - Add new DIO request element.
+ * @ioq: DIO queue instance
+ * @t: DIO request to be added.
+ * @wake: True - Wake up suspended process.
+ * @tag: Special tag to assign - For search and get.
+ *
+ * Return:
+ * Status.
+ *
+ * Insert new element to Q tail.
+ */
+BC_STATUS crystalhd_dioq_add(crystalhd_dioq_t *ioq, void *data,
+ bool wake, uint32_t tag)
+{
+ unsigned long flags = 0;
+ crystalhd_elem_t *tmp;
+
+ if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG) || !data) {
+ BCMLOG_ERR("Invalid arg!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ tmp = crystalhd_alloc_elem(ioq->adp);
+ if (!tmp) {
+ BCMLOG_ERR("No free elements.\n");
+ return BC_STS_INSUFF_RES;
+ }
+
+ tmp->data = data;
+ tmp->tag = tag;
+ spin_lock_irqsave(&ioq->lock, flags);
+ tmp->flink = (crystalhd_elem_t *)&ioq->head;
+ tmp->blink = ioq->tail;
+ tmp->flink->blink = tmp;
+ tmp->blink->flink = tmp;
+ ioq->count++;
+ spin_unlock_irqrestore(&ioq->lock, flags);
+
+ if (wake)
+ crystalhd_set_event(&ioq->event);
+
+ return BC_STS_SUCCESS;
+}
+
+/**
+ * crystalhd_dioq_fetch - Fetch element from head.
+ * @ioq: DIO queue instance
+ *
+ * Return:
+ * data element from the head..
+ *
+ * Remove an element from Queue.
+ */
+void *crystalhd_dioq_fetch(crystalhd_dioq_t *ioq)
+{
+ unsigned long flags = 0;
+ crystalhd_elem_t *tmp;
+ crystalhd_elem_t *ret = NULL;
+ void *data = NULL;
+
+ if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG)) {
+ BCMLOG_ERR("Invalid arg!!\n");
+ return data;
+ }
+
+ spin_lock_irqsave(&ioq->lock, flags);
+ tmp = ioq->head;
+ if (tmp != (crystalhd_elem_t *)&ioq->head) {
+ ret = tmp;
+ tmp->flink->blink = tmp->blink;
+ tmp->blink->flink = tmp->flink;
+ ioq->count--;
+ }
+ spin_unlock_irqrestore(&ioq->lock, flags);
+ if (ret) {
+ data = ret->data;
+ crystalhd_free_elem(ioq->adp, ret);
+ }
+
+ return data;
+}
+/**
+ * crystalhd_dioq_find_and_fetch - Search the tag and Fetch element
+ * @ioq: DIO queue instance
+ * @tag: Tag to search for.
+ *
+ * Return:
+ * element from the head..
+ *
+ * Search TAG and remove the element.
+ */
+void *crystalhd_dioq_find_and_fetch(crystalhd_dioq_t *ioq, uint32_t tag)
+{
+ unsigned long flags = 0;
+ crystalhd_elem_t *tmp;
+ crystalhd_elem_t *ret = NULL;
+ void *data = NULL;
+
+ if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG)) {
+ BCMLOG_ERR("Invalid arg!!\n");
+ return data;
+ }
+
+ spin_lock_irqsave(&ioq->lock, flags);
+ tmp = ioq->head;
+ while (tmp != (crystalhd_elem_t *)&ioq->head) {
+ if (tmp->tag == tag) {
+ ret = tmp;
+ tmp->flink->blink = tmp->blink;
+ tmp->blink->flink = tmp->flink;
+ ioq->count--;
+ break;
+ }
+ tmp = tmp->flink;
+ }
+ spin_unlock_irqrestore(&ioq->lock, flags);
+
+ if (ret) {
+ data = ret->data;
+ crystalhd_free_elem(ioq->adp, ret);
+ }
+
+ return data;
+}
+
+/**
+ * crystalhd_dioq_fetch_wait - Fetch element from Head.
+ * @ioq: DIO queue instance
+ * @to_secs: Wait timeout in seconds..
+ *
+ * Return:
+ * element from the head..
+ *
+ * Return element from head if Q is not empty. Wait for new element
+ * if Q is empty for Timeout seconds.
+ */
+void *crystalhd_dioq_fetch_wait(crystalhd_dioq_t *ioq, uint32_t to_secs,
+ uint32_t *sig_pend)
+{
+ unsigned long flags = 0;
+ int rc = 0, count;
+ void *tmp = NULL;
+
+ if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG) || !to_secs || !sig_pend) {
+ BCMLOG_ERR("Invalid arg!!\n");
+ return tmp;
+ }
+
+ count = to_secs;
+ spin_lock_irqsave(&ioq->lock, flags);
+ while ((ioq->count == 0) && count) {
+ spin_unlock_irqrestore(&ioq->lock, flags);
+
+ crystalhd_wait_on_event(&ioq->event, (ioq->count > 0), 1000, rc, 0);
+ if (rc == 0) {
+ goto out;
+ } else if (rc == -EINTR) {
+ BCMLOG(BCMLOG_INFO, "Cancelling fetch wait\n");
+ *sig_pend = 1;
+ return tmp;
+ }
+ spin_lock_irqsave(&ioq->lock, flags);
+ count--;
+ }
+ spin_unlock_irqrestore(&ioq->lock, flags);
+
+out:
+ return crystalhd_dioq_fetch(ioq);
+}
+
+/**
+ * crystalhd_map_dio - Map user address for DMA
+ * @adp: Adapter instance
+ * @ubuff: User buffer to map.
+ * @ubuff_sz: User buffer size.
+ * @uv_offset: UV buffer offset.
+ * @en_422mode: TRUE:422 FALSE:420 Capture mode.
+ * @dir_tx: TRUE for Tx (To device from host)
+ * @dio_hnd: Handle to mapped DIO request.
+ *
+ * Return:
+ * Status.
+ *
+ * This routine maps user address and lock pages for DMA.
+ *
+ */
+BC_STATUS crystalhd_map_dio(struct crystalhd_adp *adp, void *ubuff,
+ uint32_t ubuff_sz, uint32_t uv_offset,
+ bool en_422mode, bool dir_tx,
+ crystalhd_dio_req **dio_hnd)
+{
+ crystalhd_dio_req *dio;
+ /* FIXME: jarod: should some of these unsigned longs be uint32_t or uintptr_t? */
+ unsigned long start = 0, end = 0, uaddr = 0, count = 0;
+ unsigned long spsz = 0, uv_start = 0;
+ int i = 0, rw = 0, res = 0, nr_pages = 0, skip_fb_sg = 0;
+
+ if (!adp || !ubuff || !ubuff_sz || !dio_hnd) {
+ BCMLOG_ERR("Invalid arg \n");
+ return BC_STS_INV_ARG;
+ }
+ /* Compute pages */
+ uaddr = (unsigned long)ubuff;
+ count = (unsigned long)ubuff_sz;
+ end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ start = uaddr >> PAGE_SHIFT;
+ nr_pages = end - start;
+
+ if (!count || ((uaddr + count) < uaddr)) {
+ BCMLOG_ERR("User addr overflow!!\n");
+ return BC_STS_INV_ARG;
+ }
+
+ dio = crystalhd_alloc_dio(adp);
+ if (!dio) {
+ BCMLOG_ERR("dio pool empty..\n");
+ return BC_STS_INSUFF_RES;
+ }
+
+ if (dir_tx) {
+ rw = WRITE;
+ dio->direction = DMA_TO_DEVICE;
+ } else {
+ rw = READ;
+ dio->direction = DMA_FROM_DEVICE;
+ }
+
+ if (nr_pages > dio->max_pages) {
+ BCMLOG_ERR("max_pages(%d) exceeded(%d)!!\n",
+ dio->max_pages, nr_pages);
+ crystalhd_unmap_dio(adp, dio);
+ return BC_STS_INSUFF_RES;
+ }
+
+ if (uv_offset) {
+ uv_start = (uaddr + (unsigned long)uv_offset) >> PAGE_SHIFT;
+ dio->uinfo.uv_sg_ix = uv_start - start;
+ dio->uinfo.uv_sg_off = ((uaddr + (unsigned long)uv_offset) & ~PAGE_MASK);
+ }
+
+ dio->fb_size = ubuff_sz & 0x03;
+ if (dio->fb_size) {
+ res = copy_from_user(dio->fb_va,
+ (void *)(uaddr + count - dio->fb_size),
+ dio->fb_size);
+ if (res) {
+ BCMLOG_ERR("failed %d to copy %u fill bytes from %p\n",
+ res, dio->fb_size,
+ (void *)(uaddr + count-dio->fb_size));
+ crystalhd_unmap_dio(adp, dio);
+ return BC_STS_INSUFF_RES;
+ }
+ }
+
+ down_read(&current->mm->mmap_sem);
+ res = get_user_pages(current, current->mm, uaddr, nr_pages, rw == READ,
+ 0, dio->pages, NULL);
+ up_read(&current->mm->mmap_sem);
+
+ /* Save for release..*/
+ dio->sig = crystalhd_dio_locked;
+ if (res < nr_pages) {
+ BCMLOG_ERR("get pages failed: %d-%d\n", nr_pages, res);
+ dio->page_cnt = res;
+ crystalhd_unmap_dio(adp, dio);
+ return BC_STS_ERROR;
+ }
+
+ dio->page_cnt = nr_pages;
+ /* Get scatter/gather */
+ crystalhd_init_sg(dio->sg, dio->page_cnt);
+ crystalhd_set_sg(&dio->sg[0], dio->pages[0], 0, uaddr & ~PAGE_MASK);
+ if (nr_pages > 1) {
+ dio->sg[0].length = PAGE_SIZE - dio->sg[0].offset;
+
+#ifdef CONFIG_X86_64
+ dio->sg[0].dma_length = dio->sg[0].length;
+#endif
+ count -= dio->sg[0].length;
+ for (i = 1; i < nr_pages; i++) {
+ if (count < 4) {
+ spsz = count;
+ skip_fb_sg = 1;
+ } else {
+ spsz = (count < PAGE_SIZE) ?
+ (count & ~0x03) : PAGE_SIZE;
+ }
+ crystalhd_set_sg(&dio->sg[i], dio->pages[i], spsz, 0);
+ count -= spsz;
+ }
+ } else {
+ if (count < 4) {
+ dio->sg[0].length = count;
+ skip_fb_sg = 1;
+ } else {
+ dio->sg[0].length = count - dio->fb_size;
+ }
+#ifdef CONFIG_X86_64
+ dio->sg[0].dma_length = dio->sg[0].length;
+#endif
+ }
+ dio->sg_cnt = pci_map_sg(adp->pdev, dio->sg,
+ dio->page_cnt, dio->direction);
+ if (dio->sg_cnt <= 0) {
+ BCMLOG_ERR("sg map %d-%d \n", dio->sg_cnt, dio->page_cnt);
+ crystalhd_unmap_dio(adp, dio);
+ return BC_STS_ERROR;
+ }
+ if (dio->sg_cnt && skip_fb_sg)
+ dio->sg_cnt -= 1;
+ dio->sig = crystalhd_dio_sg_mapped;
+ /* Fill in User info.. */
+ dio->uinfo.xfr_len = ubuff_sz;
+ dio->uinfo.xfr_buff = ubuff;
+ dio->uinfo.uv_offset = uv_offset;
+ dio->uinfo.b422mode = en_422mode;
+ dio->uinfo.dir_tx = dir_tx;
+
+ *dio_hnd = dio;
+
+ return BC_STS_SUCCESS;
+}
+
+/**
+ * crystalhd_unmap_sgl - Release mapped resources
+ * @adp: Adapter instance
+ * @dio: DIO request instance
+ *
+ * Return:
+ * Status.
+ *
+ * This routine is to unmap the user buffer pages.
+ */
+BC_STATUS crystalhd_unmap_dio(struct crystalhd_adp *adp, crystalhd_dio_req *dio)
+{
+ struct page *page = NULL;
+ int j = 0;
+
+ if (!adp || !dio) {
+ BCMLOG_ERR("Invalid arg \n");
+ return BC_STS_INV_ARG;
+ }
+
+ if ((dio->page_cnt > 0) && (dio->sig != crystalhd_dio_inv)) {
+ for (j = 0; j < dio->page_cnt; j++) {
+ page = dio->pages[j];
+ if (page) {
+ if (!PageReserved(page) &&
+ (dio->direction == DMA_FROM_DEVICE))
+ SetPageDirty(page);
+ page_cache_release(page);
+ }
+ }
+ }
+ if (dio->sig == crystalhd_dio_sg_mapped)
+ pci_unmap_sg(adp->pdev, dio->sg, dio->page_cnt, dio->direction);
+
+ crystalhd_free_dio(adp, dio);
+
+ return BC_STS_SUCCESS;
+}
+
+/**
+ * crystalhd_create_dio_pool - Allocate mem pool for DIO management.
+ * @adp: Adapter instance
+ * @max_pages: Max pages for size calculation.
+ *
+ * Return:
+ * system error.
+ *
+ * This routine creates a memory pool to hold dio context for
+ * for HW Direct IO operation.
+ */
+int crystalhd_create_dio_pool(struct crystalhd_adp *adp, uint32_t max_pages)
+{
+ uint32_t asz = 0, i = 0;
+ uint8_t *temp;
+ crystalhd_dio_req *dio;
+
+ if (!adp || !max_pages) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return -EINVAL;
+ }
+
+ /* Get dma memory for fill byte handling..*/
+ adp->fill_byte_pool = pci_pool_create("crystalhd_fbyte",
+ adp->pdev, 8, 8, 0);
+ if (!adp->fill_byte_pool) {
+ BCMLOG_ERR("failed to create fill byte pool\n");
+ return -ENOMEM;
+ }
+
+ /* Get the max size from user based on 420/422 modes */
+ asz = (sizeof(*dio->pages) * max_pages) +
+ (sizeof(*dio->sg) * max_pages) + sizeof(*dio);
+
+ BCMLOG(BCMLOG_DBG, "Initializing Dio pool %d %d %x %p\n",
+ BC_LINK_SG_POOL_SZ, max_pages, asz, adp->fill_byte_pool);
+
+ for (i = 0; i < BC_LINK_SG_POOL_SZ; i++) {
+ temp = (uint8_t *)kzalloc(asz, GFP_KERNEL);
+ if ((temp) == NULL) {
+ BCMLOG_ERR("Failed to alloc %d mem\n", asz);
+ return -ENOMEM;
+ }
+
+ dio = (crystalhd_dio_req *)temp;
+ temp += sizeof(*dio);
+ dio->pages = (struct page **)temp;
+ temp += (sizeof(*dio->pages) * max_pages);
+ dio->sg = (struct scatterlist *)temp;
+ dio->max_pages = max_pages;
+ dio->fb_va = pci_pool_alloc(adp->fill_byte_pool, GFP_KERNEL,
+ &dio->fb_pa);
+ if (!dio->fb_va) {
+ BCMLOG_ERR("fill byte alloc failed.\n");
+ return -ENOMEM;
+ }
+
+ crystalhd_free_dio(adp, dio);
+ }
+
+ return 0;
+}
+
+/**
+ * crystalhd_destroy_dio_pool - Release DIO mem pool.
+ * @adp: Adapter instance
+ *
+ * Return:
+ * none.
+ *
+ * This routine releases dio memory pool during close.
+ */
+void crystalhd_destroy_dio_pool(struct crystalhd_adp *adp)
+{
+ crystalhd_dio_req *dio;
+ int count = 0;
+
+ if (!adp) {
+ BCMLOG_ERR("Invalid Arg!!\n");
+ return;
+ }
+
+ do {
+ dio = crystalhd_alloc_dio(adp);
+ if (dio) {
+ if (dio->fb_va)
+ pci_pool_free(adp->fill_byte_pool,
+ dio->fb_va, dio->fb_pa);
+ count++;
+ kfree(dio);
+ }
+ } while (dio);
+
+ if (adp->fill_byte_pool) {
+ pci_pool_destroy(adp->fill_byte_pool);
+ adp->fill_byte_pool = NULL;
+ }
+
+ BCMLOG(BCMLOG_DBG, "Released dio pool %d \n", count);
+}
+
+/**
+ * crystalhd_create_elem_pool - List element pool creation.
+ * @adp: Adapter instance
+ * @pool_size: Number of elements in the pool.
+ *
+ * Return:
+ * 0 - success, <0 error
+ *
+ * Create general purpose list element pool to hold pending,
+ * and active requests.
+ */
+int __devinit crystalhd_create_elem_pool(struct crystalhd_adp *adp,
+ uint32_t pool_size)
+{
+ uint32_t i;
+ crystalhd_elem_t *temp;
+
+ if (!adp || !pool_size)
+ return -EINVAL;
+
+ for (i = 0; i < pool_size; i++) {
+ temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+ if (!temp) {
+ BCMLOG_ERR("kalloc failed \n");
+ return -ENOMEM;
+ }
+ crystalhd_free_elem(adp, temp);
+ }
+ BCMLOG(BCMLOG_DBG, "allocated %d elem\n", pool_size);
+ return 0;
+}
+
+/**
+ * crystalhd_delete_elem_pool - List element pool deletion.
+ * @adp: Adapter instance
+ *
+ * Return:
+ * none
+ *
+ * Delete general purpose list element pool.
+ */
+void crystalhd_delete_elem_pool(struct crystalhd_adp *adp)
+{
+ crystalhd_elem_t *temp;
+ int dbg_cnt = 0;
+
+ if (!adp)
+ return;
+
+ do {
+ temp = crystalhd_alloc_elem(adp);
+ if (temp) {
+ kfree(temp);
+ dbg_cnt++;
+ }
+ } while (temp);
+
+ BCMLOG(BCMLOG_DBG, "released %d elem\n", dbg_cnt);
+}
+
+/*================ Debug support routines.. ================================*/
+void crystalhd_show_buffer(uint32_t off, uint8_t *buff, uint32_t dwcount)
+{
+ uint32_t i, k = 1;
+
+ for (i = 0; i < dwcount; i++) {
+ if (k == 1)
+ BCMLOG(BCMLOG_DATA, "0x%08X : ", off);
+
+ BCMLOG(BCMLOG_DATA, " 0x%08X ", *((uint32_t *)buff));
+
+ buff += sizeof(uint32_t);
+ off += sizeof(uint32_t);
+ k++;
+ if ((i == dwcount - 1) || (k > 4)) {
+ BCMLOG(BCMLOG_DATA, "\n");
+ k = 1;
+ }
+ }
+}
diff --git a/drivers/staging/crystalhd/crystalhd_misc.h b/drivers/staging/crystalhd/crystalhd_misc.h
new file mode 100644
index 000000000000..a2aa6ad7fc81
--- /dev/null
+++ b/drivers/staging/crystalhd/crystalhd_misc.h
@@ -0,0 +1,229 @@
+/***************************************************************************
+ * Copyright (c) 2005-2009, Broadcom Corporation.
+ *
+ * Name: crystalhd_misc . h
+ *
+ * Description:
+ * BCM70012 Linux driver general purpose routines.
+ * Includes reg/mem read and write routines.
+ *
+ * HISTORY:
+ *
+ **********************************************************************
+ * This file is part of the crystalhd device driver.
+ *
+ * This driver 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.
+ *
+ * This driver 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 driver. If not, see <http://www.gnu.org/licenses/>.
+ **********************************************************************/
+
+#ifndef _CRYSTALHD_MISC_H_
+#define _CRYSTALHD_MISC_H_
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ioctl.h>
+#include <linux/dma-mapping.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <asm/system.h>
+#include "bc_dts_glob_lnx.h"
+
+/* Global log level variable defined in crystal_misc.c file */
+extern uint32_t g_linklog_level;
+
+/* Global element pool for all Queue management.
+ * TX: Active = BC_TX_LIST_CNT, Free = BC_TX_LIST_CNT.
+ * RX: Free = BC_RX_LIST_CNT, Active = 2
+ * FW-CMD: 4
+ */
+#define BC_LINK_ELEM_POOL_SZ ((BC_TX_LIST_CNT * 2) + BC_RX_LIST_CNT + 2 + 4)
+
+/* Driver's IODATA pool count */
+#define CHD_IODATA_POOL_SZ (BC_IOCTL_DATA_POOL_SIZE * BC_LINK_MAX_OPENS)
+
+/* Scatter Gather memory pool size for Tx and Rx */
+#define BC_LINK_SG_POOL_SZ (BC_TX_LIST_CNT + BC_RX_LIST_CNT)
+
+enum _crystalhd_dio_sig {
+ crystalhd_dio_inv = 0,
+ crystalhd_dio_locked,
+ crystalhd_dio_sg_mapped,
+};
+
+struct crystalhd_dio_user_info {
+ void *xfr_buff;
+ uint32_t xfr_len;
+ uint32_t uv_offset;
+ bool dir_tx;
+
+ uint32_t uv_sg_ix;
+ uint32_t uv_sg_off;
+ int comp_sts;
+ int ev_sts;
+ uint32_t y_done_sz;
+ uint32_t uv_done_sz;
+ uint32_t comp_flags;
+ bool b422mode;
+};
+
+typedef struct _crystalhd_dio_req {
+ uint32_t sig;
+ uint32_t max_pages;
+ struct page **pages;
+ struct scatterlist *sg;
+ int sg_cnt;
+ int page_cnt;
+ int direction;
+ struct crystalhd_dio_user_info uinfo;
+ void *fb_va;
+ uint32_t fb_size;
+ dma_addr_t fb_pa;
+ struct _crystalhd_dio_req *next;
+} crystalhd_dio_req;
+
+#define BC_LINK_DIOQ_SIG (0x09223280)
+
+typedef struct _crystalhd_elem_s {
+ struct _crystalhd_elem_s *flink;
+ struct _crystalhd_elem_s *blink;
+ void *data;
+ uint32_t tag;
+} crystalhd_elem_t;
+
+typedef void (*crystalhd_data_free_cb)(void *context, void *data);
+
+typedef struct _crystalhd_dioq_s {
+ uint32_t sig;
+ struct crystalhd_adp *adp;
+ crystalhd_elem_t *head;
+ crystalhd_elem_t *tail;
+ uint32_t count;
+ spinlock_t lock;
+ wait_queue_head_t event;
+ crystalhd_data_free_cb data_rel_cb;
+ void *cb_context;
+} crystalhd_dioq_t;
+
+typedef void (*hw_comp_callback)(crystalhd_dio_req *,
+ wait_queue_head_t *event, BC_STATUS sts);
+
+/*========= Decoder (7412) register access routines.================= */
+uint32_t bc_dec_reg_rd(struct crystalhd_adp *, uint32_t);
+void bc_dec_reg_wr(struct crystalhd_adp *, uint32_t, uint32_t);
+
+/*========= Link (70012) register access routines.. =================*/
+uint32_t crystalhd_reg_rd(struct crystalhd_adp *, uint32_t);
+void crystalhd_reg_wr(struct crystalhd_adp *, uint32_t, uint32_t);
+
+/*========= Decoder (7412) memory access routines..=================*/
+BC_STATUS crystalhd_mem_rd(struct crystalhd_adp *, uint32_t, uint32_t, uint32_t *);
+BC_STATUS crystalhd_mem_wr(struct crystalhd_adp *, uint32_t, uint32_t, uint32_t *);
+
+/*==========Link (70012) PCIe Config access routines.================*/
+BC_STATUS crystalhd_pci_cfg_rd(struct crystalhd_adp *, uint32_t, uint32_t, uint32_t *);
+BC_STATUS crystalhd_pci_cfg_wr(struct crystalhd_adp *, uint32_t, uint32_t, uint32_t);
+
+/*========= Linux Kernel Interface routines. ======================= */
+void *bc_kern_dma_alloc(struct crystalhd_adp *, uint32_t, dma_addr_t *);
+void bc_kern_dma_free(struct crystalhd_adp *, uint32_t,
+ void *, dma_addr_t);
+#define crystalhd_create_event(_ev) init_waitqueue_head(_ev)
+#define crystalhd_set_event(_ev) wake_up_interruptible(_ev)
+#define crystalhd_wait_on_event(ev, condition, timeout, ret, nosig) \
+do { \
+ DECLARE_WAITQUEUE(entry, current); \
+ unsigned long end = jiffies + ((timeout * HZ) / 1000); \
+ ret = 0; \
+ add_wait_queue(ev, &entry); \
+ for (;;) { \
+ __set_current_state(TASK_INTERRUPTIBLE); \
+ if (condition) { \
+ break; \
+ } \
+ if (time_after_eq(jiffies, end)) { \
+ ret = -EBUSY; \
+ break; \
+ } \
+ schedule_timeout((HZ / 100 > 1) ? HZ / 100 : 1); \
+ if (!nosig && signal_pending(current)) { \
+ ret = -EINTR; \
+ break; \
+ } \
+ } \
+ __set_current_state(TASK_RUNNING); \
+ remove_wait_queue(ev, &entry); \
+} while (0)
+
+/*================ Direct IO mapping routines ==================*/
+extern int crystalhd_create_dio_pool(struct crystalhd_adp *, uint32_t);
+extern void crystalhd_destroy_dio_pool(struct crystalhd_adp *);
+extern BC_STATUS crystalhd_map_dio(struct crystalhd_adp *, void *, uint32_t,
+ uint32_t, bool, bool, crystalhd_dio_req**);
+
+extern BC_STATUS crystalhd_unmap_dio(struct crystalhd_adp *, crystalhd_dio_req*);
+#define crystalhd_get_sgle_paddr(_dio, _ix) (cpu_to_le64(sg_dma_address(&_dio->sg[_ix])))
+#define crystalhd_get_sgle_len(_dio, _ix) (cpu_to_le32(sg_dma_len(&_dio->sg[_ix])))
+
+/*================ General Purpose Queues ==================*/
+extern BC_STATUS crystalhd_create_dioq(struct crystalhd_adp *, crystalhd_dioq_t **, crystalhd_data_free_cb , void *);
+extern void crystalhd_delete_dioq(struct crystalhd_adp *, crystalhd_dioq_t *);
+extern BC_STATUS crystalhd_dioq_add(crystalhd_dioq_t *ioq, void *data, bool wake, uint32_t tag);
+extern void *crystalhd_dioq_fetch(crystalhd_dioq_t *ioq);
+extern void *crystalhd_dioq_find_and_fetch(crystalhd_dioq_t *ioq, uint32_t tag);
+extern void *crystalhd_dioq_fetch_wait(crystalhd_dioq_t *ioq, uint32_t to_secs, uint32_t *sig_pend);
+
+#define crystalhd_dioq_count(_ioq) ((_ioq) ? _ioq->count : 0)
+
+extern int crystalhd_create_elem_pool(struct crystalhd_adp *, uint32_t);
+extern void crystalhd_delete_elem_pool(struct crystalhd_adp *);
+
+
+/*================ Debug routines/macros .. ================================*/
+extern void crystalhd_show_buffer(uint32_t off, uint8_t *buff, uint32_t dwcount);
+
+enum _chd_log_levels {
+ BCMLOG_ERROR = 0x80000000, /* Don't disable this option */
+ BCMLOG_DATA = 0x40000000, /* Data, enable by default */
+ BCMLOG_SPINLOCK = 0x20000000, /* Spcial case for Spin locks*/
+
+ /* Following are allowed only in debug mode */
+ BCMLOG_INFO = 0x00000001, /* Generic informational */
+ BCMLOG_DBG = 0x00000002, /* First level Debug info */
+ BCMLOG_SSTEP = 0x00000004, /* Stepping information */
+ BCMLOG_ENTER_LEAVE = 0x00000008, /* stack tracking */
+};
+
+#define BCMLOG_ENTER \
+if (g_linklog_level & BCMLOG_ENTER_LEAVE) { \
+ printk("Entered %s\n", __func__); \
+}
+
+#define BCMLOG_LEAVE \
+if (g_linklog_level & BCMLOG_ENTER_LEAVE) { \
+ printk("Leaving %s\n", __func__); \
+}
+
+#define BCMLOG(trace, fmt, args...) \
+if (g_linklog_level & trace) { \
+ printk(fmt, ##args); \
+}
+
+#define BCMLOG_ERR(fmt, args...) \
+do { \
+ if (g_linklog_level & BCMLOG_ERROR) { \
+ printk("*ERR*:%s:%d: "fmt, __FILE__, __LINE__, ##args); \
+ } \
+} while (0);
+
+#endif
diff --git a/drivers/staging/cx25821/cx25821-audups11.c b/drivers/staging/cx25821/cx25821-audups11.c
index 89c8fe2997fa..46c7f78bb972 100644
--- a/drivers/staging/cx25821/cx25821-audups11.c
+++ b/drivers/staging/cx25821/cx25821-audups11.c
@@ -343,10 +343,11 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctl)
{
struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
+ struct cx25821_dev *dev;
int err;
if (fh) {
+ dev = fh->dev;
err = v4l2_prio_check(&dev->prio, &fh->prio);
if (0 != err)
return err;
diff --git a/drivers/staging/cx25821/cx25821-medusa-video.c b/drivers/staging/cx25821/cx25821-medusa-video.c
index e4df8134f059..d6016200d699 100644
--- a/drivers/staging/cx25821/cx25821-medusa-video.c
+++ b/drivers/staging/cx25821/cx25821-medusa-video.c
@@ -795,10 +795,8 @@ int medusa_video_init(struct cx25821_dev *dev)
value &= 0xFFFFFFDF;
ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value);
- if (ret_val < 0) {
- mutex_unlock(&dev->lock);
+ if (ret_val < 0)
return -EINVAL;
- }
mutex_unlock(&dev->lock);
@@ -860,10 +858,8 @@ int medusa_video_init(struct cx25821_dev *dev)
ret_val = medusa_set_videostandard(dev);
- if (ret_val < 0) {
- mutex_unlock(&dev->lock);
+ if (ret_val < 0)
return -EINVAL;
- }
return 1;
}
diff --git a/drivers/staging/cx25821/cx25821-video.c b/drivers/staging/cx25821/cx25821-video.c
index c7c14c7698a7..8cd3986d2e5c 100644
--- a/drivers/staging/cx25821/cx25821-video.c
+++ b/drivers/staging/cx25821/cx25821-video.c
@@ -876,7 +876,7 @@ int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i)
dprintk(1, "%s()\n", __func__);
n = i->index;
- if (n > 2)
+ if (n >= 2)
return -EINVAL;
if (0 == INPUT(n)->type)
@@ -963,10 +963,11 @@ int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f)
int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f)
{
struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
+ struct cx25821_dev *dev;
int err;
if (fh) {
+ dev = fh->dev;
err = v4l2_prio_check(&dev->prio, &fh->prio);
if (0 != err)
return err;
diff --git a/drivers/staging/dream/camera/Kconfig b/drivers/staging/dream/camera/Kconfig
index 0a3e903b3363..bfb6d241d807 100644
--- a/drivers/staging/dream/camera/Kconfig
+++ b/drivers/staging/dream/camera/Kconfig
@@ -15,7 +15,7 @@ config MSM_CAMERA_DEBUG
config MSM_CAMERA_FLASH
bool "Qualcomm MSM camera flash support"
- depends on MSM_CAMERA
+ depends on MSM_CAMERA && BROKEN
---help---
Enable support for LED flash for msm camera
diff --git a/drivers/staging/dream/camera/Makefile b/drivers/staging/dream/camera/Makefile
index 4429ae5fcafd..db228d7d1136 100644
--- a/drivers/staging/dream/camera/Makefile
+++ b/drivers/staging/dream/camera/Makefile
@@ -1,3 +1,4 @@
+EXTRA_CFLAGS=-Idrivers/staging/dream/include
obj-$(CONFIG_MT9T013) += mt9t013.o mt9t013_reg.o
obj-$(CONFIG_MT9D112) += mt9d112.o mt9d112_reg.o
obj-$(CONFIG_MT9P012) += mt9p012_fox.o mt9p012_reg.o
diff --git a/drivers/staging/dream/camera/msm_camera.c b/drivers/staging/dream/camera/msm_camera.c
index 7d938772eacc..dc7c603625c7 100644
--- a/drivers/staging/dream/camera/msm_camera.c
+++ b/drivers/staging/dream/camera/msm_camera.c
@@ -2,7 +2,7 @@
* Copyright (C) 2008-2009 QUALCOMM Incorporated.
*/
-//FIXME: most allocations need not be GFP_ATOMIC
+/* FIXME: most allocations need not be GFP_ATOMIC */
/* FIXME: management of mutexes */
/* FIXME: msm_pmem_region_lookup return values */
/* FIXME: way too many copy to/from user */
@@ -76,14 +76,14 @@ static LIST_HEAD(msm_sensors);
list_del_init(&qcmd->list); \
kfree(qcmd); \
}; \
-} while(0)
+} while (0)
#define MSM_DRAIN_QUEUE(sync, name) do { \
unsigned long flags; \
spin_lock_irqsave(&(sync)->name##_lock, flags); \
MSM_DRAIN_QUEUE_NOSYNC(sync, name); \
spin_unlock_irqrestore(&(sync)->name##_lock, flags); \
-} while(0)
+} while (0)
static int check_overlap(struct hlist_head *ptype,
unsigned long paddr,
@@ -361,7 +361,7 @@ static int __msm_get_frame(struct msm_sync *sync,
if (!frame->buffer) {
pr_err("%s: cannot get frame, invalid lookup address "
"y=%x cbcr=%x offset=%d\n",
- __FUNCTION__,
+ __func__,
pphy->y_phy,
pphy->cbcr_phy,
frame->y_off);
@@ -455,7 +455,7 @@ static int msm_disable_vfe(struct msm_sync *sync, void __user *arg)
return rc;
}
-static struct msm_queue_cmd* __msm_control(struct msm_sync *sync,
+static struct msm_queue_cmd *__msm_control(struct msm_sync *sync,
struct msm_control_device_queue *queue,
struct msm_queue_cmd *qcmd,
int timeout)
@@ -592,8 +592,7 @@ end:
* a result of a successful completion, we are freeing the qcmd that
* we dequeued from queue->ctrl_status_q.
*/
- if (qcmd)
- kfree(qcmd);
+ kfree(qcmd);
CDBG("msm_control: end rc = %d\n", rc);
return rc;
@@ -670,7 +669,7 @@ static int msm_get_stats(struct msm_sync *sync, void __user *arg)
&(stats.fd));
if (!stats.buffer) {
pr_err("%s: msm_pmem_stats_ptov_lookup error\n",
- __FUNCTION__);
+ __func__);
rc = -EINVAL;
goto failure;
}
@@ -718,8 +717,7 @@ static int msm_get_stats(struct msm_sync *sync, void __user *arg)
buf.fmain.buffer =
(unsigned long)region.vaddr;
buf.fmain.fd = region.fd;
- }
- else {
+ } else {
pr_err("%s: pmem lookup failed\n",
__func__);
rc = -EINVAL;
@@ -796,8 +794,7 @@ static int msm_get_stats(struct msm_sync *sync, void __user *arg)
}
failure:
- if (qcmd)
- kfree(qcmd);
+ kfree(qcmd);
CDBG("msm_get_stats: %d\n", rc);
return rc;
@@ -838,8 +835,8 @@ static int msm_ctrl_cmd_done(struct msm_control_device *ctrl_pmsm,
kfree(qcmd);
goto end;
}
- }
- else ctrlcmd->value = NULL;
+ } else
+ ctrlcmd->value = NULL;
end:
CDBG("msm_ctrl_cmd_done: end rc = %d\n", rc);
@@ -869,14 +866,14 @@ static int msm_config_vfe(struct msm_sync *sync, void __user *arg)
return -EFAULT;
}
- switch(cfgcmd.cmd_type) {
+ switch (cfgcmd.cmd_type) {
case CMD_STATS_ENABLE:
axi_data.bufnum1 =
msm_pmem_region_lookup(&sync->stats,
MSM_PMEM_AEC_AWB, &region[0],
NUM_WB_EXP_STAT_OUTPUT_BUFFERS);
if (!axi_data.bufnum1) {
- pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+ pr_err("%s: pmem region lookup error\n", __func__);
return -EINVAL;
}
axi_data.region = &region[0];
@@ -888,7 +885,7 @@ static int msm_config_vfe(struct msm_sync *sync, void __user *arg)
MSM_PMEM_AF, &region[0],
NUM_AF_STAT_OUTPUT_BUFFERS);
if (!axi_data.bufnum1) {
- pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+ pr_err("%s: pmem region lookup error\n", __func__);
return -EINVAL;
}
axi_data.region = &region[0];
@@ -899,7 +896,7 @@ static int msm_config_vfe(struct msm_sync *sync, void __user *arg)
break;
default:
pr_err("%s: unknown command type %d\n",
- __FUNCTION__, cfgcmd.cmd_type);
+ __func__, cfgcmd.cmd_type);
return -EINVAL;
}
@@ -928,7 +925,7 @@ static int msm_frame_axi_cfg(struct msm_sync *sync,
msm_pmem_region_lookup(&sync->frame, pmem_type,
&region[0], 8);
if (!axi_data.bufnum1) {
- pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+ pr_err("%s: pmem region lookup error\n", __func__);
return -EINVAL;
}
break;
@@ -939,7 +936,7 @@ static int msm_frame_axi_cfg(struct msm_sync *sync,
msm_pmem_region_lookup(&sync->frame, pmem_type,
&region[0], 8);
if (!axi_data.bufnum2) {
- pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+ pr_err("%s: pmem region lookup error\n", __func__);
return -EINVAL;
}
break;
@@ -950,7 +947,7 @@ static int msm_frame_axi_cfg(struct msm_sync *sync,
msm_pmem_region_lookup(&sync->frame, pmem_type,
&region[0], 8);
if (!axi_data.bufnum1) {
- pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+ pr_err("%s: pmem region lookup error\n", __func__);
return -EINVAL;
}
@@ -959,7 +956,7 @@ static int msm_frame_axi_cfg(struct msm_sync *sync,
msm_pmem_region_lookup(&sync->frame, pmem_type,
&region[axi_data.bufnum1], 8);
if (!axi_data.bufnum2) {
- pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+ pr_err("%s: pmem region lookup error\n", __func__);
return -EINVAL;
}
break;
@@ -970,7 +967,7 @@ static int msm_frame_axi_cfg(struct msm_sync *sync,
msm_pmem_region_lookup(&sync->frame, pmem_type,
&region[0], 8);
if (!axi_data.bufnum2) {
- pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+ pr_err("%s: pmem region lookup error\n", __func__);
return -EINVAL;
}
break;
@@ -981,7 +978,7 @@ static int msm_frame_axi_cfg(struct msm_sync *sync,
default:
pr_err("%s: unknown command type %d\n",
- __FUNCTION__, cfgcmd->cmd_type);
+ __func__, cfgcmd->cmd_type);
return -EINVAL;
}
@@ -1047,7 +1044,7 @@ static int __msm_put_frame_buf(struct msm_sync *sync,
rc = sync->vfefn.vfe_config(&cfgcmd, &pphy);
} else {
pr_err("%s: msm_pmem_frame_vtop_lookup failed\n",
- __FUNCTION__);
+ __func__);
rc = -EINVAL;
}
@@ -1131,7 +1128,7 @@ static int msm_stats_axi_cfg(struct msm_sync *sync,
break;
default:
pr_err("%s: unknown command type %d\n",
- __FUNCTION__, cfgcmd->cmd_type);
+ __func__, cfgcmd->cmd_type);
return -EINVAL;
}
@@ -1140,7 +1137,7 @@ static int msm_stats_axi_cfg(struct msm_sync *sync,
msm_pmem_region_lookup(&sync->stats, pmem_type,
&region[0], NUM_WB_EXP_STAT_OUTPUT_BUFFERS);
if (!axi_data.bufnum1) {
- pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+ pr_err("%s: pmem region lookup error\n", __func__);
return -EINVAL;
}
axi_data.region = &region[0];
@@ -1177,7 +1174,7 @@ static int msm_put_stats_buffer(struct msm_sync *sync, void __user *arg)
cfgcmd.cmd_type = CMD_STATS_AF_BUF_RELEASE;
else {
pr_err("%s: invalid buf type %d\n",
- __FUNCTION__,
+ __func__,
buf.type);
rc = -EINVAL;
goto put_done;
@@ -1223,7 +1220,7 @@ static int msm_axi_config(struct msm_sync *sync, void __user *arg)
default:
pr_err("%s: unknown command type %d\n",
- __FUNCTION__,
+ __func__,
cfgcmd.cmd_type);
return -EINVAL;
}
@@ -1622,7 +1619,8 @@ static int msm_release_control(struct inode *node, struct file *filep)
int rc;
struct msm_control_device *ctrl_pmsm = filep->private_data;
struct msm_device *pmsm = ctrl_pmsm->pmsm;
- printk("msm_camera: RELEASE %s\n", filep->f_path.dentry->d_name.name);
+ printk(KERN_INFO "msm_camera: RELEASE %s\n",
+ filep->f_path.dentry->d_name.name);
rc = __msm_release(pmsm->sync);
if (!rc) {
MSM_DRAIN_QUEUE(&ctrl_pmsm->ctrl_q, ctrl_status_q);
@@ -1636,7 +1634,8 @@ static int msm_release_frame(struct inode *node, struct file *filep)
{
int rc;
struct msm_device *pmsm = filep->private_data;
- printk("msm_camera: RELEASE %s\n", filep->f_path.dentry->d_name.name);
+ printk(KERN_INFO "msm_camera: RELEASE %s\n",
+ filep->f_path.dentry->d_name.name);
rc = __msm_release(pmsm->sync);
if (!rc) {
MSM_DRAIN_QUEUE(pmsm->sync, prev_frame_q);
@@ -1720,7 +1719,7 @@ static void msm_vfe_sync(struct msm_vfe_resp *vdata,
qcmd->type = qtype;
if (qtype == MSM_CAM_Q_VFE_MSG) {
- switch(vdata->type) {
+ switch (vdata->type) {
case VFE_MSG_OUTPUT1:
case VFE_MSG_OUTPUT2:
qcmd_frame =
@@ -1885,8 +1884,10 @@ static int msm_open_control(struct inode *inode, struct file *filep)
return -ENOMEM;
rc = msm_open_common(inode, filep, 0);
- if (rc < 0)
+ if (rc < 0) {
+ kfree(ctrl_pmsm);
return rc;
+ }
ctrl_pmsm->pmsm = filep->private_data;
filep->private_data = ctrl_pmsm;
@@ -1929,7 +1930,7 @@ static int __msm_v4l2_control(struct msm_sync *sync,
memcpy(out->value, ctrl->value, ctrl->length);
end:
- if (rcmd) kfree(rcmd);
+ kfree(rcmd);
CDBG("__msm_v4l2_control: end rc = %d\n", rc);
return rc;
}
diff --git a/drivers/staging/dream/camera/msm_vfe7x.c b/drivers/staging/dream/camera/msm_vfe7x.c
index 33ab3ac6ac57..62fd24d632d5 100644
--- a/drivers/staging/dream/camera/msm_vfe7x.c
+++ b/drivers/staging/dream/camera/msm_vfe7x.c
@@ -255,8 +255,7 @@ static int vfe_7x_init(struct msm_vfe_callback *presp,
extlen = sizeof(struct vfe_frame_extra);
- extdata =
- kmalloc(sizeof(extlen), GFP_ATOMIC);
+ extdata = kmalloc(extlen, GFP_ATOMIC);
if (!extdata) {
rc = -ENOMEM;
goto init_fail;
diff --git a/drivers/staging/dream/camera/s5k3e2fx.c b/drivers/staging/dream/camera/s5k3e2fx.c
index edba19889b0f..841792e2624b 100644
--- a/drivers/staging/dream/camera/s5k3e2fx.c
+++ b/drivers/staging/dream/camera/s5k3e2fx.c
@@ -743,12 +743,12 @@ static int s5k3e2fx_sensor_open_init(const struct msm_camera_sensor_info *data)
}
/* initialize AF */
- if ((rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
- 0x3146, 0x3A)) < 0)
+ rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3146, 0x3A);
+ if (rc < 0)
goto init_fail1;
- if ((rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
- 0x3130, 0x03)) < 0)
+ rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3130, 0x03);
+ if (rc < 0)
goto init_fail1;
goto init_done;
@@ -814,20 +814,20 @@ static uint16_t s5k3e2fx_get_prev_lines_pf(void)
static uint16_t s5k3e2fx_get_prev_pixels_pl(void)
{
- return (s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
- s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p);
+ return s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
+ s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p;
}
static uint16_t s5k3e2fx_get_pict_lines_pf(void)
{
- return (s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
- s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l);
+ return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
+ s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l;
}
static uint16_t s5k3e2fx_get_pict_pixels_pl(void)
{
- return (s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
- s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p);
+ return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
+ s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p;
}
static uint32_t s5k3e2fx_get_pict_max_exp_lc(void)
@@ -1093,14 +1093,10 @@ static int32_t s5k3e2fx_move_focus(int direction, int32_t num_steps)
actual_step = step_direction * (int16_t)num_steps;
pos_offset = init_code + s5k3e2fx_ctrl->curr_lens_pos;
- gain = actual_step * 0x400 / 5;
+ gain = ((actual_step << 10) / 5) >> 10;
- for (i = 0; i <= 4; i++) {
- if (actual_step >= 0)
- s_move[i] = ((((i+1)*gain+0x200) - (i*gain+0x200))/0x400);
- else
- s_move[i] = ((((i+1)*gain-0x200) - (i*gain-0x200))/0x400);
- }
+ for (i = 0; i <= 4; i++)
+ s_move[i] = gain;
/* Ring Damping Code */
for (i = 0; i <= 4; i++) {
diff --git a/drivers/staging/dream/include/linux/android_pmem.h b/drivers/staging/dream/include/linux/android_pmem.h
new file mode 100644
index 000000000000..2fc05d7d335b
--- /dev/null
+++ b/drivers/staging/dream/include/linux/android_pmem.h
@@ -0,0 +1,80 @@
+/* drivers/staging/dream/include/linux/android_pmem.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _ANDROID_PMEM_H_
+#define _ANDROID_PMEM_H_
+
+#define PMEM_IOCTL_MAGIC 'p'
+#define PMEM_GET_PHYS _IOW(PMEM_IOCTL_MAGIC, 1, unsigned int)
+#define PMEM_MAP _IOW(PMEM_IOCTL_MAGIC, 2, unsigned int)
+#define PMEM_GET_SIZE _IOW(PMEM_IOCTL_MAGIC, 3, unsigned int)
+#define PMEM_UNMAP _IOW(PMEM_IOCTL_MAGIC, 4, unsigned int)
+/* This ioctl will allocate pmem space, backing the file, it will fail
+ * if the file already has an allocation, pass it the len as the argument
+ * to the ioctl */
+#define PMEM_ALLOCATE _IOW(PMEM_IOCTL_MAGIC, 5, unsigned int)
+/* This will connect a one pmem file to another, pass the file that is already
+ * backed in memory as the argument to the ioctl
+ */
+#define PMEM_CONNECT _IOW(PMEM_IOCTL_MAGIC, 6, unsigned int)
+/* Returns the total size of the pmem region it is sent to as a pmem_region
+ * struct (with offset set to 0).
+ */
+#define PMEM_GET_TOTAL_SIZE _IOW(PMEM_IOCTL_MAGIC, 7, unsigned int)
+/* Revokes gpu registers and resets the gpu. Pass a pointer to the
+ * start of the mapped gpu regs (the vaddr returned by mmap) as the argument.
+ */
+#define HW3D_REVOKE_GPU _IOW(PMEM_IOCTL_MAGIC, 8, unsigned int)
+#define HW3D_GRANT_GPU _IOW(PMEM_IOCTL_MAGIC, 9, unsigned int)
+#define HW3D_WAIT_FOR_INTERRUPT _IOW(PMEM_IOCTL_MAGIC, 10, unsigned int)
+
+int get_pmem_file(int fd, unsigned long *start, unsigned long *vstart,
+ unsigned long *end, struct file **filp);
+int get_pmem_user_addr(struct file *file, unsigned long *start,
+ unsigned long *end);
+void put_pmem_file(struct file* file);
+void flush_pmem_file(struct file *file, unsigned long start, unsigned long len);
+
+struct android_pmem_platform_data
+{
+ const char* name;
+ /* starting physical address of memory region */
+ unsigned long start;
+ /* size of memory region */
+ unsigned long size;
+ /* set to indicate the region should not be managed with an allocator */
+ unsigned no_allocator;
+ /* set to indicate maps of this region should be cached, if a mix of
+ * cached and uncached is desired, set this and open the device with
+ * O_SYNC to get an uncached region */
+ unsigned cached;
+ /* The MSM7k has bits to enable a write buffer in the bus controller*/
+ unsigned buffered;
+};
+
+struct pmem_region {
+ unsigned long offset;
+ unsigned long len;
+};
+
+int pmem_setup(struct android_pmem_platform_data *pdata,
+ long (*ioctl)(struct file *, unsigned int, unsigned long),
+ int (*release)(struct inode *, struct file *));
+
+int pmem_remap(struct pmem_region *region, struct file *file,
+ unsigned operation);
+
+#endif //_ANDROID_PPP_H_
+
diff --git a/drivers/staging/dream/include/linux/gpio_event.h b/drivers/staging/dream/include/linux/gpio_event.h
new file mode 100644
index 000000000000..ffc5da392ad7
--- /dev/null
+++ b/drivers/staging/dream/include/linux/gpio_event.h
@@ -0,0 +1,154 @@
+/* drivers/staging/dream/include/linux/gpio_event.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_GPIO_EVENT_H
+#define _LINUX_GPIO_EVENT_H
+
+#include <linux/input.h>
+
+enum {
+ GPIO_EVENT_FUNC_UNINIT = 0x0,
+ GPIO_EVENT_FUNC_INIT = 0x1,
+ GPIO_EVENT_FUNC_SUSPEND = 0x2,
+ GPIO_EVENT_FUNC_RESUME = 0x3,
+};
+struct gpio_event_info {
+ int (*func)(struct input_dev *input_dev,
+ struct gpio_event_info *info,
+ void **data, int func);
+ int (*event)(struct input_dev *input_dev,
+ struct gpio_event_info *info,
+ void **data, unsigned int type,
+ unsigned int code, int value); /* out events */
+};
+
+struct gpio_event_platform_data {
+ const char *name;
+ struct gpio_event_info **info;
+ size_t info_count;
+ int (*power)(const struct gpio_event_platform_data *pdata, bool on);
+};
+
+#define GPIO_EVENT_DEV_NAME "gpio-event"
+
+/* Key matrix */
+
+enum gpio_event_matrix_flags {
+ /* unset: drive active output low, set: drive active output high */
+ GPIOKPF_ACTIVE_HIGH = 1U << 0,
+ GPIOKPF_DEBOUNCE = 1U << 1,
+ GPIOKPF_REMOVE_SOME_PHANTOM_KEYS = 1U << 2,
+ GPIOKPF_REMOVE_PHANTOM_KEYS = GPIOKPF_REMOVE_SOME_PHANTOM_KEYS |
+ GPIOKPF_DEBOUNCE,
+ GPIOKPF_DRIVE_INACTIVE = 1U << 3,
+ GPIOKPF_LEVEL_TRIGGERED_IRQ = 1U << 4,
+ GPIOKPF_PRINT_UNMAPPED_KEYS = 1U << 16,
+ GPIOKPF_PRINT_MAPPED_KEYS = 1U << 17,
+ GPIOKPF_PRINT_PHANTOM_KEYS = 1U << 18,
+};
+
+extern int gpio_event_matrix_func(struct input_dev *input_dev,
+ struct gpio_event_info *info, void **data, int func);
+struct gpio_event_matrix_info {
+ /* initialize to gpio_event_matrix_func */
+ struct gpio_event_info info;
+ /* size must be ninputs * noutputs */
+ const unsigned short *keymap;
+ unsigned int *input_gpios;
+ unsigned int *output_gpios;
+ unsigned int ninputs;
+ unsigned int noutputs;
+ /* time to wait before reading inputs after driving each output */
+ ktime_t settle_time;
+ /* time to wait before scanning the keypad a second time */
+ ktime_t debounce_delay;
+ ktime_t poll_time;
+ unsigned flags;
+};
+
+/* Directly connected inputs and outputs */
+
+enum gpio_event_direct_flags {
+ GPIOEDF_ACTIVE_HIGH = 1U << 0,
+/* GPIOEDF_USE_DOWN_IRQ = 1U << 1, */
+/* GPIOEDF_USE_IRQ = (1U << 2) | GPIOIDF_USE_DOWN_IRQ, */
+ GPIOEDF_PRINT_KEYS = 1U << 8,
+ GPIOEDF_PRINT_KEY_DEBOUNCE = 1U << 9,
+};
+
+struct gpio_event_direct_entry {
+ uint32_t gpio:23;
+ uint32_t code:9;
+};
+
+/* inputs */
+extern int gpio_event_input_func(struct input_dev *input_dev,
+ struct gpio_event_info *info, void **data, int func);
+struct gpio_event_input_info {
+ /* initialize to gpio_event_input_func */
+ struct gpio_event_info info;
+ ktime_t debounce_time;
+ ktime_t poll_time;
+ uint16_t flags;
+ uint16_t type;
+ const struct gpio_event_direct_entry *keymap;
+ size_t keymap_size;
+};
+
+/* outputs */
+extern int gpio_event_output_func(struct input_dev *input_dev,
+ struct gpio_event_info *info, void **data, int func);
+extern int gpio_event_output_event(struct input_dev *input_dev,
+ struct gpio_event_info *info, void **data,
+ unsigned int type, unsigned int code, int value);
+struct gpio_event_output_info {
+ /* initialize to gpio_event_output_func and gpio_event_output_event */
+ struct gpio_event_info info;
+ uint16_t flags;
+ uint16_t type;
+ const struct gpio_event_direct_entry *keymap;
+ size_t keymap_size;
+};
+
+
+/* axes */
+
+enum gpio_event_axis_flags {
+ GPIOEAF_PRINT_UNKNOWN_DIRECTION = 1U << 16,
+ GPIOEAF_PRINT_RAW = 1U << 17,
+ GPIOEAF_PRINT_EVENT = 1U << 18,
+};
+
+extern int gpio_event_axis_func(struct input_dev *input_dev,
+ struct gpio_event_info *info, void **data, int func);
+struct gpio_event_axis_info {
+ /* initialize to gpio_event_axis_func */
+ struct gpio_event_info info;
+ uint8_t count;
+ uint8_t type; /* EV_REL or EV_ABS */
+ uint16_t code;
+ uint16_t decoded_size;
+ uint16_t (*map)(struct gpio_event_axis_info *info, uint16_t in);
+ uint32_t *gpio;
+ uint32_t flags;
+};
+#define gpio_axis_2bit_gray_map gpio_axis_4bit_gray_map
+#define gpio_axis_3bit_gray_map gpio_axis_4bit_gray_map
+uint16_t gpio_axis_4bit_gray_map(
+ struct gpio_event_axis_info *info, uint16_t in);
+uint16_t gpio_axis_5bit_singletrack_map(
+ struct gpio_event_axis_info *info, uint16_t in);
+
+#endif
diff --git a/drivers/staging/dream/include/linux/msm_adsp.h b/drivers/staging/dream/include/linux/msm_adsp.h
new file mode 100644
index 000000000000..e775f3e94f1d
--- /dev/null
+++ b/drivers/staging/dream/include/linux/msm_adsp.h
@@ -0,0 +1,84 @@
+/* drivers/staging/dream/include/linux/msm_adsp.h
+ *
+ * Copyright (c) QUALCOMM Incorporated
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Iliyan Malchev <ibm@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __LINUX_MSM_ADSP_H
+#define __LINUX_MSM_ADSP_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define ADSP_IOCTL_MAGIC 'q'
+
+/* ADSP_IOCTL_WRITE_COMMAND */
+struct adsp_command_t {
+ uint16_t queue;
+ uint32_t len; /* bytes */
+ uint8_t *data;
+};
+
+/* ADSP_IOCTL_GET_EVENT */
+struct adsp_event_t {
+ uint16_t type; /* 1 == event (RPC), 0 == message (adsp) */
+ uint32_t timeout_ms; /* -1 for infinite, 0 for immediate return */
+ uint16_t msg_id;
+ uint16_t flags; /* 1 == 16--bit event, 0 == 32-bit event */
+ uint32_t len; /* size in, number of bytes out */
+ uint8_t *data;
+};
+
+#define ADSP_IOCTL_ENABLE \
+ _IOR(ADSP_IOCTL_MAGIC, 1, unsigned)
+
+#define ADSP_IOCTL_DISABLE \
+ _IOR(ADSP_IOCTL_MAGIC, 2, unsigned)
+
+#define ADSP_IOCTL_DISABLE_ACK \
+ _IOR(ADSP_IOCTL_MAGIC, 3, unsigned)
+
+#define ADSP_IOCTL_WRITE_COMMAND \
+ _IOR(ADSP_IOCTL_MAGIC, 4, struct adsp_command_t *)
+
+#define ADSP_IOCTL_GET_EVENT \
+ _IOWR(ADSP_IOCTL_MAGIC, 5, struct adsp_event_data_t *)
+
+#define ADSP_IOCTL_SET_CLKRATE \
+ _IOR(ADSP_IOCTL_MAGIC, 6, unsigned)
+
+#define ADSP_IOCTL_DISABLE_EVENT_RSP \
+ _IOR(ADSP_IOCTL_MAGIC, 10, unsigned)
+
+struct adsp_pmem_info {
+ int fd;
+ void *vaddr;
+};
+
+#define ADSP_IOCTL_REGISTER_PMEM \
+ _IOW(ADSP_IOCTL_MAGIC, 13, unsigned)
+
+#define ADSP_IOCTL_UNREGISTER_PMEM \
+ _IOW(ADSP_IOCTL_MAGIC, 14, unsigned)
+
+/* Cause any further GET_EVENT ioctls to fail (-ENODEV)
+ * until the device is closed and reopened. Useful for
+ * terminating event dispatch threads
+ */
+#define ADSP_IOCTL_ABORT_EVENT_READ \
+ _IOW(ADSP_IOCTL_MAGIC, 15, unsigned)
+
+#define ADSP_IOCTL_LINK_TASK \
+ _IOW(ADSP_IOCTL_MAGIC, 16, unsigned)
+
+#endif
diff --git a/drivers/staging/dream/include/linux/msm_audio.h b/drivers/staging/dream/include/linux/msm_audio.h
new file mode 100644
index 000000000000..cfbdaa0d98b2
--- /dev/null
+++ b/drivers/staging/dream/include/linux/msm_audio.h
@@ -0,0 +1,115 @@
+/* drivers/staging/dream/include/linux/msm_audio.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __LINUX_MSM_AUDIO_H
+#define __LINUX_MSM_AUDIO_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/sizes.h>
+
+/* PCM Audio */
+
+#define AUDIO_IOCTL_MAGIC 'a'
+
+#define AUDIO_START _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned)
+#define AUDIO_STOP _IOW(AUDIO_IOCTL_MAGIC, 1, unsigned)
+#define AUDIO_FLUSH _IOW(AUDIO_IOCTL_MAGIC, 2, unsigned)
+#define AUDIO_GET_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 3, unsigned)
+#define AUDIO_SET_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 4, unsigned)
+#define AUDIO_GET_STATS _IOR(AUDIO_IOCTL_MAGIC, 5, unsigned)
+#define AUDIO_ENABLE_AUDPP _IOW(AUDIO_IOCTL_MAGIC, 6, unsigned)
+#define AUDIO_SET_ADRC _IOW(AUDIO_IOCTL_MAGIC, 7, unsigned)
+#define AUDIO_SET_EQ _IOW(AUDIO_IOCTL_MAGIC, 8, unsigned)
+#define AUDIO_SET_RX_IIR _IOW(AUDIO_IOCTL_MAGIC, 9, unsigned)
+#define AUDIO_SET_VOLUME _IOW(AUDIO_IOCTL_MAGIC, 10, unsigned)
+#define AUDIO_ENABLE_AUDPRE _IOW(AUDIO_IOCTL_MAGIC, 11, unsigned)
+#define AUDIO_SET_AGC _IOW(AUDIO_IOCTL_MAGIC, 12, unsigned)
+#define AUDIO_SET_NS _IOW(AUDIO_IOCTL_MAGIC, 13, unsigned)
+#define AUDIO_SET_TX_IIR _IOW(AUDIO_IOCTL_MAGIC, 14, unsigned)
+#define AUDIO_PAUSE _IOW(AUDIO_IOCTL_MAGIC, 15, unsigned)
+#define AUDIO_GET_PCM_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 30, unsigned)
+#define AUDIO_SET_PCM_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 31, unsigned)
+#define AUDIO_SWITCH_DEVICE _IOW(AUDIO_IOCTL_MAGIC, 32, unsigned)
+
+#define AUDIO_MAX_COMMON_IOCTL_NUM 100
+
+#define AUDIO_MAX_COMMON_IOCTL_NUM 100
+
+struct msm_audio_config {
+ uint32_t buffer_size;
+ uint32_t buffer_count;
+ uint32_t channel_count;
+ uint32_t sample_rate;
+ uint32_t type;
+ uint32_t unused[3];
+};
+
+struct msm_audio_stats {
+ uint32_t byte_count;
+ uint32_t sample_count;
+ uint32_t unused[2];
+};
+
+/* Audio routing */
+
+#define SND_IOCTL_MAGIC 's'
+
+#define SND_MUTE_UNMUTED 0
+#define SND_MUTE_MUTED 1
+
+struct msm_snd_device_config {
+ uint32_t device;
+ uint32_t ear_mute;
+ uint32_t mic_mute;
+};
+
+#define SND_SET_DEVICE _IOW(SND_IOCTL_MAGIC, 2, struct msm_device_config *)
+
+#define SND_METHOD_VOICE 0
+
+struct msm_snd_volume_config {
+ uint32_t device;
+ uint32_t method;
+ uint32_t volume;
+};
+
+#define SND_SET_VOLUME _IOW(SND_IOCTL_MAGIC, 3, struct msm_snd_volume_config *)
+
+/* Returns the number of SND endpoints supported. */
+
+#define SND_GET_NUM_ENDPOINTS _IOR(SND_IOCTL_MAGIC, 4, unsigned *)
+
+struct msm_snd_endpoint {
+ int id; /* input and output */
+ char name[64]; /* output only */
+};
+
+/* Takes an index between 0 and one less than the number returned by
+ * SND_GET_NUM_ENDPOINTS, and returns the SND index and name of a
+ * SND endpoint. On input, the .id field contains the number of the
+ * endpoint, and on exit it contains the SND index, while .name contains
+ * the description of the endpoint.
+ */
+
+#define SND_GET_ENDPOINT _IOWR(SND_IOCTL_MAGIC, 5, struct msm_snd_endpoint *)
+
+struct msm_audio_pcm_config {
+ uint32_t pcm_feedback; /* 0 - disable > 0 - enable */
+ uint32_t buffer_count; /* Number of buffers to allocate */
+ uint32_t buffer_size; /* Size of buffer for capturing of
+ PCM samples */
+};
+#endif
diff --git a/drivers/staging/dream/include/linux/msm_rpcrouter.h b/drivers/staging/dream/include/linux/msm_rpcrouter.h
new file mode 100644
index 000000000000..64845fb481f1
--- /dev/null
+++ b/drivers/staging/dream/include/linux/msm_rpcrouter.h
@@ -0,0 +1,47 @@
+/* drivers/staging/dream/include/linux/msm_rpcrouter.h
+ *
+ * Copyright (c) QUALCOMM Incorporated
+ * Copyright (C) 2007 Google, Inc.
+ * Author: San Mehat <san@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __LINUX_MSM_RPCROUTER_H
+#define __LINUX_MSM_RPCROUTER_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define RPC_ROUTER_VERSION_V1 0x00010000
+
+struct rpcrouter_ioctl_server_args {
+ uint32_t prog;
+ uint32_t vers;
+};
+
+#define RPC_ROUTER_IOCTL_MAGIC (0xC1)
+
+#define RPC_ROUTER_IOCTL_GET_VERSION \
+ _IOR(RPC_ROUTER_IOCTL_MAGIC, 0, unsigned int)
+
+#define RPC_ROUTER_IOCTL_GET_MTU \
+ _IOR(RPC_ROUTER_IOCTL_MAGIC, 1, unsigned int)
+
+#define RPC_ROUTER_IOCTL_REGISTER_SERVER \
+ _IOWR(RPC_ROUTER_IOCTL_MAGIC, 2, unsigned int)
+
+#define RPC_ROUTER_IOCTL_UNREGISTER_SERVER \
+ _IOWR(RPC_ROUTER_IOCTL_MAGIC, 3, unsigned int)
+
+#define RPC_ROUTER_IOCTL_GET_MINOR_VERSION \
+ _IOW(RPC_ROUTER_IOCTL_MAGIC, 4, unsigned int)
+
+#endif
diff --git a/drivers/staging/dream/include/linux/wakelock.h b/drivers/staging/dream/include/linux/wakelock.h
new file mode 100644
index 000000000000..93c31a4d1ca7
--- /dev/null
+++ b/drivers/staging/dream/include/linux/wakelock.h
@@ -0,0 +1,91 @@
+/* drivers/staging/dream/include/linux/wakelock.h
+ *
+ * Copyright (C) 2007-2008 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_WAKELOCK_H
+#define _LINUX_WAKELOCK_H
+
+#include <linux/list.h>
+#include <linux/ktime.h>
+
+/* A wake_lock prevents the system from entering suspend or other low power
+ * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock
+ * prevents a full system suspend. If the type is WAKE_LOCK_IDLE, low power
+ * states that cause large interrupt latencies or that disable a set of
+ * interrupts will not entered from idle until the wake_locks are released.
+ */
+
+enum {
+ WAKE_LOCK_SUSPEND, /* Prevent suspend */
+ WAKE_LOCK_IDLE, /* Prevent low power idle */
+ WAKE_LOCK_TYPE_COUNT
+};
+
+struct wake_lock {
+#ifdef CONFIG_HAS_WAKELOCK
+ struct list_head link;
+ int flags;
+ const char *name;
+ unsigned long expires;
+#ifdef CONFIG_WAKELOCK_STAT
+ struct {
+ int count;
+ int expire_count;
+ int wakeup_count;
+ ktime_t total_time;
+ ktime_t prevent_suspend_time;
+ ktime_t max_time;
+ ktime_t last_time;
+ } stat;
+#endif
+#endif
+};
+
+#ifdef CONFIG_HAS_WAKELOCK
+
+void wake_lock_init(struct wake_lock *lock, int type, const char *name);
+void wake_lock_destroy(struct wake_lock *lock);
+void wake_lock(struct wake_lock *lock);
+void wake_lock_timeout(struct wake_lock *lock, long timeout);
+void wake_unlock(struct wake_lock *lock);
+
+/* wake_lock_active returns a non-zero value if the wake_lock is currently
+ * locked. If the wake_lock has a timeout, it does not check the timeout
+ * but if the timeout had aready been checked it will return 0.
+ */
+int wake_lock_active(struct wake_lock *lock);
+
+/* has_wake_lock returns 0 if no wake locks of the specified type are active,
+ * and non-zero if one or more wake locks are held. Specifically it returns
+ * -1 if one or more wake locks with no timeout are active or the
+ * number of jiffies until all active wake locks time out.
+ */
+long has_wake_lock(int type);
+
+#else
+
+static inline void wake_lock_init(struct wake_lock *lock, int type,
+ const char *name) {}
+static inline void wake_lock_destroy(struct wake_lock *lock) {}
+static inline void wake_lock(struct wake_lock *lock) {}
+static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) {}
+static inline void wake_unlock(struct wake_lock *lock) {}
+
+static inline int wake_lock_active(struct wake_lock *lock) { return 0; }
+static inline long has_wake_lock(int type) { return 0; }
+
+#endif
+
+#endif
+
diff --git a/drivers/staging/dream/include/mach/camera.h b/drivers/staging/dream/include/mach/camera.h
new file mode 100644
index 000000000000..c20f0423abd4
--- /dev/null
+++ b/drivers/staging/dream/include/mach/camera.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+#ifndef __ASM__ARCH_CAMERA_H
+#define __ASM__ARCH_CAMERA_H
+
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include "linux/types.h"
+
+#include <mach/board.h>
+#include <media/msm_camera.h>
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define CDBG(fmt, args...) printk(KERN_INFO "msm_camera: " fmt, ##args)
+#else
+#define CDBG(fmt, args...) do { } while (0)
+#endif
+
+#define MSM_CAMERA_MSG 0
+#define MSM_CAMERA_EVT 1
+#define NUM_WB_EXP_NEUTRAL_REGION_LINES 4
+#define NUM_WB_EXP_STAT_OUTPUT_BUFFERS 3
+#define NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS 16
+#define NUM_AF_STAT_OUTPUT_BUFFERS 3
+
+enum msm_queue {
+ MSM_CAM_Q_CTRL, /* control command or control command status */
+ MSM_CAM_Q_VFE_EVT, /* adsp event */
+ MSM_CAM_Q_VFE_MSG, /* adsp message */
+ MSM_CAM_Q_V4L2_REQ, /* v4l2 request */
+};
+
+enum vfe_resp_msg {
+ VFE_EVENT,
+ VFE_MSG_GENERAL,
+ VFE_MSG_SNAPSHOT,
+ VFE_MSG_OUTPUT1,
+ VFE_MSG_OUTPUT2,
+ VFE_MSG_STATS_AF,
+ VFE_MSG_STATS_WE,
+};
+
+struct msm_vfe_phy_info {
+ uint32_t sbuf_phy;
+ uint32_t y_phy;
+ uint32_t cbcr_phy;
+};
+
+struct msm_vfe_resp {
+ enum vfe_resp_msg type;
+ struct msm_vfe_evt_msg evt_msg;
+ struct msm_vfe_phy_info phy;
+ void *extdata;
+ int32_t extlen;
+};
+
+struct msm_vfe_callback {
+ void (*vfe_resp)(struct msm_vfe_resp *,
+ enum msm_queue, void *syncdata);
+ void* (*vfe_alloc)(int, void *syncdata);
+};
+
+struct msm_camvfe_fn {
+ int (*vfe_init)(struct msm_vfe_callback *, struct platform_device *);
+ int (*vfe_enable)(struct camera_enable_cmd *);
+ int (*vfe_config)(struct msm_vfe_cfg_cmd *, void *);
+ int (*vfe_disable)(struct camera_enable_cmd *,
+ struct platform_device *dev);
+ void (*vfe_release)(struct platform_device *);
+};
+
+struct msm_sensor_ctrl {
+ int (*s_init)(const struct msm_camera_sensor_info *);
+ int (*s_release)(void);
+ int (*s_config)(void __user *);
+};
+
+struct msm_sync {
+ /* These two queues are accessed from a process context only. */
+ struct hlist_head frame; /* most-frequently accessed */
+ struct hlist_head stats;
+
+ /* The message queue is used by the control thread to send commands
+ * to the config thread, and also by the DSP to send messages to the
+ * config thread. Thus it is the only queue that is accessed from
+ * both interrupt and process context.
+ */
+ spinlock_t msg_event_q_lock;
+ struct list_head msg_event_q;
+ wait_queue_head_t msg_event_wait;
+
+ /* This queue contains preview frames. It is accessed by the DSP (in
+ * in interrupt context, and by the frame thread.
+ */
+ spinlock_t prev_frame_q_lock;
+ struct list_head prev_frame_q;
+ wait_queue_head_t prev_frame_wait;
+ int unblock_poll_frame;
+
+ /* This queue contains snapshot frames. It is accessed by the DSP (in
+ * interrupt context, and by the control thread.
+ */
+ spinlock_t pict_frame_q_lock;
+ struct list_head pict_frame_q;
+ wait_queue_head_t pict_frame_wait;
+
+ struct msm_camera_sensor_info *sdata;
+ struct msm_camvfe_fn vfefn;
+ struct msm_sensor_ctrl sctrl;
+ struct platform_device *pdev;
+ uint8_t opencnt;
+ void *cropinfo;
+ int croplen;
+ unsigned pict_pp;
+
+ const char *apps_id;
+
+ struct mutex lock;
+ struct list_head list;
+};
+
+#define MSM_APPS_ID_V4L2 "msm_v4l2"
+#define MSM_APPS_ID_PROP "msm_qct"
+
+struct msm_device {
+ struct msm_sync *sync; /* most-frequently accessed */
+ struct device *device;
+ struct cdev cdev;
+ /* opened is meaningful only for the config and frame nodes,
+ * which may be opened only once.
+ */
+ atomic_t opened;
+};
+
+struct msm_control_device_queue {
+ spinlock_t ctrl_status_q_lock;
+ struct list_head ctrl_status_q;
+ wait_queue_head_t ctrl_status_wait;
+};
+
+struct msm_control_device {
+ struct msm_device *pmsm;
+
+ /* This queue used by the config thread to send responses back to the
+ * control thread. It is accessed only from a process context.
+ */
+ struct msm_control_device_queue ctrl_q;
+};
+
+/* this structure is used in kernel */
+struct msm_queue_cmd {
+ struct list_head list;
+ enum msm_queue type;
+ void *command;
+};
+
+struct register_address_value_pair {
+ uint16_t register_address;
+ uint16_t register_value;
+};
+
+struct msm_pmem_region {
+ struct hlist_node list;
+ int type;
+ void *vaddr;
+ unsigned long paddr;
+ unsigned long len;
+ struct file *file;
+ uint32_t y_off;
+ uint32_t cbcr_off;
+ int fd;
+ uint8_t active;
+};
+
+struct axidata {
+ uint32_t bufnum1;
+ uint32_t bufnum2;
+ struct msm_pmem_region *region;
+};
+
+#ifdef CONFIG_MSM_CAMERA_FLASH
+int msm_camera_flash_set_led_state(unsigned led_state);
+#else
+static inline int msm_camera_flash_set_led_state(unsigned led_state)
+{
+ return -ENOTSUPP;
+}
+#endif
+
+/* Below functions are added for V4L2 kernel APIs */
+struct msm_v4l2_driver {
+ struct msm_sync *sync;
+ int (*open)(struct msm_sync *, const char *apps_id);
+ int (*release)(struct msm_sync *);
+ int (*ctrl)(struct msm_sync *, struct msm_ctrl_cmd *);
+ int (*reg_pmem)(struct msm_sync *, struct msm_pmem_info *);
+ int (*get_frame) (struct msm_sync *, struct msm_frame *);
+ int (*put_frame) (struct msm_sync *, struct msm_frame *);
+ int (*get_pict) (struct msm_sync *, struct msm_ctrl_cmd *);
+ unsigned int (*drv_poll) (struct msm_sync *, struct file *,
+ struct poll_table_struct *);
+};
+
+int msm_v4l2_register(struct msm_v4l2_driver *);
+int msm_v4l2_unregister(struct msm_v4l2_driver *);
+
+void msm_camvfe_init(void);
+int msm_camvfe_check(void *);
+void msm_camvfe_fn_init(struct msm_camvfe_fn *, void *);
+int msm_camera_drv_start(struct platform_device *dev,
+ int (*sensor_probe)(const struct msm_camera_sensor_info *,
+ struct msm_sensor_ctrl *));
+
+enum msm_camio_clk_type {
+ CAMIO_VFE_MDC_CLK,
+ CAMIO_MDC_CLK,
+ CAMIO_VFE_CLK,
+ CAMIO_VFE_AXI_CLK,
+
+ CAMIO_MAX_CLK
+};
+
+enum msm_camio_clk_src_type {
+ MSM_CAMIO_CLK_SRC_INTERNAL,
+ MSM_CAMIO_CLK_SRC_EXTERNAL,
+ MSM_CAMIO_CLK_SRC_MAX
+};
+
+enum msm_s_test_mode {
+ S_TEST_OFF,
+ S_TEST_1,
+ S_TEST_2,
+ S_TEST_3
+};
+
+enum msm_s_resolution {
+ S_QTR_SIZE,
+ S_FULL_SIZE,
+ S_INVALID_SIZE
+};
+
+enum msm_s_reg_update {
+ /* Sensor egisters that need to be updated during initialization */
+ S_REG_INIT,
+ /* Sensor egisters that needs periodic I2C writes */
+ S_UPDATE_PERIODIC,
+ /* All the sensor Registers will be updated */
+ S_UPDATE_ALL,
+ /* Not valid update */
+ S_UPDATE_INVALID
+};
+
+enum msm_s_setting {
+ S_RES_PREVIEW,
+ S_RES_CAPTURE
+};
+
+int msm_camio_enable(struct platform_device *dev);
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clk);
+int msm_camio_clk_disable(enum msm_camio_clk_type clk);
+int msm_camio_clk_config(uint32_t freq);
+void msm_camio_clk_rate_set(int rate);
+void msm_camio_clk_axi_rate_set(int rate);
+
+void msm_camio_camif_pad_reg_reset(void);
+void msm_camio_camif_pad_reg_reset_2(void);
+
+void msm_camio_vfe_blk_reset(void);
+
+void msm_camio_clk_sel(enum msm_camio_clk_src_type);
+void msm_camio_disable(struct platform_device *);
+int msm_camio_probe_on(struct platform_device *);
+int msm_camio_probe_off(struct platform_device *);
+#endif
diff --git a/drivers/staging/dream/include/mach/msm_adsp.h b/drivers/staging/dream/include/mach/msm_adsp.h
new file mode 100644
index 000000000000..a081683328a3
--- /dev/null
+++ b/drivers/staging/dream/include/mach/msm_adsp.h
@@ -0,0 +1,112 @@
+/* include/asm-arm/arch-msm/msm_adsp.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ASM__ARCH_MSM_ADSP_H
+#define __ASM__ARCH_MSM_ADSP_H
+
+struct msm_adsp_module;
+
+struct msm_adsp_ops {
+ /* event is called from interrupt context when a message
+ * arrives from the DSP. Use the provided function pointer
+ * to copy the message into a local buffer. Do NOT call
+ * it multiple times.
+ */
+ void (*event)(void *driver_data, unsigned id, size_t len,
+ void (*getevent)(void *ptr, size_t len));
+};
+
+/* Get, Put, Enable, and Disable are synchronous and must only
+ * be called from thread context. Enable and Disable will block
+ * up to one second in the event of a fatal DSP error but are
+ * much faster otherwise.
+ */
+int msm_adsp_get(const char *name, struct msm_adsp_module **module,
+ struct msm_adsp_ops *ops, void *driver_data);
+void msm_adsp_put(struct msm_adsp_module *module);
+int msm_adsp_enable(struct msm_adsp_module *module);
+int msm_adsp_disable(struct msm_adsp_module *module);
+int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate);
+
+/* Write is safe to call from interrupt context.
+ */
+int msm_adsp_write(struct msm_adsp_module *module,
+ unsigned queue_id,
+ void *data, size_t len);
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+/* Command Queue Indexes */
+#define QDSP_lpmCommandQueue 0
+#define QDSP_mpuAfeQueue 1
+#define QDSP_mpuGraphicsCmdQueue 2
+#define QDSP_mpuModmathCmdQueue 3
+#define QDSP_mpuVDecCmdQueue 4
+#define QDSP_mpuVDecPktQueue 5
+#define QDSP_mpuVEncCmdQueue 6
+#define QDSP_rxMpuDecCmdQueue 7
+#define QDSP_rxMpuDecPktQueue 8
+#define QDSP_txMpuEncQueue 9
+#define QDSP_uPAudPPCmd1Queue 10
+#define QDSP_uPAudPPCmd2Queue 11
+#define QDSP_uPAudPPCmd3Queue 12
+#define QDSP_uPAudPlay0BitStreamCtrlQueue 13
+#define QDSP_uPAudPlay1BitStreamCtrlQueue 14
+#define QDSP_uPAudPlay2BitStreamCtrlQueue 15
+#define QDSP_uPAudPlay3BitStreamCtrlQueue 16
+#define QDSP_uPAudPlay4BitStreamCtrlQueue 17
+#define QDSP_uPAudPreProcCmdQueue 18
+#define QDSP_uPAudRecBitStreamQueue 19
+#define QDSP_uPAudRecCmdQueue 20
+#define QDSP_uPDiagQueue 21
+#define QDSP_uPJpegActionCmdQueue 22
+#define QDSP_uPJpegCfgCmdQueue 23
+#define QDSP_uPVocProcQueue 24
+#define QDSP_vfeCommandQueue 25
+#define QDSP_vfeCommandScaleQueue 26
+#define QDSP_vfeCommandTableQueue 27
+#define QDSP_MAX_NUM_QUEUES 28
+#else
+/* Command Queue Indexes */
+#define QDSP_lpmCommandQueue 0
+#define QDSP_mpuAfeQueue 1
+#define QDSP_mpuGraphicsCmdQueue 2
+#define QDSP_mpuModmathCmdQueue 3
+#define QDSP_mpuVDecCmdQueue 4
+#define QDSP_mpuVDecPktQueue 5
+#define QDSP_mpuVEncCmdQueue 6
+#define QDSP_rxMpuDecCmdQueue 7
+#define QDSP_rxMpuDecPktQueue 8
+#define QDSP_txMpuEncQueue 9
+#define QDSP_uPAudPPCmd1Queue 10
+#define QDSP_uPAudPPCmd2Queue 11
+#define QDSP_uPAudPPCmd3Queue 12
+#define QDSP_uPAudPlay0BitStreamCtrlQueue 13
+#define QDSP_uPAudPlay1BitStreamCtrlQueue 14
+#define QDSP_uPAudPlay2BitStreamCtrlQueue 15
+#define QDSP_uPAudPlay3BitStreamCtrlQueue 16
+#define QDSP_uPAudPlay4BitStreamCtrlQueue 17
+#define QDSP_uPAudPreProcCmdQueue 18
+#define QDSP_uPAudRecBitStreamQueue 19
+#define QDSP_uPAudRecCmdQueue 20
+#define QDSP_uPJpegActionCmdQueue 21
+#define QDSP_uPJpegCfgCmdQueue 22
+#define QDSP_uPVocProcQueue 23
+#define QDSP_vfeCommandQueue 24
+#define QDSP_vfeCommandScaleQueue 25
+#define QDSP_vfeCommandTableQueue 26
+#define QDSP_QUEUE_MAX 26
+#endif
+
+#endif
diff --git a/drivers/staging/dream/include/mach/msm_rpcrouter.h b/drivers/staging/dream/include/mach/msm_rpcrouter.h
new file mode 100644
index 000000000000..9724ece1c97c
--- /dev/null
+++ b/drivers/staging/dream/include/mach/msm_rpcrouter.h
@@ -0,0 +1,179 @@
+/** include/asm-arm/arch-msm/msm_rpcrouter.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009 QUALCOMM Incorporated
+ * Author: San Mehat <san@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ASM__ARCH_MSM_RPCROUTER_H
+#define __ASM__ARCH_MSM_RPCROUTER_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+/* RPC API version structure
+ * Version bit 31 : 1->hashkey versioning,
+ * 0->major-minor (backward compatible) versioning
+ * hashkey versioning:
+ * Version bits 31-0 hashkey
+ * major-minor (backward compatible) versioning
+ * Version bits 30-28 reserved (no match)
+ * Version bits 27-16 major (must match)
+ * Version bits 15-0 minor (greater or equal)
+ */
+#define RPC_VERSION_MODE_MASK 0x80000000
+#define RPC_VERSION_MAJOR_MASK 0x0fff0000
+#define RPC_VERSION_MAJOR_OFFSET 16
+#define RPC_VERSION_MINOR_MASK 0x0000ffff
+
+#define MSM_RPC_VERS(major, minor) \
+ ((uint32_t)((((major) << RPC_VERSION_MAJOR_OFFSET) & \
+ RPC_VERSION_MAJOR_MASK) | \
+ ((minor) & RPC_VERSION_MINOR_MASK)))
+#define MSM_RPC_GET_MAJOR(vers) (((vers) & RPC_VERSION_MAJOR_MASK) >> \
+ RPC_VERSION_MAJOR_OFFSET)
+#define MSM_RPC_GET_MINOR(vers) ((vers) & RPC_VERSION_MINOR_MASK)
+#else
+#define MSM_RPC_VERS(major, minor) (major)
+#define MSM_RPC_GET_MAJOR(vers) (vers)
+#define MSM_RPC_GET_MINOR(vers) 0
+#endif
+
+struct msm_rpc_endpoint;
+
+struct rpcsvr_platform_device
+{
+ struct platform_device base;
+ uint32_t prog;
+ uint32_t vers;
+};
+
+#define RPC_DATA_IN 0
+/*
+ * Structures for sending / receiving direct RPC requests
+ * XXX: Any cred/verif lengths > 0 not supported
+ */
+
+struct rpc_request_hdr
+{
+ uint32_t xid;
+ uint32_t type; /* 0 */
+ uint32_t rpc_vers; /* 2 */
+ uint32_t prog;
+ uint32_t vers;
+ uint32_t procedure;
+ uint32_t cred_flavor;
+ uint32_t cred_length;
+ uint32_t verf_flavor;
+ uint32_t verf_length;
+};
+
+typedef struct
+{
+ uint32_t low;
+ uint32_t high;
+} rpc_reply_progmismatch_data;
+
+typedef struct
+{
+} rpc_denied_reply_hdr;
+
+typedef struct
+{
+ uint32_t verf_flavor;
+ uint32_t verf_length;
+ uint32_t accept_stat;
+#define RPC_ACCEPTSTAT_SUCCESS 0
+#define RPC_ACCEPTSTAT_PROG_UNAVAIL 1
+#define RPC_ACCEPTSTAT_PROG_MISMATCH 2
+#define RPC_ACCEPTSTAT_PROC_UNAVAIL 3
+#define RPC_ACCEPTSTAT_GARBAGE_ARGS 4
+#define RPC_ACCEPTSTAT_SYSTEM_ERR 5
+#define RPC_ACCEPTSTAT_PROG_LOCKED 6
+ /*
+ * Following data is dependant on accept_stat
+ * If ACCEPTSTAT == PROG_MISMATCH then there is a
+ * 'rpc_reply_progmismatch_data' structure following the header.
+ * Otherwise the data is procedure specific
+ */
+} rpc_accepted_reply_hdr;
+
+struct rpc_reply_hdr
+{
+ uint32_t xid;
+ uint32_t type;
+ uint32_t reply_stat;
+#define RPCMSG_REPLYSTAT_ACCEPTED 0
+#define RPCMSG_REPLYSTAT_DENIED 1
+ union {
+ rpc_accepted_reply_hdr acc_hdr;
+ rpc_denied_reply_hdr dny_hdr;
+ } data;
+};
+
+/* flags for msm_rpc_connect() */
+#define MSM_RPC_UNINTERRUPTIBLE 0x0001
+
+/* use IS_ERR() to check for failure */
+struct msm_rpc_endpoint *msm_rpc_open(void);
+/* Connect with the specified server version */
+struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags);
+uint32_t msm_rpc_get_vers(struct msm_rpc_endpoint *ept);
+/* check if server version can handle client requested version */
+int msm_rpc_is_compatible_version(uint32_t server_version,
+ uint32_t client_version);
+
+int msm_rpc_close(struct msm_rpc_endpoint *ept);
+int msm_rpc_write(struct msm_rpc_endpoint *ept,
+ void *data, int len);
+int msm_rpc_read(struct msm_rpc_endpoint *ept,
+ void **data, unsigned len, long timeout);
+void msm_rpc_setup_req(struct rpc_request_hdr *hdr,
+ uint32_t prog, uint32_t vers, uint32_t proc);
+int msm_rpc_register_server(struct msm_rpc_endpoint *ept,
+ uint32_t prog, uint32_t vers);
+int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept,
+ uint32_t prog, uint32_t vers);
+
+/* simple blocking rpc call
+ *
+ * request is mandatory and must have a rpc_request_hdr
+ * at the start. The header will be filled out for you.
+ *
+ * reply provides a buffer for replies of reply_max_size
+ */
+int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc,
+ void *request, int request_size,
+ void *reply, int reply_max_size,
+ long timeout);
+int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc,
+ void *request, int request_size,
+ long timeout);
+
+struct msm_rpc_server
+{
+ struct list_head list;
+ uint32_t flags;
+
+ uint32_t prog;
+ uint32_t vers;
+
+ int (*rpc_call)(struct msm_rpc_server *server,
+ struct rpc_request_hdr *req, unsigned len);
+};
+
+int msm_rpc_create_server(struct msm_rpc_server *server);
+
+#endif
diff --git a/drivers/staging/dream/include/mach/msm_smd.h b/drivers/staging/dream/include/mach/msm_smd.h
new file mode 100644
index 000000000000..bdf7731ab680
--- /dev/null
+++ b/drivers/staging/dream/include/mach/msm_smd.h
@@ -0,0 +1,107 @@
+/* linux/include/asm-arm/arch-msm/msm_smd.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_SMD_H
+#define __ASM_ARCH_MSM_SMD_H
+
+typedef struct smd_channel smd_channel_t;
+
+/* warning: notify() may be called before open returns */
+int smd_open(const char *name, smd_channel_t **ch, void *priv,
+ void (*notify)(void *priv, unsigned event));
+
+#define SMD_EVENT_DATA 1
+#define SMD_EVENT_OPEN 2
+#define SMD_EVENT_CLOSE 3
+
+int smd_close(smd_channel_t *ch);
+
+/* passing a null pointer for data reads and discards */
+int smd_read(smd_channel_t *ch, void *data, int len);
+
+/* Write to stream channels may do a partial write and return
+** the length actually written.
+** Write to packet channels will never do a partial write --
+** it will return the requested length written or an error.
+*/
+int smd_write(smd_channel_t *ch, const void *data, int len);
+
+int smd_write_avail(smd_channel_t *ch);
+int smd_read_avail(smd_channel_t *ch);
+
+/* Returns the total size of the current packet being read.
+** Returns 0 if no packets available or a stream channel.
+*/
+int smd_cur_packet_size(smd_channel_t *ch);
+
+/* used for tty unthrottling and the like -- causes the notify()
+** callback to be called from the same lock context as is used
+** when it is called from channel updates
+*/
+void smd_kick(smd_channel_t *ch);
+
+
+#if 0
+/* these are interruptable waits which will block you until the specified
+** number of bytes are readable or writable.
+*/
+int smd_wait_until_readable(smd_channel_t *ch, int bytes);
+int smd_wait_until_writable(smd_channel_t *ch, int bytes);
+#endif
+
+typedef enum
+{
+ SMD_PORT_DS = 0,
+ SMD_PORT_DIAG,
+ SMD_PORT_RPC_CALL,
+ SMD_PORT_RPC_REPLY,
+ SMD_PORT_BT,
+ SMD_PORT_CONTROL,
+ SMD_PORT_MEMCPY_SPARE1,
+ SMD_PORT_DATA1,
+ SMD_PORT_DATA2,
+ SMD_PORT_DATA3,
+ SMD_PORT_DATA4,
+ SMD_PORT_DATA5,
+ SMD_PORT_DATA6,
+ SMD_PORT_DATA7,
+ SMD_PORT_DATA8,
+ SMD_PORT_DATA9,
+ SMD_PORT_DATA10,
+ SMD_PORT_DATA11,
+ SMD_PORT_DATA12,
+ SMD_PORT_DATA13,
+ SMD_PORT_DATA14,
+ SMD_PORT_DATA15,
+ SMD_PORT_DATA16,
+ SMD_PORT_DATA17,
+ SMD_PORT_DATA18,
+ SMD_PORT_DATA19,
+ SMD_PORT_DATA20,
+ SMD_PORT_GPS_NMEA,
+ SMD_PORT_BRIDGE_1,
+ SMD_PORT_BRIDGE_2,
+ SMD_PORT_BRIDGE_3,
+ SMD_PORT_BRIDGE_4,
+ SMD_PORT_BRIDGE_5,
+ SMD_PORT_LOOPBACK,
+ SMD_PORT_CS_APPS_MODEM,
+ SMD_PORT_CS_APPS_DSP,
+ SMD_PORT_CS_MODEM_DSP,
+ SMD_NUM_PORTS,
+} smd_port_id_type;
+
+#endif
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audplaycmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audplaycmdi.h
new file mode 100644
index 000000000000..0b6a31259bb0
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5audplaycmdi.h
@@ -0,0 +1,94 @@
+#ifndef QDSP5AUDPLAYCMDI_H
+#define QDSP5AUDPLAYCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ Q D S P 5 A U D I O P L A Y T A S K C O M M A N D S
+
+GENERAL DESCRIPTION
+ Command Interface for AUDPLAYTASK on QDSP5
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+
+ audplay_cmd_dec_data_avail
+ Send buffer to AUDPLAY task
+
+
+Copyright(c) 1992 - 2009 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audplaycmdi.h#2 $
+
+===========================================================================*/
+
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL 0x0000
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_LEN \
+ sizeof(audplay_cmd_bitstream_data_avail)
+
+/* Type specification of dec_data_avail message sent to AUDPLAYTASK
+*/
+typedef struct {
+ /*command ID*/
+ unsigned int cmd_id;
+
+ /* Decoder ID for which message is being sent */
+ unsigned int decoder_id;
+
+ /* Start address of data in ARM global memory */
+ unsigned int buf_ptr;
+
+ /* Number of 16-bit words of bit-stream data contiguously available at the
+ * above-mentioned address. */
+ unsigned int buf_size;
+
+ /* Partition number used by audPlayTask to communicate with DSP's RTOS
+ * kernel */
+ unsigned int partition_number;
+} __attribute__((packed)) audplay_cmd_bitstream_data_avail;
+
+#define AUDPLAY_CMD_HPCM_BUF_CFG 0x0003
+#define AUDPLAY_CMD_HPCM_BUF_CFG_LEN \
+ sizeof(struct audplay_cmd_hpcm_buf_cfg)
+
+struct audplay_cmd_hpcm_buf_cfg {
+ unsigned int cmd_id;
+ unsigned int hostpcm_config;
+ unsigned int feedback_frequency;
+ unsigned int byte_swap;
+ unsigned int max_buffers;
+ unsigned int partition_number;
+} __attribute__((packed));
+
+#define AUDPLAY_CMD_BUFFER_REFRESH 0x0004
+#define AUDPLAY_CMD_BUFFER_REFRESH_LEN \
+ sizeof(struct audplay_cmd_buffer_update)
+
+struct audplay_cmd_buffer_refresh {
+ unsigned int cmd_id;
+ unsigned int num_buffers;
+ unsigned int buf_read_count;
+ unsigned int buf0_address;
+ unsigned int buf0_length;
+ unsigned int buf1_address;
+ unsigned int buf1_length;
+} __attribute__((packed));
+#endif /* QDSP5AUDPLAYCMD_H */
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audplaymsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audplaymsg.h
new file mode 100644
index 000000000000..c63034b8bf13
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5audplaymsg.h
@@ -0,0 +1,70 @@
+#ifndef QDSP5AUDPLAYMSG_H
+#define QDSP5AUDPLAYMSG_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ Q D S P 5 A U D I O P L A Y T A S K M S G
+
+GENERAL DESCRIPTION
+ Message sent by AUDPLAY task
+
+REFERENCES
+ None
+
+
+Copyright(c) 1992 - 2009 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audplaymsg.h#3 $
+
+===========================================================================*/
+#define AUDPLAY_MSG_DEC_NEEDS_DATA 0x0001
+#define AUDPLAY_MSG_DEC_NEEDS_DATA_MSG_LEN \
+ sizeof(audplay_msg_dec_needs_data)
+
+typedef struct{
+ /* reserved*/
+ unsigned int dec_id;
+
+ /* The read pointer offset of external memory until which the
+ * bitstream has been DMAed in. */
+ unsigned int adecDataReadPtrOffset;
+
+ /* The buffer size of external memory. */
+ unsigned int adecDataBufSize;
+
+ unsigned int bitstream_free_len;
+ unsigned int bitstream_write_ptr;
+ unsigned int bitstarem_buf_start;
+ unsigned int bitstream_buf_len;
+} __attribute__((packed)) audplay_msg_dec_needs_data;
+
+#define AUDPLAY_MSG_BUFFER_UPDATE 0x0004
+#define AUDPLAY_MSG_BUFFER_UPDATE_LEN \
+ sizeof(struct audplay_msg_buffer_update)
+
+struct audplay_msg_buffer_update {
+ unsigned int buffer_write_count;
+ unsigned int num_of_buffer;
+ unsigned int buf0_address;
+ unsigned int buf0_length;
+ unsigned int buf1_address;
+ unsigned int buf1_length;
+} __attribute__((packed));
+#endif /* QDSP5AUDPLAYMSG_H */
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audppcmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audppcmdi.h
new file mode 100644
index 000000000000..8bee9c62980b
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5audppcmdi.h
@@ -0,0 +1,914 @@
+#ifndef QDSP5AUDPPCMDI_H
+#define QDSP5AUDPPCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ A U D I O P O S T P R O C E S S I N G I N T E R N A L C O M M A N D S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of commands
+ that are accepted by AUDPP Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audppcmdi.h#2 $
+
+===========================================================================*/
+
+/*
+ * ARM to AUDPPTASK Commands
+ *
+ * ARM uses three command queues to communicate with AUDPPTASK
+ * 1)uPAudPPCmd1Queue : Used for more frequent and shorter length commands
+ * Location : MEMA
+ * Buffer Size : 6 words
+ * No of buffers in a queue : 20 for gaming audio and 5 for other images
+ * 2)uPAudPPCmd2Queue : Used for commands which are not much lengthier
+ * Location : MEMA
+ * Buffer Size : 23
+ * No of buffers in a queue : 2
+ * 3)uPAudOOCmd3Queue : Used for lengthier and more frequent commands
+ * Location : MEMA
+ * Buffer Size : 145
+ * No of buffers in a queue : 3
+ */
+
+/*
+ * Commands Related to uPAudPPCmd1Queue
+ */
+
+/*
+ * Command Structure to enable or disable the active decoders
+ */
+
+#define AUDPP_CMD_CFG_DEC_TYPE 0x0001
+#define AUDPP_CMD_CFG_DEC_TYPE_LEN sizeof(audpp_cmd_cfg_dec_type)
+
+/* Enable the decoder */
+#define AUDPP_CMD_DEC_TYPE_M 0x000F
+
+#define AUDPP_CMD_ENA_DEC_V 0x4000
+#define AUDPP_CMD_DIS_DEC_V 0x0000
+#define AUDPP_CMD_DEC_STATE_M 0x4000
+
+#define AUDPP_CMD_UPDATDE_CFG_DEC 0x8000
+#define AUDPP_CMD_DONT_UPDATE_CFG_DEC 0x0000
+
+
+/* Type specification of cmd_cfg_dec */
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short dec0_cfg;
+ unsigned short dec1_cfg;
+ unsigned short dec2_cfg;
+ unsigned short dec3_cfg;
+ unsigned short dec4_cfg;
+} __attribute__((packed)) audpp_cmd_cfg_dec_type;
+
+/*
+ * Command Structure to Pause , Resume and flushes the selected audio decoders
+ */
+
+#define AUDPP_CMD_DEC_CTRL 0x0002
+#define AUDPP_CMD_DEC_CTRL_LEN sizeof(audpp_cmd_dec_ctrl)
+
+/* Decoder control commands for pause, resume and flush */
+#define AUDPP_CMD_FLUSH_V 0x2000
+
+#define AUDPP_CMD_PAUSE_V 0x4000
+#define AUDPP_CMD_RESUME_V 0x0000
+
+#define AUDPP_CMD_UPDATE_V 0x8000
+#define AUDPP_CMD_IGNORE_V 0x0000
+
+
+/* Type Spec for decoder control command*/
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short dec0_ctrl;
+ unsigned short dec1_ctrl;
+ unsigned short dec2_ctrl;
+ unsigned short dec3_ctrl;
+ unsigned short dec4_ctrl;
+} __attribute__((packed)) audpp_cmd_dec_ctrl;
+
+/*
+ * Command Structure to Configure the AVSync FeedBack Mechanism
+ */
+
+#define AUDPP_CMD_AVSYNC 0x0003
+#define AUDPP_CMD_AVSYNC_LEN sizeof(audpp_cmd_avsync)
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short object_number;
+ unsigned short interrupt_interval_lsw;
+ unsigned short interrupt_interval_msw;
+} __attribute__((packed)) audpp_cmd_avsync;
+
+/*
+ * Command Structure to enable or disable(sleep) the AUDPPTASK
+ */
+
+#define AUDPP_CMD_CFG 0x0004
+#define AUDPP_CMD_CFG_LEN sizeof(audpp_cmd_cfg)
+
+#define AUDPP_CMD_CFG_SLEEP 0x0000
+#define AUDPP_CMD_CFG_ENABLE 0xFFFF
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short cfg;
+} __attribute__((packed)) audpp_cmd_cfg;
+
+/*
+ * Command Structure to Inject or drop the specified no of samples
+ */
+
+#define AUDPP_CMD_ADJUST_SAMP 0x0005
+#define AUDPP_CMD_ADJUST_SAMP_LEN sizeof(audpp_cmd_adjust_samp)
+
+#define AUDPP_CMD_SAMP_DROP -1
+#define AUDPP_CMD_SAMP_INSERT 0x0001
+
+#define AUDPP_CMD_NUM_SAMPLES 0x0001
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short object_no;
+ signed short sample_insert_or_drop;
+ unsigned short num_samples;
+} __attribute__((packed)) audpp_cmd_adjust_samp;
+
+/*
+ * Command Structure to Configure AVSync Feedback Mechanism
+ */
+
+#define AUDPP_CMD_AVSYNC_CMD_2 0x0006
+#define AUDPP_CMD_AVSYNC_CMD_2_LEN sizeof(audpp_cmd_avsync_cmd_2)
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short object_number;
+ unsigned short interrupt_interval_lsw;
+ unsigned short interrupt_interval_msw;
+ unsigned short sample_counter_dlsw;
+ unsigned short sample_counter_dmsw;
+ unsigned short sample_counter_msw;
+ unsigned short byte_counter_dlsw;
+ unsigned short byte_counter_dmsw;
+ unsigned short byte_counter_msw;
+} __attribute__((packed)) audpp_cmd_avsync_cmd_2;
+
+/*
+ * Command Structure to Configure AVSync Feedback Mechanism
+ */
+
+#define AUDPP_CMD_AVSYNC_CMD_3 0x0007
+#define AUDPP_CMD_AVSYNC_CMD_3_LEN sizeof(audpp_cmd_avsync_cmd_3)
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short object_number;
+ unsigned short interrupt_interval_lsw;
+ unsigned short interrupt_interval_msw;
+ unsigned short sample_counter_dlsw;
+ unsigned short sample_counter_dmsw;
+ unsigned short sample_counter_msw;
+ unsigned short byte_counter_dlsw;
+ unsigned short byte_counter_dmsw;
+ unsigned short byte_counter_msw;
+} __attribute__((packed)) audpp_cmd_avsync_cmd_3;
+
+#define AUDPP_CMD_ROUTING_MODE 0x0008
+#define AUDPP_CMD_ROUTING_MODE_LEN \
+sizeof(struct audpp_cmd_routing_mode)
+
+struct audpp_cmd_routing_mode {
+ unsigned short cmd_id;
+ unsigned short object_number;
+ unsigned short routing_mode;
+} __attribute__((packed));
+
+/*
+ * Commands Related to uPAudPPCmd2Queue
+ */
+
+/*
+ * Command Structure to configure Per decoder Parameters (Common)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS 0x0000
+#define AUDPP_CMD_CFG_ADEC_PARAMS_COMMON_LEN \
+ sizeof(audpp_cmd_cfg_adec_params_common)
+
+#define AUDPP_CMD_STATUS_MSG_FLAG_ENA_FCM 0x4000
+#define AUDPP_CMD_STATUS_MSG_FLAG_DIS_FCM 0x0000
+
+#define AUDPP_CMD_STATUS_MSG_FLAG_ENA_DCM 0x8000
+#define AUDPP_CMD_STATUS_MSG_FLAG_DIS_DCM 0x0000
+
+/* Sampling frequency*/
+#define AUDPP_CMD_SAMP_RATE_96000 0x0000
+#define AUDPP_CMD_SAMP_RATE_88200 0x0001
+#define AUDPP_CMD_SAMP_RATE_64000 0x0002
+#define AUDPP_CMD_SAMP_RATE_48000 0x0003
+#define AUDPP_CMD_SAMP_RATE_44100 0x0004
+#define AUDPP_CMD_SAMP_RATE_32000 0x0005
+#define AUDPP_CMD_SAMP_RATE_24000 0x0006
+#define AUDPP_CMD_SAMP_RATE_22050 0x0007
+#define AUDPP_CMD_SAMP_RATE_16000 0x0008
+#define AUDPP_CMD_SAMP_RATE_12000 0x0009
+#define AUDPP_CMD_SAMP_RATE_11025 0x000A
+#define AUDPP_CMD_SAMP_RATE_8000 0x000B
+
+
+/*
+ * Type specification of cmd_adec_cfg sent to all decoder
+ */
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short length;
+ unsigned short dec_id;
+ unsigned short status_msg_flag;
+ unsigned short decoder_frame_counter_msg_period;
+ unsigned short input_sampling_frequency;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_common;
+
+/*
+ * Command Structure to configure Per decoder Parameters (Wav)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_WAV_LEN \
+ sizeof(audpp_cmd_cfg_adec_params_wav)
+
+
+#define AUDPP_CMD_WAV_STEREO_CFG_MONO 0x0001
+#define AUDPP_CMD_WAV_STEREO_CFG_STEREO 0x0002
+
+#define AUDPP_CMD_WAV_PCM_WIDTH_8 0x0000
+#define AUDPP_CMD_WAV_PCM_WIDTH_16 0x0001
+#define AUDPP_CMD_WAV_PCM_WIDTH_32 0x0002
+
+typedef struct {
+ audpp_cmd_cfg_adec_params_common common;
+ unsigned short stereo_cfg;
+ unsigned short pcm_width;
+ unsigned short sign;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_wav;
+
+/*
+ * Command Structure to configure Per decoder Parameters (ADPCM)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_ADPCM_LEN \
+ sizeof(audpp_cmd_cfg_adec_params_adpcm)
+
+
+#define AUDPP_CMD_ADPCM_STEREO_CFG_MONO 0x0001
+#define AUDPP_CMD_ADPCM_STEREO_CFG_STEREO 0x0002
+
+typedef struct {
+ audpp_cmd_cfg_adec_params_common common;
+ unsigned short stereo_cfg;
+ unsigned short block_size;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_adpcm;
+
+/*
+ * Command Structure to configure Per decoder Parameters (MP3)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_MP3_LEN \
+ sizeof(audpp_cmd_cfg_adec_params_mp3)
+
+typedef struct {
+ audpp_cmd_cfg_adec_params_common common;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_mp3;
+
+
+/*
+ * Command Structure to configure Per decoder Parameters (AAC)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_AAC_LEN \
+ sizeof(audpp_cmd_cfg_adec_params_aac)
+
+
+#define AUDPP_CMD_AAC_FORMAT_ADTS -1
+#define AUDPP_CMD_AAC_FORMAT_RAW 0x0000
+#define AUDPP_CMD_AAC_FORMAT_PSUEDO_RAW 0x0001
+#define AUDPP_CMD_AAC_FORMAT_LOAS 0x0002
+
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_LC 0x0002
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_LTP 0x0004
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_ERLC 0x0011
+
+#define AUDPP_CMD_AAC_SBR_ON_FLAG_ON 0x0001
+#define AUDPP_CMD_AAC_SBR_ON_FLAG_OFF 0x0000
+
+#define AUDPP_CMD_AAC_SBR_PS_ON_FLAG_ON 0x0001
+#define AUDPP_CMD_AAC_SBR_PS_ON_FLAG_OFF 0x0000
+
+typedef struct {
+ audpp_cmd_cfg_adec_params_common common;
+ signed short format;
+ unsigned short audio_object;
+ unsigned short ep_config;
+ unsigned short aac_section_data_resilience_flag;
+ unsigned short aac_scalefactor_data_resilience_flag;
+ unsigned short aac_spectral_data_resilience_flag;
+ unsigned short sbr_on_flag;
+ unsigned short sbr_ps_on_flag;
+ unsigned short dual_mono_mode;
+ unsigned short channel_configuration;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_aac;
+
+/*
+ * Command Structure to configure Per decoder Parameters (V13K)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN \
+ sizeof(struct audpp_cmd_cfg_adec_params_v13k)
+
+
+#define AUDPP_CMD_STEREO_CFG_MONO 0x0001
+#define AUDPP_CMD_STEREO_CFG_STEREO 0x0002
+
+struct audpp_cmd_cfg_adec_params_v13k {
+ audpp_cmd_cfg_adec_params_common common;
+ unsigned short stereo_cfg;
+} __attribute__((packed));
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_EVRC_LEN \
+ sizeof(struct audpp_cmd_cfg_adec_params_evrc)
+
+struct audpp_cmd_cfg_adec_params_evrc {
+ audpp_cmd_cfg_adec_params_common common;
+ unsigned short stereo_cfg;
+} __attribute__ ((packed));
+
+/*
+ * Command Structure to configure the HOST PCM interface
+ */
+
+#define AUDPP_CMD_PCM_INTF 0x0001
+#define AUDPP_CMD_PCM_INTF_2 0x0002
+#define AUDPP_CMD_PCM_INTF_LEN sizeof(audpp_cmd_pcm_intf)
+
+#define AUDPP_CMD_PCM_INTF_MONO_V 0x0001
+#define AUDPP_CMD_PCM_INTF_STEREO_V 0x0002
+
+/* These two values differentiate the two types of commands that could be issued
+ * Interface configuration command and Buffer update command */
+
+#define AUDPP_CMD_PCM_INTF_CONFIG_CMD_V 0x0000
+#define AUDPP_CMD_PCM_INTF_BUFFER_CMD_V -1
+
+#define AUDPP_CMD_PCM_INTF_RX_ENA_M 0x000F
+#define AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V 0x0008
+#define AUDPP_CMD_PCM_INTF_RX_ENA_DSPTOARM_V 0x0004
+
+/* These flags control the enabling and disabling of the interface together
+ * with host interface bit mask. */
+
+#define AUDPP_CMD_PCM_INTF_ENA_V -1
+#define AUDPP_CMD_PCM_INTF_DIS_V 0x0000
+
+
+#define AUDPP_CMD_PCM_INTF_FULL_DUPLEX 0x0
+#define AUDPP_CMD_PCM_INTF_HALF_DUPLEX_TODSP 0x1
+
+
+#define AUDPP_CMD_PCM_INTF_OBJECT_NUM 0x5
+#define AUDPP_CMD_PCM_INTF_COMMON_OBJECT_NUM 0x6
+
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short object_num;
+ signed short config;
+ unsigned short intf_type;
+
+ /* DSP -> ARM Configuration */
+ unsigned short read_buf1LSW;
+ unsigned short read_buf1MSW;
+ unsigned short read_buf1_len;
+
+ unsigned short read_buf2LSW;
+ unsigned short read_buf2MSW;
+ unsigned short read_buf2_len;
+ /* 0:HOST_PCM_INTF disable
+ ** 0xFFFF: HOST_PCM_INTF enable
+ */
+ signed short dsp_to_arm_flag;
+ unsigned short partition_number;
+
+ /* ARM -> DSP Configuration */
+ unsigned short write_buf1LSW;
+ unsigned short write_buf1MSW;
+ unsigned short write_buf1_len;
+
+ unsigned short write_buf2LSW;
+ unsigned short write_buf2MSW;
+ unsigned short write_buf2_len;
+
+ /* 0:HOST_PCM_INTF disable
+ ** 0xFFFF: HOST_PCM_INTF enable
+ */
+ signed short arm_to_rx_flag;
+ unsigned short weight_decoder_to_rx;
+ unsigned short weight_arm_to_rx;
+
+ unsigned short partition_number_arm_to_dsp;
+ unsigned short sample_rate;
+ unsigned short channel_mode;
+} __attribute__((packed)) audpp_cmd_pcm_intf;
+
+/*
+ ** BUFFER UPDATE COMMAND
+ */
+#define AUDPP_CMD_PCM_INTF_SEND_BUF_PARAMS_LEN \
+ sizeof(audpp_cmd_pcm_intf_send_buffer)
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short host_pcm_object;
+ /* set config = 0xFFFF for configuration*/
+ signed short config;
+ unsigned short intf_type;
+ unsigned short dsp_to_arm_buf_id;
+ unsigned short arm_to_dsp_buf_id;
+ unsigned short arm_to_dsp_buf_len;
+} __attribute__((packed)) audpp_cmd_pcm_intf_send_buffer;
+
+
+/*
+ * Commands Related to uPAudPPCmd3Queue
+ */
+
+/*
+ * Command Structure to configure post processing params (Commmon)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS 0x0000
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN \
+ sizeof(audpp_cmd_cfg_object_params_common)
+
+#define AUDPP_CMD_OBJ0_UPDATE 0x8000
+#define AUDPP_CMD_OBJ0_DONT_UPDATE 0x0000
+
+#define AUDPP_CMD_OBJ1_UPDATE 0x8000
+#define AUDPP_CMD_OBJ1_DONT_UPDATE 0x0000
+
+#define AUDPP_CMD_OBJ2_UPDATE 0x8000
+#define AUDPP_CMD_OBJ2_DONT_UPDATE 0x0000
+
+#define AUDPP_CMD_OBJ3_UPDATE 0x8000
+#define AUDPP_CMD_OBJ3_DONT_UPDATE 0x0000
+
+#define AUDPP_CMD_OBJ4_UPDATE 0x8000
+#define AUDPP_CMD_OBJ4_DONT_UPDATE 0x0000
+
+#define AUDPP_CMD_HPCM_UPDATE 0x8000
+#define AUDPP_CMD_HPCM_DONT_UPDATE 0x0000
+
+#define AUDPP_CMD_COMMON_CFG_UPDATE 0x8000
+#define AUDPP_CMD_COMMON_CFG_DONT_UPDATE 0x0000
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short obj0_cfg;
+ unsigned short obj1_cfg;
+ unsigned short obj2_cfg;
+ unsigned short obj3_cfg;
+ unsigned short obj4_cfg;
+ unsigned short host_pcm_obj_cfg;
+ unsigned short comman_cfg;
+ unsigned short command_type;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_common;
+
+/*
+ * Command Structure to configure post processing params (Volume)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_VOLUME_LEN \
+ sizeof(audpp_cmd_cfg_object_params_volume)
+
+typedef struct {
+ audpp_cmd_cfg_object_params_common common;
+ unsigned short volume;
+ unsigned short pan;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_volume;
+
+/*
+ * Command Structure to configure post processing params (PCM Filter) --DOUBT
+ */
+
+typedef struct {
+ unsigned short numerator_b0_filter_lsw;
+ unsigned short numerator_b0_filter_msw;
+ unsigned short numerator_b1_filter_lsw;
+ unsigned short numerator_b1_filter_msw;
+ unsigned short numerator_b2_filter_lsw;
+ unsigned short numerator_b2_filter_msw;
+} __attribute__((packed)) numerator;
+
+typedef struct {
+ unsigned short denominator_a0_filter_lsw;
+ unsigned short denominator_a0_filter_msw;
+ unsigned short denominator_a1_filter_lsw;
+ unsigned short denominator_a1_filter_msw;
+} __attribute__((packed)) denominator;
+
+typedef struct {
+ unsigned short shift_factor_0;
+} __attribute__((packed)) shift_factor;
+
+typedef struct {
+ unsigned short pan_filter_0;
+} __attribute__((packed)) pan;
+
+typedef struct {
+ numerator numerator_filter;
+ denominator denominator_filter;
+ shift_factor shift_factor_filter;
+ pan pan_filter;
+} __attribute__((packed)) filter_1;
+
+typedef struct {
+ numerator numerator_filter[2];
+ denominator denominator_filter[2];
+ shift_factor shift_factor_filter[2];
+ pan pan_filter[2];
+} __attribute__((packed)) filter_2;
+
+typedef struct {
+ numerator numerator_filter[3];
+ denominator denominator_filter[3];
+ shift_factor shift_factor_filter[3];
+ pan pan_filter[3];
+} __attribute__((packed)) filter_3;
+
+typedef struct {
+ numerator numerator_filter[4];
+ denominator denominator_filter[4];
+ shift_factor shift_factor_filter[4];
+ pan pan_filter[4];
+} __attribute__((packed)) filter_4;
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_PCM_LEN \
+ sizeof(audpp_cmd_cfg_object_params_pcm)
+
+
+typedef struct {
+ audpp_cmd_cfg_object_params_common common;
+ unsigned short active_flag;
+ unsigned short num_bands;
+ union {
+ filter_1 filter_1_params;
+ filter_2 filter_2_params;
+ filter_3 filter_3_params;
+ filter_4 filter_4_params;
+ } __attribute__((packed)) params_filter;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_pcm;
+
+
+/*
+ * Command Structure to configure post processing parameters (equalizer)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_EQALIZER_LEN \
+ sizeof(audpp_cmd_cfg_object_params_eqalizer)
+
+typedef struct {
+ unsigned short numerator_coeff_0_lsw;
+ unsigned short numerator_coeff_0_msw;
+ unsigned short numerator_coeff_1_lsw;
+ unsigned short numerator_coeff_1_msw;
+ unsigned short numerator_coeff_2_lsw;
+ unsigned short numerator_coeff_2_msw;
+} __attribute__((packed)) eq_numerator;
+
+typedef struct {
+ unsigned short denominator_coeff_0_lsw;
+ unsigned short denominator_coeff_0_msw;
+ unsigned short denominator_coeff_1_lsw;
+ unsigned short denominator_coeff_1_msw;
+} __attribute__((packed)) eq_denominator;
+
+typedef struct {
+ unsigned short shift_factor;
+} __attribute__((packed)) eq_shiftfactor;
+
+typedef struct {
+ eq_numerator numerator;
+ eq_denominator denominator;
+ eq_shiftfactor shiftfactor;
+} __attribute__((packed)) eq_coeff_1;
+
+typedef struct {
+ eq_numerator numerator[2];
+ eq_denominator denominator[2];
+ eq_shiftfactor shiftfactor[2];
+} __attribute__((packed)) eq_coeff_2;
+
+typedef struct {
+ eq_numerator numerator[3];
+ eq_denominator denominator[3];
+ eq_shiftfactor shiftfactor[3];
+} __attribute__((packed)) eq_coeff_3;
+
+typedef struct {
+ eq_numerator numerator[4];
+ eq_denominator denominator[4];
+ eq_shiftfactor shiftfactor[4];
+} __attribute__((packed)) eq_coeff_4;
+
+typedef struct {
+ eq_numerator numerator[5];
+ eq_denominator denominator[5];
+ eq_shiftfactor shiftfactor[5];
+} __attribute__((packed)) eq_coeff_5;
+
+typedef struct {
+ eq_numerator numerator[6];
+ eq_denominator denominator[6];
+ eq_shiftfactor shiftfactor[6];
+} __attribute__((packed)) eq_coeff_6;
+
+typedef struct {
+ eq_numerator numerator[7];
+ eq_denominator denominator[7];
+ eq_shiftfactor shiftfactor[7];
+} __attribute__((packed)) eq_coeff_7;
+
+typedef struct {
+ eq_numerator numerator[8];
+ eq_denominator denominator[8];
+ eq_shiftfactor shiftfactor[8];
+} __attribute__((packed)) eq_coeff_8;
+
+typedef struct {
+ eq_numerator numerator[9];
+ eq_denominator denominator[9];
+ eq_shiftfactor shiftfactor[9];
+} __attribute__((packed)) eq_coeff_9;
+
+typedef struct {
+ eq_numerator numerator[10];
+ eq_denominator denominator[10];
+ eq_shiftfactor shiftfactor[10];
+} __attribute__((packed)) eq_coeff_10;
+
+typedef struct {
+ eq_numerator numerator[11];
+ eq_denominator denominator[11];
+ eq_shiftfactor shiftfactor[11];
+} __attribute__((packed)) eq_coeff_11;
+
+typedef struct {
+ eq_numerator numerator[12];
+ eq_denominator denominator[12];
+ eq_shiftfactor shiftfactor[12];
+} __attribute__((packed)) eq_coeff_12;
+
+
+typedef struct {
+ audpp_cmd_cfg_object_params_common common;
+ unsigned short eq_flag;
+ unsigned short num_bands;
+ union {
+ eq_coeff_1 eq_coeffs_1;
+ eq_coeff_2 eq_coeffs_2;
+ eq_coeff_3 eq_coeffs_3;
+ eq_coeff_4 eq_coeffs_4;
+ eq_coeff_5 eq_coeffs_5;
+ eq_coeff_6 eq_coeffs_6;
+ eq_coeff_7 eq_coeffs_7;
+ eq_coeff_8 eq_coeffs_8;
+ eq_coeff_9 eq_coeffs_9;
+ eq_coeff_10 eq_coeffs_10;
+ eq_coeff_11 eq_coeffs_11;
+ eq_coeff_12 eq_coeffs_12;
+ } __attribute__((packed)) eq_coeff;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_eqalizer;
+
+
+/*
+ * Command Structure to configure post processing parameters (ADRC)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_ADRC_LEN \
+ sizeof(audpp_cmd_cfg_object_params_adrc)
+
+
+#define AUDPP_CMD_ADRC_FLAG_DIS 0x0000
+#define AUDPP_CMD_ADRC_FLAG_ENA -1
+
+typedef struct {
+ audpp_cmd_cfg_object_params_common common;
+ signed short adrc_flag;
+ unsigned short compression_th;
+ unsigned short compression_slope;
+ unsigned short rms_time;
+ unsigned short attack_const_lsw;
+ unsigned short attack_const_msw;
+ unsigned short release_const_lsw;
+ unsigned short release_const_msw;
+ unsigned short adrc_system_delay;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_adrc;
+
+/*
+ * Command Structure to configure post processing parameters(Spectrum Analizer)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_SPECTRAM_LEN \
+ sizeof(audpp_cmd_cfg_object_params_spectram)
+
+
+typedef struct {
+ audpp_cmd_cfg_object_params_common common;
+ unsigned short sample_interval;
+ unsigned short num_coeff;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_spectram;
+
+/*
+ * Command Structure to configure post processing parameters (QConcert)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_QCONCERT_LEN \
+ sizeof(audpp_cmd_cfg_object_params_qconcert)
+
+
+#define AUDPP_CMD_QCON_ENA_FLAG_ENA -1
+#define AUDPP_CMD_QCON_ENA_FLAG_DIS 0x0000
+
+#define AUDPP_CMD_QCON_OP_MODE_HEADPHONE -1
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_FRONT 0x0000
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_SIDE 0x0001
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_DESKTOP 0x0002
+
+#define AUDPP_CMD_QCON_GAIN_UNIT 0x7FFF
+#define AUDPP_CMD_QCON_GAIN_SIX_DB 0x4027
+
+
+#define AUDPP_CMD_QCON_EXPANSION_MAX 0x7FFF
+
+
+typedef struct {
+ audpp_cmd_cfg_object_params_common common;
+ signed short enable_flag;
+ signed short output_mode;
+ signed short gain;
+ signed short expansion;
+ signed short delay;
+ unsigned short stages_per_mode;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_qconcert;
+
+/*
+ * Command Structure to configure post processing parameters (Side Chain)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_SIDECHAIN_LEN \
+ sizeof(audpp_cmd_cfg_object_params_sidechain)
+
+
+#define AUDPP_CMD_SIDECHAIN_ACTIVE_FLAG_DIS 0x0000
+#define AUDPP_CMD_SIDECHAIN_ACTIVE_FLAG_ENA -1
+
+typedef struct {
+ audpp_cmd_cfg_object_params_common common;
+ signed short active_flag;
+ unsigned short num_bands;
+ union {
+ filter_1 filter_1_params;
+ filter_2 filter_2_params;
+ filter_3 filter_3_params;
+ filter_4 filter_4_params;
+ } __attribute__((packed)) params_filter;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_sidechain;
+
+
+/*
+ * Command Structure to configure post processing parameters (QAFX)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_QAFX_LEN \
+ sizeof(audpp_cmd_cfg_object_params_qafx)
+
+#define AUDPP_CMD_QAFX_ENA_DISA 0x0000
+#define AUDPP_CMD_QAFX_ENA_ENA_CFG -1
+#define AUDPP_CMD_QAFX_ENA_DIS_CFG 0x0001
+
+#define AUDPP_CMD_QAFX_CMD_TYPE_ENV 0x0100
+#define AUDPP_CMD_QAFX_CMD_TYPE_OBJ 0x0010
+#define AUDPP_CMD_QAFX_CMD_TYPE_QUERY 0x1000
+
+#define AUDPP_CMD_QAFX_CMDS_ENV_OP_MODE 0x0100
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_POS 0x0101
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_ORI 0x0102
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_VEL 0X0103
+#define AUDPP_CMD_QAFX_CMDS_ENV_ENV_RES 0x0107
+
+#define AUDPP_CMD_QAFX_CMDS_OBJ_SAMP_FREQ 0x0010
+#define AUDPP_CMD_QAFX_CMDS_OBJ_VOL 0x0011
+#define AUDPP_CMD_QAFX_CMDS_OBJ_DIST 0x0012
+#define AUDPP_CMD_QAFX_CMDS_OBJ_POS 0x0013
+#define AUDPP_CMD_QAFX_CMDS_OBJ_VEL 0x0014
+
+
+typedef struct {
+ audpp_cmd_cfg_object_params_common common;
+ signed short enable;
+ unsigned short command_type;
+ unsigned short num_commands;
+ unsigned short commands;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_qafx;
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (Common)
+ */
+
+#define AUDPP_CMD_REVERB_CONFIG 0x0001
+#define AUDPP_CMD_REVERB_CONFIG_COMMON_LEN \
+ sizeof(audpp_cmd_reverb_config_common)
+
+#define AUDPP_CMD_ENA_ENA 0xFFFF
+#define AUDPP_CMD_ENA_DIS 0x0000
+#define AUDPP_CMD_ENA_CFG 0x0001
+
+#define AUDPP_CMD_CMD_TYPE_ENV 0x0104
+#define AUDPP_CMD_CMD_TYPE_OBJ 0x0015
+#define AUDPP_CMD_CMD_TYPE_QUERY 0x1000
+
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short enable;
+ unsigned short cmd_type;
+} __attribute__((packed)) audpp_cmd_reverb_config_common;
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (ENV-0x0104)
+ */
+
+#define AUDPP_CMD_REVERB_CONFIG_ENV_104_LEN \
+ sizeof(audpp_cmd_reverb_config_env_104)
+
+typedef struct {
+ audpp_cmd_reverb_config_common common;
+ unsigned short env_gain;
+ unsigned short decay_msw;
+ unsigned short decay_lsw;
+ unsigned short decay_timeratio_msw;
+ unsigned short decay_timeratio_lsw;
+ unsigned short delay_time;
+ unsigned short reverb_gain;
+ unsigned short reverb_delay;
+} __attribute__((packed)) audpp_cmd_reverb_config_env_104;
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (ENV-0x0015)
+ */
+
+#define AUDPP_CMD_REVERB_CONFIG_ENV_15_LEN \
+ sizeof(audpp_cmd_reverb_config_env_15)
+
+typedef struct {
+ audpp_cmd_reverb_config_common common;
+ unsigned short object_num;
+ unsigned short absolute_gain;
+} __attribute__((packed)) audpp_cmd_reverb_config_env_15;
+
+
+#endif /* QDSP5AUDPPCMDI_H */
+
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audppmsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audppmsg.h
new file mode 100644
index 000000000000..44fea224001a
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5audppmsg.h
@@ -0,0 +1,318 @@
+#ifndef QDSP5AUDPPMSG_H
+#define QDSP5AUDPPMSG_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ Q D S P 5 A U D I O P O S T P R O C E S S I N G M S G
+
+GENERAL DESCRIPTION
+ Messages sent by AUDPPTASK to ARM
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2009 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+ $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audppmsg.h#4 $
+
+===========================================================================*/
+
+/*
+ * AUDPPTASK uses audPPuPRlist to send messages to the ARM
+ * Location : MEMA
+ * Buffer Size : 45
+ * No of Buffers in a queue : 5 for gaming audio and 1 for other images
+ */
+
+/*
+ * MSG to Informs the ARM os Success/Failure of bringing up the decoder
+ */
+
+#define AUDPP_MSG_STATUS_MSG 0x0001
+#define AUDPP_MSG_STATUS_MSG_LEN \
+ sizeof(audpp_msg_status_msg)
+
+#define AUDPP_MSG_STATUS_SLEEP 0x0000
+#define AUDPP_MSG__STATUS_INIT 0x0001
+#define AUDPP_MSG_MSG_STATUS_CFG 0x0002
+#define AUDPP_MSG_STATUS_PLAY 0x0003
+
+#define AUDPP_MSG_REASON_MIPS 0x0000
+#define AUDPP_MSG_REASON_MEM 0x0001
+
+typedef struct{
+ unsigned short dec_id;
+ unsigned short status;
+ unsigned short reason;
+} __attribute__((packed)) audpp_msg_status_msg;
+
+/*
+ * MSG to communicate the spectrum analyzer output bands to the ARM
+ */
+#define AUDPP_MSG_SPA_BANDS 0x0002
+#define AUDPP_MSG_SPA_BANDS_LEN \
+ sizeof(audpp_msg_spa_bands)
+
+typedef struct {
+ unsigned short current_object;
+ unsigned short spa_band_1;
+ unsigned short spa_band_2;
+ unsigned short spa_band_3;
+ unsigned short spa_band_4;
+ unsigned short spa_band_5;
+ unsigned short spa_band_6;
+ unsigned short spa_band_7;
+ unsigned short spa_band_8;
+ unsigned short spa_band_9;
+ unsigned short spa_band_10;
+ unsigned short spa_band_11;
+ unsigned short spa_band_12;
+ unsigned short spa_band_13;
+ unsigned short spa_band_14;
+ unsigned short spa_band_15;
+ unsigned short spa_band_16;
+ unsigned short spa_band_17;
+ unsigned short spa_band_18;
+ unsigned short spa_band_19;
+ unsigned short spa_band_20;
+ unsigned short spa_band_21;
+ unsigned short spa_band_22;
+ unsigned short spa_band_23;
+ unsigned short spa_band_24;
+ unsigned short spa_band_25;
+ unsigned short spa_band_26;
+ unsigned short spa_band_27;
+ unsigned short spa_band_28;
+ unsigned short spa_band_29;
+ unsigned short spa_band_30;
+ unsigned short spa_band_31;
+ unsigned short spa_band_32;
+} __attribute__((packed)) audpp_msg_spa_bands;
+
+/*
+ * MSG to communicate the PCM I/O buffer status to ARM
+ */
+#define AUDPP_MSG_HOST_PCM_INTF_MSG 0x0003
+#define AUDPP_MSG_HOST_PCM_INTF_MSG_LEN \
+ sizeof(audpp_msg_host_pcm_intf_msg)
+
+#define AUDPP_MSG_HOSTPCM_ID_TX_ARM 0x0000
+#define AUDPP_MSG_HOSTPCM_ID_ARM_TX 0x0001
+#define AUDPP_MSG_HOSTPCM_ID_RX_ARM 0x0002
+#define AUDPP_MSG_HOSTPCM_ID_ARM_RX 0x0003
+
+#define AUDPP_MSG_SAMP_FREQ_INDX_96000 0x0000
+#define AUDPP_MSG_SAMP_FREQ_INDX_88200 0x0001
+#define AUDPP_MSG_SAMP_FREQ_INDX_64000 0x0002
+#define AUDPP_MSG_SAMP_FREQ_INDX_48000 0x0003
+#define AUDPP_MSG_SAMP_FREQ_INDX_44100 0x0004
+#define AUDPP_MSG_SAMP_FREQ_INDX_32000 0x0005
+#define AUDPP_MSG_SAMP_FREQ_INDX_24000 0x0006
+#define AUDPP_MSG_SAMP_FREQ_INDX_22050 0x0007
+#define AUDPP_MSG_SAMP_FREQ_INDX_16000 0x0008
+#define AUDPP_MSG_SAMP_FREQ_INDX_12000 0x0009
+#define AUDPP_MSG_SAMP_FREQ_INDX_11025 0x000A
+#define AUDPP_MSG_SAMP_FREQ_INDX_8000 0x000B
+
+#define AUDPP_MSG_CHANNEL_MODE_MONO 0x0001
+#define AUDPP_MSG_CHANNEL_MODE_STEREO 0x0002
+
+typedef struct{
+ unsigned short obj_num;
+ unsigned short numbers_of_samples;
+ unsigned short host_pcm_id;
+ unsigned short buf_indx;
+ unsigned short samp_freq_indx;
+ unsigned short channel_mode;
+} __attribute__((packed)) audpp_msg_host_pcm_intf_msg;
+
+
+/*
+ * MSG to communicate 3D position of the source and listener , source volume
+ * source rolloff, source orientation
+ */
+
+#define AUDPP_MSG_QAFX_POS 0x0004
+#define AUDPP_MSG_QAFX_POS_LEN \
+ sizeof(audpp_msg_qafx_pos)
+
+typedef struct {
+ unsigned short current_object;
+ unsigned short x_pos_lis_msw;
+ unsigned short x_pos_lis_lsw;
+ unsigned short y_pos_lis_msw;
+ unsigned short y_pos_lis_lsw;
+ unsigned short z_pos_lis_msw;
+ unsigned short z_pos_lis_lsw;
+ unsigned short x_fwd_msw;
+ unsigned short x_fwd_lsw;
+ unsigned short y_fwd_msw;
+ unsigned short y_fwd_lsw;
+ unsigned short z_fwd_msw;
+ unsigned short z_fwd_lsw;
+ unsigned short x_up_msw;
+ unsigned short x_up_lsw;
+ unsigned short y_up_msw;
+ unsigned short y_up_lsw;
+ unsigned short z_up_msw;
+ unsigned short z_up_lsw;
+ unsigned short x_vel_lis_msw;
+ unsigned short x_vel_lis_lsw;
+ unsigned short y_vel_lis_msw;
+ unsigned short y_vel_lis_lsw;
+ unsigned short z_vel_lis_msw;
+ unsigned short z_vel_lis_lsw;
+ unsigned short threed_enable_flag;
+ unsigned short volume;
+ unsigned short x_pos_source_msw;
+ unsigned short x_pos_source_lsw;
+ unsigned short y_pos_source_msw;
+ unsigned short y_pos_source_lsw;
+ unsigned short z_pos_source_msw;
+ unsigned short z_pos_source_lsw;
+ unsigned short max_dist_0_msw;
+ unsigned short max_dist_0_lsw;
+ unsigned short min_dist_0_msw;
+ unsigned short min_dist_0_lsw;
+ unsigned short roll_off_factor;
+ unsigned short mute_after_max_flag;
+ unsigned short x_vel_source_msw;
+ unsigned short x_vel_source_lsw;
+ unsigned short y_vel_source_msw;
+ unsigned short y_vel_source_lsw;
+ unsigned short z_vel_source_msw;
+ unsigned short z_vel_source_lsw;
+} __attribute__((packed)) audpp_msg_qafx_pos;
+
+/*
+ * MSG to provide AVSYNC feedback from DSP to ARM
+ */
+
+#define AUDPP_MSG_AVSYNC_MSG 0x0005
+#define AUDPP_MSG_AVSYNC_MSG_LEN \
+ sizeof(audpp_msg_avsync_msg)
+
+typedef struct {
+ unsigned short active_flag;
+ unsigned short num_samples_counter0_HSW;
+ unsigned short num_samples_counter0_MSW;
+ unsigned short num_samples_counter0_LSW;
+ unsigned short num_bytes_counter0_HSW;
+ unsigned short num_bytes_counter0_MSW;
+ unsigned short num_bytes_counter0_LSW;
+ unsigned short samp_freq_obj_0;
+ unsigned short samp_freq_obj_1;
+ unsigned short samp_freq_obj_2;
+ unsigned short samp_freq_obj_3;
+ unsigned short samp_freq_obj_4;
+ unsigned short samp_freq_obj_5;
+ unsigned short samp_freq_obj_6;
+ unsigned short samp_freq_obj_7;
+ unsigned short samp_freq_obj_8;
+ unsigned short samp_freq_obj_9;
+ unsigned short samp_freq_obj_10;
+ unsigned short samp_freq_obj_11;
+ unsigned short samp_freq_obj_12;
+ unsigned short samp_freq_obj_13;
+ unsigned short samp_freq_obj_14;
+ unsigned short samp_freq_obj_15;
+ unsigned short num_samples_counter4_HSW;
+ unsigned short num_samples_counter4_MSW;
+ unsigned short num_samples_counter4_LSW;
+ unsigned short num_bytes_counter4_HSW;
+ unsigned short num_bytes_counter4_MSW;
+ unsigned short num_bytes_counter4_LSW;
+} __attribute__((packed)) audpp_msg_avsync_msg;
+
+/*
+ * MSG to provide PCM DMA Missed feedback from the DSP to ARM
+ */
+
+#define AUDPP_MSG_PCMDMAMISSED 0x0006
+#define AUDPP_MSG_PCMDMAMISSED_LEN \
+ sizeof(audpp_msg_pcmdmamissed);
+
+typedef struct{
+ /*
+ ** Bit 0 0 = PCM DMA not missed for object 0
+ ** 1 = PCM DMA missed for object0
+ ** Bit 1 0 = PCM DMA not missed for object 1
+ ** 1 = PCM DMA missed for object1
+ ** Bit 2 0 = PCM DMA not missed for object 2
+ ** 1 = PCM DMA missed for object2
+ ** Bit 3 0 = PCM DMA not missed for object 3
+ ** 1 = PCM DMA missed for object3
+ ** Bit 4 0 = PCM DMA not missed for object 4
+ ** 1 = PCM DMA missed for object4
+ */
+ unsigned short pcmdmamissed;
+} __attribute__((packed)) audpp_msg_pcmdmamissed;
+
+/*
+ * MSG to AUDPP enable or disable feedback form DSP to ARM
+ */
+
+#define AUDPP_MSG_CFG_MSG 0x0007
+#define AUDPP_MSG_CFG_MSG_LEN \
+ sizeof(audpp_msg_cfg_msg)
+
+#define AUDPP_MSG_ENA_ENA 0xFFFF
+#define AUDPP_MSG_ENA_DIS 0x0000
+
+typedef struct{
+ /* Enabled - 0xffff
+ ** Disabled - 0
+ */
+ unsigned short enabled;
+} __attribute__((packed)) audpp_msg_cfg_msg;
+
+/*
+ * MSG to communicate the reverb per object volume
+ */
+
+#define AUDPP_MSG_QREVERB_VOLUME 0x0008
+#define AUDPP_MSG_QREVERB_VOLUME_LEN \
+ sizeof(audpp_msg_qreverb_volume)
+
+
+typedef struct {
+ unsigned short obj_0_gain;
+ unsigned short obj_1_gain;
+ unsigned short obj_2_gain;
+ unsigned short obj_3_gain;
+ unsigned short obj_4_gain;
+ unsigned short hpcm_obj_volume;
+} __attribute__((packed)) audpp_msg_qreverb_volume;
+
+#define AUDPP_MSG_ROUTING_ACK 0x0009
+#define AUDPP_MSG_ROUTING_ACK_LEN \
+ sizeof(struct audpp_msg_routing_ack)
+
+struct audpp_msg_routing_ack {
+ unsigned short dec_id;
+ unsigned short routing_mode;
+} __attribute__((packed));
+
+#define AUDPP_MSG_FLUSH_ACK 0x000A
+
+#endif /* QDSP5AUDPPMSG_H */
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audpreproccmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audpreproccmdi.h
new file mode 100644
index 000000000000..06d33d571583
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5audpreproccmdi.h
@@ -0,0 +1,256 @@
+#ifndef QDSP5AUDPREPROCCMDI_H
+#define QDSP5AUDPREPROCCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ A U D I O P R E P R O C E S S I N G I N T E R N A L C O M M A N D S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of commands
+ that are accepted by AUDPREPROC Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audpreproccmdi.h#2 $
+
+===========================================================================*/
+
+/*
+ * AUDIOPREPROC COMMANDS:
+ * ARM uses uPAudPreProcCmdQueue to communicate with AUDPREPROCTASK
+ * Location : MEMB
+ * Buffer size : 51
+ * Number of buffers in a queue : 3
+ */
+
+/*
+ * Command to configure the parameters of AGC
+ */
+
+#define AUDPREPROC_CMD_CFG_AGC_PARAMS 0x0000
+#define AUDPREPROC_CMD_CFG_AGC_PARAMS_LEN \
+ sizeof(audpreproc_cmd_cfg_agc_params)
+
+#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_SLOPE 0x0009
+#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_TH 0x000A
+#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_SLOPE 0x000B
+#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_TH 0x000C
+#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_AIG_FLAG 0x000D
+#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_STATIC_GAIN 0x000E
+#define AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG 0x000F
+
+#define AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA -1
+#define AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS 0x0000
+
+#define AUDPREPROC_CMD_ADP_GAIN_FLAG_ENA_ADP_GAIN -1
+#define AUDPREPROC_CMD_ADP_GAIN_FLAG_ENA_STATIC_GAIN 0x0000
+
+#define AUDPREPROC_CMD_PARAM_MASK_RMS_TAY 0x0004
+#define AUDPREPROC_CMD_PARAM_MASK_RELEASEK 0x0005
+#define AUDPREPROC_CMD_PARAM_MASK_DELAY 0x0006
+#define AUDPREPROC_CMD_PARAM_MASK_ATTACKK 0x0007
+#define AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_SLOW 0x0008
+#define AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_FAST 0x0009
+#define AUDPREPROC_CMD_PARAM_MASK_AIG_RELEASEK 0x000A
+#define AUDPREPROC_CMD_PARAM_MASK_AIG_MIN 0x000B
+#define AUDPREPROC_CMD_PARAM_MASK_AIG_MAX 0x000C
+#define AUDPREPROC_CMD_PARAM_MASK_LEAK_UP 0x000D
+#define AUDPREPROC_CMD_PARAM_MASK_LEAK_DOWN 0x000E
+#define AUDPREPROC_CMD_PARAM_MASK_AIG_ATTACKK 0x000F
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short tx_agc_param_mask;
+ unsigned short tx_agc_enable_flag;
+ unsigned short static_gain;
+ signed short adaptive_gain_flag;
+ unsigned short expander_th;
+ unsigned short expander_slope;
+ unsigned short compressor_th;
+ unsigned short compressor_slope;
+ unsigned short param_mask;
+ unsigned short aig_attackk;
+ unsigned short aig_leak_down;
+ unsigned short aig_leak_up;
+ unsigned short aig_max;
+ unsigned short aig_min;
+ unsigned short aig_releasek;
+ unsigned short aig_leakrate_fast;
+ unsigned short aig_leakrate_slow;
+ unsigned short attackk_msw;
+ unsigned short attackk_lsw;
+ unsigned short delay;
+ unsigned short releasek_msw;
+ unsigned short releasek_lsw;
+ unsigned short rms_tav;
+} __attribute__((packed)) audpreproc_cmd_cfg_agc_params;
+
+
+/*
+ * Command to configure the params of Advanved AGC
+ */
+
+#define AUDPREPROC_CMD_CFG_AGC_PARAMS_2 0x0001
+#define AUDPREPROC_CMD_CFG_AGC_PARAMS_2_LEN \
+ sizeof(audpreproc_cmd_cfg_agc_params_2)
+
+#define AUDPREPROC_CMD_2_TX_AGC_ENA_FLAG_ENA -1;
+#define AUDPREPROC_CMD_2_TX_AGC_ENA_FLAG_DIS 0x0000;
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short agc_param_mask;
+ signed short tx_agc_enable_flag;
+ unsigned short comp_static_gain;
+ unsigned short exp_th;
+ unsigned short exp_slope;
+ unsigned short comp_th;
+ unsigned short comp_slope;
+ unsigned short comp_rms_tav;
+ unsigned short comp_samp_mask;
+ unsigned short comp_attackk_msw;
+ unsigned short comp_attackk_lsw;
+ unsigned short comp_releasek_msw;
+ unsigned short comp_releasek_lsw;
+ unsigned short comp_delay;
+ unsigned short comp_makeup_gain;
+} __attribute__((packed)) audpreproc_cmd_cfg_agc_params_2;
+
+/*
+ * Command to configure params for ns
+ */
+
+#define AUDPREPROC_CMD_CFG_NS_PARAMS 0x0002
+#define AUDPREPROC_CMD_CFG_NS_PARAMS_LEN \
+ sizeof(audpreproc_cmd_cfg_ns_params)
+
+#define AUDPREPROC_CMD_EC_MODE_NEW_NLMS_ENA 0x0001
+#define AUDPREPROC_CMD_EC_MODE_NEW_NLMS_DIS 0x0000
+#define AUDPREPROC_CMD_EC_MODE_NEW_DES_ENA 0x0002
+#define AUDPREPROC_CMD_EC_MODE_NEW_DES_DIS 0x0000
+#define AUDPREPROC_CMD_EC_MODE_NEW_NS_ENA 0x0004
+#define AUDPREPROC_CMD_EC_MODE_NEW_NS_DIS 0x0000
+#define AUDPREPROC_CMD_EC_MODE_NEW_CNI_ENA 0x0008
+#define AUDPREPROC_CMD_EC_MODE_NEW_CNI_DIS 0x0000
+
+#define AUDPREPROC_CMD_EC_MODE_NEW_NLES_ENA 0x0010
+#define AUDPREPROC_CMD_EC_MODE_NEW_NLES_DIS 0x0000
+#define AUDPREPROC_CMD_EC_MODE_NEW_HB_ENA 0x0020
+#define AUDPREPROC_CMD_EC_MODE_NEW_HB_DIS 0x0000
+#define AUDPREPROC_CMD_EC_MODE_NEW_VA_ENA 0x0040
+#define AUDPREPROC_CMD_EC_MODE_NEW_VA_DIS 0x0000
+#define AUDPREPROC_CMD_EC_MODE_NEW_PCD_ENA 0x0080
+#define AUDPREPROC_CMD_EC_MODE_NEW_PCD_DIS 0x0000
+#define AUDPREPROC_CMD_EC_MODE_NEW_FEHI_ENA 0x0100
+#define AUDPREPROC_CMD_EC_MODE_NEW_FEHI_DIS 0x0000
+#define AUDPREPROC_CMD_EC_MODE_NEW_NEHI_ENA 0x0200
+#define AUDPREPROC_CMD_EC_MODE_NEW_NEHI_DIS 0x0000
+#define AUDPREPROC_CMD_EC_MODE_NEW_NLPP_ENA 0x0400
+#define AUDPREPROC_CMD_EC_MODE_NEW_NLPP_DIS 0x0000
+#define AUDPREPROC_CMD_EC_MODE_NEW_FNE_ENA 0x0800
+#define AUDPREPROC_CMD_EC_MODE_NEW_FNE_DIS 0x0000
+#define AUDPREPROC_CMD_EC_MODE_NEW_PRENLMS_ENA 0x1000
+#define AUDPREPROC_CMD_EC_MODE_NEW_PRENLMS_DIS 0x0000
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short ec_mode_new;
+ unsigned short dens_gamma_n;
+ unsigned short dens_nfe_block_size;
+ unsigned short dens_limit_ns;
+ unsigned short dens_limit_ns_d;
+ unsigned short wb_gamma_e;
+ unsigned short wb_gamma_n;
+} __attribute__((packed)) audpreproc_cmd_cfg_ns_params;
+
+/*
+ * Command to configure parameters for IIR tuning filter
+ */
+
+#define AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS 0x0003
+#define AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS_LEN \
+ sizeof(audpreproc_cmd_cfg_iir_tuning_filter_params)
+
+#define AUDPREPROC_CMD_IIR_ACTIVE_FLAG_DIS 0x0000
+#define AUDPREPROC_CMD_IIR_ACTIVE_FLAG_ENA 0x0001
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short active_flag;
+ unsigned short num_bands;
+ unsigned short numerator_coeff_b0_filter0_lsw;
+ unsigned short numerator_coeff_b0_filter0_msw;
+ unsigned short numerator_coeff_b1_filter0_lsw;
+ unsigned short numerator_coeff_b1_filter0_msw;
+ unsigned short numerator_coeff_b2_filter0_lsw;
+ unsigned short numerator_coeff_b2_filter0_msw;
+ unsigned short numerator_coeff_b0_filter1_lsw;
+ unsigned short numerator_coeff_b0_filter1_msw;
+ unsigned short numerator_coeff_b1_filter1_lsw;
+ unsigned short numerator_coeff_b1_filter1_msw;
+ unsigned short numerator_coeff_b2_filter1_lsw;
+ unsigned short numerator_coeff_b2_filter1_msw;
+ unsigned short numerator_coeff_b0_filter2_lsw;
+ unsigned short numerator_coeff_b0_filter2_msw;
+ unsigned short numerator_coeff_b1_filter2_lsw;
+ unsigned short numerator_coeff_b1_filter2_msw;
+ unsigned short numerator_coeff_b2_filter2_lsw;
+ unsigned short numerator_coeff_b2_filter2_msw;
+ unsigned short numerator_coeff_b0_filter3_lsw;
+ unsigned short numerator_coeff_b0_filter3_msw;
+ unsigned short numerator_coeff_b1_filter3_lsw;
+ unsigned short numerator_coeff_b1_filter3_msw;
+ unsigned short numerator_coeff_b2_filter3_lsw;
+ unsigned short numerator_coeff_b2_filter3_msw;
+ unsigned short denominator_coeff_a0_filter0_lsw;
+ unsigned short denominator_coeff_a0_filter0_msw;
+ unsigned short denominator_coeff_a1_filter0_lsw;
+ unsigned short denominator_coeff_a1_filter0_msw;
+ unsigned short denominator_coeff_a0_filter1_lsw;
+ unsigned short denominator_coeff_a0_filter1_msw;
+ unsigned short denominator_coeff_a1_filter1_lsw;
+ unsigned short denominator_coeff_a1_filter1_msw;
+ unsigned short denominator_coeff_a0_filter2_lsw;
+ unsigned short denominator_coeff_a0_filter2_msw;
+ unsigned short denominator_coeff_a1_filter2_lsw;
+ unsigned short denominator_coeff_a1_filter2_msw;
+ unsigned short denominator_coeff_a0_filter3_lsw;
+ unsigned short denominator_coeff_a0_filter3_msw;
+ unsigned short denominator_coeff_a1_filter3_lsw;
+ unsigned short denominator_coeff_a1_filter3_msw;
+
+ unsigned short shift_factor_filter0;
+ unsigned short shift_factor_filter1;
+ unsigned short shift_factor_filter2;
+ unsigned short shift_factor_filter3;
+
+ unsigned short channel_selected0;
+ unsigned short channel_selected1;
+ unsigned short channel_selected2;
+ unsigned short channel_selected3;
+} __attribute__((packed))audpreproc_cmd_cfg_iir_tuning_filter_params;
+
+#endif
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audpreprocmsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audpreprocmsg.h
new file mode 100644
index 000000000000..f40e41e76737
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5audpreprocmsg.h
@@ -0,0 +1,85 @@
+#ifndef QDSP5AUDPREPROCMSG_H
+#define QDSP5AUDPREPROCMSG_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ A U D I O P R E P R O C E S S I N G M E S S A G E S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of messages
+ that are rcvd by AUDPREPROC Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+ $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audpreprocmsg.h#3 $
+
+===========================================================================*/
+
+/*
+ * ADSPREPROCTASK Messages
+ * AUDPREPROCTASK uses audPreProcUpRlist to communicate with ARM
+ * Location : MEMA
+ * Message Length : 2
+ */
+
+/*
+ * Message to indicate particular feature has been enabled or disabled
+ */
+
+
+#define AUDPREPROC_MSG_CMD_CFG_DONE_MSG 0x0000
+#define AUDPREPROC_MSG_CMD_CFG_DONE_MSG_LEN \
+ sizeof(audpreproc_msg_cmd_cfg_done_msg)
+
+#define AUDPREPROC_MSG_TYPE_AGC 0x0000
+#define AUDPREPROC_MSG_TYPE_NOISE_REDUCTION 0x0001
+#define AUDPREPROC_MSG_TYPE_IIR_FILTER 0x0002
+
+
+#define AUDPREPROC_MSG_STATUS_FLAG_ENA -1
+#define AUDPREPROC_MSG_STATUS_FLAG_DIS 0x0000
+
+typedef struct {
+ unsigned short type;
+ signed short status_flag;
+} __attribute__((packed)) audpreproc_msg_cmd_cfg_done_msg;
+
+
+/*
+ * Message to indicate particular feature has selected for wrong samp freq
+ */
+
+#define AUDPREPROC_MSG_ERROR_MSG_ID 0x0001
+#define AUDPREPROC_MSG_ERROR_MSG_ID_LEN \
+ sizeof(audpreproc_msg_error_msg_id)
+
+#define AUDPREPROC_MSG_ERR_INDEX_NS 0x0000
+
+typedef struct {
+ unsigned short err_index;
+} __attribute__((packed)) audpreproc_msg_error_msg_id;
+
+#endif
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audreccmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audreccmdi.h
new file mode 100644
index 000000000000..d03ee024ae91
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5audreccmdi.h
@@ -0,0 +1,176 @@
+#ifndef QDSP5AUDRECCMDI_H
+#define QDSP5AUDRECCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ A U D I O R E C O R D I N T E R N A L C O M M A N D S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of commands
+ that are accepted by AUDREC Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+ $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audreccmdi.h#3 $
+
+============================================================================*/
+
+/*
+ * AUDRECTASK COMMANDS
+ * ARM uses 2 queues to communicate with the AUDRECTASK
+ * 1.uPAudRecCmdQueue
+ * Location :MEMC
+ * Buffer Size : 8
+ * No of Buffers in a queue : 3
+ * 2.audRecUpBitStreamQueue
+ * Location : MEMC
+ * Buffer Size : 4
+ * No of buffers in a queue : 2
+ */
+
+/*
+ * Commands on uPAudRecCmdQueue
+ */
+
+/*
+ * Command to initiate and terminate the audio recording section
+ */
+
+#define AUDREC_CMD_CFG 0x0000
+#define AUDREC_CMD_CFG_LEN sizeof(audrec_cmd_cfg)
+
+#define AUDREC_CMD_TYPE_0_INDEX_WAV 0x0000
+#define AUDREC_CMD_TYPE_0_INDEX_AAC 0x0001
+
+#define AUDREC_CMD_TYPE_0_ENA 0x4000
+#define AUDREC_CMD_TYPE_0_DIS 0x0000
+
+#define AUDREC_CMD_TYPE_0_NOUPDATE 0x0000
+#define AUDREC_CMD_TYPE_0_UPDATE 0x8000
+
+#define AUDREC_CMD_TYPE_1_INDEX_SBC 0x0002
+
+#define AUDREC_CMD_TYPE_1_ENA 0x4000
+#define AUDREC_CMD_TYPE_1_DIS 0x0000
+
+#define AUDREC_CMD_TYPE_1_NOUPDATE 0x0000
+#define AUDREC_CMD_TYPE_1_UPDATE 0x8000
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short type_0;
+ unsigned short type_1;
+} __attribute__((packed)) audrec_cmd_cfg;
+
+
+/*
+ * Command to configure the recording parameters for RecType0(AAC/WAV) encoder
+ */
+
+#define AUDREC_CMD_AREC0PARAM_CFG 0x0001
+#define AUDREC_CMD_AREC0PARAM_CFG_LEN \
+ sizeof(audrec_cmd_arec0param_cfg)
+
+#define AUDREC_CMD_SAMP_RATE_INDX_8000 0x000B
+#define AUDREC_CMD_SAMP_RATE_INDX_11025 0x000A
+#define AUDREC_CMD_SAMP_RATE_INDX_12000 0x0009
+#define AUDREC_CMD_SAMP_RATE_INDX_16000 0x0008
+#define AUDREC_CMD_SAMP_RATE_INDX_22050 0x0007
+#define AUDREC_CMD_SAMP_RATE_INDX_24000 0x0006
+#define AUDREC_CMD_SAMP_RATE_INDX_32000 0x0005
+#define AUDREC_CMD_SAMP_RATE_INDX_44100 0x0004
+#define AUDREC_CMD_SAMP_RATE_INDX_48000 0x0003
+
+#define AUDREC_CMD_STEREO_MODE_MONO 0x0000
+#define AUDREC_CMD_STEREO_MODE_STEREO 0x0001
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short ptr_to_extpkt_buffer_msw;
+ unsigned short ptr_to_extpkt_buffer_lsw;
+ unsigned short buf_len;
+ unsigned short samp_rate_index;
+ unsigned short stereo_mode;
+ unsigned short rec_quality;
+} __attribute__((packed)) audrec_cmd_arec0param_cfg;
+
+/*
+ * Command to configure the recording parameters for RecType1(SBC) encoder
+ */
+
+#define AUDREC_CMD_AREC1PARAM_CFG 0x0002
+#define AUDREC_CMD_AREC1PARAM_CFG_LEN \
+ sizeof(audrec_cmd_arec1param_cfg)
+
+#define AUDREC_CMD_PARAM_BUF_BLOCKS_4 0x0000
+#define AUDREC_CMD_PARAM_BUF_BLOCKS_8 0x0001
+#define AUDREC_CMD_PARAM_BUF_BLOCKS_12 0x0002
+#define AUDREC_CMD_PARAM_BUF_BLOCKS_16 0x0003
+
+#define AUDREC_CMD_PARAM_BUF_SUB_BANDS_8 0x0010
+#define AUDREC_CMD_PARAM_BUF_MODE_MONO 0x0000
+#define AUDREC_CMD_PARAM_BUF_MODE_DUAL 0x0040
+#define AUDREC_CMD_PARAM_BUF_MODE_STEREO 0x0050
+#define AUDREC_CMD_PARAM_BUF_MODE_JSTEREO 0x0060
+#define AUDREC_CMD_PARAM_BUF_LOUDNESS 0x0000
+#define AUDREC_CMD_PARAM_BUF_SNR 0x0100
+#define AUDREC_CMD_PARAM_BUF_BASIC_VER 0x0000
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short ptr_to_extpkt_buffer_msw;
+ unsigned short ptr_to_extpkt_buffer_lsw;
+ unsigned short buf_len;
+ unsigned short param_buf;
+ unsigned short bit_rate_0;
+ unsigned short bit_rate_1;
+} __attribute__((packed)) audrec_cmd_arec1param_cfg;
+
+
+/*
+ * Commands on audRecUpBitStreamQueue
+ */
+
+/*
+ * Command to indicate the current packet read count
+ */
+
+#define AUDREC_CMD_PACKET_EXT_PTR 0x0000
+#define AUDREC_CMD_PACKET_EXT_PTR_LEN \
+ sizeof(audrec_cmd_packet_ext_ptr)
+
+#define AUDREC_CMD_TYPE_0 0x0000
+#define AUDREC_CMD_TYPE_1 0x0001
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short type;
+ unsigned short curr_rec_count_msw;
+ unsigned short curr_rec_count_lsw;
+} __attribute__((packed)) audrec_cmd_packet_ext_ptr;
+
+#endif
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5audrecmsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5audrecmsg.h
new file mode 100644
index 000000000000..bb6eb5093cf5
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5audrecmsg.h
@@ -0,0 +1,127 @@
+#ifndef QDSP5AUDRECMSGI_H
+#define QDSP5AUDRECMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ A U D I O R E C O R D M E S S A G E S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of messages
+ that are sent by AUDREC Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+ $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audrecmsg.h#3 $
+
+============================================================================*/
+
+/*
+ * AUDRECTASK MESSAGES
+ * AUDRECTASK uses audRecUpRlist to communicate with ARM
+ * Location : MEMC
+ * Buffer size : 4
+ * No of buffers in a queue : 2
+ */
+
+/*
+ * Message to notify that config command is done
+ */
+
+#define AUDREC_MSG_CMD_CFG_DONE_MSG 0x0002
+#define AUDREC_MSG_CMD_CFG_DONE_MSG_LEN \
+ sizeof(audrec_msg_cmd_cfg_done_msg)
+
+
+#define AUDREC_MSG_CFG_DONE_TYPE_0_ENA 0x4000
+#define AUDREC_MSG_CFG_DONE_TYPE_0_DIS 0x0000
+
+#define AUDREC_MSG_CFG_DONE_TYPE_0_NO_UPDATE 0x0000
+#define AUDREC_MSG_CFG_DONE_TYPE_0_UPDATE 0x8000
+
+#define AUDREC_MSG_CFG_DONE_TYPE_1_ENA 0x4000
+#define AUDREC_MSG_CFG_DONE_TYPE_1_DIS 0x0000
+
+#define AUDREC_MSG_CFG_DONE_TYPE_1_NO_UPDATE 0x0000
+#define AUDREC_MSG_CFG_DONE_TYPE_1_UPDATE 0x8000
+
+typedef struct {
+ unsigned short type_0;
+ unsigned short type_1;
+} __attribute__((packed))audrec_msg_cmd_cfg_done_msg;
+
+
+/*
+ * Message to notify arec0/1 cfg done and recording params revd by task
+ */
+
+#define AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG 0x0003
+#define AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG_LEN \
+ sizeof(audrec_msg_cmd_arec_param_cfg_done_msg)
+
+#define AUDREC_MSG_AREC_PARAM_TYPE_0 0x0000
+#define AUDREC_MSG_AREC_PARAM_TYPE_1 0x0001
+
+typedef struct {
+ unsigned short type;
+} __attribute__((packed))audrec_msg_cmd_arec_param_cfg_done_msg;
+
+
+/*
+ * Message to notify no more buffers are available in ext mem to DME
+ */
+
+#define AUDREC_MSG_FATAL_ERR_MSG 0x0004
+#define AUDREC_MSG_FATAL_ERR_MSG_LEN \
+ sizeof(audrec_msg_fatal_err_msg)
+
+#define AUDREC_MSG_FATAL_ERR_TYPE_0 0x0000
+#define AUDREC_MSG_FATAL_ERR_TYPE_1 0x0001
+
+typedef struct {
+ unsigned short type;
+} __attribute__((packed))audrec_msg_fatal_err_msg;
+
+/*
+ * Message to notify DME deliverd the encoded pkt to ext pkt buffer
+ */
+
+#define AUDREC_MSG_PACKET_READY_MSG 0x0005
+#define AUDREC_MSG_PACKET_READY_MSG_LEN \
+ sizeof(audrec_msg_packet_ready_msg)
+
+#define AUDREC_MSG_PACKET_READY_TYPE_0 0x0000
+#define AUDREC_MSG_PACKET_READY_TYPE_1 0x0001
+
+typedef struct {
+ unsigned short type;
+ unsigned short pkt_counter_msw;
+ unsigned short pkt_counter_lsw;
+ unsigned short pkt_read_cnt_msw;
+ unsigned short pkt_read_cnt_lsw;
+} __attribute__((packed))audrec_msg_packet_ready_msg;
+
+#endif
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5jpegcmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5jpegcmdi.h
new file mode 100644
index 000000000000..574ad6bbcade
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5jpegcmdi.h
@@ -0,0 +1,376 @@
+#ifndef QDSP5VIDJPEGCMDI_H
+#define QDSP5VIDJPEGCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ J P E G I N T E R N A L C O M M A N D S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of commands
+ that are accepted by JPEG Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5jpegcmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+when who what, where, why
+-------- --- ----------------------------------------------------------
+06/09/08 sv initial version
+===========================================================================*/
+
+/*
+ * ARM to JPEG configuration commands are passed through the
+ * uPJpegCfgCmdQueue
+ */
+
+/*
+ * Command to configure JPEG Encoder
+ */
+
+#define JPEG_CMD_ENC_CFG 0x0000
+#define JPEG_CMD_ENC_CFG_LEN sizeof(jpeg_cmd_enc_cfg)
+
+#define JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_0 0x0000
+#define JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_90 0x0100
+#define JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_180 0x0200
+#define JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_270 0x0300
+#define JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_M 0x0003
+#define JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H2V2 0x0000
+#define JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H2V1 0x0001
+#define JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H1V2 0x0002
+
+#define JPEG_CMD_IP_SIZE_CFG_LUMA_HEIGHT_M 0x0000FFFF
+#define JPEG_CMD_IP_SIZE_CFG_LUMA_WIDTH_M 0xFFFF0000
+#define JPEG_CMD_ENC_UPSAMP_IP_SIZE_CFG_ENA 0x0001
+#define JPEG_CMD_ENC_UPSAMP_IP_SIZE_CFG_DIS 0x0000
+
+#define JPEG_CMD_FRAG_SIZE_LUMA_HEIGHT_M 0xFFFF
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int process_cfg;
+ unsigned int ip_size_cfg;
+ unsigned int op_size_cfg;
+ unsigned int frag_cfg;
+ unsigned int frag_cfg_part[16];
+
+ unsigned int part_num;
+
+ unsigned int op_buf_0_cfg_part1;
+ unsigned int op_buf_0_cfg_part2;
+ unsigned int op_buf_1_cfg_part1;
+ unsigned int op_buf_1_cfg_part2;
+
+ unsigned int luma_qunt_table[32];
+ unsigned int chroma_qunt_table[32];
+
+ unsigned int upsamp_ip_size_cfg;
+ unsigned int upsamp_ip_frame_off;
+ unsigned int upsamp_pp_filter_coeff[64];
+} __attribute__((packed)) jpeg_cmd_enc_cfg;
+
+/*
+ * Command to configure JPEG Decoder
+ */
+
+#define JPEG_CMD_DEC_CFG 0x0001
+#define JPEG_CMD_DEC_CFG_LEN sizeof(jpeg_cmd_dec_cfg)
+
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_M 0x0001
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_H2V2 0x0000
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_H2V1 0x0001
+
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_8 0x000000
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_4 0x010000
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_2 0x020000
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_1 0x030000
+
+#define JPEG_CMD_DEC_IP_STREAM_BUF_CFG_PART3_NOT_FINAL 0x0000
+#define JPEG_CMD_DEC_IP_STREAM_BUF_CFG_PART3_FINAL 0x0001
+
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int img_dimension_cfg;
+ unsigned int op_data_format;
+ unsigned int restart_interval;
+ unsigned int ip_buf_partition_num;
+ unsigned int ip_stream_buf_cfg_part1;
+ unsigned int ip_stream_buf_cfg_part2;
+ unsigned int ip_stream_buf_cfg_part3;
+ unsigned int op_stream_buf_0_cfg_part1;
+ unsigned int op_stream_buf_0_cfg_part2;
+ unsigned int op_stream_buf_0_cfg_part3;
+ unsigned int op_stream_buf_1_cfg_part1;
+ unsigned int op_stream_buf_1_cfg_part2;
+ unsigned int op_stream_buf_1_cfg_part3;
+ unsigned int luma_qunt_table_0_3;
+ unsigned int luma_qunt_table_4_7;
+ unsigned int luma_qunt_table_8_11;
+ unsigned int luma_qunt_table_12_15;
+ unsigned int luma_qunt_table_16_19;
+ unsigned int luma_qunt_table_20_23;
+ unsigned int luma_qunt_table_24_27;
+ unsigned int luma_qunt_table_28_31;
+ unsigned int luma_qunt_table_32_35;
+ unsigned int luma_qunt_table_36_39;
+ unsigned int luma_qunt_table_40_43;
+ unsigned int luma_qunt_table_44_47;
+ unsigned int luma_qunt_table_48_51;
+ unsigned int luma_qunt_table_52_55;
+ unsigned int luma_qunt_table_56_59;
+ unsigned int luma_qunt_table_60_63;
+ unsigned int chroma_qunt_table_0_3;
+ unsigned int chroma_qunt_table_4_7;
+ unsigned int chroma_qunt_table_8_11;
+ unsigned int chroma_qunt_table_12_15;
+ unsigned int chroma_qunt_table_16_19;
+ unsigned int chroma_qunt_table_20_23;
+ unsigned int chroma_qunt_table_24_27;
+ unsigned int chroma_qunt_table_28_31;
+ unsigned int chroma_qunt_table_32_35;
+ unsigned int chroma_qunt_table_36_39;
+ unsigned int chroma_qunt_table_40_43;
+ unsigned int chroma_qunt_table_44_47;
+ unsigned int chroma_qunt_table_48_51;
+ unsigned int chroma_qunt_table_52_55;
+ unsigned int chroma_qunt_table_56_59;
+ unsigned int chroma_qunt_table_60_63;
+ unsigned int luma_dc_hm_code_cnt_table_0_3;
+ unsigned int luma_dc_hm_code_cnt_table_4_7;
+ unsigned int luma_dc_hm_code_cnt_table_8_11;
+ unsigned int luma_dc_hm_code_cnt_table_12_15;
+ unsigned int luma_dc_hm_code_val_table_0_3;
+ unsigned int luma_dc_hm_code_val_table_4_7;
+ unsigned int luma_dc_hm_code_val_table_8_11;
+ unsigned int chroma_dc_hm_code_cnt_table_0_3;
+ unsigned int chroma_dc_hm_code_cnt_table_4_7;
+ unsigned int chroma_dc_hm_code_cnt_table_8_11;
+ unsigned int chroma_dc_hm_code_cnt_table_12_15;
+ unsigned int chroma_dc_hm_code_val_table_0_3;
+ unsigned int chroma_dc_hm_code_val_table_4_7;
+ unsigned int chroma_dc_hm_code_val_table_8_11;
+ unsigned int luma_ac_hm_code_cnt_table_0_3;
+ unsigned int luma_ac_hm_code_cnt_table_4_7;
+ unsigned int luma_ac_hm_code_cnt_table_8_11;
+ unsigned int luma_ac_hm_code_cnt_table_12_15;
+ unsigned int luma_ac_hm_code_val_table_0_3;
+ unsigned int luma_ac_hm_code_val_table_4_7;
+ unsigned int luma_ac_hm_code_val_table_8_11;
+ unsigned int luma_ac_hm_code_val_table_12_15;
+ unsigned int luma_ac_hm_code_val_table_16_19;
+ unsigned int luma_ac_hm_code_val_table_20_23;
+ unsigned int luma_ac_hm_code_val_table_24_27;
+ unsigned int luma_ac_hm_code_val_table_28_31;
+ unsigned int luma_ac_hm_code_val_table_32_35;
+ unsigned int luma_ac_hm_code_val_table_36_39;
+ unsigned int luma_ac_hm_code_val_table_40_43;
+ unsigned int luma_ac_hm_code_val_table_44_47;
+ unsigned int luma_ac_hm_code_val_table_48_51;
+ unsigned int luma_ac_hm_code_val_table_52_55;
+ unsigned int luma_ac_hm_code_val_table_56_59;
+ unsigned int luma_ac_hm_code_val_table_60_63;
+ unsigned int luma_ac_hm_code_val_table_64_67;
+ unsigned int luma_ac_hm_code_val_table_68_71;
+ unsigned int luma_ac_hm_code_val_table_72_75;
+ unsigned int luma_ac_hm_code_val_table_76_79;
+ unsigned int luma_ac_hm_code_val_table_80_83;
+ unsigned int luma_ac_hm_code_val_table_84_87;
+ unsigned int luma_ac_hm_code_val_table_88_91;
+ unsigned int luma_ac_hm_code_val_table_92_95;
+ unsigned int luma_ac_hm_code_val_table_96_99;
+ unsigned int luma_ac_hm_code_val_table_100_103;
+ unsigned int luma_ac_hm_code_val_table_104_107;
+ unsigned int luma_ac_hm_code_val_table_108_111;
+ unsigned int luma_ac_hm_code_val_table_112_115;
+ unsigned int luma_ac_hm_code_val_table_116_119;
+ unsigned int luma_ac_hm_code_val_table_120_123;
+ unsigned int luma_ac_hm_code_val_table_124_127;
+ unsigned int luma_ac_hm_code_val_table_128_131;
+ unsigned int luma_ac_hm_code_val_table_132_135;
+ unsigned int luma_ac_hm_code_val_table_136_139;
+ unsigned int luma_ac_hm_code_val_table_140_143;
+ unsigned int luma_ac_hm_code_val_table_144_147;
+ unsigned int luma_ac_hm_code_val_table_148_151;
+ unsigned int luma_ac_hm_code_val_table_152_155;
+ unsigned int luma_ac_hm_code_val_table_156_159;
+ unsigned int luma_ac_hm_code_val_table_160_161;
+ unsigned int chroma_ac_hm_code_cnt_table_0_3;
+ unsigned int chroma_ac_hm_code_cnt_table_4_7;
+ unsigned int chroma_ac_hm_code_cnt_table_8_11;
+ unsigned int chroma_ac_hm_code_cnt_table_12_15;
+ unsigned int chroma_ac_hm_code_val_table_0_3;
+ unsigned int chroma_ac_hm_code_val_table_4_7;
+ unsigned int chroma_ac_hm_code_val_table_8_11;
+ unsigned int chroma_ac_hm_code_val_table_12_15;
+ unsigned int chroma_ac_hm_code_val_table_16_19;
+ unsigned int chroma_ac_hm_code_val_table_20_23;
+ unsigned int chroma_ac_hm_code_val_table_24_27;
+ unsigned int chroma_ac_hm_code_val_table_28_31;
+ unsigned int chroma_ac_hm_code_val_table_32_35;
+ unsigned int chroma_ac_hm_code_val_table_36_39;
+ unsigned int chroma_ac_hm_code_val_table_40_43;
+ unsigned int chroma_ac_hm_code_val_table_44_47;
+ unsigned int chroma_ac_hm_code_val_table_48_51;
+ unsigned int chroma_ac_hm_code_val_table_52_55;
+ unsigned int chroma_ac_hm_code_val_table_56_59;
+ unsigned int chroma_ac_hm_code_val_table_60_63;
+ unsigned int chroma_ac_hm_code_val_table_64_67;
+ unsigned int chroma_ac_hm_code_val_table_68_71;
+ unsigned int chroma_ac_hm_code_val_table_72_75;
+ unsigned int chroma_ac_hm_code_val_table_76_79;
+ unsigned int chroma_ac_hm_code_val_table_80_83;
+ unsigned int chroma_ac_hm_code_val_table_84_87;
+ unsigned int chroma_ac_hm_code_val_table_88_91;
+ unsigned int chroma_ac_hm_code_val_table_92_95;
+ unsigned int chroma_ac_hm_code_val_table_96_99;
+ unsigned int chroma_ac_hm_code_val_table_100_103;
+ unsigned int chroma_ac_hm_code_val_table_104_107;
+ unsigned int chroma_ac_hm_code_val_table_108_111;
+ unsigned int chroma_ac_hm_code_val_table_112_115;
+ unsigned int chroma_ac_hm_code_val_table_116_119;
+ unsigned int chroma_ac_hm_code_val_table_120_123;
+ unsigned int chroma_ac_hm_code_val_table_124_127;
+ unsigned int chroma_ac_hm_code_val_table_128_131;
+ unsigned int chroma_ac_hm_code_val_table_132_135;
+ unsigned int chroma_ac_hm_code_val_table_136_139;
+ unsigned int chroma_ac_hm_code_val_table_140_143;
+ unsigned int chroma_ac_hm_code_val_table_144_147;
+ unsigned int chroma_ac_hm_code_val_table_148_151;
+ unsigned int chroma_ac_hm_code_val_table_152_155;
+ unsigned int chroma_ac_hm_code_val_table_156_159;
+ unsigned int chroma_ac_hm_code_val_table_160_161;
+} __attribute__((packed)) jpeg_cmd_dec_cfg;
+
+
+/*
+ * ARM to JPEG configuration commands are passed through the
+ * uPJpegActionCmdQueue
+ */
+
+/*
+ * Command to start the encode process
+ */
+
+#define JPEG_CMD_ENC_ENCODE 0x0000
+#define JPEG_CMD_ENC_ENCODE_LEN sizeof(jpeg_cmd_enc_encode)
+
+
+typedef struct {
+ unsigned short cmd_id;
+} __attribute__((packed)) jpeg_cmd_enc_encode;
+
+
+/*
+ * Command to transition from current state of encoder to IDLE state
+ */
+
+#define JPEG_CMD_ENC_IDLE 0x0001
+#define JPEG_CMD_ENC_IDLE_LEN sizeof(jpeg_cmd_enc_idle)
+
+
+typedef struct {
+ unsigned short cmd_id;
+} __attribute__((packed)) jpeg_cmd_enc_idle;
+
+
+/*
+ * Command to inform the encoder that another buffer is ready
+ */
+
+#define JPEG_CMD_ENC_OP_CONSUMED 0x0002
+#define JPEG_CMD_ENC_OP_CONSUMED_LEN sizeof(jpeg_cmd_enc_op_consumed)
+
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int op_buf_addr;
+ unsigned int op_buf_size;
+} __attribute__((packed)) jpeg_cmd_enc_op_consumed;
+
+
+/*
+ * Command to start the decoding process
+ */
+
+#define JPEG_CMD_DEC_DECODE 0x0003
+#define JPEG_CMD_DEC_DECODE_LEN sizeof(jpeg_cmd_dec_decode)
+
+
+typedef struct {
+ unsigned short cmd_id;
+} __attribute__((packed)) jpeg_cmd_dec_decode;
+
+
+/*
+ * Command to transition from the current state of decoder to IDLE
+ */
+
+#define JPEG_CMD_DEC_IDLE 0x0004
+#define JPEG_CMD_DEC_IDLE_LEN sizeof(jpeg_cmd_dec_idle)
+
+
+typedef struct {
+ unsigned short cmd_id;
+} __attribute__((packed)) jpeg_cmd_dec_idle;
+
+
+/*
+ * Command to inform that an op buffer is ready for use
+ */
+
+#define JPEG_CMD_DEC_OP_CONSUMED 0x0005
+#define JPEG_CMD_DEC_OP_CONSUMED_LEN sizeof(jpeg_cmd_dec_op_consumed)
+
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int luma_op_buf_addr;
+ unsigned int luma_op_buf_size;
+ unsigned int chroma_op_buf_addr;
+} __attribute__((packed)) jpeg_cmd_dec_op_consumed;
+
+
+/*
+ * Command to pass a new ip buffer to the jpeg decoder
+ */
+
+#define JPEG_CMD_DEC_IP 0x0006
+#define JPEG_CMD_DEC_IP_LEN sizeof(jpeg_cmd_dec_ip_len)
+
+#define JPEG_CMD_EOI_INDICATOR_NOT_END 0x0000
+#define JPEG_CMD_EOI_INDICATOR_END 0x0001
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int ip_buf_addr;
+ unsigned int ip_buf_size;
+ unsigned int eoi_indicator;
+} __attribute__((packed)) jpeg_cmd_dec_ip;
+
+
+
+#endif
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5jpegmsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5jpegmsg.h
new file mode 100644
index 000000000000..d11aa3fbccb6
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5jpegmsg.h
@@ -0,0 +1,177 @@
+#ifndef QDSP5VIDJPEGMSGI_H
+#define QDSP5VIDJPEGMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ J P E G I N T E R N A L M E S S A G E S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of messages
+ that are sent by JPEG Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5jpegmsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when who what, where, why
+-------- --- ----------------------------------------------------------
+05/10/08 sv initial version
+===========================================================================*/
+
+/*
+ * Messages from JPEG task to ARM through jpeguPMsgQueue
+ */
+
+/*
+ * Message is ACK for CMD_JPEGE_ENCODE cmd
+ */
+
+#define JPEG_MSG_ENC_ENCODE_ACK 0x0000
+#define JPEG_MSG_ENC_ENCODE_ACK_LEN \
+ sizeof(jpeg_msg_enc_encode_ack)
+
+typedef struct {
+} __attribute__((packed)) jpeg_msg_enc_encode_ack;
+
+
+/*
+ * Message informs the up when op buffer is ready for consumption and
+ * when encoding is complete or errors
+ */
+
+#define JPEG_MSG_ENC_OP_PRODUCED 0x0001
+#define JPEG_MSG_ENC_OP_PRODUCED_LEN \
+ sizeof(jpeg_msg_enc_op_produced)
+
+#define JPEG_MSGOP_OP_BUF_STATUS_ENC_DONE_PROGRESS 0x0000
+#define JPEG_MSGOP_OP_BUF_STATUS_ENC_DONE_COMPLETE 0x0001
+#define JPEG_MSGOP_OP_BUF_STATUS_ENC_ERR 0x10000
+
+typedef struct {
+ unsigned int op_buf_addr;
+ unsigned int op_buf_size;
+ unsigned int op_buf_status;
+} __attribute__((packed)) jpeg_msg_enc_op_produced;
+
+
+/*
+ * Message to ack CMD_JPEGE_IDLE
+ */
+
+#define JPEG_MSG_ENC_IDLE_ACK 0x0002
+#define JPEG_MSG_ENC_IDLE_ACK_LEN sizeof(jpeg_msg_enc_idle_ack)
+
+
+typedef struct {
+} __attribute__ ((packed)) jpeg_msg_enc_idle_ack;
+
+
+/*
+ * Message to indicate the illegal command
+ */
+
+#define JPEG_MSG_ENC_ILLEGAL_COMMAND 0x0003
+#define JPEG_MSG_ENC_ILLEGAL_COMMAND_LEN \
+ sizeof(jpeg_msg_enc_illegal_command)
+
+typedef struct {
+ unsigned int status;
+} __attribute__((packed)) jpeg_msg_enc_illegal_command;
+
+
+/*
+ * Message to ACK CMD_JPEGD_DECODE
+ */
+
+#define JPEG_MSG_DEC_DECODE_ACK 0x0004
+#define JPEG_MSG_DEC_DECODE_ACK_LEN \
+ sizeof(jpeg_msg_dec_decode_ack)
+
+
+typedef struct {
+} __attribute__((packed)) jpeg_msg_dec_decode_ack;
+
+
+/*
+ * Message to inform up that an op buffer is ready for consumption and when
+ * decoding is complete or an error occurs
+ */
+
+#define JPEG_MSG_DEC_OP_PRODUCED 0x0005
+#define JPEG_MSG_DEC_OP_PRODUCED_LEN \
+ sizeof(jpeg_msg_dec_op_produced)
+
+#define JPEG_MSG_DEC_OP_BUF_STATUS_PROGRESS 0x0000
+#define JPEG_MSG_DEC_OP_BUF_STATUS_DONE 0x0001
+
+typedef struct {
+ unsigned int luma_op_buf_addr;
+ unsigned int chroma_op_buf_addr;
+ unsigned int num_mcus;
+ unsigned int op_buf_status;
+} __attribute__((packed)) jpeg_msg_dec_op_produced;
+
+/*
+ * Message to ack CMD_JPEGD_IDLE cmd
+ */
+
+#define JPEG_MSG_DEC_IDLE_ACK 0x0006
+#define JPEG_MSG_DEC_IDLE_ACK_LEN sizeof(jpeg_msg_dec_idle_ack)
+
+
+typedef struct {
+} __attribute__((packed)) jpeg_msg_dec_idle_ack;
+
+
+/*
+ * Message to indicate illegal cmd was received
+ */
+
+#define JPEG_MSG_DEC_ILLEGAL_COMMAND 0x0007
+#define JPEG_MSG_DEC_ILLEGAL_COMMAND_LEN \
+ sizeof(jpeg_msg_dec_illegal_command)
+
+
+typedef struct {
+ unsigned int status;
+} __attribute__((packed)) jpeg_msg_dec_illegal_command;
+
+/*
+ * Message to request up for the next segment of ip bit stream
+ */
+
+#define JPEG_MSG_DEC_IP_REQUEST 0x0008
+#define JPEG_MSG_DEC_IP_REQUEST_LEN \
+ sizeof(jpeg_msg_dec_ip_request)
+
+
+typedef struct {
+} __attribute__((packed)) jpeg_msg_dec_ip_request;
+
+
+
+#endif
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5lpmcmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5lpmcmdi.h
new file mode 100644
index 000000000000..6c76e2c20cf4
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5lpmcmdi.h
@@ -0,0 +1,82 @@
+#ifndef QDSP5LPMCMDI_H
+#define QDSP5LPMCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ L P M I N T E R N A L C O M M A N D S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of commands
+ that are accepted by LPM Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5lpmcmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when who what, where, why
+-------- --- ----------------------------------------------------------
+06/12/08 sv initial version
+===========================================================================*/
+
+
+/*
+ * Command to start LPM processing based on the config params
+ */
+
+#define LPM_CMD_START 0x0000
+#define LPM_CMD_START_LEN sizeof(lpm_cmd_start)
+
+#define LPM_CMD_SPATIAL_FILTER_PART_OPMODE_0 0x00000000
+#define LPM_CMD_SPATIAL_FILTER_PART_OPMODE_1 0x00010000
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int ip_data_cfg_part1;
+ unsigned int ip_data_cfg_part2;
+ unsigned int ip_data_cfg_part3;
+ unsigned int ip_data_cfg_part4;
+ unsigned int op_data_cfg_part1;
+ unsigned int op_data_cfg_part2;
+ unsigned int op_data_cfg_part3;
+ unsigned int spatial_filter_part[32];
+} __attribute__((packed)) lpm_cmd_start;
+
+
+
+/*
+ * Command to stop LPM processing
+ */
+
+#define LPM_CMD_IDLE 0x0001
+#define LPM_CMD_IDLE_LEN sizeof(lpm_cmd_idle)
+
+typedef struct {
+ unsigned int cmd_id;
+} __attribute__((packed)) lpm_cmd_idle;
+
+
+#endif
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5lpmmsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5lpmmsg.h
new file mode 100644
index 000000000000..3d1039d6ba42
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5lpmmsg.h
@@ -0,0 +1,80 @@
+#ifndef QDSP5LPMMSGI_H
+#define QDSP5LPMMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ L P M I N T E R N A L M E S S A G E S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of commands
+ that are accepted by LPM Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5lpmmsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when who what, where, why
+-------- --- ----------------------------------------------------------
+06/12/08 sv initial version
+===========================================================================*/
+
+/*
+ * Message to acknowledge CMD_LPM_IDLE command
+ */
+
+#define LPM_MSG_IDLE_ACK 0x0000
+#define LPM_MSG_IDLE_ACK_LEN sizeof(lpm_msg_idle_ack)
+
+typedef struct {
+} __attribute__((packed)) lpm_msg_idle_ack;
+
+
+/*
+ * Message to acknowledge CMD_LPM_START command
+ */
+
+
+#define LPM_MSG_START_ACK 0x0001
+#define LPM_MSG_START_ACK_LEN sizeof(lpm_msg_start_ack)
+
+
+typedef struct {
+} __attribute__((packed)) lpm_msg_start_ack;
+
+
+/*
+ * Message to notify the ARM that LPM processing is complete
+ */
+
+#define LPM_MSG_DONE 0x0002
+#define LPM_MSG_DONE_LEN sizeof(lpm_msg_done)
+
+typedef struct {
+} __attribute__((packed)) lpm_msg_done;
+
+
+#endif
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5vdeccmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5vdeccmdi.h
new file mode 100644
index 000000000000..3a32ee99c6e4
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5vdeccmdi.h
@@ -0,0 +1,235 @@
+#ifndef QDSP5VIDDECCMDI_H
+#define QDSP5VIDDECCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ V I D E O D E C O D E R I N T E R N A L C O M M A N D S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of commands
+ that are accepted by VIDDEC Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vdeccmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when who what, where, why
+-------- --- ----------------------------------------------------------
+05/10/08 ac initial version
+===========================================================================*/
+
+
+/*
+ * Command to inform VIDDEC that new subframe packet is ready
+ */
+
+#define VIDDEC_CMD_SUBFRAME_PKT 0x0000
+#define VIDDEC_CMD_SUBFRAME_PKT_LEN \
+ sizeof(viddec_cmd_subframe_pkt)
+
+#define VIDDEC_CMD_SF_INFO_1_DM_DMA_STATS_EXCHANGE_FLAG_DM 0x0000
+#define VIDDEC_CMD_SF_INFO_1_DM_DMA_STATS_EXCHANGE_FLAG_DMA 0x0001
+
+#define VIDDEC_CMD_SF_INFO_0_SUBFRAME_CONTI 0x0000
+#define VIDDEC_CMD_SF_INFO_0_SUBFRAME_FIRST 0x0001
+#define VIDDEC_CMD_SF_INFO_0_SUBFRAME_LAST 0x0002
+#define VIDDEC_CMD_SF_INFO_0_SUBFRAME_FIRST_AND_LAST 0x0003
+
+#define VIDDEC_CMD_CODEC_SELECTION_WORD_MPEG_4 0x0000
+#define VIDDEC_CMD_CODEC_SELECTION_WORD_H_263_P0 0x0001
+#define VIDDEC_CMD_CODEC_SELECTION_WORD_H_264 0x0002
+#define VIDDEC_CMD_CODEC_SELECTION_WORD_H_263_p3 0x0003
+#define VIDDEC_CMD_CODEC_SELECTION_WORD_RV9 0x0004
+#define VIDDEC_CMD_CODEC_SELECTION_WORD_WMV9 0x0005
+#define VIDDEC_CMD_CODEC_SELECTION_WORD_SMCDB 0x0006
+#define VIDDEC_CMD_CODEC_SELECTION_WORD_QFRE 0x0007
+#define VIDDEC_CMD_CODEC_SELECTION_WORD_VLD 0x0008
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short packet_seq_number;
+ unsigned short codec_instance_id;
+ unsigned short subframe_packet_size_high;
+ unsigned short subframe_packet_size_low;
+ unsigned short subframe_packet_high;
+ unsigned short subframe_packet_low;
+ unsigned short subframe_packet_partition;
+ unsigned short statistics_packet_size_high;
+ unsigned short statistics_packet_size_low;
+ unsigned short statistics_packet_high;
+ unsigned short statistics_packet_low;
+ unsigned short statistics_partition;
+ unsigned short subframe_info_1;
+ unsigned short subframe_info_0;
+ unsigned short codec_selection_word;
+ unsigned short num_mbs;
+} __attribute__((packed)) viddec_cmd_subframe_pkt;
+
+
+/*
+ * Command to inform VIDDEC task that post processing is required for the frame
+ */
+
+#define VIDDEC_CMD_PP_ENABLE 0x0001
+#define VIDDEC_CMD_PP_ENABLE_LEN \
+ sizeof(viddec_cmd_pp_enable)
+
+#define VIDDEC_CMD_PP_INFO_0_DM_DMA_LS_EXCHANGE_FLAG_DM 0x0000
+#define VIDDEC_CMD_PP_INFO_0_DM_DMA_LS_EXCHANGE_FLAG_DMA 0x0001
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short packet_seq_num;
+ unsigned short codec_instance_id;
+ unsigned short postproc_info_0;
+ unsigned short codec_selection_word;
+ unsigned short pp_output_addr_high;
+ unsigned short pp_output_addr_low;
+ unsigned short postproc_info_1;
+ unsigned short load_sharing_packet_size_high;
+ unsigned short load_sharing_packet_size_low;
+ unsigned short load_sharing_packet_high;
+ unsigned short load_sharing_packet_low;
+ unsigned short load_sharing_partition;
+ unsigned short pp_param_0;
+ unsigned short pp_param_1;
+ unsigned short pp_param_2;
+ unsigned short pp_param_3;
+} __attribute__((packed)) viddec_cmd_pp_enable;
+
+
+/*
+ * FRAME Header Packet : It is at the start of new frame
+ */
+
+#define VIDDEC_CMD_FRAME_HEADER_PACKET 0x0002
+#define VIDDEC_CMD_FRAME_HEADER_PACKET_LEN \
+ sizeof(viddec_cmd_frame_header_packet)
+
+#define VIDDEC_CMD_FRAME_INFO_0_ERROR_SKIP 0x0000
+#define VIDDEC_CMD_FRAME_INFO_0_ERROR_BLACK 0x0800
+
+typedef struct {
+ unsigned short packet_id;
+ unsigned short x_dimension;
+ unsigned short y_dimension;
+ unsigned short line_width;
+ unsigned short frame_info_0;
+ unsigned short frame_buffer_0_high;
+ unsigned short frame_buffer_0_low;
+ unsigned short frame_buffer_1_high;
+ unsigned short frame_buffer_1_low;
+ unsigned short frame_buffer_2_high;
+ unsigned short frame_buffer_2_low;
+ unsigned short frame_buffer_3_high;
+ unsigned short frame_buffer_3_low;
+ unsigned short frame_buffer_4_high;
+ unsigned short frame_buffer_4_low;
+ unsigned short frame_buffer_5_high;
+ unsigned short frame_buffer_5_low;
+ unsigned short frame_buffer_6_high;
+ unsigned short frame_buffer_6_low;
+ unsigned short frame_buffer_7_high;
+ unsigned short frame_buffer_7_low;
+ unsigned short frame_buffer_8_high;
+ unsigned short frame_buffer_8_low;
+ unsigned short frame_buffer_9_high;
+ unsigned short frame_buffer_9_low;
+ unsigned short frame_buffer_10_high;
+ unsigned short frame_buffer_10_low;
+ unsigned short frame_buffer_11_high;
+ unsigned short frame_buffer_11_low;
+ unsigned short frame_buffer_12_high;
+ unsigned short frame_buffer_12_low;
+ unsigned short frame_buffer_13_high;
+ unsigned short frame_buffer_13_low;
+ unsigned short frame_buffer_14_high;
+ unsigned short frame_buffer_14_low;
+ unsigned short frame_buffer_15_high;
+ unsigned short frame_buffer_15_low;
+ unsigned short output_frame_buffer_high;
+ unsigned short output_frame_buffer_low;
+ unsigned short end_of_packet_marker;
+} __attribute__((packed)) viddec_cmd_frame_header_packet;
+
+
+/*
+ * SLICE HEADER PACKET
+ * I-Slice and P-Slice
+ */
+
+#define VIDDEC_CMD_SLICE_HEADER_PKT_ISLICE 0x0003
+#define VIDDEC_CMD_SLICE_HEADER_PKT_ISLICE_LEN \
+ sizeof(viddec_cmd_slice_header_pkt_islice)
+
+#define VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_PSLICE 0x0000
+#define VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_BSLICE 0x0100
+#define VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_ISLICE 0x0200
+#define VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_SPSLICE 0x0300
+#define VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_SISLICE 0x0400
+#define VIDDEC_CMD_ISLICE_INFO_1_NOPADDING 0x0000
+#define VIDDEC_CMD_ISLICE_INFO_1_PADDING 0x0800
+
+#define VIDDEC_CMD_ISLICE_EOP_MARKER 0x7FFF
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short packet_id;
+ unsigned short slice_info_0;
+ unsigned short slice_info_1;
+ unsigned short slice_info_2;
+ unsigned short num_bytes_in_rbsp_high;
+ unsigned short num_bytes_in_rbsp_low;
+ unsigned short num_bytes_in_rbsp_consumed;
+ unsigned short end_of_packet_marker;
+} __attribute__((packed)) viddec_cmd_slice_header_pkt_islice;
+
+
+#define VIDDEC_CMD_SLICE_HEADER_PKT_PSLICE 0x0003
+#define VIDDEC_CMD_SLICE_HEADER_PKT_PSLICE_LEN \
+ sizeof(viddec_cmd_slice_header_pkt_pslice)
+
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short packet_id;
+ unsigned short slice_info_0;
+ unsigned short slice_info_1;
+ unsigned short slice_info_2;
+ unsigned short slice_info_3;
+ unsigned short refidx_l0_map_tab_info_0;
+ unsigned short refidx_l0_map_tab_info_1;
+ unsigned short refidx_l0_map_tab_info_2;
+ unsigned short refidx_l0_map_tab_info_3;
+ unsigned short num_bytes_in_rbsp_high;
+ unsigned short num_bytes_in_rbsp_low;
+ unsigned short num_bytes_in_rbsp_consumed;
+ unsigned short end_of_packet_marker;
+} __attribute__((packed)) viddec_cmd_slice_header_pkt_pslice;
+
+
+#endif
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5vdecmsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5vdecmsg.h
new file mode 100644
index 000000000000..c1744c1644dd
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5vdecmsg.h
@@ -0,0 +1,107 @@
+#ifndef QDSP5VIDDECMSGI_H
+#define QDSP5VIDDECMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ V I D E O D E C O D E R I N T E R N A L M E S S A G E S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of messages
+ that are sent by VIDDEC Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vdecmsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when who what, where, why
+-------- --- ----------------------------------------------------------
+05/10/08 ac initial version
+===========================================================================*/
+
+/*
+ * Message to inform ARM which VDEC_SUBFRAME_PKT_CMD processed by VIDDEC TASK
+ */
+
+#define VIDDEC_MSG_SUBF_DONE 0x0000
+#define VIDDEC_MSG_SUBF_DONE_LEN \
+ sizeof(viddec_msg_subf_done)
+
+typedef struct {
+ unsigned short packet_seq_number;
+ unsigned short codec_instance_id;
+} __attribute__((packed)) viddec_msg_subf_done;
+
+
+/*
+ * Message to inform ARM one frame has been decoded
+ */
+
+#define VIDDEC_MSG_FRAME_DONE 0x0001
+#define VIDDEC_MSG_FRAME_DONE_LEN \
+ sizeof(viddec_msg_frame_done)
+
+typedef struct {
+ unsigned short packet_seq_number;
+ unsigned short codec_instance_id;
+} __attribute__((packed)) viddec_msg_frame_done;
+
+
+/*
+ * Message to inform ARM that post processing frame has been decoded
+ */
+
+#define VIDDEC_MSG_PP_ENABLE_CMD_DONE 0x0002
+#define VIDDEC_MSG_PP_ENABLE_CMD_DONE_LEN \
+ sizeof(viddec_msg_pp_enable_cmd_done)
+
+typedef struct {
+ unsigned short packet_seq_number;
+ unsigned short codec_instance_id;
+} __attribute__((packed)) viddec_msg_pp_enable_cmd_done;
+
+
+/*
+ * Message to inform ARM that one post processing frame has been decoded
+ */
+
+
+#define VIDDEC_MSG_PP_FRAME_DONE 0x0003
+#define VIDDEC_MSG_PP_FRAME_DONE_LEN \
+ sizeof(viddec_msg_pp_frame_done)
+
+#define VIDDEC_MSG_DISP_WORTHY_DISP 0x0000
+#define VIDDEC_MSG_DISP_WORTHY_DISP_NONE 0xFFFF
+
+
+typedef struct {
+ unsigned short packet_seq_number;
+ unsigned short codec_instance_id;
+ unsigned short display_worthy;
+} __attribute__((packed)) viddec_msg_pp_frame_done;
+
+
+#endif
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5venccmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5venccmdi.h
new file mode 100644
index 000000000000..819544d186da
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5venccmdi.h
@@ -0,0 +1,212 @@
+#ifndef QDSP5VIDENCCMDI_H
+#define QDSP5VIDENCCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ V I D E O E N C O D E R I N T E R N A L C O M M A N D S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of commands
+ that are accepted by VIDENC Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 2008 by QUALCOMM, Incorporated.
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+Revision History:
+
+when who what, where, why
+-------- --- ----------------------------------------------------------
+09/25/08 umeshp initial version
+===========================================================================*/
+
+ #define VIDENC_CMD_CFG 0x0000
+ #define VIDENC_CMD_ACTIVE 0x0001
+ #define VIDENC_CMD_IDLE 0x0002
+ #define VIDENC_CMD_FRAME_START 0x0003
+ #define VIDENC_CMD_STATUS_QUERY 0x0004
+ #define VIDENC_CMD_RC_CFG 0x0005
+ #define VIDENC_CMD_DIS_CFG 0x0006
+ #define VIDENC_CMD_DIS 0x0007
+ #define VIDENC_CMD_INTRA_REFRESH 0x0008
+ #define VIDENC_CMD_DIGITAL_ZOOM 0x0009
+
+
+/*
+ * Command to pass the frame message information to VIDENC
+ */
+
+
+#define VIDENC_CMD_FRAME_START_LEN \
+ sizeof(videnc_cmd_frame_start)
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short frame_info;
+ unsigned short frame_rho_budget_word_high;
+ unsigned short frame_rho_budget_word_low;
+ unsigned short input_luma_addr_high;
+ unsigned short input_luma_addr_low;
+ unsigned short input_chroma_addr_high;
+ unsigned short input_chroma_addr_low;
+ unsigned short ref_vop_buf_ptr_high;
+ unsigned short ref_vop_buf_ptr_low;
+ unsigned short enc_pkt_buf_ptr_high;
+ unsigned short enc_pkt_buf_ptr_low;
+ unsigned short enc_pkt_buf_size_high;
+ unsigned short enc_pkt_buf_size_low;
+ unsigned short unfilt_recon_vop_buf_ptr_high;
+ unsigned short unfilt_recon_vop_buf_ptr_low;
+ unsigned short filt_recon_vop_buf_ptr_high;
+ unsigned short filt_recon_vop_buf_ptr_low;
+} __attribute__((packed)) videnc_cmd_frame_start;
+
+/*
+ * Command to pass the frame-level digital stabilization parameters to VIDENC
+ */
+
+
+#define VIDENC_CMD_DIS_LEN \
+ sizeof(videnc_cmd_dis)
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short vfe_out_prev_luma_addr_high;
+ unsigned short vfe_out_prev_luma_addr_low;
+ unsigned short stabilization_info;
+} __attribute__((packed)) videnc_cmd_dis;
+
+/*
+ * Command to pass the codec related parameters to VIDENC
+ */
+
+
+#define VIDENC_CMD_CFG_LEN \
+ sizeof(videnc_cmd_cfg)
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short cfg_info_0;
+ unsigned short cfg_info_1;
+ unsigned short four_mv_threshold;
+ unsigned short ise_fse_mv_cost_fac;
+ unsigned short venc_frame_dim;
+ unsigned short venc_DM_partition;
+} __attribute__((packed)) videnc_cmd_cfg;
+
+/*
+ * Command to start the video encoding
+ */
+
+
+#define VIDENC_CMD_ACTIVE_LEN \
+ sizeof(videnc_cmd_active)
+
+typedef struct {
+ unsigned short cmd_id;
+} __attribute__((packed)) videnc_cmd_active;
+
+/*
+ * Command to stop the video encoding
+ */
+
+
+#define VIDENC_CMD_IDLE_LEN \
+ sizeof(videnc_cmd_idle)
+
+typedef struct {
+ unsigned short cmd_id;
+} __attribute__((packed)) videnc_cmd_idle;
+
+/*
+ * Command to query staus of VIDENC
+ */
+
+
+#define VIDENC_CMD_STATUS_QUERY_LEN \
+ sizeof(videnc_cmd_status_query)
+
+typedef struct {
+ unsigned short cmd_id;
+} __attribute__((packed)) videnc_cmd_status_query;
+
+/*
+ * Command to set rate control for a frame
+ */
+
+
+#define VIDENC_CMD_RC_CFG_LEN \
+ sizeof(videnc_cmd_rc_cfg)
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short max_frame_qp_delta;
+ unsigned short max_min_frame_qp;
+} __attribute__((packed)) videnc_cmd_rc_cfg;
+
+/*
+ * Command to set intra-refreshing
+ */
+
+
+#define VIDENC_CMD_INTRA_REFRESH_LEN \
+ sizeof(videnc_cmd_intra_refresh)
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short num_mb_refresh;
+ unsigned short mb_index[15];
+} __attribute__((packed)) videnc_cmd_intra_refresh;
+
+/*
+ * Command to pass digital zoom information to the VIDENC
+ */
+#define VIDENC_CMD_DIGITAL_ZOOM_LEN \
+ sizeof(videnc_cmd_digital_zoom)
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short digital_zoom_en;
+ unsigned short luma_frame_shift_X;
+ unsigned short luma_frame_shift_Y;
+ unsigned short up_ip_luma_rows;
+ unsigned short up_ip_luma_cols;
+ unsigned short up_ip_chroma_rows;
+ unsigned short up_ip_chroma_cols;
+ unsigned short luma_ph_incr_V_low;
+ unsigned short luma_ph_incr_V_high;
+ unsigned short luma_ph_incr_H_low;
+ unsigned short luma_ph_incr_H_high;
+ unsigned short chroma_ph_incr_V_low;
+ unsigned short chroma_ph_incr_V_high;
+ unsigned short chroma_ph_incr_H_low;
+ unsigned short chroma_ph_incr_H_high;
+} __attribute__((packed)) videnc_cmd_digital_zoom;
+
+/*
+ * Command to configure digital stabilization parameters
+ */
+
+#define VIDENC_CMD_DIS_CFG_LEN \
+ sizeof(videnc_cmd_dis_cfg)
+
+typedef struct {
+ unsigned short cmd_id;
+ unsigned short image_stab_subf_start_row_col;
+ unsigned short image_stab_subf_dim;
+ unsigned short image_stab_info_0;
+} __attribute__((packed)) videnc_cmd_dis_cfg;
+
+
+#endif
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5vfecmdi.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5vfecmdi.h
new file mode 100644
index 000000000000..55e8fc2269f7
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5vfecmdi.h
@@ -0,0 +1,910 @@
+#ifndef QDSP5VFECMDI_H
+#define QDSP5VFECMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ V F E I N T E R N A L C O M M A N D S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of commands
+ that are accepted by VFE Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vfecmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when who what, where, why
+-------- --- ----------------------------------------------------------
+06/12/08 sv initial version
+===========================================================================*/
+
+/******************************************************************************
+ * Commands through vfeCommandScaleQueue
+ *****************************************************************************/
+
+/*
+ * Command to program scaler for op1 . max op of scaler is VGA
+ */
+
+
+#define VFE_CMD_SCALE_OP1_CFG 0x0000
+#define VFE_CMD_SCALE_OP1_CFG_LEN \
+ sizeof(vfe_cmd_scale_op1_cfg)
+
+#define VFE_CMD_SCALE_OP1_SEL_IP_SEL_Y_STANDARD 0x0000
+#define VFE_CMD_SCALE_OP1_SEL_IP_SEL_Y_CASCADED 0x0001
+#define VFE_CMD_SCALE_OP1_SEL_H_Y_SCALER_DIS 0x0000
+#define VFE_CMD_SCALE_OP1_SEL_H_Y_SCALER_ENA 0x0002
+#define VFE_CMD_SCALE_OP1_SEL_H_PP_Y_SCALER_DIS 0x0000
+#define VFE_CMD_SCALE_OP1_SEL_H_PP_Y_SCALER_ENA 0x0004
+#define VFE_CMD_SCALE_OP1_SEL_V_Y_SCALER_DIS 0x0000
+#define VFE_CMD_SCALE_OP1_SEL_V_Y_SCALER_ENA 0x0008
+#define VFE_CMD_SCALE_OP1_SEL_V_PP_Y_SCALER_DIS 0x0000
+#define VFE_CMD_SCALE_OP1_SEL_V_PP_Y_SCALER_ENA 0x0010
+#define VFE_CMD_SCALE_OP1_SEL_IP_SEL_CBCR_STANDARD 0x0000
+#define VFE_CMD_SCALE_OP1_SEL_IP_SEL_CBCR_CASCADED 0x0020
+#define VFE_CMD_SCALE_OP1_SEL_H_CBCR_SCALER_DIS 0x0000
+#define VFE_CMD_SCALE_OP1_SEL_H_CBCR_SCALER_ENA 0x0040
+#define VFE_CMD_SCALE_OP1_SEL_V_CBCR_SCALER_DIS 0x0000
+#define VFE_CMD_SCALE_OP1_SEL_V_CBCR_SCALER_ENA 0x0080
+
+#define VFE_CMD_OP1_PP_Y_SCALER_CFG_PART1_DONT_LOAD_COEFFS 0x80000000
+#define VFE_CMD_OP1_PP_Y_SCALER_CFG_PART1_LOAD_COEFFS 0x80000000
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int scale_op1_sel;
+ unsigned int y_scaler_cfg_part1;
+ unsigned int y_scaler_cfg_part2;
+ unsigned int cbcr_scaler_cfg_part1;
+ unsigned int cbcr_scaler_cfg_part2;
+ unsigned int cbcr_scaler_cfg_part3;
+ unsigned int pp_y_scaler_cfg_part1;
+ unsigned int pp_y_scaler_cfg_part2;
+ unsigned int y_scaler_v_coeff_bank_part1[16];
+ unsigned int y_scaler_v_coeff_bank_part2[16];
+ unsigned int y_scaler_h_coeff_bank_part1[16];
+ unsigned int y_scaler_h_coeff_bank_part2[16];
+} __attribute__((packed)) vfe_cmd_scale_op1_cfg;
+
+
+/*
+ * Command to program scaler for op2
+ */
+
+#define VFE_CMD_SCALE_OP2_CFG 0x0001
+#define VFE_CMD_SCALE_OP2_CFG_LEN \
+ sizeof(vfe_cmd_scale_op2_cfg)
+
+#define VFE_CMD_SCALE_OP2_SEL_IP_SEL_Y_STANDARD 0x0000
+#define VFE_CMD_SCALE_OP2_SEL_IP_SEL_Y_CASCADED 0x0001
+#define VFE_CMD_SCALE_OP2_SEL_H_Y_SCALER_DIS 0x0000
+#define VFE_CMD_SCALE_OP2_SEL_H_Y_SCALER_ENA 0x0002
+#define VFE_CMD_SCALE_OP2_SEL_H_PP_Y_SCALER_DIS 0x0000
+#define VFE_CMD_SCALE_OP2_SEL_H_PP_Y_SCALER_ENA 0x0004
+#define VFE_CMD_SCALE_OP2_SEL_V_Y_SCALER_DIS 0x0000
+#define VFE_CMD_SCALE_OP2_SEL_V_Y_SCALER_ENA 0x0008
+#define VFE_CMD_SCALE_OP2_SEL_V_PP_Y_SCALER_DIS 0x0000
+#define VFE_CMD_SCALE_OP2_SEL_V_PP_Y_SCALER_ENA 0x0010
+#define VFE_CMD_SCALE_OP2_SEL_IP_SEL_CBCR_STANDARD 0x0000
+#define VFE_CMD_SCALE_OP2_SEL_IP_SEL_CBCR_CASCADED 0x0020
+#define VFE_CMD_SCALE_OP2_SEL_H_CBCR_SCALER_DIS 0x0000
+#define VFE_CMD_SCALE_OP2_SEL_H_CBCR_SCALER_ENA 0x0040
+#define VFE_CMD_SCALE_OP2_SEL_V_CBCR_SCALER_DIS 0x0000
+#define VFE_CMD_SCALE_OP2_SEL_V_CBCR_SCALER_ENA 0x0080
+
+#define VFE_CMD_OP2_PP_Y_SCALER_CFG_PART1_DONT_LOAD_COEFFS 0x80000000
+#define VFE_CMD_OP2_PP_Y_SCALER_CFG_PART1_LOAD_COEFFS 0x80000000
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int scale_op2_sel;
+ unsigned int y_scaler_cfg_part1;
+ unsigned int y_scaler_cfg_part2;
+ unsigned int cbcr_scaler_cfg_part1;
+ unsigned int cbcr_scaler_cfg_part2;
+ unsigned int cbcr_scaler_cfg_part3;
+ unsigned int pp_y_scaler_cfg_part1;
+ unsigned int pp_y_scaler_cfg_part2;
+ unsigned int y_scaler_v_coeff_bank_part1[16];
+ unsigned int y_scaler_v_coeff_bank_part2[16];
+ unsigned int y_scaler_h_coeff_bank_part1[16];
+ unsigned int y_scaler_h_coeff_bank_part2[16];
+} __attribute__((packed)) vfe_cmd_scale_op2_cfg;
+
+
+/******************************************************************************
+ * Commands through vfeCommandTableQueue
+ *****************************************************************************/
+
+/*
+ * Command to program the AXI ip paths
+ */
+
+#define VFE_CMD_AXI_IP_CFG 0x0000
+#define VFE_CMD_AXI_IP_CFG_LEN sizeof(vfe_cmd_axi_ip_cfg)
+
+#define VFE_CMD_IP_SEL_IP_FORMAT_8 0x0000
+#define VFE_CMD_IP_SEL_IP_FORMAT_10 0x0001
+#define VFE_CMD_IP_SEL_IP_FORMAT_12 0x0002
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int ip_sel;
+ unsigned int ip_cfg_part1;
+ unsigned int ip_cfg_part2;
+ unsigned int ip_unpack_cfg_part[6];
+ unsigned int ip_buf_addr[8];
+} __attribute__ ((packed)) vfe_cmd_axi_ip_cfg;
+
+
+/*
+ * Command to program axi op paths
+ */
+
+#define VFE_CMD_AXI_OP_CFG 0x0001
+#define VFE_CMD_AXI_OP_CFG_LEN sizeof(vfe_cmd_axi_op_cfg)
+
+#define VFE_CMD_OP_SEL_OP1 0x0000
+#define VFE_CMD_OP_SEL_OP2 0x0001
+#define VFE_CMD_OP_SEL_OP1_OP2 0x0002
+#define VFE_CMD_OP_SEL_CTOA 0x0003
+#define VFE_CMD_OP_SEL_CTOA_OP1 0x0004
+#define VFE_CMD_OP_SEL_CTOA_OP2 0x0005
+#define VFE_CMD_OP_SEL_OP_FORMAT_8 0x0000
+#define VFE_CMD_OP_SEL_OP_FORMAT_10 0x0008
+#define VFE_CMD_OP_SEL_OP_FORMAT_12 0x0010
+
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int op_sel;
+ unsigned int op1_y_cfg_part1;
+ unsigned int op1_y_cfg_part2;
+ unsigned int op1_cbcr_cfg_part1;
+ unsigned int op1_cbcr_cfg_part2;
+ unsigned int op2_y_cfg_part1;
+ unsigned int op2_y_cfg_part2;
+ unsigned int op2_cbcr_cfg_part1;
+ unsigned int op2_cbcr_cfg_part2;
+ unsigned int op1_buf1_addr[16];
+ unsigned int op2_buf1_addr[16];
+} __attribute__((packed)) vfe_cmd_axi_op_cfg;
+
+
+
+
+/*
+ * Command to program the roll off correction module
+ */
+
+#define VFE_CMD_ROLLOFF_CFG 0x0002
+#define VFE_CMD_ROLLOFF_CFG_LEN \
+ sizeof(vfe_cmd_rolloff_cfg)
+
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int correction_opt_center_pos;
+ unsigned int radius_square_entry[32];
+ unsigned int red_table_entry[32];
+ unsigned int green_table_entry[32];
+ unsigned int blue_table_entry[32];
+} __attribute__((packed)) vfe_cmd_rolloff_cfg;
+
+/*
+ * Command to program RGB gamma table
+ */
+
+#define VFE_CMD_RGB_GAMMA_CFG 0x0003
+#define VFE_CMD_RGB_GAMMA_CFG_LEN \
+ sizeof(vfe_cmd_rgb_gamma_cfg)
+
+#define VFE_CMD_RGB_GAMMA_SEL_LINEAR 0x0000
+#define VFE_CMD_RGB_GAMMA_SEL_PW_LINEAR 0x0001
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int rgb_gamma_sel;
+ unsigned int rgb_gamma_entry[256];
+} __attribute__((packed)) vfe_cmd_rgb_gamma_cfg;
+
+
+/*
+ * Command to program luma gamma table for the noise reduction path
+ */
+
+#define VFE_CMD_Y_GAMMA_CFG 0x0004
+#define VFE_CMD_Y_GAMMA_CFG_LEN \
+ sizeof(vfe_cmd_y_gamma_cfg)
+
+#define VFE_CMD_Y_GAMMA_SEL_LINEAR 0x0000
+#define VFE_CMD_Y_GAMMA_SEL_PW_LINEAR 0x0001
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int y_gamma_sel;
+ unsigned int y_gamma_entry[256];
+} __attribute__((packed)) vfe_cmd_y_gamma_cfg;
+
+
+
+/******************************************************************************
+ * Commands through vfeCommandQueue
+ *****************************************************************************/
+
+/*
+ * Command to reset the VFE to a known good state.All previously programmed
+ * Params will be lost
+ */
+
+
+#define VFE_CMD_RESET 0x0000
+#define VFE_CMD_RESET_LEN sizeof(vfe_cmd_reset)
+
+
+typedef struct {
+ unsigned short cmd_id;
+} __attribute__((packed)) vfe_cmd_reset;
+
+
+/*
+ * Command to start VFE processing based on the config params
+ */
+
+
+#define VFE_CMD_START 0x0001
+#define VFE_CMD_START_LEN sizeof(vfe_cmd_start)
+
+#define VFE_CMD_STARTUP_PARAMS_SRC_CAMIF 0x0000
+#define VFE_CMD_STARTUP_PARAMS_SRC_AXI 0x0001
+#define VFE_CMD_STARTUP_PARAMS_MODE_CONTINUOUS 0x0000
+#define VFE_CMD_STARTUP_PARAMS_MODE_SNAPSHOT 0x0002
+
+#define VFE_CMD_IMAGE_PL_BLACK_LVL_CORR_DIS 0x0000
+#define VFE_CMD_IMAGE_PL_BLACK_LVL_CORR_ENA 0x0001
+#define VFE_CMD_IMAGE_PL_ROLLOFF_CORR_DIS 0x0000
+#define VFE_CMD_IMAGE_PL_ROLLOFF_CORR_ENA 0x0002
+#define VFE_CMD_IMAGE_PL_WHITE_BAL_DIS 0x0000
+#define VFE_CMD_IMAGE_PL_WHITE_BAL_ENA 0x0004
+#define VFE_CMD_IMAGE_PL_RGB_GAMMA_DIS 0x0000
+#define VFE_CMD_IMAGE_PL_RGB_GAMMA_ENA 0x0008
+#define VFE_CMD_IMAGE_PL_LUMA_NOISE_RED_PATH_DIS 0x0000
+#define VFE_CMD_IMAGE_PL_LUMA_NOISE_RED_PATH_ENA 0x0010
+#define VFE_CMD_IMAGE_PL_ADP_FILTER_DIS 0x0000
+#define VFE_CMD_IMAGE_PL_ADP_FILTER_ENA 0x0020
+#define VFE_CMD_IMAGE_PL_CHROMA_SAMP_DIS 0x0000
+#define VFE_CMD_IMAGE_PL_CHROMA_SAMP_ENA 0x0040
+
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int startup_params;
+ unsigned int image_pipeline;
+ unsigned int frame_dimension;
+} __attribute__((packed)) vfe_cmd_start;
+
+
+/*
+ * Command to halt all processing
+ */
+
+#define VFE_CMD_STOP 0x0002
+#define VFE_CMD_STOP_LEN sizeof(vfe_cmd_stop)
+
+typedef struct {
+ unsigned short cmd_id;
+} __attribute__((packed)) vfe_cmd_stop;
+
+
+/*
+ * Command to commit the params that have been programmed to take
+ * effect on the next frame
+ */
+
+#define VFE_CMD_UPDATE 0x0003
+#define VFE_CMD_UPDATE_LEN sizeof(vfe_cmd_update)
+
+
+typedef struct {
+ unsigned short cmd_id;
+} __attribute__((packed)) vfe_cmd_update;
+
+
+/*
+ * Command to program CAMIF module
+ */
+
+#define VFE_CMD_CAMIF_CFG 0x0004
+#define VFE_CMD_CAMIF_CFG_LEN sizeof(vfe_cmd_camif_cfg)
+
+#define VFE_CMD_CFG_VSYNC_SYNC_EDGE_HIGH 0x0000
+#define VFE_CMD_CFG_VSYNC_SYNC_EDGE_LOW 0x0002
+#define VFE_CMD_CFG_HSYNC_SYNC_EDGE_HIGH 0x0000
+#define VFE_CMD_CFG_HSYNC_SYNC_EDGE_LOW 0x0004
+#define VFE_CMD_CFG_SYNC_MODE_APS 0x0000
+#define VFE_CMD_CFG_SYNC_MODE_EFS 0X0008
+#define VFE_CMD_CFG_SYNC_MODE_ELS 0x0010
+#define VFE_CMD_CFG_SYNC_MODE_RVD 0x0018
+#define VFE_CMD_CFG_VFE_SUBSAMP_EN_DIS 0x0000
+#define VFE_CMD_CFG_VFE_SUBSAMP_EN_ENA 0x0020
+#define VFE_CMD_CFG_BUS_SUBSAMP_EN_DIS 0x0000
+#define VFE_CMD_CFG_BUS_SUBSAMP_EN_ENA 0x0080
+#define VFE_CMD_CFG_IRQ_SUBSAMP_EN_DIS 0x0000
+#define VFE_CMD_CFG_IRQ_SUBSAMP_EN_ENA 0x0800
+
+#define VFE_CMD_SUBSAMP2_CFG_PIXEL_SKIP_16 0x0000
+#define VFE_CMD_SUBSAMP2_CFG_PIXEL_SKIP_12 0x0010
+
+#define VFE_CMD_EPOCH_IRQ_1_DIS 0x0000
+#define VFE_CMD_EPOCH_IRQ_1_ENA 0x4000
+#define VFE_CMD_EPOCH_IRQ_2_DIS 0x0000
+#define VFE_CMD_EPOCH_IRQ_2_ENA 0x8000
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int cfg;
+ unsigned int efs_cfg;
+ unsigned int frame_cfg;
+ unsigned int window_width_cfg;
+ unsigned int window_height_cfg;
+ unsigned int subsamp1_cfg;
+ unsigned int subsamp2_cfg;
+ unsigned int epoch_irq;
+} __attribute__((packed)) vfe_cmd_camif_cfg;
+
+
+
+/*
+ * Command to program the black level module
+ */
+
+#define VFE_CMD_BLACK_LVL_CFG 0x0005
+#define VFE_CMD_BLACK_LVL_CFG_LEN sizeof(vfe_cmd_black_lvl_cfg)
+
+#define VFE_CMD_BL_SEL_MANUAL 0x0000
+#define VFE_CMD_BL_SEL_AUTO 0x0001
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int black_lvl_sel;
+ unsigned int cfg_part[3];
+} __attribute__((packed)) vfe_cmd_black_lvl_cfg;
+
+
+/*
+ * Command to program the active region by cropping the region of interest
+ */
+
+#define VFE_CMD_ACTIVE_REGION_CFG 0x0006
+#define VFE_CMD_ACTIVE_REGION_CFG_LEN \
+ sizeof(vfe_cmd_active_region_cfg)
+
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int cfg_part1;
+ unsigned int cfg_part2;
+} __attribute__((packed)) vfe_cmd_active_region_cfg;
+
+
+
+/*
+ * Command to program the defective pixel correction(DPC) ,
+ * adaptive bayer filter (ABF) and demosaic modules
+ */
+
+#define VFE_CMD_DEMOSAIC_CFG 0x0007
+#define VFE_CMD_DEMOSAIC_CFG_LEN sizeof(vfe_cmd_demosaic_cfg)
+
+#define VFE_CMD_DEMOSAIC_PART1_ABF_EN_DIS 0x0000
+#define VFE_CMD_DEMOSAIC_PART1_ABF_EN_ENA 0x0001
+#define VFE_CMD_DEMOSAIC_PART1_DPC_EN_DIS 0x0000
+#define VFE_CMD_DEMOSAIC_PART1_DPC_EN_ENA 0x0002
+#define VFE_CMD_DEMOSAIC_PART1_FORCE_ABF_OFF 0x0000
+#define VFE_CMD_DEMOSAIC_PART1_FORCE_ABF_ON 0x0004
+#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1 0x00000000
+#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_2 0x10000000
+#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_4 0x20000000
+#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_8 0x30000000
+#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1_2 0x50000000
+#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1_4 0x60000000
+#define VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1_8 0x70000000
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int demosaic_part1;
+ unsigned int demosaic_part2;
+ unsigned int demosaic_part3;
+ unsigned int demosaic_part4;
+ unsigned int demosaic_part5;
+} __attribute__((packed)) vfe_cmd_demosaic_cfg;
+
+
+/*
+ * Command to program the ip format
+ */
+
+#define VFE_CMD_IP_FORMAT_CFG 0x0008
+#define VFE_CMD_IP_FORMAT_CFG_LEN \
+ sizeof(vfe_cmd_ip_format_cfg)
+
+#define VFE_CMD_IP_FORMAT_SEL_RGRG 0x0000
+#define VFE_CMD_IP_FORMAT_SEL_GRGR 0x0001
+#define VFE_CMD_IP_FORMAT_SEL_BGBG 0x0002
+#define VFE_CMD_IP_FORMAT_SEL_GBGB 0x0003
+#define VFE_CMD_IP_FORMAT_SEL_YCBYCR 0x0004
+#define VFE_CMD_IP_FORMAT_SEL_YCRYCB 0x0005
+#define VFE_CMD_IP_FORMAT_SEL_CBYCRY 0x0006
+#define VFE_CMD_IP_FORMAT_SEL_CRYCBY 0x0007
+#define VFE_CMD_IP_FORMAT_SEL_NO_CHROMA 0x0000
+#define VFE_CMD_IP_FORMAT_SEL_CHROMA 0x0008
+
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int ip_format_sel;
+ unsigned int balance_gains_part1;
+ unsigned int balance_gains_part2;
+} __attribute__((packed)) vfe_cmd_ip_format_cfg;
+
+
+
+/*
+ * Command to program max and min allowed op values
+ */
+
+#define VFE_CMD_OP_CLAMP_CFG 0x0009
+#define VFE_CMD_OP_CLAMP_CFG_LEN \
+ sizeof(vfe_cmd_op_clamp_cfg)
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int op_clamp_max;
+ unsigned int op_clamp_min;
+} __attribute__((packed)) vfe_cmd_op_clamp_cfg;
+
+
+/*
+ * Command to program chroma sub sample module
+ */
+
+#define VFE_CMD_CHROMA_SUBSAMPLE_CFG 0x000A
+#define VFE_CMD_CHROMA_SUBSAMPLE_CFG_LEN \
+ sizeof(vfe_cmd_chroma_subsample_cfg)
+
+#define VFE_CMD_CHROMA_SUBSAMP_SEL_H_INTERESTIAL_SAMPS 0x0000
+#define VFE_CMD_CHROMA_SUBSAMP_SEL_H_COSITED_SAMPS 0x0001
+#define VFE_CMD_CHROMA_SUBSAMP_SEL_V_INTERESTIAL_SAMPS 0x0000
+#define VFE_CMD_CHROMA_SUBSAMP_SEL_V_COSITED_SAMPS 0x0002
+#define VFE_CMD_CHROMA_SUBSAMP_SEL_H_SUBSAMP_DIS 0x0000
+#define VFE_CMD_CHROMA_SUBSAMP_SEL_H_SUBSAMP_ENA 0x0004
+#define VFE_CMD_CHROMA_SUBSAMP_SEL_V_SUBSAMP_DIS 0x0000
+#define VFE_CMD_CHROMA_SUBSAMP_SEL_V_SUBSAMP_ENA 0x0008
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int chroma_subsamp_sel;
+} __attribute__((packed)) vfe_cmd_chroma_subsample_cfg;
+
+
+/*
+ * Command to program the white balance module
+ */
+
+#define VFE_CMD_WHITE_BALANCE_CFG 0x000B
+#define VFE_CMD_WHITE_BALANCE_CFG_LEN \
+ sizeof(vfe_cmd_white_balance_cfg)
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int white_balance_gains;
+} __attribute__((packed)) vfe_cmd_white_balance_cfg;
+
+
+/*
+ * Command to program the color processing module
+ */
+
+#define VFE_CMD_COLOR_PROCESS_CFG 0x000C
+#define VFE_CMD_COLOR_PROCESS_CFG_LEN \
+ sizeof(vfe_cmd_color_process_cfg)
+
+#define VFE_CMD_COLOR_CORRE_PART7_Q7_FACTORS 0x0000
+#define VFE_CMD_COLOR_CORRE_PART7_Q8_FACTORS 0x0001
+#define VFE_CMD_COLOR_CORRE_PART7_Q9_FACTORS 0x0002
+#define VFE_CMD_COLOR_CORRE_PART7_Q10_FACTORS 0x0003
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int color_correction_part1;
+ unsigned int color_correction_part2;
+ unsigned int color_correction_part3;
+ unsigned int color_correction_part4;
+ unsigned int color_correction_part5;
+ unsigned int color_correction_part6;
+ unsigned int color_correction_part7;
+ unsigned int chroma_enhance_part1;
+ unsigned int chroma_enhance_part2;
+ unsigned int chroma_enhance_part3;
+ unsigned int chroma_enhance_part4;
+ unsigned int chroma_enhance_part5;
+ unsigned int luma_calc_part1;
+ unsigned int luma_calc_part2;
+} __attribute__((packed)) vfe_cmd_color_process_cfg;
+
+
+/*
+ * Command to program adaptive filter module
+ */
+
+#define VFE_CMD_ADP_FILTER_CFG 0x000D
+#define VFE_CMD_ADP_FILTER_CFG_LEN \
+ sizeof(vfe_cmd_adp_filter_cfg)
+
+#define VFE_CMD_ASF_CFG_PART_SMOOTH_FILTER_DIS 0x0000
+#define VFE_CMD_ASF_CFG_PART_SMOOTH_FILTER_ENA 0x0001
+#define VFE_CMD_ASF_CFG_PART_NO_SHARP_MODE 0x0000
+#define VFE_CMD_ASF_CFG_PART_SINGLE_FILTER 0x0002
+#define VFE_CMD_ASF_CFG_PART_DUAL_FILTER 0x0004
+#define VFE_CMD_ASF_CFG_PART_SHARP_MODE 0x0007
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int asf_cfg_part[7];
+} __attribute__((packed)) vfe_cmd_adp_filter_cfg;
+
+
+/*
+ * Command to program for frame skip pattern for op1 and op2
+ */
+
+#define VFE_CMD_FRAME_SKIP_CFG 0x000E
+#define VFE_CMD_FRAME_SKIP_CFG_LEN \
+ sizeof(vfe_cmd_frame_skip_cfg)
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int frame_skip_pattern_op1;
+ unsigned int frame_skip_pattern_op2;
+} __attribute__((packed)) vfe_cmd_frame_skip_cfg;
+
+
+/*
+ * Command to program field-of-view crop for digital zoom
+ */
+
+#define VFE_CMD_FOV_CROP 0x000F
+#define VFE_CMD_FOV_CROP_LEN sizeof(vfe_cmd_fov_crop)
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int fov_crop_part1;
+ unsigned int fov_crop_part2;
+} __attribute__((packed)) vfe_cmd_fov_crop;
+
+
+
+/*
+ * Command to program auto focus(AF) statistics module
+ */
+
+#define VFE_CMD_STATS_AUTOFOCUS_CFG 0x0010
+#define VFE_CMD_STATS_AUTOFOCUS_CFG_LEN \
+ sizeof(vfe_cmd_stats_autofocus_cfg)
+
+#define VFE_CMD_AF_STATS_SEL_STATS_DIS 0x0000
+#define VFE_CMD_AF_STATS_SEL_STATS_ENA 0x0001
+#define VFE_CMD_AF_STATS_SEL_PRI_FIXED 0x0000
+#define VFE_CMD_AF_STATS_SEL_PRI_VAR 0x0002
+#define VFE_CMD_AF_STATS_CFG_PART_METRIC_SUM 0x00000000
+#define VFE_CMD_AF_STATS_CFG_PART_METRIC_MAX 0x00200000
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int af_stats_sel;
+ unsigned int af_stats_cfg_part[8];
+ unsigned int af_stats_op_buf_hdr;
+ unsigned int af_stats_op_buf[3];
+} __attribute__((packed)) vfe_cmd_stats_autofocus_cfg;
+
+
+/*
+ * Command to program White balance(wb) and exposure (exp)
+ * statistics module
+ */
+
+#define VFE_CMD_STATS_WB_EXP_CFG 0x0011
+#define VFE_CMD_STATS_WB_EXP_CFG_LEN \
+ sizeof(vfe_cmd_stats_wb_exp_cfg)
+
+#define VFE_CMD_WB_EXP_STATS_SEL_STATS_DIS 0x0000
+#define VFE_CMD_WB_EXP_STATS_SEL_STATS_ENA 0x0001
+#define VFE_CMD_WB_EXP_STATS_SEL_PRI_FIXED 0x0000
+#define VFE_CMD_WB_EXP_STATS_SEL_PRI_VAR 0x0002
+
+#define VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_REG_8_8 0x0000
+#define VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_REG_16_16 0x0001
+#define VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_SREG_8_8 0x0000
+#define VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_SREG_4_4 0x0002
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int wb_exp_stats_sel;
+ unsigned int wb_exp_stats_cfg_part1;
+ unsigned int wb_exp_stats_cfg_part2;
+ unsigned int wb_exp_stats_cfg_part3;
+ unsigned int wb_exp_stats_cfg_part4;
+ unsigned int wb_exp_stats_op_buf_hdr;
+ unsigned int wb_exp_stats_op_buf[3];
+} __attribute__((packed)) vfe_cmd_stats_wb_exp_cfg;
+
+
+/*
+ * Command to program histogram(hg) stats module
+ */
+
+#define VFE_CMD_STATS_HG_CFG 0x0012
+#define VFE_CMD_STATS_HG_CFG_LEN \
+ sizeof(vfe_cmd_stats_hg_cfg)
+
+#define VFE_CMD_HG_STATS_SEL_PRI_FIXED 0x0000
+#define VFE_CMD_HG_STATS_SEL_PRI_VAR 0x0002
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int hg_stats_sel;
+ unsigned int hg_stats_cfg_part1;
+ unsigned int hg_stats_cfg_part2;
+ unsigned int hg_stats_op_buf_hdr;
+ unsigned int hg_stats_op_buf;
+} __attribute__((packed)) vfe_cmd_stats_hg_cfg;
+
+
+/*
+ * Command to acknowledge last MSG_VFE_OP1 message
+ */
+
+#define VFE_CMD_OP1_ACK 0x0013
+#define VFE_CMD_OP1_ACK_LEN sizeof(vfe_cmd_op1_ack)
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int op1_buf_y_addr;
+ unsigned int op1_buf_cbcr_addr;
+} __attribute__((packed)) vfe_cmd_op1_ack;
+
+
+
+/*
+ * Command to acknowledge last MSG_VFE_OP2 message
+ */
+
+#define VFE_CMD_OP2_ACK 0x0014
+#define VFE_CMD_OP2_ACK_LEN sizeof(vfe_cmd_op2_ack)
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int op2_buf_y_addr;
+ unsigned int op2_buf_cbcr_addr;
+} __attribute__((packed)) vfe_cmd_op2_ack;
+
+
+
+/*
+ * Command to acknowledge MSG_VFE_STATS_AUTOFOCUS msg
+ */
+
+#define VFE_CMD_STATS_AF_ACK 0x0015
+#define VFE_CMD_STATS_AF_ACK_LEN sizeof(vfe_cmd_stats_af_ack)
+
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int af_stats_op_buf;
+} __attribute__((packed)) vfe_cmd_stats_af_ack;
+
+
+/*
+ * Command to acknowledge MSG_VFE_STATS_WB_EXP msg
+ */
+
+#define VFE_CMD_STATS_WB_EXP_ACK 0x0016
+#define VFE_CMD_STATS_WB_EXP_ACK_LEN sizeof(vfe_cmd_stats_wb_exp_ack)
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int wb_exp_stats_op_buf;
+} __attribute__((packed)) vfe_cmd_stats_wb_exp_ack;
+
+
+/*
+ * Command to acknowledge MSG_VFE_EPOCH1 message
+ */
+
+#define VFE_CMD_EPOCH1_ACK 0x0017
+#define VFE_CMD_EPOCH1_ACK_LEN sizeof(vfe_cmd_epoch1_ack)
+
+typedef struct {
+ unsigned short cmd_id;
+} __attribute__((packed)) vfe_cmd_epoch1_ack;
+
+
+/*
+ * Command to acknowledge MSG_VFE_EPOCH2 message
+ */
+
+#define VFE_CMD_EPOCH2_ACK 0x0018
+#define VFE_CMD_EPOCH2_ACK_LEN sizeof(vfe_cmd_epoch2_ack)
+
+typedef struct {
+ unsigned short cmd_id;
+} __attribute__((packed)) vfe_cmd_epoch2_ack;
+
+
+
+/*
+ * Command to configure, enable or disable synchronous timer1
+ */
+
+#define VFE_CMD_SYNC_TIMER1_CFG 0x0019
+#define VFE_CMD_SYNC_TIMER1_CFG_LEN \
+ sizeof(vfe_cmd_sync_timer1_cfg)
+
+#define VFE_CMD_SYNC_T1_CFG_PART1_TIMER_DIS 0x0000
+#define VFE_CMD_SYNC_T1_CFG_PART1_TIMER_ENA 0x0001
+#define VFE_CMD_SYNC_T1_CFG_PART1_POL_HIGH 0x0000
+#define VFE_CMD_SYNC_T1_CFG_PART1_POL_LOW 0x0002
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int sync_t1_cfg_part1;
+ unsigned int sync_t1_h_sync_countdown;
+ unsigned int sync_t1_pclk_countdown;
+ unsigned int sync_t1_duration;
+} __attribute__((packed)) vfe_cmd_sync_timer1_cfg;
+
+
+/*
+ * Command to configure, enable or disable synchronous timer1
+ */
+
+#define VFE_CMD_SYNC_TIMER2_CFG 0x001A
+#define VFE_CMD_SYNC_TIMER2_CFG_LEN \
+ sizeof(vfe_cmd_sync_timer2_cfg)
+
+#define VFE_CMD_SYNC_T2_CFG_PART1_TIMER_DIS 0x0000
+#define VFE_CMD_SYNC_T2_CFG_PART1_TIMER_ENA 0x0001
+#define VFE_CMD_SYNC_T2_CFG_PART1_POL_HIGH 0x0000
+#define VFE_CMD_SYNC_T2_CFG_PART1_POL_LOW 0x0002
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int sync_t2_cfg_part1;
+ unsigned int sync_t2_h_sync_countdown;
+ unsigned int sync_t2_pclk_countdown;
+ unsigned int sync_t2_duration;
+} __attribute__((packed)) vfe_cmd_sync_timer2_cfg;
+
+
+/*
+ * Command to configure and start asynchronous timer1
+ */
+
+#define VFE_CMD_ASYNC_TIMER1_START 0x001B
+#define VFE_CMD_ASYNC_TIMER1_START_LEN \
+ sizeof(vfe_cmd_async_timer1_start)
+
+#define VFE_CMD_ASYNC_T1_POLARITY_A_HIGH 0x0000
+#define VFE_CMD_ASYNC_T1_POLARITY_A_LOW 0x0001
+#define VFE_CMD_ASYNC_T1_POLARITY_B_HIGH 0x0000
+#define VFE_CMD_ASYNC_T1_POLARITY_B_LOW 0x0002
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int async_t1a_cfg;
+ unsigned int async_t1b_cfg;
+ unsigned int async_t1_polarity;
+} __attribute__((packed)) vfe_cmd_async_timer1_start;
+
+
+/*
+ * Command to configure and start asynchronous timer2
+ */
+
+#define VFE_CMD_ASYNC_TIMER2_START 0x001C
+#define VFE_CMD_ASYNC_TIMER2_START_LEN \
+ sizeof(vfe_cmd_async_timer2_start)
+
+#define VFE_CMD_ASYNC_T2_POLARITY_A_HIGH 0x0000
+#define VFE_CMD_ASYNC_T2_POLARITY_A_LOW 0x0001
+#define VFE_CMD_ASYNC_T2_POLARITY_B_HIGH 0x0000
+#define VFE_CMD_ASYNC_T2_POLARITY_B_LOW 0x0002
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int async_t2a_cfg;
+ unsigned int async_t2b_cfg;
+ unsigned int async_t2_polarity;
+} __attribute__((packed)) vfe_cmd_async_timer2_start;
+
+
+/*
+ * Command to program partial configurations of auto focus(af)
+ */
+
+#define VFE_CMD_STATS_AF_UPDATE 0x001D
+#define VFE_CMD_STATS_AF_UPDATE_LEN \
+ sizeof(vfe_cmd_stats_af_update)
+
+#define VFE_CMD_AF_UPDATE_PART1_WINDOW_ONE 0x00000000
+#define VFE_CMD_AF_UPDATE_PART1_WINDOW_MULTI 0x80000000
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int af_update_part1;
+ unsigned int af_update_part2;
+} __attribute__((packed)) vfe_cmd_stats_af_update;
+
+
+/*
+ * Command to program partial cfg of wb and exp
+ */
+
+#define VFE_CMD_STATS_WB_EXP_UPDATE 0x001E
+#define VFE_CMD_STATS_WB_EXP_UPDATE_LEN \
+ sizeof(vfe_cmd_stats_wb_exp_update)
+
+#define VFE_CMD_WB_EXP_UPDATE_PART1_REGIONS_8_8 0x0000
+#define VFE_CMD_WB_EXP_UPDATE_PART1_REGIONS_16_16 0x0001
+#define VFE_CMD_WB_EXP_UPDATE_PART1_SREGIONS_8_8 0x0000
+#define VFE_CMD_WB_EXP_UPDATE_PART1_SREGIONS_4_4 0x0002
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int wb_exp_update_part1;
+ unsigned int wb_exp_update_part2;
+ unsigned int wb_exp_update_part3;
+ unsigned int wb_exp_update_part4;
+} __attribute__((packed)) vfe_cmd_stats_wb_exp_update;
+
+
+
+/*
+ * Command to re program the CAMIF FRAME CONFIG settings
+ */
+
+#define VFE_CMD_UPDATE_CAMIF_FRAME_CFG 0x001F
+#define VFE_CMD_UPDATE_CAMIF_FRAME_CFG_LEN \
+ sizeof(vfe_cmd_update_camif_frame_cfg)
+
+typedef struct {
+ unsigned int cmd_id;
+ unsigned int camif_frame_cfg;
+} __attribute__((packed)) vfe_cmd_update_camif_frame_cfg;
+
+
+#endif
diff --git a/drivers/staging/dream/include/mach/qdsp5/qdsp5vfemsg.h b/drivers/staging/dream/include/mach/qdsp5/qdsp5vfemsg.h
new file mode 100644
index 000000000000..0053cfb65ba1
--- /dev/null
+++ b/drivers/staging/dream/include/mach/qdsp5/qdsp5vfemsg.h
@@ -0,0 +1,290 @@
+#ifndef QDSP5VFEMSGI_H
+#define QDSP5VFEMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+ V F E I N T E R N A L M E S S A G E S
+
+GENERAL DESCRIPTION
+ This file contains defintions of format blocks of commands
+ that are sent by VFE Task
+
+REFERENCES
+ None
+
+EXTERNALIZED FUNCTIONS
+ None
+
+Copyright(c) 1992 - 2008 by QUALCOMM, Incorporated.
+
+This software is licensed under the terms of the GNU General Public
+License version 2, as published by the Free Software Foundation, and
+may be copied, distributed, and modified under those terms.
+
+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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+ EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vfemsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $
+Revision History:
+
+when who what, where, why
+-------- --- ----------------------------------------------------------
+06/12/08 sv initial version
+===========================================================================*/
+
+
+/*
+ * Message to acknowledge CMD_VFE_REST command
+ */
+
+#define VFE_MSG_RESET_ACK 0x0000
+#define VFE_MSG_RESET_ACK_LEN sizeof(vfe_msg_reset_ack)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_reset_ack;
+
+
+/*
+ * Message to acknowledge CMD_VFE_START command
+ */
+
+#define VFE_MSG_START_ACK 0x0001
+#define VFE_MSG_START_ACK_LEN sizeof(vfe_msg_start_ack)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_start_ack;
+
+/*
+ * Message to acknowledge CMD_VFE_STOP command
+ */
+
+#define VFE_MSG_STOP_ACK 0x0002
+#define VFE_MSG_STOP_ACK_LEN sizeof(vfe_msg_stop_ack)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_stop_ack;
+
+
+/*
+ * Message to acknowledge CMD_VFE_UPDATE command
+ */
+
+#define VFE_MSG_UPDATE_ACK 0x0003
+#define VFE_MSG_UPDATE_ACK_LEN sizeof(vfe_msg_update_ack)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_update_ack;
+
+
+/*
+ * Message to notify the ARM that snapshot processing is complete
+ * and that the VFE is now STATE_VFE_IDLE
+ */
+
+#define VFE_MSG_SNAPSHOT_DONE 0x0004
+#define VFE_MSG_SNAPSHOT_DONE_LEN \
+ sizeof(vfe_msg_snapshot_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_snapshot_done;
+
+
+
+/*
+ * Message to notify ARM that illegal cmd was received and
+ * system is in the IDLE state
+ */
+
+#define VFE_MSG_ILLEGAL_CMD 0x0005
+#define VFE_MSG_ILLEGAL_CMD_LEN \
+ sizeof(vfe_msg_illegal_cmd)
+
+typedef struct {
+ unsigned int status;
+} __attribute__((packed)) vfe_msg_illegal_cmd;
+
+
+/*
+ * Message to notify ARM that op1 buf is full and ready
+ */
+
+#define VFE_MSG_OP1 0x0006
+#define VFE_MSG_OP1_LEN sizeof(vfe_msg_op1)
+
+typedef struct {
+ unsigned int op1_buf_y_addr;
+ unsigned int op1_buf_cbcr_addr;
+ unsigned int black_level_even_col;
+ unsigned int black_level_odd_col;
+ unsigned int defect_pixels_detected;
+ unsigned int asf_max_edge;
+} __attribute__((packed)) vfe_msg_op1;
+
+
+/*
+ * Message to notify ARM that op2 buf is full and ready
+ */
+
+#define VFE_MSG_OP2 0x0007
+#define VFE_MSG_OP2_LEN sizeof(vfe_msg_op2)
+
+typedef struct {
+ unsigned int op2_buf_y_addr;
+ unsigned int op2_buf_cbcr_addr;
+ unsigned int black_level_even_col;
+ unsigned int black_level_odd_col;
+ unsigned int defect_pixels_detected;
+ unsigned int asf_max_edge;
+} __attribute__((packed)) vfe_msg_op2;
+
+
+/*
+ * Message to notify ARM that autofocus(af) stats are ready
+ */
+
+#define VFE_MSG_STATS_AF 0x0008
+#define VFE_MSG_STATS_AF_LEN sizeof(vfe_msg_stats_af)
+
+typedef struct {
+ unsigned int af_stats_op_buffer;
+} __attribute__((packed)) vfe_msg_stats_af;
+
+
+/*
+ * Message to notify ARM that white balance(wb) and exposure (exp)
+ * stats are ready
+ */
+
+#define VFE_MSG_STATS_WB_EXP 0x0009
+#define VFE_MSG_STATS_WB_EXP_LEN \
+ sizeof(vfe_msg_stats_wb_exp)
+
+typedef struct {
+ unsigned int wb_exp_stats_op_buf;
+} __attribute__((packed)) vfe_msg_stats_wb_exp;
+
+
+/*
+ * Message to notify the ARM that histogram(hg) stats are ready
+ */
+
+#define VFE_MSG_STATS_HG 0x000A
+#define VFE_MSG_STATS_HG_LEN sizeof(vfe_msg_stats_hg)
+
+typedef struct {
+ unsigned int hg_stats_op_buf;
+} __attribute__((packed)) vfe_msg_stats_hg;
+
+
+/*
+ * Message to notify the ARM that epoch1 event occurred in the CAMIF
+ */
+
+#define VFE_MSG_EPOCH1 0x000B
+#define VFE_MSG_EPOCH1_LEN sizeof(vfe_msg_epoch1)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_epoch1;
+
+
+/*
+ * Message to notify the ARM that epoch2 event occurred in the CAMIF
+ */
+
+#define VFE_MSG_EPOCH2 0x000C
+#define VFE_MSG_EPOCH2_LEN sizeof(vfe_msg_epoch2)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_epoch2;
+
+
+/*
+ * Message to notify the ARM that sync timer1 op is completed
+ */
+
+#define VFE_MSG_SYNC_T1_DONE 0x000D
+#define VFE_MSG_SYNC_T1_DONE_LEN sizeof(vfe_msg_sync_t1_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_sync_t1_done;
+
+
+/*
+ * Message to notify the ARM that sync timer2 op is completed
+ */
+
+#define VFE_MSG_SYNC_T2_DONE 0x000E
+#define VFE_MSG_SYNC_T2_DONE_LEN sizeof(vfe_msg_sync_t2_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_sync_t2_done;
+
+
+/*
+ * Message to notify the ARM that async t1 operation completed
+ */
+
+#define VFE_MSG_ASYNC_T1_DONE 0x000F
+#define VFE_MSG_ASYNC_T1_DONE_LEN sizeof(vfe_msg_async_t1_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_async_t1_done;
+
+
+
+/*
+ * Message to notify the ARM that async t2 operation completed
+ */
+
+#define VFE_MSG_ASYNC_T2_DONE 0x0010
+#define VFE_MSG_ASYNC_T2_DONE_LEN sizeof(vfe_msg_async_t2_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_async_t2_done;
+
+
+
+/*
+ * Message to notify the ARM that an error has occurred
+ */
+
+#define VFE_MSG_ERROR 0x0011
+#define VFE_MSG_ERROR_LEN sizeof(vfe_msg_error)
+
+#define VFE_MSG_ERR_COND_NO_CAMIF_ERR 0x0000
+#define VFE_MSG_ERR_COND_CAMIF_ERR 0x0001
+#define VFE_MSG_ERR_COND_OP1_Y_NO_BUS_OF 0x0000
+#define VFE_MSG_ERR_COND_OP1_Y_BUS_OF 0x0002
+#define VFE_MSG_ERR_COND_OP1_CBCR_NO_BUS_OF 0x0000
+#define VFE_MSG_ERR_COND_OP1_CBCR_BUS_OF 0x0004
+#define VFE_MSG_ERR_COND_OP2_Y_NO_BUS_OF 0x0000
+#define VFE_MSG_ERR_COND_OP2_Y_BUS_OF 0x0008
+#define VFE_MSG_ERR_COND_OP2_CBCR_NO_BUS_OF 0x0000
+#define VFE_MSG_ERR_COND_OP2_CBCR_BUS_OF 0x0010
+#define VFE_MSG_ERR_COND_AF_NO_BUS_OF 0x0000
+#define VFE_MSG_ERR_COND_AF_BUS_OF 0x0020
+#define VFE_MSG_ERR_COND_WB_EXP_NO_BUS_OF 0x0000
+#define VFE_MSG_ERR_COND_WB_EXP_BUS_OF 0x0040
+#define VFE_MSG_ERR_COND_NO_AXI_ERR 0x0000
+#define VFE_MSG_ERR_COND_AXI_ERR 0x0080
+
+#define VFE_MSG_CAMIF_STS_IDLE 0x0000
+#define VFE_MSG_CAMIF_STS_CAPTURE_DATA 0x0001
+
+typedef struct {
+ unsigned int err_cond;
+ unsigned int camif_sts;
+} __attribute__((packed)) vfe_msg_error;
+
+
+#endif
diff --git a/drivers/staging/dream/include/media/msm_camera.h b/drivers/staging/dream/include/media/msm_camera.h
new file mode 100644
index 000000000000..09812d62cc1e
--- /dev/null
+++ b/drivers/staging/dream/include/media/msm_camera.h
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+#ifndef __LINUX_MSM_CAMERA_H
+#define __LINUX_MSM_CAMERA_H
+
+#include <linux/types.h>
+#include <asm/sizes.h>
+#include <linux/ioctl.h>
+
+#define MSM_CAM_IOCTL_MAGIC 'm'
+
+#define MSM_CAM_IOCTL_GET_SENSOR_INFO \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 1, struct msm_camsensor_info *)
+
+#define MSM_CAM_IOCTL_REGISTER_PMEM \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 2, struct msm_pmem_info *)
+
+#define MSM_CAM_IOCTL_UNREGISTER_PMEM \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 3, unsigned)
+
+#define MSM_CAM_IOCTL_CTRL_COMMAND \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 4, struct msm_ctrl_cmd *)
+
+#define MSM_CAM_IOCTL_CONFIG_VFE \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 5, struct msm_camera_vfe_cfg_cmd *)
+
+#define MSM_CAM_IOCTL_GET_STATS \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 6, struct msm_camera_stats_event_ctrl *)
+
+#define MSM_CAM_IOCTL_GETFRAME \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 7, struct msm_camera_get_frame *)
+
+#define MSM_CAM_IOCTL_ENABLE_VFE \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 8, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_CTRL_CMD_DONE \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 9, struct camera_cmd *)
+
+#define MSM_CAM_IOCTL_CONFIG_CMD \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 10, struct camera_cmd *)
+
+#define MSM_CAM_IOCTL_DISABLE_VFE \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 11, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_PAD_REG_RESET2 \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 12, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_VFE_APPS_RESET \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 13, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 14, struct camera_enable_cmd *)
+
+#define MSM_CAM_IOCTL_RELEASE_STATS_BUFFER \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 15, struct msm_stats_buf *)
+
+#define MSM_CAM_IOCTL_AXI_CONFIG \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 16, struct msm_camera_vfe_cfg_cmd *)
+
+#define MSM_CAM_IOCTL_GET_PICTURE \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 17, struct msm_camera_ctrl_cmd *)
+
+#define MSM_CAM_IOCTL_SET_CROP \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 18, struct crop_info *)
+
+#define MSM_CAM_IOCTL_PICT_PP \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 19, uint8_t *)
+
+#define MSM_CAM_IOCTL_PICT_PP_DONE \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 20, struct msm_snapshot_pp_status *)
+
+#define MSM_CAM_IOCTL_SENSOR_IO_CFG \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 21, struct sensor_cfg_data *)
+
+#define MSM_CAMERA_LED_OFF 0
+#define MSM_CAMERA_LED_LOW 1
+#define MSM_CAMERA_LED_HIGH 2
+
+#define MSM_CAM_IOCTL_FLASH_LED_CFG \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 22, unsigned *)
+
+#define MSM_CAM_IOCTL_UNBLOCK_POLL_FRAME \
+ _IO(MSM_CAM_IOCTL_MAGIC, 23)
+
+#define MSM_CAM_IOCTL_CTRL_COMMAND_2 \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 24, struct msm_ctrl_cmd *)
+
+#define MAX_SENSOR_NUM 3
+#define MAX_SENSOR_NAME 32
+
+#define MSM_CAM_CTRL_CMD_DONE 0
+#define MSM_CAM_SENSOR_VFE_CMD 1
+
+/*****************************************************
+ * structure
+ *****************************************************/
+
+/* define five type of structures for userspace <==> kernel
+ * space communication:
+ * command 1 - 2 are from userspace ==> kernel
+ * command 3 - 4 are from kernel ==> userspace
+ *
+ * 1. control command: control command(from control thread),
+ * control status (from config thread);
+ */
+struct msm_ctrl_cmd {
+ uint16_t type;
+ uint16_t length;
+ void *value;
+ uint16_t status;
+ uint32_t timeout_ms;
+ int resp_fd; /* FIXME: to be used by the kernel, pass-through for now */
+};
+
+struct msm_vfe_evt_msg {
+ unsigned short type; /* 1 == event (RPC), 0 == message (adsp) */
+ unsigned short msg_id;
+ unsigned int len; /* size in, number of bytes out */
+ void *data;
+};
+
+#define MSM_CAM_RESP_CTRL 0
+#define MSM_CAM_RESP_STAT_EVT_MSG 1
+#define MSM_CAM_RESP_V4L2 2
+#define MSM_CAM_RESP_MAX 3
+
+/* this one is used to send ctrl/status up to config thread */
+struct msm_stats_event_ctrl {
+ /* 0 - ctrl_cmd from control thread,
+ * 1 - stats/event kernel,
+ * 2 - V4L control or read request */
+ int resptype;
+ int timeout_ms;
+ struct msm_ctrl_cmd ctrl_cmd;
+ /* struct vfe_event_t stats_event; */
+ struct msm_vfe_evt_msg stats_event;
+};
+
+/* 2. config command: config command(from config thread); */
+struct msm_camera_cfg_cmd {
+ /* what to config:
+ * 1 - sensor config, 2 - vfe config */
+ uint16_t cfg_type;
+
+ /* sensor config type */
+ uint16_t cmd_type;
+ uint16_t queue;
+ uint16_t length;
+ void *value;
+};
+
+#define CMD_GENERAL 0
+#define CMD_AXI_CFG_OUT1 1
+#define CMD_AXI_CFG_SNAP_O1_AND_O2 2
+#define CMD_AXI_CFG_OUT2 3
+#define CMD_PICT_T_AXI_CFG 4
+#define CMD_PICT_M_AXI_CFG 5
+#define CMD_RAW_PICT_AXI_CFG 6
+#define CMD_STATS_AXI_CFG 7
+#define CMD_STATS_AF_AXI_CFG 8
+#define CMD_FRAME_BUF_RELEASE 9
+#define CMD_PREV_BUF_CFG 10
+#define CMD_SNAP_BUF_RELEASE 11
+#define CMD_SNAP_BUF_CFG 12
+#define CMD_STATS_DISABLE 13
+#define CMD_STATS_ENABLE 14
+#define CMD_STATS_AF_ENABLE 15
+#define CMD_STATS_BUF_RELEASE 16
+#define CMD_STATS_AF_BUF_RELEASE 17
+#define UPDATE_STATS_INVALID 18
+
+/* vfe config command: config command(from config thread)*/
+struct msm_vfe_cfg_cmd {
+ int cmd_type;
+ uint16_t length;
+ void *value;
+};
+
+#define MAX_CAMERA_ENABLE_NAME_LEN 32
+struct camera_enable_cmd {
+ char name[MAX_CAMERA_ENABLE_NAME_LEN];
+};
+
+#define MSM_PMEM_OUTPUT1 0
+#define MSM_PMEM_OUTPUT2 1
+#define MSM_PMEM_OUTPUT1_OUTPUT2 2
+#define MSM_PMEM_THUMBAIL 3
+#define MSM_PMEM_MAINIMG 4
+#define MSM_PMEM_RAW_MAINIMG 5
+#define MSM_PMEM_AEC_AWB 6
+#define MSM_PMEM_AF 7
+#define MSM_PMEM_MAX 8
+
+#define FRAME_PREVIEW_OUTPUT1 0
+#define FRAME_PREVIEW_OUTPUT2 1
+#define FRAME_SNAPSHOT 2
+#define FRAME_THUMBAIL 3
+#define FRAME_RAW_SNAPSHOT 4
+#define FRAME_MAX 5
+
+struct msm_pmem_info {
+ int type;
+ int fd;
+ void *vaddr;
+ uint32_t y_off;
+ uint32_t cbcr_off;
+ uint8_t active;
+};
+
+struct outputCfg {
+ uint32_t height;
+ uint32_t width;
+
+ uint32_t window_height_firstline;
+ uint32_t window_height_lastline;
+};
+
+#define OUTPUT_1 0
+#define OUTPUT_2 1
+#define OUTPUT_1_AND_2 2
+#define CAMIF_TO_AXI_VIA_OUTPUT_2 3
+#define OUTPUT_1_AND_CAMIF_TO_AXI_VIA_OUTPUT_2 4
+#define OUTPUT_2_AND_CAMIF_TO_AXI_VIA_OUTPUT_1 5
+#define LAST_AXI_OUTPUT_MODE_ENUM = OUTPUT_2_AND_CAMIF_TO_AXI_VIA_OUTPUT_1 6
+
+#define MSM_FRAME_PREV_1 0
+#define MSM_FRAME_PREV_2 1
+#define MSM_FRAME_ENC 2
+
+struct msm_frame {
+ int path;
+ unsigned long buffer;
+ uint32_t y_off;
+ uint32_t cbcr_off;
+ int fd;
+
+ void *cropinfo;
+ int croplen;
+};
+
+#define STAT_AEAW 0
+#define STAT_AF 1
+#define STAT_MAX 2
+
+struct msm_stats_buf {
+ int type;
+ unsigned long buffer;
+ int fd;
+};
+
+#define MSM_V4L2_VID_CAP_TYPE 0
+#define MSM_V4L2_STREAM_ON 1
+#define MSM_V4L2_STREAM_OFF 2
+#define MSM_V4L2_SNAPSHOT 3
+#define MSM_V4L2_QUERY_CTRL 4
+#define MSM_V4L2_GET_CTRL 5
+#define MSM_V4L2_SET_CTRL 6
+#define MSM_V4L2_QUERY 7
+#define MSM_V4L2_MAX 8
+
+struct crop_info {
+ void *info;
+ int len;
+};
+
+struct msm_postproc {
+ int ftnum;
+ struct msm_frame fthumnail;
+ int fmnum;
+ struct msm_frame fmain;
+};
+
+struct msm_snapshot_pp_status {
+ void *status;
+};
+
+#define CFG_SET_MODE 0
+#define CFG_SET_EFFECT 1
+#define CFG_START 2
+#define CFG_PWR_UP 3
+#define CFG_PWR_DOWN 4
+#define CFG_WRITE_EXPOSURE_GAIN 5
+#define CFG_SET_DEFAULT_FOCUS 6
+#define CFG_MOVE_FOCUS 7
+#define CFG_REGISTER_TO_REAL_GAIN 8
+#define CFG_REAL_TO_REGISTER_GAIN 9
+#define CFG_SET_FPS 10
+#define CFG_SET_PICT_FPS 11
+#define CFG_SET_BRIGHTNESS 12
+#define CFG_SET_CONTRAST 13
+#define CFG_SET_ZOOM 14
+#define CFG_SET_EXPOSURE_MODE 15
+#define CFG_SET_WB 16
+#define CFG_SET_ANTIBANDING 17
+#define CFG_SET_EXP_GAIN 18
+#define CFG_SET_PICT_EXP_GAIN 19
+#define CFG_SET_LENS_SHADING 20
+#define CFG_GET_PICT_FPS 21
+#define CFG_GET_PREV_L_PF 22
+#define CFG_GET_PREV_P_PL 23
+#define CFG_GET_PICT_L_PF 24
+#define CFG_GET_PICT_P_PL 25
+#define CFG_GET_AF_MAX_STEPS 26
+#define CFG_GET_PICT_MAX_EXP_LC 27
+#define CFG_MAX 28
+
+#define MOVE_NEAR 0
+#define MOVE_FAR 1
+
+#define SENSOR_PREVIEW_MODE 0
+#define SENSOR_SNAPSHOT_MODE 1
+#define SENSOR_RAW_SNAPSHOT_MODE 2
+
+#define SENSOR_QTR_SIZE 0
+#define SENSOR_FULL_SIZE 1
+#define SENSOR_INVALID_SIZE 2
+
+#define CAMERA_EFFECT_OFF 0
+#define CAMERA_EFFECT_MONO 1
+#define CAMERA_EFFECT_NEGATIVE 2
+#define CAMERA_EFFECT_SOLARIZE 3
+#define CAMERA_EFFECT_PASTEL 4
+#define CAMERA_EFFECT_MOSAIC 5
+#define CAMERA_EFFECT_RESIZE 6
+#define CAMERA_EFFECT_SEPIA 7
+#define CAMERA_EFFECT_POSTERIZE 8
+#define CAMERA_EFFECT_WHITEBOARD 9
+#define CAMERA_EFFECT_BLACKBOARD 10
+#define CAMERA_EFFECT_AQUA 11
+#define CAMERA_EFFECT_MAX 12
+
+struct sensor_pict_fps {
+ uint16_t prevfps;
+ uint16_t pictfps;
+};
+
+struct exp_gain_cfg {
+ uint16_t gain;
+ uint32_t line;
+};
+
+struct focus_cfg {
+ int32_t steps;
+ int dir;
+};
+
+struct fps_cfg {
+ uint16_t f_mult;
+ uint16_t fps_div;
+ uint32_t pict_fps_div;
+};
+
+struct sensor_cfg_data {
+ int cfgtype;
+ int mode;
+ int rs;
+ uint8_t max_steps;
+
+ union {
+ int8_t effect;
+ uint8_t lens_shading;
+ uint16_t prevl_pf;
+ uint16_t prevp_pl;
+ uint16_t pictl_pf;
+ uint16_t pictp_pl;
+ uint32_t pict_max_exp_lc;
+ uint16_t p_fps;
+ struct sensor_pict_fps gfps;
+ struct exp_gain_cfg exp_gain;
+ struct focus_cfg focus;
+ struct fps_cfg fps;
+ } cfg;
+};
+
+#define GET_NAME 0
+#define GET_PREVIEW_LINE_PER_FRAME 1
+#define GET_PREVIEW_PIXELS_PER_LINE 2
+#define GET_SNAPSHOT_LINE_PER_FRAME 3
+#define GET_SNAPSHOT_PIXELS_PER_LINE 4
+#define GET_SNAPSHOT_FPS 5
+#define GET_SNAPSHOT_MAX_EP_LINE_CNT 6
+
+struct msm_camsensor_info {
+ char name[MAX_SENSOR_NAME];
+ uint8_t flash_enabled;
+};
+#endif /* __LINUX_MSM_CAMERA_H */
diff --git a/drivers/staging/dream/pmem.c b/drivers/staging/dream/pmem.c
index def646812348..503ba212dc96 100644
--- a/drivers/staging/dream/pmem.c
+++ b/drivers/staging/dream/pmem.c
@@ -37,17 +37,17 @@
* the file should not be released until put_pmem_file is called */
#define PMEM_FLAGS_BUSY 0x1
/* indicates that this is a suballocation of a larger master range */
-#define PMEM_FLAGS_CONNECTED 0x1 << 1
+#define PMEM_FLAGS_CONNECTED ( 0x1 << 1 )
/* indicates this is a master and not a sub allocation and that it is mmaped */
-#define PMEM_FLAGS_MASTERMAP 0x1 << 2
+#define PMEM_FLAGS_MASTERMAP ( 0x1 << 2 )
/* submap and unsubmap flags indicate:
* 00: subregion has never been mmaped
* 10: subregion has been mmaped, reference to the mm was taken
* 11: subretion has ben released, refernece to the mm still held
* 01: subretion has been released, reference to the mm has been released
*/
-#define PMEM_FLAGS_SUBMAP 0x1 << 3
-#define PMEM_FLAGS_UNSUBMAP 0x1 << 4
+#define PMEM_FLAGS_SUBMAP ( 0x1 << 3 )
+#define PMEM_FLAGS_UNSUBMAP ( 0x1 << 4 )
struct pmem_data {
@@ -91,7 +91,7 @@ struct pmem_region_node {
#define PMEM_DEBUG_MSGS 0
#if PMEM_DEBUG_MSGS
-#define DLOG(fmt,args...) \
+#define DLOG(fmt, args...) \
do { printk(KERN_INFO "[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \
##args); } \
while (0)
@@ -152,7 +152,7 @@ struct pmem_info {
static struct pmem_info pmem[PMEM_MAX_DEVICES];
static int id_count;
-#define PMEM_IS_FREE(id, index) !(pmem[id].bitmap[index].allocated)
+#define PMEM_IS_FREE(id, index) ( !(pmem[id].bitmap[index].allocated) )
#define PMEM_ORDER(id, index) pmem[id].bitmap[index].order
#define PMEM_BUDDY_INDEX(id, index) (index ^ (1 << PMEM_ORDER(id, index)))
#define PMEM_NEXT_INDEX(id, index) (index + (1 << PMEM_ORDER(id, index)))
@@ -708,9 +708,8 @@ int get_pmem_addr(struct file *file, unsigned long *start,
struct pmem_data *data;
int id;
- if (!is_pmem_file(file) || !has_allocation(file)) {
+ if (!is_pmem_file(file) || !has_allocation(file))
return -1;
- }
data = (struct pmem_data *)file->private_data;
if (data->index == -1) {
@@ -789,9 +788,8 @@ void flush_pmem_file(struct file *file, unsigned long offset, unsigned long len)
struct list_head *elt;
void *flush_start, *flush_end;
- if (!is_pmem_file(file) || !has_allocation(file)) {
+ if (!is_pmem_file(file) || !has_allocation(file))
return;
- }
id = get_id(file);
data = (struct pmem_data *)file->private_data;
@@ -833,7 +831,7 @@ static int pmem_connect(unsigned long connect, struct file *file)
src_file = fget_light(connect, &put_needed);
DLOG("connect %p to %p\n", file, src_file);
if (!src_file) {
- printk("pmem: src file not found!\n");
+ printk(KERN_INFO "pmem: src file not found!\n");
ret = -EINVAL;
goto err_no_file;
}
@@ -846,7 +844,7 @@ static int pmem_connect(unsigned long connect, struct file *file)
src_data = (struct pmem_data *)src_file->private_data;
if (has_allocation(file) && (data->index != src_data->index)) {
- printk("pmem: file is already mapped but doesn't match this"
+ printk(KERN_INFO "pmem: file is already mapped but doesn't match this"
" src_file!\n");
ret = -EINVAL;
goto err_bad_file;
@@ -885,7 +883,7 @@ lock_mm:
mm = get_task_mm(data->task);
if (!mm) {
#if PMEM_DEBUG
- printk("pmem: can't remap task is gone!\n");
+ printk(KERN_DEBUG "pmem: can't remap task is gone!\n");
#endif
up_read(&data->sem);
return -1;
@@ -936,7 +934,7 @@ int pmem_remap(struct pmem_region *region, struct file *file,
if (unlikely(!PMEM_IS_PAGE_ALIGNED(region->offset) ||
!PMEM_IS_PAGE_ALIGNED(region->len))) {
#if PMEM_DEBUG
- printk("pmem: request for unaligned pmem suballocation "
+ printk(KERN_DEBUG "pmem: request for unaligned pmem suballocation "
"%lx %lx\n", region->offset, region->len);
#endif
return -EINVAL;
diff --git a/drivers/staging/dream/qdsp5/Makefile b/drivers/staging/dream/qdsp5/Makefile
index 991d4a7e157f..beedaaff5cc5 100644
--- a/drivers/staging/dream/qdsp5/Makefile
+++ b/drivers/staging/dream/qdsp5/Makefile
@@ -1,3 +1,4 @@
+EXTRA_CFLAGS=-Idrivers/staging/dream/include
obj-y += adsp.o
ifeq ($(CONFIG_MSM_AMSS_VERSION_6350),y)
obj-y += adsp_info.o
diff --git a/drivers/staging/dream/qdsp5/audio_mp3.c b/drivers/staging/dream/qdsp5/audio_mp3.c
index b95574f699ff..7ed6e261d6c9 100644
--- a/drivers/staging/dream/qdsp5/audio_mp3.c
+++ b/drivers/staging/dream/qdsp5/audio_mp3.c
@@ -650,8 +650,7 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
&audio->read_phys,
GFP_KERNEL);
if (!audio->read_data) {
- pr_err("audio_mp3: malloc pcm \
- buf failed\n");
+ pr_err("audio_mp3: malloc pcm buf failed\n");
rc = -1;
} else {
uint8_t index;
diff --git a/drivers/staging/dream/smd/Makefile b/drivers/staging/dream/smd/Makefile
index 892c7414bbed..1c87618366a7 100644
--- a/drivers/staging/dream/smd/Makefile
+++ b/drivers/staging/dream/smd/Makefile
@@ -1,3 +1,4 @@
+EXTRA_CFLAGS=-Idrivers/staging/dream/include
obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
diff --git a/drivers/staging/dream/smd/smd_rpcrouter.c b/drivers/staging/dream/smd/smd_rpcrouter.c
index 5ac2cd4a5978..69911a7bc87a 100644
--- a/drivers/staging/dream/smd/smd_rpcrouter.c
+++ b/drivers/staging/dream/smd/smd_rpcrouter.c
@@ -38,8 +38,6 @@
#include <linux/platform_device.h>
#include <linux/uaccess.h>
-#include <asm/byteorder.h>
-
#include <mach/msm_smd.h>
#include "smd_rpcrouter.h"
diff --git a/drivers/staging/dt3155/Kconfig b/drivers/staging/dt3155/Kconfig
new file mode 100644
index 000000000000..4a3293c721b1
--- /dev/null
+++ b/drivers/staging/dt3155/Kconfig
@@ -0,0 +1,4 @@
+config DT3155
+ tristate "DT3155 Digitizer support"
+ depends on PCI
+
diff --git a/drivers/staging/dt3155/Makefile b/drivers/staging/dt3155/Makefile
new file mode 100644
index 000000000000..136f21fdbbee
--- /dev/null
+++ b/drivers/staging/dt3155/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_DT3155) += dt3155.o
+dt3155-objs := \
+ dt3155_drv.o \
+ dt3155_isr.o \
+ dt3155_io.o \
+ allocator.o
diff --git a/drivers/staging/dt3155/TODO b/drivers/staging/dt3155/TODO
new file mode 100644
index 000000000000..3baa3b6294cc
--- /dev/null
+++ b/drivers/staging/dt3155/TODO
@@ -0,0 +1,10 @@
+TODO:
+ - fix checkpatch.pl issues
+ - remove old kernel support, it is not needed
+ - convert to proper PCI device API
+ - fix sparse warnings
+ - audit for correct subsystem interaction
+ - review review review!
+
+Please send patches to Greg Kroah-Hartman <greg@kroah.com>
+and Scott Smedley <ss@aao.gov.au>
diff --git a/drivers/staging/dt3155/allocator.README b/drivers/staging/dt3155/allocator.README
new file mode 100644
index 000000000000..05700b6c926c
--- /dev/null
+++ b/drivers/staging/dt3155/allocator.README
@@ -0,0 +1,98 @@
+
+The allocator shown here exploits high memory. This document explains
+how a user can deal with drivers uses this allocator and how a
+programmer can link in the module.
+
+The module is being used by my pxc and pxdrv device drivers (as well as
+other ones), available from ftp.systemy.it/pub/develop and
+ftp.linux.it/pub/People/Rubini
+
+ User's manual
+ =============
+
+
+One of the most compelling problems with any DMA-capable device is the
+allocation of a suitable memory buffer. The "allocator" module tries
+to deal with the problem in a clean way. The module is able to use
+high memory (above the one used in normal operation) for DMA
+allocation.
+
+To prevent the kernel for using high memory, so that it remains
+available for DMA, you should pass a command line argument to the
+kernel. Command line arguments can be passed to Lilo, to Loadlin or
+to whichever loader you are using (unless it's very poor in design).
+For Lilo, either use "append=" in /etc/lilo.conf or add commandline
+arguments to the interactive prompt. For example, I have a 32MB box
+and reserve two megs for DMA:
+
+In lilo.conf:
+ image = /zImage
+ label = linux
+ append = "mem=30M"
+
+Or, interactively:
+ LILO: linux mem=30M
+
+Once the kernel is booted with the right command-line argument, any
+driver linked with the allocator module will be able to get
+DMA-capable memory without much trouble (unless the various drivers
+need more memory than available).
+
+The module implements an alloc/free mechanism, so that it can serve
+multiple drivers at the same time. Note however that the allocator
+uses all of high memory and assumes to be the only piece of software
+using such memory.
+
+
+ Programmer's manual
+ ===================
+
+The allocator, as released, is designed to be linked to a device
+driver. In this case, the driver must call allocator_init() before
+using the allocator and must call allocator_cleanup() before
+unloading. This is usually done from within init_module() and
+cleanup_module(). If the allocator is linked to a driver, it won't be
+possible for several drivers to allocate high DMA memory, as explained
+above.
+
+It is possible, on the other hand, to compile the module as a standalone
+module, so that several modules can rely on the allocator for they DMA
+buffers. To compile the allocator as a standalone module, do the
+following in this directory (or provide a suitable Makefile, or edit
+the source code):
+
+ make allocator.o CC="gcc -Dallocator_init=init_module -Dallocator_cleanup=cleanup_module -include /usr/include/linux/module.h"
+
+The previous commandline tells to include <linux/module.h> in the
+first place, and to rename the init and cleanup function to the ones
+needed for module loading and unloading. Drivers using a standalone
+allocator won't need to call allocator_init() nor allocator_cleanup().
+
+The allocator exports the following functions (declared in allocator.h):
+
+ unsigned long allocator_allocate_dma (unsigned long kilobytes,
+ int priority);
+
+ This function returns a physical address, over high_memory,
+ which corresponds to an area of at least "kilobytes" kilobytes.
+ The area will be owned by the module calling the function.
+ The returned address can be passed to device boards, to instruct
+ their DMA controllers, via phys_to_bus(). The address can be used
+ by C code after vremap()/ioremap(). The "priority" argument should
+ be GFP_KERNEL or GFP_ATOMIC, according to the context of the
+ caller; it is used to call kmalloc(), as the allocator must keep
+ track of any region it gives away. In case of error the function
+ returns 0, and the caller is expected to issue a -ENOMEM error.
+
+
+ void allocator_free_dma (unsigned long address);
+
+ This function is the reverse of the previous one. If a driver
+ doesn't free the DMA memory it allocated, the allocator will
+ consider such memory as busy. Note, however, that
+ allocator_cleanup() calls kfree() on every region it reclaimed,
+ so that a driver with the allocator linked in can avoid calling
+ allocator_free_dma() at unload time.
+
+
+
diff --git a/drivers/staging/dt3155/allocator.c b/drivers/staging/dt3155/allocator.c
new file mode 100644
index 000000000000..c74234c66895
--- /dev/null
+++ b/drivers/staging/dt3155/allocator.c
@@ -0,0 +1,295 @@
+/*
+ * allocator.c -- allocate after high_memory, if available
+ *
+ * NOTE: this is different from my previous allocator, the one that
+ * assembles pages, which revealed itself both slow and unreliable.
+ *
+ * Copyright (C) 1998 rubini@linux.it (Alessandro Rubini)
+ *
+ * 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.
+ *
+
+-- Changes --
+
+ Date Programmer Description of changes made
+ -------------------------------------------------------------------
+ 02-Aug-2002 NJC allocator now steps in 1MB increments, rather
+ than doubling its size each time.
+ Also, allocator_init(u32 *) now returns
+ (in the first arg) the size of the free
+ space. This is no longer consistent with
+ using the allocator as a module, and some changes
+ may be necessary for that purpose. This was
+ designed to work with the DT3155 driver, in
+ stand alone mode only!!!
+ 26-Oct-2009 SS Port to 2.6.30 kernel.
+ */
+
+
+#ifndef __KERNEL__
+# define __KERNEL__
+#endif
+#ifndef MODULE
+# define MODULE
+#endif
+
+#include <linux/version.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mm.h> /* PAGE_ALIGN() */
+#include <linux/io.h>
+
+#include <asm/page.h>
+
+/*#define ALL_DEBUG*/
+#define ALL_MSG "allocator: "
+
+#undef PDEBUG /* undef it, just in case */
+#ifdef ALL_DEBUG
+# define __static
+# define DUMP_LIST() dump_list()
+# ifdef __KERNEL__
+ /* This one if debugging is on, and kernel space */
+# define PDEBUG(fmt, args...) printk(KERN_DEBUG ALL_MSG fmt, ## args)
+# else
+ /* This one for user space */
+# define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
+# endif
+#else
+# define PDEBUG(fmt, args...) /* not debugging: nothing */
+# define DUMP_LIST()
+# define __static static
+#endif
+
+#undef PDEBUGG
+#define PDEBUGG(fmt, args...)
+/*#define PDEBUGG(fmt, args...) printk( KERN_DEBUG ALL_MSG fmt, ## args)*/
+
+
+int allocator_himem = 1; /* 0 = probe, pos. = megs, neg. = disable */
+int allocator_step = 1; /* This is the step size in MB */
+int allocator_probe = 1; /* This is a flag -- 1=probe, 0=don't probe */
+
+static unsigned long allocator_buffer; /* physical address */
+static unsigned long allocator_buffer_size; /* kilobytes */
+
+/*
+ * The allocator keeps a list of DMA areas, so multiple devices
+ * can coexist. The list is kept sorted by address
+ */
+
+struct allocator_struct {
+ unsigned long address;
+ unsigned long size;
+ struct allocator_struct *next;
+};
+
+struct allocator_struct *allocator_list;
+
+
+#ifdef ALL_DEBUG
+static int dump_list(void)
+{
+ struct allocator_struct *ptr;
+
+ PDEBUG("Current list:\n");
+ for (ptr = allocator_list; ptr; ptr = ptr->next)
+ PDEBUG("0x%08lx (size %likB)\n", ptr->address, ptr->size>>10);
+ return 0;
+}
+#endif
+
+/* ========================================================================
+ * This function is the actual allocator.
+ *
+ * If space is available in high memory (as detected at load time), that
+ * one is returned. The return value is a physical address (i.e., it can
+ * be used straight ahead for DMA, but needs remapping for program use).
+ */
+
+unsigned long allocator_allocate_dma(unsigned long kilobytes, int prio)
+{
+ struct allocator_struct *ptr = allocator_list, *newptr;
+ unsigned long bytes = kilobytes << 10;
+
+ /* check if high memory is available */
+ if (!allocator_buffer)
+ return 0;
+
+ /* Round it to a multiple of the pagesize */
+ bytes = PAGE_ALIGN(bytes);
+ PDEBUG("request for %li bytes\n", bytes);
+
+ while (ptr && ptr->next) {
+ if (ptr->next->address - (ptr->address + ptr->size) >= bytes)
+ break; /* enough space */
+ ptr = ptr->next;
+ }
+ if (!ptr->next) {
+ DUMP_LIST();
+ PDEBUG("alloc failed\n");
+ return 0; /* end of list */
+ }
+ newptr = kmalloc(sizeof(struct allocator_struct), prio);
+ if (!newptr)
+ return 0;
+
+ /* ok, now stick it after ptr */
+ newptr->address = ptr->address + ptr->size;
+ newptr->size = bytes;
+ newptr->next = ptr->next;
+ ptr->next = newptr;
+
+ DUMP_LIST();
+ PDEBUG("returning 0x%08lx\n", newptr->address);
+ return newptr->address;
+}
+
+int allocator_free_dma(unsigned long address)
+{
+ struct allocator_struct *ptr = allocator_list, *prev;
+
+ while (ptr && ptr->next) {
+ if (ptr->next->address == address)
+ break;
+ ptr = ptr->next;
+ }
+ /* the one being freed is ptr->next */
+ prev = ptr; ptr = ptr->next;
+
+ if (!ptr) {
+ printk(KERN_ERR ALL_MSG
+ "free_dma(0x%08lx) but add. not allocated\n",
+ ptr->address);
+ return -EINVAL;
+ }
+ PDEBUGG("freeing: %08lx (%li) next %08lx\n", ptr->address, ptr->size,
+ ptr->next->address);
+ prev->next = ptr->next;
+ kfree(ptr);
+
+ /* dump_list(); */
+ return 0;
+}
+
+/* ========================================================================
+ * Init and cleanup
+ *
+ * On cleanup everything is released. If the list is not empty, that a
+ * problem of our clients
+ */
+int allocator_init(u32 *allocator_max)
+{
+ /* check how much free memory is there */
+ void *remapped;
+ unsigned long max;
+ unsigned long trial_size = allocator_himem<<20;
+ unsigned long last_trial = 0;
+ unsigned long step = allocator_step<<20;
+ unsigned long i = 0;
+ struct allocator_struct *head, *tail;
+ char test_string[] = "0123456789abcde"; /* 16 bytes */
+
+ PDEBUGG("himem = %i\n", allocator_himem);
+ if (allocator_himem < 0) /* don't even try */
+ return -EINVAL;
+
+ if (!trial_size)
+ trial_size = 1<<20; /* not specified: try one meg */
+
+ while (1) {
+ remapped = ioremap(__pa(high_memory), trial_size);
+ if (!remapped) {
+ PDEBUGG("%li megs failed!\n", trial_size>>20);
+ break;
+ }
+ PDEBUGG("Trying %li megs (at %p, %p)\n", trial_size>>20,
+ (void *)__pa(high_memory), remapped);
+ for (i = last_trial; i < trial_size; i += 16) {
+ strcpy((char *)(remapped)+i, test_string);
+ if (strcmp((char *)(remapped)+i, test_string))
+ break;
+ }
+ iounmap((void *)remapped);
+ schedule();
+ last_trial = trial_size;
+ if (i == trial_size)
+ trial_size += step; /* increment, if all went well */
+ else {
+ PDEBUGG("%li megs copy test failed!\n", trial_size>>20);
+ break;
+ }
+ if (!allocator_probe)
+ break;
+ }
+ PDEBUG("%li megs (%li k, %li b)\n", i>>20, i>>10, i);
+ allocator_buffer_size = i>>10; /* kilobytes */
+ allocator_buffer = __pa(high_memory);
+ if (!allocator_buffer_size) {
+ printk(KERN_WARNING ALL_MSG "no free high memory to use\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * to simplify things, always have two cells in the list:
+ * the first and the last. This avoids some conditionals and
+ * extra code when allocating and deallocating: we only play
+ * in the middle of the list
+ */
+ head = kmalloc(sizeof(struct allocator_struct), GFP_KERNEL);
+ if (!head)
+ return -ENOMEM;
+ tail = kmalloc(sizeof(struct allocator_struct), GFP_KERNEL);
+ if (!tail) {
+ kfree(head);
+ return -ENOMEM;
+ }
+
+ max = allocator_buffer_size<<10;
+
+ head->size = tail->size = 0;
+ head->address = allocator_buffer;
+ tail->address = allocator_buffer + max;
+ head->next = tail;
+ tail->next = NULL;
+ allocator_list = head;
+
+ /* Back to the user code, in KB */
+ *allocator_max = allocator_buffer_size;
+
+ return 0; /* ok, ready */
+}
+
+void allocator_cleanup(void)
+{
+ struct allocator_struct *ptr, *next;
+
+ for (ptr = allocator_list; ptr; ptr = next) {
+ next = ptr->next;
+ PDEBUG("freeing list: 0x%08lx\n", ptr->address);
+ kfree(ptr);
+ }
+
+ allocator_buffer = 0;
+ allocator_buffer_size = 0;
+ allocator_list = NULL;
+}
+
+
diff --git a/drivers/staging/dt3155/allocator.h b/drivers/staging/dt3155/allocator.h
new file mode 100644
index 000000000000..bdf3268ca52d
--- /dev/null
+++ b/drivers/staging/dt3155/allocator.h
@@ -0,0 +1,28 @@
+/*
+ * allocator.h -- prototypes for allocating high memory
+ *
+ * NOTE: this is different from my previous allocator, the one that
+ * assembles pages, which revealed itself both slow and unreliable.
+ *
+ * Copyright (C) 1998 rubini@linux.it (Alessandro Rubini)
+ *
+ * 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.
+ *
+ */
+
+void allocator_free_dma(unsigned long address);
+unsigned long allocator_allocate_dma(unsigned long kilobytes, int priority);
+int allocator_init(u32 *);
+void allocator_cleanup(void);
diff --git a/drivers/staging/dt3155/dt3155.h b/drivers/staging/dt3155/dt3155.h
new file mode 100644
index 000000000000..1bf786364eec
--- /dev/null
+++ b/drivers/staging/dt3155/dt3155.h
@@ -0,0 +1,171 @@
+/*
+
+Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
+ Jason Lapenta, Scott Smedley
+
+This file is part of the DT3155 Device Driver.
+
+The DT3155 Device Driver 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.
+
+The DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+MA 02111-1307 USA
+
+-- Changes --
+
+ Date Programmer Description of changes made
+ -------------------------------------------------------------------
+ 03-Jul-2000 JML n/a
+ 10-Oct-2001 SS port to 2.4 kernel.
+ 24-Jul-2002 SS remove unused code & added GPL licence.
+ 05-Aug-2005 SS port to 2.6 kernel; make CCIR mode default.
+
+*/
+
+#ifndef _DT3155_INC
+#define _DT3155_INC
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/time.h> /* struct timeval */
+#else
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+
+#define TRUE 1
+#define FALSE 0
+
+/* Uncomment this for 50Hz CCIR */
+#define CCIR 1
+
+/* Can be 1 or 2 */
+#define MAXBOARDS 1
+
+#define BOARD_MAX_BUFFS 3
+#define MAXBUFFERS (BOARD_MAX_BUFFS*MAXBOARDS)
+
+#define PCI_PAGE_SIZE (1 << 12)
+
+#ifdef CCIR
+#define DT3155_MAX_ROWS 576
+#define DT3155_MAX_COLS 768
+#define FORMAT50HZ TRUE
+#else
+#define DT3155_MAX_ROWS 480
+#define DT3155_MAX_COLS 640
+#define FORMAT50HZ FALSE
+#endif
+
+/* Configuration structure */
+struct dt3155_config_s {
+ u32 acq_mode;
+ u32 cols, rows;
+ u32 continuous;
+};
+
+
+/* hold data for each frame */
+typedef struct {
+ u32 addr; /* address of the buffer with the frame */
+ u32 tag; /* unique number for the frame */
+ struct timeval time; /* time that capture took place */
+} frame_info_t;
+
+/*
+ * Structure for interrupt and buffer handling.
+ * This is the setup for 1 card
+ */
+struct dt3155_fbuffer_s {
+ int nbuffers;
+
+ frame_info_t frame_info[BOARD_MAX_BUFFS];
+
+ int empty_buffers[BOARD_MAX_BUFFS]; /* indexes empty frames */
+ int empty_len; /* Number of empty buffers */
+ /* Zero means empty */
+
+ int active_buf; /* Where data is currently dma'ing */
+ int locked_buf; /* Buffers used by user */
+
+ int ready_que[BOARD_MAX_BUFFS];
+ u32 ready_head; /* The most recent buffer located here */
+ u32 ready_len; /* The number of ready buffers */
+
+ int even_happened;
+ int even_stopped;
+
+ int stop_acquire; /* Flag to stop interrupts */
+ u32 frame_count; /* Counter for frames acquired by this card */
+};
+
+
+
+#define DT3155_MODE_FRAME 1
+#define DT3155_MODE_FIELD 2
+
+#define DT3155_SNAP 1
+#define DT3155_ACQ 2
+
+/* There is one status structure for each card. */
+typedef struct dt3155_status_s {
+ int fixed_mode; /* if 1, we are in fixed frame mode */
+ u32 reg_addr; /* Register address for a single card */
+ u32 mem_addr; /* Buffer start addr for this card */
+ u32 mem_size; /* This is the amount of mem available */
+ u32 irq; /* this card's irq */
+ struct dt3155_config_s config; /* configuration struct */
+ struct dt3155_fbuffer_s fbuffer; /* frame buffer state struct */
+ u32 state; /* this card's state */
+ u32 device_installed; /* Flag if installed. 1=installed */
+} dt3155_status_t;
+
+/* Reference to global status structure */
+extern struct dt3155_status_s dt3155_status[MAXBOARDS];
+
+#define DT3155_STATE_IDLE 0x00
+#define DT3155_STATE_FRAME 0x01
+#define DT3155_STATE_FLD 0x02
+#define DT3155_STATE_STOP 0x100
+#define DT3155_STATE_ERROR 0x200
+#define DT3155_STATE_MODE 0x0ff
+
+#define DT3155_IOC_MAGIC '!'
+
+#define DT3155_SET_CONFIG _IOW(DT3155_IOC_MAGIC, 1, struct dt3155_config_s)
+#define DT3155_GET_CONFIG _IOR(DT3155_IOC_MAGIC, 2, struct dt3155_status_s)
+#define DT3155_STOP _IO(DT3155_IOC_MAGIC, 3)
+#define DT3155_START _IO(DT3155_IOC_MAGIC, 4)
+#define DT3155_FLUSH _IO(DT3155_IOC_MAGIC, 5)
+#define DT3155_IOC_MAXNR 5
+
+/* Error codes */
+
+#define DT_ERR_NO_BUFFERS 0x10000 /* not used but it might be one day */
+#define DT_ERR_CORRUPT 0x20000
+#define DT_ERR_OVERRUN 0x30000
+#define DT_ERR_I2C_TIMEOUT 0x40000
+#define DT_ERR_MASK 0xff0000/* not used but it might be one day */
+
+/* User code will probably want to declare one of these for each card */
+typedef struct dt3155_read_s {
+ u32 offset;
+ u32 frame_seq;
+ u32 state;
+
+ frame_info_t frame_info;
+} dt3155_read_t;
+
+#endif /* _DT3155_inc */
diff --git a/drivers/staging/dt3155/dt3155.sysvinit b/drivers/staging/dt3155/dt3155.sysvinit
new file mode 100644
index 000000000000..92ec0939cb7a
--- /dev/null
+++ b/drivers/staging/dt3155/dt3155.sysvinit
@@ -0,0 +1,60 @@
+#! /bin/sh
+#
+# Module load/unload script for use with SysV-style /etc/init.d/ systems.
+# On a Debian system, copy this to /etc/init.d/dt3155 and then run
+# /usr/sbin/update-rc.d dt3155 defaults 55
+# to create the appropriate /etc/rc?.d/[SK]55dt3155 start/stop links.
+# (The "55" is arbitrary but is what I use to load this rather late.)
+#
+# Andy Dougherty Feb 22 2000 doughera@lafayette.edu
+# Dept. of Physics
+# Lafayette College, Easton PA 18042
+#
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+
+# Edit to point to your local copy.
+FILE=/usr/local/lib/modules/dt3155/dt3155.o
+NAME="dt3155"
+DESC="dt3155 Frame Grabber module"
+DEV="dt3155"
+
+if test ! -f $FILE; then
+ echo "Unable to locate $FILE"
+ exit 0
+fi
+
+set -e
+
+case "$1" in
+ start)
+ echo -n "Loading $DESC "
+ if /sbin/insmod -v -f $FILE; then
+ major=`grep $DEV /proc/devices | awk "{print \\$1}"`
+ rm -f /dev/dt3155?
+ mknod /dev/dt3155a c $major 0
+ mknod /dev/dt3155b c $major 1
+ chmod go+rw /dev/dt3155?
+ echo
+ else
+ echo "$FILE not loaded."
+ fi
+ ;;
+ stop)
+ echo -n "Unloading $DESC: "
+ if /sbin/rmmod $NAME ; then
+ echo
+ else
+ echo "$DEV not removed"
+ exit 0
+ fi
+ rm -f /dev/dt3155?
+ ;;
+ *)
+ echo "Usage: /etc/init.d/$NAME {start|stop}"
+ exit 1
+ ;;
+esac
+
+exit 0
+
diff --git a/drivers/staging/dt3155/dt3155_drv.c b/drivers/staging/dt3155/dt3155_drv.c
new file mode 100644
index 000000000000..a67c622869d2
--- /dev/null
+++ b/drivers/staging/dt3155/dt3155_drv.c
@@ -0,0 +1,1095 @@
+/*
+
+Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
+ Jason Lapenta, Scott Smedley, Greg Sharp
+
+This file is part of the DT3155 Device Driver.
+
+The DT3155 Device Driver 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.
+
+The DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+MA 02111-1307 USA
+
+-- Changes --
+
+ Date Programmer Description of changes made
+ -------------------------------------------------------------------
+ 03-Jul-2000 JML n/a
+ 10-Oct-2001 SS port to 2.4 kernel
+ 02-Apr-2002 SS Mods to use allocator as a standalone module;
+ Merged John Roll's changes (john@cfa.harvard.edu)
+ to make work with multiple boards.
+ 02-Jul-2002 SS Merged James Rose's chages (rosejr@purdue.edu) to:
+ * fix successive interrupt-driven captures
+ * add select/poll support.
+ 10-Jul-2002 GCS Add error check when ndevices > MAXBOARDS.
+ 02-Aug-2002 GCS Fix field mode so that odd (lower) field is stored
+ in lower half of buffer.
+ 05-Aug-2005 SS port to 2.6 kernel.
+ 26-Oct-2009 SS port to 2.6.30 kernel.
+
+-- Notes --
+
+** appended "mem=124" in lilo.conf to allow for 4megs free on my 128meg system.
+ * using allocator.c and allocator.h from o'reilly book (alessandro rubini)
+ ftp://ftp.systemy.it/pub/develop (see README.allocator)
+
+ + might want to get rid of MAXboards for allocating initial buffer.
+ confusing and not necessary
+
+ + in cleanup_module the MOD_IN_USE looks like it is check after it should
+
+ * GFP_DMA should not be set with a PCI system (pg 291)
+
+ - NJC why are only two buffers allowed? (see isr, approx line 358)
+
+*/
+
+extern void printques(int);
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/interrupt.h>
+
+
+MODULE_LICENSE("GPL");
+
+#endif
+
+#ifndef CONFIG_PCI
+#error "DT3155 : Kernel PCI support not enabled (DT3155 drive requires PCI)"
+#endif
+
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include "dt3155.h"
+#include "dt3155_drv.h"
+#include "dt3155_isr.h"
+#include "dt3155_io.h"
+#include "allocator.h"
+
+/* Error variable. Zero means no error. */
+int dt3155_errno = 0;
+
+#ifndef PCI_DEVICE_ID_INTEL_7116
+#define PCI_DEVICE_ID_INTEL_7116 0x1223
+#endif
+
+#define DT3155_VENDORID PCI_VENDOR_ID_INTEL
+#define DT3155_DEVICEID PCI_DEVICE_ID_INTEL_7116
+#define MAXPCI 16
+
+#ifdef DT_DEBUG
+#define DT_3155_DEBUG_MSG(x,y) printk(x,y)
+#else
+#define DT_3155_DEBUG_MSG(x,y)
+#endif
+
+/* wait queue for interrupts */
+wait_queue_head_t dt3155_read_wait_queue[ MAXBOARDS ];
+
+#define DT_3155_SUCCESS 0
+#define DT_3155_FAILURE -EIO
+
+/* set to dynamicaly allocate, but it is tunable: */
+/* insmod DT_3155 dt3155 dt3155_major=XX */
+int dt3155_major = 0;
+
+/* The minor numbers are 0 and 1 ... they are not tunable.
+ * They are used as the indices for the structure vectors,
+ * and register address vectors
+ */
+
+/* Global structures and variables */
+
+/* Status of each device */
+struct dt3155_status_s dt3155_status[ MAXBOARDS ];
+
+/* kernel logical address of the board */
+u8 *dt3155_lbase[ MAXBOARDS ] = { NULL
+#if MAXBOARDS == 2
+ , NULL
+#endif
+};
+/* DT3155 registers */
+u8 *dt3155_bbase = NULL; /* kernel logical address of the *
+ * buffer region */
+u32 dt3155_dev_open[ MAXBOARDS ] = {0
+#if MAXBOARDS == 2
+ , 0
+#endif
+};
+
+u32 ndevices = 0;
+u32 unique_tag = 0;;
+
+
+/*
+ * Stops interrupt generation right away and resets the status
+ * to idle. I don't know why this works and the other way doesn't.
+ * (James Rose)
+ */
+static void quick_stop (int minor)
+{
+ // TODO: scott was here
+#if 1
+ ReadMReg((dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg);
+ /* disable interrupts */
+ int_csr_r.fld.FLD_END_EVE_EN = 0;
+ int_csr_r.fld.FLD_END_ODD_EN = 0;
+ WriteMReg((dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
+
+ dt3155_status[ minor ].state &= ~(DT3155_STATE_STOP|0xff);
+ /* mark the system stopped: */
+ dt3155_status[ minor ].state |= DT3155_STATE_IDLE;
+ dt3155_fbuffer[ minor ]->stop_acquire = 0;
+ dt3155_fbuffer[ minor ]->even_stopped = 0;
+#else
+ dt3155_status[minor].state |= DT3155_STATE_STOP;
+ dt3155_status[minor].fbuffer.stop_acquire = 1;
+#endif
+
+}
+
+
+/*****************************************************
+ * dt3155_isr() Interrupt service routien
+ *
+ * - looks like this isr supports IRQ sharing (or could) JML
+ * - Assumes irq's are disabled, via SA_INTERRUPT flag
+ * being set in request_irq() call from init_module()
+ *****************************************************/
+static inline void dt3155_isr( int irq, void *dev_id, struct pt_regs *regs )
+{
+ int minor = -1;
+ int index;
+ unsigned long flags;
+ u32 buffer_addr;
+
+ /* find out who issued the interrupt */
+ for ( index = 0; index < ndevices; index++ ) {
+ if( dev_id == (void*) &dt3155_status[ index ])
+ {
+ minor = index;
+ break;
+ }
+ }
+
+ /* hopefully we should not get here */
+ if ( minor < 0 || minor >= MAXBOARDS ) {
+ printk(KERN_ERR "dt3155_isr called with invalid dev_id\n");
+ return;
+ }
+
+ /* Check for corruption and set a flag if so */
+ ReadMReg( (dt3155_lbase[ minor ] + CSR1), csr1_r.reg );
+
+ if ( (csr1_r.fld.FLD_CRPT_EVE) || (csr1_r.fld.FLD_CRPT_ODD) )
+ {
+ /* TODO: this should probably stop acquisition */
+ /* and set some flags so that dt3155_read */
+ /* returns an error next time it is called */
+ dt3155_errno = DT_ERR_CORRUPT;
+ printk("dt3155: corrupt field\n");
+ return;
+ }
+
+ ReadMReg((dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg);
+
+ /* Handle the even field ... */
+ if (int_csr_r.fld.FLD_END_EVE)
+ {
+ if ( (dt3155_status[ minor ].state & DT3155_STATE_MODE) ==
+ DT3155_STATE_FLD )
+ {
+ dt3155_fbuffer[ minor ]->frame_count++;
+ }
+
+ ReadI2C(dt3155_lbase[ minor ], EVEN_CSR, &i2c_even_csr.reg);
+
+ /* Clear the interrupt? */
+ int_csr_r.fld.FLD_END_EVE = 1;
+
+ /* disable the interrupt if last field */
+ if (dt3155_fbuffer[ minor ]->stop_acquire)
+ {
+ printk("dt3155: even stopped.\n");
+ dt3155_fbuffer[ minor ]->even_stopped = 1;
+ if (i2c_even_csr.fld.SNGL_EVE)
+ {
+ int_csr_r.fld.FLD_END_EVE_EN = 0;
+ }
+ else
+ {
+ i2c_even_csr.fld.SNGL_EVE = 1;
+ }
+ }
+
+ WriteMReg( (dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
+
+ /* Set up next DMA if we are doing FIELDS */
+ if ( (dt3155_status[ minor ].state & DT3155_STATE_MODE ) ==
+ DT3155_STATE_FLD)
+ {
+ /* GCS (Aug 2, 2002) -- In field mode, dma the odd field
+ into the lower half of the buffer */
+ const u32 stride = dt3155_status[ minor ].config.cols;
+ buffer_addr = dt3155_fbuffer[ minor ]->
+ frame_info[ dt3155_fbuffer[ minor ]->active_buf ].addr
+ + (DT3155_MAX_ROWS / 2) * stride;
+ local_save_flags(flags);
+ local_irq_disable();
+ wake_up_interruptible( &dt3155_read_wait_queue[ minor ] );
+
+ /* Set up the DMA address for the next field */
+ local_irq_restore(flags);
+ WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_START), buffer_addr);
+ }
+
+ /* Check for errors. */
+ i2c_even_csr.fld.DONE_EVE = 1;
+ if ( i2c_even_csr.fld.ERROR_EVE )
+ dt3155_errno = DT_ERR_OVERRUN;
+
+ WriteI2C( dt3155_lbase[ minor ], EVEN_CSR, i2c_even_csr.reg );
+
+ /* Note that we actually saw an even field meaning */
+ /* that subsequent odd field complete the frame */
+ dt3155_fbuffer[ minor ]->even_happened = 1;
+
+ /* recording the time that the even field finished, this should be */
+ /* about time in the middle of the frame */
+ do_gettimeofday( &(dt3155_fbuffer[ minor ]->
+ frame_info[ dt3155_fbuffer[ minor ]->
+ active_buf ].time) );
+ return;
+ }
+
+ /* ... now handle the odd field */
+ if ( int_csr_r.fld.FLD_END_ODD )
+ {
+ ReadI2C( dt3155_lbase[ minor ], ODD_CSR, &i2c_odd_csr.reg );
+
+ /* Clear the interrupt? */
+ int_csr_r.fld.FLD_END_ODD = 1;
+
+ if (dt3155_fbuffer[ minor ]->even_happened ||
+ (dt3155_status[ minor ].state & DT3155_STATE_MODE) ==
+ DT3155_STATE_FLD)
+ {
+ dt3155_fbuffer[ minor ]->frame_count++;
+ }
+
+ if ( dt3155_fbuffer[ minor ]->stop_acquire &&
+ dt3155_fbuffer[ minor ]->even_stopped )
+ {
+ printk(KERN_DEBUG "dt3155: stopping odd..\n");
+ if ( i2c_odd_csr.fld.SNGL_ODD )
+ {
+ /* disable interrupts */
+ int_csr_r.fld.FLD_END_ODD_EN = 0;
+ dt3155_status[ minor ].state &= ~(DT3155_STATE_STOP|0xff);
+
+ /* mark the system stopped: */
+ dt3155_status[ minor ].state |= DT3155_STATE_IDLE;
+ dt3155_fbuffer[ minor ]->stop_acquire = 0;
+ dt3155_fbuffer[ minor ]->even_stopped = 0;
+
+ printk(KERN_DEBUG "dt3155: state is now %x\n",
+ dt3155_status[minor].state);
+ }
+ else
+ {
+ i2c_odd_csr.fld.SNGL_ODD = 1;
+ }
+ }
+
+ WriteMReg( (dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
+
+ /* if the odd field has been acquired, then */
+ /* change the next dma location for both fields */
+ /* and wake up the process if sleeping */
+ if ( dt3155_fbuffer[ minor ]->even_happened ||
+ (dt3155_status[ minor ].state & DT3155_STATE_MODE) ==
+ DT3155_STATE_FLD )
+ {
+
+ local_save_flags(flags);
+ local_irq_disable();
+
+#ifdef DEBUG_QUES_B
+ printques( minor );
+#endif
+ if ( dt3155_fbuffer[ minor ]->nbuffers > 2 )
+ {
+ if ( !are_empty_buffers( minor ) )
+ {
+ /* The number of active + locked buffers is
+ * at most 2, and since there are none empty, there
+ * must be at least nbuffers-2 ready buffers.
+ * This is where we 'drop frames', oldest first. */
+ push_empty( pop_ready( minor ), minor );
+ }
+
+ /* The ready_que can't be full, since we know
+ * there is one active buffer right now, so it's safe
+ * to push the active buf on the ready_que. */
+ push_ready( minor, dt3155_fbuffer[ minor ]->active_buf );
+ /* There's at least 1 empty -- make it active */
+ dt3155_fbuffer[ minor ]->active_buf = pop_empty( minor );
+ dt3155_fbuffer[ minor ]->
+ frame_info[ dt3155_fbuffer[ minor ]->
+ active_buf ].tag = ++unique_tag;
+ }
+ else /* nbuffers == 2, special case */
+ { /* There is 1 active buffer.
+ * If there is a locked buffer, keep the active buffer
+ * the same -- that means we drop a frame.
+ */
+ if ( dt3155_fbuffer[ minor ]->locked_buf < 0 )
+ {
+ push_ready( minor,
+ dt3155_fbuffer[ minor ]->active_buf );
+ if (are_empty_buffers( minor ) )
+ {
+ dt3155_fbuffer[ minor ]->active_buf =
+ pop_empty( minor );
+ }
+ else
+ { /* no empty or locked buffers, so use a readybuf */
+ dt3155_fbuffer[ minor ]->active_buf =
+ pop_ready( minor );
+ }
+ }
+ }
+
+#ifdef DEBUG_QUES_B
+ printques( minor );
+#endif
+
+ dt3155_fbuffer[ minor ]->even_happened = 0;
+
+ wake_up_interruptible( &dt3155_read_wait_queue[ minor ] );
+
+ local_irq_restore(flags);
+ }
+
+
+ /* Set up the DMA address for the next frame/field */
+ buffer_addr = dt3155_fbuffer[ minor ]->
+ frame_info[ dt3155_fbuffer[ minor ]->active_buf ].addr;
+ if ( (dt3155_status[ minor ].state & DT3155_STATE_MODE) ==
+ DT3155_STATE_FLD )
+ {
+ WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START), buffer_addr);
+ }
+ else
+ {
+ WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START), buffer_addr);
+
+ WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_START), buffer_addr
+ + dt3155_status[ minor ].config.cols);
+ }
+
+ /* Do error checking */
+ i2c_odd_csr.fld.DONE_ODD = 1;
+ if ( i2c_odd_csr.fld.ERROR_ODD )
+ dt3155_errno = DT_ERR_OVERRUN;
+
+ WriteI2C(dt3155_lbase[ minor ], ODD_CSR, i2c_odd_csr.reg );
+
+ return;
+ }
+ /* If we get here, the Odd Field wasn't it either... */
+ printk( "neither even nor odd. shared perhaps?\n");
+}
+
+/*****************************************************
+ * init_isr(int minor)
+ * turns on interupt generation for the card
+ * designated by "minor".
+ * It is called *only* from inside ioctl().
+ *****************************************************/
+static void dt3155_init_isr(int minor)
+{
+ const u32 stride = dt3155_status[ minor ].config.cols;
+
+ switch (dt3155_status[ minor ].state & DT3155_STATE_MODE)
+ {
+ case DT3155_STATE_FLD:
+ {
+ even_dma_start_r = dt3155_status[ minor ].
+ fbuffer.frame_info[ dt3155_status[ minor ].fbuffer.active_buf ].addr;
+ even_dma_stride_r = 0;
+ odd_dma_stride_r = 0;
+
+ WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START),
+ even_dma_start_r);
+ WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_STRIDE),
+ even_dma_stride_r);
+ WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_STRIDE),
+ odd_dma_stride_r);
+ break;
+ }
+
+ case DT3155_STATE_FRAME:
+ default:
+ {
+ even_dma_start_r = dt3155_status[ minor ].
+ fbuffer.frame_info[ dt3155_status[ minor ].fbuffer.active_buf ].addr;
+ odd_dma_start_r = even_dma_start_r + stride;
+ even_dma_stride_r = stride;
+ odd_dma_stride_r = stride;
+
+ WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_START),
+ even_dma_start_r);
+ WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_START),
+ odd_dma_start_r);
+ WriteMReg((dt3155_lbase[ minor ] + EVEN_DMA_STRIDE),
+ even_dma_stride_r);
+ WriteMReg((dt3155_lbase[ minor ] + ODD_DMA_STRIDE),
+ odd_dma_stride_r);
+ break;
+ }
+ }
+
+ /* 50/60 Hz should be set before this point but let's make sure it is */
+ /* right anyway */
+
+ ReadI2C(dt3155_lbase[ minor ], CONFIG, &i2c_csr2.reg);
+ i2c_csr2.fld.HZ50 = FORMAT50HZ;
+ WriteI2C(dt3155_lbase[ minor ], CONFIG, i2c_config.reg);
+
+ /* enable busmaster chip, clear flags */
+
+ /*
+ * TODO:
+ * shouldn't we be concered with continuous values of
+ * DT3155_SNAP & DT3155_ACQ here? (SS)
+ */
+
+ csr1_r.reg = 0;
+ csr1_r.fld.CAP_CONT_EVE = 1; /* use continuous capture bits to */
+ csr1_r.fld.CAP_CONT_ODD = 1; /* enable */
+ csr1_r.fld.FLD_DN_EVE = 1; /* writing a 1 clears flags */
+ csr1_r.fld.FLD_DN_ODD = 1;
+ csr1_r.fld.SRST = 1; /* reset - must be 1 */
+ csr1_r.fld.FIFO_EN = 1; /* fifo control - must be 1 */
+ csr1_r.fld.FLD_CRPT_EVE = 1; /* writing a 1 clears flags */
+ csr1_r.fld.FLD_CRPT_ODD = 1;
+
+ WriteMReg((dt3155_lbase[ minor ] + CSR1),csr1_r.reg);
+
+ /* Enable interrupts at the end of each field */
+
+ int_csr_r.reg = 0;
+ int_csr_r.fld.FLD_END_EVE_EN = 1;
+ int_csr_r.fld.FLD_END_ODD_EN = 1;
+ int_csr_r.fld.FLD_START_EN = 0;
+
+ WriteMReg((dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg);
+
+ /* start internal BUSY bits */
+
+ ReadI2C(dt3155_lbase[ minor ], CSR2, &i2c_csr2.reg);
+ i2c_csr2.fld.BUSY_ODD = 1;
+ i2c_csr2.fld.BUSY_EVE = 1;
+ WriteI2C(dt3155_lbase[ minor ], CSR2, i2c_csr2.reg);
+
+ /* Now its up to the interrupt routine!! */
+
+ return;
+}
+
+
+/*****************************************************
+ * ioctl()
+ *
+ *****************************************************/
+static int dt3155_ioctl(struct inode *inode,
+ struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ int minor = MINOR(inode->i_rdev); /* What device are we ioctl()'ing? */
+
+ if ( minor >= MAXBOARDS || minor < 0 )
+ return -ENODEV;
+
+ /* make sure it is valid command */
+ if (_IOC_NR(cmd) > DT3155_IOC_MAXNR)
+ {
+ printk("DT3155: invalid IOCTL(0x%x)\n",cmd);
+ printk("DT3155: Valid commands (0x%x), (0x%x), (0x%x), (0x%x), (0x%x)\n",
+ (unsigned int)DT3155_GET_CONFIG,
+ (unsigned int)DT3155_SET_CONFIG,
+ (unsigned int)DT3155_START,
+ (unsigned int)DT3155_STOP,
+ (unsigned int)DT3155_FLUSH);
+ return -EINVAL;
+ }
+
+ switch (cmd)
+ {
+ case DT3155_SET_CONFIG:
+ {
+ if (dt3155_status[minor].state != DT3155_STATE_IDLE)
+ return -EBUSY;
+
+ {
+ struct dt3155_config_s tmp;
+ if (copy_from_user((void *)&tmp, (void *) arg, sizeof(tmp)))
+ return -EFAULT;
+ /* check for valid settings */
+ if (tmp.rows > DT3155_MAX_ROWS ||
+ tmp.cols > DT3155_MAX_COLS ||
+ (tmp.acq_mode != DT3155_MODE_FRAME &&
+ tmp.acq_mode != DT3155_MODE_FIELD) ||
+ (tmp.continuous != DT3155_SNAP &&
+ tmp.continuous != DT3155_ACQ))
+ {
+ return -EINVAL;
+ }
+ dt3155_status[minor].config = tmp;
+ }
+ return 0;
+ }
+ case DT3155_GET_CONFIG:
+ {
+ if (copy_to_user((void *) arg, (void *) &dt3155_status[minor],
+ sizeof(dt3155_status_t) ))
+ return -EFAULT;
+ return 0;
+ }
+ case DT3155_FLUSH: /* Flushes the buffers -- ensures fresh data */
+ {
+ if (dt3155_status[minor].state != DT3155_STATE_IDLE)
+ return -EBUSY;
+ return dt3155_flush(minor);
+ }
+ case DT3155_STOP:
+ {
+ if (dt3155_status[minor].state & DT3155_STATE_STOP ||
+ dt3155_status[minor].fbuffer.stop_acquire)
+ return -EBUSY;
+
+ if (dt3155_status[minor].state == DT3155_STATE_IDLE)
+ return 0;
+
+ quick_stop(minor);
+ if (copy_to_user((void *) arg, (void *) &dt3155_status[minor],
+ sizeof(dt3155_status_t)))
+ return -EFAULT;
+ return 0;
+ }
+ case DT3155_START:
+ {
+ if (dt3155_status[minor].state != DT3155_STATE_IDLE)
+ return -EBUSY;
+
+ dt3155_status[minor].fbuffer.stop_acquire = 0;
+ dt3155_status[minor].fbuffer.frame_count = 0;
+
+ /* Set the MODE in the status -- we default to FRAME */
+ if (dt3155_status[minor].config.acq_mode == DT3155_MODE_FIELD)
+ {
+ dt3155_status[minor].state = DT3155_STATE_FLD;
+ }
+ else
+ {
+ dt3155_status[minor].state = DT3155_STATE_FRAME;
+ }
+
+ dt3155_init_isr(minor);
+ if (copy_to_user( (void *) arg, (void *) &dt3155_status[minor],
+ sizeof(dt3155_status_t)))
+ return -EFAULT;
+ return 0;
+ }
+ default:
+ {
+ printk("DT3155: invalid IOCTL(0x%x)\n",cmd);
+ printk("DT3155: Valid commands (0x%x), (0x%x), (0x%x), (0x%x), (0x%x)\n",
+ (unsigned int)DT3155_GET_CONFIG,
+ (unsigned int)DT3155_SET_CONFIG,
+ DT3155_START, DT3155_STOP, DT3155_FLUSH);
+ return -ENOSYS;
+ }
+ }
+ return -ENOSYS;
+}
+
+/*****************************************************
+ * mmap()
+ *
+ * only allow the user to mmap the registers and buffer
+ * It is quite possible that this is broken, since the
+ * addition of of the capacity for two cards!!!!!!!!
+ * It *looks* like it should work but since I'm not
+ * sure how to use it, I'm not actually sure. (NJC? ditto by SS)
+ *****************************************************/
+static int dt3155_mmap (struct file * file, struct vm_area_struct * vma)
+{
+ /* which device are we mmapping? */
+ int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ unsigned long offset;
+ offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC))
+ vma->vm_flags |= VM_IO;
+
+ /* Don't try to swap out physical pages.. */
+ vma->vm_flags |= VM_RESERVED;
+
+ /* they are mapping the registers or the buffer */
+ if ((offset == dt3155_status[minor].reg_addr &&
+ vma->vm_end - vma->vm_start == PCI_PAGE_SIZE) ||
+ (offset == dt3155_status[minor].mem_addr &&
+ vma->vm_end - vma->vm_start == dt3155_status[minor].mem_size))
+ {
+ if (remap_pfn_range(vma,
+ vma->vm_start,
+ offset >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ printk("DT3155: remap_page_range() failed.\n");
+ return -EAGAIN;
+ }
+ }
+ else
+ {
+ printk("DT3155: dt3155_mmap() bad call.\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+
+/*****************************************************
+ * open()
+ *
+ * Our special open code.
+ * MOD_INC_USE_COUNT make sure that the driver memory is not freed
+ * while the device is in use.
+ *****************************************************/
+static int dt3155_open( struct inode* inode, struct file* filep)
+{
+ int minor = MINOR(inode->i_rdev); /* what device are we opening? */
+ if (dt3155_dev_open[ minor ]) {
+ printk ("DT3155: Already opened by another process.\n");
+ return -EBUSY;
+ }
+
+ if (dt3155_status[ minor ].device_installed==0)
+ {
+ printk("DT3155 Open Error: No such device dt3155 minor number %d\n",
+ minor);
+ return -EIO;
+ }
+
+ if (dt3155_status[ minor ].state != DT3155_STATE_IDLE) {
+ printk ("DT3155: Not in idle state (state = %x)\n",
+ dt3155_status[ minor ].state);
+ return -EBUSY;
+ }
+
+ printk("DT3155: Device opened.\n");
+
+ dt3155_dev_open[ minor ] = 1 ;
+
+ dt3155_flush( minor );
+
+ /* Disable ALL interrupts */
+ int_csr_r.reg = 0;
+ WriteMReg( (dt3155_lbase[ minor ] + INT_CSR), int_csr_r.reg );
+
+ init_waitqueue_head(&(dt3155_read_wait_queue[minor]));
+
+ return 0;
+}
+
+
+/*****************************************************
+ * close()
+ *
+ * Now decrement the use count.
+ *
+ *****************************************************/
+static int dt3155_close( struct inode *inode, struct file *filep)
+{
+ int minor;
+
+ minor = MINOR(inode->i_rdev); /* which device are we closing */
+ if (!dt3155_dev_open[ minor ])
+ {
+ printk("DT3155: attempt to CLOSE a not OPEN device\n");
+ }
+ else
+ {
+ dt3155_dev_open[ minor ] = 0;
+
+ if (dt3155_status[ minor ].state != DT3155_STATE_IDLE)
+ {
+ quick_stop(minor);
+ }
+ }
+ return 0;
+}
+
+/*****************************************************
+ * read()
+ *
+ *****************************************************/
+static ssize_t dt3155_read(struct file *filep, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ /* which device are we reading from? */
+ int minor = MINOR(filep->f_dentry->d_inode->i_rdev);
+ u32 offset;
+ int frame_index;
+ frame_info_t *frame_info_p;
+
+ /* TODO: this should check the error flag and */
+ /* return an error on hardware failures */
+ if (count != sizeof(dt3155_read_t))
+ {
+ printk("DT3155 ERROR (NJC): count is not right\n");
+ return -EINVAL;
+ }
+
+
+ /* Hack here -- I'm going to allow reading even when idle.
+ * this is so that the frames can be read after STOP has
+ * been called. Leaving it here, commented out, as a reminder
+ * for a short while to make sure there are no problems.
+ * Note that if the driver is not opened in non_blocking mode,
+ * and the device is idle, then it could sit here forever! */
+
+ /* if (dt3155_status[minor].state == DT3155_STATE_IDLE)*/
+ /* return -EBUSY;*/
+
+ /* non-blocking reads should return if no data */
+ if (filep->f_flags & O_NDELAY)
+ {
+ if ((frame_index = dt3155_get_ready_buffer(minor)) < 0) {
+ /*printk( "dt3155: no buffers available (?)\n");*/
+ /* printques(minor); */
+ return -EAGAIN;
+ }
+ }
+ else
+ {
+ /*
+ * sleep till data arrives , or we get interrupted.
+ * Note that wait_event_interruptible() does not actually
+ * sleep/wait if it's condition evaluates to true upon entry.
+ */
+ wait_event_interruptible(dt3155_read_wait_queue[minor],
+ (frame_index = dt3155_get_ready_buffer(minor))
+ >= 0);
+
+ if (frame_index < 0)
+ {
+ printk ("DT3155: read: interrupted\n");
+ quick_stop (minor);
+ printques(minor);
+ return -EINTR;
+ }
+ }
+
+ frame_info_p = &dt3155_status[minor].fbuffer.frame_info[frame_index];
+
+ /* make this an offset */
+ offset = frame_info_p->addr - dt3155_status[minor].mem_addr;
+
+ put_user(offset, (unsigned int *) buf);
+ buf += sizeof(u32);
+ put_user( dt3155_status[minor].fbuffer.frame_count, (unsigned int *) buf);
+ buf += sizeof(u32);
+ put_user(dt3155_status[minor].state, (unsigned int *) buf);
+ buf += sizeof(u32);
+ if (copy_to_user(buf, frame_info_p, sizeof(frame_info_t)))
+ return -EFAULT;
+
+ return sizeof(dt3155_read_t);
+}
+
+static unsigned int dt3155_poll (struct file * filp, poll_table *wait)
+{
+ int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+
+ if (!is_ready_buf_empty(minor))
+ return POLLIN | POLLRDNORM;
+
+ poll_wait (filp, &dt3155_read_wait_queue[minor], wait);
+
+ return 0;
+}
+
+
+/*****************************************************
+ * file operations supported by DT3155 driver
+ * needed by init_module
+ * register_chrdev
+ *****************************************************/
+static struct file_operations dt3155_fops = {
+ read: dt3155_read,
+ ioctl: dt3155_ioctl,
+ mmap: dt3155_mmap,
+ poll: dt3155_poll,
+ open: dt3155_open,
+ release: dt3155_close
+};
+
+
+/*****************************************************
+ * find_PCI();
+ *
+ * PCI has been totally reworked in 2.1..
+ *****************************************************/
+static int find_PCI (void)
+{
+ struct pci_dev *pci_dev = NULL;
+ int error, pci_index = 0;
+ unsigned short rev_device;
+ unsigned long base;
+ unsigned char irq;
+
+ while ((pci_dev = pci_get_device
+ (DT3155_VENDORID, DT3155_DEVICEID, pci_dev)) != NULL)
+ {
+ pci_index ++;
+
+ /* Is it really there? */
+ if ((error =
+ pci_read_config_word(pci_dev, PCI_CLASS_DEVICE, &rev_device)))
+ continue;
+
+ /* Found a board */
+ DT_3155_DEBUG_MSG("DT3155: Device number %d \n", pci_index);
+
+ /* Make sure the driver was compiled with enough buffers to handle
+ this many boards */
+ if (pci_index > MAXBOARDS) {
+ printk("DT3155: ERROR - found %d devices, but driver only configured "
+ "for %d devices\n"
+ "DT3155: Please change MAXBOARDS in dt3155.h\n",
+ pci_index, MAXBOARDS);
+ goto err;
+ }
+
+ /* Now, just go out and make sure that this/these device(s) is/are
+ actually mapped into the kernel address space */
+ if ((error = pci_read_config_dword( pci_dev, PCI_BASE_ADDRESS_0,
+ (u32 *) &base)))
+ {
+ printk("DT3155: Was not able to find device \n");
+ goto err;
+ }
+
+ DT_3155_DEBUG_MSG("DT3155: Base address 0 for device is %lx \n", base);
+ dt3155_status[pci_index-1].reg_addr = base;
+
+ /* Remap the base address to a logical address through which we
+ * can access it. */
+ dt3155_lbase[ pci_index - 1 ] = ioremap(base,PCI_PAGE_SIZE);
+ dt3155_status[ pci_index - 1 ].reg_addr = base;
+ DT_3155_DEBUG_MSG("DT3155: New logical address is %p \n",
+ dt3155_lbase[pci_index-1]);
+ if ( !dt3155_lbase[pci_index-1] )
+ {
+ printk("DT3155: Unable to remap control registers\n");
+ goto err;
+ }
+
+ if ( (error = pci_read_config_byte( pci_dev, PCI_INTERRUPT_LINE, &irq)) )
+ {
+ printk("DT3155: Was not able to find device \n");
+ goto err;
+ }
+
+ DT_3155_DEBUG_MSG("DT3155: IRQ is %d \n",irq);
+ dt3155_status[ pci_index-1 ].irq = irq;
+ /* Set flag: kth device found! */
+ dt3155_status[ pci_index-1 ].device_installed = 1;
+ printk("DT3155: Installing device %d w/irq %d and address %p\n",
+ pci_index,
+ dt3155_status[pci_index-1].irq,
+ dt3155_lbase[pci_index-1]);
+
+ }
+ ndevices = pci_index;
+
+ return DT_3155_SUCCESS;
+
+err:
+ pci_dev_put(pci_dev);
+ return DT_3155_FAILURE;
+}
+
+u32 allocatorAddr = 0;
+
+/*****************************************************
+ * init_module()
+ *****************************************************/
+int init_module(void)
+{
+ int index;
+ int rcode = 0;
+ char *devname[ MAXBOARDS ];
+
+ devname[ 0 ] = "dt3155a";
+#if MAXBOARDS == 2
+ devname[ 1 ] = "dt3155b";
+#endif
+
+ printk("DT3155: Loading module...\n");
+
+ /* Register the device driver */
+ rcode = register_chrdev( dt3155_major, "dt3155", &dt3155_fops );
+ if( rcode < 0 )
+ {
+ printk( KERN_INFO "DT3155: register_chrdev failed \n");
+ return rcode;
+ }
+
+ if( dt3155_major == 0 )
+ dt3155_major = rcode; /* dynamic */
+
+
+ /* init the status variables. */
+ /* DMA memory is taken care of in setup_buffers() */
+ for ( index = 0; index < MAXBOARDS; index++ )
+ {
+ dt3155_status[ index ].config.acq_mode = DT3155_MODE_FRAME;
+ dt3155_status[ index ].config.continuous = DT3155_ACQ;
+ dt3155_status[ index ].config.cols = DT3155_MAX_COLS;
+ dt3155_status[ index ].config.rows = DT3155_MAX_ROWS;
+ dt3155_status[ index ].state = DT3155_STATE_IDLE;
+
+ /* find_PCI() will check if devices are installed; */
+ /* first assume they're not: */
+ dt3155_status[ index ].mem_addr = 0;
+ dt3155_status[ index ].mem_size = 0;
+ dt3155_status[ index ].state = DT3155_STATE_IDLE;
+ dt3155_status[ index ].device_installed = 0;
+ }
+
+ /* Now let's find the hardware. find_PCI() will set ndevices to the
+ * number of cards found in this machine. */
+ {
+ if ( (rcode = find_PCI()) != DT_3155_SUCCESS )
+ {
+ printk("DT3155 error: find_PCI() failed to find dt3155 board(s)\n");
+ unregister_chrdev( dt3155_major, "dt3155" );
+ return rcode;
+ }
+ }
+
+ /* Ok, time to setup the frame buffers */
+ if( (rcode = dt3155_setup_buffers(&allocatorAddr)) < 0 )
+ {
+ printk("DT3155: Error: setting up buffer not large enough.");
+ unregister_chrdev( dt3155_major, "dt3155" );
+ return rcode;
+ }
+
+ /* If we are this far, then there is enough RAM */
+ /* for the buffers: Print the configuration. */
+ for( index = 0; index < ndevices; index++ )
+ {
+ printk("DT3155: Device = %d; acq_mode = %d; "
+ "continuous = %d; cols = %d; rows = %d;\n",
+ index ,
+ dt3155_status[ index ].config.acq_mode,
+ dt3155_status[ index ].config.continuous,
+ dt3155_status[ index ].config.cols,
+ dt3155_status[ index ].config.rows);
+ printk("DT3155: m_addr = 0x%x; m_size = %ld; "
+ "state = %d; device_installed = %d\n",
+ dt3155_status[ index ].mem_addr,
+ (long int)dt3155_status[ index ].mem_size,
+ dt3155_status[ index ].state,
+ dt3155_status[ index ].device_installed);
+ }
+
+ /* Disable ALL interrupts */
+ int_csr_r.reg = 0;
+ for( index = 0; index < ndevices; index++ )
+ {
+ WriteMReg( (dt3155_lbase[ index ] + INT_CSR), int_csr_r.reg );
+ if( dt3155_status[ index ].device_installed )
+ {
+ /*
+ * This driver *looks* like it can handle sharing interrupts,
+ * but I can't actually test myself. I've had reports that it
+ * DOES work so I'll enable it for now. This comment will remain
+ * as a reminder in case any problems arise. (SS)
+ */
+ /* in older kernels flags are: SA_SHIRQ | SA_INTERRUPT */
+ rcode = request_irq( dt3155_status[ index ].irq, (void *)dt3155_isr,
+ IRQF_SHARED | IRQF_DISABLED, devname[ index ],
+ (void*) &dt3155_status[index]);
+ if( rcode < 0 )
+ {
+ printk("DT3155: minor %d request_irq failed for IRQ %d\n",
+ index, dt3155_status[index].irq);
+ unregister_chrdev( dt3155_major, "dt3155" );
+ return rcode;
+ }
+ }
+ }
+
+ printk("DT3155: finished loading\n");
+
+ return 0;
+}
+
+/*****************************************************
+ * cleanup_module(void)
+ *
+ *****************************************************/
+void cleanup_module(void)
+{
+ int index;
+
+ printk("DT3155: cleanup_module called\n");
+
+ /* removed DMA allocated with the allocator */
+#ifdef STANDALONE_ALLOCATOR
+ if (allocatorAddr != 0)
+ allocator_free_dma(allocatorAddr);
+#else
+ allocator_cleanup();
+#endif
+
+ unregister_chrdev( dt3155_major, "dt3155" );
+
+ for( index = 0; index < ndevices; index++ )
+ {
+ if( dt3155_status[ index ].device_installed == 1 )
+ {
+ printk( "DT3155: Freeing irq %d for device %d\n",
+ dt3155_status[ index ].irq, index );
+ free_irq( dt3155_status[ index ].irq, (void*)&dt3155_status[index] );
+ }
+ }
+}
+
diff --git a/drivers/staging/dt3155/dt3155_drv.h b/drivers/staging/dt3155/dt3155_drv.h
new file mode 100644
index 000000000000..95e68c3388a4
--- /dev/null
+++ b/drivers/staging/dt3155/dt3155_drv.h
@@ -0,0 +1,45 @@
+/*
+
+Copyright 1996,2002 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
+ Scott Smedley
+
+This file is part of the DT3155 Device Driver.
+
+The DT3155 Device Driver 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.
+
+The DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+MA 02111-1307 USA
+*/
+
+#ifndef DT3155_DRV_INC
+#define DT3155_DRV_INC
+
+/* kernel logical address of the frame grabbers */
+extern u8 *dt3155_lbase[MAXBOARDS];
+
+/* kernel logical address of ram buffer */
+extern u8 *dt3155_bbase;
+
+#ifdef __KERNEL__
+#include <linux/wait.h>
+
+/* wait queue for reads */
+extern wait_queue_head_t dt3155_read_wait_queue[MAXBOARDS];
+#endif
+
+/* number of devices */
+extern u32 ndevices;
+
+extern int dt3155_errno;
+
+#endif
diff --git a/drivers/staging/dt3155/dt3155_io.c b/drivers/staging/dt3155/dt3155_io.c
new file mode 100644
index 000000000000..6b9c68501a61
--- /dev/null
+++ b/drivers/staging/dt3155/dt3155_io.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
+ * Jason Lapenta, Scott Smedley
+ *
+ * This file is part of the DT3155 Device Driver.
+ *
+ * The DT3155 Device Driver 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.
+ *
+ * The DT3155 Device Driver 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.
+ */
+
+/*
+ * This file provides some basic register io routines. It is modified from
+ * demo code provided by Data Translations.
+ */
+
+#include <linux/delay.h>
+#include "dt3155.h"
+#include "dt3155_io.h"
+#include "dt3155_drv.h"
+
+
+/****** local copies of board's 32 bit registers ******/
+u32 even_dma_start_r; /* bit 0 should always be 0 */
+u32 odd_dma_start_r; /* .. */
+u32 even_dma_stride_r; /* bits 0&1 should always be 0 */
+u32 odd_dma_stride_r; /* .. */
+u32 even_pixel_fmt_r;
+u32 odd_pixel_fmt_r;
+
+FIFO_TRIGGER_R fifo_trigger_r;
+XFER_MODE_R xfer_mode_r;
+CSR1_R csr1_r;
+RETRY_WAIT_CNT_R retry_wait_cnt_r;
+INT_CSR_R int_csr_r;
+
+u32 even_fld_mask_r;
+u32 odd_fld_mask_r;
+
+MASK_LENGTH_R mask_length_r;
+FIFO_FLAG_CNT_R fifo_flag_cnt_r;
+IIC_CLK_DUR_R iic_clk_dur_r;
+IIC_CSR1_R iic_csr1_r;
+IIC_CSR2_R iic_csr2_r;
+DMA_UPPER_LMT_R even_dma_upper_lmt_r;
+DMA_UPPER_LMT_R odd_dma_upper_lmt_r;
+
+
+
+/******** local copies of board's 8 bit I2C registers ******/
+I2C_CSR2 i2c_csr2;
+I2C_EVEN_CSR i2c_even_csr;
+I2C_ODD_CSR i2c_odd_csr;
+I2C_CONFIG i2c_config;
+u8 i2c_dt_id;
+u8 i2c_x_clip_start;
+u8 i2c_y_clip_start;
+u8 i2c_x_clip_end;
+u8 i2c_y_clip_end;
+u8 i2c_ad_addr;
+u8 i2c_ad_lut;
+I2C_AD_CMD i2c_ad_cmd;
+u8 i2c_dig_out;
+u8 i2c_pm_lut_addr;
+u8 i2c_pm_lut_data;
+
+/*
+ * wait_ibsyclr()
+ *
+ * This function handles read/write timing and r/w timeout error
+ *
+ * Returns TRUE if NEW_CYCLE clears
+ * Returns FALSE if NEW_CYCLE doesn't clear in roughly 3 msecs, otherwise
+ * returns 0
+ */
+static int wait_ibsyclr(u8 *lpReg)
+{
+ /* wait 100 microseconds */
+ udelay(100L);
+ /* __delay(loops_per_sec/10000); */
+ if (iic_csr2_r.fld.NEW_CYCLE) {
+ /* if NEW_CYCLE didn't clear */
+ /* TIMEOUT ERROR */
+ dt3155_errno = DT_ERR_I2C_TIMEOUT;
+ return FALSE;
+ } else
+ return TRUE; /* no error */
+}
+
+/*
+ * WriteI2C()
+ *
+ * This function handles writing to 8-bit DT3155 registers
+ *
+ * 1st parameter is pointer to 32-bit register base address
+ * 2nd parameter is reg. index;
+ * 3rd is value to be written
+ *
+ * Returns TRUE - Successful completion
+ * FALSE - Timeout error - cycle did not complete!
+ */
+int WriteI2C(u8 *lpReg, u_short wIregIndex, u8 byVal)
+{
+ int writestat; /* status for return */
+
+ /* read 32 bit IIC_CSR2 register data into union */
+
+ ReadMReg((lpReg + IIC_CSR2), iic_csr2_r.reg);
+
+ /* for write operation */
+ iic_csr2_r.fld.DIR_RD = 0;
+ /* I2C address of I2C register: */
+ iic_csr2_r.fld.DIR_ADDR = wIregIndex;
+ /* 8 bit data to be written to I2C reg */
+ iic_csr2_r.fld.DIR_WR_DATA = byVal;
+ /* will start a direct I2C cycle: */
+ iic_csr2_r.fld.NEW_CYCLE = 1;
+
+ /* xfer union data into 32 bit IIC_CSR2 register */
+ WriteMReg((lpReg + IIC_CSR2), iic_csr2_r.reg);
+
+ /* wait for IIC cycle to finish */
+ writestat = wait_ibsyclr(lpReg);
+ return writestat;
+}
+
+/*
+ * ReadI2C()
+ *
+ * This function handles reading from 8-bit DT3155 registers
+ *
+ * 1st parameter is pointer to 32-bit register base address
+ * 2nd parameter is reg. index;
+ * 3rd is adrs of value to be read
+ *
+ * Returns TRUE - Successful completion
+ * FALSE - Timeout error - cycle did not complete!
+ */
+int ReadI2C(u8 *lpReg, u_short wIregIndex, u8 *byVal)
+{
+ int writestat; /* status for return */
+
+ /* read 32 bit IIC_CSR2 register data into union */
+ ReadMReg((lpReg + IIC_CSR2), iic_csr2_r.reg);
+
+ /* for read operation */
+ iic_csr2_r.fld.DIR_RD = 1;
+
+ /* I2C address of I2C register: */
+ iic_csr2_r.fld.DIR_ADDR = wIregIndex;
+
+ /* will start a direct I2C cycle: */
+ iic_csr2_r.fld.NEW_CYCLE = 1;
+
+ /* xfer union's data into 32 bit IIC_CSR2 register */
+ WriteMReg((lpReg + IIC_CSR2), iic_csr2_r.reg);
+
+ /* wait for IIC cycle to finish */
+ writestat = wait_ibsyclr(lpReg);
+
+ /* Next 2 commands read 32 bit IIC_CSR1 register's data into union */
+ /* first read data is in IIC_CSR1 */
+ ReadMReg((lpReg + IIC_CSR1), iic_csr1_r.reg);
+
+ /* now get data u8 out of register */
+ *byVal = (u8) iic_csr1_r.fld.RD_DATA;
+
+ return writestat;
+}
diff --git a/drivers/staging/dt3155/dt3155_io.h b/drivers/staging/dt3155/dt3155_io.h
new file mode 100644
index 000000000000..d1a25100169f
--- /dev/null
+++ b/drivers/staging/dt3155/dt3155_io.h
@@ -0,0 +1,358 @@
+/*
+
+Copyright 1996,2002 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
+ Jason Lapenta, Scott Smedley
+
+This file is part of the DT3155 Device Driver.
+
+The DT3155 Device Driver 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.
+
+The DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+MA 02111-1307 USA
+
+
+-- Changes --
+
+ Date Programmer Description of changes made
+ -------------------------------------------------------------------
+ 24-Jul-2002 SS GPL licence.
+
+*/
+
+/* This code is a modified version of examples provided by Data Translations.*/
+
+#ifndef DT3155_IO_INC
+#define DT3155_IO_INC
+
+/* macros to access registers */
+
+#define WriteMReg(Address, Data) (*((u32 *)(Address)) = Data)
+#define ReadMReg(Address, Data) (Data = *((u32 *)(Address)))
+
+/***************** 32 bit register globals **************/
+
+/* offsets for 32-bit memory mapped registers */
+
+#define EVEN_DMA_START 0x000
+#define ODD_DMA_START 0x00C
+#define EVEN_DMA_STRIDE 0x018
+#define ODD_DMA_STRIDE 0x024
+#define EVEN_PIXEL_FMT 0x030
+#define ODD_PIXEL_FMT 0x034
+#define FIFO_TRIGGER 0x038
+#define XFER_MODE 0x03C
+#define CSR1 0x040
+#define RETRY_WAIT_CNT 0x044
+#define INT_CSR 0x048
+#define EVEN_FLD_MASK 0x04C
+#define ODD_FLD_MASK 0x050
+#define MASK_LENGTH 0x054
+#define FIFO_FLAG_CNT 0x058
+#define IIC_CLK_DUR 0x05C
+#define IIC_CSR1 0x060
+#define IIC_CSR2 0x064
+#define EVEN_DMA_UPPR_LMT 0x08C
+#define ODD_DMA_UPPR_LMT 0x090
+
+#define CLK_DUR_VAL 0x01010101
+
+
+
+/******** Assignments and Typedefs for 32 bit Memory Mapped Registers ********/
+
+typedef union fifo_trigger_tag {
+ u32 reg;
+ struct {
+ u32 PACKED:6;
+ u32 :9;
+ u32 PLANER:7;
+ u32 :9;
+ } fld;
+} FIFO_TRIGGER_R;
+
+typedef union xfer_mode_tag {
+ u32 reg;
+ struct {
+ u32 :2;
+ u32 FIELD_TOGGLE:1;
+ u32 :5;
+ u32 :2;
+ u32 :22;
+ } fld;
+} XFER_MODE_R;
+
+typedef union csr1_tag {
+ u32 reg;
+ struct {
+ u32 CAP_CONT_EVE:1;
+ u32 CAP_CONT_ODD:1;
+ u32 CAP_SNGL_EVE:1;
+ u32 CAP_SNGL_ODD:1;
+ u32 FLD_DN_EVE :1;
+ u32 FLD_DN_ODD :1;
+ u32 SRST :1;
+ u32 FIFO_EN :1;
+ u32 FLD_CRPT_EVE:1;
+ u32 FLD_CRPT_ODD:1;
+ u32 ADDR_ERR_EVE:1;
+ u32 ADDR_ERR_ODD:1;
+ u32 CRPT_DIS :1;
+ u32 RANGE_EN :1;
+ u32 :16;
+ } fld;
+} CSR1_R;
+
+typedef union retry_wait_cnt_tag {
+ u32 reg;
+ struct {
+ u32 RTRY_WAIT_CNT:8;
+ u32 :24;
+ } fld;
+} RETRY_WAIT_CNT_R;
+
+typedef union int_csr_tag {
+ u32 reg;
+ struct {
+ u32 FLD_END_EVE :1;
+ u32 FLD_END_ODD :1;
+ u32 FLD_START :1;
+ u32 :5;
+ u32 FLD_END_EVE_EN:1;
+ u32 FLD_END_ODD_EN:1;
+ u32 FLD_START_EN :1;
+ u32 :21;
+ } fld;
+} INT_CSR_R;
+
+typedef union mask_length_tag {
+ u32 reg;
+ struct {
+ u32 MASK_LEN_EVE:5;
+ u32 :11;
+ u32 MASK_LEN_ODD:5;
+ u32 :11;
+ } fld;
+} MASK_LENGTH_R;
+
+typedef union fifo_flag_cnt_tag {
+ u32 reg;
+ struct {
+ u32 AF_COUNT:7;
+ u32 :9;
+ u32 AE_COUNT:7;
+ u32 :9;
+ } fld;
+} FIFO_FLAG_CNT_R;
+
+typedef union iic_clk_dur {
+ u32 reg;
+ struct {
+ u32 PHASE_1:8;
+ u32 PHASE_2:8;
+ u32 PHASE_3:8;
+ u32 PHASE_4:8;
+ } fld;
+} IIC_CLK_DUR_R;
+
+typedef union iic_csr1_tag {
+ u32 reg;
+ struct {
+ u32 AUTO_EN :1;
+ u32 BYPASS :1;
+ u32 SDA_OUT :1;
+ u32 SCL_OUT :1;
+ u32 :4;
+ u32 AUTO_ABORT :1;
+ u32 DIRECT_ABORT:1;
+ u32 SDA_IN :1;
+ u32 SCL_IN :1;
+ u32 :4;
+ u32 AUTO_ADDR :8;
+ u32 RD_DATA :8;
+ } fld;
+} IIC_CSR1_R;
+
+/**********************************
+ * iic_csr2_tag
+ */
+typedef union iic_csr2_tag {
+ u32 reg;
+ struct {
+ u32 DIR_WR_DATA :8;
+ u32 DIR_SUB_ADDR:8;
+ u32 DIR_RD :1;
+ u32 DIR_ADDR :7;
+ u32 NEW_CYCLE :1;
+ u32 :7;
+ } fld;
+} IIC_CSR2_R;
+
+/* use for both EVEN and ODD DMA UPPER LIMITS */
+
+/*
+ * dma_upper_lmt_tag
+ */
+typedef union dma_upper_lmt_tag {
+ u32 reg;
+ struct {
+ u32 DMA_UPPER_LMT_VAL:24;
+ u32 :8;
+ } fld;
+} DMA_UPPER_LMT_R;
+
+
+/*
+ * Global declarations of local copies of boards' 32 bit registers
+ */
+extern u32 even_dma_start_r; /* bit 0 should always be 0 */
+extern u32 odd_dma_start_r; /* .. */
+extern u32 even_dma_stride_r; /* bits 0&1 should always be 0 */
+extern u32 odd_dma_stride_r; /* .. */
+extern u32 even_pixel_fmt_r;
+extern u32 odd_pixel_fmt_r;
+
+extern FIFO_TRIGGER_R fifo_trigger_r;
+extern XFER_MODE_R xfer_mode_r;
+extern CSR1_R csr1_r;
+extern RETRY_WAIT_CNT_R retry_wait_cnt_r;
+extern INT_CSR_R int_csr_r;
+
+extern u32 even_fld_mask_r;
+extern u32 odd_fld_mask_r;
+
+extern MASK_LENGTH_R mask_length_r;
+extern FIFO_FLAG_CNT_R fifo_flag_cnt_r;
+extern IIC_CLK_DUR_R iic_clk_dur_r;
+extern IIC_CSR1_R iic_csr1_r;
+extern IIC_CSR2_R iic_csr2_r;
+extern DMA_UPPER_LMT_R even_dma_upper_lmt_r;
+extern DMA_UPPER_LMT_R odd_dma_upper_lmt_r;
+
+
+
+/***************** 8 bit I2C register globals ***********/
+#define CSR2 0x010 /* indices of 8-bit I2C mapped reg's*/
+#define EVEN_CSR 0x011
+#define ODD_CSR 0x012
+#define CONFIG 0x013
+#define DT_ID 0x01F
+#define X_CLIP_START 0x020
+#define Y_CLIP_START 0x022
+#define X_CLIP_END 0x024
+#define Y_CLIP_END 0x026
+#define AD_ADDR 0x030
+#define AD_LUT 0x031
+#define AD_CMD 0x032
+#define DIG_OUT 0x040
+#define PM_LUT_ADDR 0x050
+#define PM_LUT_DATA 0x051
+
+
+/******** Assignments and Typedefs for 8 bit I2C Registers********************/
+
+typedef union i2c_csr2_tag {
+ u8 reg;
+ struct {
+ u8 CHROM_FIL:1;
+ u8 SYNC_SNTL:1;
+ u8 HZ50:1;
+ u8 SYNC_PRESENT:1;
+ u8 BUSY_EVE:1;
+ u8 BUSY_ODD:1;
+ u8 DISP_PASS:1;
+ } fld;
+} I2C_CSR2;
+
+typedef union i2c_even_csr_tag {
+ u8 reg;
+ struct {
+ u8 DONE_EVE :1;
+ u8 SNGL_EVE :1;
+ u8 ERROR_EVE:1;
+ u8 :5;
+ } fld;
+} I2C_EVEN_CSR;
+
+typedef union i2c_odd_csr_tag {
+ u8 reg;
+ struct {
+ u8 DONE_ODD:1;
+ u8 SNGL_ODD:1;
+ u8 ERROR_ODD:1;
+ u8 :5;
+ } fld;
+} I2C_ODD_CSR;
+
+typedef union i2c_config_tag {
+ u8 reg;
+ struct {
+ u8 ACQ_MODE:2;
+ u8 EXT_TRIG_EN:1;
+ u8 EXT_TRIG_POL:1;
+ u8 H_SCALE:1;
+ u8 CLIP:1;
+ u8 PM_LUT_SEL:1;
+ u8 PM_LUT_PGM:1;
+ } fld;
+} I2C_CONFIG;
+
+
+typedef union i2c_ad_cmd_tag {
+ /* bits can have 3 different meanings depending on value of AD_ADDR */
+ u8 reg;
+ /* Bt252 Command Register if AD_ADDR = 00h */
+ struct {
+ u8 :2;
+ u8 SYNC_LVL_SEL:2;
+ u8 SYNC_CNL_SEL:2;
+ u8 DIGITIZE_CNL_SEL1:2;
+ } bt252_command;
+
+ /* Bt252 IOUT0 register if AD_ADDR = 01h */
+ struct {
+ u8 IOUT_DATA:8;
+ } bt252_iout0;
+
+ /* BT252 IOUT1 register if AD_ADDR = 02h */
+ struct {
+ u8 IOUT_DATA:8;
+ } bt252_iout1;
+} I2C_AD_CMD;
+
+
+/***** Global declarations of local copies of boards' 8 bit I2C registers ***/
+
+extern I2C_CSR2 i2c_csr2;
+extern I2C_EVEN_CSR i2c_even_csr;
+extern I2C_ODD_CSR i2c_odd_csr;
+extern I2C_CONFIG i2c_config;
+extern u8 i2c_dt_id;
+extern u8 i2c_x_clip_start;
+extern u8 i2c_y_clip_start;
+extern u8 i2c_x_clip_end;
+extern u8 i2c_y_clip_end;
+extern u8 i2c_ad_addr;
+extern u8 i2c_ad_lut;
+extern I2C_AD_CMD i2c_ad_cmd;
+extern u8 i2c_dig_out;
+extern u8 i2c_pm_lut_addr;
+extern u8 i2c_pm_lut_data;
+
+/* Functions for Global use */
+
+/* access 8-bit IIC registers */
+
+extern int ReadI2C(u8 *lpReg, u_short wIregIndex, u8 *byVal);
+extern int WriteI2C(u8 *lpReg, u_short wIregIndex, u8 byVal);
+
+#endif
diff --git a/drivers/staging/dt3155/dt3155_isr.c b/drivers/staging/dt3155/dt3155_isr.c
new file mode 100644
index 000000000000..fd7f93d6c33d
--- /dev/null
+++ b/drivers/staging/dt3155/dt3155_isr.c
@@ -0,0 +1,516 @@
+/*
+
+Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
+ Jason Lapenta, Scott Smedley, Greg Sharp
+
+This file is part of the DT3155 Device Driver.
+
+The DT3155 Device Driver 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.
+
+The DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+MA 02111-1307 USA
+
+ File: dt3155_isr.c
+Purpose: Buffer management routines, and other routines for the ISR
+ (the actual isr is in dt3155_drv.c)
+
+-- Changes --
+
+ Date Programmer Description of changes made
+ -------------------------------------------------------------------
+ 03-Jul-2000 JML n/a
+ 02-Apr-2002 SS Mods to make work with separate allocator
+ module; Merged John Roll's mods to make work with
+ multiple boards.
+ 10-Jul-2002 GCS Complete rewrite of setup_buffers to disallow
+ buffers which span a 4MB boundary.
+ 24-Jul-2002 SS GPL licence.
+ 30-Jul-2002 NJC Added support for buffer loop.
+ 31-Jul-2002 NJC Complete rewrite of buffer management
+ 02-Aug-2002 NJC Including slab.h instead of malloc.h (no warning).
+ Also, allocator_init() now returns allocator_max
+ so cleaned up allocate_buffers() accordingly.
+ 08-Aug-2005 SS port to 2.6 kernel.
+
+*/
+
+#include <asm/system.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+
+#include "dt3155.h"
+#include "dt3155_drv.h"
+#include "dt3155_io.h"
+#include "dt3155_isr.h"
+#include "allocator.h"
+
+#define FOUR_MB (0x0400000) /* Can't DMA accross a 4MB boundary!*/
+#define UPPER_10_BITS (0x3FF<<22) /* Can't DMA accross a 4MB boundary!*/
+
+
+/* Pointer into global structure for handling buffers */
+struct dt3155_fbuffer_s *dt3155_fbuffer[MAXBOARDS] = {NULL
+#if MAXBOARDS == 2
+ , NULL
+#endif
+};
+
+/******************************************************************************
+ * Simple array based que struct
+ *
+ * Some handy functions using the buffering structure.
+ *****************************************************************************/
+
+
+/***************************
+ * are_empty_buffers
+ * m is minor # of device
+ ***************************/
+inline bool are_empty_buffers( int m )
+{
+ return ( dt3155_fbuffer[ m ]->empty_len );
+}
+
+/**************************
+ * push_empty
+ * m is minor # of device
+ *
+ * This is slightly confusing. The number empty_len is the literal #
+ * of empty buffers. After calling, empty_len-1 is the index into the
+ * empty buffer stack. So, if empty_len == 1, there is one empty buffer,
+ * given by dt3155_fbuffer[m]->empty_buffers[0].
+ * empty_buffers should never fill up, though this is not checked.
+ **************************/
+inline void push_empty( int index, int m )
+{
+ dt3155_fbuffer[m]->empty_buffers[ dt3155_fbuffer[m]->empty_len ] = index;
+ dt3155_fbuffer[m]->empty_len++;
+}
+
+/**************************
+ * pop_empty( m )
+ * m is minor # of device
+ **************************/
+inline int pop_empty( int m )
+{
+ dt3155_fbuffer[m]->empty_len--;
+ return dt3155_fbuffer[m]->empty_buffers[ dt3155_fbuffer[m]->empty_len ];
+}
+
+/*************************
+ * is_ready_buf_empty( m )
+ * m is minor # of device
+ *************************/
+inline bool is_ready_buf_empty( int m )
+{
+ return ((dt3155_fbuffer[ m ]->ready_len) == 0);
+}
+
+/*************************
+ * is_ready_buf_full( m )
+ * m is minor # of device
+ * this should *never* be true if there are any active, locked or empty
+ * buffers, since it corresponds to nbuffers ready buffers!!
+ * 7/31/02: total rewrite. --NJC
+ *************************/
+inline bool is_ready_buf_full( int m )
+{
+ return ( dt3155_fbuffer[ m ]->ready_len == dt3155_fbuffer[ m ]->nbuffers );
+}
+
+/*****************************************************
+ * push_ready( m, buffer )
+ * m is minor # of device
+ *
+ *****************************************************/
+inline void push_ready( int m, int index )
+{
+ int head = dt3155_fbuffer[m]->ready_head;
+
+ dt3155_fbuffer[ m ]->ready_que[ head ] = index;
+ dt3155_fbuffer[ m ]->ready_head = ( (head + 1) %
+ (dt3155_fbuffer[ m ]->nbuffers) );
+ dt3155_fbuffer[ m ]->ready_len++;
+
+}
+
+/*****************************************************
+ * get_tail()
+ * m is minor # of device
+ *
+ * Simply comptutes the tail given the head and the length.
+ *****************************************************/
+static inline int get_tail( int m )
+{
+ return ((dt3155_fbuffer[ m ]->ready_head -
+ dt3155_fbuffer[ m ]->ready_len +
+ dt3155_fbuffer[ m ]->nbuffers)%
+ (dt3155_fbuffer[ m ]->nbuffers));
+}
+
+
+
+/*****************************************************
+ * pop_ready()
+ * m is minor # of device
+ *
+ * This assumes that there is a ready buffer ready... should
+ * be checked (e.g. with is_ready_buf_empty() prior to call.
+ *****************************************************/
+inline int pop_ready( int m )
+{
+ int tail;
+ tail = get_tail(m);
+ dt3155_fbuffer[ m ]->ready_len--;
+ return dt3155_fbuffer[ m ]->ready_que[ tail ];
+}
+
+
+/*****************************************************
+ * printques
+ * m is minor # of device
+ *****************************************************/
+inline void printques( int m )
+{
+ int head = dt3155_fbuffer[ m ]->ready_head;
+ int tail;
+ int num = dt3155_fbuffer[ m ]->nbuffers;
+ int frame_index;
+ int index;
+
+ tail = get_tail(m);
+
+ printk("\n R:");
+ for ( index = tail; index != head; index++, index = index % (num) )
+ {
+ frame_index = dt3155_fbuffer[ m ]->ready_que[ index ];
+ printk(" %d ", frame_index );
+ }
+
+ printk("\n E:");
+ for ( index = 0; index < dt3155_fbuffer[ m ]->empty_len; index++ )
+ {
+ frame_index = dt3155_fbuffer[ m ]->empty_buffers[ index ];
+ printk(" %d ", frame_index );
+ }
+
+ frame_index = dt3155_fbuffer[ m ]->active_buf;
+ printk("\n A: %d", frame_index);
+
+ frame_index = dt3155_fbuffer[ m ]->locked_buf;
+ printk("\n L: %d \n", frame_index );
+
+}
+
+/*****************************************************
+ * adjust_4MB
+ *
+ * If a buffer intersects the 4MB boundary, push
+ * the start address up to the beginning of the
+ * next 4MB chunk (assuming bufsize < 4MB).
+ *****************************************************/
+u32 adjust_4MB (u32 buf_addr, u32 bufsize) {
+ if (((buf_addr+bufsize) & UPPER_10_BITS) != (buf_addr & UPPER_10_BITS))
+ return (buf_addr+bufsize) & UPPER_10_BITS;
+ else
+ return buf_addr;
+}
+
+
+/*****************************************************
+ * allocate_buffers
+ *
+ * Try to allocate enough memory for all requested
+ * buffers. If there is not enough free space
+ * try for less memory.
+ *****************************************************/
+void allocate_buffers (u32 *buf_addr, u32* total_size_kbs,
+ u32 bufsize)
+{
+ /* Compute the minimum amount of memory guaranteed to hold all
+ MAXBUFFERS such that no buffer crosses the 4MB boundary.
+ Store this value in the variable "full_size" */
+
+ u32 allocator_max;
+ u32 bufs_per_chunk = (FOUR_MB / bufsize);
+ u32 filled_chunks = (MAXBUFFERS-1) / bufs_per_chunk;
+ u32 leftover_bufs = MAXBUFFERS - filled_chunks * bufs_per_chunk;
+
+ u32 full_size = bufsize /* possibly unusable part of 1st chunk */
+ + filled_chunks * FOUR_MB /* max # of completely filled 4mb chunks */
+ + leftover_bufs * bufsize; /* these buffs will be in a partly filled
+ chunk at beginning or end */
+
+ u32 full_size_kbs = 1 + (full_size-1) / 1024;
+ u32 min_size_kbs = 2*ndevices*bufsize / 1024;
+ u32 size_kbs;
+
+ /* Now, try to allocate full_size. If this fails, keep trying for
+ less & less memory until it succeeds. */
+#ifndef STANDALONE_ALLOCATOR
+ /* initialize the allocator */
+ allocator_init(&allocator_max);
+#endif
+ size_kbs = full_size_kbs;
+ *buf_addr = 0;
+ printk("DT3155: We would like to get: %d KB\n", full_size_kbs);
+ printk("DT3155: ...but need at least: %d KB\n", min_size_kbs);
+ printk("DT3155: ...the allocator has: %d KB\n", allocator_max);
+ size_kbs = (full_size_kbs <= allocator_max ? full_size_kbs : allocator_max);
+ if (size_kbs > min_size_kbs) {
+ if ((*buf_addr = allocator_allocate_dma (size_kbs, GFP_KERNEL)) != 0) {
+ printk("DT3155: Managed to allocate: %d KB\n", size_kbs);
+ *total_size_kbs = size_kbs;
+ return;
+ }
+ }
+ /* If we got here, the allocation failed */
+ printk ("DT3155: Allocator failed!\n");
+ *buf_addr = 0;
+ *total_size_kbs = 0;
+ return;
+
+}
+
+
+/*****************************************************
+ * dt3155_setup_buffers
+ *
+ * setup_buffers just puts the buffering system into
+ * a consistent state before the start of interrupts
+ *
+ * JML : it looks like all the buffers need to be
+ * continuous. So I'm going to try and allocate one
+ * continuous buffer.
+ *
+ * GCS : Fix DMA problems when buffer spans
+ * 4MB boundary. Also, add error checking. This
+ * function will return -ENOMEM when not enough memory.
+ *****************************************************/
+u32 dt3155_setup_buffers(u32 *allocatorAddr)
+
+{
+ u32 index;
+ u32 rambuff_addr; /* start of allocation */
+ u32 rambuff_size; /* total size allocated to driver */
+ u32 rambuff_acm; /* accumlator, keep track of how much
+ is left after being split up*/
+ u32 rambuff_end; /* end of rambuff */
+ u32 numbufs; /* number of useful buffers allocated (per device) */
+ u32 bufsize = DT3155_MAX_ROWS * DT3155_MAX_COLS;
+ int m; /* minor # of device, looped for all devs */
+
+ /* zero the fbuffer status and address structure */
+ for ( m = 0; m < ndevices; m++)
+ {
+ dt3155_fbuffer[ m ] = &(dt3155_status[ m ].fbuffer);
+
+ /* Make sure the buffering variables are consistent */
+ {
+ u8 *ptr = (u8 *) dt3155_fbuffer[ m ];
+ for( index = 0; index < sizeof(struct dt3155_fbuffer_s); index++)
+ *(ptr++)=0;
+ }
+ }
+
+ /* allocate a large contiguous chunk of RAM */
+ allocate_buffers (&rambuff_addr, &rambuff_size, bufsize);
+ printk("DT3155: mem info\n");
+ printk(" - rambuf_addr = 0x%x \n", rambuff_addr);
+ printk(" - length (kb) = %u \n", rambuff_size);
+ if( rambuff_addr == 0 )
+ {
+ printk( KERN_INFO
+ "DT3155: Error setup_buffers() allocator dma failed \n" );
+ return -ENOMEM;
+ }
+ *allocatorAddr = rambuff_addr;
+ rambuff_end = rambuff_addr + 1024 * rambuff_size;
+
+ /* after allocation, we need to count how many useful buffers there
+ are so we can give an equal number to each device */
+ rambuff_acm = rambuff_addr;
+ for ( index = 0; index < MAXBUFFERS; index++) {
+ rambuff_acm = adjust_4MB (rambuff_acm, bufsize);/*avoid spanning 4MB bdry*/
+ if (rambuff_acm + bufsize > rambuff_end)
+ break;
+ rambuff_acm += bufsize;
+ }
+ /* Following line is OK, will waste buffers if index
+ * not evenly divisible by ndevices -NJC*/
+ numbufs = index / ndevices;
+ printk(" - numbufs = %u\n", numbufs);
+ if (numbufs < 2) {
+ printk( KERN_INFO
+ "DT3155: Error setup_buffers() couldn't allocate 2 bufs/board\n" );
+ return -ENOMEM;
+ }
+
+ /* now that we have board memory we spit it up */
+ /* between the boards and the buffers */
+ rambuff_acm = rambuff_addr;
+ for ( m = 0; m < ndevices; m ++)
+ {
+ rambuff_acm = adjust_4MB (rambuff_acm, bufsize);
+
+ /* Save the start of this boards buffer space (for mmap). */
+ dt3155_status[ m ].mem_addr = rambuff_acm;
+
+ for (index = 0; index < numbufs; index++)
+ {
+ rambuff_acm = adjust_4MB (rambuff_acm, bufsize);
+ if (rambuff_acm + bufsize > rambuff_end) {
+ /* Should never happen */
+ printk ("DT3155 PROGRAM ERROR (GCS)\n"
+ "Error distributing allocated buffers\n");
+ return -ENOMEM;
+ }
+
+ dt3155_fbuffer[ m ]->frame_info[ index ].addr = rambuff_acm;
+ push_empty( index, m );
+ /* printk(" - Buffer : %lx\n",
+ * dt3155_fbuffer[ m ]->frame_info[ index ].addr );
+ */
+ dt3155_fbuffer[ m ]->nbuffers += 1;
+ rambuff_acm += bufsize;
+ }
+
+ /* Make sure there is an active buffer there. */
+ dt3155_fbuffer[ m ]->active_buf = pop_empty( m );
+ dt3155_fbuffer[ m ]->even_happened = 0;
+ dt3155_fbuffer[ m ]->even_stopped = 0;
+
+ /* make sure there is no locked_buf JML 2/28/00 */
+ dt3155_fbuffer[ m ]->locked_buf = -1;
+
+ dt3155_status[ m ].mem_size =
+ rambuff_acm - dt3155_status[ m ].mem_addr;
+
+ /* setup the ready queue */
+ dt3155_fbuffer[ m ]->ready_head = 0;
+ dt3155_fbuffer[ m ]->ready_len = 0;
+ printk("Available buffers for device %d: %d\n",
+ m, dt3155_fbuffer[ m ]->nbuffers);
+ }
+
+ return 1;
+}
+
+/*****************************************************
+ * internal_release_locked_buffer
+ *
+ * The internal function for releasing a locked buffer.
+ * It assumes interrupts are turned off.
+ *
+ * m is minor number of device
+ *****************************************************/
+static inline void internal_release_locked_buffer( int m )
+{
+ /* Pointer into global structure for handling buffers */
+ if ( dt3155_fbuffer[ m ]->locked_buf >= 0 )
+ {
+ push_empty( dt3155_fbuffer[ m ]->locked_buf, m );
+ dt3155_fbuffer[ m ]->locked_buf = -1;
+ }
+}
+
+
+/*****************************************************
+ * dt3155_release_locked_buffer()
+ * m is minor # of device
+ *
+ * The user function of the above.
+ *
+ *****************************************************/
+inline void dt3155_release_locked_buffer( int m )
+{
+ unsigned long int flags;
+ local_save_flags(flags);
+ local_irq_disable();
+ internal_release_locked_buffer(m);
+ local_irq_restore(flags);
+}
+
+
+/*****************************************************
+ * dt3155_flush()
+ * m is minor # of device
+ *
+ *****************************************************/
+inline int dt3155_flush( int m )
+{
+ int index;
+ unsigned long int flags;
+ local_save_flags(flags);
+ local_irq_disable();
+
+ internal_release_locked_buffer( m );
+ dt3155_fbuffer[ m ]->empty_len = 0;
+
+ for ( index = 0; index < dt3155_fbuffer[ m ]->nbuffers; index++ )
+ push_empty( index, m );
+
+ /* Make sure there is an active buffer there. */
+ dt3155_fbuffer[ m ]->active_buf = pop_empty( m );
+
+ dt3155_fbuffer[ m ]->even_happened = 0;
+ dt3155_fbuffer[ m ]->even_stopped = 0;
+
+ /* setup the ready queue */
+ dt3155_fbuffer[ m ]->ready_head = 0;
+ dt3155_fbuffer[ m ]->ready_len = 0;
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+/*****************************************************
+ * dt3155_get_ready_buffer()
+ * m is minor # of device
+ *
+ * get_ready_buffer will grab the next chunk of data
+ * if it is already there, otherwise it returns 0.
+ * If the user has a buffer locked it will unlock
+ * that buffer before returning the new one.
+ *****************************************************/
+inline int dt3155_get_ready_buffer( int m )
+{
+ int frame_index;
+ unsigned long int flags;
+ local_save_flags(flags);
+ local_irq_disable();
+
+#ifdef DEBUG_QUES_A
+ printques( m );
+#endif
+
+ internal_release_locked_buffer( m );
+
+ if (is_ready_buf_empty( m ))
+ frame_index = -1;
+ else
+ {
+ frame_index = pop_ready( m );
+ dt3155_fbuffer[ m ]->locked_buf = frame_index;
+ }
+
+#ifdef DEBUG_QUES_B
+ printques( m );
+#endif
+
+ local_irq_restore(flags);
+
+ return frame_index;
+}
diff --git a/drivers/staging/dt3155/dt3155_isr.h b/drivers/staging/dt3155/dt3155_isr.h
new file mode 100644
index 000000000000..7595cb16c988
--- /dev/null
+++ b/drivers/staging/dt3155/dt3155_isr.h
@@ -0,0 +1,77 @@
+/*
+
+Copyright 1996,2002 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
+ Jason Lapenta, Scott Smedley
+
+This file is part of the DT3155 Device Driver.
+
+The DT3155 Device Driver 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.
+
+The DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+MA 02111-1307 USA
+
+
+-- Changes --
+
+ Date Programmer Description of changes made
+ -------------------------------------------------------------------
+ 03-Jul-2000 JML n/a
+ 24-Jul-2002 SS GPL licence.
+ 26-Oct-2009 SS Porting to 2.6.30 kernel.
+
+-- notes --
+
+*/
+
+#ifndef DT3155_ISR_H
+#define DT3155_ISR_H
+
+extern struct dt3155_fbuffer_s *dt3155_fbuffer[MAXBOARDS];
+
+/* User functions for buffering */
+/* Initialize the buffering system. This should */
+/* be called prior to enabling interrupts */
+
+u32 dt3155_setup_buffers(u32 *allocatorAddr);
+
+/* Get the next frame of data if it is ready. Returns */
+/* zero if no data is ready. If there is data but */
+/* the user has a locked buffer, it will unlock that */
+/* buffer and return it to the free list. */
+
+int dt3155_get_ready_buffer(int minor);
+
+/* Return a locked buffer to the free list */
+
+void dt3155_release_locked_buffer(int minor);
+
+/* Flush the buffer system */
+int dt3155_flush(int minor);
+
+/**********************************
+ * Simple array based que struct
+ **********************************/
+
+bool are_empty_buffers(int minor);
+void push_empty(int index, int minor);
+
+int pop_empty(int minor);
+
+bool is_ready_buf_empty(int minor);
+bool is_ready_buf_full(int minor);
+
+void push_ready(int minor, int index);
+int pop_ready(int minor);
+
+
+#endif
diff --git a/drivers/staging/et131x/et1310_address_map.h b/drivers/staging/et131x/et1310_address_map.h
index 6da843cc343c..ea746ba41faf 100644
--- a/drivers/staging/et131x/et1310_address_map.h
+++ b/drivers/staging/et131x/et1310_address_map.h
@@ -149,7 +149,7 @@
* GLOBAL Module of JAGCore Address Mapping
* Located at address 0x0000
*/
-typedef struct _GLOBAL_t { /* Location: */
+struct global_regs { /* Location: */
u32 txq_start_addr; /* 0x0000 */
u32 txq_end_addr; /* 0x0004 */
u32 rxq_start_addr; /* 0x0008 */
@@ -165,9 +165,7 @@ typedef struct _GLOBAL_t { /* Location: */
u32 msi_config; /* 0x0030 */
u32 loopback; /* 0x0034 */
u32 watchdog_timer; /* 0x0038 */
-} GLOBAL_t, *PGLOBAL_t;
-
-/* END OF GLOBAL REGISTER ADDRESS MAP */
+};
/* START OF TXDMA REGISTER ADDRESS MAP */
@@ -203,11 +201,14 @@ typedef struct _GLOBAL_t { /* Location: */
* 9-0: pr ndes
*/
-#define ET_DMA10_MASK 0x3FF /* 10 bit mask for DMA10W types */
-#define ET_DMA10_WRAP 0x400
-#define ET_DMA4_MASK 0x00F /* 4 bit mask for DMA4W types */
-#define ET_DMA4_WRAP 0x010
+#define ET_DMA12_MASK 0x0FFF /* 12 bit mask for DMA12W types */
+#define ET_DMA12_WRAP 0x1000
+#define ET_DMA10_MASK 0x03FF /* 10 bit mask for DMA10W types */
+#define ET_DMA10_WRAP 0x0400
+#define ET_DMA4_MASK 0x000F /* 4 bit mask for DMA4W types */
+#define ET_DMA4_WRAP 0x0010
+#define INDEX12(x) ((x) & ET_DMA12_MASK)
#define INDEX10(x) ((x) & ET_DMA10_MASK)
#define INDEX4(x) ((x) & ET_DMA4_MASK)
@@ -216,6 +217,11 @@ extern inline void add_10bit(u32 *v, int n)
*v = INDEX10(*v + n) | (*v & ET_DMA10_WRAP);
}
+extern inline void add_12bit(u32 *v, int n)
+{
+ *v = INDEX12(*v + n) | (*v & ET_DMA12_WRAP);
+}
+
/*
* 10bit DMA with wrap
* txdma tx queue write address reg in txdma address map at 0x1010
@@ -247,7 +253,7 @@ extern inline void add_10bit(u32 *v, int n)
* Tx DMA Module of JAGCore Address Mapping
* Located at address 0x1000
*/
-typedef struct _TXDMA_t { /* Location: */
+struct txdma_regs { /* Location: */
u32 csr; /* 0x1000 */
u32 pr_base_hi; /* 0x1004 */
u32 pr_base_lo; /* 0x1008 */
@@ -274,7 +280,7 @@ typedef struct _TXDMA_t { /* Location: */
u32 DroppedTLPCount; /* 0x105c */
u32 NewServiceComplete; /* 0x1060 */
u32 EthernetPacketCount; /* 0x1064 */
-} TXDMA_t, *PTXDMA_t;
+};
/* END OF TXDMA REGISTER ADDRESS MAP */
@@ -284,45 +290,25 @@ typedef struct _TXDMA_t { /* Location: */
/*
* structure for control status reg in rxdma address map
* Located at address 0x2000
+ *
+ * CSR
+ * 0: halt
+ * 1-3: tc
+ * 4: fbr_big_endian
+ * 5: psr_big_endian
+ * 6: pkt_big_endian
+ * 7: dma_big_endian
+ * 8-9: fbr0_size
+ * 10: fbr0_enable
+ * 11-12: fbr1_size
+ * 13: fbr1_enable
+ * 14: unused
+ * 15: pkt_drop_disable
+ * 16: pkt_done_flush
+ * 17: halt_status
+ * 18-31: unused
*/
-typedef union _RXDMA_CSR_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 unused2:14; /* bits 18-31 */
- u32 halt_status:1; /* bit 17 */
- u32 pkt_done_flush:1; /* bit 16 */
- u32 pkt_drop_disable:1; /* bit 15 */
- u32 unused1:1; /* bit 14 */
- u32 fbr1_enable:1; /* bit 13 */
- u32 fbr1_size:2; /* bits 11-12 */
- u32 fbr0_enable:1; /* bit 10 */
- u32 fbr0_size:2; /* bits 8-9 */
- u32 dma_big_endian:1; /* bit 7 */
- u32 pkt_big_endian:1; /* bit 6 */
- u32 psr_big_endian:1; /* bit 5 */
- u32 fbr_big_endian:1; /* bit 4 */
- u32 tc:3; /* bits 1-3 */
- u32 halt:1; /* bit 0 */
-#else
- u32 halt:1; /* bit 0 */
- u32 tc:3; /* bits 1-3 */
- u32 fbr_big_endian:1; /* bit 4 */
- u32 psr_big_endian:1; /* bit 5 */
- u32 pkt_big_endian:1; /* bit 6 */
- u32 dma_big_endian:1; /* bit 7 */
- u32 fbr0_size:2; /* bits 8-9 */
- u32 fbr0_enable:1; /* bit 10 */
- u32 fbr1_size:2; /* bits 11-12 */
- u32 fbr1_enable:1; /* bit 13 */
- u32 unused1:1; /* bit 14 */
- u32 pkt_drop_disable:1; /* bit 15 */
- u32 pkt_done_flush:1; /* bit 16 */
- u32 halt_status:1; /* bit 17 */
- u32 unused2:14; /* bits 18-31 */
-#endif
- } bits;
-} RXDMA_CSR_t, *PRXDMA_CSR_t;
+
/*
* structure for dma writeback lo reg in rxdma address map
@@ -443,18 +429,6 @@ typedef union _RXDMA_CSR_t {
* 31-10: unused
* 9-0: fbr ndesc
*/
-typedef union _RXDMA_FBR_NUM_DES_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 unused:22; /* bits 10-31 */
- u32 fbr_ndesc:10; /* bits 0-9 */
-#else
- u32 fbr_ndesc:10; /* bits 0-9 */
- u32 unused:22; /* bits 10-31 */
-#endif
- } bits;
-} RXDMA_FBR_NUM_DES_t, *PRXDMA_FBR_NUM_DES_t;
/*
* structure for free buffer ring 0 available offset reg in rxdma address map
@@ -524,8 +498,8 @@ typedef union _RXDMA_FBR_NUM_DES_t {
* Rx DMA Module of JAGCore Address Mapping
* Located at address 0x2000
*/
-typedef struct _RXDMA_t { /* Location: */
- RXDMA_CSR_t csr; /* 0x2000 */
+struct rxdma_regs { /* Location: */
+ u32 csr; /* 0x2000 */
u32 dma_wb_base_lo; /* 0x2004 */
u32 dma_wb_base_hi; /* 0x2008 */
u32 num_pkt_done; /* 0x200C */
@@ -554,7 +528,7 @@ typedef struct _RXDMA_t { /* Location: */
u32 fbr1_full_offset; /* 0x2068 */
u32 fbr1_rd_index; /* 0x206C */
u32 fbr1_min_des; /* 0x2070 */
-} RXDMA_t, *PRXDMA_t;
+};
/* END OF RXDMA REGISTER ADDRESS MAP */
@@ -564,33 +538,18 @@ typedef struct _RXDMA_t { /* Location: */
/*
* structure for control reg in txmac address map
* located at address 0x3000
+ *
+ * bits
+ * 31-8: unused
+ * 7: cklseg_disable
+ * 6: ckbcnt_disable
+ * 5: cksegnum
+ * 4: async_disable
+ * 3: fc_disable
+ * 2: mcif_disable
+ * 1: mif_disable
+ * 0: txmac_en
*/
-typedef union _TXMAC_CTL_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 unused:24; /* bits 8-31 */
- u32 cklseg_diable:1; /* bit 7 */
- u32 ckbcnt_disable:1; /* bit 6 */
- u32 cksegnum:1; /* bit 5 */
- u32 async_disable:1; /* bit 4 */
- u32 fc_disable:1; /* bit 3 */
- u32 mcif_disable:1; /* bit 2 */
- u32 mif_disable:1; /* bit 1 */
- u32 txmac_en:1; /* bit 0 */
-#else
- u32 txmac_en:1; /* bit 0 */
- u32 mif_disable:1; /* bit 1 mac interface */
- u32 mcif_disable:1; /* bit 2 mem. contr. interface */
- u32 fc_disable:1; /* bit 3 */
- u32 async_disable:1; /* bit 4 */
- u32 cksegnum:1; /* bit 5 */
- u32 ckbcnt_disable:1; /* bit 6 */
- u32 cklseg_diable:1; /* bit 7 */
- u32 unused:24; /* bits 8-31 */
-#endif
- } bits;
-} TXMAC_CTL_t, *PTXMAC_CTL_t;
/*
* structure for shadow pointer reg in txmac address map
@@ -604,23 +563,12 @@ typedef union _TXMAC_CTL_t {
/*
* structure for error count reg in txmac address map
* located at address 0x3008
+ *
+ * 31-12: unused
+ * 11-8: reserved
+ * 7-4: txq_underrun
+ * 3-0: fifo_underrun
*/
-typedef union _TXMAC_ERR_CNT_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 unused:20; /* bits 12-31 */
- u32 reserved:4; /* bits 8-11 */
- u32 txq_underrun:4; /* bits 4-7 */
- u32 fifo_underrun:4; /* bits 0-3 */
-#else
- u32 fifo_underrun:4; /* bits 0-3 */
- u32 txq_underrun:4; /* bits 4-7 */
- u32 reserved:4; /* bits 8-11 */
- u32 unused:20; /* bits 12-31 */
-#endif
- } bits;
-} TXMAC_ERR_CNT_t, *PTXMAC_ERR_CNT_t;
/*
* structure for max fill reg in txmac address map
@@ -649,64 +597,32 @@ typedef union _TXMAC_ERR_CNT_t {
/*
* structure for error reg in txmac address map
* located at address 0x3018
+ *
+ * 31-9: unused
+ * 8: fifo_underrun
+ * 7-6: unused
+ * 5: ctrl2_err
+ * 4: txq_underrun
+ * 3: bcnt_err
+ * 2: lseg_err
+ * 1: segnum_err
+ * 0: seg0_err
*/
-typedef union _TXMAC_ERR_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 unused2:23; /* bits 9-31 */
- u32 fifo_underrun:1; /* bit 8 */
- u32 unused1:2; /* bits 6-7 */
- u32 ctrl2_err:1; /* bit 5 */
- u32 txq_underrun:1; /* bit 4 */
- u32 bcnt_err:1; /* bit 3 */
- u32 lseg_err:1; /* bit 2 */
- u32 segnum_err:1; /* bit 1 */
- u32 seg0_err:1; /* bit 0 */
-#else
- u32 seg0_err:1; /* bit 0 */
- u32 segnum_err:1; /* bit 1 */
- u32 lseg_err:1; /* bit 2 */
- u32 bcnt_err:1; /* bit 3 */
- u32 txq_underrun:1; /* bit 4 */
- u32 ctrl2_err:1; /* bit 5 */
- u32 unused1:2; /* bits 6-7 */
- u32 fifo_underrun:1; /* bit 8 */
- u32 unused2:23; /* bits 9-31 */
-#endif
- } bits;
-} TXMAC_ERR_t, *PTXMAC_ERR_t;
/*
* structure for error interrupt reg in txmac address map
* located at address 0x301C
+ *
+ * 31-9: unused
+ * 8: fifo_underrun
+ * 7-6: unused
+ * 5: ctrl2_err
+ * 4: txq_underrun
+ * 3: bcnt_err
+ * 2: lseg_err
+ * 1: segnum_err
+ * 0: seg0_err
*/
-typedef union _TXMAC_ERR_INT_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 unused2:23; /* bits 9-31 */
- u32 fifo_underrun:1; /* bit 8 */
- u32 unused1:2; /* bits 6-7 */
- u32 ctrl2_err:1; /* bit 5 */
- u32 txq_underrun:1; /* bit 4 */
- u32 bcnt_err:1; /* bit 3 */
- u32 lseg_err:1; /* bit 2 */
- u32 segnum_err:1; /* bit 1 */
- u32 seg0_err:1; /* bit 0 */
-#else
- u32 seg0_err:1; /* bit 0 */
- u32 segnum_err:1; /* bit 1 */
- u32 lseg_err:1; /* bit 2 */
- u32 bcnt_err:1; /* bit 3 */
- u32 txq_underrun:1; /* bit 4 */
- u32 ctrl2_err:1; /* bit 5 */
- u32 unused1:2; /* bits 6-7 */
- u32 fifo_underrun:1; /* bit 8 */
- u32 unused2:23; /* bits 9-31 */
-#endif
- } bits;
-} TXMAC_ERR_INT_t, *PTXMAC_ERR_INT_t;
/*
* structure for error interrupt reg in txmac address map
@@ -720,17 +636,17 @@ typedef union _TXMAC_ERR_INT_t {
/*
* Tx MAC Module of JAGCore Address Mapping
*/
-typedef struct _TXMAC_t { /* Location: */
- TXMAC_CTL_t ctl; /* 0x3000 */
+struct txmac_regs { /* Location: */
+ u32 ctl; /* 0x3000 */
u32 shadow_ptr; /* 0x3004 */
- TXMAC_ERR_CNT_t err_cnt; /* 0x3008 */
+ u32 err_cnt; /* 0x3008 */
u32 max_fill; /* 0x300C */
u32 cf_param; /* 0x3010 */
u32 tx_test; /* 0x3014 */
- TXMAC_ERR_t err; /* 0x3018 */
- TXMAC_ERR_INT_t err_int; /* 0x301C */
+ u32 err; /* 0x3018 */
+ u32 err_int; /* 0x301C */
u32 bp_ctrl; /* 0x3020 */
-} TXMAC_t, *PTXMAC_t;
+};
/* END OF TXMAC REGISTER ADDRESS MAP */
@@ -739,106 +655,47 @@ typedef struct _TXMAC_t { /* Location: */
/*
* structure for rxmac control reg in rxmac address map
* located at address 0x4000
+ *
+ * 31-7: reserved
+ * 6: rxmac_int_disable
+ * 5: async_disable
+ * 4: mif_disable
+ * 3: wol_disable
+ * 2: pkt_filter_disable
+ * 1: mcif_disable
+ * 0: rxmac_en
*/
-typedef union _RXMAC_CTRL_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 reserved:25; /* bits 7-31 */
- u32 rxmac_int_disable:1; /* bit 6 */
- u32 async_disable:1; /* bit 5 */
- u32 mif_disable:1; /* bit 4 */
- u32 wol_disable:1; /* bit 3 */
- u32 pkt_filter_disable:1; /* bit 2 */
- u32 mcif_disable:1; /* bit 1 */
- u32 rxmac_en:1; /* bit 0 */
-#else
- u32 rxmac_en:1; /* bit 0 */
- u32 mcif_disable:1; /* bit 1 */
- u32 pkt_filter_disable:1; /* bit 2 */
- u32 wol_disable:1; /* bit 3 */
- u32 mif_disable:1; /* bit 4 */
- u32 async_disable:1; /* bit 5 */
- u32 rxmac_int_disable:1; /* bit 6 */
- u32 reserved:25; /* bits 7-31 */
-#endif
- } bits;
-} RXMAC_CTRL_t, *PRXMAC_CTRL_t;
/*
* structure for Wake On Lan Control and CRC 0 reg in rxmac address map
* located at address 0x4004
+ * 31-16: crc
+ * 15-12: reserved
+ * 11: ignore_pp
+ * 10: ignore_mp
+ * 9: clr_intr
+ * 8: ignore_link_chg
+ * 7: ignore_uni
+ * 6: ignore_multi
+ * 5: ignore_broad
+ * 4-0: valid_crc 4-0
*/
-typedef union _RXMAC_WOL_CTL_CRC0_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 crc0:16; /* bits 16-31 */
- u32 reserve:4; /* bits 12-15 */
- u32 ignore_pp:1; /* bit 11 */
- u32 ignore_mp:1; /* bit 10 */
- u32 clr_intr:1; /* bit 9 */
- u32 ignore_link_chg:1; /* bit 8 */
- u32 ignore_uni:1; /* bit 7 */
- u32 ignore_multi:1; /* bit 6 */
- u32 ignore_broad:1; /* bit 5 */
- u32 valid_crc4:1; /* bit 4 */
- u32 valid_crc3:1; /* bit 3 */
- u32 valid_crc2:1; /* bit 2 */
- u32 valid_crc1:1; /* bit 1 */
- u32 valid_crc0:1; /* bit 0 */
-#else
- u32 valid_crc0:1; /* bit 0 */
- u32 valid_crc1:1; /* bit 1 */
- u32 valid_crc2:1; /* bit 2 */
- u32 valid_crc3:1; /* bit 3 */
- u32 valid_crc4:1; /* bit 4 */
- u32 ignore_broad:1; /* bit 5 */
- u32 ignore_multi:1; /* bit 6 */
- u32 ignore_uni:1; /* bit 7 */
- u32 ignore_link_chg:1; /* bit 8 */
- u32 clr_intr:1; /* bit 9 */
- u32 ignore_mp:1; /* bit 10 */
- u32 ignore_pp:1; /* bit 11 */
- u32 reserve:4; /* bits 12-15 */
- u32 crc0:16; /* bits 16-31 */
-#endif
- } bits;
-} RXMAC_WOL_CTL_CRC0_t, *PRXMAC_WOL_CTL_CRC0_t;
/*
* structure for CRC 1 and CRC 2 reg in rxmac address map
* located at address 0x4008
+ *
+ * 31-16: crc2
+ * 15-0: crc1
*/
-typedef union _RXMAC_WOL_CRC12_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 crc2:16; /* bits 16-31 */
- u32 crc1:16; /* bits 0-15 */
-#else
- u32 crc1:16; /* bits 0-15 */
- u32 crc2:16; /* bits 16-31 */
-#endif
- } bits;
-} RXMAC_WOL_CRC12_t, *PRXMAC_WOL_CRC12_t;
/*
* structure for CRC 3 and CRC 4 reg in rxmac address map
* located at address 0x400C
+ *
+ * 31-16: crc4
+ * 15-0: crc3
*/
-typedef union _RXMAC_WOL_CRC34_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 crc4:16; /* bits 16-31 */
- u32 crc3:16; /* bits 0-15 */
-#else
- u32 crc3:16; /* bits 0-15 */
- u32 crc4:16; /* bits 16-31 */
-#endif
- } bits;
-} RXMAC_WOL_CRC34_t, *PRXMAC_WOL_CRC34_t;
/*
* structure for Wake On Lan Source Address Lo reg in rxmac address map
@@ -958,164 +815,84 @@ typedef union _RXMAC_UNI_PF_ADDR3_t {
/*
* structure for Packet Filter Control reg in rxmac address map
* located at address 0x4084
+ *
+ * 31-23: unused
+ * 22-16: min_pkt_size
+ * 15-4: unused
+ * 3: filter_frag_en
+ * 2: filter_uni_en
+ * 1: filter_multi_en
+ * 0: filter_broad_en
*/
-typedef union _RXMAC_PF_CTRL_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 unused2:9; /* bits 23-31 */
- u32 min_pkt_size:7; /* bits 16-22 */
- u32 unused1:12; /* bits 4-15 */
- u32 filter_frag_en:1; /* bit 3 */
- u32 filter_uni_en:1; /* bit 2 */
- u32 filter_multi_en:1; /* bit 1 */
- u32 filter_broad_en:1; /* bit 0 */
-#else
- u32 filter_broad_en:1; /* bit 0 */
- u32 filter_multi_en:1; /* bit 1 */
- u32 filter_uni_en:1; /* bit 2 */
- u32 filter_frag_en:1; /* bit 3 */
- u32 unused1:12; /* bits 4-15 */
- u32 min_pkt_size:7; /* bits 16-22 */
- u32 unused2:9; /* bits 23-31 */
-#endif
- } bits;
-} RXMAC_PF_CTRL_t, *PRXMAC_PF_CTRL_t;
/*
* structure for Memory Controller Interface Control Max Segment reg in rxmac
* address map. Located at address 0x4088
+ *
+ * 31-10: reserved
+ * 9-2: max_size
+ * 1: fc_en
+ * 0: seg_en
*/
-typedef union _RXMAC_MCIF_CTRL_MAX_SEG_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 reserved:22; /* bits 10-31 */
- u32 max_size:8; /* bits 2-9 */
- u32 fc_en:1; /* bit 1 */
- u32 seg_en:1; /* bit 0 */
-#else
- u32 seg_en:1; /* bit 0 */
- u32 fc_en:1; /* bit 1 */
- u32 max_size:8; /* bits 2-9 */
- u32 reserved:22; /* bits 10-31 */
-#endif
- } bits;
-} RXMAC_MCIF_CTRL_MAX_SEG_t, *PRXMAC_MCIF_CTRL_MAX_SEG_t;
/*
* structure for Memory Controller Interface Water Mark reg in rxmac address
* map. Located at address 0x408C
+ *
+ * 31-26: unused
+ * 25-16: mark_hi
+ * 15-10: unused
+ * 9-0: mark_lo
*/
-typedef union _RXMAC_MCIF_WATER_MARK_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 reserved2:6; /* bits 26-31 */
- u32 mark_hi:10; /* bits 16-25 */
- u32 reserved1:6; /* bits 10-15 */
- u32 mark_lo:10; /* bits 0-9 */
-#else
- u32 mark_lo:10; /* bits 0-9 */
- u32 reserved1:6; /* bits 10-15 */
- u32 mark_hi:10; /* bits 16-25 */
- u32 reserved2:6; /* bits 26-31 */
-#endif
- } bits;
-} RXMAC_MCIF_WATER_MARK_t, *PRXMAC_MCIF_WATER_MARK_t;
/*
* structure for Rx Queue Dialog reg in rxmac address map.
* located at address 0x4090
+ *
+ * 31-26: reserved
+ * 25-16: rd_ptr
+ * 15-10: reserved
+ * 9-0: wr_ptr
*/
-typedef union _RXMAC_RXQ_DIAG_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 reserved2:6; /* bits 26-31 */
- u32 rd_ptr:10; /* bits 16-25 */
- u32 reserved1:6; /* bits 10-15 */
- u32 wr_ptr:10; /* bits 0-9 */
-#else
- u32 wr_ptr:10; /* bits 0-9 */
- u32 reserved1:6; /* bits 10-15 */
- u32 rd_ptr:10; /* bits 16-25 */
- u32 reserved2:6; /* bits 26-31 */
-#endif
- } bits;
-} RXMAC_RXQ_DIAG_t, *PRXMAC_RXQ_DIAG_t;
/*
* structure for space availiable reg in rxmac address map.
* located at address 0x4094
+ *
+ * 31-17: reserved
+ * 16: space_avail_en
+ * 15-10: reserved
+ * 9-0: space_avail
*/
-typedef union _RXMAC_SPACE_AVAIL_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 reserved2:15; /* bits 17-31 */
- u32 space_avail_en:1; /* bit 16 */
- u32 reserved1:6; /* bits 10-15 */
- u32 space_avail:10; /* bits 0-9 */
-#else
- u32 space_avail:10; /* bits 0-9 */
- u32 reserved1:6; /* bits 10-15 */
- u32 space_avail_en:1; /* bit 16 */
- u32 reserved2:15; /* bits 17-31 */
-#endif
- } bits;
-} RXMAC_SPACE_AVAIL_t, *PRXMAC_SPACE_AVAIL_t;
/*
* structure for management interface reg in rxmac address map.
* located at address 0x4098
+ *
+ * 31-18: reserved
+ * 17: drop_pkt_en
+ * 16-0: drop_pkt_mask
*/
-typedef union _RXMAC_MIF_CTL_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 reserve:14; /* bits 18-31 */
- u32 drop_pkt_en:1; /* bit 17 */
- u32 drop_pkt_mask:17; /* bits 0-16 */
-#else
- u32 drop_pkt_mask:17; /* bits 0-16 */
- u32 drop_pkt_en:1; /* bit 17 */
- u32 reserve:14; /* bits 18-31 */
-#endif
- } bits;
-} RXMAC_MIF_CTL_t, *PRXMAC_MIF_CTL_t;
/*
* structure for Error reg in rxmac address map.
* located at address 0x409C
+ *
+ * 31-4: unused
+ * 3: mif
+ * 2: async
+ * 1: pkt_filter
+ * 0: mcif
*/
-typedef union _RXMAC_ERROR_REG_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 reserve:28; /* bits 4-31 */
- u32 mif:1; /* bit 3 */
- u32 async:1; /* bit 2 */
- u32 pkt_filter:1; /* bit 1 */
- u32 mcif:1; /* bit 0 */
-#else
- u32 mcif:1; /* bit 0 */
- u32 pkt_filter:1; /* bit 1 */
- u32 async:1; /* bit 2 */
- u32 mif:1; /* bit 3 */
- u32 reserve:28; /* bits 4-31 */
-#endif
- } bits;
-} RXMAC_ERROR_REG_t, *PRXMAC_ERROR_REG_t;
/*
* Rx MAC Module of JAGCore Address Mapping
*/
typedef struct _RXMAC_t { /* Location: */
- RXMAC_CTRL_t ctrl; /* 0x4000 */
- RXMAC_WOL_CTL_CRC0_t crc0; /* 0x4004 */
- RXMAC_WOL_CRC12_t crc12; /* 0x4008 */
- RXMAC_WOL_CRC34_t crc34; /* 0x400C */
+ u32 ctrl; /* 0x4000 */
+ u32 crc0; /* 0x4004 */
+ u32 crc12; /* 0x4008 */
+ u32 crc34; /* 0x400C */
RXMAC_WOL_SA_LO_t sa_lo; /* 0x4010 */
RXMAC_WOL_SA_HI_t sa_hi; /* 0x4014 */
u32 mask0_word0; /* 0x4018 */
@@ -1145,17 +922,17 @@ typedef struct _RXMAC_t { /* Location: */
u32 multi_hash2; /* 0x4078 */
u32 multi_hash3; /* 0x407C */
u32 multi_hash4; /* 0x4080 */
- RXMAC_PF_CTRL_t pf_ctrl; /* 0x4084 */
- RXMAC_MCIF_CTRL_MAX_SEG_t mcif_ctrl_max_seg; /* 0x4088 */
- RXMAC_MCIF_WATER_MARK_t mcif_water_mark; /* 0x408C */
- RXMAC_RXQ_DIAG_t rxq_diag; /* 0x4090 */
- RXMAC_SPACE_AVAIL_t space_avail; /* 0x4094 */
-
- RXMAC_MIF_CTL_t mif_ctrl; /* 0x4098 */
- RXMAC_ERROR_REG_t err_reg; /* 0x409C */
+ u32 pf_ctrl; /* 0x4084 */
+ u32 mcif_ctrl_max_seg; /* 0x4088 */
+ u32 mcif_water_mark; /* 0x408C */
+ u32 rxq_diag; /* 0x4090 */
+ u32 space_avail; /* 0x4094 */
+
+ u32 mif_ctrl; /* 0x4098 */
+ u32 err_reg; /* 0x409C */
} RXMAC_t, *PRXMAC_t;
-/* END OF TXMAC REGISTER ADDRESS MAP */
+/* END OF RXMAC REGISTER ADDRESS MAP */
/* START OF MAC REGISTER ADDRESS MAP */
@@ -1329,37 +1106,19 @@ typedef struct _RXMAC_t { /* Location: */
/*
* structure for Interface Status reg in mac address map.
* located at address 0x503C
+ *
+ * 31-10: reserved
+ * 9: excess_defer
+ * 8: clash
+ * 7: phy_jabber
+ * 6: phy_link_ok
+ * 5: phy_full_duplex
+ * 4: phy_speed
+ * 3: pe100x_link_fail
+ * 2: pe10t_loss_carrier
+ * 1: pe10t_sqe_error
+ * 0: pe10t_jabber
*/
-typedef union _MAC_IF_STAT_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 reserved:22; /* bits 10-31 */
- u32 excess_defer:1; /* bit 9 */
- u32 clash:1; /* bit 8 */
- u32 phy_jabber:1; /* bit 7 */
- u32 phy_link_ok:1; /* bit 6 */
- u32 phy_full_duplex:1; /* bit 5 */
- u32 phy_speed:1; /* bit 4 */
- u32 pe100x_link_fail:1; /* bit 3 */
- u32 pe10t_loss_carrie:1; /* bit 2 */
- u32 pe10t_sqe_error:1; /* bit 1 */
- u32 pe10t_jabber:1; /* bit 0 */
-#else
- u32 pe10t_jabber:1; /* bit 0 */
- u32 pe10t_sqe_error:1; /* bit 1 */
- u32 pe10t_loss_carrie:1; /* bit 2 */
- u32 pe100x_link_fail:1; /* bit 3 */
- u32 phy_speed:1; /* bit 4 */
- u32 phy_full_duplex:1; /* bit 5 */
- u32 phy_link_ok:1; /* bit 6 */
- u32 phy_jabber:1; /* bit 7 */
- u32 clash:1; /* bit 8 */
- u32 excess_defer:1; /* bit 9 */
- u32 reserved:22; /* bits 10-31 */
-#endif
- } bits;
-} MAC_IF_STAT_t, *PMAC_IF_STAT_t;
/*
* structure for Mac Station Address, Part 1 reg in mac address map.
@@ -1420,7 +1179,7 @@ typedef struct _MAC_t { /* Location: */
u32 mii_mgmt_stat; /* 0x5030 */
u32 mii_mgmt_indicator; /* 0x5034 */
u32 if_ctrl; /* 0x5038 */
- MAC_IF_STAT_t if_stat; /* 0x503C */
+ u32 if_stat; /* 0x503C */
MAC_STATION_ADDR1_t station_addr_1; /* 0x5040 */
MAC_STATION_ADDR2_t station_addr_2; /* 0x5044 */
} MAC_t, *PMAC_t;
@@ -1490,8 +1249,9 @@ typedef struct _MAC_t { /* Location: */
/*
* MAC STATS Module of JAGCore Address Mapping
*/
-typedef struct _MAC_STAT_t { /* Location: */
- u32 pad[32]; /* 0x6000 - 607C */
+struct macstat_regs
+{ /* Location: */
+ u32 pad[32]; /* 0x6000 - 607C */
/* Tx/Rx 0-64 Byte Frame Counter */
u32 TR64; /* 0x6080 */
@@ -1636,7 +1396,7 @@ typedef struct _MAC_STAT_t { /* Location: */
/* Carry Register Two Mask Register */
u32 Carry2M; /* 0x613C */
-} MAC_STAT_t, *PMAC_STAT_t;
+};
/* END OF MAC STAT REGISTER ADDRESS MAP */
@@ -1674,70 +1434,49 @@ typedef struct _MAC_STAT_t { /* Location: */
/*
* Memory Control Module of JAGCore Address Mapping
*/
-typedef struct _MMC_t { /* Location: */
+struct mmc_regs { /* Location: */
u32 mmc_ctrl; /* 0x7000 */
u32 sram_access; /* 0x7004 */
u32 sram_word1; /* 0x7008 */
u32 sram_word2; /* 0x700C */
u32 sram_word3; /* 0x7010 */
u32 sram_word4; /* 0x7014 */
-} MMC_t, *PMMC_t;
+};
/* END OF MMC REGISTER ADDRESS MAP */
-/* START OF EXP ROM REGISTER ADDRESS MAP */
-
-/*
- * Expansion ROM Module of JAGCore Address Mapping
- */
-
-/* Take this out until it is not empty */
-#if 0
-typedef struct _EXP_ROM_t {
-
-} EXP_ROM_t, *PEXP_ROM_t;
-#endif
-
-/* END OF EXP ROM REGISTER ADDRESS MAP */
-
-
/*
* JAGCore Address Mapping
*/
typedef struct _ADDRESS_MAP_t {
- GLOBAL_t global;
+ struct global_regs global;
/* unused section of global address map */
- u8 unused_global[4096 - sizeof(GLOBAL_t)];
- TXDMA_t txdma;
+ u8 unused_global[4096 - sizeof(struct global_regs)];
+ struct txdma_regs txdma;
/* unused section of txdma address map */
- u8 unused_txdma[4096 - sizeof(TXDMA_t)];
- RXDMA_t rxdma;
+ u8 unused_txdma[4096 - sizeof(struct txdma_regs)];
+ struct rxdma_regs rxdma;
/* unused section of rxdma address map */
- u8 unused_rxdma[4096 - sizeof(RXDMA_t)];
- TXMAC_t txmac;
+ u8 unused_rxdma[4096 - sizeof(struct rxdma_regs)];
+ struct txmac_regs txmac;
/* unused section of txmac address map */
- u8 unused_txmac[4096 - sizeof(TXMAC_t)];
+ u8 unused_txmac[4096 - sizeof(struct txmac_regs)];
RXMAC_t rxmac;
/* unused section of rxmac address map */
u8 unused_rxmac[4096 - sizeof(RXMAC_t)];
MAC_t mac;
/* unused section of mac address map */
u8 unused_mac[4096 - sizeof(MAC_t)];
- MAC_STAT_t macStat;
+ struct macstat_regs macstat;
/* unused section of mac stat address map */
- u8 unused_mac_stat[4096 - sizeof(MAC_STAT_t)];
- MMC_t mmc;
+ u8 unused_mac_stat[4096 - sizeof(struct macstat_regs)];
+ struct mmc_regs mmc;
/* unused section of mmc address map */
- u8 unused_mmc[4096 - sizeof(MMC_t)];
+ u8 unused_mmc[4096 - sizeof(struct mmc_regs)];
/* unused section of address map */
u8 unused_[1015808];
-/* Take this out until it is not empty */
-#if 0
- EXP_ROM_t exp_rom;
-#endif
-
u8 unused_exp_rom[4096]; /* MGS-size TBD */
u8 unused__[524288]; /* unused section of address map */
} ADDRESS_MAP_t, *PADDRESS_MAP_t;
diff --git a/drivers/staging/et131x/et1310_eeprom.c b/drivers/staging/et131x/et1310_eeprom.c
index bcca1f86f516..3ca253672ba1 100644
--- a/drivers/staging/et131x/et1310_eeprom.c
+++ b/drivers/staging/et131x/et1310_eeprom.c
@@ -84,17 +84,42 @@
#include <linux/ioport.h>
#include "et1310_phy.h"
-#include "et1310_pm.h"
-#include "et1310_jagcore.h"
-#include "et1310_eeprom.h"
-
#include "et131x_adapter.h"
-#include "et131x_initpci.h"
-#include "et131x_isr.h"
-
-#include "et1310_tx.h"
+#include "et131x.h"
+/*
+ * EEPROM Defines
+ */
+/* LBCIF Register Groups (addressed via 32-bit offsets) */
+#define LBCIF_DWORD0_GROUP 0xAC
+#define LBCIF_DWORD1_GROUP 0xB0
+
+/* LBCIF Registers (addressed via 8-bit offsets) */
+#define LBCIF_ADDRESS_REGISTER 0xAC
+#define LBCIF_DATA_REGISTER 0xB0
+#define LBCIF_CONTROL_REGISTER 0xB1
+#define LBCIF_STATUS_REGISTER 0xB2
+
+/* LBCIF Control Register Bits */
+#define LBCIF_CONTROL_SEQUENTIAL_READ 0x01
+#define LBCIF_CONTROL_PAGE_WRITE 0x02
+#define LBCIF_CONTROL_EEPROM_RELOAD 0x08
+#define LBCIF_CONTROL_TWO_BYTE_ADDR 0x20
+#define LBCIF_CONTROL_I2C_WRITE 0x40
+#define LBCIF_CONTROL_LBCIF_ENABLE 0x80
+
+/* LBCIF Status Register Bits */
+#define LBCIF_STATUS_PHY_QUEUE_AVAIL 0x01
+#define LBCIF_STATUS_I2C_IDLE 0x02
+#define LBCIF_STATUS_ACK_ERROR 0x04
+#define LBCIF_STATUS_GENERAL_ERROR 0x08
+#define LBCIF_STATUS_CHECKSUM_ERROR 0x40
+#define LBCIF_STATUS_EEPROM_PRESENT 0x80
+
+/* Miscellaneous Constraints */
+#define MAX_NUM_REGISTER_POLLS 1000
+#define MAX_NUM_WRITE_RETRIES 2
static int eeprom_wait_ready(struct pci_dev *pdev, u32 *status)
{
diff --git a/drivers/staging/et131x/et1310_eeprom.h b/drivers/staging/et131x/et1310_eeprom.h
deleted file mode 100644
index 6a6c6a632a8f..000000000000
--- a/drivers/staging/et131x/et1310_eeprom.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Agere Systems Inc.
- * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- * http://www.agere.com
- *
- *------------------------------------------------------------------------------
- *
- * et1310_eeprom.h - Defines, structs, enums, prototypes, etc. used for EEPROM
- * access routines
- *
- *------------------------------------------------------------------------------
- *
- * SOFTWARE LICENSE
- *
- * This software is provided subject to the following terms and conditions,
- * which you should read carefully before using the software. Using this
- * software indicates your acceptance of these terms and conditions. If you do
- * not agree with these terms and conditions, do not use the software.
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- *
- * Redistribution and use in source or binary forms, with or without
- * modifications, 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 as comments in the code as
- * well as in the documentation and/or other materials provided with the
- * distribution.
- *
- * . Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following Disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * . Neither the name of Agere Systems Inc. nor the names of the contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * Disclaimer
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
- * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
- * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. 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, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- */
-
-#ifndef __ET1310_EEPROM_H__
-#define __ET1310_EEPROM_H__
-
-#include "et1310_address_map.h"
-
-/*
- * EEPROM Defines
- */
-
-/* LBCIF Register Groups (addressed via 32-bit offsets) */
-#define LBCIF_DWORD0_GROUP 0xAC
-#define LBCIF_DWORD1_GROUP 0xB0
-
-/* LBCIF Registers (addressed via 8-bit offsets) */
-#define LBCIF_ADDRESS_REGISTER 0xAC
-#define LBCIF_DATA_REGISTER 0xB0
-#define LBCIF_CONTROL_REGISTER 0xB1
-#define LBCIF_STATUS_REGISTER 0xB2
-
-/* LBCIF Control Register Bits */
-#define LBCIF_CONTROL_SEQUENTIAL_READ 0x01
-#define LBCIF_CONTROL_PAGE_WRITE 0x02
-#define LBCIF_CONTROL_EEPROM_RELOAD 0x08
-#define LBCIF_CONTROL_TWO_BYTE_ADDR 0x20
-#define LBCIF_CONTROL_I2C_WRITE 0x40
-#define LBCIF_CONTROL_LBCIF_ENABLE 0x80
-
-/* LBCIF Status Register Bits */
-#define LBCIF_STATUS_PHY_QUEUE_AVAIL 0x01
-#define LBCIF_STATUS_I2C_IDLE 0x02
-#define LBCIF_STATUS_ACK_ERROR 0x04
-#define LBCIF_STATUS_GENERAL_ERROR 0x08
-#define LBCIF_STATUS_CHECKSUM_ERROR 0x40
-#define LBCIF_STATUS_EEPROM_PRESENT 0x80
-
-/* Miscellaneous Constraints */
-#define MAX_NUM_REGISTER_POLLS 1000
-#define MAX_NUM_WRITE_RETRIES 2
-
-/* Forward declaration of the private adapter structure */
-struct et131x_adapter;
-
-int et131x_init_eeprom(struct et131x_adapter *etdev);
-
-#endif /* _ET1310_EEPROM_H_ */
diff --git a/drivers/staging/et131x/et1310_jagcore.h b/drivers/staging/et131x/et1310_jagcore.h
deleted file mode 100644
index 0807a01d88ae..000000000000
--- a/drivers/staging/et131x/et1310_jagcore.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Agere Systems Inc.
- * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- * http://www.agere.com
- *
- *------------------------------------------------------------------------------
- *
- * et1310_jagcore.h - Defines, structs, enums, prototypes, etc. pertaining to
- * the JAGCore
- *
- *------------------------------------------------------------------------------
- *
- * SOFTWARE LICENSE
- *
- * This software is provided subject to the following terms and conditions,
- * which you should read carefully before using the software. Using this
- * software indicates your acceptance of these terms and conditions. If you do
- * not agree with these terms and conditions, do not use the software.
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- *
- * Redistribution and use in source or binary forms, with or without
- * modifications, 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 as comments in the code as
- * well as in the documentation and/or other materials provided with the
- * distribution.
- *
- * . Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following Disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * . Neither the name of Agere Systems Inc. nor the names of the contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * Disclaimer
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
- * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
- * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. 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, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- */
-
-#ifndef __ET1310_JAGCORE_H__
-#define __ET1310_JAGCORE_H__
-
-#include "et1310_address_map.h"
-
-
-#define INTERNAL_MEM_SIZE 0x400 /* 1024 of internal memory */
-#define INTERNAL_MEM_RX_OFFSET 0x1FF /* 50% Tx, 50% Rx */
-
-/*
- * For interrupts, normal running is:
- * rxdma_xfr_done, phy_interrupt, mac_stat_interrupt,
- * watchdog_interrupt & txdma_xfer_done
- *
- * In both cases, when flow control is enabled for either Tx or bi-direction,
- * we additional enable rx_fbr0_low and rx_fbr1_low, so we know when the
- * buffer rings are running low.
- */
-#define INT_MASK_DISABLE 0xffffffff
-
-/* NOTE: Masking out MAC_STAT Interrupt for now...
- * #define INT_MASK_ENABLE 0xfff6bf17
- * #define INT_MASK_ENABLE_NO_FLOW 0xfff6bfd7
- */
-#define INT_MASK_ENABLE 0xfffebf17
-#define INT_MASK_ENABLE_NO_FLOW 0xfffebfd7
-
-/* Forward declaration of the private adapter structure */
-struct et131x_adapter;
-
-void ConfigGlobalRegs(struct et131x_adapter *pAdapter);
-void ConfigMMCRegs(struct et131x_adapter *pAdapter);
-void et131x_enable_interrupts(struct et131x_adapter *adapter);
-void et131x_disable_interrupts(struct et131x_adapter *adapter);
-
-#endif /* __ET1310_JAGCORE_H__ */
diff --git a/drivers/staging/et131x/et1310_mac.c b/drivers/staging/et131x/et1310_mac.c
index b8a1f2037314..a292b1edc414 100644
--- a/drivers/staging/et131x/et1310_mac.c
+++ b/drivers/staging/et131x/et1310_mac.c
@@ -85,12 +85,19 @@
#include <linux/crc32.h>
#include "et1310_phy.h"
-#include "et1310_pm.h"
-#include "et1310_jagcore.h"
-#include "et1310_mac.h"
-
#include "et131x_adapter.h"
-#include "et131x_initpci.h"
+#include "et131x.h"
+
+
+#define COUNTER_WRAP_28_BIT 0x10000000
+#define COUNTER_WRAP_22_BIT 0x400000
+#define COUNTER_WRAP_16_BIT 0x10000
+#define COUNTER_WRAP_12_BIT 0x1000
+
+#define COUNTER_MASK_28_BIT (COUNTER_WRAP_28_BIT - 1)
+#define COUNTER_MASK_22_BIT (COUNTER_WRAP_22_BIT - 1)
+#define COUNTER_MASK_16_BIT (COUNTER_WRAP_16_BIT - 1)
+#define COUNTER_MASK_12_BIT (COUNTER_WRAP_12_BIT - 1)
/**
* ConfigMacRegs1 - Initialize the first part of MAC regs
@@ -163,9 +170,9 @@ void ConfigMACRegs2(struct et131x_adapter *etdev)
u32 cfg1;
u32 cfg2;
u32 ifctrl;
- TXMAC_CTL_t ctl;
+ u32 ctl;
- ctl.value = readl(&etdev->regs->txmac.ctl.value);
+ ctl = readl(&etdev->regs->txmac.ctl);
cfg1 = readl(&pMac->cfg1);
cfg2 = readl(&pMac->cfg2);
ifctrl = readl(&pMac->if_ctrl);
@@ -219,9 +226,8 @@ void ConfigMACRegs2(struct et131x_adapter *etdev)
}
/* Enable TXMAC */
- ctl.bits.txmac_en = 0x1;
- ctl.bits.fc_disable = 0x1;
- writel(ctl.value, &etdev->regs->txmac.ctl.value);
+ ctl |= 0x05; /* TX mac enable, FC disable */
+ writel(ctl, &etdev->regs->txmac.ctl);
/* Ready to start the RXDMA/TXDMA engine */
if (etdev->Flags & fMP_ADAPTER_LOWER_POWER) {
@@ -235,15 +241,15 @@ void ConfigRxMacRegs(struct et131x_adapter *etdev)
struct _RXMAC_t __iomem *pRxMac = &etdev->regs->rxmac;
RXMAC_WOL_SA_LO_t sa_lo;
RXMAC_WOL_SA_HI_t sa_hi;
- RXMAC_PF_CTRL_t pf_ctrl = { 0 };
+ u32 pf_ctrl = 0;
/* Disable the MAC while it is being configured (also disable WOL) */
- writel(0x8, &pRxMac->ctrl.value);
+ writel(0x8, &pRxMac->ctrl);
/* Initialize WOL to disabled. */
- writel(0, &pRxMac->crc0.value);
- writel(0, &pRxMac->crc12.value);
- writel(0, &pRxMac->crc34.value);
+ writel(0, &pRxMac->crc0);
+ writel(0, &pRxMac->crc12);
+ writel(0, &pRxMac->crc34);
/* We need to set the WOL mask0 - mask4 next. We initialize it to
* its default Values of 0x00000000 because there are not WOL masks
@@ -286,12 +292,12 @@ void ConfigRxMacRegs(struct et131x_adapter *etdev)
writel(sa_hi.value, &pRxMac->sa_hi.value);
/* Disable all Packet Filtering */
- writel(0, &pRxMac->pf_ctrl.value);
+ writel(0, &pRxMac->pf_ctrl);
/* Let's initialize the Unicast Packet filtering address */
if (etdev->PacketFilter & ET131X_PACKET_TYPE_DIRECTED) {
SetupDeviceForUnicast(etdev);
- pf_ctrl.bits.filter_uni_en = 1;
+ pf_ctrl |= 4; /* Unicast filter */
} else {
writel(0, &pRxMac->uni_pf_addr1.value);
writel(0, &pRxMac->uni_pf_addr2.value);
@@ -299,20 +305,16 @@ void ConfigRxMacRegs(struct et131x_adapter *etdev)
}
/* Let's initialize the Multicast hash */
- if (etdev->PacketFilter & ET131X_PACKET_TYPE_ALL_MULTICAST) {
- pf_ctrl.bits.filter_multi_en = 0;
- } else {
- pf_ctrl.bits.filter_multi_en = 1;
+ if (!(etdev->PacketFilter & ET131X_PACKET_TYPE_ALL_MULTICAST)) {
+ pf_ctrl |= 2; /* Multicast filter */
SetupDeviceForMulticast(etdev);
}
/* Runt packet filtering. Didn't work in version A silicon. */
- pf_ctrl.bits.min_pkt_size = NIC_MIN_PACKET_SIZE + 4;
- pf_ctrl.bits.filter_frag_en = 1;
-
- if (etdev->RegistryJumboPacket > 8192) {
- RXMAC_MCIF_CTRL_MAX_SEG_t mcif_ctrl_max_seg;
+ pf_ctrl |= (NIC_MIN_PACKET_SIZE + 4) << 16;
+ pf_ctrl |= 8; /* Fragment filter */
+ if (etdev->RegistryJumboPacket > 8192)
/* In order to transmit jumbo packets greater than 8k, the
* FIFO between RxMAC and RxDMA needs to be reduced in size
* to (16k - Jumbo packet size). In order to implement this,
@@ -320,25 +322,21 @@ void ConfigRxMacRegs(struct et131x_adapter *etdev)
* packets down into segments which are (max_size * 16). In
* this case we selected 256 bytes, since this is the size of
* the PCI-Express TLP's that the 1310 uses.
+ *
+ * seg_en on, fc_en off, size 0x10
*/
- mcif_ctrl_max_seg.bits.seg_en = 0x1;
- mcif_ctrl_max_seg.bits.fc_en = 0x0;
- mcif_ctrl_max_seg.bits.max_size = 0x10;
-
- writel(mcif_ctrl_max_seg.value,
- &pRxMac->mcif_ctrl_max_seg.value);
- } else {
- writel(0, &pRxMac->mcif_ctrl_max_seg.value);
- }
+ writel(0x41, &pRxMac->mcif_ctrl_max_seg);
+ else
+ writel(0, &pRxMac->mcif_ctrl_max_seg);
/* Initialize the MCIF water marks */
- writel(0, &pRxMac->mcif_water_mark.value);
+ writel(0, &pRxMac->mcif_water_mark);
/* Initialize the MIF control */
- writel(0, &pRxMac->mif_ctrl.value);
+ writel(0, &pRxMac->mif_ctrl);
/* Initialize the Space Available Register */
- writel(0, &pRxMac->space_avail.value);
+ writel(0, &pRxMac->space_avail);
/* Initialize the the mif_ctrl register
* bit 3: Receive code error. One or more nibbles were signaled as
@@ -354,9 +352,9 @@ void ConfigRxMacRegs(struct et131x_adapter *etdev)
* bit 17: Drop packet enable
*/
if (etdev->linkspeed == TRUEPHY_SPEED_100MBPS)
- writel(0x30038, &pRxMac->mif_ctrl.value);
+ writel(0x30038, &pRxMac->mif_ctrl);
else
- writel(0x30030, &pRxMac->mif_ctrl.value);
+ writel(0x30030, &pRxMac->mif_ctrl);
/* Finally we initialize RxMac to be enabled & WOL disabled. Packet
* filter is always enabled since it is where the runt packets are
@@ -364,28 +362,28 @@ void ConfigRxMacRegs(struct et131x_adapter *etdev)
* dropping doesn't work, so it is disabled in the pf_ctrl register,
* but we still leave the packet filter on.
*/
- writel(pf_ctrl.value, &pRxMac->pf_ctrl.value);
- writel(0x9, &pRxMac->ctrl.value);
+ writel(pf_ctrl, &pRxMac->pf_ctrl);
+ writel(0x9, &pRxMac->ctrl);
}
void ConfigTxMacRegs(struct et131x_adapter *etdev)
{
- struct _TXMAC_t __iomem *pTxMac = &etdev->regs->txmac;
+ struct txmac_regs *txmac = &etdev->regs->txmac;
/* We need to update the Control Frame Parameters
* cfpt - control frame pause timer set to 64 (0x40)
* cfep - control frame extended pause timer set to 0x0
*/
if (etdev->FlowControl == None)
- writel(0, &pTxMac->cf_param);
+ writel(0, &txmac->cf_param);
else
- writel(0x40, &pTxMac->cf_param);
+ writel(0x40, &txmac->cf_param);
}
void ConfigMacStatRegs(struct et131x_adapter *etdev)
{
- struct _MAC_STAT_t __iomem *macstat =
- &etdev->regs->macStat;
+ struct macstat_regs __iomem *macstat =
+ &etdev->regs->macstat;
/* Next we need to initialize all the MAC_STAT registers to zero on
* the device.
@@ -456,8 +454,8 @@ void ConfigFlowControl(struct et131x_adapter *etdev)
void UpdateMacStatHostCounters(struct et131x_adapter *etdev)
{
struct _ce_stats_t *stats = &etdev->Stats;
- struct _MAC_STAT_t __iomem *macstat =
- &etdev->regs->macStat;
+ struct macstat_regs __iomem *macstat =
+ &etdev->regs->macstat;
stats->collisions += readl(&macstat->TNcl);
stats->first_collision += readl(&macstat->TScl);
@@ -493,11 +491,11 @@ void HandleMacStatInterrupt(struct et131x_adapter *etdev)
/* Read the interrupt bits from the register(s). These are Clear On
* Write.
*/
- Carry1 = readl(&etdev->regs->macStat.Carry1);
- Carry2 = readl(&etdev->regs->macStat.Carry2);
+ Carry1 = readl(&etdev->regs->macstat.Carry1);
+ Carry2 = readl(&etdev->regs->macstat.Carry2);
- writel(Carry1, &etdev->regs->macStat.Carry1);
- writel(Carry2, &etdev->regs->macStat.Carry2);
+ writel(Carry1, &etdev->regs->macstat.Carry1);
+ writel(Carry2, &etdev->regs->macstat.Carry2);
/* We need to do update the host copy of all the MAC_STAT counters.
* For each counter, check it's overflow bit. If the overflow bit is
diff --git a/drivers/staging/et131x/et1310_mac.h b/drivers/staging/et131x/et1310_mac.h
deleted file mode 100644
index 2c3859594538..000000000000
--- a/drivers/staging/et131x/et1310_mac.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Agere Systems Inc.
- * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- * http://www.agere.com
- *
- *------------------------------------------------------------------------------
- *
- * et1310_mac.h - Defines, structs, enums, prototypes, etc. pertaining to the
- * MAC.
- *
- *------------------------------------------------------------------------------
- *
- * SOFTWARE LICENSE
- *
- * This software is provided subject to the following terms and conditions,
- * which you should read carefully before using the software. Using this
- * software indicates your acceptance of these terms and conditions. If you do
- * not agree with these terms and conditions, do not use the software.
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- *
- * Redistribution and use in source or binary forms, with or without
- * modifications, 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 as comments in the code as
- * well as in the documentation and/or other materials provided with the
- * distribution.
- *
- * . Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following Disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * . Neither the name of Agere Systems Inc. nor the names of the contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * Disclaimer
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
- * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
- * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. 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, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- */
-
-#ifndef _ET1310_MAC_H_
-#define _ET1310_MAC_H_
-
-
-#include "et1310_address_map.h"
-
-
-#define COUNTER_WRAP_28_BIT 0x10000000
-#define COUNTER_WRAP_22_BIT 0x400000
-#define COUNTER_WRAP_16_BIT 0x10000
-#define COUNTER_WRAP_12_BIT 0x1000
-
-#define COUNTER_MASK_28_BIT (COUNTER_WRAP_28_BIT - 1)
-#define COUNTER_MASK_22_BIT (COUNTER_WRAP_22_BIT - 1)
-#define COUNTER_MASK_16_BIT (COUNTER_WRAP_16_BIT - 1)
-#define COUNTER_MASK_12_BIT (COUNTER_WRAP_12_BIT - 1)
-
-#define UPDATE_COUNTER(HostCnt, DevCnt) \
- HostCnt = HostCnt + DevCnt;
-
-/* Forward declaration of the private adapter structure */
-struct et131x_adapter;
-
-void ConfigMACRegs1(struct et131x_adapter *adapter);
-void ConfigMACRegs2(struct et131x_adapter *adapter);
-void ConfigRxMacRegs(struct et131x_adapter *adapter);
-void ConfigTxMacRegs(struct et131x_adapter *adapter);
-void ConfigMacStatRegs(struct et131x_adapter *adapter);
-void ConfigFlowControl(struct et131x_adapter *adapter);
-void UpdateMacStatHostCounters(struct et131x_adapter *adapter);
-void HandleMacStatInterrupt(struct et131x_adapter *adapter);
-void SetupDeviceForMulticast(struct et131x_adapter *adapter);
-void SetupDeviceForUnicast(struct et131x_adapter *adapter);
-
-#endif /* _ET1310_MAC_H_ */
diff --git a/drivers/staging/et131x/et1310_phy.c b/drivers/staging/et131x/et1310_phy.c
index 6ecad619f779..4a55fbfbd59d 100644
--- a/drivers/staging/et131x/et1310_phy.c
+++ b/drivers/staging/et131x/et1310_phy.c
@@ -85,17 +85,14 @@
#include <linux/random.h>
#include "et1310_phy.h"
-#include "et1310_pm.h"
-#include "et1310_jagcore.h"
#include "et131x_adapter.h"
-#include "et131x_netdev.h"
-#include "et131x_initpci.h"
#include "et1310_address_map.h"
#include "et1310_tx.h"
#include "et1310_rx.h"
-#include "et1310_mac.h"
+
+#include "et131x.h"
/* Prototypes for functions with local scope */
static void et131x_xcvr_init(struct et131x_adapter *etdev);
diff --git a/drivers/staging/et131x/et1310_phy.h b/drivers/staging/et131x/et1310_phy.h
index 758b9b251715..47907ba76012 100644
--- a/drivers/staging/et131x/et1310_phy.h
+++ b/drivers/staging/et131x/et1310_phy.h
@@ -736,32 +736,8 @@ typedef union _MI_LCR2_t {
/* MI Register 29 - 31: Reserved Reg(0x1D - 0x1E) */
-/* Forward declaration of the private adapter structure */
-struct et131x_adapter;
/* Prototypes for ET1310_phy.c */
-int et131x_xcvr_find(struct et131x_adapter *adapter);
-void et131x_setphy_normal(struct et131x_adapter *adapter);
-
-/* static inline function does not work because et131x_adapter is not always
- * defined
- */
-int PhyMiRead(struct et131x_adapter *adapter, u8 xcvrAddr,
- u8 xcvrReg, u16 *value);
-#define MiRead(adapter, xcvrReg, value) \
- PhyMiRead((adapter), (adapter)->Stats.xcvr_addr, (xcvrReg), (value))
-
-int32_t MiWrite(struct et131x_adapter *adapter,
- u8 xcvReg, u16 value);
-void et131x_Mii_check(struct et131x_adapter *pAdapter,
- MI_BMSR_t bmsr, MI_BMSR_t bmsr_ints);
-
-/* This last is not strictly required (the driver could call the TPAL
- * version instead), but this sets the adapter up correctly, and calls the
- * access routine indirectly. This protects the driver from changes in TPAL.
- */
-void SetPhy_10BaseTHalfDuplex(struct et131x_adapter *adapter);
-
/* Defines for PHY access routines */
/* Define bit operation flags */
@@ -843,14 +819,4 @@ void SetPhy_10BaseTHalfDuplex(struct et131x_adapter *adapter);
/* #define TRU_VMI_LINK_CONTROL_REGISTER 29 */
/* #define TRU_VMI_TIMING_CONTROL_REGISTER */
-/* Prototypes for PHY access routines */
-void ET1310_PhyInit(struct et131x_adapter *adapter);
-void ET1310_PhyReset(struct et131x_adapter *adapter);
-void ET1310_PhyPowerDown(struct et131x_adapter *adapter, bool down);
-void ET1310_PhyAdvertise1000BaseT(struct et131x_adapter *adapter,
- u16 duplex);
-void ET1310_PhyAccessMiBit(struct et131x_adapter *adapter,
- u16 action,
- u16 regnum, u16 bitnum, u8 *value);
-
#endif /* _ET1310_PHY_H_ */
diff --git a/drivers/staging/et131x/et1310_pm.c b/drivers/staging/et131x/et1310_pm.c
index 7d0772359291..41019e390af5 100644
--- a/drivers/staging/et131x/et1310_pm.c
+++ b/drivers/staging/et131x/et1310_pm.c
@@ -83,13 +83,9 @@
#include <linux/ioport.h>
#include "et1310_phy.h"
-#include "et1310_pm.h"
-#include "et1310_jagcore.h"
-#include "et1310_mac.h"
#include "et1310_rx.h"
-
#include "et131x_adapter.h"
-#include "et131x_initpci.h"
+#include "et131x.h"
/**
* EnablePhyComa - called when network cable is unplugged
diff --git a/drivers/staging/et131x/et1310_pm.h b/drivers/staging/et131x/et1310_pm.h
deleted file mode 100644
index 295f3ab132fb..000000000000
--- a/drivers/staging/et131x/et1310_pm.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Agere Systems Inc.
- * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- * http://www.agere.com
- *
- *------------------------------------------------------------------------------
- *
- * et1310_pm.h - Defines, structs, enums, prototypes, etc. pertaining to power
- * management.
- *
- *------------------------------------------------------------------------------
- *
- * SOFTWARE LICENSE
- *
- * This software is provided subject to the following terms and conditions,
- * which you should read carefully before using the software. Using this
- * software indicates your acceptance of these terms and conditions. If you do
- * not agree with these terms and conditions, do not use the software.
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- *
- * Redistribution and use in source or binary forms, with or without
- * modifications, 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 as comments in the code as
- * well as in the documentation and/or other materials provided with the
- * distribution.
- *
- * . Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following Disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * . Neither the name of Agere Systems Inc. nor the names of the contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * Disclaimer
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
- * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
- * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. 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, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- */
-
-#ifndef _ET1310_PM_H_
-#define _ET1310_PM_H_
-
-#include "et1310_address_map.h"
-
-typedef struct _MP_POWER_MGMT {
- /* variable putting the phy into coma mode when boot up with no cable
- * plugged in after 5 seconds
- */
- u8 TransPhyComaModeOnBoot;
-
- /* Next two used to save power information at power down. This
- * information will be used during power up to set up parts of Power
- * Management in JAGCore
- */
- u16 PowerDownSpeed;
- u8 PowerDownDuplex;
-} MP_POWER_MGMT, *PMP_POWER_MGMT;
-
-/* Forward declaration of the private adapter structure
- */
-struct et131x_adapter;
-
-void EnablePhyComa(struct et131x_adapter *adapter);
-void DisablePhyComa(struct et131x_adapter *adapter);
-
-#endif /* _ET1310_PM_H_ */
diff --git a/drivers/staging/et131x/et1310_rx.c b/drivers/staging/et131x/et1310_rx.c
index 3ddc9b12b8db..54686e2ace69 100644
--- a/drivers/staging/et131x/et1310_rx.c
+++ b/drivers/staging/et131x/et1310_rx.c
@@ -84,14 +84,9 @@
#include <linux/ioport.h>
#include "et1310_phy.h"
-#include "et1310_pm.h"
-#include "et1310_jagcore.h"
-
#include "et131x_adapter.h"
-#include "et131x_initpci.h"
-
#include "et1310_rx.h"
-
+#include "et131x.h"
void nic_return_rfd(struct et131x_adapter *etdev, PMP_RFD pMpRfd);
@@ -109,17 +104,16 @@ int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter)
u32 i, j;
u32 bufsize;
u32 pktStatRingSize, FBRChunkSize;
- RX_RING_t *rx_ring;
+ struct rx_ring *rx_ring;
/* Setup some convenience pointers */
- rx_ring = (RX_RING_t *) &adapter->RxRing;
+ rx_ring = &adapter->rx_ring;
/* Alloc memory for the lookup table */
#ifdef USE_FBR0
- rx_ring->Fbr[0] = kmalloc(sizeof(FBRLOOKUPTABLE), GFP_KERNEL);
+ rx_ring->fbr[0] = kmalloc(sizeof(struct fbr_lookup), GFP_KERNEL);
#endif
-
- rx_ring->Fbr[1] = kmalloc(sizeof(FBRLOOKUPTABLE), GFP_KERNEL);
+ rx_ring->fbr[1] = kmalloc(sizeof(struct fbr_lookup), GFP_KERNEL);
/* The first thing we will do is configure the sizes of the buffer
* rings. These will change based on jumbo packet support. Larger
@@ -163,14 +157,14 @@ int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter)
}
#ifdef USE_FBR0
- adapter->RxRing.PsrNumEntries = adapter->RxRing.Fbr0NumEntries +
- adapter->RxRing.Fbr1NumEntries;
+ adapter->rx_ring.PsrNumEntries = adapter->rx_ring.Fbr0NumEntries +
+ adapter->rx_ring.Fbr1NumEntries;
#else
- adapter->RxRing.PsrNumEntries = adapter->RxRing.Fbr1NumEntries;
+ adapter->rx_ring.PsrNumEntries = adapter->rx_ring.Fbr1NumEntries;
#endif
/* Allocate an area of memory for Free Buffer Ring 1 */
- bufsize = (sizeof(FBR_DESC_t) * rx_ring->Fbr1NumEntries) + 0xfff;
+ bufsize = (sizeof(struct fbr_desc) * rx_ring->Fbr1NumEntries) + 0xfff;
rx_ring->pFbr1RingVa = pci_alloc_consistent(adapter->pdev,
bufsize,
&rx_ring->pFbr1RingPa);
@@ -194,12 +188,12 @@ int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter)
&rx_ring->Fbr1Realpa,
&rx_ring->Fbr1offset, 0x0FFF);
- rx_ring->pFbr1RingVa = (void *)((uint8_t *) rx_ring->pFbr1RingVa +
+ rx_ring->pFbr1RingVa = (void *)((u8 *) rx_ring->pFbr1RingVa +
rx_ring->Fbr1offset);
#ifdef USE_FBR0
/* Allocate an area of memory for Free Buffer Ring 0 */
- bufsize = (sizeof(FBR_DESC_t) * rx_ring->Fbr0NumEntries) + 0xfff;
+ bufsize = (sizeof(struct fbr_desc) * rx_ring->Fbr0NumEntries) + 0xfff;
rx_ring->pFbr0RingVa = pci_alloc_consistent(adapter->pdev,
bufsize,
&rx_ring->pFbr0RingPa);
@@ -223,7 +217,7 @@ int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter)
&rx_ring->Fbr0Realpa,
&rx_ring->Fbr0offset, 0x0FFF);
- rx_ring->pFbr0RingVa = (void *)((uint8_t *) rx_ring->pFbr0RingVa +
+ rx_ring->pFbr0RingVa = (void *)((u8 *) rx_ring->pFbr0RingVa +
rx_ring->Fbr0offset);
#endif
@@ -270,23 +264,23 @@ int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter)
/* Save the Virtual address of this index for quick
* access later
*/
- rx_ring->Fbr[1]->Va[index] =
- (uint8_t *) rx_ring->Fbr1MemVa[i] +
+ rx_ring->fbr[1]->virt[index] =
+ (u8 *) rx_ring->Fbr1MemVa[i] +
(j * rx_ring->Fbr1BufferSize) + Fbr1Offset;
/* now store the physical address in the descriptor
* so the device can access it
*/
- rx_ring->Fbr[1]->PAHigh[index] =
+ rx_ring->fbr[1]->bus_high[index] =
(u32) (Fbr1TempPa >> 32);
- rx_ring->Fbr[1]->PALow[index] = (u32) Fbr1TempPa;
+ rx_ring->fbr[1]->bus_low[index] = (u32) Fbr1TempPa;
Fbr1TempPa += rx_ring->Fbr1BufferSize;
- rx_ring->Fbr[1]->Buffer1[index] =
- rx_ring->Fbr[1]->Va[index];
- rx_ring->Fbr[1]->Buffer2[index] =
- rx_ring->Fbr[1]->Va[index] - 4;
+ rx_ring->fbr[1]->buffer1[index] =
+ rx_ring->fbr[1]->virt[index];
+ rx_ring->fbr[1]->buffer2[index] =
+ rx_ring->fbr[1]->virt[index] - 4;
}
}
@@ -319,27 +313,27 @@ int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter)
for (j = 0; j < FBR_CHUNKS; j++) {
u32 index = (i * FBR_CHUNKS) + j;
- rx_ring->Fbr[0]->Va[index] =
- (uint8_t *) rx_ring->Fbr0MemVa[i] +
+ rx_ring->fbr[0]->virt[index] =
+ (u8 *) rx_ring->Fbr0MemVa[i] +
(j * rx_ring->Fbr0BufferSize) + Fbr0Offset;
- rx_ring->Fbr[0]->PAHigh[index] =
+ rx_ring->fbr[0]->bus_high[index] =
(u32) (Fbr0TempPa >> 32);
- rx_ring->Fbr[0]->PALow[index] = (u32) Fbr0TempPa;
+ rx_ring->fbr[0]->bus_low[index] = (u32) Fbr0TempPa;
Fbr0TempPa += rx_ring->Fbr0BufferSize;
- rx_ring->Fbr[0]->Buffer1[index] =
- rx_ring->Fbr[0]->Va[index];
- rx_ring->Fbr[0]->Buffer2[index] =
- rx_ring->Fbr[0]->Va[index] - 4;
+ rx_ring->fbr[0]->buffer1[index] =
+ rx_ring->fbr[0]->virt[index];
+ rx_ring->fbr[0]->buffer2[index] =
+ rx_ring->fbr[0]->virt[index] - 4;
}
}
#endif
/* Allocate an area of memory for FIFO of Packet Status ring entries */
pktStatRingSize =
- sizeof(PKT_STAT_DESC_t) * adapter->RxRing.PsrNumEntries;
+ sizeof(struct pkt_stat_desc) * adapter->rx_ring.PsrNumEntries;
rx_ring->pPSRingVa = pci_alloc_consistent(adapter->pdev,
pktStatRingSize,
@@ -360,16 +354,16 @@ int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter)
*/
/* Allocate an area of memory for writeback of status information */
- rx_ring->pRxStatusVa = pci_alloc_consistent(adapter->pdev,
- sizeof(RX_STATUS_BLOCK_t),
- &rx_ring->pRxStatusPa);
- if (!rx_ring->pRxStatusVa) {
+ rx_ring->rx_status_block = pci_alloc_consistent(adapter->pdev,
+ sizeof(struct rx_status_block),
+ &rx_ring->rx_status_bus);
+ if (!rx_ring->rx_status_block) {
dev_err(&adapter->pdev->dev,
"Cannot alloc memory for Status Block\n");
return -ENOMEM;
}
rx_ring->NumRfd = NIC_DEFAULT_NUM_RFD;
- printk("PRS %lx\n", (unsigned long)rx_ring->pRxStatusPa);
+ printk("PRS %lx\n", (unsigned long)rx_ring->rx_status_bus);
/* Recv
* pci_pool_create initializes a lookaside list. After successful
@@ -403,10 +397,10 @@ void et131x_rx_dma_memory_free(struct et131x_adapter *adapter)
u32 bufsize;
u32 pktStatRingSize;
PMP_RFD rfd;
- RX_RING_t *rx_ring;
+ struct rx_ring *rx_ring;
/* Setup some convenience pointers */
- rx_ring = (RX_RING_t *) &adapter->RxRing;
+ rx_ring = &adapter->rx_ring;
/* Free RFDs and associated packet descriptors */
WARN_ON(rx_ring->nReadyRecv != rx_ring->NumRfd);
@@ -417,7 +411,7 @@ void et131x_rx_dma_memory_free(struct et131x_adapter *adapter)
list_del(&rfd->list_node);
rfd->Packet = NULL;
- kmem_cache_free(adapter->RxRing.RecvLookaside, rfd);
+ kmem_cache_free(adapter->rx_ring.RecvLookaside, rfd);
}
/* Free Free Buffer Ring 1 */
@@ -447,15 +441,14 @@ void et131x_rx_dma_memory_free(struct et131x_adapter *adapter)
}
/* Now the FIFO itself */
- rx_ring->pFbr1RingVa = (void *)((uint8_t *)
+ rx_ring->pFbr1RingVa = (void *)((u8 *)
rx_ring->pFbr1RingVa - rx_ring->Fbr1offset);
- bufsize =
- (sizeof(FBR_DESC_t) * rx_ring->Fbr1NumEntries) + 0xfff;
+ bufsize = (sizeof(struct fbr_desc) * rx_ring->Fbr1NumEntries)
+ + 0xfff;
- pci_free_consistent(adapter->pdev,
- bufsize,
- rx_ring->pFbr1RingVa, rx_ring->pFbr1RingPa);
+ pci_free_consistent(adapter->pdev, bufsize,
+ rx_ring->pFbr1RingVa, rx_ring->pFbr1RingPa);
rx_ring->pFbr1RingVa = NULL;
}
@@ -481,11 +474,11 @@ void et131x_rx_dma_memory_free(struct et131x_adapter *adapter)
}
/* Now the FIFO itself */
- rx_ring->pFbr0RingVa = (void *)((uint8_t *)
+ rx_ring->pFbr0RingVa = (void *)((u8 *)
rx_ring->pFbr0RingVa - rx_ring->Fbr0offset);
- bufsize =
- (sizeof(FBR_DESC_t) * rx_ring->Fbr0NumEntries) + 0xfff;
+ bufsize = (sizeof(struct fbr_desc) * rx_ring->Fbr0NumEntries)
+ + 0xfff;
pci_free_consistent(adapter->pdev,
bufsize,
@@ -498,7 +491,7 @@ void et131x_rx_dma_memory_free(struct et131x_adapter *adapter)
/* Free Packet Status Ring */
if (rx_ring->pPSRingVa) {
pktStatRingSize =
- sizeof(PKT_STAT_DESC_t) * adapter->RxRing.PsrNumEntries;
+ sizeof(struct pkt_stat_desc) * adapter->rx_ring.PsrNumEntries;
pci_free_consistent(adapter->pdev, pktStatRingSize,
rx_ring->pPSRingVa, rx_ring->pPSRingPa);
@@ -507,12 +500,11 @@ void et131x_rx_dma_memory_free(struct et131x_adapter *adapter)
}
/* Free area of memory for the writeback of status information */
- if (rx_ring->pRxStatusVa) {
+ if (rx_ring->rx_status_block) {
pci_free_consistent(adapter->pdev,
- sizeof(RX_STATUS_BLOCK_t),
- rx_ring->pRxStatusVa, rx_ring->pRxStatusPa);
-
- rx_ring->pRxStatusVa = NULL;
+ sizeof(struct rx_status_block),
+ rx_ring->rx_status_block, rx_ring->rx_status_bus);
+ rx_ring->rx_status_block = NULL;
}
/* Free receive buffer pool */
@@ -527,10 +519,10 @@ void et131x_rx_dma_memory_free(struct et131x_adapter *adapter)
/* Free the FBR Lookup Table */
#ifdef USE_FBR0
- kfree(rx_ring->Fbr[0]);
+ kfree(rx_ring->fbr[0]);
#endif
- kfree(rx_ring->Fbr[1]);
+ kfree(rx_ring->fbr[1]);
/* Reset Counters */
rx_ring->nReadyRecv = 0;
@@ -548,10 +540,10 @@ int et131x_init_recv(struct et131x_adapter *adapter)
PMP_RFD rfd = NULL;
u32 rfdct;
u32 numrfd = 0;
- RX_RING_t *rx_ring = NULL;
+ struct rx_ring *rx_ring;
/* Setup some convenience pointers */
- rx_ring = (RX_RING_t *) &adapter->RxRing;
+ rx_ring = &adapter->rx_ring;
/* Setup each RFD */
for (rfdct = 0; rfdct < rx_ring->NumRfd; rfdct++) {
@@ -594,9 +586,9 @@ int et131x_init_recv(struct et131x_adapter *adapter)
*/
void ConfigRxDmaRegs(struct et131x_adapter *etdev)
{
- struct _RXDMA_t __iomem *rx_dma = &etdev->regs->rxdma;
- struct _rx_ring_t *rx_local = &etdev->RxRing;
- PFBR_DESC_t fbr_entry;
+ struct rxdma_regs __iomem *rx_dma = &etdev->regs->rxdma;
+ struct rx_ring *rx_local = &etdev->rx_ring;
+ struct fbr_desc *fbr_entry;
u32 entry;
u32 psr_num_des;
unsigned long flags;
@@ -611,11 +603,11 @@ void ConfigRxDmaRegs(struct et131x_adapter *etdev)
* are ever returned, make sure the high part is retrieved here
* before storing the adjusted address.
*/
- writel((u32) ((u64)rx_local->pRxStatusPa >> 32),
+ writel((u32) ((u64)rx_local->rx_status_bus >> 32),
&rx_dma->dma_wb_base_hi);
- writel((u32) rx_local->pRxStatusPa, &rx_dma->dma_wb_base_lo);
+ writel((u32) rx_local->rx_status_bus, &rx_dma->dma_wb_base_lo);
- memset(rx_local->pRxStatusVa, 0, sizeof(RX_STATUS_BLOCK_t));
+ memset(rx_local->rx_status_block, 0, sizeof(struct rx_status_block));
/* Set the address and parameters of the packet status ring into the
* 1310's registers
@@ -636,11 +628,11 @@ void ConfigRxDmaRegs(struct et131x_adapter *etdev)
rx_local->local_psr_full = 0;
/* Now's the best time to initialize FBR1 contents */
- fbr_entry = (PFBR_DESC_t) rx_local->pFbr1RingVa;
+ fbr_entry = (struct fbr_desc *) rx_local->pFbr1RingVa;
for (entry = 0; entry < rx_local->Fbr1NumEntries; entry++) {
- fbr_entry->addr_hi = rx_local->Fbr[1]->PAHigh[entry];
- fbr_entry->addr_lo = rx_local->Fbr[1]->PALow[entry];
- fbr_entry->word2.bits.bi = entry;
+ fbr_entry->addr_hi = rx_local->fbr[1]->bus_high[entry];
+ fbr_entry->addr_lo = rx_local->fbr[1]->bus_low[entry];
+ fbr_entry->word2 = entry;
fbr_entry++;
}
@@ -661,11 +653,11 @@ void ConfigRxDmaRegs(struct et131x_adapter *etdev)
#ifdef USE_FBR0
/* Now's the best time to initialize FBR0 contents */
- fbr_entry = (PFBR_DESC_t) rx_local->pFbr0RingVa;
+ fbr_entry = (struct fbr_desc *) rx_local->pFbr0RingVa;
for (entry = 0; entry < rx_local->Fbr0NumEntries; entry++) {
- fbr_entry->addr_hi = rx_local->Fbr[0]->PAHigh[entry];
- fbr_entry->addr_lo = rx_local->Fbr[0]->PALow[entry];
- fbr_entry->word2.bits.bi = entry;
+ fbr_entry->addr_hi = rx_local->fbr[0]->bus_high[entry];
+ fbr_entry->addr_lo = rx_local->fbr[0]->bus_low[entry];
+ fbr_entry->word2 = entry;
fbr_entry++;
}
@@ -721,18 +713,17 @@ void SetRxDmaTimer(struct et131x_adapter *etdev)
*/
void et131x_rx_dma_disable(struct et131x_adapter *etdev)
{
- RXDMA_CSR_t csr;
-
+ u32 csr;
/* Setup the receive dma configuration register */
- writel(0x00002001, &etdev->regs->rxdma.csr.value);
- csr.value = readl(&etdev->regs->rxdma.csr.value);
- if (csr.bits.halt_status != 1) {
+ writel(0x00002001, &etdev->regs->rxdma.csr);
+ csr = readl(&etdev->regs->rxdma.csr);
+ if ((csr & 0x00020000) != 1) { /* Check halt status (bit 17) */
udelay(5);
- csr.value = readl(&etdev->regs->rxdma.csr.value);
- if (csr.bits.halt_status != 1)
+ csr = readl(&etdev->regs->rxdma.csr);
+ if ((csr & 0x00020000) != 1)
dev_err(&etdev->pdev->dev,
- "RX Dma failed to enter halt state. CSR 0x%08x\n",
- csr.value);
+ "RX Dma failed to enter halt state. CSR 0x%08x\n",
+ csr);
}
}
@@ -743,34 +734,33 @@ void et131x_rx_dma_disable(struct et131x_adapter *etdev)
void et131x_rx_dma_enable(struct et131x_adapter *etdev)
{
/* Setup the receive dma configuration register for normal operation */
- RXDMA_CSR_t csr = { 0 };
-
- csr.bits.fbr1_enable = 1;
- if (etdev->RxRing.Fbr1BufferSize == 4096)
- csr.bits.fbr1_size = 1;
- else if (etdev->RxRing.Fbr1BufferSize == 8192)
- csr.bits.fbr1_size = 2;
- else if (etdev->RxRing.Fbr1BufferSize == 16384)
- csr.bits.fbr1_size = 3;
+ u32 csr = 0x2000; /* FBR1 enable */
+
+ if (etdev->rx_ring.Fbr1BufferSize == 4096)
+ csr |= 0x0800;
+ else if (etdev->rx_ring.Fbr1BufferSize == 8192)
+ csr |= 0x1000;
+ else if (etdev->rx_ring.Fbr1BufferSize == 16384)
+ csr |= 0x1800;
#ifdef USE_FBR0
- csr.bits.fbr0_enable = 1;
- if (etdev->RxRing.Fbr0BufferSize == 256)
- csr.bits.fbr0_size = 1;
- else if (etdev->RxRing.Fbr0BufferSize == 512)
- csr.bits.fbr0_size = 2;
- else if (etdev->RxRing.Fbr0BufferSize == 1024)
- csr.bits.fbr0_size = 3;
+ csr |= 0x0400; /* FBR0 enable */
+ if (etdev->rx_ring.Fbr0BufferSize == 256)
+ csr |= 0x0100;
+ else if (etdev->rx_ring.Fbr0BufferSize == 512)
+ csr |= 0x0200;
+ else if (etdev->rx_ring.Fbr0BufferSize == 1024)
+ csr |= 0x0300;
#endif
- writel(csr.value, &etdev->regs->rxdma.csr.value);
+ writel(csr, &etdev->regs->rxdma.csr);
- csr.value = readl(&etdev->regs->rxdma.csr.value);
- if (csr.bits.halt_status != 0) {
+ csr = readl(&etdev->regs->rxdma.csr);
+ if ((csr & 0x00020000) != 0) {
udelay(5);
- csr.value = readl(&etdev->regs->rxdma.csr.value);
- if (csr.bits.halt_status != 0) {
+ csr = readl(&etdev->regs->rxdma.csr);
+ if ((csr & 0x00020000) != 0) {
dev_err(&etdev->pdev->dev,
"RX Dma failed to exit halt state. CSR 0x%08x\n",
- csr.value);
+ csr);
}
}
}
@@ -788,53 +778,51 @@ void et131x_rx_dma_enable(struct et131x_adapter *etdev)
*/
PMP_RFD nic_rx_pkts(struct et131x_adapter *etdev)
{
- struct _rx_ring_t *rx_local = &etdev->RxRing;
- PRX_STATUS_BLOCK_t status;
- PPKT_STAT_DESC_t psr;
+ struct rx_ring *rx_local = &etdev->rx_ring;
+ struct rx_status_block *status;
+ struct pkt_stat_desc *psr;
PMP_RFD rfd;
u32 i;
- uint8_t *buf;
+ u8 *buf;
unsigned long flags;
struct list_head *element;
- uint8_t rindex;
- uint16_t bindex;
+ u8 rindex;
+ u16 bindex;
u32 len;
- PKT_STAT_DESC_WORD0_t Word0;
+ u32 word0;
+ u32 word1;
/* RX Status block is written by the DMA engine prior to every
* interrupt. It contains the next to be used entry in the Packet
* Status Ring, and also the two Free Buffer rings.
*/
- status = (PRX_STATUS_BLOCK_t) rx_local->pRxStatusVa;
+ status = rx_local->rx_status_block;
+ word1 = status->Word1 >> 16; /* Get the useful bits */
- /* FIXME: tidy later when conversions complete */
- if (status->Word1.bits.PSRoffset ==
- (rx_local->local_psr_full & 0xFFF) &&
- status->Word1.bits.PSRwrap ==
- ((rx_local->local_psr_full >> 12) & 1)) {
+ /* Check the PSR and wrap bits do not match */
+ if ((word1 & 0x1FFF) == (rx_local->local_psr_full & 0x1FFF))
/* Looks like this ring is not updated yet */
return NULL;
- }
/* The packet status ring indicates that data is available. */
- psr = (PPKT_STAT_DESC_t) (rx_local->pPSRingVa) +
+ psr = (struct pkt_stat_desc *) (rx_local->pPSRingVa) +
(rx_local->local_psr_full & 0xFFF);
/* Grab any information that is required once the PSR is
* advanced, since we can no longer rely on the memory being
* accurate
*/
- len = psr->word1.bits.length;
- rindex = (uint8_t) psr->word1.bits.ri;
- bindex = (uint16_t) psr->word1.bits.bi;
- Word0 = psr->word0;
+ len = psr->word1 & 0xFFFF;
+ rindex = (psr->word1 >> 26) & 0x03;
+ bindex = (psr->word1 >> 16) & 0x3FF;
+ word0 = psr->word0;
/* Indicate that we have used this PSR entry. */
/* FIXME wrap 12 */
- rx_local->local_psr_full = (rx_local->local_psr_full + 1) & 0xFFF;
- if (rx_local->local_psr_full > rx_local->PsrNumEntries - 1) {
+ add_12bit(&rx_local->local_psr_full, 1);
+ if ((rx_local->local_psr_full & 0xFFF) > rx_local->PsrNumEntries - 1) {
/* Clear psr full and toggle the wrap bit */
- rx_local->local_psr_full &= 0xFFF;
+ rx_local->local_psr_full &= ~0xFFF;
rx_local->local_psr_full ^= 0x1000;
}
@@ -842,9 +830,8 @@ PMP_RFD nic_rx_pkts(struct et131x_adapter *etdev)
&etdev->regs->rxdma.psr_full_offset);
#ifndef USE_FBR0
- if (rindex != 1) {
+ if (rindex != 1)
return NULL;
- }
#endif
#ifdef USE_FBR0
@@ -899,7 +886,7 @@ PMP_RFD nic_rx_pkts(struct et131x_adapter *etdev)
if (len) {
if (etdev->ReplicaPhyLoopbk == 1) {
- buf = rx_local->Fbr[rindex]->Va[bindex];
+ buf = rx_local->fbr[rindex]->virt[bindex];
if (memcmp(&buf[6], &etdev->CurrentAddress[0],
ETH_ALEN) == 0) {
@@ -911,8 +898,8 @@ PMP_RFD nic_rx_pkts(struct et131x_adapter *etdev)
}
/* Determine if this is a multicast packet coming in */
- if ((Word0.value & ALCATEL_MULTICAST_PKT) &&
- !(Word0.value & ALCATEL_BROADCAST_PKT)) {
+ if ((word0 & ALCATEL_MULTICAST_PKT) &&
+ !(word0 & ALCATEL_BROADCAST_PKT)) {
/* Promiscuous mode and Multicast mode are
* not mutually exclusive as was first
* thought. I guess Promiscuous is just
@@ -923,8 +910,8 @@ PMP_RFD nic_rx_pkts(struct et131x_adapter *etdev)
if ((etdev->PacketFilter & ET131X_PACKET_TYPE_MULTICAST)
&& !(etdev->PacketFilter & ET131X_PACKET_TYPE_PROMISCUOUS)
&& !(etdev->PacketFilter & ET131X_PACKET_TYPE_ALL_MULTICAST)) {
- buf = rx_local->Fbr[rindex]->
- Va[bindex];
+ buf = rx_local->fbr[rindex]->
+ virt[bindex];
/* Loop through our list to see if the
* destination address of this packet
@@ -963,7 +950,7 @@ PMP_RFD nic_rx_pkts(struct et131x_adapter *etdev)
if (len > 0)
etdev->Stats.multircv++;
- } else if (Word0.value & ALCATEL_BROADCAST_PKT)
+ } else if (word0 & ALCATEL_BROADCAST_PKT)
etdev->Stats.brdcstrcv++;
else
/* Not sure what this counter measures in
@@ -990,7 +977,7 @@ PMP_RFD nic_rx_pkts(struct et131x_adapter *etdev)
etdev->net_stats.rx_bytes += rfd->PacketSize;
memcpy(skb_put(skb, rfd->PacketSize),
- rx_local->Fbr[rindex]->Va[bindex],
+ rx_local->fbr[rindex]->virt[bindex],
rfd->PacketSize);
skb->dev = etdev->netdev;
@@ -1014,7 +1001,7 @@ PMP_RFD nic_rx_pkts(struct et131x_adapter *etdev)
*/
void et131x_reset_recv(struct et131x_adapter *etdev)
{
- WARN_ON(list_empty(&etdev->RxRing.RecvList));
+ WARN_ON(list_empty(&etdev->rx_ring.RecvList));
}
@@ -1032,8 +1019,8 @@ void et131x_handle_recv_interrupt(struct et131x_adapter *etdev)
/* Process up to available RFD's */
while (count < NUM_PACKETS_HANDLED) {
- if (list_empty(&etdev->RxRing.RecvList)) {
- WARN_ON(etdev->RxRing.nReadyRecv != 0);
+ if (list_empty(&etdev->rx_ring.RecvList)) {
+ WARN_ON(etdev->rx_ring.nReadyRecv != 0);
done = false;
break;
}
@@ -1058,7 +1045,7 @@ void et131x_handle_recv_interrupt(struct et131x_adapter *etdev)
etdev->Stats.ipackets++;
/* Set the status on the packet, either resources or success */
- if (etdev->RxRing.nReadyRecv < RFD_LOW_WATER_MARK) {
+ if (etdev->rx_ring.nReadyRecv < RFD_LOW_WATER_MARK) {
dev_warn(&etdev->pdev->dev,
"RFD's are running out\n");
}
@@ -1066,12 +1053,12 @@ void et131x_handle_recv_interrupt(struct et131x_adapter *etdev)
}
if (count == NUM_PACKETS_HANDLED || !done) {
- etdev->RxRing.UnfinishedReceives = true;
+ etdev->rx_ring.UnfinishedReceives = true;
writel(PARM_TX_TIME_INT_DEF * NANO_IN_A_MICRO,
&etdev->regs->global.watchdog_timer);
} else
/* Watchdog timer will disable itself if appropriate. */
- etdev->RxRing.UnfinishedReceives = false;
+ etdev->rx_ring.UnfinishedReceives = false;
}
static inline u32 bump_fbr(u32 *fbr, u32 limit)
@@ -1099,10 +1086,10 @@ static inline u32 bump_fbr(u32 *fbr, u32 limit)
*/
void nic_return_rfd(struct et131x_adapter *etdev, PMP_RFD rfd)
{
- struct _rx_ring_t *rx_local = &etdev->RxRing;
- struct _RXDMA_t __iomem *rx_dma = &etdev->regs->rxdma;
- uint16_t bi = rfd->bufferindex;
- uint8_t ri = rfd->ringindex;
+ struct rx_ring *rx_local = &etdev->rx_ring;
+ struct rxdma_regs __iomem *rx_dma = &etdev->regs->rxdma;
+ u16 bi = rfd->bufferindex;
+ u8 ri = rfd->ringindex;
unsigned long flags;
/* We don't use any of the OOB data besides status. Otherwise, we
@@ -1116,17 +1103,17 @@ void nic_return_rfd(struct et131x_adapter *etdev, PMP_RFD rfd)
spin_lock_irqsave(&etdev->FbrLock, flags);
if (ri == 1) {
- PFBR_DESC_t next =
- (PFBR_DESC_t) (rx_local->pFbr1RingVa) +
- INDEX10(rx_local->local_Fbr1_full);
+ struct fbr_desc *next =
+ (struct fbr_desc *) (rx_local->pFbr1RingVa) +
+ INDEX10(rx_local->local_Fbr1_full);
/* Handle the Free Buffer Ring advancement here. Write
* the PA / Buffer Index for the returned buffer into
* the oldest (next to be freed)FBR entry
*/
- next->addr_hi = rx_local->Fbr[1]->PAHigh[bi];
- next->addr_lo = rx_local->Fbr[1]->PALow[bi];
- next->word2.value = bi;
+ next->addr_hi = rx_local->fbr[1]->bus_high[bi];
+ next->addr_lo = rx_local->fbr[1]->bus_low[bi];
+ next->word2 = bi;
writel(bump_fbr(&rx_local->local_Fbr1_full,
rx_local->Fbr1NumEntries - 1),
@@ -1134,17 +1121,17 @@ void nic_return_rfd(struct et131x_adapter *etdev, PMP_RFD rfd)
}
#ifdef USE_FBR0
else {
- PFBR_DESC_t next =
- (PFBR_DESC_t) rx_local->pFbr0RingVa +
- INDEX10(rx_local->local_Fbr0_full);
+ struct fbr_desc *next = (struct fbr_desc *)
+ rx_local->pFbr0RingVa +
+ INDEX10(rx_local->local_Fbr0_full);
/* Handle the Free Buffer Ring advancement here. Write
* the PA / Buffer Index for the returned buffer into
* the oldest (next to be freed) FBR entry
*/
- next->addr_hi = rx_local->Fbr[0]->PAHigh[bi];
- next->addr_lo = rx_local->Fbr[0]->PALow[bi];
- next->word2.value = bi;
+ next->addr_hi = rx_local->fbr[0]->bus_high[bi];
+ next->addr_lo = rx_local->fbr[0]->bus_low[bi];
+ next->word2 = bi;
writel(bump_fbr(&rx_local->local_Fbr0_full,
rx_local->Fbr0NumEntries - 1),
diff --git a/drivers/staging/et131x/et1310_rx.h b/drivers/staging/et131x/et1310_rx.h
index 69514593612c..ca84a9146d69 100644
--- a/drivers/staging/et131x/et1310_rx.h
+++ b/drivers/staging/et131x/et1310_rx.h
@@ -91,120 +91,60 @@
#define ALCATEL_BROADCAST_PKT 0x02000000
/* typedefs for Free Buffer Descriptors */
-typedef union _FBR_WORD2_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 reserved:22; /* bits 10-31 */
- u32 bi:10; /* bits 0-9(Buffer Index) */
-#else
- u32 bi:10; /* bits 0-9(Buffer Index) */
- u32 reserved:22; /* bit 10-31 */
-#endif
- } bits;
-} FBR_WORD2_t, *PFBR_WORD2_t;
-
-typedef struct _FBR_DESC_t {
+struct fbr_desc
+{
u32 addr_lo;
u32 addr_hi;
- FBR_WORD2_t word2;
-} FBR_DESC_t, *PFBR_DESC_t;
-
-/* Typedefs for Packet Status Ring Descriptors */
-typedef union _PKT_STAT_DESC_WORD0_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- /* top 16 bits are from the Alcatel Status Word as enumerated in */
- /* PE-MCXMAC Data Sheet IPD DS54 0210-1 (also IPD-DS80 0205-2) */
-#if 0
- u32 asw_trunc:1; /* bit 31(Rx frame truncated) */
-#endif
- u32 asw_long_evt:1; /* bit 31(Rx long event) */
- u32 asw_VLAN_tag:1; /* bit 30(VLAN tag detected) */
- u32 asw_unsupported_op:1; /* bit 29(unsupported OP code) */
- u32 asw_pause_frame:1; /* bit 28(is a pause frame) */
- u32 asw_control_frame:1; /* bit 27(is a control frame) */
- u32 asw_dribble_nibble:1; /* bit 26(spurious bits after EOP) */
- u32 asw_broadcast:1; /* bit 25(has a broadcast address) */
- u32 asw_multicast:1; /* bit 24(has a multicast address) */
- u32 asw_OK:1; /* bit 23(valid CRC + no code error) */
- u32 asw_too_long:1; /* bit 22(frame length > 1518 bytes) */
- u32 asw_len_chk_err:1; /* bit 21(frame length field incorrect) */
- u32 asw_CRC_err:1; /* bit 20(CRC error) */
- u32 asw_code_err:1; /* bit 19(one or more nibbles signalled as errors) */
- u32 asw_false_carrier_event:1; /* bit 18(bad carrier since last good packet) */
- u32 asw_RX_DV_event:1; /* bit 17(short receive event detected) */
- u32 asw_prev_pkt_dropped:1;/* bit 16(e.g. IFG too small on previous) */
- u32 unused:5; /* bits 11-15 */
- u32 vp:1; /* bit 10(VLAN Packet) */
- u32 jp:1; /* bit 9(Jumbo Packet) */
- u32 ft:1; /* bit 8(Frame Truncated) */
- u32 drop:1; /* bit 7(Drop packet) */
- u32 rxmac_error:1; /* bit 6(RXMAC Error Indicator) */
- u32 wol:1; /* bit 5(WOL Event) */
- u32 tcpp:1; /* bit 4(TCP checksum pass) */
- u32 tcpa:1; /* bit 3(TCP checksum assist) */
- u32 ipp:1; /* bit 2(IP checksum pass) */
- u32 ipa:1; /* bit 1(IP checksum assist) */
- u32 hp:1; /* bit 0(hash pass) */
-#else
- u32 hp:1; /* bit 0(hash pass) */
- u32 ipa:1; /* bit 1(IP checksum assist) */
- u32 ipp:1; /* bit 2(IP checksum pass) */
- u32 tcpa:1; /* bit 3(TCP checksum assist) */
- u32 tcpp:1; /* bit 4(TCP checksum pass) */
- u32 wol:1; /* bit 5(WOL Event) */
- u32 rxmac_error:1; /* bit 6(RXMAC Error Indicator) */
- u32 drop:1; /* bit 7(Drop packet) */
- u32 ft:1; /* bit 8(Frame Truncated) */
- u32 jp:1; /* bit 9(Jumbo Packet) */
- u32 vp:1; /* bit 10(VLAN Packet) */
- u32 unused:5; /* bits 11-15 */
- u32 asw_prev_pkt_dropped:1;/* bit 16(e.g. IFG too small on previous) */
- u32 asw_RX_DV_event:1; /* bit 17(short receive event detected) */
- u32 asw_false_carrier_event:1; /* bit 18(bad carrier since last good packet) */
- u32 asw_code_err:1; /* bit 19(one or more nibbles signalled as errors) */
- u32 asw_CRC_err:1; /* bit 20(CRC error) */
- u32 asw_len_chk_err:1; /* bit 21(frame length field incorrect) */
- u32 asw_too_long:1; /* bit 22(frame length > 1518 bytes) */
- u32 asw_OK:1; /* bit 23(valid CRC + no code error) */
- u32 asw_multicast:1; /* bit 24(has a multicast address) */
- u32 asw_broadcast:1; /* bit 25(has a broadcast address) */
- u32 asw_dribble_nibble:1; /* bit 26(spurious bits after EOP) */
- u32 asw_control_frame:1; /* bit 27(is a control frame) */
- u32 asw_pause_frame:1; /* bit 28(is a pause frame) */
- u32 asw_unsupported_op:1; /* bit 29(unsupported OP code) */
- u32 asw_VLAN_tag:1; /* bit 30(VLAN tag detected) */
- u32 asw_long_evt:1; /* bit 31(Rx long event) */
-#if 0
- u32 asw_trunc:1; /* bit 31(Rx frame truncated) */
-#endif
-#endif
- } bits;
-} PKT_STAT_DESC_WORD0_t, *PPKT_STAT_WORD0_t;
+ u32 word2; /* Bits 10-31 reserved, 0-9 descriptor */
+};
-typedef union _PKT_STAT_DESC_WORD1_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 unused:4; /* bits 28-31 */
- u32 ri:2; /* bits 26-27(Ring Index) */
- u32 bi:10; /* bits 16-25(Buffer Index) */
- u32 length:16; /* bit 0-15(length in bytes) */
-#else
- u32 length:16; /* bit 0-15(length in bytes) */
- u32 bi:10; /* bits 16-25(Buffer Index) */
- u32 ri:2; /* bits 26-27(Ring Index) */
- u32 unused:4; /* bits 28-31 */
-#endif
- } bits;
-} PKT_STAT_DESC_WORD1_t, *PPKT_STAT_WORD1_t;
+/* Packet Status Ring Descriptors
+ *
+ * Word 0:
+ *
+ * top 16 bits are from the Alcatel Status Word as enumerated in
+ * PE-MCXMAC Data Sheet IPD DS54 0210-1 (also IPD-DS80 0205-2)
+ *
+ * 0: hp hash pass
+ * 1: ipa IP checksum assist
+ * 2: ipp IP checksum pass
+ * 3: tcpa TCP checksum assist
+ * 4: tcpp TCP checksum pass
+ * 5: wol WOL Event
+ * 6: rxmac_error RXMAC Error Indicator
+ * 7: drop Drop packet
+ * 8: ft Frame Truncated
+ * 9: jp Jumbo Packet
+ * 10: vp VLAN Packet
+ * 11-15: unused
+ * 16: asw_prev_pkt_dropped e.g. IFG too small on previous
+ * 17: asw_RX_DV_event short receive event detected
+ * 18: asw_false_carrier_event bad carrier since last good packet
+ * 19: asw_code_err one or more nibbles signalled as errors
+ * 20: asw_CRC_err CRC error
+ * 21: asw_len_chk_err frame length field incorrect
+ * 22: asw_too_long frame length > 1518 bytes
+ * 23: asw_OK valid CRC + no code error
+ * 24: asw_multicast has a multicast address
+ * 25: asw_broadcast has a broadcast address
+ * 26: asw_dribble_nibble spurious bits after EOP
+ * 27: asw_control_frame is a control frame
+ * 28: asw_pause_frame is a pause frame
+ * 29: asw_unsupported_op unsupported OP code
+ * 30: asw_VLAN_tag VLAN tag detected
+ * 31: asw_long_evt Rx long event
+ *
+ * Word 1:
+ * 0-15: length length in bytes
+ * 16-25: bi Buffer Index
+ * 26-27: ri Ring Index
+ * 28-31: reserved
+ */
-typedef struct _PKT_STAT_DESC_t {
- PKT_STAT_DESC_WORD0_t word0;
- PKT_STAT_DESC_WORD1_t word1;
-} PKT_STAT_DESC_t, *PPKT_STAT_DESC_t;
+struct pkt_stat_desc {
+ u32 word0;
+ u32 word1;
+};
/* Typedefs for the RX DMA status word */
@@ -223,59 +163,38 @@ typedef struct _PKT_STAT_DESC_t {
* RXSTAT_WORD1_t structure holds part of the status bits of the Rx DMA engine
* that get copied out to memory by the ET-1310. Word 3 is a 32 bit word
* which contains the Packet Status Ring available offset.
+ *
+ * bit 0-15 reserved
+ * bit 16-27 PSRoffset
+ * bit 28 PSRwrap
+ * bit 29-31 unused
*/
-#define RXSTAT1_OFFSET 16
-#define RXSTAT1_MASK 0xFFF
-#define RXSTAT1_WRAP 0x10000000
-
-typedef union _rxstat_word1_t {
- u32 value;
- struct {
-#ifdef _BIT_FIELDS_HTOL
- u32 PSRunused:3; /* bits 29-31 */
- u32 PSRwrap:1; /* bit 28 */
- u32 PSRoffset:12; /* bits 16-27 */
- u32 reserved:16; /* bits 0-15 */
-#else
- u32 reserved:16; /* bits 0-15 */
- u32 PSRoffset:12; /* bits 16-27 */
- u32 PSRwrap:1; /* bit 28 */
- u32 PSRunused:3; /* bits 29-31 */
-#endif
- } bits;
-} RXSTAT_WORD1_t, *PRXSTAT_WORD1_t;
-
/*
- * RX_STATUS_BLOCK_t is sructure representing the status of the Rx DMA engine
- * it sits in free memory, and is pointed to by 0x101c / 0x1020
+ * struct rx_status_block is a structure representing the status of the Rx
+ * DMA engine it sits in free memory, and is pointed to by 0x101c / 0x1020
*/
-typedef struct _rx_status_block_t {
+struct rx_status_block {
u32 Word0;
- RXSTAT_WORD1_t Word1;
-} RX_STATUS_BLOCK_t, *PRX_STATUS_BLOCK_t;
+ u32 Word1;
+};
/*
* Structure for look-up table holding free buffer ring pointers
*/
-typedef struct _FbrLookupTable {
- void *Va[MAX_DESC_PER_RING_RX];
- void *Buffer1[MAX_DESC_PER_RING_RX];
- void *Buffer2[MAX_DESC_PER_RING_RX];
- u32 PAHigh[MAX_DESC_PER_RING_RX];
- u32 PALow[MAX_DESC_PER_RING_RX];
-} FBRLOOKUPTABLE, *PFBRLOOKUPTABLE;
-
-typedef enum {
- ONE_PACKET_INTERRUPT,
- FOUR_PACKET_INTERRUPT
-} eRX_INTERRUPT_STATE_t, *PeRX_INTERRUPT_STATE_t;
+struct fbr_lookup {
+ void *virt[MAX_DESC_PER_RING_RX];
+ void *buffer1[MAX_DESC_PER_RING_RX];
+ void *buffer2[MAX_DESC_PER_RING_RX];
+ u32 bus_high[MAX_DESC_PER_RING_RX];
+ u32 bus_low[MAX_DESC_PER_RING_RX];
+};
/*
- * RX_RING_t is sructure representing the adaptor's local reference(s) to the
- * rings
+ * struct rx_ring is the ssructure representing the adaptor's local
+ * reference(s) to the rings
*/
-typedef struct _rx_ring_t {
+struct rx_ring {
#ifdef USE_FBR0
void *pFbr0RingVa;
dma_addr_t pFbr0RingPa;
@@ -293,7 +212,7 @@ typedef struct _rx_ring_t {
dma_addr_t Fbr1MemPa[MAX_DESC_PER_RING_RX / FBR_CHUNKS];
uint64_t Fbr1Realpa;
uint64_t Fbr1offset;
- FBRLOOKUPTABLE *Fbr[2];
+ struct fbr_lookup *fbr[2]; /* One per ring */
u32 local_Fbr1_full;
u32 Fbr1NumEntries;
u32 Fbr1BufferSize;
@@ -303,8 +222,8 @@ typedef struct _rx_ring_t {
u32 local_psr_full;
u32 PsrNumEntries;
- void *pRxStatusVa;
- dma_addr_t pRxStatusPa;
+ struct rx_status_block *rx_status_block;
+ dma_addr_t rx_status_bus;
struct list_head RecvBufferPool;
@@ -320,30 +239,6 @@ typedef struct _rx_ring_t {
/* lookaside lists */
struct kmem_cache *RecvLookaside;
-} RX_RING_t, *PRX_RING_t;
-
-/* Forward reference of RFD */
-struct _MP_RFD;
-
-/* Forward declaration of the private adapter structure */
-struct et131x_adapter;
-
-/* PROTOTYPES for Initialization */
-int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter);
-void et131x_rx_dma_memory_free(struct et131x_adapter *adapter);
-int et131x_rfd_resources_alloc(struct et131x_adapter *adapter,
- struct _MP_RFD *pMpRfd);
-void et131x_rfd_resources_free(struct et131x_adapter *adapter,
- struct _MP_RFD *pMpRfd);
-int et131x_init_recv(struct et131x_adapter *adapter);
-
-void ConfigRxDmaRegs(struct et131x_adapter *adapter);
-void SetRxDmaTimer(struct et131x_adapter *adapter);
-void et131x_rx_dma_disable(struct et131x_adapter *adapter);
-void et131x_rx_dma_enable(struct et131x_adapter *adapter);
-
-void et131x_reset_recv(struct et131x_adapter *adapter);
-
-void et131x_handle_recv_interrupt(struct et131x_adapter *adapter);
+};
#endif /* __ET1310_RX_H__ */
diff --git a/drivers/staging/et131x/et1310_tx.c b/drivers/staging/et131x/et1310_tx.c
index 977e8b34e7a6..b6ff20f47de4 100644
--- a/drivers/staging/et131x/et1310_tx.c
+++ b/drivers/staging/et131x/et1310_tx.c
@@ -84,15 +84,9 @@
#include <linux/ioport.h>
#include "et1310_phy.h"
-#include "et1310_pm.h"
-#include "et1310_jagcore.h"
-
#include "et131x_adapter.h"
-#include "et131x_initpci.h"
-#include "et131x_isr.h"
-
#include "et1310_tx.h"
-
+#include "et131x.h"
static inline void et131x_free_send_packet(struct et131x_adapter *etdev,
struct tcb *tcb);
@@ -200,7 +194,7 @@ void et131x_tx_dma_memory_free(struct et131x_adapter *adapter)
*/
void ConfigTxDmaRegs(struct et131x_adapter *etdev)
{
- struct _TXDMA_t __iomem *txdma = &etdev->regs->txdma;
+ struct txdma_regs __iomem *txdma = &etdev->regs->txdma;
/* Load the hardware with the start of the transmit descriptor ring. */
writel((u32) ((u64)etdev->tx_ring.tx_desc_ring_pa >> 32),
diff --git a/drivers/staging/et131x/et1310_tx.h b/drivers/staging/et131x/et1310_tx.h
index 4f0ea81978f5..82d06e9870de 100644
--- a/drivers/staging/et131x/et1310_tx.h
+++ b/drivers/staging/et131x/et1310_tx.h
@@ -147,18 +147,4 @@ struct tx_ring {
int since_irq;
};
-/* Forward declaration of the private adapter structure */
-struct et131x_adapter;
-
-/* PROTOTYPES for et1310_tx.c */
-int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter);
-void et131x_tx_dma_memory_free(struct et131x_adapter *adapter);
-void ConfigTxDmaRegs(struct et131x_adapter *adapter);
-void et131x_init_send(struct et131x_adapter *adapter);
-void et131x_tx_dma_disable(struct et131x_adapter *adapter);
-void et131x_tx_dma_enable(struct et131x_adapter *adapter);
-void et131x_handle_send_interrupt(struct et131x_adapter *adapter);
-void et131x_free_busy_send_packets(struct et131x_adapter *adapter);
-int et131x_send_packets(struct sk_buff *skb, struct net_device *netdev);
-
#endif /* __ET1310_TX_H__ */
diff --git a/drivers/staging/et131x/et131x.h b/drivers/staging/et131x/et131x.h
new file mode 100644
index 000000000000..a8abfe6ca81f
--- /dev/null
+++ b/drivers/staging/et131x/et131x.h
@@ -0,0 +1,153 @@
+/*
+ * Merged from files
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, 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 as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. 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, INCLUDING, BUT NOT LIMITED TO, 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.
+ *
+ */
+
+/* et131x_eeprom.c */
+int et131x_init_eeprom(struct et131x_adapter *etdev);
+
+/* et131x_initpci.c */
+void ConfigGlobalRegs(struct et131x_adapter *pAdapter);
+void ConfigMMCRegs(struct et131x_adapter *pAdapter);
+void et131x_enable_interrupts(struct et131x_adapter *adapter);
+void et131x_disable_interrupts(struct et131x_adapter *adapter);
+void et131x_align_allocated_memory(struct et131x_adapter *adapter,
+ u64 *phys_addr,
+ u64 *offset, u64 mask);
+
+int et131x_adapter_setup(struct et131x_adapter *adapter);
+int et131x_adapter_memory_alloc(struct et131x_adapter *adapter);
+void et131x_adapter_memory_free(struct et131x_adapter *adapter);
+void et131x_hwaddr_init(struct et131x_adapter *adapter);
+void et131x_soft_reset(struct et131x_adapter *adapter);
+
+/* et131x_isr.c */
+irqreturn_t et131x_isr(int irq, void *dev_id);
+void et131x_isr_handler(struct work_struct *work);
+
+/* et1310_mac.c */
+void ConfigMACRegs1(struct et131x_adapter *adapter);
+void ConfigMACRegs2(struct et131x_adapter *adapter);
+void ConfigRxMacRegs(struct et131x_adapter *adapter);
+void ConfigTxMacRegs(struct et131x_adapter *adapter);
+void ConfigMacStatRegs(struct et131x_adapter *adapter);
+void ConfigFlowControl(struct et131x_adapter *adapter);
+void UpdateMacStatHostCounters(struct et131x_adapter *adapter);
+void HandleMacStatInterrupt(struct et131x_adapter *adapter);
+void SetupDeviceForMulticast(struct et131x_adapter *adapter);
+void SetupDeviceForUnicast(struct et131x_adapter *adapter);
+
+/* et131x_netdev.c */
+struct net_device *et131x_device_alloc(void);
+
+/* et131x_pm.c */
+void EnablePhyComa(struct et131x_adapter *adapter);
+void DisablePhyComa(struct et131x_adapter *adapter);
+
+/* et131x_phy.c */
+void ET1310_PhyInit(struct et131x_adapter *adapter);
+void ET1310_PhyReset(struct et131x_adapter *adapter);
+void ET1310_PhyPowerDown(struct et131x_adapter *adapter, bool down);
+void ET1310_PhyAdvertise1000BaseT(struct et131x_adapter *adapter,
+ u16 duplex);
+void ET1310_PhyAccessMiBit(struct et131x_adapter *adapter,
+ u16 action,
+ u16 regnum, u16 bitnum, u8 *value);
+
+int et131x_xcvr_find(struct et131x_adapter *adapter);
+void et131x_setphy_normal(struct et131x_adapter *adapter);
+
+/* static inline function does not work because et131x_adapter is not always
+ * defined
+ */
+int PhyMiRead(struct et131x_adapter *adapter, u8 xcvrAddr,
+ u8 xcvrReg, u16 *value);
+#define MiRead(adapter, xcvrReg, value) \
+ PhyMiRead((adapter), (adapter)->Stats.xcvr_addr, (xcvrReg), (value))
+
+int32_t MiWrite(struct et131x_adapter *adapter,
+ u8 xcvReg, u16 value);
+void et131x_Mii_check(struct et131x_adapter *pAdapter,
+ MI_BMSR_t bmsr, MI_BMSR_t bmsr_ints);
+
+/* This last is not strictly required (the driver could call the TPAL
+ * version instead), but this sets the adapter up correctly, and calls the
+ * access routine indirectly. This protects the driver from changes in TPAL.
+ */
+void SetPhy_10BaseTHalfDuplex(struct et131x_adapter *adapter);
+
+
+/* et1310_rx.c */
+int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter);
+void et131x_rx_dma_memory_free(struct et131x_adapter *adapter);
+int et131x_rfd_resources_alloc(struct et131x_adapter *adapter,
+ struct _MP_RFD *pMpRfd);
+void et131x_rfd_resources_free(struct et131x_adapter *adapter,
+ struct _MP_RFD *pMpRfd);
+int et131x_init_recv(struct et131x_adapter *adapter);
+
+void ConfigRxDmaRegs(struct et131x_adapter *adapter);
+void SetRxDmaTimer(struct et131x_adapter *adapter);
+void et131x_rx_dma_disable(struct et131x_adapter *adapter);
+void et131x_rx_dma_enable(struct et131x_adapter *adapter);
+
+void et131x_reset_recv(struct et131x_adapter *adapter);
+
+void et131x_handle_recv_interrupt(struct et131x_adapter *adapter);
+
+/* et131x_tx.c */
+int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter);
+void et131x_tx_dma_memory_free(struct et131x_adapter *adapter);
+void ConfigTxDmaRegs(struct et131x_adapter *adapter);
+void et131x_init_send(struct et131x_adapter *adapter);
+void et131x_tx_dma_disable(struct et131x_adapter *adapter);
+void et131x_tx_dma_enable(struct et131x_adapter *adapter);
+void et131x_handle_send_interrupt(struct et131x_adapter *adapter);
+void et131x_free_busy_send_packets(struct et131x_adapter *adapter);
+int et131x_send_packets(struct sk_buff *skb, struct net_device *netdev);
+
diff --git a/drivers/staging/et131x/et131x_adapter.h b/drivers/staging/et131x/et131x_adapter.h
index 3f7f37a56b6c..64a678fcb60a 100644
--- a/drivers/staging/et131x/et131x_adapter.h
+++ b/drivers/staging/et131x/et131x_adapter.h
@@ -77,38 +77,11 @@
*/
#define NUM_TRAFFIC_CLASSES 1
-/*
- * There are three ways of counting errors - if there are more than X errors
- * in Y packets (represented by the "SAMPLE" macros), if there are more than
- * N errors in a S mSec time period (the "PERIOD" macros), or if there are
- * consecutive packets with errors (CONSEC_ERRORED_THRESH). This last covers
- * for "Bursty" errors, and the errored packets may well not be contiguous,
- * but several errors where the packet counter has changed by less than a
- * small amount will cause this count to increment.
- */
-#define TX_PACKETS_IN_SAMPLE 10000
-#define TX_MAX_ERRORS_IN_SAMPLE 50
-
#define TX_ERROR_PERIOD 1000
-#define TX_MAX_ERRORS_IN_PERIOD 10
-
-#define LINK_DETECTION_TIMER 5000
-
-#define TX_CONSEC_RANGE 5
-#define TX_CONSEC_ERRORED_THRESH 10
#define LO_MARK_PERCENT_FOR_PSR 15
#define LO_MARK_PERCENT_FOR_RX 15
-/* Counters for error rate monitoring */
-typedef struct _MP_ERR_COUNTERS {
- u32 PktCountTxPackets;
- u32 PktCountTxErrors;
- u32 TimerBasedTxErrors;
- u32 PktCountLastError;
- u32 ErredConsecPackets;
-} MP_ERR_COUNTERS, *PMP_ERR_COUNTERS;
-
/* RFD (Receive Frame Descriptor) */
typedef struct _MP_RFD {
struct list_head list_node;
@@ -174,6 +147,20 @@ typedef struct _ce_stats_t {
u32 InterruptStatus;
} CE_STATS_t, *PCE_STATS_t;
+typedef struct _MP_POWER_MGMT {
+ /* variable putting the phy into coma mode when boot up with no cable
+ * plugged in after 5 seconds
+ */
+ u8 TransPhyComaModeOnBoot;
+
+ /* Next two used to save power information at power down. This
+ * information will be used during power up to set up parts of Power
+ * Management in JAGCore
+ */
+ u16 PowerDownSpeed;
+ u8 PowerDownDuplex;
+} MP_POWER_MGMT, *PMP_POWER_MGMT;
+
/* The private adapter structure */
struct et131x_adapter {
struct net_device *netdev;
@@ -248,7 +235,7 @@ struct et131x_adapter {
struct tx_ring tx_ring;
/* Rx Memory Variables */
- RX_RING_t RxRing;
+ struct rx_ring rx_ring;
/* Loopback specifics */
u8 ReplicaPhyLoopbk; /* Replica Enable */
diff --git a/drivers/staging/et131x/et131x_config.h b/drivers/staging/et131x/et131x_config.h
deleted file mode 100644
index 642c0f6dd6f3..000000000000
--- a/drivers/staging/et131x/et131x_config.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Agere Systems Inc.
- * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- * http://www.agere.com
- *
- *------------------------------------------------------------------------------
- *
- * et131x_config.h - Defines, structs, enums, prototypes, etc. to support
- * et131x_config.c
- *
- *------------------------------------------------------------------------------
- *
- * SOFTWARE LICENSE
- *
- * This software is provided subject to the following terms and conditions,
- * which you should read carefully before using the software. Using this
- * software indicates your acceptance of these terms and conditions. If you do
- * not agree with these terms and conditions, do not use the software.
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- *
- * Redistribution and use in source or binary forms, with or without
- * modifications, 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 as comments in the code as
- * well as in the documentation and/or other materials provided with the
- * distribution.
- *
- * . Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following Disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * . Neither the name of Agere Systems Inc. nor the names of the contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * Disclaimer
- *
- * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
- * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
- * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. 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, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- */
-
-#ifndef __ET131X_CONFIG_H__
-#define __ET131X_CONFIG_H__
-
-/* Forward declaration of the private adapter structure */
-struct et131x_adapter;
-
-void et131x_config_parse(struct et131x_adapter *adapter);
-
-#endif /* __ET131X_CONFIG_H__ */
diff --git a/drivers/staging/et131x/et131x_initpci.c b/drivers/staging/et131x/et131x_initpci.c
index 0892b6a538db..5ad7e5a6f631 100644
--- a/drivers/staging/et131x/et131x_initpci.c
+++ b/drivers/staging/et131x/et131x_initpci.c
@@ -87,20 +87,16 @@
#include <linux/random.h>
#include "et1310_phy.h"
-#include "et1310_pm.h"
-#include "et1310_jagcore.h"
#include "et131x_adapter.h"
-#include "et131x_netdev.h"
-#include "et131x_config.h"
-#include "et131x_isr.h"
#include "et1310_address_map.h"
#include "et1310_tx.h"
#include "et1310_rx.h"
-#include "et1310_mac.h"
-#include "et1310_eeprom.h"
+#include "et131x.h"
+#define INTERNAL_MEM_SIZE 0x400 /* 1024 of internal memory */
+#define INTERNAL_MEM_RX_OFFSET 0x1FF /* 50% Tx, 50% Rx */
/* Defines for Parameter Default/Min/Max vaules */
#define PARM_SPEED_DUPLEX_MIN 0
@@ -327,7 +323,7 @@ void et131x_link_detection_handler(unsigned long data)
*/
void ConfigGlobalRegs(struct et131x_adapter *etdev)
{
- struct _GLOBAL_t __iomem *regs = &etdev->regs->global;
+ struct global_regs __iomem *regs = &etdev->regs->global;
writel(0, &regs->rxq_start_addr);
writel(INTERNAL_MEM_SIZE - 1, &regs->txq_end_addr);
diff --git a/drivers/staging/et131x/et131x_initpci.h b/drivers/staging/et131x/et131x_initpci.h
deleted file mode 100644
index 7269569a874b..000000000000
--- a/drivers/staging/et131x/et131x_initpci.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Agere Systems Inc.
- * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- * http://www.agere.com
- *
- *------------------------------------------------------------------------------
- *
- * et131x_initpci.h - Header which includes common data and function prototypes
- * related to the driver's PCI (and PCI Express) information.
- *
- *------------------------------------------------------------------------------
- *
- * SOFTWARE LICENSE
- *
- * This software is provided subject to the following terms and conditions,
- * which you should read carefully before using the software. Using this
- * software indicates your acceptance of these terms and conditions. If you do
- * not agree with these terms and conditions, do not use the software.
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- *
- * Redistribution and use in source or binary forms, with or without
- * modifications, 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 as comments in the code as
- * well as in the documentation and/or other materials provided with the
- * distribution.
- *
- * . Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following Disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * . Neither the name of Agere Systems Inc. nor the names of the contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * Disclaimer
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
- * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
- * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. 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, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- */
-
-#ifndef __ET131X_INITPCI_H__
-#define __ET131X_INITPCI_H__
-
-/* Function Prototypes */
-void et131x_align_allocated_memory(struct et131x_adapter *adapter,
- u64 *phys_addr,
- u64 *offset, u64 mask);
-
-int et131x_adapter_setup(struct et131x_adapter *adapter);
-int et131x_adapter_memory_alloc(struct et131x_adapter *adapter);
-void et131x_adapter_memory_free(struct et131x_adapter *adapter);
-void et131x_hwaddr_init(struct et131x_adapter *adapter);
-void et131x_soft_reset(struct et131x_adapter *adapter);
-
-#endif /* __ET131X_INITPCI_H__ */
diff --git a/drivers/staging/et131x/et131x_isr.c b/drivers/staging/et131x/et131x_isr.c
index f6d452dd14e2..8b6e0b7ec568 100644
--- a/drivers/staging/et131x/et131x_isr.c
+++ b/drivers/staging/et131x/et131x_isr.c
@@ -85,11 +85,27 @@
#include <linux/ioport.h>
#include "et1310_phy.h"
-#include "et1310_pm.h"
-#include "et1310_jagcore.h"
-#include "et1310_mac.h"
-
#include "et131x_adapter.h"
+#include "et131x.h"
+
+/*
+ * For interrupts, normal running is:
+ * rxdma_xfr_done, phy_interrupt, mac_stat_interrupt,
+ * watchdog_interrupt & txdma_xfer_done
+ *
+ * In both cases, when flow control is enabled for either Tx or bi-direction,
+ * we additional enable rx_fbr0_low and rx_fbr1_low, so we know when the
+ * buffer rings are running low.
+ */
+#define INT_MASK_DISABLE 0xffffffff
+
+/* NOTE: Masking out MAC_STAT Interrupt for now...
+ * #define INT_MASK_ENABLE 0xfff6bf17
+ * #define INT_MASK_ENABLE_NO_FLOW 0xfff6bfd7
+ */
+#define INT_MASK_ENABLE 0xfffebf17
+#define INT_MASK_ENABLE_NO_FLOW 0xfffebfd7
+
/**
* et131x_enable_interrupts - enable interrupt
@@ -185,7 +201,7 @@ irqreturn_t et131x_isr(int irq, void *dev_id)
if (++tcb->stale > 1)
status |= ET_INTR_TXDMA_ISR;
- if (adapter->RxRing.UnfinishedReceives)
+ if (adapter->rx_ring.UnfinishedReceives)
status |= ET_INTR_RXDMA_XFR_DONE;
else if (tcb == NULL)
writel(0, &adapter->regs->global.watchdog_timer);
@@ -390,7 +406,7 @@ void et131x_isr_handler(struct work_struct *work)
/* Let's move on to the TxMac */
if (status & ET_INTR_TXMAC) {
- u32 err = readl(&iomem->txmac.err.value);
+ u32 err = readl(&iomem->txmac.err);
/*
* When any of the errors occur and TXMAC generates
@@ -425,12 +441,12 @@ void et131x_isr_handler(struct work_struct *work)
dev_warn(&etdev->pdev->dev,
"RXMAC interrupt, error 0x%08x. Requesting reset\n",
- readl(&iomem->rxmac.err_reg.value));
+ readl(&iomem->rxmac.err_reg));
dev_warn(&etdev->pdev->dev,
"Enable 0x%08x, Diag 0x%08x\n",
- readl(&iomem->rxmac.ctrl.value),
- readl(&iomem->rxmac.rxq_diag.value));
+ readl(&iomem->rxmac.ctrl),
+ readl(&iomem->rxmac.rxq_diag));
/*
* If we are debugging, we want to see this error,
diff --git a/drivers/staging/et131x/et131x_isr.h b/drivers/staging/et131x/et131x_isr.h
deleted file mode 100644
index 906d57727e20..000000000000
--- a/drivers/staging/et131x/et131x_isr.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Agere Systems Inc.
- * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- * http://www.agere.com
- *
- *------------------------------------------------------------------------------
- *
- * et131x_isr.h - Defines, structs, enums, prototypes, etc. pertaining to the
- * ISR processing code.
- *
- *------------------------------------------------------------------------------
- *
- * SOFTWARE LICENSE
- *
- * This software is provided subject to the following terms and conditions,
- * which you should read carefully before using the software. Using this
- * software indicates your acceptance of these terms and conditions. If you do
- * not agree with these terms and conditions, do not use the software.
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- *
- * Redistribution and use in source or binary forms, with or without
- * modifications, 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 as comments in the code as
- * well as in the documentation and/or other materials provided with the
- * distribution.
- *
- * . Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following Disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * . Neither the name of Agere Systems Inc. nor the names of the contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * Disclaimer
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
- * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
- * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. 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, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- */
-
-#ifndef __ET131X_ISR_H__
-#define __ET131X_ISR_H__
-
-irqreturn_t et131x_isr(int irq, void *dev_id);
-void et131x_isr_handler(struct work_struct *work);
-
-#endif /* __ET131X_ISR_H__ */
diff --git a/drivers/staging/et131x/et131x_netdev.c b/drivers/staging/et131x/et131x_netdev.c
index 24d97b4fa6fb..40f8954dde47 100644
--- a/drivers/staging/et131x/et131x_netdev.c
+++ b/drivers/staging/et131x/et131x_netdev.c
@@ -85,14 +85,9 @@
#include <linux/ioport.h>
#include "et1310_phy.h"
-#include "et1310_pm.h"
-#include "et1310_jagcore.h"
-#include "et1310_mac.h"
#include "et1310_tx.h"
-
#include "et131x_adapter.h"
-#include "et131x_isr.h"
-#include "et131x_initpci.h"
+#include "et131x.h"
struct net_device_stats *et131x_stats(struct net_device *netdev);
int et131x_open(struct net_device *netdev);
@@ -339,66 +334,64 @@ int et131x_ioctl(struct net_device *netdev, struct ifreq *reqbuf, int cmd)
* et131x_set_packet_filter - Configures the Rx Packet filtering on the device
* @adapter: pointer to our private adapter structure
*
+ * FIXME: lot of dups with MAC code
+ *
* Returns 0 on success, errno on failure
*/
int et131x_set_packet_filter(struct et131x_adapter *adapter)
{
int status = 0;
uint32_t filter = adapter->PacketFilter;
- RXMAC_CTRL_t ctrl;
- RXMAC_PF_CTRL_t pf_ctrl;
+ u32 ctrl;
+ u32 pf_ctrl;
- ctrl.value = readl(&adapter->regs->rxmac.ctrl.value);
- pf_ctrl.value = readl(&adapter->regs->rxmac.pf_ctrl.value);
+ ctrl = readl(&adapter->regs->rxmac.ctrl);
+ pf_ctrl = readl(&adapter->regs->rxmac.pf_ctrl);
/* Default to disabled packet filtering. Enable it in the individual
* case statements that require the device to filter something
*/
- ctrl.bits.pkt_filter_disable = 1;
+ ctrl |= 0x04;
/* Set us to be in promiscuous mode so we receive everything, this
* is also true when we get a packet filter of 0
*/
- if ((filter & ET131X_PACKET_TYPE_PROMISCUOUS) || filter == 0) {
- pf_ctrl.bits.filter_broad_en = 0;
- pf_ctrl.bits.filter_multi_en = 0;
- pf_ctrl.bits.filter_uni_en = 0;
- } else {
+ if ((filter & ET131X_PACKET_TYPE_PROMISCUOUS) || filter == 0)
+ pf_ctrl &= ~7; /* Clear filter bits */
+ else {
/*
* Set us up with Multicast packet filtering. Three cases are
* possible - (1) we have a multi-cast list, (2) we receive ALL
* multicast entries or (3) we receive none.
*/
- if (filter & ET131X_PACKET_TYPE_ALL_MULTICAST) {
- pf_ctrl.bits.filter_multi_en = 0;
- } else {
+ if (filter & ET131X_PACKET_TYPE_ALL_MULTICAST)
+ pf_ctrl &= ~2; /* Multicast filter bit */
+ else {
SetupDeviceForMulticast(adapter);
- pf_ctrl.bits.filter_multi_en = 1;
- ctrl.bits.pkt_filter_disable = 0;
+ pf_ctrl |= 2;
+ ctrl &= ~0x04;
}
/* Set us up with Unicast packet filtering */
if (filter & ET131X_PACKET_TYPE_DIRECTED) {
SetupDeviceForUnicast(adapter);
- pf_ctrl.bits.filter_uni_en = 1;
- ctrl.bits.pkt_filter_disable = 0;
+ pf_ctrl |= 4;
+ ctrl &= ~0x04;
}
/* Set us up with Broadcast packet filtering */
if (filter & ET131X_PACKET_TYPE_BROADCAST) {
- pf_ctrl.bits.filter_broad_en = 1;
- ctrl.bits.pkt_filter_disable = 0;
- } else {
- pf_ctrl.bits.filter_broad_en = 0;
- }
+ pf_ctrl |= 1; /* Broadcast filter bit */
+ ctrl &= ~0x04;
+ } else
+ pf_ctrl &= ~1;
/* Setup the receive mac configuration registers - Packet
* Filter control + the enable / disable for packet filter
* in the control reg.
*/
- writel(pf_ctrl.value,
- &adapter->regs->rxmac.pf_ctrl.value);
- writel(ctrl.value, &adapter->regs->rxmac.ctrl.value);
+ writel(pf_ctrl, &adapter->regs->rxmac.pf_ctrl);
+ writel(ctrl, &adapter->regs->rxmac.ctrl);
}
return status;
}
@@ -411,9 +404,9 @@ void et131x_multicast(struct net_device *netdev)
{
struct et131x_adapter *adapter = netdev_priv(netdev);
uint32_t PacketFilter = 0;
- uint32_t count;
unsigned long flags;
- struct dev_mc_list *mclist = netdev->mc_list;
+ struct dev_mc_list *mclist;
+ int i;
spin_lock_irqsave(&adapter->Lock, flags);
@@ -444,11 +437,11 @@ void et131x_multicast(struct net_device *netdev)
adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST;
}
- if (netdev->mc_count > NIC_MAX_MCAST_LIST) {
+ if (netdev_mc_count(netdev) > NIC_MAX_MCAST_LIST) {
adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST;
}
- if (netdev->mc_count < 1) {
+ if (netdev_mc_count(netdev) < 1) {
adapter->PacketFilter &= ~ET131X_PACKET_TYPE_ALL_MULTICAST;
adapter->PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST;
} else {
@@ -456,12 +449,13 @@ void et131x_multicast(struct net_device *netdev)
}
/* Set values in the private adapter struct */
- adapter->MCAddressCount = netdev->mc_count;
-
- if (netdev->mc_count) {
- count = netdev->mc_count - 1;
- memcpy(adapter->MCList[count], mclist->dmi_addr, ETH_ALEN);
+ i = 0;
+ netdev_for_each_mc_addr(mclist, netdev) {
+ if (i == NIC_MAX_MCAST_LIST)
+ break;
+ memcpy(adapter->MCList[i++], mclist->dmi_addr, ETH_ALEN);
}
+ adapter->MCAddressCount = i;
/* Are the new flags different from the previous ones? If not, then no
* action is required
@@ -674,12 +668,8 @@ int et131x_set_mac_addr(struct net_device *netdev, void *new_mac)
memcpy(netdev->dev_addr, address->sa_data, netdev->addr_len);
- printk(KERN_INFO
- "%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n",
- netdev->name,
- netdev->dev_addr[0], netdev->dev_addr[1],
- netdev->dev_addr[2], netdev->dev_addr[3],
- netdev->dev_addr[4], netdev->dev_addr[5]);
+ printk(KERN_INFO "%s: Setting MAC address to %pM\n",
+ netdev->name, netdev->dev_addr);
/* Free Rx DMA memory */
et131x_adapter_memory_free(adapter);
diff --git a/drivers/staging/et131x/et131x_netdev.h b/drivers/staging/et131x/et131x_netdev.h
deleted file mode 100644
index 1eb4a922c01d..000000000000
--- a/drivers/staging/et131x/et131x_netdev.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Agere Systems Inc.
- * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- * http://www.agere.com
- *
- *------------------------------------------------------------------------------
- *
- * et131x_netdev.h - Defines, structs, enums, prototypes, etc. related to the
- * driver's net_device support.
- *
- *------------------------------------------------------------------------------
- *
- * SOFTWARE LICENSE
- *
- * This software is provided subject to the following terms and conditions,
- * which you should read carefully before using the software. Using this
- * software indicates your acceptance of these terms and conditions. If you do
- * not agree with these terms and conditions, do not use the software.
- *
- * Copyright © 2005 Agere Systems Inc.
- * All rights reserved.
- *
- * Redistribution and use in source or binary forms, with or without
- * modifications, 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 as comments in the code as
- * well as in the documentation and/or other materials provided with the
- * distribution.
- *
- * . Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following Disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * . Neither the name of Agere Systems Inc. nor the names of the contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * Disclaimer
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
- * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
- * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. 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, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- */
-
-#ifndef __ET131X_NETDEV_H__
-#define __ET131X_NETDEV_H__
-
-struct net_device *et131x_device_alloc(void);
-
-#endif /* __ET131X_NETDEV_H__ */
diff --git a/drivers/staging/et131x/et131x_version.h b/drivers/staging/et131x/et131x_version.h
index 568f6c8c34f5..2aa9bda44ac0 100644
--- a/drivers/staging/et131x/et131x_version.h
+++ b/drivers/staging/et131x/et131x_version.h
@@ -62,20 +62,13 @@
#define DRIVER_LICENSE "Dual BSD/GPL"
#define DRIVER_DEVICE_STRING "ET1310"
#define DRIVER_NAME "et131x"
-#define DRIVER_MAJOR_VERSION 1
-#define DRIVER_MINOR_VERSION 2
-#define DRIVER_PATCH_VERSION 3
-#define DRIVER_VERSION_STRING "1.2.3"
+#define DRIVER_VERSION_STRING "1.2.3-lk"
#define DRIVER_VENDOR "Agere Systems, http://www.agere.com"
#define DRIVER_DESC "10/100/1000 Base-T Ethernet Driver"
-#define STRUCT_MODULE "net" /* blux: missed by the kernel */
-
#define DRIVER_INFO DRIVER_DESC " for the "\
DRIVER_DEVICE_STRING ", v" \
DRIVER_VERSION_STRING " by " \
DRIVER_VENDOR
-#define DRIVER_NAME_EXT "et131x.ko"
-
#endif /* __ET131X_VERSION_H__ */
diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c
index 15aed87fe1bb..a50a21518a8e 100644
--- a/drivers/staging/frontier/alphatrack.c
+++ b/drivers/staging/frontier/alphatrack.c
@@ -58,7 +58,7 @@
#endif
/* table of devices that work with this driver */
-static struct usb_device_id usb_alphatrack_table[] = {
+static const struct usb_device_id usb_alphatrack_table[] = {
{USB_DEVICE(VENDOR_ID, PRODUCT_ID)},
{} /* Terminating entry */
};
diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c
index ef8fcc8c67bd..2f03f43f3a2e 100644
--- a/drivers/staging/frontier/tranzport.c
+++ b/drivers/staging/frontier/tranzport.c
@@ -55,7 +55,7 @@
#endif
/* table of devices that work with this driver */
-static struct usb_device_id usb_tranzport_table[] = {
+static const struct usb_device_id usb_tranzport_table[] = {
{USB_DEVICE(VENDOR_ID, PRODUCT_ID)},
{} /* Terminating entry */
};
diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c
index fb1345ffb858..d42ba1696999 100644
--- a/drivers/staging/go7007/go7007-driver.c
+++ b/drivers/staging/go7007/go7007-driver.c
@@ -128,6 +128,8 @@ static int go7007_load_encoder(struct go7007 *go)
return rv;
}
+MODULE_FIRMWARE("go7007fw.bin");
+
/*
* Boot the encoder and register the I2C adapter if requested. Do the
* minimum initialization necessary, since the board-specific code may
diff --git a/drivers/staging/go7007/go7007-usb.c b/drivers/staging/go7007/go7007-usb.c
index 1e89dc04ec23..ee278f64a16b 100644
--- a/drivers/staging/go7007/go7007-usb.c
+++ b/drivers/staging/go7007/go7007-usb.c
@@ -444,7 +444,9 @@ static struct go7007_usb_board board_sensoray_2250 = {
},
};
-static struct usb_device_id go7007_usb_id_table[] = {
+MODULE_FIRMWARE("go7007tv.bin");
+
+static const struct usb_device_id go7007_usb_id_table[] = {
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/staging/go7007/s2250-board.c b/drivers/staging/go7007/s2250-board.c
index 8cf7f2750b3f..dc89502ea1b7 100644
--- a/drivers/staging/go7007/s2250-board.c
+++ b/drivers/staging/go7007/s2250-board.c
@@ -159,7 +159,7 @@ static int write_reg(struct i2c_client *client, u8 reg, u8 value)
struct go7007 *go = i2c_get_adapdata(client->adapter);
struct go7007_usb *usb;
int rc;
- int dev_addr = client->addr;
+ int dev_addr = client->addr << 1; /* firmware wants 8-bit address */
u8 *buf;
if (go == NULL)
@@ -667,7 +667,7 @@ static int s2250_remove(struct i2c_client *client)
return 0;
}
-static struct i2c_device_id s2250_id[] = {
+static const struct i2c_device_id s2250_id[] = {
{ "s2250", 0 },
{ }
};
diff --git a/drivers/staging/go7007/s2250-loader.c b/drivers/staging/go7007/s2250-loader.c
index c152ab9be2fb..1de2dfb16d3f 100644
--- a/drivers/staging/go7007/s2250-loader.c
+++ b/drivers/staging/go7007/s2250-loader.c
@@ -139,7 +139,7 @@ failed2:
static void s2250loader_disconnect(struct usb_interface *interface)
{
- pdevice_extension_t s = usb_get_intfdata(interface);
+ pdevice_extension_t s;
printk(KERN_INFO "s2250: disconnect\n");
lock_kernel();
s = usb_get_intfdata(interface);
@@ -148,7 +148,7 @@ static void s2250loader_disconnect(struct usb_interface *interface)
unlock_kernel();
}
-static struct usb_device_id s2250loader_ids[] = {
+static const struct usb_device_id s2250loader_ids[] = {
{USB_DEVICE(0x1943, 0xa250)},
{} /* Terminating entry */
};
diff --git a/drivers/staging/go7007/saa7134-go7007.c b/drivers/staging/go7007/saa7134-go7007.c
index 665bbf59d026..b25d7d2090e1 100644
--- a/drivers/staging/go7007/saa7134-go7007.c
+++ b/drivers/staging/go7007/saa7134-go7007.c
@@ -84,6 +84,7 @@ static struct go7007_board_info board_voyager = {
},
},
};
+MODULE_FIRMWARE("go7007tv.bin");
/********************* Driver for GPIO HPI interface *********************/
diff --git a/drivers/staging/go7007/wis-ov7640.c b/drivers/staging/go7007/wis-ov7640.c
index 04d6d3a498a3..4f0cbdde2765 100644
--- a/drivers/staging/go7007/wis-ov7640.c
+++ b/drivers/staging/go7007/wis-ov7640.c
@@ -77,7 +77,7 @@ static int wis_ov7640_remove(struct i2c_client *client)
return 0;
}
-static struct i2c_device_id wis_ov7640_id[] = {
+static const struct i2c_device_id wis_ov7640_id[] = {
{ "wis_ov7640", 0 },
{ }
};
diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/go7007/wis-saa7113.c
index 9ab893bd204e..d196e16fe72b 100644
--- a/drivers/staging/go7007/wis-saa7113.c
+++ b/drivers/staging/go7007/wis-saa7113.c
@@ -304,7 +304,7 @@ static int wis_saa7113_remove(struct i2c_client *client)
return 0;
}
-static struct i2c_device_id wis_saa7113_id[] = {
+static const struct i2c_device_id wis_saa7113_id[] = {
{ "wis_saa7113", 0 },
{ }
};
diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/go7007/wis-saa7115.c
index 8687ad2de761..0f2b4a0ceccf 100644
--- a/drivers/staging/go7007/wis-saa7115.c
+++ b/drivers/staging/go7007/wis-saa7115.c
@@ -437,7 +437,7 @@ static int wis_saa7115_remove(struct i2c_client *client)
return 0;
}
-static struct i2c_device_id wis_saa7115_id[] = {
+static const struct i2c_device_id wis_saa7115_id[] = {
{ "wis_saa7115", 0 },
{ }
};
diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c
index 086896cec49b..c723e4aa7147 100644
--- a/drivers/staging/go7007/wis-sony-tuner.c
+++ b/drivers/staging/go7007/wis-sony-tuner.c
@@ -688,7 +688,7 @@ static int wis_sony_tuner_remove(struct i2c_client *client)
return 0;
}
-static struct i2c_device_id wis_sony_tuner_id[] = {
+static const struct i2c_device_id wis_sony_tuner_id[] = {
{ "wis_sony_tuner", 0 },
{ }
};
diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/go7007/wis-tw2804.c
index e15794a2a0ae..1983839f554d 100644
--- a/drivers/staging/go7007/wis-tw2804.c
+++ b/drivers/staging/go7007/wis-tw2804.c
@@ -327,7 +327,7 @@ static int wis_tw2804_remove(struct i2c_client *client)
return 0;
}
-static struct i2c_device_id wis_tw2804_id[] = {
+static const struct i2c_device_id wis_tw2804_id[] = {
{ "wis_tw2804", 0 },
{ }
};
diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/go7007/wis-tw9903.c
index 506dca6e942e..f97e2be3c0b5 100644
--- a/drivers/staging/go7007/wis-tw9903.c
+++ b/drivers/staging/go7007/wis-tw9903.c
@@ -309,7 +309,7 @@ static int wis_tw9903_remove(struct i2c_client *client)
return 0;
}
-static struct i2c_device_id wis_tw9903_id[] = {
+static const struct i2c_device_id wis_tw9903_id[] = {
{ "wis_tw9903", 0 },
{ }
};
diff --git a/drivers/staging/go7007/wis-uda1342.c b/drivers/staging/go7007/wis-uda1342.c
index 739c7ae8913f..5c4eb49d7357 100644
--- a/drivers/staging/go7007/wis-uda1342.c
+++ b/drivers/staging/go7007/wis-uda1342.c
@@ -82,7 +82,7 @@ static int wis_uda1342_remove(struct i2c_client *client)
return 0;
}
-static struct i2c_device_id wis_uda1342_id[] = {
+static const struct i2c_device_id wis_uda1342_id[] = {
{ "wis_uda1342", 0 },
{ }
};
diff --git a/drivers/staging/hv/Channel.c b/drivers/staging/hv/Channel.c
index 746370e82115..d46eb145484f 100644
--- a/drivers/staging/hv/Channel.c
+++ b/drivers/staging/hv/Channel.c
@@ -991,9 +991,8 @@ void VmbusChannelOnTimer(unsigned long data)
{
struct vmbus_channel *channel = (struct vmbus_channel *)data;
- if (channel->OnChannelCallback) {
+ if (channel->OnChannelCallback)
channel->OnChannelCallback(channel->ChannelCallbackContext);
- }
}
/**
diff --git a/drivers/staging/hv/Hv.c b/drivers/staging/hv/Hv.c
index c5b6613f2f2f..51149e69f3e8 100644
--- a/drivers/staging/hv/Hv.c
+++ b/drivers/staging/hv/Hv.c
@@ -208,50 +208,51 @@ int HvInit(void)
/* HvQueryHypervisorFeatures(maxLeaf); */
/*
- * Determine if we are running on xenlinux (ie x2v shim) or native
- * linux
+ * We only support running on top of Hyper-V
*/
rdmsrl(HV_X64_MSR_GUEST_OS_ID, gHvContext.GuestId);
- if (gHvContext.GuestId == 0) {
- /* Write our OS info */
- wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
- gHvContext.GuestId = HV_LINUX_GUEST_ID;
+
+ if (gHvContext.GuestId != 0) {
+ DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!",
+ gHvContext.GuestId);
+ goto Cleanup;
}
+ /* Write our OS info */
+ wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
+ gHvContext.GuestId = HV_LINUX_GUEST_ID;
+
/* See if the hypercall page is already set */
rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
- if (gHvContext.GuestId == HV_LINUX_GUEST_ID) {
- /* Allocate the hypercall page memory */
- /* virtAddr = osd_PageAlloc(1); */
- virtAddr = osd_VirtualAllocExec(PAGE_SIZE);
-
- if (!virtAddr) {
- DPRINT_ERR(VMBUS,
- "unable to allocate hypercall page!!");
- goto Cleanup;
- }
- hypercallMsr.Enable = 1;
- /* hypercallMsr.GuestPhysicalAddress =
- * virt_to_phys(virtAddr) >> PAGE_SHIFT; */
- hypercallMsr.GuestPhysicalAddress = vmalloc_to_pfn(virtAddr);
- wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
+ /*
+ * Allocate the hypercall page memory
+ * virtAddr = osd_PageAlloc(1);
+ */
+ virtAddr = osd_VirtualAllocExec(PAGE_SIZE);
- /* Confirm that hypercall page did get setup. */
- hypercallMsr.AsUINT64 = 0;
- rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
- if (!hypercallMsr.Enable) {
- DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
- goto Cleanup;
- }
+ if (!virtAddr) {
+ DPRINT_ERR(VMBUS,
+ "unable to allocate hypercall page!!");
+ goto Cleanup;
+ }
- gHvContext.HypercallPage = virtAddr;
- } else {
- DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!",
- gHvContext.GuestId);
+ hypercallMsr.Enable = 1;
+
+ hypercallMsr.GuestPhysicalAddress = vmalloc_to_pfn(virtAddr);
+ wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
+
+ /* Confirm that hypercall page did get setup. */
+ hypercallMsr.AsUINT64 = 0;
+ rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
+
+ if (!hypercallMsr.Enable) {
+ DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
goto Cleanup;
}
+ gHvContext.HypercallPage = virtAddr;
+
DPRINT_INFO(VMBUS, "Hypercall page VA=%p, PA=0x%0llx",
gHvContext.HypercallPage,
(u64)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT);
@@ -273,8 +274,6 @@ int HvInit(void)
gHvContext.SignalEventParam->FlagNumber = 0;
gHvContext.SignalEventParam->RsvdZ = 0;
- /* DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId()); */
-
DPRINT_EXIT(VMBUS);
return ret;
@@ -311,17 +310,14 @@ void HvCleanup(void)
kfree(gHvContext.SignalEventBuffer);
}
- if (gHvContext.GuestId == HV_LINUX_GUEST_ID) {
- if (gHvContext.HypercallPage) {
- hypercallMsr.AsUINT64 = 0;
- wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
- vfree(gHvContext.HypercallPage);
- gHvContext.HypercallPage = NULL;
- }
+ if (gHvContext.HypercallPage) {
+ hypercallMsr.AsUINT64 = 0;
+ wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
+ vfree(gHvContext.HypercallPage);
+ gHvContext.HypercallPage = NULL;
}
DPRINT_EXIT(VMBUS);
-
}
/**
@@ -386,21 +382,22 @@ u16 HvSignalEvent(void)
* retrieve the initialized message and event pages. Otherwise, we create and
* initialize the message and event pages.
*/
-int HvSynicInit(u32 irqVector)
+void HvSynicInit(void *irqarg)
{
u64 version;
union hv_synic_simp simp;
union hv_synic_siefp siefp;
union hv_synic_sint sharedSint;
union hv_synic_scontrol sctrl;
- u64 guestID;
- int ret = 0;
+
+ u32 irqVector = *((u32 *)(irqarg));
+ int cpu = smp_processor_id();
DPRINT_ENTER(VMBUS);
if (!gHvContext.HypercallPage) {
DPRINT_EXIT(VMBUS);
- return ret;
+ return;
}
/* Check the version */
@@ -408,71 +405,41 @@ int HvSynicInit(u32 irqVector)
DPRINT_INFO(VMBUS, "SynIC version: %llx", version);
- /* TODO: Handle SMP */
- if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID) {
- DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since "
- "it is already set.");
-
- rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
-
- DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx",
- simp.AsUINT64, siefp.AsUINT64);
-
- /*
- * Determine if we are running on xenlinux (ie x2v shim) or
- * native linux
- */
- rdmsrl(HV_X64_MSR_GUEST_OS_ID, guestID);
- if (guestID == HV_LINUX_GUEST_ID) {
- gHvContext.synICMessagePage[0] =
- phys_to_virt(simp.BaseSimpGpa << PAGE_SHIFT);
- gHvContext.synICEventPage[0] =
- phys_to_virt(siefp.BaseSiefpGpa << PAGE_SHIFT);
- } else {
- DPRINT_ERR(VMBUS, "unknown guest id!!");
- goto Cleanup;
- }
- DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p",
- gHvContext.synICMessagePage[0],
- gHvContext.synICEventPage[0]);
- } else {
- gHvContext.synICMessagePage[0] = osd_PageAlloc(1);
- if (gHvContext.synICMessagePage[0] == NULL) {
- DPRINT_ERR(VMBUS,
- "unable to allocate SYNIC message page!!");
- goto Cleanup;
- }
+ gHvContext.synICMessagePage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC);
- gHvContext.synICEventPage[0] = osd_PageAlloc(1);
- if (gHvContext.synICEventPage[0] == NULL) {
- DPRINT_ERR(VMBUS,
- "unable to allocate SYNIC event page!!");
- goto Cleanup;
- }
+ if (gHvContext.synICMessagePage[cpu] == NULL) {
+ DPRINT_ERR(VMBUS,
+ "unable to allocate SYNIC message page!!");
+ goto Cleanup;
+ }
+
+ gHvContext.synICEventPage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC);
+
+ if (gHvContext.synICEventPage[cpu] == NULL) {
+ DPRINT_ERR(VMBUS,
+ "unable to allocate SYNIC event page!!");
+ goto Cleanup;
+ }
- /* Setup the Synic's message page */
- rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- simp.SimpEnabled = 1;
- simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[0])
- >> PAGE_SHIFT;
+ /* Setup the Synic's message page */
+ rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
+ simp.SimpEnabled = 1;
+ simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[cpu])
+ >> PAGE_SHIFT;
- DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx",
- simp.AsUINT64);
+ DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64);
- wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
+ wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- /* Setup the Synic's event page */
- rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
- siefp.SiefpEnabled = 1;
- siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[0])
- >> PAGE_SHIFT;
+ /* Setup the Synic's event page */
+ rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
+ siefp.SiefpEnabled = 1;
+ siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[cpu])
+ >> PAGE_SHIFT;
- DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx",
- siefp.AsUINT64);
+ DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64);
- wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
- }
+ wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
/* Setup the interception SINT. */
/* wrmsrl((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), */
@@ -501,32 +468,28 @@ int HvSynicInit(u32 irqVector)
DPRINT_EXIT(VMBUS);
- return ret;
+ return;
Cleanup:
- ret = -1;
-
- if (gHvContext.GuestId == HV_LINUX_GUEST_ID) {
- if (gHvContext.synICEventPage[0])
- osd_PageFree(gHvContext.synICEventPage[0], 1);
+ if (gHvContext.synICEventPage[cpu])
+ osd_PageFree(gHvContext.synICEventPage[cpu], 1);
- if (gHvContext.synICMessagePage[0])
- osd_PageFree(gHvContext.synICMessagePage[0], 1);
- }
+ if (gHvContext.synICMessagePage[cpu])
+ osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
DPRINT_EXIT(VMBUS);
-
- return ret;
+ return;
}
/**
* HvSynicCleanup - Cleanup routine for HvSynicInit().
*/
-void HvSynicCleanup(void)
+void HvSynicCleanup(void *arg)
{
union hv_synic_sint sharedSint;
union hv_synic_simp simp;
union hv_synic_siefp siefp;
+ int cpu = smp_processor_id();
DPRINT_ENTER(VMBUS);
@@ -539,30 +502,24 @@ void HvSynicCleanup(void)
sharedSint.Masked = 1;
+ /* Need to correctly cleanup in the case of SMP!!! */
/* Disable the interrupt */
wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
- /*
- * Disable and free the resources only if we are running as
- * native linux since in xenlinux, we are sharing the
- * resources with the x2v shim
- */
- if (gHvContext.GuestId == HV_LINUX_GUEST_ID) {
- rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- simp.SimpEnabled = 0;
- simp.BaseSimpGpa = 0;
+ rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
+ simp.SimpEnabled = 0;
+ simp.BaseSimpGpa = 0;
- wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
+ wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
- siefp.SiefpEnabled = 0;
- siefp.BaseSiefpGpa = 0;
+ rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
+ siefp.SiefpEnabled = 0;
+ siefp.BaseSiefpGpa = 0;
- wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
+ wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
- osd_PageFree(gHvContext.synICMessagePage[0], 1);
- osd_PageFree(gHvContext.synICEventPage[0], 1);
- }
+ osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
+ osd_PageFree(gHvContext.synICEventPage[cpu], 1);
DPRINT_EXIT(VMBUS);
}
diff --git a/drivers/staging/hv/Hv.h b/drivers/staging/hv/Hv.h
index 5379e4bfc56e..41f5ebb86e17 100644
--- a/drivers/staging/hv/Hv.h
+++ b/drivers/staging/hv/Hv.h
@@ -41,11 +41,6 @@ enum {
#define HV_PRESENT_BIT 0x80000000
-#define HV_XENLINUX_GUEST_ID_LO 0x00000000
-#define HV_XENLINUX_GUEST_ID_HI 0x0B00B135
-#define HV_XENLINUX_GUEST_ID (((u64)HV_XENLINUX_GUEST_ID_HI << 32) \
- | HV_XENLINUX_GUEST_ID_LO)
-
#define HV_LINUX_GUEST_ID_LO 0x00000000
#define HV_LINUX_GUEST_ID_HI 0xB16B00B5
#define HV_LINUX_GUEST_ID (((u64)HV_LINUX_GUEST_ID_HI << 32) | \
@@ -93,7 +88,7 @@ static const struct hv_guid VMBUS_SERVICE_ID = {
},
};
-#define MAX_NUM_CPUS 1
+#define MAX_NUM_CPUS 32
struct hv_input_signal_event_buffer {
@@ -102,8 +97,9 @@ struct hv_input_signal_event_buffer {
};
struct hv_context {
- /* XenLinux or native Linux. If XenLinux, the hypercall and synic pages
- * has already been initialized */
+ /* We only support running on top of Hyper-V
+ * So at this point this really can only contain the Hyper-V ID
+ */
u64 GuestId;
void *HypercallPage;
@@ -137,8 +133,8 @@ extern u16 HvPostMessage(union hv_connection_id connectionId,
extern u16 HvSignalEvent(void);
-extern int HvSynicInit(u32 irqVector);
+extern void HvSynicInit(void *irqarg);
-extern void HvSynicCleanup(void);
+extern void HvSynicCleanup(void *arg);
#endif /* __HV_H__ */
diff --git a/drivers/staging/hv/NetVscApi.h b/drivers/staging/hv/NetVscApi.h
index 1ce2b74a34a7..95d7a32b12f2 100644
--- a/drivers/staging/hv/NetVscApi.h
+++ b/drivers/staging/hv/NetVscApi.h
@@ -105,8 +105,6 @@ struct netvsc_driver {
void (*OnLinkStatusChanged)(struct hv_device *dev, u32 Status);
/* Specific to this driver */
- int (*OnOpen)(struct hv_device *dev);
- int (*OnClose)(struct hv_device *dev);
int (*OnSend)(struct hv_device *dev, struct hv_netvsc_packet *packet);
void *Context;
@@ -119,5 +117,7 @@ struct netvsc_device_info {
/* Interface */
int NetVscInitialize(struct hv_driver *drv);
+int RndisFilterOnOpen(struct hv_device *Device);
+int RndisFilterOnClose(struct hv_device *Device);
#endif /* _NETVSC_API_H_ */
diff --git a/drivers/staging/hv/RingBuffer.c b/drivers/staging/hv/RingBuffer.c
index f69ae33a91e3..80b8a2c7784f 100644
--- a/drivers/staging/hv/RingBuffer.c
+++ b/drivers/staging/hv/RingBuffer.c
@@ -48,7 +48,7 @@ Description:
static inline void
GetRingBufferAvailBytes(RING_BUFFER_INFO *rbi, u32 *read, u32 *write)
{
- u32 read_loc,write_loc;
+ u32 read_loc, write_loc;
/* Capture the read/write indices before they changed */
read_loc = rbi->RingBuffer->ReadIndex;
@@ -68,7 +68,7 @@ Description:
--*/
static inline u32
-GetNextWriteLocation(RING_BUFFER_INFO* RingInfo)
+GetNextWriteLocation(RING_BUFFER_INFO *RingInfo)
{
u32 next = RingInfo->RingBuffer->WriteIndex;
@@ -87,7 +87,7 @@ Description:
--*/
static inline void
-SetNextWriteLocation(RING_BUFFER_INFO* RingInfo, u32 NextWriteLocation)
+SetNextWriteLocation(RING_BUFFER_INFO *RingInfo, u32 NextWriteLocation)
{
RingInfo->RingBuffer->WriteIndex = NextWriteLocation;
}
@@ -102,7 +102,7 @@ Description:
--*/
static inline u32
-GetNextReadLocation(RING_BUFFER_INFO* RingInfo)
+GetNextReadLocation(RING_BUFFER_INFO *RingInfo)
{
u32 next = RingInfo->RingBuffer->ReadIndex;
@@ -122,7 +122,7 @@ Description:
--*/
static inline u32
-GetNextReadLocationWithOffset(RING_BUFFER_INFO* RingInfo, u32 Offset)
+GetNextReadLocationWithOffset(RING_BUFFER_INFO *RingInfo, u32 Offset)
{
u32 next = RingInfo->RingBuffer->ReadIndex;
@@ -143,7 +143,7 @@ Description:
--*/
static inline void
-SetNextReadLocation(RING_BUFFER_INFO* RingInfo, u32 NextReadLocation)
+SetNextReadLocation(RING_BUFFER_INFO *RingInfo, u32 NextReadLocation)
{
RingInfo->RingBuffer->ReadIndex = NextReadLocation;
}
@@ -159,7 +159,7 @@ Description:
--*/
static inline void *
-GetRingBuffer(RING_BUFFER_INFO* RingInfo)
+GetRingBuffer(RING_BUFFER_INFO *RingInfo)
{
return (void *)RingInfo->RingBuffer->Buffer;
}
@@ -175,7 +175,7 @@ Description:
--*/
static inline u32
-GetRingBufferSize(RING_BUFFER_INFO* RingInfo)
+GetRingBufferSize(RING_BUFFER_INFO *RingInfo)
{
return RingInfo->RingDataSize;
}
@@ -190,9 +190,10 @@ Description:
--*/
static inline u64
-GetRingBufferIndices(RING_BUFFER_INFO* RingInfo)
+GetRingBufferIndices(RING_BUFFER_INFO *RingInfo)
{
- return ((u64)RingInfo->RingBuffer->WriteIndex << 32) || RingInfo->RingBuffer->ReadIndex;
+ return ((u64)RingInfo->RingBuffer->WriteIndex << 32)
+ || RingInfo->RingBuffer->ReadIndex;
}
@@ -210,9 +211,14 @@ void DumpRingInfo(RING_BUFFER_INFO *RingInfo, char *Prefix)
u32 bytesAvailToWrite;
u32 bytesAvailToRead;
- GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
+ GetRingBufferAvailBytes(RingInfo,
+ &bytesAvailToRead,
+ &bytesAvailToWrite);
- DPRINT(VMBUS, DEBUG_RING_LVL, "%s <<ringinfo %p buffer %p avail write %u avail read %u read idx %u write idx %u>>",
+ DPRINT(VMBUS,
+ DEBUG_RING_LVL,
+ "%s <<ringinfo %p buffer %p avail write %u "
+ "avail read %u read idx %u write idx %u>>",
Prefix,
RingInfo,
RingInfo->RingBuffer->Buffer,
@@ -229,13 +235,13 @@ static u32
CopyToRingBuffer(
RING_BUFFER_INFO *RingInfo,
u32 StartWriteOffset,
- void * Src,
+ void *Src,
u32 SrcLen);
static u32
CopyFromRingBuffer(
RING_BUFFER_INFO *RingInfo,
- void * Dest,
+ void *Dest,
u32 DestLen,
u32 StartReadOffset);
@@ -256,15 +262,15 @@ void RingBufferGetDebugInfo(RING_BUFFER_INFO *RingInfo,
u32 bytesAvailToWrite;
u32 bytesAvailToRead;
- if (RingInfo->RingBuffer)
- {
- GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
+ if (RingInfo->RingBuffer) {
+ GetRingBufferAvailBytes(RingInfo,
+ &bytesAvailToRead,
+ &bytesAvailToWrite);
DebugInfo->BytesAvailToRead = bytesAvailToRead;
DebugInfo->BytesAvailToWrite = bytesAvailToWrite;
DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
-
DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
}
}
@@ -299,7 +305,7 @@ int RingBufferInit(RING_BUFFER_INFO *RingInfo, void *Buffer, u32 BufferLen)
memset(RingInfo, 0, sizeof(RING_BUFFER_INFO));
- RingInfo->RingBuffer = (RING_BUFFER*)Buffer;
+ RingInfo->RingBuffer = (RING_BUFFER *)Buffer;
RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0;
RingInfo->RingSize = BufferLen;
@@ -319,7 +325,7 @@ Description:
Cleanup the ring buffer
--*/
-void RingBufferCleanup(RING_BUFFER_INFO* RingInfo)
+void RingBufferCleanup(RING_BUFFER_INFO *RingInfo)
{
}
@@ -335,14 +341,14 @@ Description:
int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo,
struct scatterlist *sglist, u32 sgcount)
{
- int i=0;
+ int i = 0;
u32 byteAvailToWrite;
u32 byteAvailToRead;
- u32 totalBytesToWrite=0;
+ u32 totalBytesToWrite = 0;
struct scatterlist *sg;
volatile u32 nextWriteLocation;
- u64 prevIndices=0;
+ u64 prevIndices = 0;
unsigned long flags;
DPRINT_ENTER(VMBUS);
@@ -356,17 +362,23 @@ int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo,
spin_lock_irqsave(&OutRingInfo->ring_lock, flags);
- GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite);
+ GetRingBufferAvailBytes(OutRingInfo,
+ &byteAvailToRead,
+ &byteAvailToWrite);
DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
/* DumpRingInfo(OutRingInfo, "BEFORE "); */
- /* If there is only room for the packet, assume it is full. Otherwise, the next time around, we think the ring buffer */
+ /* If there is only room for the packet, assume it is full. */
+ /* Otherwise, the next time around, we think the ring buffer */
/* is empty since the read index == write index */
- if (byteAvailToWrite <= totalBytesToWrite)
- {
- DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite);
+ if (byteAvailToWrite <= totalBytesToWrite) {
+ DPRINT_DBG(VMBUS,
+ "No more space left on outbound ring buffer "
+ "(needed %u, avail %u)",
+ totalBytesToWrite,
+ byteAvailToWrite);
spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
@@ -423,17 +435,22 @@ int RingBufferPeek(RING_BUFFER_INFO *InRingInfo, void *Buffer, u32 BufferLen)
{
u32 bytesAvailToWrite;
u32 bytesAvailToRead;
- u32 nextReadLocation=0;
+ u32 nextReadLocation = 0;
unsigned long flags;
spin_lock_irqsave(&InRingInfo->ring_lock, flags);
- GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
+ GetRingBufferAvailBytes(InRingInfo,
+ &bytesAvailToRead,
+ &bytesAvailToWrite);
/* Make sure there is something to read */
- if (bytesAvailToRead < BufferLen )
- {
- /* DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen); */
+ if (bytesAvailToRead < BufferLen) {
+ /* DPRINT_DBG(VMBUS,
+ "got callback but not enough to read "
+ "<avail to read %d read size %d>!!",
+ bytesAvailToRead,
+ BufferLen); */
spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
@@ -444,9 +461,9 @@ int RingBufferPeek(RING_BUFFER_INFO *InRingInfo, void *Buffer, u32 BufferLen)
nextReadLocation = GetNextReadLocation(InRingInfo);
nextReadLocation = CopyFromRingBuffer(InRingInfo,
- Buffer,
- BufferLen,
- nextReadLocation);
+ Buffer,
+ BufferLen,
+ nextReadLocation);
spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
@@ -468,24 +485,29 @@ int RingBufferRead(RING_BUFFER_INFO *InRingInfo, void *Buffer,
{
u32 bytesAvailToWrite;
u32 bytesAvailToRead;
- u32 nextReadLocation=0;
- u64 prevIndices=0;
+ u32 nextReadLocation = 0;
+ u64 prevIndices = 0;
unsigned long flags;
ASSERT(BufferLen > 0);
spin_lock_irqsave(&InRingInfo->ring_lock, flags);
- GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
+ GetRingBufferAvailBytes(InRingInfo,
+ &bytesAvailToRead,
+ &bytesAvailToWrite);
DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
/* DumpRingInfo(InRingInfo, "BEFORE "); */
/* Make sure there is something to read */
- if (bytesAvailToRead < BufferLen )
- {
- DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen);
+ if (bytesAvailToRead < BufferLen) {
+ DPRINT_DBG(VMBUS,
+ "got callback but not enough to read "
+ "<avail to read %d read size %d>!!",
+ bytesAvailToRead,
+ BufferLen);
spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
@@ -495,17 +517,18 @@ int RingBufferRead(RING_BUFFER_INFO *InRingInfo, void *Buffer,
nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset);
nextReadLocation = CopyFromRingBuffer(InRingInfo,
- Buffer,
- BufferLen,
- nextReadLocation);
+ Buffer,
+ BufferLen,
+ nextReadLocation);
nextReadLocation = CopyFromRingBuffer(InRingInfo,
- &prevIndices,
- sizeof(u64),
- nextReadLocation);
+ &prevIndices,
+ sizeof(u64),
+ nextReadLocation);
/* Make sure all reads are done before we update the read index since */
- /* the writer may start writing to the read area once the read index is updated */
+ /* the writer may start writing to the read area once the read index */
+ /*is updated */
mb();
/* Update the read index */
@@ -533,25 +556,22 @@ static u32
CopyToRingBuffer(
RING_BUFFER_INFO *RingInfo,
u32 StartWriteOffset,
- void * Src,
+ void *Src,
u32 SrcLen)
{
- void * ringBuffer=GetRingBuffer(RingInfo);
- u32 ringBufferSize=GetRingBufferSize(RingInfo);
+ void *ringBuffer = GetRingBuffer(RingInfo);
+ u32 ringBufferSize = GetRingBufferSize(RingInfo);
u32 fragLen;
- if (SrcLen > ringBufferSize - StartWriteOffset) /* wrap-around detected! */
- {
+ /* wrap-around detected! */
+ if (SrcLen > ringBufferSize - StartWriteOffset) {
DPRINT_DBG(VMBUS, "wrap-around detected!");
fragLen = ringBufferSize - StartWriteOffset;
memcpy(ringBuffer + StartWriteOffset, Src, fragLen);
memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen);
- }
- else
- {
+ } else
memcpy(ringBuffer + StartWriteOffset, Src, SrcLen);
- }
StartWriteOffset += SrcLen;
StartWriteOffset %= ringBufferSize;
@@ -573,28 +593,27 @@ Description:
static u32
CopyFromRingBuffer(
RING_BUFFER_INFO *RingInfo,
- void * Dest,
+ void *Dest,
u32 DestLen,
u32 StartReadOffset)
{
- void * ringBuffer=GetRingBuffer(RingInfo);
- u32 ringBufferSize=GetRingBufferSize(RingInfo);
+ void *ringBuffer = GetRingBuffer(RingInfo);
+ u32 ringBufferSize = GetRingBufferSize(RingInfo);
u32 fragLen;
- if (DestLen > ringBufferSize - StartReadOffset) /* wrap-around detected at the src */
- {
+ /* wrap-around detected at the src */
+ if (DestLen > ringBufferSize - StartReadOffset) {
DPRINT_DBG(VMBUS, "src wrap-around detected!");
fragLen = ringBufferSize - StartReadOffset;
memcpy(Dest, ringBuffer + StartReadOffset, fragLen);
memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen);
- }
- else
- {
+ } else
+
memcpy(Dest, ringBuffer + StartReadOffset, DestLen);
- }
+
StartReadOffset += DestLen;
StartReadOffset %= ringBufferSize;
diff --git a/drivers/staging/hv/RndisFilter.c b/drivers/staging/hv/RndisFilter.c
index 26d79975387c..1ab7fa97d373 100644
--- a/drivers/staging/hv/RndisFilter.c
+++ b/drivers/staging/hv/RndisFilter.c
@@ -85,10 +85,6 @@ static int RndisFilterOnDeviceRemove(struct hv_device *Device);
static void RndisFilterOnCleanup(struct hv_driver *Driver);
-static int RndisFilterOnOpen(struct hv_device *Device);
-
-static int RndisFilterOnClose(struct hv_device *Device);
-
static int RndisFilterOnSend(struct hv_device *Device,
struct hv_netvsc_packet *Packet);
@@ -654,8 +650,6 @@ int RndisFilterInit(struct netvsc_driver *Driver)
Driver->Base.OnDeviceRemove = RndisFilterOnDeviceRemove;
Driver->Base.OnCleanup = RndisFilterOnCleanup;
Driver->OnSend = RndisFilterOnSend;
- Driver->OnOpen = RndisFilterOnOpen;
- Driver->OnClose = RndisFilterOnClose;
/* Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; */
Driver->OnReceiveCallback = RndisFilterOnReceive;
@@ -888,7 +882,7 @@ static void RndisFilterOnCleanup(struct hv_driver *Driver)
DPRINT_EXIT(NETVSC);
}
-static int RndisFilterOnOpen(struct hv_device *Device)
+int RndisFilterOnOpen(struct hv_device *Device)
{
int ret;
struct netvsc_device *netDevice = Device->Extension;
@@ -903,7 +897,7 @@ static int RndisFilterOnOpen(struct hv_device *Device)
return ret;
}
-static int RndisFilterOnClose(struct hv_device *Device)
+int RndisFilterOnClose(struct hv_device *Device)
{
int ret;
struct netvsc_device *netDevice = Device->Extension;
diff --git a/drivers/staging/hv/StorVsc.c b/drivers/staging/hv/StorVsc.c
index 2f7c425896f7..38ea1407f222 100644
--- a/drivers/staging/hv/StorVsc.c
+++ b/drivers/staging/hv/StorVsc.c
@@ -625,7 +625,7 @@ static int StorVscOnDeviceRemove(struct hv_device *Device)
return 0;
}
-static int StorVscOnHostReset(struct hv_device *Device)
+int StorVscOnHostReset(struct hv_device *Device)
{
struct storvsc_device *storDevice;
struct storvsc_request_extension *request;
@@ -842,7 +842,6 @@ int StorVscInitialize(struct hv_driver *Driver)
storDriver->Base.OnCleanup = StorVscOnCleanup;
storDriver->OnIORequest = StorVscOnIORequest;
- storDriver->OnHostReset = StorVscOnHostReset;
DPRINT_EXIT(STORVSC);
diff --git a/drivers/staging/hv/StorVscApi.h b/drivers/staging/hv/StorVscApi.h
index 69c14066c479..126a8588edb1 100644
--- a/drivers/staging/hv/StorVscApi.h
+++ b/drivers/staging/hv/StorVscApi.h
@@ -91,13 +91,9 @@ struct storvsc_driver_object {
/* Maximum # of requests in flight per channel/device */
u32 MaxOutstandingRequestsPerChannel;
- /* Set by the caller to allow us to re-enumerate the bus on the host */
- void (*OnHostRescan)(struct hv_device *Device);
-
/* Specific to this driver */
int (*OnIORequest)(struct hv_device *Device,
struct hv_storvsc_request *Request);
- int (*OnHostReset)(struct hv_device *Device);
};
struct storvsc_device_info {
@@ -108,6 +104,7 @@ struct storvsc_device_info {
/* Interface */
int StorVscInitialize(struct hv_driver *driver);
+int StorVscOnHostReset(struct hv_device *Device);
int BlkVscInitialize(struct hv_driver *driver);
#endif /* _STORVSC_API_H_ */
diff --git a/drivers/staging/hv/VersionInfo.h b/drivers/staging/hv/VersionInfo.h
index 9c3641d99ed8..10d7b19a485f 100644
--- a/drivers/staging/hv/VersionInfo.h
+++ b/drivers/staging/hv/VersionInfo.h
@@ -24,8 +24,24 @@
#ifndef __HV_VERSION_INFO
#define __HV_VERSION_INFO
-static const char VersionDate[] = __DATE__;
-static const char VersionTime[] = __TIME__;
-static const char VersionDesc[] = "Version 2.0";
+/*
+ * We use the same version numbering for all Hyper-V modules.
+ *
+ * Definition of versioning is as follows;
+ *
+ * Major Number Changes for these scenarios;
+ * 1. When a new version of Windows Hyper-V
+ * is released.
+ * 2. A Major change has occurred in the
+ * Linux IC's.
+ * (For example the merge for the first time
+ * into the kernel) Every time the Major Number
+ * changes, the Revision number is reset to 0.
+ * Minor Number Changes when new functionality is added
+ * to the Linux IC's that is not a bug fix.
+ *
+ */
+#define HV_DRV_VERSION "3.0"
+
#endif
diff --git a/drivers/staging/hv/Vmbus.c b/drivers/staging/hv/Vmbus.c
index a4dd06f6d459..3d0a240ed664 100644
--- a/drivers/staging/hv/Vmbus.c
+++ b/drivers/staging/hv/Vmbus.c
@@ -129,7 +129,7 @@ static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo)
/* strcpy(dev->name, "vmbus"); */
/* SynIC setup... */
- ret = HvSynicInit(*irqvector);
+ on_each_cpu(HvSynicInit, (void *)irqvector, 1);
/* Connect to VMBus in the root partition */
ret = VmbusConnect();
@@ -150,7 +150,7 @@ static int VmbusOnDeviceRemove(struct hv_device *dev)
DPRINT_ENTER(VMBUS);
VmbusChannelReleaseUnattachedChannels();
VmbusDisconnect();
- HvSynicCleanup();
+ on_each_cpu(HvSynicCleanup, NULL, 1);
DPRINT_EXIT(VMBUS);
return ret;
@@ -173,7 +173,8 @@ static void VmbusOnCleanup(struct hv_driver *drv)
*/
static void VmbusOnMsgDPC(struct hv_driver *drv)
{
- void *page_addr = gHvContext.synICMessagePage[0];
+ int cpu = smp_processor_id();
+ void *page_addr = gHvContext.synICMessagePage[cpu];
struct hv_message *msg = (struct hv_message *)page_addr +
VMBUS_MESSAGE_SINT;
struct hv_message *copied;
@@ -230,11 +231,12 @@ static void VmbusOnEventDPC(struct hv_driver *drv)
static int VmbusOnISR(struct hv_driver *drv)
{
int ret = 0;
+ int cpu = smp_processor_id();
void *page_addr;
struct hv_message *msg;
union hv_synic_event_flags *event;
- page_addr = gHvContext.synICMessagePage[0];
+ page_addr = gHvContext.synICMessagePage[cpu];
msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
DPRINT_ENTER(VMBUS);
@@ -248,7 +250,7 @@ static int VmbusOnISR(struct hv_driver *drv)
}
/* TODO: Check if there are events to be process */
- page_addr = gHvContext.synICEventPage[0];
+ page_addr = gHvContext.synICEventPage[cpu];
event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
/* Since we are a child, we only need to check bit 0 */
@@ -271,10 +273,8 @@ int VmbusInitialize(struct hv_driver *drv)
DPRINT_ENTER(VMBUS);
- DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++",
- VersionDate, VersionTime);
- DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++",
- VersionDesc);
+ DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++",
+ HV_DRV_VERSION);
DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++",
VMBUS_REVISION_NUMBER);
DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++",
diff --git a/drivers/staging/hv/blkvsc_drv.c b/drivers/staging/hv/blkvsc_drv.c
index 62b282844a53..abeac12c093d 100644
--- a/drivers/staging/hv/blkvsc_drv.c
+++ b/drivers/staging/hv/blkvsc_drv.c
@@ -31,6 +31,7 @@
#include <scsi/scsi_dbg.h>
#include "osd.h"
#include "logging.h"
+#include "VersionInfo.h"
#include "vmbus.h"
#include "StorVscApi.h"
@@ -92,7 +93,7 @@ struct blkvsc_request {
/* Per device structure */
struct block_device_context {
/* point back to our device context */
- struct device_context *device_ctx;
+ struct vm_device *device_ctx;
struct kmem_cache *request_pool;
spinlock_t lock;
struct gendisk *gd;
@@ -254,7 +255,7 @@ static int blkvsc_probe(struct device *device)
(struct blkvsc_driver_context *)driver_ctx;
struct storvsc_driver_object *storvsc_drv_obj =
&blkvsc_drv_ctx->drv_obj;
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
struct hv_device *device_obj = &device_ctx->device_obj;
struct block_device_context *blkdev = NULL;
@@ -363,10 +364,7 @@ static int blkvsc_probe(struct device *device)
blkdev->gd->queue = blk_init_queue(blkvsc_request, &blkdev->lock);
blk_queue_max_segment_size(blkdev->gd->queue, PAGE_SIZE);
- blk_queue_max_phys_segments(blkdev->gd->queue,
- MAX_MULTIPAGE_BUFFER_COUNT);
- blk_queue_max_hw_segments(blkdev->gd->queue,
- MAX_MULTIPAGE_BUFFER_COUNT);
+ blk_queue_max_segments(blkdev->gd->queue, MAX_MULTIPAGE_BUFFER_COUNT);
blk_queue_segment_boundary(blkdev->gd->queue, PAGE_SIZE-1);
blk_queue_bounce_limit(blkdev->gd->queue, BLK_BOUNCE_ANY);
blk_queue_dma_alignment(blkdev->gd->queue, 511);
@@ -745,7 +743,7 @@ static int blkvsc_remove(struct device *device)
(struct blkvsc_driver_context *)driver_ctx;
struct storvsc_driver_object *storvsc_drv_obj =
&blkvsc_drv_ctx->drv_obj;
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
struct hv_device *device_obj = &device_ctx->device_obj;
struct block_device_context *blkdev = dev_get_drvdata(device);
unsigned long flags;
@@ -865,7 +863,7 @@ static int blkvsc_submit_request(struct blkvsc_request *blkvsc_req,
void (*request_completion)(struct hv_storvsc_request *))
{
struct block_device_context *blkdev = blkvsc_req->dev;
- struct device_context *device_ctx = blkdev->device_ctx;
+ struct vm_device *device_ctx = blkdev->device_ctx;
struct driver_context *driver_ctx =
driver_to_driver_context(device_ctx->device.driver);
struct blkvsc_driver_context *blkvsc_drv_ctx =
@@ -1507,6 +1505,7 @@ static void __exit blkvsc_exit(void)
}
MODULE_LICENSE("GPL");
+MODULE_VERSION(HV_DRV_VERSION);
module_param(blkvsc_ringbuffer_size, int, S_IRUGO);
module_init(blkvsc_init);
module_exit(blkvsc_exit);
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c
index 0d7459e2d036..1af3dcbafd65 100644
--- a/drivers/staging/hv/netvsc_drv.c
+++ b/drivers/staging/hv/netvsc_drv.c
@@ -35,14 +35,13 @@
#include <net/pkt_sched.h>
#include "osd.h"
#include "logging.h"
+#include "VersionInfo.h"
#include "vmbus.h"
#include "NetVscApi.h"
-MODULE_LICENSE("GPL");
-
struct net_device_context {
/* point back to our device context */
- struct device_context *device_ctx;
+ struct vm_device *device_ctx;
struct net_device_stats stats;
};
@@ -72,11 +71,6 @@ static void netvsc_set_multicast_list(struct net_device *net)
static int netvsc_open(struct net_device *net)
{
struct net_device_context *net_device_ctx = netdev_priv(net);
- struct driver_context *driver_ctx =
- driver_to_driver_context(net_device_ctx->device_ctx->device.driver);
- struct netvsc_driver_context *net_drv_ctx =
- (struct netvsc_driver_context *)driver_ctx;
- struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj;
int ret = 0;
@@ -87,7 +81,7 @@ static int netvsc_open(struct net_device *net)
sizeof(struct net_device_stats));
/* Open up the device */
- ret = net_drv_obj->OnOpen(device_obj);
+ ret = RndisFilterOnOpen(device_obj);
if (ret != 0) {
DPRINT_ERR(NETVSC_DRV,
"unable to open device (ret %d).", ret);
@@ -106,11 +100,6 @@ static int netvsc_open(struct net_device *net)
static int netvsc_close(struct net_device *net)
{
struct net_device_context *net_device_ctx = netdev_priv(net);
- struct driver_context *driver_ctx =
- driver_to_driver_context(net_device_ctx->device_ctx->device.driver);
- struct netvsc_driver_context *net_drv_ctx =
- (struct netvsc_driver_context *)driver_ctx;
- struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj;
int ret;
@@ -118,7 +107,7 @@ static int netvsc_close(struct net_device *net)
netif_stop_queue(net);
- ret = net_drv_obj->OnClose(device_obj);
+ ret = RndisFilterOnClose(device_obj);
if (ret != 0)
DPRINT_ERR(NETVSC_DRV, "unable to close device (ret %d).", ret);
@@ -282,7 +271,7 @@ retry_send:
static void netvsc_linkstatus_callback(struct hv_device *device_obj,
unsigned int status)
{
- struct device_context *device_ctx = to_device_context(device_obj);
+ struct vm_device *device_ctx = to_vm_device(device_obj);
struct net_device *net = dev_get_drvdata(&device_ctx->device);
DPRINT_ENTER(NETVSC_DRV);
@@ -309,7 +298,7 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj,
static int netvsc_recv_callback(struct hv_device *device_obj,
struct hv_netvsc_packet *packet)
{
- struct device_context *device_ctx = to_device_context(device_obj);
+ struct vm_device *device_ctx = to_vm_device(device_obj);
struct net_device *net = dev_get_drvdata(&device_ctx->device);
struct net_device_context *net_device_ctx;
struct sk_buff *skb;
@@ -401,7 +390,7 @@ static int netvsc_probe(struct device *device)
struct netvsc_driver_context *net_drv_ctx =
(struct netvsc_driver_context *)driver_ctx;
struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
struct hv_device *device_obj = &device_ctx->device_obj;
struct net_device *net = NULL;
struct net_device_context *net_device_ctx;
@@ -473,7 +462,7 @@ static int netvsc_remove(struct device *device)
struct netvsc_driver_context *net_drv_ctx =
(struct netvsc_driver_context *)driver_ctx;
struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
struct net_device *net = dev_get_drvdata(&device_ctx->device);
struct hv_device *device_obj = &device_ctx->device_obj;
int ret;
@@ -613,6 +602,8 @@ static void __exit netvsc_exit(void)
DPRINT_EXIT(NETVSC_DRV);
}
+MODULE_LICENSE("GPL");
+MODULE_VERSION(HV_DRV_VERSION);
module_param(netvsc_ringbuffer_size, int, S_IRUGO);
module_init(netvsc_init);
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index d49dc21d4cb4..3988f4bec1ce 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -32,6 +32,7 @@
#include <scsi/scsi_dbg.h>
#include "osd.h"
#include "logging.h"
+#include "VersionInfo.h"
#include "vmbus.h"
#include "StorVscApi.h"
@@ -39,10 +40,8 @@
struct host_device_context {
/* must be 1st field
* FIXME this is a bug */
- struct work_struct host_rescan_work;
-
/* point back to our device context */
- struct device_context *device_ctx;
+ struct vm_device *device_ctx;
struct kmem_cache *request_pool;
unsigned int port;
unsigned char path;
@@ -77,8 +76,6 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
static int storvsc_device_alloc(struct scsi_device *);
static int storvsc_device_configure(struct scsi_device *);
static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd);
-static void storvsc_host_rescan_callback(struct work_struct *work);
-static void storvsc_host_rescan(struct hv_device *device_obj);
static int storvsc_remove(struct device *dev);
static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
@@ -94,8 +91,6 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
struct scatterlist *bounce_sgl,
unsigned int orig_sgl_count);
-static int storvsc_report_luns(struct scsi_device *sdev, unsigned int luns[],
- unsigned int *lun_count);
static int storvsc_get_chs(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int *info);
@@ -148,7 +143,6 @@ static int storvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
vmbus_get_interface(&storvsc_drv_obj->Base.VmbusChannelInterface);
storvsc_drv_obj->RingBufferSize = storvsc_ringbuffer_size;
- storvsc_drv_obj->OnHostRescan = storvsc_host_rescan;
/* Callback to client driver to complete the initialization */
drv_init(&storvsc_drv_obj->Base);
@@ -240,7 +234,7 @@ static int storvsc_probe(struct device *device)
(struct storvsc_driver_context *)driver_ctx;
struct storvsc_driver_object *storvsc_drv_obj =
&storvsc_drv_ctx->drv_obj;
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
struct hv_device *device_obj = &device_ctx->device_obj;
struct Scsi_Host *host;
struct host_device_context *host_device_ctx;
@@ -266,9 +260,6 @@ static int storvsc_probe(struct device *device)
host_device_ctx->port = host->host_no;
host_device_ctx->device_ctx = device_ctx;
- INIT_WORK(&host_device_ctx->host_rescan_work,
- storvsc_host_rescan_callback);
-
host_device_ctx->request_pool =
kmem_cache_create(dev_name(&device_ctx->device),
sizeof(struct storvsc_cmd_request) +
@@ -339,7 +330,7 @@ static int storvsc_remove(struct device *device)
(struct storvsc_driver_context *)driver_ctx;
struct storvsc_driver_object *storvsc_drv_obj =
&storvsc_drv_ctx->drv_obj;
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
struct hv_device *device_obj = &device_ctx->device_obj;
struct Scsi_Host *host = dev_get_drvdata(device);
struct host_device_context *host_device_ctx =
@@ -640,7 +631,7 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
int ret;
struct host_device_context *host_device_ctx =
(struct host_device_context *)scmnd->device->host->hostdata;
- struct device_context *device_ctx = host_device_ctx->device_ctx;
+ struct vm_device *device_ctx = host_device_ctx->device_ctx;
struct driver_context *driver_ctx =
driver_to_driver_context(device_ctx->device.driver);
struct storvsc_driver_context *storvsc_drv_ctx =
@@ -879,14 +870,7 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
int ret;
struct host_device_context *host_device_ctx =
(struct host_device_context *)scmnd->device->host->hostdata;
- struct device_context *device_ctx = host_device_ctx->device_ctx;
- struct driver_context *driver_ctx =
- driver_to_driver_context(device_ctx->device.driver);
- struct storvsc_driver_context *storvsc_drv_ctx =
- (struct storvsc_driver_context *)driver_ctx;
-
- struct storvsc_driver_object *storvsc_drv_obj =
- &storvsc_drv_ctx->drv_obj;
+ struct vm_device *device_ctx = host_device_ctx->device_ctx;
DPRINT_ENTER(STORVSC_DRV);
@@ -894,8 +878,7 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
scmnd->device, &device_ctx->device_obj);
/* Invokes the vsc to reset the host/bus */
- ASSERT(storvsc_drv_obj->OnHostReset);
- ret = storvsc_drv_obj->OnHostReset(&device_ctx->device_obj);
+ ret = StorVscOnHostReset(&device_ctx->device_obj);
if (ret != 0) {
DPRINT_EXIT(STORVSC_DRV);
return ret;
@@ -909,201 +892,6 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
return ret;
}
-/**
- * storvsc_host_rescan - Rescan the scsi HBA
- */
-static void storvsc_host_rescan_callback(struct work_struct *work)
-{
- struct hv_device *device_obj =
- &((struct host_device_context *)work)->device_ctx->device_obj;
- struct device_context *device_ctx = to_device_context(device_obj);
- struct Scsi_Host *host = dev_get_drvdata(&device_ctx->device);
- struct scsi_device *sdev;
- struct host_device_context *host_device_ctx;
- struct scsi_device **sdevs_remove_list;
- unsigned int sdevs_count = 0;
- unsigned int found;
- unsigned int i;
- unsigned int lun_count = 0;
- unsigned int *lun_list;
-
- DPRINT_ENTER(STORVSC_DRV);
-
- host_device_ctx = (struct host_device_context *)host->hostdata;
- lun_list = kcalloc(STORVSC_MAX_LUNS_PER_TARGET, sizeof(unsigned int),
- GFP_ATOMIC);
- if (!lun_list) {
- DPRINT_ERR(STORVSC_DRV, "unable to allocate lun list");
- return;
- }
-
- sdevs_remove_list = kcalloc(STORVSC_MAX_LUNS_PER_TARGET,
- sizeof(void *), GFP_ATOMIC);
- if (!sdevs_remove_list) {
- kfree(lun_list);
- DPRINT_ERR(STORVSC_DRV, "unable to allocate lun remove list");
- return;
- }
-
- DPRINT_INFO(STORVSC_DRV, "rescanning host for new scsi devices...");
-
- /* Rescan for new device */
- scsi_scan_target(&host->shost_gendev, host_device_ctx->path,
- host_device_ctx->target, SCAN_WILD_CARD, 1);
-
- DPRINT_INFO(STORVSC_DRV, "rescanning host for removed scsi device...");
-
- /* Use the 1st device to send the report luns cmd */
- shost_for_each_device(sdev, host) {
- lun_count = STORVSC_MAX_LUNS_PER_TARGET;
- storvsc_report_luns(sdev, lun_list, &lun_count);
-
- DPRINT_INFO(STORVSC_DRV,
- "report luns on scsi device (%p) found %u luns ",
- sdev, lun_count);
- DPRINT_INFO(STORVSC_DRV,
- "existing luns on scsi device (%p) host (%d)",
- sdev, host->host_no);
-
- scsi_device_put(sdev);
- break;
- }
-
- for (i = 0; i < lun_count; i++)
- DPRINT_INFO(STORVSC_DRV, "%d) lun %u", i, lun_list[i]);
-
- /* Rescan for devices that may have been removed.
- * We do not have to worry that new devices may have been added since
- * this callback is serialized by the workqueue ie add/remove are done
- * here.
- */
- shost_for_each_device(sdev, host) {
- /* See if this device is still here */
- found = 0;
- for (i = 0; i < lun_count; i++) {
- if (sdev->lun == lun_list[i]) {
- found = 1;
- break;
- }
- }
- if (!found) {
- DPRINT_INFO(STORVSC_DRV, "lun (%u) does not exists",
- sdev->lun);
- sdevs_remove_list[sdevs_count++] = sdev;
- }
- }
-
- /* Now remove the devices */
- for (i = 0; i < sdevs_count; i++) {
- DPRINT_INFO(STORVSC_DRV,
- "removing scsi device (%p) lun (%u)...",
- sdevs_remove_list[i], sdevs_remove_list[i]->lun);
-
- /* make sure it is not removed from underneath us */
- if (!scsi_device_get(sdevs_remove_list[i])) {
- scsi_remove_device(sdevs_remove_list[i]);
- scsi_device_put(sdevs_remove_list[i]);
- }
- }
-
- DPRINT_INFO(STORVSC_DRV, "rescan completed on dev obj (%p) "
- "target (%u) bus (%u)", device_obj,
- host_device_ctx->target, host_device_ctx->path);
-
- kfree(lun_list);
- kfree(sdevs_remove_list);
-
- DPRINT_EXIT(STORVSC_DRV);
-}
-
-static int storvsc_report_luns(struct scsi_device *sdev, unsigned int luns[],
- unsigned int *lun_count)
-{
- int i, j;
- unsigned int lun = 0;
- unsigned int num_luns;
- int result;
- unsigned char *data;
- struct scsi_sense_hdr sshdr;
- unsigned char cmd[16] = {0};
- /* Add 1 to cover the report_lun header */
- unsigned int report_len = 8 * (STORVSC_MAX_LUNS_PER_TARGET+1);
- unsigned long long *report_luns;
- const unsigned int in_lun_count = *lun_count;
-
- *lun_count = 0;
-
- report_luns = kzalloc(report_len, GFP_ATOMIC);
- if (!report_luns)
- return -ENOMEM;
-
- cmd[0] = REPORT_LUNS;
-
- /* cmd length */
- *(unsigned int *)&cmd[6] = cpu_to_be32(report_len);
-
- result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE,
- (unsigned char *)report_luns, report_len,
- &sshdr, 30 * HZ, 3, NULL);
- if (result != 0) {
- kfree(report_luns);
- return -EBUSY;
- }
-
- /* get the length from the first four bytes */
- report_len = be32_to_cpu(*(unsigned int *)&report_luns[0]);
-
- num_luns = (report_len / sizeof(unsigned long long));
- if (num_luns > in_lun_count) {
- kfree(report_luns);
- return -EINVAL;
- }
-
- *lun_count = num_luns;
-
- DPRINT_DBG(STORVSC_DRV,
- "report luns on scsi device (%p) found %u luns ",
- sdev, num_luns);
-
- /* lun id starts at 1 */
- for (i = 1; i < num_luns + 1; i++) {
- lun = 0;
- data = (unsigned char *)&report_luns[i];
- for (j = 0; j < sizeof(lun); j += 2) {
- lun = lun | (((data[j] << 8) | data[j + 1]) <<
- (j * 8));
- }
-
- luns[i-1] = lun;
- }
-
- kfree(report_luns);
- return 0;
-}
-
-static void storvsc_host_rescan(struct hv_device *device_obj)
-{
- struct device_context *device_ctx = to_device_context(device_obj);
- struct Scsi_Host *host = dev_get_drvdata(&device_ctx->device);
- struct host_device_context *host_device_ctx;
-
- DPRINT_ENTER(STORVSC_DRV);
-
- host_device_ctx = (struct host_device_context *)host->hostdata;
-
- DPRINT_INFO(STORVSC_DRV, "initiating rescan on dev obj (%p) "
- "target (%u) bus (%u)...", device_obj,
- host_device_ctx->target, host_device_ctx->path);
-
- /*
- * We need to queue this since the scanning may block and the caller
- * may be in an intr context
- */
- /* scsi_queue_work(host, &host_device_ctx->host_rescan_work); */
- schedule_work(&host_device_ctx->host_rescan_work);
- DPRINT_EXIT(STORVSC_DRV);
-}
-
static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev,
sector_t capacity, int *info)
{
@@ -1203,6 +991,7 @@ static void __exit storvsc_exit(void)
}
MODULE_LICENSE("GPL");
+MODULE_VERSION(HV_DRV_VERSION);
module_param(storvsc_ringbuffer_size, int, S_IRUGO);
module_init(storvsc_init);
module_exit(storvsc_exit);
diff --git a/drivers/staging/hv/vmbus.h b/drivers/staging/hv/vmbus.h
index ae0a896eb392..6404b8424bef 100644
--- a/drivers/staging/hv/vmbus.h
+++ b/drivers/staging/hv/vmbus.h
@@ -43,23 +43,23 @@ struct driver_context {
void (*shutdown)(struct device *);
};
-struct device_context {
+struct vm_device {
struct work_struct probe_failed_work_item;
struct hv_guid class_id;
struct hv_guid device_id;
int probe_error;
- struct device device;
struct hv_device device_obj;
+ struct device device;
};
-static inline struct device_context *to_device_context(struct hv_device *d)
+static inline struct vm_device *to_vm_device(struct hv_device *d)
{
- return container_of(d, struct device_context, device_obj);
+ return container_of(d, struct vm_device, device_obj);
}
-static inline struct device_context *device_to_device_context(struct device *d)
+static inline struct vm_device *device_to_vm_device(struct device *d)
{
- return container_of(d, struct device_context, device);
+ return container_of(d, struct vm_device, device);
}
static inline struct driver_context *driver_to_driver_context(struct device_driver *d)
diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c
index 894eecfc63ca..2c906195b9c8 100644
--- a/drivers/staging/hv/vmbus_drv.c
+++ b/drivers/staging/hv/vmbus_drv.c
@@ -24,6 +24,9 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/sysctl.h>
+#include <linux/pci.h>
+#include <linux/dmi.h>
+#include "VersionInfo.h"
#include "osd.h"
#include "logging.h"
#include "vmbus.h"
@@ -47,7 +50,7 @@ struct vmbus_driver_context {
struct tasklet_struct event_dpc;
/* The bus root device */
- struct device_context device_ctx;
+ struct vm_device device_ctx;
};
static int vmbus_match(struct device *device, struct device_driver *driver);
@@ -135,7 +138,7 @@ static ssize_t vmbus_show_device_attr(struct device *dev,
struct device_attribute *dev_attr,
char *buf)
{
- struct device_context *device_ctx = device_to_device_context(dev);
+ struct vm_device *device_ctx = device_to_vm_device(dev);
struct hv_device_info device_info;
memset(&device_info, 0, sizeof(struct hv_device_info));
@@ -245,7 +248,7 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv))
{
struct vmbus_driver_context *vmbus_drv_ctx = &g_vmbus_drv;
struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
- struct device_context *dev_ctx = &g_vmbus_drv.device_ctx;
+ struct vm_device *dev_ctx = &g_vmbus_drv.device_ctx;
int ret;
unsigned int vector;
@@ -307,7 +310,7 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv))
DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector);
/* Call to bus driver to add the root device */
- memset(dev_ctx, 0, sizeof(struct device_context));
+ memset(dev_ctx, 0, sizeof(struct vm_device));
ret = vmbus_drv_obj->Base.OnDeviceAdd(&dev_ctx->device_obj, &vector);
if (ret != 0) {
@@ -368,7 +371,7 @@ static void vmbus_bus_exit(void)
struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
struct vmbus_driver_context *vmbus_drv_ctx = &g_vmbus_drv;
- struct device_context *dev_ctx = &g_vmbus_drv.device_ctx;
+ struct vm_device *dev_ctx = &g_vmbus_drv.device_ctx;
DPRINT_ENTER(VMBUS_DRV);
@@ -471,13 +474,13 @@ static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
struct hv_guid *instance,
void *context)
{
- struct device_context *child_device_ctx;
+ struct vm_device *child_device_ctx;
struct hv_device *child_device_obj;
DPRINT_ENTER(VMBUS_DRV);
/* Allocate the new child device */
- child_device_ctx = kzalloc(sizeof(struct device_context), GFP_KERNEL);
+ child_device_ctx = kzalloc(sizeof(struct vm_device), GFP_KERNEL);
if (!child_device_ctx) {
DPRINT_ERR(VMBUS_DRV,
"unable to allocate device_context for child device");
@@ -526,10 +529,10 @@ static int vmbus_child_device_register(struct hv_device *root_device_obj,
struct hv_device *child_device_obj)
{
int ret = 0;
- struct device_context *root_device_ctx =
- to_device_context(root_device_obj);
- struct device_context *child_device_ctx =
- to_device_context(child_device_obj);
+ struct vm_device *root_device_ctx =
+ to_vm_device(root_device_obj);
+ struct vm_device *child_device_ctx =
+ to_vm_device(child_device_obj);
static atomic_t device_num = ATOMIC_INIT(0);
DPRINT_ENTER(VMBUS_DRV);
@@ -572,7 +575,7 @@ static int vmbus_child_device_register(struct hv_device *root_device_obj,
*/
static void vmbus_child_device_unregister(struct hv_device *device_obj)
{
- struct device_context *device_ctx = to_device_context(device_obj);
+ struct vm_device *device_ctx = to_vm_device(device_obj);
DPRINT_ENTER(VMBUS_DRV);
@@ -610,7 +613,7 @@ static void vmbus_child_device_destroy(struct hv_device *device_obj)
*/
static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
{
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
int ret;
DPRINT_ENTER(VMBUS_DRV);
@@ -687,7 +690,7 @@ static int vmbus_match(struct device *device, struct device_driver *driver)
{
int match = 0;
struct driver_context *driver_ctx = driver_to_driver_context(driver);
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
DPRINT_ENTER(VMBUS_DRV);
@@ -724,7 +727,7 @@ static int vmbus_match(struct device *device, struct device_driver *driver)
*/
static void vmbus_probe_failed_cb(struct work_struct *context)
{
- struct device_context *device_ctx = (struct device_context *)context;
+ struct vm_device *device_ctx = (struct vm_device *)context;
DPRINT_ENTER(VMBUS_DRV);
@@ -746,8 +749,8 @@ static int vmbus_probe(struct device *child_device)
int ret = 0;
struct driver_context *driver_ctx =
driver_to_driver_context(child_device->driver);
- struct device_context *device_ctx =
- device_to_device_context(child_device);
+ struct vm_device *device_ctx =
+ device_to_vm_device(child_device);
DPRINT_ENTER(VMBUS_DRV);
@@ -871,7 +874,7 @@ static void vmbus_bus_release(struct device *device)
*/
static void vmbus_device_release(struct device *device)
{
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
DPRINT_ENTER(VMBUS_DRV);
@@ -946,6 +949,19 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
}
}
+static struct dmi_system_id __initdata microsoft_hv_dmi_table[] = {
+ {
+ .ident = "Hyper-V",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+ DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
+ },
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(dmi, microsoft_hv_dmi_table);
+
static int __init vmbus_init(void)
{
int ret = 0;
@@ -957,6 +973,9 @@ static int __init vmbus_init(void)
vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel));
/* Todo: it is used for loglevel, to be ported to new kernel. */
+ if (!dmi_check_system(microsoft_hv_dmi_table))
+ return -ENODEV;
+
ret = vmbus_bus_init(VmbusInitialize);
DPRINT_EXIT(VMBUS_DRV);
@@ -973,7 +992,20 @@ static void __exit vmbus_exit(void)
return;
}
+/*
+ * We use a PCI table to determine if we should autoload this driver This is
+ * needed by distro tools to determine if the hyperv drivers should be
+ * installed and/or configured. We don't do anything else with the table, but
+ * it needs to be present.
+ */
+const static struct pci_device_id microsoft_hv_pci_table[] = {
+ { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, microsoft_hv_pci_table);
+
MODULE_LICENSE("GPL");
+MODULE_VERSION(HV_DRV_VERSION);
module_param(vmbus_irq, int, S_IRUGO);
module_param(vmbus_loglevel, int, S_IRUGO);
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c
index 768f44894d08..b456dfc8fe27 100644
--- a/drivers/staging/iio/industrialio-core.c
+++ b/drivers/staging/iio/industrialio-core.c
@@ -79,11 +79,14 @@ EXPORT_SYMBOL(__iio_change_event);
/* Does anyone care? */
mutex_lock(&ev_int->event_list_lock);
if (test_bit(IIO_BUSY_BIT_POS, &ev_int->handler.flags)) {
- if (ev_int->current_events == ev_int->max_events)
+ if (ev_int->current_events == ev_int->max_events) {
+ mutex_unlock(&ev_int->event_list_lock);
return 0;
+ }
ev = kmalloc(sizeof(*ev), GFP_KERNEL);
if (ev == NULL) {
ret = -ENOMEM;
+ mutex_unlock(&ev_int->event_list_lock);
goto error_ret;
}
ev->ev.id = ev_code;
@@ -115,7 +118,7 @@ int iio_push_event(struct iio_dev *dev_info,
EXPORT_SYMBOL(iio_push_event);
/* Generic interrupt line interrupt handler */
-irqreturn_t iio_interrupt_handler(int irq, void *_int_info)
+static irqreturn_t iio_interrupt_handler(int irq, void *_int_info)
{
struct iio_interrupt *int_info = _int_info;
struct iio_dev *dev_info = int_info->dev_info;
@@ -249,10 +252,10 @@ void iio_remove_event_from_list(struct iio_event_handler_list *el,
}
EXPORT_SYMBOL(iio_remove_event_from_list);
-ssize_t iio_event_chrdev_read(struct file *filep,
- char *buf,
- size_t count,
- loff_t *f_ps)
+static ssize_t iio_event_chrdev_read(struct file *filep,
+ char __user *buf,
+ size_t count,
+ loff_t *f_ps)
{
struct iio_event_interface *ev_int = filep->private_data;
struct iio_detected_event_list *el;
@@ -289,16 +292,16 @@ ssize_t iio_event_chrdev_read(struct file *filep,
mutex_unlock(&ev_int->event_list_lock);
/*
* Possible concurency issue if an update of this event is on its way
- * through. May lead to new even being removed whilst the reported event
- * was the unescalated event. In typical use case this is not a problem
- * as userspace will say read half the buffer due to a 50% full event
- * which would make the correct 100% full incorrect anyway.
+ * through. May lead to new event being removed whilst the reported
+ * event was the unescalated event. In typical use case this is not a
+ * problem as userspace will say read half the buffer due to a 50%
+ * full event which would make the correct 100% full incorrect anyway.
*/
- spin_lock(&el->shared_pointer->lock);
- if (el->shared_pointer)
+ if (el->shared_pointer) {
+ spin_lock(&el->shared_pointer->lock);
(el->shared_pointer->ev_p) = NULL;
- spin_unlock(&el->shared_pointer->lock);
-
+ spin_unlock(&el->shared_pointer->lock);
+ }
kfree(el);
return len;
@@ -310,7 +313,7 @@ error_ret:
return ret;
}
-int iio_event_chrdev_release(struct inode *inode, struct file *filep)
+static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
{
struct iio_handler *hand = iio_cdev_to_handler(inode->i_cdev);
struct iio_event_interface *ev_int = hand->private;
@@ -332,7 +335,7 @@ int iio_event_chrdev_release(struct inode *inode, struct file *filep)
return 0;
}
-int iio_event_chrdev_open(struct inode *inode, struct file *filep)
+static int iio_event_chrdev_open(struct inode *inode, struct file *filep)
{
struct iio_handler *hand = iio_cdev_to_handler(inode->i_cdev);
struct iio_event_interface *ev_int = hand->private;
diff --git a/drivers/staging/iio/ring_generic.h b/drivers/staging/iio/ring_generic.h
index 93b91b28a02f..09044adf7327 100644
--- a/drivers/staging/iio/ring_generic.h
+++ b/drivers/staging/iio/ring_generic.h
@@ -146,8 +146,7 @@ static inline void __iio_init_ring_buffer(struct iio_ring_buffer *ring,
ring->length = length;
ring->loopcount = 0;
ring->shared_ev_pointer.ev_p = 0;
- ring->shared_ev_pointer.lock =
- __SPIN_LOCK_UNLOCKED(ring->shared_ev_pointer->loc);
+ spin_lock_init(&ring->shared_ev_pointer.lock);
}
/**
diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c
index 359ff9208f36..6f7f4d5a93f3 100644
--- a/drivers/staging/iio/ring_sw.c
+++ b/drivers/staging/iio/ring_sw.c
@@ -8,7 +8,6 @@
*/
#include <linux/kernel.h>
-#include <linux/device.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/workqueue.h>
@@ -21,7 +20,7 @@ static inline int __iio_init_sw_ring_buffer(struct iio_sw_ring_buffer *ring,
return -EINVAL;
__iio_init_ring_buffer(&ring->buf, bytes_per_datum, length);
- ring->use_lock = __SPIN_LOCK_UNLOCKED((ring)->use_lock);
+ spin_lock_init(&ring->use_lock);
ring->data = kmalloc(length*ring->buf.bpd, GFP_KERNEL);
ring->read_p = 0;
ring->write_p = 0;
diff --git a/drivers/staging/iio/trigger_consumer.h b/drivers/staging/iio/trigger_consumer.h
index a02d70b0d24a..9d52d9637777 100644
--- a/drivers/staging/iio/trigger_consumer.h
+++ b/drivers/staging/iio/trigger_consumer.h
@@ -27,7 +27,7 @@ int iio_device_unregister_trigger_consumer(struct iio_dev *dev_info);
* iio_device_register_trigger_consumer() - set up an iio_dev to use triggers
* @dev_info: iio_dev associated with the device that will consume the trigger
**/
-int iio_device_register_trigger_consumer(struct iio_dev *dev_info)
+static int iio_device_register_trigger_consumer(struct iio_dev *dev_info)
{
return 0;
};
@@ -36,7 +36,7 @@ int iio_device_register_trigger_consumer(struct iio_dev *dev_info)
* iio_device_unregister_trigger_consumer() - reverse the registration process
* @dev_info: iio_dev associated with the device that consumed the trigger
**/
-int iio_device_unregister_trigger_consumer(struct iio_dev *dev_info)
+static int iio_device_unregister_trigger_consumer(struct iio_dev *dev_info)
{
return 0;
};
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
index e4078a92d399..0392a4bc8cc8 100644
--- a/drivers/staging/line6/driver.c
+++ b/drivers/staging/line6/driver.c
@@ -33,7 +33,7 @@
/* table of devices that work with this driver */
-static struct usb_device_id line6_id_table[] = {
+static const struct usb_device_id line6_id_table[] = {
{ USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXT) },
{ USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTLIVE) },
{ USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTPRO) },
diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c
index 48d834b0fa1b..58fef82c247d 100644
--- a/drivers/staging/line6/variax.c
+++ b/drivers/staging/line6/variax.c
@@ -254,7 +254,7 @@ static ssize_t variax_set_active(struct device *dev,
if (ret)
return ret;
- variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = value ? 1: 0;
+ variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = value ? 1 : 0;
line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
sizeof(variax_activate));
return count;
diff --git a/drivers/staging/mimio/Kconfig b/drivers/staging/mimio/Kconfig
deleted file mode 100644
index 505dcb275796..000000000000
--- a/drivers/staging/mimio/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-config INPUT_MIMIO
- tristate "Mimio Xi interactive whiteboard support"
- depends on USB && INPUT
- default N
- help
- Say Y here if you want to use a Mimio Xi interactive
- whiteboard device.
-
- To compile this driver as a module, choose M here: the
- module will be called mimio.
diff --git a/drivers/staging/mimio/Makefile b/drivers/staging/mimio/Makefile
deleted file mode 100644
index 77807ee0450e..000000000000
--- a/drivers/staging/mimio/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_INPUT_MIMIO) += mimio.o
diff --git a/drivers/staging/mimio/mimio.c b/drivers/staging/mimio/mimio.c
deleted file mode 100644
index 1ba8103f5003..000000000000
--- a/drivers/staging/mimio/mimio.c
+++ /dev/null
@@ -1,914 +0,0 @@
-/*
- * Hardware event => input event mapping:
- *
- *
- *
- input.h:#define BTN_TOOL_PEN 0x140 black
- input.h:#define BTN_TOOL_RUBBER 0x141 blue
- input.h:#define BTN_TOOL_BRUSH 0x142 green
- input.h:#define BTN_TOOL_PENCIL 0x143 red
- input.h:#define BTN_TOOL_AIRBRUSH 0x144 eraser
- input.h:#define BTN_TOOL_FINGER 0x145 small eraser
- input.h:#define BTN_TOOL_MOUSE 0x146 mimio interactive
- input.h:#define BTN_TOOL_LENS 0x147 mimio interactive but1
- input.h:#define LOCALBTN_TOOL_EXTRA1 0x14a mimio interactive but2 == BTN_TOUCH
- input.h:#define LOCALBTN_TOOL_EXTRA2 0x14b mimio extra pens (orange, brown, yellow, purple) == BTN_STYLUS
- input.h:#define LOCALBTN_TOOL_EXTRA3 0x14c unused == BTN_STYLUS2
- input.h:#define BTN_TOOL_DOUBLETAP 0x14d unused
- input.h:#define BTN_TOOL_TRIPLETAP 0x14e unused
- *
- * MIMIO_EV_PENDOWN(MIMIO_PEN_K) => EV_KEY BIT(BTN_TOOL_PEN)
- * MIMIO_EV_PENDOWN(MIMIO_PEN_B) => EV_KEY BIT(BTN_TOOL_RUBBER)
- * MIMIO_EV_PENDOWN(MIMIO_PEN_G) => EV_KEY BIT(BTN_TOOL_BRUSH)
- * MIMIO_EV_PENDOWN(MIMIO_PEN_R) => EV_KEY BIT(BTN_TOOL_PENCIL)
- * MIMIO_EV_PENDOWN(MIMIO_PEN_E) => EV_KEY BIT(BTN_TOOL_AIRBRUSH)
- * MIMIO_EV_PENDOWN(MIMIO_PEN_ES) => EV_KEY BIT(BTN_TOOL_FINGER)
- * MIMIO_EV_PENDOWN(MIMIO_PEN_I) => EV_KEY BIT(BTN_TOOL_MOUSE)
- * MIMIO_EV_PENDOWN(MIMIO_PEN_IL) => EV_KEY BIT(BTN_TOOL_LENS)
- * MIMIO_EV_PENDOWN(MIMIO_PEN_IR) => EV_KEY BIT(BTN_TOOL_DOUBLETAP)
- * MIMIO_EV_PENDOWN(MIMIO_PEN_EX) => EV_KEY BIT(BTN_TOOL_TRIPLETAP)
- * MIMIO_EV_PENDATA => EV_ABS BIT(ABS_X), BIT(ABS_Y)
- * MIMIO_EV_MEMRESET => EV_KEY BIT(BTN_0)
- * MIMIO_EV_ACC(ACC_NEWPAGE) => EV_KEY BIT(BTN_1)
- * MIMIO_EV_ACC(ACC_TAGPAGE) => EV_KEY BIT(BTN_2)
- * MIMIO_EV_ACC(ACC_PRINTPAGE) => EV_KEY BIT(BTN_3)
- * MIMIO_EV_ACC(ACC_MAXIMIZE) => EV_KEY BIT(BTN_4)
- * MIMIO_EV_ACC(ACC_FINDCTLPNL) => EV_KEY BIT(BTN_5)
- *
- *
- * open issues:
- * - cold-load of data captured when mimio in standalone mode not yet
- * supported; need to snoop Win32 box to see datastream for this.
- * - mimio mouse not yet supported; need to snoop Win32 box to see the
- * datastream for this.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/input.h>
-#include <linux/usb.h>
-
-#define DRIVER_VERSION "v0.031"
-#define DRIVER_AUTHOR "mwilder@cs.nmsu.edu"
-#define DRIVER_DESC "USB mimio-xi driver"
-
-enum {UPVALUE, DOWNVALUE, MOVEVALUE};
-
-#define MIMIO_XRANGE_MAX 9600
-#define MIMIO_YRANGE_MAX 4800
-
-#define LOCALBTN_TOOL_EXTRA1 BTN_TOUCH
-#define LOCALBTN_TOOL_EXTRA2 BTN_STYLUS
-#define LOCALBTN_TOOL_EXTRA3 BTN_STYLUS2
-
-#define MIMIO_VENDOR_ID 0x08d3
-#define MIMIO_PRODUCT_ID 0x0001
-#define MIMIO_MAXPAYLOAD (8)
-#define MIMIO_MAXNAMELEN (64)
-#define MIMIO_TXWAIT (1)
-#define MIMIO_TXDONE (2)
-
-#define MIMIO_EV_PENDOWN (0x22)
-#define MIMIO_EV_PENDATA (0x24)
-#define MIMIO_EV_PENUP (0x51)
-#define MIMIO_EV_MEMRESET (0x45)
-#define MIMIO_EV_ACC (0xb2)
-
-#define MIMIO_PEN_K (1) /* black pen */
-#define MIMIO_PEN_B (2) /* blue pen */
-#define MIMIO_PEN_G (3) /* green pen */
-#define MIMIO_PEN_R (4) /* red pen */
-/* 5, 6, 7, 8 are extra pens */
-#define MIMIO_PEN_E (9) /* big eraser */
-#define MIMIO_PEN_ES (10) /* lil eraser */
-#define MIMIO_PENJUMP_START (10)
-#define MIMIO_PENJUMP (6)
-#define MIMIO_PEN_I (17) /* mimio interactive */
-#define MIMIO_PEN_IL (18) /* mimio interactive button 1 */
-#define MIMIO_PEN_IR (19) /* mimio interactive button 2 */
-
-#define MIMIO_PEN_MAX (MIMIO_PEN_IR)
-
-#define ACC_DONE (0)
-#define ACC_NEWPAGE (1)
-#define ACC_TAGPAGE (2)
-#define ACC_PRINTPAGE (4)
-#define ACC_MAXIMIZE (8)
-#define ACC_FINDCTLPNL (16)
-
-#define isvalidtxsize(n) ((n) > 0 && (n) <= MIMIO_MAXPAYLOAD)
-
-
-struct pktbuf {
- unsigned char instr;
- unsigned char buf[16];
- unsigned char *p;
- unsigned char *q;
-};
-
-struct usbintendpt {
- dma_addr_t dma;
- struct urb *urb;
- unsigned char *buf;
- struct usb_endpoint_descriptor *desc;
-};
-
-struct mimio {
- struct input_dev *idev;
- struct usb_device *udev;
- struct usb_interface *uifc;
- int open;
- int present;
- int greeted;
- int txflags;
- char phys[MIMIO_MAXNAMELEN];
- struct usbintendpt in;
- struct usbintendpt out;
- struct pktbuf pktbuf;
- unsigned char minor;
- wait_queue_head_t waitq;
- spinlock_t txlock;
- void (*rxhandler)(struct mimio *, unsigned char *, unsigned int);
- int last_pen_down;
-};
-
-static void mimio_close(struct input_dev *);
-static void mimio_dealloc(struct mimio *);
-static void mimio_disconnect(struct usb_interface *);
-static int mimio_greet(struct mimio *);
-static void mimio_irq_in(struct urb *);
-static void mimio_irq_out(struct urb *);
-static int mimio_open(struct input_dev *);
-static int mimio_probe(struct usb_interface *, const struct usb_device_id *);
-static void mimio_rx_handler(struct mimio *, unsigned char *, unsigned int);
-static int mimio_tx(struct mimio *, const char *, int);
-
-static char mimio_name[] = "VirtualInk mimio-Xi";
-static struct usb_device_id mimio_table [] = {
- { USB_DEVICE(MIMIO_VENDOR_ID, MIMIO_PRODUCT_ID) },
- { USB_DEVICE(0x0525, 0xa4a0) }, /* gadget zero firmware */
- { }
-};
-
-MODULE_DEVICE_TABLE(usb, mimio_table);
-
-static struct usb_driver mimio_driver = {
- .name = "mimio",
- .probe = mimio_probe,
- .disconnect = mimio_disconnect,
- .id_table = mimio_table,
-};
-
-static DECLARE_MUTEX(disconnect_sem);
-
-static void mimio_close(struct input_dev *idev)
-{
- struct mimio *mimio;
-
- mimio = input_get_drvdata(idev);
- if (!mimio) {
- dev_err(&idev->dev, "null mimio attached to input device\n");
- return;
- }
-
- if (mimio->open <= 0)
- dev_err(&idev->dev, "mimio not open.\n");
- else
- mimio->open--;
-
- if (mimio->present == 0 && mimio->open == 0)
- mimio_dealloc(mimio);
-}
-
-static void mimio_dealloc(struct mimio *mimio)
-{
- if (mimio == NULL)
- return;
-
- usb_kill_urb(mimio->in.urb);
-
- usb_kill_urb(mimio->out.urb);
-
- if (mimio->idev) {
- input_unregister_device(mimio->idev);
- if (mimio->idev->grab)
- input_close_device(mimio->idev->grab);
- else
- dev_dbg(&mimio->idev->dev, "mimio->idev->grab == NULL"
- " -- didn't call input_close_device\n");
- }
-
- usb_free_urb(mimio->in.urb);
-
- usb_free_urb(mimio->out.urb);
-
- if (mimio->in.buf) {
- usb_buffer_free(mimio->udev, MIMIO_MAXPAYLOAD, mimio->in.buf,
- mimio->in.dma);
- }
-
- if (mimio->out.buf)
- usb_buffer_free(mimio->udev, MIMIO_MAXPAYLOAD, mimio->out.buf,
- mimio->out.dma);
-
- if (mimio->idev)
- input_free_device(mimio->idev);
-
- kfree(mimio);
-}
-
-static void mimio_disconnect(struct usb_interface *ifc)
-{
- struct mimio *mimio;
-
- down(&disconnect_sem);
-
- mimio = usb_get_intfdata(ifc);
- usb_set_intfdata(ifc, NULL);
- dev_dbg(&mimio->idev->dev, "disconnect\n");
-
- if (mimio) {
- mimio->present = 0;
-
- if (mimio->open <= 0)
- mimio_dealloc(mimio);
- }
-
- up(&disconnect_sem);
-}
-
-static int mimio_greet(struct mimio *mimio)
-{
- const struct grtpkt {
- int nbytes;
- unsigned delay;
- char data[8];
- } grtpkts[] = {
- { 3, 0, { 0x11, 0x55, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00 } },
- { 5, 0, { 0x53, 0x55, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00 } },
- { 5, 0, { 0x43, 0x55, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00 } },
- { 5, 0, { 0x33, 0x55, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00 } },
- { 5, 0, { 0x13, 0x00, 0x5e, 0x02, 0x4f, 0x00, 0x00, 0x00 } },
- { 5, 0, { 0x13, 0x00, 0x04, 0x03, 0x14, 0x00, 0x00, 0x00 } },
- { 5, 2, { 0x13, 0x00, 0x00, 0x04, 0x17, 0x00, 0x00, 0x00 } },
- { 5, 0, { 0x13, 0x00, 0x0d, 0x08, 0x16, 0x00, 0x00, 0x00 } },
- { 5, 0, { 0x13, 0x00, 0x4d, 0x01, 0x5f, 0x00, 0x00, 0x00 } },
- { 3, 0, { 0xf1, 0x55, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00 } },
- { 7, 2, { 0x52, 0x55, 0x00, 0x07, 0x31, 0x55, 0x64, 0x00 } },
- { 0, 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
- };
- int rslt;
- const struct grtpkt *pkt;
-
- for (pkt = grtpkts; pkt->nbytes; pkt++) {
- rslt = mimio_tx(mimio, pkt->data, pkt->nbytes);
- if (rslt)
- return rslt;
- if (pkt->delay)
- msleep(pkt->delay);
- }
-
- return 0;
-}
-
-static void mimio_irq_in(struct urb *urb)
-{
- int rslt;
- char *data;
- const char *reason = "going down";
- struct mimio *mimio;
-
- mimio = urb->context;
-
- if (mimio == NULL)
- /* paranoia */
- return;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ETIMEDOUT:
- reason = "timeout -- unplugged?";
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- dev_dbg(&mimio->idev->dev, "%s.\n", reason);
- return;
- default:
- dev_dbg(&mimio->idev->dev, "unknown urb-status: %d.\n",
- urb->status);
- goto exit;
- }
- data = mimio->in.buf;
-
- if (mimio->rxhandler)
- mimio->rxhandler(mimio, data, urb->actual_length);
-exit:
- /*
- * Keep listening to device on same urb.
- */
- rslt = usb_submit_urb(urb, GFP_ATOMIC);
- if (rslt)
- dev_err(&mimio->idev->dev, "usb_submit_urb failure: %d.\n",
- rslt);
-}
-
-static void mimio_irq_out(struct urb *urb)
-{
- unsigned long flags;
- struct mimio *mimio;
-
- mimio = urb->context;
-
- if (urb->status)
- dev_dbg(&mimio->idev->dev, "urb-status: %d.\n", urb->status);
-
- spin_lock_irqsave(&mimio->txlock, flags);
- mimio->txflags |= MIMIO_TXDONE;
- spin_unlock_irqrestore(&mimio->txlock, flags);
- wmb();
- wake_up(&mimio->waitq);
-}
-
-static int mimio_open(struct input_dev *idev)
-{
- int rslt;
- struct mimio *mimio;
-
- rslt = 0;
- down(&disconnect_sem);
- mimio = input_get_drvdata(idev);
- dev_dbg(&idev->dev, "mimio_open\n");
-
- if (mimio == NULL) {
- dev_err(&idev->dev, "null mimio.\n");
- rslt = -ENODEV;
- goto exit;
- }
-
- if (mimio->open++)
- goto exit;
-
- if (mimio->present && !mimio->greeted) {
- struct urb *urb = mimio->in.urb;
- mimio->in.urb->dev = mimio->udev;
- rslt = usb_submit_urb(mimio->in.urb, GFP_KERNEL);
- if (rslt) {
- dev_err(&idev->dev, "usb_submit_urb failure "
- "(res = %d: %s). Not greeting.\n",
- rslt,
- (!urb ? "urb is NULL" :
- (urb->hcpriv ? "urb->hcpriv is non-NULL" :
- (!urb->complete ? "urb is not complete" :
- (urb->number_of_packets <= 0 ? "urb has no packets" :
- (urb->interval <= 0 ? "urb interval too small" :
- "urb interval too large or some other error"))))));
- rslt = -EIO;
- goto exit;
- }
- rslt = mimio_greet(mimio);
- if (rslt == 0) {
- dev_dbg(&idev->dev, "Mimio greeted OK.\n");
- mimio->greeted = 1;
- } else {
- dev_dbg(&idev->dev, "Mimio greet Failure (%d)\n",
- rslt);
- }
- }
-
-exit:
- up(&disconnect_sem);
- return rslt;
-}
-
-static int mimio_probe(struct usb_interface *ifc,
- const struct usb_device_id *id)
-{
- char path[64];
- int pipe, maxp;
- struct mimio *mimio;
- struct usb_device *udev;
- struct usb_host_interface *hostifc;
- struct input_dev *input_dev;
- int res = 0;
- int i;
-
- udev = interface_to_usbdev(ifc);
-
- mimio = kzalloc(sizeof(struct mimio), GFP_KERNEL);
- if (!mimio)
- return -ENOMEM;
-
- input_dev = input_allocate_device();
- if (!input_dev) {
- mimio_dealloc(mimio);
- return -ENOMEM;
- }
-
- mimio->uifc = ifc;
- mimio->udev = udev;
- mimio->pktbuf.p = mimio->pktbuf.buf;
- mimio->pktbuf.q = mimio->pktbuf.buf;
- /* init_input_dev(mimio->idev); */
- mimio->idev = input_dev;
- init_waitqueue_head(&mimio->waitq);
- spin_lock_init(&mimio->txlock);
- hostifc = ifc->cur_altsetting;
-
- if (hostifc->desc.bNumEndpoints != 2) {
- dev_err(&udev->dev, "Unexpected endpoint count: %d.\n",
- hostifc->desc.bNumEndpoints);
- mimio_dealloc(mimio);
- return -ENODEV;
- }
-
- mimio->in.desc = &(hostifc->endpoint[0].desc);
- mimio->out.desc = &(hostifc->endpoint[1].desc);
-
- mimio->in.buf = usb_buffer_alloc(udev, MIMIO_MAXPAYLOAD, GFP_KERNEL,
- &mimio->in.dma);
- mimio->out.buf = usb_buffer_alloc(udev, MIMIO_MAXPAYLOAD, GFP_KERNEL,
- &mimio->out.dma);
-
- if (mimio->in.buf == NULL || mimio->out.buf == NULL) {
- dev_err(&udev->dev, "usb_buffer_alloc failure.\n");
- mimio_dealloc(mimio);
- return -ENOMEM;
- }
-
- mimio->in.urb = usb_alloc_urb(0, GFP_KERNEL);
- mimio->out.urb = usb_alloc_urb(0, GFP_KERNEL);
-
- if (mimio->in.urb == NULL || mimio->out.urb == NULL) {
- dev_err(&udev->dev, "usb_alloc_urb failure.\n");
- mimio_dealloc(mimio);
- return -ENOMEM;
- }
-
- /*
- * Build the input urb.
- */
- pipe = usb_rcvintpipe(udev, mimio->in.desc->bEndpointAddress);
- maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
- if (maxp > MIMIO_MAXPAYLOAD)
- maxp = MIMIO_MAXPAYLOAD;
- usb_fill_int_urb(mimio->in.urb, udev, pipe, mimio->in.buf, maxp,
- mimio_irq_in, mimio, mimio->in.desc->bInterval);
- mimio->in.urb->transfer_dma = mimio->in.dma;
- mimio->in.urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
- /*
- * Build the output urb.
- */
- pipe = usb_sndintpipe(udev, mimio->out.desc->bEndpointAddress);
- maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
- if (maxp > MIMIO_MAXPAYLOAD)
- maxp = MIMIO_MAXPAYLOAD;
- usb_fill_int_urb(mimio->out.urb, udev, pipe, mimio->out.buf, maxp,
- mimio_irq_out, mimio, mimio->out.desc->bInterval);
- mimio->out.urb->transfer_dma = mimio->out.dma;
- mimio->out.urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
- /*
- * Build input device info
- */
- usb_make_path(udev, path, 64);
- snprintf(mimio->phys, MIMIO_MAXNAMELEN, "%s/input0", path);
- input_set_drvdata(input_dev, mimio);
- /* input_dev->dev = &ifc->dev; */
- input_dev->open = mimio_open;
- input_dev->close = mimio_close;
- input_dev->name = mimio_name;
- input_dev->phys = mimio->phys;
- input_dev->dev.parent = &ifc->dev;
-
- input_dev->id.bustype = BUS_USB;
- input_dev->id.vendor = le16_to_cpu(udev->descriptor.idVendor);
- input_dev->id.product = le16_to_cpu(udev->descriptor.idProduct);
- input_dev->id.version = le16_to_cpu(udev->descriptor.bcdDevice);
-
- input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
- for (i = BTN_TOOL_PEN; i <= LOCALBTN_TOOL_EXTRA2; ++i)
- set_bit(i, input_dev->keybit);
-
- input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) |
- BIT_MASK(BTN_1) |
- BIT_MASK(BTN_2) |
- BIT_MASK(BTN_3) |
- BIT_MASK(BTN_4) |
- BIT_MASK(BTN_5);
- /* input_dev->keybit[BTN_MOUSE] |= BIT(BTN_LEFT); */
- input_dev->absbit[0] |= BIT_MASK(ABS_X) | BIT_MASK(ABS_Y);
- input_set_abs_params(input_dev, ABS_X, 0, MIMIO_XRANGE_MAX, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, MIMIO_YRANGE_MAX, 0, 0);
- input_dev->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
-
-#if 0
- input_dev->absmin[ABS_X] = 0;
- input_dev->absmin[ABS_Y] = 0;
- input_dev->absmax[ABS_X] = 9600;
- input_dev->absmax[ABS_Y] = 4800;
- input_dev->absfuzz[ABS_X] = 0;
- input_dev->absfuzz[ABS_Y] = 0;
- input_dev->absflat[ABS_X] = 0;
- input_dev->absflat[ABS_Y] = 0;
-#endif
-
-#if 0
- /* this will just reduce the precision */
- input_dev->absfuzz[ABS_X] = 8; /* experimental; may need to change */
- input_dev->absfuzz[ABS_Y] = 8; /* experimental; may need to change */
-#endif
-
- /*
- * Register the input device.
- */
- res = input_register_device(mimio->idev);
- if (res) {
- dev_err(&udev->dev, "input_register_device failure (%d)\n",
- res);
- mimio_dealloc(mimio);
- return -EIO;
- }
- dev_dbg(&mimio->idev->dev, "input: %s on %s (res = %d).\n",
- input_dev->name, input_dev->phys, res);
-
- usb_set_intfdata(ifc, mimio);
- mimio->present = 1;
-
- /*
- * Submit the input urb to the usb subsystem.
- */
- mimio->in.urb->dev = mimio->udev;
- res = usb_submit_urb(mimio->in.urb, GFP_KERNEL);
- if (res) {
- dev_err(&mimio->idev->dev, "usb_submit_urb failure (%d)\n",
- res);
- mimio_dealloc(mimio);
- return -EIO;
- }
-
- /*
- * Attempt to greet the mimio after giving
- * it some post-init settling time.
- *
- * note: sometimes this sleep interval isn't
- * long enough to permit the device to re-init
- * after a hot-swap; maybe need to bump it up.
- *
- * As it is, this probably breaks module unloading support!
- */
- msleep(1024);
-
- res = mimio_greet(mimio);
- if (res == 0) {
- dev_dbg(&mimio->idev->dev, "Mimio greeted OK.\n");
- mimio->greeted = 1;
- mimio->rxhandler = mimio_rx_handler;
- } else {
- dev_dbg(&mimio->idev->dev, "Mimio greet Failure (%d)\n", res);
- }
-
- return 0;
-}
-
-static int handle_mimio_rx_penupdown(struct mimio *mimio,
- int down,
- const char *const instr[],
- const int instr_ofst[])
-{
- int penid, x;
- if (mimio->pktbuf.q - mimio->pktbuf.p < (down ? 4 : 3))
- return 1; /* partial pkt */
-
- if (down) {
- x = *mimio->pktbuf.p ^ *(mimio->pktbuf.p + 1) ^
- *(mimio->pktbuf.p + 2);
- if (x != *(mimio->pktbuf.p + 3)) {
- dev_dbg(&mimio->idev->dev, "EV_PEN%s: bad xsum.\n",
- down ? "DOWN":"UP");
- /* skip this event data */
- mimio->pktbuf.p += 4;
- /* decode any remaining events */
- return 0;
- }
- penid = mimio->pktbuf.instr = *(mimio->pktbuf.p + 2);
- if (penid > MIMIO_PEN_MAX) {
- dev_dbg(&mimio->idev->dev,
- "Unmapped penID (not in [0, %d]): %d\n",
- MIMIO_PEN_MAX, (int)mimio->pktbuf.instr);
- penid = mimio->pktbuf.instr = 0;
- }
- mimio->last_pen_down = penid;
- } else {
- penid = mimio->last_pen_down;
- }
- dev_dbg(&mimio->idev->dev, "%s (id %d, code %d) %s.\n", instr[penid],
- instr_ofst[penid], penid, down ? "down" : "up");
-
- if (instr_ofst[penid] >= 0) {
- int code = BTN_TOOL_PEN + instr_ofst[penid];
- int value = down ? DOWNVALUE : UPVALUE;
- if (code > KEY_MAX)
- dev_dbg(&mimio->idev->dev, "input_event will ignore "
- "-- code (%d) > KEY_MAX\n", code);
- if (!test_bit(code, mimio->idev->keybit))
- dev_dbg(&mimio->idev->dev, "input_event will ignore "
- "-- bit for code (%d) not enabled\n", code);
- if (!!test_bit(code, mimio->idev->key) == value)
- dev_dbg(&mimio->idev->dev, "input_event will ignore "
- "-- bit for code (%d) already set to %d\n",
- code, value);
- if (value != DOWNVALUE) {
- /* input_regs(mimio->idev, regs); */
- input_report_key(mimio->idev, code, value);
- input_sync(mimio->idev);
- } else {
- /* wait until we get some coordinates */
- }
- } else {
- dev_dbg(&mimio->idev->dev, "penID offset[%d] == %d is < 0 "
- "- not sending\n", penid, instr_ofst[penid]);
- }
- mimio->pktbuf.p += down ? 4 : 3; /* 3 for up, 4 for down */
- return 0;
-}
-
-/*
- * Stay tuned for partial-packet excitement.
- *
- * This routine buffers data packets received from the mimio device
- * in the mimio's data space. This buffering is necessary because
- * the mimio's in endpoint can serve us partial packets of data, and
- * we want the driver to support the servicing of multiple mimios.
- * Empirical evidence gathered so far suggests that the method of
- * buffering packet data in the mimio's data space works. Previous
- * versions of this driver did not buffer packet data in each mimio's
- * data-space, and were therefore not able to service multiple mimios.
- * Note that since the caller of this routine is running in interrupt
- * context, care needs to be taken to ensure that this routine does not
- * become bloated, and it may be that another spinlock is needed in each
- * mimio to guard the buffered packet data properly.
- */
-static void mimio_rx_handler(struct mimio *mimio,
- unsigned char *data,
- unsigned int nbytes)
-{
- struct device *dev = &mimio->idev->dev;
- unsigned int x;
- unsigned int y;
- static const char * const instr[] = {
- "?0",
- "black pen", "blue pen", "green pen", "red pen",
- "brown pen", "orange pen", "purple pen", "yellow pen",
- "big eraser", "lil eraser",
- "?11", "?12", "?13", "?14", "?15", "?16",
- "mimio interactive", "interactive button1",
- "interactive button2"
- };
-
- /* Mimio Interactive gives:
- * down: [0x22 0x01 0x11 0x32 0x24]
- * b1 : [0x22 0x01 0x12 0x31 0x24]
- * b2 : [0x22 0x01 0x13 0x30 0x24]
- */
- static const int instr_ofst[] = {
- -1,
- 0, 1, 2, 3,
- 9, 9, 9, 9,
- 4, 5,
- -1, -1, -1, -1, -1, -1,
- 6, 7, 8,
- };
-
- memcpy(mimio->pktbuf.q, data, nbytes);
- mimio->pktbuf.q += nbytes;
-
- while (mimio->pktbuf.p < mimio->pktbuf.q) {
- int t = *mimio->pktbuf.p;
- switch (t) {
- case MIMIO_EV_PENUP:
- case MIMIO_EV_PENDOWN:
- if (handle_mimio_rx_penupdown(mimio,
- t == MIMIO_EV_PENDOWN,
- instr, instr_ofst))
- return; /* partial packet */
- break;
-
- case MIMIO_EV_PENDATA:
- if (mimio->pktbuf.q - mimio->pktbuf.p < 6)
- /* partial pkt */
- return;
- x = *mimio->pktbuf.p ^ *(mimio->pktbuf.p + 1) ^
- *(mimio->pktbuf.p + 2) ^
- *(mimio->pktbuf.p + 3) ^
- *(mimio->pktbuf.p + 4);
- if (x != *(mimio->pktbuf.p + 5)) {
- dev_dbg(dev, "EV_PENDATA: bad xsum.\n");
- mimio->pktbuf.p += 6; /* skip this event data */
- break; /* decode any remaining events */
- }
- x = *(mimio->pktbuf.p + 1);
- x <<= 8;
- x |= *(mimio->pktbuf.p + 2);
- y = *(mimio->pktbuf.p + 3);
- y <<= 8;
- y |= *(mimio->pktbuf.p + 4);
- dev_dbg(dev, "coord: (%d, %d)\n", x, y);
- if (instr_ofst[mimio->pktbuf.instr] >= 0) {
- int code = BTN_TOOL_PEN +
- instr_ofst[mimio->last_pen_down];
-#if 0
- /* Utter hack to ensure we get forwarded _AND_
- * so we can identify when a complete signal is
- * received */
- mimio->idev->abs[ABS_Y] = -1;
- mimio->idev->abs[ABS_X] = -1;
-#endif
- /* input_regs(mimio->idev, regs); */
- input_report_abs(mimio->idev, ABS_X, x);
- input_report_abs(mimio->idev, ABS_Y, y);
- /* fake a penup */
- change_bit(code, mimio->idev->key);
- input_report_key(mimio->idev,
- code,
- DOWNVALUE);
- /* always sync here */
- mimio->idev->sync = 0;
- input_sync(mimio->idev);
- }
- mimio->pktbuf.p += 6;
- break;
- case MIMIO_EV_MEMRESET:
- if (mimio->pktbuf.q - mimio->pktbuf.p < 7)
- /* partial pkt */
- return;
- dev_dbg(dev, "mem-reset.\n");
- /* input_regs(mimio->idev, regs); */
- input_event(mimio->idev, EV_KEY, BTN_0, 1);
- input_event(mimio->idev, EV_KEY, BTN_0, 0);
- input_sync(mimio->idev);
- mimio->pktbuf.p += 7;
- break;
- case MIMIO_EV_ACC:
- if (mimio->pktbuf.q - mimio->pktbuf.p < 4)
- /* partial pkt */
- return;
- x = *mimio->pktbuf.p ^ *(mimio->pktbuf.p + 1) ^
- *(mimio->pktbuf.p + 2);
- if (x != *(mimio->pktbuf.p + 3)) {
- dev_dbg(dev, "EV_ACC: bad xsum.\n");
- mimio->pktbuf.p += 4; /* skip this event data */
- break; /* decode any remaining events */
- }
- switch (*(mimio->pktbuf.p + 2)) {
- case ACC_NEWPAGE:
- dev_dbg(&mimio->idev->dev, "new-page.\n");
- /* input_regs(mimio->idev, regs); */
- input_event(mimio->idev, EV_KEY, BTN_1, 1);
- input_event(mimio->idev, EV_KEY, BTN_1, 0);
- input_sync(mimio->idev);
- break;
- case ACC_TAGPAGE:
- dev_dbg(&mimio->idev->dev, "tag-page.\n");
- /* input_regs(mimio->idev, regs); */
- input_event(mimio->idev, EV_KEY, BTN_2, 1);
- input_event(mimio->idev, EV_KEY, BTN_2, 0);
- input_sync(mimio->idev);
- break;
- case ACC_PRINTPAGE:
- dev_dbg(&mimio->idev->dev, "print-page.\n");
- /* input_regs(mimio->idev, regs);*/
- input_event(mimio->idev, EV_KEY, BTN_3, 1);
- input_event(mimio->idev, EV_KEY, BTN_3, 0);
- input_sync(mimio->idev);
- break;
- case ACC_MAXIMIZE:
- dev_dbg(&mimio->idev->dev,
- "maximize-window.\n");
- /* input_regs(mimio->idev, regs); */
- input_event(mimio->idev, EV_KEY, BTN_4, 1);
- input_event(mimio->idev, EV_KEY, BTN_4, 0);
- input_sync(mimio->idev);
- break;
- case ACC_FINDCTLPNL:
- dev_dbg(&mimio->idev->dev, "find-ctl-panel.\n");
- /* input_regs(mimio->idev, regs); */
- input_event(mimio->idev, EV_KEY, BTN_5, 1);
- input_event(mimio->idev, EV_KEY, BTN_5, 0);
- input_sync(mimio->idev);
- break;
- case ACC_DONE:
- dev_dbg(&mimio->idev->dev, "acc-done.\n");
- /* no event is dispatched to the input
- * subsystem for this device event.
- */
- break;
- default:
- dev_dbg(dev, "unknown acc event.\n");
- break;
- }
- mimio->pktbuf.p += 4;
- break;
- default:
- mimio->pktbuf.p++;
- break;
- }
- }
-
- /*
- * No partial event was received, so reset mimio's pktbuf ptrs.
- */
- mimio->pktbuf.p = mimio->pktbuf.q = mimio->pktbuf.buf;
-}
-
-static int mimio_tx(struct mimio *mimio, const char *buf, int nbytes)
-{
- int rslt;
- int timeout;
- unsigned long flags;
- DECLARE_WAITQUEUE(wait, current);
-
- if (!(isvalidtxsize(nbytes))) {
- dev_err(&mimio->idev->dev, "invalid arg: nbytes: %d.\n",
- nbytes);
- return -EINVAL;
- }
-
- /*
- * Init the out urb and copy the data to send.
- */
- mimio->out.urb->dev = mimio->udev;
- mimio->out.urb->transfer_buffer_length = nbytes;
- memcpy(mimio->out.urb->transfer_buffer, buf, nbytes);
-
- /*
- * Send the data.
- */
- spin_lock_irqsave(&mimio->txlock, flags);
- mimio->txflags = MIMIO_TXWAIT;
- rslt = usb_submit_urb(mimio->out.urb, GFP_ATOMIC);
- spin_unlock_irqrestore(&mimio->txlock, flags);
- dev_dbg(&mimio->idev->dev, "rslt: %d.\n", rslt);
-
- if (rslt) {
- dev_err(&mimio->idev->dev, "usb_submit_urb failure: %d.\n",
- rslt);
- return rslt;
- }
-
- /*
- * Wait for completion to be signalled (the mimio_irq_out
- * completion routine will or MIMIO_TXDONE in with txflags).
- */
- timeout = HZ;
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&mimio->waitq, &wait);
-
- while (timeout && ((mimio->txflags & MIMIO_TXDONE) == 0)) {
- timeout = schedule_timeout(timeout);
- rmb();
- }
-
- if ((mimio->txflags & MIMIO_TXDONE) == 0)
- dev_dbg(&mimio->idev->dev, "tx timed out.\n");
-
- /*
- * Now that completion has been signalled,
- * unlink the urb so that it can be recycled.
- */
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&mimio->waitq, &wait);
- usb_unlink_urb(mimio->out.urb);
-
- return rslt;
-}
-
-static int __init mimio_init(void)
-{
- int rslt;
-
- rslt = usb_register(&mimio_driver);
- if (rslt != 0) {
- err("%s: usb_register failure: %d", __func__, rslt);
- return rslt;
- }
-
- printk(KERN_INFO KBUILD_MODNAME ":"
- DRIVER_DESC " " DRIVER_VERSION "\n");
- return rslt;
-}
-
-static void __exit mimio_exit(void)
-{
- usb_deregister(&mimio_driver);
-}
-
-module_init(mimio_init);
-module_exit(mimio_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/netwave/netwave_cs.c b/drivers/staging/netwave/netwave_cs.c
index e61e6b9440ab..e936717d1f4b 100644
--- a/drivers/staging/netwave/netwave_cs.c
+++ b/drivers/staging/netwave/netwave_cs.c
@@ -1341,15 +1341,15 @@ static void set_multicast_list(struct net_device *dev)
#ifdef PCMCIA_DEBUG
{
xstatic int old;
- if (old != dev->mc_count) {
- old = dev->mc_count;
+ if (old != netdev_mc_count(dev)) {
+ old = netdev_mc_count(dev);
pr_debug("%s: setting Rx mode to %d addresses.\n",
- dev->name, dev->mc_count);
+ dev->name, netdev_mc_count(dev));
}
}
#endif
- if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) {
+ if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) {
/* Multicast Mode */
rcvMode = rxConfRxEna + rxConfAMP + rxConfBcast;
} else if (dev->flags & IFF_PROMISC) {
diff --git a/drivers/staging/octeon/Makefile b/drivers/staging/octeon/Makefile
index c0a583cc2227..87447c102fa0 100644
--- a/drivers/staging/octeon/Makefile
+++ b/drivers/staging/octeon/Makefile
@@ -14,7 +14,6 @@ obj-${CONFIG_OCTEON_ETHERNET} := octeon-ethernet.o
octeon-ethernet-objs := ethernet.o
octeon-ethernet-objs += ethernet-mdio.o
octeon-ethernet-objs += ethernet-mem.o
-octeon-ethernet-objs += ethernet-proc.o
octeon-ethernet-objs += ethernet-rgmii.o
octeon-ethernet-objs += ethernet-rx.o
octeon-ethernet-objs += ethernet-sgmii.o
diff --git a/drivers/staging/octeon/ethernet-defines.h b/drivers/staging/octeon/ethernet-defines.h
index f13131b03c33..6a2cd50a17df 100644
--- a/drivers/staging/octeon/ethernet-defines.h
+++ b/drivers/staging/octeon/ethernet-defines.h
@@ -41,17 +41,10 @@
* Tells the driver to populate the packet buffers with kernel skbuffs.
* This allows the driver to receive packets without copying them. It also
* means that 32bit userspace can't access the packet buffers.
- * USE_32BIT_SHARED
- * This define tells the driver to allocate memory for buffers from the
- * 32bit sahred region instead of the kernel memory space.
* USE_HW_TCPUDP_CHECKSUM
* Controls if the Octeon TCP/UDP checksum engine is used for packet
* output. If this is zero, the kernel will perform the checksum in
* software.
- * USE_MULTICORE_RECEIVE
- * Process receive interrupts on multiple cores. This spreads the network
- * load across the first 8 processors. If ths is zero, only one core
- * processes incomming packets.
* USE_ASYNC_IOBDMA
* Use asynchronous IO access to hardware. This uses Octeon's asynchronous
* IOBDMAs to issue IO accesses without stalling. Set this to zero
@@ -75,29 +68,15 @@
#define CONFIG_CAVIUM_RESERVE32 0
#endif
-#if CONFIG_CAVIUM_RESERVE32
-#define USE_32BIT_SHARED 1
-#define USE_SKBUFFS_IN_HW 0
-#define REUSE_SKBUFFS_WITHOUT_FREE 0
-#else
-#define USE_32BIT_SHARED 0
#define USE_SKBUFFS_IN_HW 1
#ifdef CONFIG_NETFILTER
#define REUSE_SKBUFFS_WITHOUT_FREE 0
#else
#define REUSE_SKBUFFS_WITHOUT_FREE 1
#endif
-#endif
-
-/* Max interrupts per second per core */
-#define INTERRUPT_LIMIT 10000
-/* Don't limit the number of interrupts */
-/*#define INTERRUPT_LIMIT 0 */
#define USE_HW_TCPUDP_CHECKSUM 1
-#define USE_MULTICORE_RECEIVE 1
-
/* Enable Random Early Dropping under load */
#define USE_RED 1
#define USE_ASYNC_IOBDMA (CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0)
@@ -115,21 +94,12 @@
/* Use this to not have FPA frees control L2 */
/*#define DONT_WRITEBACK(x) 0 */
-/* Maximum number of packets to process per interrupt. */
-#define MAX_RX_PACKETS 120
/* Maximum number of SKBs to try to free per xmit packet. */
-#define MAX_SKB_TO_FREE 10
#define MAX_OUT_QUEUE_DEPTH 1000
-#ifndef CONFIG_SMP
-#undef USE_MULTICORE_RECEIVE
-#define USE_MULTICORE_RECEIVE 0
-#endif
-
-#define IP_PROTOCOL_TCP 6
-#define IP_PROTOCOL_UDP 0x11
+#define FAU_TOTAL_TX_TO_CLEAN (CVMX_FAU_REG_END - sizeof(uint32_t))
+#define FAU_NUM_PACKET_BUFFERS_TO_FREE (FAU_TOTAL_TX_TO_CLEAN - sizeof(uint32_t))
-#define FAU_NUM_PACKET_BUFFERS_TO_FREE (CVMX_FAU_REG_END - sizeof(uint32_t))
#define TOTAL_NUMBER_OF_PORTS (CVMX_PIP_NUM_INPUT_PORTS+1)
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index 05a5cc0f43ed..7e0be8d00dc3 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -96,11 +96,11 @@ const struct ethtool_ops cvm_oct_ethtool_ops = {
};
/**
- * IOCTL support for PHY control
- *
+ * cvm_oct_ioctl - IOCTL support for PHY control
* @dev: Device to change
* @rq: the request
* @cmd: the command
+ *
* Returns Zero on success
*/
int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -153,7 +153,7 @@ static void cvm_oct_adjust_link(struct net_device *dev)
/**
- * Setup the PHY
+ * cvm_oct_phy_setup_device - setup the PHY
*
* @dev: Device to setup
*
diff --git a/drivers/staging/octeon/ethernet-mdio.h b/drivers/staging/octeon/ethernet-mdio.h
index 55d0614a7cd9..a417d4fce12c 100644
--- a/drivers/staging/octeon/ethernet-mdio.h
+++ b/drivers/staging/octeon/ethernet-mdio.h
@@ -32,7 +32,6 @@
#include <linux/ip.h>
#include <linux/string.h>
#include <linux/ethtool.h>
-#include <linux/mii.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <net/dst.h>
diff --git a/drivers/staging/octeon/ethernet-mem.c b/drivers/staging/octeon/ethernet-mem.c
index b595903e2af1..00cc91df6b46 100644
--- a/drivers/staging/octeon/ethernet-mem.c
+++ b/drivers/staging/octeon/ethernet-mem.c
@@ -4,7 +4,7 @@
* Contact: support@caviumnetworks.com
* This file is part of the OCTEON SDK
*
- * Copyright (c) 2003-2007 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, Version 2, as
@@ -26,8 +26,6 @@
**********************************************************************/
#include <linux/kernel.h>
#include <linux/netdevice.h>
-#include <linux/mii.h>
-#include <net/dst.h>
#include <asm/octeon/octeon.h>
@@ -36,18 +34,19 @@
#include "cvmx-fpa.h"
/**
- * Fill the supplied hardware pool with skbuffs
- *
+ * cvm_oct_fill_hw_skbuff - fill the supplied hardware pool with skbuffs
* @pool: Pool to allocate an skbuff for
* @size: Size of the buffer needed for the pool
* @elements: Number of buffers to allocate
+ *
+ * Returns the actual number of buffers allocated.
*/
static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
{
int freed = elements;
while (freed) {
- struct sk_buff *skb = dev_alloc_skb(size + 128);
+ struct sk_buff *skb = dev_alloc_skb(size + 256);
if (unlikely(skb == NULL)) {
pr_warning
("Failed to allocate skb for hardware pool %d\n",
@@ -55,7 +54,7 @@ static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
break;
}
- skb_reserve(skb, 128 - (((unsigned long)skb->data) & 0x7f));
+ skb_reserve(skb, 256 - (((unsigned long)skb->data) & 0x7f));
*(struct sk_buff **)(skb->data - sizeof(void *)) = skb;
cvmx_fpa_free(skb->data, pool, DONT_WRITEBACK(size / 128));
freed--;
@@ -64,8 +63,7 @@ static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
}
/**
- * Free the supplied hardware pool of skbuffs
- *
+ * cvm_oct_free_hw_skbuff- free hardware pool skbuffs
* @pool: Pool to allocate an skbuff for
* @size: Size of the buffer needed for the pool
* @elements: Number of buffers to allocate
@@ -93,96 +91,76 @@ static void cvm_oct_free_hw_skbuff(int pool, int size, int elements)
}
/**
- * This function fills a hardware pool with memory. Depending
- * on the config defines, this memory might come from the
- * kernel or global 32bit memory allocated with
- * cvmx_bootmem_alloc.
- *
+ * cvm_oct_fill_hw_memory - fill a hardware pool with memory.
* @pool: Pool to populate
* @size: Size of each buffer in the pool
* @elements: Number of buffers to allocate
+ *
+ * Returns the actual number of buffers allocated.
*/
static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
{
char *memory;
+ char *fpa;
int freed = elements;
- if (USE_32BIT_SHARED) {
- extern uint64_t octeon_reserve32_memory;
-
- memory =
- cvmx_bootmem_alloc_range(elements * size, 128,
- octeon_reserve32_memory,
- octeon_reserve32_memory +
- (CONFIG_CAVIUM_RESERVE32 << 20) -
- 1);
- if (memory == NULL)
- panic("Unable to allocate %u bytes for FPA pool %d\n",
- elements * size, pool);
-
- pr_notice("Memory range %p - %p reserved for "
- "hardware\n", memory,
- memory + elements * size - 1);
-
- while (freed) {
- cvmx_fpa_free(memory, pool, 0);
- memory += size;
- freed--;
- }
- } else {
- while (freed) {
- /* We need to force alignment to 128 bytes here */
- memory = kmalloc(size + 127, GFP_ATOMIC);
- if (unlikely(memory == NULL)) {
- pr_warning("Unable to allocate %u bytes for "
- "FPA pool %d\n",
- elements * size, pool);
- break;
- }
- memory = (char *)(((unsigned long)memory + 127) & -128);
- cvmx_fpa_free(memory, pool, 0);
- freed--;
+ while (freed) {
+ /*
+ * FPA memory must be 128 byte aligned. Since we are
+ * aligning we need to save the original pointer so we
+ * can feed it to kfree when the memory is returned to
+ * the kernel.
+ *
+ * We allocate an extra 256 bytes to allow for
+ * alignment and space for the original pointer saved
+ * just before the block.
+ */
+ memory = kmalloc(size + 256, GFP_ATOMIC);
+ if (unlikely(memory == NULL)) {
+ pr_warning("Unable to allocate %u bytes for FPA pool %d\n",
+ elements * size, pool);
+ break;
}
+ fpa = (char *)(((unsigned long)memory + 256) & ~0x7fUL);
+ *((char **)fpa - 1) = memory;
+ cvmx_fpa_free(fpa, pool, 0);
+ freed--;
}
return elements - freed;
}
/**
- * Free memory previously allocated with cvm_oct_fill_hw_memory
- *
+ * cvm_oct_free_hw_memory - Free memory allocated by cvm_oct_fill_hw_memory
* @pool: FPA pool to free
* @size: Size of each buffer in the pool
* @elements: Number of buffers that should be in the pool
*/
static void cvm_oct_free_hw_memory(int pool, int size, int elements)
{
- if (USE_32BIT_SHARED) {
- pr_warning("Warning: 32 shared memory is not freeable\n");
- } else {
- char *memory;
- do {
- memory = cvmx_fpa_alloc(pool);
- if (memory) {
- elements--;
- kfree(phys_to_virt(cvmx_ptr_to_phys(memory)));
- }
- } while (memory);
+ char *memory;
+ char *fpa;
+ do {
+ fpa = cvmx_fpa_alloc(pool);
+ if (fpa) {
+ elements--;
+ fpa = (char *)phys_to_virt(cvmx_ptr_to_phys(fpa));
+ memory = *((char **)fpa - 1);
+ kfree(memory);
+ }
+ } while (fpa);
- if (elements < 0)
- pr_warning("Freeing of pool %u had too many "
- "buffers (%d)\n",
- pool, elements);
- else if (elements > 0)
- pr_warning("Warning: Freeing of pool %u is "
- "missing %d buffers\n",
- pool, elements);
- }
+ if (elements < 0)
+ pr_warning("Freeing of pool %u had too many buffers (%d)\n",
+ pool, elements);
+ else if (elements > 0)
+ pr_warning("Warning: Freeing of pool %u is missing %d buffers\n",
+ pool, elements);
}
int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
{
int freed;
- if (USE_SKBUFFS_IN_HW)
+ if (USE_SKBUFFS_IN_HW && pool == CVMX_FPA_PACKET_POOL)
freed = cvm_oct_fill_hw_skbuff(pool, size, elements);
else
freed = cvm_oct_fill_hw_memory(pool, size, elements);
@@ -191,7 +169,7 @@ int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
void cvm_oct_mem_empty_fpa(int pool, int size, int elements)
{
- if (USE_SKBUFFS_IN_HW)
+ if (USE_SKBUFFS_IN_HW && pool == CVMX_FPA_PACKET_POOL)
cvm_oct_free_hw_skbuff(pool, size, elements);
else
cvm_oct_free_hw_memory(pool, size, elements);
diff --git a/drivers/staging/octeon/ethernet-proc.c b/drivers/staging/octeon/ethernet-proc.c
deleted file mode 100644
index 16308d484d3b..000000000000
--- a/drivers/staging/octeon/ethernet-proc.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/**********************************************************************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2007 Cavium Networks
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, Version 2, as
- * published by the Free Software Foundation.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
-**********************************************************************/
-#include <linux/kernel.h>
-#include <linux/seq_file.h>
-#include <linux/proc_fs.h>
-#include <net/dst.h>
-
-#include <asm/octeon/octeon.h>
-
-#include "octeon-ethernet.h"
-#include "ethernet-defines.h"
-
-#include "cvmx-helper.h"
-#include "cvmx-pip.h"
-
-/**
- * User is reading /proc/octeon_ethernet_stats
- *
- * @m:
- * @v:
- * Returns
- */
-static int cvm_oct_stats_show(struct seq_file *m, void *v)
-{
- struct octeon_ethernet *priv;
- int port;
-
- for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) {
-
- if (cvm_oct_device[port]) {
- priv = netdev_priv(cvm_oct_device[port]);
-
- seq_printf(m, "\nOcteon Port %d (%s)\n", port,
- cvm_oct_device[port]->name);
- seq_printf(m,
- "rx_packets: %12lu\t"
- "tx_packets: %12lu\n",
- priv->stats.rx_packets,
- priv->stats.tx_packets);
- seq_printf(m,
- "rx_bytes: %12lu\t"
- "tx_bytes: %12lu\n",
- priv->stats.rx_bytes, priv->stats.tx_bytes);
- seq_printf(m,
- "rx_errors: %12lu\t"
- "tx_errors: %12lu\n",
- priv->stats.rx_errors,
- priv->stats.tx_errors);
- seq_printf(m,
- "rx_dropped: %12lu\t"
- "tx_dropped: %12lu\n",
- priv->stats.rx_dropped,
- priv->stats.tx_dropped);
- seq_printf(m,
- "rx_length_errors: %12lu\t"
- "tx_aborted_errors: %12lu\n",
- priv->stats.rx_length_errors,
- priv->stats.tx_aborted_errors);
- seq_printf(m,
- "rx_over_errors: %12lu\t"
- "tx_carrier_errors: %12lu\n",
- priv->stats.rx_over_errors,
- priv->stats.tx_carrier_errors);
- seq_printf(m,
- "rx_crc_errors: %12lu\t"
- "tx_fifo_errors: %12lu\n",
- priv->stats.rx_crc_errors,
- priv->stats.tx_fifo_errors);
- seq_printf(m,
- "rx_frame_errors: %12lu\t"
- "tx_heartbeat_errors: %12lu\n",
- priv->stats.rx_frame_errors,
- priv->stats.tx_heartbeat_errors);
- seq_printf(m,
- "rx_fifo_errors: %12lu\t"
- "tx_window_errors: %12lu\n",
- priv->stats.rx_fifo_errors,
- priv->stats.tx_window_errors);
- seq_printf(m,
- "rx_missed_errors: %12lu\t"
- "multicast: %12lu\n",
- priv->stats.rx_missed_errors,
- priv->stats.multicast);
- }
- }
-
- return 0;
-}
-
-/**
- * /proc/octeon_ethernet_stats was openned. Use the single_open iterator
- *
- * @inode:
- * @file:
- * Returns
- */
-static int cvm_oct_stats_open(struct inode *inode, struct file *file)
-{
- return single_open(file, cvm_oct_stats_show, NULL);
-}
-
-static const struct file_operations cvm_oct_stats_operations = {
- .open = cvm_oct_stats_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-void cvm_oct_proc_initialize(void)
-{
- struct proc_dir_entry *entry =
- create_proc_entry("octeon_ethernet_stats", 0, NULL);
- if (entry)
- entry->proc_fops = &cvm_oct_stats_operations;
-}
-
-void cvm_oct_proc_shutdown(void)
-{
- remove_proc_entry("octeon_ethernet_stats", NULL);
-}
diff --git a/drivers/staging/octeon/ethernet-proc.h b/drivers/staging/octeon/ethernet-proc.h
deleted file mode 100644
index 82c7d9f78bc4..000000000000
--- a/drivers/staging/octeon/ethernet-proc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*********************************************************************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2007 Cavium Networks
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, Version 2, as
- * published by the Free Software Foundation.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
-*********************************************************************/
-
-void cvm_oct_proc_initialize(void);
-void cvm_oct_proc_shutdown(void);
diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c
index 3820f1ec11d1..a0d4d4b98bdc 100644
--- a/drivers/staging/octeon/ethernet-rgmii.c
+++ b/drivers/staging/octeon/ethernet-rgmii.c
@@ -26,7 +26,7 @@
**********************************************************************/
#include <linux/kernel.h>
#include <linux/netdevice.h>
-#include <linux/mii.h>
+#include <linux/phy.h>
#include <net/dst.h>
#include <asm/octeon/octeon.h>
@@ -48,14 +48,20 @@ static int number_rgmii_ports;
static void cvm_oct_rgmii_poll(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
- unsigned long flags;
+ unsigned long flags = 0;
cvmx_helper_link_info_t link_info;
+ int use_global_register_lock = (priv->phydev == NULL);
- /*
- * Take the global register lock since we are going to touch
- * registers that affect more than one port.
- */
- spin_lock_irqsave(&global_register_lock, flags);
+ BUG_ON(in_interrupt());
+ if (use_global_register_lock) {
+ /*
+ * Take the global register lock since we are going to
+ * touch registers that affect more than one port.
+ */
+ spin_lock_irqsave(&global_register_lock, flags);
+ } else {
+ mutex_lock(&priv->phydev->bus->mdio_lock);
+ }
link_info = cvmx_helper_link_get(priv->port);
if (link_info.u64 == priv->link_info) {
@@ -115,7 +121,11 @@ static void cvm_oct_rgmii_poll(struct net_device *dev)
dev->name);
}
}
- spin_unlock_irqrestore(&global_register_lock, flags);
+
+ if (use_global_register_lock)
+ spin_unlock_irqrestore(&global_register_lock, flags);
+ else
+ mutex_unlock(&priv->phydev->bus->mdio_lock);
return;
}
@@ -151,7 +161,12 @@ static void cvm_oct_rgmii_poll(struct net_device *dev)
link_info = cvmx_helper_link_autoconf(priv->port);
priv->link_info = link_info.u64;
}
- spin_unlock_irqrestore(&global_register_lock, flags);
+
+ if (use_global_register_lock)
+ spin_unlock_irqrestore(&global_register_lock, flags);
+ else {
+ mutex_unlock(&priv->phydev->bus->mdio_lock);
+ }
if (priv->phydev == NULL) {
/* Tell core. */
@@ -213,8 +228,11 @@ static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
struct net_device *dev =
cvm_oct_device[cvmx_helper_get_ipd_port
(interface, index)];
- if (dev)
- cvm_oct_rgmii_poll(dev);
+ struct octeon_ethernet *priv = netdev_priv(dev);
+
+ if (dev && !atomic_read(&cvm_oct_poll_queue_stopping))
+ queue_work(cvm_oct_poll_queue, &priv->port_work);
+
gmx_rx_int_reg.u64 = 0;
gmx_rx_int_reg.s.phy_dupx = 1;
gmx_rx_int_reg.s.phy_link = 1;
@@ -252,8 +270,11 @@ static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
struct net_device *dev =
cvm_oct_device[cvmx_helper_get_ipd_port
(interface, index)];
- if (dev)
- cvm_oct_rgmii_poll(dev);
+ struct octeon_ethernet *priv = netdev_priv(dev);
+
+ if (dev && !atomic_read(&cvm_oct_poll_queue_stopping))
+ queue_work(cvm_oct_poll_queue, &priv->port_work);
+
gmx_rx_int_reg.u64 = 0;
gmx_rx_int_reg.s.phy_dupx = 1;
gmx_rx_int_reg.s.phy_link = 1;
@@ -302,6 +323,12 @@ int cvm_oct_rgmii_stop(struct net_device *dev)
return 0;
}
+static void cvm_oct_rgmii_immediate_poll(struct work_struct *work)
+{
+ struct octeon_ethernet *priv = container_of(work, struct octeon_ethernet, port_work);
+ cvm_oct_rgmii_poll(cvm_oct_device[priv->port]);
+}
+
int cvm_oct_rgmii_init(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
@@ -309,7 +336,7 @@ int cvm_oct_rgmii_init(struct net_device *dev)
cvm_oct_common_init(dev);
dev->netdev_ops->ndo_stop(dev);
-
+ INIT_WORK(&priv->port_work, cvm_oct_rgmii_immediate_poll);
/*
* Due to GMX errata in CN3XXX series chips, it is necessary
* to take the link down immediately when the PHY changes
@@ -397,4 +424,5 @@ void cvm_oct_rgmii_uninit(struct net_device *dev)
number_rgmii_ports--;
if (number_rgmii_ports == 0)
free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);
+ cancel_work_sync(&priv->port_work);
}
diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c
index 1b237b7e689d..cb38f9eb2cc0 100644
--- a/drivers/staging/octeon/ethernet-rx.c
+++ b/drivers/staging/octeon/ethernet-rx.c
@@ -4,7 +4,7 @@
* Contact: support@caviumnetworks.com
* This file is part of the OCTEON SDK
*
- * Copyright (c) 2003-2007 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, Version 2, as
@@ -27,16 +27,14 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cache.h>
+#include <linux/cpumask.h>
#include <linux/netdevice.h>
#include <linux/init.h>
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <linux/string.h>
#include <linux/prefetch.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/seq_file.h>
-#include <linux/proc_fs.h>
+#include <linux/smp.h>
#include <net/dst.h>
#ifdef CONFIG_XFRM
#include <linux/xfrm.h>
@@ -48,8 +46,9 @@
#include <asm/octeon/octeon.h>
#include "ethernet-defines.h"
-#include "octeon-ethernet.h"
#include "ethernet-mem.h"
+#include "ethernet-rx.h"
+#include "octeon-ethernet.h"
#include "ethernet-util.h"
#include "cvmx-helper.h"
@@ -61,62 +60,88 @@
#include "cvmx-gmxx-defs.h"
-struct cvm_tasklet_wrapper {
- struct tasklet_struct t;
-};
+struct cvm_napi_wrapper {
+ struct napi_struct napi;
+} ____cacheline_aligned_in_smp;
-/*
- * Aligning the tasklet_struct on cachline boundries seems to decrease
- * throughput even though in theory it would reduce contantion on the
- * cache lines containing the locks.
- */
+static struct cvm_napi_wrapper cvm_oct_napi[NR_CPUS] __cacheline_aligned_in_smp;
-static struct cvm_tasklet_wrapper cvm_oct_tasklet[NR_CPUS];
+struct cvm_oct_core_state {
+ int baseline_cores;
+ /*
+ * The number of additional cores that could be processing
+ * input packtes.
+ */
+ atomic_t available_cores;
+ cpumask_t cpu_state;
+} ____cacheline_aligned_in_smp;
-/**
- * Interrupt handler. The interrupt occurs whenever the POW
- * transitions from 0->1 packets in our group.
- *
- * @cpl:
- * @dev_id:
- * @regs:
- * Returns
- */
-irqreturn_t cvm_oct_do_interrupt(int cpl, void *dev_id)
+static struct cvm_oct_core_state core_state __cacheline_aligned_in_smp;
+
+static void cvm_oct_enable_napi(void *_)
{
- /* Acknowledge the interrupt */
- if (INTERRUPT_LIMIT)
- cvmx_write_csr(CVMX_POW_WQ_INT, 1 << pow_receive_group);
- else
- cvmx_write_csr(CVMX_POW_WQ_INT, 0x10001 << pow_receive_group);
- preempt_disable();
- tasklet_schedule(&cvm_oct_tasklet[smp_processor_id()].t);
- preempt_enable();
- return IRQ_HANDLED;
+ int cpu = smp_processor_id();
+ napi_schedule(&cvm_oct_napi[cpu].napi);
+}
+
+static void cvm_oct_enable_one_cpu(void)
+{
+ int v;
+ int cpu;
+
+ /* Check to see if more CPUs are available for receive processing... */
+ v = atomic_sub_if_positive(1, &core_state.available_cores);
+ if (v < 0)
+ return;
+
+ /* ... if a CPU is available, Turn on NAPI polling for that CPU. */
+ for_each_online_cpu(cpu) {
+ if (!cpu_test_and_set(cpu, core_state.cpu_state)) {
+ v = smp_call_function_single(cpu, cvm_oct_enable_napi,
+ NULL, 0);
+ if (v)
+ panic("Can't enable NAPI.");
+ break;
+ }
+ }
+}
+
+static void cvm_oct_no_more_work(void)
+{
+ int cpu = smp_processor_id();
+
+ /*
+ * CPU zero is special. It always has the irq enabled when
+ * waiting for incoming packets.
+ */
+ if (cpu == 0) {
+ enable_irq(OCTEON_IRQ_WORKQ0 + pow_receive_group);
+ return;
+ }
+
+ cpu_clear(cpu, core_state.cpu_state);
+ atomic_add(1, &core_state.available_cores);
}
-#ifdef CONFIG_NET_POLL_CONTROLLER
/**
- * This is called when the kernel needs to manually poll the
- * device. For Octeon, this is simply calling the interrupt
- * handler. We actually poll all the devices, not just the
- * one supplied.
+ * cvm_oct_do_interrupt - interrupt handler.
+ *
+ * The interrupt occurs whenever the POW has packets in our group.
*
- * @dev: Device to poll. Unused
*/
-void cvm_oct_poll_controller(struct net_device *dev)
+static irqreturn_t cvm_oct_do_interrupt(int cpl, void *dev_id)
{
- preempt_disable();
- tasklet_schedule(&cvm_oct_tasklet[smp_processor_id()].t);
- preempt_enable();
+ /* Disable the IRQ and start napi_poll. */
+ disable_irq_nosync(OCTEON_IRQ_WORKQ0 + pow_receive_group);
+ cvm_oct_enable_napi(NULL);
+
+ return IRQ_HANDLED;
}
-#endif
/**
- * This is called on receive errors, and determines if the packet
- * can be dropped early-on in cvm_oct_tasklet_rx().
- *
+ * cvm_oct_check_rcv_error - process receive errors
* @work: Work queue entry pointing to the packet.
+ *
* Returns Non-zero if the packet can be dropped, zero otherwise.
*/
static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work)
@@ -199,19 +224,20 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work)
}
/**
- * Tasklet function that is scheduled on a core when an interrupt occurs.
+ * cvm_oct_napi_poll - the NAPI poll function.
+ * @napi: The NAPI instance, or null if called from cvm_oct_poll_controller
+ * @budget: Maximum number of packets to receive.
*
- * @unused:
+ * Returns the number of packets processed.
*/
-void cvm_oct_tasklet_rx(unsigned long unused)
+static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
{
- const int coreid = cvmx_get_core_num();
- uint64_t old_group_mask;
- uint64_t old_scratch;
- int rx_count = 0;
- int number_to_free;
- int num_freed;
- int packet_not_copied;
+ const int coreid = cvmx_get_core_num();
+ uint64_t old_group_mask;
+ uint64_t old_scratch;
+ int rx_count = 0;
+ int did_work_request = 0;
+ int packet_not_copied;
/* Prefetch cvm_oct_device since we know we need it soon */
prefetch(cvm_oct_device);
@@ -227,59 +253,63 @@ void cvm_oct_tasklet_rx(unsigned long unused)
cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid),
(old_group_mask & ~0xFFFFull) | 1 << pow_receive_group);
- if (USE_ASYNC_IOBDMA)
+ if (USE_ASYNC_IOBDMA) {
cvmx_pow_work_request_async(CVMX_SCR_SCRATCH, CVMX_POW_NO_WAIT);
+ did_work_request = 1;
+ }
- while (1) {
+ while (rx_count < budget) {
struct sk_buff *skb = NULL;
+ struct sk_buff **pskb = NULL;
int skb_in_hw;
cvmx_wqe_t *work;
- if (USE_ASYNC_IOBDMA) {
+ if (USE_ASYNC_IOBDMA && did_work_request)
work = cvmx_pow_work_response_async(CVMX_SCR_SCRATCH);
- } else {
- if ((INTERRUPT_LIMIT == 0)
- || likely(rx_count < MAX_RX_PACKETS))
- work =
- cvmx_pow_work_request_sync
- (CVMX_POW_NO_WAIT);
- else
- work = NULL;
- }
+ else
+ work = cvmx_pow_work_request_sync(CVMX_POW_NO_WAIT);
+
prefetch(work);
- if (work == NULL)
+ did_work_request = 0;
+ if (work == NULL) {
+ union cvmx_pow_wq_int wq_int;
+ wq_int.u64 = 0;
+ wq_int.s.iq_dis = 1 << pow_receive_group;
+ wq_int.s.wq_int = 1 << pow_receive_group;
+ cvmx_write_csr(CVMX_POW_WQ_INT, wq_int.u64);
break;
+ }
+ pskb = (struct sk_buff **)(cvm_oct_get_buffer_ptr(work->packet_ptr) - sizeof(void *));
+ prefetch(pskb);
- /*
- * Limit each core to processing MAX_RX_PACKETS
- * packets without a break. This way the RX can't
- * starve the TX task.
- */
- if (USE_ASYNC_IOBDMA) {
-
- if ((INTERRUPT_LIMIT == 0)
- || likely(rx_count < MAX_RX_PACKETS))
- cvmx_pow_work_request_async_nocheck
- (CVMX_SCR_SCRATCH, CVMX_POW_NO_WAIT);
- else {
- cvmx_scratch_write64(CVMX_SCR_SCRATCH,
- 0x8000000000000000ull);
- cvmx_pow_tag_sw_null_nocheck();
- }
+ if (USE_ASYNC_IOBDMA && rx_count < (budget - 1)) {
+ cvmx_pow_work_request_async_nocheck(CVMX_SCR_SCRATCH, CVMX_POW_NO_WAIT);
+ did_work_request = 1;
+ }
+
+ if (rx_count == 0) {
+ /*
+ * First time through, see if there is enough
+ * work waiting to merit waking another
+ * CPU.
+ */
+ union cvmx_pow_wq_int_cntx counts;
+ int backlog;
+ int cores_in_use = core_state.baseline_cores - atomic_read(&core_state.available_cores);
+ counts.u64 = cvmx_read_csr(CVMX_POW_WQ_INT_CNTX(pow_receive_group));
+ backlog = counts.s.iq_cnt + counts.s.ds_cnt;
+ if (backlog > budget * cores_in_use && napi != NULL)
+ cvm_oct_enable_one_cpu();
}
skb_in_hw = USE_SKBUFFS_IN_HW && work->word2.s.bufs == 1;
if (likely(skb_in_hw)) {
- skb =
- *(struct sk_buff
- **)(cvm_oct_get_buffer_ptr(work->packet_ptr) -
- sizeof(void *));
+ skb = *pskb;
prefetch(&skb->head);
prefetch(&skb->len);
}
prefetch(cvm_oct_device[work->ipprt]);
- rx_count++;
/* Immediately throw away all packets with receive errors */
if (unlikely(work->word2.snoip.rcv_error)) {
if (cvm_oct_check_rcv_error(work))
@@ -292,39 +322,27 @@ void cvm_oct_tasklet_rx(unsigned long unused)
* buffer.
*/
if (likely(skb_in_hw)) {
- /*
- * This calculation was changed in case the
- * skb header is using a different address
- * aliasing type than the buffer. It doesn't
- * make any differnece now, but the new one is
- * more correct.
- */
- skb->data =
- skb->head + work->packet_ptr.s.addr -
- cvmx_ptr_to_phys(skb->head);
+ skb->data = skb->head + work->packet_ptr.s.addr - cvmx_ptr_to_phys(skb->head);
prefetch(skb->data);
skb->len = work->len;
skb_set_tail_pointer(skb, skb->len);
packet_not_copied = 1;
} else {
-
/*
* We have to copy the packet. First allocate
* an skbuff for it.
*/
skb = dev_alloc_skb(work->len);
if (!skb) {
- DEBUGPRINT("Port %d failed to allocate "
- "skbuff, packet dropped\n",
- work->ipprt);
+ DEBUGPRINT("Port %d failed to allocate skbuff, packet dropped\n",
+ work->ipprt);
cvm_oct_free_work(work);
continue;
}
/*
* Check if we've received a packet that was
- * entirely stored in the work entry. This is
- * untested.
+ * entirely stored in the work entry.
*/
if (unlikely(work->word2.s.bufs == 0)) {
uint8_t *ptr = work->packet_data;
@@ -343,15 +361,13 @@ void cvm_oct_tasklet_rx(unsigned long unused)
/* No packet buffers to free */
} else {
int segments = work->word2.s.bufs;
- union cvmx_buf_ptr segment_ptr =
- work->packet_ptr;
+ union cvmx_buf_ptr segment_ptr = work->packet_ptr;
int len = work->len;
while (segments--) {
union cvmx_buf_ptr next_ptr =
- *(union cvmx_buf_ptr *)
- cvmx_phys_to_ptr(segment_ptr.s.
- addr - 8);
+ *(union cvmx_buf_ptr *)cvmx_phys_to_ptr(segment_ptr.s.addr - 8);
+
/*
* Octeon Errata PKI-100: The segment size is
* wrong. Until it is fixed, calculate the
@@ -361,22 +377,18 @@ void cvm_oct_tasklet_rx(unsigned long unused)
* one: int segment_size =
* segment_ptr.s.size;
*/
- int segment_size =
- CVMX_FPA_PACKET_POOL_SIZE -
- (segment_ptr.s.addr -
- (((segment_ptr.s.addr >> 7) -
- segment_ptr.s.back) << 7));
- /* Don't copy more than what is left
- in the packet */
+ int segment_size = CVMX_FPA_PACKET_POOL_SIZE -
+ (segment_ptr.s.addr - (((segment_ptr.s.addr >> 7) - segment_ptr.s.back) << 7));
+ /*
+ * Don't copy more than what
+ * is left in the packet.
+ */
if (segment_size > len)
segment_size = len;
/* Copy the data into the packet */
memcpy(skb_put(skb, segment_size),
- cvmx_phys_to_ptr(segment_ptr.s.
- addr),
+ cvmx_phys_to_ptr(segment_ptr.s.addr),
segment_size);
- /* Reduce the amount of bytes left
- to copy */
len -= segment_size;
segment_ptr = next_ptr;
}
@@ -389,16 +401,15 @@ void cvm_oct_tasklet_rx(unsigned long unused)
struct net_device *dev = cvm_oct_device[work->ipprt];
struct octeon_ethernet *priv = netdev_priv(dev);
- /* Only accept packets for devices
- that are currently up */
+ /*
+ * Only accept packets for devices that are
+ * currently up.
+ */
if (likely(dev->flags & IFF_UP)) {
skb->protocol = eth_type_trans(skb, dev);
skb->dev = dev;
- if (unlikely
- (work->word2.s.not_IP
- || work->word2.s.IP_exc
- || work->word2.s.L4_error))
+ if (unlikely(work->word2.s.not_IP || work->word2.s.IP_exc || work->word2.s.L4_error))
skb->ip_summed = CHECKSUM_NONE;
else
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -414,15 +425,13 @@ void cvm_oct_tasklet_rx(unsigned long unused)
#endif
}
netif_receive_skb(skb);
+ rx_count++;
} else {
+ /* Drop any packet received for a device that isn't up */
/*
- * Drop any packet received for a
- * device that isn't up.
- */
- /*
- DEBUGPRINT("%s: Device not up, packet dropped\n",
- dev->name);
- */
+ DEBUGPRINT("%s: Device not up, packet dropped\n",
+ dev->name);
+ */
#ifdef CONFIG_64BIT
atomic64_add(1, (atomic64_t *)&priv->stats.rx_dropped);
#else
@@ -435,9 +444,8 @@ void cvm_oct_tasklet_rx(unsigned long unused)
* Drop any packet received for a device that
* doesn't exist.
*/
- DEBUGPRINT("Port %d not controlled by Linux, packet "
- "dropped\n",
- work->ipprt);
+ DEBUGPRINT("Port %d not controlled by Linux, packet dropped\n",
+ work->ipprt);
dev_kfree_skb_irq(skb);
}
/*
@@ -459,47 +467,93 @@ void cvm_oct_tasklet_rx(unsigned long unused)
cvm_oct_free_work(work);
}
}
-
/* Restore the original POW group mask */
cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), old_group_mask);
if (USE_ASYNC_IOBDMA) {
/* Restore the scratch area */
cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch);
}
+ cvm_oct_rx_refill_pool(0);
- if (USE_SKBUFFS_IN_HW) {
- /* Refill the packet buffer pool */
- number_to_free =
- cvmx_fau_fetch_and_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
-
- if (number_to_free > 0) {
- cvmx_fau_atomic_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE,
- -number_to_free);
- num_freed =
- cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL,
- CVMX_FPA_PACKET_POOL_SIZE,
- number_to_free);
- if (num_freed != number_to_free) {
- cvmx_fau_atomic_add32
- (FAU_NUM_PACKET_BUFFERS_TO_FREE,
- number_to_free - num_freed);
- }
- }
+ if (rx_count < budget && napi != NULL) {
+ /* No more work */
+ napi_complete(napi);
+ cvm_oct_no_more_work();
}
+ return rx_count;
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/**
+ * cvm_oct_poll_controller - poll for receive packets
+ * device.
+ *
+ * @dev: Device to poll. Unused
+ */
+void cvm_oct_poll_controller(struct net_device *dev)
+{
+ cvm_oct_napi_poll(NULL, 16);
+}
+#endif
+
void cvm_oct_rx_initialize(void)
{
int i;
- /* Initialize all of the tasklets */
- for (i = 0; i < NR_CPUS; i++)
- tasklet_init(&cvm_oct_tasklet[i].t, cvm_oct_tasklet_rx, 0);
+ struct net_device *dev_for_napi = NULL;
+ union cvmx_pow_wq_int_thrx int_thr;
+ union cvmx_pow_wq_int_pc int_pc;
+
+ for (i = 0; i < TOTAL_NUMBER_OF_PORTS; i++) {
+ if (cvm_oct_device[i]) {
+ dev_for_napi = cvm_oct_device[i];
+ break;
+ }
+ }
+
+ if (NULL == dev_for_napi)
+ panic("No net_devices were allocated.");
+
+ if (max_rx_cpus > 1 && max_rx_cpus < num_online_cpus())
+ atomic_set(&core_state.available_cores, max_rx_cpus);
+ else
+ atomic_set(&core_state.available_cores, num_online_cpus());
+ core_state.baseline_cores = atomic_read(&core_state.available_cores);
+
+ core_state.cpu_state = CPU_MASK_NONE;
+ for_each_possible_cpu(i) {
+ netif_napi_add(dev_for_napi, &cvm_oct_napi[i].napi,
+ cvm_oct_napi_poll, rx_napi_weight);
+ napi_enable(&cvm_oct_napi[i].napi);
+ }
+ /* Register an IRQ hander for to receive POW interrupts */
+ i = request_irq(OCTEON_IRQ_WORKQ0 + pow_receive_group,
+ cvm_oct_do_interrupt, 0, "Ethernet", cvm_oct_device);
+
+ if (i)
+ panic("Could not acquire Ethernet IRQ %d\n",
+ OCTEON_IRQ_WORKQ0 + pow_receive_group);
+
+ disable_irq_nosync(OCTEON_IRQ_WORKQ0 + pow_receive_group);
+
+ int_thr.u64 = 0;
+ int_thr.s.tc_en = 1;
+ int_thr.s.tc_thr = 1;
+ /* Enable POW interrupt when our port has at least one packet */
+ cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), int_thr.u64);
+
+ int_pc.u64 = 0;
+ int_pc.s.pc_thr = 5;
+ cvmx_write_csr(CVMX_POW_WQ_INT_PC, int_pc.u64);
+
+
+ /* Scheduld NAPI now. This will indirectly enable interrupts. */
+ cvm_oct_enable_one_cpu();
}
void cvm_oct_rx_shutdown(void)
{
int i;
- /* Shutdown all of the tasklets */
- for (i = 0; i < NR_CPUS; i++)
- tasklet_kill(&cvm_oct_tasklet[i].t);
+ /* Shutdown all of the NAPIs */
+ for_each_possible_cpu(i)
+ netif_napi_del(&cvm_oct_napi[i].napi);
}
diff --git a/drivers/staging/octeon/ethernet-rx.h b/drivers/staging/octeon/ethernet-rx.h
index a9b72b87a7a6..a0743b85d54e 100644
--- a/drivers/staging/octeon/ethernet-rx.h
+++ b/drivers/staging/octeon/ethernet-rx.h
@@ -24,10 +24,29 @@
* This file may also be available under a different license from Cavium.
* Contact Cavium Networks for more information
*********************************************************************/
+#include "cvmx-fau.h"
-irqreturn_t cvm_oct_do_interrupt(int cpl, void *dev_id);
void cvm_oct_poll_controller(struct net_device *dev);
-void cvm_oct_tasklet_rx(unsigned long unused);
-
void cvm_oct_rx_initialize(void);
void cvm_oct_rx_shutdown(void);
+
+static inline void cvm_oct_rx_refill_pool(int fill_threshold)
+{
+ int number_to_free;
+ int num_freed;
+ /* Refill the packet buffer pool */
+ number_to_free =
+ cvmx_fau_fetch_and_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
+
+ if (number_to_free > fill_threshold) {
+ cvmx_fau_atomic_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE,
+ -number_to_free);
+ num_freed = cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL,
+ CVMX_FPA_PACKET_POOL_SIZE,
+ number_to_free);
+ if (num_freed != number_to_free) {
+ cvmx_fau_atomic_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE,
+ number_to_free - num_freed);
+ }
+ }
+}
diff --git a/drivers/staging/octeon/ethernet-sgmii.c b/drivers/staging/octeon/ethernet-sgmii.c
index 6061d01eca2d..2d8589eb461e 100644
--- a/drivers/staging/octeon/ethernet-sgmii.c
+++ b/drivers/staging/octeon/ethernet-sgmii.c
@@ -26,7 +26,6 @@
**********************************************************************/
#include <linux/kernel.h>
#include <linux/netdevice.h>
-#include <linux/mii.h>
#include <net/dst.h>
#include <asm/octeon/octeon.h>
diff --git a/drivers/staging/octeon/ethernet-spi.c b/drivers/staging/octeon/ethernet-spi.c
index 00dc0f4bad19..b58b8971f939 100644
--- a/drivers/staging/octeon/ethernet-spi.c
+++ b/drivers/staging/octeon/ethernet-spi.c
@@ -26,7 +26,6 @@
**********************************************************************/
#include <linux/kernel.h>
#include <linux/netdevice.h>
-#include <linux/mii.h>
#include <net/dst.h>
#include <asm/octeon/octeon.h>
diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c
index 535294105f65..afc2b734d554 100644
--- a/drivers/staging/octeon/ethernet-tx.c
+++ b/drivers/staging/octeon/ethernet-tx.c
@@ -4,7 +4,7 @@
* Contact: support@caviumnetworks.com
* This file is part of the OCTEON SDK
*
- * Copyright (c) 2003-2007 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, Version 2, as
@@ -31,10 +31,6 @@
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <linux/string.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/seq_file.h>
-#include <linux/proc_fs.h>
#include <net/dst.h>
#ifdef CONFIG_XFRM
#include <linux/xfrm.h>
@@ -52,11 +48,14 @@
#include "cvmx-wqe.h"
#include "cvmx-fau.h"
+#include "cvmx-pip.h"
#include "cvmx-pko.h"
#include "cvmx-helper.h"
#include "cvmx-gmxx-defs.h"
+#define CVM_OCT_SKB_CB(skb) ((u64 *)((skb)->cb))
+
/*
* You can define GET_SKBUFF_QOS() to override how the skbuff output
* function determines which output queue is used. The default
@@ -68,12 +67,81 @@
#define GET_SKBUFF_QOS(skb) 0
#endif
+static void cvm_oct_tx_do_cleanup(unsigned long arg);
+static DECLARE_TASKLET(cvm_oct_tx_cleanup_tasklet, cvm_oct_tx_do_cleanup, 0);
+
+/* Maximum number of SKBs to try to free per xmit packet. */
+#define MAX_SKB_TO_FREE (MAX_OUT_QUEUE_DEPTH * 2)
+
+static inline int32_t cvm_oct_adjust_skb_to_free(int32_t skb_to_free, int fau)
+{
+ int32_t undo;
+ undo = skb_to_free > 0 ? MAX_SKB_TO_FREE : skb_to_free + MAX_SKB_TO_FREE;
+ if (undo > 0)
+ cvmx_fau_atomic_add32(fau, -undo);
+ skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ? MAX_SKB_TO_FREE : -skb_to_free;
+ return skb_to_free;
+}
+
+static void cvm_oct_kick_tx_poll_watchdog(void)
+{
+ union cvmx_ciu_timx ciu_timx;
+ ciu_timx.u64 = 0;
+ ciu_timx.s.one_shot = 1;
+ ciu_timx.s.len = cvm_oct_tx_poll_interval;
+ cvmx_write_csr(CVMX_CIU_TIMX(1), ciu_timx.u64);
+}
+
+void cvm_oct_free_tx_skbs(struct net_device *dev)
+{
+ int32_t skb_to_free;
+ int qos, queues_per_port;
+ int total_freed = 0;
+ int total_remaining = 0;
+ unsigned long flags;
+ struct octeon_ethernet *priv = netdev_priv(dev);
+
+ queues_per_port = cvmx_pko_get_num_queues(priv->port);
+ /* Drain any pending packets in the free list */
+ for (qos = 0; qos < queues_per_port; qos++) {
+ if (skb_queue_len(&priv->tx_free_list[qos]) == 0)
+ continue;
+ skb_to_free = cvmx_fau_fetch_and_add32(priv->fau+qos*4, MAX_SKB_TO_FREE);
+ skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, priv->fau+qos*4);
+
+
+ total_freed += skb_to_free;
+ if (skb_to_free > 0) {
+ struct sk_buff *to_free_list = NULL;
+ spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
+ while (skb_to_free > 0) {
+ struct sk_buff *t = __skb_dequeue(&priv->tx_free_list[qos]);
+ t->next = to_free_list;
+ to_free_list = t;
+ skb_to_free--;
+ }
+ spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags);
+ /* Do the actual freeing outside of the lock. */
+ while (to_free_list) {
+ struct sk_buff *t = to_free_list;
+ to_free_list = to_free_list->next;
+ dev_kfree_skb_any(t);
+ }
+ }
+ total_remaining += skb_queue_len(&priv->tx_free_list[qos]);
+ }
+ if (total_freed >= 0 && netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+ if (total_remaining)
+ cvm_oct_kick_tx_poll_watchdog();
+}
+
/**
- * Packet transmit
- *
+ * cvm_oct_xmit - transmit a packet
* @skb: Packet to send
* @dev: Device info structure
- * Returns Always returns zero
+ *
+ * Returns Always returns NETDEV_TX_OK
*/
int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -81,13 +149,15 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
union cvmx_buf_ptr hw_buffer;
uint64_t old_scratch;
uint64_t old_scratch2;
- int dropped;
int qos;
- int queue_it_up;
+ int i;
+ enum {QUEUE_CORE, QUEUE_HW, QUEUE_DROP} queue_type;
struct octeon_ethernet *priv = netdev_priv(dev);
+ struct sk_buff *to_free_list;
int32_t skb_to_free;
- int32_t undo;
int32_t buffers_to_free;
+ u32 total_to_clean;
+ unsigned long flags;
#if REUSE_SKBUFFS_WITHOUT_FREE
unsigned char *fpa_head;
#endif
@@ -98,9 +168,6 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
*/
prefetch(priv);
- /* Start off assuming no drop */
- dropped = 0;
-
/*
* The check on CVMX_PKO_QUEUES_PER_PORT_* is designed to
* completely remove "qos" in the event neither interface
@@ -135,6 +202,28 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
}
/*
+ * We have space for 6 segment pointers, If there will be more
+ * than that, we must linearize.
+ */
+ if (unlikely(skb_shinfo(skb)->nr_frags > 5)) {
+ if (unlikely(__skb_linearize(skb))) {
+ queue_type = QUEUE_DROP;
+ if (USE_ASYNC_IOBDMA) {
+ /* Get the number of skbuffs in use by the hardware */
+ CVMX_SYNCIOBDMA;
+ skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
+ } else {
+ /* Get the number of skbuffs in use by the hardware */
+ skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4,
+ MAX_SKB_TO_FREE);
+ }
+ skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, priv->fau + qos * 4);
+ spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
+ goto skip_xmit;
+ }
+ }
+
+ /*
* The CN3XXX series of parts has an errata (GMX-401) which
* causes the GMX block to hang if a collision occurs towards
* the end of a <68 byte packet. As a workaround for this, we
@@ -162,13 +251,6 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
- /* Build the PKO buffer pointer */
- hw_buffer.u64 = 0;
- hw_buffer.s.addr = cvmx_ptr_to_phys(skb->data);
- hw_buffer.s.pool = 0;
- hw_buffer.s.size =
- (unsigned long)skb_end_pointer(skb) - (unsigned long)skb->head;
-
/* Build the PKO command */
pko_command.u64 = 0;
pko_command.s.n2 = 1; /* Don't pollute L2 with the outgoing packet */
@@ -178,7 +260,31 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
pko_command.s.subone0 = 1;
pko_command.s.dontfree = 1;
- pko_command.s.reg0 = priv->fau + qos * 4;
+
+ /* Build the PKO buffer pointer */
+ hw_buffer.u64 = 0;
+ if (skb_shinfo(skb)->nr_frags == 0) {
+ hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)skb->data);
+ hw_buffer.s.pool = 0;
+ hw_buffer.s.size = skb->len;
+ } else {
+ hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)skb->data);
+ hw_buffer.s.pool = 0;
+ hw_buffer.s.size = skb_headlen(skb);
+ CVM_OCT_SKB_CB(skb)[0] = hw_buffer.u64;
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ struct skb_frag_struct *fs = skb_shinfo(skb)->frags + i;
+ hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)(page_address(fs->page) + fs->page_offset));
+ hw_buffer.s.size = fs->size;
+ CVM_OCT_SKB_CB(skb)[i + 1] = hw_buffer.u64;
+ }
+ hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)CVM_OCT_SKB_CB(skb));
+ hw_buffer.s.size = skb_shinfo(skb)->nr_frags + 1;
+ pko_command.s.segs = skb_shinfo(skb)->nr_frags + 1;
+ pko_command.s.gather = 1;
+ goto dont_put_skbuff_in_hw;
+ }
+
/*
* See if we can put this skb in the FPA pool. Any strange
* behavior from the Linux networking stack will most likely
@@ -190,7 +296,7 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
* shown a 25% increase in performance under some loads.
*/
#if REUSE_SKBUFFS_WITHOUT_FREE
- fpa_head = skb->head + 128 - ((unsigned long)skb->head & 0x7f);
+ fpa_head = skb->head + 256 - ((unsigned long)skb->head & 0x7f);
if (unlikely(skb->data < fpa_head)) {
/*
* printk("TX buffer beginning can't meet FPA
@@ -248,10 +354,9 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
* We can use this buffer in the FPA. We don't need the FAU
* update anymore
*/
- pko_command.s.reg0 = 0;
pko_command.s.dontfree = 0;
- hw_buffer.s.back = (skb->data - fpa_head) >> 7;
+ hw_buffer.s.back = ((unsigned long)skb->data >> 7) - ((unsigned long)fpa_head >> 7);
*(struct sk_buff **)(fpa_head - sizeof(void *)) = skb;
/*
@@ -272,16 +377,16 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
skb->tc_verd = 0;
#endif /* CONFIG_NET_CLS_ACT */
#endif /* CONFIG_NET_SCHED */
+#endif /* REUSE_SKBUFFS_WITHOUT_FREE */
dont_put_skbuff_in_hw:
-#endif /* REUSE_SKBUFFS_WITHOUT_FREE */
/* Check if we can use the hardware checksumming */
if (USE_HW_TCPUDP_CHECKSUM && (skb->protocol == htons(ETH_P_IP)) &&
(ip_hdr(skb)->version == 4) && (ip_hdr(skb)->ihl == 5) &&
((ip_hdr(skb)->frag_off == 0) || (ip_hdr(skb)->frag_off == 1 << 14))
- && ((ip_hdr(skb)->protocol == IP_PROTOCOL_TCP)
- || (ip_hdr(skb)->protocol == IP_PROTOCOL_UDP))) {
+ && ((ip_hdr(skb)->protocol == IPPROTO_TCP)
+ || (ip_hdr(skb)->protocol == IPPROTO_UDP))) {
/* Use hardware checksum calc */
pko_command.s.ipoffp1 = sizeof(struct ethhdr) + 1;
}
@@ -299,89 +404,116 @@ dont_put_skbuff_in_hw:
cvmx_fau_fetch_and_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
}
- /*
- * We try to claim MAX_SKB_TO_FREE buffers. If there were not
- * that many available, we have to un-claim (undo) any that
- * were in excess. If skb_to_free is positive we will free
- * that many buffers.
- */
- undo = skb_to_free > 0 ?
- MAX_SKB_TO_FREE : skb_to_free + MAX_SKB_TO_FREE;
- if (undo > 0)
- cvmx_fau_atomic_add32(priv->fau+qos*4, -undo);
- skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ?
- MAX_SKB_TO_FREE : -skb_to_free;
+ skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, priv->fau+qos*4);
/*
* If we're sending faster than the receive can free them then
* don't do the HW free.
*/
- if ((buffers_to_free < -100) && !pko_command.s.dontfree) {
+ if ((buffers_to_free < -100) && !pko_command.s.dontfree)
pko_command.s.dontfree = 1;
- pko_command.s.reg0 = priv->fau + qos * 4;
+
+ if (pko_command.s.dontfree) {
+ queue_type = QUEUE_CORE;
+ pko_command.s.reg0 = priv->fau+qos*4;
+ } else {
+ queue_type = QUEUE_HW;
}
+ if (USE_ASYNC_IOBDMA)
+ cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH, FAU_TOTAL_TX_TO_CLEAN, 1);
- cvmx_pko_send_packet_prepare(priv->port, priv->queue + qos,
- CVMX_PKO_LOCK_CMD_QUEUE);
+ spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
/* Drop this packet if we have too many already queued to the HW */
- if (unlikely
- (skb_queue_len(&priv->tx_free_list[qos]) >= MAX_OUT_QUEUE_DEPTH)) {
- /*
- DEBUGPRINT("%s: Tx dropped. Too many queued\n", dev->name);
- */
- dropped = 1;
+ if (unlikely(skb_queue_len(&priv->tx_free_list[qos]) >= MAX_OUT_QUEUE_DEPTH)) {
+ if (dev->tx_queue_len != 0) {
+ /* Drop the lock when notifying the core. */
+ spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags);
+ netif_stop_queue(dev);
+ spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
+ } else {
+ /* If not using normal queueing. */
+ queue_type = QUEUE_DROP;
+ goto skip_xmit;
+ }
}
+
+ cvmx_pko_send_packet_prepare(priv->port, priv->queue + qos,
+ CVMX_PKO_LOCK_NONE);
+
/* Send the packet to the output queue */
- else if (unlikely
- (cvmx_pko_send_packet_finish
- (priv->port, priv->queue + qos, pko_command, hw_buffer,
- CVMX_PKO_LOCK_CMD_QUEUE))) {
+ if (unlikely(cvmx_pko_send_packet_finish(priv->port,
+ priv->queue + qos,
+ pko_command, hw_buffer,
+ CVMX_PKO_LOCK_NONE))) {
DEBUGPRINT("%s: Failed to send the packet\n", dev->name);
- dropped = 1;
+ queue_type = QUEUE_DROP;
+ }
+skip_xmit:
+ to_free_list = NULL;
+
+ switch (queue_type) {
+ case QUEUE_DROP:
+ skb->next = to_free_list;
+ to_free_list = skb;
+ priv->stats.tx_dropped++;
+ break;
+ case QUEUE_HW:
+ cvmx_fau_atomic_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, -1);
+ break;
+ case QUEUE_CORE:
+ __skb_queue_tail(&priv->tx_free_list[qos], skb);
+ break;
+ default:
+ BUG();
+ }
+
+ while (skb_to_free > 0) {
+ struct sk_buff *t = __skb_dequeue(&priv->tx_free_list[qos]);
+ t->next = to_free_list;
+ to_free_list = t;
+ skb_to_free--;
+ }
+
+ spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags);
+
+ /* Do the actual freeing outside of the lock. */
+ while (to_free_list) {
+ struct sk_buff *t = to_free_list;
+ to_free_list = to_free_list->next;
+ dev_kfree_skb_any(t);
}
if (USE_ASYNC_IOBDMA) {
+ CVMX_SYNCIOBDMA;
+ total_to_clean = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
/* Restore the scratch area */
cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch);
cvmx_scratch_write64(CVMX_SCR_SCRATCH + 8, old_scratch2);
- }
-
- queue_it_up = 0;
- if (unlikely(dropped)) {
- dev_kfree_skb_any(skb);
- priv->stats.tx_dropped++;
} else {
- if (USE_SKBUFFS_IN_HW) {
- /* Put this packet on the queue to be freed later */
- if (pko_command.s.dontfree)
- queue_it_up = 1;
- else
- cvmx_fau_atomic_add32
- (FAU_NUM_PACKET_BUFFERS_TO_FREE, -1);
- } else {
- /* Put this packet on the queue to be freed later */
- queue_it_up = 1;
- }
+ total_to_clean = cvmx_fau_fetch_and_add32(FAU_TOTAL_TX_TO_CLEAN, 1);
}
- if (queue_it_up) {
- spin_lock(&priv->tx_free_list[qos].lock);
- __skb_queue_tail(&priv->tx_free_list[qos], skb);
- cvm_oct_free_tx_skbs(priv, skb_to_free, qos, 0);
- spin_unlock(&priv->tx_free_list[qos].lock);
- } else {
- cvm_oct_free_tx_skbs(priv, skb_to_free, qos, 1);
+ if (total_to_clean & 0x3ff) {
+ /*
+ * Schedule the cleanup tasklet every 1024 packets for
+ * the pathological case of high traffic on one port
+ * delaying clean up of packets on a different port
+ * that is blocked waiting for the cleanup.
+ */
+ tasklet_schedule(&cvm_oct_tx_cleanup_tasklet);
}
- return 0;
+ cvm_oct_kick_tx_poll_watchdog();
+
+ return NETDEV_TX_OK;
}
/**
- * Packet transmit to the POW
- *
+ * cvm_oct_xmit_pow - transmit a packet to the POW
* @skb: Packet to send
* @dev: Device info structure
+
* Returns Always returns zero
*/
int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev)
@@ -459,8 +591,8 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev)
work->word2.s.dec_ipcomp = 0; /* FIXME */
#endif
work->word2.s.tcp_or_udp =
- (ip_hdr(skb)->protocol == IP_PROTOCOL_TCP)
- || (ip_hdr(skb)->protocol == IP_PROTOCOL_UDP);
+ (ip_hdr(skb)->protocol == IPPROTO_TCP)
+ || (ip_hdr(skb)->protocol == IPPROTO_UDP);
#if 0
/* FIXME */
work->word2.s.dec_ipsec = 0;
@@ -529,116 +661,63 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev)
}
/**
- * Transmit a work queue entry out of the ethernet port. Both
- * the work queue entry and the packet data can optionally be
- * freed. The work will be freed on error as well.
- *
- * @dev: Device to transmit out.
- * @work_queue_entry:
- * Work queue entry to send
- * @do_free: True if the work queue entry and packet data should be
- * freed. If false, neither will be freed.
- * @qos: Index into the queues for this port to transmit on. This
- * is used to implement QoS if their are multiple queues per
- * port. This parameter must be between 0 and the number of
- * queues per port minus 1. Values outside of this range will
- * be change to zero.
+ * cvm_oct_tx_shutdown_dev - free all skb that are currently queued for TX.
+ * @dev: Device being shutdown
*
- * Returns Zero on success, negative on failure.
*/
-int cvm_oct_transmit_qos(struct net_device *dev, void *work_queue_entry,
- int do_free, int qos)
+void cvm_oct_tx_shutdown_dev(struct net_device *dev)
{
- unsigned long flags;
- union cvmx_buf_ptr hw_buffer;
- cvmx_pko_command_word0_t pko_command;
- int dropped;
struct octeon_ethernet *priv = netdev_priv(dev);
- cvmx_wqe_t *work = work_queue_entry;
+ unsigned long flags;
+ int qos;
- if (!(dev->flags & IFF_UP)) {
- DEBUGPRINT("%s: Device not up\n", dev->name);
- if (do_free)
- cvm_oct_free_work(work);
- return -1;
+ for (qos = 0; qos < 16; qos++) {
+ spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
+ while (skb_queue_len(&priv->tx_free_list[qos]))
+ dev_kfree_skb_any(__skb_dequeue
+ (&priv->tx_free_list[qos]));
+ spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags);
}
+}
- /* The check on CVMX_PKO_QUEUES_PER_PORT_* is designed to completely
- remove "qos" in the event neither interface supports
- multiple queues per port */
- if ((CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 > 1) ||
- (CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 > 1)) {
- if (qos <= 0)
- qos = 0;
- else if (qos >= cvmx_pko_get_num_queues(priv->port))
- qos = 0;
- } else
- qos = 0;
-
- /* Start off assuming no drop */
- dropped = 0;
-
- local_irq_save(flags);
- cvmx_pko_send_packet_prepare(priv->port, priv->queue + qos,
- CVMX_PKO_LOCK_CMD_QUEUE);
-
- /* Build the PKO buffer pointer */
- hw_buffer.u64 = 0;
- hw_buffer.s.addr = work->packet_ptr.s.addr;
- hw_buffer.s.pool = CVMX_FPA_PACKET_POOL;
- hw_buffer.s.size = CVMX_FPA_PACKET_POOL_SIZE;
- hw_buffer.s.back = work->packet_ptr.s.back;
+static void cvm_oct_tx_do_cleanup(unsigned long arg)
+{
+ int port;
- /* Build the PKO command */
- pko_command.u64 = 0;
- pko_command.s.n2 = 1; /* Don't pollute L2 with the outgoing packet */
- pko_command.s.dontfree = !do_free;
- pko_command.s.segs = work->word2.s.bufs;
- pko_command.s.total_bytes = work->len;
+ for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) {
+ if (cvm_oct_device[port]) {
+ struct net_device *dev = cvm_oct_device[port];
+ cvm_oct_free_tx_skbs(dev);
+ }
+ }
+}
- /* Check if we can use the hardware checksumming */
- if (unlikely(work->word2.s.not_IP || work->word2.s.IP_exc))
- pko_command.s.ipoffp1 = 0;
- else
- pko_command.s.ipoffp1 = sizeof(struct ethhdr) + 1;
+static irqreturn_t cvm_oct_tx_cleanup_watchdog(int cpl, void *dev_id)
+{
+ /* Disable the interrupt. */
+ cvmx_write_csr(CVMX_CIU_TIMX(1), 0);
+ /* Do the work in the tasklet. */
+ tasklet_schedule(&cvm_oct_tx_cleanup_tasklet);
+ return IRQ_HANDLED;
+}
- /* Send the packet to the output queue */
- if (unlikely
- (cvmx_pko_send_packet_finish
- (priv->port, priv->queue + qos, pko_command, hw_buffer,
- CVMX_PKO_LOCK_CMD_QUEUE))) {
- DEBUGPRINT("%s: Failed to send the packet\n", dev->name);
- dropped = -1;
- }
- local_irq_restore(flags);
+void cvm_oct_tx_initialize(void)
+{
+ int i;
- if (unlikely(dropped)) {
- if (do_free)
- cvm_oct_free_work(work);
- priv->stats.tx_dropped++;
- } else if (do_free)
- cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1));
+ /* Disable the interrupt. */
+ cvmx_write_csr(CVMX_CIU_TIMX(1), 0);
+ /* Register an IRQ hander for to receive CIU_TIMX(1) interrupts */
+ i = request_irq(OCTEON_IRQ_TIMER1,
+ cvm_oct_tx_cleanup_watchdog, 0,
+ "Ethernet", cvm_oct_device);
- return dropped;
+ if (i)
+ panic("Could not acquire Ethernet IRQ %d\n", OCTEON_IRQ_TIMER1);
}
-EXPORT_SYMBOL(cvm_oct_transmit_qos);
-/**
- * This function frees all skb that are currently queued for TX.
- *
- * @dev: Device being shutdown
- */
-void cvm_oct_tx_shutdown(struct net_device *dev)
+void cvm_oct_tx_shutdown(void)
{
- struct octeon_ethernet *priv = netdev_priv(dev);
- unsigned long flags;
- int qos;
-
- for (qos = 0; qos < 16; qos++) {
- spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
- while (skb_queue_len(&priv->tx_free_list[qos]))
- dev_kfree_skb_any(__skb_dequeue
- (&priv->tx_free_list[qos]));
- spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags);
- }
+ /* Free the interrupt handler */
+ free_irq(OCTEON_IRQ_TIMER1, cvm_oct_device);
}
diff --git a/drivers/staging/octeon/ethernet-tx.h b/drivers/staging/octeon/ethernet-tx.h
index c0bebf750bc0..547680c6c371 100644
--- a/drivers/staging/octeon/ethernet-tx.h
+++ b/drivers/staging/octeon/ethernet-tx.h
@@ -29,29 +29,6 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev);
int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev);
int cvm_oct_transmit_qos(struct net_device *dev, void *work_queue_entry,
int do_free, int qos);
-void cvm_oct_tx_shutdown(struct net_device *dev);
-
-/**
- * Free dead transmit skbs.
- *
- * @priv: The driver data
- * @skb_to_free: The number of SKBs to free (free none if negative).
- * @qos: The queue to free from.
- * @take_lock: If true, acquire the skb list lock.
- */
-static inline void cvm_oct_free_tx_skbs(struct octeon_ethernet *priv,
- int skb_to_free,
- int qos, int take_lock)
-{
- /* Free skbuffs not in use by the hardware. */
- if (skb_to_free > 0) {
- if (take_lock)
- spin_lock(&priv->tx_free_list[qos].lock);
- while (skb_to_free > 0) {
- dev_kfree_skb(__skb_dequeue(&priv->tx_free_list[qos]));
- skb_to_free--;
- }
- if (take_lock)
- spin_unlock(&priv->tx_free_list[qos].lock);
- }
-}
+void cvm_oct_tx_initialize(void);
+void cvm_oct_tx_shutdown(void);
+void cvm_oct_tx_shutdown_dev(struct net_device *dev);
diff --git a/drivers/staging/octeon/ethernet-util.h b/drivers/staging/octeon/ethernet-util.h
index 37b665918000..23467563fe57 100644
--- a/drivers/staging/octeon/ethernet-util.h
+++ b/drivers/staging/octeon/ethernet-util.h
@@ -30,10 +30,9 @@
} while (0)
/**
- * Given a packet data address, return a pointer to the
- * beginning of the packet buffer.
- *
+ * cvm_oct_get_buffer_ptr - convert packet data address to pointer
* @packet_ptr: Packet data hardware address
+ *
* Returns Packet buffer pointer
*/
static inline void *cvm_oct_get_buffer_ptr(union cvmx_buf_ptr packet_ptr)
@@ -43,9 +42,7 @@ static inline void *cvm_oct_get_buffer_ptr(union cvmx_buf_ptr packet_ptr)
}
/**
- * Given an IPD/PKO port number, return the logical interface it is
- * on.
- *
+ * INTERFACE - convert IPD port to locgical interface
* @ipd_port: Port to check
*
* Returns Logical interface
@@ -65,9 +62,7 @@ static inline int INTERFACE(int ipd_port)
}
/**
- * Given an IPD/PKO port number, return the port's index on a
- * logical interface.
- *
+ * INDEX - convert IPD/PKO port number to the port's interface index
* @ipd_port: Port to check
*
* Returns Index into interface port list
diff --git a/drivers/staging/octeon/ethernet-xaui.c b/drivers/staging/octeon/ethernet-xaui.c
index ee3dc41b2c53..3fca1cc31ed8 100644
--- a/drivers/staging/octeon/ethernet-xaui.c
+++ b/drivers/staging/octeon/ethernet-xaui.c
@@ -26,7 +26,6 @@
**********************************************************************/
#include <linux/kernel.h>
#include <linux/netdevice.h>
-#include <linux/mii.h>
#include <net/dst.h>
#include <asm/octeon/octeon.h>
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index 4cfd4b136b32..4a2161f70c7f 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -29,7 +29,6 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/delay.h>
#include <linux/phy.h>
#include <net/dst.h>
@@ -43,8 +42,6 @@
#include "ethernet-tx.h"
#include "ethernet-mdio.h"
#include "ethernet-util.h"
-#include "ethernet-proc.h"
-
#include "cvmx-pip.h"
#include "cvmx-pko.h"
@@ -104,13 +101,15 @@ MODULE_PARM_DESC(pow_send_list, "\n"
"\t\"eth2,spi3,spi7\" would cause these three devices to transmit\n"
"\tusing the pow_send_group.");
-static int disable_core_queueing = 1;
-module_param(disable_core_queueing, int, 0444);
-MODULE_PARM_DESC(disable_core_queueing, "\n"
- "\tWhen set the networking core's tx_queue_len is set to zero. This\n"
- "\tallows packets to be sent without lock contention in the packet\n"
- "\tscheduler resulting in some cases in improved throughput.\n");
+int max_rx_cpus = -1;
+module_param(max_rx_cpus, int, 0444);
+MODULE_PARM_DESC(max_rx_cpus, "\n"
+ "\t\tThe maximum number of CPUs to use for packet reception.\n"
+ "\t\tUse -1 to use all available CPUs.");
+int rx_napi_weight = 32;
+module_param(rx_napi_weight, int, 0444);
+MODULE_PARM_DESC(rx_napi_weight, "The NAPI WEIGHT parameter.");
/*
* The offset from mac_addr_base that should be used for the next port
@@ -122,9 +121,16 @@ MODULE_PARM_DESC(disable_core_queueing, "\n"
static unsigned int cvm_oct_mac_addr_offset;
/**
- * Periodic timer to check auto negotiation
+ * cvm_oct_poll_queue - Workqueue for polling operations.
+ */
+struct workqueue_struct *cvm_oct_poll_queue;
+
+/**
+ * cvm_oct_poll_queue_stopping - flag to indicate polling should stop.
+ *
+ * Set to one right before cvm_oct_poll_queue is destroyed.
*/
-static struct timer_list cvm_oct_poll_timer;
+atomic_t cvm_oct_poll_queue_stopping = ATOMIC_INIT(0);
/**
* Array of every ethernet device owned by this driver indexed by
@@ -132,65 +138,44 @@ static struct timer_list cvm_oct_poll_timer;
*/
struct net_device *cvm_oct_device[TOTAL_NUMBER_OF_PORTS];
-/**
- * Periodic timer tick for slow management operations
- *
- * @arg: Device to check
- */
-static void cvm_do_timer(unsigned long arg)
+u64 cvm_oct_tx_poll_interval;
+
+static void cvm_oct_rx_refill_worker(struct work_struct *work);
+static DECLARE_DELAYED_WORK(cvm_oct_rx_refill_work, cvm_oct_rx_refill_worker);
+
+static void cvm_oct_rx_refill_worker(struct work_struct *work)
{
- int32_t skb_to_free, undo;
- int queues_per_port;
- int qos;
- struct octeon_ethernet *priv;
- static int port;
+ /*
+ * FPA 0 may have been drained, try to refill it if we need
+ * more than num_packet_buffers / 2, otherwise normal receive
+ * processing will refill it. If it were drained, no packets
+ * could be received so cvm_oct_napi_poll would never be
+ * invoked to do the refill.
+ */
+ cvm_oct_rx_refill_pool(num_packet_buffers / 2);
- if (port >= CVMX_PIP_NUM_INPUT_PORTS) {
- /*
- * All ports have been polled. Start the next
- * iteration through the ports in one second.
- */
- port = 0;
- mod_timer(&cvm_oct_poll_timer, jiffies + HZ);
- return;
- }
- if (!cvm_oct_device[port])
- goto out;
+ if (!atomic_read(&cvm_oct_poll_queue_stopping))
+ queue_delayed_work(cvm_oct_poll_queue,
+ &cvm_oct_rx_refill_work, HZ);
+}
+
+static void cvm_oct_periodic_worker(struct work_struct *work)
+{
+ struct octeon_ethernet *priv = container_of(work,
+ struct octeon_ethernet,
+ port_periodic_work.work);
- priv = netdev_priv(cvm_oct_device[port]);
if (priv->poll)
- priv->poll(cvm_oct_device[port]);
-
- queues_per_port = cvmx_pko_get_num_queues(port);
- /* Drain any pending packets in the free list */
- for (qos = 0; qos < queues_per_port; qos++) {
- if (skb_queue_len(&priv->tx_free_list[qos]) == 0)
- continue;
- skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4,
- MAX_SKB_TO_FREE);
- undo = skb_to_free > 0 ?
- MAX_SKB_TO_FREE : skb_to_free + MAX_SKB_TO_FREE;
- if (undo > 0)
- cvmx_fau_atomic_add32(priv->fau+qos*4, -undo);
- skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ?
- MAX_SKB_TO_FREE : -skb_to_free;
- cvm_oct_free_tx_skbs(priv, skb_to_free, qos, 1);
- }
- cvm_oct_device[port]->netdev_ops->ndo_get_stats(cvm_oct_device[port]);
+ priv->poll(cvm_oct_device[priv->port]);
-out:
- port++;
- /* Poll the next port in a 50th of a second.
- This spreads the polling of ports out a little bit */
- mod_timer(&cvm_oct_poll_timer, jiffies + HZ / 50);
-}
+ cvm_oct_device[priv->port]->netdev_ops->ndo_get_stats(cvm_oct_device[priv->port]);
+
+ if (!atomic_read(&cvm_oct_poll_queue_stopping))
+ queue_delayed_work(cvm_oct_poll_queue, &priv->port_periodic_work, HZ);
+ }
-/**
- * Configure common hardware for all interfaces
- */
static __init void cvm_oct_configure_common_hw(void)
{
- int r;
/* Setup the FPA */
cvmx_fpa_enable();
cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE,
@@ -205,28 +190,13 @@ static __init void cvm_oct_configure_common_hw(void)
cvmx_helper_setup_red(num_packet_buffers / 4,
num_packet_buffers / 8);
- /* Enable the MII interface */
- if (!octeon_is_simulation())
- cvmx_write_csr(CVMX_SMIX_EN(0), 1);
-
- /* Register an IRQ hander for to receive POW interrupts */
- r = request_irq(OCTEON_IRQ_WORKQ0 + pow_receive_group,
- cvm_oct_do_interrupt, IRQF_SHARED, "Ethernet",
- cvm_oct_device);
-
-#if defined(CONFIG_SMP) && 0
- if (USE_MULTICORE_RECEIVE) {
- irq_set_affinity(OCTEON_IRQ_WORKQ0 + pow_receive_group,
- cpu_online_mask);
- }
-#endif
}
/**
- * Free a work queue entry received in a intercept callback.
+ * cvm_oct_free_work- Free a work queue entry
+ *
+ * @work_queue_entry: Work queue entry to free
*
- * @work_queue_entry:
- * Work queue entry to free
* Returns Zero on success, Negative on failure.
*/
int cvm_oct_free_work(void *work_queue_entry)
@@ -253,9 +223,9 @@ int cvm_oct_free_work(void *work_queue_entry)
EXPORT_SYMBOL(cvm_oct_free_work);
/**
- * Get the low level ethernet statistics
- *
+ * cvm_oct_common_get_stats - get the low level ethernet statistics
* @dev: Device to get the statistics from
+ *
* Returns Pointer to the statistics
*/
static struct net_device_stats *cvm_oct_common_get_stats(struct net_device *dev)
@@ -299,8 +269,7 @@ static struct net_device_stats *cvm_oct_common_get_stats(struct net_device *dev)
}
/**
- * Change the link MTU. Unimplemented
- *
+ * cvm_oct_common_change_mtu - change the link MTU
* @dev: Device to change
* @new_mtu: The new MTU
*
@@ -364,8 +333,7 @@ static int cvm_oct_common_change_mtu(struct net_device *dev, int new_mtu)
}
/**
- * Set the multicast list. Currently unimplemented.
- *
+ * cvm_oct_common_set_multicast_list - set the multicast list
* @dev: Device to work on
*/
static void cvm_oct_common_set_multicast_list(struct net_device *dev)
@@ -382,7 +350,7 @@ static void cvm_oct_common_set_multicast_list(struct net_device *dev)
control.u64 = 0;
control.s.bcst = 1; /* Allow broadcast MAC addresses */
- if (dev->mc_list || (dev->flags & IFF_ALLMULTI) ||
+ if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI) ||
(dev->flags & IFF_PROMISC))
/* Force accept multicast packets */
control.s.mcst = 2;
@@ -420,10 +388,10 @@ static void cvm_oct_common_set_multicast_list(struct net_device *dev)
}
/**
- * Set the hardware MAC address for a device
- *
- * @dev: Device to change the MAC address for
- * @addr: Address structure to change it too. MAC address is addr + 2.
+ * cvm_oct_common_set_mac_address - set the hardware MAC address for a device
+ * @dev: The device in question.
+ * @addr: Address structure to change it too.
+
* Returns Zero on success
*/
static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
@@ -470,9 +438,9 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
}
/**
- * Per network device initialization
- *
+ * cvm_oct_common_init - per network device initialization
* @dev: Device to initialize
+ *
* Returns Zero on success
*/
int cvm_oct_common_init(struct net_device *dev)
@@ -510,8 +478,11 @@ int cvm_oct_common_init(struct net_device *dev)
&& (always_use_pow || strstr(pow_send_list, dev->name)))
priv->queue = -1;
- if (priv->queue != -1 && USE_HW_TCPUDP_CHECKSUM)
- dev->features |= NETIF_F_IP_CSUM;
+ if (priv->queue != -1) {
+ dev->features |= NETIF_F_SG;
+ if (USE_HW_TCPUDP_CHECKSUM)
+ dev->features |= NETIF_F_IP_CSUM;
+ }
/* We do our own locking, Linux doesn't need to */
dev->features |= NETIF_F_LLTX;
@@ -625,12 +596,6 @@ static const struct net_device_ops cvm_oct_pow_netdev_ops = {
extern void octeon_mdiobus_force_mod_depencency(void);
-/**
- * Module/ driver initialization. Creates the linux network
- * devices.
- *
- * Returns Zero on success
- */
static int __init cvm_oct_init_module(void)
{
int num_interfaces;
@@ -648,8 +613,12 @@ static int __init cvm_oct_init_module(void)
else
cvm_oct_mac_addr_offset = 0;
- cvm_oct_proc_initialize();
- cvm_oct_rx_initialize();
+ cvm_oct_poll_queue = create_singlethread_workqueue("octeon-ethernet");
+ if (cvm_oct_poll_queue == NULL) {
+ pr_err("octeon-ethernet: Cannot create workqueue");
+ return -ENOMEM;
+ }
+
cvm_oct_configure_common_hw();
cvmx_helper_initialize_packet_io_global();
@@ -682,6 +651,9 @@ static int __init cvm_oct_init_module(void)
*/
cvmx_fau_atomic_write32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
+ /* Initialize the FAU used for counting tx SKBs that need to be freed */
+ cvmx_fau_atomic_write32(FAU_TOTAL_TX_TO_CLEAN, 0);
+
if ((pow_send_group != -1)) {
struct net_device *dev;
pr_info("\tConfiguring device for POW only access\n");
@@ -689,7 +661,6 @@ static int __init cvm_oct_init_module(void)
if (dev) {
/* Initialize the device private structure. */
struct octeon_ethernet *priv = netdev_priv(dev);
- memset(priv, 0, sizeof(struct octeon_ethernet));
dev->netdev_ops = &cvm_oct_pow_netdev_ops;
priv->imode = CVMX_HELPER_INTERFACE_MODE_DISABLED;
@@ -700,19 +671,16 @@ static int __init cvm_oct_init_module(void)
skb_queue_head_init(&priv->tx_free_list[qos]);
if (register_netdev(dev) < 0) {
- pr_err("Failed to register ethernet "
- "device for POW\n");
+ pr_err("Failed to register ethernet device for POW\n");
kfree(dev);
} else {
cvm_oct_device[CVMX_PIP_NUM_INPUT_PORTS] = dev;
- pr_info("%s: POW send group %d, receive "
- "group %d\n",
- dev->name, pow_send_group,
- pow_receive_group);
+ pr_info("%s: POW send group %d, receive group %d\n",
+ dev->name, pow_send_group,
+ pow_receive_group);
}
} else {
- pr_err("Failed to allocate ethernet device "
- "for POW\n");
+ pr_err("Failed to allocate ethernet device for POW\n");
}
}
@@ -730,17 +698,15 @@ static int __init cvm_oct_init_module(void)
struct net_device *dev =
alloc_etherdev(sizeof(struct octeon_ethernet));
if (!dev) {
- pr_err("Failed to allocate ethernet device "
- "for port %d\n", port);
+ pr_err("Failed to allocate ethernet device for port %d\n", port);
continue;
}
- if (disable_core_queueing)
- dev->tx_queue_len = 0;
/* Initialize the device private structure. */
priv = netdev_priv(dev);
- memset(priv, 0, sizeof(struct octeon_ethernet));
+ INIT_DELAYED_WORK(&priv->port_periodic_work,
+ cvm_oct_periodic_worker);
priv->imode = imode;
priv->port = port;
priv->queue = cvmx_pko_get_base_queue(priv->port);
@@ -803,44 +769,25 @@ static int __init cvm_oct_init_module(void)
fau -=
cvmx_pko_get_num_queues(priv->port) *
sizeof(uint32_t);
+ queue_delayed_work(cvm_oct_poll_queue,
+ &priv->port_periodic_work, HZ);
}
}
}
- if (INTERRUPT_LIMIT) {
- /*
- * Set the POW timer rate to give an interrupt at most
- * INTERRUPT_LIMIT times per second.
- */
- cvmx_write_csr(CVMX_POW_WQ_INT_PC,
- octeon_bootinfo->eclock_hz / (INTERRUPT_LIMIT *
- 16 * 256) << 8);
+ cvm_oct_tx_initialize();
+ cvm_oct_rx_initialize();
- /*
- * Enable POW timer interrupt. It will count when
- * there are packets available.
- */
- cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group),
- 0x1ful << 24);
- } else {
- /* Enable POW interrupt when our port has at least one packet */
- cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1001);
- }
+ /*
+ * 150 uS: about 10 1500-byte packtes at 1GE.
+ */
+ cvm_oct_tx_poll_interval = 150 * (octeon_get_clock_rate() / 1000000);
- /* Enable the poll timer for checking RGMII status */
- init_timer(&cvm_oct_poll_timer);
- cvm_oct_poll_timer.data = 0;
- cvm_oct_poll_timer.function = cvm_do_timer;
- mod_timer(&cvm_oct_poll_timer, jiffies + HZ);
+ queue_delayed_work(cvm_oct_poll_queue, &cvm_oct_rx_refill_work, HZ);
return 0;
}
-/**
- * Module / driver shutdown
- *
- * Returns Zero on success
- */
static void __exit cvm_oct_cleanup_module(void)
{
int port;
@@ -853,22 +800,31 @@ static void __exit cvm_oct_cleanup_module(void)
/* Free the interrupt handler */
free_irq(OCTEON_IRQ_WORKQ0 + pow_receive_group, cvm_oct_device);
- del_timer(&cvm_oct_poll_timer);
+ atomic_inc_return(&cvm_oct_poll_queue_stopping);
+ cancel_delayed_work_sync(&cvm_oct_rx_refill_work);
+
cvm_oct_rx_shutdown();
+ cvm_oct_tx_shutdown();
+
cvmx_pko_disable();
/* Free the ethernet devices */
for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) {
if (cvm_oct_device[port]) {
- cvm_oct_tx_shutdown(cvm_oct_device[port]);
- unregister_netdev(cvm_oct_device[port]);
- kfree(cvm_oct_device[port]);
+ struct net_device *dev = cvm_oct_device[port];
+ struct octeon_ethernet *priv = netdev_priv(dev);
+ cancel_delayed_work_sync(&priv->port_periodic_work);
+
+ cvm_oct_tx_shutdown_dev(dev);
+ unregister_netdev(dev);
+ kfree(dev);
cvm_oct_device[port] = NULL;
}
}
+ destroy_workqueue(cvm_oct_poll_queue);
+
cvmx_pko_shutdown();
- cvm_oct_proc_shutdown();
cvmx_ipd_free_ptr();
diff --git a/drivers/staging/octeon/octeon-ethernet.h b/drivers/staging/octeon/octeon-ethernet.h
index 402a15b9bb0e..d58192563552 100644
--- a/drivers/staging/octeon/octeon-ethernet.h
+++ b/drivers/staging/octeon/octeon-ethernet.h
@@ -4,7 +4,7 @@
* Contact: support@caviumnetworks.com
* This file is part of the OCTEON SDK
*
- * Copyright (c) 2003-2007 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, Version 2, as
@@ -57,58 +57,12 @@ struct octeon_ethernet {
uint64_t link_info;
/* Called periodically to check link status */
void (*poll) (struct net_device *dev);
+ struct delayed_work port_periodic_work;
+ struct work_struct port_work; /* may be unused. */
};
-/**
- * Free a work queue entry received in a intercept callback.
- *
- * @work_queue_entry:
- * Work queue entry to free
- * Returns Zero on success, Negative on failure.
- */
int cvm_oct_free_work(void *work_queue_entry);
-/**
- * Transmit a work queue entry out of the ethernet port. Both
- * the work queue entry and the packet data can optionally be
- * freed. The work will be freed on error as well.
- *
- * @dev: Device to transmit out.
- * @work_queue_entry:
- * Work queue entry to send
- * @do_free: True if the work queue entry and packet data should be
- * freed. If false, neither will be freed.
- * @qos: Index into the queues for this port to transmit on. This
- * is used to implement QoS if their are multiple queues per
- * port. This parameter must be between 0 and the number of
- * queues per port minus 1. Values outside of this range will
- * be change to zero.
- *
- * Returns Zero on success, negative on failure.
- */
-int cvm_oct_transmit_qos(struct net_device *dev, void *work_queue_entry,
- int do_free, int qos);
-
-/**
- * Transmit a work queue entry out of the ethernet port. Both
- * the work queue entry and the packet data can optionally be
- * freed. The work will be freed on error as well. This simply
- * wraps cvmx_oct_transmit_qos() for backwards compatability.
- *
- * @dev: Device to transmit out.
- * @work_queue_entry:
- * Work queue entry to send
- * @do_free: True if the work queue entry and packet data should be
- * freed. If false, neither will be freed.
- *
- * Returns Zero on success, negative on failure.
- */
-static inline int cvm_oct_transmit(struct net_device *dev,
- void *work_queue_entry, int do_free)
-{
- return cvm_oct_transmit_qos(dev, work_queue_entry, do_free, 0);
-}
-
extern int cvm_oct_rgmii_init(struct net_device *dev);
extern void cvm_oct_rgmii_uninit(struct net_device *dev);
extern int cvm_oct_rgmii_open(struct net_device *dev);
@@ -134,5 +88,11 @@ extern int pow_send_group;
extern int pow_receive_group;
extern char pow_send_list[];
extern struct net_device *cvm_oct_device[];
+extern struct workqueue_struct *cvm_oct_poll_queue;
+extern atomic_t cvm_oct_poll_queue_stopping;
+extern u64 cvm_oct_tx_poll_interval;
+
+extern int max_rx_cpus;
+extern int rx_napi_weight;
#endif
diff --git a/drivers/staging/otus/80211core/cagg.c b/drivers/staging/otus/80211core/cagg.c
index dbd0a5f0fcdf..f9514c06c14c 100644
--- a/drivers/staging/otus/80211core/cagg.c
+++ b/drivers/staging/otus/80211core/cagg.c
@@ -1832,14 +1832,12 @@ u16_t zfAggRxClear(zdev_t* dev, u32_t time)
struct agg_tid_rx* zfAggRxEnabled(zdev_t* dev, zbuf_t* buf)
{
- u16_t dst0, src[3], ac, aid, fragOff;
- u8_t up;
+ u16_t dst0, src[3], aid;
u16_t offset = 0;
u16_t seq_no;
u16_t frameType;
u16_t frameCtrl;
u16_t frameSubtype;
- u32_t tcp_seq;
//struct aggSta *agg_sta;
#if ZM_AGG_FPGA_REORDERING
struct agg_tid_rx *tid_rx;
@@ -1864,13 +1862,17 @@ struct agg_tid_rx* zfAggRxEnabled(zdev_t* dev, zbuf_t* buf)
return NULL;
}
#ifdef ZM_ENABLE_PERFORMANCE_EVALUATION
- tcp_seq = zmw_rx_buf_readb(dev, buf, 22+36) << 24;
- tcp_seq += zmw_rx_buf_readb(dev, buf, 22+37) << 16;
- tcp_seq += zmw_rx_buf_readb(dev, buf, 22+38) << 8;
- tcp_seq += zmw_rx_buf_readb(dev, buf, 22+39);
+ {
+ u32_t tcp_seq;
+
+ tcp_seq = zmw_rx_buf_readb(dev, buf, 22+36) << 24;
+ tcp_seq += zmw_rx_buf_readb(dev, buf, 22+37) << 16;
+ tcp_seq += zmw_rx_buf_readb(dev, buf, 22+38) << 8;
+ tcp_seq += zmw_rx_buf_readb(dev, buf, 22+39);
+ ZM_SEQ_DEBUG("In %5d, %12u\n", seq_no, tcp_seq);
+ }
#endif
- ZM_SEQ_DEBUG("In %5d, %12u\n", seq_no, tcp_seq);
dst0 = zmw_rx_buf_readh(dev, buf, offset+4);
src[0] = zmw_rx_buf_readh(dev, buf, offset+10);
diff --git a/drivers/staging/otus/80211core/ccmd.c b/drivers/staging/otus/80211core/ccmd.c
index 8da28eee7fb0..3e3d9b500f65 100644
--- a/drivers/staging/otus/80211core/ccmd.c
+++ b/drivers/staging/otus/80211core/ccmd.c
@@ -1659,7 +1659,7 @@ void zfiWlanSetPacketTypePromiscuous(zdev_t *dev, u32_t setValue)
if (setValue) {
/* write register for sniffer mode */
zfHpSetSnifferMode(dev, 1);
- zm_msg0_mm(ZM_LV_1, "enalbe sniffer mode");
+ zm_msg0_mm(ZM_LV_1, "enable sniffer mode");
} else {
zfHpSetSnifferMode(dev, 0);
zm_msg0_mm(ZM_LV_0, "disalbe sniffer mode");
diff --git a/drivers/staging/otus/80211core/cfunc.c b/drivers/staging/otus/80211core/cfunc.c
index d7c49d7523df..e0a9f383c755 100644
--- a/drivers/staging/otus/80211core/cfunc.c
+++ b/drivers/staging/otus/80211core/cfunc.c
@@ -1194,8 +1194,6 @@ u16_t zfFindMinimumUtilizationChannelIndex(zdev_t* dev, u16_t* array, u16_t coun
u8_t i;
u16_t tempMinIndex, tempMinValue;
- zmw_get_wlan_dev(dev);
-
i = 1;
tempMinIndex = 0;
tempMinValue = array[tempMinIndex];
diff --git a/drivers/staging/otus/80211core/cmm.c b/drivers/staging/otus/80211core/cmm.c
index a6c1b41ba848..484e753df358 100644
--- a/drivers/staging/otus/80211core/cmm.c
+++ b/drivers/staging/otus/80211core/cmm.c
@@ -346,8 +346,6 @@ u16_t zfFindSuperGElement(zdev_t* dev, zbuf_t* buf, u8_t type)
u8_t super_feature;
u8_t ouiSuperG[6] = {0x00,0x03,0x7f,0x01, 0x01, 0x00};
- zmw_get_wlan_dev(dev);
-
/* Get offset of first element */
subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4);
if ((offset = zgElementOffsetTable[subType]) == 0xff)
@@ -411,8 +409,6 @@ u16_t zfFindXRElement(zdev_t* dev, zbuf_t* buf, u8_t type)
u8_t id;
u8_t ouixr[6] = {0x00,0x03,0x7f,0x03, 0x01, 0x00};
- zmw_get_wlan_dev(dev);
-
/* Get offset of first element */
subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4);
if ((offset = zgElementOffsetTable[subType]) == 0xff)
diff --git a/drivers/staging/otus/80211core/cmmsta.c b/drivers/staging/otus/80211core/cmmsta.c
index a11d559167b1..c3fd47529c14 100644
--- a/drivers/staging/otus/80211core/cmmsta.c
+++ b/drivers/staging/otus/80211core/cmmsta.c
@@ -2808,7 +2808,7 @@ void zfStaProcessProbeReq(zdev_t* dev, zbuf_t* buf, u16_t* src)
zmw_get_wlan_dev(dev);
/* check mode : AP/IBSS */
- if ((wd->wlanMode != ZM_MODE_AP) || (wd->wlanMode != ZM_MODE_IBSS))
+ if ((wd->wlanMode != ZM_MODE_AP) && (wd->wlanMode != ZM_MODE_IBSS))
{
zm_msg0_mm(ZM_LV_3, "Ignore probe req");
return;
@@ -4848,8 +4848,6 @@ u16_t zfStaAddIePowerCap(zdev_t* dev, zbuf_t* buf, u16_t offset)
u8_t MaxTxPower;
u8_t MinTxPower;
- zmw_get_wlan_dev(dev);
-
/* Element ID */
zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_POWER_CAPABILITY);
@@ -5276,7 +5274,6 @@ u16_t zfStaRxValidateFrame(zdev_t* dev, zbuf_t* buf)
u8_t da0;
//u16_t sa[3];
u16_t ret;
- u16_t i;
//u8_t sa0;
zmw_get_wlan_dev(dev);
@@ -5738,8 +5735,6 @@ u16_t zfComputeBssInfoWeightValue(zdev_t *dev, u8_t isBMode, u8_t isHT, u8_t isH
u8_t weightOfN40BelowThr = 16;
u8_t weightOfN40UpThr = 32;
- zmw_get_wlan_dev(dev);
-
if( isBMode == 0 )
return (signalStrength + weightOfB); // pure b mode , do not add the weight value for this AP !
else
diff --git a/drivers/staging/otus/80211core/cpsmgr.c b/drivers/staging/otus/80211core/cpsmgr.c
index cf73caca8e52..98e1f0cc0727 100644
--- a/drivers/staging/otus/80211core/cpsmgr.c
+++ b/drivers/staging/otus/80211core/cpsmgr.c
@@ -381,8 +381,6 @@ static void zfPowerSavingMgrSleepIfIdle(zdev_t *dev)
static void zfPowerSavingMgrDisconnectMain(zdev_t* dev)
{
- zmw_get_wlan_dev(dev);
-
#ifdef ZM_ENABLE_DISCONNECT_PS
switch(wd->sta.psMgr.state)
{
diff --git a/drivers/staging/otus/80211core/cscanmgr.c b/drivers/staging/otus/80211core/cscanmgr.c
index b32835c87590..be7d8ebe82ba 100644
--- a/drivers/staging/otus/80211core/cscanmgr.c
+++ b/drivers/staging/otus/80211core/cscanmgr.c
@@ -289,8 +289,6 @@ static void zfScanMgrEventSetFreqCompleteCb(zdev_t* dev)
static void zfScanMgrEventScanCompleteCb(zdev_t* dev)
{
- zmw_get_wlan_dev(dev);
-
if ((zfStaIsConnected(dev)) && (!zfPowerSavingMgrIsSleeping(dev)))
{
zfSendNullData(dev, 0);
diff --git a/drivers/staging/otus/80211core/ctkip.c b/drivers/staging/otus/80211core/ctkip.c
index be42f7aaa37d..ca0740227be4 100644
--- a/drivers/staging/otus/80211core/ctkip.c
+++ b/drivers/staging/otus/80211core/ctkip.c
@@ -255,7 +255,8 @@ void zfTkipInit(u8_t* key, u8_t* ta, struct zsTkipSeed* pSeed, u8_t* initIv)
zfMemoryCopy(pSeed->ta, ta, 6);
zfMemoryCopy(pSeed->tk, key, 16);
- iv16 = *initIv++;
+ iv16 = *initIv;
+ initIv++;
iv16 += *initIv<<8;
initIv++;
@@ -264,7 +265,7 @@ void zfTkipInit(u8_t* key, u8_t* ta, struct zsTkipSeed* pSeed, u8_t* initIv)
for(i=0; i<4; i++) // initiv is little endian
{
iv32 += *initIv<<(i*8);
- *initIv++;
+ initIv++;
}
pSeed->iv32 = iv32+1; // Force Recalculating on Tkip Phase1
diff --git a/drivers/staging/otus/80211core/ctxrx.c b/drivers/staging/otus/80211core/ctxrx.c
index ac54d5a636b0..4e7f4bd86f47 100644
--- a/drivers/staging/otus/80211core/ctxrx.c
+++ b/drivers/staging/otus/80211core/ctxrx.c
@@ -536,8 +536,7 @@ void zfProtRspSim(zdev_t* dev, zbuf_t* buf)
zm_msg2_rx(ZM_LV_2, "ip1=", dip[1]);
//ARP request to 192.168.1.15
- if ((arpOp == 0x0100) && (dip[0] == 0xa8c0) && (dip[1] == 0x0f01));
- {
+ if ((arpOp == 0x0100) && (dip[0] == 0xa8c0) && (dip[1] == 0x0f01)) {
zm_msg0_rx(ZM_LV_2, "ARP");
/* ARP response */
zmw_rx_buf_writeh(dev, buf, 20, 0x0200);
@@ -883,7 +882,6 @@ zlError:
/************************************************************************/
u16_t zfTxSendEth(zdev_t* dev, zbuf_t* buf, u16_t port, u16_t bufType, u16_t flag)
{
- u16_t err;
//u16_t addrTblSize;
//struct zsAddrTbl addrTbl;
u16_t removeLen;
@@ -905,7 +903,6 @@ u16_t zfTxSendEth(zdev_t* dev, zbuf_t* buf, u16_t port, u16_t bufType, u16_t fla
u8_t qosType, keyIdx = 0;
u16_t fragOff;
u16_t newFlag;
- struct zsMicVar* pMicKey;
u8_t tkipFrameOffset = 0;
zmw_get_wlan_dev(dev);
@@ -1693,8 +1690,6 @@ void zfShowTxEAPOL(zdev_t* dev, zbuf_t* buf, u16_t offset)
u16_t packetLen, keyInfo, keyLen, keyDataLen, length, Op_Code;
u32_t replayCounterH, replayCounterL, vendorId, VendorType;
- zmw_get_wlan_dev(dev);
-
zm_debug_msg1("EAPOL Packet size = ", zfwBufGetSize(dev, buf));
/* EAPOL packet type */
@@ -2437,7 +2432,6 @@ void zfiRecv80211(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo)
u16_t IvOffset;
u8_t keyLen = 5;
u8_t iv[3];
- u8_t *wepKey;
u8_t keyIdx;
IvOffset = offset + ZM_SIZE_OF_WLAN_DATA_HEADER;
diff --git a/drivers/staging/otus/80211core/ledmgr.c b/drivers/staging/otus/80211core/ledmgr.c
index 1e104a928ca4..eafce0b1204f 100644
--- a/drivers/staging/otus/80211core/ledmgr.c
+++ b/drivers/staging/otus/80211core/ledmgr.c
@@ -187,7 +187,6 @@ void zfLedCtrlType2_scan(zdev_t* dev);
void zfLedCtrlType2(zdev_t* dev)
{
- u32_t ton, toff, tmp, period;
u16_t OperateLED;
zmw_get_wlan_dev(dev);
diff --git a/drivers/staging/otus/80211core/pub_zfi.h b/drivers/staging/otus/80211core/pub_zfi.h
index b7b7f455f357..5202e5a645d5 100644
--- a/drivers/staging/otus/80211core/pub_zfi.h
+++ b/drivers/staging/otus/80211core/pub_zfi.h
@@ -814,7 +814,6 @@ extern void zfiRxPerformanceReg(zdev_t* dev, u32_t reg, u32_t rsp);
#define ZM_PERFORMANCE_RX_AMSDU(dev, buf, len)
#define ZM_PERFORMANCE_RX_FLUSH(dev)
#define ZM_PERFORMANCE_RX_CLEAR(dev)
-#define ZM_SEQ_DEBUG
#define ZM_PERFORMANCE_RX_REORDER(dev)
#endif
/***** End of section 3 *****/
diff --git a/drivers/staging/otus/Kconfig b/drivers/staging/otus/Kconfig
index f6cc2625e341..e9181340bef1 100644
--- a/drivers/staging/otus/Kconfig
+++ b/drivers/staging/otus/Kconfig
@@ -1,6 +1,8 @@
config OTUS
tristate "Atheros OTUS 802.11n USB wireless support"
depends on USB && WLAN && MAC80211
+ select WIRELESS_EXT
+ select WEXT_PRIV
default N
---help---
Enable support for Atheros 802.11n USB hardware:
diff --git a/drivers/staging/otus/apdbg.c b/drivers/staging/otus/apdbg.c
index 0eb93f19958a..b59028e7e33c 100644
--- a/drivers/staging/otus/apdbg.c
+++ b/drivers/staging/otus/apdbg.c
@@ -90,8 +90,27 @@ struct zdap_ioctl {
#endif
-char hex(char);
-unsigned char asctohex(char *str);
+static char hex(char v)
+{
+ if (isdigit(v))
+ return v - '0';
+ else if (isxdigit(v))
+ return tolower(v) - 'a' + 10;
+ else
+ return 0;
+}
+
+static unsigned char asctohex(char *str)
+{
+ unsigned char value;
+
+ value = hex(*str) & 0x0f;
+ value = value << 4;
+ str++;
+ value |= hex(*str) & 0x0f;
+
+ return value;
+}
char *prgname;
@@ -109,10 +128,10 @@ int set_ioctl(int sock, struct ifreq *req)
int read_reg(int sock, struct ifreq *req)
{
- struct zdap_ioctl *zdreq = 0;
+ struct zdap_ioctl *zdreq = NULL;
if (!set_ioctl(sock, req))
- return -1;
+ return -1;
/*
* zdreq = (struct zdap_ioctl *)req->ifr_data;
@@ -125,7 +144,7 @@ int read_reg(int sock, struct ifreq *req)
int read_mem(int sock, struct ifreq *req)
{
- struct zdap_ioctl *zdreq = 0;
+ struct zdap_ioctl *zdreq = NULL;
int i;
if (!set_ioctl(sock, req))
@@ -368,7 +387,7 @@ int main(int argc, char **argv)
zdreq.addr = addr;
zdreq.cmd = ZM_IOCTL_SET_PIBSS_MODE;
- } else {
+ } else {
fprintf(stderr, "error action\n");
exit(1);
}
@@ -380,25 +399,3 @@ fail:
exit(0);
}
-unsigned char asctohex(char *str)
-{
- unsigned char value;
-
- value = hex(*str) & 0x0f;
- value = value << 4;
- str++;
- value |= hex(*str) & 0x0f;
-
- return value;
-}
-
-char hex(char v)
-{
- if (isdigit(v))
- return v - '0';
- else if (isxdigit(v))
- return tolower(v) - 'a' + 10;
- else
- return 0;
-}
-
diff --git a/drivers/staging/otus/hal/hpmain.c b/drivers/staging/otus/hal/hpmain.c
index 94f9cbbbdefc..8dff5b97dfe3 100644
--- a/drivers/staging/otus/hal/hpmain.c
+++ b/drivers/staging/otus/hal/hpmain.c
@@ -1316,7 +1316,6 @@ void zfHpSetFrequencyEx(zdev_t* dev, u32_t frequency, u8_t bw40,
u8_t extOffset, u8_t initRF)
{
u32_t cmd[9];
- u32_t cmdB[3];
u16_t ret;
u8_t old_band;
u8_t new_band;
@@ -3434,7 +3433,6 @@ void zfSetPowerCalTable(zdev_t* dev, u32_t frequency, u8_t bw40, u8_t extOffset)
/* Write PHY regs 672-703 */
for (i=0; i<128; i+=4)
{
- u32_t regAddr = 0x9800 + (672 * 4);
u32_t val;
val = ((u32_t)vpd_chain1[i+3]<<24) |
@@ -3485,7 +3483,6 @@ void zfSetPowerCalTable(zdev_t* dev, u32_t frequency, u8_t bw40, u8_t extOffset)
/* Write PHY regs 672-703 + 0x1000 */
for (i=0; i<128; i+=4)
{
- u32_t regAddr = 0x9800 + (672 * 4) + 0x1000;
u32_t val;
val = ((u32_t)vpd_chain3[i+3]<<24) |
@@ -4584,7 +4581,6 @@ void zfHpSetRollCallTable(zdev_t* dev)
void zfHpSetTTSIFSTime(zdev_t* dev, u8_t sifs_time)
{
u32_t reg_value = 0;
- zmw_get_wlan_dev(dev);
sifs_time &= 0x3f;
reg_value = 0x14400b | (((u32_t)sifs_time)<<24);
diff --git a/drivers/staging/otus/hal/hpreg.c b/drivers/staging/otus/hal/hpreg.c
index d9894fe5f4ec..178777c09dbd 100644
--- a/drivers/staging/otus/hal/hpreg.c
+++ b/drivers/staging/otus/hal/hpreg.c
@@ -786,45 +786,6 @@ enum {
WT1_5760_5800,
};
-static REG_DMN_FREQ_BAND regDmn5GhzTurboFreq[] = {
- { 5130, 5210, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5130_5210 */
- { 5250, 5330, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0, 0}, /* T1_5250_5330 */
- { 5370, 5490, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5370_5490 */
- { 5530, 5650, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0, 0}, /* T1_5530_5650 */
-
- { 5150, 5190, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5150_5190 */
- { 5230, 5310, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0, 0}, /* T1_5230_5310 */
- { 5350, 5470, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5350_5470 */
- { 5510, 5670, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0, 0}, /* T1_5510_5670 */
-
- { 5200, 5240, 17, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5200_5240 */
- { 5200, 5240, 23, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T2_5200_5240 */
- { 5210, 5210, 17, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5210_5210 */
- { 5210, 5210, 23, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T2_5210_5210 */
-
- { 5280, 5280, 23, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T1_5280_5280 */
- { 5280, 5280, 20, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T2_5280_5280 */
- { 5250, 5250, 17, 0, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T1_5250_5250 */
- { 5290, 5290, 20, 0, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T1_5290_5290 */
- { 5250, 5290, 20, 0, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T1_5250_5290 */
- { 5250, 5290, 23, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T2_5250_5290 */
-
- { 5540, 5660, 20, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T1_5540_5660 */
- { 5760, 5800, 20, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5760_5800 */
- { 5760, 5800, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T2_5760_5800 */
-
- { 5765, 5805, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5765_5805 */
-
- /*
- * Below are the WWR frequencies
- */
-
- { 5210, 5250, 15, 0, 40, 40, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0, 0}, /* WT1_5210_5250 */
- { 5290, 5290, 18, 0, 40, 40, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0, 0}, /* WT1_5290_5290 */
- { 5540, 5660, 20, 0, 40, 40, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0, 0}, /* WT1_5540_5660 */
- { 5760, 5800, 20, 0, 40, 40, NO_DFS, PSCAN_WWR, 0, 0}, /* WT1_5760_5800 */
-};
-
/*
* 2GHz 11b channel tags
*/
@@ -864,45 +825,6 @@ enum {
W2_2484_2484,
};
-static REG_DMN_FREQ_BAND regDmn2GhzFreq[] = {
- { 2312, 2372, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2312_2372 */
- { 2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F2_2312_2372 */
-
- { 2412, 2472, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2412_2472 */
- { 2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 0, 0}, /* F2_2412_2472 */
- { 2412, 2472, 30, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F3_2412_2472 */
-
- { 2412, 2462, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2412_2462 */
- { 2412, 2462, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 0, 0}, /* F2_2412_2462 */
- { 2432, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2432_2442 */
-
- { 2457, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2457_2472 */
-
- { 2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA2 | PSCAN_MKKA, 0, 0}, /* F1_2467_2472 */
-
- { 2484, 2484, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2484_2484 */
- { 2484, 2484, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA | PSCAN_MKKA1 | PSCAN_MKKA2, 0, 0}, /* F2_2484_2484 */
-
- { 2512, 2732, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2512_2732 */
-
- /*
- * WWR have powers opened up to 20dBm. Limits should often come from CTL/Max powers
- */
-
- { 2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* W1_2312_2372 */
- { 2412, 2412, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* W1_2412_2412 */
- { 2417, 2432, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* W1_2417_2432 */
- { 2437, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* W1_2437_2442 */
- { 2447, 2457, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* W1_2447_2457 */
- { 2462, 2462, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* W1_2462_2462 */
- { 2467, 2467, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0, 0}, /* W1_2467_2467 */
- { 2467, 2467, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0, 0}, /* W2_2467_2467 */
- { 2472, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0, 0}, /* W1_2472_2472 */
- { 2472, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0, 0}, /* W2_2472_2472 */
- { 2484, 2484, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0, 0}, /* W1_2484_2484 */
- { 2484, 2484, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0, 0}, /* W2_2484_2484 */
-};
-
/*
* 2GHz 11g channel tags
@@ -984,16 +906,6 @@ enum {
T1_2512_2732
};
-static REG_DMN_FREQ_BAND regDmn2Ghz11gTurboFreq[] = {
- { 2312, 2372, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_2312_2372 */
- { 2437, 2437, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_2437_2437 */
- { 2437, 2437, 20, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T2_2437_2437 */
- { 2437, 2437, 18, 6, 40, 40, NO_DFS, PSCAN_WWR, 0, 0}, /* T3_2437_2437 */
- { 2512, 2732, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_2512_2732 */
-};
-
-
-
/*
* 2GHz 11n frequency tags
*/
@@ -1005,15 +917,6 @@ enum {
NG_DEMO_ALL_CHANNELS,
};
-static REG_DMN_FREQ_BAND regDmn2Ghz11ngFreq[] = {
- { 2422, 2452, 20, 0, 40, 5, NO_DFS, NO_PSCAN, 0, 0}, /* NG1_2422_2452 */
- { 2422, 2452, 27, 0, 40, 5, NO_DFS, NO_PSCAN, 0, 0}, /* NG2_2422_2452 */
- { 2422, 2452, 30, 0, 40, 5, NO_DFS, NO_PSCAN, 0, 0}, /* NG3_2422_2452 */
-
- { 2312, 2732, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* NG_DEMO_ALL_CHANNELS */
-};
-
-
/*
* 5GHz 11n frequency tags
*/
@@ -1050,42 +953,6 @@ enum {
NA_DEMO_ALL_CHANNELS,
};
-static REG_DMN_FREQ_BAND regDmn5Ghz11naFreq[] = {
- /*
- * ToDo: This table needs to be completely populated with 5GHz 11n properties
- */
- { 5190, 5230, 15, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA1_5190_5230 */
- { 5190, 5230, 17, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA2_5190_5230 */
- { 5190, 5230, 18, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA3_5190_5230 */
- { 5190, 5230, 20, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA4_5190_5230 */
- { 5190, 5230, 23, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA5_5190_5230 */
-
- { 5270, 5270, 23, 6, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA1_5270_5270 */
-
- { 5270, 5310, 18, 6, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA1_5270_5310 */
- { 5270, 5310, 20, 0, 40, 40, DFS_FCC3|DFS_ETSI|DFS_MKK4, NO_PSCAN, 0, 1}, /* NA2_5270_5310 */
- { 5270, 5310, 23, 6, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA3_5270_5310 */
- { 5270, 5310, 30, 6, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA4_5270_5310 */
-
- { 5310, 5310, 17, 6, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA1_5310_5310 */
-
- { 5510, 5630, 30, 6, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA1_5510_5630 */
-
- { 5510, 5670, 20, 6, 40, 40, DFS_FCC3|DFS_ETSI|DFS_MKK4, NO_PSCAN, 0, 1}, /* NA1_5510_5670 */
- { 5510, 5670, 27, 0, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA2_5510_5670 */
- { 5510, 5670, 30, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0, 1}, /* NA3_5510_5670 */
-
- { 5755, 5795, 17, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA1_5755_5795 */
- { 5755, 5795, 20, 6, 40, 40, DFS_ETSI, NO_PSCAN, 0, 0}, /* NA2_5755_5795 */
- { 5755, 5795, 23, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA3_5755_5795 */
- { 5755, 5795, 30, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA4_5755_5795 */
- { 5755, 5795, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA5_5755_5795 */
-
- { 5795, 5795, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA1_5795_5795 */
-
- { 4920, 6100, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA_DEMO_ALL_CHANNELS */
-};
-
typedef struct regDomain {
u16_t regDmnEnum; /* value from EnumRd table */
u8_t conformanceTestLimit;
diff --git a/drivers/staging/otus/hal/hprw.c b/drivers/staging/otus/hal/hprw.c
index d9fad47d5d59..4dbd5fb44b0a 100644
--- a/drivers/staging/otus/hal/hprw.c
+++ b/drivers/staging/otus/hal/hprw.c
@@ -282,7 +282,6 @@ void zfIdlRsp(zdev_t* dev, u32_t* rsp, u16_t rspLen)
else if (src == ZM_OID_FLASH_READ)
{
u32_t datalen;
- u16_t i;
datalen = (rsp[0] & 255);
diff --git a/drivers/staging/otus/ioctl.c b/drivers/staging/otus/ioctl.c
index 6808e69fb354..8c47b1a68627 100644
--- a/drivers/staging/otus/ioctl.c
+++ b/drivers/staging/otus/ioctl.c
@@ -866,15 +866,15 @@ int usbdrvwext_giwscan(struct net_device *dev,
char *current_ev = extra;
char *end_buf;
int i;
- /* struct zsBssList BssList; */
- struct zsBssListV1 *pBssList = kmalloc(sizeof(struct zsBssListV1),
- GFP_KERNEL);
/* BssList = wd->sta.pBssList; */
/* zmw_get_wlan_dev(dev); */
if (macp->DeviceOpened != 1)
return 0;
+ /* struct zsBssList BssList; */
+ struct zsBssListV1 *pBssList = kmalloc(sizeof(struct zsBssListV1),
+ GFP_KERNEL);
if (data->length == 0)
end_buf = extra + IW_SCAN_MAX_DATA;
else
@@ -930,7 +930,7 @@ int usbdrvwext_siwessid(struct net_device *dev,
return -EINVAL;
if (essid->flags == 1) {
- if (essid->length > (IW_ESSID_MAX_SIZE + 1))
+ if (essid->length > IW_ESSID_MAX_SIZE)
return -E2BIG;
if (copy_from_user(&EssidBuf, essid->pointer, essid->length))
@@ -2227,7 +2227,8 @@ int usbdrv_wpa_ioctl(struct net_device *dev, struct athr_wlan_param *zdparm)
case ZD_CMD_SCAN_REQ:
printk(KERN_ERR "usbdrv_wpa_ioctl: ZD_CMD_SCAN_REQ\n");
break;
- case ZD_CMD_SET_GENERIC_ELEMENT:
+ case ZD_CMD_SET_GENERIC_ELEMENT: {
+ u8_t len, *wpaie;
printk(KERN_ERR "usbdrv_wpa_ioctl:"
" ZD_CMD_SET_GENERIC_ELEMENT\n");
@@ -2250,8 +2251,8 @@ int usbdrv_wpa_ioctl(struct net_device *dev, struct athr_wlan_param *zdparm)
/* zfiWlanSetWpaIe(dev, zdparm->u.generic_elem.data,
* zdparm->u.generic_elem.len);
*/
- u8_t len = zdparm->u.generic_elem.len;
- u8_t *wpaie = (u8_t *)zdparm->u.generic_elem.data;
+ len = zdparm->u.generic_elem.len;
+ wpaie = zdparm->u.generic_elem.data;
printk(KERN_ERR "wd->ap.wpaLen : % d\n", len);
@@ -2273,6 +2274,7 @@ int usbdrv_wpa_ioctl(struct net_device *dev, struct athr_wlan_param *zdparm)
* #endif
*/
break;
+ }
/* #ifdef ZM_HOSTAPD_SUPPORT */
case ZD_CMD_GET_TSC:
diff --git a/drivers/staging/otus/usbdrv.c b/drivers/staging/otus/usbdrv.c
index b0adbc8b2dc2..5e6a12037b12 100644
--- a/drivers/staging/otus/usbdrv.c
+++ b/drivers/staging/otus/usbdrv.c
@@ -829,7 +829,7 @@ int zfLnxRegisterVapDev(struct net_device* parentDev, u16_t vapId)
{
/* Allocate net device structure */
vap[vapId].dev = alloc_etherdev(0);
- printk("Register vap dev=%x\n", (u32_t)vap[vapId].dev);
+ printk("Register vap dev=%p\n", vap[vapId].dev);
if(vap[vapId].dev == NULL) {
printk("alloc_etherdev fail\n");
@@ -883,7 +883,7 @@ int zfLnxUnregisterVapDev(struct net_device* parentDev, u16_t vapId)
printk("Unregister VAP dev : %s\n", vap[vapId].dev->name);
if(vap[vapId].dev != NULL) {
- printk("Unregister vap dev=%x\n", (u32_t)vap[vapId].dev);
+ printk("Unregister vap dev=%p\n", vap[vapId].dev);
//
//unregister_netdevice(wds[wdsId].dev);
unregister_netdev(vap[vapId].dev);
diff --git a/drivers/staging/otus/wrap_pkt.c b/drivers/staging/otus/wrap_pkt.c
index 75bb952fd0a5..a2f5cb1f5298 100644
--- a/drivers/staging/otus/wrap_pkt.c
+++ b/drivers/staging/otus/wrap_pkt.c
@@ -58,7 +58,7 @@ void zfLnxRecv80211(zdev_t *dev, zbuf_t *buf, struct zsAdditionInfo *addInfo)
skb1 = skb_copy(buf, GFP_ATOMIC);
if (skb1 != NULL) {
skb1->dev = dev;
- skb1->mac_header = skb1->data;
+ skb_reset_mac_header(skb1);
skb1->ip_summed = CHECKSUM_NONE;
skb1->pkt_type = PACKET_OTHERHOST;
/* ETH_P_80211_RAW */
@@ -85,13 +85,7 @@ void zfLnxRecvEth(zdev_t *dev, zbuf_t *buf, u16_t port)
/* new_buf = dev_alloc_skb(2048); */
new_buf = dev_alloc_skb(buf->len);
-#ifdef NET_SKBUFF_DATA_USES_OFFSET
- new_buf->tail = 0;
- new_buf->len = 0;
-#else
- new_buf->tail = new_buf->data;
- new_buf->len = 0;
-#endif
+ skb_reset_tail_pointer(new_buf);
skb_put(new_buf, buf->len);
memcpy(new_buf->data, buf->data, buf->len);
diff --git a/drivers/staging/otus/zdusb.c b/drivers/staging/otus/zdusb.c
index 2a6d937ba5e8..4cd9b7f5a887 100644
--- a/drivers/staging/otus/zdusb.c
+++ b/drivers/staging/otus/zdusb.c
@@ -45,7 +45,7 @@ MODULE_LICENSE("Dual BSD/GPL");
static const char driver_name[] = "Otus";
/* table of devices that work with this driver */
-static struct usb_device_id zd1221_ids [] = {
+static const struct usb_device_id zd1221_ids[] = {
{ USB_DEVICE(VENDOR_ATHR, PRODUCT_AR9170) },
{ USB_DEVICE(VENDOR_DLINK, PRODUCT_DWA160A) },
{ USB_DEVICE(VENDOR_NETGEAR, PRODUCT_WNDA3100) },
diff --git a/drivers/staging/p9auth/Kconfig b/drivers/staging/p9auth/Kconfig
deleted file mode 100644
index d1c66d262020..000000000000
--- a/drivers/staging/p9auth/Kconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-config PLAN9AUTH
- tristate "Plan 9 style capability device implementation"
- default n
- depends on CRYPTO
- help
- This module implements the Plan 9 style capability device.
-
- To compile this driver as a module, choose
- M here: the module will be called p9auth.
diff --git a/drivers/staging/p9auth/Makefile b/drivers/staging/p9auth/Makefile
deleted file mode 100644
index 3ebf6ff0eef2..000000000000
--- a/drivers/staging/p9auth/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_PLAN9AUTH) += p9auth.o
diff --git a/drivers/staging/p9auth/p9auth.c b/drivers/staging/p9auth/p9auth.c
deleted file mode 100644
index db7962621210..000000000000
--- a/drivers/staging/p9auth/p9auth.c
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * Plan 9 style capability device implementation for the Linux Kernel
- *
- * Copyright 2008, 2009 Ashwin Ganti <ashwin.ganti@gmail.com>
- *
- * Released under the GPLv2
- *
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/moduleparam.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/cdev.h>
-#include <linux/uaccess.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/crypto.h>
-#include <linux/highmem.h>
-#include <linux/scatterlist.h>
-#include <linux/sched.h>
-#include <linux/cred.h>
-
-#ifndef CAP_MAJOR
-#define CAP_MAJOR 0
-#endif
-
-#ifndef CAP_NR_DEVS
-#define CAP_NR_DEVS 2 /* caphash and capuse */
-#endif
-
-#ifndef CAP_NODE_SIZE
-#define CAP_NODE_SIZE 20
-#endif
-
-#define MAX_DIGEST_SIZE 20
-
-struct cap_node {
- char data[CAP_NODE_SIZE];
- struct list_head list;
-};
-
-struct cap_dev {
- struct cap_node *head;
- int node_size;
- unsigned long size;
- struct semaphore sem;
- struct cdev cdev;
-};
-
-static int cap_major = CAP_MAJOR;
-static int cap_minor;
-static int cap_nr_devs = CAP_NR_DEVS;
-static int cap_node_size = CAP_NODE_SIZE;
-
-module_param(cap_major, int, S_IRUGO);
-module_param(cap_minor, int, S_IRUGO);
-module_param(cap_nr_devs, int, S_IRUGO);
-
-MODULE_AUTHOR("Ashwin Ganti");
-MODULE_LICENSE("GPL");
-
-static struct cap_dev *cap_devices;
-
-static void hexdump(unsigned char *buf, unsigned int len)
-{
- while (len--)
- printk("%02x", *buf++);
- printk("\n");
-}
-
-static char *cap_hash(char *plain_text, unsigned int plain_text_size,
- char *key, unsigned int key_size)
-{
- struct scatterlist sg;
- char *result;
- struct crypto_hash *tfm;
- struct hash_desc desc;
- int ret;
-
- tfm = crypto_alloc_hash("hmac(sha1)", 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(tfm)) {
- printk(KERN_ERR
- "failed to load transform for hmac(sha1): %ld\n",
- PTR_ERR(tfm));
- return NULL;
- }
-
- desc.tfm = tfm;
- desc.flags = 0;
-
- result = kzalloc(MAX_DIGEST_SIZE, GFP_KERNEL);
- if (!result) {
- printk(KERN_ERR "out of memory!\n");
- goto out;
- }
-
- sg_set_buf(&sg, plain_text, plain_text_size);
-
- ret = crypto_hash_setkey(tfm, key, key_size);
- if (ret) {
- printk(KERN_ERR "setkey() failed ret=%d\n", ret);
- kfree(result);
- result = NULL;
- goto out;
- }
-
- ret = crypto_hash_digest(&desc, &sg, plain_text_size, result);
- if (ret) {
- printk(KERN_ERR "digest () failed ret=%d\n", ret);
- kfree(result);
- result = NULL;
- goto out;
- }
-
- printk(KERN_DEBUG "crypto hash digest size %d\n",
- crypto_hash_digestsize(tfm));
- hexdump(result, MAX_DIGEST_SIZE);
-
-out:
- crypto_free_hash(tfm);
- return result;
-}
-
-static int cap_trim(struct cap_dev *dev)
-{
- struct cap_node *tmp;
- struct list_head *pos, *q;
- if (dev->head != NULL) {
- list_for_each_safe(pos, q, &(dev->head->list)) {
- tmp = list_entry(pos, struct cap_node, list);
- list_del(pos);
- kfree(tmp);
- }
- }
- return 0;
-}
-
-static int cap_open(struct inode *inode, struct file *filp)
-{
- struct cap_dev *dev;
- dev = container_of(inode->i_cdev, struct cap_dev, cdev);
- filp->private_data = dev;
-
- /* trim to 0 the length of the device if open was write-only */
- if ((filp->f_flags & O_ACCMODE) == O_WRONLY) {
- if (down_interruptible(&dev->sem))
- return -ERESTARTSYS;
- cap_trim(dev);
- up(&dev->sem);
- }
- /* initialise the head if it is NULL */
- if (dev->head == NULL) {
- dev->head = kmalloc(sizeof(struct cap_node), GFP_KERNEL);
- INIT_LIST_HEAD(&(dev->head->list));
- }
- return 0;
-}
-
-static int cap_release(struct inode *inode, struct file *filp)
-{
- return 0;
-}
-
-static ssize_t cap_write(struct file *filp, const char __user *buf,
- size_t count, loff_t *f_pos)
-{
- struct cap_node *node_ptr, *tmp;
- struct list_head *pos;
- struct cap_dev *dev = filp->private_data;
- ssize_t retval = -ENOMEM;
- struct cred *new;
- int len, target_int, source_int, flag = 0;
- char *user_buf, *user_buf_running, *source_user, *target_user,
- *rand_str, *hash_str, *result;
-
- if (down_interruptible(&dev->sem))
- return -ERESTARTSYS;
-
- user_buf_running = NULL;
- hash_str = NULL;
- node_ptr = kmalloc(sizeof(struct cap_node), GFP_KERNEL);
- user_buf = kzalloc(count+1, GFP_KERNEL);
- if (!node_ptr || !user_buf)
- goto out;
-
- if (copy_from_user(user_buf, buf, count)) {
- retval = -EFAULT;
- goto out;
- }
-
- /*
- * If the minor number is 0 ( /dev/caphash ) then simply add the
- * hashed capability supplied by the user to the list of hashes
- */
- if (0 == iminor(filp->f_dentry->d_inode)) {
- if (count > CAP_NODE_SIZE) {
- retval = -EINVAL;
- goto out;
- }
- printk(KERN_INFO "Capability being written to /dev/caphash : \n");
- hexdump(user_buf, count);
- memcpy(node_ptr->data, user_buf, count);
- list_add(&(node_ptr->list), &(dev->head->list));
- node_ptr = NULL;
- } else {
- char *tmpu;
- if (!cap_devices[0].head ||
- list_empty(&(cap_devices[0].head->list))) {
- retval = -EINVAL;
- goto out;
- }
- /*
- * break the supplied string into tokens with @ as the
- * delimiter If the string is "user1@user2@randomstring" we
- * need to split it and hash 'user1@user2' using 'randomstring'
- * as the key.
- */
- tmpu = user_buf_running = kstrdup(user_buf, GFP_KERNEL);
- source_user = strsep(&tmpu, "@");
- target_user = strsep(&tmpu, "@");
- rand_str = tmpu;
- if (!source_user || !target_user || !rand_str) {
- retval = -EINVAL;
- goto out;
- }
-
- /* hash the string user1@user2 with rand_str as the key */
- len = strlen(source_user) + strlen(target_user) + 1;
- /* src, @, len, \0 */
- hash_str = kzalloc(len+1, GFP_KERNEL);
- strcat(hash_str, source_user);
- strcat(hash_str, "@");
- strcat(hash_str, target_user);
-
- printk(KERN_ALERT "the source user is %s \n", source_user);
- printk(KERN_ALERT "the target user is %s \n", target_user);
-
- result = cap_hash(hash_str, len, rand_str, strlen(rand_str));
- if (NULL == result) {
- retval = -EFAULT;
- goto out;
- }
- memcpy(node_ptr->data, result, CAP_NODE_SIZE); /* why? */
- /* Change the process's uid if the hash is present in the
- * list of hashes
- */
- list_for_each(pos, &(cap_devices->head->list)) {
- /*
- * Change the user id of the process if the hashes
- * match
- */
- if (0 ==
- memcmp(result,
- list_entry(pos, struct cap_node,
- list)->data,
- CAP_NODE_SIZE)) {
- target_int = (unsigned int)
- simple_strtol(target_user, NULL, 0);
- source_int = (unsigned int)
- simple_strtol(source_user, NULL, 0);
- flag = 1;
-
- /*
- * Check whether the process writing to capuse
- * is actually owned by the source owner
- */
- if (source_int != current_uid()) {
- printk(KERN_ALERT
- "Process is not owned by the source user of the capability.\n");
- retval = -EFAULT;
- goto out;
- }
- /*
- * What all id's need to be changed here? uid,
- * euid, fsid, savedids ?? Currently I am
- * changing the effective user id since most of
- * the authorisation decisions are based on it
- */
- new = prepare_creds();
- if (!new) {
- retval = -ENOMEM;
- goto out;
- }
- new->uid = (uid_t) target_int;
- new->euid = (uid_t) target_int;
- retval = commit_creds(new);
- if (retval)
- goto out;
-
- /*
- * Remove the capability from the list and
- * break
- */
- tmp = list_entry(pos, struct cap_node, list);
- list_del(pos);
- kfree(tmp);
- break;
- }
- }
- if (0 == flag) {
- /*
- * The capability is not present in the list of the
- * hashes stored, hence return failure
- */
- printk(KERN_ALERT
- "Invalid capabiliy written to /dev/capuse \n");
- retval = -EFAULT;
- goto out;
- }
- }
- *f_pos += count;
- retval = count;
- /* update the size */
- if (dev->size < *f_pos)
- dev->size = *f_pos;
-
-out:
- kfree(node_ptr);
- kfree(user_buf);
- kfree(user_buf_running);
- kfree(hash_str);
- up(&dev->sem);
- return retval;
-}
-
-static const struct file_operations cap_fops = {
- .owner = THIS_MODULE,
- .write = cap_write,
- .open = cap_open,
- .release = cap_release,
-};
-
-/* no __exit here because it can be called by the init function */
-static void cap_cleanup_module(void)
-{
- int i;
- dev_t devno = MKDEV(cap_major, cap_minor);
- if (cap_devices) {
- for (i = 0; i < cap_nr_devs; i++) {
- cap_trim(cap_devices + i);
- cdev_del(&cap_devices[i].cdev);
- }
- kfree(cap_devices);
- }
- unregister_chrdev_region(devno, cap_nr_devs);
-
-}
-
-static void cap_setup_cdev(struct cap_dev *dev, int index)
-{
- int err, devno = MKDEV(cap_major, cap_minor + index);
- cdev_init(&dev->cdev, &cap_fops);
- dev->cdev.owner = THIS_MODULE;
- dev->cdev.ops = &cap_fops;
- err = cdev_add(&dev->cdev, devno, 1);
- if (err)
- printk(KERN_NOTICE "Error %d adding cap%d", err, index);
-}
-
-static int __init cap_init_module(void)
-{
- int result, i;
- dev_t dev = 0;
-
- if (cap_major) {
- dev = MKDEV(cap_major, cap_minor);
- result = register_chrdev_region(dev, cap_nr_devs, "cap");
- } else {
- result = alloc_chrdev_region(&dev, cap_minor, cap_nr_devs,
- "cap");
- cap_major = MAJOR(dev);
- }
-
- if (result < 0) {
- printk(KERN_WARNING "cap: can't get major %d\n",
- cap_major);
- return result;
- }
-
- cap_devices = kzalloc(cap_nr_devs * sizeof(struct cap_dev),
- GFP_KERNEL);
- if (!cap_devices) {
- result = -ENOMEM;
- goto fail;
- }
-
- /* Initialize each device. */
- for (i = 0; i < cap_nr_devs; i++) {
- cap_devices[i].node_size = cap_node_size;
- init_MUTEX(&cap_devices[i].sem);
- cap_setup_cdev(&cap_devices[i], i);
- }
-
- return 0;
-
-fail:
- cap_cleanup_module();
- return result;
-}
-
-module_init(cap_init_module);
-module_exit(cap_cleanup_module);
-
-
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index 95c93e82ccec..377884f3480d 100644
--- a/drivers/staging/panel/panel.c
+++ b/drivers/staging/panel/panel.c
@@ -41,7 +41,6 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
diff --git a/drivers/staging/phison/phison.c b/drivers/staging/phison/phison.c
index 3817d7497049..0c495eacb75b 100644
--- a/drivers/staging/phison/phison.c
+++ b/drivers/staging/phison/phison.c
@@ -62,14 +62,14 @@ static int phison_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
};
const struct ata_port_info *ppi[] = { &info, NULL };
- ret = ata_pci_sff_init_one(pdev, ppi, &phison_sht, NULL);
+ ret = ata_pci_sff_init_one(pdev, ppi, &phison_sht, NULL, 0);
dev_dbg(&pdev->dev, "phison_init_one(), ret = %x\n", ret);
return ret;
}
-static struct pci_device_id phison_pci_tbl[] = {
+static const struct pci_device_id phison_pci_tbl[] = {
{ PCI_VENDOR_ID_PHISON, PCI_DEVICE_ID_PS5000, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
{ 0, },
diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c
index f69b7783027f..63275529ff55 100644
--- a/drivers/staging/pohmelfs/inode.c
+++ b/drivers/staging/pohmelfs/inode.c
@@ -36,6 +36,7 @@
#define POHMELFS_MAGIC_NUM 0x504f482e
static struct kmem_cache *pohmelfs_inode_cache;
+static atomic_t psb_bdi_num = ATOMIC_INIT(0);
/*
* Removes inode from all trees, drops local name cache and removes all queued
@@ -322,7 +323,7 @@ int pohmelfs_write_create_inode(struct pohmelfs_inode *pi)
t = netfs_trans_alloc(psb, err + 1, 0, 0);
if (!t) {
err = -ENOMEM;
- goto err_out_put;
+ goto err_out_exit;
}
t->complete = pohmelfs_write_inode_complete;
t->private = igrab(inode);
@@ -395,7 +396,8 @@ int pohmelfs_remove_child(struct pohmelfs_inode *pi, struct pohmelfs_name *n)
/*
* Writeback for given inode.
*/
-static int pohmelfs_write_inode(struct inode *inode, int sync)
+static int pohmelfs_write_inode(struct inode *inode,
+ struct writeback_control *wbc)
{
struct pohmelfs_inode *pi = POHMELFS_I(inode);
@@ -969,7 +971,7 @@ int pohmelfs_setattr_raw(struct inode *inode, struct iattr *attr)
if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
(attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
- err = vfs_dq_transfer(inode, attr) ? -EDQUOT : 0;
+ err = dquot_transfer(inode, attr);
if (err)
goto err_out_exit;
}
@@ -1331,6 +1333,8 @@ static void pohmelfs_put_super(struct super_block *sb)
pohmelfs_crypto_exit(psb);
pohmelfs_state_exit(psb);
+ bdi_destroy(&psb->bdi);
+
kfree(psb);
sb->s_fs_info = NULL;
}
@@ -1767,8 +1771,7 @@ static int pohmelfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
seq_printf(m, "%u ", ctl->idx);
if (ctl->addr.sa_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)&st->ctl.addr;
- /* seq_printf(m, "%pi4:%u", &sin->sin_addr.s_addr, ntohs(sin->sin_port)); */
- seq_printf(m, "%u.%u.%u.%u:%u", NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port));
+ seq_printf(m, "%pI4:%u", &sin->sin_addr.s_addr, ntohs(sin->sin_port));
} else if (ctl->addr.sa_family == AF_INET6) {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&st->ctl.addr;
seq_printf(m, "%pi6:%u", &sin->sin6_addr, ntohs(sin->sin6_port));
@@ -1815,11 +1818,22 @@ static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent)
if (!psb)
goto err_out_exit;
+ err = bdi_init(&psb->bdi);
+ if (err)
+ goto err_out_free_sb;
+
+ err = bdi_register(&psb->bdi, NULL, "pfs-%d", atomic_inc_return(&psb_bdi_num));
+ if (err) {
+ bdi_destroy(&psb->bdi);
+ goto err_out_free_sb;
+ }
+
sb->s_fs_info = psb;
sb->s_op = &pohmelfs_sb_ops;
sb->s_magic = POHMELFS_MAGIC_NUM;
sb->s_maxbytes = MAX_LFS_FILESIZE;
sb->s_blocksize = PAGE_SIZE;
+ sb->s_bdi = &psb->bdi;
psb->sb = sb;
@@ -1863,11 +1877,11 @@ static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent)
err = pohmelfs_parse_options((char *) data, psb, 0);
if (err)
- goto err_out_free_sb;
+ goto err_out_free_bdi;
err = pohmelfs_copy_crypto(psb);
if (err)
- goto err_out_free_sb;
+ goto err_out_free_bdi;
err = pohmelfs_state_init(psb);
if (err)
@@ -1916,6 +1930,8 @@ err_out_state_exit:
err_out_free_strings:
kfree(psb->cipher_string);
kfree(psb->hash_string);
+err_out_free_bdi:
+ bdi_destroy(&psb->bdi);
err_out_free_sb:
kfree(psb);
err_out_exit:
diff --git a/drivers/staging/pohmelfs/netfs.h b/drivers/staging/pohmelfs/netfs.h
index 623a07d29dea..01cba006e07a 100644
--- a/drivers/staging/pohmelfs/netfs.h
+++ b/drivers/staging/pohmelfs/netfs.h
@@ -18,6 +18,7 @@
#include <linux/types.h>
#include <linux/connector.h>
+#include <linux/backing-dev.h>
#define POHMELFS_CN_IDX 5
#define POHMELFS_CN_VAL 0
@@ -624,6 +625,8 @@ struct pohmelfs_sb {
struct super_block *sb;
+ struct backing_dev_info bdi;
+
/*
* Algorithm strings.
*/
diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c
index f7726f1d3641..1561f74a413b 100644
--- a/drivers/staging/quatech_usb2/quatech_usb2.c
+++ b/drivers/staging/quatech_usb2/quatech_usb2.c
@@ -116,7 +116,7 @@ static int debug;
#define FOURTHCHAR ((unsigned char *)(urb->transfer_buffer))[i + 3]
#define FIFTHCHAR ((unsigned char *)(urb->transfer_buffer))[i + 4]
-static struct usb_device_id quausb2_id_table[] = {
+static const struct usb_device_id quausb2_id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)},
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)},
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)},
diff --git a/drivers/staging/ramzswap/Kconfig b/drivers/staging/ramzswap/Kconfig
index 24e25691fae2..127b3c6c9596 100644
--- a/drivers/staging/ramzswap/Kconfig
+++ b/drivers/staging/ramzswap/Kconfig
@@ -5,7 +5,7 @@ config RAMZSWAP
select LZO_DECOMPRESS
default n
help
- Creates virtual block devices which can be used (only) as a swap
+ Creates virtual block devices which can (only) be used as swap
disks. Pages swapped to these disks are compressed and stored in
memory itself.
diff --git a/drivers/staging/ramzswap/ramzswap.txt b/drivers/staging/ramzswap/ramzswap.txt
index e9f1619505a0..9694acfeb43f 100644
--- a/drivers/staging/ramzswap/ramzswap.txt
+++ b/drivers/staging/ramzswap/ramzswap.txt
@@ -5,9 +5,9 @@ Project home: http://compcache.googlecode.com/
* Introduction
-It creates RAM based block devices which can be used (only) as swap disks.
-Pages swapped to these devices are compressed and stored in memory itself.
-See project home for use cases, performance numbers and a lot more.
+The ramzswap module creates RAM based block devices which can (only) be used as
+swap disks. Pages swapped to these devices are compressed and stored in memory
+itself. See project home for use cases, performance numbers and a lot more.
Individual ramzswap devices are configured and initialized using rzscontrol
userspace utility as shown in examples below. See rzscontrol man page for more
diff --git a/drivers/staging/ramzswap/ramzswap_drv.c b/drivers/staging/ramzswap/ramzswap_drv.c
index 989fac5b01b3..5e422e254ee8 100644
--- a/drivers/staging/ramzswap/ramzswap_drv.c
+++ b/drivers/staging/ramzswap/ramzswap_drv.c
@@ -1,7 +1,7 @@
/*
* Compressed RAM based swap device
*
- * Copyright (C) 2008, 2009 Nitin Gupta
+ * Copyright (C) 2008, 2009, 2010 Nitin Gupta
*
* This code is released using a dual license strategy: BSD/GPL
* You can choose the licence that better fits your requirements.
@@ -24,12 +24,10 @@
#include <linux/genhd.h>
#include <linux/highmem.h>
#include <linux/lzo.h>
-#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/swap.h>
#include <linux/swapops.h>
#include <linux/vmalloc.h>
-#include <linux/version.h>
#include "ramzswap_drv.h"
@@ -222,7 +220,7 @@ out:
return ret;
}
-void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
+static void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
struct ramzswap_ioctl_stats *s)
{
strncpy(s->backing_swap_name, rzs->backing_swap_name,
@@ -240,7 +238,8 @@ void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
mem_used = xv_get_total_size_bytes(rzs->mem_pool)
+ (rs->pages_expand << PAGE_SHIFT);
- succ_writes = rs->num_writes - rs->failed_writes;
+ succ_writes = rzs_stat64_read(rzs, &rs->num_writes) -
+ rzs_stat64_read(rzs, &rs->failed_writes);
if (succ_writes && rs->pages_stored) {
good_compress_perc = rs->good_compress * 100
@@ -249,11 +248,12 @@ void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
/ rs->pages_stored;
}
- s->num_reads = rs->num_reads;
- s->num_writes = rs->num_writes;
- s->failed_reads = rs->failed_reads;
- s->failed_writes = rs->failed_writes;
- s->invalid_io = rs->invalid_io;
+ s->num_reads = rzs_stat64_read(rzs, &rs->num_reads);
+ s->num_writes = rzs_stat64_read(rzs, &rs->num_writes);
+ s->failed_reads = rzs_stat64_read(rzs, &rs->failed_reads);
+ s->failed_writes = rzs_stat64_read(rzs, &rs->failed_writes);
+ s->invalid_io = rzs_stat64_read(rzs, &rs->invalid_io);
+ s->notify_free = rzs_stat64_read(rzs, &rs->notify_free);
s->pages_zero = rs->pages_zero;
s->good_compress_pct = good_compress_perc;
@@ -265,8 +265,8 @@ void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
s->compr_data_size = rs->compr_size;
s->mem_used_total = mem_used;
- s->bdev_num_reads = rs->bdev_num_reads;
- s->bdev_num_writes = rs->bdev_num_writes;
+ s->bdev_num_reads = rzs_stat64_read(rzs, &rs->bdev_num_reads);
+ s->bdev_num_writes = rzs_stat64_read(rzs, &rs->bdev_num_writes);
}
#endif /* CONFIG_RAMZSWAP_STATS */
}
@@ -502,6 +502,14 @@ static int setup_backing_swap(struct ramzswap *rzs)
goto bad_param;
}
disksize = i_size_read(inode);
+ /*
+ * Can happen if user gives an extended partition as
+ * backing swap or simply a bad disk.
+ */
+ if (!disksize) {
+ pr_err("Error reading backing swap size.\n");
+ goto bad_param;
+ }
} else if (S_ISREG(inode->i_mode)) {
bdev = inode->i_sb->s_bdev;
if (IS_SWAPFILE(inode)) {
@@ -519,7 +527,6 @@ static int setup_backing_swap(struct ramzswap *rzs)
rzs->swap_file = swap_file;
rzs->backing_swap = bdev;
rzs->disksize = disksize;
- BUG_ON(!rzs->disksize);
return 0;
@@ -537,7 +544,7 @@ out:
* Map logical page number 'pagenum' to physical page number
* on backing swap device. For block device, this is a nop.
*/
-u32 map_backing_swap_page(struct ramzswap *rzs, u32 pagenum)
+static u32 map_backing_swap_page(struct ramzswap *rzs, u32 pagenum)
{
u32 skip_pages, entries_per_page;
size_t delta, se_offset, skipped;
@@ -593,9 +600,13 @@ static void ramzswap_free_page(struct ramzswap *rzs, size_t index)
u32 offset = rzs->table[index].offset;
if (unlikely(!page)) {
+ /*
+ * No memory is allocated for zero filled pages.
+ * Simply clear zero page flag.
+ */
if (rzs_test_flag(rzs, index, RZS_ZERO)) {
rzs_clear_flag(rzs, index, RZS_ZERO);
- stat_dec(rzs->stats.pages_zero);
+ rzs_stat_dec(&rzs->stats.pages_zero);
}
return;
}
@@ -604,7 +615,7 @@ static void ramzswap_free_page(struct ramzswap *rzs, size_t index)
clen = PAGE_SIZE;
__free_page(page);
rzs_clear_flag(rzs, index, RZS_UNCOMPRESSED);
- stat_dec(rzs->stats.pages_expand);
+ rzs_stat_dec(&rzs->stats.pages_expand);
goto out;
}
@@ -614,11 +625,11 @@ static void ramzswap_free_page(struct ramzswap *rzs, size_t index)
xv_free(rzs->mem_pool, page, offset);
if (clen <= PAGE_SIZE / 2)
- stat_dec(rzs->stats.good_compress);
+ rzs_stat_dec(&rzs->stats.good_compress);
out:
rzs->stats.compr_size -= clen;
- stat_dec(rzs->stats.pages_stored);
+ rzs_stat_dec(&rzs->stats.pages_stored);
rzs->table[index].page = NULL;
rzs->table[index].offset = 0;
@@ -664,7 +675,6 @@ static int handle_uncompressed_page(struct ramzswap *rzs, struct bio *bio)
return 0;
}
-
/*
* Called when request page is not present in ramzswap.
* Its either in backing swap device (if present) or
@@ -680,8 +690,8 @@ static int handle_ramzswap_fault(struct ramzswap *rzs, struct bio *bio)
*/
if (rzs->backing_swap) {
u32 pagenum;
- stat_dec(rzs->stats.num_reads);
- stat_inc(rzs->stats.bdev_num_reads);
+ rzs_stat64_dec(rzs, &rzs->stats.num_reads);
+ rzs_stat64_inc(rzs, &rzs->stats.bdev_num_reads);
bio->bi_bdev = rzs->backing_swap;
/*
@@ -719,7 +729,7 @@ static int ramzswap_read(struct ramzswap *rzs, struct bio *bio)
struct zobj_header *zheader;
unsigned char *user_mem, *cmem;
- stat_inc(rzs->stats.num_reads);
+ rzs_stat64_inc(rzs, &rzs->stats.num_reads);
page = bio->bi_io_vec[0].bv_page;
index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
@@ -731,7 +741,7 @@ static int ramzswap_read(struct ramzswap *rzs, struct bio *bio)
if (!rzs->table[index].page)
return handle_ramzswap_fault(rzs, bio);
- /* Page is stored uncompressed since its incompressible */
+ /* Page is stored uncompressed since it's incompressible */
if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)))
return handle_uncompressed_page(rzs, bio);
@@ -753,7 +763,7 @@ static int ramzswap_read(struct ramzswap *rzs, struct bio *bio)
if (unlikely(ret != LZO_E_OK)) {
pr_err("Decompression failed! err=%d, page=%u\n",
ret, index);
- stat_inc(rzs->stats.failed_reads);
+ rzs_stat64_inc(rzs, &rzs->stats.failed_reads);
goto out;
}
@@ -777,7 +787,7 @@ static int ramzswap_write(struct ramzswap *rzs, struct bio *bio)
struct page *page, *page_store;
unsigned char *user_mem, *cmem, *src;
- stat_inc(rzs->stats.num_writes);
+ rzs_stat64_inc(rzs, &rzs->stats.num_writes);
page = bio->bi_io_vec[0].bv_page;
index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
@@ -789,25 +799,16 @@ static int ramzswap_write(struct ramzswap *rzs, struct bio *bio)
* is no longer referenced by any process. So, its now safe
* to free the memory that was allocated for this page.
*/
- if (rzs->table[index].page)
+ if (rzs->table[index].page || rzs_test_flag(rzs, index, RZS_ZERO))
ramzswap_free_page(rzs, index);
- /*
- * No memory ia allocated for zero filled pages.
- * Simply clear zero page flag.
- */
- if (rzs_test_flag(rzs, index, RZS_ZERO)) {
- stat_dec(rzs->stats.pages_zero);
- rzs_clear_flag(rzs, index, RZS_ZERO);
- }
-
mutex_lock(&rzs->lock);
user_mem = kmap_atomic(page, KM_USER0);
if (page_zero_filled(user_mem)) {
kunmap_atomic(user_mem, KM_USER0);
mutex_unlock(&rzs->lock);
- stat_inc(rzs->stats.pages_zero);
+ rzs_stat_inc(&rzs->stats.pages_zero);
rzs_set_flag(rzs, index, RZS_ZERO);
set_bit(BIO_UPTODATE, &bio->bi_flags);
@@ -831,7 +832,7 @@ static int ramzswap_write(struct ramzswap *rzs, struct bio *bio)
if (unlikely(ret != LZO_E_OK)) {
mutex_unlock(&rzs->lock);
pr_err("Compression failed! err=%d\n", ret);
- stat_inc(rzs->stats.failed_writes);
+ rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
goto out;
}
@@ -854,13 +855,13 @@ static int ramzswap_write(struct ramzswap *rzs, struct bio *bio)
mutex_unlock(&rzs->lock);
pr_info("Error allocating memory for incompressible "
"page: %u\n", index);
- stat_inc(rzs->stats.failed_writes);
+ rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
goto out;
}
offset = 0;
rzs_set_flag(rzs, index, RZS_UNCOMPRESSED);
- stat_inc(rzs->stats.pages_expand);
+ rzs_stat_inc(&rzs->stats.pages_expand);
rzs->table[index].page = page_store;
src = kmap_atomic(page, KM_USER0);
goto memstore;
@@ -872,7 +873,7 @@ static int ramzswap_write(struct ramzswap *rzs, struct bio *bio)
mutex_unlock(&rzs->lock);
pr_info("Error allocating memory for compressed "
"page: %u, size=%zu\n", index, clen);
- stat_inc(rzs->stats.failed_writes);
+ rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
if (rzs->backing_swap)
fwd_write_request = 1;
goto out;
@@ -901,9 +902,9 @@ memstore:
/* Update stats */
rzs->stats.compr_size += clen;
- stat_inc(rzs->stats.pages_stored);
+ rzs_stat_inc(&rzs->stats.pages_stored);
if (clen <= PAGE_SIZE / 2)
- stat_inc(rzs->stats.good_compress);
+ rzs_stat_inc(&rzs->stats.good_compress);
mutex_unlock(&rzs->lock);
@@ -913,7 +914,7 @@ memstore:
out:
if (fwd_write_request) {
- stat_inc(rzs->stats.bdev_num_writes);
+ rzs_stat64_inc(rzs, &rzs->stats.bdev_num_writes);
bio->bi_bdev = rzs->backing_swap;
#if 0
/*
@@ -941,7 +942,6 @@ out:
return 0;
}
-
/*
* Check if request is within bounds and page aligned.
*/
@@ -975,7 +975,7 @@ static int ramzswap_make_request(struct request_queue *queue, struct bio *bio)
}
if (!valid_swap_request(rzs, bio)) {
- stat_inc(rzs->stats.invalid_io);
+ rzs_stat64_inc(rzs, &rzs->stats.invalid_io);
bio_io_error(bio);
return 0;
}
@@ -1000,6 +1000,9 @@ static void reset_device(struct ramzswap *rzs)
unsigned entries_per_page;
unsigned long num_table_pages, entry = 0;
+ /* Do not accept any new I/O request */
+ rzs->init_done = 0;
+
if (rzs->backing_swap && !rzs->num_extents)
is_backing_blkdev = 1;
@@ -1066,6 +1069,7 @@ static void reset_device(struct ramzswap *rzs)
bd_release(rzs->backing_swap);
filp_close(rzs->swap_file, NULL);
rzs->backing_swap = NULL;
+ memset(rzs->backing_swap_name, 0, MAX_SWAP_NAME_LEN);
}
/* Reset stats */
@@ -1073,9 +1077,6 @@ static void reset_device(struct ramzswap *rzs)
rzs->disksize = 0;
rzs->memlimit = 0;
-
- /* Back to uninitialized state */
- rzs->init_done = 0;
}
static int ramzswap_ioctl_init_device(struct ramzswap *rzs)
@@ -1276,6 +1277,11 @@ static int ramzswap_ioctl(struct block_device *bdev, fmode_t mode,
ret = -EBUSY;
goto out;
}
+
+ /* Make sure all pending I/O is finished */
+ if (bdev)
+ fsync_bdev(bdev);
+
ret = ramzswap_ioctl_reset_device(rzs);
break;
@@ -1293,16 +1299,20 @@ static struct block_device_operations ramzswap_devops = {
.owner = THIS_MODULE,
};
-static void create_device(struct ramzswap *rzs, int device_id)
+static int create_device(struct ramzswap *rzs, int device_id)
{
+ int ret = 0;
+
mutex_init(&rzs->lock);
+ spin_lock_init(&rzs->stat64_lock);
INIT_LIST_HEAD(&rzs->backing_swap_extent_list);
rzs->queue = blk_alloc_queue(GFP_KERNEL);
if (!rzs->queue) {
pr_err("Error allocating disk queue for device %d\n",
device_id);
- return;
+ ret = -ENOMEM;
+ goto out;
}
blk_queue_make_request(rzs->queue, ramzswap_make_request);
@@ -1314,7 +1324,8 @@ static void create_device(struct ramzswap *rzs, int device_id)
blk_cleanup_queue(rzs->queue);
pr_warning("Error allocating disk structure for device %d\n",
device_id);
- return;
+ ret = -ENOMEM;
+ goto out;
}
rzs->disk->major = ramzswap_major;
@@ -1329,9 +1340,16 @@ static void create_device(struct ramzswap *rzs, int device_id)
* or set equal to backing swap device (if provided)
*/
set_capacity(rzs->disk, 0);
+
+ blk_queue_physical_block_size(rzs->disk->queue, PAGE_SIZE);
+ blk_queue_logical_block_size(rzs->disk->queue, PAGE_SIZE);
+
add_disk(rzs->disk);
rzs->init_done = 0;
+
+out:
+ return ret;
}
static void destroy_device(struct ramzswap *rzs)
@@ -1347,18 +1365,20 @@ static void destroy_device(struct ramzswap *rzs)
static int __init ramzswap_init(void)
{
- int i, ret;
+ int ret, dev_id;
if (num_devices > max_num_devices) {
pr_warning("Invalid value for num_devices: %u\n",
num_devices);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
ramzswap_major = register_blkdev(0, "ramzswap");
if (ramzswap_major <= 0) {
pr_warning("Unable to get major number\n");
- return -EBUSY;
+ ret = -EBUSY;
+ goto out;
}
if (!num_devices) {
@@ -1371,15 +1391,23 @@ static int __init ramzswap_init(void)
devices = kzalloc(num_devices * sizeof(struct ramzswap), GFP_KERNEL);
if (!devices) {
ret = -ENOMEM;
- goto out;
+ goto unregister;
}
- for (i = 0; i < num_devices; i++)
- create_device(&devices[i], i);
+ for (dev_id = 0; dev_id < num_devices; dev_id++) {
+ ret = create_device(&devices[dev_id], dev_id);
+ if (ret)
+ goto free_devices;
+ }
return 0;
-out:
+
+free_devices:
+ while (dev_id)
+ destroy_device(&devices[--dev_id]);
+unregister:
unregister_blkdev(ramzswap_major, "ramzswap");
+out:
return ret;
}
diff --git a/drivers/staging/ramzswap/ramzswap_drv.h b/drivers/staging/ramzswap/ramzswap_drv.h
index a6ea240935b6..c7e0e767c223 100644
--- a/drivers/staging/ramzswap/ramzswap_drv.h
+++ b/drivers/staging/ramzswap/ramzswap_drv.h
@@ -1,7 +1,7 @@
/*
* Compressed RAM based swap device
*
- * Copyright (C) 2008, 2009 Nitin Gupta
+ * Copyright (C) 2008, 2009, 2010 Nitin Gupta
*
* This code is released using a dual license strategy: BSD/GPL
* You can choose the licence that better fits your requirements.
@@ -15,6 +15,9 @@
#ifndef _RAMZSWAP_DRV_H_
#define _RAMZSWAP_DRV_H_
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+
#include "ramzswap_ioctl.h"
#include "xvmalloc.h"
@@ -71,15 +74,6 @@ static const unsigned max_zpage_size_nobdev = PAGE_SIZE / 4 * 3;
#define SECTORS_PER_PAGE_SHIFT (PAGE_SHIFT - SECTOR_SHIFT)
#define SECTORS_PER_PAGE (1 << SECTORS_PER_PAGE_SHIFT)
-/* Debugging and Stats */
-#if defined(CONFIG_RAMZSWAP_STATS)
-#define stat_inc(stat) ((stat)++)
-#define stat_dec(stat) ((stat)--)
-#else
-#define stat_inc(x)
-#define stat_dec(x)
-#endif
-
/* Flags for ramzswap pages (table[page_no].flags) */
enum rzs_pageflags {
/* Page is stored uncompressed */
@@ -102,7 +96,7 @@ struct table {
u16 offset;
u8 count; /* object ref count (not yet used) */
u8 flags;
-} __attribute__((aligned(4)));;
+} __attribute__((aligned(4)));
/*
* Swap extent information in case backing swap is a regular
@@ -121,9 +115,10 @@ struct ramzswap_stats {
#if defined(CONFIG_RAMZSWAP_STATS)
u64 num_reads; /* failed + successful */
u64 num_writes; /* --do-- */
- u64 failed_reads; /* can happen when memory is too low */
- u64 failed_writes; /* should NEVER! happen */
+ u64 failed_reads; /* should NEVER! happen */
+ u64 failed_writes; /* can happen when memory is too low */
u64 invalid_io; /* non-swap I/O requests */
+ u64 notify_free; /* no. of swap slot free notifications */
u32 pages_zero; /* no. of zero filled pages */
u32 pages_stored; /* no. of pages currently stored */
u32 good_compress; /* % of pages with compression ratio<=50% */
@@ -138,6 +133,7 @@ struct ramzswap {
void *compress_workmem;
void *compress_buffer;
struct table *table;
+ spinlock_t stat64_lock; /* protect 64-bit stats */
struct mutex lock;
struct request_queue *queue;
struct gendisk *disk;
@@ -167,5 +163,48 @@ struct ramzswap {
/*-- */
-#endif
+/* Debugging and Stats */
+#if defined(CONFIG_RAMZSWAP_STATS)
+static void rzs_stat_inc(u32 *v)
+{
+ *v = *v + 1;
+}
+
+static void rzs_stat_dec(u32 *v)
+{
+ *v = *v - 1;
+}
+
+static void rzs_stat64_inc(struct ramzswap *rzs, u64 *v)
+{
+ spin_lock(&rzs->stat64_lock);
+ *v = *v + 1;
+ spin_unlock(&rzs->stat64_lock);
+}
+
+static void rzs_stat64_dec(struct ramzswap *rzs, u64 *v)
+{
+ spin_lock(&rzs->stat64_lock);
+ *v = *v - 1;
+ spin_unlock(&rzs->stat64_lock);
+}
+
+static u64 rzs_stat64_read(struct ramzswap *rzs, u64 *v)
+{
+ u64 val;
+
+ spin_lock(&rzs->stat64_lock);
+ val = *v;
+ spin_unlock(&rzs->stat64_lock);
+
+ return val;
+}
+#else
+#define rzs_stat_inc(v)
+#define rzs_stat_dec(v)
+#define rzs_stat64_inc(r, v)
+#define rzs_stat64_dec(r, v)
+#define rzs_stat64_read(r, v)
+#endif /* CONFIG_RAMZSWAP_STATS */
+#endif
diff --git a/drivers/staging/ramzswap/ramzswap_ioctl.h b/drivers/staging/ramzswap/ramzswap_ioctl.h
index c713a09af580..d26076d41bde 100644
--- a/drivers/staging/ramzswap/ramzswap_ioctl.h
+++ b/drivers/staging/ramzswap/ramzswap_ioctl.h
@@ -1,7 +1,7 @@
/*
* Compressed RAM based swap device
*
- * Copyright (C) 2008, 2009 Nitin Gupta
+ * Copyright (C) 2008, 2009, 2010 Nitin Gupta
*
* This code is released using a dual license strategy: BSD/GPL
* You can choose the licence that better fits your requirements.
@@ -24,9 +24,10 @@ struct ramzswap_ioctl_stats {
* size (if present) */
u64 num_reads; /* failed + successful */
u64 num_writes; /* --do-- */
- u64 failed_reads; /* can happen when memory is too low */
- u64 failed_writes; /* should NEVER! happen */
+ u64 failed_reads; /* should NEVER! happen */
+ u64 failed_writes; /* can happen when memory is too low */
u64 invalid_io; /* non-swap I/O requests */
+ u64 notify_free; /* no. of swap slot free notifications */
u32 pages_zero; /* no. of zero filled pages */
u32 good_compress_pct; /* no. of pages with compression ratio<=50% */
u32 pages_expand_pct; /* no. of incompressible pages */
diff --git a/drivers/staging/ramzswap/xvmalloc.c b/drivers/staging/ramzswap/xvmalloc.c
index b3e986c33141..3fdbb8ada827 100644
--- a/drivers/staging/ramzswap/xvmalloc.c
+++ b/drivers/staging/ramzswap/xvmalloc.c
@@ -1,7 +1,7 @@
/*
* xvmalloc memory allocator
*
- * Copyright (C) 2008, 2009 Nitin Gupta
+ * Copyright (C) 2008, 2009, 2010 Nitin Gupta
*
* This code is released using a dual license strategy: BSD/GPL
* You can choose the licence that better fits your requirements.
@@ -273,7 +273,7 @@ static void remove_block(struct xv_pool *pool, struct page *page, u32 offset,
}
/*
- * Allocate a page and add it freelist of given pool.
+ * Allocate a page and add it to freelist of given pool.
*/
static int grow_pool(struct xv_pool *pool, gfp_t flags)
{
diff --git a/drivers/staging/ramzswap/xvmalloc.h b/drivers/staging/ramzswap/xvmalloc.h
index 010c6fe5e173..5b1a81aa5faf 100644
--- a/drivers/staging/ramzswap/xvmalloc.h
+++ b/drivers/staging/ramzswap/xvmalloc.h
@@ -1,7 +1,7 @@
/*
* xvmalloc memory allocator
*
- * Copyright (C) 2008, 2009 Nitin Gupta
+ * Copyright (C) 2008, 2009, 2010 Nitin Gupta
*
* This code is released using a dual license strategy: BSD/GPL
* You can choose the licence that better fits your requirements.
diff --git a/drivers/staging/ramzswap/xvmalloc_int.h b/drivers/staging/ramzswap/xvmalloc_int.h
index 03c1a652a3aa..e23ed5c8b8e4 100644
--- a/drivers/staging/ramzswap/xvmalloc_int.h
+++ b/drivers/staging/ramzswap/xvmalloc_int.h
@@ -1,7 +1,7 @@
/*
* xvmalloc memory allocator
*
- * Copyright (C) 2008, 2009 Nitin Gupta
+ * Copyright (C) 2008, 2009, 2010 Nitin Gupta
*
* This code is released using a dual license strategy: BSD/GPL
* You can choose the licence that better fits your requirements.
@@ -62,7 +62,7 @@ struct link_free {
struct block_header {
union {
- /* This common header must be ALIGN bytes */
+ /* This common header must be XV_ALIGN bytes */
u8 common[XV_ALIGN];
struct {
u16 size;
diff --git a/drivers/staging/rar/Kconfig b/drivers/staging/rar/Kconfig
deleted file mode 100644
index 17f8bf3bb41a..000000000000
--- a/drivers/staging/rar/Kconfig
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# RAR device configuration
-#
-
-menu "RAR Register Driver"
-#
-# Restricted Access Register Manager
-#
-config RAR_REGISTER
- tristate "Restricted Access Region Register Driver"
- default n
- ---help---
- This driver allows other kernel drivers access to the
- contents of the restricted access region control
- registers.
-
-endmenu
diff --git a/drivers/staging/rar/Makefile b/drivers/staging/rar/Makefile
deleted file mode 100644
index 5422ed04ccf1..000000000000
--- a/drivers/staging/rar/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-EXTRA_CFLAGS += -DLITTLE__ENDIAN
-obj-$(CONFIG_RAR_REGISTER) += rar_driver.o
diff --git a/drivers/staging/rar/rar_driver.c b/drivers/staging/rar/rar_driver.c
deleted file mode 100644
index d85d1890e81e..000000000000
--- a/drivers/staging/rar/rar_driver.c
+++ /dev/null
@@ -1,444 +0,0 @@
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/kdev_t.h>
-#include <linux/semaphore.h>
-#include <linux/mm.h>
-#include <linux/poll.h>
-#include <linux/wait.h>
-#include <linux/ioctl.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/pagemap.h>
-#include <linux/pci.h>
-#include <linux/firmware.h>
-#include <linux/sched.h>
-#include "rar_driver.h"
-
-/* The following defines are for the IPC process to retrieve RAR in */
-
-/* === Lincroft Message Bus Interface === */
-/* Message Control Register */
-#define LNC_MCR_OFFSET 0xD0
-
-/* Message Data Register */
-#define LNC_MDR_OFFSET 0xD4
-
-/* Message Opcodes */
-#define LNC_MESSAGE_READ_OPCODE 0xD0
-#define LNC_MESSAGE_WRITE_OPCODE 0xE0
-
-/* Message Write Byte Enables */
-#define LNC_MESSAGE_BYTE_WRITE_ENABLES 0xF
-
-/* B-unit Port */
-#define LNC_BUNIT_PORT 0x3
-
-/* === Lincroft B-Unit Registers - Programmed by IA32 firmware === */
-#define LNC_BRAR0L 0x10
-#define LNC_BRAR0H 0x11
-#define LNC_BRAR1L 0x12
-#define LNC_BRAR1H 0x13
-
-/* Reserved for SeP */
-#define LNC_BRAR2L 0x14
-#define LNC_BRAR2H 0x15
-
-
-/* This structure is only used during module initialization. */
-struct RAR_offsets {
- int low; /* Register offset for low RAR physical address. */
- int high; /* Register offset for high RAR physical address. */
-};
-
-struct pci_dev *rar_dev;
-static uint32_t registered;
-
-/* Moorestown supports three restricted access regions. */
-#define MRST_NUM_RAR 3
-
-struct RAR_address_struct rar_addr[MRST_NUM_RAR];
-
-/* prototype for init */
-static int __init rar_init_handler(void);
-static void __exit rar_exit_handler(void);
-
-/*
- function that is activated on the successfull probe of the RAR device
-*/
-static int __devinit rar_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
-
-static struct pci_device_id rar_pci_id_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4110) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl);
-
-/* field for registering driver to PCI device */
-static struct pci_driver rar_pci_driver = {
- .name = "rar_driver",
- .id_table = rar_pci_id_tbl,
- .probe = rar_probe
-};
-
-/* This function is used to retrieved RAR info using the IPC message
- bus interface */
-static int memrar_get_rar_addr(struct pci_dev* pdev,
- int offset,
- u32 *addr)
-{
- /*
- * ======== The Lincroft Message Bus Interface ========
- * Lincroft registers may be obtained from the PCI
- * (the Host Bridge) using the Lincroft Message Bus
- * Interface. That message bus interface is generally
- * comprised of two registers: a control register (MCR, 0xDO)
- * and a data register (MDR, 0xD4).
- *
- * The MCR (message control register) format is the following:
- * 1. [31:24]: Opcode
- * 2. [23:16]: Port
- * 3. [15:8]: Register Offset
- * 4. [7:4]: Byte Enables (use 0xF to set all of these bits
- * to 1)
- * 5. [3:0]: reserved
- *
- * Read (0xD0) and write (0xE0) opcodes are written to the
- * control register when reading and writing to Lincroft
- * registers, respectively.
- *
- * We're interested in registers found in the Lincroft
- * B-unit. The B-unit port is 0x3.
- *
- * The six B-unit RAR register offsets we use are listed
- * earlier in this file.
- *
- * Lastly writing to the MCR register requires the "Byte
- * enables" bits to be set to 1. This may be achieved by
- * writing 0xF at bit 4.
- *
- * The MDR (message data register) format is the following:
- * 1. [31:0]: Read/Write Data
- *
- * Data being read from this register is only available after
- * writing the appropriate control message to the MCR
- * register.
- *
- * Data being written to this register must be written before
- * writing the appropriate control message to the MCR
- * register.
- */
-
- int result = 0; /* result */
- /* Construct control message */
- u32 const message =
- (LNC_MESSAGE_READ_OPCODE << 24)
- | (LNC_BUNIT_PORT << 16)
- | (offset << 8)
- | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
-
- printk(KERN_WARNING "rar- offset to LNC MSG is %x\n",offset);
-
- if (addr == 0)
- return -EINVAL;
-
- /* Send the control message */
- result = pci_write_config_dword(pdev,
- LNC_MCR_OFFSET,
- message);
-
- printk(KERN_WARNING "rar- result from send ctl register is %x\n"
- ,result);
-
- if (!result)
- result = pci_read_config_dword(pdev,
- LNC_MDR_OFFSET,
- addr);
-
- printk(KERN_WARNING "rar- result from read data register is %x\n",
- result);
-
- printk(KERN_WARNING "rar- value read from data register is %x\n",
- *addr);
-
- if (result)
- return -1;
- else
- return 0;
-}
-
-static int memrar_set_rar_addr(struct pci_dev* pdev,
- int offset,
- u32 addr)
-{
- /*
- * ======== The Lincroft Message Bus Interface ========
- * Lincroft registers may be obtained from the PCI
- * (the Host Bridge) using the Lincroft Message Bus
- * Interface. That message bus interface is generally
- * comprised of two registers: a control register (MCR, 0xDO)
- * and a data register (MDR, 0xD4).
- *
- * The MCR (message control register) format is the following:
- * 1. [31:24]: Opcode
- * 2. [23:16]: Port
- * 3. [15:8]: Register Offset
- * 4. [7:4]: Byte Enables (use 0xF to set all of these bits
- * to 1)
- * 5. [3:0]: reserved
- *
- * Read (0xD0) and write (0xE0) opcodes are written to the
- * control register when reading and writing to Lincroft
- * registers, respectively.
- *
- * We're interested in registers found in the Lincroft
- * B-unit. The B-unit port is 0x3.
- *
- * The six B-unit RAR register offsets we use are listed
- * earlier in this file.
- *
- * Lastly writing to the MCR register requires the "Byte
- * enables" bits to be set to 1. This may be achieved by
- * writing 0xF at bit 4.
- *
- * The MDR (message data register) format is the following:
- * 1. [31:0]: Read/Write Data
- *
- * Data being read from this register is only available after
- * writing the appropriate control message to the MCR
- * register.
- *
- * Data being written to this register must be written before
- * writing the appropriate control message to the MCR
- * register.
- */
-
- int result = 0; /* result */
-
- /* Construct control message */
- u32 const message =
- (LNC_MESSAGE_WRITE_OPCODE << 24)
- | (LNC_BUNIT_PORT << 16)
- | (offset << 8)
- | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
-
- printk(KERN_WARNING "rar- offset to LNC MSG is %x\n",offset);
-
- if (addr == 0)
- return -EINVAL;
-
- /* Send the control message */
- result = pci_write_config_dword(pdev,
- LNC_MDR_OFFSET,
- addr);
-
- printk(KERN_WARNING "rar- result from send ctl register is %x\n"
- ,result);
-
- if (!result)
- result = pci_write_config_dword(pdev,
- LNC_MCR_OFFSET,
- message);
-
- printk(KERN_WARNING "rar- result from write data register is %x\n",
- result);
-
- printk(KERN_WARNING "rar- value read to data register is %x\n",
- addr);
-
- if (result)
- return -1;
- else
- return 0;
-}
-
-/*
-
- * Initialize RAR parameters, such as physical addresses, etc.
-
- */
-static int memrar_init_rar_params(struct pci_dev *pdev)
-{
- struct RAR_offsets const offsets[] = {
- { LNC_BRAR0L, LNC_BRAR0H },
- { LNC_BRAR1L, LNC_BRAR1H },
- { LNC_BRAR2L, LNC_BRAR2H }
- };
-
- size_t const num_offsets = sizeof(offsets) / sizeof(offsets[0]);
- struct RAR_offsets const *end = offsets + num_offsets;
- struct RAR_offsets const *i;
- unsigned int n = 0;
- int result = 0;
-
- /* Retrieve RAR start and end physical addresses. */
-
- /*
- * Access the RAR registers through the Lincroft Message Bus
- * Interface on PCI device: 00:00.0 Host bridge.
- */
-
- /* struct pci_dev *pdev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); */
-
- if (pdev == NULL)
- return -ENODEV;
-
- for (i = offsets; i != end; ++i, ++n) {
- if (memrar_get_rar_addr (pdev,
- (*i).low,
- &(rar_addr[n].low)) != 0
- || memrar_get_rar_addr (pdev,
- (*i).high,
- &(rar_addr[n].high)) != 0) {
- result = -1;
- break;
- }
- }
-
- /* Done accessing the device. */
- /* pci_dev_put(pdev); */
-
- if (result == 0) {
- if(1) {
- size_t z;
- for (z = 0; z != MRST_NUM_RAR; ++z) {
- printk(KERN_WARNING "rar - BRAR[%Zd] physical address low\n"
- "\tlow: 0x%08x\n"
- "\thigh: 0x%08x\n",
- z,
- rar_addr[z].low,
- rar_addr[z].high);
- }
- }
- }
-
- return result;
-}
-
-/*
- function that is activated on the successfull probe of the RAR device
-*/
-static int __devinit rar_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- /* error */
- int error;
-
- /*------------------------
- CODE
- ---------------------------*/
-
- DEBUG_PRINT_0(RAR_DEBUG_LEVEL_EXTENDED,
- "Rar pci probe starting\n");
- error = 0;
-
- /* enable the device */
- error = pci_enable_device(pdev);
- if (error) {
- DEBUG_PRINT_0(RAR_DEBUG_LEVEL_EXTENDED,
- "error enabling pci device\n");
- goto end_function;
- }
-
- rar_dev = pdev;
- registered = 1;
-
- /* Initialize the RAR parameters, which have to be retrieved */
- /* via the message bus service */
- error=memrar_init_rar_params(rar_dev);
-
- if (error) {
- DEBUG_PRINT_0(RAR_DEBUG_LEVEL_EXTENDED,
- "error getting RAR addresses device\n");
- registered = 0;
- goto end_function;
- }
-
-end_function:
-
- return error;
-}
-
-/*
- this function registers th driver to
- the device subsystem( either PCI, USB, etc)
-*/
-static int __init rar_init_handler(void)
-{
- return pci_register_driver(&rar_pci_driver);
-}
-
-static void __exit rar_exit_handler(void)
-{
- pci_unregister_driver(&rar_pci_driver);
-}
-
-module_init(rar_init_handler);
-module_exit(rar_exit_handler);
-
-MODULE_LICENSE("GPL");
-
-
-/* The get_rar_address function is used by other device drivers
- * to obtain RAR address information on a RAR. It takes two
- * parameter:
- *
- * int rar_index
- * The rar_index is an index to the rar for which you wish to retrieve
- * the address information.
- * Values can be 0,1, or 2.
- *
- * struct RAR_address_struct is a pointer to a place to which the function
- * can return the address structure for the RAR.
- *
- * The function returns a 0 upon success or a -1 if there is no RAR
- * facility on this system.
- */
-int get_rar_address(int rar_index,struct RAR_address_struct *addresses)
-{
- if (registered && (rar_index < 3) && (rar_index >= 0)) {
- *addresses=rar_addr[rar_index];
- /* strip off lock bit information */
- addresses->low = addresses->low & 0xfffffff0;
- addresses->high = addresses->high & 0xfffffff0;
- return 0;
- }
-
- else {
- return -ENODEV;
- }
-}
-
-
-EXPORT_SYMBOL(get_rar_address);
-
-/* The lock_rar function is ued by other device drivers to lock an RAR.
- * once an RAR is locked, it stays locked until the next system reboot.
- * The function takes one parameter:
- *
- * int rar_index
- * The rar_index is an index to the rar that you want to lock.
- * Values can be 0,1, or 2.
- *
- * The function returns a 0 upon success or a -1 if there is no RAR
- * facility on this system.
- */
-int lock_rar(int rar_index)
-{
- u32 working_addr;
- int result;
-if (registered && (rar_index < 3) && (rar_index >= 0)) {
- /* first make sure that lock bits are clear (this does lock) */
- working_addr=rar_addr[rar_index].low & 0xfffffff0;
-
- /* now send that value to the register using the IPC */
- result=memrar_set_rar_addr(rar_dev,rar_index,working_addr);
- return result;
- }
-
-else {
- return -ENODEV;
- }
-}
diff --git a/drivers/staging/rar/rar_driver.h b/drivers/staging/rar/rar_driver.h
deleted file mode 100644
index 3690f984ff55..000000000000
--- a/drivers/staging/rar/rar_driver.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* === RAR Physical Addresses === */
-struct RAR_address_struct {
- u32 low;
- u32 high;
-};
-
-/* The get_rar_address function is used by other device drivers
- * to obtain RAR address information on a RAR. It takes two
- * parameter:
- *
- * int rar_index
- * The rar_index is an index to the rar for which you wish to retrieve
- * the address information.
- * Values can be 0,1, or 2.
- *
- * struct RAR_address_struct is a pointer to a place to which the function
- * can return the address structure for the RAR.
- *
- * The function returns a 0 upon success or a -1 if there is no RAR
- * facility on this system.
- */
-int get_rar_address(int rar_index,struct RAR_address_struct *addresses);
-
-
-/* The lock_rar function is ued by other device drivers to lock an RAR.
- * once an RAR is locked, it stays locked until the next system reboot.
- * The function takes one parameter:
- *
- * int rar_index
- * The rar_index is an index to the rar that you want to lock.
- * Values can be 0,1, or 2.
- *
- * The function returns a 0 upon success or a -1 if there is no RAR
- * facility on this system.
- */
-int lock_rar(int rar_index);
-
-
-/* DEBUG LEVEL MASKS */
-#define RAR_DEBUG_LEVEL_BASIC 0x1
-
-#define RAR_DEBUG_LEVEL_REGISTERS 0x2
-
-#define RAR_DEBUG_LEVEL_EXTENDED 0x4
-
-#define DEBUG_LEVEL 0x7
-
-/* FUNCTIONAL MACROS */
-
-/* debug macro without paramaters */
-#define DEBUG_PRINT_0(DEBUG_LEVEL , info) \
-do \
-{ \
- if(DEBUG_LEVEL) \
- { \
- printk(KERN_WARNING info); \
- } \
-}while(0)
-
-/* debug macro with 1 paramater */
-#define DEBUG_PRINT_1(DEBUG_LEVEL , info , param1) \
-do \
-{ \
- if(DEBUG_LEVEL) \
- { \
- printk(KERN_WARNING info , param1); \
- } \
-}while(0)
-
-/* debug macro with 2 paramaters */
-#define DEBUG_PRINT_2(DEBUG_LEVEL , info , param1, param2) \
-do \
-{ \
- if(DEBUG_LEVEL) \
- { \
- printk(KERN_WARNING info , param1, param2); \
- } \
-}while(0)
-
-/* debug macro with 3 paramaters */
-#define DEBUG_PRINT_3(DEBUG_LEVEL , info , param1, param2 , param3) \
-do \
-{ \
- if(DEBUG_LEVEL) \
- { \
- printk(KERN_WARNING info , param1, param2 , param3); \
- } \
-}while(0)
-
-/* debug macro with 4 paramaters */
-#define DEBUG_PRINT_4(DEBUG_LEVEL , info , param1, param2 , param3 , param4) \
-do \
-{ \
- if(DEBUG_LEVEL) \
- { \
- printk(KERN_WARNING info , param1, param2 , param3 , param4); \
- } \
-}while(0)
-
diff --git a/drivers/staging/rar_register/Kconfig b/drivers/staging/rar_register/Kconfig
new file mode 100644
index 000000000000..3f73839643e9
--- /dev/null
+++ b/drivers/staging/rar_register/Kconfig
@@ -0,0 +1,30 @@
+#
+# RAR device configuration
+#
+
+menu "RAR Register Driver"
+#
+# Restricted Access Register Manager
+#
+config RAR_REGISTER
+ tristate "Restricted Access Region Register Driver"
+ default n
+ ---help---
+ This driver allows other kernel drivers access to the
+ contents of the restricted access region control
+ registers.
+
+ The restricted access region control registers
+ (rar_registers) are used to pass address and
+ locking information on restricted access regions
+ to other drivers that use restricted access regions
+
+ The restricted access regions are regions of memory
+ on the Intel MID Platform that are not accessible to
+ the x86 processor, but are accessible to dedicated
+ processors on board peripheral devices.
+
+ The purpose of the restricted access regions is to
+ protect sensitive data from compromise by unauthorized
+ programs running on the x86 processor.
+endmenu
diff --git a/drivers/staging/rar_register/Makefile b/drivers/staging/rar_register/Makefile
new file mode 100644
index 000000000000..d5954ccc16c9
--- /dev/null
+++ b/drivers/staging/rar_register/Makefile
@@ -0,0 +1,2 @@
+EXTRA_CFLAGS += -DLITTLE__ENDIAN
+obj-$(CONFIG_RAR_REGISTER) += rar_register.o
diff --git a/drivers/staging/rar_register/rar_register.c b/drivers/staging/rar_register/rar_register.c
new file mode 100644
index 000000000000..bfc0e31f1a6f
--- /dev/null
+++ b/drivers/staging/rar_register/rar_register.c
@@ -0,0 +1,615 @@
+/*
+ * rar_register.c - An Intel Restricted Access Region register driver
+ *
+ * Copyright(c) 2009 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.
+ *
+ * -------------------------------------------------------------------
+ * 20091204 Mark Allyn <mark.a.allyn@intel.com>
+ * Ossama Othman <ossama.othman@intel.com>
+ * Cleanup per feedback from Alan Cox and Arjan Van De Ven
+ *
+ * 20090806 Ossama Othman <ossama.othman@intel.com>
+ * Return zero high address if upper 22 bits is zero.
+ * Cleaned up checkpatch errors.
+ * Clarified that driver is dealing with bus addresses.
+ *
+ * 20090702 Ossama Othman <ossama.othman@intel.com>
+ * Removed unnecessary include directives
+ * Cleaned up spinlocks.
+ * Cleaned up logging.
+ * Improved invalid parameter checks.
+ * Fixed and simplified RAR address retrieval and RAR locking
+ * code.
+ *
+ * 20090626 Mark Allyn <mark.a.allyn@intel.com>
+ * Initial publish
+ */
+
+#define DEBUG 1
+
+#include "rar_register.h"
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+
+/* === Lincroft Message Bus Interface === */
+/* Message Control Register */
+#define LNC_MCR_OFFSET 0xD0
+
+/* Maximum number of clients (other drivers using this driver) */
+#define MAX_RAR_CLIENTS 10
+
+/* Message Data Register */
+#define LNC_MDR_OFFSET 0xD4
+
+/* Message Opcodes */
+#define LNC_MESSAGE_READ_OPCODE 0xD0
+#define LNC_MESSAGE_WRITE_OPCODE 0xE0
+
+/* Message Write Byte Enables */
+#define LNC_MESSAGE_BYTE_WRITE_ENABLES 0xF
+
+/* B-unit Port */
+#define LNC_BUNIT_PORT 0x3
+
+/* === Lincroft B-Unit Registers - Programmed by IA32 firmware === */
+#define LNC_BRAR0L 0x10
+#define LNC_BRAR0H 0x11
+#define LNC_BRAR1L 0x12
+#define LNC_BRAR1H 0x13
+
+/* Reserved for SeP */
+#define LNC_BRAR2L 0x14
+#define LNC_BRAR2H 0x15
+
+/* Moorestown supports three restricted access regions. */
+#define MRST_NUM_RAR 3
+
+
+/* RAR Bus Address Range */
+struct RAR_address_range {
+ dma_addr_t low;
+ dma_addr_t high;
+};
+
+/* Structure containing low and high RAR register offsets. */
+struct RAR_offsets {
+ u32 low; /* Register offset for low RAR bus address. */
+ u32 high; /* Register offset for high RAR bus address. */
+};
+
+struct client {
+ int (*client_callback)(void *client_data);
+ void *customer_data;
+ int client_called;
+ };
+
+static DEFINE_MUTEX(rar_mutex);
+static DEFINE_MUTEX(lnc_reg_mutex);
+
+struct RAR_device {
+ struct RAR_offsets const rar_offsets[MRST_NUM_RAR];
+ struct RAR_address_range rar_addr[MRST_NUM_RAR];
+ struct pci_dev *rar_dev;
+ bool registered;
+ };
+
+/* this platform has only one rar_device for 3 rar regions */
+static struct RAR_device my_rar_device = {
+ .rar_offsets = {
+ [0].low = LNC_BRAR0L,
+ [0].high = LNC_BRAR0H,
+ [1].low = LNC_BRAR1L,
+ [1].high = LNC_BRAR1H,
+ [2].low = LNC_BRAR2L,
+ [2].high = LNC_BRAR2H
+ }
+};
+
+/* this data is for handling requests from other drivers which arrive
+ * prior to this driver initializing
+ */
+
+static struct client clients[MAX_RAR_CLIENTS];
+static int num_clients;
+
+/*
+ * This function is used to retrieved RAR info using the Lincroft
+ * message bus interface.
+ */
+static int retrieve_rar_addr(struct pci_dev *pdev,
+ int offset,
+ dma_addr_t *addr)
+{
+ /*
+ * ======== The Lincroft Message Bus Interface ========
+ * Lincroft registers may be obtained from the PCI
+ * (the Host Bridge) using the Lincroft Message Bus
+ * Interface. That message bus interface is generally
+ * comprised of two registers: a control register (MCR, 0xDO)
+ * and a data register (MDR, 0xD4).
+ *
+ * The MCR (message control register) format is the following:
+ * 1. [31:24]: Opcode
+ * 2. [23:16]: Port
+ * 3. [15:8]: Register Offset
+ * 4. [7:4]: Byte Enables (use 0xF to set all of these bits
+ * to 1)
+ * 5. [3:0]: reserved
+ *
+ * Read (0xD0) and write (0xE0) opcodes are written to the
+ * control register when reading and writing to Lincroft
+ * registers, respectively.
+ *
+ * We're interested in registers found in the Lincroft
+ * B-unit. The B-unit port is 0x3.
+ *
+ * The six B-unit RAR register offsets we use are listed
+ * earlier in this file.
+ *
+ * Lastly writing to the MCR register requires the "Byte
+ * enables" bits to be set to 1. This may be achieved by
+ * writing 0xF at bit 4.
+ *
+ * The MDR (message data register) format is the following:
+ * 1. [31:0]: Read/Write Data
+ *
+ * Data being read from this register is only available after
+ * writing the appropriate control message to the MCR
+ * register.
+ *
+ * Data being written to this register must be written before
+ * writing the appropriate control message to the MCR
+ * register.
+ */
+
+ int result;
+
+ /* Construct control message */
+ u32 const message =
+ (LNC_MESSAGE_READ_OPCODE << 24)
+ | (LNC_BUNIT_PORT << 16)
+ | (offset << 8)
+ | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
+
+ dev_dbg(&pdev->dev, "Offset for 'get' LNC MSG is %x\n", offset);
+
+ if (addr == 0) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ /*
+ * We synchronize access to the Lincroft MCR and MDR registers
+ * until BOTH the command is issued through the MCR register
+ * and the corresponding data is read from the MDR register.
+ * Otherwise a race condition would exist between accesses to
+ * both registers.
+ */
+
+ mutex_lock(&lnc_reg_mutex);
+
+ /* Send the control message */
+ result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message);
+
+ dev_dbg(&pdev->dev, "Result from send ctl register is %x\n", result);
+
+ if (!result) {
+ result = pci_read_config_dword(pdev, LNC_MDR_OFFSET,
+ (u32 *)addr);
+ dev_dbg(&pdev->dev,
+ "Result from read data register is %x\n", result);
+
+ dev_dbg(&pdev->dev,
+ "Value read from data register is %lx\n",
+ (unsigned long)*addr);
+ }
+
+ mutex_unlock(&lnc_reg_mutex);
+
+ return result;
+}
+
+static int set_rar_address(struct pci_dev *pdev,
+ int offset,
+ dma_addr_t addr)
+{
+ /*
+ * Data being written to this register must be written before
+ * writing the appropriate control message to the MCR
+ * register.
+ * @note See rar_get_address() for a description of the
+ * message bus interface being used here.
+ */
+
+ int result = 0;
+
+ /* Construct control message */
+ u32 const message = (LNC_MESSAGE_WRITE_OPCODE << 24)
+ | (LNC_BUNIT_PORT << 16)
+ | (offset << 8)
+ | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
+
+ if (addr == 0) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ dev_dbg(&pdev->dev, "Offset for 'set' LNC MSG is %x\n", offset);
+
+ /*
+ * We synchronize access to the Lincroft MCR and MDR registers
+ * until BOTH the command is issued through the MCR register
+ * and the corresponding data is read from the MDR register.
+ * Otherwise a race condition would exist between accesses to
+ * both registers.
+ */
+
+ mutex_lock(&lnc_reg_mutex);
+
+ /* Send the control message */
+ result = pci_write_config_dword(pdev, LNC_MDR_OFFSET, addr);
+
+ dev_dbg(&pdev->dev, "Result from write data register is %x\n", result);
+
+ if (!result) {
+ dev_dbg(&pdev->dev,
+ "Value written to data register is %lx\n",
+ (unsigned long)addr);
+
+ result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message);
+
+ dev_dbg(&pdev->dev, "Result from send ctl register is %x\n",
+ result);
+ }
+
+ mutex_unlock(&lnc_reg_mutex);
+
+ return result;
+}
+
+/*
+* Initialize RAR parameters, such as bus addresses, etc.
+*/
+static int init_rar_params(struct pci_dev *pdev)
+{
+ unsigned int i;
+ int result = 0;
+
+ /* Retrieve RAR start and end bus addresses.
+ * Access the RAR registers through the Lincroft Message Bus
+ * Interface on PCI device: 00:00.0 Host bridge.
+ */
+
+ for (i = 0; i < MRST_NUM_RAR; ++i) {
+ struct RAR_offsets const *offset =
+ &my_rar_device.rar_offsets[i];
+ struct RAR_address_range *addr = &my_rar_device.rar_addr[i];
+
+ if ((retrieve_rar_addr(pdev, offset->low, &addr->low) != 0)
+ || (retrieve_rar_addr(pdev, offset->high, &addr->high) != 0)) {
+ result = -1;
+ break;
+ }
+
+ /*
+ * Only the upper 22 bits of the RAR addresses are
+ * stored in their corresponding RAR registers so we
+ * must set the lower 10 bits accordingly.
+
+ * The low address has its lower 10 bits cleared, and
+ * the high address has all its lower 10 bits set,
+ * e.g.:
+ * low = 0x2ffffc00
+ */
+
+ addr->low &= (dma_addr_t)0xfffffc00u;
+
+ /*
+ * Set bits 9:0 on uppser address if bits 31:10 are non
+ * zero; otherwize clear all bits
+ */
+
+ if ((addr->high & 0xfffffc00u) == 0)
+ addr->high = 0;
+ else
+ addr->high |= 0x3ffu;
+ }
+ /* Done accessing the device. */
+
+ if (result == 0) {
+ int z;
+ for (z = 0; z != MRST_NUM_RAR; ++z) {
+ /*
+ * "BRAR" refers to the RAR registers in the
+ * Lincroft B-unit.
+ */
+ dev_info(&pdev->dev, "BRAR[%u] bus address range = "
+ "[%lx, %lx]\n", z,
+ (unsigned long)my_rar_device.rar_addr[z].low,
+ (unsigned long)my_rar_device.rar_addr[z].high);
+ }
+ }
+
+ return result;
+}
+
+/*
+ * The rar_get_address function is used by other device drivers
+ * to obtain RAR address information on a RAR. It takes three
+ * parameters:
+ *
+ * int rar_index
+ * The rar_index is an index to the rar for which you wish to retrieve
+ * the address information.
+ * Values can be 0,1, or 2.
+ *
+ * The function returns a 0 upon success or a -1 if there is no RAR
+ * facility on this system.
+ */
+int rar_get_address(int rar_index,
+ dma_addr_t *start_address,
+ dma_addr_t *end_address)
+{
+ int result = -ENODEV;
+
+ if (my_rar_device.registered) {
+ if (start_address == 0 || end_address == 0
+ || rar_index >= MRST_NUM_RAR || rar_index < 0) {
+ result = -EINVAL;
+ } else {
+ *start_address =
+ my_rar_device.rar_addr[rar_index].low;
+ *end_address =
+ my_rar_device.rar_addr[rar_index].high;
+
+ result = 0;
+ }
+ }
+
+ return result;
+}
+EXPORT_SYMBOL(rar_get_address);
+
+/*
+ * The rar_lock function is ued by other device drivers to lock an RAR.
+ * once an RAR is locked, it stays locked until the next system reboot.
+ * The function takes one parameter:
+ *
+ * int rar_index
+ * The rar_index is an index to the rar that you want to lock.
+ * Values can be 0,1, or 2.
+ *
+ * The function returns a 0 upon success or a -1 if there is no RAR
+ * facility on this system.
+ */
+int rar_lock(int rar_index)
+{
+ int result = -ENODEV;
+
+ if (rar_index >= MRST_NUM_RAR || rar_index < 0) {
+ result = -EINVAL;
+ return result;
+ }
+
+ dev_dbg(&my_rar_device.rar_dev->dev, "rar_lock mutex locking\n");
+ mutex_lock(&rar_mutex);
+
+ if (my_rar_device.registered) {
+
+ dma_addr_t low = my_rar_device.rar_addr[rar_index].low &
+ 0xfffffc00u;
+
+ dma_addr_t high = my_rar_device.rar_addr[rar_index].high &
+ 0xfffffc00u;
+
+ /*
+ * Only allow I/O from the graphics and Langwell;
+ * Not from the x96 processor
+ */
+ if (rar_index == (int)RAR_TYPE_VIDEO) {
+ low |= 0x00000009;
+ high |= 0x00000015;
+ }
+
+ else if (rar_index == (int)RAR_TYPE_AUDIO) {
+ /* Only allow I/O from Langwell; nothing from x86 */
+ low |= 0x00000008;
+ high |= 0x00000018;
+ }
+
+ else
+ /* Read-only from all agents */
+ high |= 0x00000018;
+
+ /*
+ * Now program the register using the Lincroft message
+ * bus interface.
+ */
+ result = set_rar_address(my_rar_device.rar_dev,
+ my_rar_device.rar_offsets[rar_index].low,
+ low);
+
+ if (result == 0)
+ result = set_rar_address(
+ my_rar_device.rar_dev,
+ my_rar_device.rar_offsets[rar_index].high,
+ high);
+ }
+
+ dev_dbg(&my_rar_device.rar_dev->dev, "rar_lock mutex unlocking\n");
+ mutex_unlock(&rar_mutex);
+ return result;
+}
+EXPORT_SYMBOL(rar_lock);
+
+/* The register_rar function is to used by other device drivers
+ * to ensure that this driver is ready. As we cannot be sure of
+ * the compile/execute order of dirvers in ther kernel, it is
+ * best to give this driver a callback function to call when
+ * it is ready to give out addresses. The callback function
+ * would have those steps that continue the initialization of
+ * a driver that do require a valid RAR address. One of those
+ * steps would be to call rar_get_address()
+ * This function return 0 on success an -1 on failure.
+*/
+int register_rar(int (*callback)(void *yourparameter), void *yourparameter)
+{
+
+ int result = -ENODEV;
+
+ if (callback == NULL)
+ return -EINVAL;
+
+ mutex_lock(&rar_mutex);
+
+ if (my_rar_device.registered) {
+
+ mutex_unlock(&rar_mutex);
+ /*
+ * if the driver already registered, then we can simply
+ * call the callback right now
+ */
+
+ return (*callback)(yourparameter);
+ }
+
+ if (num_clients < MRST_NUM_RAR) {
+
+ clients[num_clients].client_callback = callback;
+ clients[num_clients].customer_data = yourparameter;
+ num_clients += 1;
+ result = 0;
+ }
+
+ mutex_unlock(&rar_mutex);
+ return result;
+
+}
+EXPORT_SYMBOL(register_rar);
+
+/* Suspend - returns -ENOSYS */
+static int rar_suspend(struct pci_dev *dev, pm_message_t state)
+{
+ return -ENOSYS;
+}
+
+static int rar_resume(struct pci_dev *dev)
+{
+ return -ENOSYS;
+}
+
+/*
+ * This function registers the driver with the device subsystem (
+ * either PCI, USB, etc).
+ * Function that is activaed on the succesful probe of the RAR device
+ * (Moorestown host controller).
+ */
+static int rar_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ int error;
+ int counter;
+
+ dev_dbg(&dev->dev, "PCI probe starting\n");
+
+ /* enable the device */
+ error = pci_enable_device(dev);
+ if (error) {
+ dev_err(&dev->dev,
+ "Error enabling RAR register PCI device\n");
+ goto end_function;
+ }
+
+ /* we have only one device; fill in the rar_device structure */
+ my_rar_device.rar_dev = dev;
+
+ /*
+ * Initialize the RAR parameters, which have to be retrieved
+ * via the message bus interface.
+ */
+ error = init_rar_params(dev);
+ if (error) {
+ pci_disable_device(dev);
+
+ dev_err(&dev->dev,
+ "Error retrieving RAR addresses\n");
+
+ goto end_function;
+ }
+
+ dev_dbg(&dev->dev, "PCI probe locking\n");
+ mutex_lock(&rar_mutex);
+ my_rar_device.registered = 1;
+
+ /* now call anyone who has registered (using callbacks) */
+ for (counter = 0; counter < num_clients; counter += 1) {
+ if (clients[counter].client_callback) {
+ error = (*clients[counter].client_callback)(
+ clients[counter].customer_data);
+ /* set callback to NULL to indicate it has been done */
+ clients[counter].client_callback = NULL;
+ dev_dbg(&my_rar_device.rar_dev->dev,
+ "Callback called for %d\n",
+ counter);
+ }
+ }
+
+ dev_dbg(&dev->dev, "PCI probe unlocking\n");
+ mutex_unlock(&rar_mutex);
+
+end_function:
+
+ return error;
+}
+
+const struct pci_device_id rar_pci_id_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_RAR_DEVICE_ID) },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl);
+
+const struct pci_device_id *my_id_table = rar_pci_id_tbl;
+
+/* field for registering driver to PCI device */
+static struct pci_driver rar_pci_driver = {
+ .name = "rar_register_driver",
+ .id_table = rar_pci_id_tbl,
+ .probe = rar_probe,
+ .suspend = rar_suspend,
+ .resume = rar_resume
+};
+
+static int __init rar_init_handler(void)
+{
+ return pci_register_driver(&rar_pci_driver);
+}
+
+static void __exit rar_exit_handler(void)
+{
+ pci_unregister_driver(&rar_pci_driver);
+}
+
+module_init(rar_init_handler);
+module_exit(rar_exit_handler);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel Restricted Access Region Register Driver");
diff --git a/drivers/staging/rar_register/rar_register.h b/drivers/staging/rar_register/rar_register.h
new file mode 100644
index 000000000000..29ade0f361d2
--- /dev/null
+++ b/drivers/staging/rar_register/rar_register.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General
+ * Public License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 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 _RAR_REGISTER_H
+#define _RAR_REGISTER_H
+
+# include <linux/types.h>
+
+/* following are used both in drivers as well as user space apps */
+enum RAR_type {
+ RAR_TYPE_VIDEO = 0,
+ RAR_TYPE_AUDIO,
+ RAR_TYPE_IMAGE,
+ RAR_TYPE_DATA
+};
+
+#ifdef __KERNEL__
+
+/* PCI device id for controller */
+#define PCI_RAR_DEVICE_ID 0x4110
+
+/* The register_rar function is to used by other device drivers
+ * to ensure that this driver is ready. As we cannot be sure of
+ * the compile/execute order of dirvers in ther kernel, it is
+ * best to give this driver a callback function to call when
+ * it is ready to give out addresses. The callback function
+ * would have those steps that continue the initialization of
+ * a driver that do require a valid RAR address. One of those
+ * steps would be to call get_rar_address()
+ * This function return 0 on success an -1 on failure.
+ */
+int register_rar(int (*callback)(void *yourparameter), void *yourparameter);
+
+/* The get_rar_address function is used by other device drivers
+ * to obtain RAR address information on a RAR. It takes two
+ * parameter:
+ *
+ * int rar_index
+ * The rar_index is an index to the rar for which you wish to retrieve
+ * the address information.
+ * Values can be 0,1, or 2.
+ *
+ * struct RAR_address_struct is a pointer to a place to which the function
+ * can return the address structure for the RAR.
+ *
+ * The function returns a 0 upon success or a -1 if there is no RAR
+ * facility on this system.
+ */
+int rar_get_address(int rar_index,
+ dma_addr_t *start_address,
+ dma_addr_t *end_address);
+
+/* The lock_rar function is ued by other device drivers to lock an RAR.
+ * once an RAR is locked, it stays locked until the next system reboot.
+ * The function takes one parameter:
+ *
+ * int rar_index
+ * The rar_index is an index to the rar that you want to lock.
+ * Values can be 0,1, or 2.
+ *
+ * The function returns a 0 upon success or a -1 if there is no RAR
+ * facility on this system.
+ */
+int rar_lock(int rar_index);
+
+#endif /* __KERNEL__ */
+#endif /* _RAR_REGISTER_H */
diff --git a/drivers/staging/rt2860/Kconfig b/drivers/staging/rt2860/Kconfig
index f9962b693128..f3a7e47df5e9 100644
--- a/drivers/staging/rt2860/Kconfig
+++ b/drivers/staging/rt2860/Kconfig
@@ -3,6 +3,8 @@ config RT2860
depends on PCI && X86 && WLAN
select WIRELESS_EXT
select WEXT_PRIV
+ select CRC_CCITT
+ select FW_LOADER
---help---
This is an experimental driver for the Ralink 2860 and 3090
wireless chips.
diff --git a/drivers/staging/rt2860/common/firmware.h b/drivers/staging/rt2860/common/firmware.h
deleted file mode 100644
index 2fecd32f7600..000000000000
--- a/drivers/staging/rt2860/common/firmware.h
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- Copyright (c) 2007, Ralink Technology Corporation
- All rights reserved.
-
- Redistribution. Redistribution and use in binary form, without
- modification, are permitted provided that the following conditions are
- met:
-
- * Redistributions must reproduce the above copyright notice and the
- following disclaimer in the documentation and/or other materials
- provided with the distribution.
- * Neither the name of Ralink Technology Corporation nor the names of its
- suppliers may be used to endorse or promote products derived from this
- software without specific prior written permission.
- * No reverse engineering, decompilation, or disassembly of this software
- is permitted.
-
- Limited patent license. Ralink Technology Corporation grants a world-wide,
- royalty-free, non-exclusive license under patents it now or hereafter
- owns or controls to make, have made, use, import, offer to sell and
- sell ("Utilize") this software, but solely to the extent that any
- such patent is necessary to Utilize the software alone, or in
- combination with an operating system licensed under an approved Open
- Source license as listed by the Open Source Initiative at
- http://opensource.org/licenses. The patent license shall not apply to
- any other combinations which include this software. No hardware per
- se is licensed hereunder.
-
- DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
- BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- DAMAGE.
-*/
-/* AUTO GEN PLEASE DO NOT MODIFY IT */
-/* AUTO GEN PLEASE DO NOT MODIFY IT */
-
-
-u8 FirmwareImage_2860 [] = {
-0x02, 0x03, 0x5e, 0x02, 0x02, 0xb1, 0x22, 0x22, 0xff, 0xff, 0xff, 0x02, 0x01, 0x82, 0xff, 0xff,
-0xff, 0xff, 0xff, 0x02, 0x00, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x01, 0x33, 0xc0, 0xe0,
-0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x18, 0xc2, 0xaf, 0x30, 0x45, 0x03,
-0x12, 0x10, 0x09, 0x90, 0x04, 0x16, 0xe0, 0x30, 0xe3, 0x03, 0x74, 0x08, 0xf0, 0x90, 0x04, 0x14,
-0xe0, 0x20, 0xe7, 0x03, 0x02, 0x00, 0xcb, 0x74, 0x80, 0xf0, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x2f,
-0x90, 0x04, 0x04, 0xe0, 0x24, 0xcf, 0x60, 0x30, 0x14, 0x60, 0x42, 0x24, 0xe2, 0x60, 0x47, 0x14,
-0x60, 0x55, 0x24, 0x21, 0x70, 0x60, 0xe5, 0x55, 0x24, 0xfe, 0x60, 0x07, 0x14, 0x60, 0x08, 0x24,
-0x02, 0x70, 0x08, 0x7d, 0x01, 0x80, 0x28, 0x7d, 0x02, 0x80, 0x24, 0x90, 0x70, 0x10, 0xe0, 0xf5,
-0x50, 0x85, 0x2f, 0x40, 0xd2, 0x01, 0x80, 0x3e, 0xe5, 0x55, 0x64, 0x03, 0x60, 0x04, 0xe5, 0x55,
-0x70, 0x04, 0x7d, 0x02, 0x80, 0x09, 0x85, 0x2f, 0x41, 0xd2, 0x02, 0x80, 0x29, 0xad, 0x55, 0xaf,
-0x2f, 0x12, 0x02, 0x8d, 0x80, 0x20, 0x90, 0x70, 0x10, 0xe0, 0xf5, 0x47, 0x90, 0x70, 0x11, 0xe0,
-0xf5, 0x44, 0x12, 0x10, 0x25, 0x80, 0x06, 0x90, 0x70, 0x10, 0xe0, 0xf5, 0x45, 0xe4, 0xfd, 0xaf,
-0x2f, 0x12, 0x02, 0x8d, 0xd2, 0x04, 0x90, 0x70, 0x13, 0xe4, 0xf0, 0xd2, 0xaf, 0xd0, 0xd0, 0xd0,
-0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0x90, 0x70, 0x2a, 0xe0, 0x30, 0xe1, 0x53, 0xc2,
-0xaf, 0x90, 0x70, 0x28, 0xe0, 0x90, 0x10, 0x1c, 0xf0, 0x90, 0x70, 0x29, 0xe0, 0x90, 0x10, 0x1d,
-0xf0, 0x90, 0x70, 0x2a, 0xe0, 0x90, 0x10, 0x1e, 0xf0, 0x90, 0x10, 0x1c, 0xe0, 0xf5, 0x30, 0x90,
-0x10, 0x1e, 0xe0, 0x20, 0xe1, 0xf3, 0x90, 0x10, 0x1c, 0xe0, 0x90, 0x70, 0x28, 0xf0, 0x90, 0x10,
-0x1d, 0xe0, 0x90, 0x70, 0x29, 0xf0, 0x90, 0x10, 0x1e, 0xe0, 0x90, 0x70, 0x2a, 0xf0, 0x30, 0x4a,
-0x0d, 0x90, 0x70, 0x24, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x02, 0x2c, 0x74, 0xff, 0xf0, 0xc2, 0x05,
-0xd2, 0xaf, 0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0xe8, 0xc0, 0xe0,
-0xe9, 0xc0, 0xe0, 0xea, 0xc0, 0xe0, 0xeb, 0xc0, 0xe0, 0xec, 0xc0, 0xe0, 0xed, 0xc0, 0xe0, 0xee,
-0xc0, 0xe0, 0xef, 0xc0, 0xe0, 0xc2, 0xaf, 0x30, 0x45, 0x03, 0x12, 0x10, 0x12, 0xd2, 0xaf, 0xd0,
-0xe0, 0xff, 0xd0, 0xe0, 0xfe, 0xd0, 0xe0, 0xfd, 0xd0, 0xe0, 0xfc, 0xd0, 0xe0, 0xfb, 0xd0, 0xe0,
-0xfa, 0xd0, 0xe0, 0xf9, 0xd0, 0xe0, 0xf8, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0,
-0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0xc2,
-0xaf, 0x30, 0x45, 0x03, 0x12, 0x10, 0x0c, 0x30, 0x58, 0x0a, 0xe5, 0x54, 0x60, 0x04, 0x15, 0x54,
-0x80, 0x02, 0xc2, 0x58, 0x30, 0x59, 0x0a, 0xe5, 0x50, 0x60, 0x04, 0x15, 0x50, 0x80, 0x02, 0xc2,
-0x59, 0xd5, 0x53, 0x07, 0x30, 0x60, 0x04, 0x15, 0x46, 0xd2, 0x04, 0x30, 0x45, 0x03, 0x12, 0x10,
-0x0f, 0xc2, 0x8d, 0xd2, 0xaf, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32,
-0x12, 0x02, 0xd3, 0x30, 0x45, 0x03, 0x12, 0x10, 0x03, 0x30, 0x01, 0x06, 0x20, 0x09, 0x03, 0x12,
-0x10, 0x1c, 0x30, 0x02, 0x06, 0x20, 0x0a, 0x03, 0x12, 0x10, 0x1f, 0x30, 0x03, 0x06, 0x20, 0x0b,
-0x03, 0x12, 0x10, 0x1f, 0x30, 0x04, 0x06, 0x20, 0x0c, 0x03, 0x12, 0x10, 0x22, 0x20, 0x13, 0x09,
-0x20, 0x11, 0x06, 0xe5, 0x2b, 0x45, 0x2c, 0x60, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0xa9, 0x12,
-0x02, 0xec, 0x80, 0xbf, 0xc2, 0x43, 0xd2, 0x45, 0xe4, 0xf5, 0x20, 0xf5, 0x21, 0xf5, 0x53, 0xf5,
-0x46, 0xf5, 0x2b, 0xf5, 0x2c, 0xc2, 0x42, 0xf5, 0x51, 0xf5, 0x52, 0xf5, 0x55, 0x90, 0x04, 0x18,
-0x74, 0x80, 0xf0, 0x90, 0x04, 0x1a, 0x74, 0x08, 0xf0, 0xc2, 0x19, 0xc2, 0x18, 0xc2, 0x1a, 0x22,
-0xc8, 0xef, 0xc8, 0xe6, 0xfa, 0x08, 0xe6, 0x4a, 0x60, 0x0c, 0xc8, 0xef, 0xc8, 0x08, 0xe6, 0x16,
-0x18, 0x70, 0x01, 0x16, 0xc3, 0x22, 0xed, 0x24, 0xff, 0xfd, 0xec, 0x34, 0xff, 0xc8, 0xef, 0xc8,
-0xf6, 0x08, 0xc6, 0xed, 0xc6, 0xd3, 0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12,
-0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83,
-0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0xef, 0xf4, 0x60,
-0x1f, 0xe4, 0xfe, 0x12, 0x03, 0x6a, 0xe0, 0xb4, 0xff, 0x12, 0x12, 0x03, 0x6a, 0xef, 0xf0, 0x74,
-0x1c, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xed, 0xf0, 0x22, 0x0e, 0xbe, 0x04, 0xe3,
-0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x08, 0xc2, 0xaf,
-0x30, 0x45, 0x03, 0x12, 0x10, 0x06, 0xd2, 0xaf, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0,
-0xd0, 0xe0, 0x32, 0xc2, 0xaf, 0x12, 0x00, 0x06, 0x12, 0x02, 0x14, 0x12, 0x03, 0x1c, 0xe4, 0xf5,
-0x22, 0xf5, 0x47, 0x90, 0x04, 0x00, 0x74, 0x80, 0xf0, 0xd2, 0xaf, 0x22, 0x30, 0x45, 0x03, 0x12,
-0x10, 0x15, 0xe5, 0x20, 0x70, 0x03, 0x20, 0x10, 0x03, 0x30, 0x11, 0x03, 0x43, 0x87, 0x01, 0x22,
-0xc0, 0x2a, 0x74, 0x03, 0xc0, 0xe0, 0xc0, 0x82, 0xc0, 0x83, 0x75, 0x2a, 0x0a, 0x22, 0xc0, 0x2a,
-0x74, 0x03, 0xc0, 0xe0, 0xc0, 0x82, 0xc0, 0x83, 0x75, 0x2a, 0x18, 0x22, 0x75, 0x89, 0x02, 0xe4,
-0xf5, 0x8c, 0xf5, 0x8a, 0xf5, 0x88, 0xf5, 0xb8, 0xf5, 0xe8, 0x75, 0x90, 0x18, 0xd2, 0x8c, 0x75,
-0xa8, 0x05, 0x22, 0xce, 0xef, 0xce, 0xee, 0x60, 0x08, 0x7f, 0xff, 0x12, 0x03, 0x80, 0x1e, 0x80,
-0xf5, 0x22, 0xc8, 0xef, 0xc8, 0xe6, 0x60, 0x03, 0x16, 0xc3, 0x22, 0xed, 0x14, 0xf6, 0xd3, 0x22,
-0xc8, 0xef, 0xc8, 0xe6, 0x60, 0x06, 0x16, 0xe6, 0x24, 0xff, 0xb3, 0x22, 0xc3, 0x22, 0x78, 0x7f,
-0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x5f, 0x02, 0x01, 0xd0, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4,
-0x34, 0x70, 0xf5, 0x83, 0x22, 0xef, 0x90, 0x03, 0x7e, 0x93, 0x90, 0x03, 0x00, 0x73, 0x0a, 0x18,
-0xef, 0x60, 0x03, 0x1f, 0x80, 0xfa, 0x22, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0x02, 0x10, 0x28, 0x02, 0x10, 0x3b, 0x02, 0x10, 0x3c, 0x02, 0x12, 0xb8, 0x02,
-0x12, 0xb9, 0x02, 0x13, 0x3e, 0x02, 0x13, 0x3f, 0xc3, 0x22, 0xff, 0xff, 0x02, 0x16, 0x56, 0x02,
-0x17, 0x6b, 0x02, 0x14, 0x2a, 0x02, 0x13, 0x40, 0x30, 0x05, 0x06, 0x20, 0x0d, 0x03, 0x12, 0x00,
-0xd8, 0x30, 0x06, 0x06, 0x20, 0x0e, 0x03, 0x12, 0x18, 0x5e, 0x22, 0x22, 0x90, 0x04, 0x14, 0xe0,
-0x20, 0xe7, 0x03, 0x02, 0x12, 0xb7, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x56, 0x90, 0x04, 0x04, 0xe0,
-0x12, 0x02, 0x67, 0x11, 0x4e, 0x30, 0x11, 0x25, 0x31, 0x10, 0x87, 0x33, 0x10, 0xaa, 0x34, 0x10,
-0xc3, 0x35, 0x11, 0x57, 0x50, 0x11, 0x7b, 0x51, 0x11, 0x84, 0x52, 0x11, 0x84, 0x53, 0x11, 0x84,
-0x54, 0x11, 0xc5, 0x55, 0x11, 0xdc, 0x70, 0x12, 0x07, 0x71, 0x12, 0x34, 0x72, 0x12, 0x5e, 0x80,
-0x12, 0x81, 0x83, 0x00, 0x00, 0x12, 0xb7, 0x75, 0x24, 0x05, 0x75, 0x25, 0xdc, 0x90, 0x70, 0x9f,
-0x74, 0x12, 0xf0, 0xd2, 0x18, 0xd2, 0x61, 0x75, 0x35, 0x0d, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5,
-0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0xb7, 0x02, 0x12, 0xaa, 0xc2, 0x18, 0x90, 0x01, 0x14, 0xe0,
-0x54, 0xfd, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0xb7,
-0x02, 0x12, 0xaa, 0xe5, 0x55, 0x64, 0x02, 0x70, 0x37, 0x90, 0x70, 0x10, 0xe0, 0x60, 0x08, 0x90,
-0x01, 0x0d, 0x74, 0x09, 0xf0, 0x80, 0x25, 0xe5, 0x34, 0x14, 0x60, 0x0a, 0x14, 0x60, 0x0f, 0x14,
-0x60, 0x14, 0x24, 0x03, 0x70, 0x16, 0x90, 0x01, 0x0d, 0x74, 0x08, 0xf0, 0x80, 0x0e, 0x90, 0x01,
-0x0d, 0x74, 0x0b, 0xf0, 0x80, 0x06, 0x90, 0x01, 0x0d, 0x74, 0x1b, 0xf0, 0x7d, 0x01, 0x80, 0x02,
-0x7d, 0x02, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0x90, 0x70, 0x11, 0xe0, 0x24, 0xff, 0x92, 0x1b, 0x90,
-0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02,
-0x12, 0xb7, 0x02, 0x12, 0xaa, 0x20, 0x02, 0x03, 0x30, 0x03, 0x1d, 0x7d, 0x02, 0xaf, 0x56, 0x12,
-0x02, 0x8d, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4,
-0x70, 0x03, 0x02, 0x12, 0xb7, 0x02, 0x12, 0xaa, 0x85, 0x56, 0x41, 0xd2, 0x02, 0x22, 0x90, 0x70,
-0x11, 0xe0, 0x24, 0xff, 0x92, 0x1b, 0x22, 0x90, 0x70, 0x10, 0xe0, 0x54, 0x7f, 0x64, 0x02, 0x60,
-0x03, 0x02, 0x12, 0xb7, 0x90, 0x70, 0x11, 0xe0, 0x64, 0x08, 0x60, 0x08, 0xe0, 0x64, 0x20, 0x60,
-0x03, 0x02, 0x12, 0xb7, 0x75, 0x4e, 0x03, 0x75, 0x4f, 0x20, 0x22, 0x90, 0x70, 0x11, 0xe0, 0x24,
-0xff, 0x92, 0x47, 0x22, 0x90, 0x04, 0x04, 0xe0, 0x25, 0xe0, 0x24, 0x5d, 0xf5, 0x57, 0x90, 0x70,
-0x10, 0xe0, 0xff, 0x74, 0x47, 0x25, 0x57, 0xf8, 0xc6, 0xef, 0xc6, 0x90, 0x70, 0x11, 0xe0, 0xff,
-0x74, 0x48, 0x25, 0x57, 0xf8, 0xc6, 0xef, 0xc6, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0x90,
-0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02,
-0x12, 0xb7, 0x02, 0x12, 0xaa, 0xe5, 0x47, 0xb4, 0x07, 0x08, 0x90, 0x70, 0x11, 0xe0, 0x54, 0x07,
-0xf5, 0x26, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0xd2, 0x04, 0x22, 0x90, 0x70, 0x10, 0xe0,
-0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed, 0xf8, 0xe6, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x02,
-0x8d, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70,
-0x03, 0x02, 0x12, 0xb7, 0x02, 0x12, 0xaa, 0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0,
-0xfd, 0xed, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0x90,
-0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02,
-0x12, 0xb7, 0x80, 0x76, 0xe4, 0xf5, 0x4e, 0xf5, 0x4f, 0x75, 0x26, 0xff, 0xc2, 0x19, 0xc2, 0x18,
-0xc2, 0x1a, 0x75, 0x34, 0xff, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0x90, 0x04, 0x14, 0x74,
-0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x5b, 0x80, 0x4c, 0x90, 0x70,
-0x10, 0xe0, 0x24, 0xff, 0x92, 0x4a, 0xd2, 0x05, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0x90,
-0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x38, 0x80,
-0x29, 0x90, 0x70, 0x10, 0xe0, 0xf5, 0x34, 0xd3, 0x94, 0x00, 0x40, 0x07, 0x90, 0x01, 0x0d, 0xe0,
-0x54, 0xfb, 0xf0, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0,
-0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x0d, 0x90, 0x70, 0x25, 0xe0, 0x44, 0x01,
-0xf0, 0x90, 0x02, 0x2c, 0x74, 0xff, 0xf0, 0x22, 0x22, 0xe5, 0x53, 0x60, 0x03, 0x02, 0x13, 0x3d,
-0xe5, 0x4f, 0x45, 0x4e, 0x60, 0x08, 0xe5, 0x4f, 0x15, 0x4f, 0x70, 0x02, 0x15, 0x4e, 0xa2, 0x19,
-0xe4, 0x33, 0x90, 0x70, 0x90, 0xf0, 0xa2, 0x18, 0xe4, 0x33, 0xa3, 0xf0, 0x30, 0x19, 0x4d, 0x90,
-0x70, 0x98, 0x74, 0x23, 0xf0, 0xa3, 0xe5, 0x25, 0xf0, 0xe5, 0x24, 0xa3, 0xf0, 0x7f, 0x35, 0x7d,
-0x32, 0x12, 0x03, 0x42, 0x50, 0x09, 0x90, 0x10, 0x04, 0xe0, 0x54, 0xf7, 0xf0, 0xd2, 0x06, 0xe5,
-0x35, 0xd3, 0x94, 0x10, 0x40, 0x1e, 0x30, 0x1a, 0x1b, 0xc2, 0x1a, 0xa2, 0x18, 0x92, 0x19, 0x20,
-0x19, 0x12, 0x90, 0x04, 0x09, 0xe0, 0x54, 0xdd, 0xf0, 0x90, 0x10, 0x04, 0xe0, 0x44, 0x08, 0xf0,
-0xc2, 0x61, 0xd2, 0x03, 0xe5, 0x35, 0xb4, 0x0b, 0x14, 0xd2, 0x03, 0x22, 0xe4, 0xf5, 0x35, 0xa2,
-0x18, 0x92, 0x19, 0x30, 0x19, 0x07, 0x90, 0x04, 0x09, 0xe0, 0x44, 0x22, 0xf0, 0x22, 0x22, 0x22,
-0xc2, 0x4b, 0xc2, 0x4c, 0xe5, 0x44, 0x12, 0x02, 0x67, 0x13, 0x62, 0x00, 0x13, 0xf5, 0x04, 0x13,
-0xf1, 0x08, 0x13, 0xcc, 0x10, 0x13, 0x76, 0x20, 0x13, 0x96, 0x60, 0x13, 0xa7, 0xa0, 0x00, 0x00,
-0x13, 0xf7, 0x85, 0x48, 0x43, 0x85, 0x4a, 0x42, 0x85, 0x4c, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x60,
-0x03, 0x02, 0x13, 0xf7, 0x80, 0x1b, 0xe5, 0x48, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4a, 0xc4,
-0x54, 0x0f, 0xf5, 0x42, 0xe5, 0x4c, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70,
-0x66, 0x53, 0x43, 0x0f, 0x80, 0x61, 0x85, 0x49, 0x43, 0x85, 0x4b, 0x42, 0x85, 0x4d, 0x5e, 0xe5,
-0x47, 0x64, 0x06, 0x70, 0x52, 0x80, 0x1b, 0xe5, 0x49, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4b,
-0xc4, 0x54, 0x0f, 0xf5, 0x42, 0xe5, 0x4d, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06,
-0x70, 0x35, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x10, 0xf5, 0x43, 0x80, 0x2b, 0xe5, 0x47, 0xb4, 0x04,
-0x06, 0x53, 0x5e, 0xfb, 0x75, 0x42, 0x09, 0xe5, 0x47, 0xb4, 0x05, 0x06, 0x43, 0x5e, 0x04, 0x75,
-0x42, 0x09, 0xe5, 0x47, 0xb4, 0x06, 0x10, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x30, 0xf5, 0x43, 0x80,
-0x06, 0xd2, 0x4b, 0x80, 0x02, 0xd2, 0x4c, 0xe4, 0xf5, 0x38, 0xe5, 0x42, 0xc4, 0x54, 0xf0, 0xff,
-0xe5, 0x43, 0x54, 0x0f, 0x4f, 0xf5, 0x5f, 0x90, 0x70, 0x44, 0xf0, 0xa3, 0xe5, 0x5e, 0xf0, 0xa3,
-0xe5, 0x4a, 0xf0, 0xa3, 0xe5, 0x48, 0xf0, 0xa3, 0xe5, 0x4c, 0xf0, 0xa3, 0xe5, 0x44, 0xf0, 0xa3,
-0xe5, 0x42, 0xf0, 0xa3, 0xe5, 0x43, 0xf0, 0xd2, 0x60, 0x22, 0xe5, 0x47, 0x60, 0x10, 0x24, 0xc0,
-0x70, 0x03, 0x12, 0x16, 0x36, 0x12, 0x14, 0x3f, 0xc2, 0xaf, 0xc2, 0x04, 0xd2, 0xaf, 0x22, 0xc2,
-0xaf, 0x90, 0x04, 0x14, 0xe0, 0x54, 0x0e, 0x60, 0x04, 0xd2, 0x1c, 0x80, 0x08, 0xe5, 0x4e, 0x45,
-0x4f, 0x24, 0xff, 0x92, 0x1c, 0xd2, 0xaf, 0x90, 0x04, 0x14, 0xe0, 0xa2, 0xe4, 0x92, 0x1d, 0x74,
-0x1e, 0xf0, 0xe5, 0x5f, 0x54, 0x0f, 0xf5, 0x2d, 0xe5, 0x38, 0x70, 0x13, 0x30, 0x1c, 0x05, 0xe5,
-0x5f, 0x20, 0xe5, 0x0b, 0x30, 0x1d, 0x19, 0xe5, 0x5f, 0x54, 0x30, 0xff, 0xbf, 0x30, 0x11, 0xe5,
-0x38, 0x70, 0x05, 0x75, 0x38, 0x0c, 0x80, 0x02, 0x15, 0x38, 0xd2, 0x6c, 0xd2, 0x6d, 0x80, 0x0f,
-0xe5, 0x5f, 0x30, 0xe6, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x04, 0xd2, 0x6c, 0xc2, 0x6d, 0xe5,
-0x47, 0x64, 0x03, 0x70, 0x21, 0x30, 0x4b, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x18, 0xe5, 0x38,
-0x70, 0x03, 0x30, 0x4c, 0x11, 0xc2, 0x4c, 0xe5, 0x38, 0x70, 0x05, 0x75, 0x38, 0x07, 0x80, 0x02,
-0x15, 0x38, 0xd2, 0x6c, 0xd2, 0x6d, 0x90, 0x70, 0x46, 0xe5, 0x2d, 0xf0, 0x20, 0x69, 0x07, 0xe5,
-0x5e, 0x20, 0xe0, 0x02, 0xb2, 0x68, 0x20, 0x6b, 0x07, 0xe5, 0x5e, 0x20, 0xe1, 0x02, 0xb2, 0x6a,
-0x20, 0x6d, 0x07, 0xe5, 0x5e, 0x20, 0xe2, 0x02, 0xb2, 0x6c, 0x90, 0x70, 0x47, 0xe5, 0x2d, 0xf0,
-0x75, 0x2e, 0x40, 0x20, 0x69, 0x04, 0xa2, 0x68, 0x80, 0x15, 0x30, 0x68, 0x06, 0xe5, 0x46, 0xa2,
-0xe3, 0x80, 0x0c, 0xe5, 0x46, 0x54, 0xf0, 0xff, 0xbf, 0xf0, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92,
-0x73, 0x92, 0x72, 0x20, 0x6b, 0x04, 0xa2, 0x6a, 0x80, 0x15, 0x30, 0x6a, 0x06, 0xe5, 0x46, 0xa2,
-0xe3, 0x80, 0x0c, 0xe5, 0x46, 0x54, 0xf0, 0xff, 0xbf, 0xf0, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92,
-0x75, 0x92, 0x74, 0x20, 0x6d, 0x04, 0xa2, 0x6c, 0x80, 0x15, 0x30, 0x6c, 0x06, 0xe5, 0x46, 0xa2,
-0xe3, 0x80, 0x0c, 0xe5, 0x46, 0x54, 0xf0, 0xff, 0xbf, 0xf0, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92,
-0x71, 0x92, 0x70, 0x90, 0x10, 0x2f, 0xe5, 0x2e, 0xf0, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x46, 0x90,
-0x02, 0x29, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x43, 0xc4, 0x54, 0x0f, 0x14, 0x60, 0x14, 0x24, 0xfe,
-0x60, 0x1f, 0x24, 0x03, 0x60, 0x03, 0x02, 0x16, 0x35, 0x90, 0x02, 0x28, 0xe0, 0x30, 0x47, 0x0d,
-0x80, 0x07, 0x90, 0x02, 0x28, 0xe0, 0x20, 0x47, 0x04, 0x54, 0xfe, 0xf0, 0x22, 0x44, 0x01, 0xf0,
-0x22, 0xe5, 0x46, 0x30, 0xe3, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x02, 0x28, 0xe0,
-0x54, 0xfe, 0x4f, 0xf0, 0x22, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x03, 0x02, 0x16, 0x35, 0xf5, 0x27,
-0x90, 0x02, 0x29, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x26, 0x14, 0x60, 0x26, 0x14, 0x60, 0x2e, 0x14,
-0x60, 0x36, 0x24, 0x03, 0x70, 0x5f, 0xe5, 0x46, 0x13, 0x13, 0x13, 0x54, 0x1f, 0x75, 0xf0, 0x03,
-0x84, 0xaf, 0xf0, 0x20, 0x47, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e, 0x00, 0xef, 0x6e, 0x24, 0xff,
-0x80, 0x02, 0xa2, 0x47, 0x92, 0x39, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x80, 0x3f, 0xe5, 0x46, 0x30,
-0xe3, 0x03, 0xd3, 0x80, 0x27, 0xc3, 0x80, 0x24, 0xe5, 0x46, 0x30, 0xe3, 0x0d, 0x54, 0x70, 0xc3,
-0x94, 0x60, 0x50, 0x06, 0x7e, 0x00, 0x7f, 0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x20, 0x47,
-0x04, 0x7d, 0x01, 0x80, 0x02, 0x7d, 0x00, 0xef, 0x6d, 0x4e, 0x24, 0xff, 0x92, 0x38, 0xa2, 0x47,
-0xb3, 0x92, 0x39, 0x80, 0x07, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x92, 0x39, 0x90, 0x02, 0x28, 0xe0,
-0x54, 0xfc, 0x45, 0x27, 0xf0, 0x22, 0xe4, 0x90, 0x02, 0x29, 0xf0, 0x30, 0x47, 0x04, 0xaf, 0x45,
-0x80, 0x04, 0xe5, 0x45, 0xf4, 0xff, 0x90, 0x02, 0x28, 0xef, 0xf0, 0x22, 0x8f, 0x50, 0xd2, 0x59,
-0x22, 0x8f, 0x54, 0xd2, 0x58, 0x22, 0xe4, 0xf5, 0x30, 0xc2, 0xaf, 0xe5, 0x51, 0x14, 0x60, 0x4a,
-0x14, 0x60, 0x6a, 0x24, 0x02, 0x60, 0x03, 0x02, 0x17, 0x4c, 0xd2, 0x59, 0x75, 0x55, 0x01, 0x20,
-0x19, 0x1c, 0x90, 0x02, 0x08, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, 0x20, 0xe1, 0x23, 0x90, 0x04, 0x34,
-0xe0, 0xb4, 0x02, 0x1c, 0xa3, 0xe0, 0xb4, 0x02, 0x17, 0xa3, 0xe0, 0xb4, 0x02, 0x12, 0x7f, 0x20,
-0x12, 0x16, 0x4c, 0x90, 0x10, 0x04, 0xe0, 0x54, 0xf3, 0xf0, 0x75, 0x51, 0x01, 0x02, 0x17, 0x4c,
-0xe5, 0x50, 0x70, 0x06, 0x75, 0x30, 0x03, 0x02, 0x17, 0x4c, 0x90, 0x12, 0x00, 0xe0, 0x54, 0x03,
-0x70, 0x15, 0x7f, 0x20, 0x12, 0x16, 0x4c, 0x20, 0x19, 0x07, 0x90, 0x02, 0x08, 0xe0, 0x54, 0xfb,
-0xf0, 0x75, 0x51, 0x02, 0x02, 0x17, 0x4c, 0xe5, 0x50, 0x70, 0x02, 0x80, 0x7a, 0x20, 0x19, 0x0f,
-0x90, 0x02, 0x08, 0xe0, 0x20, 0xe3, 0x6c, 0x90, 0x04, 0x37, 0xe0, 0x64, 0x22, 0x70, 0x64, 0x90,
-0x12, 0x04, 0x74, 0x0a, 0xf0, 0x30, 0x1b, 0x11, 0x90, 0x13, 0x28, 0xe0, 0x54, 0xf0, 0xf0, 0xa3,
-0xe0, 0x54, 0xf0, 0xf0, 0xa3, 0xe0, 0x54, 0xfa, 0xf0, 0x20, 0x19, 0x07, 0x90, 0x04, 0x01, 0xe0,
-0x44, 0x10, 0xf0, 0xe5, 0x34, 0xf4, 0x90, 0x04, 0x01, 0x60, 0x06, 0xe0, 0x54, 0xfb, 0xf0, 0x80,
-0x04, 0xe0, 0x54, 0xf9, 0xf0, 0x20, 0x19, 0x07, 0x90, 0x12, 0x04, 0xe0, 0x44, 0x04, 0xf0, 0xe5,
-0x34, 0xf4, 0x60, 0x14, 0x90, 0x01, 0x0d, 0xe0, 0xf5, 0x33, 0xe5, 0x34, 0xd3, 0x94, 0x02, 0x40,
-0x07, 0x90, 0x12, 0x04, 0xe0, 0x54, 0xfd, 0xf0, 0x75, 0x30, 0x01, 0x75, 0x55, 0x02, 0xe4, 0xf5,
-0x51, 0x80, 0x09, 0xe5, 0x50, 0x70, 0x05, 0x75, 0x30, 0x03, 0xf5, 0x51, 0xe5, 0x30, 0x60, 0x18,
-0xc2, 0x01, 0xe4, 0xf5, 0x51, 0xc2, 0x59, 0x20, 0x19, 0x0e, 0xad, 0x30, 0xaf, 0x40, 0x12, 0x18,
-0x2a, 0xe5, 0x30, 0xb4, 0x03, 0x02, 0xd2, 0x03, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0x30, 0x01, 0x0e,
-0xe4, 0xf5, 0x51, 0xc2, 0x59, 0xc2, 0x01, 0x7d, 0x02, 0xaf, 0x40, 0x12, 0x18, 0x2a, 0xe5, 0x52,
-0x14, 0x60, 0x55, 0x14, 0x60, 0x2f, 0x24, 0x02, 0x60, 0x03, 0x02, 0x18, 0x27, 0xe5, 0x34, 0xf4,
-0x60, 0x23, 0xe5, 0x34, 0xd3, 0x94, 0x02, 0x40, 0x16, 0x90, 0x12, 0x04, 0xe0, 0x44, 0x02, 0xf0,
-0x90, 0x01, 0x0d, 0xe0, 0x20, 0xe3, 0x03, 0x02, 0x18, 0x27, 0x7f, 0x50, 0x12, 0x16, 0x51, 0x75,
-0x52, 0x02, 0x75, 0x55, 0x03, 0xe5, 0x34, 0xf4, 0x60, 0x0a, 0xe5, 0x54, 0x70, 0x69, 0x90, 0x01,
-0x0d, 0xe5, 0x33, 0xf0, 0x90, 0x12, 0x04, 0xe0, 0x54, 0xfb, 0xf0, 0x7f, 0x20, 0x12, 0x16, 0x51,
-0x75, 0x52, 0x01, 0x75, 0x55, 0x03, 0x80, 0x4f, 0xe5, 0x54, 0x70, 0x4b, 0x90, 0x04, 0x01, 0xe0,
-0x44, 0x0e, 0xf0, 0x20, 0x19, 0x04, 0xe0, 0x54, 0xef, 0xf0, 0x90, 0x13, 0x28, 0xe0, 0x44, 0x0f,
-0xf0, 0xa3, 0xe0, 0x44, 0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x05, 0xf0, 0x90, 0x12, 0x04, 0x74, 0x03,
-0xf0, 0x20, 0x19, 0x07, 0x90, 0x02, 0x08, 0xe0, 0x44, 0x05, 0xf0, 0x90, 0x10, 0x04, 0xe0, 0x44,
-0x0c, 0xf0, 0xe4, 0xf5, 0x52, 0xf5, 0x55, 0x30, 0x02, 0x0b, 0xc2, 0x02, 0x7d, 0x01, 0xaf, 0x41,
-0x12, 0x18, 0x2a, 0x80, 0x02, 0xc2, 0x03, 0xd2, 0xaf, 0x22, 0xef, 0xf4, 0x60, 0x2d, 0xe4, 0xfe,
-0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xe0, 0xb4, 0xff, 0x19, 0x74, 0x14,
-0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xef, 0xf0, 0x74, 0x1c, 0x2e, 0xf5, 0x82, 0xe4,
-0x34, 0x70, 0xf5, 0x83, 0xed, 0xf0, 0x22, 0x0e, 0xbe, 0x04, 0xd5, 0x22, 0x22, 0x22, 0x20, 0x19,
-0x03, 0x02, 0x19, 0x0f, 0x90, 0x70, 0x80, 0xe0, 0x04, 0xf0, 0x90, 0x04, 0x37, 0xe0, 0x30, 0xe5,
-0x03, 0x02, 0x19, 0x0b, 0x90, 0x04, 0x28, 0xe0, 0xf5, 0x31, 0xa3, 0xe0, 0xf5, 0x30, 0xf5, 0x32,
-0xe4, 0xf5, 0x37, 0x90, 0x70, 0x81, 0xe0, 0x04, 0xf0, 0x90, 0x70, 0x82, 0xe0, 0x04, 0xf0, 0xe5,
-0x32, 0x75, 0xf0, 0x80, 0xa4, 0x24, 0x00, 0xff, 0xe5, 0xf0, 0x34, 0x80, 0xfe, 0xe5, 0x30, 0x65,
-0x32, 0x70, 0x05, 0xfc, 0x7d, 0x18, 0x80, 0x04, 0x7c, 0x00, 0x7d, 0x00, 0xef, 0x2d, 0xff, 0xee,
-0x3c, 0xfe, 0x12, 0x19, 0x10, 0x50, 0x25, 0x90, 0x70, 0x83, 0xe0, 0x04, 0xf0, 0x90, 0x01, 0x14,
-0xe0, 0x44, 0x02, 0xf0, 0xe0, 0x30, 0xe1, 0x06, 0x90, 0x70, 0x92, 0x74, 0x45, 0xf0, 0x90, 0x70,
-0x93, 0xe0, 0x04, 0xf0, 0x90, 0x04, 0x01, 0xe0, 0x90, 0x70, 0x94, 0xf0, 0xe5, 0x32, 0x65, 0x31,
-0x60, 0x10, 0xe4, 0x25, 0x32, 0xff, 0xe4, 0x34, 0x80, 0x8f, 0x82, 0xf5, 0x83, 0xe0, 0xf5, 0x32,
-0x80, 0x97, 0x90, 0x04, 0x10, 0x74, 0x01, 0xf0, 0x90, 0x04, 0x28, 0xe5, 0x31, 0xf0, 0xa3, 0xe5,
-0x30, 0xf0, 0x90, 0x04, 0x11, 0x74, 0x01, 0xf0, 0x02, 0x18, 0x6a, 0xc2, 0x06, 0xd2, 0x1a, 0x22,
-0x90, 0x70, 0x84, 0xe5, 0x37, 0xf0, 0xc3, 0x94, 0x06, 0x50, 0x19, 0x8f, 0x82, 0x8e, 0x83, 0xe0,
-0xb4, 0xff, 0x07, 0x05, 0x37, 0xe4, 0xf5, 0x36, 0x80, 0x59, 0xe4, 0xf5, 0x37, 0x8f, 0x82, 0x8e,
-0x83, 0xf0, 0x80, 0x4f, 0xe5, 0x36, 0x75, 0xf0, 0x06, 0x84, 0x74, 0x08, 0x25, 0xf0, 0xf5, 0x82,
-0xe4, 0x34, 0x10, 0xf5, 0x83, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xfc, 0x6d, 0x70, 0x30,
-0x90, 0x70, 0x88, 0xe0, 0x04, 0xf0, 0xa3, 0xe0, 0xfd, 0xd3, 0x95, 0x37, 0x40, 0x02, 0x80, 0x02,
-0xad, 0x37, 0x90, 0x70, 0x89, 0xed, 0xf0, 0x05, 0x37, 0x05, 0x36, 0xe5, 0x36, 0x75, 0xf0, 0x06,
-0x84, 0x74, 0x8a, 0x25, 0xf0, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xec, 0xf0, 0x80, 0x03,
-0xe4, 0xf5, 0x37, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0xef, 0x54, 0x7f, 0x60, 0x0a, 0xe5, 0x37, 0xc3,
-0x94, 0x4e, 0x50, 0x03, 0x02, 0x19, 0x10, 0xe5, 0x37, 0xb4, 0x4e, 0x03, 0xd3, 0x80, 0x01, 0xc3,
-0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x94, 0xeb, } ;
diff --git a/drivers/staging/rt2860/common/firmware_3070.h b/drivers/staging/rt2860/common/firmware_3070.h
deleted file mode 100644
index b710d40bc046..000000000000
--- a/drivers/staging/rt2860/common/firmware_3070.h
+++ /dev/null
@@ -1,517 +0,0 @@
-/* AUTO GEN PLEASE DO NOT MODIFY IT */
-/* AUTO GEN PLEASE DO NOT MODIFY IT */
-
-
-u8 FirmwareImage_3070 [] = {
-0xff, 0xff, 0xff, 0x02, 0x10, 0x28, 0x02, 0x10, 0x32, 0x02, 0x10, 0x78, 0x02, 0x13, 0x1f, 0x02,
-0x13, 0x20, 0x02, 0x13, 0x3f, 0x02, 0x13, 0x44, 0x12, 0x13, 0x40, 0x22, 0x02, 0x17, 0xae, 0x02,
-0x18, 0xd2, 0x02, 0x14, 0x3d, 0x02, 0x13, 0x78, 0x30, 0x05, 0x06, 0x20, 0x0d, 0x03, 0x12, 0x19,
-0x95, 0x22, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe3, 0x1b, 0xe5, 0x4c, 0x30, 0xe0, 0x04, 0x7f, 0x40,
-0x80, 0x02, 0x7f, 0x00, 0x90, 0x10, 0x2f, 0xef, 0xf0, 0x90, 0x01, 0x8c, 0x74, 0x08, 0xf0, 0xe4,
-0x90, 0x01, 0xa7, 0xf0, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe0, 0x1c, 0x90, 0x01, 0x80, 0xe0, 0xb4,
-0x02, 0x15, 0xa3, 0xe0, 0xb4, 0x01, 0x10, 0x90, 0x01, 0x84, 0xe0, 0xb4, 0x81, 0x09, 0x90, 0x01,
-0x8c, 0x74, 0x01, 0xf0, 0x12, 0x0d, 0xc8, 0x22, 0x90, 0x04, 0x14, 0xe0, 0x20, 0xe7, 0x03, 0x02,
-0x13, 0x1e, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x56, 0x90, 0x04, 0x04, 0xe0, 0x12, 0x0a, 0x9d, 0x10,
-0xd9, 0x31, 0x10, 0xbd, 0x36, 0x11, 0x02, 0x50, 0x11, 0x39, 0x51, 0x11, 0x42, 0x52, 0x11, 0x42,
-0x53, 0x11, 0x42, 0x54, 0x11, 0x83, 0x55, 0x11, 0xd2, 0x56, 0x12, 0x25, 0x70, 0x12, 0x50, 0x71,
-0x12, 0x7e, 0x72, 0x12, 0xd5, 0x73, 0x12, 0xf6, 0x80, 0x00, 0x00, 0x13, 0x1e, 0x90, 0x70, 0x11,
-0xe0, 0xf5, 0x3c, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe5, 0x56,
-0xf4, 0x70, 0x03, 0x02, 0x13, 0x1e, 0x02, 0x13, 0x17, 0x20, 0x02, 0x03, 0x30, 0x03, 0x1d, 0x7d,
-0x02, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13,
-0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x13, 0x1e, 0x02, 0x13, 0x17, 0x85, 0x56, 0x41, 0xd2,
-0x02, 0x22, 0x90, 0x70, 0x10, 0xe0, 0x54, 0x7f, 0xff, 0xbf, 0x0a, 0x0d, 0x90, 0x70, 0x11, 0xe0,
-0xb4, 0x08, 0x06, 0x75, 0x4e, 0x01, 0x75, 0x4f, 0x84, 0x90, 0x70, 0x10, 0xe0, 0x54, 0x7f, 0xff,
-0xbf, 0x02, 0x12, 0x90, 0x70, 0x11, 0xe0, 0x64, 0x08, 0x60, 0x04, 0xe0, 0xb4, 0x20, 0x06, 0x75,
-0x4e, 0x03, 0x75, 0x4f, 0x20, 0xe4, 0xf5, 0x27, 0x22, 0x90, 0x70, 0x11, 0xe0, 0x24, 0xff, 0x92,
-0x47, 0x22, 0x90, 0x04, 0x04, 0xe0, 0x25, 0xe0, 0x24, 0x5d, 0xf5, 0x57, 0x90, 0x70, 0x10, 0xe0,
-0xff, 0x74, 0x47, 0x25, 0x57, 0xf8, 0xc6, 0xef, 0xc6, 0x90, 0x70, 0x11, 0xe0, 0xff, 0x74, 0x48,
-0x25, 0x57, 0xf8, 0xc6, 0xef, 0xc6, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14,
-0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x13, 0x1e,
-0x02, 0x13, 0x17, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x1d, 0xe5, 0x47, 0x64, 0x08, 0x60, 0x17, 0xe5,
-0x47, 0x64, 0x09, 0x60, 0x11, 0xe5, 0x47, 0x64, 0x0a, 0x60, 0x0b, 0xe5, 0x47, 0x64, 0x0b, 0x60,
-0x05, 0xe5, 0x47, 0xb4, 0x0c, 0x08, 0x90, 0x70, 0x11, 0xe0, 0x54, 0x0f, 0xf5, 0x3a, 0xe5, 0x47,
-0xb4, 0x09, 0x08, 0xe5, 0x3a, 0xb4, 0x03, 0x03, 0xe4, 0xf5, 0x46, 0xe5, 0x47, 0xb4, 0x0a, 0x08,
-0xe5, 0x3a, 0xb4, 0x01, 0x03, 0xe4, 0xf5, 0x46, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0xd2,
-0x04, 0x22, 0x90, 0x70, 0x11, 0xe0, 0xf4, 0xff, 0x90, 0x70, 0x10, 0xe0, 0x5f, 0xff, 0x90, 0x70,
-0x11, 0xe0, 0x55, 0x27, 0x4f, 0x90, 0x70, 0x18, 0xf0, 0x90, 0x70, 0x11, 0xe0, 0x90, 0x70, 0x19,
-0xf0, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x30, 0x15, 0x03, 0xd2, 0x14, 0x22, 0x90, 0x70,
-0x18, 0xe0, 0xf5, 0x27, 0x90, 0x02, 0x29, 0xe0, 0xff, 0x90, 0x70, 0x19, 0xe0, 0xfe, 0xef, 0x5e,
-0x90, 0x02, 0x29, 0xf0, 0x30, 0x47, 0x04, 0xaf, 0x27, 0x80, 0x04, 0xe5, 0x27, 0xf4, 0xff, 0x90,
-0x02, 0x28, 0xef, 0xf0, 0x22, 0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed,
-0xf8, 0xe6, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0,
-0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x13, 0x1e, 0x02, 0x13, 0x17,
-0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed, 0xf5, 0x82, 0x8e, 0x83, 0xe0,
-0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90,
-0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x13, 0x1e, 0x02, 0x13, 0x17, 0x90, 0x10,
-0x00, 0xe0, 0xf5, 0x57, 0x90, 0x10, 0x02, 0xe0, 0xf5, 0x58, 0xa3, 0xe0, 0xf5, 0x59, 0xe5, 0x58,
-0xb4, 0x70, 0x1e, 0xe5, 0x59, 0xb4, 0x30, 0x19, 0x90, 0x05, 0x08, 0xe0, 0x44, 0x01, 0xf0, 0xfd,
-0x90, 0x05, 0x05, 0xe0, 0x54, 0xfb, 0xf0, 0x44, 0x04, 0xf0, 0xed, 0x54, 0xfe, 0x90, 0x05, 0x08,
-0xf0, 0xe4, 0xf5, 0x4e, 0xf5, 0x4f, 0x75, 0x3a, 0xff, 0x75, 0x3c, 0xff, 0xad, 0x57, 0xaf, 0x56,
-0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56,
-0xf4, 0x60, 0x4b, 0x80, 0x42, 0x90, 0x70, 0x10, 0xe0, 0x24, 0xff, 0x92, 0x93, 0xe4, 0xfd, 0xaf,
-0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5,
-0x56, 0xf4, 0x60, 0x2a, 0x80, 0x21, 0x90, 0x70, 0x10, 0xe0, 0x24, 0xff, 0x92, 0x4a, 0xd2, 0x05,
-0xad, 0x57, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70,
-0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x07, 0x90, 0x70, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x22, 0x22,
-0xe5, 0x53, 0x70, 0x1a, 0x30, 0x60, 0x09, 0xb2, 0x4d, 0x30, 0x4d, 0x04, 0x05, 0x46, 0xc2, 0x04,
-0xe5, 0x4f, 0x45, 0x4e, 0x60, 0x08, 0xe5, 0x4f, 0x15, 0x4f, 0x70, 0x02, 0x15, 0x4e, 0x22, 0x22,
-0xc2, 0x42, 0xd3, 0x22, 0x30, 0x14, 0x30, 0x90, 0x70, 0x19, 0xe0, 0x55, 0x27, 0xff, 0x90, 0x70,
-0x18, 0xe0, 0x4f, 0xf5, 0x27, 0x90, 0x02, 0x29, 0xe0, 0xff, 0x90, 0x70, 0x19, 0xe0, 0xfe, 0xef,
-0x5e, 0x90, 0x02, 0x29, 0xf0, 0x30, 0x47, 0x04, 0xaf, 0x27, 0x80, 0x04, 0xe5, 0x27, 0xf4, 0xff,
-0x90, 0x02, 0x28, 0xef, 0xf0, 0xc2, 0x14, 0x22, 0xc2, 0x4b, 0xc2, 0x4c, 0xe5, 0x44, 0x12, 0x0a,
-0x9d, 0x13, 0x9a, 0x00, 0x14, 0x28, 0x04, 0x14, 0x24, 0x08, 0x14, 0x04, 0x10, 0x13, 0xae, 0x20,
-0x13, 0xce, 0x60, 0x13, 0xdf, 0xa0, 0x00, 0x00, 0x14, 0x2a, 0x85, 0x48, 0x43, 0x85, 0x4a, 0x42,
-0x85, 0x4c, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x60, 0x03, 0x02, 0x14, 0x2a, 0x80, 0x1b, 0xe5, 0x48,
-0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4a, 0xc4, 0x54, 0x0f, 0xf5, 0x42, 0xe5, 0x4c, 0xc4, 0x54,
-0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x61, 0x53, 0x43, 0x0f, 0x80, 0x5c, 0x85, 0x49,
-0x43, 0x85, 0x4b, 0x42, 0x85, 0x4d, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x4d, 0x80, 0x1b, 0xe5,
-0x49, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4b, 0xc4, 0x54, 0x0f, 0xf5, 0x42, 0xe5, 0x4d, 0xc4,
-0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x30, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x10,
-0xf5, 0x43, 0x80, 0x26, 0xe5, 0x47, 0x64, 0x04, 0x60, 0x05, 0xe5, 0x47, 0xb4, 0x05, 0x06, 0x43,
-0x5e, 0x04, 0x75, 0x42, 0x09, 0xe5, 0x47, 0xb4, 0x06, 0x10, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x30,
-0xf5, 0x43, 0x80, 0x06, 0xd2, 0x4b, 0x80, 0x02, 0xd2, 0x4c, 0xe4, 0xf5, 0x25, 0xe5, 0x42, 0xc4,
-0x54, 0xf0, 0xff, 0xe5, 0x43, 0x54, 0x0f, 0x4f, 0xf5, 0x5f, 0xd2, 0x60, 0x22, 0xd2, 0x15, 0xe5,
-0x47, 0x24, 0xf5, 0x60, 0x0b, 0x24, 0xcb, 0x60, 0x07, 0x24, 0x40, 0x70, 0x06, 0xc2, 0x15, 0x22,
-0x12, 0x17, 0x79, 0x12, 0x14, 0x5f, 0xc2, 0x15, 0xc2, 0xaf, 0xc2, 0x04, 0xd2, 0xaf, 0x22, 0xc2,
-0xaf, 0x90, 0x04, 0x14, 0xe0, 0x54, 0x0e, 0x60, 0x04, 0xd2, 0x18, 0x80, 0x08, 0xe5, 0x4e, 0x45,
-0x4f, 0x24, 0xff, 0x92, 0x18, 0xd2, 0xaf, 0x90, 0x04, 0x14, 0xe0, 0xa2, 0xe4, 0x92, 0x19, 0x74,
-0x1e, 0xf0, 0xe5, 0x5f, 0x54, 0x0f, 0xf5, 0x2d, 0xe5, 0x25, 0x70, 0x13, 0x30, 0x18, 0x05, 0xe5,
-0x5f, 0x20, 0xe5, 0x0b, 0x30, 0x19, 0x19, 0xe5, 0x5f, 0x54, 0x30, 0xff, 0xbf, 0x30, 0x11, 0xe5,
-0x25, 0x70, 0x05, 0x75, 0x25, 0x0c, 0x80, 0x02, 0x15, 0x25, 0xd2, 0x6c, 0xd2, 0x6d, 0x80, 0x0f,
-0xe5, 0x5f, 0x30, 0xe6, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x04, 0xd2, 0x6c, 0xc2, 0x6d, 0xe5,
-0x47, 0x64, 0x03, 0x70, 0x21, 0x30, 0x4b, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x18, 0xe5, 0x25,
-0x70, 0x03, 0x30, 0x4c, 0x11, 0xc2, 0x4c, 0xe5, 0x25, 0x70, 0x05, 0x75, 0x25, 0x07, 0x80, 0x02,
-0x15, 0x25, 0xd2, 0x6c, 0xd2, 0x6d, 0xe5, 0x47, 0xb4, 0x09, 0x14, 0xe5, 0x44, 0x20, 0xe3, 0x0b,
-0xe5, 0x3a, 0x64, 0x02, 0x60, 0x05, 0xe5, 0x3a, 0xb4, 0x03, 0x04, 0xc2, 0x6c, 0xd2, 0x6d, 0xe5,
-0x47, 0xb4, 0x0a, 0x13, 0xe5, 0x3a, 0xb4, 0x01, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x08, 0xe5,
-0x3a, 0x70, 0x04, 0xd2, 0x6c, 0xc2, 0x6d, 0x20, 0x69, 0x07, 0xe5, 0x5e, 0x20, 0xe0, 0x02, 0xb2,
-0x68, 0x20, 0x6b, 0x07, 0xe5, 0x5e, 0x20, 0xe1, 0x02, 0xb2, 0x6a, 0x20, 0x6d, 0x07, 0xe5, 0x5e,
-0x20, 0xe2, 0x02, 0xb2, 0x6c, 0x75, 0x2e, 0x40, 0x20, 0x69, 0x04, 0xa2, 0x68, 0x80, 0x26, 0x30,
-0x68, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe2, 0x04, 0x7f, 0x01, 0x80,
-0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e,
-0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x73, 0x92, 0x72, 0x20, 0x6b, 0x04, 0xa2, 0x6a, 0x80, 0x26,
-0x30, 0x6a, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe0, 0x04, 0x7f, 0x01,
-0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, 0x02,
-0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x75, 0x92, 0x74, 0x20, 0x6d, 0x04, 0xa2, 0x6c, 0x80,
-0x26, 0xe5, 0x47, 0x64, 0x0a, 0x70, 0x22, 0x30, 0x6c, 0x06, 0xe5, 0x46, 0xa2, 0xe3, 0x80, 0x17,
-0xe5, 0x3a, 0xb4, 0x01, 0x06, 0xe5, 0x46, 0xa2, 0xe3, 0x80, 0x34, 0xe5, 0x46, 0x20, 0xe4, 0x03,
-0x30, 0xe5, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x80, 0x26, 0x30, 0x6c, 0x06, 0xe5, 0x46, 0xa2, 0xe2,
-0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe1, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54,
-0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92,
-0x71, 0x92, 0x70, 0x90, 0x10, 0x00, 0xe0, 0x90, 0x10, 0x2c, 0xf0, 0x90, 0x10, 0x03, 0xe0, 0xc3,
-0x94, 0x30, 0x40, 0x14, 0xa2, 0x71, 0x92, 0x77, 0xa2, 0x70, 0x92, 0x76, 0xe5, 0x2e, 0x13, 0x13,
-0x54, 0x3f, 0xf5, 0x2e, 0xc2, 0x77, 0xd2, 0x76, 0x90, 0x10, 0x2f, 0xe5, 0x2e, 0xf0, 0xe5, 0x47,
-0x64, 0x06, 0x70, 0x39, 0x90, 0x02, 0x29, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x43, 0xc4, 0x54, 0x0f,
-0x14, 0x60, 0x0c, 0x24, 0xfe, 0x60, 0x0c, 0x24, 0x03, 0x70, 0x13, 0xc2, 0x38, 0x80, 0x0f, 0xd2,
-0x38, 0x80, 0x0b, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x38, 0x30, 0x47,
-0x05, 0xaf, 0x27, 0x02, 0x17, 0x73, 0xe5, 0x27, 0xf4, 0xff, 0x02, 0x17, 0x73, 0xe5, 0x47, 0x64,
-0x07, 0x60, 0x0f, 0xe5, 0x47, 0x64, 0x08, 0x60, 0x09, 0xe5, 0x47, 0x64, 0x09, 0x60, 0x03, 0x02,
-0x16, 0xf2, 0x90, 0x02, 0x29, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x3a, 0x14, 0x60, 0x22, 0x14, 0x60,
-0x25, 0x14, 0x60, 0x2d, 0x24, 0xfc, 0x60, 0x49, 0x24, 0xf9, 0x60, 0x14, 0x24, 0x0e, 0x70, 0x50,
-0xe5, 0x46, 0x13, 0x13, 0x54, 0x3f, 0x75, 0xf0, 0x03, 0x84, 0xe5, 0xf0, 0x24, 0xff, 0x80, 0x3a,
-0xd2, 0x39, 0xc2, 0x38, 0x80, 0x3e, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x1d, 0xc3, 0x80,
-0x1a, 0xe5, 0x46, 0x30, 0xe2, 0x0d, 0x54, 0x38, 0xc3, 0x94, 0x30, 0x50, 0x06, 0x7e, 0x00, 0x7f,
-0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0xee, 0x4f, 0x24, 0xff, 0x92, 0x38, 0xc2, 0x39, 0x80,
-0x13, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x39, 0xc2, 0x38, 0x80, 0x04,
-0xc2, 0x38, 0xc2, 0x39, 0x30, 0x47, 0x04, 0xaf, 0x27, 0x80, 0x04, 0xe5, 0x27, 0xf4, 0xff, 0x02,
-0x17, 0x73, 0xe5, 0x47, 0x64, 0x0c, 0x60, 0x06, 0xe5, 0x47, 0x64, 0x0b, 0x70, 0x7a, 0x90, 0x02,
-0x29, 0xe0, 0x54, 0xfd, 0xf0, 0xe5, 0x3a, 0x14, 0x60, 0x20, 0x14, 0x60, 0x21, 0x14, 0x60, 0x2b,
-0x24, 0xfc, 0x60, 0x45, 0x24, 0xf9, 0x60, 0x12, 0x24, 0x0e, 0x70, 0x4a, 0xe5, 0x46, 0x13, 0x13,
-0x54, 0x3f, 0x75, 0xf0, 0x03, 0x84, 0xe5, 0xf0, 0x80, 0x29, 0xd2, 0x39, 0x80, 0x3a, 0xe5, 0x46,
-0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x39, 0x80, 0x2d, 0xe5, 0x46, 0x30, 0xe2, 0x0d,
-0x54, 0x38, 0xc3, 0x94, 0x30, 0x50, 0x06, 0x7e, 0x00, 0x7f, 0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f,
-0x00, 0xee, 0x4f, 0x24, 0xff, 0x92, 0x39, 0x80, 0x0f, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80,
-0x01, 0xc3, 0x92, 0x39, 0x80, 0x02, 0xc2, 0x39, 0x30, 0x47, 0x04, 0xaf, 0x27, 0x80, 0x04, 0xe5,
-0x27, 0xf4, 0xff, 0x90, 0x02, 0x28, 0xef, 0xf0, 0x22, 0xe5, 0x47, 0xb4, 0x0b, 0x10, 0x90, 0x02,
-0x29, 0xe0, 0x54, 0xeb, 0xf0, 0xe5, 0x27, 0x54, 0xeb, 0x45, 0x45, 0xf5, 0x27, 0x22, 0xe4, 0x90,
-0x02, 0x29, 0xf0, 0x30, 0x47, 0x04, 0xaf, 0x45, 0x80, 0x04, 0xe5, 0x45, 0xf4, 0xff, 0x90, 0x02,
-0x28, 0xef, 0xf0, 0x22, 0x8f, 0x50, 0xd2, 0x59, 0x22, 0x8f, 0x54, 0xd2, 0x58, 0x22, 0xe4, 0xf5,
-0x62, 0xc2, 0xaf, 0xe5, 0x51, 0x14, 0x60, 0x48, 0x14, 0x60, 0x66, 0x24, 0x02, 0x60, 0x03, 0x02,
-0x18, 0xb6, 0xd2, 0x59, 0x75, 0x55, 0x01, 0x90, 0x02, 0xa2, 0xe0, 0x54, 0x7f, 0xf0, 0xa3, 0xe0,
-0x20, 0xe7, 0x23, 0x90, 0x04, 0x34, 0xe0, 0xb4, 0x02, 0x1c, 0xa3, 0xe0, 0xb4, 0x02, 0x17, 0xa3,
-0xe0, 0xb4, 0x02, 0x12, 0x7f, 0x20, 0x12, 0x17, 0xa4, 0x90, 0x10, 0x04, 0xe0, 0x54, 0xf3, 0xf0,
-0x75, 0x51, 0x01, 0x02, 0x18, 0xb6, 0xe5, 0x50, 0x70, 0x06, 0x75, 0x62, 0x03, 0x02, 0x18, 0xb6,
-0x90, 0x12, 0x00, 0xe0, 0x54, 0x03, 0x70, 0x12, 0x7f, 0x20, 0x12, 0x17, 0xa4, 0x90, 0x02, 0xa2,
-0xe0, 0x54, 0xbf, 0xf0, 0x75, 0x51, 0x02, 0x02, 0x18, 0xb6, 0xe5, 0x50, 0x70, 0x03, 0x02, 0x18,
-0xb1, 0x90, 0x02, 0xa3, 0xe0, 0x30, 0xe6, 0x03, 0x02, 0x18, 0xad, 0x90, 0x04, 0x37, 0xe0, 0x64,
-0x22, 0x70, 0x7a, 0x90, 0x01, 0x8a, 0x74, 0x7e, 0xf0, 0x90, 0x01, 0x96, 0xf0, 0x90, 0x12, 0x04,
-0x74, 0x0a, 0xf0, 0xe5, 0x58, 0xb4, 0x72, 0x15, 0xe5, 0x59, 0xb4, 0x35, 0x10, 0xe4, 0x90, 0x05,
-0x00, 0xf0, 0xa3, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0x74, 0x03, 0xf0, 0x7f, 0x01, 0x12,
-0x0d, 0x2a, 0x90, 0x13, 0x28, 0xe0, 0x54, 0xf0, 0xf0, 0xa3, 0xe0, 0x54, 0xf0, 0xf0, 0xe5, 0x59,
-0xb4, 0x35, 0x14, 0xe5, 0x3c, 0xf4, 0x60, 0x06, 0xa3, 0xe0, 0x54, 0xf3, 0x80, 0x14, 0x90, 0x13,
-0x2a, 0xe0, 0x54, 0xfb, 0xf0, 0x80, 0x14, 0xe5, 0x3c, 0xf4, 0x90, 0x13, 0x2a, 0x60, 0x08, 0xe0,
-0x54, 0xf2, 0x45, 0x3c, 0xf0, 0x80, 0x04, 0xe0, 0x54, 0xfa, 0xf0, 0x90, 0x04, 0x01, 0xe0, 0x54,
-0xfd, 0xf0, 0x75, 0x62, 0x01, 0x75, 0x55, 0x02, 0xe4, 0xf5, 0x51, 0x80, 0x09, 0xe5, 0x50, 0x70,
-0x05, 0x75, 0x62, 0x03, 0xf5, 0x51, 0xe5, 0x62, 0x60, 0x15, 0xc2, 0x01, 0xe4, 0xf5, 0x51, 0xc2,
-0x59, 0xad, 0x62, 0xaf, 0x40, 0x12, 0x19, 0x61, 0xe5, 0x62, 0xb4, 0x03, 0x02, 0xd2, 0x03, 0xd2,
-0xaf, 0x22, 0xc2, 0xaf, 0x30, 0x01, 0x12, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xf5, 0x51, 0xc2, 0x59,
-0xc2, 0x01, 0x7d, 0x02, 0xaf, 0x40, 0x12, 0x19, 0x61, 0xe5, 0x52, 0x14, 0x60, 0x09, 0x04, 0x70,
-0x6d, 0x75, 0x52, 0x01, 0x75, 0x55, 0x03, 0x90, 0x04, 0x01, 0xe0, 0x44, 0x0e, 0xf0, 0x90, 0x13,
-0x28, 0xe0, 0x44, 0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x05, 0xf0, 0x90,
-0x12, 0x04, 0x74, 0x03, 0xf0, 0xe5, 0x58, 0xb4, 0x72, 0x16, 0xe5, 0x59, 0xb4, 0x35, 0x11, 0x90,
-0x05, 0x00, 0x74, 0xe2, 0xf0, 0xa3, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0x74, 0x03, 0xf0,
-0x7f, 0x01, 0x12, 0x0d, 0x2a, 0x90, 0x02, 0xa2, 0xe0, 0x44, 0xc0, 0xf0, 0x90, 0x10, 0x04, 0xe0,
-0x44, 0x0c, 0xf0, 0xe4, 0xf5, 0x52, 0xf5, 0x55, 0x30, 0x02, 0x09, 0xc2, 0x02, 0x7d, 0x01, 0xaf,
-0x41, 0x12, 0x19, 0x61, 0x30, 0x03, 0x02, 0xc2, 0x03, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xd2, 0xaf,
-0x22, 0xef, 0xf4, 0x60, 0x2d, 0xe4, 0xfe, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5,
-0x83, 0xe0, 0xb4, 0xff, 0x19, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xef,
-0xf0, 0x74, 0x1c, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xed, 0xf0, 0x22, 0x0e, 0xbe,
-0x04, 0xd5, 0x22, 0x22, 0x22, 0x90, 0x70, 0x2a, 0xe0, 0x30, 0xe1, 0x4d, 0xc2, 0xaf, 0x90, 0x70,
-0x28, 0xe0, 0x90, 0x10, 0x1c, 0xf0, 0x90, 0x70, 0x29, 0xe0, 0x90, 0x10, 0x1d, 0xf0, 0x90, 0x70,
-0x2a, 0xe0, 0x90, 0x10, 0x1e, 0xf0, 0x90, 0x10, 0x1c, 0xe0, 0xf5, 0x62, 0x90, 0x10, 0x1e, 0xe0,
-0x20, 0xe1, 0xf3, 0x90, 0x10, 0x1c, 0xe0, 0x90, 0x70, 0x28, 0xf0, 0x90, 0x10, 0x1d, 0xe0, 0x90,
-0x70, 0x29, 0xf0, 0x90, 0x10, 0x1e, 0xe0, 0x90, 0x70, 0x2a, 0xf0, 0x30, 0x4a, 0x07, 0x90, 0x70,
-0x24, 0xe0, 0x44, 0x01, 0xf0, 0xc2, 0x05, 0xd2, 0xaf, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x7b, 0xc4,
-0xff, 0xff, 0xff, 0x02, 0x10, 0x28, 0x02, 0x10, 0x32, 0x02, 0x10, 0x78, 0x02, 0x13, 0x1f, 0x02,
-0x13, 0x20, 0x02, 0x13, 0x3f, 0x02, 0x13, 0x44, 0x12, 0x13, 0x40, 0x22, 0x02, 0x17, 0xae, 0x02,
-0x18, 0xd2, 0x02, 0x14, 0x3d, 0x02, 0x13, 0x78, 0x30, 0x05, 0x06, 0x20, 0x0d, 0x03, 0x12, 0x19,
-0x95, 0x22, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe3, 0x1b, 0xe5, 0x4c, 0x30, 0xe0, 0x04, 0x7f, 0x40,
-0x80, 0x02, 0x7f, 0x00, 0x90, 0x10, 0x2f, 0xef, 0xf0, 0x90, 0x01, 0x8c, 0x74, 0x08, 0xf0, 0xe4,
-0x90, 0x01, 0xa7, 0xf0, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe0, 0x1c, 0x90, 0x01, 0x80, 0xe0, 0xb4,
-0x02, 0x15, 0xa3, 0xe0, 0xb4, 0x01, 0x10, 0x90, 0x01, 0x84, 0xe0, 0xb4, 0x81, 0x09, 0x90, 0x01,
-0x8c, 0x74, 0x01, 0xf0, 0x12, 0x0d, 0xdd, 0x22, 0x90, 0x04, 0x14, 0xe0, 0x20, 0xe7, 0x03, 0x02,
-0x13, 0x1e, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x56, 0x90, 0x04, 0x04, 0xe0, 0x12, 0x0a, 0xb6, 0x10,
-0xd9, 0x31, 0x10, 0xbd, 0x36, 0x11, 0x02, 0x50, 0x11, 0x39, 0x51, 0x11, 0x42, 0x52, 0x11, 0x42,
-0x53, 0x11, 0x42, 0x54, 0x11, 0x83, 0x55, 0x11, 0xd2, 0x56, 0x12, 0x25, 0x70, 0x12, 0x50, 0x71,
-0x12, 0x7e, 0x72, 0x12, 0xd5, 0x73, 0x12, 0xf6, 0x80, 0x00, 0x00, 0x13, 0x1e, 0x90, 0x70, 0x11,
-0xe0, 0xf5, 0x3c, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe5, 0x56,
-0xf4, 0x70, 0x03, 0x02, 0x13, 0x1e, 0x02, 0x13, 0x17, 0x20, 0x02, 0x03, 0x30, 0x03, 0x1d, 0x7d,
-0x02, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13,
-0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x13, 0x1e, 0x02, 0x13, 0x17, 0x85, 0x56, 0x41, 0xd2,
-0x02, 0x22, 0x90, 0x70, 0x10, 0xe0, 0x54, 0x7f, 0xff, 0xbf, 0x0a, 0x0d, 0x90, 0x70, 0x11, 0xe0,
-0xb4, 0x08, 0x06, 0x75, 0x4e, 0x01, 0x75, 0x4f, 0x84, 0x90, 0x70, 0x10, 0xe0, 0x54, 0x7f, 0xff,
-0xbf, 0x02, 0x12, 0x90, 0x70, 0x11, 0xe0, 0x64, 0x08, 0x60, 0x04, 0xe0, 0xb4, 0x20, 0x06, 0x75,
-0x4e, 0x03, 0x75, 0x4f, 0x20, 0xe4, 0xf5, 0x27, 0x22, 0x90, 0x70, 0x11, 0xe0, 0x24, 0xff, 0x92,
-0x47, 0x22, 0x90, 0x04, 0x04, 0xe0, 0x25, 0xe0, 0x24, 0x5d, 0xf5, 0x57, 0x90, 0x70, 0x10, 0xe0,
-0xff, 0x74, 0x47, 0x25, 0x57, 0xf8, 0xc6, 0xef, 0xc6, 0x90, 0x70, 0x11, 0xe0, 0xff, 0x74, 0x48,
-0x25, 0x57, 0xf8, 0xc6, 0xef, 0xc6, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14,
-0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x13, 0x1e,
-0x02, 0x13, 0x17, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x1d, 0xe5, 0x47, 0x64, 0x08, 0x60, 0x17, 0xe5,
-0x47, 0x64, 0x09, 0x60, 0x11, 0xe5, 0x47, 0x64, 0x0a, 0x60, 0x0b, 0xe5, 0x47, 0x64, 0x0b, 0x60,
-0x05, 0xe5, 0x47, 0xb4, 0x0c, 0x08, 0x90, 0x70, 0x11, 0xe0, 0x54, 0x0f, 0xf5, 0x3a, 0xe5, 0x47,
-0xb4, 0x09, 0x08, 0xe5, 0x3a, 0xb4, 0x03, 0x03, 0xe4, 0xf5, 0x46, 0xe5, 0x47, 0xb4, 0x0a, 0x08,
-0xe5, 0x3a, 0xb4, 0x01, 0x03, 0xe4, 0xf5, 0x46, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0xd2,
-0x04, 0x22, 0x90, 0x70, 0x11, 0xe0, 0xf4, 0xff, 0x90, 0x70, 0x10, 0xe0, 0x5f, 0xff, 0x90, 0x70,
-0x11, 0xe0, 0x55, 0x27, 0x4f, 0x90, 0x70, 0x18, 0xf0, 0x90, 0x70, 0x11, 0xe0, 0x90, 0x70, 0x19,
-0xf0, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x30, 0x15, 0x03, 0xd2, 0x14, 0x22, 0x90, 0x70,
-0x18, 0xe0, 0xf5, 0x27, 0x90, 0x02, 0x29, 0xe0, 0xff, 0x90, 0x70, 0x19, 0xe0, 0xfe, 0xef, 0x5e,
-0x90, 0x02, 0x29, 0xf0, 0x30, 0x47, 0x04, 0xaf, 0x27, 0x80, 0x04, 0xe5, 0x27, 0xf4, 0xff, 0x90,
-0x02, 0x28, 0xef, 0xf0, 0x22, 0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed,
-0xf8, 0xe6, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0,
-0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x13, 0x1e, 0x02, 0x13, 0x17,
-0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed, 0xf5, 0x82, 0x8e, 0x83, 0xe0,
-0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90,
-0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x13, 0x1e, 0x02, 0x13, 0x17, 0x90, 0x10,
-0x00, 0xe0, 0xf5, 0x57, 0x90, 0x10, 0x02, 0xe0, 0xf5, 0x58, 0xa3, 0xe0, 0xf5, 0x59, 0xe5, 0x58,
-0xb4, 0x70, 0x1e, 0xe5, 0x59, 0xb4, 0x30, 0x19, 0x90, 0x05, 0x08, 0xe0, 0x44, 0x01, 0xf0, 0xfd,
-0x90, 0x05, 0x05, 0xe0, 0x54, 0xfb, 0xf0, 0x44, 0x04, 0xf0, 0xed, 0x54, 0xfe, 0x90, 0x05, 0x08,
-0xf0, 0xe4, 0xf5, 0x4e, 0xf5, 0x4f, 0x75, 0x3a, 0xff, 0x75, 0x3c, 0xff, 0xad, 0x57, 0xaf, 0x56,
-0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56,
-0xf4, 0x60, 0x4b, 0x80, 0x42, 0x90, 0x70, 0x10, 0xe0, 0x24, 0xff, 0x92, 0x93, 0xe4, 0xfd, 0xaf,
-0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5,
-0x56, 0xf4, 0x60, 0x2a, 0x80, 0x21, 0x90, 0x70, 0x10, 0xe0, 0x24, 0xff, 0x92, 0x4a, 0xd2, 0x05,
-0xad, 0x57, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70,
-0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x07, 0x90, 0x70, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x22, 0x22,
-0xe5, 0x53, 0x70, 0x1a, 0x30, 0x60, 0x09, 0xb2, 0x4d, 0x30, 0x4d, 0x04, 0x05, 0x46, 0xc2, 0x04,
-0xe5, 0x4f, 0x45, 0x4e, 0x60, 0x08, 0xe5, 0x4f, 0x15, 0x4f, 0x70, 0x02, 0x15, 0x4e, 0x22, 0x22,
-0xc2, 0x42, 0xd3, 0x22, 0x30, 0x14, 0x30, 0x90, 0x70, 0x19, 0xe0, 0x55, 0x27, 0xff, 0x90, 0x70,
-0x18, 0xe0, 0x4f, 0xf5, 0x27, 0x90, 0x02, 0x29, 0xe0, 0xff, 0x90, 0x70, 0x19, 0xe0, 0xfe, 0xef,
-0x5e, 0x90, 0x02, 0x29, 0xf0, 0x30, 0x47, 0x04, 0xaf, 0x27, 0x80, 0x04, 0xe5, 0x27, 0xf4, 0xff,
-0x90, 0x02, 0x28, 0xef, 0xf0, 0xc2, 0x14, 0x22, 0xc2, 0x4b, 0xc2, 0x4c, 0xe5, 0x44, 0x12, 0x0a,
-0xb6, 0x13, 0x9a, 0x00, 0x14, 0x28, 0x04, 0x14, 0x24, 0x08, 0x14, 0x04, 0x10, 0x13, 0xae, 0x20,
-0x13, 0xce, 0x60, 0x13, 0xdf, 0xa0, 0x00, 0x00, 0x14, 0x2a, 0x85, 0x48, 0x43, 0x85, 0x4a, 0x42,
-0x85, 0x4c, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x60, 0x03, 0x02, 0x14, 0x2a, 0x80, 0x1b, 0xe5, 0x48,
-0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4a, 0xc4, 0x54, 0x0f, 0xf5, 0x42, 0xe5, 0x4c, 0xc4, 0x54,
-0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x61, 0x53, 0x43, 0x0f, 0x80, 0x5c, 0x85, 0x49,
-0x43, 0x85, 0x4b, 0x42, 0x85, 0x4d, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x4d, 0x80, 0x1b, 0xe5,
-0x49, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4b, 0xc4, 0x54, 0x0f, 0xf5, 0x42, 0xe5, 0x4d, 0xc4,
-0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x30, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x10,
-0xf5, 0x43, 0x80, 0x26, 0xe5, 0x47, 0x64, 0x04, 0x60, 0x05, 0xe5, 0x47, 0xb4, 0x05, 0x06, 0x43,
-0x5e, 0x04, 0x75, 0x42, 0x09, 0xe5, 0x47, 0xb4, 0x06, 0x10, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x30,
-0xf5, 0x43, 0x80, 0x06, 0xd2, 0x4b, 0x80, 0x02, 0xd2, 0x4c, 0xe4, 0xf5, 0x25, 0xe5, 0x42, 0xc4,
-0x54, 0xf0, 0xff, 0xe5, 0x43, 0x54, 0x0f, 0x4f, 0xf5, 0x5f, 0xd2, 0x60, 0x22, 0xd2, 0x15, 0xe5,
-0x47, 0x24, 0xf5, 0x60, 0x0b, 0x24, 0xcb, 0x60, 0x07, 0x24, 0x40, 0x70, 0x06, 0xc2, 0x15, 0x22,
-0x12, 0x17, 0x79, 0x12, 0x14, 0x5f, 0xc2, 0x15, 0xc2, 0xaf, 0xc2, 0x04, 0xd2, 0xaf, 0x22, 0xc2,
-0xaf, 0x90, 0x04, 0x14, 0xe0, 0x54, 0x0e, 0x60, 0x04, 0xd2, 0x18, 0x80, 0x08, 0xe5, 0x4e, 0x45,
-0x4f, 0x24, 0xff, 0x92, 0x18, 0xd2, 0xaf, 0x90, 0x04, 0x14, 0xe0, 0xa2, 0xe4, 0x92, 0x19, 0x74,
-0x1e, 0xf0, 0xe5, 0x5f, 0x54, 0x0f, 0xf5, 0x2d, 0xe5, 0x25, 0x70, 0x13, 0x30, 0x18, 0x05, 0xe5,
-0x5f, 0x20, 0xe5, 0x0b, 0x30, 0x19, 0x19, 0xe5, 0x5f, 0x54, 0x30, 0xff, 0xbf, 0x30, 0x11, 0xe5,
-0x25, 0x70, 0x05, 0x75, 0x25, 0x0c, 0x80, 0x02, 0x15, 0x25, 0xd2, 0x6c, 0xd2, 0x6d, 0x80, 0x0f,
-0xe5, 0x5f, 0x30, 0xe6, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x04, 0xd2, 0x6c, 0xc2, 0x6d, 0xe5,
-0x47, 0x64, 0x03, 0x70, 0x21, 0x30, 0x4b, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x18, 0xe5, 0x25,
-0x70, 0x03, 0x30, 0x4c, 0x11, 0xc2, 0x4c, 0xe5, 0x25, 0x70, 0x05, 0x75, 0x25, 0x07, 0x80, 0x02,
-0x15, 0x25, 0xd2, 0x6c, 0xd2, 0x6d, 0xe5, 0x47, 0xb4, 0x09, 0x14, 0xe5, 0x44, 0x20, 0xe3, 0x0b,
-0xe5, 0x3a, 0x64, 0x02, 0x60, 0x05, 0xe5, 0x3a, 0xb4, 0x03, 0x04, 0xc2, 0x6c, 0xd2, 0x6d, 0xe5,
-0x47, 0xb4, 0x0a, 0x13, 0xe5, 0x3a, 0xb4, 0x01, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x08, 0xe5,
-0x3a, 0x70, 0x04, 0xd2, 0x6c, 0xc2, 0x6d, 0x20, 0x69, 0x07, 0xe5, 0x5e, 0x20, 0xe0, 0x02, 0xb2,
-0x68, 0x20, 0x6b, 0x07, 0xe5, 0x5e, 0x20, 0xe1, 0x02, 0xb2, 0x6a, 0x20, 0x6d, 0x07, 0xe5, 0x5e,
-0x20, 0xe2, 0x02, 0xb2, 0x6c, 0x75, 0x2e, 0x40, 0x20, 0x69, 0x04, 0xa2, 0x68, 0x80, 0x26, 0x30,
-0x68, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe2, 0x04, 0x7f, 0x01, 0x80,
-0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e,
-0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x73, 0x92, 0x72, 0x20, 0x6b, 0x04, 0xa2, 0x6a, 0x80, 0x26,
-0x30, 0x6a, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe0, 0x04, 0x7f, 0x01,
-0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, 0x02,
-0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x75, 0x92, 0x74, 0x20, 0x6d, 0x04, 0xa2, 0x6c, 0x80,
-0x26, 0xe5, 0x47, 0x64, 0x0a, 0x70, 0x22, 0x30, 0x6c, 0x06, 0xe5, 0x46, 0xa2, 0xe3, 0x80, 0x17,
-0xe5, 0x3a, 0xb4, 0x01, 0x06, 0xe5, 0x46, 0xa2, 0xe3, 0x80, 0x34, 0xe5, 0x46, 0x20, 0xe4, 0x03,
-0x30, 0xe5, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x80, 0x26, 0x30, 0x6c, 0x06, 0xe5, 0x46, 0xa2, 0xe2,
-0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe1, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54,
-0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92,
-0x71, 0x92, 0x70, 0x90, 0x10, 0x00, 0xe0, 0x90, 0x10, 0x2c, 0xf0, 0x90, 0x10, 0x03, 0xe0, 0xc3,
-0x94, 0x30, 0x40, 0x14, 0xa2, 0x71, 0x92, 0x77, 0xa2, 0x70, 0x92, 0x76, 0xe5, 0x2e, 0x13, 0x13,
-0x54, 0x3f, 0xf5, 0x2e, 0xc2, 0x77, 0xd2, 0x76, 0x90, 0x10, 0x2f, 0xe5, 0x2e, 0xf0, 0xe5, 0x47,
-0x64, 0x06, 0x70, 0x39, 0x90, 0x02, 0x29, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x43, 0xc4, 0x54, 0x0f,
-0x14, 0x60, 0x0c, 0x24, 0xfe, 0x60, 0x0c, 0x24, 0x03, 0x70, 0x13, 0xc2, 0x38, 0x80, 0x0f, 0xd2,
-0x38, 0x80, 0x0b, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x38, 0x30, 0x47,
-0x05, 0xaf, 0x27, 0x02, 0x17, 0x73, 0xe5, 0x27, 0xf4, 0xff, 0x02, 0x17, 0x73, 0xe5, 0x47, 0x64,
-0x07, 0x60, 0x0f, 0xe5, 0x47, 0x64, 0x08, 0x60, 0x09, 0xe5, 0x47, 0x64, 0x09, 0x60, 0x03, 0x02,
-0x16, 0xf2, 0x90, 0x02, 0x29, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x3a, 0x14, 0x60, 0x22, 0x14, 0x60,
-0x25, 0x14, 0x60, 0x2d, 0x24, 0xfc, 0x60, 0x49, 0x24, 0xf9, 0x60, 0x14, 0x24, 0x0e, 0x70, 0x50,
-0xe5, 0x46, 0x13, 0x13, 0x54, 0x3f, 0x75, 0xf0, 0x03, 0x84, 0xe5, 0xf0, 0x24, 0xff, 0x80, 0x3a,
-0xd2, 0x39, 0xc2, 0x38, 0x80, 0x3e, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x1d, 0xc3, 0x80,
-0x1a, 0xe5, 0x46, 0x30, 0xe2, 0x0d, 0x54, 0x38, 0xc3, 0x94, 0x30, 0x50, 0x06, 0x7e, 0x00, 0x7f,
-0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0xee, 0x4f, 0x24, 0xff, 0x92, 0x38, 0xc2, 0x39, 0x80,
-0x13, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x39, 0xc2, 0x38, 0x80, 0x04,
-0xc2, 0x38, 0xc2, 0x39, 0x30, 0x47, 0x04, 0xaf, 0x27, 0x80, 0x04, 0xe5, 0x27, 0xf4, 0xff, 0x02,
-0x17, 0x73, 0xe5, 0x47, 0x64, 0x0c, 0x60, 0x06, 0xe5, 0x47, 0x64, 0x0b, 0x70, 0x7a, 0x90, 0x02,
-0x29, 0xe0, 0x54, 0xfd, 0xf0, 0xe5, 0x3a, 0x14, 0x60, 0x20, 0x14, 0x60, 0x21, 0x14, 0x60, 0x2b,
-0x24, 0xfc, 0x60, 0x45, 0x24, 0xf9, 0x60, 0x12, 0x24, 0x0e, 0x70, 0x4a, 0xe5, 0x46, 0x13, 0x13,
-0x54, 0x3f, 0x75, 0xf0, 0x03, 0x84, 0xe5, 0xf0, 0x80, 0x29, 0xd2, 0x39, 0x80, 0x3a, 0xe5, 0x46,
-0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x39, 0x80, 0x2d, 0xe5, 0x46, 0x30, 0xe2, 0x0d,
-0x54, 0x38, 0xc3, 0x94, 0x30, 0x50, 0x06, 0x7e, 0x00, 0x7f, 0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f,
-0x00, 0xee, 0x4f, 0x24, 0xff, 0x92, 0x39, 0x80, 0x0f, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80,
-0x01, 0xc3, 0x92, 0x39, 0x80, 0x02, 0xc2, 0x39, 0x30, 0x47, 0x04, 0xaf, 0x27, 0x80, 0x04, 0xe5,
-0x27, 0xf4, 0xff, 0x90, 0x02, 0x28, 0xef, 0xf0, 0x22, 0xe5, 0x47, 0xb4, 0x0b, 0x10, 0x90, 0x02,
-0x29, 0xe0, 0x54, 0xeb, 0xf0, 0xe5, 0x27, 0x54, 0xeb, 0x45, 0x45, 0xf5, 0x27, 0x22, 0xe4, 0x90,
-0x02, 0x29, 0xf0, 0x30, 0x47, 0x04, 0xaf, 0x45, 0x80, 0x04, 0xe5, 0x45, 0xf4, 0xff, 0x90, 0x02,
-0x28, 0xef, 0xf0, 0x22, 0x8f, 0x50, 0xd2, 0x59, 0x22, 0x8f, 0x54, 0xd2, 0x58, 0x22, 0xe4, 0xf5,
-0x62, 0xc2, 0xaf, 0xe5, 0x51, 0x14, 0x60, 0x48, 0x14, 0x60, 0x66, 0x24, 0x02, 0x60, 0x03, 0x02,
-0x18, 0xb6, 0xd2, 0x59, 0x75, 0x55, 0x01, 0x90, 0x02, 0xa2, 0xe0, 0x54, 0x7f, 0xf0, 0xa3, 0xe0,
-0x20, 0xe7, 0x23, 0x90, 0x04, 0x34, 0xe0, 0xb4, 0x02, 0x1c, 0xa3, 0xe0, 0xb4, 0x02, 0x17, 0xa3,
-0xe0, 0xb4, 0x02, 0x12, 0x7f, 0x20, 0x12, 0x17, 0xa4, 0x90, 0x10, 0x04, 0xe0, 0x54, 0xf3, 0xf0,
-0x75, 0x51, 0x01, 0x02, 0x18, 0xb6, 0xe5, 0x50, 0x70, 0x06, 0x75, 0x62, 0x03, 0x02, 0x18, 0xb6,
-0x90, 0x12, 0x00, 0xe0, 0x54, 0x03, 0x70, 0x12, 0x7f, 0x20, 0x12, 0x17, 0xa4, 0x90, 0x02, 0xa2,
-0xe0, 0x54, 0xbf, 0xf0, 0x75, 0x51, 0x02, 0x02, 0x18, 0xb6, 0xe5, 0x50, 0x70, 0x03, 0x02, 0x18,
-0xb1, 0x90, 0x02, 0xa3, 0xe0, 0x30, 0xe6, 0x03, 0x02, 0x18, 0xad, 0x90, 0x04, 0x37, 0xe0, 0x64,
-0x22, 0x70, 0x7a, 0x90, 0x01, 0x8a, 0x74, 0x7e, 0xf0, 0x90, 0x01, 0x96, 0xf0, 0x90, 0x12, 0x04,
-0x74, 0x0a, 0xf0, 0xe5, 0x58, 0xb4, 0x72, 0x15, 0xe5, 0x59, 0xb4, 0x35, 0x10, 0xe4, 0x90, 0x05,
-0x00, 0xf0, 0xa3, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0x74, 0x03, 0xf0, 0x7f, 0x01, 0x12,
-0x0d, 0x48, 0x90, 0x13, 0x28, 0xe0, 0x54, 0xf0, 0xf0, 0xa3, 0xe0, 0x54, 0xf0, 0xf0, 0xe5, 0x59,
-0xb4, 0x35, 0x14, 0xe5, 0x3c, 0xf4, 0x60, 0x06, 0xa3, 0xe0, 0x54, 0xf3, 0x80, 0x14, 0x90, 0x13,
-0x2a, 0xe0, 0x54, 0xfb, 0xf0, 0x80, 0x14, 0xe5, 0x3c, 0xf4, 0x90, 0x13, 0x2a, 0x60, 0x08, 0xe0,
-0x54, 0xf2, 0x45, 0x3c, 0xf0, 0x80, 0x04, 0xe0, 0x54, 0xfa, 0xf0, 0x90, 0x04, 0x01, 0xe0, 0x54,
-0xfd, 0xf0, 0x75, 0x62, 0x01, 0x75, 0x55, 0x02, 0xe4, 0xf5, 0x51, 0x80, 0x09, 0xe5, 0x50, 0x70,
-0x05, 0x75, 0x62, 0x03, 0xf5, 0x51, 0xe5, 0x62, 0x60, 0x15, 0xc2, 0x01, 0xe4, 0xf5, 0x51, 0xc2,
-0x59, 0xad, 0x62, 0xaf, 0x40, 0x12, 0x19, 0x61, 0xe5, 0x62, 0xb4, 0x03, 0x02, 0xd2, 0x03, 0xd2,
-0xaf, 0x22, 0xc2, 0xaf, 0x30, 0x01, 0x12, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xf5, 0x51, 0xc2, 0x59,
-0xc2, 0x01, 0x7d, 0x02, 0xaf, 0x40, 0x12, 0x19, 0x61, 0xe5, 0x52, 0x14, 0x60, 0x09, 0x04, 0x70,
-0x6d, 0x75, 0x52, 0x01, 0x75, 0x55, 0x03, 0x90, 0x04, 0x01, 0xe0, 0x44, 0x0e, 0xf0, 0x90, 0x13,
-0x28, 0xe0, 0x44, 0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x05, 0xf0, 0x90,
-0x12, 0x04, 0x74, 0x03, 0xf0, 0xe5, 0x58, 0xb4, 0x72, 0x16, 0xe5, 0x59, 0xb4, 0x35, 0x11, 0x90,
-0x05, 0x00, 0x74, 0xe2, 0xf0, 0xa3, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0x74, 0x03, 0xf0,
-0x7f, 0x01, 0x12, 0x0d, 0x48, 0x90, 0x02, 0xa2, 0xe0, 0x44, 0xc0, 0xf0, 0x90, 0x10, 0x04, 0xe0,
-0x44, 0x0c, 0xf0, 0xe4, 0xf5, 0x52, 0xf5, 0x55, 0x30, 0x02, 0x09, 0xc2, 0x02, 0x7d, 0x01, 0xaf,
-0x41, 0x12, 0x19, 0x61, 0x30, 0x03, 0x02, 0xc2, 0x03, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xd2, 0xaf,
-0x22, 0xef, 0xf4, 0x60, 0x2d, 0xe4, 0xfe, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5,
-0x83, 0xe0, 0xb4, 0xff, 0x19, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xef,
-0xf0, 0x74, 0x1c, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xed, 0xf0, 0x22, 0x0e, 0xbe,
-0x04, 0xd5, 0x22, 0x22, 0x22, 0x90, 0x70, 0x2a, 0xe0, 0x30, 0xe1, 0x4d, 0xc2, 0xaf, 0x90, 0x70,
-0x28, 0xe0, 0x90, 0x10, 0x1c, 0xf0, 0x90, 0x70, 0x29, 0xe0, 0x90, 0x10, 0x1d, 0xf0, 0x90, 0x70,
-0x2a, 0xe0, 0x90, 0x10, 0x1e, 0xf0, 0x90, 0x10, 0x1c, 0xe0, 0xf5, 0x62, 0x90, 0x10, 0x1e, 0xe0,
-0x20, 0xe1, 0xf3, 0x90, 0x10, 0x1c, 0xe0, 0x90, 0x70, 0x28, 0xf0, 0x90, 0x10, 0x1d, 0xe0, 0x90,
-0x70, 0x29, 0xf0, 0x90, 0x10, 0x1e, 0xe0, 0x90, 0x70, 0x2a, 0xf0, 0x30, 0x4a, 0x07, 0x90, 0x70,
-0x24, 0xe0, 0x44, 0x01, 0xf0, 0xc2, 0x05, 0xd2, 0xaf, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x65, 0xd3, } ;
diff --git a/drivers/staging/rt2860/common/rtmp_mcu.c b/drivers/staging/rt2860/common/rtmp_mcu.c
index 9f03901433bb..844d4b987b78 100644
--- a/drivers/staging/rt2860/common/rtmp_mcu.c
+++ b/drivers/staging/rt2860/common/rtmp_mcu.c
@@ -37,35 +37,38 @@
#include "../rt_config.h"
-#if defined(RT2860) || defined(RT3090)
-#include "firmware.h"
-#include "../../rt3090/firmware.h"
-#endif
-#ifdef RT2870
-#include "../../rt3070/firmware.h"
-#include "firmware_3070.h"
-#endif
-
-#include <linux/bitrev.h>
+#include <linux/crc-ccitt.h>
+#include <linux/firmware.h>
#ifdef RTMP_MAC_USB
-/* */
-/* RT2870 Firmware Spec only used 1 oct for version expression */
-/* */
-#define FIRMWARE_MINOR_VERSION 7
-#endif /* RTMP_MAC_USB // */
-/* New 8k byte firmware size for RT3071/RT3072 */
-#define FIRMWAREIMAGE_MAX_LENGTH 0x2000
-#define FIRMWAREIMAGE_LENGTH (sizeof (FirmwareImage) / sizeof(u8))
-#define FIRMWARE_MAJOR_VERSION 0
+#define FIRMWAREIMAGE_LENGTH 0x1000
-#define FIRMWAREIMAGEV1_LENGTH 0x1000
-#define FIRMWAREIMAGEV2_LENGTH 0x1000
+#define FIRMWARE_2870_MIN_VERSION 12
+#define FIRMWARE_2870_FILENAME "rt2870.bin"
+MODULE_FIRMWARE(FIRMWARE_2870_FILENAME);
-#ifdef RTMP_MAC_PCI
-#define FIRMWARE_MINOR_VERSION 2
-#endif /* RTMP_MAC_PCI // */
+#define FIRMWARE_3070_MIN_VERSION 17
+#define FIRMWARE_3070_FILENAME "rt3070.bin"
+MODULE_FIRMWARE(FIRMWARE_3070_FILENAME);
+
+#define FIRMWARE_3071_MIN_VERSION 17
+#define FIRMWARE_3071_FILENAME "rt3071.bin" /* for RT3071/RT3072 */
+MODULE_FIRMWARE(FIRMWARE_3071_FILENAME);
+
+#else /* RTMP_MAC_PCI */
+
+#define FIRMWAREIMAGE_LENGTH 0x2000
+
+#define FIRMWARE_2860_MIN_VERSION 11
+#define FIRMWARE_2860_FILENAME "rt2860.bin"
+MODULE_FIRMWARE(FIRMWARE_2860_FILENAME);
+
+#define FIRMWARE_3090_MIN_VERSION 19
+#define FIRMWARE_3090_FILENAME "rt3090.bin" /* for RT3090/RT3390 */
+MODULE_FIRMWARE(FIRMWARE_3090_FILENAME);
+
+#endif
/*
========================================================================
@@ -90,6 +93,78 @@ int RtmpAsicEraseFirmware(struct rt_rtmp_adapter *pAd)
return 0;
}
+static const struct firmware *rtmp_get_firmware(struct rt_rtmp_adapter *adapter)
+{
+ const char *name;
+ const struct firmware *fw = NULL;
+ u8 min_version;
+ struct device *dev;
+ int err;
+
+ if (adapter->firmware)
+ return adapter->firmware;
+
+#ifdef RTMP_MAC_USB
+ if (IS_RT3071(adapter)) {
+ name = FIRMWARE_3071_FILENAME;
+ min_version = FIRMWARE_3071_MIN_VERSION;
+ } else if (IS_RT3070(adapter)) {
+ name = FIRMWARE_3070_FILENAME;
+ min_version = FIRMWARE_3070_MIN_VERSION;
+ } else {
+ name = FIRMWARE_2870_FILENAME;
+ min_version = FIRMWARE_2870_MIN_VERSION;
+ }
+ dev = &((struct os_cookie *)adapter->OS_Cookie)->pUsb_Dev->dev;
+#else /* RTMP_MAC_PCI */
+ if (IS_RT3090(adapter) || IS_RT3390(adapter)) {
+ name = FIRMWARE_3090_FILENAME;
+ min_version = FIRMWARE_3090_MIN_VERSION;
+ } else {
+ name = FIRMWARE_2860_FILENAME;
+ min_version = FIRMWARE_2860_MIN_VERSION;
+ }
+ dev = &((struct os_cookie *)adapter->OS_Cookie)->pci_dev->dev;
+#endif
+
+ err = request_firmware(&fw, name, dev);
+ if (err) {
+ dev_err(dev, "firmware file %s request failed (%d)\n",
+ name, err);
+ return NULL;
+ }
+
+ if (fw->size < FIRMWAREIMAGE_LENGTH) {
+ dev_err(dev, "firmware file %s size is invalid\n", name);
+ goto invalid;
+ }
+
+ /* is it new enough? */
+ adapter->FirmwareVersion = fw->data[FIRMWAREIMAGE_LENGTH - 3];
+ if (adapter->FirmwareVersion < min_version) {
+ dev_err(dev,
+ "firmware file %s is too old;"
+ " driver requires v%d or later\n",
+ name, min_version);
+ goto invalid;
+ }
+
+ /* is the internal CRC correct? */
+ if (crc_ccitt(0xffff, fw->data, FIRMWAREIMAGE_LENGTH - 2) !=
+ (fw->data[FIRMWAREIMAGE_LENGTH - 2] |
+ (fw->data[FIRMWAREIMAGE_LENGTH - 1] << 8))) {
+ dev_err(dev, "firmware file %s failed internal CRC\n", name);
+ goto invalid;
+ }
+
+ adapter->firmware = fw;
+ return fw;
+
+invalid:
+ release_firmware(fw);
+ return NULL;
+}
+
/*
========================================================================
@@ -109,46 +184,16 @@ int RtmpAsicEraseFirmware(struct rt_rtmp_adapter *pAd)
*/
int RtmpAsicLoadFirmware(struct rt_rtmp_adapter *pAd)
{
-
+ const struct firmware *fw;
int Status = NDIS_STATUS_SUCCESS;
- u8 *pFirmwareImage = NULL;
- unsigned long FileLength, Index;
+ unsigned long Index;
u32 MacReg = 0;
-#ifdef RTMP_MAC_USB
- u32 Version = (pAd->MACVersion >> 16);
-#endif
- /* New 8k byte firmware size for RT3071/RT3072 */
- {
-#ifdef RTMP_MAC_PCI
- if (IS_RT3090(pAd) || IS_RT3390(pAd)) {
- pFirmwareImage = FirmwareImage_3090;
- FileLength = FIRMWAREIMAGE_MAX_LENGTH;
- } else {
- pFirmwareImage = FirmwareImage_2860;
- FileLength = FIRMWAREIMAGE_MAX_LENGTH;
- }
-#endif /* RTMP_MAC_PCI // */
-#ifdef RTMP_MAC_USB
- /* the firmware image consists of two parts */
- if ((Version != 0x2860) && (Version != 0x2872) && (Version != 0x3070)) { /* use the second part */
- /*printk("KH:Use New Version,part2\n"); */
- pFirmwareImage =
- (u8 *)&
- FirmwareImage_3070[FIRMWAREIMAGEV1_LENGTH];
- FileLength = FIRMWAREIMAGEV2_LENGTH;
- } else {
- /*printk("KH:Use New Version,part1\n"); */
- if (Version == 0x3070)
- pFirmwareImage = FirmwareImage_3070;
- else
- pFirmwareImage = FirmwareImage_2870;
- FileLength = FIRMWAREIMAGEV1_LENGTH;
- }
-#endif /* RTMP_MAC_USB // */
- }
+ fw = rtmp_get_firmware(pAd);
+ if (!fw)
+ return NDIS_STATUS_FAILURE;
- RTMP_WRITE_FIRMWARE(pAd, pFirmwareImage, FileLength);
+ RTMP_WRITE_FIRMWARE(pAd, fw->data, FIRMWAREIMAGE_LENGTH);
/* check if MCU is ready */
Index = 0;
@@ -221,7 +266,7 @@ int RtmpAsicSendCommandToMcu(struct rt_rtmp_adapter *pAd,
("AsicSendCommanToMcu::Mail box is busy\n"));
} while (i++ < 100);
- if (i >= 100) {
+ if (i > 100) {
DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n"));
return FALSE;
}
diff --git a/drivers/staging/rt2860/rt_linux.c b/drivers/staging/rt2860/rt_linux.c
index 9357fb26cc2a..b5c78aecf5e3 100644
--- a/drivers/staging/rt2860/rt_linux.c
+++ b/drivers/staging/rt2860/rt_linux.c
@@ -25,6 +25,7 @@
*************************************************************************
*/
+#include <linux/firmware.h>
#include <linux/sched.h>
#include "rt_config.h"
@@ -260,6 +261,8 @@ void RTMPFreeAdapter(struct rt_rtmp_adapter *pAd)
NdisFreeSpinLock(&pAd->irq_lock);
+ release_firmware(pAd->firmware);
+
vfree(pAd); /* pci_free_consistent(os_cookie->pci_dev,sizeof(struct rt_rtmp_adapter),pAd,os_cookie->pAd_pa); */
if (os_cookie)
kfree(os_cookie);
@@ -462,9 +465,9 @@ void *duplicate_pkt(struct rt_rtmp_adapter *pAd,
if ((skb =
__dev_alloc_skb(HdrLen + DataSize + 2, MEM_ALLOC_FLAG)) != NULL) {
skb_reserve(skb, 2);
- NdisMoveMemory(skb->tail, pHeader802_3, HdrLen);
+ NdisMoveMemory(skb_tail_pointer(skb), pHeader802_3, HdrLen);
skb_put(skb, HdrLen);
- NdisMoveMemory(skb->tail, pData, DataSize);
+ NdisMoveMemory(skb_tail_pointer(skb), pData, DataSize);
skb_put(skb, DataSize);
skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID);
pPacket = OSPKT_TO_RTPKT(skb);
@@ -515,7 +518,7 @@ void *ClonePacket(struct rt_rtmp_adapter *pAd,
pClonedPkt->dev = pRxPkt->dev;
pClonedPkt->data = pData;
pClonedPkt->len = DataSize;
- pClonedPkt->tail = pClonedPkt->data + pClonedPkt->len;
+ skb_set_tail_pointer(pClonedPkt, DataSize)
ASSERT(DataSize < 1530);
}
return pClonedPkt;
@@ -535,7 +538,7 @@ void update_os_packet_info(struct rt_rtmp_adapter *pAd,
pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID);
pOSPkt->data = pRxBlk->pData;
pOSPkt->len = pRxBlk->DataSize;
- pOSPkt->tail = pOSPkt->data + pOSPkt->len;
+ skb_set_tail_pointer(pOSPkt, pOSPkt->len);
}
void wlan_802_11_to_802_3_packet(struct rt_rtmp_adapter *pAd,
@@ -553,7 +556,7 @@ void wlan_802_11_to_802_3_packet(struct rt_rtmp_adapter *pAd,
pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID);
pOSPkt->data = pRxBlk->pData;
pOSPkt->len = pRxBlk->DataSize;
- pOSPkt->tail = pOSPkt->data + pOSPkt->len;
+ skb_set_tail_pointer(pOSPkt, pOSPkt->len);
/* */
/* copy 802.3 header */
diff --git a/drivers/staging/rt2860/rt_linux.h b/drivers/staging/rt2860/rt_linux.h
index f85508d9d5a9..a7c540f8e3e3 100644
--- a/drivers/staging/rt2860/rt_linux.h
+++ b/drivers/staging/rt2860/rt_linux.h
@@ -658,9 +658,9 @@ void linux_pci_unmap_single(void *handle, dma_addr_t dma_addr, size_t size,
(RTPKT_TO_OSPKT(_pkt)->len) = (_len)
#define GET_OS_PKT_DATATAIL(_pkt) \
- (RTPKT_TO_OSPKT(_pkt)->tail)
+ (skb_tail_pointer(RTPKT_TO_OSPKT(_pkt))
#define SET_OS_PKT_DATATAIL(_pkt, _start, _len) \
- ((RTPKT_TO_OSPKT(_pkt))->tail) = (u8 *)((_start) + (_len))
+ (skb_set_tail_pointer(RTPKT_TO_OSPKT(_pkt), _len))
#define GET_OS_PKT_HEAD(_pkt) \
(RTPKT_TO_OSPKT(_pkt)->head)
diff --git a/drivers/staging/rt2860/rt_main_dev.c b/drivers/staging/rt2860/rt_main_dev.c
index c3d92802d0c9..fbddb00cfedd 100644
--- a/drivers/staging/rt2860/rt_main_dev.c
+++ b/drivers/staging/rt2860/rt_main_dev.c
@@ -216,7 +216,7 @@ int rt28xx_close(struct net_device *dev)
u32 i = 0;
#ifdef RTMP_MAC_USB
- DECLARE_WAIT_QUEUE_HEAD(unlink_wakeup);
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup);
DECLARE_WAITQUEUE(wait, current);
#endif /* RTMP_MAC_USB // */
diff --git a/drivers/staging/rt2860/rtmp.h b/drivers/staging/rt2860/rtmp.h
index c50abf4b8068..4401a55bda67 100644
--- a/drivers/staging/rt2860/rtmp.h
+++ b/drivers/staging/rt2860/rtmp.h
@@ -1719,6 +1719,7 @@ struct rt_rtmp_adapter {
void *OS_Cookie; /* save specific structure relative to OS */
struct net_device *net_dev;
unsigned long VirtualIfCnt;
+ const struct firmware *firmware;
struct rt_rtmp_chip_op chipOps;
u16 ThisTbttNumToNextWakeUp;
@@ -4043,10 +4044,10 @@ int RTUSBMultiRead(struct rt_rtmp_adapter *pAd,
u16 Offset, u8 *pData, u16 length);
int RTUSBMultiWrite(struct rt_rtmp_adapter *pAd,
- u16 Offset, u8 *pData, u16 length);
+ u16 Offset, const u8 *pData, u16 length);
int RTUSBMultiWrite_OneByte(struct rt_rtmp_adapter *pAd,
- u16 Offset, u8 *pData);
+ u16 Offset, const u8 *pData);
int RTUSBReadBBPRegister(struct rt_rtmp_adapter *pAd,
u8 Id, u8 *pValue);
@@ -4112,7 +4113,7 @@ int RTUSBSingleWrite(struct rt_rtmp_adapter *pAd,
u16 Offset, u16 Value);
int RTUSBFirmwareWrite(struct rt_rtmp_adapter *pAd,
- u8 *pFwImage, unsigned long FwLen);
+ const u8 *pFwImage, unsigned long FwLen);
int RTUSBVenderReset(struct rt_rtmp_adapter *pAd);
diff --git a/drivers/staging/rt2860/sta/connect.c b/drivers/staging/rt2860/sta/connect.c
index 17e59ba3d807..55732b10062d 100644
--- a/drivers/staging/rt2860/sta/connect.c
+++ b/drivers/staging/rt2860/sta/connect.c
@@ -62,8 +62,8 @@ u8 CipherSuiteWpaNoneAes[] = {
u8 CipherSuiteWpaNoneAesLen =
(sizeof(CipherSuiteWpaNoneAes) / sizeof(u8));
-/* The following MACRO is called after 1. starting an new IBSS, 2. succesfully JOIN an IBSS, */
-/* or 3. succesfully ASSOCIATE to a BSS, 4. successfully RE_ASSOCIATE to a BSS */
+/* The following MACRO is called after 1. starting an new IBSS, 2. successfully JOIN an IBSS, */
+/* or 3. successfully ASSOCIATE to a BSS, 4. successfully RE_ASSOCIATE to a BSS */
/* All settings successfuly negotiated furing MLME state machines become final settings */
/* and are copied to pAd->StaActive */
#define COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \
diff --git a/drivers/staging/rt2860/sta_ioctl.c b/drivers/staging/rt2860/sta_ioctl.c
index d8fbe6cc6941..de4b6277baee 100644
--- a/drivers/staging/rt2860/sta_ioctl.c
+++ b/drivers/staging/rt2860/sta_ioctl.c
@@ -975,10 +975,7 @@ int rt_ioctl_giwscan(struct net_device *dev,
/*================================ */
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWFREQ;
- if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter))
- iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel;
- else
- iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel;
+ iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel;
iwe.u.freq.e = 0;
iwe.u.freq.i = 0;
diff --git a/drivers/staging/rt2860/usb_main_dev.c b/drivers/staging/rt2860/usb_main_dev.c
index 925a236e1044..1873a79bb033 100644
--- a/drivers/staging/rt2860/usb_main_dev.c
+++ b/drivers/staging/rt2860/usb_main_dev.c
@@ -216,10 +216,6 @@ static int rt2870_suspend(struct usb_interface *intf, pm_message_t state);
static int rt2870_resume(struct usb_interface *intf);
#endif /* CONFIG_PM // */
-static int rtusb_probe(struct usb_interface *intf,
- const struct usb_device_id *id);
-static void rtusb_disconnect(struct usb_interface *intf);
-
static BOOLEAN USBDevConfigInit(IN struct usb_device *dev,
IN struct usb_interface *intf,
struct rt_rtmp_adapter *pAd)
@@ -296,7 +292,7 @@ static BOOLEAN USBDevConfigInit(IN struct usb_device *dev,
}
-static int rtusb_probe(struct usb_interface *intf,
+static int __devinit rtusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct rt_rtmp_adapter *pAd;
diff --git a/drivers/staging/rt2870/Kconfig b/drivers/staging/rt2870/Kconfig
index fd3ba3a3b127..6ea172b433e9 100644
--- a/drivers/staging/rt2870/Kconfig
+++ b/drivers/staging/rt2870/Kconfig
@@ -3,5 +3,7 @@ config RT2870
depends on USB && X86 && WLAN
select WIRELESS_EXT
select WEXT_PRIV
+ select CRC_CCITT
+ select FW_LOADER
---help---
This is an experimental driver for the Ralink xx70 wireless chips.
diff --git a/drivers/staging/rt2870/common/rtusb_io.c b/drivers/staging/rt2870/common/rtusb_io.c
index 34443f2243f1..cf0d2f5dbc6c 100644
--- a/drivers/staging/rt2870/common/rtusb_io.c
+++ b/drivers/staging/rt2870/common/rtusb_io.c
@@ -84,7 +84,7 @@ static int RTUSBFirmwareRun(struct rt_rtmp_adapter *pAd)
========================================================================
*/
int RTUSBFirmwareWrite(struct rt_rtmp_adapter *pAd,
- u8 *pFwImage, unsigned long FwLen)
+ const u8 *pFwImage, unsigned long FwLen)
{
u32 MacReg;
int Status;
@@ -167,7 +167,7 @@ int RTUSBMultiRead(struct rt_rtmp_adapter *pAd,
========================================================================
*/
int RTUSBMultiWrite_OneByte(struct rt_rtmp_adapter *pAd,
- u16 Offset, u8 *pData)
+ u16 Offset, const u8 *pData)
{
int Status;
@@ -175,18 +175,18 @@ int RTUSBMultiWrite_OneByte(struct rt_rtmp_adapter *pAd,
Status = RTUSB_VendorRequest(pAd,
USBD_TRANSFER_DIRECTION_OUT,
DEVICE_VENDOR_REQUEST_OUT,
- 0x6, 0, Offset, pData, 1);
+ 0x6, 0, Offset, (u8 *)pData, 1);
return Status;
}
int RTUSBMultiWrite(struct rt_rtmp_adapter *pAd,
- u16 Offset, u8 *pData, u16 length)
+ u16 Offset, const u8 *pData, u16 length)
{
int Status;
u16 index = 0, Value;
- u8 *pSrc = pData;
+ const u8 *pSrc = pData;
u16 resude = 0;
resude = length % 2;
diff --git a/drivers/staging/rt3070/firmware.h b/drivers/staging/rt3070/firmware.h
deleted file mode 100644
index 5cf9cbcf4ab6..000000000000
--- a/drivers/staging/rt3070/firmware.h
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- Copyright (c) 2007, Ralink Technology Corporation
- All rights reserved.
-
- Redistribution. Redistribution and use in binary form, without
- modification, are permitted provided that the following conditions are
- met:
-
- * Redistributions must reproduce the above copyright notice and the
- following disclaimer in the documentation and/or other materials
- provided with the distribution.
- * Neither the name of Ralink Technology Corporation nor the names of its
- suppliers may be used to endorse or promote products derived from this
- software without specific prior written permission.
- * No reverse engineering, decompilation, or disassembly of this software
- is permitted.
-
- Limited patent license. Ralink Technology Corporation grants a world-wide,
- royalty-free, non-exclusive license under patents it now or hereafter
- owns or controls to make, have made, use, import, offer to sell and
- sell ("Utilize") this software, but solely to the extent that any
- such patent is necessary to Utilize the software alone, or in
- combination with an operating system licensed under an approved Open
- Source license as listed by the Open Source Initiative at
- http://opensource.org/licenses. The patent license shall not apply to
- any other combinations which include this software. No hardware per
- se is licensed hereunder.
-
- DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
- BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- DAMAGE.
-*/
-/* AUTO GEN PLEASE DO NOT MODIFY IT */
-/* AUTO GEN PLEASE DO NOT MODIFY IT */
-
-
-u8 FirmwareImage_2870 [] = {
-0xff, 0xff, 0xff, 0x02, 0x10, 0x28, 0x02, 0x10, 0x32, 0x02, 0x10, 0x78, 0x02, 0x12, 0x67, 0x02,
-0x12, 0x68, 0x02, 0x12, 0x87, 0x02, 0x12, 0x8c, 0x12, 0x12, 0x88, 0x22, 0x02, 0x16, 0x49, 0x02,
-0x17, 0x1f, 0x02, 0x13, 0x77, 0x02, 0x12, 0x8d, 0x30, 0x05, 0x06, 0x20, 0x0d, 0x03, 0x12, 0x17,
-0xc1, 0x22, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe3, 0x1b, 0xe5, 0x4c, 0x30, 0xe0, 0x04, 0x7f, 0x40,
-0x80, 0x02, 0x7f, 0x00, 0x90, 0x10, 0x2f, 0xef, 0xf0, 0x90, 0x01, 0x8c, 0x74, 0x08, 0xf0, 0xe4,
-0x90, 0x01, 0xa7, 0xf0, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe0, 0x1c, 0x90, 0x01, 0x80, 0xe0, 0xb4,
-0x02, 0x15, 0xa3, 0xe0, 0xb4, 0x01, 0x10, 0x90, 0x01, 0x84, 0xe0, 0xb4, 0x81, 0x09, 0x90, 0x01,
-0x8c, 0x74, 0x01, 0xf0, 0x12, 0x0d, 0xc8, 0x22, 0x90, 0x04, 0x14, 0xe0, 0x20, 0xe7, 0x03, 0x02,
-0x12, 0x66, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x56, 0x90, 0x04, 0x04, 0xe0, 0x12, 0x0a, 0x9d, 0x10,
-0xb7, 0x31, 0x10, 0xe0, 0x50, 0x11, 0x04, 0x51, 0x11, 0x0d, 0x52, 0x11, 0x0d, 0x53, 0x11, 0x0d,
-0x54, 0x11, 0x4e, 0x55, 0x11, 0x7e, 0x70, 0x11, 0xa9, 0x71, 0x11, 0xd7, 0x72, 0x12, 0x1d, 0x73,
-0x12, 0x3e, 0x80, 0x00, 0x00, 0x12, 0x66, 0x20, 0x02, 0x03, 0x30, 0x03, 0x1d, 0x7d, 0x02, 0xaf,
-0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5,
-0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0x85, 0x56, 0x41, 0xd2, 0x02, 0x22,
-0x90, 0x70, 0x10, 0xe0, 0x54, 0x7f, 0x64, 0x02, 0x60, 0x03, 0x02, 0x12, 0x66, 0x90, 0x70, 0x11,
-0xe0, 0x64, 0x08, 0x60, 0x08, 0xe0, 0x64, 0x20, 0x60, 0x03, 0x02, 0x12, 0x66, 0x75, 0x4e, 0x03,
-0x75, 0x4f, 0x20, 0x22, 0x90, 0x70, 0x11, 0xe0, 0x24, 0xff, 0x92, 0x47, 0x22, 0x90, 0x04, 0x04,
-0xe0, 0x25, 0xe0, 0x24, 0x5d, 0xf5, 0x57, 0x90, 0x70, 0x10, 0xe0, 0xff, 0x74, 0x47, 0x25, 0x57,
-0xf8, 0xc6, 0xef, 0xc6, 0x90, 0x70, 0x11, 0xe0, 0xff, 0x74, 0x48, 0x25, 0x57, 0xf8, 0xc6, 0xef,
-0xc6, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90,
-0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0xe5, 0x47,
-0x64, 0x07, 0x60, 0x0b, 0xe5, 0x47, 0x64, 0x08, 0x60, 0x05, 0xe5, 0x47, 0xb4, 0x09, 0x08, 0x90,
-0x70, 0x11, 0xe0, 0x54, 0x0f, 0xf5, 0x3a, 0xe5, 0x47, 0xb4, 0x09, 0x08, 0xe5, 0x3a, 0xb4, 0x03,
-0x03, 0xe4, 0xf5, 0x46, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0xd2, 0x04, 0x22, 0x90, 0x70,
-0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed, 0xf8, 0xe6, 0xf5, 0x57, 0xfd, 0xaf, 0x56,
-0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56,
-0xf4, 0x70, 0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70,
-0x11, 0xe0, 0xfd, 0xed, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x0b,
-0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70,
-0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0x90, 0x10, 0x02, 0xe0, 0xb4, 0x70, 0x1e, 0xa3, 0xe0,
-0xb4, 0x30, 0x19, 0x90, 0x05, 0x08, 0xe0, 0x44, 0x01, 0xf0, 0xfd, 0x90, 0x05, 0x05, 0xe0, 0x54,
-0xfb, 0xf0, 0x44, 0x04, 0xf0, 0xed, 0x54, 0xfe, 0x90, 0x05, 0x08, 0xf0, 0xe4, 0xf5, 0x4e, 0xf5,
-0x4f, 0x75, 0x3a, 0xff, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80,
-0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x4b, 0x80, 0x42, 0x90, 0x70, 0x10,
-0xe0, 0x24, 0xff, 0x92, 0x93, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74,
-0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x2a, 0x80, 0x21, 0x90, 0x70,
-0x10, 0xe0, 0x24, 0xff, 0x92, 0x4a, 0xd2, 0x05, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90,
-0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x07, 0x90,
-0x70, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x22, 0x22, 0xe5, 0x53, 0x70, 0x1a, 0x30, 0x60, 0x09, 0xb2,
-0x4d, 0x30, 0x4d, 0x04, 0x05, 0x46, 0xc2, 0x04, 0xe5, 0x4f, 0x45, 0x4e, 0x60, 0x08, 0xe5, 0x4f,
-0x15, 0x4f, 0x70, 0x02, 0x15, 0x4e, 0x22, 0x22, 0xc2, 0x42, 0xd3, 0x22, 0x22, 0xc2, 0x4b, 0xc2,
-0x4c, 0xe5, 0x44, 0x12, 0x0a, 0x9d, 0x12, 0xaf, 0x00, 0x13, 0x42, 0x04, 0x13, 0x3e, 0x08, 0x13,
-0x19, 0x10, 0x12, 0xc3, 0x20, 0x12, 0xe3, 0x60, 0x12, 0xf4, 0xa0, 0x00, 0x00, 0x13, 0x44, 0x85,
-0x48, 0x43, 0x85, 0x4a, 0x42, 0x85, 0x4c, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x60, 0x03, 0x02, 0x13,
-0x44, 0x80, 0x1b, 0xe5, 0x48, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4a, 0xc4, 0x54, 0x0f, 0xf5,
-0x42, 0xe5, 0x4c, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x66, 0x53, 0x43,
-0x0f, 0x80, 0x61, 0x85, 0x49, 0x43, 0x85, 0x4b, 0x42, 0x85, 0x4d, 0x5e, 0xe5, 0x47, 0x64, 0x06,
-0x70, 0x52, 0x80, 0x1b, 0xe5, 0x49, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4b, 0xc4, 0x54, 0x0f,
-0xf5, 0x42, 0xe5, 0x4d, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x35, 0xe5,
-0x43, 0x54, 0x0f, 0x44, 0x10, 0xf5, 0x43, 0x80, 0x2b, 0xe5, 0x47, 0xb4, 0x04, 0x06, 0x53, 0x5e,
-0xfb, 0x75, 0x42, 0x09, 0xe5, 0x47, 0xb4, 0x05, 0x06, 0x43, 0x5e, 0x04, 0x75, 0x42, 0x09, 0xe5,
-0x47, 0xb4, 0x06, 0x10, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x30, 0xf5, 0x43, 0x80, 0x06, 0xd2, 0x4b,
-0x80, 0x02, 0xd2, 0x4c, 0xe4, 0xf5, 0x25, 0xe5, 0x42, 0xc4, 0x54, 0xf0, 0xff, 0xe5, 0x43, 0x54,
-0x0f, 0x4f, 0xf5, 0x5f, 0x90, 0x70, 0x44, 0xf0, 0xa3, 0xe5, 0x5e, 0xf0, 0xa3, 0xe5, 0x4a, 0xf0,
-0xa3, 0xe5, 0x48, 0xf0, 0xa3, 0xe5, 0x4c, 0xf0, 0xa3, 0xe5, 0x44, 0xf0, 0xa3, 0xe5, 0x42, 0xf0,
-0xa3, 0xe5, 0x43, 0xf0, 0xd2, 0x60, 0x22, 0xe5, 0x47, 0x60, 0x10, 0x24, 0xc0, 0x70, 0x03, 0x12,
-0x16, 0x29, 0x12, 0x13, 0x8c, 0xc2, 0xaf, 0xc2, 0x04, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0x90, 0x04,
-0x14, 0xe0, 0x54, 0x0e, 0x60, 0x04, 0xd2, 0x18, 0x80, 0x08, 0xe5, 0x4e, 0x45, 0x4f, 0x24, 0xff,
-0x92, 0x18, 0xd2, 0xaf, 0x90, 0x04, 0x14, 0xe0, 0xa2, 0xe4, 0x92, 0x19, 0x74, 0x1e, 0xf0, 0xe5,
-0x5f, 0x54, 0x0f, 0xf5, 0x2d, 0xe5, 0x25, 0x70, 0x13, 0x30, 0x18, 0x05, 0xe5, 0x5f, 0x20, 0xe5,
-0x0b, 0x30, 0x19, 0x19, 0xe5, 0x5f, 0x54, 0x30, 0xff, 0xbf, 0x30, 0x11, 0xe5, 0x25, 0x70, 0x05,
-0x75, 0x25, 0x0c, 0x80, 0x02, 0x15, 0x25, 0xd2, 0x6c, 0xd2, 0x6d, 0x80, 0x0f, 0xe5, 0x5f, 0x30,
-0xe6, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x04, 0xd2, 0x6c, 0xc2, 0x6d, 0xe5, 0x47, 0x64, 0x03,
-0x70, 0x21, 0x30, 0x4b, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x18, 0xe5, 0x25, 0x70, 0x03, 0x30,
-0x4c, 0x11, 0xc2, 0x4c, 0xe5, 0x25, 0x70, 0x05, 0x75, 0x25, 0x07, 0x80, 0x02, 0x15, 0x25, 0xd2,
-0x6c, 0xd2, 0x6d, 0xe5, 0x47, 0xb4, 0x09, 0x14, 0xe5, 0x44, 0x20, 0xe3, 0x0b, 0xe5, 0x3a, 0x64,
-0x02, 0x60, 0x05, 0xe5, 0x3a, 0xb4, 0x03, 0x04, 0xc2, 0x6c, 0xd2, 0x6d, 0x90, 0x70, 0x46, 0xe5,
-0x2d, 0xf0, 0x20, 0x69, 0x07, 0xe5, 0x5e, 0x20, 0xe0, 0x02, 0xb2, 0x68, 0x20, 0x6b, 0x07, 0xe5,
-0x5e, 0x20, 0xe1, 0x02, 0xb2, 0x6a, 0x20, 0x6d, 0x07, 0xe5, 0x5e, 0x20, 0xe2, 0x02, 0xb2, 0x6c,
-0x90, 0x70, 0x47, 0xe5, 0x2d, 0xf0, 0x75, 0x2e, 0x40, 0x20, 0x69, 0x04, 0xa2, 0x68, 0x80, 0x26,
-0x30, 0x68, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe2, 0x04, 0x7f, 0x01,
-0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, 0x02,
-0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x73, 0x92, 0x72, 0x20, 0x6b, 0x04, 0xa2, 0x6a, 0x80,
-0x26, 0x30, 0x6a, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe0, 0x04, 0x7f,
-0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80,
-0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x75, 0x92, 0x74, 0x20, 0x6d, 0x04, 0xa2, 0x6c,
-0x80, 0x26, 0x30, 0x6c, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe1, 0x04,
-0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01,
-0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x71, 0x92, 0x70, 0x90, 0x10, 0x00, 0xe0,
-0x90, 0x10, 0x2f, 0xf0, 0x90, 0x10, 0x03, 0xe0, 0xc3, 0x94, 0x30, 0x40, 0x14, 0xa2, 0x71, 0x92,
-0x77, 0xa2, 0x70, 0x92, 0x76, 0xe5, 0x2e, 0x13, 0x13, 0x54, 0x3f, 0xf5, 0x2e, 0xc2, 0x77, 0xd2,
-0x76, 0x90, 0x10, 0x2f, 0xe5, 0x2e, 0xf0, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x4c, 0x90, 0x02, 0x29,
-0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x43, 0xc4, 0x54, 0x0f, 0x14, 0x60, 0x14, 0x24, 0xfe, 0x60, 0x23,
-0x24, 0x03, 0x60, 0x03, 0x02, 0x16, 0x18, 0x90, 0x02, 0x28, 0xe0, 0x30, 0x47, 0x0f, 0x80, 0x07,
-0x90, 0x02, 0x28, 0xe0, 0x20, 0x47, 0x06, 0x54, 0xfe, 0xf0, 0x02, 0x16, 0x18, 0x44, 0x01, 0xf0,
-0x02, 0x16, 0x18, 0xe5, 0x46, 0x30, 0xe2, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x02,
-0x28, 0xe0, 0x54, 0xfe, 0x4f, 0xf0, 0x02, 0x16, 0x18, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x0f, 0xe5,
-0x47, 0x64, 0x08, 0x60, 0x09, 0xe5, 0x47, 0x64, 0x09, 0x60, 0x03, 0x02, 0x16, 0x18, 0xe4, 0xf5,
-0x27, 0x90, 0x02, 0x29, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x3a, 0x14, 0x60, 0x2d, 0x14, 0x60, 0x2e,
-0x14, 0x60, 0x36, 0x24, 0xfc, 0x60, 0x5f, 0x24, 0xf9, 0x60, 0x1f, 0x24, 0x0e, 0x70, 0x69, 0xe5,
-0x46, 0x13, 0x13, 0x54, 0x3f, 0x75, 0xf0, 0x03, 0x84, 0xaf, 0xf0, 0x20, 0x47, 0x04, 0x7e, 0x01,
-0x80, 0x02, 0x7e, 0x00, 0xef, 0x6e, 0x24, 0xff, 0x80, 0x45, 0xa2, 0x47, 0x80, 0x41, 0xe5, 0x46,
-0x30, 0xe2, 0x03, 0xd3, 0x80, 0x27, 0xc3, 0x80, 0x24, 0xe5, 0x46, 0x30, 0xe2, 0x0d, 0x54, 0x38,
-0xc3, 0x94, 0x30, 0x50, 0x06, 0x7e, 0x00, 0x7f, 0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x20,
-0x47, 0x04, 0x7d, 0x01, 0x80, 0x02, 0x7d, 0x00, 0xef, 0x6d, 0x4e, 0x24, 0xff, 0x92, 0x38, 0xa2,
-0x47, 0xb3, 0x92, 0x39, 0x80, 0x19, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92,
-0x39, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x80, 0x07, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x92, 0x39, 0x90,
-0x02, 0x28, 0xe0, 0x54, 0xfc, 0x45, 0x27, 0xf0, 0x90, 0x70, 0x9c, 0xe5, 0x3a, 0xf0, 0xa3, 0xe5,
-0x47, 0xf0, 0x90, 0x70, 0x41, 0xe5, 0x3a, 0xf0, 0x22, 0xe4, 0x90, 0x02, 0x29, 0xf0, 0x30, 0x47,
-0x04, 0xaf, 0x45, 0x80, 0x04, 0xe5, 0x45, 0xf4, 0xff, 0x90, 0x02, 0x28, 0xef, 0xf0, 0x22, 0x8f,
-0x50, 0xd2, 0x59, 0x22, 0x8f, 0x54, 0xd2, 0x58, 0x22, 0xe4, 0xf5, 0x62, 0xc2, 0xaf, 0xe5, 0x51,
-0x14, 0x60, 0x46, 0x14, 0x60, 0x62, 0x24, 0x02, 0x60, 0x03, 0x02, 0x17, 0x03, 0xd2, 0x59, 0x75,
-0x55, 0x01, 0x90, 0x02, 0xa2, 0xe0, 0x54, 0x7f, 0xf0, 0xa3, 0xe0, 0x20, 0xe7, 0x22, 0x90, 0x04,
-0x34, 0xe0, 0xb4, 0x02, 0x1b, 0xa3, 0xe0, 0xb4, 0x02, 0x16, 0xa3, 0xe0, 0xb4, 0x02, 0x11, 0x7f,
-0x20, 0x12, 0x16, 0x3f, 0x90, 0x10, 0x04, 0xe0, 0x54, 0xf3, 0xf0, 0x75, 0x51, 0x01, 0x80, 0x73,
-0xe5, 0x50, 0x70, 0x05, 0x75, 0x62, 0x03, 0x80, 0x6a, 0x90, 0x12, 0x00, 0xe0, 0x54, 0x03, 0x70,
-0x11, 0x7f, 0x20, 0x12, 0x16, 0x3f, 0x90, 0x02, 0xa2, 0xe0, 0x54, 0xbf, 0xf0, 0x75, 0x51, 0x02,
-0x80, 0x51, 0xe5, 0x50, 0x70, 0x02, 0x80, 0x46, 0x90, 0x02, 0xa3, 0xe0, 0x20, 0xe6, 0x3b, 0x90,
-0x04, 0x37, 0xe0, 0x64, 0x22, 0x70, 0x33, 0x90, 0x01, 0x8a, 0x74, 0x7e, 0xf0, 0x90, 0x01, 0x96,
-0xf0, 0x90, 0x12, 0x04, 0x74, 0x0a, 0xf0, 0x90, 0x13, 0x28, 0xe0, 0x54, 0xf0, 0xf0, 0xa3, 0xe0,
-0x54, 0xf0, 0xf0, 0xa3, 0xe0, 0x54, 0xfa, 0xf0, 0x90, 0x04, 0x01, 0xe0, 0x54, 0xf9, 0xf0, 0x75,
-0x62, 0x01, 0x75, 0x55, 0x02, 0xe4, 0xf5, 0x51, 0x80, 0x09, 0xe5, 0x50, 0x70, 0x05, 0x75, 0x62,
-0x03, 0xf5, 0x51, 0xe5, 0x62, 0x60, 0x15, 0xc2, 0x01, 0xe4, 0xf5, 0x51, 0xc2, 0x59, 0xad, 0x62,
-0xaf, 0x40, 0x12, 0x17, 0x8d, 0xe5, 0x62, 0xb4, 0x03, 0x02, 0xd2, 0x03, 0xd2, 0xaf, 0x22, 0xc2,
-0xaf, 0x30, 0x01, 0x12, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xf5, 0x51, 0xc2, 0x59, 0xc2, 0x01, 0x7d,
-0x02, 0xaf, 0x40, 0x12, 0x17, 0x8d, 0xe5, 0x52, 0x14, 0x60, 0x09, 0x04, 0x70, 0x4c, 0x75, 0x52,
-0x01, 0x75, 0x55, 0x03, 0x90, 0x04, 0x01, 0xe0, 0x44, 0x0e, 0xf0, 0x90, 0x13, 0x28, 0xe0, 0x44,
-0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x05, 0xf0, 0x90, 0x12, 0x04, 0x74,
-0x03, 0xf0, 0x90, 0x02, 0xa2, 0xe0, 0x44, 0xc0, 0xf0, 0x90, 0x10, 0x04, 0xe0, 0x44, 0x0c, 0xf0,
-0xe4, 0xf5, 0x52, 0xf5, 0x55, 0x30, 0x02, 0x0b, 0xc2, 0x02, 0x7d, 0x01, 0xaf, 0x41, 0x12, 0x17,
-0x8d, 0x80, 0x02, 0xc2, 0x03, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xd2, 0xaf, 0x22, 0xef, 0xf4, 0x60,
-0x2d, 0xe4, 0xfe, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xe0, 0xb4, 0xff,
-0x19, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xef, 0xf0, 0x74, 0x1c, 0x2e,
-0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xed, 0xf0, 0x22, 0x0e, 0xbe, 0x04, 0xd5, 0x22, 0x22,
-0x22, 0x90, 0x70, 0x2a, 0xe0, 0x30, 0xe1, 0x4d, 0xc2, 0xaf, 0x90, 0x70, 0x28, 0xe0, 0x90, 0x10,
-0x1c, 0xf0, 0x90, 0x70, 0x29, 0xe0, 0x90, 0x10, 0x1d, 0xf0, 0x90, 0x70, 0x2a, 0xe0, 0x90, 0x10,
-0x1e, 0xf0, 0x90, 0x10, 0x1c, 0xe0, 0xf5, 0x62, 0x90, 0x10, 0x1e, 0xe0, 0x20, 0xe1, 0xf3, 0x90,
-0x10, 0x1c, 0xe0, 0x90, 0x70, 0x28, 0xf0, 0x90, 0x10, 0x1d, 0xe0, 0x90, 0x70, 0x29, 0xf0, 0x90,
-0x10, 0x1e, 0xe0, 0x90, 0x70, 0x2a, 0xf0, 0x30, 0x4a, 0x07, 0x90, 0x70, 0x24, 0xe0, 0x44, 0x01,
-0xf0, 0xc2, 0x05, 0xd2, 0xaf, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x94, 0x3f,
-0xff, 0xff, 0xff, 0x02, 0x10, 0x28, 0x02, 0x10, 0x32, 0x02, 0x10, 0x78, 0x02, 0x12, 0x67, 0x02,
-0x12, 0x68, 0x02, 0x12, 0x87, 0x02, 0x12, 0x8c, 0x12, 0x12, 0x88, 0x22, 0x02, 0x16, 0x49, 0x02,
-0x17, 0x1f, 0x02, 0x13, 0x77, 0x02, 0x12, 0x8d, 0x30, 0x05, 0x06, 0x20, 0x0d, 0x03, 0x12, 0x17,
-0xc1, 0x22, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe3, 0x1b, 0xe5, 0x4c, 0x30, 0xe0, 0x04, 0x7f, 0x40,
-0x80, 0x02, 0x7f, 0x00, 0x90, 0x10, 0x2f, 0xef, 0xf0, 0x90, 0x01, 0x8c, 0x74, 0x08, 0xf0, 0xe4,
-0x90, 0x01, 0xa7, 0xf0, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe0, 0x1c, 0x90, 0x01, 0x80, 0xe0, 0xb4,
-0x02, 0x15, 0xa3, 0xe0, 0xb4, 0x01, 0x10, 0x90, 0x01, 0x84, 0xe0, 0xb4, 0x81, 0x09, 0x90, 0x01,
-0x8c, 0x74, 0x01, 0xf0, 0x12, 0x0d, 0xdd, 0x22, 0x90, 0x04, 0x14, 0xe0, 0x20, 0xe7, 0x03, 0x02,
-0x12, 0x66, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x56, 0x90, 0x04, 0x04, 0xe0, 0x12, 0x0a, 0xb6, 0x10,
-0xb7, 0x31, 0x10, 0xe0, 0x50, 0x11, 0x04, 0x51, 0x11, 0x0d, 0x52, 0x11, 0x0d, 0x53, 0x11, 0x0d,
-0x54, 0x11, 0x4e, 0x55, 0x11, 0x7e, 0x70, 0x11, 0xa9, 0x71, 0x11, 0xd7, 0x72, 0x12, 0x1d, 0x73,
-0x12, 0x3e, 0x80, 0x00, 0x00, 0x12, 0x66, 0x20, 0x02, 0x03, 0x30, 0x03, 0x1d, 0x7d, 0x02, 0xaf,
-0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5,
-0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0x85, 0x56, 0x41, 0xd2, 0x02, 0x22,
-0x90, 0x70, 0x10, 0xe0, 0x54, 0x7f, 0x64, 0x02, 0x60, 0x03, 0x02, 0x12, 0x66, 0x90, 0x70, 0x11,
-0xe0, 0x64, 0x08, 0x60, 0x08, 0xe0, 0x64, 0x20, 0x60, 0x03, 0x02, 0x12, 0x66, 0x75, 0x4e, 0x03,
-0x75, 0x4f, 0x20, 0x22, 0x90, 0x70, 0x11, 0xe0, 0x24, 0xff, 0x92, 0x47, 0x22, 0x90, 0x04, 0x04,
-0xe0, 0x25, 0xe0, 0x24, 0x5d, 0xf5, 0x57, 0x90, 0x70, 0x10, 0xe0, 0xff, 0x74, 0x47, 0x25, 0x57,
-0xf8, 0xc6, 0xef, 0xc6, 0x90, 0x70, 0x11, 0xe0, 0xff, 0x74, 0x48, 0x25, 0x57, 0xf8, 0xc6, 0xef,
-0xc6, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90,
-0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0xe5, 0x47,
-0x64, 0x07, 0x60, 0x0b, 0xe5, 0x47, 0x64, 0x08, 0x60, 0x05, 0xe5, 0x47, 0xb4, 0x09, 0x08, 0x90,
-0x70, 0x11, 0xe0, 0x54, 0x0f, 0xf5, 0x3a, 0xe5, 0x47, 0xb4, 0x09, 0x08, 0xe5, 0x3a, 0xb4, 0x03,
-0x03, 0xe4, 0xf5, 0x46, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0xd2, 0x04, 0x22, 0x90, 0x70,
-0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed, 0xf8, 0xe6, 0xf5, 0x57, 0xfd, 0xaf, 0x56,
-0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56,
-0xf4, 0x70, 0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70,
-0x11, 0xe0, 0xfd, 0xed, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x0b,
-0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70,
-0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0x90, 0x10, 0x02, 0xe0, 0xb4, 0x70, 0x1e, 0xa3, 0xe0,
-0xb4, 0x30, 0x19, 0x90, 0x05, 0x08, 0xe0, 0x44, 0x01, 0xf0, 0xfd, 0x90, 0x05, 0x05, 0xe0, 0x54,
-0xfb, 0xf0, 0x44, 0x04, 0xf0, 0xed, 0x54, 0xfe, 0x90, 0x05, 0x08, 0xf0, 0xe4, 0xf5, 0x4e, 0xf5,
-0x4f, 0x75, 0x3a, 0xff, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80,
-0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x4b, 0x80, 0x42, 0x90, 0x70, 0x10,
-0xe0, 0x24, 0xff, 0x92, 0x93, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74,
-0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x2a, 0x80, 0x21, 0x90, 0x70,
-0x10, 0xe0, 0x24, 0xff, 0x92, 0x4a, 0xd2, 0x05, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90,
-0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x07, 0x90,
-0x70, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x22, 0x22, 0xe5, 0x53, 0x70, 0x1a, 0x30, 0x60, 0x09, 0xb2,
-0x4d, 0x30, 0x4d, 0x04, 0x05, 0x46, 0xc2, 0x04, 0xe5, 0x4f, 0x45, 0x4e, 0x60, 0x08, 0xe5, 0x4f,
-0x15, 0x4f, 0x70, 0x02, 0x15, 0x4e, 0x22, 0x22, 0xc2, 0x42, 0xd3, 0x22, 0x22, 0xc2, 0x4b, 0xc2,
-0x4c, 0xe5, 0x44, 0x12, 0x0a, 0xb6, 0x12, 0xaf, 0x00, 0x13, 0x42, 0x04, 0x13, 0x3e, 0x08, 0x13,
-0x19, 0x10, 0x12, 0xc3, 0x20, 0x12, 0xe3, 0x60, 0x12, 0xf4, 0xa0, 0x00, 0x00, 0x13, 0x44, 0x85,
-0x48, 0x43, 0x85, 0x4a, 0x42, 0x85, 0x4c, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x60, 0x03, 0x02, 0x13,
-0x44, 0x80, 0x1b, 0xe5, 0x48, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4a, 0xc4, 0x54, 0x0f, 0xf5,
-0x42, 0xe5, 0x4c, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x66, 0x53, 0x43,
-0x0f, 0x80, 0x61, 0x85, 0x49, 0x43, 0x85, 0x4b, 0x42, 0x85, 0x4d, 0x5e, 0xe5, 0x47, 0x64, 0x06,
-0x70, 0x52, 0x80, 0x1b, 0xe5, 0x49, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4b, 0xc4, 0x54, 0x0f,
-0xf5, 0x42, 0xe5, 0x4d, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x35, 0xe5,
-0x43, 0x54, 0x0f, 0x44, 0x10, 0xf5, 0x43, 0x80, 0x2b, 0xe5, 0x47, 0xb4, 0x04, 0x06, 0x53, 0x5e,
-0xfb, 0x75, 0x42, 0x09, 0xe5, 0x47, 0xb4, 0x05, 0x06, 0x43, 0x5e, 0x04, 0x75, 0x42, 0x09, 0xe5,
-0x47, 0xb4, 0x06, 0x10, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x30, 0xf5, 0x43, 0x80, 0x06, 0xd2, 0x4b,
-0x80, 0x02, 0xd2, 0x4c, 0xe4, 0xf5, 0x25, 0xe5, 0x42, 0xc4, 0x54, 0xf0, 0xff, 0xe5, 0x43, 0x54,
-0x0f, 0x4f, 0xf5, 0x5f, 0x90, 0x70, 0x44, 0xf0, 0xa3, 0xe5, 0x5e, 0xf0, 0xa3, 0xe5, 0x4a, 0xf0,
-0xa3, 0xe5, 0x48, 0xf0, 0xa3, 0xe5, 0x4c, 0xf0, 0xa3, 0xe5, 0x44, 0xf0, 0xa3, 0xe5, 0x42, 0xf0,
-0xa3, 0xe5, 0x43, 0xf0, 0xd2, 0x60, 0x22, 0xe5, 0x47, 0x60, 0x10, 0x24, 0xc0, 0x70, 0x03, 0x12,
-0x16, 0x29, 0x12, 0x13, 0x8c, 0xc2, 0xaf, 0xc2, 0x04, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0x90, 0x04,
-0x14, 0xe0, 0x54, 0x0e, 0x60, 0x04, 0xd2, 0x18, 0x80, 0x08, 0xe5, 0x4e, 0x45, 0x4f, 0x24, 0xff,
-0x92, 0x18, 0xd2, 0xaf, 0x90, 0x04, 0x14, 0xe0, 0xa2, 0xe4, 0x92, 0x19, 0x74, 0x1e, 0xf0, 0xe5,
-0x5f, 0x54, 0x0f, 0xf5, 0x2d, 0xe5, 0x25, 0x70, 0x13, 0x30, 0x18, 0x05, 0xe5, 0x5f, 0x20, 0xe5,
-0x0b, 0x30, 0x19, 0x19, 0xe5, 0x5f, 0x54, 0x30, 0xff, 0xbf, 0x30, 0x11, 0xe5, 0x25, 0x70, 0x05,
-0x75, 0x25, 0x0c, 0x80, 0x02, 0x15, 0x25, 0xd2, 0x6c, 0xd2, 0x6d, 0x80, 0x0f, 0xe5, 0x5f, 0x30,
-0xe6, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x04, 0xd2, 0x6c, 0xc2, 0x6d, 0xe5, 0x47, 0x64, 0x03,
-0x70, 0x21, 0x30, 0x4b, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x18, 0xe5, 0x25, 0x70, 0x03, 0x30,
-0x4c, 0x11, 0xc2, 0x4c, 0xe5, 0x25, 0x70, 0x05, 0x75, 0x25, 0x07, 0x80, 0x02, 0x15, 0x25, 0xd2,
-0x6c, 0xd2, 0x6d, 0xe5, 0x47, 0xb4, 0x09, 0x14, 0xe5, 0x44, 0x20, 0xe3, 0x0b, 0xe5, 0x3a, 0x64,
-0x02, 0x60, 0x05, 0xe5, 0x3a, 0xb4, 0x03, 0x04, 0xc2, 0x6c, 0xd2, 0x6d, 0x90, 0x70, 0x46, 0xe5,
-0x2d, 0xf0, 0x20, 0x69, 0x07, 0xe5, 0x5e, 0x20, 0xe0, 0x02, 0xb2, 0x68, 0x20, 0x6b, 0x07, 0xe5,
-0x5e, 0x20, 0xe1, 0x02, 0xb2, 0x6a, 0x20, 0x6d, 0x07, 0xe5, 0x5e, 0x20, 0xe2, 0x02, 0xb2, 0x6c,
-0x90, 0x70, 0x47, 0xe5, 0x2d, 0xf0, 0x75, 0x2e, 0x40, 0x20, 0x69, 0x04, 0xa2, 0x68, 0x80, 0x26,
-0x30, 0x68, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe2, 0x04, 0x7f, 0x01,
-0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, 0x02,
-0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x73, 0x92, 0x72, 0x20, 0x6b, 0x04, 0xa2, 0x6a, 0x80,
-0x26, 0x30, 0x6a, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe0, 0x04, 0x7f,
-0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80,
-0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x75, 0x92, 0x74, 0x20, 0x6d, 0x04, 0xa2, 0x6c,
-0x80, 0x26, 0x30, 0x6c, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe1, 0x04,
-0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01,
-0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x71, 0x92, 0x70, 0x90, 0x10, 0x00, 0xe0,
-0x90, 0x10, 0x2f, 0xf0, 0x90, 0x10, 0x03, 0xe0, 0xc3, 0x94, 0x30, 0x40, 0x14, 0xa2, 0x71, 0x92,
-0x77, 0xa2, 0x70, 0x92, 0x76, 0xe5, 0x2e, 0x13, 0x13, 0x54, 0x3f, 0xf5, 0x2e, 0xc2, 0x77, 0xd2,
-0x76, 0x90, 0x10, 0x2f, 0xe5, 0x2e, 0xf0, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x4c, 0x90, 0x02, 0x29,
-0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x43, 0xc4, 0x54, 0x0f, 0x14, 0x60, 0x14, 0x24, 0xfe, 0x60, 0x23,
-0x24, 0x03, 0x60, 0x03, 0x02, 0x16, 0x18, 0x90, 0x02, 0x28, 0xe0, 0x30, 0x47, 0x0f, 0x80, 0x07,
-0x90, 0x02, 0x28, 0xe0, 0x20, 0x47, 0x06, 0x54, 0xfe, 0xf0, 0x02, 0x16, 0x18, 0x44, 0x01, 0xf0,
-0x02, 0x16, 0x18, 0xe5, 0x46, 0x30, 0xe2, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x02,
-0x28, 0xe0, 0x54, 0xfe, 0x4f, 0xf0, 0x02, 0x16, 0x18, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x0f, 0xe5,
-0x47, 0x64, 0x08, 0x60, 0x09, 0xe5, 0x47, 0x64, 0x09, 0x60, 0x03, 0x02, 0x16, 0x18, 0xe4, 0xf5,
-0x27, 0x90, 0x02, 0x29, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x3a, 0x14, 0x60, 0x2d, 0x14, 0x60, 0x2e,
-0x14, 0x60, 0x36, 0x24, 0xfc, 0x60, 0x5f, 0x24, 0xf9, 0x60, 0x1f, 0x24, 0x0e, 0x70, 0x69, 0xe5,
-0x46, 0x13, 0x13, 0x54, 0x3f, 0x75, 0xf0, 0x03, 0x84, 0xaf, 0xf0, 0x20, 0x47, 0x04, 0x7e, 0x01,
-0x80, 0x02, 0x7e, 0x00, 0xef, 0x6e, 0x24, 0xff, 0x80, 0x45, 0xa2, 0x47, 0x80, 0x41, 0xe5, 0x46,
-0x30, 0xe2, 0x03, 0xd3, 0x80, 0x27, 0xc3, 0x80, 0x24, 0xe5, 0x46, 0x30, 0xe2, 0x0d, 0x54, 0x38,
-0xc3, 0x94, 0x30, 0x50, 0x06, 0x7e, 0x00, 0x7f, 0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x20,
-0x47, 0x04, 0x7d, 0x01, 0x80, 0x02, 0x7d, 0x00, 0xef, 0x6d, 0x4e, 0x24, 0xff, 0x92, 0x38, 0xa2,
-0x47, 0xb3, 0x92, 0x39, 0x80, 0x19, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92,
-0x39, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x80, 0x07, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x92, 0x39, 0x90,
-0x02, 0x28, 0xe0, 0x54, 0xfc, 0x45, 0x27, 0xf0, 0x90, 0x70, 0x9c, 0xe5, 0x3a, 0xf0, 0xa3, 0xe5,
-0x47, 0xf0, 0x90, 0x70, 0x41, 0xe5, 0x3a, 0xf0, 0x22, 0xe4, 0x90, 0x02, 0x29, 0xf0, 0x30, 0x47,
-0x04, 0xaf, 0x45, 0x80, 0x04, 0xe5, 0x45, 0xf4, 0xff, 0x90, 0x02, 0x28, 0xef, 0xf0, 0x22, 0x8f,
-0x50, 0xd2, 0x59, 0x22, 0x8f, 0x54, 0xd2, 0x58, 0x22, 0xe4, 0xf5, 0x62, 0xc2, 0xaf, 0xe5, 0x51,
-0x14, 0x60, 0x46, 0x14, 0x60, 0x62, 0x24, 0x02, 0x60, 0x03, 0x02, 0x17, 0x03, 0xd2, 0x59, 0x75,
-0x55, 0x01, 0x90, 0x02, 0xa2, 0xe0, 0x54, 0x7f, 0xf0, 0xa3, 0xe0, 0x20, 0xe7, 0x22, 0x90, 0x04,
-0x34, 0xe0, 0xb4, 0x02, 0x1b, 0xa3, 0xe0, 0xb4, 0x02, 0x16, 0xa3, 0xe0, 0xb4, 0x02, 0x11, 0x7f,
-0x20, 0x12, 0x16, 0x3f, 0x90, 0x10, 0x04, 0xe0, 0x54, 0xf3, 0xf0, 0x75, 0x51, 0x01, 0x80, 0x73,
-0xe5, 0x50, 0x70, 0x05, 0x75, 0x62, 0x03, 0x80, 0x6a, 0x90, 0x12, 0x00, 0xe0, 0x54, 0x03, 0x70,
-0x11, 0x7f, 0x20, 0x12, 0x16, 0x3f, 0x90, 0x02, 0xa2, 0xe0, 0x54, 0xbf, 0xf0, 0x75, 0x51, 0x02,
-0x80, 0x51, 0xe5, 0x50, 0x70, 0x02, 0x80, 0x46, 0x90, 0x02, 0xa3, 0xe0, 0x20, 0xe6, 0x3b, 0x90,
-0x04, 0x37, 0xe0, 0x64, 0x22, 0x70, 0x33, 0x90, 0x01, 0x8a, 0x74, 0x7e, 0xf0, 0x90, 0x01, 0x96,
-0xf0, 0x90, 0x12, 0x04, 0x74, 0x0a, 0xf0, 0x90, 0x13, 0x28, 0xe0, 0x54, 0xf0, 0xf0, 0xa3, 0xe0,
-0x54, 0xf0, 0xf0, 0xa3, 0xe0, 0x54, 0xfa, 0xf0, 0x90, 0x04, 0x01, 0xe0, 0x54, 0xf9, 0xf0, 0x75,
-0x62, 0x01, 0x75, 0x55, 0x02, 0xe4, 0xf5, 0x51, 0x80, 0x09, 0xe5, 0x50, 0x70, 0x05, 0x75, 0x62,
-0x03, 0xf5, 0x51, 0xe5, 0x62, 0x60, 0x15, 0xc2, 0x01, 0xe4, 0xf5, 0x51, 0xc2, 0x59, 0xad, 0x62,
-0xaf, 0x40, 0x12, 0x17, 0x8d, 0xe5, 0x62, 0xb4, 0x03, 0x02, 0xd2, 0x03, 0xd2, 0xaf, 0x22, 0xc2,
-0xaf, 0x30, 0x01, 0x12, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xf5, 0x51, 0xc2, 0x59, 0xc2, 0x01, 0x7d,
-0x02, 0xaf, 0x40, 0x12, 0x17, 0x8d, 0xe5, 0x52, 0x14, 0x60, 0x09, 0x04, 0x70, 0x4c, 0x75, 0x52,
-0x01, 0x75, 0x55, 0x03, 0x90, 0x04, 0x01, 0xe0, 0x44, 0x0e, 0xf0, 0x90, 0x13, 0x28, 0xe0, 0x44,
-0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x05, 0xf0, 0x90, 0x12, 0x04, 0x74,
-0x03, 0xf0, 0x90, 0x02, 0xa2, 0xe0, 0x44, 0xc0, 0xf0, 0x90, 0x10, 0x04, 0xe0, 0x44, 0x0c, 0xf0,
-0xe4, 0xf5, 0x52, 0xf5, 0x55, 0x30, 0x02, 0x0b, 0xc2, 0x02, 0x7d, 0x01, 0xaf, 0x41, 0x12, 0x17,
-0x8d, 0x80, 0x02, 0xc2, 0x03, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xd2, 0xaf, 0x22, 0xef, 0xf4, 0x60,
-0x2d, 0xe4, 0xfe, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xe0, 0xb4, 0xff,
-0x19, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xef, 0xf0, 0x74, 0x1c, 0x2e,
-0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xed, 0xf0, 0x22, 0x0e, 0xbe, 0x04, 0xd5, 0x22, 0x22,
-0x22, 0x90, 0x70, 0x2a, 0xe0, 0x30, 0xe1, 0x4d, 0xc2, 0xaf, 0x90, 0x70, 0x28, 0xe0, 0x90, 0x10,
-0x1c, 0xf0, 0x90, 0x70, 0x29, 0xe0, 0x90, 0x10, 0x1d, 0xf0, 0x90, 0x70, 0x2a, 0xe0, 0x90, 0x10,
-0x1e, 0xf0, 0x90, 0x10, 0x1c, 0xe0, 0xf5, 0x62, 0x90, 0x10, 0x1e, 0xe0, 0x20, 0xe1, 0xf3, 0x90,
-0x10, 0x1c, 0xe0, 0x90, 0x70, 0x28, 0xf0, 0x90, 0x10, 0x1d, 0xe0, 0x90, 0x70, 0x29, 0xf0, 0x90,
-0x10, 0x1e, 0xe0, 0x90, 0x70, 0x2a, 0xf0, 0x30, 0x4a, 0x07, 0x90, 0x70, 0x24, 0xe0, 0x44, 0x01,
-0xf0, 0xc2, 0x05, 0xd2, 0xaf, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x9b, 0xc0, } ;
diff --git a/drivers/staging/rt3070/md4.h b/drivers/staging/rt3070/md4.h
index a9cc7b0f3ee3..b3fb63726182 100644
--- a/drivers/staging/rt3070/md4.h
+++ b/drivers/staging/rt3070/md4.h
@@ -35,8 +35,8 @@ typedef struct _MD4_CTX_ {
u8 buffer[64]; /* input buffer */
} MD4_CTX;
-void MD4Init (MD4_CTX *);
-void MD4Update (MD4_CTX *, u8 *, UINT);
-void MD4Final (u8 [16], MD4_CTX *);
+void MD4Init(MD4_CTX *);
+void MD4Update(MD4_CTX *, u8 *, UINT);
+void MD4Final(u8 [16], MD4_CTX *);
-#endif //__MD4_H__ \ No newline at end of file
+#endif /*__MD4_H__*/
diff --git a/drivers/staging/rt3090/firmware.h b/drivers/staging/rt3090/firmware.h
deleted file mode 100644
index 17056e26795b..000000000000
--- a/drivers/staging/rt3090/firmware.h
+++ /dev/null
@@ -1,517 +0,0 @@
-/* AUTO GEN PLEASE DO NOT MODIFY IT */
-/* AUTO GEN PLEASE DO NOT MODIFY IT */
-
-
-u8 FirmwareImage_3090 [] = {
-0x02, 0x02, 0xf3, 0x02, 0x02, 0xa1, 0x22, 0x22, 0xff, 0xff, 0xff, 0x02, 0x01, 0x27, 0xff, 0xff,
-0xff, 0xff, 0xff, 0x02, 0x00, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0xd8, 0xc0, 0xe0,
-0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x18, 0xc2, 0xaf, 0x30, 0x45, 0x03,
-0x12, 0x10, 0x09, 0x90, 0x04, 0x16, 0xe0, 0x30, 0xe3, 0x03, 0x74, 0x08, 0xf0, 0x90, 0x04, 0x14,
-0xe0, 0x20, 0xe7, 0x03, 0x02, 0x00, 0xcb, 0x74, 0x80, 0xf0, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x36,
-0x90, 0x04, 0x04, 0xe0, 0x24, 0xcf, 0x60, 0x30, 0x14, 0x60, 0x42, 0x24, 0xe2, 0x60, 0x47, 0x14,
-0x60, 0x55, 0x24, 0x21, 0x70, 0x60, 0xe5, 0x55, 0x24, 0xfe, 0x60, 0x07, 0x14, 0x60, 0x08, 0x24,
-0x02, 0x70, 0x08, 0x7d, 0x01, 0x80, 0x28, 0x7d, 0x02, 0x80, 0x24, 0x90, 0x70, 0x10, 0xe0, 0xf5,
-0x50, 0x85, 0x36, 0x40, 0xd2, 0x01, 0x80, 0x3e, 0xe5, 0x55, 0x64, 0x03, 0x60, 0x04, 0xe5, 0x55,
-0x70, 0x04, 0x7d, 0x02, 0x80, 0x09, 0x85, 0x36, 0x41, 0xd2, 0x02, 0x80, 0x29, 0xad, 0x55, 0xaf,
-0x36, 0x12, 0x02, 0x7d, 0x80, 0x20, 0x90, 0x70, 0x10, 0xe0, 0xf5, 0x47, 0x90, 0x70, 0x11, 0xe0,
-0xf5, 0x44, 0x12, 0x10, 0x25, 0x80, 0x06, 0x90, 0x70, 0x10, 0xe0, 0xf5, 0x45, 0xe4, 0xfd, 0xaf,
-0x36, 0x12, 0x02, 0x7d, 0xd2, 0x04, 0x90, 0x70, 0x13, 0xe4, 0xf0, 0xd2, 0xaf, 0xd0, 0xd0, 0xd0,
-0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82,
-0xc0, 0xd0, 0xe8, 0xc0, 0xe0, 0xe9, 0xc0, 0xe0, 0xea, 0xc0, 0xe0, 0xeb, 0xc0, 0xe0, 0xec, 0xc0,
-0xe0, 0xed, 0xc0, 0xe0, 0xee, 0xc0, 0xe0, 0xef, 0xc0, 0xe0, 0xc2, 0xaf, 0x30, 0x45, 0x03, 0x12,
-0x10, 0x12, 0xd2, 0xaf, 0xd0, 0xe0, 0xff, 0xd0, 0xe0, 0xfe, 0xd0, 0xe0, 0xfd, 0xd0, 0xe0, 0xfc,
-0xd0, 0xe0, 0xfb, 0xd0, 0xe0, 0xfa, 0xd0, 0xe0, 0xf9, 0xd0, 0xe0, 0xf8, 0xd0, 0xd0, 0xd0, 0x82,
-0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0,
-0xd0, 0x75, 0xd0, 0x10, 0xc2, 0xaf, 0x30, 0x45, 0x03, 0x12, 0x10, 0x0c, 0x30, 0x58, 0x0a, 0xe5,
-0x54, 0x60, 0x04, 0x15, 0x54, 0x80, 0x02, 0xc2, 0x58, 0x30, 0x59, 0x0a, 0xe5, 0x50, 0x60, 0x04,
-0x15, 0x50, 0x80, 0x02, 0xc2, 0x59, 0xd5, 0x53, 0x07, 0x30, 0x60, 0x04, 0x15, 0x46, 0xd2, 0x04,
-0x30, 0x45, 0x03, 0x12, 0x10, 0x0f, 0xc2, 0x8d, 0xd2, 0xaf, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83,
-0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0x90, 0x70, 0x2a, 0xe0, 0x30, 0xe1, 0x43, 0xc2, 0xaf, 0x90, 0x70,
-0x28, 0xe0, 0x90, 0x10, 0x1c, 0xf0, 0x90, 0x70, 0x29, 0xe0, 0x90, 0x10, 0x1d, 0xf0, 0x90, 0x70,
-0x2a, 0xe0, 0x90, 0x10, 0x1e, 0xf0, 0x90, 0x10, 0x1c, 0xe0, 0xf5, 0x37, 0x90, 0x10, 0x1e, 0xe0,
-0x20, 0xe1, 0xf3, 0x90, 0x10, 0x1c, 0xe0, 0x90, 0x70, 0x28, 0xf0, 0x90, 0x10, 0x1d, 0xe0, 0x90,
-0x70, 0x29, 0xf0, 0x90, 0x10, 0x1e, 0xe0, 0x90, 0x70, 0x2a, 0xf0, 0xc2, 0x05, 0xd2, 0xaf, 0x22,
-0x12, 0x02, 0xc3, 0x30, 0x45, 0x03, 0x12, 0x10, 0x03, 0x30, 0x01, 0x06, 0x20, 0x09, 0x03, 0x12,
-0x10, 0x1c, 0x30, 0x02, 0x06, 0x20, 0x0a, 0x03, 0x12, 0x10, 0x1f, 0x30, 0x03, 0x06, 0x20, 0x0b,
-0x03, 0x12, 0x10, 0x1f, 0x30, 0x04, 0x06, 0x20, 0x0c, 0x03, 0x12, 0x10, 0x22, 0x20, 0x13, 0x09,
-0x20, 0x11, 0x06, 0xe5, 0x2b, 0x45, 0x2c, 0x60, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0xa9, 0x12,
-0x03, 0x1c, 0x80, 0xbf, 0xc2, 0x43, 0xd2, 0x45, 0xe4, 0xf5, 0x20, 0xf5, 0x21, 0xf5, 0x53, 0xf5,
-0x46, 0xf5, 0x2b, 0xf5, 0x2c, 0xc2, 0x42, 0xf5, 0x51, 0xf5, 0x52, 0xf5, 0x55, 0x90, 0x04, 0x18,
-0x74, 0x80, 0xf0, 0x90, 0x04, 0x1a, 0x74, 0x08, 0xf0, 0xc2, 0x1a, 0xc2, 0x18, 0xc2, 0x1b, 0x22,
-0xc8, 0xef, 0xc8, 0xe6, 0xfa, 0x08, 0xe6, 0x4a, 0x60, 0x0c, 0xc8, 0xef, 0xc8, 0x08, 0xe6, 0x16,
-0x18, 0x70, 0x01, 0x16, 0xc3, 0x22, 0xed, 0x24, 0xff, 0xfd, 0xec, 0x34, 0xff, 0xc8, 0xef, 0xc8,
-0xf6, 0x08, 0xc6, 0xed, 0xc6, 0xd3, 0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12,
-0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83,
-0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0xef, 0xf4, 0x60,
-0x1f, 0xe4, 0xfe, 0x12, 0x03, 0x5b, 0xe0, 0xb4, 0xff, 0x12, 0x12, 0x03, 0x5b, 0xef, 0xf0, 0x74,
-0x1c, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xed, 0xf0, 0x22, 0x0e, 0xbe, 0x04, 0xe3,
-0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x08, 0xc2, 0xaf,
-0x30, 0x45, 0x03, 0x12, 0x10, 0x06, 0xd2, 0xaf, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0,
-0xd0, 0xe0, 0x32, 0xc2, 0xaf, 0x12, 0x00, 0x06, 0x12, 0x02, 0x04, 0x12, 0x02, 0xdc, 0xe4, 0xf5,
-0x22, 0xf5, 0x47, 0x90, 0x04, 0x00, 0x74, 0x80, 0xf0, 0xd2, 0xaf, 0x22, 0x75, 0x89, 0x02, 0xe4,
-0xf5, 0x8c, 0xf5, 0x8a, 0xf5, 0x88, 0xf5, 0xb8, 0xf5, 0xe8, 0x75, 0x90, 0x18, 0xd2, 0x8c, 0x75,
-0xa8, 0x05, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x5f, 0x02, 0x01, 0xc0, 0xff,
-0xc0, 0x26, 0x74, 0x03, 0xc0, 0xe0, 0xc0, 0x82, 0xc0, 0x83, 0x75, 0x26, 0x0a, 0x22, 0xc0, 0x26,
-0x74, 0x03, 0xc0, 0xe0, 0xc0, 0x82, 0xc0, 0x83, 0x75, 0x26, 0x18, 0x22, 0x30, 0x45, 0x03, 0x12,
-0x10, 0x15, 0xe5, 0x20, 0x70, 0x03, 0x20, 0x10, 0x03, 0x30, 0x11, 0x03, 0x43, 0x87, 0x01, 0x22,
-0xce, 0xef, 0xce, 0xee, 0x60, 0x08, 0x7f, 0xff, 0x12, 0x03, 0x71, 0x1e, 0x80, 0xf5, 0x22, 0xc8,
-0xef, 0xc8, 0xe6, 0x60, 0x03, 0x16, 0xc3, 0x22, 0xed, 0x14, 0xf6, 0xd3, 0x22, 0xc8, 0xef, 0xc8,
-0xe6, 0x60, 0x06, 0x16, 0xe6, 0x24, 0xff, 0xb3, 0x22, 0xc3, 0x22, 0x74, 0x14, 0x2e, 0xf5, 0x82,
-0xe4, 0x34, 0x70, 0xf5, 0x83, 0x22, 0xef, 0x90, 0x03, 0x6f, 0x93, 0x90, 0x03, 0x00, 0x73, 0x0a,
-0x18, 0xef, 0x60, 0x03, 0x1f, 0x80, 0xfa, 0x22, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0x02, 0x10, 0x28, 0x02, 0x10, 0x3b, 0x02, 0x10, 0x3c, 0x02, 0x13, 0x68, 0x02,
-0x13, 0x69, 0x02, 0x14, 0x1e, 0x02, 0x14, 0x1f, 0xc3, 0x22, 0xff, 0xff, 0x02, 0x19, 0xa1, 0x02,
-0x1b, 0x31, 0x02, 0x14, 0xea, 0x02, 0x14, 0x20, 0x30, 0x05, 0x06, 0x20, 0x0d, 0x03, 0x12, 0x01,
-0x75, 0x30, 0x06, 0x06, 0x20, 0x0e, 0x03, 0x12, 0x1c, 0x4f, 0x22, 0x22, 0x90, 0x04, 0x14, 0xe0,
-0x20, 0xe7, 0x03, 0x02, 0x13, 0x67, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x56, 0x90, 0x04, 0x04, 0xe0,
-0x12, 0x02, 0x57, 0x11, 0x11, 0x30, 0x10, 0xe2, 0x31, 0x10, 0x90, 0x33, 0x10, 0xa0, 0x34, 0x10,
-0xbe, 0x35, 0x10, 0xac, 0x36, 0x11, 0x1f, 0x50, 0x11, 0x68, 0x51, 0x11, 0x71, 0x52, 0x11, 0x71,
-0x53, 0x11, 0x71, 0x54, 0x11, 0xb3, 0x55, 0x12, 0x16, 0x70, 0x12, 0x42, 0x71, 0x12, 0x71, 0x72,
-0x12, 0xda, 0x73, 0x12, 0xfe, 0x80, 0x13, 0x29, 0x83, 0x13, 0x47, 0x84, 0x00, 0x00, 0x13, 0x67,
-0xd2, 0x18, 0xd2, 0x61, 0x75, 0x35, 0x2a, 0x75, 0x32, 0x0b, 0x75, 0x33, 0xb8, 0x02, 0x13, 0x62,
-0xc2, 0x18, 0x90, 0x01, 0x14, 0xe0, 0x54, 0xfd, 0xf0, 0x02, 0x13, 0x62, 0x90, 0x70, 0x11, 0xe0,
-0xf5, 0x3c, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0x22, 0xe5, 0x55,
-0xb4, 0x02, 0x0f, 0xe5, 0x59, 0xb4, 0x28, 0x06, 0x90, 0x01, 0x0d, 0x74, 0x08, 0xf0, 0x7d, 0x01,
-0x80, 0x02, 0x7d, 0x02, 0xaf, 0x56, 0x12, 0x02, 0x7d, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0x02,
-0x13, 0x62, 0x20, 0x02, 0x03, 0x30, 0x03, 0x10, 0x7d, 0x02, 0xaf, 0x56, 0x12, 0x02, 0x7d, 0x90,
-0x04, 0x14, 0x74, 0x80, 0xf0, 0x02, 0x13, 0x62, 0xe5, 0x34, 0xc3, 0x94, 0x03, 0x40, 0x0c, 0x90,
-0x01, 0x0c, 0xe0, 0x44, 0x02, 0xf0, 0xa3, 0xe0, 0x44, 0x04, 0xf0, 0x85, 0x56, 0x41, 0xd2, 0x02,
-0x22, 0x90, 0x70, 0x11, 0xe0, 0xf4, 0x70, 0x03, 0x02, 0x13, 0x67, 0xe0, 0xf5, 0x30, 0x22, 0xe5,
-0x34, 0xc3, 0x94, 0x03, 0x40, 0x07, 0xe5, 0x55, 0x60, 0x03, 0x02, 0x13, 0x67, 0x90, 0x70, 0x10,
-0xe0, 0x54, 0x7f, 0xff, 0xbf, 0x0a, 0x0d, 0x90, 0x70, 0x11, 0xe0, 0xb4, 0x08, 0x06, 0x75, 0x4e,
-0x01, 0x75, 0x4f, 0x84, 0x90, 0x70, 0x10, 0xe0, 0x54, 0x7f, 0x64, 0x02, 0x60, 0x03, 0x02, 0x13,
-0x67, 0x90, 0x70, 0x11, 0xe0, 0x64, 0x08, 0x60, 0x08, 0xe0, 0x64, 0x20, 0x60, 0x03, 0x02, 0x13,
-0x67, 0x75, 0x4e, 0x03, 0x75, 0x4f, 0x20, 0x22, 0x90, 0x70, 0x11, 0xe0, 0x24, 0xff, 0x92, 0x47,
-0x22, 0xe5, 0x34, 0xc3, 0x94, 0x03, 0x40, 0x07, 0xe5, 0x55, 0x60, 0x03, 0x02, 0x13, 0x09, 0x90,
-0x04, 0x04, 0xe0, 0x25, 0xe0, 0x24, 0x5d, 0xf5, 0x57, 0x90, 0x70, 0x10, 0xe0, 0xff, 0x74, 0x47,
-0x25, 0x57, 0xf8, 0xc6, 0xef, 0xc6, 0x90, 0x70, 0x11, 0xe0, 0xff, 0x74, 0x48, 0x25, 0x57, 0xf8,
-0xc6, 0xef, 0xc6, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x02, 0x7d, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0,
-0x02, 0x13, 0x62, 0xe5, 0x34, 0xc3, 0x94, 0x03, 0x40, 0x07, 0xe5, 0x55, 0x60, 0x03, 0x02, 0x13,
-0x09, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x23, 0xe5, 0x47, 0x64, 0x08, 0x60, 0x1d, 0xe5, 0x47, 0x64,
-0x09, 0x60, 0x17, 0xe5, 0x47, 0x64, 0x0a, 0x60, 0x11, 0xe5, 0x47, 0x64, 0x0b, 0x60, 0x0b, 0xe5,
-0x47, 0x64, 0x0d, 0x60, 0x05, 0xe5, 0x47, 0xb4, 0x0d, 0x08, 0x90, 0x70, 0x11, 0xe0, 0x54, 0x0f,
-0xf5, 0x3a, 0xe5, 0x47, 0xb4, 0x09, 0x08, 0xe5, 0x3a, 0xb4, 0x03, 0x03, 0xe4, 0xf5, 0x46, 0xe5,
-0x47, 0xb4, 0x0a, 0x08, 0xe5, 0x3a, 0xb4, 0x01, 0x03, 0xe4, 0xf5, 0x46, 0xe4, 0xfd, 0xaf, 0x56,
-0x12, 0x02, 0x7d, 0xd2, 0x04, 0x22, 0xe5, 0x34, 0xc3, 0x94, 0x03, 0x40, 0x07, 0xe5, 0x55, 0x60,
-0x03, 0x02, 0x13, 0x09, 0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed, 0xf8,
-0xe6, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x02, 0x7d, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0x02,
-0x13, 0x62, 0xe5, 0x34, 0xc3, 0x94, 0x03, 0x40, 0x07, 0xe5, 0x55, 0x60, 0x03, 0x02, 0x13, 0x09,
-0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed, 0xf5, 0x82, 0x8e, 0x83, 0xe0,
-0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x02, 0x7d, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0x02, 0x13,
-0x62, 0x90, 0x10, 0x00, 0xe0, 0xf5, 0x57, 0x90, 0x10, 0x02, 0xe0, 0xf5, 0x58, 0xa3, 0xe0, 0xf5,
-0x59, 0xe5, 0x58, 0xb4, 0x70, 0x1e, 0xe5, 0x59, 0xb4, 0x30, 0x19, 0x90, 0x05, 0x08, 0xe0, 0x44,
-0x01, 0xf0, 0xfd, 0x90, 0x05, 0x05, 0xe0, 0x54, 0xfb, 0xf0, 0x44, 0x04, 0xf0, 0xed, 0x54, 0xfe,
-0x90, 0x05, 0x08, 0xf0, 0xe4, 0xf5, 0x4e, 0xf5, 0x4f, 0x75, 0x3a, 0xff, 0xc2, 0x1a, 0xc2, 0x18,
-0xc2, 0x1b, 0xf5, 0x34, 0x90, 0x05, 0xa4, 0x74, 0x11, 0xf0, 0xa3, 0x74, 0xff, 0xf0, 0xa3, 0x74,
-0x03, 0xf0, 0xe4, 0xf5, 0x30, 0xc2, 0x19, 0x75, 0x3c, 0xff, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x02,
-0x7d, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0x02, 0x13, 0x62, 0xe5, 0x34, 0xc3, 0x94, 0x03, 0x40,
-0x06, 0xe5, 0x55, 0x60, 0x02, 0x80, 0x22, 0x90, 0x70, 0x10, 0xe0, 0x24, 0xff, 0x92, 0x93, 0xe4,
-0xfd, 0xaf, 0x56, 0x12, 0x02, 0x7d, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0x80, 0x64, 0xe5, 0x34,
-0xc3, 0x94, 0x03, 0x40, 0x0b, 0xe5, 0x55, 0x60, 0x07, 0x7d, 0x03, 0xaf, 0x56, 0x02, 0x02, 0x7d,
-0x90, 0x70, 0x10, 0xe0, 0x24, 0xff, 0x92, 0x4a, 0xd2, 0x05, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x02,
-0x7d, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0x80, 0x39, 0xe4, 0xf5, 0x34, 0xf5, 0x30, 0x90, 0x70,
-0x10, 0xe0, 0xf4, 0x60, 0x03, 0xe0, 0xf5, 0x34, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x02, 0x7d, 0x90,
-0x04, 0x14, 0x74, 0x80, 0xf0, 0x80, 0x1b, 0xd2, 0x19, 0x05, 0x2f, 0xe5, 0x2f, 0xb4, 0x1a, 0x03,
-0xe4, 0xf5, 0x2f, 0xd2, 0x04, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x02, 0x7d, 0x90, 0x04, 0x14, 0x74,
-0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0x22, 0x22, 0xe5, 0x34, 0xc3, 0x94, 0x03, 0x40, 0x17,
-0xe5, 0x55, 0xb4, 0x02, 0x12, 0xe5, 0x30, 0x60, 0x0e, 0x30, 0x60, 0x0b, 0x74, 0xfd, 0x25, 0x46,
-0xf5, 0x46, 0xd2, 0x04, 0xe4, 0xf5, 0x53, 0xe5, 0x53, 0x60, 0x03, 0x02, 0x14, 0x1d, 0x30, 0x60,
-0x21, 0xb2, 0x4d, 0x30, 0x4d, 0x1c, 0xe5, 0x34, 0xc3, 0x94, 0x03, 0x40, 0x11, 0xe5, 0x55, 0xb4,
-0x02, 0x0c, 0xe5, 0x30, 0x60, 0x08, 0x74, 0x03, 0x25, 0x46, 0xf5, 0x46, 0x80, 0x02, 0x05, 0x46,
-0xc2, 0x04, 0xe5, 0x4f, 0x45, 0x4e, 0x60, 0x08, 0xe5, 0x4f, 0x15, 0x4f, 0x70, 0x02, 0x15, 0x4e,
-0x30, 0x1a, 0x49, 0x7f, 0x32, 0x7d, 0xb8, 0x7c, 0x0b, 0x12, 0x02, 0x30, 0x50, 0x06, 0x90, 0x04,
-0x10, 0x74, 0x40, 0xf0, 0x7f, 0x35, 0x7d, 0x32, 0x12, 0x03, 0x3f, 0x50, 0x09, 0x90, 0x10, 0x04,
-0xe0, 0x54, 0xf7, 0xf0, 0xd2, 0x06, 0xe5, 0x35, 0xd3, 0x94, 0x2d, 0x40, 0x30, 0x30, 0x1b, 0x2d,
-0xc2, 0x1b, 0xa2, 0x18, 0x92, 0x1a, 0x20, 0x1a, 0x24, 0x90, 0x04, 0x09, 0xe0, 0x54, 0xdd, 0xf0,
-0x90, 0x10, 0x04, 0xe0, 0x44, 0x08, 0xf0, 0xc2, 0x61, 0xd2, 0x03, 0x22, 0xe4, 0xf5, 0x35, 0xa2,
-0x18, 0x92, 0x1a, 0x30, 0x1a, 0x07, 0x90, 0x04, 0x09, 0xe0, 0x44, 0x22, 0xf0, 0x22, 0x22, 0x22,
-0xc2, 0x4b, 0xc2, 0x4c, 0xe5, 0x44, 0x12, 0x02, 0x57, 0x14, 0x42, 0x00, 0x14, 0xd5, 0x04, 0x14,
-0xd1, 0x08, 0x14, 0xac, 0x10, 0x14, 0x56, 0x20, 0x14, 0x76, 0x60, 0x14, 0x87, 0xa0, 0x00, 0x00,
-0x14, 0xd7, 0x85, 0x48, 0x43, 0x85, 0x4a, 0x42, 0x85, 0x4c, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x60,
-0x03, 0x02, 0x14, 0xd7, 0x80, 0x1b, 0xe5, 0x48, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4a, 0xc4,
-0x54, 0x0f, 0xf5, 0x42, 0xe5, 0x4c, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70,
-0x66, 0x53, 0x43, 0x0f, 0x80, 0x61, 0x85, 0x49, 0x43, 0x85, 0x4b, 0x42, 0x85, 0x4d, 0x5e, 0xe5,
-0x47, 0x64, 0x06, 0x70, 0x52, 0x80, 0x1b, 0xe5, 0x49, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4b,
-0xc4, 0x54, 0x0f, 0xf5, 0x42, 0xe5, 0x4d, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06,
-0x70, 0x35, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x10, 0xf5, 0x43, 0x80, 0x2b, 0xe5, 0x47, 0xb4, 0x04,
-0x06, 0x53, 0x5e, 0xfb, 0x75, 0x42, 0x09, 0xe5, 0x47, 0xb4, 0x05, 0x06, 0x43, 0x5e, 0x04, 0x75,
-0x42, 0x09, 0xe5, 0x47, 0xb4, 0x06, 0x10, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x30, 0xf5, 0x43, 0x80,
-0x06, 0xd2, 0x4b, 0x80, 0x02, 0xd2, 0x4c, 0xe4, 0xf5, 0x2a, 0xe5, 0x42, 0xc4, 0x54, 0xf0, 0xff,
-0xe5, 0x43, 0x54, 0x0f, 0x4f, 0xf5, 0x5f, 0xd2, 0x60, 0x22, 0xe5, 0x47, 0x60, 0x1a, 0x24, 0xc0,
-0x60, 0x0a, 0x24, 0x35, 0x70, 0x09, 0x12, 0x19, 0x5f, 0x12, 0x15, 0x09, 0x12, 0x19, 0x5f, 0x12,
-0x15, 0x09, 0xc2, 0xaf, 0xc2, 0x04, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0x90, 0x04, 0x14, 0xe0, 0x54,
-0x0e, 0x60, 0x04, 0xd2, 0x1c, 0x80, 0x08, 0xe5, 0x4e, 0x45, 0x4f, 0x24, 0xff, 0x92, 0x1c, 0xd2,
-0xaf, 0x90, 0x04, 0x14, 0xe0, 0xa2, 0xe4, 0x92, 0x1d, 0x74, 0x1e, 0xf0, 0xe5, 0x5f, 0x54, 0x0f,
-0xf5, 0x2d, 0xe5, 0x2a, 0x70, 0x13, 0x30, 0x1c, 0x05, 0xe5, 0x5f, 0x20, 0xe5, 0x0b, 0x30, 0x1d,
-0x29, 0xe5, 0x5f, 0x54, 0x30, 0x64, 0x30, 0x70, 0x21, 0xe5, 0x2a, 0x70, 0x15, 0xe5, 0x34, 0xc3,
-0x94, 0x03, 0x40, 0x09, 0xe5, 0x30, 0x60, 0x05, 0x75, 0x2a, 0x05, 0x80, 0x07, 0x75, 0x2a, 0x0c,
-0x80, 0x02, 0x15, 0x2a, 0xd2, 0x6c, 0xd2, 0x6d, 0x80, 0x0f, 0xe5, 0x5f, 0x30, 0xe6, 0x06, 0xc2,
-0x6c, 0xd2, 0x6d, 0x80, 0x04, 0xd2, 0x6c, 0xc2, 0x6d, 0xe5, 0x47, 0x64, 0x03, 0x70, 0x21, 0x30,
-0x4b, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x18, 0xe5, 0x2a, 0x70, 0x03, 0x30, 0x4c, 0x11, 0xc2,
-0x4c, 0xe5, 0x2a, 0x70, 0x05, 0x75, 0x2a, 0x07, 0x80, 0x02, 0x15, 0x2a, 0xd2, 0x6c, 0xd2, 0x6d,
-0xe5, 0x47, 0xb4, 0x09, 0x14, 0xe5, 0x44, 0x20, 0xe3, 0x0b, 0xe5, 0x3a, 0x64, 0x02, 0x60, 0x05,
-0xe5, 0x3a, 0xb4, 0x03, 0x04, 0xc2, 0x6c, 0xd2, 0x6d, 0xe5, 0x47, 0xb4, 0x0a, 0x13, 0xe5, 0x3a,
-0xb4, 0x01, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x08, 0xe5, 0x3a, 0x70, 0x04, 0xd2, 0x6c, 0xc2,
-0x6d, 0x20, 0x69, 0x07, 0xe5, 0x5e, 0x20, 0xe0, 0x02, 0xb2, 0x68, 0x20, 0x6b, 0x07, 0xe5, 0x5e,
-0x20, 0xe1, 0x02, 0xb2, 0x6a, 0x20, 0x6d, 0x07, 0xe5, 0x5e, 0x20, 0xe2, 0x02, 0xb2, 0x6c, 0x75,
-0x2e, 0x40, 0x20, 0x69, 0x04, 0xa2, 0x68, 0x80, 0x45, 0x30, 0x68, 0x06, 0xe5, 0x46, 0xa2, 0xe2,
-0x80, 0x3c, 0x30, 0x19, 0x1c, 0xe5, 0x5e, 0x20, 0xe2, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00,
-0xe5, 0x2f, 0xb4, 0x19, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x80,
-0x1d, 0xe5, 0x5e, 0x20, 0xe2, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0,
-0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x73,
-0x92, 0x72, 0x20, 0x6b, 0x04, 0xa2, 0x6a, 0x80, 0x45, 0x30, 0x6a, 0x06, 0xe5, 0x46, 0xa2, 0xe2,
-0x80, 0x3c, 0x30, 0x19, 0x1c, 0xe5, 0x5e, 0x20, 0xe0, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00,
-0xe5, 0x2f, 0xb4, 0x19, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x80,
-0x1d, 0xe5, 0x5e, 0x20, 0xe0, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0,
-0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x75,
-0x92, 0x74, 0x20, 0x6d, 0x04, 0xa2, 0x6c, 0x80, 0x64, 0xe5, 0x47, 0x64, 0x0a, 0x70, 0x19, 0xe5,
-0x3a, 0xb4, 0x01, 0x06, 0xe5, 0x46, 0xa2, 0xe3, 0x80, 0x53, 0xe5, 0x46, 0x20, 0xe4, 0x03, 0x30,
-0xe5, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x80, 0x45, 0x30, 0x6c, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80,
-0x3c, 0x30, 0x19, 0x1c, 0xe5, 0x5e, 0x20, 0xe1, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5,
-0x2f, 0xb4, 0x19, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x80, 0x1d,
-0xe5, 0x5e, 0x20, 0xe1, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe,
-0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x71, 0x92,
-0x70, 0x90, 0x10, 0x00, 0xe0, 0x90, 0x10, 0x2c, 0xf0, 0x90, 0x10, 0x03, 0xe0, 0xc3, 0x94, 0x30,
-0x40, 0x14, 0xa2, 0x71, 0x92, 0x77, 0xa2, 0x70, 0x92, 0x76, 0xe5, 0x2e, 0x13, 0x13, 0x54, 0x3f,
-0xf5, 0x2e, 0xc2, 0x77, 0xd2, 0x76, 0x90, 0x10, 0x2f, 0xe5, 0x2e, 0xf0, 0xe5, 0x47, 0x64, 0x06,
-0x70, 0x46, 0x90, 0x02, 0x29, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x43, 0xc4, 0x54, 0x0f, 0x14, 0x60,
-0x14, 0x24, 0xfe, 0x60, 0x1f, 0x24, 0x03, 0x60, 0x03, 0x02, 0x19, 0x5e, 0x90, 0x02, 0x28, 0xe0,
-0x30, 0x47, 0x0d, 0x80, 0x07, 0x90, 0x02, 0x28, 0xe0, 0x20, 0x47, 0x04, 0x54, 0xfe, 0xf0, 0x22,
-0x44, 0x01, 0xf0, 0x22, 0xe5, 0x46, 0x30, 0xe2, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90,
-0x02, 0x28, 0xe0, 0x54, 0xfe, 0x4f, 0xf0, 0x22, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x0f, 0xe5, 0x47,
-0x64, 0x08, 0x60, 0x09, 0xe5, 0x47, 0x64, 0x09, 0x60, 0x03, 0x02, 0x18, 0x27, 0xe4, 0xf5, 0x27,
-0x90, 0x02, 0x29, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x3a, 0x14, 0x60, 0x2d, 0x14, 0x60, 0x2e, 0x14,
-0x60, 0x36, 0x24, 0xfc, 0x60, 0x5f, 0x24, 0xf9, 0x60, 0x1f, 0x24, 0x0e, 0x70, 0x69, 0xe5, 0x46,
-0x13, 0x13, 0x54, 0x3f, 0x75, 0xf0, 0x03, 0x84, 0xaf, 0xf0, 0x20, 0x47, 0x04, 0x7e, 0x01, 0x80,
-0x02, 0x7e, 0x00, 0xef, 0x6e, 0x24, 0xff, 0x80, 0x45, 0xa2, 0x47, 0x80, 0x41, 0xe5, 0x46, 0x30,
-0xe2, 0x03, 0xd3, 0x80, 0x27, 0xc3, 0x80, 0x24, 0xe5, 0x46, 0x30, 0xe2, 0x0d, 0x54, 0x38, 0xc3,
-0x94, 0x30, 0x50, 0x06, 0x7e, 0x00, 0x7f, 0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x20, 0x47,
-0x04, 0x7d, 0x01, 0x80, 0x02, 0x7d, 0x00, 0xef, 0x6d, 0x4e, 0x24, 0xff, 0x92, 0x38, 0xa2, 0x47,
-0xb3, 0x92, 0x39, 0x80, 0x19, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x39,
-0xa2, 0x47, 0xb3, 0x92, 0x38, 0x80, 0x07, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x92, 0x39, 0x90, 0x02,
-0x28, 0xe0, 0x54, 0xfc, 0x02, 0x19, 0x5b, 0xe5, 0x47, 0x64, 0x0c, 0x60, 0x09, 0xe5, 0x47, 0x64,
-0x0b, 0x60, 0x03, 0x02, 0x18, 0xc6, 0xe4, 0xf5, 0x27, 0x90, 0x02, 0x29, 0xe0, 0x54, 0xfd, 0xf0,
-0xe5, 0x3a, 0x14, 0x60, 0x2b, 0x14, 0x60, 0x2e, 0x14, 0x60, 0x38, 0x24, 0xfc, 0x60, 0x5c, 0x24,
-0xf9, 0x60, 0x1d, 0x24, 0x0e, 0x70, 0x61, 0xe5, 0x46, 0x13, 0x13, 0x54, 0x3f, 0x75, 0xf0, 0x03,
-0x84, 0xaf, 0xf0, 0x20, 0x47, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e, 0x00, 0xef, 0x6e, 0x80, 0x35,
-0xa2, 0x47, 0x92, 0x39, 0x80, 0x47, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92,
-0x39, 0x80, 0x3a, 0xe5, 0x46, 0x30, 0xe2, 0x0d, 0x54, 0x38, 0xc3, 0x94, 0x30, 0x50, 0x06, 0x7e,
-0x00, 0x7f, 0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x20, 0x47, 0x04, 0x7d, 0x01, 0x80, 0x02,
-0x7d, 0x00, 0xef, 0x6d, 0x4e, 0x24, 0xff, 0x92, 0x39, 0x80, 0x12, 0xe5, 0x46, 0x30, 0xe2, 0x03,
-0xd3, 0x80, 0x01, 0xc3, 0x92, 0x39, 0x80, 0x05, 0xa2, 0x47, 0xb3, 0x92, 0x39, 0x90, 0x02, 0x28,
-0xe0, 0x54, 0xfd, 0x02, 0x19, 0x5b, 0xe5, 0x47, 0x64, 0x0d, 0x60, 0x03, 0x02, 0x19, 0x5e, 0xf5,
-0x27, 0x90, 0x02, 0x29, 0xe0, 0x54, 0xef, 0xf0, 0xe5, 0x3a, 0x14, 0x60, 0x2b, 0x14, 0x60, 0x2e,
-0x14, 0x60, 0x38, 0x24, 0xfc, 0x60, 0x5c, 0x24, 0xf9, 0x60, 0x1d, 0x24, 0x0e, 0x70, 0x61, 0xe5,
-0x46, 0x13, 0x13, 0x54, 0x3f, 0x75, 0xf0, 0x03, 0x84, 0xaf, 0xf0, 0x20, 0x47, 0x04, 0x7e, 0x01,
-0x80, 0x02, 0x7e, 0x00, 0xef, 0x6e, 0x80, 0x35, 0xa2, 0x47, 0x92, 0x3c, 0x80, 0x47, 0xe5, 0x46,
-0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x3c, 0x80, 0x3a, 0xe5, 0x46, 0x30, 0xe2, 0x0d,
-0x54, 0x38, 0xc3, 0x94, 0x30, 0x50, 0x06, 0x7e, 0x00, 0x7f, 0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f,
-0x00, 0x20, 0x47, 0x04, 0x7d, 0x01, 0x80, 0x02, 0x7d, 0x00, 0xef, 0x6d, 0x4e, 0x24, 0xff, 0x92,
-0x3c, 0x80, 0x12, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x3c, 0x80, 0x05,
-0xa2, 0x47, 0xb3, 0x92, 0x3c, 0x90, 0x02, 0x28, 0xe0, 0x54, 0xef, 0x45, 0x27, 0xf0, 0x22, 0xe5,
-0x47, 0x64, 0x0b, 0x70, 0x1c, 0x90, 0x02, 0x29, 0xe0, 0x54, 0xeb, 0xf0, 0x30, 0x47, 0x04, 0xaf,
-0x45, 0x80, 0x05, 0xe5, 0x45, 0x64, 0x14, 0xff, 0x90, 0x02, 0x28, 0xe0, 0x54, 0xeb, 0x4f, 0xf0,
-0x22, 0xe4, 0x90, 0x02, 0x29, 0xf0, 0x30, 0x47, 0x04, 0xaf, 0x45, 0x80, 0x04, 0xe5, 0x45, 0xf4,
-0xff, 0x90, 0x02, 0x28, 0xef, 0xf0, 0x22, 0x8f, 0x50, 0xd2, 0x59, 0x22, 0x8f, 0x54, 0xd2, 0x58,
-0x22, 0xe4, 0xf5, 0x37, 0xc2, 0xaf, 0xe5, 0x51, 0x14, 0x60, 0x4a, 0x14, 0x60, 0x6b, 0x24, 0x02,
-0x60, 0x03, 0x02, 0x1b, 0x12, 0xd2, 0x59, 0x75, 0x55, 0x01, 0x20, 0x1a, 0x1c, 0x90, 0x02, 0x08,
-0xe0, 0x54, 0xfe, 0xf0, 0xe0, 0x20, 0xe1, 0x23, 0x90, 0x04, 0x34, 0xe0, 0xb4, 0x02, 0x1c, 0xa3,
-0xe0, 0xb4, 0x02, 0x17, 0xa3, 0xe0, 0xb4, 0x02, 0x12, 0x7f, 0x20, 0x12, 0x19, 0x97, 0x90, 0x10,
-0x04, 0xe0, 0x54, 0xf3, 0xf0, 0x75, 0x51, 0x01, 0x02, 0x1b, 0x12, 0xe5, 0x50, 0x70, 0x06, 0x75,
-0x37, 0x03, 0x02, 0x1b, 0x12, 0x90, 0x12, 0x00, 0xe0, 0x54, 0x03, 0x70, 0x15, 0x7f, 0x20, 0x12,
-0x19, 0x97, 0x20, 0x1a, 0x07, 0x90, 0x02, 0x08, 0xe0, 0x54, 0xfb, 0xf0, 0x75, 0x51, 0x02, 0x02,
-0x1b, 0x12, 0xe5, 0x50, 0x70, 0x03, 0x02, 0x1b, 0x0d, 0x20, 0x1a, 0x15, 0x90, 0x02, 0x08, 0xe0,
-0x30, 0xe3, 0x03, 0x02, 0x1b, 0x09, 0x90, 0x04, 0x37, 0xe0, 0x64, 0x22, 0x60, 0x03, 0x02, 0x1b,
-0x09, 0x90, 0x12, 0x04, 0x74, 0x0a, 0xf0, 0xe5, 0x58, 0xb4, 0x72, 0x15, 0xe5, 0x59, 0xb4, 0x35,
-0x10, 0xe4, 0x90, 0x05, 0x00, 0xf0, 0xa3, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0x74, 0x03,
-0xf0, 0x7f, 0x01, 0x12, 0x03, 0x30, 0x90, 0x13, 0x28, 0xe0, 0x54, 0xf0, 0xf0, 0xa3, 0xe0, 0x54,
-0xf0, 0xf0, 0xe5, 0x59, 0xb4, 0x35, 0x14, 0xe5, 0x3c, 0xf4, 0x60, 0x06, 0xa3, 0xe0, 0x54, 0xf3,
-0x80, 0x14, 0x90, 0x13, 0x2a, 0xe0, 0x54, 0xfb, 0xf0, 0x80, 0x14, 0xe5, 0x3c, 0xf4, 0x90, 0x13,
-0x2a, 0x60, 0x08, 0xe0, 0x54, 0xf2, 0x45, 0x3c, 0xf0, 0x80, 0x04, 0xe0, 0x54, 0xfa, 0xf0, 0x20,
-0x1a, 0x07, 0x90, 0x04, 0x01, 0xe0, 0x44, 0x10, 0xf0, 0xe5, 0x34, 0xc3, 0x94, 0x03, 0x40, 0x09,
-0xe5, 0x30, 0x70, 0x05, 0x75, 0x8c, 0x40, 0x80, 0x03, 0x75, 0x8c, 0x80, 0x90, 0x04, 0x01, 0xe0,
-0x54, 0xfd, 0xf0, 0x20, 0x1a, 0x07, 0x90, 0x12, 0x04, 0xe0, 0x44, 0x04, 0xf0, 0xe5, 0x59, 0xb4,
-0x28, 0x06, 0x90, 0x01, 0x0d, 0xe0, 0xf5, 0x31, 0xe5, 0x34, 0xc3, 0x94, 0x02, 0x40, 0x14, 0x90,
-0x01, 0x0d, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x59, 0x64, 0x35, 0x60, 0x07, 0x90, 0x12, 0x04, 0xe0,
-0x54, 0xfd, 0xf0, 0xe5, 0x34, 0xc3, 0x94, 0x03, 0x40, 0x14, 0x20, 0x02, 0x11, 0x20, 0x03, 0x0e,
-0x90, 0x01, 0x0d, 0xe0, 0x54, 0xfb, 0xf0, 0x90, 0x01, 0x0c, 0xe0, 0x54, 0xfd, 0xf0, 0x75, 0x37,
-0x01, 0x75, 0x55, 0x02, 0xe4, 0xf5, 0x51, 0x80, 0x09, 0xe5, 0x50, 0x70, 0x05, 0x75, 0x37, 0x03,
-0xf5, 0x51, 0xe5, 0x37, 0x60, 0x18, 0xc2, 0x01, 0xe4, 0xf5, 0x51, 0xc2, 0x59, 0x20, 0x1a, 0x0e,
-0xad, 0x37, 0xaf, 0x40, 0x12, 0x1c, 0x1b, 0xe5, 0x37, 0xb4, 0x03, 0x02, 0xd2, 0x03, 0xd2, 0xaf,
-0x22, 0xc2, 0xaf, 0x30, 0x01, 0x0e, 0xe4, 0xf5, 0x51, 0xc2, 0x59, 0xc2, 0x01, 0x7d, 0x02, 0xaf,
-0x40, 0x12, 0x1c, 0x1b, 0xe5, 0x52, 0x14, 0x60, 0x5c, 0x14, 0x60, 0x3a, 0x24, 0x02, 0x60, 0x03,
-0x02, 0x1c, 0x18, 0xe5, 0x34, 0xc3, 0x94, 0x03, 0x40, 0x0c, 0x90, 0x01, 0x0c, 0xe0, 0x44, 0x02,
-0xf0, 0xa3, 0xe0, 0x44, 0x04, 0xf0, 0xe5, 0x34, 0xc3, 0x94, 0x02, 0x40, 0x13, 0x90, 0x12, 0x04,
-0xe0, 0x44, 0x02, 0xf0, 0x7f, 0x32, 0x12, 0x03, 0x30, 0x90, 0x01, 0x0d, 0xe0, 0x54, 0xfe, 0xf0,
-0x75, 0x52, 0x02, 0x75, 0x55, 0x03, 0xe5, 0x59, 0xb4, 0x28, 0x06, 0x90, 0x01, 0x0d, 0xe5, 0x31,
-0xf0, 0x90, 0x12, 0x04, 0xe0, 0x54, 0xfb, 0xf0, 0x7f, 0x20, 0x12, 0x19, 0x9c, 0x75, 0x52, 0x01,
-0x75, 0x55, 0x03, 0x80, 0x73, 0xe5, 0x54, 0x70, 0x6f, 0x90, 0x04, 0x01, 0xe0, 0x44, 0x0e, 0xf0,
-0x20, 0x1a, 0x04, 0xe0, 0x54, 0xef, 0xf0, 0xe4, 0xf5, 0x8c, 0x90, 0x13, 0x28, 0xe0, 0x44, 0x0f,
-0xf0, 0xa3, 0xe0, 0x44, 0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x05, 0xf0, 0x90, 0x12, 0x04, 0x74, 0x03,
-0xf0, 0xe5, 0x58, 0xb4, 0x72, 0x16, 0xe5, 0x59, 0xb4, 0x35, 0x11, 0x90, 0x05, 0x00, 0x74, 0xe2,
-0xf0, 0xa3, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0x74, 0x03, 0xf0, 0x7f, 0x01, 0x12, 0x03,
-0x30, 0x20, 0x1a, 0x07, 0x90, 0x02, 0x08, 0xe0, 0x44, 0x05, 0xf0, 0x90, 0x10, 0x04, 0xe0, 0x44,
-0x0c, 0xf0, 0xe4, 0xf5, 0x52, 0xf5, 0x55, 0x30, 0x02, 0x09, 0xc2, 0x02, 0x7d, 0x01, 0xaf, 0x41,
-0x12, 0x1c, 0x1b, 0x30, 0x03, 0x02, 0xc2, 0x03, 0xd2, 0xaf, 0x22, 0xef, 0xf4, 0x60, 0x2d, 0xe4,
-0xfe, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xe0, 0xb4, 0xff, 0x19, 0x74,
-0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xef, 0xf0, 0x74, 0x1c, 0x2e, 0xf5, 0x82,
-0xe4, 0x34, 0x70, 0xf5, 0x83, 0xed, 0xf0, 0x22, 0x0e, 0xbe, 0x04, 0xd5, 0x22, 0x22, 0x22, 0x30,
-0x1a, 0x77, 0x90, 0x04, 0x37, 0xe0, 0x20, 0xe5, 0x6c, 0x90, 0x04, 0x28, 0xe0, 0xf5, 0x38, 0xa3,
-0xe0, 0xf5, 0x37, 0xf5, 0x39, 0xe4, 0xf5, 0x25, 0xe5, 0x39, 0x75, 0xf0, 0x80, 0xa4, 0x24, 0x00,
-0xff, 0xe5, 0xf0, 0x34, 0x80, 0xfe, 0xe5, 0x37, 0x65, 0x39, 0x70, 0x05, 0xfc, 0x7d, 0x28, 0x80,
-0x04, 0x7c, 0x00, 0x7d, 0x00, 0xef, 0x2d, 0xff, 0xee, 0x3c, 0xfe, 0x12, 0x1c, 0xca, 0x50, 0x07,
-0x90, 0x01, 0x14, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x39, 0x65, 0x38, 0x60, 0x10, 0xe4, 0x25, 0x39,
-0xff, 0xe4, 0x34, 0x80, 0x8f, 0x82, 0xf5, 0x83, 0xe0, 0xf5, 0x39, 0x80, 0xbb, 0x90, 0x04, 0x10,
-0x74, 0x01, 0xf0, 0x90, 0x04, 0x28, 0xe5, 0x38, 0xf0, 0xa3, 0xe5, 0x37, 0xf0, 0x90, 0x04, 0x11,
-0x74, 0x01, 0xf0, 0x80, 0x8d, 0xc2, 0x06, 0xd2, 0x1b, 0x22, 0xe5, 0x25, 0xc3, 0x94, 0x06, 0x50,
-0x19, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xb4, 0xff, 0x07, 0x05, 0x25, 0xe4, 0xf5, 0x24, 0x80, 0x2e,
-0xe4, 0xf5, 0x25, 0x8f, 0x82, 0x8e, 0x83, 0xf0, 0x80, 0x24, 0xe5, 0x24, 0x75, 0xf0, 0x06, 0x84,
-0x74, 0x08, 0x25, 0xf0, 0xf5, 0x82, 0xe4, 0x34, 0x10, 0xf5, 0x83, 0xe0, 0xfd, 0x8f, 0x82, 0x8e,
-0x83, 0xe0, 0x6d, 0x70, 0x06, 0x05, 0x25, 0x05, 0x24, 0x80, 0x03, 0xe4, 0xf5, 0x25, 0x0f, 0xbf,
-0x00, 0x01, 0x0e, 0xef, 0x54, 0x7f, 0x60, 0x07, 0xe5, 0x25, 0xc3, 0x94, 0x2a, 0x40, 0xab, 0xe5,
-0x25, 0xb4, 0x2a, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xe3, 0x34, } ;
diff --git a/drivers/staging/rtl8187se/Kconfig b/drivers/staging/rtl8187se/Kconfig
index e24a6f7a0d85..155a78e07405 100644
--- a/drivers/staging/rtl8187se/Kconfig
+++ b/drivers/staging/rtl8187se/Kconfig
@@ -3,6 +3,7 @@ config R8187SE
depends on PCI && WLAN
select WIRELESS_EXT
select WEXT_PRIV
+ select EEPROM_93CX6
default N
---help---
If built as a module, it will be called r8187se.ko.
diff --git a/drivers/staging/rtl8187se/Makefile b/drivers/staging/rtl8187se/Makefile
index b395acf5a38e..e6adf91cdd2c 100644
--- a/drivers/staging/rtl8187se/Makefile
+++ b/drivers/staging/rtl8187se/Makefile
@@ -18,7 +18,6 @@ EXTRA_CFLAGS += -DENABLE_LPS
r8187se-objs := \
r8180_core.o \
- r8180_93cx6.o \
r8180_wx.o \
r8180_rtl8225z2.o \
r8185b_init.o \
diff --git a/drivers/staging/rtl8187se/TODO b/drivers/staging/rtl8187se/TODO
index a762e79873e9..704949a9da0d 100644
--- a/drivers/staging/rtl8187se/TODO
+++ b/drivers/staging/rtl8187se/TODO
@@ -5,7 +5,6 @@ TODO:
- switch to use shared "librtl" instead of private ieee80211 stack
- switch to use LIB80211
- switch to use MAC80211
-- switch to use EEPROM_93CX6
- use kernel coding style
- checkpatch.pl fixes
- sparse fixes
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
index 0d490c164db6..4cd95c3dc947 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
@@ -29,6 +29,7 @@
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <linux/sched.h>
+#include <linux/semaphore.h>
#include <linux/wireless.h>
#include <linux/ieee80211.h>
@@ -161,10 +162,6 @@ do { if (ieee80211_debug_level & (level)) \
#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
#endif /* CONFIG_IEEE80211_DEBUG */
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAC_ARG(x) ((u8 *)(x))[0], ((u8 *)(x))[1], ((u8 *)(x))[2], \
- ((u8 *)(x))[3], ((u8 *)(x))[4], ((u8 *)(x))[5]
-
/*
* To use the debug system;
*
@@ -482,15 +479,6 @@ struct ieee80211_header_data {
u16 seq_ctrl;
};
-struct ieee80211_hdr_3addr {
- u16 frame_ctl;
- u16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- u16 seq_ctl;
-} __attribute__ ((packed));
-
struct ieee80211_hdr_4addr {
u16 frame_ctl;
u16 duration_id;
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c
index 172e8f3ae6c1..40f1b99faad2 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c
@@ -285,7 +285,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (!(keyidx & (1 << 5))) {
if (net_ratelimit()) {
printk(KERN_DEBUG "CCMP: received packet without ExtIV"
- " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ " flag from %pM\n", hdr->addr2);
}
key->dot11RSNAStatsCCMPFormatErrors++;
return -2;
@@ -298,9 +298,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
if (!key->key_set) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT
+ printk(KERN_DEBUG "CCMP: received packet from %pM"
" with keyid=%d that does not have a configured"
- " key\n", MAC_ARG(hdr->addr2), keyidx);
+ " key\n", hdr->addr2, keyidx);
}
return -3;
}
@@ -315,11 +315,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
- " previous PN %02x%02x%02x%02x%02x%02x "
- "received PN %02x%02x%02x%02x%02x%02x\n",
- MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn),
- MAC_ARG(pn));
+ printk(KERN_DEBUG "CCMP: replay detected: STA=%pM"
+ " previous PN %pm received PN %pm\n",
+ hdr->addr2, key->rx_pn, pn);
}
key->dot11RSNAStatsCCMPReplays++;
return -4;
@@ -347,7 +345,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
if (net_ratelimit()) {
printk(KERN_DEBUG "CCMP: decrypt failed: STA="
- MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ "%pM\n", hdr->addr2);
}
key->dot11RSNAStatsCCMPDecryptErrors++;
return -5;
@@ -423,11 +421,10 @@ static char * ieee80211_ccmp_print_stats(char *p, void *priv)
{
struct ieee80211_ccmp_data *ccmp = priv;
p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
- "tx_pn=%02x%02x%02x%02x%02x%02x "
- "rx_pn=%02x%02x%02x%02x%02x%02x "
+ "tx_pn=%pm rx_pn=%pm "
"format_errors=%d replays=%d decrypt_errors=%d\n",
ccmp->key_idx, ccmp->key_set,
- MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn),
+ ccmp->tx_pn, ccmp->rx_pn,
ccmp->dot11RSNAStatsCCMPFormatErrors,
ccmp->dot11RSNAStatsCCMPReplays,
ccmp->dot11RSNAStatsCCMPDecryptErrors);
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c
index e6d8385e1d88..a5254111d9a1 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c
@@ -385,7 +385,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (!(keyidx & (1 << 5))) {
if (net_ratelimit()) {
printk(KERN_DEBUG "TKIP: received packet without ExtIV"
- " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ " flag from %pM\n", hdr->addr2);
}
return -2;
}
@@ -397,9 +397,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
if (!tkey->key_set) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT
+ printk(KERN_DEBUG "TKIP: received packet from %pM"
" with keyid=%d that does not have a configured"
- " key\n", MAC_ARG(hdr->addr2), keyidx);
+ " key\n", hdr->addr2, keyidx);
}
return -3;
}
@@ -410,9 +410,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (iv32 < tkey->rx_iv32 ||
(iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
+ printk(KERN_DEBUG "TKIP: replay detected: STA=%pM"
" previous TSC %08x%04x received TSC "
- "%08x%04x\n", MAC_ARG(hdr->addr2),
+ "%08x%04x\n", hdr->addr2,
tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
}
tkey->dot11RSNAStatsTKIPReplays++;
@@ -431,8 +431,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
if (net_ratelimit()) {
printk(KERN_DEBUG ": TKIP: failed to decrypt "
- "received packet from " MAC_FMT "\n",
- MAC_ARG(hdr->addr2));
+ "received packet from %pM\n",
+ hdr->addr2);
}
return -7;
}
@@ -450,7 +450,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
if (net_ratelimit()) {
printk(KERN_DEBUG "TKIP: ICV error detected: STA="
- MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ "%pM\n", hdr->addr2);
}
tkey->dot11RSNAStatsTKIPICVErrors++;
return -5;
@@ -604,8 +604,8 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
struct ieee80211_hdr_4addr *hdr;
hdr = (struct ieee80211_hdr_4addr *)skb->data;
printk(KERN_DEBUG "%s: Michael MIC verification failed for "
- "MSDU from " MAC_FMT " keyidx=%d\n",
- skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2),
+ "MSDU from %pM keyidx=%d\n",
+ skb->dev ? skb->dev->name : "N/A", hdr->addr2,
keyidx);
if (skb->dev)
ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
index 9128c181bc7d..2b7080cc2c05 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
@@ -311,8 +311,8 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb,
strcmp(crypt->ops->name, "TKIP") == 0) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "received packet from " MAC_FMT "\n",
- ieee->dev->name, MAC_ARG(hdr->addr2));
+ "received packet from %pM\n",
+ ieee->dev->name, hdr->addr2);
}
return -1;
}
@@ -323,8 +323,8 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb,
atomic_dec(&crypt->refcnt);
if (res < 0) {
IEEE80211_DEBUG_DROP(
- "decryption failed (SA=" MAC_FMT
- ") res=%d\n", MAC_ARG(hdr->addr2), res);
+ "decryption failed (SA=%pM"
+ ") res=%d\n", hdr->addr2, res);
if (res == -2)
IEEE80211_DEBUG_DROP("Decryption failed ICV "
"mismatch (key %d)\n",
@@ -356,8 +356,8 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct sk_buff *s
atomic_dec(&crypt->refcnt);
if (res < 0) {
printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
- " (SA=" MAC_FMT " keyidx=%d)\n",
- ieee->dev->name, MAC_ARG(hdr->addr2), keyidx);
+ " (SA=%pM keyidx=%d)\n",
+ ieee->dev->name, hdr->addr2, keyidx);
return -1;
}
@@ -550,8 +550,8 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
* frames silently instead of filling system log with
* these reports. */
IEEE80211_DEBUG_DROP("Decryption failed (not set)"
- " (SA=" MAC_FMT ")\n",
- MAC_ARG(hdr->addr2));
+ " (SA=%pM)\n",
+ hdr->addr2);
ieee->ieee_stats.rx_discards_undecryptable++;
goto rx_dropped;
}
@@ -709,8 +709,8 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
} else {
IEEE80211_DEBUG_DROP(
"encryption configured, but RX "
- "frame not encrypted (SA=" MAC_FMT ")\n",
- MAC_ARG(hdr->addr2));
+ "frame not encrypted (SA=%pM)\n",
+ hdr->addr2);
goto rx_dropped;
}
}
@@ -729,9 +729,9 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
!ieee80211_is_eapol_frame(ieee, skb, hdrlen)) {
IEEE80211_DEBUG_DROP(
"dropped unencrypted RX data "
- "frame from " MAC_FMT
+ "frame from %pM"
" (drop_unencrypted=1)\n",
- MAC_ARG(hdr->addr2));
+ hdr->addr2);
goto rx_dropped;
}
/*
@@ -1196,11 +1196,11 @@ inline int ieee80211_network_init(
}
if (network->mode == 0) {
- IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' "
+ IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' "
"network.\n",
escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid));
+ network->bssid);
return 1;
}
@@ -1341,9 +1341,9 @@ inline void ieee80211_process_probe_response(
memset(&network, 0, sizeof(struct ieee80211_network));
IEEE80211_DEBUG_SCAN(
- "'%s' (" MAC_FMT "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
+ "'%s' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
escape_essid(info_element->data, info_element->len),
- MAC_ARG(beacon->header.addr3),
+ beacon->header.addr3,
(beacon->capability & (1<<0xf)) ? '1' : '0',
(beacon->capability & (1<<0xe)) ? '1' : '0',
(beacon->capability & (1<<0xd)) ? '1' : '0',
@@ -1362,10 +1362,10 @@ inline void ieee80211_process_probe_response(
(beacon->capability & (1<<0x0)) ? '1' : '0');
if (ieee80211_network_init(ieee, beacon, &network, stats)) {
- IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n",
+ IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n",
escape_essid(info_element->data,
info_element->len),
- MAC_ARG(beacon->header.addr3),
+ beacon->header.addr3,
WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
@@ -1464,11 +1464,11 @@ inline void ieee80211_process_probe_response(
/* If there are no more slots, expire the oldest */
list_del(&oldest->list);
target = oldest;
- IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from "
+ IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from "
"network list.\n",
escape_essid(target->ssid,
target->ssid_len),
- MAC_ARG(target->bssid));
+ target->bssid);
} else {
/* Otherwise just pull from the free list */
target = list_entry(ieee->network_free_list.next,
@@ -1478,10 +1478,10 @@ inline void ieee80211_process_probe_response(
#ifdef CONFIG_IEEE80211_DEBUG
- IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n",
+ IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n",
escape_essid(network.ssid,
network.ssid_len),
- MAC_ARG(network.bssid),
+ network.bssid,
WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
@@ -1492,10 +1492,10 @@ inline void ieee80211_process_probe_response(
if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)
ieee80211_softmac_new_net(ieee,&network);
} else {
- IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n",
+ IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
escape_essid(target->ssid,
target->ssid_len),
- MAC_ARG(target->bssid),
+ target->bssid,
WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
index c7c645af0ebb..c2f472ee6eb6 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
@@ -203,7 +203,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee
enqueue_mgmt(ieee,skb);
}else{
- header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4);
+ header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0]<<4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@@ -220,7 +220,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee
spin_unlock_irqrestore(&ieee->lock, flags);
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags);
- header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+ header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@@ -246,7 +246,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i
if(single){
- header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+ header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@@ -259,7 +259,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i
}else{
- header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+ header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@@ -287,7 +287,7 @@ inline struct sk_buff *ieee80211_disassociate_skb(
return NULL;
disass = (struct ieee80211_disassoc_frame *) skb_put(skb,sizeof(struct ieee80211_disassoc_frame));
- disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
+ disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
disass->header.duration_id = 0;
memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN);
@@ -905,7 +905,7 @@ struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest)
assoc = (struct ieee80211_assoc_response_frame *)
skb_put(skb,sizeof(struct ieee80211_assoc_response_frame));
- assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP);
+ assoc->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP);
memcpy(assoc->header.addr1, dest,ETH_ALEN);
memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN);
memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
@@ -981,7 +981,7 @@ struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr)
memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN);
memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN);
- hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS |
(pwr ? IEEE80211_FCTL_PM:0));
@@ -1084,7 +1084,7 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco
skb_put(skb, sizeof(struct ieee80211_assoc_request_frame));
- hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ;
+ hdr->header.frame_control = IEEE80211_STYPE_ASSOC_REQ;
hdr->header.duration_id= 37; //FIXME
memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN);
memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
@@ -1573,7 +1573,7 @@ ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
ieee80211_resp_to_assoc_rq(ieee, dest);
}
- printk(KERN_INFO"New client associated: "MAC_FMT"\n", MAC_ARG(dest));
+ printk(KERN_INFO"New client associated: %pM\n", dest);
}
@@ -1786,11 +1786,11 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
tasklet_schedule(&ieee->ps_task);
- if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP &&
- WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON)
+ if (WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_PROBE_RESP &&
+ WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_BEACON)
ieee->last_rx_ps_time = jiffies;
- switch (WLAN_FC_GET_STYPE(header->frame_ctl)) {
+ switch (WLAN_FC_GET_STYPE(header->frame_control)) {
case IEEE80211_STYPE_ASSOC_RESP:
case IEEE80211_STYPE_REASSOC_RESP:
@@ -2064,7 +2064,7 @@ void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
header = (struct ieee80211_hdr_3addr *) skb->data;
- header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+ header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
index f1d6cb452563..ad42bcdc9374 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
@@ -482,8 +482,7 @@ int ieee80211_wx_set_power(struct ieee80211_device *ieee,
(!ieee->enter_sleep_state) ||
(!ieee->ps_is_queue_empty)){
- printk("ERROR. PS mode is tryied to be use but\
-driver missed a callback\n\n");
+ printk("ERROR. PS mode tried to be use but driver missed a callback\n\n");
return -1;
}
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
index 69bd02164b0c..6cb31e1760ac 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
@@ -198,8 +198,8 @@ int ieee80211_encrypt_fragment(
header = (struct ieee80211_hdr_4addr *)frag->data;
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "TX packet to " MAC_FMT "\n",
- ieee->dev->name, MAC_ARG(header->addr1));
+ "TX packet to %pM\n",
+ ieee->dev->name, header->addr1);
}
return -1;
}
@@ -407,7 +407,7 @@ int ieee80211_rtl_xmit(struct sk_buff *skb,
memcpy(&header.addr2, src, ETH_ALEN);
memcpy(&header.addr3, ieee->current_network.bssid, ETH_ALEN);
}
- // printk(KERN_WARNING "essid MAC address is "MAC_FMT, MAC_ARG(&header.addr1));
+ // printk(KERN_WARNING "essid MAC address is %pM", &header.addr1);
header.frame_ctl = cpu_to_le16(fc);
//hdr_len = IEEE80211_3ADDR_LEN;
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
index 6aad48fe2e18..bd5e77bf7162 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
@@ -234,10 +234,10 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
else
IEEE80211_DEBUG_SCAN(
"Not showing network '%s ("
- MAC_FMT ")' due to age (%lums).\n",
+ "%pM)' due to age (%lums).\n",
escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid),
+ network->bssid,
(jiffies - network->last_scanned) / (HZ / 100));
}
}
@@ -694,7 +694,7 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
#if 1
case IW_AUTH_WPA_ENABLED:
ieee->wpa_enabled = (data->value)?1:0;
- //printk("enalbe wpa:%d\n", ieee->wpa_enabled);
+ //printk("enable wpa:%d\n", ieee->wpa_enabled);
break;
#endif
diff --git a/drivers/staging/rtl8187se/r8180.h b/drivers/staging/rtl8187se/r8180.h
index ce828885b64f..d15bdf64efd0 100644
--- a/drivers/staging/rtl8187se/r8180.h
+++ b/drivers/staging/rtl8187se/r8180.h
@@ -366,7 +366,6 @@ typedef struct r8180_priv
short diversity;
u8 cs_treshold;
short rcr_csense;
- short rf_chip;
u32 key0[4];
short (*rf_set_sens)(struct net_device *dev,short sens);
void (*rf_set_chan)(struct net_device *dev,short ch);
@@ -479,9 +478,6 @@ typedef struct r8180_priv
u8 retry_rts;
u16 rts;
-//add for RF power on power off by lizhaoming 080512
- u8 RegThreeWireMode; // See "Three wire mode" defined above, 2006.05.31, by rcnjko.
-
//by amy for led
LED_STRATEGY_8185 LedStrategy;
//by amy for led
diff --git a/drivers/staging/rtl8187se/r8180_93cx6.c b/drivers/staging/rtl8187se/r8180_93cx6.c
deleted file mode 100644
index 7e4711fb930c..000000000000
--- a/drivers/staging/rtl8187se/r8180_93cx6.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- This files contains card eeprom (93c46 or 93c56) programming routines,
- memory is addressed by 16 bits words.
-
- This is part of rtl8180 OpenSource driver.
- Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
- Released under the terms of GPL (General Public Licence)
-
- Parts of this driver are based on the GPL part of the
- official realtek driver.
-
- Parts of this driver are based on the rtl8180 driver skeleton
- from Patric Schenke & Andres Salomon.
-
- Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
-
- We want to tanks the Authors of those projects and the Ndiswrapper
- project Authors.
-*/
-
-#include "r8180_93cx6.h"
-
-void eprom_cs(struct net_device *dev, short bit)
-{
- if(bit)
- write_nic_byte(dev, EPROM_CMD,
- (1<<EPROM_CS_SHIFT) | \
- read_nic_byte(dev, EPROM_CMD)); //enable EPROM
- else
- write_nic_byte(dev, EPROM_CMD, read_nic_byte(dev, EPROM_CMD)\
- &~(1<<EPROM_CS_SHIFT)); //disable EPROM
-
- force_pci_posting(dev);
- udelay(EPROM_DELAY);
-}
-
-
-void eprom_ck_cycle(struct net_device *dev)
-{
- write_nic_byte(dev, EPROM_CMD,
- (1<<EPROM_CK_SHIFT) | read_nic_byte(dev,EPROM_CMD));
- force_pci_posting(dev);
- udelay(EPROM_DELAY);
- write_nic_byte(dev, EPROM_CMD,
- read_nic_byte(dev, EPROM_CMD) &~ (1<<EPROM_CK_SHIFT));
- force_pci_posting(dev);
- udelay(EPROM_DELAY);
-}
-
-
-void eprom_w(struct net_device *dev,short bit)
-{
- if(bit)
- write_nic_byte(dev, EPROM_CMD, (1<<EPROM_W_SHIFT) | \
- read_nic_byte(dev,EPROM_CMD));
- else
- write_nic_byte(dev, EPROM_CMD, read_nic_byte(dev,EPROM_CMD)\
- &~(1<<EPROM_W_SHIFT));
-
- force_pci_posting(dev);
- udelay(EPROM_DELAY);
-}
-
-
-short eprom_r(struct net_device *dev)
-{
- short bit;
-
- bit=(read_nic_byte(dev, EPROM_CMD) & (1<<EPROM_R_SHIFT) );
- udelay(EPROM_DELAY);
-
- if(bit) return 1;
- return 0;
-}
-
-
-void eprom_send_bits_string(struct net_device *dev, short b[], int len)
-{
- int i;
-
- for(i=0; i<len; i++){
- eprom_w(dev, b[i]);
- eprom_ck_cycle(dev);
- }
-}
-
-
-u32 eprom_read(struct net_device *dev, u32 addr)
-{
- struct r8180_priv *priv = ieee80211_priv(dev);
- short read_cmd[]={1,1,0};
- short addr_str[8];
- int i;
- int addr_len;
- u32 ret;
-
- ret=0;
- //enable EPROM programming
- write_nic_byte(dev, EPROM_CMD,
- (EPROM_CMD_PROGRAM<<EPROM_CMD_OPERATING_MODE_SHIFT));
- force_pci_posting(dev);
- udelay(EPROM_DELAY);
-
- if (priv->epromtype==EPROM_93c56){
- addr_str[7]=addr & 1;
- addr_str[6]=addr & (1<<1);
- addr_str[5]=addr & (1<<2);
- addr_str[4]=addr & (1<<3);
- addr_str[3]=addr & (1<<4);
- addr_str[2]=addr & (1<<5);
- addr_str[1]=addr & (1<<6);
- addr_str[0]=addr & (1<<7);
- addr_len=8;
- }else{
- addr_str[5]=addr & 1;
- addr_str[4]=addr & (1<<1);
- addr_str[3]=addr & (1<<2);
- addr_str[2]=addr & (1<<3);
- addr_str[1]=addr & (1<<4);
- addr_str[0]=addr & (1<<5);
- addr_len=6;
- }
- eprom_cs(dev, 1);
- eprom_ck_cycle(dev);
- eprom_send_bits_string(dev, read_cmd, 3);
- eprom_send_bits_string(dev, addr_str, addr_len);
-
- //keep chip pin D to low state while reading.
- //I'm unsure if it is necessary, but anyway shouldn't hurt
- eprom_w(dev, 0);
-
- for(i=0;i<16;i++){
- //eeprom needs a clk cycle between writing opcode&adr
- //and reading data. (eeprom outs a dummy 0)
- eprom_ck_cycle(dev);
- ret |= (eprom_r(dev)<<(15-i));
- }
-
- eprom_cs(dev, 0);
- eprom_ck_cycle(dev);
-
- //disable EPROM programming
- write_nic_byte(dev, EPROM_CMD,
- (EPROM_CMD_NORMAL<<EPROM_CMD_OPERATING_MODE_SHIFT));
- return ret;
-}
diff --git a/drivers/staging/rtl8187se/r8180_93cx6.h b/drivers/staging/rtl8187se/r8180_93cx6.h
index 36ae100f3f16..79e7391ac881 100644
--- a/drivers/staging/rtl8187se/r8180_93cx6.h
+++ b/drivers/staging/rtl8187se/r8180_93cx6.h
@@ -45,13 +45,10 @@
#define EPROM_TXPW_OFDM_CH1_2 0x20
-//#define EPROM_TXPW_CH1_2 0x10
-#define EPROM_TXPW_CH1_2 0x30
-#define EPROM_TXPW_CH3_4 0x11
-#define EPROM_TXPW_CH5_6 0x12
-#define EPROM_TXPW_CH7_8 0x13
-#define EPROM_TXPW_CH9_10 0x14
-#define EPROM_TXPW_CH11_12 0x15
-#define EPROM_TXPW_CH13_14 0x16
-
-u32 eprom_read(struct net_device *dev,u32 addr); //reads a 16 bits word
+#define EPROM_TXPW_CH1_2 0x30
+
+#define RTL818X_EEPROM_CMD_READ (1 << 0)
+#define RTL818X_EEPROM_CMD_WRITE (1 << 1)
+#define RTL818X_EEPROM_CMD_CK (1 << 2)
+#define RTL818X_EEPROM_CMD_CS (1 << 3)
+
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index e0f13efdb15a..b1757acabedc 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -31,6 +31,7 @@
#undef DUMMY_RX
#include <linux/syscalls.h>
+#include <linux/eeprom_93cx6.h>
#include "r8180_hw.h"
#include "r8180.h"
@@ -41,13 +42,6 @@
#include "ieee80211/dot11d.h"
-#ifndef PCI_VENDOR_ID_BELKIN
- #define PCI_VENDOR_ID_BELKIN 0x1799
-#endif
-#ifndef PCI_VENDOR_ID_DLINK
- #define PCI_VENDOR_ID_DLINK 0x1186
-#endif
-
static struct pci_device_id rtl8180_pci_id_tbl[] __devinitdata = {
{
.vendor = PCI_VENDOR_ID_REALTEK,
@@ -669,11 +663,8 @@ unsigned char STRENGTH_MAP[] = {
void rtl8180_RSSI_calc(struct net_device *dev, u8 *rssi, u8 *qual)
{
- struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
u32 temp;
u32 temp2;
- u32 temp3;
- u32 lsb;
u32 q;
u32 orig_qual;
u8 _rssi;
@@ -695,88 +686,6 @@ void rtl8180_RSSI_calc(struct net_device *dev, u8 *rssi, u8 *qual)
*qual = temp;
temp2 = *rssi;
- switch(priv->rf_chip){
- case RFCHIPID_RFMD:
- lsb = temp2 & 1;
- temp2 &= 0x7e;
- if ( !lsb || !(temp2 <= 0x3c) ) {
- temp2 = 0x64;
- } else {
- temp2 = 100 * temp2 / 0x3c;
- }
- *rssi = temp2 & 0xff;
- _rssi = temp2 & 0xff;
- break;
- case RFCHIPID_INTERSIL:
- lsb = temp2;
- temp2 &= 0xfffffffe;
- temp2 *= 251;
- temp3 = temp2;
- temp2 <<= 6;
- temp3 += temp2;
- temp3 <<= 1;
- temp2 = 0x4950df;
- temp2 -= temp3;
- lsb &= 1;
- if ( temp2 <= 0x3e0000 ) {
- if ( temp2 < 0xffef0000 )
- temp2 = 0xffef0000;
- } else {
- temp2 = 0x3e0000;
- }
- if ( !lsb ) {
- temp2 -= 0xf0000;
- } else {
- temp2 += 0xf0000;
- }
-
- temp3 = 0x4d0000;
- temp3 -= temp2;
- temp3 *= 100;
- temp3 = temp3 / 0x6d;
- temp3 >>= 0x10;
- _rssi = temp3 & 0xff;
- *rssi = temp3 & 0xff;
- break;
- case RFCHIPID_GCT:
- lsb = temp2 & 1;
- temp2 &= 0x7e;
- if ( ! lsb || !(temp2 <= 0x3c) ){
- temp2 = 0x64;
- } else {
- temp2 = (100 * temp2) / 0x3c;
- }
- *rssi = temp2 & 0xff;
- _rssi = temp2 & 0xff;
- break;
- case RFCHIPID_PHILIPS:
- if( orig_qual <= 0x4e ){
- _rssi = STRENGTH_MAP[orig_qual];
- *rssi = _rssi;
- } else {
- orig_qual -= 0x80;
- if ( !orig_qual ){
- _rssi = 1;
- *rssi = 1;
- } else {
- _rssi = 0x32;
- *rssi = 0x32;
- }
- }
- break;
- case RFCHIPID_MAXIM:
- lsb = temp2 & 1;
- temp2 &= 0x7e;
- temp2 >>= 1;
- temp2 += 0x42;
- if( lsb != 0 ){
- temp2 += 0xa;
- }
- *rssi = temp2 & 0xff;
- _rssi = temp2 & 0xff;
- break;
- }
-
if ( _rssi < 0x64 ){
if ( _rssi == 0 ) {
*rssi = 1;
@@ -1421,11 +1330,9 @@ u16 N_DBPSOfRate(u16 DataRate)
return N_DBPS;
}
-//{by amy 080312
//
// Description:
// For Netgear case, they want good-looking singal strength.
-// 2004.12.05, by rcnjko.
//
long NetgearSignalStrengthTranslate(long LastSS, long CurrSS)
{
@@ -1481,7 +1388,6 @@ long TranslateToDbm8185(u8 SignalStrengthIndex)
// This is different with PerformSignalSmoothing8185 in smoothing fomula.
// No dramatic adjustion is apply because dynamic mechanism need some degree
// of correctness. Ported from 8187B.
-// 2007-02-26, by Bruce.
//
void PerformUndecoratedSignalSmoothing8185(struct r8180_priv *priv,
bool bCckRate)
@@ -1502,7 +1408,6 @@ void PerformUndecoratedSignalSmoothing8185(struct r8180_priv *priv,
priv->CurCCKRSSI = 0;
}
-//by amy 080312}
/* This is rough RX isr handling routine*/
void rtl8180_rx(struct net_device *dev)
@@ -1638,7 +1543,7 @@ void rtl8180_rx(struct net_device *dev)
}
signal=(unsigned char)(((*(priv->rxringtail+3))& (0x00ff0000))>>16);
- signal=(signal&0xfe)>>1; // Modify by hikaru 6.6
+ signal = (signal & 0xfe) >> 1;
quality=(unsigned char)((*(priv->rxringtail+3)) & (0xff));
@@ -1652,7 +1557,6 @@ void rtl8180_rx(struct net_device *dev)
stats.rate = rtl8180_rate2rate(rate);
Antenna = (((*(priv->rxringtail +3))& (0x00008000)) == 0 )? 0:1 ;
-//by amy for antenna
if(!rtl8180_IsWirelessBMode(stats.rate))
{ // OFDM rate.
@@ -1691,11 +1595,10 @@ void rtl8180_rx(struct net_device *dev)
RXAGC=(95-RXAGC)*100/65;
}
priv->SignalStrength = (u8)RXAGC;
- priv->RecvSignalPower = RxAGC_dBm ; // It can use directly by SD3 CMLin
+ priv->RecvSignalPower = RxAGC_dBm;
priv->RxPower = rxpower;
priv->RSSI = RSSI;
-//{by amy 080312
- // SQ translation formular is provided by SD3 DZ. 2006.06.27, by rcnjko.
+ /* SQ translation formula is provided by SD3 DZ. 2006.06.27 */
if(quality >= 127)
quality = 1;//0; //0 will cause epc to show signal zero , walk aroud now;
else if(quality < 27)
@@ -1712,7 +1615,6 @@ void rtl8180_rx(struct net_device *dev)
// printk("==========================>rx : RXAGC is %d,signalstrength is %d\n",RXAGC,stats.signalstrength);
stats.rssi = priv->wstats.qual.qual = priv->SignalQuality;
stats.noise = priv->wstats.qual.noise = 100 - priv ->wstats.qual.qual;
-//by amy 080312}
bHwError = (((*(priv->rxringtail))& (0x00000fff)) == 4080)| (((*(priv->rxringtail))& (0x04000000)) != 0 )
| (((*(priv->rxringtail))& (0x08000000)) != 0 )| (((~(*(priv->rxringtail)))& (0x10000000)) != 0 )| (((~(*(priv->rxringtail)))& (0x20000000)) != 0 );
bCRC = ((*(priv->rxringtail)) & (0x00002000)) >> 13;
@@ -1725,11 +1627,12 @@ void rtl8180_rx(struct net_device *dev)
(eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS)? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS )? hdr->addr2 : hdr->addr3))
&& (!bHwError) && (!bCRC)&& (!bICV))
{
-//by amy 080312
- // Perform signal smoothing for dynamic mechanism on demand.
- // This is different with PerformSignalSmoothing8185 in smoothing fomula.
- // No dramatic adjustion is apply because dynamic mechanism need some degree
- // of correctness. 2007.01.23, by shien chang.
+ /* Perform signal smoothing for dynamic
+ * mechanism on demand. This is different
+ * with PerformSignalSmoothing8185 in smoothing
+ * fomula. No dramatic adjustion is apply
+ * because dynamic mechanism need some degree
+ * of correctness. */
PerformUndecoratedSignalSmoothing8185(priv,bCckRate);
//
// For good-looking singal strength.
@@ -1749,12 +1652,9 @@ void rtl8180_rx(struct net_device *dev)
// Figure out which antenna that received the lasted packet.
priv->LastRxPktAntenna = Antenna ? 1 : 0; // 0: aux, 1: main.
-//by amy 080312
SwAntennaDiversityRxOk8185(dev, priv->SignalStrength);
}
-//by amy for antenna
-#ifndef DUMMY_RX
if(first){
if(!priv->rx_skb_complete){
/* seems that HW sometimes fails to reiceve and
@@ -1810,19 +1710,12 @@ void rtl8180_rx(struct net_device *dev)
if(last && !priv->rx_skb_complete){
if(priv->rx_skb->len > 4)
skb_trim(priv->rx_skb,priv->rx_skb->len-4);
-#ifndef RX_DONT_PASS_UL
if(!ieee80211_rtl_rx(priv->ieee80211,
- priv->rx_skb, &stats)){
-#endif // RX_DONT_PASS_UL
-
+ priv->rx_skb, &stats))
dev_kfree_skb_any(priv->rx_skb);
-#ifndef RX_DONT_PASS_UL
- }
-#endif
priv->rx_skb_complete=1;
}
-#endif //DUMMY_RX
pci_dma_sync_single_for_device(priv->pdev,
priv->rxbuffer->dma,
priv->rxbuffersize * \
@@ -1890,7 +1783,7 @@ rate)
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
int mode;
struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data;
- short morefrag = (h->frame_ctl) & IEEE80211_FCTL_MOREFRAGS;
+ short morefrag = (h->frame_control) & IEEE80211_FCTL_MOREFRAGS;
unsigned long flags;
int priority;
@@ -2056,7 +1949,7 @@ short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority,
u16 RtsDur = 0;
u16 ThisFrameTime = 0;
u16 TxDescDuration = 0;
- u8 ownbit_flag = false; //added by david woo for sync Tx, 2007.12.14
+ u8 ownbit_flag = false;
switch(priority) {
case MANAGE_PRIORITY:
@@ -2123,7 +2016,8 @@ short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority,
//YJ,add,080828,for Keep alive
priv->NumTxUnicast++;
- // Figure out ACK rate according to BSS basic rate and Tx rate, 2006.03.08 by rcnjko.
+ /* Figure out ACK rate according to BSS basic rate
+ * and Tx rate. */
AckTime = ComputeTxTime(14, 10,0, 0); // AckCTSLng = 14 use 1M bps send
if ( ((len + sCrcLng) > priv->rts) && priv->rts )
@@ -2158,7 +2052,7 @@ short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority,
TxDescDuration = ThisFrameTime + aSifsTime + AckTime;
}
- if(!(frag_hdr->frame_ctl & IEEE80211_FCTL_MOREFRAGS)) { //no more fragment
+ if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) {
// ThisFrame-ACK.
Duration = aSifsTime + AckTime;
} else { // One or more fragments remained.
@@ -2206,7 +2100,7 @@ short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority,
*tail |= (1<<15); /* no encrypt */
if(remain==len && !descfrag) {
- ownbit_flag = false; //added by david woo,2007.12.14
+ ownbit_flag = false;
*tail = *tail| (1<<29) ; //fist segment of the packet
*tail = *tail |(len);
} else {
@@ -2556,27 +2450,16 @@ void watch_dog_adaptive(unsigned long data)
}
// Tx High Power Mechanism.
-#ifdef HIGH_POWER
if(CheckHighPower((struct net_device *)data))
- {
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->tx_pw_wq);
- }
-#endif
// Tx Power Tracking on 87SE.
-#ifdef TX_TRACK
- //if( priv->bTxPowerTrack ) //lzm mod 080826
- if( CheckTxPwrTracking((struct net_device *)data));
+ if (CheckTxPwrTracking((struct net_device *)data))
TxPwrTracking87SE((struct net_device *)data);
-#endif
// Perform DIG immediately.
-#ifdef SW_DIG
if(CheckDig((struct net_device *)data) == true)
- {
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_dig_wq);
- }
-#endif
rtl8180_watch_dog((struct net_device *)data);
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->GPIOChangeRFWorkItem);
@@ -2675,6 +2558,36 @@ static void rtl8180_link_detect_init(plink_detect_t plink_detect)
}
//YJ,add,080828,end
+static void rtl8187se_eeprom_register_read(struct eeprom_93cx6 *eeprom)
+{
+ struct net_device *dev = eeprom->data;
+ u8 reg = read_nic_byte(dev, EPROM_CMD);
+
+ eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE;
+ eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ;
+ eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK;
+ eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS;
+}
+
+static void rtl8187se_eeprom_register_write(struct eeprom_93cx6 *eeprom)
+{
+ struct net_device *dev = eeprom->data;
+ u8 reg = 2 << 6;
+
+ if (eeprom->reg_data_in)
+ reg |= RTL818X_EEPROM_CMD_WRITE;
+ if (eeprom->reg_data_out)
+ reg |= RTL818X_EEPROM_CMD_READ;
+ if (eeprom->reg_data_clock)
+ reg |= RTL818X_EEPROM_CMD_CK;
+ if (eeprom->reg_chip_select)
+ reg |= RTL818X_EEPROM_CMD_CS;
+
+ write_nic_byte(dev, EPROM_CMD, reg);
+ read_nic_byte(dev, EPROM_CMD);
+ udelay(10);
+}
+
short rtl8180_init(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
@@ -2683,8 +2596,16 @@ short rtl8180_init(struct net_device *dev)
u32 usValue;
u16 tmpu16;
int i, j;
+ struct eeprom_93cx6 eeprom;
+ u16 eeprom_val;
+
+ eeprom.data = dev;
+ eeprom.register_read = rtl8187se_eeprom_register_read;
+ eeprom.register_write = rtl8187se_eeprom_register_write;
+ eeprom.width = PCI_EEPROM_WIDTH_93C46;
- priv->channel_plan = eprom_read(dev, EEPROM_COUNTRY_CODE>>1) & 0xFF;
+ eeprom_93cx6_read(&eeprom, EEPROM_COUNTRY_CODE>>1, &eeprom_val);
+ priv->channel_plan = eeprom_val & 0xFF;
if(priv->channel_plan > COUNTRY_CODE_GLOBAL_DOMAIN){
printk("rtl8180_init:Error channel plan! Set to default.\n");
priv->channel_plan = 0;
@@ -2701,8 +2622,6 @@ short rtl8180_init(struct net_device *dev)
priv->txbeaconcount = 2;
priv->rx_skb_complete = 1;
- priv->RegThreeWireMode = HW_THREE_WIRE_SI;
-
priv->RFChangeInProgress = false;
priv->SetRFPowerStateInProgress = false;
priv->RFProgType = 0;
@@ -2747,10 +2666,8 @@ short rtl8180_init(struct net_device *dev)
priv->TxPollingTimes = 0;//lzm add 080826
priv->bLeisurePs = true;
priv->dot11PowerSaveMode = eActive;
-//by amy for antenna
priv->AdMinCheckPeriod = 5;
priv->AdMaxCheckPeriod = 10;
-// Lower signal strength threshold to fit the HW participation in antenna diversity. +by amy 080312
priv->AdMaxRxSsThreshold = 30;//60->30
priv->AdRxSsThreshold = 20;//50->20
priv->AdCheckPeriod = priv->AdMinCheckPeriod;
@@ -2765,8 +2682,6 @@ short rtl8180_init(struct net_device *dev)
init_timer(&priv->SwAntennaDiversityTimer);
priv->SwAntennaDiversityTimer.data = (unsigned long)dev;
priv->SwAntennaDiversityTimer.function = (void *)SwAntennaDiversityTimerCallback;
-//by amy for antenna
-//{by amy 080312
priv->bDigMechanism = 1;
priv->InitialGain = 6;
priv->bXtalCalibration = false;
@@ -2803,58 +2718,63 @@ short rtl8180_init(struct net_device *dev)
priv->NumTxUnicast = 0;
priv->keepAliveLevel = DEFAULT_KEEP_ALIVE_LEVEL;
priv->PowerProfile = POWER_PROFILE_AC;
- priv->CurrRetryCnt=0;
- priv->LastRetryCnt=0;
- priv->LastTxokCnt=0;
- priv->LastRxokCnt=0;
- priv->LastRetryRate=0;
- priv->bTryuping=0;
- priv->CurrTxRate=0;
- priv->CurrRetryRate=0;
- priv->TryupingCount=0;
- priv->TryupingCountNoData=0;
- priv->TryDownCountLowData=0;
- priv->LastTxOKBytes=0;
- priv->LastFailTxRate=0;
- priv->LastFailTxRateSS=0;
- priv->FailTxRateCount=0;
- priv->LastTxThroughput=0;
- priv->NumTxOkBytesTotal=0;
+ priv->CurrRetryCnt = 0;
+ priv->LastRetryCnt = 0;
+ priv->LastTxokCnt = 0;
+ priv->LastRxokCnt = 0;
+ priv->LastRetryRate = 0;
+ priv->bTryuping = 0;
+ priv->CurrTxRate = 0;
+ priv->CurrRetryRate = 0;
+ priv->TryupingCount = 0;
+ priv->TryupingCountNoData = 0;
+ priv->TryDownCountLowData = 0;
+ priv->LastTxOKBytes = 0;
+ priv->LastFailTxRate = 0;
+ priv->LastFailTxRateSS = 0;
+ priv->FailTxRateCount = 0;
+ priv->LastTxThroughput = 0;
+ priv->NumTxOkBytesTotal = 0;
priv->ForcedDataRate = 0;
priv->RegBModeGainStage = 1;
- priv->promisc = (dev->flags & IFF_PROMISC) ? 1:0;
+ priv->promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
spin_lock_init(&priv->irq_lock);
spin_lock_init(&priv->irq_th_lock);
spin_lock_init(&priv->tx_lock);
spin_lock_init(&priv->ps_lock);
spin_lock_init(&priv->rf_ps_lock);
- sema_init(&priv->wx_sem,1);
- sema_init(&priv->rf_state,1);
- INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart_wq);
- INIT_WORK(&priv->tx_irq_wq,(void*) rtl8180_tx_irq_wq);
- INIT_DELAYED_WORK(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8180_hw_wakeup_wq);
- INIT_DELAYED_WORK(&priv->ieee80211->hw_sleep_wq,(void*) rtl8180_hw_sleep_wq);
- INIT_WORK(&priv->ieee80211->wmm_param_update_wq,(void*) rtl8180_wmm_param_update);
- INIT_DELAYED_WORK(&priv->ieee80211->rate_adapter_wq,(void*)rtl8180_rate_adapter);//+by amy 080312
- INIT_DELAYED_WORK(&priv->ieee80211->hw_dig_wq,(void*)rtl8180_hw_dig_wq);//+by amy 080312
- INIT_DELAYED_WORK(&priv->ieee80211->tx_pw_wq,(void*)rtl8180_tx_pw_wq);//+by amy 080312
-
- INIT_DELAYED_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,(void*) GPIOChangeRFWorkItemCallBack);
-
+ sema_init(&priv->wx_sem, 1);
+ sema_init(&priv->rf_state, 1);
+ INIT_WORK(&priv->reset_wq, (void *)rtl8180_restart_wq);
+ INIT_WORK(&priv->tx_irq_wq, (void *)rtl8180_tx_irq_wq);
+ INIT_DELAYED_WORK(&priv->ieee80211->hw_wakeup_wq,
+ (void *)rtl8180_hw_wakeup_wq);
+ INIT_DELAYED_WORK(&priv->ieee80211->hw_sleep_wq,
+ (void *)rtl8180_hw_sleep_wq);
+ INIT_WORK(&priv->ieee80211->wmm_param_update_wq,
+ (void *)rtl8180_wmm_param_update);
+ INIT_DELAYED_WORK(&priv->ieee80211->rate_adapter_wq,
+ (void *)rtl8180_rate_adapter);
+ INIT_DELAYED_WORK(&priv->ieee80211->hw_dig_wq,
+ (void *)rtl8180_hw_dig_wq);
+ INIT_DELAYED_WORK(&priv->ieee80211->tx_pw_wq,
+ (void *)rtl8180_tx_pw_wq);
+ INIT_DELAYED_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,
+ (void *) GPIOChangeRFWorkItemCallBack);
tasklet_init(&priv->irq_rx_tasklet,
(void(*)(unsigned long)) rtl8180_irq_rx_tasklet,
(unsigned long)priv);
- init_timer(&priv->watch_dog_timer);
+ init_timer(&priv->watch_dog_timer);
priv->watch_dog_timer.data = (unsigned long)dev;
priv->watch_dog_timer.function = watch_dog_adaptive;
- init_timer(&priv->rateadapter_timer);
- priv->rateadapter_timer.data = (unsigned long)dev;
- priv->rateadapter_timer.function = timer_rate_adaptive;
- priv->RateAdaptivePeriod= RATE_ADAPTIVE_TIMER_PERIOD;
- priv->bEnhanceTxPwr=false;
+ init_timer(&priv->rateadapter_timer);
+ priv->rateadapter_timer.data = (unsigned long)dev;
+ priv->rateadapter_timer.function = timer_rate_adaptive;
+ priv->RateAdaptivePeriod = RATE_ADAPTIVE_TIMER_PERIOD;
+ priv->bEnhanceTxPwr = false;
priv->ieee80211->softmac_hard_start_xmit = rtl8180_hard_start_xmit;
priv->ieee80211->set_chan = rtl8180_set_chan;
@@ -2877,30 +2797,28 @@ short rtl8180_init(struct net_device *dev)
priv->CSMethod = (0x01 << 29);
- priv->TransmitConfig =
- 1<<TCR_DurProcMode_OFFSET | //for RTL8185B, duration setting by HW
- (7<<TCR_MXDMA_OFFSET) | // Max DMA Burst Size per Tx DMA Burst, 7: reservied.
- (priv->ShortRetryLimit<<TCR_SRL_OFFSET) | // Short retry limit
- (priv->LongRetryLimit<<TCR_LRL_OFFSET) | // Long retry limit
- (0 ? TCR_SAT : 0); // FALSE: HW provies PLCP length and LENGEXT, TURE: SW proiveds them
-
- priv->ReceiveConfig =
- RCR_AMF | RCR_ADF | //accept management/data
- RCR_ACF | //accept control frame for SW AP needs PS-poll, 2005.07.07, by rcnjko.
- RCR_AB | RCR_AM | RCR_APM | //accept BC/MC/UC
- (7<<RCR_MXDMA_OFFSET) | // Max DMA Burst Size per Rx DMA Burst, 7: unlimited.
- (priv->EarlyRxThreshold<<RCR_FIFO_OFFSET) | // Rx FIFO Threshold, 7: No Rx threshold.
- (priv->EarlyRxThreshold == 7 ? RCR_ONLYERLPKT:0);
+ priv->TransmitConfig = TCR_DurProcMode_OFFSET |
+ (7<<TCR_MXDMA_OFFSET) |
+ (priv->ShortRetryLimit<<TCR_SRL_OFFSET) |
+ (priv->LongRetryLimit<<TCR_LRL_OFFSET) |
+ (0 ? TCR_SAT : 0);
+
+ priv->ReceiveConfig = RCR_AMF | RCR_ADF | RCR_ACF |
+ RCR_AB | RCR_AM | RCR_APM |
+ (7<<RCR_MXDMA_OFFSET) |
+ (priv->EarlyRxThreshold<<RCR_FIFO_OFFSET) |
+ (priv->EarlyRxThreshold == 7 ?
+ RCR_ONLYERLPKT : 0);
priv->IntrMask = IMR_TMGDOK | IMR_TBDER | IMR_THPDER |
- IMR_THPDER | IMR_THPDOK |
- IMR_TVODER | IMR_TVODOK |
- IMR_TVIDER | IMR_TVIDOK |
- IMR_TBEDER | IMR_TBEDOK |
- IMR_TBKDER | IMR_TBKDOK |
- IMR_RDU | // To handle the defragmentation not enough Rx descriptors case. Annie, 2006-03-27.
- IMR_RER | IMR_ROK |
- IMR_RQoSOK; // <NOTE> ROK and RQoSOK are mutually exclusive, so, we must handle RQoSOK interrupt to receive QoS frames, 2005.12.09, by rcnjko.
+ IMR_THPDER | IMR_THPDOK |
+ IMR_TVODER | IMR_TVODOK |
+ IMR_TVIDER | IMR_TVIDOK |
+ IMR_TBEDER | IMR_TBEDOK |
+ IMR_TBKDER | IMR_TBKDOK |
+ IMR_RDU |
+ IMR_RER | IMR_ROK |
+ IMR_RQoSOK;
priv->InitialGain = 6;
@@ -2913,7 +2831,8 @@ short rtl8180_init(struct net_device *dev)
// just for sync 85
priv->enable_gpio0 = 0;
- usValue = eprom_read(dev, EEPROM_SW_REVD_OFFSET);
+ eeprom_93cx6_read(&eeprom, EEPROM_SW_REVD_OFFSET, &eeprom_val);
+ usValue = eeprom_val;
DMESG("usValue is 0x%x\n",usValue);
//3Read AntennaDiversity
@@ -2953,54 +2872,46 @@ short rtl8180_init(struct net_device *dev)
else
priv->epromtype=EPROM_93c46;
- dev->dev_addr[0]=eprom_read(dev,MAC_ADR) & 0xff;
- dev->dev_addr[1]=(eprom_read(dev,MAC_ADR) & 0xff00)>>8;
- dev->dev_addr[2]=eprom_read(dev,MAC_ADR+1) & 0xff;
- dev->dev_addr[3]=(eprom_read(dev,MAC_ADR+1) & 0xff00)>>8;
- dev->dev_addr[4]=eprom_read(dev,MAC_ADR+2) & 0xff;
- dev->dev_addr[5]=(eprom_read(dev,MAC_ADR+2) & 0xff00)>>8;
+ eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)
+ dev->dev_addr, 3);
for(i=1,j=0; i<14; i+=2,j++){
- word = eprom_read(dev,EPROM_TXPW_CH1_2 + j);
+ eeprom_93cx6_read(&eeprom, EPROM_TXPW_CH1_2 + j, &word);
priv->chtxpwr[i]=word & 0xff;
priv->chtxpwr[i+1]=(word & 0xff00)>>8;
}
for (i = 1, j = 0; i < 14; i += 2, j++) {
- word = eprom_read(dev, EPROM_TXPW_OFDM_CH1_2 + j);
+ eeprom_93cx6_read(&eeprom, EPROM_TXPW_OFDM_CH1_2 + j, &word);
priv->chtxpwr_ofdm[i] = word & 0xff;
- priv->chtxpwr_ofdm[i+1] = (word & 0xff00)>>8;
+ priv->chtxpwr_ofdm[i+1] = (word & 0xff00) >> 8;
}
- //3Read crystal calibtration and thermal meter indication on 87SE.
-
- // By SD3 SY's request. Added by Roger, 2007.12.11.
+ /* 3Read crystal calibtration and thermal meter indication on 87SE. */
+ eeprom_93cx6_read(&eeprom, EEPROM_RSV>>1, &tmpu16);
- tmpu16 = eprom_read(dev, EEPROM_RSV>>1);
+ /* Crystal calibration for Xin and Xout resp. */
+ priv->XtalCal_Xout = tmpu16 & EEPROM_XTAL_CAL_XOUT_MASK;
+ priv->XtalCal_Xin = (tmpu16 & EEPROM_XTAL_CAL_XIN_MASK) >> 4;
+ if ((tmpu16 & EEPROM_XTAL_CAL_ENABLE) >> 12)
+ priv->bXtalCalibration = true;
- // Crystal calibration for Xin and Xout resp.
- priv->XtalCal_Xout = tmpu16 & EEPROM_XTAL_CAL_XOUT_MASK; // 0~7.5pF
- priv->XtalCal_Xin = (tmpu16 & EEPROM_XTAL_CAL_XIN_MASK)>>4; // 0~7.5pF
- if((tmpu16 & EEPROM_XTAL_CAL_ENABLE)>>12)
- priv->bXtalCalibration = true;
+ /* Thermal meter reference indication. */
+ priv->ThermalMeter = (u8)((tmpu16 & EEPROM_THERMAL_METER_MASK) >> 8);
+ if ((tmpu16 & EEPROM_THERMAL_METER_ENABLE) >> 13)
+ priv->bTxPowerTrack = true;
- // Thermal meter reference indication.
- priv->ThermalMeter = (u8)((tmpu16 & EEPROM_THERMAL_METER_MASK)>>8);
- if((tmpu16 & EEPROM_THERMAL_METER_ENABLE)>>13)
- priv->bTxPowerTrack = true;
-
- word = eprom_read(dev,EPROM_TXPW_BASE);
+ eeprom_93cx6_read(&eeprom, EPROM_TXPW_BASE, &word);
priv->cck_txpwr_base = word & 0xf;
priv->ofdm_txpwr_base = (word>>4) & 0xf;
- version = eprom_read(dev,EPROM_VERSION);
+ eeprom_93cx6_read(&eeprom, EPROM_VERSION, &version);
DMESG("EEPROM version %x",version);
priv->rcr_csense = 3;
- priv->cs_treshold = (eprom_read(dev, ENERGY_TRESHOLD) & 0xff00) >> 8;
-
- priv->rf_chip = 0xff & eprom_read(dev, RFCHIPID);
+ eeprom_93cx6_read(&eeprom, ENERGY_TRESHOLD, &eeprom_val);
+ priv->cs_treshold = (eeprom_val & 0xff00) >> 8;
- priv->rf_chip = RF_ZEBRA4;
+ eeprom_93cx6_read(&eeprom, RFCHIPID, &eeprom_val);
priv->rf_sleep = rtl8225z4_rf_sleep;
priv->rf_wakeup = rtl8225z4_rf_wakeup;
DMESGW("**PLEASE** REPORT SUCCESSFUL/UNSUCCESSFUL TO Realtek!");
@@ -3010,7 +2921,6 @@ short rtl8180_init(struct net_device *dev)
priv->rf_set_chan = rtl8225z2_rf_set_chan;
priv->rf_set_sens = NULL;
-
if (0!=alloc_rx_desc_ring(dev, priv->rxbuffersize, priv->rxringcount))
return -ENOMEM;
@@ -3042,11 +2952,7 @@ short rtl8180_init(struct net_device *dev)
TX_BEACON_RING_ADDR))
return -ENOMEM;
-#if !defined(SA_SHIRQ)
if(request_irq(dev->irq, (void *)rtl8180_interrupt, IRQF_SHARED, dev->name, dev)){
-#else
- if(request_irq(dev->irq, (void *)rtl8180_interrupt, SA_SHIRQ, dev->name, dev)){
-#endif
DMESGE("Error allocating IRQ %d",dev->irq);
return -1;
}else{
@@ -3169,43 +3075,6 @@ void write_phy_cck (struct net_device *dev, u8 adr, u32 data)
rtl8185_write_phy(dev, adr, data | 0x10000);
}
-/* 70*3 = 210 ms
- * I hope this is enougth
- */
-#define MAX_PHY 70
-void write_phy(struct net_device *dev, u8 adr, u8 data)
-{
- u32 phy;
- int i;
-
- phy = 0xff0000;
- phy |= adr;
- phy |= 0x80; /* this should enable writing */
- phy |= (data<<8);
-
- //PHY_ADR, PHY_R and PHY_W are contig and treated as one dword
- write_nic_dword(dev,PHY_ADR, phy);
-
- phy= 0xffff00;
- phy |= adr;
-
- write_nic_dword(dev,PHY_ADR, phy);
- for(i=0;i<MAX_PHY;i++){
- phy=read_nic_dword(dev,PHY_ADR);
- phy= phy & 0xff0000;
- phy= phy >> 16;
- if(phy == data){ //SUCCESS!
- force_pci_posting(dev);
- mdelay(3); //random value
- return;
- }else{
- force_pci_posting(dev);
- mdelay(3); //random value
- }
- }
- DMESGW ("Phy writing %x %x failed!", adr,data);
-}
-
void rtl8185_set_rate(struct net_device *dev)
{
int i;
@@ -3335,7 +3204,6 @@ static struct net_device_stats *rtl8180_stats(struct net_device *dev)
}
//
// Change current and default preamble mode.
-// 2005.01.06, by rcnjko.
//
bool
MgntActSet_802_11_PowerSaveMode(
@@ -3454,7 +3322,6 @@ void rtl8180_watch_dog(struct net_device *dev)
MgntLinkKeepAlive(priv);
//YJ,add,080828,for LPS
-#ifdef ENABLE_LPS
if (priv->PowerProfile == POWER_PROFILE_BATTERY)
priv->bLeisurePs = true;
else if (priv->PowerProfile == POWER_PROFILE_AC) {
@@ -3464,7 +3331,6 @@ void rtl8180_watch_dog(struct net_device *dev)
if(priv->ieee80211->state == IEEE80211_LINKED){
priv->link_detect.NumRxOkInPeriod = priv->ieee80211->NumRxDataInPeriod;
- //printk("TxOk=%d RxOk=%d\n", priv->link_detect.NumTxOkInPeriod, priv->link_detect.NumRxOkInPeriod);
if( priv->link_detect.NumRxOkInPeriod> 666 ||
priv->link_detect.NumTxOkInPeriod> 666 ) {
bBusyTraffic = true;
@@ -3481,7 +3347,6 @@ void rtl8180_watch_dog(struct net_device *dev)
LeisurePSLeave(priv);
} else
LeisurePSLeave(priv);
-#endif
priv->link_detect.bBusyTraffic = bBusyTraffic;
priv->link_detect.NumRxOkInPeriod = 0;
priv->link_detect.NumTxOkInPeriod = 0;
@@ -3503,16 +3368,11 @@ int _rtl8180_up(struct net_device *dev)
if(priv->ieee80211->iw_mode == IW_MODE_ADHOC)
IPSLeave(dev);
}
-#ifdef RATE_ADAPT
timer_rate_adaptive((unsigned long)dev);
-#endif
watch_dog_adaptive((unsigned long)dev);
-#ifdef SW_ANTE
if(priv->bSwAntennaDiverity)
SwAntennaDiversityTimerCallback(dev);
-#endif
ieee80211_softmac_start_protocol(priv->ieee80211);
-
return 0;
}
@@ -3748,7 +3608,7 @@ static int __devinit rtl8180_pci_probe(struct pci_dev *pdev,
dev->wireless_handlers = &r8180_wx_handlers_def;
dev->type=ARPHRD_ETHER;
- dev->watchdog_timeo = HZ*3; //added by david woo, 2007.12.13
+ dev->watchdog_timeo = HZ*3;
if (dev_alloc_name(dev, ifname) < 0){
DMESG("Oops: devname already taken! Trying wlan%%d...\n");
@@ -3864,8 +3724,7 @@ static int __init rtl8180_pci_module_init(void)
return ret;
}
- printk(KERN_INFO "\nLinux kernel driver for RTL8180 \
-/ RTL8185 based WLAN cards\n");
+ printk(KERN_INFO "\nLinux kernel driver for RTL8180 / RTL8185 based WLAN cards\n");
printk(KERN_INFO "Copyright (c) 2004-2005, Andrea Merello\n");
DMESG("Initializing module");
DMESG("Wireless extensions version %d", WIRELESS_EXT);
@@ -4236,60 +4095,51 @@ void GPIOChangeRFWorkItemCallBack(struct work_struct *work)
static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL};
static int readf_count = 0;
-#ifdef ENABLE_LPS
if(readf_count % 10 == 0)
priv->PowerProfile = read_acadapter_file("/proc/acpi/ac_adapter/AC0/state");
readf_count = (readf_count+1)%0xffff;
-#endif
- {
- // We should turn off LED before polling FF51[4].
+ /* We should turn off LED before polling FF51[4]. */
- //Turn off LED.
- btPSR = read_nic_byte(dev, PSR);
- write_nic_byte(dev, PSR, (btPSR & ~BIT3));
+ /* Turn off LED. */
+ btPSR = read_nic_byte(dev, PSR);
+ write_nic_byte(dev, PSR, (btPSR & ~BIT3));
- //It need to delay 4us suggested by Jong, 2008-01-16
- udelay(4);
+ /* It need to delay 4us suggested by Jong, 2008-01-16 */
+ udelay(4);
- //HW radio On/Off according to the value of FF51[4](config0)
- btConfig0 = btPSR = read_nic_byte(dev, CONFIG0);
+ /* HW radio On/Off according to the value of FF51[4](config0) */
+ btConfig0 = btPSR = read_nic_byte(dev, CONFIG0);
- //Turn on LED.
- write_nic_byte(dev, PSR, btPSR| BIT3);
+ eRfPowerStateToSet = (btConfig0 & BIT4) ? eRfOn : eRfOff;
- eRfPowerStateToSet = (btConfig0 & BIT4) ? eRfOn : eRfOff;
+ /* Turn LED back on when radio enabled */
+ if (eRfPowerStateToSet == eRfOn)
+ write_nic_byte(dev, PSR, btPSR | BIT3);
- if((priv->ieee80211->bHwRadioOff == true) && (eRfPowerStateToSet == eRfOn))
- {
- priv->ieee80211->bHwRadioOff = false;
- bActuallySet = true;
- }
- else if((priv->ieee80211->bHwRadioOff == false) && (eRfPowerStateToSet == eRfOff))
- {
- priv->ieee80211->bHwRadioOff = true;
- bActuallySet = true;
- }
+ if ((priv->ieee80211->bHwRadioOff == true) &&
+ (eRfPowerStateToSet == eRfOn)) {
+ priv->ieee80211->bHwRadioOff = false;
+ bActuallySet = true;
+ } else if ((priv->ieee80211->bHwRadioOff == false) &&
+ (eRfPowerStateToSet == eRfOff)) {
+ priv->ieee80211->bHwRadioOff = true;
+ bActuallySet = true;
+ }
- if(bActuallySet)
- {
- MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW);
-
- /* To update the UI status for Power status changed */
- if(priv->ieee80211->bHwRadioOff == true)
- argv[1] = "RFOFF";
- else{
- //if(!priv->RfOffReason)
- argv[1] = "RFON";
- //else
- // argv[1] = "RFOFF";
- }
- argv[0] = RadioPowerPath;
- argv[2] = NULL;
-
- call_usermodehelper(RadioPowerPath,argv,envp,1);
- }
- }
+ if (bActuallySet) {
+ MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW);
+
+ /* To update the UI status for Power status changed */
+ if (priv->ieee80211->bHwRadioOff == true)
+ argv[1] = "RFOFF";
+ else
+ argv[1] = "RFON";
+ argv[0] = RadioPowerPath;
+ argv[2] = NULL;
+
+ call_usermodehelper(RadioPowerPath, argv, envp, 1);
+ }
}
static u8 read_acadapter_file(char *filename)
diff --git a/drivers/staging/rtl8187se/r8180_dm.c b/drivers/staging/rtl8187se/r8180_dm.c
index cbca58db85e1..fc4907839c58 100644
--- a/drivers/staging/rtl8187se/r8180_dm.c
+++ b/drivers/staging/rtl8187se/r8180_dm.c
@@ -282,30 +282,13 @@ DIG_Zebra(
// Dispatch DIG implementation according to RF.
//
void
-DynamicInitGain(
- struct net_device *dev
- )
+DynamicInitGain(struct net_device *dev)
{
- struct r8180_priv *priv = ieee80211_priv(dev);
-
- switch(priv->rf_chip)
- {
- case RF_ZEBRA2: // [AnnieWorkaround] For Zebra2, 2005-08-01.
- case RF_ZEBRA4:
- DIG_Zebra( dev );
- break;
-
- default:
- printk("DynamicInitGain(): unknown RFChipID(%d) !!!\n", priv->rf_chip);
- break;
- }
+ DIG_Zebra(dev);
}
void rtl8180_hw_dig_wq (struct work_struct *work)
{
-// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq);
-// struct ieee80211_device * ieee = (struct ieee80211_device*)
-// container_of(work, struct ieee80211_device, watch_dog_wq);
struct delayed_work *dwork = to_delayed_work(work);
struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_dig_wq);
struct net_device *dev = ieee->dev;
@@ -1310,44 +1293,24 @@ SetAntenna8185(
switch(u1bAntennaIndex)
{
case 0:
- switch(priv->rf_chip)
- {
- case RF_ZEBRA2:
- case RF_ZEBRA4:
- // Mac register, main antenna
- write_nic_byte(dev, ANTSEL, 0x03);
- //base band
- write_phy_cck(dev,0x11, 0x9b); // Config CCK RX antenna.
- write_phy_ofdm(dev, 0x0d, 0x5c); // Config OFDM RX antenna.
-
-
- bAntennaSwitched = true;
- break;
+ /* Mac register, main antenna */
+ write_nic_byte(dev, ANTSEL, 0x03);
+ /* base band */
+ write_phy_cck(dev, 0x11, 0x9b); /* Config CCK RX antenna. */
+ write_phy_ofdm(dev, 0x0d, 0x5c); /* Config OFDM RX antenna. */
- default:
- printk("SetAntenna8185: unknown RFChipID(%d)\n", priv->rf_chip);
- break;
- }
+ bAntennaSwitched = true;
break;
case 1:
- switch(priv->rf_chip)
- {
- case RF_ZEBRA2:
- case RF_ZEBRA4:
- // Mac register, aux antenna
- write_nic_byte(dev, ANTSEL, 0x00);
- //base band
- write_phy_cck(dev, 0x11, 0xbb); // Config CCK RX antenna.
- write_phy_ofdm(dev, 0x0d, 0x54); // Config OFDM RX antenna.
-
- bAntennaSwitched = true;
- break;
+ /* Mac register, aux antenna */
+ write_nic_byte(dev, ANTSEL, 0x00);
+ /* base band */
+ write_phy_cck(dev, 0x11, 0xbb); /* Config CCK RX antenna. */
+ write_phy_ofdm(dev, 0x0d, 0x54); /* Config OFDM RX antenna. */
+
+ bAntennaSwitched = true;
- default:
- printk("SetAntenna8185: unknown RFChipID(%d)\n", priv->rf_chip);
- break;
- }
break;
default:
diff --git a/drivers/staging/rtl8187se/r8180_rtl8225z2.c b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
index afe10f0b75a8..6edf5a46fa40 100644
--- a/drivers/staging/rtl8187se/r8180_rtl8225z2.c
+++ b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
@@ -854,134 +854,48 @@ bool SetZebraRFPowerState8185(struct net_device *dev,
btConfig3 = read_nic_byte(dev, CONFIG3);
write_nic_byte(dev, CONFIG3, (btConfig3 | CONFIG3_PARM_En));
- switch (priv->rf_chip) {
- case RF_ZEBRA2:
- switch (eRFPowerState) {
- case eRfOn:
- RF_WriteReg(dev,0x4,0x9FF);
+ switch (eRFPowerState) {
+ case eRfOn:
+ write_nic_word(dev, 0x37C, 0x00EC);
- write_nic_dword(dev, ANAPARAM, ANAPARM_ON);
- write_nic_dword(dev, ANAPARAM2, ANAPARM2_ON);
+ /* turn on AFE */
+ write_nic_byte(dev, 0x54, 0x00);
+ write_nic_byte(dev, 0x62, 0x00);
- write_nic_byte(dev, CONFIG4, priv->RFProgType);
+ /* turn on RF */
+ RF_WriteReg(dev, 0x0, 0x009f); udelay(500);
+ RF_WriteReg(dev, 0x4, 0x0972); udelay(500);
- /* turn on CCK and OFDM */
- u1bTmp = read_nic_byte(dev, 0x24E);
- write_nic_byte(dev, 0x24E, (u1bTmp & (~(BIT5 | BIT6))));
- break;
- case eRfSleep:
- break;
- case eRfOff:
- break;
- default:
- bResult = false;
- break;
- }
- break;
- case RF_ZEBRA4:
- switch (eRFPowerState) {
- case eRfOn:
- write_nic_word(dev, 0x37C, 0x00EC);
-
- /* turn on AFE */
- write_nic_byte(dev, 0x54, 0x00);
- write_nic_byte(dev, 0x62, 0x00);
-
- /* turn on RF */
- RF_WriteReg(dev, 0x0, 0x009f); udelay(500);
- RF_WriteReg(dev, 0x4, 0x0972); udelay(500);
-
- /* turn on RF again */
- RF_WriteReg(dev, 0x0, 0x009f); udelay(500);
- RF_WriteReg(dev, 0x4, 0x0972); udelay(500);
+ /* turn on RF again */
+ RF_WriteReg(dev, 0x0, 0x009f); udelay(500);
+ RF_WriteReg(dev, 0x4, 0x0972); udelay(500);
- /* turn on BB */
- write_phy_ofdm(dev,0x10,0x40);
- write_phy_ofdm(dev,0x12,0x40);
-
- /* Avoid power down at init time. */
- write_nic_byte(dev, CONFIG4, priv->RFProgType);
-
- u1bTmp = read_nic_byte(dev, 0x24E);
- write_nic_byte(dev, 0x24E, (u1bTmp & (~(BIT5 | BIT6))));
- break;
- case eRfSleep:
- for (QueueID = 0, i = 0; QueueID < 6;) {
- if (get_curr_tx_free_desc(dev, QueueID) == priv->txringcount) {
- QueueID++;
- continue;
- } else {
- priv->TxPollingTimes ++;
- if (priv->TxPollingTimes >= LPS_MAX_SLEEP_WAITING_TIMES_87SE) {
- bActionAllowed = false;
- break;
- } else
- udelay(10);
- }
- }
+ /* turn on BB */
+ write_phy_ofdm(dev, 0x10, 0x40);
+ write_phy_ofdm(dev, 0x12, 0x40);
- if (bActionAllowed) {
- /* turn off BB RXIQ matrix to cut off rx signal */
- write_phy_ofdm(dev, 0x10, 0x00);
- write_phy_ofdm(dev, 0x12, 0x00);
-
- /* turn off RF */
- RF_WriteReg(dev, 0x4, 0x0000);
- RF_WriteReg(dev, 0x0, 0x0000);
-
- /* turn off AFE except PLL */
- write_nic_byte(dev, 0x62, 0xff);
- write_nic_byte(dev, 0x54, 0xec);
-
- mdelay(1);
-
- {
- int i = 0;
- while (true) {
- u8 tmp24F = read_nic_byte(dev, 0x24f);
-
- if ((tmp24F == 0x01) || (tmp24F == 0x09)) {
- bTurnOffBB = true;
- break;
- } else {
- udelay(10);
- i++;
- priv->TxPollingTimes++;
-
- if (priv->TxPollingTimes >= LPS_MAX_SLEEP_WAITING_TIMES_87SE) {
- bTurnOffBB = false;
- break;
- } else
- udelay(10);
- }
- }
- }
-
- if (bTurnOffBB) {
- /* turn off BB */
- u1bTmp = read_nic_byte(dev, 0x24E);
- write_nic_byte(dev, 0x24E, (u1bTmp | BIT5 | BIT6));
-
- /* turn off AFE PLL */
- write_nic_byte(dev, 0x54, 0xFC);
- write_nic_word(dev, 0x37C, 0x00FC);
- }
- }
- break;
- case eRfOff:
- for (QueueID = 0, i = 0; QueueID < 6;) {
- if (get_curr_tx_free_desc(dev, QueueID) == priv->txringcount) {
- QueueID++;
- continue;
- } else {
- udelay(10);
- i++;
- }
+ /* Avoid power down at init time. */
+ write_nic_byte(dev, CONFIG4, priv->RFProgType);
- if (i >= MAX_DOZE_WAITING_TIMES_85B)
+ u1bTmp = read_nic_byte(dev, 0x24E);
+ write_nic_byte(dev, 0x24E, (u1bTmp & (~(BIT5 | BIT6))));
+ break;
+ case eRfSleep:
+ for (QueueID = 0, i = 0; QueueID < 6;) {
+ if (get_curr_tx_free_desc(dev, QueueID) == priv->txringcount) {
+ QueueID++;
+ continue;
+ } else {
+ priv->TxPollingTimes++;
+ if (priv->TxPollingTimes >= LPS_MAX_SLEEP_WAITING_TIMES_87SE) {
+ bActionAllowed = false;
break;
+ } else
+ udelay(10);
}
+ }
+ if (bActionAllowed) {
/* turn off BB RXIQ matrix to cut off rx signal */
write_phy_ofdm(dev, 0x10, 0x00);
write_phy_ofdm(dev, 0x12, 0x00);
@@ -998,22 +912,23 @@ bool SetZebraRFPowerState8185(struct net_device *dev,
{
int i = 0;
-
- while (true)
- {
+ while (true) {
u8 tmp24F = read_nic_byte(dev, 0x24f);
if ((tmp24F == 0x01) || (tmp24F == 0x09)) {
bTurnOffBB = true;
break;
} else {
- bTurnOffBB = false;
udelay(10);
i++;
- }
+ priv->TxPollingTimes++;
- if (i > MAX_POLLING_24F_TIMES_87SE)
- break;
+ if (priv->TxPollingTimes >= LPS_MAX_SLEEP_WAITING_TIMES_87SE) {
+ bTurnOffBB = false;
+ break;
+ } else
+ udelay(10);
+ }
}
}
@@ -1022,15 +937,68 @@ bool SetZebraRFPowerState8185(struct net_device *dev,
u1bTmp = read_nic_byte(dev, 0x24E);
write_nic_byte(dev, 0x24E, (u1bTmp | BIT5 | BIT6));
- /* turn off AFE PLL (80M) */
+ /* turn off AFE PLL */
write_nic_byte(dev, 0x54, 0xFC);
write_nic_word(dev, 0x37C, 0x00FC);
}
- break;
- default:
- bResult = false;
- printk("SetZebraRFPowerState8185(): unknown state to set: 0x%X!!!\n", eRFPowerState);
- break;
+ }
+ break;
+ case eRfOff:
+ for (QueueID = 0, i = 0; QueueID < 6;) {
+ if (get_curr_tx_free_desc(dev, QueueID) == priv->txringcount) {
+ QueueID++;
+ continue;
+ } else {
+ udelay(10);
+ i++;
+ }
+
+ if (i >= MAX_DOZE_WAITING_TIMES_85B)
+ break;
+ }
+
+ /* turn off BB RXIQ matrix to cut off rx signal */
+ write_phy_ofdm(dev, 0x10, 0x00);
+ write_phy_ofdm(dev, 0x12, 0x00);
+
+ /* turn off RF */
+ RF_WriteReg(dev, 0x4, 0x0000);
+ RF_WriteReg(dev, 0x0, 0x0000);
+
+ /* turn off AFE except PLL */
+ write_nic_byte(dev, 0x62, 0xff);
+ write_nic_byte(dev, 0x54, 0xec);
+
+ mdelay(1);
+
+ {
+ int i = 0;
+
+ while (true) {
+ u8 tmp24F = read_nic_byte(dev, 0x24f);
+
+ if ((tmp24F == 0x01) || (tmp24F == 0x09)) {
+ bTurnOffBB = true;
+ break;
+ } else {
+ bTurnOffBB = false;
+ udelay(10);
+ i++;
+ }
+
+ if (i > MAX_POLLING_24F_TIMES_87SE)
+ break;
+ }
+ }
+
+ if (bTurnOffBB) {
+ /* turn off BB */
+ u1bTmp = read_nic_byte(dev, 0x24E);
+ write_nic_byte(dev, 0x24E, (u1bTmp | BIT5 | BIT6));
+
+ /* turn off AFE PLL (80M) */
+ write_nic_byte(dev, 0x54, 0xFC);
+ write_nic_word(dev, 0x37C, 0x00FC);
}
break;
}
diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c
index 50309f2da9c1..a0ece1fd64a5 100644
--- a/drivers/staging/rtl8187se/r8185b_init.c
+++ b/drivers/staging/rtl8187se/r8185b_init.c
@@ -238,100 +238,12 @@ PlatformIORead4Byte(
return data;
}
-void
-SetOutputEnableOfRfPins(
- struct net_device *dev
- )
+void SetOutputEnableOfRfPins(struct net_device *dev)
{
- struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
-
- switch(priv->rf_chip)
- {
- case RFCHIPID_RTL8225:
- case RF_ZEBRA2:
- case RF_ZEBRA4:
- write_nic_word(dev, RFPinsEnable, 0x1bff);
- //write_nic_word(dev, RFPinsEnable, 0x1fff);
- break;
- }
+ write_nic_word(dev, RFPinsEnable, 0x1bff);
}
-void
-ZEBRA_RFSerialWrite(
- struct net_device *dev,
- u32 data2Write,
- u8 totalLength,
- u8 low2high
- )
-{
- ThreeWireReg twreg;
- int i;
- u16 oval,oval2,oval3;
- u32 mask;
- u16 UshortBuffer;
-
- u8 u1bTmp;
- // RTL8187S HSSI Read/Write Function
- u1bTmp = read_nic_byte(dev, RF_SW_CONFIG);
- u1bTmp |= RF_SW_CFG_SI; //reg08[1]=1 Serial Interface(SI)
- write_nic_byte(dev, RF_SW_CONFIG, u1bTmp);
- UshortBuffer = read_nic_word(dev, RFPinsOutput);
- oval = UshortBuffer & 0xfff8; // We shall clear bit0, 1, 2 first, 2005.10.28, by rcnjko.
-
- oval2 = read_nic_word(dev, RFPinsEnable);
- oval3 = read_nic_word(dev, RFPinsSelect);
-
- // <RJ_NOTE> 3-wire should be controled by HW when we finish SW 3-wire programming. 2005.08.10, by rcnjko.
- oval3 &= 0xfff8;
-
- write_nic_word(dev, RFPinsEnable, (oval2|0x0007)); // Set To Output Enable
- write_nic_word(dev, RFPinsSelect, (oval3|0x0007)); // Set To SW Switch
- udelay(10);
-
- // Add this to avoid hardware and software 3-wire conflict.
- // 2005.03.01, by rcnjko.
- twreg.longData = 0;
- twreg.struc.enableB = 1;
- write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); // Set SI_EN (RFLE)
- udelay(2);
- twreg.struc.enableB = 0;
- write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); // Clear SI_EN (RFLE)
- udelay(10);
-
- mask = (low2high)?0x01:((u32)0x01<<(totalLength-1));
-
- for(i=0; i<totalLength/2; i++)
- {
- twreg.struc.data = ((data2Write&mask)!=0) ? 1 : 0;
- write_nic_word(dev, RFPinsOutput, (twreg.longData|oval));
- twreg.struc.clk = 1;
- write_nic_word(dev, RFPinsOutput, (twreg.longData|oval));
- write_nic_word(dev, RFPinsOutput, (twreg.longData|oval));
-
- mask = (low2high)?(mask<<1):(mask>>1);
- twreg.struc.data = ((data2Write&mask)!=0) ? 1 : 0;
- write_nic_word(dev, RFPinsOutput, (twreg.longData|oval));
- write_nic_word(dev, RFPinsOutput, (twreg.longData|oval));
- twreg.struc.clk = 0;
- write_nic_word(dev, RFPinsOutput, (twreg.longData|oval));
- mask = (low2high)?(mask<<1):(mask>>1);
- }
-
- twreg.struc.enableB = 1;
- twreg.struc.clk = 0;
- twreg.struc.data = 0;
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval);
- udelay(10);
-
- write_nic_word(dev, RFPinsOutput, oval|0x0004);
- write_nic_word(dev, RFPinsSelect, oval3|0x0000);
-
- SetOutputEnableOfRfPins(dev);
-}
-//by amy
-
-
-int
+static int
HwHSSIThreeWire(
struct net_device *dev,
u8 *pDataBuf,
@@ -469,420 +381,30 @@ HwHSSIThreeWire(
return bResult;
}
-//by amy
-
-int
-HwThreeWire(
- struct net_device *dev,
- u8 *pDataBuf,
- u8 nDataBufBitCnt,
- int bHold,
- int bWrite
- )
-{
- int bResult = 1;
- u8 TryCnt;
- u8 u1bTmp;
-
- do
- {
- // Check if WE and RE are cleared.
- for(TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++)
- {
- u1bTmp = read_nic_byte(dev, SW_3W_CMD1);
- if( (u1bTmp & (SW_3W_CMD1_RE|SW_3W_CMD1_WE)) == 0 )
- {
- break;
- }
- udelay(10);
- }
- if (TryCnt == TC_3W_POLL_MAX_TRY_CNT)
- panic("HwThreeWire(): CmdReg: %#X RE|WE bits are not clear!!\n", u1bTmp);
-
- // Fill up data buffer for write operation.
- if(nDataBufBitCnt == 16)
- {
- write_nic_word(dev, SW_3W_DB0, *((u16 *)pDataBuf));
- }
- else if(nDataBufBitCnt == 64)
- {
- write_nic_dword(dev, SW_3W_DB0, *((u32 *)pDataBuf));
- write_nic_dword(dev, SW_3W_DB1, *((u32 *)(pDataBuf + 4)));
- }
- else
- {
- int idx;
- int ByteCnt = nDataBufBitCnt / 8;
-
- if ((nDataBufBitCnt % 8) != 0)
- panic("HwThreeWire(): nDataBufBitCnt(%d) should be multiple of 8!!!\n",
- nDataBufBitCnt);
-
- if (nDataBufBitCnt > 64)
- panic("HwThreeWire(): nDataBufBitCnt(%d) should <= 64!!!\n",
- nDataBufBitCnt);
-
- for(idx = 0; idx < ByteCnt; idx++)
- {
- write_nic_byte(dev, (SW_3W_DB0+idx), *(pDataBuf+idx));
- }
- }
-
- // Fill up length field.
- u1bTmp = (u8)(nDataBufBitCnt - 1); // Number of bits - 1.
- if(bHold)
- u1bTmp |= SW_3W_CMD0_HOLD;
- write_nic_byte(dev, SW_3W_CMD0, u1bTmp);
-
- // Set up command: WE or RE.
- if(bWrite)
- {
- write_nic_byte(dev, SW_3W_CMD1, SW_3W_CMD1_WE);
- }
- else
- {
- write_nic_byte(dev, SW_3W_CMD1, SW_3W_CMD1_RE);
- }
-
- // Check if WE and RE are cleared and DONE is set.
- for(TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++)
- {
- u1bTmp = read_nic_byte(dev, SW_3W_CMD1);
- if( (u1bTmp & (SW_3W_CMD1_RE|SW_3W_CMD1_WE)) == 0 &&
- (u1bTmp & SW_3W_CMD1_DONE) != 0 )
- {
- break;
- }
- udelay(10);
- }
- if(TryCnt == TC_3W_POLL_MAX_TRY_CNT)
- {
- //RT_ASSERT(TryCnt != TC_3W_POLL_MAX_TRY_CNT,
- // ("HwThreeWire(): CmdReg: %#X RE|WE bits are not clear or DONE is not set!!\n", u1bTmp));
- // Workaround suggested by wcchu: clear WE here. 2006.07.07, by rcnjko.
- write_nic_byte(dev, SW_3W_CMD1, 0);
- }
-
- // Read back data for read operation.
- // <RJ_TODO> I am not sure if this is correct output format of a read operation.
- if(bWrite == 0)
- {
- if(nDataBufBitCnt == 16)
- {
- *((u16 *)pDataBuf) = read_nic_word(dev, SW_3W_DB0);
- }
- else if(nDataBufBitCnt == 64)
- {
- *((u32 *)pDataBuf) = read_nic_dword(dev, SW_3W_DB0);
- *((u32 *)(pDataBuf + 4)) = read_nic_dword(dev, SW_3W_DB1);
- }
- else
- {
- int idx;
- int ByteCnt = nDataBufBitCnt / 8;
-
- if ((nDataBufBitCnt % 8) != 0)
- panic("HwThreeWire(): nDataBufBitCnt(%d) should be multiple of 8!!!\n",
- nDataBufBitCnt);
-
- if (nDataBufBitCnt > 64)
- panic("HwThreeWire(): nDataBufBitCnt(%d) should <= 64!!!\n",
- nDataBufBitCnt);
-
- for(idx = 0; idx < ByteCnt; idx++)
- {
- *(pDataBuf+idx) = read_nic_byte(dev, (SW_3W_DB0+idx));
- }
- }
- }
-
- }while(0);
-
- return bResult;
-}
-
void
-RF_WriteReg(
- struct net_device *dev,
- u8 offset,
- u32 data
- )
+RF_WriteReg(struct net_device *dev, u8 offset, u32 data)
{
- //RFReg reg;
- u32 data2Write;
- u8 len;
- u8 low2high;
- //u32 RF_Read = 0;
- struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
-
-
- switch(priv->rf_chip)
- {
- case RFCHIPID_RTL8225:
- case RF_ZEBRA2: // Annie 2006-05-12.
- case RF_ZEBRA4: //by amy
- switch(priv->RegThreeWireMode)
- {
- case SW_THREE_WIRE:
- { // Perform SW 3-wire programming by driver.
- data2Write = (data << 4) | (u32)(offset & 0x0f);
- len = 16;
- low2high = 0;
- ZEBRA_RFSerialWrite(dev, data2Write, len, low2high);
- }
- break;
+ u32 data2Write;
+ u8 len;
- case HW_THREE_WIRE:
- { // Pure HW 3-wire.
- data2Write = (data << 4) | (u32)(offset & 0x0f);
- len = 16;
- HwThreeWire(
- dev,
- (u8 *)(&data2Write), // pDataBuf,
- len, // nDataBufBitCnt,
- 0, // bHold,
- 1); // bWrite
- }
- break;
- case HW_THREE_WIRE_PI: //Parallel Interface
- { // Pure HW 3-wire.
- data2Write = (data << 4) | (u32)(offset & 0x0f);
- len = 16;
- HwHSSIThreeWire(
- dev,
- (u8*)(&data2Write), // pDataBuf,
- len, // nDataBufBitCnt,
- 0, // bSI
- 1); // bWrite
-
- //printk("33333\n");
- }
- break;
-
- case HW_THREE_WIRE_SI: //Serial Interface
- { // Pure HW 3-wire.
- data2Write = (data << 4) | (u32)(offset & 0x0f);
- len = 16;
-// printk(" enter ZEBRA_RFSerialWrite\n ");
-// low2high = 0;
-// ZEBRA_RFSerialWrite(dev, data2Write, len, low2high);
-
- HwHSSIThreeWire(
- dev,
- (u8*)(&data2Write), // pDataBuf,
- len, // nDataBufBitCnt,
- 1, // bSI
- 1); // bWrite
-
-// printk(" exit ZEBRA_RFSerialWrite\n ");
- }
- break;
-
-
- default:
- DMESGE("RF_WriteReg(): invalid RegThreeWireMode(%d) !!!", priv->RegThreeWireMode);
- break;
- }
- break;
-
- default:
- DMESGE("RF_WriteReg(): unknown RFChipID: %#X", priv->rf_chip);
- break;
- }
-}
-
-
-void
-ZEBRA_RFSerialRead(
- struct net_device *dev,
- u32 data2Write,
- u8 wLength,
- u32 *data2Read,
- u8 rLength,
- u8 low2high
- )
-{
- ThreeWireReg twreg;
- int i;
- u16 oval,oval2,oval3,tmp, wReg80;
- u32 mask;
- u8 u1bTmp;
- ThreeWireReg tdata;
- //PHAL_DATA_8187 pHalData = GetHalData8187(pAdapter);
- { // RTL8187S HSSI Read/Write Function
- u1bTmp = read_nic_byte(dev, RF_SW_CONFIG);
- u1bTmp |= RF_SW_CFG_SI; //reg08[1]=1 Serial Interface(SI)
- write_nic_byte(dev, RF_SW_CONFIG, u1bTmp);
- }
-
- wReg80 = oval = read_nic_word(dev, RFPinsOutput);
- oval2 = read_nic_word(dev, RFPinsEnable);
- oval3 = read_nic_word(dev, RFPinsSelect);
-
- write_nic_word(dev, RFPinsEnable, oval2|0xf);
- write_nic_word(dev, RFPinsSelect, oval3|0xf);
-
- *data2Read = 0;
-
- // We must clear BIT0-3 here, otherwise,
- // SW_Enalbe will be true when we first call ZEBRA_RFSerialRead() after 8187MPVC open,
- // which will cause the value read become 0. 2005.04.11, by rcnjko.
- oval &= ~0xf;
-
- // Avoid collision with hardware three-wire.
- twreg.longData = 0;
- twreg.struc.enableB = 1;
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(4);
-
- twreg.longData = 0;
- twreg.struc.enableB = 0;
- twreg.struc.clk = 0;
- twreg.struc.read_write = 0;
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(5);
-
- mask = (low2high) ? 0x01 : ((u32)0x01<<(32-1));
- for(i = 0; i < wLength/2; i++)
- {
- twreg.struc.data = ((data2Write&mask) != 0) ? 1 : 0;
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(1);
- twreg.struc.clk = 1;
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2);
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2);
-
- mask = (low2high) ? (mask<<1): (mask>>1);
-
- if(i == 2)
- {
- // Commented out by Jackie, 2004.08.26. <RJ_NOTE> We must comment out the following two lines for we cannot pull down VCOPDN during RF Serail Read.
- //PlatformEFIOWrite2Byte(pAdapter, RFPinsEnable, 0xe); // turn off data enable
- //PlatformEFIOWrite2Byte(pAdapter, RFPinsSelect, 0xe);
-
- twreg.struc.read_write=1;
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2);
- twreg.struc.clk = 0;
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2);
- break;
- }
- twreg.struc.data = ((data2Write&mask) != 0) ? 1: 0;
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2);
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2);
-
- twreg.struc.clk = 0;
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(1);
-
- mask = (low2high) ? (mask<<1) : (mask>>1);
- }
-
- twreg.struc.clk = 0;
- twreg.struc.data = 0;
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2);
- mask = (low2high) ? 0x01 : ((u32)0x01 << (12-1));
-
- //
- // 061016, by rcnjko:
- // We must set data pin to HW controled, otherwise RF can't driver it and
- // value RF register won't be able to read back properly.
- //
- write_nic_word(dev, RFPinsEnable, ( ((oval2|0x0E) & (~0x01))) );
+ /* Pure HW 3-wire. */
+ data2Write = (data << 4) | (u32)(offset & 0x0f);
+ len = 16;
- for(i = 0; i < rLength; i++)
- {
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(1);
- twreg.struc.clk = 1;
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2);
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2);
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2);
- tmp = read_nic_word(dev, RFPinsInput);
- tdata.longData = tmp;
- *data2Read |= tdata.struc.clk ? mask : 0;
-
- twreg.struc.clk = 0;
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2);
-
- mask = (low2high) ? (mask<<1) : (mask>>1);
- }
- twreg.struc.enableB = 1;
- twreg.struc.clk = 0;
- twreg.struc.data = 0;
- twreg.struc.read_write = 1;
- write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2);
-
- //PlatformEFIOWrite2Byte(pAdapter, RFPinsEnable, oval2|0x8); // Set To Output Enable
- write_nic_word(dev, RFPinsEnable, oval2); // Set To Output Enable, <RJ_NOTE> We cannot enable BIT3 here, otherwise, we will failed to switch channel. 2005.04.12.
- //PlatformEFIOWrite2Byte(pAdapter, RFPinsEnable, 0x1bff);
- write_nic_word(dev, RFPinsSelect, oval3); // Set To SW Switch
- //PlatformEFIOWrite2Byte(pAdapter, RFPinsSelect, 0x0488);
- write_nic_word(dev, RFPinsOutput, 0x3a0);
- //PlatformEFIOWrite2Byte(pAdapter, RFPinsOutput, 0x0480);
+ HwHSSIThreeWire(dev, (u8 *)(&data2Write), len, 1, 1);
}
-
-u32
-RF_ReadReg(
- struct net_device *dev,
- u8 offset
- )
+u32 RF_ReadReg(struct net_device *dev, u8 offset)
{
- struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- u32 data2Write;
- u8 wlen;
- u8 rlen;
- u8 low2high;
- u32 dataRead;
+ u32 data2Write;
+ u8 wlen;
+ u32 dataRead;
- switch(priv->rf_chip)
- {
- case RFCHIPID_RTL8225:
- case RF_ZEBRA2:
- case RF_ZEBRA4:
- switch(priv->RegThreeWireMode)
- {
- case HW_THREE_WIRE_PI: // For 87S Parallel Interface.
- {
- data2Write = ((u32)(offset&0x0f));
- wlen=16;
- HwHSSIThreeWire(
- dev,
- (u8*)(&data2Write), // pDataBuf,
- wlen, // nDataBufBitCnt,
- 0, // bSI
- 0); // bWrite
- dataRead= data2Write;
- }
- break;
-
- case HW_THREE_WIRE_SI: // For 87S Serial Interface.
- {
- data2Write = ((u32)(offset&0x0f)) ;
- wlen=16;
- HwHSSIThreeWire(
- dev,
- (u8*)(&data2Write), // pDataBuf,
- wlen, // nDataBufBitCnt,
- 1, // bSI
- 0 // bWrite
- );
- dataRead= data2Write;
- }
- break;
-
- // Perform SW 3-wire programming by driver.
- default:
- {
- data2Write = ((u32)(offset&0x1f)) << 27; // For Zebra E-cut. 2005.04.11, by rcnjko.
- wlen = 6;
- rlen = 12;
- low2high = 0;
- ZEBRA_RFSerialRead(dev, data2Write, wlen,&dataRead,rlen, low2high);
- }
- break;
- }
- break;
- default:
- dataRead = 0;
- break;
- }
+ data2Write = ((u32)(offset & 0x0f));
+ wlen = 16;
+ HwHSSIThreeWire(dev, (u8 *)(&data2Write), wlen, 1, 0);
+ dataRead = data2Write;
return dataRead;
}
@@ -1043,15 +565,12 @@ ZEBRA_Config_85BASIC_HardCode(
// Page0 : reg0-reg15
-// RF_WriteReg(dev, 0x00, 0x003f); mdelay(1);//1
RF_WriteReg(dev, 0x00, 0x009f); mdelay(1);// 1
RF_WriteReg(dev, 0x01, 0x06e0); mdelay(1);
-// RF_WriteReg(dev, 0x02, 0x004c); mdelay(1);//2
RF_WriteReg(dev, 0x02, 0x004d); mdelay(1);// 2
-// RF_WriteReg(dev, 0x03, 0x0000); mdelay(1);//3
RF_WriteReg(dev, 0x03, 0x07f1); mdelay(1);// 3
RF_WriteReg(dev, 0x04, 0x0975); mdelay(1);
@@ -1080,8 +599,6 @@ ZEBRA_Config_85BASIC_HardCode(
RF_WriteReg(dev, 0x07, 0x01A0); mdelay(1);
// Don't write RF23/RF24 to make a difference between 87S C cut and D cut. asked by SD3 stevenl.
-// RF_WriteReg(dev, 0x08, 0x0597); mdelay(1);
-// RF_WriteReg(dev, 0x09, 0x050a); mdelay(1);
RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1);
RF_WriteReg(dev, 0x0b, 0x0418); mdelay(1);
@@ -1097,7 +614,6 @@ ZEBRA_Config_85BASIC_HardCode(
RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1);
-// RF_WriteReg(dev, 0x00, 0x017f); mdelay(1);//6
RF_WriteReg(dev, 0x00, 0x01d7); mdelay(1);// 6
RF_WriteReg(dev, 0x03, 0x0e00); mdelay(1);
@@ -1106,20 +622,14 @@ ZEBRA_Config_85BASIC_HardCode(
{
RF_WriteReg(dev, 0x01, i); mdelay(1);
RF_WriteReg(dev, 0x02, ZEBRA_RF_RX_GAIN_TABLE[i]); mdelay(1);
- //DbgPrint("RF - 0x%x = 0x%x", i, ZEBRA_RF_RX_GAIN_TABLE[i]);
}
RF_WriteReg(dev, 0x05, 0x0203); mdelay(1); /// 203, 343
- //RF_WriteReg(dev, 0x06, 0x0300); mdelay(1); // 400
RF_WriteReg(dev, 0x06, 0x0200); mdelay(1); // 400
RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); // switch to reg16-reg30, and HSSI disable 137
mdelay(10); // Deay 10 ms. //0xfd
-// RF_WriteReg(dev, 0x0c, 0x09be); mdelay(1); // 7
- //RF_WriteReg(dev, 0x0c, 0x07be); mdelay(1);
- //mdelay(10); // Deay 10 ms. //0xfd
-
RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); // Z4 synthesizer loop filter setting, 392
mdelay(10); // Deay 10 ms. //0xfd
@@ -1165,10 +675,8 @@ ZEBRA_Config_85BASIC_HardCode(
RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1);
}
//by amy 080312
-// RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1); //-by amy 080312
RF_WriteReg(dev, 0x00, 0x00bf); mdelay(1); // switch to reg0-reg15, and HSSI enable
-// RF_WriteReg(dev, 0x0d, 0x009f); mdelay(1); // Rx BB start calibration, 00c//-edward
RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); // Rx BB start calibration, 00c//+edward
RF_WriteReg(dev, 0x02, 0x004d); mdelay(1); // temperature meter off
RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); // Rx mode
@@ -1217,13 +725,10 @@ ZEBRA_Config_85BASIC_HardCode(
// AGC.txt
//=============================================================================
-// PlatformIOWrite4Byte( dev, PhyAddr, 0x00001280); // Annie, 2006-05-05
write_phy_ofdm(dev, 0x00, 0x12);
- //WriteBBPortUchar(dev, 0x00001280);
for (i=0; i<128; i++)
{
- //DbgPrint("AGC - [%x+1] = 0x%x\n", i, ZEBRA_AGC[i+1]);
data = ZEBRA_AGC[i+1];
data = data << 8;
@@ -1239,7 +744,6 @@ ZEBRA_Config_85BASIC_HardCode(
}
PlatformIOWrite4Byte( dev, PhyAddr, 0x00001080); // Annie, 2006-05-05
- //WriteBBPortUchar(dev, 0x00001080);
//=============================================================================
@@ -1252,8 +756,6 @@ ZEBRA_Config_85BASIC_HardCode(
u4bRegOffset=i;
u4bRegValue=OFDM_CONFIG[i];
- //DbgPrint("OFDM - 0x%x = 0x%x\n", u4bRegOffset, u4bRegValue);
-
WriteBBPortUchar(dev,
(0x00000080 |
(u4bRegOffset & 0x7f) |
@@ -1277,9 +779,6 @@ UpdateInitialGain(
)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- //unsigned char* IGTable;
- //u8 DIG_CurrentInitialGain = 4;
- //unsigned char u1Tmp;
//lzm add 080826
if(priv->eRFPowerState != eRfOn)
@@ -1291,81 +790,59 @@ UpdateInitialGain(
return;
}
- switch(priv->rf_chip)
- {
- case RF_ZEBRA4:
- // Dynamic set initial gain, follow 87B
- switch(priv->InitialGain)
- {
- case 1: //m861dBm
- //DMESG("RTL8187 + 8225 Initial Gain State 1: -82 dBm \n");
- write_phy_ofdm(dev, 0x17, 0x26); mdelay(1);
- write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
- write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1);
- break;
-
- case 2: //m862dBm
- //DMESG("RTL8187 + 8225 Initial Gain State 2: -82 dBm \n");
- write_phy_ofdm(dev, 0x17, 0x36); mdelay(1);
- write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
- write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1);
- break;
-
- case 3: //m863dBm
- //DMESG("RTL8187 + 8225 Initial Gain State 3: -82 dBm \n");
- write_phy_ofdm(dev, 0x17, 0x36); mdelay(1);
- write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
- write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1);
- break;
-
- case 4: //m864dBm
- //DMESG("RTL8187 + 8225 Initial Gain State 4: -78 dBm \n");
- write_phy_ofdm(dev, 0x17, 0x46); mdelay(1);
- write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
- write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1);
- break;
+ switch (priv->InitialGain) {
+ case 1: /* m861dBm */
+ write_phy_ofdm(dev, 0x17, 0x26); mdelay(1);
+ write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
+ write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1);
+ break;
- case 5: //m82dBm
- //DMESG("RTL8187 + 8225 Initial Gain State 5: -74 dBm \n");
- write_phy_ofdm(dev, 0x17, 0x46); mdelay(1);
- write_phy_ofdm(dev, 0x24, 0x96); mdelay(1);
- write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1);
- break;
+ case 2: /* m862dBm */
+ write_phy_ofdm(dev, 0x17, 0x36); mdelay(1);
+ write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
+ write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1);
+ break;
- case 6: //m78dBm
- //DMESG ("RTL8187 + 8225 Initial Gain State 6: -70 dBm \n");
- write_phy_ofdm(dev, 0x17, 0x56); mdelay(1);
- write_phy_ofdm(dev, 0x24, 0x96); mdelay(1);
- write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1);
- break;
+ case 3: /* m863dBm */
+ write_phy_ofdm(dev, 0x17, 0x36); mdelay(1);
+ write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
+ write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1);
+ break;
- case 7: //m74dBm
- //DMESG("RTL8187 + 8225 Initial Gain State 7: -66 dBm \n");
- write_phy_ofdm(dev, 0x17, 0x56); mdelay(1);
- write_phy_ofdm(dev, 0x24, 0xa6); mdelay(1);
- write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1);
- break;
+ case 4: /* m864dBm */
+ write_phy_ofdm(dev, 0x17, 0x46); mdelay(1);
+ write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
+ write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1);
+ break;
- case 8:
- //DMESG("RTL8187 + 8225 Initial Gain State 8:\n");
- write_phy_ofdm(dev, 0x17, 0x66); mdelay(1);
- write_phy_ofdm(dev, 0x24, 0xb6); mdelay(1);
- write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1);
- break;
+ case 5: /* m82dBm */
+ write_phy_ofdm(dev, 0x17, 0x46); mdelay(1);
+ write_phy_ofdm(dev, 0x24, 0x96); mdelay(1);
+ write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1);
+ break;
+ case 6: /* m78dBm */
+ write_phy_ofdm(dev, 0x17, 0x56); mdelay(1);
+ write_phy_ofdm(dev, 0x24, 0x96); mdelay(1);
+ write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1);
+ break;
- default: //MP
- //DMESG("RTL8187 + 8225 Initial Gain State 1: -82 dBm (default)\n");
- write_phy_ofdm(dev, 0x17, 0x26); mdelay(1);
- write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
- write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1);
- break;
- }
+ case 7: /* m74dBm */
+ write_phy_ofdm(dev, 0x17, 0x56); mdelay(1);
+ write_phy_ofdm(dev, 0x24, 0xa6); mdelay(1);
+ write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1);
break;
+ case 8:
+ write_phy_ofdm(dev, 0x17, 0x66); mdelay(1);
+ write_phy_ofdm(dev, 0x24, 0xb6); mdelay(1);
+ write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1);
+ break;
- default:
- DMESG("UpdateInitialGain(): unknown RFChipID: %#X\n", priv->rf_chip);
+ default: /* MP */
+ write_phy_ofdm(dev, 0x17, 0x26); mdelay(1);
+ write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
+ write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1);
break;
}
}
@@ -1379,13 +856,11 @@ InitTxPwrTracking87SE(
struct net_device *dev
)
{
- //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
u32 u4bRfReg;
u4bRfReg = RF_ReadReg(dev, 0x02);
// Enable Thermal meter indication.
- //printk("InitTxPwrTracking87SE(): Enable thermal meter indication, Write RF[0x02] = %#x", u4bRfReg|PWR_METER_EN);
RF_WriteReg(dev, 0x02, u4bRfReg|PWR_METER_EN); mdelay(1);
}
@@ -1397,21 +872,14 @@ PhyConfig8185(
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
write_nic_dword(dev, RCR, priv->ReceiveConfig);
priv->RFProgType = read_nic_byte(dev, CONFIG4) & 0x03;
- // RF config
- switch(priv->rf_chip)
- {
- case RF_ZEBRA2:
- case RF_ZEBRA4:
- ZEBRA_Config_85BASIC_HardCode( dev);
- break;
- }
+ /* RF config */
+ ZEBRA_Config_85BASIC_HardCode(dev);
//{by amy 080312
// Set default initial gain state to 4, approved by SD3 DZ, by Bruce, 2007-06-06.
if(priv->bDigMechanism)
{
if(priv->InitialGain == 0)
priv->InitialGain = 4;
- //printk("PhyConfig8185(): DIG is enabled, set default initial gain index to %d\n", priv->InitialGain);
}
//
@@ -1429,34 +897,17 @@ PhyConfig8185(
return;
}
-
-
-
void
HwConfigureRTL8185(
struct net_device *dev
)
{
//RTL8185_TODO: Determine Retrylimit, TxAGC, AutoRateFallback control.
-// u8 bUNIVERSAL_CONTROL_RL = 1;
u8 bUNIVERSAL_CONTROL_RL = 0;
-
u8 bUNIVERSAL_CONTROL_AGC = 1;
u8 bUNIVERSAL_CONTROL_ANT = 1;
u8 bAUTO_RATE_FALLBACK_CTL = 1;
u8 val8;
- //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- //struct ieee80211_device *ieee = priv->ieee80211;
- //if(IS_WIRELESS_MODE_A(dev) || IS_WIRELESS_MODE_G(dev))
-//{by amy 080312 if((ieee->mode == IEEE_G)||(ieee->mode == IEEE_A))
-// {
-// write_nic_word(dev, BRSR, 0xffff);
-// }
-// else
-// {
-// write_nic_word(dev, BRSR, 0x000f);
-// }
-//by amy 080312}
write_nic_word(dev, BRSR, 0x0fff);
// Retry limit
val8 = read_nic_byte(dev, CW_CONF);
@@ -1507,20 +958,11 @@ HwConfigureRTL8185(
val8 |= RATE_FALLBACK_CTL_ENABLE | RATE_FALLBACK_CTL_AUTO_STEP1;
// <RJ_TODO_8185B> We shall set up the ARFR according to user's setting.
- //write_nic_word(dev, ARFR, 0x0fff); // set 1M ~ 54M
-//by amy
- // Aadded by Roger, 2007.11.15.
PlatformIOWrite2Byte(dev, ARFR, 0x0fff); //set 1M ~ 54Mbps.
-//by amy
- }
- else
- {
}
write_nic_byte(dev, RATE_FALLBACK, val8);
}
-
-
static void
MacConfig_85BASIC_HardCode(
struct net_device *dev)
@@ -1548,14 +990,11 @@ MacConfig_85BASIC_HardCode(
{
u4bRegOffset |= (u4bPageIndex << 8);
}
- //DbgPrint("MAC - 0x%x = 0x%x\n", u4bRegOffset, u4bRegValue);
write_nic_byte(dev, u4bRegOffset, (u8)u4bRegValue);
}
//============================================================================
}
-
-
static void
MacConfig_85BASIC(
struct net_device *dev)
@@ -1578,8 +1017,6 @@ MacConfig_85BASIC(
PlatformIOWrite1Byte(dev, 0x1F8, 0x00);
// Asked for by SD3 CM Lin, 2006.06.27, by rcnjko.
- //PlatformIOWrite4Byte(dev, RFTiming, 0x00004001);
-//by amy
// power save parameter based on "87SE power save parameters 20071127.doc", as follow.
//Enable DA10 TX power saving
@@ -1598,35 +1035,18 @@ MacConfig_85BASIC(
write_nic_word(dev, 0x378, 0x0560);
write_nic_word(dev, 0x37A, 0x0560);
write_nic_word(dev, 0x37C, 0x00EC);
-// write_nic_word(dev, 0x37E, 0x00FE);//-edward
write_nic_word(dev, 0x37E, 0x00EC);//+edward
write_nic_byte(dev, 0x24E,0x01);
-//by amy
-
}
-
-
-
u8
GetSupportedWirelessMode8185(
struct net_device *dev
)
{
u8 btSupportedWirelessMode = 0;
- struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
-
- switch(priv->rf_chip)
- {
- case RF_ZEBRA2:
- case RF_ZEBRA4:
- btSupportedWirelessMode = (WIRELESS_MODE_B | WIRELESS_MODE_G);
- break;
- default:
- btSupportedWirelessMode = WIRELESS_MODE_B;
- break;
- }
+ btSupportedWirelessMode = (WIRELESS_MODE_B | WIRELESS_MODE_G);
return btSupportedWirelessMode;
}
@@ -1641,7 +1061,6 @@ ActUpdateChannelAccessSetting(
struct ieee80211_device *ieee = priv->ieee80211;
AC_CODING eACI;
AC_PARAM AcParam;
- //PSTA_QOS pStaQos = Adapter->MgntInfo.pStaQos;
u8 bFollowLegacySetting = 0;
u8 u1bAIFS;
@@ -1663,40 +1082,14 @@ ActUpdateChannelAccessSetting(
ChnlAccessSetting->CWmaxIndex = 7; // 2006.06.02, by rcnjko.
write_nic_byte(dev, SIFS, ChnlAccessSetting->SIFS_Timer);
- //Adapter->HalFunc.SetHwRegHandler( Adapter, HW_VAR_SLOT_TIME, &ChnlAccessSetting->SlotTimeTimer ); // Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29.
write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer); // Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29.
u1bAIFS = aSifsTime + (2 * ChnlAccessSetting->SlotTimeTimer );
- //write_nic_byte(dev, AC_VO_PARAM, u1bAIFS);
- //write_nic_byte(dev, AC_VI_PARAM, u1bAIFS);
- //write_nic_byte(dev, AC_BE_PARAM, u1bAIFS);
- //write_nic_byte(dev, AC_BK_PARAM, u1bAIFS);
-
write_nic_byte(dev, EIFS, ChnlAccessSetting->EIFS_Timer);
write_nic_byte(dev, AckTimeOutReg, 0x5B); // <RJ_EXPR_QOS> Suggested by wcchu, it is the default value of EIFS register, 2005.12.08.
-#ifdef TODO
- // <RJ_TODO_NOW_8185B> Update ECWmin/ECWmax, AIFS, TXOP Limit of each AC to the value defined by SPEC.
- if( pStaQos->CurrentQosMode > QOS_DISABLE )
- { // QoS mode.
- if(pStaQos->QBssWirelessMode == WirelessMode)
- {
- // Follow AC Parameters of the QBSS.
- for(eACI = 0; eACI < AC_MAX; eACI++)
- {
- Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_AC_PARAM, (pu1Byte)(&(pStaQos->WMMParamEle.AcParam[eACI])) );
- }
- }
- else
- {
- // Follow Default WMM AC Parameters.
- bFollowLegacySetting = 1;
- }
- }
- else
-#endif
{ // Legacy 802.11.
bFollowLegacySetting = 1;
@@ -1719,14 +1112,12 @@ ActUpdateChannelAccessSetting(
AcParam.f.TXOPLimit = 0;
//lzm reserved 080826
-#if 1
// For turbo mode setting. port from 87B by Isaiah 2008-08-01
if( ieee->current_network.Turbo_Enable == 1 )
AcParam.f.TXOPLimit = 0x01FF;
// For 87SE with Intel 4965 Ad-Hoc mode have poor throughput (19MB)
if (ieee->iw_mode == IW_MODE_ADHOC)
AcParam.f.TXOPLimit = 0x0020;
-#endif
for(eACI = 0; eACI < AC_MAX; eACI++)
{
@@ -1770,18 +1161,13 @@ ActUpdateChannelAccessSetting(
// Cehck ACM bit.
// If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13.
- //write_nic_byte(dev, ACM_CONTROL, pAcParam->f.AciAifsn);
{
PACI_AIFSN pAciAifsn = (PACI_AIFSN)(&pAcParam->f.AciAifsn);
AC_CODING eACI = pAciAifsn->f.ACI;
//modified Joseph
//for 8187B AsynIORead issue
-#ifdef TODO
- u8 AcmCtrl = pHalData->AcmControl;
-#else
u8 AcmCtrl = 0;
-#endif
if( pAciAifsn->f.ACM )
{ // ACM bit is 1.
switch(eACI)
@@ -1823,19 +1209,10 @@ ActUpdateChannelAccessSetting(
break;
}
}
-
- //printk(KERN_WARNING "SetHwReg8185(): [HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl);
-
-#ifdef TO_DO
- pHalData->AcmControl = AcmCtrl;
-#endif
- //write_nic_byte(dev, ACM_CONTROL, AcmCtrl);
write_nic_byte(dev, ACM_CONTROL, 0);
}
}
}
-
-
}
}
@@ -1847,7 +1224,6 @@ ActSetWirelessMode8185(
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee80211;
- //PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo);
u8 btSupportedWirelessMode = GetSupportedWirelessMode8185(dev);
if( (btWirelessMode & btSupportedWirelessMode) == 0 )
@@ -1880,24 +1256,11 @@ ActSetWirelessMode8185(
}
}
-
- // 2. Swtich band: RF or BB specific actions,
- // for example, refresh tables in omc8255, or change initial gain if necessary.
- switch(priv->rf_chip)
- {
- case RF_ZEBRA2:
- case RF_ZEBRA4:
- {
- // Nothing to do for Zebra to switch band.
- // Update current wireless mode if we swtich to specified band successfully.
- ieee->mode = (WIRELESS_MODE)btWirelessMode;
- }
- break;
-
- default:
- DMESGW("ActSetWirelessMode8185(): unsupported RF: 0x%X !!!\n", priv->rf_chip);
- break;
- }
+ /* 2. Swtich band: RF or BB specific actions,
+ * for example, refresh tables in omc8255, or change initial gain if necessary.
+ * Nothing to do for Zebra to switch band.
+ * Update current wireless mode if we swtich to specified band successfully. */
+ ieee->mode = (WIRELESS_MODE)btWirelessMode;
// 3. Change related setting.
if( ieee->mode == WIRELESS_MODE_A ){
@@ -1909,7 +1272,6 @@ ActSetWirelessMode8185(
else if( ieee->mode == WIRELESS_MODE_G ){
DMESG("WIRELESS_MODE_G\n");
}
-
ActUpdateChannelAccessSetting( dev, ieee->mode, &priv->ChannelAccessSetting);
}
@@ -1927,11 +1289,7 @@ DrvIFIndicateDisassociation(
u16 reason
)
{
- //printk("==> DrvIFIndicateDisassociation()\n");
-
// nothing is needed after disassociation request.
-
- //printk("<== DrvIFIndicateDisassociation()\n");
}
void
MgntDisconnectIBSS(
@@ -1941,11 +1299,7 @@ MgntDisconnectIBSS(
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
u8 i;
- //printk("XXXXXXXXXX MgntDisconnect IBSS\n");
-
DrvIFIndicateDisassociation(dev, unspec_reason);
-
-// PlatformZeroMemory( pMgntInfo->Bssid, 6 );
for(i=0;i<6;i++) priv->ieee80211->current_network.bssid[i] = 0x55;
priv->ieee80211->state = IEEE80211_NOLINK;
@@ -1957,16 +1311,10 @@ MgntDisconnectIBSS(
// Because Bcn DMA isn't complete, mgnt queue would stuck until Bcn packet send.
// Disable Beacon Queue Own bit, suggested by jong
-// Adapter->HalFunc.SetTxDescOWNHandler(Adapter, BEACON_QUEUE, 0, 0);
ieee80211_stop_send_beacons(priv->ieee80211);
priv->ieee80211->link_change(dev);
notify_wx_assoc_event(priv->ieee80211);
-
- // Stop SW Beacon.Use hw beacon so do not need to do so.by amy
-
-// MgntIndicateMediaStatus( Adapter, RT_MEDIA_DISCONNECT, GENERAL_INDICATE );
-
}
void
MlmeDisassociateRequest(
@@ -1986,14 +1334,8 @@ MlmeDisassociateRequest(
DrvIFIndicateDisassociation(dev, unspec_reason);
- // pMgntInfo->AsocTimestamp = 0;
for(i=0;i<6;i++) priv->ieee80211->current_network.bssid[i] = 0x22;
-// pMgntInfo->mBrates.Length = 0;
-// Adapter->HalFunc.SetHwRegHandler( Adapter, HW_VAR_BASIC_RATE, (pu1Byte)(&pMgntInfo->mBrates) );
-
ieee80211_disassociate(priv->ieee80211);
-
-
}
}
@@ -2011,23 +1353,12 @@ MgntDisconnectAP(
// I move SecClearAllKeys() to MgntActSet_802_11_DISASSOCIATE().
//
// //2004/09/15, kcwu, the key should be cleared, or the new handshaking will not success
-// SecClearAllKeys(Adapter);
// In WPA WPA2 need to Clear all key ... because new key will set after new handshaking.
-#ifdef TODO
- if( pMgntInfo->SecurityInfo.AuthMode > RT_802_11AuthModeAutoSwitch ||
- (pMgntInfo->bAPSuportCCKM && pMgntInfo->bCCX8021xenable) ) // In CCKM mode will Clear key
- {
- SecClearAllKeys(Adapter);
- RT_TRACE(COMP_SEC, DBG_LOUD,("======>CCKM clear key..."))
- }
-#endif
// 2004.10.11, by rcnjko.
- //MlmeDisassociateRequest( Adapter, pMgntInfo->Bssid, disas_lv_ss );
MlmeDisassociateRequest( dev, priv->ieee80211->current_network.bssid, asRsn );
priv->ieee80211->state = IEEE80211_NOLINK;
-// pMgntInfo->AsocTimestamp = 0;
}
bool
MgntDisconnect(
@@ -2039,20 +1370,7 @@ MgntDisconnect(
//
// Schedule an workitem to wake up for ps mode, 070109, by rcnjko.
//
-#ifdef TODO
- if(pMgntInfo->mPss != eAwake)
- {
- //
- // Using AwkaeTimer to prevent mismatch ps state.
- // In the timer the state will be changed according to the RF is being awoke or not. By Bruce, 2007-10-31.
- //
- // PlatformScheduleWorkItem( &(pMgntInfo->AwakeWorkItem) );
- PlatformSetTimer( Adapter, &(pMgntInfo->AwakeTimer), 0 );
- }
-#endif
- // Indication of disassociation event.
- //DrvIFIndicateDisassociation(Adapter, asRsn);
if(IS_DOT11D_ENABLE(priv->ieee80211))
Dot11d_Reset(priv->ieee80211);
// In adhoc mode, update beacon frame.
@@ -2060,8 +1378,6 @@ MgntDisconnect(
{
if( priv->ieee80211->iw_mode == IW_MODE_ADHOC )
{
-// RT_TRACE(COMP_MLME, DBG_LOUD, ("MgntDisconnect() ===> MgntDisconnectIBSS\n"));
- //printk("MgntDisconnect() ===> MgntDisconnectIBSS\n");
MgntDisconnectIBSS(dev);
}
if( priv->ieee80211->iw_mode == IW_MODE_INFRA )
@@ -2071,17 +1387,10 @@ MgntDisconnect(
// e.g. OID_802_11_DISASSOCIATE in Windows while as MgntDisconnectAP() is
// used to handle disassociation related things to AP, e.g. send Disassoc
// frame to AP. 2005.01.27, by rcnjko.
-// SecClearAllKeys(Adapter);
-
-// RT_TRACE(COMP_MLME, DBG_LOUD, ("MgntDisconnect() ===> MgntDisconnectAP\n"));
- //printk("MgntDisconnect() ===> MgntDisconnectAP\n");
MgntDisconnectAP(dev, asRsn);
}
-
// Inidicate Disconnect, 2005.02.23, by rcnjko.
-// MgntIndicateMediaStatus( Adapter, RT_MEDIA_DISCONNECT, GENERAL_INDICATE);
}
-
return true;
}
//
@@ -2101,25 +1410,12 @@ SetRFPowerState(
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
bool bResult = false;
-// printk("---------> SetRFPowerState(): eRFPowerState(%d)\n", eRFPowerState);
if(eRFPowerState == priv->eRFPowerState)
{
-// printk("<--------- SetRFPowerState(): discard the request for eRFPowerState(%d) is the same.\n", eRFPowerState);
return bResult;
}
- switch(priv->rf_chip)
- {
- case RF_ZEBRA2:
- case RF_ZEBRA4:
- bResult = SetZebraRFPowerState8185(dev, eRFPowerState);
- break;
-
- default:
- printk("SetRFPowerState8185(): unknown RFChipID: 0x%X!!!\n", priv->rf_chip);
- break;;
-}
-// printk("<--------- SetRFPowerState(): bResult(%d)\n", bResult);
+ bResult = SetZebraRFPowerState8185(dev, eRFPowerState);
return bResult;
}
@@ -2149,33 +1445,25 @@ MgntActSet_RF_State(
RT_RF_POWER_STATE rtState;
u16 RFWaitCounter = 0;
unsigned long flag;
-// printk("===>MgntActSet_RF_State(): StateToSet(%d), ChangeSource(0x%x)\n",StateToSet, ChangeSource);
//
// Prevent the race condition of RF state change. By Bruce, 2007-11-28.
// Only one thread can change the RF state at one time, and others should wait to be executed.
//
-#if 1
while(true)
{
-// down(&priv->rf_state);
spin_lock_irqsave(&priv->rf_ps_lock,flag);
if(priv->RFChangeInProgress)
{
-// printk("====================>haha111111111\n");
-// up(&priv->rf_state);
-// RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State(): RF Change in progress! Wait to set..StateToSet(%d).\n", StateToSet));
spin_unlock_irqrestore(&priv->rf_ps_lock,flag);
// Set RF after the previous action is done.
while(priv->RFChangeInProgress)
{
RFWaitCounter ++;
-// RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State(): Wait 1 ms (%d times)...\n", RFWaitCounter));
udelay(1000); // 1 ms
// Wait too long, return FALSE to avoid to be stuck here.
if(RFWaitCounter > 1000) // 1sec
{
-// RT_ASSERT(FALSE, ("MgntActSet_RF_State(): Wait too logn to set RF\n"));
printk("MgntActSet_RF_State(): Wait too long to set RF\n");
// TODO: Reset RF state?
return false;
@@ -2184,17 +1472,13 @@ MgntActSet_RF_State(
}
else
{
-// printk("========================>haha2\n");
priv->RFChangeInProgress = true;
-// up(&priv->rf_state);
spin_unlock_irqrestore(&priv->rf_ps_lock,flag);
break;
}
}
-#endif
rtState = priv->eRFPowerState;
-
switch(StateToSet)
{
case eRfOn:
@@ -2215,7 +1499,6 @@ MgntActSet_RF_State(
}
}
else
-// RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State - eRfon reject pMgntInfo->RfOffReason= 0x%x, ChangeSource=0x%X\n", pMgntInfo->RfOffReason, ChangeSource));
;
break;
@@ -2232,38 +1515,26 @@ MgntActSet_RF_State(
//
// Calling MgntDisconnect() instead of MgntActSet_802_11_DISASSOCIATE(),
// because we do NOT need to set ssid to dummy ones.
- // Revised by Roger, 2007.12.04.
//
MgntDisconnect( dev, disas_lv_ss );
// Clear content of bssDesc[] and bssDesc4Query[] to avoid reporting old bss to UI.
- // 2007.05.28, by shien chang.
-// PlatformZeroMemory( pMgntInfo->bssDesc, sizeof(RT_WLAN_BSS)*MAX_BSS_DESC );
-// pMgntInfo->NumBssDesc = 0;
-// PlatformZeroMemory( pMgntInfo->bssDesc4Query, sizeof(RT_WLAN_BSS)*MAX_BSS_DESC );
-// pMgntInfo->NumBssDesc4Query = 0;
}
-
-
priv->RfOffReason |= ChangeSource;
bActionAllowed = true;
break;
-
case eRfSleep:
priv->RfOffReason |= ChangeSource;
bActionAllowed = true;
break;
-
default:
break;
}
if(bActionAllowed)
{
-// RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State(): Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n", StateToSet, pMgntInfo->RfOffReason));
// Config HW to the specified mode.
-// printk("MgntActSet_RF_State(): Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n", StateToSet, priv->RfOffReason);
SetRFPowerState(dev, StateToSet);
// Turn on RF.
@@ -2273,7 +1544,6 @@ MgntActSet_RF_State(
if(bConnectBySSID)
{
// by amy not supported
-// MgntActSet_802_11_SSID(Adapter, Adapter->MgntInfo.Ssid.Octet, Adapter->MgntInfo.Ssid.Length, TRUE );
}
}
// Turn off RF.
@@ -2282,18 +1552,11 @@ MgntActSet_RF_State(
HalDisableRx8185Dummy(dev);
}
}
- else
- {
- // printk("MgntActSet_RF_State(): Action is rejected.... StateToSet(%d), ChangeSource(%#X), RfOffReason(%#X)\n", StateToSet, ChangeSource, priv->RfOffReason);
- }
// Release RF spinlock
-// down(&priv->rf_state);
spin_lock_irqsave(&priv->rf_ps_lock,flag);
priv->RFChangeInProgress = false;
-// up(&priv->rf_state);
spin_unlock_irqrestore(&priv->rf_ps_lock,flag);
-// printk("<===MgntActSet_RF_State()\n");
return bActionAllowed;
}
void
@@ -2302,15 +1565,12 @@ InactivePowerSave(
)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- //u8 index = 0;
-
//
// This flag "bSwRfProcessing", indicates the status of IPS procedure, should be set if the IPS workitem
// is really scheduled.
// The old code, sets this flag before scheduling the IPS workitem and however, at the same time the
// previous IPS workitem did not end yet, fails to schedule the current workitem. Thus, bSwRfProcessing
// blocks the IPS procedure of switching RF.
- // By Bruce, 2007-12-25.
//
priv->bSwRfProcessing = true;
@@ -2326,7 +1586,6 @@ InactivePowerSave(
//
// Description:
// Enter the inactive power save mode. RF will be off
-// 2007.08.17, by shien chang.
//
void
IPSEnter(
@@ -2335,13 +1594,11 @@ IPSEnter(
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
RT_RF_POWER_STATE rtState;
- //printk("==============================>enter IPS\n");
if (priv->bInactivePs)
{
rtState = priv->eRFPowerState;
//
- // Added by Bruce, 2007-12-25.
// Do not enter IPS in the following conditions:
// (1) RF is already OFF or Sleep
// (2) bSwRfProcessing (indicates the IPS is still under going)
@@ -2352,12 +1609,10 @@ IPSEnter(
if (rtState == eRfOn && !priv->bSwRfProcessing
&& (priv->ieee80211->state != IEEE80211_LINKED ))
{
- // printk("IPSEnter(): Turn off RF.\n");
priv->eInactivePowerState = eRfOff;
InactivePowerSave(dev);
}
}
-// printk("priv->eRFPowerState is %d\n",priv->eRFPowerState);
}
void
IPSLeave(
@@ -2366,20 +1621,17 @@ IPSLeave(
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
RT_RF_POWER_STATE rtState;
- //printk("===================================>leave IPS\n");
if (priv->bInactivePs)
{
rtState = priv->eRFPowerState;
if ((rtState == eRfOff || rtState == eRfSleep) && (!priv->bSwRfProcessing) && priv->RfOffReason <= RF_CHANGE_BY_IPS)
{
-// printk("IPSLeave(): Turn on RF.\n");
priv->eInactivePowerState = eRfOn;
InactivePowerSave(dev);
}
}
-// printk("priv->eRFPowerState is %d\n",priv->eRFPowerState);
}
-//by amy for power save
+
void rtl8185b_adapter_start(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
@@ -2388,75 +1640,45 @@ void rtl8185b_adapter_start(struct net_device *dev)
u8 SupportedWirelessMode;
u8 InitWirelessMode;
u8 bInvalidWirelessMode = 0;
- //int i;
u8 tmpu8;
- //u8 u1tmp,u2tmp;
u8 btCR9346;
u8 TmpU1b;
u8 btPSR;
- //rtl8180_rtx_disable(dev);
-//{by amy 080312
write_nic_byte(dev,0x24e, (BIT5|BIT6|BIT0));
-//by amy 080312}
rtl8180_reset(dev);
priv->dma_poll_mask = 0;
priv->dma_poll_stop_mask = 0;
- //rtl8180_beacon_tx_disable(dev);
-
HwConfigureRTL8185(dev);
-
write_nic_dword(dev, MAC0, ((u32*)dev->dev_addr)[0]);
write_nic_word(dev, MAC4, ((u32*)dev->dev_addr)[1] & 0xffff );
-
write_nic_byte(dev, MSR, read_nic_byte(dev, MSR) & 0xf3); // default network type to 'No Link'
-
- //write_nic_byte(dev, BRSR, 0x0); // Set BRSR= 1M
-
write_nic_word(dev, BcnItv, 100);
write_nic_word(dev, AtimWnd, 2);
-
- //PlatformEFIOWrite2Byte(dev, FEMR, 0xFFFF);
PlatformIOWrite2Byte(dev, FEMR, 0xFFFF);
-
write_nic_byte(dev, WPA_CONFIG, 0);
-
MacConfig_85BASIC(dev);
-
// Override the RFSW_CTRL (MAC offset 0x272-0x273), 2006.06.07, by rcnjko.
// BT_DEMO_BOARD type
PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x569a);
-//by amy
-//#ifdef CONFIG_RTL818X_S
- // for jong required
-// PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x9a56);
-//#endif
-//by amy
- //BT_QA_BOARD
- //PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x9a56);
//-----------------------------------------------------------------------------
// Set up PHY related.
//-----------------------------------------------------------------------------
// Enable Config3.PARAM_En to revise AnaaParm.
write_nic_byte(dev, CR9346, 0xc0); // enable config register write
-//by amy
tmpu8 = read_nic_byte(dev, CONFIG3);
write_nic_byte(dev, CONFIG3, (tmpu8 |CONFIG3_PARM_En) );
-//by amy
// Turn on Analog power.
// Asked for by William, otherwise, MAC 3-wire can't work, 2006.06.27, by rcnjko.
write_nic_dword(dev, ANAPARAM2, ANAPARM2_ASIC_ON);
write_nic_dword(dev, ANAPARAM, ANAPARM_ASIC_ON);
-//by amy
write_nic_word(dev, ANAPARAM3, 0x0010);
-//by amy
write_nic_byte(dev, CONFIG3, tmpu8);
write_nic_byte(dev, CR9346, 0x00);
-//{by amy 080312 for led
// enable EEM0 and EEM1 in 9346CR
btCR9346 = read_nic_byte(dev, CR9346);
write_nic_byte(dev, CR9346, (btCR9346|0xC0) );
@@ -2474,7 +1696,6 @@ void rtl8185b_adapter_start(struct net_device *dev)
// B-cut RF Radio on/off 5e[3]=0
btPSR = read_nic_byte(dev, PSR);
write_nic_byte(dev, PSR, (btPSR | BIT3));
-//by amy 080312 for led}
// setup initial timing for RFE.
write_nic_word(dev, RFPinsOutput, 0x0480);
SetOutputEnableOfRfPins(dev);
@@ -2537,55 +1758,19 @@ void rtl8185b_adapter_start(struct net_device *dev)
InitWirelessMode = ieee->mode;
}
//by amy for power save
-// printk("initialize ENABLE_IPS\n");
priv->eRFPowerState = eRfOff;
priv->RfOffReason = 0;
{
- // u32 tmp2;
- // u32 tmp = jiffies;
MgntActSet_RF_State(dev, eRfOn, 0);
- // tmp2 = jiffies;
- // printk("rf on cost jiffies:%lx\n", (tmp2-tmp)*1000/HZ);
}
-// DrvIFIndicateCurrentPhyStatus(priv);
//
// If inactive power mode is enabled, disable rf while in disconnected state.
- // 2007.07.16, by shien chang.
//
if (priv->bInactivePs)
{
- // u32 tmp2;
- // u32 tmp = jiffies;
MgntActSet_RF_State(dev,eRfOff, RF_CHANGE_BY_IPS);
- // tmp2 = jiffies;
- // printk("rf off cost jiffies:%lx\n", (tmp2-tmp)*1000/HZ);
-
}
-// IPSEnter(dev);
//by amy for power save
-#ifdef TODO
- // Turn off RF if necessary. 2005.08.23, by rcnjko.
- // We shall turn off RF after setting CMDR, otherwise,
- // RF will be turnned on after we enable MAC Tx/Rx.
- if(Adapter->MgntInfo.RegRfOff == TRUE)
- {
- SetRFPowerState8185(Adapter, RF_OFF);
- }
- else
- {
- SetRFPowerState8185(Adapter, RF_ON);
- }
-#endif
-
-/* //these is equal with above TODO.
- write_nic_byte(dev, CR9346, 0xc0); // enable config register write
- write_nic_byte(dev, CONFIG3, read_nic_byte(dev, CONFIG3) | CONFIG3_PARM_En);
- RF_WriteReg(dev, 0x4, 0x9FF);
- write_nic_dword(dev, ANAPARAM2, ANAPARM2_ASIC_ON);
- write_nic_dword(dev, ANAPARAM, ANAPARM_ASIC_ON);
- write_nic_byte(dev, CONFIG3, (read_nic_byte(dev, CONFIG3)&(~CONFIG3_PARM_En)));
- write_nic_byte(dev, CR9346, 0x00);
-*/
ActSetWirelessMode8185(dev, (u8)(InitWirelessMode));
@@ -2594,14 +1779,11 @@ void rtl8185b_adapter_start(struct net_device *dev)
rtl8185b_irq_enable(dev);
netif_start_queue(dev);
-
}
-
void rtl8185b_rx_enable(struct net_device *dev)
{
u8 cmd;
- //u32 rxconf;
/* for now we accept data, management & ctl frame*/
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
@@ -2613,11 +1795,6 @@ void rtl8185b_rx_enable(struct net_device *dev)
priv->ReceiveConfig = priv->ReceiveConfig | RCR_AAP;
}
- /*if(priv->ieee80211->iw_mode == IW_MODE_MASTER){
- rxconf = rxconf | (1<<ACCEPT_ALLMAC_FRAME_SHIFT);
- rxconf = rxconf | (1<<RX_CHECK_BSSID_SHIFT);
- }*/
-
if(priv->ieee80211->iw_mode == IW_MODE_MONITOR){
priv->ReceiveConfig = priv->ReceiveConfig | RCR_ACF | RCR_APWRMGT | RCR_AICV;
}
@@ -2629,9 +1806,6 @@ void rtl8185b_rx_enable(struct net_device *dev)
fix_rx_fifo(dev);
-#ifdef DEBUG_RX
- DMESG("rxconf: %x %x",priv->ReceiveConfig ,read_nic_dword(dev,RCR));
-#endif
cmd=read_nic_byte(dev,CMD);
write_nic_byte(dev,CMD,cmd | (1<<CMD_RX_ENABLE_SHIFT));
@@ -2640,9 +1814,7 @@ void rtl8185b_rx_enable(struct net_device *dev)
void rtl8185b_tx_enable(struct net_device *dev)
{
u8 cmd;
- //u8 tx_agc_ctl;
u8 byte;
- //u32 txconf;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
write_nic_dword(dev, TCR, priv->TransmitConfig);
@@ -2652,21 +1824,7 @@ void rtl8185b_tx_enable(struct net_device *dev)
fix_tx_fifo(dev);
-#ifdef DEBUG_TX
- DMESG("txconf: %x %x",priv->TransmitConfig,read_nic_dword(dev,TCR));
-#endif
-
cmd=read_nic_byte(dev,CMD);
write_nic_byte(dev,CMD,cmd | (1<<CMD_TX_ENABLE_SHIFT));
-
- //write_nic_dword(dev,TX_CONF,txconf);
-
-
-/*
- rtl8180_set_mode(dev,EPROM_CMD_CONFIG);
- write_nic_byte(dev, TX_DMA_POLLING, priv->dma_poll_mask);
- rtl8180_set_mode(dev,EPROM_CMD_NORMAL);
- */
}
-
diff --git a/drivers/staging/rtl8192e/Makefile b/drivers/staging/rtl8192e/Makefile
index 5e4aa9546b51..e032c3e1e864 100644
--- a/drivers/staging/rtl8192e/Makefile
+++ b/drivers/staging/rtl8192e/Makefile
@@ -1,13 +1,15 @@
NIC_SELECT = RTL8192E
-
EXTRA_CFLAGS += -DRTL8192E
EXTRA_CFLAGS += -std=gnu89
EXTRA_CFLAGS += -O2
EXTRA_CFLAGS += -DTHOMAS_TURBO
EXTRA_CFLAGS += -DENABLE_DOT11D
-r8192_pci-objs := \
+EXTRA_CFLAGS += -DENABLE_IPS
+EXTRA_CFLAGS += -DENABLE_LPS
+
+r8192e_pci-objs := \
r8192E_core.o \
r8180_93cx6.o \
r8192E_wx.o \
@@ -31,4 +33,5 @@ r8192_pci-objs := \
ieee80211/ieee80211_crypt_ccmp.o \
ieee80211/ieee80211_crypt_wep.o
-obj-$(CONFIG_RTL8192E) += r8192_pci.o
+obj-$(CONFIG_RTL8192E) += r8192e_pci.o
+
diff --git a/drivers/staging/rtl8192e/dot11d.h b/drivers/staging/rtl8192e/dot11d.h
index 15b7a4ba37b6..5b0e2dbc2bb8 100644
--- a/drivers/staging/rtl8192e/dot11d.h
+++ b/drivers/staging/rtl8192e/dot11d.h
@@ -1,102 +1,96 @@
-#ifndef __INC_DOT11D_H
-#define __INC_DOT11D_H
+#ifndef INC_DOT11D_H
+#define INC_DOT11D_H
#ifdef ENABLE_DOT11D
#include "ieee80211.h"
-//#define ENABLE_DOT11D
-
-//#define DOT11D_MAX_CHNL_NUM 83
-
typedef struct _CHNL_TXPOWER_TRIPLE {
u8 FirstChnl;
u8 NumChnls;
u8 MaxTxPowerInDbm;
-}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE;
+} CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE;
typedef enum _DOT11D_STATE {
DOT11D_STATE_NONE = 0,
DOT11D_STATE_LEARNED,
DOT11D_STATE_DONE,
-}DOT11D_STATE;
+} DOT11D_STATE;
+
+/**
+ * struct _RT_DOT11D_INFO
+ * @CountryIeLen: value greater than 0 if @CountryIeBuf contains
+ * valid country information element.
+ * @chanell_map: holds channel values
+ * 0 - invalid,
+ * 1 - valid (active scan),
+ * 2 - valid (passive scan)
+ * @CountryIeSrcAddr - Source AP of the country IE
+ */
typedef struct _RT_DOT11D_INFO {
- //DECLARE_RT_OBJECT(RT_DOT11D_INFO);
+ bool bEnabled;
- bool bEnabled; // dot11MultiDomainCapabilityEnabled
+ u16 CountryIeLen;
+ u8 CountryIeBuf[MAX_IE_LEN];
+ u8 CountryIeSrcAddr[6];
+ u8 CountryIeWatchdog;
- u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element.
- u8 CountryIeBuf[MAX_IE_LEN];
- u8 CountryIeSrcAddr[6]; // Source AP of the country IE.
- u8 CountryIeWatchdog;
-
- u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan)
- //u8 ChnlListLen; // #Bytes valid in ChnlList[].
- //u8 ChnlList[DOT11D_MAX_CHNL_NUM];
- u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1];
+ u8 channel_map[MAX_CHANNEL_NUMBER+1];
+ u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1];
DOT11D_STATE State;
-}RT_DOT11D_INFO, *PRT_DOT11D_INFO;
-#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 )
-#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5])
-#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo))
+} RT_DOT11D_INFO, *PRT_DOT11D_INFO;
+
+#define eqMacAddr(a, b) (((a)[0] == (b)[0] && (a)[1] == (b)[1] && (a)[2] == \
+ (b)[2] && (a)[3] == (b)[3] && (a)[4] == (b)[4] && \
+ (a)[5] == (b)[5]) ? 1 : 0)
+
+#define cpMacAddr(des, src) ((des)[0] = (src)[0], (des)[1] = (src)[1], \
+ (des)[2] = (src)[2], (des)[3] = (src)[3], \
+ (des)[4] = (src)[4], (des)[5] = (src)[5])
+
+#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO) \
+ ((__pIeeeDev)->pDot11dInfo))
#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled
-#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0)
+#define IS_COUNTRY_IE_VALID(__pIeeeDev) \
+ (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0)
-#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
-#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
+#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) \
+ eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
+
+#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) \
+ cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa)
#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \
- (((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \
- FALSE : \
- (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length)))
+ (((__Ie).Length == 0 || (__Ie).Length != \
+ GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? FALSE : \
+ (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, \
+ (__Ie).Octet, (__Ie).Length)))
#define CIE_WATCHDOG_TH 1
#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog
#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0
#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev)
-#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE)
-
-
-void
-Dot11d_Init(
- struct ieee80211_device *dev
- );
-
-void
-Dot11d_Reset(
- struct ieee80211_device *dev
- );
-
-void
-Dot11d_UpdateCountryIe(
- struct ieee80211_device *dev,
- u8 * pTaddr,
- u16 CoutryIeLen,
- u8 * pCoutryIe
- );
-
-u8
-DOT11D_GetMaxTxPwrInDbm(
- struct ieee80211_device *dev,
- u8 Channel
- );
-
-void
-DOT11D_ScanComplete(
- struct ieee80211_device * dev
- );
-
-int IsLegalChannel(
- struct ieee80211_device * dev,
- u8 channel
-);
-
-int ToLegalChannel(
- struct ieee80211_device * dev,
- u8 channel
-);
-#endif //ENABLE_DOT11D
-#endif // #ifndef __INC_DOT11D_H
+#define IS_DOT11D_STATE_DONE(__pIeeeDev) \
+ (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE)
+
+
+void Dot11d_Init(struct ieee80211_device *dev);
+
+void Dot11d_Reset(struct ieee80211_device *dev);
+
+void Dot11d_UpdateCountryIe(struct ieee80211_device *dev, u8 *pTaddr,
+ u16 CoutryIeLen, u8 *pCoutryIe);
+
+u8 DOT11D_GetMaxTxPwrInDbm(struct ieee80211_device *dev, u8 channel);
+
+void DOT11D_ScanComplete(struct ieee80211_device *dev);
+
+int IsLegalChannel(struct ieee80211_device *dev, u8 channel);
+
+int ToLegalChannel(struct ieee80211_device *dev, u8 channel);
+
+#endif /* ENABLE_DOT11D */
+#endif /* INC_DOT11D_H */
diff --git a/drivers/staging/rtl8192e/ieee80211.h b/drivers/staging/rtl8192e/ieee80211.h
index 3ba9e9e90bda..c39249eb54b5 100644
--- a/drivers/staging/rtl8192e/ieee80211.h
+++ b/drivers/staging/rtl8192e/ieee80211.h
@@ -547,9 +547,6 @@ do { if (ieee80211_debug_level & (level)) \
/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
-
/*
* To use the debug system;
*
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211.h b/drivers/staging/rtl8192e/ieee80211/ieee80211.h
index aa76390487bb..1f613a28152f 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211.h
@@ -35,6 +35,7 @@
#endif
#include <linux/timer.h>
#include <linux/sched.h>
+#include <linux/semaphore.h>
#include <linux/delay.h>
#include <linux/wireless.h>
@@ -180,6 +181,8 @@ typedef struct cb_desc {
u8 DrvAggrNum;
u16 pkt_size;
u8 reserved12;
+
+ u8 bdhcp;
}cb_desc, *pcb_desc;
/*--------------------------Define -------------------------------------------*/
@@ -615,9 +618,6 @@ do { if (ieee80211_debug_level & (level)) \
/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
-
/*
* To use the debug system;
*
@@ -743,6 +743,8 @@ struct ieee80211_snap_hdr {
#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS)
#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
+#define WLAN_FC_MORE_DATA(fc) ((fc) & IEEE80211_FCTL_MOREDATA)
+
#define WLAN_FC_GET_FRAMETYPE(fc) ((fc) & IEEE80211_FCTL_FRAMETYPE)
#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
@@ -1055,7 +1057,7 @@ struct ieee80211_device;
#define SEC_ALG_NONE 0
#define SEC_ALG_WEP 1
#define SEC_ALG_TKIP 2
-#define SEC_ALG_CCMP 3
+#define SEC_ALG_CCMP 4
#define WEP_KEYS 4
#define WEP_KEY_LEN 13
@@ -1124,6 +1126,14 @@ enum ieee80211_mfie {
/* Minimal header; can be used for passing 802.11 frames with sufficient
* information to determine what type of underlying data type is actually
* stored in the data. */
+ struct ieee80211_pspoll_hdr {
+ __le16 frame_ctl;
+ __le16 aid;
+ u8 bssid[ETH_ALEN];
+ u8 ta[ETH_ALEN];
+ //u8 payload[0];
+} __attribute__ ((packed));
+
struct ieee80211_hdr {
__le16 frame_ctl;
__le16 duration_id;
@@ -1660,6 +1670,7 @@ struct ieee80211_network {
bool ralink_cap_exist;
bool atheros_cap_exist;
bool cisco_cap_exist;
+ bool marvell_cap_exist;
bool unknown_cap_exist;
// u8 berp_info;
bool berp_info_valid;
@@ -1865,6 +1876,19 @@ typedef struct _RT_POWER_SAVE_CONTROL
// Leisre Poswer Save : Disable RF if connected but traffic is not busy
//
bool bLeisurePs;
+ u32 PowerProfile;
+ u8 LpsIdleCount;
+ u8 RegMaxLPSAwakeIntvl;
+ u8 LPSAwakeIntvl;
+
+ u32 CurPsLevel;
+ u32 RegRfPsLevel;
+
+ bool bFwCtrlLPS;
+ u8 FWCtrlPSMode;
+
+ bool LinkReqInIPSRFOffPgs;
+ bool BufConnectinfoBefore;
}RT_POWER_SAVE_CONTROL,*PRT_POWER_SAVE_CONTROL;
@@ -1905,14 +1929,121 @@ typedef struct _RT_LINK_DETECT_T{
u32 NumTxOkInPeriod;
u32 NumRxOkInPeriod;
+ u32 NumRxUnicastOkInPeriod;
bool bBusyTraffic;
}RT_LINK_DETECT_T, *PRT_LINK_DETECT_T;
+//added by amy 090330
+typedef enum _HW_VARIABLES{
+ HW_VAR_ETHER_ADDR,
+ HW_VAR_MULTICAST_REG,
+ HW_VAR_BASIC_RATE,
+ HW_VAR_BSSID,
+ HW_VAR_MEDIA_STATUS,
+ HW_VAR_SECURITY_CONF,
+ HW_VAR_BEACON_INTERVAL,
+ HW_VAR_ATIM_WINDOW,
+ HW_VAR_LISTEN_INTERVAL,
+ HW_VAR_CS_COUNTER,
+ HW_VAR_DEFAULTKEY0,
+ HW_VAR_DEFAULTKEY1,
+ HW_VAR_DEFAULTKEY2,
+ HW_VAR_DEFAULTKEY3,
+ HW_VAR_SIFS,
+ HW_VAR_DIFS,
+ HW_VAR_EIFS,
+ HW_VAR_SLOT_TIME,
+ HW_VAR_ACK_PREAMBLE,
+ HW_VAR_CW_CONFIG,
+ HW_VAR_CW_VALUES,
+ HW_VAR_RATE_FALLBACK_CONTROL,
+ HW_VAR_CONTENTION_WINDOW,
+ HW_VAR_RETRY_COUNT,
+ HW_VAR_TR_SWITCH,
+ HW_VAR_COMMAND, // For Command Register, Annie, 2006-04-07.
+ HW_VAR_WPA_CONFIG, //2004/08/23, kcwu, for 8187 Security config
+ HW_VAR_AMPDU_MIN_SPACE, // The spacing between sub-frame. Roger, 2008.07.04.
+ HW_VAR_SHORTGI_DENSITY, // The density for shortGI. Roger, 2008.07.04.
+ HW_VAR_AMPDU_FACTOR,
+ HW_VAR_MCS_RATE_AVAILABLE,
+ HW_VAR_AC_PARAM, // For AC Parameters, 2005.12.01, by rcnjko.
+ HW_VAR_ACM_CTRL, // For ACM Control, Annie, 2005-12-13.
+ HW_VAR_DIS_Req_Qsize, // For DIS_Reg_Qsize, Joseph
+ HW_VAR_CCX_CHNL_LOAD, // For CCX 2 channel load request, 2006.05.04.
+ HW_VAR_CCX_NOISE_HISTOGRAM, // For CCX 2 noise histogram request, 2006.05.04.
+ HW_VAR_CCX_CLM_NHM, // For CCX 2 parallel channel load request and noise histogram request, 2006.05.12.
+ HW_VAR_TxOPLimit, // For turbo mode related settings, added by Roger, 2006.12.07
+ HW_VAR_TURBO_MODE, // For turbo mode related settings, added by Roger, 2006.12.15.
+ HW_VAR_RF_STATE, // For change or query RF power state, 061214, rcnjko.
+ HW_VAR_RF_OFF_BY_HW, // For UI to query if external HW signal disable RF, 061229, rcnjko.
+ HW_VAR_BUS_SPEED, // In unit of bps. 2006.07.03, by rcnjko.
+ HW_VAR_SET_DEV_POWER, // Set to low power, added by LanHsin, 2007.
+
+ //1!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ //1Attention Please!!!<11n or 8190 specific code should be put below this line>
+ //1!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ HW_VAR_RCR, //for RCR, David 2006,05,11
+ HW_VAR_RATR_0,
+ HW_VAR_RRSR,
+ HW_VAR_CPU_RST,
+ HW_VAR_CECHK_BSSID,
+ HW_VAR_LBK_MODE, // Set lookback mode, 2008.06.11. added by Roger.
+ // Set HW related setting for 11N AES bug.
+ HW_VAR_AES_11N_FIX,
+ // Set Usb Rx Aggregation
+ HW_VAR_USB_RX_AGGR,
+ HW_VAR_USER_CONTROL_TURBO_MODE,
+ HW_VAR_RETRY_LIMIT,
+#ifndef _RTL8192_EXT_PATCH_
+ HW_VAR_INIT_TX_RATE, //Get Current Tx rate register. 2008.12.10. Added by tynli
+#endif
+ HW_VAR_TX_RATE_REG, //Get Current Tx rate register. 2008.12.10. Added by tynli
+ HW_VAR_EFUSE_USAGE, //Get current EFUSE utilization. 2008.12.19. Added by Roger.
+ HW_VAR_EFUSE_BYTES,
+ HW_VAR_AUTOLOAD_STATUS, //Get current autoload status, 0: autoload success, 1: autoload fail. 2008.12.19. Added by Roger.
+ HW_VAR_RF_2R_DISABLE, // 2R disable
+ HW_VAR_SET_RPWM,
+ HW_VAR_H2C_FW_PWRMODE, // For setting FW related H2C cmd structure. by tynli. 2009.2.18
+ HW_VAR_H2C_FW_JOINBSSRPT, // For setting FW related H2C cmd structure. by tynli. 2009.2.18
+ HW_VAR_1X1_RECV_COMBINE, // For 1T2R but only 1SS, Add by hpfan 2009.04.16 hpfan
+ HW_VAR_STOP_SEND_BEACON,
+ HW_VAR_TSF_TIMER, // Read from TSF register to get the current TSF timer, by Bruce, 2009-07-22.
+ HW_VAR_IO_CMD,
+ HW_VAR_HANDLE_FW_C2H, //Added by tynli. For handling FW C2H command. 2009.10.07.
+ HW_VAR_DL_FW_RSVD_PAGE, //Added by tynli. Download the packets that FW will use to RSVD page. 2009.10.14.
+ HW_VAR_AID, //Added by tynli.
+ HW_VAR_HW_SEQ_ENABLE, //Added by tynli. 2009.10.20.
+ HW_VAR_UPDATE_TSF, //Added by tynli. 2009.10.22. For Hw count TBTT time.
+ HW_VAR_BCN_VALID, //Added by tynli.
+ HW_VAR_FWLPS_RF_ON //Added by tynli. 2009.11.09. For checking if Fw finishs RF on sequence.
+}HW_VARIABLES;
+
+#define RT_CHECK_FOR_HANG_PERIOD 2
struct ieee80211_device {
struct net_device *dev;
struct ieee80211_security sec;
+ bool need_sw_enc;
+#ifdef ENABLE_LPS
+ bool bAwakePktSent;
+ u8 LPSDelayCnt;
+ bool bIsAggregateFrame;
+ bool polling;
+ void (*LeisurePSLeave)(struct net_device *dev);
+#endif
+
+#ifdef ENABLE_IPS
+ bool proto_stoppping;
+ bool wx_set_enc;
+ struct semaphore ips_sem;
+ struct work_struct ips_leave_wq;
+ void (*ieee80211_ips_leave_wq) (struct net_device *dev);
+ void (*ieee80211_ips_leave)(struct net_device *dev);
+#endif
+ void (*SetHwRegHandler)(struct net_device *dev,u8 variable,u8* val);
+ u8 (*rtllib_ap_sec_type)(struct ieee80211_device *ieee);
+
//hw security related
// u8 hwsec_support; //support?
u8 hwsec_active; //hw security active.
@@ -2319,7 +2450,7 @@ struct ieee80211_device {
* stop_send_bacons is NOT guaranteed to be called only
* after start_send_beacons.
*/
- void (*start_send_beacons) (struct net_device *dev,u16 tx_rate);
+ void (*start_send_beacons) (struct net_device *dev);
void (*stop_send_beacons) (struct net_device *dev);
/* power save mode related */
@@ -2373,6 +2504,19 @@ struct ieee80211_device {
u8 priv[0];
};
+#define RT_RF_OFF_LEVL_ASPM BIT0 // PCI ASPM
+#define RT_RF_OFF_LEVL_CLK_REQ BIT1 // PCI clock request
+#define RT_RF_OFF_LEVL_PCI_D3 BIT2 // PCI D3 mode
+#define RT_RF_OFF_LEVL_HALT_NIC BIT3 // NIC halt, re-initialize hw parameters
+#define RT_RF_OFF_LEVL_FREE_FW BIT4 // FW free, re-download the FW
+#define RT_RF_OFF_LEVL_FW_32K BIT5 // FW in 32k
+#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT6 // Always enable ASPM and Clock Req in initialization.
+#define RT_RF_LPS_DISALBE_2R BIT30 // When LPS is on, disable 2R if no packet is received or transmittd.
+#define RT_RF_LPS_LEVEL_ASPM BIT31 // LPS with ASPM
+#define RT_IN_PS_LEVEL(pPSC, _PS_FLAG) ((pPSC->CurPsLevel & _PS_FLAG) ? true : false)
+#define RT_CLEAR_PS_LEVEL(pPSC, _PS_FLAG) (pPSC->CurPsLevel &= (~(_PS_FLAG)))
+#define RT_SET_PS_LEVEL(pPSC, _PS_FLAG) (pPSC->CurPsLevel |= _PS_FLAG)
+
#define IEEE_A (1<<0)
#define IEEE_B (1<<1)
#define IEEE_G (1<<2)
@@ -2609,9 +2753,9 @@ extern void ieee80211_stop_scan(struct ieee80211_device *ieee);
extern void ieee80211_start_scan_syncro(struct ieee80211_device *ieee);
extern void ieee80211_check_all_nets(struct ieee80211_device *ieee);
extern void ieee80211_start_protocol(struct ieee80211_device *ieee);
-extern void ieee80211_stop_protocol(struct ieee80211_device *ieee);
+extern void ieee80211_stop_protocol(struct ieee80211_device *ieee,u8 shutdown);
extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee);
-extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee);
+extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee,u8 shutdown);
extern void ieee80211_reset_queue(struct ieee80211_device *ieee);
extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee);
extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee);
@@ -2798,5 +2942,7 @@ extern int ieee80211_parse_info_param(struct ieee80211_device *ieee,
struct ieee80211_rx_stats *stats);
void ieee80211_indicate_packets(struct ieee80211_device *ieee, struct ieee80211_rxb** prxbIndicateArray,u8 index);
+void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr);
+void ieee80211_sta_ps_send_pspoll_frame(struct ieee80211_device *ieee);
#define RT_ASOC_RETRY_LIMIT 5
#endif /* IEEE80211_H */
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.c
index b1c54932da3e..b3c9bf4b4ea6 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.c
@@ -225,7 +225,7 @@ out:
}
-void __exit ieee80211_crypto_deinit(void)
+void ieee80211_crypto_deinit(void)
{
struct list_head *ptr, *n;
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_ccmp.c
index ab871b360b5d..1776f7e69bfe 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_ccmp.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_ccmp.c
@@ -331,7 +331,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (!(keyidx & (1 << 5))) {
if (net_ratelimit()) {
printk(KERN_DEBUG "CCMP: received packet without ExtIV"
- " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ " flag from %pM\n", hdr->addr2);
}
key->dot11RSNAStatsCCMPFormatErrors++;
return -2;
@@ -344,9 +344,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
if (!key->key_set) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT
+ printk(KERN_DEBUG "CCMP: received packet from %pM"
" with keyid=%d that does not have a configured"
- " key\n", MAC_ARG(hdr->addr2), keyidx);
+ " key\n", hdr->addr2, keyidx);
}
return -3;
}
@@ -361,11 +361,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
- " previous PN %02x%02x%02x%02x%02x%02x "
- "received PN %02x%02x%02x%02x%02x%02x\n",
- MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn),
- MAC_ARG(pn));
+ //printk(KERN_DEBUG "CCMP: replay detected: STA=%pM"
+ // " previous PN %pm received PN %pm\n",
+ // hdr->addr2, key->rx_pn, pn);
}
key->dot11RSNAStatsCCMPReplays++;
return -4;
@@ -402,7 +400,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
if (net_ratelimit()) {
printk(KERN_DEBUG "CCMP: decrypt failed: STA="
- MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ "%pM\n", hdr->addr2);
}
key->dot11RSNAStatsCCMPDecryptErrors++;
return -5;
@@ -477,12 +475,19 @@ static int ieee80211_ccmp_get_key(void *key, int len, u8 *seq, void *priv)
static char * ieee80211_ccmp_print_stats(char *p, void *priv)
{
struct ieee80211_ccmp_data *ccmp = priv;
- p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
- "tx_pn=%02x%02x%02x%02x%02x%02x "
- "rx_pn=%02x%02x%02x%02x%02x%02x "
- "format_errors=%d replays=%d decrypt_errors=%d\n",
- ccmp->key_idx, ccmp->key_set,
- MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn),
+ int i;
+
+ p += sprintf(p, "key[%d] alg=CCMP key_set=%d tx_pn=",
+ ccmp->key_idx, ccmp->key_set);
+
+ for (i = 0; i < ARRAY_SIZE(ccmp->tx_pn); i++)
+ p += sprintf(p, "%02x", ccmp->tx_pn[i]);
+
+ sprintf(p, " rx_pn=");
+ for (i = 0; i < ARRAY_SIZE(ccmp->rx_pn); i++)
+ p += sprintf(p, "%02x", ccmp->tx_pn[i]);
+
+ p += sprintf(p, " format_errors=%d replays=%d decrypt_errors=%d\n",
ccmp->dot11RSNAStatsCCMPFormatErrors,
ccmp->dot11RSNAStatsCCMPReplays,
ccmp->dot11RSNAStatsCCMPDecryptErrors);
@@ -519,7 +524,7 @@ int __init ieee80211_crypto_ccmp_init(void)
}
-void __exit ieee80211_crypto_ccmp_exit(void)
+void ieee80211_crypto_ccmp_exit(void)
{
ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp);
}
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_tkip.c
index 7a1797e6cbec..03cb21eb0658 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_tkip.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_tkip.c
@@ -520,7 +520,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (!(keyidx & (1 << 5))) {
if (net_ratelimit()) {
printk(KERN_DEBUG "TKIP: received packet without ExtIV"
- " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ " flag from %pM\n", hdr->addr2);
}
return -2;
}
@@ -532,9 +532,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
if (!tkey->key_set) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT
+ printk(KERN_DEBUG "TKIP: received packet from %pM"
" with keyid=%d that does not have a configured"
- " key\n", MAC_ARG(hdr->addr2), keyidx);
+ " key\n", hdr->addr2, keyidx);
}
return -3;
}
@@ -547,9 +547,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (iv32 < tkey->rx_iv32 ||
(iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
+ printk(KERN_DEBUG "TKIP: replay detected: STA=%pM"
" previous TSC %08x%04x received TSC "
- "%08x%04x\n", MAC_ARG(hdr->addr2),
+ "%08x%04x\n", hdr->addr2,
tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
}
tkey->dot11RSNAStatsTKIPReplays++;
@@ -582,8 +582,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
if (net_ratelimit()) {
printk(KERN_DEBUG ": TKIP: failed to decrypt "
- "received packet from " MAC_FMT "\n",
- MAC_ARG(hdr->addr2));
+ "received packet from %pM\n",
+ hdr->addr2);
}
return -7;
}
@@ -606,8 +606,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
tkey->rx_phase1_done = 0;
}
if (net_ratelimit()) {
- printk(KERN_DEBUG "TKIP: ICV error detected: STA="
- MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ printk(KERN_DEBUG
+ "TKIP: ICV error detected: STA=%pM\n",
+ hdr->addr2);
}
tkey->dot11RSNAStatsTKIPICVErrors++;
return -5;
@@ -816,8 +817,8 @@ static void ieee80211_michael_mic_failure(struct net_device *dev,
/* TODO: needed parameters: count, keyid, key type, TSC */
sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr="
- MAC_FMT ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
- MAC_ARG(hdr->addr2));
+ "%pM)", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
+ hdr->addr2);
memset(&wrqu, 0, sizeof(wrqu));
wrqu.data.length = strlen(buf);
wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
@@ -862,8 +863,8 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
struct ieee80211_hdr_4addr *hdr;
hdr = (struct ieee80211_hdr_4addr *) skb->data;
printk(KERN_DEBUG "%s: Michael MIC verification failed for "
- "MSDU from " MAC_FMT " keyidx=%d\n",
- skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2),
+ "MSDU from %pM keyidx=%d\n",
+ skb->dev ? skb->dev->name : "N/A", hdr->addr2,
keyidx);
if (skb->dev)
ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
@@ -1011,7 +1012,7 @@ int __init ieee80211_crypto_tkip_init(void)
}
-void __exit ieee80211_crypto_tkip_exit(void)
+void ieee80211_crypto_tkip_exit(void)
{
ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip);
}
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c
index 06d91715143c..ce265ae5fe18 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c
@@ -312,6 +312,17 @@ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,
if (skb->len < 24)
return 0;
+#if 1
+ if (ieee->hwsec_active)
+ {
+ cb_desc *tcb_desc = (cb_desc *)(skb->cb+ MAX_DEV_ADDR_SIZE);
+ tcb_desc->bHwSec = 1;
+
+ if(ieee->need_sw_enc)
+ tcb_desc->bHwSec = 0;
+ }
+#endif
+
hdr = (struct ieee80211_hdr_4addr *) skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
@@ -366,8 +377,8 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb,
strcmp(crypt->ops->name, "TKIP") == 0) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "received packet from " MAC_FMT "\n",
- ieee->dev->name, MAC_ARG(hdr->addr2));
+ "received packet from %pM\n",
+ ieee->dev->name, hdr->addr2);
}
return -1;
}
@@ -378,8 +389,8 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb,
atomic_dec(&crypt->refcnt);
if (res < 0) {
IEEE80211_DEBUG_DROP(
- "decryption failed (SA=" MAC_FMT
- ") res=%d\n", MAC_ARG(hdr->addr2), res);
+ "decryption failed (SA=%pM"
+ ") res=%d\n", hdr->addr2, res);
if (res == -2)
IEEE80211_DEBUG_DROP("Decryption failed ICV "
"mismatch (key %d)\n",
@@ -406,6 +417,10 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct sk_buff *s
{
cb_desc *tcb_desc = (cb_desc *)(skb->cb+ MAX_DEV_ADDR_SIZE);
tcb_desc->bHwSec = 1;
+
+ if(ieee->need_sw_enc)
+ tcb_desc->bHwSec = 0;
+
}
hdr = (struct ieee80211_hdr_4addr *) skb->data;
@@ -416,8 +431,8 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct sk_buff *s
atomic_dec(&crypt->refcnt);
if (res < 0) {
printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
- " (SA=" MAC_FMT " keyidx=%d)\n",
- ieee->dev->name, MAC_ARG(hdr->addr2), keyidx);
+ " (SA=%pM keyidx=%d)\n",
+ ieee->dev->name, hdr->addr2, keyidx);
return -1;
}
@@ -799,7 +814,7 @@ void RxReorderIndicatePacket( struct ieee80211_device *ieee,
#endif
}
-u8 parse_subframe(struct sk_buff *skb,
+u8 parse_subframe(struct ieee80211_device* ieee,struct sk_buff *skb,
struct ieee80211_rx_stats *rx_stats,
struct ieee80211_rxb *rxb,u8* src,u8* dst)
{
@@ -839,6 +854,7 @@ u8 parse_subframe(struct sk_buff *skb,
}
skb_pull(skb, LLCOffset);
+ ieee->bIsAggregateFrame = bIsAggregateFrame;//added by amy for Leisure PS
if(!bIsAggregateFrame) {
rxb->nr_subframes = 1;
@@ -940,6 +956,7 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
u8 TID = 0;
u16 SeqNum = 0;
PRX_TS_RECORD pTS = NULL;
+ bool unicast_packet = false;
//bool bIsAggregateFrame = false;
//added by amy for reorder
#ifdef NOT_YET
@@ -1045,8 +1062,8 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
* frames silently instead of filling system log with
* these reports. */
IEEE80211_DEBUG_DROP("Decryption failed (not set)"
- " (SA=" MAC_FMT ")\n",
- MAC_ARG(hdr->addr2));
+ " (SA=%pM)\n",
+ hdr->addr2);
ieee->ieee_stats.rx_discards_undecryptable++;
goto rx_dropped;
}
@@ -1114,8 +1131,8 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
(keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0)
{
printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
- "from " MAC_FMT "\n", dev->name,
- MAC_ARG(hdr->addr2));
+ "from %pM\n", dev->name,
+ hdr->addr2);
/* TODO: could inform hostapd about this so that it
* could send auth failure report */
goto rx_dropped;
@@ -1215,6 +1232,24 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
if (memcmp(bssid, ieee->current_network.bssid, ETH_ALEN))
goto rx_dropped;
+#ifdef ENABLE_LPS
+ if ((ieee->iw_mode == IW_MODE_INFRA) && (ieee->sta_sleep == 1)
+ && (ieee->polling)) {
+ if (WLAN_FC_MORE_DATA(fc)) {
+ /* more data bit is set, let's request a new frame from the AP */
+ ieee80211_sta_ps_send_pspoll_frame(ieee);
+ } else {
+ ieee->polling = false;
+ }
+ }
+#endif
+
+ ieee->need_sw_enc = 0;
+
+ if((!rx_stats->Decrypted)){
+ ieee->need_sw_enc = 1;
+ }
+
/* skb: hdr + (possibly fragmented, possibly encrypted) payload */
if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) &&
@@ -1296,6 +1331,9 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
ieee->LinkDetectInfo.NumRxOkInPeriod++;
hdr = (struct ieee80211_hdr_4addr *) skb->data;
+ if((!is_multicast_ether_addr(hdr->addr1)) && (!is_broadcast_ether_addr(hdr->addr1)))
+ unicast_packet = true;
+
if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep) {
if (/*ieee->ieee802_1x &&*/
ieee80211_is_eapol_frame(ieee, skb, hdrlen)) {
@@ -1311,8 +1349,8 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
} else {
IEEE80211_DEBUG_DROP(
"encryption configured, but RX "
- "frame not encrypted (SA=" MAC_FMT ")\n",
- MAC_ARG(hdr->addr2));
+ "frame not encrypted (SA=%pM)\n",
+ hdr->addr2);
goto rx_dropped;
}
}
@@ -1331,9 +1369,9 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
!ieee80211_is_eapol_frame(ieee, skb, hdrlen)) {
IEEE80211_DEBUG_DROP(
"dropped unencrypted RX data "
- "frame from " MAC_FMT
+ "frame from %pM"
" (drop_unencrypted=1)\n",
- MAC_ARG(hdr->addr2));
+ hdr->addr2);
goto rx_dropped;
}
/*
@@ -1367,7 +1405,7 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
}
/* to parse amsdu packets */
/* qos data packets & reserved bit is 1 */
- if(parse_subframe(skb,rx_stats,rxb,src,dst) == 0) {
+ if(parse_subframe(ieee, skb,rx_stats,rxb,src,dst) == 0) {
/* only to free rxb, and not submit the packets to upper layer */
for(i =0; i < rxb->nr_subframes; i++) {
dev_kfree_skb(rxb->subframes[i]);
@@ -1377,6 +1415,32 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
goto rx_dropped;
}
+#ifdef ENABLE_LPS
+ if(unicast_packet)
+ {
+ if (type == IEEE80211_FTYPE_DATA)
+ {
+
+ if(ieee->bIsAggregateFrame)
+ ieee->LinkDetectInfo.NumRxUnicastOkInPeriod+=rxb->nr_subframes;
+ else
+ ieee->LinkDetectInfo.NumRxUnicastOkInPeriod++;
+
+ // 2009.03.03 Leave DC mode immediately when detect high traffic
+ // DbgPrint("ending Seq %d\n", Frame_SeqNum(pduOS));
+ if((ieee->state == IEEE80211_LINKED) /*&& !MgntInitAdapterInProgress(pMgntInfo)*/)
+ {
+ if( ((ieee->LinkDetectInfo.NumRxUnicastOkInPeriod +ieee->LinkDetectInfo.NumTxOkInPeriod) > 8 ) ||
+ (ieee->LinkDetectInfo.NumRxUnicastOkInPeriod > 2) )
+ {
+ if(ieee->LeisurePSLeave)
+ ieee->LeisurePSLeave(dev);
+ }
+ }
+ }
+ }
+#endif
+
ieee->last_rx_ps_time = jiffies;
//added by amy for reorder
if(ieee->pHTInfo->bCurRxReorderEnable == false ||pTS == NULL){
@@ -2013,12 +2077,22 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
info_element->data[1] == 0x13 &&
info_element->data[2] == 0x74))
{
- printk("========>%s(): athros AP is exist\n",__FUNCTION__);
+ //printk("========>%s(): athros AP is exist\n",__FUNCTION__);
network->atheros_cap_exist = true;
}
else
network->atheros_cap_exist = false;
+ if ((info_element->len >= 3 &&
+ info_element->data[0] == 0x00 &&
+ info_element->data[1] == 0x50 &&
+ info_element->data[2] == 0x43) )
+ {
+ network->marvell_cap_exist = true;
+ //printk("========>%s(): marvel AP is exist\n",__FUNCTION__);
+ }
+
+
if(info_element->len >= 3 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x40 &&
@@ -2219,7 +2293,8 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
}
if(!network->atheros_cap_exist && !network->broadcom_cap_exist &&
- !network->cisco_cap_exist && !network->ralink_cap_exist && !network->bssht.bdRT2RTAggregation)
+ !network->cisco_cap_exist && !network->ralink_cap_exist && !network->bssht.bdRT2RTAggregation &&
+ !network->marvell_cap_exist)
{
network->unknown_cap_exist = true;
}
@@ -2333,6 +2408,7 @@ static inline int ieee80211_network_init(
network->broadcom_cap_exist = false;
network->ralink_cap_exist = false;
network->atheros_cap_exist = false;
+ network->marvell_cap_exist = false;
network->cisco_cap_exist = false;
network->unknown_cap_exist = false;
#ifdef THOMAS_TURBO
@@ -2369,11 +2445,11 @@ static inline int ieee80211_network_init(
}
if (network->mode == 0) {
- IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' "
+ IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' "
"network.\n",
escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid));
+ network->bssid);
return 1;
}
@@ -2463,6 +2539,7 @@ static inline void update_network(struct ieee80211_network *dst,
dst->broadcom_cap_exist = src->broadcom_cap_exist;
dst->ralink_cap_exist = src->ralink_cap_exist;
dst->atheros_cap_exist = src->atheros_cap_exist;
+ dst->marvell_cap_exist = src->marvell_cap_exist;
dst->cisco_cap_exist = src->cisco_cap_exist;
dst->unknown_cap_exist = src->unknown_cap_exist;
memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len);
@@ -2557,9 +2634,9 @@ static inline void ieee80211_process_probe_response(
memset(&network, 0, sizeof(struct ieee80211_network));
IEEE80211_DEBUG_SCAN(
- "'%s' (" MAC_FMT "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
+ "'%s' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
escape_essid(info_element->data, info_element->len),
- MAC_ARG(beacon->header.addr3),
+ beacon->header.addr3,
(beacon->capability & (1<<0xf)) ? '1' : '0',
(beacon->capability & (1<<0xe)) ? '1' : '0',
(beacon->capability & (1<<0xd)) ? '1' : '0',
@@ -2578,10 +2655,10 @@ static inline void ieee80211_process_probe_response(
(beacon->capability & (1<<0x0)) ? '1' : '0');
if (ieee80211_network_init(ieee, beacon, &network, stats)) {
- IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n",
+ IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n",
escape_essid(info_element->data,
info_element->len),
- MAC_ARG(beacon->header.addr3),
+ beacon->header.addr3,
WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
@@ -2692,11 +2769,11 @@ static inline void ieee80211_process_probe_response(
/* If there are no more slots, expire the oldest */
list_del(&oldest->list);
target = oldest;
- IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from "
+ IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from "
"network list.\n",
escape_essid(target->ssid,
target->ssid_len),
- MAC_ARG(target->bssid));
+ target->bssid);
} else {
/* Otherwise just pull from the free list */
target = list_entry(ieee->network_free_list.next,
@@ -2706,10 +2783,10 @@ static inline void ieee80211_process_probe_response(
#ifdef CONFIG_IEEE80211_DEBUG
- IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n",
+ IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n",
escape_essid(network.ssid,
network.ssid_len),
- MAC_ARG(network.bssid),
+ network.bssid,
WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
@@ -2719,10 +2796,10 @@ static inline void ieee80211_process_probe_response(
if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)
ieee80211_softmac_new_net(ieee,&network);
} else {
- IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n",
+ IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
escape_essid(target->ssid,
target->ssid_len),
- MAC_ARG(target->bssid),
+ target->bssid,
WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
@@ -2761,12 +2838,14 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
struct ieee80211_hdr_4addr *header,
struct ieee80211_rx_stats *stats)
{
+#if 0
if(ieee->sta_sleep || (ieee->ps != IEEE80211_PS_DISABLED &&
ieee->iw_mode == IW_MODE_INFRA &&
ieee->state == IEEE80211_LINKED))
{
tasklet_schedule(&ieee->ps_task);
}
+#endif
if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP &&
WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON)
@@ -2780,6 +2859,15 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
IEEE80211_DEBUG_SCAN("Beacon\n");
ieee80211_process_probe_response(
ieee, (struct ieee80211_probe_response *)header, stats);
+
+ //printk("----------->%s()\n", __func__);
+ if(ieee->sta_sleep || (ieee->ps != IEEE80211_PS_DISABLED &&
+ ieee->iw_mode == IW_MODE_INFRA &&
+ ieee->state == IEEE80211_LINKED))
+ {
+ tasklet_schedule(&ieee->ps_task);
+ }
+
break;
case IEEE80211_STYPE_PROBE_RESP:
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c
index 6d1ddec39f0e..ea96c4956930 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c
@@ -646,7 +646,7 @@ void ieee80211_stop_send_beacons(struct ieee80211_device *ieee)
void ieee80211_start_send_beacons(struct ieee80211_device *ieee)
{
if(ieee->start_send_beacons)
- ieee->start_send_beacons(ieee->dev,ieee->basic_rate);
+ ieee->start_send_beacons(ieee->dev);
if(ieee->softmac_features & IEEE_SOFTMAC_BEACONS)
ieee80211_beacons_start(ieee);
}
@@ -686,6 +686,11 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee)
/* called with ieee->lock held */
void ieee80211_rtl_start_scan(struct ieee80211_device *ieee)
{
+#ifdef ENABLE_IPS
+ if(ieee->ieee80211_ips_leave_wq != NULL)
+ ieee->ieee80211_ips_leave_wq(ieee->dev);
+#endif
+
#ifdef ENABLE_DOT11D
if(IS_DOT11D_ENABLE(ieee) )
{
@@ -1093,6 +1098,40 @@ struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr)
}
+struct sk_buff* ieee80211_pspoll_func(struct ieee80211_device *ieee)
+{
+ struct sk_buff *skb;
+ struct ieee80211_pspoll_hdr* hdr;
+
+#ifdef USB_USE_ALIGNMENT
+ u32 Tmpaddr=0;
+ int alignment=0;
+ skb = dev_alloc_skb(sizeof(struct ieee80211_pspoll_hdr) + ieee->tx_headroom + USB_512B_ALIGNMENT_SIZE);
+#else
+ skb = dev_alloc_skb(sizeof(struct ieee80211_pspoll_hdr)+ieee->tx_headroom);
+#endif
+ if (!skb)
+ return NULL;
+
+#ifdef USB_USE_ALIGNMENT
+ Tmpaddr = (u32)skb->data;
+ alignment = Tmpaddr & 0x1ff;
+ skb_reserve(skb,(USB_512B_ALIGNMENT_SIZE - alignment));
+#endif
+ skb_reserve(skb, ieee->tx_headroom);
+
+ hdr = (struct ieee80211_pspoll_hdr*)skb_put(skb,sizeof(struct ieee80211_pspoll_hdr));
+
+ memcpy(hdr->bssid, ieee->current_network.bssid, ETH_ALEN);
+ memcpy(hdr->ta, ieee->dev->dev_addr, ETH_ALEN);
+
+ hdr->aid = cpu_to_le16(ieee->assoc_id | 0xc000);
+ hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_CTL |IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM);
+
+ return skb;
+
+}
+
void ieee80211_resp_to_assoc_rq(struct ieee80211_device *ieee, u8* dest)
{
@@ -1582,6 +1621,11 @@ void ieee80211_associate_procedure_wq(struct ieee80211_device *ieee)
{
#endif
ieee->sync_scan_hurryup = 1;
+#ifdef ENABLE_IPS
+ if(ieee->ieee80211_ips_leave != NULL)
+ ieee->ieee80211_ips_leave(ieee->dev);
+#endif
+
down(&ieee->wx_sem);
if (ieee->data_hard_stop)
@@ -1592,6 +1636,17 @@ void ieee80211_associate_procedure_wq(struct ieee80211_device *ieee)
//ieee->set_chan(ieee->dev, ieee->current_network.channel);
HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
+#ifdef ENABLE_IPS
+ if(ieee->eRFPowerState == eRfOff)
+ {
+ if(ieee->ieee80211_ips_leave_wq != NULL)
+ ieee->ieee80211_ips_leave_wq(ieee->dev);
+
+ up(&ieee->wx_sem);
+ return;
+ }
+#endif
+
ieee->associate_seq = 1;
ieee80211_associate_step1(ieee);
@@ -1897,7 +1952,7 @@ ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
ieee80211_resp_to_assoc_rq(ieee, dest);
}
- printk(KERN_INFO"New client associated: "MAC_FMT"\n", MAC_ARG(dest));
+ printk(KERN_INFO"New client associated: %pM\n", dest);
//FIXME
#if 0
spin_lock_irqsave(&ieee->lock,flags);
@@ -1918,43 +1973,92 @@ void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr)
}
+void ieee80211_sta_ps_send_pspoll_frame(struct ieee80211_device *ieee)
+{
+
+ struct sk_buff *buf = ieee80211_pspoll_func(ieee);
+
+ if (buf)
+ softmac_ps_mgmt_xmit(buf, ieee);
+
+}
short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h, u32 *time_l)
{
int timeout = ieee->ps_timeout;
u8 dtim;
- /*if(ieee->ps == IEEE80211_PS_DISABLED ||
- ieee->iw_mode != IW_MODE_INFRA ||
- ieee->state != IEEE80211_LINKED)
+ PRT_POWER_SAVE_CONTROL pPSC = (PRT_POWER_SAVE_CONTROL)(&(ieee->PowerSaveControl));
+ if(ieee->LPSDelayCnt)
+ {
+ //printk("===============>Delay enter LPS for DHCP and ARP packets...\n");
+ ieee->LPSDelayCnt --;
return 0;
- */
+ }
+
dtim = ieee->current_network.dtim_data;
- //printk("DTIM\n");
+// printk("%s():DTIM:%d\n",__FUNCTION__,dtim);
if(!(dtim & IEEE80211_DTIM_VALID))
return 0;
timeout = ieee->current_network.beacon_interval; //should we use ps_timeout value or beacon_interval
//printk("VALID\n");
ieee->current_network.dtim_data = IEEE80211_DTIM_INVALID;
-
- if(dtim & ((IEEE80211_DTIM_UCAST | IEEE80211_DTIM_MBCAST)& ieee->ps))
+ /* there's no need to nofity AP that I find you buffered with broadcast packet */
+ if(dtim & (IEEE80211_DTIM_UCAST & ieee->ps))
return 2;
- if(!time_after(jiffies, ieee->dev->trans_start + MSECS(timeout)))
+ if(!time_after(jiffies, ieee->dev->trans_start + MSECS(timeout))){
+// printk("%s():111Oh Oh ,it is not time out return 0\n",__FUNCTION__);
return 0;
-
- if(!time_after(jiffies, ieee->last_rx_ps_time + MSECS(timeout)))
+ }
+ if(!time_after(jiffies, ieee->last_rx_ps_time + MSECS(timeout))){
+// printk("%s():222Oh Oh ,it is not time out return 0\n",__FUNCTION__);
return 0;
-
+ }
if((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE ) &&
(ieee->mgmt_queue_tail != ieee->mgmt_queue_head))
return 0;
if(time_l){
+ if(ieee->bAwakePktSent == true) {
+ pPSC->LPSAwakeIntvl = 1;//tx wake one beacon
+ } else {
+ u8 MaxPeriod = 1;
+
+ if(pPSC->LPSAwakeIntvl == 0)
+ pPSC->LPSAwakeIntvl = 1;
+ //pNdisCommon->RegLPSMaxIntvl /// 0x0 - eFastPs, 0xFF -DTIM, 0xNN - 0xNN * BeaconIntvl
+ if(pPSC->RegMaxLPSAwakeIntvl == 0) // Default (0x0 - eFastPs, 0xFF -DTIM, 0xNN - 0xNN * BeaconIntvl)
+ MaxPeriod = 1; // 1 Beacon interval
+ else if(pPSC->RegMaxLPSAwakeIntvl == 0xFF) // DTIM
+ MaxPeriod = ieee->current_network.dtim_period;
+ else
+ MaxPeriod = pPSC->RegMaxLPSAwakeIntvl;
+ pPSC->LPSAwakeIntvl = (pPSC->LPSAwakeIntvl >= MaxPeriod) ? MaxPeriod : (pPSC->LPSAwakeIntvl + 1);
+ }
+ {
+ u8 LPSAwakeIntvl_tmp = 0;
+ u8 period = ieee->current_network.dtim_period;
+ u8 count = ieee->current_network.tim.tim_count;
+ if(count == 0 ) {
+ if(pPSC->LPSAwakeIntvl > period)
+ LPSAwakeIntvl_tmp = period + (pPSC->LPSAwakeIntvl - period) -((pPSC->LPSAwakeIntvl-period)%period);
+ else
+ LPSAwakeIntvl_tmp = pPSC->LPSAwakeIntvl;
+
+ } else {
+ if(pPSC->LPSAwakeIntvl > ieee->current_network.tim.tim_count)
+ LPSAwakeIntvl_tmp = count + (pPSC->LPSAwakeIntvl - count) -((pPSC->LPSAwakeIntvl-count)%period);
+ else
+ LPSAwakeIntvl_tmp = pPSC->LPSAwakeIntvl;//ieee->current_network.tim.tim_count;//pPSC->LPSAwakeIntvl;
+ }
+ //printk("=========>%s()assoc_id:%d(%#x),bAwakePktSent:%d,DTIM:%d, sleep interval:%d, LPSAwakeIntvl_tmp:%d, count:%d\n",__func__,ieee->assoc_id,cpu_to_le16(ieee->assoc_id),ieee->bAwakePktSent,ieee->current_network.dtim_period,pPSC->LPSAwakeIntvl,LPSAwakeIntvl_tmp,count);
+
*time_l = ieee->current_network.last_dtim_sta_time[0]
- + (ieee->current_network.beacon_interval);
+ + MSECS(ieee->current_network.beacon_interval * LPSAwakeIntvl_tmp);
// * ieee->current_network.dtim_period) * 1000;
}
+ }
if(time_h){
*time_h = ieee->current_network.last_dtim_sta_time[1];
@@ -1982,6 +2086,8 @@ inline void ieee80211_sta_ps(struct ieee80211_device *ieee)
ieee->state != IEEE80211_LINKED)){
// #warning CHECK_LOCK_HERE
+ printk("=====>%s(): no need to ps,wake up!! ieee->ps is %d,ieee->iw_mode is %d,ieee->state is %d\n",
+ __FUNCTION__,ieee->ps,ieee->iw_mode,ieee->state);
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
ieee80211_sta_wakeup(ieee, 1);
@@ -1991,27 +2097,27 @@ inline void ieee80211_sta_ps(struct ieee80211_device *ieee)
sleep = ieee80211_sta_ps_sleep(ieee,&th, &tl);
/* 2 wake, 1 sleep, 0 do nothing */
- if(sleep == 0)
+ if(sleep == 0)//it is not time out or dtim is not valid
+ {
+ //printk("===========>sleep is 0,do nothing\n");
goto out;
-
+ }
if(sleep == 1){
-
- if(ieee->sta_sleep == 1)
+ //printk("===========>sleep is 1,to sleep\n");
+ if(ieee->sta_sleep == 1){
+ //printk("%s(1): sta_sleep = 1, sleep again ++++++++++ \n", __func__);
ieee->enter_sleep_state(ieee->dev,th,tl);
+ }
else if(ieee->sta_sleep == 0){
// printk("send null 1\n");
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
if(ieee->ps_is_queue_empty(ieee->dev)){
-
-
ieee->sta_sleep = 2;
-
ieee->ack_tx_to_ieee = 1;
-
+ //printk("%s(2): sta_sleep = 0, notify AP we will sleeped ++++++++++ SendNullFunctionData\n", __func__);
ieee80211_sta_ps_send_null_frame(ieee,1);
-
ieee->ps_th = th;
ieee->ps_tl = tl;
}
@@ -2019,11 +2125,13 @@ inline void ieee80211_sta_ps(struct ieee80211_device *ieee)
}
+ ieee->bAwakePktSent = false;//after null to power save we set it to false. not listen every beacon.
}else if(sleep == 2){
-//#warning CHECK_LOCK_HERE
+ //printk("==========>sleep is 2,to wakeup\n");
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
+ //printk("%s(3): pkt buffered in ap will awake ++++++++++ ieee80211_sta_wakeup\n", __func__);
ieee80211_sta_wakeup(ieee,1);
spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
@@ -2038,9 +2146,19 @@ void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl)
{
if(ieee->sta_sleep == 0){
if(nl){
- printk("Warning: driver is probably failing to report TX ps error\n");
- ieee->ack_tx_to_ieee = 1;
- ieee80211_sta_ps_send_null_frame(ieee, 0);
+ if(ieee->pHTInfo->IOTAction & HT_IOT_ACT_NULL_DATA_POWER_SAVING)
+ {
+ //printk("%s(1): notify AP we are awaked ++++++++++ SendNullFunctionData\n", __func__);
+ //printk("Warning: driver is probably failing to report TX ps error\n");
+ ieee->ack_tx_to_ieee = 1;
+ ieee80211_sta_ps_send_null_frame(ieee, 0);
+ }
+ else
+ {
+ ieee->ack_tx_to_ieee = 1;
+ //printk("%s(2): notify AP we are awaked ++++++++++ Send PS-Poll\n", __func__);
+ ieee80211_sta_ps_send_pspoll_frame(ieee);
+ }
}
return;
@@ -2048,12 +2166,27 @@ void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl)
if(ieee->sta_sleep == 1)
ieee->sta_wake_up(ieee->dev);
+ if(nl){
- ieee->sta_sleep = 0;
+ if(ieee->pHTInfo->IOTAction & HT_IOT_ACT_NULL_DATA_POWER_SAVING)
+ {
+ //printk("%s(3): notify AP we are awaked ++++++++++ SendNullFunctionData\n", __func__);
+ //printk("Warning: driver is probably failing to report TX ps error\n");
+ ieee->ack_tx_to_ieee = 1;
+ ieee80211_sta_ps_send_null_frame(ieee, 0);
+ }
+ else
+ {
+ ieee->ack_tx_to_ieee = 1;
+ ieee->polling = true;
+ //printk("%s(4): notify AP we are awaked ++++++++++ Send PS-Poll\n", __func__);
+ //ieee80211_sta_ps_send_null_frame(ieee, 0);
+ ieee80211_sta_ps_send_pspoll_frame(ieee);
+ }
- if(nl){
- ieee->ack_tx_to_ieee = 1;
- ieee80211_sta_ps_send_null_frame(ieee, 0);
+ } else {
+ ieee->sta_sleep = 0;
+ ieee->polling = false;
}
}
@@ -2067,23 +2200,30 @@ void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success)
/* Null frame with PS bit set */
if(success){
ieee->sta_sleep = 1;
+ //printk("notify AP we will sleep and send null ok, so sleep now++++++++++ enter_sleep_state\n");
ieee->enter_sleep_state(ieee->dev,ieee->ps_th,ieee->ps_tl);
}
- /* if the card report not success we can't be sure the AP
- * has not RXed so we can't assume the AP believe us awake
- */
- }
- /* 21112005 - tx again null without PS bit if lost */
- else {
+ } else {/* 21112005 - tx again null without PS bit if lost */
if((ieee->sta_sleep == 0) && !success){
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
- ieee80211_sta_ps_send_null_frame(ieee, 0);
+ //ieee80211_sta_ps_send_null_frame(ieee, 0);
+ if(ieee->pHTInfo->IOTAction & HT_IOT_ACT_NULL_DATA_POWER_SAVING)
+ {
+ //printk("notify AP we will sleep but send bull failed, so resend++++++++++ SendNullFunctionData\n");
+ ieee80211_sta_ps_send_null_frame(ieee, 0);
+ }
+ else
+ {
+ //printk("notify AP we are awaked but send pspoll failed, so resend++++++++++ Send PS-Poll\n");
+ ieee80211_sta_ps_send_pspoll_frame(ieee);
+ }
spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
}
}
spin_unlock_irqrestore(&ieee->lock, flags);
}
+
void ieee80211_process_action(struct ieee80211_device* ieee, struct sk_buff* skb)
{
struct ieee80211_hdr* header = (struct ieee80211_hdr*)skb->data;
@@ -2227,7 +2367,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
{
if (!ieee->GetNmodeSupportBySecCfg(ieee->dev))
{
- // WEP or TKIP encryption
+ // WEP or TKIP encryption
if(IsHTHalfNmodeAPs(ieee))
{
bSupportNmode = true;
@@ -2238,7 +2378,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
bSupportNmode = false;
bHalfSupportNmode = false;
}
- printk("==========>to link with AP using SEC(%d, %d)", bSupportNmode, bHalfSupportNmode);
+ printk("==========>to link with AP using SEC(%d, %d)\n", bSupportNmode, bHalfSupportNmode);
}
}
/* Dummy wirless mode setting to avoid encryption issue */
@@ -2574,6 +2714,7 @@ void ieee80211_start_ibss_wq(struct ieee80211_device *ieee)
ieee->ssid_set = 1;
}
+ ieee->state = IEEE80211_NOLINK;
/* check if we have this cell in our network list */
ieee80211_softmac_check_all_nets(ieee);
@@ -2705,6 +2846,10 @@ void ieee80211_start_bss(struct ieee80211_device *ieee)
spin_lock_irqsave(&ieee->lock, flags);
if (ieee->state == IEEE80211_NOLINK){
+#ifdef ENABLE_IPS
+ if(ieee->ieee80211_ips_leave_wq != NULL)
+ ieee->ieee80211_ips_leave_wq(ieee->dev);
+#endif
ieee->actscanning = true;
ieee80211_rtl_start_scan(ieee);
}
@@ -2823,21 +2968,23 @@ struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee)
return skb;
}
-void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee)
+void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee, u8 shutdown)
{
ieee->sync_scan_hurryup = 1;
down(&ieee->wx_sem);
- ieee80211_stop_protocol(ieee);
+ ieee80211_stop_protocol(ieee, shutdown);
up(&ieee->wx_sem);
}
-void ieee80211_stop_protocol(struct ieee80211_device *ieee)
+void ieee80211_stop_protocol(struct ieee80211_device *ieee, u8 shutdown)
{
if (!ieee->proto_started)
return;
- ieee->proto_started = 0;
+ if(shutdown)
+ ieee->proto_started = 0;
+ ieee->proto_stoppping = 1;
ieee80211_stop_send_beacons(ieee);
del_timer_sync(&ieee->associate_timer);
@@ -2849,6 +2996,8 @@ void ieee80211_stop_protocol(struct ieee80211_device *ieee)
ieee80211_disassociate(ieee);
RemoveAllTS(ieee); //added as we disconnect from the previous BSS, Remove all TS
+
+ ieee->proto_stoppping = 0;
}
void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee)
@@ -2894,6 +3043,8 @@ void ieee80211_start_protocol(struct ieee80211_device *ieee)
ieee->init_wmmparam_flag = 0;//reinitialize AC_xx_PARAM registers.
+ ieee->state = IEEE80211_NOLINK;
+
/* if the user set the MAC of the ad-hoc cell and then
* switch to managed mode, shall we make sure that association
@@ -3013,7 +3164,9 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee)
#endif
sema_init(&ieee->wx_sem, 1);
sema_init(&ieee->scan_sem, 1);
-
+#ifdef ENABLE_IPS
+ sema_init(&ieee->ips_sem,1);
+#endif
spin_lock_init(&ieee->mgmt_tx_lock);
spin_lock_init(&ieee->beacon_lock);
@@ -3537,5 +3690,6 @@ EXPORT_SYMBOL_NOVERS(ieee80211_stop_scan);
EXPORT_SYMBOL_NOVERS(ieee80211_send_probe_requests);
EXPORT_SYMBOL_NOVERS(ieee80211_softmac_scan_syncro);
EXPORT_SYMBOL_NOVERS(ieee80211_start_scan_syncro);
+EXPORT_SYMBOL_NOVERS(ieee80211_sta_ps_send_null_frame);
+EXPORT_SYMBOL_NOVERS(ieee80211_sta_ps_send_pspoll_frame);
#endif
-//EXPORT_SYMBOL(ieee80211_sta_ps_send_null_frame);
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c
index 7c21aaab9063..1bbd49f1d6f6 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c
@@ -160,7 +160,7 @@ int ieee80211_wx_set_wap(struct ieee80211_device *ieee,
}
if (ifup)
- ieee80211_stop_protocol(ieee);
+ ieee80211_stop_protocol(ieee,true);
/* just to avoid to give inconsistent infos in the
* get wx method. not really needed otherwise
@@ -302,7 +302,7 @@ int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info
if (!ieee->proto_started){
ieee->iw_mode = wrqu->mode;
}else{
- ieee80211_stop_protocol(ieee);
+ ieee80211_stop_protocol(ieee,true);
ieee->iw_mode = wrqu->mode;
ieee80211_start_protocol(ieee);
}
@@ -326,6 +326,17 @@ void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee)
int b40M = 0;
static int count = 0;
chan = ieee->current_network.channel;
+
+#ifdef ENABLE_LPS
+ if (ieee->LeisurePSLeave) {
+ ieee->LeisurePSLeave(ieee->dev);
+ }
+
+ /* notify AP to be in PS mode */
+ ieee80211_sta_ps_send_null_frame(ieee, 1);
+ ieee80211_sta_ps_send_null_frame(ieee, 1);
+#endif
+
netif_carrier_off(ieee->dev);
if (ieee->data_hard_stop)
@@ -360,6 +371,12 @@ void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee)
ieee->InitialGainHandler(ieee->dev,IG_Restore);
ieee->state = IEEE80211_LINKED;
ieee->link_change(ieee->dev);
+
+#ifdef ENABLE_LPS
+ /* Notify AP that I wake up again */
+ ieee80211_sta_ps_send_null_frame(ieee, 0);
+#endif
+
// To prevent the immediately calling watch_dog after scan.
if(ieee->LinkDetectInfo.NumRecvBcnInPeriod==0||ieee->LinkDetectInfo.NumRecvDataInPeriod==0 )
{
@@ -429,8 +446,9 @@ int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
goto out;
}
- if(proto_started)
- ieee80211_stop_protocol(ieee);
+ if(proto_started){
+ ieee80211_stop_protocol(ieee,true);
+ }
/* this is just to be sure that the GET wx callback
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c
index 798fb4154c25..a75f3668a40a 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c
@@ -200,8 +200,8 @@ int ieee80211_encrypt_fragment(
header = (struct ieee80211_hdr *) frag->data;
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "TX packet to " MAC_FMT "\n",
- ieee->dev->name, MAC_ARG(header->addr1));
+ "TX packet to %pM\n",
+ ieee->dev->name, header->addr1);
}
return -1;
}
@@ -334,6 +334,13 @@ void ieee80211_tx_query_agg_cap(struct ieee80211_device* ieee, struct sk_buff* s
if(!Adapter->HalFunc.GetNmodeSupportBySecCfgHandler(Adapter))
return;
#endif
+
+ if(tcb_desc->bdhcp)// || ieee->CntAfterLink<2)
+ {
+ return;
+ }
+
+
#if 1
if(!ieee->GetNmodeSupportBySecCfg(ieee->dev))
{
@@ -628,6 +635,7 @@ int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
int qos_actived = ieee->current_network.qos_data.active;
struct ieee80211_crypt_data* crypt;
+ bool bdhcp =false;
cb_desc *tcb_desc;
@@ -672,6 +680,55 @@ int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
}
#endif
+ // The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time
+ // to prevent DHCP protocol fail
+ if (skb->len > 282){//MINIMUM_DHCP_PACKET_SIZE) {
+ if (ETH_P_IP == ether_type) {// IP header
+ const struct iphdr *ip = (struct iphdr *)((u8 *)skb->data+14);
+ if (IPPROTO_UDP == ip->protocol) {//FIXME windows is 11 but here UDP in linux kernel is 17.
+ struct udphdr *udp = (struct udphdr *)((u8 *)ip + (ip->ihl << 2));
+ //if(((ntohs(udp->source) == 68) && (ntohs(udp->dest) == 67)) ||
+ /// ((ntohs(udp->source) == 67) && (ntohs(udp->dest) == 68))) {
+ if(((((u8 *)udp)[1] == 68) && (((u8 *)udp)[3] == 67)) ||
+ ((((u8 *)udp)[1] == 67) && (((u8 *)udp)[3] == 68))) {
+ // 68 : UDP BOOTP client
+ // 67 : UDP BOOTP server
+ printk("DHCP pkt src port:%d, dest port:%d!!\n", ((u8 *)udp)[1],((u8 *)udp)[3]);
+ // Use low rate to send DHCP packet.
+ //if(pMgntInfo->IOTAction & HT_IOT_ACT_WA_IOT_Broadcom)
+ //{
+ // tcb_desc->DataRate = MgntQuery_TxRateExcludeCCKRates(ieee);//0xc;//ofdm 6m
+ // tcb_desc->bTxDisableRateFallBack = false;
+ //}
+ //else
+ //pTcb->DataRate = Adapter->MgntInfo.LowestBasicRate;
+ //RTPRINT(FDM, WA_IOT, ("DHCP TranslateHeader(), pTcb->DataRate = 0x%x\n", pTcb->DataRate));
+
+ bdhcp = true;
+#ifdef _RTL8192_EXT_PATCH_
+ ieee->LPSDelayCnt = 100;//pPSC->LPSAwakeIntvl*2; //AMY,090701
+#else
+ ieee->LPSDelayCnt = 100;//pPSC->LPSAwakeIntvl*2;
+#endif
+ }
+ }
+ }else if(ETH_P_ARP == ether_type){// IP ARP packet
+ printk("=================>DHCP Protocol start tx ARP pkt!!\n");
+ bdhcp = true;
+ ieee->LPSDelayCnt = ieee->current_network.tim.tim_count;
+
+ //if(pMgntInfo->IOTAction & HT_IOT_ACT_WA_IOT_Broadcom)
+ //{
+ // tcb_desc->DataRate = MgntQuery_TxRateExcludeCCKRates(Adapter->MgntInfo.mBrates);//0xc;//ofdm 6m
+ // tcb_desc->bTxDisableRateFallBack = FALSE;
+ //}
+ //else
+ // tcb_desc->DataRate = Adapter->MgntInfo.LowestBasicRate;
+ //RTPRINT(FDM, WA_IOT, ("ARP TranslateHeader(), pTcb->DataRate = 0x%x\n", pTcb->DataRate));
+
+ }
+ }
+
/* Save source and destination addresses */
memcpy(&dest, skb->data, ETH_ALEN);
memcpy(&src, skb->data+ETH_ALEN, ETH_ALEN);
@@ -895,6 +952,25 @@ int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
else
//tcb_desc->data_rate = CURRENT_RATE(ieee->current_network.mode, ieee->rate, ieee->HTCurrentOperaRate);
tcb_desc->data_rate = CURRENT_RATE(ieee->mode, ieee->rate, ieee->HTCurrentOperaRate);
+
+ if(bdhcp == true){
+ // Use low rate to send DHCP packet.
+ //if(ieee->pHTInfo->IOTAction & HT_IOT_ACT_WA_IOT_Broadcom) {
+ // tcb_desc->data_rate = MGN_1M;//MgntQuery_TxRateExcludeCCKRates(ieee);//0xc;//ofdm 6m
+ // tcb_desc->bTxDisableRateFallBack = false;
+ //}
+ //else
+ {
+ tcb_desc->data_rate = MGN_1M;
+ tcb_desc->bTxDisableRateFallBack = 1;
+ }
+
+ tcb_desc->RATRIndex = 7;
+ tcb_desc->bTxUseDriverAssingedRate = 1;
+ tcb_desc->bdhcp = 1;
+ }
+
+
ieee80211_qurey_ShortPreambleMode(ieee, tcb_desc);
ieee80211_tx_query_agg_cap(ieee, txb->fragments[0], tcb_desc);
ieee80211_query_HTCapShortGI(ieee, tcb_desc);
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c
index 3441b72dd8fa..a3302d5e01ab 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c
@@ -386,10 +386,10 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
else
IEEE80211_DEBUG_SCAN(
"Not showing network '%s ("
- MAC_FMT ")' due to age (%lums).\n",
+ "%pM)' due to age (%lums).\n",
escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid),
+ network->bssid,
(jiffies - network->last_scanned) / (HZ / 100));
}
@@ -933,7 +933,7 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
#if 1
case IW_AUTH_WPA_ENABLED:
ieee->wpa_enabled = (data->value)?1:0;
- //printk("enalbe wpa:%d\n", ieee->wpa_enabled);
+ //printk("enable wpa:%d\n", ieee->wpa_enabled);
break;
#endif
diff --git a/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c
index e41e8a0c739c..ae0e5b9e2183 100644
--- a/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c
@@ -113,7 +113,7 @@ static struct sk_buff* ieee80211_ADDBA(struct ieee80211_device* ieee, u8* Dst, P
u16 tmp = 0;
u16 len = ieee->tx_headroom + 9;
//category(1) + action field(1) + Dialog Token(1) + BA Parameter Set(2) + BA Timeout Value(2) + BA Start SeqCtrl(2)(or StatusCode(2))
- IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:"MAC_FMT", ieee->dev:%p\n", __FUNCTION__, type, MAC_ARG(Dst), ieee->dev);
+ IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:%pM, ieee->dev:%p\n", __FUNCTION__, type, Dst, ieee->dev);
if (pBA == NULL||ieee == NULL)
{
IEEE80211_DEBUG(IEEE80211_DL_ERR, "pBA(%p) is NULL or ieee(%p) is NULL\n", pBA, ieee);
@@ -243,7 +243,7 @@ static struct sk_buff* ieee80211_DELBA(
u16 len = 6 + ieee->tx_headroom;
if (net_ratelimit())
- IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), ReasonCode(%d) sentd to:"MAC_FMT"\n", __FUNCTION__, ReasonCode, MAC_ARG(dst));
+ IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), ReasonCode(%d) sentd to:%pM\n", __FUNCTION__, ReasonCode, dst);
memset(&DelbaParamSet, 0, 2);
@@ -397,7 +397,7 @@ int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb)
pBaTimeoutVal = (u16*)(tag + 5);
pBaStartSeqCtrl = (PSEQUENCE_CONTROL)(req + 7);
- printk("====================>rx ADDBAREQ from :"MAC_FMT"\n", MAC_ARG(dst));
+ printk("====================>rx ADDBAREQ from :%pM\n", dst);
//some other capability is not ready now.
if( (ieee->current_network.qos_data.active == 0) ||
(ieee->pHTInfo->bCurrentHTSupport == false)) //||
diff --git a/drivers/staging/rtl8192e/ieee80211/rtl819x_HT.h b/drivers/staging/rtl8192e/ieee80211/rtl819x_HT.h
index 992b71825a8b..f968817d073c 100644
--- a/drivers/staging/rtl8192e/ieee80211/rtl819x_HT.h
+++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_HT.h
@@ -458,7 +458,8 @@ typedef enum _HT_IOT_PEER
HT_IOT_PEER_RALINK = 3,
HT_IOT_PEER_ATHEROS = 4,
HT_IOT_PEER_CISCO= 5,
- HT_IOT_PEER_MAX = 6
+ HT_IOT_PEER_MARVELL=6,
+ HT_IOT_PEER_MAX = 7
}HT_IOT_PEER_E, *PHTIOT_PEER_E;
//
@@ -475,6 +476,7 @@ typedef enum _HT_IOT_ACTION{
HT_IOT_ACT_CDD_FSYNC = 0x00000080,
HT_IOT_ACT_PURE_N_MODE = 0x00000100,
HT_IOT_ACT_FORCED_CTS2SELF = 0x00000200,
+ HT_IOT_ACT_NULL_DATA_POWER_SAVING = 0x00800000,
}HT_IOT_ACTION_E, *PHT_IOT_ACTION_E;
#endif //_RTL819XU_HTTYPE_H_
diff --git a/drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c
index 1e392141779a..4c4b1df350ac 100644
--- a/drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c
+++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c
@@ -32,7 +32,7 @@ u16 MCS_DATA_RATE[2][2][77] =
static u8 UNKNOWN_BORADCOM[3] = {0x00, 0x14, 0xbf};
static u8 LINKSYSWRT330_LINKSYSWRT300_BROADCOM[3] = {0x00, 0x1a, 0x70};
static u8 LINKSYSWRT350_LINKSYSWRT150_BROADCOM[3] = {0x00, 0x1d, 0x7e};
-static u8 NETGEAR834Bv2_BROADCOM[3] = {0x00, 0x1b, 0x2f};
+//static u8 NETGEAR834Bv2_BROADCOM[3] = {0x00, 0x1b, 0x2f};
static u8 BELKINF5D8233V1_RALINK[3] = {0x00, 0x17, 0x3f}; //cosa 03202008
static u8 BELKINF5D82334V3_RALINK[3] = {0x00, 0x1c, 0xdf};
static u8 PCI_RALINK[3] = {0x00, 0x90, 0xcc};
@@ -40,8 +40,9 @@ static u8 EDIMAX_RALINK[3] = {0x00, 0x0e, 0x2e};
static u8 AIRLINK_RALINK[3] = {0x00, 0x18, 0x02};
static u8 DLINK_ATHEROS[3] = {0x00, 0x1c, 0xf0};
static u8 CISCO_BROADCOM[3] = {0x00, 0x17, 0x94};
+static u8 LINKSYS_MARVELL_4400N[3] = {0x00, 0x14, 0xa4};
-// 2008/04/01 MH For Cisco G mode RX TP We need to change FW duration. Shoud we put the
+// 2008/04/01 MH For Cisco G mode RX TP We need to change FW duration. Should we put the
// code in other place??
//static u8 WIFI_CISCO_G_AP[3] = {0x00, 0x40, 0x96};
/********************************************************************************************************************
@@ -349,12 +350,12 @@ bool IsHTHalfNmodeAPs(struct ieee80211_device* ieee)
bool retValue = false;
struct ieee80211_network* net = &ieee->current_network;
#if 0
- if(pMgntInfo->bHalfNMode == false)
+ if(ieee->bHalfNMode == false)
retValue = false;
else
#endif
if((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3)==0) ||
- (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3)==0) ||
+ (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3)==0) ||
(memcmp(net->bssid, PCI_RALINK, 3)==0) ||
(memcmp(net->bssid, EDIMAX_RALINK, 3)==0) ||
(memcmp(net->bssid, AIRLINK_RALINK, 3)==0) ||
@@ -363,7 +364,7 @@ bool IsHTHalfNmodeAPs(struct ieee80211_device* ieee)
else if((memcmp(net->bssid, UNKNOWN_BORADCOM, 3)==0) ||
(memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0)||
(memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)==0)||
- (memcmp(net->bssid, NETGEAR834Bv2_BROADCOM, 3)==0) ||
+ //(memcmp(net->bssid, NETGEAR834Bv2_BROADCOM, 3)==0) ||
(net->broadcom_cap_exist))
retValue = true;
else if(net->bssht.bdRT2RTAggregation)
@@ -387,13 +388,15 @@ void HTIOTPeerDetermine(struct ieee80211_device* ieee)
struct ieee80211_network* net = &ieee->current_network;
if(net->bssht.bdRT2RTAggregation)
pHTInfo->IOTPeer = HT_IOT_PEER_REALTEK;
- else if(net->broadcom_cap_exist)
+ else if(net->broadcom_cap_exist){
pHTInfo->IOTPeer = HT_IOT_PEER_BROADCOM;
+ }
else if((memcmp(net->bssid, UNKNOWN_BORADCOM, 3)==0) ||
(memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0)||
- (memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)==0)||
- (memcmp(net->bssid, NETGEAR834Bv2_BROADCOM, 3)==0) )
+ (memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)==0)){//||
+ //(memcmp(net->bssid, NETGEAR834Bv2_BROADCOM, 3)==0) ){
pHTInfo->IOTPeer = HT_IOT_PEER_BROADCOM;
+ }
else if((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3)==0) ||
(memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3)==0) ||
(memcmp(net->bssid, PCI_RALINK, 3)==0) ||
@@ -405,6 +408,10 @@ void HTIOTPeerDetermine(struct ieee80211_device* ieee)
pHTInfo->IOTPeer = HT_IOT_PEER_ATHEROS;
else if(memcmp(net->bssid, CISCO_BROADCOM, 3)==0)
pHTInfo->IOTPeer = HT_IOT_PEER_CISCO;
+ else if ((memcmp(net->bssid, LINKSYS_MARVELL_4400N, 3) == 0) ||
+ net->marvell_cap_exist){
+ pHTInfo->IOTPeer = HT_IOT_PEER_MARVELL;
+ }
else
pHTInfo->IOTPeer = HT_IOT_PEER_UNKNOWN;
@@ -442,6 +449,18 @@ u8 HTIOTActIsDisableMCS14(struct ieee80211_device* ieee, u8* PeerMacAddr)
return ret;
}
+u8 HTIOTActIsForcedCTS2Self(struct ieee80211_device *ieee, struct ieee80211_network *network)
+{
+ u8 retValue = 0;
+ //if(network->marvell_cap_exist)
+ if(ieee->pHTInfo->IOTPeer == HT_IOT_PEER_MARVELL)
+ {
+ retValue = 1;
+ }
+
+ return retValue;
+}
+
/**
* Function: HTIOTActIsDisableMCS15
@@ -578,6 +597,23 @@ u8 HTIOTActIsCCDFsync(u8* PeerMacAddr)
return retValue;
}
+//
+// Send null data for to tell AP that we are awake.
+//
+bool
+HTIOTActIsNullDataPowerSaving(struct ieee80211_device* ieee,struct ieee80211_network *network)
+{
+ bool retValue = false;
+
+ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
+ {
+ if(pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM) // ||(pBssDesc->Vender == HT_IOT_PEER_ATHEROS && pBssDesc->SubTypeOfVender == HT_IOT_PEER_ATHEROS_DIR635))
+ return true;
+
+ }
+ return retValue;
+}
+
void HTResetIOTSetting(
PRT_HIGH_THROUGHPUT pHTInfo
)
@@ -1071,6 +1107,13 @@ void HTOnAssocRsp(struct ieee80211_device *ieee)
// Config and configure A-MSDU setting
//
pHTInfo->bCurrent_AMSDU_Support = pHTInfo->bAMSDU_Support;
+ if (ieee->rtllib_ap_sec_type &&
+ (ieee->rtllib_ap_sec_type(ieee)&(SEC_ALG_WEP|SEC_ALG_TKIP))){
+ if( (pHTInfo->IOTPeer== HT_IOT_PEER_ATHEROS) ||
+ (pHTInfo->IOTPeer == HT_IOT_PEER_UNKNOWN) )
+ pHTInfo->bCurrentAMPDUEnable = false;
+ }
+
nMaxAMSDUSize = (pPeerHTCap->MaxAMSDUSize==0)?3839:7935;
@@ -1515,6 +1558,9 @@ void HTResetSelfAndSavePeerSetting(struct ieee80211_device* ieee, struct ieee80
bIOTAction = HTIOTActIsDisableMCS14(ieee, pNetwork->bssid);
if(bIOTAction)
pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_MCS14;
+ bIOTAction = HTIOTActIsForcedCTS2Self(ieee, pNetwork);
+ if(bIOTAction)
+ pHTInfo->IOTAction |= HT_IOT_ACT_FORCED_CTS2SELF;
bIOTAction = HTIOTActIsDisableMCS15(ieee);
if(bIOTAction)
@@ -1537,6 +1583,9 @@ void HTResetSelfAndSavePeerSetting(struct ieee80211_device* ieee, struct ieee80
if(bIOTAction)
pHTInfo->IOTAction |= HT_IOT_ACT_CDD_FSYNC;
+ bIOTAction = HTIOTActIsNullDataPowerSaving(ieee, pNetwork);
+ if(bIOTAction)
+ pHTInfo->IOTAction |= HT_IOT_ACT_NULL_DATA_POWER_SAVING;
}
else
diff --git a/drivers/staging/rtl8192e/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192e/ieee80211/rtl819x_TSProc.c
index 2816b60a08a9..e2cbfd3aa00f 100644
--- a/drivers/staging/rtl8192e/ieee80211/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_TSProc.c
@@ -304,7 +304,7 @@ PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee, u8* Addr, u8
if(search_dir[dir] ==false )
continue;
list_for_each_entry(pRet, psearch_list, List){
- // IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:"MAC_FMT", TID:%d, dir:%d\n", MAC_ARG(pRet->Addr), pRet->TSpec.f.TSInfo.field.ucTSID, pRet->TSpec.f.TSInfo.field.ucDirection);
+ // IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:%pM, TID:%d, dir:%d\n", pRet->Addr, pRet->TSpec.f.TSInfo.field.ucTSID, pRet->TSpec.f.TSInfo.field.ucDirection);
if (memcmp(pRet->Addr, Addr, 6) == 0)
if (pRet->TSpec.f.TSInfo.field.ucTSID == TID)
if(pRet->TSpec.f.TSInfo.field.ucDirection == dir)
@@ -466,7 +466,7 @@ bool GetTs(
ResetRxTsEntry(tmp);
}
- IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:"MAC_FMT"\n", UP, Dir, MAC_ARG(Addr));
+ IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP, Dir, Addr);
// Prepare TS Info releated field
pTSInfo->field.ucTrafficType = 0; // Traffic type: WMM is reserved in this field
pTSInfo->field.ucTSID = UP; // TSID
@@ -552,7 +552,7 @@ void RemoveTsEntry(
void RemovePeerTS(struct ieee80211_device* ieee, u8* Addr)
{
PTS_COMMON_INFO pTS, pTmpTS;
- printk("===========>RemovePeerTS,"MAC_FMT"\n", MAC_ARG(Addr));
+ printk("===========>RemovePeerTS,%pM\n", Addr);
#if 1
list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List)
{
diff --git a/drivers/staging/rtl8192e/r8180_93cx6.c b/drivers/staging/rtl8192e/r8180_93cx6.c
index 79f7a0f39623..262ed5fd086a 100644
--- a/drivers/staging/rtl8192e/r8180_93cx6.c
+++ b/drivers/staging/rtl8192e/r8180_93cx6.c
@@ -22,7 +22,7 @@
static void eprom_cs(struct net_device *dev, short bit)
{
- if(bit)
+ if (bit)
write_nic_byte(dev, EPROM_CMD,
(1<<EPROM_CS_SHIFT) | \
read_nic_byte(dev, EPROM_CMD)); //enable EPROM
@@ -38,23 +38,23 @@ static void eprom_cs(struct net_device *dev, short bit)
static void eprom_ck_cycle(struct net_device *dev)
{
write_nic_byte(dev, EPROM_CMD,
- (1<<EPROM_CK_SHIFT) | read_nic_byte(dev,EPROM_CMD));
+ (1<<EPROM_CK_SHIFT) | read_nic_byte(dev, EPROM_CMD));
force_pci_posting(dev);
udelay(EPROM_DELAY);
write_nic_byte(dev, EPROM_CMD,
- read_nic_byte(dev, EPROM_CMD) &~ (1<<EPROM_CK_SHIFT));
+ read_nic_byte(dev, EPROM_CMD) & ~(1<<EPROM_CK_SHIFT));
force_pci_posting(dev);
udelay(EPROM_DELAY);
}
-static void eprom_w(struct net_device *dev,short bit)
+static void eprom_w(struct net_device *dev, short bit)
{
- if(bit)
+ if (bit)
write_nic_byte(dev, EPROM_CMD, (1<<EPROM_W_SHIFT) | \
- read_nic_byte(dev,EPROM_CMD));
+ read_nic_byte(dev, EPROM_CMD));
else
- write_nic_byte(dev, EPROM_CMD, read_nic_byte(dev,EPROM_CMD)\
+ write_nic_byte(dev, EPROM_CMD, read_nic_byte(dev, EPROM_CMD)\
&~(1<<EPROM_W_SHIFT));
force_pci_posting(dev);
@@ -66,10 +66,11 @@ static short eprom_r(struct net_device *dev)
{
short bit;
- bit=(read_nic_byte(dev, EPROM_CMD) & (1<<EPROM_R_SHIFT) );
+ bit = (read_nic_byte(dev, EPROM_CMD) & (1<<EPROM_R_SHIFT));
udelay(EPROM_DELAY);
- if(bit) return 1;
+ if (bit)
+ return 1;
return 0;
}
@@ -78,7 +79,7 @@ static void eprom_send_bits_string(struct net_device *dev, short b[], int len)
{
int i;
- for(i=0; i<len; i++){
+ for (i = 0; i < len; i++) {
eprom_w(dev, b[i]);
eprom_ck_cycle(dev);
}
@@ -88,37 +89,37 @@ static void eprom_send_bits_string(struct net_device *dev, short b[], int len)
u32 eprom_read(struct net_device *dev, u32 addr)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- short read_cmd[]={1,1,0};
+ short read_cmd[] = {1, 1, 0};
short addr_str[8];
int i;
int addr_len;
u32 ret;
- ret=0;
+ ret = 0;
//enable EPROM programming
write_nic_byte(dev, EPROM_CMD,
(EPROM_CMD_PROGRAM<<EPROM_CMD_OPERATING_MODE_SHIFT));
force_pci_posting(dev);
udelay(EPROM_DELAY);
- if (priv->epromtype==EPROM_93c56){
- addr_str[7]=addr & 1;
- addr_str[6]=addr & (1<<1);
- addr_str[5]=addr & (1<<2);
- addr_str[4]=addr & (1<<3);
- addr_str[3]=addr & (1<<4);
- addr_str[2]=addr & (1<<5);
- addr_str[1]=addr & (1<<6);
- addr_str[0]=addr & (1<<7);
- addr_len=8;
- }else{
- addr_str[5]=addr & 1;
- addr_str[4]=addr & (1<<1);
- addr_str[3]=addr & (1<<2);
- addr_str[2]=addr & (1<<3);
- addr_str[1]=addr & (1<<4);
- addr_str[0]=addr & (1<<5);
- addr_len=6;
+ if (priv->epromtype == EPROM_93c56) {
+ addr_str[7] = addr & 1;
+ addr_str[6] = addr & (1<<1);
+ addr_str[5] = addr & (1<<2);
+ addr_str[4] = addr & (1<<3);
+ addr_str[3] = addr & (1<<4);
+ addr_str[2] = addr & (1<<5);
+ addr_str[1] = addr & (1<<6);
+ addr_str[0] = addr & (1<<7);
+ addr_len = 8;
+ } else {
+ addr_str[5] = addr & 1;
+ addr_str[4] = addr & (1<<1);
+ addr_str[3] = addr & (1<<2);
+ addr_str[2] = addr & (1<<3);
+ addr_str[1] = addr & (1<<4);
+ addr_str[0] = addr & (1<<5);
+ addr_len = 6;
}
eprom_cs(dev, 1);
eprom_ck_cycle(dev);
@@ -129,7 +130,7 @@ u32 eprom_read(struct net_device *dev, u32 addr)
//I'm unsure if it is necessary, but anyway shouldn't hurt
eprom_w(dev, 0);
- for(i=0;i<16;i++){
+ for (i = 0; i < 16; i++) {
//eeprom needs a clk cycle between writing opcode&adr
//and reading data. (eeprom outs a dummy 0)
eprom_ck_cycle(dev);
diff --git a/drivers/staging/rtl8192e/r8180_93cx6.h b/drivers/staging/rtl8192e/r8180_93cx6.h
index 62e14c78e960..4c3f675c6a66 100644
--- a/drivers/staging/rtl8192e/r8180_93cx6.h
+++ b/drivers/staging/rtl8192e/r8180_93cx6.h
@@ -1,17 +1,18 @@
-/*
- This is part of rtl8187 OpenSource driver
- Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
- Released under the terms of GPL (General Public Licence)
-
- Parts of this driver are based on the GPL part of the official realtek driver
- Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon
- Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
-
- We want to tanks the Authors of such projects and the Ndiswrapper project Authors.
-*/
-
-/*This files contains card eeprom (93c46 or 93c56) programming routines*/
-/*memory is addressed by WORDS*/
+/* r8180_93cx6.h - 93c46 or 93c56 eeprom card programming routines
+ *
+ * This is part of rtl8187 OpenSource driver
+ * Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
+ * Released under the terms of GPL (General Public Licence)
+ * Parts of this driver are based on the GPL part of the official realtek driver
+ *
+ * Parts of this driver are based on the rtl8180 driver skeleton from
+ * Patric Schenke & Andres Salomon.
+ *
+ * Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
+ *
+ * We want to thank the authors of the above mentioned projects and to
+ * the authors of the Ndiswrapper project.
+ */
#include "r8192E.h"
#include "r8192E_hw.h"
@@ -36,5 +37,5 @@
#define EPROM_TXPW2 0x1b
#define EPROM_TXPW1 0x3d
-
-u32 eprom_read(struct net_device *dev,u32 addr); //reads a 16 bits word
+/* Reads a 16 bits word. */
+u32 eprom_read(struct net_device *dev, u32 addr);
diff --git a/drivers/staging/rtl8192e/r8190_rtl8256.c b/drivers/staging/rtl8192e/r8190_rtl8256.c
index 3d67fbb65b96..1bd054d42f24 100644
--- a/drivers/staging/rtl8192e/r8190_rtl8256.c
+++ b/drivers/staging/rtl8192e/r8190_rtl8256.c
@@ -429,11 +429,12 @@ SetRFPowerState8190(
bool bResult = true;
//u8 eRFPath;
u8 i = 0, QueueID = 0;
- ptx_ring head=NULL,tail=NULL;
+ //ptx_ring head=NULL,tail=NULL;
+ struct rtl8192_tx_ring *ring = NULL;
if(priv->SetRFPowerStateInProgress == true)
return false;
- RT_TRACE(COMP_POWER, "===========> SetRFPowerState8190()!\n");
+ //RT_TRACE(COMP_PS, "===========> SetRFPowerState8190()!\n");
priv->SetRFPowerStateInProgress = true;
switch(priv->rf_chip)
@@ -442,11 +443,11 @@ SetRFPowerState8190(
switch( eRFPowerState )
{
case eRfOn:
- RT_TRACE(COMP_POWER, "SetRFPowerState8190() eRfOn !\n");
+ //RT_TRACE(COMP_PS, "SetRFPowerState8190() eRfOn !\n");
//RXTX enable control: On
//for(eRFPath = 0; eRFPath <pHalData->NumTotalRFPath; eRFPath++)
- // PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x2);
- #ifdef RTL8190P
+ // PHY_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x2);
+#ifdef RTL8190P
if(priv->rf_type == RF_2T4R)
{
//enable RF-Chip A/B
@@ -479,36 +480,92 @@ SetRFPowerState8190(
//analog to digital part2 on
rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x1800, 0x3); // 0x880[12:11]
}
- #else
- write_nic_byte(dev, ANAPAR, 0x37);//160MHz
- write_nic_byte(dev, MacBlkCtrl, 0x17); // 0x403
- mdelay(1);
- //enable clock 80/88 MHz
-
- priv->bHwRfOffAction = 0;
- //}
-
- // Baseband reset 2008.09.30 add
- write_nic_byte(dev, BB_RESET, (read_nic_byte(dev, BB_RESET)|BIT0));
-
- //2 AFE
- // 2008.09.30 add
- rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0x20000000, 0x1); // 0x884
- //analog to digital part2 on
- rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, 0x3); // 0x880[6:5]
- //digital to analog on
- rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x98, 0x13); // 0x880[4:3]
- //analog to digital on
- rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf03, 0xf03);// 0x88c[9:8]
- //rx antenna on
- //PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, 0x3, 0x3);// 0xc04[1:0]
- //rx antenna on 2008.09.30 mark
- //PHY_SetBBReg(Adapter, rOFDM1_TRxPathEnable, 0x3, 0x3);// 0xd04[1:0]
-
- //2 RF
- //enable RF-Chip A/B
+ else if(priv->rf_type == RF_1T1R) //RF-C
+ {
+ //enable RF-Chip C/D
+ rtl8192_setBBreg(dev, rFPGA0_XC_RFInterfaceOE, BIT4, 0x1); // 0x868[4]
+ //analog to digital on
+ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x400, 0x1);// 0x88c[10]
+ //digital to analog on
+ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x80, 0x1); // 0x880[7]
+ //rx antenna on
+ rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x4, 0x1);// 0xc04[2]
+ //rx antenna on
+ rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x4, 0x1);// 0xd04[2]
+ //analog to digital part2 on
+ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x800, 0x1); // 0x880[11]
+ }
+
+#elif defined RTL8192E
+ // turn on RF
+ if((priv->ieee80211->eRFPowerState == eRfOff) && RT_IN_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC))
+ { // The current RF state is OFF and the RF OFF level is halting the NIC, re-initialize the NIC.
+ bool rtstatus = true;
+ u32 InitilizeCount = 3;
+ do
+ {
+ InitilizeCount--;
+ priv->RegRfOff = false;
+ rtstatus = NicIFEnableNIC(dev);
+ }while( (rtstatus != true) &&(InitilizeCount >0) );
+
+ if(rtstatus != true)
+ {
+ RT_TRACE(COMP_ERR,"%s():Initialize Adapter fail,return\n",__FUNCTION__);
+ priv->SetRFPowerStateInProgress = false;
+ return false;
+ }
+
+ RT_CLEAR_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC);
+ } else {
+ write_nic_byte(dev, ANAPAR, 0x37);//160MHz
+ //write_nic_byte(dev, MacBlkCtrl, 0x17); // 0x403
+ mdelay(1);
+ //enable clock 80/88 MHz
+ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x4, 0x1); // 0x880[2]
+ priv->bHwRfOffAction = 0;
+ //}
+
+ //RF-A, RF-B
+ //enable RF-Chip A/B
rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x1); // 0x860[4]
- rtl8192_setBBreg(dev, rFPGA0_XB_RFInterfaceOE, BIT4, 0x1); // 0x864[4]
+ //analog to digital on
+ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3);// 0x88c[9:8]
+ //digital to analog on
+ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x18, 0x3); // 0x880[4:3]
+ //rx antenna on
+ rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x3, 0x3);// 0xc04[1:0]
+ //rx antenna on
+ rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x3, 0x3);// 0xd04[1:0]
+ //analog to digital part2 on
+ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, 0x3); // 0x880[6:5]
+
+ // Baseband reset 2008.09.30 add
+ //write_nic_byte(dev, BB_RESET, (read_nic_byte(dev, BB_RESET)|BIT0));
+
+ //2 AFE
+ // 2008.09.30 add
+ //rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0x20000000, 0x1); // 0x884
+ //analog to digital part2 on
+ //rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, 0x3); // 0x880[6:5]
+
+
+ //digital to analog on
+ //rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x98, 0x13); // 0x880[4:3]
+ //analog to digital on
+ //rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf03, 0xf03);// 0x88c[9:8]
+ //rx antenna on
+ //PHY_SetBBReg(dev, rOFDM0_TRxPathEnable, 0x3, 0x3);// 0xc04[1:0]
+ //rx antenna on 2008.09.30 mark
+ //PHY_SetBBReg(dev, rOFDM1_TRxPathEnable, 0x3, 0x3);// 0xd04[1:0]
+
+ //2 RF
+ //enable RF-Chip A/B
+ //rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x1); // 0x860[4]
+ //rtl8192_setBBreg(dev, rFPGA0_XB_RFInterfaceOE, BIT4, 0x1); // 0x864[4]
+
+ }
+
#endif
break;
@@ -517,119 +574,137 @@ SetRFPowerState8190(
// By Bruce, 2008-01-16.
//
case eRfSleep:
- case eRfOff:
- RT_TRACE(COMP_POWER, "SetRFPowerState8190() eRfOff/Sleep !\n");
- if (pPSC->bLeisurePs)
+ {
+ // HW setting had been configured with deeper mode.
+ if(priv->ieee80211->eRFPowerState == eRfOff)
+ break;
+
+ // Update current RF state variable.
+ //priv->ieee80211->eRFPowerState = eRFPowerState;
+
+ //if (pPSC->bLeisurePs)
{
for(QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; )
{
- switch(QueueID) {
- case MGNT_QUEUE:
- tail=priv->txmapringtail;
- head=priv->txmapringhead;
+ ring = &priv->tx_ring[QueueID];
+
+ if(skb_queue_len(&ring->queue) == 0)
+ {
+ QueueID++;
+ continue;
+ }
+ else
+ {
+ RT_TRACE((COMP_POWER|COMP_RF), "eRf Off/Sleep: %d times TcbBusyQueue[%d] !=0 before doze!\n", (i+1), QueueID);
+ udelay(10);
+ i++;
+ }
+
+ if(i >= MAX_DOZE_WAITING_TIMES_9x)
+ {
+ RT_TRACE(COMP_POWER, "\n\n\n TimeOut!! SetRFPowerState8190(): eRfOff: %d times TcbBusyQueue[%d] != 0 !!!\n\n\n", MAX_DOZE_WAITING_TIMES_9x, QueueID);
break;
+ }
+ }
+ }
- case BK_QUEUE:
- tail=priv->txbkpringtail;
- head=priv->txbkpringhead;
+ //if(Adapter->HardwareType == HARDWARE_TYPE_RTL8190P)
+#ifdef RTL8190P
+ {
+ PHY_SetRtl8190pRfOff(dev);
+ }
+ //else if(Adapter->HardwareType == HARDWARE_TYPE_RTL8192E)
+#elif defined RTL8192E
+ {
+ PHY_SetRtl8192eRfOff(dev);
+ }
+#endif
+ }
break;
- case BE_QUEUE:
- tail=priv->txbepringtail;
- head=priv->txbepringhead;
- break;
+ case eRfOff:
+ //RT_TRACE(COMP_PS, "SetRFPowerState8190() eRfOff/Sleep !\n");
- case VI_QUEUE:
- tail=priv->txvipringtail;
- head=priv->txvipringhead;
- break;
+ // Update current RF state variable.
+ //priv->ieee80211->eRFPowerState = eRFPowerState;
- case VO_QUEUE:
- tail=priv->txvopringtail;
- head=priv->txvopringhead;
- break;
+ //
+ // Disconnect with Any AP or STA.
+ //
+ for(QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; )
+ {
+ ring = &priv->tx_ring[QueueID];
- default:
- tail=head=NULL;
- break;
- }
- if(tail == head)
+ if(skb_queue_len(&ring->queue) == 0)
{
- //DbgPrint("QueueID = %d", QueueID);
QueueID++;
continue;
}
else
{
- RT_TRACE(COMP_POWER, "eRf Off/Sleep: %d times BusyQueue[%d] !=0 before doze!\n", (i+1), QueueID);
+ RT_TRACE(COMP_POWER,
+ "eRf Off/Sleep: %d times TcbBusyQueue[%d] !=0 before doze!\n", (i+1), QueueID);
udelay(10);
i++;
}
if(i >= MAX_DOZE_WAITING_TIMES_9x)
{
- RT_TRACE(COMP_POWER, "\n\n\n TimeOut!! SetRFPowerState8190(): eRfOff: %d times BusyQueue[%d] != 0 !!!\n\n\n", MAX_DOZE_WAITING_TIMES_9x, QueueID);
+ RT_TRACE(COMP_POWER, "\n\n\n SetZebraRFPowerState8185B(): eRfOff: %d times TcbBusyQueue[%d] != 0 !!!\n\n\n", MAX_DOZE_WAITING_TIMES_9x, QueueID);
break;
}
}
+
+ //if(Adapter->HardwareType == HARDWARE_TYPE_RTL8190P)
+#if defined RTL8190P
+ {
+ PHY_SetRtl8190pRfOff(dev);
}
- #ifdef RTL8190P
- if(priv->rf_type == RF_2T4R)
+ //else if(Adapter->HardwareType == HARDWARE_TYPE_RTL8192E)
+#elif defined RTL8192E
{
- //disable RF-Chip A/B
- rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x0); // 0x860[4]
+ //if(pPSC->RegRfPsLevel & RT_RF_OFF_LEVL_HALT_NIC && !RT_IN_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC) && priv->ieee80211->RfOffReason > RF_CHANGE_BY_PS)
+ if (pPSC->RegRfPsLevel & RT_RF_OFF_LEVL_HALT_NIC && !RT_IN_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC))
+ { // Disable all components.
+ //
+ // Note:
+ // NicIFSetLinkStatus is a big problem when we indicate the status to OS,
+ // the OS(XP) will reset. But now, we cnnot find why the NIC is hard to receive
+ // packets after RF ON. Just keep this function here and still work to find out the root couse.
+ // By Bruce, 2009-05-01.
+ //
+ //NicIFSetLinkStatus( Adapter, RT_MEDIA_DISCONNECT );
+ //if HW radio of , need to indicate scan complete first for not be reset.
+ //if(MgntScanInProgress(pMgntInfo))
+ // MgntResetScanProcess( Adapter );
+
+ // <1> Disable Interrupt
+ //rtl8192_irq_disable(dev);
+ // <2> Stop all timer
+ //MgntCancelAllTimer(Adapter);
+ // <3> Disable Adapter
+ //NicIFHaltAdapter(Adapter, false);
+ NicIFDisableNIC(dev);
+ RT_SET_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC);
+ }
+ else if (!(pPSC->RegRfPsLevel & RT_RF_OFF_LEVL_HALT_NIC))
+ { // Normal case.
+ // IPS should go to this.
+ PHY_SetRtl8192eRfOff(dev);
+ }
+ }
+#else
+ else
+ {
+ RT_TRACE(COMP_DBG,DBG_TRACE,("It is not 8190Pci and 8192PciE \n"));
}
- //disable RF-Chip C/D
- rtl8192_setBBreg(dev, rFPGA0_XC_RFInterfaceOE, BIT4, 0x0); // 0x868[4]
- //analog to digital off, for power save
- rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0);// 0x88c[11:8]
- //digital to analog off, for power save
- rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x1e0, 0x0); // 0x880[8:5]
- //rx antenna off
- rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0xf, 0x0);// 0xc04[3:0]
- //rx antenna off
- rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0);// 0xd04[3:0]
- //analog to digital part2 off, for power save
- rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x1e00, 0x0); // 0x880[12:9]
-#else //8192E
- //2 RF
- //disable RF-Chip A/B
- rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x0); // 0x860[4]
- rtl8192_setBBreg(dev, rFPGA0_XB_RFInterfaceOE, BIT4, 0x0); // 0x864[4]
- //2 AFE
- //analog to digital off, for power save
- //PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter4, 0xf00, 0x0);// 0x88c[11:8]
- rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf03, 0x0); // 2008.09.30 Modify
- //digital to analog off, for power save
- //PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter1, 0x18, 0x0); // 0x880[4:3]
- rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x98, 0x0); // 0x880 2008.09.30 Modify
- //rx antenna off 2008.09.30 mark
- //PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, 0xf, 0x0);// 0xc04[3:0]
- //rx antenna off 2008.09.30 mark
- //PHY_SetBBReg(Adapter, rOFDM1_TRxPathEnable, 0xf, 0x0);// 0xd04[3:0]
- //analog to digital part2 off, for power save
- rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, 0x0); // 0x880[6:5]
- // 2008.09.30 add
- rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0x20000000, 0x0); // 0x884
-
-
- //disable clock 80/88 MHz 2008.09.30 mark
- //PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter1, 0x4, 0x0); // 0x880[2]
- //2 BB
- // Baseband reset 2008.09.30 add
- write_nic_byte(dev, BB_RESET, (read_nic_byte(dev, BB_RESET)|BIT0)); // 0x101
- //MAC: off
- write_nic_byte(dev, MacBlkCtrl, 0x0); // 0x403
- //slow down cpu/lbus clock from 160MHz to Lower
- write_nic_byte(dev, ANAPAR, 0x07); // 0x 17 40MHz
- priv->bHwRfOffAction = 0;
- //}
#endif
+
break;
default:
bResult = false;
- RT_TRACE(COMP_ERR, "SetRFPowerState8190(): unknown state to set: 0x%X!!!\n", eRFPowerState);
+ RT_TRACE(COMP_ERR, "SetRFPowerState8190(): unknow state to set: 0x%X!!!\n", eRFPowerState);
break;
}
@@ -644,64 +719,11 @@ SetRFPowerState8190(
{
// Update current RF state variable.
priv->ieee80211->eRFPowerState = eRFPowerState;
-
- switch(priv->rf_chip )
- {
- case RF_8256:
- switch(priv->ieee80211->eRFPowerState)
- {
- case eRfOff:
- //
- //If Rf off reason is from IPS, Led should blink with no link, by Maddest 071015
- //
- if(priv->ieee80211->RfOffReason==RF_CHANGE_BY_IPS )
- {
- #ifdef TO_DO
- Adapter->HalFunc.LedControlHandler(Adapter,LED_CTL_NO_LINK);
- #endif
- }
- else
- {
- // Turn off LED if RF is not ON.
- #ifdef TO_DO
- Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_POWER_OFF);
- #endif
- }
- break;
-
- case eRfOn:
- // Turn on RF we are still linked, which might happen when
- // we quickly turn off and on HW RF. 2006.05.12, by rcnjko.
- if( priv->ieee80211->state == IEEE80211_LINKED)
- {
- #ifdef TO_DO
- Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_LINK);
- #endif
- }
- else
- {
- // Turn off LED if RF is not ON.
- #ifdef TO_DO
- Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_NO_LINK);
- #endif
- }
- break;
-
- default:
- // do nothing.
- break;
- }// Switch RF state
-
- break;
-
- default:
- RT_TRACE(COMP_ERR, "SetRFPowerState8190(): Unknown RF type\n");
- break;
- }// Switch RFChipID
}
+ //printk("%s()priv->ieee80211->eRFPowerState:%s\n" ,__func__,priv->ieee80211->eRFPowerState == eRfOn ? "On" : "Off");
priv->SetRFPowerStateInProgress = false;
- RT_TRACE(COMP_POWER, "<=========== SetRFPowerState8190() bResult = %d!\n", bResult);
+ //RT_TRACE(COMP_PS, "<=========== SetRFPowerState8190() bResult = %d!\n", bResult);
return bResult;
}
diff --git a/drivers/staging/rtl8192e/r8190_rtl8256.h b/drivers/staging/rtl8192e/r8190_rtl8256.h
index 7d9095a70aec..ce49c606521a 100644
--- a/drivers/staging/rtl8192e/r8190_rtl8256.h
+++ b/drivers/staging/rtl8192e/r8190_rtl8256.h
@@ -1,28 +1,33 @@
-/*
- This is part of the rtl8180-sa2400 driver
- released under the GPL (See file COPYING for details).
- Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+/* r8190_rtl8256.h - rtl8256 radio frontend
+ *
+ * This is part of the rtl8180-sa2400 driver
+ * released under the GPL (See file COPYING for details).
+ * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Many thanks to Realtek Corp. for their great support!
+ */
- This files contains programming code for the rtl8256
- radio frontend.
-
- *Many* thanks to Realtek Corp. for their great support!
-
-*/
-
-#ifndef RTL8225H
-#define RTL8225H
+#ifndef RTL8225_H
+#define RTL8225_H
#ifdef RTL8190P
-#define RTL819X_TOTAL_RF_PATH 4
+#define RTL819X_TOTAL_RF_PATH 4
#else
-#define RTL819X_TOTAL_RF_PATH 2 //for 8192E
+#define RTL819X_TOTAL_RF_PATH 2 /* for 8192E */
#endif
-extern void PHY_SetRF8256Bandwidth(struct net_device* dev , HT_CHANNEL_WIDTH Bandwidth);
-extern RT_STATUS PHY_RF8256_Config(struct net_device* dev);
-extern RT_STATUS phy_RF8256_Config_ParaFile(struct net_device* dev);
-extern void PHY_SetRF8256CCKTxPower(struct net_device* dev, u8 powerlevel);
-extern void PHY_SetRF8256OFDMTxPower(struct net_device* dev, u8 powerlevel);
-extern bool MgntActSet_RF_State(struct net_device* dev, RT_RF_POWER_STATE StateToSet, RT_RF_CHANGE_SOURCE ChangeSource);
-#endif
+extern void PHY_SetRF8256Bandwidth(struct net_device *dev,
+ HT_CHANNEL_WIDTH Bandwidth);
+
+extern RT_STATUS PHY_RF8256_Config(struct net_device *dev);
+
+extern RT_STATUS phy_RF8256_Config_ParaFile(struct net_device *dev);
+
+extern void PHY_SetRF8256CCKTxPower(struct net_device *dev, u8 powerlevel);
+extern void PHY_SetRF8256OFDMTxPower(struct net_device *dev, u8 powerlevel);
+
+extern bool MgntActSet_RF_State(struct net_device *dev,
+ RT_RF_POWER_STATE StateToSet,
+ RT_RF_CHANGE_SOURCE ChangeSource);
+
+#endif /* RTL8225_H */
diff --git a/drivers/staging/rtl8192e/r8192E.h b/drivers/staging/rtl8192e/r8192E.h
index 61b6f250b917..f4be9cc11005 100644
--- a/drivers/staging/rtl8192e/r8192E.h
+++ b/drivers/staging/rtl8192e/r8192E.h
@@ -39,7 +39,7 @@
#include <linux/random.h>
#include <linux/version.h>
#include <asm/io.h>
-#include "ieee80211.h"
+#include "ieee80211/ieee80211.h"
@@ -1003,6 +1003,11 @@ typedef struct r8192_priv
int irq;
short irq_enabled;
struct ieee80211_device *ieee80211;
+#ifdef ENABLE_LPS
+ bool ps_force;
+ bool force_lps;
+ bool bdisable_nic;
+#endif
bool being_init_adapter;
u8 Rf_Mode;
short card_8192; /* O: rtl8192, 1:rtl8185 V B/C, 2:rtl8185 V D */
@@ -1477,7 +1482,7 @@ void write_nic_word(struct net_device *dev, int x,u16 y);
void write_nic_dword(struct net_device *dev, int x,u32 y);
void force_pci_posting(struct net_device *dev);
-void rtl8192_rtx_disable(struct net_device *);
+void rtl8192_halt_adapter(struct net_device *dev, bool reset);
void rtl8192_rx_enable(struct net_device *);
void rtl8192_tx_enable(struct net_device *);
@@ -1512,5 +1517,19 @@ short rtl8192_is_tx_queue_empty(struct net_device *dev);
#ifdef ENABLE_IPS
void IPSEnter(struct net_device *dev);
void IPSLeave(struct net_device *dev);
+void InactivePsWorkItemCallback(struct net_device *dev);
+void IPSLeave_wq(void *data);
+void ieee80211_ips_leave_wq(struct net_device *dev);
+void ieee80211_ips_leave(struct net_device *dev);
+#endif
+#ifdef ENABLE_LPS
+void LeisurePSEnter(struct net_device *dev);
+void LeisurePSLeave(struct net_device *dev);
#endif
+
+bool NicIFEnableNIC(struct net_device* dev);
+bool NicIFDisableNIC(struct net_device* dev);
+
+void rtl8192_irq_disable(struct net_device *dev);
+void PHY_SetRtl8192eRfOff(struct net_device* dev);
#endif
diff --git a/drivers/staging/rtl8192e/r8192E_core.c b/drivers/staging/rtl8192e/r8192E_core.c
index 0ca5d8b4f746..886105db8b7c 100644
--- a/drivers/staging/rtl8192e/r8192E_core.c
+++ b/drivers/staging/rtl8192e/r8192E_core.c
@@ -66,7 +66,7 @@
#endif
#ifdef ENABLE_DOT11D
-#include "dot11d.h"
+#include "ieee80211/dot11d.h"
#endif
//set here to open your trace code. //WB
@@ -75,7 +75,7 @@ u32 rt_global_debug_component = \
// COMP_EPROM |
// COMP_PHY |
// COMP_RF |
- COMP_FIRMWARE |
+// COMP_FIRMWARE |
// COMP_TRACE |
// COMP_DOWN |
// COMP_SWBW |
@@ -343,6 +343,141 @@ void write_nic_word(struct net_device *dev, int x,u16 y)
#endif /* RTL_IO_MAP */
+u8 rtl8192e_ap_sec_type(struct ieee80211_device *ieee)
+{
+ //struct r8192_priv* priv = ieee80211_priv(dev);
+ //struct ieee80211_device *ieee = priv->ieee80211;
+
+ static u8 ccmp_ie[4] = {0x00,0x50,0xf2,0x04};
+ static u8 ccmp_rsn_ie[4] = {0x00, 0x0f, 0xac, 0x04};
+ int wpa_ie_len= ieee->wpa_ie_len;
+ struct ieee80211_crypt_data* crypt;
+ int encrypt;
+
+ crypt = ieee->crypt[ieee->tx_keyidx];
+
+ encrypt = (ieee->current_network.capability & WLAN_CAPABILITY_PRIVACY) ||\
+ (ieee->host_encrypt && crypt && crypt->ops && \
+ (0 == strcmp(crypt->ops->name,"WEP")));
+
+ /* simply judge */
+ if(encrypt && (wpa_ie_len == 0)) {
+ // wep encryption, no N mode setting */
+ return SEC_ALG_WEP;
+ } else if((wpa_ie_len != 0)) {
+ // parse pairwise key type */
+ if (((ieee->wpa_ie[0] == 0xdd) && (!memcmp(&(ieee->wpa_ie[14]),ccmp_ie,4))) ||
+ ((ieee->wpa_ie[0] == 0x30) && (!memcmp(&ieee->wpa_ie[10],ccmp_rsn_ie, 4))))
+ return SEC_ALG_CCMP;
+ else
+ return SEC_ALG_TKIP;
+ } else {
+ return SEC_ALG_NONE;
+ }
+}
+
+void
+rtl8192e_SetHwReg(struct net_device *dev,u8 variable,u8* val)
+{
+ struct r8192_priv* priv = ieee80211_priv(dev);
+
+ switch(variable)
+ {
+
+ case HW_VAR_BSSID:
+ write_nic_dword(dev, BSSIDR, ((u32*)(val))[0]);
+ write_nic_word(dev, BSSIDR+2, ((u16*)(val+2))[0]);
+ break;
+
+ case HW_VAR_MEDIA_STATUS:
+ {
+ RT_OP_MODE OpMode = *((RT_OP_MODE *)(val));
+ //LED_CTL_MODE LedAction = LED_CTL_NO_LINK;
+ u8 btMsr = read_nic_byte(dev, MSR);
+
+ btMsr &= 0xfc;
+
+ switch(OpMode)
+ {
+ case RT_OP_MODE_INFRASTRUCTURE:
+ btMsr |= MSR_INFRA;
+ //LedAction = LED_CTL_LINK;
+ break;
+
+ case RT_OP_MODE_IBSS:
+ btMsr |= MSR_ADHOC;
+ // led link set seperate
+ break;
+
+ case RT_OP_MODE_AP:
+ btMsr |= MSR_AP;
+ //LedAction = LED_CTL_LINK;
+ break;
+
+ default:
+ btMsr |= MSR_NOLINK;
+ break;
+ }
+
+ write_nic_byte(dev, MSR, btMsr);
+
+ //priv->ieee80211->LedControlHandler(dev, LedAction);
+ }
+ break;
+
+ case HW_VAR_CECHK_BSSID:
+ {
+ u32 RegRCR, Type;
+
+ Type = ((u8*)(val))[0];
+ //priv->ieee80211->GetHwRegHandler(dev, HW_VAR_RCR, (u8*)(&RegRCR));
+ RegRCR = read_nic_dword(dev,RCR);
+ priv->ReceiveConfig = RegRCR;
+
+ if (Type == true)
+ RegRCR |= (RCR_CBSSID);
+ else if (Type == false)
+ RegRCR &= (~RCR_CBSSID);
+
+ //priv->ieee80211->SetHwRegHandler( dev, HW_VAR_RCR, (u8*)(&RegRCR) );
+ write_nic_dword(dev, RCR,RegRCR);
+ priv->ReceiveConfig = RegRCR;
+
+ }
+ break;
+
+ case HW_VAR_SLOT_TIME:
+ {
+ //PSTA_QOS pStaQos = Adapter->MgntInfo.pStaQos;
+ //AC_CODING eACI;
+
+ priv->slot_time = val[0];
+ write_nic_byte(dev, SLOT_TIME, val[0]);
+
+ }
+ break;
+
+ case HW_VAR_ACK_PREAMBLE:
+ {
+ u32 regTmp = 0;
+ priv->short_preamble = (bool)(*(u8*)val );
+ regTmp = priv->basic_rate;
+ if (priv->short_preamble)
+ regTmp |= BRSR_AckShortPmb;
+ write_nic_dword(dev, RRSR, regTmp);
+ }
+ break;
+
+ case HW_VAR_CPU_RST:
+ write_nic_dword(dev, CPU_GEN, ((u32*)(val))[0]);
+ break;
+
+ default:
+ break;
+ }
+
+}
+
///////////////////////////////////////////////////////////
@@ -365,11 +500,6 @@ void rtl8192_restart(struct work_struct *work);
//void rtl8192_rq_tx_ack(struct work_struct *work);
void watch_dog_timer_callback(unsigned long data);
-#ifdef ENABLE_IPS
-void IPSEnter(struct net_device *dev);
-void IPSLeave(struct net_device *dev);
-void InactivePsWorkItemCallback(struct net_device *dev);
-#endif
/****************************************************************************
-----------------------------PROCFS STUFF-------------------------
*****************************************************************************/
@@ -707,7 +837,7 @@ static void rtl8192_irq_enable(struct net_device *dev)
}
-static void rtl8192_irq_disable(struct net_device *dev)
+void rtl8192_irq_disable(struct net_device *dev)
{
struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
@@ -717,6 +847,7 @@ static void rtl8192_irq_disable(struct net_device *dev)
}
+#if 0
static void rtl8192_set_mode(struct net_device *dev,int mode)
{
u8 ecmd;
@@ -727,7 +858,7 @@ static void rtl8192_set_mode(struct net_device *dev,int mode)
ecmd=ecmd &~ (1<<EPROM_CK_SHIFT);
write_nic_byte(dev, EPROM_CMD, ecmd);
}
-
+#endif
void rtl8192_update_msr(struct net_device *dev)
{
@@ -861,7 +992,7 @@ static void rtl8192_free_tx_ring(struct net_device *dev, unsigned int prio)
ring->desc = NULL;
}
-
+#if 0
static void rtl8192_beacon_disable(struct net_device *dev)
{
struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
@@ -873,38 +1004,116 @@ static void rtl8192_beacon_disable(struct net_device *dev)
reg &= ~(IMR_BcnInt | IMR_BcnInt | IMR_TBDOK | IMR_TBDER);
write_nic_dword(priv->ieee80211->dev, INTA_MASK, reg);
}
+#endif
+
+void PHY_SetRtl8192eRfOff(struct net_device* dev )
+{
+ //struct r8192_priv *priv = ieee80211_priv(dev);
+
+ //disable RF-Chip A/B
+ rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x0);
+ //analog to digital off, for power save
+ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, 0x0);
+ //digital to analog off, for power save
+ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x18, 0x0);
+ //rx antenna off
+ rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0xf, 0x0);
+ //rx antenna off
+ rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0);
+ //analog to digital part2 off, for power save
+ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, 0x0);
+ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x4, 0x0);
+ // Analog parameter!!Change bias and Lbus control.
+ write_nic_byte(dev, ANAPAR_FOR_8192PciE, 0x07);
+
+}
-void rtl8192_rtx_disable(struct net_device *dev)
+void rtl8192_halt_adapter(struct net_device *dev, bool reset)
{
- u8 cmd;
+ //u8 cmd;
struct r8192_priv *priv = ieee80211_priv(dev);
- int i;
+ int i;
+ u8 OpMode;
+ u8 u1bTmp;
+ u32 ulRegRead;
+
+ OpMode = RT_OP_MODE_NO_LINK;
+ priv->ieee80211->SetHwRegHandler(dev, HW_VAR_MEDIA_STATUS, &OpMode);
+#if 1
+ if(!priv->ieee80211->bSupportRemoteWakeUp)
+ {
+ u1bTmp = 0x0; // disable tx/rx. In 8185 we write 0x10 (Reset bit), but here we make reference to WMAC and wirte 0x0. 2006.11.21 Emily
+ //priv->ieee80211->SetHwRegHandler(dev, HW_VAR_COMMAND, &u1bTmp ); // Using HW_VAR_COMMAND instead of writing CMDR directly. Rewrited by Annie, 2006-04-07.
+ write_nic_byte(dev, CMDR, u1bTmp);
+ }
+#else
cmd=read_nic_byte(dev,CMDR);
-// if(!priv->ieee80211->bSupportRemoteWakeUp) {
- write_nic_byte(dev, CMDR, cmd &~ \
- (CR_TE|CR_RE));
-// }
- force_pci_posting(dev);
- mdelay(30);
+ write_nic_byte(dev, CMDR, cmd &~ (CR_TE|CR_RE));
+#endif
- for(i = 0; i < MAX_QUEUE_SIZE; i++) {
- skb_queue_purge(&priv->ieee80211->skb_waitQ [i]);
- }
- for(i = 0; i < MAX_QUEUE_SIZE; i++) {
- skb_queue_purge(&priv->ieee80211->skb_aggQ [i]);
- }
+ mdelay(20);
+ if(!reset)
+ {
+ //PlatformStallExecution(150000);
+ mdelay(150);
+
+#ifdef RTL8192E
+ priv->bHwRfOffAction = 2;
+#endif
+
+ //
+ // Call MgntActSet_RF_State instead to prevent RF config race condition.
+ // By Bruce, 2008-01-17.
+ //
+ if(!priv->ieee80211->bSupportRemoteWakeUp)
+ {
+ //MgntActSet_RF_State(Adapter, eRfOff, RF_CHANGE_BY_INIT);
+ //MgntActSet_RF_State(Adapter, eRfOff, Adapter->MgntInfo.RfOffReason);
+ //if(Adapter->HardwareType == HARDWARE_TYPE_RTL8190P)
+
+ PHY_SetRtl8192eRfOff(dev);
+
+ // 2006.11.30. System reset bit
+ //priv->ieee80211->GetHwRegHandler(dev, HW_VAR_CPU_RST, (u32*)(&ulRegRead) );
+ ulRegRead = read_nic_dword(dev,CPU_GEN);
+ ulRegRead|=CPU_GEN_SYSTEM_RESET;
+ //priv->ieee80211->SetHwRegHandler(dev, HW_VAR_CPU_RST, &ulRegRead);
+ write_nic_dword(dev,CPU_GEN, ulRegRead);
+ }
+ else
+ {
+ //2008.06.03 for WOL
+ write_nic_dword(dev, WFCRC0, 0xffffffff);
+ write_nic_dword(dev, WFCRC1, 0xffffffff);
+ write_nic_dword(dev, WFCRC2, 0xffffffff);
+
+ //Write PMR register
+ write_nic_byte(dev, PMR, 0x5);
+ //Disable tx, enanble rx
+ write_nic_byte(dev, MacBlkCtrl, 0xa);
+ }
+ }
+
+ for(i = 0; i < MAX_QUEUE_SIZE; i++) {
+ skb_queue_purge(&priv->ieee80211->skb_waitQ [i]);
+ }
+ for(i = 0; i < MAX_QUEUE_SIZE; i++) {
+ skb_queue_purge(&priv->ieee80211->skb_aggQ [i]);
+ }
skb_queue_purge(&priv->skb_queue);
return;
}
+#if 0
static void rtl8192_reset(struct net_device *dev)
{
rtl8192_irq_disable(dev);
printk("This is RTL819xP Reset procedure\n");
}
+#endif
static u16 rtl_rate[] = {10,20,55,110,60,90,120,180,240,360,480,540};
inline u16 rtl8192_rate2rate(short rate)
@@ -954,6 +1163,12 @@ static void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev,
/* shall not be referred by command packet */
assert(queue_index != TXCMD_QUEUE);
+ if((priv->bHwRadioOff == true)||(!priv->up))
+ {
+ kfree_skb(skb);
+ return;
+ }
+
//spin_lock_irqsave(&priv->tx_lock,flags);
memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
@@ -996,6 +1211,13 @@ static int rtl8192_hard_start_xmit(struct sk_buff *skb,struct net_device *dev)
cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
u8 queue_index = tcb_desc->queue_index;
+ if(queue_index != TXCMD_QUEUE){
+ if((priv->bHwRadioOff == true)||(!priv->up))
+ {
+ kfree_skb(skb);
+ return 0;
+ }
+ }
//spin_lock_irqsave(&priv->tx_lock,flags);
@@ -1379,6 +1601,15 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff* skb)
u8* pda_addr = NULL;
int idx;
+ if(priv->bdisable_nic){
+ RT_TRACE(COMP_ERR,"%s: ERR!! Nic is disabled! Can't tx packet len=%d qidx=%d!!!\n", __FUNCTION__, skb->len, tcb_desc->queue_index);
+ return skb->len;
+ }
+
+#ifdef ENABLE_LPS
+ priv->ieee80211->bAwakePktSent = true;
+#endif
+
mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
/* collect the tx packets statitcs */
pda_addr = ((u8*)skb->data) + sizeof(TX_FWINFO_8190PCI);
@@ -1481,6 +1712,7 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff* skb)
if((pdesc->OWN == 1) && (tcb_desc->queue_index != BEACON_QUEUE)) {
RT_TRACE(COMP_ERR,"No more TX desc@%d, ring->idx = %d,idx = %d,%x", \
tcb_desc->queue_index,ring->idx, idx,skb->len);
+ spin_unlock_irqrestore(&priv->irq_th_lock,flags);
return skb->len;
}
@@ -1575,7 +1807,7 @@ static short rtl8192_alloc_rx_desc_ring(struct net_device *dev)
return 0;
priv->rx_buf[i] = skb;
mapping = (dma_addr_t *)skb->cb;
- *mapping = pci_map_single(priv->pdev, skb->tail,//skb_tail_pointer(skb),
+ *mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb),
priv->rxbuffersize, PCI_DMA_FROMDEVICE);
entry->BufferAddress = cpu_to_le32(*mapping);
@@ -1779,7 +2011,7 @@ static void rtl8192_qos_activate(struct work_struct * work)
(((u32)(qos_parameters->cw_max[i]))<< AC_PARAM_ECW_MAX_OFFSET)|
(((u32)(qos_parameters->cw_min[i]))<< AC_PARAM_ECW_MIN_OFFSET)|
((u32)u1bAIFS << AC_PARAM_AIFS_OFFSET));
- printk("===>u4bAcParam:%x, ", u4bAcParam);
+ //printk("===>u4bAcParam:%x, ", u4bAcParam);
write_nic_dword(dev, WDCAPARA_ADD[i], u4bAcParam);
//write_nic_dword(dev, WDCAPARA_ADD[i], 0x005e4332);
}
@@ -1964,11 +2196,24 @@ void rtl8192_update_ratr_table(struct net_device* dev)
write_nic_byte(dev, UFWP, 1);
}
+#if 0
static u8 ccmp_ie[4] = {0x00,0x50,0xf2,0x04};
static u8 ccmp_rsn_ie[4] = {0x00, 0x0f, 0xac, 0x04};
+#endif
+
static bool GetNmodeSupportBySecCfg8190Pci(struct net_device*dev)
{
#if 1
+
+ struct r8192_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee80211;
+ if (ieee->rtllib_ap_sec_type &&
+ (ieee->rtllib_ap_sec_type(ieee)&(SEC_ALG_WEP|SEC_ALG_TKIP))) {
+ return false;
+ } else {
+ return true;
+ }
+#else
struct r8192_priv* priv = ieee80211_priv(dev);
struct ieee80211_device* ieee = priv->ieee80211;
int wpa_ie_len= ieee->wpa_ie_len;
@@ -1995,18 +2240,6 @@ static bool GetNmodeSupportBySecCfg8190Pci(struct net_device*dev)
return true;
}
-#if 0
- //In here we discuss with SD4 David. He think we still can send TKIP in broadcast group key in MCS rate.
- //We can't force in G mode if Pairwie key is AES and group key is TKIP
- if((pSecInfo->GroupEncAlgorithm == WEP104_Encryption) || (pSecInfo->GroupEncAlgorithm == WEP40_Encryption) ||
- (pSecInfo->PairwiseEncAlgorithm == WEP104_Encryption) ||
- (pSecInfo->PairwiseEncAlgorithm == WEP40_Encryption) || (pSecInfo->PairwiseEncAlgorithm == TKIP_Encryption))
- {
- return false;
- }
- else
- return true;
-#endif
return true;
#endif
}
@@ -2080,7 +2313,7 @@ static void rtl8192_SetWirelessMode(struct net_device* dev, u8 wireless_mode)
wireless_mode = WIRELESS_MODE_B;
}
}
-#ifdef TO_DO_LIST //// TODO: this function doesn't work well at this time, we shoud wait for FPGA
+#ifdef TO_DO_LIST //// TODO: this function doesn't work well at this time, we should wait for FPGA
ActUpdateChannelAccessSetting( pAdapter, pHalData->CurrentWirelessMode, &pAdapter->MgntInfo.Info8185.ChannelAccessSetting );
#endif
priv->ieee80211->mode = wireless_mode;
@@ -2127,7 +2360,19 @@ short rtl8192_is_tx_queue_empty(struct net_device *dev)
}
static void rtl8192_hw_sleep_down(struct net_device *dev)
{
- RT_TRACE(COMP_POWER, "%s()============>come to sleep down\n", __FUNCTION__);
+ struct r8192_priv *priv = ieee80211_priv(dev);
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&priv->rf_ps_lock,flags);
+ if (priv->RFChangeInProgress) {
+ spin_unlock_irqrestore(&priv->rf_ps_lock,flags);
+ RT_TRACE(COMP_RF, "rtl8192_hw_sleep_down(): RF Change in progress! \n");
+ printk("rtl8192_hw_sleep_down(): RF Change in progress!\n");
+ return;
+ }
+ spin_unlock_irqrestore(&priv->rf_ps_lock,flags);
+ //RT_TRACE(COMP_PS, "%s()============>come to sleep down\n", __FUNCTION__);
+
MgntActSet_RF_State(dev, eRfSleep, RF_CHANGE_BY_PS);
}
static void rtl8192_hw_sleep_wq (struct work_struct *work)
@@ -2138,21 +2383,29 @@ static void rtl8192_hw_sleep_wq (struct work_struct *work)
struct delayed_work *dwork = container_of(work,struct delayed_work,work);
struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_sleep_wq);
struct net_device *dev = ieee->dev;
- //printk("=========>%s()\n", __FUNCTION__);
+
rtl8192_hw_sleep_down(dev);
}
-// printk("dev is %d\n",dev);
-// printk("&*&(^*(&(&=========>%s()\n", __FUNCTION__);
+
static void rtl8192_hw_wakeup(struct net_device* dev)
{
-// u32 flags = 0;
+ struct r8192_priv *priv = ieee80211_priv(dev);
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&priv->rf_ps_lock,flags);
+ if (priv->RFChangeInProgress) {
+ spin_unlock_irqrestore(&priv->rf_ps_lock,flags);
+ RT_TRACE(COMP_RF, "rtl8192_hw_wakeup(): RF Change in progress! \n");
+ printk("rtl8192_hw_wakeup(): RF Change in progress! schedule wake up task again\n");
+ queue_delayed_work(priv->ieee80211->wq,&priv->ieee80211->hw_wakeup_wq,MSECS(10));//PowerSave is not supported if kernel version is below 2.6.20
+ return;
+ }
+ spin_unlock_irqrestore(&priv->rf_ps_lock,flags);
-// spin_lock_irqsave(&priv->ps_lock,flags);
- RT_TRACE(COMP_POWER, "%s()============>come to wake up\n", __FUNCTION__);
+ //RT_TRACE(COMP_PS, "%s()============>come to wake up\n", __FUNCTION__);
MgntActSet_RF_State(dev, eRfOn, RF_CHANGE_BY_PS);
- //FIXME: will we send package stored while nic is sleep?
-// spin_unlock_irqrestore(&priv->ps_lock,flags);
}
+
void rtl8192_hw_wakeup_wq (struct work_struct *work)
{
// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq);
@@ -2169,7 +2422,6 @@ void rtl8192_hw_wakeup_wq (struct work_struct *work)
#define MAX_SLEEP_TIME 10000
static void rtl8192_hw_to_sleep(struct net_device *dev, u32 th, u32 tl)
{
-
struct r8192_priv *priv = ieee80211_priv(dev);
u32 rb = jiffies;
@@ -2177,58 +2429,55 @@ static void rtl8192_hw_to_sleep(struct net_device *dev, u32 th, u32 tl)
spin_lock_irqsave(&priv->ps_lock,flags);
- /* Writing HW register with 0 equals to disable
- * the timer, that is not really what we want
- */
- tl -= MSECS(4+16+7);
-
- //if(tl == 0) tl = 1;
-
- /* FIXME HACK FIXME HACK */
-// force_pci_posting(dev);
- //mdelay(1);
-
-// rb = read_nic_dword(dev, TSFTR);
+ // Writing HW register with 0 equals to disable
+ // the timer, that is not really what we want
+ //
+ tl -= MSECS(8+16+7);
- /* If the interval in witch we are requested to sleep is too
- * short then give up and remain awake
- */
+ // If the interval in witch we are requested to sleep is too
+ // short then give up and remain awake
+ // when we sleep after send null frame, the timer will be too short to sleep.
+ //
if(((tl>=rb)&& (tl-rb) <= MSECS(MIN_SLEEP_TIME))
- ||((rb>tl)&& (rb-tl) < MSECS(MIN_SLEEP_TIME))) {
+ ||((rb>tl)&& (rb-tl) < MSECS(MIN_SLEEP_TIME))) {
spin_unlock_irqrestore(&priv->ps_lock,flags);
- printk("too short to sleep\n");
+ printk("too short to sleep::%x, %x, %lx\n",tl, rb, MSECS(MIN_SLEEP_TIME));
return;
}
-// write_nic_dword(dev, TimerInt, tl);
-// rb = read_nic_dword(dev, TSFTR);
- {
- u32 tmp = (tl>rb)?(tl-rb):(rb-tl);
- // if (tl<rb)
- queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp); //as tl may be less than rb
- }
- /* if we suspect the TimerInt is gone beyond tl
- * while setting it, then give up
- */
-#if 1
if(((tl > rb) && ((tl-rb) > MSECS(MAX_SLEEP_TIME)))||
- ((tl < rb) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))) {
+ ((tl < rb) && (tl>MSECS(69)) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))||
+ ((tl<rb)&&(tl<MSECS(69))&&((tl+0xffffffff-rb)>MSECS(MAX_SLEEP_TIME)))) {
printk("========>too long to sleep:%x, %x, %lx\n", tl, rb, MSECS(MAX_SLEEP_TIME));
spin_unlock_irqrestore(&priv->ps_lock,flags);
return;
}
-#endif
-// if(priv->rf_sleep)
-// priv->rf_sleep(dev);
-
- //printk("<=========%s()\n", __FUNCTION__);
- queue_delayed_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_sleep_wq,0);
+ {
+ u32 tmp = (tl>rb)?(tl-rb):(rb-tl);
+ queue_delayed_work(priv->ieee80211->wq,
+ &priv->ieee80211->hw_wakeup_wq,tmp);
+ //PowerSave not supported when kernel version less 2.6.20
+ }
+ queue_delayed_work(priv->ieee80211->wq,
+ (void *)&priv->ieee80211->hw_sleep_wq,0);
spin_unlock_irqrestore(&priv->ps_lock,flags);
+
}
static void rtl8192_init_priv_variable(struct net_device* dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u8 i;
+ PRT_POWER_SAVE_CONTROL pPSC = (PRT_POWER_SAVE_CONTROL)(&(priv->ieee80211->PowerSaveControl));
+
+ // Default Halt the NIC if RF is OFF.
+ pPSC->RegRfPsLevel |= RT_RF_OFF_LEVL_HALT_NIC;
+ pPSC->RegRfPsLevel |= RT_RF_OFF_LEVL_CLK_REQ;
+ pPSC->RegRfPsLevel |= RT_RF_OFF_LEVL_ASPM;
+ pPSC->RegRfPsLevel |= RT_RF_LPS_LEVEL_ASPM;
+ pPSC->bLeisurePs = true;
+ pPSC->RegMaxLPSAwakeIntvl = 5;
+ priv->bHwRadioOff = false;
+
priv->being_init_adapter = false;
priv->txbuffsize = 1600;//1024;
priv->txfwbuffersize = 4096;
@@ -2328,6 +2577,17 @@ static void rtl8192_init_priv_variable(struct net_device* dev)
//added by amy
priv->ieee80211->InitialGainHandler = InitialGain819xPci;
+#ifdef ENABLE_IPS
+ priv->ieee80211->ieee80211_ips_leave_wq = ieee80211_ips_leave_wq;
+ priv->ieee80211->ieee80211_ips_leave = ieee80211_ips_leave;
+#endif
+#ifdef ENABLE_LPS
+ priv->ieee80211->LeisurePSLeave = LeisurePSLeave;
+#endif//ENABL
+
+ priv->ieee80211->SetHwRegHandler = rtl8192e_SetHwReg;
+ priv->ieee80211->rtllib_ap_sec_type = rtl8192e_ap_sec_type;
+
priv->card_type = USB;
{
priv->ShortRetryLimit = 0x30;
@@ -2400,6 +2660,10 @@ static void rtl8192_init_priv_task(struct net_device* dev)
priv->priv_wq = create_workqueue(DRV_NAME);
#endif
+#ifdef ENABLE_IPS
+ INIT_WORK(&priv->ieee80211->ips_leave_wq, (void*)IPSLeave_wq);
+#endif
+
// INIT_WORK(&priv->reset_wq, (void(*)(void*)) rtl8192_restart);
INIT_WORK(&priv->reset_wq, rtl8192_restart);
// INIT_DELAYED_WORK(&priv->watch_dog_wq, hal_dm_watchdog);
@@ -2550,10 +2814,7 @@ static void rtl8192_read_eeprom_info(struct net_device* dev)
memcpy(dev->dev_addr, bMac_Tmp_Addr, 6);
}
- RT_TRACE(COMP_INIT, "Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5]);
+ RT_TRACE(COMP_INIT, "Permanent Address = %pM\n", dev->dev_addr);
//2 TX Power Check EEPROM Fail or not
if(priv->card_8192_version > VERSION_8190_BD) {
@@ -2926,13 +3187,14 @@ static void rtl8192_read_eeprom_info(struct net_device* dev)
#endif
break;
}
-/*
- //2008.06.03, for WOL
+
+
if( priv->eeprom_vid == 0x1186 && priv->eeprom_did == 0x3304)
- priv->ieee80211->bSupportRemoteWakeUp = TRUE;
+ priv->ieee80211->bSupportRemoteWakeUp = true;
else
- priv->ieee80211->bSupportRemoteWakeUp = FALSE;
-*/
+ priv->ieee80211->bSupportRemoteWakeUp = false;
+
+
RT_TRACE(COMP_INIT, "RegChannelPlan(%d)\n", priv->RegChannelPlan);
RT_TRACE(COMP_INIT, "ChannelPlan = %d \n", priv->ChannelPlan);
RT_TRACE(COMP_INIT, "LedStrategy = %d \n", priv->LedStrategy);
@@ -4006,12 +4268,19 @@ static void rtl819x_ifsilentreset(struct net_device *dev)
struct ieee80211_device *ieee = priv->ieee80211;
+ return;
+
// 2007.07.20. If we need to check CCK stop, please uncomment this line.
//bStuck = Adapter->HalFunc.CheckHWStopHandler(Adapter);
if(priv->ResetProgress==RESET_TYPE_NORESET)
{
RESET_START:
+#ifdef ENABLE_LPS
+ //LZM for PS-Poll AID issue. 090429
+ if(priv->ieee80211->state == IEEE80211_LINKED)
+ LeisurePSLeave(dev);
+#endif
RT_TRACE(COMP_RESET,"=========>Reset progress!! \n");
@@ -4051,9 +4320,9 @@ RESET_START:
}
else{
printk("ieee->state is NOT LINKED\n");
- ieee80211_softmac_stop_protocol(priv->ieee80211);
+ ieee80211_softmac_stop_protocol(priv->ieee80211,true);
}
- rtl8192_rtx_disable(dev);
+ rtl8192_halt_adapter(dev, true);
up(&priv->wx_sem);
RT_TRACE(COMP_RESET,"%s():<==========down process is finished\n",__FUNCTION__);
RT_TRACE(COMP_RESET,"%s():===========>start to up the driver\n",__FUNCTION__);
@@ -4150,6 +4419,128 @@ void InactivePsWorkItemCallback(struct net_device *dev)
RT_TRACE(COMP_POWER, "InactivePsWorkItemCallback() <--------- \n");
}
+#ifdef ENABLE_LPS
+//
+// Change current and default preamble mode.
+// 2005.01.06, by rcnjko.
+//
+bool MgntActSet_802_11_PowerSaveMode(struct net_device *dev, u8 rtPsMode)
+{
+ struct r8192_priv *priv = ieee80211_priv(dev);
+ //PRT_POWER_SAVE_CONTROL pPSC = (PRT_POWER_SAVE_CONTROL)(&(priv->ieee80211->PowerSaveControl));
+ //u8 RpwmVal, FwPwrMode;
+
+ // Currently, we do not change power save mode on IBSS mode.
+ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC)
+ {
+ return false;
+ }
+
+ //
+ // <RJ_NOTE> If we make HW to fill up the PwrMgt bit for us,
+ // some AP will not response to our mgnt frames with PwrMgt bit set,
+ // e.g. cannot associate the AP.
+ // So I commented out it. 2005.02.16, by rcnjko.
+ //
+// // Change device's power save mode.
+// Adapter->HalFunc.SetPSModeHandler( Adapter, rtPsMode );
+
+ // Update power save mode configured.
+ //RT_TRACE(COMP_LPS,"%s(): set ieee->ps = %x\n",__FUNCTION__,rtPsMode);
+ if(!priv->ps_force) {
+ priv->ieee80211->ps = rtPsMode;
+ }
+
+ // Awake immediately
+ if(priv->ieee80211->sta_sleep != 0 && rtPsMode == IEEE80211_PS_DISABLED)
+ {
+ unsigned long flags;
+
+ //PlatformSetTimer(Adapter, &(pMgntInfo->AwakeTimer), 0);
+ // Notify the AP we awke.
+ rtl8192_hw_wakeup(dev);
+ priv->ieee80211->sta_sleep = 0;
+
+ spin_lock_irqsave(&(priv->ieee80211->mgmt_tx_lock), flags);
+ printk("LPS leave: notify AP we are awaked ++++++++++ SendNullFunctionData\n");
+ ieee80211_sta_ps_send_null_frame(priv->ieee80211, 0);
+ spin_unlock_irqrestore(&(priv->ieee80211->mgmt_tx_lock), flags);
+ }
+
+ return true;
+}
+
+//================================================================================
+// Leisure Power Save in linked state.
+//================================================================================
+
+//
+// Description:
+// Enter the leisure power save mode.
+//
+void LeisurePSEnter(struct net_device *dev)
+{
+ struct r8192_priv *priv = ieee80211_priv(dev);
+ PRT_POWER_SAVE_CONTROL pPSC = (PRT_POWER_SAVE_CONTROL)(&(priv->ieee80211->PowerSaveControl));
+
+ //RT_TRACE(COMP_PS, "LeisurePSEnter()...\n");
+ //RT_TRACE(COMP_PS, "pPSC->bLeisurePs = %d, ieee->ps = %d,pPSC->LpsIdleCount is %d,RT_CHECK_FOR_HANG_PERIOD is %d\n",
+ // pPSC->bLeisurePs, priv->ieee80211->ps,pPSC->LpsIdleCount,RT_CHECK_FOR_HANG_PERIOD);
+
+ if(!((priv->ieee80211->iw_mode == IW_MODE_INFRA) &&
+ (priv->ieee80211->state == IEEE80211_LINKED)) ||
+ (priv->ieee80211->iw_mode == IW_MODE_ADHOC) ||
+ (priv->ieee80211->iw_mode == IW_MODE_MASTER))
+ return;
+
+ if (pPSC->bLeisurePs)
+ {
+ // Idle for a while if we connect to AP a while ago.
+ if(pPSC->LpsIdleCount >= RT_CHECK_FOR_HANG_PERIOD) // 4 Sec
+ {
+
+ if(priv->ieee80211->ps == IEEE80211_PS_DISABLED)
+ {
+
+ //RT_TRACE(COMP_LPS, "LeisurePSEnter(): Enter 802.11 power save mode...\n");
+ MgntActSet_802_11_PowerSaveMode(dev, IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST);
+
+ }
+ }
+ else
+ pPSC->LpsIdleCount++;
+ }
+}
+
+
+//
+// Description:
+// Leave the leisure power save mode.
+//
+void LeisurePSLeave(struct net_device *dev)
+{
+ struct r8192_priv *priv = ieee80211_priv(dev);
+ PRT_POWER_SAVE_CONTROL pPSC = (PRT_POWER_SAVE_CONTROL)(&(priv->ieee80211->PowerSaveControl));
+
+
+ //RT_TRACE(COMP_PS, "LeisurePSLeave()...\n");
+ //RT_TRACE(COMP_PS, "pPSC->bLeisurePs = %d, ieee->ps = %d\n",
+ // pPSC->bLeisurePs, priv->ieee80211->ps);
+
+ if (pPSC->bLeisurePs)
+ {
+ if(priv->ieee80211->ps != IEEE80211_PS_DISABLED)
+ {
+ // move to lps_wakecomplete()
+ //RT_TRACE(COMP_LPS, "LeisurePSLeave(): Busy Traffic , Leave 802.11 power save..\n");
+ MgntActSet_802_11_PowerSaveMode(dev, IEEE80211_PS_DISABLED);
+
+ }
+ }
+}
+#endif
+
+
//
// Description:
// Enter the inactive power save mode. RF will be off
@@ -4178,6 +4569,7 @@ IPSEnter(struct net_device *dev)
&& (priv->ieee80211->state != IEEE80211_LINKED) )
{
RT_TRACE(COMP_RF,"IPSEnter(): Turn off RF.\n");
+ //printk("IPSEnter(): Turn off RF.\n");
pPSC->eInactivePowerState = eRfOff;
// queue_work(priv->priv_wq,&(pPSC->InactivePsWorkItem));
InactivePsWorkItemCallback(dev);
@@ -4203,12 +4595,53 @@ IPSLeave(struct net_device *dev)
if (rtState != eRfOn && !pPSC->bSwRfProcessing && priv->ieee80211->RfOffReason <= RF_CHANGE_BY_IPS)
{
RT_TRACE(COMP_POWER, "IPSLeave(): Turn on RF.\n");
+ //printk("IPSLeave(): Turn on RF.\n");
pPSC->eInactivePowerState = eRfOn;
// queue_work(priv->priv_wq,&(pPSC->InactivePsWorkItem));
InactivePsWorkItemCallback(dev);
}
}
}
+
+void IPSLeave_wq(void *data)
+{
+ struct ieee80211_device *ieee = container_of(data,struct ieee80211_device,ips_leave_wq);
+ struct net_device *dev = ieee->dev;
+
+ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
+ down(&priv->ieee80211->ips_sem);
+ IPSLeave(dev);
+ up(&priv->ieee80211->ips_sem);
+}
+
+void ieee80211_ips_leave_wq(struct net_device *dev)
+{
+ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
+ RT_RF_POWER_STATE rtState;
+ rtState = priv->ieee80211->eRFPowerState;
+
+ if(priv->ieee80211->PowerSaveControl.bInactivePs){
+ if(rtState == eRfOff){
+ if(priv->ieee80211->RfOffReason > RF_CHANGE_BY_IPS)
+ {
+ RT_TRACE(COMP_ERR, "%s(): RF is OFF.\n",__FUNCTION__);
+ return;
+ }
+ else{
+ printk("=========>%s(): IPSLeave\n",__FUNCTION__);
+ queue_work(priv->ieee80211->wq,&priv->ieee80211->ips_leave_wq);
+ }
+ }
+ }
+}
+//added by amy 090331 end
+void ieee80211_ips_leave(struct net_device *dev)
+{
+ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
+ down(&priv->ieee80211->ips_sem);
+ IPSLeave(dev);
+ up(&priv->ieee80211->ips_sem);
+}
#endif
static void rtl819x_update_rxcounts(
@@ -4244,15 +4677,23 @@ void rtl819x_watchdog_wqcallback(struct work_struct *work)
unsigned long flags;
bool bBusyTraffic = false;
static u8 last_time = 0;
+ bool bEnterPS = false;
+
+ if((!priv->up) || (priv->bHwRadioOff == true))
+ return;
+
if(!priv->up)
return;
hal_dm_watchdog(dev);
#ifdef ENABLE_IPS
// printk("watch_dog ENABLE_IPS\n");
if(ieee->actscanning == false){
- if((ieee->iw_mode != IW_MODE_ADHOC) && (ieee->state == IEEE80211_NOLINK) && (ieee->beinretry == false) && (ieee->eRFPowerState == eRfOn) && !ieee->is_set_key){
+ //printk("%d,%d,%d,%d\n", ieee->eRFPowerState, ieee->is_set_key, ieee->proto_stoppping, ieee->wx_set_enc);
+ if((ieee->iw_mode == IW_MODE_INFRA) && (ieee->state == IEEE80211_NOLINK) &&\
+ (ieee->eRFPowerState == eRfOn)&&!ieee->is_set_key &&\
+ (!ieee->proto_stoppping) && !ieee->wx_set_enc){
if(ieee->PowerSaveControl.ReturnPoint == IPS_CALLBACK_NONE){
- printk("====================>haha:IPSEnter()\n");
+ //printk("====================>haha:IPSEnter()\n");
IPSEnter(dev);
//ieee80211_stop_scan(priv->ieee80211);
}
@@ -4262,14 +4703,49 @@ void rtl819x_watchdog_wqcallback(struct work_struct *work)
{//to get busy traffic condition
if(ieee->state == IEEE80211_LINKED)
{
- if( ieee->LinkDetectInfo.NumRxOkInPeriod> 666 ||
- ieee->LinkDetectInfo.NumTxOkInPeriod> 666 ) {
+ if( ieee->LinkDetectInfo.NumRxOkInPeriod> 100 ||
+ ieee->LinkDetectInfo.NumTxOkInPeriod> 100 ) {
bBusyTraffic = true;
}
+#ifdef ENABLE_LPS
+ //added by amy for Leisure PS
+ if( ((ieee->LinkDetectInfo.NumRxUnicastOkInPeriod + ieee->LinkDetectInfo.NumTxOkInPeriod) > 8 ) ||
+ (ieee->LinkDetectInfo.NumRxUnicastOkInPeriod > 2) )
+ {
+ //printk("ieee->LinkDetectInfo.NumRxUnicastOkInPeriod is %d,ieee->LinkDetectInfo.NumTxOkInPeriod is %d\n",
+ // ieee->LinkDetectInfo.NumRxUnicastOkInPeriod,ieee->LinkDetectInfo.NumTxOkInPeriod);
+ bEnterPS= false;
+ }
+ else
+ {
+ bEnterPS= true;
+ }
+
+ //printk("***bEnterPS = %d\n", bEnterPS);
+ // LeisurePS only work in infra mode.
+ if(bEnterPS)
+ {
+ LeisurePSEnter(dev);
+ }
+ else
+ {
+ LeisurePSLeave(dev);
+ }
+#endif
+
+ }
+ else
+ {
+#ifdef ENABLE_LPS
+ //RT_TRACE(COMP_LPS,"====>no link LPS leave\n");
+ LeisurePSLeave(dev);
+#endif
}
+
ieee->LinkDetectInfo.NumRxOkInPeriod = 0;
ieee->LinkDetectInfo.NumTxOkInPeriod = 0;
+ ieee->LinkDetectInfo.NumRxUnicastOkInPeriod = 0;
ieee->LinkDetectInfo.bBusyTraffic = bBusyTraffic;
}
@@ -4288,14 +4764,14 @@ void rtl819x_watchdog_wqcallback(struct work_struct *work)
if( ieee->eRFPowerState == eRfOff)
RT_TRACE(COMP_ERR,"========>%s()\n",__FUNCTION__);
printk("===>%s(): AP is power off,connect another one\n",__FUNCTION__);
- // Dot11d_Reset(dev);
+ // Dot11d_Reset(dev);
ieee->state = IEEE80211_ASSOCIATING;
notify_wx_assoc_event(priv->ieee80211);
- RemovePeerTS(priv->ieee80211,priv->ieee80211->current_network.bssid);
+ RemovePeerTS(priv->ieee80211,priv->ieee80211->current_network.bssid);
ieee->is_roaming = true;
ieee->is_set_key = false;
- ieee->link_change(dev);
- queue_work(ieee->wq, &ieee->associate_procedure_wq);
+ ieee->link_change(dev);
+ queue_work(ieee->wq, &ieee->associate_procedure_wq);
}
}
ieee->LinkDetectInfo.NumRecvBcnInPeriod=0;
@@ -4348,6 +4824,7 @@ int _rtl8192_up(struct net_device *dev)
RT_STATUS init_status = RT_STATUS_SUCCESS;
priv->up=1;
priv->ieee80211->ieee_up=1;
+ priv->bdisable_nic = false; //YJ,add,091111
RT_TRACE(COMP_INIT, "Bringing up iface");
init_status = rtl8192_adapter_start(dev);
@@ -4422,6 +4899,12 @@ int rtl8192_down(struct net_device *dev)
#endif
if (priv->up == 0) return -1;
+#ifdef ENABLE_LPS
+ //LZM for PS-Poll AID issue. 090429
+ if(priv->ieee80211->state == IEEE80211_LINKED)
+ LeisurePSLeave(dev);
+#endif
+
priv->up=0;
priv->ieee80211->ieee_up = 0;
RT_TRACE(COMP_DOWN, "==========>%s()\n", __FUNCTION__);
@@ -4459,11 +4942,9 @@ int rtl8192_down(struct net_device *dev)
deinit_hal_dm(dev);
del_timer_sync(&priv->watch_dog_timer);
- ieee80211_softmac_stop_protocol(priv->ieee80211);
-#ifdef ENABLE_IPS
- MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_INIT);
-#endif
- rtl8192_rtx_disable(dev);
+ ieee80211_softmac_stop_protocol(priv->ieee80211,true);
+
+ rtl8192_halt_adapter(dev,false);
memset(&priv->ieee80211->current_network, 0 , offsetof(struct ieee80211_network, list));
RT_TRACE(COMP_DOWN, "<==========%s()\n", __FUNCTION__);
@@ -4479,10 +4960,10 @@ void rtl8192_commit(struct net_device *dev)
if (priv->up == 0) return ;
- ieee80211_softmac_stop_protocol(priv->ieee80211);
+ ieee80211_softmac_stop_protocol(priv->ieee80211,true);
rtl8192_irq_disable(dev);
- rtl8192_rtx_disable(dev);
+ rtl8192_halt_adapter(dev,true);
_rtl8192_up(dev);
}
@@ -5806,8 +6287,7 @@ static void rtl8192_rx(struct net_device *dev)
skb = new_skb;
priv->rx_buf[priv->rx_idx] = skb;
- *((dma_addr_t *) skb->cb) = pci_map_single(priv->pdev, skb->tail, priv->rxbuffersize, PCI_DMA_FROMDEVICE);
-// *((dma_addr_t *) skb->cb) = pci_map_single(priv->pdev, skb_tail_pointer(skb), priv->rxbuffersize, PCI_DMA_FROMDEVICE);
+ *((dma_addr_t *) skb->cb) = pci_map_single(priv->pdev, skb_tail_pointer(skb), priv->rxbuffersize, PCI_DMA_FROMDEVICE);
}
}
@@ -6036,7 +6516,7 @@ void rtl8192_cancel_deferred_work(struct r8192_priv* priv)
/* call cancel_work_sync instead of cancel_delayed_work if and only if Linux_version_code
* is or is newer than 2.6.20 and work structure is defined to be struct work_struct.
* Otherwise call cancel_delayed_work is enough.
- * FIXME (2.6.20 shoud 2.6.22, work_struct shoud not cancel)
+ * FIXME (2.6.20 should 2.6.22, work_struct should not cancel)
* */
cancel_delayed_work(&priv->watch_dog_wq);
cancel_delayed_work(&priv->update_beacon_wq);
@@ -6381,11 +6861,13 @@ void setKey( struct net_device *dev,
if(priv->ieee80211->RfOffReason > RF_CHANGE_BY_IPS)
{
RT_TRACE(COMP_ERR, "%s(): RF is OFF.\n",__FUNCTION__);
- up(&priv->wx_sem);
+ //up(&priv->wx_sem);
return ;
}
else{
+ down(&priv->ieee80211->ips_sem);
IPSLeave(dev);
+ up(&priv->ieee80211->ips_sem);
}
}
}
@@ -6394,7 +6876,7 @@ void setKey( struct net_device *dev,
if (EntryNo >= TOTAL_CAM_ENTRY)
RT_TRACE(COMP_ERR, "cam entry exceeds in setKey()\n");
- RT_TRACE(COMP_SEC, "====>to setKey(), dev:%p, EntryNo:%d, KeyIndex:%d, KeyType:%d, MacAddr"MAC_FMT"\n", dev,EntryNo, KeyIndex, KeyType, MAC_ARG(MacAddr));
+ RT_TRACE(COMP_SEC, "====>to setKey(), dev:%p, EntryNo:%d, KeyIndex:%d, KeyType:%d, MacAddr%pM\n", dev,EntryNo, KeyIndex, KeyType, MacAddr);
if (DefaultKey)
usConfig |= BIT15 | (KeyType<<2);
@@ -6455,6 +6937,65 @@ void CamPrintDbgReg(struct net_device* dev)
RT_TRACE(COMP_SEC, "WPA_Config=%x \n",ucValue);
}
+bool NicIFEnableNIC(struct net_device* dev)
+{
+ RT_STATUS init_status = RT_STATUS_SUCCESS;
+ struct r8192_priv* priv = ieee80211_priv(dev);
+ PRT_POWER_SAVE_CONTROL pPSC = (PRT_POWER_SAVE_CONTROL)(&(priv->ieee80211->PowerSaveControl));
+
+ //YJ,add,091109
+ if (priv->up == 0){
+ RT_TRACE(COMP_ERR, "ERR!!! %s(): Driver is already down!\n",__FUNCTION__);
+ priv->bdisable_nic = false; //YJ,add,091111
+ return false;
+ }
+ // <1> Reset memory: descriptor, buffer,..
+ //NicIFResetMemory(Adapter);
+
+ // <2> Enable Adapter
+ //printk("===========>%s()\n",__FUNCTION__);
+ //priv->bfirst_init = true;
+ init_status = rtl8192_adapter_start(dev);
+ if (init_status != RT_STATUS_SUCCESS) {
+ RT_TRACE(COMP_ERR,"ERR!!! %s(): initialization is failed!\n",__FUNCTION__);
+ priv->bdisable_nic = false; //YJ,add,091111
+ return -1;
+ }
+ //printk("start adapter finished\n");
+ RT_CLEAR_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC);
+ //priv->bfirst_init = false;
+
+ // <3> Enable Interrupt
+ rtl8192_irq_enable(dev);
+ priv->bdisable_nic = false;
+ //RT_TRACE(COMP_PS,"<===========%s()\n",__FUNCTION__);
+ return (init_status == RT_STATUS_SUCCESS) ? true:false;
+}
+bool NicIFDisableNIC(struct net_device* dev)
+{
+ bool status = true;
+ struct r8192_priv* priv = ieee80211_priv(dev);
+ u8 tmp_state = 0;
+ // <1> Disable Interrupt
+ //RT_TRACE(COMP_PS, "=========>%s()\n",__FUNCTION__);
+ priv->bdisable_nic = true; //YJ,move,091109
+ tmp_state = priv->ieee80211->state;
+
+ ieee80211_softmac_stop_protocol(priv->ieee80211, false);
+
+ priv->ieee80211->state = tmp_state;
+ rtl8192_cancel_deferred_work(priv);
+ rtl8192_irq_disable(dev);
+ // <2> Stop all timer
+
+ // <3> Disable Adapter
+ rtl8192_halt_adapter(dev, false);
+// priv->bdisable_nic = true;
+ //RT_TRACE(COMP_PS, "<=========%s()\n",__FUNCTION__);
+
+ return status;
+}
+
/***************************************************************************
------------------- module init / exit stubs ----------------
diff --git a/drivers/staging/rtl8192e/r8192E_dm.c b/drivers/staging/rtl8192e/r8192E_dm.c
index 5ffb4f74055b..a249f00da60d 100644
--- a/drivers/staging/rtl8192e/r8192E_dm.c
+++ b/drivers/staging/rtl8192e/r8192E_dm.c
@@ -19,26 +19,28 @@ Major Change History:
#include "r819xE_phy.h"
#include "r819xE_phyreg.h"
#include "r8190_rtl8256.h"
+
+#define DRV_NAME "rtl819xE"
/*---------------------------Define Local Constant---------------------------*/
//
// Indicate different AP vendor for IOT issue.
//
#ifdef RTL8190P
static u32 edca_setting_DL[HT_IOT_PEER_MAX] =
-{ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5e4322};
+{ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5e4322, 0x5e4322};
static u32 edca_setting_UL[HT_IOT_PEER_MAX] =
-{ 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5e4322, 0x5e4322};
+{ 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5e4322, 0x5e4322, 0x5e4322};
#else
#ifdef RTL8192E
static u32 edca_setting_DL[HT_IOT_PEER_MAX] =
-{ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5e4322};
+{ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5e4322, 0x5e4322};
static u32 edca_setting_UL[HT_IOT_PEER_MAX] =
-{ 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5e4322, 0x5e4322};
+{ 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5e4322, 0x5e4322, 0x5e4322};
#else
static u32 edca_setting_DL[HT_IOT_PEER_MAX] =
-{ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5ea44f};
+{ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5ea44f, 0x5e4322};
static u32 edca_setting_UL[HT_IOT_PEER_MAX] =
-{ 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5ea44f, 0x5ea44f};
+{ 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5ea44f, 0x5ea44f, 0x5e4322};
#endif
#endif
@@ -275,6 +277,30 @@ void dm_CheckRxAggregation(struct net_device *dev) {
#endif
+// call the script file to enable
+void dm_check_ac_dc_power(struct net_device *dev)
+{
+ struct r8192_priv *priv = ieee80211_priv(dev);
+ static char *ac_dc_check_script_path = "/etc/acpi/wireless-rtl-ac-dc-power.sh";
+ char *argv[] = {ac_dc_check_script_path,DRV_NAME,NULL};
+ static char *envp[] = {"HOME=/",
+ "TERM=linux",
+ "PATH=/usr/bin:/bin",
+ NULL};
+
+ if(priv->ResetProgress == RESET_TYPE_SILENT)
+ {
+ RT_TRACE((COMP_INIT | COMP_POWER | COMP_RF), "GPIOChangeRFWorkItemCallBack(): Silent Reseting!!!!!!!\n");
+ return;
+ }
+
+ if(priv->ieee80211->state != IEEE80211_LINKED) {
+ return;
+ }
+ call_usermodehelper(ac_dc_check_script_path,argv,envp,1);
+
+ return;
+};
void hal_dm_watchdog(struct net_device *dev)
{
@@ -282,6 +308,8 @@ void hal_dm_watchdog(struct net_device *dev)
//static u8 previous_bssid[6] ={0};
+ dm_check_ac_dc_power(dev);
+
/*Add by amy 2008/05/15 ,porting from windows code.*/
dm_check_rate_adaptive(dev);
dm_dynamic_txpower(dev);
diff --git a/drivers/staging/rtl8192e/r8192E_hw.h b/drivers/staging/rtl8192e/r8192E_hw.h
index 388908fc8d20..346bfb18e2b0 100644
--- a/drivers/staging/rtl8192e/r8192E_hw.h
+++ b/drivers/staging/rtl8192e/r8192E_hw.h
@@ -808,4 +808,12 @@ enum _RTL8192Pci_HW {
#define GPI 0x108
#define GPO 0x109
#define GPE 0x10a
+
+#define ANAPAR_FOR_8192PciE 0x17 // Analog parameter register
+
+#define MSR_NOLINK 0x00
+#define MSR_ADHOC 0x01
+#define MSR_INFRA 0x02
+#define MSR_AP 0x03
+
#endif
diff --git a/drivers/staging/rtl8192e/r8192E_wx.c b/drivers/staging/rtl8192e/r8192E_wx.c
index d1eb89229cdf..0b0f39ce3ced 100644
--- a/drivers/staging/rtl8192e/r8192E_wx.c
+++ b/drivers/staging/rtl8192e/r8192E_wx.c
@@ -22,7 +22,7 @@
#include "r8192E_hw.h"
#include "r8192E_wx.h"
#ifdef ENABLE_DOT11D
-#include "dot11d.h"
+#include "ieee80211/dot11d.h"
#endif
#define RATE_COUNT 12
@@ -70,6 +70,9 @@ static int r8192_wx_set_rate(struct net_device *dev,
int ret;
struct r8192_priv *priv = ieee80211_priv(dev);
+ if(priv->bHwRadioOff == true)
+ return 0;
+
down(&priv->wx_sem);
ret = ieee80211_wx_set_rate(priv->ieee80211,info,wrqu,extra);
@@ -87,6 +90,9 @@ static int r8192_wx_set_rts(struct net_device *dev,
int ret;
struct r8192_priv *priv = ieee80211_priv(dev);
+ if(priv->bHwRadioOff == true)
+ return 0;
+
down(&priv->wx_sem);
ret = ieee80211_wx_set_rts(priv->ieee80211,info,wrqu,extra);
@@ -111,6 +117,9 @@ static int r8192_wx_set_power(struct net_device *dev,
int ret;
struct r8192_priv *priv = ieee80211_priv(dev);
+ if(priv->bHwRadioOff == true)
+ return 0;
+
down(&priv->wx_sem);
ret = ieee80211_wx_set_power(priv->ieee80211,info,wrqu,extra);
@@ -290,6 +299,9 @@ static int r8192_wx_set_rawtx(struct net_device *dev,
struct r8192_priv *priv = ieee80211_priv(dev);
int ret;
+ if(priv->bHwRadioOff == true)
+ return 0;
+
down(&priv->wx_sem);
ret = ieee80211_wx_set_rawtx(priv->ieee80211, info, wrqu, extra);
@@ -325,6 +337,9 @@ static int r8192_wx_set_crcmon(struct net_device *dev,
int enable = (parms[0] > 0);
short prev = priv->crcmon;
+ if(priv->bHwRadioOff == true)
+ return 0;
+
down(&priv->wx_sem);
if(enable)
@@ -352,6 +367,9 @@ static int r8192_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
RT_RF_POWER_STATE rtState;
int ret;
+ if(priv->bHwRadioOff == true)
+ return 0;
+
rtState = priv->ieee80211->eRFPowerState;
down(&priv->wx_sem);
#ifdef ENABLE_IPS
@@ -366,8 +384,10 @@ static int r8192_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
return -1;
}
else{
- printk("=========>%s(): IPSLeave\n",__FUNCTION__);
+ RT_TRACE(COMP_ERR, "%s(): IPSLeave\n",__FUNCTION__);
+ down(&priv->ieee80211->ips_sem);
IPSLeave(dev);
+ up(&priv->ieee80211->ips_sem);
}
}
}
@@ -425,7 +445,7 @@ static int rtl8180_wx_get_range(struct net_device *dev,
*/
/* ~5 Mb/s real (802.11b) */
- range->throughput = 5 * 1000 * 1000;
+ range->throughput = 130 * 1000 * 1000;
// TODO: Not used in 802.11b?
// range->min_nwid; /* Minimal NWID we are able to set */
@@ -468,7 +488,7 @@ static int rtl8180_wx_get_range(struct net_device *dev,
range->pmt_flags = IW_POWER_TIMEOUT;
range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 16;
+ range->we_version_source = 18;
// range->retry_capa; /* What retry options are supported */
// range->retry_flags; /* How to decode max/min retry limit */
@@ -517,7 +537,12 @@ static int r8192_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
struct ieee80211_device* ieee = priv->ieee80211;
RT_RF_POWER_STATE rtState;
int ret;
+
+ if(priv->bHwRadioOff == true)
+ return 0;
+
rtState = priv->ieee80211->eRFPowerState;
+
if(!priv->up) return -ENETDOWN;
if (priv->ieee80211->LinkDetectInfo.bBusyTraffic == true)
return -EAGAIN;
@@ -547,8 +572,10 @@ static int r8192_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
return -1;
}
else{
- printk("=========>%s(): IPSLeave\n",__FUNCTION__);
+ //RT_TRACE(COMP_PS, "%s(): IPSLeave\n",__FUNCTION__);
+ down(&priv->ieee80211->ips_sem);
IPSLeave(dev);
+ up(&priv->ieee80211->ips_sem);
}
}
}
@@ -580,6 +607,9 @@ static int r8192_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
int ret;
struct r8192_priv *priv = ieee80211_priv(dev);
+ if(priv->bHwRadioOff == true)
+ return 0;
+
if(!priv->up) return -ENETDOWN;
down(&priv->wx_sem);
@@ -599,23 +629,16 @@ static int r8192_wx_set_essid(struct net_device *dev,
RT_RF_POWER_STATE rtState;
int ret;
+ if(priv->bHwRadioOff == true)
+ return 0;
+
rtState = priv->ieee80211->eRFPowerState;
down(&priv->wx_sem);
+
#ifdef ENABLE_IPS
- if(priv->ieee80211->PowerSaveControl.bInactivePs){
- if(rtState == eRfOff){
- if(priv->ieee80211->RfOffReason > RF_CHANGE_BY_IPS)
- {
- RT_TRACE(COMP_ERR, "%s(): RF is OFF.\n",__FUNCTION__);
- up(&priv->wx_sem);
- return -1;
- }
- else{
- printk("=========>%s(): IPSLeave\n",__FUNCTION__);
- IPSLeave(dev);
- }
- }
- }
+ down(&priv->ieee80211->ips_sem);
+ IPSLeave(dev);
+ up(&priv->ieee80211->ips_sem);
#endif
ret = ieee80211_wx_set_essid(priv->ieee80211,a,wrqu,b);
@@ -650,6 +673,9 @@ static int r8192_wx_set_freq(struct net_device *dev, struct iw_request_info *a,
int ret;
struct r8192_priv *priv = ieee80211_priv(dev);
+ if(priv->bHwRadioOff == true)
+ return 0;
+
down(&priv->wx_sem);
ret = ieee80211_wx_set_freq(priv->ieee80211, a, wrqu, b);
@@ -673,6 +699,9 @@ static int r8192_wx_set_frag(struct net_device *dev,
{
struct r8192_priv *priv = ieee80211_priv(dev);
+ if(priv->bHwRadioOff == true)
+ return 0;
+
if (wrqu->frag.disabled)
priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD;
else {
@@ -711,8 +740,16 @@ static int r8192_wx_set_wap(struct net_device *dev,
struct r8192_priv *priv = ieee80211_priv(dev);
// struct sockaddr *temp = (struct sockaddr *)awrq;
+ if(priv->bHwRadioOff == true)
+ return 0;
+
down(&priv->wx_sem);
+#ifdef ENABLE_IPS
+ down(&priv->ieee80211->ips_sem);
+ IPSLeave(dev);
+ up(&priv->ieee80211->ips_sem);
+#endif
ret = ieee80211_wx_set_wap(priv->ieee80211,info,awrq,extra);
up(&priv->wx_sem);
@@ -753,14 +790,24 @@ static int r8192_wx_set_enc(struct net_device *dev,
u32 hwkey[4]={0,0,0,0};
u8 mask=0xff;
u32 key_idx=0;
- u8 zero_addr[4][6] ={ {0x00,0x00,0x00,0x00,0x00,0x00},
+ u8 zero_addr[4][6] ={{0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x01},
{0x00,0x00,0x00,0x00,0x00,0x02},
{0x00,0x00,0x00,0x00,0x00,0x03} };
int i;
+ if(priv->bHwRadioOff == true)
+ return 0;
+
if(!priv->up) return -ENETDOWN;
+ priv->ieee80211->wx_set_enc = 1;
+#ifdef ENABLE_IPS
+ down(&priv->ieee80211->ips_sem);
+ IPSLeave(dev);
+ up(&priv->ieee80211->ips_sem);
+#endif
+
down(&priv->wx_sem);
RT_TRACE(COMP_SEC, "Setting SW wep key");
@@ -768,7 +815,6 @@ static int r8192_wx_set_enc(struct net_device *dev,
up(&priv->wx_sem);
-
//sometimes, the length is zero while we do not type key value
if(wrqu->encoding.length!=0){
@@ -868,6 +914,8 @@ static int r8192_wx_set_enc(struct net_device *dev,
}
#endif
+ priv->ieee80211->wx_set_enc = 0;
+
return ret;
}
@@ -893,6 +941,9 @@ static int r8192_wx_set_retry(struct net_device *dev,
struct r8192_priv *priv = ieee80211_priv(dev);
int err = 0;
+ if(priv->bHwRadioOff == true)
+ return 0;
+
down(&priv->wx_sem);
if (wrqu->retry.flags & IW_RETRY_LIFETIME ||
@@ -985,6 +1036,10 @@ static int r8192_wx_set_sens(struct net_device *dev,
struct r8192_priv *priv = ieee80211_priv(dev);
short err = 0;
+
+ if(priv->bHwRadioOff == true)
+ return 0;
+
down(&priv->wx_sem);
//DMESG("attempt to set sensivity to %ddb",wrqu->sens.value);
if(priv->rf_set_sens == NULL) {
@@ -1011,7 +1066,19 @@ static int r8192_wx_set_enc_ext(struct net_device *dev,
struct r8192_priv *priv = ieee80211_priv(dev);
struct ieee80211_device* ieee = priv->ieee80211;
+ if(priv->bHwRadioOff == true)
+ return 0;
+
down(&priv->wx_sem);
+
+ priv->ieee80211->wx_set_enc = 1;
+
+#ifdef ENABLE_IPS
+ down(&priv->ieee80211->ips_sem);
+ IPSLeave(dev);
+ up(&priv->ieee80211->ips_sem);
+#endif
+
ret = ieee80211_wx_set_encode_ext(ieee, info, wrqu, extra);
{
@@ -1091,6 +1158,7 @@ static int r8192_wx_set_enc_ext(struct net_device *dev,
}
end_hw_sec:
+ priv->ieee80211->wx_set_enc = 0;
up(&priv->wx_sem);
return ret;
@@ -1102,6 +1170,10 @@ static int r8192_wx_set_auth(struct net_device *dev,
int ret=0;
//printk("====>%s()\n", __FUNCTION__);
struct r8192_priv *priv = ieee80211_priv(dev);
+
+ if(priv->bHwRadioOff == true)
+ return 0;
+
down(&priv->wx_sem);
ret = ieee80211_wx_set_auth(priv->ieee80211, info, &(data->param), extra);
up(&priv->wx_sem);
@@ -1116,6 +1188,10 @@ static int r8192_wx_set_mlme(struct net_device *dev,
int ret=0;
struct r8192_priv *priv = ieee80211_priv(dev);
+
+ if(priv->bHwRadioOff == true)
+ return 0;
+
down(&priv->wx_sem);
ret = ieee80211_wx_set_mlme(priv->ieee80211, info, wrqu, extra);
up(&priv->wx_sem);
@@ -1129,6 +1205,10 @@ static int r8192_wx_set_gen_ie(struct net_device *dev,
//printk("====>%s(), len:%d\n", __FUNCTION__, data->length);
int ret=0;
struct r8192_priv *priv = ieee80211_priv(dev);
+
+ if(priv->bHwRadioOff == true)
+ return 0;
+
down(&priv->wx_sem);
ret = ieee80211_wx_set_gen_ie(priv->ieee80211, extra, data->data.length);
up(&priv->wx_sem);
@@ -1142,6 +1222,42 @@ static int dummy(struct net_device *dev, struct iw_request_info *a,
return -1;
}
+// check ac/dc status with the help of user space application */
+static int r8192_wx_adapter_power_status(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct r8192_priv *priv = ieee80211_priv(dev);
+#ifdef ENABLE_LPS
+ PRT_POWER_SAVE_CONTROL pPSC = (PRT_POWER_SAVE_CONTROL)(&(priv->ieee80211->PowerSaveControl));
+ struct ieee80211_device* ieee = priv->ieee80211;
+#endif
+ down(&priv->wx_sem);
+
+#ifdef ENABLE_LPS
+ RT_TRACE(COMP_POWER, "%s(): %s\n",__FUNCTION__, (*extra == 6)?"DC power":"AC power");
+ // ieee->ps shall not be set under DC mode, otherwise it conflict
+ // with Leisure power save mode setting.
+ //
+ if(*extra || priv->force_lps) {
+ priv->ps_force = false;
+ pPSC->bLeisurePs = true;
+ } else {
+ //LZM for PS-Poll AID issue. 090429
+ if(priv->ieee80211->state == IEEE80211_LINKED)
+ LeisurePSLeave(dev);
+
+ priv->ps_force = true;
+ pPSC->bLeisurePs = false;
+ ieee->ps = *extra;
+ }
+
+#endif
+ up(&priv->wx_sem);
+ return 0;
+
+}
+
static iw_handler r8192_wx_handlers[] =
{
@@ -1231,72 +1347,28 @@ static const struct iw_priv_args r8192_private_args[] = {
SIOCIWFIRSTPRIV + 0x2,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rawtx"
}
-#ifdef JOHN_IOCTL
,
{
SIOCIWFIRSTPRIV + 0x3,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readRF"
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "forcereset"
+
}
,
{
SIOCIWFIRSTPRIV + 0x4,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writeRF"
- }
- ,
- {
- SIOCIWFIRSTPRIV + 0x5,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readBB"
- }
- ,
- {
- SIOCIWFIRSTPRIV + 0x6,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writeBB"
- }
- ,
- {
- SIOCIWFIRSTPRIV + 0x7,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readnicb"
- }
- ,
- {
- SIOCIWFIRSTPRIV + 0x8,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writenicb"
- }
- ,
- {
- SIOCIWFIRSTPRIV + 0x9,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo"
- }
-
-#endif
- ,
- {
- SIOCIWFIRSTPRIV + 0x3,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "forcereset"
-
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED|1, IW_PRIV_TYPE_NONE,
+ "set_power"
}
};
static iw_handler r8192_private_handler[] = {
-// r8192_wx_set_monitor, /* SIOCIWFIRSTPRIV */
r8192_wx_set_crcmon, /*SIOCIWSECONDPRIV*/
-// r8192_wx_set_forceassociate,
-// r8192_wx_set_beaconinterval,
-// r8192_wx_set_monitor_type,
r8192_wx_set_scan_type,
r8192_wx_set_rawtx,
-#ifdef JOHN_IOCTL
- r8192_wx_read_regs,
- r8192_wx_write_regs,
- r8192_wx_read_bb,
- r8192_wx_write_bb,
- r8192_wx_read_nicb,
- r8192_wx_write_nicb,
- r8192_wx_get_ap_status
-#endif
r8192_wx_force_reset,
+ r8192_wx_adapter_power_status,
};
//#if WIRELESS_EXT >= 17
diff --git a/drivers/staging/rtl8192e/r8192E_wx.h b/drivers/staging/rtl8192e/r8192E_wx.h
index 79ebdb698a41..047030bc051a 100644
--- a/drivers/staging/rtl8192e/r8192E_wx.h
+++ b/drivers/staging/rtl8192e/r8192E_wx.h
@@ -15,7 +15,6 @@
#ifndef R8180_WX_H
#define R8180_WX_H
//#include <linux/wireless.h>
-//#include "ieee80211.h"
extern struct iw_handler_def r8192_wx_handlers_def;
/* Enable the rtl819x_core.c to share this function, david 2008.9.22 */
extern struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev);
diff --git a/drivers/staging/rtl8192e/r819xE_cmdpkt.c b/drivers/staging/rtl8192e/r819xE_cmdpkt.c
index 2aaa4e1bb375..87c334fb7333 100644
--- a/drivers/staging/rtl8192e/r819xE_cmdpkt.c
+++ b/drivers/staging/rtl8192e/r819xE_cmdpkt.c
@@ -135,7 +135,7 @@ RT_STATUS cmpk_message_handle_tx(
* Transform from little endian to big endian
* and pending zero
*/
- seg_ptr = skb->tail;
+ seg_ptr = skb_tail_pointer(skb);
for(i=0 ; i < frag_length; i+=4) {
*seg_ptr++ = ((i+0)<frag_length)?code_virtual_address[i+3]:0;
*seg_ptr++ = ((i+1)<frag_length)?code_virtual_address[i+2]:0;
diff --git a/drivers/staging/rtl8192e/r819xE_firmware.c b/drivers/staging/rtl8192e/r819xE_firmware.c
index 1f9e413bcd49..793a17545554 100644
--- a/drivers/staging/rtl8192e/r819xE_firmware.c
+++ b/drivers/staging/rtl8192e/r819xE_firmware.c
@@ -1,5 +1,5 @@
/*
- * Procedure: Init boot code/firmware code/data session
+ * Procedure: Init boot code/firmware code/data session
*
* Description: This routine will intialize firmware. If any error occurs
* during the initialization process, the routine shall terminate
@@ -7,19 +7,21 @@
* NdisOpenFile only from MiniportInitialize.
*
* Arguments: The pointer of the adapter
-
+ *
* Returns:
* NDIS_STATUS_FAILURE - the following initialization process
* should be terminated
* NDIS_STATUS_SUCCESS - if firmware initialization process
* success
*/
+
#include "r8192E.h"
#include "r8192E_hw.h"
+
#include <linux/firmware.h>
/* It should be double word alignment */
-#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) (4 * (v / 4) - 8)
+#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) (4 * (v / 4) - 8)
enum firmware_init_step {
FW_INIT_STEP0_BOOT = 0,
@@ -47,17 +49,17 @@ void firmware_init_param(struct net_device *dev)
static bool fw_download_code(struct net_device *dev, u8 *code_virtual_address,
u32 buffer_len)
{
- struct r8192_priv *priv = ieee80211_priv(dev);
- bool rt_status = true;
- u16 frag_threshold;
- u16 frag_length, frag_offset = 0;
- int i;
-
- rt_firmware *pfirmware = priv->pFirmware;
- struct sk_buff *skb;
- unsigned char *seg_ptr;
- cb_desc *tcb_desc;
- u8 bLastIniPkt;
+ struct r8192_priv *priv = ieee80211_priv(dev);
+ bool rt_status = true;
+ u16 frag_threshold;
+ u16 frag_length, frag_offset = 0;
+ int i;
+
+ rt_firmware *pfirmware = priv->pFirmware;
+ struct sk_buff *skb;
+ unsigned char *seg_ptr;
+ cb_desc *tcb_desc;
+ u8 bLastIniPkt;
firmware_init_param(dev);
@@ -89,10 +91,17 @@ static bool fw_download_code(struct net_device *dev, u8 *code_virtual_address,
* Transform from little endian to big endian and pending zero
*/
for (i = 0; i < frag_length; i += 4) {
- *seg_ptr++ = ((i+0) < frag_length) ? code_virtual_address[i+3] : 0;
- *seg_ptr++ = ((i+1) < frag_length) ? code_virtual_address[i+2] : 0;
- *seg_ptr++ = ((i+2) < frag_length) ? code_virtual_address[i+1] : 0;
- *seg_ptr++ = ((i+3) < frag_length) ? code_virtual_address[i+0] : 0;
+ *seg_ptr++ = ((i+0) < frag_length) ? \
+ code_virtual_address[i+3] : 0;
+
+ *seg_ptr++ = ((i+1) < frag_length) ? \
+ code_virtual_address[i+2] : 0;
+
+ *seg_ptr++ = ((i+2) < frag_length) ? \
+ code_virtual_address[i+1] : 0;
+
+ *seg_ptr++ = ((i+3) < frag_length) ? \
+ code_virtual_address[i+0] : 0;
}
tcb_desc->txbuf_size = (u16)i;
skb_put(skb, i);
@@ -204,16 +213,16 @@ CPUCheckFirmwareReady_Fail:
bool init_firmware(struct net_device *dev)
{
- struct r8192_priv *priv = ieee80211_priv(dev);
- bool rt_status = TRUE;
- u32 file_length = 0;
- u8 *mapped_file = NULL;
- u32 init_step = 0;
- enum opt_rst_type rst_opt = OPT_SYSTEM_RESET;
+ struct r8192_priv *priv = ieee80211_priv(dev);
+ bool rt_status = true;
+ u32 file_length = 0;
+ u8 *mapped_file = NULL;
+ u32 init_step = 0;
+ enum opt_rst_type rst_opt = OPT_SYSTEM_RESET;
enum firmware_init_step starting_state = FW_INIT_STEP0_BOOT;
- rt_firmware *pfirmware = priv->pFirmware;
- const struct firmware *fw_entry;
+ rt_firmware *pfirmware = priv->pFirmware;
+ const struct firmware *fw_entry;
const char *fw_name[3] = { "RTL8192E/boot.img",
"RTL8192E/main.img",
"RTL8192E/data.img"};
@@ -240,31 +249,37 @@ bool init_firmware(struct net_device *dev)
* Download boot, main, and data image for System reset.
* Download data image for firmware reseta
*/
- for (init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) {
+ for (init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; \
+ init_step++) {
/*
* Open Image file, and map file to contineous memory if open file success.
* or read image file from array. Default load from IMG file
*/
if (rst_opt == OPT_SYSTEM_RESET) {
if (pfirmware->firmware_buf_size[init_step] == 0) {
- rc = request_firmware(&fw_entry, fw_name[init_step], &priv->pdev->dev);
+ rc = request_firmware(&fw_entry,
+ fw_name[init_step], &priv->pdev->dev);
+
if (rc < 0) {
RT_TRACE(COMP_FIRMWARE, "request firmware fail!\n");
goto download_firmware_fail;
}
if (fw_entry->size > sizeof(pfirmware->firmware_buf[init_step])) {
- RT_TRACE(COMP_FIRMWARE, "img file size exceed the container buffer fail!\n");
+ RT_TRACE(COMP_FIRMWARE, \
+ "img file size exceed the container buffer fail!\n");
goto download_firmware_fail;
}
if (init_step != FW_INIT_STEP1_MAIN) {
- memcpy(pfirmware->firmware_buf[init_step], fw_entry->data, fw_entry->size);
+ memcpy(pfirmware->firmware_buf[init_step],
+ fw_entry->data, fw_entry->size);
pfirmware->firmware_buf_size[init_step] = fw_entry->size;
} else {
memset(pfirmware->firmware_buf[init_step], 0, 128);
- memcpy(&pfirmware->firmware_buf[init_step][128], fw_entry->data, fw_entry->size);
+ memcpy(&pfirmware->firmware_buf[init_step][128], fw_entry->data,
+ fw_entry->size);
pfirmware->firmware_buf_size[init_step] = fw_entry->size+128;
}
@@ -273,6 +288,7 @@ bool init_firmware(struct net_device *dev)
}
mapped_file = pfirmware->firmware_buf[init_step];
file_length = pfirmware->firmware_buf_size[init_step];
+
} else if (rst_opt == OPT_FIRMWARE_RESET) {
/* we only need to download data.img here */
mapped_file = pfirmware->firmware_buf[init_step];
@@ -346,7 +362,10 @@ bool init_firmware(struct net_device *dev)
download_firmware_fail:
RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__);
- rt_status = FALSE;
+ rt_status = false;
return rt_status;
-
}
+
+MODULE_FIRMWARE("RTL8192E/boot.img");
+MODULE_FIRMWARE("RTL8192E/main.img");
+MODULE_FIRMWARE("RTL8192E/data.img");
diff --git a/drivers/staging/rtl8192e/r819xE_phy.c b/drivers/staging/rtl8192e/r819xE_phy.c
index c44059aeacb6..7bd4fae0667e 100644
--- a/drivers/staging/rtl8192e/r819xE_phy.c
+++ b/drivers/staging/rtl8192e/r819xE_phy.c
@@ -5,7 +5,7 @@
#include "r819xE_phy.h"
#include "r8192E_dm.h"
#ifdef ENABLE_DOT11D
-#include "dot11d.h"
+#include "ieee80211/dot11d.h"
#endif
static u32 RF_CHANNEL_TABLE_ZEBRA[] = {
0,
diff --git a/drivers/staging/rtl8192e/r819xE_phy.h b/drivers/staging/rtl8192e/r819xE_phy.h
index fa77abe88827..41e0d777eabd 100644
--- a/drivers/staging/rtl8192e/r819xE_phy.h
+++ b/drivers/staging/rtl8192e/r819xE_phy.h
@@ -1,43 +1,46 @@
#ifndef _R819XU_PHY_H
#define _R819XU_PHY_H
-/* Channel switch:The size of command tables for switch channel*/
+
+/* Channel switch: the size of command tables for switch channel */
#define MAX_PRECMD_CNT 16
#define MAX_RFDEPENDCMD_CNT 16
#define MAX_POSTCMD_CNT 16
#ifdef RTL8190P
#define MACPHY_Array_PGLength 21
-#define Rtl819XMACPHY_Array_PG Rtl8190PciMACPHY_Array_PG
-#define Rtl819XMACPHY_Array Rtl8190PciMACPHY_Array
+#define Rtl819XMACPHY_Array_PG Rtl8190PciMACPHY_Array_PG
+#define Rtl819XMACPHY_Array Rtl8190PciMACPHY_Array
#define RadioC_ArrayLength 246
#define RadioD_ArrayLength 78
-#define Rtl819XRadioA_Array Rtl8190PciRadioA_Array
-#define Rtl819XRadioB_Array Rtl8190PciRadioB_Array
-#define Rtl819XRadioC_Array Rtl8190PciRadioC_Array
-#define Rtl819XRadioD_Array Rtl8190PciRadioD_Array
-#define Rtl819XAGCTAB_Array Rtl8190PciAGCTAB_Array
-#define PHY_REGArrayLength 280
-#define Rtl819XPHY_REGArray Rtl8190PciPHY_REGArray
-#define PHY_REG_1T2RArrayLength 280
-#define Rtl819XPHY_REG_1T2RArray Rtl8190PciPHY_REG_1T2RArray
+#define Rtl819XRadioA_Array Rtl8190PciRadioA_Array
+#define Rtl819XRadioB_Array Rtl8190PciRadioB_Array
+#define Rtl819XRadioC_Array Rtl8190PciRadioC_Array
+#define Rtl819XRadioD_Array Rtl8190PciRadioD_Array
+#define Rtl819XAGCTAB_Array Rtl8190PciAGCTAB_Array
+#define PHY_REGArrayLength 280
+#define Rtl819XPHY_REGArray Rtl8190PciPHY_REGArray
+#define PHY_REG_1T2RArrayLength 280
+#define Rtl819XPHY_REG_1T2RArray Rtl8190PciPHY_REG_1T2RArray
+#endif
+
+
+#ifdef RTL8192E
+#define MACPHY_Array_PGLength 30
+#define Rtl819XMACPHY_Array_PG Rtl8192PciEMACPHY_Array_PG
+#define Rtl819XMACPHY_Array Rtl8192PciEMACPHY_Array
+#define RadioC_ArrayLength 1
+#define RadioD_ArrayLength 1
+#define Rtl819XRadioA_Array Rtl8192PciERadioA_Array
+#define Rtl819XRadioB_Array Rtl8192PciERadioB_Array
+#define Rtl819XRadioC_Array Rtl8192PciERadioC_Array
+#define Rtl819XRadioD_Array Rtl8192PciERadioD_Array
+#define Rtl819XAGCTAB_Array Rtl8192PciEAGCTAB_Array
+#define PHY_REGArrayLength 1
+#define Rtl819XPHY_REGArray Rtl8192PciEPHY_REGArray
+#define PHY_REG_1T2RArrayLength 296
+#define Rtl819XPHY_REG_1T2RArray Rtl8192PciEPHY_REG_1T2RArray
#endif
- #ifdef RTL8192E
- #define MACPHY_Array_PGLength 30
- #define Rtl819XMACPHY_Array_PG Rtl8192PciEMACPHY_Array_PG
- #define Rtl819XMACPHY_Array Rtl8192PciEMACPHY_Array
- #define RadioC_ArrayLength 1
- #define RadioD_ArrayLength 1
- #define Rtl819XRadioA_Array Rtl8192PciERadioA_Array
- #define Rtl819XRadioB_Array Rtl8192PciERadioB_Array
- #define Rtl819XRadioC_Array Rtl8192PciERadioC_Array
- #define Rtl819XRadioD_Array Rtl8192PciERadioD_Array
- #define Rtl819XAGCTAB_Array Rtl8192PciEAGCTAB_Array
- #define PHY_REGArrayLength 1
- #define Rtl819XPHY_REGArray Rtl8192PciEPHY_REGArray
- #define PHY_REG_1T2RArrayLength 296
- #define Rtl819XPHY_REG_1T2RArray Rtl8192PciEPHY_REG_1T2RArray
- #endif
#define AGCTAB_ArrayLength 384
#define MACPHY_ArrayLength 18
@@ -45,7 +48,7 @@
#define RadioB_ArrayLength 78
-typedef enum _SwChnlCmdID{
+typedef enum _SwChnlCmdID {
CmdID_End,
CmdID_SetTxPowerLevel,
CmdID_BBRegWrite10,
@@ -53,16 +56,15 @@ typedef enum _SwChnlCmdID{
CmdID_WritePortUshort,
CmdID_WritePortUchar,
CmdID_RF_WriteReg,
-}SwChnlCmdID;
+} SwChnlCmdID;
-/*--------------------------------Define structure--------------------------------*/
-/* 1. Switch channel related */
-typedef struct _SwChnlCmd{
- SwChnlCmdID CmdID;
- u32 Para1;
- u32 Para2;
- u32 msDelay;
-}__attribute__ ((packed)) SwChnlCmd;
+/* switch channel data structure */
+typedef struct _SwChnlCmd {
+ SwChnlCmdID CmdID;
+ u32 Para1;
+ u32 Para2;
+ u32 msDelay;
+} __attribute__ ((packed)) SwChnlCmd;
extern u32 rtl819XMACPHY_Array_PG[];
extern u32 rtl819XPHY_REG_1T2RArray[];
@@ -72,54 +74,90 @@ extern u32 rtl819XRadioB_Array[];
extern u32 rtl819XRadioC_Array[];
extern u32 rtl819XRadioD_Array[];
-typedef enum _HW90_BLOCK{
+typedef enum _HW90_BLOCK {
HW90_BLOCK_MAC = 0,
HW90_BLOCK_PHY0 = 1,
HW90_BLOCK_PHY1 = 2,
HW90_BLOCK_RF = 3,
- HW90_BLOCK_MAXIMUM = 4, // Never use this
-}HW90_BLOCK_E, *PHW90_BLOCK_E;
-
-typedef enum _RF90_RADIO_PATH{
- RF90_PATH_A = 0, //Radio Path A
- RF90_PATH_B = 1, //Radio Path B
- RF90_PATH_C = 2, //Radio Path C
- RF90_PATH_D = 3, //Radio Path D
- RF90_PATH_MAX //Max RF number 92 support
-}RF90_RADIO_PATH_E, *PRF90_RADIO_PATH_E;
-
-#define bMaskByte0 0xff
-#define bMaskByte1 0xff00
-#define bMaskByte2 0xff0000
-#define bMaskByte3 0xff000000
-#define bMaskHWord 0xffff0000
-#define bMaskLWord 0x0000ffff
-#define bMaskDWord 0xffffffff
-
-//extern u32 rtl8192_CalculateBitShift(u32 dwBitMask);
-extern u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device* dev, u32 eRFPath);
-extern void rtl8192_setBBreg(struct net_device* dev, u32 dwRegAddr, u32 dwBitMask, u32 dwData);
-extern u32 rtl8192_QueryBBReg(struct net_device* dev, u32 dwRegAddr, u32 dwBitMask);
-//extern u32 rtl8192_phy_RFSerialRead(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset);
-//extern void rtl8192_phy_RFSerialWrite(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset, u32 Data);
-extern void rtl8192_phy_SetRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask, u32 Data);
-extern u32 rtl8192_phy_QueryRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask);
-extern void rtl8192_phy_configmac(struct net_device* dev);
-extern void rtl8192_phyConfigBB(struct net_device* dev, u8 ConfigType);
-//extern void rtl8192_InitBBRFRegDef(struct net_device* dev);
-extern RT_STATUS rtl8192_phy_checkBBAndRF(struct net_device* dev, HW90_BLOCK_E CheckBlock, RF90_RADIO_PATH_E eRFPath);
-//extern RT_STATUS rtl8192_BB_Config_ParaFile(struct net_device* dev);
-extern RT_STATUS rtl8192_BBConfig(struct net_device* dev);
-extern void rtl8192_phy_getTxPower(struct net_device* dev);
-extern void rtl8192_phy_setTxPower(struct net_device* dev, u8 channel);
+ /* Don't ever use this. */
+ HW90_BLOCK_MAXIMUM = 4,
+} HW90_BLOCK_E, *PHW90_BLOCK_E;
+
+typedef enum _RF90_RADIO_PATH {
+ /* Radio paths */
+ RF90_PATH_A = 0,
+ RF90_PATH_B = 1,
+ RF90_PATH_C = 2,
+ RF90_PATH_D = 3,
+
+ /* Max RF number 92 support */
+ RF90_PATH_MAX
+} RF90_RADIO_PATH_E, *PRF90_RADIO_PATH_E;
+
+#define bMaskByte0 0xff
+#define bMaskByte1 0xff00
+#define bMaskByte2 0xff0000
+#define bMaskByte3 0xff000000
+#define bMaskHWord 0xffff0000
+#define bMaskLWord 0x0000ffff
+#define bMaskDWord 0xffffffff
+
+/*extern u32 rtl8192_CalculateBitShift(u32 dwBitMask);
+
+extern u32 rtl8192_phy_RFSerialRead(struct net_device *dev,
+ RF90_RADIO_PATH_E eRFPath, u32 Offset);
+
+extern void rtl8192_phy_RFSerialWrite(struct net_device *dev,
+ RF90_RADIO_PATH_E eRFPath, u32 Offset, u32 Data);
+
+extern void rtl8192_InitBBRFRegDef(struct net_device *dev);
+
+extern RT_STATUS rtl8192_BB_Config_ParaFile(struct net_device *dev); */
+
+extern u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device *dev, u32 eRFPath);
+
+extern void rtl8192_setBBreg(struct net_device *dev, u32 dwRegAddr,
+ u32 dwBitMask, u32 dwData);
+
+extern u32 rtl8192_QueryBBReg(struct net_device *dev, u32 dwRegAddr,
+ u32 dwBitMask);
+
+extern void rtl8192_phy_SetRFReg(struct net_device *dev,
+ RF90_RADIO_PATH_E eRFPath, u32 RegAddr,
+ u32 BitMask, u32 Data);
+
+extern u32 rtl8192_phy_QueryRFReg(struct net_device *dev,
+ RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask);
+
+extern void rtl8192_phy_configmac(struct net_device *dev);
+
+extern void rtl8192_phyConfigBB(struct net_device *dev, u8 ConfigType);
+
+extern RT_STATUS rtl8192_phy_checkBBAndRF(struct net_device *dev,
+ HW90_BLOCK_E CheckBlock, RF90_RADIO_PATH_E eRFPath);
+
+extern RT_STATUS rtl8192_BBConfig(struct net_device *dev);
+
+extern void rtl8192_phy_getTxPower(struct net_device *dev);
+
+extern void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel);
+
extern RT_STATUS rtl8192_phy_RFConfig(struct net_device* dev);
+
extern void rtl8192_phy_updateInitGain(struct net_device* dev);
-extern u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev, RF90_RADIO_PATH_E eRFPath);
-extern u8 rtl8192_phy_SwChnl(struct net_device* dev, u8 channel);
-extern void rtl8192_SetBWMode(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset);
+extern u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device *dev,
+ RF90_RADIO_PATH_E eRFPath);
+
+extern u8 rtl8192_phy_SwChnl(struct net_device *dev, u8 channel);
+
+extern void rtl8192_SetBWMode(struct net_device *dev,
+ HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset);
+
extern void rtl8192_SwChnl_WorkItem(struct net_device *dev);
+
extern void rtl8192_SetBWModeWorkItem(struct net_device *dev);
+
extern void InitialGain819xPci(struct net_device *dev, u8 Operation);
-#endif
+#endif /* _R819XU_PHY_H */
diff --git a/drivers/staging/rtl8192e/r819xE_phyreg.h b/drivers/staging/rtl8192e/r819xE_phyreg.h
index 37f0feefaf2c..d5de279f6644 100644
--- a/drivers/staging/rtl8192e/r819xE_phyreg.h
+++ b/drivers/staging/rtl8192e/r819xE_phyreg.h
@@ -38,6 +38,8 @@
#define MCS_TXAGC 0x340 // MCS AGC
#define CCK_TXAGC 0x348 // CCK AGC
+#define MacBlkCtrl 0x403 // Mac block on/off control register
+
//page8
#define rFPGA0_RFMOD 0x800 //RF mode & CCK TxSC
#define rFPGA0_TxInfo 0x804
@@ -79,55 +81,70 @@
#define rFPGA0_XB_LSSIReadBack 0x8a4
#define rFPGA0_XC_LSSIReadBack 0x8a8
#define rFPGA0_XD_LSSIReadBack 0x8ac
-#define rFPGA0_PSDReport 0x8b4
+#define rFPGA0_PSDReport 0x8b4
#define rFPGA0_XAB_RFInterfaceRB 0x8e0
#define rFPGA0_XCD_RFInterfaceRB 0x8e4
-//page 9
-#define rFPGA1_RFMOD 0x900 //RF mode & OFDM TxSC
-#define rFPGA1_TxBlock 0x904
-#define rFPGA1_DebugSelect 0x908
-#define rFPGA1_TxInfo 0x90c
-
-//page a
-#define rCCK0_System 0xa00
-#define rCCK0_AFESetting 0xa04
-#define rCCK0_CCA 0xa08
-#define rCCK0_RxAGC1 0xa0c //AGC default value, saturation level
-#define rCCK0_RxAGC2 0xa10 //AGC & DAGC
-#define rCCK0_RxHP 0xa14
-#define rCCK0_DSPParameter1 0xa18 //Timing recovery & Channel estimation threshold
-#define rCCK0_DSPParameter2 0xa1c //SQ threshold
-#define rCCK0_TxFilter1 0xa20
-#define rCCK0_TxFilter2 0xa24
-#define rCCK0_DebugPort 0xa28 //debug port and Tx filter3
-#define rCCK0_FalseAlarmReport 0xa2c //0xa2d
-#define rCCK0_TRSSIReport 0xa50
-#define rCCK0_RxReport 0xa54 //0xa57
-#define rCCK0_FACounterLower 0xa5c //0xa5b
-#define rCCK0_FACounterUpper 0xa58 //0xa5c
-
-//page c
-#define rOFDM0_LSTF 0xc00
+/* Page 9 - RF mode & OFDM TxSC */
+#define rFPGA1_RFMOD 0x900
+#define rFPGA1_TxBlock 0x904
+#define rFPGA1_DebugSelect 0x908
+#define rFPGA1_TxInfo 0x90c
+
+/* Page a */
+#define rCCK0_System 0xa00
+#define rCCK0_AFESetting 0xa04
+#define rCCK0_CCA 0xa08
+/* AGC default value, saturation level */
+#define rCCK0_RxAGC1 0xa0c
+/* AGC & DAGC */
+#define rCCK0_RxAGC2 0xa10
+#define rCCK0_RxHP 0xa14
+/* Timing recovery & channel estimation threshold */
+#define rCCK0_DSPParameter1 0xa18
+/* SQ threshold */
+#define rCCK0_DSPParameter2 0xa1c
+#define rCCK0_TxFilter1 0xa20
+#define rCCK0_TxFilter2 0xa24
+/* Debug port and TX filter 3 */
+#define rCCK0_DebugPort 0xa28
+#define rCCK0_FalseAlarmReport 0xa2c
+#define rCCK0_TRSSIReport 0xa50
+#define rCCK0_RxReport 0xa54
+#define rCCK0_FACounterLower 0xa5c
+#define rCCK0_FACounterUpper 0xa58
+
+/* Page c */
+#define rOFDM0_LSTF 0xc00
#define rOFDM0_TRxPathEnable 0xc04
-#define rOFDM0_TRMuxPar 0xc08
-#define rOFDM0_TRSWIsolation 0xc0c
-#define rOFDM0_XARxAFE 0xc10 //RxIQ DC offset, Rx digital filter, DC notch filter
-#define rOFDM0_XARxIQImbalance 0xc14 //RxIQ imblance matrix
-#define rOFDM0_XBRxAFE 0xc18
+#define rOFDM0_TRMuxPar 0xc08
+#define rOFDM0_TRSWIsolation 0xc0c
+/* RxIQ DC offset, Rx digital filter, DC notch filter */
+#define rOFDM0_XARxAFE 0xc10
+/* RxIQ imblance matrix */
+#define rOFDM0_XARxIQImbalance 0xc14
+#define rOFDM0_XBRxAFE 0xc18
#define rOFDM0_XBRxIQImbalance 0xc1c
-#define rOFDM0_XCRxAFE 0xc20
+#define rOFDM0_XCRxAFE 0xc20
#define rOFDM0_XCRxIQImbalance 0xc24
-#define rOFDM0_XDRxAFE 0xc28
+#define rOFDM0_XDRxAFE 0xc28
#define rOFDM0_XDRxIQImbalance 0xc2c
-#define rOFDM0_RxDetector1 0xc30 //PD,BW & SBD
-#define rOFDM0_RxDetector2 0xc34 //SBD & Fame Sync.
-#define rOFDM0_RxDetector3 0xc38 //Frame Sync.
-#define rOFDM0_RxDetector4 0xc3c //PD, SBD, Frame Sync & Short-GI
-#define rOFDM0_RxDSP 0xc40 //Rx Sync Path
-#define rOFDM0_CFOandDAGC 0xc44 //CFO & DAGC
-#define rOFDM0_CCADropThreshold 0xc48 //CCA Drop threshold
-#define rOFDM0_ECCAThreshold 0xc4c // energy CCA
+/* PD, BW & SBD */
+#define rOFDM0_RxDetector1 0xc30
+/* SBD */
+#define rOFDM0_RxDetector2 0xc34
+/* Frame Sync */
+#define rOFDM0_RxDetector3 0xc38
+/* PD, SBD, Frame Sync & Short-GI */
+#define rOFDM0_RxDetector4 0xc3c
+/* Rx Sync Path */
+#define rOFDM0_RxDSP 0xc40
+/* CFO & DAGC */
+#define rOFDM0_CFOandDAGC 0xc44
+/* CCA Drop threshold */
+#define rOFDM0_CCADropThreshold 0xc48
+/* Energy CCA */
+#define rOFDM0_ECCAThreshold 0xc4c
#define rOFDM0_XAAGCCore1 0xc50
#define rOFDM0_XAAGCCore2 0xc54
#define rOFDM0_XBAGCCore1 0xc58
@@ -139,501 +156,517 @@
#define rOFDM0_AGCParameter1 0xc70
#define rOFDM0_AGCParameter2 0xc74
#define rOFDM0_AGCRSSITable 0xc78
-#define rOFDM0_HTSTFAGC 0xc7c
+#define rOFDM0_HTSTFAGC 0xc7c
#define rOFDM0_XATxIQImbalance 0xc80
-#define rOFDM0_XATxAFE 0xc84
+#define rOFDM0_XATxAFE 0xc84
#define rOFDM0_XBTxIQImbalance 0xc88
-#define rOFDM0_XBTxAFE 0xc8c
+#define rOFDM0_XBTxAFE 0xc8c
#define rOFDM0_XCTxIQImbalance 0xc90
-#define rOFDM0_XCTxAFE 0xc94
+#define rOFDM0_XCTxAFE 0xc94
#define rOFDM0_XDTxIQImbalance 0xc98
-#define rOFDM0_XDTxAFE 0xc9c
+#define rOFDM0_XDTxAFE 0xc9c
#define rOFDM0_RxHPParameter 0xce0
#define rOFDM0_TxPseudoNoiseWgt 0xce4
-#define rOFDM0_FrameSync 0xcf0
-#define rOFDM0_DFSReport 0xcf4
-#define rOFDM0_TxCoeff1 0xca4
-#define rOFDM0_TxCoeff2 0xca8
-#define rOFDM0_TxCoeff3 0xcac
-#define rOFDM0_TxCoeff4 0xcb0
-#define rOFDM0_TxCoeff5 0xcb4
-#define rOFDM0_TxCoeff6 0xcb8
-
-
-//page d
-#define rOFDM1_LSTF 0xd00
+#define rOFDM0_FrameSync 0xcf0
+#define rOFDM0_DFSReport 0xcf4
+#define rOFDM0_TxCoeff1 0xca4
+#define rOFDM0_TxCoeff2 0xca8
+#define rOFDM0_TxCoeff3 0xcac
+#define rOFDM0_TxCoeff4 0xcb0
+#define rOFDM0_TxCoeff5 0xcb4
+#define rOFDM0_TxCoeff6 0xcb8
+
+
+/* Page d */
+#define rOFDM1_LSTF 0xd00
#define rOFDM1_TRxPathEnable 0xd04
-#define rOFDM1_CFO 0xd08
-#define rOFDM1_CSI1 0xd10
-#define rOFDM1_SBD 0xd14
-#define rOFDM1_CSI2 0xd18
-#define rOFDM1_CFOTracking 0xd2c
+#define rOFDM1_CFO 0xd08
+#define rOFDM1_CSI1 0xd10
+#define rOFDM1_SBD 0xd14
+#define rOFDM1_CSI2 0xd18
+#define rOFDM1_CFOTracking 0xd2c
#define rOFDM1_TRxMesaure1 0xd34
-#define rOFDM1_IntfDet 0xd3c
-#define rOFDM1_PseudoNoiseStateAB 0xd50
-#define rOFDM1_PseudoNoiseStateCD 0xd54
-#define rOFDM1_RxPseudoNoiseWgt 0xd58
-#define rOFDM_PHYCounter1 0xda0 //cca, parity fail
-#define rOFDM_PHYCounter2 0xda4 //rate illegal, crc8 fail
-#define rOFDM_PHYCounter3 0xda8 //MCS not support
-#define rOFDM_ShortCFOAB 0xdac
-#define rOFDM_ShortCFOCD 0xdb0
-#define rOFDM_LongCFOAB 0xdb4
-#define rOFDM_LongCFOCD 0xdb8
-#define rOFDM_TailCFOAB 0xdbc
-#define rOFDM_TailCFOCD 0xdc0
+#define rOFDM1_IntfDet 0xd3c
+#define rOFDM1_PseudoNoiseStateAB 0xd50
+#define rOFDM1_PseudoNoiseStateCD 0xd54
+#define rOFDM1_RxPseudoNoiseWgt 0xd58
+/* cca, parity fail */
+#define rOFDM_PHYCounter1 0xda0
+/* rate illegal, crc8 fail */
+#define rOFDM_PHYCounter2 0xda4
+/* MCS not supported */
+#define rOFDM_PHYCounter3 0xda8
+#define rOFDM_ShortCFOAB 0xdac
+#define rOFDM_ShortCFOCD 0xdb0
+#define rOFDM_LongCFOAB 0xdb4
+#define rOFDM_LongCFOCD 0xdb8
+#define rOFDM_TailCFOAB 0xdbc
+#define rOFDM_TailCFOCD 0xdc0
#define rOFDM_PWMeasure1 0xdc4
#define rOFDM_PWMeasure2 0xdc8
-#define rOFDM_BWReport 0xdcc
-#define rOFDM_AGCReport 0xdd0
-#define rOFDM_RxSNR 0xdd4
-#define rOFDM_RxEVMCSI 0xdd8
-#define rOFDM_SIGReport 0xddc
-
-//page e
-#define rTxAGC_Rate18_06 0xe00
-#define rTxAGC_Rate54_24 0xe04
-#define rTxAGC_CCK_Mcs32 0xe08
-#define rTxAGC_Mcs03_Mcs00 0xe10
-#define rTxAGC_Mcs07_Mcs04 0xe14
-#define rTxAGC_Mcs11_Mcs08 0xe18
-#define rTxAGC_Mcs15_Mcs12 0xe1c
-
-
-//RF
-//Zebra1
+#define rOFDM_BWReport 0xdcc
+#define rOFDM_AGCReport 0xdd0
+#define rOFDM_RxSNR 0xdd4
+#define rOFDM_RxEVMCSI 0xdd8
+#define rOFDM_SIGReport 0xddc
+
+/* Page e */
+#define rTxAGC_Rate18_06 0xe00
+#define rTxAGC_Rate54_24 0xe04
+#define rTxAGC_CCK_Mcs32 0xe08
+#define rTxAGC_Mcs03_Mcs00 0xe10
+#define rTxAGC_Mcs07_Mcs04 0xe14
+#define rTxAGC_Mcs11_Mcs08 0xe18
+#define rTxAGC_Mcs15_Mcs12 0xe1c
+
+
+/* RF Zebra 1 */
#define rZebra1_HSSIEnable 0x0
#define rZebra1_TRxEnable1 0x1
#define rZebra1_TRxEnable2 0x2
-#define rZebra1_AGC 0x4
+#define rZebra1_AGC 0x4
#define rZebra1_ChargePump 0x5
-#define rZebra1_Channel 0x7
-#define rZebra1_TxGain 0x8
-#define rZebra1_TxLPF 0x9
-#define rZebra1_RxLPF 0xb
+#define rZebra1_Channel 0x7
+#define rZebra1_TxGain 0x8
+#define rZebra1_TxLPF 0x9
+#define rZebra1_RxLPF 0xb
#define rZebra1_RxHPFCorner 0xc
-//Zebra4
-#define rGlobalCtrl 0
-#define rRTL8256_TxLPF 19
-#define rRTL8256_RxLPF 11
+/* Zebra 4 */
+#define rGlobalCtrl 0
+#define rRTL8256_TxLPF 19
+#define rRTL8256_RxLPF 11
-//RTL8258
-#define rRTL8258_TxLPF 0x11
-#define rRTL8258_RxLPF 0x13
+/* RTL8258 */
+#define rRTL8258_TxLPF 0x11
+#define rRTL8258_RxLPF 0x13
#define rRTL8258_RSSILPF 0xa
-//Bit Mask
-//page-1
-#define bBBResetB 0x100
-#define bGlobalResetB 0x200
-#define bOFDMTxStart 0x4
-#define bCCKTxStart 0x8
-#define bCRC32Debug 0x100
-#define bPMACLoopback 0x10
-#define bTxLSIG 0xffffff
-#define bOFDMTxRate 0xf
-#define bOFDMTxReserved 0x10
-#define bOFDMTxLength 0x1ffe0
-#define bOFDMTxParity 0x20000
-#define bTxHTSIG1 0xffffff
-#define bTxHTMCSRate 0x7f
-#define bTxHTBW 0x80
-#define bTxHTLength 0xffff00
-#define bTxHTSIG2 0xffffff
-#define bTxHTSmoothing 0x1
-#define bTxHTSounding 0x2
-#define bTxHTReserved 0x4
-#define bTxHTAggreation 0x8
-#define bTxHTSTBC 0x30
-#define bTxHTAdvanceCoding 0x40
-#define bTxHTShortGI 0x80
-#define bTxHTNumberHT_LTF 0x300
-#define bTxHTCRC8 0x3fc00
-#define bCounterReset 0x10000
-#define bNumOfOFDMTx 0xffff
-#define bNumOfCCKTx 0xffff0000
-#define bTxIdleInterval 0xffff
-#define bOFDMService 0xffff0000
-#define bTxMACHeader 0xffffffff
-#define bTxDataInit 0xff
-#define bTxHTMode 0x100
-#define bTxDataType 0x30000
-#define bTxRandomSeed 0xffffffff
-#define bCCKTxPreamble 0x1
-#define bCCKTxSFD 0xffff0000
-#define bCCKTxSIG 0xff
-#define bCCKTxService 0xff00
-#define bCCKLengthExt 0x8000
-#define bCCKTxLength 0xffff0000
-#define bCCKTxCRC16 0xffff
-#define bCCKTxStatus 0x1
-#define bOFDMTxStatus 0x2
-
-//page-8
-#define bRFMOD 0x1
-#define bJapanMode 0x2
-#define bCCKTxSC 0x30
-#define bCCKEn 0x1000000
-#define bOFDMEn 0x2000000
-#define bOFDMRxADCPhase 0x10000
-#define bOFDMTxDACPhase 0x40000
-#define bXATxAGC 0x3f
-#define bXBTxAGC 0xf00
-#define bXCTxAGC 0xf000
-#define bXDTxAGC 0xf0000
-#define bPAStart 0xf0000000
-#define bTRStart 0x00f00000
-#define bRFStart 0x0000f000
-#define bBBStart 0x000000f0
-#define bBBCCKStart 0x0000000f
-#define bPAEnd 0xf //Reg0x814
-#define bTREnd 0x0f000000
-#define bRFEnd 0x000f0000
-#define bCCAMask 0x000000f0 //T2R
-#define bR2RCCAMask 0x00000f00
-#define bHSSI_R2TDelay 0xf8000000
-#define bHSSI_T2RDelay 0xf80000
-#define bContTxHSSI 0x400 //channel gain at continue Tx
-#define bIGFromCCK 0x200
-#define bAGCAddress 0x3f
-#define bRxHPTx 0x7000
-#define bRxHPT2R 0x38000
-#define bRxHPCCKIni 0xc0000
-#define bAGCTxCode 0xc00000
-#define bAGCRxCode 0x300000
-#define b3WireDataLength 0x800
-#define b3WireAddressLength 0x400
-#define b3WireRFPowerDown 0x1
-//#define bHWSISelect 0x8
-#define b5GPAPEPolarity 0x40000000
-#define b2GPAPEPolarity 0x80000000
-#define bRFSW_TxDefaultAnt 0x3
-#define bRFSW_TxOptionAnt 0x30
-#define bRFSW_RxDefaultAnt 0x300
-#define bRFSW_RxOptionAnt 0x3000
-#define bRFSI_3WireData 0x1
-#define bRFSI_3WireClock 0x2
-#define bRFSI_3WireLoad 0x4
-#define bRFSI_3WireRW 0x8
-#define bRFSI_3Wire 0xf //3-wire total control
-#define bRFSI_RFENV 0x10
-#define bRFSI_TRSW 0x20
-#define bRFSI_TRSWB 0x40
-#define bRFSI_ANTSW 0x100
-#define bRFSI_ANTSWB 0x200
-#define bRFSI_PAPE 0x400
-#define bRFSI_PAPE5G 0x800
-#define bBandSelect 0x1
-#define bHTSIG2_GI 0x80
-#define bHTSIG2_Smoothing 0x01
-#define bHTSIG2_Sounding 0x02
-#define bHTSIG2_Aggreaton 0x08
-#define bHTSIG2_STBC 0x30
-#define bHTSIG2_AdvCoding 0x40
+/* Bit Mask */
+/* Page 1 */
+#define bBBResetB 0x100
+#define bGlobalResetB 0x200
+#define bOFDMTxStart 0x4
+#define bCCKTxStart 0x8
+#define bCRC32Debug 0x100
+#define bPMACLoopback 0x10
+#define bTxLSIG 0xffffff
+#define bOFDMTxRate 0xf
+#define bOFDMTxReserved 0x10
+#define bOFDMTxLength 0x1ffe0
+#define bOFDMTxParity 0x20000
+#define bTxHTSIG1 0xffffff
+#define bTxHTMCSRate 0x7f
+#define bTxHTBW 0x80
+#define bTxHTLength 0xffff00
+#define bTxHTSIG2 0xffffff
+#define bTxHTSmoothing 0x1
+#define bTxHTSounding 0x2
+#define bTxHTReserved 0x4
+#define bTxHTAggreation 0x8
+#define bTxHTSTBC 0x30
+#define bTxHTAdvanceCoding 0x40
+#define bTxHTShortGI 0x80
+#define bTxHTNumberHT_LTF 0x300
+#define bTxHTCRC8 0x3fc00
+#define bCounterReset 0x10000
+#define bNumOfOFDMTx 0xffff
+#define bNumOfCCKTx 0xffff0000
+#define bTxIdleInterval 0xffff
+#define bOFDMService 0xffff0000
+#define bTxMACHeader 0xffffffff
+#define bTxDataInit 0xff
+#define bTxHTMode 0x100
+#define bTxDataType 0x30000
+#define bTxRandomSeed 0xffffffff
+#define bCCKTxPreamble 0x1
+#define bCCKTxSFD 0xffff0000
+#define bCCKTxSIG 0xff
+#define bCCKTxService 0xff00
+#define bCCKLengthExt 0x8000
+#define bCCKTxLength 0xffff0000
+#define bCCKTxCRC16 0xffff
+#define bCCKTxStatus 0x1
+#define bOFDMTxStatus 0x2
+
+/* Page 8 */
+#define bRFMOD 0x1
+#define bJapanMode 0x2
+#define bCCKTxSC 0x30
+#define bCCKEn 0x1000000
+#define bOFDMEn 0x2000000
+#define bOFDMRxADCPhase 0x10000
+#define bOFDMTxDACPhase 0x40000
+#define bXATxAGC 0x3f
+#define bXBTxAGC 0xf00
+#define bXCTxAGC 0xf000
+#define bXDTxAGC 0xf0000
+#define bPAStart 0xf0000000
+#define bTRStart 0x00f00000
+#define bRFStart 0x0000f000
+#define bBBStart 0x000000f0
+#define bBBCCKStart 0x0000000f
+/* Reg)x814 */
+#define bPAEnd 0xf
+#define bTREnd 0x0f000000
+#define bRFEnd 0x000f0000
+/* T2R */
+#define bCCAMask 0x000000f0
+#define bR2RCCAMask 0x00000f00
+#define bHSSI_R2TDelay 0xf8000000
+#define bHSSI_T2RDelay 0xf80000
+/* Channel gain at continue TX. */
+#define bContTxHSSI 0x400
+#define bIGFromCCK 0x200
+#define bAGCAddress 0x3f
+#define bRxHPTx 0x7000
+#define bRxHPT2R 0x38000
+#define bRxHPCCKIni 0xc0000
+#define bAGCTxCode 0xc00000
+#define bAGCRxCode 0x300000
+#define b3WireDataLength 0x800
+#define b3WireAddressLength 0x400
+#define b3WireRFPowerDown 0x1
+/*#define bHWSISelect 0x8 */
+#define b5GPAPEPolarity 0x40000000
+#define b2GPAPEPolarity 0x80000000
+#define bRFSW_TxDefaultAnt 0x3
+#define bRFSW_TxOptionAnt 0x30
+#define bRFSW_RxDefaultAnt 0x300
+#define bRFSW_RxOptionAnt 0x3000
+#define bRFSI_3WireData 0x1
+#define bRFSI_3WireClock 0x2
+#define bRFSI_3WireLoad 0x4
+#define bRFSI_3WireRW 0x8
+/* 3-wire total control */
+#define bRFSI_3Wire 0xf
+#define bRFSI_RFENV 0x10
+#define bRFSI_TRSW 0x20
+#define bRFSI_TRSWB 0x40
+#define bRFSI_ANTSW 0x100
+#define bRFSI_ANTSWB 0x200
+#define bRFSI_PAPE 0x400
+#define bRFSI_PAPE5G 0x800
+#define bBandSelect 0x1
+#define bHTSIG2_GI 0x80
+#define bHTSIG2_Smoothing 0x01
+#define bHTSIG2_Sounding 0x02
+#define bHTSIG2_Aggreaton 0x08
+#define bHTSIG2_STBC 0x30
+#define bHTSIG2_AdvCoding 0x40
#define bHTSIG2_NumOfHTLTF 0x300
-#define bHTSIG2_CRC8 0x3fc
-#define bHTSIG1_MCS 0x7f
-#define bHTSIG1_BandWidth 0x80
-#define bHTSIG1_HTLength 0xffff
-#define bLSIG_Rate 0xf
-#define bLSIG_Reserved 0x10
-#define bLSIG_Length 0x1fffe
-#define bLSIG_Parity 0x20
-#define bCCKRxPhase 0x4
-#define bLSSIReadAddress 0x3f000000 //LSSI "Read" Address
-#define bLSSIReadEdge 0x80000000 //LSSI "Read" edge signal
-#define bLSSIReadBackData 0xfff
-#define bLSSIReadOKFlag 0x1000
-#define bCCKSampleRate 0x8 //0: 44MHz, 1:88MHz
-
-#define bRegulator0Standby 0x1
-#define bRegulatorPLLStandby 0x2
-#define bRegulator1Standby 0x4
-#define bPLLPowerUp 0x8
-#define bDPLLPowerUp 0x10
-#define bDA10PowerUp 0x20
-#define bAD7PowerUp 0x200
-#define bDA6PowerUp 0x2000
-#define bXtalPowerUp 0x4000
-#define b40MDClkPowerUP 0x8000
-#define bDA6DebugMode 0x20000
-#define bDA6Swing 0x380000
-#define bADClkPhase 0x4000000
-#define b80MClkDelay 0x18000000
-#define bAFEWatchDogEnable 0x20000000
-#define bXtalCap 0x0f000000
-#define bXtalCap01 0xc0000000
-#define bXtalCap23 0x3
-#define bXtalCap92x 0x0f000000
-#define bIntDifClkEnable 0x400
-#define bExtSigClkEnable 0x800
+#define bHTSIG2_CRC8 0x3fc
+#define bHTSIG1_MCS 0x7f
+#define bHTSIG1_BandWidth 0x80
+#define bHTSIG1_HTLength 0xffff
+#define bLSIG_Rate 0xf
+#define bLSIG_Reserved 0x10
+#define bLSIG_Length 0x1fffe
+#define bLSIG_Parity 0x20
+#define bCCKRxPhase 0x4
+/* LSSI "read" address */
+#define bLSSIReadAddress 0x3f000000
+/* LSSI "read" edge signal */
+#define bLSSIReadEdge 0x80000000
+#define bLSSIReadBackData 0xfff
+#define bLSSIReadOKFlag 0x1000
+/* 0: 44 MHz, 1: 88MHz */
+#define bCCKSampleRate 0x8
+
+#define bRegulator0Standby 0x1
+#define bRegulatorPLLStandby 0x2
+#define bRegulator1Standby 0x4
+#define bPLLPowerUp 0x8
+#define bDPLLPowerUp 0x10
+#define bDA10PowerUp 0x20
+#define bAD7PowerUp 0x200
+#define bDA6PowerUp 0x2000
+#define bXtalPowerUp 0x4000
+#define b40MDClkPowerUP 0x8000
+#define bDA6DebugMode 0x20000
+#define bDA6Swing 0x380000
+#define bADClkPhase 0x4000000
+#define b80MClkDelay 0x18000000
+#define bAFEWatchDogEnable 0x20000000
+#define bXtalCap 0x0f000000
+#define bXtalCap01 0xc0000000
+#define bXtalCap23 0x3
+#define bXtalCap92x 0x0f000000
+#define bIntDifClkEnable 0x400
+#define bExtSigClkEnable 0x800
#define bBandgapMbiasPowerUp 0x10000
-#define bAD11SHGain 0xc0000
-#define bAD11InputRange 0x700000
-#define bAD11OPCurrent 0x3800000
-#define bIPathLoopback 0x4000000
-#define bQPathLoopback 0x8000000
-#define bAFELoopback 0x10000000
-#define bDA10Swing 0x7e0
-#define bDA10Reverse 0x800
-#define bDAClkSource 0x1000
-#define bAD7InputRange 0x6000
-#define bAD7Gain 0x38000
-#define bAD7OutputCMMode 0x40000
-#define bAD7InputCMMode 0x380000
-#define bAD7Current 0xc00000
-#define bRegulatorAdjust 0x7000000
-#define bAD11PowerUpAtTx 0x1
-#define bDA10PSAtTx 0x10
-#define bAD11PowerUpAtRx 0x100
-#define bDA10PSAtRx 0x1000
-
-#define bCCKRxAGCFormat 0x200
-
-#define bPSDFFTSamplepPoint 0xc000
-#define bPSDAverageNum 0x3000
-#define bIQPathControl 0xc00
-#define bPSDFreq 0x3ff
-#define bPSDAntennaPath 0x30
-#define bPSDIQSwitch 0x40
-#define bPSDRxTrigger 0x400000
-#define bPSDTxTrigger 0x80000000
-#define bPSDSineToneScale 0x7f000000
-#define bPSDReport 0xffff
-
-//page-9
-#define bOFDMTxSC 0x30000000
-#define bCCKTxOn 0x1
-#define bOFDMTxOn 0x2
-#define bDebugPage 0xfff //reset debug page and also HWord, LWord
-#define bDebugItem 0xff //reset debug page and LWord
-#define bAntL 0x10
-#define bAntNonHT 0x100
-#define bAntHT1 0x1000
-#define bAntHT2 0x10000
-#define bAntHT1S1 0x100000
-#define bAntNonHTS1 0x1000000
-
-//page-a
-#define bCCKBBMode 0x3
-#define bCCKTxPowerSaving 0x80
-#define bCCKRxPowerSaving 0x40
-#define bCCKSideBand 0x10
-#define bCCKScramble 0x8
-#define bCCKAntDiversity 0x8000
+#define bAD11SHGain 0xc0000
+#define bAD11InputRange 0x700000
+#define bAD11OPCurrent 0x3800000
+#define bIPathLoopback 0x4000000
+#define bQPathLoopback 0x8000000
+#define bAFELoopback 0x10000000
+#define bDA10Swing 0x7e0
+#define bDA10Reverse 0x800
+#define bDAClkSource 0x1000
+#define bAD7InputRange 0x6000
+#define bAD7Gain 0x38000
+#define bAD7OutputCMMode 0x40000
+#define bAD7InputCMMode 0x380000
+#define bAD7Current 0xc00000
+#define bRegulatorAdjust 0x7000000
+#define bAD11PowerUpAtTx 0x1
+#define bDA10PSAtTx 0x10
+#define bAD11PowerUpAtRx 0x100
+#define bDA10PSAtRx 0x1000
+
+#define bCCKRxAGCFormat 0x200
+
+#define bPSDFFTSamplepPoint 0xc000
+#define bPSDAverageNum 0x3000
+#define bIQPathControl 0xc00
+#define bPSDFreq 0x3ff
+#define bPSDAntennaPath 0x30
+#define bPSDIQSwitch 0x40
+#define bPSDRxTrigger 0x400000
+#define bPSDTxTrigger 0x80000000
+#define bPSDSineToneScale 0x7f000000
+#define bPSDReport 0xffff
+
+/* Page 8 */
+#define bOFDMTxSC 0x30000000
+#define bCCKTxOn 0x1
+#define bOFDMTxOn 0x2
+/* Reset debug page and also HWord, LWord */
+#define bDebugPage 0xfff
+/* Reset debug page and LWord */
+#define bDebugItem 0xff
+#define bAntL 0x10
+#define bAntNonHT 0x100
+#define bAntHT1 0x1000
+#define bAntHT2 0x10000
+#define bAntHT1S1 0x100000
+#define bAntNonHTS1 0x1000000
+
+/* Page a */
+#define bCCKBBMode 0x3
+#define bCCKTxPowerSaving 0x80
+#define bCCKRxPowerSaving 0x40
+#define bCCKSideBand 0x10
+#define bCCKScramble 0x8
+#define bCCKAntDiversity 0x8000
#define bCCKCarrierRecovery 0x4000
-#define bCCKTxRate 0x3000
-#define bCCKDCCancel 0x0800
-#define bCCKISICancel 0x0400
-#define bCCKMatchFilter 0x0200
-#define bCCKEqualizer 0x0100
-#define bCCKPreambleDetect 0x800000
-#define bCCKFastFalseCCA 0x400000
-#define bCCKChEstStart 0x300000
-#define bCCKCCACount 0x080000
-#define bCCKcs_lim 0x070000
-#define bCCKBistMode 0x80000000
-#define bCCKCCAMask 0x40000000
+#define bCCKTxRate 0x3000
+#define bCCKDCCancel 0x0800
+#define bCCKISICancel 0x0400
+#define bCCKMatchFilter 0x0200
+#define bCCKEqualizer 0x0100
+#define bCCKPreambleDetect 0x800000
+#define bCCKFastFalseCCA 0x400000
+#define bCCKChEstStart 0x300000
+#define bCCKCCACount 0x080000
+#define bCCKcs_lim 0x070000
+#define bCCKBistMode 0x80000000
+#define bCCKCCAMask 0x40000000
#define bCCKTxDACPhase 0x4
-#define bCCKRxADCPhase 0x20000000 //r_rx_clk
+/* r_rx_clk */
+#define bCCKRxADCPhase 0x20000000
#define bCCKr_cp_mode0 0x0100
-#define bCCKTxDCOffset 0xf0
-#define bCCKRxDCOffset 0xf
-#define bCCKCCAMode 0xc000
-#define bCCKFalseCS_lim 0x3f00
-#define bCCKCS_ratio 0xc00000
-#define bCCKCorgBit_sel 0x300000
-#define bCCKPD_lim 0x0f0000
-#define bCCKNewCCA 0x80000000
-#define bCCKRxHPofIG 0x8000
-#define bCCKRxIG 0x7f00
-#define bCCKLNAPolarity 0x800000
-#define bCCKRx1stGain 0x7f0000
-#define bCCKRFExtend 0x20000000 //CCK Rx Iinital gain polarity
-#define bCCKRxAGCSatLevel 0x1f000000
-#define bCCKRxAGCSatCount 0xe0
-#define bCCKRxRFSettle 0x1f //AGCsamp_dly
-#define bCCKFixedRxAGC 0x8000
-//#define bCCKRxAGCFormat 0x4000 //remove to HSSI register 0x824
-#define bCCKAntennaPolarity 0x2000
-#define bCCKTxFilterType 0x0c00
+#define bCCKTxDCOffset 0xf0
+#define bCCKRxDCOffset 0xf
+#define bCCKCCAMode 0xc000
+#define bCCKFalseCS_lim 0x3f00
+#define bCCKCS_ratio 0xc00000
+#define bCCKCorgBit_sel 0x300000
+#define bCCKPD_lim 0x0f0000
+#define bCCKNewCCA 0x80000000
+#define bCCKRxHPofIG 0x8000
+#define bCCKRxIG 0x7f00
+#define bCCKLNAPolarity 0x800000
+#define bCCKRx1stGain 0x7f0000
+/* CCK Rx Initial gain polarity */
+#define bCCKRFExtend 0x20000000
+#define bCCKRxAGCSatLevel 0x1f000000
+#define bCCKRxAGCSatCount 0xe0
+/* AGCSAmp_dly */
+#define bCCKRxRFSettle 0x1f
+#define bCCKFixedRxAGC 0x8000
+/*#define bCCKRxAGCFormat 0x4000 remove to HSSI register 0x824 */
+#define bCCKAntennaPolarity 0x2000
+#define bCCKTxFilterType 0x0c00
#define bCCKRxAGCReportType 0x0300
-#define bCCKRxDAGCEn 0x80000000
-#define bCCKRxDAGCPeriod 0x20000000
+#define bCCKRxDAGCEn 0x80000000
+#define bCCKRxDAGCPeriod 0x20000000
#define bCCKRxDAGCSatLevel 0x1f000000
-#define bCCKTimingRecovery 0x800000
-#define bCCKTxC0 0x3f0000
-#define bCCKTxC1 0x3f000000
-#define bCCKTxC2 0x3f
-#define bCCKTxC3 0x3f00
-#define bCCKTxC4 0x3f0000
-#define bCCKTxC5 0x3f000000
-#define bCCKTxC6 0x3f
-#define bCCKTxC7 0x3f00
-#define bCCKDebugPort 0xff0000
-#define bCCKDACDebug 0x0f000000
-#define bCCKFalseAlarmEnable 0x8000
-#define bCCKFalseAlarmRead 0x4000
-#define bCCKTRSSI 0x7f
-#define bCCKRxAGCReport 0xfe
-#define bCCKRxReport_AntSel 0x80000000
-#define bCCKRxReport_MFOff 0x40000000
+#define bCCKTimingRecovery 0x800000
+#define bCCKTxC0 0x3f0000
+#define bCCKTxC1 0x3f000000
+#define bCCKTxC2 0x3f
+#define bCCKTxC3 0x3f00
+#define bCCKTxC4 0x3f0000
+#define bCCKTxC5 0x3f000000
+#define bCCKTxC6 0x3f
+#define bCCKTxC7 0x3f00
+#define bCCKDebugPort 0xff0000
+#define bCCKDACDebug 0x0f000000
+#define bCCKFalseAlarmEnable 0x8000
+#define bCCKFalseAlarmRead 0x4000
+#define bCCKTRSSI 0x7f
+#define bCCKRxAGCReport 0xfe
+#define bCCKRxReport_AntSel 0x80000000
+#define bCCKRxReport_MFOff 0x40000000
#define bCCKRxRxReport_SQLoss 0x20000000
-#define bCCKRxReport_Pktloss 0x10000000
+#define bCCKRxReport_Pktloss 0x10000000
#define bCCKRxReport_Lockedbit 0x08000000
#define bCCKRxReport_RateError 0x04000000
-#define bCCKRxReport_RxRate 0x03000000
+#define bCCKRxReport_RxRate 0x03000000
#define bCCKRxFACounterLower 0xff
#define bCCKRxFACounterUpper 0xff000000
-#define bCCKRxHPAGCStart 0xe000
-#define bCCKRxHPAGCFinal 0x1c00
+#define bCCKRxHPAGCStart 0xe000
+#define bCCKRxHPAGCFinal 0x1c00
#define bCCKRxFalseAlarmEnable 0x8000
-#define bCCKFACounterFreeze 0x4000
-
-#define bCCKTxPathSel 0x10000000
-#define bCCKDefaultRxPath 0xc000000
-#define bCCKOptionRxPath 0x3000000
-
-//page c
-#define bNumOfSTF 0x3
-#define bShift_L 0xc0
-#define bGI_TH 0xc
-#define bRxPathA 0x1
-#define bRxPathB 0x2
-#define bRxPathC 0x4
-#define bRxPathD 0x8
-#define bTxPathA 0x1
-#define bTxPathB 0x2
-#define bTxPathC 0x4
-#define bTxPathD 0x8
-#define bTRSSIFreq 0x200
-#define bADCBackoff 0x3000
-#define bDFIRBackoff 0xc000
-#define bTRSSILatchPhase 0x10000
-#define bRxIDCOffset 0xff
-#define bRxQDCOffset 0xff00
-#define bRxDFIRMode 0x1800000
-#define bRxDCNFType 0xe000000
-#define bRXIQImb_A 0x3ff
-#define bRXIQImb_B 0xfc00
-#define bRXIQImb_C 0x3f0000
-#define bRXIQImb_D 0xffc00000
-#define bDC_dc_Notch 0x60000
-#define bRxNBINotch 0x1f000000
-#define bPD_TH 0xf
-#define bPD_TH_Opt2 0xc000
-#define bPWED_TH 0x700
-#define bIfMF_Win_L 0x800
-#define bPD_Option 0x1000
-#define bMF_Win_L 0xe000
-#define bBW_Search_L 0x30000
-#define bwin_enh_L 0xc0000
-#define bBW_TH 0x700000
-#define bED_TH2 0x3800000
-#define bBW_option 0x4000000
-#define bRatio_TH 0x18000000
-#define bWindow_L 0xe0000000
-#define bSBD_Option 0x1
-#define bFrame_TH 0x1c
-#define bFS_Option 0x60
-#define bDC_Slope_check 0x80
-#define bFGuard_Counter_DC_L 0xe00
-#define bFrame_Weight_Short 0x7000
-#define bSub_Tune 0xe00000
-#define bFrame_DC_Length 0xe000000
-#define bSBD_start_offset 0x30000000
-#define bFrame_TH_2 0x7
-#define bFrame_GI2_TH 0x38
-#define bGI2_Sync_en 0x40
-#define bSarch_Short_Early 0x300
-#define bSarch_Short_Late 0xc00
-#define bSarch_GI2_Late 0x70000
-#define bCFOAntSum 0x1
-#define bCFOAcc 0x2
-#define bCFOStartOffset 0xc
-#define bCFOLookBack 0x70
-#define bCFOSumWeight 0x80
-#define bDAGCEnable 0x10000
-#define bTXIQImb_A 0x3ff
-#define bTXIQImb_B 0xfc00
-#define bTXIQImb_C 0x3f0000
-#define bTXIQImb_D 0xffc00000
-#define bTxIDCOffset 0xff
-#define bTxQDCOffset 0xff00
-#define bTxDFIRMode 0x10000
-#define bTxPesudoNoiseOn 0x4000000
-#define bTxPesudoNoise_A 0xff
-#define bTxPesudoNoise_B 0xff00
-#define bTxPesudoNoise_C 0xff0000
-#define bTxPesudoNoise_D 0xff000000
-#define bCCADropOption 0x20000
-#define bCCADropThres 0xfff00000
-#define bEDCCA_H 0xf
-#define bEDCCA_L 0xf0
-#define bLambda_ED 0x300
-#define bRxInitialGain 0x7f
-#define bRxAntDivEn 0x80
-#define bRxAGCAddressForLNA 0x7f00
-#define bRxHighPowerFlow 0x8000
-#define bRxAGCFreezeThres 0xc0000
-#define bRxFreezeStep_AGC1 0x300000
-#define bRxFreezeStep_AGC2 0xc00000
-#define bRxFreezeStep_AGC3 0x3000000
-#define bRxFreezeStep_AGC0 0xc000000
-#define bRxRssi_Cmp_En 0x10000000
-#define bRxQuickAGCEn 0x20000000
-#define bRxAGCFreezeThresMode 0x40000000
-#define bRxOverFlowCheckType 0x80000000
-#define bRxAGCShift 0x7f
-#define bTRSW_Tri_Only 0x80
-#define bPowerThres 0x300
-#define bRxAGCEn 0x1
-#define bRxAGCTogetherEn 0x2
-#define bRxAGCMin 0x4
-#define bRxHP_Ini 0x7
-#define bRxHP_TRLNA 0x70
-#define bRxHP_RSSI 0x700
-#define bRxHP_BBP1 0x7000
-#define bRxHP_BBP2 0x70000
-#define bRxHP_BBP3 0x700000
-#define bRSSI_H 0x7f0000 //the threshold for high power
-#define bRSSI_Gen 0x7f000000 //the threshold for ant diversity
-#define bRxSettle_TRSW 0x7
-#define bRxSettle_LNA 0x38
-#define bRxSettle_RSSI 0x1c0
-#define bRxSettle_BBP 0xe00
-#define bRxSettle_RxHP 0x7000
-#define bRxSettle_AntSW_RSSI 0x38000
-#define bRxSettle_AntSW 0xc0000
-#define bRxProcessTime_DAGC 0x300000
-#define bRxSettle_HSSI 0x400000
-#define bRxProcessTime_BBPPW 0x800000
-#define bRxAntennaPowerShift 0x3000000
-#define bRSSITableSelect 0xc000000
-#define bRxHP_Final 0x7000000
-#define bRxHTSettle_BBP 0x7
-#define bRxHTSettle_HSSI 0x8
-#define bRxHTSettle_RxHP 0x70
-#define bRxHTSettle_BBPPW 0x80
-#define bRxHTSettle_Idle 0x300
-#define bRxHTSettle_Reserved 0x1c00
-#define bRxHTRxHPEn 0x8000
-#define bRxHTAGCFreezeThres 0x30000
-#define bRxHTAGCTogetherEn 0x40000
-#define bRxHTAGCMin 0x80000
-#define bRxHTAGCEn 0x100000
-#define bRxHTDAGCEn 0x200000
-#define bRxHTRxHP_BBP 0x1c00000
-#define bRxHTRxHP_Final 0xe0000000
-#define bRxPWRatioTH 0x3
-#define bRxPWRatioEn 0x4
-#define bRxMFHold 0x3800
-#define bRxPD_Delay_TH1 0x38
-#define bRxPD_Delay_TH2 0x1c0
-#define bRxPD_DC_COUNT_MAX 0x600
-//#define bRxMF_Hold 0x3800
+#define bCCKFACounterFreeze 0x4000
+
+#define bCCKTxPathSel 0x10000000
+#define bCCKDefaultRxPath 0xc000000
+#define bCCKOptionRxPath 0x3000000
+
+/* Page c */
+#define bNumOfSTF 0x3
+#define bShift_L 0xc0
+#define bGI_TH 0xc
+#define bRxPathA 0x1
+#define bRxPathB 0x2
+#define bRxPathC 0x4
+#define bRxPathD 0x8
+#define bTxPathA 0x1
+#define bTxPathB 0x2
+#define bTxPathC 0x4
+#define bTxPathD 0x8
+#define bTRSSIFreq 0x200
+#define bADCBackoff 0x3000
+#define bDFIRBackoff 0xc000
+#define bTRSSILatchPhase 0x10000
+#define bRxIDCOffset 0xff
+#define bRxQDCOffset 0xff00
+#define bRxDFIRMode 0x1800000
+#define bRxDCNFType 0xe000000
+#define bRXIQImb_A 0x3ff
+#define bRXIQImb_B 0xfc00
+#define bRXIQImb_C 0x3f0000
+#define bRXIQImb_D 0xffc00000
+#define bDC_dc_Notch 0x60000
+#define bRxNBINotch 0x1f000000
+#define bPD_TH 0xf
+#define bPD_TH_Opt2 0xc000
+#define bPWED_TH 0x700
+#define bIfMF_Win_L 0x800
+#define bPD_Option 0x1000
+#define bMF_Win_L 0xe000
+#define bBW_Search_L 0x30000
+#define bwin_enh_L 0xc0000
+#define bBW_TH 0x700000
+#define bED_TH2 0x3800000
+#define bBW_option 0x4000000
+#define bRatio_TH 0x18000000
+#define bWindow_L 0xe0000000
+#define bSBD_Option 0x1
+#define bFrame_TH 0x1c
+#define bFS_Option 0x60
+#define bDC_Slope_check 0x80
+#define bFGuard_Counter_DC_L 0xe00
+#define bFrame_Weight_Short 0x7000
+#define bSub_Tune 0xe00000
+#define bFrame_DC_Length 0xe000000
+#define bSBD_start_offset 0x30000000
+#define bFrame_TH_2 0x7
+#define bFrame_GI2_TH 0x38
+#define bGI2_Sync_en 0x40
+#define bSarch_Short_Early 0x300
+#define bSarch_Short_Late 0xc00
+#define bSarch_GI2_Late 0x70000
+#define bCFOAntSum 0x1
+#define bCFOAcc 0x2
+#define bCFOStartOffset 0xc
+#define bCFOLookBack 0x70
+#define bCFOSumWeight 0x80
+#define bDAGCEnable 0x10000
+#define bTXIQImb_A 0x3ff
+#define bTXIQImb_B 0xfc00
+#define bTXIQImb_C 0x3f0000
+#define bTXIQImb_D 0xffc00000
+#define bTxIDCOffset 0xff
+#define bTxQDCOffset 0xff00
+#define bTxDFIRMode 0x10000
+#define bTxPesudoNoiseOn 0x4000000
+#define bTxPesudoNoise_A 0xff
+#define bTxPesudoNoise_B 0xff00
+#define bTxPesudoNoise_C 0xff0000
+#define bTxPesudoNoise_D 0xff000000
+#define bCCADropOption 0x20000
+#define bCCADropThres 0xfff00000
+#define bEDCCA_H 0xf
+#define bEDCCA_L 0xf0
+#define bLambda_ED 0x300
+#define bRxInitialGain 0x7f
+#define bRxAntDivEn 0x80
+#define bRxAGCAddressForLNA 0x7f00
+#define bRxHighPowerFlow 0x8000
+#define bRxAGCFreezeThres 0xc0000
+#define bRxFreezeStep_AGC1 0x300000
+#define bRxFreezeStep_AGC2 0xc00000
+#define bRxFreezeStep_AGC3 0x3000000
+#define bRxFreezeStep_AGC0 0xc000000
+#define bRxRssi_Cmp_En 0x10000000
+#define bRxQuickAGCEn 0x20000000
+#define bRxAGCFreezeThresMode 0x40000000
+#define bRxOverFlowCheckType 0x80000000
+#define bRxAGCShift 0x7f
+#define bTRSW_Tri_Only 0x80
+#define bPowerThres 0x300
+#define bRxAGCEn 0x1
+#define bRxAGCTogetherEn 0x2
+#define bRxAGCMin 0x4
+#define bRxHP_Ini 0x7
+#define bRxHP_TRLNA 0x70
+#define bRxHP_RSSI 0x700
+#define bRxHP_BBP1 0x7000
+#define bRxHP_BBP2 0x70000
+#define bRxHP_BBP3 0x700000
+/* The threshold for high power */
+#define bRSSI_H 0x7f0000
+/* The threshold for ant diversity */
+#define bRSSI_Gen 0x7f000000
+#define bRxSettle_TRSW 0x7
+#define bRxSettle_LNA 0x38
+#define bRxSettle_RSSI 0x1c0
+#define bRxSettle_BBP 0xe00
+#define bRxSettle_RxHP 0x7000
+#define bRxSettle_AntSW_RSSI 0x38000
+#define bRxSettle_AntSW 0xc0000
+#define bRxProcessTime_DAGC 0x300000
+#define bRxSettle_HSSI 0x400000
+#define bRxProcessTime_BBPPW 0x800000
+#define bRxAntennaPowerShift 0x3000000
+#define bRSSITableSelect 0xc000000
+#define bRxHP_Final 0x7000000
+#define bRxHTSettle_BBP 0x7
+#define bRxHTSettle_HSSI 0x8
+#define bRxHTSettle_RxHP 0x70
+#define bRxHTSettle_BBPPW 0x80
+#define bRxHTSettle_Idle 0x300
+#define bRxHTSettle_Reserved 0x1c00
+#define bRxHTRxHPEn 0x8000
+#define bRxHTAGCFreezeThres 0x30000
+#define bRxHTAGCTogetherEn 0x40000
+#define bRxHTAGCMin 0x80000
+#define bRxHTAGCEn 0x100000
+#define bRxHTDAGCEn 0x200000
+#define bRxHTRxHP_BBP 0x1c00000
+#define bRxHTRxHP_Final 0xe0000000
+#define bRxPWRatioTH 0x3
+#define bRxPWRatioEn 0x4
+#define bRxMFHold 0x3800
+#define bRxPD_Delay_TH1 0x38
+#define bRxPD_Delay_TH2 0x1c0
+#define bRxPD_DC_COUNT_MAX 0x600
+/*#define bRxMF_Hold 0x3800*/
#define bRxPD_Delay_TH 0x8000
#define bRxProcess_Delay 0xf0000
#define bRxSearchrange_GI2_Early 0x700000
@@ -659,7 +692,7 @@
#define bExtLNAGain 0x7c00
-//page d
+/* Page d */
#define bSTBCEn 0x4
#define bAntennaMapping 0x10
#define bNss 0x20
@@ -669,12 +702,12 @@
#define bOFDMContinueTx 0x10000000
#define bOFDMSingleCarrier 0x20000000
#define bOFDMSingleTone 0x40000000
-//#define bRxPath1 0x01
-//#define bRxPath2 0x02
-//#define bRxPath3 0x04
-//#define bRxPath4 0x08
-//#define bTxPath1 0x10
-//#define bTxPath2 0x20
+/*#define bRxPath1 0x01
+#define bRxPath2 0x02
+#define bRxPath3 0x04
+#define bRxPath4 0x08
+#define bTxPath1 0x10
+#define bTxPath2 0x20*/
#define bHTDetect 0x100
#define bCFOEn 0x10000
#define bCFOValue 0xfff00000
@@ -687,8 +720,10 @@
#define bCounter_MCSNoSupport 0xffff
#define bCounter_FastSync 0xffff
#define bShortCFO 0xfff
-#define bShortCFOTLength 12 //total
-#define bShortCFOFLength 11 //fraction
+/* total */
+#define bShortCFOTLength 12
+/* fraction */
+#define bShortCFOFLength 11
#define bLongCFO 0x7ff
#define bLongCFOTLength 11
#define bLongCFOFLength 11
@@ -765,18 +800,18 @@
#define bUChCfg 0x7000000
#define bUpdEqz 0x8000000
-//page e
-#define bTxAGCRate18_06 0x7f7f7f7f
-#define bTxAGCRate54_24 0x7f7f7f7f
+/* Page e */
+#define bTxAGCRate18_06 0x7f7f7f7f
+#define bTxAGCRate54_24 0x7f7f7f7f
#define bTxAGCRateMCS32 0x7f
-#define bTxAGCRateCCK 0x7f00
+#define bTxAGCRateCCK 0x7f00
#define bTxAGCRateMCS3_MCS0 0x7f7f7f7f
#define bTxAGCRateMCS7_MCS4 0x7f7f7f7f
#define bTxAGCRateMCS11_MCS8 0x7f7f7f7f
#define bTxAGCRateMCS15_MCS12 0x7f7f7f7f
-//Rx Pseduo noise
+/* Rx Pseduo noise */
#define bRxPesudoNoiseOn 0x20000000
#define bRxPesudoNoise_A 0xff
#define bRxPesudoNoise_B 0xff00
@@ -787,8 +822,7 @@
#define bPesudoNoiseState_C 0xffff
#define bPesudoNoiseState_D 0xffff0000
-//RF
-//Zebra1
+/* RF Zebra 1 */
#define bZebra1_HSSIEnable 0x8
#define bZebra1_TRxControl 0xc00
#define bZebra1_TRxGainSetting 0x07f
@@ -799,7 +833,7 @@
#define bZebra1_TxLPFBW 0x400
#define bZebra1_RxLPFBW 0x600
-//Zebra4
+/* Zebra4 */
#define bRTL8256RegModeCtrl1 0x100
#define bRTL8256RegModeCtrl0 0x40
#define bRTL8256_TxLPFBW 0x18
@@ -810,7 +844,7 @@
#define bRTL8258_RxLPFBW 0xc00
#define bRTL8258_RSSILPFBW 0xc0
-//byte endable for sb_write
+/* byte endable for sb_write */
#define bByte0 0x1
#define bByte1 0x2
#define bByte2 0x4
@@ -819,7 +853,7 @@
#define bWord1 0xc
#define bDWord 0xf
-//for PutRegsetting & GetRegSetting BitMask
+/* for PutRegsetting & GetRegSetting BitMask */
#define bMaskByte0 0xff
#define bMaskByte1 0xff00
#define bMaskByte2 0xff0000
@@ -828,7 +862,7 @@
#define bMaskLWord 0x0000ffff
#define bMaskDWord 0xffffffff
-//for PutRFRegsetting & GetRFRegSetting BitMask
+/* for PutRFRegsetting & GetRFRegSetting BitMask */
#define bMask12Bits 0xfff
#define bEnable 0x1
@@ -837,14 +871,16 @@
#define LeftAntenna 0x0
#define RightAntenna 0x1
-#define tCheckTxStatus 500 //500ms
-#define tUpdateRxCounter 100 //100ms
+/* 500 ms */
+#define tCheckTxStatus 500
+/* 100 ms */
+#define tUpdateRxCounter 100
#define rateCCK 0
#define rateOFDM 1
#define rateHT 2
-//define Register-End
+/* define Register-End */
#define bPMAC_End 0x1ff
#define bFPGAPHY0_End 0x8ff
#define bFPGAPHY1_End 0x9ff
@@ -852,12 +888,12 @@
#define bOFDMPHY0_End 0xcff
#define bOFDMPHY1_End 0xdff
-//define max debug item in each debug page
-//#define bMaxItem_FPGA_PHY0 0x9
-//#define bMaxItem_FPGA_PHY1 0x3
-//#define bMaxItem_PHY_11B 0x16
-//#define bMaxItem_OFDM_PHY0 0x29
-//#define bMaxItem_OFDM_PHY1 0x0
+/*#define max debug item in each debug page
+#define bMaxItem_FPGA_PHY0 0x9
+#define bMaxItem_FPGA_PHY1 0x3
+#define bMaxItem_PHY_11B 0x16
+#define bMaxItem_OFDM_PHY0 0x29
+#define bMaxItem_OFDM_PHY1 0x0 */
#define bPMACControl 0x0
#define bWMACControl 0x1
@@ -868,11 +904,12 @@
#define PathC 0x2
#define PathD 0x3
-#define rRTL8256RxMixerPole 0xb
-#define bZebraRxMixerPole 0x6
-#define rRTL8256TxBBOPBias 0x9
-#define bRTL8256TxBBOPBias 0x400
-#define rRTL8256TxBBBW 19
-#define bRTL8256TxBBBW 0x18
+#define rRTL8256RxMixerPole 0xb
+#define bZebraRxMixerPole 0x6
+#define rRTL8256TxBBOPBias 0x9
+#define bRTL8256TxBBOPBias 0x400
+#define rRTL8256TxBBBW 19
+#define bRTL8256TxBBBW 0x18
+
-#endif //__INC_HAL8190PCIPHYREG_H
+#endif /* __INC_HAL8190PCIPHYREG_H */
diff --git a/drivers/staging/rtl8192su/Kconfig b/drivers/staging/rtl8192su/Kconfig
index 123fa6d6a93b..b72a96206f58 100644
--- a/drivers/staging/rtl8192su/Kconfig
+++ b/drivers/staging/rtl8192su/Kconfig
@@ -1,6 +1,7 @@
config RTL8192SU
tristate "RealTek RTL8192SU Wireless LAN NIC driver"
depends on PCI && WLAN && USB
- depends on WIRELESS_EXT
+ select WIRELESS_EXT
+ select WEXT_PRIV
default N
---help---
diff --git a/drivers/staging/rtl8192su/TODO b/drivers/staging/rtl8192su/TODO
index f11eec700030..3c8da157a93c 100644
--- a/drivers/staging/rtl8192su/TODO
+++ b/drivers/staging/rtl8192su/TODO
@@ -4,7 +4,6 @@ TODO:
- cleanup ieee80211.h
- move rtl8192su's specific code out from ieee80211.h
- abstract rtl819su's specific code
- - use list_for_each_safe() in ieee80211_crypto_deinit
- switch to use shared "librtl" instead of private ieee80211 stack
- switch to use LIB80211
- switch to use MAC80211
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211.h b/drivers/staging/rtl8192su/ieee80211/ieee80211.h
index 9a4c858b0666..32b261d15594 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211.h
@@ -30,6 +30,7 @@
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <linux/sched.h>
+#include <linux/semaphore.h>
#include <linux/delay.h>
#include <linux/wireless.h>
@@ -195,10 +196,6 @@ extern u32 ieee80211_debug_level;
#define IEEE80211_DEBUG_DATA(level, data, datalen) do {} while(0)
#endif /* CONFIG_IEEE80211_DEBUG */
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAC_ARG(x) ((u8 *)(x))[0], ((u8 *)(x))[1], ((u8 *)(x))[2], \
- ((u8 *)(x))[3], ((u8 *)(x))[4], ((u8 *)(x))[5]
-
/*
* To use the debug system;
*
@@ -609,16 +606,6 @@ struct ieee80211_hdr_2addr {
u8 payload[0];
} __attribute__ ((packed));
-struct ieee80211_hdr_3addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 payload[0];
-} __attribute__ ((packed));
-
struct ieee80211_hdr_4addr {
__le16 frame_ctl;
__le16 duration_id;
@@ -1672,7 +1659,7 @@ static inline u8 *ieee80211_get_payload(struct rtl_ieee80211_hdr *hdr)
case IEEE80211_2ADDR_LEN:
return ((struct ieee80211_hdr_2addr *)hdr)->payload;
case IEEE80211_3ADDR_LEN:
- return ((struct ieee80211_hdr_3addr *)hdr)->payload;
+ return (void *)hdr+sizeof(struct ieee80211_hdr_3addr);
case IEEE80211_4ADDR_LEN:
return ((struct ieee80211_hdr_4addr *)hdr)->payload;
}
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c
index 521e7b989934..c4640e63196b 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c
@@ -226,19 +226,20 @@ out:
void __exit ieee80211_crypto_deinit(void)
{
struct list_head *ptr, *n;
+ struct ieee80211_crypto_alg *alg = NULL;
if (hcrypt == NULL)
return;
- for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs;
- ptr = n, n = ptr->next) {
- struct ieee80211_crypto_alg *alg =
- (struct ieee80211_crypto_alg *) ptr;
- list_del(ptr);
- printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
- "'%s' (deinit)\n", alg->ops->name);
- kfree(alg);
+ list_for_each_safe(ptr, n, &hcrypt->algs) {
+ alg = list_entry(ptr, struct ieee80211_crypto_alg, list);
+ if (alg) {
+ list_del(ptr);
+ printk(KERN_DEBUG
+ "ieee80211_crypt: unregistered algorithm '%s' (deinit)\n",
+ alg->ops->name);
+ kfree(alg);
+ }
}
-
kfree(hcrypt);
}
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c
index 7bc956e1f458..8a93f7d3eb38 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c
@@ -288,7 +288,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (!(keyidx & (1 << 5))) {
if (net_ratelimit()) {
printk(KERN_DEBUG "CCMP: received packet without ExtIV"
- " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ " flag from %pM\n", hdr->addr2);
}
key->dot11RSNAStatsCCMPFormatErrors++;
return -2;
@@ -301,9 +301,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
if (!key->key_set) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT
+ printk(KERN_DEBUG "CCMP: received packet from %pM"
" with keyid=%d that does not have a configured"
- " key\n", MAC_ARG(hdr->addr2), keyidx);
+ " key\n", hdr->addr2, keyidx);
}
return -3;
}
@@ -318,11 +318,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
- " previous PN %02x%02x%02x%02x%02x%02x "
- "received PN %02x%02x%02x%02x%02x%02x\n",
- MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn),
- MAC_ARG(pn));
+ printk(KERN_DEBUG "CCMP: replay detected: STA=%pM"
+ " previous PN %pm received PN %pm\n",
+ hdr->addr2, key->rx_pn, pn);
}
key->dot11RSNAStatsCCMPReplays++;
return -4;
@@ -359,7 +357,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
if (net_ratelimit()) {
printk(KERN_DEBUG "CCMP: decrypt failed: STA="
- MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ "%pM\n", hdr->addr2);
}
key->dot11RSNAStatsCCMPDecryptErrors++;
return -5;
@@ -435,11 +433,10 @@ static char * ieee80211_ccmp_print_stats(char *p, void *priv)
{
struct ieee80211_ccmp_data *ccmp = priv;
p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
- "tx_pn=%02x%02x%02x%02x%02x%02x "
- "rx_pn=%02x%02x%02x%02x%02x%02x "
+ "tx_pn=%pm rx_pn=%pm "
"format_errors=%d replays=%d decrypt_errors=%d\n",
ccmp->key_idx, ccmp->key_set,
- MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn),
+ ccmp->tx_pn, ccmp->rx_pn,
ccmp->dot11RSNAStatsCCMPFormatErrors,
ccmp->dot11RSNAStatsCCMPReplays,
ccmp->dot11RSNAStatsCCMPDecryptErrors);
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c
index 9b9438fb5f60..7e48748da102 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c
@@ -410,7 +410,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (!(keyidx & (1 << 5))) {
if (net_ratelimit()) {
printk(KERN_DEBUG "TKIP: received packet without ExtIV"
- " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ " flag from %pM\n", hdr->addr2);
}
return -2;
}
@@ -422,9 +422,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
if (!tkey->key_set) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT
+ printk(KERN_DEBUG "TKIP: received packet from %pM"
" with keyid=%d that does not have a configured"
- " key\n", MAC_ARG(hdr->addr2), keyidx);
+ " key\n", hdr->addr2, keyidx);
}
return -3;
}
@@ -437,9 +437,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (iv32 < tkey->rx_iv32 ||
(iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
+ printk(KERN_DEBUG "TKIP: replay detected: STA=%pM"
" previous TSC %08x%04x received TSC "
- "%08x%04x\n", MAC_ARG(hdr->addr2),
+ "%08x%04x\n", hdr->addr2,
tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
}
tkey->dot11RSNAStatsTKIPReplays++;
@@ -460,8 +460,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
if (net_ratelimit()) {
printk(KERN_DEBUG ": TKIP: failed to decrypt "
- "received packet from " MAC_FMT "\n",
- MAC_ARG(hdr->addr2));
+ "received packet from %pM\n",
+ hdr->addr2);
}
return -7;
}
@@ -480,7 +480,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
if (net_ratelimit()) {
printk(KERN_DEBUG "TKIP: ICV error detected: STA="
- MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ "%pM\n", hdr->addr2);
}
tkey->dot11RSNAStatsTKIPICVErrors++;
return -5;
@@ -635,8 +635,8 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
struct ieee80211_hdr_4addr *hdr;
hdr = (struct ieee80211_hdr_4addr *) skb->data;
printk(KERN_DEBUG "%s: Michael MIC verification failed for "
- "MSDU from " MAC_FMT " keyidx=%d\n",
- skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2),
+ "MSDU from %pM keyidx=%d\n",
+ skb->dev ? skb->dev->name : "N/A", hdr->addr2,
keyidx);
if (skb->dev)
ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c
index e8c67d5dfb76..c024fa600729 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c
@@ -262,7 +262,7 @@ static int store_debug_level(struct file *file, const char *buffer,
unsigned long count, void *data)
{
char buf[] = "0x00000000";
- unsigned long len = min(sizeof(buf) - 1, count);
+ unsigned long len = min_t(unsigned long, sizeof(buf) - 1, count);
char *p = (char *)buf;
unsigned long val;
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h b/drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h
index 123abcf0f497..7d6c3bc143ae 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h
@@ -201,7 +201,7 @@ typedef union _frameqos {
static inline u8 Frame_QoSTID(u8 *buf)
{
struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)buf;
- u16 fc = le16_to_cpu(hdr->frame_ctl);
+ u16 fc = le16_to_cpu(hdr->frame_control);
return (u8)((frameqos *)(buf +
(((fc & IEEE80211_FCTL_TODS) &&
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c
index fecfa120ff48..cc80faf6598b 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c
@@ -314,8 +314,8 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb,
strcmp(crypt->ops->name, "TKIP") == 0) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "received packet from " MAC_FMT "\n",
- ieee->dev->name, MAC_ARG(hdr->addr2));
+ "received packet from %pM\n",
+ ieee->dev->name, hdr->addr2);
}
return -1;
}
@@ -326,8 +326,8 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb,
atomic_dec(&crypt->refcnt);
if (res < 0) {
IEEE80211_DEBUG_DROP(
- "decryption failed (SA=" MAC_FMT
- ") res=%d\n", MAC_ARG(hdr->addr2), res);
+ "decryption failed (SA=%pM"
+ ") res=%d\n", hdr->addr2, res);
if (res == -2)
IEEE80211_DEBUG_DROP("Decryption failed ICV "
"mismatch (key %d)\n",
@@ -364,8 +364,8 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct sk_buff *s
atomic_dec(&crypt->refcnt);
if (res < 0) {
printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
- " (SA=" MAC_FMT " keyidx=%d)\n",
- ieee->dev->name, MAC_ARG(hdr->addr2), keyidx);
+ " (SA=%pM keyidx=%d)\n",
+ ieee->dev->name, hdr->addr2, keyidx);
return -1;
}
@@ -744,7 +744,7 @@ u8 parse_subframe(struct sk_buff *skb,
struct ieee80211_rxb *rxb,u8* src,u8* dst)
{
struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr* )skb->data;
- u16 fc = le16_to_cpu(hdr->frame_ctl);
+ u16 fc = le16_to_cpu(hdr->frame_control);
u16 LLCOffset= sizeof(struct ieee80211_hdr_3addr);
u16 ChkLength;
@@ -756,7 +756,7 @@ u8 parse_subframe(struct sk_buff *skb,
struct sk_buff *sub_skb;
u8 *data_ptr;
/* just for debug purpose */
- SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctl));
+ SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctrl));
if((IEEE80211_QOS_HAS_SEQ(fc))&&\
(((frameqos *)(skb->data + IEEE80211_3ADDR_LEN))->field.reserved)) {
@@ -939,8 +939,8 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
* frames silently instead of filling system log with
* these reports. */
IEEE80211_DEBUG_DROP("Decryption failed (not set)"
- " (SA=" MAC_FMT ")\n",
- MAC_ARG(hdr->addr2));
+ " (SA=%pM)\n",
+ hdr->addr2);
ieee->ieee_stats.rx_discards_undecryptable++;
goto rx_dropped;
}
@@ -1143,8 +1143,8 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
} else {
IEEE80211_DEBUG_DROP(
"encryption configured, but RX "
- "frame not encrypted (SA=" MAC_FMT ")\n",
- MAC_ARG(hdr->addr2));
+ "frame not encrypted (SA=%pM)\n",
+ hdr->addr2);
goto rx_dropped;
}
}
@@ -1163,9 +1163,9 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
!ieee80211_is_eapol_frame(ieee, skb, hdrlen)) {
IEEE80211_DEBUG_DROP(
"dropped unencrypted RX data "
- "frame from " MAC_FMT
+ "frame from %pM"
" (drop_unencrypted=1)\n",
- MAC_ARG(hdr->addr2));
+ hdr->addr2);
goto rx_dropped;
}
/*
@@ -2159,11 +2159,11 @@ static inline int ieee80211_network_init(
}
if (network->mode == 0) {
- IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' "
+ IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' "
"network.\n",
escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid));
+ network->bssid);
return 1;
}
@@ -2345,9 +2345,9 @@ static inline void ieee80211_process_probe_response(
memset(&network, 0, sizeof(struct ieee80211_network));
IEEE80211_DEBUG_SCAN(
- "'%s' (" MAC_FMT "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
+ "'%s' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
escape_essid(info_element->data, info_element->len),
- MAC_ARG(beacon->header.addr3),
+ beacon->header.addr3,
(beacon->capability & (1<<0xf)) ? '1' : '0',
(beacon->capability & (1<<0xe)) ? '1' : '0',
(beacon->capability & (1<<0xd)) ? '1' : '0',
@@ -2366,11 +2366,11 @@ static inline void ieee80211_process_probe_response(
(beacon->capability & (1<<0x0)) ? '1' : '0');
if (ieee80211_network_init(ieee, beacon, &network, stats)) {
- IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n",
+ IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n",
escape_essid(info_element->data,
info_element->len),
- MAC_ARG(beacon->header.addr3),
- WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
+ beacon->header.addr3,
+ WLAN_FC_GET_STYPE(beacon->header.frame_control) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
return;
@@ -2387,7 +2387,7 @@ static inline void ieee80211_process_probe_response(
return;
if(ieee->bGlobalDomain)
{
- if (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP)
+ if (WLAN_FC_GET_STYPE(beacon->header.frame_control) == IEEE80211_STYPE_PROBE_RESP)
{
// Case 1: Country code
if(IS_COUNTRY_IE_VALID(ieee) )
@@ -2454,7 +2454,7 @@ static inline void ieee80211_process_probe_response(
else
ieee->current_network.buseprotection = false;
}
- if(is_beacon(beacon->header.frame_ctl))
+ if(is_beacon(beacon->header.frame_control))
{
if(ieee->state == IEEE80211_LINKED)
ieee->LinkDetectInfo.NumRecvBcnInPeriod++;
@@ -2478,11 +2478,11 @@ static inline void ieee80211_process_probe_response(
/* If there are no more slots, expire the oldest */
list_del(&oldest->list);
target = oldest;
- IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from "
+ IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from "
"network list.\n",
escape_essid(target->ssid,
target->ssid_len),
- MAC_ARG(target->bssid));
+ target->bssid);
} else {
/* Otherwise just pull from the free list */
target = list_entry(ieee->network_free_list.next,
@@ -2492,11 +2492,11 @@ static inline void ieee80211_process_probe_response(
#ifdef CONFIG_IEEE80211_DEBUG
- IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n",
+ IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n",
escape_essid(network.ssid,
network.ssid_len),
- MAC_ARG(network.bssid),
- WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
+ network.bssid,
+ WLAN_FC_GET_STYPE(beacon->header.frame_control) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
#endif
@@ -2505,11 +2505,11 @@ static inline void ieee80211_process_probe_response(
if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)
ieee80211_softmac_new_net(ieee,&network);
} else {
- IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n",
+ IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
escape_essid(target->ssid,
target->ssid_len),
- MAC_ARG(target->bssid),
- WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
+ target->bssid,
+ WLAN_FC_GET_STYPE(beacon->header.frame_control) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
@@ -2519,7 +2519,7 @@ static inline void ieee80211_process_probe_response(
*/
renew = !time_after(target->last_scanned + ieee->scan_age, jiffies);
//YJ,add,080819,for hidden ap
- if(is_beacon(beacon->header.frame_ctl) == 0)
+ if(is_beacon(beacon->header.frame_control) == 0)
network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & target->flags);
//if(strncmp(network.ssid, "linksys-c",9) == 0)
// printk("====>2 network.ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network.ssid, network.flags, target->ssid, target->flags);
@@ -2535,7 +2535,7 @@ static inline void ieee80211_process_probe_response(
}
spin_unlock_irqrestore(&ieee->lock, flags);
- if (is_beacon(beacon->header.frame_ctl)&&is_same_network(&ieee->current_network, &network, ieee)&&\
+ if (is_beacon(beacon->header.frame_control)&&is_same_network(&ieee->current_network, &network, ieee)&&\
(ieee->state == IEEE80211_LINKED)) {
if(ieee->handle_beacon != NULL) {
ieee->handle_beacon(ieee->dev,beacon,&ieee->current_network);
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c
index 95d4f84dcf3f..9d8cb0e575d3 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c
@@ -242,7 +242,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee
if(ieee->queue_stop){
enqueue_mgmt(ieee,skb);
}else{
- header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4);
+ header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0]<<4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@@ -260,7 +260,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee
spin_unlock_irqrestore(&ieee->lock, flags);
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags);
- header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+ header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@@ -302,7 +302,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i
//printk("=============>%s()\n", __FUNCTION__);
if(single){
- header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+ header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@@ -315,7 +315,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i
}else{
- header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+ header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@@ -347,7 +347,7 @@ inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee)
skb_reserve(skb, ieee->tx_headroom);
req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request));
- req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+ req->header.frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
req->header.duration_id = 0; //FIXME: is this OK ?
memset(req->header.addr1, 0xff, ETH_ALEN);
@@ -662,8 +662,8 @@ inline struct sk_buff *ieee80211_authentication_req(struct ieee80211_network *be
auth = (struct ieee80211_authentication *)
skb_put(skb, sizeof(struct ieee80211_authentication));
- auth->header.frame_ctl = IEEE80211_STYPE_AUTH;
- if (challengelen) auth->header.frame_ctl |= IEEE80211_FCTL_WEP;
+ auth->header.frame_control = IEEE80211_STYPE_AUTH;
+ if (challengelen) auth->header.frame_control |= IEEE80211_FCTL_WEP;
auth->header.duration_id = 0x013a; //FIXME
@@ -801,7 +801,7 @@ static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *d
beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
- beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP);
+ beacon_buf->header.frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP);
beacon_buf->info_element[0].id = MFIE_TYPE_SSID;
beacon_buf->info_element[0].len = ssid_len;
@@ -880,7 +880,7 @@ struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest)
assoc = (struct ieee80211_assoc_response_frame *)
skb_put(skb,sizeof(struct ieee80211_assoc_response_frame));
- assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP);
+ assoc->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP);
memcpy(assoc->header.addr1, dest,ETH_ALEN);
memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN);
memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
@@ -935,7 +935,7 @@ struct sk_buff* ieee80211_auth_resp(struct ieee80211_device *ieee,int status, u8
memcpy(auth->header.addr3, ieee->dev->dev_addr, ETH_ALEN);
memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
memcpy(auth->header.addr1, dest, ETH_ALEN);
- auth->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_AUTH);
+ auth->header.frame_control = cpu_to_le16(IEEE80211_STYPE_AUTH);
return skb;
@@ -957,7 +957,7 @@ struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr)
memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN);
memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN);
- hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS |
(pwr ? IEEE80211_FCTL_PM:0));
@@ -1083,7 +1083,7 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco
skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)+2);
- hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ;
+ hdr->header.frame_control = IEEE80211_STYPE_ASSOC_REQ;
hdr->header.duration_id= 37; //FIXME
memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN);
memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
@@ -1709,7 +1709,7 @@ ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
ieee80211_resp_to_assoc_rq(ieee, dest);
}
- printk(KERN_INFO"New client associated: "MAC_FMT"\n", MAC_ARG(dest));
+ printk(KERN_INFO"New client associated: %pM\n", dest);
//FIXME
}
@@ -1940,13 +1940,13 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
if(!ieee->proto_started)
return 0;
- switch (WLAN_FC_GET_STYPE(header->frame_ctl)) {
+ switch (WLAN_FC_GET_STYPE(header->frame_control)) {
case IEEE80211_STYPE_ASSOC_RESP:
case IEEE80211_STYPE_REASSOC_RESP:
IEEE80211_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n",
- WLAN_FC_GET_STYPE(header->frame_ctl));
+ WLAN_FC_GET_STYPE(header->frame_control));
if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATED &&
ieee->iw_mode == IW_MODE_INFRA){
@@ -2088,7 +2088,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
ieee->state == IEEE80211_LINKED &&
ieee->iw_mode == IW_MODE_INFRA){
- printk("==========>received disassoc/deauth(%x) frame, reason code:%x\n",WLAN_FC_GET_STYPE(header->frame_ctl), ((struct ieee80211_disassoc*)skb->data)->reason);
+ printk("==========>received disassoc/deauth(%x) frame, reason code:%x\n",WLAN_FC_GET_STYPE(header->frame_control), ((struct ieee80211_disassoc*)skb->data)->reason);
ieee->state = IEEE80211_ASSOCIATING;
ieee->softmac_stats.reassoc++;
ieee->is_roaming = true;
@@ -2145,8 +2145,8 @@ void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *
ieee80211_sta_wakeup(ieee,0);
/* update the tx status */
-// ieee->stats.tx_bytes += txb->payload_size;
-// ieee->stats.tx_packets++;
+ ieee->stats.tx_bytes += txb->payload_size;
+ ieee->stats.tx_packets++;
tcb_desc = (cb_desc *)(txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE);
if(tcb_desc->bMulticast) {
ieee->stats.multicast++;
@@ -2239,7 +2239,7 @@ void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
header = (struct ieee80211_hdr_3addr *) skb->data;
- header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+ header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@@ -2574,7 +2574,7 @@ struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee)
return NULL;
b = (struct ieee80211_probe_response *) skb->data;
- b->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_BEACON);
+ b->header.frame_control = cpu_to_le16(IEEE80211_STYPE_BEACON);
return skb;
@@ -2590,7 +2590,7 @@ struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee)
return NULL;
b = (struct ieee80211_probe_response *) skb->data;
- b->header.seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+ b->header.seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
ieee->seq_ctrl[0] = 0;
@@ -3139,7 +3139,7 @@ inline struct sk_buff *ieee80211_disassociate_skb(
return NULL;
disass = (struct ieee80211_disassoc *) skb_put(skb,sizeof(struct ieee80211_disassoc));
- disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
+ disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
disass->header.duration_id = 0;
memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN);
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c
index 4d54e1e62d22..484c3aba5cb3 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c
@@ -199,8 +199,8 @@ int ieee80211_encrypt_fragment(
header = (struct rtl_ieee80211_hdr *)frag->data;
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "TX packet to " MAC_FMT "\n",
- ieee->dev->name, MAC_ARG(header->addr1));
+ "TX packet to %pM\n",
+ ieee->dev->name, header->addr1);
}
return -1;
}
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c
index 85c7e96b622d..122f8004904b 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c
@@ -261,10 +261,10 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
else
IEEE80211_DEBUG_SCAN(
"Not showing network '%s ("
- MAC_FMT ")' due to age (%lums).\n",
+ "%pM)' due to age (%lums).\n",
escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid),
+ network->bssid,
(jiffies - network->last_scanned) / (HZ / 100));
}
@@ -731,7 +731,7 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
#if 1
case IW_AUTH_WPA_ENABLED:
ieee->wpa_enabled = (data->value)?1:0;
- //printk("enalbe wpa:%d\n", ieee->wpa_enabled);
+ //printk("enable wpa:%d\n", ieee->wpa_enabled);
break;
#endif
diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c
index 8d12ffca18fa..8c37dd124fc9 100644
--- a/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c
@@ -113,7 +113,7 @@ static struct sk_buff* ieee80211_ADDBA(struct ieee80211_device* ieee, u8* Dst, P
u16 tmp = 0;
u16 len = ieee->tx_headroom + 9;
//category(1) + action field(1) + Dialog Token(1) + BA Parameter Set(2) + BA Timeout Value(2) + BA Start SeqCtrl(2)(or StatusCode(2))
- IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:"MAC_FMT", ieee->dev:%p\n", __FUNCTION__, type, MAC_ARG(Dst), ieee->dev);
+ IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:%pM, ieee->dev:%p\n", __FUNCTION__, type, Dst, ieee->dev);
if (pBA == NULL||ieee == NULL)
{
IEEE80211_DEBUG(IEEE80211_DL_ERR, "pBA(%p) is NULL or ieee(%p) is NULL\n", pBA, ieee);
@@ -136,7 +136,7 @@ static struct sk_buff* ieee80211_ADDBA(struct ieee80211_device* ieee, u8* Dst, P
memcpy(BAReq->addr3, ieee->current_network.bssid, ETH_ALEN);
- BAReq->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame
+ BAReq->frame_control = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame
//tag += sizeof( struct ieee80211_hdr_3addr); //move to action field
tag = (u8*)skb_put(skb, 9);
@@ -200,7 +200,7 @@ static struct sk_buff* ieee80211_DELBA(
u16 len = 6 + ieee->tx_headroom;
if (net_ratelimit())
- IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), ReasonCode(%d) sentd to:"MAC_FMT"\n", __FUNCTION__, ReasonCode, MAC_ARG(dst));
+ IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), ReasonCode(%d) sentd to:%pM\n", __FUNCTION__, ReasonCode, dst);
memset(&DelbaParamSet, 0, 2);
@@ -221,7 +221,7 @@ static struct sk_buff* ieee80211_DELBA(
memcpy(Delba->addr1, dst, ETH_ALEN);
memcpy(Delba->addr2, ieee->dev->dev_addr, ETH_ALEN);
memcpy(Delba->addr3, ieee->current_network.bssid, ETH_ALEN);
- Delba->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame
+ Delba->frame_control = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame
tag = (u8*)skb_put(skb, 6);
@@ -339,7 +339,10 @@ int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb)
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9)
{
- IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %ld)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
+ IEEE80211_DEBUG(IEEE80211_DL_ERR,
+ " Invalid skb len in BAREQ(%d / %zd)\n",
+ skb->len,
+ sizeof(struct ieee80211_hdr_3addr) + 9);
return -1;
}
@@ -354,7 +357,7 @@ int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb)
pBaTimeoutVal = (u16*)(tag + 5);
pBaStartSeqCtrl = (PSEQUENCE_CONTROL)(req + 7);
- printk("====================>rx ADDBAREQ from :"MAC_FMT"\n", MAC_ARG(dst));
+ printk("====================>rx ADDBAREQ from :%pM\n", dst);
//some other capability is not ready now.
if( (ieee->current_network.qos_data.active == 0) ||
(ieee->pHTInfo->bCurrentHTSupport == false) ||
@@ -440,7 +443,10 @@ int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb)
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9)
{
- IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %ld)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
+ IEEE80211_DEBUG(IEEE80211_DL_ERR,
+ " Invalid skb len in BARSP(%d / %zd)\n",
+ skb->len,
+ sizeof(struct ieee80211_hdr_3addr) + 9);
return -1;
}
rsp = ( struct ieee80211_hdr_3addr*)skb->data;
@@ -570,7 +576,10 @@ int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb)
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 6)
{
- IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %ld)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6));
+ IEEE80211_DEBUG(IEEE80211_DL_ERR,
+ " Invalid skb len in DELBA(%d / %zd)\n",
+ skb->len,
+ sizeof(struct ieee80211_hdr_3addr) + 6);
return -1;
}
diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c
index 33c7fa7edc8b..01114c5181bb 100644
--- a/drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c
+++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c
@@ -42,7 +42,7 @@ static u8 DLINK_ATHEROS_1[3] = {0x00, 0x1c, 0xf0};
static u8 DLINK_ATHEROS_2[3] = {0x00, 0x21, 0x91};
static u8 CISCO_BROADCOM[3] = {0x00, 0x17, 0x94};
static u8 LINKSYS_MARVELL_4400N[3] = {0x00, 0x14, 0xa4};
-// 2008/04/01 MH For Cisco G mode RX TP We need to change FW duration. Shoud we put the
+// 2008/04/01 MH For Cisco G mode RX TP We need to change FW duration. Should we put the
// code in other place??
//static u8 WIFI_CISCO_G_AP[3] = {0x00, 0x40, 0x96};
/********************************************************************************************************************
diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c
index ad3bf35d80e6..60cf1f8781ce 100644
--- a/drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c
@@ -291,7 +291,7 @@ PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee, u8* Addr, u8
if(search_dir[dir] ==false )
continue;
list_for_each_entry(pRet, psearch_list, List){
- // IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:"MAC_FMT", TID:%d, dir:%d\n", MAC_ARG(pRet->Addr), pRet->TSpec.f.TSInfo.field.ucTSID, pRet->TSpec.f.TSInfo.field.ucDirection);
+ // IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:%pM, TID:%d, dir:%d\n", pRet->Addr, pRet->TSpec.f.TSInfo.field.ucTSID, pRet->TSpec.f.TSInfo.field.ucDirection);
if (memcmp(pRet->Addr, Addr, 6) == 0)
if (pRet->TSpec.f.TSInfo.field.ucTSID == TID)
if(pRet->TSpec.f.TSInfo.field.ucDirection == dir)
@@ -447,7 +447,7 @@ bool GetTs(
ResetRxTsEntry(tmp);
}
- IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:"MAC_FMT"\n", UP, Dir, MAC_ARG(Addr));
+ IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP, Dir, Addr);
// Prepare TS Info releated field
pTSInfo->field.ucTrafficType = 0; // Traffic type: WMM is reserved in this field
pTSInfo->field.ucTSID = UP; // TSID
@@ -533,7 +533,7 @@ void RemoveTsEntry(
void RemovePeerTS(struct ieee80211_device* ieee, u8* Addr)
{
PTS_COMMON_INFO pTS, pTmpTS;
- printk("===========>RemovePeerTS,"MAC_FMT"\n", MAC_ARG(Addr));
+ printk("===========>RemovePeerTS,%pM\n", Addr);
#if 1
list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List)
{
diff --git a/drivers/staging/rtl8192su/r8192SU_HWImg.c b/drivers/staging/rtl8192su/r8192SU_HWImg.c
index cbb65795a302..ba8e12c209ca 100644
--- a/drivers/staging/rtl8192su/r8192SU_HWImg.c
+++ b/drivers/staging/rtl8192su/r8192SU_HWImg.c
@@ -2,4282 +2,6 @@
#include "r8192SU_HWImg.h"
-u8 Rtl8192SUFwImgArray[ImgArrayLength] = {
-0x92,0x81,0x2b,0x90,0x30,0x00,0x00,0x00,0x08,0x74,0x00,0x00,0x88,0x96,0x00,0x00,
-0x30,0x00,0x00,0x00,0x00,0x95,0x00,0x00,0x00,0x00,0x2b,0x00,0x03,0x03,0x23,0x00,
-0x92,0x81,0x02,0x01,0x00,0x00,0x12,0x04,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x01,0x01,0x01,0x00,0x00,
-0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x7f,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x1f,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x25,0xb0,0x1a,0x3c,0x80,0x03,0x5a,0x37,0x00,0x80,0x1b,0x3c,0x80,0x00,0x7b,0x37,
-0x00,0x00,0x5b,0xaf,0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x37,0x00,0x80,0x1b,0x3c,
-0x80,0x00,0x7b,0x37,0x00,0x00,0x5b,0xaf,0x00,0x80,0x1a,0x3c,0x10,0x6d,0x5a,0x27,
-0x08,0x00,0x40,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x04,0x00,0xa1,0xaf,0x08,0x00,0xa2,0xaf,0x0c,0x00,0xa3,0xaf,0x10,0x00,0xa4,0xaf,
-0x14,0x00,0xa5,0xaf,0x18,0x00,0xa6,0xaf,0x1c,0x00,0xa7,0xaf,0x20,0x00,0xa8,0xaf,
-0x24,0x00,0xa9,0xaf,0x28,0x00,0xaa,0xaf,0x2c,0x00,0xab,0xaf,0x30,0x00,0xac,0xaf,
-0x34,0x00,0xad,0xaf,0x38,0x00,0xae,0xaf,0x3c,0x00,0xaf,0xaf,0x12,0x40,0x00,0x00,
-0x10,0x48,0x00,0x00,0x00,0x70,0x0a,0x40,0x40,0x00,0xb0,0xaf,0x44,0x00,0xb1,0xaf,
-0x48,0x00,0xb2,0xaf,0x4c,0x00,0xb3,0xaf,0x50,0x00,0xb4,0xaf,0x54,0x00,0xb5,0xaf,
-0x58,0x00,0xb6,0xaf,0x5c,0x00,0xb7,0xaf,0x60,0x00,0xb8,0xaf,0x64,0x00,0xb9,0xaf,
-0x68,0x00,0xbc,0xaf,0x6c,0x00,0xbd,0xaf,0x70,0x00,0xbe,0xaf,0x74,0x00,0xbf,0xaf,
-0x78,0x00,0xa8,0xaf,0x7c,0x00,0xa9,0xaf,0x80,0x00,0xaa,0xaf,0xdf,0x1a,0x00,0x08,
-0x21,0x20,0xa0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x25,0xb0,0x06,0x3c,0x00,0x80,0x02,0x3c,0xe8,0xff,0xbd,0x27,0x18,0x03,0xc3,0x34,
-0x00,0x03,0x42,0x24,0x14,0x00,0xbf,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x00,0x62,0xac,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x42,0xb0,0x03,0x3c,
-0x03,0x00,0x63,0x34,0x00,0x00,0x62,0x90,0x02,0x80,0x0a,0x3c,0x02,0x80,0x10,0x3c,
-0xff,0x00,0x42,0x30,0x00,0x46,0x02,0x00,0x10,0x00,0x42,0x30,0x13,0x00,0x40,0x10,
-0x03,0x46,0x08,0x00,0xc4,0x7d,0x42,0x8d,0x68,0x15,0x05,0x26,0xd4,0x63,0xa4,0x94,
-0x01,0x00,0x47,0x24,0x10,0x00,0x02,0x24,0xb0,0x03,0xc9,0x34,0x00,0x00,0x62,0xa0,
-0x07,0x00,0x80,0x10,0x1c,0x03,0xc6,0x34,0xd8,0x63,0xa2,0x8c,0xd4,0x63,0xa0,0xa4,
-0xd8,0x63,0xa0,0xac,0x00,0x00,0x04,0x24,0x00,0x00,0xc2,0xac,0x00,0x00,0x20,0xad,
-0x01,0x00,0x82,0x24,0xc4,0x7d,0x47,0xad,0xd4,0x63,0xa2,0xa4,0x12,0x00,0x00,0x05,
-0x42,0xb0,0x02,0x3c,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,
-0x00,0x60,0x81,0x40,0x68,0x15,0x04,0x26,0x0c,0x4b,0x83,0x94,0x08,0x4b,0x85,0x94,
-0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f,0x80,0x00,0x63,0x30,0x41,0xb0,0x02,0x3c,
-0x25,0x18,0x65,0x00,0x08,0x00,0x42,0x34,0x18,0x00,0xbd,0x27,0x00,0x00,0x43,0xa4,
-0x08,0x00,0xe0,0x03,0x08,0x4b,0x83,0xa4,0x80,0xff,0x03,0x24,0x03,0x00,0x42,0x34,
-0x00,0x00,0x43,0xa0,0xc8,0x0e,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x68,0x15,0x04,0x26,
-0x0c,0x4b,0x83,0x94,0x08,0x4b,0x85,0x94,0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f,
-0x80,0x00,0x63,0x30,0x41,0xb0,0x02,0x3c,0x25,0x18,0x65,0x00,0x08,0x00,0x42,0x34,
-0x18,0x00,0xbd,0x27,0x00,0x00,0x43,0xa4,0x08,0x00,0xe0,0x03,0x08,0x4b,0x83,0xa4,
-0xff,0x00,0x84,0x30,0x0b,0x00,0x82,0x2c,0xff,0xff,0xe7,0x30,0x10,0x00,0xa8,0x93,
-0x19,0x00,0x40,0x10,0x21,0x18,0x00,0x00,0x02,0x80,0x03,0x3c,0x80,0x10,0x04,0x00,
-0xc0,0x91,0x63,0x24,0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,0x00,0x00,0x00,0x00,
-0x08,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x43,0xb0,0x02,0x3c,0x78,0x00,0x44,0x34,
-0x07,0x00,0xe2,0x30,0x00,0x00,0x85,0xac,0x04,0x00,0x86,0xac,0x04,0x00,0x40,0x18,
-0x00,0x00,0x00,0x00,0xf8,0xff,0xe2,0x30,0x08,0x00,0x42,0x24,0xff,0xff,0x47,0x30,
-0x21,0x10,0xe8,0x00,0x00,0x80,0x03,0x3c,0x08,0x00,0x82,0xac,0x25,0x10,0x43,0x00,
-0x08,0x00,0x82,0xac,0x01,0x00,0x03,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,
-0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08,0x6c,0x00,0x44,0x34,0x43,0xb0,0x02,0x3c,
-0x20,0x01,0x00,0x08,0x60,0x00,0x44,0x34,0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08,
-0x54,0x00,0x44,0x34,0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08,0x48,0x00,0x44,0x34,
-0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08,0x3c,0x00,0x44,0x34,0x43,0xb0,0x02,0x3c,
-0x20,0x01,0x00,0x08,0x30,0x00,0x44,0x34,0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08,
-0x24,0x00,0x44,0x34,0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08,0x18,0x00,0x44,0x34,
-0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08,0x0c,0x00,0x44,0x34,0x20,0x01,0x00,0x08,
-0x43,0xb0,0x04,0x3c,0x01,0x00,0x02,0x24,0x25,0xb0,0x03,0x3c,0x04,0x20,0x82,0x00,
-0x18,0x03,0x67,0x34,0x00,0x80,0x02,0x3c,0x43,0xb0,0x03,0x3c,0x34,0x05,0x46,0x24,
-0x88,0x00,0x65,0x34,0x21,0x10,0x00,0x00,0x01,0x00,0x42,0x24,0xff,0xff,0x42,0x30,
-0x05,0x00,0x43,0x2c,0xfd,0xff,0x60,0x14,0x01,0x00,0x42,0x24,0x00,0x00,0xe6,0xac,
-0x00,0x00,0xa2,0x94,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x30,0x24,0x10,0x44,0x00,
-0xf4,0xff,0x40,0x1c,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x25,0xb0,0x08,0x3c,0x00,0x80,0x02,0x3c,0xc8,0xff,0xbd,0x27,0x18,0x03,0x03,0x35,
-0x90,0x05,0x42,0x24,0x00,0x00,0x62,0xac,0x30,0x00,0xb6,0xaf,0x28,0x00,0xb4,0xaf,
-0x24,0x00,0xb3,0xaf,0x1c,0x00,0xb1,0xaf,0x34,0x00,0xbf,0xaf,0x2c,0x00,0xb5,0xaf,
-0x20,0x00,0xb2,0xaf,0x18,0x00,0xb0,0xaf,0x0c,0x00,0xf2,0x84,0x08,0x00,0xf5,0x8c,
-0xff,0x00,0xc6,0x30,0x00,0x01,0x02,0x24,0x23,0x10,0x46,0x00,0xff,0xff,0x51,0x30,
-0xd0,0x03,0x08,0x35,0xff,0x00,0x96,0x30,0x00,0x00,0x12,0xad,0x21,0xa0,0xa0,0x00,
-0x21,0x30,0xc5,0x00,0x00,0x00,0x15,0xad,0x21,0x20,0xc0,0x02,0x21,0x28,0xa0,0x02,
-0x21,0x38,0x20,0x02,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x23,0x18,0x51,0x02,
-0xff,0xff,0x82,0x32,0x00,0x94,0x03,0x00,0x03,0x94,0x12,0x00,0xa6,0x01,0x00,0x08,
-0x02,0x9a,0x02,0x00,0x28,0xb0,0x03,0x3c,0xc0,0x10,0x13,0x00,0x21,0x10,0x43,0x00,
-0x00,0x00,0x44,0x90,0x25,0xb0,0x10,0x3c,0x20,0x10,0x02,0x3c,0xff,0x00,0x93,0x30,
-0x00,0x22,0x13,0x00,0xff,0xff,0x43,0x32,0x01,0x01,0x45,0x2a,0x21,0xa0,0x82,0x00,
-0x21,0xa8,0xb1,0x02,0xd0,0x03,0x02,0x36,0x00,0x01,0x11,0x24,0x0b,0x88,0x65,0x00,
-0x21,0x20,0xc0,0x02,0x00,0x00,0x53,0xac,0x4d,0x01,0x00,0x0c,0xb0,0x03,0x10,0x36,
-0x21,0x30,0x80,0x02,0x21,0x20,0xc0,0x02,0x21,0x28,0xa0,0x02,0x21,0x38,0x20,0x02,
-0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x23,0x18,0x51,0x02,0x00,0x94,0x03,0x00,
-0x03,0x94,0x12,0x00,0x00,0x00,0x12,0xae,0xe2,0xff,0x40,0x1e,0x00,0x00,0x00,0x00,
-0x34,0x00,0xbf,0x8f,0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,
-0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,
-0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27,0xc8,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c,
-0x25,0xb0,0x04,0x3c,0x20,0x00,0xb2,0xaf,0x68,0x15,0x52,0x24,0x00,0x80,0x02,0x3c,
-0x18,0x03,0x83,0x34,0xc8,0x06,0x42,0x24,0x28,0x00,0xb4,0xaf,0x24,0x00,0xb3,0xaf,
-0x30,0x00,0xbf,0xaf,0x2c,0x00,0xb5,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,
-0x00,0x00,0x62,0xac,0xb0,0x03,0x93,0x34,0x21,0xa0,0x40,0x02,0x54,0x64,0x42,0x8e,
-0xc0,0x64,0x50,0x8e,0x21,0x20,0x00,0x00,0x00,0x00,0x62,0xae,0x58,0x64,0x42,0xae,
-0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00,0xc0,0x64,0x44,0x8e,
-0xc4,0x64,0x43,0x8e,0x20,0x00,0x84,0x24,0x3f,0x00,0x62,0x24,0x2b,0x10,0x44,0x00,
-0x0a,0x18,0x82,0x00,0xc0,0x64,0x43,0xae,0xc0,0x64,0x85,0x8e,0x00,0x00,0x00,0x00,
-0x00,0x00,0x65,0xae,0x02,0x80,0x02,0x3c,0xff,0xff,0x10,0x32,0x25,0x80,0x02,0x02,
-0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92,0xff,0x00,0x15,0x24,0x21,0x20,0x00,0x00,
-0x00,0x00,0x62,0xae,0x0c,0x00,0x11,0x92,0x20,0x10,0x02,0x3c,0x20,0x00,0x07,0x24,
-0x00,0x1a,0x11,0x00,0x21,0x18,0x62,0x00,0x05,0x00,0x35,0x12,0x21,0x30,0x60,0x00,
-0x08,0x64,0x91,0xa2,0x54,0x64,0x83,0xae,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,
-0x04,0x00,0x04,0x8e,0x08,0x00,0x03,0x8e,0xff,0xe0,0x02,0x3c,0xff,0xff,0x42,0x34,
-0x1f,0x00,0x84,0x30,0x24,0x18,0x62,0x00,0x00,0x26,0x04,0x00,0xff,0xdf,0x02,0x3c,
-0x25,0x18,0x64,0x00,0xff,0xff,0x42,0x34,0x24,0x18,0x62,0x00,0x00,0x40,0x04,0x3c,
-0x25,0x18,0x64,0x00,0xc0,0xff,0x02,0x24,0x24,0x18,0x62,0x00,0x08,0x00,0x03,0xae,
-0xc9,0x64,0x84,0x92,0x2a,0xb0,0x02,0x3c,0x01,0x00,0x03,0x24,0x01,0x00,0x84,0x24,
-0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0xc4,0xff,0x35,0x16,0xc9,0x64,0x84,0xa2,
-0xfc,0x4a,0x82,0x8e,0x41,0xb0,0x03,0x3c,0x30,0x00,0xbf,0x8f,0x00,0x38,0x42,0x34,
-0x00,0x00,0x62,0xac,0x2c,0x00,0xb5,0x8f,0xfc,0x4a,0x82,0xae,0x24,0x00,0xb3,0x8f,
-0x28,0x00,0xb4,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,
-0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27,0x25,0xb0,0x04,0x3c,0x00,0x80,0x02,0x3c,
-0xc8,0xff,0xbd,0x27,0x18,0x03,0x83,0x34,0x38,0x08,0x42,0x24,0x34,0x00,0xbf,0xaf,
-0x30,0x00,0xb6,0xaf,0x2c,0x00,0xb5,0xaf,0x28,0x00,0xb4,0xaf,0x24,0x00,0xb3,0xaf,
-0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,0x00,0x00,0x62,0xac,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x02,0x80,0x16,0x3c,
-0x68,0x15,0xd2,0x26,0xb0,0x03,0x93,0x34,0x2d,0x02,0x00,0x08,0x21,0xa8,0x40,0x02,
-0x2a,0xb0,0x02,0x3c,0x08,0x00,0x04,0xae,0x09,0x00,0x42,0x34,0x01,0x00,0x03,0x24,
-0x02,0x00,0x04,0x24,0x00,0x00,0x43,0xa0,0x00,0x00,0x44,0xa0,0x42,0x00,0x34,0x12,
-0x00,0x00,0x00,0x00,0x6c,0x64,0x42,0x8e,0xd8,0x64,0x50,0x8e,0x01,0x00,0x04,0x24,
-0x00,0x00,0x62,0xae,0x70,0x64,0x42,0xae,0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c,
-0x00,0x00,0x00,0x00,0xd8,0x64,0x44,0x8e,0xdc,0x64,0x43,0x8e,0x20,0x00,0x84,0x24,
-0x3f,0x00,0x62,0x24,0x2b,0x10,0x44,0x00,0x0a,0x18,0x82,0x00,0xd8,0x64,0x43,0xae,
-0xd8,0x64,0xa5,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x65,0xae,0x02,0x80,0x02,0x3c,
-0xff,0xff,0x10,0x32,0x25,0x80,0x02,0x02,0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92,
-0xff,0x00,0x14,0x24,0x01,0x00,0x04,0x24,0x00,0x00,0x62,0xae,0x0c,0x00,0x11,0x92,
-0x20,0x10,0x02,0x3c,0x20,0x00,0x07,0x24,0x00,0x1a,0x11,0x00,0x21,0x18,0x62,0x00,
-0x05,0x00,0x34,0x12,0x21,0x30,0x60,0x00,0x6c,0x64,0xa3,0xae,0x10,0x64,0xb1,0xa2,
-0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x04,0x00,0x04,0x8e,0x08,0x00,0x03,0x8e,
-0xff,0xe0,0x02,0x3c,0xff,0xff,0x42,0x34,0x1f,0x00,0x84,0x30,0x24,0x18,0x62,0x00,
-0x00,0x26,0x04,0x00,0xff,0xdf,0x02,0x3c,0x25,0x18,0x64,0x00,0xff,0xff,0x42,0x34,
-0x24,0x18,0x62,0x00,0x00,0x40,0x04,0x3c,0x25,0x18,0x64,0x00,0xc0,0xff,0x05,0x24,
-0x82,0x11,0x03,0x00,0x24,0x20,0x65,0x00,0x01,0x00,0x42,0x30,0xc0,0xff,0x40,0x10,
-0x04,0x00,0x84,0x34,0x2a,0xb0,0x02,0x3c,0x08,0x00,0x03,0xae,0x09,0x00,0x42,0x34,
-0x01,0x00,0x03,0x24,0x02,0x00,0x04,0x24,0x00,0x00,0x43,0xa0,0x00,0x00,0x44,0xa0,
-0xc0,0xff,0x34,0x16,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x68,0x15,0xc2,0x26,0xfc,0x4a,0x43,0x8c,
-0x34,0x00,0xbf,0x8f,0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,
-0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,
-0x00,0x38,0x63,0x34,0x41,0xb0,0x04,0x3c,0x38,0x00,0xbd,0x27,0x00,0x00,0x83,0xac,
-0x08,0x00,0xe0,0x03,0xfc,0x4a,0x43,0xac,0x25,0xb0,0x04,0x3c,0x00,0x80,0x02,0x3c,
-0xc0,0xff,0xbd,0x27,0x18,0x03,0x83,0x34,0x08,0x0a,0x42,0x24,0x38,0x00,0xbf,0xaf,
-0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x2c,0x00,0xb5,0xaf,0x28,0x00,0xb4,0xaf,
-0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,
-0x00,0x00,0x62,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0x02,0x80,0x17,0x3c,0x68,0x15,0xf2,0x26,0xb0,0x03,0x93,0x34,0x02,0x80,0x14,0x3c,
-0xab,0x02,0x00,0x08,0x21,0xb0,0x40,0x02,0x2a,0xb0,0x03,0x3c,0x08,0x00,0x04,0xae,
-0x05,0x00,0x63,0x34,0x01,0x00,0x02,0x24,0x02,0x00,0x04,0x24,0x00,0x00,0x62,0xa0,
-0x00,0x00,0x64,0xa0,0xca,0x7d,0x82,0x96,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,
-0xca,0x7d,0x82,0xa6,0xca,0x7d,0x83,0x96,0x25,0xb0,0x02,0x3c,0x66,0x03,0x42,0x34,
-0x00,0x00,0x43,0xa4,0x4a,0x00,0x35,0x12,0x00,0x00,0x00,0x00,0x60,0x64,0x42,0x8e,
-0xcc,0x64,0x50,0x8e,0x01,0x00,0x04,0x24,0x00,0x00,0x62,0xae,0x64,0x64,0x42,0xae,
-0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00,0xcc,0x64,0x44,0x8e,
-0xd0,0x64,0x43,0x8e,0x20,0x00,0x84,0x24,0x3f,0x00,0x62,0x24,0x2b,0x10,0x44,0x00,
-0x0a,0x18,0x82,0x00,0xcc,0x64,0x43,0xae,0xcc,0x64,0xc5,0x8e,0x00,0x00,0x00,0x00,
-0x00,0x00,0x65,0xae,0x02,0x80,0x02,0x3c,0xff,0xff,0x10,0x32,0x25,0x80,0x02,0x02,
-0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92,0xff,0x00,0x15,0x24,0x01,0x00,0x04,0x24,
-0x00,0x00,0x62,0xae,0x0c,0x00,0x11,0x92,0x20,0x10,0x02,0x3c,0x20,0x00,0x07,0x24,
-0x00,0x1a,0x11,0x00,0x21,0x18,0x62,0x00,0x05,0x00,0x35,0x12,0x21,0x30,0x60,0x00,
-0x60,0x64,0xc3,0xae,0x0c,0x64,0xd1,0xa2,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,
-0x04,0x00,0x04,0x8e,0x08,0x00,0x03,0x8e,0xff,0xe0,0x02,0x3c,0xff,0xff,0x42,0x34,
-0x1f,0x00,0x84,0x30,0x24,0x18,0x62,0x00,0x00,0x26,0x04,0x00,0xff,0xdf,0x02,0x3c,
-0x25,0x18,0x64,0x00,0xff,0xff,0x42,0x34,0x24,0x18,0x62,0x00,0x00,0x40,0x04,0x3c,
-0x25,0x18,0x64,0x00,0xc0,0xff,0x05,0x24,0x82,0x11,0x03,0x00,0x24,0x20,0x65,0x00,
-0x01,0x00,0x42,0x30,0xb8,0xff,0x40,0x10,0x04,0x00,0x84,0x34,0x08,0x00,0x03,0xae,
-0x2a,0xb0,0x03,0x3c,0x05,0x00,0x63,0x34,0x01,0x00,0x02,0x24,0x02,0x00,0x04,0x24,
-0x00,0x00,0x62,0xa0,0x00,0x00,0x64,0xa0,0xca,0x7d,0x82,0x96,0x00,0x00,0x00,0x00,
-0x01,0x00,0x42,0x24,0xca,0x7d,0x82,0xa6,0xca,0x7d,0x83,0x96,0x25,0xb0,0x02,0x3c,
-0x66,0x03,0x42,0x34,0x00,0x00,0x43,0xa4,0xb8,0xff,0x35,0x16,0x00,0x00,0x00,0x00,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x68,0x15,0xe2,0x26,0xfc,0x4a,0x43,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f,
-0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,
-0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x00,0x38,0x63,0x34,
-0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x83,0xac,0x08,0x00,0xe0,0x03,
-0xfc,0x4a,0x43,0xac,0xc0,0xff,0xbd,0x27,0x2c,0x00,0xb5,0xaf,0x38,0x00,0xbf,0xaf,
-0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x28,0x00,0xb4,0xaf,0x24,0x00,0xb3,0xaf,
-0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,0x02,0x80,0x06,0x3c,
-0x7c,0x7e,0xc5,0x90,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c,0x18,0x03,0x42,0x34,
-0x24,0x0c,0x63,0x24,0x40,0x00,0xa4,0x30,0x00,0x00,0x43,0xac,0x21,0xa8,0x00,0x00,
-0x03,0x00,0x80,0x10,0x7f,0x00,0xa2,0x30,0xbf,0x00,0xa2,0x30,0x01,0x00,0x15,0x24,
-0x7c,0x7e,0xc2,0xa0,0x7c,0x7e,0xc2,0x90,0x25,0xb0,0x04,0x3c,0x88,0x02,0x83,0x34,
-0x00,0x00,0x62,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0x02,0x80,0x16,0x3c,0x68,0x15,0xd2,0x26,0xb0,0x03,0x93,0x34,0x02,0x80,0x14,0x3c,
-0x43,0x03,0x00,0x08,0x21,0xb8,0x40,0x02,0x24,0x10,0xa2,0x00,0x04,0x00,0x42,0x34,
-0x2a,0xb0,0x07,0x3c,0x08,0x00,0x02,0xae,0x0d,0x00,0xe2,0x34,0x04,0x00,0x43,0x24,
-0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24,0x02,0x00,0x03,0x24,0x00,0x00,0x44,0xa0,
-0x00,0x00,0x43,0xa0,0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c,0x66,0x03,0xc5,0x34,
-0x01,0x00,0x84,0x24,0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96,0xff,0x00,0x03,0x24,
-0x00,0x00,0xa2,0xa4,0x5a,0x00,0x23,0x12,0x00,0x00,0x00,0x00,0x24,0x64,0x42,0x8e,
-0x90,0x64,0x50,0x8e,0x03,0x00,0x04,0x24,0x00,0x00,0x62,0xae,0x28,0x64,0x42,0xae,
-0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00,0x90,0x64,0x44,0x8e,
-0x94,0x64,0x43,0x8e,0x20,0x00,0x84,0x24,0x3f,0x00,0x62,0x24,0x2b,0x10,0x44,0x00,
-0x0a,0x18,0x82,0x00,0x90,0x64,0x43,0xae,0x90,0x64,0xe2,0x8e,0x00,0x00,0x00,0x00,
-0x00,0x00,0x62,0xae,0x02,0x80,0x02,0x3c,0xff,0xff,0x10,0x32,0x25,0x80,0x02,0x02,
-0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xae,
-0x0c,0x00,0x11,0x92,0xff,0x00,0x02,0x24,0x0d,0x00,0x22,0x12,0x00,0x12,0x11,0x00,
-0x20,0x10,0x03,0x3c,0x21,0x10,0x43,0x00,0x5a,0x00,0xa0,0x12,0x24,0x64,0xe2,0xae,
-0xec,0x63,0xf1,0xa2,0x68,0x15,0xc2,0x26,0x24,0x64,0x46,0x8c,0x90,0x64,0x45,0x8c,
-0x03,0x00,0x04,0x24,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,
-0x04,0x00,0x04,0x8e,0x14,0x00,0x03,0x8e,0x08,0x00,0x05,0x8e,0xff,0xe0,0x02,0x3c,
-0x1f,0x00,0x84,0x30,0x42,0x1a,0x03,0x00,0xff,0xff,0x42,0x34,0x00,0x26,0x04,0x00,
-0x24,0x28,0xa2,0x00,0x3f,0x00,0x63,0x30,0x25,0x28,0xa4,0x00,0x0c,0x00,0x63,0x28,
-0x06,0x00,0x60,0x14,0x21,0x20,0xa0,0x00,0x00,0x00,0x02,0x96,0x00,0x00,0x00,0x00,
-0xfd,0x0f,0x42,0x28,0x08,0x00,0x40,0x14,0x82,0x11,0x05,0x00,0xff,0xdf,0x02,0x3c,
-0xff,0xff,0x42,0x34,0x24,0x28,0x82,0x00,0x00,0x40,0x03,0x3c,0x25,0x20,0xa3,0x00,
-0x21,0x28,0x80,0x00,0x82,0x11,0x05,0x00,0x01,0x00,0x42,0x30,0xa6,0xff,0x40,0x10,
-0xc0,0xff,0x02,0x24,0x2a,0xb0,0x07,0x3c,0x0d,0x00,0xe2,0x34,0x04,0x00,0x43,0x24,
-0x08,0x00,0x04,0xae,0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24,0x02,0x00,0x03,0x24,
-0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0,0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c,
-0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24,0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96,
-0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4,0xa8,0xff,0x23,0x16,0x00,0x00,0x00,0x00,
-0x22,0x00,0xa0,0x12,0x68,0x15,0xc2,0x26,0xec,0x63,0x43,0x90,0x41,0x00,0xe4,0x34,
-0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0,0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa4,0x8c,
-0x01,0x00,0x02,0x3c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f,0x30,0x00,0xb6,0x8f,
-0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,
-0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x00,0x80,0x42,0x34,0x25,0x20,0x82,0x00,
-0x41,0xb0,0x03,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x64,0xac,0x08,0x00,0xe0,0x03,
-0xfc,0x4a,0xa4,0xac,0x65,0x03,0x00,0x08,0xe8,0x63,0xf1,0xa2,0xe8,0x63,0x43,0x90,
-0x40,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0,0x00,0x00,0xa3,0xac,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x68,0x15,0xc5,0x26,
-0xfc,0x4a,0xa4,0x8c,0x01,0x00,0x02,0x3c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f,
-0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,
-0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x00,0x80,0x42,0x34,
-0x25,0x20,0x82,0x00,0x41,0xb0,0x03,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x64,0xac,
-0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa4,0xac,0xc0,0xff,0xbd,0x27,0x2c,0x00,0xb5,0xaf,
-0x38,0x00,0xbf,0xaf,0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x28,0x00,0xb4,0xaf,
-0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,
-0x02,0x80,0x06,0x3c,0x7c,0x7e,0xc5,0x90,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c,
-0x18,0x03,0x42,0x34,0x78,0x0f,0x63,0x24,0x10,0x00,0xa4,0x30,0x00,0x00,0x43,0xac,
-0x21,0xa8,0x00,0x00,0x03,0x00,0x80,0x10,0xdf,0x00,0xa2,0x30,0xef,0x00,0xa2,0x30,
-0x01,0x00,0x15,0x24,0x7c,0x7e,0xc2,0xa0,0x7c,0x7e,0xc3,0x90,0x25,0xb0,0x02,0x3c,
-0xb0,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x02,0x80,0x16,0x3c,0x68,0x15,0xd2,0x26,
-0x21,0x98,0x40,0x00,0x02,0x80,0x14,0x3c,0x19,0x04,0x00,0x08,0x21,0xb8,0x40,0x02,
-0x24,0x10,0xa2,0x00,0x04,0x00,0x42,0x34,0x2a,0xb0,0x07,0x3c,0x08,0x00,0x02,0xae,
-0x15,0x00,0xe2,0x34,0x04,0x00,0x43,0x24,0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24,
-0x02,0x00,0x03,0x24,0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0,0xca,0x7d,0x84,0x96,
-0x25,0xb0,0x06,0x3c,0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24,0xca,0x7d,0x84,0xa6,
-0xca,0x7d,0x82,0x96,0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4,0x5a,0x00,0x23,0x12,
-0x00,0x00,0x00,0x00,0x30,0x64,0x42,0x8e,0x9c,0x64,0x50,0x8e,0x04,0x00,0x04,0x24,
-0x00,0x00,0x62,0xae,0x34,0x64,0x42,0xae,0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x9c,0x64,0x44,0x8e,0xa0,0x64,0x43,0x8e,0x20,0x00,0x84,0x24,
-0x3f,0x00,0x62,0x24,0x2b,0x10,0x44,0x00,0x0a,0x18,0x82,0x00,0x9c,0x64,0x43,0xae,
-0x9c,0x64,0xe2,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xae,0x02,0x80,0x02,0x3c,
-0xff,0xff,0x10,0x32,0x25,0x80,0x02,0x02,0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92,
-0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xae,0x0c,0x00,0x11,0x92,0xff,0x00,0x02,0x24,
-0x0d,0x00,0x22,0x12,0x00,0x12,0x11,0x00,0x20,0x10,0x03,0x3c,0x21,0x10,0x43,0x00,
-0x59,0x00,0xa0,0x12,0x30,0x64,0xe2,0xae,0xf4,0x63,0xf1,0xa2,0x68,0x15,0xc2,0x26,
-0x30,0x64,0x46,0x8c,0x9c,0x64,0x45,0x8c,0x04,0x00,0x04,0x24,0x20,0x00,0x07,0x24,
-0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x04,0x00,0x04,0x8e,0x14,0x00,0x03,0x8e,
-0x08,0x00,0x05,0x8e,0xff,0xe0,0x02,0x3c,0x1f,0x00,0x84,0x30,0x42,0x1a,0x03,0x00,
-0xff,0xff,0x42,0x34,0x00,0x26,0x04,0x00,0x24,0x28,0xa2,0x00,0x3f,0x00,0x63,0x30,
-0x25,0x28,0xa4,0x00,0x0c,0x00,0x63,0x28,0x06,0x00,0x60,0x14,0x21,0x20,0xa0,0x00,
-0x00,0x00,0x02,0x96,0x00,0x00,0x00,0x00,0xfd,0x0f,0x42,0x28,0x08,0x00,0x40,0x14,
-0x82,0x11,0x05,0x00,0xff,0xdf,0x02,0x3c,0xff,0xff,0x42,0x34,0x24,0x28,0x82,0x00,
-0x00,0x40,0x03,0x3c,0x25,0x20,0xa3,0x00,0x21,0x28,0x80,0x00,0x82,0x11,0x05,0x00,
-0x01,0x00,0x42,0x30,0xa6,0xff,0x40,0x10,0xc0,0xff,0x02,0x24,0x2a,0xb0,0x07,0x3c,
-0x15,0x00,0xe2,0x34,0x04,0x00,0x43,0x24,0x08,0x00,0x04,0xae,0x0b,0x10,0x75,0x00,
-0x01,0x00,0x04,0x24,0x02,0x00,0x03,0x24,0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0,
-0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c,0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24,
-0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96,0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4,
-0xa8,0xff,0x23,0x16,0x00,0x00,0x00,0x00,0x21,0x00,0xa0,0x12,0x68,0x15,0xc2,0x26,
-0xf4,0x63,0x43,0x90,0x43,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0,
-0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa2,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f,
-0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,
-0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x06,0x00,0x03,0x3c,
-0x25,0x10,0x43,0x00,0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x82,0xac,
-0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa2,0xac,0x3b,0x04,0x00,0x08,0xf0,0x63,0xf1,0xa2,
-0xf0,0x63,0x43,0x90,0x42,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0,
-0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa2,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f,
-0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,
-0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x06,0x00,0x03,0x3c,
-0x25,0x10,0x43,0x00,0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x82,0xac,
-0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa2,0xac,0xc0,0xff,0xbd,0x27,0x2c,0x00,0xb5,0xaf,
-0x38,0x00,0xbf,0xaf,0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x28,0x00,0xb4,0xaf,
-0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,
-0x02,0x80,0x06,0x3c,0x7c,0x7e,0xc5,0x90,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c,
-0x18,0x03,0x42,0x34,0xc8,0x12,0x63,0x24,0x01,0x00,0xa4,0x30,0x00,0x00,0x43,0xac,
-0x21,0xa8,0x00,0x00,0x03,0x00,0x80,0x10,0xf7,0x00,0xa2,0x30,0xfe,0x00,0xa2,0x30,
-0x01,0x00,0x15,0x24,0x7c,0x7e,0xc2,0xa0,0x7c,0x7e,0xc3,0x90,0x25,0xb0,0x02,0x3c,
-0xb0,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x00,0x60,0x81,0x40,0x02,0x80,0x16,0x3c,0x68,0x15,0xd2,0x26,0x21,0x98,0x40,0x00,
-0x02,0x80,0x14,0x3c,0xf8,0x04,0x00,0x08,0x21,0xb8,0x40,0x02,0x00,0x00,0x02,0x96,
-0x00,0x00,0x00,0x00,0xfd,0x0f,0x42,0x28,0x54,0x00,0x40,0x10,0xff,0xdf,0x02,0x3c,
-0x00,0x20,0x02,0x3c,0x25,0x28,0xa2,0x00,0x82,0x11,0x05,0x00,0x01,0x00,0x42,0x30,
-0x57,0x00,0x40,0x14,0x2a,0xb0,0x07,0x3c,0xc0,0xff,0x02,0x24,0x24,0x10,0xa2,0x00,
-0x04,0x00,0x42,0x34,0x2a,0xb0,0x07,0x3c,0x08,0x00,0x02,0xae,0x1d,0x00,0xe2,0x34,
-0x04,0x00,0x43,0x24,0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24,0x02,0x00,0x03,0x24,
-0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0,0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c,
-0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24,0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96,
-0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4,0x53,0x00,0x23,0x12,0x00,0x00,0x00,0x00,
-0x3c,0x64,0x42,0x8e,0xa8,0x64,0x50,0x8e,0x05,0x00,0x04,0x24,0x00,0x00,0x62,0xae,
-0x40,0x64,0x42,0xae,0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00,
-0xa8,0x64,0x44,0x8e,0xac,0x64,0x43,0x8e,0x20,0x00,0x84,0x24,0x3f,0x00,0x62,0x24,
-0x2b,0x10,0x44,0x00,0x0a,0x18,0x82,0x00,0xa8,0x64,0x43,0xae,0xa8,0x64,0xe2,0x8e,
-0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xae,0x02,0x80,0x02,0x3c,0xff,0xff,0x10,0x32,
-0x25,0x80,0x02,0x02,0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92,0x00,0x00,0x00,0x00,
-0x00,0x00,0x62,0xae,0x0c,0x00,0x11,0x92,0xff,0x00,0x02,0x24,0x0d,0x00,0x22,0x12,
-0x00,0x12,0x11,0x00,0x20,0x10,0x03,0x3c,0x21,0x10,0x43,0x00,0x52,0x00,0xa0,0x12,
-0x3c,0x64,0xe2,0xae,0x04,0x64,0xf1,0xa2,0x68,0x15,0xc2,0x26,0x3c,0x64,0x46,0x8c,
-0xa8,0x64,0x45,0x8c,0x05,0x00,0x04,0x24,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,
-0x10,0x00,0xa0,0xaf,0x14,0x00,0x03,0x8e,0x04,0x00,0x04,0x8e,0x08,0x00,0x05,0x8e,
-0x42,0x1a,0x03,0x00,0xff,0xe0,0x02,0x3c,0x1f,0x00,0x84,0x30,0x3f,0x00,0x63,0x30,
-0xff,0xff,0x42,0x34,0x24,0x28,0xa2,0x00,0x00,0x26,0x04,0x00,0x0c,0x00,0x63,0x28,
-0xaa,0xff,0x60,0x10,0x25,0x28,0xa4,0x00,0xff,0xdf,0x02,0x3c,0xff,0xff,0x42,0x34,
-0x24,0x10,0xa2,0x00,0x00,0x40,0x03,0x3c,0x25,0x28,0x43,0x00,0x82,0x11,0x05,0x00,
-0x01,0x00,0x42,0x30,0xad,0xff,0x40,0x10,0xc0,0xff,0x02,0x24,0x2a,0xb0,0x07,0x3c,
-0x1d,0x00,0xe2,0x34,0x04,0x00,0x43,0x24,0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24,
-0x02,0x00,0x03,0x24,0x08,0x00,0x05,0xae,0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0,
-0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c,0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24,
-0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96,0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4,
-0xaf,0xff,0x23,0x16,0x00,0x00,0x00,0x00,0x21,0x00,0xa0,0x12,0x68,0x15,0xc2,0x26,
-0x04,0x64,0x43,0x90,0x45,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0,
-0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa2,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f,
-0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,
-0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x18,0x00,0x03,0x3c,
-0x25,0x10,0x43,0x00,0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x82,0xac,
-0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa2,0xac,0x1a,0x05,0x00,0x08,0xf8,0x63,0xf1,0xa2,
-0xf8,0x63,0x43,0x90,0x44,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0,
-0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa2,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f,
-0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,
-0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x18,0x00,0x03,0x3c,
-0x25,0x10,0x43,0x00,0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x82,0xac,
-0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa2,0xac,0xc0,0xff,0xbd,0x27,0x2c,0x00,0xb5,0xaf,
-0x38,0x00,0xbf,0xaf,0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x28,0x00,0xb4,0xaf,
-0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,
-0x02,0x80,0x06,0x3c,0x7c,0x7e,0xc5,0x90,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c,
-0x18,0x03,0x42,0x34,0x28,0x16,0x63,0x24,0x02,0x00,0xa4,0x30,0x00,0x00,0x43,0xac,
-0x21,0xa8,0x00,0x00,0x03,0x00,0x80,0x10,0xfb,0x00,0xa2,0x30,0xfd,0x00,0xa2,0x30,
-0x01,0x00,0x15,0x24,0x7c,0x7e,0xc2,0xa0,0x7c,0x7e,0xc3,0x90,0x25,0xb0,0x02,0x3c,
-0xb0,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x00,0x60,0x81,0x40,0x02,0x80,0x16,0x3c,0x68,0x15,0xd2,0x26,0x21,0x98,0x40,0x00,
-0x02,0x80,0x14,0x3c,0xd0,0x05,0x00,0x08,0x21,0xb8,0x40,0x02,0x00,0x00,0x02,0x96,
-0x00,0x00,0x00,0x00,0xfd,0x0f,0x42,0x28,0x54,0x00,0x40,0x10,0xff,0xdf,0x02,0x3c,
-0x00,0x20,0x02,0x3c,0x25,0x28,0xa2,0x00,0x82,0x11,0x05,0x00,0x01,0x00,0x42,0x30,
-0x57,0x00,0x40,0x14,0x2a,0xb0,0x07,0x3c,0xc0,0xff,0x02,0x24,0x24,0x10,0xa2,0x00,
-0x04,0x00,0x42,0x34,0x2a,0xb0,0x07,0x3c,0x08,0x00,0x02,0xae,0x25,0x00,0xe2,0x34,
-0x04,0x00,0x43,0x24,0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24,0x02,0x00,0x03,0x24,
-0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0,0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c,
-0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24,0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96,
-0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4,0x53,0x00,0x23,0x12,0x00,0x00,0x00,0x00,
-0x48,0x64,0x42,0x8e,0xb4,0x64,0x50,0x8e,0x06,0x00,0x04,0x24,0x00,0x00,0x62,0xae,
-0x4c,0x64,0x42,0xae,0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00,
-0xb4,0x64,0x44,0x8e,0xb8,0x64,0x43,0x8e,0x20,0x00,0x84,0x24,0x3f,0x00,0x62,0x24,
-0x2b,0x10,0x44,0x00,0x0a,0x18,0x82,0x00,0xb4,0x64,0x43,0xae,0xb4,0x64,0xe2,0x8e,
-0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xae,0x02,0x80,0x02,0x3c,0xff,0xff,0x10,0x32,
-0x25,0x80,0x02,0x02,0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92,0x00,0x00,0x00,0x00,
-0x00,0x00,0x62,0xae,0x0c,0x00,0x11,0x92,0xff,0x00,0x02,0x24,0x0d,0x00,0x22,0x12,
-0x00,0x12,0x11,0x00,0x20,0x10,0x03,0x3c,0x21,0x10,0x43,0x00,0x52,0x00,0xa0,0x12,
-0x48,0x64,0xe2,0xae,0x00,0x64,0xf1,0xa2,0x68,0x15,0xc2,0x26,0x48,0x64,0x46,0x8c,
-0xb4,0x64,0x45,0x8c,0x06,0x00,0x04,0x24,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,
-0x10,0x00,0xa0,0xaf,0x14,0x00,0x03,0x8e,0x04,0x00,0x04,0x8e,0x08,0x00,0x05,0x8e,
-0x42,0x1a,0x03,0x00,0xff,0xe0,0x02,0x3c,0x1f,0x00,0x84,0x30,0x3f,0x00,0x63,0x30,
-0xff,0xff,0x42,0x34,0x24,0x28,0xa2,0x00,0x00,0x26,0x04,0x00,0x0c,0x00,0x63,0x28,
-0xaa,0xff,0x60,0x10,0x25,0x28,0xa4,0x00,0xff,0xdf,0x02,0x3c,0xff,0xff,0x42,0x34,
-0x24,0x10,0xa2,0x00,0x00,0x40,0x03,0x3c,0x25,0x28,0x43,0x00,0x82,0x11,0x05,0x00,
-0x01,0x00,0x42,0x30,0xad,0xff,0x40,0x10,0xc0,0xff,0x02,0x24,0x2a,0xb0,0x07,0x3c,
-0x25,0x00,0xe2,0x34,0x04,0x00,0x43,0x24,0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24,
-0x02,0x00,0x03,0x24,0x08,0x00,0x05,0xae,0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0,
-0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c,0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24,
-0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96,0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4,
-0xaf,0xff,0x23,0x16,0x00,0x00,0x00,0x00,0x21,0x00,0xa0,0x12,0x68,0x15,0xc2,0x26,
-0x00,0x64,0x43,0x90,0x47,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0,
-0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa2,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f,
-0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,
-0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x60,0x00,0x03,0x3c,
-0x25,0x10,0x43,0x00,0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x82,0xac,
-0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa2,0xac,0xf2,0x05,0x00,0x08,0xfc,0x63,0xf1,0xa2,
-0xfc,0x63,0x43,0x90,0x46,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0,
-0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa2,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f,
-0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,
-0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x60,0x00,0x03,0x3c,
-0x25,0x10,0x43,0x00,0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x82,0xac,
-0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa2,0xac,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c,
-0x88,0x19,0x63,0x24,0x18,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x02,0x80,0x05,0x3c,0x68,0x15,0xa5,0x24,
-0x04,0x4b,0xa2,0x8c,0xfc,0x4a,0xa4,0x8c,0x00,0x08,0x03,0x3c,0x24,0x10,0x43,0x00,
-0x25,0x20,0x82,0x00,0x41,0xb0,0x03,0x3c,0x00,0x00,0x64,0xac,0x08,0x00,0xe0,0x03,
-0xfc,0x4a,0xa4,0xac,0x25,0xb0,0x04,0x3c,0x00,0x80,0x02,0x3c,0xc0,0xff,0xbd,0x27,
-0x18,0x03,0x83,0x34,0xe4,0x19,0x42,0x24,0x3c,0x00,0xbf,0xaf,0x38,0x00,0xbe,0xaf,
-0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x2c,0x00,0xb5,0xaf,0x28,0x00,0xb4,0xaf,
-0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,
-0x00,0x00,0x62,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0x02,0x80,0x02,0x3c,0x2a,0xb0,0x03,0x3c,0x68,0x15,0x51,0x24,0xb0,0x03,0x93,0x34,
-0x2c,0x00,0x77,0x34,0x02,0x80,0x15,0x3c,0x02,0x80,0x16,0x3c,0x9c,0x06,0x00,0x08,
-0x02,0x80,0x1e,0x3c,0x14,0x64,0x26,0x92,0xe4,0x64,0x25,0x8e,0x00,0x32,0x06,0x00,
-0x21,0x30,0xc2,0x00,0x78,0x64,0x26,0xae,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,
-0xe4,0x64,0x30,0x8e,0x0a,0x00,0x04,0x24,0x21,0x90,0x00,0x00,0x00,0x00,0x70,0xae,
-0x4d,0x01,0x00,0x0c,0xff,0xff,0x10,0x32,0x02,0x80,0x02,0x3c,0x25,0x80,0x02,0x02,
-0x0c,0x00,0x05,0x92,0x02,0x00,0x04,0x92,0xff,0x00,0x02,0x24,0xff,0x00,0xa3,0x30,
-0x04,0x00,0x62,0x10,0x21,0x80,0x04,0x02,0x00,0x00,0x63,0xae,0x01,0x00,0x12,0x24,
-0x14,0x64,0x25,0xa2,0x88,0x96,0xb0,0xae,0x21,0x28,0x00,0x02,0x02,0x00,0xa2,0x90,
-0x08,0x00,0x10,0x26,0x21,0x20,0x00,0x02,0xff,0x00,0x42,0x30,0x00,0x00,0x62,0xae,
-0x03,0x00,0xa3,0x90,0x00,0x00,0x00,0x00,0x7f,0x00,0x63,0x30,0x00,0x00,0x63,0xae,
-0x00,0x00,0x72,0xae,0x03,0x00,0xa2,0x90,0x84,0x96,0xc3,0x92,0x02,0x00,0xa2,0x90,
-0x00,0x00,0x00,0x00,0xff,0x00,0x42,0x30,0x2c,0x00,0x42,0x28,0x11,0x00,0x40,0x10,
-0x08,0x00,0x02,0x24,0x03,0x00,0xa2,0x90,0x00,0x00,0x00,0x00,0x7f,0x00,0x42,0x30,
-0x84,0x96,0xc2,0xa2,0x02,0x00,0xa3,0x90,0x02,0x80,0x02,0x3c,0x74,0x84,0x42,0x24,
-0xff,0x00,0x63,0x30,0xc0,0x18,0x03,0x00,0x21,0x18,0x62,0x00,0x04,0x00,0x62,0x8c,
-0x00,0x00,0x00,0x00,0x09,0xf8,0x40,0x00,0x80,0x96,0xc2,0xaf,0x21,0xa0,0x40,0x00,
-0x08,0x00,0x02,0x24,0x0a,0x00,0x04,0x24,0x05,0x00,0x82,0x12,0x00,0x01,0x07,0x24,
-0x01,0x00,0x02,0x24,0x02,0x00,0x03,0x24,0x01,0x00,0xe2,0xa2,0x01,0x00,0xe3,0xa2,
-0xbc,0xff,0x40,0x16,0x20,0x10,0x02,0x3c,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0xfc,0x4a,0x22,0x8e,0x00,0x04,0x03,0x3c,
-0x41,0xb0,0x04,0x3c,0x25,0x10,0x43,0x00,0x00,0x00,0x82,0xac,0x3c,0x00,0xbf,0x8f,
-0xfc,0x4a,0x22,0xae,0x38,0x00,0xbe,0x8f,0x34,0x00,0xb7,0x8f,0x30,0x00,0xb6,0x8f,
-0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,
-0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x40,0x00,0xbd,0x27,
-0xc8,0xff,0xbd,0x27,0xff,0xff,0xa8,0x30,0x02,0x80,0x02,0x3c,0x25,0x40,0x02,0x01,
-0x30,0x00,0xb6,0xaf,0x20,0x00,0xb2,0xaf,0x34,0x00,0xbf,0xaf,0x2c,0x00,0xb5,0xaf,
-0x28,0x00,0xb4,0xaf,0x24,0x00,0xb3,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,
-0x00,0x00,0x03,0x8d,0xff,0xff,0xd2,0x30,0x21,0xb0,0xa0,0x00,0x00,0xc0,0x02,0x24,
-0x08,0x00,0x45,0x26,0x04,0x00,0x06,0x8d,0x24,0x18,0x62,0x00,0xff,0x3f,0xa5,0x30,
-0xf0,0xff,0x02,0x3c,0x25,0x18,0x65,0x00,0xff,0xff,0x42,0x34,0x24,0x18,0x62,0x00,
-0x00,0x80,0x05,0x3c,0x25,0x18,0x65,0x00,0xff,0x01,0xc6,0x34,0x00,0x00,0x03,0xad,
-0x04,0x00,0x06,0xad,0x21,0x48,0x80,0x00,0xff,0xff,0xe7,0x30,0x18,0x00,0x12,0xa5,
-0x1a,0x00,0x07,0xa1,0x18,0x00,0x03,0x8d,0xff,0x7f,0x02,0x3c,0xff,0xff,0x42,0x34,
-0x24,0x18,0x62,0x00,0x02,0x80,0x15,0x3c,0x18,0x00,0x03,0xad,0x68,0x15,0xa5,0x26,
-0xd6,0x63,0xa3,0x90,0x00,0x00,0x00,0x00,0x01,0x00,0x62,0x24,0xd6,0x63,0xa2,0xa0,
-0x18,0x00,0x04,0x8d,0xff,0x80,0x02,0x3c,0x20,0x00,0x45,0x26,0xff,0xff,0x42,0x34,
-0x7f,0x00,0x63,0x30,0xff,0xff,0xb2,0x30,0x24,0x20,0x82,0x00,0x00,0x1e,0x03,0x00,
-0x25,0xb0,0x02,0x3c,0xc0,0x00,0x42,0x34,0x25,0x20,0x83,0x00,0x07,0x00,0x45,0x32,
-0x18,0x00,0x04,0xad,0x00,0x00,0x52,0xa4,0x03,0x00,0xa0,0x10,0xff,0xff,0x42,0x32,
-0x08,0x00,0x42,0x26,0xff,0xff,0x42,0x30,0x68,0x15,0xb4,0x26,0x54,0x65,0x86,0x8e,
-0x58,0x65,0x90,0x8e,0xf8,0xff,0x52,0x30,0x21,0x10,0xd2,0x00,0x2b,0x10,0x02,0x02,
-0x31,0x00,0x40,0x10,0xff,0x00,0x33,0x31,0x23,0x80,0x06,0x02,0x21,0x28,0xc0,0x02,
-0xff,0xff,0x07,0x32,0x01,0x00,0x11,0x24,0x21,0x20,0x60,0x02,0x10,0x01,0x00,0x0c,
-0x10,0x00,0xb1,0xaf,0x23,0x18,0x50,0x02,0xff,0xff,0x72,0x30,0x22,0x10,0x02,0x3c,
-0x21,0x10,0x42,0x02,0x21,0x20,0x60,0x02,0x4d,0x01,0x00,0x0c,0x54,0x65,0x82,0xae,
-0x21,0x28,0xd0,0x02,0x21,0x38,0x40,0x02,0x21,0x20,0x60,0x02,0x10,0x00,0xb1,0xaf,
-0x22,0x10,0x06,0x3c,0x10,0x01,0x00,0x0c,0x68,0x15,0xb1,0x26,0x54,0x65,0x23,0x8e,
-0x25,0xb0,0x10,0x3c,0xb0,0x03,0x02,0x36,0x21,0x20,0x60,0x02,0x00,0x00,0x43,0xac,
-0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00,0x54,0x65,0x25,0x8e,0xec,0x00,0x02,0x36,
-0xbd,0x00,0x04,0x36,0x00,0x00,0x45,0xac,0x00,0x00,0x83,0x90,0xc2,0x00,0x10,0x36,
-0x34,0x00,0xbf,0x8f,0x10,0x00,0x63,0x34,0x00,0x00,0x83,0xa0,0x30,0x00,0xb6,0x8f,
-0x00,0x00,0x05,0xa6,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,
-0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x01,0x00,0x02,0x24,
-0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27,0x21,0x28,0xc0,0x02,0x21,0x20,0x60,0x02,
-0x21,0x38,0x40,0x02,0x01,0x00,0x02,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa2,0xaf,
-0x54,0x65,0x83,0x8e,0x68,0x15,0xb1,0x26,0x25,0xb0,0x10,0x3c,0x21,0x18,0x72,0x00,
-0x54,0x65,0x83,0xae,0x54,0x65,0x23,0x8e,0xb0,0x03,0x02,0x36,0x21,0x20,0x60,0x02,
-0x00,0x00,0x43,0xac,0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00,0x54,0x65,0x25,0x8e,
-0xec,0x00,0x02,0x36,0xbd,0x00,0x04,0x36,0x00,0x00,0x45,0xac,0x00,0x00,0x83,0x90,
-0xc2,0x00,0x10,0x36,0x34,0x00,0xbf,0x8f,0x10,0x00,0x63,0x34,0x00,0x00,0x83,0xa0,
-0x30,0x00,0xb6,0x8f,0x00,0x00,0x05,0xa6,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,
-0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,
-0x01,0x00,0x02,0x24,0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27,
-0x25,0xb0,0x02,0x3c,0x14,0x00,0xb1,0xaf,0x18,0x00,0xbf,0xaf,0x10,0x00,0xb0,0xaf,
-0xbf,0x00,0x42,0x34,0x00,0x00,0x43,0x90,0x21,0x28,0x00,0x00,0x08,0x00,0x06,0x24,
-0x04,0x00,0x63,0x2c,0x12,0x00,0x60,0x14,0x21,0x88,0x80,0x00,0x00,0x60,0x02,0x40,
-0x01,0x00,0x41,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x02,0x80,0x03,0x3c,
-0x00,0x7b,0x63,0x24,0x04,0x00,0x64,0x8c,0x00,0x00,0x23,0xae,0x04,0x00,0x71,0xac,
-0x00,0x00,0x91,0xac,0x04,0x00,0x24,0xae,0x00,0x60,0x82,0x40,0x18,0x00,0xbf,0x8f,
-0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,
-0x08,0x00,0x82,0x94,0x02,0x80,0x04,0x3c,0x97,0x45,0x00,0x0c,0x25,0x20,0x44,0x00,
-0x00,0x60,0x10,0x40,0x01,0x00,0x01,0x36,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x08,0x00,0x25,0x8e,0x0c,0x00,0x26,0x96,0x14,0x00,0x27,0x96,0xf0,0x06,0x00,0x0c,
-0x09,0x00,0x04,0x24,0x04,0x00,0x23,0x8e,0x00,0x00,0x22,0x8e,0x21,0x20,0x20,0x02,
-0x00,0x00,0x62,0xac,0x04,0x00,0x43,0xac,0x00,0x00,0x31,0xae,0xbd,0x4e,0x00,0x0c,
-0x04,0x00,0x31,0xae,0x00,0x60,0x90,0x40,0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0x02,0x80,0x02,0x3c,
-0x68,0x15,0x47,0x24,0x8c,0x64,0xe3,0x90,0xff,0xff,0xa5,0x30,0x09,0x00,0xa3,0x10,
-0x21,0x20,0xc0,0x00,0xfc,0x64,0xe2,0x8c,0x00,0x00,0x00,0x00,0x08,0x00,0xc2,0xac,
-0x06,0x65,0xe3,0x94,0x0e,0x00,0x02,0x24,0x14,0x00,0xc2,0xac,0x8b,0x07,0x00,0x08,
-0x0c,0x00,0xc3,0xac,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x3c,
-0x25,0xb0,0x02,0x3c,0xd0,0xff,0xbd,0x27,0x4c,0x1f,0x63,0x24,0x18,0x03,0x42,0x34,
-0x28,0x00,0xbf,0xaf,0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,
-0x18,0x00,0xb0,0xaf,0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x00,0x60,0x81,0x40,0x2a,0xb0,0x02,0x3c,0x36,0x00,0x42,0x34,0x00,0x00,0x43,0x90,
-0x02,0x80,0x13,0x3c,0x68,0x15,0x66,0x26,0xc0,0x18,0x03,0x00,0x5c,0x65,0xc5,0x8c,
-0x23,0xb0,0x04,0x3c,0xf0,0x07,0x63,0x30,0xff,0x1f,0x02,0x3c,0x21,0x18,0x64,0x00,
-0xff,0xff,0x42,0x34,0x24,0x20,0x62,0x00,0x23,0x88,0x85,0x00,0x2b,0x38,0x85,0x00,
-0x00,0x04,0x22,0x26,0x00,0x65,0xc3,0x8c,0x0b,0x88,0x47,0x00,0x01,0x04,0x25,0x2e,
-0xfc,0x64,0xc3,0xac,0x60,0x65,0xc4,0xac,0x06,0x65,0xc0,0xa4,0x11,0x00,0xa0,0x14,
-0x05,0x65,0xc0,0xa0,0x00,0xfc,0x83,0x24,0x23,0x10,0x02,0x3c,0x0b,0x18,0x87,0x00,
-0xff,0x03,0x42,0x34,0x2b,0x10,0x43,0x00,0x33,0x00,0x40,0x14,0x00,0x00,0x00,0x00,
-0x23,0x88,0x83,0x00,0x2b,0x10,0x83,0x00,0x5c,0x65,0xc3,0xac,0x03,0x00,0x40,0x10,
-0x01,0x04,0x25,0x2e,0x00,0x04,0x31,0x26,0x01,0x04,0x25,0x2e,0x0e,0x00,0xa0,0x10,
-0x68,0x15,0x70,0x26,0x68,0x15,0x70,0x26,0x60,0x65,0x03,0x8e,0x5c,0x65,0x04,0x8e,
-0x00,0x00,0x00,0x00,0x2b,0x10,0x83,0x00,0x25,0x00,0x40,0x14,0x2b,0x10,0x64,0x00,
-0x51,0x00,0x40,0x14,0x25,0xb0,0x02,0x3c,0x80,0x00,0x03,0x24,0xd0,0x03,0x42,0x34,
-0x00,0x00,0x43,0xac,0x68,0x15,0x70,0x26,0x5c,0x65,0x03,0x96,0x2a,0xb0,0x02,0x3c,
-0x35,0x00,0x42,0x34,0xc2,0x88,0x03,0x00,0x00,0x00,0x51,0xa0,0x8f,0x10,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x06,0x65,0x03,0x96,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,
-0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,
-0x00,0x60,0x81,0x40,0xfc,0x4a,0x02,0x8e,0x80,0x00,0x03,0x3c,0x41,0xb0,0x04,0x3c,
-0x25,0x10,0x43,0x00,0x00,0x00,0x82,0xac,0x28,0x00,0xbf,0x8f,0xfc,0x4a,0x02,0xae,
-0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,
-0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,0x00,0x08,0x00,0x08,0x00,0xfc,0x63,0x24,
-0xfc,0x64,0x05,0x8e,0x21,0x30,0x80,0x00,0xff,0xff,0x27,0x32,0x09,0x00,0x04,0x24,
-0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0xfc,0x64,0x03,0x8e,0x06,0x65,0x05,0x96,
-0x5c,0x65,0x02,0x8e,0x21,0x18,0x71,0x00,0x21,0x28,0x25,0x02,0x21,0x10,0x51,0x00,
-0x09,0x00,0x04,0x24,0x5c,0x65,0x02,0xae,0xfc,0x64,0x03,0xae,0x4d,0x01,0x00,0x0c,
-0x06,0x65,0x05,0xa6,0x68,0x15,0x70,0x26,0x5c,0x65,0x03,0x96,0x2a,0xb0,0x02,0x3c,
-0x35,0x00,0x42,0x34,0xc2,0x88,0x03,0x00,0x00,0x00,0x51,0xa0,0x8f,0x10,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x06,0x65,0x03,0x96,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,
-0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,
-0x00,0x60,0x81,0x40,0xfc,0x4a,0x02,0x8e,0x80,0x00,0x03,0x3c,0x41,0xb0,0x04,0x3c,
-0x25,0x10,0x43,0x00,0x00,0x00,0x82,0xac,0x28,0x00,0xbf,0x8f,0xfc,0x4a,0x02,0xae,
-0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,
-0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,0x64,0x65,0x02,0x8e,0xfc,0x64,0x05,0x8e,
-0x21,0x30,0x80,0x00,0x23,0x88,0x44,0x00,0xff,0xff,0x27,0x32,0x09,0x00,0x04,0x24,
-0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0xfc,0x64,0x03,0x8e,0x06,0x65,0x02,0x96,
-0x60,0x65,0x12,0x96,0x21,0x18,0x71,0x00,0x21,0x10,0x22,0x02,0x23,0x10,0x11,0x3c,
-0xfc,0x64,0x03,0xae,0x06,0x65,0x02,0xa6,0x06,0x00,0x40,0x16,0x5c,0x65,0x11,0xae,
-0x09,0x00,0x04,0x24,0x4d,0x01,0x00,0x0c,0x68,0x15,0x70,0x26,0x46,0x08,0x00,0x08,
-0x00,0x00,0x00,0x00,0x4d,0x01,0x00,0x0c,0x09,0x00,0x04,0x24,0xfc,0x64,0x05,0x8e,
-0x09,0x00,0x04,0x24,0x23,0x10,0x06,0x3c,0x21,0x38,0x40,0x02,0x10,0x01,0x00,0x0c,
-0x10,0x00,0xa0,0xaf,0xfc,0x64,0x03,0x8e,0x06,0x65,0x02,0x96,0x21,0x20,0x51,0x02,
-0x21,0x18,0x72,0x00,0x21,0x10,0x42,0x02,0x5c,0x65,0x04,0xae,0x09,0x00,0x04,0x24,
-0xfc,0x64,0x03,0xae,0x75,0x08,0x00,0x08,0x06,0x65,0x02,0xa6,0x02,0x80,0x09,0x3c,
-0x68,0x15,0x28,0x25,0xdc,0x63,0x06,0x8d,0xff,0xff,0x02,0x34,0x3f,0x00,0xc2,0x10,
-0x21,0x38,0x80,0x00,0x2b,0x10,0xc7,0x00,0x30,0x00,0x40,0x10,0x02,0x19,0x06,0x00,
-0x21,0x10,0xc7,0x00,0x23,0x10,0x43,0x00,0x10,0x00,0x46,0x24,0xdc,0x63,0x06,0xad,
-0x68,0x15,0x26,0x25,0x04,0x40,0xc4,0x8c,0xe0,0x63,0x02,0xad,0xff,0xff,0x02,0x34,
-0x2f,0x00,0x82,0x10,0x00,0x00,0x00,0x00,0x2b,0x10,0x87,0x00,0x1f,0x00,0x40,0x10,
-0x02,0x19,0x04,0x00,0x21,0x10,0x87,0x00,0x23,0x10,0x43,0x00,0x10,0x00,0x44,0x24,
-0x04,0x40,0xc4,0xac,0xe0,0x63,0xc2,0xac,0xc0,0x10,0x05,0x00,0x21,0x10,0x45,0x00,
-0x80,0x10,0x02,0x00,0x21,0x10,0x45,0x00,0x68,0x15,0x23,0x25,0x80,0x10,0x02,0x00,
-0x21,0x28,0x43,0x00,0x68,0x51,0xa6,0x8c,0x00,0x21,0x07,0x00,0xff,0xff,0xc2,0x38,
-0x0a,0x30,0x82,0x00,0x2b,0x18,0xc7,0x00,0x07,0x00,0x60,0x10,0x21,0x10,0xc7,0x00,
-0x02,0x19,0x06,0x00,0x23,0x10,0x43,0x00,0x10,0x00,0x46,0x24,0x68,0x51,0xa6,0xac,
-0x08,0x00,0xe0,0x03,0x6c,0x51,0xa2,0xac,0x02,0x19,0x06,0x00,0x23,0x10,0x43,0x00,
-0x68,0x51,0xa2,0xac,0x08,0x00,0xe0,0x03,0x6c,0x51,0xa2,0xac,0x21,0x10,0x87,0x00,
-0x23,0x10,0x43,0x00,0xa5,0x08,0x00,0x08,0x04,0x40,0xc2,0xac,0x21,0x10,0xc7,0x00,
-0x68,0x15,0x26,0x25,0x04,0x40,0xc4,0x8c,0x23,0x10,0x43,0x00,0xdc,0x63,0x02,0xad,
-0xe0,0x63,0x02,0xad,0xff,0xff,0x02,0x34,0xd4,0xff,0x82,0x14,0x2b,0x10,0x87,0x00,
-0x00,0x21,0x07,0x00,0x9e,0x08,0x00,0x08,0x04,0x40,0xc4,0xac,0x00,0x31,0x04,0x00,
-0x91,0x08,0x00,0x08,0xdc,0x63,0x06,0xad,0x63,0x00,0x82,0x24,0x77,0x00,0x42,0x2c,
-0x00,0x00,0x85,0x28,0x04,0x00,0x40,0x10,0x21,0x18,0x00,0x00,0x64,0x00,0x82,0x24,
-0x64,0x00,0x03,0x24,0x0b,0x18,0x45,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,
-0x0c,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x3f,0x00,0x42,0x30,0x04,0x00,0x42,0x28,
-0x17,0x00,0x40,0x10,0x25,0xb0,0x02,0x3c,0x24,0x08,0x42,0x34,0x00,0x00,0x43,0x8c,
-0x00,0x00,0x00,0x00,0x00,0x02,0x63,0x30,0x16,0x00,0x60,0x14,0x01,0x00,0x02,0x24,
-0x05,0x00,0xa3,0x90,0x00,0x00,0x00,0x00,0x82,0x21,0x03,0x00,0x28,0x00,0x82,0x10,
-0xf5,0xff,0x02,0x24,0x02,0x00,0x82,0x28,0x39,0x00,0x40,0x14,0x02,0x00,0x02,0x24,
-0x2e,0x00,0x82,0x10,0xe9,0xff,0x02,0x24,0x03,0x00,0x02,0x24,0x24,0x00,0x82,0x10,
-0x3e,0x00,0x63,0x30,0x05,0x00,0xc4,0x24,0xd2,0x08,0x00,0x08,0x00,0x00,0x00,0x00,
-0x04,0x00,0xa4,0x90,0x00,0x00,0x00,0x00,0x42,0x20,0x04,0x00,0xd2,0x08,0x00,0x08,
-0x96,0xff,0x84,0x24,0x05,0x00,0xa3,0x90,0x00,0x00,0x00,0x00,0x60,0x00,0x64,0x30,
-0x42,0x21,0x04,0x00,0x0e,0x00,0x82,0x10,0x1f,0x00,0x62,0x30,0x02,0x00,0x82,0x28,
-0x1d,0x00,0x40,0x14,0x02,0x00,0x02,0x24,0x14,0x00,0x82,0x10,0x1f,0x00,0x62,0x30,
-0x03,0x00,0x02,0x24,0xeb,0xff,0x82,0x14,0x1f,0x00,0x62,0x30,0x40,0x10,0x02,0x00,
-0xdd,0xff,0x03,0x24,0x23,0x30,0x62,0x00,0xf6,0x08,0x00,0x08,0x05,0x00,0xc4,0x24,
-0x40,0x10,0x02,0x00,0xf5,0xff,0x03,0x24,0x0e,0x09,0x00,0x08,0x23,0x30,0x62,0x00,
-0x3e,0x00,0x63,0x30,0x23,0x30,0x43,0x00,0xf6,0x08,0x00,0x08,0x05,0x00,0xc4,0x24,
-0xdd,0xff,0x02,0x24,0x16,0x09,0x00,0x08,0x23,0x30,0x43,0x00,0x40,0x10,0x02,0x00,
-0xe9,0xff,0x03,0x24,0x0e,0x09,0x00,0x08,0x23,0x30,0x62,0x00,0x3e,0x00,0x63,0x30,
-0x16,0x09,0x00,0x08,0x23,0x30,0x43,0x00,0xd2,0xff,0x80,0x14,0x1f,0x00,0x62,0x30,
-0x40,0x10,0x02,0x00,0xf8,0xff,0x03,0x24,0x0e,0x09,0x00,0x08,0x23,0x30,0x62,0x00,
-0xcc,0xff,0x80,0x14,0x3e,0x00,0x63,0x30,0xf8,0xff,0x02,0x24,0x16,0x09,0x00,0x08,
-0x23,0x30,0x43,0x00,0xa0,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c,0x4c,0x00,0xb5,0xaf,
-0x5c,0x00,0xbf,0xaf,0x58,0x00,0xbe,0xaf,0x54,0x00,0xb7,0xaf,0x50,0x00,0xb6,0xaf,
-0x48,0x00,0xb4,0xaf,0x44,0x00,0xb3,0xaf,0x40,0x00,0xb2,0xaf,0x3c,0x00,0xb1,0xaf,
-0x38,0x00,0xb0,0xaf,0x68,0x15,0x55,0x24,0x25,0xb0,0x03,0x3c,0x04,0x01,0x62,0x34,
-0x00,0x00,0x43,0x8c,0x44,0x65,0xa7,0x8e,0x00,0x00,0x00,0x00,0x33,0x00,0xe3,0x10,
-0x48,0x65,0xa3,0xae,0x2b,0x10,0x67,0x00,0xa8,0x00,0x40,0x14,0x2b,0x10,0xe3,0x00,
-0xd1,0x00,0x40,0x14,0x02,0x80,0x02,0x3c,0x68,0x15,0x44,0x24,0x18,0x65,0x83,0x94,
-0x02,0x80,0x02,0x3c,0x21,0x88,0x00,0x00,0x19,0x00,0x40,0x1a,0x25,0x98,0x62,0x00,
-0x21,0xb8,0x80,0x00,0x21,0xb0,0x80,0x00,0x01,0x00,0x14,0x24,0x21,0x20,0x00,0x00,
-0x21,0x80,0x93,0x00,0x00,0x00,0x05,0x8e,0x00,0x00,0x00,0x00,0x07,0x00,0xa0,0x10,
-0x01,0x00,0x22,0x26,0x04,0x00,0x02,0x8e,0x00,0xf0,0x03,0x3c,0x00,0x20,0x04,0x3c,
-0x24,0x10,0x43,0x00,0x1e,0x00,0x44,0x10,0x06,0x00,0x22,0x26,0xff,0xff,0x51,0x30,
-0x82,0x16,0x05,0x00,0x01,0x00,0x42,0x30,0x34,0x00,0x54,0x10,0x00,0x00,0x00,0x00,
-0x80,0x20,0x11,0x00,0x2a,0x10,0x92,0x00,0xed,0xff,0x40,0x14,0x00,0x00,0x00,0x00,
-0xbd,0x4e,0x00,0x0c,0x21,0x20,0xc0,0x03,0x02,0x80,0x02,0x3c,0x08,0x04,0x44,0x24,
-0x21,0x28,0x00,0x00,0x21,0x30,0x00,0x00,0x31,0x1c,0x00,0x0c,0x21,0x38,0x00,0x00,
-0x25,0xb0,0x03,0x3c,0x04,0x01,0x62,0x34,0x00,0x00,0x43,0x8c,0x44,0x65,0xa7,0x8e,
-0x00,0x00,0x00,0x00,0xcf,0xff,0xe3,0x14,0x48,0x65,0xa3,0xae,0x25,0xb0,0x03,0x3c,
-0x00,0x01,0x62,0x34,0x00,0x00,0x47,0xac,0x66,0x09,0x00,0x08,0x44,0x65,0xa7,0xae,
-0xb0,0x4c,0xe2,0x8e,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,0xb0,0x4c,0xe2,0xae,
-0x0c,0x00,0x04,0x8e,0x0c,0x00,0x02,0x24,0x3f,0x00,0x83,0x30,0x64,0x00,0x62,0x10,
-0x21,0x28,0xe0,0x02,0x3f,0x00,0x83,0x30,0x0d,0x00,0x02,0x24,0x59,0x00,0x62,0x10,
-0x00,0x00,0x00,0x00,0x3f,0x00,0x83,0x30,0x0e,0x00,0x02,0x24,0x04,0x00,0x62,0x10,
-0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x8e,0x5b,0x09,0x00,0x08,0x06,0x00,0x22,0x26,
-0xbc,0x4c,0xe2,0x8e,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,0xbc,0x4c,0xe2,0xae,
-0x00,0x00,0x05,0x8e,0x5b,0x09,0x00,0x08,0x06,0x00,0x22,0x26,0x00,0x40,0xc2,0x8e,
-0x00,0x00,0x00,0x00,0x02,0x12,0x02,0x00,0x0f,0x00,0x42,0x30,0x05,0x00,0x54,0x10,
-0xc2,0x13,0x05,0x00,0x1e,0x00,0x42,0x30,0x21,0x10,0x51,0x00,0x60,0x09,0x00,0x08,
-0xff,0xff,0x51,0x30,0x02,0x40,0xc2,0x92,0x00,0x00,0x00,0x00,0x1e,0x00,0x40,0x14,
-0x02,0x80,0x03,0x3c,0x04,0x00,0x03,0x8e,0x00,0x00,0x00,0x00,0x02,0x14,0x03,0x00,
-0x0f,0x00,0x42,0x30,0x17,0x00,0x40,0x14,0x02,0x17,0x03,0x00,0x03,0x00,0x44,0x30,
-0x08,0x00,0x80,0x10,0x00,0xc0,0x02,0x3c,0x24,0x10,0x62,0x00,0x11,0x00,0x40,0x14,
-0x03,0x00,0x02,0x24,0x10,0x00,0x82,0x10,0x02,0x80,0x03,0x3c,0x0f,0x00,0x80,0x10,
-0x68,0x15,0x63,0x24,0x80,0x10,0x11,0x00,0x21,0x28,0x53,0x00,0xec,0xff,0xa3,0x8c,
-0x25,0xb0,0x02,0x3c,0xd4,0x02,0x42,0x34,0x21,0x20,0x00,0x02,0x00,0x00,0x43,0xac,
-0xdc,0x08,0x00,0x0c,0x00,0x00,0x00,0x00,0x21,0x20,0x40,0x00,0x8b,0x08,0x00,0x0c,
-0x21,0x28,0x00,0x00,0x02,0x80,0x03,0x3c,0x68,0x15,0x63,0x24,0x02,0x40,0x62,0x90,
-0x00,0x00,0x00,0x00,0x85,0x00,0x54,0x10,0x00,0x00,0x00,0x00,0x02,0x80,0x04,0x3c,
-0x68,0x15,0x84,0x24,0x02,0x40,0x83,0x90,0x02,0x00,0x02,0x24,0x68,0x00,0x62,0x10,
-0x00,0x00,0x00,0x00,0x25,0xb0,0x03,0x3c,0x4c,0x00,0x63,0x34,0x00,0x00,0x62,0x90,
-0x00,0x00,0x00,0x00,0x03,0x00,0x42,0x30,0x08,0x00,0x54,0x10,0x02,0x80,0x04,0x3c,
-0x00,0x00,0x05,0x8e,0x00,0x00,0x00,0x00,0xc2,0x13,0x05,0x00,0x1e,0x00,0x42,0x30,
-0x21,0x10,0x51,0x00,0x60,0x09,0x00,0x08,0xff,0xff,0x51,0x30,0xd0,0x02,0x02,0x24,
-0x68,0x15,0x84,0x24,0xdc,0x63,0x82,0xac,0x00,0x00,0x05,0x8e,0xd3,0x09,0x00,0x08,
-0xc2,0x13,0x05,0x00,0xb8,0x4c,0xa2,0x8c,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,
-0xb8,0x4c,0xa2,0xac,0x0c,0x00,0x04,0x8e,0x86,0x09,0x00,0x08,0x3f,0x00,0x83,0x30,
-0xb4,0x4c,0xe2,0x8e,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,0xb4,0x4c,0xe2,0xae,
-0x0c,0x00,0x04,0x8e,0x82,0x09,0x00,0x08,0x3f,0x00,0x83,0x30,0x4c,0x65,0xa2,0x8e,
-0xff,0xff,0x71,0x30,0x23,0x10,0x47,0x00,0xff,0xff,0x50,0x30,0x21,0x18,0x11,0x02,
-0xff,0xff,0x72,0x30,0xa1,0x4e,0x00,0x0c,0x21,0x20,0x40,0x02,0x76,0x00,0x40,0x10,
-0x21,0xf0,0x40,0x00,0x08,0x00,0x42,0x8c,0x44,0x65,0xa6,0x8e,0x21,0x38,0x00,0x02,
-0x21,0x18,0x52,0x00,0x21,0x28,0x40,0x00,0x08,0x00,0x04,0x24,0x14,0x65,0xa3,0xae,
-0x18,0x65,0xa2,0xae,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x4d,0x01,0x00,0x0c,
-0x08,0x00,0x04,0x24,0x18,0x65,0xa5,0x8e,0x25,0xb0,0x03,0x3c,0x24,0x10,0x02,0x3c,
-0x21,0x28,0xb0,0x00,0x00,0x01,0x70,0x34,0x00,0x00,0x02,0xae,0x21,0x38,0x20,0x02,
-0x08,0x00,0x04,0x24,0x24,0x10,0x06,0x3c,0x44,0x65,0xa2,0xae,0x10,0x01,0x00,0x0c,
-0x10,0x00,0xa0,0xaf,0x48,0x65,0xa3,0x8e,0x08,0x00,0x04,0x24,0x4d,0x01,0x00,0x0c,
-0x44,0x65,0xa3,0xae,0x44,0x65,0xa2,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xae,
-0x46,0x09,0x00,0x08,0x02,0x80,0x02,0x3c,0x23,0x10,0x67,0x00,0xff,0xff,0x52,0x30,
-0xa1,0x4e,0x00,0x0c,0x21,0x20,0x40,0x02,0x56,0x00,0x40,0x10,0x21,0xf0,0x40,0x00,
-0x08,0x00,0x42,0x8c,0x44,0x65,0xa6,0x8e,0x08,0x00,0x04,0x24,0x21,0x18,0x52,0x00,
-0x21,0x28,0x40,0x00,0x21,0x38,0x40,0x02,0x14,0x65,0xa3,0xae,0x18,0x65,0xa2,0xae,
-0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x48,0x65,0xa3,0x8e,0x08,0x00,0x04,0x24,
-0x4d,0x01,0x00,0x0c,0x44,0x65,0xa3,0xae,0x44,0x65,0xa3,0x8e,0x25,0xb0,0x04,0x3c,
-0x00,0x01,0x82,0x34,0x00,0x00,0x43,0xac,0x46,0x09,0x00,0x08,0x02,0x80,0x02,0x3c,
-0x04,0x00,0x03,0x8e,0x00,0x00,0x00,0x00,0x02,0x14,0x03,0x00,0x0f,0x00,0x42,0x30,
-0x08,0x00,0x42,0x28,0x93,0xff,0x40,0x10,0x02,0x17,0x03,0x00,0x03,0x00,0x42,0x30,
-0x90,0xff,0x40,0x14,0x80,0x10,0x11,0x00,0x21,0x28,0x53,0x00,0xec,0xff,0xa3,0x8c,
-0x25,0xb0,0x02,0x3c,0xd4,0x02,0x42,0x34,0x21,0x20,0x00,0x02,0x00,0x00,0x43,0xac,
-0xdc,0x08,0x00,0x0c,0x00,0x00,0x00,0x00,0x21,0x20,0x40,0x00,0x8b,0x08,0x00,0x0c,
-0x21,0x28,0x00,0x00,0xca,0x09,0x00,0x08,0x25,0xb0,0x03,0x3c,0x04,0x00,0x03,0x8e,
-0x00,0x00,0x00,0x00,0x02,0x14,0x03,0x00,0x0f,0x00,0x42,0x30,0x08,0x00,0x42,0x28,
-0x06,0x00,0x40,0x10,0x00,0xc0,0x02,0x3c,0x02,0x17,0x03,0x00,0x03,0x00,0x42,0x30,
-0x0c,0x00,0x40,0x10,0x80,0x10,0x11,0x00,0x00,0xc0,0x02,0x3c,0x24,0x10,0x62,0x00,
-0x6f,0xff,0x40,0x14,0x02,0x80,0x04,0x3c,0x02,0x17,0x03,0x00,0x03,0x00,0x42,0x30,
-0x03,0x00,0x03,0x24,0x6b,0xff,0x43,0x10,0x68,0x15,0x84,0x24,0x67,0xff,0x40,0x10,
-0x80,0x10,0x11,0x00,0x21,0x28,0x53,0x00,0xec,0xff,0xa3,0x8c,0x25,0xb0,0x02,0x3c,
-0xd4,0x02,0x42,0x34,0x21,0x20,0x00,0x02,0x00,0x00,0x43,0xac,0xdc,0x08,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x21,0x20,0x40,0x00,0x8b,0x08,0x00,0x0c,0x21,0x28,0x00,0x00,
-0xc4,0x09,0x00,0x08,0x02,0x80,0x04,0x3c,0x25,0xb0,0x04,0x3c,0x44,0x44,0x02,0x3c,
-0xbc,0x02,0x83,0x34,0x44,0x44,0x42,0x34,0x00,0x00,0x62,0xac,0x67,0x09,0x00,0x08,
-0x02,0x80,0x02,0x3c,0x48,0x65,0xa5,0x8e,0x25,0xb0,0x04,0x3c,0x66,0x66,0x02,0x3c,
-0x00,0x01,0x83,0x34,0x66,0x66,0x42,0x34,0xbc,0x02,0x84,0x34,0x00,0x00,0x65,0xac,
-0x00,0x00,0x82,0xac,0x66,0x09,0x00,0x08,0x44,0x65,0xa5,0xae,0x00,0x60,0x02,0x40,
-0x01,0x00,0x41,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x02,0x80,0x03,0x3c,
-0xd8,0x8c,0x64,0xac,0x00,0x60,0x82,0x40,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x02,0x80,0x02,0x3c,0xd8,0x8c,0x45,0x8c,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c,
-0x18,0x03,0x42,0x34,0x10,0x2a,0x63,0x24,0x00,0x00,0x43,0xac,0x04,0x00,0x02,0x24,
-0x1e,0x00,0xa2,0x10,0x05,0x00,0xa2,0x2c,0x10,0x00,0x40,0x10,0x05,0x00,0x02,0x24,
-0x03,0x00,0x02,0x24,0x08,0x00,0xa2,0x10,0x00,0x19,0x04,0x00,0x80,0x10,0x04,0x00,
-0x21,0x10,0x44,0x00,0xc0,0x10,0x02,0x00,0x23,0x10,0x44,0x00,0x00,0x11,0x02,0x00,
-0x21,0x10,0x44,0x00,0x40,0x19,0x02,0x00,0xff,0xff,0x63,0x24,0xfe,0xff,0x60,0x14,
-0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xf3,0xff,0xa2,0x10,
-0x06,0x00,0x02,0x24,0xf2,0xff,0xa2,0x14,0x80,0x10,0x04,0x00,0x40,0x11,0x04,0x00,
-0x23,0x10,0x44,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x44,0x00,0x00,0x19,0x02,0x00,
-0x23,0x18,0x62,0x00,0x9a,0x0a,0x00,0x08,0x00,0x19,0x03,0x00,0x80,0x10,0x04,0x00,
-0x21,0x10,0x44,0x00,0xc0,0x10,0x02,0x00,0x23,0x10,0x44,0x00,0x00,0x11,0x02,0x00,
-0x21,0x10,0x44,0x00,0x9a,0x0a,0x00,0x08,0x00,0x19,0x02,0x00,0x02,0x80,0x02,0x3c,
-0xd8,0x8c,0x45,0x8c,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c,0x18,0x03,0x42,0x34,
-0xcc,0x2a,0x63,0x24,0x00,0x00,0x43,0xac,0x05,0x00,0x02,0x24,0x10,0x00,0xa2,0x10,
-0x06,0x00,0xa2,0x2c,0x09,0x00,0x40,0x14,0x04,0x00,0x02,0x24,0x06,0x00,0x02,0x24,
-0x0f,0x00,0xa2,0x10,0x00,0x11,0x04,0x00,0xff,0xff,0x84,0x24,0xfe,0xff,0x80,0x14,
-0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xfa,0xff,0xa2,0x14,
-0x80,0x10,0x04,0x00,0x21,0x10,0x44,0x00,0xc2,0x0a,0x00,0x08,0x40,0x20,0x02,0x00,
-0x80,0x10,0x04,0x00,0x21,0x10,0x44,0x00,0xc2,0x0a,0x00,0x08,0x80,0x20,0x02,0x00,
-0x23,0x10,0x44,0x00,0xc2,0x0a,0x00,0x08,0x40,0x20,0x02,0x00,0xff,0xff,0x85,0x30,
-0x21,0x30,0x00,0x00,0x25,0xb0,0x03,0x3c,0x2a,0xb0,0x04,0x3c,0xb4,0x00,0x63,0x34,
-0x01,0x00,0xa2,0x24,0x31,0x00,0x84,0x34,0x00,0x00,0x65,0xa0,0x00,0x00,0x85,0xa0,
-0xff,0xff,0x45,0x30,0x12,0x00,0xa0,0x10,0x01,0x00,0x03,0x24,0x28,0xb0,0x07,0x3c,
-0xe8,0x0a,0x00,0x08,0xff,0xff,0x08,0x24,0x00,0x00,0x83,0xa0,0x01,0x00,0x63,0x24,
-0xff,0xff,0x63,0x30,0x2b,0x10,0xa3,0x00,0x09,0x00,0x40,0x14,0x08,0x00,0xc6,0x24,
-0xf9,0xff,0x65,0x14,0x21,0x20,0xc7,0x00,0x01,0x00,0x63,0x24,0xff,0xff,0x63,0x30,
-0x2b,0x10,0xa3,0x00,0x00,0x00,0x88,0xa0,0xf9,0xff,0x40,0x10,0x08,0x00,0xc6,0x24,
-0x00,0x01,0xa2,0x2c,0x13,0x00,0x40,0x10,0x21,0x18,0xa0,0x00,0xff,0x00,0x08,0x24,
-0x28,0xb0,0x07,0x3c,0xfc,0x0a,0x00,0x08,0xff,0xff,0x09,0x24,0xff,0xff,0x43,0x30,
-0x00,0x00,0xa2,0xa0,0x00,0x01,0x62,0x2c,0x0a,0x00,0x40,0x10,0x08,0x00,0xc6,0x24,
-0x01,0x00,0x62,0x24,0xf9,0xff,0x68,0x14,0x21,0x28,0xc7,0x00,0x00,0x01,0x02,0x24,
-0xff,0xff,0x43,0x30,0x00,0x01,0x62,0x2c,0x00,0x00,0xa9,0xa0,0xf8,0xff,0x40,0x14,
-0x08,0x00,0xc6,0x24,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xd8,0xff,0xbd,0x27,
-0x24,0x00,0xbf,0xaf,0x20,0x00,0xb4,0xaf,0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf,
-0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x25,0xb0,0x10,0x3c,0x42,0x00,0x14,0x36,
-0xff,0xff,0x02,0x24,0x00,0x00,0x82,0xa2,0xd8,0x00,0x05,0x36,0x40,0x00,0x11,0x36,
-0xa8,0x00,0x13,0x36,0xa0,0x00,0x12,0x36,0x00,0x10,0x03,0x24,0xa4,0x00,0x10,0x36,
-0x00,0x80,0x02,0x3c,0x00,0x00,0x23,0xa6,0x00,0x00,0xa0,0xa0,0x00,0x00,0x40,0xae,
-0x00,0x00,0x00,0xae,0x00,0x00,0x62,0xae,0x00,0x00,0xa3,0x90,0x80,0xff,0x02,0x24,
-0xfd,0x00,0x04,0x24,0x25,0x18,0x62,0x00,0xfc,0x17,0x02,0x24,0x00,0x00,0xa3,0xa0,
-0x00,0x00,0x22,0xa6,0xd3,0x0a,0x00,0x0c,0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c,
-0x68,0x15,0x42,0x24,0x68,0x4b,0x45,0x8c,0x60,0x4b,0x43,0x8c,0x64,0x4b,0x44,0x8c,
-0xfc,0x37,0x02,0x24,0x00,0x00,0x43,0xae,0x00,0x00,0x04,0xae,0x00,0x00,0x65,0xae,
-0x00,0x00,0x22,0xa6,0x00,0x00,0x80,0xa2,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x00,0x60,0x81,0x40,0x24,0x00,0xbf,0x8f,0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f,
-0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,
-0x28,0x00,0xbd,0x27,0xd0,0xff,0xbd,0x27,0x2c,0x00,0xbf,0xaf,0x28,0x00,0xb6,0xaf,
-0x24,0x00,0xb5,0xaf,0x20,0x00,0xb4,0xaf,0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf,
-0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x25,0xb0,0x10,0x3c,0x40,0x00,0x05,0x36,
-0x00,0x00,0xa2,0x94,0x24,0xfa,0x03,0x24,0xa8,0x00,0x13,0x36,0x24,0x10,0x43,0x00,
-0x00,0x00,0xa2,0xa4,0xa0,0x00,0x12,0x36,0xa4,0x00,0x10,0x36,0x00,0x00,0x55,0x8e,
-0x00,0x00,0x16,0x8e,0x00,0x00,0x71,0x8e,0x00,0x80,0x14,0x3c,0xfc,0x37,0x02,0x24,
-0x00,0x00,0x40,0xae,0xfd,0x00,0x04,0x24,0x00,0x00,0x00,0xae,0x21,0x88,0x34,0x02,
-0x00,0x00,0x74,0xae,0x00,0x00,0xa2,0xa4,0xd3,0x0a,0x00,0x0c,0x00,0x00,0x00,0x00,
-0x00,0x00,0x55,0xae,0x00,0x00,0x16,0xae,0x00,0x00,0x71,0xae,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x2c,0x00,0xbf,0x8f,0x28,0x00,0xb6,0x8f,
-0x24,0x00,0xb5,0x8f,0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,
-0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,
-0xd0,0xff,0xbd,0x27,0x2c,0x00,0xbf,0xaf,0x28,0x00,0xb6,0xaf,0x24,0x00,0xb5,0xaf,
-0x20,0x00,0xb4,0xaf,0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf,0x14,0x00,0xb1,0xaf,
-0x10,0x00,0xb0,0xaf,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,
-0x00,0x60,0x81,0x40,0x25,0xb0,0x10,0x3c,0x40,0x00,0x05,0x36,0x00,0x00,0xa2,0x94,
-0xaf,0xff,0x03,0x24,0xa8,0x00,0x13,0x36,0x24,0x10,0x43,0x00,0x00,0x00,0xa2,0xa4,
-0xa0,0x00,0x12,0x36,0xa4,0x00,0x10,0x36,0x00,0x00,0x55,0x8e,0x00,0x00,0x16,0x8e,
-0x00,0x00,0x71,0x8e,0x00,0x80,0x14,0x3c,0xfc,0x37,0x02,0x24,0x00,0x00,0x40,0xae,
-0xfd,0x00,0x04,0x24,0x00,0x00,0x00,0xae,0x21,0x88,0x34,0x02,0x00,0x00,0x74,0xae,
-0x00,0x00,0xa2,0xa4,0xd3,0x0a,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xae,
-0x00,0x00,0x16,0xae,0x00,0x00,0x71,0xae,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x00,0x60,0x81,0x40,0x2c,0x00,0xbf,0x8f,0x28,0x00,0xb6,0x8f,0x24,0x00,0xb5,0x8f,
-0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x25,0xb0,0x04,0x3c,
-0x40,0x00,0x84,0x34,0x00,0x00,0x82,0x94,0xd8,0xfd,0x03,0x24,0x24,0x10,0x43,0x00,
-0xfc,0x37,0x03,0x24,0x00,0x00,0x82,0xa4,0x00,0x00,0x83,0xa4,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x00,0x00,0x82,0x8c,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x30,
-0x10,0x00,0x02,0x24,0x0c,0x00,0xc2,0x10,0x11,0x00,0xc3,0x28,0x06,0x00,0x60,0x10,
-0x20,0x00,0x02,0x24,0x08,0x00,0x02,0x24,0x0d,0x00,0xc2,0x10,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x06,0x00,0xc2,0x10,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xa4,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xac,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x00,0x00,0x85,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,
-0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x25,0xb0,0x02,0x3c,
-0x0a,0x00,0x42,0x34,0x00,0x00,0x43,0x90,0xff,0xff,0xa5,0x24,0x00,0x2c,0x05,0x00,
-0xfd,0x00,0x63,0x30,0x03,0x2c,0x05,0x00,0xff,0xff,0x87,0x30,0x00,0x00,0x43,0xa0,
-0x1a,0x00,0xa0,0x04,0x00,0x00,0x00,0x00,0x21,0x30,0x40,0x00,0x07,0x10,0xa7,0x00,
-0x01,0x00,0x42,0x30,0xfd,0x00,0x64,0x30,0x00,0x00,0x42,0x38,0x02,0x00,0x63,0x34,
-0x0a,0x18,0x82,0x00,0x00,0x00,0xc3,0xa0,0x04,0x00,0x63,0x34,0x00,0x00,0xc3,0xa0,
-0x09,0x00,0x02,0x24,0xff,0xff,0x42,0x24,0xff,0xff,0x41,0x04,0xff,0xff,0x42,0x24,
-0xfb,0x00,0x63,0x30,0x00,0x00,0xc3,0xa0,0x04,0x00,0x02,0x24,0xff,0xff,0x42,0x24,
-0xff,0xff,0x41,0x04,0xff,0xff,0x42,0x24,0xff,0xff,0xa2,0x24,0x00,0x2c,0x02,0x00,
-0x03,0x2c,0x05,0x00,0xea,0xff,0xa1,0x04,0x07,0x10,0xa7,0x00,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x25,0xb0,0x02,0x3c,0x0a,0x00,0x42,0x34,0x00,0x00,0x43,0x90,
-0xff,0xff,0x84,0x24,0x00,0x24,0x04,0x00,0x03,0x24,0x04,0x00,0xff,0x00,0x65,0x30,
-0x1d,0x00,0x80,0x04,0x21,0x38,0x00,0x00,0x21,0x30,0x40,0x00,0x01,0x00,0x08,0x24,
-0x04,0x00,0xa5,0x34,0x00,0x00,0xc5,0xa0,0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00,
-0xff,0x00,0x45,0x30,0x01,0x00,0xa3,0x30,0x05,0x00,0x60,0x10,0x04,0x00,0x02,0x24,
-0x04,0x10,0x88,0x00,0x25,0x10,0x47,0x00,0xff,0xff,0x47,0x30,0x04,0x00,0x02,0x24,
-0xff,0xff,0x42,0x24,0xff,0xff,0x41,0x04,0xff,0xff,0x42,0x24,0xfb,0x00,0xa5,0x30,
-0x00,0x00,0xc5,0xa0,0x09,0x00,0x02,0x24,0xff,0xff,0x42,0x24,0xff,0xff,0x41,0x04,
-0xff,0xff,0x42,0x24,0xff,0xff,0x82,0x24,0x00,0x24,0x02,0x00,0x03,0x24,0x04,0x00,
-0xe7,0xff,0x81,0x04,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0xe0,0x00,
-0xe0,0xff,0xbd,0x27,0x10,0x00,0xb0,0xaf,0x25,0xb0,0x10,0x3c,0x0a,0x00,0x10,0x36,
-0x18,0x00,0xbf,0xaf,0x14,0x00,0xb1,0xaf,0x00,0x00,0x02,0x92,0xff,0xff,0x91,0x30,
-0x03,0x00,0x05,0x24,0xc0,0x00,0x42,0x30,0x80,0x00,0x43,0x34,0x00,0x00,0x03,0xa2,
-0x04,0x00,0x63,0x34,0x00,0x00,0x03,0xa2,0xfb,0x00,0x63,0x30,0x00,0x00,0x03,0xa2,
-0x08,0x00,0x63,0x34,0x00,0x00,0x03,0xa2,0x04,0x00,0x63,0x34,0x00,0x00,0x03,0xa2,
-0xfb,0x00,0x63,0x30,0x00,0x00,0x03,0xa2,0xd7,0x0b,0x00,0x0c,0x06,0x00,0x04,0x24,
-0x42,0x20,0x11,0x00,0xd7,0x0b,0x00,0x0c,0x06,0x00,0x05,0x24,0xfd,0x0b,0x00,0x0c,
-0x10,0x00,0x04,0x24,0x00,0x00,0x03,0x92,0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,
-0xc0,0x00,0x63,0x30,0x00,0x00,0x03,0xa2,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,
-0x20,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf,0xff,0xff,0xb1,0x30,
-0x18,0x00,0xb2,0xaf,0x10,0x00,0xb0,0xaf,0x1c,0x00,0xbf,0xaf,0x21,0x90,0xc0,0x00,
-0x0a,0x00,0x20,0x12,0xff,0xff,0x90,0x30,0x24,0x0c,0x00,0x0c,0x21,0x20,0x00,0x02,
-0xfe,0xff,0x23,0x26,0x02,0x00,0x04,0x26,0x00,0x00,0x42,0xa6,0xff,0xff,0x71,0x30,
-0xff,0xff,0x90,0x30,0xf8,0xff,0x20,0x16,0x02,0x00,0x52,0x26,0x1c,0x00,0xbf,0x8f,
-0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,
-0x20,0x00,0xbd,0x27,0x25,0xb0,0x03,0x3c,0x0a,0x00,0x68,0x34,0x00,0x00,0x02,0x91,
-0xff,0xff,0xa5,0x30,0xff,0x00,0x84,0x30,0x1f,0x00,0xa0,0x10,0xff,0x00,0x47,0x30,
-0x21,0x48,0x00,0x01,0x0c,0x00,0x6c,0x34,0x0b,0x00,0x6b,0x34,0xc0,0xff,0x0a,0x24,
-0x21,0x68,0x00,0x01,0x25,0x10,0xea,0x00,0xff,0x00,0x47,0x30,0x00,0x00,0x64,0xa1,
-0x00,0x00,0x27,0xa1,0x00,0x00,0x22,0x91,0x00,0x00,0x00,0x00,0xff,0x00,0x47,0x30,
-0xc0,0x00,0xe3,0x30,0x08,0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x21,0x40,0xa0,0x01,
-0x00,0x00,0x02,0x91,0x00,0x00,0x00,0x00,0xff,0x00,0x47,0x30,0xc0,0x00,0xe3,0x30,
-0xfb,0xff,0x60,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x8d,0xfc,0xff,0xa3,0x24,
-0x04,0x00,0x84,0x24,0xff,0xff,0x65,0x30,0x00,0x00,0xc2,0xac,0xff,0x00,0x84,0x30,
-0xe8,0xff,0xa0,0x14,0x04,0x00,0xc6,0x24,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0xff,0x00,0x84,0x30,0x21,0x68,0xe0,0x00,0xff,0xff,0xa5,0x30,0xc0,0x50,0x04,0x00,
-0x00,0x60,0x0c,0x40,0x01,0x00,0x81,0x35,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x00,0x00,0xc2,0x90,0x01,0x00,0xc3,0x90,0x25,0xb0,0x07,0x3c,0x00,0x14,0x02,0x00,
-0x25,0x28,0xa2,0x00,0x00,0x1e,0x03,0x00,0x01,0x80,0x08,0x3c,0x25,0x20,0xa3,0x00,
-0x40,0x02,0xe9,0x34,0x25,0x18,0x48,0x01,0x44,0x02,0xe7,0x34,0x00,0x00,0xe4,0xac,
-0x00,0x00,0x23,0xad,0x03,0x00,0xc2,0x90,0x02,0x00,0xc4,0x90,0x04,0x00,0xc3,0x90,
-0x05,0x00,0xc5,0x90,0x00,0x12,0x02,0x00,0x25,0x20,0x82,0x00,0x00,0x1c,0x03,0x00,
-0x01,0x00,0x4a,0x25,0x25,0x20,0x83,0x00,0x00,0x2e,0x05,0x00,0x25,0x40,0x48,0x01,
-0x25,0x20,0x85,0x00,0x00,0x00,0xe4,0xac,0x01,0x00,0x4a,0x25,0x00,0x00,0x28,0xad,
-0x01,0x80,0x0b,0x3c,0x21,0x40,0x00,0x00,0x21,0x10,0xa8,0x01,0x01,0x00,0x43,0x90,
-0x00,0x00,0x45,0x90,0x02,0x00,0x44,0x90,0x03,0x00,0x46,0x90,0x00,0x1a,0x03,0x00,
-0x25,0x28,0xa3,0x00,0x00,0x24,0x04,0x00,0x25,0x28,0xa4,0x00,0x00,0x36,0x06,0x00,
-0x04,0x00,0x08,0x25,0x25,0x10,0x4b,0x01,0x25,0x20,0xa6,0x00,0x10,0x00,0x03,0x2d,
-0x00,0x00,0xe4,0xac,0x01,0x00,0x4a,0x25,0x00,0x00,0x22,0xad,0xee,0xff,0x60,0x14,
-0x00,0x00,0x00,0x00,0x00,0x60,0x8c,0x40,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0xff,0xff,0x84,0x30,0x42,0xb0,0x08,0x3c,0x80,0x10,0x04,0x00,0x21,0x10,0x48,0x00,
-0x04,0x00,0x46,0xac,0x00,0x00,0x07,0x91,0x40,0x18,0x04,0x00,0x03,0x00,0x06,0x24,
-0xff,0x00,0xe7,0x30,0x04,0x30,0x66,0x00,0x01,0x00,0x02,0x24,0x04,0x10,0x62,0x00,
-0x25,0x30,0xc7,0x00,0xff,0xff,0xa5,0x30,0x25,0x10,0x47,0x00,0x02,0x00,0xa0,0x14,
-0xff,0x00,0xc7,0x30,0xff,0x00,0x47,0x30,0x42,0xb0,0x02,0x3c,0x00,0x00,0x47,0xa0,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x42,0xb0,0x02,0x3c,0x03,0x00,0x47,0x34,
-0x00,0x00,0xe3,0x90,0xff,0x00,0x84,0x30,0x04,0x00,0x84,0x24,0xff,0x00,0x65,0x30,
-0x01,0x00,0x02,0x24,0x04,0x30,0x82,0x00,0x07,0x18,0x85,0x00,0x25,0xb0,0x02,0x3c,
-0xe8,0x03,0x42,0x34,0x01,0x00,0x63,0x30,0x21,0x20,0xc0,0x00,0x00,0x00,0x45,0xa0,
-0x02,0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0xe6,0xa0,0x08,0x00,0xe0,0x03,
-0x24,0x10,0x85,0x00,0x00,0x60,0x03,0x40,0x01,0x00,0x61,0x34,0x01,0x00,0x21,0x38,
-0x00,0x60,0x81,0x40,0x02,0x80,0x02,0x3c,0xdc,0x8c,0x42,0x24,0x04,0x00,0x45,0x8c,
-0x00,0x00,0x82,0xac,0x04,0x00,0x44,0xac,0x00,0x00,0xa4,0xac,0x04,0x00,0x85,0xac,
-0x00,0x60,0x83,0x40,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x14,0x00,0x83,0x90,
-0x01,0x00,0x02,0x24,0x08,0x00,0x86,0xac,0x18,0x00,0x85,0xac,0x00,0x00,0x84,0xac,
-0x03,0x00,0x62,0x10,0x04,0x00,0x84,0xac,0xed,0x0c,0x00,0x08,0x0c,0x00,0x80,0xac,
-0x0c,0x00,0x82,0x8c,0xed,0x0c,0x00,0x08,0x10,0x00,0x82,0xac,0x00,0x60,0x03,0x40,
-0x01,0x00,0x61,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x04,0x00,0x85,0x8c,
-0x00,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0xac,0x04,0x00,0x45,0xac,
-0x00,0x00,0x84,0xac,0x04,0x00,0x84,0xac,0x00,0x60,0x83,0x40,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0xd0,0xff,0xbd,0x27,0x28,0x00,0xb6,0xaf,0x24,0x00,0xb5,0xaf,
-0x20,0x00,0xb4,0xaf,0x14,0x00,0xb1,0xaf,0x2c,0x00,0xbf,0xaf,0x1c,0x00,0xb3,0xaf,
-0x18,0x00,0xb2,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x80,0x16,0x3c,0x02,0x80,0x14,0x3c,
-0x02,0x80,0x11,0x3c,0x02,0x80,0x15,0x3c,0xc4,0x7d,0x24,0x8e,0x25,0xb0,0x02,0x3c,
-0x54,0x34,0xc3,0x26,0x18,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0xdc,0x8c,0x90,0x8e,
-0x18,0x00,0x80,0x10,0xdc,0x8c,0x82,0x26,0x15,0x00,0x02,0x12,0x00,0x00,0x00,0x00,
-0x21,0x98,0x40,0x00,0x01,0x00,0x12,0x24,0x14,0x00,0x02,0x92,0x00,0x00,0x00,0x00,
-0x1d,0x00,0x52,0x10,0x00,0x00,0x00,0x00,0x09,0x00,0x40,0x14,0x00,0x00,0x00,0x00,
-0x0c,0x00,0x03,0x8e,0xc4,0x7d,0x22,0x8e,0x00,0x00,0x00,0x00,0x23,0x20,0x62,0x00,
-0x2b,0x10,0x43,0x00,0x0e,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0xae,
-0x00,0x00,0x10,0x8e,0x00,0x00,0x00,0x00,0xef,0xff,0x13,0x16,0x00,0x00,0x00,0x00,
-0xc4,0x7d,0x20,0xae,0x08,0x0c,0xa4,0x26,0x21,0x28,0x00,0x00,0x21,0x30,0x00,0x00,
-0x31,0x1c,0x00,0x0c,0x21,0x38,0x00,0x00,0x22,0x0d,0x00,0x08,0x00,0x00,0x00,0x00,
-0x08,0x00,0x02,0x8e,0x18,0x00,0x04,0x8e,0x09,0xf8,0x40,0x00,0x00,0x00,0x00,0x00,
-0x3c,0x0d,0x00,0x08,0x0c,0x00,0x02,0xae,0x0c,0x00,0x03,0x8e,0xc4,0x7d,0x22,0x8e,
-0x00,0x00,0x00,0x00,0x23,0x20,0x62,0x00,0x2b,0x10,0x43,0x00,0xe7,0xff,0x40,0x14,
-0x00,0x00,0x00,0x00,0x08,0x00,0x02,0x8e,0x18,0x00,0x04,0x8e,0x09,0xf8,0x40,0x00,
-0x00,0x00,0x00,0x00,0x10,0x00,0x03,0x8e,0x3c,0x0d,0x00,0x08,0x0c,0x00,0x03,0xae,
-0xff,0x00,0xa5,0x30,0x25,0xb0,0x02,0x3c,0x21,0x28,0xa2,0x00,0xff,0x00,0x84,0x30,
-0x60,0x01,0xa4,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xff,0x00,0x84,0x30,
-0x01,0x00,0x03,0x24,0x10,0x00,0x02,0x3c,0x04,0x18,0x83,0x00,0xf0,0x70,0x42,0x34,
-0x15,0x00,0x84,0x2c,0x06,0x00,0x80,0x10,0x24,0x28,0x62,0x00,0x0f,0x00,0x63,0x30,
-0x04,0x00,0xa0,0x14,0x01,0x00,0x02,0x24,0x02,0x00,0x60,0x14,0x02,0x00,0x02,0x24,
-0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xff,0x00,0xa5,0x30,
-0x04,0x00,0xa2,0x2c,0x14,0x00,0x40,0x10,0xff,0x00,0x84,0x30,0x02,0x80,0x03,0x3c,
-0x8e,0x7d,0x62,0x90,0x00,0x00,0x00,0x00,0xef,0xff,0x42,0x24,0xff,0x00,0x42,0x30,
-0x02,0x00,0x42,0x2c,0x0e,0x00,0x40,0x10,0x02,0x00,0x03,0x24,0x24,0x00,0x83,0x10,
-0x0f,0x10,0x02,0x3c,0x03,0x00,0x82,0x28,0x14,0x00,0x40,0x10,0x03,0x00,0x02,0x24,
-0x01,0x00,0x02,0x24,0x2f,0x00,0x82,0x10,0x00,0x00,0x00,0x00,0xff,0x1f,0x02,0x3c,
-0x08,0x00,0xe0,0x03,0xff,0xff,0x42,0x34,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x35,0x00,0x83,0x10,0x0f,0x1f,0x02,0x3c,0x03,0x00,0x82,0x28,0x16,0x00,0x40,0x10,
-0x03,0x00,0x02,0x24,0x01,0x00,0x02,0x24,0xf4,0xff,0x82,0x14,0x00,0x00,0x00,0x00,
-0x0f,0x1f,0x02,0x3c,0x08,0x00,0xe0,0x03,0x00,0x80,0x42,0x34,0xf0,0xff,0x82,0x14,
-0xff,0x1f,0x02,0x3c,0x01,0x00,0x02,0x24,0x29,0x00,0xa2,0x10,0x0f,0x10,0x02,0x3c,
-0x02,0x00,0xa2,0x28,0x1f,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0x28,0x00,0xa3,0x10,
-0x00,0x00,0x00,0x00,0xe5,0xff,0xa4,0x14,0x00,0x00,0x00,0x00,0x0f,0x10,0x02,0x3c,
-0x08,0x00,0xe0,0x03,0x00,0xf0,0x42,0x34,0xe1,0xff,0x82,0x14,0xff,0x1f,0x02,0x3c,
-0x01,0x00,0x02,0x24,0x1c,0x00,0xa2,0x10,0x0f,0x00,0x02,0x3c,0x02,0x00,0xa2,0x28,
-0x0b,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0x1c,0x00,0xa3,0x10,0x00,0x00,0x00,0x00,
-0xd6,0xff,0xa4,0x14,0x00,0x00,0x00,0x00,0x0f,0x00,0x02,0x3c,0x08,0x00,0xe0,0x03,
-0x00,0xf0,0x42,0x34,0x0f,0x10,0x02,0x3c,0x08,0x00,0xe0,0x03,0x00,0x80,0x42,0x34,
-0xce,0xff,0xa0,0x14,0x00,0x00,0x00,0x00,0x0f,0x00,0x02,0x3c,0x08,0x00,0xe0,0x03,
-0x15,0xf0,0x42,0x34,0xc9,0xff,0xa0,0x14,0x00,0x00,0x00,0x00,0x0f,0x10,0x02,0x3c,
-0x08,0x00,0xe0,0x03,0x15,0xf0,0x42,0x34,0x08,0x00,0xe0,0x03,0x00,0xf0,0x42,0x34,
-0x08,0x00,0xe0,0x03,0x10,0xf0,0x42,0x34,0x08,0x00,0xe0,0x03,0x10,0xf0,0x42,0x34,
-0x0f,0x10,0x02,0x3c,0x08,0x00,0xe0,0x03,0x05,0xf0,0x42,0x34,0x0f,0x00,0x02,0x3c,
-0x08,0x00,0xe0,0x03,0x05,0xf0,0x42,0x34,0xc0,0x40,0x04,0x00,0x21,0x18,0x04,0x01,
-0x80,0x18,0x03,0x00,0x21,0x18,0x64,0x00,0x02,0x80,0x02,0x3c,0x80,0x18,0x03,0x00,
-0x68,0x15,0x42,0x24,0x21,0x18,0x62,0x00,0x74,0x51,0x66,0x8c,0x21,0x38,0x60,0x00,
-0x7a,0x51,0x60,0xa0,0x7b,0x51,0x60,0xa0,0x1c,0x00,0x05,0x24,0xdf,0x0d,0x00,0x08,
-0x01,0x00,0x03,0x24,0x08,0x00,0xa0,0x04,0x21,0x10,0x04,0x01,0x04,0x10,0xa3,0x00,
-0x24,0x10,0xc2,0x00,0xfb,0xff,0x40,0x10,0xff,0xff,0xa5,0x24,0x01,0x00,0xa5,0x24,
-0x7a,0x51,0xe5,0xa0,0x21,0x10,0x04,0x01,0x80,0x10,0x02,0x00,0x21,0x10,0x44,0x00,
-0x02,0x80,0x03,0x3c,0x80,0x10,0x02,0x00,0x68,0x15,0x63,0x24,0x21,0x18,0x43,0x00,
-0x74,0x51,0x66,0x8c,0x21,0x28,0x00,0x00,0xf3,0x0d,0x00,0x08,0x01,0x00,0x07,0x24,
-0x1d,0x00,0xa2,0x28,0x08,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x04,0x10,0xa7,0x00,
-0x24,0x10,0xc2,0x00,0xfa,0xff,0x40,0x10,0x01,0x00,0xa5,0x24,0xff,0xff,0xa5,0x24,
-0x08,0x00,0xe0,0x03,0x7b,0x51,0x65,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0xc8,0xff,0xbd,0x27,0x28,0x00,0xb6,0xaf,0x02,0x80,0x16,0x3c,0x30,0x00,0xbe,0xaf,
-0x2c,0x00,0xb7,0xaf,0x24,0x00,0xb5,0xaf,0x20,0x00,0xb4,0xaf,0x18,0x00,0xb2,0xaf,
-0x14,0x00,0xb1,0xaf,0x01,0x00,0x15,0x24,0x21,0x88,0x00,0x00,0x68,0x15,0xde,0x26,
-0x21,0xa0,0x00,0x00,0x21,0x90,0x00,0x00,0x25,0xb0,0x17,0x3c,0x34,0x00,0xbf,0xaf,
-0x1c,0x00,0xb3,0xaf,0x14,0x0e,0x00,0x08,0x10,0x00,0xb0,0xaf,0x01,0x00,0x31,0x26,
-0x20,0x00,0x22,0x2e,0x94,0x00,0x52,0x26,0x2e,0x00,0x40,0x10,0x94,0x00,0x94,0x26,
-0x68,0x15,0xc2,0x26,0x21,0x30,0x42,0x02,0x78,0x51,0xc5,0x8c,0x00,0x00,0x00,0x00,
-0x02,0x13,0x05,0x00,0x01,0x00,0x42,0x30,0xf4,0xff,0x55,0x14,0x42,0x1a,0x05,0x00,
-0x68,0x51,0xc2,0x8c,0x07,0x00,0x64,0x30,0x02,0x11,0x02,0x00,0x7f,0x00,0x43,0x30,
-0x2d,0x00,0x95,0x10,0x07,0x00,0xb3,0x30,0x02,0x00,0x82,0x28,0x3a,0x00,0x40,0x14,
-0x02,0x00,0x02,0x24,0x30,0x00,0x82,0x10,0x03,0x00,0x02,0x24,0x3c,0x00,0x82,0x10,
-0x1a,0x00,0x62,0x2c,0x21,0x80,0x9e,0x02,0x78,0x51,0x02,0x8e,0x04,0x00,0x63,0x2e,
-0x42,0x12,0x02,0x00,0x0a,0x00,0x60,0x10,0x07,0x00,0x44,0x30,0x73,0x0d,0x00,0x0c,
-0x21,0x28,0x60,0x02,0x80,0x20,0x13,0x00,0x70,0x51,0x02,0xae,0x21,0x20,0x97,0x00,
-0x84,0x01,0x83,0x8c,0x00,0x00,0x00,0x00,0x24,0x18,0x62,0x00,0x74,0x51,0x03,0xae,
-0xce,0x0d,0x00,0x0c,0x21,0x20,0x20,0x02,0x21,0x10,0x37,0x02,0x01,0x00,0x31,0x26,
-0x60,0x01,0x43,0x90,0x20,0x00,0x22,0x2e,0x94,0x00,0x52,0x26,0xd4,0xff,0x40,0x14,
-0x94,0x00,0x94,0x26,0x34,0x00,0xbf,0x8f,0x30,0x00,0xbe,0x8f,0x2c,0x00,0xb7,0x8f,
-0x28,0x00,0xb6,0x8f,0x24,0x00,0xb5,0x8f,0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f,
-0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27,0x32,0x00,0x62,0x2c,0xda,0xff,0x40,0x10,
-0x21,0x80,0x9e,0x02,0xff,0xf1,0x03,0x24,0x24,0x10,0xa3,0x00,0x00,0x04,0x42,0x34,
-0x29,0x0e,0x00,0x08,0x78,0x51,0xc2,0xac,0x38,0x00,0x62,0x2c,0x12,0x00,0x40,0x14,
-0x14,0x00,0x62,0x2c,0xff,0xf1,0x03,0x24,0x24,0x10,0xa3,0x00,0x00,0x02,0x42,0x34,
-0x29,0x0e,0x00,0x08,0x78,0x51,0xc2,0xac,0xcb,0xff,0x80,0x14,0x21,0x80,0x9e,0x02,
-0xff,0xf1,0x03,0x24,0x24,0x10,0xa3,0x00,0x2a,0x0e,0x00,0x08,0x78,0x51,0xc2,0xac,
-0xc5,0xff,0x40,0x14,0x21,0x80,0x9e,0x02,0xff,0xf1,0x03,0x24,0x24,0x10,0xa3,0x00,
-0x54,0x0e,0x00,0x08,0x00,0x04,0x42,0x34,0xbf,0xff,0x40,0x10,0x21,0x80,0x9e,0x02,
-0xff,0xf1,0x03,0x24,0x24,0x10,0xa3,0x00,0x00,0x06,0x42,0x34,0x2a,0x0e,0x00,0x08,
-0x78,0x51,0xc2,0xac,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xd8,0xff,0xbd,0x27,
-0x10,0x00,0xb0,0xaf,0xc0,0x80,0x04,0x00,0x21,0x80,0x04,0x02,0x80,0x80,0x10,0x00,
-0x21,0x80,0x04,0x02,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,0x80,0x80,0x10,0x00,
-0x20,0x00,0xbf,0xaf,0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf,0x21,0x80,0x02,0x02,
-0x14,0x00,0xb1,0xaf,0x78,0x51,0x03,0x8e,0x25,0xb0,0x02,0x3c,0x80,0x01,0x53,0x34,
-0x07,0x00,0x63,0x30,0x80,0x18,0x03,0x00,0x21,0x18,0x62,0x00,0x00,0x00,0x71,0x92,
-0x70,0x51,0x05,0x8e,0x84,0x01,0x62,0x8c,0x21,0x90,0x80,0x00,0xff,0x00,0x31,0x32,
-0x24,0x10,0x45,0x00,0xce,0x0d,0x00,0x0c,0x74,0x51,0x02,0xae,0x7a,0x51,0x04,0x92,
-0x5c,0x0d,0x00,0x0c,0xff,0x00,0x45,0x32,0x7a,0x51,0x04,0x92,0x63,0x0d,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x38,0x04,0x00,0x03,0x24,0x0a,0x88,0x62,0x00,
-0x00,0x00,0x71,0xa2,0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,
-0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x28,0x00,0xbd,0x27,
-0xff,0xff,0x84,0x30,0x00,0x02,0x82,0x30,0x07,0x00,0x03,0x24,0x0d,0x00,0x40,0x14,
-0x0b,0x00,0x84,0x30,0x0c,0x00,0x82,0x2c,0x0a,0x00,0x40,0x10,0x00,0x00,0x00,0x00,
-0x02,0x80,0x03,0x3c,0x80,0x10,0x04,0x00,0xf0,0x91,0x63,0x24,0x21,0x10,0x43,0x00,
-0x00,0x00,0x44,0x8c,0x00,0x00,0x00,0x00,0x08,0x00,0x80,0x00,0x00,0x00,0x00,0x00,
-0x07,0x00,0x03,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,0x06,0x00,0x03,0x24,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,0x05,0x00,0x03,0x24,0x08,0x00,0xe0,0x03,
-0x21,0x10,0x60,0x00,0x04,0x00,0x03,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,
-0x03,0x00,0x03,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,0x02,0x00,0x03,0x24,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,0x01,0x00,0x03,0x24,0x08,0x00,0xe0,0x03,
-0x21,0x10,0x60,0x00,0x21,0x18,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,
-0xa0,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c,0x58,0x00,0xbe,0xaf,0x54,0x00,0xb7,0xaf,
-0x50,0x00,0xb6,0xaf,0x4c,0x00,0xb5,0xaf,0x48,0x00,0xb4,0xaf,0x40,0x00,0xb2,0xaf,
-0x3c,0x00,0xb1,0xaf,0x5c,0x00,0xbf,0xaf,0x44,0x00,0xb3,0xaf,0x38,0x00,0xb0,0xaf,
-0x20,0x92,0x42,0x24,0x00,0x00,0x53,0x8c,0x08,0x00,0x03,0x24,0x02,0x80,0x0b,0x3c,
-0x21,0x90,0x00,0x00,0x21,0xa0,0x00,0x00,0x21,0xb8,0x00,0x00,0x21,0xf0,0x00,0x00,
-0x21,0xa8,0x00,0x00,0x21,0xb0,0x00,0x00,0x21,0x88,0x60,0x02,0x10,0x00,0xa3,0xaf,
-0x14,0x00,0xa0,0xaf,0x18,0x00,0xa0,0xaf,0x1c,0x00,0xa0,0xaf,0x20,0x00,0xa0,0xaf,
-0x24,0x00,0xa0,0xaf,0x28,0x00,0xa0,0xaf,0x7a,0x0f,0x00,0x08,0x2c,0x00,0xa0,0xaf,
-0x44,0x51,0x22,0xae,0x60,0x51,0x24,0x8e,0x5c,0x51,0x27,0x8e,0x48,0x51,0x28,0x8e,
-0x4c,0x51,0x25,0x8e,0x54,0x51,0x26,0x8e,0x58,0x51,0x23,0x8e,0x21,0x38,0xe4,0x00,
-0x02,0x80,0x04,0x3c,0x68,0x15,0x84,0x24,0x21,0x10,0x04,0x02,0x21,0x40,0x05,0x01,
-0x21,0x30,0xc3,0x00,0xca,0x44,0x42,0x90,0x44,0x51,0x2a,0x8e,0x0c,0x00,0xe0,0x10,
-0x21,0x48,0x00,0x00,0x2b,0x48,0x47,0x00,0x0b,0x00,0x20,0x15,0x02,0x80,0x02,0x3c,
-0x07,0x00,0x02,0x2e,0x59,0x01,0x40,0x14,0xc0,0x10,0x07,0x00,0x0c,0x00,0x02,0x24,
-0x55,0x01,0x02,0x12,0x0d,0x00,0x02,0x24,0x54,0x01,0x02,0x12,0xc0,0x10,0x07,0x00,
-0x92,0x00,0x20,0x11,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,0x80,0x18,0x10,0x00,
-0x21,0x18,0x62,0x00,0x21,0x20,0x30,0x02,0xb6,0x51,0x85,0x90,0xec,0x44,0x62,0x8c,
-0x00,0x00,0x00,0x00,0x04,0x10,0xa2,0x00,0x2b,0x10,0x4a,0x00,0x87,0x00,0x40,0x10,
-0x00,0x00,0x00,0x00,0xd4,0x51,0x22,0x8e,0x01,0x00,0x07,0x24,0x04,0x18,0x07,0x02,
-0x24,0x10,0x43,0x00,0xf0,0x00,0x40,0x10,0x1c,0x00,0x02,0x2e,0x21,0x28,0x30,0x02,
-0x7c,0x51,0xa6,0x90,0xb6,0x51,0xa2,0x90,0x0a,0x00,0x04,0x24,0xff,0x00,0xc3,0x30,
-0x04,0x20,0x44,0x00,0x2a,0x18,0x64,0x00,0xe7,0x00,0x60,0x10,0x1c,0x00,0x02,0x2e,
-0x01,0x00,0xc2,0x24,0xff,0x00,0x43,0x30,0x56,0x01,0x64,0x10,0x7c,0x51,0xa2,0xa0,
-0x68,0x15,0x65,0x25,0x80,0x10,0x10,0x00,0x21,0x10,0x45,0x00,0x60,0x45,0x44,0x8c,
-0xec,0x44,0x43,0x8c,0x21,0x30,0xc5,0x02,0x40,0x10,0x04,0x00,0x21,0x10,0x44,0x00,
-0x21,0x18,0x62,0x00,0x82,0x50,0x03,0x00,0x44,0x51,0xca,0xac,0x8c,0x65,0xa3,0x8c,
-0xff,0xff,0x02,0x34,0x07,0x00,0x62,0x10,0x21,0x20,0x00,0x02,0x21,0x20,0x00,0x02,
-0xff,0x00,0x45,0x32,0x5c,0x0d,0x00,0x0c,0x30,0x00,0xab,0xaf,0x30,0x00,0xab,0x8f,
-0x21,0x20,0x00,0x02,0x63,0x0d,0x00,0x0c,0x30,0x00,0xab,0xaf,0x10,0x00,0xa4,0x8f,
-0x01,0x00,0x42,0x38,0x04,0x00,0x03,0x24,0x0a,0x20,0x62,0x00,0x10,0x00,0xa4,0xaf,
-0x30,0x00,0xab,0x8f,0x11,0x00,0x40,0x16,0x68,0x15,0x62,0x25,0x58,0x51,0x47,0x8c,
-0x54,0x51,0x43,0x8c,0x4c,0x51,0x44,0x94,0x48,0x51,0x45,0x94,0x50,0x51,0x46,0x94,
-0x21,0x18,0x67,0x00,0x00,0x24,0x04,0x00,0x25,0xb0,0x02,0x3c,0x00,0x1c,0x03,0x00,
-0x21,0x28,0xa4,0x00,0x21,0x30,0xc3,0x00,0x6c,0x0c,0x44,0x34,0x68,0x0c,0x42,0x34,
-0x00,0x00,0x45,0xac,0x00,0x00,0x86,0xac,0x68,0x15,0x62,0x25,0x21,0x10,0x82,0x02,
-0x58,0x51,0x40,0xac,0x5c,0x51,0x40,0xac,0x60,0x51,0x40,0xac,0x48,0x51,0x40,0xac,
-0x4c,0x51,0x40,0xac,0x50,0x51,0x40,0xac,0x54,0x51,0x40,0xac,0x2c,0x00,0xa2,0x8f,
-0x28,0x00,0xa4,0x8f,0x01,0x00,0x52,0x26,0x94,0x00,0x42,0x24,0x2c,0x00,0xa2,0xaf,
-0x24,0x00,0xa2,0x8f,0x94,0x00,0x84,0x24,0x28,0x00,0xa4,0xaf,0x94,0x00,0x42,0x24,
-0x20,0x00,0xa4,0x8f,0x24,0x00,0xa2,0xaf,0x1c,0x00,0xa2,0x8f,0x94,0x00,0x84,0x24,
-0x20,0x00,0xa4,0xaf,0x94,0x00,0x42,0x24,0x18,0x00,0xa4,0x8f,0x1c,0x00,0xa2,0xaf,
-0x14,0x00,0xa2,0x8f,0x94,0x00,0x84,0x24,0x20,0x00,0x43,0x2a,0x94,0x00,0x42,0x24,
-0x94,0x00,0x31,0x26,0x94,0x00,0xd6,0x26,0x94,0x00,0xb5,0x26,0x18,0x00,0xa4,0xaf,
-0x14,0x00,0xa2,0xaf,0x94,0x00,0xde,0x27,0x94,0x00,0x73,0x26,0x94,0x00,0xf7,0x26,
-0xe5,0x00,0x60,0x10,0x94,0x00,0x94,0x26,0x78,0x51,0x22,0x8e,0x00,0x00,0x00,0x00,
-0x02,0x13,0x02,0x00,0x01,0x00,0x42,0x30,0xd3,0xff,0x40,0x10,0x25,0xb0,0x02,0x3c,
-0x21,0x10,0x42,0x02,0x60,0x01,0x44,0x90,0x60,0x51,0x23,0x8e,0x5c,0x51,0x26,0x8e,
-0xff,0x00,0x90,0x30,0x02,0x80,0x04,0x3c,0x68,0x15,0x84,0x24,0x21,0x10,0x04,0x02,
-0x73,0x44,0x44,0x90,0x56,0x44,0x45,0x90,0x44,0x51,0x27,0x8e,0x18,0x00,0x64,0x00,
-0x12,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xc5,0x00,
-0x12,0x30,0x00,0x00,0x21,0x30,0xc3,0x00,0x2b,0x10,0xe6,0x00,0x54,0xff,0x40,0x10,
-0x23,0x10,0xe6,0x00,0xe9,0x0e,0x00,0x08,0x44,0x51,0x20,0xae,0x62,0x00,0xe0,0x10,
-0x00,0x00,0x00,0x00,0x63,0x00,0x20,0x15,0x68,0x15,0x62,0x25,0x40,0x10,0x07,0x00,
-0x21,0x10,0x47,0x00,0x82,0x10,0x02,0x00,0x2b,0x10,0x46,0x00,0x99,0xff,0x40,0x10,
-0x21,0x20,0x00,0x02,0x68,0x15,0x68,0x25,0x21,0x20,0xa8,0x02,0x21,0x30,0x90,0x00,
-0xd4,0x51,0x83,0x8c,0x01,0x00,0x05,0x24,0x04,0x10,0x05,0x02,0x99,0x51,0xc7,0x90,
-0x27,0x10,0x02,0x00,0x24,0x18,0x62,0x00,0xd4,0x51,0x83,0xac,0x09,0x00,0xe5,0x10,
-0x7c,0x51,0xc0,0xa0,0x18,0x00,0xa2,0x8f,0x21,0x38,0x00,0x00,0x21,0x20,0x48,0x00,
-0x21,0x18,0x87,0x00,0x01,0x00,0xe7,0x24,0x1d,0x00,0xe2,0x28,0xfc,0xff,0x40,0x14,
-0xb6,0x51,0x60,0xa0,0x14,0x00,0xa4,0x8f,0x68,0x15,0x63,0x25,0x21,0x50,0x60,0x00,
-0x21,0x10,0x83,0x00,0x21,0x10,0x50,0x00,0x99,0x51,0x40,0xa0,0x02,0x80,0x03,0x3c,
-0x02,0x80,0x02,0x3c,0x4c,0x91,0x49,0x24,0xd8,0x90,0x68,0x24,0x21,0x38,0x00,0x00,
-0x80,0x18,0x07,0x00,0x21,0x10,0x69,0x00,0x21,0x20,0x68,0x00,0x00,0x00,0x46,0x8c,
-0x00,0x00,0x85,0x8c,0x01,0x00,0xe7,0x24,0x21,0x18,0x6a,0x00,0x1d,0x00,0xe2,0x28,
-0xec,0x44,0x65,0xac,0xf6,0xff,0x40,0x14,0x60,0x45,0x66,0xac,0x14,0x00,0x00,0x12,
-0x68,0x15,0x63,0x25,0x7b,0x51,0x62,0x92,0xff,0xff,0x07,0x26,0x2a,0x10,0xe2,0x00,
-0x0e,0x00,0x40,0x14,0x02,0x80,0x0b,0x3c,0x68,0x15,0x62,0x25,0x21,0x10,0xc2,0x03,
-0x7b,0x51,0x45,0x90,0x74,0x51,0x44,0x8c,0x01,0x00,0x06,0x24,0x04,0x18,0xe6,0x00,
-0x24,0x10,0x83,0x00,0xb3,0x00,0x43,0x10,0x00,0x00,0x00,0x00,0xff,0xff,0xe7,0x24,
-0x2a,0x10,0xe5,0x00,0xfa,0xff,0x40,0x10,0x04,0x18,0xe6,0x00,0x68,0x15,0x63,0x25,
-0x80,0x10,0x10,0x00,0x21,0x10,0x43,0x00,0x60,0x45,0x45,0x8c,0xec,0x44,0x44,0x8c,
-0x02,0x80,0x03,0x3c,0x40,0x10,0x05,0x00,0x8e,0x7d,0x66,0x90,0x21,0x10,0x45,0x00,
-0x21,0x20,0x82,0x00,0x22,0x00,0x02,0x24,0x98,0x00,0xc2,0x10,0x82,0x50,0x04,0x00,
-0xd4,0x51,0x63,0x8e,0x01,0x00,0x02,0x24,0x04,0x10,0x02,0x02,0x25,0x18,0x62,0x00,
-0xd4,0x51,0x63,0xae,0x68,0x15,0x63,0x25,0x21,0x10,0xe3,0x02,0x44,0x51,0x4a,0xac,
-0x8c,0x65,0x64,0x8c,0xff,0xff,0x02,0x34,0x3c,0xff,0x82,0x14,0x21,0x20,0x00,0x02,
-0x39,0x0f,0x00,0x08,0x00,0x00,0x00,0x00,0x3e,0xff,0x20,0x11,0x21,0x20,0x00,0x02,
-0x68,0x15,0x62,0x25,0x80,0x18,0x10,0x00,0x21,0x18,0x62,0x00,0x60,0x45,0x64,0x8c,
-0x00,0x00,0x00,0x00,0x2b,0x20,0x44,0x01,0x36,0xff,0x80,0x10,0x21,0x20,0x00,0x02,
-0xa2,0x0f,0x00,0x08,0x68,0x15,0x68,0x25,0x1e,0xff,0x40,0x10,0x68,0x15,0x65,0x25,
-0x21,0x20,0x30,0x02,0x99,0x51,0x83,0x90,0x01,0x00,0x02,0x24,0x63,0x00,0x62,0x10,
-0x02,0x80,0x02,0x3c,0x2c,0x00,0xa3,0x8f,0x68,0x15,0x42,0x24,0x21,0x38,0x00,0x00,
-0x21,0x20,0x62,0x00,0x21,0x18,0x87,0x00,0x01,0x00,0xe7,0x24,0x1d,0x00,0xe2,0x28,
-0xfc,0xff,0x40,0x14,0xb6,0x51,0x60,0xa0,0x28,0x00,0xa3,0x8f,0x02,0x80,0x0b,0x3c,
-0x68,0x15,0x65,0x25,0x21,0x30,0x65,0x00,0xd4,0x51,0xc2,0x8c,0x01,0x00,0x03,0x24,
-0x04,0x18,0x03,0x02,0x27,0x18,0x03,0x00,0x21,0x20,0xd0,0x00,0x24,0x10,0x43,0x00,
-0x99,0x51,0x80,0xa0,0xd4,0x51,0xc2,0xac,0x12,0x00,0x00,0x16,0x7c,0x51,0x80,0xa0,
-0x7a,0x51,0xc2,0x90,0x00,0x00,0x00,0x00,0x0e,0x00,0x40,0x10,0x01,0x00,0x07,0x24,
-0x24,0x00,0xa4,0x8f,0x01,0x00,0x06,0x24,0x21,0x10,0x85,0x00,0x7a,0x51,0x44,0x90,
-0x74,0x51,0x45,0x8c,0x04,0x18,0xe6,0x00,0x24,0x10,0xa3,0x00,0x5b,0x00,0x43,0x10,
-0x00,0x00,0x00,0x00,0x01,0x00,0xe7,0x24,0x2a,0x10,0x87,0x00,0xfa,0xff,0x40,0x10,
-0x04,0x18,0xe6,0x00,0x20,0x00,0xa2,0x8f,0x02,0x80,0x0b,0x3c,0x68,0x15,0x64,0x25,
-0x21,0x18,0x44,0x00,0x7a,0x51,0x62,0x90,0x01,0x00,0x07,0x26,0x2a,0x10,0x47,0x00,
-0x0e,0x00,0x40,0x14,0x01,0x00,0x06,0x24,0x1c,0x00,0xa3,0x8f,0x00,0x00,0x00,0x00,
-0x21,0x10,0x64,0x00,0x7a,0x51,0x45,0x90,0x74,0x51,0x44,0x8c,0x04,0x18,0xe6,0x00,
-0x24,0x10,0x83,0x00,0x42,0x00,0x43,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0xe7,0x24,
-0x2a,0x10,0xa7,0x00,0xfa,0xff,0x40,0x10,0x04,0x18,0xe6,0x00,0x02,0x80,0x02,0x3c,
-0x8e,0x7d,0x44,0x90,0x22,0x00,0x03,0x24,0xd6,0xfe,0x83,0x14,0x68,0x15,0x65,0x25,
-0xee,0xff,0x02,0x26,0xff,0x00,0x42,0x30,0x02,0x00,0x42,0x2c,0x18,0x00,0x03,0x24,
-0x25,0x0f,0x00,0x08,0x0b,0x80,0x62,0x00,0xc0,0x10,0x07,0x00,0x23,0x10,0x47,0x00,
-0xc2,0x10,0x02,0x00,0x2b,0x10,0x48,0x00,0xb6,0xfe,0x40,0x14,0x00,0x00,0x00,0x00,
-0x04,0x0f,0x00,0x08,0x00,0x00,0x00,0x00,0x10,0x00,0xa3,0x8f,0x5c,0x00,0xbf,0x8f,
-0x58,0x00,0xbe,0x8f,0x54,0x00,0xb7,0x8f,0x50,0x00,0xb6,0x8f,0x4c,0x00,0xb5,0x8f,
-0x48,0x00,0xb4,0x8f,0x44,0x00,0xb3,0x8f,0x40,0x00,0xb2,0x8f,0x3c,0x00,0xb1,0x8f,
-0x38,0x00,0xb0,0x8f,0x25,0xb0,0x02,0x3c,0x80,0x01,0x42,0x34,0x60,0x00,0xbd,0x27,
-0x00,0x00,0x43,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x18,0x00,0x02,0x2e,
-0x0a,0x00,0x40,0x14,0x05,0x00,0x02,0x2e,0xb6,0x51,0x83,0x90,0x00,0x00,0x00,0x00,
-0x05,0x00,0x62,0x2c,0xa0,0xff,0x40,0x10,0x01,0x00,0x62,0x24,0x16,0x10,0x00,0x08,
-0xb6,0x51,0x82,0xa0,0x24,0x0f,0x00,0x08,0x99,0x51,0xa7,0xa0,0x04,0x00,0x40,0x10,
-0x00,0x00,0x00,0x00,0xb6,0x51,0x83,0x90,0x75,0x10,0x00,0x08,0x03,0x00,0x62,0x2c,
-0xb6,0x51,0x83,0x90,0x75,0x10,0x00,0x08,0x04,0x00,0x62,0x2c,0x13,0x00,0x02,0x24,
-0x67,0xff,0x02,0x16,0x68,0x15,0x63,0x25,0xf3,0x0f,0x00,0x08,0x21,0x10,0xe3,0x02,
-0xff,0x00,0xf0,0x30,0x4c,0x10,0x00,0x08,0x02,0x80,0x02,0x3c,0x35,0x10,0x00,0x08,
-0xff,0x00,0xf0,0x30,0xdf,0x0f,0x00,0x08,0xff,0x00,0xf0,0x30,0xd8,0xff,0xbd,0x27,
-0x02,0x80,0x02,0x3c,0x14,0x00,0xb1,0xaf,0x24,0x00,0xbf,0xaf,0x20,0x00,0xb4,0xaf,
-0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf,0x10,0x00,0xb0,0xaf,0x68,0x15,0x45,0x24,
-0x05,0x65,0xa4,0x90,0x00,0x65,0xa3,0x8c,0xfc,0x64,0xa2,0x8c,0x21,0x88,0x64,0x00,
-0x2b,0x10,0x22,0x02,0x60,0x00,0x40,0x10,0x21,0x80,0xa0,0x00,0x02,0x80,0x14,0x3c,
-0x21,0x98,0xa0,0x00,0xa8,0x10,0x00,0x08,0x21,0x90,0xa0,0x00,0xfc,0x64,0x42,0x8e,
-0x10,0x00,0x31,0x26,0x2b,0x10,0x22,0x02,0x57,0x00,0x40,0x10,0x21,0x80,0x40,0x02,
-0x05,0x65,0x02,0x92,0xff,0xff,0x23,0x32,0x02,0x80,0x05,0x3c,0x10,0x00,0x42,0x24,
-0x25,0x28,0x65,0x00,0x2c,0x79,0x84,0x26,0x10,0x00,0x06,0x24,0x9f,0x45,0x00,0x0c,
-0x05,0x65,0x02,0xa2,0xc8,0x63,0x06,0x8e,0x00,0x00,0x00,0x00,0x42,0x24,0x06,0x00,
-0x1f,0x00,0x84,0x30,0xc0,0x10,0x04,0x00,0x21,0x10,0x44,0x00,0x80,0x10,0x02,0x00,
-0x21,0x10,0x44,0x00,0x80,0x10,0x02,0x00,0x21,0x38,0x50,0x00,0x78,0x51,0xe3,0x8c,
-0x00,0x00,0x00,0x00,0x02,0x1b,0x03,0x00,0x01,0x00,0x63,0x30,0xe3,0xff,0x60,0x10,
-0x25,0xb0,0x02,0x3c,0xc4,0x63,0x05,0x8e,0x21,0x10,0x82,0x00,0x60,0x01,0x44,0x90,
-0x82,0x1d,0x05,0x00,0x3f,0x00,0x63,0x30,0x04,0x00,0x0a,0x24,0x05,0x00,0x62,0x28,
-0x21,0x40,0x40,0x01,0x0b,0x40,0x62,0x00,0x07,0x00,0xa0,0x04,0xff,0x00,0x89,0x30,
-0x64,0x51,0xe2,0x8c,0x04,0x00,0x08,0x24,0x01,0x00,0x42,0x24,0x64,0x51,0xe2,0xac,
-0xc8,0x63,0x66,0x8e,0x00,0x00,0x00,0x00,0x02,0x13,0x06,0x00,0x1f,0x00,0x42,0x30,
-0x08,0x00,0x42,0x28,0xcd,0xff,0x40,0x10,0x00,0x00,0x00,0x00,0xc4,0x63,0x62,0x8e,
-0x00,0x00,0x00,0x00,0x3f,0x00,0x42,0x30,0xc8,0xff,0x49,0x14,0x00,0x00,0x00,0x00,
-0x29,0x00,0x00,0x11,0x01,0x00,0x02,0x24,0x2e,0x00,0x02,0x11,0x02,0x00,0x02,0x24,
-0x33,0x00,0x02,0x11,0x03,0x00,0x02,0x24,0x38,0x00,0x02,0x11,0x00,0x00,0x00,0x00,
-0x3b,0x00,0x0a,0x11,0x00,0x00,0x00,0x00,0x68,0x51,0xe2,0x8c,0x21,0x18,0x33,0x01,
-0x90,0x44,0x64,0x90,0x02,0x11,0x02,0x00,0x2b,0x10,0x44,0x00,0x3e,0x00,0x40,0x14,
-0x00,0x00,0x00,0x00,0x5c,0x51,0xe3,0x8c,0x80,0x10,0x09,0x00,0x21,0x10,0x49,0x00,
-0x01,0x00,0x63,0x24,0x21,0x10,0x53,0x00,0x5c,0x51,0xe3,0xac,0x21,0x10,0x48,0x00,
-0x34,0x43,0x44,0x90,0x44,0x51,0xe3,0x8c,0x00,0x00,0x00,0x00,0x21,0x18,0x64,0x00,
-0x44,0x51,0xe3,0xac,0xfc,0x64,0x42,0x8e,0x10,0x00,0x31,0x26,0x2b,0x10,0x22,0x02,
-0xab,0xff,0x40,0x14,0x21,0x80,0x40,0x02,0x24,0x00,0xbf,0x8f,0x20,0x00,0xb4,0x8f,
-0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,
-0x08,0x00,0xe0,0x03,0x28,0x00,0xbd,0x27,0x48,0x51,0xe2,0x8c,0x00,0x00,0x00,0x00,
-0x01,0x00,0x42,0x24,0x48,0x51,0xe2,0xac,0x01,0x00,0x02,0x24,0xd4,0xff,0x02,0x15,
-0x02,0x00,0x02,0x24,0x4c,0x51,0xe2,0x8c,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,
-0x4c,0x51,0xe2,0xac,0x02,0x00,0x02,0x24,0xcf,0xff,0x02,0x15,0x03,0x00,0x02,0x24,
-0x50,0x51,0xe2,0x8c,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,0x50,0x51,0xe2,0xac,
-0x03,0x00,0x02,0x24,0xca,0xff,0x02,0x15,0x00,0x00,0x00,0x00,0x54,0x51,0xe2,0x8c,
-0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,0xc7,0xff,0x0a,0x15,0x54,0x51,0xe2,0xac,
-0x58,0x51,0xe2,0x8c,0x21,0x18,0x33,0x01,0x01,0x00,0x42,0x24,0x58,0x51,0xe2,0xac,
-0x68,0x51,0xe2,0x8c,0x90,0x44,0x64,0x90,0x02,0x11,0x02,0x00,0x2b,0x10,0x44,0x00,
-0xc4,0xff,0x40,0x10,0x00,0x00,0x00,0x00,0x60,0x51,0xe3,0x8c,0x80,0x10,0x09,0x00,
-0x21,0x10,0x49,0x00,0x01,0x00,0x63,0x24,0x21,0x10,0x53,0x00,0x60,0x51,0xe3,0xac,
-0x21,0x10,0x48,0x00,0xc5,0x43,0x44,0x90,0x44,0x51,0xe3,0x8c,0x00,0x00,0x00,0x00,
-0x21,0x18,0x64,0x00,0xf9,0x10,0x00,0x08,0x44,0x51,0xe3,0xac,0x25,0xb0,0x02,0x3c,
-0x25,0xb0,0x05,0x3c,0x02,0x80,0x03,0x3c,0x58,0x00,0x4a,0x34,0x5c,0x00,0x4b,0x34,
-0x4c,0x00,0xa2,0x34,0x00,0x00,0x44,0x90,0x68,0x15,0x66,0x24,0xed,0x4a,0xc2,0x90,
-0x29,0xb0,0x07,0x3c,0x03,0x00,0x84,0x30,0x21,0x18,0xc0,0x00,0x0f,0x00,0x44,0x10,
-0x04,0x00,0xe8,0x34,0x07,0x00,0x80,0x14,0x58,0x0c,0xa9,0x34,0xe6,0x42,0xc2,0x90,
-0x1c,0x00,0x06,0x24,0x03,0x00,0x40,0x14,0x50,0x0c,0xa5,0x34,0x00,0x00,0xa6,0xa0,
-0x00,0x00,0x26,0xa1,0x00,0x00,0x42,0x8d,0xed,0x4a,0x64,0xa0,0x00,0x00,0xe2,0xac,
-0x00,0x00,0x62,0x8d,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xad,0x08,0x00,0xe0,0x03,
-0x21,0x10,0x00,0x00,0x25,0xb0,0x0d,0x3c,0xe8,0xff,0xbd,0x27,0x10,0x00,0xbf,0xaf,
-0x2d,0x0a,0xa7,0x35,0xa2,0x0d,0xa2,0x35,0xa4,0x0d,0xa3,0x35,0xa6,0x0d,0xa4,0x35,
-0xa8,0x0d,0xa5,0x35,0x00,0x00,0x48,0x94,0x00,0x00,0x69,0x94,0x00,0x00,0x8a,0x94,
-0x00,0x00,0xab,0x94,0x00,0x00,0xe3,0x90,0x5b,0x0a,0xa4,0x35,0x5c,0x0a,0xa6,0x35,
-0x00,0x2e,0x03,0x00,0x03,0x2e,0x05,0x00,0x40,0x00,0xa2,0x34,0x00,0x00,0xe2,0xa0,
-0x00,0x00,0x85,0x90,0x00,0x00,0xc3,0x90,0x02,0x80,0x0e,0x3c,0x68,0x15,0xcc,0x25,
-0xff,0xff,0x22,0x31,0xff,0x00,0xa5,0x30,0xff,0xff,0x04,0x31,0x21,0x20,0x82,0x00,
-0xff,0x00,0x63,0x30,0x00,0x40,0x87,0x8d,0x00,0x2a,0x05,0x00,0xff,0xff,0x46,0x31,
-0x21,0x28,0xa3,0x00,0xff,0xff,0x62,0x31,0x21,0x20,0x86,0x00,0x21,0x20,0x82,0x00,
-0xff,0xff,0xa3,0x30,0x64,0x0c,0xa2,0x35,0x00,0x00,0x45,0xa4,0x21,0x20,0x83,0x00,
-0x0f,0x00,0xe7,0x30,0x01,0x00,0x02,0x24,0xe0,0x42,0x84,0xad,0xd8,0x42,0x88,0xa5,
-0xda,0x42,0x89,0xa5,0xdc,0x42,0x8a,0xa5,0xde,0x42,0x8b,0xa5,0x07,0x00,0xe2,0x10,
-0xe4,0x42,0x85,0xa5,0xa8,0x56,0x00,0x0c,0x00,0x00,0x00,0x00,0x10,0x00,0xbf,0x8f,
-0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27,0x4c,0x00,0xa3,0x35,
-0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,0x03,0x00,0x42,0x30,0x67,0x00,0x47,0x10,
-0x68,0x15,0xc4,0x25,0xe6,0x42,0x82,0x90,0x00,0x00,0x00,0x00,0x2d,0x00,0x40,0x10,
-0x01,0x00,0x03,0x24,0x68,0x15,0xc5,0x25,0xe6,0x42,0xa3,0x90,0xff,0x00,0x02,0x24,
-0xec,0xff,0x62,0x14,0x25,0xb0,0x03,0x3c,0xc8,0x42,0xa2,0x94,0xe0,0x42,0xa6,0x8c,
-0x50,0x0c,0x63,0x34,0x00,0x00,0x64,0x90,0x2b,0x10,0xc2,0x00,0x5e,0x00,0x40,0x14,
-0x7f,0x00,0x84,0x30,0xca,0x42,0xa2,0x94,0x00,0x00,0x00,0x00,0x2b,0x10,0xc2,0x00,
-0x09,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0xcc,0x42,0xa2,0x94,0x00,0x00,0x00,0x00,
-0x2b,0x10,0xc2,0x00,0x02,0x00,0x40,0x10,0x02,0x00,0x82,0x24,0x01,0x00,0x82,0x24,
-0xff,0x00,0x44,0x30,0x68,0x15,0xc5,0x25,0xd0,0x42,0xa3,0x90,0x00,0x00,0x00,0x00,
-0x2b,0x10,0x64,0x00,0x4e,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x21,0x20,0x60,0x00,
-0x68,0x15,0xc3,0x25,0xe0,0x42,0x62,0x8c,0x00,0x00,0x00,0x00,0xe9,0x03,0x42,0x2c,
-0x02,0x00,0x40,0x14,0x25,0xb0,0x02,0x3c,0xd0,0x42,0x64,0x90,0x58,0x0c,0x43,0x34,
-0x50,0x0c,0x42,0x34,0x00,0x00,0x44,0xa0,0x00,0x00,0x64,0xa0,0x85,0x11,0x00,0x08,
-0x00,0x00,0x00,0x00,0x00,0x40,0x82,0x8c,0x00,0x00,0x00,0x00,0x02,0x12,0x02,0x00,
-0x0f,0x00,0x42,0x30,0xd0,0xff,0x43,0x14,0x68,0x15,0xc5,0x25,0x25,0xb0,0x02,0x3c,
-0x4c,0x00,0x42,0x34,0x00,0x00,0x43,0x90,0x00,0x00,0x00,0x00,0x03,0x00,0x63,0x30,
-0xb8,0xff,0x60,0x10,0xff,0xff,0x02,0x34,0xdc,0x63,0x83,0x8c,0x00,0x00,0x00,0x00,
-0xb4,0xff,0x62,0x10,0x00,0x00,0x00,0x00,0xe0,0x42,0x83,0x8c,0x00,0x00,0x00,0x00,
-0x65,0x00,0x62,0x2c,0x3b,0x00,0x40,0x14,0x28,0x00,0x62,0x2c,0xd2,0x42,0x83,0x90,
-0x00,0x00,0x00,0x00,0x00,0x16,0x03,0x00,0x03,0x16,0x02,0x00,0xfe,0xff,0x42,0x24,
-0xfc,0xff,0x42,0x28,0x02,0x00,0x40,0x10,0xfe,0xff,0x62,0x24,0xfc,0xff,0x02,0x24,
-0xd2,0x42,0x82,0xa0,0x68,0x15,0xc4,0x25,0xdc,0x63,0x82,0x8c,0xd2,0x42,0x83,0x90,
-0xce,0x42,0x86,0x90,0x02,0x11,0x02,0x00,0x7f,0x00,0x42,0x30,0x0a,0x00,0x45,0x24,
-0x23,0x18,0xa3,0x00,0x00,0x2e,0x03,0x00,0x03,0x2e,0x05,0x00,0xff,0x00,0xc2,0x30,
-0x2a,0x10,0x45,0x00,0x17,0x00,0x40,0x10,0x25,0xb0,0x02,0x3c,0x00,0x2e,0x06,0x00,
-0x03,0x2e,0x05,0x00,0x58,0x0c,0x43,0x34,0x50,0x0c,0x42,0x34,0x00,0x00,0x45,0xa0,
-0x00,0x00,0x65,0xa0,0x85,0x11,0x00,0x08,0x00,0x00,0x00,0x00,0xe6,0x42,0x82,0x91,
-0x00,0x00,0x00,0x00,0x97,0xff,0x40,0x14,0x00,0x00,0x00,0x00,0xff,0xff,0x02,0x24,
-0x91,0x11,0x00,0x08,0xe6,0x42,0x82,0xa1,0xac,0x11,0x00,0x08,0xff,0xff,0x82,0x24,
-0xd1,0x42,0xa3,0x90,0x00,0x00,0x00,0x00,0x2b,0x10,0x83,0x00,0xb4,0x11,0x00,0x08,
-0x0b,0x20,0x62,0x00,0xcf,0x42,0x83,0x80,0x00,0x00,0x00,0x00,0xff,0x00,0x62,0x30,
-0x2a,0x10,0xa2,0x00,0x0b,0x28,0x62,0x00,0x25,0xb0,0x02,0x3c,0x58,0x0c,0x43,0x34,
-0x50,0x0c,0x42,0x34,0x00,0x00,0x45,0xa0,0x00,0x00,0x65,0xa0,0x85,0x11,0x00,0x08,
-0x00,0x00,0x00,0x00,0xcf,0xff,0x40,0x10,0x00,0x00,0x00,0x00,0xd2,0x42,0x83,0x90,
-0x00,0x00,0x00,0x00,0x00,0x16,0x03,0x00,0x03,0x16,0x02,0x00,0x02,0x00,0x42,0x24,
-0x0d,0x00,0x42,0x28,0x03,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0xe0,0x11,0x00,0x08,
-0x0c,0x00,0x02,0x24,0xe0,0x11,0x00,0x08,0x02,0x00,0x62,0x24,0xc0,0xff,0xbd,0x27,
-0x18,0x00,0xb0,0xaf,0x25,0xb0,0x10,0x3c,0x28,0x00,0xb4,0xaf,0x24,0x00,0xb3,0xaf,
-0x1c,0x00,0xb1,0xaf,0x3c,0x00,0xbf,0xaf,0x38,0x00,0xbe,0xaf,0x34,0x00,0xb7,0xaf,
-0x30,0x00,0xb6,0xaf,0x2c,0x00,0xb5,0xaf,0x20,0x00,0xb2,0xaf,0xd8,0x00,0x06,0x36,
-0x00,0x00,0xc3,0x90,0x02,0x80,0x02,0x3c,0x68,0x15,0x54,0x24,0x2a,0xb0,0x11,0x3c,
-0xa0,0xff,0x02,0x24,0x25,0x18,0x62,0x00,0x34,0x00,0x25,0x36,0xfe,0xff,0x02,0x24,
-0xbc,0x42,0x92,0x92,0x40,0x00,0x04,0x24,0x00,0x00,0xc3,0xa0,0x00,0x00,0xa2,0xa0,
-0xa1,0x4e,0x00,0x0c,0x00,0x96,0x12,0x00,0x21,0x98,0x40,0x00,0x6b,0x00,0x60,0x12,
-0x00,0x40,0x02,0x3c,0x08,0x00,0x63,0x8e,0xb0,0x03,0x02,0x36,0x21,0x20,0x60,0x02,
-0x00,0x00,0x43,0xac,0x3a,0x45,0x00,0x0c,0x21,0xb8,0x80,0x02,0x01,0x00,0x1e,0x24,
-0x42,0x00,0x16,0x36,0x03,0x0c,0x11,0x36,0x17,0x0e,0x15,0x36,0x04,0x00,0x14,0x24,
-0x2a,0xb0,0x03,0x3c,0x06,0x00,0x63,0x34,0x00,0x00,0x62,0x94,0x00,0x00,0x00,0x00,
-0x00,0xff,0x42,0x30,0x0a,0x00,0x40,0x18,0x00,0x00,0x00,0x00,0x02,0x80,0x04,0x3c,
-0xc8,0x94,0x84,0x24,0x00,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0x94,
-0x00,0x00,0x00,0x00,0x00,0xff,0x42,0x30,0xfc,0xff,0x40,0x1c,0x00,0x00,0x00,0x00,
-0x08,0x00,0x65,0x8e,0x20,0x10,0x06,0x3c,0x00,0xfe,0xc6,0x34,0x40,0x00,0x07,0x24,
-0x01,0x00,0x04,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xbe,0xaf,0x4d,0x01,0x00,0x0c,
-0x01,0x00,0x04,0x24,0x2a,0xb0,0x02,0x3c,0x05,0x00,0x42,0x34,0xff,0xff,0x03,0x24,
-0x00,0x00,0x5e,0xa0,0x00,0x00,0xc3,0xa2,0x00,0x00,0x22,0x92,0xc1,0x42,0xe5,0x92,
-0x2a,0xb0,0x04,0x3c,0x02,0x00,0x03,0x24,0x40,0x00,0x42,0x34,0x05,0x00,0x84,0x34,
-0x00,0x00,0x22,0xa2,0x00,0x00,0x83,0xa0,0xef,0xff,0x02,0x24,0x00,0x00,0xb0,0x92,
-0x64,0x00,0x04,0x24,0x00,0x00,0xa5,0xa2,0x00,0x00,0xc2,0xa2,0xb3,0x0a,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x92,0xbf,0xff,0x03,0x24,0x84,0x03,0x04,0x24,
-0x24,0x10,0x43,0x00,0x00,0x00,0x22,0xa2,0xb3,0x0a,0x00,0x0c,0xff,0x00,0x10,0x32,
-0x25,0xb0,0x02,0x3c,0xf4,0x08,0x42,0x34,0x00,0x00,0x44,0x8c,0x00,0x00,0xb0,0xa2,
-0x00,0x00,0xc0,0xa2,0x00,0x00,0x22,0x92,0xbe,0x42,0xe3,0x92,0x1f,0x00,0x85,0x30,
-0x40,0x00,0x42,0x34,0x00,0x00,0x22,0xa2,0x00,0x80,0x02,0x3c,0xdf,0x07,0x42,0x34,
-0x2b,0x18,0xa3,0x00,0x09,0x00,0x60,0x10,0x24,0x20,0x82,0x00,0xbf,0x42,0xe2,0x92,
-0x00,0x00,0x00,0x00,0x2b,0x10,0x45,0x00,0x05,0x00,0x40,0x10,0x02,0x80,0x02,0x3c,
-0x01,0x00,0x02,0x3c,0x25,0x10,0xa2,0x00,0x21,0x90,0x42,0x02,0x02,0x80,0x02,0x3c,
-0x8e,0x7d,0x43,0x90,0x22,0x00,0x02,0x24,0x1c,0x00,0x62,0x10,0x92,0x00,0x02,0x24,
-0x1b,0x00,0x62,0x10,0x02,0x80,0x03,0x3c,0xff,0xff,0x94,0x26,0xb3,0x0a,0x00,0x0c,
-0xf4,0x01,0x04,0x24,0xab,0xff,0x81,0x06,0x2a,0xb0,0x03,0x3c,0x04,0x00,0x60,0x12,
-0x25,0xb0,0x02,0x3c,0xbd,0x4e,0x00,0x0c,0x21,0x20,0x60,0x02,0x25,0xb0,0x02,0x3c,
-0xd8,0x02,0x42,0x34,0x00,0x00,0x52,0xac,0x21,0x10,0x40,0x02,0x3c,0x00,0xbf,0x8f,
-0x38,0x00,0xbe,0x8f,0x34,0x00,0xb7,0x8f,0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,
-0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,
-0x18,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x40,0x00,0xbd,0x27,0x02,0x80,0x03,0x3c,
-0x68,0x15,0x63,0x24,0xbe,0x42,0x62,0x90,0xc0,0x07,0x83,0x30,0x82,0x19,0x03,0x00,
-0x2b,0x10,0x62,0x00,0xe0,0xff,0x40,0x10,0x02,0x80,0x04,0x3c,0x68,0x15,0x84,0x24,
-0xbf,0x42,0x82,0x90,0x00,0x00,0x00,0x00,0x2b,0x10,0x43,0x00,0xda,0xff,0x40,0x10,
-0x00,0x12,0x03,0x00,0x10,0x00,0x03,0x3c,0x25,0x10,0x43,0x00,0x9a,0x12,0x00,0x08,
-0x21,0x90,0x42,0x02,0xe8,0xff,0xbd,0x27,0x10,0x00,0xb0,0xaf,0x0f,0x00,0x10,0x3c,
-0xff,0xff,0x05,0x36,0xf0,0xf8,0x06,0x34,0x14,0x00,0xbf,0xaf,0xba,0x44,0x00,0x0c,
-0x15,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0xff,0xff,0x05,0x36,
-0x56,0x30,0x06,0x24,0xba,0x44,0x00,0x0c,0x1a,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,
-0x64,0x00,0x04,0x24,0x02,0x80,0x0b,0x3c,0x68,0x15,0x64,0x25,0x04,0x43,0x83,0x90,
-0x04,0x00,0x02,0x24,0x19,0x00,0x62,0x10,0x25,0xb0,0x02,0x3c,0x14,0x43,0x8a,0x8c,
-0x18,0x43,0x88,0x8c,0x25,0xb0,0x02,0x3c,0x1c,0x0e,0x49,0x34,0x00,0x0e,0x43,0x34,
-0x04,0x0e,0x44,0x34,0x08,0x0e,0x45,0x34,0x10,0x0e,0x46,0x34,0x14,0x0e,0x47,0x34,
-0x18,0x0e,0x42,0x34,0x00,0x00,0x6a,0xac,0x00,0x00,0x8a,0xac,0x00,0x00,0xa8,0xac,
-0x00,0x00,0xca,0xac,0x00,0x00,0xea,0xac,0x00,0x00,0x4a,0xac,0x00,0x00,0x2a,0xad,
-0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f,0x68,0x15,0x63,0x25,0x04,0x00,0x02,0x24,
-0x18,0x00,0xbd,0x27,0x08,0x00,0xe0,0x03,0x04,0x43,0x62,0xa0,0x00,0x0e,0x42,0x34,
-0x00,0x00,0x43,0x8c,0x14,0x43,0x8a,0x8c,0x00,0x00,0x00,0x00,0xe4,0xff,0x6a,0x14,
-0x00,0x00,0x00,0x00,0xec,0x12,0x00,0x08,0x00,0x00,0x00,0x00,0xe8,0xff,0xbd,0x27,
-0x10,0x00,0xb0,0xaf,0x0f,0x00,0x10,0x3c,0xff,0xff,0x05,0x36,0xf0,0xf8,0x06,0x34,
-0x14,0x00,0xbf,0xaf,0xba,0x44,0x00,0x0c,0x15,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,
-0x64,0x00,0x04,0x24,0xff,0xff,0x05,0x36,0x56,0x30,0x06,0x24,0xba,0x44,0x00,0x0c,
-0x1a,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x02,0x80,0x04,0x3c,
-0x68,0x15,0x83,0x24,0x04,0x43,0x65,0x90,0x21,0x70,0x60,0x00,0x10,0x10,0x03,0x3c,
-0x25,0xb0,0x02,0x3c,0x10,0x10,0x66,0x34,0x01,0x00,0x03,0x24,0x1c,0x0e,0x4d,0x34,
-0x00,0x0e,0x4a,0x34,0x04,0x0e,0x4b,0x34,0x08,0x0e,0x4c,0x34,0x10,0x0e,0x47,0x34,
-0x14,0x0e,0x48,0x34,0x0f,0x00,0xa3,0x10,0x18,0x0e,0x49,0x34,0x10,0x10,0x02,0x24,
-0x00,0x00,0x46,0xad,0x00,0x00,0x66,0xad,0x00,0x00,0x82,0xad,0x00,0x00,0xe6,0xac,
-0x00,0x00,0x06,0xad,0x00,0x00,0x26,0xad,0x00,0x00,0xa6,0xad,0x14,0x00,0xbf,0x8f,
-0x10,0x00,0xb0,0x8f,0x01,0x00,0x02,0x24,0x18,0x00,0xbd,0x27,0x08,0x00,0xe0,0x03,
-0x04,0x43,0xc2,0xa1,0x00,0x00,0x44,0x8d,0x00,0x00,0x00,0x00,0xf0,0xff,0x86,0x14,
-0x10,0x10,0x02,0x24,0x23,0x13,0x00,0x08,0x00,0x00,0x00,0x00,0xe0,0xff,0xbd,0x27,
-0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x01,0x00,0x11,0x3c,0x0f,0x00,0x10,0x3c,
-0xff,0xff,0x05,0x36,0xf4,0x98,0x26,0x36,0x18,0x00,0xbf,0xaf,0xba,0x44,0x00,0x0c,
-0x15,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0xff,0xff,0x05,0x36,
-0x56,0x30,0x26,0x36,0xba,0x44,0x00,0x0c,0x1a,0x00,0x04,0x24,0x02,0x80,0x10,0x3c,
-0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x68,0x15,0x04,0x26,0x04,0x43,0x82,0x90,
-0x00,0x00,0x00,0x00,0x0d,0x00,0x40,0x14,0x25,0xb0,0x02,0x3c,0x00,0x0e,0x42,0x34,
-0x00,0x00,0x43,0x8c,0xec,0x42,0x8f,0x8c,0x00,0x00,0x00,0x00,0x08,0x00,0x6f,0x14,
-0x68,0x15,0x02,0x26,0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,
-0x20,0x00,0xbd,0x27,0x08,0x00,0xe0,0x03,0x04,0x43,0x40,0xa0,0xec,0x42,0x8f,0x8c,
-0xe8,0x42,0x88,0x8c,0xf0,0x42,0x8a,0x8c,0xf4,0x42,0x8b,0x8c,0xf8,0x42,0x8c,0x8c,
-0xfc,0x42,0x8d,0x8c,0x25,0xb0,0x02,0x3c,0x00,0x43,0x8e,0x8c,0x1c,0x0e,0x49,0x34,
-0x08,0x0e,0x43,0x34,0x00,0x0e,0x44,0x34,0x04,0x0e,0x45,0x34,0x10,0x0e,0x46,0x34,
-0x14,0x0e,0x47,0x34,0x18,0x0e,0x42,0x34,0x00,0x00,0x68,0xac,0x18,0x00,0xbf,0x8f,
-0x00,0x00,0x8f,0xac,0x14,0x00,0xb1,0x8f,0x00,0x00,0xaa,0xac,0x00,0x00,0xcb,0xac,
-0x00,0x00,0xec,0xac,0x00,0x00,0x4d,0xac,0x68,0x15,0x02,0x26,0x10,0x00,0xb0,0x8f,
-0x20,0x00,0xbd,0x27,0x00,0x00,0x2e,0xad,0x08,0x00,0xe0,0x03,0x04,0x43,0x40,0xa0,
-0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x01,0x00,0x11,0x3c,
-0x0f,0x00,0x10,0x3c,0xff,0xff,0x05,0x36,0xf4,0x98,0x26,0x36,0x18,0x00,0xbf,0xaf,
-0xba,0x44,0x00,0x0c,0x15,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,
-0xff,0xff,0x05,0x36,0x56,0x30,0x26,0x36,0xba,0x44,0x00,0x0c,0x1a,0x00,0x04,0x24,
-0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x02,0x80,0x18,0x3c,0x68,0x15,0x05,0x27,
-0x04,0x43,0xa3,0x90,0x03,0x00,0x02,0x24,0x2a,0x00,0x62,0x10,0x25,0xb0,0x02,0x3c,
-0xec,0x42,0xaf,0x8c,0x08,0x43,0xa3,0x8c,0xe8,0x42,0xa2,0x8c,0xf0,0x42,0xac,0x8c,
-0xf4,0x42,0xad,0x8c,0xf8,0x42,0xa9,0x8c,0xfc,0x42,0xaa,0x8c,0x00,0x43,0xab,0x8c,
-0x21,0x70,0x43,0x00,0xff,0xff,0x02,0x3c,0x25,0xb0,0x03,0x3c,0xff,0x00,0x42,0x34,
-0x00,0xff,0xc4,0x31,0x04,0x0e,0x65,0x34,0x10,0x0e,0x66,0x34,0x14,0x0e,0x67,0x34,
-0x18,0x0e,0x68,0x34,0x24,0x80,0xc2,0x01,0x08,0x0e,0x71,0x34,0x00,0x0e,0x62,0x34,
-0x01,0x3f,0x84,0x2c,0x1c,0x0e,0x63,0x34,0x00,0x00,0x4f,0xac,0x00,0x00,0xac,0xac,
-0x00,0x00,0xcd,0xac,0x00,0x00,0xe9,0xac,0x00,0x00,0x0a,0xad,0x00,0x00,0x6b,0xac,
-0x0a,0x00,0x80,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0xae,0x18,0x00,0xbf,0x8f,
-0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x68,0x15,0x03,0x27,0x03,0x00,0x02,0x24,
-0x20,0x00,0xbd,0x27,0x08,0x00,0xe0,0x03,0x04,0x43,0x62,0xa0,0xa6,0x13,0x00,0x08,
-0x00,0x3f,0x0e,0x36,0x00,0x0e,0x42,0x34,0x00,0x00,0x43,0x8c,0xec,0x42,0xaf,0x8c,
-0x00,0x00,0x00,0x00,0xd3,0xff,0x6f,0x14,0x00,0x00,0x00,0x00,0xa7,0x13,0x00,0x08,
-0x00,0x00,0x00,0x00,0xd0,0xff,0xbd,0x27,0x18,0x00,0xb2,0xaf,0x02,0x80,0x12,0x3c,
-0x24,0x00,0xb5,0xaf,0x20,0x00,0xb4,0xaf,0x28,0x00,0xbf,0xaf,0x1c,0x00,0xb3,0xaf,
-0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x68,0x15,0x44,0x26,0x02,0x80,0x14,0x3c,
-0x00,0x40,0x85,0x8c,0xdc,0x63,0x83,0x8c,0x8e,0x7d,0x86,0x92,0x25,0xb0,0x02,0x3c,
-0x0f,0x0c,0x42,0x34,0x00,0x00,0x46,0xa0,0x02,0x19,0x03,0x00,0xf0,0xf0,0xa5,0x30,
-0x00,0x10,0x02,0x24,0x04,0x43,0x93,0x90,0x71,0x00,0xa2,0x10,0x7f,0x00,0x75,0x30,
-0x25,0xb0,0x09,0x3c,0x4c,0x00,0x23,0x35,0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,
-0x03,0x00,0x42,0x30,0x09,0x00,0x40,0x10,0x68,0x15,0x45,0x26,0x68,0x15,0x4a,0x26,
-0x00,0x40,0x42,0x8d,0x00,0x00,0x00,0x00,0x02,0x13,0x02,0x00,0x0f,0x00,0x42,0x30,
-0x33,0x00,0x40,0x10,0x00,0x0e,0x25,0x35,0x68,0x15,0x45,0x26,0x04,0x43,0xa2,0x8c,
-0x00,0x00,0x00,0x00,0x02,0x12,0x02,0x00,0x0f,0x00,0x40,0x14,0x68,0x15,0x4a,0x26,
-0x25,0xb0,0x02,0x3c,0x84,0x01,0x42,0x34,0x00,0x00,0x44,0x8c,0x0d,0x00,0x03,0x24,
-0x7e,0x00,0x83,0x10,0x3e,0x00,0x02,0x24,0x4a,0x00,0x03,0x24,0x1f,0x43,0xa2,0xa0,
-0x1c,0x43,0xa3,0xa0,0x45,0x00,0x02,0x24,0x43,0x00,0x03,0x24,0x1d,0x43,0xa2,0xa0,
-0x1e,0x43,0xa3,0xa0,0x68,0x15,0x4a,0x26,0xdc,0x63,0x4c,0x8d,0x04,0x40,0x42,0x8d,
-0x00,0x40,0x4b,0x8d,0x1e,0x43,0x4d,0x91,0x1c,0x43,0x4e,0x91,0x25,0xb0,0x09,0x3c,
-0x02,0x11,0x02,0x00,0x60,0x0c,0x27,0x35,0x02,0x19,0x0c,0x00,0x98,0x0c,0x24,0x35,
-0x00,0x00,0xe3,0xa0,0x66,0x0c,0x25,0x35,0x00,0x00,0x82,0xa0,0x67,0x0c,0x26,0x35,
-0xf0,0xf0,0x68,0x31,0x10,0x10,0x02,0x24,0x00,0x00,0xad,0xa0,0x00,0x00,0xce,0xa0,
-0x43,0x00,0x02,0x11,0xff,0xff,0x02,0x34,0x28,0x00,0xbf,0x8f,0x24,0x00,0xb5,0x8f,
-0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,
-0x00,0x00,0xa2,0x8c,0x00,0x00,0x00,0x00,0x5d,0x00,0x40,0x10,0x10,0x0e,0x28,0x35,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x08,0x0e,0x22,0x35,0x04,0x0e,0x24,0x35,0x00,0x00,0x43,0x8c,0x00,0x00,0xa5,0x8c,
-0x00,0x00,0x82,0x8c,0xe8,0x42,0x43,0xad,0xec,0x42,0x45,0xad,0xf0,0x42,0x42,0xad,
-0x14,0x0e,0x24,0x35,0x18,0x0e,0x22,0x35,0x1c,0x0e,0x25,0x35,0x00,0x00,0x08,0x8d,
-0x8e,0x7d,0x8b,0x92,0x00,0x00,0x86,0x8c,0x00,0xff,0x63,0x30,0x00,0x00,0x47,0x8c,
-0x00,0x00,0xa4,0x8c,0x9a,0x0c,0x22,0x35,0x02,0x1a,0x03,0x00,0x00,0x00,0x43,0xa0,
-0x22,0x00,0x02,0x24,0xf4,0x42,0x48,0xad,0xf8,0x42,0x46,0xad,0xfc,0x42,0x47,0xad,
-0x58,0x00,0x62,0x11,0x00,0x43,0x44,0xad,0x92,0x00,0x02,0x24,0x56,0x00,0x62,0x11,
-0x0d,0x08,0x22,0x35,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0x68,0x15,0x44,0x26,0x00,0x40,0x83,0x8c,0xff,0xff,0x02,0x3c,0xff,0x0f,0x42,0x34,
-0x24,0x18,0x62,0x00,0x00,0x10,0x63,0x34,0xde,0x13,0x00,0x08,0x00,0x40,0x83,0xac,
-0x01,0x00,0x02,0x24,0x35,0x00,0x62,0x12,0x04,0x00,0x02,0x24,0x33,0x00,0x62,0x12,
-0x68,0x15,0x43,0x26,0xff,0xff,0x02,0x24,0xd0,0x13,0x00,0x08,0x04,0x43,0x62,0xa0,
-0xbd,0xff,0x82,0x11,0x02,0x12,0x0b,0x00,0x0f,0x00,0x48,0x30,0x01,0x00,0x03,0x24,
-0xb9,0xff,0x03,0x15,0x4c,0x00,0x23,0x35,0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,
-0x03,0x00,0x42,0x30,0xb4,0xff,0x40,0x10,0x03,0x00,0x02,0x24,0x5f,0x00,0x62,0x12,
-0x04,0x00,0x62,0x2a,0x45,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x64,0x00,0x60,0x12,
-0xff,0x00,0xa2,0x31,0xac,0xff,0x68,0x16,0xff,0x00,0xc2,0x31,0x2b,0x10,0xa2,0x02,
-0x52,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x1f,0x43,0x42,0x91,0x00,0x00,0x00,0x00,
-0x2b,0x10,0x55,0x00,0x44,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0x2f,0x13,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x06,0x14,0x00,0x08,0x00,0x00,0x00,0x00,0x3b,0x00,0x02,0x24,
-0x46,0x00,0x03,0x24,0x1f,0x43,0xa2,0xa0,0x1c,0x43,0xa3,0xa0,0x41,0x00,0x02,0x24,
-0x40,0x00,0x03,0x24,0x1d,0x43,0xa2,0xa0,0xf1,0x13,0x00,0x08,0x1e,0x43,0xa3,0xa0,
-0x00,0x00,0x03,0x8d,0x3f,0x3f,0x02,0x3c,0x3f,0x3f,0x42,0x34,0xa0,0xff,0x62,0x14,
-0x00,0x00,0x00,0x00,0xdf,0x13,0x00,0x08,0x68,0x15,0x45,0x26,0x0f,0x00,0x10,0x3c,
-0x01,0x00,0x11,0x3c,0xff,0xff,0x05,0x36,0xf4,0x98,0x26,0x36,0xba,0x44,0x00,0x0c,
-0x15,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0xff,0xff,0x05,0x36,
-0x56,0x30,0x26,0x36,0xba,0x44,0x00,0x0c,0x1a,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,
-0x64,0x00,0x04,0x24,0x68,0x15,0x43,0x26,0xff,0xff,0x02,0x24,0xd0,0x13,0x00,0x08,
-0x04,0x43,0x62,0xa0,0x0d,0x08,0x22,0x35,0x00,0x00,0x43,0x90,0x00,0x00,0x00,0x00,
-0x0f,0x00,0x63,0x30,0x08,0x00,0x62,0x2c,0x0f,0x00,0x63,0x38,0xa5,0xff,0x40,0x14,
-0x01,0x00,0x65,0x24,0x00,0x16,0x05,0x00,0x00,0x24,0x05,0x00,0x00,0x1a,0x05,0x00,
-0x25,0x10,0x44,0x00,0x25,0x10,0x43,0x00,0x25,0x10,0x45,0x00,0x25,0x18,0x65,0x00,
-0x18,0x43,0x43,0xad,0x35,0x14,0x00,0x08,0x14,0x43,0x42,0xad,0x04,0x00,0x02,0x24,
-0x0d,0x00,0x62,0x12,0xff,0x00,0x02,0x24,0x67,0xff,0x62,0x16,0xff,0x00,0xa2,0x31,
-0x2b,0x10,0xa2,0x02,0x1d,0x00,0x40,0x14,0xff,0x00,0xc2,0x31,0x2b,0x10,0xa2,0x02,
-0x0a,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0xfb,0x12,0x00,0x0c,0x00,0x00,0x00,0x00,
-0x06,0x14,0x00,0x08,0x00,0x00,0x00,0x00,0x1d,0x43,0x42,0x91,0x00,0x00,0x00,0x00,
-0x2b,0x10,0x55,0x00,0xf8,0xff,0x40,0x10,0x00,0x00,0x00,0x00,0xc5,0x12,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x06,0x14,0x00,0x08,0x00,0x00,0x00,0x00,0x20,0x43,0x42,0x91,
-0x00,0x00,0x00,0x00,0x2b,0x10,0xa2,0x02,0xac,0xff,0x40,0x10,0x00,0x00,0x00,0x00,
-0x70,0x13,0x00,0x0c,0x00,0x00,0x00,0x00,0x06,0x14,0x00,0x08,0x00,0x00,0x00,0x00,
-0x2b,0x10,0xa2,0x02,0xe8,0xff,0x40,0x10,0x00,0x00,0x00,0x00,0x21,0x43,0x42,0x91,
-0x00,0x00,0x00,0x00,0x2b,0x10,0x55,0x00,0xa0,0xff,0x40,0x14,0x00,0x00,0x00,0x00,
-0x70,0x13,0x00,0x0c,0x00,0x00,0x00,0x00,0x06,0x14,0x00,0x08,0x00,0x00,0x00,0x00,
-0x02,0x80,0x08,0x3c,0x68,0x15,0x05,0x25,0xdc,0x63,0xa4,0x8c,0xe6,0x42,0xa3,0x90,
-0x02,0x11,0x04,0x00,0x1f,0x00,0x60,0x14,0x7f,0x00,0x46,0x30,0x25,0xb0,0x07,0x3c,
-0x4c,0x00,0xe2,0x34,0x00,0x00,0x43,0x90,0x00,0x00,0x00,0x00,0x19,0x00,0x60,0x10,
-0x00,0x00,0x00,0x00,0xff,0xff,0x02,0x34,0x16,0x00,0x82,0x10,0x00,0x00,0x00,0x00,
-0x00,0x08,0xe3,0x34,0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x30,
-0x12,0x00,0x40,0x10,0x4b,0x00,0xc2,0x2c,0x29,0x00,0x40,0x10,0x01,0x00,0x04,0x24,
-0xd8,0xff,0xc2,0x24,0x1e,0x00,0x42,0x2c,0x2f,0x00,0x40,0x10,0x23,0x00,0xc2,0x2c,
-0x68,0x15,0x04,0x25,0xd3,0x42,0x82,0x90,0x00,0x00,0x00,0x00,0x29,0x00,0x40,0x10,
-0x25,0xb0,0x02,0x3c,0x20,0x00,0x03,0x24,0x87,0x0c,0x42,0x34,0x00,0x00,0x43,0xa0,
-0xd3,0x42,0x80,0xa0,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x0f,0x00,0x40,0x10,
-0x01,0x00,0x04,0x24,0xd8,0xff,0xc2,0x24,0x1e,0x00,0x42,0x2c,0x2c,0x00,0x40,0x10,
-0x23,0x00,0xc2,0x2c,0x68,0x15,0x04,0x25,0xd3,0x42,0x82,0x90,0x00,0x00,0x00,0x00,
-0x26,0x00,0x40,0x10,0x25,0xb0,0x02,0x3c,0x44,0x00,0x03,0x24,0x30,0x0c,0x42,0x34,
-0x00,0x00,0x43,0xa0,0xed,0x14,0x00,0x08,0xd3,0x42,0x80,0xa0,0xd3,0x42,0xa2,0x90,
-0x00,0x00,0x00,0x00,0xef,0xff,0x44,0x10,0x30,0x0c,0xe3,0x34,0x43,0x00,0x02,0x24,
-0xd3,0x42,0xa4,0xa0,0x00,0x00,0x62,0xa0,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0xd3,0x42,0xa2,0x90,0x00,0x00,0x00,0x00,0xd5,0xff,0x44,0x10,0x87,0x0c,0xe3,0x34,
-0x10,0x00,0x02,0x24,0xd3,0x42,0xa4,0xa0,0x00,0x00,0x62,0xa0,0x06,0x15,0x00,0x08,
-0x00,0x00,0x00,0x00,0x23,0x00,0xc2,0x2c,0xda,0xff,0x40,0x10,0x00,0x00,0x00,0x00,
-0x68,0x15,0x04,0x25,0xd3,0x42,0x82,0x90,0x02,0x00,0x03,0x24,0xd5,0xff,0x43,0x10,
-0x00,0x00,0x00,0x00,0x25,0xb0,0x02,0x3c,0x87,0x0c,0x42,0x34,0xd3,0x42,0x83,0xa0,
-0x00,0x00,0x40,0xa0,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x23,0x00,0xc2,0x2c,
-0xcc,0xff,0x40,0x10,0x00,0x00,0x00,0x00,0x68,0x15,0x04,0x25,0xd3,0x42,0x82,0x90,
-0x02,0x00,0x03,0x24,0xc7,0xff,0x43,0x10,0x00,0x00,0x00,0x00,0x25,0xb0,0x02,0x3c,
-0xd3,0x42,0x83,0xa0,0x30,0x0c,0x42,0x34,0x42,0x00,0x03,0x24,0x00,0x00,0x43,0xa0,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x02,0x80,0x02,0x3c,0x68,0x15,0x45,0x24,
-0xd5,0x42,0xa3,0x90,0x02,0x00,0x02,0x24,0x03,0x00,0x62,0x10,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0xdc,0x63,0xa2,0x8c,0x25,0xb0,0x03,0x3c,
-0x0a,0x0a,0x68,0x34,0x02,0x11,0x02,0x00,0x7f,0x00,0x42,0x30,0x1a,0x00,0x44,0x2c,
-0x14,0x00,0x42,0x2c,0x01,0x0a,0x66,0x34,0x0b,0x00,0x40,0x14,0x2e,0x0a,0x67,0x34,
-0xf3,0xff,0x80,0x14,0x00,0x00,0x00,0x00,0xd4,0x42,0xa4,0x90,0x01,0x00,0x02,0x24,
-0x01,0x0a,0x67,0x34,0x0f,0x00,0x82,0x10,0x2e,0x0a,0x66,0x34,0xd4,0x42,0xa0,0xa0,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x40,0x00,0x02,0x24,0x00,0x00,0xc2,0xa0,
-0x01,0x00,0x03,0x24,0xdf,0xff,0x02,0x24,0xd4,0x42,0xa3,0xa0,0x00,0x00,0xe2,0xa0,
-0x03,0x00,0x03,0x24,0x21,0x10,0x00,0x00,0x00,0x00,0x03,0xa1,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x47,0x00,0x02,0x24,0x00,0x00,0xe2,0xa0,0xd3,0xff,0x03,0x24,
-0x83,0xff,0x02,0x24,0x00,0x00,0xc3,0xa0,0x00,0x00,0x02,0xa1,0x48,0x15,0x00,0x08,
-0xd4,0x42,0xa0,0xa0,0xd0,0xff,0xbd,0x27,0x1c,0x00,0xb1,0xaf,0x28,0x00,0xbf,0xaf,
-0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x18,0x00,0xb0,0xaf,0xff,0xff,0x11,0x24,
-0x02,0x80,0x13,0x3c,0x41,0xb0,0x02,0x3c,0x68,0x15,0x66,0x26,0x04,0x00,0x42,0x34,
-0x00,0x00,0x47,0x8c,0x00,0x4b,0xc5,0x8c,0x02,0x80,0x03,0x3c,0x96,0x7d,0x64,0x90,
-0xfc,0x4a,0xc8,0x8c,0x02,0x80,0x02,0x3c,0xb8,0x7d,0x49,0x90,0x25,0xb0,0x0a,0x3c,
-0x25,0x90,0xa7,0x00,0xb0,0x03,0x42,0x35,0x00,0x00,0x52,0xac,0x00,0x24,0x04,0x00,
-0x00,0x00,0x48,0xac,0x84,0x02,0x43,0x35,0x8c,0x02,0x45,0x35,0x01,0x00,0x02,0x24,
-0x00,0x00,0x72,0xac,0x00,0x00,0xa4,0xac,0xb9,0x04,0x22,0x11,0x00,0x4b,0xd2,0xac,
-0x68,0x15,0x66,0x26,0xfc,0x4a,0xc2,0x8c,0x00,0x00,0x00,0x00,0x24,0x28,0x52,0x00,
-0x01,0x00,0xa3,0x30,0x09,0x00,0x60,0x10,0x04,0x00,0xa2,0x30,0x00,0x4b,0xc2,0x8c,
-0x25,0xb0,0x03,0x3c,0x01,0x00,0x04,0x24,0x01,0x00,0x42,0x38,0xb0,0x03,0x63,0x34,
-0x00,0x00,0x64,0xac,0x00,0x4b,0xc2,0xac,0x04,0x00,0xa2,0x30,0x09,0x00,0x40,0x10,
-0x08,0x00,0xa2,0x30,0x00,0x4b,0xc2,0x8c,0x25,0xb0,0x03,0x3c,0x04,0x00,0x04,0x24,
-0x04,0x00,0x42,0x38,0xb0,0x03,0x63,0x34,0x00,0x00,0x64,0xac,0x00,0x4b,0xc2,0xac,
-0x08,0x00,0xa2,0x30,0x0e,0x00,0x40,0x10,0x68,0x15,0x64,0x26,0xc9,0x64,0xc2,0x90,
-0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x18,0x2a,0xb0,0x02,0x3c,0x02,0x00,0x03,0x24,
-0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0xc9,0x64,0xc0,0xa0,0x00,0x4b,0xc2,0x8c,
-0x00,0x00,0x00,0x00,0x08,0x00,0x42,0x38,0x00,0x4b,0xc2,0xac,0x68,0x15,0x64,0x26,
-0xfc,0x4a,0x82,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00,0x10,0x00,0x42,0x30,
-0x0d,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0xc9,0x64,0x82,0x90,0x00,0x00,0x00,0x00,
-0x05,0x00,0x40,0x18,0x2a,0xb0,0x02,0x3c,0x02,0x00,0x03,0x24,0x01,0x00,0x42,0x34,
-0x00,0x00,0x43,0xa0,0xc9,0x64,0x80,0xa0,0x00,0x4b,0x82,0x8c,0x00,0x00,0x00,0x00,
-0x10,0x00,0x42,0x38,0x00,0x4b,0x82,0xac,0x68,0x15,0x64,0x26,0xfc,0x4a,0x82,0x8c,
-0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00,0x20,0x00,0x42,0x30,0x0e,0x00,0x40,0x10,
-0x00,0x00,0x00,0x00,0xc9,0x64,0x82,0x90,0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x18,
-0x2a,0xb0,0x02,0x3c,0x02,0x00,0x03,0x24,0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,
-0xc9,0x64,0x80,0xa0,0x00,0x4b,0x82,0x8c,0x00,0x00,0x00,0x00,0x20,0x00,0x42,0x38,
-0x00,0x4b,0x82,0xac,0x68,0x15,0x64,0x26,0xfc,0x4a,0x82,0x8c,0x00,0x00,0x00,0x00,
-0x24,0x10,0x52,0x00,0x40,0x00,0x42,0x30,0x0d,0x00,0x40,0x10,0x00,0x00,0x00,0x00,
-0xc9,0x64,0x82,0x90,0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x18,0x2a,0xb0,0x02,0x3c,
-0x02,0x00,0x03,0x24,0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0xc9,0x64,0x80,0xa0,
-0x00,0x4b,0x82,0x8c,0x00,0x00,0x00,0x00,0x40,0x00,0x42,0x38,0x00,0x4b,0x82,0xac,
-0x68,0x15,0x64,0x26,0xfc,0x4a,0x82,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00,
-0x80,0x00,0x42,0x30,0x0e,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0xc9,0x64,0x82,0x90,
-0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x18,0x2a,0xb0,0x02,0x3c,0x02,0x00,0x03,0x24,
-0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0xc9,0x64,0x80,0xa0,0x00,0x4b,0x82,0x8c,
-0x00,0x00,0x00,0x00,0x80,0x00,0x42,0x38,0x00,0x4b,0x82,0xac,0x68,0x15,0x64,0x26,
-0xfc,0x4a,0x82,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00,0x00,0x01,0x42,0x30,
-0x0d,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0xc9,0x64,0x82,0x90,0x00,0x00,0x00,0x00,
-0x05,0x00,0x40,0x18,0x2a,0xb0,0x02,0x3c,0x02,0x00,0x03,0x24,0x01,0x00,0x42,0x34,
-0x00,0x00,0x43,0xa0,0xc9,0x64,0x80,0xa0,0x00,0x4b,0x82,0x8c,0x00,0x00,0x00,0x00,
-0x00,0x01,0x42,0x38,0x00,0x4b,0x82,0xac,0x68,0x15,0x64,0x26,0xfc,0x4a,0x82,0x8c,
-0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00,0x00,0x02,0x42,0x30,0x0e,0x00,0x40,0x10,
-0x00,0x00,0x00,0x00,0xc9,0x64,0x82,0x90,0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x18,
-0x2a,0xb0,0x02,0x3c,0x02,0x00,0x03,0x24,0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,
-0xc9,0x64,0x80,0xa0,0x00,0x4b,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x02,0x42,0x38,
-0x00,0x4b,0x82,0xac,0x68,0x15,0x64,0x26,0xfc,0x4a,0x82,0x8c,0x00,0x00,0x00,0x00,
-0x24,0x10,0x52,0x00,0x00,0x04,0x42,0x30,0x0d,0x00,0x40,0x10,0x00,0x00,0x00,0x00,
-0xc9,0x64,0x82,0x90,0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x18,0x2a,0xb0,0x02,0x3c,
-0x02,0x00,0x03,0x24,0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0xc9,0x64,0x80,0xa0,
-0x00,0x4b,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x04,0x42,0x38,0x00,0x4b,0x82,0xac,
-0x68,0x15,0x63,0x26,0xfc,0x4a,0x62,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00,
-0x00,0x08,0x42,0x30,0x3a,0x00,0x40,0x10,0x2a,0xb0,0x05,0x3c,0x00,0x00,0xa8,0x8c,
-0xff,0x00,0x02,0x24,0xff,0x00,0x04,0x31,0x31,0x00,0x82,0x10,0x00,0x80,0x02,0x31,
-0x08,0x04,0x40,0x14,0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,
-0x05,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0xc9,0x64,0x62,0x90,0x00,0x00,0x00,0x00,
-0x0b,0x00,0x40,0x18,0xff,0x00,0x02,0x24,0x08,0x64,0x62,0x90,0x20,0xb0,0x03,0x3c,
-0x00,0x12,0x02,0x00,0x21,0x10,0x43,0x00,0x0c,0x00,0x48,0x8c,0x25,0xb0,0x03,0x3c,
-0xb0,0x03,0x63,0x34,0x00,0x00,0x68,0xac,0xff,0x00,0x04,0x31,0xff,0x00,0x02,0x24,
-0x1a,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31,0xc0,0x64,0x05,0x8e,
-0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,0x21,0x30,0x60,0x00,
-0x54,0x64,0x03,0xae,0x21,0x20,0x00,0x00,0x08,0x64,0x08,0xa2,0x20,0x00,0x07,0x24,
-0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0xfc,0x4a,0x05,0x8e,0x02,0x80,0x06,0x3c,
-0x6c,0x7e,0xc4,0x8c,0xff,0xc7,0x02,0x24,0x24,0x28,0xa2,0x00,0x25,0xb0,0x02,0x3c,
-0x04,0x00,0x84,0x34,0x80,0x03,0x42,0x34,0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac,
-0x00,0x00,0x65,0xac,0x6c,0x7e,0xc4,0xac,0xfc,0x4a,0x05,0xae,0x68,0x15,0x63,0x26,
-0x00,0x4b,0x62,0x8c,0x00,0x00,0x00,0x00,0x00,0x08,0x42,0x38,0x00,0x4b,0x62,0xac,
-0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00,
-0x00,0x10,0x42,0x30,0x38,0x00,0x40,0x10,0x2a,0xb0,0x02,0x3c,0x08,0x00,0x43,0x34,
-0x00,0x00,0x68,0x8c,0xff,0x00,0x02,0x24,0xff,0x00,0x04,0x31,0x2c,0x00,0x82,0x10,
-0x00,0x80,0x02,0x31,0xca,0x03,0x40,0x14,0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,
-0x24,0x10,0x02,0x01,0x0b,0x00,0x40,0x10,0xff,0x00,0x02,0x24,0x10,0x64,0xa2,0x90,
-0x20,0xb0,0x03,0x3c,0x00,0x12,0x02,0x00,0x21,0x10,0x43,0x00,0x0c,0x00,0x48,0x8c,
-0x25,0xb0,0x03,0x3c,0xb0,0x03,0x63,0x34,0x00,0x00,0x68,0xac,0xff,0x00,0x04,0x31,
-0xff,0x00,0x02,0x24,0x1a,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31,
-0xd8,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,
-0x21,0x30,0x60,0x00,0x6c,0x64,0x03,0xae,0x01,0x00,0x04,0x24,0x10,0x64,0x08,0xa2,
-0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0xfc,0x4a,0x05,0x8e,
-0x02,0x80,0x06,0x3c,0x6c,0x7e,0xc4,0x8c,0xff,0xc7,0x02,0x24,0x24,0x28,0xa2,0x00,
-0x25,0xb0,0x02,0x3c,0x10,0x00,0x84,0x34,0x80,0x03,0x42,0x34,0x41,0xb0,0x03,0x3c,
-0x00,0x00,0x44,0xac,0x00,0x00,0x65,0xac,0x6c,0x7e,0xc4,0xac,0xfc,0x4a,0x05,0xae,
-0x68,0x15,0x63,0x26,0x00,0x4b,0x62,0x8c,0x00,0x00,0x00,0x00,0x00,0x10,0x42,0x38,
-0x00,0x4b,0x62,0xac,0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x00,0x00,0x00,0x00,
-0x24,0x10,0x52,0x00,0x00,0x20,0x42,0x30,0x37,0x00,0x40,0x10,0x2a,0xb0,0x02,0x3c,
-0x04,0x00,0x43,0x34,0x00,0x00,0x68,0x8c,0xff,0x00,0x02,0x24,0xff,0x00,0x04,0x31,
-0xab,0x03,0x82,0x10,0x00,0x80,0x02,0x31,0x90,0x03,0x40,0x14,0x00,0x80,0x02,0x3c,
-0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x0b,0x00,0x40,0x10,0xff,0x00,0x02,0x24,
-0x0c,0x64,0xa2,0x90,0x20,0xb0,0x03,0x3c,0x00,0x12,0x02,0x00,0x21,0x10,0x43,0x00,
-0x0c,0x00,0x48,0x8c,0x25,0xb0,0x03,0x3c,0xb0,0x03,0x63,0x34,0x00,0x00,0x68,0xac,
-0xff,0x00,0x04,0x31,0xff,0x00,0x02,0x24,0x1a,0x00,0x82,0x10,0xff,0x00,0x03,0x31,
-0x68,0x15,0x70,0x26,0xcc,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,
-0x21,0x18,0x62,0x00,0x21,0x30,0x60,0x00,0x60,0x64,0x03,0xae,0x01,0x00,0x04,0x24,
-0x0c,0x64,0x08,0xa2,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,
-0xfc,0x4a,0x05,0x8e,0x02,0x80,0x06,0x3c,0x6c,0x7e,0xc4,0x8c,0xff,0xc7,0x02,0x24,
-0x24,0x28,0xa2,0x00,0x25,0xb0,0x02,0x3c,0x20,0x00,0x84,0x34,0x80,0x03,0x42,0x34,
-0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac,0x00,0x00,0x65,0xac,0x6c,0x7e,0xc4,0xac,
-0xfc,0x4a,0x05,0xae,0x68,0x15,0x63,0x26,0x00,0x4b,0x62,0x8c,0x00,0x00,0x00,0x00,
-0x00,0x20,0x42,0x38,0x00,0x4b,0x62,0xac,0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,
-0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00,0x00,0x80,0x42,0x30,0x59,0x00,0x40,0x10,
-0x2a,0xb0,0x06,0x3c,0x0c,0x00,0xc3,0x34,0x00,0x00,0x68,0x8c,0xff,0x00,0x07,0x24,
-0xff,0x00,0x04,0x31,0x78,0x03,0x87,0x10,0x00,0x80,0x02,0x31,0x24,0x00,0x40,0x14,
-0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x22,0x00,0x40,0x10,
-0xff,0x00,0x02,0x24,0x40,0x00,0xc6,0x34,0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00,
-0xff,0x00,0x44,0x30,0x0f,0x00,0x87,0x10,0x68,0x15,0x62,0x26,0xe8,0x63,0xa4,0xa0,
-0x00,0x00,0xc2,0x90,0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30,0x09,0x00,0x83,0x10,
-0x68,0x15,0x62,0x26,0x21,0x38,0xa0,0x00,0x21,0x28,0xc0,0x00,0x00,0x00,0xa2,0x90,
-0x21,0x18,0x80,0x00,0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30,0xe8,0x63,0xe3,0xa0,
-0x68,0x15,0x62,0x26,0xe8,0x63,0x43,0x90,0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00,
-0x21,0x18,0x62,0x00,0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,
-0xff,0x00,0x04,0x31,0x00,0x00,0x48,0xac,0x16,0x17,0x00,0x08,0xff,0x00,0x02,0x24,
-0x00,0x00,0x62,0xac,0xff,0x00,0x02,0x24,0x24,0x00,0x82,0x10,0x68,0x15,0x70,0x26,
-0xff,0x00,0x03,0x31,0x90,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,
-0x21,0x18,0x62,0x00,0x21,0x30,0x60,0x00,0xe8,0x63,0x08,0xa2,0x24,0x64,0x03,0xae,
-0x03,0x00,0x04,0x24,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,
-0x02,0x80,0x0a,0x3c,0x7c,0x7e,0x47,0x91,0x02,0x80,0x09,0x3c,0x6c,0x7e,0x25,0x8d,
-0xfc,0x4a,0x06,0x8e,0x01,0x00,0x08,0x3c,0x80,0xff,0x02,0x24,0x25,0x38,0xe2,0x00,
-0x00,0x80,0x03,0x35,0x80,0x00,0xa5,0x34,0x27,0x18,0x03,0x00,0x00,0x26,0x07,0x00,
-0x25,0xb0,0x02,0x3c,0x24,0x30,0xc3,0x00,0x25,0x20,0x85,0x00,0x80,0x03,0x42,0x34,
-0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac,0x27,0x88,0x08,0x00,0x00,0x00,0x66,0xac,
-0x6c,0x7e,0x25,0xad,0x7c,0x7e,0x47,0xa1,0xfc,0x4a,0x06,0xae,0x68,0x15,0x63,0x26,
-0x00,0x4b,0x62,0x8c,0x00,0x00,0x00,0x00,0x00,0x80,0x42,0x38,0x00,0x4b,0x62,0xac,
-0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x01,0x00,0x03,0x3c,0x24,0x10,0x52,0x00,
-0x24,0x10,0x51,0x00,0x24,0x10,0x43,0x00,0x56,0x00,0x40,0x10,0x2a,0xb0,0x06,0x3c,
-0x10,0x00,0xc3,0x34,0x00,0x00,0x68,0x8c,0xff,0x00,0x07,0x24,0xff,0x00,0x04,0x31,
-0x23,0x03,0x87,0x10,0x25,0xb0,0x02,0x3c,0x00,0x80,0x02,0x31,0x23,0x00,0x40,0x14,
-0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x21,0x00,0x40,0x10,
-0xff,0x00,0x02,0x24,0x41,0x00,0xc6,0x34,0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00,
-0xff,0x00,0x44,0x30,0x0e,0x00,0x87,0x10,0x68,0x15,0x62,0x26,0xec,0x63,0xa4,0xa0,
-0x00,0x00,0xc2,0x90,0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30,0x07,0x00,0x83,0x10,
-0x21,0x38,0xa0,0x00,0x21,0x28,0xc0,0x00,0x00,0x00,0xa2,0x90,0x21,0x18,0x80,0x00,
-0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30,0xec,0x63,0xe3,0xa0,0x68,0x15,0x62,0x26,
-0xec,0x63,0x43,0x90,0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,
-0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,0xff,0x00,0x04,0x31,
-0x00,0x00,0x48,0xac,0x75,0x17,0x00,0x08,0xff,0x00,0x02,0x24,0x00,0x00,0x62,0xac,
-0xff,0x00,0x02,0x24,0x22,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31,
-0x90,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,
-0x21,0x30,0x60,0x00,0xec,0x63,0x08,0xa2,0x24,0x64,0x03,0xae,0x03,0x00,0x04,0x24,
-0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x02,0x80,0x09,0x3c,
-0x7c,0x7e,0x27,0x91,0x02,0x80,0x08,0x3c,0x6c,0x7e,0x05,0x8d,0xfc,0x4a,0x06,0x8e,
-0x01,0x00,0x02,0x3c,0x00,0x80,0x42,0x34,0x40,0x00,0xe7,0x34,0x27,0x10,0x02,0x00,
-0x24,0x30,0xc2,0x00,0x80,0x00,0xa5,0x34,0x00,0x26,0x07,0x00,0x25,0xb0,0x02,0x3c,
-0x25,0x20,0x85,0x00,0x80,0x03,0x42,0x34,0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac,
-0x00,0x00,0x66,0xac,0x6c,0x7e,0x05,0xad,0x7c,0x7e,0x27,0xa1,0xfc,0x4a,0x06,0xae,
-0x68,0x15,0x62,0x26,0x00,0x4b,0x43,0x8c,0x01,0x00,0x04,0x3c,0x26,0x18,0x64,0x00,
-0x00,0x4b,0x43,0xac,0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x02,0x00,0x03,0x3c,
-0x24,0x10,0x52,0x00,0x24,0x10,0x43,0x00,0x5a,0x00,0x40,0x10,0x2a,0xb0,0x06,0x3c,
-0x14,0x00,0xc3,0x34,0x00,0x00,0x68,0x8c,0xff,0x00,0x07,0x24,0xff,0x00,0x04,0x31,
-0xcc,0x02,0x87,0x10,0x25,0xb0,0x02,0x3c,0x00,0x80,0x02,0x31,0x23,0x00,0x40,0x14,
-0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x21,0x00,0x40,0x10,
-0xff,0x00,0x02,0x24,0x42,0x00,0xc6,0x34,0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00,
-0xff,0x00,0x44,0x30,0x0e,0x00,0x87,0x10,0x68,0x15,0x62,0x26,0xf0,0x63,0xa4,0xa0,
-0x00,0x00,0xc2,0x90,0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30,0x07,0x00,0x83,0x10,
-0x21,0x38,0xa0,0x00,0x21,0x28,0xc0,0x00,0x00,0x00,0xa2,0x90,0x21,0x18,0x80,0x00,
-0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30,0xf0,0x63,0xe3,0xa0,0x68,0x15,0x62,0x26,
-0xf0,0x63,0x43,0x90,0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,
-0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,0xff,0x00,0x04,0x31,
-0x00,0x00,0x48,0xac,0xd1,0x17,0x00,0x08,0xff,0x00,0x02,0x24,0x00,0x00,0x62,0xac,
-0xff,0x00,0x02,0x24,0x25,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31,
-0x9c,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,
-0x21,0x30,0x60,0x00,0xf0,0x63,0x08,0xa2,0x30,0x64,0x03,0xae,0x04,0x00,0x04,0x24,
-0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x02,0x80,0x0a,0x3c,
-0x7c,0x7e,0x47,0x91,0x02,0x80,0x09,0x3c,0x6c,0x7e,0x25,0x8d,0xfc,0x4a,0x06,0x8e,
-0x06,0x00,0x02,0x3c,0x20,0x00,0xe7,0x34,0x27,0x10,0x02,0x00,0x24,0x30,0xc2,0x00,
-0x00,0x01,0xa5,0x34,0x25,0xb0,0x03,0x3c,0x04,0x00,0x02,0x3c,0x00,0x26,0x07,0x00,
-0x26,0x88,0x22,0x02,0xb0,0x03,0x68,0x34,0x25,0x20,0x85,0x00,0x80,0x03,0x63,0x34,
-0x41,0xb0,0x02,0x3c,0x00,0x00,0x64,0xac,0x00,0x00,0x46,0xac,0x6c,0x7e,0x25,0xad,
-0x7c,0x7e,0x47,0xa1,0xfc,0x4a,0x06,0xae,0x00,0x00,0x11,0xad,0x68,0x15,0x62,0x26,
-0x00,0x4b,0x43,0x8c,0x02,0x00,0x04,0x3c,0x26,0x18,0x64,0x00,0x00,0x4b,0x43,0xac,
-0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x04,0x00,0x03,0x3c,0x24,0x10,0x52,0x00,
-0x24,0x10,0x51,0x00,0x24,0x10,0x43,0x00,0x58,0x00,0x40,0x10,0x25,0xb0,0x03,0x3c,
-0xb0,0x03,0x62,0x34,0x2a,0xb0,0x09,0x3c,0x00,0x00,0x51,0xac,0x18,0x00,0x26,0x35,
-0x00,0x00,0xc8,0x8c,0xff,0x00,0x07,0x24,0xff,0x00,0x04,0x31,0x3a,0x02,0x87,0x10,
-0x04,0x00,0x02,0x24,0x00,0x80,0x02,0x31,0x23,0x00,0x40,0x14,0x00,0x80,0x02,0x3c,
-0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x21,0x00,0x40,0x10,0xff,0x00,0x02,0x24,
-0x43,0x00,0x26,0x35,0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00,0xff,0x00,0x44,0x30,
-0x0e,0x00,0x87,0x10,0x68,0x15,0x62,0x26,0xf4,0x63,0xa4,0xa0,0x00,0x00,0xc2,0x90,
-0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30,0x07,0x00,0x83,0x10,0x21,0x38,0xa0,0x00,
-0x21,0x28,0xc0,0x00,0x00,0x00,0xa2,0x90,0x21,0x18,0x80,0x00,0xfd,0xff,0x62,0x14,
-0xff,0x00,0x44,0x30,0xf4,0x63,0xe3,0xa0,0x68,0x15,0x62,0x26,0xf4,0x63,0x43,0x90,
-0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,0x0c,0x00,0x68,0x8c,
-0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,0xff,0x00,0x04,0x31,0x00,0x00,0x48,0xac,
-0x34,0x18,0x00,0x08,0xff,0x00,0x02,0x24,0x00,0x00,0xc2,0xac,0xff,0x00,0x02,0x24,
-0x21,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31,0x9c,0x64,0x05,0x8e,
-0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,0x21,0x30,0x60,0x00,
-0xf4,0x63,0x08,0xa2,0x30,0x64,0x03,0xae,0x04,0x00,0x04,0x24,0x20,0x00,0x07,0x24,
-0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x02,0x80,0x09,0x3c,0x7c,0x7e,0x27,0x91,
-0x02,0x80,0x08,0x3c,0x6c,0x7e,0x05,0x8d,0xfc,0x4a,0x06,0x8e,0x06,0x00,0x02,0x3c,
-0x10,0x00,0xe7,0x34,0x27,0x10,0x02,0x00,0x24,0x30,0xc2,0x00,0x00,0x01,0xa5,0x34,
-0x00,0x26,0x07,0x00,0x25,0xb0,0x02,0x3c,0x25,0x20,0x85,0x00,0x80,0x03,0x42,0x34,
-0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac,0x00,0x00,0x66,0xac,0x6c,0x7e,0x05,0xad,
-0x7c,0x7e,0x27,0xa1,0xfc,0x4a,0x06,0xae,0x68,0x15,0x62,0x26,0x00,0x4b,0x43,0x8c,
-0x04,0x00,0x04,0x3c,0x26,0x18,0x64,0x00,0x00,0x4b,0x43,0xac,0x68,0x15,0x65,0x26,
-0xfc,0x4a,0xa2,0x8c,0x08,0x00,0x03,0x3c,0x24,0x10,0x52,0x00,0x24,0x10,0x43,0x00,
-0x5a,0x00,0x40,0x10,0x2a,0xb0,0x06,0x3c,0x1c,0x00,0xc3,0x34,0x00,0x00,0x68,0x8c,
-0xff,0x00,0x07,0x24,0xff,0x00,0x04,0x31,0x13,0x02,0x87,0x10,0x25,0xb0,0x02,0x3c,
-0x00,0x80,0x02,0x31,0x23,0x00,0x40,0x14,0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,
-0x24,0x10,0x02,0x01,0x21,0x00,0x40,0x10,0xff,0x00,0x02,0x24,0x44,0x00,0xc6,0x34,
-0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00,0xff,0x00,0x44,0x30,0x0e,0x00,0x87,0x10,
-0x68,0x15,0x62,0x26,0xf8,0x63,0xa4,0xa0,0x00,0x00,0xc2,0x90,0xff,0x00,0x83,0x30,
-0xff,0x00,0x44,0x30,0x07,0x00,0x83,0x10,0x21,0x38,0xa0,0x00,0x21,0x28,0xc0,0x00,
-0x00,0x00,0xa2,0x90,0x21,0x18,0x80,0x00,0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30,
-0xf8,0x63,0xe3,0xa0,0x68,0x15,0x62,0x26,0xf8,0x63,0x43,0x90,0x20,0xb0,0x02,0x3c,
-0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c,
-0xb0,0x03,0x42,0x34,0xff,0x00,0x04,0x31,0x00,0x00,0x48,0xac,0x8f,0x18,0x00,0x08,
-0xff,0x00,0x02,0x24,0x00,0x00,0x62,0xac,0xff,0x00,0x02,0x24,0x25,0x00,0x82,0x10,
-0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31,0xa8,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,
-0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,0x21,0x30,0x60,0x00,0xf8,0x63,0x08,0xa2,
-0x3c,0x64,0x03,0xae,0x05,0x00,0x04,0x24,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,
-0x10,0x00,0xa0,0xaf,0x02,0x80,0x0a,0x3c,0x7c,0x7e,0x47,0x91,0x02,0x80,0x09,0x3c,
-0x6c,0x7e,0x25,0x8d,0xfc,0x4a,0x06,0x8e,0x18,0x00,0x02,0x3c,0x08,0x00,0xe7,0x34,
-0x27,0x10,0x02,0x00,0x24,0x30,0xc2,0x00,0x00,0x02,0xa5,0x34,0x25,0xb0,0x03,0x3c,
-0x10,0x00,0x02,0x3c,0x00,0x26,0x07,0x00,0x26,0x88,0x22,0x02,0xb0,0x03,0x68,0x34,
-0x25,0x20,0x85,0x00,0x80,0x03,0x63,0x34,0x41,0xb0,0x02,0x3c,0x00,0x00,0x64,0xac,
-0x00,0x00,0x46,0xac,0x6c,0x7e,0x25,0xad,0x7c,0x7e,0x47,0xa1,0xfc,0x4a,0x06,0xae,
-0x00,0x00,0x11,0xad,0x68,0x15,0x62,0x26,0x00,0x4b,0x43,0x8c,0x08,0x00,0x04,0x3c,
-0x26,0x18,0x64,0x00,0x00,0x4b,0x43,0xac,0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,
-0x10,0x00,0x03,0x3c,0x24,0x10,0x52,0x00,0x24,0x10,0x51,0x00,0x24,0x10,0x43,0x00,
-0x58,0x00,0x40,0x10,0x25,0xb0,0x06,0x3c,0xb0,0x03,0xc2,0x34,0x2a,0xb0,0x09,0x3c,
-0x00,0x00,0x51,0xac,0x20,0x00,0x23,0x35,0x00,0x00,0x68,0x8c,0xff,0x00,0x07,0x24,
-0xff,0x00,0x04,0x31,0x80,0x01,0x87,0x10,0x90,0x03,0xc2,0x34,0x00,0x80,0x02,0x31,
-0x23,0x00,0x40,0x14,0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,
-0x21,0x00,0x40,0x10,0xff,0x00,0x02,0x24,0x45,0x00,0x26,0x35,0x00,0x00,0xc2,0x90,
-0x00,0x00,0x00,0x00,0xff,0x00,0x44,0x30,0x0e,0x00,0x87,0x10,0x68,0x15,0x62,0x26,
-0x04,0x64,0xa4,0xa0,0x00,0x00,0xc2,0x90,0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30,
-0x07,0x00,0x83,0x10,0x21,0x38,0xa0,0x00,0x21,0x28,0xc0,0x00,0x00,0x00,0xa2,0x90,
-0x21,0x18,0x80,0x00,0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30,0x04,0x64,0xe3,0xa0,
-0x68,0x15,0x62,0x26,0x04,0x64,0x43,0x90,0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00,
-0x21,0x18,0x62,0x00,0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,
-0xff,0x00,0x04,0x31,0x00,0x00,0x48,0xac,0xf2,0x18,0x00,0x08,0xff,0x00,0x02,0x24,
-0x00,0x00,0x62,0xac,0xff,0x00,0x02,0x24,0x21,0x00,0x82,0x10,0x68,0x15,0x70,0x26,
-0xff,0x00,0x03,0x31,0xa8,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,
-0x21,0x18,0x62,0x00,0x21,0x30,0x60,0x00,0x04,0x64,0x08,0xa2,0x3c,0x64,0x03,0xae,
-0x05,0x00,0x04,0x24,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,
-0x02,0x80,0x09,0x3c,0x7c,0x7e,0x27,0x91,0x02,0x80,0x08,0x3c,0x6c,0x7e,0x05,0x8d,
-0xfc,0x4a,0x06,0x8e,0x18,0x00,0x02,0x3c,0x01,0x00,0xe7,0x34,0x27,0x10,0x02,0x00,
-0x24,0x30,0xc2,0x00,0x00,0x02,0xa5,0x34,0x00,0x26,0x07,0x00,0x25,0xb0,0x02,0x3c,
-0x25,0x20,0x85,0x00,0x80,0x03,0x42,0x34,0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac,
-0x00,0x00,0x66,0xac,0x6c,0x7e,0x05,0xad,0x7c,0x7e,0x27,0xa1,0xfc,0x4a,0x06,0xae,
-0x68,0x15,0x62,0x26,0x00,0x4b,0x43,0x8c,0x10,0x00,0x04,0x3c,0x26,0x18,0x64,0x00,
-0x00,0x4b,0x43,0xac,0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x20,0x00,0x03,0x3c,
-0x24,0x10,0x52,0x00,0x24,0x10,0x43,0x00,0x5a,0x00,0x40,0x10,0x2a,0xb0,0x06,0x3c,
-0x24,0x00,0xc3,0x34,0x00,0x00,0x68,0x8c,0xff,0x00,0x07,0x24,0xff,0x00,0x04,0x31,
-0x28,0x01,0x87,0x10,0x25,0xb0,0x02,0x3c,0x00,0x80,0x02,0x31,0x23,0x00,0x40,0x14,
-0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x21,0x00,0x40,0x10,
-0xff,0x00,0x02,0x24,0x46,0x00,0xc6,0x34,0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00,
-0xff,0x00,0x44,0x30,0x0e,0x00,0x87,0x10,0x68,0x15,0x62,0x26,0xfc,0x63,0xa4,0xa0,
-0x00,0x00,0xc2,0x90,0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30,0x07,0x00,0x83,0x10,
-0x21,0x38,0xa0,0x00,0x21,0x28,0xc0,0x00,0x00,0x00,0xa2,0x90,0x21,0x18,0x80,0x00,
-0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30,0xfc,0x63,0xe3,0xa0,0x68,0x15,0x62,0x26,
-0xfc,0x63,0x43,0x90,0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,
-0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,0xff,0x00,0x04,0x31,
-0x00,0x00,0x48,0xac,0x4d,0x19,0x00,0x08,0xff,0x00,0x02,0x24,0x00,0x00,0x62,0xac,
-0xff,0x00,0x02,0x24,0x25,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31,
-0xb4,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,
-0x21,0x30,0x60,0x00,0xfc,0x63,0x08,0xa2,0x48,0x64,0x03,0xae,0x06,0x00,0x04,0x24,
-0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x02,0x80,0x0a,0x3c,
-0x7c,0x7e,0x47,0x91,0x02,0x80,0x09,0x3c,0x6c,0x7e,0x25,0x8d,0xfc,0x4a,0x06,0x8e,
-0x60,0x00,0x02,0x3c,0x04,0x00,0xe7,0x34,0x27,0x10,0x02,0x00,0x24,0x30,0xc2,0x00,
-0x00,0x04,0xa5,0x34,0x25,0xb0,0x03,0x3c,0x40,0x00,0x02,0x3c,0x00,0x26,0x07,0x00,
-0x26,0x88,0x22,0x02,0xb0,0x03,0x68,0x34,0x25,0x20,0x85,0x00,0x80,0x03,0x63,0x34,
-0x41,0xb0,0x02,0x3c,0x00,0x00,0x64,0xac,0x00,0x00,0x46,0xac,0x6c,0x7e,0x25,0xad,
-0x7c,0x7e,0x47,0xa1,0xfc,0x4a,0x06,0xae,0x00,0x00,0x11,0xad,0x68,0x15,0x62,0x26,
-0x00,0x4b,0x43,0x8c,0x20,0x00,0x04,0x3c,0x26,0x18,0x64,0x00,0x00,0x4b,0x43,0xac,
-0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x40,0x00,0x03,0x3c,0x24,0x10,0x52,0x00,
-0x24,0x10,0x51,0x00,0x24,0x10,0x43,0x00,0x5a,0x00,0x40,0x10,0x68,0x15,0x70,0x26,
-0x25,0xb0,0x02,0x3c,0x2a,0xb0,0x07,0x3c,0xb0,0x03,0x42,0x34,0x00,0x00,0x51,0xac,
-0x28,0x00,0xe3,0x34,0x00,0x00,0x68,0x8c,0xff,0x00,0x06,0x24,0xff,0x00,0x04,0x31,
-0xc9,0x00,0x86,0x10,0x25,0xbd,0x02,0x3c,0x00,0x80,0x02,0x31,0x23,0x00,0x40,0x14,
-0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x21,0x00,0x40,0x10,
-0xff,0x00,0x02,0x24,0x47,0x00,0xe7,0x34,0x00,0x00,0xe2,0x90,0x00,0x00,0x00,0x00,
-0xff,0x00,0x44,0x30,0x0e,0x00,0x86,0x10,0x68,0x15,0x62,0x26,0x00,0x64,0xa4,0xa0,
-0x00,0x00,0xe2,0x90,0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30,0x07,0x00,0x83,0x10,
-0x21,0x30,0xa0,0x00,0x21,0x28,0xe0,0x00,0x00,0x00,0xa2,0x90,0x21,0x18,0x80,0x00,
-0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30,0x00,0x64,0xc3,0xa0,0x68,0x15,0x62,0x26,
-0x00,0x64,0x43,0x90,0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,
-0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,0xff,0x00,0x04,0x31,
-0x00,0x00,0x48,0xac,0xb1,0x19,0x00,0x08,0xff,0x00,0x02,0x24,0x00,0x00,0x62,0xac,
-0xff,0x00,0x02,0x24,0x21,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31,
-0xb4,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,
-0x21,0x30,0x60,0x00,0x00,0x64,0x08,0xa2,0x48,0x64,0x03,0xae,0x06,0x00,0x04,0x24,
-0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x02,0x80,0x09,0x3c,
-0x7c,0x7e,0x27,0x91,0x02,0x80,0x08,0x3c,0x6c,0x7e,0x05,0x8d,0xfc,0x4a,0x06,0x8e,
-0x60,0x00,0x02,0x3c,0x02,0x00,0xe7,0x34,0x27,0x10,0x02,0x00,0x24,0x30,0xc2,0x00,
-0x00,0x04,0xa5,0x34,0x00,0x26,0x07,0x00,0x25,0xb0,0x02,0x3c,0x25,0x20,0x85,0x00,
-0x80,0x03,0x42,0x34,0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac,0x00,0x00,0x66,0xac,
-0x6c,0x7e,0x05,0xad,0x7c,0x7e,0x27,0xa1,0xfc,0x4a,0x06,0xae,0x68,0x15,0x62,0x26,
-0x00,0x4b,0x43,0x8c,0x40,0x00,0x04,0x3c,0x26,0x18,0x64,0x00,0x00,0x4b,0x43,0xac,
-0x68,0x15,0x70,0x26,0xfc,0x4a,0x06,0x8e,0x00,0x04,0x11,0x3c,0x24,0x10,0xd2,0x00,
-0x24,0x10,0x51,0x00,0x4c,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0x24,0x28,0xd2,0x00,
-0x00,0x08,0x04,0x3c,0x24,0x10,0xa4,0x00,0x08,0x00,0x40,0x10,0x80,0x00,0x07,0x3c,
-0x00,0x4b,0x03,0x8e,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,0x26,0x18,0x64,0x00,
-0x00,0x00,0x44,0xac,0x00,0x4b,0x03,0xae,0x80,0x00,0x07,0x3c,0x24,0x10,0xa7,0x00,
-0x21,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x00,0x4b,0x03,0x8e,0x25,0xb0,0x08,0x3c,
-0xb0,0x03,0x09,0x35,0x2a,0xb0,0x02,0x3c,0x00,0x00,0x23,0xad,0x36,0x00,0x42,0x34,
-0x00,0x00,0x43,0x90,0x23,0xb0,0x04,0x3c,0xff,0x1f,0x02,0x3c,0xc0,0x18,0x03,0x00,
-0xf0,0x07,0x63,0x30,0x5c,0x65,0x05,0x8e,0x21,0x18,0x64,0x00,0xff,0xff,0x42,0x34,
-0x24,0x18,0x62,0x00,0x59,0x00,0x65,0x10,0x60,0x65,0x03,0xae,0x02,0x80,0x05,0x3c,
-0x6c,0x7e,0xa3,0x8c,0x27,0x20,0x07,0x00,0x24,0x20,0xc4,0x00,0x00,0x08,0x63,0x34,
-0x41,0xb0,0x02,0x3c,0x00,0x00,0x23,0xad,0x00,0x00,0x44,0xac,0x6c,0x7e,0xa3,0xac,
-0xfc,0x4a,0x04,0xae,0x68,0x15,0x62,0x26,0x00,0x4b,0x43,0x8c,0x80,0x00,0x04,0x3c,
-0x26,0x18,0x64,0x00,0x00,0x4b,0x43,0xac,0x68,0x15,0x66,0x26,0xfc,0x4a,0xc3,0x8c,
-0x00,0x01,0x04,0x3c,0x24,0x28,0x72,0x00,0x24,0x10,0xa4,0x00,0x06,0x00,0x40,0x10,
-0x25,0xb0,0x02,0x3c,0x00,0x4b,0xc3,0x8c,0xb0,0x03,0x42,0x34,0x26,0x18,0x64,0x00,
-0x00,0x00,0x44,0xac,0x00,0x4b,0xc3,0xac,0x00,0x02,0x04,0x3c,0x24,0x10,0xa4,0x00,
-0x06,0x00,0x40,0x10,0x25,0xb0,0x03,0x3c,0x00,0x4b,0xc2,0x8c,0xb0,0x03,0x63,0x34,
-0x26,0x10,0x44,0x00,0x00,0x4b,0xc2,0xac,0x00,0x00,0x64,0xac,0x28,0x00,0xbf,0x8f,
-0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,
-0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,0x5b,0x4e,0x00,0x0c,0x07,0x00,0x04,0x24,
-0x00,0x4b,0x03,0x8e,0xfc,0x4a,0x06,0x8e,0x25,0xb0,0x02,0x3c,0x26,0x18,0x71,0x00,
-0xb0,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0xdf,0x19,0x00,0x08,0x00,0x4b,0x03,0xae,
-0x56,0x01,0x42,0x35,0x00,0x00,0x43,0x94,0x00,0x00,0x00,0x00,0x44,0xfb,0x60,0x10,
-0x00,0x00,0x00,0x00,0x5b,0x4e,0x00,0x0c,0x07,0x00,0x04,0x24,0x7d,0x15,0x00,0x08,
-0x68,0x15,0x66,0x26,0x00,0x00,0xa2,0xac,0x48,0x16,0x00,0x08,0xff,0x00,0x02,0x24,
-0x00,0x00,0x62,0xac,0x85,0x16,0x00,0x08,0xff,0x00,0x02,0x24,0x00,0x00,0x62,0xac,
-0xc2,0x16,0x00,0x08,0xff,0x00,0x02,0x24,0x90,0x03,0x63,0x34,0x00,0x00,0x62,0xac,
-0x57,0x18,0x00,0x08,0x68,0x15,0x62,0x26,0x00,0x00,0x40,0xac,0x15,0x19,0x00,0x08,
-0x68,0x15,0x62,0x26,0x02,0x00,0x03,0x24,0x90,0x03,0x42,0x34,0x00,0x00,0x43,0xac,
-0x74,0x19,0x00,0x08,0x68,0x15,0x62,0x26,0x01,0x00,0x03,0x24,0x90,0x03,0x42,0x34,
-0x00,0x00,0x43,0xac,0xd4,0x19,0x00,0x08,0x68,0x15,0x62,0x26,0xd0,0x03,0x03,0x35,
-0x80,0x00,0x02,0x24,0x00,0x00,0x62,0xac,0x0a,0x1a,0x00,0x08,0x68,0x15,0x62,0x26,
-0x25,0xb0,0x02,0x3c,0x07,0x00,0x03,0x24,0x90,0x03,0x42,0x34,0x00,0x00,0x43,0xac,
-0x68,0x15,0x63,0x26,0x00,0x4b,0x62,0x8c,0x00,0x00,0x00,0x00,0x00,0x20,0x42,0x38,
-0xe2,0x16,0x00,0x08,0x00,0x4b,0x62,0xac,0x25,0xb0,0x02,0x3c,0x07,0x00,0x03,0x24,
-0x90,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0x68,0x15,0x63,0x26,0x00,0x4b,0x62,0x8c,
-0x00,0x00,0x00,0x00,0x00,0x80,0x42,0x38,0x40,0x17,0x00,0x08,0x00,0x4b,0x62,0xac,
-0x06,0x00,0x03,0x24,0x90,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0x99,0x17,0x00,0x08,
-0x68,0x15,0x62,0x26,0x05,0x00,0x03,0x24,0x90,0x03,0x42,0x34,0x00,0x00,0x43,0xac,
-0xf8,0x17,0x00,0x08,0x68,0x15,0x62,0x26,0x03,0x00,0x03,0x24,0x90,0x03,0x42,0x34,
-0x00,0x00,0x43,0xac,0xb6,0x18,0x00,0x08,0x68,0x15,0x62,0x26,0x25,0xb0,0x0d,0x3c,
-0x00,0x80,0x02,0x3c,0x18,0x03,0xa4,0x35,0xfc,0x69,0x42,0x24,0x02,0x80,0x03,0x3c,
-0x41,0xb0,0x08,0x3c,0x00,0x00,0x82,0xac,0x68,0x15,0x6a,0x24,0x0a,0x00,0x02,0x35,
-0x00,0x00,0x44,0x94,0x0a,0x4b,0x43,0x95,0x08,0x4b,0x4b,0x95,0x25,0x18,0x64,0x00,
-0xff,0xff,0x6c,0x30,0x24,0x10,0x8b,0x01,0x02,0x00,0x42,0x30,0x4d,0x00,0x40,0x10,
-0x02,0x00,0x64,0x38,0x02,0x00,0x02,0x24,0xc0,0x03,0xa3,0x35,0x00,0x00,0x62,0xac,
-0x0a,0x4b,0x44,0xa5,0x24,0x38,0x8b,0x01,0x04,0x00,0xe2,0x30,0x0a,0x00,0x40,0x10,
-0x08,0x00,0xe2,0x30,0x0a,0x4b,0x43,0x95,0x0c,0x00,0x04,0x35,0xc0,0x03,0xa5,0x35,
-0x04,0x00,0x63,0x38,0x04,0x00,0x02,0x24,0x00,0x00,0x86,0x8c,0x00,0x00,0xa2,0xac,
-0x0a,0x4b,0x43,0xa5,0x08,0x00,0xe2,0x30,0x08,0x00,0x40,0x10,0x10,0x00,0xe2,0x30,
-0x0a,0x4b,0x42,0x95,0xc0,0x03,0xa4,0x35,0x08,0x00,0x03,0x24,0x08,0x00,0x42,0x38,
-0x00,0x00,0x83,0xac,0x0a,0x4b,0x42,0xa5,0x10,0x00,0xe2,0x30,0x08,0x00,0x40,0x10,
-0x20,0x00,0xe2,0x30,0x0a,0x4b,0x42,0x95,0xc0,0x03,0xa4,0x35,0x10,0x00,0x03,0x24,
-0x10,0x00,0x42,0x38,0x00,0x00,0x83,0xac,0x0a,0x4b,0x42,0xa5,0x20,0x00,0xe2,0x30,
-0x08,0x00,0x40,0x10,0x80,0x00,0xe2,0x30,0x0a,0x4b,0x42,0x95,0xc0,0x03,0xa4,0x35,
-0x20,0x00,0x03,0x24,0x20,0x00,0x42,0x38,0x00,0x00,0x83,0xac,0x0a,0x4b,0x42,0xa5,
-0x80,0x00,0xe2,0x30,0x15,0x00,0x40,0x10,0x24,0x10,0x8b,0x01,0x02,0x80,0x09,0x3c,
-0x0a,0x4b,0x46,0x95,0x6c,0x7e,0x25,0x8d,0x08,0x00,0x02,0x3c,0x7f,0xff,0x04,0x24,
-0x24,0x20,0x64,0x01,0x25,0x28,0xa2,0x00,0x80,0x00,0xc6,0x38,0xb0,0x03,0xa7,0x35,
-0x08,0x00,0x08,0x35,0xc0,0x03,0xa3,0x35,0x80,0x00,0x02,0x24,0x00,0x00,0x62,0xac,
-0x21,0x58,0x80,0x00,0x00,0x00,0xe5,0xac,0x0a,0x4b,0x46,0xa5,0x6c,0x7e,0x25,0xad,
-0x00,0x00,0x04,0xa5,0x08,0x4b,0x44,0xa5,0x24,0x10,0x8b,0x01,0x00,0x30,0x42,0x30,
-0x06,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x0a,0x4b,0x42,0x95,0x00,0x00,0x00,0x00,
-0x00,0x10,0x42,0x38,0x00,0x20,0x42,0x34,0x0a,0x4b,0x42,0xa5,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x95,0x1a,0x00,0x08,0x0a,0x4b,0x43,0xa5,0xf8,0xff,0xbd,0x27,
-0x04,0x00,0xb1,0xaf,0x00,0x00,0xb0,0xaf,0x00,0x40,0x02,0x40,0x00,0x68,0x08,0x40,
-0x00,0x70,0x02,0x40,0x00,0x60,0x09,0x40,0x25,0xb0,0x05,0x3c,0x00,0x80,0x02,0x3c,
-0x18,0x03,0xa3,0x34,0x7c,0x6b,0x42,0x24,0x00,0x00,0x62,0xac,0x80,0x00,0x87,0x8c,
-0x7c,0x02,0xa2,0x34,0x84,0x02,0xa3,0x34,0x88,0x02,0xa6,0x34,0x00,0x00,0x47,0xac,
-0x00,0x00,0x68,0xac,0x00,0x00,0xc9,0xac,0x74,0x00,0x83,0x8c,0x8c,0x02,0xa2,0x34,
-0x90,0x02,0xa7,0x34,0x00,0x00,0x43,0xac,0x08,0x00,0x86,0x8c,0x94,0x02,0xa8,0x34,
-0x98,0x02,0xa9,0x34,0x00,0x00,0xe6,0xac,0x0c,0x00,0x82,0x8c,0x9c,0x02,0xa6,0x34,
-0xa0,0x02,0xa7,0x34,0x00,0x00,0x02,0xad,0x10,0x00,0x83,0x8c,0xa4,0x02,0xa8,0x34,
-0xa8,0x02,0xaa,0x34,0x00,0x00,0x23,0xad,0x14,0x00,0x82,0x8c,0xac,0x02,0xa9,0x34,
-0xb0,0x02,0xab,0x34,0x00,0x00,0xc2,0xac,0x18,0x00,0x83,0x8c,0xb4,0x02,0xa6,0x34,
-0xb8,0x02,0xac,0x34,0x00,0x00,0xe3,0xac,0x1c,0x00,0x82,0x8c,0xbc,0x02,0xa7,0x34,
-0xc0,0x02,0xad,0x34,0x00,0x00,0x02,0xad,0x20,0x00,0x83,0x8c,0xc4,0x02,0xa8,0x34,
-0xc8,0x02,0xae,0x34,0x00,0x00,0x43,0xad,0x24,0x00,0x82,0x8c,0xcc,0x02,0xaa,0x34,
-0xd0,0x02,0xaf,0x34,0x00,0x00,0x22,0xad,0x28,0x00,0x83,0x8c,0xd4,0x02,0xa9,0x34,
-0xd8,0x02,0xb0,0x34,0x00,0x00,0x63,0xad,0x2c,0x00,0x82,0x8c,0x70,0x02,0xab,0x34,
-0x74,0x02,0xb1,0x34,0x00,0x00,0xc2,0xac,0x30,0x00,0x83,0x8c,0x78,0x02,0xa5,0x34,
-0x00,0x00,0x83,0xad,0x34,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0xe2,0xac,
-0x38,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0xad,0x3c,0x00,0x82,0x8c,
-0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xad,0x40,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,
-0x00,0x00,0xc3,0xad,0x44,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0xad,
-0x48,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0xe3,0xad,0x4c,0x00,0x82,0x8c,
-0x00,0x00,0x00,0x00,0x00,0x00,0x22,0xad,0x50,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,
-0x00,0x00,0x03,0xae,0x54,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xad,
-0x58,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0xae,0x5c,0x00,0x82,0x8c,
-0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0xac,0x42,0x1b,0x00,0x08,0x00,0x00,0x00,0x00,
-0x00,0x80,0x1b,0x3c,0x10,0x6d,0x7b,0x27,0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x27,
-0x00,0x00,0x5b,0xaf,0x21,0xd8,0xa0,0x03,0x82,0xda,0x1b,0x00,0x80,0xda,0x1b,0x00,
-0x08,0x00,0x7b,0x27,0x04,0x00,0x61,0xaf,0x08,0x00,0x62,0xaf,0x0c,0x00,0x63,0xaf,
-0x10,0x00,0x64,0xaf,0x14,0x00,0x65,0xaf,0x18,0x00,0x66,0xaf,0x1c,0x00,0x67,0xaf,
-0x20,0x00,0x68,0xaf,0x24,0x00,0x69,0xaf,0x28,0x00,0x6a,0xaf,0x2c,0x00,0x6b,0xaf,
-0x30,0x00,0x6c,0xaf,0x34,0x00,0x6d,0xaf,0x38,0x00,0x6e,0xaf,0x3c,0x00,0x6f,0xaf,
-0x12,0x40,0x00,0x00,0x10,0x48,0x00,0x00,0x00,0x70,0x0a,0x40,0x40,0x00,0x70,0xaf,
-0x44,0x00,0x71,0xaf,0x48,0x00,0x72,0xaf,0x4c,0x00,0x73,0xaf,0x50,0x00,0x74,0xaf,
-0x54,0x00,0x75,0xaf,0x58,0x00,0x76,0xaf,0x5c,0x00,0x77,0xaf,0x60,0x00,0x78,0xaf,
-0x64,0x00,0x79,0xaf,0x68,0x00,0x7c,0xaf,0x6c,0x00,0x7d,0xaf,0x70,0x00,0x7e,0xaf,
-0x74,0x00,0x7f,0xaf,0x78,0x00,0x68,0xaf,0x7c,0x00,0x69,0xaf,0x80,0x00,0x6a,0xaf,
-0x00,0x68,0x1a,0x40,0x25,0xb0,0x1b,0x3c,0x1c,0x03,0x7b,0x37,0x00,0x00,0x00,0x00,
-0x00,0x00,0x7a,0xaf,0x7f,0x00,0x5b,0x33,0x30,0x00,0x60,0x13,0x00,0x00,0x00,0x00,
-0x25,0xb0,0x1b,0x3c,0x30,0x03,0x7b,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x7a,0xaf,
-0x00,0x00,0x00,0x00,0x21,0xd8,0xa0,0x03,0x82,0xda,0x1b,0x00,0x80,0xda,0x1b,0x00,
-0x08,0x00,0x7b,0x27,0x04,0x00,0x61,0xaf,0x08,0x00,0x62,0xaf,0x0c,0x00,0x63,0xaf,
-0x10,0x00,0x64,0xaf,0x14,0x00,0x65,0xaf,0x18,0x00,0x66,0xaf,0x1c,0x00,0x67,0xaf,
-0x20,0x00,0x68,0xaf,0x24,0x00,0x69,0xaf,0x28,0x00,0x6a,0xaf,0x2c,0x00,0x6b,0xaf,
-0x30,0x00,0x6c,0xaf,0x34,0x00,0x6d,0xaf,0x38,0x00,0x6e,0xaf,0x3c,0x00,0x6f,0xaf,
-0x12,0x40,0x00,0x00,0x10,0x48,0x00,0x00,0x00,0x70,0x0a,0x40,0x40,0x00,0x70,0xaf,
-0x44,0x00,0x71,0xaf,0x48,0x00,0x72,0xaf,0x4c,0x00,0x73,0xaf,0x50,0x00,0x74,0xaf,
-0x54,0x00,0x75,0xaf,0x58,0x00,0x76,0xaf,0x5c,0x00,0x77,0xaf,0x60,0x00,0x78,0xaf,
-0x64,0x00,0x79,0xaf,0x68,0x00,0x7c,0xaf,0x6c,0x00,0x7d,0xaf,0x70,0x00,0x7e,0xaf,
-0x74,0x00,0x7f,0xaf,0x78,0x00,0x68,0xaf,0x7c,0x00,0x69,0xaf,0x80,0x00,0x6a,0xaf,
-0xdf,0x1a,0x00,0x08,0x21,0x20,0x60,0x03,0x00,0x00,0x00,0x00,0x25,0xb0,0x08,0x3c,
-0x20,0x03,0x08,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0xad,0x00,0x04,0x5b,0x33,
-0x0a,0x00,0x60,0x13,0x00,0x00,0x00,0x00,0x00,0x80,0x08,0x3c,0x74,0x55,0x08,0x25,
-0x00,0x00,0x00,0x00,0x25,0xb0,0x1b,0x3c,0x24,0x03,0x7b,0x37,0x00,0x00,0x00,0x00,
-0x00,0x00,0x68,0xaf,0x09,0xf8,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x08,0x5b,0x33,
-0x25,0xb0,0x08,0x3c,0x28,0x03,0x08,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x1b,0xad,
-0x06,0x00,0x60,0x13,0x00,0x00,0x00,0x00,0x00,0x80,0x08,0x3c,0xfc,0x69,0x08,0x25,
-0x00,0x00,0x00,0x00,0x09,0xf8,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x80,0x1a,0x3c,
-0x6c,0x7e,0x5a,0x27,0x04,0x00,0x5b,0x97,0x25,0xb0,0x08,0x3c,0x30,0x03,0x08,0x35,
-0x00,0x00,0x00,0x00,0x00,0x00,0x1b,0xad,0x18,0x00,0x60,0x13,0x00,0x00,0x00,0x00,
-0x08,0xec,0x9b,0x27,0x00,0x00,0x00,0x00,0x04,0x00,0x61,0x8f,0xfc,0x03,0x70,0x7b,
-0x7c,0x00,0x62,0x7b,0xbc,0x00,0x64,0x7b,0xfc,0x00,0x66,0x7b,0x3c,0x01,0x68,0x7b,
-0x13,0x00,0x00,0x02,0x11,0x00,0x20,0x02,0x7c,0x01,0x6a,0x7b,0xbc,0x01,0x6c,0x7b,
-0xfc,0x01,0x6e,0x7b,0x3c,0x02,0x70,0x7b,0x7c,0x02,0x72,0x7b,0xbc,0x02,0x74,0x7b,
-0xfc,0x02,0x76,0x7b,0x3c,0x03,0x78,0x7b,0x7c,0x03,0x7c,0x7b,0xbc,0x03,0x7e,0x7b,
-0x80,0x00,0x7b,0x8f,0x2f,0x1c,0x00,0x08,0x00,0x00,0x00,0x00,0x21,0xd8,0xa0,0x03,
-0x82,0xda,0x1b,0x00,0x80,0xda,0x1b,0x00,0x08,0x00,0x7b,0x27,0x08,0x00,0x5b,0xaf,
-0xfc,0xef,0x9d,0x27,0x00,0x00,0x4a,0x8f,0x00,0x00,0x00,0x00,0x21,0x00,0x40,0x11,
-0x00,0x00,0x00,0x00,0x02,0x80,0x08,0x3c,0xcc,0x7d,0x08,0x25,0x21,0x48,0x00,0x00,
-0x21,0x58,0x00,0x00,0x01,0x00,0x6b,0x25,0x1a,0x00,0x40,0x11,0x24,0x70,0x4b,0x01,
-0x14,0x00,0xc0,0x11,0x01,0x00,0x04,0x24,0x00,0x00,0x00,0x00,0x04,0x00,0x44,0xa3,
-0x26,0x50,0x4b,0x01,0x00,0x00,0x4a,0xaf,0x80,0x80,0x09,0x00,0x21,0x80,0x08,0x02,
-0x00,0x00,0x10,0x8e,0x00,0x00,0x00,0x00,0x09,0xf8,0x00,0x02,0x00,0x00,0x00,0x00,
-0x00,0x80,0x1b,0x3c,0xe8,0x6f,0x7b,0x27,0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x27,
-0x00,0x00,0x5b,0xaf,0x02,0x80,0x1a,0x3c,0x6c,0x7e,0x5a,0x27,0xe1,0xff,0x00,0x10,
-0x00,0x00,0x00,0x00,0x01,0x00,0x29,0x25,0x40,0x58,0x0b,0x00,0xf2,0x1b,0x00,0x08,
-0x00,0x00,0x00,0x00,0x02,0x80,0x1b,0x3c,0x6c,0x7e,0x7b,0x27,0x21,0x60,0x00,0x00,
-0x04,0x00,0x6c,0xa7,0x08,0x00,0x7a,0x8f,0x00,0x00,0x00,0x00,0xf8,0xff,0x5a,0x27,
-0x00,0x00,0x5a,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0x5a,0x27,0x84,0x00,0x44,0x8f,
-0x00,0x00,0x00,0x00,0xf9,0xff,0x80,0x10,0x00,0x00,0x00,0x00,0x04,0x00,0x41,0x8f,
-0xfc,0x03,0x50,0x7b,0x7c,0x00,0x42,0x7b,0xbc,0x00,0x44,0x7b,0xfc,0x00,0x46,0x7b,
-0x3c,0x01,0x48,0x7b,0x13,0x00,0x00,0x02,0x11,0x00,0x20,0x02,0x7c,0x01,0x4a,0x7b,
-0xbc,0x01,0x4c,0x7b,0xfc,0x01,0x4e,0x7b,0x3c,0x02,0x50,0x7b,0x7c,0x02,0x52,0x7b,
-0xbc,0x02,0x54,0x7b,0xfc,0x02,0x56,0x7b,0x3c,0x03,0x58,0x7b,0x7c,0x03,0x5c,0x7b,
-0xbc,0x03,0x5e,0x7b,0x80,0x00,0x5b,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0x60,0x03,
-0x10,0x00,0x00,0x42,0x00,0x60,0x05,0x40,0x42,0x28,0x05,0x00,0x40,0x28,0x05,0x00,
-0x00,0x60,0x85,0x40,0x04,0x00,0x81,0xac,0x08,0x00,0x82,0xac,0x0c,0x00,0x83,0xac,
-0x20,0x00,0x88,0xac,0x24,0x00,0x89,0xac,0x28,0x00,0x8a,0xac,0x2c,0x00,0x8b,0xac,
-0x30,0x00,0x8c,0xac,0x34,0x00,0x8d,0xac,0x38,0x00,0x8e,0xac,0x3c,0x00,0x8f,0xac,
-0x12,0x40,0x00,0x00,0x10,0x48,0x00,0x00,0x40,0x00,0x90,0xac,0x44,0x00,0x91,0xac,
-0x48,0x00,0x92,0xac,0x4c,0x00,0x93,0xac,0x50,0x00,0x94,0xac,0x54,0x00,0x95,0xac,
-0x58,0x00,0x96,0xac,0x5c,0x00,0x97,0xac,0x60,0x00,0x98,0xac,0x64,0x00,0x99,0xac,
-0x68,0x00,0x9c,0xac,0x6c,0x00,0x9d,0xac,0x70,0x00,0x9e,0xac,0x74,0x00,0x9f,0xac,
-0x78,0x00,0x88,0xac,0x7c,0x00,0x89,0xac,0x80,0x00,0x9f,0xac,0xf8,0xff,0x84,0x24,
-0x00,0x00,0x84,0x8c,0x00,0x00,0x00,0x00,0x08,0x00,0x84,0x24,0x84,0x00,0x86,0x8c,
-0x00,0x00,0x00,0x00,0xf9,0xff,0xc0,0x10,0x00,0x00,0x00,0x00,0x21,0xd8,0x80,0x00,
-0x01,0x00,0xba,0x24,0x04,0x00,0x61,0x8f,0xfc,0x03,0x70,0x7b,0x7c,0x00,0x62,0x7b,
-0xbc,0x00,0x64,0x7b,0xfc,0x00,0x66,0x7b,0x3c,0x01,0x68,0x7b,0x13,0x00,0x00,0x02,
-0x11,0x00,0x20,0x02,0x7c,0x01,0x6a,0x7b,0xbc,0x01,0x6c,0x7b,0xfc,0x01,0x6e,0x7b,
-0x3c,0x02,0x70,0x7b,0x7c,0x02,0x72,0x7b,0xbc,0x02,0x74,0x7b,0xfc,0x02,0x76,0x7b,
-0x3c,0x03,0x78,0x7b,0x7c,0x03,0x7c,0x7b,0xbc,0x03,0x7e,0x7b,0x80,0x00,0x7b,0x8f,
-0x00,0x00,0x00,0x00,0x08,0x00,0x60,0x03,0x00,0x60,0x9a,0x40,0x00,0x60,0x05,0x40,
-0x42,0x28,0x05,0x00,0x40,0x28,0x05,0x00,0x00,0x60,0x85,0x40,0x04,0x00,0x81,0xac,
-0x08,0x00,0x82,0xac,0x0c,0x00,0x83,0xac,0x20,0x00,0x88,0xac,0x24,0x00,0x89,0xac,
-0x28,0x00,0x8a,0xac,0x2c,0x00,0x8b,0xac,0x30,0x00,0x8c,0xac,0x34,0x00,0x8d,0xac,
-0x38,0x00,0x8e,0xac,0x3c,0x00,0x8f,0xac,0x12,0x40,0x00,0x00,0x10,0x48,0x00,0x00,
-0x40,0x00,0x90,0xac,0x44,0x00,0x91,0xac,0x48,0x00,0x92,0xac,0x4c,0x00,0x93,0xac,
-0x50,0x00,0x94,0xac,0x54,0x00,0x94,0xac,0x58,0x00,0x96,0xac,0x5c,0x00,0x96,0xac,
-0x60,0x00,0x98,0xac,0x64,0x00,0x99,0xac,0x68,0x00,0x9c,0xac,0x6c,0x00,0x9d,0xac,
-0x70,0x00,0x9e,0xac,0x78,0x00,0x88,0xac,0x7c,0x00,0x89,0xac,0x80,0x00,0x9f,0xac,
-0x84,0x00,0x80,0xac,0xf8,0xff,0x84,0x24,0x00,0x00,0x84,0x8c,0x00,0x00,0x00,0x00,
-0x08,0x00,0x84,0x24,0x84,0x00,0x86,0x8c,0xfa,0xff,0xc0,0x10,0x00,0x00,0x00,0x00,
-0x21,0xd8,0x80,0x00,0x01,0x00,0xba,0x24,0x04,0x00,0x61,0x8f,0xfc,0x03,0x70,0x7b,
-0x7c,0x00,0x62,0x7b,0xbc,0x00,0x64,0x7b,0xfc,0x00,0x66,0x7b,0x3c,0x01,0x68,0x7b,
-0x13,0x00,0x00,0x02,0x11,0x00,0x20,0x02,0x7c,0x01,0x6a,0x7b,0xbc,0x01,0x6c,0x7b,
-0xfc,0x01,0x6e,0x7b,0x3c,0x02,0x70,0x7b,0x7c,0x02,0x72,0x7b,0xbc,0x02,0x74,0x7b,
-0xfc,0x02,0x76,0x7b,0x3c,0x03,0x78,0x7b,0x7c,0x03,0x7c,0x7b,0xbc,0x03,0x7e,0x7b,
-0x80,0x00,0x7b,0x8f,0x08,0x00,0x60,0x03,0x00,0x60,0x9a,0x40,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0xc6,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x1b,0x3c,0x00,0x00,0x7b,0x27,
-0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x27,0x00,0x00,0x5b,0xaf,0x00,0x00,0x05,0x24,
-0x03,0x00,0xa4,0x24,0x00,0xa0,0x80,0x40,0x00,0xa0,0x84,0x40,0x01,0x80,0x04,0x3c,
-0x98,0x03,0x84,0x24,0x08,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x01,0x80,0x1b,0x3c,0x98,0x03,0x7b,0x27,0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x27,
-0x00,0x00,0x5b,0xaf,0x02,0x80,0x1a,0x3c,0x00,0x00,0x5a,0x27,0xfc,0x03,0x5d,0x27,
-0x02,0x80,0x1c,0x3c,0x00,0x14,0x9c,0x27,0x00,0xf0,0x08,0x3c,0x00,0x0c,0x08,0x35,
-0x00,0x60,0x88,0x40,0x02,0x80,0x04,0x3c,0x00,0x00,0x84,0x24,0xff,0x7f,0x05,0x3c,
-0xff,0xff,0xa5,0x34,0x24,0x20,0x85,0x00,0x00,0x20,0x84,0x4c,0xff,0xff,0x05,0x34,
-0x21,0x28,0xa4,0x00,0x00,0x28,0x85,0x4c,0x00,0x80,0x04,0x3c,0x00,0x00,0x84,0x24,
-0xff,0x7f,0x05,0x3c,0xff,0xff,0xa5,0x34,0x24,0x20,0x85,0x00,0x00,0x00,0x84,0x4c,
-0xff,0x7f,0x06,0x24,0x21,0x30,0xc4,0x00,0x24,0x30,0xc5,0x00,0x00,0x08,0x86,0x4c,
-0x00,0xa0,0x04,0x40,0x10,0x00,0x84,0x34,0x00,0xa0,0x84,0x40,0x01,0x80,0x1b,0x3c,
-0x24,0x04,0x7b,0x27,0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x27,0x00,0x00,0x5b,0xaf,
-0x00,0x00,0x00,0x00,0x25,0xb0,0x04,0x3c,0x44,0x00,0x84,0x34,0x00,0x00,0x85,0x84,
-0x20,0x00,0x06,0x24,0x25,0x28,0xa6,0x00,0x00,0x00,0x85,0xa4,0x01,0x80,0x1b,0x3c,
-0x54,0x04,0x7b,0x27,0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x27,0x00,0x00,0x5b,0xaf,
-0x25,0xb0,0x04,0x3c,0x44,0x00,0x84,0x34,0x00,0x00,0x85,0x8c,0x00,0x00,0x00,0x00,
-0x10,0x00,0xa5,0x30,0xfc,0xff,0xa0,0x10,0x00,0x00,0x00,0x00,0xff,0x1f,0x07,0x3c,
-0xff,0xff,0xe7,0x34,0x02,0x80,0x05,0x3c,0x88,0x7d,0xa5,0x24,0xff,0xff,0xa5,0x30,
-0x40,0xb0,0x04,0x3c,0x25,0x28,0xa4,0x00,0x24,0x28,0xa7,0x00,0x21,0x30,0x00,0x00,
-0x43,0xb0,0x02,0x3c,0x00,0x80,0x04,0x3c,0x40,0x00,0x84,0x34,0x00,0x00,0x45,0xac,
-0x04,0x00,0x46,0xac,0x08,0x00,0x44,0xac,0x4e,0x58,0x00,0x08,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x09,0x00,0x02,0x24,0xff,0xff,0x42,0x24,
-0xff,0xff,0x41,0x04,0xff,0xff,0x42,0x24,0x08,0x00,0xe0,0x03,0x01,0x00,0x42,0x24,
-0x00,0x60,0x02,0x40,0x01,0x00,0x41,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x82,0xac,0x00,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,
-0x21,0x18,0x40,0x00,0x00,0x60,0x83,0x40,0x08,0x00,0xe0,0x03,0x00,0x00,0x82,0xac,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,
-0x00,0x60,0x81,0x40,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x01,0x80,0x03,0x3c,
-0x25,0xb0,0x02,0x3c,0x44,0x05,0x63,0x24,0x18,0x03,0x42,0x34,0x00,0x00,0x43,0xac,
-0x04,0x00,0x85,0x8c,0x00,0x80,0x03,0x3c,0x01,0x00,0x02,0x24,0x25,0x28,0xa3,0x00,
-0x00,0x00,0xa4,0x8c,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x01,0x80,0x03,0x3c,
-0x25,0xb0,0x02,0x3c,0x74,0x05,0x63,0x24,0x18,0x03,0x42,0x34,0x00,0x00,0x43,0xac,
-0x04,0x00,0x82,0x8c,0x02,0x00,0x83,0x94,0x00,0x80,0x07,0x3c,0x25,0x28,0x47,0x00,
-0x00,0x00,0xa2,0x8c,0x10,0x00,0x02,0x24,0x13,0x00,0x62,0x10,0x11,0x00,0x66,0x28,
-0x06,0x00,0xc0,0x10,0x20,0x00,0x02,0x24,0x08,0x00,0x02,0x24,0x17,0x00,0x62,0x10,
-0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,0xfd,0xff,0x62,0x14,
-0x00,0x00,0x00,0x00,0x08,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0xac,
-0x04,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x25,0x10,0x47,0x00,0x00,0x00,0x42,0x8c,
-0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,0x08,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,
-0x00,0x00,0xa2,0xa4,0x04,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,0x25,0x18,0x67,0x00,
-0x00,0x00,0x62,0x94,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,0x08,0x00,0x82,0x8c,
-0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0xa0,0x04,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,
-0x25,0x18,0x67,0x00,0x00,0x00,0x62,0x90,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,
-0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf,0x02,0x80,0x11,0x3c,0x1c,0x00,0xbf,0xaf,
-0x18,0x00,0xb2,0xaf,0x10,0x00,0xb0,0xaf,0x68,0x15,0x31,0x26,0xe4,0x64,0x30,0x96,
-0x02,0x80,0x02,0x3c,0x01,0x80,0x03,0x3c,0x25,0x80,0x02,0x02,0x25,0xb0,0x02,0x3c,
-0x38,0x06,0x63,0x24,0x18,0x03,0x42,0x34,0x60,0x00,0x04,0x26,0x80,0x00,0x05,0x26,
-0x00,0x00,0x43,0xac,0xab,0x45,0x00,0x0c,0x03,0x00,0x06,0x24,0x21,0x20,0x00,0x02,
-0x21,0x28,0x00,0x00,0x97,0x45,0x00,0x0c,0x08,0x00,0x06,0x24,0xe4,0x64,0x22,0x8e,
-0x0c,0x00,0x03,0x24,0x0c,0x00,0x43,0xae,0x08,0x00,0x42,0xae,0x12,0x00,0x02,0x24,
-0x14,0x00,0x42,0xae,0x21,0x20,0x40,0x02,0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f,
-0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x8b,0x07,0x00,0x08,0x20,0x00,0xbd,0x27,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,
-0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,0x02,0x80,0x02,0x3c,0x21,0x48,0x80,0x00,
-0x68,0x15,0x48,0x24,0x21,0x38,0x00,0x00,0x21,0x28,0x27,0x01,0x00,0x00,0xa2,0x90,
-0x21,0x20,0xe8,0x00,0x01,0x00,0xe7,0x24,0x38,0x4c,0x82,0xa0,0x1e,0x00,0xa3,0x90,
-0x1e,0x00,0xe6,0x28,0x56,0x4c,0x83,0xa0,0x3c,0x00,0xa2,0x90,0x00,0x00,0x00,0x00,
-0x74,0x4c,0x82,0xa0,0x5a,0x00,0xa3,0x90,0xf3,0xff,0xc0,0x14,0x92,0x4c,0x83,0xa0,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,
-0x20,0xbd,0x03,0x3c,0x58,0x00,0x63,0x34,0x00,0x00,0x62,0x90,0x0f,0x27,0x07,0x24,
-0x20,0x00,0x42,0x34,0x00,0x00,0x62,0xa0,0xff,0xff,0xe7,0x24,0xff,0xff,0xe1,0x04,
-0xff,0xff,0xe7,0x24,0x62,0xbd,0x04,0x3c,0x24,0x10,0x82,0x34,0x00,0x00,0x40,0xa0,
-0x28,0x10,0x83,0x34,0x0c,0x11,0x86,0x34,0x0e,0x00,0x02,0x24,0x00,0x00,0x60,0xa0,
-0x00,0x11,0x85,0x34,0x00,0x00,0xc2,0xa0,0x00,0x00,0xa7,0x8c,0xdf,0xff,0x02,0x24,
-0x10,0x00,0x86,0x34,0x24,0x38,0xe2,0x00,0x49,0x0c,0x03,0x24,0xcf,0xff,0x02,0x24,
-0x00,0x00,0xc3,0xac,0x04,0x00,0x84,0x34,0x00,0x00,0xa7,0xac,0x24,0x38,0xe2,0x00,
-0x41,0x0c,0x02,0x24,0x00,0x00,0xa7,0xac,0x00,0x00,0x80,0xac,0x00,0x00,0xc2,0xac,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0xd0,0xff,0xbd,0x27,0x25,0xb0,0x03,0x3c,
-0x01,0x80,0x02,0x3c,0xb0,0x03,0x68,0x34,0x1c,0x00,0xb1,0xaf,0x18,0x03,0x63,0x34,
-0xd8,0xff,0x91,0x24,0xa0,0x08,0x42,0x24,0x00,0x00,0x62,0xac,0x28,0x00,0xbf,0xaf,
-0x00,0x00,0x11,0xad,0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x18,0x00,0xb0,0xaf,
-0x02,0x80,0x13,0x3c,0x00,0x00,0x23,0x96,0x68,0x15,0x73,0x26,0xff,0xff,0x32,0x32,
-0x40,0x10,0x02,0x3c,0x78,0x64,0x65,0x8e,0x25,0x90,0x42,0x02,0x02,0x80,0x10,0x3c,
-0x8c,0x96,0x10,0x26,0x20,0x00,0x42,0x26,0x00,0x00,0x03,0xad,0x20,0x00,0x06,0x24,
-0x00,0x00,0x02,0xad,0x21,0x38,0x00,0x02,0x0c,0x00,0x03,0xae,0x0a,0x00,0x04,0x24,
-0x64,0x01,0x00,0x0c,0x08,0x00,0x02,0xae,0x04,0x00,0x23,0x8e,0xff,0xe0,0x02,0x24,
-0x28,0x00,0x04,0x24,0x24,0x18,0x62,0x00,0x00,0x10,0x63,0x34,0x02,0x00,0x24,0xa2,
-0x04,0x00,0x23,0xae,0x0c,0x00,0x02,0x8e,0x0a,0x00,0x04,0x24,0xf8,0xff,0x42,0x24,
-0x4d,0x01,0x00,0x0c,0x00,0x00,0x22,0xa6,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x0c,0x00,0x07,0x8e,0x20,0x10,0x06,0x3c,
-0x21,0x28,0x40,0x02,0x20,0x00,0xe7,0x24,0x00,0xfe,0xc6,0x34,0xff,0xff,0xe7,0x30,
-0x01,0x00,0x11,0x24,0x0a,0x00,0x04,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xb1,0xaf,
-0xd5,0x4a,0x63,0x92,0x2a,0xb0,0x10,0x3c,0x32,0x00,0x02,0x36,0x01,0x00,0x63,0x24,
-0x00,0x00,0x43,0xa0,0x4d,0x01,0x00,0x0c,0x0a,0x00,0x04,0x24,0xc9,0x64,0x62,0x92,
-0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,0xc9,0x64,0x62,0xa2,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x01,0x00,0x10,0x36,0x00,0x00,0x11,0xa2,
-0x28,0x00,0xbf,0x8f,0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,
-0x18,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,
-0x25,0xb0,0x05,0x3c,0x01,0x80,0x03,0x3c,0x21,0x38,0x80,0x00,0x18,0x03,0xa2,0x34,
-0xe8,0x09,0x63,0x24,0x01,0x00,0x04,0x24,0x00,0x00,0x43,0xac,0x35,0x00,0xe4,0x10,
-0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x10,0x20,0x08,0xa2,0x34,0x02,0x00,0x02,0x24,
-0x83,0x00,0xe2,0x10,0x03,0x00,0x02,0x24,0x5a,0x00,0xe2,0x10,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x02,0x80,0x03,0x3c,0x00,0x00,0x44,0x8c,
-0x68,0x15,0x66,0x24,0x70,0x08,0x02,0x24,0xe0,0x08,0x03,0x24,0x74,0x4b,0xc2,0xac,
-0x40,0x08,0x02,0x24,0x78,0x4b,0xc3,0xac,0x84,0x4b,0xc2,0xac,0x78,0x08,0x03,0x24,
-0x0c,0x08,0x02,0x24,0x88,0x4b,0xc3,0xac,0x8c,0x4b,0xc2,0xac,0x10,0x08,0x03,0x24,
-0x20,0x08,0x02,0x24,0x90,0x4b,0xc3,0xac,0x94,0x4b,0xc2,0xac,0x24,0x08,0x03,0x24,
-0x58,0x08,0x02,0x24,0x98,0x4b,0xc3,0xac,0x9c,0x4b,0xc2,0xac,0x50,0x0c,0x03,0x24,
-0x54,0x0c,0x02,0x24,0xa0,0x4b,0xc3,0xac,0xa4,0x4b,0xc2,0xac,0x14,0x0c,0x03,0x24,
-0x10,0x0c,0x02,0x24,0x60,0x08,0x05,0x24,0xa8,0x4b,0xc3,0xac,0xac,0x4b,0xc2,0xac,
-0x80,0x0c,0x03,0x24,0x84,0x0c,0x02,0x24,0x00,0x01,0x84,0x30,0xb4,0x4b,0xc2,0xac,
-0x80,0x4b,0xc5,0xac,0xb0,0x4b,0xc3,0xac,0x71,0x4b,0xc0,0xa0,0x7c,0x4b,0xc5,0xac,
-0x02,0x00,0x80,0x10,0xa0,0x08,0x02,0x24,0xb8,0x08,0x02,0x24,0x08,0x00,0xe0,0x03,
-0xb8,0x4b,0xc2,0xac,0x28,0x08,0xa2,0x34,0x02,0x80,0x03,0x3c,0x00,0x00,0x44,0x8c,
-0x68,0x15,0x66,0x24,0x70,0x08,0x02,0x24,0xe0,0x08,0x03,0x24,0x74,0x4b,0xc2,0xac,
-0x44,0x08,0x02,0x24,0x78,0x4b,0xc3,0xac,0x84,0x4b,0xc2,0xac,0x78,0x08,0x03,0x24,
-0x0c,0x08,0x02,0x24,0x88,0x4b,0xc3,0xac,0x8c,0x4b,0xc2,0xac,0x14,0x08,0x03,0x24,
-0x28,0x08,0x02,0x24,0x90,0x4b,0xc3,0xac,0x94,0x4b,0xc2,0xac,0x2c,0x08,0x03,0x24,
-0x58,0x08,0x02,0x24,0x98,0x4b,0xc3,0xac,0x9c,0x4b,0xc2,0xac,0x58,0x0c,0x03,0x24,
-0x5c,0x0c,0x02,0x24,0xa0,0x4b,0xc3,0xac,0xa4,0x4b,0xc2,0xac,0x1c,0x0c,0x03,0x24,
-0x18,0x0c,0x02,0x24,0x64,0x08,0x05,0x24,0xa8,0x4b,0xc3,0xac,0xac,0x4b,0xc2,0xac,
-0x88,0x0c,0x03,0x24,0x8c,0x0c,0x02,0x24,0x00,0x01,0x84,0x30,0xb4,0x4b,0xc2,0xac,
-0x71,0x4b,0xc7,0xa0,0x80,0x4b,0xc5,0xac,0xb0,0x4b,0xc3,0xac,0x7c,0x4b,0xc5,0xac,
-0xd6,0xff,0x80,0x10,0xa4,0x08,0x02,0x24,0xbc,0x08,0x02,0x24,0x08,0x00,0xe0,0x03,
-0xb8,0x4b,0xc2,0xac,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,0xac,0x08,0x03,0x24,
-0xb8,0x4b,0x43,0xac,0x74,0x08,0x03,0x24,0xe4,0x08,0x04,0x24,0x74,0x4b,0x43,0xac,
-0x4c,0x08,0x03,0x24,0x78,0x4b,0x44,0xac,0x84,0x4b,0x43,0xac,0x7c,0x08,0x04,0x24,
-0x0c,0x08,0x03,0x24,0x88,0x4b,0x44,0xac,0x8c,0x4b,0x43,0xac,0x1c,0x08,0x04,0x24,
-0x38,0x08,0x03,0x24,0x90,0x4b,0x44,0xac,0x94,0x4b,0x43,0xac,0x3c,0x08,0x04,0x24,
-0x5c,0x08,0x03,0x24,0x98,0x4b,0x44,0xac,0x9c,0x4b,0x43,0xac,0x68,0x0c,0x04,0x24,
-0x6c,0x0c,0x03,0x24,0xa0,0x4b,0x44,0xac,0xa4,0x4b,0x43,0xac,0x2c,0x0c,0x04,0x24,
-0x28,0x0c,0x03,0x24,0x6c,0x08,0x05,0x24,0xa8,0x4b,0x44,0xac,0xac,0x4b,0x43,0xac,
-0x98,0x0c,0x04,0x24,0x9c,0x0c,0x03,0x24,0x71,0x4b,0x47,0xa0,0x80,0x4b,0x45,0xac,
-0xb0,0x4b,0x44,0xac,0xb4,0x4b,0x43,0xac,0x08,0x00,0xe0,0x03,0x7c,0x4b,0x45,0xac,
-0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,0xa8,0x08,0x03,0x24,0xb8,0x4b,0x43,0xac,
-0x74,0x08,0x03,0x24,0xe4,0x08,0x04,0x24,0x74,0x4b,0x43,0xac,0x48,0x08,0x03,0x24,
-0x78,0x4b,0x44,0xac,0x84,0x4b,0x43,0xac,0x7c,0x08,0x04,0x24,0x0c,0x08,0x03,0x24,
-0x88,0x4b,0x44,0xac,0x8c,0x4b,0x43,0xac,0x18,0x08,0x04,0x24,0x30,0x08,0x03,0x24,
-0x90,0x4b,0x44,0xac,0x94,0x4b,0x43,0xac,0x34,0x08,0x04,0x24,0x5c,0x08,0x03,0x24,
-0x98,0x4b,0x44,0xac,0x9c,0x4b,0x43,0xac,0x60,0x0c,0x04,0x24,0x64,0x0c,0x03,0x24,
-0xa0,0x4b,0x44,0xac,0xa4,0x4b,0x43,0xac,0x24,0x0c,0x04,0x24,0x20,0x0c,0x03,0x24,
-0x68,0x08,0x05,0x24,0xa8,0x4b,0x44,0xac,0xac,0x4b,0x43,0xac,0x90,0x0c,0x04,0x24,
-0x94,0x0c,0x03,0x24,0x71,0x4b,0x47,0xa0,0x80,0x4b,0x45,0xac,0xb0,0x4b,0x44,0xac,
-0xb4,0x4b,0x43,0xac,0x08,0x00,0xe0,0x03,0x7c,0x4b,0x45,0xac,0x36,0x43,0x00,0x08,
-0x21,0x18,0x00,0x00,0x20,0x00,0x62,0x2c,0x06,0x00,0x40,0x10,0x00,0x00,0x00,0x00,
-0x06,0x10,0x64,0x00,0x01,0x00,0x42,0x30,0xfa,0xff,0x40,0x10,0x01,0x00,0x63,0x24,
-0xff,0xff,0x63,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,0xd8,0xff,0xbd,0x27,
-0x25,0xb0,0x02,0x3c,0x18,0x00,0xb2,0xaf,0x21,0x90,0x82,0x00,0xff,0xff,0x02,0x24,
-0x1c,0x00,0xb3,0xaf,0x14,0x00,0xb1,0xaf,0x20,0x00,0xbf,0xaf,0x10,0x00,0xb0,0xaf,
-0x21,0x88,0xa0,0x00,0x21,0x20,0xa0,0x00,0x21,0x18,0x40,0x02,0x10,0x00,0xa2,0x10,
-0x21,0x98,0xc0,0x00,0x00,0x00,0x50,0x8e,0x31,0x43,0x00,0x0c,0x00,0x00,0x00,0x00,
-0x04,0x10,0x53,0x00,0x27,0x18,0x11,0x00,0x25,0x18,0x62,0x00,0x24,0x18,0x70,0x00,
-0x00,0x00,0x43,0xae,0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,
-0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x28,0x00,0xbd,0x27,
-0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x28,0x00,0xbd,0x27,0x00,0x00,0x66,0xac,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c,0x21,0x30,0x80,0x00,0xec,0x60,0x44,0x8c,
-0x3d,0x43,0x00,0x08,0xff,0xff,0x05,0x24,0xe0,0xff,0xbd,0x27,0x25,0xb0,0x02,0x3c,
-0x18,0x00,0xbf,0xaf,0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x21,0x20,0x82,0x00,
-0x00,0x00,0x90,0x8c,0x21,0x88,0xa0,0x00,0x31,0x43,0x00,0x0c,0x21,0x20,0xa0,0x00,
-0x24,0x80,0x11,0x02,0x06,0x10,0x50,0x00,0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0xd0,0xff,0xbd,0x27,
-0x14,0x00,0xb1,0xaf,0x02,0x80,0x11,0x3c,0x28,0x00,0xbf,0xaf,0x20,0x00,0xb4,0xaf,
-0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf,0x24,0x00,0xb5,0xaf,0x10,0x00,0xb0,0xaf,
-0x68,0x15,0x31,0x26,0x98,0x4b,0x22,0x8e,0x25,0xb0,0x12,0x3c,0x24,0x08,0x53,0x36,
-0x21,0x10,0x52,0x00,0x00,0x00,0x70,0x8e,0x00,0x00,0x55,0x8c,0x7f,0x80,0x03,0x3c,
-0xff,0x7f,0x02,0x3c,0xff,0xff,0x63,0x34,0xff,0xff,0x42,0x34,0x24,0x10,0x02,0x02,
-0x24,0x18,0xa3,0x02,0xc0,0x25,0x04,0x00,0x25,0x18,0x64,0x00,0x00,0x80,0x14,0x3c,
-0x00,0x00,0x62,0xae,0x01,0x00,0x04,0x24,0x84,0x0a,0x00,0x0c,0x25,0xa8,0x74,0x00,
-0x98,0x4b,0x22,0x8e,0x25,0x80,0x14,0x02,0x01,0x00,0x04,0x24,0x21,0x10,0x52,0x00,
-0x00,0x00,0x55,0xac,0x84,0x0a,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0xae,
-0x84,0x0a,0x00,0x0c,0x01,0x00,0x04,0x24,0xb8,0x4b,0x24,0x8e,0x0f,0x00,0x05,0x3c,
-0x28,0x00,0xbf,0x8f,0x24,0x00,0xb5,0x8f,0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f,
-0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0xff,0xff,0xa5,0x34,
-0x68,0x43,0x00,0x08,0x30,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf,
-0x02,0x80,0x11,0x3c,0x10,0x00,0xb0,0xaf,0x18,0x00,0xbf,0xaf,0x68,0x15,0x27,0x26,
-0x73,0x4b,0xe5,0x90,0x01,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c,0xb0,0x0e,0x63,0x24,
-0x18,0x03,0x42,0x34,0x02,0x00,0x06,0x24,0x00,0x00,0x43,0xac,0x34,0x00,0xa6,0x10,
-0x21,0x80,0x80,0x00,0x03,0x00,0x03,0x24,0x3a,0x00,0xa3,0x10,0x2e,0x00,0x02,0x2e,
-0x10,0x00,0x02,0x2e,0x07,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0xff,0x00,0x04,0x32,
-0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x79,0x43,0x00,0x08,
-0x20,0x00,0xbd,0x27,0xfa,0xff,0xa6,0x14,0xff,0x00,0x04,0x32,0x71,0x4b,0xe4,0x90,
-0x01,0x00,0x02,0x24,0x33,0x00,0x82,0x10,0x02,0x00,0x82,0x28,0x38,0x00,0x40,0x14,
-0x00,0x00,0x00,0x00,0x38,0x00,0x85,0x10,0x68,0x15,0x22,0x26,0x2e,0x00,0x83,0x10,
-0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x24,0x68,0x43,0x00,0x0c,0xff,0xff,0x05,0x24,
-0xff,0xfc,0x06,0x3c,0xff,0xff,0xc6,0x34,0x24,0x30,0x46,0x00,0x00,0x08,0x04,0x24,
-0x3d,0x43,0x00,0x0c,0xff,0xff,0x05,0x24,0x68,0x15,0x22,0x26,0x71,0x4b,0x44,0x90,
-0x01,0x00,0x03,0x24,0x07,0x00,0x83,0x10,0x02,0x00,0x82,0x28,0x2c,0x00,0x40,0x14,
-0x02,0x00,0x02,0x24,0x2c,0x00,0x82,0x10,0x03,0x00,0x02,0x24,0xdb,0xff,0x82,0x14,
-0x00,0x00,0x00,0x00,0x68,0x15,0x22,0x26,0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x3c,
-0x3d,0x43,0x00,0x0c,0x21,0x30,0x00,0x00,0xc2,0x43,0x00,0x08,0xff,0x00,0x04,0x32,
-0x25,0x00,0x82,0x2c,0xcc,0xff,0x40,0x14,0x03,0x00,0x03,0x24,0x18,0x00,0xbf,0x8f,
-0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,
-0x20,0x00,0xbd,0x27,0xc7,0xff,0x40,0x14,0x10,0x00,0x02,0x2e,0x18,0x00,0xbf,0x8f,
-0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,
-0x20,0x00,0xbd,0x27,0x68,0x15,0x22,0x26,0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x3c,
-0x3d,0x43,0x00,0x0c,0x0f,0x00,0x06,0x24,0xd4,0x43,0x00,0x08,0x00,0x08,0x04,0x24,
-0xcc,0xff,0x80,0x14,0x68,0x15,0x22,0x26,0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x24,
-0x3d,0x43,0x00,0x0c,0x0f,0x00,0x06,0x24,0xd4,0x43,0x00,0x08,0x00,0x08,0x04,0x24,
-0xb2,0xff,0x80,0x14,0x00,0x00,0x00,0x00,0x68,0x15,0x22,0x26,0x74,0x4b,0x44,0x8c,
-0x0f,0x00,0x05,0x24,0x3d,0x43,0x00,0x0c,0x21,0x30,0x00,0x00,0xc2,0x43,0x00,0x08,
-0xff,0x00,0x04,0x32,0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf,0x02,0x80,0x11,0x3c,
-0x68,0x15,0x28,0x26,0x73,0x4b,0x06,0x91,0x01,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c,
-0x5c,0x10,0x63,0x24,0x18,0x03,0x42,0x34,0x02,0x00,0x07,0x24,0x18,0x00,0xb2,0xaf,
-0x10,0x00,0xb0,0xaf,0x1c,0x00,0xbf,0xaf,0x00,0x00,0x43,0xac,0x21,0x90,0xa0,0x00,
-0x39,0x00,0xc7,0x10,0xff,0x00,0x90,0x30,0x03,0x00,0x03,0x24,0x3f,0x00,0xc3,0x10,
-0x2e,0x00,0x02,0x2e,0x10,0x00,0x02,0x2e,0x0c,0x00,0x40,0x10,0x00,0x00,0x00,0x00,
-0x0f,0x00,0x04,0x3c,0xff,0xff,0x84,0x34,0x24,0x20,0x44,0x02,0x00,0x15,0x10,0x00,
-0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,
-0x25,0x20,0x44,0x00,0x63,0x43,0x00,0x08,0x20,0x00,0xbd,0x27,0xf5,0xff,0xc7,0x14,
-0x0f,0x00,0x04,0x3c,0x71,0x4b,0x04,0x91,0x01,0x00,0x02,0x24,0x33,0x00,0x82,0x10,
-0x02,0x00,0x82,0x28,0x38,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0x38,0x00,0x86,0x10,
-0x68,0x15,0x22,0x26,0x2e,0x00,0x83,0x10,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x24,
-0x68,0x43,0x00,0x0c,0xff,0xff,0x05,0x24,0xff,0xfc,0x06,0x3c,0xff,0xff,0xc6,0x34,
-0x24,0x30,0x46,0x00,0x00,0x08,0x04,0x24,0x3d,0x43,0x00,0x0c,0xff,0xff,0x05,0x24,
-0x68,0x15,0x22,0x26,0x71,0x4b,0x44,0x90,0x01,0x00,0x03,0x24,0x07,0x00,0x83,0x10,
-0x02,0x00,0x82,0x28,0x2c,0x00,0x40,0x14,0x02,0x00,0x02,0x24,0x2c,0x00,0x82,0x10,
-0x03,0x00,0x02,0x24,0xd6,0xff,0x82,0x14,0x00,0x00,0x00,0x00,0x68,0x15,0x22,0x26,
-0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x3c,0x3d,0x43,0x00,0x0c,0x21,0x30,0x00,0x00,
-0x2f,0x44,0x00,0x08,0x0f,0x00,0x04,0x3c,0x25,0x00,0x02,0x2e,0xc7,0xff,0x40,0x14,
-0x03,0x00,0x03,0x24,0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0xc1,0xff,0x40,0x14,
-0x00,0x00,0x00,0x00,0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0x68,0x15,0x22,0x26,
-0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x3c,0x3d,0x43,0x00,0x0c,0x0f,0x00,0x06,0x24,
-0x46,0x44,0x00,0x08,0x00,0x08,0x04,0x24,0xcc,0xff,0x80,0x14,0x68,0x15,0x22,0x26,
-0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x24,0x3d,0x43,0x00,0x0c,0x0f,0x00,0x06,0x24,
-0x46,0x44,0x00,0x08,0x00,0x08,0x04,0x24,0xad,0xff,0x80,0x14,0x00,0x00,0x00,0x00,
-0x68,0x15,0x22,0x26,0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x24,0x3d,0x43,0x00,0x0c,
-0x21,0x30,0x00,0x00,0x2f,0x44,0x00,0x08,0x0f,0x00,0x04,0x3c,0xe8,0xff,0xbd,0x27,
-0x10,0x00,0xb0,0xaf,0x21,0x80,0x80,0x00,0x14,0x00,0xbf,0xaf,0x79,0x43,0x00,0x0c,
-0x21,0x20,0x00,0x00,0x40,0x01,0x44,0x34,0x21,0x18,0x40,0x00,0x1f,0x00,0x02,0x2e,
-0x00,0x23,0x04,0x00,0x10,0x00,0x40,0x10,0x10,0x00,0x05,0x2e,0x00,0x01,0x64,0x34,
-0x06,0x00,0xa0,0x10,0x00,0x23,0x04,0x00,0x21,0x10,0x00,0x02,0x14,0x00,0xbf,0x8f,
-0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27,0x63,0x43,0x00,0x0c,
-0xf1,0xff,0x10,0x26,0x21,0x10,0x00,0x02,0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f,
-0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27,0x63,0x43,0x00,0x0c,0xe2,0xff,0x10,0x26,
-0x21,0x10,0x00,0x02,0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,
-0x18,0x00,0xbd,0x27,0x25,0xb0,0x02,0x3c,0x27,0x38,0x05,0x00,0x21,0x40,0x82,0x00,
-0xff,0xff,0x02,0x24,0x07,0x00,0xa2,0x10,0x25,0x38,0xe6,0x00,0x00,0x00,0x02,0x8d,
-0x00,0x00,0x00,0x00,0x24,0x10,0xe2,0x00,0x00,0x00,0x02,0xad,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xad,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x01,0x80,0x02,0x3c,0x25,0xb0,0x03,0x3c,0xe8,0x12,0x42,0x24,0x18,0x03,0x63,0x34,
-0xd8,0xff,0xbd,0x27,0x00,0x00,0x62,0xac,0x0f,0x00,0x02,0x3c,0x14,0x00,0xb1,0xaf,
-0xff,0xff,0x42,0x34,0x21,0x88,0xa0,0x00,0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf,
-0x20,0x00,0xbf,0xaf,0x10,0x00,0xb0,0xaf,0x21,0x90,0xc0,0x00,0x21,0x28,0xc0,0x00,
-0x0a,0x00,0x22,0x12,0x21,0x98,0x80,0x00,0xac,0x43,0x00,0x0c,0x00,0x00,0x00,0x00,
-0x21,0x20,0x20,0x02,0x31,0x43,0x00,0x0c,0x21,0x80,0x40,0x00,0x04,0x10,0x52,0x00,
-0x27,0x28,0x11,0x00,0x25,0x28,0xa2,0x00,0x24,0x28,0xb0,0x00,0xff,0x00,0x64,0x32,
-0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x17,0x44,0x00,0x08,0x28,0x00,0xbd,0x27,0x01,0x80,0x03,0x3c,
-0x25,0xb0,0x02,0x3c,0x74,0x13,0x63,0x24,0x18,0x03,0x42,0x34,0xe0,0xff,0xbd,0x27,
-0x00,0x00,0x43,0xac,0x18,0x00,0xbf,0xaf,0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,
-0xac,0x43,0x00,0x0c,0x21,0x88,0xa0,0x00,0x21,0x80,0x40,0x00,0x31,0x43,0x00,0x0c,
-0x21,0x20,0x20,0x02,0x24,0x80,0x11,0x02,0x06,0x10,0x50,0x00,0x18,0x00,0xbf,0x8f,
-0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0xc8,0xff,0xbd,0x27,0x2c,0x00,0xb1,0xaf,0xff,0xff,0x05,0x24,0x21,0x88,0x80,0x00,
-0x02,0x00,0x06,0x24,0x10,0x00,0xa4,0x27,0x34,0x00,0xbf,0xaf,0x30,0x00,0xb2,0xaf,
-0x97,0x45,0x00,0x0c,0x28,0x00,0xb0,0xaf,0x08,0x00,0x30,0x96,0x02,0x80,0x02,0x3c,
-0x21,0x28,0x00,0x00,0x25,0x80,0x02,0x02,0x21,0x20,0x00,0x02,0x97,0x45,0x00,0x0c,
-0x10,0x00,0x06,0x24,0x20,0x00,0x02,0x96,0x24,0x00,0x04,0x26,0x10,0x00,0xa5,0x27,
-0x03,0xff,0x42,0x30,0xc8,0x00,0x42,0x34,0x20,0x00,0x02,0xa6,0x9f,0x45,0x00,0x0c,
-0x06,0x00,0x06,0x24,0x25,0xb0,0x03,0x3c,0x50,0x00,0x62,0x34,0x00,0x00,0x44,0x8c,
-0x54,0x00,0x65,0x34,0x58,0x00,0x66,0x34,0x18,0x00,0xa4,0xaf,0x00,0x00,0xa2,0x8c,
-0x5c,0x00,0x63,0x34,0x2a,0x00,0x04,0x26,0x1c,0x00,0xa2,0xaf,0x00,0x00,0xc7,0x8c,
-0x18,0x00,0xa5,0x27,0x06,0x00,0x06,0x24,0x20,0x00,0xa7,0xaf,0x00,0x00,0x62,0x8c,
-0x1a,0x00,0x12,0x24,0x9f,0x45,0x00,0x0c,0x24,0x00,0xa2,0xaf,0x30,0x00,0x04,0x26,
-0x20,0x00,0xa5,0x27,0x9f,0x45,0x00,0x0c,0x06,0x00,0x06,0x24,0x13,0x00,0x03,0x24,
-0x14,0x00,0x23,0xae,0x0c,0x00,0x32,0xae,0x08,0x00,0x05,0x8e,0x04,0x00,0x04,0x8e,
-0xff,0xdf,0x02,0x3c,0x14,0x00,0x06,0x8e,0xff,0xff,0x42,0x34,0x10,0x00,0x07,0x8e,
-0xff,0xe0,0x03,0x24,0x24,0x28,0xa2,0x00,0x00,0x40,0x02,0x3c,0x24,0x20,0x83,0x00,
-0x25,0x28,0xa2,0x00,0xff,0x81,0x03,0x24,0xfe,0xff,0x02,0x3c,0x24,0x30,0xc3,0x00,
-0xff,0xff,0x42,0x34,0x00,0x12,0x84,0x34,0x00,0x80,0x03,0x3c,0x24,0x20,0x82,0x00,
-0x25,0x38,0xe3,0x00,0x00,0x26,0xc6,0x34,0x80,0x00,0xa5,0x34,0x20,0x00,0x02,0x24,
-0x00,0x00,0x12,0xa6,0x10,0x00,0x07,0xae,0x02,0x00,0x02,0xa2,0x14,0x00,0x06,0xae,
-0x04,0x00,0x04,0xae,0x08,0x00,0x05,0xae,0x34,0x00,0xbf,0x8f,0x30,0x00,0xb2,0x8f,
-0x2c,0x00,0xb1,0x8f,0x28,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27,
-0x93,0x45,0x00,0x08,0xff,0x00,0xa5,0x30,0x00,0x00,0x85,0xa0,0xff,0xff,0xc6,0x24,
-0x01,0x00,0x84,0x24,0xfc,0xff,0xc0,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x05,0x00,0xc0,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xac,
-0xff,0xff,0xc6,0x24,0xfd,0xff,0xc0,0x14,0x04,0x00,0x84,0x24,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x21,0x38,0x80,0x00,0x08,0x00,0xc0,0x10,0xff,0xff,0xc3,0x24,
-0xff,0xff,0x06,0x24,0x00,0x00,0xa2,0x90,0xff,0xff,0x63,0x24,0x01,0x00,0xa5,0x24,
-0x00,0x00,0xe2,0xa0,0xfb,0xff,0x66,0x14,0x01,0x00,0xe7,0x24,0x08,0x00,0xe0,0x03,
-0x21,0x10,0x80,0x00,0x21,0x38,0x80,0x00,0x08,0x00,0xc0,0x10,0xff,0xff,0xc3,0x24,
-0xff,0xff,0x06,0x24,0x00,0x00,0xa2,0x8c,0xff,0xff,0x63,0x24,0x04,0x00,0xa5,0x24,
-0x00,0x00,0xe2,0xac,0xfb,0xff,0x66,0x14,0x04,0x00,0xe7,0x24,0x08,0x00,0xe0,0x03,
-0x21,0x10,0x80,0x00,0x2b,0x10,0xa4,0x00,0x0d,0x00,0x40,0x14,0xff,0xff,0x02,0x24,
-0xff,0xff,0xc6,0x24,0x08,0x00,0xc2,0x10,0x21,0x18,0x80,0x00,0xff,0xff,0x07,0x24,
-0x00,0x00,0xa2,0x90,0xff,0xff,0xc6,0x24,0x01,0x00,0xa5,0x24,0x00,0x00,0x62,0xa0,
-0xfb,0xff,0xc7,0x14,0x01,0x00,0x63,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x80,0x00,
-0x21,0x28,0xa6,0x00,0x21,0x18,0x86,0x00,0xff,0xff,0xc6,0x24,0xfa,0xff,0xc2,0x10,
-0x00,0x00,0x00,0x00,0xff,0xff,0x07,0x24,0xff,0xff,0xa5,0x24,0x00,0x00,0xa2,0x90,
-0xff,0xff,0x63,0x24,0xff,0xff,0xc6,0x24,0xfb,0xff,0xc7,0x14,0x00,0x00,0x62,0xa0,
-0x08,0x00,0xe0,0x03,0x21,0x10,0x80,0x00,0x0c,0x00,0xc0,0x10,0x00,0x00,0x00,0x00,
-0x00,0x00,0x82,0x90,0x00,0x00,0xa3,0x90,0x01,0x00,0x84,0x24,0x23,0x10,0x43,0x00,
-0x00,0x16,0x02,0x00,0x03,0x16,0x02,0x00,0x04,0x00,0x40,0x14,0x01,0x00,0xa5,0x24,
-0xff,0xff,0xc6,0x24,0xf6,0xff,0xc0,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,
-0x21,0x10,0xc0,0x00,0xea,0x45,0x00,0x08,0x21,0x18,0x86,0x00,0x00,0x00,0x82,0x90,
-0x00,0x00,0x00,0x00,0x04,0x00,0x45,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0x84,0x24,
-0xfa,0xff,0x83,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x80,0x00,
-0x09,0x00,0xc0,0x10,0xff,0xff,0xc3,0x24,0xff,0x00,0xa5,0x30,0xff,0xff,0x06,0x24,
-0x00,0x00,0x82,0x90,0xff,0xff,0x63,0x24,0x05,0x00,0x45,0x10,0x01,0x00,0x84,0x24,
-0xfb,0xff,0x66,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0xff,0xff,0x82,0x24,0x21,0x38,0x00,0x00,0x1f,0x00,0xc0,0x10,
-0x21,0x18,0x00,0x00,0x02,0x80,0x02,0x3c,0x80,0x95,0x4b,0x24,0x00,0x00,0x87,0x90,
-0x00,0x00,0xa3,0x90,0xff,0xff,0xc6,0x24,0x01,0x00,0x84,0x24,0x21,0x10,0xeb,0x00,
-0x16,0x00,0xe0,0x10,0x01,0x00,0xa5,0x24,0x14,0x00,0x60,0x10,0x21,0x48,0x6b,0x00,
-0x10,0x00,0xe3,0x10,0x20,0x00,0xe8,0x24,0x00,0x00,0x42,0x90,0x00,0x00,0x00,0x00,
-0x01,0x00,0x42,0x30,0x02,0x00,0x40,0x10,0x20,0x00,0x6a,0x24,0xff,0x00,0x07,0x31,
-0x00,0x00,0x22,0x91,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x30,0x02,0x00,0x40,0x10,
-0xff,0x00,0xe7,0x30,0xff,0x00,0x43,0x31,0xff,0x00,0x63,0x30,0x03,0x00,0xe3,0x14,
-0x00,0x00,0x00,0x00,0xe5,0xff,0xc0,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,
-0x23,0x10,0xe3,0x00,0x21,0x18,0x80,0x00,0x00,0x00,0xa2,0x90,0x01,0x00,0xa5,0x24,
-0x00,0x00,0x82,0xa0,0xfc,0xff,0x40,0x14,0x01,0x00,0x84,0x24,0x08,0x00,0xe0,0x03,
-0x21,0x10,0x60,0x00,0x21,0x38,0x80,0x00,0xff,0xff,0x03,0x24,0xff,0xff,0xc6,0x24,
-0x06,0x00,0xc3,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0x90,0x01,0x00,0xa5,0x24,
-0x00,0x00,0x82,0xa0,0xf9,0xff,0x40,0x14,0x01,0x00,0x84,0x24,0x08,0x00,0xe0,0x03,
-0x21,0x10,0xe0,0x00,0x00,0x00,0x82,0x80,0x39,0x46,0x00,0x08,0x21,0x18,0x80,0x00,
-0x01,0x00,0x84,0x24,0x00,0x00,0x82,0x80,0x00,0x00,0x00,0x00,0xfc,0xff,0x40,0x14,
-0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0x90,0x01,0x00,0xa5,0x24,0x00,0x00,0x82,0xa0,
-0xfc,0xff,0x40,0x14,0x01,0x00,0x84,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,
-0x12,0x00,0xc0,0x10,0x21,0x18,0x80,0x00,0x00,0x00,0x82,0x80,0x4a,0x46,0x00,0x08,
-0x00,0x00,0x00,0x00,0x01,0x00,0x84,0x24,0x00,0x00,0x82,0x80,0x00,0x00,0x00,0x00,
-0xfc,0xff,0x40,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0x90,0x01,0x00,0xa5,0x24,
-0x00,0x00,0x82,0xa0,0x05,0x00,0x40,0x10,0x01,0x00,0x84,0x24,0xff,0xff,0xc6,0x24,
-0xf9,0xff,0xc0,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xa0,0x08,0x00,0xe0,0x03,
-0x21,0x10,0x60,0x00,0x00,0x00,0x83,0x90,0x00,0x00,0xa2,0x90,0x01,0x00,0x84,0x24,
-0x23,0x10,0x62,0x00,0x00,0x16,0x02,0x00,0x03,0x16,0x02,0x00,0x03,0x00,0x40,0x14,
-0x01,0x00,0xa5,0x24,0xf7,0xff,0x60,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x21,0x10,0x00,0x00,0x0b,0x00,0xc0,0x10,0x00,0x00,0x00,0x00,
-0x00,0x00,0xa2,0x90,0x00,0x00,0x83,0x90,0xff,0xff,0xc6,0x24,0x23,0x10,0x62,0x00,
-0x00,0x16,0x02,0x00,0x03,0x16,0x02,0x00,0x03,0x00,0x40,0x14,0x01,0x00,0xa5,0x24,
-0xf5,0xff,0x60,0x14,0x01,0x00,0x84,0x24,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x00,0x00,0x83,0x80,0x00,0x2e,0x05,0x00,0x21,0x10,0x80,0x00,0x7b,0x46,0x00,0x08,
-0x03,0x2e,0x05,0x00,0x07,0x00,0x60,0x10,0x01,0x00,0x42,0x24,0x00,0x00,0x43,0x80,
-0x00,0x00,0x00,0x00,0xfb,0xff,0x65,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x00,0x00,0x82,0x80,
-0x87,0x46,0x00,0x08,0x21,0x18,0x80,0x00,0x01,0x00,0x63,0x24,0x00,0x00,0x62,0x80,
-0x00,0x00,0x00,0x00,0xfc,0xff,0x40,0x14,0x23,0x10,0x64,0x00,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0xe0,0xff,0xbd,0x27,0x10,0x00,0xb0,0xaf,0x21,0x80,0xa0,0x00,
-0x14,0x00,0xb1,0xaf,0x18,0x00,0xbf,0xaf,0x21,0x88,0x80,0x00,0x81,0x46,0x00,0x0c,
-0x00,0x86,0x10,0x00,0x21,0x18,0x51,0x00,0x03,0x86,0x10,0x00,0x00,0x00,0x62,0x80,
-0x00,0x00,0x00,0x00,0x0a,0x00,0x50,0x10,0x21,0x10,0x60,0x00,0xff,0xff,0x63,0x24,
-0x2b,0x10,0x71,0x00,0xf9,0xff,0x40,0x10,0x21,0x10,0x00,0x00,0x18,0x00,0xbf,0x8f,
-0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,
-0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,
-0x20,0x00,0xbd,0x27,0x21,0x30,0x80,0x00,0x0d,0x00,0xa0,0x10,0xff,0xff,0xa3,0x24,
-0x00,0x00,0x82,0x80,0x00,0x00,0x00,0x00,0x09,0x00,0x40,0x10,0x00,0x00,0x00,0x00,
-0xff,0xff,0x05,0x24,0xff,0xff,0x63,0x24,0x05,0x00,0x65,0x10,0x01,0x00,0xc6,0x24,
-0x00,0x00,0xc2,0x80,0x00,0x00,0x00,0x00,0xfa,0xff,0x40,0x14,0x00,0x00,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x23,0x10,0xc4,0x00,0x00,0x00,0x82,0x90,0x00,0x00,0x00,0x00,
-0x19,0x00,0x40,0x10,0x21,0x40,0x00,0x00,0x00,0x00,0xa9,0x80,0x00,0x00,0x00,0x00,
-0x17,0x00,0x20,0x11,0x21,0x30,0xa0,0x00,0x00,0x3e,0x02,0x00,0x03,0x3e,0x07,0x00,
-0x21,0x18,0x20,0x01,0x15,0x00,0xe3,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0xc6,0x24,
-0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00,0x00,0x1e,0x02,0x00,0x03,0x1e,0x03,0x00,
-0xf8,0xff,0x60,0x14,0x00,0x16,0x02,0x00,0x03,0x16,0x02,0x00,0x06,0x00,0x40,0x10,
-0x00,0x00,0x00,0x00,0x01,0x00,0x84,0x24,0x00,0x00,0x82,0x90,0x00,0x00,0x00,0x00,
-0xeb,0xff,0x40,0x14,0x01,0x00,0x08,0x25,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x01,
-0x00,0x00,0xa2,0x90,0xcc,0x46,0x00,0x08,0x00,0x16,0x02,0x00,0x00,0x00,0xc2,0x90,
-0xcc,0x46,0x00,0x08,0x00,0x16,0x02,0x00,0x00,0x00,0x87,0x90,0x00,0x00,0x00,0x00,
-0x14,0x00,0xe0,0x10,0x21,0x10,0x80,0x00,0x00,0x00,0xa4,0x90,0x00,0x00,0x00,0x00,
-0x00,0x1e,0x04,0x00,0x03,0x1e,0x03,0x00,0x09,0x00,0x60,0x10,0x21,0x30,0xa0,0x00,
-0x00,0x3e,0x07,0x00,0x03,0x3e,0x07,0x00,0x0b,0x00,0xe3,0x10,0x01,0x00,0xc6,0x24,
-0x00,0x00,0xc3,0x80,0x00,0x00,0x00,0x00,0xfb,0xff,0x60,0x14,0x00,0x00,0x00,0x00,
-0x01,0x00,0x42,0x24,0x00,0x00,0x47,0x90,0x00,0x00,0x00,0x00,0xf0,0xff,0xe0,0x14,
-0x00,0x00,0x00,0x00,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x18,0x00,0xbf,0xaf,
-0x21,0x80,0x80,0x00,0x1d,0x00,0x80,0x10,0x21,0x88,0xa0,0x00,0xb8,0x46,0x00,0x0c,
-0x21,0x20,0x00,0x02,0x21,0x80,0x02,0x02,0x00,0x00,0x02,0x82,0x21,0x28,0x20,0x02,
-0x21,0x20,0x00,0x02,0x22,0x00,0x40,0x10,0x21,0x18,0x00,0x00,0xdc,0x46,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x10,0x21,0x18,0x40,0x00,0x00,0x00,0x42,0x80,
-0x00,0x00,0x00,0x00,0x0a,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c,
-0xa8,0x96,0x43,0xac,0x21,0x18,0x00,0x02,0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x21,0x10,0x60,0x00,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,
-0x00,0x00,0x60,0xa0,0x0d,0x47,0x00,0x08,0x01,0x00,0x63,0x24,0x02,0x80,0x02,0x3c,
-0xa8,0x96,0x50,0x8c,0x00,0x00,0x00,0x00,0xf3,0xff,0x00,0x12,0x21,0x18,0x00,0x00,
-0xb8,0x46,0x00,0x0c,0x21,0x20,0x00,0x02,0x21,0x80,0x02,0x02,0x00,0x00,0x02,0x82,
-0x21,0x28,0x20,0x02,0x21,0x20,0x00,0x02,0xe0,0xff,0x40,0x14,0x21,0x18,0x00,0x00,
-0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x02,0x80,0x02,0x3c,
-0xa8,0x96,0x40,0xac,0x20,0x00,0xbd,0x27,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,
-0xe0,0xff,0xbd,0x27,0x18,0x00,0xb2,0xaf,0x14,0x00,0xb1,0xaf,0x1c,0x00,0xbf,0xaf,
-0x10,0x00,0xb0,0xaf,0x00,0x00,0x90,0x8c,0x21,0x90,0x80,0x00,0x21,0x88,0xa0,0x00,
-0x21,0x18,0x00,0x00,0x0f,0x00,0x00,0x12,0x21,0x20,0x00,0x02,0xb8,0x46,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x21,0x80,0x02,0x02,0x00,0x00,0x02,0x82,0x21,0x28,0x20,0x02,
-0x21,0x20,0x00,0x02,0x07,0x00,0x40,0x10,0x21,0x18,0x00,0x00,0xdc,0x46,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x21,0x18,0x40,0x00,0x09,0x00,0x40,0x14,0x00,0x00,0x42,0xae,
-0x21,0x18,0x00,0x02,0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x21,0x10,0x60,0x00,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,
-0x00,0x00,0x42,0x80,0x00,0x00,0x00,0x00,0xf5,0xff,0x40,0x10,0x01,0x00,0x64,0x24,
-0x00,0x00,0x60,0xa0,0x46,0x47,0x00,0x08,0x00,0x00,0x44,0xae,0xd8,0xff,0xbd,0x27,
-0x14,0x00,0xb1,0xaf,0x21,0x88,0x80,0x00,0x21,0x20,0xa0,0x00,0x1c,0x00,0xb3,0xaf,
-0x18,0x00,0xb2,0xaf,0x20,0x00,0xbf,0xaf,0x10,0x00,0xb0,0xaf,0x81,0x46,0x00,0x0c,
-0x21,0x98,0xa0,0x00,0x21,0x90,0x40,0x00,0x08,0x00,0x40,0x16,0x21,0x10,0x20,0x02,
-0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x28,0x00,0xbd,0x27,0x81,0x46,0x00,0x0c,
-0x21,0x20,0x20,0x02,0x21,0x80,0x40,0x00,0x2a,0x10,0x52,0x00,0x0a,0x00,0x40,0x14,
-0x00,0x00,0x00,0x00,0x21,0x20,0x20,0x02,0x21,0x28,0x60,0x02,0x21,0x30,0x40,0x02,
-0xd4,0x45,0x00,0x0c,0xff,0xff,0x10,0x26,0x0b,0x00,0x40,0x10,0x2a,0x18,0x12,0x02,
-0xf8,0xff,0x60,0x10,0x01,0x00,0x31,0x26,0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f,
-0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00,
-0x08,0x00,0xe0,0x03,0x28,0x00,0xbd,0x27,0x62,0x47,0x00,0x08,0x21,0x10,0x20,0x02,
-0x01,0x80,0x02,0x3c,0xc0,0xff,0xbd,0x27,0x08,0x1e,0x44,0x24,0x25,0xb0,0x02,0x3c,
-0x28,0x00,0xb4,0xaf,0x02,0x80,0x03,0x3c,0x25,0xb0,0x14,0x3c,0x18,0x03,0x42,0x34,
-0x38,0x00,0xbe,0xaf,0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x2c,0x00,0xb5,0xaf,
-0x24,0x00,0xb3,0xaf,0x3c,0x00,0xbf,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,
-0x18,0x00,0xb0,0xaf,0x68,0x15,0x73,0x24,0x00,0x00,0x44,0xac,0x02,0x80,0x16,0x3c,
-0x02,0x80,0x15,0x3c,0xc4,0x02,0x9e,0x36,0x64,0x03,0x97,0x36,0x01,0x80,0x04,0x3c,
-0x08,0x1e,0x82,0x24,0x18,0x03,0x83,0x36,0x00,0x00,0x62,0xac,0xa0,0x02,0x87,0x36,
-0x00,0x00,0xe4,0x8c,0xd8,0x63,0x63,0x8e,0xff,0x0f,0x02,0x3c,0xff,0xff,0x46,0x34,
-0x24,0x80,0x86,0x00,0x01,0x00,0x05,0x3c,0x01,0x00,0x63,0x24,0x2b,0x10,0xb0,0x00,
-0x07,0x00,0x40,0x10,0xd8,0x63,0x63,0xae,0xa4,0x02,0x82,0x36,0x00,0x00,0x51,0x8c,
-0x00,0xb0,0x03,0x3c,0x25,0x80,0x03,0x02,0x00,0x00,0x11,0xae,0x00,0x00,0xe0,0xac,
-0xb0,0x02,0x84,0x36,0x00,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x24,0x80,0x46,0x00,
-0x2b,0x18,0xb0,0x00,0x08,0x00,0x60,0x10,0xc0,0x02,0x82,0x36,0x00,0xb0,0x02,0x3c,
-0x25,0x80,0x02,0x02,0x00,0x00,0x11,0x8e,0xb4,0x02,0x82,0x36,0x00,0x00,0x51,0xac,
-0x00,0x00,0x80,0xac,0xc0,0x02,0x82,0x36,0x00,0x00,0x50,0x8c,0xff,0x00,0x08,0x3c,
-0xff,0xff,0x02,0x35,0x2b,0x10,0x50,0x00,0x47,0x00,0x40,0x10,0x00,0x00,0x00,0x00,
-0x00,0x00,0x82,0x8e,0x00,0xff,0x06,0x3c,0xac,0x02,0x84,0x36,0x01,0x00,0x45,0x24,
-0xbc,0x02,0x83,0x36,0xff,0x00,0xc2,0x34,0x00,0xfd,0x07,0x3c,0x00,0x00,0x85,0xac,
-0x00,0x00,0x70,0xac,0x24,0x18,0x02,0x02,0x07,0x00,0xe2,0x34,0x00,0x00,0x85,0x8c,
-0x52,0x03,0x62,0x10,0x25,0xb0,0x12,0x3c,0x2b,0x10,0x43,0x00,0xa2,0x00,0x40,0x14,
-0xa4,0x00,0xe2,0x34,0x00,0xf8,0x04,0x3c,0x15,0x00,0x82,0x34,0x57,0x03,0x62,0x10,
-0x2b,0x10,0x43,0x00,0xc8,0x00,0x40,0x14,0x00,0xf9,0x05,0x3c,0x00,0xf0,0x05,0x3c,
-0x20,0x00,0xa2,0x34,0x67,0x03,0x62,0x10,0x2b,0x10,0x43,0x00,0x20,0x01,0x40,0x14,
-0x10,0x00,0x82,0x34,0x70,0x03,0x65,0x10,0x2b,0x10,0xa3,0x00,0xc8,0x01,0x40,0x14,
-0x02,0x00,0xa2,0x34,0x00,0xd0,0x02,0x3c,0x2a,0x02,0x62,0x10,0x2b,0x10,0x43,0x00,
-0xaf,0x02,0x40,0x14,0x00,0xe0,0x02,0x3c,0x00,0xc0,0x02,0x3c,0xbb,0x03,0x62,0x10,
-0xff,0x00,0x03,0x3c,0x00,0xf0,0x02,0x3c,0x24,0x30,0x02,0x02,0x18,0x00,0xc2,0x10,
-0x02,0x1d,0x10,0x00,0x00,0x70,0x05,0x3c,0x24,0x10,0x05,0x02,0x02,0x4f,0x02,0x00,
-0x0f,0x00,0x02,0x3c,0xff,0xff,0x42,0x34,0x00,0x50,0x07,0x3c,0xff,0x00,0x68,0x30,
-0xff,0x00,0x04,0x32,0x96,0x01,0xc7,0x10,0x24,0x18,0x02,0x02,0x2b,0x10,0xe6,0x00,
-0x8a,0x01,0x40,0x14,0x00,0x80,0x02,0x3c,0x00,0x20,0x02,0x3c,0x1a,0x03,0xc2,0x10,
-0x2b,0x10,0x46,0x00,0x82,0x02,0x40,0x14,0x00,0x30,0x02,0x3c,0x17,0x03,0xc0,0x10,
-0x80,0x10,0x08,0x00,0x00,0x10,0x02,0x3c,0x14,0x03,0xc2,0x10,0x80,0x10,0x08,0x00,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x00,0x00,0xe2,0x92,0x25,0xb0,0x07,0x3c,
-0xc8,0x7d,0xc2,0xa2,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0xc8,0x7d,0xc2,0x92,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x30,0x4e,0x00,0x40,0x10,
-0x02,0x80,0x03,0x3c,0x00,0x40,0x62,0x8e,0xf0,0xff,0x03,0x24,0xd7,0x42,0x60,0xa2,
-0x24,0x10,0x43,0x00,0x01,0x00,0x42,0x34,0x00,0x40,0x62,0xae,0xc8,0x7d,0xc2,0x92,
-0x00,0x00,0x00,0x00,0x02,0x00,0x42,0x30,0x3d,0x00,0x40,0x10,0x0f,0xff,0x03,0x24,
-0x00,0x40,0x62,0x8e,0x00,0x00,0x00,0x00,0x24,0x10,0x43,0x00,0x10,0x00,0x42,0x34,
-0x00,0x40,0x62,0xae,0xc8,0x7d,0xc2,0x92,0x00,0x00,0x00,0x00,0x04,0x00,0x42,0x30,
-0x30,0x00,0x40,0x10,0xff,0xf0,0x03,0x24,0x00,0x40,0x62,0x8e,0x00,0x00,0x00,0x00,
-0x24,0x10,0x43,0x00,0x00,0x01,0x42,0x34,0x25,0xb0,0x05,0x3c,0x00,0x40,0x62,0xae,
-0x4c,0x00,0xa3,0x34,0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,0x03,0x00,0x42,0x30,
-0x05,0x00,0x40,0x14,0xff,0xff,0x02,0x3c,0x00,0x40,0x63,0x8e,0xff,0x0f,0x42,0x34,
-0x24,0x18,0x62,0x00,0x00,0x40,0x63,0xae,0x00,0x7b,0xa4,0x8e,0x01,0x80,0x06,0x3c,
-0x08,0x1f,0xc2,0x24,0x18,0x03,0xa3,0x34,0x00,0x7b,0xa6,0x26,0x00,0x00,0x62,0xac,
-0x10,0x00,0x86,0x10,0x02,0x80,0x02,0x3c,0xbf,0x00,0xb2,0x34,0x68,0x15,0x51,0x24,
-0x21,0x80,0xc0,0x00,0x00,0x00,0x42,0x92,0x00,0x00,0x00,0x00,0x04,0x00,0x42,0x2c,
-0x09,0x00,0x40,0x10,0x02,0x80,0x07,0x3c,0x98,0x65,0x24,0x8e,0x8b,0x07,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x00,0x7b,0xa2,0x8e,0x00,0x00,0x00,0x00,0xf5,0xff,0x50,0x14,
-0x00,0x00,0x00,0x00,0x02,0x80,0x07,0x3c,0x08,0x08,0xe4,0x24,0x21,0x28,0x00,0x00,
-0x21,0x30,0x00,0x00,0x31,0x1c,0x00,0x0c,0x21,0x38,0x00,0x00,0x9a,0x47,0x00,0x08,
-0x01,0x80,0x04,0x3c,0x00,0x40,0x62,0x8e,0x30,0x48,0x00,0x08,0x24,0x10,0x43,0x00,
-0x00,0x40,0x62,0x8e,0x04,0x43,0x64,0x92,0x24,0x10,0x43,0x00,0x00,0x40,0x62,0xae,
-0x27,0x48,0x00,0x08,0x04,0x43,0x64,0xae,0x68,0x15,0x66,0x24,0x00,0x40,0xc2,0x8c,
-0xd7,0x42,0xc4,0x90,0xf0,0xff,0x03,0x24,0x24,0x10,0x43,0x00,0xb3,0xff,0x80,0x14,
-0x00,0x40,0xc2,0xac,0x1c,0x00,0x04,0x24,0x58,0x0c,0xe5,0x34,0x50,0x0c,0xe3,0x34,
-0x01,0x00,0x02,0x24,0xd7,0x42,0xc2,0xa0,0x00,0x00,0x64,0xa0,0x00,0x00,0xa4,0xa0,
-0x1d,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xb2,0x02,0x62,0x10,0x2b,0x10,0x43,0x00,
-0x3f,0x00,0x40,0x14,0xaf,0x00,0xe2,0x34,0x20,0x00,0xe2,0x34,0xc0,0x02,0x62,0x10,
-0x2b,0x10,0x43,0x00,0xe3,0x00,0x40,0x14,0x29,0x00,0xe2,0x34,0x15,0x00,0xe2,0x34,
-0x0c,0x03,0x62,0x10,0x2b,0x10,0x43,0x00,0x9d,0x01,0x40,0x14,0x17,0x00,0xe2,0x34,
-0x09,0x00,0xe2,0x34,0xd8,0x03,0x62,0x10,0x2b,0x10,0x62,0x00,0x81,0x02,0x40,0x14,
-0x14,0x00,0xe2,0x34,0x64,0xff,0x62,0x14,0x00,0xf0,0x02,0x3c,0xff,0x00,0x07,0x3c,
-0x00,0xff,0xe7,0x34,0x24,0x10,0x07,0x02,0x7a,0xff,0x40,0x10,0xc0,0x02,0x82,0x36,
-0x04,0x43,0x64,0x92,0xff,0x00,0x02,0x3c,0x24,0x10,0x02,0x02,0x00,0xff,0x03,0x32,
-0x02,0x14,0x02,0x00,0x02,0x1a,0x03,0x00,0xfb,0xff,0x45,0x24,0x1c,0x43,0x62,0xa2,
-0x00,0x01,0x84,0x34,0xfb,0xff,0x66,0x24,0xc0,0x02,0x82,0x36,0x04,0x43,0x64,0xae,
-0x1d,0x43,0x65,0xa2,0x1f,0x43,0x66,0xa2,0x1e,0x43,0x63,0xa2,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x05,0x00,0xa2,0x34,0x91,0x02,0x62,0x10,
-0x2b,0x10,0x43,0x00,0x8e,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0xde,0x02,0x65,0x10,
-0x2b,0x10,0xa3,0x00,0x32,0x01,0x40,0x14,0x02,0x00,0xa2,0x34,0x17,0x00,0x82,0x34,
-0x61,0x04,0x62,0x10,0x2b,0x10,0x62,0x00,0xa9,0x03,0x40,0x14,0x18,0x00,0x82,0x34,
-0x3d,0xff,0x62,0x14,0x00,0xf0,0x02,0x3c,0x74,0x0b,0x00,0x0c,0x00,0x00,0x00,0x00,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0xa8,0x02,0x62,0x10,0x2b,0x10,0x43,0x00,0x95,0x00,0x40,0x14,0x0c,0x00,0xc2,0x34,
-0xaa,0x00,0xe2,0x34,0xdc,0x02,0x62,0x10,0x2b,0x10,0x43,0x00,0xd9,0x00,0x40,0x14,
-0xac,0x00,0xe2,0x34,0xa6,0x00,0xe2,0x34,0x1c,0x04,0x62,0x10,0x2b,0x10,0x62,0x00,
-0x69,0x03,0x40,0x14,0xa7,0x00,0xe2,0x34,0x27,0xff,0x62,0x14,0x00,0xf0,0x02,0x3c,
-0x00,0xff,0x02,0x32,0xff,0x00,0x04,0x3c,0x02,0x8a,0x02,0x00,0x24,0x18,0x04,0x02,
-0x01,0x00,0x02,0x24,0xa6,0x04,0x22,0x12,0x02,0x1c,0x03,0x00,0x02,0x00,0x02,0x24,
-0xc9,0x04,0x22,0x12,0x03,0x00,0x02,0x24,0xdf,0x04,0x22,0x12,0x04,0x00,0x02,0x24,
-0xd1,0x04,0x22,0x12,0x08,0x00,0x02,0x24,0x2e,0x05,0x22,0x12,0x09,0x00,0x02,0x24,
-0x1e,0x05,0x22,0x12,0x0a,0x00,0x02,0x24,0x0e,0x05,0x22,0x12,0x0b,0x00,0x02,0x24,
-0xfe,0x04,0x22,0x12,0x0c,0x00,0x02,0x24,0x5e,0x05,0x22,0x12,0x0d,0x00,0x02,0x24,
-0x4e,0x05,0x22,0x12,0x0e,0x00,0x02,0x24,0x3e,0x05,0x22,0x12,0x0f,0x00,0x02,0x24,
-0x2e,0x05,0x22,0x12,0x10,0x00,0x02,0x24,0x22,0xff,0x22,0x16,0xc0,0x02,0x82,0x36,
-0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,
-0x80,0x10,0x02,0x00,0x21,0x10,0x53,0x00,0x4c,0x51,0x43,0x94,0x48,0x51,0x44,0x94,
-0x25,0xb0,0x06,0x3c,0x00,0x1c,0x03,0x00,0x21,0x20,0x83,0x00,0x00,0x00,0xc4,0xaf,
-0x58,0x51,0x45,0x8c,0x54,0x51,0x43,0x8c,0x50,0x51,0x44,0x94,0xc8,0x02,0xc6,0x34,
-0x21,0x18,0x65,0x00,0x00,0x1c,0x03,0x00,0x21,0x20,0x83,0x00,0xc0,0x02,0x82,0x36,
-0x00,0x00,0xc4,0xac,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x66,0x02,0x62,0x10,0x2b,0x10,0x43,0x00,0xbf,0x00,0x40,0x14,0x12,0x00,0x82,0x34,
-0x00,0xf1,0x04,0x3c,0x01,0x00,0x82,0x34,0xc1,0x02,0x62,0x10,0x2b,0x10,0x43,0x00,
-0xb7,0x01,0x40,0x14,0x02,0x00,0x82,0x34,0xe3,0xfe,0x64,0x14,0x00,0xf0,0x02,0x3c,
-0xff,0x00,0x04,0x3c,0x00,0xff,0x84,0x34,0x24,0x10,0x04,0x02,0x02,0x8a,0x02,0x00,
-0x80,0x1a,0x11,0x00,0x00,0xf4,0x63,0x24,0x94,0x00,0x82,0x36,0x00,0x00,0x51,0xa4,
-0x26,0xb0,0x04,0x3c,0x42,0x89,0x03,0x00,0x98,0x00,0x86,0x36,0xff,0x01,0x02,0x24,
-0x10,0x00,0x03,0x24,0x9a,0x00,0x85,0x36,0x00,0x00,0xa2,0xa4,0x7c,0x00,0x89,0x34,
-0x00,0x00,0xc3,0xa4,0x01,0x00,0x02,0x24,0x04,0x00,0x03,0x24,0x96,0x00,0x87,0x36,
-0x7a,0x00,0x84,0x34,0xb0,0x03,0x88,0x36,0x25,0xb0,0x06,0x3c,0x00,0x00,0xe2,0xa4,
-0x44,0x00,0xc6,0x34,0x00,0x00,0x83,0xa0,0x00,0x00,0x11,0xad,0x00,0x00,0x31,0xa5,
-0x00,0x00,0xc3,0x94,0xff,0xfd,0x02,0x24,0x24,0x18,0x62,0x00,0x00,0x00,0xc3,0xa4,
-0x00,0x00,0xc2,0x94,0x00,0x00,0x00,0x00,0x00,0x02,0x42,0x34,0x00,0x00,0xc2,0xa4,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x65,0x01,0x67,0x10,0x2b,0x10,0xe3,0x00,0xc5,0x00,0x40,0x14,0x02,0x00,0xe2,0x34,
-0x07,0x00,0xa2,0x34,0xfc,0x02,0x62,0x10,0x2b,0x10,0x62,0x00,0xa9,0x01,0x40,0x14,
-0x20,0x00,0xa2,0x34,0xb0,0xfe,0x62,0x14,0x00,0xf0,0x02,0x3c,0xff,0x00,0x03,0x3c,
-0x00,0xff,0x63,0x34,0x24,0x10,0x03,0x02,0x02,0x3a,0x02,0x00,0x80,0x04,0xe0,0x10,
-0x02,0x80,0x04,0x3c,0x05,0x00,0x02,0x24,0xc2,0xfe,0xe2,0x14,0xc0,0x02,0x82,0x36,
-0x02,0x80,0x06,0x3c,0x8f,0x7d,0xc2,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x2e,0x02,0x62,0x10,0x2b,0x10,0x43,0x00,0x98,0x00,0x40,0x14,0x0e,0x00,0xc2,0x34,
-0x01,0x00,0xc2,0x34,0xab,0x03,0x62,0x10,0x2b,0x10,0x43,0x00,0x48,0x01,0x40,0x14,
-0x00,0xff,0x02,0x3c,0x94,0xfe,0x66,0x14,0x00,0xf0,0x02,0x3c,0x5b,0x4e,0x00,0x0c,
-0x21,0x20,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0x4c,0x02,0x62,0x10,0x2b,0x10,0x43,0x00,0xa6,0x00,0x40,0x14,
-0xa1,0x00,0xe2,0x34,0x22,0x00,0xe2,0x34,0xbd,0x02,0x62,0x10,0x2b,0x10,0x62,0x00,
-0x88,0x01,0x40,0x14,0x00,0x20,0x02,0x3c,0x28,0x00,0xe2,0x34,0x82,0xfe,0x62,0x14,
-0x00,0xf0,0x02,0x3c,0x0f,0x00,0x04,0x3c,0xff,0xff,0x85,0x34,0x60,0x00,0x06,0x24,
-0xba,0x44,0x00,0x0c,0x24,0x00,0x04,0x24,0x84,0x0a,0x00,0x0c,0xe8,0x03,0x04,0x24,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x0f,0x00,0x06,0x3c,0x24,0x00,0x04,0x24,0xdd,0x44,0x00,0x0c,0xff,0xff,0xc5,0x34,
-0x1f,0x00,0x51,0x30,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0xc0,0x02,0x82,0x36,0x00,0x00,0xd1,0xa3,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x18,0x02,0xc2,0x10,
-0x2b,0x10,0x46,0x00,0x01,0x01,0x40,0x14,0x00,0xa0,0x02,0x3c,0x00,0x60,0x02,0x3c,
-0x04,0x00,0xc2,0x10,0x80,0x10,0x08,0x00,0x7a,0xfe,0xc5,0x14,0xc0,0x02,0x82,0x36,
-0x80,0x10,0x08,0x00,0x21,0x10,0x48,0x00,0x21,0x10,0x53,0x00,0x21,0x10,0x49,0x00,
-0xc1,0x43,0x44,0xa0,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0x3f,0x03,0x62,0x10,0x2b,0x10,0x62,0x00,0xb6,0x02,0x40,0x14,
-0xad,0x00,0xe2,0x34,0xc7,0x03,0x62,0x10,0xae,0x00,0xe2,0x34,0x4e,0xfe,0x62,0x14,
-0x00,0xf0,0x02,0x3c,0xff,0x00,0x02,0x3c,0x24,0x20,0x02,0x02,0x00,0xff,0x05,0x32,
-0x02,0x24,0x04,0x00,0x69,0x4f,0x00,0x0c,0x02,0x2a,0x05,0x00,0x00,0x00,0xc2,0xa3,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x4b,0x02,0x62,0x10,0x2b,0x10,0x62,0x00,0x17,0x01,0x40,0x14,0x03,0x00,0xa2,0x34,
-0x82,0x03,0x62,0x10,0x08,0x00,0xa2,0x34,0x3b,0xfe,0x62,0x14,0x00,0xf0,0x02,0x3c,
-0x00,0xff,0x02,0x32,0x02,0x82,0x02,0x00,0xcc,0x02,0x83,0x36,0x00,0x00,0x70,0xac,
-0x12,0x04,0x00,0x12,0x01,0x00,0x02,0x24,0x9c,0x04,0x02,0x12,0x00,0x00,0x00,0x00,
-0x7a,0x42,0x00,0x0c,0x21,0x20,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x4e,0x02,0x62,0x10,0x2b,0x10,0x62,0x00,
-0xe4,0x00,0x40,0x14,0x00,0xff,0x02,0x32,0x13,0x00,0x82,0x34,0x4c,0x03,0x62,0x10,
-0x14,0x00,0x82,0x34,0x24,0xfe,0x62,0x14,0x00,0xf0,0x02,0x3c,0xd3,0x0a,0x00,0x0c,
-0xfd,0x00,0x04,0x24,0x10,0x10,0x03,0x3c,0xa0,0x00,0x82,0x36,0x10,0x10,0x63,0x34,
-0x00,0xc0,0x07,0x3c,0x25,0xb0,0x06,0x3c,0x00,0x00,0x43,0xac,0xa4,0x00,0x84,0x36,
-0x00,0xa1,0xe7,0x34,0xa8,0x00,0xc6,0x34,0xc0,0x02,0x82,0x36,0x00,0x00,0x80,0xac,
-0x00,0x00,0xc7,0xac,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x60,0x02,0x62,0x10,0x2b,0x10,0x62,0x00,0xf6,0x00,0x40,0x14,0x03,0x00,0xa2,0x34,
-0x4b,0x03,0x62,0x10,0x04,0x00,0xa2,0x34,0x0b,0xfe,0x62,0x14,0x00,0xf0,0x02,0x3c,
-0xf4,0x63,0x62,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf,0xc0,0x02,0x82,0x36,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x61,0x02,0x62,0x10,
-0x2b,0x10,0x62,0x00,0xfe,0x00,0x40,0x14,0x01,0x00,0x02,0x24,0x0f,0x00,0xc2,0x34,
-0x63,0x03,0x62,0x10,0x10,0x00,0xc2,0x34,0xfb,0xfd,0x62,0x14,0x00,0xf0,0x02,0x3c,
-0x00,0xff,0x03,0x32,0x00,0xff,0x02,0x34,0x9d,0x03,0x62,0x10,0xc0,0x02,0x82,0x36,
-0x8c,0x65,0x60,0xae,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x47,0x02,0x62,0x10,0x2b,0x10,0x62,0x00,0x02,0x01,0x40,0x14,0x03,0x00,0xe2,0x34,
-0x8d,0x03,0x62,0x10,0x04,0x00,0xe2,0x34,0xeb,0xfd,0x62,0x14,0x00,0xf0,0x02,0x3c,
-0x1e,0x57,0x00,0x0c,0x00,0x00,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x9b,0x01,0x62,0x10,0x2b,0x10,0x43,0x00,
-0xcf,0x00,0x40,0x14,0xa2,0x00,0xe2,0x34,0xa0,0x00,0xe2,0x34,0xde,0xfd,0x62,0x14,
-0x00,0xf0,0x02,0x3c,0x00,0x0f,0x02,0x32,0x02,0x22,0x02,0x00,0x01,0x00,0x03,0x24,
-0x3c,0x04,0x83,0x10,0x02,0x00,0x02,0x24,0x34,0x04,0x82,0x10,0x03,0x00,0x02,0x24,
-0x46,0x03,0x82,0x10,0x00,0x00,0x00,0x00,0xde,0x4f,0x00,0x0c,0x21,0x20,0x00,0x00,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x46,0x02,0x62,0x10,0x2b,0x10,0x62,0x00,0xe6,0xfd,0x40,0x14,0xc0,0x02,0x82,0x36,
-0x18,0x00,0xe2,0x34,0x45,0x03,0x62,0x10,0x19,0x00,0xe2,0x34,0xc6,0xfd,0x62,0x14,
-0x00,0xf0,0x02,0x3c,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x94,0x0e,0x83,0x36,
-0x9c,0x0e,0x82,0x36,0xa4,0x0e,0x84,0x36,0xac,0x0e,0x87,0x36,0x00,0x00,0x65,0x8c,
-0x00,0x00,0x48,0x8c,0x00,0x00,0x8a,0x8c,0x00,0x00,0xe6,0x8c,0x02,0x80,0x07,0x3c,
-0x68,0x15,0xed,0x24,0xb4,0x0e,0x82,0x36,0x00,0x00,0x47,0x8c,0x0c,0x40,0xa3,0x8d,
-0xff,0x03,0x02,0x3c,0x10,0x40,0xa4,0x8d,0x24,0x28,0xa2,0x00,0x24,0x30,0xc2,0x00,
-0xbc,0x0e,0x82,0x36,0x00,0x00,0x4b,0x8c,0x00,0xfc,0x02,0x24,0x02,0x2c,0x05,0x00,
-0x24,0x18,0x62,0x00,0x02,0x34,0x06,0x00,0x24,0x20,0x82,0x00,0xc4,0x0e,0x82,0x36,
-0x25,0x18,0x65,0x00,0x25,0x20,0x86,0x00,0x00,0x00,0x45,0x8c,0xff,0x03,0x06,0x3c,
-0xf0,0xff,0x02,0x3c,0xff,0x03,0x42,0x34,0x24,0x38,0xe6,0x00,0x82,0x39,0x07,0x00,
-0x24,0x20,0x82,0x00,0x24,0x40,0x06,0x01,0x08,0x40,0xa9,0x8d,0x25,0x20,0x87,0x00,
-0xcc,0x0e,0x8c,0x36,0xff,0x03,0x07,0x3c,0x00,0x00,0x86,0x8d,0x24,0x18,0x62,0x00,
-0x24,0x50,0x47,0x01,0x24,0x58,0x67,0x01,0x82,0x41,0x08,0x00,0xff,0x9f,0x02,0x3c,
-0x0f,0xc0,0x07,0x3c,0xff,0xff,0xe7,0x34,0xff,0xff,0x42,0x34,0x25,0x18,0x68,0x00,
-0x24,0x48,0x22,0x01,0x24,0x18,0x67,0x00,0xff,0x03,0x02,0x3c,0x24,0x20,0x87,0x00,
-0xff,0x00,0x07,0x3c,0x24,0x28,0xa2,0x00,0x24,0x30,0xc2,0x00,0x00,0x51,0x0a,0x00,
-0x00,0x20,0x02,0x3c,0x00,0x59,0x0b,0x00,0x00,0xff,0xe7,0x34,0x25,0x48,0x22,0x01,
-0x25,0x18,0x6a,0x00,0x25,0x20,0x8b,0x00,0x02,0x2c,0x05,0x00,0x02,0x34,0x06,0x00,
-0x24,0x10,0x07,0x02,0x08,0x40,0xa9,0xad,0x0c,0x40,0xa3,0xad,0x10,0x40,0xa4,0xad,
-0x14,0x40,0xa5,0xa5,0x4e,0x03,0x40,0x10,0x16,0x40,0xa6,0xa5,0xff,0x00,0x02,0x3c,
-0x24,0x10,0x02,0x02,0x02,0x14,0x02,0x00,0x02,0x1a,0x10,0x00,0xc7,0x42,0xa2,0xa1,
-0xc3,0x42,0xa3,0xa1,0xc3,0x42,0x62,0x92,0x25,0xb0,0x03,0x3c,0x61,0x0c,0x63,0x34,
-0x10,0x00,0xa4,0x27,0x00,0x00,0x62,0xa0,0x7a,0x54,0x00,0x0c,0x00,0x00,0x00,0x00,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x95,0x00,0xc2,0x10,0x00,0x40,0x02,0x3c,0x09,0xff,0xc2,0x10,0xc0,0x02,0x82,0x36,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x7b,0x02,0xc2,0x10,
-0x2b,0x10,0x46,0x00,0x83,0x00,0x40,0x14,0x00,0xb0,0x02,0x3c,0x00,0x90,0x02,0x3c,
-0x78,0xfd,0xc2,0x14,0xc0,0x02,0x82,0x36,0x21,0x10,0x13,0x01,0x73,0x44,0x44,0xa0,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x55,0xfd,0x62,0x14,0x00,0xf0,0x02,0x3c,0x6a,0x56,0x00,0x0c,0x21,0x20,0x00,0x02,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x07,0x00,0x42,0x34,0x4c,0xfd,0x62,0x14,0x00,0xf0,0x02,0x3c,0x5b,0x4e,0x00,0x0c,
-0x07,0x00,0x04,0x24,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0x02,0x1a,0x02,0x00,0x21,0x88,0x00,0x00,0xaf,0x4a,0x00,0x08,
-0x27,0xb0,0x06,0x3c,0x01,0x00,0x31,0x26,0x00,0x01,0x22,0x2e,0x08,0x00,0x40,0x10,
-0xff,0x00,0x22,0x2e,0x00,0x00,0xc2,0x94,0x00,0x00,0x00,0x00,0xff,0x00,0x42,0x30,
-0xf8,0xff,0x43,0x14,0x08,0x00,0xc6,0x24,0x00,0x00,0xd1,0xa7,0xff,0x00,0x22,0x2e,
-0x50,0xfd,0x40,0x14,0xc0,0x02,0x82,0x36,0x12,0x87,0x02,0x3c,0x00,0x00,0xc2,0xaf,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x2d,0xfd,0x62,0x14,0x00,0xf0,0x02,0x3c,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xff,0x00,0x03,0x3c,0x00,0xff,0x63,0x34,
-0x24,0x10,0x03,0x02,0x02,0x82,0x02,0x00,0xcc,0x02,0x83,0x36,0x00,0x00,0x70,0xac,
-0x00,0x00,0xd1,0x8f,0x21,0x10,0x14,0x02,0x00,0x00,0x51,0xac,0x00,0x00,0x51,0x8c,
-0xc0,0x02,0x82,0x36,0x00,0x00,0xd1,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0x00,0x64,0x62,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0xf4,0x02,0x62,0x10,0xa3,0x00,0xe2,0x34,0x0f,0xfd,0x62,0x14,0x00,0xf0,0x02,0x3c,
-0xc0,0x02,0x82,0x36,0x8c,0x65,0x60,0xae,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xec,0x63,0x62,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0xe6,0x63,0x62,0xa6,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0x08,0x40,0x63,0x8e,0xff,0x9f,0x07,0x3c,0xff,0xff,0xe7,0x34,
-0x02,0x2c,0x10,0x00,0x00,0x1f,0x04,0x32,0x24,0x18,0x67,0x00,0x25,0x18,0x62,0x00,
-0x02,0x8a,0x04,0x00,0x3f,0x00,0xa5,0x30,0xc0,0x02,0x82,0x36,0x08,0x40,0x63,0xae,
-0xbc,0x42,0x71,0xa2,0xc1,0x42,0x65,0xa2,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0x00,0x00,0xe2,0x92,0x00,0x00,0x00,0x00,0xfa,0x00,0x42,0x30,
-0x00,0x00,0xe2,0xa2,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0x00,0x00,0xe2,0x92,0x00,0x00,0x00,0x00,0xfd,0x00,0x42,0x30,
-0x00,0x00,0xe2,0xa2,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xf7,0xfc,0xc2,0x14,0xc0,0x02,0x82,0x36,0x80,0x10,0x08,0x00,
-0x21,0x10,0x53,0x00,0x60,0x45,0x43,0xac,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x80,0x10,0x08,0x00,0x21,0x10,0x48,0x00,
-0x21,0x10,0x53,0x00,0x21,0x10,0x49,0x00,0x34,0x43,0x44,0xa0,0xc0,0x02,0x82,0x36,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x77,0x56,0x00,0x0c,
-0x21,0x20,0x00,0x02,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xff,0xff,0x02,0x34,0x8c,0x65,0x62,0xae,0xc0,0x02,0x82,0x36,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x07,0x0b,0x00,0x0c,
-0x00,0x00,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xf0,0x63,0x62,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x08,0x40,0x62,0x8e,0xff,0x9f,0x03,0x3c,0xff,0xff,0x63,0x34,0x24,0x10,0x43,0x00,
-0x08,0x40,0x62,0xae,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,
-0x00,0x60,0x81,0x40,0x22,0x51,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xff,0x00,0x07,0x3c,0x00,0xff,0xe7,0x34,
-0x24,0x10,0x07,0x02,0x02,0x82,0x02,0x00,0xcc,0x02,0x43,0x36,0x00,0x00,0x70,0xac,
-0x21,0x10,0x12,0x02,0x00,0x00,0x51,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0xaf,
-0x00,0x00,0x51,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xb7,0x4f,0x00,0x0c,0x00,0x00,0x00,0x00,0xc0,0x02,0x82,0x36,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x21,0x88,0x00,0x00,
-0x6c,0x4b,0x00,0x08,0x27,0xb0,0x04,0x3c,0x01,0x00,0x31,0x26,0x00,0x01,0x22,0x2e,
-0x0a,0x00,0x40,0x10,0xff,0x00,0x22,0x2e,0x00,0x00,0x83,0x94,0x00,0x00,0x00,0x00,
-0xff,0xff,0x67,0x30,0xff,0x00,0xe2,0x30,0xf0,0x00,0x42,0x28,0xf6,0xff,0x40,0x14,
-0x08,0x00,0x84,0x24,0x00,0x00,0xc7,0xa7,0xff,0x00,0x22,0x2e,0x91,0xfc,0x40,0x14,
-0xc0,0x02,0x82,0x36,0x12,0x87,0x02,0x3c,0x00,0x00,0xc2,0xaf,0xc0,0x02,0x82,0x36,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xe4,0x63,0x62,0x96,
-0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xa7,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x04,0x64,0x62,0x92,0x00,0x00,0x00,0x00,
-0x00,0x00,0xc2,0xaf,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0x00,0xff,0x02,0x32,0x02,0x12,0x02,0x00,0x03,0x00,0x43,0x2c,
-0x02,0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x02,0x40,0x62,0xa2,0x02,0x40,0x63,0x92,
-0x90,0x0c,0x42,0x36,0x00,0x00,0x43,0xa0,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xd7,0x56,0x00,0x0c,0x00,0x00,0x00,0x00,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x21,0x10,0x13,0x01,0x56,0x44,0x44,0xa0,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xff,0x00,0x03,0x3c,0x24,0x20,0x03,0x02,
-0x73,0x0e,0x00,0x0c,0x02,0x24,0x04,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x02,0x1c,0x10,0x00,0x00,0x1f,0x02,0x32,
-0x02,0x8a,0x02,0x00,0x3f,0x00,0x65,0x30,0xc1,0x42,0x65,0xa2,0xbc,0x42,0x71,0xa2,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x1f,0x12,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x03,0x40,0x62,0x92,0x0e,0x0c,0x44,0x36,
-0x01,0x00,0x42,0x24,0xff,0x00,0x43,0x30,0x00,0x00,0x83,0xa0,0x03,0x40,0x62,0xa2,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x00,0xff,0x02,0x32,0x02,0x3a,0x02,0x00,0x1a,0x01,0xe0,0x10,0x4f,0x00,0x82,0x36,
-0x94,0x00,0x42,0x36,0x00,0x00,0x43,0x94,0xff,0xff,0xe2,0x24,0xb0,0x03,0x45,0x36,
-0xff,0xff,0x71,0x30,0x1b,0x00,0x27,0x02,0x02,0x00,0xe0,0x14,0x00,0x00,0x00,0x00,
-0x0d,0x00,0x07,0x00,0xff,0xff,0x47,0x30,0x00,0x00,0xb1,0xac,0x80,0xff,0x02,0x24,
-0x00,0x19,0x07,0x00,0x25,0x18,0x62,0x00,0x4f,0x00,0x44,0x36,0x9e,0x00,0x46,0x36,
-0x00,0x00,0xa7,0xac,0x00,0x00,0x83,0xa0,0x25,0xb0,0x04,0x3c,0x44,0x00,0x84,0x34,
-0x12,0x88,0x00,0x00,0x80,0x12,0x11,0x00,0x00,0xfc,0x42,0x24,0x00,0x00,0xb1,0xac,
-0x00,0x00,0xd1,0xa4,0x42,0x89,0x02,0x00,0x26,0xb0,0x02,0x3c,0x7c,0x00,0x42,0x34,
-0x00,0x00,0xb1,0xac,0x00,0x00,0x51,0xa4,0x25,0xb0,0x02,0x3c,0x44,0x00,0x42,0x34,
-0x00,0x00,0x43,0x94,0xff,0xfd,0x02,0x24,0x24,0x18,0x62,0x00,0x00,0x00,0x83,0xa4,
-0x00,0x00,0x82,0x94,0x00,0x00,0x00,0x00,0x00,0x02,0x42,0x34,0x00,0x00,0x82,0xa4,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x24,0x10,0x08,0x02,0xcc,0x02,0x43,0x36,0x00,0xff,0x04,0x32,0x02,0x3c,0x02,0x00,
-0x00,0x00,0x70,0xac,0x04,0x00,0xe0,0x10,0x02,0x82,0x04,0x00,0x01,0x00,0x02,0x24,
-0x02,0x00,0xe2,0x10,0x01,0x00,0x04,0x24,0x21,0x20,0x00,0x00,0x7a,0x42,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x0f,0x00,0x06,0x3c,0x21,0x20,0x00,0x02,0xdd,0x44,0x00,0x0c,
-0xff,0xff,0xc5,0x34,0x0f,0x00,0x07,0x3c,0xff,0xff,0xe7,0x34,0x24,0x88,0x47,0x00,
-0xc0,0x02,0x82,0x36,0x00,0x00,0xd1,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0x28,0xb0,0x02,0x3c,0x00,0x00,0x43,0x90,0xff,0x00,0x02,0x24,
-0xff,0x00,0x70,0x30,0xf3,0xfb,0x02,0x12,0xc0,0x02,0x82,0x36,0x28,0xb0,0x05,0x3c,
-0xff,0x00,0x04,0x24,0xc0,0x10,0x10,0x00,0x21,0x10,0x45,0x00,0x00,0x00,0x43,0x90,
-0x00,0x00,0x00,0x00,0xff,0x00,0x70,0x30,0xfb,0xff,0x04,0x16,0xc0,0x10,0x10,0x00,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x00,0x1f,0x02,0x32,0x02,0x1c,0x10,0x00,0x02,0x8a,0x02,0x00,0x3f,0x00,0x65,0x30,
-0xc0,0x02,0x82,0x36,0xbc,0x42,0x71,0xa2,0xc1,0x42,0x65,0xa2,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xff,0x00,0x07,0x3c,0x24,0x20,0x07,0x02,
-0x15,0x51,0x00,0x0c,0x02,0x24,0x04,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xe8,0x63,0x62,0x92,0x00,0x00,0x00,0x00,
-0x00,0x00,0xc2,0xaf,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xfc,0x63,0x62,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x00,0x00,0xe2,0x92,0x00,0x00,0x00,0x00,0xff,0x00,0x51,0x30,0x05,0x00,0x23,0x36,
-0xc0,0x02,0x82,0x36,0x00,0x00,0xe3,0xa2,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xc0,0x02,0x82,0x36,0xe6,0x63,0x60,0xa6,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xbd,0x56,0x00,0x0c,0x21,0x20,0x00,0x02,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x41,0x0b,0x00,0x0c,0x00,0x00,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0xe2,0x92,0x00,0x00,0x00,0x00,
-0xff,0x00,0x51,0x30,0x02,0x00,0x23,0x36,0xc0,0x02,0x82,0x36,0x00,0x00,0xe3,0xa2,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c,
-0xec,0x91,0x42,0x24,0x00,0x00,0x47,0x8c,0xc0,0x02,0x43,0x36,0x25,0xb0,0x0c,0x3c,
-0x08,0x40,0xe4,0x8c,0x00,0x00,0x60,0xac,0x42,0x17,0x04,0x00,0x03,0x00,0x42,0x30,
-0x60,0x00,0x40,0x14,0x03,0x0d,0x42,0x36,0x00,0x00,0x45,0x90,0x10,0x40,0xe6,0x8c,
-0xff,0x9f,0x03,0x3c,0xff,0xff,0x63,0x34,0xff,0x3f,0x02,0x3c,0x24,0x20,0x83,0x00,
-0xff,0xff,0x42,0x34,0x00,0x20,0x03,0x3c,0x24,0x58,0xc2,0x00,0x25,0x20,0x83,0x00,
-0x00,0x40,0x02,0x3c,0x70,0x00,0xa5,0x30,0x25,0x58,0x62,0x01,0x08,0x01,0xa0,0x10,
-0x08,0x40,0xe4,0xac,0x94,0x0e,0x82,0x35,0x9c,0x0e,0x83,0x35,0xa4,0x0e,0x86,0x35,
-0x00,0x00,0x45,0x8c,0xac,0x0e,0x87,0x35,0x00,0x00,0x68,0x8c,0x00,0x00,0xca,0x8c,
-0x02,0x80,0x06,0x3c,0x00,0x00,0xe4,0x8c,0x68,0x15,0xc6,0x24,0x0c,0x40,0xc3,0x8c,
-0xb4,0x0e,0x82,0x35,0x00,0x00,0x47,0x8c,0xff,0x03,0x02,0x3c,0x00,0xfc,0x06,0x24,
-0x24,0x28,0xa2,0x00,0x24,0x20,0x82,0x00,0xbc,0x0e,0x82,0x35,0x00,0x00,0x49,0x8c,
-0x02,0x2c,0x05,0x00,0x24,0x10,0x66,0x01,0x24,0x18,0x66,0x00,0x02,0x24,0x04,0x00,
-0xc4,0x0e,0x86,0x35,0x25,0x18,0x65,0x00,0x25,0x10,0x44,0x00,0x00,0x00,0xc5,0x8c,
-0xff,0x03,0x04,0x3c,0xf0,0xff,0x06,0x3c,0xff,0x03,0xc6,0x34,0x24,0x38,0xe4,0x00,
-0xcc,0x0e,0x8b,0x35,0x24,0x40,0x04,0x01,0x82,0x39,0x07,0x00,0x00,0x00,0x64,0x8d,
-0x24,0x10,0x46,0x00,0x24,0x18,0x66,0x00,0x25,0x10,0x47,0x00,0x82,0x41,0x08,0x00,
-0xff,0x03,0x07,0x3c,0x0f,0xc0,0x06,0x3c,0x24,0x50,0x47,0x01,0x24,0x48,0x27,0x01,
-0xff,0xff,0xc6,0x34,0x25,0x18,0x68,0x00,0x24,0x28,0xa7,0x00,0x24,0x20,0x87,0x00,
-0x00,0x51,0x0a,0x00,0x24,0x18,0x66,0x00,0x00,0x49,0x09,0x00,0x24,0x10,0x46,0x00,
-0x02,0x80,0x07,0x3c,0x68,0x15,0xe7,0x24,0x25,0x18,0x6a,0x00,0x25,0x10,0x49,0x00,
-0x02,0x2c,0x05,0x00,0x02,0x24,0x04,0x00,0x0c,0x40,0xe3,0xac,0x10,0x40,0xe2,0xac,
-0x14,0x40,0xe5,0xa4,0x16,0x40,0xe4,0xa4,0x02,0x80,0x02,0x3c,0x68,0x15,0x43,0x24,
-0x0c,0x40,0x62,0x8c,0x00,0x00,0x00,0x00,0xbd,0x00,0x40,0x04,0x00,0x00,0x00,0x00,
-0x00,0xff,0x02,0x32,0xc6,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x02,0x12,0x02,0x00,
-0xc3,0x42,0x62,0xa0,0x7a,0x54,0x00,0x0c,0x10,0x00,0xa4,0x27,0xc2,0x53,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x0c,0x40,0x62,0x8e,0x00,0x80,0x03,0x3c,0x25,0x10,0x43,0x00,
-0x0c,0x40,0x62,0xae,0xc3,0x42,0x62,0x92,0x25,0xb0,0x03,0x3c,0x61,0x0c,0x63,0x34,
-0x00,0x00,0x62,0xa0,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xcf,0x4e,0x00,0x0c,0x21,0x20,0x00,0x02,0xc0,0x02,0x82,0x36,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x17,0x51,0x00,0x0c,
-0x00,0x00,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0x9e,0x00,0x83,0x36,0x00,0x00,0x40,0xa0,0x00,0x00,0x60,0xa4,
-0x94,0x00,0x82,0x36,0x00,0x00,0x43,0x94,0x25,0xb0,0x06,0x3c,0x44,0x00,0xc6,0x34,
-0xff,0xff,0x71,0x30,0x80,0x12,0x11,0x00,0x00,0xf8,0x42,0x24,0x42,0x89,0x02,0x00,
-0x26,0xb0,0x02,0x3c,0xb0,0x03,0x83,0x36,0x7c,0x00,0x42,0x34,0x00,0x00,0x71,0xac,
-0x00,0x00,0x51,0xa4,0x00,0x00,0xc3,0x94,0xff,0xfd,0x02,0x24,0x24,0x18,0x62,0x00,
-0x00,0x00,0xc3,0xa4,0x00,0x00,0xc2,0x94,0x00,0x00,0x00,0x00,0x00,0x02,0x42,0x34,
-0x00,0x00,0xc2,0xa4,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0x5b,0x4e,0x00,0x0c,0x01,0x00,0x04,0x24,0xc0,0x02,0x82,0x36,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x80,0x10,0x08,0x00,
-0x21,0x10,0x53,0x00,0xec,0x44,0x43,0xac,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xa7,0x0b,0x00,0x0c,0x00,0x00,0x00,0x00,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x28,0xb0,0x11,0x3c,0x00,0x00,0x22,0x96,0xff,0x00,0x04,0x3c,0x24,0x18,0x04,0x02,
-0x02,0x24,0x03,0x00,0xff,0x00,0x42,0x30,0x0a,0x00,0x82,0x10,0xff,0x7f,0x02,0x3c,
-0x08,0x00,0x31,0x26,0x00,0x00,0x22,0x96,0xff,0xff,0x23,0x32,0xff,0x00,0x42,0x30,
-0x03,0x00,0x82,0x10,0x00,0x08,0x63,0x2c,0xf9,0xff,0x60,0x14,0x00,0x00,0x00,0x00,
-0xff,0x7f,0x02,0x3c,0xff,0xff,0x42,0x34,0x24,0x10,0x22,0x02,0x00,0x00,0xc2,0xaf,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0xf8,0x63,0x62,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf,0xc0,0x02,0x82,0x36,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xff,0x00,0x03,0x3c,
-0x24,0x10,0x03,0x02,0x00,0xff,0x04,0x32,0xcc,0x02,0x83,0x36,0x02,0x3c,0x02,0x00,
-0x00,0x00,0x70,0xac,0x04,0x00,0xe0,0x10,0x02,0x82,0x04,0x00,0x01,0x00,0x02,0x24,
-0x02,0x00,0xe2,0x10,0x01,0x00,0x04,0x24,0x21,0x20,0x00,0x00,0x7a,0x42,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x8f,0x0f,0x00,0x06,0x3c,0xff,0xff,0xc5,0x34,
-0x21,0x20,0x00,0x02,0xba,0x44,0x00,0x0c,0x21,0x30,0x20,0x02,0x0f,0x00,0x07,0x3c,
-0x21,0x20,0x00,0x02,0xdd,0x44,0x00,0x0c,0xff,0xff,0xe5,0x34,0x00,0x00,0xc2,0xaf,
-0x21,0x88,0x40,0x00,0x25,0xb0,0x02,0x3c,0xc8,0x02,0x42,0x34,0x00,0x00,0x51,0xac,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x25,0xb0,0x06,0x3c,0xff,0x00,0x02,0x24,0x56,0x01,0xc6,0x34,0x00,0x00,0xc2,0xa4,
-0x01,0x00,0x03,0x24,0x02,0x80,0x07,0x3c,0xc0,0x02,0x82,0x36,0xb8,0x7d,0xe3,0xa0,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xde,0x4f,0x00,0x0c,
-0x03,0x00,0x04,0x24,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xde,0x4e,0x00,0x0c,0x21,0x20,0x00,0x02,0xc0,0x02,0x82,0x36,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x40,0x62,0x8e,
-0xff,0x9f,0x04,0x3c,0xff,0xff,0x84,0x34,0x24,0x10,0x44,0x00,0x08,0x40,0x62,0xae,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,
-0x80,0x10,0x02,0x00,0x21,0x10,0x53,0x00,0x70,0x51,0x43,0x8c,0xc0,0x02,0x82,0x36,
-0x00,0x00,0xc3,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x7a,0x54,0x00,0x0c,0x10,0x00,0xa4,0x27,0xc3,0x42,0x62,0x92,0x25,0xb0,0x03,0x3c,
-0x61,0x0c,0x63,0x34,0x00,0x00,0x62,0xa0,0xd4,0x4c,0x00,0x08,0xc0,0x02,0x82,0x36,
-0x22,0x51,0x00,0x0c,0x10,0x40,0xeb,0xac,0xbd,0x4c,0x00,0x08,0x02,0x80,0x02,0x3c,
-0xc6,0x4c,0x00,0x08,0x12,0x00,0x02,0x24,0x1a,0x57,0x00,0x0c,0x00,0x00,0x00,0x00,
-0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0xff,0xff,0x02,0x34,0x8c,0x65,0x62,0xae,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,
-0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x53,0x00,
-0x74,0x51,0x43,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0xc3,0xaf,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,
-0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x53,0x00,
-0xd4,0x51,0x43,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0xc3,0xaf,0x00,0x00,0x40,0xac,
-0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,
-0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x02,0x80,0x06,0x3c,0x80,0x10,0x02,0x00,
-0xe0,0x66,0xc3,0x24,0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,0xc0,0x02,0x82,0x36,
-0x00,0x00,0xc4,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,
-0x12,0x00,0x02,0x24,0xc7,0x42,0xa2,0xa1,0x77,0x4a,0x00,0x08,0xc3,0x42,0xa2,0xa1,
-0x88,0x7d,0x82,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf,0xc0,0x02,0x82,0x36,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x7a,0x42,0x00,0x0c,
-0x21,0x20,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xff,0x00,0x06,0x3c,0x00,0xff,0xc6,0x34,0x00,0x00,0xc5,0x8f,
-0x24,0x20,0x06,0x02,0xe1,0x50,0x00,0x0c,0x02,0x22,0x04,0x00,0xc0,0x02,0x82,0x36,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,
-0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x02,0x80,0x07,0x3c,
-0x80,0x10,0x02,0x00,0xf0,0x66,0xe3,0x24,0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,
-0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,
-0x21,0x10,0x43,0x00,0x02,0x80,0x06,0x3c,0x80,0x10,0x02,0x00,0xec,0x66,0xc3,0x24,
-0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,
-0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x02,0x80,0x04,0x3c,
-0xe8,0x66,0x83,0x24,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,
-0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,
-0x21,0x10,0x43,0x00,0x02,0x80,0x07,0x3c,0x80,0x10,0x02,0x00,0xe4,0x66,0xe3,0x24,
-0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,
-0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x02,0x80,0x04,0x3c,
-0x00,0x67,0x83,0x24,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,
-0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,
-0x21,0x10,0x43,0x00,0x02,0x80,0x07,0x3c,0x80,0x10,0x02,0x00,0xfc,0x66,0xe3,0x24,
-0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,
-0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x02,0x80,0x06,0x3c,
-0x80,0x10,0x02,0x00,0xf8,0x66,0xc3,0x24,0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,
-0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,
-0x21,0x10,0x43,0x00,0x02,0x80,0x04,0x3c,0xf4,0x66,0x83,0x24,0x80,0x10,0x02,0x00,
-0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xde,0x4f,0x00,0x0c,
-0x02,0x00,0x04,0x24,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0xde,0x4f,0x00,0x0c,0x01,0x00,0x04,0x24,0xc0,0x02,0x82,0x36,
-0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x7a,0x42,0x00,0x0c,
-0x01,0x00,0x04,0x24,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,
-0x00,0x00,0x00,0x00,0x25,0xb0,0x05,0x3c,0x01,0x00,0x06,0x24,0x01,0x80,0x02,0x3c,
-0x04,0x30,0x86,0x00,0xf1,0x02,0xa7,0x34,0xed,0x02,0xa4,0x34,0x6c,0x39,0x42,0x24,
-0x18,0x03,0xa5,0x34,0x08,0x00,0x03,0x24,0x00,0x00,0xa2,0xac,0x00,0x00,0xe3,0xa0,
-0x00,0x00,0x80,0xa0,0x00,0x00,0x86,0xa0,0x00,0x00,0x80,0xa0,0x00,0x00,0x86,0xa0,
-0x00,0x00,0x80,0xa0,0x00,0x00,0x86,0xa0,0x00,0x00,0x80,0xa0,0x00,0x00,0x86,0xa0,
-0x00,0x00,0x80,0xa0,0x00,0x00,0xe0,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x01,0x80,0x02,0x3c,0x25,0xb0,0x03,0x3c,0xc8,0x39,0x42,0x24,0x18,0x03,0x63,0x34,
-0x00,0x00,0x62,0xac,0x00,0x00,0x83,0x90,0x30,0x00,0x02,0x24,0x05,0x00,0x62,0x10,
-0x21,0x20,0x00,0x00,0x31,0x00,0x02,0x24,0x02,0x00,0x62,0x10,0x01,0x00,0x04,0x24,
-0x07,0x00,0x04,0x24,0x5b,0x4e,0x00,0x08,0x00,0x00,0x00,0x00,0x01,0x80,0x02,0x3c,
-0x25,0xb0,0x03,0x3c,0x04,0x3a,0x42,0x24,0x18,0x03,0x63,0x34,0x02,0x80,0x04,0x3c,
-0x00,0x00,0x62,0xac,0x08,0x00,0xe0,0x03,0xc4,0x7d,0x80,0xac,0x02,0x80,0x02,0x3c,
-0x08,0x7b,0x42,0x24,0xc0,0x20,0x04,0x00,0x21,0x20,0x82,0x00,0x21,0x28,0x00,0x00,
-0x00,0x60,0x06,0x40,0x01,0x00,0xc1,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,
-0x00,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x09,0x00,0x44,0x10,0x00,0x00,0x00,0x00,
-0x04,0x00,0x43,0x8c,0x21,0x28,0x40,0x00,0x00,0x00,0x42,0x8c,0x00,0x00,0x00,0x00,
-0x00,0x00,0x62,0xac,0x04,0x00,0x43,0xac,0x00,0x00,0xa5,0xac,0x04,0x00,0xa5,0xac,
-0x00,0x60,0x86,0x40,0x08,0x00,0xe0,0x03,0x21,0x10,0xa0,0x00,0x21,0x18,0x80,0x00,
-0xe8,0xff,0xbd,0x27,0x01,0x01,0x62,0x2c,0x10,0x00,0xbf,0xaf,0x01,0x00,0x04,0x24,
-0x01,0x02,0x65,0x2c,0x0a,0x00,0x40,0x14,0x21,0x30,0x00,0x00,0x02,0x00,0x04,0x24,
-0x07,0x00,0xa0,0x14,0x01,0x08,0x62,0x2c,0x05,0x00,0x40,0x14,0x03,0x00,0x04,0x24,
-0x10,0x00,0xbf,0x8f,0x21,0x10,0xc0,0x00,0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27,
-0x89,0x4e,0x00,0x0c,0x00,0x00,0x00,0x00,0x10,0x00,0xbf,0x8f,0x21,0x30,0x40,0x00,
-0x21,0x10,0xc0,0x00,0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27,0x02,0x80,0x03,0x3c,
-0x20,0x7b,0x62,0x8c,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x00,0x60,0x06,0x40,
-0x01,0x00,0xc1,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x10,0x00,0x83,0x8c,
-0x02,0x80,0x02,0x3c,0x08,0x7b,0x42,0x24,0xc0,0x18,0x03,0x00,0x21,0x18,0x62,0x00,
-0x00,0x00,0x65,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xac,0x04,0x00,0xa4,0xac,
-0x00,0x00,0x64,0xac,0x04,0x00,0x83,0xac,0x00,0x60,0x86,0x40,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x02,0x24,0x04,0x00,0xff,0x00,0x84,0x30,0xc0,0x18,0x04,0x00,
-0x21,0x18,0x64,0x00,0x80,0x18,0x03,0x00,0x21,0x18,0x64,0x00,0x02,0x80,0x02,0x3c,
-0x68,0x15,0x42,0x24,0x80,0x18,0x03,0x00,0x21,0x18,0x62,0x00,0x78,0x51,0x64,0x8c,
-0xff,0xf1,0x02,0x24,0x24,0x20,0x82,0x00,0x08,0x00,0xe0,0x03,0x78,0x51,0x64,0xac,
-0x02,0x24,0x04,0x00,0xff,0x00,0x84,0x30,0xc0,0x18,0x04,0x00,0x21,0x18,0x64,0x00,
-0x80,0x18,0x03,0x00,0x21,0x18,0x64,0x00,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,
-0x80,0x18,0x03,0x00,0x21,0x18,0x62,0x00,0x78,0x51,0x64,0x8c,0xff,0xf1,0x02,0x24,
-0x24,0x20,0x82,0x00,0x00,0x02,0x84,0x34,0x08,0x00,0xe0,0x03,0x78,0x51,0x64,0xac,
-0xe0,0xff,0xbd,0x27,0x10,0x00,0xb0,0xaf,0xc0,0x80,0x04,0x00,0x21,0x80,0x04,0x02,
-0x80,0x80,0x10,0x00,0x21,0x80,0x04,0x02,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,
-0x80,0x80,0x10,0x00,0x21,0x80,0x02,0x02,0x1c,0x00,0xbf,0xaf,0x18,0x00,0xb2,0xaf,
-0x14,0x00,0xb1,0xaf,0x78,0x51,0x05,0x8e,0xff,0x1f,0x02,0x3c,0x25,0xb0,0x12,0x3c,
-0xff,0xff,0x42,0x34,0x70,0x51,0x02,0xae,0x84,0x01,0x43,0x36,0xf8,0xff,0x02,0x24,
-0x00,0x00,0x66,0x8c,0x24,0x28,0xa2,0x00,0xff,0xfe,0x02,0x24,0x24,0x28,0xa2,0x00,
-0xff,0xef,0x03,0x24,0x24,0x28,0xa3,0x00,0x74,0x51,0x06,0xae,0x78,0x51,0x05,0xae,
-0xce,0x0d,0x00,0x0c,0x21,0x88,0x80,0x00,0x7a,0x51,0x02,0x92,0x21,0x88,0x32,0x02,
-0x1c,0x00,0xbf,0x8f,0x60,0x01,0x22,0xa2,0x18,0x00,0xb2,0x8f,0x64,0x51,0x00,0xae,
-0x48,0x51,0x00,0xae,0x4c,0x51,0x00,0xae,0x50,0x51,0x00,0xae,0x54,0x51,0x00,0xae,
-0x58,0x51,0x00,0xae,0x5c,0x51,0x00,0xae,0x60,0x51,0x00,0xae,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0xff,0x00,0xa5,0x30,
-0xc0,0x10,0x05,0x00,0x21,0x10,0x45,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x45,0x00,
-0x02,0x80,0x03,0x3c,0x68,0x15,0x63,0x24,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,
-0x78,0x51,0x43,0x8c,0x25,0xb0,0x05,0x3c,0xff,0x00,0xc6,0x30,0x21,0x30,0xc5,0x00,
-0xaf,0x01,0xc2,0x90,0x07,0x00,0x63,0x30,0x80,0x18,0x03,0x00,0x21,0x18,0x65,0x00,
-0xff,0x00,0x88,0x30,0xff,0x00,0x49,0x30,0x84,0x01,0x66,0x8c,0x21,0x50,0x00,0x00,
-0x21,0x58,0x00,0x00,0x2b,0x00,0x20,0x11,0x21,0x20,0x00,0x01,0x2b,0x00,0xc0,0x10,
-0x2b,0x10,0x09,0x01,0x21,0x28,0x00,0x00,0x3e,0x4f,0x00,0x08,0x01,0x00,0x07,0x24,
-0xff,0x00,0x65,0x30,0x1d,0x00,0xa2,0x2c,0x07,0x00,0x40,0x10,0xff,0xff,0x02,0x25,
-0x04,0x10,0xa7,0x00,0x24,0x10,0x46,0x00,0xf9,0xff,0x40,0x10,0x01,0x00,0xa3,0x24,
-0x21,0x58,0xa0,0x00,0xff,0xff,0x02,0x25,0xff,0x00,0x45,0x30,0x2b,0x18,0xab,0x00,
-0x0f,0x00,0x60,0x14,0x2b,0x10,0x49,0x01,0x01,0x00,0x04,0x24,0x04,0x10,0xa4,0x00,
-0x24,0x10,0x46,0x00,0xff,0xff,0xa7,0x24,0x04,0x00,0x40,0x10,0x01,0x00,0x43,0x25,
-0x17,0x00,0x49,0x11,0xff,0x00,0x6a,0x30,0x21,0x40,0xa0,0x00,0xff,0x00,0xe5,0x30,
-0x2b,0x10,0xab,0x00,0xf6,0xff,0x40,0x10,0x04,0x10,0xa4,0x00,0x2b,0x10,0x49,0x01,
-0x08,0x00,0x40,0x10,0x21,0x20,0x00,0x01,0x23,0x10,0x2a,0x01,0x2a,0x10,0x62,0x01,
-0x04,0x00,0x40,0x14,0x21,0x20,0x00,0x00,0x23,0x10,0x69,0x01,0x21,0x10,0x4a,0x00,
-0xff,0x00,0x44,0x30,0x08,0x00,0xe0,0x03,0x21,0x10,0x80,0x00,0xfd,0xff,0x40,0x14,
-0x21,0x20,0x00,0x00,0x23,0x10,0x09,0x01,0x5f,0x4f,0x00,0x08,0xff,0x00,0x44,0x30,
-0x21,0x20,0x00,0x01,0x08,0x00,0xe0,0x03,0x21,0x10,0x80,0x00,0xff,0x00,0x84,0x30,
-0xc0,0x10,0x04,0x00,0x21,0x10,0x44,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x44,0x00,
-0x02,0x80,0x03,0x3c,0x68,0x15,0x63,0x24,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,
-0x25,0xb0,0x06,0x3c,0x78,0x51,0x43,0x8c,0xff,0x00,0xa5,0x30,0x21,0x20,0x86,0x00,
-0x21,0x28,0xa6,0x00,0x60,0x01,0x82,0x90,0xaf,0x01,0xa4,0x90,0x07,0x00,0x63,0x30,
-0x80,0x18,0x03,0x00,0x21,0x18,0x66,0x00,0xff,0x00,0x48,0x30,0xff,0x00,0x89,0x30,
-0x84,0x01,0x66,0x8c,0x21,0x50,0x00,0x00,0x21,0x58,0x00,0x00,0x2b,0x00,0x20,0x11,
-0x21,0x20,0x00,0x01,0x2b,0x00,0xc0,0x10,0x2b,0x10,0x09,0x01,0x21,0x28,0x00,0x00,
-0x8c,0x4f,0x00,0x08,0x01,0x00,0x07,0x24,0xff,0x00,0x65,0x30,0x1d,0x00,0xa2,0x2c,
-0x07,0x00,0x40,0x10,0xff,0xff,0x02,0x25,0x04,0x10,0xa7,0x00,0x24,0x10,0x46,0x00,
-0xf9,0xff,0x40,0x10,0x01,0x00,0xa3,0x24,0x21,0x58,0xa0,0x00,0xff,0xff,0x02,0x25,
-0xff,0x00,0x45,0x30,0x2b,0x18,0xab,0x00,0x0f,0x00,0x60,0x14,0x2b,0x10,0x49,0x01,
-0x01,0x00,0x04,0x24,0x04,0x10,0xa4,0x00,0x24,0x10,0x46,0x00,0xff,0xff,0xa7,0x24,
-0x04,0x00,0x40,0x10,0x01,0x00,0x43,0x25,0x17,0x00,0x49,0x11,0xff,0x00,0x6a,0x30,
-0x21,0x40,0xa0,0x00,0xff,0x00,0xe5,0x30,0x2b,0x10,0xab,0x00,0xf6,0xff,0x40,0x10,
-0x04,0x10,0xa4,0x00,0x2b,0x10,0x49,0x01,0x08,0x00,0x40,0x10,0x21,0x20,0x00,0x01,
-0x23,0x10,0x2a,0x01,0x2a,0x10,0x62,0x01,0x04,0x00,0x40,0x14,0x21,0x20,0x00,0x00,
-0x23,0x10,0x69,0x01,0x21,0x10,0x4a,0x00,0xff,0x00,0x44,0x30,0x08,0x00,0xe0,0x03,
-0x21,0x10,0x80,0x00,0xfd,0xff,0x40,0x14,0x21,0x20,0x00,0x00,0x23,0x10,0x09,0x01,
-0xad,0x4f,0x00,0x08,0xff,0x00,0x44,0x30,0x21,0x20,0x00,0x01,0x08,0x00,0xe0,0x03,
-0x21,0x10,0x80,0x00,0xe0,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c,0x10,0x00,0xb0,0xaf,
-0x68,0x15,0x50,0x24,0x18,0x00,0xb2,0xaf,0x14,0x00,0xb1,0xaf,0x1c,0x00,0xbf,0xaf,
-0x21,0x88,0x00,0x00,0x21,0x90,0x00,0x02,0xee,0x4e,0x00,0x0c,0x21,0x20,0x20,0x02,
-0x7a,0x51,0x02,0x92,0x21,0x28,0x00,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x52,0x00,
-0xec,0x44,0x44,0x8c,0x60,0x45,0x43,0x8c,0x00,0x00,0x00,0x00,0x21,0x18,0x64,0x00,
-0x42,0x18,0x03,0x00,0x44,0x51,0x03,0xae,0x21,0x10,0x05,0x02,0x01,0x00,0xa5,0x24,
-0x1d,0x00,0xa3,0x28,0xb6,0x51,0x40,0xa0,0x7c,0x51,0x40,0xa0,0xfa,0xff,0x60,0x14,
-0x99,0x51,0x40,0xa0,0x01,0x00,0x31,0x26,0x20,0x00,0x22,0x2a,0xd4,0x51,0x00,0xae,
-0xe9,0xff,0x40,0x14,0x94,0x00,0x10,0x26,0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f,
-0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,
-0xc8,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c,0x30,0x00,0xbe,0xaf,0x28,0x00,0xb6,0xaf,
-0x68,0x15,0x46,0x24,0x34,0x00,0xbf,0xaf,0x2c,0x00,0xb7,0xaf,0x24,0x00,0xb5,0xaf,
-0x20,0x00,0xb4,0xaf,0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf,0x14,0x00,0xb1,0xaf,
-0x10,0x00,0xb0,0xaf,0x8c,0x65,0xc2,0x8c,0xff,0x00,0x8d,0x30,0xff,0x00,0x03,0x24,
-0xff,0xff,0x42,0x38,0x21,0xf0,0x00,0x00,0xff,0xff,0x04,0x34,0x0a,0xf0,0x62,0x00,
-0x8c,0x65,0xc4,0xac,0xb0,0x00,0xa0,0x11,0x08,0x00,0x16,0x24,0x02,0x80,0x02,0x3c,
-0xb8,0x90,0x45,0x24,0x90,0x44,0xc4,0x24,0xff,0x4f,0x00,0x08,0x21,0x88,0x00,0x00,
-0x01,0x00,0x31,0x26,0x00,0x00,0x82,0xa0,0x1d,0x00,0x22,0x2a,0x0b,0x00,0x40,0x10,
-0x01,0x00,0x84,0x24,0x21,0x10,0x25,0x02,0x00,0x00,0x42,0x90,0x00,0x00,0x00,0x00,
-0xf7,0xff,0x40,0x10,0xfd,0xff,0x43,0x24,0x01,0x00,0x31,0x26,0x1d,0x00,0x22,0x2a,
-0x00,0x00,0x83,0xa0,0xf7,0xff,0x40,0x14,0x01,0x00,0x84,0x24,0x02,0x80,0x02,0x3c,
-0x68,0x15,0x4a,0x24,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0x50,0x8e,0x6c,0x24,
-0xd8,0x8d,0x4b,0x24,0x21,0x88,0x00,0x00,0x21,0x48,0x00,0x00,0x21,0x30,0x00,0x00,
-0x21,0x40,0x2a,0x01,0x21,0x38,0x2c,0x01,0x21,0x10,0xe6,0x00,0x91,0x00,0x44,0x90,
-0x00,0x00,0x45,0x90,0x21,0x18,0x06,0x01,0x01,0x00,0xc6,0x24,0x05,0x00,0xc2,0x28,
-0xc5,0x43,0x64,0xa0,0xf8,0xff,0x40,0x14,0x34,0x43,0x65,0xa0,0x21,0x10,0x2b,0x02,
-0x1d,0x00,0x44,0x90,0x00,0x00,0x45,0x90,0x21,0x18,0x2a,0x02,0x01,0x00,0x31,0x26,
-0x1d,0x00,0x22,0x2a,0x73,0x44,0x64,0xa0,0x56,0x44,0x65,0xa0,0xeb,0xff,0x40,0x14,
-0x05,0x00,0x29,0x25,0xa6,0x00,0xa0,0x11,0x02,0x80,0x02,0x3c,0x68,0x15,0x48,0x24,
-0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0x4c,0x91,0x69,0x24,0xd8,0x90,0x47,0x24,
-0x21,0x88,0x00,0x00,0x80,0x18,0x11,0x00,0x21,0x10,0x69,0x00,0x21,0x20,0x67,0x00,
-0x00,0x00,0x46,0x8c,0x00,0x00,0x85,0x8c,0x01,0x00,0x31,0x26,0x21,0x18,0x68,0x00,
-0x04,0x00,0x22,0x2a,0xec,0x44,0x65,0xac,0xf6,0xff,0x40,0x14,0x60,0x45,0x66,0xac,
-0x02,0x80,0x02,0x3c,0x68,0x15,0x49,0x24,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,
-0x4c,0x91,0x68,0x24,0xd8,0x90,0x47,0x24,0x04,0x00,0x11,0x24,0x80,0x20,0x11,0x00,
-0x21,0x10,0x88,0x00,0x21,0x30,0x87,0x00,0x00,0x00,0x45,0x8c,0x00,0x00,0xc3,0x8c,
-0x01,0x00,0x31,0x26,0x21,0x20,0x89,0x00,0x82,0x28,0x05,0x00,0x82,0x18,0x03,0x00,
-0x1d,0x00,0x22,0x2a,0xec,0x44,0x83,0xac,0xf4,0xff,0x40,0x14,0x60,0x45,0x85,0xac,
-0x02,0x80,0x02,0x3c,0x68,0x15,0x55,0x24,0x21,0x88,0x00,0x00,0x21,0xb8,0xa0,0x02,
-0x21,0xa0,0x00,0x00,0x5a,0x50,0x00,0x08,0x21,0x90,0xa0,0x02,0x01,0x00,0x31,0x26,
-0x20,0x00,0x22,0x2a,0x94,0x00,0x52,0x26,0x38,0x00,0x40,0x10,0x94,0x00,0x94,0x26,
-0x78,0x51,0x44,0x8e,0x01,0x00,0x03,0x24,0x02,0x13,0x04,0x00,0x01,0x00,0x53,0x30,
-0xf6,0xff,0x63,0x16,0x07,0x00,0x82,0x30,0x25,0xb0,0x03,0x3c,0x80,0x10,0x02,0x00,
-0x21,0x10,0x43,0x00,0x84,0x01,0x45,0x8c,0x70,0x51,0x43,0x8e,0x21,0x20,0x20,0x02,
-0x24,0x28,0xa3,0x00,0xce,0x0d,0x00,0x0c,0x74,0x51,0x45,0xae,0x7a,0x51,0x44,0x92,
-0x5c,0x0d,0x00,0x0c,0xff,0x00,0x25,0x32,0x7a,0x51,0x50,0x92,0x00,0x00,0x00,0x00,
-0x21,0x20,0x00,0x02,0x63,0x0d,0x00,0x0c,0x80,0x80,0x10,0x00,0x21,0x80,0x17,0x02,
-0x48,0x51,0x40,0xae,0x4c,0x51,0x40,0xae,0x50,0x51,0x40,0xae,0x54,0x51,0x40,0xae,
-0x58,0x51,0x40,0xae,0x5c,0x51,0x40,0xae,0x60,0x51,0x40,0xae,0x64,0x51,0x40,0xae,
-0xec,0x44,0x04,0x8e,0x60,0x45,0x03,0x8e,0x26,0x10,0x53,0x00,0x21,0x30,0x00,0x00,
-0x21,0x18,0x64,0x00,0x42,0x18,0x03,0x00,0x04,0x00,0x04,0x24,0x0a,0xb0,0x82,0x00,
-0x44,0x51,0x43,0xae,0x21,0x20,0x95,0x02,0x21,0x10,0x86,0x00,0x01,0x00,0xc6,0x24,
-0x1d,0x00,0xc3,0x28,0xb6,0x51,0x40,0xa0,0x7c,0x51,0x40,0xa0,0xfa,0xff,0x60,0x14,
-0x99,0x51,0x40,0xa0,0x01,0x00,0x31,0x26,0x20,0x00,0x22,0x2a,0xd4,0x51,0x80,0xac,
-0x94,0x00,0x52,0x26,0xca,0xff,0x40,0x14,0x94,0x00,0x94,0x26,0x25,0xb0,0x02,0x3c,
-0x80,0x01,0x42,0x34,0x00,0x00,0x56,0xa0,0x03,0x00,0xc0,0x17,0x02,0x80,0x03,0x3c,
-0x68,0x15,0x62,0x24,0x8c,0x65,0x40,0xac,0x34,0x00,0xbf,0x8f,0x30,0x00,0xbe,0x8f,
-0x2c,0x00,0xb7,0x8f,0x28,0x00,0xb6,0x8f,0x24,0x00,0xb5,0x8f,0x20,0x00,0xb4,0x8f,
-0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,
-0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27,0x02,0x80,0x02,0x3c,0xb8,0x90,0x45,0x24,
-0x90,0x44,0xc4,0x24,0x21,0x88,0x00,0x00,0x21,0x10,0x25,0x02,0x00,0x00,0x43,0x90,
-0x01,0x00,0x31,0x26,0x1d,0x00,0x22,0x2a,0x00,0x00,0x83,0xa0,0xfa,0xff,0x40,0x14,
-0x01,0x00,0x84,0x24,0x02,0x80,0x02,0x3c,0x68,0x15,0x4a,0x24,0x02,0x80,0x03,0x3c,
-0x02,0x80,0x02,0x3c,0x74,0x8f,0x6c,0x24,0x14,0x8e,0x4b,0x24,0x21,0x88,0x00,0x00,
-0x21,0x48,0x00,0x00,0x21,0x30,0x00,0x00,0x21,0x40,0x2a,0x01,0x21,0x38,0x2c,0x01,
-0x21,0x10,0xe6,0x00,0x91,0x00,0x44,0x90,0x00,0x00,0x45,0x90,0x21,0x18,0x06,0x01,
-0x01,0x00,0xc6,0x24,0x05,0x00,0xc2,0x28,0xc5,0x43,0x64,0xa0,0xf8,0xff,0x40,0x14,
-0x34,0x43,0x65,0xa0,0x21,0x10,0x2b,0x02,0x1d,0x00,0x44,0x90,0x00,0x00,0x45,0x90,
-0x21,0x18,0x2a,0x02,0x01,0x00,0x31,0x26,0x1d,0x00,0x22,0x2a,0x73,0x44,0x64,0xa0,
-0x56,0x44,0x65,0xa0,0xeb,0xff,0x40,0x14,0x05,0x00,0x29,0x25,0x02,0x80,0x02,0x3c,
-0x68,0x15,0x49,0x24,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0x4c,0x91,0x68,0x24,
-0xd8,0x90,0x47,0x24,0x21,0x88,0x00,0x00,0x80,0x18,0x11,0x00,0x21,0x10,0x68,0x00,
-0x21,0x20,0x67,0x00,0x00,0x00,0x46,0x8c,0x00,0x00,0x85,0x8c,0x01,0x00,0x31,0x26,
-0x21,0x18,0x69,0x00,0x1d,0x00,0x22,0x2a,0xec,0x44,0x65,0xac,0xf6,0xff,0x40,0x14,
-0x60,0x45,0x66,0xac,0x4f,0x50,0x00,0x08,0x02,0x80,0x02,0x3c,0xd8,0xff,0xbd,0x27,
-0xff,0xff,0x84,0x30,0x18,0x00,0xb2,0xaf,0xf0,0x01,0x92,0x30,0x02,0x91,0x12,0x00,
-0x14,0x00,0xb1,0xaf,0xc0,0x88,0x12,0x00,0x21,0x88,0x32,0x02,0x80,0x88,0x11,0x00,
-0x21,0x88,0x32,0x02,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,0x80,0x88,0x11,0x00,
-0x21,0x88,0x22,0x02,0x20,0x00,0xbf,0xaf,0x1c,0x00,0xb3,0xaf,0x10,0x00,0xb0,0xaf,
-0x78,0x51,0x30,0x8e,0x00,0x02,0x82,0x30,0xff,0xfe,0x03,0x24,0x2b,0x10,0x02,0x00,
-0x00,0x10,0x10,0x36,0x24,0x80,0x03,0x02,0x00,0x12,0x02,0x00,0x25,0x80,0x02,0x02,
-0x70,0x51,0x25,0xae,0x78,0x51,0x30,0xae,0xa0,0x0e,0x00,0x0c,0x21,0x98,0xa0,0x00,
-0xf8,0xff,0x03,0x24,0x24,0x80,0x03,0x02,0x07,0x00,0x42,0x30,0x25,0x80,0x02,0x02,
-0x07,0x00,0x03,0x32,0x25,0xb0,0x02,0x3c,0x80,0x18,0x03,0x00,0x78,0x51,0x30,0xae,
-0x21,0x18,0x62,0x00,0x84,0x01,0x62,0x8c,0x21,0x20,0x40,0x02,0x24,0x10,0x53,0x00,
-0xce,0x0d,0x00,0x0c,0x74,0x51,0x22,0xae,0x7a,0x51,0x24,0x92,0x21,0x28,0x40,0x02,
-0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x5c,0x0d,0x00,0x08,0x28,0x00,0xbd,0x27,0xee,0x4e,0x00,0x08,
-0xff,0x00,0x84,0x30,0x02,0x80,0x02,0x3c,0x68,0x15,0x43,0x24,0x1f,0x00,0x04,0x24,
-0x78,0x51,0x62,0x8c,0xff,0xff,0x84,0x24,0x00,0x10,0x42,0x34,0x78,0x51,0x62,0xac,
-0xfb,0xff,0x81,0x04,0x94,0x00,0x63,0x24,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x78,0xff,0xbd,0x27,0x60,0x00,0xb0,0xaf,0x25,0xb0,0x10,0x3c,0x70,0x00,0xb4,0xaf,
-0xc4,0x02,0x14,0x36,0x00,0x00,0x80,0xae,0x74,0x00,0xb5,0xaf,0x6c,0x00,0xb3,0xaf,
-0x68,0x00,0xb2,0xaf,0x64,0x00,0xb1,0xaf,0x84,0x00,0xbf,0xaf,0x80,0x00,0xbe,0xaf,
-0x7c,0x00,0xb7,0xaf,0x78,0x00,0xb6,0xaf,0x04,0x00,0x02,0x36,0x04,0x0c,0x13,0x36,
-0x00,0x00,0x43,0x8c,0x00,0x00,0x62,0x8e,0x0f,0x00,0x11,0x3c,0x24,0x18,0x71,0x00,
-0x08,0x0c,0x12,0x36,0x4c,0x00,0xa2,0xaf,0x02,0xac,0x03,0x00,0x00,0x00,0x43,0x8e,
-0x00,0x00,0x00,0x00,0x50,0x00,0xa3,0xaf,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x21,0x20,0x00,0x00,0xdd,0x44,0x00,0x0c,
-0xff,0xff,0x25,0x36,0x10,0x00,0xa2,0xaf,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x00,0x60,0x81,0x40,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x7a,0x42,0x00,0x0c,
-0x01,0x00,0x04,0x24,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,
-0x00,0x60,0x81,0x40,0x21,0x20,0x00,0x00,0xdd,0x44,0x00,0x0c,0xff,0xff,0x25,0x36,
-0x14,0x00,0xa2,0xaf,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x7a,0x42,0x00,0x0c,0x21,0x20,0x00,0x00,
-0xe0,0x0e,0x05,0x36,0x00,0x00,0xad,0x8c,0xdc,0x0e,0x06,0x36,0x70,0x0e,0x07,0x36,
-0x18,0x00,0xad,0xaf,0x00,0x00,0xc2,0x8c,0x74,0x0e,0x08,0x36,0x78,0x0e,0x09,0x36,
-0x1c,0x00,0xa2,0xaf,0x00,0x00,0xe3,0x8c,0x7c,0x0e,0x0a,0x36,0x80,0x0e,0x0b,0x36,
-0x20,0x00,0xa3,0xaf,0x00,0x00,0x0d,0x8d,0x84,0x0e,0x0c,0x36,0x88,0x0e,0x17,0x36,
-0x24,0x00,0xad,0xaf,0x00,0x00,0x22,0x8d,0x8c,0x0e,0x0e,0x36,0xd0,0x0e,0x18,0x36,
-0x28,0x00,0xa2,0xaf,0x00,0x00,0x43,0x8d,0xd8,0x0e,0x11,0x36,0xd4,0x0e,0x10,0x36,
-0x2c,0x00,0xa3,0xaf,0x00,0x00,0x6d,0x8d,0xed,0x3f,0x04,0x3c,0xfb,0x92,0x84,0x34,
-0x30,0x00,0xad,0xaf,0x00,0x00,0x82,0x8d,0x25,0xb0,0x1e,0x3c,0x21,0xb0,0x00,0x00,
-0x34,0x00,0xa2,0xaf,0x00,0x00,0xe3,0x8e,0xff,0x03,0x0f,0x3c,0x38,0x00,0xa3,0xaf,
-0x00,0x00,0xcd,0x8d,0x00,0x00,0x00,0x00,0x3c,0x00,0xad,0xaf,0x00,0x00,0x02,0x8f,
-0x00,0x00,0x00,0x00,0x40,0x00,0xa2,0xaf,0x00,0x00,0x03,0x8e,0x00,0x00,0x00,0x00,
-0x44,0x00,0xa3,0xaf,0x00,0x00,0x2d,0x8e,0x00,0x00,0x00,0x00,0x48,0x00,0xad,0xaf,
-0x00,0x00,0xa4,0xac,0x00,0x00,0xc4,0xac,0x00,0x00,0xe4,0xac,0x00,0x00,0x04,0xad,
-0x00,0x00,0x24,0xad,0x00,0x00,0x44,0xad,0x00,0x00,0x64,0xad,0x00,0x00,0x84,0xad,
-0x00,0x00,0xe4,0xae,0x00,0x00,0xc4,0xad,0x00,0x00,0x04,0xaf,0x00,0x00,0x04,0xae,
-0x00,0x00,0x24,0xae,0xd0,0x51,0x00,0x08,0x00,0x00,0x00,0x00,0x7a,0x00,0xa2,0x12,
-0x00,0x10,0x03,0x3c,0xac,0x0e,0xc2,0x37,0x94,0x0e,0xc3,0x37,0x25,0xb0,0x09,0x3c,
-0x00,0x00,0x4a,0x8c,0xbc,0x0e,0x29,0x35,0x00,0x00,0x64,0x8c,0xb4,0x0e,0xc2,0x37,
-0x9c,0x0e,0xc3,0x37,0x00,0x00,0x45,0x8c,0x00,0x00,0x66,0x8c,0x00,0x00,0x27,0x8d,
-0x24,0x20,0x8f,0x00,0x00,0xd8,0x02,0x3c,0x24,0x10,0x42,0x01,0x24,0x28,0xaf,0x00,
-0x24,0x30,0xcf,0x00,0x24,0x38,0xef,0x00,0x02,0x24,0x04,0x00,0x20,0x01,0x03,0x24,
-0x01,0x00,0x42,0x2c,0x02,0x2c,0x05,0x00,0x02,0x34,0x06,0x00,0xf2,0x00,0x83,0x10,
-0x02,0x3c,0x07,0x00,0xf0,0x00,0xa3,0x10,0x20,0x00,0x03,0x24,0xee,0x00,0xc3,0x10,
-0x00,0x00,0x00,0x00,0xec,0x00,0xe3,0x10,0x01,0x00,0x08,0x24,0x80,0x00,0x03,0x24,
-0x08,0x00,0x83,0x10,0x21,0x20,0x00,0x00,0x06,0x00,0xa3,0x10,0x21,0x20,0x00,0x00,
-0xe0,0x03,0x03,0x24,0x03,0x00,0xc3,0x10,0x00,0x00,0x00,0x00,0xe5,0x00,0xe3,0x10,
-0x01,0x00,0x04,0x24,0x06,0x00,0x40,0x10,0x09,0x00,0x02,0x24,0x04,0x00,0x00,0x11,
-0x00,0x00,0x00,0x00,0x6d,0x01,0x80,0x14,0x25,0xb0,0x12,0x3c,0x09,0x00,0x02,0x24,
-0xde,0x00,0xc2,0x12,0x25,0xb0,0x04,0x3c,0x01,0x00,0xd6,0x26,0x0a,0x00,0xc2,0x2e,
-0x1d,0x01,0x40,0x10,0x00,0x00,0x00,0x00,0xc8,0xff,0xa0,0x16,0x01,0x00,0x02,0x24,
-0xa0,0x00,0x03,0x3c,0x25,0xb0,0x09,0x3c,0x30,0x54,0x62,0x34,0x04,0x0c,0x29,0x35,
-0x00,0x00,0x22,0xad,0x25,0xb0,0x0d,0x3c,0x08,0x00,0x02,0x3c,0xe4,0x00,0x42,0x34,
-0x08,0x0c,0xad,0x35,0x25,0xb0,0x09,0x3c,0x00,0x00,0xa2,0xad,0x28,0x0e,0x29,0x35,
-0x80,0x80,0x02,0x3c,0x00,0x00,0x22,0xad,0x14,0x02,0x04,0x3c,0x16,0x68,0x02,0x3c,
-0x48,0x01,0x83,0x34,0x40,0x0e,0xc5,0x37,0x44,0x0e,0xc6,0x37,0xa2,0x04,0x42,0x34,
-0x25,0xb0,0x0d,0x3c,0x00,0x00,0xa3,0xac,0x4c,0x0e,0xad,0x35,0x00,0x00,0xc2,0xac,
-0xd1,0x28,0x02,0x24,0x00,0x00,0xa2,0xad,0x14,0x02,0x03,0x3c,0x16,0x28,0x02,0x3c,
-0x4d,0x01,0x63,0x34,0x60,0x0e,0xc7,0x37,0x64,0x0e,0xc8,0x37,0xba,0x08,0x42,0x34,
-0x00,0x00,0xe3,0xac,0x25,0xb0,0x06,0x3c,0x00,0x00,0x02,0xad,0x00,0xfb,0x0d,0x3c,
-0x25,0xb0,0x09,0x3c,0x00,0xf8,0x02,0x3c,0xd1,0x28,0x07,0x24,0x6c,0x0e,0xc6,0x34,
-0x48,0x0e,0x29,0x35,0x01,0x00,0x42,0x34,0x01,0x00,0xad,0x35,0x00,0x00,0xc7,0xac,
-0x03,0x00,0x04,0x24,0x00,0x00,0x2d,0xad,0x00,0x00,0x22,0xad,0x84,0x0a,0x00,0x0c,
-0x58,0x00,0xaf,0xaf,0xa0,0x00,0x04,0x3c,0x25,0xb0,0x03,0x3c,0x25,0xb0,0x06,0x3c,
-0x25,0xb0,0x07,0x3c,0xe4,0x00,0x02,0x24,0x33,0x54,0x84,0x34,0x04,0x0c,0x63,0x34,
-0x08,0x0c,0xc6,0x34,0x28,0x0e,0xe7,0x34,0x00,0x00,0x64,0xac,0x00,0x00,0xc2,0xac,
-0x00,0x00,0xe0,0xac,0x01,0x00,0x02,0x24,0x58,0x00,0xaf,0x8f,0x8a,0xff,0xa2,0x16,
-0xac,0x0e,0xc2,0x37,0x00,0x10,0x03,0x3c,0x1f,0xdc,0x79,0x34,0x1f,0x8c,0x7f,0x34,
-0x23,0x8c,0x6d,0x34,0xa0,0x00,0x03,0x3c,0x30,0x54,0x65,0x34,0x00,0x01,0x17,0x3c,
-0x25,0xb0,0x09,0x3c,0x25,0xb0,0x03,0x3c,0x00,0x01,0xe2,0x36,0x20,0x08,0x29,0x35,
-0x20,0x08,0x63,0x34,0x00,0x00,0x30,0x8d,0x00,0x00,0x62,0xac,0x25,0xb0,0x03,0x3c,
-0x28,0x08,0x63,0x34,0x00,0x00,0x62,0xac,0x25,0xb0,0x02,0x3c,0x04,0x0c,0x42,0x34,
-0x00,0x00,0x45,0xac,0x25,0xb0,0x03,0x3c,0x08,0x00,0x02,0x3c,0xe4,0x00,0x42,0x34,
-0x08,0x0c,0x63,0x34,0x00,0x00,0x62,0xac,0x25,0xb0,0x03,0x3c,0x00,0x7c,0xf3,0x36,
-0x00,0x48,0xf4,0x36,0x30,0x0e,0xc6,0x37,0x34,0x0e,0xc7,0x37,0x80,0x80,0x02,0x3c,
-0x28,0x0e,0x63,0x34,0x00,0x00,0x62,0xac,0x00,0x00,0xd3,0xac,0x00,0x00,0xf4,0xac,
-0x14,0x02,0x06,0x3c,0x16,0x68,0x07,0x3c,0x38,0x0e,0xc8,0x37,0x40,0x0e,0xca,0x37,
-0x44,0x0e,0xcb,0x37,0x3c,0x0e,0xc9,0x37,0x02,0x01,0xc6,0x34,0xc7,0x04,0xe7,0x34,
-0x00,0x00,0x19,0xad,0x25,0xb0,0x03,0x3c,0x00,0x00,0x3f,0xad,0x00,0x00,0x46,0xad,
-0x25,0xb0,0x09,0x3c,0x00,0x00,0x67,0xad,0x25,0xb0,0x06,0x3c,0x00,0x10,0x07,0x3c,
-0x50,0x0e,0xcc,0x37,0x58,0x0e,0xce,0x37,0x5c,0x0e,0xd8,0x37,0xd1,0x28,0x02,0x24,
-0x23,0xdc,0xe7,0x34,0x4c,0x0e,0x29,0x35,0x6c,0x0e,0x63,0x34,0x54,0x0e,0xc6,0x34,
-0x00,0x00,0x22,0xad,0x00,0x00,0x62,0xac,0x14,0x02,0x09,0x3c,0x00,0x00,0x93,0xad,
-0x25,0xb0,0x02,0x3c,0x00,0x00,0xd4,0xac,0x00,0x00,0xc7,0xad,0x00,0x00,0x0d,0xaf,
-0x16,0x28,0x0d,0x3c,0x48,0x0e,0x42,0x34,0x00,0xf8,0x06,0x3c,0x02,0x01,0x29,0x35,
-0x07,0x0d,0xad,0x35,0x00,0xfb,0x03,0x3c,0x60,0x0e,0xd1,0x37,0x64,0x0e,0xd2,0x37,
-0x00,0x00,0x29,0xae,0x03,0x00,0x04,0x24,0x00,0x00,0x4d,0xae,0x00,0x00,0x43,0xac,
-0x00,0x00,0x46,0xac,0x84,0x0a,0x00,0x0c,0x58,0x00,0xaf,0xaf,0x00,0x02,0x02,0x3c,
-0x25,0xb0,0x07,0x3c,0x25,0xb0,0x09,0x3c,0xd1,0x28,0x42,0x34,0x4c,0x0e,0xe7,0x34,
-0x6c,0x0e,0x29,0x35,0x25,0xb0,0x0d,0x3c,0x00,0x00,0xe2,0xac,0x48,0x0e,0xad,0x35,
-0x00,0x00,0x22,0xad,0x00,0xf8,0x03,0x3c,0x00,0xfb,0x02,0x3c,0x00,0x00,0xa2,0xad,
-0x03,0x00,0x04,0x24,0x00,0x00,0xa3,0xad,0x84,0x0a,0x00,0x0c,0x00,0x00,0x00,0x00,
-0x4c,0x00,0xa6,0x8f,0x25,0xb0,0x04,0x3c,0x04,0x0c,0x84,0x34,0x00,0x00,0x86,0xac,
-0x50,0x00,0xa9,0x8f,0x25,0xb0,0x07,0x3c,0x25,0xb0,0x0d,0x3c,0x00,0x01,0x10,0x32,
-0x08,0x0c,0xe7,0x34,0x28,0x0e,0xad,0x35,0x00,0x00,0xe9,0xac,0x2b,0x80,0x10,0x00,
-0x00,0x00,0xa0,0xad,0x58,0x00,0xaf,0x8f,0x17,0xff,0x00,0x16,0xac,0x0e,0xc2,0x37,
-0x25,0xb0,0x02,0x3c,0x25,0xb0,0x03,0x3c,0x20,0x08,0x42,0x34,0x28,0x08,0x63,0x34,
-0x00,0x00,0x57,0xac,0x25,0xb0,0x09,0x3c,0x00,0x00,0x77,0xac,0xac,0x0e,0xc2,0x37,
-0x94,0x0e,0xc3,0x37,0x00,0x00,0x4a,0x8c,0xbc,0x0e,0x29,0x35,0x00,0x00,0x64,0x8c,
-0xb4,0x0e,0xc2,0x37,0x9c,0x0e,0xc3,0x37,0x00,0x00,0x45,0x8c,0x00,0x00,0x66,0x8c,
-0x00,0x00,0x27,0x8d,0x24,0x20,0x8f,0x00,0x00,0xd8,0x02,0x3c,0x24,0x10,0x42,0x01,
-0x24,0x28,0xaf,0x00,0x24,0x30,0xcf,0x00,0x24,0x38,0xef,0x00,0x02,0x24,0x04,0x00,
-0x20,0x01,0x03,0x24,0x01,0x00,0x42,0x2c,0x02,0x2c,0x05,0x00,0x02,0x34,0x06,0x00,
-0x10,0xff,0x83,0x14,0x02,0x3c,0x07,0x00,0x80,0x00,0x03,0x24,0x16,0xff,0x83,0x14,
-0x21,0x40,0x00,0x00,0xc3,0x51,0x00,0x08,0x21,0x20,0x00,0x00,0xff,0xff,0x02,0x34,
-0xc4,0x02,0x84,0x34,0x00,0x00,0x82,0xac,0x94,0x0e,0xc3,0x37,0x9c,0x0e,0xc2,0x37,
-0xa4,0x0e,0xc4,0x37,0xac,0x0e,0xc7,0x37,0x00,0x00,0x66,0x8c,0x00,0x00,0x49,0x8c,
-0x00,0x00,0x8b,0x8c,0x00,0x00,0xe5,0x8c,0x02,0x80,0x07,0x3c,0x68,0x15,0xe7,0x24,
-0x0c,0x40,0xe3,0x8c,0x10,0x40,0xe4,0x8c,0xb4,0x0e,0xc2,0x37,0x00,0x00,0x47,0x8c,
-0x25,0xb0,0x0d,0x3c,0x00,0xfc,0x02,0x24,0x24,0x30,0xcf,0x00,0x24,0x28,0xaf,0x00,
-0xbc,0x0e,0xad,0x35,0x00,0x00,0xa8,0x8d,0x24,0x20,0x82,0x00,0x02,0x34,0x06,0x00,
-0x24,0x18,0x62,0x00,0x02,0x2c,0x05,0x00,0xc4,0x0e,0xca,0x37,0xcc,0x0e,0xcc,0x37,
-0xf0,0xff,0x02,0x3c,0xff,0x03,0x42,0x34,0x25,0x18,0x66,0x00,0x25,0x20,0x85,0x00,
-0x00,0x00,0x46,0x8d,0x24,0x48,0x2f,0x01,0x00,0x00,0x85,0x8d,0x24,0x38,0xef,0x00,
-0x24,0x20,0x82,0x00,0x24,0x18,0x62,0x00,0x82,0x49,0x09,0x00,0x82,0x39,0x07,0x00,
-0x0f,0xc0,0x02,0x3c,0xff,0xff,0x42,0x34,0x25,0x18,0x69,0x00,0x25,0x20,0x87,0x00,
-0x24,0x58,0x6f,0x01,0x24,0x40,0x0f,0x01,0x24,0x20,0x82,0x00,0x24,0x18,0x62,0x00,
-0x00,0x59,0x0b,0x00,0x00,0x41,0x08,0x00,0x24,0x30,0xcf,0x00,0x24,0x28,0xaf,0x00,
-0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,0x25,0x18,0x6b,0x00,0x25,0x20,0x88,0x00,
-0x02,0x34,0x06,0x00,0x02,0x2c,0x05,0x00,0x01,0x00,0xd6,0x26,0x0c,0x40,0x43,0xac,
-0x10,0x40,0x44,0xac,0x14,0x40,0x46,0xa4,0x16,0x40,0x45,0xa4,0x0a,0x00,0xc2,0x2e,
-0xe5,0xfe,0x40,0x14,0x00,0x00,0x00,0x00,0x18,0x00,0xad,0x8f,0x25,0xb0,0x02,0x3c,
-0xe0,0x0e,0x43,0x34,0x10,0x00,0xa6,0x8f,0x00,0x00,0x6d,0xac,0x1c,0x00,0xa3,0x8f,
-0xdc,0x0e,0x47,0x34,0x70,0x0e,0x48,0x34,0x00,0x00,0xe3,0xac,0x20,0x00,0xa7,0x8f,
-0x74,0x0e,0x49,0x34,0x78,0x0e,0x4a,0x34,0x00,0x00,0x07,0xad,0x24,0x00,0xad,0x8f,
-0x7c,0x0e,0x4b,0x34,0x80,0x0e,0x4c,0x34,0x00,0x00,0x2d,0xad,0x28,0x00,0xa3,0x8f,
-0x25,0xb0,0x0d,0x3c,0x84,0x0e,0xad,0x35,0x00,0x00,0x43,0xad,0x2c,0x00,0xa7,0x8f,
-0x88,0x0e,0x52,0x34,0x8c,0x0e,0x4e,0x34,0x00,0x00,0x67,0xad,0x30,0x00,0xa9,0x8f,
-0xd4,0x0e,0x51,0x34,0xd0,0x0e,0x42,0x34,0x00,0x00,0x89,0xad,0x34,0x00,0xa3,0x8f,
-0x0f,0x00,0x10,0x3c,0xff,0xff,0x05,0x36,0x00,0x00,0xa3,0xad,0x38,0x00,0xa7,0x8f,
-0x21,0x20,0x00,0x00,0x00,0x00,0x47,0xae,0x3c,0x00,0xa9,0x8f,0x00,0x00,0x00,0x00,
-0x00,0x00,0xc9,0xad,0x40,0x00,0xad,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x4d,0xac,
-0x44,0x00,0xa2,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0xae,0x48,0x00,0xa3,0x8f,
-0x00,0x00,0x00,0x00,0x00,0x00,0x43,0xae,0xba,0x44,0x00,0x0c,0x00,0x00,0x00,0x00,
-0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x7a,0x42,0x00,0x0c,0x01,0x00,0x04,0x24,
-0x14,0x00,0xa6,0x8f,0xff,0xff,0x05,0x36,0xba,0x44,0x00,0x0c,0x21,0x20,0x00,0x00,
-0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x84,0x00,0xbf,0x8f,0x80,0x00,0xbe,0x8f,
-0x7c,0x00,0xb7,0x8f,0x78,0x00,0xb6,0x8f,0x74,0x00,0xb5,0x8f,0x70,0x00,0xb4,0x8f,
-0x6c,0x00,0xb3,0x8f,0x68,0x00,0xb2,0x8f,0x64,0x00,0xb1,0x8f,0x60,0x00,0xb0,0x8f,
-0x21,0x20,0x00,0x00,0x7a,0x42,0x00,0x08,0x88,0x00,0xbd,0x27,0x94,0x0e,0x42,0x36,
-0x9c,0x0e,0x43,0x36,0xa4,0x0e,0x44,0x36,0xac,0x0e,0x45,0x36,0x02,0x80,0x0d,0x3c,
-0x00,0x00,0x47,0x8c,0x68,0x15,0xad,0x25,0x00,0x00,0x6a,0x8c,0x00,0x00,0x8c,0x8c,
-0x00,0x00,0xa3,0x8c,0x10,0x40,0xa4,0x8d,0xb4,0x0e,0x42,0x36,0x00,0x00,0x48,0x8c,
-0x0c,0x40,0xa5,0x8d,0x25,0xb0,0x02,0x3c,0x00,0xfc,0x13,0x24,0xbc,0x0e,0x42,0x34,
-0x24,0x18,0x6f,0x00,0x00,0x00,0x49,0x8c,0x02,0x1c,0x03,0x00,0x24,0x38,0xef,0x00,
-0x24,0x20,0x93,0x00,0xf0,0xff,0x06,0x3c,0x25,0x20,0x83,0x00,0xff,0x03,0xc6,0x34,
-0x02,0x3c,0x07,0x00,0xc4,0x0e,0x42,0x36,0x24,0x28,0xb3,0x00,0x24,0x40,0x0f,0x01,
-0xcc,0x0e,0x4b,0x36,0x25,0x28,0xa7,0x00,0x24,0x20,0x86,0x00,0x00,0x00,0x47,0x8c,
-0x24,0x50,0x4f,0x01,0x00,0x00,0x63,0x8d,0x82,0x41,0x08,0x00,0x0f,0xc0,0x02,0x3c,
-0xff,0xff,0x42,0x34,0x25,0x20,0x88,0x00,0x82,0x51,0x0a,0x00,0x24,0x28,0xa6,0x00,
-0x24,0x48,0x2f,0x01,0x24,0x88,0x82,0x00,0x25,0x28,0xaa,0x00,0x24,0x60,0x8f,0x01,
-0x00,0x49,0x09,0x00,0x25,0x88,0x29,0x02,0x24,0x28,0xa2,0x00,0x24,0x18,0x6f,0x00,
-0x00,0x61,0x0c,0x00,0x24,0x38,0xef,0x00,0x25,0x28,0xac,0x00,0x02,0x3c,0x07,0x00,
-0x02,0x1c,0x03,0x00,0x82,0x27,0x11,0x00,0x01,0x00,0x02,0x24,0x16,0x40,0xa3,0xa5,
-0x14,0x40,0xa7,0xa5,0x0c,0x40,0xa5,0xad,0x4a,0x00,0x82,0x10,0x10,0x40,0xb1,0xad,
-0x80,0x0c,0x4c,0x36,0x00,0x00,0x8a,0x8d,0x82,0x72,0x05,0x00,0xff,0x03,0xce,0x31,
-0x00,0x02,0xc3,0x31,0x25,0x10,0xd3,0x01,0x0b,0x70,0x43,0x00,0x82,0x85,0x0a,0x00,
-0x18,0x00,0xd0,0x01,0xff,0x03,0xaf,0x30,0x00,0x02,0xa3,0x30,0x25,0x10,0xf3,0x01,
-0x0b,0x78,0x43,0x00,0x02,0x75,0x11,0x00,0xff,0x03,0xce,0x31,0xc0,0xff,0x08,0x3c,
-0x25,0x18,0xd3,0x01,0x00,0x02,0xc2,0x31,0x00,0xfc,0x06,0x35,0x0b,0x70,0x62,0x00,
-0x24,0x38,0x46,0x01,0x94,0x0c,0x4a,0x36,0xff,0x0f,0x09,0x3c,0xff,0xff,0x29,0x35,
-0x88,0x0c,0x54,0x36,0x12,0x20,0x00,0x00,0x02,0x22,0x04,0x00,0x3f,0x00,0x82,0x30,
-0x18,0x00,0xf0,0x01,0x82,0x7a,0x11,0x00,0xff,0x03,0xef,0x31,0x00,0x14,0x02,0x00,
-0x25,0x38,0xe2,0x00,0x00,0x02,0xe3,0x31,0x25,0x10,0xf3,0x01,0x0b,0x78,0x43,0x00,
-0xc0,0x03,0x84,0x30,0x80,0x25,0x04,0x00,0x9c,0x0c,0x4b,0x36,0x12,0x28,0x00,0x00,
-0x02,0x2a,0x05,0x00,0xff,0x03,0xa2,0x30,0x25,0x10,0xe2,0x00,0x00,0x00,0x82,0xad,
-0x00,0x00,0x42,0x8d,0x00,0x00,0x00,0x00,0x24,0x10,0x49,0x00,0x25,0x10,0x44,0x00,
-0x00,0x00,0x42,0xad,0x00,0x00,0x8a,0x8e,0x00,0x00,0x00,0x00,0x24,0x40,0x48,0x01,
-0x82,0x85,0x08,0x00,0x18,0x00,0xd0,0x01,0x24,0x30,0x46,0x01,0x12,0x18,0x00,0x00,
-0x02,0x1a,0x03,0x00,0x3f,0x00,0x62,0x30,0x18,0x00,0xf0,0x01,0x00,0x14,0x02,0x00,
-0x25,0x30,0xc2,0x00,0xc0,0x03,0x63,0x30,0x80,0x1d,0x03,0x00,0x12,0x20,0x00,0x00,
-0x02,0x22,0x04,0x00,0xff,0x03,0x82,0x30,0x25,0x10,0xc2,0x00,0x00,0x00,0x82,0xae,
-0x00,0x00,0x62,0x8d,0x00,0x00,0x00,0x00,0x24,0x10,0x49,0x00,0x25,0x10,0x43,0x00,
-0x00,0x00,0x62,0xad,0x00,0x17,0x16,0x00,0x25,0xb0,0x03,0x3c,0xdd,0xdd,0x42,0x34,
-0xc4,0x02,0x63,0x34,0x00,0x00,0x62,0xac,0xec,0x52,0x00,0x08,0x00,0x00,0x00,0x00,
-0xe0,0xff,0xbd,0x27,0x44,0x00,0x02,0x24,0x10,0x00,0xa2,0xa3,0x49,0x00,0x03,0x24,
-0x47,0x00,0x02,0x24,0x02,0x80,0x07,0x3c,0x8c,0x97,0xe7,0x24,0x11,0x00,0xa3,0xa3,
-0x12,0x00,0xa2,0xa3,0x10,0x27,0x03,0x24,0x01,0x00,0x02,0x24,0x01,0x80,0x06,0x3c,
-0x10,0x00,0xa5,0x27,0x21,0x20,0xe0,0x00,0xe8,0x51,0xc6,0x24,0x0c,0x00,0xe3,0xac,
-0x14,0x00,0xe2,0xa0,0x18,0x00,0xbf,0xaf,0xfb,0x0c,0x00,0x0c,0x13,0x00,0xa0,0xa3,
-0x18,0x00,0xbf,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,
-0xd0,0xff,0xbd,0x27,0x25,0xb0,0x02,0x3c,0x20,0x00,0xb4,0xaf,0x1c,0x00,0xb3,0xaf,
-0x03,0x0d,0x44,0x34,0x2c,0x00,0xbf,0xaf,0x28,0x00,0xb6,0xaf,0x24,0x00,0xb5,0xaf,
-0x18,0x00,0xb2,0xaf,0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x00,0x83,0x90,
-0x42,0x00,0x45,0x34,0xff,0x00,0x73,0x30,0x70,0x00,0x74,0x32,0x29,0x00,0x80,0x16,
-0x8f,0x00,0x62,0x32,0xff,0xff,0x02,0x24,0x00,0x00,0xa2,0xa0,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x0f,0x00,0x11,0x3c,
-0x18,0x00,0x04,0x24,0xdd,0x44,0x00,0x0c,0xff,0xff,0x25,0x36,0x21,0x80,0x40,0x00,
-0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0xb3,0x0a,0x00,0x0c,
-0x64,0x00,0x04,0x24,0x00,0x80,0x06,0x36,0xff,0xff,0x25,0x36,0xba,0x44,0x00,0x0c,
-0x18,0x00,0x04,0x24,0x84,0x0a,0x00,0x0c,0x03,0x00,0x04,0x24,0x21,0x30,0xa0,0x02,
-0xff,0xff,0x25,0x36,0x5c,0x00,0x80,0x16,0x21,0x20,0x00,0x00,0x2c,0x00,0xbf,0x8f,
-0x28,0x00,0xb6,0x8f,0x24,0x00,0xb5,0x8f,0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f,
-0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x25,0xb0,0x02,0x3c,
-0x42,0x00,0x42,0x34,0x30,0x00,0xbd,0x27,0x00,0x00,0x40,0xa0,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x00,0x00,0x82,0xa0,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x0f,0x00,0x11,0x3c,0x21,0x20,0x00,0x00,
-0xdd,0x44,0x00,0x0c,0xff,0xff,0x25,0x36,0x21,0xa8,0x40,0x00,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,
-0x7a,0x42,0x00,0x0c,0x01,0x00,0x04,0x24,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x21,0x20,0x00,0x00,0xdd,0x44,0x00,0x0c,
-0xff,0xff,0x25,0x36,0x21,0xb0,0x40,0x00,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x00,0x60,0x81,0x40,0x64,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,0x08,0x00,0x10,0x3c,
-0xff,0xff,0x10,0x36,0x7a,0x42,0x00,0x0c,0x21,0x20,0x00,0x00,0x01,0x00,0x12,0x3c,
-0x24,0x30,0xb0,0x02,0x25,0x30,0xd2,0x00,0xff,0xff,0x25,0x36,0xba,0x44,0x00,0x0c,
-0x21,0x20,0x00,0x00,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x24,0x80,0xd0,0x02,
-0x7a,0x42,0x00,0x0c,0x01,0x00,0x04,0x24,0x25,0x30,0x12,0x02,0xff,0xff,0x25,0x36,
-0xba,0x44,0x00,0x0c,0x21,0x20,0x00,0x00,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,
-0x7a,0x42,0x00,0x0c,0x21,0x20,0x00,0x00,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,
-0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x0f,0x00,0x11,0x3c,0x18,0x00,0x04,0x24,
-0xdd,0x44,0x00,0x0c,0xff,0xff,0x25,0x36,0x21,0x80,0x40,0x00,0x00,0x60,0x01,0x40,
-0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,
-0x00,0x80,0x06,0x36,0xff,0xff,0x25,0x36,0xba,0x44,0x00,0x0c,0x18,0x00,0x04,0x24,
-0x84,0x0a,0x00,0x0c,0x03,0x00,0x04,0x24,0x21,0x30,0xa0,0x02,0xff,0xff,0x25,0x36,
-0xa6,0xff,0x80,0x12,0x21,0x20,0x00,0x00,0x25,0xb0,0x02,0x3c,0x03,0x0d,0x42,0x34,
-0x00,0x00,0x53,0xa0,0xba,0x44,0x00,0x0c,0x00,0x00,0x00,0x00,0xb3,0x0a,0x00,0x0c,
-0x64,0x00,0x04,0x24,0x7a,0x42,0x00,0x0c,0x01,0x00,0x04,0x24,0xff,0xff,0x25,0x36,
-0x21,0x30,0xc0,0x02,0xba,0x44,0x00,0x0c,0x21,0x20,0x00,0x00,0xb3,0x0a,0x00,0x0c,
-0x64,0x00,0x04,0x24,0x2c,0x00,0xbf,0x8f,0x28,0x00,0xb6,0x8f,0x24,0x00,0xb5,0x8f,
-0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x21,0x20,0x00,0x00,0x7a,0x42,0x00,0x08,0x30,0x00,0xbd,0x27,
-0xd0,0xff,0xbd,0x27,0x28,0x00,0xb4,0xaf,0x02,0x80,0x14,0x3c,0x2c,0x00,0xbf,0xaf,
-0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,
-0x68,0x15,0x86,0x26,0x0c,0x40,0xc2,0x8c,0x00,0x00,0x00,0x00,0x82,0x17,0x02,0x00,
-0x01,0x00,0x42,0x30,0x07,0x00,0x40,0x14,0x68,0x15,0x85,0x26,0x08,0x40,0xc2,0x8c,
-0x01,0x00,0x03,0x24,0x42,0x17,0x02,0x00,0x03,0x00,0x42,0x30,0xf0,0x00,0x43,0x10,
-0x25,0xb0,0x02,0x3c,0x0c,0x40,0xa2,0x8c,0x01,0x00,0x03,0x24,0x82,0x17,0x02,0x00,
-0x01,0x00,0x44,0x30,0x0a,0x00,0x83,0x10,0x00,0x00,0x00,0x00,0x2c,0x00,0xbf,0x8f,
-0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,
-0x18,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,
-0x08,0x40,0xa2,0x8c,0x00,0x00,0x00,0x00,0x42,0x17,0x02,0x00,0x03,0x00,0x42,0x30,
-0xf2,0xff,0x44,0x14,0x25,0xb0,0x02,0x3c,0x0e,0x0c,0x44,0x34,0x00,0x00,0x83,0x90,
-0x00,0x01,0x02,0x24,0xff,0x00,0x63,0x30,0x01,0x00,0x63,0x24,0x8b,0x01,0x62,0x10,
-0x00,0x00,0x00,0x00,0x00,0x00,0x83,0xa0,0x68,0x15,0x84,0x26,0x10,0x40,0x82,0x8c,
-0x01,0x00,0x03,0x24,0x82,0x17,0x02,0x00,0xa4,0x01,0x43,0x10,0x0f,0x00,0x10,0x3c,
-0xc7,0x42,0x92,0x90,0x68,0x15,0x90,0x26,0xc6,0x42,0x03,0x92,0x25,0xb0,0x11,0x3c,
-0x62,0x0c,0x22,0x36,0x00,0x00,0x52,0xa0,0x17,0x01,0x60,0x10,0x01,0x00,0x02,0x24,
-0x03,0x0d,0x23,0x36,0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,0x70,0x00,0x42,0x30,
-0x3e,0x01,0x40,0x14,0x63,0x0c,0x23,0x36,0xc4,0x42,0x02,0x96,0x00,0x00,0x00,0x00,
-0x23,0x20,0x52,0x00,0x2b,0x18,0x52,0x00,0x23,0x10,0x42,0x02,0x0a,0x10,0x83,0x00,
-0x03,0x00,0x42,0x2c,0x0b,0x01,0x40,0x10,0x00,0x00,0x00,0x00,0xc4,0x42,0x03,0x96,
-0x63,0x0c,0x22,0x36,0x00,0x00,0x43,0xa0,0x68,0x15,0x83,0x26,0xc3,0x42,0x62,0x90,
-0x08,0x40,0x66,0x8c,0xc2,0x42,0x72,0xa0,0x23,0x20,0x52,0x00,0x2b,0x38,0x42,0x02,
-0x23,0x50,0x42,0x02,0x02,0x2c,0x06,0x00,0x0b,0x50,0x87,0x00,0x3f,0x00,0xa5,0x30,
-0x3f,0x00,0xc4,0x30,0x24,0x00,0x02,0x24,0x20,0x00,0x03,0x24,0x23,0x10,0x44,0x00,
-0x2d,0x01,0x40,0x15,0x23,0x18,0x65,0x00,0x21,0x30,0x80,0x00,0x21,0x48,0xa0,0x00,
-0x02,0x80,0x0b,0x3c,0x68,0x15,0x83,0x26,0x80,0x10,0x06,0x00,0x21,0x10,0x43,0x00,
-0x0c,0x40,0x63,0x8c,0x18,0x40,0x44,0x8c,0xff,0x03,0x67,0x30,0x1b,0x01,0xe0,0x10,
-0x82,0x2d,0x04,0x00,0x00,0x02,0x62,0x30,0x04,0x00,0x40,0x10,0x18,0x00,0xe5,0x00,
-0x00,0xfc,0x02,0x24,0x25,0x38,0xe2,0x00,0x18,0x00,0xe5,0x00,0x82,0x22,0x03,0x00,
-0xff,0x03,0x84,0x30,0x00,0x02,0x83,0x30,0x12,0x10,0x00,0x00,0x02,0x12,0x02,0x00,
-0x03,0x00,0x60,0x10,0xff,0x03,0x48,0x30,0x00,0xfc,0x02,0x24,0x25,0x20,0x82,0x00,
-0x18,0x00,0x85,0x00,0x80,0x2d,0x05,0x00,0x25,0xb0,0x06,0x3c,0x80,0x0c,0xc7,0x34,
-0x94,0x0c,0xc6,0x34,0x12,0x20,0x00,0x00,0x02,0x22,0x04,0x00,0x3f,0x00,0x82,0x30,
-0x00,0x14,0x02,0x00,0x25,0x28,0xa2,0x00,0x25,0x28,0xa8,0x00,0x10,0x00,0xa5,0xaf,
-0x00,0x00,0xe5,0xac,0x00,0x00,0xc3,0x8c,0xff,0x0f,0x02,0x3c,0xc0,0x03,0x84,0x30,
-0xff,0xff,0x42,0x34,0x80,0x25,0x04,0x00,0x24,0x18,0x62,0x00,0x25,0x18,0x64,0x00,
-0x10,0x00,0xa3,0xaf,0x00,0x00,0xc3,0xac,0x68,0x15,0x83,0x26,0x08,0x40,0x62,0x8c,
-0x00,0x00,0x00,0x00,0x08,0x01,0x40,0x04,0xc0,0x28,0x09,0x00,0x21,0x28,0xa3,0x00,
-0xac,0x40,0xa3,0x90,0x25,0xb0,0x04,0x3c,0x22,0x0a,0x82,0x34,0x00,0x00,0x43,0xa0,
-0xad,0x40,0xa6,0x90,0x23,0x0a,0x82,0x34,0x24,0x0a,0x87,0x34,0x00,0x00,0x46,0xa0,
-0xae,0x40,0xa3,0x90,0x25,0x0a,0x86,0x34,0x26,0x0a,0x88,0x34,0x00,0x00,0xe3,0xa0,
-0xaf,0x40,0xa2,0x90,0x27,0x0a,0x87,0x34,0x28,0x0a,0x89,0x34,0x00,0x00,0xc2,0xa0,
-0xb0,0x40,0xa3,0x90,0x29,0x0a,0x84,0x34,0x00,0x00,0x03,0xa1,0xb1,0x40,0xa2,0x90,
-0x00,0x00,0x00,0x00,0x00,0x00,0xe2,0xa0,0xb2,0x40,0xa3,0x90,0x00,0x00,0x00,0x00,
-0x00,0x00,0x23,0xa1,0xb3,0x40,0xa2,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x82,0xa0,
-0x8e,0x7d,0x63,0x91,0x22,0x00,0x02,0x24,0x03,0x00,0x62,0x10,0x92,0x00,0x02,0x24,
-0x62,0xff,0x62,0x14,0x00,0x00,0x00,0x00,0x68,0x15,0x82,0x26,0x08,0x40,0x43,0x8c,
-0x01,0x00,0x44,0x39,0x24,0x00,0x02,0x24,0x02,0x1a,0x03,0x00,0x3f,0x00,0x63,0x30,
-0x01,0x00,0x84,0x30,0x04,0x01,0x80,0x10,0x23,0x28,0x43,0x00,0x42,0x18,0x0a,0x00,
-0x40,0x10,0x03,0x00,0x21,0x50,0x43,0x00,0x68,0x15,0x83,0x26,0xc3,0x42,0x62,0x90,
-0x00,0x00,0x00,0x00,0x2b,0x10,0x42,0x02,0x08,0x01,0x40,0x10,0x21,0x20,0x00,0x00,
-0x2b,0x10,0x45,0x01,0x07,0x00,0x40,0x10,0x24,0x00,0x04,0x24,0x08,0x40,0x62,0x8c,
-0x00,0x00,0x00,0x00,0x02,0x12,0x02,0x00,0x3f,0x00,0x42,0x30,0x21,0x20,0x4a,0x00,
-0x68,0x15,0x83,0x26,0x80,0x10,0x04,0x00,0x10,0x40,0x66,0x8c,0x21,0x10,0x43,0x00,
-0x18,0x40,0x44,0x8c,0x82,0x3a,0x06,0x00,0xff,0x03,0xe7,0x30,0xf0,0x00,0xe0,0x10,
-0x82,0x2d,0x04,0x00,0x00,0x02,0xe2,0x30,0x04,0x00,0x40,0x10,0x18,0x00,0xe5,0x00,
-0x00,0xfc,0x02,0x24,0x25,0x38,0xe2,0x00,0x18,0x00,0xe5,0x00,0x02,0x25,0x06,0x00,
-0xff,0x03,0x84,0x30,0x00,0x02,0x83,0x30,0x12,0x10,0x00,0x00,0x02,0x12,0x02,0x00,
-0x03,0x00,0x60,0x10,0xff,0x03,0x48,0x30,0x00,0xfc,0x02,0x24,0x25,0x20,0x82,0x00,
-0x18,0x00,0x85,0x00,0x80,0x2d,0x05,0x00,0x25,0xb0,0x06,0x3c,0x88,0x0c,0xc7,0x34,
-0x9c,0x0c,0xc6,0x34,0x12,0x20,0x00,0x00,0x02,0x22,0x04,0x00,0x3f,0x00,0x82,0x30,
-0x00,0x14,0x02,0x00,0x25,0x28,0xa2,0x00,0x25,0x28,0xa8,0x00,0x10,0x00,0xa5,0xaf,
-0x00,0x00,0xe5,0xac,0x00,0x00,0xc3,0x8c,0xff,0x0f,0x02,0x3c,0xc0,0x03,0x84,0x30,
-0xff,0xff,0x42,0x34,0x80,0x25,0x04,0x00,0x24,0x18,0x62,0x00,0x25,0x18,0x64,0x00,
-0x10,0x00,0xa3,0xaf,0x00,0x00,0xc3,0xac,0x95,0x54,0x00,0x08,0x00,0x00,0x00,0x00,
-0x80,0x0c,0x42,0x34,0x00,0x00,0x43,0x8c,0xc0,0xff,0x02,0x3c,0x21,0x88,0x00,0x00,
-0x24,0x28,0x62,0x00,0xc0,0xff,0x04,0x3c,0x8a,0x55,0x00,0x08,0x18,0x40,0xc3,0x24,
-0x01,0x00,0x31,0x26,0x25,0x00,0x22,0x2e,0x0d,0x00,0x40,0x10,0x02,0x80,0x0b,0x3c,
-0x00,0x00,0x62,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x44,0x00,0xf8,0xff,0x45,0x14,
-0x04,0x00,0x63,0x24,0x08,0x40,0xc2,0x8c,0xc0,0xff,0x03,0x24,0x3f,0x00,0x24,0x32,
-0x24,0x10,0x43,0x00,0x25,0x10,0x44,0x00,0x08,0x40,0xc2,0xac,0x02,0x80,0x0b,0x3c,
-0x8e,0x7d,0x63,0x91,0x22,0x00,0x02,0x24,0x3e,0x00,0x62,0x10,0x92,0x00,0x02,0x24,
-0x3d,0x00,0x62,0x10,0x25,0xb0,0x02,0x3c,0x25,0xb0,0x02,0x3c,0x24,0x0a,0x42,0x34,
-0x00,0x00,0x44,0x8c,0x3f,0x3f,0x03,0x3c,0x3f,0x3f,0x63,0x34,0x24,0x20,0x83,0x00,
-0x02,0x80,0x02,0x3c,0x02,0x80,0x03,0x3c,0x16,0x56,0x53,0x24,0x1e,0x57,0x72,0x24,
-0x21,0x88,0x00,0x00,0xb1,0x55,0x00,0x08,0x10,0x00,0xa4,0xaf,0xd4,0x45,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x47,0x00,0x40,0x10,0x68,0x15,0x85,0x26,0x01,0x00,0x31,0x26,
-0x21,0x00,0x22,0x2e,0x17,0x00,0x40,0x10,0x68,0x15,0x84,0x26,0xc0,0x80,0x11,0x00,
-0x10,0x00,0xa4,0x27,0x21,0x28,0x13,0x02,0xd4,0x45,0x00,0x0c,0x04,0x00,0x06,0x24,
-0x21,0x28,0x12,0x02,0x10,0x00,0xa4,0x27,0xf0,0xff,0x40,0x14,0x04,0x00,0x06,0x24,
-0x68,0x15,0x85,0x26,0x08,0x40,0xa3,0x8c,0xc0,0xff,0x02,0x3c,0xff,0xff,0x42,0x34,
-0x3f,0x00,0x24,0x32,0x24,0x18,0x62,0x00,0x00,0x24,0x04,0x00,0xff,0x7f,0x02,0x3c,
-0x25,0x18,0x64,0x00,0xff,0xff,0x42,0x34,0x24,0x18,0x62,0x00,0x08,0x40,0xa3,0xac,
-0x68,0x15,0x84,0x26,0x0c,0x40,0x83,0x8c,0x00,0x40,0x02,0x3c,0x25,0x18,0x62,0x00,
-0x25,0xb0,0x02,0x3c,0x0e,0x0c,0x42,0x34,0x0c,0x40,0x83,0xac,0x00,0x00,0x40,0xa0,
-0x8f,0x54,0x00,0x08,0x68,0x15,0x85,0x26,0xc6,0x42,0x02,0xa2,0xba,0x54,0x00,0x08,
-0xc4,0x42,0x12,0xa6,0xda,0x53,0x00,0x0c,0x00,0x00,0x00,0x00,0xc9,0x54,0x00,0x08,
-0xc4,0x42,0x12,0xa6,0x25,0xb0,0x02,0x3c,0x88,0x0c,0x42,0x34,0x00,0x00,0x44,0x8c,
-0x02,0x80,0x03,0x3c,0x68,0x15,0x66,0x24,0xc0,0xff,0x02,0x3c,0x24,0x28,0x82,0x00,
-0x21,0x88,0x00,0x00,0xc0,0xff,0x04,0x3c,0xe6,0x55,0x00,0x08,0x18,0x40,0xc3,0x24,
-0x01,0x00,0x31,0x26,0x25,0x00,0x22,0x2e,0xb8,0xff,0x40,0x10,0x25,0xb0,0x02,0x3c,
-0x00,0x00,0x62,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x44,0x00,0xf8,0xff,0x45,0x14,
-0x04,0x00,0x63,0x24,0x08,0x40,0xc2,0x8c,0x3f,0x00,0x23,0x32,0xff,0xc0,0x04,0x24,
-0x24,0x10,0x44,0x00,0x00,0x1a,0x03,0x00,0x25,0x10,0x43,0x00,0x9c,0x55,0x00,0x08,
-0x08,0x40,0xc2,0xac,0x08,0x40,0xa3,0x8c,0xc0,0xff,0x02,0x3c,0xff,0xff,0x42,0x34,
-0x3f,0x00,0x24,0x32,0x24,0x18,0x62,0x00,0x00,0x24,0x04,0x00,0x25,0x18,0x64,0x00,
-0x00,0x80,0x02,0x3c,0xc5,0x55,0x00,0x08,0x25,0x18,0x62,0x00,0xcc,0xff,0x02,0x24,
-0x00,0x00,0x62,0xa0,0xcd,0x54,0x00,0x08,0x68,0x15,0x83,0x26,0x25,0xb0,0x02,0x3c,
-0x94,0x0c,0x43,0x34,0x80,0x0c,0x42,0x34,0x00,0x00,0x44,0xac,0x00,0x00,0x60,0xac,
-0x0d,0x55,0x00,0x08,0x68,0x15,0x83,0x26,0x2f,0x00,0xe0,0x10,0x21,0x30,0x00,0x00,
-0x2b,0x10,0x42,0x01,0x21,0x20,0x8a,0x00,0x00,0x00,0x42,0x38,0x24,0x00,0x06,0x24,
-0x2b,0x18,0x43,0x01,0x0b,0x30,0x82,0x00,0xcd,0xfe,0x60,0x10,0x20,0x00,0x09,0x24,
-0x68,0x15,0x83,0x26,0x0a,0x40,0x62,0x94,0x02,0x80,0x0b,0x3c,0x3f,0x00,0x42,0x30,
-0xe0,0x54,0x00,0x08,0x21,0x48,0x4a,0x00,0x21,0x28,0xa3,0x00,0xb4,0x41,0xa3,0x90,
-0x25,0xb0,0x04,0x3c,0x22,0x0a,0x82,0x34,0x00,0x00,0x43,0xa0,0xb5,0x41,0xa6,0x90,
-0x23,0x0a,0x82,0x34,0x24,0x0a,0x87,0x34,0x00,0x00,0x46,0xa0,0xb6,0x41,0xa3,0x90,
-0x25,0x0a,0x86,0x34,0x26,0x0a,0x88,0x34,0x00,0x00,0xe3,0xa0,0xb7,0x41,0xa2,0x90,
-0x27,0x0a,0x87,0x34,0x28,0x0a,0x89,0x34,0x00,0x00,0xc2,0xa0,0xb8,0x41,0xa3,0x90,
-0x29,0x0a,0x84,0x34,0x00,0x00,0x03,0xa1,0xb9,0x41,0xa2,0x90,0x00,0x00,0x00,0x00,
-0x00,0x00,0xe2,0xa0,0xba,0x41,0xa3,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0xa1,
-0xbb,0x41,0xa2,0x90,0x2d,0x55,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xa0,
-0xad,0x54,0x00,0x08,0x68,0x15,0x84,0x26,0x23,0x10,0x8a,0x00,0x2b,0x18,0x44,0x01,
-0x2b,0x20,0x45,0x01,0x0b,0x30,0x43,0x00,0xa1,0xfe,0x80,0x14,0x23,0x48,0xaa,0x00,
-0xde,0x54,0x00,0x08,0x21,0x48,0x00,0x00,0xff,0xff,0x43,0x25,0x42,0x18,0x03,0x00,
-0x40,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x40,0x55,0x00,0x08,0x01,0x00,0x4a,0x24,
-0x25,0xb0,0x02,0x3c,0x9c,0x0c,0x43,0x34,0x88,0x0c,0x42,0x34,0x00,0x00,0x44,0xac,
-0x00,0x00,0x60,0xac,0x95,0x54,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x40,0x62,0x8c,
-0x00,0x00,0x00,0x00,0x02,0x12,0x02,0x00,0x3f,0x00,0x42,0x30,0x23,0x18,0x4a,0x00,
-0x2b,0x10,0x42,0x01,0x4e,0x55,0x00,0x08,0x0b,0x20,0x62,0x00,0xff,0xff,0x05,0x36,
-0x60,0x00,0x06,0x24,0xba,0x44,0x00,0x0c,0x24,0x00,0x04,0x24,0x84,0x0a,0x00,0x0c,
-0xe8,0x03,0x04,0x24,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,
-0x00,0x60,0x81,0x40,0x24,0x00,0x04,0x24,0xdd,0x44,0x00,0x0c,0xff,0xff,0x05,0x36,
-0x1f,0x00,0x52,0x30,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0xb4,0x54,0x00,0x08,0x68,0x15,0x90,0x26,
-0x00,0xff,0x84,0x30,0x02,0x22,0x04,0x00,0x08,0x00,0x80,0x10,0x02,0x80,0x02,0x3c,
-0xff,0x00,0x02,0x24,0x04,0x00,0x82,0x10,0xcc,0xff,0x03,0x24,0x02,0x80,0x02,0x3c,
-0x08,0x00,0xe0,0x03,0x4e,0x58,0x43,0xa0,0x02,0x80,0x02,0x3c,0x08,0x00,0xe0,0x03,
-0x4e,0x58,0x44,0xa0,0x02,0x24,0x04,0x00,0xff,0x00,0x84,0x30,0xc0,0x10,0x04,0x00,
-0x21,0x10,0x44,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x44,0x00,0x02,0x80,0x03,0x3c,
-0x80,0x10,0x02,0x00,0x68,0x15,0x63,0x24,0x20,0x00,0x84,0x2c,0x09,0x00,0x80,0x10,
-0x21,0x10,0x43,0x00,0x68,0x51,0x43,0x8c,0x25,0xb0,0x02,0x3c,0xc4,0x02,0x42,0x34,
-0x02,0x19,0x03,0x00,0x7f,0x00,0x63,0x30,0x00,0x00,0x43,0xac,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c,0x44,0x79,0x43,0x8c,0x25,0xb0,0x02,0x3c,
-0xc4,0x02,0x42,0x34,0x02,0x19,0x03,0x00,0x7f,0x00,0x63,0x30,0x00,0x00,0x43,0xac,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xff,0x00,0x85,0x30,0xd2,0xff,0xa3,0x24,
-0xfe,0xff,0xa2,0x24,0xda,0xff,0xa4,0x24,0x04,0x00,0x63,0x2c,0x08,0x00,0x84,0x2c,
-0x06,0x00,0x60,0x14,0xff,0x00,0x42,0x30,0xf0,0xff,0xa2,0x24,0xfc,0xff,0xa3,0x24,
-0x16,0x00,0x46,0x2c,0x03,0x00,0x80,0x10,0xff,0x00,0x62,0x30,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0xfa,0xff,0xa3,0x24,0xfc,0xff,0xc0,0x10,0x21,0x10,0xa0,0x00,
-0x08,0x00,0xe0,0x03,0xff,0x00,0x62,0x30,0x25,0xb0,0x04,0x3c,0x03,0x0d,0x85,0x34,
-0x00,0x00,0xa3,0x90,0x2d,0x0a,0x84,0x34,0xff,0x00,0x63,0x30,0x08,0x00,0x63,0x34,
-0x00,0x00,0xa3,0xa0,0x00,0x00,0xa2,0x90,0x00,0x00,0x00,0x00,0xf7,0x00,0x42,0x30,
-0x00,0x00,0xa2,0xa0,0x00,0x00,0x83,0x90,0x00,0x00,0x00,0x00,0x3f,0x00,0x63,0x30,
-0x00,0x00,0x83,0xa0,0x00,0x00,0x82,0x90,0x80,0xff,0x03,0x24,0x25,0x10,0x43,0x00,
-0x00,0x00,0x82,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x25,0xb0,0x02,0x3c,
-0xff,0x00,0x03,0x3c,0x82,0x01,0x49,0x34,0x81,0x01,0x48,0x34,0x24,0x10,0x83,0x00,
-0x02,0x3c,0x02,0x00,0x00,0xff,0x63,0x34,0x02,0x80,0x02,0x3c,0x68,0x15,0x45,0x24,
-0x02,0x32,0x04,0x00,0x01,0x00,0x02,0x24,0x24,0x20,0x83,0x00,0xc2,0x4c,0xa2,0xa0,
-0xb0,0x4c,0xa0,0xac,0xb4,0x4c,0xa0,0xac,0xb8,0x4c,0xa0,0xac,0x06,0x00,0x80,0x14,
-0xbc,0x4c,0xa0,0xac,0x00,0x00,0x02,0x91,0x00,0x00,0x23,0x91,0xc0,0x4c,0xa2,0xa0,
-0x08,0x00,0xe0,0x03,0xc1,0x4c,0xa3,0xa0,0xc1,0x4c,0xa7,0xa0,0x08,0x00,0xe0,0x03,
-0xc0,0x4c,0xa6,0xa0,0x02,0x80,0x03,0x3c,0x68,0x15,0x63,0x24,0xc1,0x4c,0x66,0x90,
-0xc0,0x4c,0x65,0x90,0x25,0xb0,0x02,0x3c,0x82,0x01,0x44,0x34,0x81,0x01,0x42,0x34,
-0x00,0x00,0x45,0xa0,0x00,0x00,0x86,0xa0,0x08,0x00,0xe0,0x03,0xc2,0x4c,0x60,0xa0,
-0x02,0x80,0x08,0x3c,0x68,0x15,0x04,0x25,0xc2,0x4c,0x82,0x90,0x00,0x00,0x00,0x00,
-0x15,0x00,0x40,0x10,0x21,0x18,0x00,0x00,0xb4,0x4c,0x82,0x8c,0xb0,0x4c,0x85,0x8c,
-0x25,0xb0,0x03,0x3c,0x40,0x11,0x02,0x00,0x2b,0x10,0xa2,0x00,0x82,0x01,0x67,0x34,
-0x0f,0x00,0x40,0x10,0x81,0x01,0x66,0x34,0xc1,0x4c,0x83,0x90,0xc0,0x4c,0x82,0x90,
-0xf0,0x00,0x63,0x30,0x1f,0x00,0x42,0x30,0x00,0x00,0xc2,0xa0,0x00,0x00,0xe3,0xa0,
-0x68,0x15,0x02,0x25,0x01,0x00,0x03,0x24,0xbc,0x4c,0x40,0xac,0xb0,0x4c,0x40,0xac,
-0xb4,0x4c,0x40,0xac,0xb8,0x4c,0x40,0xac,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,
-0xb8,0x4c,0x82,0x8c,0x25,0xb0,0x03,0x3c,0x82,0x01,0x69,0x34,0x40,0x11,0x02,0x00,
-0x2b,0x10,0xa2,0x00,0x0e,0x00,0x40,0x14,0x81,0x01,0x66,0x34,0xbc,0x4c,0x82,0x8c,
-0x00,0x00,0x00,0x00,0x40,0x11,0x02,0x00,0x2b,0x10,0xa2,0x00,0x08,0x00,0x40,0x14,
-0x00,0x00,0x00,0x00,0xc1,0x4c,0x83,0x90,0xc0,0x4c,0x82,0x90,0x00,0x00,0x00,0x00,
-0x00,0x00,0xc2,0xa0,0x00,0x00,0x23,0xa1,0xf7,0x56,0x00,0x08,0x68,0x15,0x02,0x25,
-0xc1,0x4c,0x83,0x90,0xc0,0x4c,0x82,0x90,0xf0,0x00,0x63,0x30,0x7f,0x00,0x42,0x30,
-0x00,0x00,0xc2,0xa0,0x00,0x00,0x23,0xa1,0xf7,0x56,0x00,0x08,0x68,0x15,0x02,0x25,
-0x02,0x00,0x03,0x24,0x02,0x80,0x02,0x3c,0x08,0x00,0xe0,0x03,0x3d,0x58,0x43,0xa0,
-0xcc,0xff,0x03,0x24,0x02,0x80,0x02,0x3c,0x08,0x00,0xe0,0x03,0x3d,0x58,0x43,0xa0,
-0x25,0xb0,0x03,0x3c,0x33,0x02,0x65,0x34,0x00,0x11,0x04,0x00,0x00,0x00,0xa2,0xa0,
-0x30,0x02,0x63,0x34,0x00,0x00,0x65,0x8c,0x0f,0x00,0x02,0x3c,0xff,0xff,0x42,0x34,
-0x24,0x28,0xa2,0x00,0x01,0x00,0x03,0x24,0x04,0x18,0x83,0x00,0x02,0x00,0xa0,0x10,
-0x21,0x10,0x00,0x00,0xff,0xff,0x62,0x30,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf,0x25,0xb0,0x11,0x3c,0x18,0x00,0xb2,0xaf,
-0x4c,0x00,0x22,0x36,0x1c,0x00,0xbf,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x00,0x44,0x90,
-0x02,0x80,0x03,0x3c,0x02,0x00,0x02,0x24,0xff,0x00,0x84,0x30,0x07,0x00,0x82,0x10,
-0x68,0x15,0x72,0x24,0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,
-0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0xe6,0x63,0x43,0x96,
-0x01,0x00,0x02,0x24,0xf7,0xff,0x62,0x14,0x21,0x20,0x00,0x00,0x22,0x57,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x24,0x22,0x57,0x00,0x0c,0x21,0x80,0x40,0x00,
-0x25,0x80,0x02,0x02,0x33,0x02,0x23,0x36,0x08,0x00,0x02,0x24,0xff,0xff,0x10,0x32,
-0x40,0x00,0x25,0x36,0x00,0x00,0x62,0xa0,0xea,0xff,0x00,0x16,0x00,0x00,0x00,0x00,
-0x00,0x00,0xa2,0x94,0xe4,0x63,0x43,0x96,0xff,0xdf,0x42,0x30,0x00,0x20,0x44,0x34,
-0x01,0x00,0x63,0x24,0xe4,0x63,0x43,0xa6,0x00,0x00,0xa2,0xa4,0x00,0x00,0xa4,0xa4,
-0x3f,0x57,0x00,0x08,0x00,0x00,0x00,0x00,0x01,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c,
-0x18,0x03,0x42,0x34,0x80,0x5d,0x63,0x24,0x00,0x00,0x43,0xac,0x63,0x00,0x02,0x24,
-0xff,0xff,0x42,0x24,0xff,0xff,0x41,0x04,0xff,0xff,0x42,0x24,0x02,0x80,0x02,0x3c,
-0x88,0x7d,0x45,0x94,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0x8b,0x7d,0x66,0x90,
-0x98,0x7d,0x47,0x90,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0xa3,0x7d,0x69,0x90,
-0xa5,0x7d,0x4a,0x90,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0xa8,0x7d,0x6b,0x90,
-0xaa,0x7d,0x4c,0x90,0x07,0x00,0x03,0x24,0x02,0x80,0x02,0x3c,0x25,0xb0,0x04,0x3c,
-0x95,0x7d,0x43,0xa0,0xb0,0x03,0x84,0x34,0x02,0x80,0x02,0x3c,0x02,0x80,0x18,0x3c,
-0x8a,0x7d,0x08,0x93,0x00,0x00,0x85,0xac,0x96,0x7d,0x40,0xa0,0x02,0x80,0x02,0x3c,
-0x00,0x00,0x86,0xac,0x02,0x80,0x0f,0x3c,0x97,0x7d,0x40,0xa0,0x02,0x80,0x02,0x3c,
-0x00,0x00,0x87,0xac,0x68,0x15,0xee,0x25,0xb8,0x7d,0x40,0xa0,0xfd,0xff,0x02,0x24,
-0xd5,0x4a,0xc2,0xa1,0x01,0x00,0x03,0x24,0x00,0x78,0x02,0x24,0xd4,0x4a,0xc3,0xa1,
-0xd8,0x4a,0xc2,0xa5,0xff,0x07,0x03,0x24,0x0f,0x00,0x0d,0x31,0x02,0x00,0x02,0x24,
-0xda,0x4a,0xc3,0xa5,0x00,0x00,0x88,0xac,0x00,0x00,0x89,0xac,0x00,0x00,0x8a,0xac,
-0x00,0x00,0x8b,0xac,0x00,0x00,0x8c,0xac,0x17,0x00,0xa2,0x11,0x02,0x80,0x02,0x3c,
-0x8a,0x7d,0x02,0x93,0x01,0x00,0x03,0x24,0x0f,0x00,0x42,0x30,0x05,0x00,0x43,0x10,
-0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c,0xca,0x7d,0x40,0xa4,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x00,0x80,0x02,0x3c,0x68,0x15,0xe4,0x25,0x02,0xbc,0x42,0x34,
-0x68,0x4b,0x82,0xac,0x15,0x15,0x03,0x3c,0x02,0x02,0x02,0x3c,0x07,0x07,0x63,0x34,
-0x64,0x4b,0x82,0xac,0x02,0x80,0x02,0x3c,0x60,0x4b,0x83,0xac,0xca,0x7d,0x40,0xa4,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x8f,0x7d,0x44,0x90,0x06,0x00,0x03,0x24,
-0x15,0x00,0x83,0x10,0x0b,0x00,0x02,0x24,0x0a,0x00,0x82,0x10,0x00,0xe0,0x02,0x3c,
-0x68,0x15,0xe4,0x25,0x00,0xb2,0x42,0x34,0x00,0x1c,0x03,0x3c,0x68,0x4b,0x82,0xac,
-0x00,0x1c,0x63,0x34,0x00,0x04,0x02,0x24,0x60,0x4b,0x83,0xac,0x9a,0x57,0x00,0x08,
-0x64,0x4b,0x82,0xac,0x00,0x80,0x02,0x3c,0x00,0xbc,0x42,0x34,0x15,0x15,0x03,0x3c,
-0x68,0x4b,0xc2,0xad,0x07,0x07,0x63,0x34,0x03,0x03,0x02,0x3c,0x60,0x4b,0xc3,0xad,
-0x9a,0x57,0x00,0x08,0x64,0x4b,0xc2,0xad,0x00,0xc0,0x02,0x3c,0x00,0xb2,0x42,0x34,
-0x1c,0x1c,0x03,0x3c,0x68,0x4b,0xc2,0xad,0x07,0x07,0x63,0x34,0x00,0x04,0x02,0x24,
-0x60,0x4b,0xc3,0xad,0x9a,0x57,0x00,0x08,0x64,0x4b,0xc2,0xad,0x25,0xb0,0x02,0x3c,
-0x4d,0x00,0x44,0x34,0xff,0x00,0x03,0x3c,0xec,0x02,0x42,0x34,0x00,0x00,0x43,0xac,
-0x00,0x00,0x80,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x01,0x80,0x03,0x3c,
-0x25,0xb0,0x02,0x3c,0x64,0x5f,0x63,0x24,0x18,0x03,0x42,0x34,0x00,0x00,0x43,0xac,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x7f,0x00,0x02,0x3c,0xfd,0xbf,0x45,0x34,
-0x80,0x04,0x03,0x3c,0x25,0x28,0xa3,0x00,0x00,0x08,0x04,0x3c,0x02,0x80,0x02,0x3c,
-0x68,0x15,0x42,0x24,0x25,0x28,0xa4,0x00,0x41,0xb0,0x03,0x3c,0x00,0x00,0x65,0xac,
-0x04,0x4b,0x45,0xac,0xfc,0x4a,0x45,0xac,0x08,0x00,0x63,0x34,0x86,0x00,0x05,0x24,
-0x00,0x00,0x65,0xa4,0x08,0x4b,0x45,0xa4,0x00,0x4b,0x40,0xac,0x0a,0x4b,0x40,0xa4,
-0x0c,0x4b,0x45,0xa4,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,
-0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xf8,0x57,0x00,0x08,0x00,0x00,0x00,0x00,
-0x42,0xb0,0x02,0x3c,0xa0,0xff,0x03,0x24,0x01,0x00,0x42,0x34,0xe8,0xff,0xbd,0x27,
-0x21,0x20,0x00,0x00,0x01,0x00,0x05,0x24,0x00,0x01,0x06,0x24,0x00,0x00,0x43,0xa0,
-0x10,0x00,0xbf,0xaf,0xc4,0x0c,0x00,0x0c,0x00,0x00,0x00,0x00,0x10,0x00,0xbf,0x8f,
-0x03,0x00,0x04,0x24,0x01,0x00,0x05,0x24,0x40,0x1f,0x06,0x24,0xc4,0x0c,0x00,0x08,
-0x18,0x00,0xbd,0x27,0xe8,0xff,0xbd,0x27,0x10,0x00,0xb0,0xaf,0x14,0x00,0xbf,0xaf,
-0x21,0x5b,0x00,0x0c,0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,
-0x48,0x01,0x03,0x24,0xe0,0x63,0x43,0xac,0xdc,0x63,0x43,0xac,0x21,0x80,0x40,0x00,
-0x1f,0x00,0x03,0x24,0xff,0xff,0x63,0x24,0xc4,0x4c,0x40,0xa4,0xc6,0x4c,0x40,0xa4,
-0xc8,0x4c,0x40,0xa4,0xca,0x4c,0x40,0xa4,0xcc,0x4c,0x40,0xa4,0xce,0x4c,0x40,0xa4,
-0xd0,0x4c,0x40,0xa4,0xd2,0x4c,0x40,0xa4,0xd4,0x4c,0x40,0xa4,0xf5,0xff,0x61,0x04,
-0x24,0x00,0x42,0x24,0x25,0xb0,0x02,0x3c,0x10,0x00,0x03,0x24,0xb0,0x03,0x42,0x34,
-0x02,0x80,0x04,0x3c,0x8c,0x58,0x84,0x24,0x00,0x00,0x43,0xac,0x21,0x28,0x00,0x00,
-0x97,0x45,0x00,0x0c,0x04,0x00,0x06,0x24,0xef,0x5b,0x00,0x0c,0x00,0x00,0x00,0x00,
-0x71,0x5c,0x00,0x0c,0x8c,0x65,0x00,0xae,0xa7,0x5d,0x00,0x0c,0x00,0x00,0x00,0x00,
-0x4b,0x5e,0x00,0x0c,0x00,0x00,0x00,0x00,0x02,0x80,0x03,0x3c,0x8e,0x7d,0x64,0x90,
-0x92,0x00,0x02,0x24,0x03,0x00,0x82,0x10,0x00,0x00,0x00,0x00,0xf7,0x5d,0x00,0x0c,
-0x00,0x00,0x00,0x00,0xdd,0x5d,0x00,0x0c,0x00,0x00,0x00,0x00,0x8b,0x5c,0x00,0x0c,
-0x00,0x00,0x00,0x00,0xe4,0x63,0x00,0xa6,0x67,0x5e,0x00,0x0c,0xe6,0x63,0x00,0xa6,
-0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f,0x02,0x80,0x04,0x3c,0x02,0x80,0x05,0x3c,
-0xf8,0x7a,0x82,0x24,0x00,0x7b,0xa3,0x24,0x18,0x00,0xbd,0x27,0x04,0x00,0x42,0xac,
-0xf8,0x7a,0x82,0xac,0x00,0x7b,0xa3,0xac,0x08,0x00,0xe0,0x03,0x04,0x00,0x63,0xac,
-0xe8,0xff,0xbd,0x27,0x10,0x00,0xb0,0xaf,0x01,0x80,0x02,0x3c,0x25,0xb0,0x10,0x3c,
-0x18,0x03,0x03,0x36,0x38,0x61,0x42,0x24,0x00,0x00,0x62,0xac,0x14,0x00,0xbf,0xaf,
-0x60,0x57,0x00,0x0c,0x00,0x00,0x00,0x00,0xd5,0x58,0x00,0x0c,0x00,0x00,0x00,0x00,
-0x01,0x00,0x03,0x24,0x02,0x80,0x02,0x3c,0xfd,0x5a,0x00,0x0c,0xdb,0x60,0x43,0xa0,
-0xd1,0x57,0x00,0x0c,0x00,0x00,0x00,0x00,0x32,0x41,0x00,0x0c,0x00,0x00,0x00,0x00,
-0x0b,0x58,0x00,0x0c,0x00,0x00,0x00,0x00,0x44,0x00,0x03,0x36,0x00,0x00,0x62,0x94,
-0x00,0x00,0x00,0x00,0x40,0x00,0x42,0x34,0x00,0x00,0x62,0xa4,0xd9,0x57,0x00,0x0c,
-0x00,0x00,0x00,0x00,0xfa,0x57,0x00,0x0c,0x00,0x00,0x00,0x00,0xc9,0x5a,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x8e,0x5a,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x3c,
-0xb4,0x24,0x84,0x24,0xe6,0x5a,0x00,0x0c,0x01,0x00,0x05,0x24,0x01,0x80,0x04,0x3c,
-0x08,0x1e,0x84,0x24,0xe6,0x5a,0x00,0x0c,0x02,0x00,0x05,0x24,0x81,0x4e,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x3c,0x54,0x34,0x84,0x24,0xe6,0x5a,0x00,0x0c,
-0x03,0x00,0x05,0x24,0x02,0x80,0x02,0x3c,0x98,0x7d,0x43,0x90,0x43,0x00,0x04,0x36,
-0x29,0x00,0x60,0x10,0xd8,0x00,0x10,0x36,0x07,0x00,0x02,0x24,0x2b,0x00,0x62,0x10,
-0x25,0xb0,0x04,0x3c,0x10,0x02,0x86,0x34,0x43,0x00,0x85,0x34,0x03,0x00,0x02,0x24,
-0x10,0x00,0x03,0x24,0x00,0x00,0xa2,0xa0,0xd8,0x00,0x84,0x34,0x00,0x00,0xc3,0xa0,
-0x00,0x00,0x82,0x90,0x80,0xff,0x03,0x24,0x42,0xb0,0x05,0x3c,0x25,0x10,0x43,0x00,
-0x00,0x00,0x82,0xa0,0x25,0xb0,0x04,0x3c,0x44,0x00,0x84,0x34,0x00,0x00,0x82,0x94,
-0x00,0x00,0x00,0x00,0xc0,0x00,0x42,0x34,0x00,0x00,0x82,0xa4,0x00,0x00,0xa3,0x90,
-0x00,0x00,0x00,0x00,0x01,0x00,0x63,0x34,0x00,0x00,0xa3,0xa0,0xe0,0x57,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x02,0x80,0x04,0x3c,0x08,0x00,0x84,0x24,0x21,0x28,0x00,0x00,
-0x21,0x30,0x00,0x00,0x31,0x1c,0x00,0x0c,0x21,0x38,0x00,0x00,0xf8,0x57,0x00,0x0c,
-0x00,0x00,0x00,0x00,0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f,0x01,0x00,0x02,0x24,
-0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27,0x00,0x00,0x80,0xa0,0x00,0x00,0x03,0x92,
-0x80,0xff,0x02,0x24,0x25,0x18,0x62,0x00,0x00,0x00,0x03,0xa2,0x25,0xb0,0x04,0x3c,
-0x44,0x00,0x84,0x34,0x00,0x00,0x82,0x94,0x42,0xb0,0x05,0x3c,0xc0,0x00,0x42,0x34,
-0x00,0x00,0x82,0xa4,0x00,0x00,0xa3,0x90,0x00,0x00,0x00,0x00,0x01,0x00,0x63,0x34,
-0x00,0x00,0xa3,0xa0,0xe0,0x57,0x00,0x0c,0x00,0x00,0x00,0x00,0x02,0x80,0x04,0x3c,
-0x08,0x00,0x84,0x24,0x21,0x28,0x00,0x00,0x21,0x30,0x00,0x00,0x31,0x1c,0x00,0x0c,
-0x21,0x38,0x00,0x00,0xf8,0x57,0x00,0x0c,0x00,0x00,0x00,0x00,0x14,0x00,0xbf,0x8f,
-0x10,0x00,0xb0,0x8f,0x01,0x00,0x02,0x24,0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27,
-0x21,0x20,0x00,0x00,0x20,0xb0,0x06,0x3c,0xff,0xff,0x05,0x34,0x21,0x18,0x86,0x00,
-0x04,0x00,0x84,0x24,0x2a,0x10,0xa4,0x00,0x00,0x00,0x60,0xac,0xfb,0xff,0x40,0x10,
-0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xb8,0xff,0xbd,0x27,
-0x25,0xb0,0x04,0x3c,0x44,0x00,0xbf,0xaf,0x40,0x00,0xbe,0xaf,0x3c,0x00,0xb7,0xaf,
-0x38,0x00,0xb6,0xaf,0x34,0x00,0xb5,0xaf,0x30,0x00,0xb4,0xaf,0x2c,0x00,0xb3,0xaf,
-0x28,0x00,0xb2,0xaf,0x24,0x00,0xb1,0xaf,0x20,0x00,0xb0,0xaf,0x0a,0x00,0x83,0x34,
-0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,0x20,0x00,0x42,0x30,0x0c,0x00,0x40,0x10,
-0x4c,0x87,0x02,0x3c,0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,0x10,0x00,0x42,0x30,
-0x66,0x01,0x40,0x10,0x4c,0x87,0x02,0x3c,0x54,0x00,0x83,0x34,0x50,0x00,0x82,0x34,
-0x00,0x00,0x45,0xac,0x00,0x00,0x65,0xa4,0xf9,0x58,0x00,0x08,0x02,0x80,0x03,0x3c,
-0x54,0x00,0x85,0x34,0x00,0xe0,0x42,0x34,0x50,0x00,0x84,0x34,0x12,0x01,0x03,0x24,
-0x00,0x00,0x82,0xac,0x00,0x00,0xa3,0xac,0x02,0x80,0x03,0x3c,0x68,0x15,0x62,0x24,
-0xd5,0x4a,0x43,0x90,0xda,0x4a,0x45,0x94,0x25,0xb0,0x1e,0x3c,0x1c,0x00,0xa3,0xa3,
-0x60,0x4b,0x43,0x8c,0x58,0x00,0xc6,0x37,0xff,0xff,0x04,0x24,0x10,0x00,0xa3,0xaf,
-0x64,0x4b,0x43,0x8c,0x5c,0x00,0xc7,0x37,0x60,0x00,0xc8,0x37,0x14,0x00,0xa3,0xaf,
-0x68,0x4b,0x42,0x8c,0x64,0x00,0xc9,0x37,0x8a,0x00,0xca,0x37,0x18,0x00,0xa2,0xaf,
-0x24,0x10,0x02,0x3c,0x21,0x28,0xa2,0x00,0x4c,0x81,0x02,0x3c,0x00,0xe0,0x42,0x34,
-0x00,0x00,0xc2,0xac,0x96,0x01,0x03,0x24,0x28,0x28,0x02,0x24,0x00,0x00,0xe3,0xac,
-0x89,0x00,0xcb,0x37,0x00,0x00,0x04,0xad,0x8c,0x00,0xcc,0x37,0x00,0x00,0x24,0xad,
-0x09,0x00,0x03,0x24,0x00,0x00,0x42,0xa5,0x10,0x10,0x02,0x24,0x00,0x00,0x63,0xa1,
-0x8e,0x00,0xcd,0x37,0x00,0x00,0x82,0xa5,0x0a,0x0a,0x03,0x24,0x13,0x00,0x02,0x24,
-0x90,0x00,0xce,0x37,0x00,0x00,0xa3,0xa5,0x00,0x00,0xc2,0xa1,0x25,0xb0,0x02,0x3c,
-0x40,0x00,0x03,0x24,0x91,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0x25,0xb0,0x03,0x3c,
-0x3a,0x01,0x02,0x24,0x92,0x00,0x63,0x34,0x00,0x00,0x62,0xa4,0xb5,0x00,0xd1,0x37,
-0x21,0x00,0x03,0x24,0x00,0x00,0x23,0xa2,0x10,0x00,0xa2,0x8f,0xa0,0x00,0xd2,0x37,
-0xa4,0x00,0xd3,0x37,0x00,0x00,0x42,0xae,0x14,0x00,0xa3,0x8f,0xa8,0x00,0xd4,0x37,
-0xac,0x00,0xd5,0x37,0x00,0x00,0x63,0xae,0x18,0x00,0xa2,0x8f,0x25,0xb0,0x03,0x3c,
-0xb0,0x00,0x63,0x34,0x00,0x00,0x82,0xae,0x21,0x10,0x02,0x3c,0xff,0x77,0x42,0x34,
-0x00,0x00,0xa2,0xae,0x25,0xb0,0x02,0x3c,0xd8,0x00,0x42,0x34,0x00,0x00,0x65,0xac,
-0x00,0x00,0x40,0xa0,0x1c,0x00,0xa2,0x93,0x25,0xb0,0x03,0x3c,0xb4,0x00,0x63,0x34,
-0x00,0x00,0x62,0xa0,0x25,0xb0,0x03,0x3c,0x04,0x00,0x02,0x24,0xb6,0x00,0x63,0x34,
-0x00,0x00,0x62,0xa0,0x25,0xb0,0x03,0x3c,0x0f,0x00,0x02,0x24,0xba,0x00,0x63,0x34,
-0xb9,0x00,0xdf,0x37,0x00,0x00,0xe4,0xa3,0x00,0x00,0x62,0xa4,0x25,0xb0,0x02,0x3c,
-0x1a,0x01,0x42,0x34,0x16,0x01,0xd0,0x37,0x18,0x01,0xcf,0x37,0x00,0x00,0x00,0xa6,
-0x25,0xb0,0x03,0x3c,0x00,0x00,0xe0,0xa5,0x00,0x00,0x40,0xa4,0xff,0xff,0x02,0x3c,
-0xff,0x0f,0x42,0x34,0xdc,0x00,0x63,0x34,0x00,0x00,0x62,0xac,0x2f,0x00,0x03,0x3c,
-0x25,0xb0,0x02,0x3c,0x32,0x32,0x63,0x34,0xd0,0x01,0x42,0x34,0x00,0x00,0x43,0xac,
-0x5e,0x00,0x02,0x3c,0x25,0xb0,0x03,0x3c,0x32,0x43,0x42,0x34,0xd4,0x01,0x63,0x34,
-0x00,0x00,0x62,0xac,0x08,0x00,0x03,0x3c,0x25,0xb0,0x02,0x3c,0x30,0xa5,0x63,0x34,
-0xd8,0x01,0x42,0x34,0x00,0x00,0x43,0xac,0xdc,0x01,0xc4,0x37,0x02,0x80,0x03,0x3c,
-0x49,0xa5,0x02,0x34,0x8e,0x7d,0x6d,0x90,0x00,0x00,0x82,0xac,0xc2,0x00,0x02,0x3c,
-0x1a,0x06,0x03,0x24,0x51,0x10,0x42,0x34,0xe0,0x01,0xc5,0x37,0xf4,0x01,0xc6,0x37,
-0xf8,0x01,0xc7,0x37,0x07,0x07,0x04,0x24,0x00,0x00,0xa3,0xa4,0x00,0x02,0xc8,0x37,
-0x00,0x00,0xc4,0xa4,0x26,0x00,0x03,0x24,0x00,0x00,0xe2,0xac,0x03,0x02,0xc9,0x37,
-0x04,0x00,0x02,0x24,0x00,0x00,0x03,0xa5,0x36,0x02,0xca,0x37,0x00,0x00,0x22,0xa1,
-0xc0,0x01,0x03,0x24,0x0c,0x00,0x02,0x24,0x34,0x02,0xcb,0x37,0x00,0x00,0x42,0xa1,
-0x37,0x02,0xcc,0x37,0x00,0x00,0x63,0xa5,0x03,0x00,0x02,0x24,0x22,0x00,0x03,0x24,
-0x00,0x00,0x82,0xa1,0xd6,0x00,0xa3,0x11,0x1b,0x1b,0x02,0x3c,0x13,0x13,0x02,0x3c,
-0x13,0x13,0x42,0x34,0x60,0x01,0xc3,0x37,0x64,0x01,0xc4,0x37,0x68,0x01,0xc5,0x37,
-0x7c,0x01,0xca,0x37,0x6c,0x01,0xc6,0x37,0x70,0x01,0xc7,0x37,0x74,0x01,0xc8,0x37,
-0x78,0x01,0xc9,0x37,0x00,0x00,0x62,0xac,0x00,0x00,0x82,0xac,0x02,0x80,0x03,0x3c,
-0x00,0x00,0xa2,0xac,0x00,0x00,0xc2,0xac,0x00,0x00,0xe2,0xac,0x00,0x00,0x02,0xad,
-0x00,0x00,0x22,0xad,0x00,0x00,0x42,0xad,0x8e,0x7d,0x65,0x90,0x25,0xb0,0x0c,0x3c,
-0x01,0x70,0x03,0x3c,0x80,0x01,0x82,0x35,0x08,0x5f,0x63,0x34,0x22,0x00,0x04,0x24,
-0x00,0x00,0x43,0xac,0xb5,0x00,0xa4,0x10,0x0f,0x1f,0x02,0x3c,0x92,0x00,0x02,0x24,
-0xb2,0x00,0xa2,0x10,0x0f,0x1f,0x02,0x3c,0x0f,0x10,0x02,0x3c,0x00,0xf0,0x51,0x34,
-0xf7,0x01,0x92,0x35,0x15,0xf0,0x4d,0x34,0x77,0x00,0x0e,0x24,0x84,0x01,0x87,0x35,
-0x88,0x01,0x88,0x35,0x10,0xf0,0x44,0x34,0x8c,0x01,0x85,0x35,0x05,0xf0,0x42,0x34,
-0x00,0x00,0xed,0xac,0x90,0x01,0x83,0x35,0x00,0x00,0x04,0xad,0x94,0x01,0x86,0x35,
-0x00,0x00,0xa2,0xac,0xf5,0x0f,0x02,0x24,0x00,0x00,0x71,0xac,0x25,0xb0,0x05,0x3c,
-0x00,0x00,0xc2,0xac,0x98,0x01,0x89,0x35,0x9c,0x01,0x8a,0x35,0xf0,0x0f,0x03,0x24,
-0x0d,0x00,0x02,0x24,0x00,0x00,0x23,0xad,0xa0,0x01,0x8b,0x35,0x00,0x00,0x42,0xad,
-0xa7,0x01,0xb7,0x34,0xf6,0x01,0x8c,0x35,0xff,0xff,0x02,0x24,0x00,0x00,0x6d,0xad,
-0x00,0x00,0x8e,0xa1,0x00,0x00,0x4e,0xa2,0x00,0x00,0xe2,0xa2,0x25,0xb0,0x02,0x3c,
-0xa8,0x01,0xb6,0x34,0xff,0xff,0x09,0x24,0xac,0x01,0x42,0x34,0x00,0x00,0xc9,0xae,
-0x03,0x04,0x04,0x3c,0x00,0x00,0x49,0xac,0x07,0x08,0x03,0x3c,0x25,0xb0,0x02,0x3c,
-0x01,0x02,0x84,0x34,0x05,0x06,0x63,0x34,0xb4,0x01,0xb1,0x34,0xb8,0x01,0xb2,0x34,
-0xbc,0x01,0xb3,0x34,0xb0,0x01,0x42,0x34,0x00,0x00,0x44,0xac,0x00,0x00,0x23,0xae,
-0x25,0xb0,0x02,0x3c,0x00,0x00,0x44,0xae,0x00,0x00,0x63,0xae,0x25,0xb0,0x03,0x3c,
-0x0c,0x00,0x06,0x24,0xc0,0x01,0xb4,0x34,0xc1,0x01,0xb5,0x34,0x0d,0x00,0x08,0x24,
-0xc2,0x01,0x63,0x34,0xc3,0x01,0x42,0x34,0x00,0x00,0x86,0xa2,0xc4,0x01,0xab,0x34,
-0x00,0x00,0xa6,0xa2,0xc5,0x01,0xac,0x34,0x00,0x00,0x66,0xa0,0x0e,0x00,0x07,0x24,
-0x00,0x00,0x48,0xa0,0xc6,0x01,0xaa,0x34,0xc7,0x01,0xad,0x34,0x0f,0x00,0x02,0x24,
-0x00,0x00,0x68,0xa1,0x00,0x00,0x87,0xa1,0x00,0x00,0x47,0xa1,0x00,0x00,0xa2,0xa1,
-0x57,0x01,0x02,0x3c,0x48,0x00,0xbf,0x34,0x46,0x00,0xae,0x34,0x0e,0xe2,0x42,0x34,
-0x00,0x00,0xc0,0xa5,0x4c,0x00,0xbe,0x34,0x00,0x00,0xe2,0xaf,0x4d,0x00,0xb9,0x34,
-0x80,0xff,0x02,0x24,0x00,0x00,0xc0,0xa3,0x00,0x00,0x22,0xa3,0x25,0xb0,0x02,0x3c,
-0xbc,0x00,0x03,0x24,0x40,0x00,0x42,0x34,0x00,0x00,0x43,0xa4,0x25,0xb0,0x03,0x3c,
-0x64,0x03,0xb8,0x34,0xfc,0x37,0x02,0x24,0x40,0x00,0x63,0x34,0x00,0x00,0x00,0xa3,
-0xd8,0x00,0xa7,0x34,0x00,0x00,0x62,0xa4,0x00,0x00,0xe3,0x90,0x2a,0xb0,0x04,0x3c,
-0x80,0xff,0x02,0x24,0x26,0xb0,0x06,0x3c,0x25,0x18,0x62,0x00,0x30,0x00,0x89,0x34,
-0x20,0x20,0x02,0x24,0x38,0x00,0x84,0x34,0x00,0x00,0xe3,0xa0,0x79,0x00,0xc8,0x34,
-0x00,0x00,0x82,0xa4,0x40,0x00,0x03,0x24,0x16,0x00,0x02,0x24,0x00,0x00,0x23,0xa1,
-0x94,0x00,0xaa,0x34,0x00,0x00,0x02,0xa1,0x98,0x00,0xab,0x34,0x64,0x00,0x03,0x24,
-0x22,0x00,0x02,0x24,0x00,0x00,0x43,0xa5,0x7c,0x00,0xd1,0x34,0x00,0x00,0x62,0xa5,
-0x04,0x00,0x12,0x24,0x9c,0x00,0xac,0x34,0x7a,0x00,0xc6,0x34,0x20,0x0c,0x02,0x24,
-0x0a,0x00,0x03,0x24,0x00,0x00,0xd2,0xa0,0x9a,0x00,0xad,0x34,0x00,0x00,0x22,0xa6,
-0x96,0x00,0xae,0x34,0x00,0x00,0x83,0xa1,0xff,0x03,0x02,0x24,0x02,0x00,0x03,0x24,
-0x00,0x00,0xa2,0xa5,0x00,0x00,0xc3,0xa5,0x25,0xb0,0x03,0x3c,0x20,0x00,0x02,0x24,
-0xb7,0x00,0x63,0x34,0x00,0x00,0x62,0xa0,0x25,0xb0,0x02,0x3c,0x09,0x00,0x03,0x24,
-0x89,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0x44,0x00,0xa5,0x34,0x00,0x00,0xa2,0x94,
-0x02,0x80,0x03,0x3c,0x68,0x15,0x66,0x24,0xff,0xfd,0x03,0x24,0x24,0x10,0x43,0x00,
-0x00,0x00,0xa2,0xa4,0x00,0x00,0xa3,0x94,0xd5,0x4a,0xc4,0x90,0x29,0xb0,0x02,0x3c,
-0x40,0x00,0x42,0x34,0x00,0x02,0x63,0x34,0x00,0x00,0xa3,0xa4,0x00,0x00,0x52,0xa0,
-0xd3,0x0a,0x00,0x0c,0x00,0x00,0x00,0x00,0x44,0x00,0xbf,0x8f,0x40,0x00,0xbe,0x8f,
-0x3c,0x00,0xb7,0x8f,0x38,0x00,0xb6,0x8f,0x34,0x00,0xb5,0x8f,0x30,0x00,0xb4,0x8f,
-0x2c,0x00,0xb3,0x8f,0x28,0x00,0xb2,0x8f,0x24,0x00,0xb1,0x8f,0x20,0x00,0xb0,0x8f,
-0x01,0x00,0x02,0x24,0x08,0x00,0xe0,0x03,0x48,0x00,0xbd,0x27,0x54,0x00,0x85,0x34,
-0x00,0xe0,0x42,0x34,0x50,0x00,0x84,0x34,0x12,0x01,0x03,0x24,0x00,0x00,0x82,0xac,
-0x00,0x00,0xa3,0xa4,0xf9,0x58,0x00,0x08,0x02,0x80,0x03,0x3c,0x00,0xf0,0x51,0x34,
-0xf7,0x01,0x92,0x35,0x15,0xf0,0x4d,0x34,0xad,0x59,0x00,0x08,0xff,0xff,0x0e,0x24,
-0x8b,0x59,0x00,0x08,0x1b,0x1b,0x42,0x34,0x25,0xb0,0x03,0x3c,0x25,0xb0,0x08,0x3c,
-0xfc,0x37,0x02,0x24,0x40,0x00,0x63,0x34,0x02,0x80,0x04,0x3c,0x00,0x00,0x62,0xa4,
-0x14,0x80,0x84,0x24,0xff,0x00,0x07,0x24,0xb0,0x03,0x06,0x35,0x00,0x00,0x83,0x94,
-0x00,0x00,0x00,0x00,0xff,0x00,0x62,0x30,0x21,0x18,0x68,0x00,0x0a,0x00,0x47,0x10,
-0xff,0x00,0x65,0x30,0x04,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xac,
-0x00,0x00,0xc3,0xac,0x04,0x00,0x82,0x8c,0x08,0x00,0x84,0x24,0x00,0x00,0xc2,0xac,
-0xf2,0xff,0xa7,0x14,0x00,0x00,0x00,0x00,0x25,0xb0,0x08,0x3c,0x01,0x80,0x02,0x3c,
-0x0c,0x7a,0x44,0x24,0xff,0x00,0x07,0x24,0xb0,0x03,0x06,0x35,0x00,0x00,0x83,0x94,
-0x00,0x00,0x00,0x00,0xff,0x00,0x62,0x30,0x21,0x18,0x68,0x00,0x0a,0x00,0x47,0x10,
-0xff,0x00,0x65,0x30,0x04,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xac,
-0x00,0x00,0xc3,0xac,0x04,0x00,0x82,0x8c,0x08,0x00,0x84,0x24,0x00,0x00,0xc2,0xac,
-0xf2,0xff,0xa7,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,
-0x01,0x80,0x02,0x3c,0x02,0x80,0x05,0x3c,0x10,0x6b,0x42,0x24,0x02,0x80,0x03,0x3c,
-0xcc,0x7d,0xa2,0xac,0x00,0x80,0x02,0x3c,0x6c,0x7e,0x60,0xac,0xcc,0x7d,0xa4,0x24,
-0x02,0x80,0x03,0x3c,0xc8,0x06,0x42,0x24,0x70,0x7e,0x60,0xa4,0x08,0x00,0x82,0xac,
-0x02,0x80,0x03,0x3c,0x00,0x80,0x02,0x3c,0x72,0x7e,0x60,0xa4,0x02,0x80,0x06,0x3c,
-0x08,0x0a,0x42,0x24,0x00,0x80,0x03,0x3c,0x74,0x7e,0xc7,0x24,0x14,0x00,0x82,0xac,
-0x38,0x08,0x63,0x24,0x02,0x80,0x02,0x3c,0x74,0x7e,0xc0,0xac,0x10,0x00,0x83,0xac,
-0x04,0x00,0xe0,0xac,0x7c,0x7e,0x40,0xa0,0x00,0x80,0x02,0x3c,0x88,0x19,0x42,0x24,
-0x3c,0x00,0x82,0xac,0x00,0x80,0x03,0x3c,0x00,0x80,0x02,0x3c,0x24,0x0c,0x63,0x24,
-0x78,0x0f,0x42,0x24,0x1c,0x00,0x83,0xac,0x20,0x00,0x82,0xac,0x00,0x80,0x03,0x3c,
-0x00,0x80,0x02,0x3c,0xc8,0x12,0x63,0x24,0x28,0x16,0x42,0x24,0x24,0x00,0x83,0xac,
-0x28,0x00,0x82,0xac,0x00,0x80,0x03,0x3c,0x01,0x80,0x02,0x3c,0x4c,0x1f,0x63,0x24,
-0xd0,0x04,0x42,0x24,0x2c,0x00,0x83,0xac,0x30,0x00,0x82,0xac,0x00,0x80,0x03,0x3c,
-0x00,0x80,0x02,0x3c,0xe4,0x19,0x63,0x24,0x00,0x03,0x42,0x24,0x38,0x00,0x83,0xac,
-0x08,0x00,0xe0,0x03,0x4c,0x00,0x82,0xac,0x25,0xb0,0x02,0x3c,0x08,0x00,0x42,0x34,
-0x00,0x00,0x43,0x8c,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x02,0x80,0x0e,0x3c,
-0x02,0x80,0x08,0x3c,0x02,0x80,0x02,0x3c,0x02,0x80,0x03,0x3c,0xf8,0x03,0x4d,0x24,
-0x00,0x14,0x6c,0x24,0x01,0x00,0x07,0x24,0x00,0x00,0xcb,0x25,0xff,0xff,0x0a,0x24,
-0x00,0x04,0x09,0x25,0x80,0x1a,0x07,0x00,0x21,0x10,0x6b,0x00,0x00,0x00,0x42,0xac,
-0x90,0x00,0x4a,0xac,0x00,0x04,0x04,0x8d,0x01,0x00,0xe7,0x24,0x08,0x00,0x45,0x24,
-0x21,0x18,0x6d,0x00,0x05,0x00,0xe6,0x28,0x04,0x00,0x82,0xac,0x00,0x00,0x44,0xac,
-0x04,0x00,0x49,0xac,0x00,0x04,0x02,0xad,0x8c,0x00,0x40,0xac,0x6c,0x00,0xa3,0xac,
-0xf0,0xff,0xc0,0x14,0x68,0x00,0xac,0xac,0x08,0x00,0xe0,0x03,0x00,0x00,0xc9,0xad,
-0x05,0x00,0xa2,0x2c,0x13,0x00,0x40,0x10,0xff,0xff,0x07,0x24,0x02,0x80,0x02,0x3c,
-0x80,0x1a,0x05,0x00,0x00,0x00,0x42,0x24,0x0e,0x00,0xa0,0x10,0x21,0x30,0x62,0x00,
-0x90,0x00,0xc3,0x8c,0xff,0xff,0x02,0x24,0x0a,0x00,0x62,0x14,0x00,0x00,0x00,0x00,
-0x8c,0x00,0xc2,0x8c,0x00,0x00,0x00,0x00,0x06,0x00,0x40,0x14,0x00,0x00,0x00,0x00,
-0x01,0x00,0x02,0x24,0x88,0x00,0xc4,0xac,0x8c,0x00,0xc2,0xac,0x90,0x00,0xc5,0xac,
-0x21,0x38,0xa0,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0xe0,0x00,0x25,0xb0,0x04,0x3c,
-0x01,0x80,0x02,0x3c,0x18,0x03,0x85,0x34,0xf4,0x6b,0x42,0x24,0xe0,0xff,0xbd,0x27,
-0x00,0x00,0xa2,0xac,0x1b,0x00,0x86,0x34,0xdb,0xff,0x03,0x24,0x27,0x00,0x84,0x34,
-0x07,0x00,0x02,0x24,0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x00,0x83,0xa0,
-0x18,0x00,0xbf,0xaf,0x00,0x00,0xc2,0xa0,0x01,0x00,0x11,0x24,0x21,0x80,0x00,0x00,
-0x7a,0x42,0x00,0x0c,0x21,0x20,0x00,0x02,0x01,0x00,0x02,0x26,0xff,0x00,0x50,0x30,
-0x2b,0x18,0x30,0x02,0xfa,0xff,0x60,0x10,0x00,0x00,0x00,0x00,0x7a,0x42,0x00,0x0c,
-0x21,0x20,0x00,0x00,0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,
-0x01,0x00,0x02,0x24,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0x08,0x00,0xe0,0x03,
-0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c,
-0x68,0x15,0x42,0x24,0x40,0x10,0x03,0x3c,0xff,0xff,0x44,0x30,0x25,0xc0,0x83,0x00,
-0x94,0x64,0x58,0xac,0x40,0x00,0x18,0x27,0xa0,0x64,0x58,0xac,0x40,0x00,0x18,0x27,
-0xac,0x64,0x58,0xac,0x40,0x00,0x18,0x27,0xb8,0x64,0x58,0xac,0x40,0x00,0x18,0x27,
-0xe0,0xff,0xbd,0x27,0xc4,0x64,0x58,0xac,0x40,0x00,0x18,0x27,0x1c,0x00,0xb7,0xaf,
-0x18,0x00,0xb6,0xaf,0x14,0x00,0xb5,0xaf,0x10,0x00,0xb4,0xaf,0x0c,0x00,0xb3,0xaf,
-0x08,0x00,0xb2,0xaf,0x04,0x00,0xb1,0xaf,0x00,0x00,0xb0,0xaf,0xd0,0x64,0x58,0xac,
-0xa0,0x64,0x45,0x8c,0xac,0x64,0x46,0x8c,0xb8,0x64,0x47,0x8c,0xc4,0x64,0x48,0x8c,
-0xd0,0x64,0x49,0x8c,0x40,0x00,0x18,0x27,0xdc,0x64,0x58,0xac,0x21,0x50,0x00,0x03,
-0x25,0x20,0x83,0x00,0x40,0x00,0x18,0x27,0x20,0x10,0x03,0x3c,0x90,0x64,0x44,0xac,
-0x9c,0x64,0x45,0xac,0xa8,0x64,0x46,0xac,0xb4,0x64,0x47,0xac,0xc0,0x64,0x48,0xac,
-0xcc,0x64,0x49,0xac,0x25,0xb0,0x06,0x3c,0x28,0x64,0x43,0xac,0x24,0x64,0x43,0xac,
-0x34,0x64,0x43,0xac,0x30,0x64,0x43,0xac,0x40,0x64,0x43,0xac,0x3c,0x64,0x43,0xac,
-0x4c,0x64,0x43,0xac,0x48,0x64,0x43,0xac,0xe8,0x64,0x58,0xac,0x00,0x02,0x18,0x27,
-0xd8,0x64,0x4a,0xac,0x00,0x65,0x58,0xac,0x58,0x64,0x43,0xac,0x54,0x64,0x43,0xac,
-0x64,0x64,0x43,0xac,0x60,0x64,0x43,0xac,0x70,0x64,0x43,0xac,0x6c,0x64,0x43,0xac,
-0xac,0x00,0xc4,0x34,0xb0,0x00,0xc5,0x34,0x00,0x00,0x92,0x8c,0xe8,0x64,0x50,0x8c,
-0x00,0x00,0xb3,0x8c,0x21,0x10,0x04,0x3c,0x23,0x10,0x09,0x3c,0x22,0x10,0x0c,0x3c,
-0x02,0x80,0x14,0x3c,0x02,0x80,0x15,0x3c,0x02,0x80,0x16,0x3c,0x02,0x80,0x17,0x3c,
-0x24,0x10,0x05,0x3c,0x21,0x88,0x00,0x03,0x08,0x7b,0x87,0x26,0x00,0x04,0x18,0x27,
-0x10,0x7b,0xa8,0x26,0x18,0x7b,0xca,0x26,0x20,0x7b,0xeb,0x26,0x00,0x04,0x2d,0x35,
-0x00,0x40,0x8e,0x34,0x00,0x80,0x8f,0x35,0x00,0x01,0xc6,0x34,0xe4,0x64,0x50,0xac,
-0xfc,0x64,0x51,0xac,0x64,0x65,0x4d,0xac,0x28,0x65,0x52,0xac,0x34,0x65,0x4e,0xac,
-0x58,0x65,0x4f,0xac,0x4c,0x65,0x53,0xac,0x00,0x00,0xc5,0xac,0x48,0x65,0x45,0xac,
-0x68,0x65,0x43,0xac,0x74,0x65,0x58,0xac,0x7c,0x64,0x43,0xac,0x78,0x64,0x43,0xac,
-0x06,0x65,0x40,0xa4,0x05,0x65,0x40,0xa0,0x04,0x65,0x40,0xa0,0x5c,0x65,0x49,0xac,
-0x60,0x65,0x49,0xac,0x20,0x65,0x44,0xac,0x24,0x65,0x44,0xac,0x2c,0x65,0x44,0xac,
-0x30,0x65,0x44,0xac,0x50,0x65,0x4c,0xac,0x54,0x65,0x4c,0xac,0x44,0x65,0x45,0xac,
-0x6c,0x65,0x43,0xac,0x78,0x65,0x58,0xac,0x04,0x00,0x08,0xad,0x08,0x7b,0x87,0xae,
-0x04,0x00,0x4a,0xad,0x10,0x7b,0xa8,0xae,0x04,0x00,0x6b,0xad,0x18,0x7b,0xca,0xae,
-0x20,0x7b,0xeb,0xae,0x04,0x00,0xe7,0xac,0x02,0x80,0x02,0x3c,0x00,0x14,0x43,0x24,
-0x21,0x20,0xe0,0x00,0x03,0x00,0x06,0x24,0x21,0x10,0x80,0x00,0xff,0xff,0xc6,0x24,
-0x08,0x00,0x78,0xac,0x00,0x00,0x63,0xac,0x10,0x00,0x60,0xac,0x00,0x00,0x67,0xac,
-0x21,0x20,0x60,0x00,0x04,0x00,0x62,0xac,0x00,0x00,0x43,0xac,0x00,0x01,0x18,0x27,
-0xf5,0xff,0xc1,0x04,0x18,0x00,0x63,0x24,0x02,0x80,0x02,0x3c,0x10,0x7b,0x49,0x24,
-0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0x04,0x00,0x28,0x8d,0x60,0x14,0x4b,0x24,
-0x04,0x00,0xe4,0xac,0x00,0x14,0x6a,0x24,0x01,0x00,0x07,0x24,0x21,0x28,0x00,0x00,
-0x07,0x00,0x06,0x24,0x21,0x20,0xab,0x00,0x21,0x10,0xaa,0x00,0xff,0xff,0xc6,0x24,
-0x68,0x00,0x58,0xac,0x70,0x00,0x47,0xac,0x18,0x00,0xa5,0x24,0x00,0x00,0x89,0xac,
-0x04,0x00,0x88,0xac,0x00,0x00,0x04,0xad,0x00,0x01,0x18,0x27,0xf5,0xff,0xc1,0x04,
-0x21,0x40,0x80,0x00,0x02,0x80,0x02,0x3c,0x18,0x7b,0x4a,0x24,0x02,0x80,0x03,0x3c,
-0x02,0x80,0x02,0x3c,0x04,0x00,0x45,0x8d,0x20,0x15,0x4b,0x24,0x04,0x00,0x24,0xad,
-0x02,0x00,0x07,0x24,0x00,0x14,0x69,0x24,0x21,0x20,0x00,0x00,0x01,0x00,0x06,0x24,
-0x21,0x40,0x8b,0x00,0x21,0x10,0x89,0x00,0xff,0xff,0xc6,0x24,0x28,0x01,0x58,0xac,
-0x30,0x01,0x47,0xac,0x18,0x00,0x84,0x24,0x00,0x00,0x0a,0xad,0x04,0x00,0x05,0xad,
-0x00,0x00,0xa8,0xac,0x00,0x02,0x18,0x27,0xf5,0xff,0xc1,0x04,0x21,0x28,0x00,0x01,
-0x02,0x80,0x05,0x3c,0x20,0x7b,0xa5,0x24,0x04,0x00,0xa6,0x8c,0x1c,0x00,0xb7,0x8f,
-0x18,0x00,0xb6,0x8f,0x14,0x00,0xb5,0x8f,0x10,0x00,0xb4,0x8f,0x0c,0x00,0xb3,0x8f,
-0x08,0x00,0xb2,0x8f,0x04,0x00,0xb1,0x8f,0x00,0x00,0xb0,0x8f,0x02,0x80,0x07,0x3c,
-0x02,0x80,0x03,0x3c,0x50,0x15,0xe4,0x24,0x00,0x14,0x63,0x24,0x03,0x00,0x02,0x24,
-0x20,0x00,0xbd,0x27,0x58,0x01,0x78,0xac,0x04,0x00,0x48,0xad,0x04,0x00,0xa4,0xac,
-0x60,0x01,0x62,0xac,0x50,0x15,0xe5,0xac,0x04,0x00,0x86,0xac,0x08,0x00,0xe0,0x03,
-0x00,0x00,0xc4,0xac,0xd0,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c,0x20,0x00,0xb2,0xaf,
-0x02,0x80,0x03,0x3c,0x4c,0x91,0x52,0x24,0x02,0x80,0x02,0x3c,0x28,0x00,0xb4,0xaf,
-0x24,0x00,0xb3,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,0x2c,0x00,0xbf,0xaf,
-0xd8,0x90,0x73,0x24,0x68,0x15,0x50,0x24,0x21,0x88,0x00,0x00,0x02,0x80,0x14,0x3c,
-0xee,0x4e,0x00,0x0c,0x21,0x20,0x20,0x02,0x78,0x51,0x05,0x8e,0x6c,0x00,0x66,0x8e,
-0xb8,0x90,0x82,0x26,0x6c,0x00,0x43,0x8e,0x1b,0x00,0x44,0x90,0xff,0xf1,0x02,0x24,
-0x21,0x18,0x66,0x00,0x24,0x28,0xa2,0x00,0x00,0x21,0x04,0x00,0x42,0x18,0x03,0x00,
-0x00,0x02,0xa5,0x34,0x44,0x51,0x03,0xae,0x68,0x51,0x04,0xae,0x78,0x51,0x05,0xae,
-0x6c,0x51,0x04,0xae,0x21,0x30,0x00,0x00,0x21,0x10,0x06,0x02,0x01,0x00,0xc6,0x24,
-0x1d,0x00,0xc3,0x28,0x99,0x51,0x40,0xa0,0x7c,0x51,0x40,0xa0,0xfa,0xff,0x60,0x14,
-0xb6,0x51,0x40,0xa0,0x01,0x00,0x31,0x26,0x20,0x00,0x22,0x2a,0xd4,0x51,0x00,0xae,
-0xe3,0xff,0x40,0x14,0x94,0x00,0x10,0x26,0x02,0x80,0x02,0x3c,0x02,0x80,0x03,0x3c,
-0x68,0x15,0x4b,0x24,0x02,0x80,0x02,0x3c,0x4c,0x91,0x6f,0x24,0xd8,0x90,0x4d,0x24,
-0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0xb8,0x90,0x6e,0x24,0x98,0x90,0x4c,0x24,
-0x21,0x88,0x00,0x00,0x80,0x18,0x11,0x00,0x21,0x20,0x6d,0x00,0x21,0x10,0x6f,0x00,
-0x21,0x28,0x2e,0x02,0x21,0x30,0x2c,0x02,0x00,0x00,0x88,0x8c,0x00,0x00,0xa9,0x90,
-0x00,0x00,0xc7,0x90,0x00,0x00,0x4a,0x8c,0x21,0x10,0x2b,0x02,0x01,0x00,0x31,0x26,
-0x21,0x18,0x6b,0x00,0x1d,0x00,0x24,0x2a,0xec,0x44,0x68,0xac,0xca,0x44,0x47,0xa0,
-0x60,0x45,0x6a,0xac,0xef,0xff,0x80,0x14,0x90,0x44,0x49,0xa0,0x02,0x80,0x02,0x3c,
-0x68,0x15,0x4a,0x24,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0x74,0x8f,0x6b,0x24,
-0x14,0x8e,0x4c,0x24,0x21,0x88,0x00,0x00,0x21,0x48,0x00,0x00,0x21,0x30,0x00,0x00,
-0x21,0x40,0x2a,0x01,0x21,0x38,0x2b,0x01,0x21,0x10,0xe6,0x00,0x91,0x00,0x44,0x90,
-0x00,0x00,0x45,0x90,0x21,0x18,0x06,0x01,0x01,0x00,0xc6,0x24,0x05,0x00,0xc2,0x28,
-0xc5,0x43,0x64,0xa0,0xf8,0xff,0x40,0x14,0x34,0x43,0x65,0xa0,0x21,0x10,0x2c,0x02,
-0x1d,0x00,0x44,0x90,0x00,0x00,0x45,0x90,0x21,0x18,0x2a,0x02,0x01,0x00,0x31,0x26,
-0x1d,0x00,0x22,0x2a,0x73,0x44,0x64,0xa0,0x56,0x44,0x65,0xa0,0xeb,0xff,0x40,0x14,
-0x05,0x00,0x29,0x25,0x52,0x00,0x02,0x24,0x10,0x00,0xa2,0xa3,0x41,0x00,0x03,0x24,
-0x4d,0x00,0x02,0x24,0x02,0x80,0x07,0x3c,0x1c,0x97,0xe7,0x24,0x11,0x00,0xa3,0xa3,
-0x12,0x00,0xa2,0xa3,0xe8,0x03,0x03,0x24,0x01,0x00,0x02,0x24,0x00,0x80,0x06,0x3c,
-0x10,0x00,0xa5,0x27,0x21,0x20,0xe0,0x00,0xf0,0x37,0xc6,0x24,0x0c,0x00,0xe3,0xac,
-0x14,0x00,0xe2,0xa0,0xfb,0x0c,0x00,0x0c,0x13,0x00,0xa0,0xa3,0x2c,0x00,0xbf,0x8f,
-0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,
-0x18,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27,
-0x02,0x80,0x02,0x3c,0x42,0x00,0x03,0x24,0x10,0x00,0xa3,0xa3,0x55,0x60,0x40,0xa0,
-0x4e,0x00,0x03,0x24,0x43,0x00,0x02,0x24,0x02,0x80,0x07,0x3c,0x54,0x97,0xe7,0x24,
-0x11,0x00,0xa2,0xa3,0x12,0x00,0xa3,0xa3,0xd0,0x07,0x02,0x24,0x01,0x00,0x03,0x24,
-0x00,0x80,0x06,0x3c,0x10,0x00,0xa5,0x27,0x21,0x20,0xe0,0x00,0xdc,0x44,0xc6,0x24,
-0x0c,0x00,0xe2,0xac,0x14,0x00,0xe3,0xa0,0x18,0x00,0xbf,0xaf,0xfb,0x0c,0x00,0x0c,
-0x13,0x00,0xa0,0xa3,0x18,0x00,0xbf,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,
-0x20,0x00,0xbd,0x27,0x48,0xfd,0xbd,0x27,0xb4,0x02,0xb3,0xaf,0x02,0x80,0x02,0x3c,
-0x02,0x80,0x13,0x3c,0x24,0x92,0x46,0x24,0x68,0x15,0x63,0x26,0xb0,0x02,0xb2,0xaf,
-0xac,0x02,0xb1,0xaf,0xa8,0x02,0xb0,0xaf,0x03,0x40,0x60,0xa0,0x21,0x38,0xa0,0x03,
-0x90,0x00,0xc8,0x24,0x00,0x00,0xc2,0x8c,0x04,0x00,0xc3,0x8c,0x08,0x00,0xc4,0x8c,
-0x0c,0x00,0xc5,0x8c,0x10,0x00,0xc6,0x24,0x00,0x00,0xe2,0xac,0x04,0x00,0xe3,0xac,
-0x08,0x00,0xe4,0xac,0x0c,0x00,0xe5,0xac,0xf6,0xff,0xc8,0x14,0x10,0x00,0xe7,0x24,
-0x00,0x00,0xc3,0x8c,0x02,0x80,0x02,0x3c,0xb8,0x92,0x58,0x24,0x00,0x00,0xe3,0xac,
-0x98,0x00,0xb9,0x27,0x00,0x01,0x12,0x27,0x01,0x00,0x02,0x93,0x05,0x00,0x03,0x93,
-0x09,0x00,0x04,0x93,0x0d,0x00,0x05,0x93,0x00,0x00,0x11,0x93,0x02,0x00,0x0d,0x93,
-0x04,0x00,0x10,0x93,0x06,0x00,0x0c,0x93,0x08,0x00,0x0f,0x93,0x0a,0x00,0x07,0x93,
-0x0c,0x00,0x0e,0x93,0x0e,0x00,0x06,0x93,0x03,0x00,0x08,0x93,0x07,0x00,0x09,0x93,
-0x0b,0x00,0x0a,0x93,0x0f,0x00,0x0b,0x93,0x00,0x12,0x02,0x00,0x00,0x1a,0x03,0x00,
-0x00,0x22,0x04,0x00,0x00,0x2a,0x05,0x00,0x25,0x10,0x51,0x00,0x25,0x18,0x70,0x00,
-0x25,0x20,0x8f,0x00,0x25,0x28,0xae,0x00,0x00,0x6c,0x0d,0x00,0x00,0x64,0x0c,0x00,
-0x00,0x3c,0x07,0x00,0x00,0x34,0x06,0x00,0x25,0x68,0xa2,0x01,0x25,0x60,0x83,0x01,
-0x25,0x38,0xe4,0x00,0x25,0x30,0xc5,0x00,0x00,0x46,0x08,0x00,0x00,0x4e,0x09,0x00,
-0x00,0x56,0x0a,0x00,0x00,0x5e,0x0b,0x00,0x25,0x40,0x0d,0x01,0x25,0x48,0x2c,0x01,
-0x25,0x50,0x47,0x01,0x25,0x58,0x66,0x01,0x10,0x00,0x18,0x27,0x00,0x00,0x28,0xaf,
-0x04,0x00,0x29,0xaf,0x08,0x00,0x2a,0xaf,0x0c,0x00,0x2b,0xaf,0xd2,0xff,0x12,0x17,
-0x10,0x00,0x39,0x27,0x01,0x00,0x02,0x93,0x05,0x00,0x03,0x93,0x00,0x00,0x09,0x93,
-0x02,0x00,0x04,0x93,0x04,0x00,0x08,0x93,0x06,0x00,0x05,0x93,0x07,0x00,0x06,0x93,
-0x03,0x00,0x07,0x93,0x00,0x12,0x02,0x00,0x00,0x1a,0x03,0x00,0x25,0x10,0x49,0x00,
-0x25,0x18,0x68,0x00,0x00,0x24,0x04,0x00,0x00,0x2c,0x05,0x00,0x25,0x20,0x82,0x00,
-0x25,0x28,0xa3,0x00,0x00,0x3e,0x07,0x00,0x00,0x36,0x06,0x00,0x02,0x80,0x02,0x3c,
-0x25,0x38,0xe4,0x00,0x25,0x30,0xc5,0x00,0xc0,0x93,0x58,0x24,0x04,0x00,0x26,0xaf,
-0x00,0x00,0x27,0xaf,0x00,0x01,0x12,0x27,0xa0,0x01,0xb9,0x27,0x01,0x00,0x02,0x93,
-0x05,0x00,0x03,0x93,0x09,0x00,0x04,0x93,0x0d,0x00,0x05,0x93,0x00,0x00,0x11,0x93,
-0x02,0x00,0x0d,0x93,0x04,0x00,0x10,0x93,0x06,0x00,0x0c,0x93,0x08,0x00,0x0f,0x93,
-0x0a,0x00,0x07,0x93,0x0c,0x00,0x0e,0x93,0x0e,0x00,0x06,0x93,0x03,0x00,0x08,0x93,
-0x07,0x00,0x09,0x93,0x0b,0x00,0x0a,0x93,0x0f,0x00,0x0b,0x93,0x00,0x12,0x02,0x00,
-0x00,0x1a,0x03,0x00,0x00,0x22,0x04,0x00,0x00,0x2a,0x05,0x00,0x25,0x10,0x51,0x00,
-0x25,0x18,0x70,0x00,0x25,0x20,0x8f,0x00,0x25,0x28,0xae,0x00,0x00,0x6c,0x0d,0x00,
-0x00,0x64,0x0c,0x00,0x00,0x3c,0x07,0x00,0x00,0x34,0x06,0x00,0x25,0x68,0xa2,0x01,
-0x25,0x60,0x83,0x01,0x25,0x38,0xe4,0x00,0x25,0x30,0xc5,0x00,0x00,0x46,0x08,0x00,
-0x00,0x4e,0x09,0x00,0x00,0x56,0x0a,0x00,0x00,0x5e,0x0b,0x00,0x25,0x40,0x0d,0x01,
-0x25,0x48,0x2c,0x01,0x25,0x50,0x47,0x01,0x25,0x58,0x66,0x01,0x10,0x00,0x18,0x27,
-0x00,0x00,0x28,0xaf,0x04,0x00,0x29,0xaf,0x08,0x00,0x2a,0xaf,0x0c,0x00,0x2b,0xaf,
-0xd2,0xff,0x12,0x17,0x10,0x00,0x39,0x27,0x01,0x00,0x02,0x93,0x05,0x00,0x03,0x93,
-0x00,0x00,0x09,0x93,0x02,0x00,0x04,0x93,0x04,0x00,0x08,0x93,0x06,0x00,0x05,0x93,
-0x07,0x00,0x06,0x93,0x03,0x00,0x07,0x93,0x00,0x12,0x02,0x00,0x00,0x1a,0x03,0x00,
-0x25,0x10,0x49,0x00,0x25,0x18,0x68,0x00,0x00,0x24,0x04,0x00,0x00,0x2c,0x05,0x00,
-0x25,0x20,0x82,0x00,0x25,0x28,0xa3,0x00,0x00,0x3e,0x07,0x00,0x00,0x36,0x06,0x00,
-0x25,0x30,0xc5,0x00,0x25,0x38,0xe4,0x00,0x02,0x80,0x02,0x3c,0x04,0x00,0x26,0xaf,
-0x00,0x00,0x27,0xaf,0x68,0x15,0x46,0x24,0x21,0x50,0x00,0x00,0x80,0x20,0x0a,0x00,
-0x21,0x10,0x9d,0x00,0x00,0x00,0x45,0x8c,0x01,0x00,0x43,0x25,0xff,0x00,0x6a,0x30,
-0x21,0x20,0x86,0x00,0x25,0x00,0x42,0x2d,0xf8,0xff,0x40,0x14,0x18,0x40,0x85,0xac,
-0x02,0x80,0x02,0x3c,0x68,0x15,0x4b,0x24,0x21,0x50,0x00,0x00,0xc0,0x10,0x0a,0x00,
-0x21,0x48,0x5d,0x00,0x21,0x38,0x00,0x00,0x21,0x40,0x4b,0x00,0x21,0x10,0x27,0x01,
-0xa0,0x01,0x46,0x90,0x98,0x00,0x45,0x90,0x01,0x00,0xe4,0x24,0x21,0x18,0x07,0x01,
-0xff,0x00,0x87,0x30,0x08,0x00,0xe2,0x2c,0xb4,0x41,0x66,0xa0,0xf7,0xff,0x40,0x14,
-0xac,0x40,0x65,0xa0,0x01,0x00,0x42,0x25,0xff,0x00,0x4a,0x30,0x21,0x00,0x43,0x2d,
-0xef,0xff,0x60,0x14,0xc0,0x10,0x0a,0x00,0x25,0xb0,0x02,0x3c,0x0a,0x00,0x42,0x34,
-0x00,0x00,0x43,0x90,0x00,0x00,0x00,0x00,0x20,0x00,0x63,0x30,0x42,0x00,0x60,0x10,
-0x68,0x15,0x64,0x26,0x33,0x00,0x02,0x24,0xc1,0x42,0x62,0xa1,0x1c,0x00,0x03,0x24,
-0x0f,0x00,0x02,0x24,0xbc,0x42,0x63,0xa1,0xbd,0x42,0x62,0xa1,0x68,0x15,0x65,0x26,
-0x08,0x40,0xa4,0x8c,0xff,0x7f,0x08,0x3c,0xff,0xff,0x08,0x35,0xc0,0xff,0x02,0x24,
-0x24,0x20,0x88,0x00,0x24,0x20,0x82,0x00,0x0c,0x00,0x84,0x34,0xff,0xc0,0x02,0x24,
-0x24,0x20,0x82,0x00,0xc0,0xff,0x02,0x3c,0xff,0xff,0x42,0x34,0x00,0x18,0x84,0x34,
-0xbf,0xff,0x03,0x3c,0x24,0x20,0x82,0x00,0xff,0xff,0x63,0x34,0x7f,0xff,0x02,0x3c,
-0x24,0x20,0x83,0x00,0xff,0xff,0x42,0x34,0x24,0x20,0x82,0x00,0x0c,0x40,0xa6,0x8c,
-0x7f,0xff,0x03,0x24,0x40,0x40,0x84,0x34,0xff,0xff,0x02,0x3c,0x24,0x20,0x83,0x00,
-0xff,0x7f,0x42,0x34,0xff,0xbf,0x03,0x3c,0x10,0x40,0xa7,0x8c,0x24,0x20,0x82,0x00,
-0xff,0xff,0x63,0x34,0xff,0x9f,0x02,0x3c,0x24,0x30,0xc3,0x00,0xff,0xff,0x42,0x34,
-0xff,0x3f,0x03,0x3c,0x24,0x20,0x82,0x00,0xff,0xff,0x63,0x34,0x12,0x00,0x02,0x24,
-0xb4,0x02,0xb3,0x8f,0xb0,0x02,0xb2,0x8f,0xac,0x02,0xb1,0x8f,0xa8,0x02,0xb0,0x8f,
-0x24,0x38,0xe3,0x00,0xc7,0x42,0xa2,0xa0,0x1f,0x00,0x03,0x24,0x01,0x00,0x02,0x24,
-0x24,0x30,0xc8,0x00,0xbe,0x42,0xa3,0xa0,0xc0,0x42,0xa2,0xa0,0xff,0x00,0x03,0x24,
-0xff,0xff,0x02,0x24,0xb8,0x02,0xbd,0x27,0x08,0x40,0xa4,0xac,0x10,0x40,0xa7,0xac,
-0x0c,0x40,0xa6,0xac,0xc2,0x42,0xa2,0xa0,0xc4,0x42,0xa3,0xa4,0xbf,0x42,0xa0,0xa0,
-0x08,0x00,0xe0,0x03,0xc6,0x42,0xa0,0xa0,0x33,0x00,0x02,0x24,0xc1,0x42,0x82,0xa0,
-0x0d,0x00,0x03,0x24,0x03,0x00,0x02,0x24,0xbc,0x42,0x83,0xa0,0x65,0x5d,0x00,0x08,
-0xbd,0x42,0x82,0xa0,0xe0,0xff,0xbd,0x27,0x02,0x80,0x07,0x3c,0x68,0x15,0xe7,0x24,
-0x18,0x00,0xbf,0xaf,0x00,0x40,0xe3,0x8c,0xf0,0xff,0x02,0x24,0x02,0x80,0x08,0x3c,
-0x24,0x18,0x62,0x00,0xff,0xf0,0x02,0x24,0x24,0x18,0x62,0x00,0x00,0x40,0xe3,0xac,
-0x1c,0x00,0x03,0x24,0x36,0x00,0x02,0x24,0xcf,0x42,0xe3,0xa0,0x20,0x00,0x03,0x24,
-0xce,0x42,0xe2,0xa0,0xd1,0x42,0xe3,0xa0,0x32,0x00,0x02,0x24,0x20,0x00,0x03,0x24,
-0xd0,0x42,0xe2,0xa0,0xc8,0x42,0xe3,0xa4,0x0a,0x00,0x02,0x24,0x00,0x02,0x03,0x24,
-0xd2,0x42,0xe2,0xa0,0xcc,0x42,0xe3,0xa4,0x00,0x01,0x02,0x24,0x49,0x00,0x03,0x24,
-0x38,0x97,0x08,0x25,0xff,0xff,0x0a,0x34,0x01,0x00,0x09,0x24,0x11,0x00,0xa3,0xa3,
-0xca,0x42,0xe2,0xa4,0xd0,0x07,0x03,0x24,0x44,0x00,0x02,0x24,0x00,0x80,0x06,0x3c,
-0x10,0x00,0xa2,0xa3,0x10,0x00,0xa5,0x27,0x47,0x00,0x02,0x24,0x21,0x20,0x00,0x01,
-0x54,0x45,0xc6,0x24,0x04,0x40,0xea,0xac,0x02,0x40,0xe9,0xa0,0x0c,0x00,0x03,0xad,
-0x14,0x00,0x09,0xa1,0xe6,0x42,0xe0,0xa0,0xdc,0x63,0xea,0xac,0xd7,0x42,0xe0,0xa0,
-0x12,0x00,0xa2,0xa3,0xfb,0x0c,0x00,0x0c,0x13,0x00,0xa0,0xa3,0x18,0x00,0xbf,0x8f,
-0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27,
-0x02,0x80,0x02,0x3c,0x50,0x00,0x03,0x24,0x10,0x00,0xa3,0xa3,0x2a,0x62,0x40,0xa0,
-0x41,0x00,0x03,0x24,0x52,0x00,0x02,0x24,0x02,0x80,0x07,0x3c,0xc4,0x97,0xe7,0x24,
-0x11,0x00,0xa2,0xa3,0x12,0x00,0xa3,0xa3,0xd0,0x07,0x02,0x24,0x01,0x00,0x03,0x24,
-0x01,0x80,0x06,0x3c,0x10,0x00,0xa5,0x27,0x21,0x20,0xe0,0x00,0x88,0x5b,0xc6,0x24,
-0x0c,0x00,0xe2,0xac,0x14,0x00,0xe3,0xa0,0x18,0x00,0xbf,0xaf,0xfb,0x0c,0x00,0x0c,
-0x13,0x00,0xa0,0xa3,0x18,0x00,0xbf,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,
-0x20,0x00,0xbd,0x27,0xd8,0xff,0xbd,0x27,0x18,0x00,0xb0,0xaf,0x02,0x80,0x10,0x3c,
-0x68,0x15,0x10,0x26,0x20,0x00,0xbf,0xaf,0x1c,0x00,0xb1,0xaf,0x00,0x40,0x09,0x8e,
-0xff,0xff,0x02,0x24,0xff,0x00,0x4b,0x30,0x0f,0xff,0x02,0x24,0x24,0x48,0x22,0x01,
-0xff,0xff,0x02,0x3c,0xff,0x0f,0x42,0x34,0x24,0x48,0x22,0x01,0x01,0x00,0x07,0x3c,
-0x47,0x00,0x02,0x24,0x3b,0x00,0x03,0x24,0x02,0x80,0x08,0x3c,0x10,0x00,0xa2,0xa3,
-0x11,0x00,0xa3,0xa3,0xe0,0x97,0x08,0x25,0x56,0x30,0xea,0x34,0xd0,0x07,0x02,0x24,
-0x01,0x00,0x03,0x24,0xf4,0x98,0xe7,0x34,0x00,0x80,0x06,0x3c,0x04,0x43,0x0b,0xae,
-0x00,0x40,0x09,0xae,0x43,0x00,0x11,0x24,0x10,0x00,0xa5,0x27,0x0c,0x43,0x07,0xae,
-0x10,0x43,0x0a,0xae,0x0c,0x00,0x02,0xad,0x14,0x00,0x03,0xa1,0x08,0x43,0x00,0xae,
-0x14,0x43,0x00,0xae,0x18,0x43,0x00,0xae,0x21,0x20,0x00,0x01,0xe4,0x4e,0xc6,0x24,
-0x12,0x00,0xb1,0xa3,0xfb,0x0c,0x00,0x0c,0x13,0x00,0xa0,0xa3,0x1e,0x00,0x02,0x24,
-0x21,0x43,0x02,0xa2,0x4a,0x00,0x03,0x24,0x45,0x00,0x02,0x24,0x1c,0x43,0x03,0xa2,
-0x1d,0x43,0x02,0xa2,0x23,0x00,0x03,0x24,0x3e,0x00,0x02,0x24,0x1e,0x43,0x11,0xa2,
-0x1f,0x43,0x02,0xa2,0x20,0x43,0x03,0xa2,0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb1,0x8f,
-0x18,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x28,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27,
-0x3b,0x00,0x02,0x24,0x43,0x00,0x03,0x24,0x10,0x00,0xa2,0xa3,0x11,0x00,0xa3,0xa3,
-0x36,0x00,0x02,0x24,0x02,0x80,0x03,0x3c,0x02,0x80,0x07,0x3c,0xfc,0x97,0xe7,0x24,
-0x12,0x00,0xa2,0xa3,0x3b,0x58,0x60,0xa0,0xd0,0x07,0x02,0x24,0x01,0x00,0x03,0x24,
-0x00,0x80,0x06,0x3c,0x10,0x00,0xa5,0x27,0x21,0x20,0xe0,0x00,0x20,0x53,0xc6,0x24,
-0x0c,0x00,0xe2,0xac,0x14,0x00,0xe3,0xa0,0x18,0x00,0xbf,0xaf,0xfb,0x0c,0x00,0x0c,
-0x13,0x00,0xa0,0xa3,0x18,0x00,0xbf,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,
-0x20,0x00,0xbd,0x27,0xff,0xff,0x07,0x24,0x02,0x80,0x02,0x3c,0xe0,0xff,0xbd,0x27,
-0x3d,0x58,0x47,0xa0,0x3b,0x00,0x03,0x24,0x43,0x00,0x02,0x24,0x10,0x00,0xa3,0xa3,
-0x11,0x00,0xa2,0xa3,0x36,0x00,0x03,0x24,0x16,0x00,0x02,0x24,0x02,0x80,0x08,0x3c,
-0x18,0x98,0x08,0x25,0x12,0x00,0xa3,0xa3,0x13,0x00,0xa2,0xa3,0xd0,0x07,0x03,0x24,
-0x01,0x00,0x02,0x24,0x00,0x80,0x06,0x3c,0x10,0x00,0xa5,0x27,0x21,0x20,0x00,0x01,
-0x0c,0x00,0x03,0xad,0x14,0x00,0x02,0xa1,0x18,0x00,0xbf,0xaf,0xfb,0x0c,0x00,0x0c,
-0xb8,0x54,0xc6,0x24,0x18,0x00,0xbf,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,
-0x20,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c,0x52,0x00,0x03,0x24,
-0x10,0x00,0xa3,0xa3,0x4c,0x79,0x40,0xa4,0x54,0x00,0x03,0x24,0x53,0x00,0x02,0x24,
-0x02,0x80,0x07,0x3c,0x34,0x98,0xe7,0x24,0x11,0x00,0xa2,0xa3,0x12,0x00,0xa3,0xa3,
-0xf4,0x01,0x02,0x24,0x01,0x00,0x03,0x24,0x01,0x80,0x06,0x3c,0x10,0x00,0xa5,0x27,
-0x21,0x20,0xe0,0x00,0xc8,0x5c,0xc6,0x24,0x0c,0x00,0xe2,0xac,0x14,0x00,0xe3,0xa0,
-0x18,0x00,0xbf,0xaf,0xfb,0x0c,0x00,0x0c,0x13,0x00,0xa0,0xa3,0x18,0x00,0xbf,0x8f,
-0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x78,0x0c,0x00,0x00,0x01,0x00,0x00,0x5e,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x01,0x5e,0x78,0x0c,0x00,0x00,0x01,0x00,0x02,0x5e,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x03,0x5e,0x78,0x0c,0x00,0x00,0x01,0x00,0x04,0x5d,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x05,0x5b,0x78,0x0c,0x00,0x00,0x01,0x00,0x06,0x59,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x07,0x57,0x78,0x0c,0x00,0x00,0x01,0x00,0x08,0x55,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x09,0x53,0x78,0x0c,0x00,0x00,0x01,0x00,0x0a,0x51,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x0b,0x4f,0x78,0x0c,0x00,0x00,0x01,0x00,0x0c,0x4d,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x0d,0x4b,0x78,0x0c,0x00,0x00,0x01,0x00,0x0e,0x49,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x0f,0x47,0x78,0x0c,0x00,0x00,0x01,0x00,0x10,0x45,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x11,0x43,0x78,0x0c,0x00,0x00,0x01,0x00,0x12,0x41,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x13,0x3f,0x78,0x0c,0x00,0x00,0x01,0x00,0x14,0x3d,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x15,0x3b,0x78,0x0c,0x00,0x00,0x01,0x00,0x16,0x39,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x17,0x37,0x78,0x0c,0x00,0x00,0x01,0x00,0x18,0x35,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x19,0x33,0x78,0x0c,0x00,0x00,0x01,0x00,0x1a,0x31,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x1b,0x2f,0x78,0x0c,0x00,0x00,0x01,0x00,0x1c,0x2d,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x1d,0x2b,0x78,0x0c,0x00,0x00,0x01,0x00,0x1e,0x29,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x1f,0x27,0x78,0x0c,0x00,0x00,0x01,0x00,0x20,0x25,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x21,0x23,0x78,0x0c,0x00,0x00,0x01,0x00,0x22,0x21,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x23,0x1f,0x78,0x0c,0x00,0x00,0x01,0x00,0x24,0x1d,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x25,0x1b,0x78,0x0c,0x00,0x00,0x01,0x00,0x26,0x19,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x27,0x17,0x78,0x0c,0x00,0x00,0x01,0x00,0x28,0x15,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x29,0x13,0x78,0x0c,0x00,0x00,0x01,0x00,0x2a,0x11,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x2b,0x0f,0x78,0x0c,0x00,0x00,0x01,0x00,0x2c,0x0d,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x2d,0x0b,0x78,0x0c,0x00,0x00,0x01,0x00,0x2e,0x09,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x2f,0x07,0x78,0x0c,0x00,0x00,0x01,0x00,0x30,0x05,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x31,0x03,0x78,0x0c,0x00,0x00,0x01,0x00,0x32,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x33,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x34,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x35,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x36,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x37,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x38,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x39,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x3a,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x3b,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x3c,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x3d,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x3e,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x3f,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x40,0x5e,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x41,0x5e,0x78,0x0c,0x00,0x00,0x01,0x00,0x42,0x5e,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x43,0x5e,0x78,0x0c,0x00,0x00,0x01,0x00,0x44,0x5d,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x45,0x5b,0x78,0x0c,0x00,0x00,0x01,0x00,0x46,0x59,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x47,0x57,0x78,0x0c,0x00,0x00,0x01,0x00,0x48,0x55,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x49,0x53,0x78,0x0c,0x00,0x00,0x01,0x00,0x4a,0x51,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x4b,0x4f,0x78,0x0c,0x00,0x00,0x01,0x00,0x4c,0x4d,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x4d,0x4b,0x78,0x0c,0x00,0x00,0x01,0x00,0x4e,0x49,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x4f,0x47,0x78,0x0c,0x00,0x00,0x01,0x00,0x50,0x45,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x51,0x43,0x78,0x0c,0x00,0x00,0x01,0x00,0x52,0x41,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x53,0x3f,0x78,0x0c,0x00,0x00,0x01,0x00,0x54,0x3d,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x55,0x3b,0x78,0x0c,0x00,0x00,0x01,0x00,0x56,0x39,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x57,0x37,0x78,0x0c,0x00,0x00,0x01,0x00,0x58,0x35,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x59,0x33,0x78,0x0c,0x00,0x00,0x01,0x00,0x5a,0x31,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x5b,0x2f,0x78,0x0c,0x00,0x00,0x01,0x00,0x5c,0x2d,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x5d,0x2b,0x78,0x0c,0x00,0x00,0x01,0x00,0x5e,0x29,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x5f,0x27,0x78,0x0c,0x00,0x00,0x01,0x00,0x60,0x25,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x61,0x23,0x78,0x0c,0x00,0x00,0x01,0x00,0x62,0x21,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x63,0x1f,0x78,0x0c,0x00,0x00,0x01,0x00,0x64,0x1d,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x65,0x1b,0x78,0x0c,0x00,0x00,0x01,0x00,0x66,0x19,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x67,0x17,0x78,0x0c,0x00,0x00,0x01,0x00,0x68,0x15,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x69,0x13,0x78,0x0c,0x00,0x00,0x01,0x00,0x6a,0x11,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x6b,0x0f,0x78,0x0c,0x00,0x00,0x01,0x00,0x6c,0x0d,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x6d,0x0b,0x78,0x0c,0x00,0x00,0x01,0x00,0x6e,0x09,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x6f,0x07,0x78,0x0c,0x00,0x00,0x01,0x00,0x70,0x05,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x71,0x03,0x78,0x0c,0x00,0x00,0x01,0x00,0x72,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x73,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x74,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x75,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x76,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x77,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x78,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x79,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x7a,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x7b,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x7c,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x7d,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x7e,0x01,0x78,0x0c,0x00,0x00,
-0x01,0x00,0x7f,0x01,0x78,0x0c,0x00,0x00,0x1e,0x00,0x00,0x30,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x01,0x30,0x78,0x0c,0x00,0x00,0x1e,0x00,0x02,0x30,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x03,0x30,0x78,0x0c,0x00,0x00,0x1e,0x00,0x04,0x30,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x05,0x30,0x78,0x0c,0x00,0x00,0x1e,0x00,0x06,0x30,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x07,0x30,0x78,0x0c,0x00,0x00,0x1e,0x00,0x08,0x3e,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x09,0x40,0x78,0x0c,0x00,0x00,0x1e,0x00,0x0a,0x42,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x0b,0x44,0x78,0x0c,0x00,0x00,0x1e,0x00,0x0c,0x46,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x0d,0x48,0x78,0x0c,0x00,0x00,0x1e,0x00,0x0e,0x48,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x0f,0x4a,0x78,0x0c,0x00,0x00,0x1e,0x00,0x10,0x4a,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x11,0x4c,0x78,0x0c,0x00,0x00,0x1e,0x00,0x12,0x4c,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x13,0x4e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x14,0x50,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x15,0x50,0x78,0x0c,0x00,0x00,0x1e,0x00,0x16,0x50,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x17,0x52,0x78,0x0c,0x00,0x00,0x1e,0x00,0x18,0x52,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x19,0x52,0x78,0x0c,0x00,0x00,0x1e,0x00,0x1a,0x54,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x1b,0x54,0x78,0x0c,0x00,0x00,0x1e,0x00,0x1c,0x54,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x1d,0x56,0x78,0x0c,0x00,0x00,0x1e,0x00,0x1e,0x56,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x1f,0x56,0x78,0x0c,0x00,0x00,0x1e,0x00,0x20,0x56,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x21,0x58,0x78,0x0c,0x00,0x00,0x1e,0x00,0x22,0x58,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x23,0x58,0x78,0x0c,0x00,0x00,0x1e,0x00,0x24,0x58,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x25,0x5a,0x78,0x0c,0x00,0x00,0x1e,0x00,0x26,0x5a,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x27,0x5a,0x78,0x0c,0x00,0x00,0x1e,0x00,0x28,0x5c,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x29,0x5c,0x78,0x0c,0x00,0x00,0x1e,0x00,0x2a,0x5e,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x2b,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x2c,0x5e,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x2d,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x2e,0x5e,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x2f,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x30,0x5e,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x31,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x32,0x5e,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x33,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x34,0x5e,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x35,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x36,0x5e,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x37,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x38,0x5e,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x39,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x3a,0x5e,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x3b,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x3c,0x5e,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x3d,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x3e,0x5e,0x78,0x0c,0x00,0x00,
-0x1e,0x00,0x3f,0x5e,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x08,0x00,0x00,
-0x00,0x00,0x04,0x03,0x04,0x08,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x08,0x00,0x00,
-0x00,0xfc,0x00,0x00,0x0c,0x08,0x00,0x00,0x0a,0x00,0x00,0x04,0x10,0x08,0x00,0x00,
-0xff,0x10,0x10,0x80,0x14,0x08,0x00,0x00,0x10,0x3d,0x0c,0x02,0x18,0x08,0x00,0x00,
-0xc5,0x03,0x00,0x00,0x1c,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x08,0x00,0x00,
-0x04,0x00,0x00,0x00,0x24,0x08,0x00,0x00,0x00,0x02,0x69,0x00,0x28,0x08,0x00,0x00,
-0x04,0x00,0x00,0x00,0x2c,0x08,0x00,0x00,0x00,0x02,0x69,0x00,0x30,0x08,0x00,0x00,
-0x04,0x00,0x00,0x00,0x34,0x08,0x00,0x00,0x00,0x02,0x69,0x00,0x38,0x08,0x00,0x00,
-0x04,0x00,0x00,0x00,0x3c,0x08,0x00,0x00,0x00,0x02,0x69,0x00,0x40,0x08,0x00,0x00,
-0x00,0x00,0x00,0x00,0x44,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x00,0x00,
-0x00,0x00,0x00,0x00,0x4c,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x08,0x00,0x00,
-0x00,0x00,0x00,0x00,0x54,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x08,0x00,0x00,
-0x65,0xa9,0x65,0xa9,0x5c,0x08,0x00,0x00,0x65,0xa9,0x65,0xa9,0x60,0x08,0x00,0x00,
-0x30,0x01,0x7f,0x0f,0x64,0x08,0x00,0x00,0x30,0x01,0x7f,0x0f,0x68,0x08,0x00,0x00,
-0x30,0x01,0x7f,0x0f,0x6c,0x08,0x00,0x00,0x30,0x01,0x7f,0x0f,0x70,0x08,0x00,0x00,
-0x00,0x03,0x00,0x03,0x74,0x08,0x00,0x00,0x00,0x03,0x00,0x03,0x78,0x08,0x00,0x00,
-0x00,0x00,0x00,0x00,0x7c,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x08,0x00,0x00,
-0x00,0x00,0x00,0x00,0x94,0x08,0x00,0x00,0xfe,0xff,0xff,0xff,0x98,0x08,0x00,0x00,
-0x10,0x20,0x30,0x40,0x9c,0x08,0x00,0x00,0x50,0x60,0x70,0x00,0xb0,0x08,0x00,0x00,
-0x00,0x00,0x00,0x00,0xe0,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0x08,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x03,0x03,0x03,0x03,0x04,0x0e,0x00,0x00,
-0x03,0x03,0x03,0x03,0x08,0x0e,0x00,0x00,0x03,0x03,0x00,0x00,0x0c,0x0e,0x00,0x00,
-0x00,0x00,0x00,0x00,0x10,0x0e,0x00,0x00,0x03,0x03,0x03,0x03,0x14,0x0e,0x00,0x00,
-0x03,0x03,0x03,0x03,0x18,0x0e,0x00,0x00,0x03,0x03,0x03,0x03,0x1c,0x0e,0x00,0x00,
-0x03,0x03,0x03,0x03,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x09,0x00,0x00,
-0x23,0x00,0x00,0x00,0x08,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x09,0x00,0x00,
-0x33,0x13,0x32,0x03,0x08,0x0a,0x00,0x00,0x00,0x86,0x88,0x8f,0x2c,0x0a,0x00,0x00,
-0x00,0x00,0x92,0x00,0x00,0x0c,0x00,0x00,0x80,0x00,0x00,0x00,0x04,0x0c,0x00,0x00,
-0x33,0x54,0x00,0x00,0x08,0x0c,0x00,0x00,0xe4,0x00,0x00,0x00,0x0c,0x0c,0x00,0x00,
-0x6c,0x6c,0x6c,0x6c,0x10,0x0c,0x00,0x00,0x00,0x00,0x00,0x08,0x14,0x0c,0x00,0x00,
-0x00,0x01,0x00,0x40,0x18,0x0c,0x00,0x00,0x00,0x00,0x00,0x08,0x1c,0x0c,0x00,0x00,
-0x00,0x01,0x00,0x40,0x20,0x0c,0x00,0x00,0x00,0x00,0x00,0x08,0x24,0x0c,0x00,0x00,
-0x00,0x01,0x00,0x40,0x28,0x0c,0x00,0x00,0x00,0x00,0x00,0x08,0x2c,0x0c,0x00,0x00,
-0x00,0x01,0x00,0x40,0x30,0x0c,0x00,0x00,0x44,0x6a,0xe9,0x8d,0x34,0x0c,0x00,0x00,
-0xcd,0x52,0x96,0x46,0x38,0x0c,0x00,0x00,0x90,0x5a,0x01,0x48,0x3c,0x0c,0x00,0x00,
-0x64,0x97,0x97,0x1a,0x40,0x0c,0x00,0x00,0x3f,0x42,0x7c,0x1f,0x44,0x0c,0x00,0x00,
-0xb7,0x00,0x01,0x00,0x48,0x0c,0x00,0x00,0x00,0x00,0x02,0xec,0x4c,0x0c,0x00,0x00,
-0x03,0x03,0xfc,0x00,0x50,0x0c,0x00,0x00,0x1c,0x34,0x54,0x69,0x54,0x0c,0x00,0x00,
-0x94,0x00,0x3c,0x43,0x58,0x0c,0x00,0x00,0x1c,0x34,0x54,0x69,0x5c,0x0c,0x00,0x00,
-0x94,0x00,0x3c,0x43,0x60,0x0c,0x00,0x00,0x1c,0x34,0x54,0x69,0x64,0x0c,0x00,0x00,
-0x94,0x00,0x3c,0x43,0x68,0x0c,0x00,0x00,0x1c,0x34,0x54,0x69,0x6c,0x0c,0x00,0x00,
-0x94,0x00,0x3c,0x43,0x70,0x0c,0x00,0x00,0x0d,0x00,0x5a,0x2c,0x74,0x0c,0x00,0x00,
-0x1b,0x15,0x86,0x01,0x78,0x0c,0x00,0x00,0x1f,0x00,0x00,0x00,0x7c,0x0c,0x00,0x00,
-0x12,0x16,0xb9,0x00,0x80,0x0c,0x00,0x00,0x80,0x00,0x00,0x20,0x84,0x0c,0x00,0x00,
-0x00,0x00,0x00,0x00,0x88,0x0c,0x00,0x00,0x80,0x00,0x00,0x20,0x8c,0x0c,0x00,0x00,
-0x00,0x00,0x20,0x08,0x90,0x0c,0x00,0x00,0x00,0x01,0x00,0x40,0x94,0x0c,0x00,0x00,
-0x00,0x00,0x00,0x00,0x98,0x0c,0x00,0x00,0x00,0x01,0x00,0x40,0x9c,0x0c,0x00,0x00,
-0x00,0x00,0x00,0x00,0xa0,0x0c,0x00,0x00,0x92,0x24,0x49,0x00,0xa4,0x0c,0x00,0x00,
-0x00,0x00,0x00,0x00,0xa8,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x0c,0x00,0x00,
-0x00,0x00,0x00,0x00,0xb0,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xb4,0x0c,0x00,0x00,
-0x00,0x00,0x00,0x00,0xb8,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xbc,0x0c,0x00,0x00,
-0x92,0x24,0x49,0x00,0xc0,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xc4,0x0c,0x00,0x00,
-0x00,0x00,0x00,0x00,0xc8,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xcc,0x0c,0x00,0x00,
-0x00,0x00,0x00,0x00,0xd0,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xd4,0x0c,0x00,0x00,
-0x00,0x00,0x00,0x00,0xd8,0x0c,0x00,0x00,0x27,0x24,0xb2,0x64,0xdc,0x0c,0x00,0x00,
-0x32,0x69,0x76,0x00,0xe0,0x0c,0x00,0x00,0x22,0x22,0x22,0x00,0xe4,0x0c,0x00,0x00,
-0x00,0x00,0x00,0x00,0xe8,0x0c,0x00,0x00,0x02,0x43,0x64,0x07,0x00,0x0d,0x00,0x00,
-0x80,0x07,0x00,0x00,0x04,0x0d,0x00,0x00,0x03,0x04,0x00,0x00,0x08,0x0d,0x00,0x00,
-0x7f,0x90,0x00,0x00,0x0c,0x0d,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x0d,0x00,0x00,
-0x99,0x99,0x69,0xa0,0x14,0x0d,0x00,0x00,0x67,0x3c,0x99,0x99,0x18,0x0d,0x00,0x00,
-0x6b,0x5b,0x8f,0x6a,0x1c,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x0d,0x00,0x00,
-0x00,0x00,0x00,0x00,0x24,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x0d,0x00,0x00,
-0x00,0x00,0x00,0x00,0x2c,0x0d,0x00,0x00,0x75,0x19,0x97,0xcc,0x30,0x0d,0x00,0x00,
-0x00,0x00,0x00,0x00,0x34,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x0d,0x00,0x00,
-0x00,0x00,0x00,0x00,0x3c,0x0d,0x00,0x00,0x93,0x72,0x02,0x00,0x40,0x0d,0x00,0x00,
-0x00,0x00,0x00,0x00,0x44,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x0d,0x00,0x00,
-0x00,0x00,0x00,0x00,0x50,0x0d,0x00,0x00,0x0a,0x14,0x37,0x64,0x54,0x0d,0x00,0x00,
-0x02,0xbd,0x4d,0x02,0x58,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x0d,0x00,0x00,
-0x64,0x20,0x03,0x30,0x60,0x0d,0x00,0x00,0x68,0xde,0x53,0x46,0x64,0x0d,0x00,0x00,
-0x3c,0x8a,0x51,0x00,0x68,0x0d,0x00,0x00,0x06,0x01,0x00,0x00,0xff,0x00,0x00,0x00,
-0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
-0x44,0x05,0x01,0x80,0x10,0x00,0x00,0x00,0x74,0x05,0x01,0x80,0x10,0x00,0x00,0x00,
-0xe0,0x2e,0x00,0x80,0x10,0x00,0x00,0x00,0xec,0x2e,0x00,0x80,0x10,0x00,0x00,0x00,
-0xa0,0x08,0x01,0x80,0x08,0x00,0x00,0x00,0x38,0x06,0x01,0x80,0x00,0xb7,0x00,0x00,
-0x01,0xe0,0x0e,0x00,0x02,0x4d,0x04,0x00,0x03,0x41,0x04,0x00,0x04,0xc3,0x08,0x00,
-0x05,0x72,0x0c,0x00,0x06,0xe6,0x00,0x00,0x07,0x2a,0x08,0x00,0x08,0x3f,0x00,0x00,
-0x09,0x35,0x03,0x00,0x0a,0xd4,0x09,0x00,0x0b,0xbb,0x07,0x00,0x0c,0x50,0x08,0x00,
-0x0d,0xdf,0x0c,0x00,0x0e,0x2b,0x00,0x00,0x0f,0x14,0x01,0x00,0x00,0xb7,0x01,0x00,
-0x01,0x01,0x00,0x00,0x02,0x00,0x04,0x00,0x01,0x02,0x00,0x00,0x02,0x01,0x04,0x00,
-0x01,0x03,0x00,0x00,0x02,0x02,0x04,0x00,0x01,0x04,0x00,0x00,0x02,0x03,0x04,0x00,
-0x01,0x05,0x00,0x00,0x02,0x04,0x04,0x00,0x01,0x06,0x00,0x00,0x02,0x05,0x04,0x00,
-0x01,0x07,0x00,0x00,0x02,0x08,0x04,0x00,0x01,0x08,0x00,0x00,0x02,0x09,0x04,0x00,
-0x01,0x09,0x00,0x00,0x02,0x0a,0x04,0x00,0x01,0x0a,0x00,0x00,0x02,0x0b,0x04,0x00,
-0x01,0x0b,0x00,0x00,0x02,0x02,0x05,0x00,0x01,0x0c,0x00,0x00,0x02,0x03,0x05,0x00,
-0x01,0x0d,0x00,0x00,0x02,0x04,0x05,0x00,0x01,0x0e,0x00,0x00,0x02,0x05,0x05,0x00,
-0x01,0x0f,0x00,0x00,0x02,0x40,0x05,0x00,0x01,0x10,0x00,0x00,0x02,0x41,0x05,0x00,
-0x01,0x11,0x00,0x00,0x02,0x42,0x05,0x00,0x01,0x12,0x00,0x00,0x02,0x43,0x05,0x00,
-0x01,0x13,0x00,0x00,0x02,0x44,0x05,0x00,0x01,0x14,0x00,0x00,0x02,0x45,0x05,0x00,
-0x01,0x15,0x00,0x00,0x02,0x80,0x05,0x00,0x01,0x16,0x00,0x00,0x02,0x81,0x05,0x00,
-0x01,0x17,0x00,0x00,0x02,0x82,0x05,0x00,0x01,0x18,0x00,0x00,0x02,0x83,0x05,0x00,
-0x01,0x19,0x00,0x00,0x02,0x84,0x05,0x00,0x01,0x1a,0x00,0x00,0x02,0x85,0x05,0x00,
-0x01,0x1b,0x00,0x00,0x02,0x88,0x05,0x00,0x01,0x1c,0x00,0x00,0x02,0x89,0x05,0x00,
-0x01,0x1d,0x00,0x00,0x02,0x8a,0x05,0x00,0x01,0x1e,0x00,0x00,0x02,0x8b,0x05,0x00,
-0x01,0x1f,0x00,0x00,0x02,0x43,0x06,0x00,0x01,0x20,0x00,0x00,0x02,0x44,0x06,0x00,
-0x01,0x21,0x00,0x00,0x02,0x45,0x06,0x00,0x01,0x22,0x00,0x00,0x02,0x80,0x06,0x00,
-0x01,0x23,0x00,0x00,0x02,0x81,0x06,0x00,0x01,0x24,0x00,0x00,0x02,0x82,0x06,0x00,
-0x01,0x25,0x00,0x00,0x02,0x83,0x06,0x00,0x01,0x26,0x00,0x00,0x02,0x84,0x06,0x00,
-0x01,0x27,0x00,0x00,0x02,0x85,0x06,0x00,0x01,0x28,0x00,0x00,0x02,0x88,0x06,0x00,
-0x01,0x29,0x00,0x00,0x02,0x89,0x06,0x00,0x01,0x2a,0x00,0x00,0x02,0x8a,0x06,0x00,
-0x01,0x2b,0x00,0x00,0x02,0x8b,0x06,0x00,0x01,0x2c,0x00,0x00,0x02,0x8c,0x06,0x00,
-0x01,0x2d,0x00,0x00,0x02,0x42,0x07,0x00,0x01,0x2e,0x00,0x00,0x02,0x43,0x07,0x00,
-0x01,0x2f,0x00,0x00,0x02,0x44,0x07,0x00,0x01,0x30,0x00,0x00,0x02,0x45,0x07,0x00,
-0x01,0x31,0x00,0x00,0x02,0x80,0x07,0x00,0x01,0x32,0x00,0x00,0x02,0x81,0x07,0x00,
-0x01,0x33,0x00,0x00,0x02,0x82,0x07,0x00,0x01,0x34,0x00,0x00,0x02,0x83,0x07,0x00,
-0x01,0x35,0x00,0x00,0x02,0x84,0x07,0x00,0x01,0x36,0x00,0x00,0x02,0x85,0x07,0x00,
-0x01,0x37,0x00,0x00,0x02,0x88,0x07,0x00,0x01,0x38,0x00,0x00,0x02,0x89,0x07,0x00,
-0x01,0x39,0x00,0x00,0x02,0x8a,0x07,0x00,0x01,0x3a,0x00,0x00,0x02,0x8b,0x07,0x00,
-0x01,0x3b,0x00,0x00,0x02,0x8c,0x07,0x00,0x01,0x3c,0x00,0x00,0x02,0x8d,0x07,0x00,
-0x01,0x3d,0x00,0x00,0x02,0x90,0x07,0x00,0x01,0x3e,0x00,0x00,0x02,0x91,0x07,0x00,
-0x01,0x3f,0x00,0x00,0x02,0x92,0x07,0x00,0x01,0x40,0x00,0x00,0x02,0x93,0x07,0x00,
-0x01,0x41,0x00,0x00,0x02,0x94,0x07,0x00,0x01,0x42,0x00,0x00,0x02,0x95,0x07,0x00,
-0x01,0x43,0x00,0x00,0x02,0x98,0x07,0x00,0x01,0x44,0x00,0x00,0x02,0x99,0x07,0x00,
-0x01,0x45,0x00,0x00,0x02,0x9a,0x07,0x00,0x01,0x46,0x00,0x00,0x02,0x9b,0x07,0x00,
-0x01,0x47,0x00,0x00,0x02,0x9c,0x07,0x00,0x01,0x48,0x00,0x00,0x02,0x9d,0x07,0x00,
-0x01,0x49,0x00,0x00,0x02,0xa0,0x07,0x00,0x01,0x4a,0x00,0x00,0x02,0xa1,0x07,0x00,
-0x01,0x4b,0x00,0x00,0x02,0xa2,0x07,0x00,0x01,0x4c,0x00,0x00,0x02,0xa3,0x07,0x00,
-0x01,0x4d,0x00,0x00,0x02,0xa4,0x07,0x00,0x01,0x4e,0x00,0x00,0x02,0xa5,0x07,0x00,
-0x01,0x4f,0x00,0x00,0x02,0xa8,0x07,0x00,0x01,0x50,0x00,0x00,0x02,0xa9,0x07,0x00,
-0x01,0x51,0x00,0x00,0x02,0xaa,0x03,0x00,0x01,0x52,0x00,0x00,0x02,0xab,0x03,0x00,
-0x01,0x53,0x00,0x00,0x02,0xac,0x03,0x00,0x01,0x54,0x00,0x00,0x02,0xad,0x03,0x00,
-0x01,0x55,0x00,0x00,0x02,0xb0,0x03,0x00,0x01,0x56,0x00,0x00,0x02,0xb1,0x03,0x00,
-0x01,0x57,0x00,0x00,0x02,0xb2,0x03,0x00,0x01,0x58,0x00,0x00,0x02,0xb3,0x03,0x00,
-0x01,0x59,0x00,0x00,0x02,0xb4,0x03,0x00,0x01,0x5a,0x00,0x00,0x02,0xb5,0x03,0x00,
-0x01,0x5b,0x00,0x00,0x02,0xb8,0x03,0x00,0x01,0x5c,0x00,0x00,0x02,0xb9,0x03,0x00,
-0x01,0x5d,0x00,0x00,0x02,0xba,0x03,0x00,0x01,0x5e,0x00,0x00,0x02,0xbb,0x03,0x00,
-0x01,0x5f,0x00,0x00,0x02,0xbb,0x03,0x00,0x03,0x80,0x00,0x00,0x05,0x04,0x00,0x00,
-0x00,0xb7,0x00,0x00,0xfe,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,
-0x02,0x4d,0x0c,0x00,0xfe,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x02,0x4d,0x04,0x00,
-0x00,0xbf,0x02,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0xb7,0x00,0x00,
-0x01,0xe0,0x0e,0x00,0x02,0x4d,0x04,0x00,0x03,0x41,0x04,0x00,0x04,0xc3,0x08,0x00,
-0x05,0x72,0x0c,0x00,0x06,0xe6,0x00,0x00,0x07,0x2a,0x08,0x00,0x08,0x3f,0x00,0x00,
-0x09,0x35,0x03,0x00,0x0a,0xd4,0x09,0x00,0x0b,0xbb,0x07,0x00,0x0c,0x50,0x08,0x00,
-0x0d,0xdf,0x0c,0x00,0x0e,0x2b,0x00,0x00,0x0f,0x14,0x01,0x00,0x00,0xb7,0x01,0x00,
-0x01,0x01,0x00,0x00,0x02,0x00,0x04,0x00,0x01,0x02,0x00,0x00,0x02,0x01,0x04,0x00,
-0x01,0x03,0x00,0x00,0x02,0x02,0x04,0x00,0x01,0x04,0x00,0x00,0x02,0x03,0x04,0x00,
-0x01,0x05,0x00,0x00,0x02,0x04,0x04,0x00,0x01,0x06,0x00,0x00,0x02,0x05,0x04,0x00,
-0x01,0x07,0x00,0x00,0x02,0x08,0x04,0x00,0x01,0x08,0x00,0x00,0x02,0x09,0x04,0x00,
-0x01,0x09,0x00,0x00,0x02,0x0a,0x04,0x00,0x01,0x0a,0x00,0x00,0x02,0x0b,0x04,0x00,
-0x01,0x0b,0x00,0x00,0x02,0x02,0x05,0x00,0x01,0x0c,0x00,0x00,0x02,0x03,0x05,0x00,
-0x01,0x0d,0x00,0x00,0x02,0x04,0x05,0x00,0x01,0x0e,0x00,0x00,0x02,0x05,0x05,0x00,
-0x01,0x0f,0x00,0x00,0x02,0x40,0x05,0x00,0x01,0x10,0x00,0x00,0x02,0x41,0x05,0x00,
-0x01,0x11,0x00,0x00,0x02,0x42,0x05,0x00,0x01,0x12,0x00,0x00,0x02,0x43,0x05,0x00,
-0x01,0x13,0x00,0x00,0x02,0x44,0x05,0x00,0x01,0x14,0x00,0x00,0x02,0x45,0x05,0x00,
-0x01,0x15,0x00,0x00,0x02,0x80,0x05,0x00,0x01,0x16,0x00,0x00,0x02,0x81,0x05,0x00,
-0x01,0x17,0x00,0x00,0x02,0x82,0x05,0x00,0x01,0x18,0x00,0x00,0x02,0x83,0x05,0x00,
-0x01,0x19,0x00,0x00,0x02,0x84,0x05,0x00,0x01,0x1a,0x00,0x00,0x02,0x85,0x05,0x00,
-0x01,0x1b,0x00,0x00,0x02,0x88,0x05,0x00,0x01,0x1c,0x00,0x00,0x02,0x89,0x05,0x00,
-0x01,0x1d,0x00,0x00,0x02,0x8a,0x05,0x00,0x01,0x1e,0x00,0x00,0x02,0x8b,0x05,0x00,
-0x01,0x1f,0x00,0x00,0x02,0x43,0x06,0x00,0x01,0x20,0x00,0x00,0x02,0x44,0x06,0x00,
-0x01,0x21,0x00,0x00,0x02,0x45,0x06,0x00,0x01,0x22,0x00,0x00,0x02,0x80,0x06,0x00,
-0x01,0x23,0x00,0x00,0x02,0x81,0x06,0x00,0x01,0x24,0x00,0x00,0x02,0x82,0x06,0x00,
-0x01,0x25,0x00,0x00,0x02,0x83,0x06,0x00,0x01,0x26,0x00,0x00,0x02,0x84,0x06,0x00,
-0x01,0x27,0x00,0x00,0x02,0x85,0x06,0x00,0x01,0x28,0x00,0x00,0x02,0x88,0x06,0x00,
-0x01,0x29,0x00,0x00,0x02,0x89,0x06,0x00,0x01,0x2a,0x00,0x00,0x02,0x8a,0x06,0x00,
-0x01,0x2b,0x00,0x00,0x02,0x8b,0x06,0x00,0x01,0x2c,0x00,0x00,0x02,0x8c,0x06,0x00,
-0x01,0x2d,0x00,0x00,0x02,0x42,0x07,0x00,0x01,0x2e,0x00,0x00,0x02,0x43,0x07,0x00,
-0x01,0x2f,0x00,0x00,0x02,0x44,0x07,0x00,0x01,0x30,0x00,0x00,0x02,0x45,0x07,0x00,
-0x01,0x31,0x00,0x00,0x02,0x80,0x07,0x00,0x01,0x32,0x00,0x00,0x02,0x81,0x07,0x00,
-0x01,0x33,0x00,0x00,0x02,0x82,0x07,0x00,0x01,0x34,0x00,0x00,0x02,0x83,0x07,0x00,
-0x01,0x35,0x00,0x00,0x02,0x84,0x07,0x00,0x01,0x36,0x00,0x00,0x02,0x85,0x07,0x00,
-0x01,0x37,0x00,0x00,0x02,0x88,0x07,0x00,0x01,0x38,0x00,0x00,0x02,0x89,0x07,0x00,
-0x01,0x39,0x00,0x00,0x02,0x8a,0x07,0x00,0x01,0x3a,0x00,0x00,0x02,0x8b,0x07,0x00,
-0x01,0x3b,0x00,0x00,0x02,0x8c,0x07,0x00,0x01,0x3c,0x00,0x00,0x02,0x8d,0x07,0x00,
-0x01,0x3d,0x00,0x00,0x02,0x90,0x07,0x00,0x01,0x3e,0x00,0x00,0x02,0x91,0x07,0x00,
-0x01,0x3f,0x00,0x00,0x02,0x92,0x07,0x00,0x01,0x40,0x00,0x00,0x02,0x93,0x07,0x00,
-0x01,0x41,0x00,0x00,0x02,0x94,0x07,0x00,0x01,0x42,0x00,0x00,0x02,0x95,0x07,0x00,
-0x01,0x43,0x00,0x00,0x02,0x98,0x07,0x00,0x01,0x44,0x00,0x00,0x02,0x99,0x07,0x00,
-0x01,0x45,0x00,0x00,0x02,0x9a,0x07,0x00,0x01,0x46,0x00,0x00,0x02,0x9b,0x07,0x00,
-0x01,0x47,0x00,0x00,0x02,0x9c,0x07,0x00,0x01,0x48,0x00,0x00,0x02,0x9d,0x07,0x00,
-0x01,0x49,0x00,0x00,0x02,0xa0,0x07,0x00,0x01,0x4a,0x00,0x00,0x02,0xa1,0x07,0x00,
-0x01,0x4b,0x00,0x00,0x02,0xa2,0x07,0x00,0x01,0x4c,0x00,0x00,0x02,0xa3,0x07,0x00,
-0x01,0x4d,0x00,0x00,0x02,0xa4,0x07,0x00,0x01,0x4e,0x00,0x00,0x02,0xa5,0x07,0x00,
-0x01,0x4f,0x00,0x00,0x02,0xa8,0x07,0x00,0x01,0x50,0x00,0x00,0x02,0xa9,0x07,0x00,
-0x01,0x51,0x00,0x00,0x02,0xaa,0x03,0x00,0x01,0x52,0x00,0x00,0x02,0xab,0x03,0x00,
-0x01,0x53,0x00,0x00,0x02,0xac,0x03,0x00,0x01,0x54,0x00,0x00,0x02,0xad,0x03,0x00,
-0x01,0x55,0x00,0x00,0x02,0xb0,0x03,0x00,0x01,0x56,0x00,0x00,0x02,0xb1,0x03,0x00,
-0x01,0x57,0x00,0x00,0x02,0xb2,0x03,0x00,0x01,0x58,0x00,0x00,0x02,0xb3,0x03,0x00,
-0x01,0x59,0x00,0x00,0x02,0xb4,0x03,0x00,0x01,0x5a,0x00,0x00,0x02,0xb5,0x03,0x00,
-0x01,0x5b,0x00,0x00,0x02,0xb8,0x03,0x00,0x01,0x5c,0x00,0x00,0x02,0xb9,0x03,0x00,
-0x01,0x5d,0x00,0x00,0x02,0xba,0x03,0x00,0x01,0x5e,0x00,0x00,0x02,0xbb,0x03,0x00,
-0x01,0x5f,0x00,0x00,0x02,0xbb,0x03,0x00,0x03,0x80,0x00,0x00,0x05,0x04,0x00,0x00,
-0x00,0xb7,0x00,0x00,0xfe,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,
-0x02,0x4d,0x0c,0x00,0xfe,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x02,0x4d,0x04,0x00,
-0x00,0xbf,0x02,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x0a,0x00,0x00,0x00,
-0x4f,0x6e,0x41,0x73,0x73,0x6f,0x63,0x52,0x65,0x71,0x00,0x00,0x4f,0x6e,0x41,0x73,
-0x73,0x6f,0x63,0x52,0x73,0x70,0x00,0x00,0x4f,0x6e,0x52,0x65,0x41,0x73,0x73,0x6f,
-0x63,0x52,0x65,0x71,0x00,0x00,0x00,0x00,0x4f,0x6e,0x52,0x65,0x41,0x73,0x73,0x6f,
-0x63,0x52,0x73,0x70,0x00,0x00,0x00,0x00,0x4f,0x6e,0x50,0x72,0x6f,0x62,0x65,0x52,
-0x65,0x71,0x00,0x00,0x4f,0x6e,0x50,0x72,0x6f,0x62,0x65,0x52,0x73,0x70,0x00,0x00,
-0x44,0x6f,0x52,0x65,0x73,0x65,0x72,0x76,0x65,0x64,0x00,0x00,0x44,0x6f,0x52,0x65,
-0x73,0x65,0x72,0x76,0x65,0x64,0x00,0x00,0x4f,0x6e,0x42,0x65,0x61,0x63,0x6f,0x6e,
-0x00,0x00,0x00,0x00,0x4f,0x6e,0x41,0x54,0x49,0x4d,0x00,0x00,0x4f,0x6e,0x44,0x69,
-0x73,0x61,0x73,0x73,0x6f,0x63,0x00,0x00,0x4f,0x6e,0x41,0x75,0x74,0x68,0x00,0x00,
-0x4f,0x6e,0x44,0x65,0x41,0x75,0x74,0x68,0x00,0x00,0x00,0x00,0x4f,0x6e,0x41,0x63,
-0x74,0x69,0x6f,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x8b,0x01,0x80,
-0x28,0x14,0x01,0x80,0x10,0x00,0x00,0x00,0x94,0x8b,0x01,0x80,0x30,0x14,0x01,0x80,
-0x20,0x00,0x00,0x00,0xa0,0x8b,0x01,0x80,0x28,0x14,0x01,0x80,0x30,0x00,0x00,0x00,
-0xb0,0x8b,0x01,0x80,0x30,0x14,0x01,0x80,0x40,0x00,0x00,0x00,0xc0,0x8b,0x01,0x80,
-0x38,0x14,0x01,0x80,0x50,0x00,0x00,0x00,0xcc,0x8b,0x01,0x80,0x40,0x14,0x01,0x80,
-0x00,0x00,0x00,0x00,0xd8,0x8b,0x01,0x80,0xa8,0x14,0x01,0x80,0x00,0x00,0x00,0x00,
-0xe4,0x8b,0x01,0x80,0xa8,0x14,0x01,0x80,0x80,0x00,0x00,0x00,0xf0,0x8b,0x01,0x80,
-0x48,0x14,0x01,0x80,0x90,0x00,0x00,0x00,0xfc,0x8b,0x01,0x80,0x50,0x14,0x01,0x80,
-0xa0,0x00,0x00,0x00,0x04,0x8c,0x01,0x80,0x58,0x14,0x01,0x80,0xb0,0x00,0x00,0x00,
-0x10,0x8c,0x01,0x80,0x90,0x14,0x01,0x80,0xc0,0x00,0x00,0x00,0x18,0x8c,0x01,0x80,
-0x98,0x14,0x01,0x80,0xd0,0x00,0x00,0x00,0x24,0x8c,0x01,0x80,0xa0,0x14,0x01,0x80,
-0x00,0x00,0x00,0x00,0xdc,0x8c,0x01,0x80,0xdc,0x8c,0x01,0x80,0x31,0x10,0x10,0x00,
-0x00,0x30,0x00,0x00,0x31,0x20,0x10,0x00,0x00,0x30,0x00,0x00,0x31,0x28,0x10,0x00,
-0x00,0x30,0x00,0x00,0x31,0x2c,0x10,0x10,0x00,0x30,0x00,0x00,0x31,0x2f,0x10,0x10,
-0x00,0x30,0x00,0x00,0x31,0x30,0x18,0x00,0x00,0x30,0x00,0x00,0x31,0x30,0x20,0x10,
-0x00,0x30,0x00,0x00,0x22,0x20,0x18,0x08,0x00,0x20,0x00,0x00,0x22,0x21,0x14,0x08,
-0x00,0x20,0x00,0x00,0x22,0x21,0x1c,0x08,0x00,0x20,0x00,0x00,0x22,0x21,0x20,0x08,
-0x00,0x20,0x00,0x00,0x22,0x21,0x20,0x10,0x00,0x20,0x00,0x00,0x22,0x21,0x20,0x18,
-0x00,0x20,0x00,0x00,0x1a,0x19,0x18,0x10,0x00,0x18,0x00,0x00,0x12,0x11,0x10,0x08,
-0x00,0x10,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x08,0x00,0x00,0x0a,0x09,0x08,0x02,
-0x00,0x08,0x00,0x00,0x0a,0x09,0x08,0x04,0x00,0x08,0x00,0x00,0x0a,0x09,0x08,0x06,
-0x00,0x08,0x00,0x00,0x08,0x07,0x06,0x04,0x00,0x06,0x00,0x00,0x06,0x05,0x04,0x02,
-0x00,0x04,0x00,0x00,0x06,0x05,0x04,0x03,0x00,0x04,0x00,0x00,0x05,0x04,0x03,0x02,
-0x00,0x03,0x00,0x00,0x09,0x08,0x07,0x06,0x07,0x06,0x06,0x05,0x05,0x04,0x04,0x03,
-0x06,0x05,0x05,0x04,0x04,0x03,0x03,0x03,0x05,0x04,0x04,0x03,0x03,0x02,0x02,0x02,
-0x00,0x09,0x08,0x07,0x06,0x07,0x06,0x06,0x05,0x05,0x04,0x04,0x03,0x05,0x04,0x04,
-0x03,0x03,0x02,0x02,0x02,0x04,0x03,0x03,0x02,0x02,0x01,0x01,0x01,0x00,0x00,0x00,
-0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x08,0x08,0x08,0x08,
-0x20,0x20,0x20,0x20,0x08,0x08,0x08,0x08,0x08,0x20,0x20,0x20,0x30,0x08,0x08,0x08,
-0x08,0x18,0x18,0x18,0x18,0x18,0x20,0x30,0x30,0x10,0x20,0x20,0x20,0x20,0x20,0x30,
-0x30,0x08,0x10,0x20,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x08,0x08,0x08,0x08,
-0x08,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x08,0x08,0x08,0x08,0x08,0x20,0x20,0x20,
-0x08,0x08,0x08,0x08,0x08,0x20,0x20,0x20,0x20,0x08,0x08,0x08,0x08,0x18,0x18,0x18,
-0x18,0x18,0x20,0x30,0x30,0x10,0x20,0x20,0x20,0x20,0x20,0x30,0x30,0x08,0x10,0x20,
-0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,
-0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x00,
-0x00,0x0a,0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,
-0x0a,0x09,0x08,0x00,0x00,0x12,0x11,0x10,0x08,0x00,0x12,0x11,0x10,0x08,0x00,0x22,
-0x21,0x20,0x18,0x00,0x0a,0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x0a,0x09,
-0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x22,0x21,0x20,0x18,0x00,0x22,0x21,0x20,
-0x18,0x00,0x22,0x21,0x1c,0x08,0x00,0x22,0x20,0x18,0x08,0x00,0x0a,0x09,0x08,0x02,
-0x00,0x0a,0x09,0x08,0x02,0x00,0x0a,0x09,0x08,0x02,0x00,0x0a,0x09,0x08,0x02,0x00,
-0x0a,0x09,0x08,0x00,0x00,0x22,0x21,0x20,0x10,0x00,0x22,0x21,0x20,0x08,0x00,0x22,
-0x21,0x1c,0x08,0x00,0x31,0x30,0x18,0x00,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,
-0x08,0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x1a,0x19,0x18,
-0x10,0x00,0x1a,0x19,0x18,0x10,0x00,0x1a,0x19,0x18,0x10,0x00,0x1a,0x19,0x18,0x10,
-0x00,0x1a,0x19,0x18,0x10,0x00,0x22,0x21,0x20,0x08,0x00,0x31,0x2c,0x10,0x10,0x00,
-0x31,0x28,0x10,0x00,0x00,0x12,0x11,0x10,0x08,0x00,0x22,0x21,0x20,0x18,0x00,0x22,
-0x21,0x20,0x18,0x00,0x22,0x21,0x20,0x08,0x00,0x22,0x21,0x14,0x08,0x00,0x22,0x20,
-0x18,0x08,0x00,0x31,0x30,0x20,0x10,0x00,0x31,0x2c,0x10,0x10,0x00,0x0a,0x09,0x08,
-0x00,0x00,0x12,0x11,0x10,0x08,0x00,0x22,0x21,0x20,0x18,0x00,0x22,0x21,0x20,0x18,
-0x00,0x31,0x30,0x20,0x10,0x00,0x31,0x2f,0x10,0x10,0x00,0x31,0x2f,0x10,0x10,0x00,
-0x31,0x10,0x10,0x00,0x00,0x31,0x2c,0x10,0x10,0x00,0x00,0x00,0x0a,0x09,0x08,0x04,
-0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x04,0x00,
-0x0a,0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x0a,
-0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x12,0x11,0x10,0x08,0x00,0x12,0x11,
-0x10,0x08,0x00,0x22,0x21,0x20,0x18,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,
-0x04,0x00,0x0a,0x09,0x08,0x02,0x00,0x0a,0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00,
-0x00,0x22,0x21,0x20,0x18,0x00,0x22,0x21,0x1c,0x08,0x00,0x22,0x21,0x14,0x08,0x00,
-0x0a,0x09,0x08,0x02,0x00,0x0a,0x09,0x08,0x02,0x00,0x0a,0x09,0x08,0x02,0x00,0x0a,
-0x09,0x08,0x02,0x00,0x0a,0x09,0x08,0x00,0x00,0x22,0x21,0x20,0x10,0x00,0x22,0x21,
-0x20,0x08,0x00,0x22,0x21,0x14,0x08,0x00,0x22,0x21,0x14,0x08,0x00,0x0a,0x09,0x08,
-0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x04,
-0x00,0x1a,0x19,0x18,0x10,0x00,0x1a,0x19,0x18,0x10,0x00,0x1a,0x19,0x18,0x10,0x00,
-0x1a,0x19,0x18,0x10,0x00,0x1a,0x19,0x18,0x10,0x00,0x22,0x21,0x20,0x08,0x00,0x31,
-0x2c,0x10,0x10,0x00,0x31,0x28,0x10,0x00,0x00,0x12,0x11,0x10,0x08,0x00,0x22,0x21,
-0x20,0x18,0x00,0x22,0x21,0x20,0x18,0x00,0x22,0x21,0x20,0x08,0x00,0x22,0x21,0x14,
-0x08,0x00,0x22,0x20,0x18,0x08,0x00,0x31,0x30,0x20,0x10,0x00,0x31,0x2c,0x10,0x10,
-0x00,0x0a,0x09,0x08,0x00,0x00,0x12,0x11,0x10,0x08,0x00,0x22,0x21,0x20,0x18,0x00,
-0x22,0x21,0x20,0x18,0x00,0x31,0x30,0x20,0x10,0x00,0x31,0x2f,0x10,0x10,0x00,0x31,
-0x2f,0x10,0x10,0x00,0x31,0x10,0x10,0x00,0x00,0x31,0x2c,0x10,0x10,0x00,0x00,0x00,
-0x01,0x02,0x04,0x08,0x02,0x04,0x08,0x0c,0x10,0x18,0x20,0x30,0x02,0x04,0x08,0x0c,
-0x10,0x18,0x20,0x30,0x06,0x0c,0x10,0x18,0x24,0x30,0x3c,0x48,0x48,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x25,0x27,0x2c,0x19,0x1b,0x1e,0x20,
-0x23,0x29,0x2a,0x2b,0x00,0x00,0x00,0x00,0x25,0x29,0x2b,0x2e,0x2e,0x00,0x00,0x00,
-0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
-0x18,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x48,0x00,0x00,0x00,
-0x60,0x00,0x00,0x00,0x90,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xd8,0x00,0x00,0x00,
-0x50,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,
-0x40,0x01,0x00,0x00,0x90,0x01,0x00,0x00,0xe0,0x01,0x00,0x00,0x30,0x02,0x00,0x00,
-0x2c,0x01,0x00,0x00,0x40,0x01,0x00,0x00,0xe0,0x01,0x00,0x00,0xd0,0x02,0x00,0x00,
-0x80,0x0c,0x00,0x00,0x80,0x0c,0x00,0x00,0x80,0x0c,0x00,0x00,0xa0,0x0f,0x00,0x00,
-0xa0,0x0f,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
-0x08,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x18,0x00,0x00,0x00,
-0x24,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x60,0x00,0x00,0x00,
-0x6c,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x50,0x00,0x00,0x00,
-0x64,0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,
-0x18,0x01,0x00,0x00,0x64,0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,
-0x68,0x01,0x00,0x00,0x40,0x06,0x00,0x00,0x40,0x06,0x00,0x00,0x40,0x06,0x00,0x00,
-0xd0,0x07,0x00,0x00,0xd0,0x07,0x00,0x00,0x2c,0x05,0x00,0x80,0x20,0x05,0x00,0x80,
-0x14,0x05,0x00,0x80,0x08,0x05,0x00,0x80,0xfc,0x04,0x00,0x80,0xf0,0x04,0x00,0x80,
-0xe4,0x04,0x00,0x80,0xd8,0x04,0x00,0x80,0xcc,0x04,0x00,0x80,0xc0,0x04,0x00,0x80,
-0x78,0x04,0x00,0x80,0x68,0x15,0x02,0x80,0xc0,0x3a,0x00,0x80,0xcc,0x3a,0x00,0x80,
-0xd8,0x3a,0x00,0x80,0xe4,0x3a,0x00,0x80,0xc0,0x3a,0x00,0x80,0xc0,0x3a,0x00,0x80,
-0xc0,0x3a,0x00,0x80,0xc0,0x3a,0x00,0x80,0xf0,0x3a,0x00,0x80,0xfc,0x3a,0x00,0x80,
-0x08,0x3b,0x00,0x80,0x14,0x3b,0x00,0x80,0x68,0x15,0x02,0x80,0xfe,0x01,0x80,0x7f,
-0xe2,0x01,0x80,0x78,0xc7,0x01,0xc0,0x71,0xae,0x01,0x80,0x6b,0x95,0x01,0x40,0x65,
-0x7f,0x01,0xc0,0x5f,0x69,0x01,0x40,0x5a,0x55,0x01,0x40,0x55,0x42,0x01,0x80,0x50,
-0x30,0x01,0x00,0x4c,0x1f,0x01,0xc0,0x47,0x0f,0x01,0xc0,0x43,0x00,0x01,0x00,0x40,
-0xf2,0x00,0x80,0x3c,0xe4,0x00,0x00,0x39,0xd7,0x00,0xc0,0x35,0xcb,0x00,0xc0,0x32,
-0xc0,0x00,0x00,0x30,0xb5,0x00,0x40,0x2d,0xab,0x00,0xc0,0x2a,0xa2,0x00,0x80,0x28,
-0x98,0x00,0x00,0x26,0x90,0x00,0x00,0x24,0x88,0x00,0x00,0x22,0x80,0x00,0x00,0x20,
-0x79,0x00,0x40,0x1e,0x72,0x00,0x80,0x1c,0x6c,0x00,0x00,0x1b,0x66,0x00,0x80,0x19,
-0x60,0x00,0x00,0x18,0x5b,0x00,0xc0,0x16,0x56,0x00,0x80,0x15,0x51,0x00,0x40,0x14,
-0x4c,0x00,0x00,0x13,0x48,0x00,0x00,0x12,0x44,0x00,0x00,0x11,0x40,0x00,0x00,0x10,
-0x36,0x35,0x2e,0x25,0x1c,0x12,0x09,0x04,0x33,0x32,0x2b,0x23,0x1a,0x11,0x08,0x04,
-0x30,0x2f,0x29,0x21,0x19,0x10,0x08,0x03,0x2d,0x2d,0x27,0x1f,0x18,0x0f,0x08,0x03,
-0x2b,0x2a,0x25,0x1e,0x16,0x0e,0x07,0x03,0x28,0x28,0x22,0x1c,0x15,0x0d,0x07,0x03,
-0x26,0x25,0x21,0x1b,0x14,0x0d,0x06,0x03,0x24,0x23,0x1f,0x19,0x13,0x0c,0x06,0x03,
-0x22,0x21,0x1d,0x18,0x11,0x0b,0x06,0x02,0x20,0x20,0x1b,0x16,0x11,0x08,0x05,0x02,
-0x1f,0x1e,0x1a,0x15,0x10,0x0a,0x05,0x02,0x1d,0x1c,0x18,0x14,0x0f,0x0a,0x05,0x02,
-0x1b,0x1a,0x17,0x13,0x0e,0x09,0x04,0x02,0x1a,0x19,0x16,0x12,0x0d,0x09,0x04,0x02,
-0x18,0x17,0x15,0x11,0x0c,0x08,0x04,0x02,0x17,0x16,0x13,0x10,0x0c,0x08,0x04,0x02,
-0x16,0x15,0x12,0x0f,0x0b,0x07,0x04,0x01,0x14,0x14,0x11,0x0e,0x0b,0x07,0x03,0x02,
-0x13,0x13,0x10,0x0d,0x0a,0x06,0x03,0x01,0x12,0x12,0x0f,0x0c,0x09,0x06,0x03,0x01,
-0x11,0x11,0x0f,0x0c,0x09,0x06,0x03,0x01,0x10,0x10,0x0e,0x0b,0x08,0x05,0x03,0x01,
-0x0f,0x0f,0x0d,0x0b,0x08,0x05,0x03,0x01,0x0e,0x0e,0x0c,0x0a,0x08,0x05,0x02,0x01,
-0x0d,0x0d,0x0c,0x0a,0x07,0x05,0x02,0x01,0x0d,0x0c,0x0b,0x09,0x07,0x04,0x02,0x01,
-0x0c,0x0c,0x0a,0x09,0x06,0x04,0x02,0x01,0x0b,0x0b,0x0a,0x08,0x06,0x04,0x02,0x01,
-0x0b,0x0a,0x09,0x08,0x06,0x04,0x02,0x01,0x0a,0x0a,0x09,0x07,0x05,0x03,0x02,0x01,
-0x0a,0x09,0x08,0x07,0x05,0x03,0x02,0x01,0x09,0x09,0x08,0x06,0x05,0x03,0x01,0x01,
-0x09,0x08,0x07,0x06,0x04,0x03,0x01,0x01,0x36,0x35,0x2e,0x1b,0x00,0x00,0x00,0x00,
-0x33,0x32,0x2b,0x19,0x00,0x00,0x00,0x00,0x30,0x2f,0x29,0x18,0x00,0x00,0x00,0x00,
-0x2d,0x2d,0x17,0x17,0x00,0x00,0x00,0x00,0x2b,0x2a,0x25,0x15,0x00,0x00,0x00,0x00,
-0x28,0x28,0x24,0x14,0x00,0x00,0x00,0x00,0x26,0x25,0x21,0x13,0x00,0x00,0x00,0x00,
-0x24,0x23,0x1f,0x12,0x00,0x00,0x00,0x00,0x22,0x21,0x1d,0x11,0x00,0x00,0x00,0x00,
-0x20,0x20,0x1b,0x10,0x00,0x00,0x00,0x00,0x1f,0x1e,0x1a,0x0f,0x00,0x00,0x00,0x00,
-0x1d,0x1c,0x18,0x0e,0x00,0x00,0x00,0x00,0x1b,0x1a,0x17,0x0e,0x00,0x00,0x00,0x00,
-0x1a,0x19,0x16,0x0d,0x00,0x00,0x00,0x00,0x18,0x17,0x15,0x0c,0x00,0x00,0x00,0x00,
-0x17,0x16,0x13,0x0b,0x00,0x00,0x00,0x00,0x16,0x15,0x12,0x0b,0x00,0x00,0x00,0x00,
-0x14,0x14,0x11,0x0a,0x00,0x00,0x00,0x00,0x13,0x13,0x10,0x0a,0x00,0x00,0x00,0x00,
-0x12,0x12,0x0f,0x09,0x00,0x00,0x00,0x00,0x11,0x11,0x0f,0x09,0x00,0x00,0x00,0x00,
-0x10,0x10,0x0e,0x08,0x00,0x00,0x00,0x00,0x0f,0x0f,0x0d,0x08,0x00,0x00,0x00,0x00,
-0x0e,0x0e,0x0c,0x07,0x00,0x00,0x00,0x00,0x0d,0x0d,0x0c,0x07,0x00,0x00,0x00,0x00,
-0x0d,0x0c,0x0b,0x06,0x00,0x00,0x00,0x00,0x0c,0x0c,0x0a,0x06,0x00,0x00,0x00,0x00,
-0x0b,0x0b,0x0a,0x06,0x00,0x00,0x00,0x00,0x0b,0x0a,0x09,0x05,0x00,0x00,0x00,0x00,
-0x0a,0x0a,0x09,0x05,0x00,0x00,0x00,0x00,0x0a,0x09,0x08,0x05,0x00,0x00,0x00,0x00,
-0x09,0x09,0x08,0x05,0x00,0x00,0x00,0x00,0x09,0x08,0x07,0x04,0x00,0x00,0x00,0x00,
-0x06,0x00,0x2a,0xb0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
-0x08,0x28,0x28,0x28,0x28,0x28,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
-0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0xa0,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
-0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
-0x04,0x04,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x41,0x41,0x41,0x41,0x41,0x41,0x01,
-0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
-0x01,0x01,0x01,0x10,0x10,0x10,0x10,0x10,0x10,0x42,0x42,0x42,0x42,0x42,0x42,0x02,
-0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
-0x02,0x02,0x02,0x10,0x10,0x10,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
-0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
-0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
-0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x10,
-0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
-0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x10,
-0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x19,0x77,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x26,0x72,0xb0,0x00,0x26,0x72,0xb0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x26,0x65,0x60,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x02,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xf2,0x30,0xb8,0xff,0xff,0xff,0xff,
-};
-
u8 Rtl8192SUFwMainArray[MainArrayLength] = {
0x0, };
diff --git a/drivers/staging/rtl8192su/r8192SU_HWImg.h b/drivers/staging/rtl8192su/r8192SU_HWImg.h
index 96b15252ea86..36e84aff6ed6 100644
--- a/drivers/staging/rtl8192su/r8192SU_HWImg.h
+++ b/drivers/staging/rtl8192su/r8192SU_HWImg.h
@@ -5,8 +5,6 @@
/*Created on 2009/ 3/ 6, 5:29*/
-#define ImgArrayLength 68368
-extern u8 Rtl8192SUFwImgArray[ImgArrayLength];
#define MainArrayLength 1
extern u8 Rtl8192SUFwMainArray[MainArrayLength];
#define DataArrayLength 1
diff --git a/drivers/staging/rtl8192su/r8192S_firmware.c b/drivers/staging/rtl8192su/r8192S_firmware.c
index 3561adf0468a..752a3f1fb3f5 100644
--- a/drivers/staging/rtl8192su/r8192S_firmware.c
+++ b/drivers/staging/rtl8192su/r8192S_firmware.c
@@ -360,117 +360,58 @@ bool FirmwareDownload92S(struct net_device *dev)
RT_TRACE(COMP_FIRMWARE, " --->FirmwareDownload92S()\n");
- //3//
- //3 //<1> Open Image file, and map file to contineous memory if open file success.
- //3 // or read image file from array. Default load from BIN file
- //3//
- priv->firmware_source = FW_SOURCE_IMG_FILE;// We should decided by Reg.
-
- switch( priv->firmware_source )
+/*
+* Load the firmware from RTL8192SU/rtl8192sfw.bin
+*/
+ if(pFirmware->szFwTmpBufferLen == 0)
{
- case FW_SOURCE_IMG_FILE:
- if(pFirmware->szFwTmpBufferLen == 0)
- {
-
- rc = request_firmware(&fw_entry, pFwImageFileName[ulInitStep],&priv->udev->dev);//===>1
- if(rc < 0 ) {
- RT_TRACE(COMP_ERR, "request firmware fail!\n");
- goto DownloadFirmware_Fail;
- }
-
- if(fw_entry->size > sizeof(pFirmware->szFwTmpBuffer))
- {
- RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n");
- release_firmware(fw_entry);
- goto DownloadFirmware_Fail;
- }
+ rc = request_firmware(&fw_entry, pFwImageFileName[ulInitStep],&priv->udev->dev);
+ if(rc < 0 ) {
+ RT_TRACE(COMP_ERR, "request firmware fail!\n");
+ goto DownloadFirmware_Fail;
+ }
- memcpy(pFirmware->szFwTmpBuffer,fw_entry->data,fw_entry->size);
- pFirmware->szFwTmpBufferLen = fw_entry->size;
+ if(fw_entry->size > sizeof(pFirmware->szFwTmpBuffer)) {
+ RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n");
release_firmware(fw_entry);
-
- pucMappedFile = pFirmware->szFwTmpBuffer;
- file_length = pFirmware->szFwTmpBufferLen;
-
- //Retrieve FW header.
- pFirmware->pFwHeader = (PRT_8192S_FIRMWARE_HDR) pucMappedFile;
- pFwHdr = pFirmware->pFwHeader;
- RT_TRACE(COMP_FIRMWARE,"signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", \
- pFwHdr->Signature, pFwHdr->Version, pFwHdr->DMEMSize, \
- pFwHdr->IMG_IMEM_SIZE, pFwHdr->IMG_SRAM_SIZE);
- pFirmware->FirmwareVersion = byte(pFwHdr->Version ,0);
- if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM)))
- {
- RT_TRACE(COMP_ERR, "%s: memory for data image is less than IMEM required\n",\
- __FUNCTION__);
- goto DownloadFirmware_Fail;
- } else {
- pucMappedFile+=FwHdrSize;
-
- //Retrieve IMEM image.
- memcpy(pFirmware->FwIMEM, pucMappedFile, pFwHdr->IMG_IMEM_SIZE);
- pFirmware->FwIMEMLen = pFwHdr->IMG_IMEM_SIZE;
- }
-
- if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM))
- {
- RT_TRACE(COMP_ERR, "%s: memory for data image is less than EMEM required\n",\
- __FUNCTION__);
- goto DownloadFirmware_Fail;
- } else {
- pucMappedFile += pFirmware->FwIMEMLen;
-
- /* Retriecve EMEM image */
- memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE);//===>6
- pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE;
- }
-
-
+ goto DownloadFirmware_Fail;
}
- break;
- case FW_SOURCE_HEADER_FILE:
-#if 1
-#define Rtl819XFwImageArray Rtl8192SUFwImgArray
- //2008.11.10 Add by tynli.
- pucMappedFile = Rtl819XFwImageArray;
- ulFileLength = ImgArrayLength;
+ memcpy(pFirmware->szFwTmpBuffer,fw_entry->data,fw_entry->size);
+ pFirmware->szFwTmpBufferLen = fw_entry->size;
+ release_firmware(fw_entry);
+
+ pucMappedFile = pFirmware->szFwTmpBuffer;
+ file_length = pFirmware->szFwTmpBufferLen;
- RT_TRACE(COMP_INIT,"Fw download from header.\n");
- /* Retrieve FW header*/
+ /* Retrieve FW header. */
pFirmware->pFwHeader = (PRT_8192S_FIRMWARE_HDR) pucMappedFile;
pFwHdr = pFirmware->pFwHeader;
RT_TRACE(COMP_FIRMWARE,"signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", \
pFwHdr->Signature, pFwHdr->Version, pFwHdr->DMEMSize, \
pFwHdr->IMG_IMEM_SIZE, pFwHdr->IMG_SRAM_SIZE);
pFirmware->FirmwareVersion = byte(pFwHdr->Version ,0);
-
- if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM)))
- {
- printk("FirmwareDownload92S(): memory for data image is less than IMEM required\n");
+ if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM))) {
+ RT_TRACE(COMP_ERR, "%s: memory for data image is less than IMEM required\n",\
+ __FUNCTION__);
goto DownloadFirmware_Fail;
} else {
pucMappedFile+=FwHdrSize;
- //Retrieve IMEM image.
+ /* Retrieve IMEM image. */
memcpy(pFirmware->FwIMEM, pucMappedFile, pFwHdr->IMG_IMEM_SIZE);
pFirmware->FwIMEMLen = pFwHdr->IMG_IMEM_SIZE;
}
- if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM))
- {
- printk(" FirmwareDownload92S(): memory for data image is less than EMEM required\n");
- goto DownloadFirmware_Fail;
- } else {
- pucMappedFile+= pFirmware->FwIMEMLen;
-
- //Retriecve EMEM image.
- memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE);
- pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE;
- }
-#endif
- break;
- default:
- break;
+ if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM)) {
+ RT_TRACE(COMP_ERR, "%s: memory for data image is less than EMEM required\n",\
+ __FUNCTION__);
+ goto DownloadFirmware_Fail;
+ } else {
+ pucMappedFile += pFirmware->FwIMEMLen;
+ /* Retriecve EMEM image */
+ memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE);//===>6
+ pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE;
+ }
}
FwStatus = FirmwareGetNextStatus(pFirmware->FWStatus);
@@ -538,3 +479,4 @@ bool FirmwareDownload92S(struct net_device *dev)
return rtStatus;
}
+MODULE_FIRMWARE("RTL8192SU/rtl8192sfw.bin");
diff --git a/drivers/staging/rtl8192su/r8192S_firmware.h b/drivers/staging/rtl8192su/r8192S_firmware.h
index c525380e6473..2c2cf8032ded 100644
--- a/drivers/staging/rtl8192su/r8192S_firmware.h
+++ b/drivers/staging/rtl8192su/r8192S_firmware.h
@@ -59,12 +59,6 @@ typedef enum _desc_packet_type_e{
DESC_PACKET_TYPE_NORMAL = 1,
}desc_packet_type_e;
-typedef enum _firmware_source{
- FW_SOURCE_IMG_FILE = 0,
- FW_SOURCE_HEADER_FILE = 1,
-}firmware_source_e, *pfirmware_source_e;
-
-
typedef enum _opt_rst_type{
OPT_SYSTEM_RESET = 0,
OPT_FIRMWARE_RESET = 1,
@@ -185,7 +179,6 @@ typedef enum _FIRMWARE_8192S_STATUS{
#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 //64k
typedef struct _rt_firmware{
- firmware_source_e eFWSource;
PRT_8192S_FIRMWARE_HDR pFwHeader;
FIRMWARE_8192S_STATUS FWStatus;
u16 FirmwareVersion;
diff --git a/drivers/staging/rtl8192su/r8192S_phy.c b/drivers/staging/rtl8192su/r8192S_phy.c
index 77ab026288d3..63d4e5fd7b18 100644
--- a/drivers/staging/rtl8192su/r8192S_phy.c
+++ b/drivers/staging/rtl8192su/r8192S_phy.c
@@ -2407,8 +2407,8 @@ void PHY_SetBWModeCallback8192S(struct net_device *dev)
break;
default:
- RT_TRACE(COMP_DBG, "SetBWModeCallback8190Pci():\
- unknown Bandwidth: %#X\n",priv->CurrentChannelBW);
+ RT_TRACE(COMP_DBG, "SetBWModeCallback8190Pci(): unknown Bandwidth: %#X\n",
+ priv->CurrentChannelBW);
break;
}
@@ -3398,8 +3398,8 @@ void SwChnlCallback8192SUsb(struct net_device *dev)
u32 delay;
// bool ret;
- RT_TRACE(COMP_SCAN, "==>SwChnlCallback8190Pci(), switch to channel\
- %d\n", priv->chan);
+ RT_TRACE(COMP_SCAN, "==>SwChnlCallback8190Pci(), switch to channel %d\n",
+ priv->chan);
if(!priv->up)
@@ -3525,8 +3525,8 @@ void SetBWModeCallback8192SUsb(struct net_device *dev)
break;
default:
- RT_TRACE(COMP_DBG, "SetChannelBandwidth8190Pci():\
- unknown Bandwidth: %#X\n",priv->CurrentChannelBW);
+ RT_TRACE(COMP_DBG, "SetChannelBandwidth8190Pci(): unknown Bandwidth: %#X\n",
+ priv->CurrentChannelBW);
break;
}
@@ -3660,8 +3660,8 @@ void SetBWModeCallback8192SUsbWorkItem(struct net_device *dev)
break;
default:
- RT_TRACE(COMP_DBG, "SetBWModeCallback8192SUsbWorkItem():\
- unknown Bandwidth: %#X\n",priv->CurrentChannelBW);
+ RT_TRACE(COMP_DBG, "SetBWModeCallback8192SUsbWorkItem(): unknown Bandwidth: %#X\n",
+ priv->CurrentChannelBW);
break;
}
diff --git a/drivers/staging/rtl8192su/r8192U.h b/drivers/staging/rtl8192su/r8192U.h
index 2a11e0113d3a..ba87623f32ee 100644
--- a/drivers/staging/rtl8192su/r8192U.h
+++ b/drivers/staging/rtl8192su/r8192U.h
@@ -1258,7 +1258,6 @@ typedef struct r8192_priv
u8 Rf_Mode; //add for Firmware RF -R/W switch
prt_firmware pFirmware;
rtl819xUsb_loopback_e LoopbackMode;
- firmware_source_e firmware_source;
bool usb_error;
u16 EEPROMTxPowerDiff;
diff --git a/drivers/staging/rtl8192su/r8192U_core.c b/drivers/staging/rtl8192su/r8192U_core.c
index ccb9d5b8cd44..7d0305cc2106 100644
--- a/drivers/staging/rtl8192su/r8192U_core.c
+++ b/drivers/staging/rtl8192su/r8192U_core.c
@@ -110,7 +110,7 @@ u32 rt_global_debug_component = \
#define TOTAL_CAM_ENTRY 32
#define CAM_CONTENT_COUNT 8
-static struct usb_device_id rtl8192_usb_id_tbl[] = {
+static const struct usb_device_id rtl8192_usb_id_tbl[] = {
/* Realtek */
{USB_DEVICE(0x0bda, 0x8192)},
{USB_DEVICE(0x0bda, 0x8709)},
@@ -2340,25 +2340,24 @@ short rtl8192SU_tx(struct net_device *dev, struct sk_buff* skb)
skb->len, rtl8192_tx_isr, skb);
status = usb_submit_urb(tx_urb, GFP_ATOMIC);
- if (!status){
-//we need to send 0 byte packet whenever 512N bytes/64N(HIGN SPEED/NORMAL SPEED) bytes packet has been transmitted. Otherwise, it will be halt to wait for another packet. WB. 2008.08.27
+ if (!status) {
+ /*
+ * we need to send 0 byte packet whenever 512N bytes/64N(HIGN SPEED/NORMAL SPEED) bytes packet has been transmitted.
+ * Otherwise, it will be halt to wait for another packet. WB. 2008.08.27
+ */
bool bSend0Byte = false;
u8 zero = 0;
- if(udev->speed == USB_SPEED_HIGH)
- {
+ if(udev->speed == USB_SPEED_HIGH) {
if (skb->len > 0 && skb->len % 512 == 0)
bSend0Byte = true;
}
- else
- {
+ else {
if (skb->len > 0 && skb->len % 64 == 0)
bSend0Byte = true;
}
- if (bSend0Byte)
- {
-#if 1
+ if (bSend0Byte) {
tx_urb_zero = usb_alloc_urb(0,GFP_ATOMIC);
- if(!tx_urb_zero){
+ if(!tx_urb_zero) {
RT_TRACE(COMP_ERR, "can't alloc urb for zero byte\n");
return -ENOMEM;
}
@@ -2366,16 +2365,23 @@ short rtl8192SU_tx(struct net_device *dev, struct sk_buff* skb)
usb_sndbulkpipe(udev,idx_pipe), &zero,
0, tx_zero_isr, dev);
status = usb_submit_urb(tx_urb_zero, GFP_ATOMIC);
- if (status){
- RT_TRACE(COMP_ERR, "Error TX URB for zero byte %d, error %d", atomic_read(&priv->tx_pending[tcb_desc->queue_index]), status);
- return -1;
+ switch (status) {
+ case 0:
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ break;
+ default:
+ RT_TRACE(COMP_ERR, "Error TX URB for zero byte %d, error %d",
+ atomic_read(&priv->tx_pending[tcb_desc->queue_index]), status);
+ return -1;
}
-#endif
}
dev->trans_start = jiffies;
atomic_inc(&priv->tx_pending[tcb_desc->queue_index]);
return 0;
- }else{
+ } else {
RT_TRACE(COMP_ERR, "Error TX URB %d, error %d", atomic_read(&priv->tx_pending[tcb_desc->queue_index]),
status);
return -1;
@@ -2952,7 +2958,7 @@ void rtl8192_SetWirelessMode(struct net_device* dev, u8 wireless_mode)
wireless_mode = WIRELESS_MODE_B;
}
}
-#ifdef TO_DO_LIST //// TODO: this function doesn't work well at this time, we shoud wait for FPGA
+#ifdef TO_DO_LIST //// TODO: this function doesn't work well at this time, we should wait for FPGA
ActUpdateChannelAccessSetting( pAdapter, pHalData->CurrentWirelessMode, &pAdapter->MgntInfo.Info8185.ChannelAccessSetting );
#endif
//LZM 090306 usb crash here, mark it temp
@@ -3359,6 +3365,46 @@ u8 rtl8192SU_BoardTypeToRFtype(struct net_device* dev, u8 Boardtype)
return RFtype;
}
+void update_hal_variables(struct r8192_priv *priv)
+{
+ int rf_path;
+ int i;
+ u8 index;
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ for (i = 0; i < 3; i++) {
+ RT_TRACE((COMP_INIT), "CCK RF-%d CHan_Area-%d = 0x%x\n", rf_path, i, priv->RfCckChnlAreaTxPwr[rf_path][i]);
+ RT_TRACE((COMP_INIT), "OFDM-1T RF-%d CHan_Area-%d = 0x%x\n", rf_path, i, priv->RfOfdmChnlAreaTxPwr1T[rf_path][i]);
+ RT_TRACE((COMP_INIT), "OFDM-2T RF-%d CHan_Area-%d = 0x%x\n", rf_path, i, priv->RfOfdmChnlAreaTxPwr2T[rf_path][i]);
+ }
+ /* Assign dedicated channel tx power */
+ for(i = 0; i < 14; i++) {
+ /* channel 1-3 use the same Tx Power Level. */
+ if (i < 3) /* Channel 1-3 */
+ index = 0;
+ else if (i < 9) /* Channel 4-9 */
+ index = 1;
+ else /* Channel 10-14 */
+ index = 2;
+ /* Record A & B CCK /OFDM - 1T/2T Channel area tx power */
+ priv->RfTxPwrLevelCck[rf_path][i] = priv->RfCckChnlAreaTxPwr[rf_path][index];
+ priv->RfTxPwrLevelOfdm1T[rf_path][i] = priv->RfOfdmChnlAreaTxPwr1T[rf_path][index];
+ priv->RfTxPwrLevelOfdm2T[rf_path][i] = priv->RfOfdmChnlAreaTxPwr2T[rf_path][index];
+ if (rf_path == 0) {
+ priv->TxPowerLevelOFDM24G[i] = priv->RfTxPwrLevelOfdm1T[rf_path][i] ;
+ priv->TxPowerLevelCCK[i] = priv->RfTxPwrLevelCck[rf_path][i];
+ }
+ }
+ for(i = 0; i < 14; i++) {
+ RT_TRACE((COMP_INIT),
+ "Rf-%d TxPwr CH-%d CCK OFDM_1T OFDM_2T= 0x%x/0x%x/0x%x\n",
+ rf_path, i, priv->RfTxPwrLevelCck[rf_path][i],
+ priv->RfTxPwrLevelOfdm1T[rf_path][i] ,
+ priv->RfTxPwrLevelOfdm2T[rf_path][i] );
+ }
+ }
+}
+
//
// Description:
// Config HW adapter information into initial value.
@@ -3374,7 +3420,7 @@ rtl8192SU_ConfigAdapterInfo8192SForAutoLoadFail(struct net_device* dev)
struct r8192_priv *priv = ieee80211_priv(dev);
//u16 i,usValue;
//u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0x81, 0x92, 0x00};
- u8 rf_path, index; // For EEPROM/EFUSE After V0.6_1117
+ u8 rf_path; // For EEPROM/EFUSE After V0.6_1117
int i;
RT_TRACE(COMP_INIT, "====> ConfigAdapterInfo8192SForAutoLoadFail\n");
@@ -3426,10 +3472,9 @@ rtl8192SU_ConfigAdapterInfo8192SForAutoLoadFail(struct net_device* dev)
write_nic_dword(dev, IDR0, ((u32*)dev->dev_addr)[0]);
write_nic_word(dev, IDR4, ((u16*)(dev->dev_addr + 4))[0]);
- RT_TRACE(COMP_INIT, "ReadAdapterInfo8192SEFuse(), Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5]);
+ RT_TRACE(COMP_INIT,
+ "ReadAdapterInfo8192SEFuse(), Permanent Address = %pM\n",
+ dev->dev_addr);
priv->EEPROMBoardType = EEPROM_Default_BoardType;
priv->rf_type = RF_1T2R; //RF_2T2R
@@ -3455,42 +3500,7 @@ rtl8192SU_ConfigAdapterInfo8192SForAutoLoadFail(struct net_device* dev)
}
}
- for (i = 0; i < 3; i++)
- {
- //RT_TRACE((COMP_EFUSE), "CCK RF-%d CHan_Area-%d = 0x%x\n", rf_path, i,
- //priv->RfCckChnlAreaTxPwr[rf_path][i]);
- //RT_TRACE((COMP_EFUSE), "OFDM-1T RF-%d CHan_Area-%d = 0x%x\n", rf_path, i,
- //priv->RfOfdmChnlAreaTxPwr1T[rf_path][i]);
- //RT_TRACE((COMP_EFUSE), "OFDM-2T RF-%d CHan_Area-%d = 0x%x\n", rf_path, i,
- //priv->RfOfdmChnlAreaTxPwr2T[rf_path][i]);
- }
-
- // Assign dedicated channel tx power
- for(i=0; i<14; i++) // channel 1~3 use the same Tx Power Level.
- {
- if (i < 3) // Cjanel 1-3
- index = 0;
- else if (i < 9) // Channel 4-9
- index = 1;
- else // Channel 10-14
- index = 2;
-
- // Record A & B CCK /OFDM - 1T/2T Channel area tx power
- priv->RfTxPwrLevelCck[rf_path][i] =
- priv->RfCckChnlAreaTxPwr[rf_path][index];
- priv->RfTxPwrLevelOfdm1T[rf_path][i] =
- priv->RfOfdmChnlAreaTxPwr1T[rf_path][index];
- priv->RfTxPwrLevelOfdm2T[rf_path][i] =
- priv->RfOfdmChnlAreaTxPwr2T[rf_path][index];
- }
-
- for(i=0; i<14; i++)
- {
- //RT_TRACE((COMP_EFUSE), "Rf-%d TxPwr CH-%d CCK OFDM_1T OFDM_2T= 0x%x/0x%x/0x%x\n",
- //rf_path, i, priv->RfTxPwrLevelCck[0][i],
- //priv->RfTxPwrLevelOfdm1T[0][i] ,
- //priv->RfTxPwrLevelOfdm2T[0][i] );
- }
+ update_hal_variables(priv);
//
// Update remained HAL variables.
@@ -3767,10 +3777,9 @@ rtl8192SU_ReadAdapterInfo8192SUsb(struct net_device* dev)
write_nic_dword(dev, IDR0, ((u32*)dev->dev_addr)[0]);
write_nic_word(dev, IDR4, ((u16*)(dev->dev_addr + 4))[0]);
- RT_TRACE(COMP_INIT, "ReadAdapterInfo8192SEFuse(), Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5]);
+ RT_TRACE(COMP_INIT,
+ "ReadAdapterInfo8192SEFuse(), Permanent Address = %pM\n",
+ dev->dev_addr);
//
// Get CustomerID(Boad Type)
@@ -3901,53 +3910,7 @@ rtl8192SU_ReadAdapterInfo8192SUsb(struct net_device* dev)
}
}
-//
- // Update Tx Power HAL variables.
-//
- for (rf_path = 0; rf_path < 2; rf_path++)
- {
- for (i = 0; i < 3; i++)
- {
- RT_TRACE((COMP_INIT), "CCK RF-%d CHan_Area-%d = 0x%x\n", rf_path, i,
- priv->RfCckChnlAreaTxPwr[rf_path][i]);
- RT_TRACE((COMP_INIT), "OFDM-1T RF-%d CHan_Area-%d = 0x%x\n", rf_path, i,
- priv->RfOfdmChnlAreaTxPwr1T[rf_path][i]);
- RT_TRACE((COMP_INIT), "OFDM-2T RF-%d CHan_Area-%d = 0x%x\n", rf_path, i, priv->RfOfdmChnlAreaTxPwr2T[rf_path][i]);
- }
-
- // Assign dedicated channel tx power
- for(i=0; i<14; i++) // channel 1~3 use the same Tx Power Level.
- {
- if (i < 3) // Cjanel 1-3
- index = 0;
- else if (i < 9) // Channel 4-9
- index = 1;
- else // Channel 10-14
- index = 2;
-
- // Record A & B CCK /OFDM - 1T/2T Channel area tx power
- priv->RfTxPwrLevelCck[rf_path][i] =
- priv->RfCckChnlAreaTxPwr[rf_path][index];
- priv->RfTxPwrLevelOfdm1T[rf_path][i] =
- priv->RfOfdmChnlAreaTxPwr1T[rf_path][index];
- priv->RfTxPwrLevelOfdm2T[rf_path][i] =
- priv->RfOfdmChnlAreaTxPwr2T[rf_path][index];
- if (rf_path == 0)
- {
- priv->TxPowerLevelOFDM24G[i] = priv->RfTxPwrLevelOfdm1T[rf_path][i] ;
- priv->TxPowerLevelCCK[i] = priv->RfTxPwrLevelCck[rf_path][i];
- }
- }
-
- for(i=0; i<14; i++)
- {
- RT_TRACE((COMP_INIT),
- "Rf-%d TxPwr CH-%d CCK OFDM_1T OFDM_2T= 0x%x/0x%x/0x%x\n",
- rf_path, i, priv->RfTxPwrLevelCck[rf_path][i],
- priv->RfTxPwrLevelOfdm1T[rf_path][i] ,
- priv->RfTxPwrLevelOfdm2T[rf_path][i] );
- }
- }
+ update_hal_variables(priv);
}
//
@@ -6168,7 +6131,7 @@ void rtl8192_process_phyinfo(struct r8192_priv * priv,u8* buffer, struct ieee802
u16 sc ;
unsigned int frag,seq;
hdr = (struct ieee80211_hdr_3addr *)buffer;
- sc = le16_to_cpu(hdr->seq_ctl);
+ sc = le16_to_cpu(hdr->seq_ctrl);
frag = WLAN_GET_SEQ_FRAG(sc);
seq = WLAN_GET_SEQ_SEQ(sc);
//cosa add 04292008 to record the sequence number
@@ -6827,7 +6790,7 @@ void rtl8192SU_TranslateRxSignalStuff(struct sk_buff *skb,
tmp_buf = (u8*)skb->data;// + get_rxpacket_shiftbytes_819xusb(pstats);
hdr = (struct ieee80211_hdr_3addr *)tmp_buf;
- fc = le16_to_cpu(hdr->frame_ctl);
+ fc = le16_to_cpu(hdr->frame_control);
type = WLAN_FC_GET_TYPE(fc);
praddr = hdr->addr1;
@@ -7677,7 +7640,7 @@ void setKey( struct net_device *dev,
if (EntryNo >= TOTAL_CAM_ENTRY)
RT_TRACE(COMP_ERR, "cam entry exceeds in setKey()\n");
- RT_TRACE(COMP_SEC, "====>to setKey(), dev:%p, EntryNo:%d, KeyIndex:%d, KeyType:%d, MacAddr"MAC_FMT"\n", dev,EntryNo, KeyIndex, KeyType, MAC_ARG(MacAddr));
+ RT_TRACE(COMP_SEC, "====>to setKey(), dev:%p, EntryNo:%d, KeyIndex:%d, KeyType:%d, MacAddr%pM\n", dev,EntryNo, KeyIndex, KeyType, MacAddr);
if (DefaultKey)
usConfig |= BIT15 | (KeyType<<2);
diff --git a/drivers/staging/rtl8192su/r8192U_dm.c b/drivers/staging/rtl8192su/r8192U_dm.c
index 7891e9640272..fa5e24416dde 100644
--- a/drivers/staging/rtl8192su/r8192U_dm.c
+++ b/drivers/staging/rtl8192su/r8192U_dm.c
@@ -2697,7 +2697,7 @@ static void dm_check_edca_turbo(
u8* peername[11] = {"unknown", "realtek", "realtek_92se", "broadcom", "ralink", "atheros", "cisco", "marvell", "92u_softap", "self_softap"};
static int wb_tmp = 0;
if (wb_tmp == 0){
- printk("%s():iot peer is %#x:%s, bssid:"MAC_FMT"\n",__FUNCTION__,pHTInfo->IOTPeer,peername[pHTInfo->IOTPeer], MAC_ARG(priv->ieee80211->current_network.bssid));
+ printk("%s():iot peer is %#x:%s, bssid:%pM\n",__FUNCTION__,pHTInfo->IOTPeer,peername[pHTInfo->IOTPeer], priv->ieee80211->current_network.bssid);
wb_tmp = 1;
}
}
diff --git a/drivers/staging/rtl8192u/Kconfig b/drivers/staging/rtl8192u/Kconfig
index 9913ab8fb359..0439c90b4163 100644
--- a/drivers/staging/rtl8192u/Kconfig
+++ b/drivers/staging/rtl8192u/Kconfig
@@ -1,6 +1,7 @@
config RTL8192U
tristate "RealTek RTL8192U Wireless LAN NIC driver"
depends on PCI && WLAN && USB
- depends on WIRELESS_EXT
+ select WIRELESS_EXT
+ select WEXT_PRIV
default N
---help---
diff --git a/drivers/staging/rtl8192u/Makefile b/drivers/staging/rtl8192u/Makefile
index 2d59c4ef6c5b..738f4a80ec67 100644
--- a/drivers/staging/rtl8192u/Makefile
+++ b/drivers/staging/rtl8192u/Makefile
@@ -3,7 +3,7 @@ NIC_SELECT = RTL8192U
EXTRA_CFLAGS += -std=gnu89
EXTRA_CFLAGS += -O2
-EXTRA_CFLAGS += -mhard-float -DCONFIG_FORCE_HARD_FLOAT=y
+EXTRA_CFLAGS += -DCONFIG_FORCE_HARD_FLOAT=y
EXTRA_CFLAGS += -DJACKSON_NEW_8187 -DJACKSON_NEW_RX
EXTRA_CFLAGS += -DTHOMAS_BEACON -DTHOMAS_TASKLET -DTHOMAS_SKB -DTHOMAS_TURBO
#EXTRA_CFLAGS += -DUSB_TX_DRIVER_AGGREGATION_ENABLE
diff --git a/drivers/staging/rtl8192u/ieee80211.h b/drivers/staging/rtl8192u/ieee80211.h
index 3a47f1213e85..9d05ed6791ee 100644
--- a/drivers/staging/rtl8192u/ieee80211.h
+++ b/drivers/staging/rtl8192u/ieee80211.h
@@ -551,9 +551,6 @@ do { if (ieee80211_debug_level & (level)) \
/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
-
/*
* To use the debug system;
*
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
index 10908e123b86..39847c81e29c 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
@@ -30,6 +30,7 @@
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <linux/sched.h>
+#include <linux/semaphore.h>
#include <linux/delay.h>
#include <linux/wireless.h>
@@ -551,9 +552,6 @@ do { if (ieee80211_debug_level & (level)) \
/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
-
/*
* To use the debug system;
*
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c
index 0b33bf463320..0b57632bcff9 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c
@@ -288,7 +288,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (!(keyidx & (1 << 5))) {
if (net_ratelimit()) {
printk(KERN_DEBUG "CCMP: received packet without ExtIV"
- " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ " flag from %pM\n", hdr->addr2);
}
key->dot11RSNAStatsCCMPFormatErrors++;
return -2;
@@ -301,9 +301,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
if (!key->key_set) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT
+ printk(KERN_DEBUG "CCMP: received packet from %pM"
" with keyid=%d that does not have a configured"
- " key\n", MAC_ARG(hdr->addr2), keyidx);
+ " key\n", hdr->addr2, keyidx);
}
return -3;
}
@@ -318,11 +318,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
- " previous PN %02x%02x%02x%02x%02x%02x "
- "received PN %02x%02x%02x%02x%02x%02x\n",
- MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn),
- MAC_ARG(pn));
+ printk(KERN_DEBUG "CCMP: replay detected: STA=%pM"
+ " previous PN %pm received PN %pm\n",
+ hdr->addr2, key->rx_pn, pn);
}
key->dot11RSNAStatsCCMPReplays++;
return -4;
@@ -359,7 +357,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
if (net_ratelimit()) {
printk(KERN_DEBUG "CCMP: decrypt failed: STA="
- MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ "%pM\n", hdr->addr2);
}
key->dot11RSNAStatsCCMPDecryptErrors++;
return -5;
@@ -435,11 +433,10 @@ static char * ieee80211_ccmp_print_stats(char *p, void *priv)
{
struct ieee80211_ccmp_data *ccmp = priv;
p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
- "tx_pn=%02x%02x%02x%02x%02x%02x "
- "rx_pn=%02x%02x%02x%02x%02x%02x "
+ "tx_pn=%pm rx_pn=%pm "
"format_errors=%d replays=%d decrypt_errors=%d\n",
ccmp->key_idx, ccmp->key_set,
- MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn),
+ ccmp->tx_pn, ccmp->rx_pn,
ccmp->dot11RSNAStatsCCMPFormatErrors,
ccmp->dot11RSNAStatsCCMPReplays,
ccmp->dot11RSNAStatsCCMPDecryptErrors);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
index 841b99955b79..9510507d8d05 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
@@ -410,7 +410,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (!(keyidx & (1 << 5))) {
if (net_ratelimit()) {
printk(KERN_DEBUG "TKIP: received packet without ExtIV"
- " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ " flag from %pM\n", hdr->addr2);
}
return -2;
}
@@ -422,9 +422,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
if (!tkey->key_set) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT
+ printk(KERN_DEBUG "TKIP: received packet from %pM"
" with keyid=%d that does not have a configured"
- " key\n", MAC_ARG(hdr->addr2), keyidx);
+ " key\n", hdr->addr2, keyidx);
}
return -3;
}
@@ -437,9 +437,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (iv32 < tkey->rx_iv32 ||
(iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
+ printk(KERN_DEBUG "TKIP: replay detected: STA=%pM"
" previous TSC %08x%04x received TSC "
- "%08x%04x\n", MAC_ARG(hdr->addr2),
+ "%08x%04x\n", hdr->addr2,
tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
}
tkey->dot11RSNAStatsTKIPReplays++;
@@ -460,8 +460,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
if (net_ratelimit()) {
printk(KERN_DEBUG ": TKIP: failed to decrypt "
- "received packet from " MAC_FMT "\n",
- MAC_ARG(hdr->addr2));
+ "received packet from %pM\n",
+ hdr->addr2);
}
return -7;
}
@@ -480,7 +480,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
if (net_ratelimit()) {
printk(KERN_DEBUG "TKIP: ICV error detected: STA="
- MAC_FMT "\n", MAC_ARG(hdr->addr2));
+ "%pM\n", hdr->addr2);
}
tkey->dot11RSNAStatsTKIPICVErrors++;
return -5;
@@ -635,8 +635,8 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
struct ieee80211_hdr_4addr *hdr;
hdr = (struct ieee80211_hdr_4addr *) skb->data;
printk(KERN_DEBUG "%s: Michael MIC verification failed for "
- "MSDU from " MAC_FMT " keyidx=%d\n",
- skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2),
+ "MSDU from %pM keyidx=%d\n",
+ skb->dev ? skb->dev->name : "N/A", hdr->addr2,
keyidx);
if (skb->dev)
ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
index 7a8690f449b4..b752017a4d18 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
@@ -260,7 +260,7 @@ static int store_debug_level(struct file *file, const char *buffer,
unsigned long count, void *data)
{
char buf[] = "0x00000000";
- unsigned long len = min(sizeof(buf) - 1, count);
+ unsigned long len = min_t(unsigned long, sizeof(buf) - 1, count);
char *p = (char *)buf;
unsigned long val;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
index 0e003c5bb000..7e9b367594a0 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
@@ -360,8 +360,8 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb,
strcmp(crypt->ops->name, "TKIP") == 0) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "received packet from " MAC_FMT "\n",
- ieee->dev->name, MAC_ARG(hdr->addr2));
+ "received packet from %pM\n",
+ ieee->dev->name, hdr->addr2);
}
return -1;
}
@@ -372,8 +372,8 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb,
atomic_dec(&crypt->refcnt);
if (res < 0) {
IEEE80211_DEBUG_DROP(
- "decryption failed (SA=" MAC_FMT
- ") res=%d\n", MAC_ARG(hdr->addr2), res);
+ "decryption failed (SA=%pM"
+ ") res=%d\n", hdr->addr2, res);
if (res == -2)
IEEE80211_DEBUG_DROP("Decryption failed ICV "
"mismatch (key %d)\n",
@@ -410,8 +410,8 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct sk_buff *s
atomic_dec(&crypt->refcnt);
if (res < 0) {
printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
- " (SA=" MAC_FMT " keyidx=%d)\n",
- ieee->dev->name, MAC_ARG(hdr->addr2), keyidx);
+ " (SA=%pM keyidx=%d)\n",
+ ieee->dev->name, hdr->addr2, keyidx);
return -1;
}
@@ -1016,8 +1016,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
* frames silently instead of filling system log with
* these reports. */
IEEE80211_DEBUG_DROP("Decryption failed (not set)"
- " (SA=" MAC_FMT ")\n",
- MAC_ARG(hdr->addr2));
+ " (SA=%pM)\n",
+ hdr->addr2);
ieee->ieee_stats.rx_discards_undecryptable++;
goto rx_dropped;
}
@@ -1256,8 +1256,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
} else {
IEEE80211_DEBUG_DROP(
"encryption configured, but RX "
- "frame not encrypted (SA=" MAC_FMT ")\n",
- MAC_ARG(hdr->addr2));
+ "frame not encrypted (SA=%pM)\n",
+ hdr->addr2);
goto rx_dropped;
}
}
@@ -1276,9 +1276,9 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
!ieee80211_is_eapol_frame(ieee, skb, hdrlen)) {
IEEE80211_DEBUG_DROP(
"dropped unencrypted RX data "
- "frame from " MAC_FMT
+ "frame from %pM"
" (drop_unencrypted=1)\n",
- MAC_ARG(hdr->addr2));
+ hdr->addr2);
goto rx_dropped;
}
/*
@@ -2260,11 +2260,11 @@ static inline int ieee80211_network_init(
}
if (network->mode == 0) {
- IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' "
+ IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' "
"network.\n",
escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid));
+ network->bssid);
return 1;
}
@@ -2439,9 +2439,9 @@ static inline void ieee80211_process_probe_response(
memset(&network, 0, sizeof(struct ieee80211_network));
IEEE80211_DEBUG_SCAN(
- "'%s' (" MAC_FMT "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
+ "'%s' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
escape_essid(info_element->data, info_element->len),
- MAC_ARG(beacon->header.addr3),
+ beacon->header.addr3,
(beacon->capability & (1<<0xf)) ? '1' : '0',
(beacon->capability & (1<<0xe)) ? '1' : '0',
(beacon->capability & (1<<0xd)) ? '1' : '0',
@@ -2460,10 +2460,10 @@ static inline void ieee80211_process_probe_response(
(beacon->capability & (1<<0x0)) ? '1' : '0');
if (ieee80211_network_init(ieee, beacon, &network, stats)) {
- IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n",
+ IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n",
escape_essid(info_element->data,
info_element->len),
- MAC_ARG(beacon->header.addr3),
+ beacon->header.addr3,
WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
@@ -2574,11 +2574,11 @@ static inline void ieee80211_process_probe_response(
/* If there are no more slots, expire the oldest */
list_del(&oldest->list);
target = oldest;
- IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from "
+ IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from "
"network list.\n",
escape_essid(target->ssid,
target->ssid_len),
- MAC_ARG(target->bssid));
+ target->bssid);
} else {
/* Otherwise just pull from the free list */
target = list_entry(ieee->network_free_list.next,
@@ -2588,10 +2588,10 @@ static inline void ieee80211_process_probe_response(
#ifdef CONFIG_IEEE80211_DEBUG
- IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n",
+ IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n",
escape_essid(network.ssid,
network.ssid_len),
- MAC_ARG(network.bssid),
+ network.bssid,
WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
@@ -2601,10 +2601,10 @@ static inline void ieee80211_process_probe_response(
if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)
ieee80211_softmac_new_net(ieee,&network);
} else {
- IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n",
+ IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
escape_essid(target->ssid,
target->ssid_len),
- MAC_ARG(target->bssid),
+ target->bssid,
WLAN_FC_GET_STYPE(beacon->header.frame_ctl) ==
IEEE80211_STYPE_PROBE_RESP ?
"PROBE RESPONSE" : "BEACON");
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
index 8a86e93465c8..27d925712cdd 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
@@ -1731,7 +1731,7 @@ ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
ieee80211_resp_to_assoc_rq(ieee, dest);
}
- printk(KERN_INFO"New client associated: "MAC_FMT"\n", MAC_ARG(dest));
+ printk(KERN_INFO"New client associated: %pM\n", dest);
//FIXME
}
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
index b29c36bac377..48537d948945 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
@@ -200,8 +200,8 @@ int ieee80211_encrypt_fragment(
header = (struct ieee80211_hdr *) frag->data;
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "TX packet to " MAC_FMT "\n",
- ieee->dev->name, MAC_ARG(header->addr1));
+ "TX packet to %pM\n",
+ ieee->dev->name, header->addr1);
}
return -1;
}
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
index 5f12d62658c9..c0b2c02b0ac4 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
@@ -289,10 +289,10 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
else
IEEE80211_DEBUG_SCAN(
"Not showing network '%s ("
- MAC_FMT ")' due to age (%lums).\n",
+ "%pM)' due to age (%lums).\n",
escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid),
+ network->bssid,
(jiffies - network->last_scanned) / (HZ / 100));
}
@@ -718,7 +718,7 @@ int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
} else
idx = ieee->tx_keyidx;
- if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
+ if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
ext->alg != IW_ENCODE_ALG_WEP)
if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
return -EINVAL;
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
index 512a57aebde3..27d083a70eb2 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
@@ -113,7 +113,7 @@ static struct sk_buff* ieee80211_ADDBA(struct ieee80211_device* ieee, u8* Dst, P
u16 tmp = 0;
u16 len = ieee->tx_headroom + 9;
//category(1) + action field(1) + Dialog Token(1) + BA Parameter Set(2) + BA Timeout Value(2) + BA Start SeqCtrl(2)(or StatusCode(2))
- IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:"MAC_FMT", ieee->dev:%p\n", __FUNCTION__, type, MAC_ARG(Dst), ieee->dev);
+ IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:%pM, ieee->dev:%p\n", __FUNCTION__, type, Dst, ieee->dev);
if (pBA == NULL||ieee == NULL)
{
IEEE80211_DEBUG(IEEE80211_DL_ERR, "pBA(%p) is NULL or ieee(%p) is NULL\n", pBA, ieee);
@@ -201,7 +201,7 @@ static struct sk_buff* ieee80211_DELBA(
u16 len = 6 + ieee->tx_headroom;
if (net_ratelimit())
- IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), ReasonCode(%d) sentd to:"MAC_FMT"\n", __FUNCTION__, ReasonCode, MAC_ARG(dst));
+ IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), ReasonCode(%d) sentd to:%pM\n", __FUNCTION__, ReasonCode, dst);
memset(&DelbaParamSet, 0, 2);
@@ -355,7 +355,7 @@ int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb)
pBaTimeoutVal = (u16*)(tag + 5);
pBaStartSeqCtrl = (PSEQUENCE_CONTROL)(req + 7);
- printk("====================>rx ADDBAREQ from :"MAC_FMT"\n", MAC_ARG(dst));
+ printk("====================>rx ADDBAREQ from :%pM\n", dst);
//some other capability is not ready now.
if( (ieee->current_network.qos_data.active == 0) ||
(ieee->pHTInfo->bCurrentHTSupport == false)) //||
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
index 2c4eb38c89a8..50f4f5943e75 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
@@ -41,7 +41,7 @@ static u8 AIRLINK_RALINK[3] = {0x00, 0x18, 0x02};
//static u8 DLINK_ATHEROS[3] = {0x00, 0x1c, 0xf0};
static u8 CISCO_BROADCOM[3] = {0x00, 0x17, 0x94};
-// 2008/04/01 MH For Cisco G mode RX TP We need to change FW duration. Shoud we put the
+// 2008/04/01 MH For Cisco G mode RX TP We need to change FW duration. Should we put the
// code in other place??
//static u8 WIFI_CISCO_G_AP[3] = {0x00, 0x40, 0x96};
/********************************************************************************************************************
@@ -1342,7 +1342,7 @@ void HTUseDefaultSetting(struct ieee80211_device* ieee)
pHTInfo->CurrentAMPDUFactor = pHTInfo->AMPDU_Factor;
- pHTInfo->CurrentMPDUDensity = pHTInfo->CurrentMPDUDensity;
+ pHTInfo->CurrentMPDUDensity = pHTInfo->MPDU_Density;
// Set BWOpMode register
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
index 5373d565af24..d1275e887f0c 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
@@ -290,7 +290,7 @@ PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee, u8* Addr, u8
if(search_dir[dir] ==false )
continue;
list_for_each_entry(pRet, psearch_list, List){
- // IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:"MAC_FMT", TID:%d, dir:%d\n", MAC_ARG(pRet->Addr), pRet->TSpec.f.TSInfo.field.ucTSID, pRet->TSpec.f.TSInfo.field.ucDirection);
+ // IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:%pM, TID:%d, dir:%d\n", pRet->Addr, pRet->TSpec.f.TSInfo.field.ucTSID, pRet->TSpec.f.TSInfo.field.ucDirection);
if (memcmp(pRet->Addr, Addr, 6) == 0)
if (pRet->TSpec.f.TSInfo.field.ucTSID == TID)
if(pRet->TSpec.f.TSInfo.field.ucDirection == dir)
@@ -445,7 +445,7 @@ bool GetTs(
ResetRxTsEntry(tmp);
}
- IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:"MAC_FMT"\n", UP, Dir, MAC_ARG(Addr));
+ IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP, Dir, Addr);
// Prepare TS Info releated field
pTSInfo->field.ucTrafficType = 0; // Traffic type: WMM is reserved in this field
pTSInfo->field.ucTSID = UP; // TSID
@@ -531,7 +531,7 @@ void RemoveTsEntry(
void RemovePeerTS(struct ieee80211_device* ieee, u8* Addr)
{
PTS_COMMON_INFO pTS, pTmpTS;
- printk("===========>RemovePeerTS,"MAC_FMT"\n", MAC_ARG(Addr));
+ printk("===========>RemovePeerTS,%pM\n", Addr);
list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List)
{
if (memcmp(pTS->Addr, Addr, 6) == 0)
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index adade13e1e19..f1e085ba1cf1 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -104,7 +104,7 @@ u32 rt_global_debug_component = \
#define TOTAL_CAM_ENTRY 32
#define CAM_CONTENT_COUNT 8
-static struct usb_device_id rtl8192_usb_id_tbl[] = {
+static const struct usb_device_id rtl8192_usb_id_tbl[] = {
/* Realtek */
{USB_DEVICE(0x0bda, 0x8192)},
{USB_DEVICE(0x0bda, 0x8709)},
@@ -2719,7 +2719,7 @@ void rtl8192_SetWirelessMode(struct net_device* dev, u8 wireless_mode)
wireless_mode = WIRELESS_MODE_B;
}
}
-#ifdef TO_DO_LIST //// TODO: this function doesn't work well at this time, we shoud wait for FPGA
+#ifdef TO_DO_LIST //// TODO: this function doesn't work well at this time, we should wait for FPGA
ActUpdateChannelAccessSetting( pAdapter, pHalData->CurrentWirelessMode, &pAdapter->MgntInfo.Info8185.ChannelAccessSetting );
#endif
priv->ieee80211->mode = wireless_mode;
@@ -2976,7 +2976,7 @@ static void rtl8192_read_eeprom_info(struct net_device* dev)
memcpy(dev->dev_addr, bMac_Tmp_Addr, 6);
//should I set IDR0 here?
}
- RT_TRACE(COMP_EPROM, "MAC addr:"MAC_FMT"\n", MAC_ARG(dev->dev_addr));
+ RT_TRACE(COMP_EPROM, "MAC addr:%pM\n", dev->dev_addr);
priv->rf_type = RTL819X_DEFAULT_RF_TYPE; //default 1T2R
priv->rf_chip = RF_8256;
@@ -6037,7 +6037,7 @@ void setKey( struct net_device *dev,
if (EntryNo >= TOTAL_CAM_ENTRY)
RT_TRACE(COMP_ERR, "cam entry exceeds in setKey()\n");
- RT_TRACE(COMP_SEC, "====>to setKey(), dev:%p, EntryNo:%d, KeyIndex:%d, KeyType:%d, MacAddr"MAC_FMT"\n", dev,EntryNo, KeyIndex, KeyType, MAC_ARG(MacAddr));
+ RT_TRACE(COMP_SEC, "====>to setKey(), dev:%p, EntryNo:%d, KeyIndex:%d, KeyType:%d, MacAddr%pM\n", dev,EntryNo, KeyIndex, KeyType, MacAddr);
if (DefaultKey)
usConfig |= BIT15 | (KeyType<<2);
diff --git a/drivers/staging/samsung-laptop/samsung-laptop.c b/drivers/staging/samsung-laptop/samsung-laptop.c
index 4877138a9f96..dd7ea4c075db 100644
--- a/drivers/staging/samsung-laptop/samsung-laptop.c
+++ b/drivers/staging/samsung-laptop/samsung-laptop.c
@@ -99,7 +99,8 @@ static struct rfkill *rfk;
static int force;
module_param(force, bool, 0);
-MODULE_PARM_DESC(force, "Disable the DMI check and forces the driver to be loaded");
+MODULE_PARM_DESC(force,
+ "Disable the DMI check and forces the driver to be loaded");
static int debug;
module_param(debug, bool, S_IRUGO | S_IWUSR);
@@ -370,7 +371,8 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
{
.ident = "N128",
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
DMI_MATCH(DMI_BOARD_NAME, "N128"),
},
@@ -379,7 +381,8 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
{
.ident = "N130",
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
DMI_MATCH(DMI_BOARD_NAME, "N130"),
},
diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c
index e7bc9ec63a8c..265de7949a78 100644
--- a/drivers/staging/sep/sep_driver.c
+++ b/drivers/staging/sep/sep_driver.c
@@ -35,6 +35,7 @@
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/mutex.h>
+#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/wait.h>
@@ -182,8 +183,8 @@ static DECLARE_WAIT_QUEUE_HEAD(sep_event);
static int sep_load_firmware(struct sep_device *sep)
{
const struct firmware *fw;
- char *cache_name = "cache.image.bin";
- char *res_name = "resident.image.bin";
+ char *cache_name = "sep/cache.image.bin";
+ char *res_name = "sep/resident.image.bin";
int error;
edbg("SEP Driver:rar_virtual is %p\n", sep->rar_addr);
@@ -222,6 +223,9 @@ static int sep_load_firmware(struct sep_device *sep)
return 0;
}
+MODULE_FIRMWARE("sep/cache.image.bin");
+MODULE_FIRMWARE("sep/resident.image.bin");
+
/**
* sep_map_and_alloc_shared_area - allocate shared block
* @sep: security processor
@@ -273,8 +277,8 @@ static dma_addr_t sep_shared_virt_to_bus(struct sep_device *sep,
void *virt_address)
{
dma_addr_t pa = sep->shared_bus + (virt_address - sep->shared_addr);
- edbg("sep: virt to bus b %08llx v %p\n",
- (unsigned long long)pa, virt_address);
+ edbg("sep: virt to bus b %08llx v %p\n", (unsigned long long) pa,
+ virt_address);
return pa;
}
@@ -380,8 +384,7 @@ static int sep_mmap(struct file *filp, struct vm_area_struct *vma)
shared area */
if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) {
edbg("SEP Driver mmap requested size is more than allowed\n");
- printk(KERN_WARNING "SEP Driver mmap requested size is more \
- than allowed\n");
+ printk(KERN_WARNING "SEP Driver mmap requested size is more than allowed\n");
printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_end);
printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_start);
return -EAGAIN;
@@ -941,8 +944,9 @@ static int sep_lock_user_pages(struct sep_device *sep,
dbg("data_size is %lu\n", data_size);
while (1);
}
- edbg("lli_array[%lu].physical_address is %08lx, \
- lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size);
+ edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n",
+ count, lli_array[count].physical_address,
+ count, lli_array[count].block_size);
}
/* set output params */
@@ -1771,7 +1775,7 @@ static struct sep_flow_context_t *sep_find_flow_context(struct sep_device *sep,
static int sep_create_flow_dma_tables_handler(struct sep_device *sep,
unsigned long arg)
{
- int error;
+ int error = -ENOENT;
struct sep_driver_build_flow_table_t command_args;
/* first table - output */
struct sep_lli_entry_t first_table_data;
@@ -2232,7 +2236,7 @@ static int sep_set_flow_id_handler(struct sep_device *sep,
return error;
}
-static int sep_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int error = 0;
struct sep_device *sep = filp->private_data;
@@ -2586,7 +2590,7 @@ end_function:
return error;
}
-static struct pci_device_id sep_pci_id_tbl[] = {
+static const struct pci_device_id sep_pci_id_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080c)},
{0}
};
@@ -2607,7 +2611,7 @@ static dev_t sep_devno;
/* the files operations structure of the driver */
static struct file_operations sep_file_operations = {
.owner = THIS_MODULE,
- .ioctl = sep_ioctl,
+ .unlocked_ioctl = sep_ioctl,
.poll = sep_poll,
.open = sep_open,
.release = sep_release,
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index 060e9de3b065..44f2d4eaf84b 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -126,7 +126,7 @@ static int debug;
#define MODEM_CTRL 0x40
#define RS232_MODE 0x00
-static struct usb_device_id serqt_id_table[] = {
+static const struct usb_device_id serqt_id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)},
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU200)},
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU100)},
@@ -1277,7 +1277,7 @@ static void qt_set_termios(struct tty_struct *tty,
if (cflag & CSTOPB)
new_LCR |= SERIAL_TWO_STOPB;
else
- new_LCR |= SERIAL_TWO_STOPB;
+ new_LCR |= SERIAL_ONE_STOPB;
dbg("%s - 4\n", __func__);
diff --git a/drivers/staging/slicoss/slic.h b/drivers/staging/slicoss/slic.h
index ccf7625b8bb3..eb3a619c6a94 100644
--- a/drivers/staging/slicoss/slic.h
+++ b/drivers/staging/slicoss/slic.h
@@ -527,15 +527,6 @@ struct adapter {
(largestat) += ((newstat) - (oldstat)); \
}
-#define ETHER_EQ_ADDR(_AddrA, _AddrB, _Result) \
-{ \
- _Result = true; \
- if (*(u32 *)(_AddrA) != *(u32 *)(_AddrB)) \
- _Result = false; \
- if (*(u16 *)(&((_AddrA)[4])) != *(u16 *)(&((_AddrB)[4]))) \
- _Result = false; \
-}
-
#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
#define SLIC_GET_ADDR_LOW(_addr) (u32)((u64)(_addr) & \
0x00000000FFFFFFFF)
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index 5b191afc1442..7daeced317c4 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -101,7 +101,7 @@ static struct net_device_stats *slic_get_stats(struct net_device *dev);
static int slic_entry_open(struct net_device *dev);
static int slic_entry_halt(struct net_device *dev);
static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev);
+static netdev_tx_t slic_xmit_start(struct sk_buff *skb, struct net_device *dev);
static void slic_xmit_fail(struct adapter *adapter, struct sk_buff *skb,
void *cmd, u32 skbtype, u32 status);
static void slic_config_pci(struct pci_dev *pcidev);
@@ -194,14 +194,10 @@ MODULE_PARM_DESC(dynamic_intagg, "Dynamic Interrupt Aggregation Setting");
module_param(intagg_delay, int, 0);
MODULE_PARM_DESC(intagg_delay, "uSec Interrupt Aggregation Delay");
-static struct pci_device_id slic_pci_tbl[] __devinitdata = {
- {PCI_VENDOR_ID_ALACRITECH,
- SLIC_1GB_DEVICE_ID,
- PCI_ANY_ID, PCI_ANY_ID,},
- {PCI_VENDOR_ID_ALACRITECH,
- SLIC_2GB_DEVICE_ID,
- PCI_ANY_ID, PCI_ANY_ID,},
- {0,}
+static DEFINE_PCI_DEVICE_TABLE(slic_pci_tbl) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ALACRITECH, SLIC_1GB_DEVICE_ID) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ALACRITECH, SLIC_2GB_DEVICE_ID) },
+ { 0 }
};
MODULE_DEVICE_TABLE(pci, slic_pci_tbl);
@@ -292,7 +288,7 @@ static void slic_init_adapter(struct net_device *netdev,
{
ushort index;
struct slic_handle *pslic_handle;
- struct adapter *adapter = (struct adapter *)netdev_priv(netdev);
+ struct adapter *adapter = netdev_priv(netdev);
/* adapter->pcidev = pcidev;*/
adapter->vendid = pci_tbl_entry->vendor;
@@ -370,6 +366,7 @@ static int __devinit slic_entry_probe(struct pci_dev *pcidev,
ulong mmio_start = 0;
ulong mmio_len = 0;
struct sliccard *card = NULL;
+ int pci_using_dac = 0;
slic_global.dynamic_intagg = dynamic_intagg;
@@ -383,16 +380,26 @@ static int __devinit slic_entry_probe(struct pci_dev *pcidev,
printk(KERN_DEBUG "%s\n", slic_proc_version);
}
- err = pci_set_dma_mask(pcidev, DMA_BIT_MASK(64));
- if (err) {
- err = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32));
- if (err)
+ if (!pci_set_dma_mask(pcidev, DMA_BIT_MASK(64))) {
+ pci_using_dac = 1;
+ if (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64))) {
+ dev_err(&pcidev->dev, "unable to obtain 64-bit DMA for "
+ "consistent allocations\n");
goto err_out_disable_pci;
+ }
+ } else if (pci_set_dma_mask(pcidev, DMA_BIT_MASK(32))) {
+ pci_using_dac = 0;
+ pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32));
+ } else {
+ dev_err(&pcidev->dev, "no usable DMA configuration\n");
+ goto err_out_disable_pci;
}
err = pci_request_regions(pcidev, DRV_NAME);
- if (err)
+ if (err) {
+ dev_err(&pcidev->dev, "can't obtain PCI resources\n");
goto err_out_disable_pci;
+ }
pci_set_master(pcidev);
@@ -408,6 +415,8 @@ static int __devinit slic_entry_probe(struct pci_dev *pcidev,
adapter = netdev_priv(netdev);
adapter->netdev = netdev;
adapter->pcidev = pcidev;
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
mmio_start = pci_resource_start(pcidev, 0);
mmio_len = pci_resource_len(pcidev, 0);
@@ -484,7 +493,7 @@ err_out_disable_pci:
static int slic_entry_open(struct net_device *dev)
{
- struct adapter *adapter = (struct adapter *) netdev_priv(dev);
+ struct adapter *adapter = netdev_priv(dev);
struct sliccard *card = adapter->card;
u32 locked = 0;
int status;
@@ -534,7 +543,7 @@ static void __devexit slic_entry_remove(struct pci_dev *pcidev)
struct net_device *dev = pci_get_drvdata(pcidev);
u32 mmio_start = 0;
uint mmio_len = 0;
- struct adapter *adapter = (struct adapter *) netdev_priv(dev);
+ struct adapter *adapter = netdev_priv(dev);
struct sliccard *card;
struct mcast_address *mcaddr, *mlist;
@@ -581,7 +590,7 @@ static void __devexit slic_entry_remove(struct pci_dev *pcidev)
static int slic_entry_halt(struct net_device *dev)
{
- struct adapter *adapter = (struct adapter *)netdev_priv(dev);
+ struct adapter *adapter = netdev_priv(dev);
struct sliccard *card = adapter->card;
__iomem struct slic_regs *slic_regs = adapter->slic_regs;
@@ -624,7 +633,7 @@ static int slic_entry_halt(struct net_device *dev)
static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct adapter *adapter = (struct adapter *)netdev_priv(dev);
+ struct adapter *adapter = netdev_priv(dev);
struct ethtool_cmd edata;
struct ethtool_cmd ecmd;
u32 data[7];
@@ -649,8 +658,7 @@ static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (copy_from_user(data, rq->ifr_data, 28)) {
PRINT_ERROR
- ("slic: copy_from_user FAILED getting \
- initial simba param\n");
+ ("slic: copy_from_user FAILED getting initial simba param\n");
return -EFAULT;
}
@@ -665,8 +673,7 @@ static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
(tracemon_request ==
SLIC_DUMP_IN_PROGRESS)) {
PRINT_ERROR
- ("ATK Diagnostic Trace Dump Requested but \
- already in progress... ignore\n");
+ ("ATK Diagnostic Trace Dump Requested but already in progress... ignore\n");
} else {
PRINT_ERROR
("ATK Diagnostic Trace Dump Requested\n");
@@ -784,10 +791,10 @@ static void slic_xmit_build_request(struct adapter *adapter,
#define NORMAL_ETHFRAME 0
-static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t slic_xmit_start(struct sk_buff *skb, struct net_device *dev)
{
struct sliccard *card;
- struct adapter *adapter = (struct adapter *)netdev_priv(dev);
+ struct adapter *adapter = netdev_priv(dev);
struct slic_hostcmd *hcmd = NULL;
u32 status = 0;
u32 skbtype = NORMAL_ETHFRAME;
@@ -1071,7 +1078,7 @@ static void slic_xmit_complete(struct adapter *adapter)
static irqreturn_t slic_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
- struct adapter *adapter = (struct adapter *)netdev_priv(dev);
+ struct adapter *adapter = netdev_priv(dev);
u32 isr;
if ((adapter->pshmem) && (adapter->pshmem->isr)) {
@@ -1229,22 +1236,21 @@ static void slic_init_cleanup(struct adapter *adapter)
static struct net_device_stats *slic_get_stats(struct net_device *dev)
{
- struct adapter *adapter = (struct adapter *)netdev_priv(dev);
- struct net_device_stats *stats;
+ struct adapter *adapter = netdev_priv(dev);
ASSERT(adapter);
- stats = &adapter->stats;
- stats->collisions = adapter->slic_stats.iface.xmit_collisions;
- stats->rx_errors = adapter->slic_stats.iface.rcv_errors;
- stats->tx_errors = adapter->slic_stats.iface.xmt_errors;
- stats->rx_missed_errors = adapter->slic_stats.iface.rcv_discards;
- stats->tx_heartbeat_errors = 0;
- stats->tx_aborted_errors = 0;
- stats->tx_window_errors = 0;
- stats->tx_fifo_errors = 0;
- stats->rx_frame_errors = 0;
- stats->rx_length_errors = 0;
- return &adapter->stats;
+ dev->stats.collisions = adapter->slic_stats.iface.xmit_collisions;
+ dev->stats.rx_errors = adapter->slic_stats.iface.rcv_errors;
+ dev->stats.tx_errors = adapter->slic_stats.iface.xmt_errors;
+ dev->stats.rx_missed_errors = adapter->slic_stats.iface.rcv_discards;
+ dev->stats.tx_heartbeat_errors = 0;
+ dev->stats.tx_aborted_errors = 0;
+ dev->stats.tx_window_errors = 0;
+ dev->stats.tx_fifo_errors = 0;
+ dev->stats.rx_frame_errors = 0;
+ dev->stats.rx_length_errors = 0;
+
+ return &dev->stats;
}
/*
@@ -1254,13 +1260,11 @@ static struct net_device_stats *slic_get_stats(struct net_device *dev)
static int slic_mcast_add_list(struct adapter *adapter, char *address)
{
struct mcast_address *mcaddr, *mlist;
- bool equaladdr;
/* Check to see if it already exists */
mlist = adapter->mcastaddrs;
while (mlist) {
- ETHER_EQ_ADDR(mlist->address, address, equaladdr);
- if (equaladdr)
+ if (!compare_ether_addr(mlist->address, address))
return STATUS_SUCCESS;
mlist = mlist->next;
}
@@ -1360,27 +1364,19 @@ static void slic_mcast_set_bit(struct adapter *adapter, char *address)
static void slic_mcast_set_list(struct net_device *dev)
{
- struct adapter *adapter = (struct adapter *)netdev_priv(dev);
+ struct adapter *adapter = netdev_priv(dev);
int status = STATUS_SUCCESS;
- int i;
char *addresses;
- struct dev_mc_list *mc_list = dev->mc_list;
- int mc_count = dev->mc_count;
+ struct dev_mc_list *mc_list;
ASSERT(adapter);
- for (i = 1; i <= mc_count; i++) {
+ netdev_for_each_mc_addr(mc_list, dev) {
addresses = (char *) &mc_list->dmi_addr;
- if (mc_list->dmi_addrlen == 6) {
- status = slic_mcast_add_list(adapter, addresses);
- if (status != STATUS_SUCCESS)
- break;
- } else {
- status = -EINVAL;
+ status = slic_mcast_add_list(adapter, addresses);
+ if (status != STATUS_SUCCESS)
break;
- }
slic_mcast_set_bit(adapter, addresses);
- mc_list = mc_list->next;
}
if (adapter->devflags_prev != dev->flags) {
@@ -1860,6 +1856,9 @@ static int slic_card_download_gbrcv(struct adapter *adapter)
return 0;
}
+MODULE_FIRMWARE("slicoss/oasisrcvucode.sys");
+MODULE_FIRMWARE("slicoss/gbrcvucode.sys");
+
static int slic_card_download(struct adapter *adapter)
{
const struct firmware *fw;
@@ -1971,6 +1970,9 @@ static int slic_card_download(struct adapter *adapter)
return STATUS_SUCCESS;
}
+MODULE_FIRMWARE("slicoss/oasisdownload.sys");
+MODULE_FIRMWARE("slicoss/gbdownload.sys");
+
static void slic_adapter_set_hwaddr(struct adapter *adapter)
{
struct sliccard *card = adapter->card;
@@ -2474,7 +2476,6 @@ static bool slic_mac_filter(struct adapter *adapter,
u32 opts = adapter->macopts;
u32 *dhost4 = (u32 *)&ether_frame->ether_dhost[0];
u16 *dhost2 = (u16 *)&ether_frame->ether_dhost[4];
- bool equaladdr;
if (opts & MAC_PROMISC)
return true;
@@ -2498,10 +2499,8 @@ static bool slic_mac_filter(struct adapter *adapter,
struct mcast_address *mcaddr = adapter->mcastaddrs;
while (mcaddr) {
- ETHER_EQ_ADDR(mcaddr->address,
- ether_frame->ether_dhost,
- equaladdr);
- if (equaladdr) {
+ if (!compare_ether_addr(mcaddr->address,
+ ether_frame->ether_dhost)) {
adapter->rcv_multicasts++;
adapter->stats.multicast++;
return true;
@@ -2523,7 +2522,7 @@ static bool slic_mac_filter(struct adapter *adapter,
static int slic_mac_set_address(struct net_device *dev, void *ptr)
{
- struct adapter *adapter = (struct adapter *)netdev_priv(dev);
+ struct adapter *adapter = netdev_priv(dev);
struct sockaddr *addr = ptr;
if (netif_running(dev))
@@ -2531,6 +2530,9 @@ static int slic_mac_set_address(struct net_device *dev, void *ptr)
if (!adapter)
return -EBUSY;
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
memcpy(adapter->currmacaddr, addr->sa_data, dev->addr_len);
@@ -3968,10 +3970,8 @@ static void slic_debug_adapter_create(struct adapter *adapter)
static void slic_debug_adapter_destroy(struct adapter *adapter)
{
- if (adapter->debugfs_entry) {
- debugfs_remove(adapter->debugfs_entry);
- adapter->debugfs_entry = NULL;
- }
+ debugfs_remove(adapter->debugfs_entry);
+ adapter->debugfs_entry = NULL;
}
static void slic_debug_card_create(struct sliccard *card)
diff --git a/drivers/staging/sm7xx/Kconfig b/drivers/staging/sm7xx/Kconfig
index 204dbfc3c38b..315102c7fed1 100644
--- a/drivers/staging/sm7xx/Kconfig
+++ b/drivers/staging/sm7xx/Kconfig
@@ -6,10 +6,3 @@ config FB_SM7XX
select FB_CFB_IMAGEBLIT
help
Frame Buffer driver for the Silicon Motion SM7XX serial graphic card.
-
-config FB_SM7XX_ACCEL
- bool "Siliconmotion Acceleration functions (EXPERIMENTAL)"
- depends on FB_SM7XX && EXPERIMENTAL
- help
- This will compile the Trident frame buffer device with
- acceleration functions.
diff --git a/drivers/staging/sm7xx/TODO b/drivers/staging/sm7xx/TODO
index 1f61f5e11cf5..a66d9e406497 100644
--- a/drivers/staging/sm7xx/TODO
+++ b/drivers/staging/sm7xx/TODO
@@ -1,5 +1,6 @@
TODO:
- Dual head support
+- 2D acceleration support
- use kernel coding style
- checkpatch.pl clean
- refine the code and remove unused code
diff --git a/drivers/staging/sm7xx/smtc2d.c b/drivers/staging/sm7xx/smtc2d.c
deleted file mode 100644
index 133b86c6a678..000000000000
--- a/drivers/staging/sm7xx/smtc2d.c
+++ /dev/null
@@ -1,979 +0,0 @@
-/*
- * Silicon Motion SM7XX 2D drawing engine functions.
- *
- * Copyright (C) 2006 Silicon Motion Technology Corp.
- * Author: Boyod boyod.yang@siliconmotion.com.cn
- *
- * Copyright (C) 2009 Lemote, Inc.
- * Author: Wu Zhangjin, wuzj@lemote.com
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- *
- * Version 0.10.26192.21.01
- * - Add PowerPC support
- * - Add 2D support for Lynx -
- * Verified on 2.6.19.2
- * Boyod.yang <boyod.yang@siliconmotion.com.cn>
- */
-
-unsigned char smtc_de_busy;
-
-void SMTC_write2Dreg(unsigned long nOffset, unsigned long nData)
-{
- writel(nData, smtc_2DBaseAddress + nOffset);
-}
-
-unsigned long SMTC_read2Dreg(unsigned long nOffset)
-{
- return readl(smtc_2DBaseAddress + nOffset);
-}
-
-void SMTC_write2Ddataport(unsigned long nOffset, unsigned long nData)
-{
- writel(nData, smtc_2Ddataport + nOffset);
-}
-
-/**********************************************************************
- *
- * deInit
- *
- * Purpose
- * Drawing engine initialization.
- *
- **********************************************************************/
-
-void deInit(unsigned int nModeWidth, unsigned int nModeHeight,
- unsigned int bpp)
-{
- /* Get current power configuration. */
- unsigned char clock;
- clock = smtc_seqr(0x21);
-
- /* initialize global 'mutex lock' variable */
- smtc_de_busy = 0;
-
- /* Enable 2D Drawing Engine */
- smtc_seqw(0x21, clock & 0xF8);
-
- SMTC_write2Dreg(DE_CLIP_TL,
- FIELD_VALUE(0, DE_CLIP_TL, TOP, 0) |
- FIELD_SET(0, DE_CLIP_TL, STATUS, DISABLE) |
- FIELD_SET(0, DE_CLIP_TL, INHIBIT, OUTSIDE) |
- FIELD_VALUE(0, DE_CLIP_TL, LEFT, 0));
-
- if (bpp >= 24) {
- SMTC_write2Dreg(DE_PITCH,
- FIELD_VALUE(0, DE_PITCH, DESTINATION,
- nModeWidth * 3) | FIELD_VALUE(0,
- DE_PITCH,
- SOURCE,
- nModeWidth
- * 3));
- } else {
- SMTC_write2Dreg(DE_PITCH,
- FIELD_VALUE(0, DE_PITCH, DESTINATION,
- nModeWidth) | FIELD_VALUE(0,
- DE_PITCH,
- SOURCE,
- nModeWidth));
- }
-
- SMTC_write2Dreg(DE_WINDOW_WIDTH,
- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
- nModeWidth) | FIELD_VALUE(0,
- DE_WINDOW_WIDTH,
- SOURCE,
- nModeWidth));
-
- switch (bpp) {
- case 8:
- SMTC_write2Dreg(DE_STRETCH_FORMAT,
- FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
- NORMAL) | FIELD_VALUE(0,
- DE_STRETCH_FORMAT,
- PATTERN_Y,
- 0) |
- FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
- 0) | FIELD_SET(0, DE_STRETCH_FORMAT,
- PIXEL_FORMAT,
- 8) | FIELD_SET(0,
- DE_STRETCH_FORMAT,
- ADDRESSING,
- XY) |
- FIELD_VALUE(0, DE_STRETCH_FORMAT,
- SOURCE_HEIGHT, 3));
- break;
- case 24:
- SMTC_write2Dreg(DE_STRETCH_FORMAT,
- FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
- NORMAL) | FIELD_VALUE(0,
- DE_STRETCH_FORMAT,
- PATTERN_Y,
- 0) |
- FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
- 0) | FIELD_SET(0, DE_STRETCH_FORMAT,
- PIXEL_FORMAT,
- 24) | FIELD_SET(0,
- DE_STRETCH_FORMAT,
- ADDRESSING,
- XY) |
- FIELD_VALUE(0, DE_STRETCH_FORMAT,
- SOURCE_HEIGHT, 3));
- break;
- case 16:
- default:
- SMTC_write2Dreg(DE_STRETCH_FORMAT,
- FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
- NORMAL) | FIELD_VALUE(0,
- DE_STRETCH_FORMAT,
- PATTERN_Y,
- 0) |
- FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
- 0) | FIELD_SET(0, DE_STRETCH_FORMAT,
- PIXEL_FORMAT,
- 16) | FIELD_SET(0,
- DE_STRETCH_FORMAT,
- ADDRESSING,
- XY) |
- FIELD_VALUE(0, DE_STRETCH_FORMAT,
- SOURCE_HEIGHT, 3));
- break;
- }
-
- SMTC_write2Dreg(DE_MASKS,
- FIELD_VALUE(0, DE_MASKS, BYTE_MASK, 0xFFFF) |
- FIELD_VALUE(0, DE_MASKS, BIT_MASK, 0xFFFF));
- SMTC_write2Dreg(DE_COLOR_COMPARE_MASK,
- FIELD_VALUE(0, DE_COLOR_COMPARE_MASK, MASKS, \
- 0xFFFFFF));
- SMTC_write2Dreg(DE_COLOR_COMPARE,
- FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR, 0xFFFFFF));
-}
-
-void deVerticalLine(unsigned long dst_base,
- unsigned long dst_pitch,
- unsigned long nX,
- unsigned long nY,
- unsigned long dst_height, unsigned long nColor)
-{
- deWaitForNotBusy();
-
- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
- FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
- dst_base));
-
- SMTC_write2Dreg(DE_PITCH,
- FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) |
- FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch));
-
- SMTC_write2Dreg(DE_WINDOW_WIDTH,
- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
- dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH,
- SOURCE,
- dst_pitch));
-
- SMTC_write2Dreg(DE_FOREGROUND,
- FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
-
- SMTC_write2Dreg(DE_DESTINATION,
- FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
- FIELD_VALUE(0, DE_DESTINATION, X, nX) |
- FIELD_VALUE(0, DE_DESTINATION, Y, nY));
-
- SMTC_write2Dreg(DE_DIMENSION,
- FIELD_VALUE(0, DE_DIMENSION, X, 1) |
- FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
-
- SMTC_write2Dreg(DE_CONTROL,
- FIELD_SET(0, DE_CONTROL, STATUS, START) |
- FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
- FIELD_SET(0, DE_CONTROL, MAJOR, Y) |
- FIELD_SET(0, DE_CONTROL, STEP_X, NEGATIVE) |
- FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) |
- FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
- FIELD_SET(0, DE_CONTROL, COMMAND, SHORT_STROKE) |
- FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
- FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C));
-
- smtc_de_busy = 1;
-}
-
-void deHorizontalLine(unsigned long dst_base,
- unsigned long dst_pitch,
- unsigned long nX,
- unsigned long nY,
- unsigned long dst_width, unsigned long nColor)
-{
- deWaitForNotBusy();
-
- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
- FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
- dst_base));
-
- SMTC_write2Dreg(DE_PITCH,
- FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) |
- FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch));
-
- SMTC_write2Dreg(DE_WINDOW_WIDTH,
- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
- dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH,
- SOURCE,
- dst_pitch));
- SMTC_write2Dreg(DE_FOREGROUND,
- FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
- SMTC_write2Dreg(DE_DESTINATION,
- FIELD_SET(0, DE_DESTINATION, WRAP,
- DISABLE) | FIELD_VALUE(0, DE_DESTINATION, X,
- nX) | FIELD_VALUE(0,
- DE_DESTINATION,
- Y,
- nY));
- SMTC_write2Dreg(DE_DIMENSION,
- FIELD_VALUE(0, DE_DIMENSION, X,
- dst_width) | FIELD_VALUE(0, DE_DIMENSION,
- Y_ET, 1));
- SMTC_write2Dreg(DE_CONTROL,
- FIELD_SET(0, DE_CONTROL, STATUS, START) | FIELD_SET(0,
- DE_CONTROL,
- DIRECTION,
- RIGHT_TO_LEFT)
- | FIELD_SET(0, DE_CONTROL, MAJOR, X) | FIELD_SET(0,
- DE_CONTROL,
- STEP_X,
- POSITIVE)
- | FIELD_SET(0, DE_CONTROL, STEP_Y,
- NEGATIVE) | FIELD_SET(0, DE_CONTROL,
- LAST_PIXEL,
- OFF) | FIELD_SET(0,
- DE_CONTROL,
- COMMAND,
- SHORT_STROKE)
- | FIELD_SET(0, DE_CONTROL, ROP_SELECT,
- ROP2) | FIELD_VALUE(0, DE_CONTROL, ROP,
- 0x0C));
-
- smtc_de_busy = 1;
-}
-
-void deLine(unsigned long dst_base,
- unsigned long dst_pitch,
- unsigned long nX1,
- unsigned long nY1,
- unsigned long nX2, unsigned long nY2, unsigned long nColor)
-{
- unsigned long nCommand =
- FIELD_SET(0, DE_CONTROL, STATUS, START) |
- FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
- FIELD_SET(0, DE_CONTROL, MAJOR, X) |
- FIELD_SET(0, DE_CONTROL, STEP_X, POSITIVE) |
- FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) |
- FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
- FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
- FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C);
- unsigned long DeltaX;
- unsigned long DeltaY;
-
- /* Calculate delta X */
- if (nX1 <= nX2)
- DeltaX = nX2 - nX1;
- else {
- DeltaX = nX1 - nX2;
- nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_X, NEGATIVE);
- }
-
- /* Calculate delta Y */
- if (nY1 <= nY2)
- DeltaY = nY2 - nY1;
- else {
- DeltaY = nY1 - nY2;
- nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_Y, NEGATIVE);
- }
-
- /* Determine the major axis */
- if (DeltaX < DeltaY)
- nCommand = FIELD_SET(nCommand, DE_CONTROL, MAJOR, Y);
-
- /* Vertical line? */
- if (nX1 == nX2)
- deVerticalLine(dst_base, dst_pitch, nX1, nY1, DeltaY, nColor);
-
- /* Horizontal line? */
- else if (nY1 == nY2)
- deHorizontalLine(dst_base, dst_pitch, nX1, nY1, \
- DeltaX, nColor);
-
- /* Diagonal line? */
- else if (DeltaX == DeltaY) {
- deWaitForNotBusy();
-
- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
- FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE,
- ADDRESS, dst_base));
-
- SMTC_write2Dreg(DE_PITCH,
- FIELD_VALUE(0, DE_PITCH, DESTINATION,
- dst_pitch) | FIELD_VALUE(0,
- DE_PITCH,
- SOURCE,
- dst_pitch));
-
- SMTC_write2Dreg(DE_WINDOW_WIDTH,
- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
- dst_pitch) | FIELD_VALUE(0,
- DE_WINDOW_WIDTH,
- SOURCE,
- dst_pitch));
-
- SMTC_write2Dreg(DE_FOREGROUND,
- FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
-
- SMTC_write2Dreg(DE_DESTINATION,
- FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
- FIELD_VALUE(0, DE_DESTINATION, X, 1) |
- FIELD_VALUE(0, DE_DESTINATION, Y, nY1));
-
- SMTC_write2Dreg(DE_DIMENSION,
- FIELD_VALUE(0, DE_DIMENSION, X, 1) |
- FIELD_VALUE(0, DE_DIMENSION, Y_ET, DeltaX));
-
- SMTC_write2Dreg(DE_CONTROL,
- FIELD_SET(nCommand, DE_CONTROL, COMMAND,
- SHORT_STROKE));
- }
-
- /* Generic line */
- else {
- unsigned int k1, k2, et, w;
- if (DeltaX < DeltaY) {
- k1 = 2 * DeltaX;
- et = k1 - DeltaY;
- k2 = et - DeltaY;
- w = DeltaY + 1;
- } else {
- k1 = 2 * DeltaY;
- et = k1 - DeltaX;
- k2 = et - DeltaX;
- w = DeltaX + 1;
- }
-
- deWaitForNotBusy();
-
- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
- FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE,
- ADDRESS, dst_base));
-
- SMTC_write2Dreg(DE_PITCH,
- FIELD_VALUE(0, DE_PITCH, DESTINATION,
- dst_pitch) | FIELD_VALUE(0,
- DE_PITCH,
- SOURCE,
- dst_pitch));
-
- SMTC_write2Dreg(DE_WINDOW_WIDTH,
- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
- dst_pitch) | FIELD_VALUE(0,
- DE_WINDOW_WIDTH,
- SOURCE,
- dst_pitch));
-
- SMTC_write2Dreg(DE_FOREGROUND,
- FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
-
- SMTC_write2Dreg(DE_SOURCE,
- FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
- FIELD_VALUE(0, DE_SOURCE, X_K1, k1) |
- FIELD_VALUE(0, DE_SOURCE, Y_K2, k2));
-
- SMTC_write2Dreg(DE_DESTINATION,
- FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
- FIELD_VALUE(0, DE_DESTINATION, X, nX1) |
- FIELD_VALUE(0, DE_DESTINATION, Y, nY1));
-
- SMTC_write2Dreg(DE_DIMENSION,
- FIELD_VALUE(0, DE_DIMENSION, X, w) |
- FIELD_VALUE(0, DE_DIMENSION, Y_ET, et));
-
- SMTC_write2Dreg(DE_CONTROL,
- FIELD_SET(nCommand, DE_CONTROL, COMMAND,
- LINE_DRAW));
- }
-
- smtc_de_busy = 1;
-}
-
-void deFillRect(unsigned long dst_base,
- unsigned long dst_pitch,
- unsigned long dst_X,
- unsigned long dst_Y,
- unsigned long dst_width,
- unsigned long dst_height, unsigned long nColor)
-{
- deWaitForNotBusy();
-
- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
- FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
- dst_base));
-
- if (dst_pitch) {
- SMTC_write2Dreg(DE_PITCH,
- FIELD_VALUE(0, DE_PITCH, DESTINATION,
- dst_pitch) | FIELD_VALUE(0,
- DE_PITCH,
- SOURCE,
- dst_pitch));
-
- SMTC_write2Dreg(DE_WINDOW_WIDTH,
- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
- dst_pitch) | FIELD_VALUE(0,
- DE_WINDOW_WIDTH,
- SOURCE,
- dst_pitch));
- }
-
- SMTC_write2Dreg(DE_FOREGROUND,
- FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
-
- SMTC_write2Dreg(DE_DESTINATION,
- FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
- FIELD_VALUE(0, DE_DESTINATION, X, dst_X) |
- FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y));
-
- SMTC_write2Dreg(DE_DIMENSION,
- FIELD_VALUE(0, DE_DIMENSION, X, dst_width) |
- FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
-
- SMTC_write2Dreg(DE_CONTROL,
- FIELD_SET(0, DE_CONTROL, STATUS, START) |
- FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
- FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
- FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL) |
- FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
- FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C));
-
- smtc_de_busy = 1;
-}
-
-/**********************************************************************
- *
- * deRotatePattern
- *
- * Purpose
- * Rotate the given pattern if necessary
- *
- * Parameters
- * [in]
- * pPattern - Pointer to DE_SURFACE structure containing
- * pattern attributes
- * patternX - X position (0-7) of pattern origin
- * patternY - Y position (0-7) of pattern origin
- *
- * [out]
- * pattern_dstaddr - Pointer to pre-allocated buffer containing
- * rotated pattern
- *
- **********************************************************************/
-void deRotatePattern(unsigned char *pattern_dstaddr,
- unsigned long pattern_src_addr,
- unsigned long pattern_BPP,
- unsigned long pattern_stride, int patternX, int patternY)
-{
- unsigned int i;
- unsigned long pattern[PATTERN_WIDTH * PATTERN_HEIGHT];
- unsigned int x, y;
- unsigned char *pjPatByte;
-
- if (pattern_dstaddr != NULL) {
- deWaitForNotBusy();
-
- if (patternX || patternY) {
- /* Rotate pattern */
- pjPatByte = (unsigned char *)pattern;
-
- switch (pattern_BPP) {
- case 8:
- {
- for (y = 0; y < 8; y++) {
- unsigned char *pjBuffer =
- pattern_dstaddr +
- ((patternY + y) & 7) * 8;
- for (x = 0; x < 8; x++) {
- pjBuffer[(patternX +
- x) & 7] =
- pjPatByte[x];
- }
- pjPatByte += pattern_stride;
- }
- break;
- }
-
- case 16:
- {
- for (y = 0; y < 8; y++) {
- unsigned short *pjBuffer =
- (unsigned short *)
- pattern_dstaddr +
- ((patternY + y) & 7) * 8;
- for (x = 0; x < 8; x++) {
- pjBuffer[(patternX +
- x) & 7] =
- ((unsigned short *)
- pjPatByte)[x];
- }
- pjPatByte += pattern_stride;
- }
- break;
- }
-
- case 32:
- {
- for (y = 0; y < 8; y++) {
- unsigned long *pjBuffer =
- (unsigned long *)
- pattern_dstaddr +
- ((patternY + y) & 7) * 8;
- for (x = 0; x < 8; x++) {
- pjBuffer[(patternX +
- x) & 7] =
- ((unsigned long *)
- pjPatByte)[x];
- }
- pjPatByte += pattern_stride;
- }
- break;
- }
- }
- } else {
- /*Don't rotate,just copy pattern into pattern_dstaddr*/
- for (i = 0; i < (pattern_BPP * 2); i++) {
- ((unsigned long *)pattern_dstaddr)[i] =
- pattern[i];
- }
- }
-
- }
-}
-
-/**********************************************************************
- *
- * deCopy
- *
- * Purpose
- * Copy a rectangular area of the source surface to a destination surface
- *
- * Remarks
- * Source bitmap must have the same color depth (BPP) as the destination
- * bitmap.
- *
-**********************************************************************/
-void deCopy(unsigned long dst_base,
- unsigned long dst_pitch,
- unsigned long dst_BPP,
- unsigned long dst_X,
- unsigned long dst_Y,
- unsigned long dst_width,
- unsigned long dst_height,
- unsigned long src_base,
- unsigned long src_pitch,
- unsigned long src_X,
- unsigned long src_Y, pTransparent pTransp, unsigned char nROP2)
-{
- unsigned long nDirection = 0;
- unsigned long nTransparent = 0;
- /* Direction of ROP2 operation:
- * 1 = Left to Right,
- * (-1) = Right to Left
- */
- unsigned long opSign = 1;
- /* xWidth is in pixels */
- unsigned long xWidth = 192 / (dst_BPP / 8);
- unsigned long de_ctrl = 0;
-
- deWaitForNotBusy();
-
- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
- FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
- dst_base));
-
- SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE,
- FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS,
- src_base));
-
- if (dst_pitch && src_pitch) {
- SMTC_write2Dreg(DE_PITCH,
- FIELD_VALUE(0, DE_PITCH, DESTINATION,
- dst_pitch) | FIELD_VALUE(0,
- DE_PITCH,
- SOURCE,
- src_pitch));
-
- SMTC_write2Dreg(DE_WINDOW_WIDTH,
- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
- dst_pitch) | FIELD_VALUE(0,
- DE_WINDOW_WIDTH,
- SOURCE,
- src_pitch));
- }
-
- /* Set transparent bits if necessary */
- if (pTransp != NULL) {
- nTransparent =
- pTransp->match | pTransp->select | pTransp->control;
-
- /* Set color compare register */
- SMTC_write2Dreg(DE_COLOR_COMPARE,
- FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR,
- pTransp->color));
- }
-
- /* Determine direction of operation */
- if (src_Y < dst_Y) {
- /* +----------+
- |S |
- | +----------+
- | | | |
- | | | |
- +---|------+ |
- | D |
- +----------+ */
-
- nDirection = BOTTOM_TO_TOP;
- } else if (src_Y > dst_Y) {
- /* +----------+
- |D |
- | +----------+
- | | | |
- | | | |
- +---|------+ |
- | S |
- +----------+ */
-
- nDirection = TOP_TO_BOTTOM;
- } else {
- /* src_Y == dst_Y */
-
- if (src_X <= dst_X) {
- /* +------+---+------+
- |S | | D|
- | | | |
- | | | |
- | | | |
- +------+---+------+ */
-
- nDirection = RIGHT_TO_LEFT;
- } else {
- /* src_X > dst_X */
-
- /* +------+---+------+
- |D | | S|
- | | | |
- | | | |
- | | | |
- +------+---+------+ */
-
- nDirection = LEFT_TO_RIGHT;
- }
- }
-
- if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) {
- src_X += dst_width - 1;
- src_Y += dst_height - 1;
- dst_X += dst_width - 1;
- dst_Y += dst_height - 1;
- opSign = (-1);
- }
-
- if (dst_BPP >= 24) {
- src_X *= 3;
- src_Y *= 3;
- dst_X *= 3;
- dst_Y *= 3;
- dst_width *= 3;
- if ((nDirection == BOTTOM_TO_TOP)
- || (nDirection == RIGHT_TO_LEFT)) {
- src_X += 2;
- dst_X += 2;
- }
- }
-
- /* Workaround for 192 byte hw bug */
- if ((nROP2 != 0x0C) && ((dst_width * (dst_BPP / 8)) >= 192)) {
- /*
- * Perform the ROP2 operation in chunks of (xWidth *
- * dst_height)
- */
- while (1) {
- deWaitForNotBusy();
-
- SMTC_write2Dreg(DE_SOURCE,
- FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
- FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) |
- FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y));
-
- SMTC_write2Dreg(DE_DESTINATION,
- FIELD_SET(0, DE_DESTINATION, WRAP,
- DISABLE) | FIELD_VALUE(0,
- DE_DESTINATION,
- X,
- dst_X)
- | FIELD_VALUE(0, DE_DESTINATION, Y,
- dst_Y));
-
- SMTC_write2Dreg(DE_DIMENSION,
- FIELD_VALUE(0, DE_DIMENSION, X,
- xWidth) | FIELD_VALUE(0,
- DE_DIMENSION,
- Y_ET,
- dst_height));
-
- de_ctrl =
- FIELD_VALUE(0, DE_CONTROL, ROP,
- nROP2) | nTransparent | FIELD_SET(0,
- DE_CONTROL,
- ROP_SELECT,
- ROP2)
- | FIELD_SET(0, DE_CONTROL, COMMAND,
- BITBLT) | ((nDirection ==
- 1) ? FIELD_SET(0,
- DE_CONTROL,
- DIRECTION,
- RIGHT_TO_LEFT)
- : FIELD_SET(0, DE_CONTROL,
- DIRECTION,
- LEFT_TO_RIGHT)) |
- FIELD_SET(0, DE_CONTROL, STATUS, START);
-
- SMTC_write2Dreg(DE_CONTROL, de_ctrl);
-
- src_X += (opSign * xWidth);
- dst_X += (opSign * xWidth);
- dst_width -= xWidth;
-
- if (dst_width <= 0) {
- /* ROP2 operation is complete */
- break;
- }
-
- if (xWidth > dst_width)
- xWidth = dst_width;
- }
- } else {
- deWaitForNotBusy();
- SMTC_write2Dreg(DE_SOURCE,
- FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
- FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) |
- FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y));
-
- SMTC_write2Dreg(DE_DESTINATION,
- FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
- FIELD_VALUE(0, DE_DESTINATION, X, dst_X) |
- FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y));
-
- SMTC_write2Dreg(DE_DIMENSION,
- FIELD_VALUE(0, DE_DIMENSION, X, dst_width) |
- FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
-
- de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, nROP2) |
- nTransparent |
- FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
- FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
- ((nDirection == 1) ? FIELD_SET(0, DE_CONTROL, DIRECTION,
- RIGHT_TO_LEFT)
- : FIELD_SET(0, DE_CONTROL, DIRECTION,
- LEFT_TO_RIGHT)) | FIELD_SET(0, DE_CONTROL,
- STATUS, START);
- SMTC_write2Dreg(DE_CONTROL, de_ctrl);
- }
-
- smtc_de_busy = 1;
-}
-
-/*
- * This function sets the pixel format that will apply to the 2D Engine.
- */
-void deSetPixelFormat(unsigned long bpp)
-{
- unsigned long de_format;
-
- de_format = SMTC_read2Dreg(DE_STRETCH_FORMAT);
-
- switch (bpp) {
- case 8:
- de_format =
- FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 8);
- break;
- default:
- case 16:
- de_format =
- FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 16);
- break;
- case 32:
- de_format =
- FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 32);
- break;
- }
-
- SMTC_write2Dreg(DE_STRETCH_FORMAT, de_format);
-}
-
-/*
- * System memory to Video memory monochrome expansion.
- *
- * Source is monochrome image in system memory. This function expands the
- * monochrome data to color image in video memory.
- */
-
-long deSystemMem2VideoMemMonoBlt(const char *pSrcbuf,
- long srcDelta,
- unsigned long startBit,
- unsigned long dBase,
- unsigned long dPitch,
- unsigned long bpp,
- unsigned long dx, unsigned long dy,
- unsigned long width, unsigned long height,
- unsigned long fColor,
- unsigned long bColor,
- unsigned long rop2) {
- unsigned long bytePerPixel;
- unsigned long ulBytesPerScan;
- unsigned long ul4BytesPerScan;
- unsigned long ulBytesRemain;
- unsigned long de_ctrl = 0;
- unsigned char ajRemain[4];
- long i, j;
-
- bytePerPixel = bpp / 8;
-
- /* Just make sure the start bit is within legal range */
- startBit &= 7;
-
- ulBytesPerScan = (width + startBit + 7) / 8;
- ul4BytesPerScan = ulBytesPerScan & ~3;
- ulBytesRemain = ulBytesPerScan & 3;
-
- if (smtc_de_busy)
- deWaitForNotBusy();
-
- /*
- * 2D Source Base. Use 0 for HOST Blt.
- */
-
- SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE, 0);
-
- /*
- * 2D Destination Base.
- *
- * It is an address offset (128 bit aligned) from the beginning of
- * frame buffer.
- */
-
- SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, dBase);
-
- if (dPitch) {
-
- /*
- * Program pitch (distance between the 1st points of two
- * adjacent lines).
- *
- * Note that input pitch is BYTE value, but the 2D Pitch
- * register uses pixel values. Need Byte to pixel convertion.
- */
-
- SMTC_write2Dreg(DE_PITCH,
- FIELD_VALUE(0, DE_PITCH, DESTINATION,
- dPitch /
- bytePerPixel) | FIELD_VALUE(0,
- DE_PITCH,
- SOURCE,
- dPitch /
- bytePerPixel));
-
- /* Screen Window width in Pixels.
- *
- * 2D engine uses this value to calculate the linear address in
- * frame buffer for a given point.
- */
-
- SMTC_write2Dreg(DE_WINDOW_WIDTH,
- FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
- (dPitch /
- bytePerPixel)) | FIELD_VALUE(0,
- DE_WINDOW_WIDTH,
- SOURCE,
- (dPitch
- /
- bytePerPixel)));
- }
- /* Note: For 2D Source in Host Write, only X_K1 field is needed, and
- * Y_K2 field is not used. For mono bitmap, use startBit for X_K1.
- */
-
- SMTC_write2Dreg(DE_SOURCE,
- FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
- FIELD_VALUE(0, DE_SOURCE, X_K1, startBit) |
- FIELD_VALUE(0, DE_SOURCE, Y_K2, 0));
-
- SMTC_write2Dreg(DE_DESTINATION,
- FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
- FIELD_VALUE(0, DE_DESTINATION, X, dx) |
- FIELD_VALUE(0, DE_DESTINATION, Y, dy));
-
- SMTC_write2Dreg(DE_DIMENSION,
- FIELD_VALUE(0, DE_DIMENSION, X, width) |
- FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
-
- SMTC_write2Dreg(DE_FOREGROUND, fColor);
- SMTC_write2Dreg(DE_BACKGROUND, bColor);
-
- if (bpp)
- deSetPixelFormat(bpp);
- /* Set the pixel format of the destination */
-
- de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
- FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
- FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
- FIELD_SET(0, DE_CONTROL, HOST, MONO) |
- FIELD_SET(0, DE_CONTROL, STATUS, START);
-
- SMTC_write2Dreg(DE_CONTROL, de_ctrl | deGetTransparency());
-
- /* Write MONO data (line by line) to 2D Engine data port */
- for (i = 0; i < height; i++) {
- /* For each line, send the data in chunks of 4 bytes */
- for (j = 0; j < (ul4BytesPerScan / 4); j++)
- SMTC_write2Ddataport(0,
- *(unsigned long *)(pSrcbuf +
- (j * 4)));
-
- if (ulBytesRemain) {
- memcpy(ajRemain, pSrcbuf + ul4BytesPerScan,
- ulBytesRemain);
- SMTC_write2Ddataport(0, *(unsigned long *)ajRemain);
- }
-
- pSrcbuf += srcDelta;
- }
- smtc_de_busy = 1;
-
- return 0;
-}
-
-/*
- * This function gets the transparency status from DE_CONTROL register.
- * It returns a double word with the transparent fields properly set,
- * while other fields are 0.
- */
-unsigned long deGetTransparency(void)
-{
- unsigned long de_ctrl;
-
- de_ctrl = SMTC_read2Dreg(DE_CONTROL);
-
- de_ctrl &=
- FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) |
- FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT) |
- FIELD_MASK(DE_CONTROL_TRANSPARENCY);
-
- return de_ctrl;
-}
diff --git a/drivers/staging/sm7xx/smtc2d.h b/drivers/staging/sm7xx/smtc2d.h
deleted file mode 100644
index 38d0c335322b..000000000000
--- a/drivers/staging/sm7xx/smtc2d.h
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Silicon Motion SM712 2D drawing engine functions.
- *
- * Copyright (C) 2006 Silicon Motion Technology Corp.
- * Author: Ge Wang, gewang@siliconmotion.com
- *
- * Copyright (C) 2009 Lemote, Inc.
- * Author: Wu Zhangjin, wuzj@lemote.com
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- */
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-/* Internal macros */
-
-#define _F_START(f) (0 ? f)
-#define _F_END(f) (1 ? f)
-#define _F_SIZE(f) (1 + _F_END(f) - _F_START(f))
-#define _F_MASK(f) (((1ULL << _F_SIZE(f)) - 1) << _F_START(f))
-#define _F_NORMALIZE(v, f) (((v) & _F_MASK(f)) >> _F_START(f))
-#define _F_DENORMALIZE(v, f) (((v) << _F_START(f)) & _F_MASK(f))
-
-/* Global macros */
-
-#define FIELD_GET(x, reg, field) \
-( \
- _F_NORMALIZE((x), reg ## _ ## field) \
-)
-
-#define FIELD_SET(x, reg, field, value) \
-( \
- (x & ~_F_MASK(reg ## _ ## field)) \
- | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \
-)
-
-#define FIELD_VALUE(x, reg, field, value) \
-( \
- (x & ~_F_MASK(reg ## _ ## field)) \
- | _F_DENORMALIZE(value, reg ## _ ## field) \
-)
-
-#define FIELD_CLEAR(reg, field) \
-( \
- ~_F_MASK(reg ## _ ## field) \
-)
-
-/* Field Macros */
-
-#define FIELD_START(field) (0 ? field)
-#define FIELD_END(field) (1 ? field)
-#define FIELD_SIZE(field) \
- (1 + FIELD_END(field) - FIELD_START(field))
-
-#define FIELD_MASK(field) \
- (((1 << (FIELD_SIZE(field)-1)) \
- | ((1 << (FIELD_SIZE(field)-1)) - 1)) \
- << FIELD_START(field))
-
-#define FIELD_NORMALIZE(reg, field) \
- (((reg) & FIELD_MASK(field)) >> FIELD_START(field))
-
-#define FIELD_DENORMALIZE(field, value) \
- (((value) << FIELD_START(field)) & FIELD_MASK(field))
-
-#define FIELD_INIT(reg, field, value) \
- FIELD_DENORMALIZE(reg ## _ ## field, \
- reg ## _ ## field ## _ ## value)
-
-#define FIELD_INIT_VAL(reg, field, value) \
- (FIELD_DENORMALIZE(reg ## _ ## field, value))
-
-#define FIELD_VAL_SET(x, r, f, v) ({ \
- x = (x & ~FIELD_MASK(r ## _ ## f)) \
- | FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v) \
-})
-
-#define RGB(r, g, b) ((unsigned long)(((r) << 16) | ((g) << 8) | (b)))
-
-/* Transparent info definition */
-typedef struct {
- unsigned long match; /* Matching pixel is OPAQUE/TRANSPARENT */
- unsigned long select; /* Transparency controlled by SRC/DST */
- unsigned long control; /* ENABLE/DISABLE transparency */
- unsigned long color; /* Transparent color */
-} Transparent, *pTransparent;
-
-#define PIXEL_DEPTH_1_BP 0 /* 1 bit per pixel */
-#define PIXEL_DEPTH_8_BPP 1 /* 8 bits per pixel */
-#define PIXEL_DEPTH_16_BPP 2 /* 16 bits per pixel */
-#define PIXEL_DEPTH_32_BPP 3 /* 32 bits per pixel */
-#define PIXEL_DEPTH_YUV422 8 /* 16 bits per pixel YUV422 */
-#define PIXEL_DEPTH_YUV420 9 /* 16 bits per pixel YUV420 */
-
-#define PATTERN_WIDTH 8
-#define PATTERN_HEIGHT 8
-
-#define TOP_TO_BOTTOM 0
-#define BOTTOM_TO_TOP 1
-#define RIGHT_TO_LEFT BOTTOM_TO_TOP
-#define LEFT_TO_RIGHT TOP_TO_BOTTOM
-
-/* Constants used in Transparent structure */
-#define MATCH_OPAQUE 0x00000000
-#define MATCH_TRANSPARENT 0x00000400
-#define SOURCE 0x00000000
-#define DESTINATION 0x00000200
-
-/* 2D registers. */
-
-#define DE_SOURCE 0x000000
-#define DE_SOURCE_WRAP 31 : 31
-#define DE_SOURCE_WRAP_DISABLE 0
-#define DE_SOURCE_WRAP_ENABLE 1
-#define DE_SOURCE_X_K1 29 : 16
-#define DE_SOURCE_Y_K2 15 : 0
-
-#define DE_DESTINATION 0x000004
-#define DE_DESTINATION_WRAP 31 : 31
-#define DE_DESTINATION_WRAP_DISABLE 0
-#define DE_DESTINATION_WRAP_ENABLE 1
-#define DE_DESTINATION_X 28 : 16
-#define DE_DESTINATION_Y 15 : 0
-
-#define DE_DIMENSION 0x000008
-#define DE_DIMENSION_X 28 : 16
-#define DE_DIMENSION_Y_ET 15 : 0
-
-#define DE_CONTROL 0x00000C
-#define DE_CONTROL_STATUS 31 : 31
-#define DE_CONTROL_STATUS_STOP 0
-#define DE_CONTROL_STATUS_START 1
-#define DE_CONTROL_PATTERN 30 : 30
-#define DE_CONTROL_PATTERN_MONO 0
-#define DE_CONTROL_PATTERN_COLOR 1
-#define DE_CONTROL_UPDATE_DESTINATION_X 29 : 29
-#define DE_CONTROL_UPDATE_DESTINATION_X_DISABLE 0
-#define DE_CONTROL_UPDATE_DESTINATION_X_ENABLE 1
-#define DE_CONTROL_QUICK_START 28 : 28
-#define DE_CONTROL_QUICK_START_DISABLE 0
-#define DE_CONTROL_QUICK_START_ENABLE 1
-#define DE_CONTROL_DIRECTION 27 : 27
-#define DE_CONTROL_DIRECTION_LEFT_TO_RIGHT 0
-#define DE_CONTROL_DIRECTION_RIGHT_TO_LEFT 1
-#define DE_CONTROL_MAJOR 26 : 26
-#define DE_CONTROL_MAJOR_X 0
-#define DE_CONTROL_MAJOR_Y 1
-#define DE_CONTROL_STEP_X 25 : 25
-#define DE_CONTROL_STEP_X_POSITIVE 1
-#define DE_CONTROL_STEP_X_NEGATIVE 0
-#define DE_CONTROL_STEP_Y 24 : 24
-#define DE_CONTROL_STEP_Y_POSITIVE 1
-#define DE_CONTROL_STEP_Y_NEGATIVE 0
-#define DE_CONTROL_STRETCH 23 : 23
-#define DE_CONTROL_STRETCH_DISABLE 0
-#define DE_CONTROL_STRETCH_ENABLE 1
-#define DE_CONTROL_HOST 22 : 22
-#define DE_CONTROL_HOST_COLOR 0
-#define DE_CONTROL_HOST_MONO 1
-#define DE_CONTROL_LAST_PIXEL 21 : 21
-#define DE_CONTROL_LAST_PIXEL_OFF 0
-#define DE_CONTROL_LAST_PIXEL_ON 1
-#define DE_CONTROL_COMMAND 20 : 16
-#define DE_CONTROL_COMMAND_BITBLT 0
-#define DE_CONTROL_COMMAND_RECTANGLE_FILL 1
-#define DE_CONTROL_COMMAND_DE_TILE 2
-#define DE_CONTROL_COMMAND_TRAPEZOID_FILL 3
-#define DE_CONTROL_COMMAND_ALPHA_BLEND 4
-#define DE_CONTROL_COMMAND_RLE_STRIP 5
-#define DE_CONTROL_COMMAND_SHORT_STROKE 6
-#define DE_CONTROL_COMMAND_LINE_DRAW 7
-#define DE_CONTROL_COMMAND_HOST_WRITE 8
-#define DE_CONTROL_COMMAND_HOST_READ 9
-#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP 10
-#define DE_CONTROL_COMMAND_ROTATE 11
-#define DE_CONTROL_COMMAND_FONT 12
-#define DE_CONTROL_COMMAND_TEXTURE_LOAD 15
-#define DE_CONTROL_ROP_SELECT 15 : 15
-#define DE_CONTROL_ROP_SELECT_ROP3 0
-#define DE_CONTROL_ROP_SELECT_ROP2 1
-#define DE_CONTROL_ROP2_SOURCE 14 : 14
-#define DE_CONTROL_ROP2_SOURCE_BITMAP 0
-#define DE_CONTROL_ROP2_SOURCE_PATTERN 1
-#define DE_CONTROL_MONO_DATA 13 : 12
-#define DE_CONTROL_MONO_DATA_NOT_PACKED 0
-#define DE_CONTROL_MONO_DATA_8_PACKED 1
-#define DE_CONTROL_MONO_DATA_16_PACKED 2
-#define DE_CONTROL_MONO_DATA_32_PACKED 3
-#define DE_CONTROL_REPEAT_ROTATE 11 : 11
-#define DE_CONTROL_REPEAT_ROTATE_DISABLE 0
-#define DE_CONTROL_REPEAT_ROTATE_ENABLE 1
-#define DE_CONTROL_TRANSPARENCY_MATCH 10 : 10
-#define DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE 0
-#define DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT 1
-#define DE_CONTROL_TRANSPARENCY_SELECT 9 : 9
-#define DE_CONTROL_TRANSPARENCY_SELECT_SOURCE 0
-#define DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION 1
-#define DE_CONTROL_TRANSPARENCY 8 : 8
-#define DE_CONTROL_TRANSPARENCY_DISABLE 0
-#define DE_CONTROL_TRANSPARENCY_ENABLE 1
-#define DE_CONTROL_ROP 7 : 0
-
-/* Pseudo fields. */
-
-#define DE_CONTROL_SHORT_STROKE_DIR 27 : 24
-#define DE_CONTROL_SHORT_STROKE_DIR_225 0
-#define DE_CONTROL_SHORT_STROKE_DIR_135 1
-#define DE_CONTROL_SHORT_STROKE_DIR_315 2
-#define DE_CONTROL_SHORT_STROKE_DIR_45 3
-#define DE_CONTROL_SHORT_STROKE_DIR_270 4
-#define DE_CONTROL_SHORT_STROKE_DIR_90 5
-#define DE_CONTROL_SHORT_STROKE_DIR_180 8
-#define DE_CONTROL_SHORT_STROKE_DIR_0 10
-#define DE_CONTROL_ROTATION 25 : 24
-#define DE_CONTROL_ROTATION_0 0
-#define DE_CONTROL_ROTATION_270 1
-#define DE_CONTROL_ROTATION_90 2
-#define DE_CONTROL_ROTATION_180 3
-
-#define DE_PITCH 0x000010
-#define DE_PITCH_DESTINATION 28 : 16
-#define DE_PITCH_SOURCE 12 : 0
-
-#define DE_FOREGROUND 0x000014
-#define DE_FOREGROUND_COLOR 31 : 0
-
-#define DE_BACKGROUND 0x000018
-#define DE_BACKGROUND_COLOR 31 : 0
-
-#define DE_STRETCH_FORMAT 0x00001C
-#define DE_STRETCH_FORMAT_PATTERN_XY 30 : 30
-#define DE_STRETCH_FORMAT_PATTERN_XY_NORMAL 0
-#define DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE 1
-#define DE_STRETCH_FORMAT_PATTERN_Y 29 : 27
-#define DE_STRETCH_FORMAT_PATTERN_X 25 : 23
-#define DE_STRETCH_FORMAT_PIXEL_FORMAT 21 : 20
-#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8 0
-#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16 1
-#define DE_STRETCH_FORMAT_PIXEL_FORMAT_24 3
-#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32 2
-#define DE_STRETCH_FORMAT_ADDRESSING 19 : 16
-#define DE_STRETCH_FORMAT_ADDRESSING_XY 0
-#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR 15
-#define DE_STRETCH_FORMAT_SOURCE_HEIGHT 11 : 0
-
-#define DE_COLOR_COMPARE 0x000020
-#define DE_COLOR_COMPARE_COLOR 23 : 0
-
-#define DE_COLOR_COMPARE_MASK 0x000024
-#define DE_COLOR_COMPARE_MASK_MASKS 23 : 0
-
-#define DE_MASKS 0x000028
-#define DE_MASKS_BYTE_MASK 31 : 16
-#define DE_MASKS_BIT_MASK 15 : 0
-
-#define DE_CLIP_TL 0x00002C
-#define DE_CLIP_TL_TOP 31 : 16
-#define DE_CLIP_TL_STATUS 13 : 13
-#define DE_CLIP_TL_STATUS_DISABLE 0
-#define DE_CLIP_TL_STATUS_ENABLE 1
-#define DE_CLIP_TL_INHIBIT 12 : 12
-#define DE_CLIP_TL_INHIBIT_OUTSIDE 0
-#define DE_CLIP_TL_INHIBIT_INSIDE 1
-#define DE_CLIP_TL_LEFT 11 : 0
-
-#define DE_CLIP_BR 0x000030
-#define DE_CLIP_BR_BOTTOM 31 : 16
-#define DE_CLIP_BR_RIGHT 12 : 0
-
-#define DE_MONO_PATTERN_LOW 0x000034
-#define DE_MONO_PATTERN_LOW_PATTERN 31 : 0
-
-#define DE_MONO_PATTERN_HIGH 0x000038
-#define DE_MONO_PATTERN_HIGH_PATTERN 31 : 0
-
-#define DE_WINDOW_WIDTH 0x00003C
-#define DE_WINDOW_WIDTH_DESTINATION 28 : 16
-#define DE_WINDOW_WIDTH_SOURCE 12 : 0
-
-#define DE_WINDOW_SOURCE_BASE 0x000040
-#define DE_WINDOW_SOURCE_BASE_EXT 27 : 27
-#define DE_WINDOW_SOURCE_BASE_EXT_LOCAL 0
-#define DE_WINDOW_SOURCE_BASE_EXT_EXTERNAL 1
-#define DE_WINDOW_SOURCE_BASE_CS 26 : 26
-#define DE_WINDOW_SOURCE_BASE_CS_0 0
-#define DE_WINDOW_SOURCE_BASE_CS_1 1
-#define DE_WINDOW_SOURCE_BASE_ADDRESS 25 : 0
-
-#define DE_WINDOW_DESTINATION_BASE 0x000044
-#define DE_WINDOW_DESTINATION_BASE_EXT 27 : 27
-#define DE_WINDOW_DESTINATION_BASE_EXT_LOCAL 0
-#define DE_WINDOW_DESTINATION_BASE_EXT_EXTERNAL 1
-#define DE_WINDOW_DESTINATION_BASE_CS 26 : 26
-#define DE_WINDOW_DESTINATION_BASE_CS_0 0
-#define DE_WINDOW_DESTINATION_BASE_CS_1 1
-#define DE_WINDOW_DESTINATION_BASE_ADDRESS 25 : 0
-
-#define DE_ALPHA 0x000048
-#define DE_ALPHA_VALUE 7 : 0
-
-#define DE_WRAP 0x00004C
-#define DE_WRAP_X 31 : 16
-#define DE_WRAP_Y 15 : 0
-
-#define DE_STATUS 0x000050
-#define DE_STATUS_CSC 1 : 1
-#define DE_STATUS_CSC_CLEAR 0
-#define DE_STATUS_CSC_NOT_ACTIVE 0
-#define DE_STATUS_CSC_ACTIVE 1
-#define DE_STATUS_2D 0 : 0
-#define DE_STATUS_2D_CLEAR 0
-#define DE_STATUS_2D_NOT_ACTIVE 0
-#define DE_STATUS_2D_ACTIVE 1
-
-/* Color Space Conversion registers. */
-
-#define CSC_Y_SOURCE_BASE 0x0000C8
-#define CSC_Y_SOURCE_BASE_EXT 27 : 27
-#define CSC_Y_SOURCE_BASE_EXT_LOCAL 0
-#define CSC_Y_SOURCE_BASE_EXT_EXTERNAL 1
-#define CSC_Y_SOURCE_BASE_CS 26 : 26
-#define CSC_Y_SOURCE_BASE_CS_0 0
-#define CSC_Y_SOURCE_BASE_CS_1 1
-#define CSC_Y_SOURCE_BASE_ADDRESS 25 : 0
-
-#define CSC_CONSTANTS 0x0000CC
-#define CSC_CONSTANTS_Y 31 : 24
-#define CSC_CONSTANTS_R 23 : 16
-#define CSC_CONSTANTS_G 15 : 8
-#define CSC_CONSTANTS_B 7 : 0
-
-#define CSC_Y_SOURCE_X 0x0000D0
-#define CSC_Y_SOURCE_X_INTEGER 26 : 16
-#define CSC_Y_SOURCE_X_FRACTION 15 : 3
-
-#define CSC_Y_SOURCE_Y 0x0000D4
-#define CSC_Y_SOURCE_Y_INTEGER 27 : 16
-#define CSC_Y_SOURCE_Y_FRACTION 15 : 3
-
-#define CSC_U_SOURCE_BASE 0x0000D8
-#define CSC_U_SOURCE_BASE_EXT 27 : 27
-#define CSC_U_SOURCE_BASE_EXT_LOCAL 0
-#define CSC_U_SOURCE_BASE_EXT_EXTERNAL 1
-#define CSC_U_SOURCE_BASE_CS 26 : 26
-#define CSC_U_SOURCE_BASE_CS_0 0
-#define CSC_U_SOURCE_BASE_CS_1 1
-#define CSC_U_SOURCE_BASE_ADDRESS 25 : 0
-
-#define CSC_V_SOURCE_BASE 0x0000DC
-#define CSC_V_SOURCE_BASE_EXT 27 : 27
-#define CSC_V_SOURCE_BASE_EXT_LOCAL 0
-#define CSC_V_SOURCE_BASE_EXT_EXTERNAL 1
-#define CSC_V_SOURCE_BASE_CS 26 : 26
-#define CSC_V_SOURCE_BASE_CS_0 0
-#define CSC_V_SOURCE_BASE_CS_1 1
-#define CSC_V_SOURCE_BASE_ADDRESS 25 : 0
-
-#define CSC_SOURCE_DIMENSION 0x0000E0
-#define CSC_SOURCE_DIMENSION_X 31 : 16
-#define CSC_SOURCE_DIMENSION_Y 15 : 0
-
-#define CSC_SOURCE_PITCH 0x0000E4
-#define CSC_SOURCE_PITCH_Y 31 : 16
-#define CSC_SOURCE_PITCH_UV 15 : 0
-
-#define CSC_DESTINATION 0x0000E8
-#define CSC_DESTINATION_WRAP 31 : 31
-#define CSC_DESTINATION_WRAP_DISABLE 0
-#define CSC_DESTINATION_WRAP_ENABLE 1
-#define CSC_DESTINATION_X 27 : 16
-#define CSC_DESTINATION_Y 11 : 0
-
-#define CSC_DESTINATION_DIMENSION 0x0000EC
-#define CSC_DESTINATION_DIMENSION_X 31 : 16
-#define CSC_DESTINATION_DIMENSION_Y 15 : 0
-
-#define CSC_DESTINATION_PITCH 0x0000F0
-#define CSC_DESTINATION_PITCH_X 31 : 16
-#define CSC_DESTINATION_PITCH_Y 15 : 0
-
-#define CSC_SCALE_FACTOR 0x0000F4
-#define CSC_SCALE_FACTOR_HORIZONTAL 31 : 16
-#define CSC_SCALE_FACTOR_VERTICAL 15 : 0
-
-#define CSC_DESTINATION_BASE 0x0000F8
-#define CSC_DESTINATION_BASE_EXT 27 : 27
-#define CSC_DESTINATION_BASE_EXT_LOCAL 0
-#define CSC_DESTINATION_BASE_EXT_EXTERNAL 1
-#define CSC_DESTINATION_BASE_CS 26 : 26
-#define CSC_DESTINATION_BASE_CS_0 0
-#define CSC_DESTINATION_BASE_CS_1 1
-#define CSC_DESTINATION_BASE_ADDRESS 25 : 0
-
-#define CSC_CONTROL 0x0000FC
-#define CSC_CONTROL_STATUS 31 : 31
-#define CSC_CONTROL_STATUS_STOP 0
-#define CSC_CONTROL_STATUS_START 1
-#define CSC_CONTROL_SOURCE_FORMAT 30 : 28
-#define CSC_CONTROL_SOURCE_FORMAT_YUV422 0
-#define CSC_CONTROL_SOURCE_FORMAT_YUV420I 1
-#define CSC_CONTROL_SOURCE_FORMAT_YUV420 2
-#define CSC_CONTROL_SOURCE_FORMAT_YVU9 3
-#define CSC_CONTROL_SOURCE_FORMAT_IYU1 4
-#define CSC_CONTROL_SOURCE_FORMAT_IYU2 5
-#define CSC_CONTROL_SOURCE_FORMAT_RGB565 6
-#define CSC_CONTROL_SOURCE_FORMAT_RGB8888 7
-#define CSC_CONTROL_DESTINATION_FORMAT 27 : 26
-#define CSC_CONTROL_DESTINATION_FORMAT_RGB565 0
-#define CSC_CONTROL_DESTINATION_FORMAT_RGB8888 1
-#define CSC_CONTROL_HORIZONTAL_FILTER 25 : 25
-#define CSC_CONTROL_HORIZONTAL_FILTER_DISABLE 0
-#define CSC_CONTROL_HORIZONTAL_FILTER_ENABLE 1
-#define CSC_CONTROL_VERTICAL_FILTER 24 : 24
-#define CSC_CONTROL_VERTICAL_FILTER_DISABLE 0
-#define CSC_CONTROL_VERTICAL_FILTER_ENABLE 1
-#define CSC_CONTROL_BYTE_ORDER 23 : 23
-#define CSC_CONTROL_BYTE_ORDER_YUYV 0
-#define CSC_CONTROL_BYTE_ORDER_UYVY 1
-
-#define DE_DATA_PORT_501 0x110000
-#define DE_DATA_PORT_712 0x400000
-#define DE_DATA_PORT_722 0x6000
-
-/* point to virtual Memory Map IO starting address */
-extern char *smtc_RegBaseAddress;
-/* point to virtual video memory starting address */
-extern char *smtc_VRAMBaseAddress;
-extern unsigned char smtc_de_busy;
-
-extern unsigned long memRead32(unsigned long nOffset);
-extern void memWrite32(unsigned long nOffset, unsigned long nData);
-extern unsigned long SMTC_read2Dreg(unsigned long nOffset);
-
-/* 2D functions */
-extern void deInit(unsigned int nModeWidth, unsigned int nModeHeight,
- unsigned int bpp);
-
-extern void deWaitForNotBusy(void);
-
-extern void deVerticalLine(unsigned long dst_base,
- unsigned long dst_pitch,
- unsigned long nX,
- unsigned long nY,
- unsigned long dst_height,
- unsigned long nColor);
-
-extern void deHorizontalLine(unsigned long dst_base,
- unsigned long dst_pitch,
- unsigned long nX,
- unsigned long nY,
- unsigned long dst_width,
- unsigned long nColor);
-
-extern void deLine(unsigned long dst_base,
- unsigned long dst_pitch,
- unsigned long nX1,
- unsigned long nY1,
- unsigned long nX2,
- unsigned long nY2,
- unsigned long nColor);
-
-extern void deFillRect(unsigned long dst_base,
- unsigned long dst_pitch,
- unsigned long dst_X,
- unsigned long dst_Y,
- unsigned long dst_width,
- unsigned long dst_height,
- unsigned long nColor);
-
-extern void deRotatePattern(unsigned char *pattern_dstaddr,
- unsigned long pattern_src_addr,
- unsigned long pattern_BPP,
- unsigned long pattern_stride,
- int patternX,
- int patternY);
-
-extern void deCopy(unsigned long dst_base,
- unsigned long dst_pitch,
- unsigned long dst_BPP,
- unsigned long dst_X,
- unsigned long dst_Y,
- unsigned long dst_width,
- unsigned long dst_height,
- unsigned long src_base,
- unsigned long src_pitch,
- unsigned long src_X,
- unsigned long src_Y,
- pTransparent pTransp,
- unsigned char nROP2);
-
-/*
- * System memory to Video memory monochrome expansion.
- *
- * Source is monochrome image in system memory. This function expands the
- * monochrome data to color image in video memory.
- *
- * @pSrcbuf: pointer to start of source buffer in system memory
- * @srcDelta: Pitch value (in bytes) of the source buffer, +ive means top
- * down and -ive mean button up
- * @startBit: Mono data can start at any bit in a byte, this value should
- * be 0 to 7
- * @dBase: Address of destination : offset in frame buffer
- * @dPitch: Pitch value of destination surface in BYTE
- * @bpp: Color depth of destination surface
- * @dx, dy: Starting coordinate of destination surface
- * @width, height: width and height of rectange in pixel value
- * @fColor,bColor: Foreground, Background color (corresponding to a 1, 0 in
- * the monochrome data)
- * @rop2: ROP value
- */
-
-extern long deSystemMem2VideoMemMonoBlt(
- const char *pSrcbuf,
- long srcDelta,
- unsigned long startBit,
- unsigned long dBase,
- unsigned long dPitch,
- unsigned long bpp,
- unsigned long dx, unsigned long dy,
- unsigned long width, unsigned long height,
- unsigned long fColor,
- unsigned long bColor,
- unsigned long rop2);
-
-extern unsigned long deGetTransparency(void);
-extern void deSetPixelFormat(unsigned long bpp);
diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c
index 161dbc9c1397..9c82a1a81ccc 100644
--- a/drivers/staging/sm7xx/smtcfb.c
+++ b/drivers/staging/sm7xx/smtcfb.c
@@ -6,7 +6,7 @@
* Boyod boyod.yang@siliconmotion.com.cn
*
* Copyright (C) 2009 Lemote, Inc.
- * Author: Wu Zhangjin, wuzj@lemote.com
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
@@ -45,7 +45,6 @@
struct screen_info smtc_screen_info;
#include "smtcfb.h"
-#include "smtc2d.h"
#ifdef DEBUG
#define smdbg(format, arg...) printk(KERN_DEBUG format , ## arg)
@@ -120,10 +119,6 @@ static struct vesa_mode_table vesa_mode[] = {
char __iomem *smtc_RegBaseAddress; /* Memory Map IO starting address */
char __iomem *smtc_VRAMBaseAddress; /* video memory starting address */
-char *smtc_2DBaseAddress; /* 2D engine starting address */
-char *smtc_2Ddataport; /* 2D data port offset */
-short smtc_2Dacceleration;
-
static u32 colreg[17];
static struct par_info hw; /* hardware information */
@@ -135,16 +130,6 @@ u16 smtc_ChipIDs[] = {
#define numSMTCchipIDs (sizeof(smtc_ChipIDs) / sizeof(u16))
-void deWaitForNotBusy(void)
-{
- unsigned long i = 0x1000000;
- while (i--) {
- if ((smtc_seqr(0x16) & 0x18) == 0x10)
- break;
- }
- smtc_de_busy = 0;
-}
-
static void sm712_set_timing(struct smtcfb_info *sfb,
struct par_info *ppar_info)
{
@@ -324,7 +309,7 @@ static inline unsigned int chan_to_field(unsigned int chan,
return chan << bf->offset;
}
-static int smtcfb_blank(int blank_mode, struct fb_info *info)
+static int cfb_blank(int blank_mode, struct fb_info *info)
{
/* clear DPMS setting */
switch (blank_mode) {
@@ -622,93 +607,13 @@ smtcfb_write(struct fb_info *info, const char __user *buf, size_t count,
}
#endif /* ! __BIG_ENDIAN */
-#include "smtc2d.c"
-
-void smtcfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
-{
- struct par_info *p = (struct par_info *)info->par;
-
- if (smtc_2Dacceleration) {
- if (!area->width || !area->height)
- return;
-
- deCopy(p->BaseAddressInVRAM, 0, info->var.bits_per_pixel,
- area->dx, area->dy, area->width, area->height,
- p->BaseAddressInVRAM, 0, area->sx, area->sy, 0, 0xC);
-
- } else
- cfb_copyarea(info, area);
-}
-
-void smtcfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
-{
- struct par_info *p = (struct par_info *)info->par;
-
- if (smtc_2Dacceleration) {
- if (!rect->width || !rect->height)
- return;
- if (info->var.bits_per_pixel >= 24)
- deFillRect(p->BaseAddressInVRAM, 0, rect->dx * 3,
- rect->dy * 3, rect->width * 3, rect->height,
- rect->color);
- else
- deFillRect(p->BaseAddressInVRAM, 0, rect->dx, rect->dy,
- rect->width, rect->height, rect->color);
- } else
- cfb_fillrect(info, rect);
-}
-
-void smtcfb_imageblit(struct fb_info *info, const struct fb_image *image)
-{
- struct par_info *p = (struct par_info *)info->par;
- u32 bg_col = 0, fg_col = 0;
-
- if ((smtc_2Dacceleration) && (image->depth == 1)) {
- if (smtc_de_busy)
- deWaitForNotBusy();
-
- switch (info->var.bits_per_pixel) {
- case 8:
- bg_col = image->bg_color;
- fg_col = image->fg_color;
- break;
- case 16:
- bg_col =
- ((u32 *) (info->pseudo_palette))[image->bg_color];
- fg_col =
- ((u32 *) (info->pseudo_palette))[image->fg_color];
- break;
- case 32:
- bg_col =
- ((u32 *) (info->pseudo_palette))[image->bg_color];
- fg_col =
- ((u32 *) (info->pseudo_palette))[image->fg_color];
- break;
- }
-
- deSystemMem2VideoMemMonoBlt(
- image->data,
- image->width / 8,
- 0,
- p->BaseAddressInVRAM,
- 0,
- 0,
- image->dx, image->dy,
- image->width, image->height,
- fg_col, bg_col,
- 0x0C);
-
- } else
- cfb_imageblit(info, image);
-}
-
static struct fb_ops smtcfb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = smtc_setcolreg,
- .fb_blank = smtcfb_blank,
- .fb_fillrect = smtcfb_fillrect,
- .fb_imageblit = smtcfb_imageblit,
- .fb_copyarea = smtcfb_copyarea,
+ .fb_blank = cfb_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_imageblit = cfb_imageblit,
+ .fb_copyarea = cfb_copyarea,
#ifdef __BIG_ENDIAN
.fb_read = smtcfb_read,
.fb_write = smtcfb_write,
@@ -772,12 +677,6 @@ void smtcfb_setmode(struct smtcfb_info *sfb)
hw.height = sfb->fb.var.yres;
hw.hz = 60;
smtc_set_timing(sfb, &hw);
- if (smtc_2Dacceleration) {
- printk("2D acceleration enabled!\n");
- /* Init smtc drawing engine */
- deInit(sfb->fb.var.xres, sfb->fb.var.yres,
- sfb->fb.var.bits_per_pixel);
- }
}
/*
@@ -1004,9 +903,7 @@ static int __init smtcfb_pci_probe(struct pci_dev *pdev,
#endif
hw.m_pMMIO = (smtc_RegBaseAddress =
smtc_VRAMBaseAddress + 0x00700000);
- smtc_2DBaseAddress = (hw.m_pDPR =
- smtc_VRAMBaseAddress + 0x00408000);
- smtc_2Ddataport = smtc_VRAMBaseAddress + DE_DATA_PORT_712;
+ hw.m_pDPR = smtc_VRAMBaseAddress + 0x00408000;
hw.m_pVPR = hw.m_pLFB + 0x0040c000;
#ifdef __BIG_ENDIAN
if (sfb->fb.var.bits_per_pixel == 32) {
@@ -1035,27 +932,21 @@ static int __init smtcfb_pci_probe(struct pci_dev *pdev,
if (sfb->fb.var.bits_per_pixel == 32)
smtc_seqw(0x17, 0x30);
#endif
-#ifdef CONFIG_FB_SM7XX_ACCEL
- smtc_2Dacceleration = 1;
-#endif
break;
case 0x720:
sfb->fb.fix.mmio_start = pFramebufferPhysical;
sfb->fb.fix.mmio_len = 0x00200000;
smem_size = SM722_VIDEOMEMORYSIZE;
- smtc_2DBaseAddress = (hw.m_pDPR =
- ioremap(pFramebufferPhysical, 0x00a00000));
+ hw.m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000);
hw.m_pLFB = (smtc_VRAMBaseAddress =
- smtc_2DBaseAddress + 0x00200000);
+ hw.m_pDPR + 0x00200000);
hw.m_pMMIO = (smtc_RegBaseAddress =
- smtc_2DBaseAddress + 0x000c0000);
- smtc_2Ddataport = smtc_2DBaseAddress + DE_DATA_PORT_722;
- hw.m_pVPR = smtc_2DBaseAddress + 0x800;
+ hw.m_pDPR + 0x000c0000);
+ hw.m_pVPR = hw.m_pDPR + 0x800;
smtc_seqw(0x62, 0xff);
smtc_seqw(0x6a, 0x0d);
smtc_seqw(0x6b, 0x02);
- smtc_2Dacceleration = 0;
break;
default:
printk(KERN_INFO
@@ -1103,7 +994,7 @@ static int __init smtcfb_pci_probe(struct pci_dev *pdev,
/* Jason (08/11/2009) PCI_DRV wrapper essential structs */
-static struct pci_device_id smtcfb_pci_table[] = {
+static const struct pci_device_id smtcfb_pci_table[] = {
{0x126f, 0x710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x126f, 0x712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x126f, 0x720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
diff --git a/drivers/staging/sm7xx/smtcfb.h b/drivers/staging/sm7xx/smtcfb.h
index 7f2c34138215..7ee565c2c952 100644
--- a/drivers/staging/sm7xx/smtcfb.h
+++ b/drivers/staging/sm7xx/smtcfb.h
@@ -6,7 +6,7 @@
* Boyod boyod.yang@siliconmotion.com.cn
*
* Copyright (C) 2009 Lemote, Inc.
- * Author: Wu Zhangjin, wuzj@lemote.com
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
diff --git a/drivers/staging/udlfb/Kconfig b/drivers/staging/udlfb/Kconfig
index 641692da0e4f..65bd5db4ca56 100644
--- a/drivers/staging/udlfb/Kconfig
+++ b/drivers/staging/udlfb/Kconfig
@@ -1,8 +1,14 @@
config FB_UDL
tristate "Displaylink USB Framebuffer support"
depends on FB && USB
+ select FB_MODE_HELPERS
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_SYS_FOPS
+ select FB_DEFERRED_IO
---help---
- This is an experimental driver for DisplayLink USB devices
- that provides a framebuffer device. A normal framebuffer can
- be used with this driver, or xorg can be run on the device
- using it.
+ This is a kernel framebuffer driver for DisplayLink USB devices.
+ Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and
+ mplayer -vo fbdev. Supports all USB 2.0 era DisplayLink devices.
+ To compile as a module, choose M here: the module name is udlfb.
diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
index f5416af1e902..8f6223c8303a 100644
--- a/drivers/staging/udlfb/udlfb.c
+++ b/drivers/staging/udlfb/udlfb.c
@@ -1,17 +1,20 @@
-/*****************************************************************************
- * DLFB Kernel Driver *
- * Version 0.2 (udlfb) *
- * (C) 2009 Roberto De Ioris <roberto@unbit.it> *
- * *
- * This file is licensed under the GPLv2. See COPYING in the package. *
- * Based on the amazing work of Florian Echtler and libdlo 0.1 *
- * *
- * *
- * 10.06.09 release 0.2.3 (edid ioctl, fallback for unsupported modes) *
- * 05.06.09 release 0.2.2 (real screen blanking, rle compression, double buffer) *
- * 31.05.09 release 0.2 *
- * 22.05.09 First public (ugly) release *
- *****************************************************************************/
+/*
+ * udlfb.c -- Framebuffer driver for DisplayLink USB controller
+ *
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Layout is based on skeletonfb by James Simmons and Geert Uytterhoeven,
+ * usb-skeleton by GregKH.
+ *
+ * Device-specific portions based on information from Displaylink, with work
+ * from Florian Echtler, Henrik Bjerregaard Pedersen, and others.
+ */
#include <linux/module.h>
#include <linux/kernel.h>
@@ -20,606 +23,672 @@
#include <linux/uaccess.h>
#include <linux/mm.h>
#include <linux/fb.h>
-#include <linux/mutex.h>
#include <linux/vmalloc.h>
#include "udlfb.h"
-#define DRIVER_VERSION "DLFB 0.2"
+static struct fb_fix_screeninfo dlfb_fix = {
+ .id = "udlfb",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
-/* memory functions taken from vfb */
+static const u32 udlfb_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
+#ifdef FBINFO_VIRTFB
+ FBINFO_VIRTFB |
+#endif
+ FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT |
+ FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR;
-static void *rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr;
+/*
+ * There are many DisplayLink-based products, all with unique PIDs. We are able
+ * to support all volume ones (circa 2009) with a single driver, so we match
+ * globally on VID. TODO: Probe() needs to detect when we might be running
+ * "future" chips, and bail on those, so a compatible driver can match.
+ */
+static struct usb_device_id id_table[] = {
+ {.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
+ {},
+};
+MODULE_DEVICE_TABLE(usb, id_table);
- size = PAGE_ALIGN(size);
- mem = vmalloc_32(size);
- if (!mem)
- return NULL;
+#ifndef CONFIG_FB_DEFERRED_IO
+#warning message "kernel FB_DEFFERRED_IO option to support generic fbdev apps"
+#endif
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long)mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
+#ifndef CONFIG_FB_SYS_IMAGEBLIT
+#ifndef CONFIG_FB_SYS_IMAGEBLIT_MODULE
+#warning message "FB_SYS_* in kernel or module option to support fb console"
+#endif
+#endif
- return mem;
-}
+#ifndef CONFIG_FB_MODE_HELPERS
+#warning message "kernel FB_MODE_HELPERS required. Expect build break"
+#endif
-static void rvfree(void *mem, unsigned long size)
-{
- unsigned long adr;
+/* dlfb keeps a list of urbs for efficient bulk transfers */
+static void dlfb_urb_completion(struct urb *urb);
+static struct urb *dlfb_get_urb(struct dlfb_data *dev);
+static int dlfb_submit_urb(struct dlfb_data *dev, struct urb * urb, size_t len);
+static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size);
+static void dlfb_free_urb_list(struct dlfb_data *dev);
- if (!mem)
- return;
+/* other symbols with dependents */
+#ifdef CONFIG_FB_DEFERRED_IO
+static struct fb_deferred_io dlfb_defio;
+#endif
- adr = (unsigned long)mem;
- while ((long)size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
+/*
+ * All DisplayLink bulk operations start with 0xAF, followed by specific code
+ * All operations are written to buffers which then later get sent to device
+ */
+static char *dlfb_set_register(char *buf, u8 reg, u8 val)
+{
+ *buf++ = 0xAF;
+ *buf++ = 0x20;
+ *buf++ = reg;
+ *buf++ = val;
+ return buf;
}
-static int dlfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+static char *dlfb_vidreg_lock(char *buf)
{
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end - vma->vm_start;
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- unsigned long page, pos;
-
- printk("MMAP: %lu %u\n", offset + size, info->fix.smem_len);
-
- if (offset + size > info->fix.smem_len)
- return -EINVAL;
-
- pos = (unsigned long)info->fix.smem_start + offset;
-
- while (size > 0) {
- page = vmalloc_to_pfn((void *)pos);
- if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
- return -EAGAIN;
-
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
- return 0;
-
+ return dlfb_set_register(buf, 0xFF, 0x00);
}
-/* ioctl structure */
-struct dloarea {
- int x, y;
- int w, h;
- int x2, y2;
-};
+static char *dlfb_vidreg_unlock(char *buf)
+{
+ return dlfb_set_register(buf, 0xFF, 0xFF);
+}
/*
-static struct usb_device_id id_table [] = {
- { USB_DEVICE(0x17e9, 0x023d) },
- { }
-};
-*/
+ * On/Off for driving the DisplayLink framebuffer to the display
+ */
+static char *dlfb_enable_hvsync(char *buf, bool enable)
+{
+ if (enable)
+ return dlfb_set_register(buf, 0x1F, 0x00);
+ else
+ return dlfb_set_register(buf, 0x1F, 0x01);
+}
-static struct usb_device_id id_table[] = {
- {.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
- {},
-};
-MODULE_DEVICE_TABLE(usb, id_table);
+static char *dlfb_set_color_depth(char *buf, u8 selection)
+{
+ return dlfb_set_register(buf, 0x00, selection);
+}
-static struct usb_driver dlfb_driver;
+static char *dlfb_set_base16bpp(char *wrptr, u32 base)
+{
+ /* the base pointer is 16 bits wide, 0x20 is hi byte. */
+ wrptr = dlfb_set_register(wrptr, 0x20, base >> 16);
+ wrptr = dlfb_set_register(wrptr, 0x21, base >> 8);
+ return dlfb_set_register(wrptr, 0x22, base);
+}
-// thanks to Henrik Bjerregaard Pedersen for this function
-static char *rle_compress16(uint16_t * src, char *dst, int rem)
+/*
+ * DisplayLink HW has separate 16bpp and 8bpp framebuffers.
+ * In 24bpp modes, the low 323 RGB bits go in the 8bpp framebuffer
+ */
+static char *dlfb_set_base8bpp(char *wrptr, u32 base)
{
+ wrptr = dlfb_set_register(wrptr, 0x26, base >> 16);
+ wrptr = dlfb_set_register(wrptr, 0x27, base >> 8);
+ return dlfb_set_register(wrptr, 0x28, base);
+}
- int rl;
- uint16_t pix0;
- char *end_if_raw = dst + 6 + 2 * rem;
+static char *dlfb_set_register_16(char *wrptr, u8 reg, u16 value)
+{
+ wrptr = dlfb_set_register(wrptr, reg, value >> 8);
+ return dlfb_set_register(wrptr, reg+1, value);
+}
- dst += 6; // header will be filled in if RLE is worth it
+/*
+ * This is kind of weird because the controller takes some
+ * register values in a different byte order than other registers.
+ */
+static char *dlfb_set_register_16be(char *wrptr, u8 reg, u16 value)
+{
+ wrptr = dlfb_set_register(wrptr, reg, value);
+ return dlfb_set_register(wrptr, reg+1, value >> 8);
+}
- while (rem && dst < end_if_raw) {
- char *start = (char *)src;
+/*
+ * LFSR is linear feedback shift register. The reason we have this is
+ * because the display controller needs to minimize the clock depth of
+ * various counters used in the display path. So this code reverses the
+ * provided value into the lfsr16 value by counting backwards to get
+ * the value that needs to be set in the hardware comparator to get the
+ * same actual count. This makes sense once you read above a couple of
+ * times and think about it from a hardware perspective.
+ */
+static u16 dlfb_lfsr16(u16 actual_count)
+{
+ u32 lv = 0xFFFF; /* This is the lfsr value that the hw starts with */
- pix0 = *src++;
- rl = 1;
- rem--;
- while (rem && *src == pix0)
- rem--, rl++, src++;
- *dst++ = rl;
- *dst++ = start[1];
- *dst++ = start[0];
+ while (actual_count--) {
+ lv = ((lv << 1) |
+ (((lv >> 15) ^ (lv >> 4) ^ (lv >> 2) ^ (lv >> 1)) & 1))
+ & 0xFFFF;
}
- return dst;
+ return (u16) lv;
}
/*
-Thanks to Henrik Bjerregaard Pedersen for rle implementation and code refactoring.
-Next step is huffman compression.
-*/
-
-static int
-image_blit(struct dlfb_data *dev_info, int x, int y, int width, int height,
- char *data)
+ * This does LFSR conversion on the value that is to be written.
+ * See LFSR explanation above for more detail.
+ */
+static char *dlfb_set_register_lfsr16(char *wrptr, u8 reg, u16 value)
{
+ return dlfb_set_register_16(wrptr, reg, dlfb_lfsr16(value));
+}
- int i, j, base;
- int rem = width;
- int ret;
-
- int firstdiff, thistime;
-
- char *bufptr;
-
- if (x + width > dev_info->info->var.xres)
- return -EINVAL;
-
- if (y + height > dev_info->info->var.yres)
- return -EINVAL;
+/*
+ * This takes a standard fbdev screeninfo struct and all of its monitor mode
+ * details and converts them into the DisplayLink equivalent register commands.
+ */
+static char *dlfb_set_vid_cmds(char *wrptr, struct fb_var_screeninfo *var)
+{
+ u16 xds, yds;
+ u16 xde, yde;
+ u16 yec;
- mutex_lock(&dev_info->bulk_mutex);
+ /* x display start */
+ xds = var->left_margin + var->hsync_len;
+ wrptr = dlfb_set_register_lfsr16(wrptr, 0x01, xds);
+ /* x display end */
+ xde = xds + var->xres;
+ wrptr = dlfb_set_register_lfsr16(wrptr, 0x03, xde);
- base =
- dev_info->base16 + ((dev_info->info->var.xres * 2 * y) + (x * 2));
+ /* y display start */
+ yds = var->upper_margin + var->vsync_len;
+ wrptr = dlfb_set_register_lfsr16(wrptr, 0x05, yds);
+ /* y display end */
+ yde = yds + var->yres;
+ wrptr = dlfb_set_register_lfsr16(wrptr, 0x07, yde);
- data += (dev_info->info->var.xres * 2 * y) + (x * 2);
+ /* x end count is active + blanking - 1 */
+ wrptr = dlfb_set_register_lfsr16(wrptr, 0x09,
+ xde + var->right_margin - 1);
- /* printk("IMAGE_BLIT\n"); */
+ /* libdlo hardcodes hsync start to 1 */
+ wrptr = dlfb_set_register_lfsr16(wrptr, 0x0B, 1);
- bufptr = dev_info->buf;
+ /* hsync end is width of sync pulse + 1 */
+ wrptr = dlfb_set_register_lfsr16(wrptr, 0x0D, var->hsync_len + 1);
- for (i = y; i < y + height; i++) {
+ /* hpixels is active pixels */
+ wrptr = dlfb_set_register_16(wrptr, 0x0F, var->xres);
- if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
- ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
- bufptr = dev_info->buf;
- }
+ /* yendcount is vertical active + vertical blanking */
+ yec = var->yres + var->upper_margin + var->lower_margin +
+ var->vsync_len;
+ wrptr = dlfb_set_register_lfsr16(wrptr, 0x11, yec);
- rem = width;
+ /* libdlo hardcodes vsync start to 0 */
+ wrptr = dlfb_set_register_lfsr16(wrptr, 0x13, 0);
- /* printk("WRITING LINE %d\n", i); */
+ /* vsync end is width of vsync pulse */
+ wrptr = dlfb_set_register_lfsr16(wrptr, 0x15, var->vsync_len);
- while (rem) {
+ /* vpixels is active pixels */
+ wrptr = dlfb_set_register_16(wrptr, 0x17, var->yres);
- if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
- ret =
- dlfb_bulk_msg(dev_info,
- bufptr - dev_info->buf);
- bufptr = dev_info->buf;
- }
- // number of pixels to consider this time
- thistime = rem;
- if (thistime > 255)
- thistime = 255;
-
- // find position of first pixel that has changed
- firstdiff = -1;
- for (j = 0; j < thistime * 2; j++) {
- if (dev_info->backing_buffer
- [base - dev_info->base16 + j] != data[j]) {
- firstdiff = j / 2;
- break;
- }
- }
+ /* convert picoseconds to 5kHz multiple for pclk5k = x * 1E12/5k */
+ wrptr = dlfb_set_register_16be(wrptr, 0x1B,
+ 200*1000*1000/var->pixclock);
- if (firstdiff >= 0) {
- char *end_of_rle;
-
- end_of_rle =
- rle_compress16((uint16_t *) (data +
- firstdiff * 2),
- bufptr,
- thistime - firstdiff);
-
- if (end_of_rle <
- bufptr + 6 + 2 * (thistime - firstdiff)) {
- bufptr[0] = 0xAF;
- bufptr[1] = 0x69;
-
- bufptr[2] =
- (char)((base +
- firstdiff * 2) >> 16);
- bufptr[3] =
- (char)((base + firstdiff * 2) >> 8);
- bufptr[4] =
- (char)(base + firstdiff * 2);
- bufptr[5] = thistime - firstdiff;
-
- bufptr = end_of_rle;
-
- } else {
- // fallback to raw (or some other encoding?)
- *bufptr++ = 0xAF;
- *bufptr++ = 0x68;
-
- *bufptr++ =
- (char)((base +
- firstdiff * 2) >> 16);
- *bufptr++ =
- (char)((base + firstdiff * 2) >> 8);
- *bufptr++ =
- (char)(base + firstdiff * 2);
- *bufptr++ = thistime - firstdiff;
- // PUT COMPRESSION HERE
- for (j = firstdiff * 2;
- j < thistime * 2; j += 2) {
- *bufptr++ = data[j + 1];
- *bufptr++ = data[j];
- }
- }
- }
+ return wrptr;
+}
- base += thistime * 2;
- data += thistime * 2;
- rem -= thistime;
- }
+/*
+ * This takes a standard fbdev screeninfo struct that was fetched or prepared
+ * and then generates the appropriate command sequence that then drives the
+ * display controller.
+ */
+static int dlfb_set_video_mode(struct dlfb_data *dev,
+ struct fb_var_screeninfo *var)
+{
+ char *buf;
+ char *wrptr;
+ int retval = 0;
+ int writesize;
+ struct urb *urb;
- memcpy(dev_info->backing_buffer + (base - dev_info->base16) -
- (width * 2), data - (width * 2), width * 2);
+ if (!atomic_read(&dev->usb_active))
+ return -EPERM;
- base += (dev_info->info->var.xres * 2) - (width * 2);
- data += (dev_info->info->var.xres * 2) - (width * 2);
+ urb = dlfb_get_urb(dev);
+ if (!urb)
+ return -ENOMEM;
+ buf = (char *) urb->transfer_buffer;
- }
+ /*
+ * This first section has to do with setting the base address on the
+ * controller * associated with the display. There are 2 base
+ * pointers, currently, we only * use the 16 bpp segment.
+ */
+ wrptr = dlfb_vidreg_lock(buf);
+ wrptr = dlfb_set_color_depth(wrptr, 0x00);
+ /* set base for 16bpp segment to 0 */
+ wrptr = dlfb_set_base16bpp(wrptr, 0);
+ /* set base for 8bpp segment to end of fb */
+ wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len);
- if (bufptr > dev_info->buf) {
- ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
- }
+ wrptr = dlfb_set_vid_cmds(wrptr, var);
+ wrptr = dlfb_enable_hvsync(wrptr, true);
+ wrptr = dlfb_vidreg_unlock(wrptr);
- mutex_unlock(&dev_info->bulk_mutex);
+ writesize = wrptr - buf;
- return base;
+ retval = dlfb_submit_urb(dev, urb, writesize);
+ return retval;
}
-static int
-draw_rect(struct dlfb_data *dev_info, int x, int y, int width, int height,
- unsigned char red, unsigned char green, unsigned char blue)
+static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
+ unsigned long start = vma->vm_start;
+ unsigned long size = vma->vm_end - vma->vm_start;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long page, pos;
+ struct dlfb_data *dev = info->par;
- int i, j, base;
- int ret;
- unsigned short col =
- (((((red) & 0xF8) | ((green) >> 5)) & 0xFF) << 8) +
- (((((green) & 0x1C) << 3) | ((blue) >> 3)) & 0xFF);
- int rem = width;
-
- char *bufptr;
+ dl_notice("MMAP: %lu %u\n", offset + size, info->fix.smem_len);
- if (x + width > dev_info->info->var.xres)
+ if (offset + size > info->fix.smem_len)
return -EINVAL;
- if (y + height > dev_info->info->var.yres)
- return -EINVAL;
+ pos = (unsigned long)info->fix.smem_start + offset;
- mutex_lock(&dev_info->bulk_mutex);
+ while (size > 0) {
+ page = vmalloc_to_pfn((void *)pos);
+ if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+ return -EAGAIN;
- base = dev_info->base16 + (dev_info->info->var.xres * 2 * y) + (x * 2);
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
- bufptr = dev_info->buf;
+ vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+ return 0;
- for (i = y; i < y + height; i++) {
+}
- for (j = 0; j < width * 2; j += 2) {
- dev_info->backing_buffer[base - dev_info->base16 + j] =
- (char)(col >> 8);
- dev_info->backing_buffer[base - dev_info->base16 + j +
- 1] = (char)(col);
- }
- if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
- ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
- bufptr = dev_info->buf;
+/*
+ * Trims identical data from front and back of line
+ * Sets new front buffer address and width
+ * And returns byte count of identical pixels
+ * Assumes CPU natural alignment (unsigned long)
+ * for back and front buffer ptrs and width
+ */
+static int dlfb_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
+{
+ int j, k;
+ const unsigned long *back = (const unsigned long *) bback;
+ const unsigned long *front = (const unsigned long *) *bfront;
+ const int width = *width_bytes / sizeof(unsigned long);
+ int identical = width;
+ int start = width;
+ int end = width;
+
+ prefetch((void *) front);
+ prefetch((void *) back);
+
+ for (j = 0; j < width; j++) {
+ if (back[j] != front[j]) {
+ start = j;
+ break;
}
+ }
- rem = width;
-
- while (rem) {
-
- if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
- ret =
- dlfb_bulk_msg(dev_info,
- bufptr - dev_info->buf);
- bufptr = dev_info->buf;
- }
-
- *bufptr++ = 0xAF;
- *bufptr++ = 0x69;
-
- *bufptr++ = (char)(base >> 16);
- *bufptr++ = (char)(base >> 8);
- *bufptr++ = (char)(base);
-
- if (rem > 255) {
- *bufptr++ = 255;
- *bufptr++ = 255;
- rem -= 255;
- base += 255 * 2;
- } else {
- *bufptr++ = rem;
- *bufptr++ = rem;
- base += rem * 2;
- rem = 0;
- }
-
- *bufptr++ = (char)(col >> 8);
- *bufptr++ = (char)(col);
-
+ for (k = width - 1; k > j; k--) {
+ if (back[k] != front[k]) {
+ end = k+1;
+ break;
}
-
- base += (dev_info->info->var.xres * 2) - (width * 2);
-
}
- if (bufptr > dev_info->buf)
- ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
+ identical = start + (width - end);
+ *bfront = (u8 *) &front[start];
+ *width_bytes = (end - start) * sizeof(unsigned long);
- mutex_unlock(&dev_info->bulk_mutex);
-
- return 1;
+ return identical * sizeof(unsigned long);
}
-static void swapfb(struct dlfb_data *dev_info)
+/*
+Render a command stream for an encoded horizontal line segment of pixels.
+
+A command buffer holds several commands.
+It always begins with a fresh command header
+(the protocol doesn't require this, but we enforce it to allow
+multiple buffers to be potentially encoded and sent in parallel).
+A single command encodes one contiguous horizontal line of pixels
+
+The function relies on the client to do all allocation, so that
+rendering can be done directly to output buffers (e.g. USB URBs).
+The function fills the supplied command buffer, providing information
+on where it left off, so the client may call in again with additional
+buffers if the line will take several buffers to complete.
+
+A single command can transmit a maximum of 256 pixels,
+regardless of the compression ratio (protocol design limit).
+To the hardware, 0 for a size byte means 256
+
+Rather than 256 pixel commands which are either rl or raw encoded,
+the rlx command simply assumes alternating raw and rl spans within one cmd.
+This has a slightly larger header overhead, but produces more even results.
+It also processes all data (read and write) in a single pass.
+Performance benchmarks of common cases show it having just slightly better
+compression than 256 pixel raw -or- rle commands, with similar CPU consumpion.
+But for very rl friendly data, will compress not quite as well.
+*/
+static void dlfb_compress_hline(
+ const uint16_t **pixel_start_ptr,
+ const uint16_t *const pixel_end,
+ uint32_t *device_address_ptr,
+ uint8_t **command_buffer_ptr,
+ const uint8_t *const cmd_buffer_end)
{
+ const uint16_t *pixel = *pixel_start_ptr;
+ uint32_t dev_addr = *device_address_ptr;
+ uint8_t *cmd = *command_buffer_ptr;
+ const int bpp = 2;
+
+ while ((pixel_end > pixel) &&
+ (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) {
+ uint8_t *raw_pixels_count_byte = 0;
+ uint8_t *cmd_pixels_count_byte = 0;
+ const uint16_t *raw_pixel_start = 0;
+ const uint16_t *cmd_pixel_start, *cmd_pixel_end = 0;
+ const uint32_t be_dev_addr = cpu_to_be32(dev_addr);
+
+ prefetchw((void *) cmd); /* pull in one cache line at least */
+
+ *cmd++ = 0xAF;
+ *cmd++ = 0x6B;
+ *cmd++ = (uint8_t) ((be_dev_addr >> 8) & 0xFF);
+ *cmd++ = (uint8_t) ((be_dev_addr >> 16) & 0xFF);
+ *cmd++ = (uint8_t) ((be_dev_addr >> 24) & 0xFF);
+
+ cmd_pixels_count_byte = cmd++; /* we'll know this later */
+ cmd_pixel_start = pixel;
+
+ raw_pixels_count_byte = cmd++; /* we'll know this later */
+ raw_pixel_start = pixel;
+
+ cmd_pixel_end = pixel + min(MAX_CMD_PIXELS + 1,
+ min((int)(pixel_end - pixel),
+ (int)(cmd_buffer_end - cmd) / bpp));
+
+ prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp);
+
+ while (pixel < cmd_pixel_end) {
+ const uint16_t * const repeating_pixel = pixel;
+
+ *(uint16_t *)cmd = cpu_to_be16p(pixel);
+ cmd += 2;
+ pixel++;
+
+ if (unlikely((pixel < cmd_pixel_end) &&
+ (*pixel == *repeating_pixel))) {
+ /* go back and fill in raw pixel count */
+ *raw_pixels_count_byte = ((repeating_pixel -
+ raw_pixel_start) + 1) & 0xFF;
+
+ while ((pixel < cmd_pixel_end)
+ && (*pixel == *repeating_pixel)) {
+ pixel++;
+ }
- int tmpbase;
- char *bufptr;
-
- mutex_lock(&dev_info->bulk_mutex);
-
- tmpbase = dev_info->base16;
-
- dev_info->base16 = dev_info->base16d;
- dev_info->base16d = tmpbase;
+ /* immediately after raw data is repeat byte */
+ *cmd++ = ((pixel - repeating_pixel) - 1) & 0xFF;
- bufptr = dev_info->buf;
+ /* Then start another raw pixel span */
+ raw_pixel_start = pixel;
+ raw_pixels_count_byte = cmd++;
+ }
+ }
- bufptr = dlfb_set_register(bufptr, 0xFF, 0x00);
+ if (pixel > raw_pixel_start) {
+ /* finalize last RAW span */
+ *raw_pixels_count_byte = (pixel-raw_pixel_start) & 0xFF;
+ }
- // set addresses
- bufptr =
- dlfb_set_register(bufptr, 0x20, (char)(dev_info->base16 >> 16));
- bufptr = dlfb_set_register(bufptr, 0x21, (char)(dev_info->base16 >> 8));
- bufptr = dlfb_set_register(bufptr, 0x22, (char)(dev_info->base16));
+ *cmd_pixels_count_byte = (pixel - cmd_pixel_start) & 0xFF;
+ dev_addr += (pixel - cmd_pixel_start) * bpp;
+ }
- bufptr = dlfb_set_register(bufptr, 0xFF, 0x00);
+ if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) {
+ /* Fill leftover bytes with no-ops */
+ if (cmd_buffer_end > cmd)
+ memset(cmd, 0xAF, cmd_buffer_end - cmd);
+ cmd = (uint8_t *) cmd_buffer_end;
+ }
- dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
+ *command_buffer_ptr = cmd;
+ *pixel_start_ptr = pixel;
+ *device_address_ptr = dev_addr;
- mutex_unlock(&dev_info->bulk_mutex);
+ return;
}
-static int copyfb(struct dlfb_data *dev_info)
+/*
+ * There are 3 copies of every pixel: The front buffer that the fbdev
+ * client renders to, the actual framebuffer across the USB bus in hardware
+ * (that we can only write to, slowly, and can never read), and (optionally)
+ * our shadow copy that tracks what's been sent to that hardware buffer.
+ */
+static void dlfb_render_hline(struct dlfb_data *dev, struct urb **urb_ptr,
+ const char *front, char **urb_buf_ptr,
+ u32 byte_offset, u32 byte_width,
+ int *ident_ptr, int *sent_ptr)
{
- int base;
- int source;
- int rem;
- int i, ret;
-
- char *bufptr;
-
- base = dev_info->base16d;
-
- mutex_lock(&dev_info->bulk_mutex);
-
- source = dev_info->base16;
-
- bufptr = dev_info->buf;
-
- for (i = 0; i < dev_info->info->var.yres; i++) {
-
- if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
- ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
- bufptr = dev_info->buf;
- }
-
- rem = dev_info->info->var.xres;
-
- while (rem) {
-
- if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
- ret =
- dlfb_bulk_msg(dev_info,
- bufptr - dev_info->buf);
- bufptr = dev_info->buf;
-
- }
-
- *bufptr++ = 0xAF;
- *bufptr++ = 0x6A;
-
- *bufptr++ = (char)(base >> 16);
- *bufptr++ = (char)(base >> 8);
- *bufptr++ = (char)(base);
-
- if (rem > 255) {
- *bufptr++ = 255;
- *bufptr++ = (char)(source >> 16);
- *bufptr++ = (char)(source >> 8);
- *bufptr++ = (char)(source);
-
- rem -= 255;
- base += 255 * 2;
- source += 255 * 2;
-
- } else {
- *bufptr++ = rem;
- *bufptr++ = (char)(source >> 16);
- *bufptr++ = (char)(source >> 8);
- *bufptr++ = (char)(source);
+ const u8 *line_start, *line_end, *next_pixel;
+ u32 dev_addr = dev->base16 + byte_offset;
+ struct urb *urb = *urb_ptr;
+ u8 *cmd = *urb_buf_ptr;
+ u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length;
+
+ line_start = (u8 *) (front + byte_offset);
+ next_pixel = line_start;
+ line_end = next_pixel + byte_width;
+
+ if (dev->backing_buffer) {
+ int offset;
+ const u8 *back_start = (u8 *) (dev->backing_buffer
+ + byte_offset);
+
+ *ident_ptr += dlfb_trim_hline(back_start, &next_pixel,
+ &byte_width);
+
+ offset = next_pixel - line_start;
+ line_end = next_pixel + byte_width;
+ dev_addr += offset;
+ back_start += offset;
+ line_start += offset;
+
+ memcpy((char *)back_start, (char *) line_start,
+ byte_width);
+ }
- base += rem * 2;
- source += rem * 2;
- rem = 0;
- }
+ while (next_pixel < line_end) {
+
+ dlfb_compress_hline((const uint16_t **) &next_pixel,
+ (const uint16_t *) line_end, &dev_addr,
+ (u8 **) &cmd, (u8 *) cmd_end);
+
+ if (cmd >= cmd_end) {
+ int len = cmd - (u8 *) urb->transfer_buffer;
+ if (dlfb_submit_urb(dev, urb, len))
+ return; /* lost pixels is set */
+ *sent_ptr += len;
+ urb = dlfb_get_urb(dev);
+ if (!urb)
+ return; /* lost_pixels is set */
+ *urb_ptr = urb;
+ cmd = urb->transfer_buffer;
+ cmd_end = &cmd[urb->transfer_buffer_length];
}
}
- if (bufptr > dev_info->buf)
- ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
-
- mutex_unlock(&dev_info->bulk_mutex);
-
- return 1;
-
+ *urb_buf_ptr = cmd;
}
-static int
-copyarea(struct dlfb_data *dev_info, int dx, int dy, int sx, int sy,
- int width, int height)
+int dlfb_handle_damage(struct dlfb_data *dev, int x, int y,
+ int width, int height, char *data)
{
- int base;
- int source;
- int rem;
int i, ret;
-
- char *bufptr;
-
- if (dx + width > dev_info->info->var.xres)
+ char *cmd;
+ cycles_t start_cycles, end_cycles;
+ int bytes_sent = 0;
+ int bytes_identical = 0;
+ struct urb *urb;
+ int aligned_x;
+
+ start_cycles = get_cycles();
+
+ aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
+ width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
+ x = aligned_x;
+
+ if ((width <= 0) ||
+ (x + width > dev->info->var.xres) ||
+ (y + height > dev->info->var.yres))
return -EINVAL;
- if (dy + height > dev_info->info->var.yres)
- return -EINVAL;
-
- mutex_lock(&dev_info->bulk_mutex);
+ if (!atomic_read(&dev->usb_active))
+ return 0;
- base =
- dev_info->base16 + (dev_info->info->var.xres * 2 * dy) + (dx * 2);
- source = (dev_info->info->var.xres * 2 * sy) + (sx * 2);
+ urb = dlfb_get_urb(dev);
+ if (!urb)
+ return 0;
+ cmd = urb->transfer_buffer;
- bufptr = dev_info->buf;
+ for (i = y; i < y + height ; i++) {
+ const int line_offset = dev->info->fix.line_length * i;
+ const int byte_offset = line_offset + (x * BPP);
- for (i = sy; i < sy + height; i++) {
+ dlfb_render_hline(dev, &urb, (char *) dev->info->fix.smem_start,
+ &cmd, byte_offset, width * BPP,
+ &bytes_identical, &bytes_sent);
+ }
- memcpy(dev_info->backing_buffer + base - dev_info->base16,
- dev_info->backing_buffer + source, width * 2);
+ if (cmd > (char *) urb->transfer_buffer) {
+ /* Send partial buffer remaining before exiting */
+ int len = cmd - (char *) urb->transfer_buffer;
+ ret = dlfb_submit_urb(dev, urb, len);
+ bytes_sent += len;
+ } else
+ dlfb_urb_completion(urb);
+
+ atomic_add(bytes_sent, &dev->bytes_sent);
+ atomic_add(bytes_identical, &dev->bytes_identical);
+ atomic_add(width*height*2, &dev->bytes_rendered);
+ end_cycles = get_cycles();
+ atomic_add(((unsigned int) ((end_cycles - start_cycles)
+ >> 10)), /* Kcycles */
+ &dev->cpu_kcycles_used);
- if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
- ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
- bufptr = dev_info->buf;
- }
-
- rem = width;
+ return 0;
+}
- while (rem) {
+/* hardware has native COPY command (see libdlo), but not worth it for fbcon */
+static void dlfb_ops_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
- if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
- ret =
- dlfb_bulk_msg(dev_info,
- bufptr - dev_info->buf);
- bufptr = dev_info->buf;
- }
+ struct dlfb_data *dev = info->par;
- *bufptr++ = 0xAF;
- *bufptr++ = 0x6A;
+#if defined CONFIG_FB_SYS_COPYAREA || defined CONFIG_FB_SYS_COPYAREA_MODULE
- *bufptr++ = (char)(base >> 16);
- *bufptr++ = (char)(base >> 8);
- *bufptr++ = (char)(base);
+ sys_copyarea(info, area);
- if (rem > 255) {
- *bufptr++ = 255;
- *bufptr++ = (char)(source >> 16);
- *bufptr++ = (char)(source >> 8);
- *bufptr++ = (char)(source);
+ dlfb_handle_damage(dev, area->dx, area->dy,
+ area->width, area->height, info->screen_base);
+#endif
+ atomic_inc(&dev->copy_count);
- rem -= 255;
- base += 255 * 2;
- source += 255 * 2;
+}
- } else {
- *bufptr++ = rem;
- *bufptr++ = (char)(source >> 16);
- *bufptr++ = (char)(source >> 8);
- *bufptr++ = (char)(source);
+static void dlfb_ops_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ struct dlfb_data *dev = info->par;
- base += rem * 2;
- source += rem * 2;
- rem = 0;
- }
- }
+#if defined CONFIG_FB_SYS_IMAGEBLIT || defined CONFIG_FB_SYS_IMAGEBLIT_MODULE
- base += (dev_info->info->var.xres * 2) - (width * 2);
- source += (dev_info->info->var.xres * 2) - (width * 2);
- }
+ sys_imageblit(info, image);
- if (bufptr > dev_info->buf)
- ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
+ dlfb_handle_damage(dev, image->dx, image->dy,
+ image->width, image->height, info->screen_base);
- mutex_unlock(&dev_info->bulk_mutex);
+#endif
- return 1;
+ atomic_inc(&dev->blit_count);
}
-static void dlfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+static void dlfb_ops_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
{
-
struct dlfb_data *dev = info->par;
- copyarea(dev, area->dx, area->dy, area->sx, area->sy, area->width,
- area->height);
+#if defined CONFIG_FB_SYS_FILLRECT || defined CONFIG_FB_SYS_FILLRECT_MODULE
- /* printk("COPY AREA %d %d %d %d %d %d !!!\n", area->dx, area->dy, area->sx, area->sy, area->width, area->height); */
+ sys_fillrect(info, rect);
-}
+ dlfb_handle_damage(dev, rect->dx, rect->dy, rect->width,
+ rect->height, info->screen_base);
+#endif
-static void dlfb_imageblit(struct fb_info *info, const struct fb_image *image)
-{
+ atomic_inc(&dev->fill_count);
- int ret;
- struct dlfb_data *dev = info->par;
- /* printk("IMAGE BLIT (1) %d %d %d %d DEPTH %d {%p}!!!\n", image->dx, image->dy, image->width, image->height, image->depth, dev->udev); */
- cfb_imageblit(info, image);
- ret =
- image_blit(dev, image->dx, image->dy, image->width, image->height,
- info->screen_base);
- /* printk("IMAGE BLIT (2) %d %d %d %d DEPTH %d {%p} %d!!!\n", image->dx, image->dy, image->width, image->height, image->depth, dev->udev, ret); */
}
-static void dlfb_fillrect(struct fb_info *info,
- const struct fb_fillrect *region)
+static void dlfb_get_edid(struct dlfb_data *dev)
{
-
- unsigned char red, green, blue;
- struct dlfb_data *dev = info->par;
-
- memcpy(&red, &region->color, 1);
- memcpy(&green, &region->color + 1, 1);
- memcpy(&blue, &region->color + 2, 1);
- draw_rect(dev, region->dx, region->dy, region->width, region->height,
- red, green, blue);
- /* printk("FILL RECT %d %d !!!\n", region->dx, region->dy); */
-
+ int i;
+ int ret;
+ char rbuf[2];
+
+ for (i = 0; i < sizeof(dev->edid); i++) {
+ ret = usb_control_msg(dev->udev,
+ usb_rcvctrlpipe(dev->udev, 0), (0x02),
+ (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
+ 0);
+ dev->edid[i] = rbuf[1];
+ }
}
-static int dlfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
{
- struct dlfb_data *dev_info = info->par;
+ struct dlfb_data *dev = info->par;
struct dloarea *area = NULL;
- if (cmd == 0xAD) {
+ if (!atomic_read(&dev->usb_active))
+ return 0;
+
+ /* TODO: Update X server to get this from sysfs instead */
+ if (cmd == DLFB_IOCTL_RETURN_EDID) {
char *edid = (char *)arg;
- dlfb_edid(dev_info);
- if (copy_to_user(edid, dev_info->edid, 128)) {
+ dlfb_get_edid(dev);
+ if (copy_to_user(edid, dev->edid, sizeof(dev->edid)))
return -EFAULT;
- }
return 0;
}
- if (cmd == 0xAA || cmd == 0xAB || cmd == 0xAC) {
+ /* TODO: Help propose a standard fb.h ioctl to report mmap damage */
+ if (cmd == DLFB_IOCTL_REPORT_DAMAGE) {
area = (struct dloarea *)arg;
@@ -634,36 +703,20 @@ static int dlfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
if (area->y > info->var.yres)
area->y = info->var.yres;
- }
- if (cmd == 0xAA) {
- image_blit(dev_info, area->x, area->y, area->w, area->h,
+ atomic_set(&dev->use_defio, 0);
+
+ dlfb_handle_damage(dev, area->x, area->y, area->w, area->h,
info->screen_base);
+ atomic_inc(&dev->damage_count);
}
- if (cmd == 0xAC) {
- copyfb(dev_info);
- image_blit(dev_info, area->x, area->y, area->w, area->h,
- info->screen_base);
- swapfb(dev_info);
- } else if (cmd == 0xAB) {
-
- if (area->x2 < 0)
- area->x2 = 0;
-
- if (area->y2 < 0)
- area->y2 = 0;
- copyarea(dev_info,
- area->x2, area->y2, area->x, area->y, area->w,
- area->h);
- }
return 0;
}
/* taken from vesafb */
-
static int
-dlfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+dlfb_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info)
{
int err = 0;
@@ -688,234 +741,698 @@ dlfb_setcolreg(unsigned regno, unsigned red, unsigned green,
return err;
}
-static int dlfb_release(struct fb_info *info, int user)
+/*
+ * It's common for several clients to have framebuffer open simultaneously.
+ * e.g. both fbcon and X. Makes things interesting.
+ */
+static int dlfb_ops_open(struct fb_info *info, int user)
+{
+ struct dlfb_data *dev = info->par;
+
+/* if (user == 0)
+ * We could special case kernel mode clients (fbcon) here
+ */
+
+ mutex_lock(&dev->fb_open_lock);
+
+ dev->fb_count++;
+
+#ifdef CONFIG_FB_DEFERRED_IO
+ if ((atomic_read(&dev->use_defio)) && (info->fbdefio == NULL)) {
+ /* enable defio */
+ info->fbdefio = &dlfb_defio;
+ fb_deferred_io_init(info);
+ }
+#endif
+
+ dl_notice("open /dev/fb%d user=%d fb_info=%p count=%d\n",
+ info->node, user, info, dev->fb_count);
+
+ mutex_unlock(&dev->fb_open_lock);
+
+ return 0;
+}
+
+static int dlfb_ops_release(struct fb_info *info, int user)
+{
+ struct dlfb_data *dev = info->par;
+
+ mutex_lock(&dev->fb_open_lock);
+
+ dev->fb_count--;
+
+#ifdef CONFIG_FB_DEFERRED_IO
+ if ((dev->fb_count == 0) && (info->fbdefio)) {
+ fb_deferred_io_cleanup(info);
+ info->fbdefio = NULL;
+ info->fbops->fb_mmap = dlfb_ops_mmap;
+ }
+#endif
+
+ dl_notice("release /dev/fb%d user=%d count=%d\n",
+ info->node, user, dev->fb_count);
+
+ mutex_unlock(&dev->fb_open_lock);
+
+ return 0;
+}
+
+/*
+ * Called when all client interfaces to start transactions have been disabled,
+ * and all references to our device instance (dlfb_data) are released.
+ * Every transaction must have a reference, so we know are fully spun down
+ */
+static void dlfb_delete(struct kref *kref)
+{
+ struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
+
+ if (dev->backing_buffer)
+ vfree(dev->backing_buffer);
+
+ mutex_destroy(&dev->fb_open_lock);
+
+ kfree(dev);
+}
+
+/*
+ * Called by fbdev as last part of unregister_framebuffer() process
+ * No new clients can open connections. Deallocate everything fb_info.
+ */
+static void dlfb_ops_destroy(struct fb_info *info)
+{
+ struct dlfb_data *dev = info->par;
+
+ if (info->cmap.len != 0)
+ fb_dealloc_cmap(&info->cmap);
+ if (info->monspecs.modedb)
+ fb_destroy_modedb(info->monspecs.modedb);
+ if (info->screen_base)
+ vfree(info->screen_base);
+
+ fb_destroy_modelist(&info->modelist);
+
+ framebuffer_release(info);
+
+ /* ref taken before register_framebuffer() for dlfb_data clients */
+ kref_put(&dev->kref, dlfb_delete);
+}
+
+/*
+ * Check whether a video mode is supported by the DisplayLink chip
+ * We start from monitor's modes, so don't need to filter that here
+ */
+static int dlfb_is_valid_mode(struct fb_videomode *mode,
+ struct fb_info *info)
+{
+ struct dlfb_data *dev = info->par;
+
+ if (mode->xres * mode->yres > dev->sku_pixel_limit)
+ return 0;
+
+ return 1;
+}
+
+static void dlfb_var_color_format(struct fb_var_screeninfo *var)
+{
+ const struct fb_bitfield red = { 11, 5, 0 };
+ const struct fb_bitfield green = { 5, 6, 0 };
+ const struct fb_bitfield blue = { 0, 5, 0 };
+
+ var->bits_per_pixel = 16;
+ var->red = red;
+ var->green = green;
+ var->blue = blue;
+}
+
+static int dlfb_ops_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
- struct dlfb_data *dev_info = info->par;
- image_blit(dev_info, 0, 0, info->var.xres, info->var.yres,
- info->screen_base);
+ struct fb_videomode mode;
+
+ /* TODO: support dynamically changing framebuffer size */
+ if ((var->xres * var->yres * 2) > info->fix.smem_len)
+ return -EINVAL;
+
+ /* set device-specific elements of var unrelated to mode */
+ dlfb_var_color_format(var);
+
+ fb_var_to_videomode(&mode, var);
+
+ if (!dlfb_is_valid_mode(&mode, info))
+ return -EINVAL;
+
return 0;
}
-static int dlfb_blank(int blank_mode, struct fb_info *info)
+static int dlfb_ops_set_par(struct fb_info *info)
{
- struct dlfb_data *dev_info = info->par;
- char *bufptr = dev_info->buf;
+ struct dlfb_data *dev = info->par;
+
+ dl_notice("set_par mode %dx%d\n", info->var.xres, info->var.yres);
- bufptr = dlfb_set_register(bufptr, 0xFF, 0x00);
+ return dlfb_set_video_mode(dev, &info->var);
+}
+
+static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
+{
+ struct dlfb_data *dev = info->par;
+ char *bufptr;
+ struct urb *urb;
+
+ urb = dlfb_get_urb(dev);
+ if (!urb)
+ return 0;
+ bufptr = (char *) urb->transfer_buffer;
+
+ /* overloading usb_active. UNBLANK can conflict with teardown */
+
+ bufptr = dlfb_vidreg_lock(bufptr);
if (blank_mode != FB_BLANK_UNBLANK) {
- bufptr = dlfb_set_register(bufptr, 0x1F, 0x01);
+ atomic_set(&dev->usb_active, 0);
+ bufptr = dlfb_enable_hvsync(bufptr, false);
} else {
- bufptr = dlfb_set_register(bufptr, 0x1F, 0x00);
+ atomic_set(&dev->usb_active, 1);
+ bufptr = dlfb_enable_hvsync(bufptr, true);
}
- bufptr = dlfb_set_register(bufptr, 0xFF, 0xFF);
+ bufptr = dlfb_vidreg_unlock(bufptr);
- dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
+ dlfb_submit_urb(dev, urb, bufptr - (char *) urb->transfer_buffer);
return 0;
}
static struct fb_ops dlfb_ops = {
- .fb_setcolreg = dlfb_setcolreg,
- .fb_fillrect = dlfb_fillrect,
- .fb_copyarea = dlfb_copyarea,
- .fb_imageblit = dlfb_imageblit,
- .fb_mmap = dlfb_mmap,
- .fb_ioctl = dlfb_ioctl,
- .fb_release = dlfb_release,
- .fb_blank = dlfb_blank,
+ .owner = THIS_MODULE,
+ .fb_setcolreg = dlfb_ops_setcolreg,
+ .fb_fillrect = dlfb_ops_fillrect,
+ .fb_copyarea = dlfb_ops_copyarea,
+ .fb_imageblit = dlfb_ops_imageblit,
+ .fb_mmap = dlfb_ops_mmap,
+ .fb_ioctl = dlfb_ops_ioctl,
+ .fb_open = dlfb_ops_open,
+ .fb_release = dlfb_ops_release,
+ .fb_blank = dlfb_ops_blank,
+ .fb_check_var = dlfb_ops_check_var,
+ .fb_set_par = dlfb_ops_set_par,
};
-static int
-dlfb_probe(struct usb_interface *interface, const struct usb_device_id *id)
+/*
+ * Calls dlfb_get_edid() to query the EDID of attached monitor via usb cmds
+ * Then parses EDID into three places used by various parts of fbdev:
+ * fb_var_screeninfo contains the timing of the monitor's preferred mode
+ * fb_info.monspecs is full parsed EDID info, including monspecs.modedb
+ * fb_info.modelist is a linked list of all monitor & VESA modes which work
+ *
+ * If EDID is not readable/valid, then modelist is all VESA modes,
+ * monspecs is NULL, and fb_var_screeninfo is set to safe VESA mode
+ * Returns 0 if EDID parses successfully
+ */
+static int dlfb_parse_edid(struct dlfb_data *dev,
+ struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
- struct dlfb_data *dev_info;
- struct fb_info *info;
+ int i;
+ const struct fb_videomode *default_vmode = NULL;
+ int result = 0;
- int ret;
- char rbuf[4];
+ fb_destroy_modelist(&info->modelist);
+ memset(&info->monspecs, 0, sizeof(info->monspecs));
- dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL);
- if (dev_info == NULL) {
- printk("cannot allocate dev_info structure.\n");
- return -ENOMEM;
+ dlfb_get_edid(dev);
+ fb_edid_to_monspecs(dev->edid, &info->monspecs);
+
+ if (info->monspecs.modedb_len > 0) {
+
+ for (i = 0; i < info->monspecs.modedb_len; i++) {
+ if (dlfb_is_valid_mode(&info->monspecs.modedb[i], info))
+ fb_add_videomode(&info->monspecs.modedb[i],
+ &info->modelist);
+ }
+
+ default_vmode = fb_find_best_display(&info->monspecs,
+ &info->modelist);
+ } else {
+ struct fb_videomode fb_vmode = {0};
+
+ dl_err("Unable to get valid EDID from device/display\n");
+ result = 1;
+
+ /*
+ * Add the standard VESA modes to our modelist
+ * Since we don't have EDID, there may be modes that
+ * overspec monitor and/or are incorrect aspect ratio, etc.
+ * But at least the user has a chance to choose
+ */
+ for (i = 0; i < VESA_MODEDB_SIZE; i++) {
+ if (dlfb_is_valid_mode((struct fb_videomode *)
+ &vesa_modes[i], info))
+ fb_add_videomode(&vesa_modes[i],
+ &info->modelist);
+ }
+
+ /*
+ * default to resolution safe for projectors
+ * (since they are most common case without EDID)
+ */
+ fb_vmode.xres = 800;
+ fb_vmode.yres = 600;
+ fb_vmode.refresh = 60;
+ default_vmode = fb_find_nearest_mode(&fb_vmode,
+ &info->modelist);
}
- mutex_init(&dev_info->bulk_mutex);
+ fb_videomode_to_var(var, default_vmode);
+ dlfb_var_color_format(var);
- dev_info->udev = usb_get_dev(interface_to_usbdev(interface));
- dev_info->interface = interface;
+ return result;
+}
- printk("DisplayLink device attached\n");
+static ssize_t metrics_bytes_rendered_show(struct device *fbdev,
+ struct device_attribute *a, char *buf) {
+ struct fb_info *fb_info = dev_get_drvdata(fbdev);
+ struct dlfb_data *dev = fb_info->par;
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ atomic_read(&dev->bytes_rendered));
+}
- /* add framebuffer info to usb interface */
- usb_set_intfdata(interface, dev_info);
+static ssize_t metrics_bytes_identical_show(struct device *fbdev,
+ struct device_attribute *a, char *buf) {
+ struct fb_info *fb_info = dev_get_drvdata(fbdev);
+ struct dlfb_data *dev = fb_info->par;
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ atomic_read(&dev->bytes_identical));
+}
- dev_info->buf = kmalloc(BUF_SIZE, GFP_KERNEL);
- /* usb_buffer_alloc(dev_info->udev, BUF_SIZE , GFP_KERNEL, &dev_info->tx_urb->transfer_dma); */
+static ssize_t metrics_bytes_sent_show(struct device *fbdev,
+ struct device_attribute *a, char *buf) {
+ struct fb_info *fb_info = dev_get_drvdata(fbdev);
+ struct dlfb_data *dev = fb_info->par;
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ atomic_read(&dev->bytes_sent));
+}
- if (dev_info->buf == NULL) {
- printk("unable to allocate memory for dlfb commands\n");
- goto out;
- }
- dev_info->bufend = dev_info->buf + BUF_SIZE;
+static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev,
+ struct device_attribute *a, char *buf) {
+ struct fb_info *fb_info = dev_get_drvdata(fbdev);
+ struct dlfb_data *dev = fb_info->par;
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ atomic_read(&dev->cpu_kcycles_used));
+}
- dev_info->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
- usb_fill_bulk_urb(dev_info->tx_urb, dev_info->udev,
- usb_sndbulkpipe(dev_info->udev, 1), dev_info->buf, 0,
- dlfb_bulk_callback, dev_info);
+static ssize_t metrics_misc_show(struct device *fbdev,
+ struct device_attribute *a, char *buf) {
+ struct fb_info *fb_info = dev_get_drvdata(fbdev);
+ struct dlfb_data *dev = fb_info->par;
+ return snprintf(buf, PAGE_SIZE,
+ "Calls to\ndamage: %u\nblit: %u\n"
+ "defio faults: %u\ncopy: %u\n"
+ "fill: %u\n\n"
+ "active framebuffer clients: %d\n"
+ "urbs available %d(%d)\n"
+ "Shadow framebuffer in use? %s\n"
+ "Any lost pixels? %s\n",
+ atomic_read(&dev->damage_count),
+ atomic_read(&dev->blit_count),
+ atomic_read(&dev->defio_fault_count),
+ atomic_read(&dev->copy_count),
+ atomic_read(&dev->fill_count),
+ dev->fb_count,
+ dev->urbs.available, dev->urbs.limit_sem.count,
+ (dev->backing_buffer) ? "yes" : "no",
+ atomic_read(&dev->lost_pixels) ? "yes" : "no");
+}
- ret =
- usb_control_msg(dev_info->udev, usb_rcvctrlpipe(dev_info->udev, 0),
- (0x06), (0x80 | (0x02 << 5)), 0, 0, rbuf, 4, 0);
- printk("ret control msg 0: %d %x%x%x%x\n", ret, rbuf[0], rbuf[1],
- rbuf[2], rbuf[3]);
+static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *a,
+ char *buf, loff_t off, size_t count) {
+ struct device *fbdev = container_of(kobj, struct device, kobj);
+ struct fb_info *fb_info = dev_get_drvdata(fbdev);
+ struct dlfb_data *dev = fb_info->par;
+ char *edid = &dev->edid[0];
+ const size_t size = sizeof(dev->edid);
- dlfb_edid(dev_info);
+ if (dlfb_parse_edid(dev, &fb_info->var, fb_info))
+ return 0;
- info = framebuffer_alloc(sizeof(u32) * 256, &dev_info->udev->dev);
+ if (off >= size)
+ return 0;
- if (!info) {
- printk("non posso allocare il framebuffer displaylink");
- goto out;
- }
+ if (off + count > size)
+ count = size - off;
+ memcpy(buf, edid + off, count);
- fb_parse_edid(dev_info->edid, &info->var);
+ return count;
+}
- printk("EDID XRES %d YRES %d\n", info->var.xres, info->var.yres);
- if (dlfb_set_video_mode(dev_info, info->var.xres, info->var.yres) != 0) {
- info->var.xres = 1280;
- info->var.yres = 1024;
- if (dlfb_set_video_mode
- (dev_info, info->var.xres, info->var.yres) != 0) {
- goto out;
- }
+static ssize_t metrics_reset_store(struct device *fbdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *fb_info = dev_get_drvdata(fbdev);
+ struct dlfb_data *dev = fb_info->par;
+
+ atomic_set(&dev->bytes_rendered, 0);
+ atomic_set(&dev->bytes_identical, 0);
+ atomic_set(&dev->bytes_sent, 0);
+ atomic_set(&dev->cpu_kcycles_used, 0);
+ atomic_set(&dev->blit_count, 0);
+ atomic_set(&dev->copy_count, 0);
+ atomic_set(&dev->fill_count, 0);
+ atomic_set(&dev->defio_fault_count, 0);
+ atomic_set(&dev->damage_count, 0);
+
+ return count;
+}
+
+static ssize_t use_defio_show(struct device *fbdev,
+ struct device_attribute *a, char *buf) {
+ struct fb_info *fb_info = dev_get_drvdata(fbdev);
+ struct dlfb_data *dev = fb_info->par;
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ atomic_read(&dev->use_defio));
+}
+
+static ssize_t use_defio_store(struct device *fbdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *fb_info = dev_get_drvdata(fbdev);
+ struct dlfb_data *dev = fb_info->par;
+
+ if (count > 0) {
+ if (buf[0] == '0')
+ atomic_set(&dev->use_defio, 0);
+ if (buf[0] == '1')
+ atomic_set(&dev->use_defio, 1);
}
+ return count;
+}
- printk("found valid mode...%d\n", info->var.pixclock);
+static struct bin_attribute edid_attr = {
+ .attr.name = "edid",
+ .attr.mode = 0444,
+ .size = 128,
+ .read = edid_show,
+};
- info->pseudo_palette = info->par;
- info->par = dev_info;
+static struct device_attribute fb_device_attrs[] = {
+ __ATTR_RO(metrics_bytes_rendered),
+ __ATTR_RO(metrics_bytes_identical),
+ __ATTR_RO(metrics_bytes_sent),
+ __ATTR_RO(metrics_cpu_kcycles_used),
+ __ATTR_RO(metrics_misc),
+ __ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store),
+ __ATTR_RW(use_defio),
+};
- dev_info->info = info;
+#ifdef CONFIG_FB_DEFERRED_IO
+static void dlfb_dpy_deferred_io(struct fb_info *info,
+ struct list_head *pagelist)
+{
+ struct page *cur;
+ struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct dlfb_data *dev = info->par;
+ struct urb *urb;
+ char *cmd;
+ cycles_t start_cycles, end_cycles;
+ int bytes_sent = 0;
+ int bytes_identical = 0;
+ int bytes_rendered = 0;
+ int fault_count = 0;
+
+ if (!atomic_read(&dev->use_defio))
+ return;
- info->flags =
- FBINFO_DEFAULT | FBINFO_READS_FAST | FBINFO_HWACCEL_IMAGEBLIT |
- FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
- info->fbops = &dlfb_ops;
- info->screen_base = rvmalloc(dev_info->screen_size);
+ if (!atomic_read(&dev->usb_active))
+ return;
+
+ start_cycles = get_cycles();
- if (info->screen_base == NULL) {
- printk
- ("cannot allocate framebuffer virtual memory of %d bytes\n",
- dev_info->screen_size);
- goto out0;
+ urb = dlfb_get_urb(dev);
+ if (!urb)
+ return;
+ cmd = urb->transfer_buffer;
+
+ /* walk the written page list and render each to device */
+ list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+ dlfb_render_hline(dev, &urb, (char *) info->fix.smem_start,
+ &cmd, cur->index << PAGE_SHIFT,
+ PAGE_SIZE, &bytes_identical, &bytes_sent);
+ bytes_rendered += PAGE_SIZE;
+ fault_count++;
}
- printk("screen base allocated !!!\n");
+ if (cmd > (char *) urb->transfer_buffer) {
+ /* Send partial buffer remaining before exiting */
+ int len = cmd - (char *) urb->transfer_buffer;
+ dlfb_submit_urb(dev, urb, len);
+ bytes_sent += len;
+ } else
+ dlfb_urb_completion(urb);
+
+ atomic_add(fault_count, &dev->defio_fault_count);
+ atomic_add(bytes_sent, &dev->bytes_sent);
+ atomic_add(bytes_identical, &dev->bytes_identical);
+ atomic_add(bytes_rendered, &dev->bytes_rendered);
+ end_cycles = get_cycles();
+ atomic_add(((unsigned int) ((end_cycles - start_cycles)
+ >> 10)), /* Kcycles */
+ &dev->cpu_kcycles_used);
+}
- dev_info->backing_buffer = kzalloc(dev_info->screen_size, GFP_KERNEL);
+static struct fb_deferred_io dlfb_defio = {
+ .delay = 5,
+ .deferred_io = dlfb_dpy_deferred_io,
+};
- if (!dev_info->backing_buffer)
- printk("non posso allocare il backing buffer\n");
+#endif
- /* info->var = dev_info->si; */
+/*
+ * This is necessary before we can communicate with the display controller.
+ */
+static int dlfb_select_std_channel(struct dlfb_data *dev)
+{
+ int ret;
+ u8 set_def_chn[] = { 0x57, 0xCD, 0xDC, 0xA7,
+ 0x1C, 0x88, 0x5E, 0x15,
+ 0x60, 0xFE, 0xC6, 0x97,
+ 0x16, 0x3D, 0x47, 0xF2 };
+
+ ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+ NR_USB_REQUEST_CHANNEL,
+ (USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0,
+ set_def_chn, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT);
+ return ret;
+}
- info->var.bits_per_pixel = 16;
- info->var.activate = FB_ACTIVATE_TEST;
- info->var.vmode = FB_VMODE_NONINTERLACED;
- info->var.red.offset = 11;
- info->var.red.length = 5;
- info->var.red.msb_right = 0;
+static int dlfb_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usbdev;
+ struct dlfb_data *dev;
+ struct fb_info *info;
+ int videomemorysize;
+ int i;
+ unsigned char *videomemory;
+ int retval = -ENOMEM;
+ struct fb_var_screeninfo *var;
+ int registered = 0;
+ u16 *pix_framebuffer;
+
+ /* usb initialization */
+
+ usbdev = interface_to_usbdev(interface);
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ err("dlfb_usb_probe: failed alloc of dev struct\n");
+ goto error;
+ }
- info->var.green.offset = 5;
- info->var.green.length = 6;
- info->var.green.msb_right = 0;
+ /* we need to wait for both usb and fbdev to spin down on disconnect */
+ kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
+ kref_get(&dev->kref); /* matching kref_put in .fb_destroy function*/
- info->var.blue.offset = 0;
- info->var.blue.length = 5;
- info->var.blue.msb_right = 0;
+ dev->udev = usbdev;
+ dev->gdev = &usbdev->dev; /* our generic struct device * */
+ usb_set_intfdata(interface, dev);
- /* info->var.pixclock = (10000000 / FB_W * 1000 / FB_H)/2 ; */
+ if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
+ retval = -ENOMEM;
+ dl_err("dlfb_alloc_urb_list failed\n");
+ goto error;
+ }
- info->fix.smem_start = (unsigned long)info->screen_base;
- info->fix.smem_len = PAGE_ALIGN(dev_info->screen_size);
- if (strlen(dev_info->udev->product) > 15) {
- memcpy(info->fix.id, dev_info->udev->product, 15);
- } else {
- memcpy(info->fix.id, dev_info->udev->product,
- strlen(dev_info->udev->product));
+ mutex_init(&dev->fb_open_lock);
+
+ /* We don't register a new USB class. Our client interface is fbdev */
+
+ /* allocates framebuffer driver structure, not framebuffer memory */
+ info = framebuffer_alloc(0, &usbdev->dev);
+ if (!info) {
+ retval = -ENOMEM;
+ dl_err("framebuffer_alloc failed\n");
+ goto error;
+ }
+ dev->info = info;
+ info->par = dev;
+ info->pseudo_palette = dev->pseudo_palette;
+ info->fbops = &dlfb_ops;
+
+ var = &info->var;
+
+ /* TODO set limit based on actual SKU detection */
+ dev->sku_pixel_limit = 2048 * 1152;
+
+ INIT_LIST_HEAD(&info->modelist);
+ dlfb_parse_edid(dev, var, info);
+
+ /*
+ * ok, now that we've got the size info, we can alloc our framebuffer.
+ */
+ info->fix = dlfb_fix;
+ info->fix.line_length = var->xres * (var->bits_per_pixel / 8);
+ videomemorysize = info->fix.line_length * var->yres;
+
+ /*
+ * The big chunk of system memory we use as a virtual framebuffer.
+ * TODO: Handle fbcon cursor code calling blit in interrupt context
+ */
+ videomemory = vmalloc(videomemorysize);
+ if (!videomemory) {
+ retval = -ENOMEM;
+ dl_err("Virtual framebuffer alloc failed\n");
+ goto error;
}
- info->fix.type = FB_TYPE_PACKED_PIXELS;
- info->fix.visual = FB_VISUAL_TRUECOLOR;
- info->fix.accel = info->flags;
- info->fix.line_length = dev_info->line_length;
- if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
- goto out1;
+ info->screen_base = videomemory;
+ info->fix.smem_len = PAGE_ALIGN(videomemorysize);
+ info->fix.smem_start = (unsigned long) videomemory;
+ info->flags = udlfb_info_flags;
+
+
+ /*
+ * Second framebuffer copy, mirroring the state of the framebuffer
+ * on the physical USB device. We can function without this.
+ * But with imperfect damage info we may end up sending pixels over USB
+ * that were, in fact, unchanged -- wasting limited USB bandwidth
+ */
+ dev->backing_buffer = vmalloc(videomemorysize);
+ if (!dev->backing_buffer)
+ dl_warn("No shadow/backing buffer allcoated\n");
+ else
+ memset(dev->backing_buffer, 0, videomemorysize);
+
+ retval = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (retval < 0) {
+ dl_err("fb_alloc_cmap failed %x\n", retval);
+ goto error;
+ }
+
+ /* ready to begin using device */
+
+#ifdef CONFIG_FB_DEFERRED_IO
+ atomic_set(&dev->use_defio, 1);
+#endif
+ atomic_set(&dev->usb_active, 1);
+ dlfb_select_std_channel(dev);
+
+ dlfb_ops_check_var(var, info);
+ dlfb_ops_set_par(info);
+
+ /* paint greenscreen */
+ pix_framebuffer = (u16 *) videomemory;
+ for (i = 0; i < videomemorysize / 2; i++)
+ pix_framebuffer[i] = 0x37e6;
+
+ dlfb_handle_damage(dev, 0, 0, info->var.xres, info->var.yres,
+ videomemory);
- printk("colormap allocated\n");
- if (register_framebuffer(info) < 0)
- goto out2;
+ retval = register_framebuffer(info);
+ if (retval < 0) {
+ dl_err("register_framebuffer failed %d\n", retval);
+ goto error;
+ }
+ registered = 1;
+
+ for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
+ device_create_file(info->dev, &fb_device_attrs[i]);
- draw_rect(dev_info, 0, 0, dev_info->info->var.xres,
- dev_info->info->var.yres, 0x30, 0xff, 0x30);
+ device_create_bin_file(info->dev, &edid_attr);
+ dl_err("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
+ " Using %dK framebuffer memory\n", info->node,
+ var->xres, var->yres,
+ ((dev->backing_buffer) ?
+ videomemorysize * 2 : videomemorysize) >> 10);
return 0;
-out2:
- fb_dealloc_cmap(&info->cmap);
-out1:
- rvfree(info->screen_base, dev_info->screen_size);
-out0:
- framebuffer_release(info);
-out:
- usb_set_intfdata(interface, NULL);
- usb_put_dev(dev_info->udev);
- kfree(dev_info);
- return -ENOMEM;
+error:
+ if (dev) {
+ if (registered) {
+ unregister_framebuffer(info);
+ dlfb_ops_destroy(info);
+ } else
+ kref_put(&dev->kref, dlfb_delete);
+
+ if (dev->urbs.count > 0)
+ dlfb_free_urb_list(dev);
+ kref_put(&dev->kref, dlfb_delete); /* last ref from kref_init */
+
+ /* dev has been deallocated. Do not dereference */
+ }
+ return retval;
}
-static void dlfb_disconnect(struct usb_interface *interface)
+static void dlfb_usb_disconnect(struct usb_interface *interface)
{
- struct dlfb_data *dev_info = usb_get_intfdata(interface);
+ struct dlfb_data *dev;
+ struct fb_info *info;
+ int i;
+
+ dev = usb_get_intfdata(interface);
+ info = dev->info;
- mutex_unlock(&dev_info->bulk_mutex);
+ /* when non-active we'll update virtual framebuffer, but no new urbs */
+ atomic_set(&dev->usb_active, 0);
- usb_kill_urb(dev_info->tx_urb);
- usb_free_urb(dev_info->tx_urb);
usb_set_intfdata(interface, NULL);
- usb_put_dev(dev_info->udev);
- if (dev_info->info) {
- unregister_framebuffer(dev_info->info);
- fb_dealloc_cmap(&dev_info->info->cmap);
- rvfree(dev_info->info->screen_base, dev_info->screen_size);
- kfree(dev_info->backing_buffer);
- framebuffer_release(dev_info->info);
+ for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
+ device_remove_file(info->dev, &fb_device_attrs[i]);
+
+ device_remove_bin_file(info->dev, &edid_attr);
+ /* this function will wait for all in-flight urbs to complete */
+ dlfb_free_urb_list(dev);
+
+ if (info) {
+ dl_notice("Detaching /dev/fb%d\n", info->node);
+ unregister_framebuffer(info);
+ dlfb_ops_destroy(info);
}
- kfree(dev_info);
+ /* release reference taken by kref_init in probe() */
+ kref_put(&dev->kref, dlfb_delete);
+
+ /* consider dlfb_data freed */
- printk("DisplayLink device disconnected\n");
+ return;
}
static struct usb_driver dlfb_driver = {
.name = "udlfb",
- .probe = dlfb_probe,
- .disconnect = dlfb_disconnect,
+ .probe = dlfb_usb_probe,
+ .disconnect = dlfb_usb_disconnect,
.id_table = id_table,
};
-static int __init dlfb_init(void)
+static int __init dlfb_module_init(void)
{
int res;
- dlfb_init_modes();
-
res = usb_register(&dlfb_driver);
if (res)
err("usb_register failed. Error number %d", res);
@@ -925,14 +1442,186 @@ static int __init dlfb_init(void)
return res;
}
-static void __exit dlfb_exit(void)
+static void __exit dlfb_module_exit(void)
{
usb_deregister(&dlfb_driver);
}
-module_init(dlfb_init);
-module_exit(dlfb_exit);
+module_init(dlfb_module_init);
+module_exit(dlfb_module_exit);
-MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>");
-MODULE_DESCRIPTION(DRIVER_VERSION);
+static void dlfb_urb_completion(struct urb *urb)
+{
+ struct urb_node *unode = urb->context;
+ struct dlfb_data *dev = unode->dev;
+ unsigned long flags;
+
+ /* sync/async unlink faults aren't errors */
+ if (urb->status) {
+ if (!(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN)) {
+ dl_err("%s - nonzero write bulk status received: %d\n",
+ __func__, urb->status);
+ atomic_set(&dev->lost_pixels, 1);
+ }
+ }
+
+ urb->transfer_buffer_length = dev->urbs.size; /* reset to actual */
+
+ spin_lock_irqsave(&dev->urbs.lock, flags);
+ list_add_tail(&unode->entry, &dev->urbs.list);
+ dev->urbs.available++;
+ spin_unlock_irqrestore(&dev->urbs.lock, flags);
+
+ up(&dev->urbs.limit_sem);
+}
+
+static void dlfb_free_urb_list(struct dlfb_data *dev)
+{
+ int count = dev->urbs.count;
+ struct list_head *node;
+ struct urb_node *unode;
+ struct urb *urb;
+ int ret;
+ unsigned long flags;
+
+ dl_notice("Waiting for completes and freeing all render urbs\n");
+
+ /* keep waiting and freeing, until we've got 'em all */
+ while (count--) {
+ /* Timeout means a memory leak and/or fault */
+ ret = down_timeout(&dev->urbs.limit_sem, FREE_URB_TIMEOUT);
+ if (ret) {
+ BUG_ON(ret);
+ break;
+ }
+ spin_lock_irqsave(&dev->urbs.lock, flags);
+
+ node = dev->urbs.list.next; /* have reserved one with sem */
+ list_del_init(node);
+
+ spin_unlock_irqrestore(&dev->urbs.lock, flags);
+
+ unode = list_entry(node, struct urb_node, entry);
+ urb = unode->urb;
+
+ /* Free each separately allocated piece */
+ usb_buffer_free(urb->dev, dev->urbs.size,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+ kfree(node);
+ }
+
+ kref_put(&dev->kref, dlfb_delete);
+
+}
+
+static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
+{
+ int i = 0;
+ struct urb *urb;
+ struct urb_node *unode;
+ char *buf;
+
+ spin_lock_init(&dev->urbs.lock);
+
+ dev->urbs.size = size;
+ INIT_LIST_HEAD(&dev->urbs.list);
+
+ while (i < count) {
+ unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
+ if (!unode)
+ break;
+ unode->dev = dev;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ kfree(unode);
+ break;
+ }
+ unode->urb = urb;
+
+ buf = usb_buffer_alloc(dev->udev, MAX_TRANSFER, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!buf) {
+ kfree(unode);
+ usb_free_urb(urb);
+ break;
+ }
+
+ /* urb->transfer_buffer_length set to actual before submit */
+ usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 1),
+ buf, size, dlfb_urb_completion, unode);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ list_add_tail(&unode->entry, &dev->urbs.list);
+
+ i++;
+ }
+
+ sema_init(&dev->urbs.limit_sem, i);
+ dev->urbs.count = i;
+ dev->urbs.available = i;
+
+ kref_get(&dev->kref); /* released in free_render_urbs() */
+
+ dl_notice("allocated %d %d byte urbs \n", i, (int) size);
+
+ return i;
+}
+
+static struct urb *dlfb_get_urb(struct dlfb_data *dev)
+{
+ int ret = 0;
+ struct list_head *entry;
+ struct urb_node *unode;
+ struct urb *urb = NULL;
+ unsigned long flags;
+
+ /* Wait for an in-flight buffer to complete and get re-queued */
+ ret = down_timeout(&dev->urbs.limit_sem, GET_URB_TIMEOUT);
+ if (ret) {
+ atomic_set(&dev->lost_pixels, 1);
+ dl_err("wait for urb interrupted: %x\n", ret);
+ goto error;
+ }
+
+ spin_lock_irqsave(&dev->urbs.lock, flags);
+
+ BUG_ON(list_empty(&dev->urbs.list)); /* reserved one with limit_sem */
+ entry = dev->urbs.list.next;
+ list_del_init(entry);
+ dev->urbs.available--;
+
+ spin_unlock_irqrestore(&dev->urbs.lock, flags);
+
+ unode = list_entry(entry, struct urb_node, entry);
+ urb = unode->urb;
+
+error:
+ return urb;
+}
+
+static int dlfb_submit_urb(struct dlfb_data *dev, struct urb *urb, size_t len)
+{
+ int ret;
+
+ BUG_ON(len > dev->urbs.size);
+
+ urb->transfer_buffer_length = len; /* set to actual payload len */
+ ret = usb_submit_urb(urb, GFP_KERNEL);
+ if (ret) {
+ dlfb_urb_completion(urb); /* because no one else will */
+ atomic_set(&dev->lost_pixels, 1);
+ dl_err("usb_submit_urb error %x\n", ret);
+ }
+ return ret;
+}
+
+MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, "
+ "Jaya Kumar <jayakumar.lkml@gmail.com>, "
+ "Bernie Thompson <bernie@plugable.com>");
+MODULE_DESCRIPTION("DisplayLink kernel framebuffer driver");
MODULE_LICENSE("GPL");
+
diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
index 40ad85ea8e67..b07a69371f1f 100644
--- a/drivers/staging/udlfb/udlfb.h
+++ b/drivers/staging/udlfb/udlfb.h
@@ -1,225 +1,106 @@
#ifndef UDLFB_H
#define UDLFB_H
-#define MAX_VMODES 4
-#define FB_BPP 16
+/*
+ * TODO: Propose standard fb.h ioctl for reporting damage,
+ * using _IOWR() and one of the existing area structs from fb.h
+ * Consider these ioctls deprecated, but they're still used by the
+ * DisplayLink X server as yet - need both to be modified in tandem
+ * when new ioctl(s) are ready.
+ */
+#define DLFB_IOCTL_RETURN_EDID 0xAD
+#define DLFB_IOCTL_REPORT_DAMAGE 0xAA
+struct dloarea {
+ int x, y;
+ int w, h;
+ int x2, y2;
+};
-#define STD_CHANNEL "\x57\xCD\xDC\xA7\x1C\x88\x5E\x15" \
- "\x60\xFE\xC6\x97\x16\x3D\x47\xF2"
+struct urb_node {
+ struct list_head entry;
+ struct dlfb_data *dev;
+ struct urb *urb;
+};
-/* as libdlo */
-#define BUF_HIGH_WATER_MARK 1024
-#define BUF_SIZE (64*1024)
+struct urb_list {
+ struct list_head list;
+ spinlock_t lock;
+ struct semaphore limit_sem;
+ int available;
+ int count;
+ size_t size;
+};
struct dlfb_data {
struct usb_device *udev;
- struct usb_interface *interface;
- struct urb *tx_urb, *ctrl_urb;
- struct usb_ctrlrequest dr;
+ struct device *gdev; /* &udev->dev */
struct fb_info *info;
- char *buf;
- char *bufend;
+ struct urb_list urbs;
+ struct kref kref;
char *backing_buffer;
- struct mutex bulk_mutex;
+ struct delayed_work deferred_work;
+ struct mutex fb_open_lock;
+ int fb_count;
+ atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
+ atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
+ atomic_t use_defio; /* 0 = rely on ioctls and blit/copy/fill rects */
char edid[128];
- int screen_size;
- int line_length;
- struct completion done;
+ int sku_pixel_limit;
int base16;
- int base16d;
int base8;
- int base8d;
+ u32 pseudo_palette[256];
+ /* blit-only rendering path metrics, exposed through sysfs */
+ atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */
+ atomic_t bytes_identical; /* saved effort with backbuffer comparison */
+ atomic_t bytes_sent; /* to usb, after compression including overhead */
+ atomic_t cpu_kcycles_used; /* transpired during pixel processing */
+ /* interface usage metrics. Clients can call driver via several */
+ atomic_t blit_count;
+ atomic_t copy_count;
+ atomic_t fill_count;
+ atomic_t damage_count;
+ atomic_t defio_fault_count;
};
-struct dlfb_video_mode {
- uint8_t col;
- uint32_t hclock;
- uint32_t vclock;
- uint8_t unknown1[6];
- uint16_t xres;
- uint8_t unknown2[6];
- uint16_t yres;
- uint8_t unknown3[4];
-} __attribute__ ((__packed__));
-
-static struct dlfb_video_mode dlfb_video_modes[MAX_VMODES];
-
-static void dlfb_bulk_callback(struct urb *urb)
-{
- struct dlfb_data *dev_info = urb->context;
- complete(&dev_info->done);
-}
-
-static void dlfb_edid(struct dlfb_data *dev_info)
-{
- int i;
- int ret;
- char rbuf[2];
-
- for (i = 0; i < 128; i++) {
- ret =
- usb_control_msg(dev_info->udev,
- usb_rcvctrlpipe(dev_info->udev, 0), (0x02),
- (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
- 0);
- /*printk("ret control msg edid %d: %d [%d]\n",i, ret, rbuf[1]); */
- dev_info->edid[i] = rbuf[1];
- }
-
-}
-
-static int dlfb_bulk_msg(struct dlfb_data *dev_info, int len)
-{
- int ret;
-
- init_completion(&dev_info->done);
-
- dev_info->tx_urb->actual_length = 0;
- dev_info->tx_urb->transfer_buffer_length = len;
-
- ret = usb_submit_urb(dev_info->tx_urb, GFP_KERNEL);
- if (!wait_for_completion_timeout(&dev_info->done, 1000)) {
- usb_kill_urb(dev_info->tx_urb);
- printk("usb timeout !!!\n");
- }
-
- return dev_info->tx_urb->actual_length;
-}
-
-static void dlfb_init_modes(void)
-{
- dlfb_video_modes[0].col = 0;
- memcpy(&dlfb_video_modes[0].hclock, "\x20\x3C\x7A\xC9", 4);
- memcpy(&dlfb_video_modes[0].vclock, "\xF2\x6C\x48\xF9", 4);
- memcpy(&dlfb_video_modes[0].unknown1, "\x70\x53\xFF\xFF\x21\x27", 6);
- dlfb_video_modes[0].xres = 800;
- memcpy(&dlfb_video_modes[0].unknown2, "\x91\xF3\xFF\xFF\xFF\xF9", 6);
- dlfb_video_modes[0].yres = 480;
- memcpy(&dlfb_video_modes[0].unknown3, "\x01\x02\xC8\x19", 4);
-
- dlfb_video_modes[1].col = 0;
- memcpy(&dlfb_video_modes[1].hclock, "\x36\x18\xD5\x10", 4);
- memcpy(&dlfb_video_modes[1].vclock, "\x60\xA9\x7B\x33", 4);
- memcpy(&dlfb_video_modes[1].unknown1, "\xA1\x2B\x27\x32\xFF\xFF", 6);
- dlfb_video_modes[1].xres = 1024;
- memcpy(&dlfb_video_modes[1].unknown2, "\xD9\x9A\xFF\xCA\xFF\xFF", 6);
- dlfb_video_modes[1].yres = 768;
- memcpy(&dlfb_video_modes[1].unknown3, "\x04\x03\xC8\x32", 4);
-
- dlfb_video_modes[2].col = 0;
- memcpy(&dlfb_video_modes[2].hclock, "\x98\xF8\x0D\x57", 4);
- memcpy(&dlfb_video_modes[2].vclock, "\x2A\x55\x4D\x54", 4);
- memcpy(&dlfb_video_modes[2].unknown1, "\xCA\x0D\xFF\xFF\x94\x43", 6);
- dlfb_video_modes[2].xres = 1280;
- memcpy(&dlfb_video_modes[2].unknown2, "\x9A\xA8\xFF\xFF\xFF\xF9", 6);
- dlfb_video_modes[2].yres = 1024;
- memcpy(&dlfb_video_modes[2].unknown3, "\x04\x02\x60\x54", 4);
-
- dlfb_video_modes[3].col = 0;
- memcpy(&dlfb_video_modes[3].hclock, "\x42\x24\x38\x36", 4);
- memcpy(&dlfb_video_modes[3].vclock, "\xC1\x52\xD9\x29", 4);
- memcpy(&dlfb_video_modes[3].unknown1, "\xEA\xB8\x32\x60\xFF\xFF", 6);
- dlfb_video_modes[3].xres = 1400;
- memcpy(&dlfb_video_modes[3].unknown2, "\xC9\x4E\xFF\xFF\xFF\xF2", 6);
- dlfb_video_modes[3].yres = 1050;
- memcpy(&dlfb_video_modes[3].unknown3, "\x04\x02\x1E\x5F", 4);
-}
-
-static char *dlfb_set_register(char *bufptr, uint8_t reg, uint8_t val)
-{
- *bufptr++ = 0xAF;
- *bufptr++ = 0x20;
- *bufptr++ = reg;
- *bufptr++ = val;
-
- return bufptr;
-}
-
-static int dlfb_set_video_mode(struct dlfb_data *dev_info, int width, int height)
-{
- int i, ret;
- unsigned char j;
- char *bufptr = dev_info->buf;
- uint8_t *vdata;
-
- for (i = 0; i < MAX_VMODES; i++) {
- printk("INIT VIDEO %d %d %d\n", i, dlfb_video_modes[i].xres,
- dlfb_video_modes[i].yres);
- if (dlfb_video_modes[i].xres == width
- && dlfb_video_modes[i].yres == height) {
-
- dev_info->base16 = 0;
- dev_info->base16d = width * height * (FB_BPP / 8);
-
- //dev_info->base8 = width * height * (FB_BPP / 8);
-
- dev_info->base8 = dev_info->base16;
- dev_info->base8d = dev_info->base16d;
-
- /* set encryption key (null) */
- memcpy(dev_info->buf, STD_CHANNEL, 16);
- ret =
- usb_control_msg(dev_info->udev,
- usb_sndctrlpipe(dev_info->udev, 0),
- 0x12, (0x02 << 5), 0, 0,
- dev_info->buf, 16, 0);
- printk("ret control msg 1 (STD_CHANNEL): %d\n", ret);
-
- /* set registers */
- bufptr = dlfb_set_register(bufptr, 0xFF, 0x00);
-
- /* set color depth */
- bufptr = dlfb_set_register(bufptr, 0x00, 0x00);
-
- /* set addresses */
- bufptr =
- dlfb_set_register(bufptr, 0x20,
- (char)(dev_info->base16 >> 16));
- bufptr =
- dlfb_set_register(bufptr, 0x21,
- (char)(dev_info->base16 >> 8));
- bufptr =
- dlfb_set_register(bufptr, 0x22,
- (char)(dev_info->base16));
-
- bufptr =
- dlfb_set_register(bufptr, 0x26,
- (char)(dev_info->base8 >> 16));
- bufptr =
- dlfb_set_register(bufptr, 0x27,
- (char)(dev_info->base8 >> 8));
- bufptr =
- dlfb_set_register(bufptr, 0x28,
- (char)(dev_info->base8));
+#define NR_USB_REQUEST_I2C_SUB_IO 0x02
+#define NR_USB_REQUEST_CHANNEL 0x12
- /* set video mode */
- vdata = (uint8_t *)&dlfb_video_modes[i];
- for (j = 0; j < 29; j++)
- bufptr = dlfb_set_register(bufptr, j, vdata[j]);
+/* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */
+#define BULK_SIZE 512
+#define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE)
+#define WRITES_IN_FLIGHT (4)
- /* blank */
- bufptr = dlfb_set_register(bufptr, 0x1F, 0x00);
+#define GET_URB_TIMEOUT HZ
+#define FREE_URB_TIMEOUT (HZ*2)
- /* end registers */
- bufptr = dlfb_set_register(bufptr, 0xFF, 0xFF);
+#define BPP 2
+#define MAX_CMD_PIXELS 255
- /* send */
- ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
- printk("ret bulk 2: %d %td\n", ret,
- bufptr - dev_info->buf);
+#define RLX_HEADER_BYTES 7
+#define MIN_RLX_PIX_BYTES 4
+#define MIN_RLX_CMD_BYTES (RLX_HEADER_BYTES + MIN_RLX_PIX_BYTES)
- /* flush */
- ret = dlfb_bulk_msg(dev_info, 0);
- printk("ret bulk 3: %d\n", ret);
+#define RLE_HEADER_BYTES 6
+#define MIN_RLE_PIX_BYTES 3
+#define MIN_RLE_CMD_BYTES (RLE_HEADER_BYTES + MIN_RLE_PIX_BYTES)
- dev_info->screen_size = width * height * (FB_BPP / 8);
- dev_info->line_length = width * (FB_BPP / 8);
+#define RAW_HEADER_BYTES 6
+#define MIN_RAW_PIX_BYTES 2
+#define MIN_RAW_CMD_BYTES (RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES)
- return 0;
- }
- }
+/* remove these once align.h patch is taken into kernel */
+#define DL_ALIGN_UP(x, a) ALIGN(x, a)
+#define DL_ALIGN_DOWN(x, a) ALIGN(x-(a-1), a)
- return -1;
-}
+/* remove once this gets added to sysfs.h */
+#define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store)
+#define dl_err(format, arg...) \
+ dev_err(dev->gdev, "dlfb: " format, ## arg)
+#define dl_warn(format, arg...) \
+ dev_warn(dev->gdev, "dlfb: " format, ## arg)
+#define dl_notice(format, arg...) \
+ dev_notice(dev->gdev, "dlfb: " format, ## arg)
+#define dl_info(format, arg...) \
+ dev_info(dev->gdev, "dlfb: " format, ## arg)
#endif
diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig
index 350d5d65ccf3..2c1d10acb8b5 100644
--- a/drivers/staging/usbip/Kconfig
+++ b/drivers/staging/usbip/Kconfig
@@ -34,3 +34,10 @@ config USB_IP_HOST
To compile this driver as a module, choose M here: the
module will be called usbip.
+
+config USB_IP_DEBUG_ENABLE
+ bool "USB-IP Debug Enable"
+ depends on USB_IP_COMMON
+ default N
+ ---help---
+ This enables the debug messages from the USB-IP drivers.
diff --git a/drivers/staging/usbip/Makefile b/drivers/staging/usbip/Makefile
index 179f4211f96b..6f2916b1807a 100644
--- a/drivers/staging/usbip/Makefile
+++ b/drivers/staging/usbip/Makefile
@@ -7,6 +7,6 @@ vhci-hcd-objs := vhci_sysfs.o vhci_tx.o vhci_rx.o vhci_hcd.o
obj-$(CONFIG_USB_IP_HOST) += usbip.o
usbip-objs := stub_dev.o stub_main.o stub_rx.o stub_tx.o
-ifeq ($(CONFIG_USB_DEBUG),y)
+ifeq ($(CONFIG_USB_IP_DEBUG_ENABLE),y)
EXTRA_CFLAGS += -DDEBUG
endif
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index ddb6f5fd04d5..7a45da8f9565 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -33,7 +33,7 @@
/*-------------------------------------------------------------------------*/
/* debug routines */
-#ifdef CONFIG_USB_DEBUG
+#ifdef CONFIG_USB_IP_DEBUG_ENABLE
unsigned long usbip_debug_flag = 0xffffffff;
#else
unsigned long usbip_debug_flag;
@@ -55,10 +55,7 @@ static ssize_t show_flag(struct device *dev, struct device_attribute *attr,
static ssize_t store_flag(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- unsigned long flag;
-
- sscanf(buf, "%lx", &flag);
- usbip_debug_flag = flag;
+ sscanf(buf, "%lx", &usbip_debug_flag);
return count;
}
@@ -66,33 +63,8 @@ DEVICE_ATTR(usbip_debug, (S_IRUGO | S_IWUSR), show_flag, store_flag);
static void usbip_dump_buffer(char *buff, int bufflen)
{
- int i;
-
- if (bufflen > 128) {
- for (i = 0; i < 128; i++) {
- if (i%24 == 0)
- printk(KERN_DEBUG " ");
- printk(KERN_DEBUG "%02x ", (unsigned char) buff[i]);
- if (i%4 == 3)
- printk(KERN_DEBUG "| ");
- if (i%24 == 23)
- printk(KERN_DEBUG "\n");
- }
- printk(KERN_DEBUG "... (%d byte)\n", bufflen);
- return;
- }
-
- for (i = 0; i < bufflen; i++) {
- if (i%24 == 0)
- printk(KERN_DEBUG " ");
- printk(KERN_DEBUG "%02x ", (unsigned char) buff[i]);
- if (i%4 == 3)
- printk(KERN_DEBUG "| ");
- if (i%24 == 23)
- printk(KERN_DEBUG "\n");
- }
- printk(KERN_DEBUG "\n");
-
+ print_hex_dump(KERN_DEBUG, "usb-ip", DUMP_PREFIX_OFFSET, 16, 4,
+ buff, bufflen, false);
}
static void usbip_dump_pipe(unsigned int p)
@@ -558,60 +530,6 @@ err:
}
EXPORT_SYMBOL_GPL(usbip_xmit);
-
-/* now a usrland utility should set options. */
-#if 0
-int setquickack(struct socket *socket)
-{
- mm_segment_t oldfs;
- int val = 1;
- int ret;
-
- oldfs = get_fs();
- set_fs(get_ds());
- ret = socket->ops->setsockopt(socket, SOL_TCP, TCP_QUICKACK,
- (char __user *) &val, sizeof(ret));
- set_fs(oldfs);
-
- return ret;
-}
-
-int setnodelay(struct socket *socket)
-{
- mm_segment_t oldfs;
- int val = 1;
- int ret;
-
- oldfs = get_fs();
- set_fs(get_ds());
- ret = socket->ops->setsockopt(socket, SOL_TCP, TCP_NODELAY,
- (char __user *) &val, sizeof(ret));
- set_fs(oldfs);
-
- return ret;
-}
-
-int setkeepalive(struct socket *socket)
-{
- mm_segment_t oldfs;
- int val = 1;
- int ret;
-
- oldfs = get_fs();
- set_fs(get_ds());
- ret = socket->ops->setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE,
- (char __user *) &val, sizeof(ret));
- set_fs(oldfs);
-
- return ret;
-}
-
-void setreuse(struct socket *socket)
-{
- socket->sk->sk_reuse = 1;
-}
-#endif
-
struct socket *sockfd_to_socket(unsigned int sockfd)
{
struct socket *socket;
diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h
index 1ca3eab8af18..6f1dcb197d13 100644
--- a/drivers/staging/usbip/usbip_common.h
+++ b/drivers/staging/usbip/usbip_common.h
@@ -33,12 +33,12 @@
*/
/**
- * usbip_udbg - print debug messages if CONFIG_USB_DEBUG is defined
+ * usbip_udbg - print debug messages if CONFIG_USB_IP_DEBUG_ENABLE is defined
* @fmt:
* @args:
*/
-#ifdef CONFIG_USB_DEBUG
+#ifdef CONFIG_USB_IP_DEBUG_ENABLE
#define usbip_udbg(fmt, args...) \
do { \
@@ -47,11 +47,11 @@
__FILE__, __LINE__, __func__, ##args); \
} while (0)
-#else /* CONFIG_USB_DEBUG */
+#else /* CONFIG_USB_IP_DEBUG_ENABLE */
#define usbip_udbg(fmt, args...) do { } while (0)
-#endif /* CONFIG_USB_DEBUG */
+#endif /* CONFIG_USB_IP_DEBUG_ENABLE */
enum {
diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c
index d8992d10d555..f6e34e03c8e4 100644
--- a/drivers/staging/usbip/vhci_sysfs.c
+++ b/drivers/staging/usbip/vhci_sysfs.c
@@ -144,7 +144,7 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed)
case USB_SPEED_LOW:
case USB_SPEED_FULL:
case USB_SPEED_HIGH:
- case USB_SPEED_VARIABLE:
+ case USB_SPEED_WIRELESS:
break;
default:
usbip_uerr("speed %d\n", speed);
diff --git a/drivers/staging/vme/Kconfig b/drivers/staging/vme/Kconfig
index ae628a58b0c6..6411ae51ed3f 100644
--- a/drivers/staging/vme/Kconfig
+++ b/drivers/staging/vme/Kconfig
@@ -14,4 +14,6 @@ source "drivers/staging/vme/bridges/Kconfig"
source "drivers/staging/vme/devices/Kconfig"
+source "drivers/staging/vme/boards/Kconfig"
+
endif # VME
diff --git a/drivers/staging/vme/Makefile b/drivers/staging/vme/Makefile
index 8c3b90ee5853..b4ea3f8d0a50 100644
--- a/drivers/staging/vme/Makefile
+++ b/drivers/staging/vme/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_VME_BUS) += vme.o
obj-y += bridges/
obj-y += devices/
+obj-y += boards/
diff --git a/drivers/staging/vme/TODO b/drivers/staging/vme/TODO
index 2201ff6f74d1..82c222b4a146 100644
--- a/drivers/staging/vme/TODO
+++ b/drivers/staging/vme/TODO
@@ -4,28 +4,6 @@
API
===
-DMA Resource Allocation incomplete
-----------------------------------
-
-The current DMA resource Allocation provides no means of selecting the
-suitability of a DMA controller based on it's supported modes of operation, as
-opposed to the resource allocation mechanisms for master and slave windows:
-
- struct vme_resource *vme_dma_request(struct device *dev);
-
-As opposed to:
-
- struct vme_resource * vme_master_request(struct device *dev,
- vme_address_t aspace, vme_cycle_t cycle, vme_width_t width);
-
-The TSI148 can perform, VME-to-PCI, PCI-to-VME, PATTERN-to-VME, PATTERN-to-PCI,
-VME-to-VME and PCI-to-PCI transfers. The CA91C142 can only provide VME-to-PCI
-and PCI-to-VME.
-
-Add a mechanism to select a VME controller based on source/target type,
-required aspace, cycle and width requirements.
-
-
Master window broadcast select mask
-----------------------------------
@@ -59,7 +37,6 @@ chips. They are currently not supported at all by the API.
Core
====
-- Rename vme_master_resource's "pci_resource" to be bus agnostic.
- Improve generic sanity checks (Such as does an offset and size fit within a
window and parameter checking).
@@ -69,7 +46,6 @@ Bridge Support
Tempe (tsi148)
--------------
-- Driver can currently only support a single bridge.
- 2eSST Broadcast mode.
- Mailboxes unsupported.
- Improve error detection.
@@ -80,10 +56,6 @@ Tempe (tsi148)
Universe II (ca91c142)
----------------------
-- Driver can currently only support a single bridge.
-- DMA unsupported.
-- RMW transactions unsupported.
-- Location Monitors unsupported.
- Mailboxes unsupported.
- Error Detection.
- Control of prefetch size, threshold.
diff --git a/drivers/staging/vme/boards/Kconfig b/drivers/staging/vme/boards/Kconfig
new file mode 100644
index 000000000000..761631353527
--- /dev/null
+++ b/drivers/staging/vme/boards/Kconfig
@@ -0,0 +1,9 @@
+comment "VME Board Drivers"
+
+config VMIVME_7805
+ tristate "VMIVME-7805"
+ help
+ If you say Y here you get support for the VMIVME-7805 board.
+ This board has an additional control interface to the Universe II
+ chip. This driver has to be included if you want to access VME bus
+ with VMIVME-7805 board.
diff --git a/drivers/staging/vme/boards/Makefile b/drivers/staging/vme/boards/Makefile
new file mode 100644
index 000000000000..43658340885d
--- /dev/null
+++ b/drivers/staging/vme/boards/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the VME board drivers.
+#
+
+obj-$(CONFIG_VMIVME_7805) += vme_vmivme7805.o
diff --git a/drivers/staging/vme/boards/vme_vmivme7805.c b/drivers/staging/vme/boards/vme_vmivme7805.c
new file mode 100644
index 000000000000..843c9edde555
--- /dev/null
+++ b/drivers/staging/vme/boards/vme_vmivme7805.c
@@ -0,0 +1,124 @@
+/*
+ * Support for the VMIVME-7805 board access to the Universe II bridge.
+ *
+ * Author: Arthur Benilov <arthur.benilov@iba-group.com>
+ * Copyright 2010 Ion Beam Application, 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/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/io.h>
+
+#include "vme_vmivme7805.h"
+
+static int __init vmic_init(void);
+static int vmic_probe(struct pci_dev *, const struct pci_device_id *);
+static void vmic_remove(struct pci_dev *);
+static void __exit vmic_exit(void);
+
+/** Base address to access FPGA register */
+static void *vmic_base;
+
+static char driver_name[] = "vmivme_7805";
+
+static struct pci_device_id vmic_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_VMIC, PCI_DEVICE_ID_VTIMR) },
+ { },
+};
+
+static struct pci_driver vmic_driver = {
+ .name = driver_name,
+ .id_table = vmic_ids,
+ .probe = vmic_probe,
+ .remove = vmic_remove,
+};
+
+static int __init vmic_init(void)
+{
+ return pci_register_driver(&vmic_driver);
+}
+
+static int vmic_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ int retval;
+ u32 data;
+
+ /* Enable the device */
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ dev_err(&pdev->dev, "Unable to enable device\n");
+ goto err;
+ }
+
+ /* Map Registers */
+ retval = pci_request_regions(pdev, driver_name);
+ if (retval) {
+ dev_err(&pdev->dev, "Unable to reserve resources\n");
+ goto err_resource;
+ }
+
+ /* Map registers in BAR 0 */
+ vmic_base = ioremap_nocache(pci_resource_start(pdev, 0), 16);
+ if (!vmic_base) {
+ dev_err(&pdev->dev, "Unable to remap CRG region\n");
+ retval = -EIO;
+ goto err_remap;
+ }
+
+ /* Clear the FPGA VME IF contents */
+ iowrite32(0, vmic_base + VME_CONTROL);
+
+ /* Clear any initial BERR */
+ data = ioread32(vmic_base + VME_CONTROL) & 0x00000FFF;
+ data |= BM_VME_CONTROL_BERRST;
+ iowrite32(data, vmic_base + VME_CONTROL);
+
+ /* Enable the vme interface and byte swapping */
+ data = ioread32(vmic_base + VME_CONTROL) & 0x00000FFF;
+ data = data | BM_VME_CONTROL_MASTER_ENDIAN |
+ BM_VME_CONTROL_SLAVE_ENDIAN |
+ BM_VME_CONTROL_ABLE |
+ BM_VME_CONTROL_BERRI |
+ BM_VME_CONTROL_BPENA |
+ BM_VME_CONTROL_VBENA;
+ iowrite32(data, vmic_base + VME_CONTROL);
+
+ return 0;
+
+err_remap:
+ pci_release_regions(pdev);
+err_resource:
+ pci_disable_device(pdev);
+err:
+ return retval;
+}
+
+static void vmic_remove(struct pci_dev *pdev)
+{
+ iounmap(vmic_base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+
+}
+
+static void __exit vmic_exit(void)
+{
+ pci_unregister_driver(&vmic_driver);
+}
+
+MODULE_DESCRIPTION("VMIVME-7805 board support driver");
+MODULE_AUTHOR("Arthur Benilov <arthur.benilov@iba-group.com>");
+MODULE_LICENSE("GPL");
+
+module_init(vmic_init);
+module_exit(vmic_exit);
+
diff --git a/drivers/staging/vme/boards/vme_vmivme7805.h b/drivers/staging/vme/boards/vme_vmivme7805.h
new file mode 100644
index 000000000000..44c2c449808c
--- /dev/null
+++ b/drivers/staging/vme/boards/vme_vmivme7805.h
@@ -0,0 +1,37 @@
+/*
+ * vmivme_7805.h
+ *
+ * Support for the VMIVME-7805 board access to the Universe II bridge.
+ *
+ * Author: Arthur Benilov <arthur.benilov@iba-group.com>
+ * Copyright 2010 Ion Beam Application, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+
+#ifndef _VMIVME_7805_H
+#define _VMIVME_7805_H
+
+#ifndef PCI_VENDOR_ID_VMIC
+#define PCI_VENDOR_ID_VMIC 0x114A
+#endif
+
+#ifndef PCI_DEVICE_ID_VTIMR
+#define PCI_DEVICE_ID_VTIMR 0x0004
+#endif
+
+#define VME_CONTROL 0x0000
+#define BM_VME_CONTROL_MASTER_ENDIAN 0x0001
+#define BM_VME_CONTROL_SLAVE_ENDIAN 0x0002
+#define BM_VME_CONTROL_ABLE 0x0004
+#define BM_VME_CONTROL_BERRI 0x0040
+#define BM_VME_CONTROL_BERRST 0x0080
+#define BM_VME_CONTROL_BPENA 0x0400
+#define BM_VME_CONTROL_VBENA 0x0800
+
+#endif /* _VMIVME_7805_H */
+
diff --git a/drivers/staging/vme/bridges/Kconfig b/drivers/staging/vme/bridges/Kconfig
index 023cceba0c59..9331064e0476 100644
--- a/drivers/staging/vme/bridges/Kconfig
+++ b/drivers/staging/vme/bridges/Kconfig
@@ -2,12 +2,14 @@ comment "VME Bridge Drivers"
config VME_CA91CX42
tristate "Universe II"
+ depends on VIRT_TO_BUS
help
If you say Y here you get support for the Tundra CA91C142
(Universe II) VME bridge chip.
config VME_TSI148
tristate "Tempe"
+ depends on VIRT_TO_BUS
help
If you say Y here you get support for the Tundra TSI148 VME bridge
chip.
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c
index 1cf3e91db59d..2795ff2411e0 100644
--- a/drivers/staging/vme/bridges/vme_ca91cx42.c
+++ b/drivers/staging/vme/bridges/vme_ca91cx42.c
@@ -1,8 +1,8 @@
/*
* Support for the Tundra Universe I/II VME-PCI Bridge Chips
*
- * Author: Martyn Welch <martyn.welch@gefanuc.com>
- * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
*
* Based on work by Tom Armistead and Ajit Prem
* Copyright 2004 Motorola Inc.
@@ -38,25 +38,12 @@ static int ca91cx42_probe(struct pci_dev *, const struct pci_device_id *);
static void ca91cx42_remove(struct pci_dev *);
static void __exit ca91cx42_exit(void);
-struct vme_bridge *ca91cx42_bridge;
-wait_queue_head_t dma_queue;
-wait_queue_head_t iack_queue;
-wait_queue_head_t lm_queue;
-wait_queue_head_t mbox_queue;
-
-void (*lm_callback[4])(int); /* Called in interrupt handler, be careful! */
-void *crcsr_kernel;
-dma_addr_t crcsr_bus;
-
-struct mutex vme_rmw; /* Only one RMW cycle at a time */
-struct mutex vme_int; /*
- * Only one VME interrupt can be
- * generated at a time, provide locking
- */
+/* Module parameters */
+static int geoid;
static char driver_name[] = "vme_ca91cx42";
-static struct pci_device_id ca91cx42_ids[] = {
+static const struct pci_device_id ca91cx42_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C142) },
{ },
};
@@ -68,14 +55,14 @@ static struct pci_driver ca91cx42_driver = {
.remove = ca91cx42_remove,
};
-static u32 ca91cx42_DMA_irqhandler(void)
+static u32 ca91cx42_DMA_irqhandler(struct ca91cx42_driver *bridge)
{
- wake_up(&dma_queue);
+ wake_up(&(bridge->dma_queue));
return CA91CX42_LINT_DMA;
}
-static u32 ca91cx42_LM_irqhandler(u32 stat)
+static u32 ca91cx42_LM_irqhandler(struct ca91cx42_driver *bridge, u32 stat)
{
int i;
u32 serviced = 0;
@@ -83,7 +70,7 @@ static u32 ca91cx42_LM_irqhandler(u32 stat)
for (i = 0; i < 4; i++) {
if (stat & CA91CX42_LINT_LM[i]) {
/* We only enable interrupts if the callback is set */
- lm_callback[i](i);
+ bridge->lm_callback[i](i);
serviced |= CA91CX42_LINT_LM[i];
}
}
@@ -92,40 +79,25 @@ static u32 ca91cx42_LM_irqhandler(u32 stat)
}
/* XXX This needs to be split into 4 queues */
-static u32 ca91cx42_MB_irqhandler(int mbox_mask)
+static u32 ca91cx42_MB_irqhandler(struct ca91cx42_driver *bridge, int mbox_mask)
{
- wake_up(&mbox_queue);
+ wake_up(&(bridge->mbox_queue));
return CA91CX42_LINT_MBOX;
}
-static u32 ca91cx42_IACK_irqhandler(void)
+static u32 ca91cx42_IACK_irqhandler(struct ca91cx42_driver *bridge)
{
- wake_up(&iack_queue);
+ wake_up(&(bridge->iack_queue));
return CA91CX42_LINT_SW_IACK;
}
-#if 0
-int ca91cx42_bus_error_chk(int clrflag)
-{
- int tmp;
- tmp = ioread32(ca91cx42_bridge->base + PCI_COMMAND);
- if (tmp & 0x08000000) { /* S_TA is Set */
- if (clrflag)
- iowrite32(tmp | 0x08000000,
- ca91cx42_bridge->base + PCI_COMMAND);
- return 1;
- }
- return 0;
-}
-#endif
-
-static u32 ca91cx42_VERR_irqhandler(void)
+static u32 ca91cx42_VERR_irqhandler(struct ca91cx42_driver *bridge)
{
int val;
- val = ioread32(ca91cx42_bridge->base + DGCS);
+ val = ioread32(bridge->base + DGCS);
if (!(val & 0x00000800)) {
printk(KERN_ERR "ca91c042: ca91cx42_VERR_irqhandler DMA Read "
@@ -135,11 +107,11 @@ static u32 ca91cx42_VERR_irqhandler(void)
return CA91CX42_LINT_VERR;
}
-static u32 ca91cx42_LERR_irqhandler(void)
+static u32 ca91cx42_LERR_irqhandler(struct ca91cx42_driver *bridge)
{
int val;
- val = ioread32(ca91cx42_bridge->base + DGCS);
+ val = ioread32(bridge->base + DGCS);
if (!(val & 0x00000800)) {
printk(KERN_ERR "ca91c042: ca91cx42_LERR_irqhandler DMA Read "
@@ -151,13 +123,18 @@ static u32 ca91cx42_LERR_irqhandler(void)
}
-static u32 ca91cx42_VIRQ_irqhandler(int stat)
+static u32 ca91cx42_VIRQ_irqhandler(struct vme_bridge *ca91cx42_bridge,
+ int stat)
{
int vec, i, serviced = 0;
+ struct ca91cx42_driver *bridge;
+
+ bridge = ca91cx42_bridge->driver_priv;
+
for (i = 7; i > 0; i--) {
if (stat & (1 << i)) {
- vec = ioread32(ca91cx42_bridge->base +
+ vec = ioread32(bridge->base +
CA91CX42_V_STATID[i]) & 0xff;
vme_irq_handler(ca91cx42_bridge, i, vec);
@@ -169,15 +146,18 @@ static u32 ca91cx42_VIRQ_irqhandler(int stat)
return serviced;
}
-static irqreturn_t ca91cx42_irqhandler(int irq, void *dev_id)
+static irqreturn_t ca91cx42_irqhandler(int irq, void *ptr)
{
u32 stat, enable, serviced = 0;
+ struct vme_bridge *ca91cx42_bridge;
+ struct ca91cx42_driver *bridge;
- if (dev_id != ca91cx42_bridge->base)
- return IRQ_NONE;
+ ca91cx42_bridge = ptr;
- enable = ioread32(ca91cx42_bridge->base + LINT_EN);
- stat = ioread32(ca91cx42_bridge->base + LINT_STAT);
+ bridge = ca91cx42_bridge->driver_priv;
+
+ enable = ioread32(bridge->base + LINT_EN);
+ stat = ioread32(bridge->base + LINT_STAT);
/* Only look at unmasked interrupts */
stat &= enable;
@@ -186,42 +166,45 @@ static irqreturn_t ca91cx42_irqhandler(int irq, void *dev_id)
return IRQ_NONE;
if (stat & CA91CX42_LINT_DMA)
- serviced |= ca91cx42_DMA_irqhandler();
+ serviced |= ca91cx42_DMA_irqhandler(bridge);
if (stat & (CA91CX42_LINT_LM0 | CA91CX42_LINT_LM1 | CA91CX42_LINT_LM2 |
CA91CX42_LINT_LM3))
- serviced |= ca91cx42_LM_irqhandler(stat);
+ serviced |= ca91cx42_LM_irqhandler(bridge, stat);
if (stat & CA91CX42_LINT_MBOX)
- serviced |= ca91cx42_MB_irqhandler(stat);
+ serviced |= ca91cx42_MB_irqhandler(bridge, stat);
if (stat & CA91CX42_LINT_SW_IACK)
- serviced |= ca91cx42_IACK_irqhandler();
+ serviced |= ca91cx42_IACK_irqhandler(bridge);
if (stat & CA91CX42_LINT_VERR)
- serviced |= ca91cx42_VERR_irqhandler();
+ serviced |= ca91cx42_VERR_irqhandler(bridge);
if (stat & CA91CX42_LINT_LERR)
- serviced |= ca91cx42_LERR_irqhandler();
+ serviced |= ca91cx42_LERR_irqhandler(bridge);
if (stat & (CA91CX42_LINT_VIRQ1 | CA91CX42_LINT_VIRQ2 |
CA91CX42_LINT_VIRQ3 | CA91CX42_LINT_VIRQ4 |
CA91CX42_LINT_VIRQ5 | CA91CX42_LINT_VIRQ6 |
CA91CX42_LINT_VIRQ7))
- serviced |= ca91cx42_VIRQ_irqhandler(stat);
+ serviced |= ca91cx42_VIRQ_irqhandler(ca91cx42_bridge, stat);
/* Clear serviced interrupts */
- iowrite32(stat, ca91cx42_bridge->base + LINT_STAT);
+ iowrite32(stat, bridge->base + LINT_STAT);
return IRQ_HANDLED;
}
-static int ca91cx42_irq_init(struct vme_bridge *bridge)
+static int ca91cx42_irq_init(struct vme_bridge *ca91cx42_bridge)
{
int result, tmp;
struct pci_dev *pdev;
+ struct ca91cx42_driver *bridge;
+
+ bridge = ca91cx42_bridge->driver_priv;
/* Need pdev */
- pdev = container_of(bridge->parent, struct pci_dev, dev);
+ pdev = container_of(ca91cx42_bridge->parent, struct pci_dev, dev);
/* Initialise list for VME bus errors */
- INIT_LIST_HEAD(&(bridge->vme_errors));
+ INIT_LIST_HEAD(&(ca91cx42_bridge->vme_errors));
- mutex_init(&(bridge->irq_mtx));
+ mutex_init(&(ca91cx42_bridge->irq_mtx));
/* Disable interrupts from PCI to VME */
iowrite32(0, bridge->base + VINT_EN);
@@ -232,7 +215,7 @@ static int ca91cx42_irq_init(struct vme_bridge *bridge)
iowrite32(0x00FFFFFF, bridge->base + LINT_STAT);
result = request_irq(pdev->irq, ca91cx42_irqhandler, IRQF_SHARED,
- driver_name, pdev);
+ driver_name, ca91cx42_bridge);
if (result) {
dev_err(&pdev->dev, "Can't get assigned pci irq vector %02X\n",
pdev->irq);
@@ -254,15 +237,16 @@ static int ca91cx42_irq_init(struct vme_bridge *bridge)
return 0;
}
-static void ca91cx42_irq_exit(struct pci_dev *pdev)
+static void ca91cx42_irq_exit(struct ca91cx42_driver *bridge,
+ struct pci_dev *pdev)
{
/* Disable interrupts from PCI to VME */
- iowrite32(0, ca91cx42_bridge->base + VINT_EN);
+ iowrite32(0, bridge->base + VINT_EN);
/* Disable PCI interrupts */
- iowrite32(0, ca91cx42_bridge->base + LINT_EN);
+ iowrite32(0, bridge->base + LINT_EN);
/* Clear Any Pending PCI Interrupts */
- iowrite32(0x00FFFFFF, ca91cx42_bridge->base + LINT_STAT);
+ iowrite32(0x00FFFFFF, bridge->base + LINT_STAT);
free_irq(pdev->irq, pdev);
}
@@ -270,21 +254,25 @@ static void ca91cx42_irq_exit(struct pci_dev *pdev)
/*
* Set up an VME interrupt
*/
-void ca91cx42_irq_set(int level, int state, int sync)
+void ca91cx42_irq_set(struct vme_bridge *ca91cx42_bridge, int level, int state,
+ int sync)
{
struct pci_dev *pdev;
u32 tmp;
+ struct ca91cx42_driver *bridge;
+
+ bridge = ca91cx42_bridge->driver_priv;
/* Enable IRQ level */
- tmp = ioread32(ca91cx42_bridge->base + LINT_EN);
+ tmp = ioread32(bridge->base + LINT_EN);
if (state == 0)
tmp &= ~CA91CX42_LINT_VIRQ[level];
else
tmp |= CA91CX42_LINT_VIRQ[level];
- iowrite32(tmp, ca91cx42_bridge->base + LINT_EN);
+ iowrite32(tmp, bridge->base + LINT_EN);
if ((state == 0) && (sync != 0)) {
pdev = container_of(ca91cx42_bridge->parent, struct pci_dev,
@@ -294,34 +282,38 @@ void ca91cx42_irq_set(int level, int state, int sync)
}
}
-int ca91cx42_irq_generate(int level, int statid)
+int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level,
+ int statid)
{
u32 tmp;
+ struct ca91cx42_driver *bridge;
+
+ bridge = ca91cx42_bridge->driver_priv;
/* Universe can only generate even vectors */
if (statid & 1)
return -EINVAL;
- mutex_lock(&(vme_int));
+ mutex_lock(&(bridge->vme_int));
- tmp = ioread32(ca91cx42_bridge->base + VINT_EN);
+ tmp = ioread32(bridge->base + VINT_EN);
/* Set Status/ID */
- iowrite32(statid << 24, ca91cx42_bridge->base + STATID);
+ iowrite32(statid << 24, bridge->base + STATID);
/* Assert VMEbus IRQ */
tmp = tmp | (1 << (level + 24));
- iowrite32(tmp, ca91cx42_bridge->base + VINT_EN);
+ iowrite32(tmp, bridge->base + VINT_EN);
/* Wait for IACK */
- wait_event_interruptible(iack_queue, 0);
+ wait_event_interruptible(bridge->iack_queue, 0);
/* Return interrupt to low state */
- tmp = ioread32(ca91cx42_bridge->base + VINT_EN);
+ tmp = ioread32(bridge->base + VINT_EN);
tmp = tmp & ~(1 << (level + 24));
- iowrite32(tmp, ca91cx42_bridge->base + VINT_EN);
+ iowrite32(tmp, bridge->base + VINT_EN);
- mutex_unlock(&(vme_int));
+ mutex_unlock(&(bridge->vme_int));
return 0;
}
@@ -330,9 +322,12 @@ int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled,
unsigned long long vme_base, unsigned long long size,
dma_addr_t pci_base, vme_address_t aspace, vme_cycle_t cycle)
{
- unsigned int i, addr = 0, granularity = 0;
+ unsigned int i, addr = 0, granularity;
unsigned int temp_ctl = 0;
unsigned int vme_bound, pci_offset;
+ struct ca91cx42_driver *bridge;
+
+ bridge = image->parent->driver_priv;
i = image->number;
@@ -366,13 +361,9 @@ int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled,
* Bound address is a valid address for the window, adjust
* accordingly
*/
- vme_bound = vme_base + size - granularity;
+ vme_bound = vme_base + size;
pci_offset = pci_base - vme_base;
- /* XXX Need to check that vme_base, vme_bound and pci_offset aren't
- * too big for registers
- */
-
if ((i == 0) || (i == 4))
granularity = 0x1000;
else
@@ -392,26 +383,14 @@ int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled,
}
/* Disable while we are mucking around */
- temp_ctl = ioread32(ca91cx42_bridge->base + CA91CX42_VSI_CTL[i]);
+ temp_ctl = ioread32(bridge->base + CA91CX42_VSI_CTL[i]);
temp_ctl &= ~CA91CX42_VSI_CTL_EN;
- iowrite32(temp_ctl, ca91cx42_bridge->base + CA91CX42_VSI_CTL[i]);
+ iowrite32(temp_ctl, bridge->base + CA91CX42_VSI_CTL[i]);
/* Setup mapping */
- iowrite32(vme_base, ca91cx42_bridge->base + CA91CX42_VSI_BS[i]);
- iowrite32(vme_bound, ca91cx42_bridge->base + CA91CX42_VSI_BD[i]);
- iowrite32(pci_offset, ca91cx42_bridge->base + CA91CX42_VSI_TO[i]);
-
-/* XXX Prefetch stuff currently unsupported */
-#if 0
- if (vmeIn->wrPostEnable)
- temp_ctl |= CA91CX42_VSI_CTL_PWEN;
- if (vmeIn->prefetchEnable)
- temp_ctl |= CA91CX42_VSI_CTL_PREN;
- if (vmeIn->rmwLock)
- temp_ctl |= CA91CX42_VSI_CTL_LLRMW;
- if (vmeIn->data64BitCapable)
- temp_ctl |= CA91CX42_VSI_CTL_LD64EN;
-#endif
+ iowrite32(vme_base, bridge->base + CA91CX42_VSI_BS[i]);
+ iowrite32(vme_bound, bridge->base + CA91CX42_VSI_BD[i]);
+ iowrite32(pci_offset, bridge->base + CA91CX42_VSI_TO[i]);
/* Setup address space */
temp_ctl &= ~CA91CX42_VSI_CTL_VAS_M;
@@ -429,12 +408,12 @@ int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled,
temp_ctl |= CA91CX42_VSI_CTL_PGM_DATA;
/* Write ctl reg without enable */
- iowrite32(temp_ctl, ca91cx42_bridge->base + CA91CX42_VSI_CTL[i]);
+ iowrite32(temp_ctl, bridge->base + CA91CX42_VSI_CTL[i]);
if (enabled)
temp_ctl |= CA91CX42_VSI_CTL_EN;
- iowrite32(temp_ctl, ca91cx42_bridge->base + CA91CX42_VSI_CTL[i]);
+ iowrite32(temp_ctl, bridge->base + CA91CX42_VSI_CTL[i]);
return 0;
}
@@ -445,6 +424,9 @@ int ca91cx42_slave_get(struct vme_slave_resource *image, int *enabled,
{
unsigned int i, granularity = 0, ctl = 0;
unsigned long long vme_bound, pci_offset;
+ struct ca91cx42_driver *bridge;
+
+ bridge = image->parent->driver_priv;
i = image->number;
@@ -454,11 +436,11 @@ int ca91cx42_slave_get(struct vme_slave_resource *image, int *enabled,
granularity = 0x10000;
/* Read Registers */
- ctl = ioread32(ca91cx42_bridge->base + CA91CX42_VSI_CTL[i]);
+ ctl = ioread32(bridge->base + CA91CX42_VSI_CTL[i]);
- *vme_base = ioread32(ca91cx42_bridge->base + CA91CX42_VSI_BS[i]);
- vme_bound = ioread32(ca91cx42_bridge->base + CA91CX42_VSI_BD[i]);
- pci_offset = ioread32(ca91cx42_bridge->base + CA91CX42_VSI_TO[i]);
+ *vme_base = ioread32(bridge->base + CA91CX42_VSI_BS[i]);
+ vme_bound = ioread32(bridge->base + CA91CX42_VSI_BD[i]);
+ pci_offset = ioread32(bridge->base + CA91CX42_VSI_TO[i]);
*pci_base = (dma_addr_t)vme_base + pci_offset;
*size = (unsigned long long)((vme_bound - *vme_base) + granularity);
@@ -502,6 +484,9 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image,
unsigned long long existing_size;
int retval = 0;
struct pci_dev *pdev;
+ struct vme_bridge *ca91cx42_bridge;
+
+ ca91cx42_bridge = image->parent;
/* Find pci_dev container of dev */
if (ca91cx42_bridge->parent == NULL) {
@@ -510,8 +495,8 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image,
}
pdev = container_of(ca91cx42_bridge->parent, struct pci_dev, dev);
- existing_size = (unsigned long long)(image->pci_resource.end -
- image->pci_resource.start);
+ existing_size = (unsigned long long)(image->bus_resource.end -
+ image->bus_resource.start);
/* If the existing size is OK, return */
if (existing_size == (size - 1))
@@ -520,15 +505,15 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image,
if (existing_size != 0) {
iounmap(image->kern_base);
image->kern_base = NULL;
- if (image->pci_resource.name != NULL)
- kfree(image->pci_resource.name);
- release_resource(&(image->pci_resource));
- memset(&(image->pci_resource), 0, sizeof(struct resource));
+ if (image->bus_resource.name != NULL)
+ kfree(image->bus_resource.name);
+ release_resource(&(image->bus_resource));
+ memset(&(image->bus_resource), 0, sizeof(struct resource));
}
- if (image->pci_resource.name == NULL) {
- image->pci_resource.name = kmalloc(VMENAMSIZ+3, GFP_KERNEL);
- if (image->pci_resource.name == NULL) {
+ if (image->bus_resource.name == NULL) {
+ image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_KERNEL);
+ if (image->bus_resource.name == NULL) {
printk(KERN_ERR "Unable to allocate memory for resource"
" name\n");
retval = -ENOMEM;
@@ -536,26 +521,26 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image,
}
}
- sprintf((char *)image->pci_resource.name, "%s.%d",
+ sprintf((char *)image->bus_resource.name, "%s.%d",
ca91cx42_bridge->name, image->number);
- image->pci_resource.start = 0;
- image->pci_resource.end = (unsigned long)size;
- image->pci_resource.flags = IORESOURCE_MEM;
+ image->bus_resource.start = 0;
+ image->bus_resource.end = (unsigned long)size;
+ image->bus_resource.flags = IORESOURCE_MEM;
retval = pci_bus_alloc_resource(pdev->bus,
- &(image->pci_resource), size, size, PCIBIOS_MIN_MEM,
+ &(image->bus_resource), size, size, PCIBIOS_MIN_MEM,
0, NULL, NULL);
if (retval) {
printk(KERN_ERR "Failed to allocate mem resource for "
"window %d size 0x%lx start 0x%lx\n",
image->number, (unsigned long)size,
- (unsigned long)image->pci_resource.start);
+ (unsigned long)image->bus_resource.start);
goto err_resource;
}
image->kern_base = ioremap_nocache(
- image->pci_resource.start, size);
+ image->bus_resource.start, size);
if (image->kern_base == NULL) {
printk(KERN_ERR "Failed to remap resource\n");
retval = -ENOMEM;
@@ -567,24 +552,24 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image,
iounmap(image->kern_base);
image->kern_base = NULL;
err_remap:
- release_resource(&(image->pci_resource));
+ release_resource(&(image->bus_resource));
err_resource:
- kfree(image->pci_resource.name);
- memset(&(image->pci_resource), 0, sizeof(struct resource));
+ kfree(image->bus_resource.name);
+ memset(&(image->bus_resource), 0, sizeof(struct resource));
err_name:
return retval;
}
/*
- * * Free and unmap PCI Resource
- * */
+ * Free and unmap PCI Resource
+ */
static void ca91cx42_free_resource(struct vme_master_resource *image)
{
iounmap(image->kern_base);
image->kern_base = NULL;
- release_resource(&(image->pci_resource));
- kfree(image->pci_resource.name);
- memset(&(image->pci_resource), 0, sizeof(struct resource));
+ release_resource(&(image->bus_resource));
+ kfree(image->bus_resource.name);
+ memset(&(image->bus_resource), 0, sizeof(struct resource));
}
@@ -593,17 +578,27 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
{
int retval = 0;
- unsigned int i;
+ unsigned int i, granularity = 0;
unsigned int temp_ctl = 0;
unsigned long long pci_bound, vme_offset, pci_base;
+ struct ca91cx42_driver *bridge;
+
+ bridge = image->parent->driver_priv;
+
+ i = image->number;
+
+ if ((i == 0) || (i == 4))
+ granularity = 0x1000;
+ else
+ granularity = 0x10000;
/* Verify input data */
- if (vme_base & 0xFFF) {
+ if (vme_base & (granularity - 1)) {
printk(KERN_ERR "Invalid VME Window alignment\n");
retval = -EINVAL;
goto err_window;
}
- if (size & 0xFFF) {
+ if (size & (granularity - 1)) {
printk(KERN_ERR "Invalid VME Window alignment\n");
retval = -EINVAL;
goto err_window;
@@ -611,9 +606,6 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
spin_lock(&(image->lock));
- /* XXX We should do this much later, so that we can exit without
- * needing to redo the mapping...
- */
/*
* Let's allocate the resource here rather than further up the stack as
* it avoids pushing loads of bus dependant stuff up the stack
@@ -627,27 +619,19 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
goto err_res;
}
- pci_base = (unsigned long long)image->pci_resource.start;
+ pci_base = (unsigned long long)image->bus_resource.start;
/*
* Bound address is a valid address for the window, adjust
* according to window granularity.
*/
- pci_bound = pci_base + (size - 0x1000);
+ pci_bound = pci_base + size;
vme_offset = vme_base - pci_base;
- i = image->number;
-
/* Disable while we are mucking around */
- temp_ctl = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_CTL[i]);
+ temp_ctl = ioread32(bridge->base + CA91CX42_LSI_CTL[i]);
temp_ctl &= ~CA91CX42_LSI_CTL_EN;
- iowrite32(temp_ctl, ca91cx42_bridge->base + CA91CX42_LSI_CTL[i]);
-
-/* XXX Prefetch stuff currently unsupported */
-#if 0
- if (vmeOut->wrPostEnable)
- temp_ctl |= 0x40000000;
-#endif
+ iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]);
/* Setup cycle types */
temp_ctl &= ~CA91CX42_LSI_CTL_VCT_M;
@@ -718,17 +702,17 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
temp_ctl |= CA91CX42_LSI_CTL_PGM_PGM;
/* Setup mapping */
- iowrite32(pci_base, ca91cx42_bridge->base + CA91CX42_LSI_BS[i]);
- iowrite32(pci_bound, ca91cx42_bridge->base + CA91CX42_LSI_BD[i]);
- iowrite32(vme_offset, ca91cx42_bridge->base + CA91CX42_LSI_TO[i]);
+ iowrite32(pci_base, bridge->base + CA91CX42_LSI_BS[i]);
+ iowrite32(pci_bound, bridge->base + CA91CX42_LSI_BD[i]);
+ iowrite32(vme_offset, bridge->base + CA91CX42_LSI_TO[i]);
/* Write ctl reg without enable */
- iowrite32(temp_ctl, ca91cx42_bridge->base + CA91CX42_LSI_CTL[i]);
+ iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]);
if (enabled)
temp_ctl |= CA91CX42_LSI_CTL_EN;
- iowrite32(temp_ctl, ca91cx42_bridge->base + CA91CX42_LSI_CTL[i]);
+ iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]);
spin_unlock(&(image->lock));
return 0;
@@ -747,17 +731,20 @@ int __ca91cx42_master_get(struct vme_master_resource *image, int *enabled,
{
unsigned int i, ctl;
unsigned long long pci_base, pci_bound, vme_offset;
+ struct ca91cx42_driver *bridge;
+
+ bridge = image->parent->driver_priv;
i = image->number;
- ctl = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_CTL[i]);
+ ctl = ioread32(bridge->base + CA91CX42_LSI_CTL[i]);
- pci_base = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_BS[i]);
- vme_offset = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_TO[i]);
- pci_bound = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_BD[i]);
+ pci_base = ioread32(bridge->base + CA91CX42_LSI_BS[i]);
+ vme_offset = ioread32(bridge->base + CA91CX42_LSI_TO[i]);
+ pci_bound = ioread32(bridge->base + CA91CX42_LSI_BD[i]);
*vme_base = pci_base + vme_offset;
- *size = (pci_bound - pci_base) + 0x1000;
+ *size = (unsigned long long)(pci_bound - pci_base);
*enabled = 0;
*aspace = 0;
@@ -822,12 +809,6 @@ int __ca91cx42_master_get(struct vme_master_resource *image, int *enabled,
break;
}
-/* XXX Prefetch stuff currently unsupported */
-#if 0
- if (ctl & 0x40000000)
- vmeOut->wrPostEnable = 1;
-#endif
-
return 0;
}
@@ -850,7 +831,7 @@ int ca91cx42_master_get(struct vme_master_resource *image, int *enabled,
ssize_t ca91cx42_master_read(struct vme_master_resource *image, void *buf,
size_t count, loff_t offset)
{
- int retval;
+ ssize_t retval;
spin_lock(&(image->lock));
@@ -877,12 +858,528 @@ ssize_t ca91cx42_master_write(struct vme_master_resource *image, void *buf,
return retval;
}
-int ca91cx42_slot_get(void)
+unsigned int ca91cx42_master_rmw(struct vme_master_resource *image,
+ unsigned int mask, unsigned int compare, unsigned int swap,
+ loff_t offset)
+{
+ u32 pci_addr, result;
+ int i;
+ struct ca91cx42_driver *bridge;
+ struct device *dev;
+
+ bridge = image->parent->driver_priv;
+ dev = image->parent->parent;
+
+ /* Find the PCI address that maps to the desired VME address */
+ i = image->number;
+
+ /* Locking as we can only do one of these at a time */
+ mutex_lock(&(bridge->vme_rmw));
+
+ /* Lock image */
+ spin_lock(&(image->lock));
+
+ pci_addr = (u32)image->kern_base + offset;
+
+ /* Address must be 4-byte aligned */
+ if (pci_addr & 0x3) {
+ dev_err(dev, "RMW Address not 4-byte aligned\n");
+ return -EINVAL;
+ }
+
+ /* Ensure RMW Disabled whilst configuring */
+ iowrite32(0, bridge->base + SCYC_CTL);
+
+ /* Configure registers */
+ iowrite32(mask, bridge->base + SCYC_EN);
+ iowrite32(compare, bridge->base + SCYC_CMP);
+ iowrite32(swap, bridge->base + SCYC_SWP);
+ iowrite32(pci_addr, bridge->base + SCYC_ADDR);
+
+ /* Enable RMW */
+ iowrite32(CA91CX42_SCYC_CTL_CYC_RMW, bridge->base + SCYC_CTL);
+
+ /* Kick process off with a read to the required address. */
+ result = ioread32(image->kern_base + offset);
+
+ /* Disable RMW */
+ iowrite32(0, bridge->base + SCYC_CTL);
+
+ spin_unlock(&(image->lock));
+
+ mutex_unlock(&(bridge->vme_rmw));
+
+ return result;
+}
+
+int ca91cx42_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
+ struct vme_dma_attr *dest, size_t count)
+{
+ struct ca91cx42_dma_entry *entry, *prev;
+ struct vme_dma_pci *pci_attr;
+ struct vme_dma_vme *vme_attr;
+ dma_addr_t desc_ptr;
+ int retval = 0;
+
+ /* XXX descriptor must be aligned on 64-bit boundaries */
+ entry = (struct ca91cx42_dma_entry *)
+ kmalloc(sizeof(struct ca91cx42_dma_entry), GFP_KERNEL);
+ if (entry == NULL) {
+ printk(KERN_ERR "Failed to allocate memory for dma resource "
+ "structure\n");
+ retval = -ENOMEM;
+ goto err_mem;
+ }
+
+ /* Test descriptor alignment */
+ if ((unsigned long)&(entry->descriptor) & CA91CX42_DCPP_M) {
+ printk("Descriptor not aligned to 16 byte boundary as "
+ "required: %p\n", &(entry->descriptor));
+ retval = -EINVAL;
+ goto err_align;
+ }
+
+ memset(&(entry->descriptor), 0, sizeof(struct ca91cx42_dma_descriptor));
+
+ if (dest->type == VME_DMA_VME) {
+ entry->descriptor.dctl |= CA91CX42_DCTL_L2V;
+ vme_attr = (struct vme_dma_vme *)dest->private;
+ pci_attr = (struct vme_dma_pci *)src->private;
+ } else {
+ vme_attr = (struct vme_dma_vme *)src->private;
+ pci_attr = (struct vme_dma_pci *)dest->private;
+ }
+
+ /* Check we can do fullfill required attributes */
+ if ((vme_attr->aspace & ~(VME_A16 | VME_A24 | VME_A32 | VME_USER1 |
+ VME_USER2)) != 0) {
+
+ printk(KERN_ERR "Unsupported cycle type\n");
+ retval = -EINVAL;
+ goto err_aspace;
+ }
+
+ if ((vme_attr->cycle & ~(VME_SCT | VME_BLT | VME_SUPER | VME_USER |
+ VME_PROG | VME_DATA)) != 0) {
+
+ printk(KERN_ERR "Unsupported cycle type\n");
+ retval = -EINVAL;
+ goto err_cycle;
+ }
+
+ /* Check to see if we can fullfill source and destination */
+ if (!(((src->type == VME_DMA_PCI) && (dest->type == VME_DMA_VME)) ||
+ ((src->type == VME_DMA_VME) && (dest->type == VME_DMA_PCI)))) {
+
+ printk(KERN_ERR "Cannot perform transfer with this "
+ "source-destination combination\n");
+ retval = -EINVAL;
+ goto err_direct;
+ }
+
+ /* Setup cycle types */
+ if (vme_attr->cycle & VME_BLT)
+ entry->descriptor.dctl |= CA91CX42_DCTL_VCT_BLT;
+
+ /* Setup data width */
+ switch (vme_attr->dwidth) {
+ case VME_D8:
+ entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D8;
+ break;
+ case VME_D16:
+ entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D16;
+ break;
+ case VME_D32:
+ entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D32;
+ break;
+ case VME_D64:
+ entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D64;
+ break;
+ default:
+ printk(KERN_ERR "Invalid data width\n");
+ return -EINVAL;
+ }
+
+ /* Setup address space */
+ switch (vme_attr->aspace) {
+ case VME_A16:
+ entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A16;
+ break;
+ case VME_A24:
+ entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A24;
+ break;
+ case VME_A32:
+ entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A32;
+ break;
+ case VME_USER1:
+ entry->descriptor.dctl |= CA91CX42_DCTL_VAS_USER1;
+ break;
+ case VME_USER2:
+ entry->descriptor.dctl |= CA91CX42_DCTL_VAS_USER2;
+ break;
+ default:
+ printk(KERN_ERR "Invalid address space\n");
+ return -EINVAL;
+ break;
+ }
+
+ if (vme_attr->cycle & VME_SUPER)
+ entry->descriptor.dctl |= CA91CX42_DCTL_SUPER_SUPR;
+ if (vme_attr->cycle & VME_PROG)
+ entry->descriptor.dctl |= CA91CX42_DCTL_PGM_PGM;
+
+ entry->descriptor.dtbc = count;
+ entry->descriptor.dla = pci_attr->address;
+ entry->descriptor.dva = vme_attr->address;
+ entry->descriptor.dcpp = CA91CX42_DCPP_NULL;
+
+ /* Add to list */
+ list_add_tail(&(entry->list), &(list->entries));
+
+ /* Fill out previous descriptors "Next Address" */
+ if (entry->list.prev != &(list->entries)) {
+ prev = list_entry(entry->list.prev, struct ca91cx42_dma_entry,
+ list);
+ /* We need the bus address for the pointer */
+ desc_ptr = virt_to_bus(&(entry->descriptor));
+ prev->descriptor.dcpp = desc_ptr & ~CA91CX42_DCPP_M;
+ }
+
+ return 0;
+
+err_cycle:
+err_aspace:
+err_direct:
+err_align:
+ kfree(entry);
+err_mem:
+ return retval;
+}
+
+static int ca91cx42_dma_busy(struct vme_bridge *ca91cx42_bridge)
+{
+ u32 tmp;
+ struct ca91cx42_driver *bridge;
+
+ bridge = ca91cx42_bridge->driver_priv;
+
+ tmp = ioread32(bridge->base + DGCS);
+
+ if (tmp & CA91CX42_DGCS_ACT)
+ return 0;
+ else
+ return 1;
+}
+
+int ca91cx42_dma_list_exec(struct vme_dma_list *list)
+{
+ struct vme_dma_resource *ctrlr;
+ struct ca91cx42_dma_entry *entry;
+ int retval = 0;
+ dma_addr_t bus_addr;
+ u32 val;
+
+ struct ca91cx42_driver *bridge;
+
+ ctrlr = list->parent;
+
+ bridge = ctrlr->parent->driver_priv;
+
+ mutex_lock(&(ctrlr->mtx));
+
+ if (!(list_empty(&(ctrlr->running)))) {
+ /*
+ * XXX We have an active DMA transfer and currently haven't
+ * sorted out the mechanism for "pending" DMA transfers.
+ * Return busy.
+ */
+ /* Need to add to pending here */
+ mutex_unlock(&(ctrlr->mtx));
+ return -EBUSY;
+ } else {
+ list_add(&(list->list), &(ctrlr->running));
+ }
+
+ /* Get first bus address and write into registers */
+ entry = list_first_entry(&(list->entries), struct ca91cx42_dma_entry,
+ list);
+
+ bus_addr = virt_to_bus(&(entry->descriptor));
+
+ mutex_unlock(&(ctrlr->mtx));
+
+ iowrite32(0, bridge->base + DTBC);
+ iowrite32(bus_addr & ~CA91CX42_DCPP_M, bridge->base + DCPP);
+
+ /* Start the operation */
+ val = ioread32(bridge->base + DGCS);
+
+ /* XXX Could set VMEbus On and Off Counters here */
+ val &= (CA91CX42_DGCS_VON_M | CA91CX42_DGCS_VOFF_M);
+
+ val |= (CA91CX42_DGCS_CHAIN | CA91CX42_DGCS_STOP | CA91CX42_DGCS_HALT |
+ CA91CX42_DGCS_DONE | CA91CX42_DGCS_LERR | CA91CX42_DGCS_VERR |
+ CA91CX42_DGCS_PERR);
+
+ iowrite32(val, bridge->base + DGCS);
+
+ val |= CA91CX42_DGCS_GO;
+
+ iowrite32(val, bridge->base + DGCS);
+
+ wait_event_interruptible(bridge->dma_queue,
+ ca91cx42_dma_busy(ctrlr->parent));
+
+ /*
+ * Read status register, this register is valid until we kick off a
+ * new transfer.
+ */
+ val = ioread32(bridge->base + DGCS);
+
+ if (val & (CA91CX42_DGCS_LERR | CA91CX42_DGCS_VERR |
+ CA91CX42_DGCS_PERR)) {
+
+ printk(KERN_ERR "ca91c042: DMA Error. DGCS=%08X\n", val);
+ val = ioread32(bridge->base + DCTL);
+ }
+
+ /* Remove list from running list */
+ mutex_lock(&(ctrlr->mtx));
+ list_del(&(list->list));
+ mutex_unlock(&(ctrlr->mtx));
+
+ return retval;
+
+}
+
+int ca91cx42_dma_list_empty(struct vme_dma_list *list)
+{
+ struct list_head *pos, *temp;
+ struct ca91cx42_dma_entry *entry;
+
+ /* detach and free each entry */
+ list_for_each_safe(pos, temp, &(list->entries)) {
+ list_del(pos);
+ entry = list_entry(pos, struct ca91cx42_dma_entry, list);
+ kfree(entry);
+ }
+
+ return 0;
+}
+
+/*
+ * All 4 location monitors reside at the same base - this is therefore a
+ * system wide configuration.
+ *
+ * This does not enable the LM monitor - that should be done when the first
+ * callback is attached and disabled when the last callback is removed.
+ */
+int ca91cx42_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
+ vme_address_t aspace, vme_cycle_t cycle)
+{
+ u32 temp_base, lm_ctl = 0;
+ int i;
+ struct ca91cx42_driver *bridge;
+ struct device *dev;
+
+ bridge = lm->parent->driver_priv;
+ dev = lm->parent->parent;
+
+ /* Check the alignment of the location monitor */
+ temp_base = (u32)lm_base;
+ if (temp_base & 0xffff) {
+ dev_err(dev, "Location monitor must be aligned to 64KB "
+ "boundary");
+ return -EINVAL;
+ }
+
+ mutex_lock(&(lm->mtx));
+
+ /* If we already have a callback attached, we can't move it! */
+ for (i = 0; i < lm->monitors; i++) {
+ if (bridge->lm_callback[i] != NULL) {
+ mutex_unlock(&(lm->mtx));
+ dev_err(dev, "Location monitor callback attached, "
+ "can't reset\n");
+ return -EBUSY;
+ }
+ }
+
+ switch (aspace) {
+ case VME_A16:
+ lm_ctl |= CA91CX42_LM_CTL_AS_A16;
+ break;
+ case VME_A24:
+ lm_ctl |= CA91CX42_LM_CTL_AS_A24;
+ break;
+ case VME_A32:
+ lm_ctl |= CA91CX42_LM_CTL_AS_A32;
+ break;
+ default:
+ mutex_unlock(&(lm->mtx));
+ dev_err(dev, "Invalid address space\n");
+ return -EINVAL;
+ break;
+ }
+
+ if (cycle & VME_SUPER)
+ lm_ctl |= CA91CX42_LM_CTL_SUPR;
+ if (cycle & VME_USER)
+ lm_ctl |= CA91CX42_LM_CTL_NPRIV;
+ if (cycle & VME_PROG)
+ lm_ctl |= CA91CX42_LM_CTL_PGM;
+ if (cycle & VME_DATA)
+ lm_ctl |= CA91CX42_LM_CTL_DATA;
+
+ iowrite32(lm_base, bridge->base + LM_BS);
+ iowrite32(lm_ctl, bridge->base + LM_CTL);
+
+ mutex_unlock(&(lm->mtx));
+
+ return 0;
+}
+
+/* Get configuration of the callback monitor and return whether it is enabled
+ * or disabled.
+ */
+int ca91cx42_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base,
+ vme_address_t *aspace, vme_cycle_t *cycle)
+{
+ u32 lm_ctl, enabled = 0;
+ struct ca91cx42_driver *bridge;
+
+ bridge = lm->parent->driver_priv;
+
+ mutex_lock(&(lm->mtx));
+
+ *lm_base = (unsigned long long)ioread32(bridge->base + LM_BS);
+ lm_ctl = ioread32(bridge->base + LM_CTL);
+
+ if (lm_ctl & CA91CX42_LM_CTL_EN)
+ enabled = 1;
+
+ if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A16)
+ *aspace = VME_A16;
+ if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A24)
+ *aspace = VME_A24;
+ if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A32)
+ *aspace = VME_A32;
+
+ *cycle = 0;
+ if (lm_ctl & CA91CX42_LM_CTL_SUPR)
+ *cycle |= VME_SUPER;
+ if (lm_ctl & CA91CX42_LM_CTL_NPRIV)
+ *cycle |= VME_USER;
+ if (lm_ctl & CA91CX42_LM_CTL_PGM)
+ *cycle |= VME_PROG;
+ if (lm_ctl & CA91CX42_LM_CTL_DATA)
+ *cycle |= VME_DATA;
+
+ mutex_unlock(&(lm->mtx));
+
+ return enabled;
+}
+
+/*
+ * Attach a callback to a specific location monitor.
+ *
+ * Callback will be passed the monitor triggered.
+ */
+int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor,
+ void (*callback)(int))
+{
+ u32 lm_ctl, tmp;
+ struct ca91cx42_driver *bridge;
+ struct device *dev;
+
+ bridge = lm->parent->driver_priv;
+ dev = lm->parent->parent;
+
+ mutex_lock(&(lm->mtx));
+
+ /* Ensure that the location monitor is configured - need PGM or DATA */
+ lm_ctl = ioread32(bridge->base + LM_CTL);
+ if ((lm_ctl & (CA91CX42_LM_CTL_PGM | CA91CX42_LM_CTL_DATA)) == 0) {
+ mutex_unlock(&(lm->mtx));
+ dev_err(dev, "Location monitor not properly configured\n");
+ return -EINVAL;
+ }
+
+ /* Check that a callback isn't already attached */
+ if (bridge->lm_callback[monitor] != NULL) {
+ mutex_unlock(&(lm->mtx));
+ dev_err(dev, "Existing callback attached\n");
+ return -EBUSY;
+ }
+
+ /* Attach callback */
+ bridge->lm_callback[monitor] = callback;
+
+ /* Enable Location Monitor interrupt */
+ tmp = ioread32(bridge->base + LINT_EN);
+ tmp |= CA91CX42_LINT_LM[monitor];
+ iowrite32(tmp, bridge->base + LINT_EN);
+
+ /* Ensure that global Location Monitor Enable set */
+ if ((lm_ctl & CA91CX42_LM_CTL_EN) == 0) {
+ lm_ctl |= CA91CX42_LM_CTL_EN;
+ iowrite32(lm_ctl, bridge->base + LM_CTL);
+ }
+
+ mutex_unlock(&(lm->mtx));
+
+ return 0;
+}
+
+/*
+ * Detach a callback function forn a specific location monitor.
+ */
+int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor)
+{
+ u32 tmp;
+ struct ca91cx42_driver *bridge;
+
+ bridge = lm->parent->driver_priv;
+
+ mutex_lock(&(lm->mtx));
+
+ /* Disable Location Monitor and ensure previous interrupts are clear */
+ tmp = ioread32(bridge->base + LINT_EN);
+ tmp &= ~CA91CX42_LINT_LM[monitor];
+ iowrite32(tmp, bridge->base + LINT_EN);
+
+ iowrite32(CA91CX42_LINT_LM[monitor],
+ bridge->base + LINT_STAT);
+
+ /* Detach callback */
+ bridge->lm_callback[monitor] = NULL;
+
+ /* If all location monitors disabled, disable global Location Monitor */
+ if ((tmp & (CA91CX42_LINT_LM0 | CA91CX42_LINT_LM1 | CA91CX42_LINT_LM2 |
+ CA91CX42_LINT_LM3)) == 0) {
+ tmp = ioread32(bridge->base + LM_CTL);
+ tmp &= ~CA91CX42_LM_CTL_EN;
+ iowrite32(tmp, bridge->base + LM_CTL);
+ }
+
+ mutex_unlock(&(lm->mtx));
+
+ return 0;
+}
+
+int ca91cx42_slot_get(struct vme_bridge *ca91cx42_bridge)
{
u32 slot = 0;
+ struct ca91cx42_driver *bridge;
+
+ bridge = ca91cx42_bridge->driver_priv;
+
+ if (!geoid) {
+ slot = ioread32(bridge->base + VCSR_BS);
+ slot = ((slot & CA91CX42_VCSR_BS_SLOT_M) >> 27);
+ } else
+ slot = geoid;
- slot = ioread32(ca91cx42_bridge->base + VCSR_BS);
- slot = ((slot & CA91CX42_VCSR_BS_SLOT_M) >> 27);
return (int)slot;
}
@@ -900,19 +1397,21 @@ static int __init ca91cx42_init(void)
* Auto-ID or Geographic address. This function ensures that the window is
* enabled at an offset consistent with the boards geopgraphic address.
*/
-static int ca91cx42_crcsr_init(struct pci_dev *pdev)
+static int ca91cx42_crcsr_init(struct vme_bridge *ca91cx42_bridge,
+ struct pci_dev *pdev)
{
unsigned int crcsr_addr;
int tmp, slot;
+ struct ca91cx42_driver *bridge;
+
+ bridge = ca91cx42_bridge->driver_priv;
+
+ slot = ca91cx42_slot_get(ca91cx42_bridge);
+
+ /* Write CSR Base Address if slot ID is supplied as a module param */
+ if (geoid)
+ iowrite32(geoid << 27, bridge->base + VCSR_BS);
-/* XXX We may need to set this somehow as the Universe II does not support
- * geographical addressing.
- */
-#if 0
- if (vme_slotnum != -1)
- iowrite32(vme_slotnum << 27, ca91cx42_bridge->base + VCSR_BS);
-#endif
- slot = ca91cx42_slot_get();
dev_info(&pdev->dev, "CR/CSR Offset: %d\n", slot);
if (slot == 0) {
dev_err(&pdev->dev, "Slot number is unset, not configuring "
@@ -921,39 +1420,44 @@ static int ca91cx42_crcsr_init(struct pci_dev *pdev)
}
/* Allocate mem for CR/CSR image */
- crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
- &crcsr_bus);
- if (crcsr_kernel == NULL) {
+ bridge->crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
+ &(bridge->crcsr_bus));
+ if (bridge->crcsr_kernel == NULL) {
dev_err(&pdev->dev, "Failed to allocate memory for CR/CSR "
"image\n");
return -ENOMEM;
}
- memset(crcsr_kernel, 0, VME_CRCSR_BUF_SIZE);
+ memset(bridge->crcsr_kernel, 0, VME_CRCSR_BUF_SIZE);
crcsr_addr = slot * (512 * 1024);
- iowrite32(crcsr_bus - crcsr_addr, ca91cx42_bridge->base + VCSR_TO);
+ iowrite32(bridge->crcsr_bus - crcsr_addr, bridge->base + VCSR_TO);
- tmp = ioread32(ca91cx42_bridge->base + VCSR_CTL);
+ tmp = ioread32(bridge->base + VCSR_CTL);
tmp |= CA91CX42_VCSR_CTL_EN;
- iowrite32(tmp, ca91cx42_bridge->base + VCSR_CTL);
+ iowrite32(tmp, bridge->base + VCSR_CTL);
return 0;
}
-static void ca91cx42_crcsr_exit(struct pci_dev *pdev)
+static void ca91cx42_crcsr_exit(struct vme_bridge *ca91cx42_bridge,
+ struct pci_dev *pdev)
{
u32 tmp;
+ struct ca91cx42_driver *bridge;
+
+ bridge = ca91cx42_bridge->driver_priv;
/* Turn off CR/CSR space */
- tmp = ioread32(ca91cx42_bridge->base + VCSR_CTL);
+ tmp = ioread32(bridge->base + VCSR_CTL);
tmp &= ~CA91CX42_VCSR_CTL_EN;
- iowrite32(tmp, ca91cx42_bridge->base + VCSR_CTL);
+ iowrite32(tmp, bridge->base + VCSR_CTL);
/* Free image */
- iowrite32(0, ca91cx42_bridge->base + VCSR_TO);
+ iowrite32(0, bridge->base + VCSR_TO);
- pci_free_consistent(pdev, VME_CRCSR_BUF_SIZE, crcsr_kernel, crcsr_bus);
+ pci_free_consistent(pdev, VME_CRCSR_BUF_SIZE, bridge->crcsr_kernel,
+ bridge->crcsr_bus);
}
static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -961,11 +1465,11 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
int retval, i;
u32 data;
struct list_head *pos = NULL;
+ struct vme_bridge *ca91cx42_bridge;
+ struct ca91cx42_driver *ca91cx42_device;
struct vme_master_resource *master_image;
struct vme_slave_resource *slave_image;
-#if 0
struct vme_dma_resource *dma_ctrlr;
-#endif
struct vme_lm_resource *lm;
/* We want to support more than one of each bridge so we need to
@@ -982,6 +1486,19 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
memset(ca91cx42_bridge, 0, sizeof(struct vme_bridge));
+ ca91cx42_device = kmalloc(sizeof(struct ca91cx42_driver), GFP_KERNEL);
+
+ if (ca91cx42_device == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for device "
+ "structure\n");
+ retval = -ENOMEM;
+ goto err_driver;
+ }
+
+ memset(ca91cx42_device, 0, sizeof(struct ca91cx42_driver));
+
+ ca91cx42_bridge->driver_priv = ca91cx42_device;
+
/* Enable the device */
retval = pci_enable_device(pdev);
if (retval) {
@@ -997,16 +1514,16 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* map registers in BAR 0 */
- ca91cx42_bridge->base = ioremap_nocache(pci_resource_start(pdev, 0),
+ ca91cx42_device->base = ioremap_nocache(pci_resource_start(pdev, 0),
4096);
- if (!ca91cx42_bridge->base) {
+ if (!ca91cx42_device->base) {
dev_err(&pdev->dev, "Unable to remap CRG region\n");
retval = -EIO;
goto err_remap;
}
/* Check to see if the mapping worked out */
- data = ioread32(ca91cx42_bridge->base + CA91CX42_PCI_ID) & 0x0000FFFF;
+ data = ioread32(ca91cx42_device->base + CA91CX42_PCI_ID) & 0x0000FFFF;
if (data != PCI_VENDOR_ID_TUNDRA) {
dev_err(&pdev->dev, "PCI_ID check failed\n");
retval = -EIO;
@@ -1014,11 +1531,10 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* Initialize wait queues & mutual exclusion flags */
- /* XXX These need to be moved to the vme_bridge structure */
- init_waitqueue_head(&dma_queue);
- init_waitqueue_head(&iack_queue);
- mutex_init(&(vme_int));
- mutex_init(&(vme_rmw));
+ init_waitqueue_head(&(ca91cx42_device->dma_queue));
+ init_waitqueue_head(&(ca91cx42_device->iack_queue));
+ mutex_init(&(ca91cx42_device->vme_int));
+ mutex_init(&(ca91cx42_device->vme_rmw));
ca91cx42_bridge->parent = &(pdev->dev);
strcpy(ca91cx42_bridge->name, driver_name);
@@ -1050,7 +1566,7 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
VME_SUPER | VME_USER | VME_PROG | VME_DATA;
master_image->width_attr = VME_D8 | VME_D16 | VME_D32 | VME_D64;
- memset(&(master_image->pci_resource), 0,
+ memset(&(master_image->bus_resource), 0,
sizeof(struct resource));
master_image->kern_base = NULL;
list_add_tail(&(master_image->list),
@@ -1084,7 +1600,7 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
list_add_tail(&(slave_image->list),
&(ca91cx42_bridge->slave_resources));
}
-#if 0
+
/* Add dma engines to list */
INIT_LIST_HEAD(&(ca91cx42_bridge->dma_resources));
for (i = 0; i < CA91C142_MAX_DMA; i++) {
@@ -1100,12 +1616,14 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mutex_init(&(dma_ctrlr->mtx));
dma_ctrlr->locked = 0;
dma_ctrlr->number = i;
+ dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM |
+ VME_DMA_MEM_TO_VME;
INIT_LIST_HEAD(&(dma_ctrlr->pending));
INIT_LIST_HEAD(&(dma_ctrlr->running));
list_add_tail(&(dma_ctrlr->list),
&(ca91cx42_bridge->dma_resources));
}
-#endif
+
/* Add location monitor to list */
INIT_LIST_HEAD(&(ca91cx42_bridge->lm_resources));
lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
@@ -1128,33 +1646,26 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ca91cx42_bridge->master_set = ca91cx42_master_set;
ca91cx42_bridge->master_read = ca91cx42_master_read;
ca91cx42_bridge->master_write = ca91cx42_master_write;
-#if 0
ca91cx42_bridge->master_rmw = ca91cx42_master_rmw;
ca91cx42_bridge->dma_list_add = ca91cx42_dma_list_add;
ca91cx42_bridge->dma_list_exec = ca91cx42_dma_list_exec;
ca91cx42_bridge->dma_list_empty = ca91cx42_dma_list_empty;
-#endif
ca91cx42_bridge->irq_set = ca91cx42_irq_set;
ca91cx42_bridge->irq_generate = ca91cx42_irq_generate;
-#if 0
ca91cx42_bridge->lm_set = ca91cx42_lm_set;
ca91cx42_bridge->lm_get = ca91cx42_lm_get;
ca91cx42_bridge->lm_attach = ca91cx42_lm_attach;
ca91cx42_bridge->lm_detach = ca91cx42_lm_detach;
-#endif
ca91cx42_bridge->slot_get = ca91cx42_slot_get;
- data = ioread32(ca91cx42_bridge->base + MISC_CTL);
+ data = ioread32(ca91cx42_device->base + MISC_CTL);
dev_info(&pdev->dev, "Board is%s the VME system controller\n",
(data & CA91CX42_MISC_CTL_SYSCON) ? "" : " not");
- dev_info(&pdev->dev, "Slot ID is %d\n", ca91cx42_slot_get());
+ dev_info(&pdev->dev, "Slot ID is %d\n",
+ ca91cx42_slot_get(ca91cx42_bridge));
- if (ca91cx42_crcsr_init(pdev)) {
+ if (ca91cx42_crcsr_init(ca91cx42_bridge, pdev)) {
dev_err(&pdev->dev, "CR/CSR configuration failed.\n");
- retval = -EINVAL;
-#if 0
- goto err_crcsr;
-#endif
}
/* Need to save ca91cx42_bridge pointer locally in link list for use in
@@ -1166,14 +1677,13 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_reg;
}
+ pci_set_drvdata(pdev, ca91cx42_bridge);
+
return 0;
vme_unregister_bridge(ca91cx42_bridge);
err_reg:
- ca91cx42_crcsr_exit(pdev);
-#if 0
-err_crcsr:
-#endif
+ ca91cx42_crcsr_exit(ca91cx42_bridge, pdev);
err_lm:
/* resources are stored in link list */
list_for_each(pos, &(ca91cx42_bridge->lm_resources)) {
@@ -1181,7 +1691,6 @@ err_lm:
list_del(pos);
kfree(lm);
}
-#if 0
err_dma:
/* resources are stored in link list */
list_for_each(pos, &(ca91cx42_bridge->dma_resources)) {
@@ -1189,7 +1698,6 @@ err_dma:
list_del(pos);
kfree(dma_ctrlr);
}
-#endif
err_slave:
/* resources are stored in link list */
list_for_each(pos, &(ca91cx42_bridge->slave_resources)) {
@@ -1206,15 +1714,17 @@ err_master:
kfree(master_image);
}
- ca91cx42_irq_exit(pdev);
+ ca91cx42_irq_exit(ca91cx42_device, pdev);
err_irq:
err_test:
- iounmap(ca91cx42_bridge->base);
+ iounmap(ca91cx42_device->base);
err_remap:
pci_release_regions(pdev);
err_resource:
pci_disable_device(pdev);
err_enable:
+ kfree(ca91cx42_device);
+err_driver:
kfree(ca91cx42_bridge);
err_struct:
return retval;
@@ -1228,32 +1738,37 @@ void ca91cx42_remove(struct pci_dev *pdev)
struct vme_slave_resource *slave_image;
struct vme_dma_resource *dma_ctrlr;
struct vme_lm_resource *lm;
+ struct ca91cx42_driver *bridge;
+ struct vme_bridge *ca91cx42_bridge = pci_get_drvdata(pdev);
+
+ bridge = ca91cx42_bridge->driver_priv;
+
/* Turn off Ints */
- iowrite32(0, ca91cx42_bridge->base + LINT_EN);
+ iowrite32(0, bridge->base + LINT_EN);
/* Turn off the windows */
- iowrite32(0x00800000, ca91cx42_bridge->base + LSI0_CTL);
- iowrite32(0x00800000, ca91cx42_bridge->base + LSI1_CTL);
- iowrite32(0x00800000, ca91cx42_bridge->base + LSI2_CTL);
- iowrite32(0x00800000, ca91cx42_bridge->base + LSI3_CTL);
- iowrite32(0x00800000, ca91cx42_bridge->base + LSI4_CTL);
- iowrite32(0x00800000, ca91cx42_bridge->base + LSI5_CTL);
- iowrite32(0x00800000, ca91cx42_bridge->base + LSI6_CTL);
- iowrite32(0x00800000, ca91cx42_bridge->base + LSI7_CTL);
- iowrite32(0x00F00000, ca91cx42_bridge->base + VSI0_CTL);
- iowrite32(0x00F00000, ca91cx42_bridge->base + VSI1_CTL);
- iowrite32(0x00F00000, ca91cx42_bridge->base + VSI2_CTL);
- iowrite32(0x00F00000, ca91cx42_bridge->base + VSI3_CTL);
- iowrite32(0x00F00000, ca91cx42_bridge->base + VSI4_CTL);
- iowrite32(0x00F00000, ca91cx42_bridge->base + VSI5_CTL);
- iowrite32(0x00F00000, ca91cx42_bridge->base + VSI6_CTL);
- iowrite32(0x00F00000, ca91cx42_bridge->base + VSI7_CTL);
+ iowrite32(0x00800000, bridge->base + LSI0_CTL);
+ iowrite32(0x00800000, bridge->base + LSI1_CTL);
+ iowrite32(0x00800000, bridge->base + LSI2_CTL);
+ iowrite32(0x00800000, bridge->base + LSI3_CTL);
+ iowrite32(0x00800000, bridge->base + LSI4_CTL);
+ iowrite32(0x00800000, bridge->base + LSI5_CTL);
+ iowrite32(0x00800000, bridge->base + LSI6_CTL);
+ iowrite32(0x00800000, bridge->base + LSI7_CTL);
+ iowrite32(0x00F00000, bridge->base + VSI0_CTL);
+ iowrite32(0x00F00000, bridge->base + VSI1_CTL);
+ iowrite32(0x00F00000, bridge->base + VSI2_CTL);
+ iowrite32(0x00F00000, bridge->base + VSI3_CTL);
+ iowrite32(0x00F00000, bridge->base + VSI4_CTL);
+ iowrite32(0x00F00000, bridge->base + VSI5_CTL);
+ iowrite32(0x00F00000, bridge->base + VSI6_CTL);
+ iowrite32(0x00F00000, bridge->base + VSI7_CTL);
vme_unregister_bridge(ca91cx42_bridge);
-#if 0
- ca91cx42_crcsr_exit(pdev);
-#endif
+
+ ca91cx42_crcsr_exit(ca91cx42_bridge, pdev);
+
/* resources are stored in link list */
list_for_each(pos, &(ca91cx42_bridge->lm_resources)) {
lm = list_entry(pos, struct vme_lm_resource, list);
@@ -1283,9 +1798,9 @@ void ca91cx42_remove(struct pci_dev *pdev)
kfree(master_image);
}
- ca91cx42_irq_exit(pdev);
+ ca91cx42_irq_exit(bridge, pdev);
- iounmap(ca91cx42_bridge->base);
+ iounmap(bridge->base);
pci_release_regions(pdev);
@@ -1299,588 +1814,11 @@ static void __exit ca91cx42_exit(void)
pci_unregister_driver(&ca91cx42_driver);
}
+MODULE_PARM_DESC(geoid, "Override geographical addressing");
+module_param(geoid, int, 0);
+
MODULE_DESCRIPTION("VME driver for the Tundra Universe II VME bridge");
MODULE_LICENSE("GPL");
module_init(ca91cx42_init);
module_exit(ca91cx42_exit);
-
-/*----------------------------------------------------------------------------
- * STAGING
- *--------------------------------------------------------------------------*/
-
-#if 0
-#define SWIZZLE(X) ( ((X & 0xFF000000) >> 24) | ((X & 0x00FF0000) >> 8) | ((X & 0x0000FF00) << 8) | ((X & 0x000000FF) << 24))
-
-int ca91cx42_master_rmw(vmeRmwCfg_t *vmeRmw)
-{
- int temp_ctl = 0;
- int tempBS = 0;
- int tempBD = 0;
- int tempTO = 0;
- int vmeBS = 0;
- int vmeBD = 0;
- int *rmw_pci_data_ptr = NULL;
- int *vaDataPtr = NULL;
- int i;
- vmeOutWindowCfg_t vmeOut;
- if (vmeRmw->maxAttempts < 1) {
- return -EINVAL;
- }
- if (vmeRmw->targetAddrU) {
- return -EINVAL;
- }
- /* Find the PCI address that maps to the desired VME address */
- for (i = 0; i < 8; i++) {
- temp_ctl = ioread32(ca91cx42_bridge->base +
- CA91CX42_LSI_CTL[i]);
- if ((temp_ctl & 0x80000000) == 0) {
- continue;
- }
- memset(&vmeOut, 0, sizeof(vmeOut));
- vmeOut.windowNbr = i;
- ca91cx42_get_out_bound(&vmeOut);
- if (vmeOut.addrSpace != vmeRmw->addrSpace) {
- continue;
- }
- tempBS = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_BS[i]);
- tempBD = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_BD[i]);
- tempTO = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_TO[i]);
- vmeBS = tempBS + tempTO;
- vmeBD = tempBD + tempTO;
- if ((vmeRmw->targetAddr >= vmeBS) &&
- (vmeRmw->targetAddr < vmeBD)) {
- rmw_pci_data_ptr =
- (int *)(tempBS + (vmeRmw->targetAddr - vmeBS));
- vaDataPtr =
- (int *)(out_image_va[i] +
- (vmeRmw->targetAddr - vmeBS));
- break;
- }
- }
-
- /* If no window - fail. */
- if (rmw_pci_data_ptr == NULL) {
- return -EINVAL;
- }
- /* Setup the RMW registers. */
- iowrite32(0, ca91cx42_bridge->base + SCYC_CTL);
- iowrite32(SWIZZLE(vmeRmw->enableMask), ca91cx42_bridge->base + SCYC_EN);
- iowrite32(SWIZZLE(vmeRmw->compareData), ca91cx42_bridge->base +
- SCYC_CMP);
- iowrite32(SWIZZLE(vmeRmw->swapData), ca91cx42_bridge->base + SCYC_SWP);
- iowrite32((int)rmw_pci_data_ptr, ca91cx42_bridge->base + SCYC_ADDR);
- iowrite32(1, ca91cx42_bridge->base + SCYC_CTL);
-
- /* Run the RMW cycle until either success or max attempts. */
- vmeRmw->numAttempts = 1;
- while (vmeRmw->numAttempts <= vmeRmw->maxAttempts) {
-
- if ((ioread32(vaDataPtr) & vmeRmw->enableMask) ==
- (vmeRmw->swapData & vmeRmw->enableMask)) {
-
- iowrite32(0, ca91cx42_bridge->base + SCYC_CTL);
- break;
-
- }
- vmeRmw->numAttempts++;
- }
-
- /* If no success, set num Attempts to be greater than max attempts */
- if (vmeRmw->numAttempts > vmeRmw->maxAttempts) {
- vmeRmw->numAttempts = vmeRmw->maxAttempts + 1;
- }
-
- return 0;
-}
-
-int uniSetupDctlReg(vmeDmaPacket_t * vmeDma, int *dctlregreturn)
-{
- unsigned int dctlreg = 0x80;
- struct vmeAttr *vmeAttr;
-
- if (vmeDma->srcBus == VME_DMA_VME) {
- dctlreg = 0;
- vmeAttr = &vmeDma->srcVmeAttr;
- } else {
- dctlreg = 0x80000000;
- vmeAttr = &vmeDma->dstVmeAttr;
- }
-
- switch (vmeAttr->maxDataWidth) {
- case VME_D8:
- break;
- case VME_D16:
- dctlreg |= 0x00400000;
- break;
- case VME_D32:
- dctlreg |= 0x00800000;
- break;
- case VME_D64:
- dctlreg |= 0x00C00000;
- break;
- }
-
- switch (vmeAttr->addrSpace) {
- case VME_A16:
- break;
- case VME_A24:
- dctlreg |= 0x00010000;
- break;
- case VME_A32:
- dctlreg |= 0x00020000;
- break;
- case VME_USER1:
- dctlreg |= 0x00060000;
- break;
- case VME_USER2:
- dctlreg |= 0x00070000;
- break;
-
- case VME_A64: /* not supported in Universe DMA */
- case VME_CRCSR:
- case VME_USER3:
- case VME_USER4:
- return -EINVAL;
- break;
- }
- if (vmeAttr->userAccessType == VME_PROG) {
- dctlreg |= 0x00004000;
- }
- if (vmeAttr->dataAccessType == VME_SUPER) {
- dctlreg |= 0x00001000;
- }
- if (vmeAttr->xferProtocol != VME_SCT) {
- dctlreg |= 0x00000100;
- }
- *dctlregreturn = dctlreg;
- return 0;
-}
-
-unsigned int
-ca91cx42_start_dma(int channel, unsigned int dgcsreg, TDMA_Cmd_Packet *vmeLL)
-{
- unsigned int val;
-
- /* Setup registers as needed for direct or chained. */
- if (dgcsreg & 0x8000000) {
- iowrite32(0, ca91cx42_bridge->base + DTBC);
- iowrite32((unsigned int)vmeLL, ca91cx42_bridge->base + DCPP);
- } else {
-#if 0
- printk(KERN_ERR "Starting: DGCS = %08x\n", dgcsreg);
- printk(KERN_ERR "Starting: DVA = %08x\n",
- ioread32(&vmeLL->dva));
- printk(KERN_ERR "Starting: DLV = %08x\n",
- ioread32(&vmeLL->dlv));
- printk(KERN_ERR "Starting: DTBC = %08x\n",
- ioread32(&vmeLL->dtbc));
- printk(KERN_ERR "Starting: DCTL = %08x\n",
- ioread32(&vmeLL->dctl));
-#endif
- /* Write registers */
- iowrite32(ioread32(&vmeLL->dva), ca91cx42_bridge->base + DVA);
- iowrite32(ioread32(&vmeLL->dlv), ca91cx42_bridge->base + DLA);
- iowrite32(ioread32(&vmeLL->dtbc), ca91cx42_bridge->base + DTBC);
- iowrite32(ioread32(&vmeLL->dctl), ca91cx42_bridge->base + DCTL);
- iowrite32(0, ca91cx42_bridge->base + DCPP);
- }
-
- /* Start the operation */
- iowrite32(dgcsreg, ca91cx42_bridge->base + DGCS);
- val = get_tbl();
- iowrite32(dgcsreg | 0x8000000F, ca91cx42_bridge->base + DGCS);
- return val;
-}
-
-TDMA_Cmd_Packet *ca91cx42_setup_dma(vmeDmaPacket_t * vmeDma)
-{
- vmeDmaPacket_t *vmeCur;
- int maxPerPage;
- int currentLLcount;
- TDMA_Cmd_Packet *startLL;
- TDMA_Cmd_Packet *currentLL;
- TDMA_Cmd_Packet *nextLL;
- unsigned int dctlreg = 0;
-
- maxPerPage = PAGESIZE / sizeof(TDMA_Cmd_Packet) - 1;
- startLL = (TDMA_Cmd_Packet *) __get_free_pages(GFP_KERNEL, 0);
- if (startLL == 0) {
- return startLL;
- }
- /* First allocate pages for descriptors and create linked list */
- vmeCur = vmeDma;
- currentLL = startLL;
- currentLLcount = 0;
- while (vmeCur != 0) {
- if (vmeCur->pNextPacket != 0) {
- currentLL->dcpp = (unsigned int)(currentLL + 1);
- currentLLcount++;
- if (currentLLcount >= maxPerPage) {
- currentLL->dcpp =
- __get_free_pages(GFP_KERNEL, 0);
- currentLLcount = 0;
- }
- currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
- } else {
- currentLL->dcpp = (unsigned int)0;
- }
- vmeCur = vmeCur->pNextPacket;
- }
-
- /* Next fill in information for each descriptor */
- vmeCur = vmeDma;
- currentLL = startLL;
- while (vmeCur != 0) {
- if (vmeCur->srcBus == VME_DMA_VME) {
- iowrite32(vmeCur->srcAddr, &currentLL->dva);
- iowrite32(vmeCur->dstAddr, &currentLL->dlv);
- } else {
- iowrite32(vmeCur->srcAddr, &currentLL->dlv);
- iowrite32(vmeCur->dstAddr, &currentLL->dva);
- }
- uniSetupDctlReg(vmeCur, &dctlreg);
- iowrite32(dctlreg, &currentLL->dctl);
- iowrite32(vmeCur->byteCount, &currentLL->dtbc);
-
- currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
- vmeCur = vmeCur->pNextPacket;
- }
-
- /* Convert Links to PCI addresses. */
- currentLL = startLL;
- while (currentLL != 0) {
- nextLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
- if (nextLL == 0) {
- iowrite32(1, &currentLL->dcpp);
- } else {
- iowrite32((unsigned int)virt_to_bus(nextLL),
- &currentLL->dcpp);
- }
- currentLL = nextLL;
- }
-
- /* Return pointer to descriptors list */
- return startLL;
-}
-
-int ca91cx42_free_dma(TDMA_Cmd_Packet *startLL)
-{
- TDMA_Cmd_Packet *currentLL;
- TDMA_Cmd_Packet *prevLL;
- TDMA_Cmd_Packet *nextLL;
- unsigned int dcppreg;
-
- /* Convert Links to virtual addresses. */
- currentLL = startLL;
- while (currentLL != 0) {
- dcppreg = ioread32(&currentLL->dcpp);
- dcppreg &= ~6;
- if (dcppreg & 1) {
- currentLL->dcpp = 0;
- } else {
- currentLL->dcpp = (unsigned int)bus_to_virt(dcppreg);
- }
- currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
- }
-
- /* Free all pages associated with the descriptors. */
- currentLL = startLL;
- prevLL = currentLL;
- while (currentLL != 0) {
- nextLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
- if (currentLL + 1 != nextLL) {
- free_pages((int)prevLL, 0);
- prevLL = nextLL;
- }
- currentLL = nextLL;
- }
-
- /* Return pointer to descriptors list */
- return 0;
-}
-
-int ca91cx42_do_dma(vmeDmaPacket_t *vmeDma)
-{
- unsigned int dgcsreg = 0;
- unsigned int dctlreg = 0;
- int val;
- int channel, x;
- vmeDmaPacket_t *curDma;
- TDMA_Cmd_Packet *dmaLL;
-
- /* Sanity check the VME chain. */
- channel = vmeDma->channel_number;
- if (channel > 0) {
- return -EINVAL;
- }
- curDma = vmeDma;
- while (curDma != 0) {
- if (curDma->byteCount == 0) {
- return -EINVAL;
- }
- if (curDma->byteCount >= 0x1000000) {
- return -EINVAL;
- }
- if ((curDma->srcAddr & 7) != (curDma->dstAddr & 7)) {
- return -EINVAL;
- }
- switch (curDma->srcBus) {
- case VME_DMA_PCI:
- if (curDma->dstBus != VME_DMA_VME) {
- return -EINVAL;
- }
- break;
- case VME_DMA_VME:
- if (curDma->dstBus != VME_DMA_PCI) {
- return -EINVAL;
- }
- break;
- default:
- return -EINVAL;
- break;
- }
- if (uniSetupDctlReg(curDma, &dctlreg) < 0) {
- return -EINVAL;
- }
-
- curDma = curDma->pNextPacket;
- if (curDma == vmeDma) { /* Endless Loop! */
- return -EINVAL;
- }
- }
-
- /* calculate control register */
- if (vmeDma->pNextPacket != 0) {
- dgcsreg = 0x8000000;
- } else {
- dgcsreg = 0;
- }
-
- for (x = 0; x < 8; x++) { /* vme block size */
- if ((256 << x) >= vmeDma->maxVmeBlockSize) {
- break;
- }
- }
- if (x == 8)
- x = 7;
- dgcsreg |= (x << 20);
-
- if (vmeDma->vmeBackOffTimer) {
- for (x = 1; x < 8; x++) { /* vme timer */
- if ((16 << (x - 1)) >= vmeDma->vmeBackOffTimer) {
- break;
- }
- }
- if (x == 8)
- x = 7;
- dgcsreg |= (x << 16);
- }
- /*` Setup the dma chain */
- dmaLL = ca91cx42_setup_dma(vmeDma);
-
- /* Start the DMA */
- if (dgcsreg & 0x8000000) {
- vmeDma->vmeDmaStartTick =
- ca91cx42_start_dma(channel, dgcsreg,
- (TDMA_Cmd_Packet *) virt_to_phys(dmaLL));
- } else {
- vmeDma->vmeDmaStartTick =
- ca91cx42_start_dma(channel, dgcsreg, dmaLL);
- }
-
- wait_event_interruptible(dma_queue,
- ioread32(ca91cx42_bridge->base + DGCS) & 0x800);
-
- val = ioread32(ca91cx42_bridge->base + DGCS);
- iowrite32(val | 0xF00, ca91cx42_bridge->base + DGCS);
-
- vmeDma->vmeDmaStatus = 0;
-
- if (!(val & 0x00000800)) {
- vmeDma->vmeDmaStatus = val & 0x700;
- printk(KERN_ERR "ca91c042: DMA Error in ca91cx42_DMA_irqhandler"
- " DGCS=%08X\n", val);
- val = ioread32(ca91cx42_bridge->base + DCPP);
- printk(KERN_ERR "ca91c042: DCPP=%08X\n", val);
- val = ioread32(ca91cx42_bridge->base + DCTL);
- printk(KERN_ERR "ca91c042: DCTL=%08X\n", val);
- val = ioread32(ca91cx42_bridge->base + DTBC);
- printk(KERN_ERR "ca91c042: DTBC=%08X\n", val);
- val = ioread32(ca91cx42_bridge->base + DLA);
- printk(KERN_ERR "ca91c042: DLA=%08X\n", val);
- val = ioread32(ca91cx42_bridge->base + DVA);
- printk(KERN_ERR "ca91c042: DVA=%08X\n", val);
-
- }
- /* Free the dma chain */
- ca91cx42_free_dma(dmaLL);
-
- return 0;
-}
-
-int ca91cx42_lm_set(vmeLmCfg_t *vmeLm)
-{
- int temp_ctl = 0;
-
- if (vmeLm->addrU)
- return -EINVAL;
-
- switch (vmeLm->addrSpace) {
- case VME_A64:
- case VME_USER3:
- case VME_USER4:
- return -EINVAL;
- case VME_A16:
- temp_ctl |= 0x00000;
- break;
- case VME_A24:
- temp_ctl |= 0x10000;
- break;
- case VME_A32:
- temp_ctl |= 0x20000;
- break;
- case VME_CRCSR:
- temp_ctl |= 0x50000;
- break;
- case VME_USER1:
- temp_ctl |= 0x60000;
- break;
- case VME_USER2:
- temp_ctl |= 0x70000;
- break;
- }
-
- /* Disable while we are mucking around */
- iowrite32(0x00000000, ca91cx42_bridge->base + LM_CTL);
-
- iowrite32(vmeLm->addr, ca91cx42_bridge->base + LM_BS);
-
- /* Setup CTL register. */
- if (vmeLm->userAccessType & VME_SUPER)
- temp_ctl |= 0x00200000;
- if (vmeLm->userAccessType & VME_USER)
- temp_ctl |= 0x00100000;
- if (vmeLm->dataAccessType & VME_PROG)
- temp_ctl |= 0x00800000;
- if (vmeLm->dataAccessType & VME_DATA)
- temp_ctl |= 0x00400000;
-
-
- /* Write ctl reg and enable */
- iowrite32(0x80000000 | temp_ctl, ca91cx42_bridge->base + LM_CTL);
- temp_ctl = ioread32(ca91cx42_bridge->base + LM_CTL);
-
- return 0;
-}
-
-int ca91cx42_wait_lm(vmeLmCfg_t *vmeLm)
-{
- unsigned long flags;
- unsigned int tmp;
-
- spin_lock_irqsave(&lm_lock, flags);
- spin_unlock_irqrestore(&lm_lock, flags);
- if (tmp == 0) {
- if (vmeLm->lmWait < 10)
- vmeLm->lmWait = 10;
- interruptible_sleep_on_timeout(&lm_queue, vmeLm->lmWait);
- }
- iowrite32(0x00000000, ca91cx42_bridge->base + LM_CTL);
-
- return 0;
-}
-
-
-
-int ca91cx42_set_arbiter(vmeArbiterCfg_t *vmeArb)
-{
- int temp_ctl = 0;
- int vbto = 0;
-
- temp_ctl = ioread32(ca91cx42_bridge->base + MISC_CTL);
- temp_ctl &= 0x00FFFFFF;
-
- if (vmeArb->globalTimeoutTimer == 0xFFFFFFFF) {
- vbto = 7;
- } else if (vmeArb->globalTimeoutTimer > 1024) {
- return -EINVAL;
- } else if (vmeArb->globalTimeoutTimer == 0) {
- vbto = 0;
- } else {
- vbto = 1;
- while ((16 * (1 << (vbto - 1))) < vmeArb->globalTimeoutTimer)
- vbto += 1;
- }
- temp_ctl |= (vbto << 28);
-
- if (vmeArb->arbiterMode == VME_PRIORITY_MODE)
- temp_ctl |= 1 << 26;
-
- if (vmeArb->arbiterTimeoutFlag)
- temp_ctl |= 2 << 24;
-
- iowrite32(temp_ctl, ca91cx42_bridge->base + MISC_CTL);
- return 0;
-}
-
-int ca91cx42_get_arbiter(vmeArbiterCfg_t *vmeArb)
-{
- int temp_ctl = 0;
- int vbto = 0;
-
- temp_ctl = ioread32(ca91cx42_bridge->base + MISC_CTL);
-
- vbto = (temp_ctl >> 28) & 0xF;
- if (vbto != 0)
- vmeArb->globalTimeoutTimer = (16 * (1 << (vbto - 1)));
-
- if (temp_ctl & (1 << 26))
- vmeArb->arbiterMode = VME_PRIORITY_MODE;
- else
- vmeArb->arbiterMode = VME_R_ROBIN_MODE;
-
- if (temp_ctl & (3 << 24))
- vmeArb->arbiterTimeoutFlag = 1;
-
- return 0;
-}
-
-int ca91cx42_set_requestor(vmeRequesterCfg_t *vmeReq)
-{
- int temp_ctl = 0;
-
- temp_ctl = ioread32(ca91cx42_bridge->base + MAST_CTL);
- temp_ctl &= 0xFF0FFFFF;
-
- if (vmeReq->releaseMode == 1)
- temp_ctl |= (1 << 20);
-
- if (vmeReq->fairMode == 1)
- temp_ctl |= (1 << 21);
-
- temp_ctl |= (vmeReq->requestLevel << 22);
-
- iowrite32(temp_ctl, ca91cx42_bridge->base + MAST_CTL);
- return 0;
-}
-
-int ca91cx42_get_requestor(vmeRequesterCfg_t *vmeReq)
-{
- int temp_ctl = 0;
-
- temp_ctl = ioread32(ca91cx42_bridge->base + MAST_CTL);
-
- if (temp_ctl & (1 << 20))
- vmeReq->releaseMode = 1;
-
- if (temp_ctl & (1 << 21))
- vmeReq->fairMode = 1;
-
- vmeReq->requestLevel = (temp_ctl & 0xC00000) >> 22;
-
- return 0;
-}
-
-
-#endif
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.h b/drivers/staging/vme/bridges/vme_ca91cx42.h
index 95a42c240a20..e72c65b193ec 100644
--- a/drivers/staging/vme/bridges/vme_ca91cx42.h
+++ b/drivers/staging/vme/bridges/vme_ca91cx42.h
@@ -7,8 +7,8 @@
* Updated by Ajit Prem
* Copyright 2004 Motorola Inc.
*
- * Further updated by Martyn Welch <martyn.welch@gefanuc.com>
- * Copyright 2009 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ * Further updated by Martyn Welch <martyn.welch@ge.com>
+ * Copyright 2009 GE Intelligent Platforms Embedded Systems, Inc.
*
* Derived from ca91c042.h by Michael Wyrick
*
@@ -37,11 +37,27 @@
#define CA91C142_MAX_DMA 1 /* Max DMA Controllers */
#define CA91C142_MAX_MAILBOX 4 /* Max Mail Box registers */
+/* Structure used to hold driver specific information */
+struct ca91cx42_driver {
+ void *base; /* Base Address of device registers */
+ wait_queue_head_t dma_queue;
+ wait_queue_head_t iack_queue;
+ wait_queue_head_t mbox_queue;
+ void (*lm_callback[4])(int); /* Called in interrupt handler */
+ void *crcsr_kernel;
+ dma_addr_t crcsr_bus;
+ struct mutex vme_rmw; /* Only one RMW cycle at a time */
+ struct mutex vme_int; /*
+ * Only one VME interrupt can be
+ * generated at a time, provide locking
+ */
+};
+
/* See Page 2-77 in the Universe User Manual */
struct ca91cx42_dma_descriptor {
unsigned int dctl; /* DMA Control */
unsigned int dtbc; /* Transfer Byte Count */
- unsigned int dlv; /* PCI Address */
+ unsigned int dla; /* PCI Address */
unsigned int res1; /* Reserved */
unsigned int dva; /* Vme Address */
unsigned int res2; /* Reserved */
@@ -237,32 +253,6 @@ static const int CA91CX42_VSI_TO[] = { VSI0_TO, VSI1_TO, VSI2_TO, VSI3_TO,
#define VCSR_SET 0x0FF8
#define VCSR_BS 0x0FFC
-// DMA General Control/Status Register DGCS (0x220)
-// 32-24 || GO | STOPR | HALTR | 0 || CHAIN | 0 | 0 | 0 ||
-// 23-16 || VON || VOFF ||
-// 15-08 || ACT | STOP | HALT | 0 || DONE | LERR | VERR | P_ERR ||
-// 07-00 || 0 | INT_S | INT_H | 0 || I_DNE | I_LER | I_VER | I_PER ||
-
-// VON - Length Per DMA VMEBus Transfer
-// 0000 = None
-// 0001 = 256 Bytes
-// 0010 = 512
-// 0011 = 1024
-// 0100 = 2048
-// 0101 = 4096
-// 0110 = 8192
-// 0111 = 16384
-
-// VOFF - wait between DMA tenures
-// 0000 = 0 us
-// 0001 = 16
-// 0010 = 32
-// 0011 = 64
-// 0100 = 128
-// 0101 = 256
-// 0110 = 512
-// 0111 = 1024
-
/*
* PCI Class Register
* offset 008
@@ -326,6 +316,16 @@ static const int CA91CX42_VSI_TO[] = { VSI0_TO, VSI1_TO, VSI2_TO, VSI3_TO,
#define CA91CX42_LSI_CTL_VCT_MBLT (1<<8)
#define CA91CX42_LSI_CTL_LAS (1<<0)
+/*
+ * SCYC_CTL Register
+ * offset 178
+ */
+#define CA91CX42_SCYC_CTL_LAS_PCIMEM 0
+#define CA91CX42_SCYC_CTL_LAS_PCIIO (1<<2)
+
+#define CA91CX42_SCYC_CTL_CYC_M (3<<0)
+#define CA91CX42_SCYC_CTL_CYC_RMW (1<<0)
+#define CA91CX42_SCYC_CTL_CYC_ADOH (1<<1)
/*
* LMISC Register
@@ -355,6 +355,71 @@ static const int CA91CX42_VSI_TO[] = { VSI0_TO, VSI1_TO, VSI2_TO, VSI3_TO,
#define CA91CX42_BM_SLSI_RESERVED 0x3F0F0000
/*
+ * DCTL Register
+ * offset 200
+ */
+#define CA91CX42_DCTL_L2V (1<<31)
+#define CA91CX42_DCTL_VDW_M (3<<22)
+#define CA91CX42_DCTL_VDW_M (3<<22)
+#define CA91CX42_DCTL_VDW_D8 0
+#define CA91CX42_DCTL_VDW_D16 (1<<22)
+#define CA91CX42_DCTL_VDW_D32 (1<<23)
+#define CA91CX42_DCTL_VDW_D64 (3<<22)
+
+#define CA91CX42_DCTL_VAS_M (7<<16)
+#define CA91CX42_DCTL_VAS_A16 0
+#define CA91CX42_DCTL_VAS_A24 (1<<16)
+#define CA91CX42_DCTL_VAS_A32 (1<<17)
+#define CA91CX42_DCTL_VAS_USER1 (3<<17)
+#define CA91CX42_DCTL_VAS_USER2 (7<<16)
+
+#define CA91CX42_DCTL_PGM_M (1<<14)
+#define CA91CX42_DCTL_PGM_DATA 0
+#define CA91CX42_DCTL_PGM_PGM (1<<14)
+
+#define CA91CX42_DCTL_SUPER_M (1<<12)
+#define CA91CX42_DCTL_SUPER_NPRIV 0
+#define CA91CX42_DCTL_SUPER_SUPR (1<<12)
+
+#define CA91CX42_DCTL_VCT_M (1<<8)
+#define CA91CX42_DCTL_VCT_BLT (1<<8)
+#define CA91CX42_DCTL_LD64EN (1<<7)
+
+/*
+ * DCPP Register
+ * offset 218
+ */
+#define CA91CX42_DCPP_M 0xf
+#define CA91CX42_DCPP_NULL (1<<0)
+
+/*
+ * DMA General Control/Status Register (DGCS)
+ * offset 220
+ */
+#define CA91CX42_DGCS_GO (1<<31)
+#define CA91CX42_DGCS_STOP_REQ (1<<30)
+#define CA91CX42_DGCS_HALT_REQ (1<<29)
+#define CA91CX42_DGCS_CHAIN (1<<27)
+
+#define CA91CX42_DGCS_VON_M (7<<20)
+
+#define CA91CX42_DGCS_VOFF_M (0xf<<16)
+
+#define CA91CX42_DGCS_ACT (1<<15)
+#define CA91CX42_DGCS_STOP (1<<14)
+#define CA91CX42_DGCS_HALT (1<<13)
+#define CA91CX42_DGCS_DONE (1<<11)
+#define CA91CX42_DGCS_LERR (1<<10)
+#define CA91CX42_DGCS_VERR (1<<9)
+#define CA91CX42_DGCS_PERR (1<<8)
+#define CA91CX42_DGCS_INT_STOP (1<<6)
+#define CA91CX42_DGCS_INT_HALT (1<<5)
+#define CA91CX42_DGCS_INT_DONE (1<<3)
+#define CA91CX42_DGCS_INT_LERR (1<<2)
+#define CA91CX42_DGCS_INT_VERR (1<<1)
+#define CA91CX42_DGCS_INT_PERR (1<<0)
+
+/*
* PCI Interrupt Enable Register
* offset 300
*/
@@ -475,6 +540,19 @@ static const int CA91CX42_LINT_LM[] = { CA91CX42_LINT_LM0, CA91CX42_LINT_LM1,
#define CA91CX42_VSI_CTL_LAS_PCI_IO (1<<0)
#define CA91CX42_VSI_CTL_LAS_PCI_CONF (1<<1)
+/* LM_CTL Register
+ * offset F64
+ */
+#define CA91CX42_LM_CTL_EN (1<<31)
+#define CA91CX42_LM_CTL_PGM (1<<23)
+#define CA91CX42_LM_CTL_DATA (1<<22)
+#define CA91CX42_LM_CTL_SUPR (1<<21)
+#define CA91CX42_LM_CTL_NPRIV (1<<20)
+#define CA91CX42_LM_CTL_AS_M (5<<16)
+#define CA91CX42_LM_CTL_AS_A16 0
+#define CA91CX42_LM_CTL_AS_A24 (1<<16)
+#define CA91CX42_LM_CTL_AS_A32 (1<<17)
+
/*
* VRAI_CTL Register
* offset F70
diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c
index 89a7dccb934f..faf652edb70f 100644
--- a/drivers/staging/vme/bridges/vme_tsi148.c
+++ b/drivers/staging/vme/bridges/vme_tsi148.c
@@ -1,8 +1,8 @@
/*
* Support for the Tundra TSI148 VME-PCI Bridge Chip
*
- * Author: Martyn Welch <martyn.welch@gefanuc.com>
- * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
*
* Based on work by Tom Armistead and Ajit Prem
* Copyright 2004 Motorola Inc.
@@ -59,28 +59,14 @@ int tsi148_dma_list_add (struct vme_dma_list *, struct vme_dma_attr *,
int tsi148_dma_list_exec(struct vme_dma_list *);
int tsi148_dma_list_empty(struct vme_dma_list *);
int tsi148_generate_irq(int, int);
-int tsi148_slot_get(void);
-
-/* Modue parameter */
-int err_chk = 0;
-
-/* XXX These should all be in a per device structure */
-struct vme_bridge *tsi148_bridge;
-wait_queue_head_t dma_queue[2];
-wait_queue_head_t iack_queue;
-void (*lm_callback[4])(int); /* Called in interrupt handler, be careful! */
-void *crcsr_kernel;
-dma_addr_t crcsr_bus;
-struct vme_master_resource *flush_image;
-struct mutex vme_rmw; /* Only one RMW cycle at a time */
-struct mutex vme_int; /*
- * Only one VME interrupt can be
- * generated at a time, provide locking
- */
+
+/* Module parameter */
+static int err_chk;
+static int geoid;
static char driver_name[] = "vme_tsi148";
-static struct pci_device_id tsi148_ids[] = {
+static const struct pci_device_id tsi148_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_TSI148) },
{ },
};
@@ -109,16 +95,17 @@ static void reg_split(unsigned long long variable, unsigned int *high,
/*
* Wakes up DMA queue.
*/
-static u32 tsi148_DMA_irqhandler(int channel_mask)
+static u32 tsi148_DMA_irqhandler(struct tsi148_driver *bridge,
+ int channel_mask)
{
u32 serviced = 0;
if (channel_mask & TSI148_LCSR_INTS_DMA0S) {
- wake_up(&dma_queue[0]);
+ wake_up(&(bridge->dma_queue[0]));
serviced |= TSI148_LCSR_INTC_DMA0C;
}
if (channel_mask & TSI148_LCSR_INTS_DMA1S) {
- wake_up(&dma_queue[1]);
+ wake_up(&(bridge->dma_queue[1]));
serviced |= TSI148_LCSR_INTC_DMA1C;
}
@@ -128,7 +115,7 @@ static u32 tsi148_DMA_irqhandler(int channel_mask)
/*
* Wake up location monitor queue
*/
-static u32 tsi148_LM_irqhandler(u32 stat)
+static u32 tsi148_LM_irqhandler(struct tsi148_driver *bridge, u32 stat)
{
int i;
u32 serviced = 0;
@@ -136,7 +123,7 @@ static u32 tsi148_LM_irqhandler(u32 stat)
for (i = 0; i < 4; i++) {
if(stat & TSI148_LCSR_INTS_LMS[i]) {
/* We only enable interrupts if the callback is set */
- lm_callback[i](i);
+ bridge->lm_callback[i](i);
serviced |= TSI148_LCSR_INTC_LMC[i];
}
}
@@ -149,7 +136,7 @@ static u32 tsi148_LM_irqhandler(u32 stat)
*
* XXX This functionality is not exposed up though API.
*/
-static u32 tsi148_MB_irqhandler(u32 stat)
+static u32 tsi148_MB_irqhandler(struct tsi148_driver *bridge, u32 stat)
{
int i;
u32 val;
@@ -157,8 +144,7 @@ static u32 tsi148_MB_irqhandler(u32 stat)
for (i = 0; i < 4; i++) {
if(stat & TSI148_LCSR_INTS_MBS[i]) {
- val = ioread32be(tsi148_bridge->base +
- TSI148_GCSR_MBOX[i]);
+ val = ioread32be(bridge->base + TSI148_GCSR_MBOX[i]);
printk("VME Mailbox %d received: 0x%x\n", i, val);
serviced |= TSI148_LCSR_INTC_MBC[i];
}
@@ -170,22 +156,21 @@ static u32 tsi148_MB_irqhandler(u32 stat)
/*
* Display error & status message when PERR (PCI) exception interrupt occurs.
*/
-static u32 tsi148_PERR_irqhandler(void)
+static u32 tsi148_PERR_irqhandler(struct tsi148_driver *bridge)
{
printk(KERN_ERR
"PCI Exception at address: 0x%08x:%08x, attributes: %08x\n",
- ioread32be(tsi148_bridge->base + TSI148_LCSR_EDPAU),
- ioread32be(tsi148_bridge->base + TSI148_LCSR_EDPAL),
- ioread32be(tsi148_bridge->base + TSI148_LCSR_EDPAT)
+ ioread32be(bridge->base + TSI148_LCSR_EDPAU),
+ ioread32be(bridge->base + TSI148_LCSR_EDPAL),
+ ioread32be(bridge->base + TSI148_LCSR_EDPAT)
);
printk(KERN_ERR
"PCI-X attribute reg: %08x, PCI-X split completion reg: %08x\n",
- ioread32be(tsi148_bridge->base + TSI148_LCSR_EDPXA),
- ioread32be(tsi148_bridge->base + TSI148_LCSR_EDPXS)
+ ioread32be(bridge->base + TSI148_LCSR_EDPXA),
+ ioread32be(bridge->base + TSI148_LCSR_EDPXS)
);
- iowrite32be(TSI148_LCSR_EDPAT_EDPCL,
- tsi148_bridge->base + TSI148_LCSR_EDPAT);
+ iowrite32be(TSI148_LCSR_EDPAT_EDPCL, bridge->base + TSI148_LCSR_EDPAT);
return TSI148_LCSR_INTC_PERRC;
}
@@ -193,16 +178,19 @@ static u32 tsi148_PERR_irqhandler(void)
/*
* Save address and status when VME error interrupt occurs.
*/
-static u32 tsi148_VERR_irqhandler(void)
+static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge)
{
unsigned int error_addr_high, error_addr_low;
unsigned long long error_addr;
u32 error_attrib;
struct vme_bus_error *error;
+ struct tsi148_driver *bridge;
+
+ bridge = tsi148_bridge->driver_priv;
- error_addr_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_VEAU);
- error_addr_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_VEAL);
- error_attrib = ioread32be(tsi148_bridge->base + TSI148_LCSR_VEAT);
+ error_addr_high = ioread32be(bridge->base + TSI148_LCSR_VEAU);
+ error_addr_low = ioread32be(bridge->base + TSI148_LCSR_VEAL);
+ error_attrib = ioread32be(bridge->base + TSI148_LCSR_VEAT);
reg_join(error_addr_high, error_addr_low, &error_addr);
@@ -226,8 +214,7 @@ static u32 tsi148_VERR_irqhandler(void)
}
/* Clear Status */
- iowrite32be(TSI148_LCSR_VEAT_VESCL,
- tsi148_bridge->base + TSI148_LCSR_VEAT);
+ iowrite32be(TSI148_LCSR_VEAT_VESCL, bridge->base + TSI148_LCSR_VEAT);
return TSI148_LCSR_INTC_VERRC;
}
@@ -235,9 +222,9 @@ static u32 tsi148_VERR_irqhandler(void)
/*
* Wake up IACK queue.
*/
-static u32 tsi148_IACK_irqhandler(void)
+static u32 tsi148_IACK_irqhandler(struct tsi148_driver *bridge)
{
- wake_up(&iack_queue);
+ wake_up(&(bridge->iack_queue));
return TSI148_LCSR_INTC_IACKC;
}
@@ -245,9 +232,13 @@ static u32 tsi148_IACK_irqhandler(void)
/*
* Calling VME bus interrupt callback if provided.
*/
-static u32 tsi148_VIRQ_irqhandler(u32 stat)
+static u32 tsi148_VIRQ_irqhandler(struct vme_bridge *tsi148_bridge,
+ u32 stat)
{
int vec, i, serviced = 0;
+ struct tsi148_driver *bridge;
+
+ bridge = tsi148_bridge->driver_priv;
for (i = 7; i > 0; i--) {
if (stat & (1 << i)) {
@@ -257,8 +248,7 @@ static u32 tsi148_VIRQ_irqhandler(u32 stat)
* 8-bit IACK cycles on the bus, read from offset
* 3.
*/
- vec = ioread8(tsi148_bridge->base +
- TSI148_LCSR_VIACK[i] + 3);
+ vec = ioread8(bridge->base + TSI148_LCSR_VIACK[i] + 3);
vme_irq_handler(tsi148_bridge, i, vec);
@@ -273,13 +263,19 @@ static u32 tsi148_VIRQ_irqhandler(u32 stat)
* Top level interrupt handler. Clears appropriate interrupt status bits and
* then calls appropriate sub handler(s).
*/
-static irqreturn_t tsi148_irqhandler(int irq, void *dev_id)
+static irqreturn_t tsi148_irqhandler(int irq, void *ptr)
{
u32 stat, enable, serviced = 0;
+ struct vme_bridge *tsi148_bridge;
+ struct tsi148_driver *bridge;
+
+ tsi148_bridge = ptr;
+
+ bridge = tsi148_bridge->driver_priv;
/* Determine which interrupts are unmasked and set */
- enable = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
- stat = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTS);
+ enable = ioread32be(bridge->base + TSI148_LCSR_INTEO);
+ stat = ioread32be(bridge->base + TSI148_LCSR_INTS);
/* Only look at unmasked interrupts */
stat &= enable;
@@ -291,61 +287,63 @@ static irqreturn_t tsi148_irqhandler(int irq, void *dev_id)
/* Call subhandlers as appropriate */
/* DMA irqs */
if (stat & (TSI148_LCSR_INTS_DMA1S | TSI148_LCSR_INTS_DMA0S))
- serviced |= tsi148_DMA_irqhandler(stat);
+ serviced |= tsi148_DMA_irqhandler(bridge, stat);
/* Location monitor irqs */
if (stat & (TSI148_LCSR_INTS_LM3S | TSI148_LCSR_INTS_LM2S |
TSI148_LCSR_INTS_LM1S | TSI148_LCSR_INTS_LM0S))
- serviced |= tsi148_LM_irqhandler(stat);
+ serviced |= tsi148_LM_irqhandler(bridge, stat);
/* Mail box irqs */
if (stat & (TSI148_LCSR_INTS_MB3S | TSI148_LCSR_INTS_MB2S |
TSI148_LCSR_INTS_MB1S | TSI148_LCSR_INTS_MB0S))
- serviced |= tsi148_MB_irqhandler(stat);
+ serviced |= tsi148_MB_irqhandler(bridge, stat);
/* PCI bus error */
if (stat & TSI148_LCSR_INTS_PERRS)
- serviced |= tsi148_PERR_irqhandler();
+ serviced |= tsi148_PERR_irqhandler(bridge);
/* VME bus error */
if (stat & TSI148_LCSR_INTS_VERRS)
- serviced |= tsi148_VERR_irqhandler();
+ serviced |= tsi148_VERR_irqhandler(tsi148_bridge);
/* IACK irq */
if (stat & TSI148_LCSR_INTS_IACKS)
- serviced |= tsi148_IACK_irqhandler();
+ serviced |= tsi148_IACK_irqhandler(bridge);
/* VME bus irqs */
if (stat & (TSI148_LCSR_INTS_IRQ7S | TSI148_LCSR_INTS_IRQ6S |
TSI148_LCSR_INTS_IRQ5S | TSI148_LCSR_INTS_IRQ4S |
TSI148_LCSR_INTS_IRQ3S | TSI148_LCSR_INTS_IRQ2S |
TSI148_LCSR_INTS_IRQ1S))
- serviced |= tsi148_VIRQ_irqhandler(stat);
+ serviced |= tsi148_VIRQ_irqhandler(tsi148_bridge, stat);
/* Clear serviced interrupts */
- iowrite32be(serviced, tsi148_bridge->base + TSI148_LCSR_INTC);
+ iowrite32be(serviced, bridge->base + TSI148_LCSR_INTC);
return IRQ_HANDLED;
}
-static int tsi148_irq_init(struct vme_bridge *bridge)
+static int tsi148_irq_init(struct vme_bridge *tsi148_bridge)
{
int result;
unsigned int tmp;
struct pci_dev *pdev;
+ struct tsi148_driver *bridge;
+
+ pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev);
- /* Need pdev */
- pdev = container_of(bridge->parent, struct pci_dev, dev);
+ bridge = tsi148_bridge->driver_priv;
/* Initialise list for VME bus errors */
- INIT_LIST_HEAD(&(bridge->vme_errors));
+ INIT_LIST_HEAD(&(tsi148_bridge->vme_errors));
- mutex_init(&(bridge->irq_mtx));
+ mutex_init(&(tsi148_bridge->irq_mtx));
result = request_irq(pdev->irq,
tsi148_irqhandler,
IRQF_SHARED,
- driver_name, pdev);
+ driver_name, tsi148_bridge);
if (result) {
dev_err(&pdev->dev, "Can't get assigned pci irq vector %02X\n",
pdev->irq);
@@ -359,7 +357,7 @@ static int tsi148_irq_init(struct vme_bridge *bridge)
TSI148_LCSR_INTEO_PERREO | TSI148_LCSR_INTEO_VERREO |
TSI148_LCSR_INTEO_IACKEO;
- /* XXX This leaves the following interrupts masked.
+ /* This leaves the following interrupts masked.
* TSI148_LCSR_INTEO_VIEEO
* TSI148_LCSR_INTEO_SYSFLEO
* TSI148_LCSR_INTEO_ACFLEO
@@ -392,14 +390,14 @@ static int tsi148_irq_init(struct vme_bridge *bridge)
return 0;
}
-static void tsi148_irq_exit(struct pci_dev *pdev)
+static void tsi148_irq_exit(struct tsi148_driver *bridge, struct pci_dev *pdev)
{
/* Turn off interrupts */
- iowrite32be(0x0, tsi148_bridge->base + TSI148_LCSR_INTEO);
- iowrite32be(0x0, tsi148_bridge->base + TSI148_LCSR_INTEN);
+ iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEO);
+ iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEN);
/* Clear all interrupts */
- iowrite32be(0xFFFFFFFF, tsi148_bridge->base + TSI148_LCSR_INTC);
+ iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_INTC);
/* Detach interrupt handler */
free_irq(pdev->irq, pdev);
@@ -408,11 +406,11 @@ static void tsi148_irq_exit(struct pci_dev *pdev)
/*
* Check to see if an IACk has been received, return true (1) or false (0).
*/
-int tsi148_iack_received(void)
+int tsi148_iack_received(struct tsi148_driver *bridge)
{
u32 tmp;
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_VICR);
+ tmp = ioread32be(bridge->base + TSI148_LCSR_VICR);
if (tmp & TSI148_LCSR_VICR_IRQS)
return 0;
@@ -423,20 +421,24 @@ int tsi148_iack_received(void)
/*
* Configure VME interrupt
*/
-void tsi148_irq_set(int level, int state, int sync)
+void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level,
+ int state, int sync)
{
struct pci_dev *pdev;
u32 tmp;
+ struct tsi148_driver *bridge;
+
+ bridge = tsi148_bridge->driver_priv;
/* We need to do the ordering differently for enabling and disabling */
if (state == 0) {
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
+ tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
tmp &= ~TSI148_LCSR_INTEN_IRQEN[level - 1];
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEN);
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
+ tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
tmp &= ~TSI148_LCSR_INTEO_IRQEO[level - 1];
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
if (sync != 0) {
pdev = container_of(tsi148_bridge->parent,
@@ -445,13 +447,13 @@ void tsi148_irq_set(int level, int state, int sync)
synchronize_irq(pdev->irq);
}
} else {
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
+ tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
tmp |= TSI148_LCSR_INTEO_IRQEO[level - 1];
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
+ tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
tmp |= TSI148_LCSR_INTEN_IRQEN[level - 1];
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEN);
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
}
}
@@ -459,28 +461,32 @@ void tsi148_irq_set(int level, int state, int sync)
* Generate a VME bus interrupt at the requested level & vector. Wait for
* interrupt to be acked.
*/
-int tsi148_irq_generate(int level, int statid)
+int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level, int statid)
{
u32 tmp;
+ struct tsi148_driver *bridge;
+
+ bridge = tsi148_bridge->driver_priv;
- mutex_lock(&(vme_int));
+ mutex_lock(&(bridge->vme_int));
/* Read VICR register */
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_VICR);
+ tmp = ioread32be(bridge->base + TSI148_LCSR_VICR);
/* Set Status/ID */
tmp = (tmp & ~TSI148_LCSR_VICR_STID_M) |
(statid & TSI148_LCSR_VICR_STID_M);
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_VICR);
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR);
/* Assert VMEbus IRQ */
tmp = tmp | TSI148_LCSR_VICR_IRQL[level];
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_VICR);
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR);
/* XXX Consider implementing a timeout? */
- wait_event_interruptible(iack_queue, tsi148_iack_received());
+ wait_event_interruptible(bridge->iack_queue,
+ tsi148_iack_received(bridge));
- mutex_unlock(&(vme_int));
+ mutex_unlock(&(bridge->vme_int));
return 0;
}
@@ -488,8 +494,8 @@ int tsi148_irq_generate(int level, int statid)
/*
* Find the first error in this address range
*/
-static struct vme_bus_error *tsi148_find_error(vme_address_t aspace,
- unsigned long long address, size_t count)
+static struct vme_bus_error *tsi148_find_error(struct vme_bridge *tsi148_bridge,
+ vme_address_t aspace, unsigned long long address, size_t count)
{
struct list_head *err_pos;
struct vme_bus_error *vme_err, *valid = NULL;
@@ -520,8 +526,8 @@ static struct vme_bus_error *tsi148_find_error(vme_address_t aspace,
/*
* Clear errors in the provided address range.
*/
-static void tsi148_clear_errors(vme_address_t aspace,
- unsigned long long address, size_t count)
+static void tsi148_clear_errors(struct vme_bridge *tsi148_bridge,
+ vme_address_t aspace, unsigned long long address, size_t count)
{
struct list_head *err_pos, *temp;
struct vme_bus_error *vme_err;
@@ -561,16 +567,9 @@ int tsi148_slave_set(struct vme_slave_resource *image, int enabled,
unsigned int vme_bound_low, vme_bound_high;
unsigned int pci_offset_low, pci_offset_high;
unsigned long long vme_bound, pci_offset;
+ struct tsi148_driver *bridge;
-#if 0
- printk("Set slave image %d to:\n", image->number);
- printk("\tEnabled: %s\n", (enabled == 1)? "yes" : "no");
- printk("\tVME Base:0x%llx\n", vme_base);
- printk("\tWindow Size:0x%llx\n", size);
- printk("\tPCI Base:0x%lx\n", (unsigned long)pci_base);
- printk("\tAddress Space:0x%x\n", aspace);
- printk("\tTransfer Cycle Properties:0x%x\n", cycle);
-#endif
+ bridge = image->parent->driver_priv;
i = image->number;
@@ -627,49 +626,27 @@ int tsi148_slave_set(struct vme_slave_resource *image, int enabled,
return -EINVAL;
}
-#if 0
- printk("\tVME Bound:0x%llx\n", vme_bound);
- printk("\tPCI Offset:0x%llx\n", pci_offset);
-#endif
-
/* Disable while we are mucking around */
- temp_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ temp_ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITAT);
temp_ctl &= ~TSI148_LCSR_ITAT_EN;
- iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITAT);
/* Setup mapping */
- iowrite32be(vme_base_high, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ iowrite32be(vme_base_high, bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITSAU);
- iowrite32be(vme_base_low, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ iowrite32be(vme_base_low, bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITSAL);
- iowrite32be(vme_bound_high, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ iowrite32be(vme_bound_high, bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITEAU);
- iowrite32be(vme_bound_low, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ iowrite32be(vme_bound_low, bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITEAL);
- iowrite32be(pci_offset_high, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ iowrite32be(pci_offset_high, bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITOFU);
- iowrite32be(pci_offset_low, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ iowrite32be(pci_offset_low, bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITOFL);
-/* XXX Prefetch stuff currently unsupported */
-#if 0
-
- for (x = 0; x < 4; x++) {
- if ((64 << x) >= vmeIn->prefetchSize) {
- break;
- }
- }
- if (x == 4)
- x--;
- temp_ctl |= (x << 16);
-
- if (vmeIn->prefetchThreshold)
- if (vmeIn->prefetchThreshold)
- temp_ctl |= 0x40000;
-#endif
-
/* Setup 2eSST speeds */
temp_ctl &= ~TSI148_LCSR_ITAT_2eSSTM_M;
switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
@@ -712,13 +689,13 @@ int tsi148_slave_set(struct vme_slave_resource *image, int enabled,
temp_ctl |= TSI148_LCSR_ITAT_DATA;
/* Write ctl reg without enable */
- iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITAT);
if (enabled)
temp_ctl |= TSI148_LCSR_ITAT_EN;
- iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITAT);
return 0;
@@ -726,8 +703,6 @@ int tsi148_slave_set(struct vme_slave_resource *image, int enabled,
/*
* Get slave window configuration.
- *
- * XXX Prefetch currently unsupported.
*/
int tsi148_slave_get(struct vme_slave_resource *image, int *enabled,
unsigned long long *vme_base, unsigned long long *size,
@@ -738,25 +713,27 @@ int tsi148_slave_get(struct vme_slave_resource *image, int *enabled,
unsigned int vme_bound_low, vme_bound_high;
unsigned int pci_offset_low, pci_offset_high;
unsigned long long vme_bound, pci_offset;
+ struct tsi148_driver *bridge;
+ bridge = image->parent->driver_priv;
i = image->number;
/* Read registers */
- ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITAT);
- vme_base_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ vme_base_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITSAU);
- vme_base_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ vme_base_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITSAL);
- vme_bound_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ vme_bound_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITEAU);
- vme_bound_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ vme_bound_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITEAL);
- pci_offset_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ pci_offset_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITOFU);
- pci_offset_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ pci_offset_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITOFL);
/* Convert 64-bit variables to 2x 32-bit variables */
@@ -833,6 +810,9 @@ static int tsi148_alloc_resource(struct vme_master_resource *image,
unsigned long long existing_size;
int retval = 0;
struct pci_dev *pdev;
+ struct vme_bridge *tsi148_bridge;
+
+ tsi148_bridge = image->parent;
/* Find pci_dev container of dev */
if (tsi148_bridge->parent == NULL) {
@@ -841,8 +821,8 @@ static int tsi148_alloc_resource(struct vme_master_resource *image,
}
pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev);
- existing_size = (unsigned long long)(image->pci_resource.end -
- image->pci_resource.start);
+ existing_size = (unsigned long long)(image->bus_resource.end -
+ image->bus_resource.start);
/* If the existing size is OK, return */
if ((size != 0) && (existing_size == (size - 1)))
@@ -851,10 +831,10 @@ static int tsi148_alloc_resource(struct vme_master_resource *image,
if (existing_size != 0) {
iounmap(image->kern_base);
image->kern_base = NULL;
- if (image->pci_resource.name != NULL)
- kfree(image->pci_resource.name);
- release_resource(&(image->pci_resource));
- memset(&(image->pci_resource), 0, sizeof(struct resource));
+ if (image->bus_resource.name != NULL)
+ kfree(image->bus_resource.name);
+ release_resource(&(image->bus_resource));
+ memset(&(image->bus_resource), 0, sizeof(struct resource));
}
/* Exit here if size is zero */
@@ -862,9 +842,9 @@ static int tsi148_alloc_resource(struct vme_master_resource *image,
return 0;
}
- if (image->pci_resource.name == NULL) {
- image->pci_resource.name = kmalloc(VMENAMSIZ+3, GFP_KERNEL);
- if (image->pci_resource.name == NULL) {
+ if (image->bus_resource.name == NULL) {
+ image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_KERNEL);
+ if (image->bus_resource.name == NULL) {
printk(KERN_ERR "Unable to allocate memory for resource"
" name\n");
retval = -ENOMEM;
@@ -872,26 +852,26 @@ static int tsi148_alloc_resource(struct vme_master_resource *image,
}
}
- sprintf((char *)image->pci_resource.name, "%s.%d", tsi148_bridge->name,
+ sprintf((char *)image->bus_resource.name, "%s.%d", tsi148_bridge->name,
image->number);
- image->pci_resource.start = 0;
- image->pci_resource.end = (unsigned long)size;
- image->pci_resource.flags = IORESOURCE_MEM;
+ image->bus_resource.start = 0;
+ image->bus_resource.end = (unsigned long)size;
+ image->bus_resource.flags = IORESOURCE_MEM;
retval = pci_bus_alloc_resource(pdev->bus,
- &(image->pci_resource), size, size, PCIBIOS_MIN_MEM,
+ &(image->bus_resource), size, size, PCIBIOS_MIN_MEM,
0, NULL, NULL);
if (retval) {
printk(KERN_ERR "Failed to allocate mem resource for "
"window %d size 0x%lx start 0x%lx\n",
image->number, (unsigned long)size,
- (unsigned long)image->pci_resource.start);
+ (unsigned long)image->bus_resource.start);
goto err_resource;
}
image->kern_base = ioremap_nocache(
- image->pci_resource.start, size);
+ image->bus_resource.start, size);
if (image->kern_base == NULL) {
printk(KERN_ERR "Failed to remap resource\n");
retval = -ENOMEM;
@@ -903,10 +883,10 @@ static int tsi148_alloc_resource(struct vme_master_resource *image,
iounmap(image->kern_base);
image->kern_base = NULL;
err_remap:
- release_resource(&(image->pci_resource));
+ release_resource(&(image->bus_resource));
err_resource:
- kfree(image->pci_resource.name);
- memset(&(image->pci_resource), 0, sizeof(struct resource));
+ kfree(image->bus_resource.name);
+ memset(&(image->bus_resource), 0, sizeof(struct resource));
err_name:
return retval;
}
@@ -918,9 +898,9 @@ static void tsi148_free_resource(struct vme_master_resource *image)
{
iounmap(image->kern_base);
image->kern_base = NULL;
- release_resource(&(image->pci_resource));
- kfree(image->pci_resource.name);
- memset(&(image->pci_resource), 0, sizeof(struct resource));
+ release_resource(&(image->bus_resource));
+ kfree(image->bus_resource.name);
+ memset(&(image->bus_resource), 0, sizeof(struct resource));
}
/*
@@ -937,6 +917,9 @@ int tsi148_master_set( struct vme_master_resource *image, int enabled,
unsigned int pci_bound_low, pci_bound_high;
unsigned int vme_offset_low, vme_offset_high;
unsigned long long pci_bound, vme_offset, pci_base;
+ struct tsi148_driver *bridge;
+
+ bridge = image->parent->driver_priv;
/* Verify input data */
if (vme_base & 0xFFFF) {
@@ -970,7 +953,7 @@ int tsi148_master_set( struct vme_master_resource *image, int enabled,
pci_bound = 0;
vme_offset = 0;
} else {
- pci_base = (unsigned long long)image->pci_resource.start;
+ pci_base = (unsigned long long)image->bus_resource.start;
/*
* Bound address is a valid address for the window, adjust
@@ -1007,26 +990,12 @@ int tsi148_master_set( struct vme_master_resource *image, int enabled,
i = image->number;
/* Disable while we are mucking around */
- temp_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ temp_ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTAT);
temp_ctl &= ~TSI148_LCSR_OTAT_EN;
- iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTAT);
-/* XXX Prefetch stuff currently unsupported */
-#if 0
- if (vmeOut->prefetchEnable) {
- temp_ctl |= 0x40000;
- for (x = 0; x < 4; x++) {
- if ((2 << x) >= vmeOut->prefetchSize)
- break;
- }
- if (x == 4)
- x = 3;
- temp_ctl |= (x << 16);
- }
-#endif
-
/* Setup 2eSST speeds */
temp_ctl &= ~TSI148_LCSR_OTAT_2eSSTM_M;
switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
@@ -1126,33 +1095,27 @@ int tsi148_master_set( struct vme_master_resource *image, int enabled,
temp_ctl |= TSI148_LCSR_OTAT_PGM;
/* Setup mapping */
- iowrite32be(pci_base_high, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ iowrite32be(pci_base_high, bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTSAU);
- iowrite32be(pci_base_low, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ iowrite32be(pci_base_low, bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTSAL);
- iowrite32be(pci_bound_high, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ iowrite32be(pci_bound_high, bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTEAU);
- iowrite32be(pci_bound_low, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ iowrite32be(pci_bound_low, bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTEAL);
- iowrite32be(vme_offset_high, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ iowrite32be(vme_offset_high, bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTOFU);
- iowrite32be(vme_offset_low, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ iowrite32be(vme_offset_low, bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTOFL);
-/* XXX We need to deal with OTBS */
-#if 0
- iowrite32be(vmeOut->bcastSelect2esst, tsi148_bridge->base +
- TSI148_LCSR_OT[i] + TSI148_LCSR_OFFSET_OTBS);
-#endif
-
/* Write ctl reg without enable */
- iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTAT);
if (enabled)
temp_ctl |= TSI148_LCSR_OTAT_EN;
- iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTAT);
spin_unlock(&(image->lock));
@@ -1183,23 +1146,26 @@ int __tsi148_master_get( struct vme_master_resource *image, int *enabled,
unsigned int vme_offset_low, vme_offset_high;
unsigned long long pci_base, pci_bound, vme_offset;
+ struct tsi148_driver *bridge;
+
+ bridge = image->parent->driver_priv;
i = image->number;
- ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTAT);
- pci_base_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ pci_base_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTSAU);
- pci_base_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ pci_base_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTSAL);
- pci_bound_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ pci_bound_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTEAU);
- pci_bound_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ pci_bound_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTEAL);
- vme_offset_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ vme_offset_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTOFU);
- vme_offset_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ vme_offset_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTOFL);
/* Convert 64-bit variables to 2x 32-bit variables */
@@ -1305,6 +1271,9 @@ ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
vme_cycle_t cycle;
vme_width_t dwidth;
struct vme_bus_error *vme_err = NULL;
+ struct vme_bridge *tsi148_bridge;
+
+ tsi148_bridge = image->parent;
spin_lock(&(image->lock));
@@ -1317,13 +1286,15 @@ ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
__tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle,
&dwidth);
- vme_err = tsi148_find_error(aspace, vme_base + offset, count);
+ vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset,
+ count);
if(vme_err != NULL) {
dev_err(image->parent->parent, "First VME read error detected "
"an at address 0x%llx\n", vme_err->address);
retval = vme_err->address - (vme_base + offset);
/* Clear down save errors in this address range */
- tsi148_clear_errors(aspace, vme_base + offset, count);
+ tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset,
+ count);
}
skip_chk:
@@ -1333,9 +1304,6 @@ skip_chk:
}
-/* XXX We need to change vme_master_resource->mtx to a spinlock so that read
- * and write functions can be used in an interrupt context
- */
ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
size_t count, loff_t offset)
{
@@ -1346,6 +1314,12 @@ ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
vme_width_t dwidth;
struct vme_bus_error *vme_err = NULL;
+ struct vme_bridge *tsi148_bridge;
+ struct tsi148_driver *bridge;
+
+ tsi148_bridge = image->parent;
+
+ bridge = tsi148_bridge->driver_priv;
spin_lock(&(image->lock));
@@ -1373,15 +1347,17 @@ ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
__tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle,
&dwidth);
- ioread16(flush_image->kern_base + 0x7F000);
+ ioread16(bridge->flush_image->kern_base + 0x7F000);
- vme_err = tsi148_find_error(aspace, vme_base + offset, count);
+ vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset,
+ count);
if(vme_err != NULL) {
printk("First VME write error detected an at address 0x%llx\n",
vme_err->address);
retval = vme_err->address - (vme_base + offset);
/* Clear down save errors in this address range */
- tsi148_clear_errors(aspace, vme_base + offset, count);
+ tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset,
+ count);
}
skip_chk:
@@ -1403,48 +1379,50 @@ unsigned int tsi148_master_rmw(struct vme_master_resource *image,
unsigned int pci_addr_high, pci_addr_low;
u32 tmp, result;
int i;
+ struct tsi148_driver *bridge;
+ bridge = image->parent->driver_priv;
/* Find the PCI address that maps to the desired VME address */
i = image->number;
/* Locking as we can only do one of these at a time */
- mutex_lock(&(vme_rmw));
+ mutex_lock(&(bridge->vme_rmw));
/* Lock image */
spin_lock(&(image->lock));
- pci_addr_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ pci_addr_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTSAU);
- pci_addr_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ pci_addr_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTSAL);
reg_join(pci_addr_high, pci_addr_low, &pci_addr);
reg_split(pci_addr + offset, &pci_addr_high, &pci_addr_low);
/* Configure registers */
- iowrite32be(mask, tsi148_bridge->base + TSI148_LCSR_RMWEN);
- iowrite32be(compare, tsi148_bridge->base + TSI148_LCSR_RMWC);
- iowrite32be(swap, tsi148_bridge->base + TSI148_LCSR_RMWS);
- iowrite32be(pci_addr_high, tsi148_bridge->base + TSI148_LCSR_RMWAU);
- iowrite32be(pci_addr_low, tsi148_bridge->base + TSI148_LCSR_RMWAL);
+ iowrite32be(mask, bridge->base + TSI148_LCSR_RMWEN);
+ iowrite32be(compare, bridge->base + TSI148_LCSR_RMWC);
+ iowrite32be(swap, bridge->base + TSI148_LCSR_RMWS);
+ iowrite32be(pci_addr_high, bridge->base + TSI148_LCSR_RMWAU);
+ iowrite32be(pci_addr_low, bridge->base + TSI148_LCSR_RMWAL);
/* Enable RMW */
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_VMCTRL);
+ tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL);
tmp |= TSI148_LCSR_VMCTRL_RMWEN;
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_VMCTRL);
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL);
/* Kick process off with a read to the required address. */
result = ioread32be(image->kern_base + offset);
/* Disable RMW */
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_VMCTRL);
+ tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL);
tmp &= ~TSI148_LCSR_VMCTRL_RMWEN;
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_VMCTRL);
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL);
spin_unlock(&(image->lock));
- mutex_unlock(&(vme_rmw));
+ mutex_unlock(&(bridge->vme_rmw));
return result;
}
@@ -1637,8 +1615,6 @@ static int tsi148_dma_set_vme_dest_attributes(u32 *attr, vme_address_t aspace,
/*
* Add a link list descriptor to the list
- *
- * XXX Need to handle 2eSST Broadcast select bits
*/
int tsi148_dma_list_add (struct vme_dma_list *list, struct vme_dma_attr *src,
struct vme_dma_attr *dest, size_t count)
@@ -1651,7 +1627,7 @@ int tsi148_dma_list_add (struct vme_dma_list *list, struct vme_dma_attr *src,
dma_addr_t desc_ptr;
int retval = 0;
- /* XXX descriptor must be aligned on 64-bit boundaries */
+ /* Descriptor must be aligned on 64-bit boundaries */
entry = (struct tsi148_dma_entry *)kmalloc(
sizeof(struct tsi148_dma_entry), GFP_KERNEL);
if (entry == NULL) {
@@ -1788,11 +1764,14 @@ err_mem:
/*
* Check to see if the provided DMA channel is busy.
*/
-static int tsi148_dma_busy(int channel)
+static int tsi148_dma_busy(struct vme_bridge *tsi148_bridge, int channel)
{
u32 tmp;
+ struct tsi148_driver *bridge;
+
+ bridge = tsi148_bridge->driver_priv;
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_DMA[channel] +
+ tmp = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
TSI148_LCSR_OFFSET_DSTA);
if (tmp & TSI148_LCSR_DSTA_BSY)
@@ -1815,12 +1794,12 @@ int tsi148_dma_list_exec(struct vme_dma_list *list)
dma_addr_t bus_addr;
u32 bus_addr_high, bus_addr_low;
u32 val, dctlreg = 0;
-#if 0
- int x;
-#endif
+ struct tsi148_driver *bridge;
ctrlr = list->parent;
+ bridge = ctrlr->parent->driver_priv;
+
mutex_lock(&(ctrlr->mtx));
channel = ctrlr->number;
@@ -1837,48 +1816,6 @@ int tsi148_dma_list_exec(struct vme_dma_list *list)
} else {
list_add(&(list->list), &(ctrlr->running));
}
-#if 0
- /* XXX Still todo */
- for (x = 0; x < 8; x++) { /* vme block size */
- if ((32 << x) >= vmeDma->maxVmeBlockSize) {
- break;
- }
- }
- if (x == 8)
- x = 7;
- dctlreg |= (x << 12);
-
- for (x = 0; x < 8; x++) { /* pci block size */
- if ((32 << x) >= vmeDma->maxPciBlockSize) {
- break;
- }
- }
- if (x == 8)
- x = 7;
- dctlreg |= (x << 4);
-
- if (vmeDma->vmeBackOffTimer) {
- for (x = 1; x < 8; x++) { /* vme timer */
- if ((1 << (x - 1)) >= vmeDma->vmeBackOffTimer) {
- break;
- }
- }
- if (x == 8)
- x = 7;
- dctlreg |= (x << 8);
- }
-
- if (vmeDma->pciBackOffTimer) {
- for (x = 1; x < 8; x++) { /* pci timer */
- if ((1 << (x - 1)) >= vmeDma->pciBackOffTimer) {
- break;
- }
- }
- if (x == 8)
- x = 7;
- dctlreg |= (x << 0);
- }
-#endif
/* Get first bus address and write into registers */
entry = list_first_entry(&(list->entries), struct tsi148_dma_entry,
@@ -1890,21 +1827,22 @@ int tsi148_dma_list_exec(struct vme_dma_list *list)
reg_split(bus_addr, &bus_addr_high, &bus_addr_low);
- iowrite32be(bus_addr_high, tsi148_bridge->base +
+ iowrite32be(bus_addr_high, bridge->base +
TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAU);
- iowrite32be(bus_addr_low, tsi148_bridge->base +
+ iowrite32be(bus_addr_low, bridge->base +
TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAL);
/* Start the operation */
- iowrite32be(dctlreg | TSI148_LCSR_DCTL_DGO, tsi148_bridge->base +
+ iowrite32be(dctlreg | TSI148_LCSR_DCTL_DGO, bridge->base +
TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL);
- wait_event_interruptible(dma_queue[channel], tsi148_dma_busy(channel));
+ wait_event_interruptible(bridge->dma_queue[channel],
+ tsi148_dma_busy(ctrlr->parent, channel));
/*
* Read status register, this register is valid until we kick off a
* new transfer.
*/
- val = ioread32be(tsi148_bridge->base + TSI148_LCSR_DMA[channel] +
+ val = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
TSI148_LCSR_OFFSET_DSTA);
if (val & TSI148_LCSR_DSTA_VBE) {
@@ -1952,12 +1890,15 @@ int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
{
u32 lm_base_high, lm_base_low, lm_ctl = 0;
int i;
+ struct tsi148_driver *bridge;
+
+ bridge = lm->parent->driver_priv;
mutex_lock(&(lm->mtx));
/* If we already have a callback attached, we can't move it! */
for (i = 0; i < lm->monitors; i++) {
- if(lm_callback[i] != NULL) {
+ if (bridge->lm_callback[i] != NULL) {
mutex_unlock(&(lm->mtx));
printk("Location monitor callback attached, can't "
"reset\n");
@@ -1996,9 +1937,9 @@ int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
reg_split(lm_base, &lm_base_high, &lm_base_low);
- iowrite32be(lm_base_high, tsi148_bridge->base + TSI148_LCSR_LMBAU);
- iowrite32be(lm_base_low, tsi148_bridge->base + TSI148_LCSR_LMBAL);
- iowrite32be(lm_ctl, tsi148_bridge->base + TSI148_LCSR_LMAT);
+ iowrite32be(lm_base_high, bridge->base + TSI148_LCSR_LMBAU);
+ iowrite32be(lm_base_low, bridge->base + TSI148_LCSR_LMBAL);
+ iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT);
mutex_unlock(&(lm->mtx));
@@ -2012,12 +1953,15 @@ int tsi148_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base,
vme_address_t *aspace, vme_cycle_t *cycle)
{
u32 lm_base_high, lm_base_low, lm_ctl, enabled = 0;
+ struct tsi148_driver *bridge;
+
+ bridge = lm->parent->driver_priv;
mutex_lock(&(lm->mtx));
- lm_base_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_LMBAU);
- lm_base_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_LMBAL);
- lm_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_LMAT);
+ lm_base_high = ioread32be(bridge->base + TSI148_LCSR_LMBAU);
+ lm_base_low = ioread32be(bridge->base + TSI148_LCSR_LMBAL);
+ lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT);
reg_join(lm_base_high, lm_base_low, lm_base);
@@ -2060,11 +2004,14 @@ int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
void (*callback)(int))
{
u32 lm_ctl, tmp;
+ struct tsi148_driver *bridge;
+
+ bridge = lm->parent->driver_priv;
mutex_lock(&(lm->mtx));
/* Ensure that the location monitor is configured - need PGM or DATA */
- lm_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_LMAT);
+ lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT);
if ((lm_ctl & (TSI148_LCSR_LMAT_PGM | TSI148_LCSR_LMAT_DATA)) == 0) {
mutex_unlock(&(lm->mtx));
printk("Location monitor not properly configured\n");
@@ -2072,28 +2019,28 @@ int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
}
/* Check that a callback isn't already attached */
- if (lm_callback[monitor] != NULL) {
+ if (bridge->lm_callback[monitor] != NULL) {
mutex_unlock(&(lm->mtx));
printk("Existing callback attached\n");
return -EBUSY;
}
/* Attach callback */
- lm_callback[monitor] = callback;
+ bridge->lm_callback[monitor] = callback;
/* Enable Location Monitor interrupt */
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
+ tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
tmp |= TSI148_LCSR_INTEN_LMEN[monitor];
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEN);
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
+ tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
tmp |= TSI148_LCSR_INTEO_LMEO[monitor];
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
/* Ensure that global Location Monitor Enable set */
if ((lm_ctl & TSI148_LCSR_LMAT_EN) == 0) {
lm_ctl |= TSI148_LCSR_LMAT_EN;
- iowrite32be(lm_ctl, tsi148_bridge->base + TSI148_LCSR_LMAT);
+ iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT);
}
mutex_unlock(&(lm->mtx));
@@ -2107,30 +2054,33 @@ int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
{
u32 lm_en, tmp;
+ struct tsi148_driver *bridge;
+
+ bridge = lm->parent->driver_priv;
mutex_lock(&(lm->mtx));
/* Disable Location Monitor and ensure previous interrupts are clear */
- lm_en = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
+ lm_en = ioread32be(bridge->base + TSI148_LCSR_INTEN);
lm_en &= ~TSI148_LCSR_INTEN_LMEN[monitor];
- iowrite32be(lm_en, tsi148_bridge->base + TSI148_LCSR_INTEN);
+ iowrite32be(lm_en, bridge->base + TSI148_LCSR_INTEN);
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
+ tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
tmp &= ~TSI148_LCSR_INTEO_LMEO[monitor];
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
iowrite32be(TSI148_LCSR_INTC_LMC[monitor],
- tsi148_bridge->base + TSI148_LCSR_INTC);
+ bridge->base + TSI148_LCSR_INTC);
/* Detach callback */
- lm_callback[monitor] = NULL;
+ bridge->lm_callback[monitor] = NULL;
/* If all location monitors disabled, disable global Location Monitor */
if ((lm_en & (TSI148_LCSR_INTS_LM0S | TSI148_LCSR_INTS_LM1S |
TSI148_LCSR_INTS_LM2S | TSI148_LCSR_INTS_LM3S)) == 0) {
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_LMAT);
+ tmp = ioread32be(bridge->base + TSI148_LCSR_LMAT);
tmp &= ~TSI148_LCSR_LMAT_EN;
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_LMAT);
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_LMAT);
}
mutex_unlock(&(lm->mtx));
@@ -2141,12 +2091,19 @@ int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
/*
* Determine Geographical Addressing
*/
-int tsi148_slot_get(void)
+int tsi148_slot_get(struct vme_bridge *tsi148_bridge)
{
u32 slot = 0;
+ struct tsi148_driver *bridge;
+
+ bridge = tsi148_bridge->driver_priv;
+
+ if (!geoid) {
+ slot = ioread32be(bridge->base + TSI148_LCSR_VSTAT);
+ slot = slot & TSI148_LCSR_VSTAT_GA_M;
+ } else
+ slot = geoid;
- slot = ioread32be(tsi148_bridge->base + TSI148_LCSR_VSTAT);
- slot = slot & TSI148_LCSR_VSTAT_GA_M;
return (int)slot;
}
@@ -2167,45 +2124,50 @@ static int __init tsi148_init(void)
* boards registers, this means there is a fix length 508kB window which must
* be mapped onto PCI memory.
*/
-static int tsi148_crcsr_init(struct pci_dev *pdev)
+static int tsi148_crcsr_init(struct vme_bridge *tsi148_bridge,
+ struct pci_dev *pdev)
{
u32 cbar, crat, vstat;
u32 crcsr_bus_high, crcsr_bus_low;
int retval;
+ struct tsi148_driver *bridge;
+
+ bridge = tsi148_bridge->driver_priv;
/* Allocate mem for CR/CSR image */
- crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
- &crcsr_bus);
- if (crcsr_kernel == NULL) {
+ bridge->crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
+ &(bridge->crcsr_bus));
+ if (bridge->crcsr_kernel == NULL) {
dev_err(&pdev->dev, "Failed to allocate memory for CR/CSR "
"image\n");
return -ENOMEM;
}
- memset(crcsr_kernel, 0, VME_CRCSR_BUF_SIZE);
+ memset(bridge->crcsr_kernel, 0, VME_CRCSR_BUF_SIZE);
- reg_split(crcsr_bus, &crcsr_bus_high, &crcsr_bus_low);
+ reg_split(bridge->crcsr_bus, &crcsr_bus_high, &crcsr_bus_low);
- iowrite32be(crcsr_bus_high, tsi148_bridge->base + TSI148_LCSR_CROU);
- iowrite32be(crcsr_bus_low, tsi148_bridge->base + TSI148_LCSR_CROL);
+ iowrite32be(crcsr_bus_high, bridge->base + TSI148_LCSR_CROU);
+ iowrite32be(crcsr_bus_low, bridge->base + TSI148_LCSR_CROL);
/* Ensure that the CR/CSR is configured at the correct offset */
- cbar = ioread32be(tsi148_bridge->base + TSI148_CBAR);
+ cbar = ioread32be(bridge->base + TSI148_CBAR);
cbar = (cbar & TSI148_CRCSR_CBAR_M)>>3;
- vstat = tsi148_slot_get();
+ vstat = tsi148_slot_get(tsi148_bridge);
if (cbar != vstat) {
+ cbar = vstat;
dev_info(&pdev->dev, "Setting CR/CSR offset\n");
- iowrite32be(cbar<<3, tsi148_bridge->base + TSI148_CBAR);
+ iowrite32be(cbar<<3, bridge->base + TSI148_CBAR);
}
dev_info(&pdev->dev, "CR/CSR Offset: %d\n", cbar);
- crat = ioread32be(tsi148_bridge->base + TSI148_LCSR_CRAT);
+ crat = ioread32be(bridge->base + TSI148_LCSR_CRAT);
if (crat & TSI148_LCSR_CRAT_EN) {
dev_info(&pdev->dev, "Enabling CR/CSR space\n");
iowrite32be(crat | TSI148_LCSR_CRAT_EN,
- tsi148_bridge->base + TSI148_LCSR_CRAT);
+ bridge->base + TSI148_LCSR_CRAT);
} else
dev_info(&pdev->dev, "CR/CSR already enabled\n");
@@ -2214,8 +2176,9 @@ static int tsi148_crcsr_init(struct pci_dev *pdev)
* through VME writes.
*/
if(err_chk) {
- retval = tsi148_master_set(flush_image, 1, (vstat * 0x80000),
- 0x80000, VME_CRCSR, VME_SCT, VME_D16);
+ retval = tsi148_master_set(bridge->flush_image, 1,
+ (vstat * 0x80000), 0x80000, VME_CRCSR, VME_SCT,
+ VME_D16);
if (retval)
dev_err(&pdev->dev, "Configuring flush image failed\n");
}
@@ -2224,20 +2187,25 @@ static int tsi148_crcsr_init(struct pci_dev *pdev)
}
-static void tsi148_crcsr_exit(struct pci_dev *pdev)
+static void tsi148_crcsr_exit(struct vme_bridge *tsi148_bridge,
+ struct pci_dev *pdev)
{
u32 crat;
+ struct tsi148_driver *bridge;
+
+ bridge = tsi148_bridge->driver_priv;
/* Turn off CR/CSR space */
- crat = ioread32be(tsi148_bridge->base + TSI148_LCSR_CRAT);
+ crat = ioread32be(bridge->base + TSI148_LCSR_CRAT);
iowrite32be(crat & ~TSI148_LCSR_CRAT_EN,
- tsi148_bridge->base + TSI148_LCSR_CRAT);
+ bridge->base + TSI148_LCSR_CRAT);
/* Free image */
- iowrite32be(0, tsi148_bridge->base + TSI148_LCSR_CROU);
- iowrite32be(0, tsi148_bridge->base + TSI148_LCSR_CROL);
+ iowrite32be(0, bridge->base + TSI148_LCSR_CROU);
+ iowrite32be(0, bridge->base + TSI148_LCSR_CROL);
- pci_free_consistent(pdev, VME_CRCSR_BUF_SIZE, crcsr_kernel, crcsr_bus);
+ pci_free_consistent(pdev, VME_CRCSR_BUF_SIZE, bridge->crcsr_kernel,
+ bridge->crcsr_bus);
}
static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -2245,6 +2213,8 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
int retval, i, master_num;
u32 data;
struct list_head *pos = NULL;
+ struct vme_bridge *tsi148_bridge;
+ struct tsi148_driver *tsi148_device;
struct vme_master_resource *master_image;
struct vme_slave_resource *slave_image;
struct vme_dma_resource *dma_ctrlr;
@@ -2264,6 +2234,18 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
memset(tsi148_bridge, 0, sizeof(struct vme_bridge));
+ tsi148_device = kmalloc(sizeof(struct tsi148_driver), GFP_KERNEL);
+ if (tsi148_device == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for device "
+ "structure\n");
+ retval = -ENOMEM;
+ goto err_driver;
+ }
+
+ memset(tsi148_device, 0, sizeof(struct tsi148_driver));
+
+ tsi148_bridge->driver_priv = tsi148_device;
+
/* Enable the device */
retval = pci_enable_device(pdev);
if (retval) {
@@ -2279,15 +2261,16 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* map registers in BAR 0 */
- tsi148_bridge->base = ioremap_nocache(pci_resource_start(pdev, 0), 4096);
- if (!tsi148_bridge->base) {
+ tsi148_device->base = ioremap_nocache(pci_resource_start(pdev, 0),
+ 4096);
+ if (!tsi148_device->base) {
dev_err(&pdev->dev, "Unable to remap CRG region\n");
retval = -EIO;
goto err_remap;
}
/* Check to see if the mapping worked out */
- data = ioread32(tsi148_bridge->base + TSI148_PCFS_ID) & 0x0000FFFF;
+ data = ioread32(tsi148_device->base + TSI148_PCFS_ID) & 0x0000FFFF;
if (data != PCI_VENDOR_ID_TUNDRA) {
dev_err(&pdev->dev, "CRG region check failed\n");
retval = -EIO;
@@ -2295,12 +2278,11 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* Initialize wait queues & mutual exclusion flags */
- /* XXX These need to be moved to the vme_bridge structure */
- init_waitqueue_head(&dma_queue[0]);
- init_waitqueue_head(&dma_queue[1]);
- init_waitqueue_head(&iack_queue);
- mutex_init(&(vme_int));
- mutex_init(&(vme_rmw));
+ init_waitqueue_head(&(tsi148_device->dma_queue[0]));
+ init_waitqueue_head(&(tsi148_device->dma_queue[1]));
+ init_waitqueue_head(&(tsi148_device->iack_queue));
+ mutex_init(&(tsi148_device->vme_int));
+ mutex_init(&(tsi148_device->vme_rmw));
tsi148_bridge->parent = &(pdev->dev);
strcpy(tsi148_bridge->name, driver_name);
@@ -2320,29 +2302,29 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
master_num = TSI148_MAX_MASTER;
if(err_chk){
master_num--;
- /* XXX */
- flush_image = (struct vme_master_resource *)kmalloc(
- sizeof(struct vme_master_resource), GFP_KERNEL);
- if (flush_image == NULL) {
+
+ tsi148_device->flush_image = (struct vme_master_resource *)
+ kmalloc(sizeof(struct vme_master_resource), GFP_KERNEL);
+ if (tsi148_device->flush_image == NULL) {
dev_err(&pdev->dev, "Failed to allocate memory for "
"flush resource structure\n");
retval = -ENOMEM;
goto err_master;
}
- flush_image->parent = tsi148_bridge;
- spin_lock_init(&(flush_image->lock));
- flush_image->locked = 1;
- flush_image->number = master_num;
- flush_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
- VME_A64;
- flush_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
- VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
- VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
- VME_PROG | VME_DATA;
- flush_image->width_attr = VME_D16 | VME_D32;
- memset(&(flush_image->pci_resource), 0,
+ tsi148_device->flush_image->parent = tsi148_bridge;
+ spin_lock_init(&(tsi148_device->flush_image->lock));
+ tsi148_device->flush_image->locked = 1;
+ tsi148_device->flush_image->number = master_num;
+ tsi148_device->flush_image->address_attr = VME_A16 | VME_A24 |
+ VME_A32 | VME_A64;
+ tsi148_device->flush_image->cycle_attr = VME_SCT | VME_BLT |
+ VME_MBLT | VME_2eVME | VME_2eSST | VME_2eSSTB |
+ VME_2eSST160 | VME_2eSST267 | VME_2eSST320 | VME_SUPER |
+ VME_USER | VME_PROG | VME_DATA;
+ tsi148_device->flush_image->width_attr = VME_D16 | VME_D32;
+ memset(&(tsi148_device->flush_image->bus_resource), 0,
sizeof(struct resource));
- flush_image->kern_base = NULL;
+ tsi148_device->flush_image->kern_base = NULL;
}
/* Add master windows to list */
@@ -2367,7 +2349,7 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
VME_PROG | VME_DATA;
master_image->width_attr = VME_D16 | VME_D32;
- memset(&(master_image->pci_resource), 0,
+ memset(&(master_image->bus_resource), 0,
sizeof(struct resource));
master_image->kern_base = NULL;
list_add_tail(&(master_image->list),
@@ -2415,6 +2397,10 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mutex_init(&(dma_ctrlr->mtx));
dma_ctrlr->locked = 0;
dma_ctrlr->number = i;
+ dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM |
+ VME_DMA_MEM_TO_VME | VME_DMA_VME_TO_VME |
+ VME_DMA_MEM_TO_MEM | VME_DMA_PATTERN_TO_VME |
+ VME_DMA_PATTERN_TO_MEM;
INIT_LIST_HEAD(&(dma_ctrlr->pending));
INIT_LIST_HEAD(&(dma_ctrlr->running));
list_add_tail(&(dma_ctrlr->list),
@@ -2455,40 +2441,42 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
tsi148_bridge->lm_detach = tsi148_lm_detach;
tsi148_bridge->slot_get = tsi148_slot_get;
- data = ioread32be(tsi148_bridge->base + TSI148_LCSR_VSTAT);
+ data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT);
dev_info(&pdev->dev, "Board is%s the VME system controller\n",
(data & TSI148_LCSR_VSTAT_SCONS)? "" : " not");
- dev_info(&pdev->dev, "VME geographical address is %d\n",
- data & TSI148_LCSR_VSTAT_GA_M);
+ if (!geoid)
+ dev_info(&pdev->dev, "VME geographical address is %d\n",
+ data & TSI148_LCSR_VSTAT_GA_M);
+ else
+ dev_info(&pdev->dev, "VME geographical address is set to %d\n",
+ geoid);
+
dev_info(&pdev->dev, "VME Write and flush and error check is %s\n",
err_chk ? "enabled" : "disabled");
- if(tsi148_crcsr_init(pdev)) {
+ if (tsi148_crcsr_init(tsi148_bridge, pdev))
dev_err(&pdev->dev, "CR/CSR configuration failed.\n");
goto err_crcsr;
- }
-
- /* Need to save tsi148_bridge pointer locally in link list for use in
- * tsi148_remove()
- */
retval = vme_register_bridge(tsi148_bridge);
if (retval != 0) {
dev_err(&pdev->dev, "Chip Registration failed.\n");
goto err_reg;
}
+ pci_set_drvdata(pdev, tsi148_bridge);
+
/* Clear VME bus "board fail", and "power-up reset" lines */
- data = ioread32be(tsi148_bridge->base + TSI148_LCSR_VSTAT);
+ data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT);
data &= ~TSI148_LCSR_VSTAT_BRDFL;
data |= TSI148_LCSR_VSTAT_CPURST;
- iowrite32be(data, tsi148_bridge->base + TSI148_LCSR_VSTAT);
+ iowrite32be(data, tsi148_device->base + TSI148_LCSR_VSTAT);
return 0;
vme_unregister_bridge(tsi148_bridge);
err_reg:
- tsi148_crcsr_exit(pdev);
+ tsi148_crcsr_exit(tsi148_bridge, pdev);
err_crcsr:
err_lm:
/* resources are stored in link list */
@@ -2519,15 +2507,17 @@ err_master:
kfree(master_image);
}
- tsi148_irq_exit(pdev);
+ tsi148_irq_exit(tsi148_device, pdev);
err_irq:
err_test:
- iounmap(tsi148_bridge->base);
+ iounmap(tsi148_device->base);
err_remap:
pci_release_regions(pdev);
err_resource:
pci_disable_device(pdev);
err_enable:
+ kfree(tsi148_device);
+err_driver:
kfree(tsi148_bridge);
err_struct:
return retval;
@@ -2541,56 +2531,58 @@ static void tsi148_remove(struct pci_dev *pdev)
struct vme_slave_resource *slave_image;
struct vme_dma_resource *dma_ctrlr;
int i;
+ struct tsi148_driver *bridge;
+ struct vme_bridge *tsi148_bridge = pci_get_drvdata(pdev);
- dev_dbg(&pdev->dev, "Driver is being unloaded.\n");
+ bridge = tsi148_bridge->driver_priv;
- /* XXX We need to find the pdev->dev in the list of vme_bridge->dev's */
+
+ dev_dbg(&pdev->dev, "Driver is being unloaded.\n");
/*
* Shutdown all inbound and outbound windows.
*/
for (i = 0; i < 8; i++) {
- iowrite32be(0, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ iowrite32be(0, bridge->base + TSI148_LCSR_IT[i] +
TSI148_LCSR_OFFSET_ITAT);
- iowrite32be(0, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ iowrite32be(0, bridge->base + TSI148_LCSR_OT[i] +
TSI148_LCSR_OFFSET_OTAT);
}
/*
* Shutdown Location monitor.
*/
- iowrite32be(0, tsi148_bridge->base + TSI148_LCSR_LMAT);
+ iowrite32be(0, bridge->base + TSI148_LCSR_LMAT);
/*
* Shutdown CRG map.
*/
- iowrite32be(0, tsi148_bridge->base + TSI148_LCSR_CSRAT);
+ iowrite32be(0, bridge->base + TSI148_LCSR_CSRAT);
/*
* Clear error status.
*/
- iowrite32be(0xFFFFFFFF, tsi148_bridge->base + TSI148_LCSR_EDPAT);
- iowrite32be(0xFFFFFFFF, tsi148_bridge->base + TSI148_LCSR_VEAT);
- iowrite32be(0x07000700, tsi148_bridge->base + TSI148_LCSR_PSTAT);
+ iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_EDPAT);
+ iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_VEAT);
+ iowrite32be(0x07000700, bridge->base + TSI148_LCSR_PSTAT);
/*
* Remove VIRQ interrupt (if any)
*/
- if (ioread32be(tsi148_bridge->base + TSI148_LCSR_VICR) & 0x800) {
- iowrite32be(0x8000, tsi148_bridge->base + TSI148_LCSR_VICR);
- }
+ if (ioread32be(bridge->base + TSI148_LCSR_VICR) & 0x800)
+ iowrite32be(0x8000, bridge->base + TSI148_LCSR_VICR);
/*
* Map all Interrupts to PCI INTA
*/
- iowrite32be(0x0, tsi148_bridge->base + TSI148_LCSR_INTM1);
- iowrite32be(0x0, tsi148_bridge->base + TSI148_LCSR_INTM2);
+ iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM1);
+ iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM2);
- tsi148_irq_exit(pdev);
+ tsi148_irq_exit(bridge, pdev);
vme_unregister_bridge(tsi148_bridge);
- tsi148_crcsr_exit(pdev);
+ tsi148_crcsr_exit(tsi148_bridge, pdev);
/* resources are stored in link list */
list_for_each(pos, &(tsi148_bridge->dma_resources)) {
@@ -2608,19 +2600,22 @@ static void tsi148_remove(struct pci_dev *pdev)
/* resources are stored in link list */
list_for_each(pos, &(tsi148_bridge->master_resources)) {
- master_image = list_entry(pos, struct vme_master_resource, list);
+ master_image = list_entry(pos, struct vme_master_resource,
+ list);
list_del(pos);
kfree(master_image);
}
- tsi148_irq_exit(pdev);
+ tsi148_irq_exit(bridge, pdev);
- iounmap(tsi148_bridge->base);
+ iounmap(bridge->base);
pci_release_regions(pdev);
pci_disable_device(pdev);
+ kfree(tsi148_bridge->driver_priv);
+
kfree(tsi148_bridge);
}
@@ -2634,250 +2629,11 @@ static void __exit tsi148_exit(void)
MODULE_PARM_DESC(err_chk, "Check for VME errors on reads and writes");
module_param(err_chk, bool, 0);
+MODULE_PARM_DESC(geoid, "Override geographical addressing");
+module_param(geoid, int, 0);
+
MODULE_DESCRIPTION("VME driver for the Tundra Tempe VME bridge");
MODULE_LICENSE("GPL");
module_init(tsi148_init);
module_exit(tsi148_exit);
-
-/*----------------------------------------------------------------------------
- * STAGING
- *--------------------------------------------------------------------------*/
-
-#if 0
-/*
- * Direct Mode DMA transfer
- *
- * XXX Not looking at direct mode for now, we can always use link list mode
- * with a single entry.
- */
-int tsi148_dma_run(struct vme_dma_resource *resource, struct vme_dma_attr src,
- struct vme_dma_attr dest, size_t count)
-{
- u32 dctlreg = 0;
- unsigned int tmp;
- int val;
- int channel, x;
- struct vmeDmaPacket *cur_dma;
- struct tsi148_dma_descriptor *dmaLL;
-
- /* direct mode */
- dctlreg = 0x800000;
-
- for (x = 0; x < 8; x++) { /* vme block size */
- if ((32 << x) >= vmeDma->maxVmeBlockSize) {
- break;
- }
- }
- if (x == 8)
- x = 7;
- dctlreg |= (x << 12);
-
- for (x = 0; x < 8; x++) { /* pci block size */
- if ((32 << x) >= vmeDma->maxPciBlockSize) {
- break;
- }
- }
- if (x == 8)
- x = 7;
- dctlreg |= (x << 4);
-
- if (vmeDma->vmeBackOffTimer) {
- for (x = 1; x < 8; x++) { /* vme timer */
- if ((1 << (x - 1)) >= vmeDma->vmeBackOffTimer) {
- break;
- }
- }
- if (x == 8)
- x = 7;
- dctlreg |= (x << 8);
- }
-
- if (vmeDma->pciBackOffTimer) {
- for (x = 1; x < 8; x++) { /* pci timer */
- if ((1 << (x - 1)) >= vmeDma->pciBackOffTimer) {
- break;
- }
- }
- if (x == 8)
- x = 7;
- dctlreg |= (x << 0);
- }
-
- /* Program registers for DMA transfer */
- iowrite32be(dmaLL->dsau, tsi148_bridge->base +
- TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DSAU);
- iowrite32be(dmaLL->dsal, tsi148_bridge->base +
- TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DSAL);
- iowrite32be(dmaLL->ddau, tsi148_bridge->base +
- TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DDAU);
- iowrite32be(dmaLL->ddal, tsi148_bridge->base +
- TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DDAL);
- iowrite32be(dmaLL->dsat, tsi148_bridge->base +
- TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DSAT);
- iowrite32be(dmaLL->ddat, tsi148_bridge->base +
- TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DDAT);
- iowrite32be(dmaLL->dcnt, tsi148_bridge->base +
- TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCNT);
- iowrite32be(dmaLL->ddbs, tsi148_bridge->base +
- TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DDBS);
-
- /* Start the operation */
- iowrite32be(dctlreg | 0x2000000, tsi148_bridge->base +
- TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL);
-
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_DMA[channel] +
- TSI148_LCSR_OFFSET_DSTA);
- wait_event_interruptible(dma_queue[channel], (tmp & 0x1000000) == 0);
-
- /*
- * Read status register, we should probably do this in some error
- * handler rather than here so that we can be sure we haven't kicked off
- * another DMA transfer.
- */
- val = ioread32be(tsi148_bridge->base + TSI148_LCSR_DMA[channel] +
- TSI148_LCSR_OFFSET_DSTA);
-
- vmeDma->vmeDmaStatus = 0;
- if (val & 0x10000000) {
- printk(KERN_ERR
- "DMA Error in DMA_tempe_irqhandler DSTA=%08X\n",
- val);
- vmeDma->vmeDmaStatus = val;
-
- }
- return (0);
-}
-#endif
-
-#if 0
-
-/* Global VME controller information */
-struct pci_dev *vme_pci_dev;
-
-/*
- * Set the VME bus arbiter with the requested attributes
- */
-int tempe_set_arbiter(vmeArbiterCfg_t * vmeArb)
-{
- int temp_ctl = 0;
- int gto = 0;
-
- temp_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_VCTRL);
- temp_ctl &= 0xFFEFFF00;
-
- if (vmeArb->globalTimeoutTimer == 0xFFFFFFFF) {
- gto = 8;
- } else if (vmeArb->globalTimeoutTimer > 2048) {
- return (-EINVAL);
- } else if (vmeArb->globalTimeoutTimer == 0) {
- gto = 0;
- } else {
- gto = 1;
- while ((16 * (1 << (gto - 1))) < vmeArb->globalTimeoutTimer) {
- gto += 1;
- }
- }
- temp_ctl |= gto;
-
- if (vmeArb->arbiterMode != VME_PRIORITY_MODE) {
- temp_ctl |= 1 << 6;
- }
-
- if (vmeArb->arbiterTimeoutFlag) {
- temp_ctl |= 1 << 7;
- }
-
- if (vmeArb->noEarlyReleaseFlag) {
- temp_ctl |= 1 << 20;
- }
- iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_VCTRL);
-
- return (0);
-}
-
-/*
- * Return the attributes of the VME bus arbiter.
- */
-int tempe_get_arbiter(vmeArbiterCfg_t * vmeArb)
-{
- int temp_ctl = 0;
- int gto = 0;
-
-
- temp_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_VCTRL);
-
- gto = temp_ctl & 0xF;
- if (gto != 0) {
- vmeArb->globalTimeoutTimer = (16 * (1 << (gto - 1)));
- }
-
- if (temp_ctl & (1 << 6)) {
- vmeArb->arbiterMode = VME_R_ROBIN_MODE;
- } else {
- vmeArb->arbiterMode = VME_PRIORITY_MODE;
- }
-
- if (temp_ctl & (1 << 7)) {
- vmeArb->arbiterTimeoutFlag = 1;
- }
-
- if (temp_ctl & (1 << 20)) {
- vmeArb->noEarlyReleaseFlag = 1;
- }
-
- return (0);
-}
-
-/*
- * Set the VME bus requestor with the requested attributes
- */
-int tempe_set_requestor(vmeRequesterCfg_t * vmeReq)
-{
- int temp_ctl = 0;
-
- temp_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_VMCTRL);
- temp_ctl &= 0xFFFF0000;
-
- if (vmeReq->releaseMode == 1) {
- temp_ctl |= (1 << 3);
- }
-
- if (vmeReq->fairMode == 1) {
- temp_ctl |= (1 << 2);
- }
-
- temp_ctl |= (vmeReq->timeonTimeoutTimer & 7) << 8;
- temp_ctl |= (vmeReq->timeoffTimeoutTimer & 7) << 12;
- temp_ctl |= vmeReq->requestLevel;
-
- iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_VMCTRL);
- return (0);
-}
-
-/*
- * Return the attributes of the VME bus requestor
- */
-int tempe_get_requestor(vmeRequesterCfg_t * vmeReq)
-{
- int temp_ctl = 0;
-
- temp_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_VMCTRL);
-
- if (temp_ctl & 0x18) {
- vmeReq->releaseMode = 1;
- }
-
- if (temp_ctl & (1 << 2)) {
- vmeReq->fairMode = 1;
- }
-
- vmeReq->requestLevel = temp_ctl & 3;
- vmeReq->timeonTimeoutTimer = (temp_ctl >> 8) & 7;
- vmeReq->timeoffTimeoutTimer = (temp_ctl >> 12) & 7;
-
- return (0);
-}
-
-
-#endif
diff --git a/drivers/staging/vme/bridges/vme_tsi148.h b/drivers/staging/vme/bridges/vme_tsi148.h
index 6f0f705ce6be..9e5f7fa1d744 100644
--- a/drivers/staging/vme/bridges/vme_tsi148.h
+++ b/drivers/staging/vme/bridges/vme_tsi148.h
@@ -33,6 +33,22 @@
#define TSI148_MAX_MAILBOX 4 /* Max Mail Box registers */
#define TSI148_MAX_SEMAPHORE 8 /* Max Semaphores */
+/* Structure used to hold driver specific information */
+struct tsi148_driver {
+ void *base; /* Base Address of device registers */
+ wait_queue_head_t dma_queue[2];
+ wait_queue_head_t iack_queue;
+ void (*lm_callback[4])(int); /* Called in interrupt handler */
+ void *crcsr_kernel;
+ dma_addr_t crcsr_bus;
+ struct vme_master_resource *flush_image;
+ struct mutex vme_rmw; /* Only one RMW cycle at a time */
+ struct mutex vme_int; /*
+ * Only one VME interrupt can be
+ * generated at a time, provide locking
+ */
+};
+
/*
* Layout of a DMAC Linked-List Descriptor
*
diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c
index e228942ee081..c60c80fb241d 100644
--- a/drivers/staging/vme/devices/vme_user.c
+++ b/drivers/staging/vme/devices/vme_user.c
@@ -1,8 +1,8 @@
/*
* VMEbus User access driver
*
- * Author: Martyn Welch <martyn.welch@gefanuc.com>
- * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
*
* Based on work by:
* Tom Armistead and Ajit Prem
@@ -400,8 +400,39 @@ static ssize_t vme_user_write(struct file *file, const char *buf, size_t count,
static loff_t vme_user_llseek(struct file *file, loff_t off, int whence)
{
- printk(KERN_ERR "Llseek currently incomplete\n");
- return -EINVAL;
+ loff_t absolute = -1;
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ size_t image_size;
+
+ down(&image[minor].sem);
+ image_size = vme_get_size(image[minor].resource);
+
+ switch (whence) {
+ case SEEK_SET:
+ absolute = off;
+ break;
+ case SEEK_CUR:
+ absolute = file->f_pos + off;
+ break;
+ case SEEK_END:
+ absolute = image_size + off;
+ break;
+ default:
+ up(&image[minor].sem);
+ return -EINVAL;
+ break;
+ }
+
+ if ((absolute < 0) || (absolute >= image_size)) {
+ up(&image[minor].sem);
+ return -EINVAL;
+ }
+
+ file->f_pos = absolute;
+
+ up(&image[minor].sem);
+
+ return absolute;
}
/*
@@ -574,8 +605,8 @@ static int __init vme_user_init(void)
* in future revisions if that ever becomes necessary.
*/
if (bus_num > USER_BUS_MAX) {
- printk(KERN_ERR "%s: Driver only able to handle %d PIO2 "
- "Cards\n", driver_name, USER_BUS_MAX);
+ printk(KERN_ERR "%s: Driver only able to handle %d buses\n",
+ driver_name, USER_BUS_MAX);
bus_num = USER_BUS_MAX;
}
@@ -670,8 +701,12 @@ static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot)
/* Request slave resources and allocate buffers (128kB wide) */
for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) {
/* XXX Need to properly request attributes */
+ /* For ca91cx42 bridge there are only two slave windows
+ * supporting A16 addressing, so we request A24 supported
+ * by all windows.
+ */
image[i].resource = vme_slave_request(vme_user_bridge,
- VME_A16, VME_SCT);
+ VME_A24, VME_SCT);
if (image[i].resource == NULL) {
printk(KERN_WARNING "Unable to allocate slave "
"resource\n");
@@ -703,6 +738,14 @@ static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot)
"resource\n");
goto err_master;
}
+ image[i].size_buf = PCI_BUF_SIZE;
+ image[i].kern_buf = kmalloc(image[i].size_buf, GFP_KERNEL);
+ if (image[i].kern_buf == NULL) {
+ printk(KERN_WARNING "Unable to allocate memory for "
+ "master window buffers\n");
+ err = -ENOMEM;
+ goto err_master_buf;
+ }
}
/* Create sysfs entries - on udev systems this creates the dev files */
@@ -756,6 +799,9 @@ err_sysfs:
/* Ensure counter set correcty to unalloc all master windows */
i = MASTER_MAX + 1;
+err_master_buf:
+ for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++)
+ kfree(image[i].kern_buf);
err_master:
while (i > MASTER_MINOR) {
i--;
@@ -791,6 +837,9 @@ static int __exit vme_user_remove(struct device *dev, int cur_bus, int cur_slot)
}
class_destroy(vme_user_sysfs_class);
+ for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++)
+ kfree(image[i].kern_buf);
+
for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) {
vme_slave_set(image[i].resource, 0, 0, 0, 0, VME_A32, 0);
vme_slave_free(image[i].resource);
@@ -818,7 +867,7 @@ MODULE_PARM_DESC(bus, "Enumeration of VMEbus to which the driver is connected");
module_param_array(bus, int, &bus_num, 0);
MODULE_DESCRIPTION("VME User Space Access Driver");
-MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com");
+MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
MODULE_LICENSE("GPL");
module_init(vme_user_init);
diff --git a/drivers/staging/vme/vme.c b/drivers/staging/vme/vme.c
index 994fdb9b2127..d6d84ebeeec0 100644
--- a/drivers/staging/vme/vme.c
+++ b/drivers/staging/vme/vme.c
@@ -1,8 +1,8 @@
/*
* VME Bridge Framework
*
- * Author: Martyn Welch <martyn.welch@gefanuc.com>
- * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
*
* Based on work by Tom Armistead and Ajit Prem
* Copyright 2004 Motorola Inc.
@@ -37,8 +37,8 @@
static unsigned int vme_bus_numbers;
DEFINE_MUTEX(vme_bus_num_mtx);
-static void __exit vme_exit (void);
-static int __init vme_init (void);
+static void __exit vme_exit(void);
+static int __init vme_init(void);
/*
@@ -86,26 +86,26 @@ static struct vme_bridge *find_bridge(struct vme_resource *resource)
* XXX VME bridges could be available on buses other than PCI. At the momment
* this framework only supports PCI devices.
*/
-void * vme_alloc_consistent(struct vme_resource *resource, size_t size,
+void *vme_alloc_consistent(struct vme_resource *resource, size_t size,
dma_addr_t *dma)
{
struct vme_bridge *bridge;
struct pci_dev *pdev;
- if(resource == NULL) {
- printk("No resource\n");
+ if (resource == NULL) {
+ printk(KERN_ERR "No resource\n");
return NULL;
}
bridge = find_bridge(resource);
- if(bridge == NULL) {
- printk("Can't find bridge\n");
+ if (bridge == NULL) {
+ printk(KERN_ERR "Can't find bridge\n");
return NULL;
}
/* Find pci_dev container of dev */
if (bridge->parent == NULL) {
- printk("Dev entry NULL\n");
+ printk(KERN_ERR "Dev entry NULL\n");
return NULL;
}
pdev = container_of(bridge->parent, struct pci_dev, dev);
@@ -126,14 +126,14 @@ void vme_free_consistent(struct vme_resource *resource, size_t size,
struct vme_bridge *bridge;
struct pci_dev *pdev;
- if(resource == NULL) {
- printk("No resource\n");
+ if (resource == NULL) {
+ printk(KERN_ERR "No resource\n");
return;
}
bridge = find_bridge(resource);
- if(bridge == NULL) {
- printk("Can't find bridge\n");
+ if (bridge == NULL) {
+ printk(KERN_ERR "Can't find bridge\n");
return;
}
@@ -216,7 +216,7 @@ static int vme_check_window(vme_address_t aspace, unsigned long long vme_base,
/* User Defined */
break;
default:
- printk("Invalid address space\n");
+ printk(KERN_ERR "Invalid address space\n");
retval = -EINVAL;
break;
}
@@ -228,7 +228,7 @@ static int vme_check_window(vme_address_t aspace, unsigned long long vme_base,
* Request a slave image with specific attributes, return some unique
* identifier.
*/
-struct vme_resource * vme_slave_request(struct device *dev,
+struct vme_resource *vme_slave_request(struct device *dev,
vme_address_t address, vme_cycle_t cycle)
{
struct vme_bridge *bridge;
@@ -249,13 +249,13 @@ struct vme_resource * vme_slave_request(struct device *dev,
struct vme_slave_resource, list);
if (slave_image == NULL) {
- printk("Registered NULL Slave resource\n");
+ printk(KERN_ERR "Registered NULL Slave resource\n");
continue;
}
/* Find an unlocked and compatible image */
mutex_lock(&(slave_image->mtx));
- if(((slave_image->address_attr & address) == address) &&
+ if (((slave_image->address_attr & address) == address) &&
((slave_image->cycle_attr & cycle) == cycle) &&
(slave_image->locked == 0)) {
@@ -292,7 +292,7 @@ err_bus:
}
EXPORT_SYMBOL(vme_slave_request);
-int vme_slave_set (struct vme_resource *resource, int enabled,
+int vme_slave_set(struct vme_resource *resource, int enabled,
unsigned long long vme_base, unsigned long long size,
dma_addr_t buf_base, vme_address_t aspace, vme_cycle_t cycle)
{
@@ -301,25 +301,25 @@ int vme_slave_set (struct vme_resource *resource, int enabled,
int retval;
if (resource->type != VME_SLAVE) {
- printk("Not a slave resource\n");
+ printk(KERN_ERR "Not a slave resource\n");
return -EINVAL;
}
image = list_entry(resource->entry, struct vme_slave_resource, list);
if (bridge->slave_set == NULL) {
- printk("Function not supported\n");
+ printk(KERN_ERR "Function not supported\n");
return -ENOSYS;
}
- if(!(((image->address_attr & aspace) == aspace) &&
+ if (!(((image->address_attr & aspace) == aspace) &&
((image->cycle_attr & cycle) == cycle))) {
- printk("Invalid attributes\n");
+ printk(KERN_ERR "Invalid attributes\n");
return -EINVAL;
}
retval = vme_check_window(aspace, vme_base, size);
- if(retval)
+ if (retval)
return retval;
return bridge->slave_set(image, enabled, vme_base, size, buf_base,
@@ -327,7 +327,7 @@ int vme_slave_set (struct vme_resource *resource, int enabled,
}
EXPORT_SYMBOL(vme_slave_set);
-int vme_slave_get (struct vme_resource *resource, int *enabled,
+int vme_slave_get(struct vme_resource *resource, int *enabled,
unsigned long long *vme_base, unsigned long long *size,
dma_addr_t *buf_base, vme_address_t *aspace, vme_cycle_t *cycle)
{
@@ -335,14 +335,14 @@ int vme_slave_get (struct vme_resource *resource, int *enabled,
struct vme_slave_resource *image;
if (resource->type != VME_SLAVE) {
- printk("Not a slave resource\n");
+ printk(KERN_ERR "Not a slave resource\n");
return -EINVAL;
}
image = list_entry(resource->entry, struct vme_slave_resource, list);
if (bridge->slave_get == NULL) {
- printk("vme_slave_get not supported\n");
+ printk(KERN_ERR "vme_slave_get not supported\n");
return -EINVAL;
}
@@ -356,14 +356,14 @@ void vme_slave_free(struct vme_resource *resource)
struct vme_slave_resource *slave_image;
if (resource->type != VME_SLAVE) {
- printk("Not a slave resource\n");
+ printk(KERN_ERR "Not a slave resource\n");
return;
}
slave_image = list_entry(resource->entry, struct vme_slave_resource,
list);
if (slave_image == NULL) {
- printk("Can't find slave resource\n");
+ printk(KERN_ERR "Can't find slave resource\n");
return;
}
@@ -384,7 +384,7 @@ EXPORT_SYMBOL(vme_slave_free);
* Request a master image with specific attributes, return some unique
* identifier.
*/
-struct vme_resource * vme_master_request(struct device *dev,
+struct vme_resource *vme_master_request(struct device *dev,
vme_address_t address, vme_cycle_t cycle, vme_width_t dwidth)
{
struct vme_bridge *bridge;
@@ -411,7 +411,7 @@ struct vme_resource * vme_master_request(struct device *dev,
/* Find an unlocked and compatible image */
spin_lock(&(master_image->lock));
- if(((master_image->address_attr & address) == address) &&
+ if (((master_image->address_attr & address) == address) &&
((master_image->cycle_attr & cycle) == cycle) &&
((master_image->width_attr & dwidth) == dwidth) &&
(master_image->locked == 0)) {
@@ -452,7 +452,7 @@ err_bus:
}
EXPORT_SYMBOL(vme_master_request);
-int vme_master_set (struct vme_resource *resource, int enabled,
+int vme_master_set(struct vme_resource *resource, int enabled,
unsigned long long vme_base, unsigned long long size,
vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
{
@@ -461,26 +461,26 @@ int vme_master_set (struct vme_resource *resource, int enabled,
int retval;
if (resource->type != VME_MASTER) {
- printk("Not a master resource\n");
+ printk(KERN_ERR "Not a master resource\n");
return -EINVAL;
}
image = list_entry(resource->entry, struct vme_master_resource, list);
if (bridge->master_set == NULL) {
- printk("vme_master_set not supported\n");
+ printk(KERN_WARNING "vme_master_set not supported\n");
return -EINVAL;
}
- if(!(((image->address_attr & aspace) == aspace) &&
+ if (!(((image->address_attr & aspace) == aspace) &&
((image->cycle_attr & cycle) == cycle) &&
((image->width_attr & dwidth) == dwidth))) {
- printk("Invalid attributes\n");
+ printk(KERN_WARNING "Invalid attributes\n");
return -EINVAL;
}
retval = vme_check_window(aspace, vme_base, size);
- if(retval)
+ if (retval)
return retval;
return bridge->master_set(image, enabled, vme_base, size, aspace,
@@ -488,7 +488,7 @@ int vme_master_set (struct vme_resource *resource, int enabled,
}
EXPORT_SYMBOL(vme_master_set);
-int vme_master_get (struct vme_resource *resource, int *enabled,
+int vme_master_get(struct vme_resource *resource, int *enabled,
unsigned long long *vme_base, unsigned long long *size,
vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
{
@@ -496,14 +496,14 @@ int vme_master_get (struct vme_resource *resource, int *enabled,
struct vme_master_resource *image;
if (resource->type != VME_MASTER) {
- printk("Not a master resource\n");
+ printk(KERN_ERR "Not a master resource\n");
return -EINVAL;
}
image = list_entry(resource->entry, struct vme_master_resource, list);
if (bridge->master_get == NULL) {
- printk("vme_master_set not supported\n");
+ printk(KERN_WARNING "vme_master_set not supported\n");
return -EINVAL;
}
@@ -515,7 +515,7 @@ EXPORT_SYMBOL(vme_master_get);
/*
* Read data out of VME space into a buffer.
*/
-ssize_t vme_master_read (struct vme_resource *resource, void *buf, size_t count,
+ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count,
loff_t offset)
{
struct vme_bridge *bridge = find_bridge(resource);
@@ -523,12 +523,12 @@ ssize_t vme_master_read (struct vme_resource *resource, void *buf, size_t count,
size_t length;
if (bridge->master_read == NULL) {
- printk("Reading from resource not supported\n");
+ printk(KERN_WARNING "Reading from resource not supported\n");
return -EINVAL;
}
if (resource->type != VME_MASTER) {
- printk("Not a master resource\n");
+ printk(KERN_ERR "Not a master resource\n");
return -EINVAL;
}
@@ -537,7 +537,7 @@ ssize_t vme_master_read (struct vme_resource *resource, void *buf, size_t count,
length = vme_get_size(resource);
if (offset > length) {
- printk("Invalid Offset\n");
+ printk(KERN_WARNING "Invalid Offset\n");
return -EFAULT;
}
@@ -552,7 +552,7 @@ EXPORT_SYMBOL(vme_master_read);
/*
* Write data out to VME space from a buffer.
*/
-ssize_t vme_master_write (struct vme_resource *resource, void *buf,
+ssize_t vme_master_write(struct vme_resource *resource, void *buf,
size_t count, loff_t offset)
{
struct vme_bridge *bridge = find_bridge(resource);
@@ -560,12 +560,12 @@ ssize_t vme_master_write (struct vme_resource *resource, void *buf,
size_t length;
if (bridge->master_write == NULL) {
- printk("Writing to resource not supported\n");
+ printk(KERN_WARNING "Writing to resource not supported\n");
return -EINVAL;
}
if (resource->type != VME_MASTER) {
- printk("Not a master resource\n");
+ printk(KERN_ERR "Not a master resource\n");
return -EINVAL;
}
@@ -574,7 +574,7 @@ ssize_t vme_master_write (struct vme_resource *resource, void *buf,
length = vme_get_size(resource);
if (offset > length) {
- printk("Invalid Offset\n");
+ printk(KERN_WARNING "Invalid Offset\n");
return -EFAULT;
}
@@ -588,19 +588,19 @@ EXPORT_SYMBOL(vme_master_write);
/*
* Perform RMW cycle to provided location.
*/
-unsigned int vme_master_rmw (struct vme_resource *resource, unsigned int mask,
+unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask,
unsigned int compare, unsigned int swap, loff_t offset)
{
struct vme_bridge *bridge = find_bridge(resource);
struct vme_master_resource *image;
if (bridge->master_rmw == NULL) {
- printk("Writing to resource not supported\n");
+ printk(KERN_WARNING "Writing to resource not supported\n");
return -EINVAL;
}
if (resource->type != VME_MASTER) {
- printk("Not a master resource\n");
+ printk(KERN_ERR "Not a master resource\n");
return -EINVAL;
}
@@ -615,14 +615,14 @@ void vme_master_free(struct vme_resource *resource)
struct vme_master_resource *master_image;
if (resource->type != VME_MASTER) {
- printk("Not a master resource\n");
+ printk(KERN_ERR "Not a master resource\n");
return;
}
master_image = list_entry(resource->entry, struct vme_master_resource,
list);
if (master_image == NULL) {
- printk("Can't find master resource\n");
+ printk(KERN_ERR "Can't find master resource\n");
return;
}
@@ -643,7 +643,7 @@ EXPORT_SYMBOL(vme_master_free);
* Request a DMA controller with specific attributes, return some unique
* identifier.
*/
-struct vme_resource *vme_dma_request(struct device *dev)
+struct vme_resource *vme_dma_request(struct device *dev, vme_dma_route_t route)
{
struct vme_bridge *bridge;
struct list_head *dma_pos = NULL;
@@ -666,13 +666,15 @@ struct vme_resource *vme_dma_request(struct device *dev)
struct vme_dma_resource, list);
if (dma_ctrlr == NULL) {
- printk("Registered NULL DMA resource\n");
+ printk(KERN_ERR "Registered NULL DMA resource\n");
continue;
}
- /* Find an unlocked controller */
+ /* Find an unlocked and compatible controller */
mutex_lock(&(dma_ctrlr->mtx));
- if(dma_ctrlr->locked == 0) {
+ if (((dma_ctrlr->route_attr & route) == route) &&
+ (dma_ctrlr->locked == 0)) {
+
dma_ctrlr->locked = 1;
mutex_unlock(&(dma_ctrlr->mtx));
allocated_ctrlr = dma_ctrlr;
@@ -715,16 +717,15 @@ struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource)
struct vme_dma_list *dma_list;
if (resource->type != VME_DMA) {
- printk("Not a DMA resource\n");
+ printk(KERN_ERR "Not a DMA resource\n");
return NULL;
}
ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
- dma_list = (struct vme_dma_list *)kmalloc(
- sizeof(struct vme_dma_list), GFP_KERNEL);
- if(dma_list == NULL) {
- printk("Unable to allocate memory for new dma list\n");
+ dma_list = kmalloc(sizeof(struct vme_dma_list), GFP_KERNEL);
+ if (dma_list == NULL) {
+ printk(KERN_ERR "Unable to allocate memory for new dma list\n");
return NULL;
}
INIT_LIST_HEAD(&(dma_list->entries));
@@ -744,17 +745,17 @@ struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern,
struct vme_dma_attr *attributes;
struct vme_dma_pattern *pattern_attr;
- attributes = (struct vme_dma_attr *)kmalloc(
- sizeof(struct vme_dma_attr), GFP_KERNEL);
- if(attributes == NULL) {
- printk("Unable to allocate memory for attributes structure\n");
+ attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
+ if (attributes == NULL) {
+ printk(KERN_ERR "Unable to allocate memory for attributes "
+ "structure\n");
goto err_attr;
}
- pattern_attr = (struct vme_dma_pattern *)kmalloc(
- sizeof(struct vme_dma_pattern), GFP_KERNEL);
- if(pattern_attr == NULL) {
- printk("Unable to allocate memory for pattern attributes\n");
+ pattern_attr = kmalloc(sizeof(struct vme_dma_pattern), GFP_KERNEL);
+ if (pattern_attr == NULL) {
+ printk(KERN_ERR "Unable to allocate memory for pattern "
+ "attributes\n");
goto err_pat;
}
@@ -784,17 +785,17 @@ struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address)
/* XXX Run some sanity checks here */
- attributes = (struct vme_dma_attr *)kmalloc(
- sizeof(struct vme_dma_attr), GFP_KERNEL);
- if(attributes == NULL) {
- printk("Unable to allocate memory for attributes structure\n");
+ attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
+ if (attributes == NULL) {
+ printk(KERN_ERR "Unable to allocate memory for attributes "
+ "structure\n");
goto err_attr;
}
- pci_attr = (struct vme_dma_pci *)kmalloc(sizeof(struct vme_dma_pci),
- GFP_KERNEL);
- if(pci_attr == NULL) {
- printk("Unable to allocate memory for pci attributes\n");
+ pci_attr = kmalloc(sizeof(struct vme_dma_pci), GFP_KERNEL);
+ if (pci_attr == NULL) {
+ printk(KERN_ERR "Unable to allocate memory for pci "
+ "attributes\n");
goto err_pci;
}
@@ -824,19 +825,18 @@ struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address,
struct vme_dma_attr *attributes;
struct vme_dma_vme *vme_attr;
- /* XXX Run some sanity checks here */
-
- attributes = (struct vme_dma_attr *)kmalloc(
+ attributes = kmalloc(
sizeof(struct vme_dma_attr), GFP_KERNEL);
- if(attributes == NULL) {
- printk("Unable to allocate memory for attributes structure\n");
+ if (attributes == NULL) {
+ printk(KERN_ERR "Unable to allocate memory for attributes "
+ "structure\n");
goto err_attr;
}
- vme_attr = (struct vme_dma_vme *)kmalloc(sizeof(struct vme_dma_vme),
- GFP_KERNEL);
- if(vme_attr == NULL) {
- printk("Unable to allocate memory for vme attributes\n");
+ vme_attr = kmalloc(sizeof(struct vme_dma_vme), GFP_KERNEL);
+ if (vme_attr == NULL) {
+ printk(KERN_ERR "Unable to allocate memory for vme "
+ "attributes\n");
goto err_vme;
}
@@ -875,12 +875,12 @@ int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
int retval;
if (bridge->dma_list_add == NULL) {
- printk("Link List DMA generation not supported\n");
+ printk(KERN_WARNING "Link List DMA generation not supported\n");
return -EINVAL;
}
if (!mutex_trylock(&(list->mtx))) {
- printk("Link List already submitted\n");
+ printk(KERN_ERR "Link List already submitted\n");
return -EINVAL;
}
@@ -898,7 +898,7 @@ int vme_dma_list_exec(struct vme_dma_list *list)
int retval;
if (bridge->dma_list_exec == NULL) {
- printk("Link List DMA execution not supported\n");
+ printk(KERN_ERR "Link List DMA execution not supported\n");
return -EINVAL;
}
@@ -918,12 +918,12 @@ int vme_dma_list_free(struct vme_dma_list *list)
int retval;
if (bridge->dma_list_empty == NULL) {
- printk("Emptying of Link Lists not supported\n");
+ printk(KERN_WARNING "Emptying of Link Lists not supported\n");
return -EINVAL;
}
if (!mutex_trylock(&(list->mtx))) {
- printk("Link List in use\n");
+ printk(KERN_ERR "Link List in use\n");
return -EINVAL;
}
@@ -933,7 +933,7 @@ int vme_dma_list_free(struct vme_dma_list *list)
*/
retval = bridge->dma_list_empty(list);
if (retval) {
- printk("Unable to empty link-list entries\n");
+ printk(KERN_ERR "Unable to empty link-list entries\n");
mutex_unlock(&(list->mtx));
return retval;
}
@@ -949,19 +949,19 @@ int vme_dma_free(struct vme_resource *resource)
struct vme_dma_resource *ctrlr;
if (resource->type != VME_DMA) {
- printk("Not a DMA resource\n");
+ printk(KERN_ERR "Not a DMA resource\n");
return -EINVAL;
}
ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
if (!mutex_trylock(&(ctrlr->mtx))) {
- printk("Resource busy, can't free\n");
+ printk(KERN_ERR "Resource busy, can't free\n");
return -EBUSY;
}
if (!(list_empty(&(ctrlr->pending)) && list_empty(&(ctrlr->running)))) {
- printk("Resource still processing transfers\n");
+ printk(KERN_WARNING "Resource still processing transfers\n");
mutex_unlock(&(ctrlr->mtx));
return -EBUSY;
}
@@ -991,7 +991,7 @@ void vme_irq_handler(struct vme_bridge *bridge, int level, int statid)
EXPORT_SYMBOL(vme_irq_handler);
int vme_irq_request(struct device *dev, int level, int statid,
- void (*callback)(int level, int vector, void *priv_data),
+ void (*callback)(int, int, void *),
void *priv_data)
{
struct vme_bridge *bridge;
@@ -1002,7 +1002,7 @@ int vme_irq_request(struct device *dev, int level, int statid,
return -EINVAL;
}
- if((level < 1) || (level > 7)) {
+ if ((level < 1) || (level > 7)) {
printk(KERN_ERR "Invalid interrupt level\n");
return -EINVAL;
}
@@ -1025,7 +1025,7 @@ int vme_irq_request(struct device *dev, int level, int statid,
bridge->irq[level - 1].callback[statid].func = callback;
/* Enable IRQ level */
- bridge->irq_set(level, 1, 1);
+ bridge->irq_set(bridge, level, 1, 1);
mutex_unlock(&(bridge->irq_mtx));
@@ -1043,7 +1043,7 @@ void vme_irq_free(struct device *dev, int level, int statid)
return;
}
- if((level < 1) || (level > 7)) {
+ if ((level < 1) || (level > 7)) {
printk(KERN_ERR "Invalid interrupt level\n");
return;
}
@@ -1059,7 +1059,7 @@ void vme_irq_free(struct device *dev, int level, int statid)
/* Disable IRQ level if no more interrupts attached at this level*/
if (bridge->irq[level - 1].count == 0)
- bridge->irq_set(level, 0, 1);
+ bridge->irq_set(bridge, level, 0, 1);
bridge->irq[level - 1].callback[statid].func = NULL;
bridge->irq[level - 1].callback[statid].priv_data = NULL;
@@ -1078,17 +1078,17 @@ int vme_irq_generate(struct device *dev, int level, int statid)
return -EINVAL;
}
- if((level < 1) || (level > 7)) {
+ if ((level < 1) || (level > 7)) {
printk(KERN_WARNING "Invalid interrupt level\n");
return -EINVAL;
}
if (bridge->irq_generate == NULL) {
- printk("Interrupt generation not supported\n");
+ printk(KERN_WARNING "Interrupt generation not supported\n");
return -EINVAL;
}
- return bridge->irq_generate(level, statid);
+ return bridge->irq_generate(bridge, level, statid);
}
EXPORT_SYMBOL(vme_irq_generate);
@@ -1189,8 +1189,6 @@ int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base,
return -EINVAL;
}
- /* XXX Check parameters */
-
return bridge->lm_set(lm, lm_base, aspace, cycle);
}
EXPORT_SYMBOL(vme_lm_set);
@@ -1297,11 +1295,11 @@ int vme_slot_get(struct device *bus)
}
if (bridge->slot_get == NULL) {
- printk("vme_slot_get not supported\n");
+ printk(KERN_WARNING "vme_slot_get not supported\n");
return -EINVAL;
}
- return bridge->slot_get();
+ return bridge->slot_get(bridge);
}
EXPORT_SYMBOL(vme_slot_get);
@@ -1331,7 +1329,7 @@ static void vme_free_bus_num(int bus)
mutex_unlock(&vme_bus_num_mtx);
}
-int vme_register_bridge (struct vme_bridge *bridge)
+int vme_register_bridge(struct vme_bridge *bridge)
{
struct device *dev;
int retval;
@@ -1358,7 +1356,7 @@ int vme_register_bridge (struct vme_bridge *bridge)
dev_set_name(dev, "vme-%x.%x", bridge->num, i + 1);
retval = device_register(dev);
- if(retval)
+ if (retval)
goto err_reg;
}
@@ -1375,7 +1373,7 @@ err_reg:
}
EXPORT_SYMBOL(vme_register_bridge);
-void vme_unregister_bridge (struct vme_bridge *bridge)
+void vme_unregister_bridge(struct vme_bridge *bridge)
{
int i;
struct device *dev;
@@ -1392,7 +1390,7 @@ EXPORT_SYMBOL(vme_unregister_bridge);
/* - Driver Registration --------------------------------------------------- */
-int vme_register_driver (struct vme_driver *drv)
+int vme_register_driver(struct vme_driver *drv)
{
drv->driver.name = drv->name;
drv->driver.bus = &vme_bus_type;
@@ -1401,7 +1399,7 @@ int vme_register_driver (struct vme_driver *drv)
}
EXPORT_SYMBOL(vme_register_driver);
-void vme_unregister_driver (struct vme_driver *drv)
+void vme_unregister_driver(struct vme_driver *drv)
{
driver_unregister(&drv->driver);
}
@@ -1418,10 +1416,10 @@ int vme_calc_slot(struct device *dev)
/* Determine slot number */
num = 0;
- while(num < VME_SLOTS_MAX) {
- if(&(bridge->dev[num]) == dev) {
+ while (num < VME_SLOTS_MAX) {
+ if (&(bridge->dev[num]) == dev)
break;
- }
+
num++;
}
if (num == VME_SLOTS_MAX) {
@@ -1437,8 +1435,8 @@ err_dev:
static struct vme_driver *dev_to_vme_driver(struct device *dev)
{
- if(dev->driver == NULL)
- printk("Bugger dev->driver is NULL\n");
+ if (dev->driver == NULL)
+ printk(KERN_ERR "Bugger dev->driver is NULL\n");
return container_of(dev->driver, struct vme_driver, driver);
}
@@ -1462,7 +1460,7 @@ static int vme_bus_match(struct device *dev, struct device_driver *drv)
}
i = 0;
- while((driver->bind_table[i].bus != 0) ||
+ while ((driver->bind_table[i].bus != 0) ||
(driver->bind_table[i].slot != 0)) {
if (bridge->num == driver->bind_table[i].bus) {
@@ -1493,9 +1491,8 @@ static int vme_bus_probe(struct device *dev)
driver = dev_to_vme_driver(dev);
bridge = dev_to_bridge(dev);
- if(driver->probe != NULL) {
+ if (driver->probe != NULL)
retval = driver->probe(dev, bridge->num, vme_calc_slot(dev));
- }
return retval;
}
@@ -1509,9 +1506,8 @@ static int vme_bus_remove(struct device *dev)
driver = dev_to_vme_driver(dev);
bridge = dev_to_bridge(dev);
- if(driver->remove != NULL) {
+ if (driver->remove != NULL)
retval = driver->remove(dev, bridge->num, vme_calc_slot(dev));
- }
return retval;
}
@@ -1524,18 +1520,18 @@ struct bus_type vme_bus_type = {
};
EXPORT_SYMBOL(vme_bus_type);
-static int __init vme_init (void)
+static int __init vme_init(void)
{
return bus_register(&vme_bus_type);
}
-static void __exit vme_exit (void)
+static void __exit vme_exit(void)
{
bus_unregister(&vme_bus_type);
}
MODULE_DESCRIPTION("VME bridge driver framework");
-MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com");
+MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
MODULE_LICENSE("GPL");
module_init(vme_init);
diff --git a/drivers/staging/vme/vme.h b/drivers/staging/vme/vme.h
index 97dc22e34caf..48768ca97e16 100644
--- a/drivers/staging/vme/vme.h
+++ b/drivers/staging/vme/vme.h
@@ -68,6 +68,14 @@ typedef u32 vme_pattern_t;
#define VME_DMA_PATTERN_WORD (1<<1)
#define VME_DMA_PATTERN_INCREMENT (1<<2)
+typedef u32 vme_dma_route_t;
+#define VME_DMA_VME_TO_MEM (1<<0)
+#define VME_DMA_MEM_TO_VME (1<<1)
+#define VME_DMA_VME_TO_VME (1<<2)
+#define VME_DMA_MEM_TO_MEM (1<<3)
+#define VME_DMA_PATTERN_TO_VME (1<<4)
+#define VME_DMA_PATTERN_TO_MEM (1<<5)
+
struct vme_dma_attr {
vme_dma_t type;
void *private;
@@ -98,32 +106,33 @@ struct vme_driver {
struct device_driver driver;
};
-void * vme_alloc_consistent(struct vme_resource *, size_t, dma_addr_t *);
+void *vme_alloc_consistent(struct vme_resource *, size_t, dma_addr_t *);
void vme_free_consistent(struct vme_resource *, size_t, void *,
dma_addr_t);
size_t vme_get_size(struct vme_resource *);
-struct vme_resource * vme_slave_request(struct device *, vme_address_t, vme_cycle_t);
-int vme_slave_set (struct vme_resource *, int, unsigned long long,
+struct vme_resource *vme_slave_request(struct device *, vme_address_t,
+ vme_cycle_t);
+int vme_slave_set(struct vme_resource *, int, unsigned long long,
unsigned long long, dma_addr_t, vme_address_t, vme_cycle_t);
-int vme_slave_get (struct vme_resource *, int *, unsigned long long *,
+int vme_slave_get(struct vme_resource *, int *, unsigned long long *,
unsigned long long *, dma_addr_t *, vme_address_t *, vme_cycle_t *);
void vme_slave_free(struct vme_resource *);
-struct vme_resource * vme_master_request(struct device *, vme_address_t, vme_cycle_t,
- vme_width_t);
-int vme_master_set (struct vme_resource *, int, unsigned long long,
+struct vme_resource *vme_master_request(struct device *, vme_address_t,
+ vme_cycle_t, vme_width_t);
+int vme_master_set(struct vme_resource *, int, unsigned long long,
unsigned long long, vme_address_t, vme_cycle_t, vme_width_t);
-int vme_master_get (struct vme_resource *, int *, unsigned long long *,
+int vme_master_get(struct vme_resource *, int *, unsigned long long *,
unsigned long long *, vme_address_t *, vme_cycle_t *, vme_width_t *);
ssize_t vme_master_read(struct vme_resource *, void *, size_t, loff_t);
ssize_t vme_master_write(struct vme_resource *, void *, size_t, loff_t);
-unsigned int vme_master_rmw (struct vme_resource *, unsigned int, unsigned int,
+unsigned int vme_master_rmw(struct vme_resource *, unsigned int, unsigned int,
unsigned int, loff_t);
void vme_master_free(struct vme_resource *);
-struct vme_resource *vme_dma_request(struct device *);
+struct vme_resource *vme_dma_request(struct device *, vme_dma_route_t);
struct vme_dma_list *vme_new_dma_list(struct vme_resource *);
struct vme_dma_attr *vme_dma_pattern_attribute(u32, vme_pattern_t);
struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t);
@@ -153,8 +162,8 @@ void vme_lm_free(struct vme_resource *);
int vme_slot_get(struct device *);
-int vme_register_driver (struct vme_driver *);
-void vme_unregister_driver (struct vme_driver *);
+int vme_register_driver(struct vme_driver *);
+void vme_unregister_driver(struct vme_driver *);
#endif /* _VME_H_ */
diff --git a/drivers/staging/vme/vme_api.txt b/drivers/staging/vme/vme_api.txt
index a5c1b1cd5fcc..a910a0c4388b 100644
--- a/drivers/staging/vme/vme_api.txt
+++ b/drivers/staging/vme/vme_api.txt
@@ -77,16 +77,21 @@ driver in question:
struct vme_resource * vme_slave_request(struct device *dev,
vme_address_t aspace, vme_cycle_t cycle);
- struct vme_resource *vme_dma_request(struct device *dev);
+ struct vme_resource *vme_dma_request(struct device *dev,
+ vme_dma_route_t route);
For slave windows these attributes are split into those of type 'vme_address_t'
-and 'vme_cycle_t'. Master windows add a further set of attributes 'vme_cycle_t'.
-These attributes are defined as bitmasks and as such any combination of the
-attributes can be requested for a single window, the core will assign a window
-that meets the requirements, returning a pointer of type vme_resource that
-should be used to identify the allocated resource when it is used. If an
-unallocated window fitting the requirements can not be found a NULL pointer will
-be returned.
+and 'vme_cycle_t'. Master windows add a further set of attributes
+'vme_cycle_t'. These attributes are defined as bitmasks and as such any
+combination of the attributes can be requested for a single window, the core
+will assign a window that meets the requirements, returning a pointer of type
+vme_resource that should be used to identify the allocated resource when it is
+used. For DMA controllers, the request function requires the potential
+direction of any transfers to be provided in the route attributes. This is
+typically VME-to-MEM and/or MEM-to-VME, though some hardware can support
+VME-to-VME and MEM-to-MEM transfers as well as test pattern generation. If an
+unallocated window fitting the requirements can not be found a NULL pointer
+will be returned.
Functions are also provided to free window allocations once they are no longer
required. These functions should be passed the pointer to the resource provided
@@ -237,6 +242,12 @@ covered under "Transfer Attributes"):
struct vme_dma_attr *src, struct vme_dma_attr *dest,
size_t count);
+NOTE: The detailed attributes of the transfers source and destination
+ are not checked until an entry is added to a DMA list, the request
+ for a DMA channel purely checks the directions in which the
+ controller is expected to transfer data. As a result it is
+ possible for this call to return an error, for example if the
+ source or destination is in an unsupported VME address space.
Transfer Attributes
-------------------
diff --git a/drivers/staging/vme/vme_bridge.h b/drivers/staging/vme/vme_bridge.h
index 851fa92559f6..b653ec02e1fc 100644
--- a/drivers/staging/vme/vme_bridge.h
+++ b/drivers/staging/vme/vme_bridge.h
@@ -19,7 +19,7 @@ struct vme_master_resource {
vme_address_t address_attr;
vme_cycle_t cycle_attr;
vme_width_t width_attr;
- struct resource pci_resource; /* XXX Rename to be bus agnostic */
+ struct resource bus_resource;
void *kern_base;
};
@@ -64,6 +64,7 @@ struct vme_dma_resource {
int number;
struct list_head pending;
struct list_head running;
+ vme_dma_route_t route_attr;
};
struct vme_lm_resource {
@@ -101,7 +102,7 @@ struct vme_irq {
* Currently we assume that all chips are PCI-based
*/
struct vme_bridge {
- char name[VMENAMSIZ];
+ char name[VMENAMSIZ];
int num;
struct list_head master_resources;
struct list_head slave_resources;
@@ -112,7 +113,7 @@ struct vme_bridge {
/* Bridge Info - XXX Move to private structure? */
struct device *parent; /* Generic device struct (pdev->dev for PCI) */
- void * base; /* Base Address of device registers */
+ void *driver_priv; /* Private pointer for the bridge driver */
struct device dev[VME_SLOTS_MAX]; /* Device registered with
* device model on VME bus
@@ -151,8 +152,8 @@ struct vme_bridge {
int (*dma_list_empty) (struct vme_dma_list *);
/* Interrupt Functions */
- void (*irq_set) (int, int, int);
- int (*irq_generate) (int, int);
+ void (*irq_set) (struct vme_bridge *, int, int, int);
+ int (*irq_generate) (struct vme_bridge *, int, int);
/* Location monitor functions */
int (*lm_set) (struct vme_lm_resource *, unsigned long long,
@@ -163,102 +164,12 @@ struct vme_bridge {
int (*lm_detach) (struct vme_lm_resource *, int);
/* CR/CSR space functions */
- int (*slot_get) (void);
- /* Use standard master read and write functions to access CR/CSR */
-
-#if 0
- int (*set_prefetch) (void);
- int (*get_prefetch) (void);
- int (*set_arbiter) (void);
- int (*get_arbiter) (void);
- int (*set_requestor) (void);
- int (*get_requestor) (void);
-#endif
+ int (*slot_get) (struct vme_bridge *);
};
void vme_irq_handler(struct vme_bridge *, int, int);
-int vme_register_bridge (struct vme_bridge *);
-void vme_unregister_bridge (struct vme_bridge *);
+int vme_register_bridge(struct vme_bridge *);
+void vme_unregister_bridge(struct vme_bridge *);
#endif /* _VME_BRIDGE_H_ */
-
-#if 0
-/*
- * VMEbus GET INFO Arg Structure
- */
-struct vmeInfoCfg {
- int vmeSlotNum; /* VME slot number of interest */
- int boardResponded; /* Board responded */
- char sysConFlag; /* System controller flag */
- int vmeControllerID; /* Vendor/device ID of VME bridge */
- int vmeControllerRev; /* Revision of VME bridge */
- char osName[8]; /* Name of OS e.g. "Linux" */
- int vmeSharedDataValid; /* Validity of data struct */
- int vmeDriverRev; /* Revision of VME driver */
- unsigned int vmeAddrHi[8]; /* Address on VME bus */
- unsigned int vmeAddrLo[8]; /* Address on VME bus */
- unsigned int vmeSize[8]; /* Size on VME bus */
- unsigned int vmeAm[8]; /* Address modifier on VME bus */
- int reserved; /* For future use */
-};
-typedef struct vmeInfoCfg vmeInfoCfg_t;
-
-/*
- * VMEbus Requester Arg Structure
- */
-struct vmeRequesterCfg {
- int requestLevel; /* Requester Bus Request Level */
- char fairMode; /* Requester Fairness Mode Indicator */
- int releaseMode; /* Requester Bus Release Mode */
- int timeonTimeoutTimer; /* Master Time-on Time-out Timer */
- int timeoffTimeoutTimer; /* Master Time-off Time-out Timer */
- int reserved; /* For future use */
-};
-typedef struct vmeRequesterCfg vmeRequesterCfg_t;
-
-/*
- * VMEbus Arbiter Arg Structure
- */
-struct vmeArbiterCfg {
- vme_arbitration_t arbiterMode; /* Arbitration Scheduling Algorithm */
- char arbiterTimeoutFlag; /* Arbiter Time-out Timer Indicator */
- int globalTimeoutTimer; /* VMEbus Global Time-out Timer */
- char noEarlyReleaseFlag; /* No Early Release on BBUSY */
- int reserved; /* For future use */
-};
-typedef struct vmeArbiterCfg vmeArbiterCfg_t;
-
-
-/*
- * VMEbus RMW Configuration Data
- */
-struct vmeRmwCfg {
- unsigned int targetAddrU; /* VME Address (Upper) to trigger RMW cycle */
- unsigned int targetAddr; /* VME Address (Lower) to trigger RMW cycle */
- vme_address_t addrSpace; /* VME Address Space */
- int enableMask; /* Bit mask defining the bits of interest */
- int compareData; /* Data to be compared with the data read */
- int swapData; /* Data written to the VMEbus on success */
- int maxAttempts; /* Maximum times to try */
- int numAttempts; /* Number of attempts before success */
- int reserved; /* For future use */
-
-};
-typedef struct vmeRmwCfg vmeRmwCfg_t;
-
-/*
- * VMEbus Location Monitor Arg Structure
- */
-struct vmeLmCfg {
- unsigned int addrU; /* Location Monitor Address upper */
- unsigned int addr; /* Location Monitor Address lower */
- vme_address_t addrSpace; /* Address Space */
- int userAccessType; /* User/Supervisor Access Type */
- int dataAccessType; /* Data/Program Access Type */
- int lmWait; /* Time to wait for access */
- int lmEvents; /* Lm event mask */
- int reserved; /* For future use */
-};
-typedef struct vmeLmCfg vmeLmCfg_t;
-#endif
diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c
index db786142717f..bf4fd49709df 100644
--- a/drivers/staging/vt6655/card.c
+++ b/drivers/staging/vt6655/card.c
@@ -2788,16 +2788,18 @@ void CARDvUpdateBasicTopRate (PVOID pDeviceHandler)
//Determines the highest basic rate.
for (ii = RATE_54M; ii >= RATE_6M; ii --) {
- if ( (pDevice->wBasicRate) & ((WORD)(1<<ii)) )
+ if ( (pDevice->wBasicRate) & ((WORD)(1<<ii)) ) {
byTopOFDM = ii;
break;
+ }
}
pDevice->byTopOFDMBasicRate = byTopOFDM;
for (ii = RATE_11M;; ii --) {
- if ( (pDevice->wBasicRate) & ((WORD)(1<<ii)) )
+ if ( (pDevice->wBasicRate) & ((WORD)(1<<ii)) ) {
byTopCCK = ii;
break;
+ }
if (ii == RATE_1M)
break;
}
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index 0db8d7b6e79c..1d643653a7ed 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -1105,10 +1105,7 @@ static void device_print_info(PSDevice pDevice)
struct net_device* dev=pDevice->dev;
DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: %s\n",dev->name, get_chip_name(pDevice->chip_id));
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: MAC=%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
- dev->name,
- dev->dev_addr[0],dev->dev_addr[1],dev->dev_addr[2],
- dev->dev_addr[3],dev->dev_addr[4],dev->dev_addr[5]);
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: MAC=%pM", dev->name, dev->dev_addr);
#ifdef IO_MAP
DBG_PRT(MSG_LEVEL_INFO, KERN_INFO" IO=0x%lx ",(ULONG) pDevice->ioaddr);
DBG_PRT(MSG_LEVEL_INFO, KERN_INFO" IRQ=%d \n", pDevice->dev->irq);
@@ -3082,8 +3079,7 @@ static void device_set_multi(struct net_device *dev) {
PSMgmtObject pMgmt = pDevice->pMgmt;
u32 mc_filter[2];
- int i;
- struct dev_mc_list *mclist;
+ struct dev_mc_list *mclist;
VNSvInPortB(pDevice->PortOffset + MAC_REG_RCR, &(pDevice->byRxMode));
@@ -3093,7 +3089,7 @@ static void device_set_multi(struct net_device *dev) {
/* Unconditionally log net taps. */
pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST|RCR_UNICAST);
}
- else if ((dev->mc_count > pDevice->multicast_limit)
+ else if ((netdev_mc_count(dev) > pDevice->multicast_limit)
|| (dev->flags & IFF_ALLMULTI)) {
MACvSelectPage1(pDevice->PortOffset);
VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, 0xffffffff);
@@ -3103,8 +3099,7 @@ static void device_set_multi(struct net_device *dev) {
}
else {
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
}
diff --git a/drivers/staging/vt6655/iwctl.c b/drivers/staging/vt6655/iwctl.c
index 108830ff3b32..78b49830a255 100644
--- a/drivers/staging/vt6655/iwctl.c
+++ b/drivers/staging/vt6655/iwctl.c
@@ -1472,7 +1472,7 @@ if((wrq->flags & IW_ENCODE_DISABLED)==0){
if ( index < 4 ) {
pDevice->byKeyIndex = index;
}
- else if(!wrq->flags & IW_ENCODE_MODE) {
+ else if(!(wrq->flags & IW_ENCODE_MODE)) {
rc = -EINVAL;
return rc;
}
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index ef17c4958c67..a8e1adbc9592 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -1596,7 +1596,7 @@ static void device_set_multi(struct net_device *dev) {
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
u32 mc_filter[2];
int ii;
- struct dev_mc_list *mclist;
+ struct dev_mc_list *mclist;
BYTE pbyData[8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
BYTE byTmpMode = 0;
int rc;
@@ -1619,7 +1619,8 @@ static void device_set_multi(struct net_device *dev) {
// Unconditionally log net taps.
pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST|RCR_UNICAST);
}
- else if ((dev->mc_count > pDevice->multicast_limit) || (dev->flags & IFF_ALLMULTI)) {
+ else if ((netdev_mc_count(dev) > pDevice->multicast_limit) ||
+ (dev->flags & IFF_ALLMULTI)) {
CONTROLnsRequestOut(pDevice,
MESSAGE_TYPE_WRITE,
MAC_REG_MAR0,
@@ -1631,8 +1632,7 @@ static void device_set_multi(struct net_device *dev) {
}
else {
memset(mc_filter, 0, sizeof(mc_filter));
- for (ii = 0, mclist = dev->mc_list; mclist && ii < dev->mc_count;
- ii++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
}
diff --git a/drivers/staging/wavelan/wavelan.c b/drivers/staging/wavelan/wavelan.c
index d634b2da3b84..54ca63196fdd 100644
--- a/drivers/staging/wavelan/wavelan.c
+++ b/drivers/staging/wavelan/wavelan.c
@@ -1367,7 +1367,7 @@ static void wavelan_set_multicast_list(struct net_device * dev)
#ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG
"%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n",
- dev->name, dev->flags, dev->mc_count);
+ dev->name, dev->flags, netdev_mc_count(dev));
#endif
/* Are we asking for promiscuous mode,
@@ -1375,7 +1375,7 @@ static void wavelan_set_multicast_list(struct net_device * dev)
* or too many multicast addresses for the hardware filter? */
if ((dev->flags & IFF_PROMISC) ||
(dev->flags & IFF_ALLMULTI) ||
- (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) {
+ (netdev_mc_count(dev) > I82586_MAX_MULTICAST_ADDRESSES)) {
/*
* Enable promiscuous mode: receive all packets.
*/
@@ -1387,17 +1387,17 @@ static void wavelan_set_multicast_list(struct net_device * dev)
}
} else
/* Are there multicast addresses to send? */
- if (dev->mc_list != (struct dev_mc_list *) NULL) {
+ if (!netdev_mc_empty(dev)) {
/*
* Disable promiscuous mode, but receive all packets
* in multicast list
*/
#ifdef MULTICAST_AVOID
- if (lp->promiscuous || (dev->mc_count != lp->mc_count))
+ if (lp->promiscuous || (netdev_mc_count(dev) != lp->mc_count))
#endif
{
lp->promiscuous = 0;
- lp->mc_count = dev->mc_count;
+ lp->mc_count = netdev_mc_count(dev);
wv_82586_reconfig(dev);
}
@@ -3531,7 +3531,7 @@ static void wv_82586_config(struct net_device * dev)
/* Any address to set? */
if (lp->mc_count) {
- for (dmi = dev->mc_list; dmi; dmi = dmi->next)
+ netdev_for_each_mc_addr(dmi, dev)
outsw(PIOP1(ioaddr), (u16 *) dmi->dmi_addr,
WAVELAN_ADDR_SIZE >> 1);
@@ -3539,7 +3539,7 @@ static void wv_82586_config(struct net_device * dev)
printk(KERN_DEBUG
"%s: wv_82586_config(): set %d multicast addresses:\n",
dev->name, lp->mc_count);
- for (dmi = dev->mc_list; dmi; dmi = dmi->next)
+ netdev_for_each_mc_addr(dmi, dev)
printk(KERN_DEBUG " %pM\n", dmi->dmi_addr);
#endif
}
diff --git a/drivers/staging/wavelan/wavelan_cs.c b/drivers/staging/wavelan/wavelan_cs.c
index 10c702b5be4a..04f691d127b4 100644
--- a/drivers/staging/wavelan/wavelan_cs.c
+++ b/drivers/staging/wavelan/wavelan_cs.c
@@ -1373,7 +1373,7 @@ wavelan_set_multicast_list(struct net_device * dev)
#ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n",
- dev->name, dev->flags, dev->mc_count);
+ dev->name, dev->flags, netdev_mc_count(dev));
#endif
if(dev->flags & IFF_PROMISC)
@@ -1394,7 +1394,7 @@ wavelan_set_multicast_list(struct net_device * dev)
/* If all multicast addresses
* or too much multicast addresses for the hardware filter */
if((dev->flags & IFF_ALLMULTI) ||
- (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES))
+ (netdev_mc_count(dev) > I82593_MAX_MULTICAST_ADDRESSES))
{
/*
* Disable promiscuous mode, but active the all multicast mode
@@ -1410,20 +1410,19 @@ wavelan_set_multicast_list(struct net_device * dev)
}
else
/* If there is some multicast addresses to send */
- if(dev->mc_list != (struct dev_mc_list *) NULL)
- {
+ if (!netdev_mc_empty(dev)) {
/*
* Disable promiscuous mode, but receive all packets
* in multicast list
*/
#ifdef MULTICAST_AVOID
if(lp->promiscuous || lp->allmulticast ||
- (dev->mc_count != lp->mc_count))
+ (netdev_mc_count(dev) != lp->mc_count))
#endif
{
lp->promiscuous = 0;
lp->allmulticast = 0;
- lp->mc_count = dev->mc_count;
+ lp->mc_count = netdev_mc_count(dev);
wv_82593_reconfig(dev);
}
@@ -3598,13 +3597,13 @@ wv_82593_config(struct net_device * dev)
/* If any multicast address to set */
if(lp->mc_count)
{
- struct dev_mc_list * dmi;
+ struct dev_mc_list *dmi;
int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count;
#ifdef DEBUG_CONFIG_INFO
printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n",
dev->name, lp->mc_count);
- for(dmi=dev->mc_list; dmi; dmi=dmi->next)
+ netdev_for_each_mc_addr(dmi, dev)
printk(KERN_DEBUG " %pM\n", dmi->dmi_addr);
#endif
@@ -3613,7 +3612,7 @@ wv_82593_config(struct net_device * dev)
outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
outb(addrs_len & 0xff, PIOP(base)); /* byte count lsb */
outb((addrs_len >> 8), PIOP(base)); /* byte count msb */
- for(dmi=dev->mc_list; dmi; dmi=dmi->next)
+ netdev_for_each_mc_addr(dmi, dev)
outsb(PIOP(base), dmi->dmi_addr, dmi->dmi_addrlen);
/* reset transmit DMA pointer */
@@ -3622,7 +3621,8 @@ wv_82593_config(struct net_device * dev)
if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup",
OP0_MC_SETUP, SR0_MC_SETUP_DONE))
ret = FALSE;
- lp->mc_count = dev->mc_count; /* remember to avoid repeated reset */
+ /* remember to avoid repeated reset */
+ lp->mc_count = netdev_mc_count(dev);
}
/* Job done, clear the flag */
diff --git a/drivers/staging/winbond/core.h b/drivers/staging/winbond/core.h
index 7d4bd5e8f69b..0a2060bf4f94 100644
--- a/drivers/staging/winbond/core.h
+++ b/drivers/staging/winbond/core.h
@@ -14,7 +14,7 @@
struct wbsoft_priv {
u32 adapterIndex; // 20060703.4 Add for using padapterContext global adapter point
- WB_LOCALDESCRIPT sLocalPara; // Myself connected parameters
+ struct wb_local_para sLocalPara; // Myself connected parameters
MLME_FRAME sMlmeFrame; // connect to peerSTA parameters
diff --git a/drivers/staging/winbond/localpara.h b/drivers/staging/winbond/localpara.h
index 5626a76d69a4..fcf6a0442dc2 100644
--- a/drivers/staging/winbond/localpara.h
+++ b/drivers/staging/winbond/localpara.h
@@ -110,33 +110,20 @@
// 20061108 WPS IE buffer
#define MAX_IE_APPEND_SIZE 256 + 4 // Due to [E id][Length][OUI][Data] may 257 bytes
-typedef struct _EVENTLOG
-{
- u16 Count; //Total count from start
- u16 index; //Buffer index, 0 ~ 63
- u32 EventValue[64]; //BYTE 3~2 : count, BYTE 1 : Event, BYTE 0 : reason
-} Event_Log, *pEvent_Log;
-
-typedef struct _ChanInfo
+struct chan_info
{
u8 band;
u8 ChanNo;
-} ChanInfo, *pChanInfo;
+};
-typedef struct _CHAN_LIST
-{
- u16 Count;
- ChanInfo Channel[50]; // 100B
-} CHAN_LIST, *psCHAN_LIST;
-
-typedef struct _RadioOff
+struct radio_off
{
u8 boHwRadioOff;
u8 boSwRadioOff;
-} RadioOff, *psRadioOff;
+};
//===========================================================================
-typedef struct LOCAL_PARA
+struct wb_local_para
{
u8 PermanentAddress[ MAC_ADDR_LENGTH + 2 ]; // read from EPROM, manufacture set for each NetCard
u8 ThisMacAddress[ MAC_ADDR_LENGTH + 2 ]; // the driver will use actually.
@@ -186,7 +173,7 @@ typedef struct LOCAL_PARA
u16 ListenInterval; // The listen interval when SME invoking MLME_
// (Re)Associate_Request().
- RadioOff RadioOffStatus;
+ struct radio_off RadioOffStatus;
u8 Reserved0[2];
u8 boMsRadioOff; // Ndis demands to be true when set Disassoc. OID and be false when set SSID OID.
@@ -196,7 +183,7 @@ typedef struct LOCAL_PARA
u8 RoamStatus;
u8 reserved7[3];
- ChanInfo CurrentChan; //Current channel no. and channel band. It may be changed by scanning.
+ struct chan_info CurrentChan; //Current channel no. and channel band. It may be changed by scanning.
u8 boHandover; // Roaming, Hnadover to other AP.
u8 boCCAbusy;
@@ -253,19 +240,16 @@ typedef struct LOCAL_PARA
u32 _dot11WEPUndecryptableCount;
u32 _dot11FrameDuplicateCount;
- ChanInfo IbssChanSetting; // 2B. Start IBSS Channel setting by registry or WWU.
+ struct chan_info IbssChanSetting; // 2B. Start IBSS Channel setting by registry or WWU.
u8 reserved_5[2]; //It may not be used after considering RF type,
//region and modulation type.
- CHAN_LIST sSupportChanList; // 86B. It will be obtained according to RF type and region
u8 reserved_6[2]; //two variables are for wep key error detection added by ws 02/02/04
u32 bWepKeyError;
u32 bToSelfPacketReceived;
u32 WepKeyDetectTimerCount;
- Event_Log EventLog;
-
u16 SignalLostTh;
u16 SignalRoamTh;
@@ -274,6 +258,6 @@ typedef struct LOCAL_PARA
u16 IE_Append_size;
u16 reserved_7;
-} WB_LOCALDESCRIPT, *PWB_LOCALDESCRIPT;
+};
#endif
diff --git a/drivers/staging/winbond/mds_f.h b/drivers/staging/winbond/mds_f.h
index ab1ea535f7db..e09dd4b879d4 100644
--- a/drivers/staging/winbond/mds_f.h
+++ b/drivers/staging/winbond/mds_f.h
@@ -11,9 +11,6 @@ void Mds_SendComplete( struct wbsoft_priv *adapter, PT02_DESCRIPTOR pT02 );
void Mds_MpduProcess( struct wbsoft_priv *adapter, struct wb35_descriptor *pRxDes );
extern void DataDmp(u8 *pdata, u32 len, u32 offset);
-// For Asynchronous indicating. The routine collocates with USB.
-void Mds_MsduProcess( struct wbsoft_priv *adapter, PRXLAYER1 pRxLayer1, u8 SlotIndex);
-
// For data frame sending 20060802
u16 MDS_GetPacketSize( struct wbsoft_priv *adapter );
void MDS_GetNextPacket( struct wbsoft_priv *adapter, struct wb35_descriptor *pDes );
diff --git a/drivers/staging/winbond/mds_s.h b/drivers/staging/winbond/mds_s.h
index e8e13bde4744..217ff0819a93 100644
--- a/drivers/staging/winbond/mds_s.h
+++ b/drivers/staging/winbond/mds_s.h
@@ -133,32 +133,4 @@ struct wb35_mds {
};
-//
-// Reveive Layer 1 Format.
-//----------------------------
-typedef struct _RXLAYER1
-{
- u16 SequenceNumber; // The sequence number of the last received packet.
- u16 BufferTotalSize;
-
- u32 InUsed;
- u32 DecryptionMethod; // The desired defragment number of the next incoming packet.
-
- u8 DeFragmentNumber;
- u8 FrameType;
- u8 TypeEncapsulated;
- u8 BufferNumber;
-
- u32 FirstFrameArrivedTime;
-
- u8 LastFrameType; // 20061004 for fix intel 3945 's bug
- u8 RESERVED[3]; //@@ anson
-
- /////////////////////////////////////////////////////////////////////////////////////////////
- // For brand-new Rx system
- u8 ReservedBuffer[ 2400 ];//If Buffer ID is reserved one, it must copy the data into this area
- u8 *ReservedBufferPoint;// Point to the next availabe address of reserved buffer
-
-}RXLAYER1, * PRXLAYER1;
-
#endif
diff --git a/drivers/staging/winbond/mlme_s.h b/drivers/staging/winbond/mlme_s.h
index ea12684a2b1d..1217a1c025e5 100644
--- a/drivers/staging/winbond/mlme_s.h
+++ b/drivers/staging/winbond/mlme_s.h
@@ -165,14 +165,6 @@ typedef struct _AUTHREQ {
} MLME_AUTHREQ_PARA, *psMLME_AUTHREQ_PARA;
-struct _Reason_Code {
-
- u8 peerMACaddr[MAC_ADDR_LENGTH];
- u16 wReasonCode;
-};
-typedef struct _Reason_Code MLME_DEAUTHREQ_PARA, *psMLME_DEAUTHREQ_PARA;
-typedef struct _Reason_Code MLME_DISASSOCREQ_PARA, *psMLME_DISASSOCREQ_PARA;
-
typedef struct _ASSOCREQ {
u8 PeerSTAAddr[MAC_ADDR_LENGTH];
u16 CapabilityInfo;
diff --git a/drivers/staging/winbond/mto.h b/drivers/staging/winbond/mto.h
index 4fe24b0f2791..fb4781d5781b 100644
--- a/drivers/staging/winbond/mto.h
+++ b/drivers/staging/winbond/mto.h
@@ -141,11 +141,6 @@ extern u16 MTO_Frag_Th_Tbl[];
#define MTO_DATA_RATE() MTO_Data_Rate_Tbl[MTO_RATE_LEVEL()]
#define MTO_FRAG_TH() MTO_Frag_Th_Tbl[MTO_FRAG_TH_LEVEL()]
-typedef struct {
- u8 tx_rate;
- u8 tx_retry_rate;
-} TXRETRY_REC;
-
extern void MTO_Init(struct wbsoft_priv *);
extern void MTO_PeriodicTimerExpired(struct wbsoft_priv *);
extern void MTO_SetDTORateRange(struct wbsoft_priv *, u8 *, u8);
diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c
index d915cbdd38ed..5f5048af26a5 100644
--- a/drivers/staging/winbond/reg.c
+++ b/drivers/staging/winbond/reg.c
@@ -1823,12 +1823,12 @@ BBProcessor_initial( struct hw_data * pHwData )
reg->SQ3_filter[i] = 0x2f; // half of Bit 0 ~ 6
}
-void set_tx_power_per_channel_max2829( struct hw_data * pHwData, ChanInfo Channel)
+void set_tx_power_per_channel_max2829( struct hw_data * pHwData, struct chan_info Channel)
{
RFSynthesizer_SetPowerIndex( pHwData, 100 ); // 20060620.1 Modify
}
-void set_tx_power_per_channel_al2230( struct hw_data * pHwData, ChanInfo Channel )
+void set_tx_power_per_channel_al2230( struct hw_data * pHwData, struct chan_info Channel )
{
u8 index = 100;
@@ -1838,7 +1838,7 @@ void set_tx_power_per_channel_al2230( struct hw_data * pHwData, ChanInfo Chann
RFSynthesizer_SetPowerIndex( pHwData, index );
}
-void set_tx_power_per_channel_al7230( struct hw_data * pHwData, ChanInfo Channel)
+void set_tx_power_per_channel_al7230( struct hw_data * pHwData, struct chan_info Channel)
{
u8 i, index = 100;
@@ -1868,7 +1868,7 @@ void set_tx_power_per_channel_al7230( struct hw_data * pHwData, ChanInfo Chann
RFSynthesizer_SetPowerIndex( pHwData, index );
}
-void set_tx_power_per_channel_wb242( struct hw_data * pHwData, ChanInfo Channel)
+void set_tx_power_per_channel_wb242( struct hw_data * pHwData, struct chan_info Channel)
{
u8 index = 100;
@@ -1901,7 +1901,7 @@ void set_tx_power_per_channel_wb242( struct hw_data * pHwData, ChanInfo Channe
// None.
//=============================================================================================================
void
-RFSynthesizer_SwitchingChannel( struct hw_data * pHwData, ChanInfo Channel )
+RFSynthesizer_SwitchingChannel( struct hw_data * pHwData, struct chan_info Channel )
{
struct wb35_reg *reg = &pHwData->reg;
u32 pltmp[16]; // The 16 is the maximum capability of hardware
diff --git a/drivers/staging/winbond/scan_s.h b/drivers/staging/winbond/scan_s.h
index 775bb81f23cc..209717f5d47d 100644
--- a/drivers/staging/winbond/scan_s.h
+++ b/drivers/staging/winbond/scan_s.h
@@ -35,7 +35,6 @@ typedef struct _SCAN_REQ_PARA //mandatory parameters for SCAN request
{
u32 ScanType; //passive/active scan
- CHAN_LIST sChannelList; // 86B
u8 reserved_1[2];
struct SSID_Element sSSID; // 34B. scan only for this SSID
diff --git a/drivers/staging/winbond/sme_api.h b/drivers/staging/winbond/sme_api.h
index 549878302288..b5898294eb8a 100644
--- a/drivers/staging/winbond/sme_api.h
+++ b/drivers/staging/winbond/sme_api.h
@@ -193,8 +193,6 @@ s8 sme_get_cwmin_value(void *pcore_data, u8 *cwmin);
s8 sme_get_cwmax_value(void *pcore_data, u16 *cwmax);
s8 sme_get_ms_radio_mode(void *pcore_data, u8 * pMsRadioOff);
s8 sme_set_ms_radio_mode(void *pcore_data, u8 boMsRadioOff);
-s8 sme_get_radio_mode(void *pcore_data, psRadioOff pRadioOffData);
-s8 sme_set_radio_mode(void *pcore_data, RadioOff RadioOffData);
void sme_get_tx_power_level(void *pcore_data, u32 *TxPower);
u8 sme_set_tx_power_level(void *pcore_data, u32 TxPower);
@@ -203,7 +201,7 @@ void sme_get_rx_antenna(void *pcore_data, u32 *RxAntenna);
u8 sme_set_rx_antenna(void *pcore_data, u32 RxAntenna);
void sme_get_tx_antenna(void *pcore_data, u32 *TxAntenna);
s8 sme_set_tx_antenna(void *pcore_data, u32 TxAntenna);
-s8 sme_set_IBSS_chan(void *pcore_data, ChanInfo chan);
+s8 sme_set_IBSS_chan(void *pcore_data, struct chan_info chan);
//20061108 WPS
s8 sme_set_IE_append(void *pcore_data, u8 *buffer, u16 buf_len);
diff --git a/drivers/staging/winbond/wb35reg_f.h b/drivers/staging/winbond/wb35reg_f.h
index 30f5b5ad63ad..d352bce5c171 100644
--- a/drivers/staging/winbond/wb35reg_f.h
+++ b/drivers/staging/winbond/wb35reg_f.h
@@ -14,7 +14,7 @@ void Dxx_initial( struct hw_data * pHwData );
void Mxx_initial( struct hw_data * pHwData );
void RFSynthesizer_initial( struct hw_data * pHwData );
//void RFSynthesizer_SwitchingChannel( struct hw_data * pHwData, s8 Channel );
-void RFSynthesizer_SwitchingChannel( struct hw_data * pHwData, ChanInfo Channel );
+void RFSynthesizer_SwitchingChannel( struct hw_data * pHwData, struct chan_info Channel );
void BBProcessor_initial( struct hw_data * pHwData );
void BBProcessor_RateChanging( struct hw_data * pHwData, u8 rate ); // 20060613.1
//void RF_RateChanging( struct hw_data * pHwData, u8 rate ); // 20060626.5.c Add
diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c
index 067082a7d759..3482eec18651 100644
--- a/drivers/staging/winbond/wbusb.c
+++ b/drivers/staging/winbond/wbusb.c
@@ -23,7 +23,7 @@ MODULE_DESCRIPTION("IS89C35 802.11bg WLAN USB Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
-static struct usb_device_id wb35_table[] __devinitdata = {
+static const struct usb_device_id wb35_table[] __devinitconst = {
{ USB_DEVICE(0x0416, 0x0035) },
{ USB_DEVICE(0x18E8, 0x6201) },
{ USB_DEVICE(0x18E8, 0x6206) },
@@ -65,17 +65,17 @@ static void hal_set_beacon_period(struct hw_data *pHwData, u16 beacon_period)
}
static int wbsoft_add_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
struct wbsoft_priv *priv = dev->priv;
- hal_set_beacon_period(&priv->sHwData, conf->vif->bss_conf.beacon_int);
+ hal_set_beacon_period(&priv->sHwData, vif->bss_conf.beacon_int);
return 0;
}
static void wbsoft_remove_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
+ struct ieee80211_vif *vif)
{
printk("wbsoft_remove interface called\n");
}
@@ -92,13 +92,6 @@ static int wbsoft_get_stats(struct ieee80211_hw *hw,
return 0;
}
-static int wbsoft_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *stats)
-{
- printk(KERN_INFO "%s called\n", __func__);
- return 0;
-}
-
static u64 wbsoft_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
struct dev_addr_list *mc_list)
{
@@ -161,7 +154,7 @@ static void hal_set_radio_mode(struct hw_data *pHwData, unsigned char radio_off)
}
static void
-hal_set_current_channel_ex(struct hw_data *pHwData, ChanInfo channel)
+hal_set_current_channel_ex(struct hw_data *pHwData, struct chan_info channel)
{
struct wb35_reg *reg = &pHwData->reg;
@@ -180,10 +173,10 @@ hal_set_current_channel_ex(struct hw_data *pHwData, ChanInfo channel)
reg->M28_MacControl &= ~0xff; // Clean channel information field
reg->M28_MacControl |= channel.ChanNo;
Wb35Reg_WriteWithCallbackValue(pHwData, 0x0828, reg->M28_MacControl,
- (s8 *) & channel, sizeof(ChanInfo));
+ (s8 *) & channel, sizeof(struct chan_info));
}
-static void hal_set_current_channel(struct hw_data *pHwData, ChanInfo channel)
+static void hal_set_current_channel(struct hw_data *pHwData, struct chan_info channel)
{
hal_set_current_channel_ex(pHwData, channel);
}
@@ -253,7 +246,7 @@ static void hal_set_accept_beacon(struct hw_data *pHwData, u8 enable)
static int wbsoft_config(struct ieee80211_hw *dev, u32 changed)
{
struct wbsoft_priv *priv = dev->priv;
- ChanInfo ch;
+ struct chan_info ch;
printk("wbsoft_config called\n");
@@ -287,7 +280,6 @@ static const struct ieee80211_ops wbsoft_ops = {
.prepare_multicast = wbsoft_prepare_multicast,
.configure_filter = wbsoft_configure_filter,
.get_stats = wbsoft_get_stats,
- .get_tx_stats = wbsoft_get_tx_stats,
.get_tsf = wbsoft_get_tsf,
};
diff --git a/drivers/staging/wlags49_h2/wl_main.c b/drivers/staging/wlags49_h2/wl_main.c
index 16764a000942..cf0c38468b20 100644
--- a/drivers/staging/wlags49_h2/wl_main.c
+++ b/drivers/staging/wlags49_h2/wl_main.c
@@ -3792,7 +3792,7 @@ static int write_int(struct file *file, const char *buffer, unsigned long count,
}
if (count > 0 ) {
proc_number[count] = 0;
- nr = wl_atoi( proc_number );
+ nr = simple_strtoul(proc_number , NULL, 0);
*(unsigned int *)data = nr;
if ( nr & 0x8000 ) { //;?kludgy but it is unclear to me were else to place this
#if DBG
diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c
index ac3890247965..fa082d90fcad 100644
--- a/drivers/staging/wlags49_h2/wl_netdev.c
+++ b/drivers/staging/wlags49_h2/wl_netdev.c
@@ -360,7 +360,7 @@ int wl_open(struct net_device *dev)
wl_lock( lp, &flags );
if( status != HCF_SUCCESS ) {
- // Unsuccesfull, try reset of the card to recover
+ // Unsuccessful, try reset of the card to recover
status = wl_reset( dev );
}
@@ -1049,7 +1049,7 @@ void wl_multicast( struct net_device *dev )
//;?seems reasonable that even an AP-only driver could afford this small additional footprint
int x;
- struct dev_mc_list *mclist;
+ struct dev_mc_list *mclist;
struct wl_private *lp = wl_priv(dev);
unsigned long flags;
/*------------------------------------------------------------------------*/
@@ -1070,13 +1070,11 @@ void wl_multicast( struct net_device *dev )
( dev->flags & IFF_MULTICAST ) ? "Multicast " : "",
( dev->flags & IFF_ALLMULTI ) ? "All-Multicast" : "" );
- DBG_PRINT( " mc_count: %d\n", dev->mc_count );
+ DBG_PRINT( " mc_count: %d\n", netdev_mc_count(dev));
- for( x = 0, mclist = dev->mc_list; mclist && x < dev->mc_count;
- x++, mclist = mclist->next ) {
+ netdev_for_each_mc_addr(mclist, dev)
DBG_PRINT( " %s (%d)\n", DbgHwAddr(mclist->dmi_addr),
mclist->dmi_addrlen );
- }
}
#endif /* DBG */
@@ -1103,7 +1101,7 @@ void wl_multicast( struct net_device *dev )
DBG_PRINT( "Enabling Promiscuous mode (IFF_PROMISC)\n" );
hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
}
- else if(( dev->mc_count > HCF_MAX_MULTICAST ) ||
+ else if ((netdev_mc_count(dev) > HCF_MAX_MULTICAST) ||
( dev->flags & IFF_ALLMULTI )) {
/* Shutting off this filter will enable all multicast frames to
be sent up from the device; however, this is a static RID, so
@@ -1115,17 +1113,15 @@ void wl_multicast( struct net_device *dev )
hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
wl_apply( lp );
}
- else if( dev->mc_count != 0 ) {
+ else if (!netdev_mc_empty(dev)) {
/* Set the multicast addresses */
- lp->ltvRecord.len = ( dev->mc_count * 3 ) + 1;
+ lp->ltvRecord.len = ( netdev_mc_count(dev) * 3 ) + 1;
lp->ltvRecord.typ = CFG_GROUP_ADDR;
- for( x = 0, mclist = dev->mc_list;
- ( x < dev->mc_count ) && ( mclist != NULL );
- x++, mclist = mclist->next ) {
- memcpy( &( lp->ltvRecord.u.u8[x * ETH_ALEN] ),
- mclist->dmi_addr, ETH_ALEN );
- }
+ x = 0;
+ netdev_for_each_mc_addr(mclist, dev)
+ memcpy(&(lp->ltvRecord.u.u8[x++ * ETH_ALEN]),
+ mclist->dmi_addr, ETH_ALEN);
DBG_PRINT( "Setting multicast list\n" );
hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
} else {
@@ -1194,9 +1190,7 @@ static const struct net_device_ops wl_netdev_ops =
.ndo_stop = &wl_adapter_close,
.ndo_do_ioctl = &wl_ioctl,
-#ifdef HAVE_TX_TIMEOUT
.ndo_tx_timeout = &wl_tx_timeout,
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = wl_poll,
@@ -1270,9 +1264,7 @@ struct net_device * wl_device_alloc( void )
dev->stop = &wl_adapter_close;
dev->do_ioctl = &wl_ioctl;
-#ifdef HAVE_TX_TIMEOUT
dev->tx_timeout = &wl_tx_timeout;
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = wl_poll;
@@ -1280,9 +1272,7 @@ struct net_device * wl_device_alloc( void )
#endif // (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30))
-#ifdef HAVE_TX_TIMEOUT
dev->watchdog_timeo = TX_TIMEOUT;
-#endif
dev->ethtool_ops = &wl_ethtool_ops;
diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c
index a3db111d4a95..01e4bec9fd5b 100644
--- a/drivers/staging/wlags49_h2/wl_pci.c
+++ b/drivers/staging/wlags49_h2/wl_pci.c
@@ -81,7 +81,6 @@
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
diff --git a/drivers/staging/wlags49_h2/wl_profile.c b/drivers/staging/wlags49_h2/wl_profile.c
index 715f027a923f..1e0c75f28557 100644
--- a/drivers/staging/wlags49_h2/wl_profile.c
+++ b/drivers/staging/wlags49_h2/wl_profile.c
@@ -383,15 +383,15 @@ void translate_option( char *buffer, struct wl_private *lp )
DbgInfo->DebugFlag |= DBG_DEFAULTS;
}
} else {
- DbgInfo->DebugFlag = wl_atoi( value ); //;?DebugFlag;
+ DbgInfo->DebugFlag = simple_strtoul(value, NULL, 0); //;?DebugFlag;
}
- DbgInfo->DebugFlag = wl_atoi( value ); //;?Delete ASAP
+ DbgInfo->DebugFlag = simple_strtoul(value, NULL, 0); //;?Delete ASAP
}
#endif /* DBG */
if ( strcmp( key, PARM_NAME_AUTH_KEY_MGMT_SUITE ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_AUTH_KEY_MGMT_SUITE, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_AUTH_KEY_MGMT_SUITE ) || ( value_convert <= PARM_MAX_AUTH_KEY_MGMT_SUITE )) {
lp->AuthKeyMgmtSuite = value_convert;
} else {
@@ -401,7 +401,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_BRSC_2GHZ ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_BRSC_2GHZ, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_BRSC ) || ( value_convert <= PARM_MAX_BRSC )) {
lp->brsc[0] = value_convert;
} else {
@@ -411,7 +411,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_BRSC_5GHZ ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_BRSC_5GHZ, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_BRSC ) || ( value_convert <= PARM_MAX_BRSC )) {
lp->brsc[1] = value_convert;
} else {
@@ -448,7 +448,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_ENABLE_ENCRYPTION ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_ENABLE_ENCRYPTION, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_ENABLE_ENCRYPTION ) && ( value_convert <= PARM_MAX_ENABLE_ENCRYPTION )) {
lp->EnableEncryption = value_convert;
} else {
@@ -529,7 +529,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_MULTICAST_RATE ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_MULTICAST_RATE, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_MULTICAST_RATE ) && ( value_convert <= PARM_MAX_MULTICAST_RATE )) {
lp->MulticastRate[0] = value_convert;
@@ -540,7 +540,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_OWN_CHANNEL ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_OWN_CHANNEL, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if ( wl_is_a_valid_chan( value_convert )) {
if ( value_convert > 14 ) {
value_convert = value_convert | 0x100;
@@ -567,7 +567,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_RTS_THRESHOLD ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD )) {
lp->RTSThreshold = value_convert;
} else {
@@ -577,7 +577,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_SRSC_2GHZ ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_SRSC_2GHZ, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_SRSC ) || ( value_convert <= PARM_MAX_SRSC )) {
lp->srsc[0] = value_convert;
} else {
@@ -587,7 +587,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_SRSC_5GHZ ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_SRSC_5GHZ, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_SRSC ) || ( value_convert <= PARM_MAX_SRSC )) {
lp->srsc[1] = value_convert;
} else {
@@ -597,7 +597,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_SYSTEM_SCALE ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_SYSTEM_SCALE, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_SYSTEM_SCALE ) && ( value_convert <= PARM_MAX_SYSTEM_SCALE )) {
lp->DistanceBetweenAPs = value_convert;
} else {
@@ -607,9 +607,9 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_TX_KEY ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_KEY, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_TX_KEY ) && ( value_convert <= PARM_MAX_TX_KEY )) {
- lp->TransmitKeyID = wl_atoi( value );
+ lp->TransmitKeyID = simple_strtoul(value, NULL, 0);
} else {
DBG_WARNING( DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_TX_KEY );
}
@@ -617,7 +617,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_TX_RATE ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE )) {
lp->TxRateControl[0] = value_convert;
} else {
@@ -627,7 +627,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_TX_POW_LEVEL ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_POW_LEVEL, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_TX_POW_LEVEL ) || ( value_convert <= PARM_MAX_TX_POW_LEVEL )) {
lp->txPowLevel = value_convert;
} else {
@@ -645,7 +645,7 @@ void translate_option( char *buffer, struct wl_private *lp )
if ( strcmp( key, PARM_NAME_PORT_TYPE ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_PORT_TYPE, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert == PARM_MIN_PORT_TYPE ) || ( value_convert == PARM_MAX_PORT_TYPE )) {
lp->PortType = value_convert;
} else {
@@ -654,7 +654,7 @@ void translate_option( char *buffer, struct wl_private *lp )
}
else if ( strcmp( key, PARM_NAME_PM_ENABLED ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_PM_ENABLED, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
/* ;? how about wl_main.c containing
* VALID_PARAM( PARM_PM_ENABLED <= WVLAN_PM_STATE_STANDARD ||
* ( PARM_PM_ENABLED & 0x7FFF ) <= WVLAN_PM_STATE_STANDARD );
@@ -677,7 +677,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_MAX_SLEEP ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_MAX_SLEEP, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= 0 ) && ( value_convert <= 65535 )) {
lp->MaxSleepDuration = value_convert;
} else {
@@ -696,7 +696,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_AUTHENTICATION ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_AUTHENTICATION, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_AUTHENTICATION ) && ( value_convert <= PARM_MAX_AUTHENTICATION )) {
lp->authentication = value_convert;
} else {
@@ -706,7 +706,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_OWN_ATIM_WINDOW ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_OWN_ATIM_WINDOW, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_OWN_ATIM_WINDOW ) && ( value_convert <= PARM_MAX_OWN_ATIM_WINDOW )) {
lp->atimWindow = value_convert;
} else {
@@ -716,7 +716,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_PM_HOLDOVER_DURATION ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_PM_HOLDOVER_DURATION, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_PM_HOLDOVER_DURATION ) && ( value_convert <= PARM_MAX_PM_HOLDOVER_DURATION )) {
lp->holdoverDuration = value_convert;
} else {
@@ -730,7 +730,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_CONNECTION_CONTROL ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_CONNECTION_CONTROL, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_CONNECTION_CONTROL ) && ( value_convert <= PARM_MAX_CONNECTION_CONTROL )) {
lp->connectionControl = value_convert;
} else {
@@ -749,7 +749,7 @@ void translate_option( char *buffer, struct wl_private *lp )
if ( strcmp( key, PARM_NAME_OWN_DTIM_PERIOD ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_OWN_DTIM_PERIOD, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if ( value_convert >= PARM_MIN_OWN_DTIM_PERIOD ) {
lp->DTIMPeriod = value_convert;
} else {
@@ -775,7 +775,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_OWN_BEACON_INTERVAL ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_OWN_BEACON_INTERVAL, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if ( value_convert >= PARM_MIN_OWN_BEACON_INTERVAL ) {
lp->ownBeaconInterval = value_convert;
} else {
@@ -785,7 +785,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_COEXISTENCE ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_COEXISTENCE, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if ( value_convert >= PARM_MIN_COEXISTENCE ) {
lp->coexistence = value_convert;
} else {
@@ -797,7 +797,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_RTS_THRESHOLD1 ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD1, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD )) {
lp->wds_port[0].rtsThreshold = value_convert;
} else {
@@ -807,7 +807,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_RTS_THRESHOLD2 ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD2, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD )) {
lp->wds_port[1].rtsThreshold = value_convert;
} else {
@@ -817,7 +817,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_RTS_THRESHOLD3 ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD3, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD )) {
lp->wds_port[2].rtsThreshold = value_convert;
} else {
@@ -827,7 +827,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_RTS_THRESHOLD4 ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD4, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD )) {
lp->wds_port[3].rtsThreshold = value_convert;
} else {
@@ -837,7 +837,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_RTS_THRESHOLD5 ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD5, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD )) {
lp->wds_port[4].rtsThreshold = value_convert;
} else {
@@ -847,7 +847,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_RTS_THRESHOLD6 ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_RTS_THRESHOLD6, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_RTS_THRESHOLD ) && ( value_convert <= PARM_MAX_RTS_THRESHOLD )) {
lp->wds_port[5].rtsThreshold = value_convert;
} else {
@@ -857,7 +857,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_TX_RATE1 ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE1, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE )) {
lp->wds_port[0].txRateCntl = value_convert;
} else {
@@ -867,7 +867,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_TX_RATE2 ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE2, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE )) {
lp->wds_port[1].txRateCntl = value_convert;
} else {
@@ -877,7 +877,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_TX_RATE3 ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE3, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE )) {
lp->wds_port[2].txRateCntl = value_convert;
} else {
@@ -887,7 +887,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_TX_RATE4 ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE4, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE )) {
lp->wds_port[3].txRateCntl = value_convert;
} else {
@@ -897,7 +897,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_TX_RATE5 ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE5, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE )) {
lp->wds_port[4].txRateCntl = value_convert;
} else {
@@ -907,7 +907,7 @@ void translate_option( char *buffer, struct wl_private *lp )
else if ( strcmp( key, PARM_NAME_TX_RATE6 ) == 0 ) {
DBG_TRACE( DbgInfo, "%s, value: %s\n", PARM_NAME_TX_RATE6, value );
- value_convert = wl_atoi( value );
+ value_convert = simple_strtoul(value, NULL, 0);
if (( value_convert >= PARM_MIN_TX_RATE ) && ( value_convert <= PARM_MAX_TX_RATE )) {
lp->wds_port[5].txRateCntl = value_convert;
} else {
diff --git a/drivers/staging/wlags49_h2/wl_util.c b/drivers/staging/wlags49_h2/wl_util.c
index ac1e7f38f982..bbdb9973d1e5 100644
--- a/drivers/staging/wlags49_h2/wl_util.c
+++ b/drivers/staging/wlags49_h2/wl_util.c
@@ -1536,52 +1536,3 @@ int wl_get_tallies(struct wl_private *lp,
return ret;
}
-/*******************************************************************************
- * wl_atoi()
- *******************************************************************************
- *
- * DESCRIPTION:
- *
- * Believe it or not, we need our own implementation of atoi in the kernel.
- *
- * PARAMETERS:
- *
- * string - the ASCII string to convert to an integer
- *
- * RETURNS:
- *
- * unsigned integer
- *
- ******************************************************************************/
-unsigned int wl_atoi( char *string )
-{
-unsigned int base = 10; //default to decimal
-unsigned int value = 0;
-unsigned int c;
-int i = strlen( string );
-
- if ( i > 2 && string[0] == '0' && ( string[1] | ('X'^'x') ) == 'x' ) {
- base = 16;
- string +=2;
- }
- while ( ( c = *string++ ) != '\0' ) {
- if ( value > UINT_MAX / base ) { //test for overrun
- DBG_FUNC( "wl_atoi" ); //don't overload the log file with good messages
- DBG_ENTER( DbgInfo );
- DBG_ERROR( DbgInfo, "string \"%s\", lenght exceeds expectations\n", string );
- printk( "<1>string \"%s\", lenght exceeds expectations\n", string );
- DBG_LEAVE( DbgInfo );
- break;
- }
- c -= '0';
- if ( 0 <= c && c <= 9 ) value = base * value + c;
- else if ( base == 16 ) {
- c += '0';
- c |= 'A'^'a';
- c = c - 'a'+ 10;
- if ( 10 <= c && c <= 15 ) value = base * value + c;
- }
- }
- return value;
-} // wl_atoi
-
diff --git a/drivers/staging/wlags49_h2/wl_util.h b/drivers/staging/wlags49_h2/wl_util.h
index 16cd6c578adb..561e85b5c9b2 100644
--- a/drivers/staging/wlags49_h2/wl_util.h
+++ b/drivers/staging/wlags49_h2/wl_util.h
@@ -100,6 +100,4 @@ void wl_process_updated_record( struct wl_private *lp );
void wl_process_assoc_status( struct wl_private *lp );
void wl_process_security_status( struct wl_private *lp );
-unsigned int wl_atoi( char *string );
-
#endif // __WL_UTIL_H__
diff --git a/drivers/staging/wlan-ng/Kconfig b/drivers/staging/wlan-ng/Kconfig
index f44294b0d8dc..82fcc1665e92 100644
--- a/drivers/staging/wlan-ng/Kconfig
+++ b/drivers/staging/wlan-ng/Kconfig
@@ -1,6 +1,8 @@
config PRISM2_USB
tristate "Prism2.5/3 USB driver"
- depends on WLAN && USB && WIRELESS_EXT
+ depends on WLAN && USB
+ select WIRELESS_EXT
+ select WEXT_PRIV
default n
---help---
This is the wlan-ng prism 2.5/3 USB driver for a wide range of
diff --git a/drivers/staging/wlan-ng/hfa384x.h b/drivers/staging/wlan-ng/hfa384x.h
index 46cce8159e59..1fa42e01e8cb 100644
--- a/drivers/staging/wlan-ng/hfa384x.h
+++ b/drivers/staging/wlan-ng/hfa384x.h
@@ -61,17 +61,17 @@
#include <linux/if_ether.h>
/*--- Mins & Maxs -----------------------------------*/
-#define HFA384x_PORTID_MAX ((u16)7)
-#define HFA384x_NUMPORTS_MAX ((u16)(HFA384x_PORTID_MAX+1))
-#define HFA384x_PDR_LEN_MAX ((u16)512) /* in bytes, from EK */
-#define HFA384x_PDA_RECS_MAX ((u16)200) /* a guess */
-#define HFA384x_PDA_LEN_MAX ((u16)1024) /* in bytes, from EK */
-#define HFA384x_SCANRESULT_MAX ((u16)31)
-#define HFA384x_HSCANRESULT_MAX ((u16)31)
-#define HFA384x_CHINFORESULT_MAX ((u16)16)
-#define HFA384x_RID_GUESSING_MAXLEN 2048 /* I'm not really sure */
-#define HFA384x_RIDDATA_MAXLEN HFA384x_RID_GUESSING_MAXLEN
-#define HFA384x_USB_RWMEM_MAXLEN 2048
+#define HFA384x_PORTID_MAX ((u16)7)
+#define HFA384x_NUMPORTS_MAX ((u16)(HFA384x_PORTID_MAX+1))
+#define HFA384x_PDR_LEN_MAX ((u16)512) /* in bytes, from EK */
+#define HFA384x_PDA_RECS_MAX ((u16)200) /* a guess */
+#define HFA384x_PDA_LEN_MAX ((u16)1024) /* in bytes, from EK*/
+#define HFA384x_SCANRESULT_MAX ((u16)31)
+#define HFA384x_HSCANRESULT_MAX ((u16)31)
+#define HFA384x_CHINFORESULT_MAX ((u16)16)
+#define HFA384x_RID_GUESSING_MAXLEN 2048 /* I'm not really sure */
+#define HFA384x_RIDDATA_MAXLEN HFA384x_RID_GUESSING_MAXLEN
+#define HFA384x_USB_RWMEM_MAXLEN 2048
/*--- Support Constants -----------------------------*/
#define HFA384x_PORTTYPE_IBSS ((u16)0)
@@ -115,8 +115,8 @@
/* Make a 32-bit flat address from AUX format 16-bit page and offset */
#define HFA384x_ADDR_AUX_MKFLAT(p, o) \
- (((u32)(((u16)(p))&HFA384x_ADDR_AUX_PAGE_MASK)) << 7) | \
- ((u32)(((u16)(o))&HFA384x_ADDR_AUX_OFF_MASK))
+ ((((u32)(((u16)(p))&HFA384x_ADDR_AUX_PAGE_MASK)) << 7) | \
+ ((u32)(((u16)(o))&HFA384x_ADDR_AUX_OFF_MASK)))
/* Make CMD format offset and page from a 32-bit flat address */
#define HFA384x_ADDR_CMD_MKPAGE(f) \
@@ -135,12 +135,21 @@
#define HFA384x_DLSTATE_FLASHENABLED 2
/*--- Register Field Masks --------------------------*/
-#define HFA384x_CMD_AINFO ((u16)(BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8)))
-#define HFA384x_CMD_MACPORT ((u16)(BIT(10) | BIT(9) | BIT(8)))
+#define HFA384x_CMD_AINFO ((u16)(BIT(14) | BIT(13) \
+ | BIT(12) | BIT(11) \
+ | BIT(10) | BIT(9) \
+ | BIT(8)))
+#define HFA384x_CMD_MACPORT ((u16)(BIT(10) | BIT(9) | \
+ BIT(8)))
#define HFA384x_CMD_PROGMODE ((u16)(BIT(9) | BIT(8)))
-#define HFA384x_CMD_CMDCODE ((u16)(BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)))
+#define HFA384x_CMD_CMDCODE ((u16)(BIT(5) | BIT(4) | \
+ BIT(3) | BIT(2) | \
+ BIT(1) | BIT(0)))
-#define HFA384x_STATUS_RESULT ((u16)(BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8)))
+#define HFA384x_STATUS_RESULT ((u16)(BIT(14) | BIT(13) \
+ | BIT(12) | BIT(11) \
+ | BIT(10) | BIT(9) \
+ | BIT(8)))
/*--- Command Code Constants --------------------------*/
/*--- Controller Commands --------------------------*/
@@ -244,8 +253,10 @@ Information RID Lengths: MAC Information
This is the length of JUST the DATA part of the RID (does not
include the len or code fields)
--------------------------------------------------------------------*/
-#define HFA384x_RID_DBMCOMMSQUALITY_LEN ((u16)sizeof(hfa384x_dbmcommsquality_t))
-#define HFA384x_RID_JOINREQUEST_LEN ((u16)sizeof(hfa384x_JoinRequest_data_t))
+#define HFA384x_RID_DBMCOMMSQUALITY_LEN \
+ ((u16) sizeof(hfa384x_dbmcommsquality_t))
+#define HFA384x_RID_JOINREQUEST_LEN \
+ ((u16)sizeof(hfa384x_JoinRequest_data_t))
/*--------------------------------------------------------------------
Information RIDs: Modem Information
@@ -322,9 +333,11 @@ PD Record codes
/*--- Register Test/Get/Set Field macros ------------------------*/
-#define HFA384x_CMD_AINFO_SET(value) ((u16)((u16)(value) << 8))
-#define HFA384x_CMD_MACPORT_SET(value) ((u16)HFA384x_CMD_AINFO_SET(value))
-#define HFA384x_CMD_PROGMODE_SET(value) ((u16)HFA384x_CMD_AINFO_SET((u16)value))
+#define HFA384x_CMD_AINFO_SET(value) ((u16)((u16)(value) << 8))
+#define HFA384x_CMD_MACPORT_SET(value) \
+ ((u16)HFA384x_CMD_AINFO_SET(value))
+#define HFA384x_CMD_PROGMODE_SET(value) \
+ ((u16)HFA384x_CMD_AINFO_SET((u16)value))
#define HFA384x_CMD_CMDCODE_SET(value) ((u16)(value))
#define HFA384x_STATUS_RESULT_SET(value) (((u16)(value)) << 8)
@@ -402,7 +415,7 @@ typedef struct hfa384x_authenticateStation_data {
/*-- Configuration Record: WPAData (data portion only) --*/
typedef struct hfa384x_WPAData {
u16 datalen;
- u8 data[0]; // max 80
+ u8 data[0]; /* max 80 */
} __attribute__ ((packed)) hfa384x_WPAData_t;
/*--------------------------------------------------------------------
@@ -479,7 +492,8 @@ Communication Frames: Field Masks for Transmit Frames
#define HFA384x_TXSTATUS_AGEDERR ((u16)BIT(1))
#define HFA384x_TXSTATUS_RETRYERR ((u16)BIT(0))
/*-- Transmit Control Field --*/
-#define HFA384x_TX_MACPORT ((u16)(BIT(10) | BIT(9) | BIT(8)))
+#define HFA384x_TX_MACPORT ((u16)(BIT(10) | \
+ BIT(9) | BIT(8)))
#define HFA384x_TX_STRUCTYPE ((u16)(BIT(4) | BIT(3)))
#define HFA384x_TX_TXEX ((u16)BIT(2))
#define HFA384x_TX_TXOK ((u16)BIT(1))
@@ -496,7 +510,8 @@ Communication Frames: Test/Get/Set Field Values for Transmit Frames
#define HFA384x_TX_SET(v, m, s) ((((u16)(v))<<((u16)(s)))&((u16)(m)))
#define HFA384x_TX_MACPORT_SET(v) HFA384x_TX_SET(v, HFA384x_TX_MACPORT, 8)
-#define HFA384x_TX_STRUCTYPE_SET(v) HFA384x_TX_SET(v, HFA384x_TX_STRUCTYPE, 3)
+#define HFA384x_TX_STRUCTYPE_SET(v) HFA384x_TX_SET(v, \
+ HFA384x_TX_STRUCTYPE, 3)
#define HFA384x_TX_TXEX_SET(v) HFA384x_TX_SET(v, HFA384x_TX_TXEX, 2)
#define HFA384x_TX_TXOK_SET(v) HFA384x_TX_SET(v, HFA384x_TX_TXOK, 1)
/*--------------------------------------------------------------------
@@ -534,13 +549,17 @@ Communication Frames: Field Masks for Receive Frames
--------------------------------------------------------------------*/
/*-- Status Fields --*/
-#define HFA384x_RXSTATUS_MACPORT ((u16)(BIT(10) | BIT(9) | BIT(8)))
+#define HFA384x_RXSTATUS_MACPORT ((u16)(BIT(10) | \
+ BIT(9) | \
+ BIT(8)))
#define HFA384x_RXSTATUS_FCSERR ((u16)BIT(0))
/*--------------------------------------------------------------------
Communication Frames: Test/Get/Set Field Values for Receive Frames
--------------------------------------------------------------------*/
-#define HFA384x_RXSTATUS_MACPORT_GET(value) ((u16)((((u16)(value)) & HFA384x_RXSTATUS_MACPORT) >> 8))
-#define HFA384x_RXSTATUS_ISFCSERR(value) ((u16)(((u16)(value)) & HFA384x_RXSTATUS_FCSERR))
+#define HFA384x_RXSTATUS_MACPORT_GET(value) ((u16)((((u16)(value)) \
+ & HFA384x_RXSTATUS_MACPORT) >> 8))
+#define HFA384x_RXSTATUS_ISFCSERR(value) ((u16)(((u16)(value)) \
+ & HFA384x_RXSTATUS_FCSERR))
/*--------------------------------------------------------------------
FRAME STRUCTURES: Information Types and Information Frame Structures
----------------------------------------------------------------------
@@ -1133,7 +1152,7 @@ struct hfa384x;
typedef void (*ctlx_cmdcb_t) (struct hfa384x *, const struct hfa384x_usbctlx *);
-typedef void (*ctlx_usercb_t) (struct hfa384x * hw,
+typedef void (*ctlx_usercb_t) (struct hfa384x *hw,
void *ctlxresult, void *usercb_data);
typedef struct hfa384x_usbctlx {
@@ -1174,14 +1193,14 @@ typedef struct hfa484x_metacmd {
} hfa384x_metacmd_t;
#define MAX_GRP_ADDR 32
-#define WLAN_COMMENT_MAX 80 /* Max. length of user comment string. */
+#define WLAN_COMMENT_MAX 80 /* Max. length of user comment string. */
-#define WLAN_AUTH_MAX 60 /* Max. # of authenticated stations. */
-#define WLAN_ACCESS_MAX 60 /* Max. # of stations in an access list. */
-#define WLAN_ACCESS_NONE 0 /* No stations may be authenticated. */
-#define WLAN_ACCESS_ALL 1 /* All stations may be authenticated. */
-#define WLAN_ACCESS_ALLOW 2 /* Authenticate only "allowed" stations. */
-#define WLAN_ACCESS_DENY 3 /* Do not authenticate "denied" stations. */
+#define WLAN_AUTH_MAX 60 /* Max. # of authenticated stations. */
+#define WLAN_ACCESS_MAX 60 /* Max. # of stations in an access list. */
+#define WLAN_ACCESS_NONE 0 /* No stations may be authenticated. */
+#define WLAN_ACCESS_ALL 1 /* All stations may be authenticated. */
+#define WLAN_ACCESS_ALLOW 2 /* Authenticate only "allowed" stations. */
+#define WLAN_ACCESS_DENY 3 /* Do not authenticate "denied" stations. */
/* XXX These are going away ASAP */
typedef struct prism2sta_authlist {
@@ -1294,10 +1313,23 @@ typedef struct hfa384x {
hfa384x_caplevel_t cap_sup_ap;
/* Actor compatibility ranges */
- hfa384x_caplevel_t cap_act_pri_cfi; /* pri f/w to controller interface */
- hfa384x_caplevel_t cap_act_sta_cfi; /* sta f/w to controller interface */
+ hfa384x_caplevel_t cap_act_pri_cfi; /*
+ * pri f/w to controller
+ * interface
+ */
+
+ hfa384x_caplevel_t cap_act_sta_cfi; /*
+ * sta f/w to controller
+ * interface
+ */
+
hfa384x_caplevel_t cap_act_sta_mfi; /* sta f/w to modem interface */
- hfa384x_caplevel_t cap_act_ap_cfi; /* ap f/w to controller interface */
+
+ hfa384x_caplevel_t cap_act_ap_cfi; /*
+ * ap f/w to controller
+ * interface
+ */
+
hfa384x_caplevel_t cap_act_ap_mfi; /* ap f/w to modem interface */
u32 psusercount; /* Power save user count. */
@@ -1320,25 +1352,25 @@ typedef struct hfa384x {
} hfa384x_t;
-void hfa384x_create(hfa384x_t * hw, struct usb_device *usb);
-void hfa384x_destroy(hfa384x_t * hw);
+void hfa384x_create(hfa384x_t *hw, struct usb_device *usb);
+void hfa384x_destroy(hfa384x_t *hw);
int
-hfa384x_corereset(hfa384x_t * hw, int holdtime, int settletime, int genesis);
-int hfa384x_drvr_commtallies(hfa384x_t * hw);
-int hfa384x_drvr_disable(hfa384x_t * hw, u16 macport);
-int hfa384x_drvr_enable(hfa384x_t * hw, u16 macport);
-int hfa384x_drvr_flashdl_enable(hfa384x_t * hw);
-int hfa384x_drvr_flashdl_disable(hfa384x_t * hw);
-int hfa384x_drvr_flashdl_write(hfa384x_t * hw, u32 daddr, void *buf, u32 len);
-int hfa384x_drvr_getconfig(hfa384x_t * hw, u16 rid, void *buf, u16 len);
-int hfa384x_drvr_ramdl_enable(hfa384x_t * hw, u32 exeaddr);
-int hfa384x_drvr_ramdl_disable(hfa384x_t * hw);
-int hfa384x_drvr_ramdl_write(hfa384x_t * hw, u32 daddr, void *buf, u32 len);
-int hfa384x_drvr_readpda(hfa384x_t * hw, void *buf, unsigned int len);
-int hfa384x_drvr_setconfig(hfa384x_t * hw, u16 rid, void *buf, u16 len);
-
-static inline int hfa384x_drvr_getconfig16(hfa384x_t * hw, u16 rid, void *val)
+hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis);
+int hfa384x_drvr_commtallies(hfa384x_t *hw);
+int hfa384x_drvr_disable(hfa384x_t *hw, u16 macport);
+int hfa384x_drvr_enable(hfa384x_t *hw, u16 macport);
+int hfa384x_drvr_flashdl_enable(hfa384x_t *hw);
+int hfa384x_drvr_flashdl_disable(hfa384x_t *hw);
+int hfa384x_drvr_flashdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len);
+int hfa384x_drvr_getconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len);
+int hfa384x_drvr_ramdl_enable(hfa384x_t *hw, u32 exeaddr);
+int hfa384x_drvr_ramdl_disable(hfa384x_t *hw);
+int hfa384x_drvr_ramdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len);
+int hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, unsigned int len);
+int hfa384x_drvr_setconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len);
+
+static inline int hfa384x_drvr_getconfig16(hfa384x_t *hw, u16 rid, void *val)
{
int result = 0;
result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(u16));
@@ -1347,46 +1379,46 @@ static inline int hfa384x_drvr_getconfig16(hfa384x_t * hw, u16 rid, void *val)
return result;
}
-static inline int hfa384x_drvr_setconfig16(hfa384x_t * hw, u16 rid, u16 val)
+static inline int hfa384x_drvr_setconfig16(hfa384x_t *hw, u16 rid, u16 val)
{
u16 value = cpu_to_le16(val);
return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(value));
}
int
-hfa384x_drvr_getconfig_async(hfa384x_t * hw,
+hfa384x_drvr_getconfig_async(hfa384x_t *hw,
u16 rid, ctlx_usercb_t usercb, void *usercb_data);
int
-hfa384x_drvr_setconfig_async(hfa384x_t * hw,
+hfa384x_drvr_setconfig_async(hfa384x_t *hw,
u16 rid,
void *buf,
u16 len, ctlx_usercb_t usercb, void *usercb_data);
static inline int
-hfa384x_drvr_setconfig16_async(hfa384x_t * hw, u16 rid, u16 val)
+hfa384x_drvr_setconfig16_async(hfa384x_t *hw, u16 rid, u16 val)
{
u16 value = cpu_to_le16(val);
return hfa384x_drvr_setconfig_async(hw, rid, &value, sizeof(value),
NULL, NULL);
}
-int hfa384x_drvr_start(hfa384x_t * hw);
-int hfa384x_drvr_stop(hfa384x_t * hw);
+int hfa384x_drvr_start(hfa384x_t *hw);
+int hfa384x_drvr_stop(hfa384x_t *hw);
int
-hfa384x_drvr_txframe(hfa384x_t * hw, struct sk_buff *skb,
- p80211_hdr_t * p80211_hdr, p80211_metawep_t * p80211_wep);
-void hfa384x_tx_timeout(wlandevice_t * wlandev);
-
-int hfa384x_cmd_initialize(hfa384x_t * hw);
-int hfa384x_cmd_enable(hfa384x_t * hw, u16 macport);
-int hfa384x_cmd_disable(hfa384x_t * hw, u16 macport);
-int hfa384x_cmd_allocate(hfa384x_t * hw, u16 len);
-int hfa384x_cmd_monitor(hfa384x_t * hw, u16 enable);
+hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb,
+ p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep);
+void hfa384x_tx_timeout(wlandevice_t *wlandev);
+
+int hfa384x_cmd_initialize(hfa384x_t *hw);
+int hfa384x_cmd_enable(hfa384x_t *hw, u16 macport);
+int hfa384x_cmd_disable(hfa384x_t *hw, u16 macport);
+int hfa384x_cmd_allocate(hfa384x_t *hw, u16 len);
+int hfa384x_cmd_monitor(hfa384x_t *hw, u16 enable);
int
-hfa384x_cmd_download(hfa384x_t * hw,
+hfa384x_cmd_download(hfa384x_t *hw,
u16 mode, u16 lowaddr, u16 highaddr, u16 codelen);
-#endif /* __KERNEL__ */
+#endif /*__KERNEL__ */
-#endif /* _HFA384x_H */
+#endif /*_HFA384x_H */
diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c
index 925678babd9e..5df56f0238d6 100644
--- a/drivers/staging/wlan-ng/hfa384x_usb.c
+++ b/drivers/staging/wlan-ng/hfa384x_usb.c
@@ -52,7 +52,7 @@
* around the register accesses. The next higher level represents C-callable
* prism2 API functions that match the Intersil documentation as closely
* as is reasonable. The next higher layer implements common sequences
-* of invokations of the API layer (e.g. write to bap, followed by cmd).
+* of invocations of the API layer (e.g. write to bap, followed by cmd).
*
* Common sequences:
* hfa384x_drvr_xxx Highest level abstractions provided by the
@@ -118,15 +118,15 @@
#include <linux/wireless.h>
#include <linux/netdevice.h>
#include <linux/timer.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <asm/byteorder.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
#include <linux/list.h>
#include <linux/usb.h>
#include <linux/byteorder/generic.h>
-#define SUBMIT_URB(u,f) usb_submit_urb(u,f)
+#define SUBMIT_URB(u, f) usb_submit_urb(u, f)
#include "p80211types.h"
#include "p80211hdr.h"
@@ -627,7 +627,7 @@ static hfa384x_usbctlx_t *usbctlx_alloc(void)
{
hfa384x_usbctlx_t *ctlx;
- ctlx = kmalloc(sizeof(*ctlx), in_interrupt()? GFP_ATOMIC : GFP_KERNEL);
+ ctlx = kmalloc(sizeof(*ctlx), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
if (ctlx != NULL) {
memset(ctlx, 0, sizeof(*ctlx));
init_completion(&ctlx->done);
@@ -675,7 +675,7 @@ struct usbctlx_cmd_completor {
};
typedef struct usbctlx_cmd_completor usbctlx_cmd_completor_t;
-static int usbctlx_cmd_completor_fn(usbctlx_completor_t * head)
+static int usbctlx_cmd_completor_fn(usbctlx_completor_t *head)
{
usbctlx_cmd_completor_t *complete = (usbctlx_cmd_completor_t *) head;
return usbctlx_get_status(complete->cmdresp, complete->result);
@@ -1909,18 +1909,19 @@ int hfa384x_drvr_flashdl_enable(hfa384x_t *hw)
return -EINVAL;
/* Retrieve the buffer loc&size and timeout */
- if ((result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DOWNLOADBUFFER,
- &(hw->bufinfo),
- sizeof(hw->bufinfo)))) {
+ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DOWNLOADBUFFER,
+ &(hw->bufinfo), sizeof(hw->bufinfo));
+ if (result)
return result;
- }
+
hw->bufinfo.page = le16_to_cpu(hw->bufinfo.page);
hw->bufinfo.offset = le16_to_cpu(hw->bufinfo.offset);
hw->bufinfo.len = le16_to_cpu(hw->bufinfo.len);
- if ((result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_MAXLOADTIME,
- &(hw->dltimeout)))) {
+ result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_MAXLOADTIME,
+ &(hw->dltimeout));
+ if (result)
return result;
- }
+
hw->dltimeout = le16_to_cpu(hw->dltimeout);
pr_debug("flashdl_enable\n");
@@ -3071,9 +3072,9 @@ static void hfa384x_usbctlxq_run(hfa384x_t *hw)
hfa384x_ctlxout_callback, hw);
hw->ctlx_urb.transfer_flags |= USB_QUEUE_BULK;
- /* Now submit the URB and update the CTLX's state
- */
- if ((result = SUBMIT_URB(&hw->ctlx_urb, GFP_ATOMIC)) == 0) {
+ /* Now submit the URB and update the CTLX's state */
+ result = SUBMIT_URB(&hw->ctlx_urb, GFP_ATOMIC);
+ if (result == 0) {
/* This CTLX is now running on the active queue */
head->state = CTLX_REQ_SUBMITTED;
@@ -3599,7 +3600,8 @@ static void hfa384x_int_rxmonitor(wlandevice_t *wlandev,
skblen - sizeof(p80211_caphdr_t));
}
- if ((skb = dev_alloc_skb(skblen)) == NULL) {
+ skb = dev_alloc_skb(skblen);
+ if (skb == NULL) {
printk(KERN_ERR
"alloc_skb failed trying to allocate %d bytes\n",
skblen);
@@ -3642,7 +3644,7 @@ static void hfa384x_int_rxmonitor(wlandevice_t *wlandev,
/* check for unencrypted stuff if WEP bit set. */
if (*(datap - hdrlen + 1) & 0x40) /* wep set */
if ((*(datap) == 0xaa) && (*(datap + 1) == 0xaa))
- *(datap - hdrlen + 1) &= 0xbf; // clear wep; it's the 802.2 header!
+ *(datap - hdrlen + 1) &= 0xbf; /* clear wep; it's the 802.2 header! */
}
if (hw->sniff_fcs) {
@@ -3870,9 +3872,9 @@ retry:
delresp:
if (delete_resptimer) {
- if ((timer_ok = del_timer(&hw->resptimer)) != 0) {
+ timer_ok = del_timer(&hw->resptimer);
+ if (timer_ok != 0)
hw->resp_timer_done = 1;
- }
}
spin_unlock_irqrestore(&hw->ctlxq.lock, flags);
diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c
index 5952c671073f..a1605fbc8092 100644
--- a/drivers/staging/wlan-ng/p80211conv.c
+++ b/drivers/staging/wlan-ng/p80211conv.c
@@ -206,12 +206,11 @@ int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv,
/* XXXX need to pick keynum other than default? */
p80211_wep->data = kmalloc(skb->len, GFP_ATOMIC);
-
- if ((foo = wep_encrypt(wlandev, skb->data, p80211_wep->data,
- skb->len,
- (wlandev->hostwep &
- HOSTWEP_DEFAULTKEY_MASK),
- p80211_wep->iv, p80211_wep->icv))) {
+ foo = wep_encrypt(wlandev, skb->data, p80211_wep->data,
+ skb->len,
+ (wlandev->hostwep &HOSTWEP_DEFAULTKEY_MASK),
+ p80211_wep->iv, p80211_wep->icv);
+ if (foo) {
printk(KERN_WARNING
"Host en-WEP failed, dropping frame (%d).\n",
foo);
@@ -323,11 +322,12 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
skb->len);
return 1;
}
- if ((foo = wep_decrypt(wlandev, skb->data + payload_offset + 4,
+ foo = wep_decrypt(wlandev, skb->data + payload_offset + 4,
payload_length - 8, -1,
skb->data + payload_offset,
skb->data + payload_offset +
- payload_length - 4))) {
+ payload_length - 4);
+ if (foo) {
/* de-wep failed, drop skb. */
pr_debug("Host de-WEP failed, dropping frame (%d).\n",
foo);
diff --git a/drivers/staging/wlan-ng/p80211conv.h b/drivers/staging/wlan-ng/p80211conv.h
index 0c62df19fa7f..6fe163be24f6 100644
--- a/drivers/staging/wlan-ng/p80211conv.h
+++ b/drivers/staging/wlan-ng/p80211conv.h
@@ -153,8 +153,8 @@ struct wlandevice;
int skb_p80211_to_ether(struct wlandevice *wlandev, u32 ethconv,
struct sk_buff *skb);
int skb_ether_to_p80211(struct wlandevice *wlandev, u32 ethconv,
- struct sk_buff *skb, p80211_hdr_t * p80211_hdr,
- p80211_metawep_t * p80211_wep);
+ struct sk_buff *skb, p80211_hdr_t *p80211_hdr,
+ p80211_metawep_t *p80211_wep);
int p80211_stt_findproto(u16 proto);
diff --git a/drivers/staging/wlan-ng/p80211metadef.h b/drivers/staging/wlan-ng/p80211metadef.h
index da8b6f53c74f..0ccfba1294de 100644
--- a/drivers/staging/wlan-ng/p80211metadef.h
+++ b/drivers/staging/wlan-ng/p80211metadef.h
@@ -190,9 +190,9 @@
(P80211DID_MKSECTION(2) | \
P80211DID_MKGROUP(1))
#define DIDmib_dot11mac_dot11OperationTable_dot11MACAddress \
- (P80211DID_MKSECTION(2) | \
- P80211DID_MKGROUP(1) | \
- P80211DID_MKITEM(1) | 0x18000000)
+ (P80211DID_MKSECTION(2) | \
+ P80211DID_MKGROUP(1) | \
+ P80211DID_MKITEM(1) | 0x18000000)
#define DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold \
(P80211DID_MKSECTION(2) | \
P80211DID_MKGROUP(1) | \
@@ -210,18 +210,18 @@
P80211DID_MKGROUP(1) | \
P80211DID_MKITEM(5) | 0x18000000)
#define DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime \
- (P80211DID_MKSECTION(2) | \
- P80211DID_MKGROUP(1) | \
- P80211DID_MKITEM(6) | 0x10000000)
+ (P80211DID_MKSECTION(2) | \
+ P80211DID_MKGROUP(1) | \
+ P80211DID_MKITEM(6) | 0x10000000)
#define DIDmib_cat_dot11phy \
P80211DID_MKSECTION(3)
#define DIDmib_dot11phy_dot11PhyOperationTable \
(P80211DID_MKSECTION(3) | \
P80211DID_MKGROUP(1))
#define DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel \
- (P80211DID_MKSECTION(3) | \
- P80211DID_MKGROUP(3) | \
- P80211DID_MKITEM(10) | 0x18000000)
+ (P80211DID_MKSECTION(3) | \
+ P80211DID_MKGROUP(3) | \
+ P80211DID_MKITEM(10) | 0x18000000)
#define DIDmib_dot11phy_dot11PhyDSSSTable \
(P80211DID_MKSECTION(3) | \
P80211DID_MKGROUP(5))
diff --git a/drivers/staging/wlan-ng/p80211mgmt.h b/drivers/staging/wlan-ng/p80211mgmt.h
index 14cdc86d1676..deb52f5fd780 100644
--- a/drivers/staging/wlan-ng/p80211mgmt.h
+++ b/drivers/staging/wlan-ng/p80211mgmt.h
@@ -100,7 +100,7 @@
#ifndef _P80211MGMT_H
#define _P80211MGMT_H
-#ifndef _P80211HDR_H
+#ifndef _P80211HDR_H
#include "p80211hdr.h"
#endif
@@ -496,25 +496,25 @@ typedef struct wlan_fr_deauthen {
} wlan_fr_deauthen_t;
-void wlan_mgmt_encode_beacon(wlan_fr_beacon_t * f);
-void wlan_mgmt_decode_beacon(wlan_fr_beacon_t * f);
-void wlan_mgmt_encode_disassoc(wlan_fr_disassoc_t * f);
-void wlan_mgmt_decode_disassoc(wlan_fr_disassoc_t * f);
-void wlan_mgmt_encode_assocreq(wlan_fr_assocreq_t * f);
-void wlan_mgmt_decode_assocreq(wlan_fr_assocreq_t * f);
-void wlan_mgmt_encode_assocresp(wlan_fr_assocresp_t * f);
-void wlan_mgmt_decode_assocresp(wlan_fr_assocresp_t * f);
-void wlan_mgmt_encode_reassocreq(wlan_fr_reassocreq_t * f);
-void wlan_mgmt_decode_reassocreq(wlan_fr_reassocreq_t * f);
-void wlan_mgmt_encode_reassocresp(wlan_fr_reassocresp_t * f);
-void wlan_mgmt_decode_reassocresp(wlan_fr_reassocresp_t * f);
-void wlan_mgmt_encode_probereq(wlan_fr_probereq_t * f);
-void wlan_mgmt_decode_probereq(wlan_fr_probereq_t * f);
-void wlan_mgmt_encode_proberesp(wlan_fr_proberesp_t * f);
-void wlan_mgmt_decode_proberesp(wlan_fr_proberesp_t * f);
-void wlan_mgmt_encode_authen(wlan_fr_authen_t * f);
-void wlan_mgmt_decode_authen(wlan_fr_authen_t * f);
-void wlan_mgmt_encode_deauthen(wlan_fr_deauthen_t * f);
-void wlan_mgmt_decode_deauthen(wlan_fr_deauthen_t * f);
+void wlan_mgmt_encode_beacon(wlan_fr_beacon_t *f);
+void wlan_mgmt_decode_beacon(wlan_fr_beacon_t *f);
+void wlan_mgmt_encode_disassoc(wlan_fr_disassoc_t *f);
+void wlan_mgmt_decode_disassoc(wlan_fr_disassoc_t *f);
+void wlan_mgmt_encode_assocreq(wlan_fr_assocreq_t *f);
+void wlan_mgmt_decode_assocreq(wlan_fr_assocreq_t *f);
+void wlan_mgmt_encode_assocresp(wlan_fr_assocresp_t *f);
+void wlan_mgmt_decode_assocresp(wlan_fr_assocresp_t *f);
+void wlan_mgmt_encode_reassocreq(wlan_fr_reassocreq_t *f);
+void wlan_mgmt_decode_reassocreq(wlan_fr_reassocreq_t *f);
+void wlan_mgmt_encode_reassocresp(wlan_fr_reassocresp_t *f);
+void wlan_mgmt_decode_reassocresp(wlan_fr_reassocresp_t *f);
+void wlan_mgmt_encode_probereq(wlan_fr_probereq_t *f);
+void wlan_mgmt_decode_probereq(wlan_fr_probereq_t *f);
+void wlan_mgmt_encode_proberesp(wlan_fr_proberesp_t *f);
+void wlan_mgmt_decode_proberesp(wlan_fr_proberesp_t *f);
+void wlan_mgmt_encode_authen(wlan_fr_authen_t *f);
+void wlan_mgmt_decode_authen(wlan_fr_authen_t *f);
+void wlan_mgmt_encode_deauthen(wlan_fr_deauthen_t *f);
+void wlan_mgmt_decode_deauthen(wlan_fr_deauthen_t *f);
#endif /* _P80211MGMT_H */
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index 22424c8903ee..763ab1187a1c 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -586,7 +586,8 @@ static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd)
}
/* Allocate a buf of size req->len */
- if ((msgbuf = kmalloc(req->len, GFP_KERNEL))) {
+ msgbuf = kmalloc(req->len, GFP_KERNEL);
+ if (msgbuf) {
if (copy_from_user(msgbuf, (void __user *)req->data, req->len))
result = -EFAULT;
else
@@ -646,7 +647,7 @@ static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr)
/* Set up some convenience pointers. */
mibattr = &dot11req.mibattribute;
- macaddr = (p80211item_pstr6_t *) & mibattr->data;
+ macaddr = (p80211item_pstr6_t *) &mibattr->data;
resultcode = &dot11req.resultcode;
/* Set up a dot11req_mibset */
@@ -674,7 +675,7 @@ static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr)
resultcode->data = 0;
/* now fire the request */
- result = p80211req_dorequest(dev->ml_priv, (u8 *) & dot11req);
+ result = p80211req_dorequest(dev->ml_priv, (u8 *) &dot11req);
/* If the request wasn't successful, report an error and don't
* change the netdev address
diff --git a/drivers/staging/wlan-ng/p80211netdev.h b/drivers/staging/wlan-ng/p80211netdev.h
index 8bd9dfb3b9b4..3c8c64800567 100644
--- a/drivers/staging/wlan-ng/p80211netdev.h
+++ b/drivers/staging/wlan-ng/p80211netdev.h
@@ -179,16 +179,16 @@ typedef struct wlandevice {
unsigned int ethconv;
/* device methods (init by MSD, used by p80211 */
- int (*open) (struct wlandevice * wlandev);
- int (*close) (struct wlandevice * wlandev);
- void (*reset) (struct wlandevice * wlandev);
- int (*txframe) (struct wlandevice * wlandev, struct sk_buff * skb,
- p80211_hdr_t * p80211_hdr,
- p80211_metawep_t * p80211_wep);
- int (*mlmerequest) (struct wlandevice * wlandev, p80211msg_t * msg);
- int (*set_multicast_list) (struct wlandevice * wlandev,
- netdevice_t * dev);
- void (*tx_timeout) (struct wlandevice * wlandev);
+ int (*open) (struct wlandevice *wlandev);
+ int (*close) (struct wlandevice *wlandev);
+ void (*reset) (struct wlandevice *wlandev);
+ int (*txframe) (struct wlandevice *wlandev, struct sk_buff *skb,
+ p80211_hdr_t *p80211_hdr,
+ p80211_metawep_t *p80211_wep);
+ int (*mlmerequest) (struct wlandevice *wlandev, p80211msg_t *msg);
+ int (*set_multicast_list) (struct wlandevice *wlandev,
+ netdevice_t *dev);
+ void (*tx_timeout) (struct wlandevice *wlandev);
/* 802.11 State */
u8 bssid[WLAN_BSSID_LEN];
@@ -227,16 +227,16 @@ typedef struct wlandevice {
} wlandevice_t;
/* WEP stuff */
-int wep_change_key(wlandevice_t * wlandev, int keynum, u8 * key, int keylen);
-int wep_decrypt(wlandevice_t * wlandev, u8 * buf, u32 len, int key_override,
- u8 * iv, u8 * icv);
-int wep_encrypt(wlandevice_t * wlandev, u8 * buf, u8 * dst, u32 len, int keynum,
- u8 * iv, u8 * icv);
-
-int wlan_setup(wlandevice_t * wlandev);
-int wlan_unsetup(wlandevice_t * wlandev);
-int register_wlandev(wlandevice_t * wlandev);
-int unregister_wlandev(wlandevice_t * wlandev);
-void p80211netdev_rx(wlandevice_t * wlandev, struct sk_buff *skb);
-void p80211netdev_hwremoved(wlandevice_t * wlandev);
+int wep_change_key(wlandevice_t *wlandev, int keynum, u8 *key, int keylen);
+int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override,
+ u8 *iv, u8 *icv);
+int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum,
+ u8 *iv, u8 *icv);
+
+int wlan_setup(wlandevice_t *wlandev);
+int wlan_unsetup(wlandevice_t *wlandev);
+int register_wlandev(wlandevice_t *wlandev);
+int unregister_wlandev(wlandevice_t *wlandev);
+void p80211netdev_rx(wlandevice_t *wlandev, struct sk_buff *skb);
+void p80211netdev_hwremoved(wlandevice_t *wlandev);
#endif
diff --git a/drivers/staging/wlan-ng/p80211req.c b/drivers/staging/wlan-ng/p80211req.c
index c88156cdf681..c2e95f166828 100644
--- a/drivers/staging/wlan-ng/p80211req.c
+++ b/drivers/staging/wlan-ng/p80211req.c
@@ -94,7 +94,7 @@ static int p80211req_mibset_mibget(wlandevice_t *wlandev,
* Potentially blocks the caller, so it's a good idea to
* not call this function from an interrupt context.
----------------------------------------------------------------*/
-int p80211req_dorequest(wlandevice_t * wlandev, u8 * msgbuf)
+int p80211req_dorequest(wlandevice_t *wlandev, u8 *msgbuf)
{
int result = 0;
p80211msg_t *msg = (p80211msg_t *) msgbuf;
diff --git a/drivers/staging/wlan-ng/p80211req.h b/drivers/staging/wlan-ng/p80211req.h
index 5d9176762ba7..a95a45a6814d 100644
--- a/drivers/staging/wlan-ng/p80211req.h
+++ b/drivers/staging/wlan-ng/p80211req.h
@@ -48,6 +48,6 @@
#ifndef _LINUX_P80211REQ_H
#define _LINUX_P80211REQ_H
-int p80211req_dorequest(wlandevice_t * wlandev, u8 * msgbuf);
+int p80211req_dorequest(wlandevice_t *wlandev, u8 *msgbuf);
#endif
diff --git a/drivers/staging/wlan-ng/p80211types.h b/drivers/staging/wlan-ng/p80211types.h
index 2b83ab0c711b..41a99c59c6c5 100644
--- a/drivers/staging/wlan-ng/p80211types.h
+++ b/drivers/staging/wlan-ng/p80211types.h
@@ -168,12 +168,12 @@
P80211DID_MASK_ISTABLE, \
P80211DID_LSB_ISTABLE)
-#define P80211DID_MKID(s,g,i,n,t,a) (P80211DID_MKSECTION(s) | \
- P80211DID_MKGROUP(g) | \
- P80211DID_MKITEM(i) | \
- P80211DID_MKINDEX(n) | \
- P80211DID_MKISTABLE(t) | \
- (a))
+#define P80211DID_MKID(s, g, i, n, t, a) (P80211DID_MKSECTION(s) | \
+ P80211DID_MKGROUP(g) | \
+ P80211DID_MKITEM(i) | \
+ P80211DID_MKINDEX(n) | \
+ P80211DID_MKISTABLE(t) | \
+ (a))
#define P80211DID_GET(a, m, l) ((((u32)(a)) >> (l)) & (m))
@@ -340,11 +340,11 @@ struct catlistitem;
/* metadata items. Some components may choose to use more, */
/* less or different metadata items. */
-typedef void (*p80211_totext_t) (struct catlistitem *, u32 did, u8 * itembuf,
+typedef void (*p80211_totext_t) (struct catlistitem *, u32 did, u8 *itembuf,
char *textbuf);
-typedef void (*p80211_fromtext_t) (struct catlistitem *, u32 did, u8 * itembuf,
+typedef void (*p80211_fromtext_t) (struct catlistitem *, u32 did, u8 *itembuf,
char *textbuf);
-typedef u32(*p80211_valid_t) (struct catlistitem *, u32 did, u8 * itembuf);
+typedef u32(*p80211_valid_t) (struct catlistitem *, u32 did, u8 *itembuf);
/*----------------------------------------------------------------*/
/* Enumeration Lists */
diff --git a/drivers/staging/wlan-ng/p80211wext.c b/drivers/staging/wlan-ng/p80211wext.c
index 74d8022adb24..2fa1dfa23783 100644
--- a/drivers/staging/wlan-ng/p80211wext.c
+++ b/drivers/staging/wlan-ng/p80211wext.c
@@ -46,8 +46,8 @@
#include <linux/wireless.h>
#include <net/iw_handler.h>
#include <linux/if_arp.h>
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
+#include <linux/bitops.h>
+#include <linux/uaccess.h>
#include <asm/byteorder.h>
#include <linux/if_ether.h>
#include <linux/bitops.h>
@@ -134,10 +134,11 @@ static int p80211wext_dorequest(wlandevice_t *wlandev, u32 did, u32 data)
int result;
msg.msgcode = DIDmsg_dot11req_mibset;
+ memset(&mibitem, 0, sizeof(mibitem));
mibitem.did = did;
mibitem.data = data;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
return result;
}
@@ -174,7 +175,7 @@ static int p80211wext_autojoin(wlandevice_t *wlandev)
memcpy(msg.ssid.data.data, ssid, data.length);
msg.ssid.data.len = data.length;
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -211,7 +212,7 @@ struct iw_statistics *p80211wext_get_wireless_stats(netdevice_t *dev)
if (wlandev->mlmerequest == NULL)
return NULL;
- retval = wlandev->mlmerequest(wlandev, (p80211msg_t *) & quality);
+ retval = wlandev->mlmerequest(wlandev, (p80211msg_t *) &quality);
wstats->qual.qual = qual_as_percent(quality.link.data); /* overall link quality */
wstats->qual.level = quality.level.data; /* instant signal level */
@@ -269,9 +270,10 @@ static int p80211wext_giwfreq(netdevice_t *dev,
int err = 0;
msg.msgcode = DIDmsg_dot11req_mibget;
+ memset(&mibitem, 0, sizeof(mibitem));
mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -309,6 +311,7 @@ static int p80211wext_siwfreq(netdevice_t *dev,
}
msg.msgcode = DIDmsg_dot11req_mibset;
+ memset(&mibitem, 0, sizeof(mibitem));
mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel;
mibitem.status = P80211ENUM_msgitem_status_data_ok;
@@ -318,7 +321,7 @@ static int p80211wext_siwfreq(netdevice_t *dev,
mibitem.data = p80211_mhz_to_channel(freq->m);
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -396,10 +399,11 @@ static int p80211wext_siwmode(netdevice_t *dev,
/* Set Operation mode to the PORT TYPE RID */
msg.msgcode = DIDmsg_dot11req_mibset;
+ memset(&mibitem, 0, sizeof(mibitem));
mibitem.did = DIDmib_p2_p2Static_p2CnfPortType;
mibitem.data = (*mode == IW_MODE_ADHOC) ? 0 : 1;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result)
err = -EFAULT;
@@ -549,14 +553,14 @@ static int p80211wext_siwencode(netdevice_t *dev,
}
/* Check the Key index first. */
- if ((i = (erq->flags & IW_ENCODE_INDEX))) {
-
+ i = (erq->flags & IW_ENCODE_INDEX);
+ if (i) {
if ((i < 1) || (i > NUM_WEPKEYS)) {
err = -EINVAL;
goto exit;
- } else
+ } else {
i--;
-
+ }
/* Set current key number only if no keys are given */
if (erq->flags & IW_ENCODE_NOKEY) {
result =
@@ -621,7 +625,7 @@ static int p80211wext_siwencode(netdevice_t *dev,
msg.msgcode = DIDmsg_dot11req_mibset;
memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -729,7 +733,7 @@ static int p80211wext_siwessid(netdevice_t *dev,
msg.ssid.data.len = length;
pr_debug("autojoin_ssid for %s \n", essid);
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
pr_debug("autojoin_ssid %d\n", result);
if (result) {
@@ -771,9 +775,10 @@ static int p80211wext_giwrate(netdevice_t *dev,
int err = 0;
msg.msgcode = DIDmsg_dot11req_mibget;
+ memset(&mibitem, 0, sizeof(mibitem));
mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -822,9 +827,10 @@ static int p80211wext_giwrts(netdevice_t *dev,
int err = 0;
msg.msgcode = DIDmsg_dot11req_mibget;
+ memset(&mibitem, 0, sizeof(mibitem));
mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -857,6 +863,7 @@ static int p80211wext_siwrts(netdevice_t *dev,
}
msg.msgcode = DIDmsg_dot11req_mibget;
+ memset(&mibitem, 0, sizeof(mibitem));
mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold;
if (rts->disabled)
mibitem.data = 2347;
@@ -864,7 +871,7 @@ static int p80211wext_siwrts(netdevice_t *dev,
mibitem.data = rts->value;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -886,10 +893,11 @@ static int p80211wext_giwfrag(netdevice_t *dev,
int err = 0;
msg.msgcode = DIDmsg_dot11req_mibget;
+ memset(&mibitem, 0, sizeof(mibitem));
mibitem.did =
DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -922,6 +930,7 @@ static int p80211wext_siwfrag(netdevice_t *dev,
}
msg.msgcode = DIDmsg_dot11req_mibset;
+ memset(&mibitem, 0, sizeof(mibitem));
mibitem.did =
DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold;
@@ -931,7 +940,7 @@ static int p80211wext_siwfrag(netdevice_t *dev,
mibitem.data = frag->value;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -962,10 +971,11 @@ static int p80211wext_giwretry(netdevice_t *dev,
u16 shortretry, longretry, lifetime;
msg.msgcode = DIDmsg_dot11req_mibget;
+ memset(&mibitem, 0, sizeof(mibitem));
mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -979,7 +989,7 @@ static int p80211wext_giwretry(netdevice_t *dev,
mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -994,7 +1004,7 @@ static int p80211wext_giwretry(netdevice_t *dev,
DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -1037,6 +1047,8 @@ static int p80211wext_siwretry(netdevice_t *dev,
int result;
int err = 0;
+ memset(&mibitem, 0, sizeof(mibitem));
+
if (!wlan_wext_write) {
err = (-EOPNOTSUPP);
goto exit;
@@ -1055,7 +1067,7 @@ static int p80211wext_siwretry(netdevice_t *dev,
mibitem.data = rrq->value /= 1024;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -1069,7 +1081,7 @@ static int p80211wext_siwretry(netdevice_t *dev,
memcpy(&msg.mibattribute.data, &mibitem,
sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -1084,7 +1096,7 @@ static int p80211wext_siwretry(netdevice_t *dev,
memcpy(&msg.mibattribute.data, &mibitem,
sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -1114,6 +1126,7 @@ static int p80211wext_siwtxpow(netdevice_t *dev,
}
msg.msgcode = DIDmsg_dot11req_mibset;
+ memset(&mibitem, 0, sizeof(mibitem));
mibitem.did =
DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
if (rrq->fixed == 0)
@@ -1121,7 +1134,7 @@ static int p80211wext_siwtxpow(netdevice_t *dev,
else
mibitem.data = rrq->value;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -1143,11 +1156,13 @@ static int p80211wext_giwtxpow(netdevice_t *dev,
int err = 0;
msg.msgcode = DIDmsg_dot11req_mibget;
+
+ memset(&mibitem, 0, sizeof(mibitem));
mibitem.did =
DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result) {
err = -EFAULT;
@@ -1295,7 +1310,7 @@ static int p80211wext_siwscan(netdevice_t *dev,
msg.maxchanneltime.data = 250;
msg.minchanneltime.data = 200;
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if (result)
err = prism2_result2err(msg.resultcode.data);
@@ -1414,7 +1429,7 @@ static int p80211wext_giwscan(netdevice_t *dev,
msg.msgcode = DIDmsg_dot11req_scan_results;
msg.bssindex.data = i;
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
if ((result != 0) ||
(msg.resultcode.data != P80211ENUM_resultcode_success)) {
break;
@@ -1489,7 +1504,7 @@ static int p80211wext_set_encodeext(struct net_device *dev,
memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len);
memset(&msg, 0, sizeof(msg));
- pstr = (p80211item_pstr32_t *) & msg.mibattribute.data;
+ pstr = (p80211item_pstr32_t *) &msg.mibattribute.data;
memcpy(pstr->data.data, ext->key, ext->key_len);
pstr->data.len = ext->key_len;
switch (idx) {
@@ -1513,7 +1528,7 @@ static int p80211wext_set_encodeext(struct net_device *dev,
break;
}
msg.msgcode = DIDmsg_dot11req_mibset;
- result = p80211req_dorequest(wlandev, (u8 *) & msg);
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
pr_debug("result (%d)\n", result);
}
return result;
@@ -1729,15 +1744,11 @@ static iw_handler p80211wext_handlers[] = {
struct iw_handler_def p80211wext_handler_def = {
.num_standard = ARRAY_SIZE(p80211wext_handlers),
- .num_private = 0,
- .num_private_args = 0,
.standard = p80211wext_handlers,
- .private = NULL,
- .private_args = NULL,
.get_wireless_stats = p80211wext_get_wireless_stats
};
-int p80211wext_event_associated(wlandevice_t * wlandev, int assoc)
+int p80211wext_event_associated(wlandevice_t *wlandev, int assoc)
{
union iwreq_data data;
diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c
index aaa70ed57710..4be54cea6ad7 100644
--- a/drivers/staging/wlan-ng/prism2fw.c
+++ b/drivers/staging/wlan-ng/prism2fw.c
@@ -53,6 +53,7 @@
/* Local Constants */
#define PRISM2_USB_FWFILE "prism2_ru.fw"
+MODULE_FIRMWARE(PRISM2_USB_FWFILE);
#define S3DATA_MAX 5000
#define S3PLUG_MAX 200
@@ -108,9 +109,9 @@ typedef struct pda {
} pda_t;
typedef struct imgchunk {
- u32 addr; /* start address */
- u32 len; /* in bytes */
- u16 crc; /* CRC value (if it falls at a chunk boundary) */
+ u32 addr; /* start address */
+ u32 len; /* in bytes */
+ u16 crc; /* CRC value (if it falls at a chunk boundary) */
u8 *data;
} imgchunk_t;
@@ -204,7 +205,7 @@ int prism2_fwtry(struct usb_device *udev, wlandevice_t *wlandev)
return 1;
}
- printk(KERN_INFO "prism2_usb: %s will be processed, size %d\n",
+ printk(KERN_INFO "prism2_usb: %s will be processed, size %zu\n",
PRISM2_USB_FWFILE, fw_entry->size);
prism2_fwapply((const struct ihex_binrec *)fw_entry->data, wlandev);
@@ -264,7 +265,7 @@ int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev)
/* Build the PDA we're going to use. */
if (read_cardpda(&pda, wlandev)) {
printk(KERN_ERR "load_cardpda failed, exiting.\n");
- return (1);
+ return 1;
}
/* read the card's PRI-SUP */
@@ -286,9 +287,8 @@ int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev)
/* DIDmsg_dot11req_mibget */
prism2mgmt_mibset_mibget(wlandev, &getmsg);
- if (getmsg.resultcode.data != P80211ENUM_resultcode_success) {
+ if (getmsg.resultcode.data != P80211ENUM_resultcode_success)
printk(KERN_ERR "Couldn't fetch PRI-SUP info\n");
- }
/* Already in host order */
priid.role = *data++;
@@ -301,19 +301,19 @@ int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev)
result = read_fwfile(rfptr);
if (result) {
printk(KERN_ERR "Failed to read the data exiting.\n");
- return (1);
+ return 1;
}
result = validate_identity();
if (result) {
printk(KERN_ERR "Incompatible firmware image.\n");
- return (1);
+ return 1;
}
if (startaddr == 0x00000000) {
printk(KERN_ERR "Can't RAM download a Flash image!\n");
- return (1);
+ return 1;
}
/* Make the image chunks */
@@ -323,20 +323,20 @@ int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev)
result = plugimage(fchunk, nfchunks, s3plug, ns3plug, &pda);
if (result) {
printk(KERN_ERR "Failed to plug data.\n");
- return (1);
+ return 1;
}
/* Insert any CRCs */
if (crcimage(fchunk, nfchunks, s3crc, ns3crc)) {
printk(KERN_ERR "Failed to insert all CRCs\n");
- return (1);
+ return 1;
}
/* Write the image */
result = writeimage(wlandev, fchunk, nfchunks);
if (result) {
printk(KERN_ERR "Failed to ramwrite image data.\n");
- return (1);
+ return 1;
}
/* clear any allocated memory */
@@ -434,9 +434,8 @@ void free_chunks(imgchunk_t *fchunk, unsigned int *nfchunks)
{
int i;
for (i = 0; i < *nfchunks; i++) {
- if (fchunk[i].data != NULL) {
+ if (fchunk[i].data != NULL)
kfree(fchunk[i].data);
- }
}
*nfchunks = 0;
memset(fchunk, 0, sizeof(*fchunk));
@@ -531,7 +530,7 @@ int mkimage(imgchunk_t *clist, unsigned int *ccnt)
if (clist[i].data == NULL) {
printk(KERN_ERR
"failed to allocate image space, exitting.\n");
- return (1);
+ return 1;
}
memset(clist[i].data, 0, clist[i].len);
pr_debug("chunk[%d]: addr=0x%06x len=%d\n",
@@ -545,15 +544,14 @@ int mkimage(imgchunk_t *clist, unsigned int *ccnt)
for (j = 0; j < *ccnt; j++) {
cstart = clist[j].addr;
cend = cstart + clist[j].len - 1;
- if (s3start >= cstart && s3end <= cend) {
+ if (s3start >= cstart && s3end <= cend)
break;
- }
}
if (((unsigned int)j) >= (*ccnt)) {
printk(KERN_ERR
"s3rec(a=0x%06x,l=%d), no chunk match, exiting.\n",
s3start, s3data[i].len);
- return (1);
+ return 1;
}
coffset = s3start - cstart;
memcpy(clist[j].data + coffset, s3data[i].data, s3data[i].len);
@@ -586,7 +584,7 @@ int mkpdrlist(pda_t *pda)
curroff = 0;
while (curroff < (HFA384x_PDA_LEN_MAX / 2) &&
le16_to_cpu(pda16[curroff + 1]) != HFA384x_PDR_END_OF_PDA) {
- pda->rec[pda->nrec] = (hfa384x_pdrec_t *) & (pda16[curroff]);
+ pda->rec[pda->nrec] = (hfa384x_pdrec_t *) &(pda16[curroff]);
if (le16_to_cpu(pda->rec[pda->nrec]->code) == HFA384x_PDR_NICID) {
memcpy(&nicid, &pda->rec[pda->nrec]->data.nicid,
@@ -623,10 +621,10 @@ int mkpdrlist(pda_t *pda)
printk(KERN_ERR
"no end record found or invalid lengths in "
"PDR data, exiting. %x %d\n", curroff, pda->nrec);
- return (1);
+ return 1;
}
if (le16_to_cpu(pda16[curroff + 1]) == HFA384x_PDR_END_OF_PDA) {
- pda->rec[pda->nrec] = (hfa384x_pdrec_t *) & (pda16[curroff]);
+ pda->rec[pda->nrec] = (hfa384x_pdrec_t *) &(pda16[curroff]);
(pda->nrec)++;
}
return result;
@@ -869,7 +867,7 @@ int read_fwfile(const struct ihex_binrec *record)
ptr16 = (u16 *) record->data;
/* parse what was an S3 srec and put it in the right array */
- switch(addr) {
+ switch (addr) {
case S3ADDR_START:
startaddr = *ptr32;
pr_debug(" S7 start addr, record=%d "
@@ -890,7 +888,7 @@ int read_fwfile(const struct ihex_binrec *record)
s3plug[ns3plug].len);
ns3plug++;
- if ( ns3plug == S3PLUG_MAX ) {
+ if (ns3plug == S3PLUG_MAX) {
printk(KERN_ERR "S3 plugrec limit reached - aborting\n");
return 1;
}
@@ -907,7 +905,7 @@ int read_fwfile(const struct ihex_binrec *record)
s3crc[ns3crc].len,
s3crc[ns3crc].dowrite);
ns3crc++;
- if ( ns3crc == S3CRC_MAX ) {
+ if (ns3crc == S3CRC_MAX) {
printk(KERN_ERR "S3 crcrec limit reached - aborting\n");
return 1;
}
@@ -921,12 +919,12 @@ int read_fwfile(const struct ihex_binrec *record)
rcnt,
s3info[ns3info].len,
s3info[ns3info].type);
- if ( ((s3info[ns3info].len - 1) * sizeof(u16)) > sizeof(s3info[ns3info].info) ) {
+ if (((s3info[ns3info].len - 1) * sizeof(u16)) > sizeof(s3info[ns3info].info)) {
printk(KERN_ERR " S3 inforec length too long - aborting\n");
return 1;
}
- tmpinfo = (u16*)&(s3info[ns3info].info.version);
+ tmpinfo = (u16 *)&(s3info[ns3info].info.version);
pr_debug(" info=");
for (i = 0; i < s3info[ns3info].len - 1; i++) {
tmpinfo[i] = *(ptr16 + 2 + i);
@@ -935,7 +933,7 @@ int read_fwfile(const struct ihex_binrec *record)
pr_debug("\n");
ns3info++;
- if ( ns3info == S3INFO_MAX ) {
+ if (ns3info == S3INFO_MAX) {
printk(KERN_ERR "S3 inforec limit reached - aborting\n");
return 1;
}
@@ -945,7 +943,7 @@ int read_fwfile(const struct ihex_binrec *record)
s3data[ns3data].len = len;
s3data[ns3data].data = (uint8_t *) record->data;
ns3data++;
- if ( ns3data == S3DATA_MAX ) {
+ if (ns3data == S3DATA_MAX) {
printk(KERN_ERR "S3 datarec limit reached - aborting\n");
return 1;
}
@@ -1023,7 +1021,7 @@ int writeimage(wlandevice_t *wlandev, imgchunk_t *fchunk,
rstatemsg.enable.data = P80211ENUM_truth_true;
rstatemsg.exeaddr.data = startaddr;
- msgp = (p80211msg_t *) & rstatemsg;
+ msgp = (p80211msg_t *) &rstatemsg;
result = prism2mgmt_ramdl_state(wlandev, msgp);
if (result) {
printk(KERN_ERR
@@ -1063,7 +1061,7 @@ int writeimage(wlandevice_t *wlandev, imgchunk_t *fchunk,
("Sending xxxdl_write message addr=%06x len=%d.\n",
currdaddr, currlen);
- msgp = (p80211msg_t *) & rwritemsg;
+ msgp = (p80211msg_t *) &rwritemsg;
result = prism2mgmt_ramdl_write(wlandev, msgp);
/* Check the results */
@@ -1090,7 +1088,7 @@ int writeimage(wlandevice_t *wlandev, imgchunk_t *fchunk,
rstatemsg.enable.data = P80211ENUM_truth_false;
rstatemsg.exeaddr.data = 0;
- msgp = (p80211msg_t *) & rstatemsg;
+ msgp = (p80211msg_t *) &rstatemsg;
result = prism2mgmt_ramdl_state(wlandev, msgp);
if (result) {
printk(KERN_ERR
@@ -1161,7 +1159,7 @@ int validate_identity(void)
/* SEC compat range */
if ((s3info[i].info.compat.role == 1) &&
(s3info[i].info.compat.id == 4)) {
-
+ /* FIXME: isn't something missing here? */
}
break;
@@ -1196,8 +1194,9 @@ int validate_identity(void)
pr_debug("Unknown inforec type %d\n", s3info[i].type);
}
}
- // walk through
+ /* walk through */
- if (trump && (result != 2)) result = 0;
+ if (trump && (result != 2))
+ result = 0;
return result;
}
diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c
index 9f7d96cae8e3..ad163da72ae4 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.c
+++ b/drivers/staging/wlan-ng/prism2mgmt.c
@@ -67,7 +67,7 @@
#include <linux/wireless.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/byteorder.h>
#include <linux/random.h>
#include <linux/usb.h>
@@ -541,7 +541,7 @@ int prism2mgmt_start(wlandevice_t *wlandev, void *msgp)
/*** STATION ***/
/* Set the REQUIRED config items */
/* SSID */
- pstr = (p80211pstrd_t *) & (msg->ssid.data);
+ pstr = (p80211pstrd_t *) &(msg->ssid.data);
prism2mgmt_pstr2bytestr(p2bytestr, pstr);
result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID,
bytebuf, HFA384x_RID_CNFOWNSSID_LEN);
@@ -1034,7 +1034,7 @@ int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp)
/* Set the ssid */
memset(bytebuf, 0, 256);
- pstr = (p80211pstrd_t *) & (msg->ssid.data);
+ pstr = (p80211pstrd_t *) &(msg->ssid.data);
prism2mgmt_pstr2bytestr(p2bytestr, pstr);
result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID,
bytebuf,
@@ -1123,8 +1123,8 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp)
if (hw->presniff_port_type != 0) {
word = hw->presniff_port_type;
result = hfa384x_drvr_setconfig16(hw,
- HFA384x_RID_CNFPORTTYPE,
- word);
+ HFA384x_RID_CNFPORTTYPE,
+ word);
if (result) {
pr_debug
("failed to restore porttype, result=%d\n",
@@ -1156,10 +1156,8 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp)
if (wlandev->netdev->type == ARPHRD_ETHER) {
/* Save macport 0 state */
result = hfa384x_drvr_getconfig16(hw,
- HFA384x_RID_CNFPORTTYPE,
- &
- (hw->
- presniff_port_type));
+ HFA384x_RID_CNFPORTTYPE,
+ &(hw->presniff_port_type));
if (result) {
pr_debug
("failed to read porttype, result=%d\n",
@@ -1168,10 +1166,8 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp)
}
/* Save the wepflags state */
result = hfa384x_drvr_getconfig16(hw,
- HFA384x_RID_CNFWEPFLAGS,
- &
- (hw->
- presniff_wepflags));
+ HFA384x_RID_CNFWEPFLAGS,
+ &(hw->presniff_wepflags));
if (result) {
pr_debug
("failed to read wepflags, result=%d\n",
@@ -1218,8 +1214,8 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp)
/* Set the port type to pIbss */
word = HFA384x_PORTTYPE_PSUEDOIBSS;
result = hfa384x_drvr_setconfig16(hw,
- HFA384x_RID_CNFPORTTYPE,
- word);
+ HFA384x_RID_CNFPORTTYPE,
+ word);
if (result) {
pr_debug
("failed to set porttype %d, result=%d\n",
@@ -1235,8 +1231,8 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp)
HFA384x_WEPFLAGS_DISABLE_RXCRYPT;
result =
hfa384x_drvr_setconfig16(hw,
- HFA384x_RID_CNFWEPFLAGS,
- word);
+ HFA384x_RID_CNFWEPFLAGS,
+ word);
}
if (result) {
diff --git a/drivers/staging/wlan-ng/prism2mgmt.h b/drivers/staging/wlan-ng/prism2mgmt.h
index bdf2b3e03253..07eecebeb6cc 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.h
+++ b/drivers/staging/wlan-ng/prism2mgmt.h
@@ -63,43 +63,43 @@
extern int prism2_reset_holdtime;
extern int prism2_reset_settletime;
-u32 prism2sta_ifstate(wlandevice_t * wlandev, u32 ifstate);
+u32 prism2sta_ifstate(wlandevice_t *wlandev, u32 ifstate);
-void prism2sta_ev_info(wlandevice_t * wlandev, hfa384x_InfFrame_t * inf);
-void prism2sta_ev_txexc(wlandevice_t * wlandev, u16 status);
-void prism2sta_ev_tx(wlandevice_t * wlandev, u16 status);
-void prism2sta_ev_rx(wlandevice_t * wlandev, struct sk_buff *skb);
-void prism2sta_ev_alloc(wlandevice_t * wlandev);
+void prism2sta_ev_info(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf);
+void prism2sta_ev_txexc(wlandevice_t *wlandev, u16 status);
+void prism2sta_ev_tx(wlandevice_t *wlandev, u16 status);
+void prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb);
+void prism2sta_ev_alloc(wlandevice_t *wlandev);
-int prism2mgmt_mibset_mibget(wlandevice_t * wlandev, void *msgp);
-int prism2mgmt_scan(wlandevice_t * wlandev, void *msgp);
-int prism2mgmt_scan_results(wlandevice_t * wlandev, void *msgp);
-int prism2mgmt_start(wlandevice_t * wlandev, void *msgp);
-int prism2mgmt_wlansniff(wlandevice_t * wlandev, void *msgp);
-int prism2mgmt_readpda(wlandevice_t * wlandev, void *msgp);
-int prism2mgmt_ramdl_state(wlandevice_t * wlandev, void *msgp);
-int prism2mgmt_ramdl_write(wlandevice_t * wlandev, void *msgp);
-int prism2mgmt_flashdl_state(wlandevice_t * wlandev, void *msgp);
-int prism2mgmt_flashdl_write(wlandevice_t * wlandev, void *msgp);
-int prism2mgmt_autojoin(wlandevice_t * wlandev, void *msgp);
+int prism2mgmt_mibset_mibget(wlandevice_t *wlandev, void *msgp);
+int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp);
+int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp);
+int prism2mgmt_start(wlandevice_t *wlandev, void *msgp);
+int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp);
+int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp);
+int prism2mgmt_ramdl_state(wlandevice_t *wlandev, void *msgp);
+int prism2mgmt_ramdl_write(wlandevice_t *wlandev, void *msgp);
+int prism2mgmt_flashdl_state(wlandevice_t *wlandev, void *msgp);
+int prism2mgmt_flashdl_write(wlandevice_t *wlandev, void *msgp);
+int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp);
/*---------------------------------------------------------------
* conversion functions going between wlan message data types and
* Prism2 data types
---------------------------------------------------------------*/
/* byte area conversion functions*/
-void prism2mgmt_pstr2bytearea(u8 * bytearea, p80211pstrd_t * pstr);
-void prism2mgmt_bytearea2pstr(u8 * bytearea, p80211pstrd_t * pstr, int len);
+void prism2mgmt_pstr2bytearea(u8 *bytearea, p80211pstrd_t *pstr);
+void prism2mgmt_bytearea2pstr(u8 *bytearea, p80211pstrd_t *pstr, int len);
/* byte string conversion functions*/
-void prism2mgmt_pstr2bytestr(hfa384x_bytestr_t * bytestr, p80211pstrd_t * pstr);
-void prism2mgmt_bytestr2pstr(hfa384x_bytestr_t * bytestr, p80211pstrd_t * pstr);
+void prism2mgmt_pstr2bytestr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr);
+void prism2mgmt_bytestr2pstr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr);
/* functions to convert Group Addresses */
-void prism2mgmt_get_grpaddr(u32 did, p80211pstrd_t * pstr, hfa384x_t * priv);
+void prism2mgmt_get_grpaddr(u32 did, p80211pstrd_t *pstr, hfa384x_t *priv);
int prism2mgmt_set_grpaddr(u32 did,
- u8 * prism2buf, p80211pstrd_t * pstr,
- hfa384x_t * priv);
+ u8 *prism2buf, p80211pstrd_t *pstr,
+ hfa384x_t *priv);
int prism2mgmt_get_grpaddr_index(u32 did);
void prism2sta_processing_defer(struct work_struct *data);
diff --git a/drivers/staging/wlan-ng/prism2mib.c b/drivers/staging/wlan-ng/prism2mib.c
index 2fff0a110bcb..98a5d58c3f55 100644
--- a/drivers/staging/wlan-ng/prism2mib.c
+++ b/drivers/staging/wlan-ng/prism2mib.c
@@ -114,7 +114,7 @@ static int prism2mib_flag(mibrec_t *mib,
static int prism2mib_wepdefaultkey(mibrec_t *mib,
int isget,
- wlandevice_t * wlandev,
+ wlandevice_t *wlandev,
hfa384x_t *hw,
p80211msg_dot11req_mibset_t *msg,
void *data);
@@ -726,7 +726,7 @@ static int prism2mib_priv(mibrec_t *mib,
if (isget) {
hfa384x_drvr_getconfig(hw,
HFA384x_RID_CNFWPADATA,
- (u8 *) & wpa,
+ (u8 *) &wpa,
sizeof(wpa));
pstr->len = le16_to_cpu(wpa.datalen);
memcpy(pstr->data, wpa.data, pstr->len);
@@ -736,9 +736,9 @@ static int prism2mib_priv(mibrec_t *mib,
result =
hfa384x_drvr_setconfig(hw,
- HFA384x_RID_CNFWPADATA,
- (u8 *) & wpa,
- sizeof(wpa));
+ HFA384x_RID_CNFWPADATA,
+ (u8 *) &wpa,
+ sizeof(wpa));
}
break;
}
diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c
index 50f301d65212..31ac8da39c81 100644
--- a/drivers/staging/wlan-ng/prism2sta.c
+++ b/drivers/staging/wlan-ng/prism2sta.c
@@ -64,7 +64,7 @@
#include <linux/byteorder/generic.h>
#include <linux/ctype.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <asm/byteorder.h>
#include <linux/if_arp.h>
@@ -1023,13 +1023,13 @@ static void prism2sta_inf_tallies(wlandevice_t *wlandev,
cnt = sizeof(hfa384x_CommTallies32_t) / sizeof(u32);
if (inf->framelen > 22) {
- dst = (u32 *) & hw->tallies;
- src32 = (u32 *) & inf->info.commtallies32;
+ dst = (u32 *) &hw->tallies;
+ src32 = (u32 *) &inf->info.commtallies32;
for (i = 0; i < cnt; i++, dst++, src32++)
*dst += le32_to_cpu(*src32);
} else {
- dst = (u32 *) & hw->tallies;
- src16 = (u16 *) & inf->info.commtallies16;
+ dst = (u32 *) &hw->tallies;
+ src16 = (u16 *) &inf->info.commtallies16;
for (i = 0; i < cnt; i++, dst++, src16++)
*dst += le16_to_cpu(*src16);
}
@@ -1280,7 +1280,7 @@ void prism2sta_processing_defer(struct work_struct *data)
HFA384x_RID_CURRENTSSID, result);
goto failed;
}
- prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) & ssid,
+ prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) &ssid,
(p80211pstrd_t *) &
wlandev->ssid);
@@ -1368,8 +1368,8 @@ void prism2sta_processing_defer(struct work_struct *data)
HFA384x_RID_CURRENTSSID, result);
goto failed;
}
- prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) & ssid,
- (p80211pstrd_t *) & wlandev->ssid);
+ prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) &ssid,
+ (p80211pstrd_t *) &wlandev->ssid);
hw->link_status = HFA384x_LINK_CONNECTED;
netif_carrier_on(wlandev->netdev);
@@ -2028,8 +2028,8 @@ void prism2sta_commsqual_defer(struct work_struct *data)
HFA384x_RID_CURRENTSSID, result);
goto done;
}
- prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) & ssid,
- (p80211pstrd_t *) & wlandev->ssid);
+ prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) &ssid,
+ (p80211pstrd_t *) &wlandev->ssid);
/* Reschedule timer */
mod_timer(&hw->commsqual_timer, jiffies + HZ);
diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c
index 9dde68be8d74..501d27f74c7d 100644
--- a/drivers/staging/wlan-ng/prism2usb.c
+++ b/drivers/staging/wlan-ng/prism2usb.c
@@ -24,8 +24,9 @@ static struct usb_device_id usb_prism_tbl[] = {
(0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps WLAN USB Adapter")},
{PRISM_USB_DEVICE
(0x067c, 0x1022, "Siemens SpeedStream 1022 11Mbps WLAN USB Adapter")},
- {PRISM_USB_DEVICE(0x049f, 0x0033,
- "Compaq/Intel W100 PRO/Wireless 11Mbps multiport WLAN Adapter")},
+ {PRISM_USB_DEVICE
+ (0x049f, 0x0033,
+ "Compaq/Intel W100 PRO/Wireless 11Mbps multiport WLAN Adapter")},
{PRISM_USB_DEVICE
(0x0411, 0x0016, "Melco WLI-USB-S11 11Mbps WLAN Adapter")},
{PRISM_USB_DEVICE
@@ -55,7 +56,6 @@ static struct usb_device_id usb_prism_tbl[] = {
(0x04f1, 0x3009, "JVC MP-XP7250 Builtin USB WLAN Adapter")},
{PRISM_USB_DEVICE(0x0846, 0x4110, "NetGear MA111")},
{PRISM_USB_DEVICE(0x03f3, 0x0020, "Adaptec AWN-8020 USB WLAN Adapter")},
-/* {PRISM_USB_DEVICE(0x0ace, 0x1201, "ZyDAS ZD1201 Wireless USB Adapter")}, */
{PRISM_USB_DEVICE(0x2821, 0x3300, "ASUS-WL140 Wireless USB Adapter")},
{PRISM_USB_DEVICE(0x2001, 0x3700, "DWL-122 Wireless USB Adapter")},
{PRISM_USB_DEVICE
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 8aa1955f35ed..1da73ecd9799 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -44,17 +44,6 @@ config UIO_PDRV_GENIRQ
If you don't know what to do here, say N.
-config UIO_SMX
- tristate "SMX cryptengine UIO interface"
- help
- Userspace IO interface to the Cryptography engine found on the
- Nias Digital SMX boards. These will be available from Q4 2008
- from http://www.niasdigital.com. The userspace part of this
- driver will be released under the GPL at the same time as the
- hardware and will be able to be downloaded from the same site.
-
- If you compile this as a module, it will be called uio_smx.
-
config UIO_AEC
tristate "AEC video timestamp device"
depends on PCI
@@ -74,6 +63,7 @@ config UIO_AEC
config UIO_SERCOS3
tristate "Automata Sercos III PCI card driver"
+ depends on PCI
help
Userspace I/O interface for the Sercos III PCI card from
Automata GmbH. The userspace part of this driver will be
@@ -87,11 +77,21 @@ config UIO_SERCOS3
config UIO_PCI_GENERIC
tristate "Generic driver for PCI 2.3 and PCI Express cards"
depends on PCI
- default n
help
Generic driver that you can bind, dynamically, to any
PCI 2.3 compliant and PCI Express card. It is useful,
primarily, for virtualization scenarios.
If you compile this as a module, it will be called uio_pci_generic.
+config UIO_NETX
+ tristate "Hilscher NetX Card driver"
+ depends on PCI
+ help
+ Driver for Hilscher NetX based fieldbus cards (cifX, comX).
+ This driver requires a userspace component that comes with the card
+ or is available from Hilscher (http://www.hilscher.com).
+
+ To compile this driver as a module, choose M here; the module
+ will be called uio_netx.
+
endif
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index 73b2e7516729..18fd818c5b97 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_UIO) += uio.o
obj-$(CONFIG_UIO_CIF) += uio_cif.o
obj-$(CONFIG_UIO_PDRV) += uio_pdrv.o
obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o
-obj-$(CONFIG_UIO_SMX) += uio_smx.o
obj-$(CONFIG_UIO_AEC) += uio_aec.o
obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o
obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o
+obj-$(CONFIG_UIO_NETX) += uio_netx.o
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index e941367dd28f..4de382acd8f2 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -129,7 +129,7 @@ static ssize_t map_type_show(struct kobject *kobj, struct attribute *attr,
return entry->show(mem, buf);
}
-static struct sysfs_ops map_sysfs_ops = {
+static const struct sysfs_ops map_sysfs_ops = {
.show = map_type_show,
};
@@ -217,7 +217,7 @@ static ssize_t portio_type_show(struct kobject *kobj, struct attribute *attr,
return entry->show(port, buf);
}
-static struct sysfs_ops portio_sysfs_ops = {
+static const struct sysfs_ops portio_sysfs_ops = {
.show = portio_type_show,
};
diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c
new file mode 100644
index 000000000000..afbf0bd55cc9
--- /dev/null
+++ b/drivers/uio/uio_netx.c
@@ -0,0 +1,172 @@
+/*
+ * UIO driver for Hilscher NetX based fieldbus cards (cifX, comX).
+ * See http://www.hilscher.com for details.
+ *
+ * (C) 2007 Hans J. Koch <hjk@linutronix.de>
+ * (C) 2008 Manuel Traut <manut@linutronix.de>
+ *
+ * Licensed under GPL version 2 only.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uio_driver.h>
+
+#define PCI_VENDOR_ID_HILSCHER 0x15CF
+#define PCI_DEVICE_ID_HILSCHER_NETX 0x0000
+#define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235
+#define PCI_SUBDEVICE_ID_NXPCA 0x3335
+
+#define DPM_HOST_INT_EN0 0xfff0
+#define DPM_HOST_INT_STAT0 0xffe0
+
+#define DPM_HOST_INT_MASK 0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN 0x80000000
+
+static irqreturn_t netx_handler(int irq, struct uio_info *dev_info)
+{
+ void __iomem *int_enable_reg = dev_info->mem[0].internal_addr
+ + DPM_HOST_INT_EN0;
+ void __iomem *int_status_reg = dev_info->mem[0].internal_addr
+ + DPM_HOST_INT_STAT0;
+
+ /* Is one of our interrupts enabled and active ? */
+ if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
+ & DPM_HOST_INT_MASK))
+ return IRQ_NONE;
+
+ /* Disable interrupt */
+ iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN,
+ int_enable_reg);
+ return IRQ_HANDLED;
+}
+
+static int __devinit netx_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct uio_info *info;
+ int bar;
+
+ info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ if (pci_enable_device(dev))
+ goto out_free;
+
+ if (pci_request_regions(dev, "netx"))
+ goto out_disable;
+
+ switch (id->device) {
+ case PCI_DEVICE_ID_HILSCHER_NETX:
+ bar = 0;
+ info->name = "netx";
+ break;
+ default:
+ bar = 2;
+ info->name = "netx_plx";
+ }
+
+ /* BAR0 or 2 points to the card's dual port memory */
+ info->mem[0].addr = pci_resource_start(dev, bar);
+ if (!info->mem[0].addr)
+ goto out_release;
+ info->mem[0].internal_addr = ioremap(pci_resource_start(dev, bar),
+ pci_resource_len(dev, bar));
+
+ if (!info->mem[0].internal_addr)
+ goto out_release;
+
+ info->mem[0].size = pci_resource_len(dev, bar);
+ info->mem[0].memtype = UIO_MEM_PHYS;
+ info->irq = dev->irq;
+ info->irq_flags = IRQF_SHARED;
+ info->handler = netx_handler;
+ info->version = "0.0.1";
+
+ /* Make sure all interrupts are disabled */
+ iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0);
+
+ if (uio_register_device(&dev->dev, info))
+ goto out_unmap;
+
+ pci_set_drvdata(dev, info);
+ dev_info(&dev->dev, "Found %s card, registered UIO device.\n",
+ info->name);
+
+ return 0;
+
+out_unmap:
+ iounmap(info->mem[0].internal_addr);
+out_release:
+ pci_release_regions(dev);
+out_disable:
+ pci_disable_device(dev);
+out_free:
+ kfree(info);
+ return -ENODEV;
+}
+
+static void netx_pci_remove(struct pci_dev *dev)
+{
+ struct uio_info *info = pci_get_drvdata(dev);
+
+ /* Disable all interrupts */
+ iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0);
+ uio_unregister_device(info);
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+ pci_set_drvdata(dev, NULL);
+ iounmap(info->mem[0].internal_addr);
+
+ kfree(info);
+}
+
+static struct pci_device_id netx_pci_ids[] = {
+ {
+ .vendor = PCI_VENDOR_ID_HILSCHER,
+ .device = PCI_DEVICE_ID_HILSCHER_NETX,
+ .subvendor = 0,
+ .subdevice = 0,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_9030,
+ .subvendor = PCI_VENDOR_ID_PLX,
+ .subdevice = PCI_SUBDEVICE_ID_NXSB_PCA,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_9030,
+ .subvendor = PCI_VENDOR_ID_PLX,
+ .subdevice = PCI_SUBDEVICE_ID_NXPCA,
+ },
+ { 0, }
+};
+
+static struct pci_driver netx_pci_driver = {
+ .name = "netx",
+ .id_table = netx_pci_ids,
+ .probe = netx_pci_probe,
+ .remove = netx_pci_remove,
+};
+
+static int __init netx_init_module(void)
+{
+ return pci_register_driver(&netx_pci_driver);
+}
+
+static void __exit netx_exit_module(void)
+{
+ pci_unregister_driver(&netx_pci_driver);
+}
+
+module_init(netx_init_module);
+module_exit(netx_exit_module);
+
+MODULE_DEVICE_TABLE(pci, netx_pci_ids);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Hans J. Koch, Manuel Traut");
diff --git a/drivers/uio/uio_smx.c b/drivers/uio/uio_smx.c
deleted file mode 100644
index 44054a650a8a..000000000000
--- a/drivers/uio/uio_smx.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * UIO SMX Cryptengine driver.
- *
- * (C) 2008 Nias Digital P/L <bn@niasdigital.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.
- *
- */
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/uio_driver.h>
-#include <linux/io.h>
-
-#define DRV_NAME "smx-ce"
-#define DRV_VERSION "0.03"
-
-#define SMX_CSR 0x00000000
-#define SMX_EnD 0x00000001
-#define SMX_RUN 0x00000002
-#define SMX_DRDY 0x00000004
-#define SMX_ERR 0x00000008
-
-static irqreturn_t smx_handler(int irq, struct uio_info *dev_info)
-{
- void __iomem *csr = dev_info->mem[0].internal_addr + SMX_CSR;
-
- u32 status = ioread32(csr);
-
- if (!(status & SMX_DRDY))
- return IRQ_NONE;
-
- /* Disable interrupt */
- iowrite32(status & ~SMX_DRDY, csr);
- return IRQ_HANDLED;
-}
-
-static int __devinit smx_ce_probe(struct platform_device *dev)
-{
-
- int ret = -ENODEV;
- struct uio_info *info;
- struct resource *regs;
-
- info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- regs = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!regs) {
- dev_err(&dev->dev, "No memory resource specified\n");
- goto out_free;
- }
-
- info->mem[0].addr = regs->start;
- if (!info->mem[0].addr) {
- dev_err(&dev->dev, "Invalid memory resource\n");
- goto out_free;
- }
-
- info->mem[0].size = regs->end - regs->start + 1;
- info->mem[0].internal_addr = ioremap(regs->start, info->mem[0].size);
-
- if (!info->mem[0].internal_addr) {
- dev_err(&dev->dev, "Can't remap memory address range\n");
- goto out_free;
- }
-
- info->mem[0].memtype = UIO_MEM_PHYS;
-
- info->name = "smx-ce";
- info->version = "0.03";
-
- info->irq = platform_get_irq(dev, 0);
- if (info->irq < 0) {
- ret = info->irq;
- dev_err(&dev->dev, "No (or invalid) IRQ resource specified\n");
- goto out_unmap;
- }
-
- info->irq_flags = IRQF_SHARED;
- info->handler = smx_handler;
-
- platform_set_drvdata(dev, info);
-
- ret = uio_register_device(&dev->dev, info);
-
- if (ret)
- goto out_unmap;
-
- return 0;
-
-out_unmap:
- iounmap(info->mem[0].internal_addr);
-out_free:
- kfree(info);
-
- return ret;
-}
-
-static int __devexit smx_ce_remove(struct platform_device *dev)
-{
- struct uio_info *info = platform_get_drvdata(dev);
-
- uio_unregister_device(info);
- platform_set_drvdata(dev, NULL);
- iounmap(info->mem[0].internal_addr);
-
- kfree(info);
-
- return 0;
-}
-
-static struct platform_driver smx_ce_driver = {
- .probe = smx_ce_probe,
- .remove = __devexit_p(smx_ce_remove),
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static int __init smx_ce_init_module(void)
-{
- return platform_driver_register(&smx_ce_driver);
-}
-module_init(smx_ce_init_module);
-
-static void __exit smx_ce_exit_module(void)
-{
- platform_driver_unregister(&smx_ce_driver);
-}
-module_exit(smx_ce_exit_module);
-
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR("Ben Nizette <bn@niasdigital.com>");
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 81aac7f4ca59..6a58cb1330c1 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -21,6 +21,7 @@ config USB_ARCH_HAS_HCD
default y if USB_ARCH_HAS_EHCI
default y if PCMCIA && !M32R # sl811_cs
default y if ARM # SL-811
+ default y if BLACKFIN # SL-811
default y if SUPERH # r8a66597-hcd
default PCI
@@ -39,6 +40,7 @@ config USB_ARCH_HAS_OHCI
default y if ARCH_PNX4008 && I2C
default y if MFD_TC6393XB
default y if ARCH_W90X900
+ default y if ARCH_DAVINCI_DA8XX
# PPC:
default y if STB03xxx
default y if PPC_MPC52xx
@@ -61,7 +63,7 @@ config USB_ARCH_HAS_EHCI
default y if ARCH_W90X900
default y if ARCH_AT91SAM9G45
default y if ARCH_MXC
- default y if ARCH_OMAP34XX
+ default y if ARCH_OMAP3
default PCI
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index be3c9b80bc9f..80b4008c89ba 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_HWA_HCD) += host/
obj-$(CONFIG_USB_ISP1760_HCD) += host/
+obj-$(CONFIG_USB_IMX21_HCD) += host/
obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 56802d2e994b..c89990f5e018 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -5,6 +5,7 @@
* Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan
* Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
* Copyright (C) 2007 Simon Arlott
+ * Copyright (C) 2009 Simon Arlott
*
* 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,7 +44,7 @@
#include "usbatm.h"
#define DRIVER_AUTHOR "Roman Kagan, David Woodhouse, Duncan Sands, Simon Arlott"
-#define DRIVER_VERSION "0.3"
+#define DRIVER_VERSION "0.4"
#define DRIVER_DESC "Conexant AccessRunner ADSL USB modem driver"
static const char cxacru_driver_name[] = "cxacru";
@@ -52,6 +53,7 @@ static const char cxacru_driver_name[] = "cxacru";
#define CXACRU_EP_DATA 0x02 /* Bulk in/out */
#define CMD_PACKET_SIZE 64 /* Should be maxpacket(ep)? */
+#define CMD_MAX_CONFIG ((CMD_PACKET_SIZE / 4 - 1) / 2)
/* Addresses */
#define PLLFCLK_ADDR 0x00350068
@@ -105,6 +107,26 @@ enum cxacru_cm_request {
CM_REQUEST_MAX,
};
+/* commands for interaction with the flash memory
+ *
+ * read: response is the contents of the first 60 bytes of flash memory
+ * write: request contains the 60 bytes of data to write to flash memory
+ * response is the contents of the first 60 bytes of flash memory
+ *
+ * layout: PP PP VV VV MM MM MM MM MM MM ?? ?? SS SS SS SS SS SS SS SS
+ * SS SS SS SS SS SS SS SS 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ *
+ * P: le16 USB Product ID
+ * V: le16 USB Vendor ID
+ * M: be48 MAC Address
+ * S: le16 ASCII Serial Number
+ */
+enum cxacru_cm_flash {
+ CM_FLASH_READ = 0xa1,
+ CM_FLASH_WRITE = 0xa2
+};
+
/* reply codes to the commands above */
enum cxacru_cm_status {
CM_STATUS_UNDEFINED,
@@ -196,23 +218,32 @@ static DEVICE_ATTR(_name, S_IRUGO, cxacru_sysfs_show_##_name, NULL)
static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, \
cxacru_sysfs_show_##_name, cxacru_sysfs_store_##_name)
+#define CXACRU_SET_INIT(_name) \
+static DEVICE_ATTR(_name, S_IWUSR, \
+ NULL, cxacru_sysfs_store_##_name)
+
#define CXACRU_ATTR_INIT(_value, _type, _name) \
static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); \
- struct cxacru_data *instance = usbatm_instance->driver_data; \
+ struct cxacru_data *instance = to_usbatm_driver_data(\
+ to_usb_interface(dev)); \
+\
+ if (instance == NULL) \
+ return -ENODEV; \
+\
return cxacru_sysfs_showattr_##_type(instance->card_info[_value], buf); \
} \
CXACRU__ATTR_INIT(_name)
#define CXACRU_ATTR_CREATE(_v, _t, _name) CXACRU_DEVICE_CREATE_FILE(_name)
#define CXACRU_CMD_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)
+#define CXACRU_SET_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)
#define CXACRU__ATTR_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)
#define CXACRU_ATTR_REMOVE(_v, _t, _name) CXACRU_DEVICE_REMOVE_FILE(_name)
#define CXACRU_CMD_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)
+#define CXACRU_SET_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)
#define CXACRU__ATTR_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)
static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf)
@@ -267,12 +298,12 @@ static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf)
static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
{
static char *str[] = {
- NULL,
+ "",
"ANSI T1.413",
"ITU-T G.992.1 (G.DMT)",
"ITU-T G.992.2 (G.LITE)"
};
- if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL))
+ if (unlikely(value >= ARRAY_SIZE(str)))
return snprintf(buf, PAGE_SIZE, "%u\n", value);
return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
}
@@ -288,22 +319,28 @@ static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
static ssize_t cxacru_sysfs_show_mac_address(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct usb_interface *intf = to_usb_interface(dev);
- struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
- struct atm_dev *atm_dev = usbatm_instance->atm_dev;
+ struct cxacru_data *instance = to_usbatm_driver_data(
+ to_usb_interface(dev));
- return snprintf(buf, PAGE_SIZE, "%pM\n", atm_dev->esi);
+ if (instance == NULL || instance->usbatm->atm_dev == NULL)
+ return -ENODEV;
+
+ return snprintf(buf, PAGE_SIZE, "%pM\n",
+ instance->usbatm->atm_dev->esi);
}
static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct usb_interface *intf = to_usb_interface(dev);
- struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
- struct cxacru_data *instance = usbatm_instance->driver_data;
- u32 value = instance->card_info[CXINF_LINE_STARTABLE];
-
static char *str[] = { "running", "stopped" };
+ struct cxacru_data *instance = to_usbatm_driver_data(
+ to_usb_interface(dev));
+ u32 value;
+
+ if (instance == NULL)
+ return -ENODEV;
+
+ value = instance->card_info[CXINF_LINE_STARTABLE];
if (unlikely(value >= ARRAY_SIZE(str)))
return snprintf(buf, PAGE_SIZE, "%u\n", value);
return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
@@ -312,9 +349,8 @@ static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct usb_interface *intf = to_usb_interface(dev);
- struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
- struct cxacru_data *instance = usbatm_instance->driver_data;
+ struct cxacru_data *instance = to_usbatm_driver_data(
+ to_usb_interface(dev));
int ret;
int poll = -1;
char str_cmd[8];
@@ -328,13 +364,16 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
return -EINVAL;
ret = 0;
+ if (instance == NULL)
+ return -ENODEV;
+
if (mutex_lock_interruptible(&instance->adsl_state_serialize))
return -ERESTARTSYS;
if (!strcmp(str_cmd, "stop") || !strcmp(str_cmd, "restart")) {
ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_STOP, NULL, 0, NULL, 0);
if (ret < 0) {
- atm_err(usbatm_instance, "change adsl state:"
+ atm_err(instance->usbatm, "change adsl state:"
" CHIP_ADSL_LINE_STOP returned %d\n", ret);
ret = -EIO;
@@ -354,7 +393,7 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
if (!strcmp(str_cmd, "start") || !strcmp(str_cmd, "restart")) {
ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
if (ret < 0) {
- atm_err(usbatm_instance, "change adsl state:"
+ atm_err(instance->usbatm, "change adsl state:"
" CHIP_ADSL_LINE_START returned %d\n", ret);
ret = -EIO;
@@ -407,6 +446,72 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
return ret;
}
+/* CM_REQUEST_CARD_DATA_GET times out, so no show attribute */
+
+static ssize_t cxacru_sysfs_store_adsl_config(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct cxacru_data *instance = to_usbatm_driver_data(
+ to_usb_interface(dev));
+ int len = strlen(buf);
+ int ret, pos, num;
+ __le32 data[CMD_PACKET_SIZE / 4];
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EACCES;
+
+ if (instance == NULL)
+ return -ENODEV;
+
+ pos = 0;
+ num = 0;
+ while (pos < len) {
+ int tmp;
+ u32 index;
+ u32 value;
+
+ ret = sscanf(buf + pos, "%x=%x%n", &index, &value, &tmp);
+ if (ret < 2)
+ return -EINVAL;
+ if (index < 0 || index > 0x7f)
+ return -EINVAL;
+ pos += tmp;
+
+ /* skip trailing newline */
+ if (buf[pos] == '\n' && pos == len-1)
+ pos++;
+
+ data[num * 2 + 1] = cpu_to_le32(index);
+ data[num * 2 + 2] = cpu_to_le32(value);
+ num++;
+
+ /* send config values when data buffer is full
+ * or no more data
+ */
+ if (pos >= len || num >= CMD_MAX_CONFIG) {
+ char log[CMD_MAX_CONFIG * 12 + 1]; /* %02x=%08x */
+
+ data[0] = cpu_to_le32(num);
+ ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET,
+ (u8 *) data, 4 + num * 8, NULL, 0);
+ if (ret < 0) {
+ atm_err(instance->usbatm,
+ "set card data returned %d\n", ret);
+ return -EIO;
+ }
+
+ for (tmp = 0; tmp < num; tmp++)
+ snprintf(log + tmp*12, 13, " %02x=%08x",
+ le32_to_cpu(data[tmp * 2 + 1]),
+ le32_to_cpu(data[tmp * 2 + 2]));
+ atm_info(instance->usbatm, "config%s\n", log);
+ num = 0;
+ }
+ }
+
+ return len;
+}
+
/*
* All device attributes are included in CXACRU_ALL_FILES
* so that the same list can be used multiple times:
@@ -442,7 +547,8 @@ CXACRU_ATTR_##_action(CXINF_MODULATION, MODU, modulation); \
CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND, u32, adsl_headend); \
CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND_ENVIRONMENT, u32, adsl_headend_environment); \
CXACRU_ATTR_##_action(CXINF_CONTROLLER_VERSION, u32, adsl_controller_version); \
-CXACRU_CMD_##_action( adsl_state);
+CXACRU_CMD_##_action( adsl_state); \
+CXACRU_SET_##_action( adsl_config);
CXACRU_ALL_FILES(INIT);
@@ -596,7 +702,7 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
len = ret / 4;
for (offb = 0; offb < len; ) {
int l = le32_to_cpu(buf[offb++]);
- if (l > stride || l > (len - offb) / 2) {
+ if (l < 0 || l > stride || l > (len - offb) / 2) {
if (printk_ratelimit())
usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
cm, l);
@@ -649,9 +755,6 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
{
struct cxacru_data *instance = usbatm_instance->driver_data;
struct usb_interface *intf = usbatm_instance->usb_intf;
- /*
- struct atm_dev *atm_dev = usbatm_instance->atm_dev;
- */
int ret;
int start_polling = 1;
@@ -697,6 +800,9 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
mutex_unlock(&instance->poll_state_serialize);
mutex_unlock(&instance->adsl_state_serialize);
+ printk(KERN_INFO "%s%d: %s %pM\n", atm_dev->type, atm_dev->number,
+ usbatm_instance->description, atm_dev->esi);
+
if (start_polling)
cxacru_poll_status(&instance->poll_work.work);
return 0;
@@ -873,11 +979,9 @@ cleanup:
static void cxacru_upload_firmware(struct cxacru_data *instance,
const struct firmware *fw,
- const struct firmware *bp,
- const struct firmware *cf)
+ const struct firmware *bp)
{
int ret;
- int off;
struct usbatm_data *usbatm = instance->usbatm;
struct usb_device *usb_dev = usbatm->usb_dev;
__le16 signature[] = { usb_dev->descriptor.idVendor,
@@ -911,6 +1015,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
}
/* Firmware */
+ usb_info(usbatm, "loading firmware\n");
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size);
if (ret) {
usb_err(usbatm, "Firmware upload failed: %d\n", ret);
@@ -919,6 +1024,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
/* Boot ROM patch */
if (instance->modem_type->boot_rom_patch) {
+ usb_info(usbatm, "loading boot ROM patch\n");
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size);
if (ret) {
usb_err(usbatm, "Boot ROM patching failed: %d\n", ret);
@@ -933,6 +1039,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
return;
}
+ usb_info(usbatm, "starting device\n");
if (instance->modem_type->boot_rom_patch) {
val = cpu_to_le32(BR_ADDR);
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4);
@@ -958,26 +1065,6 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
usb_err(usbatm, "modem failed to initialize: %d\n", ret);
return;
}
-
- /* Load config data (le32), doing one packet at a time */
- if (cf)
- for (off = 0; off < cf->size / 4; ) {
- __le32 buf[CMD_PACKET_SIZE / 4 - 1];
- int i, len = min_t(int, cf->size / 4 - off, CMD_PACKET_SIZE / 4 / 2 - 1);
- buf[0] = cpu_to_le32(len);
- for (i = 0; i < len; i++, off++) {
- buf[i * 2 + 1] = cpu_to_le32(off);
- memcpy(buf + i * 2 + 2, cf->data + off * 4, 4);
- }
- ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET,
- (u8 *) buf, len, NULL, 0);
- if (ret < 0) {
- usb_err(usbatm, "load config data failed: %d\n", ret);
- return;
- }
- }
-
- msleep_interruptible(4000);
}
static int cxacru_find_firmware(struct cxacru_data *instance,
@@ -1003,7 +1090,7 @@ static int cxacru_find_firmware(struct cxacru_data *instance,
static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
struct usb_interface *usb_intf)
{
- const struct firmware *fw, *bp, *cf;
+ const struct firmware *fw, *bp;
struct cxacru_data *instance = usbatm_instance->driver_data;
int ret = cxacru_find_firmware(instance, "fw", &fw);
@@ -1021,13 +1108,8 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
}
}
- if (cxacru_find_firmware(instance, "cf", &cf)) /* optional */
- cf = NULL;
-
- cxacru_upload_firmware(instance, fw, bp, cf);
+ cxacru_upload_firmware(instance, fw, bp);
- if (cf)
- release_firmware(cf);
if (instance->modem_type->boot_rom_patch)
release_firmware(bp);
release_firmware(fw);
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index fbea8563df1e..9b53e8df4648 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -1333,6 +1333,7 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
if (instance->atm_dev) {
sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device");
atm_dev_deregister(instance->atm_dev);
+ instance->atm_dev = NULL;
}
usbatm_put_instance(instance); /* taken in usbatm_usb_probe */
@@ -1348,7 +1349,7 @@ static int __init usbatm_usb_init(void)
{
dbg("%s: driver version %s", __func__, DRIVER_VERSION);
- if (sizeof(struct usbatm_control) > sizeof(((struct sk_buff *) 0)->cb)) {
+ if (sizeof(struct usbatm_control) > FIELD_SIZEOF(struct sk_buff, cb)) {
printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name);
return -EIO;
}
diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h
index f6f4508a9d42..0863f85fcc26 100644
--- a/drivers/usb/atm/usbatm.h
+++ b/drivers/usb/atm/usbatm.h
@@ -204,4 +204,19 @@ struct usbatm_data {
struct urb *urbs[0];
};
+static inline void *to_usbatm_driver_data(struct usb_interface *intf)
+{
+ struct usbatm_data *usbatm_instance;
+
+ if (intf == NULL)
+ return NULL;
+
+ usbatm_instance = usb_get_intfdata(intf);
+
+ if (usbatm_instance == NULL) /* set NULL before unbind() */
+ return NULL;
+
+ return usbatm_instance->driver_data; /* set NULL after unbind() */
+}
+
#endif /* _USBATM_H_ */
diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c
index 5633bc5c8bf2..029ee4a8a1f3 100644
--- a/drivers/usb/c67x00/c67x00-drv.c
+++ b/drivers/usb/c67x00/c67x00-drv.c
@@ -137,13 +137,13 @@ static int __devinit c67x00_drv_probe(struct platform_device *pdev)
if (!c67x00)
return -ENOMEM;
- if (!request_mem_region(res->start, res->end - res->start + 1,
+ if (!request_mem_region(res->start, resource_size(res),
pdev->name)) {
dev_err(&pdev->dev, "Memory region busy\n");
ret = -EBUSY;
goto request_mem_failed;
}
- c67x00->hpi.base = ioremap(res->start, res->end - res->start + 1);
+ c67x00->hpi.base = ioremap(res->start, resource_size(res));
if (!c67x00->hpi.base) {
dev_err(&pdev->dev, "Unable to map HPI registers\n");
ret = -EIO;
@@ -182,7 +182,7 @@ static int __devinit c67x00_drv_probe(struct platform_device *pdev)
request_irq_failed:
iounmap(c67x00->hpi.base);
map_failed:
- release_mem_region(res->start, res->end - res->start + 1);
+ release_mem_region(res->start, resource_size(res));
request_mem_failed:
kfree(c67x00);
@@ -208,7 +208,7 @@ static int __devexit c67x00_drv_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res)
- release_mem_region(res->start, res->end - res->start + 1);
+ release_mem_region(res->start, resource_size(res));
kfree(c67x00);
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 34d4eb98829e..975d556b4787 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -170,6 +170,7 @@ static void acm_write_done(struct acm *acm, struct acm_wb *wb)
{
wb->use = 0;
acm->transmitting--;
+ usb_autopm_put_interface_async(acm->control);
}
/*
@@ -211,9 +212,12 @@ static int acm_write_start(struct acm *acm, int wbn)
}
dbg("%s susp_count: %d", __func__, acm->susp_count);
+ usb_autopm_get_interface_async(acm->control);
if (acm->susp_count) {
- acm->delayed_wb = wb;
- schedule_work(&acm->waker);
+ if (!acm->delayed_wb)
+ acm->delayed_wb = wb;
+ else
+ usb_autopm_put_interface_async(acm->control);
spin_unlock_irqrestore(&acm->write_lock, flags);
return 0; /* A white lie */
}
@@ -424,7 +428,6 @@ next_buffer:
throttled = acm->throttle;
spin_unlock_irqrestore(&acm->throttle_lock, flags);
if (!throttled) {
- tty_buffer_request_room(tty, buf->size);
tty_insert_flip_string(tty, buf->base, buf->size);
tty_flip_buffer_push(tty);
} else {
@@ -534,23 +537,6 @@ static void acm_softint(struct work_struct *work)
tty_kref_put(tty);
}
-static void acm_waker(struct work_struct *waker)
-{
- struct acm *acm = container_of(waker, struct acm, waker);
- int rv;
-
- rv = usb_autopm_get_interface(acm->control);
- if (rv < 0) {
- dev_err(&acm->dev->dev, "Autopm failure in %s\n", __func__);
- return;
- }
- if (acm->delayed_wb) {
- acm_start_wb(acm, acm->delayed_wb);
- acm->delayed_wb = NULL;
- }
- usb_autopm_put_interface(acm->control);
-}
-
/*
* TTY handlers
*/
@@ -566,7 +552,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
acm = acm_table[tty->index];
if (!acm || !acm->dev)
- goto err_out;
+ goto out;
else
rv = 0;
@@ -582,8 +568,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
mutex_lock(&acm->mutex);
if (acm->port.count++) {
+ mutex_unlock(&acm->mutex);
usb_autopm_put_interface(acm->control);
- goto done;
+ goto out;
}
acm->ctrlurb->dev = acm->dev;
@@ -612,18 +599,18 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
rv = tty_port_block_til_ready(&acm->port, tty, filp);
tasklet_schedule(&acm->urb_task);
-done:
+
mutex_unlock(&acm->mutex);
-err_out:
+out:
mutex_unlock(&open_mutex);
return rv;
full_bailout:
usb_kill_urb(acm->ctrlurb);
bail_out:
- usb_autopm_put_interface(acm->control);
acm->port.count--;
mutex_unlock(&acm->mutex);
+ usb_autopm_put_interface(acm->control);
early_bail:
mutex_unlock(&open_mutex);
tty_port_tty_set(&acm->port, NULL);
@@ -1023,7 +1010,7 @@ static int acm_probe(struct usb_interface *intf,
case USB_CDC_CALL_MANAGEMENT_TYPE:
call_management_function = buffer[3];
call_interface_num = buffer[4];
- if ((call_management_function & 3) != 3)
+ if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
break;
default:
@@ -1178,7 +1165,6 @@ made_compressed_probe:
acm->urb_task.func = acm_rx_tasklet;
acm->urb_task.data = (unsigned long) acm;
INIT_WORK(&acm->work, acm_softint);
- INIT_WORK(&acm->waker, acm_waker);
init_waitqueue_head(&acm->drain_wait);
spin_lock_init(&acm->throttle_lock);
spin_lock_init(&acm->write_lock);
@@ -1343,7 +1329,6 @@ static void stop_data_traffic(struct acm *acm)
tasklet_enable(&acm->urb_task);
cancel_work_sync(&acm->work);
- cancel_work_sync(&acm->waker);
}
static void acm_disconnect(struct usb_interface *intf)
@@ -1435,6 +1420,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
static int acm_resume(struct usb_interface *intf)
{
struct acm *acm = usb_get_intfdata(intf);
+ struct acm_wb *wb;
int rv = 0;
int cnt;
@@ -1449,6 +1435,21 @@ static int acm_resume(struct usb_interface *intf)
mutex_lock(&acm->mutex);
if (acm->port.count) {
rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
+
+ spin_lock_irq(&acm->write_lock);
+ if (acm->delayed_wb) {
+ wb = acm->delayed_wb;
+ acm->delayed_wb = NULL;
+ spin_unlock_irq(&acm->write_lock);
+ acm_start_wb(acm, acm->delayed_wb);
+ } else {
+ spin_unlock_irq(&acm->write_lock);
+ }
+
+ /*
+ * delayed error checking because we must
+ * do the write path at all cost
+ */
if (rv < 0)
goto err_out;
@@ -1460,6 +1461,23 @@ err_out:
return rv;
}
+static int acm_reset_resume(struct usb_interface *intf)
+{
+ struct acm *acm = usb_get_intfdata(intf);
+ struct tty_struct *tty;
+
+ mutex_lock(&acm->mutex);
+ if (acm->port.count) {
+ tty = tty_port_tty_get(&acm->port);
+ if (tty) {
+ tty_hangup(tty);
+ tty_kref_put(tty);
+ }
+ }
+ mutex_unlock(&acm->mutex);
+ return acm_resume(intf);
+}
+
#endif /* CONFIG_PM */
#define NOKIA_PCSUITE_ACM_INFO(x) \
@@ -1471,7 +1489,7 @@ err_out:
* USB driver structure.
*/
-static struct usb_device_id acm_ids[] = {
+static const struct usb_device_id acm_ids[] = {
/* quirky and broken devices */
{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
@@ -1576,6 +1594,11 @@ static struct usb_device_id acm_ids[] = {
/* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
+ /* Support Lego NXT using pbLua firmware */
+ { USB_DEVICE(0x0694, 0xff00),
+ .driver_info = NOT_A_MODEM,
+ },
+
/* control interfaces with various AT-command sets */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_ACM_PROTO_AT_V25TER) },
@@ -1602,6 +1625,7 @@ static struct usb_driver acm_driver = {
#ifdef CONFIG_PM
.suspend = acm_suspend,
.resume = acm_resume,
+ .reset_resume = acm_reset_resume,
#endif
.id_table = acm_ids,
#ifdef CONFIG_PM
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index c4a0ee8ffccf..4a8e87ec6ce9 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -112,7 +112,6 @@ struct acm {
struct mutex mutex;
struct usb_cdc_line_coding line; /* bits, stop, parity */
struct work_struct work; /* work queue entry for line discipline waking up */
- struct work_struct waker;
wait_queue_head_t drain_wait; /* close processing */
struct tasklet_struct urb_task; /* rx processing */
spinlock_t throttle_lock; /* synchronize throtteling and read callback */
@@ -137,3 +136,4 @@ struct acm {
#define NO_UNION_NORMAL 1
#define SINGLE_RX_URB 2
#define NO_CAP_LINE 4
+#define NOT_A_MODEM 8
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 3e564bfe17d1..18aafcb08fc8 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -31,7 +31,7 @@
#define DRIVER_AUTHOR "Oliver Neukum"
#define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
-static struct usb_device_id wdm_ids[] = {
+static const struct usb_device_id wdm_ids[] = {
{
.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 9bc112ee7803..93b5f85d7ceb 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -163,7 +163,6 @@ struct usblp {
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
unsigned char bidir; /* interface is bidirectional */
- unsigned char sleeping; /* interface is suspended */
unsigned char no_paper; /* Paper Out happened */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
/* first 2 bytes are (big-endian) length */
@@ -191,7 +190,6 @@ static void usblp_dump(struct usblp *usblp) {
dbg("quirks=%d", usblp->quirks);
dbg("used=%d", usblp->used);
dbg("bidir=%d", usblp->bidir);
- dbg("sleeping=%d", usblp->sleeping);
dbg("device_id_string=\"%s\"",
usblp->device_id_string ?
usblp->device_id_string + 2 :
@@ -376,7 +374,7 @@ static int usblp_check_status(struct usblp *usblp, int err)
static int handle_bidir (struct usblp *usblp)
{
- if (usblp->bidir && usblp->used && !usblp->sleeping) {
+ if (usblp->bidir && usblp->used) {
if (usblp_submit_read(usblp) < 0)
return -EIO;
}
@@ -503,11 +501,6 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto done;
}
- if (usblp->sleeping) {
- retval = -ENODEV;
- goto done;
- }
-
dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
@@ -914,8 +907,6 @@ static int usblp_wtest(struct usblp *usblp, int nonblock)
return 0;
}
spin_unlock_irqrestore(&usblp->lock, flags);
- if (usblp->sleeping)
- return -ENODEV;
if (nonblock)
return -EAGAIN;
return 1;
@@ -968,8 +959,6 @@ static int usblp_rtest(struct usblp *usblp, int nonblock)
return 0;
}
spin_unlock_irqrestore(&usblp->lock, flags);
- if (usblp->sleeping)
- return -ENODEV;
if (nonblock)
return -EAGAIN;
return 1;
@@ -1377,12 +1366,10 @@ static void usblp_disconnect(struct usb_interface *intf)
mutex_unlock (&usblp_mutex);
}
-static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
+static int usblp_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usblp *usblp = usb_get_intfdata (intf);
- /* we take no more IO */
- usblp->sleeping = 1;
usblp_unlink_urbs(usblp);
#if 0 /* XXX Do we want this? What if someone is reading, should we fail? */
/* not strictly necessary, but just in case */
@@ -1393,18 +1380,17 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
return 0;
}
-static int usblp_resume (struct usb_interface *intf)
+static int usblp_resume(struct usb_interface *intf)
{
struct usblp *usblp = usb_get_intfdata (intf);
int r;
- usblp->sleeping = 0;
r = handle_bidir (usblp);
return r;
}
-static struct usb_device_id usblp_ids [] = {
+static const struct usb_device_id usblp_ids[] = {
{ USB_DEVICE_INFO(7, 1, 1) },
{ USB_DEVICE_INFO(7, 1, 2) },
{ USB_DEVICE_INFO(7, 1, 3) },
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 7c5f4e32c920..8588c0937a89 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -48,7 +48,7 @@
*/
#define USBTMC_MAX_READS_TO_CLEAR_BULK_IN 100
-static struct usb_device_id usbtmc_devices[] = {
+static const struct usb_device_id usbtmc_devices[] = {
{ USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 0), },
{ USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 1), },
{ 0, } /* terminating entry */
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index ad925946f869..97a819c23ef3 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -91,8 +91,8 @@ config USB_DYNAMIC_MINORS
If you are unsure about this, say N here.
config USB_SUSPEND
- bool "USB selective suspend/resume and wakeup"
- depends on USB && PM
+ bool "USB runtime power management (suspend/resume and wakeup)"
+ depends on USB && PM_RUNTIME
help
If you say Y here, you can use driver calls or the sysfs
"power/level" file to suspend or resume individual USB
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 96f11715cd26..d41811bfef2a 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -117,12 +117,20 @@ static const char *format_endpt =
* However, these will come from functions that return ptrs to each of them.
*/
-static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
-static unsigned int conndiscevcnt;
-
-/* this struct stores the poll state for <mountpoint>/devices pollers */
-struct usb_device_status {
- unsigned int lastev;
+/*
+ * Wait for an connect/disconnect event to happen. We initialize
+ * the event counter with an odd number, and each event will increment
+ * the event counter by two, so it will always _stay_ odd. That means
+ * that it will never be zero, so "event 0" will never match a current
+ * event, and thus 'poll' will always trigger as readable for the first
+ * time it gets called.
+ */
+static struct device_connect_event {
+ atomic_t count;
+ wait_queue_head_t wait;
+} device_event = {
+ .count = ATOMIC_INIT(1),
+ .wait = __WAIT_QUEUE_HEAD_INITIALIZER(device_event.wait)
};
struct class_info {
@@ -156,8 +164,8 @@ static const struct class_info clas_info[] =
void usbfs_conn_disc_event(void)
{
- conndiscevcnt++;
- wake_up(&deviceconndiscwq);
+ atomic_add(2, &device_event.count);
+ wake_up(&device_event.wait);
}
static const char *class_decode(const int class)
@@ -494,7 +502,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
return 0;
/* allocate 2^1 pages = 8K (on i386);
* should be more than enough for one device */
- pages_start = (char *)__get_free_pages(GFP_KERNEL, 1);
+ pages_start = (char *)__get_free_pages(GFP_NOIO, 1);
if (!pages_start)
return -ENOMEM;
@@ -629,55 +637,16 @@ static ssize_t usb_device_read(struct file *file, char __user *buf,
static unsigned int usb_device_poll(struct file *file,
struct poll_table_struct *wait)
{
- struct usb_device_status *st = file->private_data;
- unsigned int mask = 0;
-
- lock_kernel();
- if (!st) {
- st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
-
- /* we may have dropped BKL -
- * need to check for having lost the race */
- if (file->private_data) {
- kfree(st);
- st = file->private_data;
- goto lost_race;
- }
- /* we haven't lost - check for allocation failure now */
- if (!st) {
- unlock_kernel();
- return POLLIN;
- }
+ unsigned int event_count;
- /*
- * need to prevent the module from being unloaded, since
- * proc_unregister does not call the release method and
- * we would have a memory leak
- */
- st->lastev = conndiscevcnt;
- file->private_data = st;
- mask = POLLIN;
- }
-lost_race:
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &deviceconndiscwq, wait);
- if (st->lastev != conndiscevcnt)
- mask |= POLLIN;
- st->lastev = conndiscevcnt;
- unlock_kernel();
- return mask;
-}
+ poll_wait(file, &device_event.wait, wait);
-static int usb_device_open(struct inode *inode, struct file *file)
-{
- file->private_data = NULL;
- return 0;
-}
+ event_count = atomic_read(&device_event.count);
+ if (file->f_version != event_count) {
+ file->f_version = event_count;
+ return POLLIN | POLLRDNORM;
+ }
-static int usb_device_release(struct inode *inode, struct file *file)
-{
- kfree(file->private_data);
- file->private_data = NULL;
return 0;
}
@@ -685,7 +654,7 @@ static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
{
loff_t ret;
- lock_kernel();
+ mutex_lock(&file->f_dentry->d_inode->i_mutex);
switch (orig) {
case 0:
@@ -701,7 +670,7 @@ static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
ret = -EINVAL;
}
- unlock_kernel();
+ mutex_unlock(&file->f_dentry->d_inode->i_mutex);
return ret;
}
@@ -709,6 +678,4 @@ const struct file_operations usbfs_devices_fops = {
.llseek = usb_device_lseek,
.read = usb_device_read,
.poll = usb_device_poll,
- .open = usb_device_open,
- .release = usb_device_release,
};
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 6e8bcdfd23b4..e909ff7b9094 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -122,7 +122,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
{
loff_t ret;
- lock_kernel();
+ mutex_lock(&file->f_dentry->d_inode->i_mutex);
switch (orig) {
case 0:
@@ -138,7 +138,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
ret = -EINVAL;
}
- unlock_kernel();
+ mutex_unlock(&file->f_dentry->d_inode->i_mutex);
return ret;
}
@@ -310,7 +310,8 @@ static struct async *async_getpending(struct dev_state *ps,
static void snoop_urb(struct usb_device *udev,
void __user *userurb, int pipe, unsigned length,
- int timeout_or_status, enum snoop_when when)
+ int timeout_or_status, enum snoop_when when,
+ unsigned char *data, unsigned data_len)
{
static const char *types[] = {"isoc", "int", "ctrl", "bulk"};
static const char *dirs[] = {"out", "in"};
@@ -344,6 +345,11 @@ static void snoop_urb(struct usb_device *udev,
"status %d\n",
ep, t, d, length, timeout_or_status);
}
+
+ if (data && data_len > 0) {
+ print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
+ data, data_len, 1);
+ }
}
#define AS_CONTINUATION 1
@@ -410,7 +416,9 @@ static void async_completed(struct urb *urb)
}
snoop(&urb->dev->dev, "urb complete\n");
snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
- as->status, COMPLETE);
+ as->status, COMPLETE,
+ ((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_OUT) ?
+ NULL : urb->transfer_buffer, urb->actual_length);
if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
as->status != -ENOENT)
cancel_bulk_urbs(ps, as->bulk_addr);
@@ -653,20 +661,20 @@ static int usbdev_open(struct inode *inode, struct file *file)
const struct cred *cred = current_cred();
int ret;
- lock_kernel();
- /* Protect against simultaneous removal or release */
- mutex_lock(&usbfs_mutex);
-
ret = -ENOMEM;
ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL);
if (!ps)
- goto out;
+ goto out_free_ps;
ret = -ENODEV;
+ /* Protect against simultaneous removal or release */
+ mutex_lock(&usbfs_mutex);
+
/* usbdev device-node */
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_by_devt(inode->i_rdev);
+
#ifdef CONFIG_USB_DEVICEFS
/* procfs file */
if (!dev) {
@@ -678,13 +686,19 @@ static int usbdev_open(struct inode *inode, struct file *file)
dev = NULL;
}
#endif
- if (!dev || dev->state == USB_STATE_NOTATTACHED)
- goto out;
+ mutex_unlock(&usbfs_mutex);
+
+ if (!dev)
+ goto out_free_ps;
+
+ usb_lock_device(dev);
+ if (dev->state == USB_STATE_NOTATTACHED)
+ goto out_unlock_device;
+
ret = usb_autoresume_device(dev);
if (ret)
- goto out;
+ goto out_unlock_device;
- ret = 0;
ps->dev = dev;
ps->file = file;
spin_lock_init(&ps->lock);
@@ -702,15 +716,16 @@ static int usbdev_open(struct inode *inode, struct file *file)
smp_wmb();
list_add_tail(&ps->list, &dev->filelist);
file->private_data = ps;
+ usb_unlock_device(dev);
snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current),
current->comm);
- out:
- if (ret) {
- kfree(ps);
- usb_put_dev(dev);
- }
- mutex_unlock(&usbfs_mutex);
- unlock_kernel();
+ return ret;
+
+ out_unlock_device:
+ usb_unlock_device(dev);
+ usb_put_dev(dev);
+ out_free_ps:
+ kfree(ps);
return ret;
}
@@ -724,10 +739,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
usb_lock_device(dev);
usb_hub_release_all_ports(dev, ps);
- /* Protect against simultaneous open */
- mutex_lock(&usbfs_mutex);
list_del_init(&ps->list);
- mutex_unlock(&usbfs_mutex);
for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
ifnum++) {
@@ -770,6 +782,13 @@ static int proc_control(struct dev_state *ps, void __user *arg)
if (!tbuf)
return -ENOMEM;
tmo = ctrl.timeout;
+ snoop(&dev->dev, "control urb: bRequestType=%02x "
+ "bRequest=%02x wValue=%04x "
+ "wIndex=%04x wLength=%04x\n",
+ ctrl.bRequestType, ctrl.bRequest,
+ __le16_to_cpup(&ctrl.wValue),
+ __le16_to_cpup(&ctrl.wIndex),
+ __le16_to_cpup(&ctrl.wLength));
if (ctrl.bRequestType & 0x80) {
if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,
ctrl.wLength)) {
@@ -777,15 +796,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
return -EINVAL;
}
pipe = usb_rcvctrlpipe(dev, 0);
- snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
+ snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0);
usb_unlock_device(dev);
i = usb_control_msg(dev, pipe, ctrl.bRequest,
ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
tbuf, ctrl.wLength, tmo);
usb_lock_device(dev);
- snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
-
+ snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE,
+ tbuf, i);
if ((i > 0) && ctrl.wLength) {
if (copy_to_user(ctrl.data, tbuf, i)) {
free_page((unsigned long)tbuf);
@@ -800,14 +819,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
}
}
pipe = usb_sndctrlpipe(dev, 0);
- snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
+ snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT,
+ tbuf, ctrl.wLength);
usb_unlock_device(dev);
i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
tbuf, ctrl.wLength, tmo);
usb_lock_device(dev);
- snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
+ snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0);
}
free_page((unsigned long)tbuf);
if (i < 0 && i != -EPIPE) {
@@ -853,12 +873,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
kfree(tbuf);
return -EINVAL;
}
- snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
+ snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);
usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
usb_lock_device(dev);
- snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
+ snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2);
if (!i && len2) {
if (copy_to_user(bulk.data, tbuf, len2)) {
@@ -873,12 +893,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
return -EFAULT;
}
}
- snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
+ snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);
usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
usb_lock_device(dev);
- snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
+ snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);
}
kfree(tbuf);
if (i < 0)
@@ -1097,6 +1117,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
is_in = 0;
uurb->endpoint &= ~USB_DIR_IN;
}
+ snoop(&ps->dev->dev, "control urb: bRequestType=%02x "
+ "bRequest=%02x wValue=%04x "
+ "wIndex=%04x wLength=%04x\n",
+ dr->bRequestType, dr->bRequest,
+ __le16_to_cpup(&dr->wValue),
+ __le16_to_cpup(&dr->wIndex),
+ __le16_to_cpup(&dr->wLength));
break;
case USBDEVFS_URB_TYPE_BULK:
@@ -1104,13 +1131,25 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_ISOC:
return -EINVAL;
- /* allow single-shot interrupt transfers, at bogus rates */
+ case USB_ENDPOINT_XFER_INT:
+ /* allow single-shot interrupt transfers */
+ uurb->type = USBDEVFS_URB_TYPE_INTERRUPT;
+ goto interrupt_urb;
}
uurb->number_of_packets = 0;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
break;
+ case USBDEVFS_URB_TYPE_INTERRUPT:
+ if (!usb_endpoint_xfer_int(&ep->desc))
+ return -EINVAL;
+ interrupt_urb:
+ uurb->number_of_packets = 0;
+ if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
+ return -EINVAL;
+ break;
+
case USBDEVFS_URB_TYPE_ISO:
/* arbitrary limit */
if (uurb->number_of_packets < 1 ||
@@ -1143,14 +1182,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
uurb->buffer_length = totlen;
break;
- case USBDEVFS_URB_TYPE_INTERRUPT:
- uurb->number_of_packets = 0;
- if (!usb_endpoint_xfer_int(&ep->desc))
- return -EINVAL;
- if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
- return -EINVAL;
- break;
-
default:
return -EINVAL;
}
@@ -1236,7 +1267,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
}
}
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
- as->urb->transfer_buffer_length, 0, SUBMIT);
+ as->urb->transfer_buffer_length, 0, SUBMIT,
+ is_in ? NULL : as->urb->transfer_buffer,
+ uurb->buffer_length);
async_newpending(as);
if (usb_endpoint_xfer_bulk(&ep->desc)) {
@@ -1274,7 +1307,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
dev_printk(KERN_DEBUG, &ps->dev->dev,
"usbfs: usb_submit_urb returned %d\n", ret);
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
- 0, ret, COMPLETE);
+ 0, ret, COMPLETE, NULL, 0);
async_removepending(as);
free_async(as);
return ret;
@@ -1312,9 +1345,9 @@ static int processcompl(struct async *as, void __user * __user *arg)
void __user *addr = as->userurb;
unsigned int i;
- if (as->userbuffer)
+ if (as->userbuffer && urb->actual_length)
if (copy_to_user(as->userbuffer, urb->transfer_buffer,
- urb->transfer_buffer_length))
+ urb->actual_length))
goto err_out;
if (put_user(as->status, &userurb->status))
goto err_out;
@@ -1334,14 +1367,11 @@ static int processcompl(struct async *as, void __user * __user *arg)
}
}
- free_async(as);
-
if (put_user(addr, (void __user * __user *)arg))
return -EFAULT;
return 0;
err_out:
- free_async(as);
return -EFAULT;
}
@@ -1371,8 +1401,11 @@ static struct async *reap_as(struct dev_state *ps)
static int proc_reapurb(struct dev_state *ps, void __user *arg)
{
struct async *as = reap_as(ps);
- if (as)
- return processcompl(as, (void __user * __user *)arg);
+ if (as) {
+ int retval = processcompl(as, (void __user * __user *)arg);
+ free_async(as);
+ return retval;
+ }
if (signal_pending(current))
return -EINTR;
return -EIO;
@@ -1380,11 +1413,16 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg)
static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)
{
+ int retval;
struct async *as;
- if (!(as = async_getcompleted(ps)))
- return -EAGAIN;
- return processcompl(as, (void __user * __user *)arg);
+ as = async_getcompleted(ps);
+ retval = -EAGAIN;
+ if (as) {
+ retval = processcompl(as, (void __user * __user *)arg);
+ free_async(as);
+ }
+ return retval;
}
#ifdef CONFIG_COMPAT
@@ -1475,9 +1513,9 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
void __user *addr = as->userurb;
unsigned int i;
- if (as->userbuffer)
+ if (as->userbuffer && urb->actual_length)
if (copy_to_user(as->userbuffer, urb->transfer_buffer,
- urb->transfer_buffer_length))
+ urb->actual_length))
return -EFAULT;
if (put_user(as->status, &userurb->status))
return -EFAULT;
@@ -1497,7 +1535,6 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
}
}
- free_async(as);
if (put_user(ptr_to_compat(addr), (u32 __user *)arg))
return -EFAULT;
return 0;
@@ -1506,8 +1543,11 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
static int proc_reapurb_compat(struct dev_state *ps, void __user *arg)
{
struct async *as = reap_as(ps);
- if (as)
- return processcompl_compat(as, (void __user * __user *)arg);
+ if (as) {
+ int retval = processcompl_compat(as, (void __user * __user *)arg);
+ free_async(as);
+ return retval;
+ }
if (signal_pending(current))
return -EINTR;
return -EIO;
@@ -1515,11 +1555,16 @@ static int proc_reapurb_compat(struct dev_state *ps, void __user *arg)
static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg)
{
+ int retval;
struct async *as;
- if (!(as = async_getcompleted(ps)))
- return -EAGAIN;
- return processcompl_compat(as, (void __user * __user *)arg);
+ retval = -EAGAIN;
+ as = async_getcompleted(ps);
+ if (as) {
+ retval = processcompl_compat(as, (void __user * __user *)arg);
+ free_async(as);
+ }
+ return retval;
}
@@ -1616,7 +1661,10 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
if (driver == NULL || driver->ioctl == NULL) {
retval = -ENOTTY;
} else {
+ /* keep API that guarantees BKL */
+ lock_kernel();
retval = driver->ioctl(intf, ctl->ioctl_code, buf);
+ unlock_kernel();
if (retval == -ENOIOCTLCMD)
retval = -ENOTTY;
}
@@ -1699,6 +1747,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
+
usb_lock_device(dev);
if (!connected(ps)) {
usb_unlock_device(dev);
@@ -1865,9 +1914,7 @@ static long usbdev_ioctl(struct file *file, unsigned int cmd,
{
int ret;
- lock_kernel();
ret = usbdev_do_ioctl(file, cmd, (void __user *)arg);
- unlock_kernel();
return ret;
}
@@ -1878,9 +1925,7 @@ static long usbdev_compat_ioctl(struct file *file, unsigned int cmd,
{
int ret;
- lock_kernel();
ret = usbdev_do_ioctl(file, cmd, compat_ptr(arg));
- unlock_kernel();
return ret;
}
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 60a45f1e3a67..f3c233806fa3 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -25,7 +25,7 @@
#include <linux/device.h>
#include <linux/usb.h>
#include <linux/usb/quirks.h>
-#include <linux/workqueue.h>
+#include <linux/pm_runtime.h>
#include "hcd.h"
#include "usb.h"
@@ -221,7 +221,7 @@ static int usb_probe_device(struct device *dev)
{
struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
struct usb_device *udev = to_usb_device(dev);
- int error = -ENODEV;
+ int error = 0;
dev_dbg(dev, "%s\n", __func__);
@@ -230,18 +230,23 @@ static int usb_probe_device(struct device *dev)
/* The device should always appear to be in use
* unless the driver suports autosuspend.
*/
- udev->pm_usage_cnt = !(udriver->supports_autosuspend);
+ if (!udriver->supports_autosuspend)
+ error = usb_autoresume_device(udev);
- error = udriver->probe(udev);
+ if (!error)
+ error = udriver->probe(udev);
return error;
}
/* called from driver core with dev locked */
static int usb_unbind_device(struct device *dev)
{
+ struct usb_device *udev = to_usb_device(dev);
struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
- udriver->disconnect(to_usb_device(dev));
+ udriver->disconnect(udev);
+ if (!udriver->supports_autosuspend)
+ usb_autosuspend_device(udev);
return 0;
}
@@ -274,60 +279,62 @@ static int usb_probe_interface(struct device *dev)
intf->needs_binding = 0;
if (usb_device_is_owned(udev))
- return -ENODEV;
+ return error;
if (udev->authorized == 0) {
dev_err(&intf->dev, "Device is not authorized for usage\n");
- return -ENODEV;
+ return error;
}
id = usb_match_id(intf, driver->id_table);
if (!id)
id = usb_match_dynamic_id(intf, driver);
- if (id) {
- dev_dbg(dev, "%s - got id\n", __func__);
-
- error = usb_autoresume_device(udev);
- if (error)
- return error;
+ if (!id)
+ return error;
- /* Interface "power state" doesn't correspond to any hardware
- * state whatsoever. We use it to record when it's bound to
- * a driver that may start I/0: it's not frozen/quiesced.
- */
- mark_active(intf);
- intf->condition = USB_INTERFACE_BINDING;
+ dev_dbg(dev, "%s - got id\n", __func__);
- /* The interface should always appear to be in use
- * unless the driver suports autosuspend.
- */
- atomic_set(&intf->pm_usage_cnt, !driver->supports_autosuspend);
-
- /* Carry out a deferred switch to altsetting 0 */
- if (intf->needs_altsetting0) {
- error = usb_set_interface(udev, intf->altsetting[0].
- desc.bInterfaceNumber, 0);
- if (error < 0)
- goto err;
+ error = usb_autoresume_device(udev);
+ if (error)
+ return error;
- intf->needs_altsetting0 = 0;
- }
+ intf->condition = USB_INTERFACE_BINDING;
- error = driver->probe(intf, id);
- if (error)
+ /* Bound interfaces are initially active. They are
+ * runtime-PM-enabled only if the driver has autosuspend support.
+ * They are sensitive to their children's power states.
+ */
+ pm_runtime_set_active(dev);
+ pm_suspend_ignore_children(dev, false);
+ if (driver->supports_autosuspend)
+ pm_runtime_enable(dev);
+
+ /* Carry out a deferred switch to altsetting 0 */
+ if (intf->needs_altsetting0) {
+ error = usb_set_interface(udev, intf->altsetting[0].
+ desc.bInterfaceNumber, 0);
+ if (error < 0)
goto err;
-
- intf->condition = USB_INTERFACE_BOUND;
- usb_autosuspend_device(udev);
+ intf->needs_altsetting0 = 0;
}
+ error = driver->probe(intf, id);
+ if (error)
+ goto err;
+
+ intf->condition = USB_INTERFACE_BOUND;
+ usb_autosuspend_device(udev);
return error;
-err:
- mark_quiesced(intf);
+ err:
intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
usb_cancel_queued_reset(intf);
+
+ /* Unbound interfaces are always runtime-PM-disabled and -suspended */
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+
usb_autosuspend_device(udev);
return error;
}
@@ -377,9 +384,17 @@ static int usb_unbind_interface(struct device *dev)
usb_set_intfdata(intf, NULL);
intf->condition = USB_INTERFACE_UNBOUND;
- mark_quiesced(intf);
intf->needs_remote_wakeup = 0;
+ /* Unbound interfaces are always runtime-PM-disabled and -suspended */
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+
+ /* Undo any residual pm_autopm_get_interface_* calls */
+ for (r = atomic_read(&intf->pm_usage_cnt); r > 0; --r)
+ usb_autopm_put_interface_no_suspend(intf);
+ atomic_set(&intf->pm_usage_cnt, 0);
+
if (!error)
usb_autosuspend_device(udev);
@@ -410,7 +425,6 @@ int usb_driver_claim_interface(struct usb_driver *driver,
struct usb_interface *iface, void *priv)
{
struct device *dev = &iface->dev;
- struct usb_device *udev = interface_to_usbdev(iface);
int retval = 0;
if (dev->driver)
@@ -420,11 +434,16 @@ int usb_driver_claim_interface(struct usb_driver *driver,
usb_set_intfdata(iface, priv);
iface->needs_binding = 0;
- usb_pm_lock(udev);
iface->condition = USB_INTERFACE_BOUND;
- mark_active(iface);
- atomic_set(&iface->pm_usage_cnt, !driver->supports_autosuspend);
- usb_pm_unlock(udev);
+
+ /* Bound interfaces are initially active. They are
+ * runtime-PM-enabled only if the driver has autosuspend support.
+ * They are sensitive to their children's power states.
+ */
+ pm_runtime_set_active(dev);
+ pm_suspend_ignore_children(dev, false);
+ if (driver->supports_autosuspend)
+ pm_runtime_enable(dev);
/* if interface was already added, bind now; else let
* the future device_add() bind it, bypassing probe()
@@ -470,10 +489,10 @@ void usb_driver_release_interface(struct usb_driver *driver,
if (device_is_registered(dev)) {
device_release_driver(dev);
} else {
- down(&dev->sem);
+ device_lock(dev);
usb_unbind_interface(dev);
dev->driver = NULL;
- up(&dev->sem);
+ device_unlock(dev);
}
}
EXPORT_SYMBOL_GPL(usb_driver_release_interface);
@@ -691,9 +710,6 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct usb_device *usb_dev;
- /* driver is often null here; dev_dbg() would oops */
- pr_debug("usb %s: uevent\n", dev_name(dev));
-
if (is_usb_device(dev)) {
usb_dev = to_usb_device(dev);
} else if (is_usb_interface(dev)) {
@@ -705,6 +721,7 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
}
if (usb_dev->devnum < 0) {
+ /* driver is often null here; dev_dbg() would oops */
pr_debug("usb %s: already deleted?\n", dev_name(dev));
return -ENODEV;
}
@@ -983,7 +1000,6 @@ static void do_unbind_rebind(struct usb_device *udev, int action)
}
}
-/* Caller has locked udev's pm_mutex */
static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
{
struct usb_device_driver *udriver;
@@ -1007,7 +1023,6 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
return status;
}
-/* Caller has locked udev's pm_mutex */
static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
{
struct usb_device_driver *udriver;
@@ -1022,6 +1037,14 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
goto done;
}
+ /* Non-root devices on a full/low-speed bus must wait for their
+ * companion high-speed root hub, in case a handoff is needed.
+ */
+ if (!(msg.event & PM_EVENT_AUTO) && udev->parent &&
+ udev->bus->hs_companion)
+ device_pm_wait_for_dev(&udev->dev,
+ &udev->bus->hs_companion->root_hub->dev);
+
if (udev->quirks & USB_QUIRK_RESET_RESUME)
udev->reset_resume = 1;
@@ -1033,27 +1056,20 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
return status;
}
-/* Caller has locked intf's usb_device's pm mutex */
static int usb_suspend_interface(struct usb_device *udev,
struct usb_interface *intf, pm_message_t msg)
{
struct usb_driver *driver;
int status = 0;
- /* with no hardware, USB interfaces only use FREEZE and ON states */
- if (udev->state == USB_STATE_NOTATTACHED || !is_active(intf))
- goto done;
-
- /* This can happen; see usb_driver_release_interface() */
- if (intf->condition == USB_INTERFACE_UNBOUND)
+ if (udev->state == USB_STATE_NOTATTACHED ||
+ intf->condition == USB_INTERFACE_UNBOUND)
goto done;
driver = to_usb_driver(intf->dev.driver);
if (driver->suspend) {
status = driver->suspend(intf, msg);
- if (status == 0)
- mark_quiesced(intf);
- else if (!(msg.event & PM_EVENT_AUTO))
+ if (status && !(msg.event & PM_EVENT_AUTO))
dev_err(&intf->dev, "%s error %d\n",
"suspend", status);
} else {
@@ -1061,7 +1077,6 @@ static int usb_suspend_interface(struct usb_device *udev,
intf->needs_binding = 1;
dev_warn(&intf->dev, "no %s for driver %s?\n",
"suspend", driver->name);
- mark_quiesced(intf);
}
done:
@@ -1069,14 +1084,13 @@ static int usb_suspend_interface(struct usb_device *udev,
return status;
}
-/* Caller has locked intf's usb_device's pm_mutex */
static int usb_resume_interface(struct usb_device *udev,
struct usb_interface *intf, pm_message_t msg, int reset_resume)
{
struct usb_driver *driver;
int status = 0;
- if (udev->state == USB_STATE_NOTATTACHED || is_active(intf))
+ if (udev->state == USB_STATE_NOTATTACHED)
goto done;
/* Don't let autoresume interfere with unbinding */
@@ -1127,90 +1141,11 @@ static int usb_resume_interface(struct usb_device *udev,
done:
dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
- if (status == 0 && intf->condition == USB_INTERFACE_BOUND)
- mark_active(intf);
/* Later we will unbind the driver and/or reprobe, if necessary */
return status;
}
-#ifdef CONFIG_USB_SUSPEND
-
-/* Internal routine to check whether we may autosuspend a device. */
-static int autosuspend_check(struct usb_device *udev, int reschedule)
-{
- int i;
- struct usb_interface *intf;
- unsigned long suspend_time, j;
-
- /* For autosuspend, fail fast if anything is in use or autosuspend
- * is disabled. Also fail if any interfaces require remote wakeup
- * but it isn't available.
- */
- if (udev->pm_usage_cnt > 0)
- return -EBUSY;
- if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled)
- return -EPERM;
-
- suspend_time = udev->last_busy + udev->autosuspend_delay;
- if (udev->actconfig) {
- for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
- intf = udev->actconfig->interface[i];
- if (!is_active(intf))
- continue;
- if (atomic_read(&intf->pm_usage_cnt) > 0)
- return -EBUSY;
- if (intf->needs_remote_wakeup &&
- !udev->do_remote_wakeup) {
- dev_dbg(&udev->dev, "remote wakeup needed "
- "for autosuspend\n");
- return -EOPNOTSUPP;
- }
-
- /* Don't allow autosuspend if the device will need
- * a reset-resume and any of its interface drivers
- * doesn't include support.
- */
- if (udev->quirks & USB_QUIRK_RESET_RESUME) {
- struct usb_driver *driver;
-
- driver = to_usb_driver(intf->dev.driver);
- if (!driver->reset_resume ||
- intf->needs_remote_wakeup)
- return -EOPNOTSUPP;
- }
- }
- }
-
- /* If everything is okay but the device hasn't been idle for long
- * enough, queue a delayed autosuspend request. If the device
- * _has_ been idle for long enough and the reschedule flag is set,
- * likewise queue a delayed (1 second) autosuspend request.
- */
- j = jiffies;
- if (time_before(j, suspend_time))
- reschedule = 1;
- else
- suspend_time = j + HZ;
- if (reschedule) {
- if (!timer_pending(&udev->autosuspend.timer)) {
- queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
- round_jiffies_up_relative(suspend_time - j));
- }
- return -EAGAIN;
- }
- return 0;
-}
-
-#else
-
-static inline int autosuspend_check(struct usb_device *udev, int reschedule)
-{
- return 0;
-}
-
-#endif /* CONFIG_USB_SUSPEND */
-
/**
* usb_suspend_both - suspend a USB device and its interfaces
* @udev: the usb_device to suspend
@@ -1222,27 +1157,12 @@ static inline int autosuspend_check(struct usb_device *udev, int reschedule)
* all the interfaces which were suspended are resumed so that they remain
* in the same state as the device.
*
- * If an autosuspend is in progress the routine checks first to make sure
- * that neither the device itself or any of its active interfaces is in use
- * (pm_usage_cnt is greater than 0). If they are, the autosuspend fails.
- *
- * If the suspend succeeds, the routine recursively queues an autosuspend
- * request for @udev's parent device, thereby propagating the change up
- * the device tree. If all of the parent's children are now suspended,
- * the parent will autosuspend in turn.
- *
- * The suspend method calls are subject to mutual exclusion under control
- * of @udev's pm_mutex. Many of these calls are also under the protection
- * of @udev's device lock (including all requests originating outside the
- * USB subsystem), but autosuspend requests generated by a child device or
- * interface driver may not be. Usbcore will insure that the method calls
- * do not arrive during bind, unbind, or reset operations. However, drivers
- * must be prepared to handle suspend calls arriving at unpredictable times.
- * The only way to block such calls is to do an autoresume (preventing
- * autosuspends) while holding @udev's device lock (preventing outside
- * suspends).
- *
- * The caller must hold @udev->pm_mutex.
+ * Autosuspend requests originating from a child device or an interface
+ * driver may be made without the protection of @udev's device lock, but
+ * all other suspend calls will hold the lock. Usbcore will insure that
+ * method calls do not arrive during bind, unbind, or reset operations.
+ * However drivers must be prepared to handle suspend calls arriving at
+ * unpredictable times.
*
* This routine can run only in process context.
*/
@@ -1251,20 +1171,11 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
int status = 0;
int i = 0;
struct usb_interface *intf;
- struct usb_device *parent = udev->parent;
if (udev->state == USB_STATE_NOTATTACHED ||
udev->state == USB_STATE_SUSPENDED)
goto done;
- udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
-
- if (msg.event & PM_EVENT_AUTO) {
- status = autosuspend_check(udev, 0);
- if (status < 0)
- goto done;
- }
-
/* Suspend all the interfaces and then udev itself */
if (udev->actconfig) {
for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
@@ -1279,35 +1190,21 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
- pm_message_t msg2;
-
- msg2.event = msg.event ^ (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
+ msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
while (--i >= 0) {
intf = udev->actconfig->interface[i];
- usb_resume_interface(udev, intf, msg2, 0);
+ usb_resume_interface(udev, intf, msg, 0);
}
- /* Try another autosuspend when the interfaces aren't busy */
- if (msg.event & PM_EVENT_AUTO)
- autosuspend_check(udev, status == -EBUSY);
-
- /* If the suspend succeeded then prevent any more URB submissions,
- * flush any outstanding URBs, and propagate the suspend up the tree.
+ /* If the suspend succeeded then prevent any more URB submissions
+ * and flush any outstanding URBs.
*/
} else {
- cancel_delayed_work(&udev->autosuspend);
udev->can_submit = 0;
for (i = 0; i < 16; ++i) {
usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
}
-
- /* If this is just a FREEZE or a PRETHAW, udev might
- * not really be suspended. Only true suspends get
- * propagated up the device tree.
- */
- if (parent && udev->state == USB_STATE_SUSPENDED)
- usb_autosuspend_device(parent);
}
done:
@@ -1324,23 +1221,12 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
* the resume method for @udev and then calls the resume methods for all
* the interface drivers in @udev.
*
- * Before starting the resume, the routine calls itself recursively for
- * the parent device of @udev, thereby propagating the change up the device
- * tree and assuring that @udev will be able to resume. If the parent is
- * unable to resume successfully, the routine fails.
- *
- * The resume method calls are subject to mutual exclusion under control
- * of @udev's pm_mutex. Many of these calls are also under the protection
- * of @udev's device lock (including all requests originating outside the
- * USB subsystem), but autoresume requests generated by a child device or
- * interface driver may not be. Usbcore will insure that the method calls
- * do not arrive during bind, unbind, or reset operations. However, drivers
- * must be prepared to handle resume calls arriving at unpredictable times.
- * The only way to block such calls is to do an autoresume (preventing
- * other autoresumes) while holding @udev's device lock (preventing outside
- * resumes).
- *
- * The caller must hold @udev->pm_mutex.
+ * Autoresume requests originating from a child device or an interface
+ * driver may be made without the protection of @udev's device lock, but
+ * all other resume calls will hold the lock. Usbcore will insure that
+ * method calls do not arrive during bind, unbind, or reset operations.
+ * However drivers must be prepared to handle resume calls arriving at
+ * unpredictable times.
*
* This routine can run only in process context.
*/
@@ -1349,48 +1235,18 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
int status = 0;
int i;
struct usb_interface *intf;
- struct usb_device *parent = udev->parent;
- cancel_delayed_work(&udev->autosuspend);
if (udev->state == USB_STATE_NOTATTACHED) {
status = -ENODEV;
goto done;
}
udev->can_submit = 1;
- /* Propagate the resume up the tree, if necessary */
- if (udev->state == USB_STATE_SUSPENDED) {
- if (parent) {
- status = usb_autoresume_device(parent);
- if (status == 0) {
- status = usb_resume_device(udev, msg);
- if (status || udev->state ==
- USB_STATE_NOTATTACHED) {
- usb_autosuspend_device(parent);
-
- /* It's possible usb_resume_device()
- * failed after the port was
- * unsuspended, causing udev to be
- * logically disconnected. We don't
- * want usb_disconnect() to autosuspend
- * the parent again, so tell it that
- * udev disconnected while still
- * suspended. */
- if (udev->state ==
- USB_STATE_NOTATTACHED)
- udev->discon_suspended = 1;
- }
- }
- } else {
-
- /* We can't progagate beyond the USB subsystem,
- * so if a root hub's controller is suspended
- * then we're stuck. */
- status = usb_resume_device(udev, msg);
- }
- } else if (udev->reset_resume)
+ /* Resume the device */
+ if (udev->state == USB_STATE_SUSPENDED || udev->reset_resume)
status = usb_resume_device(udev, msg);
+ /* Resume the interfaces */
if (status == 0 && udev->actconfig) {
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
intf = udev->actconfig->interface[i];
@@ -1406,55 +1262,94 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
return status;
}
-#ifdef CONFIG_USB_SUSPEND
+/* The device lock is held by the PM core */
+int usb_suspend(struct device *dev, pm_message_t msg)
+{
+ struct usb_device *udev = to_usb_device(dev);
-/* Internal routine to adjust a device's usage counter and change
- * its autosuspend state.
- */
-static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
+ do_unbind_rebind(udev, DO_UNBIND);
+ udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+ return usb_suspend_both(udev, msg);
+}
+
+/* The device lock is held by the PM core */
+int usb_resume(struct device *dev, pm_message_t msg)
{
- int status = 0;
+ struct usb_device *udev = to_usb_device(dev);
+ int status;
- usb_pm_lock(udev);
- udev->pm_usage_cnt += inc_usage_cnt;
- WARN_ON(udev->pm_usage_cnt < 0);
- if (inc_usage_cnt)
- udev->last_busy = jiffies;
- if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) {
- if (udev->state == USB_STATE_SUSPENDED)
- status = usb_resume_both(udev, PMSG_AUTO_RESUME);
- if (status != 0)
- udev->pm_usage_cnt -= inc_usage_cnt;
- else if (inc_usage_cnt)
+ /* For PM complete calls, all we do is rebind interfaces */
+ if (msg.event == PM_EVENT_ON) {
+ if (udev->state != USB_STATE_NOTATTACHED)
+ do_unbind_rebind(udev, DO_REBIND);
+ status = 0;
+
+ /* For all other calls, take the device back to full power and
+ * tell the PM core in case it was autosuspended previously.
+ */
+ } else {
+ status = usb_resume_both(udev, msg);
+ if (status == 0) {
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
udev->last_busy = jiffies;
- } else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) {
- status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
+ }
}
- usb_pm_unlock(udev);
+
+ /* Avoid PM error messages for devices disconnected while suspended
+ * as we'll display regular disconnect messages just a bit later.
+ */
+ if (status == -ENODEV)
+ status = 0;
return status;
}
-/* usb_autosuspend_work - callback routine to autosuspend a USB device */
-void usb_autosuspend_work(struct work_struct *work)
-{
- struct usb_device *udev =
- container_of(work, struct usb_device, autosuspend.work);
+#endif /* CONFIG_PM */
- usb_autopm_do_device(udev, 0);
+#ifdef CONFIG_USB_SUSPEND
+
+/**
+ * usb_enable_autosuspend - allow a USB device to be autosuspended
+ * @udev: the USB device which may be autosuspended
+ *
+ * This routine allows @udev to be autosuspended. An autosuspend won't
+ * take place until the autosuspend_delay has elapsed and all the other
+ * necessary conditions are satisfied.
+ *
+ * The caller must hold @udev's device lock.
+ */
+int usb_enable_autosuspend(struct usb_device *udev)
+{
+ if (udev->autosuspend_disabled) {
+ udev->autosuspend_disabled = 0;
+ usb_autosuspend_device(udev);
+ }
+ return 0;
}
+EXPORT_SYMBOL_GPL(usb_enable_autosuspend);
-/* usb_autoresume_work - callback routine to autoresume a USB device */
-void usb_autoresume_work(struct work_struct *work)
+/**
+ * usb_disable_autosuspend - prevent a USB device from being autosuspended
+ * @udev: the USB device which may not be autosuspended
+ *
+ * This routine prevents @udev from being autosuspended and wakes it up
+ * if it is already autosuspended.
+ *
+ * The caller must hold @udev's device lock.
+ */
+int usb_disable_autosuspend(struct usb_device *udev)
{
- struct usb_device *udev =
- container_of(work, struct usb_device, autoresume);
+ int rc = 0;
- /* Wake it up, let the drivers do their thing, and then put it
- * back to sleep.
- */
- if (usb_autopm_do_device(udev, 1) == 0)
- usb_autopm_do_device(udev, -1);
+ if (!udev->autosuspend_disabled) {
+ rc = usb_autoresume_device(udev);
+ if (rc == 0)
+ udev->autosuspend_disabled = 1;
+ }
+ return rc;
}
+EXPORT_SYMBOL_GPL(usb_disable_autosuspend);
/**
* usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
@@ -1464,15 +1359,11 @@ void usb_autoresume_work(struct work_struct *work)
* @udev and wants to allow it to autosuspend. Examples would be when
* @udev's device file in usbfs is closed or after a configuration change.
*
- * @udev's usage counter is decremented. If it or any of the usage counters
- * for an active interface is greater than 0, no autosuspend request will be
- * queued. (If an interface driver does not support autosuspend then its
- * usage counter is permanently positive.) Furthermore, if an interface
- * driver requires remote-wakeup capability during autosuspend but remote
- * wakeup is disabled, the autosuspend will fail.
+ * @udev's usage counter is decremented; if it drops to 0 and all the
+ * interfaces are inactive then a delayed autosuspend will be attempted.
+ * The attempt may fail (see autosuspend_check()).
*
- * Often the caller will hold @udev's device lock, but this is not
- * necessary.
+ * The caller must hold @udev's device lock.
*
* This routine can run only in process context.
*/
@@ -1480,9 +1371,11 @@ void usb_autosuspend_device(struct usb_device *udev)
{
int status;
- status = usb_autopm_do_device(udev, -1);
- dev_vdbg(&udev->dev, "%s: cnt %d\n",
- __func__, udev->pm_usage_cnt);
+ udev->last_busy = jiffies;
+ status = pm_runtime_put_sync(&udev->dev);
+ dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
+ __func__, atomic_read(&udev->dev.power.usage_count),
+ status);
}
/**
@@ -1492,17 +1385,22 @@ void usb_autosuspend_device(struct usb_device *udev)
* This routine should be called when a core subsystem thinks @udev may
* be ready to autosuspend.
*
- * @udev's usage counter left unchanged. If it or any of the usage counters
- * for an active interface is greater than 0, or autosuspend is not allowed
- * for any other reason, no autosuspend request will be queued.
+ * @udev's usage counter left unchanged. If it is 0 and all the interfaces
+ * are inactive then an autosuspend will be attempted. The attempt may
+ * fail or be delayed.
+ *
+ * The caller must hold @udev's device lock.
*
* This routine can run only in process context.
*/
void usb_try_autosuspend_device(struct usb_device *udev)
{
- usb_autopm_do_device(udev, 0);
- dev_vdbg(&udev->dev, "%s: cnt %d\n",
- __func__, udev->pm_usage_cnt);
+ int status;
+
+ status = pm_runtime_idle(&udev->dev);
+ dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
+ __func__, atomic_read(&udev->dev.power.usage_count),
+ status);
}
/**
@@ -1511,16 +1409,15 @@ void usb_try_autosuspend_device(struct usb_device *udev)
*
* This routine should be called when a core subsystem wants to use @udev
* and needs to guarantee that it is not suspended. No autosuspend will
- * occur until usb_autosuspend_device is called. (Note that this will not
- * prevent suspend events originating in the PM core.) Examples would be
- * when @udev's device file in usbfs is opened or when a remote-wakeup
+ * occur until usb_autosuspend_device() is called. (Note that this will
+ * not prevent suspend events originating in the PM core.) Examples would
+ * be when @udev's device file in usbfs is opened or when a remote-wakeup
* request is received.
*
* @udev's usage counter is incremented to prevent subsequent autosuspends.
* However if the autoresume fails then the usage counter is re-decremented.
*
- * Often the caller will hold @udev's device lock, but this is not
- * necessary (and attempting it might cause deadlock).
+ * The caller must hold @udev's device lock.
*
* This routine can run only in process context.
*/
@@ -1528,42 +1425,14 @@ int usb_autoresume_device(struct usb_device *udev)
{
int status;
- status = usb_autopm_do_device(udev, 1);
- dev_vdbg(&udev->dev, "%s: status %d cnt %d\n",
- __func__, status, udev->pm_usage_cnt);
- return status;
-}
-
-/* Internal routine to adjust an interface's usage counter and change
- * its device's autosuspend state.
- */
-static int usb_autopm_do_interface(struct usb_interface *intf,
- int inc_usage_cnt)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- int status = 0;
-
- usb_pm_lock(udev);
- if (intf->condition == USB_INTERFACE_UNBOUND)
- status = -ENODEV;
- else {
- atomic_add(inc_usage_cnt, &intf->pm_usage_cnt);
- udev->last_busy = jiffies;
- if (inc_usage_cnt >= 0 &&
- atomic_read(&intf->pm_usage_cnt) > 0) {
- if (udev->state == USB_STATE_SUSPENDED)
- status = usb_resume_both(udev,
- PMSG_AUTO_RESUME);
- if (status != 0)
- atomic_sub(inc_usage_cnt, &intf->pm_usage_cnt);
- else
- udev->last_busy = jiffies;
- } else if (inc_usage_cnt <= 0 &&
- atomic_read(&intf->pm_usage_cnt) <= 0) {
- status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
- }
- }
- usb_pm_unlock(udev);
+ status = pm_runtime_get_sync(&udev->dev);
+ if (status < 0)
+ pm_runtime_put_sync(&udev->dev);
+ dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
+ __func__, atomic_read(&udev->dev.power.usage_count),
+ status);
+ if (status > 0)
+ status = 0;
return status;
}
@@ -1577,34 +1446,25 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
* closed.
*
* The routine decrements @intf's usage counter. When the counter reaches
- * 0, a delayed autosuspend request for @intf's device is queued. When
- * the delay expires, if @intf->pm_usage_cnt is still <= 0 along with all
- * the other usage counters for the sibling interfaces and @intf's
- * usb_device, the device and all its interfaces will be autosuspended.
- *
- * Note that @intf->pm_usage_cnt is owned by the interface driver. The
- * core will not change its value other than the increment and decrement
- * in usb_autopm_get_interface and usb_autopm_put_interface. The driver
- * may use this simple counter-oriented discipline or may set the value
- * any way it likes.
+ * 0, a delayed autosuspend request for @intf's device is attempted. The
+ * attempt may fail (see autosuspend_check()).
*
* If the driver has set @intf->needs_remote_wakeup then autosuspend will
* take place only if the device's remote-wakeup facility is enabled.
*
- * Suspend method calls queued by this routine can arrive at any time
- * while @intf is resumed and its usage counter is equal to 0. They are
- * not protected by the usb_device's lock but only by its pm_mutex.
- * Drivers must provide their own synchronization.
- *
* This routine can run only in process context.
*/
void usb_autopm_put_interface(struct usb_interface *intf)
{
- int status;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int status;
- status = usb_autopm_do_interface(intf, -1);
- dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
- __func__, status, atomic_read(&intf->pm_usage_cnt));
+ udev->last_busy = jiffies;
+ atomic_dec(&intf->pm_usage_cnt);
+ status = pm_runtime_put_sync(&intf->dev);
+ dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
+ __func__, atomic_read(&intf->dev.power.usage_count),
+ status);
}
EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
@@ -1612,11 +1472,11 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
* usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter
* @intf: the usb_interface whose counter should be decremented
*
- * This routine does essentially the same thing as
- * usb_autopm_put_interface(): it decrements @intf's usage counter and
- * queues a delayed autosuspend request if the counter is <= 0. The
- * difference is that it does not acquire the device's pm_mutex;
- * callers must handle all synchronization issues themselves.
+ * This routine does much the same thing as usb_autopm_put_interface():
+ * It decrements @intf's usage counter and schedules a delayed
+ * autosuspend request if the counter is <= 0. The difference is that it
+ * does not perform any synchronization; callers should hold a private
+ * lock and handle all synchronization issues themselves.
*
* Typically a driver would call this routine during an URB's completion
* handler, if no more URBs were pending.
@@ -1626,28 +1486,58 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
void usb_autopm_put_interface_async(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
+ unsigned long last_busy;
int status = 0;
- if (intf->condition == USB_INTERFACE_UNBOUND) {
- status = -ENODEV;
- } else {
- udev->last_busy = jiffies;
- atomic_dec(&intf->pm_usage_cnt);
- if (udev->autosuspend_disabled || udev->autosuspend_delay < 0)
- status = -EPERM;
- else if (atomic_read(&intf->pm_usage_cnt) <= 0 &&
- !timer_pending(&udev->autosuspend.timer)) {
- queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
+ last_busy = udev->last_busy;
+ udev->last_busy = jiffies;
+ atomic_dec(&intf->pm_usage_cnt);
+ pm_runtime_put_noidle(&intf->dev);
+
+ if (!udev->autosuspend_disabled) {
+ /* Optimization: Don't schedule a delayed autosuspend if
+ * the timer is already running and the expiration time
+ * wouldn't change.
+ *
+ * We have to use the interface's timer. Attempts to
+ * schedule a suspend for the device would fail because
+ * the interface is still active.
+ */
+ if (intf->dev.power.timer_expires == 0 ||
+ round_jiffies_up(last_busy) !=
+ round_jiffies_up(jiffies)) {
+ status = pm_schedule_suspend(&intf->dev,
+ jiffies_to_msecs(
round_jiffies_up_relative(
- udev->autosuspend_delay));
+ udev->autosuspend_delay)));
}
}
- dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
- __func__, status, atomic_read(&intf->pm_usage_cnt));
+ dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
+ __func__, atomic_read(&intf->dev.power.usage_count),
+ status);
}
EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
/**
+ * usb_autopm_put_interface_no_suspend - decrement a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be decremented
+ *
+ * This routine decrements @intf's usage counter but does not carry out an
+ * autosuspend.
+ *
+ * This routine can run in atomic context.
+ */
+void usb_autopm_put_interface_no_suspend(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ udev->last_busy = jiffies;
+ atomic_dec(&intf->pm_usage_cnt);
+ pm_runtime_put_noidle(&intf->dev);
+}
+EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend);
+
+/**
* usb_autopm_get_interface - increment a USB interface's PM-usage counter
* @intf: the usb_interface whose counter should be incremented
*
@@ -1659,25 +1549,8 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
* or @intf is unbound. A typical example would be a character-device
* driver when its device file is opened.
*
- *
- * The routine increments @intf's usage counter. (However if the
- * autoresume fails then the counter is re-decremented.) So long as the
- * counter is greater than 0, autosuspend will not be allowed for @intf
- * or its usb_device. When the driver is finished using @intf it should
- * call usb_autopm_put_interface() to decrement the usage counter and
- * queue a delayed autosuspend request (if the counter is <= 0).
- *
- *
- * Note that @intf->pm_usage_cnt is owned by the interface driver. The
- * core will not change its value other than the increment and decrement
- * in usb_autopm_get_interface and usb_autopm_put_interface. The driver
- * may use this simple counter-oriented discipline or may set the value
- * any way it likes.
- *
- * Resume method calls generated by this routine can arrive at any time
- * while @intf is suspended. They are not protected by the usb_device's
- * lock but only by its pm_mutex. Drivers must provide their own
- * synchronization.
+ * @intf's usage counter is incremented to prevent subsequent autosuspends.
+ * However if the autoresume fails then the counter is re-decremented.
*
* This routine can run only in process context.
*/
@@ -1685,9 +1558,16 @@ int usb_autopm_get_interface(struct usb_interface *intf)
{
int status;
- status = usb_autopm_do_interface(intf, 1);
- dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
- __func__, status, atomic_read(&intf->pm_usage_cnt));
+ status = pm_runtime_get_sync(&intf->dev);
+ if (status < 0)
+ pm_runtime_put_sync(&intf->dev);
+ else
+ atomic_inc(&intf->pm_usage_cnt);
+ dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
+ __func__, atomic_read(&intf->dev.power.usage_count),
+ status);
+ if (status > 0)
+ status = 0;
return status;
}
EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
@@ -1697,149 +1577,207 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
* @intf: the usb_interface whose counter should be incremented
*
* This routine does much the same thing as
- * usb_autopm_get_interface(): it increments @intf's usage counter and
- * queues an autoresume request if the result is > 0. The differences
- * are that it does not acquire the device's pm_mutex (callers must
- * handle all synchronization issues themselves), and it does not
- * autoresume the device directly (it only queues a request). After a
- * successful call, the device will generally not yet be resumed.
+ * usb_autopm_get_interface(): It increments @intf's usage counter and
+ * queues an autoresume request if the device is suspended. The
+ * differences are that it does not perform any synchronization (callers
+ * should hold a private lock and handle all synchronization issues
+ * themselves), and it does not autoresume the device directly (it only
+ * queues a request). After a successful call, the device may not yet be
+ * resumed.
*
* This routine can run in atomic context.
*/
int usb_autopm_get_interface_async(struct usb_interface *intf)
{
- struct usb_device *udev = interface_to_usbdev(intf);
- int status = 0;
+ int status = 0;
+ enum rpm_status s;
- if (intf->condition == USB_INTERFACE_UNBOUND)
- status = -ENODEV;
- else {
+ /* Don't request a resume unless the interface is already suspending
+ * or suspended. Doing so would force a running suspend timer to be
+ * cancelled.
+ */
+ pm_runtime_get_noresume(&intf->dev);
+ s = ACCESS_ONCE(intf->dev.power.runtime_status);
+ if (s == RPM_SUSPENDING || s == RPM_SUSPENDED)
+ status = pm_request_resume(&intf->dev);
+
+ if (status < 0 && status != -EINPROGRESS)
+ pm_runtime_put_noidle(&intf->dev);
+ else
atomic_inc(&intf->pm_usage_cnt);
- if (atomic_read(&intf->pm_usage_cnt) > 0 &&
- udev->state == USB_STATE_SUSPENDED)
- queue_work(ksuspend_usb_wq, &udev->autoresume);
- }
- dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
- __func__, status, atomic_read(&intf->pm_usage_cnt));
+ dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
+ __func__, atomic_read(&intf->dev.power.usage_count),
+ status);
+ if (status > 0)
+ status = 0;
return status;
}
EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
-#else
-
-void usb_autosuspend_work(struct work_struct *work)
-{}
-
-void usb_autoresume_work(struct work_struct *work)
-{}
-
-#endif /* CONFIG_USB_SUSPEND */
-
/**
- * usb_external_suspend_device - external suspend of a USB device and its interfaces
- * @udev: the usb_device to suspend
- * @msg: Power Management message describing this state transition
+ * usb_autopm_get_interface_no_resume - increment a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be incremented
*
- * This routine handles external suspend requests: ones not generated
- * internally by a USB driver (autosuspend) but rather coming from the user
- * (via sysfs) or the PM core (system sleep). The suspend will be carried
- * out regardless of @udev's usage counter or those of its interfaces,
- * and regardless of whether or not remote wakeup is enabled. Of course,
- * interface drivers still have the option of failing the suspend (if
- * there are unsuspended children, for example).
+ * This routine increments @intf's usage counter but does not carry out an
+ * autoresume.
*
- * The caller must hold @udev's device lock.
+ * This routine can run in atomic context.
*/
-int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg)
+void usb_autopm_get_interface_no_resume(struct usb_interface *intf)
{
- int status;
+ struct usb_device *udev = interface_to_usbdev(intf);
- do_unbind_rebind(udev, DO_UNBIND);
- usb_pm_lock(udev);
- status = usb_suspend_both(udev, msg);
- usb_pm_unlock(udev);
- return status;
+ udev->last_busy = jiffies;
+ atomic_inc(&intf->pm_usage_cnt);
+ pm_runtime_get_noresume(&intf->dev);
}
+EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume);
-/**
- * usb_external_resume_device - external resume of a USB device and its interfaces
- * @udev: the usb_device to resume
- * @msg: Power Management message describing this state transition
- *
- * This routine handles external resume requests: ones not generated
- * internally by a USB driver (autoresume) but rather coming from the user
- * (via sysfs), the PM core (system resume), or the device itself (remote
- * wakeup). @udev's usage counter is unaffected.
- *
- * The caller must hold @udev's device lock.
- */
-int usb_external_resume_device(struct usb_device *udev, pm_message_t msg)
+/* Internal routine to check whether we may autosuspend a device. */
+static int autosuspend_check(struct usb_device *udev)
{
- int status;
+ int i;
+ struct usb_interface *intf;
+ unsigned long suspend_time, j;
- usb_pm_lock(udev);
- status = usb_resume_both(udev, msg);
- udev->last_busy = jiffies;
- usb_pm_unlock(udev);
- if (status == 0)
- do_unbind_rebind(udev, DO_REBIND);
+ /* Fail if autosuspend is disabled, or any interfaces are in use, or
+ * any interface drivers require remote wakeup but it isn't available.
+ */
+ udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+ if (udev->actconfig) {
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
- /* Now that the device is awake, we can start trying to autosuspend
- * it again. */
- if (status == 0)
- usb_try_autosuspend_device(udev);
- return status;
+ /* We don't need to check interfaces that are
+ * disabled for runtime PM. Either they are unbound
+ * or else their drivers don't support autosuspend
+ * and so they are permanently active.
+ */
+ if (intf->dev.power.disable_depth)
+ continue;
+ if (atomic_read(&intf->dev.power.usage_count) > 0)
+ return -EBUSY;
+ if (intf->needs_remote_wakeup &&
+ !udev->do_remote_wakeup) {
+ dev_dbg(&udev->dev, "remote wakeup needed "
+ "for autosuspend\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* Don't allow autosuspend if the device will need
+ * a reset-resume and any of its interface drivers
+ * doesn't include support or needs remote wakeup.
+ */
+ if (udev->quirks & USB_QUIRK_RESET_RESUME) {
+ struct usb_driver *driver;
+
+ driver = to_usb_driver(intf->dev.driver);
+ if (!driver->reset_resume ||
+ intf->needs_remote_wakeup)
+ return -EOPNOTSUPP;
+ }
+ }
+ }
+
+ /* If everything is okay but the device hasn't been idle for long
+ * enough, queue a delayed autosuspend request.
+ */
+ j = ACCESS_ONCE(jiffies);
+ suspend_time = udev->last_busy + udev->autosuspend_delay;
+ if (time_before(j, suspend_time)) {
+ pm_schedule_suspend(&udev->dev, jiffies_to_msecs(
+ round_jiffies_up_relative(suspend_time - j)));
+ return -EAGAIN;
+ }
+ return 0;
}
-int usb_suspend(struct device *dev, pm_message_t msg)
+static int usb_runtime_suspend(struct device *dev)
{
- struct usb_device *udev;
-
- udev = to_usb_device(dev);
+ int status = 0;
- /* If udev is already suspended, we can skip this suspend and
- * we should also skip the upcoming system resume. High-speed
- * root hubs are an exception; they need to resume whenever the
- * system wakes up in order for USB-PERSIST port handover to work
- * properly.
+ /* A USB device can be suspended if it passes the various autosuspend
+ * checks. Runtime suspend for a USB device means suspending all the
+ * interfaces and then the device itself.
*/
- if (udev->state == USB_STATE_SUSPENDED) {
- if (udev->parent || udev->speed != USB_SPEED_HIGH)
- udev->skip_sys_resume = 1;
- return 0;
+ if (is_usb_device(dev)) {
+ struct usb_device *udev = to_usb_device(dev);
+
+ if (autosuspend_check(udev) != 0)
+ return -EAGAIN;
+
+ status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
+
+ /* If an interface fails the suspend, adjust the last_busy
+ * time so that we don't get another suspend attempt right
+ * away.
+ */
+ if (status) {
+ udev->last_busy = jiffies +
+ (udev->autosuspend_delay == 0 ?
+ HZ/2 : 0);
+ }
+
+ /* Prevent the parent from suspending immediately after */
+ else if (udev->parent) {
+ udev->parent->last_busy = jiffies;
+ }
}
- udev->skip_sys_resume = 0;
- return usb_external_suspend_device(udev, msg);
+ /* Runtime suspend for a USB interface doesn't mean anything. */
+ return status;
}
-int usb_resume(struct device *dev, pm_message_t msg)
+static int usb_runtime_resume(struct device *dev)
{
- struct usb_device *udev;
- int status;
+ /* Runtime resume for a USB device means resuming both the device
+ * and all its interfaces.
+ */
+ if (is_usb_device(dev)) {
+ struct usb_device *udev = to_usb_device(dev);
+ int status;
- udev = to_usb_device(dev);
+ status = usb_resume_both(udev, PMSG_AUTO_RESUME);
+ udev->last_busy = jiffies;
+ return status;
+ }
- /* If udev->skip_sys_resume is set then udev was already suspended
- * when the system sleep started, so we don't want to resume it
- * during this system wakeup.
- */
- if (udev->skip_sys_resume)
- return 0;
- status = usb_external_resume_device(udev, msg);
+ /* Runtime resume for a USB interface doesn't mean anything. */
+ return 0;
+}
- /* Avoid PM error messages for devices disconnected while suspended
- * as we'll display regular disconnect messages just a bit later.
+static int usb_runtime_idle(struct device *dev)
+{
+ /* An idle USB device can be suspended if it passes the various
+ * autosuspend checks. An idle interface can be suspended at
+ * any time.
*/
- if (status == -ENODEV)
- return 0;
- return status;
+ if (is_usb_device(dev)) {
+ struct usb_device *udev = to_usb_device(dev);
+
+ if (autosuspend_check(udev) != 0)
+ return 0;
+ }
+
+ pm_runtime_suspend(dev);
+ return 0;
}
-#endif /* CONFIG_PM */
+static struct dev_pm_ops usb_bus_pm_ops = {
+ .runtime_suspend = usb_runtime_suspend,
+ .runtime_resume = usb_runtime_resume,
+ .runtime_idle = usb_runtime_idle,
+};
+
+#else
+
+#define usb_bus_pm_ops (*(struct dev_pm_ops *) NULL)
+
+#endif /* CONFIG_USB_SUSPEND */
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
+ .pm = &usb_bus_pm_ops,
};
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index fdfaa7885515..d26b9ea981f9 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -186,6 +186,7 @@ int usb_create_ep_devs(struct device *parent,
ep_dev->dev.parent = parent;
ep_dev->dev.release = ep_device_release;
dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
+ device_enable_async_suspend(&ep_dev->dev);
retval = device_register(&ep_dev->dev);
if (retval)
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index bfc6c2eea647..c3536f151f02 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -34,7 +34,6 @@ static int usb_open(struct inode * inode, struct file * file)
int err = -ENODEV;
const struct file_operations *old_fops, *new_fops = NULL;
- lock_kernel();
down_read(&minor_rwsem);
c = usb_minors[minor];
@@ -53,7 +52,6 @@ static int usb_open(struct inode * inode, struct file * file)
fops_put(old_fops);
done:
up_read(&minor_rwsem);
- unlock_kernel();
return err;
}
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 2dcf906df569..15286533c15a 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/pm_runtime.h>
#include <linux/usb.h>
#include <asm/io.h>
@@ -37,6 +38,122 @@
/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
+#ifdef CONFIG_PM_SLEEP
+
+/* Coordinate handoffs between EHCI and companion controllers
+ * during system resume
+ */
+
+static DEFINE_MUTEX(companions_mutex);
+
+#define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI
+#define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI
+#define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI
+
+enum companion_action {
+ SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS
+};
+
+static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd,
+ enum companion_action action)
+{
+ struct pci_dev *companion;
+ struct usb_hcd *companion_hcd;
+ unsigned int slot = PCI_SLOT(pdev->devfn);
+
+ /* Iterate through other PCI functions in the same slot.
+ * If pdev is OHCI or UHCI then we are looking for EHCI, and
+ * vice versa.
+ */
+ companion = NULL;
+ for (;;) {
+ companion = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, companion);
+ if (!companion)
+ break;
+ if (companion->bus != pdev->bus ||
+ PCI_SLOT(companion->devfn) != slot)
+ continue;
+
+ companion_hcd = pci_get_drvdata(companion);
+ if (!companion_hcd)
+ continue;
+
+ /* For SET_HS_COMPANION, store a pointer to the EHCI bus in
+ * the OHCI/UHCI companion bus structure.
+ * For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus
+ * in the OHCI/UHCI companion bus structure.
+ * For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI
+ * companion controllers have fully resumed.
+ */
+
+ if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) &&
+ companion->class == CL_EHCI) {
+ /* action must be SET_HS_COMPANION */
+ dev_dbg(&companion->dev, "HS companion for %s\n",
+ dev_name(&pdev->dev));
+ hcd->self.hs_companion = &companion_hcd->self;
+
+ } else if (pdev->class == CL_EHCI &&
+ (companion->class == CL_OHCI ||
+ companion->class == CL_UHCI)) {
+ switch (action) {
+ case SET_HS_COMPANION:
+ dev_dbg(&pdev->dev, "HS companion for %s\n",
+ dev_name(&companion->dev));
+ companion_hcd->self.hs_companion = &hcd->self;
+ break;
+ case CLEAR_HS_COMPANION:
+ companion_hcd->self.hs_companion = NULL;
+ break;
+ case WAIT_FOR_COMPANIONS:
+ device_pm_wait_for_dev(&pdev->dev,
+ &companion->dev);
+ break;
+ }
+ }
+ }
+}
+
+static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
+{
+ mutex_lock(&companions_mutex);
+ dev_set_drvdata(&pdev->dev, hcd);
+ companion_common(pdev, hcd, SET_HS_COMPANION);
+ mutex_unlock(&companions_mutex);
+}
+
+static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
+{
+ mutex_lock(&companions_mutex);
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ /* If pdev is OHCI or UHCI, just clear its hs_companion pointer */
+ if (pdev->class == CL_OHCI || pdev->class == CL_UHCI)
+ hcd->self.hs_companion = NULL;
+
+ /* Otherwise search for companion buses and clear their pointers */
+ else
+ companion_common(pdev, hcd, CLEAR_HS_COMPANION);
+ mutex_unlock(&companions_mutex);
+}
+
+static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd)
+{
+ /* Only EHCI controllers need to wait.
+ * No locking is needed because a controller cannot be resumed
+ * while one of its companions is getting unbound.
+ */
+ if (pdev->class == CL_EHCI)
+ companion_common(pdev, hcd, WAIT_FOR_COMPANIONS);
+}
+
+#else /* !CONFIG_PM_SLEEP */
+
+static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
+static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
+static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {}
+
+#endif /* !CONFIG_PM_SLEEP */
/*-------------------------------------------------------------------------*/
@@ -123,7 +240,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (region == PCI_ROM_RESOURCE) {
dev_dbg(&dev->dev, "no i/o regions available\n");
retval = -EBUSY;
- goto err1;
+ goto err2;
}
}
@@ -132,6 +249,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
if (retval != 0)
goto err4;
+ set_hs_companion(dev, hcd);
return retval;
err4:
@@ -142,6 +260,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
} else
release_region(hcd->rsrc_start, hcd->rsrc_len);
err2:
+ clear_hs_companion(dev, hcd);
usb_put_hcd(hcd);
err1:
pci_disable_device(dev);
@@ -180,6 +299,7 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
} else {
release_region(hcd->rsrc_start, hcd->rsrc_len);
}
+ clear_hs_companion(dev, hcd);
usb_put_hcd(hcd);
pci_disable_device(dev);
}
@@ -344,6 +464,11 @@ static int resume_common(struct device *dev, bool hibernated)
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
if (hcd->driver->pci_resume) {
+ /* This call should be made only during system resume,
+ * not during runtime resume.
+ */
+ wait_for_companions(pci_dev, hcd);
+
retval = hcd->driver->pci_resume(hcd, hibernated);
if (retval) {
dev_err(dev, "PCI post-resume error %d!\n", retval);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 0495fa651225..2f8cedda8007 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -39,6 +39,7 @@
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
#include <linux/usb.h>
@@ -141,7 +142,7 @@ static const u8 usb3_rh_dev_descriptor[18] = {
0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
- 0x02, 0x00, /* __le16 idProduct; device 0x0002 */
+ 0x03, 0x00, /* __le16 idProduct; device 0x0003 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
0x03, /* __u8 iManufacturer; */
@@ -1670,11 +1671,16 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev,
}
}
for (i = 0; i < num_intfs; ++i) {
+ struct usb_host_interface *first_alt;
+ int iface_num;
+
+ first_alt = &new_config->intf_cache[i]->altsetting[0];
+ iface_num = first_alt->desc.bInterfaceNumber;
/* Set up endpoints for alternate interface setting 0 */
- alt = usb_find_alt_setting(new_config, i, 0);
+ alt = usb_find_alt_setting(new_config, iface_num, 0);
if (!alt)
/* No alt setting 0? Pick the first setting. */
- alt = &new_config->intf_cache[i]->altsetting[0];
+ alt = first_alt;
for (j = 0; j < alt->desc.bNumEndpoints; j++) {
ret = hcd->driver->add_endpoint(hcd, udev, &alt->endpoint[j]);
@@ -1684,6 +1690,24 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev,
}
}
if (cur_alt && new_alt) {
+ struct usb_interface *iface = usb_ifnum_to_if(udev,
+ cur_alt->desc.bInterfaceNumber);
+
+ if (iface->resetting_device) {
+ /*
+ * The USB core just reset the device, so the xHCI host
+ * and the device will think alt setting 0 is installed.
+ * However, the USB core will pass in the alternate
+ * setting installed before the reset as cur_alt. Dig
+ * out the alternate setting 0 structure, or the first
+ * alternate setting if a broken device doesn't have alt
+ * setting 0.
+ */
+ cur_alt = usb_altnum_to_altsetting(iface, 0);
+ if (!cur_alt)
+ cur_alt = &iface->altsetting[0];
+ }
+
/* Drop all the endpoints in the current alt setting */
for (i = 0; i < cur_alt->desc.bNumEndpoints; i++) {
ret = hcd->driver->drop_endpoint(hcd, udev,
@@ -1835,6 +1859,10 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
return status;
}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_USB_SUSPEND
+
/* Workqueue routine for root-hub remote wakeup */
static void hcd_resume_work(struct work_struct *work)
{
@@ -1842,8 +1870,7 @@ static void hcd_resume_work(struct work_struct *work)
struct usb_device *udev = hcd->self.root_hub;
usb_lock_device(udev);
- usb_mark_last_busy(udev);
- usb_external_resume_device(udev, PMSG_REMOTE_RESUME);
+ usb_remote_wakeup(udev);
usb_unlock_device(udev);
}
@@ -1862,12 +1889,12 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
spin_lock_irqsave (&hcd_root_hub_lock, flags);
if (hcd->rh_registered)
- queue_work(ksuspend_usb_wq, &hcd->wakeup_work);
+ queue_work(pm_wq, &hcd->wakeup_work);
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
}
EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
-#endif
+#endif /* CONFIG_USB_SUSPEND */
/*-------------------------------------------------------------------------*/
@@ -2012,7 +2039,7 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
hcd->rh_timer.data = (unsigned long) hcd;
-#ifdef CONFIG_PM
+#ifdef CONFIG_USB_SUSPEND
INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
#endif
mutex_init(&hcd->bandwidth_mutex);
@@ -2212,7 +2239,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
hcd->rh_registered = 0;
spin_unlock_irq (&hcd_root_hub_lock);
-#ifdef CONFIG_PM
+#ifdef CONFIG_USB_SUSPEND
cancel_work_sync(&hcd->wakeup_work);
#endif
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index bbe2b924aae8..a3cdb09734ab 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -80,7 +80,7 @@ struct usb_hcd {
struct timer_list rh_timer; /* drives root-hub polling */
struct urb *status_urb; /* the current status urb */
-#ifdef CONFIG_PM
+#ifdef CONFIG_USB_SUSPEND
struct work_struct wakeup_work; /* for remote wakeup */
#endif
@@ -248,7 +248,7 @@ struct hc_driver {
/* xHCI specific functions */
/* Called by usb_alloc_dev to alloc HC device structures */
int (*alloc_dev)(struct usb_hcd *, struct usb_device *);
- /* Called by usb_release_dev to free HC device structures */
+ /* Called by usb_disconnect to free HC device structures */
void (*free_dev)(struct usb_hcd *, struct usb_device *);
/* Bandwidth computation functions */
@@ -286,6 +286,7 @@ struct hc_driver {
*/
int (*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
+ int (*reset_device)(struct usb_hcd *, struct usb_device *);
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
@@ -463,16 +464,20 @@ extern int usb_find_interface_driver(struct usb_device *dev,
#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
#ifdef CONFIG_PM
-extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
extern void usb_root_hub_lost_power(struct usb_device *rhdev);
extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg);
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_USB_SUSPEND
+extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
#else
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
{
return;
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_USB_SUSPEND */
+
/*
* USB device fs stuff
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 0cec6caf6e9b..0940ccd6f4f4 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -22,6 +22,7 @@
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/freezer.h>
+#include <linux/pm_runtime.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
@@ -71,7 +72,6 @@ struct usb_hub {
unsigned mA_per_port; /* current for each child */
- unsigned init_done:1;
unsigned limited_power:1;
unsigned quiescing:1;
unsigned disconnected:1;
@@ -820,7 +820,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
}
init3:
hub->quiescing = 0;
- hub->init_done = 1;
status = usb_submit_urb(hub->urb, GFP_NOIO);
if (status < 0)
@@ -861,11 +860,6 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
int i;
cancel_delayed_work_sync(&hub->init_work);
- if (!hub->init_done) {
- hub->init_done = 1;
- usb_autopm_put_interface_no_suspend(
- to_usb_interface(hub->intfdev));
- }
/* khubd and related activity won't re-trigger */
hub->quiescing = 1;
@@ -1224,6 +1218,9 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
desc = intf->cur_altsetting;
hdev = interface_to_usbdev(intf);
+ /* Hubs have proper suspend/resume support */
+ usb_enable_autosuspend(hdev);
+
if (hdev->level == MAX_TOPO_LEVEL) {
dev_err(&intf->dev,
"Unsupported bus topology: hub nested too deep\n");
@@ -1402,10 +1399,8 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev)
if (udev->children[i])
recursively_mark_NOTATTACHED(udev->children[i]);
}
- if (udev->state == USB_STATE_SUSPENDED) {
- udev->discon_suspended = 1;
+ if (udev->state == USB_STATE_SUSPENDED)
udev->active_duration -= jiffies;
- }
udev->state = USB_STATE_NOTATTACHED;
}
@@ -1448,11 +1443,11 @@ void usb_set_device_state(struct usb_device *udev,
|| new_state == USB_STATE_SUSPENDED)
; /* No change to wakeup settings */
else if (new_state == USB_STATE_CONFIGURED)
- device_init_wakeup(&udev->dev,
+ device_set_wakeup_capable(&udev->dev,
(udev->actconfig->desc.bmAttributes
& USB_CONFIG_ATT_WAKEUP));
else
- device_init_wakeup(&udev->dev, 0);
+ device_set_wakeup_capable(&udev->dev, 0);
}
if (udev->state == USB_STATE_SUSPENDED &&
new_state != USB_STATE_SUSPENDED)
@@ -1529,31 +1524,15 @@ static void update_address(struct usb_device *udev, int devnum)
udev->devnum = devnum;
}
-#ifdef CONFIG_USB_SUSPEND
-
-static void usb_stop_pm(struct usb_device *udev)
+static void hub_free_dev(struct usb_device *udev)
{
- /* Synchronize with the ksuspend thread to prevent any more
- * autosuspend requests from being submitted, and decrement
- * the parent's count of unsuspended children.
- */
- usb_pm_lock(udev);
- if (udev->parent && !udev->discon_suspended)
- usb_autosuspend_device(udev->parent);
- usb_pm_unlock(udev);
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
- /* Stop any autosuspend or autoresume requests already submitted */
- cancel_delayed_work_sync(&udev->autosuspend);
- cancel_work_sync(&udev->autoresume);
+ /* Root hubs aren't real devices, so don't free HCD resources */
+ if (hcd->driver->free_dev && udev->parent)
+ hcd->driver->free_dev(hcd, udev);
}
-#else
-
-static inline void usb_stop_pm(struct usb_device *udev)
-{ }
-
-#endif
-
/**
* usb_disconnect - disconnect a device (usbcore-internal)
* @pdev: pointer to device being disconnected
@@ -1622,7 +1601,7 @@ void usb_disconnect(struct usb_device **pdev)
*pdev = NULL;
spin_unlock_irq(&device_state_lock);
- usb_stop_pm(udev);
+ hub_free_dev(udev);
put_device(&udev->dev);
}
@@ -1799,9 +1778,18 @@ int usb_new_device(struct usb_device *udev)
{
int err;
- /* Increment the parent's count of unsuspended children */
- if (udev->parent)
- usb_autoresume_device(udev->parent);
+ if (udev->parent) {
+ /* Initialize non-root-hub device wakeup to disabled;
+ * device (un)configuration controls wakeup capable
+ * sysfs power/wakeup controls wakeup enabled/disabled
+ */
+ device_init_wakeup(&udev->dev, 0);
+ device_set_wakeup_enable(&udev->dev, 1);
+ }
+
+ /* Tell the runtime-PM framework the device is active */
+ pm_runtime_set_active(&udev->dev);
+ pm_runtime_enable(&udev->dev);
usb_detect_quirks(udev);
err = usb_enumerate_device(udev); /* Read descriptors */
@@ -1817,6 +1805,7 @@ int usb_new_device(struct usb_device *udev)
/* Tell the world! */
announce_device(udev);
+ device_enable_async_suspend(&udev->dev);
/* Register the device. The device driver is responsible
* for configuring the device and invoking the add-device
* notifier chain (used by usbfs and possibly others).
@@ -1832,7 +1821,8 @@ int usb_new_device(struct usb_device *udev)
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
- usb_stop_pm(udev);
+ pm_runtime_disable(&udev->dev);
+ pm_runtime_set_suspended(&udev->dev);
return err;
}
@@ -1981,7 +1971,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
if (!(portstatus & USB_PORT_STAT_RESET) &&
(portstatus & USB_PORT_STAT_ENABLE)) {
if (hub_is_wusb(hub))
- udev->speed = USB_SPEED_VARIABLE;
+ udev->speed = USB_SPEED_WIRELESS;
else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
udev->speed = USB_SPEED_HIGH;
else if (portstatus & USB_PORT_STAT_LOW_SPEED)
@@ -2007,7 +1997,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
struct usb_device *udev, unsigned int delay)
{
int i, status;
+ struct usb_hcd *hcd;
+ hcd = bus_to_hcd(udev->bus);
/* Block EHCI CF initialization during the port reset.
* Some companion controllers don't like it when they mix.
*/
@@ -2035,6 +2027,14 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
/* TRSTRCY = 10 ms; plus some extra */
msleep(10 + 40);
update_address(udev, 0);
+ if (hcd->driver->reset_device) {
+ status = hcd->driver->reset_device(hcd, udev);
+ if (status < 0) {
+ dev_err(&udev->dev, "Cannot reset "
+ "HCD device state\n");
+ break;
+ }
+ }
/* FALL THROUGH */
case -ENOTCONN:
case -ENODEV:
@@ -2380,14 +2380,17 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
}
/* caller has locked udev */
-static int remote_wakeup(struct usb_device *udev)
+int usb_remote_wakeup(struct usb_device *udev)
{
int status = 0;
if (udev->state == USB_STATE_SUSPENDED) {
dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
- usb_mark_last_busy(udev);
- status = usb_external_resume_device(udev, PMSG_REMOTE_RESUME);
+ status = usb_autoresume_device(udev);
+ if (status == 0) {
+ /* Let the drivers do their thing, then... */
+ usb_autosuspend_device(udev);
+ }
}
return status;
}
@@ -2424,11 +2427,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
return status;
}
-static inline int remote_wakeup(struct usb_device *udev)
-{
- return 0;
-}
-
#endif
static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
@@ -2495,11 +2493,6 @@ EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
#else /* CONFIG_PM */
-static inline int remote_wakeup(struct usb_device *udev)
-{
- return 0;
-}
-
#define hub_suspend NULL
#define hub_resume NULL
#define hub_reset_resume NULL
@@ -2644,14 +2637,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
mutex_lock(&usb_address0_mutex);
- if ((hcd->driver->flags & HCD_USB3) && udev->config) {
- /* FIXME this will need special handling by the xHCI driver. */
- dev_dbg(&udev->dev,
- "xHCI reset of configured device "
- "not supported yet.\n");
- retval = -EINVAL;
- goto fail;
- } else if (!udev->config && oldspeed == USB_SPEED_SUPER) {
+ if (!udev->config && oldspeed == USB_SPEED_SUPER) {
/* Don't reset USB 3.0 devices during an initial setup */
usb_set_device_state(udev, USB_STATE_DEFAULT);
} else {
@@ -2677,7 +2663,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
*/
switch (udev->speed) {
case USB_SPEED_SUPER:
- case USB_SPEED_VARIABLE: /* fixed at 512 */
+ case USB_SPEED_WIRELESS: /* fixed at 512 */
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
break;
case USB_SPEED_HIGH: /* fixed at 64 */
@@ -2705,7 +2691,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
case USB_SPEED_SUPER:
speed = "super";
break;
- case USB_SPEED_VARIABLE:
+ case USB_SPEED_WIRELESS:
speed = "variable";
type = "Wireless ";
break;
@@ -3005,7 +2991,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
/* For a suspended device, treat this as a
* remote wakeup event.
*/
- status = remote_wakeup(udev);
+ status = usb_remote_wakeup(udev);
#endif
} else {
@@ -3191,6 +3177,7 @@ loop_disable:
loop:
usb_ep0_reinit(udev);
release_address(udev);
+ hub_free_dev(udev);
usb_put_dev(udev);
if ((status == -ENOTCONN) || (status == -ENOTSUPP))
break;
@@ -3258,7 +3245,7 @@ static void hub_events(void)
* disconnected while waiting for the lock to succeed. */
usb_lock_device(hdev);
if (unlikely(hub->disconnected))
- goto loop2;
+ goto loop_disconnected;
/* If the hub has died, clean up after it */
if (hdev->state == USB_STATE_NOTATTACHED) {
@@ -3347,8 +3334,11 @@ static void hub_events(void)
USB_PORT_FEAT_C_SUSPEND);
udev = hdev->children[i-1];
if (udev) {
+ /* TRSMRCY = 10 msec */
+ msleep(10);
+
usb_lock_device(udev);
- ret = remote_wakeup(hdev->
+ ret = usb_remote_wakeup(hdev->
children[i-1]);
usb_unlock_device(udev);
if (ret < 0)
@@ -3415,7 +3405,7 @@ static void hub_events(void)
* kick_khubd() and allow autosuspend.
*/
usb_autopm_put_interface(intf);
- loop2:
+ loop_disconnected:
usb_unlock_device(hdev);
kref_put(&hub->kref, hub_release);
@@ -3442,7 +3432,7 @@ static int hub_thread(void *__unused)
return 0;
}
-static struct usb_device_id hub_id_table [] = {
+static const struct usb_device_id hub_id_table[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
.bDeviceClass = USB_CLASS_HUB},
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
@@ -3692,19 +3682,14 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
usb_enable_interface(udev, intf, true);
ret = 0;
} else {
- /* We've just reset the device, so it will think alt
- * setting 0 is installed. For usb_set_interface() to
- * work properly, we need to set the current alternate
- * interface setting to 0 (or the first alt setting, if
- * the device doesn't have alt setting 0).
+ /* Let the bandwidth allocation function know that this
+ * device has been reset, and it will have to use
+ * alternate setting 0 as the current alternate setting.
*/
- intf->cur_altsetting =
- usb_find_alt_setting(config, i, 0);
- if (!intf->cur_altsetting)
- intf->cur_altsetting =
- &config->intf_cache[i]->altsetting[0];
+ intf->resetting_device = 1;
ret = usb_set_interface(udev, desc->bInterfaceNumber,
desc->bAlternateSetting);
+ intf->resetting_device = 0;
}
if (ret < 0) {
dev_err(&udev->dev, "failed to restore interface %d "
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 1b994846e8e0..cd220277c6c3 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -906,11 +906,11 @@ char *usb_cache_string(struct usb_device *udev, int index)
if (index <= 0)
return NULL;
- buf = kmalloc(MAX_USB_STRING_SIZE, GFP_KERNEL);
+ buf = kmalloc(MAX_USB_STRING_SIZE, GFP_NOIO);
if (buf) {
len = usb_string(udev, index, buf, MAX_USB_STRING_SIZE);
if (len > 0) {
- smallbuf = kmalloc(++len, GFP_KERNEL);
+ smallbuf = kmalloc(++len, GFP_NOIO);
if (!smallbuf)
return buf;
memcpy(smallbuf, buf, len);
@@ -1316,7 +1316,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
alt = usb_altnum_to_altsetting(iface, alternate);
if (!alt) {
- dev_warn(&dev->dev, "selecting invalid altsetting %d",
+ dev_warn(&dev->dev, "selecting invalid altsetting %d\n",
alternate);
return -EINVAL;
}
@@ -1471,7 +1471,7 @@ int usb_reset_configuration(struct usb_device *dev)
/* If not, reinstate the old alternate settings */
if (retval < 0) {
reset_old_alts:
- for (; i >= 0; i--) {
+ for (i--; i >= 0; i--) {
struct usb_interface *intf = config->interface[i];
struct usb_host_interface *alt;
@@ -1731,7 +1731,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
if (cp) {
nintf = cp->desc.bNumInterfaces;
new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),
- GFP_KERNEL);
+ GFP_NOIO);
if (!new_interfaces) {
dev_err(&dev->dev, "Out of memory\n");
return -ENOMEM;
@@ -1740,7 +1740,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
for (; n < nintf; ++n) {
new_interfaces[n] = kzalloc(
sizeof(struct usb_interface),
- GFP_KERNEL);
+ GFP_NOIO);
if (!new_interfaces[n]) {
dev_err(&dev->dev, "Out of memory\n");
ret = -ENOMEM;
@@ -1843,7 +1843,6 @@ free_interfaces:
intf->dev.dma_mask = dev->dev.dma_mask;
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
device_initialize(&intf->dev);
- mark_quiesced(intf);
dev_set_name(&intf->dev, "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration, alt->desc.bInterfaceNumber);
@@ -1867,6 +1866,7 @@ free_interfaces:
"adding %s (config #%d, interface %d)\n",
dev_name(&intf->dev), configuration,
intf->cur_altsetting->desc.bInterfaceNumber);
+ device_enable_async_suspend(&intf->dev);
ret = device_add(&intf->dev);
if (ret != 0) {
dev_err(&dev->dev, "device_add(%s) --> %d\n",
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index ab93918d9207..f073c5cb4e7b 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -103,10 +103,19 @@ void usb_detect_quirks(struct usb_device *udev)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks);
- /* By default, disable autosuspend for all non-hubs */
#ifdef CONFIG_USB_SUSPEND
- if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
- udev->autosuspend_disabled = 1;
+
+ /* By default, disable autosuspend for all devices. The hub driver
+ * will enable it for hubs.
+ */
+ usb_disable_autosuspend(udev);
+
+ /* Autosuspend can also be disabled if the initial autosuspend_delay
+ * is negative.
+ */
+ if (udev->autosuspend_delay < 0)
+ usb_autoresume_device(udev);
+
#endif
/* For the present, all devices default to USB-PERSIST enabled */
@@ -120,6 +129,7 @@ void usb_detect_quirks(struct usb_device *udev)
* for all devices. It will affect things like hub resets
* and EMF-related port disables.
*/
- udev->persist_enabled = 1;
+ if (!(udev->quirks & USB_QUIRK_RESET_MORPHS))
+ udev->persist_enabled = 1;
#endif /* CONFIG_PM */
}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 485edf937f25..43c002e3a9aa 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -115,6 +115,12 @@ show_speed(struct device *dev, struct device_attribute *attr, char *buf)
case USB_SPEED_HIGH:
speed = "480";
break;
+ case USB_SPEED_WIRELESS:
+ speed = "480";
+ break;
+ case USB_SPEED_SUPER:
+ speed = "5000";
+ break;
default:
speed = "unknown";
}
@@ -185,6 +191,36 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
static ssize_t
+show_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET_MORPHS));
+}
+
+static ssize_t
+set_avoid_reset_quirk(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int config;
+
+ if (sscanf(buf, "%d", &config) != 1 || config < 0 || config > 1)
+ return -EINVAL;
+ usb_lock_device(udev);
+ if (config)
+ udev->quirks |= USB_QUIRK_RESET_MORPHS;
+ else
+ udev->quirks &= ~USB_QUIRK_RESET_MORPHS;
+ usb_unlock_device(udev);
+ return count;
+}
+
+static DEVICE_ATTR(avoid_reset_quirk, S_IRUGO | S_IWUSR,
+ show_avoid_reset_quirk, set_avoid_reset_quirk);
+
+static ssize_t
show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
@@ -220,9 +256,10 @@ set_persist(struct device *dev, struct device_attribute *attr,
if (sscanf(buf, "%d", &value) != 1)
return -EINVAL;
- usb_pm_lock(udev);
+
+ usb_lock_device(udev);
udev->persist_enabled = !!value;
- usb_pm_unlock(udev);
+ usb_unlock_device(udev);
return count;
}
@@ -309,20 +346,34 @@ set_autosuspend(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
- int value;
+ int value, old_delay;
+ int rc;
if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ ||
value <= - INT_MAX/HZ)
return -EINVAL;
value *= HZ;
+ usb_lock_device(udev);
+ old_delay = udev->autosuspend_delay;
udev->autosuspend_delay = value;
- if (value >= 0)
- usb_try_autosuspend_device(udev);
- else {
- if (usb_autoresume_device(udev) == 0)
+
+ if (old_delay < 0) { /* Autosuspend wasn't allowed */
+ if (value >= 0)
usb_autosuspend_device(udev);
+ } else { /* Autosuspend was allowed */
+ if (value < 0) {
+ rc = usb_autoresume_device(udev);
+ if (rc < 0) {
+ count = rc;
+ udev->autosuspend_delay = old_delay;
+ }
+ } else {
+ usb_try_autosuspend_device(udev);
+ }
}
+
+ usb_unlock_device(udev);
return count;
}
@@ -350,34 +401,25 @@ set_level(struct device *dev, struct device_attribute *attr,
struct usb_device *udev = to_usb_device(dev);
int len = count;
char *cp;
- int rc = 0;
- int old_autosuspend_disabled;
+ int rc;
cp = memchr(buf, '\n', count);
if (cp)
len = cp - buf;
usb_lock_device(udev);
- old_autosuspend_disabled = udev->autosuspend_disabled;
- /* Setting the flags without calling usb_pm_lock is a subject to
- * races, but who cares...
- */
if (len == sizeof on_string - 1 &&
- strncmp(buf, on_string, len) == 0) {
- udev->autosuspend_disabled = 1;
- rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
+ strncmp(buf, on_string, len) == 0)
+ rc = usb_disable_autosuspend(udev);
- } else if (len == sizeof auto_string - 1 &&
- strncmp(buf, auto_string, len) == 0) {
- udev->autosuspend_disabled = 0;
- rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
+ else if (len == sizeof auto_string - 1 &&
+ strncmp(buf, auto_string, len) == 0)
+ rc = usb_enable_autosuspend(udev);
- } else
+ else
rc = -EINVAL;
- if (rc)
- udev->autosuspend_disabled = old_autosuspend_disabled;
usb_unlock_device(udev);
return (rc < 0 ? rc : count);
}
@@ -552,6 +594,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_version.attr,
&dev_attr_maxchild.attr,
&dev_attr_quirks.attr,
+ &dev_attr_avoid_reset_quirk.attr,
&dev_attr_authorized.attr,
&dev_attr_remove.attr,
NULL,
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index e7cae1334693..27080561a1c2 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -387,6 +387,13 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
unsigned int orig_flags = urb->transfer_flags;
unsigned int allowed;
+ static int pipetypes[4] = {
+ PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+ };
+
+ /* Check that the pipe's type matches the endpoint's type */
+ if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
+ return -EPIPE; /* The most suitable error code :-) */
/* enforce simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
@@ -430,7 +437,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
case USB_ENDPOINT_XFER_INT:
/* too small? */
switch (dev->speed) {
- case USB_SPEED_VARIABLE:
+ case USB_SPEED_WIRELESS:
if (urb->interval < 6)
return -EINVAL;
break;
@@ -446,7 +453,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (urb->interval > (1 << 15))
return -EINVAL;
max = 1 << 15;
- case USB_SPEED_VARIABLE:
+ case USB_SPEED_WIRELESS:
if (urb->interval > 16)
return -EINVAL;
break;
@@ -473,7 +480,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
default:
return -EINVAL;
}
- if (dev->speed != USB_SPEED_VARIABLE) {
+ if (dev->speed != USB_SPEED_WIRELESS) {
/* Round down to a power of 2, no more than max */
urb->interval = min(max, 1 << ilog2(urb->interval));
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 0daff0d968ba..1297e9b16a51 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -49,9 +49,6 @@ const char *usbcore_name = "usbcore";
static int nousb; /* Disable USB when built into kernel image */
-/* Workqueue for autosuspend and for remote wakeup of root hubs */
-struct workqueue_struct *ksuspend_usb_wq;
-
#ifdef CONFIG_USB_SUSPEND
static int usb_autosuspend_delay = 2; /* Default delay value,
* in seconds */
@@ -228,9 +225,6 @@ static void usb_release_dev(struct device *dev)
hcd = bus_to_hcd(udev->bus);
usb_destroy_configuration(udev);
- /* Root hubs aren't real devices, so don't free HCD resources */
- if (hcd->driver->free_dev && udev->parent)
- hcd->driver->free_dev(hcd, udev);
usb_put_hcd(hcd);
kfree(udev->product);
kfree(udev->manufacturer);
@@ -264,23 +258,6 @@ static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
#ifdef CONFIG_PM
-static int ksuspend_usb_init(void)
-{
- /* This workqueue is supposed to be both freezable and
- * singlethreaded. Its job doesn't justify running on more
- * than one CPU.
- */
- ksuspend_usb_wq = create_freezeable_workqueue("ksuspend_usbd");
- if (!ksuspend_usb_wq)
- return -ENOMEM;
- return 0;
-}
-
-static void ksuspend_usb_cleanup(void)
-{
- destroy_workqueue(ksuspend_usb_wq);
-}
-
/* USB device Power-Management thunks.
* There's no need to distinguish here between quiescing a USB device
* and powering it down; the generic_suspend() routine takes care of
@@ -296,7 +273,7 @@ static int usb_dev_prepare(struct device *dev)
static void usb_dev_complete(struct device *dev)
{
/* Currently used only for rebinding interfaces */
- usb_resume(dev, PMSG_RESUME); /* Message event is meaningless */
+ usb_resume(dev, PMSG_ON); /* FIXME: change to PMSG_COMPLETE */
}
static int usb_dev_suspend(struct device *dev)
@@ -342,9 +319,7 @@ static const struct dev_pm_ops usb_device_pm_ops = {
#else
-#define ksuspend_usb_init() 0
-#define ksuspend_usb_cleanup() do {} while (0)
-#define usb_device_pm_ops (*(struct dev_pm_ops *)0)
+#define usb_device_pm_ops (*(struct dev_pm_ops *) NULL)
#endif /* CONFIG_PM */
@@ -472,9 +447,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
INIT_LIST_HEAD(&dev->filelist);
#ifdef CONFIG_PM
- mutex_init(&dev->pm_mutex);
- INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
- INIT_WORK(&dev->autoresume, usb_autoresume_work);
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
dev->connect_time = jiffies;
dev->active_duration = -jiffies;
@@ -1117,9 +1089,6 @@ static int __init usb_init(void)
if (retval)
goto out;
- retval = ksuspend_usb_init();
- if (retval)
- goto out;
retval = bus_register(&usb_bus_type);
if (retval)
goto bus_register_failed;
@@ -1159,7 +1128,7 @@ major_init_failed:
bus_notifier_failed:
bus_unregister(&usb_bus_type);
bus_register_failed:
- ksuspend_usb_cleanup();
+ usb_debugfs_cleanup();
out:
return retval;
}
@@ -1181,7 +1150,6 @@ static void __exit usb_exit(void)
usb_hub_cleanup();
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
bus_unregister(&usb_bus_type);
- ksuspend_usb_cleanup();
usb_debugfs_cleanup();
}
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 4c36c7f512a0..cd882203ad34 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -55,24 +55,8 @@ extern void usb_major_cleanup(void);
extern int usb_suspend(struct device *dev, pm_message_t msg);
extern int usb_resume(struct device *dev, pm_message_t msg);
-extern void usb_autosuspend_work(struct work_struct *work);
-extern void usb_autoresume_work(struct work_struct *work);
extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);
-extern int usb_external_suspend_device(struct usb_device *udev,
- pm_message_t msg);
-extern int usb_external_resume_device(struct usb_device *udev,
- pm_message_t msg);
-
-static inline void usb_pm_lock(struct usb_device *udev)
-{
- mutex_lock_nested(&udev->pm_mutex, udev->level);
-}
-
-static inline void usb_pm_unlock(struct usb_device *udev)
-{
- mutex_unlock(&udev->pm_mutex);
-}
#else
@@ -86,9 +70,6 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
return 0;
}
-static inline void usb_pm_lock(struct usb_device *udev) {}
-static inline void usb_pm_unlock(struct usb_device *udev) {}
-
#endif
#ifdef CONFIG_USB_SUSPEND
@@ -96,6 +77,7 @@ static inline void usb_pm_unlock(struct usb_device *udev) {}
extern void usb_autosuspend_device(struct usb_device *udev);
extern void usb_try_autosuspend_device(struct usb_device *udev);
extern int usb_autoresume_device(struct usb_device *udev);
+extern int usb_remote_wakeup(struct usb_device *dev);
#else
@@ -106,9 +88,13 @@ static inline int usb_autoresume_device(struct usb_device *udev)
return 0;
}
+static inline int usb_remote_wakeup(struct usb_device *udev)
+{
+ return 0;
+}
+
#endif
-extern struct workqueue_struct *ksuspend_usb_wq;
extern struct bus_type usb_bus_type;
extern struct device_type usb_device_type;
extern struct device_type usb_if_device_type;
@@ -138,23 +124,6 @@ static inline int is_usb_device_driver(struct device_driver *drv)
for_devices;
}
-/* Interfaces and their "power state" are owned by usbcore */
-
-static inline void mark_active(struct usb_interface *f)
-{
- f->is_active = 1;
-}
-
-static inline void mark_quiesced(struct usb_interface *f)
-{
- f->is_active = 0;
-}
-
-static inline int is_active(const struct usb_interface *f)
-{
- return f->is_active;
-}
-
/* for labeling diagnostics */
extern const char *usbcore_name;
diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c
index 2958a1271b20..6e98a3697844 100644
--- a/drivers/usb/early/ehci-dbgp.c
+++ b/drivers/usb/early/ehci-dbgp.c
@@ -66,8 +66,6 @@ static struct ehci_dev ehci_dev;
#define USB_DEBUG_DEVNUM 127
-#define DBGP_DATA_TOGGLE 0x8800
-
#ifdef DBGP_DEBUG
#define dbgp_printk printk
static void dbgp_ehci_status(char *str)
@@ -88,11 +86,6 @@ static inline void dbgp_ehci_status(char *str) { }
static inline void dbgp_printk(const char *fmt, ...) { }
#endif
-static inline u32 dbgp_pid_update(u32 x, u32 tok)
-{
- return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff);
-}
-
static inline u32 dbgp_len_update(u32 x, u32 len)
{
return (x & ~0x0f) | (len & 0x0f);
@@ -136,6 +129,19 @@ static inline u32 dbgp_len_update(u32 x, u32 len)
#define DBGP_MAX_PACKET 8
#define DBGP_TIMEOUT (250 * 1000)
+#define DBGP_LOOPS 1000
+
+static inline u32 dbgp_pid_write_update(u32 x, u32 tok)
+{
+ static int data0 = USB_PID_DATA1;
+ data0 ^= USB_PID_DATA_TOGGLE;
+ return (x & 0xffff0000) | (data0 << 8) | (tok & 0xff);
+}
+
+static inline u32 dbgp_pid_read_update(u32 x, u32 tok)
+{
+ return (x & 0xffff0000) | (USB_PID_DATA0 << 8) | (tok & 0xff);
+}
static int dbgp_wait_until_complete(void)
{
@@ -180,7 +186,7 @@ static int dbgp_wait_until_done(unsigned ctrl)
{
u32 pids, lpid;
int ret;
- int loop = 3;
+ int loop = DBGP_LOOPS;
retry:
writel(ctrl | DBGP_GO, &ehci_debug->control);
@@ -197,6 +203,8 @@ retry:
*/
if (ret == -DBGP_TIMEOUT && !dbgp_not_safe)
dbgp_not_safe = 1;
+ if (ret == -DBGP_ERR_BAD && --loop > 0)
+ goto retry;
return ret;
}
@@ -245,12 +253,20 @@ static inline void dbgp_get_data(void *buf, int size)
bytes[i] = (hi >> (8*(i - 4))) & 0xff;
}
-static int dbgp_out(u32 addr, const char *bytes, int size)
+static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
+ const char *bytes, int size)
{
+ int ret;
+ u32 addr;
u32 pids, ctrl;
+ if (size > DBGP_MAX_PACKET)
+ return -1;
+
+ addr = DBGP_EPADDR(devnum, endpoint);
+
pids = readl(&ehci_debug->pids);
- pids = dbgp_pid_update(pids, USB_PID_OUT);
+ pids = dbgp_pid_write_update(pids, USB_PID_OUT);
ctrl = readl(&ehci_debug->control);
ctrl = dbgp_len_update(ctrl, size);
@@ -260,34 +276,7 @@ static int dbgp_out(u32 addr, const char *bytes, int size)
dbgp_set_data(bytes, size);
writel(addr, &ehci_debug->address);
writel(pids, &ehci_debug->pids);
- return dbgp_wait_until_done(ctrl);
-}
-
-static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
- const char *bytes, int size)
-{
- int ret;
- int loops = 5;
- u32 addr;
- if (size > DBGP_MAX_PACKET)
- return -1;
-
- addr = DBGP_EPADDR(devnum, endpoint);
-try_again:
- if (loops--) {
- ret = dbgp_out(addr, bytes, size);
- if (ret == -DBGP_ERR_BAD) {
- int try_loops = 3;
- do {
- /* Emit a dummy packet to re-sync communication
- * with the debug device */
- if (dbgp_out(addr, "12345678", 8) >= 0) {
- udelay(2);
- goto try_again;
- }
- } while (try_loops--);
- }
- }
+ ret = dbgp_wait_until_done(ctrl);
return ret;
}
@@ -304,7 +293,7 @@ static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
addr = DBGP_EPADDR(devnum, endpoint);
pids = readl(&ehci_debug->pids);
- pids = dbgp_pid_update(pids, USB_PID_IN);
+ pids = dbgp_pid_read_update(pids, USB_PID_IN);
ctrl = readl(&ehci_debug->control);
ctrl = dbgp_len_update(ctrl, size);
@@ -362,7 +351,6 @@ static int dbgp_control_msg(unsigned devnum, int requesttype,
return dbgp_bulk_read(devnum, 0, data, size);
}
-
/* Find a PCI capability */
static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap)
{
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index ee411206c699..7460cd797f45 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -812,6 +812,16 @@ config USB_CDC_COMPOSITE
Say "y" to link the driver statically, or "m" to build a
dynamically linked module.
+config USB_G_NOKIA
+ tristate "Nokia composite gadget"
+ depends on PHONET
+ help
+ The Nokia composite gadget provides support for acm, obex
+ and phonet in only one composite gadget driver.
+
+ It's only really useful for N900 hardware. If you're building
+ a kernel for N900, say Y or M here. If unsure, say N.
+
config USB_G_MULTI
tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
depends on BLOCK && NET
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 2e2c047262b7..43b51da8d727 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -43,6 +43,7 @@ g_mass_storage-objs := mass_storage.o
g_printer-objs := printer.o
g_cdc-objs := cdc2.o
g_multi-objs := multi.o
+g_nokia-objs := nokia.o
obj-$(CONFIG_USB_ZERO) += g_zero.o
obj-$(CONFIG_USB_AUDIO) += g_audio.o
@@ -55,4 +56,5 @@ obj-$(CONFIG_USB_G_PRINTER) += g_printer.o
obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
obj-$(CONFIG_USB_G_MULTI) += g_multi.o
+obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 043e04db2a05..12ac9cd32a07 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -1656,9 +1656,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
if (!res)
return -ENXIO;
- if (!request_mem_region(res->start,
- res->end - res->start + 1,
- driver_name)) {
+ if (!request_mem_region(res->start, resource_size(res), driver_name)) {
DBG("someone's using UDC memory\n");
return -EBUSY;
}
@@ -1699,7 +1697,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
udc->ep[3].maxpacket = 64;
}
- udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
+ udc->udp_baseaddr = ioremap(res->start, resource_size(res));
if (!udc->udp_baseaddr) {
retval = -ENOMEM;
goto fail0a;
@@ -1781,7 +1779,7 @@ fail0a:
if (cpu_is_at91rm9200())
gpio_free(udc->board.pullup_pin);
fail0:
- release_mem_region(res->start, res->end - res->start + 1);
+ release_mem_region(res->start, resource_size(res));
DBG("%s probe failed, %d\n", driver_name, retval);
return retval;
}
@@ -1813,7 +1811,7 @@ static int __exit at91udc_remove(struct platform_device *pdev)
gpio_free(udc->board.pullup_pin);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, res->end - res->start + 1);
+ release_mem_region(res->start, resource_size(res));
clk_put(udc->iclk);
clk_put(udc->fclk);
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 4e970cf0e29a..f79bdfe4bed9 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -320,7 +320,7 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc)
static int vbus_is_present(struct usba_udc *udc)
{
if (gpio_is_valid(udc->vbus_pin))
- return gpio_get_value(udc->vbus_pin);
+ return gpio_get_value(udc->vbus_pin) ^ udc->vbus_pin_inverted;
/* No Vbus detection: Assume always present */
return 1;
@@ -1763,7 +1763,7 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
if (!udc->driver)
goto out;
- vbus = gpio_get_value(udc->vbus_pin);
+ vbus = vbus_is_present(udc);
if (vbus != udc->vbus_prev) {
if (vbus) {
toggle_bias(1);
@@ -1914,14 +1914,14 @@ static int __init usba_udc_probe(struct platform_device *pdev)
udc->vbus_pin = -ENODEV;
ret = -ENOMEM;
- udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ udc->regs = ioremap(regs->start, resource_size(regs));
if (!udc->regs) {
dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
goto err_map_regs;
}
dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
(unsigned long)regs->start, udc->regs);
- udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1);
+ udc->fifo = ioremap(fifo->start, resource_size(fifo));
if (!udc->fifo) {
dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
goto err_map_fifo;
@@ -2000,6 +2000,7 @@ static int __init usba_udc_probe(struct platform_device *pdev)
if (gpio_is_valid(pdata->vbus_pin)) {
if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
udc->vbus_pin = pdata->vbus_pin;
+ udc->vbus_pin_inverted = pdata->vbus_pin_inverted;
ret = request_irq(gpio_to_irq(udc->vbus_pin),
usba_vbus_irq, 0,
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
index f7baea307f0d..88a2e07a11a8 100644
--- a/drivers/usb/gadget/atmel_usba_udc.h
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -323,6 +323,7 @@ struct usba_udc {
struct platform_device *pdev;
int irq;
int vbus_pin;
+ int vbus_pin_inverted;
struct clk *pclk;
struct clk *hclk;
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index cd0914ec898e..65a5f94cbc04 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -265,16 +265,24 @@ struct usb_ep * __init usb_ep_autoconfig (
return ep;
}
- } else if (gadget_is_sh (gadget) && USB_ENDPOINT_XFER_INT == type) {
- /* single buffering is enough; maybe 8 byte fifo is too */
- ep = find_ep (gadget, "ep3in-bulk");
- if (ep && ep_matches (gadget, ep, desc))
- return ep;
-
- } else if (gadget_is_mq11xx (gadget) && USB_ENDPOINT_XFER_INT == type) {
- ep = find_ep (gadget, "ep1-bulk");
+#ifdef CONFIG_BLACKFIN
+ } else if (gadget_is_musbhsfc(gadget) || gadget_is_musbhdrc(gadget)) {
+ if ((USB_ENDPOINT_XFER_BULK == type) ||
+ (USB_ENDPOINT_XFER_ISOC == type)) {
+ if (USB_DIR_IN & desc->bEndpointAddress)
+ ep = find_ep (gadget, "ep5in");
+ else
+ ep = find_ep (gadget, "ep6out");
+ } else if (USB_ENDPOINT_XFER_INT == type) {
+ if (USB_DIR_IN & desc->bEndpointAddress)
+ ep = find_ep(gadget, "ep1in");
+ else
+ ep = find_ep(gadget, "ep2out");
+ } else
+ ep = NULL;
if (ep && ep_matches (gadget, ep, desc))
return ep;
+#endif
}
/* Second, look at endpoints until an unclaimed one looks usable */
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 141372b6e7a1..400f80372d93 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -259,7 +259,7 @@ static struct usb_configuration rndis_config_driver = {
/*-------------------------------------------------------------------------*/
-#ifdef USB_ETH_EEM
+#ifdef CONFIG_USB_ETH_EEM
static int use_eem = 1;
#else
static int use_eem;
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index d10353d46b86..e49c7325dce2 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -702,14 +702,6 @@ acm_unbind(struct usb_configuration *c, struct usb_function *f)
/* Some controllers can't support CDC ACM ... */
static inline bool can_support_cdc(struct usb_configuration *c)
{
- /* SH3 doesn't support multiple interfaces */
- if (gadget_is_sh(c->cdev->gadget))
- return false;
-
- /* sa1100 doesn't have a third interrupt endpoint */
- if (gadget_is_sa1100(c->cdev->gadget))
- return false;
-
/* everything else is *probably* fine ... */
return true;
}
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
index df77f6131c73..f1e3aad76c37 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_audio.c
@@ -60,7 +60,7 @@ DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
/* B.3.2 Class-Specific AC Interface Descriptor */
-static struct uac_ac_header_descriptor_2 ac_header_desc = {
+static struct uac_ac_header_descriptor_v1_2 ac_header_desc = {
.bLength = UAC_DT_AC_HEADER_LENGTH,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_HEADER,
@@ -124,7 +124,7 @@ static struct usb_audio_control_selector feature_unit = {
};
#define OUTPUT_TERMINAL_ID 3
-static struct uac_output_terminal_descriptor output_terminal_desc = {
+static struct uac_output_terminal_descriptor_v1 output_terminal_desc = {
.bLength = UAC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
@@ -154,7 +154,7 @@ static struct usb_interface_descriptor as_interface_alt_1_desc = {
};
/* B.4.2 Class-Specific AS Interface Descriptor */
-static struct uac_as_header_descriptor as_header_desc = {
+static struct uac_as_header_descriptor_v1 as_header_desc = {
.bLength = UAC_DT_AS_HEADER_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_AS_GENERAL,
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index ecf5bdd0ae06..2fff530efc19 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -497,12 +497,9 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
struct net_device *net;
/* Enable zlps by default for ECM conformance;
- * override for musb_hdrc (avoids txdma ovhead)
- * and sa1100 (can't).
+ * override for musb_hdrc (avoids txdma ovhead).
*/
- ecm->port.is_zlp_ok = !(
- gadget_is_sa1100(cdev->gadget)
- || gadget_is_musbhdrc(cdev->gadget)
+ ecm->port.is_zlp_ok = !(gadget_is_musbhdrc(cdev->gadget)
);
ecm->port.cdc_filter = DEFAULT_FILTER;
DBG(cdev, "activate ecm\n");
diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c
index 0a577d5694fd..d4f0db58a8ad 100644
--- a/drivers/usb/gadget/f_eem.c
+++ b/drivers/usb/gadget/f_eem.c
@@ -358,7 +358,7 @@ done:
* b15: bmType (0 == data)
*/
len = skb->len;
- put_unaligned_le16((len & 0x3FFF) | BIT(14), skb_push(skb, 2));
+ put_unaligned_le16(len & 0x3FFF, skb_push(skb, 2));
/* add a zero-length EEM packet, if needed */
if (padlen)
@@ -464,7 +464,6 @@ static int eem_unwrap(struct gether *port,
}
/* validate CRC */
- crc = get_unaligned_le32(skb->data + len - ETH_FCS_LEN);
if (header & BIT(14)) {
crc = get_unaligned_le32(skb->data + len
- ETH_FCS_LEN);
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index a37640eba434..5a3cdd08f1d0 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -368,7 +368,7 @@ struct fsg_common {
struct task_struct *thread_task;
/* Callback function to call when thread exits. */
- void (*thread_exits)(struct fsg_common *common);
+ int (*thread_exits)(struct fsg_common *common);
/* Gadget's private data. */
void *private_data;
@@ -392,8 +392,12 @@ struct fsg_config {
const char *lun_name_format;
const char *thread_name;
- /* Callback function to call when thread exits. */
- void (*thread_exits)(struct fsg_common *common);
+ /* Callback function to call when thread exits. If no
+ * callback is set or it returns value lower then zero MSF
+ * will force eject all LUNs it operates on (including those
+ * marked as non-removable or with prevent_medium_removal flag
+ * set). */
+ int (*thread_exits)(struct fsg_common *common);
/* Gadget's private data. */
void *private_data;
@@ -614,7 +618,12 @@ static int fsg_setup(struct usb_function *f,
return -EDOM;
VDBG(fsg, "get max LUN\n");
*(u8 *) req->buf = fsg->common->nluns - 1;
- return 1;
+
+ /* Respond with data/status */
+ req->length = min((u16)1, w_length);
+ fsg->common->ep0req_name =
+ ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out";
+ return ep0_queue(fsg->common);
}
VDBG(fsg,
@@ -1041,7 +1050,7 @@ static void invalidate_sub(struct fsg_lun *curlun)
unsigned long rc;
rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
- VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc);
+ VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
}
static int do_verify(struct fsg_common *common)
@@ -2524,14 +2533,6 @@ static void handle_exception(struct fsg_common *common)
case FSG_STATE_CONFIG_CHANGE:
rc = do_set_config(common, new_config);
- if (common->ep0_req_tag != exception_req_tag)
- break;
- if (rc != 0) { /* STALL on errors */
- DBG(common, "ep0 set halt\n");
- usb_ep_set_halt(common->ep0);
- } else { /* Complete the status stage */
- ep0_queue(common);
- }
break;
case FSG_STATE_EXIT:
@@ -2615,8 +2616,20 @@ static int fsg_main_thread(void *common_)
common->thread_task = NULL;
spin_unlock_irq(&common->lock);
- if (common->thread_exits)
- common->thread_exits(common);
+ if (!common->thread_exits || common->thread_exits(common) < 0) {
+ struct fsg_lun *curlun = common->luns;
+ unsigned i = common->nluns;
+
+ down_write(&common->filesem);
+ for (; i--; ++curlun) {
+ if (!fsg_lun_is_open(curlun))
+ continue;
+
+ fsg_lun_close(curlun);
+ curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
+ }
+ up_write(&common->filesem);
+ }
/* Let the unbind and cleanup routines know the thread has exited */
complete_and_exit(&common->thread_notifier, 0);
@@ -2763,10 +2776,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
if (cfg->release != 0xffff) {
i = cfg->release;
} else {
- /* The sa1100 controller is not supported */
- i = gadget_is_sa1100(gadget)
- ? -1
- : usb_gadget_controller_number(gadget);
+ i = usb_gadget_controller_number(gadget);
if (i >= 0) {
i = 0x0300 + i;
} else {
@@ -2791,8 +2801,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
* disable stalls.
*/
common->can_stall = cfg->can_stall &&
- !(gadget_is_sh(common->gadget) ||
- gadget_is_at91(common->gadget));
+ !(gadget_is_at91(common->gadget));
spin_lock_init(&common->lock);
@@ -2852,7 +2861,6 @@ error_release:
/* Call fsg_common_release() directly, ref might be not
* initialised */
fsg_common_release(&common->ref);
- complete(&common->thread_notifier);
return ERR_PTR(rc);
}
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 95dae4c1ea40..a30e60c7f129 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -769,10 +769,6 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
/* Some controllers can't support RNDIS ... */
static inline bool can_support_rndis(struct usb_configuration *c)
{
- /* only two endpoints on sa1100 */
- if (gadget_is_sa1100(c->cdev->gadget))
- return false;
-
/* everything else is *presumably* fine */
return true;
}
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 29dfb0277ffb..b49d86e3e45b 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1448,7 +1448,7 @@ static void invalidate_sub(struct fsg_lun *curlun)
unsigned long rc;
rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
- VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc);
+ VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
}
static int do_verify(struct fsg_dev *fsg)
@@ -3208,15 +3208,11 @@ static int __init check_parameters(struct fsg_dev *fsg)
* halt bulk endpoints correctly. If one of them is present,
* disable stalls.
*/
- if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget))
+ if (gadget_is_at91(fsg->gadget))
mod_data.can_stall = 0;
if (mod_data.release == 0xffff) { // Parameter wasn't set
- /* The sa1100 controller is not supported */
- if (gadget_is_sa1100(fsg->gadget))
- gcnum = -1;
- else
- gcnum = usb_gadget_controller_number(fsg->gadget);
+ gcnum = usb_gadget_controller_number(fsg->gadget);
if (gcnum >= 0)
mod_data.release = 0x0300 + gcnum;
else {
diff --git a/drivers/usb/gadget/fsl_mx3_udc.c b/drivers/usb/gadget/fsl_mx3_udc.c
index 4bc2bf3d602e..20a802ecaa15 100644
--- a/drivers/usb/gadget/fsl_mx3_udc.c
+++ b/drivers/usb/gadget/fsl_mx3_udc.c
@@ -17,6 +17,8 @@
#include <linux/fsl_devices.h>
#include <linux/platform_device.h>
+#include <mach/hardware.h>
+
static struct clk *mxc_ahb_clk;
static struct clk *mxc_usb_clk;
@@ -28,14 +30,16 @@ int fsl_udc_clk_init(struct platform_device *pdev)
pdata = pdev->dev.platform_data;
- mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb");
- if (IS_ERR(mxc_ahb_clk))
- return PTR_ERR(mxc_ahb_clk);
+ if (!cpu_is_mx35()) {
+ mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb");
+ if (IS_ERR(mxc_ahb_clk))
+ return PTR_ERR(mxc_ahb_clk);
- ret = clk_enable(mxc_ahb_clk);
- if (ret < 0) {
- dev_err(&pdev->dev, "clk_enable(\"usb_ahb\") failed\n");
- goto eenahb;
+ ret = clk_enable(mxc_ahb_clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "clk_enable(\"usb_ahb\") failed\n");
+ goto eenahb;
+ }
}
/* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */
@@ -50,6 +54,7 @@ int fsl_udc_clk_init(struct platform_device *pdev)
if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
(freq < 59999000 || freq > 60001000)) {
dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
+ ret = -EINVAL;
goto eclkrate;
}
@@ -66,9 +71,11 @@ eclkrate:
clk_put(mxc_usb_clk);
mxc_usb_clk = NULL;
egusb:
- clk_disable(mxc_ahb_clk);
+ if (!cpu_is_mx35())
+ clk_disable(mxc_ahb_clk);
eenahb:
- clk_put(mxc_ahb_clk);
+ if (!cpu_is_mx35())
+ clk_put(mxc_ahb_clk);
return ret;
}
@@ -90,6 +97,8 @@ void fsl_udc_clk_release(void)
clk_disable(mxc_usb_clk);
clk_put(mxc_usb_clk);
}
- clk_disable(mxc_ahb_clk);
- clk_put(mxc_ahb_clk);
+ if (!cpu_is_mx35()) {
+ clk_disable(mxc_ahb_clk);
+ clk_put(mxc_ahb_clk);
+ }
}
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index 7881f12413c4..3537d51073b2 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -2749,7 +2749,7 @@ static int __devexit qe_udc_remove(struct of_device *ofdev)
}
/*-------------------------------------------------------------------------*/
-static struct of_device_id __devinitdata qe_udc_match[] = {
+static const struct of_device_id qe_udc_match[] __devinitconst = {
{
.compatible = "fsl,mpc8323-qe-usb",
.data = (void *)PORT_QE,
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index f2d270b202f2..1edbc12fff18 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -45,46 +45,18 @@
#define gadget_is_goku(g) 0
#endif
-/* SH3 UDC -- not yet ported 2.4 --> 2.6 */
-#ifdef CONFIG_USB_GADGET_SUPERH
-#define gadget_is_sh(g) !strcmp("sh_udc", (g)->name)
-#else
-#define gadget_is_sh(g) 0
-#endif
-
-/* not yet stable on 2.6 (would help "original Zaurus") */
-#ifdef CONFIG_USB_GADGET_SA1100
-#define gadget_is_sa1100(g) !strcmp("sa1100_udc", (g)->name)
-#else
-#define gadget_is_sa1100(g) 0
-#endif
-
#ifdef CONFIG_USB_GADGET_LH7A40X
#define gadget_is_lh7a40x(g) !strcmp("lh7a40x_udc", (g)->name)
#else
#define gadget_is_lh7a40x(g) 0
#endif
-/* handhelds.org tree (?) */
-#ifdef CONFIG_USB_GADGET_MQ11XX
-#define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name)
-#else
-#define gadget_is_mq11xx(g) 0
-#endif
-
#ifdef CONFIG_USB_GADGET_OMAP
#define gadget_is_omap(g) !strcmp("omap_udc", (g)->name)
#else
#define gadget_is_omap(g) 0
#endif
-/* not yet ported 2.4 --> 2.6 */
-#ifdef CONFIG_USB_GADGET_N9604
-#define gadget_is_n9604(g) !strcmp("n9604_udc", (g)->name)
-#else
-#define gadget_is_n9604(g) 0
-#endif
-
/* various unstable versions available */
#ifdef CONFIG_USB_GADGET_PXA27X
#define gadget_is_pxa27x(g) !strcmp("pxa27x_udc", (g)->name)
@@ -122,14 +94,6 @@
#define gadget_is_fsl_usb2(g) 0
#endif
-/* Mentor high speed function controller */
-/* from Montavista kernel (?) */
-#ifdef CONFIG_USB_GADGET_MUSBHSFC
-#define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name)
-#else
-#define gadget_is_musbhsfc(g) 0
-#endif
-
/* Mentor high speed "dual role" controller, in peripheral role */
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
#define gadget_is_musbhdrc(g) !strcmp("musb_hdrc", (g)->name)
@@ -143,13 +107,6 @@
#define gadget_is_langwell(g) 0
#endif
-/* from Montavista kernel (?) */
-#ifdef CONFIG_USB_GADGET_MPC8272
-#define gadget_is_mpc8272(g) !strcmp("mpc8272_udc", (g)->name)
-#else
-#define gadget_is_mpc8272(g) 0
-#endif
-
#ifdef CONFIG_USB_GADGET_M66592
#define gadget_is_m66592(g) !strcmp("m66592_udc", (g)->name)
#else
@@ -203,20 +160,12 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x02;
else if (gadget_is_pxa(gadget))
return 0x03;
- else if (gadget_is_sh(gadget))
- return 0x04;
- else if (gadget_is_sa1100(gadget))
- return 0x05;
else if (gadget_is_goku(gadget))
return 0x06;
- else if (gadget_is_mq11xx(gadget))
- return 0x07;
else if (gadget_is_omap(gadget))
return 0x08;
else if (gadget_is_lh7a40x(gadget))
return 0x09;
- else if (gadget_is_n9604(gadget))
- return 0x10;
else if (gadget_is_pxa27x(gadget))
return 0x11;
else if (gadget_is_s3c2410(gadget))
@@ -225,12 +174,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x13;
else if (gadget_is_imx(gadget))
return 0x14;
- else if (gadget_is_musbhsfc(gadget))
- return 0x15;
else if (gadget_is_musbhdrc(gadget))
return 0x16;
- else if (gadget_is_mpc8272(gadget))
- return 0x17;
else if (gadget_is_atmel_usba(gadget))
return 0x18;
else if (gadget_is_fsl_usb2(gadget))
@@ -265,10 +210,6 @@ static inline bool gadget_supports_altsettings(struct usb_gadget *gadget)
if (gadget_is_pxa27x(gadget))
return false;
- /* SH3 hardware just doesn't do altsettings */
- if (gadget_is_sh(gadget))
- return false;
-
/* Everything else is *presumably* fine ... */
return true;
}
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index d0b1e836f0e0..04f6224b7e06 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -237,7 +237,7 @@ static const struct usb_interface_descriptor ac_interface_desc = {
};
/* B.3.2 Class-Specific AC Interface Descriptor */
-static const struct uac_ac_header_descriptor_1 ac_header_desc = {
+static const struct uac_ac_header_descriptor_v1_1 ac_header_desc = {
.bLength = UAC_DT_AC_HEADER_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = USB_MS_HEADER,
@@ -618,11 +618,6 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
}
#endif
- if (gadget_is_sa1100(gadget) && dev->config) {
- /* tx fifo is full, but we can't clear it...*/
- ERROR(dev, "can't change configurations\n");
- return -ESPIPE;
- }
gmidi_reset_config(dev);
switch (number) {
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 112bb40a427c..e8edc640381e 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -1859,7 +1859,7 @@ done:
/*-------------------------------------------------------------------------*/
-static struct pci_device_id pci_ids [] = { {
+static const struct pci_device_id pci_ids[] = { {
.class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
.class_mask = ~0,
.vendor = 0x102f, /* Toshiba */
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index bf0f6520c6df..de8a83803505 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -194,7 +194,7 @@ enum ep_state {
};
struct ep_data {
- struct semaphore lock;
+ struct mutex lock;
enum ep_state state;
atomic_t count;
struct dev_data *dev;
@@ -298,10 +298,10 @@ get_ready_ep (unsigned f_flags, struct ep_data *epdata)
int val;
if (f_flags & O_NONBLOCK) {
- if (down_trylock (&epdata->lock) != 0)
+ if (!mutex_trylock(&epdata->lock))
goto nonblock;
if (epdata->state != STATE_EP_ENABLED) {
- up (&epdata->lock);
+ mutex_unlock(&epdata->lock);
nonblock:
val = -EAGAIN;
} else
@@ -309,7 +309,8 @@ nonblock:
return val;
}
- if ((val = down_interruptible (&epdata->lock)) < 0)
+ val = mutex_lock_interruptible(&epdata->lock);
+ if (val < 0)
return val;
switch (epdata->state) {
@@ -323,7 +324,7 @@ nonblock:
// FALLTHROUGH
case STATE_EP_UNBOUND: /* clean disconnect */
val = -ENODEV;
- up (&epdata->lock);
+ mutex_unlock(&epdata->lock);
}
return val;
}
@@ -393,7 +394,7 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
if (likely (data->ep != NULL))
usb_ep_set_halt (data->ep);
spin_unlock_irq (&data->dev->lock);
- up (&data->lock);
+ mutex_unlock(&data->lock);
return -EBADMSG;
}
@@ -411,7 +412,7 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
value = -EFAULT;
free1:
- up (&data->lock);
+ mutex_unlock(&data->lock);
kfree (kbuf);
return value;
}
@@ -436,7 +437,7 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
if (likely (data->ep != NULL))
usb_ep_set_halt (data->ep);
spin_unlock_irq (&data->dev->lock);
- up (&data->lock);
+ mutex_unlock(&data->lock);
return -EBADMSG;
}
@@ -455,7 +456,7 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
VDEBUG (data->dev, "%s write %zu IN, status %d\n",
data->name, len, (int) value);
free1:
- up (&data->lock);
+ mutex_unlock(&data->lock);
kfree (kbuf);
return value;
}
@@ -466,7 +467,8 @@ ep_release (struct inode *inode, struct file *fd)
struct ep_data *data = fd->private_data;
int value;
- if ((value = down_interruptible(&data->lock)) < 0)
+ value = mutex_lock_interruptible(&data->lock);
+ if (value < 0)
return value;
/* clean up if this can be reopened */
@@ -476,7 +478,7 @@ ep_release (struct inode *inode, struct file *fd)
data->hs_desc.bDescriptorType = 0;
usb_ep_disable(data->ep);
}
- up (&data->lock);
+ mutex_unlock(&data->lock);
put_ep (data);
return 0;
}
@@ -507,7 +509,7 @@ static long ep_ioctl(struct file *fd, unsigned code, unsigned long value)
} else
status = -ENODEV;
spin_unlock_irq (&data->dev->lock);
- up (&data->lock);
+ mutex_unlock(&data->lock);
return status;
}
@@ -673,7 +675,7 @@ fail:
value = -ENODEV;
spin_unlock_irq(&epdata->dev->lock);
- up(&epdata->lock);
+ mutex_unlock(&epdata->lock);
if (unlikely(value)) {
kfree(priv);
@@ -765,7 +767,8 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
u32 tag;
int value, length = len;
- if ((value = down_interruptible (&data->lock)) < 0)
+ value = mutex_lock_interruptible(&data->lock);
+ if (value < 0)
return value;
if (data->state != STATE_EP_READY) {
@@ -854,7 +857,7 @@ fail:
data->desc.bDescriptorType = 0;
data->hs_desc.bDescriptorType = 0;
}
- up (&data->lock);
+ mutex_unlock(&data->lock);
return value;
fail0:
value = -EINVAL;
@@ -870,7 +873,7 @@ ep_open (struct inode *inode, struct file *fd)
struct ep_data *data = inode->i_private;
int value = -EBUSY;
- if (down_interruptible (&data->lock) != 0)
+ if (mutex_lock_interruptible(&data->lock) != 0)
return -EINTR;
spin_lock_irq (&data->dev->lock);
if (data->dev->state == STATE_DEV_UNBOUND)
@@ -885,7 +888,7 @@ ep_open (struct inode *inode, struct file *fd)
DBG (data->dev, "%s state %d\n",
data->name, data->state);
spin_unlock_irq (&data->dev->lock);
- up (&data->lock);
+ mutex_unlock(&data->lock);
return value;
}
@@ -1631,7 +1634,7 @@ static int activate_ep_files (struct dev_data *dev)
if (!data)
goto enomem0;
data->state = STATE_EP_DISABLED;
- init_MUTEX (&data->lock);
+ mutex_init(&data->lock);
init_waitqueue_head (&data->wait);
strncpy (data->name, ep->name, sizeof (data->name) - 1);
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index 19619fbf20ac..705cc1f76327 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -135,6 +135,12 @@ FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
static unsigned long msg_registered = 0;
static void msg_cleanup(void);
+static int msg_thread_exits(struct fsg_common *common)
+{
+ msg_cleanup();
+ return 0;
+}
+
static int __init msg_do_config(struct usb_configuration *c)
{
struct fsg_common *common;
@@ -147,7 +153,7 @@ static int __init msg_do_config(struct usb_configuration *c)
}
fsg_config_from_params(&config, &mod_data);
- config.thread_exits = (void(*)(struct fsg_common*))&msg_cleanup;
+ config.thread_exits = msg_thread_exits;
common = fsg_common_init(0, c->cdev, &config);
if (IS_ERR(common))
return PTR_ERR(common);
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index 429560100b10..76496f5d272c 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -29,7 +29,7 @@
#if defined USB_ETH_RNDIS
# undef USB_ETH_RNDIS
#endif
-#ifdef CONFIG_USB_ETH_RNDIS
+#ifdef CONFIG_USB_G_MULTI_RNDIS
# define USB_ETH_RNDIS y
#endif
diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c
new file mode 100644
index 000000000000..7d6b66a85724
--- /dev/null
+++ b/drivers/usb/gadget/nokia.c
@@ -0,0 +1,259 @@
+/*
+ * nokia.c -- Nokia Composite Gadget Driver
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Contact: Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * This gadget driver borrows from serial.c which is:
+ *
+ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
+ * Copyright (C) 2008 by David Brownell
+ * Copyright (C) 2008 by Nokia Corporation
+ *
+ * This software is distributed under the terms of the GNU General
+ * Public License ("GPL") as published by the Free Software Foundation,
+ * version 2 of that License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+#include <linux/device.h>
+
+#include "u_serial.h"
+#include "u_ether.h"
+#include "u_phonet.h"
+#include "gadget_chips.h"
+
+/* Defines */
+
+#define NOKIA_VERSION_NUM 0x0211
+#define NOKIA_LONG_NAME "N900 (PC-Suite Mode)"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module. So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+#include "composite.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+
+#include "u_serial.c"
+#include "f_acm.c"
+#include "f_ecm.c"
+#include "f_obex.c"
+#include "f_serial.c"
+#include "f_phonet.c"
+#include "u_ether.c"
+
+/*-------------------------------------------------------------------------*/
+
+#define NOKIA_VENDOR_ID 0x0421 /* Nokia */
+#define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */
+
+/* string IDs are assigned dynamically */
+
+#define STRING_MANUFACTURER_IDX 0
+#define STRING_PRODUCT_IDX 1
+#define STRING_DESCRIPTION_IDX 2
+
+static char manufacturer_nokia[] = "Nokia";
+static const char product_nokia[] = NOKIA_LONG_NAME;
+static const char description_nokia[] = "PC-Suite Configuration";
+
+static struct usb_string strings_dev[] = {
+ [STRING_MANUFACTURER_IDX].s = manufacturer_nokia,
+ [STRING_PRODUCT_IDX].s = NOKIA_LONG_NAME,
+ [STRING_DESCRIPTION_IDX].s = description_nokia,
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+ .language = 0x0409, /* en-us */
+ .strings = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+ &stringtab_dev,
+ NULL,
+};
+
+static struct usb_device_descriptor device_desc = {
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_COMM,
+ .idVendor = __constant_cpu_to_le16(NOKIA_VENDOR_ID),
+ .idProduct = __constant_cpu_to_le16(NOKIA_PRODUCT_ID),
+ /* .iManufacturer = DYNAMIC */
+ /* .iProduct = DYNAMIC */
+ .bNumConfigurations = 1,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Module */
+MODULE_DESCRIPTION("Nokia composite gadget driver for N900");
+MODULE_AUTHOR("Felipe Balbi");
+MODULE_LICENSE("GPL");
+
+/*-------------------------------------------------------------------------*/
+
+static u8 hostaddr[ETH_ALEN];
+
+static int __init nokia_bind_config(struct usb_configuration *c)
+{
+ int status = 0;
+
+ status = phonet_bind_config(c);
+ if (status)
+ printk(KERN_DEBUG "could not bind phonet config\n");
+
+ status = obex_bind_config(c, 0);
+ if (status)
+ printk(KERN_DEBUG "could not bind obex config %d\n", 0);
+
+ status = obex_bind_config(c, 1);
+ if (status)
+ printk(KERN_DEBUG "could not bind obex config %d\n", 0);
+
+ status = acm_bind_config(c, 2);
+ if (status)
+ printk(KERN_DEBUG "could not bind acm config\n");
+
+ status = ecm_bind_config(c, hostaddr);
+ if (status)
+ printk(KERN_DEBUG "could not bind ecm config\n");
+
+ return status;
+}
+
+static struct usb_configuration nokia_config_500ma_driver = {
+ .label = "Bus Powered",
+ .bind = nokia_bind_config,
+ .bConfigurationValue = 1,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_ONE,
+ .bMaxPower = 250, /* 500mA */
+};
+
+static struct usb_configuration nokia_config_100ma_driver = {
+ .label = "Self Powered",
+ .bind = nokia_bind_config,
+ .bConfigurationValue = 2,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+ .bMaxPower = 50, /* 100 mA */
+};
+
+static int __init nokia_bind(struct usb_composite_dev *cdev)
+{
+ int gcnum;
+ struct usb_gadget *gadget = cdev->gadget;
+ int status;
+
+ status = gphonet_setup(cdev->gadget);
+ if (status < 0)
+ goto err_phonet;
+
+ status = gserial_setup(cdev->gadget, 3);
+ if (status < 0)
+ goto err_serial;
+
+ status = gether_setup(cdev->gadget, hostaddr);
+ if (status < 0)
+ goto err_ether;
+
+ status = usb_string_id(cdev);
+ if (status < 0)
+ goto err_usb;
+ strings_dev[STRING_MANUFACTURER_IDX].id = status;
+
+ device_desc.iManufacturer = status;
+
+ status = usb_string_id(cdev);
+ if (status < 0)
+ goto err_usb;
+ strings_dev[STRING_PRODUCT_IDX].id = status;
+
+ device_desc.iProduct = status;
+
+ /* config description */
+ status = usb_string_id(cdev);
+ if (status < 0)
+ goto err_usb;
+ strings_dev[STRING_DESCRIPTION_IDX].id = status;
+
+ nokia_config_500ma_driver.iConfiguration = status;
+ nokia_config_100ma_driver.iConfiguration = status;
+
+ /* set up other descriptors */
+ gcnum = usb_gadget_controller_number(gadget);
+ if (gcnum >= 0)
+ device_desc.bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM);
+ else {
+ /* this should only work with hw that supports altsettings
+ * and several endpoints, anything else, panic.
+ */
+ pr_err("nokia_bind: controller '%s' not recognized\n",
+ gadget->name);
+ goto err_usb;
+ }
+
+ /* finaly register the configuration */
+ status = usb_add_config(cdev, &nokia_config_500ma_driver);
+ if (status < 0)
+ goto err_usb;
+
+ status = usb_add_config(cdev, &nokia_config_100ma_driver);
+ if (status < 0)
+ goto err_usb;
+
+ dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
+
+ return 0;
+
+err_usb:
+ gether_cleanup();
+err_ether:
+ gserial_cleanup();
+err_serial:
+ gphonet_cleanup();
+err_phonet:
+ return status;
+}
+
+static int __exit nokia_unbind(struct usb_composite_dev *cdev)
+{
+ gphonet_cleanup();
+ gserial_cleanup();
+ gether_cleanup();
+
+ return 0;
+}
+
+static struct usb_composite_driver nokia_driver = {
+ .name = "g_nokia",
+ .dev = &device_desc,
+ .strings = dev_strings,
+ .bind = nokia_bind,
+ .unbind = __exit_p(nokia_unbind),
+};
+
+static int __init nokia_init(void)
+{
+ return usb_composite_register(&nokia_driver);
+}
+module_init(nokia_init);
+
+static void __exit nokia_cleanup(void)
+{
+ usb_composite_unregister(&nokia_driver);
+}
+module_exit(nokia_cleanup);
+
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 2d867fd22413..6b8bf8c781c4 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -949,12 +949,6 @@ printer_set_config(struct printer_dev *dev, unsigned number)
int result = 0;
struct usb_gadget *gadget = dev->gadget;
- if (gadget_is_sa1100(gadget) && dev->config) {
- /* tx fifo is full, but we can't clear it...*/
- INFO(dev, "can't change configurations\n");
- return -ESPIPE;
- }
-
switch (number) {
case DEV_CONFIG_VALUE:
result = 0;
@@ -1033,12 +1027,6 @@ set_interface(struct printer_dev *dev, unsigned number)
{
int result = 0;
- if (gadget_is_sa1100(dev->gadget) && dev->interface < 0) {
- /* tx fifo is full, but we can't clear it...*/
- INFO(dev, "can't change interfaces\n");
- return -ESPIPE;
- }
-
/* Free the current interface */
switch (dev->interface) {
case PRINTER_INTERFACE:
@@ -1392,12 +1380,6 @@ printer_bind(struct usb_gadget *gadget)
goto fail;
}
- if (gadget_is_sa1100(gadget)) {
- /* hardware can't write zero length packets. */
- ERROR(dev, "SA1100 controller is unsupport by this driver\n");
- goto fail;
- }
-
gcnum = usb_gadget_controller_number(gadget);
if (gcnum >= 0) {
device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index e6fedbd5a654..be5fb34d9602 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -65,6 +65,10 @@
#include <mach/pxa25x-udc.h>
#endif
+#ifdef CONFIG_ARCH_LUBBOCK
+#include <mach/lubbock.h>
+#endif
+
#include <asm/mach/udc_pxa2xx.h>
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index adda1208a1ec..05b892c3d686 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -742,13 +742,17 @@ static void ep_del_request(struct pxa_ep *ep, struct pxa27x_request *req)
* @ep: pxa physical endpoint
* @req: pxa request
* @status: usb request status sent to gadget API
+ * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
*
- * Context: ep->lock held
+ * Context: ep->lock held if flags not NULL, else ep->lock released
*
* Retire a pxa27x usb request. Endpoint must be locked.
*/
-static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status)
+static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status,
+ unsigned long *pflags)
{
+ unsigned long flags;
+
ep_del_request(ep, req);
if (likely(req->req.status == -EINPROGRESS))
req->req.status = status;
@@ -760,38 +764,48 @@ static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status)
&req->req, status,
req->req.actual, req->req.length);
+ if (pflags)
+ spin_unlock_irqrestore(&ep->lock, *pflags);
+ local_irq_save(flags);
req->req.complete(&req->udc_usb_ep->usb_ep, &req->req);
+ local_irq_restore(flags);
+ if (pflags)
+ spin_lock_irqsave(&ep->lock, *pflags);
}
/**
* ep_end_out_req - Ends endpoint OUT request
* @ep: physical endpoint
* @req: pxa request
+ * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
*
- * Context: ep->lock held
+ * Context: ep->lock held or released (see req_done())
*
* Ends endpoint OUT request (completes usb request).
*/
-static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
+static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req,
+ unsigned long *pflags)
{
inc_ep_stats_reqs(ep, !USB_DIR_IN);
- req_done(ep, req, 0);
+ req_done(ep, req, 0, pflags);
}
/**
* ep0_end_out_req - Ends control endpoint OUT request (ends data stage)
* @ep: physical endpoint
* @req: pxa request
+ * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
*
- * Context: ep->lock held
+ * Context: ep->lock held or released (see req_done())
*
* Ends control endpoint OUT request (completes usb request), and puts
* control endpoint into idle state
*/
-static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
+static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req,
+ unsigned long *pflags)
{
set_ep0state(ep->dev, OUT_STATUS_STAGE);
- ep_end_out_req(ep, req);
+ ep_end_out_req(ep, req, pflags);
ep0_idle(ep->dev);
}
@@ -799,31 +813,35 @@ static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
* ep_end_in_req - Ends endpoint IN request
* @ep: physical endpoint
* @req: pxa request
+ * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
*
- * Context: ep->lock held
+ * Context: ep->lock held or released (see req_done())
*
* Ends endpoint IN request (completes usb request).
*/
-static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
+static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req,
+ unsigned long *pflags)
{
inc_ep_stats_reqs(ep, USB_DIR_IN);
- req_done(ep, req, 0);
+ req_done(ep, req, 0, pflags);
}
/**
* ep0_end_in_req - Ends control endpoint IN request (ends data stage)
* @ep: physical endpoint
* @req: pxa request
+ * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
*
- * Context: ep->lock held
+ * Context: ep->lock held or released (see req_done())
*
* Ends control endpoint IN request (completes usb request), and puts
* control endpoint into status state
*/
-static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
+static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req,
+ unsigned long *pflags)
{
set_ep0state(ep->dev, IN_STATUS_STAGE);
- ep_end_in_req(ep, req);
+ ep_end_in_req(ep, req, pflags);
}
/**
@@ -831,19 +849,22 @@ static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
* @ep: pxa endpoint
* @status: usb request status
*
- * Context: ep->lock held
+ * Context: ep->lock released
*
* Dequeues all requests on an endpoint. As a side effect, interrupts will be
* disabled on that endpoint (because no more requests).
*/
static void nuke(struct pxa_ep *ep, int status)
{
- struct pxa27x_request *req;
+ struct pxa27x_request *req;
+ unsigned long flags;
+ spin_lock_irqsave(&ep->lock, flags);
while (!list_empty(&ep->queue)) {
req = list_entry(ep->queue.next, struct pxa27x_request, queue);
- req_done(ep, req, status);
+ req_done(ep, req, status, &flags);
}
+ spin_unlock_irqrestore(&ep->lock, flags);
}
/**
@@ -1123,6 +1144,7 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
int rc = 0;
int is_first_req;
unsigned length;
+ int recursion_detected;
req = container_of(_req, struct pxa27x_request, req);
udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
@@ -1152,6 +1174,7 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
return -EMSGSIZE;
spin_lock_irqsave(&ep->lock, flags);
+ recursion_detected = ep->in_handle_ep;
is_first_req = list_empty(&ep->queue);
ep_dbg(ep, "queue req %p(first=%s), len %d buf %p\n",
@@ -1161,12 +1184,12 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
if (!ep->enabled) {
_req->status = -ESHUTDOWN;
rc = -ESHUTDOWN;
- goto out;
+ goto out_locked;
}
if (req->in_use) {
ep_err(ep, "refusing to queue req %p (already queued)\n", req);
- goto out;
+ goto out_locked;
}
length = _req->length;
@@ -1174,12 +1197,13 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
_req->actual = 0;
ep_add_request(ep, req);
+ spin_unlock_irqrestore(&ep->lock, flags);
if (is_ep0(ep)) {
switch (dev->ep0state) {
case WAIT_ACK_SET_CONF_INTERF:
if (length == 0) {
- ep_end_in_req(ep, req);
+ ep_end_in_req(ep, req, NULL);
} else {
ep_err(ep, "got a request of %d bytes while"
"in state WAIT_ACK_SET_CONF_INTERF\n",
@@ -1192,12 +1216,12 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
case IN_DATA_STAGE:
if (!ep_is_full(ep))
if (write_ep0_fifo(ep, req))
- ep0_end_in_req(ep, req);
+ ep0_end_in_req(ep, req, NULL);
break;
case OUT_DATA_STAGE:
if ((length == 0) || !epout_has_pkt(ep))
if (read_ep0_fifo(ep, req))
- ep0_end_out_req(ep, req);
+ ep0_end_out_req(ep, req, NULL);
break;
default:
ep_err(ep, "odd state %s to send me a request\n",
@@ -1207,12 +1231,15 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
break;
}
} else {
- handle_ep(ep);
+ if (!recursion_detected)
+ handle_ep(ep);
}
out:
- spin_unlock_irqrestore(&ep->lock, flags);
return rc;
+out_locked:
+ spin_unlock_irqrestore(&ep->lock, flags);
+ goto out;
}
/**
@@ -1242,13 +1269,14 @@ static int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
/* make sure it's actually queued on this endpoint */
list_for_each_entry(req, &ep->queue, queue) {
if (&req->req == _req) {
- req_done(ep, req, -ECONNRESET);
rc = 0;
break;
}
}
spin_unlock_irqrestore(&ep->lock, flags);
+ if (!rc)
+ req_done(ep, req, -ECONNRESET, NULL);
return rc;
}
@@ -1445,7 +1473,6 @@ static int pxa_ep_disable(struct usb_ep *_ep)
{
struct pxa_ep *ep;
struct udc_usb_ep *udc_usb_ep;
- unsigned long flags;
if (!_ep)
return -EINVAL;
@@ -1455,10 +1482,8 @@ static int pxa_ep_disable(struct usb_ep *_ep)
if (!ep || is_ep0(ep) || !list_empty(&ep->queue))
return -EINVAL;
- spin_lock_irqsave(&ep->lock, flags);
ep->enabled = 0;
nuke(ep, -ESHUTDOWN);
- spin_unlock_irqrestore(&ep->lock, flags);
pxa_ep_fifo_flush(_ep);
udc_usb_ep->pxa_ep = NULL;
@@ -1907,8 +1932,10 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc,
} u;
int i;
int have_extrabytes = 0;
+ unsigned long flags;
nuke(ep, -EPROTO);
+ spin_lock_irqsave(&ep->lock, flags);
/*
* In the PXA320 manual, in the section about Back-to-Back setup
@@ -1947,10 +1974,13 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc,
/* Tell UDC to enter Data Stage */
ep_write_UDCCSR(ep, UDCCSR0_SA | UDCCSR0_OPC);
+ spin_unlock_irqrestore(&ep->lock, flags);
i = udc->driver->setup(&udc->gadget, &u.r);
+ spin_lock_irqsave(&ep->lock, flags);
if (i < 0)
goto stall;
out:
+ spin_unlock_irqrestore(&ep->lock, flags);
return;
stall:
ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n",
@@ -2055,13 +2085,13 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
if (req && !ep_is_full(ep))
completed = write_ep0_fifo(ep, req);
if (completed)
- ep0_end_in_req(ep, req);
+ ep0_end_in_req(ep, req, NULL);
break;
case OUT_DATA_STAGE: /* SET_DESCRIPTOR */
if (epout_has_pkt(ep) && req)
completed = read_ep0_fifo(ep, req);
if (completed)
- ep0_end_out_req(ep, req);
+ ep0_end_out_req(ep, req, NULL);
break;
case STALL:
ep_write_UDCCSR(ep, UDCCSR0_FST);
@@ -2091,7 +2121,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
* Tries to transfer all pending request data into the endpoint and/or
* transfer all pending data in the endpoint into usb requests.
*
- * Is always called when in_interrupt() or with ep->lock held.
+ * Is always called when in_interrupt() and with ep->lock released.
*/
static void handle_ep(struct pxa_ep *ep)
{
@@ -2100,10 +2130,17 @@ static void handle_ep(struct pxa_ep *ep)
u32 udccsr;
int is_in = ep->dir_in;
int loop = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ep->lock, flags);
+ if (ep->in_handle_ep)
+ goto recursion_detected;
+ ep->in_handle_ep = 1;
do {
completed = 0;
udccsr = udc_ep_readl(ep, UDCCSR);
+
if (likely(!list_empty(&ep->queue)))
req = list_entry(ep->queue.next,
struct pxa27x_request, queue);
@@ -2122,15 +2159,22 @@ static void handle_ep(struct pxa_ep *ep)
if (unlikely(is_in)) {
if (likely(!ep_is_full(ep)))
completed = write_fifo(ep, req);
- if (completed)
- ep_end_in_req(ep, req);
} else {
if (likely(epout_has_pkt(ep)))
completed = read_fifo(ep, req);
- if (completed)
- ep_end_out_req(ep, req);
+ }
+
+ if (completed) {
+ if (is_in)
+ ep_end_in_req(ep, req, &flags);
+ else
+ ep_end_out_req(ep, req, &flags);
}
} while (completed);
+
+ ep->in_handle_ep = 0;
+recursion_detected:
+ spin_unlock_irqrestore(&ep->lock, flags);
}
/**
@@ -2218,9 +2262,13 @@ static void irq_handle_data(int irq, struct pxa_udc *udc)
continue;
udc_writel(udc, UDCISR0, UDCISR_INT(i, UDCISR_INT_MASK));
- ep = &udc->pxa_ep[i];
- ep->stats.irqs++;
- handle_ep(ep);
+
+ WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep));
+ if (i < ARRAY_SIZE(udc->pxa_ep)) {
+ ep = &udc->pxa_ep[i];
+ ep->stats.irqs++;
+ handle_ep(ep);
+ }
}
for (i = 16; udcisr1 != 0 && i < 24; udcisr1 >>= 2, i++) {
@@ -2228,9 +2276,12 @@ static void irq_handle_data(int irq, struct pxa_udc *udc)
if (!(udcisr1 & UDCISR_INT_MASK))
continue;
- ep = &udc->pxa_ep[i];
- ep->stats.irqs++;
- handle_ep(ep);
+ WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep));
+ if (i < ARRAY_SIZE(udc->pxa_ep)) {
+ ep = &udc->pxa_ep[i];
+ ep->stats.irqs++;
+ handle_ep(ep);
+ }
}
}
@@ -2439,7 +2490,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
}
retval = -ENOMEM;
- udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ udc->regs = ioremap(regs->start, resource_size(regs));
if (!udc->regs) {
dev_err(&pdev->dev, "Unable to map UDC I/O memory\n");
goto err_map;
diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h
index e25225e26586..ff61e4866e8a 100644
--- a/drivers/usb/gadget/pxa27x_udc.h
+++ b/drivers/usb/gadget/pxa27x_udc.h
@@ -318,6 +318,11 @@ struct udc_usb_ep {
* @queue: requests queue
* @lock: lock to pxa_ep data (queues and stats)
* @enabled: true when endpoint enabled (not stopped by gadget layer)
+ * @in_handle_ep: number of recursions of handle_ep() function
+ * Prevents deadlocks or infinite recursions of types :
+ * irq->handle_ep()->req_done()->req.complete()->pxa_ep_queue()->handle_ep()
+ * or
+ * pxa_ep_queue()->handle_ep()->req_done()->req.complete()->pxa_ep_queue()
* @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX)
* @name: endpoint name (for trace/debug purpose)
* @dir_in: 1 if IN endpoint, 0 if OUT endpoint
@@ -346,6 +351,7 @@ struct pxa_ep {
spinlock_t lock; /* Protects this structure */
/* (queues, stats) */
unsigned enabled:1;
+ unsigned in_handle_ep:1;
unsigned idx:5;
char *name;
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index e220fb8091a3..8b45145b9136 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -26,6 +26,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 4b5dbd0127f5..f742c8e7397c 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -30,7 +30,7 @@
#include <plat/regs-usb-hsotg-phy.h>
#include <plat/regs-usb-hsotg.h>
-#include <plat/regs-sys.h>
+#include <mach/regs-sys.h>
#include <plat/udc-hs.h>
#define DMA_ADDR_INVALID (~((dma_addr_t)0))
@@ -317,7 +317,8 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
*
* Allocate a new USB request structure appropriate for the specified endpoint
*/
-struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, gfp_t flags)
+static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep,
+ gfp_t flags)
{
struct s3c_hsotg_req *req;
@@ -373,7 +374,7 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
req->dma = DMA_ADDR_INVALID;
hs_req->mapped = 0;
} else {
- dma_sync_single(hsotg->dev, req->dma, req->length, dir);
+ dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
}
}
@@ -755,7 +756,7 @@ static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg,
hs_req->mapped = 1;
req->dma = dma;
} else {
- dma_sync_single(hsotg->dev, req->dma, req->length, dir);
+ dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
hs_req->mapped = 0;
}
@@ -1460,7 +1461,7 @@ static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg)
* as the actual data should be sent to the memory directly and we turn
* on the completion interrupts to get notifications of transfer completion.
*/
-void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
{
u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP);
u32 epnum, status, size;
@@ -2582,6 +2583,7 @@ err:
hsotg->gadget.dev.driver = NULL;
return ret;
}
+EXPORT_SYMBOL(usb_gadget_register_driver);
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
{
@@ -3093,7 +3095,7 @@ static void s3c_hsotg_gate(struct platform_device *pdev, bool on)
local_irq_restore(flags);
}
-struct s3c_hsotg_plat s3c_hsotg_default_pdata;
+static struct s3c_hsotg_plat s3c_hsotg_default_pdata;
static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
{
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 2fc02bd95848..84ca195c2d10 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -746,6 +746,10 @@ static const struct net_device_ops eth_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
};
+static struct device_type gadget_type = {
+ .name = "gadget",
+};
+
/**
* gether_setup - initialize one ethernet-over-usb link
* @g: gadget to associated with these links
@@ -808,6 +812,7 @@ int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
dev->gadget = g;
SET_NETDEV_DEV(net, &g->dev);
+ SET_NETDEV_DEVTYPE(net, &gadget_type);
status = register_netdev(net);
if (status < 0) {
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index fd55f450bc0e..3c8c0c9f9d72 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -93,13 +93,6 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
if (!gadget_supports_altsettings(gadget))
return false;
- /* SA1100 can do ECM, *without* status endpoint ... but we'll
- * only use it in non-ECM mode for backwards compatibility
- * (and since we currently require a status endpoint)
- */
- if (gadget_is_sa1100(gadget))
- return false;
-
/* Everything else is *presumably* fine ... but this is a bit
* chancy, so be **CERTAIN** there are no hardware issues with
* your controller. Add it above if it can't handle CDC.
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 2d772401b7ad..fac81ee193dd 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -297,12 +297,10 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
*/
if (loopdefault) {
loopback_add(cdev, autoresume != 0);
- if (!gadget_is_sh(gadget))
- sourcesink_add(cdev, autoresume != 0);
+ sourcesink_add(cdev, autoresume != 0);
} else {
sourcesink_add(cdev, autoresume != 0);
- if (!gadget_is_sh(gadget))
- loopback_add(cdev, autoresume != 0);
+ loopback_add(cdev, autoresume != 0);
}
gcnum = usb_gadget_controller_number(gadget);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 2678a1624fcc..8d3df0397de3 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -399,3 +399,14 @@ config USB_HWA_HCD
To compile this driver a module, choose M here: the module
will be called "hwa-hc".
+
+config USB_IMX21_HCD
+ tristate "iMX21 HCD support"
+ depends on USB && ARM && MACH_MX21
+ help
+ This driver enables support for the on-chip USB host in the
+ iMX21 processor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called "imx21-hcd".
+
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index f58b2494c44a..4e0c67f1f51b 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -32,3 +32,5 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
+obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
+
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 87c1b7c34c0e..51bd0edf544f 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -149,7 +149,7 @@ static int __init ehci_atmel_drv_probe(struct platform_device *pdev)
goto fail_request_resource;
}
hcd->rsrc_start = res->start;
- hcd->rsrc_len = res->end - res->start + 1;
+ hcd->rsrc_len = resource_size(res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
driver->description)) {
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index dbfb482a94e3..e3a74e75e822 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -121,6 +121,7 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
+ struct resource *res;
int ret;
if (usb_disabled())
@@ -144,8 +145,9 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
if (!hcd)
return -ENOMEM;
- hcd->rsrc_start = pdev->resource[0].start;
- hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
pr_debug("request_mem_region failed");
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 991174937db3..0e26aa13f158 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 2005 MontaVista Software
+ * Copyright 2005-2009 MontaVista Software, Inc.
+ * Copyright 2008 Freescale Semiconductor, 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
@@ -17,17 +18,20 @@
*
* Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided
* by Hunter Wu.
+ * Power Management support by Dave Liu <daveliu@freescale.com>,
+ * Jerry Huang <Chang-Ming.Huang@freescale.com> and
+ * Anton Vorontsov <avorontsov@ru.mvista.com>.
*/
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include "ehci-fsl.h"
-/* FIXME: Power Management is un-ported so temporarily disable it */
-#undef CONFIG_PM
-
-
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
@@ -40,8 +44,8 @@
* Allocates basic resources for this USB host controller.
*
*/
-int usb_hcd_fsl_probe(const struct hc_driver *driver,
- struct platform_device *pdev)
+static int usb_hcd_fsl_probe(const struct hc_driver *driver,
+ struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata;
struct usb_hcd *hcd;
@@ -147,7 +151,8 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
* Reverses the effect of usb_hcd_fsl_probe().
*
*/
-void usb_hcd_fsl_remove(struct usb_hcd *hcd, struct platform_device *pdev)
+static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
+ struct platform_device *pdev)
{
usb_remove_hcd(hcd);
iounmap(hcd->regs);
@@ -284,10 +289,81 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
return retval;
}
+struct ehci_fsl {
+ struct ehci_hcd ehci;
+
+#ifdef CONFIG_PM
+ /* Saved USB PHY settings, need to restore after deep sleep. */
+ u32 usb_ctrl;
+#endif
+};
+
+#ifdef CONFIG_PM
+
+static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ return container_of(ehci, struct ehci_fsl, ehci);
+}
+
+static int ehci_fsl_drv_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
+ void __iomem *non_ehci = hcd->regs;
+
+ if (!fsl_deep_sleep())
+ return 0;
+
+ ehci_fsl->usb_ctrl = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+ return 0;
+}
+
+static int ehci_fsl_drv_resume(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ void __iomem *non_ehci = hcd->regs;
+
+ if (!fsl_deep_sleep())
+ return 0;
+
+ usb_root_hub_lost_power(hcd->self.root_hub);
+
+ /* Restore USB PHY settings and enable the controller. */
+ out_be32(non_ehci + FSL_SOC_USB_CTRL, ehci_fsl->usb_ctrl);
+
+ ehci_reset(ehci);
+ ehci_fsl_reinit(ehci);
+
+ return 0;
+}
+
+static int ehci_fsl_drv_restore(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+ usb_root_hub_lost_power(hcd->self.root_hub);
+ return 0;
+}
+
+static struct dev_pm_ops ehci_fsl_pm_ops = {
+ .suspend = ehci_fsl_drv_suspend,
+ .resume = ehci_fsl_drv_resume,
+ .restore = ehci_fsl_drv_restore,
+};
+
+#define EHCI_FSL_PM_OPS (&ehci_fsl_pm_ops)
+#else
+#define EHCI_FSL_PM_OPS NULL
+#endif /* CONFIG_PM */
+
static const struct hc_driver ehci_fsl_hc_driver = {
.description = hcd_name,
.product_desc = "Freescale On-Chip EHCI Host Controller",
- .hcd_priv_size = sizeof(struct ehci_hcd),
+ .hcd_priv_size = sizeof(struct ehci_fsl),
/*
* generic hardware linkage
@@ -354,6 +430,7 @@ static struct platform_driver ehci_fsl_driver = {
.remove = ehci_fsl_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
- .name = "fsl-ehci",
+ .name = "fsl-ehci",
+ .pm = EHCI_FSL_PM_OPS,
},
};
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 5859522d6edd..d8d6d3461d32 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -787,9 +787,10 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* start 20 msec resume signaling from this port,
* and make khubd collect PORT_STAT_C_SUSPEND to
- * stop that signaling.
+ * stop that signaling. Use 5 ms extra for safety,
+ * like usb_port_resume() does.
*/
- ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
+ ehci->reset_done[i] = jiffies + msecs_to_jiffies(25);
ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
mod_timer(&hcd->rh_timer, ehci->reset_done[i]);
}
@@ -1117,7 +1118,7 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
#endif
-#ifdef CONFIG_ARCH_OMAP34XX
+#ifdef CONFIG_ARCH_OMAP3
#include "ehci-omap.c"
#define PLATFORM_DRIVER ehci_hcd_omap_driver
#endif
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 2c6571c05f35..19372673bf09 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -120,9 +120,26 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
del_timer_sync(&ehci->watchdog);
del_timer_sync(&ehci->iaa_watchdog);
- port = HCS_N_PORTS (ehci->hcs_params);
spin_lock_irq (&ehci->lock);
+ /* Once the controller is stopped, port resumes that are already
+ * in progress won't complete. Hence if remote wakeup is enabled
+ * for the root hub and any ports are in the middle of a resume or
+ * remote wakeup, we must fail the suspend.
+ */
+ if (hcd->self.root_hub->do_remote_wakeup) {
+ port = HCS_N_PORTS(ehci->hcs_params);
+ while (port--) {
+ if (ehci->reset_done[port] != 0) {
+ spin_unlock_irq(&ehci->lock);
+ ehci_dbg(ehci, "suspend failed because "
+ "port %d is resuming\n",
+ port + 1);
+ return -EBUSY;
+ }
+ }
+ }
+
/* stop schedules, clean any completed work */
if (HC_IS_RUNNING(hcd->state)) {
ehci_quiesce (ehci);
@@ -138,6 +155,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
*/
ehci->bus_suspended = 0;
ehci->owned_ports = 0;
+ port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
u32 __iomem *reg = &ehci->regs->port_status [port];
u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
@@ -178,7 +196,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
if (hostpc_reg) {
u32 t3;
+ spin_unlock_irq(&ehci->lock);
msleep(5);/* 5ms for HCD enter low pwr mode */
+ spin_lock_irq(&ehci->lock);
t3 = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
t3 = ehci_readl(ehci, hostpc_reg);
@@ -886,17 +906,18 @@ static int ehci_hub_control (
if ((temp & PORT_PE) == 0
|| (temp & PORT_RESET) != 0)
goto error;
- ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
+
/* After above check the port must be connected.
* Set appropriate bit thus could put phy into low power
* mode if we have hostpc feature
*/
+ temp &= ~PORT_WKCONN_E;
+ temp |= PORT_WKDISC_E | PORT_WKOC_E;
+ ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
if (hostpc_reg) {
- temp &= ~PORT_WKCONN_E;
- temp |= (PORT_WKDISC_E | PORT_WKOC_E);
- ehci_writel(ehci, temp | PORT_SUSPEND,
- status_reg);
+ spin_unlock_irqrestore(&ehci->lock, flags);
msleep(5);/* 5ms for HCD enter low pwr mode */
+ spin_lock_irqsave(&ehci->lock, flags);
temp1 = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, temp1 | HOSTPC_PHCD,
hostpc_reg);
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index 35c56f40bdbb..23cd917088b4 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -162,6 +162,17 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
goto err_ioremap;
}
+ /* call platform specific init function */
+ if (pdata->init) {
+ ret = pdata->init(pdev);
+ if (ret) {
+ dev_err(dev, "platform init failed\n");
+ goto err_init;
+ }
+ /* platforms need some time to settle changed IO settings */
+ mdelay(10);
+ }
+
/* enable clocks */
priv->usbclk = clk_get(dev, "usb");
if (IS_ERR(priv->usbclk)) {
@@ -192,18 +203,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
if (ret < 0)
goto err_init;
- /* call platform specific init function */
- if (pdata->init) {
- ret = pdata->init(pdev);
- if (ret) {
- dev_err(dev, "platform init failed\n");
- goto err_init;
- }
- }
-
- /* most platforms need some time to settle changed IO settings */
- mdelay(10);
-
/* Initialize the transceiver */
if (pdata->otg) {
pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 74d07f4e8b7d..f0282d6bb7aa 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -26,10 +26,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * TODO (last updated Feb 23rd, 2009):
+ * TODO (last updated Feb 12, 2010):
* - add kernel-doc
* - enable AUTOIDLE
- * - move DPLL5 programming to clock fw
* - add suspend/resume
* - move workarounds to board-files
*/
@@ -37,6 +36,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
#include <plat/usb.h>
/*
@@ -178,6 +178,11 @@ struct ehci_hcd_omap {
void __iomem *uhh_base;
void __iomem *tll_base;
void __iomem *ehci_base;
+
+ /* Regulators for USB PHYs.
+ * Each PHY can have a seperate regulator.
+ */
+ struct regulator *regulator[OMAP3_HS_USB_PORTS];
};
/*-------------------------------------------------------------------------*/
@@ -546,6 +551,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
int irq = platform_get_irq(pdev, 0);
int ret = -ENODEV;
+ int i;
+ char supply[7];
if (!pdata) {
dev_dbg(&pdev->dev, "missing platform_data\n");
@@ -613,6 +620,21 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
goto err_tll_ioremap;
}
+ /* get ehci regulator and enable */
+ for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
+ if (omap->port_mode[i] != EHCI_HCD_OMAP_MODE_PHY) {
+ omap->regulator[i] = NULL;
+ continue;
+ }
+ snprintf(supply, sizeof(supply), "hsusb%d", i);
+ omap->regulator[i] = regulator_get(omap->dev, supply);
+ if (IS_ERR(omap->regulator[i]))
+ dev_dbg(&pdev->dev,
+ "failed to get ehci port%d regulator\n", i);
+ else
+ regulator_enable(omap->regulator[i]);
+ }
+
ret = omap_start_ehc(omap, hcd);
if (ret) {
dev_dbg(&pdev->dev, "failed to start ehci\n");
@@ -622,13 +644,12 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
omap->ehci->regs = hcd->regs
+ HC_LENGTH(readl(&omap->ehci->caps->hc_capbase));
+ dbg_hcs_params(omap->ehci, "reset");
+ dbg_hcc_params(omap->ehci, "reset");
+
/* cache this readonly data; minimize chip reads */
omap->ehci->hcs_params = readl(&omap->ehci->caps->hcs_params);
- /* SET 1 micro-frame Interrupt interval */
- writel(readl(&omap->ehci->regs->command) | (1 << 16),
- &omap->ehci->regs->command);
-
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
if (ret) {
dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
@@ -641,6 +662,12 @@ err_add_hcd:
omap_stop_ehc(omap, hcd);
err_start:
+ for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
+ if (omap->regulator[i]) {
+ regulator_disable(omap->regulator[i]);
+ regulator_put(omap->regulator[i]);
+ }
+ }
iounmap(omap->tll_base);
err_tll_ioremap:
@@ -674,13 +701,21 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
{
struct ehci_hcd_omap *omap = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ehci_to_hcd(omap->ehci);
+ int i;
usb_remove_hcd(hcd);
omap_stop_ehc(omap, hcd);
iounmap(hcd->regs);
+ for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
+ if (omap->regulator[i]) {
+ regulator_disable(omap->regulator[i]);
+ regulator_put(omap->regulator[i]);
+ }
+ }
iounmap(omap->tll_base);
iounmap(omap->uhh_base);
usb_put_hcd(hcd);
+ kfree(omap);
return 0;
}
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index 1d283e1b2b8d..0f87dc72820a 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -222,14 +222,14 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
goto err1;
}
- if (!request_mem_region(res->start, res->end - res->start + 1,
+ if (!request_mem_region(res->start, resource_size(res),
ehci_orion_hc_driver.description)) {
dev_dbg(&pdev->dev, "controller already in use\n");
err = -EBUSY;
goto err1;
}
- regs = ioremap(res->start, res->end - res->start + 1);
+ regs = ioremap(res->start, resource_size(res));
if (regs == NULL) {
dev_dbg(&pdev->dev, "error mapping memory\n");
err = -EFAULT;
@@ -244,7 +244,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
}
hcd->rsrc_start = res->start;
- hcd->rsrc_len = res->end - res->start + 1;
+ hcd->rsrc_len = resource_size(res);
hcd->regs = regs;
ehci = hcd_to_ehci(hcd);
@@ -287,7 +287,7 @@ err4:
err3:
iounmap(regs);
err2:
- release_mem_region(res->start, res->end - res->start + 1);
+ release_mem_region(res->start, resource_size(res));
err1:
dev_err(&pdev->dev, "init %s fail, %d\n",
dev_name(&pdev->dev), err);
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index 36f96da129f5..8df33b8a634c 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -134,21 +134,21 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
hcd->rsrc_len = res.end - res.start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+ printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
rv = -EBUSY;
goto err_rmr;
}
irq = irq_of_parse_and_map(dn, 0);
if (irq == NO_IRQ) {
- printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+ printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
rv = -EBUSY;
goto err_irq;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
- printk(KERN_ERR __FILE__ ": ioremap failed\n");
+ printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
rv = -ENOMEM;
goto err_ioremap;
}
@@ -161,9 +161,9 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
ehci->ohci_hcctrl_reg = ioremap(res.start +
OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN);
else
- pr_debug(__FILE__ ": no ohci offset in fdt\n");
+ pr_debug("%s: no ohci offset in fdt\n", __FILE__);
if (!ehci->ohci_hcctrl_reg) {
- pr_debug(__FILE__ ": ioremap for ohci hcctrl failed\n");
+ pr_debug("%s: ioremap for ohci hcctrl failed\n", __FILE__);
} else {
ehci->has_amcc_usb23 = 1;
}
@@ -241,7 +241,7 @@ static int ehci_hcd_ppc_of_remove(struct of_device *op)
else
release_mem_region(res.start, 0x4);
else
- pr_debug(__FILE__ ": no ohci offset in fdt\n");
+ pr_debug("%s: no ohci offset in fdt\n", __FILE__);
of_node_put(np);
}
@@ -264,7 +264,7 @@ static int ehci_hcd_ppc_of_shutdown(struct of_device *op)
}
-static struct of_device_id ehci_hcd_ppc_of_match[] = {
+static const struct of_device_id ehci_hcd_ppc_of_match[] = {
{
.compatible = "usb-ehci",
},
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index a427d3b00634..89521775c567 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -849,9 +849,10 @@ qh_make (
* But interval 1 scheduling is simpler, and
* includes high bandwidth.
*/
- dbg ("intr period %d uframes, NYET!",
- urb->interval);
- goto done;
+ urb->interval = 1;
+ } else if (qh->period > ehci->periodic_size) {
+ qh->period = ehci->periodic_size;
+ urb->interval = qh->period << 3;
}
} else {
int think_time;
@@ -874,6 +875,10 @@ qh_make (
usb_calc_bus_time (urb->dev->speed,
is_input, 0, max_packet (maxp)));
qh->period = urb->interval;
+ if (qh->period > ehci->periodic_size) {
+ qh->period = ehci->periodic_size;
+ urb->interval = qh->period;
+ }
}
}
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 1e391e624c8a..39340ae00ac4 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -510,6 +510,8 @@ static int disable_periodic (struct ehci_hcd *ehci)
ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... */
+ free_cached_itd_list(ehci);
+
ehci->next_uframe = -1;
return 0;
}
@@ -2322,9 +2324,13 @@ restart:
* No need to check for activity unless the
* frame is current.
*/
- if (frame == clock_frame && live &&
- (q.sitd->hw_results &
- SITD_ACTIVE(ehci))) {
+ if (((frame == clock_frame) ||
+ (((frame + 1) % ehci->periodic_size)
+ == clock_frame))
+ && live
+ && (q.sitd->hw_results &
+ SITD_ACTIVE(ehci))) {
+
incomplete = true;
q_p = &q.sitd->sitd_next;
hw_p = &q.sitd->hw_next;
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index a5861531ad3e..f603bb2c0a8e 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -177,21 +177,21 @@ ehci_hcd_xilinx_of_probe(struct of_device *op, const struct of_device_id *match)
hcd->rsrc_len = res.end - res.start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+ printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
rv = -EBUSY;
goto err_rmr;
}
irq = irq_of_parse_and_map(dn, 0);
if (irq == NO_IRQ) {
- printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+ printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
rv = -EBUSY;
goto err_irq;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
- printk(KERN_ERR __FILE__ ": ioremap failed\n");
+ printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
rv = -ENOMEM;
goto err_ioremap;
}
@@ -281,7 +281,7 @@ static int ehci_hcd_xilinx_of_shutdown(struct of_device *op)
}
-static struct of_device_id ehci_hcd_xilinx_of_match[] = {
+static const struct of_device_id ehci_hcd_xilinx_of_match[] = {
{.compatible = "xlnx,xps-usb-host-1.00.a",},
{},
};
diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c
index 0951818ef93b..5dcfb3de9945 100644
--- a/drivers/usb/host/fhci-hcd.c
+++ b/drivers/usb/host/fhci-hcd.c
@@ -242,9 +242,10 @@ err:
static void fhci_usb_free(void *lld)
{
struct fhci_usb *usb = lld;
- struct fhci_hcd *fhci = usb->fhci;
+ struct fhci_hcd *fhci;
if (usb) {
+ fhci = usb->fhci;
fhci_config_transceiver(fhci, FHCI_PORT_POWER_OFF);
fhci_ep0_free(usb);
kfree(usb->actual_frame);
@@ -432,7 +433,7 @@ static int fhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
return -ENOMEM;
/* allocate the private part of the URB */
- urb_priv->tds = kzalloc(size * sizeof(struct td), mem_flags);
+ urb_priv->tds = kcalloc(size, sizeof(*urb_priv->tds), mem_flags);
if (!urb_priv->tds) {
kfree(urb_priv);
return -ENOMEM;
@@ -804,7 +805,7 @@ static int __devexit of_fhci_remove(struct of_device *ofdev)
return fhci_remove(&ofdev->dev);
}
-static struct of_device_id of_fhci_match[] = {
+static const struct of_device_id of_fhci_match[] = {
{ .compatible = "fsl,mpc8323-qe-usb", },
{},
};
diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c
index d224ab467a40..e1232890c78b 100644
--- a/drivers/usb/host/fhci-tds.c
+++ b/drivers/usb/host/fhci-tds.c
@@ -105,7 +105,7 @@ void fhci_ep0_free(struct fhci_usb *usb)
if (ep->td_base)
cpm_muram_free(cpm_muram_offset(ep->td_base));
- if (ep->conf_frame_Q) {
+ if (kfifo_initialized(&ep->conf_frame_Q)) {
size = cq_howmany(&ep->conf_frame_Q);
for (; size; size--) {
struct packet *pkt = cq_get(&ep->conf_frame_Q);
@@ -115,7 +115,7 @@ void fhci_ep0_free(struct fhci_usb *usb)
cq_delete(&ep->conf_frame_Q);
}
- if (ep->empty_frame_Q) {
+ if (kfifo_initialized(&ep->empty_frame_Q)) {
size = cq_howmany(&ep->empty_frame_Q);
for (; size; size--) {
struct packet *pkt = cq_get(&ep->empty_frame_Q);
@@ -125,7 +125,7 @@ void fhci_ep0_free(struct fhci_usb *usb)
cq_delete(&ep->empty_frame_Q);
}
- if (ep->dummy_packets_Q) {
+ if (kfifo_initialized(&ep->dummy_packets_Q)) {
size = cq_howmany(&ep->dummy_packets_Q);
for (; size; size--) {
u8 *buff = cq_get(&ep->dummy_packets_Q);
diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c
new file mode 100644
index 000000000000..512f647448ca
--- /dev/null
+++ b/drivers/usb/host/imx21-dbg.c
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2009 by Martin Fuzzey
+ *
+ * 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.
+ */
+
+/* this file is part of imx21-hcd.c */
+
+#ifndef DEBUG
+
+static inline void create_debug_files(struct imx21 *imx21) { }
+static inline void remove_debug_files(struct imx21 *imx21) { }
+static inline void debug_urb_submitted(struct imx21 *imx21, struct urb *urb) {}
+static inline void debug_urb_completed(struct imx21 *imx21, struct urb *urb,
+ int status) {}
+static inline void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb) {}
+static inline void debug_urb_queued_for_etd(struct imx21 *imx21,
+ struct urb *urb) {}
+static inline void debug_urb_queued_for_dmem(struct imx21 *imx21,
+ struct urb *urb) {}
+static inline void debug_etd_allocated(struct imx21 *imx21) {}
+static inline void debug_etd_freed(struct imx21 *imx21) {}
+static inline void debug_dmem_allocated(struct imx21 *imx21, int size) {}
+static inline void debug_dmem_freed(struct imx21 *imx21, int size) {}
+static inline void debug_isoc_submitted(struct imx21 *imx21,
+ int frame, struct td *td) {}
+static inline void debug_isoc_completed(struct imx21 *imx21,
+ int frame, struct td *td, int cc, int len) {}
+
+#else
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static const char *dir_labels[] = {
+ "TD 0",
+ "OUT",
+ "IN",
+ "TD 1"
+};
+
+static const char *speed_labels[] = {
+ "Full",
+ "Low"
+};
+
+static const char *format_labels[] = {
+ "Control",
+ "ISO",
+ "Bulk",
+ "Interrupt"
+};
+
+static inline struct debug_stats *stats_for_urb(struct imx21 *imx21,
+ struct urb *urb)
+{
+ return usb_pipeisoc(urb->pipe) ?
+ &imx21->isoc_stats : &imx21->nonisoc_stats;
+}
+
+static void debug_urb_submitted(struct imx21 *imx21, struct urb *urb)
+{
+ stats_for_urb(imx21, urb)->submitted++;
+}
+
+static void debug_urb_completed(struct imx21 *imx21, struct urb *urb, int st)
+{
+ if (st)
+ stats_for_urb(imx21, urb)->completed_failed++;
+ else
+ stats_for_urb(imx21, urb)->completed_ok++;
+}
+
+static void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb)
+{
+ stats_for_urb(imx21, urb)->unlinked++;
+}
+
+static void debug_urb_queued_for_etd(struct imx21 *imx21, struct urb *urb)
+{
+ stats_for_urb(imx21, urb)->queue_etd++;
+}
+
+static void debug_urb_queued_for_dmem(struct imx21 *imx21, struct urb *urb)
+{
+ stats_for_urb(imx21, urb)->queue_dmem++;
+}
+
+static inline void debug_etd_allocated(struct imx21 *imx21)
+{
+ imx21->etd_usage.maximum = max(
+ ++(imx21->etd_usage.value),
+ imx21->etd_usage.maximum);
+}
+
+static inline void debug_etd_freed(struct imx21 *imx21)
+{
+ imx21->etd_usage.value--;
+}
+
+static inline void debug_dmem_allocated(struct imx21 *imx21, int size)
+{
+ imx21->dmem_usage.value += size;
+ imx21->dmem_usage.maximum = max(
+ imx21->dmem_usage.value,
+ imx21->dmem_usage.maximum);
+}
+
+static inline void debug_dmem_freed(struct imx21 *imx21, int size)
+{
+ imx21->dmem_usage.value -= size;
+}
+
+
+static void debug_isoc_submitted(struct imx21 *imx21,
+ int frame, struct td *td)
+{
+ struct debug_isoc_trace *trace = &imx21->isoc_trace[
+ imx21->isoc_trace_index++];
+
+ imx21->isoc_trace_index %= ARRAY_SIZE(imx21->isoc_trace);
+ trace->schedule_frame = td->frame;
+ trace->submit_frame = frame;
+ trace->request_len = td->len;
+ trace->td = td;
+}
+
+static inline void debug_isoc_completed(struct imx21 *imx21,
+ int frame, struct td *td, int cc, int len)
+{
+ struct debug_isoc_trace *trace, *trace_failed;
+ int i;
+ int found = 0;
+
+ trace = imx21->isoc_trace;
+ for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++) {
+ if (trace->td == td) {
+ trace->done_frame = frame;
+ trace->done_len = len;
+ trace->cc = cc;
+ trace->td = NULL;
+ found = 1;
+ break;
+ }
+ }
+
+ if (found && cc) {
+ trace_failed = &imx21->isoc_trace_failed[
+ imx21->isoc_trace_index_failed++];
+
+ imx21->isoc_trace_index_failed %= ARRAY_SIZE(
+ imx21->isoc_trace_failed);
+ *trace_failed = *trace;
+ }
+}
+
+
+static char *format_ep(struct usb_host_endpoint *ep, char *buf, int bufsize)
+{
+ if (ep)
+ snprintf(buf, bufsize, "ep_%02x (type:%02X kaddr:%p)",
+ ep->desc.bEndpointAddress,
+ usb_endpoint_type(&ep->desc),
+ ep);
+ else
+ snprintf(buf, bufsize, "none");
+ return buf;
+}
+
+static char *format_etd_dword0(u32 value, char *buf, int bufsize)
+{
+ snprintf(buf, bufsize,
+ "addr=%d ep=%d dir=%s speed=%s format=%s halted=%d",
+ value & 0x7F,
+ (value >> DW0_ENDPNT) & 0x0F,
+ dir_labels[(value >> DW0_DIRECT) & 0x03],
+ speed_labels[(value >> DW0_SPEED) & 0x01],
+ format_labels[(value >> DW0_FORMAT) & 0x03],
+ (value >> DW0_HALTED) & 0x01);
+ return buf;
+}
+
+static int debug_status_show(struct seq_file *s, void *v)
+{
+ struct imx21 *imx21 = s->private;
+ int etds_allocated = 0;
+ int etds_sw_busy = 0;
+ int etds_hw_busy = 0;
+ int dmem_blocks = 0;
+ int queued_for_etd = 0;
+ int queued_for_dmem = 0;
+ unsigned int dmem_bytes = 0;
+ int i;
+ struct etd_priv *etd;
+ u32 etd_enable_mask;
+ unsigned long flags;
+ struct imx21_dmem_area *dmem;
+ struct ep_priv *ep_priv;
+
+ spin_lock_irqsave(&imx21->lock, flags);
+
+ etd_enable_mask = readl(imx21->regs + USBH_ETDENSET);
+ for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) {
+ if (etd->alloc)
+ etds_allocated++;
+ if (etd->urb)
+ etds_sw_busy++;
+ if (etd_enable_mask & (1<<i))
+ etds_hw_busy++;
+ }
+
+ list_for_each_entry(dmem, &imx21->dmem_list, list) {
+ dmem_bytes += dmem->size;
+ dmem_blocks++;
+ }
+
+ list_for_each_entry(ep_priv, &imx21->queue_for_etd, queue)
+ queued_for_etd++;
+
+ list_for_each_entry(etd, &imx21->queue_for_dmem, queue)
+ queued_for_dmem++;
+
+ spin_unlock_irqrestore(&imx21->lock, flags);
+
+ seq_printf(s,
+ "Frame: %d\n"
+ "ETDs allocated: %d/%d (max=%d)\n"
+ "ETDs in use sw: %d\n"
+ "ETDs in use hw: %d\n"
+ "DMEM alocated: %d/%d (max=%d)\n"
+ "DMEM blocks: %d\n"
+ "Queued waiting for ETD: %d\n"
+ "Queued waiting for DMEM: %d\n",
+ readl(imx21->regs + USBH_FRMNUB) & 0xFFFF,
+ etds_allocated, USB_NUM_ETD, imx21->etd_usage.maximum,
+ etds_sw_busy,
+ etds_hw_busy,
+ dmem_bytes, DMEM_SIZE, imx21->dmem_usage.maximum,
+ dmem_blocks,
+ queued_for_etd,
+ queued_for_dmem);
+
+ return 0;
+}
+
+static int debug_dmem_show(struct seq_file *s, void *v)
+{
+ struct imx21 *imx21 = s->private;
+ struct imx21_dmem_area *dmem;
+ unsigned long flags;
+ char ep_text[40];
+
+ spin_lock_irqsave(&imx21->lock, flags);
+
+ list_for_each_entry(dmem, &imx21->dmem_list, list)
+ seq_printf(s,
+ "%04X: size=0x%X "
+ "ep=%s\n",
+ dmem->offset, dmem->size,
+ format_ep(dmem->ep, ep_text, sizeof(ep_text)));
+
+ spin_unlock_irqrestore(&imx21->lock, flags);
+
+ return 0;
+}
+
+static int debug_etd_show(struct seq_file *s, void *v)
+{
+ struct imx21 *imx21 = s->private;
+ struct etd_priv *etd;
+ char buf[60];
+ u32 dword;
+ int i, j;
+ unsigned long flags;
+
+ spin_lock_irqsave(&imx21->lock, flags);
+
+ for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) {
+ int state = -1;
+ struct urb_priv *urb_priv;
+ if (etd->urb) {
+ urb_priv = etd->urb->hcpriv;
+ if (urb_priv)
+ state = urb_priv->state;
+ }
+
+ seq_printf(s,
+ "etd_num: %d\n"
+ "ep: %s\n"
+ "alloc: %d\n"
+ "len: %d\n"
+ "busy sw: %d\n"
+ "busy hw: %d\n"
+ "urb state: %d\n"
+ "current urb: %p\n",
+
+ i,
+ format_ep(etd->ep, buf, sizeof(buf)),
+ etd->alloc,
+ etd->len,
+ etd->urb != NULL,
+ (readl(imx21->regs + USBH_ETDENSET) & (1 << i)) > 0,
+ state,
+ etd->urb);
+
+ for (j = 0; j < 4; j++) {
+ dword = etd_readl(imx21, i, j);
+ switch (j) {
+ case 0:
+ format_etd_dword0(dword, buf, sizeof(buf));
+ break;
+ case 2:
+ snprintf(buf, sizeof(buf),
+ "cc=0X%02X", dword >> DW2_COMPCODE);
+ break;
+ default:
+ *buf = 0;
+ break;
+ }
+ seq_printf(s,
+ "dword %d: submitted=%08X cur=%08X [%s]\n",
+ j,
+ etd->submitted_dwords[j],
+ dword,
+ buf);
+ }
+ seq_printf(s, "\n");
+ }
+
+ spin_unlock_irqrestore(&imx21->lock, flags);
+
+ return 0;
+}
+
+static void debug_statistics_show_one(struct seq_file *s,
+ const char *name, struct debug_stats *stats)
+{
+ seq_printf(s, "%s:\n"
+ "submitted URBs: %lu\n"
+ "completed OK: %lu\n"
+ "completed failed: %lu\n"
+ "unlinked: %lu\n"
+ "queued for ETD: %lu\n"
+ "queued for DMEM: %lu\n\n",
+ name,
+ stats->submitted,
+ stats->completed_ok,
+ stats->completed_failed,
+ stats->unlinked,
+ stats->queue_etd,
+ stats->queue_dmem);
+}
+
+static int debug_statistics_show(struct seq_file *s, void *v)
+{
+ struct imx21 *imx21 = s->private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&imx21->lock, flags);
+
+ debug_statistics_show_one(s, "nonisoc", &imx21->nonisoc_stats);
+ debug_statistics_show_one(s, "isoc", &imx21->isoc_stats);
+ seq_printf(s, "unblock kludge triggers: %lu\n", imx21->debug_unblocks);
+ spin_unlock_irqrestore(&imx21->lock, flags);
+
+ return 0;
+}
+
+static void debug_isoc_show_one(struct seq_file *s,
+ const char *name, int index, struct debug_isoc_trace *trace)
+{
+ seq_printf(s, "%s %d:\n"
+ "cc=0X%02X\n"
+ "scheduled frame %d (%d)\n"
+ "submittted frame %d (%d)\n"
+ "completed frame %d (%d)\n"
+ "requested length=%d\n"
+ "completed length=%d\n\n",
+ name, index,
+ trace->cc,
+ trace->schedule_frame, trace->schedule_frame & 0xFFFF,
+ trace->submit_frame, trace->submit_frame & 0xFFFF,
+ trace->done_frame, trace->done_frame & 0xFFFF,
+ trace->request_len,
+ trace->done_len);
+}
+
+static int debug_isoc_show(struct seq_file *s, void *v)
+{
+ struct imx21 *imx21 = s->private;
+ struct debug_isoc_trace *trace;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&imx21->lock, flags);
+
+ trace = imx21->isoc_trace_failed;
+ for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace_failed); i++, trace++)
+ debug_isoc_show_one(s, "isoc failed", i, trace);
+
+ trace = imx21->isoc_trace;
+ for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++)
+ debug_isoc_show_one(s, "isoc", i, trace);
+
+ spin_unlock_irqrestore(&imx21->lock, flags);
+
+ return 0;
+}
+
+static int debug_status_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, debug_status_show, inode->i_private);
+}
+
+static int debug_dmem_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, debug_dmem_show, inode->i_private);
+}
+
+static int debug_etd_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, debug_etd_show, inode->i_private);
+}
+
+static int debug_statistics_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, debug_statistics_show, inode->i_private);
+}
+
+static int debug_isoc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, debug_isoc_show, inode->i_private);
+}
+
+static const struct file_operations debug_status_fops = {
+ .open = debug_status_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations debug_dmem_fops = {
+ .open = debug_dmem_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations debug_etd_fops = {
+ .open = debug_etd_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations debug_statistics_fops = {
+ .open = debug_statistics_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations debug_isoc_fops = {
+ .open = debug_isoc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void create_debug_files(struct imx21 *imx21)
+{
+ imx21->debug_root = debugfs_create_dir(dev_name(imx21->dev), NULL);
+ if (!imx21->debug_root)
+ goto failed_create_rootdir;
+
+ if (!debugfs_create_file("status", S_IRUGO,
+ imx21->debug_root, imx21, &debug_status_fops))
+ goto failed_create;
+
+ if (!debugfs_create_file("dmem", S_IRUGO,
+ imx21->debug_root, imx21, &debug_dmem_fops))
+ goto failed_create;
+
+ if (!debugfs_create_file("etd", S_IRUGO,
+ imx21->debug_root, imx21, &debug_etd_fops))
+ goto failed_create;
+
+ if (!debugfs_create_file("statistics", S_IRUGO,
+ imx21->debug_root, imx21, &debug_statistics_fops))
+ goto failed_create;
+
+ if (!debugfs_create_file("isoc", S_IRUGO,
+ imx21->debug_root, imx21, &debug_isoc_fops))
+ goto failed_create;
+
+ return;
+
+failed_create:
+ debugfs_remove_recursive(imx21->debug_root);
+
+failed_create_rootdir:
+ imx21->debug_root = NULL;
+}
+
+
+static void remove_debug_files(struct imx21 *imx21)
+{
+ if (imx21->debug_root) {
+ debugfs_remove_recursive(imx21->debug_root);
+ imx21->debug_root = NULL;
+ }
+}
+
+#endif
+
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
new file mode 100644
index 000000000000..213e270e1c29
--- /dev/null
+++ b/drivers/usb/host/imx21-hcd.c
@@ -0,0 +1,1789 @@
+/*
+ * USB Host Controller Driver for IMX21
+ *
+ * Copyright (C) 2006 Loping Dog Embedded Systems
+ * Copyright (C) 2009 Martin Fuzzey
+ * Originally written by Jay Monkman <jtm@lopingdog.com>
+ * Ported to 2.6.30, debugged and enhanced by Martin Fuzzey
+ *
+ * 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.
+ */
+
+
+ /*
+ * The i.MX21 USB hardware contains
+ * * 32 transfer descriptors (called ETDs)
+ * * 4Kb of Data memory
+ *
+ * The data memory is shared between the host and fuction controlers
+ * (but this driver only supports the host controler)
+ *
+ * So setting up a transfer involves:
+ * * Allocating a ETD
+ * * Fill in ETD with appropriate information
+ * * Allocating data memory (and putting the offset in the ETD)
+ * * Activate the ETD
+ * * Get interrupt when done.
+ *
+ * An ETD is assigned to each active endpoint.
+ *
+ * Low resource (ETD and Data memory) situations are handled differently for
+ * isochronous and non insosynchronous transactions :
+ *
+ * Non ISOC transfers are queued if either ETDs or Data memory are unavailable
+ *
+ * ISOC transfers use 2 ETDs per endpoint to achieve double buffering.
+ * They allocate both ETDs and Data memory during URB submission
+ * (and fail if unavailable).
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/usb.h>
+
+#include "../core/hcd.h"
+#include "imx21-hcd.h"
+
+#ifdef DEBUG
+#define DEBUG_LOG_FRAME(imx21, etd, event) \
+ (etd)->event##_frame = readl((imx21)->regs + USBH_FRMNUB)
+#else
+#define DEBUG_LOG_FRAME(imx21, etd, event) do { } while (0)
+#endif
+
+static const char hcd_name[] = "imx21-hcd";
+
+static inline struct imx21 *hcd_to_imx21(struct usb_hcd *hcd)
+{
+ return (struct imx21 *)hcd->hcd_priv;
+}
+
+
+/* =========================================== */
+/* Hardware access helpers */
+/* =========================================== */
+
+static inline void set_register_bits(struct imx21 *imx21, u32 offset, u32 mask)
+{
+ void __iomem *reg = imx21->regs + offset;
+ writel(readl(reg) | mask, reg);
+}
+
+static inline void clear_register_bits(struct imx21 *imx21,
+ u32 offset, u32 mask)
+{
+ void __iomem *reg = imx21->regs + offset;
+ writel(readl(reg) & ~mask, reg);
+}
+
+static inline void clear_toggle_bit(struct imx21 *imx21, u32 offset, u32 mask)
+{
+ void __iomem *reg = imx21->regs + offset;
+
+ if (readl(reg) & mask)
+ writel(mask, reg);
+}
+
+static inline void set_toggle_bit(struct imx21 *imx21, u32 offset, u32 mask)
+{
+ void __iomem *reg = imx21->regs + offset;
+
+ if (!(readl(reg) & mask))
+ writel(mask, reg);
+}
+
+static void etd_writel(struct imx21 *imx21, int etd_num, int dword, u32 value)
+{
+ writel(value, imx21->regs + USB_ETD_DWORD(etd_num, dword));
+}
+
+static u32 etd_readl(struct imx21 *imx21, int etd_num, int dword)
+{
+ return readl(imx21->regs + USB_ETD_DWORD(etd_num, dword));
+}
+
+static inline int wrap_frame(int counter)
+{
+ return counter & 0xFFFF;
+}
+
+static inline int frame_after(int frame, int after)
+{
+ /* handle wrapping like jiffies time_afer */
+ return (s16)((s16)after - (s16)frame) < 0;
+}
+
+static int imx21_hc_get_frame(struct usb_hcd *hcd)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+
+ return wrap_frame(readl(imx21->regs + USBH_FRMNUB));
+}
+
+
+#include "imx21-dbg.c"
+
+/* =========================================== */
+/* ETD management */
+/* =========================================== */
+
+static int alloc_etd(struct imx21 *imx21)
+{
+ int i;
+ struct etd_priv *etd = imx21->etd;
+
+ for (i = 0; i < USB_NUM_ETD; i++, etd++) {
+ if (etd->alloc == 0) {
+ memset(etd, 0, sizeof(imx21->etd[0]));
+ etd->alloc = 1;
+ debug_etd_allocated(imx21);
+ return i;
+ }
+ }
+ return -1;
+}
+
+static void disactivate_etd(struct imx21 *imx21, int num)
+{
+ int etd_mask = (1 << num);
+ struct etd_priv *etd = &imx21->etd[num];
+
+ writel(etd_mask, imx21->regs + USBH_ETDENCLR);
+ clear_register_bits(imx21, USBH_ETDDONEEN, etd_mask);
+ writel(etd_mask, imx21->regs + USB_ETDDMACHANLCLR);
+ clear_toggle_bit(imx21, USBH_ETDDONESTAT, etd_mask);
+
+ etd->active_count = 0;
+
+ DEBUG_LOG_FRAME(imx21, etd, disactivated);
+}
+
+static void reset_etd(struct imx21 *imx21, int num)
+{
+ struct etd_priv *etd = imx21->etd + num;
+ int i;
+
+ disactivate_etd(imx21, num);
+
+ for (i = 0; i < 4; i++)
+ etd_writel(imx21, num, i, 0);
+ etd->urb = NULL;
+ etd->ep = NULL;
+ etd->td = NULL;;
+}
+
+static void free_etd(struct imx21 *imx21, int num)
+{
+ if (num < 0)
+ return;
+
+ if (num >= USB_NUM_ETD) {
+ dev_err(imx21->dev, "BAD etd=%d!\n", num);
+ return;
+ }
+ if (imx21->etd[num].alloc == 0) {
+ dev_err(imx21->dev, "ETD %d already free!\n", num);
+ return;
+ }
+
+ debug_etd_freed(imx21);
+ reset_etd(imx21, num);
+ memset(&imx21->etd[num], 0, sizeof(imx21->etd[0]));
+}
+
+
+static void setup_etd_dword0(struct imx21 *imx21,
+ int etd_num, struct urb *urb, u8 dir, u16 maxpacket)
+{
+ etd_writel(imx21, etd_num, 0,
+ ((u32) usb_pipedevice(urb->pipe)) << DW0_ADDRESS |
+ ((u32) usb_pipeendpoint(urb->pipe) << DW0_ENDPNT) |
+ ((u32) dir << DW0_DIRECT) |
+ ((u32) ((urb->dev->speed == USB_SPEED_LOW) ?
+ 1 : 0) << DW0_SPEED) |
+ ((u32) fmt_urb_to_etd[usb_pipetype(urb->pipe)] << DW0_FORMAT) |
+ ((u32) maxpacket << DW0_MAXPKTSIZ));
+}
+
+static void activate_etd(struct imx21 *imx21,
+ int etd_num, dma_addr_t dma, u8 dir)
+{
+ u32 etd_mask = 1 << etd_num;
+ struct etd_priv *etd = &imx21->etd[etd_num];
+
+ clear_toggle_bit(imx21, USBH_ETDDONESTAT, etd_mask);
+ set_register_bits(imx21, USBH_ETDDONEEN, etd_mask);
+ clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
+ clear_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
+
+ if (dma) {
+ set_register_bits(imx21, USB_ETDDMACHANLCLR, etd_mask);
+ clear_toggle_bit(imx21, USBH_XBUFSTAT, etd_mask);
+ clear_toggle_bit(imx21, USBH_YBUFSTAT, etd_mask);
+ writel(dma, imx21->regs + USB_ETDSMSA(etd_num));
+ set_register_bits(imx21, USB_ETDDMAEN, etd_mask);
+ } else {
+ if (dir != TD_DIR_IN) {
+ /* need to set for ZLP */
+ set_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
+ set_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
+ }
+ }
+
+ DEBUG_LOG_FRAME(imx21, etd, activated);
+
+#ifdef DEBUG
+ if (!etd->active_count) {
+ int i;
+ etd->activated_frame = readl(imx21->regs + USBH_FRMNUB);
+ etd->disactivated_frame = -1;
+ etd->last_int_frame = -1;
+ etd->last_req_frame = -1;
+
+ for (i = 0; i < 4; i++)
+ etd->submitted_dwords[i] = etd_readl(imx21, etd_num, i);
+ }
+#endif
+
+ etd->active_count = 1;
+ writel(etd_mask, imx21->regs + USBH_ETDENSET);
+}
+
+/* =========================================== */
+/* Data memory management */
+/* =========================================== */
+
+static int alloc_dmem(struct imx21 *imx21, unsigned int size,
+ struct usb_host_endpoint *ep)
+{
+ unsigned int offset = 0;
+ struct imx21_dmem_area *area;
+ struct imx21_dmem_area *tmp;
+
+ size += (~size + 1) & 0x3; /* Round to 4 byte multiple */
+
+ if (size > DMEM_SIZE) {
+ dev_err(imx21->dev, "size=%d > DMEM_SIZE(%d)\n",
+ size, DMEM_SIZE);
+ return -EINVAL;
+ }
+
+ list_for_each_entry(tmp, &imx21->dmem_list, list) {
+ if ((size + offset) < offset)
+ goto fail;
+ if ((size + offset) <= tmp->offset)
+ break;
+ offset = tmp->size + tmp->offset;
+ if ((offset + size) > DMEM_SIZE)
+ goto fail;
+ }
+
+ area = kmalloc(sizeof(struct imx21_dmem_area), GFP_ATOMIC);
+ if (area == NULL)
+ return -ENOMEM;
+
+ area->ep = ep;
+ area->offset = offset;
+ area->size = size;
+ list_add_tail(&area->list, &tmp->list);
+ debug_dmem_allocated(imx21, size);
+ return offset;
+
+fail:
+ return -ENOMEM;
+}
+
+/* Memory now available for a queued ETD - activate it */
+static void activate_queued_etd(struct imx21 *imx21,
+ struct etd_priv *etd, u32 dmem_offset)
+{
+ struct urb_priv *urb_priv = etd->urb->hcpriv;
+ int etd_num = etd - &imx21->etd[0];
+ u32 maxpacket = etd_readl(imx21, etd_num, 1) >> DW1_YBUFSRTAD;
+ u8 dir = (etd_readl(imx21, etd_num, 2) >> DW2_DIRPID) & 0x03;
+
+ dev_dbg(imx21->dev, "activating queued ETD %d now DMEM available\n",
+ etd_num);
+ etd_writel(imx21, etd_num, 1,
+ ((dmem_offset + maxpacket) << DW1_YBUFSRTAD) | dmem_offset);
+
+ urb_priv->active = 1;
+ activate_etd(imx21, etd_num, etd->dma_handle, dir);
+}
+
+static void free_dmem(struct imx21 *imx21, int offset)
+{
+ struct imx21_dmem_area *area;
+ struct etd_priv *etd, *tmp;
+ int found = 0;
+
+ list_for_each_entry(area, &imx21->dmem_list, list) {
+ if (area->offset == offset) {
+ debug_dmem_freed(imx21, area->size);
+ list_del(&area->list);
+ kfree(area);
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ dev_err(imx21->dev,
+ "Trying to free unallocated DMEM %d\n", offset);
+ return;
+ }
+
+ /* Try again to allocate memory for anything we've queued */
+ list_for_each_entry_safe(etd, tmp, &imx21->queue_for_dmem, queue) {
+ offset = alloc_dmem(imx21, etd->dmem_size, etd->ep);
+ if (offset >= 0) {
+ list_del(&etd->queue);
+ activate_queued_etd(imx21, etd, (u32)offset);
+ }
+ }
+}
+
+static void free_epdmem(struct imx21 *imx21, struct usb_host_endpoint *ep)
+{
+ struct imx21_dmem_area *area, *tmp;
+
+ list_for_each_entry_safe(area, tmp, &imx21->dmem_list, list) {
+ if (area->ep == ep) {
+ dev_err(imx21->dev,
+ "Active DMEM %d for disabled ep=%p\n",
+ area->offset, ep);
+ list_del(&area->list);
+ kfree(area);
+ }
+ }
+}
+
+
+/* =========================================== */
+/* End handling */
+/* =========================================== */
+static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb);
+
+/* Endpoint now idle - release it's ETD(s) or asssign to queued request */
+static void ep_idle(struct imx21 *imx21, struct ep_priv *ep_priv)
+{
+ int etd_num;
+ int i;
+
+ for (i = 0; i < NUM_ISO_ETDS; i++) {
+ etd_num = ep_priv->etd[i];
+ if (etd_num < 0)
+ continue;
+
+ ep_priv->etd[i] = -1;
+ if (list_empty(&imx21->queue_for_etd)) {
+ free_etd(imx21, etd_num);
+ continue;
+ }
+
+ dev_dbg(imx21->dev,
+ "assigning idle etd %d for queued request\n", etd_num);
+ ep_priv = list_first_entry(&imx21->queue_for_etd,
+ struct ep_priv, queue);
+ list_del(&ep_priv->queue);
+ reset_etd(imx21, etd_num);
+ ep_priv->waiting_etd = 0;
+ ep_priv->etd[i] = etd_num;
+
+ if (list_empty(&ep_priv->ep->urb_list)) {
+ dev_err(imx21->dev, "No urb for queued ep!\n");
+ continue;
+ }
+ schedule_nonisoc_etd(imx21, list_first_entry(
+ &ep_priv->ep->urb_list, struct urb, urb_list));
+ }
+}
+
+static void urb_done(struct usb_hcd *hcd, struct urb *urb, int status)
+__releases(imx21->lock)
+__acquires(imx21->lock)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ struct ep_priv *ep_priv = urb->ep->hcpriv;
+ struct urb_priv *urb_priv = urb->hcpriv;
+
+ debug_urb_completed(imx21, urb, status);
+ dev_vdbg(imx21->dev, "urb %p done %d\n", urb, status);
+
+ kfree(urb_priv->isoc_td);
+ kfree(urb->hcpriv);
+ urb->hcpriv = NULL;
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock(&imx21->lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&imx21->lock);
+ if (list_empty(&ep_priv->ep->urb_list))
+ ep_idle(imx21, ep_priv);
+}
+
+/* =========================================== */
+/* ISOC Handling ... */
+/* =========================================== */
+
+static void schedule_isoc_etds(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ struct ep_priv *ep_priv = ep->hcpriv;
+ struct etd_priv *etd;
+ struct urb_priv *urb_priv;
+ struct td *td;
+ int etd_num;
+ int i;
+ int cur_frame;
+ u8 dir;
+
+ for (i = 0; i < NUM_ISO_ETDS; i++) {
+too_late:
+ if (list_empty(&ep_priv->td_list))
+ break;
+
+ etd_num = ep_priv->etd[i];
+ if (etd_num < 0)
+ break;
+
+ etd = &imx21->etd[etd_num];
+ if (etd->urb)
+ continue;
+
+ td = list_entry(ep_priv->td_list.next, struct td, list);
+ list_del(&td->list);
+ urb_priv = td->urb->hcpriv;
+
+ cur_frame = imx21_hc_get_frame(hcd);
+ if (frame_after(cur_frame, td->frame)) {
+ dev_dbg(imx21->dev, "isoc too late frame %d > %d\n",
+ cur_frame, td->frame);
+ urb_priv->isoc_status = -EXDEV;
+ td->urb->iso_frame_desc[
+ td->isoc_index].actual_length = 0;
+ td->urb->iso_frame_desc[td->isoc_index].status = -EXDEV;
+ if (--urb_priv->isoc_remaining == 0)
+ urb_done(hcd, td->urb, urb_priv->isoc_status);
+ goto too_late;
+ }
+
+ urb_priv->active = 1;
+ etd->td = td;
+ etd->ep = td->ep;
+ etd->urb = td->urb;
+ etd->len = td->len;
+
+ debug_isoc_submitted(imx21, cur_frame, td);
+
+ dir = usb_pipeout(td->urb->pipe) ? TD_DIR_OUT : TD_DIR_IN;
+ setup_etd_dword0(imx21, etd_num, td->urb, dir, etd->dmem_size);
+ etd_writel(imx21, etd_num, 1, etd->dmem_offset);
+ etd_writel(imx21, etd_num, 2,
+ (TD_NOTACCESSED << DW2_COMPCODE) |
+ ((td->frame & 0xFFFF) << DW2_STARTFRM));
+ etd_writel(imx21, etd_num, 3,
+ (TD_NOTACCESSED << DW3_COMPCODE0) |
+ (td->len << DW3_PKTLEN0));
+
+ activate_etd(imx21, etd_num, td->data, dir);
+ }
+}
+
+static void isoc_etd_done(struct usb_hcd *hcd, struct urb *urb, int etd_num)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ int etd_mask = 1 << etd_num;
+ struct urb_priv *urb_priv = urb->hcpriv;
+ struct etd_priv *etd = imx21->etd + etd_num;
+ struct td *td = etd->td;
+ struct usb_host_endpoint *ep = etd->ep;
+ int isoc_index = td->isoc_index;
+ unsigned int pipe = urb->pipe;
+ int dir_in = usb_pipein(pipe);
+ int cc;
+ int bytes_xfrd;
+
+ disactivate_etd(imx21, etd_num);
+
+ cc = (etd_readl(imx21, etd_num, 3) >> DW3_COMPCODE0) & 0xf;
+ bytes_xfrd = etd_readl(imx21, etd_num, 3) & 0x3ff;
+
+ /* Input doesn't always fill the buffer, don't generate an error
+ * when this happens.
+ */
+ if (dir_in && (cc == TD_DATAUNDERRUN))
+ cc = TD_CC_NOERROR;
+
+ if (cc == TD_NOTACCESSED)
+ bytes_xfrd = 0;
+
+ debug_isoc_completed(imx21,
+ imx21_hc_get_frame(hcd), td, cc, bytes_xfrd);
+ if (cc) {
+ urb_priv->isoc_status = -EXDEV;
+ dev_dbg(imx21->dev,
+ "bad iso cc=0x%X frame=%d sched frame=%d "
+ "cnt=%d len=%d urb=%p etd=%d index=%d\n",
+ cc, imx21_hc_get_frame(hcd), td->frame,
+ bytes_xfrd, td->len, urb, etd_num, isoc_index);
+ }
+
+ if (dir_in)
+ clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
+
+ urb->actual_length += bytes_xfrd;
+ urb->iso_frame_desc[isoc_index].actual_length = bytes_xfrd;
+ urb->iso_frame_desc[isoc_index].status = cc_to_error[cc];
+
+ etd->td = NULL;
+ etd->urb = NULL;
+ etd->ep = NULL;
+
+ if (--urb_priv->isoc_remaining == 0)
+ urb_done(hcd, urb, urb_priv->isoc_status);
+
+ schedule_isoc_etds(hcd, ep);
+}
+
+static struct ep_priv *alloc_isoc_ep(
+ struct imx21 *imx21, struct usb_host_endpoint *ep)
+{
+ struct ep_priv *ep_priv;
+ int i;
+
+ ep_priv = kzalloc(sizeof(struct ep_priv), GFP_ATOMIC);
+ if (ep_priv == NULL)
+ return NULL;
+
+ /* Allocate the ETDs */
+ for (i = 0; i < NUM_ISO_ETDS; i++) {
+ ep_priv->etd[i] = alloc_etd(imx21);
+ if (ep_priv->etd[i] < 0) {
+ int j;
+ dev_err(imx21->dev, "isoc: Couldn't allocate etd\n");
+ for (j = 0; j < i; j++)
+ free_etd(imx21, ep_priv->etd[j]);
+ goto alloc_etd_failed;
+ }
+ imx21->etd[ep_priv->etd[i]].ep = ep;
+ }
+
+ INIT_LIST_HEAD(&ep_priv->td_list);
+ ep_priv->ep = ep;
+ ep->hcpriv = ep_priv;
+ return ep_priv;
+
+alloc_etd_failed:
+ kfree(ep_priv);
+ return NULL;
+}
+
+static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep,
+ struct urb *urb, gfp_t mem_flags)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ struct urb_priv *urb_priv;
+ unsigned long flags;
+ struct ep_priv *ep_priv;
+ struct td *td = NULL;
+ int i;
+ int ret;
+ int cur_frame;
+ u16 maxpacket;
+
+ urb_priv = kzalloc(sizeof(struct urb_priv), mem_flags);
+ if (urb_priv == NULL)
+ return -ENOMEM;
+
+ urb_priv->isoc_td = kzalloc(
+ sizeof(struct td) * urb->number_of_packets, mem_flags);
+ if (urb_priv->isoc_td == NULL) {
+ ret = -ENOMEM;
+ goto alloc_td_failed;
+ }
+
+ spin_lock_irqsave(&imx21->lock, flags);
+
+ if (ep->hcpriv == NULL) {
+ ep_priv = alloc_isoc_ep(imx21, ep);
+ if (ep_priv == NULL) {
+ ret = -ENOMEM;
+ goto alloc_ep_failed;
+ }
+ } else {
+ ep_priv = ep->hcpriv;
+ }
+
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto link_failed;
+
+ urb->status = -EINPROGRESS;
+ urb->actual_length = 0;
+ urb->error_count = 0;
+ urb->hcpriv = urb_priv;
+ urb_priv->ep = ep;
+
+ /* allocate data memory for largest packets if not already done */
+ maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+ for (i = 0; i < NUM_ISO_ETDS; i++) {
+ struct etd_priv *etd = &imx21->etd[ep_priv->etd[i]];
+
+ if (etd->dmem_size > 0 && etd->dmem_size < maxpacket) {
+ /* not sure if this can really occur.... */
+ dev_err(imx21->dev, "increasing isoc buffer %d->%d\n",
+ etd->dmem_size, maxpacket);
+ ret = -EMSGSIZE;
+ goto alloc_dmem_failed;
+ }
+
+ if (etd->dmem_size == 0) {
+ etd->dmem_offset = alloc_dmem(imx21, maxpacket, ep);
+ if (etd->dmem_offset < 0) {
+ dev_dbg(imx21->dev, "failed alloc isoc dmem\n");
+ ret = -EAGAIN;
+ goto alloc_dmem_failed;
+ }
+ etd->dmem_size = maxpacket;
+ }
+ }
+
+ /* calculate frame */
+ cur_frame = imx21_hc_get_frame(hcd);
+ if (urb->transfer_flags & URB_ISO_ASAP) {
+ if (list_empty(&ep_priv->td_list))
+ urb->start_frame = cur_frame + 5;
+ else
+ urb->start_frame = list_entry(
+ ep_priv->td_list.prev,
+ struct td, list)->frame + urb->interval;
+ }
+ urb->start_frame = wrap_frame(urb->start_frame);
+ if (frame_after(cur_frame, urb->start_frame)) {
+ dev_dbg(imx21->dev,
+ "enqueue: adjusting iso start %d (cur=%d) asap=%d\n",
+ urb->start_frame, cur_frame,
+ (urb->transfer_flags & URB_ISO_ASAP) != 0);
+ urb->start_frame = wrap_frame(cur_frame + 1);
+ }
+
+ /* set up transfers */
+ td = urb_priv->isoc_td;
+ for (i = 0; i < urb->number_of_packets; i++, td++) {
+ td->ep = ep;
+ td->urb = urb;
+ td->len = urb->iso_frame_desc[i].length;
+ td->isoc_index = i;
+ td->frame = wrap_frame(urb->start_frame + urb->interval * i);
+ td->data = urb->transfer_dma + urb->iso_frame_desc[i].offset;
+ list_add_tail(&td->list, &ep_priv->td_list);
+ }
+
+ urb_priv->isoc_remaining = urb->number_of_packets;
+ dev_vdbg(imx21->dev, "setup %d packets for iso frame %d->%d\n",
+ urb->number_of_packets, urb->start_frame, td->frame);
+
+ debug_urb_submitted(imx21, urb);
+ schedule_isoc_etds(hcd, ep);
+
+ spin_unlock_irqrestore(&imx21->lock, flags);
+ return 0;
+
+alloc_dmem_failed:
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+link_failed:
+alloc_ep_failed:
+ spin_unlock_irqrestore(&imx21->lock, flags);
+ kfree(urb_priv->isoc_td);
+
+alloc_td_failed:
+ kfree(urb_priv);
+ return ret;
+}
+
+static void dequeue_isoc_urb(struct imx21 *imx21,
+ struct urb *urb, struct ep_priv *ep_priv)
+{
+ struct urb_priv *urb_priv = urb->hcpriv;
+ struct td *td, *tmp;
+ int i;
+
+ if (urb_priv->active) {
+ for (i = 0; i < NUM_ISO_ETDS; i++) {
+ int etd_num = ep_priv->etd[i];
+ if (etd_num != -1 && imx21->etd[etd_num].urb == urb) {
+ struct etd_priv *etd = imx21->etd + etd_num;
+
+ reset_etd(imx21, etd_num);
+ if (etd->dmem_size)
+ free_dmem(imx21, etd->dmem_offset);
+ etd->dmem_size = 0;
+ }
+ }
+ }
+
+ list_for_each_entry_safe(td, tmp, &ep_priv->td_list, list) {
+ if (td->urb == urb) {
+ dev_vdbg(imx21->dev, "removing td %p\n", td);
+ list_del(&td->list);
+ }
+ }
+}
+
+/* =========================================== */
+/* NON ISOC Handling ... */
+/* =========================================== */
+
+static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb)
+{
+ unsigned int pipe = urb->pipe;
+ struct urb_priv *urb_priv = urb->hcpriv;
+ struct ep_priv *ep_priv = urb_priv->ep->hcpriv;
+ int state = urb_priv->state;
+ int etd_num = ep_priv->etd[0];
+ struct etd_priv *etd;
+ int dmem_offset;
+ u32 count;
+ u16 etd_buf_size;
+ u16 maxpacket;
+ u8 dir;
+ u8 bufround;
+ u8 datatoggle;
+ u8 interval = 0;
+ u8 relpolpos = 0;
+
+ if (etd_num < 0) {
+ dev_err(imx21->dev, "No valid ETD\n");
+ return;
+ }
+ if (readl(imx21->regs + USBH_ETDENSET) & (1 << etd_num))
+ dev_err(imx21->dev, "submitting to active ETD %d\n", etd_num);
+
+ etd = &imx21->etd[etd_num];
+ maxpacket = usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe));
+ if (!maxpacket)
+ maxpacket = 8;
+
+ if (usb_pipecontrol(pipe) && (state != US_CTRL_DATA)) {
+ if (state == US_CTRL_SETUP) {
+ dir = TD_DIR_SETUP;
+ etd->dma_handle = urb->setup_dma;
+ bufround = 0;
+ count = 8;
+ datatoggle = TD_TOGGLE_DATA0;
+ } else { /* US_CTRL_ACK */
+ dir = usb_pipeout(pipe) ? TD_DIR_IN : TD_DIR_OUT;
+ etd->dma_handle = urb->transfer_dma;
+ bufround = 0;
+ count = 0;
+ datatoggle = TD_TOGGLE_DATA1;
+ }
+ } else {
+ dir = usb_pipeout(pipe) ? TD_DIR_OUT : TD_DIR_IN;
+ bufround = (dir == TD_DIR_IN) ? 1 : 0;
+ etd->dma_handle = urb->transfer_dma;
+ if (usb_pipebulk(pipe) && (state == US_BULK0))
+ count = 0;
+ else
+ count = urb->transfer_buffer_length;
+
+ if (usb_pipecontrol(pipe)) {
+ datatoggle = TD_TOGGLE_DATA1;
+ } else {
+ if (usb_gettoggle(
+ urb->dev,
+ usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe)))
+ datatoggle = TD_TOGGLE_DATA1;
+ else
+ datatoggle = TD_TOGGLE_DATA0;
+ }
+ }
+
+ etd->urb = urb;
+ etd->ep = urb_priv->ep;
+ etd->len = count;
+
+ if (usb_pipeint(pipe)) {
+ interval = urb->interval;
+ relpolpos = (readl(imx21->regs + USBH_FRMNUB) + 1) & 0xff;
+ }
+
+ /* Write ETD to device memory */
+ setup_etd_dword0(imx21, etd_num, urb, dir, maxpacket);
+
+ etd_writel(imx21, etd_num, 2,
+ (u32) interval << DW2_POLINTERV |
+ ((u32) relpolpos << DW2_RELPOLPOS) |
+ ((u32) dir << DW2_DIRPID) |
+ ((u32) bufround << DW2_BUFROUND) |
+ ((u32) datatoggle << DW2_DATATOG) |
+ ((u32) TD_NOTACCESSED << DW2_COMPCODE));
+
+ /* DMA will always transfer buffer size even if TOBYCNT in DWORD3
+ is smaller. Make sure we don't overrun the buffer!
+ */
+ if (count && count < maxpacket)
+ etd_buf_size = count;
+ else
+ etd_buf_size = maxpacket;
+
+ etd_writel(imx21, etd_num, 3,
+ ((u32) (etd_buf_size - 1) << DW3_BUFSIZE) | (u32) count);
+
+ if (!count)
+ etd->dma_handle = 0;
+
+ /* allocate x and y buffer space at once */
+ etd->dmem_size = (count > maxpacket) ? maxpacket * 2 : maxpacket;
+ dmem_offset = alloc_dmem(imx21, etd->dmem_size, urb_priv->ep);
+ if (dmem_offset < 0) {
+ /* Setup everything we can in HW and update when we get DMEM */
+ etd_writel(imx21, etd_num, 1, (u32)maxpacket << 16);
+
+ dev_dbg(imx21->dev, "Queuing etd %d for DMEM\n", etd_num);
+ debug_urb_queued_for_dmem(imx21, urb);
+ list_add_tail(&etd->queue, &imx21->queue_for_dmem);
+ return;
+ }
+
+ etd_writel(imx21, etd_num, 1,
+ (((u32) dmem_offset + (u32) maxpacket) << DW1_YBUFSRTAD) |
+ (u32) dmem_offset);
+
+ urb_priv->active = 1;
+
+ /* enable the ETD to kick off transfer */
+ dev_vdbg(imx21->dev, "Activating etd %d for %d bytes %s\n",
+ etd_num, count, dir != TD_DIR_IN ? "out" : "in");
+ activate_etd(imx21, etd_num, etd->dma_handle, dir);
+
+}
+
+static void nonisoc_etd_done(struct usb_hcd *hcd, struct urb *urb, int etd_num)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ struct etd_priv *etd = &imx21->etd[etd_num];
+ u32 etd_mask = 1 << etd_num;
+ struct urb_priv *urb_priv = urb->hcpriv;
+ int dir;
+ u16 xbufaddr;
+ int cc;
+ u32 bytes_xfrd;
+ int etd_done;
+
+ disactivate_etd(imx21, etd_num);
+
+ dir = (etd_readl(imx21, etd_num, 0) >> DW0_DIRECT) & 0x3;
+ xbufaddr = etd_readl(imx21, etd_num, 1) & 0xffff;
+ cc = (etd_readl(imx21, etd_num, 2) >> DW2_COMPCODE) & 0xf;
+ bytes_xfrd = etd->len - (etd_readl(imx21, etd_num, 3) & 0x1fffff);
+
+ /* save toggle carry */
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe),
+ (etd_readl(imx21, etd_num, 0) >> DW0_TOGCRY) & 0x1);
+
+ if (dir == TD_DIR_IN) {
+ clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
+ clear_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
+ }
+ free_dmem(imx21, xbufaddr);
+
+ urb->error_count = 0;
+ if (!(urb->transfer_flags & URB_SHORT_NOT_OK)
+ && (cc == TD_DATAUNDERRUN))
+ cc = TD_CC_NOERROR;
+
+ if (cc != 0)
+ dev_vdbg(imx21->dev, "cc is 0x%x\n", cc);
+
+ etd_done = (cc_to_error[cc] != 0); /* stop if error */
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ switch (urb_priv->state) {
+ case US_CTRL_SETUP:
+ if (urb->transfer_buffer_length > 0)
+ urb_priv->state = US_CTRL_DATA;
+ else
+ urb_priv->state = US_CTRL_ACK;
+ break;
+ case US_CTRL_DATA:
+ urb->actual_length += bytes_xfrd;
+ urb_priv->state = US_CTRL_ACK;
+ break;
+ case US_CTRL_ACK:
+ etd_done = 1;
+ break;
+ default:
+ dev_err(imx21->dev,
+ "Invalid pipe state %d\n", urb_priv->state);
+ etd_done = 1;
+ break;
+ }
+ break;
+
+ case PIPE_BULK:
+ urb->actual_length += bytes_xfrd;
+ if ((urb_priv->state == US_BULK)
+ && (urb->transfer_flags & URB_ZERO_PACKET)
+ && urb->transfer_buffer_length > 0
+ && ((urb->transfer_buffer_length %
+ usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe))) == 0)) {
+ /* need a 0-packet */
+ urb_priv->state = US_BULK0;
+ } else {
+ etd_done = 1;
+ }
+ break;
+
+ case PIPE_INTERRUPT:
+ urb->actual_length += bytes_xfrd;
+ etd_done = 1;
+ break;
+ }
+
+ if (!etd_done) {
+ dev_vdbg(imx21->dev, "next state=%d\n", urb_priv->state);
+ schedule_nonisoc_etd(imx21, urb);
+ } else {
+ struct usb_host_endpoint *ep = urb->ep;
+
+ urb_done(hcd, urb, cc_to_error[cc]);
+ etd->urb = NULL;
+
+ if (!list_empty(&ep->urb_list)) {
+ urb = list_first_entry(&ep->urb_list,
+ struct urb, urb_list);
+ dev_vdbg(imx21->dev, "next URB %p\n", urb);
+ schedule_nonisoc_etd(imx21, urb);
+ }
+ }
+}
+
+static struct ep_priv *alloc_ep(void)
+{
+ int i;
+ struct ep_priv *ep_priv;
+
+ ep_priv = kzalloc(sizeof(struct ep_priv), GFP_ATOMIC);
+ if (!ep_priv)
+ return NULL;
+
+ for (i = 0; i < NUM_ISO_ETDS; ++i)
+ ep_priv->etd[i] = -1;
+
+ return ep_priv;
+}
+
+static int imx21_hc_urb_enqueue(struct usb_hcd *hcd,
+ struct urb *urb, gfp_t mem_flags)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ struct usb_host_endpoint *ep = urb->ep;
+ struct urb_priv *urb_priv;
+ struct ep_priv *ep_priv;
+ struct etd_priv *etd;
+ int ret;
+ unsigned long flags;
+ int new_ep = 0;
+
+ dev_vdbg(imx21->dev,
+ "enqueue urb=%p ep=%p len=%d "
+ "buffer=%p dma=%08X setupBuf=%p setupDma=%08X\n",
+ urb, ep,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma,
+ urb->setup_packet, urb->setup_dma);
+
+ if (usb_pipeisoc(urb->pipe))
+ return imx21_hc_urb_enqueue_isoc(hcd, ep, urb, mem_flags);
+
+ urb_priv = kzalloc(sizeof(struct urb_priv), mem_flags);
+ if (!urb_priv)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&imx21->lock, flags);
+
+ ep_priv = ep->hcpriv;
+ if (ep_priv == NULL) {
+ ep_priv = alloc_ep();
+ if (!ep_priv) {
+ ret = -ENOMEM;
+ goto failed_alloc_ep;
+ }
+ ep->hcpriv = ep_priv;
+ ep_priv->ep = ep;
+ new_ep = 1;
+ }
+
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto failed_link;
+
+ urb->status = -EINPROGRESS;
+ urb->actual_length = 0;
+ urb->error_count = 0;
+ urb->hcpriv = urb_priv;
+ urb_priv->ep = ep;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ urb_priv->state = US_CTRL_SETUP;
+ break;
+ case PIPE_BULK:
+ urb_priv->state = US_BULK;
+ break;
+ }
+
+ debug_urb_submitted(imx21, urb);
+ if (ep_priv->etd[0] < 0) {
+ if (ep_priv->waiting_etd) {
+ dev_dbg(imx21->dev,
+ "no ETD available already queued %p\n",
+ ep_priv);
+ debug_urb_queued_for_etd(imx21, urb);
+ goto out;
+ }
+ ep_priv->etd[0] = alloc_etd(imx21);
+ if (ep_priv->etd[0] < 0) {
+ dev_dbg(imx21->dev,
+ "no ETD available queueing %p\n", ep_priv);
+ debug_urb_queued_for_etd(imx21, urb);
+ list_add_tail(&ep_priv->queue, &imx21->queue_for_etd);
+ ep_priv->waiting_etd = 1;
+ goto out;
+ }
+ }
+
+ /* Schedule if no URB already active for this endpoint */
+ etd = &imx21->etd[ep_priv->etd[0]];
+ if (etd->urb == NULL) {
+ DEBUG_LOG_FRAME(imx21, etd, last_req);
+ schedule_nonisoc_etd(imx21, urb);
+ }
+
+out:
+ spin_unlock_irqrestore(&imx21->lock, flags);
+ return 0;
+
+failed_link:
+failed_alloc_ep:
+ spin_unlock_irqrestore(&imx21->lock, flags);
+ kfree(urb_priv);
+ return ret;
+}
+
+static int imx21_hc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ unsigned long flags;
+ struct usb_host_endpoint *ep;
+ struct ep_priv *ep_priv;
+ struct urb_priv *urb_priv = urb->hcpriv;
+ int ret = -EINVAL;
+
+ dev_vdbg(imx21->dev, "dequeue urb=%p iso=%d status=%d\n",
+ urb, usb_pipeisoc(urb->pipe), status);
+
+ spin_lock_irqsave(&imx21->lock, flags);
+
+ ret = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (ret)
+ goto fail;
+ ep = urb_priv->ep;
+ ep_priv = ep->hcpriv;
+
+ debug_urb_unlinked(imx21, urb);
+
+ if (usb_pipeisoc(urb->pipe)) {
+ dequeue_isoc_urb(imx21, urb, ep_priv);
+ schedule_isoc_etds(hcd, ep);
+ } else if (urb_priv->active) {
+ int etd_num = ep_priv->etd[0];
+ if (etd_num != -1) {
+ disactivate_etd(imx21, etd_num);
+ free_dmem(imx21, etd_readl(imx21, etd_num, 1) & 0xffff);
+ imx21->etd[etd_num].urb = NULL;
+ }
+ }
+
+ urb_done(hcd, urb, status);
+
+ spin_unlock_irqrestore(&imx21->lock, flags);
+ return 0;
+
+fail:
+ spin_unlock_irqrestore(&imx21->lock, flags);
+ return ret;
+}
+
+/* =========================================== */
+/* Interrupt dispatch */
+/* =========================================== */
+
+static void process_etds(struct usb_hcd *hcd, struct imx21 *imx21, int sof)
+{
+ int etd_num;
+ int enable_sof_int = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&imx21->lock, flags);
+
+ for (etd_num = 0; etd_num < USB_NUM_ETD; etd_num++) {
+ u32 etd_mask = 1 << etd_num;
+ u32 enabled = readl(imx21->regs + USBH_ETDENSET) & etd_mask;
+ u32 done = readl(imx21->regs + USBH_ETDDONESTAT) & etd_mask;
+ struct etd_priv *etd = &imx21->etd[etd_num];
+
+
+ if (done) {
+ DEBUG_LOG_FRAME(imx21, etd, last_int);
+ } else {
+/*
+ * Kludge warning!
+ *
+ * When multiple transfers are using the bus we sometimes get into a state
+ * where the transfer has completed (the CC field of the ETD is != 0x0F),
+ * the ETD has self disabled but the ETDDONESTAT flag is not set
+ * (and hence no interrupt occurs).
+ * This causes the transfer in question to hang.
+ * The kludge below checks for this condition at each SOF and processes any
+ * blocked ETDs (after an arbitary 10 frame wait)
+ *
+ * With a single active transfer the usbtest test suite will run for days
+ * without the kludge.
+ * With other bus activity (eg mass storage) even just test1 will hang without
+ * the kludge.
+ */
+ u32 dword0;
+ int cc;
+
+ if (etd->active_count && !enabled) /* suspicious... */
+ enable_sof_int = 1;
+
+ if (!sof || enabled || !etd->active_count)
+ continue;
+
+ cc = etd_readl(imx21, etd_num, 2) >> DW2_COMPCODE;
+ if (cc == TD_NOTACCESSED)
+ continue;
+
+ if (++etd->active_count < 10)
+ continue;
+
+ dword0 = etd_readl(imx21, etd_num, 0);
+ dev_dbg(imx21->dev,
+ "unblock ETD %d dev=0x%X ep=0x%X cc=0x%02X!\n",
+ etd_num, dword0 & 0x7F,
+ (dword0 >> DW0_ENDPNT) & 0x0F,
+ cc);
+
+#ifdef DEBUG
+ dev_dbg(imx21->dev,
+ "frame: act=%d disact=%d"
+ " int=%d req=%d cur=%d\n",
+ etd->activated_frame,
+ etd->disactivated_frame,
+ etd->last_int_frame,
+ etd->last_req_frame,
+ readl(imx21->regs + USBH_FRMNUB));
+ imx21->debug_unblocks++;
+#endif
+ etd->active_count = 0;
+/* End of kludge */
+ }
+
+ if (etd->ep == NULL || etd->urb == NULL) {
+ dev_dbg(imx21->dev,
+ "Interrupt for unexpected etd %d"
+ " ep=%p urb=%p\n",
+ etd_num, etd->ep, etd->urb);
+ disactivate_etd(imx21, etd_num);
+ continue;
+ }
+
+ if (usb_pipeisoc(etd->urb->pipe))
+ isoc_etd_done(hcd, etd->urb, etd_num);
+ else
+ nonisoc_etd_done(hcd, etd->urb, etd_num);
+ }
+
+ /* only enable SOF interrupt if it may be needed for the kludge */
+ if (enable_sof_int)
+ set_register_bits(imx21, USBH_SYSIEN, USBH_SYSIEN_SOFINT);
+ else
+ clear_register_bits(imx21, USBH_SYSIEN, USBH_SYSIEN_SOFINT);
+
+
+ spin_unlock_irqrestore(&imx21->lock, flags);
+}
+
+static irqreturn_t imx21_irq(struct usb_hcd *hcd)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ u32 ints = readl(imx21->regs + USBH_SYSISR);
+
+ if (ints & USBH_SYSIEN_HERRINT)
+ dev_dbg(imx21->dev, "Scheduling error\n");
+
+ if (ints & USBH_SYSIEN_SORINT)
+ dev_dbg(imx21->dev, "Scheduling overrun\n");
+
+ if (ints & (USBH_SYSISR_DONEINT | USBH_SYSISR_SOFINT))
+ process_etds(hcd, imx21, ints & USBH_SYSISR_SOFINT);
+
+ writel(ints, imx21->regs + USBH_SYSISR);
+ return IRQ_HANDLED;
+}
+
+static void imx21_hc_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ unsigned long flags;
+ struct ep_priv *ep_priv;
+ int i;
+
+ if (ep == NULL)
+ return;
+
+ spin_lock_irqsave(&imx21->lock, flags);
+ ep_priv = ep->hcpriv;
+ dev_vdbg(imx21->dev, "disable ep=%p, ep->hcpriv=%p\n", ep, ep_priv);
+
+ if (!list_empty(&ep->urb_list))
+ dev_dbg(imx21->dev, "ep's URB list is not empty\n");
+
+ if (ep_priv != NULL) {
+ for (i = 0; i < NUM_ISO_ETDS; i++) {
+ if (ep_priv->etd[i] > -1)
+ dev_dbg(imx21->dev, "free etd %d for disable\n",
+ ep_priv->etd[i]);
+
+ free_etd(imx21, ep_priv->etd[i]);
+ }
+ kfree(ep_priv);
+ ep->hcpriv = NULL;
+ }
+
+ for (i = 0; i < USB_NUM_ETD; i++) {
+ if (imx21->etd[i].alloc && imx21->etd[i].ep == ep) {
+ dev_err(imx21->dev,
+ "Active etd %d for disabled ep=%p!\n", i, ep);
+ free_etd(imx21, i);
+ }
+ }
+ free_epdmem(imx21, ep);
+ spin_unlock_irqrestore(&imx21->lock, flags);
+}
+
+/* =========================================== */
+/* Hub handling */
+/* =========================================== */
+
+static int get_hub_descriptor(struct usb_hcd *hcd,
+ struct usb_hub_descriptor *desc)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ desc->bDescriptorType = 0x29; /* HUB descriptor */
+ desc->bHubContrCurrent = 0;
+
+ desc->bNbrPorts = readl(imx21->regs + USBH_ROOTHUBA)
+ & USBH_ROOTHUBA_NDNSTMPRT_MASK;
+ desc->bDescLength = 9;
+ desc->bPwrOn2PwrGood = 0;
+ desc->wHubCharacteristics = (__force __u16) cpu_to_le16(
+ 0x0002 | /* No power switching */
+ 0x0010 | /* No over current protection */
+ 0);
+
+ desc->bitmap[0] = 1 << 1;
+ desc->bitmap[1] = ~0;
+ return 0;
+}
+
+static int imx21_hc_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ int ports;
+ int changed = 0;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&imx21->lock, flags);
+ ports = readl(imx21->regs + USBH_ROOTHUBA)
+ & USBH_ROOTHUBA_NDNSTMPRT_MASK;
+ if (ports > 7) {
+ ports = 7;
+ dev_err(imx21->dev, "ports %d > 7\n", ports);
+ }
+ for (i = 0; i < ports; i++) {
+ if (readl(imx21->regs + USBH_PORTSTAT(i)) &
+ (USBH_PORTSTAT_CONNECTSC |
+ USBH_PORTSTAT_PRTENBLSC |
+ USBH_PORTSTAT_PRTSTATSC |
+ USBH_PORTSTAT_OVRCURIC |
+ USBH_PORTSTAT_PRTRSTSC)) {
+
+ changed = 1;
+ buf[0] |= 1 << (i + 1);
+ }
+ }
+ spin_unlock_irqrestore(&imx21->lock, flags);
+
+ if (changed)
+ dev_info(imx21->dev, "Hub status changed\n");
+ return changed;
+}
+
+static int imx21_hc_hub_control(struct usb_hcd *hcd,
+ u16 typeReq,
+ u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ int rc = 0;
+ u32 status_write = 0;
+
+ switch (typeReq) {
+ case ClearHubFeature:
+ dev_dbg(imx21->dev, "ClearHubFeature\n");
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ dev_dbg(imx21->dev, " OVER_CURRENT\n");
+ break;
+ case C_HUB_LOCAL_POWER:
+ dev_dbg(imx21->dev, " LOCAL_POWER\n");
+ break;
+ default:
+ dev_dbg(imx21->dev, " unknown\n");
+ rc = -EINVAL;
+ break;
+ }
+ break;
+
+ case ClearPortFeature:
+ dev_dbg(imx21->dev, "ClearPortFeature\n");
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ dev_dbg(imx21->dev, " ENABLE\n");
+ status_write = USBH_PORTSTAT_CURCONST;
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ dev_dbg(imx21->dev, " SUSPEND\n");
+ status_write = USBH_PORTSTAT_PRTOVRCURI;
+ break;
+ case USB_PORT_FEAT_POWER:
+ dev_dbg(imx21->dev, " POWER\n");
+ status_write = USBH_PORTSTAT_LSDEVCON;
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ dev_dbg(imx21->dev, " C_ENABLE\n");
+ status_write = USBH_PORTSTAT_PRTENBLSC;
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ dev_dbg(imx21->dev, " C_SUSPEND\n");
+ status_write = USBH_PORTSTAT_PRTSTATSC;
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ dev_dbg(imx21->dev, " C_CONNECTION\n");
+ status_write = USBH_PORTSTAT_CONNECTSC;
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ dev_dbg(imx21->dev, " C_OVER_CURRENT\n");
+ status_write = USBH_PORTSTAT_OVRCURIC;
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ dev_dbg(imx21->dev, " C_RESET\n");
+ status_write = USBH_PORTSTAT_PRTRSTSC;
+ break;
+ default:
+ dev_dbg(imx21->dev, " unknown\n");
+ rc = -EINVAL;
+ break;
+ }
+
+ break;
+
+ case GetHubDescriptor:
+ dev_dbg(imx21->dev, "GetHubDescriptor\n");
+ rc = get_hub_descriptor(hcd, (void *)buf);
+ break;
+
+ case GetHubStatus:
+ dev_dbg(imx21->dev, " GetHubStatus\n");
+ *(__le32 *) buf = 0;
+ break;
+
+ case GetPortStatus:
+ dev_dbg(imx21->dev, "GetPortStatus: port: %d, 0x%x\n",
+ wIndex, USBH_PORTSTAT(wIndex - 1));
+ *(__le32 *) buf = readl(imx21->regs +
+ USBH_PORTSTAT(wIndex - 1));
+ break;
+
+ case SetHubFeature:
+ dev_dbg(imx21->dev, "SetHubFeature\n");
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ dev_dbg(imx21->dev, " OVER_CURRENT\n");
+ break;
+
+ case C_HUB_LOCAL_POWER:
+ dev_dbg(imx21->dev, " LOCAL_POWER\n");
+ break;
+ default:
+ dev_dbg(imx21->dev, " unknown\n");
+ rc = -EINVAL;
+ break;
+ }
+
+ break;
+
+ case SetPortFeature:
+ dev_dbg(imx21->dev, "SetPortFeature\n");
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ dev_dbg(imx21->dev, " SUSPEND\n");
+ status_write = USBH_PORTSTAT_PRTSUSPST;
+ break;
+ case USB_PORT_FEAT_POWER:
+ dev_dbg(imx21->dev, " POWER\n");
+ status_write = USBH_PORTSTAT_PRTPWRST;
+ break;
+ case USB_PORT_FEAT_RESET:
+ dev_dbg(imx21->dev, " RESET\n");
+ status_write = USBH_PORTSTAT_PRTRSTST;
+ break;
+ default:
+ dev_dbg(imx21->dev, " unknown\n");
+ rc = -EINVAL;
+ break;
+ }
+ break;
+
+ default:
+ dev_dbg(imx21->dev, " unknown\n");
+ rc = -EINVAL;
+ break;
+ }
+
+ if (status_write)
+ writel(status_write, imx21->regs + USBH_PORTSTAT(wIndex - 1));
+ return rc;
+}
+
+/* =========================================== */
+/* Host controller management */
+/* =========================================== */
+
+static int imx21_hc_reset(struct usb_hcd *hcd)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ unsigned long timeout;
+ unsigned long flags;
+
+ spin_lock_irqsave(&imx21->lock, flags);
+
+ /* Reset the Host controler modules */
+ writel(USBOTG_RST_RSTCTRL | USBOTG_RST_RSTRH |
+ USBOTG_RST_RSTHSIE | USBOTG_RST_RSTHC,
+ imx21->regs + USBOTG_RST_CTRL);
+
+ /* Wait for reset to finish */
+ timeout = jiffies + HZ;
+ while (readl(imx21->regs + USBOTG_RST_CTRL) != 0) {
+ if (time_after(jiffies, timeout)) {
+ spin_unlock_irqrestore(&imx21->lock, flags);
+ dev_err(imx21->dev, "timeout waiting for reset\n");
+ return -ETIMEDOUT;
+ }
+ spin_unlock_irq(&imx21->lock);
+ schedule_timeout(1);
+ spin_lock_irq(&imx21->lock);
+ }
+ spin_unlock_irqrestore(&imx21->lock, flags);
+ return 0;
+}
+
+static int __devinit imx21_hc_start(struct usb_hcd *hcd)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ unsigned long flags;
+ int i, j;
+ u32 hw_mode = USBOTG_HWMODE_CRECFG_HOST;
+ u32 usb_control = 0;
+
+ hw_mode |= ((imx21->pdata->host_xcvr << USBOTG_HWMODE_HOSTXCVR_SHIFT) &
+ USBOTG_HWMODE_HOSTXCVR_MASK);
+ hw_mode |= ((imx21->pdata->otg_xcvr << USBOTG_HWMODE_OTGXCVR_SHIFT) &
+ USBOTG_HWMODE_OTGXCVR_MASK);
+
+ if (imx21->pdata->host1_txenoe)
+ usb_control |= USBCTRL_HOST1_TXEN_OE;
+
+ if (!imx21->pdata->host1_xcverless)
+ usb_control |= USBCTRL_HOST1_BYP_TLL;
+
+ if (imx21->pdata->otg_ext_xcvr)
+ usb_control |= USBCTRL_OTC_RCV_RXDP;
+
+
+ spin_lock_irqsave(&imx21->lock, flags);
+
+ writel((USBOTG_CLK_CTRL_HST | USBOTG_CLK_CTRL_MAIN),
+ imx21->regs + USBOTG_CLK_CTRL);
+ writel(hw_mode, imx21->regs + USBOTG_HWMODE);
+ writel(usb_control, imx21->regs + USBCTRL);
+ writel(USB_MISCCONTROL_SKPRTRY | USB_MISCCONTROL_ARBMODE,
+ imx21->regs + USB_MISCCONTROL);
+
+ /* Clear the ETDs */
+ for (i = 0; i < USB_NUM_ETD; i++)
+ for (j = 0; j < 4; j++)
+ etd_writel(imx21, i, j, 0);
+
+ /* Take the HC out of reset */
+ writel(USBH_HOST_CTRL_HCUSBSTE_OPERATIONAL | USBH_HOST_CTRL_CTLBLKSR_1,
+ imx21->regs + USBH_HOST_CTRL);
+
+ /* Enable ports */
+ if (imx21->pdata->enable_otg_host)
+ writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST,
+ imx21->regs + USBH_PORTSTAT(0));
+
+ if (imx21->pdata->enable_host1)
+ writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST,
+ imx21->regs + USBH_PORTSTAT(1));
+
+ if (imx21->pdata->enable_host2)
+ writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST,
+ imx21->regs + USBH_PORTSTAT(2));
+
+
+ hcd->state = HC_STATE_RUNNING;
+
+ /* Enable host controller interrupts */
+ set_register_bits(imx21, USBH_SYSIEN,
+ USBH_SYSIEN_HERRINT |
+ USBH_SYSIEN_DONEINT | USBH_SYSIEN_SORINT);
+ set_register_bits(imx21, USBOTG_CINT_STEN, USBOTG_HCINT);
+
+ spin_unlock_irqrestore(&imx21->lock, flags);
+
+ return 0;
+}
+
+static void imx21_hc_stop(struct usb_hcd *hcd)
+{
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ unsigned long flags;
+
+ spin_lock_irqsave(&imx21->lock, flags);
+
+ writel(0, imx21->regs + USBH_SYSIEN);
+ clear_register_bits(imx21, USBOTG_CINT_STEN, USBOTG_HCINT);
+ clear_register_bits(imx21, USBOTG_CLK_CTRL_HST | USBOTG_CLK_CTRL_MAIN,
+ USBOTG_CLK_CTRL);
+ spin_unlock_irqrestore(&imx21->lock, flags);
+}
+
+/* =========================================== */
+/* Driver glue */
+/* =========================================== */
+
+static struct hc_driver imx21_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "IMX21 USB Host Controller",
+ .hcd_priv_size = sizeof(struct imx21),
+
+ .flags = HCD_USB11,
+ .irq = imx21_irq,
+
+ .reset = imx21_hc_reset,
+ .start = imx21_hc_start,
+ .stop = imx21_hc_stop,
+
+ /* I/O requests */
+ .urb_enqueue = imx21_hc_urb_enqueue,
+ .urb_dequeue = imx21_hc_urb_dequeue,
+ .endpoint_disable = imx21_hc_endpoint_disable,
+
+ /* scheduling support */
+ .get_frame_number = imx21_hc_get_frame,
+
+ /* Root hub support */
+ .hub_status_data = imx21_hc_hub_status_data,
+ .hub_control = imx21_hc_hub_control,
+
+};
+
+static struct mx21_usbh_platform_data default_pdata = {
+ .host_xcvr = MX21_USBXCVR_TXDIF_RXDIF,
+ .otg_xcvr = MX21_USBXCVR_TXDIF_RXDIF,
+ .enable_host1 = 1,
+ .enable_host2 = 1,
+ .enable_otg_host = 1,
+
+};
+
+static int imx21_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct imx21 *imx21 = hcd_to_imx21(hcd);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ remove_debug_files(imx21);
+ usb_remove_hcd(hcd);
+
+ if (res != NULL) {
+ clk_disable(imx21->clk);
+ clk_put(imx21->clk);
+ iounmap(imx21->regs);
+ release_mem_region(res->start, resource_size(res));
+ }
+
+ kfree(hcd);
+ return 0;
+}
+
+
+static int imx21_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct imx21 *imx21;
+ struct resource *res;
+ int ret;
+ int irq;
+
+ printk(KERN_INFO "%s\n", imx21_hc_driver.product_desc);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -ENXIO;
+
+ hcd = usb_create_hcd(&imx21_hc_driver,
+ &pdev->dev, dev_name(&pdev->dev));
+ if (hcd == NULL) {
+ dev_err(&pdev->dev, "Cannot create hcd (%s)\n",
+ dev_name(&pdev->dev));
+ return -ENOMEM;
+ }
+
+ imx21 = hcd_to_imx21(hcd);
+ imx21->dev = &pdev->dev;
+ imx21->pdata = pdev->dev.platform_data;
+ if (!imx21->pdata)
+ imx21->pdata = &default_pdata;
+
+ spin_lock_init(&imx21->lock);
+ INIT_LIST_HEAD(&imx21->dmem_list);
+ INIT_LIST_HEAD(&imx21->queue_for_etd);
+ INIT_LIST_HEAD(&imx21->queue_for_dmem);
+ create_debug_files(imx21);
+
+ res = request_mem_region(res->start, resource_size(res), hcd_name);
+ if (!res) {
+ ret = -EBUSY;
+ goto failed_request_mem;
+ }
+
+ imx21->regs = ioremap(res->start, resource_size(res));
+ if (imx21->regs == NULL) {
+ dev_err(imx21->dev, "Cannot map registers\n");
+ ret = -ENOMEM;
+ goto failed_ioremap;
+ }
+
+ /* Enable clocks source */
+ imx21->clk = clk_get(imx21->dev, NULL);
+ if (IS_ERR(imx21->clk)) {
+ dev_err(imx21->dev, "no clock found\n");
+ ret = PTR_ERR(imx21->clk);
+ goto failed_clock_get;
+ }
+
+ ret = clk_set_rate(imx21->clk, clk_round_rate(imx21->clk, 48000000));
+ if (ret)
+ goto failed_clock_set;
+ ret = clk_enable(imx21->clk);
+ if (ret)
+ goto failed_clock_enable;
+
+ dev_info(imx21->dev, "Hardware HC revision: 0x%02X\n",
+ (readl(imx21->regs + USBOTG_HWMODE) >> 16) & 0xFF);
+
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ if (ret != 0) {
+ dev_err(imx21->dev, "usb_add_hcd() returned %d\n", ret);
+ goto failed_add_hcd;
+ }
+
+ return 0;
+
+failed_add_hcd:
+ clk_disable(imx21->clk);
+failed_clock_enable:
+failed_clock_set:
+ clk_put(imx21->clk);
+failed_clock_get:
+ iounmap(imx21->regs);
+failed_ioremap:
+ release_mem_region(res->start, res->end - res->start);
+failed_request_mem:
+ remove_debug_files(imx21);
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+static struct platform_driver imx21_hcd_driver = {
+ .driver = {
+ .name = (char *)hcd_name,
+ },
+ .probe = imx21_probe,
+ .remove = imx21_remove,
+ .suspend = NULL,
+ .resume = NULL,
+};
+
+static int __init imx21_hcd_init(void)
+{
+ return platform_driver_register(&imx21_hcd_driver);
+}
+
+static void __exit imx21_hcd_cleanup(void)
+{
+ platform_driver_unregister(&imx21_hcd_driver);
+}
+
+module_init(imx21_hcd_init);
+module_exit(imx21_hcd_cleanup);
+
+MODULE_DESCRIPTION("i.MX21 USB Host controller");
+MODULE_AUTHOR("Martin Fuzzey");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx21-hcd");
diff --git a/drivers/usb/host/imx21-hcd.h b/drivers/usb/host/imx21-hcd.h
new file mode 100644
index 000000000000..1b0d913780a5
--- /dev/null
+++ b/drivers/usb/host/imx21-hcd.h
@@ -0,0 +1,436 @@
+/*
+ * Macros and prototypes for i.MX21
+ *
+ * Copyright (C) 2006 Loping Dog Embedded Systems
+ * Copyright (C) 2009 Martin Fuzzey
+ * Originally written by Jay Monkman <jtm@lopingdog.com>
+ * Ported to 2.6.30, debugged and enhanced by Martin Fuzzey
+ *
+ * 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 __LINUX_IMX21_HCD_H__
+#define __LINUX_IMX21_HCD_H__
+
+#include <mach/mx21-usbhost.h>
+
+#define NUM_ISO_ETDS 2
+#define USB_NUM_ETD 32
+#define DMEM_SIZE 4096
+
+/* Register definitions */
+#define USBOTG_HWMODE 0x00
+#define USBOTG_HWMODE_ANASDBEN (1 << 14)
+#define USBOTG_HWMODE_OTGXCVR_SHIFT 6
+#define USBOTG_HWMODE_OTGXCVR_MASK (3 << 6)
+#define USBOTG_HWMODE_OTGXCVR_TD_RD (0 << 6)
+#define USBOTG_HWMODE_OTGXCVR_TS_RD (2 << 6)
+#define USBOTG_HWMODE_OTGXCVR_TD_RS (1 << 6)
+#define USBOTG_HWMODE_OTGXCVR_TS_RS (3 << 6)
+#define USBOTG_HWMODE_HOSTXCVR_SHIFT 4
+#define USBOTG_HWMODE_HOSTXCVR_MASK (3 << 4)
+#define USBOTG_HWMODE_HOSTXCVR_TD_RD (0 << 4)
+#define USBOTG_HWMODE_HOSTXCVR_TS_RD (2 << 4)
+#define USBOTG_HWMODE_HOSTXCVR_TD_RS (1 << 4)
+#define USBOTG_HWMODE_HOSTXCVR_TS_RS (3 << 4)
+#define USBOTG_HWMODE_CRECFG_MASK (3 << 0)
+#define USBOTG_HWMODE_CRECFG_HOST (1 << 0)
+#define USBOTG_HWMODE_CRECFG_FUNC (2 << 0)
+#define USBOTG_HWMODE_CRECFG_HNP (3 << 0)
+
+#define USBOTG_CINT_STAT 0x04
+#define USBOTG_CINT_STEN 0x08
+#define USBOTG_ASHNPINT (1 << 5)
+#define USBOTG_ASFCINT (1 << 4)
+#define USBOTG_ASHCINT (1 << 3)
+#define USBOTG_SHNPINT (1 << 2)
+#define USBOTG_FCINT (1 << 1)
+#define USBOTG_HCINT (1 << 0)
+
+#define USBOTG_CLK_CTRL 0x0c
+#define USBOTG_CLK_CTRL_FUNC (1 << 2)
+#define USBOTG_CLK_CTRL_HST (1 << 1)
+#define USBOTG_CLK_CTRL_MAIN (1 << 0)
+
+#define USBOTG_RST_CTRL 0x10
+#define USBOTG_RST_RSTI2C (1 << 15)
+#define USBOTG_RST_RSTCTRL (1 << 5)
+#define USBOTG_RST_RSTFC (1 << 4)
+#define USBOTG_RST_RSTFSKE (1 << 3)
+#define USBOTG_RST_RSTRH (1 << 2)
+#define USBOTG_RST_RSTHSIE (1 << 1)
+#define USBOTG_RST_RSTHC (1 << 0)
+
+#define USBOTG_FRM_INTVL 0x14
+#define USBOTG_FRM_REMAIN 0x18
+#define USBOTG_HNP_CSR 0x1c
+#define USBOTG_HNP_ISR 0x2c
+#define USBOTG_HNP_IEN 0x30
+
+#define USBOTG_I2C_TXCVR_REG(x) (0x100 + (x))
+#define USBOTG_I2C_XCVR_DEVAD 0x118
+#define USBOTG_I2C_SEQ_OP_REG 0x119
+#define USBOTG_I2C_SEQ_RD_STARTAD 0x11a
+#define USBOTG_I2C_OP_CTRL_REG 0x11b
+#define USBOTG_I2C_SCLK_TO_SCK_HPER 0x11e
+#define USBOTG_I2C_MASTER_INT_REG 0x11f
+
+#define USBH_HOST_CTRL 0x80
+#define USBH_HOST_CTRL_HCRESET (1 << 31)
+#define USBH_HOST_CTRL_SCHDOVR(x) ((x) << 16)
+#define USBH_HOST_CTRL_RMTWUEN (1 << 4)
+#define USBH_HOST_CTRL_HCUSBSTE_RESET (0 << 2)
+#define USBH_HOST_CTRL_HCUSBSTE_RESUME (1 << 2)
+#define USBH_HOST_CTRL_HCUSBSTE_OPERATIONAL (2 << 2)
+#define USBH_HOST_CTRL_HCUSBSTE_SUSPEND (3 << 2)
+#define USBH_HOST_CTRL_CTLBLKSR_1 (0 << 0)
+#define USBH_HOST_CTRL_CTLBLKSR_2 (1 << 0)
+#define USBH_HOST_CTRL_CTLBLKSR_3 (2 << 0)
+#define USBH_HOST_CTRL_CTLBLKSR_4 (3 << 0)
+
+#define USBH_SYSISR 0x88
+#define USBH_SYSISR_PSCINT (1 << 6)
+#define USBH_SYSISR_FMOFINT (1 << 5)
+#define USBH_SYSISR_HERRINT (1 << 4)
+#define USBH_SYSISR_RESDETINT (1 << 3)
+#define USBH_SYSISR_SOFINT (1 << 2)
+#define USBH_SYSISR_DONEINT (1 << 1)
+#define USBH_SYSISR_SORINT (1 << 0)
+
+#define USBH_SYSIEN 0x8c
+#define USBH_SYSIEN_PSCINT (1 << 6)
+#define USBH_SYSIEN_FMOFINT (1 << 5)
+#define USBH_SYSIEN_HERRINT (1 << 4)
+#define USBH_SYSIEN_RESDETINT (1 << 3)
+#define USBH_SYSIEN_SOFINT (1 << 2)
+#define USBH_SYSIEN_DONEINT (1 << 1)
+#define USBH_SYSIEN_SORINT (1 << 0)
+
+#define USBH_XBUFSTAT 0x98
+#define USBH_YBUFSTAT 0x9c
+#define USBH_XYINTEN 0xa0
+#define USBH_XFILLSTAT 0xa8
+#define USBH_YFILLSTAT 0xac
+#define USBH_ETDENSET 0xc0
+#define USBH_ETDENCLR 0xc4
+#define USBH_IMMEDINT 0xcc
+#define USBH_ETDDONESTAT 0xd0
+#define USBH_ETDDONEEN 0xd4
+#define USBH_FRMNUB 0xe0
+#define USBH_LSTHRESH 0xe4
+
+#define USBH_ROOTHUBA 0xe8
+#define USBH_ROOTHUBA_PWRTOGOOD_MASK (0xff)
+#define USBH_ROOTHUBA_PWRTOGOOD_SHIFT (24)
+#define USBH_ROOTHUBA_NOOVRCURP (1 << 12)
+#define USBH_ROOTHUBA_OVRCURPM (1 << 11)
+#define USBH_ROOTHUBA_DEVTYPE (1 << 10)
+#define USBH_ROOTHUBA_PWRSWTMD (1 << 9)
+#define USBH_ROOTHUBA_NOPWRSWT (1 << 8)
+#define USBH_ROOTHUBA_NDNSTMPRT_MASK (0xff)
+
+#define USBH_ROOTHUBB 0xec
+#define USBH_ROOTHUBB_PRTPWRCM(x) (1 << ((x) + 16))
+#define USBH_ROOTHUBB_DEVREMOVE(x) (1 << (x))
+
+#define USBH_ROOTSTAT 0xf0
+#define USBH_ROOTSTAT_CLRRMTWUE (1 << 31)
+#define USBH_ROOTSTAT_OVRCURCHG (1 << 17)
+#define USBH_ROOTSTAT_DEVCONWUE (1 << 15)
+#define USBH_ROOTSTAT_OVRCURI (1 << 1)
+#define USBH_ROOTSTAT_LOCPWRS (1 << 0)
+
+#define USBH_PORTSTAT(x) (0xf4 + ((x) * 4))
+#define USBH_PORTSTAT_PRTRSTSC (1 << 20)
+#define USBH_PORTSTAT_OVRCURIC (1 << 19)
+#define USBH_PORTSTAT_PRTSTATSC (1 << 18)
+#define USBH_PORTSTAT_PRTENBLSC (1 << 17)
+#define USBH_PORTSTAT_CONNECTSC (1 << 16)
+#define USBH_PORTSTAT_LSDEVCON (1 << 9)
+#define USBH_PORTSTAT_PRTPWRST (1 << 8)
+#define USBH_PORTSTAT_PRTRSTST (1 << 4)
+#define USBH_PORTSTAT_PRTOVRCURI (1 << 3)
+#define USBH_PORTSTAT_PRTSUSPST (1 << 2)
+#define USBH_PORTSTAT_PRTENABST (1 << 1)
+#define USBH_PORTSTAT_CURCONST (1 << 0)
+
+#define USB_DMAREV 0x800
+#define USB_DMAINTSTAT 0x804
+#define USB_DMAINTSTAT_EPERR (1 << 1)
+#define USB_DMAINTSTAT_ETDERR (1 << 0)
+
+#define USB_DMAINTEN 0x808
+#define USB_DMAINTEN_EPERRINTEN (1 << 1)
+#define USB_DMAINTEN_ETDERRINTEN (1 << 0)
+
+#define USB_ETDDMAERSTAT 0x80c
+#define USB_EPDMAERSTAT 0x810
+#define USB_ETDDMAEN 0x820
+#define USB_EPDMAEN 0x824
+#define USB_ETDDMAXTEN 0x828
+#define USB_EPDMAXTEN 0x82c
+#define USB_ETDDMAENXYT 0x830
+#define USB_EPDMAENXYT 0x834
+#define USB_ETDDMABST4EN 0x838
+#define USB_EPDMABST4EN 0x83c
+
+#define USB_MISCCONTROL 0x840
+#define USB_MISCCONTROL_ISOPREVFRM (1 << 3)
+#define USB_MISCCONTROL_SKPRTRY (1 << 2)
+#define USB_MISCCONTROL_ARBMODE (1 << 1)
+#define USB_MISCCONTROL_FILTCC (1 << 0)
+
+#define USB_ETDDMACHANLCLR 0x848
+#define USB_EPDMACHANLCLR 0x84c
+#define USB_ETDSMSA(x) (0x900 + ((x) * 4))
+#define USB_EPSMSA(x) (0x980 + ((x) * 4))
+#define USB_ETDDMABUFPTR(x) (0xa00 + ((x) * 4))
+#define USB_EPDMABUFPTR(x) (0xa80 + ((x) * 4))
+
+#define USB_ETD_DWORD(x, w) (0x200 + ((x) * 16) + ((w) * 4))
+#define DW0_ADDRESS 0
+#define DW0_ENDPNT 7
+#define DW0_DIRECT 11
+#define DW0_SPEED 13
+#define DW0_FORMAT 14
+#define DW0_MAXPKTSIZ 16
+#define DW0_HALTED 27
+#define DW0_TOGCRY 28
+#define DW0_SNDNAK 30
+
+#define DW1_XBUFSRTAD 0
+#define DW1_YBUFSRTAD 16
+
+#define DW2_RTRYDELAY 0
+#define DW2_POLINTERV 0
+#define DW2_STARTFRM 0
+#define DW2_RELPOLPOS 8
+#define DW2_DIRPID 16
+#define DW2_BUFROUND 18
+#define DW2_DELAYINT 19
+#define DW2_DATATOG 22
+#define DW2_ERRORCNT 24
+#define DW2_COMPCODE 28
+
+#define DW3_TOTBYECNT 0
+#define DW3_PKTLEN0 0
+#define DW3_COMPCODE0 12
+#define DW3_PKTLEN1 16
+#define DW3_BUFSIZE 21
+#define DW3_COMPCODE1 28
+
+#define USBCTRL 0x600
+#define USBCTRL_I2C_WU_INT_STAT (1 << 27)
+#define USBCTRL_OTG_WU_INT_STAT (1 << 26)
+#define USBCTRL_HOST_WU_INT_STAT (1 << 25)
+#define USBCTRL_FNT_WU_INT_STAT (1 << 24)
+#define USBCTRL_I2C_WU_INT_EN (1 << 19)
+#define USBCTRL_OTG_WU_INT_EN (1 << 18)
+#define USBCTRL_HOST_WU_INT_EN (1 << 17)
+#define USBCTRL_FNT_WU_INT_EN (1 << 16)
+#define USBCTRL_OTC_RCV_RXDP (1 << 13)
+#define USBCTRL_HOST1_BYP_TLL (1 << 12)
+#define USBCTRL_OTG_BYP_VAL(x) ((x) << 10)
+#define USBCTRL_HOST1_BYP_VAL(x) ((x) << 8)
+#define USBCTRL_OTG_PWR_MASK (1 << 6)
+#define USBCTRL_HOST1_PWR_MASK (1 << 5)
+#define USBCTRL_HOST2_PWR_MASK (1 << 4)
+#define USBCTRL_USB_BYP (1 << 2)
+#define USBCTRL_HOST1_TXEN_OE (1 << 1)
+
+
+/* Values in TD blocks */
+#define TD_DIR_SETUP 0
+#define TD_DIR_OUT 1
+#define TD_DIR_IN 2
+#define TD_FORMAT_CONTROL 0
+#define TD_FORMAT_ISO 1
+#define TD_FORMAT_BULK 2
+#define TD_FORMAT_INT 3
+#define TD_TOGGLE_CARRY 0
+#define TD_TOGGLE_DATA0 2
+#define TD_TOGGLE_DATA1 3
+
+/* control transfer states */
+#define US_CTRL_SETUP 2
+#define US_CTRL_DATA 1
+#define US_CTRL_ACK 0
+
+/* bulk transfer main state and 0-length packet */
+#define US_BULK 1
+#define US_BULK0 0
+
+/*ETD format description*/
+#define IMX_FMT_CTRL 0x0
+#define IMX_FMT_ISO 0x1
+#define IMX_FMT_BULK 0x2
+#define IMX_FMT_INT 0x3
+
+static char fmt_urb_to_etd[4] = {
+/*PIPE_ISOCHRONOUS*/ IMX_FMT_ISO,
+/*PIPE_INTERRUPT*/ IMX_FMT_INT,
+/*PIPE_CONTROL*/ IMX_FMT_CTRL,
+/*PIPE_BULK*/ IMX_FMT_BULK
+};
+
+/* condition (error) CC codes and mapping (OHCI like) */
+
+#define TD_CC_NOERROR 0x00
+#define TD_CC_CRC 0x01
+#define TD_CC_BITSTUFFING 0x02
+#define TD_CC_DATATOGGLEM 0x03
+#define TD_CC_STALL 0x04
+#define TD_DEVNOTRESP 0x05
+#define TD_PIDCHECKFAIL 0x06
+/*#define TD_UNEXPECTEDPID 0x07 - reserved, not active on MX2*/
+#define TD_DATAOVERRUN 0x08
+#define TD_DATAUNDERRUN 0x09
+#define TD_BUFFEROVERRUN 0x0C
+#define TD_BUFFERUNDERRUN 0x0D
+#define TD_SCHEDULEOVERRUN 0x0E
+#define TD_NOTACCESSED 0x0F
+
+static const int cc_to_error[16] = {
+ /* No Error */ 0,
+ /* CRC Error */ -EILSEQ,
+ /* Bit Stuff */ -EPROTO,
+ /* Data Togg */ -EILSEQ,
+ /* Stall */ -EPIPE,
+ /* DevNotResp */ -ETIMEDOUT,
+ /* PIDCheck */ -EPROTO,
+ /* UnExpPID */ -EPROTO,
+ /* DataOver */ -EOVERFLOW,
+ /* DataUnder */ -EREMOTEIO,
+ /* (for hw) */ -EIO,
+ /* (for hw) */ -EIO,
+ /* BufferOver */ -ECOMM,
+ /* BuffUnder */ -ENOSR,
+ /* (for HCD) */ -ENOSPC,
+ /* (for HCD) */ -EALREADY
+};
+
+/* HCD data associated with a usb core URB */
+struct urb_priv {
+ struct urb *urb;
+ struct usb_host_endpoint *ep;
+ int active;
+ int state;
+ struct td *isoc_td;
+ int isoc_remaining;
+ int isoc_status;
+};
+
+/* HCD data associated with a usb core endpoint */
+struct ep_priv {
+ struct usb_host_endpoint *ep;
+ struct list_head td_list;
+ struct list_head queue;
+ int etd[NUM_ISO_ETDS];
+ int waiting_etd;
+};
+
+/* isoc packet */
+struct td {
+ struct list_head list;
+ struct urb *urb;
+ struct usb_host_endpoint *ep;
+ dma_addr_t data;
+ unsigned long buf_addr;
+ int len;
+ int frame;
+ int isoc_index;
+};
+
+/* HCD data associated with a hardware ETD */
+struct etd_priv {
+ struct usb_host_endpoint *ep;
+ struct urb *urb;
+ struct td *td;
+ struct list_head queue;
+ dma_addr_t dma_handle;
+ int alloc;
+ int len;
+ int dmem_size;
+ int dmem_offset;
+ int active_count;
+#ifdef DEBUG
+ int activated_frame;
+ int disactivated_frame;
+ int last_int_frame;
+ int last_req_frame;
+ u32 submitted_dwords[4];
+#endif
+};
+
+/* Hardware data memory info */
+struct imx21_dmem_area {
+ struct usb_host_endpoint *ep;
+ unsigned int offset;
+ unsigned int size;
+ struct list_head list;
+};
+
+#ifdef DEBUG
+struct debug_usage_stats {
+ unsigned int value;
+ unsigned int maximum;
+};
+
+struct debug_stats {
+ unsigned long submitted;
+ unsigned long completed_ok;
+ unsigned long completed_failed;
+ unsigned long unlinked;
+ unsigned long queue_etd;
+ unsigned long queue_dmem;
+};
+
+struct debug_isoc_trace {
+ int schedule_frame;
+ int submit_frame;
+ int request_len;
+ int done_frame;
+ int done_len;
+ int cc;
+ struct td *td;
+};
+#endif
+
+/* HCD data structure */
+struct imx21 {
+ spinlock_t lock;
+ struct device *dev;
+ struct mx21_usbh_platform_data *pdata;
+ struct list_head dmem_list;
+ struct list_head queue_for_etd; /* eps queued due to etd shortage */
+ struct list_head queue_for_dmem; /* etds queued due to dmem shortage */
+ struct etd_priv etd[USB_NUM_ETD];
+ struct clk *clk;
+ void __iomem *regs;
+#ifdef DEBUG
+ struct dentry *debug_root;
+ struct debug_stats nonisoc_stats;
+ struct debug_stats isoc_stats;
+ struct debug_usage_stats etd_usage;
+ struct debug_usage_stats dmem_usage;
+ struct debug_isoc_trace isoc_trace[20];
+ struct debug_isoc_trace isoc_trace_failed[20];
+ unsigned long debug_unblocks;
+ int isoc_trace_index;
+ int isoc_trace_index_failed;
+#endif
+};
+
+#endif
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index 73352f3739b5..217fb5170200 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -1257,7 +1257,7 @@ static int isp1362_urb_enqueue(struct usb_hcd *hcd,
/* avoid all allocations within spinlocks: request or endpoint */
if (!hep->hcpriv) {
- ep = kcalloc(1, sizeof *ep, mem_flags);
+ ep = kzalloc(sizeof *ep, mem_flags);
if (!ep)
return -ENOMEM;
}
@@ -2270,10 +2270,10 @@ static int isp1362_mem_config(struct usb_hcd *hcd)
dev_info(hcd->self.controller, "ISP1362 Memory usage:\n");
dev_info(hcd->self.controller, " ISTL: 2 * %4d: %4d @ $%04x:$%04x\n",
istl_size / 2, istl_size, 0, istl_size / 2);
- dev_info(hcd->self.controller, " INTL: %4d * (%3lu+8): %4d @ $%04x\n",
+ dev_info(hcd->self.controller, " INTL: %4d * (%3zu+8): %4d @ $%04x\n",
ISP1362_INTL_BUFFERS, intl_blksize - PTD_HEADER_SIZE,
intl_size, istl_size);
- dev_info(hcd->self.controller, " ATL : %4d * (%3lu+8): %4d @ $%04x\n",
+ dev_info(hcd->self.controller, " ATL : %4d * (%3zu+8): %4d @ $%04x\n",
atl_buffers, atl_blksize - PTD_HEADER_SIZE,
atl_size, istl_size + intl_size);
dev_info(hcd->self.controller, " USED/FREE: %4d %4d\n", total,
@@ -2697,6 +2697,8 @@ static int __init isp1362_probe(struct platform_device *pdev)
void __iomem *data_reg;
int irq;
int retval = 0;
+ struct resource *irq_res;
+ unsigned int irq_flags = 0;
/* basic sanity checks first. board-specific init logic should
* have initialized this the three resources and probably board
@@ -2710,30 +2712,18 @@ static int __init isp1362_probe(struct platform_device *pdev)
data = platform_get_resource(pdev, IORESOURCE_MEM, 0);
addr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- irq = platform_get_irq(pdev, 0);
- if (!addr || !data || irq < 0) {
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!addr || !data || !irq_res) {
retval = -ENODEV;
goto err1;
}
+ irq = irq_res->start;
-#ifdef CONFIG_USB_HCD_DMA
- if (pdev->dev.dma_mask) {
- struct resource *dma_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-
- if (!dma_res) {
- retval = -ENODEV;
- goto err1;
- }
- isp1362_hcd->data_dma = dma_res->start;
- isp1362_hcd->max_dma_size = resource_len(dma_res);
- }
-#else
if (pdev->dev.dma_mask) {
DBG(1, "won't do DMA");
retval = -ENODEV;
goto err1;
}
-#endif
if (!request_mem_region(addr->start, resource_len(addr), hcd_name)) {
retval = -EBUSY;
@@ -2781,12 +2771,16 @@ static int __init isp1362_probe(struct platform_device *pdev)
}
#endif
-#ifdef CONFIG_ARM
- if (isp1362_hcd->board)
- set_irq_type(irq, isp1362_hcd->board->int_act_high ? IRQT_RISING : IRQT_FALLING);
-#endif
+ if (irq_res->flags & IORESOURCE_IRQ_HIGHEDGE)
+ irq_flags |= IRQF_TRIGGER_RISING;
+ if (irq_res->flags & IORESOURCE_IRQ_LOWEDGE)
+ irq_flags |= IRQF_TRIGGER_FALLING;
+ if (irq_res->flags & IORESOURCE_IRQ_HIGHLEVEL)
+ irq_flags |= IRQF_TRIGGER_HIGH;
+ if (irq_res->flags & IORESOURCE_IRQ_LOWLEVEL)
+ irq_flags |= IRQF_TRIGGER_LOW;
- retval = usb_add_hcd(hcd, irq, IRQF_TRIGGER_LOW | IRQF_DISABLED | IRQF_SHARED);
+ retval = usb_add_hcd(hcd, irq, irq_flags | IRQF_DISABLED | IRQF_SHARED);
if (retval != 0)
goto err6;
pr_info("%s, irq %d\n", hcd->product_desc, irq);
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index 9600a58299db..9f01293600b0 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -17,7 +17,9 @@
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
+#include <linux/mm.h>
#include <asm/unaligned.h>
+#include <asm/cacheflush.h>
#include "../core/hcd.h"
#include "isp1760-hcd.h"
@@ -904,6 +906,14 @@ __acquires(priv->lock)
status = 0;
}
+ if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) {
+ void *ptr;
+ for (ptr = urb->transfer_buffer;
+ ptr < urb->transfer_buffer + urb->transfer_buffer_length;
+ ptr += PAGE_SIZE)
+ flush_dcache_page(virt_to_page(ptr));
+ }
+
/* complete() can reenter this HCD */
usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
spin_unlock(&priv->lock);
@@ -1039,12 +1049,12 @@ static void do_atl_int(struct usb_hcd *usb_hcd)
if (!nakcount && (dw3 & DW3_QTD_ACTIVE)) {
u32 buffstatus;
- /* XXX
+ /*
* NAKs are handled in HW by the chip. Usually if the
* device is not able to send data fast enough.
- * This did not trigger for a long time now.
+ * This happens mostly on slower hardware.
*/
- printk(KERN_ERR "Reloading ptd %p/%p... qh %p readed: "
+ printk(KERN_NOTICE "Reloading ptd %p/%p... qh %p read: "
"%d of %zu done: %08x cur: %08x\n", qtd,
urb, qh, PTD_XFERRED_LENGTH(dw3),
qtd->length, done_map,
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index 1c9f977a5c9c..4293cfd28d61 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -109,7 +109,7 @@ static int of_isp1760_remove(struct of_device *dev)
return 0;
}
-static struct of_device_id of_isp1760_match[] = {
+static const struct of_device_id of_isp1760_match[] = {
{
.compatible = "nxp,usb-isp1760",
},
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
new file mode 100644
index 000000000000..4aa08d36d077
--- /dev/null
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -0,0 +1,456 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * TI DA8xx (OMAP-L1x) Bus Glue
+ *
+ * Derived from: ohci-omap.c and ohci-s3c2410.c
+ * Copyright (C) 2008-2009 MontaVista Software, Inc. <source@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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <mach/da8xx.h>
+#include <mach/usb.h>
+
+#ifndef CONFIG_ARCH_DAVINCI_DA8XX
+#error "This file is DA8xx bus glue. Define CONFIG_ARCH_DAVINCI_DA8XX."
+#endif
+
+#define CFGCHIP2 DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG)
+
+static struct clk *usb11_clk;
+static struct clk *usb20_clk;
+
+/* Over-current indicator change bitmask */
+static volatile u16 ocic_mask;
+
+static void ohci_da8xx_clock(int on)
+{
+ u32 cfgchip2;
+
+ cfgchip2 = __raw_readl(CFGCHIP2);
+ if (on) {
+ clk_enable(usb11_clk);
+
+ /*
+ * If USB 1.1 reference clock is sourced from USB 2.0 PHY, we
+ * need to enable the USB 2.0 module clocking, start its PHY,
+ * and not allow it to stop the clock during USB 2.0 suspend.
+ */
+ if (!(cfgchip2 & CFGCHIP2_USB1PHYCLKMUX)) {
+ clk_enable(usb20_clk);
+
+ cfgchip2 &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN);
+ cfgchip2 |= CFGCHIP2_PHY_PLLON;
+ __raw_writel(cfgchip2, CFGCHIP2);
+
+ pr_info("Waiting for USB PHY clock good...\n");
+ while (!(__raw_readl(CFGCHIP2) & CFGCHIP2_PHYCLKGD))
+ cpu_relax();
+ }
+
+ /* Enable USB 1.1 PHY */
+ cfgchip2 |= CFGCHIP2_USB1SUSPENDM;
+ } else {
+ clk_disable(usb11_clk);
+ if (!(cfgchip2 & CFGCHIP2_USB1PHYCLKMUX))
+ clk_disable(usb20_clk);
+
+ /* Disable USB 1.1 PHY */
+ cfgchip2 &= ~CFGCHIP2_USB1SUSPENDM;
+ }
+ __raw_writel(cfgchip2, CFGCHIP2);
+}
+
+/*
+ * Handle the port over-current indicator change.
+ */
+static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub,
+ unsigned port)
+{
+ ocic_mask |= 1 << port;
+
+ /* Once over-current is detected, the port needs to be powered down */
+ if (hub->get_oci(port) > 0)
+ hub->set_power(port, 0);
+}
+
+static int ohci_da8xx_init(struct usb_hcd *hcd)
+{
+ struct device *dev = hcd->self.controller;
+ struct da8xx_ohci_root_hub *hub = dev->platform_data;
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int result;
+ u32 rh_a;
+
+ dev_dbg(dev, "starting USB controller\n");
+
+ ohci_da8xx_clock(1);
+
+ /*
+ * DA8xx only have 1 port connected to the pins but the HC root hub
+ * register A reports 2 ports, thus we'll have to override it...
+ */
+ ohci->num_ports = 1;
+
+ result = ohci_init(ohci);
+ if (result < 0)
+ return result;
+
+ /*
+ * Since we're providing a board-specific root hub port power control
+ * and over-current reporting, we have to override the HC root hub A
+ * register's default value, so that ohci_hub_control() could return
+ * the correct hub descriptor...
+ */
+ rh_a = ohci_readl(ohci, &ohci->regs->roothub.a);
+ if (hub->set_power) {
+ rh_a &= ~RH_A_NPS;
+ rh_a |= RH_A_PSM;
+ }
+ if (hub->get_oci) {
+ rh_a &= ~RH_A_NOCP;
+ rh_a |= RH_A_OCPM;
+ }
+ rh_a &= ~RH_A_POTPGT;
+ rh_a |= hub->potpgt << 24;
+ ohci_writel(ohci, rh_a, &ohci->regs->roothub.a);
+
+ return result;
+}
+
+static void ohci_da8xx_stop(struct usb_hcd *hcd)
+{
+ ohci_stop(hcd);
+ ohci_da8xx_clock(0);
+}
+
+static int ohci_da8xx_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int result;
+
+ result = ohci_run(ohci);
+ if (result < 0)
+ ohci_da8xx_stop(hcd);
+
+ return result;
+}
+
+/*
+ * Update the status data from the hub with the over-current indicator change.
+ */
+static int ohci_da8xx_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ int length = ohci_hub_status_data(hcd, buf);
+
+ /* See if we have OCIC bit set on port 1 */
+ if (ocic_mask & (1 << 1)) {
+ dev_dbg(hcd->self.controller, "over-current indicator change "
+ "on port 1\n");
+
+ if (!length)
+ length = 1;
+
+ buf[0] |= 1 << 1;
+ }
+ return length;
+}
+
+/*
+ * Look at the control requests to the root hub and see if we need to override.
+ */
+static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct device *dev = hcd->self.controller;
+ struct da8xx_ohci_root_hub *hub = dev->platform_data;
+ int temp;
+
+ switch (typeReq) {
+ case GetPortStatus:
+ /* Check the port number */
+ if (wIndex != 1)
+ break;
+
+ dev_dbg(dev, "GetPortStatus(%u)\n", wIndex);
+
+ temp = roothub_portstatus(hcd_to_ohci(hcd), wIndex - 1);
+
+ /* The port power status (PPS) bit defaults to 1 */
+ if (hub->get_power && hub->get_power(wIndex) == 0)
+ temp &= ~RH_PS_PPS;
+
+ /* The port over-current indicator (POCI) bit is always 0 */
+ if (hub->get_oci && hub->get_oci(wIndex) > 0)
+ temp |= RH_PS_POCI;
+
+ /* The over-current indicator change (OCIC) bit is 0 too */
+ if (ocic_mask & (1 << wIndex))
+ temp |= RH_PS_OCIC;
+
+ put_unaligned(cpu_to_le32(temp), (__le32 *)buf);
+ return 0;
+ case SetPortFeature:
+ temp = 1;
+ goto check_port;
+ case ClearPortFeature:
+ temp = 0;
+
+check_port:
+ /* Check the port number */
+ if (wIndex != 1)
+ break;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_POWER:
+ dev_dbg(dev, "%sPortFeature(%u): %s\n",
+ temp ? "Set" : "Clear", wIndex, "POWER");
+
+ if (!hub->set_power)
+ return -EPIPE;
+
+ return hub->set_power(wIndex, temp) ? -EPIPE : 0;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ dev_dbg(dev, "%sPortFeature(%u): %s\n",
+ temp ? "Set" : "Clear", wIndex,
+ "C_OVER_CURRENT");
+
+ if (temp)
+ ocic_mask |= 1 << wIndex;
+ else
+ ocic_mask &= ~(1 << wIndex);
+ return 0;
+ }
+ }
+
+ return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+}
+
+static const struct hc_driver ohci_da8xx_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "DA8xx OHCI",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ohci_da8xx_init,
+ .start = ohci_da8xx_start,
+ .stop = ohci_da8xx_stop,
+ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_da8xx_hub_status_data,
+ .hub_control = ohci_da8xx_hub_control,
+
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+
+/**
+ * usb_hcd_da8xx_probe - initialize DA8xx-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ */
+static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
+ struct platform_device *pdev)
+{
+ struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data;
+ struct usb_hcd *hcd;
+ struct resource *mem;
+ int error, irq;
+
+ if (hub == NULL)
+ return -ENODEV;
+
+ usb11_clk = clk_get(&pdev->dev, "usb11");
+ if (IS_ERR(usb11_clk))
+ return PTR_ERR(usb11_clk);
+
+ usb20_clk = clk_get(&pdev->dev, "usb20");
+ if (IS_ERR(usb20_clk)) {
+ error = PTR_ERR(usb20_clk);
+ goto err0;
+ }
+
+ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd) {
+ error = -ENOMEM;
+ goto err1;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ error = -ENODEV;
+ goto err2;
+ }
+ hcd->rsrc_start = mem->start;
+ hcd->rsrc_len = mem->end - mem->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "request_mem_region failed\n");
+ error = -EBUSY;
+ goto err2;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ error = -ENOMEM;
+ goto err3;
+ }
+
+ ohci_hcd_init(hcd_to_ohci(hcd));
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ error = -ENODEV;
+ goto err4;
+ }
+ error = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ if (error)
+ goto err4;
+
+ if (hub->ocic_notify) {
+ error = hub->ocic_notify(ohci_da8xx_ocic_handler);
+ if (!error)
+ return 0;
+ }
+
+ usb_remove_hcd(hcd);
+err4:
+ iounmap(hcd->regs);
+err3:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err2:
+ usb_put_hcd(hcd);
+err1:
+ clk_put(usb20_clk);
+err0:
+ clk_put(usb11_clk);
+ return error;
+}
+
+/**
+ * usb_hcd_da8xx_remove - shutdown processing for DA8xx-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_da8xx_probe(), first invoking
+ * the HCD's stop() method. It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ */
+static inline void
+usb_hcd_da8xx_remove(struct usb_hcd *hcd, struct platform_device *pdev)
+{
+ struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data;
+
+ hub->ocic_notify(NULL);
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ clk_put(usb20_clk);
+ clk_put(usb11_clk);
+}
+
+static int ohci_hcd_da8xx_drv_probe(struct platform_device *dev)
+{
+ return usb_hcd_da8xx_probe(&ohci_da8xx_hc_driver, dev);
+}
+
+static int ohci_hcd_da8xx_drv_remove(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+ usb_hcd_da8xx_remove(hcd, dev);
+ platform_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ohci_da8xx_suspend(struct platform_device *dev, pm_message_t message)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+
+ ohci_da8xx_clock(0);
+ hcd->state = HC_STATE_SUSPENDED;
+ dev->dev.power.power_state = PMSG_SUSPEND;
+ return 0;
+}
+
+static int ohci_da8xx_resume(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+
+ ohci_da8xx_clock(1);
+ dev->dev.power.power_state = PMSG_ON;
+ usb_hcd_resume_root_hub(hcd);
+ return 0;
+}
+#endif
+
+/*
+ * Driver definition to register with platform structure.
+ */
+static struct platform_driver ohci_hcd_da8xx_driver = {
+ .probe = ohci_hcd_da8xx_drv_probe,
+ .remove = ohci_hcd_da8xx_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+#ifdef CONFIG_PM
+ .suspend = ohci_da8xx_suspend,
+ .resume = ohci_da8xx_resume,
+#endif
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ohci",
+ },
+};
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 811f5dfdc582..8ad2441b0284 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -53,13 +53,13 @@ urb_print(struct urb * urb, char * str, int small, int status)
int i, len;
if (usb_pipecontrol (pipe)) {
- printk (KERN_DEBUG __FILE__ ": setup(8):");
+ printk (KERN_DEBUG "%s: setup(8):", __FILE__);
for (i = 0; i < 8 ; i++)
printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
printk ("\n");
}
if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
- printk (KERN_DEBUG __FILE__ ": data(%d/%d):",
+ printk (KERN_DEBUG "%s: data(%d/%d):", __FILE__,
urb->actual_length,
urb->transfer_buffer_length);
len = usb_pipeout (pipe)?
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 24eb74781919..afe59be23645 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1051,6 +1051,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER usb_hcd_pnx4008_driver
#endif
+#ifdef CONFIG_ARCH_DAVINCI_DA8XX
+#include "ohci-da8xx.c"
+#define PLATFORM_DRIVER ohci_hcd_da8xx_driver
+#endif
+
#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_CPU_SUBTYPE_SH7763) || \
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index de42283149c7..18d39f0463ee 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -28,8 +28,8 @@ extern int usb_disabled(void);
static void lh7a404_start_hc(struct platform_device *dev)
{
- printk(KERN_DEBUG __FILE__
- ": starting LH7A404 OHCI USB Controller\n");
+ printk(KERN_DEBUG "%s: starting LH7A404 OHCI USB Controller\n",
+ __FILE__);
/*
* Now, carefully enable the USB clock, and take
@@ -39,14 +39,13 @@ static void lh7a404_start_hc(struct platform_device *dev)
udelay(1000);
USBH_CMDSTATUS = OHCI_HCR;
- printk(KERN_DEBUG __FILE__
- ": Clock to USB host has been enabled \n");
+ printk(KERN_DEBUG "%s: Clock to USB host has been enabled \n", __FILE__);
}
static void lh7a404_stop_hc(struct platform_device *dev)
{
- printk(KERN_DEBUG __FILE__
- ": stopping LH7A404 OHCI USB Controller\n");
+ printk(KERN_DEBUG "%s: stopping LH7A404 OHCI USB Controller\n",
+ __FILE__);
CSC_PWRCNT &= ~CSC_PWRCNT_USBH_EN; /* Disable clock */
}
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index 2769326da42e..cd74bbdd007c 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -327,7 +327,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
}
i2c_adap = i2c_get_adapter(2);
memset(&i2c_info, 0, sizeof(struct i2c_board_info));
- strlcpy(i2c_info.name, "isp1301_pnx", I2C_NAME_SIZE);
+ strlcpy(i2c_info.type, "isp1301_pnx", I2C_NAME_SIZE);
isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
normal_i2c);
i2c_put_adapter(i2c_adap);
@@ -411,7 +411,7 @@ out3:
out2:
clk_put(usb_clk);
out1:
- i2c_unregister_client(isp1301_i2c_client);
+ i2c_unregister_device(isp1301_i2c_client);
isp1301_i2c_client = NULL;
out_i2c_driver:
i2c_del_driver(&isp1301_driver);
@@ -430,7 +430,7 @@ static int usb_hcd_pnx4008_remove(struct platform_device *pdev)
pnx4008_unset_usb_bits();
clk_disable(usb_clk);
clk_put(usb_clk);
- i2c_unregister_client(isp1301_i2c_client);
+ i2c_unregister_device(isp1301_i2c_client);
isp1301_i2c_client = NULL;
i2c_del_driver(&isp1301_driver);
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 68a301710297..103263c230cf 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -114,21 +114,21 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
hcd->rsrc_len = res.end - res.start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+ printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
rv = -EBUSY;
goto err_rmr;
}
irq = irq_of_parse_and_map(dn, 0);
if (irq == NO_IRQ) {
- printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+ printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
rv = -EBUSY;
goto err_irq;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
- printk(KERN_ERR __FILE__ ": ioremap failed\n");
+ printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
rv = -ENOMEM;
goto err_ioremap;
}
@@ -169,7 +169,7 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
} else
release_mem_region(res.start, 0x4);
} else
- pr_debug(__FILE__ ": cannot get ehci offset from fdt\n");
+ pr_debug("%s: cannot get ehci offset from fdt\n", __FILE__);
}
iounmap(hcd->regs);
@@ -212,7 +212,7 @@ static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
}
-static struct of_device_id ohci_hcd_ppc_of_match[] = {
+static const struct of_device_id ohci_hcd_ppc_of_match[] = {
#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
{
.name = "usb",
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index cd3398b675b2..89e670e38c10 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -41,14 +41,14 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
- pr_debug(__FILE__ ": no irq\n");
+ pr_debug("%s: no irq\n", __FILE__);
return -ENODEV;
}
irq = res->start;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
- pr_debug(__FILE__ ": no reg addr\n");
+ pr_debug("%s: no reg addr\n", __FILE__);
return -ENODEV;
}
@@ -59,14 +59,14 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
hcd->rsrc_len = res->end - res->start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- pr_debug(__FILE__ ": request_mem_region failed\n");
+ pr_debug("%s: request_mem_region failed\n", __FILE__);
retval = -EBUSY;
goto err1;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
- pr_debug(__FILE__ ": ioremap failed\n");
+ pr_debug("%s: ioremap failed\n", __FILE__);
retval = -ENOMEM;
goto err2;
}
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index e4bbe8e188e4..d8eb3bdafabb 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -31,8 +31,8 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
{
unsigned int usb_rst = 0;
- printk(KERN_DEBUG __FILE__
- ": starting SA-1111 OHCI USB Controller\n");
+ printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n",
+ __FILE__);
#ifdef CONFIG_SA1100_BADGE4
if (machine_is_badge4()) {
@@ -65,8 +65,8 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
static void sa1111_stop_hc(struct sa1111_dev *dev)
{
unsigned int usb_rst;
- printk(KERN_DEBUG __FILE__
- ": stopping SA-1111 OHCI USB Controller\n");
+ printk(KERN_DEBUG "%s: stopping SA-1111 OHCI USB Controller\n",
+ __FILE__);
/*
* Put the USB host controller into reset.
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index b7a661c02bcd..bee558aed427 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -35,7 +35,9 @@
#include <linux/usb.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/mm.h>
#include <linux/irq.h>
+#include <asm/cacheflush.h>
#include "../core/hcd.h"
#include "r8a66597.h"
@@ -216,8 +218,17 @@ static void disable_controller(struct r8a66597 *r8a66597)
{
int port;
+ /* disable interrupts */
r8a66597_write(r8a66597, 0, INTENB0);
- r8a66597_write(r8a66597, 0, INTSTS0);
+ r8a66597_write(r8a66597, 0, INTENB1);
+ r8a66597_write(r8a66597, 0, BRDYENB);
+ r8a66597_write(r8a66597, 0, BEMPENB);
+ r8a66597_write(r8a66597, 0, NRDYENB);
+
+ /* clear status */
+ r8a66597_write(r8a66597, 0, BRDYSTS);
+ r8a66597_write(r8a66597, 0, NRDYSTS);
+ r8a66597_write(r8a66597, 0, BEMPSTS);
for (port = 0; port < r8a66597->max_root_hub; port++)
r8a66597_disable_port(r8a66597, port);
@@ -811,6 +822,26 @@ static void enable_r8a66597_pipe(struct r8a66597 *r8a66597, struct urb *urb,
enable_r8a66597_pipe_dma(r8a66597, dev, pipe, urb);
}
+static void r8a66597_urb_done(struct r8a66597 *r8a66597, struct urb *urb,
+ int status)
+__releases(r8a66597->lock)
+__acquires(r8a66597->lock)
+{
+ if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) {
+ void *ptr;
+
+ for (ptr = urb->transfer_buffer;
+ ptr < urb->transfer_buffer + urb->transfer_buffer_length;
+ ptr += PAGE_SIZE)
+ flush_dcache_page(virt_to_page(ptr));
+ }
+
+ usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
+ spin_unlock(&r8a66597->lock);
+ usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb, status);
+ spin_lock(&r8a66597->lock);
+}
+
/* this function must be called with interrupt disabled */
static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
{
@@ -829,15 +860,9 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
list_del(&td->queue);
kfree(td);
- if (urb) {
- usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
- urb);
+ if (urb)
+ r8a66597_urb_done(r8a66597, urb, -ENODEV);
- spin_unlock(&r8a66597->lock);
- usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb,
- -ENODEV);
- spin_lock(&r8a66597->lock);
- }
break;
}
}
@@ -997,6 +1022,8 @@ static void start_root_hub_sampling(struct r8a66597 *r8a66597, int port,
/* this function must be called with interrupt disabled */
static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port,
u16 syssts)
+__releases(r8a66597->lock)
+__acquires(r8a66597->lock)
{
if (syssts == SE0) {
r8a66597_write(r8a66597, ~ATTCH, get_intsts_reg(port));
@@ -1014,7 +1041,9 @@ static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port,
usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
}
+ spin_unlock(&r8a66597->lock);
usb_hcd_poll_rh_status(r8a66597_to_hcd(r8a66597));
+ spin_lock(&r8a66597->lock);
}
/* this function must be called with interrupt disabled */
@@ -1274,10 +1303,7 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock)
if (usb_pipeisoc(urb->pipe))
urb->start_frame = r8a66597_get_frame(hcd);
- usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
- spin_unlock(&r8a66597->lock);
- usb_hcd_giveback_urb(hcd, urb, status);
- spin_lock(&r8a66597->lock);
+ r8a66597_urb_done(r8a66597, urb, status);
}
if (restart) {
@@ -2466,6 +2492,12 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
r8a66597->rh_timer.data = (unsigned long)r8a66597;
r8a66597->reg = (unsigned long)reg;
+ /* make sure no interrupts are pending */
+ ret = r8a66597_clock_enable(r8a66597);
+ if (ret < 0)
+ goto clean_up3;
+ disable_controller(r8a66597);
+
for (i = 0; i < R8A66597_MAX_NUM_PIPE; i++) {
INIT_LIST_HEAD(&r8a66597->pipe_queue[i]);
init_timer(&r8a66597->td_timer[i]);
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 5b22a4d1c9e4..e11cc3aa4b82 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -51,6 +51,7 @@
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/byteorder.h>
+#include <asm/unaligned.h>
#include "../core/hcd.h"
#include "sl811.h"
@@ -1272,12 +1273,12 @@ sl811h_hub_control(
sl811h_hub_descriptor(sl811, (struct usb_hub_descriptor *) buf);
break;
case GetHubStatus:
- *(__le32 *) buf = cpu_to_le32(0);
+ put_unaligned_le32(0, buf);
break;
case GetPortStatus:
if (wIndex != 1)
goto error;
- *(__le32 *) buf = cpu_to_le32(sl811->port1);
+ put_unaligned_le32(sl811->port1, buf);
#ifndef VERBOSE
if (*(u16*)(buf+2)) /* only if wPortChange is interesting */
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 5cd0e48f67fb..09197067fe6b 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -735,6 +735,7 @@ static void uhci_stop(struct usb_hcd *hcd)
uhci_hc_died(uhci);
uhci_scan_schedule(uhci);
spin_unlock_irq(&uhci->lock);
+ synchronize_irq(hcd->irq);
del_timer_sync(&uhci->fsbr_timer);
release_uhci(uhci);
@@ -749,7 +750,20 @@ static int uhci_rh_suspend(struct usb_hcd *hcd)
spin_lock_irq(&uhci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
rc = -ESHUTDOWN;
- else if (!uhci->dead)
+ else if (uhci->dead)
+ ; /* Dead controllers tell no tales */
+
+ /* Once the controller is stopped, port resumes that are already
+ * in progress won't complete. Hence if remote wakeup is enabled
+ * for the root hub and any ports are in the middle of a resume or
+ * remote wakeup, we must fail the suspend.
+ */
+ else if (hcd->self.root_hub->do_remote_wakeup &&
+ uhci->resuming_ports) {
+ dev_dbg(uhci_dev(uhci), "suspend failed because a port "
+ "is resuming\n");
+ rc = -EBUSY;
+ } else
suspend_rh(uhci, UHCI_RH_SUSPENDED);
spin_unlock_irq(&uhci->lock);
return rc;
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index 885b585360b9..8270055848ca 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -167,7 +167,7 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
/* Port received a wakeup request */
set_bit(port, &uhci->resuming_ports);
uhci->ports_timeout = jiffies +
- msecs_to_jiffies(20);
+ msecs_to_jiffies(25);
/* Make sure we see the port again
* after the resuming period is over. */
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index 33128d52f212..105fa8b025bb 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -406,6 +406,25 @@ static void dbg_rsvd64(struct xhci_hcd *xhci, u64 *ctx, dma_addr_t dma)
}
}
+char *xhci_get_slot_state(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx)
+{
+ struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
+
+ switch (GET_SLOT_STATE(slot_ctx->dev_state)) {
+ case 0:
+ return "enabled/disabled";
+ case 1:
+ return "default";
+ case 2:
+ return "addressed";
+ case 3:
+ return "configured";
+ default:
+ return "reserved";
+ }
+}
+
void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
{
/* Fields are 32 bits wide, DMA addresses are in bytes */
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index ecc131c3fe33..78c4edac1db1 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -101,12 +101,15 @@ static inline int xhci_find_next_cap_offset(void __iomem *base, int ext_offset)
next = readl(base + ext_offset);
- if (ext_offset == XHCI_HCC_PARAMS_OFFSET)
+ if (ext_offset == XHCI_HCC_PARAMS_OFFSET) {
/* Find the first extended capability */
next = XHCI_HCC_EXT_CAPS(next);
- else
+ ext_offset = 0;
+ } else {
/* Find the next extended capability */
next = XHCI_EXT_CAPS_NEXT(next);
+ }
+
if (!next)
return 0;
/*
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 5e92c72df642..4cb69e0af834 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -1007,7 +1007,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
* for usb_set_interface() and usb_set_configuration() claim).
*/
if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id],
- udev, ep, GFP_KERNEL) < 0) {
+ udev, ep, GFP_NOIO) < 0) {
dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n",
__func__, ep->desc.bEndpointAddress);
return -ENOMEM;
@@ -1181,6 +1181,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
ret = xhci_queue_evaluate_context(xhci, in_ctx->dma,
udev->slot_id);
if (ret < 0) {
+ if (command)
+ list_del(&command->cmd_list);
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
return -ENOMEM;
@@ -1264,30 +1266,13 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
xhci_zero_in_ctx(xhci, virt_dev);
/* Install new rings and free or cache any old rings */
for (i = 1; i < 31; ++i) {
- int rings_cached;
-
if (!virt_dev->eps[i].new_ring)
continue;
/* Only cache or free the old ring if it exists.
* It may not if this is the first add of an endpoint.
*/
if (virt_dev->eps[i].ring) {
- rings_cached = virt_dev->num_rings_cached;
- if (rings_cached < XHCI_MAX_RINGS_CACHED) {
- virt_dev->num_rings_cached++;
- rings_cached = virt_dev->num_rings_cached;
- virt_dev->ring_cache[rings_cached] =
- virt_dev->eps[i].ring;
- xhci_dbg(xhci, "Cached old ring, "
- "%d ring%s cached\n",
- rings_cached,
- (rings_cached > 1) ? "s" : "");
- } else {
- xhci_ring_free(xhci, virt_dev->eps[i].ring);
- xhci_dbg(xhci, "Ring cache full (%d rings), "
- "freeing ring\n",
- virt_dev->num_rings_cached);
- }
+ xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
}
virt_dev->eps[i].ring = virt_dev->eps[i].new_ring;
virt_dev->eps[i].new_ring = NULL;
@@ -1458,6 +1443,131 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
}
/*
+ * This submits a Reset Device Command, which will set the device state to 0,
+ * set the device address to 0, and disable all the endpoints except the default
+ * control endpoint. The USB core should come back and call
+ * xhci_address_device(), and then re-set up the configuration. If this is
+ * called because of a usb_reset_and_verify_device(), then the old alternate
+ * settings will be re-installed through the normal bandwidth allocation
+ * functions.
+ *
+ * Wait for the Reset Device command to finish. Remove all structures
+ * associated with the endpoints that were disabled. Clear the input device
+ * structure? Cache the rings? Reset the control endpoint 0 max packet size?
+ */
+int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+ int ret, i;
+ unsigned long flags;
+ struct xhci_hcd *xhci;
+ unsigned int slot_id;
+ struct xhci_virt_device *virt_dev;
+ struct xhci_command *reset_device_cmd;
+ int timeleft;
+ int last_freed_endpoint;
+
+ ret = xhci_check_args(hcd, udev, NULL, 0, __func__);
+ if (ret <= 0)
+ return ret;
+ xhci = hcd_to_xhci(hcd);
+ slot_id = udev->slot_id;
+ virt_dev = xhci->devs[slot_id];
+ if (!virt_dev) {
+ xhci_dbg(xhci, "%s called with invalid slot ID %u\n",
+ __func__, slot_id);
+ return -EINVAL;
+ }
+
+ xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id);
+ /* Allocate the command structure that holds the struct completion.
+ * Assume we're in process context, since the normal device reset
+ * process has to wait for the device anyway. Storage devices are
+ * reset as part of error handling, so use GFP_NOIO instead of
+ * GFP_KERNEL.
+ */
+ reset_device_cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
+ if (!reset_device_cmd) {
+ xhci_dbg(xhci, "Couldn't allocate command structure.\n");
+ return -ENOMEM;
+ }
+
+ /* Attempt to submit the Reset Device command to the command ring */
+ spin_lock_irqsave(&xhci->lock, flags);
+ reset_device_cmd->command_trb = xhci->cmd_ring->enqueue;
+ list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list);
+ ret = xhci_queue_reset_device(xhci, slot_id);
+ if (ret) {
+ xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
+ list_del(&reset_device_cmd->cmd_list);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ goto command_cleanup;
+ }
+ xhci_ring_cmd_db(xhci);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+ /* Wait for the Reset Device command to finish */
+ timeleft = wait_for_completion_interruptible_timeout(
+ reset_device_cmd->completion,
+ USB_CTRL_SET_TIMEOUT);
+ if (timeleft <= 0) {
+ xhci_warn(xhci, "%s while waiting for reset device command\n",
+ timeleft == 0 ? "Timeout" : "Signal");
+ spin_lock_irqsave(&xhci->lock, flags);
+ /* The timeout might have raced with the event ring handler, so
+ * only delete from the list if the item isn't poisoned.
+ */
+ if (reset_device_cmd->cmd_list.next != LIST_POISON1)
+ list_del(&reset_device_cmd->cmd_list);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ ret = -ETIME;
+ goto command_cleanup;
+ }
+
+ /* The Reset Device command can't fail, according to the 0.95/0.96 spec,
+ * unless we tried to reset a slot ID that wasn't enabled,
+ * or the device wasn't in the addressed or configured state.
+ */
+ ret = reset_device_cmd->status;
+ switch (ret) {
+ case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */
+ case COMP_CTX_STATE: /* 0.96 completion code for same thing */
+ xhci_info(xhci, "Can't reset device (slot ID %u) in %s state\n",
+ slot_id,
+ xhci_get_slot_state(xhci, virt_dev->out_ctx));
+ xhci_info(xhci, "Not freeing device rings.\n");
+ /* Don't treat this as an error. May change my mind later. */
+ ret = 0;
+ goto command_cleanup;
+ case COMP_SUCCESS:
+ xhci_dbg(xhci, "Successful reset device command.\n");
+ break;
+ default:
+ if (xhci_is_vendor_info_code(xhci, ret))
+ break;
+ xhci_warn(xhci, "Unknown completion code %u for "
+ "reset device command.\n", ret);
+ ret = -EINVAL;
+ goto command_cleanup;
+ }
+
+ /* Everything but endpoint 0 is disabled, so free or cache the rings. */
+ last_freed_endpoint = 1;
+ for (i = 1; i < 31; ++i) {
+ if (!virt_dev->eps[i].ring)
+ continue;
+ xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
+ last_freed_endpoint = i;
+ }
+ xhci_dbg(xhci, "Output context after successful reset device cmd:\n");
+ xhci_dbg_ctx(xhci, virt_dev->out_ctx, last_freed_endpoint);
+ ret = 0;
+
+command_cleanup:
+ xhci_free_command(xhci, reset_device_cmd);
+ return ret;
+}
+
+/*
* At this point, the struct usb_device is about to go away, the device has
* disconnected, and all traffic has been stopped and the endpoints have been
* disabled. Free any HC data structures associated with that device.
@@ -1694,7 +1804,7 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
xhci_warn(xhci, "Cannot update hub desc for unknown device.\n");
return -EINVAL;
}
- config_cmd = xhci_alloc_command(xhci, true, mem_flags);
+ config_cmd = xhci_alloc_command(xhci, true, true, mem_flags);
if (!config_cmd) {
xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
return -ENOMEM;
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index eac5b53aa9e7..208b805b80eb 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -129,6 +129,50 @@ static u32 xhci_port_state_to_neutral(u32 state)
return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
}
+static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex,
+ u32 __iomem *addr, u32 port_status)
+{
+ /* Write 1 to disable the port */
+ xhci_writel(xhci, port_status | PORT_PE, addr);
+ port_status = xhci_readl(xhci, addr);
+ xhci_dbg(xhci, "disable port, actual port %d status = 0x%x\n",
+ wIndex, port_status);
+}
+
+static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
+ u16 wIndex, u32 __iomem *addr, u32 port_status)
+{
+ char *port_change_bit;
+ u32 status;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_C_RESET:
+ status = PORT_RC;
+ port_change_bit = "reset";
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ status = PORT_CSC;
+ port_change_bit = "connect";
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ status = PORT_OCC;
+ port_change_bit = "over-current";
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ status = PORT_PEC;
+ port_change_bit = "enable/disable";
+ break;
+ default:
+ /* Should never happen */
+ return;
+ }
+ /* Change bits are all write 1 to clear */
+ xhci_writel(xhci, port_status | status, addr);
+ port_status = xhci_readl(xhci, addr);
+ xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n",
+ port_change_bit, wIndex, port_status);
+}
+
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
@@ -138,7 +182,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u32 temp, status;
int retval = 0;
u32 __iomem *addr;
- char *port_change_bit;
ports = HCS_MAX_PORTS(xhci->hcs_params1);
@@ -229,26 +272,18 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_port_state_to_neutral(temp);
switch (wValue) {
case USB_PORT_FEAT_C_RESET:
- status = PORT_RC;
- port_change_bit = "reset";
- break;
case USB_PORT_FEAT_C_CONNECTION:
- status = PORT_CSC;
- port_change_bit = "connect";
- break;
case USB_PORT_FEAT_C_OVER_CURRENT:
- status = PORT_OCC;
- port_change_bit = "over-current";
+ case USB_PORT_FEAT_C_ENABLE:
+ xhci_clear_port_change_bit(xhci, wValue, wIndex,
+ addr, temp);
+ break;
+ case USB_PORT_FEAT_ENABLE:
+ xhci_disable_port(xhci, wIndex, addr, temp);
break;
default:
goto error;
}
- /* Change bits are all write 1 to clear */
- xhci_writel(xhci, temp | status, addr);
- temp = xhci_readl(xhci, addr);
- xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n",
- port_change_bit, wIndex, temp);
- temp = xhci_readl(xhci, addr); /* unblock any posted writes */
break;
default:
error:
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index bffcef7a5545..49f7d72f8b1b 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -198,6 +198,31 @@ fail:
return 0;
}
+void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ unsigned int ep_index)
+{
+ int rings_cached;
+
+ rings_cached = virt_dev->num_rings_cached;
+ if (rings_cached < XHCI_MAX_RINGS_CACHED) {
+ virt_dev->num_rings_cached++;
+ rings_cached = virt_dev->num_rings_cached;
+ virt_dev->ring_cache[rings_cached] =
+ virt_dev->eps[ep_index].ring;
+ xhci_dbg(xhci, "Cached old ring, "
+ "%d ring%s cached\n",
+ rings_cached,
+ (rings_cached > 1) ? "s" : "");
+ } else {
+ xhci_ring_free(xhci, virt_dev->eps[ep_index].ring);
+ xhci_dbg(xhci, "Ring cache full (%d rings), "
+ "freeing ring\n",
+ virt_dev->num_rings_cached);
+ }
+ virt_dev->eps[ep_index].ring = NULL;
+}
+
/* Zero an endpoint ring (except for link TRBs) and move the enqueue and dequeue
* pointers to the beginning of the ring.
*/
@@ -242,6 +267,8 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
void xhci_free_container_ctx(struct xhci_hcd *xhci,
struct xhci_container_ctx *ctx)
{
+ if (!ctx)
+ return;
dma_pool_free(xhci->device_pool, ctx->bytes, ctx->dma);
kfree(ctx);
}
@@ -427,7 +454,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
case USB_SPEED_LOW:
slot_ctx->dev_info |= (u32) SLOT_SPEED_LS;
break;
- case USB_SPEED_VARIABLE:
+ case USB_SPEED_WIRELESS:
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
return -EINVAL;
break;
@@ -471,7 +498,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
case USB_SPEED_LOW:
ep0_ctx->ep_info2 |= MAX_PACKET(8);
break;
- case USB_SPEED_VARIABLE:
+ case USB_SPEED_WIRELESS:
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
return -EINVAL;
break;
@@ -819,7 +846,8 @@ static void scratchpad_free(struct xhci_hcd *xhci)
}
struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
- bool allocate_completion, gfp_t mem_flags)
+ bool allocate_in_ctx, bool allocate_completion,
+ gfp_t mem_flags)
{
struct xhci_command *command;
@@ -827,11 +855,14 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
if (!command)
return NULL;
- command->in_ctx =
- xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, mem_flags);
- if (!command->in_ctx) {
- kfree(command);
- return NULL;
+ if (allocate_in_ctx) {
+ command->in_ctx =
+ xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT,
+ mem_flags);
+ if (!command->in_ctx) {
+ kfree(command);
+ return NULL;
+ }
}
if (allocate_completion) {
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index e097008d6fb1..417d37aff8d7 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -139,6 +139,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
.reset_bandwidth = xhci_reset_bandwidth,
.address_device = xhci_address_device,
.update_hub_device = xhci_update_hub_device,
+ .reset_device = xhci_reset_device,
/*
* scheduling support
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index ee7bc7ecbc59..6ba841bca4a2 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -953,6 +953,17 @@ bandwidth_change:
case TRB_TYPE(TRB_RESET_EP):
handle_reset_ep_completion(xhci, event, xhci->cmd_ring->dequeue);
break;
+ case TRB_TYPE(TRB_RESET_DEV):
+ xhci_dbg(xhci, "Completed reset device command.\n");
+ slot_id = TRB_TO_SLOT_ID(
+ xhci->cmd_ring->dequeue->generic.field[3]);
+ virt_dev = xhci->devs[slot_id];
+ if (virt_dev)
+ handle_cmd_in_cmd_wait_list(xhci, virt_dev, event);
+ else
+ xhci_warn(xhci, "Reset device command completion "
+ "for disabled slot %u\n", slot_id);
+ break;
default:
/* Skip over unknown commands on the event ring */
xhci->error_bitmask |= 1 << 6;
@@ -1080,6 +1091,20 @@ static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci,
return 0;
}
+int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code)
+{
+ if (trb_comp_code >= 224 && trb_comp_code <= 255) {
+ /* Vendor defined "informational" completion code,
+ * treat as not-an-error.
+ */
+ xhci_dbg(xhci, "Vendor defined info completion code %u\n",
+ trb_comp_code);
+ xhci_dbg(xhci, "Treating code as success.\n");
+ return 1;
+ }
+ return 0;
+}
+
/*
* If this function returns an error condition, it means it got a Transfer
* event with a corrupted Slot ID, Endpoint ID, or TRB DMA address.
@@ -1196,13 +1221,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
status = -ENOSR;
break;
default:
- if (trb_comp_code >= 224 && trb_comp_code <= 255) {
- /* Vendor defined "informational" completion code,
- * treat as not-an-error.
- */
- xhci_dbg(xhci, "Vendor defined info completion code %u\n",
- trb_comp_code);
- xhci_dbg(xhci, "Treating code as success.\n");
+ if (xhci_is_vendor_info_code(xhci, trb_comp_code)) {
status = 0;
break;
}
@@ -2181,6 +2200,14 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
false);
}
+/* Queue a reset device command TRB */
+int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id)
+{
+ return queue_command(xhci, 0, 0, 0,
+ TRB_TYPE(TRB_RESET_DEV) | SLOT_ID_FOR_TRB(slot_id),
+ false);
+}
+
/* Queue a configure endpoint command TRB */
int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id, bool command_must_succeed)
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 877813505ef2..e5eb09b2f38e 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1210,6 +1210,8 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst);
void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci);
void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring);
void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep);
+char *xhci_get_slot_state(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx);
/* xHCI memory management */
void xhci_mem_cleanup(struct xhci_hcd *xhci);
@@ -1233,8 +1235,12 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev,
struct usb_device *udev, struct usb_host_endpoint *ep,
gfp_t mem_flags);
void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
+void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ unsigned int ep_index);
struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
- bool allocate_completion, gfp_t mem_flags);
+ bool allocate_in_ctx, bool allocate_completion,
+ gfp_t mem_flags);
void xhci_free_command(struct xhci_hcd *xhci,
struct xhci_command *command);
@@ -1264,6 +1270,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
+int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev);
int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
@@ -1272,6 +1279,7 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
struct xhci_segment *trb_in_td(struct xhci_segment *start_seg,
union xhci_trb *start_trb, union xhci_trb *end_trb,
dma_addr_t suspect_dma);
+int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code);
void xhci_ring_cmd_db(struct xhci_hcd *xhci);
void *xhci_setup_one_noop(struct xhci_hcd *xhci);
void xhci_handle_event(struct xhci_hcd *xhci);
@@ -1293,6 +1301,7 @@ int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id);
int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
unsigned int ep_index);
+int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id);
void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
struct xhci_td *cur_td, struct xhci_dequeue_state *state);
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index eca355dccf65..e192e8f7c560 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -967,7 +967,7 @@ static const struct file_operations mdc800_device_ops =
-static struct usb_device_id mdc800_table [] = {
+static const struct usb_device_id mdc800_table[] = {
{ USB_DEVICE(MDC800_VENDOR_ID, MDC800_PRODUCT_ID) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 459a7287fe01..3a6bcd5fee09 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -155,7 +155,7 @@ static int mts_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static void mts_usb_disconnect(struct usb_interface *intf);
-static struct usb_device_id mts_usb_ids [];
+static const struct usb_device_id mts_usb_ids[];
static struct usb_driver mts_usb_driver = {
.name = "microtekX6",
@@ -656,7 +656,7 @@ static struct scsi_host_template mts_scsi_host_template = {
/* The entries of microtek_table must correspond, line-by-line to
the entries of mts_supported_products[]. */
-static struct usb_device_id mts_usb_ids [] =
+static const struct usb_device_id mts_usb_ids[] =
{
{ USB_DEVICE(0x4ce, 0x0300) },
{ USB_DEVICE(0x5da, 0x0094) },
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index abe3aa67ed00..55660eaf947c 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -87,17 +87,6 @@ config USB_LCD
To compile this driver as a module, choose M here: the
module will be called usblcd.
-config USB_BERRY_CHARGE
- tristate "USB BlackBerry recharge support"
- depends on USB
- help
- Say Y here if you want to connect a BlackBerry device to your
- computer's USB port and have it automatically switch to "recharge"
- mode.
-
- To compile this driver as a module, choose M here: the
- module will be called berry_charge.
-
config USB_LED
tristate "USB LED driver support"
depends on USB
@@ -242,17 +231,3 @@ config USB_ISIGHTFW
driver beforehand. Tools for doing so are available at
http://bersace03.free.fr
-config USB_VST
- tristate "USB VST driver"
- depends on USB
- help
- This driver is intended for Vernier Software Technologies
- bulk usb devices such as their Ocean-Optics spectrometers or
- Labquest.
- It is a bulk channel driver with configurable read and write
- timeouts.
-
- To compile this driver as a module, choose M here: the
- module will be called vstusb.
-
-
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 0826aab8303f..717703e81425 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -5,7 +5,6 @@
obj-$(CONFIG_USB_ADUTUX) += adutux.o
obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o
-obj-$(CONFIG_USB_BERRY_CHARGE) += berry_charge.o
obj-$(CONFIG_USB_CYPRESS_CY7C63)+= cypress_cy7c63.o
obj-$(CONFIG_USB_CYTHERM) += cytherm.o
obj-$(CONFIG_USB_EMI26) += emi26.o
@@ -23,7 +22,6 @@ obj-$(CONFIG_USB_TEST) += usbtest.o
obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
obj-$(CONFIG_USB_USS720) += uss720.o
obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o
-obj-$(CONFIG_USB_VST) += vstusb.o
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index 203526542013..d240de097c62 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -38,7 +38,7 @@ static int debug = 1;
#define dbg(lvl, format, arg...) \
do { \
if (debug >= lvl) \
- printk(KERN_DEBUG __FILE__ " : " format " \n", ## arg); \
+ printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \
} while (0)
@@ -56,7 +56,7 @@ MODULE_PARM_DESC(debug, "Debug enabled or not");
#define ADU_PRODUCT_ID 0x0064
/* table of devices that work with this driver */
-static struct usb_device_id device_table [] = {
+static const struct usb_device_id device_table[] = {
{ USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID) }, /* ADU100 */
{ USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+20) }, /* ADU120 */
{ USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+30) }, /* ADU130 */
@@ -132,8 +132,8 @@ static void adu_debug_data(int level, const char *function, int size,
if (debug < level)
return;
- printk(KERN_DEBUG __FILE__": %s - length = %d, data = ",
- function, size);
+ printk(KERN_DEBUG "%s: %s - length = %d, data = ",
+ __FILE__, function, size);
for (i = 0; i < size; ++i)
printk("%.2x ", data[i]);
printk("\n");
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index 1eb9e4162cc6..4d2952f1fb13 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -57,7 +57,7 @@
.bInterfaceProtocol = 0x00
/* table of devices that work with this driver */
-static struct usb_device_id appledisplay_table [] = {
+static const struct usb_device_id appledisplay_table[] = {
{ APPLEDISPLAY_DEVICE(0x9218) },
{ APPLEDISPLAY_DEVICE(0x9219) },
{ APPLEDISPLAY_DEVICE(0x921c) },
@@ -179,7 +179,7 @@ static int appledisplay_bl_get_brightness(struct backlight_device *bd)
return pdata->msgdata[1];
}
-static struct backlight_ops appledisplay_bl_data = {
+static const struct backlight_ops appledisplay_bl_data = {
.get_brightness = appledisplay_bl_get_brightness,
.update_status = appledisplay_bl_update_status,
};
@@ -283,6 +283,7 @@ static int appledisplay_probe(struct usb_interface *iface,
&appledisplay_bl_data);
if (IS_ERR(pdata->bd)) {
dev_err(&iface->dev, "Backlight registration failed\n");
+ retval = PTR_ERR(pdata->bd);
goto error;
}
diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c
deleted file mode 100644
index c05a85bc5925..000000000000
--- a/drivers/usb/misc/berry_charge.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * USB BlackBerry charging module
- *
- * Copyright (C) 2007 Greg Kroah-Hartman <gregkh@suse.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, version 2.
- *
- * Information on how to switch configs was taken by the bcharge.cc file
- * created by the barry.sf.net project.
- *
- * bcharge.cc has the following copyright:
- * Copyright (C) 2006, Net Direct Inc. (http://www.netdirect.ca/)
- * and is released under the GPLv2.
- *
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-
-#define RIM_VENDOR 0x0fca
-#define BLACKBERRY 0x0001
-#define BLACKBERRY_PEARL_DUAL 0x0004
-#define BLACKBERRY_PEARL 0x0006
-
-static int debug;
-static int pearl_dual_mode = 1;
-
-#ifdef dbg
-#undef dbg
-#endif
-#define dbg(dev, format, arg...) \
- if (debug) \
- dev_printk(KERN_DEBUG , dev , format , ## arg)
-
-static struct usb_device_id id_table [] = {
- { USB_DEVICE(RIM_VENDOR, BLACKBERRY) },
- { USB_DEVICE(RIM_VENDOR, BLACKBERRY_PEARL) },
- { USB_DEVICE(RIM_VENDOR, BLACKBERRY_PEARL_DUAL) },
- { }, /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static int magic_charge(struct usb_device *udev)
-{
- char *dummy_buffer = kzalloc(2, GFP_KERNEL);
- int retval;
-
- if (!dummy_buffer)
- return -ENOMEM;
-
- /* send two magic commands and then set the configuration. The device
- * will then reset itself with the new power usage and should start
- * charging. */
-
- /* Note, with testing, it only seems that the first message is really
- * needed (at least for the 8700c), but to be safe, we emulate what
- * other operating systems seem to be sending to their device. We
- * really need to get some specs for this device to be sure about what
- * is going on here.
- */
- dbg(&udev->dev, "Sending first magic command\n");
- retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- 0xa5, 0xc0, 0, 1, dummy_buffer, 2, 100);
- if (retval != 2) {
- dev_err(&udev->dev, "First magic command failed: %d.\n",
- retval);
- goto exit;
- }
-
- dbg(&udev->dev, "Sending second magic command\n");
- retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- 0xa2, 0x40, 0, 1, dummy_buffer, 0, 100);
- if (retval != 0) {
- dev_err(&udev->dev, "Second magic command failed: %d.\n",
- retval);
- goto exit;
- }
-
- dbg(&udev->dev, "Calling set_configuration\n");
- retval = usb_driver_set_configuration(udev, 1);
- if (retval)
- dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
-
-exit:
- kfree(dummy_buffer);
- return retval;
-}
-
-static int magic_dual_mode(struct usb_device *udev)
-{
- char *dummy_buffer = kzalloc(2, GFP_KERNEL);
- int retval;
-
- if (!dummy_buffer)
- return -ENOMEM;
-
- /* send magic command so that the Blackberry Pearl device exposes
- * two interfaces: both the USB mass-storage one and one which can
- * be used for database access. */
- dbg(&udev->dev, "Sending magic pearl command\n");
- retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- 0xa9, 0xc0, 1, 1, dummy_buffer, 2, 100);
- dbg(&udev->dev, "Magic pearl command returned %d\n", retval);
-
- dbg(&udev->dev, "Calling set_configuration\n");
- retval = usb_driver_set_configuration(udev, 1);
- if (retval)
- dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
-
- kfree(dummy_buffer);
- return retval;
-}
-
-static int berry_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
-
- if (udev->bus_mA < 500) {
- dbg(&udev->dev, "Not enough power to charge available\n");
- return -ENODEV;
- }
-
- dbg(&udev->dev, "Power is set to %dmA\n",
- udev->actconfig->desc.bMaxPower * 2);
-
- /* check the power usage so we don't try to enable something that is
- * already enabled */
- if ((udev->actconfig->desc.bMaxPower * 2) == 500) {
- dbg(&udev->dev, "device is already charging, power is "
- "set to %dmA\n", udev->actconfig->desc.bMaxPower * 2);
- return -ENODEV;
- }
-
- /* turn the power on */
- magic_charge(udev);
-
- if ((le16_to_cpu(udev->descriptor.idProduct) == BLACKBERRY_PEARL) &&
- (pearl_dual_mode))
- magic_dual_mode(udev);
-
- /* we don't really want to bind to the device, userspace programs can
- * handle the syncing just fine, so get outta here. */
- return -ENODEV;
-}
-
-static void berry_disconnect(struct usb_interface *intf)
-{
-}
-
-static struct usb_driver berry_driver = {
- .name = "berry_charge",
- .probe = berry_probe,
- .disconnect = berry_disconnect,
- .id_table = id_table,
-};
-
-static int __init berry_init(void)
-{
- return usb_register(&berry_driver);
-}
-
-static void __exit berry_exit(void)
-{
- usb_deregister(&berry_driver);
-}
-
-module_init(berry_init);
-module_exit(berry_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-module_param(pearl_dual_mode, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(pearl_dual_mode, "Change Blackberry Pearl to run in dual mode");
diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c
index 5720bfef6a38..1547d8cac5fb 100644
--- a/drivers/usb/misc/cypress_cy7c63.c
+++ b/drivers/usb/misc/cypress_cy7c63.c
@@ -56,7 +56,7 @@
/* table of devices that work with this driver */
-static struct usb_device_id cypress_table [] = {
+static const struct usb_device_id cypress_table[] = {
{ USB_DEVICE(CYPRESS_VENDOR_ID, CYPRESS_PRODUCT_ID) },
{ }
};
diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c
index 4fb3c38b924b..b9cbbbda8245 100644
--- a/drivers/usb/misc/cytherm.c
+++ b/drivers/usb/misc/cytherm.c
@@ -27,7 +27,7 @@
#define USB_SKEL_VENDOR_ID 0x04b4
#define USB_SKEL_PRODUCT_ID 0x0002
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
{ }
};
diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c
index 879a980ca8c4..a6521c95f683 100644
--- a/drivers/usb/misc/emi26.c
+++ b/drivers/usb/misc/emi26.c
@@ -245,7 +245,7 @@ wraperr:
return err;
}
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(EMI26_VENDOR_ID, EMI26_PRODUCT_ID) },
{ USB_DEVICE(EMI26_VENDOR_ID, EMI26B_PRODUCT_ID) },
{ } /* Terminating entry */
diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c
index 59860b328534..fc15ad4c3139 100644
--- a/drivers/usb/misc/emi62.c
+++ b/drivers/usb/misc/emi62.c
@@ -259,7 +259,7 @@ wraperr:
return err;
}
-static __devinitdata struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] __devinitconst = {
{ USB_DEVICE(EMI62_VENDOR_ID, EMI62_PRODUCT_ID) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 9d0675ed0d4c..1edb6d361896 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -86,7 +86,7 @@ static struct list_head ftdi_static_list;
#define USB_FTDI_ELAN_VENDOR_ID 0x0403
#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea
/* table of devices that work with this driver*/
-static struct usb_device_id ftdi_elan_table[] = {
+static const struct usb_device_id ftdi_elan_table[] = {
{USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)},
{ /* Terminating entry */ }
};
@@ -623,9 +623,12 @@ static void ftdi_elan_status_work(struct work_struct *work)
*/
static int ftdi_elan_open(struct inode *inode, struct file *file)
{
- int subminor = iminor(inode);
- struct usb_interface *interface = usb_find_interface(&ftdi_elan_driver,
- subminor);
+ int subminor;
+ struct usb_interface *interface;
+
+ subminor = iminor(inode);
+ interface = usb_find_interface(&ftdi_elan_driver, subminor);
+
if (!interface) {
printk(KERN_ERR "can't find device for minor %d\n", subminor);
return -ENODEV;
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 1337a9ce80b9..a54c3cb804ce 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -48,7 +48,7 @@
#define ID_CHERRY 0x0010
/* device ID table */
-static struct usb_device_id idmouse_table[] = {
+static const struct usb_device_id idmouse_table[] = {
{USB_DEVICE(ID_SIEMENS, ID_IDMOUSE)}, /* Siemens ID Mouse (Professional) */
{USB_DEVICE(ID_SIEMENS, ID_CHERRY )}, /* Cherry FingerTIP ID Board */
{} /* terminating null entry */
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index e75bb87ee92b..d3c852363883 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -139,7 +139,7 @@ static int usb_set_report(struct usb_interface *intf, unsigned char type,
/* driver registration */
/*---------------------*/
/* table of devices that work with this driver */
-static struct usb_device_id iowarrior_ids[] = {
+static const struct usb_device_id iowarrior_ids[] = {
{USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40)},
{USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24)},
{USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV1)},
@@ -602,10 +602,12 @@ static int iowarrior_open(struct inode *inode, struct file *file)
dbg("%s", __func__);
+ lock_kernel();
subminor = iminor(inode);
interface = usb_find_interface(&iowarrior_driver, subminor);
if (!interface) {
+ unlock_kernel();
err("%s - error, can't find device for minor %d", __func__,
subminor);
return -ENODEV;
@@ -615,6 +617,7 @@ static int iowarrior_open(struct inode *inode, struct file *file)
dev = usb_get_intfdata(interface);
if (!dev) {
mutex_unlock(&iowarrior_open_disc_lock);
+ unlock_kernel();
return -ENODEV;
}
@@ -641,6 +644,7 @@ static int iowarrior_open(struct inode *inode, struct file *file)
out:
mutex_unlock(&dev->mutex);
+ unlock_kernel();
return retval;
}
diff --git a/drivers/usb/misc/isight_firmware.c b/drivers/usb/misc/isight_firmware.c
index b897f6554ecd..06e990adc6cd 100644
--- a/drivers/usb/misc/isight_firmware.c
+++ b/drivers/usb/misc/isight_firmware.c
@@ -26,7 +26,7 @@
#include <linux/errno.h>
#include <linux/module.h>
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
{USB_DEVICE(0x05ac, 0x8300)},
{},
};
@@ -112,6 +112,8 @@ out:
return ret;
}
+MODULE_FIRMWARE("isight.fw");
+
static void isight_firmware_disconnect(struct usb_interface *intf)
{
}
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 90f130126c10..dd41d8710043 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -69,7 +69,7 @@
#endif
/* table of devices that work with this driver */
-static struct usb_device_id ld_usb_table [] = {
+static const struct usb_device_id ld_usb_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
@@ -798,7 +798,7 @@ static int __init ld_usb_init(void)
/* register this driver with the USB subsystem */
retval = usb_register(&ld_usb_driver);
if (retval)
- err("usb_register failed for the "__FILE__" driver. Error number %d\n", retval);
+ err("usb_register failed for the %s driver. Error number %d\n", __FILE__, retval);
return retval;
}
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index faa6d623de78..8547bf9e3175 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -95,8 +95,11 @@
/* Use our own dbg macro */
#undef dbg
-#define dbg(lvl, format, arg...) do { if (debug >= lvl) printk(KERN_DEBUG __FILE__ ": " format "\n", ## arg); } while (0)
-
+#define dbg(lvl, format, arg...) \
+do { \
+ if (debug >= lvl) \
+ printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \
+} while (0)
/* Version Information */
#define DRIVER_VERSION "v0.96"
@@ -192,7 +195,7 @@ struct tower_get_version_reply {
/* table of devices that work with this driver */
-static struct usb_device_id tower_table [] = {
+static const struct usb_device_id tower_table[] = {
{ USB_DEVICE(LEGO_USB_TOWER_VENDOR_ID, LEGO_USB_TOWER_PRODUCT_ID) },
{ } /* Terminating entry */
};
@@ -302,7 +305,7 @@ static inline void lego_usb_tower_debug_data (int level, const char *function, i
if (debug < level)
return;
- printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", function, size);
+ printk (KERN_DEBUG "%s: %s - length = %d, data = ", __FILE__, function, size);
for (i = 0; i < size; ++i) {
printk ("%.2x ", data[i]);
}
@@ -1055,7 +1058,7 @@ static int __init lego_usb_tower_init(void)
/* register this driver with the USB subsystem */
result = usb_register(&tower_driver);
if (result < 0) {
- err("usb_register failed for the "__FILE__" driver. Error number %d", result);
+ err("usb_register failed for the %s driver. Error number %d", __FILE__, result);
retval = -1;
goto exit;
}
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 32d0199d0c32..a85771b1563d 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -78,10 +78,13 @@ static int open_rio(struct inode *inode, struct file *file)
{
struct rio_usb_data *rio = &rio_instance;
+ /* against disconnect() */
+ lock_kernel();
mutex_lock(&(rio->lock));
if (rio->isopen || !rio->present) {
mutex_unlock(&(rio->lock));
+ unlock_kernel();
return -EBUSY;
}
rio->isopen = 1;
@@ -91,6 +94,7 @@ static int open_rio(struct inode *inode, struct file *file)
mutex_unlock(&(rio->lock));
dev_info(&rio->rio_dev->dev, "Rio opened.\n");
+ unlock_kernel();
return 0;
}
@@ -115,7 +119,6 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
int retries;
int retval=0;
- lock_kernel();
mutex_lock(&(rio->lock));
/* Sanity check to make sure rio is connected, powered, etc */
if (rio->present == 0 || rio->rio_dev == NULL) {
@@ -254,7 +257,6 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
err_out:
mutex_unlock(&(rio->lock));
- unlock_kernel();
return retval;
}
@@ -489,6 +491,7 @@ static void disconnect_rio(struct usb_interface *intf)
struct rio_usb_data *rio = usb_get_intfdata (intf);
usb_set_intfdata (intf, NULL);
+ lock_kernel();
if (rio) {
usb_deregister_dev(intf, &usb_rio_class);
@@ -498,6 +501,7 @@ static void disconnect_rio(struct usb_interface *intf)
/* better let it finish - the release will do whats needed */
rio->rio_dev = NULL;
mutex_unlock(&(rio->lock));
+ unlock_kernel();
return;
}
kfree(rio->ibuf);
@@ -508,9 +512,10 @@ static void disconnect_rio(struct usb_interface *intf)
rio->present = 0;
mutex_unlock(&(rio->lock));
}
+ unlock_kernel();
}
-static struct usb_device_id rio_table [] = {
+static const struct usb_device_id rio_table[] = {
{ USB_DEVICE(0x0841, 1) }, /* Rio 500 */
{ } /* Terminating entry */
};
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 0025847743f3..aae95a009bd5 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -250,7 +250,7 @@ sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe,
sisusb->urbstatus[index] |= SU_URB_BUSY;
/* Submit URB */
- retval = usb_submit_urb(urb, GFP_ATOMIC);
+ retval = usb_submit_urb(urb, GFP_KERNEL);
/* If OK, and if timeout > 0, wait for completion */
if ((retval == 0) && timeout) {
@@ -306,7 +306,7 @@ sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data,
urb->actual_length = 0;
sisusb->completein = 0;
- retval = usb_submit_urb(urb, GFP_ATOMIC);
+ retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval == 0) {
wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
if (!sisusb->completein) {
@@ -2416,21 +2416,28 @@ sisusb_open(struct inode *inode, struct file *file)
struct usb_interface *interface;
int subminor = iminor(inode);
- if (!(interface = usb_find_interface(&sisusb_driver, subminor)))
+ lock_kernel();
+ if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
+ unlock_kernel();
return -ENODEV;
+ }
- if (!(sisusb = usb_get_intfdata(interface)))
+ if (!(sisusb = usb_get_intfdata(interface))) {
+ unlock_kernel();
return -ENODEV;
+ }
mutex_lock(&sisusb->lock);
if (!sisusb->present || !sisusb->ready) {
mutex_unlock(&sisusb->lock);
+ unlock_kernel();
return -ENODEV;
}
if (sisusb->isopen) {
mutex_unlock(&sisusb->lock);
+ unlock_kernel();
return -EBUSY;
}
@@ -2439,11 +2446,13 @@ sisusb_open(struct inode *inode, struct file *file)
if (sisusb_init_gfxdevice(sisusb, 0)) {
mutex_unlock(&sisusb->lock);
dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
+ unlock_kernel();
return -EIO;
}
} else {
mutex_unlock(&sisusb->lock);
dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
+ unlock_kernel();
return -EIO;
}
}
@@ -2456,6 +2465,7 @@ sisusb_open(struct inode *inode, struct file *file)
file->private_data = sisusb;
mutex_unlock(&sisusb->lock);
+ unlock_kernel();
return 0;
}
@@ -3238,13 +3248,14 @@ static void sisusb_disconnect(struct usb_interface *intf)
kref_put(&sisusb->kref, sisusb_delete);
}
-static struct usb_device_id sisusb_table [] = {
+static const struct usb_device_id sisusb_table[] = {
{ USB_DEVICE(0x0711, 0x0550) },
{ USB_DEVICE(0x0711, 0x0900) },
{ USB_DEVICE(0x0711, 0x0901) },
{ USB_DEVICE(0x0711, 0x0902) },
{ USB_DEVICE(0x0711, 0x0903) },
{ USB_DEVICE(0x0711, 0x0918) },
+ { USB_DEVICE(0x0711, 0x0920) },
{ USB_DEVICE(0x182d, 0x021c) },
{ USB_DEVICE(0x182d, 0x0269) },
{ }
diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c
index 2e14102955c5..5da28eaee314 100644
--- a/drivers/usb/misc/trancevibrator.c
+++ b/drivers/usb/misc/trancevibrator.c
@@ -33,7 +33,7 @@
#define TRANCEVIBRATOR_VENDOR_ID 0x0b49 /* ASCII Corporation */
#define TRANCEVIBRATOR_PRODUCT_ID 0x064f /* Trance Vibrator */
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(TRANCEVIBRATOR_VENDOR_ID, TRANCEVIBRATOR_PRODUCT_ID) },
{ },
};
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 4fb120357c55..90aede90553e 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -30,7 +30,7 @@
#define IOCTL_GET_DRV_VERSION 2
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
{ },
};
@@ -74,10 +74,12 @@ static int lcd_open(struct inode *inode, struct file *file)
struct usb_interface *interface;
int subminor, r;
+ lock_kernel();
subminor = iminor(inode);
interface = usb_find_interface(&lcd_driver, subminor);
if (!interface) {
+ unlock_kernel();
err ("USBLCD: %s - error, can't find device for minor %d",
__func__, subminor);
return -ENODEV;
@@ -87,6 +89,7 @@ static int lcd_open(struct inode *inode, struct file *file)
dev = usb_get_intfdata(interface);
if (!dev) {
mutex_unlock(&open_disc_mutex);
+ unlock_kernel();
return -ENODEV;
}
@@ -98,11 +101,13 @@ static int lcd_open(struct inode *inode, struct file *file)
r = usb_autopm_get_interface(interface);
if (r < 0) {
kref_put(&dev->kref, lcd_delete);
+ unlock_kernel();
return r;
}
/* save our object in the file's private structure */
file->private_data = dev;
+ unlock_kernel();
return 0;
}
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
index 06cb71942dc7..63da2c3c838f 100644
--- a/drivers/usb/misc/usbled.c
+++ b/drivers/usb/misc/usbled.c
@@ -24,7 +24,7 @@
#define PRODUCT_ID 0x1223
/* table of devices that work with this driver */
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
{ },
};
diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c
index 3db255537e79..a9555cb901a1 100644
--- a/drivers/usb/misc/usbsevseg.c
+++ b/drivers/usb/misc/usbsevseg.c
@@ -27,7 +27,7 @@
#define MAXLEN 6
/* table of devices that work with this driver */
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
{ },
};
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 3dab0c0b196f..a21cce6f7403 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -1580,10 +1580,6 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
return -ERESTARTSYS;
/* FIXME: What if a system sleep starts while a test is running? */
- if (!intf->is_active) {
- mutex_unlock(&dev->lock);
- return -EHOSTUNREACH;
- }
/* some devices, like ez-usb default devices, need a non-default
* altsetting to have any active endpoints. some tests change
@@ -2101,7 +2097,7 @@ static struct usbtest_info generic_info = {
#endif
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
/*-------------------------------------------------------------*/
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 9a6c27a01793..f56fed53f2dd 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -770,7 +770,7 @@ static void uss720_disconnect(struct usb_interface *intf)
}
/* table of cables that work through this driver */
-static struct usb_device_id uss720_table [] = {
+static const struct usb_device_id uss720_table[] = {
{ USB_DEVICE(0x047e, 0x1001) },
{ USB_DEVICE(0x0557, 0x2001) },
{ USB_DEVICE(0x0729, 0x1284) },
diff --git a/drivers/usb/misc/vstusb.c b/drivers/usb/misc/vstusb.c
deleted file mode 100644
index f26ea8dc1577..000000000000
--- a/drivers/usb/misc/vstusb.c
+++ /dev/null
@@ -1,783 +0,0 @@
-/*****************************************************************************
- * File: drivers/usb/misc/vstusb.c
- *
- * Purpose: Support for the bulk USB Vernier Spectrophotometers
- *
- * Author: Johnnie Peters
- * Axian Consulting
- * Beaverton, OR, USA 97005
- *
- * Modified by: EQware Engineering, Inc.
- * Oregon City, OR, USA 97045
- *
- * Copyright: 2007, 2008
- * Vernier Software & Technology
- * Beaverton, OR, USA 97005
- *
- * Web: www.vernier.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.
- *
- *****************************************************************************/
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-
-#include <linux/usb/vstusb.h>
-
-#define DRIVER_VERSION "VST USB Driver Version 1.5"
-#define DRIVER_DESC "Vernier Software Technology Bulk USB Driver"
-
-#ifdef CONFIG_USB_DYNAMIC_MINORS
- #define VSTUSB_MINOR_BASE 0
-#else
- #define VSTUSB_MINOR_BASE 199
-#endif
-
-#define USB_VENDOR_OCEANOPTICS 0x2457
-#define USB_VENDOR_VERNIER 0x08F7 /* Vernier Software & Technology */
-
-#define USB_PRODUCT_USB2000 0x1002
-#define USB_PRODUCT_ADC1000_FW 0x1003 /* firmware download (renumerates) */
-#define USB_PRODUCT_ADC1000 0x1004
-#define USB_PRODUCT_HR2000_FW 0x1009 /* firmware download (renumerates) */
-#define USB_PRODUCT_HR2000 0x100A
-#define USB_PRODUCT_HR4000_FW 0x1011 /* firmware download (renumerates) */
-#define USB_PRODUCT_HR4000 0x1012
-#define USB_PRODUCT_USB650 0x1014 /* "Red Tide" */
-#define USB_PRODUCT_QE65000 0x1018
-#define USB_PRODUCT_USB4000 0x1022
-#define USB_PRODUCT_USB325 0x1024 /* "Vernier Spectrometer" */
-
-#define USB_PRODUCT_LABPRO 0x0001
-#define USB_PRODUCT_LABQUEST 0x0005
-
-#define VST_MAXBUFFER (64*1024)
-
-static struct usb_device_id id_table[] = {
- { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB2000)},
- { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_HR4000)},
- { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB650)},
- { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB4000)},
- { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB325)},
- { USB_DEVICE(USB_VENDOR_VERNIER, USB_PRODUCT_LABQUEST)},
- { USB_DEVICE(USB_VENDOR_VERNIER, USB_PRODUCT_LABPRO)},
- {},
-};
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-struct vstusb_device {
- struct kref kref;
- struct mutex lock;
- struct usb_device *usb_dev;
- char present;
- char isopen;
- struct usb_anchor submitted;
- int rd_pipe;
- int rd_timeout_ms;
- int wr_pipe;
- int wr_timeout_ms;
-};
-#define to_vst_dev(d) container_of(d, struct vstusb_device, kref)
-
-static struct usb_driver vstusb_driver;
-
-static void vstusb_delete(struct kref *kref)
-{
- struct vstusb_device *vstdev = to_vst_dev(kref);
-
- usb_put_dev(vstdev->usb_dev);
- kfree(vstdev);
-}
-
-static int vstusb_open(struct inode *inode, struct file *file)
-{
- struct vstusb_device *vstdev;
- struct usb_interface *interface;
-
- interface = usb_find_interface(&vstusb_driver, iminor(inode));
-
- if (!interface) {
- printk(KERN_ERR KBUILD_MODNAME
- ": %s - error, can't find device for minor %d\n",
- __func__, iminor(inode));
- return -ENODEV;
- }
-
- vstdev = usb_get_intfdata(interface);
-
- if (!vstdev)
- return -ENODEV;
-
- /* lock this device */
- mutex_lock(&vstdev->lock);
-
- /* can only open one time */
- if ((!vstdev->present) || (vstdev->isopen)) {
- mutex_unlock(&vstdev->lock);
- return -EBUSY;
- }
-
- /* increment our usage count */
- kref_get(&vstdev->kref);
-
- vstdev->isopen = 1;
-
- /* save device in the file's private structure */
- file->private_data = vstdev;
-
- dev_dbg(&vstdev->usb_dev->dev, "%s: opened\n", __func__);
-
- mutex_unlock(&vstdev->lock);
-
- return 0;
-}
-
-static int vstusb_release(struct inode *inode, struct file *file)
-{
- struct vstusb_device *vstdev;
-
- vstdev = file->private_data;
-
- if (vstdev == NULL)
- return -ENODEV;
-
- mutex_lock(&vstdev->lock);
-
- vstdev->isopen = 0;
-
- dev_dbg(&vstdev->usb_dev->dev, "%s: released\n", __func__);
-
- mutex_unlock(&vstdev->lock);
-
- kref_put(&vstdev->kref, vstusb_delete);
-
- return 0;
-}
-
-static void usb_api_blocking_completion(struct urb *urb)
-{
- struct completion *completeit = urb->context;
-
- complete(completeit);
-}
-
-static int vstusb_fill_and_send_urb(struct urb *urb,
- struct usb_device *usb_dev,
- unsigned int pipe, void *data,
- unsigned int len, struct completion *done)
-{
- struct usb_host_endpoint *ep;
- struct usb_host_endpoint **hostep;
- unsigned int pipend;
-
- int status;
-
- hostep = usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out;
- pipend = usb_pipeendpoint(pipe);
- ep = hostep[pipend];
-
- if (!ep || (len == 0))
- return -EINVAL;
-
- if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_INT) {
- pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
- usb_fill_int_urb(urb, usb_dev, pipe, data, len,
- (usb_complete_t)usb_api_blocking_completion,
- NULL, ep->desc.bInterval);
- } else
- usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
- (usb_complete_t)usb_api_blocking_completion,
- NULL);
-
- init_completion(done);
- urb->context = done;
- urb->actual_length = 0;
- status = usb_submit_urb(urb, GFP_KERNEL);
-
- return status;
-}
-
-static int vstusb_complete_urb(struct urb *urb, struct completion *done,
- int timeout, int *actual_length)
-{
- unsigned long expire;
- int status;
-
- expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
- if (!wait_for_completion_interruptible_timeout(done, expire)) {
- usb_kill_urb(urb);
- status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
-
- dev_dbg(&urb->dev->dev,
- "%s timed out on ep%d%s len=%d/%d, urb status = %d\n",
- current->comm,
- usb_pipeendpoint(urb->pipe),
- usb_pipein(urb->pipe) ? "in" : "out",
- urb->actual_length,
- urb->transfer_buffer_length,
- urb->status);
-
- } else {
- if (signal_pending(current)) {
- /* if really an error */
- if (urb->status && !((urb->status == -ENOENT) ||
- (urb->status == -ECONNRESET) ||
- (urb->status == -ESHUTDOWN))) {
- status = -EINTR;
- usb_kill_urb(urb);
- } else {
- status = 0;
- }
-
- dev_dbg(&urb->dev->dev,
- "%s: signal pending on ep%d%s len=%d/%d,"
- "urb status = %d\n",
- current->comm,
- usb_pipeendpoint(urb->pipe),
- usb_pipein(urb->pipe) ? "in" : "out",
- urb->actual_length,
- urb->transfer_buffer_length,
- urb->status);
-
- } else {
- status = urb->status;
- }
- }
-
- if (actual_length)
- *actual_length = urb->actual_length;
-
- return status;
-}
-
-static ssize_t vstusb_read(struct file *file, char __user *buffer,
- size_t count, loff_t *ppos)
-{
- struct vstusb_device *vstdev;
- int cnt = -1;
- void *buf;
- int retval = 0;
-
- struct urb *urb;
- struct usb_device *dev;
- unsigned int pipe;
- int timeout;
-
- DECLARE_COMPLETION_ONSTACK(done);
-
- vstdev = file->private_data;
-
- if (vstdev == NULL)
- return -ENODEV;
-
- /* verify that we actually want to read some data */
- if ((count == 0) || (count > VST_MAXBUFFER))
- return -EINVAL;
-
- /* lock this object */
- if (mutex_lock_interruptible(&vstdev->lock))
- return -ERESTARTSYS;
-
- /* anyone home */
- if (!vstdev->present) {
- mutex_unlock(&vstdev->lock);
- printk(KERN_ERR KBUILD_MODNAME
- ": %s: device not present\n", __func__);
- return -ENODEV;
- }
-
- /* pull out the necessary data */
- dev = vstdev->usb_dev;
- pipe = usb_rcvbulkpipe(dev, vstdev->rd_pipe);
- timeout = vstdev->rd_timeout_ms;
-
- buf = kmalloc(count, GFP_KERNEL);
- if (buf == NULL) {
- mutex_unlock(&vstdev->lock);
- return -ENOMEM;
- }
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- kfree(buf);
- mutex_unlock(&vstdev->lock);
- return -ENOMEM;
- }
-
- usb_anchor_urb(urb, &vstdev->submitted);
- retval = vstusb_fill_and_send_urb(urb, dev, pipe, buf, count, &done);
- mutex_unlock(&vstdev->lock);
- if (retval) {
- usb_unanchor_urb(urb);
- dev_err(&dev->dev, "%s: error %d filling and sending urb %d\n",
- __func__, retval, pipe);
- goto exit;
- }
-
- retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
- if (retval) {
- dev_err(&dev->dev, "%s: error %d completing urb %d\n",
- __func__, retval, pipe);
- goto exit;
- }
-
- if (copy_to_user(buffer, buf, cnt)) {
- dev_err(&dev->dev, "%s: can't copy_to_user\n", __func__);
- retval = -EFAULT;
- } else {
- retval = cnt;
- dev_dbg(&dev->dev, "%s: read %d bytes from pipe %d\n",
- __func__, cnt, pipe);
- }
-
-exit:
- usb_free_urb(urb);
- kfree(buf);
- return retval;
-}
-
-static ssize_t vstusb_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *ppos)
-{
- struct vstusb_device *vstdev;
- int cnt = -1;
- void *buf;
- int retval = 0;
-
- struct urb *urb;
- struct usb_device *dev;
- unsigned int pipe;
- int timeout;
-
- DECLARE_COMPLETION_ONSTACK(done);
-
- vstdev = file->private_data;
-
- if (vstdev == NULL)
- return -ENODEV;
-
- /* verify that we actually have some data to write */
- if ((count == 0) || (count > VST_MAXBUFFER))
- return retval;
-
- /* lock this object */
- if (mutex_lock_interruptible(&vstdev->lock))
- return -ERESTARTSYS;
-
- /* anyone home */
- if (!vstdev->present) {
- mutex_unlock(&vstdev->lock);
- printk(KERN_ERR KBUILD_MODNAME
- ": %s: device not present\n", __func__);
- return -ENODEV;
- }
-
- /* pull out the necessary data */
- dev = vstdev->usb_dev;
- pipe = usb_sndbulkpipe(dev, vstdev->wr_pipe);
- timeout = vstdev->wr_timeout_ms;
-
- buf = kmalloc(count, GFP_KERNEL);
- if (buf == NULL) {
- mutex_unlock(&vstdev->lock);
- return -ENOMEM;
- }
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- kfree(buf);
- mutex_unlock(&vstdev->lock);
- return -ENOMEM;
- }
-
- if (copy_from_user(buf, buffer, count)) {
- mutex_unlock(&vstdev->lock);
- dev_err(&dev->dev, "%s: can't copy_from_user\n", __func__);
- retval = -EFAULT;
- goto exit;
- }
-
- usb_anchor_urb(urb, &vstdev->submitted);
- retval = vstusb_fill_and_send_urb(urb, dev, pipe, buf, count, &done);
- mutex_unlock(&vstdev->lock);
- if (retval) {
- usb_unanchor_urb(urb);
- dev_err(&dev->dev, "%s: error %d filling and sending urb %d\n",
- __func__, retval, pipe);
- goto exit;
- }
-
- retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
- if (retval) {
- dev_err(&dev->dev, "%s: error %d completing urb %d\n",
- __func__, retval, pipe);
- goto exit;
- } else {
- retval = cnt;
- dev_dbg(&dev->dev, "%s: sent %d bytes to pipe %d\n",
- __func__, cnt, pipe);
- }
-
-exit:
- usb_free_urb(urb);
- kfree(buf);
- return retval;
-}
-
-static long vstusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- int retval = 0;
- int cnt = -1;
- void __user *data = (void __user *)arg;
- struct vstusb_args usb_data;
-
- struct vstusb_device *vstdev;
- void *buffer = NULL; /* must be initialized. buffer is
- * referenced on exit but not all
- * ioctls allocate it */
-
- struct urb *urb = NULL; /* must be initialized. urb is
- * referenced on exit but not all
- * ioctls allocate it */
- struct usb_device *dev;
- unsigned int pipe;
- int timeout;
-
- DECLARE_COMPLETION_ONSTACK(done);
-
- vstdev = file->private_data;
-
- if (_IOC_TYPE(cmd) != VST_IOC_MAGIC) {
- dev_warn(&vstdev->usb_dev->dev,
- "%s: ioctl command %x, bad ioctl magic %x, "
- "expected %x\n", __func__, cmd,
- _IOC_TYPE(cmd), VST_IOC_MAGIC);
- return -EINVAL;
- }
-
- if (vstdev == NULL)
- return -ENODEV;
-
- if (copy_from_user(&usb_data, data, sizeof(struct vstusb_args))) {
- dev_err(&vstdev->usb_dev->dev, "%s: can't copy_from_user\n",
- __func__);
- return -EFAULT;
- }
-
- /* lock this object */
- if (mutex_lock_interruptible(&vstdev->lock)) {
- retval = -ERESTARTSYS;
- goto exit;
- }
-
- /* anyone home */
- if (!vstdev->present) {
- mutex_unlock(&vstdev->lock);
- dev_err(&vstdev->usb_dev->dev, "%s: device not present\n",
- __func__);
- retval = -ENODEV;
- goto exit;
- }
-
- /* pull out the necessary data */
- dev = vstdev->usb_dev;
-
- switch (cmd) {
-
- case IOCTL_VSTUSB_CONFIG_RW:
-
- vstdev->rd_pipe = usb_data.rd_pipe;
- vstdev->rd_timeout_ms = usb_data.rd_timeout_ms;
- vstdev->wr_pipe = usb_data.wr_pipe;
- vstdev->wr_timeout_ms = usb_data.wr_timeout_ms;
-
- mutex_unlock(&vstdev->lock);
-
- dev_dbg(&dev->dev, "%s: setting pipes/timeouts, "
- "rdpipe = %d, rdtimeout = %d, "
- "wrpipe = %d, wrtimeout = %d\n", __func__,
- vstdev->rd_pipe, vstdev->rd_timeout_ms,
- vstdev->wr_pipe, vstdev->wr_timeout_ms);
- break;
-
- case IOCTL_VSTUSB_SEND_PIPE:
-
- if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) {
- mutex_unlock(&vstdev->lock);
- retval = -EINVAL;
- goto exit;
- }
-
- buffer = kmalloc(usb_data.count, GFP_KERNEL);
- if (buffer == NULL) {
- mutex_unlock(&vstdev->lock);
- retval = -ENOMEM;
- goto exit;
- }
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- mutex_unlock(&vstdev->lock);
- retval = -ENOMEM;
- goto exit;
- }
-
- timeout = usb_data.timeout_ms;
-
- pipe = usb_sndbulkpipe(dev, usb_data.pipe);
-
- if (copy_from_user(buffer, usb_data.buffer, usb_data.count)) {
- dev_err(&dev->dev, "%s: can't copy_from_user\n",
- __func__);
- mutex_unlock(&vstdev->lock);
- retval = -EFAULT;
- goto exit;
- }
-
- usb_anchor_urb(urb, &vstdev->submitted);
- retval = vstusb_fill_and_send_urb(urb, dev, pipe, buffer,
- usb_data.count, &done);
- mutex_unlock(&vstdev->lock);
- if (retval) {
- usb_unanchor_urb(urb);
- dev_err(&dev->dev,
- "%s: error %d filling and sending urb %d\n",
- __func__, retval, pipe);
- goto exit;
- }
-
- retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
- if (retval) {
- dev_err(&dev->dev, "%s: error %d completing urb %d\n",
- __func__, retval, pipe);
- }
-
- break;
- case IOCTL_VSTUSB_RECV_PIPE:
-
- if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) {
- mutex_unlock(&vstdev->lock);
- retval = -EINVAL;
- goto exit;
- }
-
- buffer = kmalloc(usb_data.count, GFP_KERNEL);
- if (buffer == NULL) {
- mutex_unlock(&vstdev->lock);
- retval = -ENOMEM;
- goto exit;
- }
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- mutex_unlock(&vstdev->lock);
- retval = -ENOMEM;
- goto exit;
- }
-
- timeout = usb_data.timeout_ms;
-
- pipe = usb_rcvbulkpipe(dev, usb_data.pipe);
-
- usb_anchor_urb(urb, &vstdev->submitted);
- retval = vstusb_fill_and_send_urb(urb, dev, pipe, buffer,
- usb_data.count, &done);
- mutex_unlock(&vstdev->lock);
- if (retval) {
- usb_unanchor_urb(urb);
- dev_err(&dev->dev,
- "%s: error %d filling and sending urb %d\n",
- __func__, retval, pipe);
- goto exit;
- }
-
- retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
- if (retval) {
- dev_err(&dev->dev, "%s: error %d completing urb %d\n",
- __func__, retval, pipe);
- goto exit;
- }
-
- if (copy_to_user(usb_data.buffer, buffer, cnt)) {
- dev_err(&dev->dev, "%s: can't copy_to_user\n",
- __func__);
- retval = -EFAULT;
- goto exit;
- }
-
- usb_data.count = cnt;
- if (copy_to_user(data, &usb_data, sizeof(struct vstusb_args))) {
- dev_err(&dev->dev, "%s: can't copy_to_user\n",
- __func__);
- retval = -EFAULT;
- } else {
- dev_dbg(&dev->dev, "%s: recv %zd bytes from pipe %d\n",
- __func__, usb_data.count, usb_data.pipe);
- }
-
- break;
-
- default:
- mutex_unlock(&vstdev->lock);
- dev_warn(&dev->dev, "ioctl_vstusb: invalid ioctl cmd %x\n",
- cmd);
- return -EINVAL;
- break;
- }
-exit:
- usb_free_urb(urb);
- kfree(buffer);
- return retval;
-}
-
-static const struct file_operations vstusb_fops = {
- .owner = THIS_MODULE,
- .read = vstusb_read,
- .write = vstusb_write,
- .unlocked_ioctl = vstusb_ioctl,
- .compat_ioctl = vstusb_ioctl,
- .open = vstusb_open,
- .release = vstusb_release,
-};
-
-static struct usb_class_driver usb_vstusb_class = {
- .name = "usb/vstusb%d",
- .fops = &vstusb_fops,
- .minor_base = VSTUSB_MINOR_BASE,
-};
-
-static int vstusb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct vstusb_device *vstdev;
- int i;
- int retval = 0;
-
- /* allocate memory for our device state and intialize it */
-
- vstdev = kzalloc(sizeof(*vstdev), GFP_KERNEL);
- if (vstdev == NULL)
- return -ENOMEM;
-
- /* must do usb_get_dev() prior to kref_init() since the kref_put()
- * release function will do a usb_put_dev() */
- usb_get_dev(dev);
- kref_init(&vstdev->kref);
- mutex_init(&vstdev->lock);
-
- i = dev->descriptor.bcdDevice;
-
- dev_dbg(&intf->dev, "Version %1d%1d.%1d%1d found at address %d\n",
- (i & 0xF000) >> 12, (i & 0xF00) >> 8,
- (i & 0xF0) >> 4, (i & 0xF), dev->devnum);
-
- vstdev->present = 1;
- vstdev->isopen = 0;
- vstdev->usb_dev = dev;
- init_usb_anchor(&vstdev->submitted);
-
- usb_set_intfdata(intf, vstdev);
- retval = usb_register_dev(intf, &usb_vstusb_class);
- if (retval) {
- dev_err(&intf->dev,
- "%s: Not able to get a minor for this device.\n",
- __func__);
- usb_set_intfdata(intf, NULL);
- kref_put(&vstdev->kref, vstusb_delete);
- return retval;
- }
-
- /* let the user know what node this device is now attached to */
- dev_info(&intf->dev,
- "VST USB Device #%d now attached to major %d minor %d\n",
- (intf->minor - VSTUSB_MINOR_BASE), USB_MAJOR, intf->minor);
-
- dev_info(&intf->dev, "%s, %s\n", DRIVER_DESC, DRIVER_VERSION);
-
- return retval;
-}
-
-static void vstusb_disconnect(struct usb_interface *intf)
-{
- struct vstusb_device *vstdev = usb_get_intfdata(intf);
-
- usb_deregister_dev(intf, &usb_vstusb_class);
- usb_set_intfdata(intf, NULL);
-
- if (vstdev) {
-
- mutex_lock(&vstdev->lock);
- vstdev->present = 0;
-
- usb_kill_anchored_urbs(&vstdev->submitted);
-
- mutex_unlock(&vstdev->lock);
-
- kref_put(&vstdev->kref, vstusb_delete);
- }
-
-}
-
-static int vstusb_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct vstusb_device *vstdev = usb_get_intfdata(intf);
- int time;
- if (!vstdev)
- return 0;
-
- mutex_lock(&vstdev->lock);
- time = usb_wait_anchor_empty_timeout(&vstdev->submitted, 1000);
- if (!time)
- usb_kill_anchored_urbs(&vstdev->submitted);
- mutex_unlock(&vstdev->lock);
-
- return 0;
-}
-
-static int vstusb_resume(struct usb_interface *intf)
-{
- return 0;
-}
-
-static struct usb_driver vstusb_driver = {
- .name = "vstusb",
- .probe = vstusb_probe,
- .disconnect = vstusb_disconnect,
- .suspend = vstusb_suspend,
- .resume = vstusb_resume,
- .id_table = id_table,
-};
-
-static int __init vstusb_init(void)
-{
- int rc;
-
- rc = usb_register(&vstusb_driver);
- if (rc)
- printk(KERN_ERR "%s: failed to register (%d)", __func__, rc);
-
- return rc;
-}
-
-static void __exit vstusb_exit(void)
-{
- usb_deregister(&vstusb_driver);
-}
-
-module_init(vstusb_init);
-module_exit(vstusb_exit);
-
-MODULE_AUTHOR("Dennis O'Brien/Stephen Ware");
-MODULE_DESCRIPTION(DRIVER_VERSION);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index 385ec0520167..6dd44bc1f5ff 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -460,8 +460,8 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
char ev_type, int status)
{
const struct usb_endpoint_descriptor *epd = &urb->ep->desc;
- unsigned long flags;
struct timeval ts;
+ unsigned long flags;
unsigned int urb_length;
unsigned int offset;
unsigned int length;
@@ -600,10 +600,13 @@ static void mon_bin_complete(void *data, struct urb *urb, int status)
static void mon_bin_error(void *data, struct urb *urb, int error)
{
struct mon_reader_bin *rp = data;
+ struct timeval ts;
unsigned long flags;
unsigned int offset;
struct mon_bin_hdr *ep;
+ do_gettimeofday(&ts);
+
spin_lock_irqsave(&rp->b_lock, flags);
offset = mon_buff_area_alloc(rp, PKT_SIZE);
@@ -623,6 +626,8 @@ static void mon_bin_error(void *data, struct urb *urb, int error)
ep->devnum = urb->dev->devnum;
ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
+ ep->ts_sec = ts.tv_sec;
+ ep->ts_usec = ts.tv_usec;
ep->status = error;
ep->flag_setup = '-';
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 047568ff223d..31c11888ec6a 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -180,7 +180,7 @@ static inline unsigned int mon_get_timestamp(void)
unsigned int stamp;
do_gettimeofday(&tval);
- stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s. */
+ stamp = tval.tv_sec & 0xFFF; /* 2^32 = 4294967296. Limit to 4096s. */
stamp = stamp * 1000000 + tval.tv_usec;
return stamp;
}
@@ -273,12 +273,12 @@ static void mon_text_error(void *data, struct urb *urb, int error)
ep->type = 'E';
ep->id = (unsigned long) urb;
- ep->busnum = 0;
+ ep->busnum = urb->dev->bus->busnum;
ep->devnum = urb->dev->devnum;
ep->epnum = usb_endpoint_num(&urb->ep->desc);
ep->xfertype = usb_endpoint_type(&urb->ep->desc);
ep->is_in = usb_urb_dir_in(urb);
- ep->tstamp = 0;
+ ep->tstamp = mon_get_timestamp();
ep->length = 0;
ep->status = error;
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index d9db86498022..b4c783c284ba 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -37,7 +37,7 @@ config USB_MUSB_SOC
depends on USB_MUSB_HDRC
default y if ARCH_DAVINCI
default y if ARCH_OMAP2430
- default y if ARCH_OMAP34XX
+ default y if ARCH_OMAP3
default y if (BF54x && !BF544)
default y if (BF52x && !BF522 && !BF523)
@@ -48,7 +48,7 @@ comment "OMAP 243x high speed USB support"
depends on USB_MUSB_HDRC && ARCH_OMAP2430
comment "OMAP 343x high speed USB support"
- depends on USB_MUSB_HDRC && ARCH_OMAP34XX
+ depends on USB_MUSB_HDRC && ARCH_OMAP3
comment "Blackfin high speed USB Support"
depends on USB_MUSB_HDRC && ((BF54x && !BF544) || (BF52x && !BF522 && !BF523))
@@ -153,7 +153,7 @@ config MUSB_PIO_ONLY
config USB_INVENTRA_DMA
bool
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
- default ARCH_OMAP2430 || ARCH_OMAP34XX || BLACKFIN
+ default ARCH_OMAP2430 || ARCH_OMAP3 || BLACKFIN
help
Enable DMA transfers using Mentor's engine.
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index ad26e6569665..bcee1339d4fd 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -30,7 +30,6 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
void __iomem *fifo = hw_ep->fifo;
void __iomem *epio = hw_ep->regs;
u8 epnum = hw_ep->epnum;
- u16 dma_reg = 0;
prefetch((u8 *)src);
@@ -42,15 +41,17 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
dump_fifo_data(src, len);
if (!ANOMALY_05000380 && epnum != 0) {
- flush_dcache_range((unsigned int)src,
- (unsigned int)(src + len));
+ u16 dma_reg;
+
+ flush_dcache_range((unsigned long)src,
+ (unsigned long)(src + len));
/* Setup DMA address register */
- dma_reg = (u16) ((u32) src & 0xFFFF);
+ dma_reg = (u32)src;
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
SSYNC();
- dma_reg = (u16) (((u32) src >> 16) & 0xFFFF);
+ dma_reg = (u32)src >> 16;
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
SSYNC();
@@ -79,12 +80,9 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
SSYNC();
if (unlikely((unsigned long)src & 0x01))
- outsw_8((unsigned long)fifo, src,
- len & 0x01 ? (len >> 1) + 1 : len >> 1);
+ outsw_8((unsigned long)fifo, src, (len + 1) >> 1);
else
- outsw((unsigned long)fifo, src,
- len & 0x01 ? (len >> 1) + 1 : len >> 1);
-
+ outsw((unsigned long)fifo, src, (len + 1) >> 1);
}
}
/*
@@ -94,19 +92,19 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
{
void __iomem *fifo = hw_ep->fifo;
u8 epnum = hw_ep->epnum;
- u16 dma_reg = 0;
if (ANOMALY_05000467 && epnum != 0) {
+ u16 dma_reg;
- invalidate_dcache_range((unsigned int)dst,
- (unsigned int)(dst + len));
+ invalidate_dcache_range((unsigned long)dst,
+ (unsigned long)(dst + len));
/* Setup DMA address register */
- dma_reg = (u16) ((u32) dst & 0xFFFF);
+ dma_reg = (u32)dst;
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
SSYNC();
- dma_reg = (u16) (((u32) dst >> 16) & 0xFFFF);
+ dma_reg = (u32)dst >> 16;
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
SSYNC();
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index a44a450c860d..3c69a76ec392 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -1191,8 +1191,13 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
bd = tx_ch->head;
+ /*
+ * If Head is null then this could mean that a abort interrupt
+ * that needs to be acknowledged.
+ */
if (NULL == bd) {
DBG(1, "null BD\n");
+ tx_ram->tx_complete = 0;
continue;
}
@@ -1412,15 +1417,6 @@ static int cppi_channel_abort(struct dma_channel *channel)
if (cppi_ch->transmit) {
struct cppi_tx_stateram __iomem *tx_ram;
- int enabled;
-
- /* mask interrupts raised to signal teardown complete. */
- enabled = musb_readl(tibase, DAVINCI_TXCPPI_INTENAB_REG)
- & (1 << cppi_ch->index);
- if (enabled)
- musb_writel(tibase, DAVINCI_TXCPPI_INTCLR_REG,
- (1 << cppi_ch->index));
-
/* REVISIT put timeouts on these controller handshakes */
cppi_dump_tx(6, cppi_ch, " (teardown)");
@@ -1435,7 +1431,6 @@ static int cppi_channel_abort(struct dma_channel *channel)
do {
value = musb_readl(&tx_ram->tx_complete, 0);
} while (0xFFFFFFFC != value);
- musb_writel(&tx_ram->tx_complete, 0, 0xFFFFFFFC);
/* FIXME clean up the transfer state ... here?
* the completion routine should get called with
@@ -1448,23 +1443,15 @@ static int cppi_channel_abort(struct dma_channel *channel)
musb_writew(regs, MUSB_TXCSR, value);
musb_writew(regs, MUSB_TXCSR, value);
- /* While we scrub the TX state RAM, ensure that we clean
- * up any interrupt that's currently asserted:
+ /*
* 1. Write to completion Ptr value 0x1(bit 0 set)
* (write back mode)
- * 2. Write to completion Ptr value 0x0(bit 0 cleared)
- * (compare mode)
- * Value written is compared(for bits 31:2) and when
- * equal, interrupt is deasserted.
+ * 2. Wait for abort interrupt and then put the channel in
+ * compare mode by writing 1 to the tx_complete register.
*/
cppi_reset_tx(tx_ram, 1);
- musb_writel(&tx_ram->tx_complete, 0, 0);
-
- /* re-enable interrupt */
- if (enabled)
- musb_writel(tibase, DAVINCI_TXCPPI_INTENAB_REG,
- (1 << cppi_ch->index));
-
+ cppi_ch->head = 0;
+ musb_writel(&tx_ram->tx_complete, 0, 1);
cppi_dump_tx(5, cppi_ch, " (done teardown)");
/* REVISIT tx side _should_ clean up the same way
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index 66913811af5e..a883f9dd3f8a 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -274,7 +274,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
/* NOTE: DaVinci shadows the Mentor IRQs. Don't manage them through
* the Mentor registers (except for setup), use the TI ones and EOI.
*
- * Docs describe irq "vector" registers asociated with the CPPI and
+ * Docs describe irq "vector" registers associated with the CPPI and
* USB EOI registers. These hold a bitmask corresponding to the
* current IRQ, not an irq handler address. Would using those bits
* resolve some of the races observed in this dispatch code??
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 5eb9318cff77..b4bbf8f2c238 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -557,6 +557,69 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
handled = IRQ_HANDLED;
}
+
+ if (int_usb & MUSB_INTR_SUSPEND) {
+ DBG(1, "SUSPEND (%s) devctl %02x power %02x\n",
+ otg_state_string(musb), devctl, power);
+ handled = IRQ_HANDLED;
+
+ switch (musb->xceiv->state) {
+#ifdef CONFIG_USB_MUSB_OTG
+ case OTG_STATE_A_PERIPHERAL:
+ /* We also come here if the cable is removed, since
+ * this silicon doesn't report ID-no-longer-grounded.
+ *
+ * We depend on T(a_wait_bcon) to shut us down, and
+ * hope users don't do anything dicey during this
+ * undesired detour through A_WAIT_BCON.
+ */
+ musb_hnp_stop(musb);
+ usb_hcd_resume_root_hub(musb_to_hcd(musb));
+ musb_root_disconnect(musb);
+ musb_platform_try_idle(musb, jiffies
+ + msecs_to_jiffies(musb->a_wait_bcon
+ ? : OTG_TIME_A_WAIT_BCON));
+
+ break;
+#endif
+ case OTG_STATE_B_IDLE:
+ if (!musb->is_active)
+ break;
+ case OTG_STATE_B_PERIPHERAL:
+ musb_g_suspend(musb);
+ musb->is_active = is_otg_enabled(musb)
+ && musb->xceiv->gadget->b_hnp_enable;
+ if (musb->is_active) {
+#ifdef CONFIG_USB_MUSB_OTG
+ musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
+ DBG(1, "HNP: Setting timer for b_ase0_brst\n");
+ mod_timer(&musb->otg_timer, jiffies
+ + msecs_to_jiffies(
+ OTG_TIME_B_ASE0_BRST));
+#endif
+ }
+ break;
+ case OTG_STATE_A_WAIT_BCON:
+ if (musb->a_wait_bcon != 0)
+ musb_platform_try_idle(musb, jiffies
+ + msecs_to_jiffies(musb->a_wait_bcon));
+ break;
+ case OTG_STATE_A_HOST:
+ musb->xceiv->state = OTG_STATE_A_SUSPEND;
+ musb->is_active = is_otg_enabled(musb)
+ && musb->xceiv->host->b_hnp_enable;
+ break;
+ case OTG_STATE_B_HOST:
+ /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
+ DBG(1, "REVISIT: SUSPEND as B_HOST\n");
+ break;
+ default:
+ /* "should not happen" */
+ musb->is_active = 0;
+ break;
+ }
+ }
+
if (int_usb & MUSB_INTR_CONNECT) {
struct usb_hcd *hcd = musb_to_hcd(musb);
@@ -625,10 +688,61 @@ b_host:
}
#endif /* CONFIG_USB_MUSB_HDRC_HCD */
+ if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
+ DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n",
+ otg_state_string(musb),
+ MUSB_MODE(musb), devctl);
+ handled = IRQ_HANDLED;
+
+ switch (musb->xceiv->state) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ case OTG_STATE_A_HOST:
+ case OTG_STATE_A_SUSPEND:
+ usb_hcd_resume_root_hub(musb_to_hcd(musb));
+ musb_root_disconnect(musb);
+ if (musb->a_wait_bcon != 0 && is_otg_enabled(musb))
+ musb_platform_try_idle(musb, jiffies
+ + msecs_to_jiffies(musb->a_wait_bcon));
+ break;
+#endif /* HOST */
+#ifdef CONFIG_USB_MUSB_OTG
+ case OTG_STATE_B_HOST:
+ /* REVISIT this behaves for "real disconnect"
+ * cases; make sure the other transitions from
+ * from B_HOST act right too. The B_HOST code
+ * in hnp_stop() is currently not used...
+ */
+ musb_root_disconnect(musb);
+ musb_to_hcd(musb)->self.is_b_host = 0;
+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ MUSB_DEV_MODE(musb);
+ musb_g_disconnect(musb);
+ break;
+ case OTG_STATE_A_PERIPHERAL:
+ musb_hnp_stop(musb);
+ musb_root_disconnect(musb);
+ /* FALLTHROUGH */
+ case OTG_STATE_B_WAIT_ACON:
+ /* FALLTHROUGH */
+#endif /* OTG */
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ case OTG_STATE_B_PERIPHERAL:
+ case OTG_STATE_B_IDLE:
+ musb_g_disconnect(musb);
+ break;
+#endif /* GADGET */
+ default:
+ WARNING("unhandled DISCONNECT transition (%s)\n",
+ otg_state_string(musb));
+ break;
+ }
+ }
+
/* mentor saves a bit: bus reset and babble share the same irq.
* only host sees babble; only peripheral sees bus reset.
*/
if (int_usb & MUSB_INTR_RESET) {
+ handled = IRQ_HANDLED;
if (is_host_capable() && (devctl & MUSB_DEVCTL_HM) != 0) {
/*
* Looks like non-HS BABBLE can be ignored, but
@@ -641,7 +755,7 @@ b_host:
DBG(1, "BABBLE devctl: %02x\n", devctl);
else {
ERR("Stopping host session -- babble\n");
- musb_writeb(mbase, MUSB_DEVCTL, 0);
+ musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
}
} else if (is_peripheral_capable()) {
DBG(1, "BUS RESET as %s\n", otg_state_string(musb));
@@ -686,29 +800,7 @@ b_host:
otg_state_string(musb));
}
}
-
- handled = IRQ_HANDLED;
}
- schedule_work(&musb->irq_work);
-
- return handled;
-}
-
-/*
- * Interrupt Service Routine to record USB "global" interrupts.
- * Since these do not happen often and signify things of
- * paramount importance, it seems OK to check them individually;
- * the order of the tests is specified in the manual
- *
- * @param musb instance pointer
- * @param int_usb register contents
- * @param devctl
- * @param power
- */
-static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
- u8 devctl, u8 power)
-{
- irqreturn_t handled = IRQ_NONE;
#if 0
/* REVISIT ... this would be for multiplexing periodic endpoints, or
@@ -755,117 +847,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
}
#endif
- if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
- DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n",
- otg_state_string(musb),
- MUSB_MODE(musb), devctl);
- handled = IRQ_HANDLED;
-
- switch (musb->xceiv->state) {
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
- case OTG_STATE_A_HOST:
- case OTG_STATE_A_SUSPEND:
- usb_hcd_resume_root_hub(musb_to_hcd(musb));
- musb_root_disconnect(musb);
- if (musb->a_wait_bcon != 0 && is_otg_enabled(musb))
- musb_platform_try_idle(musb, jiffies
- + msecs_to_jiffies(musb->a_wait_bcon));
- break;
-#endif /* HOST */
-#ifdef CONFIG_USB_MUSB_OTG
- case OTG_STATE_B_HOST:
- /* REVISIT this behaves for "real disconnect"
- * cases; make sure the other transitions from
- * from B_HOST act right too. The B_HOST code
- * in hnp_stop() is currently not used...
- */
- musb_root_disconnect(musb);
- musb_to_hcd(musb)->self.is_b_host = 0;
- musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
- MUSB_DEV_MODE(musb);
- musb_g_disconnect(musb);
- break;
- case OTG_STATE_A_PERIPHERAL:
- musb_hnp_stop(musb);
- musb_root_disconnect(musb);
- /* FALLTHROUGH */
- case OTG_STATE_B_WAIT_ACON:
- /* FALLTHROUGH */
-#endif /* OTG */
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
- case OTG_STATE_B_PERIPHERAL:
- case OTG_STATE_B_IDLE:
- musb_g_disconnect(musb);
- break;
-#endif /* GADGET */
- default:
- WARNING("unhandled DISCONNECT transition (%s)\n",
- otg_state_string(musb));
- break;
- }
-
- schedule_work(&musb->irq_work);
- }
-
- if (int_usb & MUSB_INTR_SUSPEND) {
- DBG(1, "SUSPEND (%s) devctl %02x power %02x\n",
- otg_state_string(musb), devctl, power);
- handled = IRQ_HANDLED;
-
- switch (musb->xceiv->state) {
-#ifdef CONFIG_USB_MUSB_OTG
- case OTG_STATE_A_PERIPHERAL:
- /* We also come here if the cable is removed, since
- * this silicon doesn't report ID-no-longer-grounded.
- *
- * We depend on T(a_wait_bcon) to shut us down, and
- * hope users don't do anything dicey during this
- * undesired detour through A_WAIT_BCON.
- */
- musb_hnp_stop(musb);
- usb_hcd_resume_root_hub(musb_to_hcd(musb));
- musb_root_disconnect(musb);
- musb_platform_try_idle(musb, jiffies
- + msecs_to_jiffies(musb->a_wait_bcon
- ? : OTG_TIME_A_WAIT_BCON));
- break;
-#endif
- case OTG_STATE_B_PERIPHERAL:
- musb_g_suspend(musb);
- musb->is_active = is_otg_enabled(musb)
- && musb->xceiv->gadget->b_hnp_enable;
- if (musb->is_active) {
-#ifdef CONFIG_USB_MUSB_OTG
- musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
- DBG(1, "HNP: Setting timer for b_ase0_brst\n");
- mod_timer(&musb->otg_timer, jiffies
- + msecs_to_jiffies(
- OTG_TIME_B_ASE0_BRST));
-#endif
- }
- break;
- case OTG_STATE_A_WAIT_BCON:
- if (musb->a_wait_bcon != 0)
- musb_platform_try_idle(musb, jiffies
- + msecs_to_jiffies(musb->a_wait_bcon));
- break;
- case OTG_STATE_A_HOST:
- musb->xceiv->state = OTG_STATE_A_SUSPEND;
- musb->is_active = is_otg_enabled(musb)
- && musb->xceiv->host->b_hnp_enable;
- break;
- case OTG_STATE_B_HOST:
- /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
- DBG(1, "REVISIT: SUSPEND as B_HOST\n");
- break;
- default:
- /* "should not happen" */
- musb->is_active = 0;
- break;
- }
- schedule_work(&musb->irq_work);
- }
-
+ schedule_work(&musb->irq_work);
return handled;
}
@@ -1000,7 +982,7 @@ static void musb_shutdown(struct platform_device *pdev)
* more than selecting one of a bunch of predefined configurations.
*/
#if defined(CONFIG_USB_TUSB6010) || \
- defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+ defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
static ushort __initdata fifo_mode = 4;
#else
static ushort __initdata fifo_mode = 2;
@@ -1095,6 +1077,36 @@ static struct fifo_cfg __initdata mode_4_cfg[] = {
{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
};
+/* mode 5 - fits in 8KB */
+static struct fifo_cfg __initdata mode_5_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 8, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 512, },
+{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },
+{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
+};
/*
* configure a fifo; for non-shared endpoints, this may be called
@@ -1210,6 +1222,10 @@ static int __init ep_config_from_table(struct musb *musb)
cfg = mode_4_cfg;
n = ARRAY_SIZE(mode_4_cfg);
break;
+ case 5:
+ cfg = mode_5_cfg;
+ n = ARRAY_SIZE(mode_5_cfg);
+ break;
}
printk(KERN_DEBUG "%s: setup fifo_mode %d\n",
@@ -1314,9 +1330,6 @@ enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, };
*/
static int __init musb_core_init(u16 musb_type, struct musb *musb)
{
-#ifdef MUSB_AHB_ID
- u32 data;
-#endif
u8 reg;
char *type;
char aInfo[90], aRevision[32], aDate[12];
@@ -1328,23 +1341,17 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
reg = musb_read_configdata(mbase);
strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8");
- if (reg & MUSB_CONFIGDATA_DYNFIFO)
+ if (reg & MUSB_CONFIGDATA_DYNFIFO) {
strcat(aInfo, ", dyn FIFOs");
+ musb->dyn_fifo = true;
+ }
if (reg & MUSB_CONFIGDATA_MPRXE) {
strcat(aInfo, ", bulk combine");
-#ifdef C_MP_RX
musb->bulk_combine = true;
-#else
- strcat(aInfo, " (X)"); /* no driver support */
-#endif
}
if (reg & MUSB_CONFIGDATA_MPTXE) {
strcat(aInfo, ", bulk split");
-#ifdef C_MP_TX
musb->bulk_split = true;
-#else
- strcat(aInfo, " (X)"); /* no driver support */
-#endif
}
if (reg & MUSB_CONFIGDATA_HBRXE) {
strcat(aInfo, ", HB-ISO Rx");
@@ -1360,20 +1367,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
printk(KERN_DEBUG "%s: ConfigData=0x%02x (%s)\n",
musb_driver_name, reg, aInfo);
-#ifdef MUSB_AHB_ID
- data = musb_readl(mbase, 0x404);
- sprintf(aDate, "%04d-%02x-%02x", (data & 0xffff),
- (data >> 16) & 0xff, (data >> 24) & 0xff);
- /* FIXME ID2 and ID3 are unused */
- data = musb_readl(mbase, 0x408);
- printk(KERN_DEBUG "ID2=%lx\n", (long unsigned)data);
- data = musb_readl(mbase, 0x40c);
- printk(KERN_DEBUG "ID3=%lx\n", (long unsigned)data);
- reg = musb_readb(mbase, 0x400);
- musb_type = ('M' == reg) ? MUSB_CONTROLLER_MHDRC : MUSB_CONTROLLER_HDRC;
-#else
aDate[0] = 0;
-#endif
if (MUSB_CONTROLLER_MHDRC == musb_type) {
musb->is_multipoint = 1;
type = "M";
@@ -1404,21 +1398,10 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
musb->nr_endpoints = 1;
musb->epmask = 1;
- if (reg & MUSB_CONFIGDATA_DYNFIFO) {
- if (musb->config->dyn_fifo)
- status = ep_config_from_table(musb);
- else {
- ERR("reconfigure software for Dynamic FIFOs\n");
- status = -ENODEV;
- }
- } else {
- if (!musb->config->dyn_fifo)
- status = ep_config_from_hw(musb);
- else {
- ERR("reconfigure software for static FIFOs\n");
- return -ENODEV;
- }
- }
+ if (musb->dyn_fifo)
+ status = ep_config_from_table(musb);
+ else
+ status = ep_config_from_hw(musb);
if (status < 0)
return status;
@@ -1587,11 +1570,6 @@ irqreturn_t musb_interrupt(struct musb *musb)
ep_num++;
}
- /* finish handling "global" interrupts after handling fifos */
- if (musb->int_usb)
- retval |= musb_stage2_irq(musb,
- musb->int_usb, devctl, power);
-
return retval;
}
@@ -1696,7 +1674,7 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
unsigned long val;
if (sscanf(buf, "%lu", &val) < 1) {
- printk(KERN_ERR "Invalid VBUS timeout ms value\n");
+ dev_err(dev, "Invalid VBUS timeout ms value\n");
return -EINVAL;
}
@@ -1746,7 +1724,7 @@ musb_srp_store(struct device *dev, struct device_attribute *attr,
if (sscanf(buf, "%hu", &srp) != 1
|| (srp != 1)) {
- printk(KERN_ERR "SRP: Value must be 1\n");
+ dev_err(dev, "SRP: Value must be 1\n");
return -EINVAL;
}
@@ -1759,6 +1737,19 @@ static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store);
#endif /* CONFIG_USB_GADGET_MUSB_HDRC */
+static struct attribute *musb_attributes[] = {
+ &dev_attr_mode.attr,
+ &dev_attr_vbus.attr,
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ &dev_attr_srp.attr,
+#endif
+ NULL
+};
+
+static const struct attribute_group musb_attr_group = {
+ .attrs = musb_attributes,
+};
+
#endif /* sysfs */
/* Only used to provide driver mode change events */
@@ -1833,11 +1824,7 @@ static void musb_free(struct musb *musb)
*/
#ifdef CONFIG_SYSFS
- device_remove_file(musb->controller, &dev_attr_mode);
- device_remove_file(musb->controller, &dev_attr_vbus);
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
- device_remove_file(musb->controller, &dev_attr_srp);
-#endif
+ sysfs_remove_group(&musb->controller->kobj, &musb_attr_group);
#endif
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
@@ -2017,22 +2004,10 @@ bad_config:
musb->irq_wake = 0;
}
- pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n",
- musb_driver_name,
- ({char *s;
- switch (musb->board_mode) {
- case MUSB_HOST: s = "Host"; break;
- case MUSB_PERIPHERAL: s = "Peripheral"; break;
- default: s = "OTG"; break;
- }; s; }),
- ctrl,
- (is_dma_capable() && musb->dma_controller)
- ? "DMA" : "PIO",
- musb->nIrq);
-
/* host side needs more setup */
if (is_host_enabled(musb)) {
struct usb_hcd *hcd = musb_to_hcd(musb);
+ u8 busctl;
otg_set_host(musb->xceiv, &hcd->self);
@@ -2040,6 +2015,13 @@ bad_config:
hcd->self.otg_port = 1;
musb->xceiv->host = &hcd->self;
hcd->power_budget = 2 * (plat->power ? : 250);
+
+ /* program PHY to use external vBus if required */
+ if (plat->extvbus) {
+ busctl = musb_readb(musb->mregs, MUSB_ULPI_BUSCONTROL);
+ busctl |= MUSB_ULPI_USE_EXTVBUS;
+ musb_writeb(musb->mregs, MUSB_ULPI_BUSCONTROL, busctl);
+ }
}
/* For the host-only role, we can activate right away.
@@ -2079,26 +2061,26 @@ bad_config:
}
#ifdef CONFIG_SYSFS
- status = device_create_file(dev, &dev_attr_mode);
- status = device_create_file(dev, &dev_attr_vbus);
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
- status = device_create_file(dev, &dev_attr_srp);
-#endif /* CONFIG_USB_GADGET_MUSB_HDRC */
- status = 0;
+ status = sysfs_create_group(&musb->controller->kobj, &musb_attr_group);
#endif
if (status)
goto fail2;
+ dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n",
+ ({char *s;
+ switch (musb->board_mode) {
+ case MUSB_HOST: s = "Host"; break;
+ case MUSB_PERIPHERAL: s = "Peripheral"; break;
+ default: s = "OTG"; break;
+ }; s; }),
+ ctrl,
+ (is_dma_capable() && musb->dma_controller)
+ ? "DMA" : "PIO",
+ musb->nIrq);
+
return 0;
fail2:
-#ifdef CONFIG_SYSFS
- device_remove_file(musb->controller, &dev_attr_mode);
- device_remove_file(musb->controller, &dev_attr_vbus);
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
- device_remove_file(musb->controller, &dev_attr_srp);
-#endif
-#endif
musb_platform_exit(musb);
fail:
dev_err(musb->controller,
@@ -2127,6 +2109,7 @@ static int __init musb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int irq = platform_get_irq(pdev, 0);
+ int status;
struct resource *iomem;
void __iomem *base;
@@ -2134,7 +2117,7 @@ static int __init musb_probe(struct platform_device *pdev)
if (!iomem || irq == 0)
return -ENODEV;
- base = ioremap(iomem->start, iomem->end - iomem->start + 1);
+ base = ioremap(iomem->start, resource_size(iomem));
if (!base) {
dev_err(dev, "ioremap failed\n");
return -ENOMEM;
@@ -2144,7 +2127,12 @@ static int __init musb_probe(struct platform_device *pdev)
/* clobbered by use_dma=n */
orig_dma_mask = dev->dma_mask;
#endif
- return musb_init_controller(dev, irq, base);
+
+ status = musb_init_controller(dev, irq, base);
+ if (status < 0)
+ iounmap(base);
+
+ return status;
}
static int __exit musb_remove(struct platform_device *pdev)
@@ -2173,6 +2161,148 @@ static int __exit musb_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
+static struct musb_context_registers musb_context;
+
+void musb_save_context(struct musb *musb)
+{
+ int i;
+ void __iomem *musb_base = musb->mregs;
+
+ if (is_host_enabled(musb)) {
+ musb_context.frame = musb_readw(musb_base, MUSB_FRAME);
+ musb_context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
+ }
+ musb_context.power = musb_readb(musb_base, MUSB_POWER);
+ musb_context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
+ musb_context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
+ musb_context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
+ musb_context.index = musb_readb(musb_base, MUSB_INDEX);
+ musb_context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
+
+ for (i = 0; i < MUSB_C_NUM_EPS; ++i) {
+ musb_writeb(musb_base, MUSB_INDEX, i);
+ musb_context.index_regs[i].txmaxp =
+ musb_readw(musb_base, 0x10 + MUSB_TXMAXP);
+ musb_context.index_regs[i].txcsr =
+ musb_readw(musb_base, 0x10 + MUSB_TXCSR);
+ musb_context.index_regs[i].rxmaxp =
+ musb_readw(musb_base, 0x10 + MUSB_RXMAXP);
+ musb_context.index_regs[i].rxcsr =
+ musb_readw(musb_base, 0x10 + MUSB_RXCSR);
+
+ if (musb->dyn_fifo) {
+ musb_context.index_regs[i].txfifoadd =
+ musb_read_txfifoadd(musb_base);
+ musb_context.index_regs[i].rxfifoadd =
+ musb_read_rxfifoadd(musb_base);
+ musb_context.index_regs[i].txfifosz =
+ musb_read_txfifosz(musb_base);
+ musb_context.index_regs[i].rxfifosz =
+ musb_read_rxfifosz(musb_base);
+ }
+ if (is_host_enabled(musb)) {
+ musb_context.index_regs[i].txtype =
+ musb_readb(musb_base, 0x10 + MUSB_TXTYPE);
+ musb_context.index_regs[i].txinterval =
+ musb_readb(musb_base, 0x10 + MUSB_TXINTERVAL);
+ musb_context.index_regs[i].rxtype =
+ musb_readb(musb_base, 0x10 + MUSB_RXTYPE);
+ musb_context.index_regs[i].rxinterval =
+ musb_readb(musb_base, 0x10 + MUSB_RXINTERVAL);
+
+ musb_context.index_regs[i].txfunaddr =
+ musb_read_txfunaddr(musb_base, i);
+ musb_context.index_regs[i].txhubaddr =
+ musb_read_txhubaddr(musb_base, i);
+ musb_context.index_regs[i].txhubport =
+ musb_read_txhubport(musb_base, i);
+
+ musb_context.index_regs[i].rxfunaddr =
+ musb_read_rxfunaddr(musb_base, i);
+ musb_context.index_regs[i].rxhubaddr =
+ musb_read_rxhubaddr(musb_base, i);
+ musb_context.index_regs[i].rxhubport =
+ musb_read_rxhubport(musb_base, i);
+ }
+ }
+
+ musb_writeb(musb_base, MUSB_INDEX, musb_context.index);
+
+ musb_platform_save_context(musb, &musb_context);
+}
+
+void musb_restore_context(struct musb *musb)
+{
+ int i;
+ void __iomem *musb_base = musb->mregs;
+ void __iomem *ep_target_regs;
+
+ musb_platform_restore_context(musb, &musb_context);
+
+ if (is_host_enabled(musb)) {
+ musb_writew(musb_base, MUSB_FRAME, musb_context.frame);
+ musb_writeb(musb_base, MUSB_TESTMODE, musb_context.testmode);
+ }
+ musb_writeb(musb_base, MUSB_POWER, musb_context.power);
+ musb_writew(musb_base, MUSB_INTRTXE, musb_context.intrtxe);
+ musb_writew(musb_base, MUSB_INTRRXE, musb_context.intrrxe);
+ musb_writeb(musb_base, MUSB_INTRUSBE, musb_context.intrusbe);
+ musb_writeb(musb_base, MUSB_DEVCTL, musb_context.devctl);
+
+ for (i = 0; i < MUSB_C_NUM_EPS; ++i) {
+ musb_writeb(musb_base, MUSB_INDEX, i);
+ musb_writew(musb_base, 0x10 + MUSB_TXMAXP,
+ musb_context.index_regs[i].txmaxp);
+ musb_writew(musb_base, 0x10 + MUSB_TXCSR,
+ musb_context.index_regs[i].txcsr);
+ musb_writew(musb_base, 0x10 + MUSB_RXMAXP,
+ musb_context.index_regs[i].rxmaxp);
+ musb_writew(musb_base, 0x10 + MUSB_RXCSR,
+ musb_context.index_regs[i].rxcsr);
+
+ if (musb->dyn_fifo) {
+ musb_write_txfifosz(musb_base,
+ musb_context.index_regs[i].txfifosz);
+ musb_write_rxfifosz(musb_base,
+ musb_context.index_regs[i].rxfifosz);
+ musb_write_txfifoadd(musb_base,
+ musb_context.index_regs[i].txfifoadd);
+ musb_write_rxfifoadd(musb_base,
+ musb_context.index_regs[i].rxfifoadd);
+ }
+
+ if (is_host_enabled(musb)) {
+ musb_writeb(musb_base, 0x10 + MUSB_TXTYPE,
+ musb_context.index_regs[i].txtype);
+ musb_writeb(musb_base, 0x10 + MUSB_TXINTERVAL,
+ musb_context.index_regs[i].txinterval);
+ musb_writeb(musb_base, 0x10 + MUSB_RXTYPE,
+ musb_context.index_regs[i].rxtype);
+ musb_writeb(musb_base, 0x10 + MUSB_RXINTERVAL,
+
+ musb_context.index_regs[i].rxinterval);
+ musb_write_txfunaddr(musb_base, i,
+ musb_context.index_regs[i].txfunaddr);
+ musb_write_txhubaddr(musb_base, i,
+ musb_context.index_regs[i].txhubaddr);
+ musb_write_txhubport(musb_base, i,
+ musb_context.index_regs[i].txhubport);
+
+ ep_target_regs =
+ musb_read_target_reg_base(i, musb_base);
+
+ musb_write_rxfunaddr(ep_target_regs,
+ musb_context.index_regs[i].rxfunaddr);
+ musb_write_rxhubaddr(ep_target_regs,
+ musb_context.index_regs[i].rxhubaddr);
+ musb_write_rxhubport(ep_target_regs,
+ musb_context.index_regs[i].rxhubport);
+ }
+ }
+
+ musb_writeb(musb_base, MUSB_INDEX, musb_context.index);
+}
+
static int musb_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -2194,6 +2324,8 @@ static int musb_suspend(struct device *dev)
*/
}
+ musb_save_context(musb);
+
if (musb->set_clock)
musb->set_clock(musb->clock, 0);
else
@@ -2215,6 +2347,8 @@ static int musb_resume_noirq(struct device *dev)
else
clk_enable(musb->clock);
+ musb_restore_context(musb);
+
/* for static cmos like DaVinci, register values were preserved
* unless for some reason the whole soc powered down or the USB
* module got reset through the PSC (vs just being disabled).
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 03d50909b078..d849fb81c131 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -52,6 +52,15 @@ struct musb;
struct musb_hw_ep;
struct musb_ep;
+/* Helper defines for struct musb->hwvers */
+#define MUSB_HWVERS_MAJOR(x) ((x >> 10) & 0x1f)
+#define MUSB_HWVERS_MINOR(x) (x & 0x3ff)
+#define MUSB_HWVERS_RC 0x8000
+#define MUSB_HWVERS_1300 0x52C
+#define MUSB_HWVERS_1400 0x590
+#define MUSB_HWVERS_1800 0x720
+#define MUSB_HWVERS_1900 0x784
+#define MUSB_HWVERS_2000 0x800
#include "musb_debug.h"
#include "musb_dma.h"
@@ -322,13 +331,6 @@ struct musb {
struct clk *clock;
irqreturn_t (*isr)(int, void *);
struct work_struct irq_work;
-#define MUSB_HWVERS_MAJOR(x) ((x >> 10) & 0x1f)
-#define MUSB_HWVERS_MINOR(x) (x & 0x3ff)
-#define MUSB_HWVERS_RC 0x8000
-#define MUSB_HWVERS_1300 0x52C
-#define MUSB_HWVERS_1400 0x590
-#define MUSB_HWVERS_1800 0x720
-#define MUSB_HWVERS_2000 0x800
u16 hwvers;
/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
@@ -411,22 +413,15 @@ struct musb {
unsigned hb_iso_rx:1; /* high bandwidth iso rx? */
unsigned hb_iso_tx:1; /* high bandwidth iso tx? */
+ unsigned dyn_fifo:1; /* dynamic FIFO supported? */
-#ifdef C_MP_TX
- unsigned bulk_split:1;
+ unsigned bulk_split:1;
#define can_bulk_split(musb,type) \
- (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split)
-#else
-#define can_bulk_split(musb, type) 0
-#endif
+ (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split)
-#ifdef C_MP_RX
- unsigned bulk_combine:1;
+ unsigned bulk_combine:1;
#define can_bulk_combine(musb,type) \
- (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine)
-#else
-#define can_bulk_combine(musb, type) 0
-#endif
+ (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine)
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
/* is_suspended means USB B_PERIPHERAL suspend */
@@ -461,6 +456,45 @@ struct musb {
#endif
};
+#ifdef CONFIG_PM
+struct musb_csr_regs {
+ /* FIFO registers */
+ u16 txmaxp, txcsr, rxmaxp, rxcsr;
+ u16 rxfifoadd, txfifoadd;
+ u8 txtype, txinterval, rxtype, rxinterval;
+ u8 rxfifosz, txfifosz;
+ u8 txfunaddr, txhubaddr, txhubport;
+ u8 rxfunaddr, rxhubaddr, rxhubport;
+};
+
+struct musb_context_registers {
+
+#if defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP2430)
+ u32 otg_sysconfig, otg_forcestandby;
+#endif
+ u8 power;
+ u16 intrtxe, intrrxe;
+ u8 intrusbe;
+ u16 frame;
+ u8 index, testmode;
+
+ u8 devctl, misc;
+
+ struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
+};
+
+#if defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP2430)
+extern void musb_platform_save_context(struct musb *musb,
+ struct musb_context_registers *musb_context);
+extern void musb_platform_restore_context(struct musb *musb,
+ struct musb_context_registers *musb_context);
+#else
+#define musb_platform_save_context(m, x) do {} while (0)
+#define musb_platform_restore_context(m, x) do {} while (0)
+#endif
+
+#endif
+
static inline void musb_set_vbus(struct musb *musb, int is_on)
{
musb->board_set_vbus(musb, is_on);
@@ -562,7 +596,7 @@ extern void musb_hnp_stop(struct musb *musb);
extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode);
#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) || \
- defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+ defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout);
#else
#define musb_platform_try_idle(x, y) do {} while (0)
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index cbcf14a236e6..a9f288cd70ed 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -895,7 +895,14 @@ static int musb_gadget_enable(struct usb_ep *ep,
/* REVISIT if can_bulk_split(), use by updating "tmp";
* likewise high bandwidth periodic tx
*/
- musb_writew(regs, MUSB_TXMAXP, tmp);
+ /* Set TXMAXP with the FIFO size of the endpoint
+ * to disable double buffering mode. Currently, It seems that double
+ * buffering has problem if musb RTL revision number < 2.0.
+ */
+ if (musb->hwvers < MUSB_HWVERS_2000)
+ musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
+ else
+ musb_writew(regs, MUSB_TXMAXP, tmp);
csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
if (musb_readw(regs, MUSB_TXCSR)
@@ -925,7 +932,13 @@ static int musb_gadget_enable(struct usb_ep *ep,
/* REVISIT if can_bulk_combine() use by updating "tmp"
* likewise high bandwidth periodic rx
*/
- musb_writew(regs, MUSB_RXMAXP, tmp);
+ /* Set RXMAXP with the FIFO size of the endpoint
+ * to disable double buffering mode.
+ */
+ if (musb->hwvers < MUSB_HWVERS_2000)
+ musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_rx);
+ else
+ musb_writew(regs, MUSB_RXMAXP, tmp);
/* force shared fifo to OUT-only mode */
if (hw_ep->is_shared_fifo) {
@@ -1697,8 +1710,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
return -EINVAL;
/* driver must be initialized to support peripheral mode */
- if (!musb || !(musb->board_mode == MUSB_OTG
- || musb->board_mode != MUSB_OTG)) {
+ if (!musb) {
DBG(1, "%s, no dev??\n", __func__);
return -ENODEV;
}
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 74c4c3698f1e..3421cf9858b5 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -605,8 +605,14 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
musb_writeb(ep->regs, MUSB_RXTYPE, qh->type_reg);
musb_writeb(ep->regs, MUSB_RXINTERVAL, qh->intv_reg);
/* NOTE: bulk combining rewrites high bits of maxpacket */
- musb_writew(ep->regs, MUSB_RXMAXP,
- qh->maxpacket | ((qh->hb_mult - 1) << 11));
+ /* Set RXMAXP with the FIFO size of the endpoint
+ * to disable double buffer mode.
+ */
+ if (musb->hwvers < MUSB_HWVERS_2000)
+ musb_writew(ep->regs, MUSB_RXMAXP, ep->max_packet_sz_rx);
+ else
+ musb_writew(ep->regs, MUSB_RXMAXP,
+ qh->maxpacket | ((qh->hb_mult - 1) << 11));
ep->rx_reinit = 0;
}
@@ -1771,6 +1777,9 @@ static int musb_schedule(
int best_end, epnum;
struct musb_hw_ep *hw_ep = NULL;
struct list_head *head = NULL;
+ u8 toggle;
+ u8 txtype;
+ struct urb *urb = next_urb(qh);
/* use fixed hardware for control and bulk */
if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
@@ -1809,6 +1818,27 @@ static int musb_schedule(
diff -= (qh->maxpacket * qh->hb_mult);
if (diff >= 0 && best_diff > diff) {
+
+ /*
+ * Mentor controller has a bug in that if we schedule
+ * a BULK Tx transfer on an endpoint that had earlier
+ * handled ISOC then the BULK transfer has to start on
+ * a zero toggle. If the BULK transfer starts on a 1
+ * toggle then this transfer will fail as the mentor
+ * controller starts the Bulk transfer on a 0 toggle
+ * irrespective of the programming of the toggle bits
+ * in the TXCSR register. Check for this condition
+ * while allocating the EP for a Tx Bulk transfer. If
+ * so skip this EP.
+ */
+ hw_ep = musb->endpoints + epnum;
+ toggle = usb_gettoggle(urb->dev, qh->epnum, !is_in);
+ txtype = (musb_readb(hw_ep->regs, MUSB_TXTYPE)
+ >> 4) & 0x3;
+ if (!is_in && (qh->type == USB_ENDPOINT_XFER_BULK) &&
+ toggle && (txtype == USB_ENDPOINT_XFER_ISOC))
+ continue;
+
best_diff = diff;
best_end = epnum;
}
diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h
index 473a94ef905f..8d8062b10e2f 100644
--- a/drivers/usb/musb/musb_regs.h
+++ b/drivers/usb/musb/musb_regs.h
@@ -72,6 +72,10 @@
#define MUSB_DEVCTL_HR 0x02
#define MUSB_DEVCTL_SESSION 0x01
+/* MUSB ULPI VBUSCONTROL */
+#define MUSB_ULPI_USE_EXTVBUS 0x01
+#define MUSB_ULPI_USE_EXTVBUSIND 0x02
+
/* TESTMODE */
#define MUSB_TEST_FORCE_HOST 0x80
#define MUSB_TEST_FIFO_ACCESS 0x40
@@ -246,6 +250,7 @@
/* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */
#define MUSB_HWVERS 0x6C /* 8 bit */
+#define MUSB_ULPI_BUSCONTROL 0x70 /* 8 bit */
#define MUSB_EPINFO 0x78 /* 8 bit */
#define MUSB_RAMINFO 0x79 /* 8 bit */
@@ -321,6 +326,26 @@ static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
musb_writew(mbase, MUSB_RXFIFOADD, c_off);
}
+static inline u8 musb_read_txfifosz(void __iomem *mbase)
+{
+ return musb_readb(mbase, MUSB_TXFIFOSZ);
+}
+
+static inline u16 musb_read_txfifoadd(void __iomem *mbase)
+{
+ return musb_readw(mbase, MUSB_TXFIFOADD);
+}
+
+static inline u8 musb_read_rxfifosz(void __iomem *mbase)
+{
+ return musb_readb(mbase, MUSB_RXFIFOSZ);
+}
+
+static inline u16 musb_read_rxfifoadd(void __iomem *mbase)
+{
+ return musb_readw(mbase, MUSB_RXFIFOADD);
+}
+
static inline u8 musb_read_configdata(void __iomem *mbase)
{
musb_writeb(mbase, MUSB_INDEX, 0);
@@ -376,6 +401,36 @@ static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
qh_h_port_reg);
}
+static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum)
+{
+ return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXFUNCADDR));
+}
+
+static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum)
+{
+ return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBADDR));
+}
+
+static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum)
+{
+ return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBPORT));
+}
+
+static inline u8 musb_read_txfunaddr(void __iomem *mbase, u8 epnum)
+{
+ return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR));
+}
+
+static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
+{
+ return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR));
+}
+
+static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum)
+{
+ return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT));
+}
+
#else /* CONFIG_BLACKFIN */
#define USB_BASE USB_FADDR
@@ -436,7 +491,7 @@ static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
#define MUSB_FLAT_OFFSET(_epnum, _offset) \
(USB_OFFSET(USB_EP_NI0_TXMAXP) + (0x40 * (_epnum)) + (_offset))
-/* Not implemented - HW has seperate Tx/Rx FIFO */
+/* Not implemented - HW has separate Tx/Rx FIFO */
#define MUSB_TXCSR_MODE 0x0000
static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
@@ -455,6 +510,22 @@ static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
{
}
+static inline u8 musb_read_txfifosz(void __iomem *mbase)
+{
+}
+
+static inline u16 musb_read_txfifoadd(void __iomem *mbase)
+{
+}
+
+static inline u8 musb_read_rxfifosz(void __iomem *mbase)
+{
+}
+
+static inline u16 musb_read_rxfifoadd(void __iomem *mbase)
+{
+}
+
static inline u8 musb_read_configdata(void __iomem *mbase)
{
return 0;
@@ -462,7 +533,11 @@ static inline u8 musb_read_configdata(void __iomem *mbase)
static inline u16 musb_read_hwvers(void __iomem *mbase)
{
- return 0;
+ /*
+ * This register is invisible on Blackfin, actually the MUSB
+ * RTL version of Blackfin is 1.9, so just harcode its value.
+ */
+ return MUSB_HWVERS_1900;
}
static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
@@ -500,6 +575,30 @@ static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
{
}
+static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline u8 musb_read_txfunaddr(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline void musb_read_txhubport(void __iomem *mbase, u8 epnum)
+{
+}
+
#endif /* CONFIG_BLACKFIN */
#endif /* __MUSB_REGS_H__ */
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index a237550f91bf..2fa7d5c00f31 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -250,20 +250,39 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
u8 bchannel;
u8 int_hsdma;
- u32 addr;
+ u32 addr, count;
u16 csr;
spin_lock_irqsave(&musb->lock, flags);
int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR);
- if (!int_hsdma)
- goto done;
#ifdef CONFIG_BLACKFIN
/* Clear DMA interrupt flags */
musb_writeb(mbase, MUSB_HSDMA_INTR, int_hsdma);
#endif
+ if (!int_hsdma) {
+ DBG(2, "spurious DMA irq\n");
+
+ for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
+ musb_channel = (struct musb_dma_channel *)
+ &(controller->channel[bchannel]);
+ channel = &musb_channel->channel;
+ if (channel->status == MUSB_DMA_STATUS_BUSY) {
+ count = musb_read_hsdma_count(mbase, bchannel);
+
+ if (count == 0)
+ int_hsdma |= (1 << bchannel);
+ }
+ }
+
+ DBG(2, "int_hsdma = 0x%x\n", int_hsdma);
+
+ if (!int_hsdma)
+ goto done;
+ }
+
for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
if (int_hsdma & (1 << bchannel)) {
musb_channel = (struct musb_dma_channel *)
diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h
index 1299d92dc83f..613f95a058f7 100644
--- a/drivers/usb/musb/musbhsdma.h
+++ b/drivers/usb/musb/musbhsdma.h
@@ -55,6 +55,10 @@
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS), \
addr)
+#define musb_read_hsdma_count(mbase, bchannel) \
+ musb_readl(mbase, \
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT))
+
#define musb_write_hsdma_count(mbase, bchannel, len) \
musb_writel(mbase, \
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT), \
@@ -96,6 +100,19 @@ static inline void musb_write_hsdma_addr(void __iomem *mbase,
((u16)(((u32) dma_addr >> 16) & 0xFFFF)));
}
+static inline u32 musb_read_hsdma_count(void __iomem *mbase, u8 bchannel)
+{
+ u32 count = musb_readw(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH));
+
+ count = count << 16;
+
+ count |= musb_readw(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW));
+
+ return count;
+}
+
static inline void musb_write_hsdma_count(void __iomem *mbase,
u8 bchannel, u32 len)
{
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 83beeac5e7bf..3fe16867b5a8 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -220,7 +220,7 @@ int __init musb_platform_init(struct musb *musb)
musb_platform_resume(musb);
- l = omap_readl(OTG_SYSCONFIG);
+ l = musb_readl(musb->mregs, OTG_SYSCONFIG);
l &= ~ENABLEWAKEUP; /* disable wakeup */
l &= ~NOSTDBY; /* remove possible nostdby */
l |= SMARTSTDBY; /* enable smart standby */
@@ -233,17 +233,19 @@ int __init musb_platform_init(struct musb *musb)
*/
if (!cpu_is_omap3430())
l |= AUTOIDLE; /* enable auto idle */
- omap_writel(l, OTG_SYSCONFIG);
+ musb_writel(musb->mregs, OTG_SYSCONFIG, l);
- l = omap_readl(OTG_INTERFSEL);
+ l = musb_readl(musb->mregs, OTG_INTERFSEL);
l |= ULPI_12PIN;
- omap_writel(l, OTG_INTERFSEL);
+ musb_writel(musb->mregs, OTG_INTERFSEL, l);
pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
"sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n",
- omap_readl(OTG_REVISION), omap_readl(OTG_SYSCONFIG),
- omap_readl(OTG_SYSSTATUS), omap_readl(OTG_INTERFSEL),
- omap_readl(OTG_SIMENABLE));
+ musb_readl(musb->mregs, OTG_REVISION),
+ musb_readl(musb->mregs, OTG_SYSCONFIG),
+ musb_readl(musb->mregs, OTG_SYSSTATUS),
+ musb_readl(musb->mregs, OTG_INTERFSEL),
+ musb_readl(musb->mregs, OTG_SIMENABLE));
omap_vbus_power(musb, musb->board_mode == MUSB_HOST, 1);
@@ -255,6 +257,22 @@ int __init musb_platform_init(struct musb *musb)
return 0;
}
+#ifdef CONFIG_PM
+void musb_platform_save_context(struct musb *musb,
+ struct musb_context_registers *musb_context)
+{
+ musb_context->otg_sysconfig = musb_readl(musb->mregs, OTG_SYSCONFIG);
+ musb_context->otg_forcestandby = musb_readl(musb->mregs, OTG_FORCESTDBY);
+}
+
+void musb_platform_restore_context(struct musb *musb,
+ struct musb_context_registers *musb_context)
+{
+ musb_writel(musb->mregs, OTG_SYSCONFIG, musb_context->otg_sysconfig);
+ musb_writel(musb->mregs, OTG_FORCESTDBY, musb_context->otg_forcestandby);
+}
+#endif
+
int musb_platform_suspend(struct musb *musb)
{
u32 l;
@@ -263,13 +281,13 @@ int musb_platform_suspend(struct musb *musb)
return 0;
/* in any role */
- l = omap_readl(OTG_FORCESTDBY);
+ l = musb_readl(musb->mregs, OTG_FORCESTDBY);
l |= ENABLEFORCE; /* enable MSTANDBY */
- omap_writel(l, OTG_FORCESTDBY);
+ musb_writel(musb->mregs, OTG_FORCESTDBY, l);
- l = omap_readl(OTG_SYSCONFIG);
+ l = musb_readl(musb->mregs, OTG_SYSCONFIG);
l |= ENABLEWAKEUP; /* enable wakeup */
- omap_writel(l, OTG_SYSCONFIG);
+ musb_writel(musb->mregs, OTG_SYSCONFIG, l);
otg_set_suspend(musb->xceiv, 1);
@@ -295,13 +313,13 @@ static int musb_platform_resume(struct musb *musb)
else
clk_enable(musb->clock);
- l = omap_readl(OTG_SYSCONFIG);
+ l = musb_readl(musb->mregs, OTG_SYSCONFIG);
l &= ~ENABLEWAKEUP; /* disable wakeup */
- omap_writel(l, OTG_SYSCONFIG);
+ musb_writel(musb->mregs, OTG_SYSCONFIG, l);
- l = omap_readl(OTG_FORCESTDBY);
+ l = musb_readl(musb->mregs, OTG_FORCESTDBY);
l &= ~ENABLEFORCE; /* disable MSTANDBY */
- omap_writel(l, OTG_FORCESTDBY);
+ musb_writel(musb->mregs, OTG_FORCESTDBY, l);
return 0;
}
diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h
index fbede7798aed..40b3c02ae9f0 100644
--- a/drivers/usb/musb/omap2430.h
+++ b/drivers/usb/musb/omap2430.h
@@ -10,47 +10,43 @@
#ifndef __MUSB_OMAP243X_H__
#define __MUSB_OMAP243X_H__
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
-#include <mach/hardware.h>
#include <plat/usb.h>
/*
* OMAP2430-specific definitions
*/
-#define MENTOR_BASE_OFFSET 0
-#if defined(CONFIG_ARCH_OMAP2430)
-#define OMAP_HSOTG_BASE (OMAP243X_HS_BASE)
-#elif defined(CONFIG_ARCH_OMAP3430)
-#define OMAP_HSOTG_BASE (OMAP34XX_HSUSB_OTG_BASE)
-#endif
-#define OMAP_HSOTG(offset) (OMAP_HSOTG_BASE + 0x400 + (offset))
-#define OTG_REVISION OMAP_HSOTG(0x0)
-#define OTG_SYSCONFIG OMAP_HSOTG(0x4)
+#define OTG_REVISION 0x400
+
+#define OTG_SYSCONFIG 0x404
# define MIDLEMODE 12 /* bit position */
# define FORCESTDBY (0 << MIDLEMODE)
# define NOSTDBY (1 << MIDLEMODE)
# define SMARTSTDBY (2 << MIDLEMODE)
+
# define SIDLEMODE 3 /* bit position */
# define FORCEIDLE (0 << SIDLEMODE)
# define NOIDLE (1 << SIDLEMODE)
# define SMARTIDLE (2 << SIDLEMODE)
+
# define ENABLEWAKEUP (1 << 2)
# define SOFTRST (1 << 1)
# define AUTOIDLE (1 << 0)
-#define OTG_SYSSTATUS OMAP_HSOTG(0x8)
+
+#define OTG_SYSSTATUS 0x408
# define RESETDONE (1 << 0)
-#define OTG_INTERFSEL OMAP_HSOTG(0xc)
+
+#define OTG_INTERFSEL 0x40c
# define EXTCP (1 << 2)
-# define PHYSEL 0 /* bit position */
+# define PHYSEL 0 /* bit position */
# define UTMI_8BIT (0 << PHYSEL)
# define ULPI_12PIN (1 << PHYSEL)
# define ULPI_8PIN (2 << PHYSEL)
-#define OTG_SIMENABLE OMAP_HSOTG(0x10)
+
+#define OTG_SIMENABLE 0x410
# define TM1 (1 << 0)
-#define OTG_FORCESTDBY OMAP_HSOTG(0x14)
-# define ENABLEFORCE (1 << 0)
-#endif /* CONFIG_ARCH_OMAP2430 */
+#define OTG_FORCESTDBY 0x414
+# define ENABLEFORCE (1 << 0)
#endif /* __MUSB_OMAP243X_H__ */
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 88b587c703e9..ab776a8d98ca 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -1118,7 +1118,7 @@ int __init musb_platform_init(struct musb *musb)
}
musb->sync = mem->start;
- sync = ioremap(mem->start, mem->end - mem->start + 1);
+ sync = ioremap(mem->start, resource_size(mem));
if (!sync) {
pr_debug("ioremap for sync failed\n");
ret = -ENOMEM;
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
index e13c77052e5e..1c868096bd6f 100644
--- a/drivers/usb/musb/tusb6010_omap.c
+++ b/drivers/usb/musb/tusb6010_omap.c
@@ -648,7 +648,7 @@ void dma_controller_destroy(struct dma_controller *c)
}
}
- if (!tusb_dma->multichannel && tusb_dma && tusb_dma->ch >= 0)
+ if (tusb_dma && !tusb_dma->multichannel && tusb_dma->ch >= 0)
omap_free_dma(tusb_dma->ch);
kfree(tusb_dma);
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index de56b3d743d7..3d2d3e549bd1 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -44,6 +44,7 @@ config ISP1301_OMAP
config USB_ULPI
bool "Generic ULPI Transceiver Driver"
depends on ARM
+ select USB_OTG_UTILS
help
Enable this to support ULPI connected USB OTG transceivers which
are likely found on embedded boards.
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
index 2be9f2fa41f9..3e4e9f434d78 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -36,7 +36,7 @@
#include <linux/i2c/twl.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
-
+#include <linux/notifier.h>
/* Register defines */
@@ -236,15 +236,6 @@
#define PMBR1 0x0D
#define GPIO_USB_4PIN_ULPI_2430C (3 << 0)
-
-
-enum linkstat {
- USB_LINK_UNKNOWN = 0,
- USB_LINK_NONE,
- USB_LINK_VBUS,
- USB_LINK_ID,
-};
-
struct twl4030_usb {
struct otg_transceiver otg;
struct device *dev;
@@ -347,10 +338,10 @@ twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
/*-------------------------------------------------------------------------*/
-static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl)
+static enum usb_xceiv_events twl4030_usb_linkstat(struct twl4030_usb *twl)
{
int status;
- int linkstat = USB_LINK_UNKNOWN;
+ int linkstat = USB_EVENT_NONE;
/*
* For ID/VBUS sensing, see manual section 15.4.8 ...
@@ -368,11 +359,11 @@ static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl)
dev_err(twl->dev, "USB link status err %d\n", status);
else if (status & (BIT(7) | BIT(2))) {
if (status & BIT(2))
- linkstat = USB_LINK_ID;
+ linkstat = USB_EVENT_ID;
else
- linkstat = USB_LINK_VBUS;
+ linkstat = USB_EVENT_VBUS;
} else
- linkstat = USB_LINK_NONE;
+ linkstat = USB_EVENT_NONE;
dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
status, status, linkstat);
@@ -383,7 +374,7 @@ static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl)
spin_lock_irq(&twl->lock);
twl->linkstat = linkstat;
- if (linkstat == USB_LINK_ID) {
+ if (linkstat == USB_EVENT_ID) {
twl->otg.default_a = true;
twl->otg.state = OTG_STATE_A_IDLE;
} else {
@@ -564,7 +555,7 @@ static ssize_t twl4030_usb_vbus_show(struct device *dev,
spin_lock_irqsave(&twl->lock, flags);
ret = sprintf(buf, "%s\n",
- (twl->linkstat == USB_LINK_VBUS) ? "on" : "off");
+ (twl->linkstat == USB_EVENT_VBUS) ? "on" : "off");
spin_unlock_irqrestore(&twl->lock, flags);
return ret;
@@ -576,17 +567,8 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
struct twl4030_usb *twl = _twl;
int status;
-#ifdef CONFIG_LOCKDEP
- /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
- * we don't want and can't tolerate. Although it might be
- * friendlier not to borrow this thread context...
- */
- local_irq_enable();
-#endif
-
status = twl4030_usb_linkstat(twl);
- if (status != USB_LINK_UNKNOWN) {
-
+ if (status >= 0) {
/* FIXME add a set_power() method so that B-devices can
* configure the charger appropriately. It's not always
* correct to consume VBUS power, and how much current to
@@ -598,12 +580,13 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
* USB_LINK_VBUS state. musb_hdrc won't care until it
* starts to handle softconnect right.
*/
- if (status == USB_LINK_NONE)
+ if (status == USB_EVENT_NONE)
twl4030_phy_suspend(twl, 0);
else
twl4030_phy_resume(twl);
- twl4030charger_usb_en(status == USB_LINK_VBUS);
+ blocking_notifier_call_chain(&twl->otg.notifier, status,
+ twl->otg.gadget);
}
sysfs_notify(&twl->dev->kobj, NULL, "vbus");
@@ -693,6 +676,8 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
if (device_create_file(&pdev->dev, &dev_attr_vbus))
dev_warn(&pdev->dev, "could not create sysfs file\n");
+ BLOCKING_INIT_NOTIFIER_HEAD(&twl->otg.notifier);
+
/* Our job is to use irqs and status from the power module
* to keep the transceiver disabled when nothing's connected.
*
@@ -702,7 +687,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
* need both handles, otherwise just one suffices.
*/
twl->irq_enabled = true;
- status = request_irq(twl->irq, twl4030_usb_irq,
+ status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
"twl4030_usb", twl);
if (status < 0) {
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index c480ea4c19f2..c78b255e3f83 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -472,6 +472,17 @@ config USB_SERIAL_OTI6858
To compile this driver as a module, choose M here: the
module will be called oti6858.
+config USB_SERIAL_QCAUX
+ tristate "USB Qualcomm Auxiliary Serial Port Driver"
+ ---help---
+ Say Y here if you want to use the auxiliary serial ports provided
+ by many modems based on Qualcomm chipsets. These ports often use
+ a proprietary protocol called DM and cannot be used for AT- or
+ PPP-based communication.
+
+ To compile this driver as a module, choose M here: the
+ module will be called moto_modem. If unsure, choose N.
+
config USB_SERIAL_QUALCOMM
tristate "USB Qualcomm Serial modem"
help
@@ -600,6 +611,14 @@ config USB_SERIAL_OPTICON
To compile this driver as a module, choose M here: the
module will be called opticon.
+config USB_SERIAL_VIVOPAY_SERIAL
+ tristate "USB ViVOpay serial interface driver"
+ help
+ Say Y here if you want to use a ViVOtech ViVOpay USB device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vivopay-serial.
+
config USB_SERIAL_DEBUG
tristate "USB Debugging Device"
help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 66619beb6cc0..83c9e431a568 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_USB_SERIAL_OPTICON) += opticon.o
obj-$(CONFIG_USB_SERIAL_OPTION) += option.o
obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o
obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
+obj-$(CONFIG_USB_SERIAL_QCAUX) += qcaux.o
obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o
@@ -55,4 +56,5 @@ obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o
obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o
+obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index b10ac8409411..365db1097bfd 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -78,7 +78,7 @@ static int debug;
#define DRIVER_DESC "AIRcable USB Driver"
/* ID table that will be registered with USB core */
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(AIRCABLE_VID, AIRCABLE_USB_PID) },
{ },
};
@@ -468,10 +468,6 @@ static void aircable_read_bulk_callback(struct urb *urb)
if (status) {
dbg("%s - urb status = %d", __func__, status);
- if (!port->port.count) {
- dbg("%s - port is closed, exiting.", __func__);
- return;
- }
if (status == -EPROTO) {
dbg("%s - caught -EPROTO, resubmitting the urb",
__func__);
@@ -530,23 +526,19 @@ static void aircable_read_bulk_callback(struct urb *urb)
}
tty_kref_put(tty);
- /* Schedule the next read _if_ we are still open */
- if (port->port.count) {
- usb_fill_bulk_urb(port->read_urb, port->serial->dev,
- usb_rcvbulkpipe(port->serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- aircable_read_bulk_callback, port);
-
- result = usb_submit_urb(urb, GFP_ATOMIC);
- if (result)
- dev_err(&urb->dev->dev,
- "%s - failed resubmitting read urb, error %d\n",
- __func__, result);
- }
-
- return;
+ /* Schedule the next read */
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ aircable_read_bulk_callback, port);
+
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result && result != -EPERM)
+ dev_err(&urb->dev->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __func__, result);
}
/* Based on ftdi_sio.c throttle */
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index a9c2dec8e3fb..547c9448c28c 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -50,7 +50,7 @@ static int debug;
/* usb timeout of 1 second */
#define ARK_TIMEOUT (1*HZ)
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x6547, 0x0232) },
{ USB_DEVICE(0x18ec, 0x3118) }, /* USB to IrDA adapter */
{ },
@@ -733,7 +733,6 @@ static void ark3116_read_bulk_callback(struct urb *urb)
tty = tty_port_tty_get(&port->port);
if (tty) {
- tty_buffer_request_room(tty, urb->actual_length + 1);
/* overrun is special, not associated with a char */
if (unlikely(lsr & UART_LSR_OE))
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index a0467bc61627..1295e44e3f1c 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -103,7 +103,7 @@ static int belkin_sa_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) },
{ USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) },
{ USB_DEVICE(PERACOM_VID, PERACOM_PID) },
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 59eff721fcc5..9f4fed1968b5 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -22,6 +22,7 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/serial.h>
+#include <asm/unaligned.h>
#define DEFAULT_BAUD_RATE 9600
#define DEFAULT_TIMEOUT 1000
@@ -70,7 +71,7 @@
static int debug;
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x4348, 0x5523) },
{ USB_DEVICE(0x1a86, 0x7523) },
{ },
@@ -392,16 +393,22 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
struct usb_serial_port *port = tty->driver_data;
int r;
uint16_t reg_contents;
- uint8_t break_reg[2];
+ uint8_t *break_reg;
dbg("%s()", __func__);
+ break_reg = kmalloc(2, GFP_KERNEL);
+ if (!break_reg) {
+ dev_err(&port->dev, "%s - kmalloc failed\n", __func__);
+ return;
+ }
+
r = ch341_control_in(port->serial->dev, CH341_REQ_READ_REG,
- ch341_break_reg, 0, break_reg, sizeof(break_reg));
+ ch341_break_reg, 0, break_reg, 2);
if (r < 0) {
- printk(KERN_WARNING "%s: USB control read error whilst getting"
- " break register contents.\n", __FILE__);
- return;
+ dev_err(&port->dev, "%s - USB control read error (%d)\n",
+ __func__, r);
+ goto out;
}
dbg("%s - initial ch341 break register contents - reg1: %x, reg2: %x",
__func__, break_reg[0], break_reg[1]);
@@ -416,12 +423,14 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
}
dbg("%s - New ch341 break register contents - reg1: %x, reg2: %x",
__func__, break_reg[0], break_reg[1]);
- reg_contents = (uint16_t)break_reg[0] | ((uint16_t)break_reg[1] << 8);
+ reg_contents = get_unaligned_le16(break_reg);
r = ch341_control_out(port->serial->dev, CH341_REQ_WRITE_REG,
ch341_break_reg, reg_contents);
if (r < 0)
- printk(KERN_WARNING "%s: USB control write error whilst setting"
- " break register contents.\n", __FILE__);
+ dev_err(&port->dev, "%s - USB control write error (%d)\n",
+ __func__, r);
+out:
+ kfree(break_reg);
}
static int ch341_tiocmset(struct tty_struct *tty, struct file *file,
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index bd254ec97d14..507382b0a9ed 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -55,7 +55,7 @@ static int cp210x_carrier_raised(struct usb_serial_port *p);
static int debug;
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */
{ USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
{ USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */
@@ -91,11 +91,12 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
{ USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
{ USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
+ { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */
{ USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */
{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
{ USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */
{ USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demostration module */
- { USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */
+ { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesys ETRX2USB */
{ USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
{ USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
@@ -612,7 +613,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
baud);
if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV,
((BAUD_RATE_GEN_FREQ + baud/2) / baud))) {
- dbg("Baud rate requested not supported by device\n");
+ dbg("Baud rate requested not supported by device");
baud = tty_termios_baud_rate(old_termios);
}
}
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index b0f6402a91ca..f744ab7a3b19 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -70,7 +70,7 @@ static void cyberjack_read_int_callback(struct urb *urb);
static void cyberjack_read_bulk_callback(struct urb *urb);
static void cyberjack_write_bulk_callback(struct urb *urb);
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) },
{ } /* Terminating entry */
};
@@ -391,11 +391,10 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
tty = tty_port_tty_get(&port->port);
if (!tty) {
- dbg("%s - ignoring since device not open\n", __func__);
+ dbg("%s - ignoring since device not open", __func__);
return;
}
if (urb->actual_length) {
- tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index a591ebec0f89..e23c77925e7a 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -66,17 +66,15 @@
#include <linux/serial.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
+#include <asm/unaligned.h>
#include "cypress_m8.h"
-#ifdef CONFIG_USB_SERIAL_DEBUG
- static int debug = 1;
-#else
- static int debug;
-#endif
+static int debug;
static int stats;
static int interval;
+static int unstable_bauds;
/*
* Version Information
@@ -89,24 +87,24 @@ static int interval;
#define CYPRESS_BUF_SIZE 1024
#define CYPRESS_CLOSING_WAIT (30*HZ)
-static struct usb_device_id id_table_earthmate [] = {
+static const struct usb_device_id id_table_earthmate[] = {
{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
{ } /* Terminating entry */
};
-static struct usb_device_id id_table_cyphidcomrs232 [] = {
+static const struct usb_device_id id_table_cyphidcomrs232[] = {
{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
{ USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
{ } /* Terminating entry */
};
-static struct usb_device_id id_table_nokiaca42v2 [] = {
+static const struct usb_device_id id_table_nokiaca42v2[] = {
{ USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
{ } /* Terminating entry */
};
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
@@ -154,7 +152,7 @@ struct cypress_private {
int isthrottled; /* if throttled, discard reads */
wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */
char prev_status, diff_status; /* used for TIOCMIWAIT */
- /* we pass a pointer to this as the arguement sent to
+ /* we pass a pointer to this as the argument sent to
cypress_set_termios old_termios */
struct ktermios tmp_termios; /* stores the old termios settings */
};
@@ -295,6 +293,9 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)
struct cypress_private *priv;
priv = usb_get_serial_port_data(port);
+ if (unstable_bauds)
+ return new_rate;
+
/*
* The general purpose firmware for the Cypress M8 allows for
* a maximum speed of 57600bps (I have no idea whether DeLorme
@@ -344,7 +345,8 @@ static int cypress_serial_control(struct tty_struct *tty,
{
int new_baudrate = 0, retval = 0, tries = 0;
struct cypress_private *priv;
- __u8 feature_buffer[5];
+ u8 *feature_buffer;
+ const unsigned int feature_len = 5;
unsigned long flags;
dbg("%s", __func__);
@@ -354,17 +356,18 @@ static int cypress_serial_control(struct tty_struct *tty,
if (!priv->comm_is_ok)
return -ENODEV;
+ feature_buffer = kcalloc(feature_len, sizeof(u8), GFP_KERNEL);
+ if (!feature_buffer)
+ return -ENOMEM;
+
switch (cypress_request_type) {
case CYPRESS_SET_CONFIG:
- new_baudrate = priv->baud_rate;
/* 0 means 'Hang up' so doesn't change the true bit rate */
- if (baud_rate == 0)
- new_baudrate = priv->baud_rate;
- /* Change of speed ? */
- else if (baud_rate != priv->baud_rate) {
+ new_baudrate = priv->baud_rate;
+ if (baud_rate && baud_rate != priv->baud_rate) {
dbg("%s - baud rate is changing", __func__);
retval = analyze_baud_rate(port, baud_rate);
- if (retval >= 0) {
+ if (retval >= 0) {
new_baudrate = retval;
dbg("%s - New baud rate set to %d",
__func__, new_baudrate);
@@ -373,9 +376,8 @@ static int cypress_serial_control(struct tty_struct *tty,
dbg("%s - baud rate is being sent as %d",
__func__, new_baudrate);
- memset(feature_buffer, 0, sizeof(feature_buffer));
/* fill the feature_buffer with new configuration */
- *((u_int32_t *)feature_buffer) = new_baudrate;
+ put_unaligned_le32(new_baudrate, feature_buffer);
feature_buffer[4] |= data_bits; /* assign data bits in 2 bit space ( max 3 ) */
/* 1 bit gap */
feature_buffer[4] |= (stop_bits << 3); /* assign stop bits in 1 bit space */
@@ -397,15 +399,15 @@ static int cypress_serial_control(struct tty_struct *tty,
HID_REQ_SET_REPORT,
USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
0x0300, 0, feature_buffer,
- sizeof(feature_buffer), 500);
+ feature_len, 500);
if (tries++ >= 3)
break;
- } while (retval != sizeof(feature_buffer) &&
+ } while (retval != feature_len &&
retval != -ENODEV);
- if (retval != sizeof(feature_buffer)) {
+ if (retval != feature_len) {
dev_err(&port->dev, "%s - failed sending serial "
"line settings - %d\n", __func__, retval);
cypress_set_dead(port);
@@ -425,43 +427,42 @@ static int cypress_serial_control(struct tty_struct *tty,
/* Not implemented for this device,
and if we try to do it we're likely
to crash the hardware. */
- return -ENOTTY;
+ retval = -ENOTTY;
+ goto out;
}
dbg("%s - retreiving serial line settings", __func__);
- /* set initial values in feature buffer */
- memset(feature_buffer, 0, sizeof(feature_buffer));
-
do {
retval = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
HID_REQ_GET_REPORT,
USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
0x0300, 0, feature_buffer,
- sizeof(feature_buffer), 500);
+ feature_len, 500);
if (tries++ >= 3)
break;
- } while (retval != sizeof(feature_buffer)
+ } while (retval != feature_len
&& retval != -ENODEV);
- if (retval != sizeof(feature_buffer)) {
+ if (retval != feature_len) {
dev_err(&port->dev, "%s - failed to retrieve serial "
"line settings - %d\n", __func__, retval);
cypress_set_dead(port);
- return retval;
+ goto out;
} else {
spin_lock_irqsave(&priv->lock, flags);
/* store the config in one byte, and later
use bit masks to check values */
priv->current_config = feature_buffer[4];
- priv->baud_rate = *((u_int32_t *)feature_buffer);
+ priv->baud_rate = get_unaligned_le32(feature_buffer);
spin_unlock_irqrestore(&priv->lock, flags);
}
}
spin_lock_irqsave(&priv->lock, flags);
++priv->cmd_count;
spin_unlock_irqrestore(&priv->lock, flags);
-
+out:
+ kfree(feature_buffer);
return retval;
} /* cypress_serial_control */
@@ -690,7 +691,6 @@ static void cypress_dtr_rts(struct usb_serial_port *port, int on)
{
struct cypress_private *priv = usb_get_serial_port_data(port);
/* drop dtr and rts */
- priv = usb_get_serial_port_data(port);
spin_lock_irq(&priv->lock);
if (on == 0)
priv->line_control = 0;
@@ -1307,13 +1307,9 @@ static void cypress_read_int_callback(struct urb *urb)
spin_unlock_irqrestore(&priv->lock, flags);
/* process read if there is data other than line status */
- if (tty && (bytes > i)) {
- bytes = tty_buffer_request_room(tty, bytes);
- for (; i < bytes ; ++i) {
- dbg("pushing byte number %d - %d - %c", i, data[i],
- data[i]);
- tty_insert_flip_char(tty, data[i], tty_flag);
- }
+ if (tty && bytes > i) {
+ tty_insert_flip_string_fixed_flag(tty, data + i,
+ bytes - i, tty_flag);
tty_flip_buffer_push(tty);
}
@@ -1325,9 +1321,9 @@ static void cypress_read_int_callback(struct urb *urb)
continue_read:
tty_kref_put(tty);
- /* Continue trying to always read... unless the port has closed. */
+ /* Continue trying to always read */
- if (port->port.count > 0 && priv->comm_is_ok) {
+ if (priv->comm_is_ok) {
usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
usb_rcvintpipe(port->serial->dev,
port->interrupt_in_endpointAddress),
@@ -1336,7 +1332,7 @@ continue_read:
cypress_read_int_callback, port,
priv->read_urb_interval);
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
- if (result) {
+ if (result && result != -EPERM) {
dev_err(&urb->dev->dev, "%s - failed resubmitting "
"read urb, error %d\n", __func__,
result);
@@ -1650,3 +1646,5 @@ module_param(stats, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(stats, "Enable statistics or not");
module_param(interval, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(interval, "Overrides interrupt interval");
+module_param(unstable_bauds, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(unstable_bauds, "Allow unstable baud rates");
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 68e80be6b9e1..68b0aa5e516c 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -470,18 +470,18 @@ static int digi_read_oob_callback(struct urb *urb);
static int debug;
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) },
{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) },
{ } /* Terminating entry */
};
-static struct usb_device_id id_table_2 [] = {
+static const struct usb_device_id id_table_2[] = {
{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) },
{ } /* Terminating entry */
};
-static struct usb_device_id id_table_4 [] = {
+static const struct usb_device_id id_table_4[] = {
{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) },
{ } /* Terminating entry */
};
@@ -1262,10 +1262,10 @@ static void digi_write_bulk_callback(struct urb *urb)
return;
}
- /* try to send any buffered data on this port, if it is open */
+ /* try to send any buffered data on this port */
spin_lock(&priv->dp_port_lock);
priv->dp_write_urb_in_use = 0;
- if (port->port.count && priv->dp_out_buf_len > 0) {
+ if (priv->dp_out_buf_len > 0) {
*((unsigned char *)(port->write_urb->transfer_buffer))
= (unsigned char)DIGI_CMD_SEND_DATA;
*((unsigned char *)(port->write_urb->transfer_buffer) + 1)
@@ -1288,7 +1288,7 @@ static void digi_write_bulk_callback(struct urb *urb)
schedule_work(&priv->dp_wakeup_work);
spin_unlock(&priv->dp_port_lock);
- if (ret)
+ if (ret && ret != -EPERM)
dev_err(&port->dev,
"%s: usb_submit_urb failed, ret=%d, port=%d\n",
__func__, ret, priv->dp_port_num);
@@ -1353,8 +1353,7 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
struct digi_port *priv = usb_get_serial_port_data(port);
struct ktermios not_termios;
- dbg("digi_open: TOP: port=%d, open_count=%d",
- priv->dp_port_num, port->port.count);
+ dbg("digi_open: TOP: port=%d", priv->dp_port_num);
/* be sure the device is started up */
if (digi_startup_device(port->serial) != 0)
@@ -1393,8 +1392,7 @@ static void digi_close(struct usb_serial_port *port)
unsigned char buf[32];
struct digi_port *priv = usb_get_serial_port_data(port);
- dbg("digi_close: TOP: port=%d, open_count=%d",
- priv->dp_port_num, port->port.count);
+ dbg("digi_close: TOP: port=%d", priv->dp_port_num);
mutex_lock(&port->serial->disc_mutex);
/* if disconnected, just clear flags */
@@ -1629,7 +1627,7 @@ static void digi_read_bulk_callback(struct urb *urb)
/* continue read */
urb->dev = port->serial->dev;
ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret != 0) {
+ if (ret != 0 && ret != -EPERM) {
dev_err(&port->dev,
"%s: failed resubmitting urb, ret=%d, port=%d\n",
__func__, ret, priv->dp_port_num);
@@ -1658,12 +1656,11 @@ static int digi_read_inb_callback(struct urb *urb)
int port_status = ((unsigned char *)urb->transfer_buffer)[2];
unsigned char *data = ((unsigned char *)urb->transfer_buffer) + 3;
int flag, throttled;
- int i;
int status = urb->status;
/* do not process callbacks on closed ports */
/* but do continue the read chain */
- if (port->port.count == 0)
+ if (urb->status == -ENOENT)
return 0;
/* short/multiple packet check */
@@ -1705,17 +1702,9 @@ static int digi_read_inb_callback(struct urb *urb)
/* data length is len-1 (one byte of len is port_status) */
--len;
-
- len = tty_buffer_request_room(tty, len);
if (len > 0) {
- /* Hot path */
- if (flag == TTY_NORMAL)
- tty_insert_flip_string(tty, data, len);
- else {
- for (i = 0; i < len; i++)
- tty_insert_flip_char(tty,
- data[i], flag);
- }
+ tty_insert_flip_string_fixed_flag(tty, data, len,
+ flag);
tty_flip_buffer_push(tty);
}
}
@@ -1776,8 +1765,7 @@ static int digi_read_oob_callback(struct urb *urb)
tty = tty_port_tty_get(&port->port);
rts = 0;
- if (port->port.count)
- rts = tty->termios->c_cflag & CRTSCTS;
+ rts = tty->termios->c_cflag & CRTSCTS;
if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
spin_lock(&priv->dp_port_lock);
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 7dd0e3eadbe6..5f740a1eacab 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -93,7 +93,7 @@ static void empeg_init_termios(struct tty_struct *tty);
static void empeg_write_bulk_callback(struct urb *urb);
static void empeg_read_bulk_callback(struct urb *urb);
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(EMPEG_VENDOR_ID, EMPEG_PRODUCT_ID) },
{ } /* Terminating entry */
};
@@ -346,7 +346,6 @@ static void empeg_read_bulk_callback(struct urb *urb)
tty = tty_port_tty_get(&port->port);
if (urb->actual_length) {
- tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
bytes_in += urb->actual_length;
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 216f187582ab..6af0dfa5f5ac 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -33,12 +33,12 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/serial.h>
@@ -50,7 +50,7 @@
* Version Information
*/
#define DRIVER_VERSION "v1.5.0"
-#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr"
#define DRIVER_DESC "USB FTDI Serial Converters Driver"
static int debug;
@@ -88,10 +88,10 @@ struct ftdi_private {
unsigned int latency; /* latency setting in use */
spinlock_t tx_lock; /* spinlock for transmit state */
- unsigned long tx_bytes;
unsigned long tx_outstanding_bytes;
unsigned long tx_outstanding_urbs;
unsigned short max_packet_size;
+ struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() */
};
/* struct ftdi_sio_quirk is used by devices requiring special attention. */
@@ -145,10 +145,15 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
+/*
+ * Device ID not listed? Test via module params product/vendor or
+ * /sys/bus/usb/ftdi_sio/new_id, then send patch/report!
+ */
static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
@@ -552,9 +557,16 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
/*
- * Due to many user requests for multiple ELV devices we enable
- * them by default.
+ * ELV devices:
*/
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_WS550_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_EC3000_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_WS888_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_TWS550_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_FEM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) },
@@ -571,11 +583,17 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_UTP8_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_WS444PC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_EM1010PC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_HS485_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_UMS100_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_TFD128_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_FM3RX_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_WS777_PID) },
{ USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
{ USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
@@ -596,6 +614,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) },
{ USB_DEVICE(TTI_VID, TTI_QL355P_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
+ { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
@@ -697,6 +716,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
{ USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) },
+ { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AD4USB_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DGQG_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) },
{ USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) },
@@ -718,6 +738,10 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
{ USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) },
+ { USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) },
+ { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) },
+ { USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) },
+ { USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
@@ -793,7 +817,7 @@ static struct usb_serial_driver ftdi_sio_device = {
.name = "ftdi_sio",
},
.description = "FTDI USB Serial Device",
- .usb_driver = &ftdi_driver ,
+ .usb_driver = &ftdi_driver,
.id_table = id_table_combined,
.num_ports = 1,
.probe = ftdi_sio_probe,
@@ -809,8 +833,8 @@ static struct usb_serial_driver ftdi_sio_device = {
.chars_in_buffer = ftdi_chars_in_buffer,
.read_bulk_callback = ftdi_read_bulk_callback,
.write_bulk_callback = ftdi_write_bulk_callback,
- .tiocmget = ftdi_tiocmget,
- .tiocmset = ftdi_tiocmset,
+ .tiocmget = ftdi_tiocmget,
+ .tiocmset = ftdi_tiocmset,
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
@@ -916,7 +940,6 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
unsigned int clear)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- char *buf;
unsigned urb_value;
int rv;
@@ -925,10 +948,6 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
return 0; /* no change */
}
- buf = kmalloc(1, GFP_NOIO);
- if (!buf)
- return -ENOMEM;
-
clear &= ~set; /* 'set' takes precedence over 'clear' */
urb_value = 0;
if (clear & TIOCM_DTR)
@@ -944,9 +963,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
FTDI_SIO_SET_MODEM_CTRL_REQUEST,
FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
urb_value, priv->interface,
- buf, 0, WDR_TIMEOUT);
-
- kfree(buf);
+ NULL, 0, WDR_TIMEOUT);
if (rv < 0) {
dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
__func__,
@@ -1105,16 +1122,11 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- char *buf;
__u16 urb_value;
__u16 urb_index;
__u32 urb_index_value;
int rv;
- buf = kmalloc(1, GFP_NOIO);
- if (!buf)
- return -ENOMEM;
-
urb_index_value = get_ftdi_divisor(tty, port);
urb_value = (__u16)urb_index_value;
urb_index = (__u16)(urb_index_value >> 16);
@@ -1127,9 +1139,7 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
FTDI_SIO_SET_BAUDRATE_REQUEST,
FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
urb_value, urb_index,
- buf, 0, WDR_SHORT_TIMEOUT);
-
- kfree(buf);
+ NULL, 0, WDR_SHORT_TIMEOUT);
return rv;
}
@@ -1137,8 +1147,7 @@ static int write_latency_timer(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
struct usb_device *udev = port->serial->dev;
- char buf[1];
- int rv = 0;
+ int rv;
int l = priv->latency;
if (priv->flags & ASYNC_LOW_LATENCY)
@@ -1151,8 +1160,7 @@ static int write_latency_timer(struct usb_serial_port *port)
FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
l, priv->interface,
- buf, 0, WDR_TIMEOUT);
-
+ NULL, 0, WDR_TIMEOUT);
if (rv < 0)
dev_err(&port->dev, "Unable to write latency timer: %i\n", rv);
return rv;
@@ -1162,24 +1170,29 @@ static int read_latency_timer(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
struct usb_device *udev = port->serial->dev;
- unsigned short latency = 0;
- int rv = 0;
-
+ unsigned char *buf;
+ int rv;
dbg("%s", __func__);
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
rv = usb_control_msg(udev,
usb_rcvctrlpipe(udev, 0),
FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
0, priv->interface,
- (char *) &latency, 1, WDR_TIMEOUT);
-
- if (rv < 0) {
+ buf, 1, WDR_TIMEOUT);
+ if (rv < 0)
dev_err(&port->dev, "Unable to read latency timer: %i\n", rv);
- return -EIO;
- }
- return latency;
+ else
+ priv->latency = buf[0];
+
+ kfree(buf);
+
+ return rv;
}
static int get_serial_info(struct usb_serial_port *port,
@@ -1210,7 +1223,7 @@ static int set_serial_info(struct tty_struct *tty,
if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
return -EFAULT;
- lock_kernel();
+ mutex_lock(&priv->cfg_lock);
old_priv = *priv;
/* Do error checking and permission checking */
@@ -1218,7 +1231,7 @@ static int set_serial_info(struct tty_struct *tty,
if (!capable(CAP_SYS_ADMIN)) {
if (((new_serial.flags & ~ASYNC_USR_MASK) !=
(priv->flags & ~ASYNC_USR_MASK))) {
- unlock_kernel();
+ mutex_unlock(&priv->cfg_lock);
return -EPERM;
}
priv->flags = ((priv->flags & ~ASYNC_USR_MASK) |
@@ -1229,7 +1242,7 @@ static int set_serial_info(struct tty_struct *tty,
if ((new_serial.baud_base != priv->baud_base) &&
(new_serial.baud_base < 9600)) {
- unlock_kernel();
+ mutex_unlock(&priv->cfg_lock);
return -EINVAL;
}
@@ -1259,11 +1272,11 @@ check_and_exit:
(priv->flags & ASYNC_SPD_MASK)) ||
(((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
(old_priv.custom_divisor != priv->custom_divisor))) {
- unlock_kernel();
+ mutex_unlock(&priv->cfg_lock);
change_speed(tty, port);
}
else
- unlock_kernel();
+ mutex_unlock(&priv->cfg_lock);
return 0;
} /* set_serial_info */
@@ -1319,20 +1332,20 @@ static void ftdi_determine_type(struct usb_serial_port *port)
__func__);
}
} else if (version < 0x200) {
- /* Old device. Assume its the original SIO. */
+ /* Old device. Assume it's the original SIO. */
priv->chip_type = SIO;
priv->baud_base = 12000000 / 16;
priv->write_offset = 1;
} else if (version < 0x400) {
- /* Assume its an FT8U232AM (or FT8U245AM) */
+ /* Assume it's an FT8U232AM (or FT8U245AM) */
/* (It might be a BM because of the iSerialNumber bug,
* but it will still work as an AM device.) */
priv->chip_type = FT8U232AM;
} else if (version < 0x600) {
- /* Assume its an FT232BM (or FT245BM) */
+ /* Assume it's an FT232BM (or FT245BM) */
priv->chip_type = FT232BM;
} else {
- /* Assume its an FT232R */
+ /* Assume it's an FT232R */
priv->chip_type = FT232RL;
}
dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]);
@@ -1352,7 +1365,7 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port)
struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc;
unsigned num_endpoints;
- int i = 0;
+ int i;
num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
@@ -1404,7 +1417,7 @@ static ssize_t store_latency_timer(struct device *dev,
struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port);
int v = simple_strtoul(valbuf, NULL, 10);
- int rv = 0;
+ int rv;
priv->latency = v;
rv = write_latency_timer(port);
@@ -1421,9 +1434,8 @@ static ssize_t store_event_char(struct device *dev,
struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port);
struct usb_device *udev = port->serial->dev;
- char buf[1];
int v = simple_strtoul(valbuf, NULL, 10);
- int rv = 0;
+ int rv;
dbg("%s: setting event char = %i", __func__, v);
@@ -1432,8 +1444,7 @@ static ssize_t store_event_char(struct device *dev,
FTDI_SIO_SET_EVENT_CHAR_REQUEST,
FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE,
v, priv->interface,
- buf, 0, WDR_TIMEOUT);
-
+ NULL, 0, WDR_TIMEOUT);
if (rv < 0) {
dbg("Unable to write event character: %i", rv);
return -EIO;
@@ -1532,9 +1543,9 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
kref_init(&priv->kref);
spin_lock_init(&priv->tx_lock);
+ mutex_init(&priv->cfg_lock);
init_waitqueue_head(&priv->delta_msr_wait);
- /* This will push the characters through immediately rather
- than queue a task to deliver them */
+
priv->flags = ASYNC_LOW_LATENCY;
if (quirk && quirk->port_probe)
@@ -1566,7 +1577,8 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
ftdi_determine_type(port);
ftdi_set_max_packet_size(port);
- read_latency_timer(port);
+ if (read_latency_timer(port) < 0)
+ priv->latency = 16;
create_sysfs_attrs(port);
return 0;
}
@@ -1611,8 +1623,6 @@ static int ftdi_NDI_device_setup(struct usb_serial *serial)
{
struct usb_device *udev = serial->dev;
int latency = ndi_latency_timer;
- int rv = 0;
- char buf[1];
if (latency == 0)
latency = 1;
@@ -1622,10 +1632,11 @@ static int ftdi_NDI_device_setup(struct usb_serial *serial)
dbg("%s setting NDI device latency to %d", __func__, latency);
dev_info(&udev->dev, "NDI device with a latency value of %d", latency);
- rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ /* FIXME: errors are not returned */
+ usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
- latency, 0, buf, 0, WDR_TIMEOUT);
+ latency, 0, NULL, 0, WDR_TIMEOUT);
return 0;
}
@@ -1701,7 +1712,7 @@ static int ftdi_submit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
urb->transfer_buffer_length,
ftdi_read_bulk_callback, port);
result = usb_submit_urb(urb, mem_flags);
- if (result)
+ if (result && result != -EPERM)
dev_err(&port->dev,
"%s - failed submitting read urb, error %d\n",
__func__, result);
@@ -1713,16 +1724,10 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
-
- int result = 0;
- char buf[1]; /* Needed for the usb_control_msg I think */
+ int result;
dbg("%s", __func__);
- spin_lock_irqsave(&priv->tx_lock, flags);
- priv->tx_bytes = 0;
- spin_unlock_irqrestore(&priv->tx_lock, flags);
-
write_latency_timer(port);
/* No error checking for this (will get errors later anyway) */
@@ -1730,7 +1735,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
FTDI_SIO_RESET_SIO,
- priv->interface, buf, 0, WDR_TIMEOUT);
+ priv->interface, NULL, 0, WDR_TIMEOUT);
/* Termios defaults are set by usb_serial_init. We don't change
port->tty->termios - this would lose speed settings, etc.
@@ -1758,7 +1763,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- char buf[1];
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected) {
@@ -1767,7 +1771,7 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
- 0, priv->interface, buf, 0,
+ 0, priv->interface, NULL, 0,
WDR_TIMEOUT) < 0) {
dev_err(&port->dev, "error from flowcontrol urb\n");
}
@@ -1828,7 +1832,7 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
spin_lock_irqsave(&priv->tx_lock, flags);
if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) {
spin_unlock_irqrestore(&priv->tx_lock, flags);
- dbg("%s - write limit hit\n", __func__);
+ dbg("%s - write limit hit", __func__);
return 0;
}
priv->tx_outstanding_urbs++;
@@ -1908,7 +1912,6 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
} else {
spin_lock_irqsave(&priv->tx_lock, flags);
priv->tx_outstanding_bytes += count;
- priv->tx_bytes += count;
spin_unlock_irqrestore(&priv->tx_lock, flags);
}
@@ -2135,8 +2138,7 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port);
- __u16 urb_value = 0;
- char buf[1];
+ __u16 urb_value;
/* break_state = -1 to turn on break, and 0 to turn off break */
/* see drivers/char/tty_io.c to see it used */
@@ -2152,7 +2154,7 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface,
- buf, 0, WDR_TIMEOUT) < 0) {
+ NULL, 0, WDR_TIMEOUT) < 0) {
dev_err(&port->dev, "%s FAILED to enable/disable break state "
"(state was %d)\n", __func__, break_state);
}
@@ -2176,7 +2178,6 @@ static void ftdi_set_termios(struct tty_struct *tty,
struct ktermios *termios = tty->termios;
unsigned int cflag = termios->c_cflag;
__u16 urb_value; /* will hold the new flags */
- char buf[1]; /* Perhaps I should dynamically alloc this? */
/* Added for xon/xoff support */
unsigned int iflag = termios->c_iflag;
@@ -2227,12 +2228,10 @@ static void ftdi_set_termios(struct tty_struct *tty,
}
if (cflag & CSIZE) {
switch (cflag & CSIZE) {
- case CS5: urb_value |= 5; dbg("Setting CS5"); break;
- case CS6: urb_value |= 6; dbg("Setting CS6"); break;
case CS7: urb_value |= 7; dbg("Setting CS7"); break;
case CS8: urb_value |= 8; dbg("Setting CS8"); break;
default:
- dev_err(&port->dev, "CSIZE was set but not CS5-CS8\n");
+ dev_err(&port->dev, "CSIZE was set but not CS7-CS8\n");
}
}
@@ -2244,7 +2243,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface,
- buf, 0, WDR_SHORT_TIMEOUT) < 0) {
+ NULL, 0, WDR_SHORT_TIMEOUT) < 0) {
dev_err(&port->dev, "%s FAILED to set "
"databits/stopbits/parity\n", __func__);
}
@@ -2256,7 +2255,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface,
- buf, 0, WDR_TIMEOUT) < 0) {
+ NULL, 0, WDR_TIMEOUT) < 0) {
dev_err(&port->dev,
"%s error from disable flowcontrol urb\n",
__func__);
@@ -2282,7 +2281,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
- buf, 0, WDR_TIMEOUT) < 0) {
+ NULL, 0, WDR_TIMEOUT) < 0) {
dev_err(&port->dev,
"urb failed to set to rts/cts flow control\n");
}
@@ -2314,7 +2313,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
urb_value , (FTDI_SIO_XON_XOFF_HS
| priv->interface),
- buf, 0, WDR_TIMEOUT) < 0) {
+ NULL, 0, WDR_TIMEOUT) < 0) {
dev_err(&port->dev, "urb failed to set to "
"xon/xoff flow control\n");
}
@@ -2328,7 +2327,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface,
- buf, 0, WDR_TIMEOUT) < 0) {
+ NULL, 0, WDR_TIMEOUT) < 0) {
dev_err(&port->dev,
"urb failed to clear flow control\n");
}
@@ -2342,21 +2341,22 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
{
struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port);
- unsigned char buf[2];
+ unsigned char *buf;
+ int len;
int ret;
dbg("%s TIOCMGET", __func__);
+
+ buf = kmalloc(2, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ /*
+ * The 8U232AM returns a two byte value (the SIO a 1 byte value) in
+ * the same format as the data returned from the in point.
+ */
switch (priv->chip_type) {
case SIO:
- /* Request the status from the device */
- ret = usb_control_msg(port->serial->dev,
- usb_rcvctrlpipe(port->serial->dev, 0),
- FTDI_SIO_GET_MODEM_STATUS_REQUEST,
- FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
- 0, 0,
- buf, 1, WDR_TIMEOUT);
- if (ret < 0)
- return ret;
+ len = 1;
break;
case FT8U232AM:
case FT232BM:
@@ -2364,27 +2364,30 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
case FT232RL:
case FT2232H:
case FT4232H:
- /* the 8U232AM returns a two byte value (the sio is a 1 byte
- value) - in the same format as the data returned from the in
- point */
- ret = usb_control_msg(port->serial->dev,
- usb_rcvctrlpipe(port->serial->dev, 0),
- FTDI_SIO_GET_MODEM_STATUS_REQUEST,
- FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
- 0, priv->interface,
- buf, 2, WDR_TIMEOUT);
- if (ret < 0)
- return ret;
+ len = 2;
break;
default:
- return -EFAULT;
+ ret = -EFAULT;
+ goto out;
}
- return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
+ ret = usb_control_msg(port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0),
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST,
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+ 0, priv->interface,
+ buf, len, WDR_TIMEOUT);
+ if (ret < 0)
+ goto out;
+
+ ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
(buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
(buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) |
(buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) |
priv->last_dtr_rts;
+out:
+ kfree(buf);
+ return ret;
}
static int ftdi_tiocmset(struct tty_struct *tty, struct file *file,
@@ -2489,8 +2492,7 @@ void ftdi_unthrottle(struct tty_struct *tty)
port->throttled = port->throttle_req = 0;
spin_unlock_irqrestore(&port->lock, flags);
- /* Resubmit urb if throttled and open. */
- if (was_throttled && test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ if (was_throttled)
ftdi_submit_read_urb(port, GFP_KERNEL);
}
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index b0e0d64f822e..ff9bf80327a3 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -28,13 +28,13 @@
#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */
#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */
-#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modern status register */
+#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */
#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */
#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */
#define FTDI_SIO_GET_LATENCY_TIMER 10 /* Get the latency timer */
-/* Interface indicies for FT2232, FT2232H and FT4232H devices*/
+/* Interface indices for FT2232, FT2232H and FT4232H devices */
#define INTERFACE_A 1
#define INTERFACE_B 2
#define INTERFACE_C 3
@@ -270,7 +270,7 @@ typedef enum {
* BmRequestType: 0100 0000b
* bRequest: FTDI_SIO_SET_FLOW_CTRL
* wValue: Xoff/Xon
- * wIndex: Protocol/Port - hIndex is protocl / lIndex is port
+ * wIndex: Protocol/Port - hIndex is protocol / lIndex is port
* wLength: 0
* Data: None
*
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index da92b4952ffb..0727e198503e 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -22,7 +22,7 @@
#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */
#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */
#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */
-#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
+#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
#define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */
@@ -38,6 +38,8 @@
/* www.candapter.com Ewert Energy Systems CANdapter device */
#define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */
+#define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */
+
/* OOCDlink by Joern Kaipf <joernk@web.de>
* (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */
#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */
@@ -47,7 +49,7 @@
#define LMI_LM3S_DEVEL_BOARD_PID 0xbcd8
#define LMI_LM3S_EVAL_BOARD_PID 0xbcd9
-#define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmBH */
+#define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */
/* OpenDCC (www.opendcc.de) product id */
#define FTDI_OPENDCC_PID 0xBFD8
@@ -161,22 +163,37 @@
/*
* ELV USB devices submitted by Christian Abt of ELV (www.elv.de).
* All of these devices use FTDI's vendor ID (0x0403).
+ * Further IDs taken from ELV Windows .inf file.
*
* The previously included PID for the UO 100 module was incorrect.
* In fact, that PID was for ELV's UR 100 USB-RS232 converter (0xFB58).
*
* Armin Laeuger originally sent the PID for the UM 100 module.
*/
+#define FTDI_ELV_USR_PID 0xE000 /* ELV Universal-Sound-Recorder */
+#define FTDI_ELV_MSM1_PID 0xE001 /* ELV Mini-Sound-Modul */
+#define FTDI_ELV_KL100_PID 0xE002 /* ELV Kfz-Leistungsmesser KL 100 */
+#define FTDI_ELV_WS550_PID 0xE004 /* WS 550 */
+#define FTDI_ELV_EC3000_PID 0xE006 /* ENERGY CONTROL 3000 USB */
+#define FTDI_ELV_WS888_PID 0xE008 /* WS 888 */
+#define FTDI_ELV_TWS550_PID 0xE009 /* Technoline WS 550 */
+#define FTDI_ELV_FEM_PID 0xE00A /* Funk Energie Monitor */
#define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */
#define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */
#define FTDI_ELV_HS485_PID 0xE0EA /* USB to RS-485 adapter */
-#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Engery monitor EM 1010 PC */
+#define FTDI_ELV_UMS100_PID 0xE0EB /* ELV USB Master-Slave Schaltsteckdose UMS 100 */
+#define FTDI_ELV_TFD128_PID 0xE0EC /* ELV Temperatur-Feuchte-Datenlogger TFD 128 */
+#define FTDI_ELV_FM3RX_PID 0xE0ED /* ELV Messwertuebertragung FM3 RX */
+#define FTDI_ELV_WS777_PID 0xE0EE /* Conrad WS 777 */
+#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Energy monitor EM 1010 PC */
#define FTDI_ELV_CSI8_PID 0xE0F0 /* Computer-Schalt-Interface (CSI 8) */
#define FTDI_ELV_EM1000DL_PID 0xE0F1 /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */
#define FTDI_ELV_PCK100_PID 0xE0F2 /* PC-Kabeltester (PCK 100) */
#define FTDI_ELV_RFP500_PID 0xE0F3 /* HF-Leistungsmesser (RFP 500) */
#define FTDI_ELV_FS20SIG_PID 0xE0F4 /* Signalgeber (FS 20 SIG) */
+#define FTDI_ELV_UTP8_PID 0xE0F5 /* ELV UTP 8 */
#define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */
+#define FTDI_ELV_WS444PC_PID 0xE0F7 /* Conrad WS 444 PC */
#define FTDI_PHI_FISCO_PID 0xE40B /* PHI Fisco USB to Serial cable */
#define FTDI_ELV_UAD8_PID 0xF068 /* USB-AD-Wandler (UAD 8) */
#define FTDI_ELV_UDA7_PID 0xF069 /* USB-DA-Wandler (UDA 7) */
@@ -195,8 +212,8 @@
* drivers, or possibly the Comedi drivers in some cases. */
#define FTDI_ELV_CLI7000_PID 0xFB59 /* Computer-Light-Interface (CLI 7000) */
#define FTDI_ELV_PPS7330_PID 0xFB5C /* Processor-Power-Supply (PPS 7330) */
-#define FTDI_ELV_TFM100_PID 0xFB5D /* Temperartur-Feuchte Messgeraet (TFM 100) */
-#define FTDI_ELV_UDF77_PID 0xFB5E /* USB DCF Funkurh (UDF 77) */
+#define FTDI_ELV_TFM100_PID 0xFB5D /* Temperatur-Feuchte-Messgeraet (TFM 100) */
+#define FTDI_ELV_UDF77_PID 0xFB5E /* USB DCF Funkuhr (UDF 77) */
#define FTDI_ELV_UIO88_PID 0xFB5F /* USB-I/O Interface (UIO 88) */
/*
@@ -303,7 +320,7 @@
/*
* 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485,
- * USB-TTY activ, USB-TTY passiv. Some PIDs are used by several devices
+ * USB-TTY aktiv, USB-TTY passiv. Some PIDs are used by several devices
* and I'm not entirely sure which are used by which.
*/
#define FTDI_4N_GALAXY_DE_1_PID 0xF3C0
@@ -313,10 +330,10 @@
* Linx Technologies product ids
*/
#define LINX_SDMUSBQSS_PID 0xF448 /* Linx SDM-USB-QS-S */
-#define LINX_MASTERDEVEL2_PID 0xF449 /* Linx Master Development 2.0 */
-#define LINX_FUTURE_0_PID 0xF44A /* Linx future device */
-#define LINX_FUTURE_1_PID 0xF44B /* Linx future device */
-#define LINX_FUTURE_2_PID 0xF44C /* Linx future device */
+#define LINX_MASTERDEVEL2_PID 0xF449 /* Linx Master Development 2.0 */
+#define LINX_FUTURE_0_PID 0xF44A /* Linx future device */
+#define LINX_FUTURE_1_PID 0xF44B /* Linx future device */
+#define LINX_FUTURE_2_PID 0xF44C /* Linx future device */
/*
* Oceanic product ids
@@ -477,6 +494,13 @@
#define RATOC_PRODUCT_ID_USB60F 0xb020
/*
+ * Contec products (http://www.contec.com)
+ * Submitted by Daniel Sangorrin
+ */
+#define CONTEC_VID 0x06CE /* Vendor ID */
+#define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */
+
+/*
* Definitions for B&B Electronics products.
*/
#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */
@@ -625,7 +649,7 @@
#define FALCOM_TWIST_PID 0x0001 /* Falcom Twist USB GPRS modem */
#define FALCOM_SAMBA_PID 0x0005 /* Falcom Samba USB GPRS modem */
-/* Larsen and Brusgaard AltiTrack/USBtrack */
+/* Larsen and Brusgaard AltiTrack/USBtrack */
#define LARSENBRUSGAARD_VID 0x0FD8
#define LB_ALTITRACK_PID 0x0001
@@ -954,7 +978,7 @@
#define ALTI2_N3_PID 0x6001 /* Neptune 3 */
/*
- * Dresden Elektronic Sensor Terminal Board
+ * Dresden Elektronik Sensor Terminal Board
*/
#define DE_VID 0x1cf1 /* Vendor ID */
#define STB_PID 0x0001 /* Sensor Terminal Board */
@@ -968,6 +992,7 @@
#define PAPOUCH_VID 0x5050 /* Vendor ID */
#define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */
#define PAPOUCH_QUIDO4x4_PID 0x0900 /* Quido 4/4 Module */
+#define PAPOUCH_AD4USB_PID 0x8003 /* AD4USB Measurement Module */
/*
* Marvell SheevaPlug
@@ -984,3 +1009,11 @@
#define EVO_8U232AM_PID 0x02FF /* Evolution robotics RCM2 (FT232AM)*/
#define EVO_HYBRID_PID 0x0302 /* Evolution robotics RCM4 PID (FT232BM)*/
#define EVO_RCM4_PID 0x0303 /* Evolution robotics RCM4 PID */
+
+/*
+ * MJS Gadgets HD Radio / XM Radio / Sirius Radio interfaces (using VID 0x0403)
+ */
+#define MJSG_GENERIC_PID 0x9378
+#define MJSG_SR_RADIO_PID 0x9379
+#define MJSG_XM_RADIO_PID 0x937A
+#define MJSG_HD_RADIO_PID 0x937C
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index d30f736d2cc5..e21ce9ddfc63 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -18,7 +18,7 @@
static int debug;
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1404, 0xcddc) },
{ },
};
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 5ac900e5a50e..a42b29a695b2 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -210,7 +210,7 @@ static unsigned char const PRIVATE_REQ[]
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
/* the same device id seems to be used by all
usb enabled GPS devices */
{ USB_DEVICE(GARMIN_VENDOR_ID, 3) },
@@ -271,7 +271,6 @@ static void send_to_tty(struct usb_serial_port *port,
usb_serial_debug_data(debug, &port->dev,
__func__, actual_length, data);
- tty_buffer_request_room(tty, actual_length);
tty_insert_flip_string(tty, data, actual_length);
tty_flip_buffer_push(tty);
}
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index f1ea3a33b6e6..89fac36684c5 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -20,6 +20,7 @@
#include <linux/usb/serial.h>
#include <linux/uaccess.h>
#include <linux/kfifo.h>
+#include <linux/serial.h>
static int debug;
@@ -41,7 +42,7 @@ static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
/* we want to look at all devices, as the vendor/product id can change
* depending on the command line argument */
-static struct usb_device_id generic_serial_ids[] = {
+static const struct usb_device_id generic_serial_ids[] = {
{.driver_info = 42},
{}
};
@@ -194,7 +195,7 @@ static int usb_serial_multi_urb_write(struct tty_struct *tty,
if (port->urbs_in_flight >
port->serial->type->max_in_flight_urbs) {
spin_unlock_irqrestore(&port->lock, flags);
- dbg("%s - write limit hit\n", __func__);
+ dbg("%s - write limit hit", __func__);
return bwrite;
}
port->tx_bytes_flight += towrite;
@@ -386,12 +387,12 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
dbg("%s - port %d", __func__, port->number);
- if (serial->type->max_in_flight_urbs) {
- spin_lock_irqsave(&port->lock, flags);
+ spin_lock_irqsave(&port->lock, flags);
+ if (serial->type->max_in_flight_urbs)
chars = port->tx_bytes_flight;
- spin_unlock_irqrestore(&port->lock, flags);
- } else if (serial->num_bulk_out)
+ else if (serial->num_bulk_out)
chars = kfifo_len(&port->write_fifo);
+ spin_unlock_irqrestore(&port->lock, flags);
dbg("%s - returns %d", __func__, chars);
return chars;
@@ -489,6 +490,8 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
dbg("%s - port %d", __func__, port->number);
if (port->serial->type->max_in_flight_urbs) {
+ kfree(urb->transfer_buffer);
+
spin_lock_irqsave(&port->lock, flags);
--port->urbs_in_flight;
port->tx_bytes_flight -= urb->transfer_buffer_length;
@@ -583,7 +586,7 @@ int usb_serial_generic_resume(struct usb_serial *serial)
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
- if (!port->port.count)
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
continue;
if (port->read_urb) {
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index 431329275133..809379159b0e 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -29,7 +29,7 @@
#define HP_VENDOR_ID 0x03f0
#define HP49GP_PRODUCT_ID 0x0121
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(HP_VENDOR_ID, HP49GP_PRODUCT_ID) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index b97960ac92f2..3ef8df0ef888 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -364,42 +364,6 @@ static void update_edgeport_E2PROM(struct edgeport_serial *edge_serial)
release_firmware(fw);
}
-
-/************************************************************************
- * *
- * Get string descriptor from device *
- * *
- ************************************************************************/
-static int get_string(struct usb_device *dev, int Id, char *string, int buflen)
-{
- struct usb_string_descriptor StringDesc;
- struct usb_string_descriptor *pStringDesc;
-
- dbg("%s - USB String ID = %d", __func__, Id);
-
- if (!usb_get_descriptor(dev, USB_DT_STRING, Id,
- &StringDesc, sizeof(StringDesc)))
- return 0;
-
- pStringDesc = kmalloc(StringDesc.bLength, GFP_KERNEL);
- if (!pStringDesc)
- return 0;
-
- if (!usb_get_descriptor(dev, USB_DT_STRING, Id,
- pStringDesc, StringDesc.bLength)) {
- kfree(pStringDesc);
- return 0;
- }
-
- unicode_to_ascii(string, buflen,
- pStringDesc->wData, pStringDesc->bLength/2);
-
- kfree(pStringDesc);
- dbg("%s - USB String %s", __func__, string);
- return strlen(string);
-}
-
-
#if 0
/************************************************************************
*
@@ -2007,7 +1971,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
return;
case IOSP_EXT_STATUS_RX_CHECK_RSP:
- dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============\n", __func__, edge_serial->rxPort, byte3);
+ dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============", __func__, edge_serial->rxPort, byte3);
/* Port->RxCheckRsp = true; */
return;
}
@@ -2075,7 +2039,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
break;
default:
- dbg("%s - Unrecognized IOSP status code %u\n", __func__, code);
+ dbg("%s - Unrecognized IOSP status code %u", __func__, code);
break;
}
return;
@@ -2091,18 +2055,13 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty,
{
int cnt;
- do {
- cnt = tty_buffer_request_room(tty, length);
- if (cnt < length) {
- dev_err(dev, "%s - dropping data, %d bytes lost\n",
- __func__, length - cnt);
- if (cnt == 0)
- break;
- }
- tty_insert_flip_string(tty, data, cnt);
- data += cnt;
- length -= cnt;
- } while (length > 0);
+ cnt = tty_insert_flip_string(tty, data, length);
+ if (cnt < length) {
+ dev_err(dev, "%s - dropping data, %d bytes lost\n",
+ __func__, length - cnt);
+ }
+ data += cnt;
+ length -= cnt;
tty_flip_buffer_push(tty);
}
@@ -2530,7 +2489,7 @@ static int calc_baud_rate_divisor(int baudrate, int *divisor)
*divisor = custom;
- dbg("%s - Baud %d = %d\n", __func__, baudrate, custom);
+ dbg("%s - Baud %d = %d", __func__, baudrate, custom);
return 0;
}
@@ -2915,7 +2874,7 @@ static void load_application_firmware(struct edgeport_serial *edge_serial)
break;
case EDGE_DOWNLOAD_FILE_NONE:
- dbg ("No download file specified, skipping download\n");
+ dbg("No download file specified, skipping download");
return;
default:
@@ -2997,10 +2956,12 @@ static int edge_startup(struct usb_serial *serial)
usb_set_serial_data(serial, edge_serial);
/* get the name for the device from the device */
- i = get_string(dev, dev->descriptor.iManufacturer,
+ i = usb_string(dev, dev->descriptor.iManufacturer,
&edge_serial->name[0], MAX_NAME_LEN+1);
+ if (i < 0)
+ i = 0;
edge_serial->name[i++] = ' ';
- get_string(dev, dev->descriptor.iProduct,
+ usb_string(dev, dev->descriptor.iProduct,
&edge_serial->name[i], MAX_NAME_LEN+2 - i);
dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index 9241d3147513..feb56a4ca799 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -14,7 +14,7 @@
#ifndef IO_TABLES_H
#define IO_TABLES_H
-static struct usb_device_id edgeport_2port_id_table [] = {
+static const struct usb_device_id edgeport_2port_id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) },
@@ -23,7 +23,7 @@ static struct usb_device_id edgeport_2port_id_table [] = {
{ }
};
-static struct usb_device_id edgeport_4port_id_table [] = {
+static const struct usb_device_id edgeport_4port_id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) },
@@ -37,7 +37,7 @@ static struct usb_device_id edgeport_4port_id_table [] = {
{ }
};
-static struct usb_device_id edgeport_8port_id_table [] = {
+static const struct usb_device_id edgeport_8port_id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) },
@@ -47,7 +47,7 @@ static struct usb_device_id edgeport_8port_id_table [] = {
{ }
};
-static struct usb_device_id Epic_port_id_table [] = {
+static const struct usb_device_id Epic_port_id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
@@ -60,7 +60,7 @@ static struct usb_device_id Epic_port_id_table [] = {
};
/* Devices that this driver supports */
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) },
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index d4cc0f7af400..aa876f71f228 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -134,7 +134,7 @@ struct edgeport_serial {
/* Devices that this driver supports */
-static struct usb_device_id edgeport_1port_id_table [] = {
+static const struct usb_device_id edgeport_1port_id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) },
@@ -154,7 +154,7 @@ static struct usb_device_id edgeport_1port_id_table [] = {
{ }
};
-static struct usb_device_id edgeport_2port_id_table [] = {
+static const struct usb_device_id edgeport_2port_id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
@@ -177,7 +177,7 @@ static struct usb_device_id edgeport_2port_id_table [] = {
};
/* Devices that this driver supports */
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) },
@@ -413,11 +413,18 @@ static int write_boot_mem(struct edgeport_serial *serial,
{
int status = 0;
int i;
- __u8 temp;
+ u8 *temp;
/* Must do a read before write */
if (!serial->TiReadI2C) {
- status = read_boot_mem(serial, 0, 1, &temp);
+ temp = kmalloc(1, GFP_KERNEL);
+ if (!temp) {
+ dev_err(&serial->serial->dev->dev,
+ "%s - out of memory\n", __func__);
+ return -ENOMEM;
+ }
+ status = read_boot_mem(serial, 0, 1, temp);
+ kfree(temp);
if (status)
return status;
}
@@ -935,37 +942,47 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev)
static int i2c_type_bootmode(struct edgeport_serial *serial)
{
int status;
- __u8 data;
+ u8 *data;
+
+ data = kmalloc(1, GFP_KERNEL);
+ if (!data) {
+ dev_err(&serial->serial->dev->dev,
+ "%s - out of memory\n", __func__);
+ return -ENOMEM;
+ }
/* Try to read type 2 */
status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ,
- DTK_ADDR_SPACE_I2C_TYPE_II, 0, &data, 0x01);
+ DTK_ADDR_SPACE_I2C_TYPE_II, 0, data, 0x01);
if (status)
dbg("%s - read 2 status error = %d", __func__, status);
else
- dbg("%s - read 2 data = 0x%x", __func__, data);
- if ((!status) && (data == UMP5152 || data == UMP3410)) {
+ dbg("%s - read 2 data = 0x%x", __func__, *data);
+ if ((!status) && (*data == UMP5152 || *data == UMP3410)) {
dbg("%s - ROM_TYPE_II", __func__);
serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
- return 0;
+ goto out;
}
/* Try to read type 3 */
status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ,
- DTK_ADDR_SPACE_I2C_TYPE_III, 0, &data, 0x01);
+ DTK_ADDR_SPACE_I2C_TYPE_III, 0, data, 0x01);
if (status)
dbg("%s - read 3 status error = %d", __func__, status);
else
- dbg("%s - read 2 data = 0x%x", __func__, data);
- if ((!status) && (data == UMP5152 || data == UMP3410)) {
+ dbg("%s - read 2 data = 0x%x", __func__, *data);
+ if ((!status) && (*data == UMP5152 || *data == UMP3410)) {
dbg("%s - ROM_TYPE_III", __func__);
serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III;
- return 0;
+ goto out;
}
dbg("%s - Unknown", __func__);
serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
- return -ENODEV;
+ status = -ENODEV;
+out:
+ kfree(data);
+ return status;
}
static int bulk_xfer(struct usb_serial *serial, void *buffer,
@@ -1113,7 +1130,7 @@ static int download_fw(struct edgeport_serial *serial)
I2C_DESC_TYPE_FIRMWARE_BASIC, rom_desc);
if (start_address != 0) {
struct ti_i2c_firmware_rec *firmware_version;
- __u8 record;
+ u8 *record;
dbg("%s - Found Type FIRMWARE (Type 2) record",
__func__);
@@ -1165,6 +1182,15 @@ static int download_fw(struct edgeport_serial *serial)
OperationalMajorVersion,
OperationalMinorVersion);
+ record = kmalloc(1, GFP_KERNEL);
+ if (!record) {
+ dev_err(dev, "%s - out of memory.\n",
+ __func__);
+ kfree(firmware_version);
+ kfree(rom_desc);
+ kfree(ti_manuf_desc);
+ return -ENOMEM;
+ }
/* In order to update the I2C firmware we must
* change the type 2 record to type 0xF2. This
* will force the UMP to come up in Boot Mode.
@@ -1177,13 +1203,14 @@ static int download_fw(struct edgeport_serial *serial)
* firmware will update the record type from
* 0xf2 to 0x02.
*/
- record = I2C_DESC_TYPE_FIRMWARE_BLANK;
+ *record = I2C_DESC_TYPE_FIRMWARE_BLANK;
/* Change the I2C Firmware record type to
0xf2 to trigger an update */
status = write_rom(serial, start_address,
- sizeof(record), &record);
+ sizeof(*record), record);
if (status) {
+ kfree(record);
kfree(firmware_version);
kfree(rom_desc);
kfree(ti_manuf_desc);
@@ -1196,19 +1223,21 @@ static int download_fw(struct edgeport_serial *serial)
*/
status = read_rom(serial,
start_address,
- sizeof(record),
- &record);
+ sizeof(*record),
+ record);
if (status) {
+ kfree(record);
kfree(firmware_version);
kfree(rom_desc);
kfree(ti_manuf_desc);
return status;
}
- if (record != I2C_DESC_TYPE_FIRMWARE_BLANK) {
+ if (*record != I2C_DESC_TYPE_FIRMWARE_BLANK) {
dev_err(dev,
"%s - error resetting device\n",
__func__);
+ kfree(record);
kfree(firmware_version);
kfree(rom_desc);
kfree(ti_manuf_desc);
@@ -1226,6 +1255,7 @@ static int download_fw(struct edgeport_serial *serial)
__func__, status);
/* return an error on purpose. */
+ kfree(record);
kfree(firmware_version);
kfree(rom_desc);
kfree(ti_manuf_desc);
@@ -1686,7 +1716,7 @@ static void edge_interrupt_callback(struct urb *urb)
case TIUMP_INTERRUPT_CODE_MSR: /* MSR */
/* Copy MSR from UMP */
msr = data[1];
- dbg("%s - ===== Port %u MSR Status = %02x ======\n",
+ dbg("%s - ===== Port %u MSR Status = %02x ======",
__func__, port_number, msr);
handle_new_msr(edge_port, msr);
break;
@@ -1790,7 +1820,6 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty,
{
int queued;
- tty_buffer_request_room(tty, length);
queued = tty_insert_flip_string(tty, data, length);
if (queued < length)
dev_err(dev, "%s - dropping data, %d bytes lost\n",
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index d6231c38813e..3fea9298eb15 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -747,7 +747,6 @@ static void ipaq_read_bulk_callback(struct urb *urb)
tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
- tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
bytes_in += urb->actual_length;
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 727d323f092a..e1d07840cee6 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -134,7 +134,7 @@ enum {
#define IPW_WANTS_TO_SEND 0x30
-static struct usb_device_id usb_ipw_ids[] = {
+static const struct usb_device_id usb_ipw_ids[] = {
{ USB_DEVICE(IPW_VID, IPW_PID) },
{ },
};
@@ -172,7 +172,6 @@ static void ipw_read_bulk_callback(struct urb *urb)
tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
- tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 95d8d26b9a44..4a0f51974232 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -100,7 +100,7 @@ static u8 ir_baud;
static u8 ir_xbof;
static u8 ir_add_bof;
-static struct usb_device_id ir_id_table[] = {
+static const struct usb_device_id ir_id_table[] = {
{ USB_DEVICE(0x050f, 0x0180) }, /* KC Technology, KC-180 */
{ USB_DEVICE(0x08e9, 0x0100) }, /* XTNDAccess */
{ USB_DEVICE(0x09c4, 0x0011) }, /* ACTiSys ACT-IR2000U */
@@ -445,11 +445,6 @@ static void ir_read_bulk_callback(struct urb *urb)
dbg("%s - port %d", __func__, port->number);
- if (!port->port.count) {
- dbg("%s - port closed.", __func__);
- return;
- }
-
switch (status) {
case 0: /* Successful */
/*
@@ -462,10 +457,8 @@ static void ir_read_bulk_callback(struct urb *urb)
usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
tty = tty_port_tty_get(&port->port);
- if (tty_buffer_request_room(tty, urb->actual_length - 1)) {
- tty_insert_flip_string(tty, data+1, urb->actual_length - 1);
- tty_flip_buffer_push(tty);
- }
+ tty_insert_flip_string(tty, data+1, urb->actual_length - 1);
+ tty_flip_buffer_push(tty);
tty_kref_put(tty);
/*
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index e6e02b178d2b..43f13cf2f016 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -43,7 +43,7 @@ static int debug;
#define DRIVER_VERSION "v0.11"
#define DRIVER_DESC "Infinity USB Unlimited Phoenix driver"
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
{USB_DEVICE(IUU_USB_VENDOR_ID, IUU_USB_PRODUCT_ID)},
{} /* Terminating entry */
};
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index f8c4b07033ff..297163c3c610 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -464,13 +464,9 @@ static void usa26_indat_callback(struct urb *urb)
/* Resubmit urb so we continue receiving */
urb->dev = port->serial->dev;
- if (port->port.count) {
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err != 0)
- dbg("%s - resubmit read urb failed. (%d)",
- __func__, err);
- }
- return;
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err != 0)
+ dbg("%s - resubmit read urb failed. (%d)", __func__, err);
}
/* Outdat handling is common for all devices */
@@ -483,8 +479,7 @@ static void usa2x_outdat_callback(struct urb *urb)
p_priv = usb_get_serial_port_data(port);
dbg("%s - urb %d", __func__, urb == p_priv->out_urbs[1]);
- if (port->port.count)
- usb_serial_port_softint(port);
+ usb_serial_port_softint(port);
}
static void usa26_inack_callback(struct urb *urb)
@@ -615,12 +610,10 @@ static void usa28_indat_callback(struct urb *urb)
/* Resubmit urb so we continue receiving */
urb->dev = port->serial->dev;
- if (port->port.count) {
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err != 0)
- dbg("%s - resubmit read urb failed. (%d)",
- __func__, err);
- }
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err != 0)
+ dbg("%s - resubmit read urb failed. (%d)",
+ __func__, err);
p_priv->in_flip ^= 1;
urb = p_priv->in_urbs[p_priv->in_flip];
@@ -856,12 +849,9 @@ static void usa49_indat_callback(struct urb *urb)
/* Resubmit urb so we continue receiving */
urb->dev = port->serial->dev;
- if (port->port.count) {
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err != 0)
- dbg("%s - resubmit read urb failed. (%d)",
- __func__, err);
- }
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err != 0)
+ dbg("%s - resubmit read urb failed. (%d)", __func__, err);
}
static void usa49wg_indat_callback(struct urb *urb)
@@ -904,11 +894,7 @@ static void usa49wg_indat_callback(struct urb *urb)
/* no error on any byte */
i++;
for (x = 1; x < len ; ++x)
- if (port->port.count)
- tty_insert_flip_char(tty,
- data[i++], 0);
- else
- i++;
+ tty_insert_flip_char(tty, data[i++], 0);
} else {
/*
* some bytes had errors, every byte has status
@@ -922,14 +908,12 @@ static void usa49wg_indat_callback(struct urb *urb)
if (stat & RXERROR_PARITY)
flag |= TTY_PARITY;
/* XXX should handle break (0x10) */
- if (port->port.count)
- tty_insert_flip_char(tty,
+ tty_insert_flip_char(tty,
data[i+1], flag);
i += 2;
}
}
- if (port->port.count)
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(tty);
tty_kref_put(tty);
}
}
@@ -1013,13 +997,9 @@ static void usa90_indat_callback(struct urb *urb)
/* Resubmit urb so we continue receiving */
urb->dev = port->serial->dev;
- if (port->port.count) {
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err != 0)
- dbg("%s - resubmit read urb failed. (%d)",
- __func__, err);
- }
- return;
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err != 0)
+ dbg("%s - resubmit read urb failed. (%d)", __func__, err);
}
@@ -2418,8 +2398,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,
msg.portEnabled = 0;
/* Sending intermediate configs */
else {
- if (port->port.count)
- msg.portEnabled = 1;
+ msg.portEnabled = 1;
msg.txBreak = (p_priv->break_on);
}
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 30771e5b3973..bf3297ddd186 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -456,7 +456,7 @@ static const struct keyspan_device_details *keyspan_devices[] = {
NULL,
};
-static struct usb_device_id keyspan_ids_combined[] = {
+static const struct usb_device_id keyspan_ids_combined[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
@@ -497,7 +497,7 @@ static struct usb_driver keyspan_driver = {
};
/* usb_device_id table for the pre-firmware download keyspan devices */
-static struct usb_device_id keyspan_pre_ids[] = {
+static const struct usb_device_id keyspan_pre_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) },
@@ -513,7 +513,7 @@ static struct usb_device_id keyspan_pre_ids[] = {
{ } /* Terminating entry */
};
-static struct usb_device_id keyspan_1port_ids[] = {
+static const struct usb_device_id keyspan_1port_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
@@ -524,7 +524,7 @@ static struct usb_device_id keyspan_1port_ids[] = {
{ } /* Terminating entry */
};
-static struct usb_device_id keyspan_2port_ids[] = {
+static const struct usb_device_id keyspan_2port_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
@@ -532,7 +532,7 @@ static struct usb_device_id keyspan_2port_ids[] = {
{ } /* Terminating entry */
};
-static struct usb_device_id keyspan_4port_ids[] = {
+static const struct usb_device_id keyspan_4port_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)},
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 1296a097f5c3..185fe9a7d4e0 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -125,7 +125,7 @@ struct keyspan_pda_private {
#define ENTREGRA_VENDOR_ID 0x1645
#define ENTREGRA_FAKE_ID 0x8093
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
#ifdef KEYSPAN
{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) },
#endif
@@ -147,20 +147,20 @@ static struct usb_driver keyspan_pda_driver = {
.no_dynamic_id = 1,
};
-static struct usb_device_id id_table_std [] = {
+static const struct usb_device_id id_table_std[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
{ } /* Terminating entry */
};
#ifdef KEYSPAN
-static struct usb_device_id id_table_fake [] = {
+static const struct usb_device_id id_table_fake[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) },
{ } /* Terminating entry */
};
#endif
#ifdef XIRCOM
-static struct usb_device_id id_table_fake_xircom [] = {
+static const struct usb_device_id id_table_fake_xircom[] = {
{ USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
{ USB_DEVICE(ENTREGRA_VENDOR_ID, ENTREGRA_FAKE_ID) },
{ }
@@ -429,13 +429,20 @@ static int keyspan_pda_get_modem_info(struct usb_serial *serial,
unsigned char *value)
{
int rc;
- unsigned char data;
+ u8 *data;
+
+ data = kmalloc(1, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
3, /* get pins */
USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
- 0, 0, &data, 1, 2000);
+ 0, 0, data, 1, 2000);
if (rc >= 0)
- *value = data;
+ *value = *data;
+
+ kfree(data);
return rc;
}
@@ -543,7 +550,14 @@ static int keyspan_pda_write(struct tty_struct *tty,
device how much room it really has. This is done only on
scheduler time, since usb_control_msg() sleeps. */
if (count > priv->tx_room && !in_interrupt()) {
- unsigned char room;
+ u8 *room;
+
+ room = kmalloc(1, GFP_KERNEL);
+ if (!room) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
rc = usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
6, /* write_room */
@@ -551,9 +565,14 @@ static int keyspan_pda_write(struct tty_struct *tty,
| USB_DIR_IN,
0, /* value: 0 means "remaining room" */
0, /* index */
- &room,
+ room,
1,
2000);
+ if (rc > 0) {
+ dbg(" roomquery says %d", *room);
+ priv->tx_room = *room;
+ }
+ kfree(room);
if (rc < 0) {
dbg(" roomquery failed");
goto exit;
@@ -563,8 +582,6 @@ static int keyspan_pda_write(struct tty_struct *tty,
rc = -EIO; /* device didn't return any data */
goto exit;
}
- dbg(" roomquery says %d", room);
- priv->tx_room = room;
}
if (count > priv->tx_room) {
/* we're about to completely fill the Tx buffer, so
@@ -684,18 +701,22 @@ static int keyspan_pda_open(struct tty_struct *tty,
struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
- unsigned char room;
+ u8 *room;
int rc = 0;
struct keyspan_pda_private *priv;
/* find out how much room is in the Tx ring */
+ room = kmalloc(1, GFP_KERNEL);
+ if (!room)
+ return -ENOMEM;
+
rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
6, /* write_room */
USB_TYPE_VENDOR | USB_RECIP_INTERFACE
| USB_DIR_IN,
0, /* value */
0, /* index */
- &room,
+ room,
1,
2000);
if (rc < 0) {
@@ -708,8 +729,8 @@ static int keyspan_pda_open(struct tty_struct *tty,
goto error;
}
priv = usb_get_serial_port_data(port);
- priv->tx_room = room;
- priv->tx_throttled = room ? 0 : 1;
+ priv->tx_room = *room;
+ priv->tx_throttled = *room ? 0 : 1;
/*Start reading from the device*/
port->interrupt_in_urb->dev = serial->dev;
@@ -718,8 +739,8 @@ static int keyspan_pda_open(struct tty_struct *tty,
dbg("%s - usb_submit_urb(read int) failed", __func__);
goto error;
}
-
error:
+ kfree(room);
return rc;
}
static void keyspan_pda_close(struct usb_serial_port *port)
@@ -789,6 +810,13 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial)
return 1;
}
+#ifdef KEYSPAN
+MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw");
+#endif
+#ifdef XIRCOM
+MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw");
+#endif
+
static int keyspan_pda_startup(struct usb_serial *serial)
{
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 3a7873806f46..8eef91ba4b1c 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -94,7 +94,7 @@ static int klsi_105_tiocmset(struct tty_struct *tty, struct file *file,
/*
* All of the device info needed for the KLSI converters.
*/
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },
{ USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) },
{ } /* Terminating entry */
@@ -212,10 +212,19 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
unsigned long *line_state_p)
{
int rc;
- __u8 status_buf[KLSI_STATUSBUF_LEN] = { -1, -1};
+ u8 *status_buf;
__u16 status;
dev_info(&port->serial->dev->dev, "sending SIO Poll request\n");
+
+ status_buf = kmalloc(KLSI_STATUSBUF_LEN, GFP_KERNEL);
+ if (!status_buf) {
+ dev_err(&port->dev, "%s - out of memory for status buffer.\n",
+ __func__);
+ return -ENOMEM;
+ }
+ status_buf[0] = 0xff;
+ status_buf[1] = 0xff;
rc = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
KL5KUSB105A_SIO_POLL,
@@ -236,6 +245,8 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
*line_state_p = klsi_105_status2linestate(status);
}
+
+ kfree(status_buf);
return rc;
}
@@ -364,7 +375,7 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
int rc;
int i;
unsigned long line_state;
- struct klsi_105_port_settings cfg;
+ struct klsi_105_port_settings *cfg;
unsigned long flags;
dbg("%s port %d", __func__, port->number);
@@ -376,12 +387,18 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
* Then read the modem line control and store values in
* priv->line_state.
*/
- cfg.pktlen = 5;
- cfg.baudrate = kl5kusb105a_sio_b9600;
- cfg.databits = kl5kusb105a_dtb_8;
- cfg.unknown1 = 0;
- cfg.unknown2 = 1;
- klsi_105_chg_port_settings(port, &cfg);
+ cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg) {
+ dev_err(&port->dev, "%s - out of memory for config buffer.\n",
+ __func__);
+ return -ENOMEM;
+ }
+ cfg->pktlen = 5;
+ cfg->baudrate = kl5kusb105a_sio_b9600;
+ cfg->databits = kl5kusb105a_dtb_8;
+ cfg->unknown1 = 0;
+ cfg->unknown2 = 1;
+ klsi_105_chg_port_settings(port, cfg);
/* set up termios structure */
spin_lock_irqsave(&priv->lock, flags);
@@ -391,11 +408,11 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
priv->termios.c_lflag = tty->termios->c_lflag;
for (i = 0; i < NCCS; i++)
priv->termios.c_cc[i] = tty->termios->c_cc[i];
- priv->cfg.pktlen = cfg.pktlen;
- priv->cfg.baudrate = cfg.baudrate;
- priv->cfg.databits = cfg.databits;
- priv->cfg.unknown1 = cfg.unknown1;
- priv->cfg.unknown2 = cfg.unknown2;
+ priv->cfg.pktlen = cfg->pktlen;
+ priv->cfg.baudrate = cfg->baudrate;
+ priv->cfg.databits = cfg->databits;
+ priv->cfg.unknown1 = cfg->unknown1;
+ priv->cfg.unknown2 = cfg->unknown2;
spin_unlock_irqrestore(&priv->lock, flags);
/* READ_ON and urb submission */
@@ -441,6 +458,7 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
retval = rc;
exit:
+ kfree(cfg);
return retval;
} /* klsi_105_open */
@@ -681,7 +699,6 @@ static void klsi_105_read_bulk_callback(struct urb *urb)
bytes_sent = urb->actual_length - 2;
}
- tty_buffer_request_room(tty, bytes_sent);
tty_insert_flip_string(tty, data + 2, bytes_sent);
tty_flip_buffer_push(tty);
tty_kref_put(tty);
@@ -714,10 +731,17 @@ static void klsi_105_set_termios(struct tty_struct *tty,
unsigned int old_iflag = old_termios->c_iflag;
unsigned int cflag = tty->termios->c_cflag;
unsigned int old_cflag = old_termios->c_cflag;
- struct klsi_105_port_settings cfg;
+ struct klsi_105_port_settings *cfg;
unsigned long flags;
speed_t baud;
+ cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg) {
+ dev_err(&port->dev, "%s - out of memory for config buffer.\n",
+ __func__);
+ return;
+ }
+
/* lock while we are modifying the settings */
spin_lock_irqsave(&priv->lock, flags);
@@ -793,11 +817,11 @@ static void klsi_105_set_termios(struct tty_struct *tty,
case CS5:
dbg("%s - 5 bits/byte not supported", __func__);
spin_unlock_irqrestore(&priv->lock, flags);
- return ;
+ goto err;
case CS6:
dbg("%s - 6 bits/byte not supported", __func__);
spin_unlock_irqrestore(&priv->lock, flags);
- return ;
+ goto err;
case CS7:
priv->cfg.databits = kl5kusb105a_dtb_7;
break;
@@ -856,11 +880,13 @@ static void klsi_105_set_termios(struct tty_struct *tty,
#endif
;
}
- memcpy(&cfg, &priv->cfg, sizeof(cfg));
+ memcpy(cfg, &priv->cfg, sizeof(*cfg));
spin_unlock_irqrestore(&priv->lock, flags);
/* now commit changes to device */
- klsi_105_chg_port_settings(port, &cfg);
+ klsi_105_chg_port_settings(port, cfg);
+err:
+ kfree(cfg);
} /* klsi_105_set_termios */
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 45ea694b3ae6..c113a2a0e10c 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -86,7 +86,7 @@ static void kobil_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static void kobil_init_termios(struct tty_struct *tty);
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },
{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_K_PRODUCT_ID) },
{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_USBTWIN_PRODUCT_ID) },
@@ -388,7 +388,6 @@ static void kobil_read_int_callback(struct urb *urb)
*/
/* END DEBUG */
- tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
@@ -624,7 +623,6 @@ static void kobil_set_termios(struct tty_struct *tty,
unsigned short urb_val = 0;
int c_cflag = tty->termios->c_cflag;
speed_t speed;
- void *settings;
priv = usb_get_serial_port_data(port);
if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
@@ -647,25 +645,13 @@ static void kobil_set_termios(struct tty_struct *tty,
}
urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits :
SUSBCR_SPASB_1StopBit;
-
- settings = kzalloc(50, GFP_KERNEL);
- if (!settings)
- return;
-
- sprintf(settings, "%d ", speed);
-
if (c_cflag & PARENB) {
- if (c_cflag & PARODD) {
+ if (c_cflag & PARODD)
urb_val |= SUSBCR_SPASB_OddParity;
- strcat(settings, "Odd Parity");
- } else {
+ else
urb_val |= SUSBCR_SPASB_EvenParity;
- strcat(settings, "Even Parity");
- }
- } else {
+ } else
urb_val |= SUSBCR_SPASB_NoParity;
- strcat(settings, "No Parity");
- }
tty->termios->c_cflag &= ~CMSPAR;
tty_encode_baud_rate(tty, speed, speed);
@@ -675,11 +661,10 @@ static void kobil_set_termios(struct tty_struct *tty,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
urb_val,
0,
- settings,
+ NULL,
0,
KOBIL_TIMEOUT
);
- kfree(settings);
}
static int kobil_ioctl(struct tty_struct *tty, struct file *file,
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index cd009cb280a5..2849f8c32015 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -75,6 +75,7 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
+#include <asm/unaligned.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include "mct_u232.h"
@@ -110,7 +111,7 @@ static void mct_u232_unthrottle(struct tty_struct *tty);
/*
* All of the device info needed for the MCT USB-RS232 converter.
*/
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
{ USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
{ USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
@@ -231,19 +232,22 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial,
static int mct_u232_set_baud_rate(struct tty_struct *tty,
struct usb_serial *serial, struct usb_serial_port *port, speed_t value)
{
- __le32 divisor;
+ unsigned int divisor;
int rc;
- unsigned char zero_byte = 0;
+ unsigned char *buf;
unsigned char cts_enable_byte = 0;
speed_t speed;
- divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value,
- &speed));
+ buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+ divisor = mct_u232_calculate_baud_rate(serial, value, &speed);
+ put_unaligned_le32(cpu_to_le32(divisor), buf);
rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
MCT_U232_SET_BAUD_RATE_REQUEST,
MCT_U232_SET_REQUEST_TYPE,
- 0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE,
+ 0, 0, buf, MCT_U232_SET_BAUD_RATE_SIZE,
WDR_TIMEOUT);
if (rc < 0) /*FIXME: What value speed results */
dev_err(&port->dev, "Set BAUD RATE %d failed (error = %d)\n",
@@ -269,10 +273,11 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty,
a device which is not asserting 'CTS'.
*/
+ buf[0] = 0;
rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
MCT_U232_SET_UNKNOWN1_REQUEST,
MCT_U232_SET_REQUEST_TYPE,
- 0, 0, &zero_byte, MCT_U232_SET_UNKNOWN1_SIZE,
+ 0, 0, buf, MCT_U232_SET_UNKNOWN1_SIZE,
WDR_TIMEOUT);
if (rc < 0)
dev_err(&port->dev, "Sending USB device request code %d "
@@ -284,30 +289,40 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty,
dbg("set_baud_rate: send second control message, data = %02X",
cts_enable_byte);
+ buf[0] = cts_enable_byte;
rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
MCT_U232_SET_CTS_REQUEST,
MCT_U232_SET_REQUEST_TYPE,
- 0, 0, &cts_enable_byte, MCT_U232_SET_CTS_SIZE,
+ 0, 0, buf, MCT_U232_SET_CTS_SIZE,
WDR_TIMEOUT);
if (rc < 0)
dev_err(&port->dev, "Sending USB device request code %d "
"failed (error = %d)\n", MCT_U232_SET_CTS_REQUEST, rc);
+ kfree(buf);
return rc;
} /* mct_u232_set_baud_rate */
static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr)
{
int rc;
+ unsigned char *buf;
+
+ buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ buf[0] = lcr;
rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
MCT_U232_SET_LINE_CTRL_REQUEST,
MCT_U232_SET_REQUEST_TYPE,
- 0, 0, &lcr, MCT_U232_SET_LINE_CTRL_SIZE,
+ 0, 0, buf, MCT_U232_SET_LINE_CTRL_SIZE,
WDR_TIMEOUT);
if (rc < 0)
dev_err(&serial->dev->dev,
"Set LINE CTRL 0x%x failed (error = %d)\n", lcr, rc);
dbg("set_line_ctrl: 0x%x", lcr);
+ kfree(buf);
return rc;
} /* mct_u232_set_line_ctrl */
@@ -315,23 +330,31 @@ static int mct_u232_set_modem_ctrl(struct usb_serial *serial,
unsigned int control_state)
{
int rc;
- unsigned char mcr = MCT_U232_MCR_NONE;
+ unsigned char mcr;
+ unsigned char *buf;
+
+ buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+ mcr = MCT_U232_MCR_NONE;
if (control_state & TIOCM_DTR)
mcr |= MCT_U232_MCR_DTR;
if (control_state & TIOCM_RTS)
mcr |= MCT_U232_MCR_RTS;
+ buf[0] = mcr;
rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
MCT_U232_SET_MODEM_CTRL_REQUEST,
MCT_U232_SET_REQUEST_TYPE,
- 0, 0, &mcr, MCT_U232_SET_MODEM_CTRL_SIZE,
+ 0, 0, buf, MCT_U232_SET_MODEM_CTRL_SIZE,
WDR_TIMEOUT);
if (rc < 0)
dev_err(&serial->dev->dev,
"Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc);
dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr);
+ kfree(buf);
return rc;
} /* mct_u232_set_modem_ctrl */
@@ -339,17 +362,27 @@ static int mct_u232_get_modem_stat(struct usb_serial *serial,
unsigned char *msr)
{
int rc;
+ unsigned char *buf;
+
+ buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
+ if (buf == NULL) {
+ *msr = 0;
+ return -ENOMEM;
+ }
rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
MCT_U232_GET_MODEM_STAT_REQUEST,
MCT_U232_GET_REQUEST_TYPE,
- 0, 0, msr, MCT_U232_GET_MODEM_STAT_SIZE,
+ 0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE,
WDR_TIMEOUT);
if (rc < 0) {
dev_err(&serial->dev->dev,
"Get MODEM STATus failed (error = %d)\n", rc);
*msr = 0;
+ } else {
+ *msr = buf[0];
}
dbg("get_modem_stat: 0x%x", *msr);
+ kfree(buf);
return rc;
} /* mct_u232_get_modem_stat */
diff --git a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h
index 07b6bec31dc8..7417d5ce1e23 100644
--- a/drivers/usb/serial/mct_u232.h
+++ b/drivers/usb/serial/mct_u232.h
@@ -73,6 +73,8 @@
#define MCT_U232_SET_CTS_REQUEST 12
#define MCT_U232_SET_CTS_SIZE 1
+#define MCT_U232_MAX_SIZE 4 /* of MCT_XXX_SIZE */
+
/*
* Baud rate (divisor)
* Actually, there are two of them, MCT website calls them "Philips solution"
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 763e32a44be0..0d47f2c4d59f 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -81,12 +81,15 @@ struct moschip_serial {
static int debug;
+static struct usb_serial_driver moschip7720_2port_driver;
+
#define USB_VENDOR_ID_MOSCHIP 0x9710
#define MOSCHIP_DEVICE_ID_7720 0x7720
#define MOSCHIP_DEVICE_ID_7715 0x7715
-static struct usb_device_id moschip_port_id_table[] = {
+static const struct usb_device_id moschip_port_id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) },
+ { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7715) },
{ } /* terminating entry */
};
MODULE_DEVICE_TABLE(usb, moschip_port_id_table);
@@ -106,7 +109,7 @@ static void mos7720_interrupt_callback(struct urb *urb)
__u8 sp1;
__u8 sp2;
- dbg("%s", " : Entering\n");
+ dbg(" : Entering");
switch (status) {
case 0:
@@ -186,6 +189,75 @@ exit:
}
/*
+ * mos7715_interrupt_callback
+ * this is the 7715's callback function for when we have received data on
+ * the interrupt endpoint.
+ */
+static void mos7715_interrupt_callback(struct urb *urb)
+{
+ int result;
+ int length;
+ int status = urb->status;
+ __u8 *data;
+ __u8 iir;
+
+ switch (status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __func__,
+ status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d", __func__,
+ status);
+ goto exit;
+ }
+
+ length = urb->actual_length;
+ data = urb->transfer_buffer;
+
+ /* Structure of data from 7715 device:
+ * Byte 1: IIR serial Port
+ * Byte 2: unused
+ * Byte 2: DSR parallel port
+ * Byte 4: FIFO status for both */
+
+ if (unlikely(length != 4)) {
+ dbg("Wrong data !!!");
+ return;
+ }
+
+ iir = data[0];
+ if (!(iir & 0x01)) { /* serial port interrupt pending */
+ switch (iir & 0x0f) {
+ case SERIAL_IIR_RLS:
+ dbg("Serial Port: Receiver status error or address "
+ "bit detected in 9-bit mode\n");
+ break;
+ case SERIAL_IIR_CTI:
+ dbg("Serial Port: Receiver time out");
+ break;
+ case SERIAL_IIR_MS:
+ dbg("Serial Port: Modem status change");
+ break;
+ }
+ }
+
+exit:
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&urb->dev->dev,
+ "%s - Error %d submitting control urb\n",
+ __func__, result);
+ return;
+}
+
+/*
* mos7720_bulk_in_callback
* this is the callback function for when we have received data on the
* bulk in endpoint.
@@ -206,7 +278,7 @@ static void mos7720_bulk_in_callback(struct urb *urb)
mos7720_port = urb->context;
if (!mos7720_port) {
- dbg("%s", "NULL mos7720_port pointer \n");
+ dbg("NULL mos7720_port pointer");
return ;
}
@@ -218,7 +290,6 @@ static void mos7720_bulk_in_callback(struct urb *urb)
tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
- tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
@@ -275,17 +346,15 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
* this function will be used for sending command to device
*/
static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value,
- __u16 index, void *data)
+ __u16 index, u8 *data)
{
int status;
- unsigned int pipe;
+ u8 *buf;
u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
- __u8 requesttype;
- __u16 size = 0x0000;
if (value < MOS_MAX_PORT) {
if (product == MOSCHIP_DEVICE_ID_7715)
- value = value*0x100+0x100;
+ value = 0x0200; /* identifies the 7715's serial port */
else
value = value*0x100+0x200;
} else {
@@ -298,27 +367,58 @@ static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value,
}
if (request == MOS_WRITE) {
- request = (__u8)MOS_WRITE;
- requesttype = (__u8)0x40;
- value = value + (__u16)*((unsigned char *)data);
- data = NULL;
- pipe = usb_sndctrlpipe(serial->dev, 0);
+ value = value + *data;
+ status = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0), MOS_WRITE,
+ 0x40, value, index, NULL, 0, MOS_WDR_TIMEOUT);
} else {
- request = (__u8)MOS_READ;
- requesttype = (__u8)0xC0;
- size = 0x01;
- pipe = usb_rcvctrlpipe(serial->dev, 0);
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf) {
+ status = -ENOMEM;
+ goto out;
+ }
+ status = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0), MOS_READ,
+ 0xc0, value, index, buf, 1, MOS_WDR_TIMEOUT);
+ *data = *buf;
+ kfree(buf);
}
-
- status = usb_control_msg(serial->dev, pipe, request, requesttype,
- value, index, data, size, MOS_WDR_TIMEOUT);
-
+out:
if (status < 0)
- dbg("Command Write failed Value %x index %x\n", value, index);
+ dbg("Command Write failed Value %x index %x", value, index);
return status;
}
+
+/*
+ * mos77xx_probe
+ * this function installs the appropriate read interrupt endpoint callback
+ * depending on whether the device is a 7720 or 7715, thus avoiding costly
+ * run-time checks in the high-frequency callback routine itself.
+ */
+static int mos77xx_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+ if (id->idProduct == MOSCHIP_DEVICE_ID_7715)
+ moschip7720_2port_driver.read_int_callback =
+ mos7715_interrupt_callback;
+ else
+ moschip7720_2port_driver.read_int_callback =
+ mos7720_interrupt_callback;
+
+ return 0;
+}
+
+static int mos77xx_calc_num_ports(struct usb_serial *serial)
+{
+ u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
+ if (product == MOSCHIP_DEVICE_ID_7715)
+ return 1;
+
+ return 2;
+}
+
static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial;
@@ -390,7 +490,7 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
*/
port_number = port->number - port->serial->minor;
send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data);
- dbg("SS::%p LSR:%x\n", mos7720_port, data);
+ dbg("SS::%p LSR:%x", mos7720_port, data);
dbg("Check:Sending Command ..........");
@@ -729,7 +829,7 @@ static void mos7720_throttle(struct tty_struct *tty)
struct moschip_port *mos7720_port;
int status;
- dbg("%s- port %d\n", __func__, port->number);
+ dbg("%s- port %d", __func__, port->number);
mos7720_port = usb_get_serial_port_data(port);
@@ -1208,7 +1308,7 @@ static void mos7720_set_termios(struct tty_struct *tty,
return;
}
- dbg("%s\n", "setting termios - ASPIRE");
+ dbg("setting termios - ASPIRE");
cflag = tty->termios->c_cflag;
@@ -1226,7 +1326,7 @@ static void mos7720_set_termios(struct tty_struct *tty,
change_port_settings(tty, mos7720_port, old_termios);
if (!port->read_urb) {
- dbg("%s", "URB KILLED !!!!!\n");
+ dbg("URB KILLED !!!!!");
return;
}
@@ -1495,6 +1595,7 @@ static int mos7720_startup(struct usb_serial *serial)
struct usb_device *dev;
int i;
char data;
+ u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
dbg("%s: Entering ..........", __func__);
@@ -1514,6 +1615,29 @@ static int mos7720_startup(struct usb_serial *serial)
usb_set_serial_data(serial, mos7720_serial);
+ /*
+ * The 7715 uses the first bulk in/out endpoint pair for the parallel
+ * port, and the second for the serial port. Because the usbserial core
+ * assumes both pairs are serial ports, we must engage in a bit of
+ * subterfuge and swap the pointers for ports 0 and 1 in order to make
+ * port 0 point to the serial port. However, both moschip devices use a
+ * single interrupt-in endpoint for both ports (as mentioned a little
+ * further down), and this endpoint was assigned to port 0. So after
+ * the swap, we must copy the interrupt endpoint elements from port 1
+ * (as newly assigned) to port 0, and null out port 1 pointers.
+ */
+ if (product == MOSCHIP_DEVICE_ID_7715) {
+ struct usb_serial_port *tmp = serial->port[0];
+ serial->port[0] = serial->port[1];
+ serial->port[1] = tmp;
+ serial->port[0]->interrupt_in_urb = tmp->interrupt_in_urb;
+ serial->port[0]->interrupt_in_buffer = tmp->interrupt_in_buffer;
+ serial->port[0]->interrupt_in_endpointAddress =
+ tmp->interrupt_in_endpointAddress;
+ serial->port[1]->interrupt_in_urb = NULL;
+ serial->port[1]->interrupt_in_buffer = NULL;
+ }
+
/* we set up the pointers to the endpoints in the mos7720_open *
* function, as the structures aren't created yet. */
@@ -1529,7 +1653,7 @@ static int mos7720_startup(struct usb_serial *serial)
/* Initialize all port interrupt end point to port 0 int
* endpoint. Our device has only one interrupt endpoint
- * comman to all ports */
+ * common to all ports */
serial->port[i]->interrupt_in_endpointAddress =
serial->port[0]->interrupt_in_endpointAddress;
@@ -1584,11 +1708,12 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.description = "Moschip 2 port adapter",
.usb_driver = &usb_driver,
.id_table = moschip_port_id_table,
- .num_ports = 2,
+ .calc_num_ports = mos77xx_calc_num_ports,
.open = mos7720_open,
.close = mos7720_close,
.throttle = mos7720_throttle,
.unthrottle = mos7720_unthrottle,
+ .probe = mos77xx_probe,
.attach = mos7720_startup,
.release = mos7720_release,
.ioctl = mos7720_ioctl,
@@ -1600,7 +1725,7 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.chars_in_buffer = mos7720_chars_in_buffer,
.break_ctl = mos7720_break,
.read_bulk_callback = mos7720_bulk_in_callback,
- .read_int_callback = mos7720_interrupt_callback,
+ .read_int_callback = NULL /* dynamically assigned in probe() */
};
static int __init moschip7720_init(void)
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 2cfe2451ed97..2fda1c0182b7 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -181,7 +181,7 @@
#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
-static struct usb_device_id moschip_port_id_table[] = {
+static const struct usb_device_id moschip_port_id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
@@ -198,7 +198,7 @@ static struct usb_device_id moschip_port_id_table[] = {
{} /* terminating entry */
};
-static __devinitdata struct usb_device_id moschip_id_table_combined[] = {
+static const struct usb_device_id moschip_id_table_combined[] __devinitconst = {
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
@@ -283,12 +283,19 @@ static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg,
{
struct usb_device *dev = port->serial->dev;
int ret = 0;
+ u8 *buf;
+
+ buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
- MCS_RD_RTYPE, 0, reg, val, VENDOR_READ_LENGTH,
+ MCS_RD_RTYPE, 0, reg, buf, VENDOR_READ_LENGTH,
MOS_WDR_TIMEOUT);
+ *val = buf[0];
dbg("mos7840_get_reg_sync offset is %x, return val %x", reg, *val);
- *val = (*val) & 0x00ff;
+
+ kfree(buf);
return ret;
}
@@ -341,6 +348,11 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
struct usb_device *dev = port->serial->dev;
int ret = 0;
__u16 Wval;
+ u8 *buf;
+
+ buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
/* dbg("application number is %4x",
(((__u16)port->number - (__u16)(port->serial->minor))+1)<<8); */
@@ -364,9 +376,11 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
}
}
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
- MCS_RD_RTYPE, Wval, reg, val, VENDOR_READ_LENGTH,
+ MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH,
MOS_WDR_TIMEOUT);
- *val = (*val) & 0x00ff;
+ *val = buf[0];
+
+ kfree(buf);
return ret;
}
@@ -750,7 +764,6 @@ static void mos7840_bulk_in_callback(struct urb *urb)
if (urb->actual_length) {
tty = tty_port_tty_get(&mos7840_port->port->port);
if (tty) {
- tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
dbg(" %s ", data);
tty_flip_buffer_push(tty);
diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c
index 99bd00f5188a..cf1718394e18 100644
--- a/drivers/usb/serial/moto_modem.c
+++ b/drivers/usb/serial/moto_modem.c
@@ -21,7 +21,7 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */
{ USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */
{ USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 5ceaa4c6be09..04a6cbbed2c0 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -22,7 +22,7 @@
static int debug;
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */
{ },
};
@@ -66,7 +66,6 @@ static void navman_read_int_callback(struct urb *urb)
tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
- tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 062265038bf0..89c724c0ac0a 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -75,7 +75,7 @@ static void omninet_disconnect(struct usb_serial *serial);
static void omninet_release(struct usb_serial *serial);
static int omninet_attach(struct usb_serial *serial);
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) },
{ USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) },
{ } /* Terminating entry */
@@ -218,8 +218,8 @@ static void omninet_read_bulk_callback(struct urb *urb)
if (debug && header->oh_xxx != 0x30) {
if (urb->actual_length) {
- printk(KERN_DEBUG __FILE__
- ": omninet_read %d: ", header->oh_len);
+ printk(KERN_DEBUG "%s: omninet_read %d: ",
+ __FILE__, header->oh_len);
for (i = 0; i < (header->oh_len +
OMNINET_HEADERLEN); i++)
printk("%.2x ", data[i]);
@@ -332,7 +332,7 @@ static void omninet_write_bulk_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
int status = urb->status;
- dbg("%s - port %0x\n", __func__, port->number);
+ dbg("%s - port %0x", __func__, port->number);
port->write_urb_busy = 0;
if (status) {
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index 4cdb975caa89..701452ae9197 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -22,7 +22,7 @@
static int debug;
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x065a, 0x0009) },
{ },
};
@@ -55,7 +55,6 @@ static void opticon_bulk_callback(struct urb *urb)
int status = urb->status;
struct tty_struct *tty;
int result;
- int available_room = 0;
int data_length;
dbg("%s - port %d", __func__, port->number);
@@ -96,13 +95,9 @@ static void opticon_bulk_callback(struct urb *urb)
/* real data, send it to the tty layer */
tty = tty_port_tty_get(&port->port);
if (tty) {
- available_room = tty_buffer_request_room(tty,
- data_length);
- if (available_room) {
- tty_insert_flip_string(tty, data,
- available_room);
- tty_flip_buffer_push(tty);
- }
+ tty_insert_flip_string(tty, data,
+ data_length);
+ tty_flip_buffer_push(tty);
tty_kref_put(tty);
}
} else {
@@ -120,7 +115,7 @@ static void opticon_bulk_callback(struct urb *urb)
}
} else {
dev_dbg(&priv->udev->dev,
- "Improper ammount of data received from the device, "
+ "Improper amount of data received from the device, "
"%d bytes", urb->actual_length);
}
@@ -217,7 +212,7 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,
spin_lock_irqsave(&priv->lock, flags);
if (priv->outstanding_urbs > URB_UPPER_LIMIT) {
spin_unlock_irqrestore(&priv->lock, flags);
- dbg("%s - write limit hit\n", __func__);
+ dbg("%s - write limit hit", __func__);
return 0;
}
priv->outstanding_urbs++;
@@ -288,7 +283,7 @@ static int opticon_write_room(struct tty_struct *tty)
spin_lock_irqsave(&priv->lock, flags);
if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) {
spin_unlock_irqrestore(&priv->lock, flags);
- dbg("%s - write limit hit\n", __func__);
+ dbg("%s - write limit hit", __func__);
return 0;
}
spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 6e94a6711f08..847b805d63a3 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -336,15 +336,42 @@ static int option_resume(struct usb_serial *serial);
#define AIRPLUS_VENDOR_ID 0x1011
#define AIRPLUS_PRODUCT_MCD650 0x3198
+/* Longcheer/Longsung vendor ID; makes whitelabel devices that
+ * many other vendors like 4G Systems, Alcatel, ChinaBird,
+ * Mobidata, etc sell under their own brand names.
+ */
+#define LONGCHEER_VENDOR_ID 0x1c9e
+
/* 4G Systems products */
-#define FOUR_G_SYSTEMS_VENDOR_ID 0x1c9e
+/* This is the 4G XS Stick W14 a.k.a. Mobilcom Debitel Surf-Stick *
+ * It seems to contain a Qualcomm QSC6240/6290 chipset */
#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603
/* Haier products */
#define HAIER_VENDOR_ID 0x201e
#define HAIER_PRODUCT_CE100 0x2009
-static struct usb_device_id option_ids[] = {
+/* some devices interfaces need special handling due to a number of reasons */
+enum option_blacklist_reason {
+ OPTION_BLACKLIST_NONE = 0,
+ OPTION_BLACKLIST_SENDSETUP = 1,
+ OPTION_BLACKLIST_RESERVED_IF = 2
+};
+
+struct option_blacklist_info {
+ const u32 infolen; /* number of interface numbers on blacklist */
+ const u8 *ifaceinfo; /* pointer to the array holding the numbers */
+ enum option_blacklist_reason reason;
+};
+
+static const u8 four_g_w14_no_sendsetup[] = { 0, 1 };
+static const struct option_blacklist_info four_g_w14_blacklist = {
+ .infolen = ARRAY_SIZE(four_g_w14_no_sendsetup),
+ .ifaceinfo = four_g_w14_no_sendsetup,
+ .reason = OPTION_BLACKLIST_SENDSETUP
+};
+
+static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
@@ -644,7 +671,9 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) },
{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
{ USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
- { USB_DEVICE(FOUR_G_SYSTEMS_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14) },
+ { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
+ .driver_info = (kernel_ulong_t)&four_g_w14_blacklist
+ },
{ USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },
{ } /* Terminating entry */
};
@@ -709,6 +738,7 @@ struct option_intf_private {
spinlock_t susp_lock;
unsigned int suspended:1;
int in_flight;
+ struct option_blacklist_info *blacklist_info;
};
struct option_port_private {
@@ -778,9 +808,27 @@ static int option_probe(struct usb_serial *serial,
if (!data)
return -ENOMEM;
spin_lock_init(&data->susp_lock);
+ data->blacklist_info = (struct option_blacklist_info*) id->driver_info;
return 0;
}
+static enum option_blacklist_reason is_blacklisted(const u8 ifnum,
+ const struct option_blacklist_info *blacklist)
+{
+ const u8 *info;
+ int i;
+
+ if (blacklist) {
+ info = blacklist->ifaceinfo;
+
+ for (i = 0; i < blacklist->infolen; i++) {
+ if (info[i] == ifnum)
+ return blacklist->reason;
+ }
+ }
+ return OPTION_BLACKLIST_NONE;
+}
+
static void option_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -921,7 +969,6 @@ static void option_indat_callback(struct urb *urb)
} else {
tty = tty_port_tty_get(&port->port);
if (urb->actual_length) {
- tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
} else
@@ -929,9 +976,9 @@ static void option_indat_callback(struct urb *urb)
tty_kref_put(tty);
/* Resubmit urb so we continue receiving */
- if (port->port.count && status != -ESHUTDOWN) {
+ if (status != -ESHUTDOWN) {
err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err)
+ if (err && err != -EPERM)
printk(KERN_ERR "%s: resubmit read urb failed. "
"(%d)", __func__, err);
else
@@ -985,7 +1032,7 @@ static void option_instat_callback(struct urb *urb)
(struct usb_ctrlrequest *)urb->transfer_buffer;
if (!req_pkt) {
- dbg("%s: NULL req_pkt\n", __func__);
+ dbg("%s: NULL req_pkt", __func__);
return;
}
if ((req_pkt->bRequestType == 0xA1) &&
@@ -1211,11 +1258,19 @@ static void option_setup_urbs(struct usb_serial *serial)
static int option_send_setup(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
+ struct option_intf_private *intfdata =
+ (struct option_intf_private *) serial->private;
struct option_port_private *portdata;
int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
int val = 0;
dbg("%s", __func__);
+ if (is_blacklisted(ifNum, intfdata->blacklist_info) ==
+ OPTION_BLACKLIST_SENDSETUP) {
+ dbg("No send_setup on blacklisted interface #%d\n", ifNum);
+ return -EIO;
+ }
+
portdata = usb_get_serial_port_data(port);
if (portdata->dtr_state)
@@ -1401,7 +1456,7 @@ static int option_resume(struct usb_serial *serial)
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
if (!port->interrupt_in_urb) {
- dbg("%s: No interrupt URB for port %d\n", __func__, i);
+ dbg("%s: No interrupt URB for port %d", __func__, i);
continue;
}
err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index c644e26394b4..deeacdea05db 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -58,7 +58,7 @@
#define OTI6858_AUTHOR "Tomasz Michal Lukaszewski <FIXME@FIXME>"
#define OTI6858_VERSION "0.1"
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(OTI6858_VENDOR_ID, OTI6858_PRODUCT_ID) },
{ }
};
@@ -302,7 +302,7 @@ void send_data(struct work_struct *work)
struct usb_serial_port *port = priv->port;
int count = 0, result;
unsigned long flags;
- unsigned char allow;
+ u8 *allow;
dbg("%s(port = %d)", __func__, port->number);
@@ -321,13 +321,20 @@ void send_data(struct work_struct *work)
count = port->bulk_out_size;
if (count != 0) {
+ allow = kmalloc(1, GFP_KERNEL);
+ if (!allow) {
+ dev_err(&port->dev, "%s(): kmalloc failed\n",
+ __func__);
+ return;
+ }
result = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
OTI6858_REQ_T_CHECK_TXBUFF,
OTI6858_REQ_CHECK_TXBUFF,
- count, 0, &allow, 1, 100);
- if (result != 1 || allow != 0)
+ count, 0, allow, 1, 100);
+ if (result != 1 || *allow != 0)
count = 0;
+ kfree(allow);
}
if (count == 0) {
@@ -578,9 +585,6 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
- if (port->port.count != 1)
- return 0;
-
buf = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL);
if (buf == NULL) {
dev_err(&port->dev, "%s(): out of memory!\n", __func__);
@@ -927,10 +931,6 @@ static void oti6858_read_bulk_callback(struct urb *urb)
spin_unlock_irqrestore(&priv->lock, flags);
if (status != 0) {
- if (!port->port.count) {
- dbg("%s(): port is closed, exiting", __func__);
- return;
- }
/*
if (status == -EPROTO) {
* PL2303 mysteriously fails with -EPROTO reschedule
@@ -954,14 +954,12 @@ static void oti6858_read_bulk_callback(struct urb *urb)
}
tty_kref_put(tty);
- /* schedule the interrupt urb if we are still open */
- if (port->port.count != 0) {
- port->interrupt_in_urb->dev = port->serial->dev;
- result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
- if (result != 0) {
- dev_err(&port->dev, "%s(): usb_submit_urb() failed,"
- " error %d\n", __func__, result);
- }
+ /* schedule the interrupt urb */
+ port->interrupt_in_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+ if (result != 0 && result != -EPERM) {
+ dev_err(&port->dev, "%s(): usb_submit_urb() failed,"
+ " error %d\n", __func__, result);
}
}
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 9ec1a49e2362..73d5f346d3e0 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -50,7 +50,7 @@ struct pl2303_buf {
char *buf_put;
};
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
@@ -451,7 +451,6 @@ static void pl2303_send(struct usb_serial_port *port)
port->write_urb->transfer_buffer);
port->write_urb->transfer_buffer_length = count;
- port->write_urb->dev = port->serial->dev;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
dev_err(&port->dev, "%s - failed submitting write urb,"
@@ -769,7 +768,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
pl2303_set_termios(tty, port, &tmp_termios);
dbg("%s - submitting read urb", __func__);
- port->read_urb->dev = serial->dev;
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting read urb,"
@@ -779,7 +777,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
}
dbg("%s - submitting interrupt urb", __func__);
- port->interrupt_in_urb->dev = serial->dev;
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting interrupt urb,"
@@ -895,10 +892,23 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
+ struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
switch (cmd) {
+ case TIOCGSERIAL:
+ memset(&ser, 0, sizeof ser);
+ ser.type = PORT_16654;
+ ser.line = port->serial->minor;
+ ser.port = port->number;
+ ser.baud_base = 460800;
+
+ if (copy_to_user((void __user *)arg, &ser, sizeof ser))
+ return -EFAULT;
+
+ return 0;
+
case TIOCMIWAIT:
dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
return wait_modem_info(port, arg);
@@ -1042,7 +1052,6 @@ static void pl2303_push_data(struct tty_struct *tty,
tty_flag = TTY_FRAME;
dbg("%s - tty_flag = %d", __func__, tty_flag);
- tty_buffer_request_room(tty, urb->actual_length + 1);
/* overrun is special, not associated with a char */
if (line_status & UART_OVERRUN_ERROR)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
@@ -1072,16 +1081,11 @@ static void pl2303_read_bulk_callback(struct urb *urb)
if (status) {
dbg("%s - urb status = %d", __func__, status);
- if (!port->port.count) {
- dbg("%s - port is closed, exiting.", __func__);
- return;
- }
if (status == -EPROTO) {
/* PL2303 mysteriously fails with -EPROTO reschedule
* the read */
dbg("%s - caught -EPROTO, resubmitting the urb",
__func__);
- urb->dev = port->serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed"
@@ -1108,15 +1112,10 @@ static void pl2303_read_bulk_callback(struct urb *urb)
}
tty_kref_put(tty);
/* Schedule the next read _if_ we are still open */
- if (port->port.count) {
- urb->dev = port->serial->dev;
- result = usb_submit_urb(urb, GFP_ATOMIC);
- if (result)
- dev_err(&urb->dev->dev, "%s - failed resubmitting"
- " read urb, error %d\n", __func__, result);
- }
-
- return;
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result && result != -EPERM)
+ dev_err(&urb->dev->dev, "%s - failed resubmitting"
+ " read urb, error %d\n", __func__, result);
}
static void pl2303_write_bulk_callback(struct urb *urb)
@@ -1146,7 +1145,6 @@ static void pl2303_write_bulk_callback(struct urb *urb)
dbg("%s - nonzero write bulk status received: %d", __func__,
status);
port->write_urb->transfer_buffer_length = 1;
- port->write_urb->dev = port->serial->dev;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed resubmitting write"
diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c
new file mode 100644
index 000000000000..0b9362061713
--- /dev/null
+++ b/drivers/usb/serial/qcaux.c
@@ -0,0 +1,96 @@
+/*
+ * Qualcomm USB Auxiliary Serial Port driver
+ *
+ * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2010 Dan Williams <dcbw@redhat.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.
+ *
+ * Devices listed here usually provide a CDC ACM port on which normal modem
+ * AT commands and PPP can be used. But when that port is in-use by PPP it
+ * cannot be used simultaneously for status or signal strength. Instead, the
+ * ports here can be queried for that information using the Qualcomm DM
+ * protocol.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+/* NOTE: for now, only use this driver for devices that provide a CDC-ACM port
+ * for normal AT commands, but also provide secondary USB interfaces for the
+ * QCDM-capable ports. Devices that do not provide a CDC-ACM port should
+ * probably be driven by option.ko.
+ */
+
+/* UTStarcom/Pantech/Curitel devices */
+#define UTSTARCOM_VENDOR_ID 0x106c
+#define UTSTARCOM_PRODUCT_PC5740 0x3701
+#define UTSTARCOM_PRODUCT_PC5750 0x3702 /* aka Pantech PX-500 */
+#define UTSTARCOM_PRODUCT_UM150 0x3711
+#define UTSTARCOM_PRODUCT_UM175_V1 0x3712
+#define UTSTARCOM_PRODUCT_UM175_V2 0x3714
+#define UTSTARCOM_PRODUCT_UM175_ALLTEL 0x3715
+
+/* CMOTECH devices */
+#define CMOTECH_VENDOR_ID 0x16d8
+#define CMOTECH_PRODUCT_CDU550 0x5553
+#define CMOTECH_PRODUCT_CDX650 0x6512
+
+static struct usb_device_id id_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5740, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5750, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM150, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM175_V1, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM175_V2, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM175_ALLTEL, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU550, 0xff, 0xff, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDX650, 0xff, 0xff, 0x00) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver qcaux_driver = {
+ .name = "qcaux",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
+static struct usb_serial_driver qcaux_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "qcaux",
+ },
+ .id_table = id_table,
+ .num_ports = 1,
+};
+
+static int __init qcaux_init(void)
+{
+ int retval;
+
+ retval = usb_serial_register(&qcaux_device);
+ if (retval)
+ return retval;
+ retval = usb_register(&qcaux_driver);
+ if (retval)
+ usb_serial_deregister(&qcaux_device);
+ return retval;
+}
+
+static void __exit qcaux_exit(void)
+{
+ usb_deregister(&qcaux_driver);
+ usb_serial_deregister(&qcaux_device);
+}
+
+module_init(qcaux_init);
+module_exit(qcaux_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 7528b8d57f1c..310ff6ec6567 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -21,7 +21,7 @@
static int debug;
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
{USB_DEVICE(0x05c6, 0x9211)}, /* Acer Gobi QDL device */
{USB_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
{USB_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */
diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c
index 951ea0c6ba77..cb8195cabfde 100644
--- a/drivers/usb/serial/siemens_mpi.c
+++ b/drivers/usb/serial/siemens_mpi.c
@@ -22,7 +22,7 @@
#define DRIVER_DESC "Driver for Siemens USB/MPI adapter"
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
/* Vendor and product id for 6ES7-972-0CB20-0XA0 */
{ USB_DEVICE(0x908, 0x0004) },
{ },
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index ac1b6449fb6a..34e6f894cba9 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -226,7 +226,7 @@ static const struct sierra_iface_info direct_ip_interface_blacklist = {
.ifaceinfo = direct_ip_non_serial_ifaces,
};
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */
{ USB_DEVICE(0x03F0, 0x1B1D) }, /* HP ev2200 a.k.a MC5720 */
{ USB_DEVICE(0x03F0, 0x1E1D) }, /* HP hs2300 a.k.a MC8775 */
@@ -298,21 +298,12 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless Direct IP modems */
.driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
},
+ { USB_DEVICE(0x413C, 0x08133) }, /* Dell Computer Corp. Wireless 5720 VZW Mobile Broadband (EVDO Rev-A) Minicard GPS Port */
{ }
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver sierra_driver = {
- .name = "sierra",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .id_table = id_table,
- .no_dynamic_id = 1,
- .supports_autosuspend = 1,
-};
struct sierra_port_private {
spinlock_t lock; /* lock the structure */
@@ -476,7 +467,7 @@ static void sierra_outdat_callback(struct urb *urb)
static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count)
{
- struct sierra_port_private *portdata = usb_get_serial_port_data(port);
+ struct sierra_port_private *portdata;
struct sierra_intf_private *intfdata;
struct usb_serial *serial = port->serial;
unsigned long flags;
@@ -603,14 +594,15 @@ static void sierra_indat_callback(struct urb *urb)
} else {
if (urb->actual_length) {
tty = tty_port_tty_get(&port->port);
-
- tty_buffer_request_room(tty, urb->actual_length);
- tty_insert_flip_string(tty, data, urb->actual_length);
- tty_flip_buffer_push(tty);
-
- tty_kref_put(tty);
- usb_serial_debug_data(debug, &port->dev, __func__,
- urb->actual_length, data);
+ if (tty) {
+ tty_insert_flip_string(tty, data,
+ urb->actual_length);
+ tty_flip_buffer_push(tty);
+
+ tty_kref_put(tty);
+ usb_serial_debug_data(debug, &port->dev,
+ __func__, urb->actual_length, data);
+ }
} else {
dev_dbg(&port->dev, "%s: empty read urb"
" received\n", __func__);
@@ -618,10 +610,10 @@ static void sierra_indat_callback(struct urb *urb)
}
/* Resubmit urb so we continue receiving */
- if (port->port.count && status != -ESHUTDOWN && status != -EPERM) {
+ if (status != -ESHUTDOWN && status != -EPERM) {
usb_mark_last_busy(port->serial->dev);
err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err)
+ if (err && err != -EPERM)
dev_err(&port->dev, "resubmit read urb failed."
"(%d)\n", err);
}
@@ -680,11 +672,11 @@ static void sierra_instat_callback(struct urb *urb)
dev_dbg(&port->dev, "%s: error %d\n", __func__, status);
/* Resubmit urb so we continue receiving IRQ data */
- if (port->port.count && status != -ESHUTDOWN && status != -ENOENT) {
+ if (status != -ESHUTDOWN && status != -ENOENT) {
usb_mark_last_busy(serial->dev);
urb->dev = serial->dev;
err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err)
+ if (err && err != -EPERM)
dev_err(&port->dev, "%s: resubmit intr urb "
"failed. (%d)\n", __func__, err);
}
@@ -1060,11 +1052,31 @@ static int sierra_resume(struct usb_serial *serial)
return ec ? -EIO : 0;
}
+
+static int sierra_reset_resume(struct usb_interface *intf)
+{
+ struct usb_serial *serial = usb_get_intfdata(intf);
+ dev_err(&serial->dev->dev, "%s\n", __func__);
+ return usb_serial_resume(intf);
+}
#else
#define sierra_suspend NULL
#define sierra_resume NULL
+#define sierra_reset_resume NULL
#endif
+static struct usb_driver sierra_driver = {
+ .name = "sierra",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .suspend = usb_serial_suspend,
+ .resume = usb_serial_resume,
+ .reset_resume = sierra_reset_resume,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+ .supports_autosuspend = 1,
+};
+
static struct usb_serial_driver sierra_device = {
.driver = {
.owner = THIS_MODULE,
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 1e58220403d1..5d39191e7244 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -45,7 +45,7 @@ static int debug;
#define SPCP8x5_835_VID 0x04fc
#define SPCP8x5_835_PID 0x0231
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(SPCP8x5_PHILIPS_VID , SPCP8x5_PHILIPS_PID)},
{ USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)},
{ USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)},
@@ -609,7 +609,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
if (i < 0)
dev_err(&port->dev, "Set UART format %#x failed (error = %d)\n",
uartdata, i);
- dbg("0x21:0x40:0:0 %d\n", i);
+ dbg("0x21:0x40:0:0 %d", i);
if (cflag & CRTSCTS) {
/* enable hardware flow control */
@@ -677,7 +677,6 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
unsigned long flags;
- int i;
int result = urb->status;
u8 status;
char tty_flag;
@@ -687,8 +686,6 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
/* check the urb status */
if (result) {
- if (!port->port.count)
- return;
if (result == -EPROTO) {
/* spcp8x5 mysteriously fails with -EPROTO */
/* reschedule the read */
@@ -726,26 +723,20 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
- tty_buffer_request_room(tty, urb->actual_length + 1);
/* overrun is special, not associated with a char */
if (status & UART_OVERRUN_ERROR)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
- for (i = 0; i < urb->actual_length; ++i)
- tty_insert_flip_char(tty, data[i], tty_flag);
+ tty_insert_flip_string_fixed_flag(tty, data,
+ urb->actual_length, tty_flag);
tty_flip_buffer_push(tty);
}
tty_kref_put(tty);
- /* Schedule the next read _if_ we are still open */
- if (port->port.count) {
- urb->dev = port->serial->dev;
- result = usb_submit_urb(urb , GFP_ATOMIC);
- if (result)
- dev_dbg(&port->dev, "failed submitting read urb %d\n",
- result);
- }
-
- return;
+ /* Schedule the next read */
+ urb->dev = port->serial->dev;
+ result = usb_submit_urb(urb , GFP_ATOMIC);
+ if (result)
+ dev_dbg(&port->dev, "failed submitting read urb %d\n", result);
}
/* get data from ring buffer and then write to usb bus */
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index b282c0f2d8e5..ee190cc1757c 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -21,7 +21,7 @@
static int debug;
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x05e0, 0x0600) },
{ },
};
@@ -51,7 +51,6 @@ static void symbol_int_callback(struct urb *urb)
int status = urb->status;
struct tty_struct *tty;
int result;
- int available_room = 0;
int data_length;
dbg("%s - port %d", __func__, port->number);
@@ -89,18 +88,13 @@ static void symbol_int_callback(struct urb *urb)
*/
tty = tty_port_tty_get(&port->port);
if (tty) {
- available_room = tty_buffer_request_room(tty,
- data_length);
- if (available_room) {
- tty_insert_flip_string(tty, &data[1],
- available_room);
- tty_flip_buffer_push(tty);
- }
+ tty_insert_flip_string(tty, &data[1], data_length);
+ tty_flip_buffer_push(tty);
tty_kref_put(tty);
}
} else {
dev_dbg(&priv->udev->dev,
- "Improper ammount of data received from the device, "
+ "Improper amount of data received from the device, "
"%d bytes", urb->actual_length);
}
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 1e9dc8821698..0afe5c71c17e 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -1271,14 +1271,13 @@ static void ti_recv(struct device *dev, struct tty_struct *tty,
int cnt;
do {
- cnt = tty_buffer_request_room(tty, length);
+ cnt = tty_insert_flip_string(tty, data, length);
if (cnt < length) {
dev_err(dev, "%s - dropping data, %d bytes lost\n",
__func__, length - cnt);
if (cnt == 0)
break;
}
- tty_insert_flip_string(tty, data, cnt);
tty_flip_buffer_push(tty);
data += cnt;
length -= cnt;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 33c85f7084f8..3873660d8217 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -358,10 +358,6 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf,
dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
- /* count is managed under the mutex lock for the tty so cannot
- drop to zero until after the last close completes */
- WARN_ON(!port->port.count);
-
/* pass on to the driver specific version of this function */
retval = port->serial->type->write(tty, port, buf, count);
@@ -373,7 +369,6 @@ static int serial_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
dbg("%s - port %d", __func__, port->number);
- WARN_ON(!port->port.count);
/* pass on to the driver specific version of this function */
return port->serial->type->write_room(tty);
}
@@ -381,7 +376,7 @@ static int serial_write_room(struct tty_struct *tty)
static int serial_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dbg("%s = port %d", __func__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* if the device was unplugged then any remaining characters
fell out of the connector ;) */
@@ -396,7 +391,6 @@ static void serial_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
dbg("%s - port %d", __func__, port->number);
- WARN_ON(!port->port.count);
/* pass on to the driver specific version of this function */
if (port->serial->type->throttle)
port->serial->type->throttle(tty);
@@ -407,7 +401,6 @@ static void serial_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
dbg("%s - port %d", __func__, port->number);
- WARN_ON(!port->port.count);
/* pass on to the driver specific version of this function */
if (port->serial->type->unthrottle)
port->serial->type->unthrottle(tty);
@@ -421,8 +414,6 @@ static int serial_ioctl(struct tty_struct *tty, struct file *file,
dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
- WARN_ON(!port->port.count);
-
/* pass on to the driver specific version of this function
if it is available */
if (port->serial->type->ioctl) {
@@ -437,7 +428,6 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
struct usb_serial_port *port = tty->driver_data;
dbg("%s - port %d", __func__, port->number);
- WARN_ON(!port->port.count);
/* pass on to the driver specific version of this function
if it is available */
if (port->serial->type->set_termios)
@@ -452,7 +442,6 @@ static int serial_break(struct tty_struct *tty, int break_state)
dbg("%s - port %d", __func__, port->number);
- WARN_ON(!port->port.count);
/* pass on to the driver specific version of this function
if it is available */
if (port->serial->type->break_ctl)
@@ -513,7 +502,6 @@ static int serial_tiocmget(struct tty_struct *tty, struct file *file)
dbg("%s - port %d", __func__, port->number);
- WARN_ON(!port->port.count);
if (port->serial->type->tiocmget)
return port->serial->type->tiocmget(tty, file);
return -EINVAL;
@@ -526,7 +514,6 @@ static int serial_tiocmset(struct tty_struct *tty, struct file *file,
dbg("%s - port %d", __func__, port->number);
- WARN_ON(!port->port.count);
if (port->serial->type->tiocmset)
return port->serial->type->tiocmset(tty, file, set, clear);
return -EINVAL;
diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index 7b5bfc4edd3d..252cc2d993b2 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -29,7 +29,7 @@ static char USB_DEBUG_BRK[USB_DEBUG_BRK_SIZE] = {
0xff,
};
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x0525, 0x127a) },
{ },
};
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index ad1f9232292d..094942707c7d 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -368,7 +368,7 @@ static int visor_write(struct tty_struct *tty, struct usb_serial_port *port,
spin_lock_irqsave(&priv->lock, flags);
if (priv->outstanding_urbs > URB_UPPER_LIMIT) {
spin_unlock_irqrestore(&priv->lock, flags);
- dbg("%s - write limit hit\n", __func__);
+ dbg("%s - write limit hit", __func__);
return 0;
}
priv->outstanding_urbs++;
@@ -446,7 +446,7 @@ static int visor_write_room(struct tty_struct *tty)
spin_lock_irqsave(&priv->lock, flags);
if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) {
spin_unlock_irqrestore(&priv->lock, flags);
- dbg("%s - write limit hit\n", __func__);
+ dbg("%s - write limit hit", __func__);
return 0;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -503,13 +503,9 @@ static void visor_read_bulk_callback(struct urb *urb)
if (urb->actual_length) {
tty = tty_port_tty_get(&port->port);
if (tty) {
- available_room = tty_buffer_request_room(tty,
- urb->actual_length);
- if (available_room) {
- tty_insert_flip_string(tty, data,
- available_room);
- tty_flip_buffer_push(tty);
- }
+ tty_insert_flip_string(tty, data,
+ urb->actual_length);
+ tty_flip_buffer_push(tty);
tty_kref_put(tty);
}
spin_lock(&priv->lock);
@@ -807,10 +803,14 @@ static int clie_3_5_startup(struct usb_serial *serial)
{
struct device *dev = &serial->dev->dev;
int result;
- u8 data;
+ u8 *data;
dbg("%s", __func__);
+ data = kmalloc(1, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
/*
* Note that PEG-300 series devices expect the following two calls.
*/
@@ -818,36 +818,42 @@ static int clie_3_5_startup(struct usb_serial *serial)
/* get the config number */
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
USB_REQ_GET_CONFIGURATION, USB_DIR_IN,
- 0, 0, &data, 1, 3000);
+ 0, 0, data, 1, 3000);
if (result < 0) {
dev_err(dev, "%s: get config number failed: %d\n",
__func__, result);
- return result;
+ goto out;
}
if (result != 1) {
dev_err(dev, "%s: get config number bad return length: %d\n",
__func__, result);
- return -EIO;
+ result = -EIO;
+ goto out;
}
/* get the interface number */
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
USB_REQ_GET_INTERFACE,
USB_DIR_IN | USB_RECIP_INTERFACE,
- 0, 0, &data, 1, 3000);
+ 0, 0, data, 1, 3000);
if (result < 0) {
dev_err(dev, "%s: get interface number failed: %d\n",
__func__, result);
- return result;
+ goto out;
}
if (result != 1) {
dev_err(dev,
"%s: get interface number bad return length: %d\n",
__func__, result);
- return -EIO;
+ result = -EIO;
+ goto out;
}
- return generic_startup(serial);
+ result = generic_startup(serial);
+out:
+ kfree(data);
+
+ return result;
}
static int treo_attach(struct usb_serial *serial)
diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c
new file mode 100644
index 000000000000..f719d00972fc
--- /dev/null
+++ b/drivers/usb/serial/vivopay-serial.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2009 Outpost Embedded, LLC
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_DESC "ViVOpay USB Serial Driver"
+
+#define VIVOPAY_VENDOR_ID 0x1d5f
+
+
+static struct usb_device_id id_table [] = {
+ /* ViVOpay 8800 */
+ { USB_DEVICE(VIVOPAY_VENDOR_ID, 0x1004) },
+ { },
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver vivopay_serial_driver = {
+ .name = "vivopay-serial",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
+static struct usb_serial_driver vivopay_serial_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "vivopay-serial",
+ },
+ .id_table = id_table,
+ .usb_driver = &vivopay_serial_driver,
+ .num_ports = 1,
+};
+
+static int __init vivopay_serial_init(void)
+{
+ int retval;
+ retval = usb_serial_register(&vivopay_serial_device);
+ if (retval)
+ goto failed_usb_serial_register;
+ retval = usb_register(&vivopay_serial_driver);
+ if (retval)
+ goto failed_usb_register;
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
+ return 0;
+failed_usb_register:
+ usb_serial_deregister(&vivopay_serial_device);
+failed_usb_serial_register:
+ return retval;
+}
+
+static void __exit vivopay_serial_exit(void)
+{
+ usb_deregister(&vivopay_serial_driver);
+ usb_serial_deregister(&vivopay_serial_device);
+}
+
+module_init(vivopay_serial_init);
+module_exit(vivopay_serial_exit);
+
+MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 1093d2eb046a..12ed8209ca72 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -111,17 +111,17 @@ static int debug;
separate ID tables, and then a third table that combines them
just for the purpose of exporting the autoloading information.
*/
-static struct usb_device_id id_table_std [] = {
+static const struct usb_device_id id_table_std[] = {
{ USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) },
{ } /* Terminating entry */
};
-static struct usb_device_id id_table_prerenumeration [] = {
+static const struct usb_device_id id_table_prerenumeration[] = {
{ USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) },
{ } /* Terminating entry */
};
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) },
{ USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) },
{ } /* Terminating entry */
@@ -1492,21 +1492,9 @@ static void rx_data_softint(struct work_struct *work)
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
urb = wrap->urb;
- if (tty && urb->actual_length) {
- int len = tty_buffer_request_room(tty,
- urb->actual_length);
- /* This stuff can go away now I suspect */
- if (unlikely(len < urb->actual_length)) {
- spin_lock_irqsave(&info->lock, flags);
- list_add(tmp, &info->rx_urb_q);
- spin_unlock_irqrestore(&info->lock, flags);
- tty_flip_buffer_push(tty);
- schedule_work(&info->rx_work);
- goto out;
- }
- tty_insert_flip_string(tty, urb->transfer_buffer, len);
- sent += len;
- }
+ if (tty && urb->actual_length)
+ sent += tty_insert_flip_string(tty,
+ urb->transfer_buffer, urb->actual_length);
urb->dev = port->serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index 80e65f29921c..198bb3ed95b2 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -202,7 +202,7 @@ static int onetouch_connect_input(struct us_data *ss)
goto fail1;
onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN,
- GFP_ATOMIC, &onetouch->data_dma);
+ GFP_KERNEL, &onetouch->data_dma);
if (!onetouch->data)
goto fail1;
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index e5e6df39e737..4cc035562cc2 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -133,15 +133,15 @@ static int slave_configure(struct scsi_device *sdev)
if (us->fflags & US_FL_MAX_SECTORS_MIN)
max_sectors = PAGE_CACHE_SIZE >> 9;
- if (queue_max_sectors(sdev->request_queue) > max_sectors)
- blk_queue_max_sectors(sdev->request_queue,
+ if (queue_max_hw_sectors(sdev->request_queue) > max_sectors)
+ blk_queue_max_hw_sectors(sdev->request_queue,
max_sectors);
} else if (sdev->type == TYPE_TAPE) {
/* Tapes need much higher max_sector limits, so just
* raise it to the maximum possible (4 GB / 512) and
* let the queue segment size sort out the real limit.
*/
- blk_queue_max_sectors(sdev->request_queue, 0x7FFFFF);
+ blk_queue_max_hw_sectors(sdev->request_queue, 0x7FFFFF);
}
/* Some USB host controllers can't do DMA; they have to use PIO.
@@ -484,7 +484,7 @@ static ssize_t show_max_sectors(struct device *dev, struct device_attribute *att
{
struct scsi_device *sdev = to_scsi_device(dev);
- return sprintf(buf, "%u\n", queue_max_sectors(sdev->request_queue));
+ return sprintf(buf, "%u\n", queue_max_hw_sectors(sdev->request_queue));
}
/* Input routine for the sysfs max_sectors file */
@@ -494,9 +494,9 @@ static ssize_t store_max_sectors(struct device *dev, struct device_attribute *at
struct scsi_device *sdev = to_scsi_device(dev);
unsigned short ms;
- if (sscanf(buf, "%hu", &ms) > 0 && ms <= SCSI_DEFAULT_MAX_SECTORS) {
- blk_queue_max_sectors(sdev->request_queue, ms);
- return strlen(buf);
+ if (sscanf(buf, "%hu", &ms) > 0) {
+ blk_queue_max_hw_sectors(sdev->request_queue, ms);
+ return count;
}
return -EINVAL;
}
@@ -539,7 +539,7 @@ struct scsi_host_template usb_stor_host_template = {
.slave_configure = slave_configure,
/* lots of sg segments can be handled */
- .sg_tablesize = SG_ALL,
+ .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS,
/* limit the total size of a transfer to 120 KB */
.max_sectors = 240,
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index b62a28814ebe..bd3f415893d8 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -1628,10 +1628,10 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
return USB_STOR_TRANSPORT_ERROR;
}
- if ( (result = usbat_multiple_write(us,
- registers, data, 7)) != USB_STOR_TRANSPORT_GOOD) {
+ result = usbat_multiple_write(us, registers, data, 7);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
return result;
- }
/*
* Write the 12-byte command header.
@@ -1643,12 +1643,11 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
* AT SPEED 4 IS UNRELIABLE!!!
*/
- if ((result = usbat_write_block(us,
- USBAT_ATA, srb->cmnd, 12,
- (srb->cmnd[0]==GPCMD_BLANK ? 75 : 10), 0) !=
- USB_STOR_TRANSPORT_GOOD)) {
+ result = usbat_write_block(us, USBAT_ATA, srb->cmnd, 12,
+ srb->cmnd[0] == GPCMD_BLANK ? 75 : 10, 0);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
return result;
- }
/* If there is response data to be read in then do it here. */
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index cc313d16d727..468038126e5e 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -47,6 +47,8 @@
#include <linux/errno.h>
#include <linux/slab.h>
+#include <linux/usb/quirks.h>
+
#include <scsi/scsi.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
@@ -1297,6 +1299,10 @@ int usb_stor_port_reset(struct us_data *us)
{
int result;
+ /*for these devices we must use the class specific method */
+ if (us->pusb_dev->quirks & USB_QUIRK_RESET_MORPHS)
+ return -EPERM;
+
result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
if (result < 0)
US_DEBUGP("unable to lock device for reset: %d\n", result);
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 64a0a2c27e12..98b549b1cab2 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -941,7 +941,7 @@ UNUSUAL_DEV( 0x07ab, 0xfccd, 0x0000, 0x9999,
UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133,
"Microtech",
"USB-SCSI-DB25",
- US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100,
@@ -1147,8 +1147,8 @@ UNUSUAL_DEV( 0x0af0, 0x7401, 0x0000, 0x0000,
0 ),
/* Reported by Jan Dumon <j.dumon@option.com>
- * This device (wrongly) has a vendor-specific device descriptor.
- * The entry is needed so usb-storage can bind to it's mass-storage
+ * These devices (wrongly) have a vendor-specific device descriptor.
+ * These entries are needed so usb-storage can bind to their mass-storage
* interface as an interface driver */
UNUSUAL_DEV( 0x0af0, 0x7501, 0x0000, 0x0000,
"Option",
@@ -1156,6 +1156,90 @@ UNUSUAL_DEV( 0x0af0, 0x7501, 0x0000, 0x0000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
0 ),
+UNUSUAL_DEV( 0x0af0, 0x7701, 0x0000, 0x0000,
+ "Option",
+ "GI 0451 SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7706, 0x0000, 0x0000,
+ "Option",
+ "GI 0451 SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7901, 0x0000, 0x0000,
+ "Option",
+ "GI 0452 SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7A01, 0x0000, 0x0000,
+ "Option",
+ "GI 0461 SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7A05, 0x0000, 0x0000,
+ "Option",
+ "GI 0461 SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x8300, 0x0000, 0x0000,
+ "Option",
+ "GI 033x SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x8302, 0x0000, 0x0000,
+ "Option",
+ "GI 033x SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x8304, 0x0000, 0x0000,
+ "Option",
+ "GI 033x SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xc100, 0x0000, 0x0000,
+ "Option",
+ "GI 070x SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd057, 0x0000, 0x0000,
+ "Option",
+ "GI 1505 SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd058, 0x0000, 0x0000,
+ "Option",
+ "GI 1509 SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd157, 0x0000, 0x0000,
+ "Option",
+ "GI 1515 SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd257, 0x0000, 0x0000,
+ "Option",
+ "GI 1215 SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd357, 0x0000, 0x0000,
+ "Option",
+ "GI 1505 SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
/* Reported by Ben Efros <ben@pc-doctor.com> */
UNUSUAL_DEV( 0x0bc2, 0x3010, 0x0000, 0x0000,
"Seagate",
@@ -1807,13 +1891,6 @@ UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_GO_SLOW ),
-/* Reported by Rohan Hart <rohan.hart17@gmail.com> */
-UNUSUAL_DEV( 0x2770, 0x915d, 0x0010, 0x0010,
- "INTOVA",
- "Pixtreme",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
-
/* Reported by Frederic Marchal <frederic.marchal@wowcompany.com>
* Mio Moov 330
*/
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 5a53d4f0dd11..bbeeb92a2131 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -78,7 +78,7 @@ MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
MODULE_LICENSE("GPL");
-static unsigned int delay_use = 5;
+static unsigned int delay_use = 1;
module_param(delay_use, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
@@ -434,7 +434,8 @@ static void adjust_quirks(struct us_data *us)
u16 vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor);
u16 pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct);
unsigned f = 0;
- unsigned int mask = (US_FL_SANE_SENSE | US_FL_FIX_CAPACITY |
+ unsigned int mask = (US_FL_SANE_SENSE | US_FL_BAD_SENSE |
+ US_FL_FIX_CAPACITY |
US_FL_CAPACITY_HEURISTICS | US_FL_IGNORE_DEVICE |
US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 |
US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE |
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index b1e579c5c97c..61522787f39c 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -28,7 +28,7 @@
#define USB_SKEL_PRODUCT_ID 0xfff0
/* table of devices that work with this driver */
-static struct usb_device_id skel_table[] = {
+static const struct usb_device_id skel_table[] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/wusbcore/cbaf.c b/drivers/usb/wusbcore/cbaf.c
index 25eae405f622..51a8e0d5789d 100644
--- a/drivers/usb/wusbcore/cbaf.c
+++ b/drivers/usb/wusbcore/cbaf.c
@@ -641,7 +641,7 @@ static void cbaf_disconnect(struct usb_interface *iface)
kzfree(cbaf);
}
-static struct usb_device_id cbaf_id_table[] = {
+static const struct usb_device_id cbaf_id_table[] = {
{ USB_INTERFACE_INFO(0xef, 0x03, 0x01), },
{ },
};
diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c
index dced419f7aba..1c918286159c 100644
--- a/drivers/usb/wusbcore/devconnect.c
+++ b/drivers/usb/wusbcore/devconnect.c
@@ -868,7 +868,7 @@ static struct usb_wireless_cap_descriptor wusb_cap_descr_default = {
* reference that we'll drop.
*
* First we need to determine if the device is a WUSB device (else we
- * ignore it). For that we use the speed setting (USB_SPEED_VARIABLE)
+ * ignore it). For that we use the speed setting (USB_SPEED_WIRELESS)
* [FIXME: maybe we'd need something more definitive]. If so, we track
* it's usb_busd and from there, the WUSB HC.
*
diff --git a/drivers/usb/wusbcore/mmc.c b/drivers/usb/wusbcore/mmc.c
index 3b52161e6e9c..2d827397e30b 100644
--- a/drivers/usb/wusbcore/mmc.c
+++ b/drivers/usb/wusbcore/mmc.c
@@ -263,7 +263,7 @@ int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
{
int result = 0;
- if (memcmp(chid, &wusb_ckhdid_zero, sizeof(chid)) == 0)
+ if (memcmp(chid, &wusb_ckhdid_zero, sizeof(*chid)) == 0)
chid = NULL;
mutex_lock(&wusbhc->mutex);
diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h
index fd2fd4e277e1..759cda55f7c3 100644
--- a/drivers/usb/wusbcore/wusbhc.h
+++ b/drivers/usb/wusbcore/wusbhc.h
@@ -198,7 +198,7 @@ struct wusb_port {
* ports) this HC will take. Read-only.
*
* @port Array of port status for each fake root port. Guaranteed to
- * always be the same lenght during device existence
+ * always be the same length during device existence
* [this allows for some unlocked but referenced reading].
*
* @mmcies_max Max number of Information Elements this HC can send
diff --git a/drivers/uwb/driver.c b/drivers/uwb/driver.c
index da77e41de990..08bd6dbfd4a6 100644
--- a/drivers/uwb/driver.c
+++ b/drivers/uwb/driver.c
@@ -74,13 +74,16 @@
unsigned long beacon_timeout_ms = 500;
static
-ssize_t beacon_timeout_ms_show(struct class *class, char *buf)
+ssize_t beacon_timeout_ms_show(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%lu\n", beacon_timeout_ms);
}
static
ssize_t beacon_timeout_ms_store(struct class *class,
+ struct class_attribute *attr,
const char *buf, size_t size)
{
unsigned long bt;
diff --git a/drivers/uwb/i1480/i1480-est.c b/drivers/uwb/i1480/i1480-est.c
index 7bf8c6febae7..f2eb4d8b76c9 100644
--- a/drivers/uwb/i1480/i1480-est.c
+++ b/drivers/uwb/i1480/i1480-est.c
@@ -54,7 +54,7 @@ static struct uwb_est_entry i1480_est_fd01[] = {
.size = sizeof(struct i1480_rceb) + 2 },
};
-static int i1480_est_init(void)
+static int __init i1480_est_init(void)
{
int result = uwb_est_register(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b,
i1480_est_fd00,
@@ -73,7 +73,7 @@ static int i1480_est_init(void)
}
module_init(i1480_est_init);
-static void i1480_est_exit(void)
+static void __exit i1480_est_exit(void)
{
uwb_est_unregister(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b,
i1480_est_fd00, ARRAY_SIZE(i1480_est_fd00));
diff --git a/drivers/uwb/umc-bus.c b/drivers/uwb/umc-bus.c
index cdd6c8efc9f8..5fad4e791b3e 100644
--- a/drivers/uwb/umc-bus.c
+++ b/drivers/uwb/umc-bus.c
@@ -62,12 +62,12 @@ int umc_controller_reset(struct umc_dev *umc)
struct device *parent = umc->dev.parent;
int ret = 0;
- if(down_trylock(&parent->sem))
+ if (device_trylock(parent))
return -EAGAIN;
ret = device_for_each_child(parent, parent, umc_bus_pre_reset_helper);
if (ret >= 0)
ret = device_for_each_child(parent, parent, umc_bus_post_reset_helper);
- up(&parent->sem);
+ device_unlock(parent);
return ret;
}
diff --git a/drivers/uwb/uwb-internal.h b/drivers/uwb/uwb-internal.h
index d5bcfc1c227a..157485c862c0 100644
--- a/drivers/uwb/uwb-internal.h
+++ b/drivers/uwb/uwb-internal.h
@@ -366,12 +366,12 @@ struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal);
static inline void uwb_dev_lock(struct uwb_dev *uwb_dev)
{
- down(&uwb_dev->dev.sem);
+ device_lock(&uwb_dev->dev);
}
static inline void uwb_dev_unlock(struct uwb_dev *uwb_dev)
{
- up(&uwb_dev->dev.sem);
+ device_unlock(&uwb_dev->dev);
}
#endif /* #ifndef __UWB_INTERNAL_H__ */
diff --git a/drivers/uwb/uwbd.c b/drivers/uwb/uwbd.c
index 5a777d8624da..6210fe1fd1bb 100644
--- a/drivers/uwb/uwbd.c
+++ b/drivers/uwb/uwbd.c
@@ -43,7 +43,7 @@
*
* EVENTS
*
- * Events have a type, a subtype, a lenght, some other stuff and the
+ * Events have a type, a subtype, a length, some other stuff and the
* data blob, which depends on the event. The header is 'struct
* uwb_event'; for payloads, see 'struct uwbd_evt_*'.
*
diff --git a/drivers/uwb/wlp/sysfs.c b/drivers/uwb/wlp/sysfs.c
index 0370399ff4bb..6627c94cc854 100644
--- a/drivers/uwb/wlp/sysfs.c
+++ b/drivers/uwb/wlp/sysfs.c
@@ -615,8 +615,7 @@ ssize_t wlp_wss_attr_store(struct kobject *kobj, struct attribute *attr,
return ret;
}
-static
-struct sysfs_ops wss_sysfs_ops = {
+static const struct sysfs_ops wss_sysfs_ops = {
.show = wlp_wss_attr_show,
.store = wlp_wss_attr_store,
};
diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig
new file mode 100644
index 000000000000..e4e2fd1b5107
--- /dev/null
+++ b/drivers/vhost/Kconfig
@@ -0,0 +1,11 @@
+config VHOST_NET
+ tristate "Host kernel accelerator for virtio net (EXPERIMENTAL)"
+ depends on NET && EVENTFD && (TUN || !TUN) && (MACVTAP || !MACVTAP) && EXPERIMENTAL
+ ---help---
+ This kernel module can be loaded in host kernel to accelerate
+ guest networking with virtio_net. Not to be confused with virtio_net
+ module itself which needs to be loaded in guest kernel.
+
+ To compile this driver as a module, choose M here: the module will
+ be called vhost_net.
+
diff --git a/drivers/vhost/Makefile b/drivers/vhost/Makefile
new file mode 100644
index 000000000000..72dd02050bb9
--- /dev/null
+++ b/drivers/vhost/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VHOST_NET) += vhost_net.o
+vhost_net-y := vhost.o net.o
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
new file mode 100644
index 000000000000..ad37da2b6cb5
--- /dev/null
+++ b/drivers/vhost/net.c
@@ -0,0 +1,669 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * virtio-net server in host kernel.
+ */
+
+#include <linux/compat.h>
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mmu_context.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/file.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+#include <linux/if_tun.h>
+#include <linux/if_macvlan.h>
+
+#include <net/sock.h>
+
+#include "vhost.h"
+
+/* Max number of bytes transferred before requeueing the job.
+ * Using this limit prevents one virtqueue from starving others. */
+#define VHOST_NET_WEIGHT 0x80000
+
+enum {
+ VHOST_NET_VQ_RX = 0,
+ VHOST_NET_VQ_TX = 1,
+ VHOST_NET_VQ_MAX = 2,
+};
+
+enum vhost_net_poll_state {
+ VHOST_NET_POLL_DISABLED = 0,
+ VHOST_NET_POLL_STARTED = 1,
+ VHOST_NET_POLL_STOPPED = 2,
+};
+
+struct vhost_net {
+ struct vhost_dev dev;
+ struct vhost_virtqueue vqs[VHOST_NET_VQ_MAX];
+ struct vhost_poll poll[VHOST_NET_VQ_MAX];
+ /* Tells us whether we are polling a socket for TX.
+ * We only do this when socket buffer fills up.
+ * Protected by tx vq lock. */
+ enum vhost_net_poll_state tx_poll_state;
+};
+
+/* Pop first len bytes from iovec. Return number of segments used. */
+static int move_iovec_hdr(struct iovec *from, struct iovec *to,
+ size_t len, int iov_count)
+{
+ int seg = 0;
+ size_t size;
+ while (len && seg < iov_count) {
+ size = min(from->iov_len, len);
+ to->iov_base = from->iov_base;
+ to->iov_len = size;
+ from->iov_len -= size;
+ from->iov_base += size;
+ len -= size;
+ ++from;
+ ++to;
+ ++seg;
+ }
+ return seg;
+}
+
+/* Caller must have TX VQ lock */
+static void tx_poll_stop(struct vhost_net *net)
+{
+ if (likely(net->tx_poll_state != VHOST_NET_POLL_STARTED))
+ return;
+ vhost_poll_stop(net->poll + VHOST_NET_VQ_TX);
+ net->tx_poll_state = VHOST_NET_POLL_STOPPED;
+}
+
+/* Caller must have TX VQ lock */
+static void tx_poll_start(struct vhost_net *net, struct socket *sock)
+{
+ if (unlikely(net->tx_poll_state != VHOST_NET_POLL_STOPPED))
+ return;
+ vhost_poll_start(net->poll + VHOST_NET_VQ_TX, sock->file);
+ net->tx_poll_state = VHOST_NET_POLL_STARTED;
+}
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_tx(struct vhost_net *net)
+{
+ struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
+ unsigned head, out, in, s;
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_iov = vq->iov,
+ .msg_flags = MSG_DONTWAIT,
+ };
+ size_t len, total_len = 0;
+ int err, wmem;
+ size_t hdr_size;
+ struct socket *sock = rcu_dereference(vq->private_data);
+ if (!sock)
+ return;
+
+ wmem = atomic_read(&sock->sk->sk_wmem_alloc);
+ if (wmem >= sock->sk->sk_sndbuf) {
+ mutex_lock(&vq->mutex);
+ tx_poll_start(net, sock);
+ mutex_unlock(&vq->mutex);
+ return;
+ }
+
+ use_mm(net->dev.mm);
+ mutex_lock(&vq->mutex);
+ vhost_disable_notify(vq);
+
+ if (wmem < sock->sk->sk_sndbuf * 2)
+ tx_poll_stop(net);
+ hdr_size = vq->hdr_size;
+
+ for (;;) {
+ head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
+ ARRAY_SIZE(vq->iov),
+ &out, &in,
+ NULL, NULL);
+ /* Nothing new? Wait for eventfd to tell us they refilled. */
+ if (head == vq->num) {
+ wmem = atomic_read(&sock->sk->sk_wmem_alloc);
+ if (wmem >= sock->sk->sk_sndbuf * 3 / 4) {
+ tx_poll_start(net, sock);
+ set_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
+ break;
+ }
+ if (unlikely(vhost_enable_notify(vq))) {
+ vhost_disable_notify(vq);
+ continue;
+ }
+ break;
+ }
+ if (in) {
+ vq_err(vq, "Unexpected descriptor format for TX: "
+ "out %d, int %d\n", out, in);
+ break;
+ }
+ /* Skip header. TODO: support TSO. */
+ s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
+ msg.msg_iovlen = out;
+ len = iov_length(vq->iov, out);
+ /* Sanity check */
+ if (!len) {
+ vq_err(vq, "Unexpected header len for TX: "
+ "%zd expected %zd\n",
+ iov_length(vq->hdr, s), hdr_size);
+ break;
+ }
+ /* TODO: Check specific error and bomb out unless ENOBUFS? */
+ err = sock->ops->sendmsg(NULL, sock, &msg, len);
+ if (unlikely(err < 0)) {
+ vhost_discard_vq_desc(vq);
+ tx_poll_start(net, sock);
+ break;
+ }
+ if (err != len)
+ pr_err("Truncated TX packet: "
+ " len %d != %zd\n", err, len);
+ vhost_add_used_and_signal(&net->dev, vq, head, 0);
+ total_len += len;
+ if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
+ vhost_poll_queue(&vq->poll);
+ break;
+ }
+ }
+
+ mutex_unlock(&vq->mutex);
+ unuse_mm(net->dev.mm);
+}
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_rx(struct vhost_net *net)
+{
+ struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
+ unsigned head, out, in, log, s;
+ struct vhost_log *vq_log;
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_control = NULL, /* FIXME: get and handle RX aux data. */
+ .msg_controllen = 0,
+ .msg_iov = vq->iov,
+ .msg_flags = MSG_DONTWAIT,
+ };
+
+ struct virtio_net_hdr hdr = {
+ .flags = 0,
+ .gso_type = VIRTIO_NET_HDR_GSO_NONE
+ };
+
+ size_t len, total_len = 0;
+ int err;
+ size_t hdr_size;
+ struct socket *sock = rcu_dereference(vq->private_data);
+ if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+ return;
+
+ use_mm(net->dev.mm);
+ mutex_lock(&vq->mutex);
+ vhost_disable_notify(vq);
+ hdr_size = vq->hdr_size;
+
+ vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
+ vq->log : NULL;
+
+ for (;;) {
+ head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
+ ARRAY_SIZE(vq->iov),
+ &out, &in,
+ vq_log, &log);
+ /* OK, now we need to know about added descriptors. */
+ if (head == vq->num) {
+ if (unlikely(vhost_enable_notify(vq))) {
+ /* They have slipped one in as we were
+ * doing that: check again. */
+ vhost_disable_notify(vq);
+ continue;
+ }
+ /* Nothing new? Wait for eventfd to tell us
+ * they refilled. */
+ break;
+ }
+ /* We don't need to be notified again. */
+ if (out) {
+ vq_err(vq, "Unexpected descriptor format for RX: "
+ "out %d, int %d\n",
+ out, in);
+ break;
+ }
+ /* Skip header. TODO: support TSO/mergeable rx buffers. */
+ s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
+ msg.msg_iovlen = in;
+ len = iov_length(vq->iov, in);
+ /* Sanity check */
+ if (!len) {
+ vq_err(vq, "Unexpected header len for RX: "
+ "%zd expected %zd\n",
+ iov_length(vq->hdr, s), hdr_size);
+ break;
+ }
+ err = sock->ops->recvmsg(NULL, sock, &msg,
+ len, MSG_DONTWAIT | MSG_TRUNC);
+ /* TODO: Check specific error and bomb out unless EAGAIN? */
+ if (err < 0) {
+ vhost_discard_vq_desc(vq);
+ break;
+ }
+ /* TODO: Should check and handle checksum. */
+ if (err > len) {
+ pr_err("Discarded truncated rx packet: "
+ " len %d > %zd\n", err, len);
+ vhost_discard_vq_desc(vq);
+ continue;
+ }
+ len = err;
+ err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size);
+ if (err) {
+ vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
+ vq->iov->iov_base, err);
+ break;
+ }
+ len += hdr_size;
+ vhost_add_used_and_signal(&net->dev, vq, head, len);
+ if (unlikely(vq_log))
+ vhost_log_write(vq, vq_log, log, len);
+ total_len += len;
+ if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
+ vhost_poll_queue(&vq->poll);
+ break;
+ }
+ }
+
+ mutex_unlock(&vq->mutex);
+ unuse_mm(net->dev.mm);
+}
+
+static void handle_tx_kick(struct work_struct *work)
+{
+ struct vhost_virtqueue *vq;
+ struct vhost_net *net;
+ vq = container_of(work, struct vhost_virtqueue, poll.work);
+ net = container_of(vq->dev, struct vhost_net, dev);
+ handle_tx(net);
+}
+
+static void handle_rx_kick(struct work_struct *work)
+{
+ struct vhost_virtqueue *vq;
+ struct vhost_net *net;
+ vq = container_of(work, struct vhost_virtqueue, poll.work);
+ net = container_of(vq->dev, struct vhost_net, dev);
+ handle_rx(net);
+}
+
+static void handle_tx_net(struct work_struct *work)
+{
+ struct vhost_net *net;
+ net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_TX].work);
+ handle_tx(net);
+}
+
+static void handle_rx_net(struct work_struct *work)
+{
+ struct vhost_net *net;
+ net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_RX].work);
+ handle_rx(net);
+}
+
+static int vhost_net_open(struct inode *inode, struct file *f)
+{
+ struct vhost_net *n = kmalloc(sizeof *n, GFP_KERNEL);
+ int r;
+ if (!n)
+ return -ENOMEM;
+ n->vqs[VHOST_NET_VQ_TX].handle_kick = handle_tx_kick;
+ n->vqs[VHOST_NET_VQ_RX].handle_kick = handle_rx_kick;
+ r = vhost_dev_init(&n->dev, n->vqs, VHOST_NET_VQ_MAX);
+ if (r < 0) {
+ kfree(n);
+ return r;
+ }
+
+ vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT);
+ vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN);
+ n->tx_poll_state = VHOST_NET_POLL_DISABLED;
+
+ f->private_data = n;
+
+ return 0;
+}
+
+static void vhost_net_disable_vq(struct vhost_net *n,
+ struct vhost_virtqueue *vq)
+{
+ if (!vq->private_data)
+ return;
+ if (vq == n->vqs + VHOST_NET_VQ_TX) {
+ tx_poll_stop(n);
+ n->tx_poll_state = VHOST_NET_POLL_DISABLED;
+ } else
+ vhost_poll_stop(n->poll + VHOST_NET_VQ_RX);
+}
+
+static void vhost_net_enable_vq(struct vhost_net *n,
+ struct vhost_virtqueue *vq)
+{
+ struct socket *sock = vq->private_data;
+ if (!sock)
+ return;
+ if (vq == n->vqs + VHOST_NET_VQ_TX) {
+ n->tx_poll_state = VHOST_NET_POLL_STOPPED;
+ tx_poll_start(n, sock);
+ } else
+ vhost_poll_start(n->poll + VHOST_NET_VQ_RX, sock->file);
+}
+
+static struct socket *vhost_net_stop_vq(struct vhost_net *n,
+ struct vhost_virtqueue *vq)
+{
+ struct socket *sock;
+
+ mutex_lock(&vq->mutex);
+ sock = vq->private_data;
+ vhost_net_disable_vq(n, vq);
+ rcu_assign_pointer(vq->private_data, NULL);
+ mutex_unlock(&vq->mutex);
+ return sock;
+}
+
+static void vhost_net_stop(struct vhost_net *n, struct socket **tx_sock,
+ struct socket **rx_sock)
+{
+ *tx_sock = vhost_net_stop_vq(n, n->vqs + VHOST_NET_VQ_TX);
+ *rx_sock = vhost_net_stop_vq(n, n->vqs + VHOST_NET_VQ_RX);
+}
+
+static void vhost_net_flush_vq(struct vhost_net *n, int index)
+{
+ vhost_poll_flush(n->poll + index);
+ vhost_poll_flush(&n->dev.vqs[index].poll);
+}
+
+static void vhost_net_flush(struct vhost_net *n)
+{
+ vhost_net_flush_vq(n, VHOST_NET_VQ_TX);
+ vhost_net_flush_vq(n, VHOST_NET_VQ_RX);
+}
+
+static int vhost_net_release(struct inode *inode, struct file *f)
+{
+ struct vhost_net *n = f->private_data;
+ struct socket *tx_sock;
+ struct socket *rx_sock;
+
+ vhost_net_stop(n, &tx_sock, &rx_sock);
+ vhost_net_flush(n);
+ vhost_dev_cleanup(&n->dev);
+ if (tx_sock)
+ fput(tx_sock->file);
+ if (rx_sock)
+ fput(rx_sock->file);
+ /* We do an extra flush before freeing memory,
+ * since jobs can re-queue themselves. */
+ vhost_net_flush(n);
+ kfree(n);
+ return 0;
+}
+
+static struct socket *get_raw_socket(int fd)
+{
+ struct {
+ struct sockaddr_ll sa;
+ char buf[MAX_ADDR_LEN];
+ } uaddr;
+ int uaddr_len = sizeof uaddr, r;
+ struct socket *sock = sockfd_lookup(fd, &r);
+ if (!sock)
+ return ERR_PTR(-ENOTSOCK);
+
+ /* Parameter checking */
+ if (sock->sk->sk_type != SOCK_RAW) {
+ r = -ESOCKTNOSUPPORT;
+ goto err;
+ }
+
+ r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa,
+ &uaddr_len, 0);
+ if (r)
+ goto err;
+
+ if (uaddr.sa.sll_family != AF_PACKET) {
+ r = -EPFNOSUPPORT;
+ goto err;
+ }
+ return sock;
+err:
+ fput(sock->file);
+ return ERR_PTR(r);
+}
+
+static struct socket *get_tap_socket(int fd)
+{
+ struct file *file = fget(fd);
+ struct socket *sock;
+ if (!file)
+ return ERR_PTR(-EBADF);
+ sock = tun_get_socket(file);
+ if (!IS_ERR(sock))
+ return sock;
+ sock = macvtap_get_socket(file);
+ if (IS_ERR(sock))
+ fput(file);
+ return sock;
+}
+
+static struct socket *get_socket(int fd)
+{
+ struct socket *sock;
+ /* special case to disable backend */
+ if (fd == -1)
+ return NULL;
+ sock = get_raw_socket(fd);
+ if (!IS_ERR(sock))
+ return sock;
+ sock = get_tap_socket(fd);
+ if (!IS_ERR(sock))
+ return sock;
+ return ERR_PTR(-ENOTSOCK);
+}
+
+static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
+{
+ struct socket *sock, *oldsock;
+ struct vhost_virtqueue *vq;
+ int r;
+
+ mutex_lock(&n->dev.mutex);
+ r = vhost_dev_check_owner(&n->dev);
+ if (r)
+ goto err;
+
+ if (index >= VHOST_NET_VQ_MAX) {
+ r = -ENOBUFS;
+ goto err;
+ }
+ vq = n->vqs + index;
+ mutex_lock(&vq->mutex);
+
+ /* Verify that ring has been setup correctly. */
+ if (!vhost_vq_access_ok(vq)) {
+ r = -EFAULT;
+ goto err;
+ }
+ sock = get_socket(fd);
+ if (IS_ERR(sock)) {
+ r = PTR_ERR(sock);
+ goto err;
+ }
+
+ /* start polling new socket */
+ oldsock = vq->private_data;
+ if (sock == oldsock)
+ goto done;
+
+ vhost_net_disable_vq(n, vq);
+ rcu_assign_pointer(vq->private_data, sock);
+ vhost_net_enable_vq(n, vq);
+ mutex_unlock(&vq->mutex);
+done:
+ if (oldsock) {
+ vhost_net_flush_vq(n, index);
+ fput(oldsock->file);
+ }
+err:
+ mutex_unlock(&n->dev.mutex);
+ return r;
+}
+
+static long vhost_net_reset_owner(struct vhost_net *n)
+{
+ struct socket *tx_sock = NULL;
+ struct socket *rx_sock = NULL;
+ long err;
+ mutex_lock(&n->dev.mutex);
+ err = vhost_dev_check_owner(&n->dev);
+ if (err)
+ goto done;
+ vhost_net_stop(n, &tx_sock, &rx_sock);
+ vhost_net_flush(n);
+ err = vhost_dev_reset_owner(&n->dev);
+done:
+ mutex_unlock(&n->dev.mutex);
+ if (tx_sock)
+ fput(tx_sock->file);
+ if (rx_sock)
+ fput(rx_sock->file);
+ return err;
+}
+
+static int vhost_net_set_features(struct vhost_net *n, u64 features)
+{
+ size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
+ sizeof(struct virtio_net_hdr) : 0;
+ int i;
+ mutex_lock(&n->dev.mutex);
+ if ((features & (1 << VHOST_F_LOG_ALL)) &&
+ !vhost_log_access_ok(&n->dev)) {
+ mutex_unlock(&n->dev.mutex);
+ return -EFAULT;
+ }
+ n->dev.acked_features = features;
+ smp_wmb();
+ for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
+ mutex_lock(&n->vqs[i].mutex);
+ n->vqs[i].hdr_size = hdr_size;
+ mutex_unlock(&n->vqs[i].mutex);
+ }
+ vhost_net_flush(n);
+ mutex_unlock(&n->dev.mutex);
+ return 0;
+}
+
+static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
+ unsigned long arg)
+{
+ struct vhost_net *n = f->private_data;
+ void __user *argp = (void __user *)arg;
+ u64 __user *featurep = argp;
+ struct vhost_vring_file backend;
+ u64 features;
+ int r;
+ switch (ioctl) {
+ case VHOST_NET_SET_BACKEND:
+ r = copy_from_user(&backend, argp, sizeof backend);
+ if (r < 0)
+ return r;
+ return vhost_net_set_backend(n, backend.index, backend.fd);
+ case VHOST_GET_FEATURES:
+ features = VHOST_FEATURES;
+ return copy_to_user(featurep, &features, sizeof features);
+ case VHOST_SET_FEATURES:
+ r = copy_from_user(&features, featurep, sizeof features);
+ if (r < 0)
+ return r;
+ if (features & ~VHOST_FEATURES)
+ return -EOPNOTSUPP;
+ return vhost_net_set_features(n, features);
+ case VHOST_RESET_OWNER:
+ return vhost_net_reset_owner(n);
+ default:
+ mutex_lock(&n->dev.mutex);
+ r = vhost_dev_ioctl(&n->dev, ioctl, arg);
+ vhost_net_flush(n);
+ mutex_unlock(&n->dev.mutex);
+ return r;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static long vhost_net_compat_ioctl(struct file *f, unsigned int ioctl,
+ unsigned long arg)
+{
+ return vhost_net_ioctl(f, ioctl, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+const static struct file_operations vhost_net_fops = {
+ .owner = THIS_MODULE,
+ .release = vhost_net_release,
+ .unlocked_ioctl = vhost_net_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = vhost_net_compat_ioctl,
+#endif
+ .open = vhost_net_open,
+};
+
+static struct miscdevice vhost_net_misc = {
+ VHOST_NET_MINOR,
+ "vhost-net",
+ &vhost_net_fops,
+};
+
+int vhost_net_init(void)
+{
+ int r = vhost_init();
+ if (r)
+ goto err_init;
+ r = misc_register(&vhost_net_misc);
+ if (r)
+ goto err_reg;
+ return 0;
+err_reg:
+ vhost_cleanup();
+err_init:
+ return r;
+
+}
+module_init(vhost_net_init);
+
+void vhost_net_exit(void)
+{
+ misc_deregister(&vhost_net_misc);
+ vhost_cleanup();
+}
+module_exit(vhost_net_exit);
+
+MODULE_VERSION("0.0.1");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Michael S. Tsirkin");
+MODULE_DESCRIPTION("Host kernel accelerator for virtio net");
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
new file mode 100644
index 000000000000..7cd55e078794
--- /dev/null
+++ b/drivers/vhost/vhost.c
@@ -0,0 +1,1104 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2006 Rusty Russell IBM Corporation
+ *
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * Inspiration, some code, and most witty comments come from
+ * Documentation/lguest/lguest.c, by Rusty Russell
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * Generic code for virtio server in host kernel.
+ */
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/highmem.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+
+#include <net/sock.h>
+
+#include "vhost.h"
+
+enum {
+ VHOST_MEMORY_MAX_NREGIONS = 64,
+ VHOST_MEMORY_F_LOG = 0x1,
+};
+
+static struct workqueue_struct *vhost_workqueue;
+
+static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
+ poll_table *pt)
+{
+ struct vhost_poll *poll;
+ poll = container_of(pt, struct vhost_poll, table);
+
+ poll->wqh = wqh;
+ add_wait_queue(wqh, &poll->wait);
+}
+
+static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync,
+ void *key)
+{
+ struct vhost_poll *poll;
+ poll = container_of(wait, struct vhost_poll, wait);
+ if (!((unsigned long)key & poll->mask))
+ return 0;
+
+ queue_work(vhost_workqueue, &poll->work);
+ return 0;
+}
+
+/* Init poll structure */
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+ unsigned long mask)
+{
+ INIT_WORK(&poll->work, func);
+ init_waitqueue_func_entry(&poll->wait, vhost_poll_wakeup);
+ init_poll_funcptr(&poll->table, vhost_poll_func);
+ poll->mask = mask;
+}
+
+/* Start polling a file. We add ourselves to file's wait queue. The caller must
+ * keep a reference to a file until after vhost_poll_stop is called. */
+void vhost_poll_start(struct vhost_poll *poll, struct file *file)
+{
+ unsigned long mask;
+ mask = file->f_op->poll(file, &poll->table);
+ if (mask)
+ vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask);
+}
+
+/* Stop polling a file. After this function returns, it becomes safe to drop the
+ * file reference. You must also flush afterwards. */
+void vhost_poll_stop(struct vhost_poll *poll)
+{
+ remove_wait_queue(poll->wqh, &poll->wait);
+}
+
+/* Flush any work that has been scheduled. When calling this, don't hold any
+ * locks that are also used by the callback. */
+void vhost_poll_flush(struct vhost_poll *poll)
+{
+ flush_work(&poll->work);
+}
+
+void vhost_poll_queue(struct vhost_poll *poll)
+{
+ queue_work(vhost_workqueue, &poll->work);
+}
+
+static void vhost_vq_reset(struct vhost_dev *dev,
+ struct vhost_virtqueue *vq)
+{
+ vq->num = 1;
+ vq->desc = NULL;
+ vq->avail = NULL;
+ vq->used = NULL;
+ vq->last_avail_idx = 0;
+ vq->avail_idx = 0;
+ vq->last_used_idx = 0;
+ vq->used_flags = 0;
+ vq->used_flags = 0;
+ vq->log_used = false;
+ vq->log_addr = -1ull;
+ vq->hdr_size = 0;
+ vq->private_data = NULL;
+ vq->log_base = NULL;
+ vq->error_ctx = NULL;
+ vq->error = NULL;
+ vq->kick = NULL;
+ vq->call_ctx = NULL;
+ vq->call = NULL;
+ vq->log_ctx = NULL;
+}
+
+long vhost_dev_init(struct vhost_dev *dev,
+ struct vhost_virtqueue *vqs, int nvqs)
+{
+ int i;
+ dev->vqs = vqs;
+ dev->nvqs = nvqs;
+ mutex_init(&dev->mutex);
+ dev->log_ctx = NULL;
+ dev->log_file = NULL;
+ dev->memory = NULL;
+ dev->mm = NULL;
+
+ for (i = 0; i < dev->nvqs; ++i) {
+ dev->vqs[i].dev = dev;
+ mutex_init(&dev->vqs[i].mutex);
+ vhost_vq_reset(dev, dev->vqs + i);
+ if (dev->vqs[i].handle_kick)
+ vhost_poll_init(&dev->vqs[i].poll,
+ dev->vqs[i].handle_kick,
+ POLLIN);
+ }
+ return 0;
+}
+
+/* Caller should have device mutex */
+long vhost_dev_check_owner(struct vhost_dev *dev)
+{
+ /* Are you the owner? If not, I don't think you mean to do that */
+ return dev->mm == current->mm ? 0 : -EPERM;
+}
+
+/* Caller should have device mutex */
+static long vhost_dev_set_owner(struct vhost_dev *dev)
+{
+ /* Is there an owner already? */
+ if (dev->mm)
+ return -EBUSY;
+ /* No owner, become one */
+ dev->mm = get_task_mm(current);
+ return 0;
+}
+
+/* Caller should have device mutex */
+long vhost_dev_reset_owner(struct vhost_dev *dev)
+{
+ struct vhost_memory *memory;
+
+ /* Restore memory to default empty mapping. */
+ memory = kmalloc(offsetof(struct vhost_memory, regions), GFP_KERNEL);
+ if (!memory)
+ return -ENOMEM;
+
+ vhost_dev_cleanup(dev);
+
+ memory->nregions = 0;
+ dev->memory = memory;
+ return 0;
+}
+
+/* Caller should have device mutex */
+void vhost_dev_cleanup(struct vhost_dev *dev)
+{
+ int i;
+ for (i = 0; i < dev->nvqs; ++i) {
+ if (dev->vqs[i].kick && dev->vqs[i].handle_kick) {
+ vhost_poll_stop(&dev->vqs[i].poll);
+ vhost_poll_flush(&dev->vqs[i].poll);
+ }
+ if (dev->vqs[i].error_ctx)
+ eventfd_ctx_put(dev->vqs[i].error_ctx);
+ if (dev->vqs[i].error)
+ fput(dev->vqs[i].error);
+ if (dev->vqs[i].kick)
+ fput(dev->vqs[i].kick);
+ if (dev->vqs[i].call_ctx)
+ eventfd_ctx_put(dev->vqs[i].call_ctx);
+ if (dev->vqs[i].call)
+ fput(dev->vqs[i].call);
+ vhost_vq_reset(dev, dev->vqs + i);
+ }
+ if (dev->log_ctx)
+ eventfd_ctx_put(dev->log_ctx);
+ dev->log_ctx = NULL;
+ if (dev->log_file)
+ fput(dev->log_file);
+ dev->log_file = NULL;
+ /* No one will access memory at this point */
+ kfree(dev->memory);
+ dev->memory = NULL;
+ if (dev->mm)
+ mmput(dev->mm);
+ dev->mm = NULL;
+}
+
+static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
+{
+ u64 a = addr / VHOST_PAGE_SIZE / 8;
+ /* Make sure 64 bit math will not overflow. */
+ if (a > ULONG_MAX - (unsigned long)log_base ||
+ a + (unsigned long)log_base > ULONG_MAX)
+ return -EFAULT;
+
+ return access_ok(VERIFY_WRITE, log_base + a,
+ (sz + VHOST_PAGE_SIZE * 8 - 1) / VHOST_PAGE_SIZE / 8);
+}
+
+/* Caller should have vq mutex and device mutex. */
+static int vq_memory_access_ok(void __user *log_base, struct vhost_memory *mem,
+ int log_all)
+{
+ int i;
+ for (i = 0; i < mem->nregions; ++i) {
+ struct vhost_memory_region *m = mem->regions + i;
+ unsigned long a = m->userspace_addr;
+ if (m->memory_size > ULONG_MAX)
+ return 0;
+ else if (!access_ok(VERIFY_WRITE, (void __user *)a,
+ m->memory_size))
+ return 0;
+ else if (log_all && !log_access_ok(log_base,
+ m->guest_phys_addr,
+ m->memory_size))
+ return 0;
+ }
+ return 1;
+}
+
+/* Can we switch to this memory table? */
+/* Caller should have device mutex but not vq mutex */
+static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem,
+ int log_all)
+{
+ int i;
+ for (i = 0; i < d->nvqs; ++i) {
+ int ok;
+ mutex_lock(&d->vqs[i].mutex);
+ /* If ring is inactive, will check when it's enabled. */
+ if (d->vqs[i].private_data)
+ ok = vq_memory_access_ok(d->vqs[i].log_base, mem,
+ log_all);
+ else
+ ok = 1;
+ mutex_unlock(&d->vqs[i].mutex);
+ if (!ok)
+ return 0;
+ }
+ return 1;
+}
+
+static int vq_access_ok(unsigned int num,
+ struct vring_desc __user *desc,
+ struct vring_avail __user *avail,
+ struct vring_used __user *used)
+{
+ return access_ok(VERIFY_READ, desc, num * sizeof *desc) &&
+ access_ok(VERIFY_READ, avail,
+ sizeof *avail + num * sizeof *avail->ring) &&
+ access_ok(VERIFY_WRITE, used,
+ sizeof *used + num * sizeof *used->ring);
+}
+
+/* Can we log writes? */
+/* Caller should have device mutex but not vq mutex */
+int vhost_log_access_ok(struct vhost_dev *dev)
+{
+ return memory_access_ok(dev, dev->memory, 1);
+}
+
+/* Verify access for write logging. */
+/* Caller should have vq mutex and device mutex */
+static int vq_log_access_ok(struct vhost_virtqueue *vq, void __user *log_base)
+{
+ return vq_memory_access_ok(log_base, vq->dev->memory,
+ vhost_has_feature(vq->dev, VHOST_F_LOG_ALL)) &&
+ (!vq->log_used || log_access_ok(log_base, vq->log_addr,
+ sizeof *vq->used +
+ vq->num * sizeof *vq->used->ring));
+}
+
+/* Can we start vq? */
+/* Caller should have vq mutex and device mutex */
+int vhost_vq_access_ok(struct vhost_virtqueue *vq)
+{
+ return vq_access_ok(vq->num, vq->desc, vq->avail, vq->used) &&
+ vq_log_access_ok(vq, vq->log_base);
+}
+
+static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
+{
+ struct vhost_memory mem, *newmem, *oldmem;
+ unsigned long size = offsetof(struct vhost_memory, regions);
+ long r;
+ r = copy_from_user(&mem, m, size);
+ if (r)
+ return r;
+ if (mem.padding)
+ return -EOPNOTSUPP;
+ if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS)
+ return -E2BIG;
+ newmem = kmalloc(size + mem.nregions * sizeof *m->regions, GFP_KERNEL);
+ if (!newmem)
+ return -ENOMEM;
+
+ memcpy(newmem, &mem, size);
+ r = copy_from_user(newmem->regions, m->regions,
+ mem.nregions * sizeof *m->regions);
+ if (r) {
+ kfree(newmem);
+ return r;
+ }
+
+ if (!memory_access_ok(d, newmem, vhost_has_feature(d, VHOST_F_LOG_ALL)))
+ return -EFAULT;
+ oldmem = d->memory;
+ rcu_assign_pointer(d->memory, newmem);
+ synchronize_rcu();
+ kfree(oldmem);
+ return 0;
+}
+
+static int init_used(struct vhost_virtqueue *vq,
+ struct vring_used __user *used)
+{
+ int r = put_user(vq->used_flags, &used->flags);
+ if (r)
+ return r;
+ return get_user(vq->last_used_idx, &used->idx);
+}
+
+static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
+{
+ struct file *eventfp, *filep = NULL,
+ *pollstart = NULL, *pollstop = NULL;
+ struct eventfd_ctx *ctx = NULL;
+ u32 __user *idxp = argp;
+ struct vhost_virtqueue *vq;
+ struct vhost_vring_state s;
+ struct vhost_vring_file f;
+ struct vhost_vring_addr a;
+ u32 idx;
+ long r;
+
+ r = get_user(idx, idxp);
+ if (r < 0)
+ return r;
+ if (idx > d->nvqs)
+ return -ENOBUFS;
+
+ vq = d->vqs + idx;
+
+ mutex_lock(&vq->mutex);
+
+ switch (ioctl) {
+ case VHOST_SET_VRING_NUM:
+ /* Resizing ring with an active backend?
+ * You don't want to do that. */
+ if (vq->private_data) {
+ r = -EBUSY;
+ break;
+ }
+ r = copy_from_user(&s, argp, sizeof s);
+ if (r < 0)
+ break;
+ if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) {
+ r = -EINVAL;
+ break;
+ }
+ vq->num = s.num;
+ break;
+ case VHOST_SET_VRING_BASE:
+ /* Moving base with an active backend?
+ * You don't want to do that. */
+ if (vq->private_data) {
+ r = -EBUSY;
+ break;
+ }
+ r = copy_from_user(&s, argp, sizeof s);
+ if (r < 0)
+ break;
+ if (s.num > 0xffff) {
+ r = -EINVAL;
+ break;
+ }
+ vq->last_avail_idx = s.num;
+ /* Forget the cached index value. */
+ vq->avail_idx = vq->last_avail_idx;
+ break;
+ case VHOST_GET_VRING_BASE:
+ s.index = idx;
+ s.num = vq->last_avail_idx;
+ r = copy_to_user(argp, &s, sizeof s);
+ break;
+ case VHOST_SET_VRING_ADDR:
+ r = copy_from_user(&a, argp, sizeof a);
+ if (r < 0)
+ break;
+ if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) {
+ r = -EOPNOTSUPP;
+ break;
+ }
+ /* For 32bit, verify that the top 32bits of the user
+ data are set to zero. */
+ if ((u64)(unsigned long)a.desc_user_addr != a.desc_user_addr ||
+ (u64)(unsigned long)a.used_user_addr != a.used_user_addr ||
+ (u64)(unsigned long)a.avail_user_addr != a.avail_user_addr) {
+ r = -EFAULT;
+ break;
+ }
+ if ((a.avail_user_addr & (sizeof *vq->avail->ring - 1)) ||
+ (a.used_user_addr & (sizeof *vq->used->ring - 1)) ||
+ (a.log_guest_addr & (sizeof *vq->used->ring - 1))) {
+ r = -EINVAL;
+ break;
+ }
+
+ /* We only verify access here if backend is configured.
+ * If it is not, we don't as size might not have been setup.
+ * We will verify when backend is configured. */
+ if (vq->private_data) {
+ if (!vq_access_ok(vq->num,
+ (void __user *)(unsigned long)a.desc_user_addr,
+ (void __user *)(unsigned long)a.avail_user_addr,
+ (void __user *)(unsigned long)a.used_user_addr)) {
+ r = -EINVAL;
+ break;
+ }
+
+ /* Also validate log access for used ring if enabled. */
+ if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) &&
+ !log_access_ok(vq->log_base, a.log_guest_addr,
+ sizeof *vq->used +
+ vq->num * sizeof *vq->used->ring)) {
+ r = -EINVAL;
+ break;
+ }
+ }
+
+ r = init_used(vq, (struct vring_used __user *)(unsigned long)
+ a.used_user_addr);
+ if (r)
+ break;
+ vq->log_used = !!(a.flags & (0x1 << VHOST_VRING_F_LOG));
+ vq->desc = (void __user *)(unsigned long)a.desc_user_addr;
+ vq->avail = (void __user *)(unsigned long)a.avail_user_addr;
+ vq->log_addr = a.log_guest_addr;
+ vq->used = (void __user *)(unsigned long)a.used_user_addr;
+ break;
+ case VHOST_SET_VRING_KICK:
+ r = copy_from_user(&f, argp, sizeof f);
+ if (r < 0)
+ break;
+ eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+ if (IS_ERR(eventfp))
+ return PTR_ERR(eventfp);
+ if (eventfp != vq->kick) {
+ pollstop = filep = vq->kick;
+ pollstart = vq->kick = eventfp;
+ } else
+ filep = eventfp;
+ break;
+ case VHOST_SET_VRING_CALL:
+ r = copy_from_user(&f, argp, sizeof f);
+ if (r < 0)
+ break;
+ eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+ if (IS_ERR(eventfp))
+ return PTR_ERR(eventfp);
+ if (eventfp != vq->call) {
+ filep = vq->call;
+ ctx = vq->call_ctx;
+ vq->call = eventfp;
+ vq->call_ctx = eventfp ?
+ eventfd_ctx_fileget(eventfp) : NULL;
+ } else
+ filep = eventfp;
+ break;
+ case VHOST_SET_VRING_ERR:
+ r = copy_from_user(&f, argp, sizeof f);
+ if (r < 0)
+ break;
+ eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+ if (IS_ERR(eventfp))
+ return PTR_ERR(eventfp);
+ if (eventfp != vq->error) {
+ filep = vq->error;
+ vq->error = eventfp;
+ ctx = vq->error_ctx;
+ vq->error_ctx = eventfp ?
+ eventfd_ctx_fileget(eventfp) : NULL;
+ } else
+ filep = eventfp;
+ break;
+ default:
+ r = -ENOIOCTLCMD;
+ }
+
+ if (pollstop && vq->handle_kick)
+ vhost_poll_stop(&vq->poll);
+
+ if (ctx)
+ eventfd_ctx_put(ctx);
+ if (filep)
+ fput(filep);
+
+ if (pollstart && vq->handle_kick)
+ vhost_poll_start(&vq->poll, vq->kick);
+
+ mutex_unlock(&vq->mutex);
+
+ if (pollstop && vq->handle_kick)
+ vhost_poll_flush(&vq->poll);
+ return r;
+}
+
+/* Caller must have device mutex */
+long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ struct file *eventfp, *filep = NULL;
+ struct eventfd_ctx *ctx = NULL;
+ u64 p;
+ long r;
+ int i, fd;
+
+ /* If you are not the owner, you can become one */
+ if (ioctl == VHOST_SET_OWNER) {
+ r = vhost_dev_set_owner(d);
+ goto done;
+ }
+
+ /* You must be the owner to do anything else */
+ r = vhost_dev_check_owner(d);
+ if (r)
+ goto done;
+
+ switch (ioctl) {
+ case VHOST_SET_MEM_TABLE:
+ r = vhost_set_memory(d, argp);
+ break;
+ case VHOST_SET_LOG_BASE:
+ r = copy_from_user(&p, argp, sizeof p);
+ if (r < 0)
+ break;
+ if ((u64)(unsigned long)p != p) {
+ r = -EFAULT;
+ break;
+ }
+ for (i = 0; i < d->nvqs; ++i) {
+ struct vhost_virtqueue *vq;
+ void __user *base = (void __user *)(unsigned long)p;
+ vq = d->vqs + i;
+ mutex_lock(&vq->mutex);
+ /* If ring is inactive, will check when it's enabled. */
+ if (vq->private_data && !vq_log_access_ok(vq, base))
+ r = -EFAULT;
+ else
+ vq->log_base = base;
+ mutex_unlock(&vq->mutex);
+ }
+ break;
+ case VHOST_SET_LOG_FD:
+ r = get_user(fd, (int __user *)argp);
+ if (r < 0)
+ break;
+ eventfp = fd == -1 ? NULL : eventfd_fget(fd);
+ if (IS_ERR(eventfp)) {
+ r = PTR_ERR(eventfp);
+ break;
+ }
+ if (eventfp != d->log_file) {
+ filep = d->log_file;
+ ctx = d->log_ctx;
+ d->log_ctx = eventfp ?
+ eventfd_ctx_fileget(eventfp) : NULL;
+ } else
+ filep = eventfp;
+ for (i = 0; i < d->nvqs; ++i) {
+ mutex_lock(&d->vqs[i].mutex);
+ d->vqs[i].log_ctx = d->log_ctx;
+ mutex_unlock(&d->vqs[i].mutex);
+ }
+ if (ctx)
+ eventfd_ctx_put(ctx);
+ if (filep)
+ fput(filep);
+ break;
+ default:
+ r = vhost_set_vring(d, ioctl, argp);
+ break;
+ }
+done:
+ return r;
+}
+
+static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
+ __u64 addr, __u32 len)
+{
+ struct vhost_memory_region *reg;
+ int i;
+ /* linear search is not brilliant, but we really have on the order of 6
+ * regions in practice */
+ for (i = 0; i < mem->nregions; ++i) {
+ reg = mem->regions + i;
+ if (reg->guest_phys_addr <= addr &&
+ reg->guest_phys_addr + reg->memory_size - 1 >= addr)
+ return reg;
+ }
+ return NULL;
+}
+
+/* TODO: This is really inefficient. We need something like get_user()
+ * (instruction directly accesses the data, with an exception table entry
+ * returning -EFAULT). See Documentation/x86/exception-tables.txt.
+ */
+static int set_bit_to_user(int nr, void __user *addr)
+{
+ unsigned long log = (unsigned long)addr;
+ struct page *page;
+ void *base;
+ int bit = nr + (log % PAGE_SIZE) * 8;
+ int r;
+ r = get_user_pages_fast(log, 1, 1, &page);
+ if (r < 0)
+ return r;
+ BUG_ON(r != 1);
+ base = kmap_atomic(page, KM_USER0);
+ set_bit(bit, base);
+ kunmap_atomic(base, KM_USER0);
+ set_page_dirty_lock(page);
+ put_page(page);
+ return 0;
+}
+
+static int log_write(void __user *log_base,
+ u64 write_address, u64 write_length)
+{
+ int r;
+ if (!write_length)
+ return 0;
+ write_address /= VHOST_PAGE_SIZE;
+ for (;;) {
+ u64 base = (u64)(unsigned long)log_base;
+ u64 log = base + write_address / 8;
+ int bit = write_address % 8;
+ if ((u64)(unsigned long)log != log)
+ return -EFAULT;
+ r = set_bit_to_user(bit, (void __user *)(unsigned long)log);
+ if (r < 0)
+ return r;
+ if (write_length <= VHOST_PAGE_SIZE)
+ break;
+ write_length -= VHOST_PAGE_SIZE;
+ write_address += VHOST_PAGE_SIZE;
+ }
+ return r;
+}
+
+int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
+ unsigned int log_num, u64 len)
+{
+ int i, r;
+
+ /* Make sure data written is seen before log. */
+ smp_wmb();
+ for (i = 0; i < log_num; ++i) {
+ u64 l = min(log[i].len, len);
+ r = log_write(vq->log_base, log[i].addr, l);
+ if (r < 0)
+ return r;
+ len -= l;
+ if (!len)
+ return 0;
+ }
+ if (vq->log_ctx)
+ eventfd_signal(vq->log_ctx, 1);
+ /* Length written exceeds what we have stored. This is a bug. */
+ BUG();
+ return 0;
+}
+
+int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
+ struct iovec iov[], int iov_size)
+{
+ const struct vhost_memory_region *reg;
+ struct vhost_memory *mem;
+ struct iovec *_iov;
+ u64 s = 0;
+ int ret = 0;
+
+ rcu_read_lock();
+
+ mem = rcu_dereference(dev->memory);
+ while ((u64)len > s) {
+ u64 size;
+ if (ret >= iov_size) {
+ ret = -ENOBUFS;
+ break;
+ }
+ reg = find_region(mem, addr, len);
+ if (!reg) {
+ ret = -EFAULT;
+ break;
+ }
+ _iov = iov + ret;
+ size = reg->memory_size - addr + reg->guest_phys_addr;
+ _iov->iov_len = min((u64)len, size);
+ _iov->iov_base = (void *)(unsigned long)
+ (reg->userspace_addr + addr - reg->guest_phys_addr);
+ s += size;
+ addr += size;
+ ++ret;
+ }
+
+ rcu_read_unlock();
+ return ret;
+}
+
+/* Each buffer in the virtqueues is actually a chain of descriptors. This
+ * function returns the next descriptor in the chain,
+ * or -1U if we're at the end. */
+static unsigned next_desc(struct vring_desc *desc)
+{
+ unsigned int next;
+
+ /* If this descriptor says it doesn't chain, we're done. */
+ if (!(desc->flags & VRING_DESC_F_NEXT))
+ return -1U;
+
+ /* Check they're not leading us off end of descriptors. */
+ next = desc->next;
+ /* Make sure compiler knows to grab that: we don't want it changing! */
+ /* We will use the result as an index in an array, so most
+ * architectures only need a compiler barrier here. */
+ read_barrier_depends();
+
+ return next;
+}
+
+static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+ struct iovec iov[], unsigned int iov_size,
+ unsigned int *out_num, unsigned int *in_num,
+ struct vhost_log *log, unsigned int *log_num,
+ struct vring_desc *indirect)
+{
+ struct vring_desc desc;
+ unsigned int i = 0, count, found = 0;
+ int ret;
+
+ /* Sanity check */
+ if (indirect->len % sizeof desc) {
+ vq_err(vq, "Invalid length in indirect descriptor: "
+ "len 0x%llx not multiple of 0x%zx\n",
+ (unsigned long long)indirect->len,
+ sizeof desc);
+ return -EINVAL;
+ }
+
+ ret = translate_desc(dev, indirect->addr, indirect->len, vq->indirect,
+ ARRAY_SIZE(vq->indirect));
+ if (ret < 0) {
+ vq_err(vq, "Translation failure %d in indirect.\n", ret);
+ return ret;
+ }
+
+ /* We will use the result as an address to read from, so most
+ * architectures only need a compiler barrier here. */
+ read_barrier_depends();
+
+ count = indirect->len / sizeof desc;
+ /* Buffers are chained via a 16 bit next field, so
+ * we can have at most 2^16 of these. */
+ if (count > USHORT_MAX + 1) {
+ vq_err(vq, "Indirect buffer length too big: %d\n",
+ indirect->len);
+ return -E2BIG;
+ }
+
+ do {
+ unsigned iov_count = *in_num + *out_num;
+ if (++found > count) {
+ vq_err(vq, "Loop detected: last one at %u "
+ "indirect size %u\n",
+ i, count);
+ return -EINVAL;
+ }
+ if (memcpy_fromiovec((unsigned char *)&desc, vq->indirect,
+ sizeof desc)) {
+ vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n",
+ i, (size_t)indirect->addr + i * sizeof desc);
+ return -EINVAL;
+ }
+ if (desc.flags & VRING_DESC_F_INDIRECT) {
+ vq_err(vq, "Nested indirect descriptor: idx %d, %zx\n",
+ i, (size_t)indirect->addr + i * sizeof desc);
+ return -EINVAL;
+ }
+
+ ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count,
+ iov_size - iov_count);
+ if (ret < 0) {
+ vq_err(vq, "Translation failure %d indirect idx %d\n",
+ ret, i);
+ return ret;
+ }
+ /* If this is an input descriptor, increment that count. */
+ if (desc.flags & VRING_DESC_F_WRITE) {
+ *in_num += ret;
+ if (unlikely(log)) {
+ log[*log_num].addr = desc.addr;
+ log[*log_num].len = desc.len;
+ ++*log_num;
+ }
+ } else {
+ /* If it's an output descriptor, they're all supposed
+ * to come before any input descriptors. */
+ if (*in_num) {
+ vq_err(vq, "Indirect descriptor "
+ "has out after in: idx %d\n", i);
+ return -EINVAL;
+ }
+ *out_num += ret;
+ }
+ } while ((i = next_desc(&desc)) != -1);
+ return 0;
+}
+
+/* This looks in the virtqueue and for the first available buffer, and converts
+ * it to an iovec for convenient access. Since descriptors consist of some
+ * number of output then some number of input descriptors, it's actually two
+ * iovecs, but we pack them into one and note how many of each there were.
+ *
+ * This function returns the descriptor number found, or vq->num (which
+ * is never a valid descriptor number) if none was found. */
+unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+ struct iovec iov[], unsigned int iov_size,
+ unsigned int *out_num, unsigned int *in_num,
+ struct vhost_log *log, unsigned int *log_num)
+{
+ struct vring_desc desc;
+ unsigned int i, head, found = 0;
+ u16 last_avail_idx;
+ int ret;
+
+ /* Check it isn't doing very strange things with descriptor numbers. */
+ last_avail_idx = vq->last_avail_idx;
+ if (get_user(vq->avail_idx, &vq->avail->idx)) {
+ vq_err(vq, "Failed to access avail idx at %p\n",
+ &vq->avail->idx);
+ return vq->num;
+ }
+
+ if ((u16)(vq->avail_idx - last_avail_idx) > vq->num) {
+ vq_err(vq, "Guest moved used index from %u to %u",
+ last_avail_idx, vq->avail_idx);
+ return vq->num;
+ }
+
+ /* If there's nothing new since last we looked, return invalid. */
+ if (vq->avail_idx == last_avail_idx)
+ return vq->num;
+
+ /* Only get avail ring entries after they have been exposed by guest. */
+ smp_rmb();
+
+ /* Grab the next descriptor number they're advertising, and increment
+ * the index we've seen. */
+ if (get_user(head, &vq->avail->ring[last_avail_idx % vq->num])) {
+ vq_err(vq, "Failed to read head: idx %d address %p\n",
+ last_avail_idx,
+ &vq->avail->ring[last_avail_idx % vq->num]);
+ return vq->num;
+ }
+
+ /* If their number is silly, that's an error. */
+ if (head >= vq->num) {
+ vq_err(vq, "Guest says index %u > %u is available",
+ head, vq->num);
+ return vq->num;
+ }
+
+ /* When we start there are none of either input nor output. */
+ *out_num = *in_num = 0;
+ if (unlikely(log))
+ *log_num = 0;
+
+ i = head;
+ do {
+ unsigned iov_count = *in_num + *out_num;
+ if (i >= vq->num) {
+ vq_err(vq, "Desc index is %u > %u, head = %u",
+ i, vq->num, head);
+ return vq->num;
+ }
+ if (++found > vq->num) {
+ vq_err(vq, "Loop detected: last one at %u "
+ "vq size %u head %u\n",
+ i, vq->num, head);
+ return vq->num;
+ }
+ ret = copy_from_user(&desc, vq->desc + i, sizeof desc);
+ if (ret) {
+ vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
+ i, vq->desc + i);
+ return vq->num;
+ }
+ if (desc.flags & VRING_DESC_F_INDIRECT) {
+ ret = get_indirect(dev, vq, iov, iov_size,
+ out_num, in_num,
+ log, log_num, &desc);
+ if (ret < 0) {
+ vq_err(vq, "Failure detected "
+ "in indirect descriptor at idx %d\n", i);
+ return vq->num;
+ }
+ continue;
+ }
+
+ ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count,
+ iov_size - iov_count);
+ if (ret < 0) {
+ vq_err(vq, "Translation failure %d descriptor idx %d\n",
+ ret, i);
+ return vq->num;
+ }
+ if (desc.flags & VRING_DESC_F_WRITE) {
+ /* If this is an input descriptor,
+ * increment that count. */
+ *in_num += ret;
+ if (unlikely(log)) {
+ log[*log_num].addr = desc.addr;
+ log[*log_num].len = desc.len;
+ ++*log_num;
+ }
+ } else {
+ /* If it's an output descriptor, they're all supposed
+ * to come before any input descriptors. */
+ if (*in_num) {
+ vq_err(vq, "Descriptor has out after in: "
+ "idx %d\n", i);
+ return vq->num;
+ }
+ *out_num += ret;
+ }
+ } while ((i = next_desc(&desc)) != -1);
+
+ /* On success, increment avail index. */
+ vq->last_avail_idx++;
+ return head;
+}
+
+/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
+void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+{
+ vq->last_avail_idx--;
+}
+
+/* After we've used one of their buffers, we tell them about it. We'll then
+ * want to notify the guest, using eventfd. */
+int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
+{
+ struct vring_used_elem *used;
+
+ /* The virtqueue contains a ring of used buffers. Get a pointer to the
+ * next entry in that used ring. */
+ used = &vq->used->ring[vq->last_used_idx % vq->num];
+ if (put_user(head, &used->id)) {
+ vq_err(vq, "Failed to write used id");
+ return -EFAULT;
+ }
+ if (put_user(len, &used->len)) {
+ vq_err(vq, "Failed to write used len");
+ return -EFAULT;
+ }
+ /* Make sure buffer is written before we update index. */
+ smp_wmb();
+ if (put_user(vq->last_used_idx + 1, &vq->used->idx)) {
+ vq_err(vq, "Failed to increment used idx");
+ return -EFAULT;
+ }
+ if (unlikely(vq->log_used)) {
+ /* Make sure data is seen before log. */
+ smp_wmb();
+ /* Log used ring entry write. */
+ log_write(vq->log_base,
+ vq->log_addr + ((void *)used - (void *)vq->used),
+ sizeof *used);
+ /* Log used index update. */
+ log_write(vq->log_base,
+ vq->log_addr + offsetof(struct vring_used, idx),
+ sizeof vq->used->idx);
+ if (vq->log_ctx)
+ eventfd_signal(vq->log_ctx, 1);
+ }
+ vq->last_used_idx++;
+ return 0;
+}
+
+/* This actually signals the guest, using eventfd. */
+void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
+{
+ __u16 flags = 0;
+ if (get_user(flags, &vq->avail->flags)) {
+ vq_err(vq, "Failed to get flags");
+ return;
+ }
+
+ /* If they don't want an interrupt, don't signal, unless empty. */
+ if ((flags & VRING_AVAIL_F_NO_INTERRUPT) &&
+ (vq->avail_idx != vq->last_avail_idx ||
+ !vhost_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY)))
+ return;
+
+ /* Signal the Guest tell them we used something up. */
+ if (vq->call_ctx)
+ eventfd_signal(vq->call_ctx, 1);
+}
+
+/* And here's the combo meal deal. Supersize me! */
+void vhost_add_used_and_signal(struct vhost_dev *dev,
+ struct vhost_virtqueue *vq,
+ unsigned int head, int len)
+{
+ vhost_add_used(vq, head, len);
+ vhost_signal(dev, vq);
+}
+
+/* OK, now we need to know about added descriptors. */
+bool vhost_enable_notify(struct vhost_virtqueue *vq)
+{
+ u16 avail_idx;
+ int r;
+ if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY))
+ return false;
+ vq->used_flags &= ~VRING_USED_F_NO_NOTIFY;
+ r = put_user(vq->used_flags, &vq->used->flags);
+ if (r) {
+ vq_err(vq, "Failed to enable notification at %p: %d\n",
+ &vq->used->flags, r);
+ return false;
+ }
+ /* They could have slipped one in as we were doing that: make
+ * sure it's written, then check again. */
+ smp_mb();
+ r = get_user(avail_idx, &vq->avail->idx);
+ if (r) {
+ vq_err(vq, "Failed to check avail idx at %p: %d\n",
+ &vq->avail->idx, r);
+ return false;
+ }
+
+ return avail_idx != vq->last_avail_idx;
+}
+
+/* We don't need to be notified again. */
+void vhost_disable_notify(struct vhost_virtqueue *vq)
+{
+ int r;
+ if (vq->used_flags & VRING_USED_F_NO_NOTIFY)
+ return;
+ vq->used_flags |= VRING_USED_F_NO_NOTIFY;
+ r = put_user(vq->used_flags, &vq->used->flags);
+ if (r)
+ vq_err(vq, "Failed to enable notification at %p: %d\n",
+ &vq->used->flags, r);
+}
+
+int vhost_init(void)
+{
+ vhost_workqueue = create_singlethread_workqueue("vhost");
+ if (!vhost_workqueue)
+ return -ENOMEM;
+ return 0;
+}
+
+void vhost_cleanup(void)
+{
+ destroy_workqueue(vhost_workqueue);
+}
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
new file mode 100644
index 000000000000..44591ba9b07a
--- /dev/null
+++ b/drivers/vhost/vhost.h
@@ -0,0 +1,161 @@
+#ifndef _VHOST_H
+#define _VHOST_H
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/skbuff.h>
+#include <linux/uio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+
+struct vhost_device;
+
+enum {
+ /* Enough place for all fragments, head, and virtio net header. */
+ VHOST_NET_MAX_SG = MAX_SKB_FRAGS + 2,
+};
+
+/* Poll a file (eventfd or socket) */
+/* Note: there's nothing vhost specific about this structure. */
+struct vhost_poll {
+ poll_table table;
+ wait_queue_head_t *wqh;
+ wait_queue_t wait;
+ /* struct which will handle all actual work. */
+ struct work_struct work;
+ unsigned long mask;
+};
+
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+ unsigned long mask);
+void vhost_poll_start(struct vhost_poll *poll, struct file *file);
+void vhost_poll_stop(struct vhost_poll *poll);
+void vhost_poll_flush(struct vhost_poll *poll);
+void vhost_poll_queue(struct vhost_poll *poll);
+
+struct vhost_log {
+ u64 addr;
+ u64 len;
+};
+
+/* The virtqueue structure describes a queue attached to a device. */
+struct vhost_virtqueue {
+ struct vhost_dev *dev;
+
+ /* The actual ring of buffers. */
+ struct mutex mutex;
+ unsigned int num;
+ struct vring_desc __user *desc;
+ struct vring_avail __user *avail;
+ struct vring_used __user *used;
+ struct file *kick;
+ struct file *call;
+ struct file *error;
+ struct eventfd_ctx *call_ctx;
+ struct eventfd_ctx *error_ctx;
+ struct eventfd_ctx *log_ctx;
+
+ struct vhost_poll poll;
+
+ /* The routine to call when the Guest pings us, or timeout. */
+ work_func_t handle_kick;
+
+ /* Last available index we saw. */
+ u16 last_avail_idx;
+
+ /* Caches available index value from user. */
+ u16 avail_idx;
+
+ /* Last index we used. */
+ u16 last_used_idx;
+
+ /* Used flags */
+ u16 used_flags;
+
+ /* Log writes to used structure. */
+ bool log_used;
+ u64 log_addr;
+
+ struct iovec indirect[VHOST_NET_MAX_SG];
+ struct iovec iov[VHOST_NET_MAX_SG];
+ struct iovec hdr[VHOST_NET_MAX_SG];
+ size_t hdr_size;
+ /* We use a kind of RCU to access private pointer.
+ * All readers access it from workqueue, which makes it possible to
+ * flush the workqueue instead of synchronize_rcu. Therefore readers do
+ * not need to call rcu_read_lock/rcu_read_unlock: the beginning of
+ * work item execution acts instead of rcu_read_lock() and the end of
+ * work item execution acts instead of rcu_read_lock().
+ * Writers use virtqueue mutex. */
+ void *private_data;
+ /* Log write descriptors */
+ void __user *log_base;
+ struct vhost_log log[VHOST_NET_MAX_SG];
+};
+
+struct vhost_dev {
+ /* Readers use RCU to access memory table pointer
+ * log base pointer and features.
+ * Writers use mutex below.*/
+ struct vhost_memory *memory;
+ struct mm_struct *mm;
+ struct mutex mutex;
+ unsigned acked_features;
+ struct vhost_virtqueue *vqs;
+ int nvqs;
+ struct file *log_file;
+ struct eventfd_ctx *log_ctx;
+};
+
+long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs);
+long vhost_dev_check_owner(struct vhost_dev *);
+long vhost_dev_reset_owner(struct vhost_dev *);
+void vhost_dev_cleanup(struct vhost_dev *);
+long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg);
+int vhost_vq_access_ok(struct vhost_virtqueue *vq);
+int vhost_log_access_ok(struct vhost_dev *);
+
+unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
+ struct iovec iov[], unsigned int iov_count,
+ unsigned int *out_num, unsigned int *in_num,
+ struct vhost_log *log, unsigned int *log_num);
+void vhost_discard_vq_desc(struct vhost_virtqueue *);
+
+int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
+void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
+void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
+ unsigned int head, int len);
+void vhost_disable_notify(struct vhost_virtqueue *);
+bool vhost_enable_notify(struct vhost_virtqueue *);
+
+int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
+ unsigned int log_num, u64 len);
+
+int vhost_init(void);
+void vhost_cleanup(void);
+
+#define vq_err(vq, fmt, ...) do { \
+ pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \
+ if ((vq)->error_ctx) \
+ eventfd_signal((vq)->error_ctx, 1);\
+ } while (0)
+
+enum {
+ VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
+ (1 << VIRTIO_RING_F_INDIRECT_DESC) |
+ (1 << VHOST_F_LOG_ALL) |
+ (1 << VHOST_NET_F_VIRTIO_NET_HDR),
+};
+
+static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
+{
+ unsigned acked_features = rcu_dereference(dev->acked_features);
+ return acked_features & (1 << bit);
+}
+
+#endif
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c
index 0b17824b0eb5..2110556f76b3 100644
--- a/drivers/video/68328fb.c
+++ b/drivers/video/68328fb.c
@@ -308,7 +308,7 @@ static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
* Pseudocolor:
* uses offset = 0 && length = RAMDAC register width.
* var->{color}.offset is 0
- * var->{color}.length contains widht of DAC
+ * var->{color}.length contains width of DAC
* cmap is not used
* RAMDAC[X] is programmed to (red, green, blue)
* Truecolor:
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 5a5c303a6373..dabe804ba575 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -400,9 +400,12 @@ config FB_SA1100
If you plan to use the LCD display with your SA-1100 system, say
Y here.
+config HAVE_FB_IMX
+ bool
+
config FB_IMX
tristate "Motorola i.MX LCD support"
- depends on FB && (ARCH_MX1 || ARCH_MX2)
+ depends on FB && (HAVE_FB_IMX || ARCH_MX1 || ARCH_MX2)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -909,6 +912,18 @@ config FB_XVR2500
mostly initialized the card already. It is treated as a
completely dumb framebuffer device.
+config FB_XVR1000
+ bool "Sun XVR-1000 support"
+ depends on SPARC64
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This is the framebuffer device for the Sun XVR-1000 and similar
+ graphics cards. The driver only works on sparc64 systems where
+ the system firmware has mostly initialized the card already. It
+ is treated as a completely dumb framebuffer device.
+
config FB_PVR2
tristate "NEC PowerVR 2 display support"
depends on FB && SH_DREAMCAST
@@ -1494,7 +1509,6 @@ config FB_VIA
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
- select FB_SOFT_CURSOR
select I2C_ALGOBIT
select I2C
help
@@ -1945,6 +1959,27 @@ config FB_S3C2410_DEBUG
Turn on debugging messages. Note that you can set/unset at run time
through sysfs
+config FB_NUC900
+ bool "NUC900 LCD framebuffer support"
+ depends on FB && ARCH_W90X900
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ Frame buffer driver for the built-in LCD controller in the Nuvoton
+ NUC900 processor
+
+config GPM1040A0_320X240
+ bool "Giantplus Technology GPM1040A0 320x240 Color TFT LCD"
+ depends on FB_NUC900
+
+config FB_NUC900_DEBUG
+ bool "NUC900 lcd debug messages"
+ depends on FB_NUC900
+ help
+ Turn on debugging messages. Note that you can set/unset at run time
+ through sysfs
+
config FB_SM501
tristate "Silicon Motion SM501 framebuffer support"
depends on FB && MFD_SM501
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 4ecb30c4f3f2..ddc2af2ba45b 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -79,6 +79,7 @@ obj-$(CONFIG_FB_N411) += n411.o
obj-$(CONFIG_FB_HGA) += hgafb.o
obj-$(CONFIG_FB_XVR500) += sunxvr500.o
obj-$(CONFIG_FB_XVR2500) += sunxvr2500.o
+obj-$(CONFIG_FB_XVR1000) += sunxvr1000.o
obj-$(CONFIG_FB_IGA) += igafb.o
obj-$(CONFIG_FB_APOLLO) += dnfb.o
obj-$(CONFIG_FB_Q40) += q40fb.o
@@ -129,6 +130,7 @@ obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
obj-$(CONFIG_FB_CARMINE) += carminefb.o
obj-$(CONFIG_FB_MB862XX) += mb862xx/
obj-$(CONFIG_FB_MSM) += msm/
+obj-$(CONFIG_FB_NUC900) += nuc900fb.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
index 0bcc59eb37fa..43d7d5067361 100644
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -1221,7 +1221,7 @@ free_unused_pages(unsigned int virtual_start, unsigned int virtual_end)
printk("acornfb: freed %dK memory\n", mb_freed);
}
-static int __init acornfb_probe(struct platform_device *dev)
+static int __devinit acornfb_probe(struct platform_device *dev)
{
unsigned long size;
u_int h_sync, v_sync;
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index c3431691c9f2..01554d696528 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -504,7 +504,7 @@ static struct fb_ops arcfb_ops = {
.fb_ioctl = arcfb_ioctl,
};
-static int __init arcfb_probe(struct platform_device *dev)
+static int __devinit arcfb_probe(struct platform_device *dev)
{
struct fb_info *info;
int retval = -ENOMEM;
diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c
index 9fe90ce928fb..e70bc225fe31 100644
--- a/drivers/video/asiliantfb.c
+++ b/drivers/video/asiliantfb.c
@@ -140,7 +140,7 @@ static void asiliant_calc_dclk2(u32 *ppixclock, u8 *dclk2_m, u8 *dclk2_n, u8 *dc
/* 3 <= m <= 257 */
if (m >= 3 && m <= 257) {
- unsigned new_error = ((Ftarget * n) - (Fref * m)) >= 0 ?
+ unsigned new_error = Ftarget * n >= Fref * m ?
((Ftarget * n) - (Fref * m)) : ((Fref * m) - (Ftarget * n));
if (new_error < best_error) {
best_n = n;
@@ -152,7 +152,7 @@ static void asiliant_calc_dclk2(u32 *ppixclock, u8 *dclk2_m, u8 *dclk2_n, u8 *dc
else if (m <= 1028) {
/* remember there are still only 8-bits of precision in m, so
* avoid over-optimistic error calculations */
- unsigned new_error = ((Ftarget * n) - (Fref * (m & ~3))) >= 0 ?
+ unsigned new_error = Ftarget * n >= Fref * (m & ~3) ?
((Ftarget * n) - (Fref * (m & ~3))) : ((Fref * (m & ~3)) - (Ftarget * n));
if (new_error < best_error) {
best_n = n;
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index e4e4d433b007..9ee67d6da710 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1931,22 +1931,22 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i
* PowerMac2,2 summer 2000 iMacs
* PowerMac4,1 january 2001 iMacs "flower power"
*/
- if (machine_is_compatible("PowerMac2,1") ||
- machine_is_compatible("PowerMac2,2") ||
- machine_is_compatible("PowerMac4,1"))
+ if (of_machine_is_compatible("PowerMac2,1") ||
+ of_machine_is_compatible("PowerMac2,2") ||
+ of_machine_is_compatible("PowerMac4,1"))
default_vmode = VMODE_1024_768_75;
/* iBook SE */
- if (machine_is_compatible("PowerBook2,2"))
+ if (of_machine_is_compatible("PowerBook2,2"))
default_vmode = VMODE_800_600_60;
/* PowerBook Firewire (Pismo), iBook Dual USB */
- if (machine_is_compatible("PowerBook3,1") ||
- machine_is_compatible("PowerBook4,1"))
+ if (of_machine_is_compatible("PowerBook3,1") ||
+ of_machine_is_compatible("PowerBook4,1"))
default_vmode = VMODE_1024_768_60;
/* PowerBook Titanium */
- if (machine_is_compatible("PowerBook3,2"))
+ if (of_machine_is_compatible("PowerBook3,2"))
default_vmode = VMODE_1152_768_60;
if (default_cmode > 16)
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 1ddeb4c34763..e45ab8db2ddc 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2439,7 +2439,7 @@ static int __devinit aty_init(struct fb_info *info)
* The Apple iBook1 uses non-standard memory frequencies.
* We detect it and set the frequency manually.
*/
- if (machine_is_compatible("PowerBook2,1")) {
+ if (of_machine_is_compatible("PowerBook2,1")) {
par->pll_limits.mclk = 70;
par->pll_limits.xclk = 53;
}
@@ -2659,7 +2659,7 @@ static int __devinit aty_init(struct fb_info *info)
FBINFO_HWACCEL_YPAN;
#ifdef CONFIG_PMAC_BACKLIGHT
- if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) {
+ if (M64_HAS(G3_PB_1_1) && of_machine_is_compatible("PowerBook1,1")) {
/*
* these bits let the 101 powerbook
* wake up from sleep -- paulus
@@ -2690,9 +2690,9 @@ static int __devinit aty_init(struct fb_info *info)
if (M64_HAS(G3_PB_1024x768))
/* G3 PowerBook with 1024x768 LCD */
default_vmode = VMODE_1024_768_60;
- else if (machine_is_compatible("iMac"))
+ else if (of_machine_is_compatible("iMac"))
default_vmode = VMODE_1024_768_75;
- else if (machine_is_compatible("PowerBook2,1"))
+ else if (of_machine_is_compatible("PowerBook2,1"))
/* iBook with 800x600 LCD */
default_vmode = VMODE_800_600_60;
else
@@ -3104,7 +3104,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
}
dp = pci_device_to_OF_node(pdev);
- if (node == dp->node) {
+ if (node == dp->phandle) {
struct fb_var_screeninfo *var = &default_var;
unsigned int N, P, Q, M, T, R;
u32 v_total, h_total;
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 1a056adb61c8..fa1198c4ccc5 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -175,9 +175,9 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo)
#ifdef CONFIG_PMAC_BACKLIGHT
pdata->negative = pdata->negative ||
- machine_is_compatible("PowerBook4,3") ||
- machine_is_compatible("PowerBook6,3") ||
- machine_is_compatible("PowerBook6,5");
+ of_machine_is_compatible("PowerBook4,3") ||
+ of_machine_is_compatible("PowerBook6,3") ||
+ of_machine_is_compatible("PowerBook6,5");
#endif
rinfo->info->bl_dev = bd;
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c
new file mode 100644
index 000000000000..b8f705cca438
--- /dev/null
+++ b/drivers/video/backlight/88pm860x_bl.c
@@ -0,0 +1,304 @@
+/*
+ * Backlight driver for Marvell Semiconductor 88PM8606
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/i2c.h>
+#include <linux/backlight.h>
+#include <linux/mfd/88pm860x.h>
+
+#define MAX_BRIGHTNESS (0xFF)
+#define MIN_BRIGHTNESS (0)
+
+#define CURRENT_MASK (0x1F << 1)
+
+struct pm860x_backlight_data {
+ struct pm860x_chip *chip;
+ struct i2c_client *i2c;
+ int current_brightness;
+ int port;
+ int pwm;
+ int iset;
+};
+
+static inline int wled_a(int port)
+{
+ int ret;
+
+ ret = ((port - PM8606_BACKLIGHT1) << 1) + 2;
+ return ret;
+}
+
+static inline int wled_b(int port)
+{
+ int ret;
+
+ ret = ((port - PM8606_BACKLIGHT1) << 1) + 3;
+ return ret;
+}
+
+/* WLED2 & WLED3 share the same IDC */
+static inline int wled_idc(int port)
+{
+ int ret;
+
+ switch (port) {
+ case PM8606_BACKLIGHT1:
+ case PM8606_BACKLIGHT2:
+ ret = ((port - PM8606_BACKLIGHT1) << 1) + 3;
+ break;
+ case PM8606_BACKLIGHT3:
+ default:
+ ret = ((port - PM8606_BACKLIGHT2) << 1) + 3;
+ break;
+ }
+ return ret;
+}
+
+static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
+{
+ struct pm860x_backlight_data *data = bl_get_data(bl);
+ struct pm860x_chip *chip = data->chip;
+ unsigned char value;
+ int ret;
+
+ if (brightness > MAX_BRIGHTNESS)
+ value = MAX_BRIGHTNESS;
+ else
+ value = brightness;
+
+ ret = pm860x_reg_write(data->i2c, wled_a(data->port), value);
+ if (ret < 0)
+ goto out;
+
+ if ((data->current_brightness == 0) && brightness) {
+ if (data->iset) {
+ ret = pm860x_set_bits(data->i2c, wled_idc(data->port),
+ CURRENT_MASK, data->iset);
+ if (ret < 0)
+ goto out;
+ }
+ if (data->pwm) {
+ ret = pm860x_set_bits(data->i2c, PM8606_PWM,
+ PM8606_PWM_FREQ_MASK, data->pwm);
+ if (ret < 0)
+ goto out;
+ }
+ if (brightness == MAX_BRIGHTNESS) {
+ /* set WLED_ON bit as 100% */
+ ret = pm860x_set_bits(data->i2c, wled_b(data->port),
+ PM8606_WLED_ON, PM8606_WLED_ON);
+ }
+ } else {
+ if (brightness == MAX_BRIGHTNESS) {
+ /* set WLED_ON bit as 100% */
+ ret = pm860x_set_bits(data->i2c, wled_b(data->port),
+ PM8606_WLED_ON, PM8606_WLED_ON);
+ } else {
+ /* clear WLED_ON bit since it's not 100% */
+ ret = pm860x_set_bits(data->i2c, wled_b(data->port),
+ PM8606_WLED_ON, 0);
+ }
+ }
+ if (ret < 0)
+ goto out;
+
+ dev_dbg(chip->dev, "set brightness %d\n", value);
+ data->current_brightness = value;
+ return 0;
+out:
+ dev_dbg(chip->dev, "set brightness %d failure with return "
+ "value:%d\n", value, ret);
+ return ret;
+}
+
+static int pm860x_backlight_update_status(struct backlight_device *bl)
+{
+ int brightness = bl->props.brightness;
+
+ if (bl->props.power != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ if (bl->props.state & BL_CORE_SUSPENDED)
+ brightness = 0;
+
+ return pm860x_backlight_set(bl, brightness);
+}
+
+static int pm860x_backlight_get_brightness(struct backlight_device *bl)
+{
+ struct pm860x_backlight_data *data = bl_get_data(bl);
+ struct pm860x_chip *chip = data->chip;
+ int ret;
+
+ ret = pm860x_reg_read(data->i2c, wled_a(data->port));
+ if (ret < 0)
+ goto out;
+ data->current_brightness = ret;
+ dev_dbg(chip->dev, "get brightness %d\n", data->current_brightness);
+ return data->current_brightness;
+out:
+ return -EINVAL;
+}
+
+static struct backlight_ops pm860x_backlight_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = pm860x_backlight_update_status,
+ .get_brightness = pm860x_backlight_get_brightness,
+};
+
+static int __check_device(struct pm860x_backlight_pdata *pdata, char *name)
+{
+ struct pm860x_backlight_pdata *p = pdata;
+ int ret = -EINVAL;
+
+ while (p && p->id) {
+ if ((p->id != PM8606_ID_BACKLIGHT) || (p->flags < 0))
+ break;
+
+ if (!strncmp(name, pm860x_backlight_name[p->flags],
+ MFD_NAME_SIZE)) {
+ ret = (int)p->flags;
+ break;
+ }
+ p++;
+ }
+ return ret;
+}
+
+static int pm860x_backlight_probe(struct platform_device *pdev)
+{
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm860x_platform_data *pm860x_pdata;
+ struct pm860x_backlight_pdata *pdata = NULL;
+ struct pm860x_backlight_data *data;
+ struct backlight_device *bl;
+ struct resource *res;
+ unsigned char value;
+ char name[MFD_NAME_SIZE];
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "No I/O resource!\n");
+ return -EINVAL;
+ }
+
+ if (pdev->dev.parent->platform_data) {
+ pm860x_pdata = pdev->dev.parent->platform_data;
+ pdata = pm860x_pdata->backlight;
+ }
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "platform data isn't assigned to "
+ "backlight\n");
+ return -EINVAL;
+ }
+
+ data = kzalloc(sizeof(struct pm860x_backlight_data), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+ strncpy(name, res->name, MFD_NAME_SIZE);
+ data->chip = chip;
+ data->i2c = (chip->id == CHIP_PM8606) ? chip->client \
+ : chip->companion;
+ data->current_brightness = MAX_BRIGHTNESS;
+ data->pwm = pdata->pwm;
+ data->iset = pdata->iset;
+ data->port = __check_device(pdata, name);
+ if (data->port < 0) {
+ dev_err(&pdev->dev, "wrong platform data is assigned");
+ return -EINVAL;
+ }
+
+ bl = backlight_device_register(name, &pdev->dev, data,
+ &pm860x_backlight_ops);
+ if (IS_ERR(bl)) {
+ dev_err(&pdev->dev, "failed to register backlight\n");
+ kfree(data);
+ return PTR_ERR(bl);
+ }
+ bl->props.max_brightness = MAX_BRIGHTNESS;
+ bl->props.brightness = MAX_BRIGHTNESS;
+
+ platform_set_drvdata(pdev, bl);
+
+ /* Enable reference VSYS */
+ ret = pm860x_reg_read(data->i2c, PM8606_VSYS);
+ if (ret < 0)
+ goto out;
+ if ((ret & PM8606_VSYS_EN) == 0) {
+ value = ret | PM8606_VSYS_EN;
+ ret = pm860x_reg_write(data->i2c, PM8606_VSYS, value);
+ if (ret < 0)
+ goto out;
+ }
+ /* Enable reference OSC */
+ ret = pm860x_reg_read(data->i2c, PM8606_MISC);
+ if (ret < 0)
+ goto out;
+ if ((ret & PM8606_MISC_OSC_EN) == 0) {
+ value = ret | PM8606_MISC_OSC_EN;
+ ret = pm860x_reg_write(data->i2c, PM8606_MISC, value);
+ if (ret < 0)
+ goto out;
+ }
+ /* read current backlight */
+ ret = pm860x_backlight_get_brightness(bl);
+ if (ret < 0)
+ goto out;
+
+ backlight_update_status(bl);
+ return 0;
+out:
+ kfree(data);
+ return ret;
+}
+
+static int pm860x_backlight_remove(struct platform_device *pdev)
+{
+ struct backlight_device *bl = platform_get_drvdata(pdev);
+ struct pm860x_backlight_data *data = bl_get_data(bl);
+
+ backlight_device_unregister(bl);
+ kfree(data);
+ return 0;
+}
+
+static struct platform_driver pm860x_backlight_driver = {
+ .driver = {
+ .name = "88pm860x-backlight",
+ .owner = THIS_MODULE,
+ },
+ .probe = pm860x_backlight_probe,
+ .remove = pm860x_backlight_remove,
+};
+
+static int __init pm860x_backlight_init(void)
+{
+ return platform_driver_register(&pm860x_backlight_driver);
+}
+module_init(pm860x_backlight_init);
+
+static void __exit pm860x_backlight_exit(void)
+{
+ platform_driver_unregister(&pm860x_backlight_driver);
+}
+module_exit(pm860x_backlight_exit);
+
+MODULE_DESCRIPTION("Backlight Driver for Marvell Semiconductor 88PM8606");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:88pm860x-backlight");
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 09bfa9662e4d..0c77fc610212 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -212,6 +212,13 @@ config BACKLIGHT_DA903X
If you have a LCD backlight connected to the WLED output of DA9030
or DA9034 WLED output, say Y here to enable this driver.
+config BACKLIGHT_MAX8925
+ tristate "Backlight driver for MAX8925"
+ depends on BACKLIGHT_CLASS_DEVICE && MFD_MAX8925
+ help
+ If you have a LCD backlight connected to the WLED output of MAX8925
+ WLED output, say Y here to enable this driver.
+
config BACKLIGHT_MBP_NVIDIA
tristate "MacBook Pro Nvidia Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && X86
@@ -262,3 +269,9 @@ config BACKLIGHT_ADP5520
To compile this driver as a module, choose M here: the module will
be called adp5520_bl.
+config BACKLIGHT_88PM860X
+ tristate "Backlight Driver for 88PM8606 using WLED"
+ depends on BACKLIGHT_CLASS_DEVICE && MFD_88PM860X
+ help
+ Say Y to enable the backlight driver for Marvell 88PM8606.
+
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 9a405548874c..6c704d41462d 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -22,10 +22,12 @@ obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
+obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o
obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o
obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o
obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o
+obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c
new file mode 100644
index 000000000000..c267069a52a3
--- /dev/null
+++ b/drivers/video/backlight/max8925_bl.c
@@ -0,0 +1,200 @@
+/*
+ * Backlight driver for Maxim MAX8925
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/i2c.h>
+#include <linux/backlight.h>
+#include <linux/mfd/max8925.h>
+
+#define MAX_BRIGHTNESS (0xff)
+#define MIN_BRIGHTNESS (0)
+
+#define LWX_FREQ(x) (((x - 601) / 100) & 0x7)
+
+struct max8925_backlight_data {
+ struct max8925_chip *chip;
+
+ int current_brightness;
+};
+
+static int max8925_backlight_set(struct backlight_device *bl, int brightness)
+{
+ struct max8925_backlight_data *data = bl_get_data(bl);
+ struct max8925_chip *chip = data->chip;
+ unsigned char value;
+ int ret;
+
+ if (brightness > MAX_BRIGHTNESS)
+ value = MAX_BRIGHTNESS;
+ else
+ value = brightness;
+
+ ret = max8925_reg_write(chip->i2c, MAX8925_WLED_CNTL, value);
+ if (ret < 0)
+ goto out;
+
+ if (!data->current_brightness && brightness)
+ /* enable WLED output */
+ ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 1);
+ else if (!brightness)
+ /* disable WLED output */
+ ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 0);
+ if (ret < 0)
+ goto out;
+ dev_dbg(chip->dev, "set brightness %d\n", value);
+ data->current_brightness = value;
+ return 0;
+out:
+ dev_dbg(chip->dev, "set brightness %d failure with return value:%d\n",
+ value, ret);
+ return ret;
+}
+
+static int max8925_backlight_update_status(struct backlight_device *bl)
+{
+ int brightness = bl->props.brightness;
+
+ if (bl->props.power != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ if (bl->props.state & BL_CORE_SUSPENDED)
+ brightness = 0;
+
+ return max8925_backlight_set(bl, brightness);
+}
+
+static int max8925_backlight_get_brightness(struct backlight_device *bl)
+{
+ struct max8925_backlight_data *data = bl_get_data(bl);
+ struct max8925_chip *chip = data->chip;
+ int ret;
+
+ ret = max8925_reg_read(chip->i2c, MAX8925_WLED_CNTL);
+ if (ret < 0)
+ return -EINVAL;
+ data->current_brightness = ret;
+ dev_dbg(chip->dev, "get brightness %d\n", data->current_brightness);
+ return ret;
+}
+
+static struct backlight_ops max8925_backlight_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = max8925_backlight_update_status,
+ .get_brightness = max8925_backlight_get_brightness,
+};
+
+static int __devinit max8925_backlight_probe(struct platform_device *pdev)
+{
+ struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct max8925_platform_data *max8925_pdata;
+ struct max8925_backlight_pdata *pdata = NULL;
+ struct max8925_backlight_data *data;
+ struct backlight_device *bl;
+ struct resource *res;
+ char name[MAX8925_NAME_SIZE];
+ unsigned char value;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "No I/O resource!\n");
+ return -EINVAL;
+ }
+
+ if (pdev->dev.parent->platform_data) {
+ max8925_pdata = pdev->dev.parent->platform_data;
+ pdata = max8925_pdata->backlight;
+ }
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "platform data isn't assigned to "
+ "backlight\n");
+ return -EINVAL;
+ }
+
+ data = kzalloc(sizeof(struct max8925_backlight_data), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+ strncpy(name, res->name, MAX8925_NAME_SIZE);
+ data->chip = chip;
+ data->current_brightness = 0;
+
+ bl = backlight_device_register(name, &pdev->dev, data,
+ &max8925_backlight_ops);
+ if (IS_ERR(bl)) {
+ dev_err(&pdev->dev, "failed to register backlight\n");
+ kfree(data);
+ return PTR_ERR(bl);
+ }
+ bl->props.max_brightness = MAX_BRIGHTNESS;
+ bl->props.brightness = MAX_BRIGHTNESS;
+
+ platform_set_drvdata(pdev, bl);
+
+ value = 0;
+ if (pdata->lxw_scl)
+ value |= (1 << 7);
+ if (pdata->lxw_freq)
+ value |= (LWX_FREQ(pdata->lxw_freq) << 4);
+ if (pdata->dual_string)
+ value |= (1 << 1);
+ ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 0xfe, value);
+ if (ret < 0)
+ goto out;
+
+ backlight_update_status(bl);
+ return 0;
+out:
+ kfree(data);
+ return ret;
+}
+
+static int __devexit max8925_backlight_remove(struct platform_device *pdev)
+{
+ struct backlight_device *bl = platform_get_drvdata(pdev);
+ struct max8925_backlight_data *data = bl_get_data(bl);
+
+ backlight_device_unregister(bl);
+ kfree(data);
+ return 0;
+}
+
+static struct platform_driver max8925_backlight_driver = {
+ .driver = {
+ .name = "max8925-backlight",
+ .owner = THIS_MODULE,
+ },
+ .probe = max8925_backlight_probe,
+ .remove = __devexit_p(max8925_backlight_remove),
+};
+
+static int __init max8925_backlight_init(void)
+{
+ return platform_driver_register(&max8925_backlight_driver);
+}
+module_init(max8925_backlight_init);
+
+static void __exit max8925_backlight_exit(void)
+{
+ platform_driver_unregister(&max8925_backlight_driver);
+};
+module_exit(max8925_backlight_exit);
+
+MODULE_DESCRIPTION("Backlight Driver for Maxim MAX8925");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:max8925-backlight");
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index e49ae5edcc00..814312a7452f 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -82,7 +82,6 @@ struct bfin_bf54xfb_info {
unsigned char *fb_buffer; /* RGB Buffer */
dma_addr_t dma_handle;
- int lq043_mmap;
int lq043_open_cnt;
int irq;
spinlock_t lock; /* lock */
@@ -316,7 +315,6 @@ static int bfin_bf54x_fb_release(struct fb_info *info, int user)
spin_lock(&fbi->lock);
fbi->lq043_open_cnt--;
- fbi->lq043_mmap = 0;
if (fbi->lq043_open_cnt <= 0) {
@@ -374,33 +372,6 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var,
return 0;
}
-static int bfin_bf54x_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
-{
-
- struct bfin_bf54xfb_info *fbi = info->par;
-
- if (fbi->lq043_mmap)
- return -1;
-
- spin_lock(&fbi->lock);
- fbi->lq043_mmap = 1;
- spin_unlock(&fbi->lock);
-
- vma->vm_start = (unsigned long)(fbi->fb_buffer);
-
- vma->vm_end = vma->vm_start + info->fix.smem_len;
- /* For those who don't understand how mmap works, go read
- * Documentation/nommu-mmap.txt.
- * For those that do, you will know that the VM_MAYSHARE flag
- * must be set in the vma->vm_flags structure on noMMU
- * Other flags can be set, and are documented in
- * include/linux/mm.h
- */
- vma->vm_flags |= VM_MAYSHARE | VM_SHARED;
-
- return 0;
-}
-
int bfin_bf54x_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
if (nocursor)
@@ -452,7 +423,6 @@ static struct fb_ops bfin_bf54x_fb_ops = {
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
- .fb_mmap = bfin_bf54x_fb_mmap,
.fb_cursor = bfin_bf54x_fb_cursor,
.fb_setcolreg = bfin_bf54x_fb_setcolreg,
};
diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c
index b690c269784a..03872365a36d 100644
--- a/drivers/video/bfin-lq035q1-fb.c
+++ b/drivers/video/bfin-lq035q1-fb.c
@@ -22,7 +22,6 @@
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
-#include <linux/dma-mapping.h>
#include <asm/blackfin.h>
#include <asm/irq.h>
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c
index 2549c53b26a0..5653d083a983 100644
--- a/drivers/video/bfin-t350mcqb-fb.c
+++ b/drivers/video/bfin-t350mcqb-fb.c
@@ -87,7 +87,6 @@ struct bfin_t350mcqbfb_info {
struct device *dev;
unsigned char *fb_buffer; /* RGB Buffer */
dma_addr_t dma_handle;
- int lq043_mmap;
int lq043_open_cnt;
int irq;
spinlock_t lock; /* lock */
@@ -235,7 +234,6 @@ static int bfin_t350mcqb_fb_release(struct fb_info *info, int user)
spin_lock(&fbi->lock);
fbi->lq043_open_cnt--;
- fbi->lq043_mmap = 0;
if (fbi->lq043_open_cnt <= 0) {
bfin_t350mcqb_disable_ppi();
@@ -293,32 +291,6 @@ static int bfin_t350mcqb_fb_check_var(struct fb_var_screeninfo *var,
return 0;
}
-static int bfin_t350mcqb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
-{
- struct bfin_t350mcqbfb_info *fbi = info->par;
-
- if (fbi->lq043_mmap)
- return -1;
-
- spin_lock(&fbi->lock);
- fbi->lq043_mmap = 1;
- spin_unlock(&fbi->lock);
-
- vma->vm_start = (unsigned long)(fbi->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET);
-
- vma->vm_end = vma->vm_start + info->fix.smem_len;
- /* For those who don't understand how mmap works, go read
- * Documentation/nommu-mmap.txt.
- * For those that do, you will know that the VM_MAYSHARE flag
- * must be set in the vma->vm_flags structure on noMMU
- * Other flags can be set, and are documented in
- * include/linux/mm.h
- */
- vma->vm_flags |= VM_MAYSHARE | VM_SHARED;
-
- return 0;
-}
-
int bfin_t350mcqb_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
if (nocursor)
@@ -370,7 +342,6 @@ static struct fb_ops bfin_t350mcqb_fb_ops = {
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
- .fb_mmap = bfin_t350mcqb_fb_mmap,
.fb_cursor = bfin_t350mcqb_fb_cursor,
.fb_setcolreg = bfin_t350mcqb_fb_setcolreg,
};
diff --git a/drivers/video/broadsheetfb.c b/drivers/video/broadsheetfb.c
index df9ccb901d86..ebda6876d3a9 100644
--- a/drivers/video/broadsheetfb.c
+++ b/drivers/video/broadsheetfb.c
@@ -29,11 +29,65 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/list.h>
+#include <linux/firmware.h>
#include <linux/uaccess.h>
#include <video/broadsheetfb.h>
-/* Display specific information */
+/* track panel specific parameters */
+struct panel_info {
+ int w;
+ int h;
+ u16 sdcfg;
+ u16 gdcfg;
+ u16 lutfmt;
+ u16 fsynclen;
+ u16 fendfbegin;
+ u16 lsynclen;
+ u16 lendlbegin;
+ u16 pixclk;
+};
+
+/* table of panel specific parameters to be indexed into by the board drivers */
+static struct panel_info panel_table[] = {
+ { /* standard 6" on TFT backplane */
+ .w = 800,
+ .h = 600,
+ .sdcfg = (100 | (1 << 8) | (1 << 9)),
+ .gdcfg = 2,
+ .lutfmt = (4 | (1 << 7)),
+ .fsynclen = 4,
+ .fendfbegin = (10 << 8) | 4,
+ .lsynclen = 10,
+ .lendlbegin = (100 << 8) | 4,
+ .pixclk = 6,
+ },
+ { /* custom 3.7" flexible on PET or steel */
+ .w = 320,
+ .h = 240,
+ .sdcfg = (67 | (0 << 8) | (0 << 9) | (0 << 10) | (0 << 12)),
+ .gdcfg = 3,
+ .lutfmt = (4 | (1 << 7)),
+ .fsynclen = 0,
+ .fendfbegin = (80 << 8) | 4,
+ .lsynclen = 10,
+ .lendlbegin = (80 << 8) | 20,
+ .pixclk = 14,
+ },
+ { /* standard 9.7" on TFT backplane */
+ .w = 1200,
+ .h = 825,
+ .sdcfg = (100 | (1 << 8) | (1 << 9) | (0 << 10) | (0 << 12)),
+ .gdcfg = 2,
+ .lutfmt = (4 | (1 << 7)),
+ .fsynclen = 0,
+ .fendfbegin = (4 << 8) | 4,
+ .lsynclen = 4,
+ .lendlbegin = (60 << 8) | 10,
+ .pixclk = 3,
+ },
+};
+
#define DPY_W 800
#define DPY_H 600
@@ -62,30 +116,30 @@ static struct fb_var_screeninfo broadsheetfb_var __devinitdata = {
};
/* main broadsheetfb functions */
-static void broadsheet_issue_data(struct broadsheetfb_par *par, u16 data)
+static void broadsheet_gpio_issue_data(struct broadsheetfb_par *par, u16 data)
{
par->board->set_ctl(par, BS_WR, 0);
par->board->set_hdb(par, data);
par->board->set_ctl(par, BS_WR, 1);
}
-static void broadsheet_issue_cmd(struct broadsheetfb_par *par, u16 data)
+static void broadsheet_gpio_issue_cmd(struct broadsheetfb_par *par, u16 data)
{
par->board->set_ctl(par, BS_DC, 0);
- broadsheet_issue_data(par, data);
+ broadsheet_gpio_issue_data(par, data);
}
-static void broadsheet_send_command(struct broadsheetfb_par *par, u16 data)
+static void broadsheet_gpio_send_command(struct broadsheetfb_par *par, u16 data)
{
par->board->wait_for_rdy(par);
par->board->set_ctl(par, BS_CS, 0);
- broadsheet_issue_cmd(par, data);
+ broadsheet_gpio_issue_cmd(par, data);
par->board->set_ctl(par, BS_DC, 1);
par->board->set_ctl(par, BS_CS, 1);
}
-static void broadsheet_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
+static void broadsheet_gpio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
int argc, u16 *argv)
{
int i;
@@ -93,15 +147,43 @@ static void broadsheet_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
par->board->wait_for_rdy(par);
par->board->set_ctl(par, BS_CS, 0);
- broadsheet_issue_cmd(par, cmd);
+ broadsheet_gpio_issue_cmd(par, cmd);
par->board->set_ctl(par, BS_DC, 1);
for (i = 0; i < argc; i++)
- broadsheet_issue_data(par, argv[i]);
+ broadsheet_gpio_issue_data(par, argv[i]);
par->board->set_ctl(par, BS_CS, 1);
}
-static void broadsheet_burst_write(struct broadsheetfb_par *par, int size,
+static void broadsheet_mmio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
+ int argc, u16 *argv)
+{
+ int i;
+
+ par->board->mmio_write(par, BS_MMIO_CMD, cmd);
+
+ for (i = 0; i < argc; i++)
+ par->board->mmio_write(par, BS_MMIO_DATA, argv[i]);
+}
+
+static void broadsheet_send_command(struct broadsheetfb_par *par, u16 data)
+{
+ if (par->board->mmio_write)
+ par->board->mmio_write(par, BS_MMIO_CMD, data);
+ else
+ broadsheet_gpio_send_command(par, data);
+}
+
+static void broadsheet_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
+ int argc, u16 *argv)
+{
+ if (par->board->mmio_write)
+ broadsheet_mmio_send_cmdargs(par, cmd, argc, argv);
+ else
+ broadsheet_gpio_send_cmdargs(par, cmd, argc, argv);
+}
+
+static void broadsheet_gpio_burst_write(struct broadsheetfb_par *par, int size,
u16 *data)
{
int i;
@@ -121,7 +203,30 @@ static void broadsheet_burst_write(struct broadsheetfb_par *par, int size,
par->board->set_ctl(par, BS_CS, 1);
}
-static u16 broadsheet_get_data(struct broadsheetfb_par *par)
+static void broadsheet_mmio_burst_write(struct broadsheetfb_par *par, int size,
+ u16 *data)
+{
+ int i;
+ u16 tmp;
+
+ for (i = 0; i < size; i++) {
+ tmp = (data[i] & 0x0F) << 4;
+ tmp |= (data[i] & 0x0F00) << 4;
+ par->board->mmio_write(par, BS_MMIO_DATA, tmp);
+ }
+
+}
+
+static void broadsheet_burst_write(struct broadsheetfb_par *par, int size,
+ u16 *data)
+{
+ if (par->board->mmio_write)
+ broadsheet_mmio_burst_write(par, size, data);
+ else
+ broadsheet_gpio_burst_write(par, size, data);
+}
+
+static u16 broadsheet_gpio_get_data(struct broadsheetfb_par *par)
{
u16 res;
/* wait for ready to go hi. (lo is busy) */
@@ -141,7 +246,16 @@ static u16 broadsheet_get_data(struct broadsheetfb_par *par)
return res;
}
-static void broadsheet_write_reg(struct broadsheetfb_par *par, u16 reg,
+
+static u16 broadsheet_get_data(struct broadsheetfb_par *par)
+{
+ if (par->board->mmio_read)
+ return par->board->mmio_read(par);
+ else
+ return broadsheet_gpio_get_data(par);
+}
+
+static void broadsheet_gpio_write_reg(struct broadsheetfb_par *par, u16 reg,
u16 data)
{
/* wait for ready to go hi. (lo is busy) */
@@ -150,44 +264,541 @@ static void broadsheet_write_reg(struct broadsheetfb_par *par, u16 reg,
/* cs lo, dc lo for cmd, we lo for each data, db as usual */
par->board->set_ctl(par, BS_CS, 0);
- broadsheet_issue_cmd(par, BS_CMD_WR_REG);
+ broadsheet_gpio_issue_cmd(par, BS_CMD_WR_REG);
par->board->set_ctl(par, BS_DC, 1);
- broadsheet_issue_data(par, reg);
- broadsheet_issue_data(par, data);
+ broadsheet_gpio_issue_data(par, reg);
+ broadsheet_gpio_issue_data(par, data);
par->board->set_ctl(par, BS_CS, 1);
}
+static void broadsheet_mmio_write_reg(struct broadsheetfb_par *par, u16 reg,
+ u16 data)
+{
+ par->board->mmio_write(par, BS_MMIO_CMD, BS_CMD_WR_REG);
+ par->board->mmio_write(par, BS_MMIO_DATA, reg);
+ par->board->mmio_write(par, BS_MMIO_DATA, data);
+
+}
+
+static void broadsheet_write_reg(struct broadsheetfb_par *par, u16 reg,
+ u16 data)
+{
+ if (par->board->mmio_write)
+ broadsheet_mmio_write_reg(par, reg, data);
+ else
+ broadsheet_gpio_write_reg(par, reg, data);
+}
+
+static void broadsheet_write_reg32(struct broadsheetfb_par *par, u16 reg,
+ u32 data)
+{
+ broadsheet_write_reg(par, reg, cpu_to_le32(data) & 0xFFFF);
+ broadsheet_write_reg(par, reg + 2, (cpu_to_le32(data) >> 16) & 0xFFFF);
+}
+
+
static u16 broadsheet_read_reg(struct broadsheetfb_par *par, u16 reg)
{
- broadsheet_send_command(par, reg);
- msleep(100);
+ broadsheet_send_cmdargs(par, BS_CMD_RD_REG, 1, &reg);
+ par->board->wait_for_rdy(par);
return broadsheet_get_data(par);
}
+/* functions for waveform manipulation */
+static int is_broadsheet_pll_locked(struct broadsheetfb_par *par)
+{
+ return broadsheet_read_reg(par, 0x000A) & 0x0001;
+}
+
+static int broadsheet_setup_plls(struct broadsheetfb_par *par)
+{
+ int retry_count = 0;
+ u16 tmp;
+
+ /* disable arral saemipu mode */
+ broadsheet_write_reg(par, 0x0006, 0x0000);
+
+ broadsheet_write_reg(par, 0x0010, 0x0004);
+ broadsheet_write_reg(par, 0x0012, 0x5949);
+ broadsheet_write_reg(par, 0x0014, 0x0040);
+ broadsheet_write_reg(par, 0x0016, 0x0000);
+
+ do {
+ if (retry_count++ > 100)
+ return -ETIMEDOUT;
+ mdelay(1);
+ } while (!is_broadsheet_pll_locked(par));
+
+ tmp = broadsheet_read_reg(par, 0x0006);
+ tmp &= ~0x1;
+ broadsheet_write_reg(par, 0x0006, tmp);
+
+ return 0;
+}
+
+static int broadsheet_setup_spi(struct broadsheetfb_par *par)
+{
+
+ broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1));
+ broadsheet_write_reg(par, 0x0208, 0x0001);
+
+ return 0;
+}
+
+static int broadsheet_setup_spiflash(struct broadsheetfb_par *par,
+ u16 *orig_sfmcd)
+{
+
+ *orig_sfmcd = broadsheet_read_reg(par, 0x0204);
+ broadsheet_write_reg(par, 0x0208, 0);
+ broadsheet_write_reg(par, 0x0204, 0);
+ broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1));
+
+ return 0;
+}
+
+static int broadsheet_spiflash_wait_for_bit(struct broadsheetfb_par *par,
+ u16 reg, int bitnum, int val,
+ int timeout)
+{
+ u16 tmp;
+
+ do {
+ tmp = broadsheet_read_reg(par, reg);
+ if (((tmp >> bitnum) & 1) == val)
+ return 0;
+ mdelay(1);
+ } while (timeout--);
+
+ return -ETIMEDOUT;
+}
+
+static int broadsheet_spiflash_write_byte(struct broadsheetfb_par *par, u8 data)
+{
+ broadsheet_write_reg(par, 0x0202, (data | 0x100));
+
+ return broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100);
+}
+
+static int broadsheet_spiflash_read_byte(struct broadsheetfb_par *par, u8 *data)
+{
+ int err;
+ u16 tmp;
+
+ broadsheet_write_reg(par, 0x0202, 0);
+
+ err = broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100);
+ if (err)
+ return err;
+
+ tmp = broadsheet_read_reg(par, 0x200);
+
+ *data = tmp & 0xFF;
+
+ return 0;
+}
+
+static int broadsheet_spiflash_wait_for_status(struct broadsheetfb_par *par,
+ int timeout)
+{
+ u8 tmp;
+ int err;
+
+ do {
+ broadsheet_write_reg(par, 0x0208, 1);
+
+ err = broadsheet_spiflash_write_byte(par, 0x05);
+ if (err)
+ goto failout;
+
+ err = broadsheet_spiflash_read_byte(par, &tmp);
+ if (err)
+ goto failout;
+
+ broadsheet_write_reg(par, 0x0208, 0);
+
+ if (!(tmp & 0x1))
+ return 0;
+
+ mdelay(5);
+ } while (timeout--);
+
+ dev_err(par->info->device, "Timed out waiting for spiflash status\n");
+ return -ETIMEDOUT;
+
+failout:
+ broadsheet_write_reg(par, 0x0208, 0);
+ return err;
+}
+
+static int broadsheet_spiflash_op_on_address(struct broadsheetfb_par *par,
+ u8 op, u32 addr)
+{
+ int i;
+ u8 tmp;
+ int err;
+
+ broadsheet_write_reg(par, 0x0208, 1);
+
+ err = broadsheet_spiflash_write_byte(par, op);
+ if (err)
+ return err;
+
+ for (i = 2; i >= 0; i--) {
+ tmp = ((addr >> (i * 8)) & 0xFF);
+ err = broadsheet_spiflash_write_byte(par, tmp);
+ if (err)
+ return err;
+ }
+
+ return err;
+}
+
+static int broadsheet_verify_spiflash(struct broadsheetfb_par *par,
+ int *flash_type)
+{
+ int err = 0;
+ u8 sig;
+
+ err = broadsheet_spiflash_op_on_address(par, 0xAB, 0x00000000);
+ if (err)
+ goto failout;
+
+ err = broadsheet_spiflash_read_byte(par, &sig);
+ if (err)
+ goto failout;
+
+ if ((sig != 0x10) && (sig != 0x11)) {
+ dev_err(par->info->device, "Unexpected flash type\n");
+ err = -EINVAL;
+ goto failout;
+ }
+
+ *flash_type = sig;
+
+failout:
+ broadsheet_write_reg(par, 0x0208, 0);
+ return err;
+}
+
+static int broadsheet_setup_for_wfm_write(struct broadsheetfb_par *par,
+ u16 *initial_sfmcd, int *flash_type)
+
+{
+ int err;
+
+ err = broadsheet_setup_plls(par);
+ if (err)
+ return err;
+
+ broadsheet_write_reg(par, 0x0106, 0x0203);
+
+ err = broadsheet_setup_spi(par);
+ if (err)
+ return err;
+
+ err = broadsheet_setup_spiflash(par, initial_sfmcd);
+ if (err)
+ return err;
+
+ return broadsheet_verify_spiflash(par, flash_type);
+}
+
+static int broadsheet_spiflash_write_control(struct broadsheetfb_par *par,
+ int mode)
+{
+ int err;
+
+ broadsheet_write_reg(par, 0x0208, 1);
+ if (mode)
+ err = broadsheet_spiflash_write_byte(par, 0x06);
+ else
+ err = broadsheet_spiflash_write_byte(par, 0x04);
+
+ broadsheet_write_reg(par, 0x0208, 0);
+ return err;
+}
+
+static int broadsheet_spiflash_erase_sector(struct broadsheetfb_par *par,
+ int addr)
+{
+ int err;
+
+ broadsheet_spiflash_write_control(par, 1);
+
+ err = broadsheet_spiflash_op_on_address(par, 0xD8, addr);
+
+ broadsheet_write_reg(par, 0x0208, 0);
+
+ if (err)
+ return err;
+
+ err = broadsheet_spiflash_wait_for_status(par, 1000);
+
+ return err;
+}
+
+static int broadsheet_spiflash_read_range(struct broadsheetfb_par *par,
+ int addr, int size, char *data)
+{
+ int err;
+ int i;
+
+ err = broadsheet_spiflash_op_on_address(par, 0x03, addr);
+ if (err)
+ goto failout;
+
+ for (i = 0; i < size; i++) {
+ err = broadsheet_spiflash_read_byte(par, &data[i]);
+ if (err)
+ goto failout;
+ }
+
+failout:
+ broadsheet_write_reg(par, 0x0208, 0);
+ return err;
+}
+
+#define BS_SPIFLASH_PAGE_SIZE 256
+static int broadsheet_spiflash_write_page(struct broadsheetfb_par *par,
+ int addr, const char *data)
+{
+ int err;
+ int i;
+
+ broadsheet_spiflash_write_control(par, 1);
+
+ err = broadsheet_spiflash_op_on_address(par, 0x02, addr);
+ if (err)
+ goto failout;
+
+ for (i = 0; i < BS_SPIFLASH_PAGE_SIZE; i++) {
+ err = broadsheet_spiflash_write_byte(par, data[i]);
+ if (err)
+ goto failout;
+ }
+
+ broadsheet_write_reg(par, 0x0208, 0);
+
+ err = broadsheet_spiflash_wait_for_status(par, 100);
+
+failout:
+ return err;
+}
+
+static int broadsheet_spiflash_write_sector(struct broadsheetfb_par *par,
+ int addr, const char *data, int sector_size)
+{
+ int i;
+ int err;
+
+ for (i = 0; i < sector_size; i += BS_SPIFLASH_PAGE_SIZE) {
+ err = broadsheet_spiflash_write_page(par, addr + i, &data[i]);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+/*
+ * The caller must guarantee that the data to be rewritten is entirely
+ * contained within this sector. That is, data_start_addr + data_len
+ * must be less than sector_start_addr + sector_size.
+ */
+static int broadsheet_spiflash_rewrite_sector(struct broadsheetfb_par *par,
+ int sector_size, int data_start_addr,
+ int data_len, const char *data)
+{
+ int err;
+ char *sector_buffer;
+ int tail_start_addr;
+ int start_sector_addr;
+
+ sector_buffer = kzalloc(sizeof(char)*sector_size, GFP_KERNEL);
+ if (!sector_buffer)
+ return -ENOMEM;
+
+ /* the start address of the sector is the 0th byte of that sector */
+ start_sector_addr = (data_start_addr / sector_size) * sector_size;
+
+ /*
+ * check if there is head data that we need to readback into our sector
+ * buffer first
+ */
+ if (data_start_addr != start_sector_addr) {
+ /*
+ * we need to read every byte up till the start address of our
+ * data and we put it into our sector buffer.
+ */
+ err = broadsheet_spiflash_read_range(par, start_sector_addr,
+ data_start_addr, sector_buffer);
+ if (err)
+ return err;
+ }
+
+ /* now we copy our data into the right place in the sector buffer */
+ memcpy(sector_buffer + data_start_addr, data, data_len);
+
+ /*
+ * now we check if there is a tail section of the sector that we need to
+ * readback.
+ */
+ tail_start_addr = (data_start_addr + data_len) % sector_size;
+
+ if (tail_start_addr) {
+ int tail_len;
+
+ tail_len = sector_size - tail_start_addr;
+
+ /* now we read this tail into our sector buffer */
+ err = broadsheet_spiflash_read_range(par, tail_start_addr,
+ tail_len, sector_buffer + tail_start_addr);
+ if (err)
+ return err;
+ }
+
+ /* if we got here we have the full sector that we want to rewrite. */
+
+ /* first erase the sector */
+ err = broadsheet_spiflash_erase_sector(par, start_sector_addr);
+ if (err)
+ return err;
+
+ /* now write it */
+ err = broadsheet_spiflash_write_sector(par, start_sector_addr,
+ sector_buffer, sector_size);
+ return err;
+}
+
+static int broadsheet_write_spiflash(struct broadsheetfb_par *par, u32 wfm_addr,
+ const u8 *wfm, int bytecount, int flash_type)
+{
+ int sector_size;
+ int err;
+ int cur_addr;
+ int writecount;
+ int maxlen;
+ int offset = 0;
+
+ switch (flash_type) {
+ case 0x10:
+ sector_size = 32*1024;
+ break;
+ case 0x11:
+ default:
+ sector_size = 64*1024;
+ break;
+ }
+
+ while (bytecount) {
+ cur_addr = wfm_addr + offset;
+ maxlen = roundup(cur_addr, sector_size) - cur_addr;
+ writecount = min(bytecount, maxlen);
+
+ err = broadsheet_spiflash_rewrite_sector(par, sector_size,
+ cur_addr, writecount, wfm + offset);
+ if (err)
+ return err;
+
+ offset += writecount;
+ bytecount -= writecount;
+ }
+
+ return 0;
+}
+
+static int broadsheet_store_waveform_to_spiflash(struct broadsheetfb_par *par,
+ const u8 *wfm, size_t wfm_size)
+{
+ int err = 0;
+ u16 initial_sfmcd = 0;
+ int flash_type = 0;
+
+ err = broadsheet_setup_for_wfm_write(par, &initial_sfmcd, &flash_type);
+ if (err)
+ goto failout;
+
+ err = broadsheet_write_spiflash(par, 0x886, wfm, wfm_size, flash_type);
+
+failout:
+ broadsheet_write_reg(par, 0x0204, initial_sfmcd);
+ return err;
+}
+
+static ssize_t broadsheet_loadstore_waveform(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ int err;
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct broadsheetfb_par *par = info->par;
+ const struct firmware *fw_entry;
+
+ if (len < 1)
+ return -EINVAL;
+
+ err = request_firmware(&fw_entry, "broadsheet.wbf", dev);
+ if (err < 0) {
+ dev_err(dev, "Failed to get broadsheet waveform\n");
+ goto err_failed;
+ }
+
+ /* try to enforce reasonable min max on waveform */
+ if ((fw_entry->size < 8*1024) || (fw_entry->size > 64*1024)) {
+ dev_err(dev, "Invalid waveform\n");
+ err = -EINVAL;
+ goto err_failed;
+ }
+
+ mutex_lock(&(par->io_lock));
+ err = broadsheet_store_waveform_to_spiflash(par, fw_entry->data,
+ fw_entry->size);
+
+ mutex_unlock(&(par->io_lock));
+ if (err < 0) {
+ dev_err(dev, "Failed to store broadsheet waveform\n");
+ goto err_failed;
+ }
+
+ dev_info(dev, "Stored broadsheet waveform, size %zd\n", fw_entry->size);
+
+ return len;
+
+err_failed:
+ return err;
+}
+static DEVICE_ATTR(loadstore_waveform, S_IWUSR, NULL,
+ broadsheet_loadstore_waveform);
+
+/* upper level functions that manipulate the display and other stuff */
static void __devinit broadsheet_init_display(struct broadsheetfb_par *par)
{
u16 args[5];
-
- args[0] = DPY_W;
- args[1] = DPY_H;
- args[2] = (100 | (1 << 8) | (1 << 9)); /* sdcfg */
- args[3] = 2; /* gdrv cfg */
- args[4] = (4 | (1 << 7)); /* lut index format */
+ int xres = par->info->var.xres;
+ int yres = par->info->var.yres;
+
+ args[0] = panel_table[par->panel_index].w;
+ args[1] = panel_table[par->panel_index].h;
+ args[2] = panel_table[par->panel_index].sdcfg;
+ args[3] = panel_table[par->panel_index].gdcfg;
+ args[4] = panel_table[par->panel_index].lutfmt;
broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args);
/* did the controller really set it? */
broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args);
- args[0] = 4; /* fsync len */
- args[1] = (10 << 8) | 4; /* fend/fbegin len */
- args[2] = 10; /* line sync len */
- args[3] = (100 << 8) | 4; /* line end/begin len */
- args[4] = 6; /* pixel clock cfg */
+ args[0] = panel_table[par->panel_index].fsynclen;
+ args[1] = panel_table[par->panel_index].fendfbegin;
+ args[2] = panel_table[par->panel_index].lsynclen;
+ args[3] = panel_table[par->panel_index].lendlbegin;
+ args[4] = panel_table[par->panel_index].pixclk;
broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_TMG, 5, args);
+ broadsheet_write_reg32(par, 0x310, xres*yres*2);
+
/* setup waveform */
args[0] = 0x886;
args[1] = 0;
@@ -207,8 +818,9 @@ static void __devinit broadsheet_init_display(struct broadsheetfb_par *par)
args[0] = 0x154;
broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
- broadsheet_burst_write(par, DPY_W*DPY_H/2,
- (u16 *) par->info->screen_base);
+ broadsheet_burst_write(par, (panel_table[par->panel_index].w *
+ panel_table[par->panel_index].h)/2,
+ (u16 *) par->info->screen_base);
broadsheet_send_command(par, BS_CMD_LD_IMG_END);
@@ -222,6 +834,21 @@ static void __devinit broadsheet_init_display(struct broadsheetfb_par *par)
par->board->wait_for_rdy(par);
}
+static void __devinit broadsheet_identify(struct broadsheetfb_par *par)
+{
+ u16 rev, prc;
+ struct device *dev = par->info->device;
+
+ rev = broadsheet_read_reg(par, BS_REG_REV);
+ prc = broadsheet_read_reg(par, BS_REG_PRC);
+ dev_info(dev, "Broadsheet Rev 0x%x, Product Code 0x%x\n", rev, prc);
+
+ if (prc != 0x0047)
+ dev_warn(dev, "Unrecognized Broadsheet Product Code\n");
+ if (rev != 0x0100)
+ dev_warn(dev, "Unrecognized Broadsheet Revision\n");
+}
+
static void __devinit broadsheet_init(struct broadsheetfb_par *par)
{
broadsheet_send_command(par, BS_CMD_INIT_SYS_RUN);
@@ -236,6 +863,7 @@ static void broadsheetfb_dpy_update_pages(struct broadsheetfb_par *par,
u16 args[5];
unsigned char *buf = (unsigned char *)par->info->screen_base;
+ mutex_lock(&(par->io_lock));
/* y1 must be a multiple of 4 so drop the lower bits */
y1 &= 0xFFFC;
/* y2 must be a multiple of 4 , but - 1 so up the lower bits */
@@ -265,6 +893,7 @@ static void broadsheetfb_dpy_update_pages(struct broadsheetfb_par *par,
broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
par->board->wait_for_rdy(par);
+ mutex_unlock(&(par->io_lock));
}
@@ -272,13 +901,15 @@ static void broadsheetfb_dpy_update(struct broadsheetfb_par *par)
{
u16 args[5];
+ mutex_lock(&(par->io_lock));
args[0] = 0x3 << 4;
broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args);
args[0] = 0x154;
broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
- broadsheet_burst_write(par, DPY_W*DPY_H/2,
- (u16 *) par->info->screen_base);
+ broadsheet_burst_write(par, (panel_table[par->panel_index].w *
+ panel_table[par->panel_index].h)/2,
+ (u16 *) par->info->screen_base);
broadsheet_send_command(par, BS_CMD_LD_IMG_END);
@@ -290,7 +921,7 @@ static void broadsheetfb_dpy_update(struct broadsheetfb_par *par)
broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
par->board->wait_for_rdy(par);
-
+ mutex_unlock(&(par->io_lock));
}
/* this is called back from the deferred io workqueue */
@@ -436,6 +1067,8 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev)
unsigned char *videomemory;
struct broadsheetfb_par *par;
int i;
+ int dpyw, dpyh;
+ int panel_index;
/* pick up board specific routines */
board = dev->dev.platform_data;
@@ -450,7 +1083,24 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev)
if (!info)
goto err;
- videomemorysize = (DPY_W*DPY_H);
+ switch (board->get_panel_type()) {
+ case 37:
+ panel_index = 1;
+ break;
+ case 97:
+ panel_index = 2;
+ break;
+ case 6:
+ default:
+ panel_index = 0;
+ break;
+ }
+
+ dpyw = panel_table[panel_index].w;
+ dpyh = panel_table[panel_index].h;
+
+ videomemorysize = roundup((dpyw*dpyh), PAGE_SIZE);
+
videomemory = vmalloc(videomemorysize);
if (!videomemory)
goto err_fb_rel;
@@ -460,16 +1110,25 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev)
info->screen_base = (char *)videomemory;
info->fbops = &broadsheetfb_ops;
+ broadsheetfb_var.xres = dpyw;
+ broadsheetfb_var.yres = dpyh;
+ broadsheetfb_var.xres_virtual = dpyw;
+ broadsheetfb_var.yres_virtual = dpyh;
info->var = broadsheetfb_var;
+
+ broadsheetfb_fix.line_length = dpyw;
info->fix = broadsheetfb_fix;
info->fix.smem_len = videomemorysize;
par = info->par;
+ par->panel_index = panel_index;
par->info = info;
par->board = board;
par->write_reg = broadsheet_write_reg;
par->read_reg = broadsheet_read_reg;
init_waitqueue_head(&par->waitq);
+ mutex_init(&par->io_lock);
+
info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
info->fbdefio = &broadsheetfb_defio;
@@ -496,13 +1155,20 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev)
if (retval < 0)
goto err_free_irq;
+ broadsheet_identify(par);
+
broadsheet_init(par);
retval = register_framebuffer(info);
if (retval < 0)
goto err_free_irq;
+
platform_set_drvdata(dev, info);
+ retval = device_create_file(&dev->dev, &dev_attr_loadstore_waveform);
+ if (retval < 0)
+ goto err_unreg_fb;
+
printk(KERN_INFO
"fb%d: Broadsheet frame buffer, using %dK of video memory\n",
info->node, videomemorysize >> 10);
@@ -510,6 +1176,8 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev)
return 0;
+err_unreg_fb:
+ unregister_framebuffer(info);
err_free_irq:
board->cleanup(par);
err_cmap:
@@ -530,6 +1198,8 @@ static int __devexit broadsheetfb_remove(struct platform_device *dev)
if (info) {
struct broadsheetfb_par *par = info->par;
+
+ device_remove_file(info->dev, &dev_attr_loadstore_waveform);
unregister_framebuffer(info);
fb_deferred_io_cleanup(info);
par->board->cleanup(par);
diff --git a/drivers/video/cobalt_lcdfb.c b/drivers/video/cobalt_lcdfb.c
index 108b89e09a80..5eb61b5adfe8 100644
--- a/drivers/video/cobalt_lcdfb.c
+++ b/drivers/video/cobalt_lcdfb.c
@@ -287,7 +287,7 @@ static struct fb_ops cobalt_lcd_fbops = {
.fb_cursor = cobalt_lcdfb_cursor,
};
-static int __init cobalt_lcdfb_probe(struct platform_device *dev)
+static int __devinit cobalt_lcdfb_probe(struct platform_device *dev)
{
struct fb_info *info;
struct resource *res;
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index fc7d9bbb548c..8e8f18d29d7a 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -37,6 +37,7 @@ config VGACON_SOFT_SCROLLBACK
config VGACON_SOFT_SCROLLBACK_SIZE
int "Scrollback Buffer Size (in KB)"
depends on VGACON_SOFT_SCROLLBACK
+ range 1 1024
default "64"
help
Enter the amount of System RAM to allocate for the scrollback
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 3681c6a88212..b0a3fa00706d 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -3025,6 +3025,20 @@ static int fbcon_fb_unregistered(struct fb_info *info)
return 0;
}
+static void fbcon_remap_all(int idx)
+{
+ int i;
+ for (i = first_fb_vc; i <= last_fb_vc; i++)
+ set_con2fb_map(i, idx, 0);
+
+ if (con_is_bound(&fb_con)) {
+ printk(KERN_INFO "fbcon: Remapping primary device, "
+ "fb%i, to tty %i-%i\n", idx,
+ first_fb_vc + 1, last_fb_vc + 1);
+ info_idx = idx;
+ }
+}
+
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
static void fbcon_select_primary(struct fb_info *info)
{
@@ -3225,6 +3239,10 @@ static int fbcon_event_notify(struct notifier_block *self,
caps = event->data;
fbcon_get_requirement(info, caps);
break;
+ case FB_EVENT_REMAP_ALL_CONSOLE:
+ idx = info->node;
+ fbcon_remap_all(idx);
+ break;
}
done:
return ret;
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index cc4bbbe44aca..182dd6f8aadd 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -112,7 +112,7 @@ static int vga_video_font_height;
static int vga_scan_lines __read_mostly;
static unsigned int vga_rolled_over;
-int vgacon_text_mode_force = 0;
+static int vgacon_text_mode_force;
bool vgacon_text_force(void)
{
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index eb12182b2059..581d2dbf675a 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -161,8 +161,17 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
return 0;
}
+static void efifb_destroy(struct fb_info *info)
+{
+ if (info->screen_base)
+ iounmap(info->screen_base);
+ release_mem_region(info->aperture_base, info->aperture_size);
+ framebuffer_release(info);
+}
+
static struct fb_ops efifb_ops = {
.owner = THIS_MODULE,
+ .fb_destroy = efifb_destroy,
.fb_setcolreg = efifb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
@@ -201,7 +210,7 @@ static int __init efifb_setup(char *options)
return 0;
}
-static int __init efifb_probe(struct platform_device *dev)
+static int __devinit efifb_probe(struct platform_device *dev)
{
struct fb_info *info;
int err;
@@ -281,7 +290,7 @@ static int __init efifb_probe(struct platform_device *dev)
info->par = NULL;
info->aperture_base = efifb_fix.smem_start;
- info->aperture_size = size_total;
+ info->aperture_size = size_remap;
info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
if (!info->screen_base) {
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
index 2735b79e52a1..6d755bb3a2bc 100644
--- a/drivers/video/epson1355fb.c
+++ b/drivers/video/epson1355fb.c
@@ -602,7 +602,7 @@ static int epson1355fb_remove(struct platform_device *dev)
return 0;
}
-int __init epson1355fb_probe(struct platform_device *dev)
+int __devinit epson1355fb_probe(struct platform_device *dev)
{
struct epson1355_par *default_par;
struct fb_info *info;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 99bbd282ce63..a15b44e9c003 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1513,7 +1513,6 @@ register_framebuffer(struct fb_info *fb_info)
fb_info->fix.id,
registered_fb[i]->fix.id);
unregister_framebuffer(registered_fb[i]);
- break;
}
}
}
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 72d68b3dc478..4637bcbe03a4 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1633,6 +1633,11 @@ static int __init fsl_diu_setup(char *options)
#endif
static struct of_device_id fsl_diu_match[] = {
+#ifdef CONFIG_PPC_MPC512x
+ {
+ .compatible = "fsl,mpc5121-diu",
+ },
+#endif
{
.compatible = "fsl,diu",
},
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index 695fa013fe7e..5643a35c1746 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -1128,7 +1128,7 @@ static int __init gbefb_setup(char *options)
return 0;
}
-static int __init gbefb_probe(struct platform_device *p_dev)
+static int __devinit gbefb_probe(struct platform_device *p_dev)
{
int i, ret = 0;
struct fb_info *info;
diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c
index 0129c044f6d6..db9b785b56eb 100644
--- a/drivers/video/hgafb.c
+++ b/drivers/video/hgafb.c
@@ -551,7 +551,7 @@ static struct fb_ops hgafb_ops = {
* Initialization
*/
-static int __init hgafb_probe(struct platform_device *pdev)
+static int __devinit hgafb_probe(struct platform_device *pdev)
{
struct fb_info *info;
diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c
index 73c83a8de2d3..bf78779199c6 100644
--- a/drivers/video/hitfb.c
+++ b/drivers/video/hitfb.c
@@ -325,7 +325,7 @@ static struct fb_ops hitfb_ops = {
.fb_imageblit = cfb_imageblit,
};
-static int __init hitfb_probe(struct platform_device *dev)
+static int __devinit hitfb_probe(struct platform_device *dev)
{
unsigned short lcdclor, ldr3, ldvndr;
struct fb_info *info;
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index 66358fa825f3..b4b6deceed15 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -593,7 +593,8 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
*/
static int imxfb_suspend(struct platform_device *dev, pm_message_t state)
{
- struct imxfb_info *fbi = platform_get_drvdata(dev);
+ struct fb_info *info = platform_get_drvdata(dev);
+ struct imxfb_info *fbi = info->par;
pr_debug("%s\n", __func__);
@@ -603,7 +604,8 @@ static int imxfb_suspend(struct platform_device *dev, pm_message_t state)
static int imxfb_resume(struct platform_device *dev)
{
- struct imxfb_info *fbi = platform_get_drvdata(dev);
+ struct fb_info *info = platform_get_drvdata(dev);
+ struct imxfb_info *fbi = info->par;
pr_debug("%s\n", __func__);
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
index d66887e8cbb1..43207cc6cc19 100644
--- a/drivers/video/macfb.c
+++ b/drivers/video/macfb.c
@@ -1,29 +1,33 @@
-/* macfb.c: Generic framebuffer for Macs whose colourmaps/modes we
- don't know how to set */
-
-/* (c) 1999 David Huggins-Daines <dhd@debian.org>
-
- Primarily based on vesafb.c, by Gerd Knorr
- (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
-
- Also uses information and code from:
-
- The original macfb.c from Linux/mac68k 2.0, by Alan Cox, Juergen
- Mellinger, Mikael Forselius, Michael Schmitz, and others.
-
- valkyriefb.c, by Martin Costabel, Kevin Schoedel, Barry Nathan, Dan
- Jacobowitz, Paul Mackerras, Fabio Riccardi, and Geert Uytterhoeven.
-
- This code is free software. You may copy, modify, and distribute
- it subject to the terms and conditions of the GNU General Public
- License, version 2, or any later version, at your convenience. */
+/*
+ * macfb.c: Generic framebuffer for Macs whose colourmaps/modes we
+ * don't know how to set.
+ *
+ * (c) 1999 David Huggins-Daines <dhd@debian.org>
+ *
+ * Primarily based on vesafb.c, by Gerd Knorr
+ * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * Also uses information and code from:
+ *
+ * The original macfb.c from Linux/mac68k 2.0, by Alan Cox, Juergen
+ * Mellinger, Mikael Forselius, Michael Schmitz, and others.
+ *
+ * valkyriefb.c, by Martin Costabel, Kevin Schoedel, Barry Nathan, Dan
+ * Jacobowitz, Paul Mackerras, Fabio Riccardi, and Geert Uytterhoeven.
+ *
+ * The VideoToolbox "Bugs" web page at
+ * http://rajsky.psych.nyu.edu/Tips/VideoBugs.html
+ *
+ * This code is free software. You may copy, modify, and distribute
+ * it subject to the terms and conditions of the GNU General Public
+ * License, version 2, or any later version, at your convenience.
+ */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/nubus.h>
#include <linux/init.h>
@@ -31,9 +35,6 @@
#include <asm/setup.h>
#include <asm/bootinfo.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
#include <asm/macintosh.h>
#include <asm/io.h>
@@ -44,7 +45,7 @@
#define DAFB_BASE 0xf9800200
/* Address for the built-in Civic framebuffer in Quadra AVs */
-#define CIVIC_BASE 0x50f30800 /* Only tested on 660AV! */
+#define CIVIC_BASE 0x50f30800
/* GSC (Gray Scale Controller) base address */
#define GSC_BASE 0x50F20000
@@ -52,37 +53,9 @@
/* CSC (Color Screen Controller) base address */
#define CSC_BASE 0x50F20000
-static int (*macfb_setpalette) (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info) = NULL;
-static int valkyrie_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info);
-static int dafb_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *fb_info);
-static int rbv_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *fb_info);
-static int mdc_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *fb_info);
-static int toby_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *fb_info);
-static int civic_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *fb_info);
-static int csc_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *fb_info);
-
-static struct {
- unsigned char addr;
- /* Note: word-aligned */
- char pad[3];
- unsigned char lut;
-} __iomem *valkyrie_cmap_regs;
+static int (*macfb_setpalette)(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ struct fb_info *info);
static struct {
unsigned char addr;
@@ -116,15 +89,15 @@ static struct {
} __iomem *civic_cmap_regs;
static struct {
- char pad1[0x40];
- unsigned char clut_waddr; /* 0x40 */
- char pad2;
- unsigned char clut_data; /* 0x42 */
- char pad3[0x3];
- unsigned char clut_raddr; /* 0x46 */
+ char pad1[0x40];
+ unsigned char clut_waddr; /* 0x40 */
+ char pad2;
+ unsigned char clut_data; /* 0x42 */
+ char pad3[0x3];
+ unsigned char clut_raddr; /* 0x46 */
} __iomem *csc_cmap_regs;
-/* We will leave these the way they are for the time being */
+/* The registers in these structs are in NuBus slot space */
struct mdc_cmap_regs {
char pad1[0x200200];
unsigned char addr;
@@ -145,13 +118,10 @@ struct jet_cmap_regs {
unsigned char lut;
};
-#define PIXEL_TO_MM(a) (((a)*10)/28) /* width in mm at 72 dpi */
-
-/* mode */
-static int video_slot = 0;
+#define PIXEL_TO_MM(a) (((a)*10)/28) /* width in mm at 72 dpi */
static struct fb_var_screeninfo macfb_defined = {
- .bits_per_pixel = 8,
+ .bits_per_pixel = 8,
.activate = FB_ACTIVATE_NOW,
.width = -1,
.height = -1,
@@ -167,181 +137,152 @@ static struct fb_fix_screeninfo macfb_fix = {
.accel = FB_ACCEL_NONE,
};
+static void *slot_addr;
static struct fb_info fb_info;
static u32 pseudo_palette[16];
-static int inverse = 0;
-static int vidtest = 0;
+static int inverse;
+static int vidtest;
-static int valkyrie_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info)
-{
- unsigned long flags;
-
- red >>= 8;
- green >>= 8;
- blue >>= 8;
-
- local_irq_save(flags);
-
- /* tell clut which address to fill */
- nubus_writeb(regno, &valkyrie_cmap_regs->addr);
- nop();
-
- /* send one color channel at a time */
- nubus_writeb(red, &valkyrie_cmap_regs->lut);
- nop();
- nubus_writeb(green, &valkyrie_cmap_regs->lut);
- nop();
- nubus_writeb(blue, &valkyrie_cmap_regs->lut);
-
- local_irq_restore(flags);
- return 0;
-}
-
-/* Unlike the Valkyrie, the DAFB cannot set individual colormap
- registers. Therefore, we do what the MacOS driver does (no
- kidding!) and simply set them one by one until we hit the one we
- want. */
-static int dafb_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info)
+/*
+ * Unlike the Valkyrie, the DAFB cannot set individual colormap
+ * registers. Therefore, we do what the MacOS driver does (no
+ * kidding!) and simply set them one by one until we hit the one we
+ * want.
+ */
+static int dafb_setpalette(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ struct fb_info *info)
{
- /* FIXME: really, really need to use ioremap() here,
- phys_to_virt() doesn't work anymore */
static int lastreg = -1;
unsigned long flags;
-
- red >>= 8;
- green >>= 8;
- blue >>= 8;
local_irq_save(flags);
-
- /* fbdev will set an entire colourmap, but X won't. Hopefully
- this should accommodate both of them */
- if (regno != lastreg+1) {
+
+ /*
+ * fbdev will set an entire colourmap, but X won't. Hopefully
+ * this should accommodate both of them
+ */
+ if (regno != lastreg + 1) {
int i;
-
+
/* Stab in the dark trying to reset the CLUT pointer */
nubus_writel(0, &dafb_cmap_regs->reset);
nop();
-
+
/* Loop until we get to the register we want */
for (i = 0; i < regno; i++) {
- nubus_writeb(info->cmap.red[i] >> 8, &dafb_cmap_regs->lut);
+ nubus_writeb(info->cmap.red[i] >> 8,
+ &dafb_cmap_regs->lut);
nop();
- nubus_writeb(info->cmap.green[i] >> 8, &dafb_cmap_regs->lut);
+ nubus_writeb(info->cmap.green[i] >> 8,
+ &dafb_cmap_regs->lut);
nop();
- nubus_writeb(info->cmap.blue[i] >> 8, &dafb_cmap_regs->lut);
+ nubus_writeb(info->cmap.blue[i] >> 8,
+ &dafb_cmap_regs->lut);
nop();
}
}
-
+
nubus_writeb(red, &dafb_cmap_regs->lut);
nop();
nubus_writeb(green, &dafb_cmap_regs->lut);
nop();
nubus_writeb(blue, &dafb_cmap_regs->lut);
-
+
local_irq_restore(flags);
lastreg = regno;
return 0;
}
/* V8 and Brazil seem to use the same DAC. Sonora does as well. */
-static int v8_brazil_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info)
+static int v8_brazil_setpalette(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ struct fb_info *info)
{
unsigned int bpp = info->var.bits_per_pixel;
- unsigned char _red =red>>8;
- unsigned char _green=green>>8;
- unsigned char _blue =blue>>8;
- unsigned char _regno;
unsigned long flags;
- if (bpp > 8) return 1; /* failsafe */
+ if (bpp > 8)
+ return 1; /* failsafe */
local_irq_save(flags);
/* On these chips, the CLUT register numbers are spread out
- across the register space. Thus:
-
- In 8bpp, all regnos are valid.
-
- In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
-
- In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff */
- _regno = (regno << (8 - bpp)) | (0xFF >> bpp);
- nubus_writeb(_regno, &v8_brazil_cmap_regs->addr); nop();
+ * across the register space. Thus:
+ * In 8bpp, all regnos are valid.
+ * In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
+ * In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff
+ */
+ regno = (regno << (8 - bpp)) | (0xFF >> bpp);
+ nubus_writeb(regno, &v8_brazil_cmap_regs->addr);
+ nop();
/* send one color channel at a time */
- nubus_writeb(_red, &v8_brazil_cmap_regs->lut); nop();
- nubus_writeb(_green, &v8_brazil_cmap_regs->lut); nop();
- nubus_writeb(_blue, &v8_brazil_cmap_regs->lut);
+ nubus_writeb(red, &v8_brazil_cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &v8_brazil_cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &v8_brazil_cmap_regs->lut);
- local_irq_restore(flags);
+ local_irq_restore(flags);
return 0;
}
-static int rbv_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info)
+/* RAM-Based Video */
+static int rbv_setpalette(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ struct fb_info *info)
{
- /* use MSBs */
- unsigned char _red =red>>8;
- unsigned char _green=green>>8;
- unsigned char _blue =blue>>8;
- unsigned char _regno;
unsigned long flags;
- if (info->var.bits_per_pixel > 8) return 1; /* failsafe */
+ if (info->var.bits_per_pixel > 8)
+ return 1; /* failsafe */
local_irq_save(flags);
-
+
/* From the VideoToolbox driver. Seems to be saying that
* regno #254 and #255 are the important ones for 1-bit color,
* regno #252-255 are the important ones for 2-bit color, etc.
*/
- _regno = regno + (256-(1 << info->var.bits_per_pixel));
+ regno += 256 - (1 << info->var.bits_per_pixel);
/* reset clut? (VideoToolbox sez "not necessary") */
- nubus_writeb(0xFF, &rbv_cmap_regs->cntl); nop();
-
+ nubus_writeb(0xFF, &rbv_cmap_regs->cntl);
+ nop();
+
/* tell clut which address to use. */
- nubus_writeb(_regno, &rbv_cmap_regs->addr); nop();
-
+ nubus_writeb(regno, &rbv_cmap_regs->addr);
+ nop();
+
/* send one color channel at a time. */
- nubus_writeb(_red, &rbv_cmap_regs->lut); nop();
- nubus_writeb(_green, &rbv_cmap_regs->lut); nop();
- nubus_writeb(_blue, &rbv_cmap_regs->lut);
-
- local_irq_restore(flags); /* done. */
+ nubus_writeb(red, &rbv_cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &rbv_cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &rbv_cmap_regs->lut);
+
+ local_irq_restore(flags);
return 0;
}
-/* Macintosh Display Card (8x24) */
+/* Macintosh Display Card (8*24) */
static int mdc_setpalette(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
struct fb_info *info)
{
- volatile struct mdc_cmap_regs *cmap_regs =
- nubus_slot_addr(video_slot);
- /* use MSBs */
- unsigned char _red =red>>8;
- unsigned char _green=green>>8;
- unsigned char _blue =blue>>8;
- unsigned char _regno=regno;
+ struct mdc_cmap_regs *cmap_regs = slot_addr;
unsigned long flags;
local_irq_save(flags);
-
+
/* the nop's are there to order writes. */
- nubus_writeb(_regno, &cmap_regs->addr); nop();
- nubus_writeb(_red, &cmap_regs->lut); nop();
- nubus_writeb(_green, &cmap_regs->lut); nop();
- nubus_writeb(_blue, &cmap_regs->lut);
+ nubus_writeb(regno, &cmap_regs->addr);
+ nop();
+ nubus_writeb(red, &cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &cmap_regs->lut);
local_irq_restore(flags);
return 0;
@@ -350,24 +291,26 @@ static int mdc_setpalette(unsigned int regno, unsigned int red,
/* Toby frame buffer */
static int toby_setpalette(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
- struct fb_info *info)
+ struct fb_info *info)
{
- volatile struct toby_cmap_regs *cmap_regs =
- nubus_slot_addr(video_slot);
+ struct toby_cmap_regs *cmap_regs = slot_addr;
unsigned int bpp = info->var.bits_per_pixel;
- /* use MSBs */
- unsigned char _red =~(red>>8);
- unsigned char _green=~(green>>8);
- unsigned char _blue =~(blue>>8);
- unsigned char _regno = (regno << (8 - bpp)) | (0xFF >> bpp);
unsigned long flags;
+ red = ~red;
+ green = ~green;
+ blue = ~blue;
+ regno = (regno << (8 - bpp)) | (0xFF >> bpp);
+
local_irq_save(flags);
-
- nubus_writeb(_regno, &cmap_regs->addr); nop();
- nubus_writeb(_red, &cmap_regs->lut); nop();
- nubus_writeb(_green, &cmap_regs->lut); nop();
- nubus_writeb(_blue, &cmap_regs->lut);
+
+ nubus_writeb(regno, &cmap_regs->addr);
+ nop();
+ nubus_writeb(red, &cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &cmap_regs->lut);
local_irq_restore(flags);
return 0;
@@ -378,20 +321,18 @@ static int jet_setpalette(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
struct fb_info *info)
{
- volatile struct jet_cmap_regs *cmap_regs =
- nubus_slot_addr(video_slot);
- /* use MSBs */
- unsigned char _red = (red>>8);
- unsigned char _green = (green>>8);
- unsigned char _blue = (blue>>8);
+ struct jet_cmap_regs *cmap_regs = slot_addr;
unsigned long flags;
local_irq_save(flags);
-
- nubus_writeb(regno, &cmap_regs->addr); nop();
- nubus_writeb(_red, &cmap_regs->lut); nop();
- nubus_writeb(_green, &cmap_regs->lut); nop();
- nubus_writeb(_blue, &cmap_regs->lut);
+
+ nubus_writeb(regno, &cmap_regs->addr);
+ nop();
+ nubus_writeb(red, &cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &cmap_regs->lut);
local_irq_restore(flags);
return 0;
@@ -400,53 +341,27 @@ static int jet_setpalette(unsigned int regno, unsigned int red,
/*
* Civic framebuffer -- Quadra AV built-in video. A chip
* called Sebastian holds the actual color palettes, and
- * apparently, there are two different banks of 512K RAM
+ * apparently, there are two different banks of 512K RAM
* which can act as separate framebuffers for doing video
* input and viewing the screen at the same time! The 840AV
- * Can add another 1MB RAM to give the two framebuffers
+ * Can add another 1MB RAM to give the two framebuffers
* 1MB RAM apiece.
- *
- * FIXME: this doesn't seem to work anymore.
*/
-static int civic_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info)
+static int civic_setpalette(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ struct fb_info *info)
{
- static int lastreg = -1;
unsigned long flags;
int clut_status;
- if (info->var.bits_per_pixel > 8) return 1; /* failsafe */
-
- red >>= 8;
- green >>= 8;
- blue >>= 8;
+ if (info->var.bits_per_pixel > 8)
+ return 1; /* failsafe */
local_irq_save(flags);
-
- /*
- * Set the register address
- */
- nubus_writeb(regno, &civic_cmap_regs->addr); nop();
- /*
- * Wait for VBL interrupt here;
- * They're usually not enabled from Penguin, so we won't check
- */
-#if 0
- {
-#define CIVIC_VBL_OFFSET 0x120
- volatile unsigned long *vbl = nubus_readl(civic_cmap_regs->vbl_addr + CIVIC_VBL_OFFSET);
- /* do interrupt setup stuff here? */
- *vbl = 0L; nop(); /* clear */
- *vbl = 1L; nop(); /* set */
- while (*vbl != 0L) /* wait for next vbl */
- {
- usleep(10); /* needed? */
- }
- /* do interrupt shutdown stuff here? */
- }
-#endif
+ /* Set the register address */
+ nubus_writeb(regno, &civic_cmap_regs->addr);
+ nop();
/*
* Grab a status word and do some checking;
@@ -459,39 +374,52 @@ static int civic_setpalette (unsigned int regno, unsigned int red,
#if 0
if ((clut_status & 0x000D) != 0)
{
- nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
- nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
+ nubus_writeb(0x00, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(0x00, &civic_cmap_regs->lut);
+ nop();
}
#endif
- nubus_writeb( red, &civic_cmap_regs->lut); nop();
- nubus_writeb(green, &civic_cmap_regs->lut); nop();
- nubus_writeb( blue, &civic_cmap_regs->lut); nop();
- nubus_writeb( 0x00, &civic_cmap_regs->lut); nop();
+ nubus_writeb(red, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(0x00, &civic_cmap_regs->lut);
}
else
{
unsigned char junk;
- junk = nubus_readb(&civic_cmap_regs->lut); nop();
- junk = nubus_readb(&civic_cmap_regs->lut); nop();
- junk = nubus_readb(&civic_cmap_regs->lut); nop();
- junk = nubus_readb(&civic_cmap_regs->lut); nop();
+ junk = nubus_readb(&civic_cmap_regs->lut);
+ nop();
+ junk = nubus_readb(&civic_cmap_regs->lut);
+ nop();
+ junk = nubus_readb(&civic_cmap_regs->lut);
+ nop();
+ junk = nubus_readb(&civic_cmap_regs->lut);
+ nop();
if ((clut_status & 0x000D) != 0)
{
- nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
- nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
+ nubus_writeb(0x00, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(0x00, &civic_cmap_regs->lut);
+ nop();
}
- nubus_writeb( red, &civic_cmap_regs->lut); nop();
- nubus_writeb(green, &civic_cmap_regs->lut); nop();
- nubus_writeb( blue, &civic_cmap_regs->lut); nop();
- nubus_writeb( junk, &civic_cmap_regs->lut); nop();
+ nubus_writeb(red, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(green, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(blue, &civic_cmap_regs->lut);
+ nop();
+ nubus_writeb(junk, &civic_cmap_regs->lut);
}
local_irq_restore(flags);
- lastreg = regno;
return 0;
}
@@ -500,16 +428,21 @@ static int civic_setpalette (unsigned int regno, unsigned int red,
* (and the 5300 too, but that's a PowerMac). This function
* brought to you in part by the ECSC driver for MkLinux.
*/
-
-static int csc_setpalette (unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- struct fb_info *info)
+static int csc_setpalette(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ struct fb_info *info)
{
- mdelay(1);
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ udelay(1); /* mklinux on PB 5300 waits for 260 ns */
nubus_writeb(regno, &csc_cmap_regs->clut_waddr);
- nubus_writeb(red, &csc_cmap_regs->clut_data);
+ nubus_writeb(red, &csc_cmap_regs->clut_data);
nubus_writeb(green, &csc_cmap_regs->clut_data);
- nubus_writeb(blue, &csc_cmap_regs->clut_data);
+ nubus_writeb(blue, &csc_cmap_regs->clut_data);
+
+ local_irq_restore(flags);
return 0;
}
@@ -518,10 +451,10 @@ static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
struct fb_info *fb_info)
{
/*
- * Set a single color register. The values supplied are
- * already rounded down to the hardware's capabilities
- * (according to the entries in the `var' structure). Return
- * != 0 for invalid regno.
+ * Set a single color register. The values supplied are
+ * already rounded down to the hardware's capabilities
+ * (according to the entries in the `var' structure).
+ * Return non-zero for invalid regno.
*/
if (regno >= fb_info->cmap.len)
@@ -536,8 +469,8 @@ static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
case 4:
case 8:
if (macfb_setpalette)
- macfb_setpalette(regno, red, green, blue,
- fb_info);
+ macfb_setpalette(regno, red >> 8, green >> 8,
+ blue >> 8, fb_info);
else
return 1;
break;
@@ -555,28 +488,22 @@ static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
} else {
/* 0:5:6:5 */
((u32*) (fb_info->pseudo_palette))[regno] =
- ((red & 0xf800) ) |
+ ((red & 0xf800) >> 0) |
((green & 0xfc00) >> 5) |
((blue & 0xf800) >> 11);
}
break;
- /* I'm pretty sure that one or the other of these
- doesn't exist on 68k Macs */
+ /*
+ * 24-bit colour almost doesn't exist on 68k Macs --
+ * http://support.apple.com/kb/TA28634 (Old Article: 10992)
+ */
case 24:
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- ((u32 *)(fb_info->pseudo_palette))[regno] =
- (red << fb_info->var.red.offset) |
- (green << fb_info->var.green.offset) |
- (blue << fb_info->var.blue.offset);
- break;
case 32:
red >>= 8;
green >>= 8;
blue >>= 8;
((u32 *)(fb_info->pseudo_palette))[regno] =
- (red << fb_info->var.red.offset) |
+ (red << fb_info->var.red.offset) |
(green << fb_info->var.green.offset) |
(blue << fb_info->var.blue.offset);
break;
@@ -597,25 +524,24 @@ static struct fb_ops macfb_ops = {
static void __init macfb_setup(char *options)
{
char *this_opt;
-
+
if (!options || !*options)
return;
-
+
while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!*this_opt) continue;
-
- if (! strcmp(this_opt, "inverse"))
- inverse=1;
- /* This means "turn on experimental CLUT code" */
- else if (!strcmp(this_opt, "vidtest"))
- vidtest=1;
+ if (!*this_opt)
+ continue;
+
+ if (!strcmp(this_opt, "inverse"))
+ inverse = 1;
+ else
+ if (!strcmp(this_opt, "vidtest"))
+ vidtest = 1; /* enable experimental CLUT code */
}
}
static void __init iounmap_macfb(void)
{
- if (valkyrie_cmap_regs)
- iounmap(valkyrie_cmap_regs);
if (dafb_cmap_regs)
iounmap(dafb_cmap_regs);
if (v8_brazil_cmap_regs)
@@ -642,48 +568,55 @@ static int __init macfb_init(void)
if (!MACH_IS_MAC)
return -ENODEV;
- /* There can only be one internal video controller anyway so
- we're not too worried about this */
+ if (mac_bi_data.id == MAC_MODEL_Q630 ||
+ mac_bi_data.id == MAC_MODEL_P588)
+ return -ENODEV; /* See valkyriefb.c */
+
macfb_defined.xres = mac_bi_data.dimensions & 0xFFFF;
macfb_defined.yres = mac_bi_data.dimensions >> 16;
macfb_defined.bits_per_pixel = mac_bi_data.videodepth;
+
macfb_fix.line_length = mac_bi_data.videorow;
- macfb_fix.smem_len = macfb_fix.line_length * macfb_defined.yres;
+ macfb_fix.smem_len = macfb_fix.line_length * macfb_defined.yres;
/* Note: physical address (since 2.1.127) */
- macfb_fix.smem_start = mac_bi_data.videoaddr;
- /* This is actually redundant with the initial mappings.
- However, there are some non-obvious aspects to the way
- those mappings are set up, so this is in fact the safest
- way to ensure that this driver will work on every possible
- Mac */
- fb_info.screen_base = ioremap(mac_bi_data.videoaddr, macfb_fix.smem_len);
-
- printk("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
- macfb_fix.smem_start, fb_info.screen_base, macfb_fix.smem_len/1024);
- printk("macfb: mode is %dx%dx%d, linelength=%d\n",
- macfb_defined.xres, macfb_defined.yres, macfb_defined.bits_per_pixel, macfb_fix.line_length);
-
+ macfb_fix.smem_start = mac_bi_data.videoaddr;
+
/*
- * Fill in the available video resolution
+ * This is actually redundant with the initial mappings.
+ * However, there are some non-obvious aspects to the way
+ * those mappings are set up, so this is in fact the safest
+ * way to ensure that this driver will work on every possible Mac
*/
-
- macfb_defined.xres_virtual = macfb_defined.xres;
- macfb_defined.yres_virtual = macfb_defined.yres;
- macfb_defined.height = PIXEL_TO_MM(macfb_defined.yres);
- macfb_defined.width = PIXEL_TO_MM(macfb_defined.xres);
+ fb_info.screen_base = ioremap(mac_bi_data.videoaddr,
+ macfb_fix.smem_len);
+ if (!fb_info.screen_base)
+ return -ENODEV;
- printk("macfb: scrolling: redraw\n");
+ printk("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
+ macfb_fix.smem_start, fb_info.screen_base,
+ macfb_fix.smem_len / 1024);
+ printk("macfb: mode is %dx%dx%d, linelength=%d\n",
+ macfb_defined.xres, macfb_defined.yres,
+ macfb_defined.bits_per_pixel, macfb_fix.line_length);
+
+ /* Fill in the available video resolution */
+ macfb_defined.xres_virtual = macfb_defined.xres;
macfb_defined.yres_virtual = macfb_defined.yres;
+ macfb_defined.height = PIXEL_TO_MM(macfb_defined.yres);
+ macfb_defined.width = PIXEL_TO_MM(macfb_defined.xres);
- /* some dummy values for timing to make fbset happy */
- macfb_defined.pixclock = 10000000 / macfb_defined.xres * 1000 / macfb_defined.yres;
+ /* Some dummy values for timing to make fbset happy */
+ macfb_defined.pixclock = 10000000 / macfb_defined.xres *
+ 1000 / macfb_defined.yres;
macfb_defined.left_margin = (macfb_defined.xres / 8) & 0xf8;
macfb_defined.hsync_len = (macfb_defined.xres / 8) & 0xf8;
switch (macfb_defined.bits_per_pixel) {
case 1:
- /* XXX: I think this will catch any program that tries
- to do FBIO_PUTCMAP when the visual is monochrome */
+ /*
+ * XXX: I think this will catch any program that tries
+ * to do FBIO_PUTCMAP when the visual is monochrome.
+ */
macfb_defined.red.length = macfb_defined.bits_per_pixel;
macfb_defined.green.length = macfb_defined.bits_per_pixel;
macfb_defined.blue.length = macfb_defined.bits_per_pixel;
@@ -708,53 +641,52 @@ static int __init macfb_init(void)
macfb_defined.green.length = 5;
macfb_defined.blue.offset = 0;
macfb_defined.blue.length = 5;
- printk("macfb: directcolor: "
- "size=1:5:5:5, shift=15:10:5:0\n");
video_cmap_len = 16;
- /* Should actually be FB_VISUAL_DIRECTCOLOR, but this
- works too */
+ /*
+ * Should actually be FB_VISUAL_DIRECTCOLOR, but this
+ * works too
+ */
macfb_fix.visual = FB_VISUAL_TRUECOLOR;
break;
case 24:
case 32:
- /* XXX: have to test these... can any 68k Macs
- actually do this on internal video? */
macfb_defined.red.offset = 16;
macfb_defined.red.length = 8;
macfb_defined.green.offset = 8;
macfb_defined.green.length = 8;
macfb_defined.blue.offset = 0;
macfb_defined.blue.length = 8;
- printk("macfb: truecolor: "
- "size=0:8:8:8, shift=0:16:8:0\n");
video_cmap_len = 16;
macfb_fix.visual = FB_VISUAL_TRUECOLOR;
+ break;
default:
video_cmap_len = 0;
macfb_fix.visual = FB_VISUAL_MONO01;
- printk("macfb: unknown or unsupported bit depth: %d\n", macfb_defined.bits_per_pixel);
+ printk("macfb: unknown or unsupported bit depth: %d\n",
+ macfb_defined.bits_per_pixel);
break;
}
- /* Hardware dependent stuff */
- /* We take a wild guess that if the video physical address is
- * in nubus slot space, that the nubus card is driving video.
- * Penguin really ought to tell us whether we are using internal
- * video or not.
+ /*
+ * We take a wild guess that if the video physical address is
+ * in nubus slot space, that the nubus card is driving video.
+ * Penguin really ought to tell us whether we are using internal
+ * video or not.
+ * Hopefully we only find one of them. Otherwise our NuBus
+ * code is really broken :-)
*/
- /* Hopefully we only find one of them. Otherwise our NuBus
- code is really broken :-) */
- while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY, NUBUS_TYPE_VIDEO, ndev))
- != NULL)
+ while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY,
+ NUBUS_TYPE_VIDEO, ndev)))
{
- if (!(mac_bi_data.videoaddr >= ndev->board->slot_addr
- && (mac_bi_data.videoaddr <
- (unsigned long)nubus_slot_addr(ndev->board->slot+1))))
+ unsigned long base = ndev->board->slot_addr;
+
+ if (mac_bi_data.videoaddr < base ||
+ mac_bi_data.videoaddr - base > 0xFFFFFF)
continue;
+
video_is_nubus = 1;
- /* We should probably just use the slot address... */
- video_slot = ndev->board->slot;
+ slot_addr = (unsigned char *)base;
switch(ndev->dr_hw) {
case NUBUS_DRHW_APPLE_MDC:
@@ -771,7 +703,7 @@ static int __init macfb_init(void)
strcpy(macfb_fix.id, "Jet");
macfb_setpalette = jet_setpalette;
macfb_defined.activate = FB_ACTIVATE_NOW;
- break;
+ break;
default:
strcpy(macfb_fix.id, "Generic NuBus");
break;
@@ -779,30 +711,19 @@ static int __init macfb_init(void)
}
/* If it's not a NuBus card, it must be internal video */
- /* FIXME: this function is getting way too big. (this driver
- is too...) */
if (!video_is_nubus)
- switch( mac_bi_data.id )
- {
- /* Valkyrie Quadras */
- case MAC_MODEL_Q630:
- /* I'm not sure about this one */
- case MAC_MODEL_P588:
- strcpy(macfb_fix.id, "Valkyrie");
- macfb_setpalette = valkyrie_setpalette;
- macfb_defined.activate = FB_ACTIVATE_NOW;
- valkyrie_cmap_regs = ioremap(DAC_BASE, 0x1000);
- break;
-
- /* DAFB Quadras */
- /* Note: these first four have the v7 DAFB, which is
- known to be rather unlike the ones used in the
- other models */
+ switch (mac_bi_data.id) {
+ /*
+ * DAFB Quadras
+ * Note: these first four have the v7 DAFB, which is
+ * known to be rather unlike the ones used in the
+ * other models
+ */
case MAC_MODEL_P475:
case MAC_MODEL_P475F:
case MAC_MODEL_P575:
case MAC_MODEL_Q605:
-
+
case MAC_MODEL_Q800:
case MAC_MODEL_Q650:
case MAC_MODEL_Q610:
@@ -817,17 +738,21 @@ static int __init macfb_init(void)
dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000);
break;
- /* LC II uses the V8 framebuffer */
+ /*
+ * LC II uses the V8 framebuffer
+ */
case MAC_MODEL_LCII:
strcpy(macfb_fix.id, "V8");
macfb_setpalette = v8_brazil_setpalette;
macfb_defined.activate = FB_ACTIVATE_NOW;
v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
break;
-
- /* IIvi, IIvx use the "Brazil" framebuffer (which is
- very much like the V8, it seems, and probably uses
- the same DAC) */
+
+ /*
+ * IIvi, IIvx use the "Brazil" framebuffer (which is
+ * very much like the V8, it seems, and probably uses
+ * the same DAC)
+ */
case MAC_MODEL_IIVI:
case MAC_MODEL_IIVX:
case MAC_MODEL_P600:
@@ -836,12 +761,14 @@ static int __init macfb_init(void)
macfb_defined.activate = FB_ACTIVATE_NOW;
v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
break;
-
- /* LC III (and friends) use the Sonora framebuffer */
- /* Incidentally this is also used in the non-AV models
- of the x100 PowerMacs */
- /* These do in fact seem to use the same DAC interface
- as the LC II. */
+
+ /*
+ * LC III (and friends) use the Sonora framebuffer
+ * Incidentally this is also used in the non-AV models
+ * of the x100 PowerMacs
+ * These do in fact seem to use the same DAC interface
+ * as the LC II.
+ */
case MAC_MODEL_LCIII:
case MAC_MODEL_P520:
case MAC_MODEL_P550:
@@ -852,9 +779,11 @@ static int __init macfb_init(void)
v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
break;
- /* IIci and IIsi use the infamous RBV chip
- (the IIsi is just a rebadged and crippled
- IIci in a different case, BTW) */
+ /*
+ * IIci and IIsi use the infamous RBV chip
+ * (the IIsi is just a rebadged and crippled
+ * IIci in a different case, BTW)
+ */
case MAC_MODEL_IICI:
case MAC_MODEL_IISI:
macfb_setpalette = rbv_setpalette;
@@ -863,7 +792,9 @@ static int __init macfb_init(void)
rbv_cmap_regs = ioremap(DAC_BASE, 0x1000);
break;
- /* AVs use the Civic framebuffer */
+ /*
+ * AVs use the Civic framebuffer
+ */
case MAC_MODEL_Q840:
case MAC_MODEL_C660:
macfb_setpalette = civic_setpalette;
@@ -873,15 +804,10 @@ static int __init macfb_init(void)
break;
- /* Write a setpalette function for your machine, then
- you can add something similar here. These are
- grouped by classes of video chipsets. Some of this
- information is from the VideoToolbox "Bugs" web
- page at
- http://rajsky.psych.nyu.edu/Tips/VideoBugs.html */
-
- /* Assorted weirdos */
- /* We think this may be like the LC II */
+ /*
+ * Assorted weirdos
+ * We think this may be like the LC II
+ */
case MAC_MODEL_LC:
if (vidtest) {
macfb_setpalette = v8_brazil_setpalette;
@@ -891,7 +817,10 @@ static int __init macfb_init(void)
}
strcpy(macfb_fix.id, "LC");
break;
- /* We think this may be like the LC II */
+
+ /*
+ * We think this may be like the LC II
+ */
case MAC_MODEL_CCL:
if (vidtest) {
macfb_setpalette = v8_brazil_setpalette;
@@ -902,31 +831,42 @@ static int __init macfb_init(void)
strcpy(macfb_fix.id, "Color Classic");
break;
- /* And we *do* mean "weirdos" */
+ /*
+ * And we *do* mean "weirdos"
+ */
case MAC_MODEL_TV:
strcpy(macfb_fix.id, "Mac TV");
break;
- /* These don't have colour, so no need to worry */
+ /*
+ * These don't have colour, so no need to worry
+ */
case MAC_MODEL_SE30:
case MAC_MODEL_CLII:
strcpy(macfb_fix.id, "Monochrome");
break;
- /* Powerbooks are particularly difficult. Many of
- them have separate framebuffers for external and
- internal video, which is admittedly pretty cool,
- but will be a bit of a headache to support here.
- Also, many of them are grayscale, and we don't
- really support that. */
-
+ /*
+ * Powerbooks are particularly difficult. Many of
+ * them have separate framebuffers for external and
+ * internal video, which is admittedly pretty cool,
+ * but will be a bit of a headache to support here.
+ * Also, many of them are grayscale, and we don't
+ * really support that.
+ */
+
+ /*
+ * Slot 0 ROM says TIM. No external video. B&W.
+ */
case MAC_MODEL_PB140:
case MAC_MODEL_PB145:
case MAC_MODEL_PB170:
strcpy(macfb_fix.id, "DDC");
break;
- /* Internal is GSC, External (if present) is ViSC */
+ /*
+ * Internal is GSC, External (if present) is ViSC
+ */
case MAC_MODEL_PB150: /* no external video */
case MAC_MODEL_PB160:
case MAC_MODEL_PB165:
@@ -936,13 +876,17 @@ static int __init macfb_init(void)
strcpy(macfb_fix.id, "GSC");
break;
- /* Internal is TIM, External is ViSC */
+ /*
+ * Internal is TIM, External is ViSC
+ */
case MAC_MODEL_PB165C:
case MAC_MODEL_PB180C:
strcpy(macfb_fix.id, "TIM");
break;
- /* Internal is CSC, External is Keystone+Ariel. */
+ /*
+ * Internal is CSC, External is Keystone+Ariel.
+ */
case MAC_MODEL_PB190: /* external video is optional */
case MAC_MODEL_PB520:
case MAC_MODEL_PB250:
@@ -954,7 +898,7 @@ static int __init macfb_init(void)
strcpy(macfb_fix.id, "CSC");
csc_cmap_regs = ioremap(CSC_BASE, 0x1000);
break;
-
+
default:
strcpy(macfb_fix.id, "Unknown");
break;
@@ -969,7 +913,7 @@ static int __init macfb_init(void)
err = fb_alloc_cmap(&fb_info.cmap, video_cmap_len, 0);
if (err)
goto fail_unmap;
-
+
err = register_framebuffer(&fb_info);
if (err)
goto fail_dealloc;
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c
index 083f60321ed8..af86c081d2be 100644
--- a/drivers/video/macmodes.c
+++ b/drivers/video/macmodes.c
@@ -33,6 +33,10 @@
static const struct fb_videomode mac_modedb[] = {
{
+ /* 512x384, 60Hz, Non-Interlaced (15.67 MHz dot clock) */
+ "mac2", 60, 512, 384, 63828, 80, 16, 19, 1, 32, 3,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
"mac5", 60, 640, 480, 39722, 32, 32, 33, 10, 96, 2,
0, FB_VMODE_NONINTERLACED
@@ -41,6 +45,10 @@ static const struct fb_videomode mac_modedb[] = {
"mac6", 67, 640, 480, 33334, 80, 80, 39, 3, 64, 3,
0, FB_VMODE_NONINTERLACED
}, {
+ /* 640x870, 75Hz (portrait), Non-Interlaced (57.28 MHz dot clock) */
+ "mac7", 75, 640, 870, 17457, 80, 32, 42, 3, 80, 3,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
/* 800x600, 56 Hz, Non-Interlaced (36.00 MHz dotclock) */
"mac9", 56, 800, 600, 27778, 112, 40, 22, 1, 72, 2,
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
@@ -105,10 +113,6 @@ static const struct fb_videomode mac_modedb[] = {
"mac1", 60, 512, 384, pixclock, left, right, upper, lower, hslen, vslen,
sync, FB_VMODE_INTERLACED
}, {
- /* VMODE_512_384_60: 512x384, 60Hz, Non-Interlaced */
- "mac2", 60, 512, 384, pixclock, left, right, upper, lower, hslen, vslen,
- sync, FB_VMODE_NONINTERLACED
- }, {
/* VMODE_640_480_50I: 640x480, 50Hz, Interlaced (PAL) */
"mac3", 50, 640, 480, pixclock, left, right, upper, lower, hslen, vslen,
sync, FB_VMODE_INTERLACED
@@ -117,10 +121,6 @@ static const struct fb_videomode mac_modedb[] = {
"mac4", 60, 640, 480, pixclock, left, right, upper, lower, hslen, vslen,
sync, FB_VMODE_INTERLACED
}, {
- /* VMODE_640_870_75P: 640x870, 75Hz (portrait), Non-Interlaced */
- "mac7", 75, 640, 870, pixclock, left, right, upper, lower, hslen, vslen,
- sync, FB_VMODE_NONINTERLACED
- }, {
/* VMODE_768_576_50I: 768x576, 50Hz (PAL full frame), Interlaced */
"mac8", 50, 768, 576, pixclock, left, right, upper, lower, hslen, vslen,
sync, FB_VMODE_INTERLACED
@@ -134,38 +134,42 @@ static const struct fb_videomode mac_modedb[] = {
*
* These MUST be ordered in
* - increasing resolution
- * - decreasing refresh rate
+ * - decreasing pixel clock period
*/
static const struct mode_map {
int vmode;
const struct fb_videomode *mode;
} mac_modes[] = {
+ /* 512x384 */
+ { VMODE_512_384_60, &mac_modedb[0] },
/* 640x480 */
- { VMODE_640_480_67, &mac_modedb[1] },
- { VMODE_640_480_60, &mac_modedb[0] },
+ { VMODE_640_480_60, &mac_modedb[1] },
+ { VMODE_640_480_67, &mac_modedb[2] },
+ /* 640x870 */
+ { VMODE_640_870_75P, &mac_modedb[3] },
/* 800x600 */
- { VMODE_800_600_75, &mac_modedb[5] },
- { VMODE_800_600_72, &mac_modedb[4] },
- { VMODE_800_600_60, &mac_modedb[3] },
- { VMODE_800_600_56, &mac_modedb[2] },
+ { VMODE_800_600_56, &mac_modedb[4] },
+ { VMODE_800_600_60, &mac_modedb[5] },
+ { VMODE_800_600_75, &mac_modedb[7] },
+ { VMODE_800_600_72, &mac_modedb[6] },
/* 832x624 */
- { VMODE_832_624_75, &mac_modedb[6] },
+ { VMODE_832_624_75, &mac_modedb[8] },
/* 1024x768 */
- { VMODE_1024_768_75, &mac_modedb[10] },
- { VMODE_1024_768_75V, &mac_modedb[9] },
- { VMODE_1024_768_70, &mac_modedb[8] },
- { VMODE_1024_768_60, &mac_modedb[7] },
+ { VMODE_1024_768_60, &mac_modedb[9] },
+ { VMODE_1024_768_70, &mac_modedb[10] },
+ { VMODE_1024_768_75V, &mac_modedb[11] },
+ { VMODE_1024_768_75, &mac_modedb[12] },
/* 1152x768 */
- { VMODE_1152_768_60, &mac_modedb[14] },
+ { VMODE_1152_768_60, &mac_modedb[16] },
/* 1152x870 */
- { VMODE_1152_870_75, &mac_modedb[11] },
+ { VMODE_1152_870_75, &mac_modedb[13] },
/* 1280x960 */
- { VMODE_1280_960_75, &mac_modedb[12] },
+ { VMODE_1280_960_75, &mac_modedb[14] },
/* 1280x1024 */
- { VMODE_1280_1024_75, &mac_modedb[13] },
+ { VMODE_1280_1024_75, &mac_modedb[15] },
/* 1600x1024 */
- { VMODE_1600_1024_60, &mac_modedb[15] },
+ { VMODE_1600_1024_60, &mac_modedb[17] },
{ -1, NULL }
};
@@ -299,7 +303,6 @@ EXPORT_SYMBOL(mac_vmode_to_var);
int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
int *cmode)
{
- const struct fb_videomode *mode = NULL;
const struct mode_map *map;
if (var->bits_per_pixel <= 8)
@@ -311,8 +314,13 @@ int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
else
return -EINVAL;
+ /*
+ * Find the mac_mode with a matching resolution or failing that, the
+ * closest larger resolution. Skip modes with a shorter pixel clock period.
+ */
for (map = mac_modes; map->vmode != -1; map++) {
- mode = map->mode;
+ const struct fb_videomode *mode = map->mode;
+
if (var->xres > mode->xres || var->yres > mode->yres)
continue;
if (var->xres_virtual > mode->xres || var->yres_virtual > mode->yres)
@@ -322,6 +330,24 @@ int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
if ((var->vmode & FB_VMODE_MASK) != mode->vmode)
continue;
*vmode = map->vmode;
+
+ /*
+ * Having found a good resolution, find the matching pixel clock
+ * or failing that, the closest longer pixel clock period.
+ */
+ map++;
+ while (map->vmode != -1) {
+ const struct fb_videomode *clk_mode = map->mode;
+
+ if (mode->xres != clk_mode->xres || mode->yres != clk_mode->yres)
+ break;
+ if (var->pixclock > mode->pixclock)
+ break;
+ if (mode->vmode != clk_mode->vmode)
+ continue;
+ *vmode = map->vmode;
+ map++;
+ }
return 0;
}
return -EINVAL;
diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c
index fabb0c59a211..8280a58a0e55 100644
--- a/drivers/video/mb862xx/mb862xxfb.c
+++ b/drivers/video/mb862xx/mb862xxfb.c
@@ -31,15 +31,6 @@
#define CARMINE_MEM_SIZE 0x8000000
#define DRV_NAME "mb862xxfb"
-#if defined(CONFIG_LWMON5)
-static struct mb862xx_gc_mode lwmon5_gc_mode = {
- /* Mode for Sharp LQ104V1DG61 TFT LCD Panel */
- { "640x480", 60, 640, 480, 40000, 48, 16, 32, 11, 96, 2, 0, 0, 0 },
- /* 16 bits/pixel, 32MB, 100MHz, SDRAM memory mode value */
- 16, 0x2000000, GC_CCF_COT_100, 0x414fb7f2
-};
-#endif
-
#if defined(CONFIG_SOCRATES)
static struct mb862xx_gc_mode socrates_gc_mode = {
/* Mode for Prime View PM070WL4 TFT LCD Panel */
@@ -600,10 +591,6 @@ static int __devinit of_platform_mb862xx_probe(struct of_device *ofdev,
goto irqdisp;
}
-#if defined(CONFIG_LWMON5)
- par->gc_mode = &lwmon5_gc_mode;
-#endif
-
#if defined(CONFIG_SOCRATES)
par->gc_mode = &socrates_gc_mode;
#endif
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c
index 01f77bcc68f9..afea9abbd678 100644
--- a/drivers/video/mbx/mbxfb.c
+++ b/drivers/video/mbx/mbxfb.c
@@ -693,7 +693,7 @@ static void __devinit setup_memc(struct fb_info *fbi)
unsigned long tmp;
int i;
- /* FIXME: use platfrom specific parameters */
+ /* FIXME: use platform specific parameters */
/* setup SDRAM controller */
write_reg_dly((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS |
LMCFG_LMA_TS),
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 0129f1bc3522..b895aae41630 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -893,7 +893,7 @@ const struct fb_videomode *fb_match_mode(const struct fb_var_screeninfo *var,
}
/**
- * fb_add_videomode: adds videomode entry to modelist
+ * fb_add_videomode - adds videomode entry to modelist
* @mode: videomode to add
* @head: struct list_head of modelist
*
@@ -928,7 +928,7 @@ int fb_add_videomode(const struct fb_videomode *mode, struct list_head *head)
}
/**
- * fb_delete_videomode: removed videomode entry from modelist
+ * fb_delete_videomode - removed videomode entry from modelist
* @mode: videomode to remove
* @head: struct list_head of modelist
*
@@ -953,7 +953,7 @@ void fb_delete_videomode(const struct fb_videomode *mode,
}
/**
- * fb_destroy_modelist: destroy modelist
+ * fb_destroy_modelist - destroy modelist
* @head: struct list_head of modelist
*/
void fb_destroy_modelist(struct list_head *head)
@@ -968,7 +968,7 @@ void fb_destroy_modelist(struct list_head *head)
EXPORT_SYMBOL_GPL(fb_destroy_modelist);
/**
- * fb_videomode_to_modelist: convert mode array to mode list
+ * fb_videomode_to_modelist - convert mode array to mode list
* @modedb: array of struct fb_videomode
* @num: number of entries in array
* @head: struct list_head of modelist
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index 054ef29be479..772ba3f45e6f 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -324,8 +324,11 @@ static void sdc_enable_channel(struct mx3fb_info *mx3_fbi)
unsigned long flags;
dma_cookie_t cookie;
- dev_dbg(mx3fb->dev, "mx3fbi %p, desc %p, sg %p\n", mx3_fbi,
- to_tx_desc(mx3_fbi->txd), to_tx_desc(mx3_fbi->txd)->sg);
+ if (mx3_fbi->txd)
+ dev_dbg(mx3fb->dev, "mx3fbi %p, desc %p, sg %p\n", mx3_fbi,
+ to_tx_desc(mx3_fbi->txd), to_tx_desc(mx3_fbi->txd)->sg);
+ else
+ dev_dbg(mx3fb->dev, "mx3fbi %p, txd = NULL\n", mx3_fbi);
/* This enables the channel */
if (mx3_fbi->cookie < 0) {
@@ -646,6 +649,7 @@ static int sdc_set_global_alpha(struct mx3fb_data *mx3fb, bool enable, uint8_t a
static void sdc_set_brightness(struct mx3fb_data *mx3fb, uint8_t value)
{
+ dev_dbg(mx3fb->dev, "%s: value = %d\n", __func__, value);
/* This might be board-specific */
mx3fb_write_reg(mx3fb, 0x03000000UL | value << 16, SDC_PWM_CTRL);
return;
@@ -1486,12 +1490,12 @@ static int mx3fb_probe(struct platform_device *pdev)
goto ersdc0;
}
+ mx3fb->backlight_level = 255;
+
ret = init_fb_chan(mx3fb, to_idmac_chan(chan));
if (ret < 0)
goto eisdc0;
- mx3fb->backlight_level = 255;
-
return 0;
eisdc0:
diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c
new file mode 100644
index 000000000000..6bf0d460a738
--- /dev/null
+++ b/drivers/video/nuc900fb.c
@@ -0,0 +1,779 @@
+/*
+ *
+ * Copyright (c) 2009 Nuvoton technology 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.
+ *
+ * Description:
+ * Nuvoton LCD Controller Driver
+ * Author:
+ * Wang Qiang (rurality.linux@gmail.com) 2009/12/11
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/io.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-ldm.h>
+#include <mach/fb.h>
+#include <mach/clkdev.h>
+
+#include "nuc900fb.h"
+
+
+/*
+ * Initialize the nuc900 video (dual) buffer address
+ */
+static void nuc900fb_set_lcdaddr(struct fb_info *info)
+{
+ struct nuc900fb_info *fbi = info->par;
+ void __iomem *regs = fbi->io;
+ unsigned long vbaddr1, vbaddr2;
+
+ vbaddr1 = info->fix.smem_start;
+ vbaddr2 = info->fix.smem_start;
+ vbaddr2 += info->fix.line_length * info->var.yres;
+
+ /* set frambuffer start phy addr*/
+ writel(vbaddr1, regs + REG_LCM_VA_BADDR0);
+ writel(vbaddr2, regs + REG_LCM_VA_BADDR1);
+
+ writel(fbi->regs.lcd_va_fbctrl, regs + REG_LCM_VA_FBCTRL);
+ writel(fbi->regs.lcd_va_scale, regs + REG_LCM_VA_SCALE);
+}
+
+/*
+ * calculate divider for lcd div
+ */
+static unsigned int nuc900fb_calc_pixclk(struct nuc900fb_info *fbi,
+ unsigned long pixclk)
+{
+ unsigned long clk = fbi->clk_rate;
+ unsigned long long div;
+
+ /* pixclk is in picseconds. our clock is in Hz*/
+ /* div = (clk * pixclk)/10^12 */
+ div = (unsigned long long)clk * pixclk;
+ div >>= 12;
+ do_div(div, 625 * 625UL * 625);
+
+ dev_dbg(fbi->dev, "pixclk %ld, divisor is %lld\n", pixclk, div);
+
+ return div;
+}
+
+/*
+ * Check the video params of 'var'.
+ */
+static int nuc900fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct nuc900fb_info *fbi = info->par;
+ struct nuc900fb_mach_info *mach_info = fbi->dev->platform_data;
+ struct nuc900fb_display *display = NULL;
+ struct nuc900fb_display *default_display = mach_info->displays +
+ mach_info->default_display;
+ int i;
+
+ dev_dbg(fbi->dev, "check_var(var=%p, info=%p)\n", var, info);
+
+ /* validate x/y resolution */
+ /* choose default mode if possible */
+ if (var->xres == default_display->xres &&
+ var->yres == default_display->yres &&
+ var->bits_per_pixel == default_display->bpp)
+ display = default_display;
+ else
+ for (i = 0; i < mach_info->num_displays; i++)
+ if (var->xres == mach_info->displays[i].xres &&
+ var->yres == mach_info->displays[i].yres &&
+ var->bits_per_pixel == mach_info->displays[i].bpp) {
+ display = mach_info->displays + i;
+ break;
+ }
+
+ if (display == NULL) {
+ printk(KERN_ERR "wrong resolution or depth %dx%d at %d bit per pixel\n",
+ var->xres, var->yres, var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ /* it should be the same size as the display */
+ var->xres_virtual = display->xres;
+ var->yres_virtual = display->yres;
+ var->height = display->height;
+ var->width = display->width;
+
+ /* copy lcd settings */
+ var->pixclock = display->pixclock;
+ var->left_margin = display->left_margin;
+ var->right_margin = display->right_margin;
+ var->upper_margin = display->upper_margin;
+ var->lower_margin = display->lower_margin;
+ var->vsync_len = display->vsync_len;
+ var->hsync_len = display->hsync_len;
+
+ var->transp.offset = 0;
+ var->transp.length = 0;
+
+ fbi->regs.lcd_dccs = display->dccs;
+ fbi->regs.lcd_device_ctrl = display->devctl;
+ fbi->regs.lcd_va_fbctrl = display->fbctrl;
+ fbi->regs.lcd_va_scale = display->scale;
+
+ /* set R/G/B possions */
+ switch (var->bits_per_pixel) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ default:
+ var->red.offset = 0;
+ var->red.length = var->bits_per_pixel;
+ var->green = var->red;
+ var->blue = var->red;
+ break;
+ case 12:
+ var->red.length = 4;
+ var->green.length = 4;
+ var->blue.length = 4;
+ var->red.offset = 8;
+ var->green.offset = 4;
+ var->blue.offset = 0;
+ break;
+ case 16:
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ break;
+ case 18:
+ var->red.length = 6;
+ var->green.length = 6;
+ var->blue.length = 6;
+ var->red.offset = 12;
+ var->green.offset = 6;
+ var->blue.offset = 0;
+ break;
+ case 32:
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Calculate lcd register values from var setting & save into hw
+ */
+static void nuc900fb_calculate_lcd_regs(const struct fb_info *info,
+ struct nuc900fb_hw *regs)
+{
+ const struct fb_var_screeninfo *var = &info->var;
+ int vtt = var->height + var->upper_margin + var->lower_margin;
+ int htt = var->width + var->left_margin + var->right_margin;
+ int hsync = var->width + var->right_margin;
+ int vsync = var->height + var->lower_margin;
+
+ regs->lcd_crtc_size = LCM_CRTC_SIZE_VTTVAL(vtt) |
+ LCM_CRTC_SIZE_HTTVAL(htt);
+ regs->lcd_crtc_dend = LCM_CRTC_DEND_VDENDVAL(var->height) |
+ LCM_CRTC_DEND_HDENDVAL(var->width);
+ regs->lcd_crtc_hr = LCM_CRTC_HR_EVAL(var->width + 5) |
+ LCM_CRTC_HR_SVAL(var->width + 1);
+ regs->lcd_crtc_hsync = LCM_CRTC_HSYNC_EVAL(hsync + var->hsync_len) |
+ LCM_CRTC_HSYNC_SVAL(hsync);
+ regs->lcd_crtc_vr = LCM_CRTC_VR_EVAL(vsync + var->vsync_len) |
+ LCM_CRTC_VR_SVAL(vsync);
+
+}
+
+/*
+ * Activate (set) the controller from the given framebuffer
+ * information
+ */
+static void nuc900fb_activate_var(struct fb_info *info)
+{
+ struct nuc900fb_info *fbi = info->par;
+ void __iomem *regs = fbi->io;
+ struct fb_var_screeninfo *var = &info->var;
+ int clkdiv;
+
+ clkdiv = nuc900fb_calc_pixclk(fbi, var->pixclock) - 1;
+ if (clkdiv < 0)
+ clkdiv = 0;
+
+ nuc900fb_calculate_lcd_regs(info, &fbi->regs);
+
+ /* set the new lcd registers*/
+
+ dev_dbg(fbi->dev, "new lcd register set:\n");
+ dev_dbg(fbi->dev, "dccs = 0x%08x\n", fbi->regs.lcd_dccs);
+ dev_dbg(fbi->dev, "dev_ctl = 0x%08x\n", fbi->regs.lcd_device_ctrl);
+ dev_dbg(fbi->dev, "crtc_size = 0x%08x\n", fbi->regs.lcd_crtc_size);
+ dev_dbg(fbi->dev, "crtc_dend = 0x%08x\n", fbi->regs.lcd_crtc_dend);
+ dev_dbg(fbi->dev, "crtc_hr = 0x%08x\n", fbi->regs.lcd_crtc_hr);
+ dev_dbg(fbi->dev, "crtc_hsync = 0x%08x\n", fbi->regs.lcd_crtc_hsync);
+ dev_dbg(fbi->dev, "crtc_vr = 0x%08x\n", fbi->regs.lcd_crtc_vr);
+
+ writel(fbi->regs.lcd_device_ctrl, regs + REG_LCM_DEV_CTRL);
+ writel(fbi->regs.lcd_crtc_size, regs + REG_LCM_CRTC_SIZE);
+ writel(fbi->regs.lcd_crtc_dend, regs + REG_LCM_CRTC_DEND);
+ writel(fbi->regs.lcd_crtc_hr, regs + REG_LCM_CRTC_HR);
+ writel(fbi->regs.lcd_crtc_hsync, regs + REG_LCM_CRTC_HSYNC);
+ writel(fbi->regs.lcd_crtc_vr, regs + REG_LCM_CRTC_VR);
+
+ /* set lcd address pointers */
+ nuc900fb_set_lcdaddr(info);
+
+ writel(fbi->regs.lcd_dccs, regs + REG_LCM_DCCS);
+}
+
+/*
+ * Alters the hardware state.
+ *
+ */
+static int nuc900fb_set_par(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+
+ switch (var->bits_per_pixel) {
+ case 32:
+ case 24:
+ case 18:
+ case 16:
+ case 12:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ break;
+ case 1:
+ info->fix.visual = FB_VISUAL_MONO01;
+ break;
+ default:
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+ }
+
+ info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
+
+ /* activate this new configuration */
+ nuc900fb_activate_var(info);
+ return 0;
+}
+
+static inline unsigned int chan_to_field(unsigned int chan,
+ struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int nuc900fb_setcolreg(unsigned regno,
+ unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *info)
+{
+ unsigned int val;
+
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ /* true-colour, use pseuo-palette */
+ if (regno < 16) {
+ u32 *pal = info->pseudo_palette;
+
+ val = chan_to_field(red, &info->var.red);
+ val |= chan_to_field(green, &info->var.green);
+ val |= chan_to_field(blue, &info->var.blue);
+ pal[regno] = val;
+ }
+ break;
+
+ default:
+ return 1; /* unknown type */
+ }
+ return 0;
+}
+
+/**
+ * nuc900fb_blank
+ *
+ */
+static int nuc900fb_blank(int blank_mode, struct fb_info *info)
+{
+
+ return 0;
+}
+
+static struct fb_ops nuc900fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = nuc900fb_check_var,
+ .fb_set_par = nuc900fb_set_par,
+ .fb_blank = nuc900fb_blank,
+ .fb_setcolreg = nuc900fb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+
+static inline void modify_gpio(void __iomem *reg,
+ unsigned long set, unsigned long mask)
+{
+ unsigned long tmp;
+ tmp = readl(reg) & ~mask;
+ writel(tmp | set, reg);
+}
+
+/*
+ * Initialise LCD-related registers
+ */
+static int nuc900fb_init_registers(struct fb_info *info)
+{
+ struct nuc900fb_info *fbi = info->par;
+ struct nuc900fb_mach_info *mach_info = fbi->dev->platform_data;
+ void __iomem *regs = fbi->io;
+
+ /*reset the display engine*/
+ writel(0, regs + REG_LCM_DCCS);
+ writel(readl(regs + REG_LCM_DCCS) | LCM_DCCS_ENG_RST,
+ regs + REG_LCM_DCCS);
+ ndelay(100);
+ writel(readl(regs + REG_LCM_DCCS) & (~LCM_DCCS_ENG_RST),
+ regs + REG_LCM_DCCS);
+ ndelay(100);
+
+ writel(0, regs + REG_LCM_DEV_CTRL);
+
+ /* config gpio output */
+ modify_gpio(W90X900_VA_GPIO + 0x54, mach_info->gpio_dir,
+ mach_info->gpio_dir_mask);
+ modify_gpio(W90X900_VA_GPIO + 0x58, mach_info->gpio_data,
+ mach_info->gpio_data_mask);
+
+ return 0;
+}
+
+
+/*
+ * Alloc the SDRAM region of NUC900 for the frame buffer.
+ * The buffer should be a non-cached, non-buffered, memory region
+ * to allow palette and pixel writes without flushing the cache.
+ */
+static int __init nuc900fb_map_video_memory(struct fb_info *info)
+{
+ struct nuc900fb_info *fbi = info->par;
+ dma_addr_t map_dma;
+ unsigned long map_size = PAGE_ALIGN(info->fix.smem_len);
+
+ dev_dbg(fbi->dev, "nuc900fb_map_video_memory(fbi=%p) map_size %lu\n",
+ fbi, map_size);
+
+ info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,
+ &map_dma, GFP_KERNEL);
+
+ if (!info->screen_base)
+ return -ENOMEM;
+
+ memset(info->screen_base, 0x00, map_size);
+ info->fix.smem_start = map_dma;
+
+ return 0;
+}
+
+static inline void nuc900fb_unmap_video_memory(struct fb_info *info)
+{
+ struct nuc900fb_info *fbi = info->par;
+ dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
+ info->screen_base, info->fix.smem_start);
+}
+
+static irqreturn_t nuc900fb_irqhandler(int irq, void *dev_id)
+{
+ struct nuc900fb_info *fbi = dev_id;
+ void __iomem *regs = fbi->io;
+ void __iomem *irq_base = fbi->irq_base;
+ unsigned long lcdirq = readl(regs + REG_LCM_INT_CS);
+
+ if (lcdirq & LCM_INT_CS_DISP_F_STATUS) {
+ writel(readl(irq_base) | 1<<30, irq_base);
+
+ /* wait VA_EN low */
+ if ((readl(regs + REG_LCM_DCCS) &
+ LCM_DCCS_SINGLE) == LCM_DCCS_SINGLE)
+ while ((readl(regs + REG_LCM_DCCS) &
+ LCM_DCCS_VA_EN) == LCM_DCCS_VA_EN)
+ ;
+ /* display_out-enable */
+ writel(readl(regs + REG_LCM_DCCS) | LCM_DCCS_DISP_OUT_EN,
+ regs + REG_LCM_DCCS);
+ /* va-enable*/
+ writel(readl(regs + REG_LCM_DCCS) | LCM_DCCS_VA_EN,
+ regs + REG_LCM_DCCS);
+ } else if (lcdirq & LCM_INT_CS_UNDERRUN_INT) {
+ writel(readl(irq_base) | LCM_INT_CS_UNDERRUN_INT, irq_base);
+ } else if (lcdirq & LCM_INT_CS_BUS_ERROR_INT) {
+ writel(readl(irq_base) | LCM_INT_CS_BUS_ERROR_INT, irq_base);
+ }
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_CPU_FREQ
+
+static int nuc900fb_cpufreq_transition(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct nuc900fb_info *info;
+ struct fb_info *fbinfo;
+ long delta_f;
+ info = container_of(nb, struct nuc900fb_info, freq_transition);
+ fbinfo = platform_get_drvdata(to_platform_device(info->dev));
+
+ delta_f = info->clk_rate - clk_get_rate(info->clk);
+
+ if ((val == CPUFREQ_POSTCHANGE && delta_f > 0) ||
+ (val == CPUFREQ_PRECHANGE && delta_f < 0)) {
+ info->clk_rate = clk_get_rate(info->clk);
+ nuc900fb_activate_var(fbinfo);
+ }
+
+ return 0;
+}
+
+static inline int nuc900fb_cpufreq_register(struct nuc900fb_info *fbi)
+{
+ fbi->freq_transition.notifier_call = nuc900fb_cpufreq_transition;
+ return cpufreq_register_notifier(&fbi->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void nuc900fb_cpufreq_deregister(struct nuc900fb_info *fbi)
+{
+ cpufreq_unregister_notifier(&fbi->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+#else
+static inline int nuc900fb_cpufreq_transition(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ return 0;
+}
+
+static inline int nuc900fb_cpufreq_register(struct nuc900fb_info *fbi)
+{
+ return 0;
+}
+
+static inline void nuc900fb_cpufreq_deregister(struct nuc900fb_info *info)
+{
+}
+#endif
+
+static char driver_name[] = "nuc900fb";
+
+static int __devinit nuc900fb_probe(struct platform_device *pdev)
+{
+ struct nuc900fb_info *fbi;
+ struct nuc900fb_display *display;
+ struct fb_info *fbinfo;
+ struct nuc900fb_mach_info *mach_info;
+ struct resource *res;
+ int ret;
+ int irq;
+ int i;
+ int size;
+
+ dev_dbg(&pdev->dev, "devinit\n");
+ mach_info = pdev->dev.platform_data;
+ if (mach_info == NULL) {
+ dev_err(&pdev->dev,
+ "no platform data for lcd, cannot attach\n");
+ return -EINVAL;
+ }
+
+ if (mach_info->default_display > mach_info->num_displays) {
+ dev_err(&pdev->dev,
+ "default display No. is %d but only %d displays \n",
+ mach_info->default_display, mach_info->num_displays);
+ return -EINVAL;
+ }
+
+
+ display = mach_info->displays + mach_info->default_display;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq for device\n");
+ return -ENOENT;
+ }
+
+ fbinfo = framebuffer_alloc(sizeof(struct nuc900fb_info), &pdev->dev);
+ if (!fbinfo)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, fbinfo);
+
+ fbi = fbinfo->par;
+ fbi->dev = &pdev->dev;
+
+#ifdef CONFIG_CPU_NUC950
+ fbi->drv_type = LCDDRV_NUC950;
+#endif
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ size = (res->end - res->start) + 1;
+ fbi->mem = request_mem_region(res->start, size, pdev->name);
+ if (fbi->mem == NULL) {
+ dev_err(&pdev->dev, "failed to alloc memory region\n");
+ ret = -ENOENT;
+ goto free_fb;
+ }
+
+ fbi->io = ioremap(res->start, size);
+ if (fbi->io == NULL) {
+ dev_err(&pdev->dev, "ioremap() of lcd registers failed\n");
+ ret = -ENXIO;
+ goto release_mem_region;
+ }
+
+ fbi->irq_base = fbi->io + REG_LCM_INT_CS;
+
+
+ /* Stop the LCD */
+ writel(0, fbi->io + REG_LCM_DCCS);
+
+ /* fill the fbinfo*/
+ strcpy(fbinfo->fix.id, driver_name);
+ fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
+ fbinfo->fix.type_aux = 0;
+ fbinfo->fix.xpanstep = 0;
+ fbinfo->fix.ypanstep = 0;
+ fbinfo->fix.ywrapstep = 0;
+ fbinfo->fix.accel = FB_ACCEL_NONE;
+ fbinfo->var.nonstd = 0;
+ fbinfo->var.activate = FB_ACTIVATE_NOW;
+ fbinfo->var.accel_flags = 0;
+ fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
+ fbinfo->fbops = &nuc900fb_ops;
+ fbinfo->flags = FBINFO_FLAG_DEFAULT;
+ fbinfo->pseudo_palette = &fbi->pseudo_pal;
+
+ ret = request_irq(irq, nuc900fb_irqhandler, IRQF_DISABLED,
+ pdev->name, fbinfo);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n",
+ irq, ret);
+ ret = -EBUSY;
+ goto release_regs;
+ }
+
+ nuc900_driver_clksrc_div(&pdev->dev, "ext", 0x2);
+
+ fbi->clk = clk_get(&pdev->dev, NULL);
+ if (!fbi->clk || IS_ERR(fbi->clk)) {
+ printk(KERN_ERR "nuc900-lcd:failed to get lcd clock source\n");
+ ret = -ENOENT;
+ goto release_irq;
+ }
+
+ clk_enable(fbi->clk);
+ dev_dbg(&pdev->dev, "got and enabled clock\n");
+
+ fbi->clk_rate = clk_get_rate(fbi->clk);
+
+ /* calutate the video buffer size */
+ for (i = 0; i < mach_info->num_displays; i++) {
+ unsigned long smem_len = mach_info->displays[i].xres;
+ smem_len *= mach_info->displays[i].yres;
+ smem_len *= mach_info->displays[i].bpp;
+ smem_len >>= 3;
+ if (fbinfo->fix.smem_len < smem_len)
+ fbinfo->fix.smem_len = smem_len;
+ }
+
+ /* Initialize Video Memory */
+ ret = nuc900fb_map_video_memory(fbinfo);
+ if (ret) {
+ printk(KERN_ERR "Failed to allocate video RAM: %x\n", ret);
+ goto release_clock;
+ }
+
+ dev_dbg(&pdev->dev, "got video memory\n");
+
+ fbinfo->var.xres = display->xres;
+ fbinfo->var.yres = display->yres;
+ fbinfo->var.bits_per_pixel = display->bpp;
+
+ nuc900fb_init_registers(fbinfo);
+
+ nuc900fb_check_var(&fbinfo->var, fbinfo);
+
+ ret = nuc900fb_cpufreq_register(fbi);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register cpufreq\n");
+ goto free_video_memory;
+ }
+
+ ret = register_framebuffer(fbinfo);
+ if (ret) {
+ printk(KERN_ERR "failed to register framebuffer device: %d\n",
+ ret);
+ goto free_cpufreq;
+ }
+
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ fbinfo->node, fbinfo->fix.id);
+
+ return 0;
+
+free_cpufreq:
+ nuc900fb_cpufreq_deregister(fbi);
+free_video_memory:
+ nuc900fb_unmap_video_memory(fbinfo);
+release_clock:
+ clk_disable(fbi->clk);
+ clk_put(fbi->clk);
+release_irq:
+ free_irq(irq, fbi);
+release_regs:
+ iounmap(fbi->io);
+release_mem_region:
+ release_mem_region((unsigned long)fbi->mem, size);
+free_fb:
+ framebuffer_release(fbinfo);
+ return ret;
+}
+
+/*
+ * shutdown the lcd controller
+ */
+static void nuc900fb_stop_lcd(struct fb_info *info)
+{
+ struct nuc900fb_info *fbi = info->par;
+ void __iomem *regs = fbi->io;
+
+ writel((~LCM_DCCS_DISP_INT_EN) | (~LCM_DCCS_VA_EN) | (~LCM_DCCS_OSD_EN),
+ regs + REG_LCM_DCCS);
+}
+
+/*
+ * Cleanup
+ */
+static int nuc900fb_remove(struct platform_device *pdev)
+{
+ struct fb_info *fbinfo = platform_get_drvdata(pdev);
+ struct nuc900fb_info *fbi = fbinfo->par;
+ int irq;
+
+ nuc900fb_stop_lcd(fbinfo);
+ msleep(1);
+
+ nuc900fb_unmap_video_memory(fbinfo);
+
+ iounmap(fbi->io);
+
+ irq = platform_get_irq(pdev, 0);
+ free_irq(irq, fbi);
+
+ release_resource(fbi->mem);
+ kfree(fbi->mem);
+
+ platform_set_drvdata(pdev, NULL);
+ framebuffer_release(fbinfo);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * suspend and resume support for the lcd controller
+ */
+
+static int nuc900fb_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct fb_info *fbinfo = platform_get_drvdata(dev);
+ struct nuc900fb_info *info = fbinfo->par;
+
+ nuc900fb_stop_lcd();
+ msleep(1);
+ clk_disable(info->clk);
+ return 0;
+}
+
+static int nuc900fb_resume(struct platform_device *dev)
+{
+ struct fb_info *fbinfo = platform_get_drvdata(dev);
+ struct nuc900fb_info *fbi = fbinfo->par;
+
+ printk(KERN_INFO "nuc900fb resume\n");
+
+ clk_enable(fbi->clk);
+ msleep(1);
+
+ nuc900fb_init_registers(fbinfo);
+ nuc900fb_activate_var(bfinfo);
+
+ return 0;
+}
+
+#else
+#define nuc900fb_suspend NULL
+#define nuc900fb_resume NULL
+#endif
+
+static struct platform_driver nuc900fb_driver = {
+ .probe = nuc900fb_probe,
+ .remove = nuc900fb_remove,
+ .suspend = nuc900fb_suspend,
+ .resume = nuc900fb_resume,
+ .driver = {
+ .name = "nuc900-lcd",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __devinit nuc900fb_init(void)
+{
+ return platform_driver_register(&nuc900fb_driver);
+}
+
+static void __exit nuc900fb_cleanup(void)
+{
+ platform_driver_unregister(&nuc900fb_driver);
+}
+
+module_init(nuc900fb_init);
+module_exit(nuc900fb_cleanup);
+
+MODULE_DESCRIPTION("Framebuffer driver for the NUC900");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/nuc900fb.h b/drivers/video/nuc900fb.h
new file mode 100644
index 000000000000..6c23aa3d3b89
--- /dev/null
+++ b/drivers/video/nuc900fb.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright (c) 2009 Nuvoton technology 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.
+ *
+ * Auther:
+ * Wang Qiang(rurality.linux@gmail.com) 2009/12/16
+ */
+
+#ifndef __NUC900FB_H
+#define __NUC900FB_H
+
+#include <mach/map.h>
+#include <mach/fb.h>
+
+enum nuc900_lcddrv_type {
+ LCDDRV_NUC910,
+ LCDDRV_NUC930,
+ LCDDRV_NUC932,
+ LCDDRV_NUC950,
+ LCDDRV_NUC960,
+};
+
+
+#define PALETTE_BUFFER_SIZE 256
+#define PALETTE_BUFF_CLEAR (0x80000000) /* entry is clear/invalid */
+
+struct nuc900fb_info {
+ struct device *dev;
+ struct clk *clk;
+
+ struct resource *mem;
+ void __iomem *io;
+ void __iomem *irq_base;
+ int drv_type;
+ struct nuc900fb_hw regs;
+ unsigned long clk_rate;
+
+#ifdef CONFIG_CPU_FREQ
+ struct notifier_block freq_transition;
+#endif
+
+ /* keep these registers in case we need to re-write palette */
+ u32 palette_buffer[PALETTE_BUFFER_SIZE];
+ u32 pseudo_pal[16];
+};
+
+int nuc900fb_init(void);
+
+#endif /* __NUC900FB_H */
diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c
index 567db6ac32c8..6978ae4ef83a 100644
--- a/drivers/video/omap/lcd_ams_delta.c
+++ b/drivers/video/omap/lcd_ams_delta.c
@@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/lcd.h>
#include <plat/board-ams-delta.h>
#include <mach/hardware.h>
@@ -32,6 +33,71 @@
#define AMS_DELTA_DEFAULT_CONTRAST 112
+#define AMS_DELTA_MAX_CONTRAST 0x00FF
+#define AMS_DELTA_LCD_POWER 0x0100
+
+
+/* LCD class device section */
+
+static int ams_delta_lcd;
+
+static int ams_delta_lcd_set_power(struct lcd_device *dev, int power)
+{
+ if (power == FB_BLANK_UNBLANK) {
+ if (!(ams_delta_lcd & AMS_DELTA_LCD_POWER)) {
+ omap_writeb(ams_delta_lcd & AMS_DELTA_MAX_CONTRAST,
+ OMAP_PWL_ENABLE);
+ omap_writeb(1, OMAP_PWL_CLK_ENABLE);
+ ams_delta_lcd |= AMS_DELTA_LCD_POWER;
+ }
+ } else {
+ if (ams_delta_lcd & AMS_DELTA_LCD_POWER) {
+ omap_writeb(0, OMAP_PWL_ENABLE);
+ omap_writeb(0, OMAP_PWL_CLK_ENABLE);
+ ams_delta_lcd &= ~AMS_DELTA_LCD_POWER;
+ }
+ }
+ return 0;
+}
+
+static int ams_delta_lcd_set_contrast(struct lcd_device *dev, int value)
+{
+ if ((value >= 0) && (value <= AMS_DELTA_MAX_CONTRAST)) {
+ omap_writeb(value, OMAP_PWL_ENABLE);
+ ams_delta_lcd &= ~AMS_DELTA_MAX_CONTRAST;
+ ams_delta_lcd |= value;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_LCD_CLASS_DEVICE
+static int ams_delta_lcd_get_power(struct lcd_device *dev)
+{
+ if (ams_delta_lcd & AMS_DELTA_LCD_POWER)
+ return FB_BLANK_UNBLANK;
+ else
+ return FB_BLANK_POWERDOWN;
+}
+
+static int ams_delta_lcd_get_contrast(struct lcd_device *dev)
+{
+ if (!(ams_delta_lcd & AMS_DELTA_LCD_POWER))
+ return 0;
+
+ return ams_delta_lcd & AMS_DELTA_MAX_CONTRAST;
+}
+
+static struct lcd_ops ams_delta_lcd_ops = {
+ .get_power = ams_delta_lcd_get_power,
+ .set_power = ams_delta_lcd_set_power,
+ .get_contrast = ams_delta_lcd_get_contrast,
+ .set_contrast = ams_delta_lcd_set_contrast,
+};
+#endif
+
+
+/* omapfb panel section */
+
static int ams_delta_panel_init(struct lcd_panel *panel,
struct omapfb_device *fbdev)
{
@@ -48,10 +114,6 @@ static int ams_delta_panel_enable(struct lcd_panel *panel)
AMS_DELTA_LATCH2_LCD_NDISP);
ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN,
AMS_DELTA_LATCH2_LCD_VBLEN);
-
- omap_writeb(1, OMAP_PWL_CLK_ENABLE);
- omap_writeb(AMS_DELTA_DEFAULT_CONTRAST, OMAP_PWL_ENABLE);
-
return 0;
}
@@ -91,8 +153,31 @@ static struct lcd_panel ams_delta_panel = {
.get_caps = ams_delta_panel_get_caps,
};
+
+/* platform driver section */
+
static int ams_delta_panel_probe(struct platform_device *pdev)
{
+ struct lcd_device *lcd_device = NULL;
+#ifdef CONFIG_LCD_CLASS_DEVICE
+ int ret;
+
+ lcd_device = lcd_device_register("omapfb", &pdev->dev, NULL,
+ &ams_delta_lcd_ops);
+
+ if (IS_ERR(lcd_device)) {
+ ret = PTR_ERR(lcd_device);
+ dev_err(&pdev->dev, "failed to register device\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, lcd_device);
+ lcd_device->props.max_contrast = AMS_DELTA_MAX_CONTRAST;
+#endif
+
+ ams_delta_lcd_set_contrast(lcd_device, AMS_DELTA_DEFAULT_CONTRAST);
+ ams_delta_lcd_set_power(lcd_device, FB_BLANK_UNBLANK);
+
omapfb_register_panel(&ams_delta_panel);
return 0;
}
diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c
index a33483910dc8..9557f963662e 100644
--- a/drivers/video/omap/lcdc.c
+++ b/drivers/video/omap/lcdc.c
@@ -389,7 +389,7 @@ static int omap_lcdc_enable_plane(int plane, int enable)
/*
* Configure the LCD DMA for a palette load operation and do the palette
* downloading synchronously. We don't use the frame+palette load mode of
- * the controller, since the palette can always be downloaded seperately.
+ * the controller, since the palette can always be downloaded separately.
*/
static void load_palette(void)
{
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
index 2c4f470fa086..8ce60e1b220a 100644
--- a/drivers/video/omap/omapfb_main.c
+++ b/drivers/video/omap/omapfb_main.c
@@ -486,10 +486,11 @@ static int set_color_mode(struct omapfb_plane_struct *plane,
return 0;
case 12:
var->bits_per_pixel = 16;
- plane->color_mode = OMAPFB_COLOR_RGB444;
- return 0;
case 16:
- plane->color_mode = OMAPFB_COLOR_RGB565;
+ if (plane->fbdev->panel->bpp == 12)
+ plane->color_mode = OMAPFB_COLOR_RGB444;
+ else
+ plane->color_mode = OMAPFB_COLOR_RGB565;
return 0;
default:
return -EINVAL;
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index b12a59c9c50a..dfb57ee50861 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -13,10 +13,28 @@ config PANEL_SHARP_LS037V7DW01
help
LCD Panel used in TI's SDP3430 and EVM boards
+config PANEL_SHARP_LQ043T1DG01
+ tristate "Sharp LQ043T1DG01 LCD Panel"
+ depends on OMAP2_DSS
+ help
+ LCD Panel used in TI's OMAP3517 EVM boards
+
config PANEL_TAAL
tristate "Taal DSI Panel"
depends on OMAP2_DSS_DSI
help
Taal DSI command mode panel from TPO.
+config PANEL_TOPPOLY_TDO35S
+ tristate "Toppoly TDO35S LCD Panel support"
+ depends on OMAP2_DSS
+ help
+ LCD Panel used in CM-T35
+
+config PANEL_TPO_TD043MTEA1
+ tristate "TPO TD043MTEA1 LCD Panel"
+ depends on OMAP2_DSS && I2C
+ help
+ LCD Panel used in OMAP3 Pandora
+
endmenu
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
index 955646440b3a..e2bb32168dee 100644
--- a/drivers/video/omap2/displays/Makefile
+++ b/drivers/video/omap2/displays/Makefile
@@ -1,4 +1,7 @@
obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
+obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o
obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
+obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o
+obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
diff --git a/drivers/video/omap2/displays/panel-generic.c b/drivers/video/omap2/displays/panel-generic.c
index eb48d1afd800..c59e4baed8b2 100644
--- a/drivers/video/omap2/displays/panel-generic.c
+++ b/drivers/video/omap2/displays/panel-generic.c
@@ -35,6 +35,35 @@ static struct omap_video_timings generic_panel_timings = {
.vbp = 7,
};
+static int generic_panel_power_on(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ r = omapdss_dpi_display_enable(dssdev);
+ if (r)
+ goto err0;
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto err1;
+ }
+
+ return 0;
+err1:
+ omapdss_dpi_display_disable(dssdev);
+err0:
+ return r;
+}
+
+static void generic_panel_power_off(struct omap_dss_device *dssdev)
+{
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ omapdss_dpi_display_disable(dssdev);
+}
+
static int generic_panel_probe(struct omap_dss_device *dssdev)
{
dssdev->panel.config = OMAP_DSS_LCD_TFT;
@@ -51,27 +80,40 @@ static int generic_panel_enable(struct omap_dss_device *dssdev)
{
int r = 0;
- if (dssdev->platform_enable)
- r = dssdev->platform_enable(dssdev);
+ r = generic_panel_power_on(dssdev);
+ if (r)
+ return r;
- return r;
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
}
static void generic_panel_disable(struct omap_dss_device *dssdev)
{
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
+ generic_panel_power_off(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int generic_panel_suspend(struct omap_dss_device *dssdev)
{
- generic_panel_disable(dssdev);
+ generic_panel_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int generic_panel_resume(struct omap_dss_device *dssdev)
{
- return generic_panel_enable(dssdev);
+ int r = 0;
+
+ r = generic_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
}
static struct omap_dss_driver generic_driver = {
diff --git a/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c b/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c
new file mode 100644
index 000000000000..10267461991c
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c
@@ -0,0 +1,159 @@
+/*
+ * LCD panel driver for Sharp LQ043T1DG01
+ *
+ * Copyright (C) 2009 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@ti.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.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+
+#include <plat/display.h>
+
+static struct omap_video_timings sharp_lq_timings = {
+ .x_res = 480,
+ .y_res = 272,
+
+ .pixel_clock = 9000,
+
+ .hsw = 42,
+ .hfp = 3,
+ .hbp = 2,
+
+ .vsw = 11,
+ .vfp = 3,
+ .vbp = 2,
+};
+
+static int sharp_lq_panel_power_on(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ r = omapdss_dpi_display_enable(dssdev);
+ if (r)
+ goto err0;
+
+ /* wait couple of vsyncs until enabling the LCD */
+ msleep(50);
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto err1;
+ }
+
+ return 0;
+err1:
+ omapdss_dpi_display_disable(dssdev);
+err0:
+ return r;
+}
+
+static void sharp_lq_panel_power_off(struct omap_dss_device *dssdev)
+{
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ /* wait at least 5 vsyncs after disabling the LCD */
+ msleep(100);
+
+ omapdss_dpi_display_disable(dssdev);
+}
+
+static int sharp_lq_panel_probe(struct omap_dss_device *dssdev)
+{
+
+ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+ OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO;
+ dssdev->panel.acb = 0x0;
+ dssdev->panel.timings = sharp_lq_timings;
+
+ return 0;
+}
+
+static void sharp_lq_panel_remove(struct omap_dss_device *dssdev)
+{
+}
+
+static int sharp_lq_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ r = sharp_lq_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void sharp_lq_panel_disable(struct omap_dss_device *dssdev)
+{
+ sharp_lq_panel_power_off(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static int sharp_lq_panel_suspend(struct omap_dss_device *dssdev)
+{
+ sharp_lq_panel_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+ return 0;
+}
+
+static int sharp_lq_panel_resume(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ r = sharp_lq_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static struct omap_dss_driver sharp_lq_driver = {
+ .probe = sharp_lq_panel_probe,
+ .remove = sharp_lq_panel_remove,
+
+ .enable = sharp_lq_panel_enable,
+ .disable = sharp_lq_panel_disable,
+ .suspend = sharp_lq_panel_suspend,
+ .resume = sharp_lq_panel_resume,
+
+ .driver = {
+ .name = "sharp_lq_panel",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sharp_lq_panel_drv_init(void)
+{
+ return omap_dss_register_driver(&sharp_lq_driver);
+}
+
+static void __exit sharp_lq_panel_drv_exit(void)
+{
+ omap_dss_unregister_driver(&sharp_lq_driver);
+}
+
+module_init(sharp_lq_panel_drv_init);
+module_exit(sharp_lq_panel_drv_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
index bbe880bbe795..8d51a5e6341c 100644
--- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
+++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
@@ -20,19 +20,10 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <plat/display.h>
-struct sharp_data {
- /* XXX This regulator should actually be in SDP board file, not here,
- * as it doesn't actually power the LCD, but something else that
- * affects the output to LCD (I think. Somebody clarify). It doesn't do
- * harm here, as SDP is the only board using this currently */
- struct regulator *vdvi_reg;
-};
-
static struct omap_video_timings sharp_ls_timings = {
.x_res = 480,
.y_res = 640,
@@ -50,77 +41,81 @@ static struct omap_video_timings sharp_ls_timings = {
static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
{
- struct sharp_data *sd;
-
dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS;
dssdev->panel.acb = 0x28;
dssdev->panel.timings = sharp_ls_timings;
- sd = kzalloc(sizeof(*sd), GFP_KERNEL);
- if (!sd)
- return -ENOMEM;
-
- dev_set_drvdata(&dssdev->dev, sd);
-
- sd->vdvi_reg = regulator_get(&dssdev->dev, "vdvi");
- if (IS_ERR(sd->vdvi_reg)) {
- kfree(sd);
- pr_err("failed to get VDVI regulator\n");
- return PTR_ERR(sd->vdvi_reg);
- }
-
return 0;
}
static void sharp_ls_panel_remove(struct omap_dss_device *dssdev)
{
- struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
-
- regulator_put(sd->vdvi_reg);
-
- kfree(sd);
}
-static int sharp_ls_panel_enable(struct omap_dss_device *dssdev)
+static int sharp_ls_power_on(struct omap_dss_device *dssdev)
{
- struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
int r = 0;
+ r = omapdss_dpi_display_enable(dssdev);
+ if (r)
+ goto err0;
+
/* wait couple of vsyncs until enabling the LCD */
msleep(50);
- regulator_enable(sd->vdvi_reg);
-
- if (dssdev->platform_enable)
+ if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto err1;
+ }
+ return 0;
+err1:
+ omapdss_dpi_display_disable(dssdev);
+err0:
return r;
}
-static void sharp_ls_panel_disable(struct omap_dss_device *dssdev)
+static void sharp_ls_power_off(struct omap_dss_device *dssdev)
{
- struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
-
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
- regulator_disable(sd->vdvi_reg);
-
/* wait at least 5 vsyncs after disabling the LCD */
msleep(100);
+
+ omapdss_dpi_display_disable(dssdev);
+}
+
+static int sharp_ls_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r;
+ r = sharp_ls_power_on(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ return r;
+}
+
+static void sharp_ls_panel_disable(struct omap_dss_device *dssdev)
+{
+ sharp_ls_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int sharp_ls_panel_suspend(struct omap_dss_device *dssdev)
{
- sharp_ls_panel_disable(dssdev);
+ sharp_ls_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int sharp_ls_panel_resume(struct omap_dss_device *dssdev)
{
- return sharp_ls_panel_enable(dssdev);
+ int r;
+ r = sharp_ls_power_on(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ return r;
}
static struct omap_dss_driver sharp_ls_driver = {
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 1f01dfc5e52e..fcd6a61a91eb 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -63,6 +63,8 @@
/* #define TAAL_USE_ESD_CHECK */
#define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000)
+static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
+
struct taal_data {
struct backlight_device *bldev;
@@ -510,15 +512,12 @@ static int taal_probe(struct omap_dss_device *dssdev)
if (td->esd_wq == NULL) {
dev_err(&dssdev->dev, "can't create ESD workqueue\n");
r = -ENOMEM;
- goto err2;
+ goto err1;
}
INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
dev_set_drvdata(&dssdev->dev, td);
- dssdev->get_timings = taal_get_timings;
- dssdev->get_resolution = taal_get_resolution;
-
/* if no platform set_backlight() defined, presume DSI backlight
* control */
if (!dssdev->set_backlight)
@@ -528,7 +527,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
&taal_bl_ops);
if (IS_ERR(bldev)) {
r = PTR_ERR(bldev);
- goto err1;
+ goto err2;
}
td->bldev = bldev;
@@ -621,14 +620,12 @@ static void taal_remove(struct omap_dss_device *dssdev)
kfree(td);
}
-static int taal_enable(struct omap_dss_device *dssdev)
+static int taal_power_on(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
u8 id1, id2, id3;
int r;
- dev_dbg(&dssdev->dev, "enable\n");
-
if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
if (r)
@@ -638,6 +635,16 @@ static int taal_enable(struct omap_dss_device *dssdev)
/* it seems we have to wait a bit until taal is ready */
msleep(5);
+ dsi_bus_lock();
+
+ r = omapdss_dsi_display_enable(dssdev);
+ if (r) {
+ dev_err(&dssdev->dev, "failed to enable DSI\n");
+ goto err0;
+ }
+
+ omapdss_dsi_vc_enable_hs(TCH, false);
+
r = taal_sleep_out(td);
if (r)
goto err;
@@ -661,6 +668,10 @@ static int taal_enable(struct omap_dss_device *dssdev)
taal_dcs_write_0(DCS_DISPLAY_ON);
+ r = _taal_enable_te(dssdev, td->te_enabled);
+ if (r)
+ goto err;
+
#ifdef TAAL_USE_ESD_CHECK
queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
#endif
@@ -676,19 +687,27 @@ static int taal_enable(struct omap_dss_device *dssdev)
td->intro_printed = true;
}
+ omapdss_dsi_vc_enable_hs(TCH, true);
+
+ dsi_bus_unlock();
+
return 0;
err:
+ dsi_bus_unlock();
+
+ omapdss_dsi_display_disable(dssdev);
+err0:
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
return r;
}
-static void taal_disable(struct omap_dss_device *dssdev)
+static void taal_power_off(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- dev_dbg(&dssdev->dev, "disable\n");
+ dsi_bus_lock();
cancel_delayed_work(&td->esd_work);
@@ -698,41 +717,124 @@ static void taal_disable(struct omap_dss_device *dssdev)
/* wait a bit so that the message goes through */
msleep(10);
+ omapdss_dsi_display_disable(dssdev);
+
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
td->enabled = 0;
+
+ dsi_bus_unlock();
+}
+
+static int taal_enable(struct omap_dss_device *dssdev)
+{
+ int r;
+ dev_dbg(&dssdev->dev, "enable\n");
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
+ return -EINVAL;
+
+ r = taal_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return r;
+}
+
+static void taal_disable(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "disable\n");
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ taal_power_off(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int taal_suspend(struct omap_dss_device *dssdev)
{
- struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- struct backlight_device *bldev = td->bldev;
+ dev_dbg(&dssdev->dev, "suspend\n");
- bldev->props.power = FB_BLANK_POWERDOWN;
- taal_bl_update_status(bldev);
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ return -EINVAL;
+
+ taal_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int taal_resume(struct omap_dss_device *dssdev)
{
+ int r;
+ dev_dbg(&dssdev->dev, "resume\n");
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
+ return -EINVAL;
+
+ r = taal_power_on(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ return r;
+}
+
+static void taal_framedone_cb(int err, void *data)
+{
+ struct omap_dss_device *dssdev = data;
+ dev_dbg(&dssdev->dev, "framedone, err %d\n", err);
+ dsi_bus_unlock();
+}
+
+static int taal_update(struct omap_dss_device *dssdev,
+ u16 x, u16 y, u16 w, u16 h)
+{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- struct backlight_device *bldev = td->bldev;
+ int r;
- bldev->props.power = FB_BLANK_UNBLANK;
- taal_bl_update_status(bldev);
+ dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
+
+ dsi_bus_lock();
+
+ if (!td->enabled) {
+ r = 0;
+ goto err;
+ }
+
+ r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h);
+ if (r)
+ goto err;
+
+ r = taal_set_update_window(x, y, w, h);
+ if (r)
+ goto err;
+
+ r = omap_dsi_update(dssdev, TCH, x, y, w, h,
+ taal_framedone_cb, dssdev);
+ if (r)
+ goto err;
+ /* note: no bus_unlock here. unlock is in framedone_cb */
return 0;
+err:
+ dsi_bus_unlock();
+ return r;
}
-static void taal_setup_update(struct omap_dss_device *dssdev,
- u16 x, u16 y, u16 w, u16 h)
+static int taal_sync(struct omap_dss_device *dssdev)
{
- taal_set_update_window(x, y, w, h);
+ dev_dbg(&dssdev->dev, "sync\n");
+
+ dsi_bus_lock();
+ dsi_bus_unlock();
+
+ dev_dbg(&dssdev->dev, "sync done\n");
+
+ return 0;
}
-static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
+static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
@@ -744,25 +846,32 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
else
r = taal_dcs_write_0(DCS_TEAR_OFF);
+ omapdss_dsi_enable_te(dssdev, enable);
+
+ /* XXX for some reason, DSI TE breaks if we don't wait here.
+ * Panel bug? Needs more studying */
+ msleep(100);
+
return r;
}
-static int taal_wait_te(struct omap_dss_device *dssdev)
+static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
{
- struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- long wait = msecs_to_jiffies(500);
+ int r;
- if (!td->use_ext_te || !td->te_enabled)
- return 0;
+ dsi_bus_lock();
- INIT_COMPLETION(td->te_completion);
- wait = wait_for_completion_timeout(&td->te_completion, wait);
- if (wait == 0) {
- dev_err(&dssdev->dev, "timeout waiting TE\n");
- return -ETIME;
- }
+ r = _taal_enable_te(dssdev, enable);
- return 0;
+ dsi_bus_unlock();
+
+ return r;
+}
+
+static int taal_get_te(struct omap_dss_device *dssdev)
+{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ return td->te_enabled;
}
static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
@@ -772,16 +881,21 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
+ dsi_bus_lock();
+
if (td->enabled) {
r = taal_set_addr_mode(rotate, td->mirror);
-
if (r)
- return r;
+ goto err;
}
td->rotate = rotate;
+ dsi_bus_unlock();
return 0;
+err:
+ dsi_bus_unlock();
+ return r;
}
static u8 taal_get_rotate(struct omap_dss_device *dssdev)
@@ -797,16 +911,20 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
dev_dbg(&dssdev->dev, "mirror %d\n", enable);
+ dsi_bus_lock();
if (td->enabled) {
r = taal_set_addr_mode(td->rotate, enable);
-
if (r)
- return r;
+ goto err;
}
td->mirror = enable;
+ dsi_bus_unlock();
return 0;
+err:
+ dsi_bus_unlock();
+ return r;
}
static bool taal_get_mirror(struct omap_dss_device *dssdev)
@@ -820,17 +938,23 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
u8 id1, id2, id3;
int r;
+ dsi_bus_lock();
+
r = taal_dcs_read_1(DCS_GET_ID1, &id1);
if (r)
- return r;
+ goto err;
r = taal_dcs_read_1(DCS_GET_ID2, &id2);
if (r)
- return r;
+ goto err;
r = taal_dcs_read_1(DCS_GET_ID3, &id3);
if (r)
- return r;
+ goto err;
+ dsi_bus_unlock();
return 0;
+err:
+ dsi_bus_unlock();
+ return r;
}
static int taal_memory_read(struct omap_dss_device *dssdev,
@@ -841,6 +965,10 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
int first = 1;
int plen;
unsigned buf_used = 0;
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+ if (!td->enabled)
+ return -ENODEV;
if (size < w * h * 3)
return -ENOMEM;
@@ -849,6 +977,8 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
dssdev->panel.timings.x_res *
dssdev->panel.timings.y_res * 3);
+ dsi_bus_lock();
+
/* plen 1 or 2 goes into short packet. until checksum error is fixed,
* use short packets. plen 32 works, but bigger packets seem to cause
* an error. */
@@ -857,11 +987,11 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
else
plen = 2;
- taal_setup_update(dssdev, x, y, w, h);
+ taal_set_update_window(x, y, w, h);
r = dsi_vc_set_max_rx_packet_size(TCH, plen);
if (r)
- return r;
+ goto err0;
while (buf_used < size) {
u8 dcs_cmd = first ? 0x2e : 0x3e;
@@ -894,7 +1024,8 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
err:
dsi_vc_set_max_rx_packet_size(TCH, 1);
-
+err0:
+ dsi_bus_unlock();
return r;
}
@@ -939,8 +1070,11 @@ static void taal_esd_work(struct work_struct *work)
}
/* Self-diagnostics result is also shown on TE GPIO line. We need
* to re-enable TE after self diagnostics */
- if (td->use_ext_te && td->te_enabled)
- taal_enable_te(dssdev, true);
+ if (td->use_ext_te && td->te_enabled) {
+ r = taal_dcs_write_1(DCS_TEAR_ON, 0);
+ if (r)
+ goto err;
+ }
dsi_bus_unlock();
@@ -958,6 +1092,20 @@ err:
queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
}
+static int taal_set_update_mode(struct omap_dss_device *dssdev,
+ enum omap_dss_update_mode mode)
+{
+ if (mode != OMAP_DSS_UPDATE_MANUAL)
+ return -EINVAL;
+ return 0;
+}
+
+static enum omap_dss_update_mode taal_get_update_mode(
+ struct omap_dss_device *dssdev)
+{
+ return OMAP_DSS_UPDATE_MANUAL;
+}
+
static struct omap_dss_driver taal_driver = {
.probe = taal_probe,
.remove = taal_remove,
@@ -967,9 +1115,18 @@ static struct omap_dss_driver taal_driver = {
.suspend = taal_suspend,
.resume = taal_resume,
- .setup_update = taal_setup_update,
+ .set_update_mode = taal_set_update_mode,
+ .get_update_mode = taal_get_update_mode,
+
+ .update = taal_update,
+ .sync = taal_sync,
+
+ .get_resolution = taal_get_resolution,
+ .get_recommended_bpp = omapdss_default_get_recommended_bpp,
+
.enable_te = taal_enable_te,
- .wait_for_te = taal_wait_te,
+ .get_te = taal_get_te,
+
.set_rotate = taal_rotate,
.get_rotate = taal_get_rotate,
.set_mirror = taal_mirror,
@@ -977,6 +1134,8 @@ static struct omap_dss_driver taal_driver = {
.run_test = taal_run_test,
.memory_read = taal_memory_read,
+ .get_timings = taal_get_timings,
+
.driver = {
.name = "taal",
.owner = THIS_MODULE,
diff --git a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c
new file mode 100644
index 000000000000..fa434ca6e4b7
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c
@@ -0,0 +1,154 @@
+/*
+ * LCD panel driver for Toppoly TDO35S
+ *
+ * Copyright (C) 2009 CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on generic panel support
+ * Copyright (C) 2008 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.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.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include <plat/display.h>
+
+static struct omap_video_timings toppoly_tdo_panel_timings = {
+ /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
+ .x_res = 480,
+ .y_res = 640,
+
+ .pixel_clock = 26000,
+
+ .hfp = 104,
+ .hsw = 8,
+ .hbp = 8,
+
+ .vfp = 4,
+ .vsw = 2,
+ .vbp = 2,
+};
+
+static int toppoly_tdo_panel_power_on(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ r = omapdss_dpi_display_enable(dssdev);
+ if (r)
+ goto err0;
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto err1;
+ }
+
+ return 0;
+err1:
+ omapdss_dpi_display_disable(dssdev);
+err0:
+ return r;
+}
+
+static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev)
+{
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ omapdss_dpi_display_disable(dssdev);
+}
+
+static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev)
+{
+ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+ OMAP_DSS_LCD_IHS;
+ dssdev->panel.timings = toppoly_tdo_panel_timings;
+
+ return 0;
+}
+
+static void toppoly_tdo_panel_remove(struct omap_dss_device *dssdev)
+{
+}
+
+static int toppoly_tdo_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ r = toppoly_tdo_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void toppoly_tdo_panel_disable(struct omap_dss_device *dssdev)
+{
+ toppoly_tdo_panel_power_off(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static int toppoly_tdo_panel_suspend(struct omap_dss_device *dssdev)
+{
+ toppoly_tdo_panel_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+ return 0;
+}
+
+static int toppoly_tdo_panel_resume(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ r = toppoly_tdo_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static struct omap_dss_driver generic_driver = {
+ .probe = toppoly_tdo_panel_probe,
+ .remove = toppoly_tdo_panel_remove,
+
+ .enable = toppoly_tdo_panel_enable,
+ .disable = toppoly_tdo_panel_disable,
+ .suspend = toppoly_tdo_panel_suspend,
+ .resume = toppoly_tdo_panel_resume,
+
+ .driver = {
+ .name = "toppoly_tdo35s_panel",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init toppoly_tdo_panel_drv_init(void)
+{
+ return omap_dss_register_driver(&generic_driver);
+}
+
+static void __exit toppoly_tdo_panel_drv_exit(void)
+{
+ omap_dss_unregister_driver(&generic_driver);
+}
+
+module_init(toppoly_tdo_panel_drv_init);
+module_exit(toppoly_tdo_panel_drv_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
new file mode 100644
index 000000000000..d578feee3550
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -0,0 +1,528 @@
+/*
+ * LCD panel driver for TPO TD043MTEA1
+ *
+ * Author: Gražvydas Ignotas <notasas@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+
+#include <plat/display.h>
+
+#define TPO_R02_MODE(x) ((x) & 7)
+#define TPO_R02_MODE_800x480 7
+#define TPO_R02_NCLK_RISING BIT(3)
+#define TPO_R02_HSYNC_HIGH BIT(4)
+#define TPO_R02_VSYNC_HIGH BIT(5)
+
+#define TPO_R03_NSTANDBY BIT(0)
+#define TPO_R03_EN_CP_CLK BIT(1)
+#define TPO_R03_EN_VGL_PUMP BIT(2)
+#define TPO_R03_EN_PWM BIT(3)
+#define TPO_R03_DRIVING_CAP_100 BIT(4)
+#define TPO_R03_EN_PRE_CHARGE BIT(6)
+#define TPO_R03_SOFTWARE_CTL BIT(7)
+
+#define TPO_R04_NFLIP_H BIT(0)
+#define TPO_R04_NFLIP_V BIT(1)
+#define TPO_R04_CP_CLK_FREQ_1H BIT(2)
+#define TPO_R04_VGL_FREQ_1H BIT(4)
+
+#define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \
+ TPO_R03_EN_VGL_PUMP | TPO_R03_EN_PWM | \
+ TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \
+ TPO_R03_SOFTWARE_CTL)
+
+#define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \
+ TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL)
+
+static const u16 tpo_td043_def_gamma[12] = {
+ 106, 200, 289, 375, 460, 543, 625, 705, 785, 864, 942, 1020
+};
+
+struct tpo_td043_device {
+ struct spi_device *spi;
+ struct regulator *vcc_reg;
+ u16 gamma[12];
+ u32 mode;
+ u32 hmirror:1;
+ u32 vmirror:1;
+};
+
+static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
+{
+ struct spi_message m;
+ struct spi_transfer xfer;
+ u16 w;
+ int r;
+
+ spi_message_init(&m);
+
+ memset(&xfer, 0, sizeof(xfer));
+
+ w = ((u16)addr << 10) | (1 << 8) | data;
+ xfer.tx_buf = &w;
+ xfer.bits_per_word = 16;
+ xfer.len = 2;
+ spi_message_add_tail(&xfer, &m);
+
+ r = spi_sync(spi, &m);
+ if (r < 0)
+ dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r);
+ return r;
+}
+
+static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12])
+{
+ u8 i, val;
+
+ /* gamma bits [9:8] */
+ for (val = i = 0; i < 4; i++)
+ val |= (gamma[i] & 0x300) >> ((i + 1) * 2);
+ tpo_td043_write(spi, 0x11, val);
+
+ for (val = i = 0; i < 4; i++)
+ val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2);
+ tpo_td043_write(spi, 0x12, val);
+
+ for (val = i = 0; i < 4; i++)
+ val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2);
+ tpo_td043_write(spi, 0x13, val);
+
+ /* gamma bits [7:0] */
+ for (val = i = 0; i < 12; i++)
+ tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff);
+}
+
+static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v)
+{
+ u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V | \
+ TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H;
+ if (h)
+ reg4 &= ~TPO_R04_NFLIP_H;
+ if (v)
+ reg4 &= ~TPO_R04_NFLIP_V;
+
+ return tpo_td043_write(spi, 4, reg4);
+}
+
+static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+
+ tpo_td043->hmirror = enable;
+ return tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror,
+ tpo_td043->vmirror);
+}
+
+static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+
+ return tpo_td043->hmirror;
+}
+
+static ssize_t tpo_td043_vmirror_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->vmirror);
+}
+
+static ssize_t tpo_td043_vmirror_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+ long val;
+ int ret;
+
+ ret = strict_strtol(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ ret = tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, val);
+ if (ret < 0)
+ return ret;
+
+ tpo_td043->vmirror = val;
+
+ return count;
+}
+
+static ssize_t tpo_td043_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->mode);
+}
+
+static ssize_t tpo_td043_mode_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+ long val;
+ int ret;
+
+ ret = strict_strtol(buf, 0, &val);
+ if (ret != 0 || val & ~7)
+ return -EINVAL;
+
+ tpo_td043->mode = val;
+
+ val |= TPO_R02_NCLK_RISING;
+ tpo_td043_write(tpo_td043->spi, 2, val);
+
+ return count;
+}
+
+static ssize_t tpo_td043_gamma_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+ ssize_t len = 0;
+ int ret;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tpo_td043->gamma); i++) {
+ ret = snprintf(buf + len, PAGE_SIZE - len, "%u ",
+ tpo_td043->gamma[i]);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ }
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static ssize_t tpo_td043_gamma_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+ unsigned int g[12];
+ int ret;
+ int i;
+
+ ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u",
+ &g[0], &g[1], &g[2], &g[3], &g[4], &g[5],
+ &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
+
+ if (ret != 12)
+ return -EINVAL;
+
+ for (i = 0; i < 12; i++)
+ tpo_td043->gamma[i] = g[i];
+
+ tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma);
+
+ return count;
+}
+
+static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR,
+ tpo_td043_vmirror_show, tpo_td043_vmirror_store);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+ tpo_td043_mode_show, tpo_td043_mode_store);
+static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR,
+ tpo_td043_gamma_show, tpo_td043_gamma_store);
+
+static struct attribute *tpo_td043_attrs[] = {
+ &dev_attr_vmirror.attr,
+ &dev_attr_mode.attr,
+ &dev_attr_gamma.attr,
+ NULL,
+};
+
+static struct attribute_group tpo_td043_attr_group = {
+ .attrs = tpo_td043_attrs,
+};
+
+static const struct omap_video_timings tpo_td043_timings = {
+ .x_res = 800,
+ .y_res = 480,
+
+ .pixel_clock = 36000,
+
+ .hsw = 1,
+ .hfp = 68,
+ .hbp = 214,
+
+ .vsw = 1,
+ .vfp = 39,
+ .vbp = 34,
+};
+
+static int tpo_td043_power_on(struct omap_dss_device *dssdev)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+ int nreset_gpio = dssdev->reset_gpio;
+ int r;
+
+ r = omapdss_dpi_display_enable(dssdev);
+ if (r)
+ goto err0;
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto err1;
+ }
+
+ regulator_enable(tpo_td043->vcc_reg);
+
+ /* wait for power up */
+ msleep(160);
+
+ if (gpio_is_valid(nreset_gpio))
+ gpio_set_value(nreset_gpio, 1);
+
+ tpo_td043_write(tpo_td043->spi, 2,
+ TPO_R02_MODE(tpo_td043->mode) | TPO_R02_NCLK_RISING);
+ tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_NORMAL);
+ tpo_td043_write(tpo_td043->spi, 0x20, 0xf0);
+ tpo_td043_write(tpo_td043->spi, 0x21, 0xf0);
+ tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror,
+ tpo_td043->vmirror);
+ tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma);
+
+ return 0;
+err1:
+ omapdss_dpi_display_disable(dssdev);
+err0:
+ return r;
+}
+
+static void tpo_td043_power_off(struct omap_dss_device *dssdev)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+ int nreset_gpio = dssdev->reset_gpio;
+
+ tpo_td043_write(tpo_td043->spi, 3,
+ TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
+
+ if (gpio_is_valid(nreset_gpio))
+ gpio_set_value(nreset_gpio, 0);
+
+ /* wait for at least 2 vsyncs before cutting off power */
+ msleep(50);
+
+ tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_STANDBY);
+
+ regulator_disable(tpo_td043->vcc_reg);
+
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ omapdss_dpi_display_disable(dssdev);
+}
+
+static int tpo_td043_enable(struct omap_dss_device *dssdev)
+{
+ int ret;
+
+ dev_dbg(&dssdev->dev, "enable\n");
+
+ ret = tpo_td043_power_on(dssdev);
+ if (ret)
+ return ret;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void tpo_td043_disable(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "disable\n");
+
+ tpo_td043_power_off(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static int tpo_td043_suspend(struct omap_dss_device *dssdev)
+{
+ tpo_td043_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+ return 0;
+}
+
+static int tpo_td043_resume(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ r = tpo_td043_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static int tpo_td043_probe(struct omap_dss_device *dssdev)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+ int nreset_gpio = dssdev->reset_gpio;
+ int ret = 0;
+
+ dev_dbg(&dssdev->dev, "probe\n");
+
+ if (tpo_td043 == NULL) {
+ dev_err(&dssdev->dev, "missing tpo_td043_device\n");
+ return -ENODEV;
+ }
+
+ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IHS |
+ OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IPC;
+ dssdev->panel.timings = tpo_td043_timings;
+ dssdev->ctrl.pixel_size = 24;
+
+ tpo_td043->mode = TPO_R02_MODE_800x480;
+ memcpy(tpo_td043->gamma, tpo_td043_def_gamma, sizeof(tpo_td043->gamma));
+
+ tpo_td043->vcc_reg = regulator_get(&dssdev->dev, "vcc");
+ if (IS_ERR(tpo_td043->vcc_reg)) {
+ dev_err(&dssdev->dev, "failed to get LCD VCC regulator\n");
+ ret = PTR_ERR(tpo_td043->vcc_reg);
+ goto fail_regulator;
+ }
+
+ if (gpio_is_valid(nreset_gpio)) {
+ ret = gpio_request(nreset_gpio, "lcd reset");
+ if (ret < 0) {
+ dev_err(&dssdev->dev, "couldn't request reset GPIO\n");
+ goto fail_gpio_req;
+ }
+
+ ret = gpio_direction_output(nreset_gpio, 0);
+ if (ret < 0) {
+ dev_err(&dssdev->dev, "couldn't set GPIO direction\n");
+ goto fail_gpio_direction;
+ }
+ }
+
+ ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
+ if (ret)
+ dev_warn(&dssdev->dev, "failed to create sysfs files\n");
+
+ return 0;
+
+fail_gpio_direction:
+ gpio_free(nreset_gpio);
+fail_gpio_req:
+ regulator_put(tpo_td043->vcc_reg);
+fail_regulator:
+ kfree(tpo_td043);
+ return ret;
+}
+
+static void tpo_td043_remove(struct omap_dss_device *dssdev)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+ int nreset_gpio = dssdev->reset_gpio;
+
+ dev_dbg(&dssdev->dev, "remove\n");
+
+ sysfs_remove_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
+ regulator_put(tpo_td043->vcc_reg);
+ if (gpio_is_valid(nreset_gpio))
+ gpio_free(nreset_gpio);
+}
+
+static struct omap_dss_driver tpo_td043_driver = {
+ .probe = tpo_td043_probe,
+ .remove = tpo_td043_remove,
+
+ .enable = tpo_td043_enable,
+ .disable = tpo_td043_disable,
+ .suspend = tpo_td043_suspend,
+ .resume = tpo_td043_resume,
+ .set_mirror = tpo_td043_set_hmirror,
+ .get_mirror = tpo_td043_get_hmirror,
+
+ .driver = {
+ .name = "tpo_td043mtea1_panel",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int tpo_td043_spi_probe(struct spi_device *spi)
+{
+ struct omap_dss_device *dssdev = spi->dev.platform_data;
+ struct tpo_td043_device *tpo_td043;
+ int ret;
+
+ if (dssdev == NULL) {
+ dev_err(&spi->dev, "missing dssdev\n");
+ return -ENODEV;
+ }
+
+ spi->bits_per_word = 16;
+ spi->mode = SPI_MODE_0;
+
+ ret = spi_setup(spi);
+ if (ret < 0) {
+ dev_err(&spi->dev, "spi_setup failed: %d\n", ret);
+ return ret;
+ }
+
+ tpo_td043 = kzalloc(sizeof(*tpo_td043), GFP_KERNEL);
+ if (tpo_td043 == NULL)
+ return -ENOMEM;
+
+ tpo_td043->spi = spi;
+ dev_set_drvdata(&spi->dev, tpo_td043);
+ dev_set_drvdata(&dssdev->dev, tpo_td043);
+
+ omap_dss_register_driver(&tpo_td043_driver);
+
+ return 0;
+}
+
+static int __devexit tpo_td043_spi_remove(struct spi_device *spi)
+{
+ struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&spi->dev);
+
+ omap_dss_unregister_driver(&tpo_td043_driver);
+ kfree(tpo_td043);
+
+ return 0;
+}
+
+static struct spi_driver tpo_td043_spi_driver = {
+ .driver = {
+ .name = "tpo_td043mtea1_panel_spi",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = tpo_td043_spi_probe,
+ .remove = __devexit_p(tpo_td043_spi_remove),
+};
+
+static int __init tpo_td043_init(void)
+{
+ return spi_register_driver(&tpo_td043_spi_driver);
+}
+
+static void __exit tpo_td043_exit(void)
+{
+ spi_unregister_driver(&tpo_td043_spi_driver);
+}
+
+module_init(tpo_td043_init);
+module_exit(tpo_td043_exit);
+
+MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
+MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
index c63ce767b277..87afb81b2c44 100644
--- a/drivers/video/omap2/dss/Kconfig
+++ b/drivers/video/omap2/dss/Kconfig
@@ -30,19 +30,29 @@ config OMAP2_DSS_COLLECT_IRQ_STATS
depends on OMAP2_DSS_DEBUG_SUPPORT
default n
help
- Collect DSS IRQ statistics, printable via debugfs
+ Collect DSS IRQ statistics, printable via debugfs.
+
+ The statistics can be found from
+ <debugfs>/omapdss/dispc_irq for DISPC interrupts, and
+ <debugfs>/omapdss/dsi_irq for DSI interrupts.
config OMAP2_DSS_RFBI
bool "RFBI support"
default n
help
- MIPI DBI, or RFBI (Remote Framebuffer Interface), support.
+ MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas
+ Instrument's terminology).
+
+ DBI is a bus between the host processor and a peripheral,
+ such as a display or a framebuffer chip.
+
+ See http://www.mipi.org/ for DBI spesifications.
config OMAP2_DSS_VENC
bool "VENC support"
default y
help
- OMAP Video Encoder support.
+ OMAP Video Encoder support for S-Video and composite TV-out.
config OMAP2_DSS_SDI
bool "SDI support"
@@ -51,12 +61,20 @@ config OMAP2_DSS_SDI
help
SDI (Serial Display Interface) support.
+ SDI is a high speed one-way display serial bus between the host
+ processor and a display.
+
config OMAP2_DSS_DSI
bool "DSI support"
depends on ARCH_OMAP3
default n
help
- MIPI DSI support.
+ MIPI DSI (Display Serial Interface) support.
+
+ DSI is a high speed half-duplex serial interface between the host
+ processor and a peripheral, such as a display or a framebuffer chip.
+
+ See http://www.mipi.org/ for DSI spesifications.
config OMAP2_DSS_USE_DSI_PLL
bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 82918eec6d2e..7ebe50b335ed 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -31,6 +31,7 @@
#include <linux/debugfs.h>
#include <linux/io.h>
#include <linux/device.h>
+#include <linux/regulator/consumer.h>
#include <plat/display.h>
#include <plat/clock.h>
@@ -47,6 +48,10 @@ static struct {
struct clk *dss_54m_fck;
struct clk *dss_96m_fck;
unsigned num_clks_enabled;
+
+ struct regulator *vdds_dsi_reg;
+ struct regulator *vdds_sdi_reg;
+ struct regulator *vdda_dac_reg;
} core;
static void dss_clk_enable_all_no_ctx(void);
@@ -284,9 +289,11 @@ static void dss_clk_enable_no_ctx(enum dss_clock clks)
void dss_clk_enable(enum dss_clock clks)
{
+ bool check_ctx = core.num_clks_enabled == 0;
+
dss_clk_enable_no_ctx(clks);
- if (cpu_is_omap34xx() && dss_need_ctx_restore())
+ if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore())
restore_all_ctx();
}
@@ -352,6 +359,50 @@ static void dss_clk_disable_all(void)
dss_clk_disable(clks);
}
+/* REGULATORS */
+
+struct regulator *dss_get_vdds_dsi(void)
+{
+ struct regulator *reg;
+
+ if (core.vdds_dsi_reg != NULL)
+ return core.vdds_dsi_reg;
+
+ reg = regulator_get(&core.pdev->dev, "vdds_dsi");
+ if (!IS_ERR(reg))
+ core.vdds_dsi_reg = reg;
+
+ return reg;
+}
+
+struct regulator *dss_get_vdds_sdi(void)
+{
+ struct regulator *reg;
+
+ if (core.vdds_sdi_reg != NULL)
+ return core.vdds_sdi_reg;
+
+ reg = regulator_get(&core.pdev->dev, "vdds_sdi");
+ if (!IS_ERR(reg))
+ core.vdds_sdi_reg = reg;
+
+ return reg;
+}
+
+struct regulator *dss_get_vdda_dac(void)
+{
+ struct regulator *reg;
+
+ if (core.vdda_dac_reg != NULL)
+ return core.vdda_dac_reg;
+
+ reg = regulator_get(&core.pdev->dev, "vdda_dac");
+ if (!IS_ERR(reg))
+ core.vdda_dac_reg = reg;
+
+ return reg;
+}
+
/* DEBUGFS */
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
static void dss_debug_dump_clocks(struct seq_file *s)
@@ -397,10 +448,12 @@ static int dss_initialize_debugfs(void)
debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
&dss_debug_dump_clocks, &dss_debug_fops);
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
debugfs_create_file("dispc_irq", S_IRUGO, dss_debugfs_dir,
&dispc_dump_irqs, &dss_debug_fops);
+#endif
-#ifdef CONFIG_OMAP2_DSS_DSI
+#if defined(CONFIG_OMAP2_DSS_DSI) && defined(CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS)
debugfs_create_file("dsi_irq", S_IRUGO, dss_debugfs_dir,
&dsi_dump_irqs, &dss_debug_fops);
#endif
@@ -473,7 +526,7 @@ static int omap_dss_probe(struct platform_device *pdev)
}
#endif
- r = dpi_init();
+ r = dpi_init(pdev);
if (r) {
DSSERR("Failed to initialize dpi\n");
goto fail0;
@@ -718,16 +771,14 @@ static int dss_driver_probe(struct device *dev)
dss_init_device(core.pdev, dssdev);
- /* skip this if the device is behind a ctrl */
- if (!dssdev->panel.ctrl) {
- force = pdata->default_device == dssdev;
- dss_recheck_connections(dssdev, force);
- }
+ force = pdata->default_device == dssdev;
+ dss_recheck_connections(dssdev, force);
r = dssdrv->probe(dssdev);
if (r) {
DSSERR("driver probe failed: %d\n", r);
+ dss_uninit_device(core.pdev, dssdev);
return r;
}
@@ -760,6 +811,13 @@ int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
dssdriver->driver.bus = &dss_bus_type;
dssdriver->driver.probe = dss_driver_probe;
dssdriver->driver.remove = dss_driver_remove;
+
+ if (dssdriver->get_resolution == NULL)
+ dssdriver->get_resolution = omapdss_default_get_resolution;
+ if (dssdriver->get_recommended_bpp == NULL)
+ dssdriver->get_recommended_bpp =
+ omapdss_default_get_recommended_bpp;
+
return driver_register(&dssdriver->driver);
}
EXPORT_SYMBOL(omap_dss_register_driver);
@@ -808,8 +866,6 @@ static void omap_dss_dev_release(struct device *dev)
int omap_dss_register_device(struct omap_dss_device *dssdev)
{
static int dev_num;
- static int panel_num;
- int r;
WARN_ON(!dssdev->driver_name);
@@ -818,36 +874,12 @@ int omap_dss_register_device(struct omap_dss_device *dssdev)
dssdev->dev.parent = &dss_bus;
dssdev->dev.release = omap_dss_dev_release;
dev_set_name(&dssdev->dev, "display%d", dev_num++);
- r = device_register(&dssdev->dev);
- if (r)
- return r;
-
- if (dssdev->ctrl.panel) {
- struct omap_dss_device *panel = dssdev->ctrl.panel;
-
- panel->panel.ctrl = dssdev;
-
- reset_device(&panel->dev, 1);
- panel->dev.bus = &dss_bus_type;
- panel->dev.parent = &dssdev->dev;
- panel->dev.release = omap_dss_dev_release;
- dev_set_name(&panel->dev, "panel%d", panel_num++);
- r = device_register(&panel->dev);
- if (r)
- return r;
- }
-
- return 0;
+ return device_register(&dssdev->dev);
}
void omap_dss_unregister_device(struct omap_dss_device *dssdev)
{
device_unregister(&dssdev->dev);
-
- if (dssdev->ctrl.panel) {
- struct omap_dss_device *panel = dssdev->ctrl.panel;
- device_unregister(&panel->dev);
- }
}
/* BUS */
@@ -901,6 +933,21 @@ static int __init omap_dss_init(void)
static void __exit omap_dss_exit(void)
{
+ if (core.vdds_dsi_reg != NULL) {
+ regulator_put(core.vdds_dsi_reg);
+ core.vdds_dsi_reg = NULL;
+ }
+
+ if (core.vdds_sdi_reg != NULL) {
+ regulator_put(core.vdds_sdi_reg);
+ core.vdds_sdi_reg = NULL;
+ }
+
+ if (core.vdda_dac_reg != NULL) {
+ regulator_put(core.vdda_dac_reg);
+ core.vdda_dac_reg = NULL;
+ }
+
platform_driver_unregister(&omap_dss_driver);
omap_dss_bus_unregister();
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index de8bfbac9e26..e777e352dbcd 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -1725,7 +1725,7 @@ static void _enable_lcd_out(bool enable)
REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
}
-void dispc_enable_lcd_out(bool enable)
+static void dispc_enable_lcd_out(bool enable)
{
struct completion frame_done_completion;
bool is_on;
@@ -1772,7 +1772,7 @@ static void _enable_digit_out(bool enable)
REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
}
-void dispc_enable_digit_out(bool enable)
+static void dispc_enable_digit_out(bool enable)
{
struct completion frame_done_completion;
int r;
@@ -1836,6 +1836,26 @@ void dispc_enable_digit_out(bool enable)
enable_clocks(0);
}
+bool dispc_is_channel_enabled(enum omap_channel channel)
+{
+ if (channel == OMAP_DSS_CHANNEL_LCD)
+ return !!REG_GET(DISPC_CONTROL, 0, 0);
+ else if (channel == OMAP_DSS_CHANNEL_DIGIT)
+ return !!REG_GET(DISPC_CONTROL, 1, 1);
+ else
+ BUG();
+}
+
+void dispc_enable_channel(enum omap_channel channel, bool enable)
+{
+ if (channel == OMAP_DSS_CHANNEL_LCD)
+ dispc_enable_lcd_out(enable);
+ else if (channel == OMAP_DSS_CHANNEL_DIGIT)
+ dispc_enable_digit_out(enable);
+ else
+ BUG();
+}
+
void dispc_lcd_enable_signal_polarity(bool act_high)
{
enable_clocks(1);
@@ -2198,7 +2218,7 @@ unsigned long dispc_fclk_rate(void)
{
unsigned long r = 0;
- if (dss_get_dispc_clk_source() == 0)
+ if (dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK)
r = dss_clk_get_rate(DSS_CLK_FCK1);
else
#ifdef CONFIG_OMAP2_DSS_DSI
@@ -2251,7 +2271,7 @@ void dispc_dump_clocks(struct seq_file *s)
seq_printf(s, "- DISPC -\n");
seq_printf(s, "dispc fclk source = %s\n",
- dss_get_dispc_clk_source() == 0 ?
+ dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
"dss1_alwon_fclk" : "dsi1_pll_fclk");
seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
@@ -2301,8 +2321,6 @@ void dispc_dump_irqs(struct seq_file *s)
PIS(WAKEUP);
#undef PIS
}
-#else
-void dispc_dump_irqs(struct seq_file *s) { }
#endif
void dispc_dump_regs(struct seq_file *s)
@@ -2854,12 +2872,13 @@ static void dispc_error_worker(struct work_struct *work)
manager = mgr;
enable = mgr->device->state ==
OMAP_DSS_DISPLAY_ACTIVE;
- mgr->device->disable(mgr->device);
+ mgr->device->driver->disable(mgr->device);
break;
}
}
if (manager) {
+ struct omap_dss_device *dssdev = manager->device;
for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
struct omap_overlay *ovl;
ovl = omap_dss_get_overlay(i);
@@ -2874,7 +2893,7 @@ static void dispc_error_worker(struct work_struct *work)
dispc_go(manager->id);
mdelay(50);
if (enable)
- manager->device->enable(manager->device);
+ dssdev->driver->enable(dssdev);
}
}
@@ -2892,12 +2911,13 @@ static void dispc_error_worker(struct work_struct *work)
manager = mgr;
enable = mgr->device->state ==
OMAP_DSS_DISPLAY_ACTIVE;
- mgr->device->disable(mgr->device);
+ mgr->device->driver->disable(mgr->device);
break;
}
}
if (manager) {
+ struct omap_dss_device *dssdev = manager->device;
for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
struct omap_overlay *ovl;
ovl = omap_dss_get_overlay(i);
@@ -2912,7 +2932,7 @@ static void dispc_error_worker(struct work_struct *work)
dispc_go(manager->id);
mdelay(50);
if (enable)
- manager->device->enable(manager->device);
+ dssdev->driver->enable(dssdev);
}
}
@@ -2923,7 +2943,7 @@ static void dispc_error_worker(struct work_struct *work)
mgr = omap_dss_get_overlay_manager(i);
if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC)
- mgr->device->disable(mgr->device);
+ mgr->device->driver->disable(mgr->device);
}
}
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index 3b92b84b9560..6a74ea116d29 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -53,11 +53,11 @@ static ssize_t display_enabled_store(struct device *dev,
if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
if (enabled) {
- r = dssdev->enable(dssdev);
+ r = dssdev->driver->enable(dssdev);
if (r)
return r;
} else {
- dssdev->disable(dssdev);
+ dssdev->driver->disable(dssdev);
}
}
@@ -69,8 +69,8 @@ static ssize_t display_upd_mode_show(struct device *dev,
{
struct omap_dss_device *dssdev = to_dss_device(dev);
enum omap_dss_update_mode mode = OMAP_DSS_UPDATE_AUTO;
- if (dssdev->get_update_mode)
- mode = dssdev->get_update_mode(dssdev);
+ if (dssdev->driver->get_update_mode)
+ mode = dssdev->driver->get_update_mode(dssdev);
return snprintf(buf, PAGE_SIZE, "%d\n", mode);
}
@@ -94,7 +94,7 @@ static ssize_t display_upd_mode_store(struct device *dev,
return -EINVAL;
}
- r = dssdev->set_update_mode(dssdev, mode);
+ r = dssdev->driver->set_update_mode(dssdev, mode);
if (r)
return r;
@@ -106,7 +106,8 @@ static ssize_t display_tear_show(struct device *dev,
{
struct omap_dss_device *dssdev = to_dss_device(dev);
return snprintf(buf, PAGE_SIZE, "%d\n",
- dssdev->get_te ? dssdev->get_te(dssdev) : 0);
+ dssdev->driver->get_te ?
+ dssdev->driver->get_te(dssdev) : 0);
}
static ssize_t display_tear_store(struct device *dev,
@@ -116,12 +117,12 @@ static ssize_t display_tear_store(struct device *dev,
unsigned long te;
int r;
- if (!dssdev->enable_te || !dssdev->get_te)
+ if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
return -ENOENT;
te = simple_strtoul(buf, NULL, 0);
- r = dssdev->enable_te(dssdev, te);
+ r = dssdev->driver->enable_te(dssdev, te);
if (r)
return r;
@@ -134,10 +135,10 @@ static ssize_t display_timings_show(struct device *dev,
struct omap_dss_device *dssdev = to_dss_device(dev);
struct omap_video_timings t;
- if (!dssdev->get_timings)
+ if (!dssdev->driver->get_timings)
return -ENOENT;
- dssdev->get_timings(dssdev, &t);
+ dssdev->driver->get_timings(dssdev, &t);
return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
t.pixel_clock,
@@ -152,7 +153,7 @@ static ssize_t display_timings_store(struct device *dev,
struct omap_video_timings t;
int r, found;
- if (!dssdev->set_timings || !dssdev->check_timings)
+ if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
return -ENOENT;
found = 0;
@@ -171,11 +172,11 @@ static ssize_t display_timings_store(struct device *dev,
&t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
return -EINVAL;
- r = dssdev->check_timings(dssdev, &t);
+ r = dssdev->driver->check_timings(dssdev, &t);
if (r)
return r;
- dssdev->set_timings(dssdev, &t);
+ dssdev->driver->set_timings(dssdev, &t);
return size;
}
@@ -185,9 +186,9 @@ static ssize_t display_rotate_show(struct device *dev,
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int rotate;
- if (!dssdev->get_rotate)
+ if (!dssdev->driver->get_rotate)
return -ENOENT;
- rotate = dssdev->get_rotate(dssdev);
+ rotate = dssdev->driver->get_rotate(dssdev);
return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
}
@@ -198,12 +199,12 @@ static ssize_t display_rotate_store(struct device *dev,
unsigned long rot;
int r;
- if (!dssdev->set_rotate || !dssdev->get_rotate)
+ if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
return -ENOENT;
rot = simple_strtoul(buf, NULL, 0);
- r = dssdev->set_rotate(dssdev, rot);
+ r = dssdev->driver->set_rotate(dssdev, rot);
if (r)
return r;
@@ -215,9 +216,9 @@ static ssize_t display_mirror_show(struct device *dev,
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int mirror;
- if (!dssdev->get_mirror)
+ if (!dssdev->driver->get_mirror)
return -ENOENT;
- mirror = dssdev->get_mirror(dssdev);
+ mirror = dssdev->driver->get_mirror(dssdev);
return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
}
@@ -228,12 +229,12 @@ static ssize_t display_mirror_store(struct device *dev,
unsigned long mirror;
int r;
- if (!dssdev->set_mirror || !dssdev->get_mirror)
+ if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
return -ENOENT;
mirror = simple_strtoul(buf, NULL, 0);
- r = dssdev->set_mirror(dssdev, mirror);
+ r = dssdev->driver->set_mirror(dssdev, mirror);
if (r)
return r;
@@ -246,10 +247,10 @@ static ssize_t display_wss_show(struct device *dev,
struct omap_dss_device *dssdev = to_dss_device(dev);
unsigned int wss;
- if (!dssdev->get_wss)
+ if (!dssdev->driver->get_wss)
return -ENOENT;
- wss = dssdev->get_wss(dssdev);
+ wss = dssdev->driver->get_wss(dssdev);
return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
}
@@ -261,7 +262,7 @@ static ssize_t display_wss_store(struct device *dev,
unsigned long wss;
int r;
- if (!dssdev->get_wss || !dssdev->set_wss)
+ if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
return -ENOENT;
if (strict_strtoul(buf, 0, &wss))
@@ -270,7 +271,7 @@ static ssize_t display_wss_store(struct device *dev,
if (wss > 0xfffff)
return -EINVAL;
- r = dssdev->set_wss(dssdev, wss);
+ r = dssdev->driver->set_wss(dssdev, wss);
if (r)
return r;
@@ -303,12 +304,13 @@ static struct device_attribute *display_sysfs_attrs[] = {
NULL
};
-static void default_get_resolution(struct omap_dss_device *dssdev,
+void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
u16 *xres, u16 *yres)
{
*xres = dssdev->panel.timings.x_res;
*yres = dssdev->panel.timings.y_res;
}
+EXPORT_SYMBOL(omapdss_default_get_resolution);
void default_get_overlay_fifo_thresholds(enum omap_plane plane,
u32 fifo_size, enum omap_burst_size *burst_size,
@@ -323,24 +325,8 @@ void default_get_overlay_fifo_thresholds(enum omap_plane plane,
*fifo_low = fifo_size - burst_size_bytes;
}
-static int default_wait_vsync(struct omap_dss_device *dssdev)
+int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
{
- unsigned long timeout = msecs_to_jiffies(500);
- u32 irq;
-
- if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
- irq = DISPC_IRQ_EVSYNC_ODD;
- else
- irq = DISPC_IRQ_VSYNC;
-
- return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
-}
-
-static int default_get_recommended_bpp(struct omap_dss_device *dssdev)
-{
- if (dssdev->panel.recommended_bpp)
- return dssdev->panel.recommended_bpp;
-
switch (dssdev->type) {
case OMAP_DISPLAY_TYPE_DPI:
if (dssdev->phy.dpi.data_lines == 24)
@@ -362,6 +348,7 @@ static int default_get_recommended_bpp(struct omap_dss_device *dssdev)
BUG();
}
}
+EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);
/* Checks if replication logic should be used. Only use for active matrix,
* when overlay is in RGB12U or RGB16 mode, and LCD interface is
@@ -425,10 +412,6 @@ void dss_init_device(struct platform_device *pdev,
return;
}
- dssdev->get_resolution = default_get_resolution;
- dssdev->get_recommended_bpp = default_get_recommended_bpp;
- dssdev->wait_vsync = default_wait_vsync;
-
switch (dssdev->type) {
case OMAP_DISPLAY_TYPE_DPI:
r = dpi_init_display(dssdev);
@@ -502,13 +485,13 @@ static int dss_suspend_device(struct device *dev, void *data)
return 0;
}
- if (!dssdev->suspend) {
+ if (!dssdev->driver->suspend) {
DSSERR("display '%s' doesn't implement suspend\n",
dssdev->name);
return -ENOSYS;
}
- r = dssdev->suspend(dssdev);
+ r = dssdev->driver->suspend(dssdev);
if (r)
return r;
@@ -537,8 +520,8 @@ static int dss_resume_device(struct device *dev, void *data)
int r;
struct omap_dss_device *dssdev = to_dss_device(dev);
- if (dssdev->activate_after_resume && dssdev->resume) {
- r = dssdev->resume(dssdev);
+ if (dssdev->activate_after_resume && dssdev->driver->resume) {
+ r = dssdev->driver->resume(dssdev);
if (r)
return r;
}
@@ -558,7 +541,7 @@ int dss_resume_all_devices(void)
static int dss_disable_device(struct device *dev, void *data)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
- dssdev->disable(dssdev);
+ dssdev->driver->disable(dssdev);
return 0;
}
@@ -591,10 +574,6 @@ struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
int match(struct device *dev, void *data)
{
- /* skip panels connected to controllers */
- if (to_dss_device(dev)->panel.ctrl)
- return 0;
-
return 1;
}
@@ -626,45 +605,21 @@ EXPORT_SYMBOL(omap_dss_find_device);
int omap_dss_start_device(struct omap_dss_device *dssdev)
{
- int r;
-
if (!dssdev->driver) {
DSSDBG("no driver\n");
- r = -ENODEV;
- goto err0;
- }
-
- if (dssdev->ctrl.panel && !dssdev->ctrl.panel->driver) {
- DSSDBG("no panel driver\n");
- r = -ENODEV;
- goto err0;
+ return -ENODEV;
}
if (!try_module_get(dssdev->dev.driver->owner)) {
- r = -ENODEV;
- goto err0;
- }
-
- if (dssdev->ctrl.panel) {
- if (!try_module_get(dssdev->ctrl.panel->dev.driver->owner)) {
- r = -ENODEV;
- goto err1;
- }
+ return -ENODEV;
}
return 0;
-err1:
- module_put(dssdev->dev.driver->owner);
-err0:
- return r;
}
EXPORT_SYMBOL(omap_dss_start_device);
void omap_dss_stop_device(struct omap_dss_device *dssdev)
{
- if (dssdev->ctrl.panel)
- module_put(dssdev->ctrl.panel->dev.driver->owner);
-
module_put(dssdev->dev.driver->owner);
}
EXPORT_SYMBOL(omap_dss_stop_device);
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 2d71031baa25..960e977a8bf0 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -25,7 +25,10 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <plat/display.h>
#include <plat/cpu.h>
@@ -33,7 +36,7 @@
#include "dss.h"
static struct {
- int update_enabled;
+ struct regulator *vdds_dsi_reg;
} dpi;
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
@@ -53,7 +56,7 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
if (r)
return r;
- dss_select_clk_source(0, 1);
+ dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
r = dispc_set_clock_div(&dispc_cinfo);
if (r)
@@ -150,7 +153,7 @@ static int dpi_basic_init(struct omap_dss_device *dssdev)
return 0;
}
-static int dpi_display_enable(struct omap_dss_device *dssdev)
+int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
{
int r;
@@ -160,10 +163,10 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
- if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
- DSSERR("display already enabled\n");
- r = -EINVAL;
- goto err1;
+ if (cpu_is_omap34xx()) {
+ r = regulator_enable(dpi.vdds_dsi_reg);
+ if (r)
+ goto err1;
}
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
@@ -184,18 +187,10 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
mdelay(2);
- dispc_enable_lcd_out(1);
-
- r = dssdev->driver->enable(dssdev);
- if (r)
- goto err5;
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ dssdev->manager->enable(dssdev->manager);
return 0;
-err5:
- dispc_enable_lcd_out(0);
err4:
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
dsi_pll_uninit();
@@ -204,78 +199,35 @@ err3:
#endif
err2:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ if (cpu_is_omap34xx())
+ regulator_disable(dpi.vdds_dsi_reg);
err1:
omap_dss_stop_device(dssdev);
err0:
return r;
}
+EXPORT_SYMBOL(omapdss_dpi_display_enable);
-static int dpi_display_resume(struct omap_dss_device *dssdev);
-
-static void dpi_display_disable(struct omap_dss_device *dssdev)
+void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
{
- if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
- return;
-
- if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
- dpi_display_resume(dssdev);
-
- dssdev->driver->disable(dssdev);
-
- dispc_enable_lcd_out(0);
+ dssdev->manager->disable(dssdev->manager);
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
- dss_select_clk_source(0, 0);
+ dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
dsi_pll_uninit();
dss_clk_disable(DSS_CLK_FCK2);
#endif
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+ if (cpu_is_omap34xx())
+ regulator_disable(dpi.vdds_dsi_reg);
omap_dss_stop_device(dssdev);
}
+EXPORT_SYMBOL(omapdss_dpi_display_disable);
-static int dpi_display_suspend(struct omap_dss_device *dssdev)
-{
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- return -EINVAL;
-
- DSSDBG("dpi_display_suspend\n");
-
- if (dssdev->driver->suspend)
- dssdev->driver->suspend(dssdev);
-
- dispc_enable_lcd_out(0);
-
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
-
- dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
-
- return 0;
-}
-
-static int dpi_display_resume(struct omap_dss_device *dssdev)
-{
- if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
- return -EINVAL;
-
- DSSDBG("dpi_display_resume\n");
-
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
-
- dispc_enable_lcd_out(1);
-
- if (dssdev->driver->resume)
- dssdev->driver->resume(dssdev);
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- return 0;
-}
-
-static void dpi_set_timings(struct omap_dss_device *dssdev,
+void dpi_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
DSSDBG("dpi_set_timings\n");
@@ -285,8 +237,9 @@ static void dpi_set_timings(struct omap_dss_device *dssdev,
dispc_go(OMAP_DSS_CHANNEL_LCD);
}
}
+EXPORT_SYMBOL(dpi_set_timings);
-static int dpi_check_timings(struct omap_dss_device *dssdev,
+int dpi_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
bool is_tft;
@@ -340,56 +293,25 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
return 0;
}
-
-static void dpi_get_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
-{
- *timings = dssdev->panel.timings;
-}
-
-static int dpi_display_set_update_mode(struct omap_dss_device *dssdev,
- enum omap_dss_update_mode mode)
-{
- if (mode == OMAP_DSS_UPDATE_MANUAL)
- return -EINVAL;
-
- if (mode == OMAP_DSS_UPDATE_DISABLED) {
- dispc_enable_lcd_out(0);
- dpi.update_enabled = 0;
- } else {
- dispc_enable_lcd_out(1);
- dpi.update_enabled = 1;
- }
-
- return 0;
-}
-
-static enum omap_dss_update_mode dpi_display_get_update_mode(
- struct omap_dss_device *dssdev)
-{
- return dpi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
- OMAP_DSS_UPDATE_DISABLED;
-}
+EXPORT_SYMBOL(dpi_check_timings);
int dpi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("init_display\n");
- dssdev->enable = dpi_display_enable;
- dssdev->disable = dpi_display_disable;
- dssdev->suspend = dpi_display_suspend;
- dssdev->resume = dpi_display_resume;
- dssdev->set_timings = dpi_set_timings;
- dssdev->check_timings = dpi_check_timings;
- dssdev->get_timings = dpi_get_timings;
- dssdev->set_update_mode = dpi_display_set_update_mode;
- dssdev->get_update_mode = dpi_display_get_update_mode;
-
return 0;
}
-int dpi_init(void)
+int dpi_init(struct platform_device *pdev)
{
+ if (cpu_is_omap34xx()) {
+ dpi.vdds_dsi_reg = dss_get_vdds_dsi();
+ if (IS_ERR(dpi.vdds_dsi_reg)) {
+ DSSERR("can't get VDDS_DSI regulator\n");
+ return PTR_ERR(dpi.vdds_dsi_reg);
+ }
+ }
+
return 0;
}
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 6122178f5f85..3af207b2bde3 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -27,11 +27,12 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/semaphore.h>
#include <linux/seq_file.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
-#include <linux/kthread.h>
#include <linux/wait.h>
+#include <linux/workqueue.h>
#include <plat/display.h>
#include <plat/clock.h>
@@ -199,7 +200,6 @@ enum dsi_vc_mode {
};
struct dsi_update_region {
- bool dirty;
u16 x, y, w, h;
struct omap_dss_device *device;
};
@@ -224,29 +224,25 @@ static struct
enum dsi_vc_mode mode;
struct omap_dss_device *dssdev;
enum fifo_size fifo_size;
- int dest_per; /* destination peripheral 0-3 */
} vc[4];
struct mutex lock;
- struct mutex bus_lock;
+ struct semaphore bus_lock;
unsigned pll_locked;
struct completion bta_completion;
- struct task_struct *thread;
- wait_queue_head_t waitqueue;
-
- spinlock_t update_lock;
- bool framedone_received;
+ int update_channel;
struct dsi_update_region update_region;
- struct dsi_update_region active_update_region;
- struct completion update_completion;
- enum omap_dss_update_mode user_update_mode;
- enum omap_dss_update_mode update_mode;
bool te_enabled;
- bool use_ext_te;
+
+ struct work_struct framedone_work;
+ void (*framedone_callback)(int, void *);
+ void *framedone_data;
+
+ struct delayed_work framedone_timeout_work;
#ifdef DSI_CATCH_MISSING_TE
struct timer_list te_timer;
@@ -261,8 +257,6 @@ static struct
#ifdef DEBUG
ktime_t perf_setup_time;
ktime_t perf_start_time;
- ktime_t perf_start_time_auto;
- int perf_measure_frames;
#endif
int debug_read;
int debug_write;
@@ -299,16 +293,21 @@ void dsi_restore_context(void)
void dsi_bus_lock(void)
{
- mutex_lock(&dsi.bus_lock);
+ down(&dsi.bus_lock);
}
EXPORT_SYMBOL(dsi_bus_lock);
void dsi_bus_unlock(void)
{
- mutex_unlock(&dsi.bus_lock);
+ up(&dsi.bus_lock);
}
EXPORT_SYMBOL(dsi_bus_unlock);
+static bool dsi_bus_is_locked(void)
+{
+ return dsi.bus_lock.count == 0;
+}
+
static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
int value)
{
@@ -333,12 +332,6 @@ static void dsi_perf_mark_start(void)
dsi.perf_start_time = ktime_get();
}
-static void dsi_perf_mark_start_auto(void)
-{
- dsi.perf_measure_frames = 0;
- dsi.perf_start_time_auto = ktime_get();
-}
-
static void dsi_perf_show(const char *name)
{
ktime_t t, setup_time, trans_time;
@@ -348,9 +341,6 @@ static void dsi_perf_show(const char *name)
if (!dsi_perf)
return;
- if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED)
- return;
-
t = ktime_get();
setup_time = ktime_sub(dsi.perf_start_time, dsi.perf_setup_time);
@@ -365,76 +355,23 @@ static void dsi_perf_show(const char *name)
total_us = setup_us + trans_us;
- total_bytes = dsi.active_update_region.w *
- dsi.active_update_region.h *
- dsi.active_update_region.device->ctrl.pixel_size / 8;
-
- if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) {
- static u32 s_total_trans_us, s_total_setup_us;
- static u32 s_min_trans_us = 0xffffffff, s_min_setup_us;
- static u32 s_max_trans_us, s_max_setup_us;
- const int numframes = 100;
- ktime_t total_time_auto;
- u32 total_time_auto_us;
-
- dsi.perf_measure_frames++;
-
- if (setup_us < s_min_setup_us)
- s_min_setup_us = setup_us;
+ total_bytes = dsi.update_region.w *
+ dsi.update_region.h *
+ dsi.update_region.device->ctrl.pixel_size / 8;
- if (setup_us > s_max_setup_us)
- s_max_setup_us = setup_us;
-
- s_total_setup_us += setup_us;
-
- if (trans_us < s_min_trans_us)
- s_min_trans_us = trans_us;
-
- if (trans_us > s_max_trans_us)
- s_max_trans_us = trans_us;
-
- s_total_trans_us += trans_us;
-
- if (dsi.perf_measure_frames < numframes)
- return;
-
- total_time_auto = ktime_sub(t, dsi.perf_start_time_auto);
- total_time_auto_us = (u32)ktime_to_us(total_time_auto);
-
- printk(KERN_INFO "DSI(%s): %u fps, setup %u/%u/%u, "
- "trans %u/%u/%u\n",
- name,
- 1000 * 1000 * numframes / total_time_auto_us,
- s_min_setup_us,
- s_max_setup_us,
- s_total_setup_us / numframes,
- s_min_trans_us,
- s_max_trans_us,
- s_total_trans_us / numframes);
-
- s_total_setup_us = 0;
- s_min_setup_us = 0xffffffff;
- s_max_setup_us = 0;
- s_total_trans_us = 0;
- s_min_trans_us = 0xffffffff;
- s_max_trans_us = 0;
- dsi_perf_mark_start_auto();
- } else {
- printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
- "%u bytes, %u kbytes/sec\n",
- name,
- setup_us,
- trans_us,
- total_us,
- 1000*1000 / total_us,
- total_bytes,
- total_bytes * 1000 / total_us);
- }
+ printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
+ "%u bytes, %u kbytes/sec\n",
+ name,
+ setup_us,
+ trans_us,
+ total_us,
+ 1000*1000 / total_us,
+ total_bytes,
+ total_bytes * 1000 / total_us);
}
#else
#define dsi_perf_mark_setup()
#define dsi_perf_mark_start()
-#define dsi_perf_mark_start_auto()
#define dsi_perf_show(x)
#endif
@@ -774,7 +711,7 @@ static unsigned long dsi_fclk_rate(void)
{
unsigned long r;
- if (dss_get_dsi_clk_source() == 0) {
+ if (dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK) {
/* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */
r = dss_clk_get_rate(DSS_CLK_FCK1);
} else {
@@ -1227,17 +1164,19 @@ void dsi_dump_clocks(struct seq_file *s)
seq_printf(s, "dsi1_pll_fck\t%-16luregm3 %u\t(%s)\n",
cinfo->dsi1_pll_fclk,
cinfo->regm3,
- dss_get_dispc_clk_source() == 0 ? "off" : "on");
+ dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
+ "off" : "on");
seq_printf(s, "dsi2_pll_fck\t%-16luregm4 %u\t(%s)\n",
cinfo->dsi2_pll_fclk,
cinfo->regm4,
- dss_get_dsi_clk_source() == 0 ? "off" : "on");
+ dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
+ "off" : "on");
seq_printf(s, "- DSI -\n");
seq_printf(s, "dsi fclk source = %s\n",
- dss_get_dsi_clk_source() == 0 ?
+ dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
"dss1_alwon_fclk" : "dsi2_pll_fclk");
seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate());
@@ -1756,29 +1695,10 @@ static int dsi_force_tx_stop_mode_io(void)
return 0;
}
-static void dsi_vc_print_status(int channel)
-{
- u32 r;
-
- r = dsi_read_reg(DSI_VC_CTRL(channel));
- DSSDBG("vc %d: TX_FIFO_NOT_EMPTY %d, BTA_EN %d, VC_BUSY %d, "
- "TX_FIFO_FULL %d, RX_FIFO_NOT_EMPTY %d, ",
- channel,
- FLD_GET(r, 5, 5),
- FLD_GET(r, 6, 6),
- FLD_GET(r, 15, 15),
- FLD_GET(r, 16, 16),
- FLD_GET(r, 20, 20));
-
- r = dsi_read_reg(DSI_TX_FIFO_VC_EMPTINESS);
- DSSDBG("EMPTINESS %d\n", (r >> (8 * channel)) & 0xff);
-}
-
static int dsi_vc_enable(int channel, bool enable)
{
- if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
- DSSDBG("dsi_vc_enable channel %d, enable %d\n",
- channel, enable);
+ DSSDBG("dsi_vc_enable channel %d, enable %d\n",
+ channel, enable);
enable = enable ? 1 : 0;
@@ -1859,10 +1779,12 @@ static void dsi_vc_config_vp(int channel)
}
-static void dsi_vc_enable_hs(int channel, bool enable)
+void omapdss_dsi_vc_enable_hs(int channel, bool enable)
{
DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
+ WARN_ON(!dsi_bus_is_locked());
+
dsi_vc_enable(channel, 0);
dsi_if_enable(0);
@@ -1873,6 +1795,7 @@ static void dsi_vc_enable_hs(int channel, bool enable)
dsi_force_tx_stop_mode_io();
}
+EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs);
static void dsi_vc_flush_long_data(int channel)
{
@@ -1955,11 +1878,10 @@ static u16 dsi_vc_flush_receive_data(int channel)
static int dsi_vc_send_bta(int channel)
{
- if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO &&
- (dsi.debug_write || dsi.debug_read))
+ if (dsi.debug_write || dsi.debug_read)
DSSDBG("dsi_vc_send_bta %d\n", channel);
- WARN_ON(!mutex_is_locked(&dsi.bus_lock));
+ WARN_ON(!dsi_bus_is_locked());
if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */
DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
@@ -2010,10 +1932,9 @@ static inline void dsi_vc_write_long_header(int channel, u8 data_type,
u32 val;
u8 data_id;
- WARN_ON(!mutex_is_locked(&dsi.bus_lock));
+ WARN_ON(!dsi_bus_is_locked());
- /*data_id = data_type | channel << 6; */
- data_id = data_type | dsi.vc[channel].dest_per << 6;
+ data_id = data_type | channel << 6;
val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
FLD_VAL(ecc, 31, 24);
@@ -2056,13 +1977,10 @@ static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
dsi_vc_write_long_header(channel, data_type, len, ecc);
- /*dsi_vc_print_status(0); */
-
p = data;
for (i = 0; i < len >> 2; i++) {
if (dsi.debug_write)
DSSDBG("\tsending full packet %d\n", i);
- /*dsi_vc_print_status(0); */
b1 = *p++;
b2 = *p++;
@@ -2105,7 +2023,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
u32 r;
u8 data_id;
- WARN_ON(!mutex_is_locked(&dsi.bus_lock));
+ WARN_ON(!dsi_bus_is_locked());
if (dsi.debug_write)
DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
@@ -2119,7 +2037,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
return -EINVAL;
}
- data_id = data_type | dsi.vc[channel].dest_per << 6;
+ data_id = data_type | channel << 6;
r = (data_id << 0) | (data << 8) | (ecc << 24);
@@ -2163,14 +2081,35 @@ int dsi_vc_dcs_write(int channel, u8 *data, int len)
r = dsi_vc_dcs_write_nosync(channel, data, len);
if (r)
- return r;
+ goto err;
r = dsi_vc_send_bta_sync(channel);
+ if (r)
+ goto err;
+ return 0;
+err:
+ DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n",
+ channel, data[0], len);
return r;
}
EXPORT_SYMBOL(dsi_vc_dcs_write);
+int dsi_vc_dcs_write_0(int channel, u8 dcs_cmd)
+{
+ return dsi_vc_dcs_write(channel, &dcs_cmd, 1);
+}
+EXPORT_SYMBOL(dsi_vc_dcs_write_0);
+
+int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param)
+{
+ u8 buf[2];
+ buf[0] = dcs_cmd;
+ buf[1] = param;
+ return dsi_vc_dcs_write(channel, buf, 2);
+}
+EXPORT_SYMBOL(dsi_vc_dcs_write_1);
+
int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
{
u32 val;
@@ -2182,16 +2121,17 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
r = dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0);
if (r)
- return r;
+ goto err;
r = dsi_vc_send_bta_sync(channel);
if (r)
- return r;
+ goto err;
/* RX_FIFO_NOT_EMPTY */
if (REG_GET(DSI_VC_CTRL(channel), 20, 20) == 0) {
DSSERR("RX fifo empty when trying to read.\n");
- return -EIO;
+ r = -EIO;
+ goto err;
}
val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
@@ -2201,15 +2141,18 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
if (dt == DSI_DT_RX_ACK_WITH_ERR) {
u16 err = FLD_GET(val, 23, 8);
dsi_show_rx_ack_with_err(err);
- return -EIO;
+ r = -EIO;
+ goto err;
} else if (dt == DSI_DT_RX_SHORT_READ_1) {
u8 data = FLD_GET(val, 15, 8);
if (dsi.debug_read)
DSSDBG("\tDCS short response, 1 byte: %02x\n", data);
- if (buflen < 1)
- return -EIO;
+ if (buflen < 1) {
+ r = -EIO;
+ goto err;
+ }
buf[0] = data;
@@ -2219,8 +2162,10 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
if (dsi.debug_read)
DSSDBG("\tDCS short response, 2 byte: %04x\n", data);
- if (buflen < 2)
- return -EIO;
+ if (buflen < 2) {
+ r = -EIO;
+ goto err;
+ }
buf[0] = data & 0xff;
buf[1] = (data >> 8) & 0xff;
@@ -2232,8 +2177,10 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
if (dsi.debug_read)
DSSDBG("\tDCS long response, len %d\n", len);
- if (len > buflen)
- return -EIO;
+ if (len > buflen) {
+ r = -EIO;
+ goto err;
+ }
/* two byte checksum ends the packet, not included in len */
for (w = 0; w < len + 2;) {
@@ -2255,14 +2202,52 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
}
return len;
-
} else {
DSSERR("\tunknown datatype 0x%02x\n", dt);
- return -EIO;
+ r = -EIO;
+ goto err;
}
+
+ BUG();
+err:
+ DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n",
+ channel, dcs_cmd);
+ return r;
+
}
EXPORT_SYMBOL(dsi_vc_dcs_read);
+int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data)
+{
+ int r;
+
+ r = dsi_vc_dcs_read(channel, dcs_cmd, data, 1);
+
+ if (r < 0)
+ return r;
+
+ if (r != 1)
+ return -EIO;
+
+ return 0;
+}
+EXPORT_SYMBOL(dsi_vc_dcs_read_1);
+
+int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data)
+{
+ int r;
+
+ r = dsi_vc_dcs_read(channel, dcs_cmd, (u8 *)data, 2);
+
+ if (r < 0)
+ return r;
+
+ if (r != 2)
+ return -EIO;
+
+ return 0;
+}
+EXPORT_SYMBOL(dsi_vc_dcs_read_2);
int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
{
@@ -2491,15 +2476,15 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
u32 r;
int buswidth = 0;
- dsi_config_tx_fifo(DSI_FIFO_SIZE_128,
- DSI_FIFO_SIZE_0,
- DSI_FIFO_SIZE_0,
- DSI_FIFO_SIZE_0);
+ dsi_config_tx_fifo(DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32);
- dsi_config_rx_fifo(DSI_FIFO_SIZE_128,
- DSI_FIFO_SIZE_0,
- DSI_FIFO_SIZE_0,
- DSI_FIFO_SIZE_0);
+ dsi_config_rx_fifo(DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32,
+ DSI_FIFO_SIZE_32);
/* XXX what values for the timeouts? */
dsi_set_stop_state_counter(1000);
@@ -2537,12 +2522,9 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
dsi_write_reg(DSI_CTRL, r);
dsi_vc_initial_config(0);
-
- /* set all vc targets to peripheral 0 */
- dsi.vc[0].dest_per = 0;
- dsi.vc[1].dest_per = 0;
- dsi.vc[2].dest_per = 0;
- dsi.vc[3].dest_per = 0;
+ dsi_vc_initial_config(1);
+ dsi_vc_initial_config(2);
+ dsi_vc_initial_config(3);
return 0;
}
@@ -2777,18 +2759,16 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
unsigned packet_payload;
unsigned packet_len;
u32 l;
- bool use_te_trigger;
- const unsigned channel = 0;
+ const unsigned channel = dsi.update_channel;
/* line buffer is 1024 x 24bits */
/* XXX: for some reason using full buffer size causes considerable TX
* slowdown with update sizes that fill the whole buffer */
const unsigned line_buf_size = 1023 * 3;
- use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;
+ DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
+ x, y, w, h);
- if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
- DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
- x, y, w, h);
+ dsi_vc_config_vp(channel);
bytespp = dssdev->ctrl.pixel_size / 8;
bytespl = w * bytespp;
@@ -2808,15 +2788,12 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
if (bytespf % packet_payload)
total_len += (bytespf % packet_payload) + 1;
- if (0)
- dsi_vc_print_status(1);
-
l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
dsi_write_reg(DSI_VC_TE(channel), l);
dsi_vc_write_long_header(channel, DSI_DT_DCS_LONG_WRITE, packet_len, 0);
- if (use_te_trigger)
+ if (dsi.te_enabled)
l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
else
l = FLD_MOD(l, 1, 31, 31); /* TE_START */
@@ -2830,9 +2807,14 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
*/
dispc_disable_sidle();
+ dsi_perf_mark_start();
+
+ schedule_delayed_work(&dsi.framedone_timeout_work,
+ msecs_to_jiffies(250));
+
dss_start_update(dssdev);
- if (use_te_trigger) {
+ if (dsi.te_enabled) {
/* disable LP_RX_TO, so that we can receive TE. Time to wait
* for TE is longer than the timer allows */
REG_FLD_MOD(DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
@@ -2852,110 +2834,64 @@ static void dsi_te_timeout(unsigned long arg)
}
#endif
-static void dsi_framedone_irq_callback(void *data, u32 mask)
+static void dsi_framedone_timeout_work_callback(struct work_struct *work)
{
- /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
- * turns itself off. However, DSI still has the pixels in its buffers,
- * and is sending the data.
- */
+ int r;
+ const int channel = dsi.update_channel;
+
+ DSSERR("Framedone not received for 250ms!\n");
/* SIDLEMODE back to smart-idle */
dispc_enable_sidle();
- dsi.framedone_received = true;
- wake_up(&dsi.waitqueue);
-}
-
-static void dsi_set_update_region(struct omap_dss_device *dssdev,
- u16 x, u16 y, u16 w, u16 h)
-{
- spin_lock(&dsi.update_lock);
- if (dsi.update_region.dirty) {
- dsi.update_region.x = min(x, dsi.update_region.x);
- dsi.update_region.y = min(y, dsi.update_region.y);
- dsi.update_region.w = max(w, dsi.update_region.w);
- dsi.update_region.h = max(h, dsi.update_region.h);
- } else {
- dsi.update_region.x = x;
- dsi.update_region.y = y;
- dsi.update_region.w = w;
- dsi.update_region.h = h;
+ if (dsi.te_enabled) {
+ /* enable LP_RX_TO again after the TE */
+ REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
}
- dsi.update_region.device = dssdev;
- dsi.update_region.dirty = true;
-
- spin_unlock(&dsi.update_lock);
-
-}
-
-static int dsi_set_update_mode(struct omap_dss_device *dssdev,
- enum omap_dss_update_mode mode)
-{
- int r = 0;
- int i;
-
- WARN_ON(!mutex_is_locked(&dsi.bus_lock));
-
- if (dsi.update_mode != mode) {
- dsi.update_mode = mode;
-
- /* Mark the overlays dirty, and do apply(), so that we get the
- * overlays configured properly after update mode change. */
- for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
- struct omap_overlay *ovl;
- ovl = omap_dss_get_overlay(i);
- if (ovl->manager == dssdev->manager)
- ovl->info_dirty = true;
- }
-
- r = dssdev->manager->apply(dssdev->manager);
-
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE &&
- mode == OMAP_DSS_UPDATE_AUTO) {
- u16 w, h;
-
- DSSDBG("starting auto update\n");
-
- dssdev->get_resolution(dssdev, &w, &h);
-
- dsi_set_update_region(dssdev, 0, 0, w, h);
-
- dsi_perf_mark_start_auto();
+ /* Send BTA after the frame. We need this for the TE to work, as TE
+ * trigger is only sent for BTAs without preceding packet. Thus we need
+ * to BTA after the pixel packets so that next BTA will cause TE
+ * trigger.
+ *
+ * This is not needed when TE is not in use, but we do it anyway to
+ * make sure that the transfer has been completed. It would be more
+ * optimal, but more complex, to wait only just before starting next
+ * transfer. */
+ r = dsi_vc_send_bta_sync(channel);
+ if (r)
+ DSSERR("BTA after framedone failed\n");
- wake_up(&dsi.waitqueue);
- }
+ /* RX_FIFO_NOT_EMPTY */
+ if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
+ DSSERR("Received error during frame transfer:\n");
+ dsi_vc_flush_receive_data(channel);
}
- return r;
+ dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data);
}
-static int dsi_set_te(struct omap_dss_device *dssdev, bool enable)
+static void dsi_framedone_irq_callback(void *data, u32 mask)
{
- int r = 0;
+ /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
+ * turns itself off. However, DSI still has the pixels in its buffers,
+ * and is sending the data.
+ */
- if (dssdev->driver->enable_te) {
- r = dssdev->driver->enable_te(dssdev, enable);
- /* XXX for some reason, DSI TE breaks if we don't wait here.
- * Panel bug? Needs more studying */
- msleep(100);
- }
+ /* SIDLEMODE back to smart-idle */
+ dispc_enable_sidle();
- return r;
+ schedule_work(&dsi.framedone_work);
}
static void dsi_handle_framedone(void)
{
int r;
- const int channel = 0;
- bool use_te_trigger;
-
- use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;
+ const int channel = dsi.update_channel;
- if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
- DSSDBG("FRAMEDONE\n");
+ DSSDBG("FRAMEDONE\n");
- if (use_te_trigger) {
+ if (dsi.te_enabled) {
/* enable LP_RX_TO again after the TE */
REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
}
@@ -2976,7 +2912,7 @@ static void dsi_handle_framedone(void)
/* RX_FIFO_NOT_EMPTY */
if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
DSSERR("Received error during frame transfer:\n");
- dsi_vc_flush_receive_data(0);
+ dsi_vc_flush_receive_data(channel);
}
#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
@@ -2984,118 +2920,79 @@ static void dsi_handle_framedone(void)
#endif
}
-static int dsi_update_thread(void *data)
+static void dsi_framedone_work_callback(struct work_struct *work)
{
- unsigned long timeout;
- struct omap_dss_device *device;
- u16 x, y, w, h;
-
- while (1) {
- bool sched;
-
- wait_event_interruptible(dsi.waitqueue,
- dsi.update_mode == OMAP_DSS_UPDATE_AUTO ||
- (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL &&
- dsi.update_region.dirty == true) ||
- kthread_should_stop());
-
- if (kthread_should_stop())
- break;
-
- dsi_bus_lock();
-
- if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED ||
- kthread_should_stop()) {
- dsi_bus_unlock();
- break;
- }
-
- dsi_perf_mark_setup();
-
- if (dsi.update_region.dirty) {
- spin_lock(&dsi.update_lock);
- dsi.active_update_region = dsi.update_region;
- dsi.update_region.dirty = false;
- spin_unlock(&dsi.update_lock);
- }
+ DSSDBGF();
- device = dsi.active_update_region.device;
- x = dsi.active_update_region.x;
- y = dsi.active_update_region.y;
- w = dsi.active_update_region.w;
- h = dsi.active_update_region.h;
+ cancel_delayed_work_sync(&dsi.framedone_timeout_work);
- if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
+ dsi_handle_framedone();
- if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL)
- dss_setup_partial_planes(device,
- &x, &y, &w, &h);
+ dsi_perf_show("DISPC");
- dispc_set_lcd_size(w, h);
- }
+ dsi.framedone_callback(0, dsi.framedone_data);
+}
- if (dsi.active_update_region.dirty) {
- dsi.active_update_region.dirty = false;
- /* XXX TODO we don't need to send the coords, if they
- * are the same that are already programmed to the
- * panel. That should speed up manual update a bit */
- device->driver->setup_update(device, x, y, w, h);
- }
+int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
+ u16 *x, u16 *y, u16 *w, u16 *h)
+{
+ u16 dw, dh;
- dsi_perf_mark_start();
+ dssdev->driver->get_resolution(dssdev, &dw, &dh);
- if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
- dsi_vc_config_vp(0);
+ if (*x > dw || *y > dh)
+ return -EINVAL;
- if (dsi.te_enabled && dsi.use_ext_te)
- device->driver->wait_for_te(device);
+ if (*x + *w > dw)
+ return -EINVAL;
- dsi.framedone_received = false;
+ if (*y + *h > dh)
+ return -EINVAL;
- dsi_update_screen_dispc(device, x, y, w, h);
+ if (*w == 1)
+ return -EINVAL;
- /* wait for framedone */
- timeout = msecs_to_jiffies(1000);
- wait_event_timeout(dsi.waitqueue,
- dsi.framedone_received == true,
- timeout);
+ if (*w == 0 || *h == 0)
+ return -EINVAL;
- if (!dsi.framedone_received) {
- DSSERR("framedone timeout\n");
- DSSERR("failed update %d,%d %dx%d\n",
- x, y, w, h);
+ dsi_perf_mark_setup();
- dispc_enable_sidle();
- dispc_enable_lcd_out(0);
+ if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
+ dss_setup_partial_planes(dssdev, x, y, w, h);
+ dispc_set_lcd_size(*w, *h);
+ }
- dsi_reset_tx_fifo(0);
- } else {
- dsi_handle_framedone();
- dsi_perf_show("DISPC");
- }
- } else {
- dsi_update_screen_l4(device, x, y, w, h);
- dsi_perf_show("L4");
- }
+ return 0;
+}
+EXPORT_SYMBOL(omap_dsi_prepare_update);
- sched = atomic_read(&dsi.bus_lock.count) < 0;
+int omap_dsi_update(struct omap_dss_device *dssdev,
+ int channel,
+ u16 x, u16 y, u16 w, u16 h,
+ void (*callback)(int, void *), void *data)
+{
+ dsi.update_channel = channel;
- complete_all(&dsi.update_completion);
+ if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
+ dsi.framedone_callback = callback;
+ dsi.framedone_data = data;
- dsi_bus_unlock();
+ dsi.update_region.x = x;
+ dsi.update_region.y = y;
+ dsi.update_region.w = w;
+ dsi.update_region.h = h;
+ dsi.update_region.device = dssdev;
- /* XXX We need to give others chance to get the bus lock. Is
- * there a better way for this? */
- if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO && sched)
- schedule_timeout_interruptible(1);
+ dsi_update_screen_dispc(dssdev, x, y, w, h);
+ } else {
+ dsi_update_screen_l4(dssdev, x, y, w, h);
+ dsi_perf_show("L4");
+ callback(0, data);
}
- DSSDBG("update thread exiting\n");
-
return 0;
}
-
-
+EXPORT_SYMBOL(omap_dsi_update);
/* Display funcs */
@@ -3203,7 +3100,8 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
if (r)
goto err1;
- dss_select_clk_source(true, true);
+ dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
+ dss_select_dsi_clk_source(DSS_SRC_DSI2_PLL_FCLK);
DSSDBG("PLL OK\n");
@@ -3229,25 +3127,18 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
/* enable interface */
dsi_vc_enable(0, 1);
+ dsi_vc_enable(1, 1);
+ dsi_vc_enable(2, 1);
+ dsi_vc_enable(3, 1);
dsi_if_enable(1);
dsi_force_tx_stop_mode_io();
- if (dssdev->driver->enable) {
- r = dssdev->driver->enable(dssdev);
- if (r)
- goto err4;
- }
-
- /* enable high-speed after initial config */
- dsi_vc_enable_hs(0, 1);
-
return 0;
-err4:
- dsi_if_enable(0);
err3:
dsi_complexio_uninit();
err2:
- dss_select_clk_source(false, false);
+ dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+ dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
err1:
dsi_pll_uninit();
err0:
@@ -3256,10 +3147,8 @@ err0:
static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
{
- if (dssdev->driver->disable)
- dssdev->driver->disable(dssdev);
-
- dss_select_clk_source(false, false);
+ dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+ dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
dsi_complexio_uninit();
dsi_pll_uninit();
}
@@ -3280,14 +3169,15 @@ static int dsi_core_init(void)
return 0;
}
-static int dsi_display_enable(struct omap_dss_device *dssdev)
+int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
{
int r = 0;
DSSDBG("dsi_display_enable\n");
+ WARN_ON(!dsi_bus_is_locked());
+
mutex_lock(&dsi.lock);
- dsi_bus_lock();
r = omap_dss_start_device(dssdev);
if (r) {
@@ -3295,100 +3185,47 @@ static int dsi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
- if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
- DSSERR("dssdev already enabled\n");
- r = -EINVAL;
- goto err1;
- }
-
enable_clocks(1);
dsi_enable_pll_clock(1);
r = _dsi_reset();
if (r)
- goto err2;
+ goto err1;
dsi_core_init();
r = dsi_display_init_dispc(dssdev);
if (r)
- goto err2;
+ goto err1;
r = dsi_display_init_dsi(dssdev);
if (r)
- goto err3;
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- dsi.use_ext_te = dssdev->phy.dsi.ext_te;
- r = dsi_set_te(dssdev, dsi.te_enabled);
- if (r)
- goto err4;
-
- dsi_set_update_mode(dssdev, dsi.user_update_mode);
+ goto err2;
- dsi_bus_unlock();
mutex_unlock(&dsi.lock);
return 0;
-err4:
-
- dsi_display_uninit_dsi(dssdev);
-err3:
- dsi_display_uninit_dispc(dssdev);
err2:
+ dsi_display_uninit_dispc(dssdev);
+err1:
enable_clocks(0);
dsi_enable_pll_clock(0);
-err1:
omap_dss_stop_device(dssdev);
err0:
- dsi_bus_unlock();
mutex_unlock(&dsi.lock);
DSSDBG("dsi_display_enable FAILED\n");
return r;
}
+EXPORT_SYMBOL(omapdss_dsi_display_enable);
-static void dsi_display_disable(struct omap_dss_device *dssdev)
+void omapdss_dsi_display_disable(struct omap_dss_device *dssdev)
{
DSSDBG("dsi_display_disable\n");
- mutex_lock(&dsi.lock);
- dsi_bus_lock();
-
- if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
- dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
- goto end;
-
- dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-
- dsi_display_uninit_dispc(dssdev);
-
- dsi_display_uninit_dsi(dssdev);
-
- enable_clocks(0);
- dsi_enable_pll_clock(0);
-
- omap_dss_stop_device(dssdev);
-end:
- dsi_bus_unlock();
- mutex_unlock(&dsi.lock);
-}
-
-static int dsi_display_suspend(struct omap_dss_device *dssdev)
-{
- DSSDBG("dsi_display_suspend\n");
+ WARN_ON(!dsi_bus_is_locked());
mutex_lock(&dsi.lock);
- dsi_bus_lock();
-
- if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
- dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
- goto end;
-
- dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
- dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
dsi_display_uninit_dispc(dssdev);
@@ -3396,312 +3233,19 @@ static int dsi_display_suspend(struct omap_dss_device *dssdev)
enable_clocks(0);
dsi_enable_pll_clock(0);
-end:
- dsi_bus_unlock();
- mutex_unlock(&dsi.lock);
-
- return 0;
-}
-
-static int dsi_display_resume(struct omap_dss_device *dssdev)
-{
- int r;
-
- DSSDBG("dsi_display_resume\n");
-
- mutex_lock(&dsi.lock);
- dsi_bus_lock();
-
- if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
- DSSERR("dssdev not suspended\n");
- r = -EINVAL;
- goto err0;
- }
-
- enable_clocks(1);
- dsi_enable_pll_clock(1);
-
- r = _dsi_reset();
- if (r)
- goto err1;
-
- dsi_core_init();
-
- r = dsi_display_init_dispc(dssdev);
- if (r)
- goto err1;
-
- r = dsi_display_init_dsi(dssdev);
- if (r)
- goto err2;
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- r = dsi_set_te(dssdev, dsi.te_enabled);
- if (r)
- goto err2;
-
- dsi_set_update_mode(dssdev, dsi.user_update_mode);
-
- dsi_bus_unlock();
- mutex_unlock(&dsi.lock);
-
- return 0;
-
-err2:
- dsi_display_uninit_dispc(dssdev);
-err1:
- enable_clocks(0);
- dsi_enable_pll_clock(0);
-err0:
- dsi_bus_unlock();
- mutex_unlock(&dsi.lock);
- DSSDBG("dsi_display_resume FAILED\n");
- return r;
-}
-
-static int dsi_display_update(struct omap_dss_device *dssdev,
- u16 x, u16 y, u16 w, u16 h)
-{
- int r = 0;
- u16 dw, dh;
-
- DSSDBG("dsi_display_update(%d,%d %dx%d)\n", x, y, w, h);
- mutex_lock(&dsi.lock);
-
- if (dsi.update_mode != OMAP_DSS_UPDATE_MANUAL)
- goto end;
-
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- goto end;
-
- dssdev->get_resolution(dssdev, &dw, &dh);
-
- if (x > dw || y > dh)
- goto end;
-
- if (x + w > dw)
- w = dw - x;
-
- if (y + h > dh)
- h = dh - y;
-
- if (w == 0 || h == 0)
- goto end;
-
- if (w == 1) {
- r = -EINVAL;
- goto end;
- }
-
- dsi_set_update_region(dssdev, x, y, w, h);
-
- wake_up(&dsi.waitqueue);
-
-end:
- mutex_unlock(&dsi.lock);
-
- return r;
-}
-
-static int dsi_display_sync(struct omap_dss_device *dssdev)
-{
- bool wait;
-
- DSSDBG("dsi_display_sync()\n");
-
- mutex_lock(&dsi.lock);
- dsi_bus_lock();
-
- if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL &&
- dsi.update_region.dirty) {
- INIT_COMPLETION(dsi.update_completion);
- wait = true;
- } else {
- wait = false;
- }
-
- dsi_bus_unlock();
- mutex_unlock(&dsi.lock);
-
- if (wait)
- wait_for_completion_interruptible(&dsi.update_completion);
-
- DSSDBG("dsi_display_sync() done\n");
- return 0;
-}
-
-static int dsi_display_set_update_mode(struct omap_dss_device *dssdev,
- enum omap_dss_update_mode mode)
-{
- int r = 0;
-
- DSSDBGF("%d", mode);
-
- mutex_lock(&dsi.lock);
- dsi_bus_lock();
-
- dsi.user_update_mode = mode;
- r = dsi_set_update_mode(dssdev, mode);
+ omap_dss_stop_device(dssdev);
- dsi_bus_unlock();
mutex_unlock(&dsi.lock);
-
- return r;
}
+EXPORT_SYMBOL(omapdss_dsi_display_disable);
-static enum omap_dss_update_mode dsi_display_get_update_mode(
- struct omap_dss_device *dssdev)
+int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
{
- return dsi.update_mode;
-}
-
-
-static int dsi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
-{
- int r = 0;
-
- DSSDBGF("%d", enable);
-
- if (!dssdev->driver->enable_te)
- return -ENOENT;
-
- dsi_bus_lock();
-
dsi.te_enabled = enable;
-
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- goto end;
-
- r = dsi_set_te(dssdev, enable);
-end:
- dsi_bus_unlock();
-
- return r;
-}
-
-static int dsi_display_get_te(struct omap_dss_device *dssdev)
-{
- return dsi.te_enabled;
-}
-
-static int dsi_display_set_rotate(struct omap_dss_device *dssdev, u8 rotate)
-{
-
- DSSDBGF("%d", rotate);
-
- if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
- return -EINVAL;
-
- dsi_bus_lock();
- dssdev->driver->set_rotate(dssdev, rotate);
- if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) {
- u16 w, h;
- /* the display dimensions may have changed, so set a new
- * update region */
- dssdev->get_resolution(dssdev, &w, &h);
- dsi_set_update_region(dssdev, 0, 0, w, h);
- }
- dsi_bus_unlock();
-
return 0;
}
-
-static u8 dsi_display_get_rotate(struct omap_dss_device *dssdev)
-{
- if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
- return 0;
-
- return dssdev->driver->get_rotate(dssdev);
-}
-
-static int dsi_display_set_mirror(struct omap_dss_device *dssdev, bool mirror)
-{
- DSSDBGF("%d", mirror);
-
- if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
- return -EINVAL;
-
- dsi_bus_lock();
- dssdev->driver->set_mirror(dssdev, mirror);
- dsi_bus_unlock();
-
- return 0;
-}
-
-static bool dsi_display_get_mirror(struct omap_dss_device *dssdev)
-{
- if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
- return 0;
-
- return dssdev->driver->get_mirror(dssdev);
-}
-
-static int dsi_display_run_test(struct omap_dss_device *dssdev, int test_num)
-{
- int r;
-
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- return -EIO;
-
- DSSDBGF("%d", test_num);
-
- dsi_bus_lock();
-
- /* run test first in low speed mode */
- dsi_vc_enable_hs(0, 0);
-
- if (dssdev->driver->run_test) {
- r = dssdev->driver->run_test(dssdev, test_num);
- if (r)
- goto end;
- }
-
- /* then in high speed */
- dsi_vc_enable_hs(0, 1);
-
- if (dssdev->driver->run_test) {
- r = dssdev->driver->run_test(dssdev, test_num);
- if (r)
- goto end;
- }
-
-end:
- dsi_vc_enable_hs(0, 1);
-
- dsi_bus_unlock();
-
- return r;
-}
-
-static int dsi_display_memory_read(struct omap_dss_device *dssdev,
- void *buf, size_t size,
- u16 x, u16 y, u16 w, u16 h)
-{
- int r;
-
- DSSDBGF("");
-
- if (!dssdev->driver->memory_read)
- return -EINVAL;
-
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- return -EIO;
-
- dsi_bus_lock();
-
- r = dssdev->driver->memory_read(dssdev, buf, size,
- x, y, w, h);
-
- /* Memory read usually changes the update area. This will
- * force the next update to re-set the update area */
- dsi.active_update_region.dirty = true;
-
- dsi_bus_unlock();
-
- return r;
-}
+EXPORT_SYMBOL(omapdss_dsi_enable_te);
void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
u32 fifo_size, enum omap_burst_size *burst_size,
@@ -3720,26 +3264,6 @@ int dsi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("DSI init\n");
- dssdev->enable = dsi_display_enable;
- dssdev->disable = dsi_display_disable;
- dssdev->suspend = dsi_display_suspend;
- dssdev->resume = dsi_display_resume;
- dssdev->update = dsi_display_update;
- dssdev->sync = dsi_display_sync;
- dssdev->set_update_mode = dsi_display_set_update_mode;
- dssdev->get_update_mode = dsi_display_get_update_mode;
- dssdev->enable_te = dsi_display_enable_te;
- dssdev->get_te = dsi_display_get_te;
-
- dssdev->get_rotate = dsi_display_get_rotate;
- dssdev->set_rotate = dsi_display_set_rotate;
-
- dssdev->get_mirror = dsi_display_get_mirror;
- dssdev->set_mirror = dsi_display_set_mirror;
-
- dssdev->run_test = dsi_display_run_test;
- dssdev->memory_read = dsi_display_memory_read;
-
/* XXX these should be figured out dynamically */
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
@@ -3754,9 +3278,6 @@ int dsi_init(struct platform_device *pdev)
{
u32 rev;
int r;
- struct sched_param param = {
- .sched_priority = MAX_USER_RT_PRIO-1
- };
spin_lock_init(&dsi.errors_lock);
dsi.errors = 0;
@@ -3767,31 +3288,19 @@ int dsi_init(struct platform_device *pdev)
#endif
init_completion(&dsi.bta_completion);
- init_completion(&dsi.update_completion);
-
- dsi.thread = kthread_create(dsi_update_thread, NULL, "dsi");
- if (IS_ERR(dsi.thread)) {
- DSSERR("cannot create kthread\n");
- r = PTR_ERR(dsi.thread);
- goto err0;
- }
- sched_setscheduler(dsi.thread, SCHED_FIFO, &param);
-
- init_waitqueue_head(&dsi.waitqueue);
- spin_lock_init(&dsi.update_lock);
mutex_init(&dsi.lock);
- mutex_init(&dsi.bus_lock);
+ sema_init(&dsi.bus_lock, 1);
+
+ INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback);
+ INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work,
+ dsi_framedone_timeout_work_callback);
#ifdef DSI_CATCH_MISSING_TE
init_timer(&dsi.te_timer);
dsi.te_timer.function = dsi_te_timeout;
dsi.te_timer.data = 0;
#endif
-
- dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
- dsi.user_update_mode = OMAP_DSS_UPDATE_DISABLED;
-
dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS);
if (!dsi.base) {
DSSERR("can't ioremap DSI\n");
@@ -3799,7 +3308,7 @@ int dsi_init(struct platform_device *pdev)
goto err1;
}
- dsi.vdds_dsi_reg = regulator_get(&pdev->dev, "vdds_dsi");
+ dsi.vdds_dsi_reg = dss_get_vdds_dsi();
if (IS_ERR(dsi.vdds_dsi_reg)) {
iounmap(dsi.base);
DSSERR("can't get VDDS_DSI regulator\n");
@@ -3815,23 +3324,15 @@ int dsi_init(struct platform_device *pdev)
enable_clocks(0);
- wake_up_process(dsi.thread);
-
return 0;
err2:
iounmap(dsi.base);
err1:
- kthread_stop(dsi.thread);
-err0:
return r;
}
void dsi_exit(void)
{
- kthread_stop(dsi.thread);
-
- regulator_put(dsi.vdds_dsi_reg);
-
iounmap(dsi.base);
DSSDBG("omap_dsi_exit\n");
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 0a26b7d84d41..8254a4232a53 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -68,6 +68,9 @@ static struct {
struct dss_clock_info cache_dss_cinfo;
struct dispc_clock_info cache_dispc_cinfo;
+ enum dss_clk_source dsi_clk_source;
+ enum dss_clk_source dispc_clk_source;
+
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
} dss;
@@ -247,23 +250,42 @@ void dss_dump_regs(struct seq_file *s)
#undef DUMPREG
}
-void dss_select_clk_source(bool dsi, bool dispc)
+void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
+{
+ int b;
+
+ BUG_ON(clk_src != DSS_SRC_DSI1_PLL_FCLK &&
+ clk_src != DSS_SRC_DSS1_ALWON_FCLK);
+
+ b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
+
+ REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */
+
+ dss.dispc_clk_source = clk_src;
+}
+
+void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
{
- u32 r;
- r = dss_read_reg(DSS_CONTROL);
- r = FLD_MOD(r, dsi, 1, 1); /* DSI_CLK_SWITCH */
- r = FLD_MOD(r, dispc, 0, 0); /* DISPC_CLK_SWITCH */
- dss_write_reg(DSS_CONTROL, r);
+ int b;
+
+ BUG_ON(clk_src != DSS_SRC_DSI2_PLL_FCLK &&
+ clk_src != DSS_SRC_DSS1_ALWON_FCLK);
+
+ b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
+
+ REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */
+
+ dss.dsi_clk_source = clk_src;
}
-int dss_get_dsi_clk_source(void)
+enum dss_clk_source dss_get_dispc_clk_source(void)
{
- return FLD_GET(dss_read_reg(DSS_CONTROL), 1, 1);
+ return dss.dispc_clk_source;
}
-int dss_get_dispc_clk_source(void)
+enum dss_clk_source dss_get_dsi_clk_source(void)
{
- return FLD_GET(dss_read_reg(DSS_CONTROL), 0, 0);
+ return dss.dsi_clk_source;
}
/* calculate clock rates using dividers in cinfo */
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 2bcb1245d6c2..24326a5fd292 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -119,6 +119,12 @@ enum dss_clock {
DSS_CLK_96M = 1 << 4,
};
+enum dss_clk_source {
+ DSS_SRC_DSI1_PLL_FCLK,
+ DSS_SRC_DSI2_PLL_FCLK,
+ DSS_SRC_DSS1_ALWON_FCLK,
+};
+
struct dss_clock_info {
/* rates that we get with dividers below */
unsigned long fck;
@@ -169,6 +175,9 @@ unsigned long dss_clk_get_rate(enum dss_clock clk);
int dss_need_ctx_restore(void);
void dss_dump_clocks(struct seq_file *s);
struct bus_type *dss_get_bus(void);
+struct regulator *dss_get_vdds_dsi(void);
+struct regulator *dss_get_vdds_sdi(void);
+struct regulator *dss_get_vdda_dac(void);
/* display */
int dss_suspend_all_devices(void);
@@ -216,9 +225,11 @@ void dss_sdi_init(u8 datapairs);
int dss_sdi_enable(void);
void dss_sdi_disable(void);
-void dss_select_clk_source(bool dsi, bool dispc);
-int dss_get_dsi_clk_source(void);
-int dss_get_dispc_clk_source(void);
+void dss_select_dispc_clk_source(enum dss_clk_source clk_src);
+void dss_select_dsi_clk_source(enum dss_clk_source clk_src);
+enum dss_clk_source dss_get_dispc_clk_source(void);
+enum dss_clk_source dss_get_dsi_clk_source(void);
+
void dss_set_venc_output(enum omap_dss_venc_type type);
void dss_set_dac_pwrdn_bgz(bool enable);
@@ -261,7 +272,7 @@ void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
u32 *fifo_low, u32 *fifo_high);
/* DPI */
-int dpi_init(void);
+int dpi_init(struct platform_device *pdev);
void dpi_exit(void);
int dpi_init_display(struct omap_dss_device *dssdev);
@@ -313,8 +324,8 @@ int dispc_setup_plane(enum omap_plane plane,
bool dispc_go_busy(enum omap_channel channel);
void dispc_go(enum omap_channel channel);
-void dispc_enable_lcd_out(bool enable);
-void dispc_enable_digit_out(bool enable);
+void dispc_enable_channel(enum omap_channel channel, bool enable);
+bool dispc_is_channel_enabled(enum omap_channel channel);
int dispc_enable_plane(enum omap_plane plane, bool enable);
void dispc_enable_replication(enum omap_plane plane, bool enable);
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index 27d9c465c851..9acef00c47ea 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -341,7 +341,7 @@ static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
return manager_attr->store(manager, buf, size);
}
-static struct sysfs_ops manager_sysfs_ops = {
+static const struct sysfs_ops manager_sysfs_ops = {
.show = manager_attr_show,
.store = manager_attr_store,
};
@@ -501,6 +501,19 @@ static int omap_dss_unset_device(struct omap_overlay_manager *mgr)
return 0;
}
+static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
+{
+ unsigned long timeout = msecs_to_jiffies(500);
+ u32 irq;
+
+ if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC)
+ irq = DISPC_IRQ_EVSYNC_ODD;
+ else
+ irq = DISPC_IRQ_VSYNC;
+
+ return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
+}
+
static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
{
unsigned long timeout = msecs_to_jiffies(500);
@@ -509,17 +522,18 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
u32 irq;
int r;
int i;
+ struct omap_dss_device *dssdev = mgr->device;
- if (!mgr->device)
+ if (!dssdev)
return 0;
- if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
+ if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
channel = OMAP_DSS_CHANNEL_DIGIT;
} else {
- if (mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
+ if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
enum omap_dss_update_mode mode;
- mode = mgr->device->get_update_mode(mgr->device);
+ mode = dssdev->driver->get_update_mode(dssdev);
if (mode != OMAP_DSS_UPDATE_AUTO)
return 0;
@@ -592,7 +606,7 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
} else {
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
enum omap_dss_update_mode mode;
- mode = dssdev->get_update_mode(dssdev);
+ mode = dssdev->driver->get_update_mode(dssdev);
if (mode != OMAP_DSS_UPDATE_AUTO)
return 0;
@@ -1064,7 +1078,7 @@ void dss_start_update(struct omap_dss_device *dssdev)
mc->shadow_dirty = false;
}
- dispc_enable_lcd_out(1);
+ dssdev->manager->enable(dssdev->manager);
}
static void dss_apply_irq_handler(void *data, u32 mask)
@@ -1196,7 +1210,8 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
oc->manual_update =
dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
- dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
+ dssdev->driver->get_update_mode(dssdev) !=
+ OMAP_DSS_UPDATE_AUTO;
++num_planes_enabled;
}
@@ -1237,7 +1252,8 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
mc->manual_update =
dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
- dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
+ dssdev->driver->get_update_mode(dssdev) !=
+ OMAP_DSS_UPDATE_AUTO;
}
/* XXX TODO: Try to get fifomerge working. The problem is that it
@@ -1351,6 +1367,18 @@ static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
*info = mgr->info;
}
+static int dss_mgr_enable(struct omap_overlay_manager *mgr)
+{
+ dispc_enable_channel(mgr->id, 1);
+ return 0;
+}
+
+static int dss_mgr_disable(struct omap_overlay_manager *mgr)
+{
+ dispc_enable_channel(mgr->id, 0);
+ return 0;
+}
+
static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
{
++num_managers;
@@ -1394,6 +1422,10 @@ int dss_init_overlay_managers(struct platform_device *pdev)
mgr->set_manager_info = &omap_dss_mgr_set_info;
mgr->get_manager_info = &omap_dss_mgr_get_info;
mgr->wait_for_go = &dss_mgr_wait_for_go;
+ mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
+
+ mgr->enable = &dss_mgr_enable;
+ mgr->disable = &dss_mgr_disable;
mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
index b7f9a7339842..aed3f3194347 100644
--- a/drivers/video/omap2/dss/overlay.c
+++ b/drivers/video/omap2/dss/overlay.c
@@ -320,7 +320,7 @@ static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
return overlay_attr->store(overlay, buf, size);
}
-static struct sysfs_ops overlay_sysfs_ops = {
+static const struct sysfs_ops overlay_sysfs_ops = {
.show = overlay_attr_show,
.store = overlay_attr_store,
};
@@ -350,7 +350,7 @@ int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
return -EINVAL;
}
- dssdev->get_resolution(dssdev, &dw, &dh);
+ dssdev->driver->get_resolution(dssdev, &dw, &dh);
DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n",
ovl->id,
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index b936495c065d..cc23f53cc62d 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -36,8 +36,6 @@
#include <plat/display.h>
#include "dss.h"
-/*#define MEASURE_PERF*/
-
#define RFBI_BASE 0x48050800
struct rfbi_reg { u16 idx; };
@@ -66,8 +64,6 @@ struct rfbi_reg { u16 idx; };
#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090)
#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094)
-#define RFBI_CMD_FIFO_LEN_BYTES (16 * sizeof(struct update_param))
-
#define REG_FLD_MOD(idx, val, start, end) \
rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
@@ -102,7 +98,6 @@ enum update_cmd {
static int rfbi_convert_timings(struct rfbi_timings *t);
static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
-static void process_cmd_fifo(void);
static struct {
void __iomem *base;
@@ -125,11 +120,6 @@ static struct {
struct completion cmd_done;
atomic_t cmd_fifo_full;
atomic_t cmd_pending;
-#ifdef MEASURE_PERF
- unsigned perf_bytes;
- ktime_t perf_setup_time;
- ktime_t perf_start_time;
-#endif
} rfbi;
struct update_region {
@@ -139,16 +129,6 @@ struct update_region {
u16 h;
};
-struct update_param {
- u8 rfbi_module;
- u8 cmd;
-
- union {
- struct update_region r;
- struct completion *sync;
- } par;
-};
-
static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
{
__raw_writel(val, rfbi.base + idx.idx);
@@ -321,55 +301,6 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
}
EXPORT_SYMBOL(omap_rfbi_write_pixels);
-#ifdef MEASURE_PERF
-static void perf_mark_setup(void)
-{
- rfbi.perf_setup_time = ktime_get();
-}
-
-static void perf_mark_start(void)
-{
- rfbi.perf_start_time = ktime_get();
-}
-
-static void perf_show(const char *name)
-{
- ktime_t t, setup_time, trans_time;
- u32 total_bytes;
- u32 setup_us, trans_us, total_us;
-
- t = ktime_get();
-
- setup_time = ktime_sub(rfbi.perf_start_time, rfbi.perf_setup_time);
- setup_us = (u32)ktime_to_us(setup_time);
- if (setup_us == 0)
- setup_us = 1;
-
- trans_time = ktime_sub(t, rfbi.perf_start_time);
- trans_us = (u32)ktime_to_us(trans_time);
- if (trans_us == 0)
- trans_us = 1;
-
- total_us = setup_us + trans_us;
-
- total_bytes = rfbi.perf_bytes;
-
- DSSINFO("%s update %u us + %u us = %u us (%uHz), %u bytes, "
- "%u kbytes/sec\n",
- name,
- setup_us,
- trans_us,
- total_us,
- 1000*1000 / total_us,
- total_bytes,
- total_bytes * 1000 / total_us);
-}
-#else
-#define perf_mark_setup()
-#define perf_mark_start()
-#define perf_show(x)
-#endif
-
void rfbi_transfer_area(u16 width, u16 height,
void (callback)(void *data), void *data)
{
@@ -382,7 +313,7 @@ void rfbi_transfer_area(u16 width, u16 height,
dispc_set_lcd_size(width, height);
- dispc_enable_lcd_out(1);
+ dispc_enable_channel(OMAP_DSS_CHANNEL_LCD, true);
rfbi.framedone_callback = callback;
rfbi.framedone_callback_data = data;
@@ -396,8 +327,6 @@ void rfbi_transfer_area(u16 width, u16 height,
if (!rfbi.te_enabled)
l = FLD_MOD(l, 1, 4, 4); /* ITE */
- perf_mark_start();
-
rfbi_write_reg(RFBI_CONTROL, l);
}
@@ -407,8 +336,6 @@ static void framedone_callback(void *data, u32 mask)
DSSDBG("FRAMEDONE\n");
- perf_show("DISPC");
-
REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
rfbi_enable_clocks(0);
@@ -416,11 +343,10 @@ static void framedone_callback(void *data, u32 mask)
callback = rfbi.framedone_callback;
rfbi.framedone_callback = NULL;
- /*callback(rfbi.framedone_callback_data);*/
+ if (callback != NULL)
+ callback(rfbi.framedone_callback_data);
atomic_set(&rfbi.cmd_pending, 0);
-
- process_cmd_fifo();
}
#if 1 /* VERBOSE */
@@ -937,52 +863,43 @@ int rfbi_configure(int rfbi_module, int bpp, int lines)
}
EXPORT_SYMBOL(rfbi_configure);
-static int rfbi_find_display(struct omap_dss_device *dssdev)
+int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
+ u16 *x, u16 *y, u16 *w, u16 *h)
{
- if (dssdev == rfbi.dssdev[0])
- return 0;
+ u16 dw, dh;
- if (dssdev == rfbi.dssdev[1])
- return 1;
+ dssdev->driver->get_resolution(dssdev, &dw, &dh);
- BUG();
- return -1;
-}
+ if (*x > dw || *y > dh)
+ return -EINVAL;
+ if (*x + *w > dw)
+ return -EINVAL;
-static void signal_fifo_waiters(void)
-{
- if (atomic_read(&rfbi.cmd_fifo_full) > 0) {
- /* DSSDBG("SIGNALING: Fifo not full for waiter!\n"); */
- complete(&rfbi.cmd_done);
- atomic_dec(&rfbi.cmd_fifo_full);
- }
-}
+ if (*y + *h > dh)
+ return -EINVAL;
-/* returns 1 for async op, and 0 for sync op */
-static int do_update(struct omap_dss_device *dssdev, struct update_region *upd)
-{
- u16 x = upd->x;
- u16 y = upd->y;
- u16 w = upd->w;
- u16 h = upd->h;
+ if (*w == 1)
+ return -EINVAL;
- perf_mark_setup();
+ if (*w == 0 || *h == 0)
+ return -EINVAL;
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
- /*dssdev->driver->enable_te(dssdev, 1); */
- dss_setup_partial_planes(dssdev, &x, &y, &w, &h);
+ dss_setup_partial_planes(dssdev, x, y, w, h);
+ dispc_set_lcd_size(*w, *h);
}
-#ifdef MEASURE_PERF
- rfbi.perf_bytes = w * h * 2; /* XXX always 16bit */
-#endif
-
- dssdev->driver->setup_update(dssdev, x, y, w, h);
+ return 0;
+}
+EXPORT_SYMBOL(omap_rfbi_prepare_update);
+int omap_rfbi_update(struct omap_dss_device *dssdev,
+ u16 x, u16 y, u16 w, u16 h,
+ void (*callback)(void *), void *data)
+{
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
- rfbi_transfer_area(w, h, NULL, NULL);
- return 1;
+ rfbi_transfer_area(w, h, callback, data);
} else {
struct omap_overlay *ovl;
void __iomem *addr;
@@ -994,123 +911,12 @@ static int do_update(struct omap_dss_device *dssdev, struct update_region *upd)
omap_rfbi_write_pixels(addr, scr_width, x, y, w, h);
- perf_show("L4");
-
- return 0;
+ callback(data);
}
-}
-
-static void process_cmd_fifo(void)
-{
- int len;
- struct update_param p;
- struct omap_dss_device *dssdev;
- unsigned long flags;
-
- if (atomic_inc_return(&rfbi.cmd_pending) != 1)
- return;
-
- while (true) {
- spin_lock_irqsave(&rfbi.cmd_lock, flags);
-
- len = kfifo_out(&rfbi.cmd_fifo, (unsigned char *)&p,
- sizeof(struct update_param));
- if (len == 0) {
- DSSDBG("nothing more in fifo\n");
- atomic_set(&rfbi.cmd_pending, 0);
- spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
- break;
- }
-
- /* DSSDBG("fifo full %d\n", rfbi.cmd_fifo_full.counter);*/
-
- spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
-
- BUG_ON(len != sizeof(struct update_param));
- BUG_ON(p.rfbi_module > 1);
-
- dssdev = rfbi.dssdev[p.rfbi_module];
-
- if (p.cmd == RFBI_CMD_UPDATE) {
- if (do_update(dssdev, &p.par.r))
- break; /* async op */
- } else if (p.cmd == RFBI_CMD_SYNC) {
- DSSDBG("Signaling SYNC done!\n");
- complete(p.par.sync);
- } else
- BUG();
- }
-
- signal_fifo_waiters();
-}
-static void rfbi_push_cmd(struct update_param *p)
-{
- int ret;
-
- while (1) {
- unsigned long flags;
- int available;
-
- spin_lock_irqsave(&rfbi.cmd_lock, flags);
- available = RFBI_CMD_FIFO_LEN_BYTES -
- kfifo_len(&rfbi.cmd_fifo);
-
-/* DSSDBG("%d bytes left in fifo\n", available); */
- if (available < sizeof(struct update_param)) {
- DSSDBG("Going to wait because FIFO FULL..\n");
- spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
- atomic_inc(&rfbi.cmd_fifo_full);
- wait_for_completion(&rfbi.cmd_done);
- /*DSSDBG("Woke up because fifo not full anymore\n");*/
- continue;
- }
-
- ret = kfifo_in(&rfbi.cmd_fifo, (unsigned char *)p,
- sizeof(struct update_param));
-/* DSSDBG("pushed %d bytes\n", ret);*/
-
- spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
-
- BUG_ON(ret != sizeof(struct update_param));
-
- break;
- }
-}
-
-static void rfbi_push_update(int rfbi_module, int x, int y, int w, int h)
-{
- struct update_param p;
-
- p.rfbi_module = rfbi_module;
- p.cmd = RFBI_CMD_UPDATE;
-
- p.par.r.x = x;
- p.par.r.y = y;
- p.par.r.w = w;
- p.par.r.h = h;
-
- DSSDBG("RFBI pushed %d,%d %dx%d\n", x, y, w, h);
-
- rfbi_push_cmd(&p);
-
- process_cmd_fifo();
-}
-
-static void rfbi_push_sync(int rfbi_module, struct completion *sync_comp)
-{
- struct update_param p;
-
- p.rfbi_module = rfbi_module;
- p.cmd = RFBI_CMD_SYNC;
- p.par.sync = sync_comp;
-
- rfbi_push_cmd(&p);
-
- DSSDBG("RFBI sync pushed to cmd fifo\n");
-
- process_cmd_fifo();
+ return 0;
}
+EXPORT_SYMBOL(omap_rfbi_update);
void rfbi_dump_regs(struct seq_file *s)
{
@@ -1155,12 +961,8 @@ int rfbi_init(void)
{
u32 rev;
u32 l;
- int r;
spin_lock_init(&rfbi.cmd_lock);
- r = kfifo_alloc(&rfbi.cmd_fifo, RFBI_CMD_FIFO_LEN_BYTES, GFP_KERNEL);
- if (r)
- return r;
init_completion(&rfbi.cmd_done);
atomic_set(&rfbi.cmd_fifo_full, 0);
@@ -1196,49 +998,10 @@ void rfbi_exit(void)
{
DSSDBG("rfbi_exit\n");
- kfifo_free(&rfbi.cmd_fifo);
-
iounmap(rfbi.base);
}
-/* struct omap_display support */
-static int rfbi_display_update(struct omap_dss_device *dssdev,
- u16 x, u16 y, u16 w, u16 h)
-{
- int rfbi_module;
-
- if (w == 0 || h == 0)
- return 0;
-
- rfbi_module = rfbi_find_display(dssdev);
-
- rfbi_push_update(rfbi_module, x, y, w, h);
-
- return 0;
-}
-
-static int rfbi_display_sync(struct omap_dss_device *dssdev)
-{
- struct completion sync_comp;
- int rfbi_module;
-
- rfbi_module = rfbi_find_display(dssdev);
-
- init_completion(&sync_comp);
- rfbi_push_sync(rfbi_module, &sync_comp);
- DSSDBG("Waiting for SYNC to happen...\n");
- wait_for_completion(&sync_comp);
- DSSDBG("Released from SYNC\n");
- return 0;
-}
-
-static int rfbi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
-{
- dssdev->driver->enable_te(dssdev, enable);
- return 0;
-}
-
-static int rfbi_display_enable(struct omap_dss_device *dssdev)
+int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
{
int r;
@@ -1269,41 +1032,25 @@ static int rfbi_display_enable(struct omap_dss_device *dssdev)
&dssdev->ctrl.rfbi_timings);
- if (dssdev->driver->enable) {
- r = dssdev->driver->enable(dssdev);
- if (r)
- goto err2;
- }
-
return 0;
-err2:
- omap_dispc_unregister_isr(framedone_callback, NULL,
- DISPC_IRQ_FRAMEDONE);
err1:
omap_dss_stop_device(dssdev);
err0:
return r;
}
+EXPORT_SYMBOL(omapdss_rfbi_display_enable);
-static void rfbi_display_disable(struct omap_dss_device *dssdev)
+void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
{
- dssdev->driver->disable(dssdev);
omap_dispc_unregister_isr(framedone_callback, NULL,
DISPC_IRQ_FRAMEDONE);
omap_dss_stop_device(dssdev);
}
+EXPORT_SYMBOL(omapdss_rfbi_display_disable);
int rfbi_init_display(struct omap_dss_device *dssdev)
{
- dssdev->enable = rfbi_display_enable;
- dssdev->disable = rfbi_display_disable;
- dssdev->update = rfbi_display_update;
- dssdev->sync = rfbi_display_sync;
- dssdev->enable_te = rfbi_display_enable_te;
-
rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
-
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
-
return 0;
}
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index c24f307d3da1..12eb4042dd82 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -41,7 +41,7 @@ static void sdi_basic_init(void)
dispc_lcd_enable_signal_polarity(1);
}
-static int sdi_display_enable(struct omap_dss_device *dssdev)
+int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
{
struct omap_video_timings *t = &dssdev->panel.timings;
struct dss_clock_info dss_cinfo;
@@ -57,12 +57,6 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
- if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
- DSSERR("dssdev already enabled\n");
- r = -EINVAL;
- goto err1;
- }
-
/* In case of skip_init sdi_init has already enabled the clocks */
if (!sdi.skip_init)
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
@@ -119,7 +113,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
mdelay(2);
}
- dispc_enable_lcd_out(1);
+ dssdev->manager->enable(dssdev->manager);
if (dssdev->driver->enable) {
r = dssdev->driver->enable(dssdev);
@@ -127,13 +121,11 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
goto err3;
}
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
sdi.skip_init = 0;
return 0;
err3:
- dispc_enable_lcd_out(0);
+ dssdev->manager->disable(dssdev->manager);
err2:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
err1:
@@ -141,120 +133,27 @@ err1:
err0:
return r;
}
+EXPORT_SYMBOL(omapdss_sdi_display_enable);
-static int sdi_display_resume(struct omap_dss_device *dssdev);
-
-static void sdi_display_disable(struct omap_dss_device *dssdev)
+void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
{
- if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
- return;
-
- if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
- if (sdi_display_resume(dssdev))
- return;
-
if (dssdev->driver->disable)
dssdev->driver->disable(dssdev);
- dispc_enable_lcd_out(0);
+ dssdev->manager->disable(dssdev->manager);
dss_sdi_disable();
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-
omap_dss_stop_device(dssdev);
}
-
-static int sdi_display_suspend(struct omap_dss_device *dssdev)
-{
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- return -EINVAL;
-
- if (dssdev->driver->suspend)
- dssdev->driver->suspend(dssdev);
-
- dispc_enable_lcd_out(0);
-
- dss_sdi_disable();
-
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
-
- dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
-
- return 0;
-}
-
-static int sdi_display_resume(struct omap_dss_device *dssdev)
-{
- int r;
-
- if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
- return -EINVAL;
-
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
-
- r = dss_sdi_enable();
- if (r)
- goto err;
- mdelay(2);
-
- dispc_enable_lcd_out(1);
-
- if (dssdev->driver->resume)
- dssdev->driver->resume(dssdev);
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- return 0;
-err:
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
- return r;
-}
-
-static int sdi_display_set_update_mode(struct omap_dss_device *dssdev,
- enum omap_dss_update_mode mode)
-{
- if (mode == OMAP_DSS_UPDATE_MANUAL)
- return -EINVAL;
-
- if (mode == OMAP_DSS_UPDATE_DISABLED) {
- dispc_enable_lcd_out(0);
- sdi.update_enabled = 0;
- } else {
- dispc_enable_lcd_out(1);
- sdi.update_enabled = 1;
- }
-
- return 0;
-}
-
-static enum omap_dss_update_mode sdi_display_get_update_mode(
- struct omap_dss_device *dssdev)
-{
- return sdi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
- OMAP_DSS_UPDATE_DISABLED;
-}
-
-static void sdi_get_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
-{
- *timings = dssdev->panel.timings;
-}
+EXPORT_SYMBOL(omapdss_sdi_display_disable);
int sdi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("SDI init\n");
- dssdev->enable = sdi_display_enable;
- dssdev->disable = sdi_display_disable;
- dssdev->suspend = sdi_display_suspend;
- dssdev->resume = sdi_display_resume;
- dssdev->set_update_mode = sdi_display_set_update_mode;
- dssdev->get_update_mode = sdi_display_get_update_mode;
- dssdev->get_timings = sdi_get_timings;
-
return 0;
}
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 749a5a0f5be4..f0ba5732d84a 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -400,114 +400,6 @@ static const struct venc_config *venc_timings_to_config(
BUG();
}
-
-
-
-
-/* driver */
-static int venc_panel_probe(struct omap_dss_device *dssdev)
-{
- dssdev->panel.timings = omap_dss_pal_timings;
-
- return 0;
-}
-
-static void venc_panel_remove(struct omap_dss_device *dssdev)
-{
-}
-
-static int venc_panel_enable(struct omap_dss_device *dssdev)
-{
- int r = 0;
-
- /* wait couple of vsyncs until enabling the LCD */
- msleep(50);
-
- if (dssdev->platform_enable)
- r = dssdev->platform_enable(dssdev);
-
- return r;
-}
-
-static void venc_panel_disable(struct omap_dss_device *dssdev)
-{
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
- /* wait at least 5 vsyncs after disabling the LCD */
-
- msleep(100);
-}
-
-static int venc_panel_suspend(struct omap_dss_device *dssdev)
-{
- venc_panel_disable(dssdev);
- return 0;
-}
-
-static int venc_panel_resume(struct omap_dss_device *dssdev)
-{
- return venc_panel_enable(dssdev);
-}
-
-static struct omap_dss_driver venc_driver = {
- .probe = venc_panel_probe,
- .remove = venc_panel_remove,
-
- .enable = venc_panel_enable,
- .disable = venc_panel_disable,
- .suspend = venc_panel_suspend,
- .resume = venc_panel_resume,
-
- .driver = {
- .name = "venc",
- .owner = THIS_MODULE,
- },
-};
-/* driver end */
-
-
-
-int venc_init(struct platform_device *pdev)
-{
- u8 rev_id;
-
- mutex_init(&venc.venc_lock);
-
- venc.wss_data = 0;
-
- venc.base = ioremap(VENC_BASE, SZ_1K);
- if (!venc.base) {
- DSSERR("can't ioremap VENC\n");
- return -ENOMEM;
- }
-
- venc.vdda_dac_reg = regulator_get(&pdev->dev, "vdda_dac");
- if (IS_ERR(venc.vdda_dac_reg)) {
- iounmap(venc.base);
- DSSERR("can't get VDDA_DAC regulator\n");
- return PTR_ERR(venc.vdda_dac_reg);
- }
-
- venc_enable_clocks(1);
-
- rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
- printk(KERN_INFO "OMAP VENC rev %d\n", rev_id);
-
- venc_enable_clocks(0);
-
- return omap_dss_register_driver(&venc_driver);
-}
-
-void venc_exit(void)
-{
- omap_dss_unregister_driver(&venc_driver);
-
- regulator_put(venc.vdda_dac_reg);
-
- iounmap(venc.base);
-}
-
static void venc_power_on(struct omap_dss_device *dssdev)
{
u32 l;
@@ -540,7 +432,7 @@ static void venc_power_on(struct omap_dss_device *dssdev)
if (dssdev->platform_enable)
dssdev->platform_enable(dssdev);
- dispc_enable_digit_out(1);
+ dssdev->manager->enable(dssdev->manager);
}
static void venc_power_off(struct omap_dss_device *dssdev)
@@ -548,7 +440,7 @@ static void venc_power_off(struct omap_dss_device *dssdev)
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
dss_set_dac_pwrdn_bgz(0);
- dispc_enable_digit_out(0);
+ dssdev->manager->disable(dssdev->manager);
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
@@ -558,7 +450,23 @@ static void venc_power_off(struct omap_dss_device *dssdev)
venc_enable_clocks(0);
}
-static int venc_enable_display(struct omap_dss_device *dssdev)
+
+
+
+
+/* driver */
+static int venc_panel_probe(struct omap_dss_device *dssdev)
+{
+ dssdev->panel.timings = omap_dss_pal_timings;
+
+ return 0;
+}
+
+static void venc_panel_remove(struct omap_dss_device *dssdev)
+{
+}
+
+static int venc_panel_enable(struct omap_dss_device *dssdev)
{
int r = 0;
@@ -568,7 +476,13 @@ static int venc_enable_display(struct omap_dss_device *dssdev)
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
r = -EINVAL;
- goto err;
+ goto err1;
+ }
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto err2;
}
venc_power_on(dssdev);
@@ -576,13 +490,21 @@ static int venc_enable_display(struct omap_dss_device *dssdev)
venc.wss_data = 0;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-err:
+
+ /* wait couple of vsyncs until enabling the LCD */
+ msleep(50);
+
mutex_unlock(&venc.venc_lock);
return r;
+err2:
+ venc_power_off(dssdev);
+err1:
+ mutex_unlock(&venc.venc_lock);
+ return r;
}
-static void venc_disable_display(struct omap_dss_device *dssdev)
+static void venc_panel_disable(struct omap_dss_device *dssdev)
{
DSSDBG("venc_disable_display\n");
@@ -599,53 +521,40 @@ static void venc_disable_display(struct omap_dss_device *dssdev)
venc_power_off(dssdev);
+ /* wait at least 5 vsyncs after disabling the LCD */
+ msleep(100);
+
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
end:
mutex_unlock(&venc.venc_lock);
}
-static int venc_display_suspend(struct omap_dss_device *dssdev)
+static int venc_panel_suspend(struct omap_dss_device *dssdev)
{
- int r = 0;
-
- DSSDBG("venc_display_suspend\n");
-
- mutex_lock(&venc.venc_lock);
-
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
- r = -EINVAL;
- goto err;
- }
-
- venc_power_off(dssdev);
-
- dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
-err:
- mutex_unlock(&venc.venc_lock);
-
- return r;
+ venc_panel_disable(dssdev);
+ return 0;
}
-static int venc_display_resume(struct omap_dss_device *dssdev)
+static int venc_panel_resume(struct omap_dss_device *dssdev)
{
- int r = 0;
-
- DSSDBG("venc_display_resume\n");
-
- mutex_lock(&venc.venc_lock);
-
- if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
- r = -EINVAL;
- goto err;
- }
-
- venc_power_on(dssdev);
+ return venc_panel_enable(dssdev);
+}
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-err:
- mutex_unlock(&venc.venc_lock);
+static enum omap_dss_update_mode venc_get_update_mode(
+ struct omap_dss_device *dssdev)
+{
+ return OMAP_DSS_UPDATE_AUTO;
+}
- return r;
+static int venc_set_update_mode(struct omap_dss_device *dssdev,
+ enum omap_dss_update_mode mode)
+{
+ if (mode != OMAP_DSS_UPDATE_AUTO)
+ return -EINVAL;
+ return 0;
}
static void venc_get_timings(struct omap_dss_device *dssdev,
@@ -666,8 +575,8 @@ static void venc_set_timings(struct omap_dss_device *dssdev,
dssdev->panel.timings = *timings;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
/* turn the venc off and on to get new timings to use */
- venc_disable_display(dssdev);
- venc_enable_display(dssdev);
+ venc_panel_disable(dssdev);
+ venc_panel_enable(dssdev);
}
}
@@ -716,30 +625,79 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
return 0;
}
-static enum omap_dss_update_mode venc_display_get_update_mode(
- struct omap_dss_device *dssdev)
+static struct omap_dss_driver venc_driver = {
+ .probe = venc_panel_probe,
+ .remove = venc_panel_remove,
+
+ .enable = venc_panel_enable,
+ .disable = venc_panel_disable,
+ .suspend = venc_panel_suspend,
+ .resume = venc_panel_resume,
+
+ .get_resolution = omapdss_default_get_resolution,
+ .get_recommended_bpp = omapdss_default_get_recommended_bpp,
+
+ .set_update_mode = venc_set_update_mode,
+ .get_update_mode = venc_get_update_mode,
+
+ .get_timings = venc_get_timings,
+ .set_timings = venc_set_timings,
+ .check_timings = venc_check_timings,
+
+ .get_wss = venc_get_wss,
+ .set_wss = venc_set_wss,
+
+ .driver = {
+ .name = "venc",
+ .owner = THIS_MODULE,
+ },
+};
+/* driver end */
+
+
+
+int venc_init(struct platform_device *pdev)
{
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
- return OMAP_DSS_UPDATE_AUTO;
- else
- return OMAP_DSS_UPDATE_DISABLED;
+ u8 rev_id;
+
+ mutex_init(&venc.venc_lock);
+
+ venc.wss_data = 0;
+
+ venc.base = ioremap(VENC_BASE, SZ_1K);
+ if (!venc.base) {
+ DSSERR("can't ioremap VENC\n");
+ return -ENOMEM;
+ }
+
+ venc.vdda_dac_reg = dss_get_vdda_dac();
+ if (IS_ERR(venc.vdda_dac_reg)) {
+ iounmap(venc.base);
+ DSSERR("can't get VDDA_DAC regulator\n");
+ return PTR_ERR(venc.vdda_dac_reg);
+ }
+
+ venc_enable_clocks(1);
+
+ rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
+ printk(KERN_INFO "OMAP VENC rev %d\n", rev_id);
+
+ venc_enable_clocks(0);
+
+ return omap_dss_register_driver(&venc_driver);
+}
+
+void venc_exit(void)
+{
+ omap_dss_unregister_driver(&venc_driver);
+
+ iounmap(venc.base);
}
int venc_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("init_display\n");
- dssdev->enable = venc_enable_display;
- dssdev->disable = venc_disable_display;
- dssdev->suspend = venc_display_suspend;
- dssdev->resume = venc_display_resume;
- dssdev->get_timings = venc_get_timings;
- dssdev->set_timings = venc_set_timings;
- dssdev->check_timings = venc_check_timings;
- dssdev->get_wss = venc_get_wss;
- dssdev->set_wss = venc_set_wss;
- dssdev->get_update_mode = venc_display_get_update_mode;
-
return 0;
}
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
index bb694cc52a50..43496d6c377f 100644
--- a/drivers/video/omap2/omapfb/Kconfig
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -16,16 +16,7 @@ config FB_OMAP2_DEBUG_SUPPORT
depends on FB_OMAP2
help
Support for debug output. You have to enable the actual printing
- with debug module parameter.
-
-config FB_OMAP2_FORCE_AUTO_UPDATE
- bool "Force main display to automatic update mode"
- depends on FB_OMAP2
- help
- Forces main display to automatic update mode (if possible),
- and also enables tearsync (if possible). By default
- displays that support manual update are started in manual
- update mode.
+ with 'debug' module parameter.
config FB_OMAP2_NUM_FBS
int "Number of framebuffers"
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index 4c4bafdfaa43..1ffa760b8545 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -167,12 +167,12 @@ static int omapfb_update_window_nolock(struct fb_info *fbi,
if (w == 0 || h == 0)
return 0;
- display->get_resolution(display, &dw, &dh);
+ display->driver->get_resolution(display, &dw, &dh);
if (x + w > dw || y + h > dh)
return -EINVAL;
- return display->update(display, x, y, w, h);
+ return display->driver->update(display, x, y, w, h);
}
/* This function is exported for SGX driver use */
@@ -202,7 +202,7 @@ static int omapfb_set_update_mode(struct fb_info *fbi,
enum omap_dss_update_mode um;
int r;
- if (!display || !display->set_update_mode)
+ if (!display || !display->driver->set_update_mode)
return -EINVAL;
switch (mode) {
@@ -222,7 +222,7 @@ static int omapfb_set_update_mode(struct fb_info *fbi,
return -EINVAL;
}
- r = display->set_update_mode(display, um);
+ r = display->driver->set_update_mode(display, um);
return r;
}
@@ -233,10 +233,15 @@ static int omapfb_get_update_mode(struct fb_info *fbi,
struct omap_dss_device *display = fb2display(fbi);
enum omap_dss_update_mode m;
- if (!display || !display->get_update_mode)
+ if (!display)
return -EINVAL;
- m = display->get_update_mode(display);
+ if (!display->driver->get_update_mode) {
+ *mode = OMAPFB_AUTO_UPDATE;
+ return 0;
+ }
+
+ m = display->driver->get_update_mode(display);
switch (m) {
case OMAP_DSS_UPDATE_DISABLED:
@@ -374,7 +379,7 @@ static int omapfb_memory_read(struct fb_info *fbi,
void *buf;
int r;
- if (!display || !display->memory_read)
+ if (!display || !display->driver->memory_read)
return -ENOENT;
if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
@@ -389,7 +394,7 @@ static int omapfb_memory_read(struct fb_info *fbi,
return -ENOMEM;
}
- r = display->memory_read(display, buf, mr->buffer_size,
+ r = display->driver->memory_read(display, buf, mr->buffer_size,
mr->x, mr->y, mr->w, mr->h);
if (r > 0) {
@@ -483,6 +488,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
struct omapfb_memory_read memory_read;
struct omapfb_vram_info vram_info;
struct omapfb_tearsync_info tearsync_info;
+ struct omapfb_display_info display_info;
} p;
int r = 0;
@@ -490,18 +496,18 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
switch (cmd) {
case OMAPFB_SYNC_GFX:
DBG("ioctl SYNC_GFX\n");
- if (!display || !display->sync) {
+ if (!display || !display->driver->sync) {
/* DSS1 never returns an error here, so we neither */
/*r = -EINVAL;*/
break;
}
- r = display->sync(display);
+ r = display->driver->sync(display);
break;
case OMAPFB_UPDATE_WINDOW_OLD:
DBG("ioctl UPDATE_WINDOW_OLD\n");
- if (!display || !display->update) {
+ if (!display || !display->driver->update) {
r = -EINVAL;
break;
}
@@ -519,7 +525,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
case OMAPFB_UPDATE_WINDOW:
DBG("ioctl UPDATE_WINDOW\n");
- if (!display || !display->update) {
+ if (!display || !display->driver->update) {
r = -EINVAL;
break;
}
@@ -648,7 +654,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
- r = display->wait_vsync(display);
+ r = display->manager->wait_for_vsync(display->manager);
break;
case OMAPFB_WAITFORGO:
@@ -669,12 +675,12 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
r = -EFAULT;
break;
}
- if (!display || !display->run_test) {
+ if (!display || !display->driver->run_test) {
r = -EINVAL;
break;
}
- r = display->run_test(display, p.test_num);
+ r = display->driver->run_test(display, p.test_num);
break;
@@ -684,12 +690,12 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
r = -EFAULT;
break;
}
- if (!display || !display->run_test) {
+ if (!display || !display->driver->run_test) {
r = -EINVAL;
break;
}
- r = display->run_test(display, p.test_num);
+ r = display->driver->run_test(display, p.test_num);
break;
@@ -731,13 +737,37 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
- if (!display->enable_te) {
+ if (!display->driver->enable_te) {
r = -ENODEV;
break;
}
- r = display->enable_te(display, !!p.tearsync_info.enabled);
+ r = display->driver->enable_te(display,
+ !!p.tearsync_info.enabled);
+
+ break;
+ }
+
+ case OMAPFB_GET_DISPLAY_INFO: {
+ u16 xres, yres;
+ DBG("ioctl GET_DISPLAY_INFO\n");
+
+ if (display == NULL) {
+ r = -ENODEV;
+ break;
+ }
+
+ display->driver->get_resolution(display, &xres, &yres);
+
+ p.display_info.xres = xres;
+ p.display_info.yres = yres;
+ p.display_info.width = 0;
+ p.display_info.height = 0;
+
+ if (copy_to_user((void __user *)arg, &p.display_info,
+ sizeof(p.display_info)))
+ r = -EFAULT;
break;
}
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index d17caef6915a..4a76917b7cc8 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -54,6 +54,8 @@ module_param_named(test, omapfb_test_pattern, bool, 0644);
#endif
static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
+static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
+ struct omap_dss_device *dssdev);
#ifdef DEBUG
static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
@@ -152,9 +154,9 @@ static void fill_fb(struct fb_info *fbi)
}
#endif
-static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot)
+static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
{
- struct vrfb *vrfb = &ofbi->region.vrfb;
+ const struct vrfb *vrfb = &ofbi->region.vrfb;
unsigned offset;
switch (rot) {
@@ -179,7 +181,7 @@ static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot)
return offset;
}
-static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi, int rot)
+static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot)
{
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
return ofbi->region.vrfb.paddr[rot]
@@ -189,7 +191,7 @@ static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi, int rot)
}
}
-static u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)
+static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi)
{
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
return ofbi->region.vrfb.paddr[0];
@@ -197,7 +199,7 @@ static u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)
return ofbi->region.paddr;
}
-static void __iomem *omapfb_get_region_vaddr(struct omapfb_info *ofbi)
+static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi)
{
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
return ofbi->region.vrfb.vaddr[0];
@@ -703,9 +705,9 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
var->width = -1;
var->grayscale = 0;
- if (display && display->get_timings) {
+ if (display && display->driver->get_timings) {
struct omap_video_timings timings;
- display->get_timings(display, &timings);
+ display->driver->get_timings(display, &timings);
/* pixclock in ps, the rest in pixclock */
var->pixclock = timings.pixel_clock != 0 ?
@@ -778,8 +780,8 @@ static int omapfb_release(struct fb_info *fbi, int user)
return 0;
}
-static unsigned calc_rotation_offset_dma(struct fb_var_screeninfo *var,
- struct fb_fix_screeninfo *fix, int rotation)
+static unsigned calc_rotation_offset_dma(const struct fb_var_screeninfo *var,
+ const struct fb_fix_screeninfo *fix, int rotation)
{
unsigned offset;
@@ -789,8 +791,8 @@ static unsigned calc_rotation_offset_dma(struct fb_var_screeninfo *var,
return offset;
}
-static unsigned calc_rotation_offset_vrfb(struct fb_var_screeninfo *var,
- struct fb_fix_screeninfo *fix, int rotation)
+static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var,
+ const struct fb_fix_screeninfo *fix, int rotation)
{
unsigned offset;
@@ -1221,11 +1223,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
goto exit;
- if (display->resume)
- r = display->resume(display);
+ if (display->driver->resume)
+ r = display->driver->resume(display);
- if (r == 0 && display->get_update_mode &&
- display->get_update_mode(display) ==
+ if (r == 0 && display->driver->get_update_mode &&
+ display->driver->get_update_mode(display) ==
OMAP_DSS_UPDATE_MANUAL)
do_update = 1;
@@ -1240,8 +1242,8 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
goto exit;
- if (display->suspend)
- r = display->suspend(display);
+ if (display->driver->suspend)
+ r = display->driver->suspend(display);
break;
@@ -1252,11 +1254,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
exit:
omapfb_unlock(fbdev);
- if (r == 0 && do_update && display->update) {
+ if (r == 0 && do_update && display->driver->update) {
u16 w, h;
- display->get_resolution(display, &w, &h);
+ display->driver->get_resolution(display, &w, &h);
- r = display->update(display, 0, 0, w, h);
+ r = display->driver->update(display, 0, 0, w, h);
}
return r;
@@ -1404,6 +1406,7 @@ static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
unsigned long paddr)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
+ struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_dss_device *display;
int bytespp;
@@ -1412,7 +1415,7 @@ static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
if (!display)
return 0;
- switch (display->get_recommended_bpp(display)) {
+ switch (omapfb_get_recommended_bpp(fbdev, display)) {
case 16:
bytespp = 2;
break;
@@ -1427,7 +1430,7 @@ static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
if (!size) {
u16 w, h;
- display->get_resolution(display, &w, &h);
+ display->driver->get_resolution(display, &w, &h);
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
size = max(omap_vrfb_min_phys_size(w, h, bytespp),
@@ -1636,8 +1639,8 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
if (old_size == size && old_type == type)
return 0;
- if (display && display->sync)
- display->sync(display);
+ if (display && display->driver->sync)
+ display->driver->sync(display);
omapfb_free_fbmem(fbi);
@@ -1745,7 +1748,7 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
u16 w, h;
int rotation = (var->rotate + ofbi->rotation[0]) % 4;
- display->get_resolution(display, &w, &h);
+ display->driver->get_resolution(display, &w, &h);
if (rotation == FB_ROTATE_CW ||
rotation == FB_ROTATE_CCW) {
@@ -1760,7 +1763,7 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
var->yres_virtual = var->yres;
if (!var->bits_per_pixel) {
- switch (display->get_recommended_bpp(display)) {
+ switch (omapfb_get_recommended_bpp(fbdev, display)) {
case 16:
var->bits_per_pixel = 16;
break;
@@ -1828,7 +1831,7 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev)
for (i = 0; i < fbdev->num_displays; i++) {
if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
- fbdev->displays[i]->disable(fbdev->displays[i]);
+ fbdev->displays[i]->driver->disable(fbdev->displays[i]);
omap_dss_put_device(fbdev->displays[i]);
}
@@ -2011,7 +2014,8 @@ static int omapfb_mode_to_timings(const char *mode_str,
}
}
-static int omapfb_set_def_mode(struct omap_dss_device *display, char *mode_str)
+static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
+ struct omap_dss_device *display, char *mode_str)
{
int r;
u8 bpp;
@@ -2021,20 +2025,37 @@ static int omapfb_set_def_mode(struct omap_dss_device *display, char *mode_str)
if (r)
return r;
- display->panel.recommended_bpp = bpp;
+ fbdev->bpp_overrides[fbdev->num_bpp_overrides].dssdev = display;
+ fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp;
+ ++fbdev->num_bpp_overrides;
- if (!display->check_timings || !display->set_timings)
+ if (!display->driver->check_timings || !display->driver->set_timings)
return -EINVAL;
- r = display->check_timings(display, &timings);
+ r = display->driver->check_timings(display, &timings);
if (r)
return r;
- display->set_timings(display, &timings);
+ display->driver->set_timings(display, &timings);
return 0;
}
+static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
+ struct omap_dss_device *dssdev)
+{
+ int i;
+
+ BUG_ON(dssdev->driver->get_recommended_bpp == NULL);
+
+ for (i = 0; i < fbdev->num_bpp_overrides; ++i) {
+ if (dssdev == fbdev->bpp_overrides[i].dssdev)
+ return fbdev->bpp_overrides[i].bpp;
+ }
+
+ return dssdev->driver->get_recommended_bpp(dssdev);
+}
+
static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
{
char *str, *options, *this_opt;
@@ -2073,7 +2094,7 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
break;
}
- r = omapfb_set_def_mode(display, mode_str);
+ r = omapfb_set_def_mode(fbdev, display, mode_str);
if (r)
break;
}
@@ -2111,18 +2132,23 @@ static int omapfb_probe(struct platform_device *pdev)
fbdev->dev = &pdev->dev;
platform_set_drvdata(pdev, fbdev);
+ r = 0;
fbdev->num_displays = 0;
dssdev = NULL;
for_each_dss_dev(dssdev) {
omap_dss_get_device(dssdev);
+
if (!dssdev->driver) {
dev_err(&pdev->dev, "no driver for display\n");
- r = -EINVAL;
- goto cleanup;
+ r = -ENODEV;
}
+
fbdev->displays[fbdev->num_displays++] = dssdev;
}
+ if (r)
+ goto cleanup;
+
if (fbdev->num_displays == 0) {
dev_err(&pdev->dev, "no displays\n");
r = -EINVAL;
@@ -2167,35 +2193,28 @@ static int omapfb_probe(struct platform_device *pdev)
}
if (def_display) {
-#ifndef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
- u16 w, h;
-#endif
- r = def_display->enable(def_display);
- if (r)
+ struct omap_dss_driver *dssdrv = def_display->driver;
+
+ r = def_display->driver->enable(def_display);
+ if (r) {
dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
def_display->name);
+ goto cleanup;
+ }
- /* set the update mode */
if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
- if (def_display->enable_te)
- def_display->enable_te(def_display, 1);
- if (def_display->set_update_mode)
- def_display->set_update_mode(def_display,
- OMAP_DSS_UPDATE_AUTO);
-#else /* MANUAL_UPDATE */
- if (def_display->enable_te)
- def_display->enable_te(def_display, 0);
- if (def_display->set_update_mode)
- def_display->set_update_mode(def_display,
+ u16 w, h;
+ if (dssdrv->enable_te)
+ dssdrv->enable_te(def_display, 1);
+ if (dssdrv->set_update_mode)
+ dssdrv->set_update_mode(def_display,
OMAP_DSS_UPDATE_MANUAL);
- def_display->get_resolution(def_display, &w, &h);
- def_display->update(def_display, 0, 0, w, h);
-#endif
+ dssdrv->get_resolution(def_display, &w, &h);
+ def_display->driver->update(def_display, 0, 0, w, h);
} else {
- if (def_display->set_update_mode)
- def_display->set_update_mode(def_display,
+ if (dssdrv->set_update_mode)
+ dssdrv->set_update_mode(def_display,
OMAP_DSS_UPDATE_AUTO);
}
}
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
index f7c9c739e5ef..cd54fdbfd8bb 100644
--- a/drivers/video/omap2/omapfb/omapfb.h
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -83,6 +83,12 @@ struct omapfb2_device {
struct omap_overlay *overlays[10];
unsigned num_managers;
struct omap_overlay_manager *managers[10];
+
+ unsigned num_bpp_overrides;
+ struct {
+ struct omap_dss_device *dssdev;
+ u8 bpp;
+ } bpp_overrides[10];
};
struct omapfb_colormode {
@@ -105,6 +111,9 @@ void omapfb_remove_sysfs(struct omapfb2_device *fbdev);
int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg);
+int omapfb_update_window(struct fb_info *fbi,
+ u32 x, u32 y, u32 w, u32 h);
+
int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
struct fb_var_screeninfo *var);
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index 36436ee6c1a4..27f93aab6ddc 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -896,7 +896,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
* Pseudocolor:
* uses offset = 0 && length = DAC register width.
* var->{color}.offset is 0
- * var->{color}.length contains widht of DAC
+ * var->{color}.length contains width of DAC
* cmap is not used
* DAC[X] is programmed to (red, green, blue)
* Truecolor:
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index 53f8f1100e81..f9975100d56d 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -831,7 +831,7 @@ static int __devinit pvr2fb_common_init(void)
printk(KERN_NOTICE "fb%d: registering with SQ API\n", fb_info->node);
pvr2fb_map = sq_remap(fb_info->fix.smem_start, fb_info->fix.smem_len,
- fb_info->fix.id, pgprot_val(PAGE_SHARED));
+ fb_info->fix.id, PAGE_SHARED);
printk(KERN_NOTICE "fb%d: Mapped video memory to SQ addr 0x%lx\n",
fb_info->node, pvr2fb_map);
diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c
index 4beac1df617b..de40a626dc76 100644
--- a/drivers/video/q40fb.c
+++ b/drivers/video/q40fb.c
@@ -85,7 +85,7 @@ static struct fb_ops q40fb_ops = {
.fb_imageblit = cfb_imageblit,
};
-static int __init q40fb_probe(struct platform_device *dev)
+static int __devinit q40fb_probe(struct platform_device *dev)
{
struct fb_info *info;
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
index 0deb0a8867b7..7b63429f1a7c 100644
--- a/drivers/video/s1d13xxxfb.c
+++ b/drivers/video/s1d13xxxfb.c
@@ -517,12 +517,12 @@ s1d13xxxfb_bitblt_copyarea(struct fb_info *info, const struct fb_copyarea *area)
src = (sy * stride) + (bpp * sx);
}
- /* set source adress */
+ /* set source address */
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START0, (src & 0xff));
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START1, (src >> 8) & 0x00ff);
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START2, (src >> 16) & 0x00ff);
- /* set destination adress */
+ /* set destination address */
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START0, (dst & 0xff));
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START1, (dst >> 8) & 0x00ff);
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START2, (dst >> 16) & 0x00ff);
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index adf9632c6b1f..53cb722c45a0 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -211,21 +211,23 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
/**
* s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
- * @id: window id.
* @sfb: The hardware state.
* @pixclock: The pixel clock wanted, in picoseconds.
*
* Given the specified pixel clock, work out the necessary divider to get
* close to the output frequency.
*/
-static int s3c_fb_calc_pixclk(unsigned char id, struct s3c_fb *sfb, unsigned int pixclk)
+static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
{
- struct s3c_fb_pd_win *win = sfb->pdata->win[id];
unsigned long clk = clk_get_rate(sfb->bus_clk);
+ unsigned long long tmp;
unsigned int result;
- pixclk *= win->win_mode.refresh;
- result = clk / pixclk;
+ tmp = (unsigned long long)clk;
+ tmp *= pixclk;
+
+ do_div(tmp, 1000000000UL);
+ result = (unsigned int)tmp / 1000;
dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
pixclk, clk, result, clk / result);
@@ -301,7 +303,7 @@ static int s3c_fb_set_par(struct fb_info *info)
/* use window 0 as the basis for the lcd output timings */
if (win_no == 0) {
- clkdiv = s3c_fb_calc_pixclk(win_no, sfb, var->pixclock);
+ clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
data = sfb->pdata->vidcon0;
data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index aac661225c78..2b094dec4a56 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -1004,12 +1004,12 @@ dealloc_fb:
return ret;
}
-static int __init s3c2410fb_probe(struct platform_device *pdev)
+static int __devinit s3c2410fb_probe(struct platform_device *pdev)
{
return s3c24xxfb_probe(pdev, DRV_S3C2410);
}
-static int __init s3c2412fb_probe(struct platform_device *pdev)
+static int __devinit s3c2412fb_probe(struct platform_device *pdev)
{
return s3c24xxfb_probe(pdev, DRV_S3C2412);
}
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index cdaa873a6054..e8b76d65a070 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -1435,7 +1435,7 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
return fbi;
}
-static int __init sa1100fb_probe(struct platform_device *pdev)
+static int __devinit sa1100fb_probe(struct platform_device *pdev)
{
struct sa1100fb_info *fbi;
int ret, irq;
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
index f86012239bff..7a3a5e28eca1 100644
--- a/drivers/video/sgivwfb.c
+++ b/drivers/video/sgivwfb.c
@@ -745,7 +745,7 @@ int __init sgivwfb_setup(char *options)
/*
* Initialisation
*/
-static int __init sgivwfb_probe(struct platform_device *dev)
+static int __devinit sgivwfb_probe(struct platform_device *dev)
{
struct sgivw_par *par;
struct fb_info *info;
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index a69830d26f7f..bbd1dbf4026a 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -19,6 +19,7 @@
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
+#include <linux/ioctl.h>
#include <video/sh_mobile_lcdc.h>
#include <asm/atomic.h>
@@ -106,6 +107,7 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
#define LDRCNTR_SRC 0x00010000
#define LDRCNTR_MRS 0x00000002
#define LDRCNTR_MRC 0x00000001
+#define LDSR_MRS 0x00000100
struct sh_mobile_lcdc_priv;
struct sh_mobile_lcdc_chan {
@@ -122,8 +124,8 @@ struct sh_mobile_lcdc_chan {
struct scatterlist *sglist;
unsigned long frame_end;
unsigned long pan_offset;
- unsigned long new_pan_offset;
wait_queue_head_t frame_end_wait;
+ struct completion vsync_completion;
};
struct sh_mobile_lcdc_priv {
@@ -366,19 +368,8 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
}
/* VSYNC End */
- if (ldintr & LDINTR_VES) {
- unsigned long ldrcntr = lcdc_read(priv, _LDRCNTR);
- /* Set the source address for the next refresh */
- lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle +
- ch->new_pan_offset);
- if (lcdc_chan_is_sublcd(ch))
- lcdc_write(ch->lcdc, _LDRCNTR,
- ldrcntr ^ LDRCNTR_SRS);
- else
- lcdc_write(ch->lcdc, _LDRCNTR,
- ldrcntr ^ LDRCNTR_MRS);
- ch->pan_offset = ch->new_pan_offset;
- }
+ if (ldintr & LDINTR_VES)
+ complete(&ch->vsync_completion);
}
return IRQ_HANDLED;
@@ -767,25 +758,69 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct sh_mobile_lcdc_chan *ch = info->par;
+ struct sh_mobile_lcdc_priv *priv = ch->lcdc;
+ unsigned long ldrcntr;
+ unsigned long new_pan_offset;
+
+ new_pan_offset = (var->yoffset * info->fix.line_length) +
+ (var->xoffset * (info->var.bits_per_pixel / 8));
- if (info->var.xoffset == var->xoffset &&
- info->var.yoffset == var->yoffset)
+ if (new_pan_offset == ch->pan_offset)
return 0; /* No change, do nothing */
- ch->new_pan_offset = (var->yoffset * info->fix.line_length) +
- (var->xoffset * (info->var.bits_per_pixel / 8));
+ ldrcntr = lcdc_read(priv, _LDRCNTR);
- if (ch->new_pan_offset != ch->pan_offset) {
- unsigned long ldintr;
- ldintr = lcdc_read(ch->lcdc, _LDINTR);
- ldintr |= LDINTR_VEE;
- lcdc_write(ch->lcdc, _LDINTR, ldintr);
- sh_mobile_lcdc_deferred_io_touch(info);
- }
+ /* Set the source address for the next refresh */
+ lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + new_pan_offset);
+ if (lcdc_chan_is_sublcd(ch))
+ lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
+ else
+ lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS);
+
+ ch->pan_offset = new_pan_offset;
+
+ sh_mobile_lcdc_deferred_io_touch(info);
+
+ return 0;
+}
+
+static int sh_mobile_wait_for_vsync(struct fb_info *info)
+{
+ struct sh_mobile_lcdc_chan *ch = info->par;
+ unsigned long ldintr;
+ int ret;
+
+ /* Enable VSync End interrupt */
+ ldintr = lcdc_read(ch->lcdc, _LDINTR);
+ ldintr |= LDINTR_VEE;
+ lcdc_write(ch->lcdc, _LDINTR, ldintr);
+
+ ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
+ msecs_to_jiffies(100));
+ if (!ret)
+ return -ETIMEDOUT;
return 0;
}
+static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ int retval;
+
+ switch (cmd) {
+ case FBIO_WAITFORVSYNC:
+ retval = sh_mobile_wait_for_vsync(info);
+ break;
+
+ default:
+ retval = -ENOIOCTLCMD;
+ break;
+ }
+ return retval;
+}
+
+
static struct fb_ops sh_mobile_lcdc_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = sh_mobile_lcdc_setcolreg,
@@ -795,6 +830,7 @@ static struct fb_ops sh_mobile_lcdc_ops = {
.fb_copyarea = sh_mobile_lcdc_copyarea,
.fb_imageblit = sh_mobile_lcdc_imageblit,
.fb_pan_display = sh_mobile_fb_pan_display,
+ .fb_ioctl = sh_mobile_ioctl,
};
static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp)
@@ -907,7 +943,7 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
static int sh_mobile_lcdc_remove(struct platform_device *pdev);
-static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
+static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
{
struct fb_info *info;
struct sh_mobile_lcdc_priv *priv;
@@ -962,8 +998,8 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
goto err1;
}
init_waitqueue_head(&priv->ch[i].frame_end_wait);
+ init_completion(&priv->ch[i].vsync_completion);
priv->ch[j].pan_offset = 0;
- priv->ch[j].new_pan_offset = 0;
switch (pdata->ch[i].chan) {
case LCDC_CHAN_MAINLCD:
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 9d2b6bc49036..a531a0f7cdf2 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -1891,9 +1891,6 @@ static struct fb_ops sisfb_ops = {
.fb_fillrect = fbcon_sis_fillrect,
.fb_copyarea = fbcon_sis_copyarea,
.fb_imageblit = cfb_imageblit,
-#ifdef CONFIG_FB_SOFT_CURSOR
- .fb_cursor = soft_cursor,
-#endif
.fb_sync = fbcon_sis_sync,
#ifdef SIS_NEW_CONFIG_COMPAT
.fb_compat_ioctl= sisfb_ioctl,
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index 35370d0ecf03..b7dc1800efa9 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -411,7 +411,7 @@ static int sm501fb_set_par_common(struct fb_info *info,
struct sm501fb_par *par = info->par;
struct sm501fb_info *fbi = par->info;
unsigned long pixclock; /* pixelclock in Hz */
- unsigned long sm501pixclock; /* pixelclock the 501 can achive in Hz */
+ unsigned long sm501pixclock; /* pixelclock the 501 can achieve in Hz */
unsigned int mem_type;
unsigned int clock_type;
unsigned int head_addr;
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
index 609d0a521ca2..79840f11fecb 100644
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -1102,7 +1102,7 @@ static void sst_set_vidmod_ics(struct fb_info *info, const int bpp)
* detect dac type
* prerequisite : write to FbiInitx enabled, video and fbi and pci fifo reset,
* dram refresh disabled, FbiInit remaped.
- * TODO: mmh.. maybe i shoud put the "prerequisite" in the func ...
+ * TODO: mmh.. maybe i should put the "prerequisite" in the func ...
*/
diff --git a/drivers/video/sunxvr1000.c b/drivers/video/sunxvr1000.c
new file mode 100644
index 000000000000..a8248c0b9192
--- /dev/null
+++ b/drivers/video/sunxvr1000.c
@@ -0,0 +1,228 @@
+/* sunxvr1000.c: Sun XVR-1000 driver for sparc64 systems
+ *
+ * Copyright (C) 2010 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/of_device.h>
+
+struct gfb_info {
+ struct fb_info *info;
+
+ char __iomem *fb_base;
+ unsigned long fb_base_phys;
+
+ struct device_node *of_node;
+
+ unsigned int width;
+ unsigned int height;
+ unsigned int depth;
+ unsigned int fb_size;
+
+ u32 pseudo_palette[16];
+};
+
+static int __devinit gfb_get_props(struct gfb_info *gp)
+{
+ gp->width = of_getintprop_default(gp->of_node, "width", 0);
+ gp->height = of_getintprop_default(gp->of_node, "height", 0);
+ gp->depth = of_getintprop_default(gp->of_node, "depth", 32);
+
+ if (!gp->width || !gp->height) {
+ printk(KERN_ERR "gfb: Critical properties missing for %s\n",
+ gp->of_node->full_name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int gfb_setcolreg(unsigned regno,
+ unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *info)
+{
+ u32 value;
+
+ if (regno < 16) {
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ value = (blue << 16) | (green << 8) | red;
+ ((u32 *)info->pseudo_palette)[regno] = value;
+ }
+
+ return 0;
+}
+
+static struct fb_ops gfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = gfb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static int __devinit gfb_set_fbinfo(struct gfb_info *gp)
+{
+ struct fb_info *info = gp->info;
+ struct fb_var_screeninfo *var = &info->var;
+
+ info->flags = FBINFO_DEFAULT;
+ info->fbops = &gfb_ops;
+ info->screen_base = gp->fb_base;
+ info->screen_size = gp->fb_size;
+
+ info->pseudo_palette = gp->pseudo_palette;
+
+ /* Fill fix common fields */
+ strlcpy(info->fix.id, "gfb", sizeof(info->fix.id));
+ info->fix.smem_start = gp->fb_base_phys;
+ info->fix.smem_len = gp->fb_size;
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ if (gp->depth == 32 || gp->depth == 24)
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ else
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+ var->xres = gp->width;
+ var->yres = gp->height;
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres;
+ var->bits_per_pixel = gp->depth;
+
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 16;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+
+ if (fb_alloc_cmap(&info->cmap, 256, 0)) {
+ printk(KERN_ERR "gfb: Cannot allocate color map.\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int __devinit gfb_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct device_node *dp = op->node;
+ struct fb_info *info;
+ struct gfb_info *gp;
+ int err;
+
+ info = framebuffer_alloc(sizeof(struct gfb_info), &op->dev);
+ if (!info) {
+ printk(KERN_ERR "gfb: Cannot allocate fb_info\n");
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ gp = info->par;
+ gp->info = info;
+ gp->of_node = dp;
+
+ gp->fb_base_phys = op->resource[6].start;
+
+ err = gfb_get_props(gp);
+ if (err)
+ goto err_release_fb;
+
+ /* Framebuffer length is the same regardless of resolution. */
+ info->fix.line_length = 16384;
+ gp->fb_size = info->fix.line_length * gp->height;
+
+ gp->fb_base = of_ioremap(&op->resource[6], 0,
+ gp->fb_size, "gfb fb");
+ if (!gp->fb_base)
+ goto err_release_fb;
+
+ err = gfb_set_fbinfo(gp);
+ if (err)
+ goto err_unmap_fb;
+
+ printk("gfb: Found device at %s\n", dp->full_name);
+
+ err = register_framebuffer(info);
+ if (err < 0) {
+ printk(KERN_ERR "gfb: Could not register framebuffer %s\n",
+ dp->full_name);
+ goto err_unmap_fb;
+ }
+
+ dev_set_drvdata(&op->dev, info);
+
+ return 0;
+
+err_unmap_fb:
+ of_iounmap(&op->resource[6], gp->fb_base, gp->fb_size);
+
+err_release_fb:
+ framebuffer_release(info);
+
+err_out:
+ return err;
+}
+
+static int __devexit gfb_remove(struct of_device *op)
+{
+ struct fb_info *info = dev_get_drvdata(&op->dev);
+ struct gfb_info *gp = info->par;
+
+ unregister_framebuffer(info);
+
+ iounmap(gp->fb_base);
+
+ of_iounmap(&op->resource[6], gp->fb_base, gp->fb_size);
+
+ framebuffer_release(info);
+
+ dev_set_drvdata(&op->dev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id gfb_match[] = {
+ {
+ .name = "SUNW,gfb",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ffb_match);
+
+static struct of_platform_driver gfb_driver = {
+ .name = "gfb",
+ .match_table = gfb_match,
+ .probe = gfb_probe,
+ .remove = __devexit_p(gfb_remove),
+};
+
+static int __init gfb_init(void)
+{
+ if (fb_get_options("gfb", NULL))
+ return -ENODEV;
+
+ return of_register_driver(&gfb_driver, &of_bus_type);
+}
+
+static void __exit gfb_exit(void)
+{
+ of_unregister_driver(&gfb_driver);
+}
+
+module_init(gfb_init);
+module_exit(gfb_exit);
+
+MODULE_DESCRIPTION("framebuffer driver for Sun XVR-1000 graphics");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c
index 18b950706cad..4cd50497264d 100644
--- a/drivers/video/sunxvr500.c
+++ b/drivers/video/sunxvr500.c
@@ -400,6 +400,7 @@ static void __devexit e3d_pci_unregister(struct pci_dev *pdev)
static struct pci_device_id e3d_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a0), },
+ { PCI_DEVICE(0x1091, 0x7a0), },
{ PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a2), },
{ .vendor = PCI_VENDOR_ID_3DLABS,
.device = PCI_ANY_ID,
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index 4bb9a0b18950..6b52bf65f0b5 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -69,7 +69,7 @@
#ifdef CONFIG_MAC
/* We don't yet have functions to read the PRAM... perhaps we can
adapt them from the PPC code? */
-static int default_vmode = VMODE_640_480_67;
+static int default_vmode = VMODE_CHOOSE;
static int default_cmode = CMODE_8;
#else
static int default_vmode = VMODE_NVRAM;
@@ -326,11 +326,11 @@ int __init valkyriefb_init(void)
#ifdef CONFIG_MAC
if (!MACH_IS_MAC)
- return 0;
+ return -ENODEV;
if (!(mac_bi_data.id == MAC_MODEL_Q630
/* I'm not sure about this one */
|| mac_bi_data.id == MAC_MODEL_P588))
- return 0;
+ return -ENODEV;
/* Hardcoded addresses... welcome to 68k Macintosh country :-) */
frame_buffer_phys = 0xf9000000;
diff --git a/drivers/video/valkyriefb.h b/drivers/video/valkyriefb.h
index 97aaf7bb6417..d787441e5a42 100644
--- a/drivers/video/valkyriefb.h
+++ b/drivers/video/valkyriefb.h
@@ -134,15 +134,7 @@ static struct valkyrie_regvals valkyrie_reg_init_14 = {
{ 1024, 0 },
1024, 768
};
-
-/* Register values for 800x600, 72Hz mode (11) */
-static struct valkyrie_regvals valkyrie_reg_init_11 = {
- 13,
- { 17, 27, 3 }, /* pixel clock = 49.63MHz for V=71.66Hz */
- { 800, 0 },
- 800, 600
-};
-#endif /* CONFIG_MAC */
+#endif /* !defined CONFIG_MAC */
/* Register values for 832x624, 75Hz mode (13) */
static struct valkyrie_regvals valkyrie_reg_init_13 = {
@@ -152,6 +144,14 @@ static struct valkyrie_regvals valkyrie_reg_init_13 = {
832, 624
};
+/* Register values for 800x600, 72Hz mode (11) */
+static struct valkyrie_regvals valkyrie_reg_init_11 = {
+ 13,
+ { 17, 27, 3 }, /* pixel clock = 49.63MHz for V=71.66Hz */
+ { 800, 0 },
+ 800, 600
+};
+
/* Register values for 800x600, 60Hz mode (10) */
static struct valkyrie_regvals valkyrie_reg_init_10 = {
12,
@@ -188,24 +188,13 @@ static struct valkyrie_regvals *valkyrie_reg_init[VMODE_MAX] = {
NULL,
NULL,
&valkyrie_reg_init_10,
-#ifdef CONFIG_MAC
- NULL,
- NULL,
- &valkyrie_reg_init_13,
- NULL,
- NULL,
- NULL,
- NULL,
-#else
&valkyrie_reg_init_11,
NULL,
&valkyrie_reg_init_13,
+#ifndef CONFIG_MAC
&valkyrie_reg_init_14,
&valkyrie_reg_init_15,
NULL,
&valkyrie_reg_init_17,
#endif
- NULL,
- NULL,
- NULL
};
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index bd37ee1f6a25..ef4128c8e57a 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -226,7 +226,7 @@ static int __init vesafb_setup(char *options)
return 0;
}
-static int __init vesafb_probe(struct platform_device *dev)
+static int __devinit vesafb_probe(struct platform_device *dev)
{
struct fb_info *info;
int i, err;
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 050d432c7d95..b8ab995fbda7 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -479,7 +479,7 @@ static int __init vfb_setup(char *options)
* Initialisation
*/
-static int __init vfb_probe(struct platform_device *dev)
+static int __devinit vfb_probe(struct platform_device *dev)
{
struct fb_info *info;
int retval = -ENOMEM;
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 5b2938903ac2..76d8dae5b1bb 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -1293,7 +1293,7 @@ static int vga16fb_setup(char *options)
}
#endif
-static int __init vga16fb_probe(struct platform_device *dev)
+static int __devinit vga16fb_probe(struct platform_device *dev)
{
struct fb_info *info;
struct vga16fb_par *par;
diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile
index e533b4b6aba4..eeed238ad6a2 100644
--- a/drivers/video/via/Makefile
+++ b/drivers/video/via/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_FB_VIA) += viafb.o
-viafb-y :=viafbdev.o hw.o iface.o via_i2c.o dvi.o lcd.o ioctl.o accel.o via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o
+viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o
diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
index 9d4f3a49ba4a..d5077dfa9e00 100644
--- a/drivers/video/via/accel.c
+++ b/drivers/video/via/accel.c
@@ -137,7 +137,7 @@ static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
tmp, dst_pitch);
return -EINVAL;
}
- tmp = (tmp >> 3) | (dst_pitch << (16 - 3));
+ tmp = VIA_PITCH_ENABLE | (tmp >> 3) | (dst_pitch << (16 - 3));
writel(tmp, engine + 0x38);
if (op == VIA_BITBLT_FILL)
@@ -352,6 +352,9 @@ int viafb_init_engine(struct fb_info *info)
viapar->shared->vq_vram_addr = viapar->fbmem_free;
viapar->fbmem_used += VQ_SIZE;
+ /* Init 2D engine reg to reset 2D engine */
+ writel(0x0, engine + VIA_REG_KEYCONTROL);
+
/* Init AGP and VQ regs */
switch (chip_name) {
case UNICHROME_K8M890:
diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h
index 474f428aea92..8c06bd3c0b4d 100644
--- a/drivers/video/via/chip.h
+++ b/drivers/video/via/chip.h
@@ -107,7 +107,6 @@
struct tmds_chip_information {
int tmds_chip_name;
int tmds_chip_slave_addr;
- int dvi_panel_id;
int data_mode;
int output_interface;
int i2c_port;
@@ -142,14 +141,9 @@ struct tmds_setting_information {
int iga_path;
int h_active;
int v_active;
- int bpp;
- int refresh_rate;
- int get_dvi_size_method;
int max_pixel_clock;
- int dvi_panel_size;
- int dvi_panel_hres;
- int dvi_panel_vres;
- int native_size;
+ int max_hres;
+ int max_vres;
};
struct lvds_setting_information {
@@ -160,7 +154,6 @@ struct lvds_setting_information {
int refresh_rate;
int get_lcd_size_method;
int lcd_panel_id;
- int lcd_panel_size;
int lcd_panel_hres;
int lcd_panel_vres;
int display_method;
diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c
index 67b36932212b..abe59b8c7a05 100644
--- a/drivers/video/via/dvi.c
+++ b/drivers/video/via/dvi.c
@@ -23,11 +23,10 @@
static void tmds_register_write(int index, u8 data);
static int tmds_register_read(int index);
static int tmds_register_read_bytes(int index, u8 *buff, int buff_len);
-static int check_reduce_blanking_mode(int mode_index,
- int refresh_rate);
-static int dvi_get_panel_size_from_DDCv1(void);
-static int dvi_get_panel_size_from_DDCv2(void);
-static unsigned char dvi_get_panel_info(void);
+static void dvi_get_panel_size_from_DDCv1(struct tmds_chip_information
+ *tmds_chip, struct tmds_setting_information *tmds_setting);
+static void dvi_get_panel_size_from_DDCv2(struct tmds_chip_information
+ *tmds_chip, struct tmds_setting_information *tmds_setting);
static int viafb_dvi_query_EDID(void);
static int check_tmds_chip(int device_id_subaddr, int device_id)
@@ -38,23 +37,24 @@ static int check_tmds_chip(int device_id_subaddr, int device_id)
return FAIL;
}
-void viafb_init_dvi_size(void)
+void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
+ struct tmds_setting_information *tmds_setting)
{
DEBUG_MSG(KERN_INFO "viafb_init_dvi_size()\n");
- DEBUG_MSG(KERN_INFO
- "viaparinfo->tmds_setting_info->get_dvi_size_method %d\n",
- viaparinfo->tmds_setting_info->get_dvi_size_method);
- switch (viaparinfo->tmds_setting_info->get_dvi_size_method) {
- case GET_DVI_SIZE_BY_SYSTEM_BIOS:
+ viafb_dvi_sense();
+ switch (viafb_dvi_query_EDID()) {
+ case 1:
+ dvi_get_panel_size_from_DDCv1(tmds_chip, tmds_setting);
break;
- case GET_DVI_SZIE_BY_HW_STRAPPING:
+ case 2:
+ dvi_get_panel_size_from_DDCv2(tmds_chip, tmds_setting);
break;
- case GET_DVI_SIZE_BY_VGA_BIOS:
default:
- dvi_get_panel_info();
+ printk(KERN_WARNING "viafb_init_dvi_size: DVI panel size undetected!\n");
break;
}
+
return;
}
@@ -189,42 +189,14 @@ static int tmds_register_read_bytes(int index, u8 *buff, int buff_len)
return 0;
}
-static int check_reduce_blanking_mode(int mode_index,
- int refresh_rate)
-{
- if (refresh_rate != 60)
- return false;
-
- switch (mode_index) {
- /* Following modes have reduce blanking mode. */
- case VIA_RES_1360X768:
- case VIA_RES_1400X1050:
- case VIA_RES_1440X900:
- case VIA_RES_1600X900:
- case VIA_RES_1680X1050:
- case VIA_RES_1920X1080:
- case VIA_RES_1920X1200:
- break;
-
- default:
- DEBUG_MSG(KERN_INFO
- "This dvi mode %d have no reduce blanking mode!\n",
- mode_index);
- return false;
- }
-
- return true;
-}
-
/* DVI Set Mode */
-void viafb_dvi_set_mode(int video_index, int mode_bpp, int set_iga)
+void viafb_dvi_set_mode(struct VideoModeTable *mode, int mode_bpp,
+ int set_iga)
{
- struct VideoModeTable *videoMode = NULL;
+ struct VideoModeTable *rb_mode;
struct crt_mode_table *pDviTiming;
unsigned long desirePixelClock, maxPixelClock;
- int status = 0;
- videoMode = viafb_get_modetbl_pointer(video_index);
- pDviTiming = videoMode->crtc;
+ pDviTiming = mode->crtc;
desirePixelClock = pDviTiming->clk / 1000000;
maxPixelClock = (unsigned long)viaparinfo->
tmds_setting_info->max_pixel_clock;
@@ -232,20 +204,14 @@ void viafb_dvi_set_mode(int video_index, int mode_bpp, int set_iga)
DEBUG_MSG(KERN_INFO "\nDVI_set_mode!!\n");
if ((maxPixelClock != 0) && (desirePixelClock > maxPixelClock)) {
- /*Check if reduce-blanking mode is exist */
- status =
- check_reduce_blanking_mode(video_index,
- pDviTiming->refresh_rate);
- if (status) {
- video_index += 100; /*Use reduce-blanking mode */
- videoMode = viafb_get_modetbl_pointer(video_index);
- pDviTiming = videoMode->crtc;
- DEBUG_MSG(KERN_INFO
- "DVI use reduce blanking mode %d!!\n",
- video_index);
+ rb_mode = viafb_get_rb_mode(mode->crtc[0].crtc.hor_addr,
+ mode->crtc[0].crtc.ver_addr);
+ if (rb_mode) {
+ mode = rb_mode;
+ pDviTiming = rb_mode->crtc;
}
}
- viafb_fill_crtc_timing(pDviTiming, video_index, mode_bpp / 8, set_iga);
+ viafb_fill_crtc_timing(pDviTiming, mode, mode_bpp / 8, set_iga);
viafb_set_output_path(DEVICE_DVI, set_iga,
viaparinfo->chip_info->tmds_chip_info.output_interface);
}
@@ -350,25 +316,18 @@ static int viafb_dvi_query_EDID(void)
return false;
}
-/*
- *
- * int dvi_get_panel_size_from_DDCv1(void)
- *
- * - Get Panel Size Using EDID1 Table
- *
- * Return Type: int
- *
- */
-static int dvi_get_panel_size_from_DDCv1(void)
+/* Get Panel Size Using EDID1 Table */
+static void dvi_get_panel_size_from_DDCv1(struct tmds_chip_information
+ *tmds_chip, struct tmds_setting_information *tmds_setting)
{
- int i, max_h = 0, max_v = 0, tmp, restore;
+ int i, max_h = 0, tmp, restore;
unsigned char rData;
unsigned char EDID_DATA[18];
DEBUG_MSG(KERN_INFO "\n dvi_get_panel_size_from_DDCv1 \n");
- restore = viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr;
- viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = 0xA0;
+ restore = tmds_chip->tmds_chip_slave_addr;
+ tmds_chip->tmds_chip_slave_addr = 0xA0;
rData = tmds_register_read(0x23);
if (rData & 0x3C)
@@ -414,8 +373,8 @@ static int dvi_get_panel_size_from_DDCv1(void)
/* The first two byte must be zero. */
if (EDID_DATA[3] == 0xFD) {
/* To get max pixel clock. */
- viaparinfo->tmds_setting_info->
- max_pixel_clock = EDID_DATA[9] * 10;
+ tmds_setting->max_pixel_clock =
+ EDID_DATA[9] * 10;
}
}
break;
@@ -425,154 +384,88 @@ static int dvi_get_panel_size_from_DDCv1(void)
}
}
+ tmds_setting->max_hres = max_h;
switch (max_h) {
case 640:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_640X480;
+ tmds_setting->max_vres = 480;
break;
case 800:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_800X600;
+ tmds_setting->max_vres = 600;
break;
case 1024:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1024X768;
+ tmds_setting->max_vres = 768;
break;
case 1280:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1280X1024;
+ tmds_setting->max_vres = 1024;
break;
case 1400:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1400X1050;
+ tmds_setting->max_vres = 1050;
break;
case 1440:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1440X1050;
+ tmds_setting->max_vres = 1050;
break;
case 1600:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1600X1200;
+ tmds_setting->max_vres = 1200;
break;
case 1920:
- if (max_v == 1200) {
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1920X1200;
- } else {
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1920X1080;
- }
-
+ tmds_setting->max_vres = 1080;
break;
default:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1024X768;
- DEBUG_MSG(KERN_INFO "Unknown panel size max resolution = %d !\
- set default panel size.\n", max_h);
+ DEBUG_MSG(KERN_INFO "Unknown panel size max resolution = %d ! "
+ "set default panel size.\n", max_h);
break;
}
DEBUG_MSG(KERN_INFO "DVI max pixelclock = %d\n",
- viaparinfo->tmds_setting_info->max_pixel_clock);
- viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = restore;
- return viaparinfo->tmds_setting_info->dvi_panel_size;
+ tmds_setting->max_pixel_clock);
+ tmds_chip->tmds_chip_slave_addr = restore;
}
-/*
- *
- * int dvi_get_panel_size_from_DDCv2(void)
- *
- * - Get Panel Size Using EDID2 Table
- *
- * Return Type: int
- *
- */
-static int dvi_get_panel_size_from_DDCv2(void)
+/* Get Panel Size Using EDID2 Table */
+static void dvi_get_panel_size_from_DDCv2(struct tmds_chip_information
+ *tmds_chip, struct tmds_setting_information *tmds_setting)
{
- int HSize = 0, restore;
+ int restore;
unsigned char R_Buffer[2];
DEBUG_MSG(KERN_INFO "\n dvi_get_panel_size_from_DDCv2 \n");
- restore = viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr;
- viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = 0xA2;
+ restore = tmds_chip->tmds_chip_slave_addr;
+ tmds_chip->tmds_chip_slave_addr = 0xA2;
/* Horizontal: 0x76, 0x77 */
tmds_register_read_bytes(0x76, R_Buffer, 2);
- HSize = R_Buffer[0];
- HSize += R_Buffer[1] << 8;
+ tmds_setting->max_hres = R_Buffer[0] + (R_Buffer[1] << 8);
- switch (HSize) {
+ switch (tmds_setting->max_hres) {
case 640:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_640X480;
+ tmds_setting->max_vres = 480;
break;
case 800:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_800X600;
+ tmds_setting->max_vres = 600;
break;
case 1024:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1024X768;
+ tmds_setting->max_vres = 768;
break;
case 1280:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1280X1024;
+ tmds_setting->max_vres = 1024;
break;
case 1400:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1400X1050;
+ tmds_setting->max_vres = 1050;
break;
case 1440:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1440X1050;
+ tmds_setting->max_vres = 1050;
break;
case 1600:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1600X1200;
- break;
- default:
- viaparinfo->tmds_setting_info->dvi_panel_size =
- VIA_RES_1024X768;
- DEBUG_MSG(KERN_INFO "Unknown panel size max resolution = %d!\
- set default panel size.\n", HSize);
- break;
- }
-
- viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = restore;
- return viaparinfo->tmds_setting_info->dvi_panel_size;
-}
-
-/*
- *
- * unsigned char dvi_get_panel_info(void)
- *
- * - Get Panel Size
- *
- * Return Type: unsigned char
- */
-static unsigned char dvi_get_panel_info(void)
-{
- unsigned char dvipanelsize;
- DEBUG_MSG(KERN_INFO "dvi_get_panel_info! \n");
-
- viafb_dvi_sense();
- switch (viafb_dvi_query_EDID()) {
- case 1:
- dvi_get_panel_size_from_DDCv1();
- break;
- case 2:
- dvi_get_panel_size_from_DDCv2();
+ tmds_setting->max_vres = 1200;
break;
default:
+ DEBUG_MSG(KERN_INFO "Unknown panel size max resolution = %d! "
+ "set default panel size.\n", tmds_setting->max_hres);
break;
}
- DEBUG_MSG(KERN_INFO "dvi panel size is %2d \n",
- viaparinfo->tmds_setting_info->dvi_panel_size);
- dvipanelsize = (unsigned char)(viaparinfo->
- tmds_setting_info->dvi_panel_size);
- return dvipanelsize;
+ tmds_chip->tmds_chip_slave_addr = restore;
}
/* If Disable DVI, turn off pad */
diff --git a/drivers/video/via/dvi.h b/drivers/video/via/dvi.h
index e1ec37fb0dc3..0dffcfd395f3 100644
--- a/drivers/video/via/dvi.h
+++ b/drivers/video/via/dvi.h
@@ -53,12 +53,13 @@
#define DEV_CONNECT_DVI 0x01
#define DEV_CONNECT_HDMI 0x02
-struct VideoModeTable *viafb_get_cea_mode_tbl_pointer(int Index);
int viafb_dvi_sense(void);
void viafb_dvi_disable(void);
void viafb_dvi_enable(void);
int viafb_tmds_trasmitter_identify(void);
-void viafb_init_dvi_size(void);
-void viafb_dvi_set_mode(int video_index, int mode_bpp, int set_iga);
+void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
+ struct tmds_setting_information *tmds_setting);
+void viafb_dvi_set_mode(struct VideoModeTable *videoMode, int mode_bpp,
+ int set_iga);
#endif /* __DVI_H__ */
diff --git a/drivers/video/via/global.c b/drivers/video/via/global.c
index b675cdbb03ad..1ee511b73307 100644
--- a/drivers/video/via/global.c
+++ b/drivers/video/via/global.c
@@ -23,15 +23,12 @@ int viafb_platform_epia_dvi = STATE_OFF;
int viafb_device_lcd_dualedge = STATE_OFF;
int viafb_bus_width = 12;
int viafb_display_hardware_layout = HW_LAYOUT_LCD_DVI;
-int viafb_memsize;
int viafb_DeviceStatus = CRT_Device;
int viafb_hotplug;
int viafb_refresh = 60;
int viafb_refresh1 = 60;
int viafb_lcd_dsp_method = LCD_EXPANDSION;
int viafb_lcd_mode = LCD_OPENLDI;
-int viafb_bpp = 32;
-int viafb_bpp1 = 32;
int viafb_CRT_ON = 1;
int viafb_DVI_ON;
int viafb_LCD_ON ;
@@ -42,8 +39,6 @@ int viafb_hotplug_Xres = 640;
int viafb_hotplug_Yres = 480;
int viafb_hotplug_bpp = 32;
int viafb_hotplug_refresh = 60;
-unsigned int viafb_second_offset;
-int viafb_second_size;
int viafb_primary_dev = None_Device;
unsigned int viafb_second_xres = 640;
unsigned int viafb_second_yres = 480;
diff --git a/drivers/video/via/global.h b/drivers/video/via/global.h
index d69d0ca99c2f..8d95d5fd1388 100644
--- a/drivers/video/via/global.h
+++ b/drivers/video/via/global.h
@@ -35,7 +35,6 @@
#include "debug.h"
-#include "iface.h"
#include "viafbdev.h"
#include "chip.h"
#include "accel.h"
@@ -68,8 +67,6 @@ extern int viafb_refresh;
extern int viafb_refresh1;
extern int viafb_lcd_dsp_method;
extern int viafb_lcd_mode;
-extern int viafb_bpp;
-extern int viafb_bpp1;
extern int viafb_CRT_ON;
extern int viafb_hotplug_Xres;
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index 3e083ff67ae2..f2583b1b527f 100644
--- a/drivers/video/via/hw.c
+++ b/drivers/video/via/hw.c
@@ -524,7 +524,6 @@ static void dvi_patch_skew_dvp1(void);
static void dvi_patch_skew_dvp_low(void);
static void set_dvi_output_path(int set_iga, int output_interface);
static void set_lcd_output_path(int set_iga, int output_interface);
-static int search_mode_setting(int ModeInfoIndex);
static void load_fix_bit_crtc_reg(void);
static void init_gfx_chip_info(struct pci_dev *pdev,
const struct pci_device_id *pdi);
@@ -686,6 +685,84 @@ void viafb_set_secondary_pitch(u32 pitch)
viafb_write_reg_mask(0x71, VIACR, (pitch >> (10 - 7)) & 0x80, 0x80);
}
+void viafb_set_primary_color_depth(u8 depth)
+{
+ u8 value;
+
+ DEBUG_MSG(KERN_DEBUG "viafb_set_primary_color_depth(%d)\n", depth);
+ switch (depth) {
+ case 8:
+ value = 0x00;
+ break;
+ case 15:
+ value = 0x04;
+ break;
+ case 16:
+ value = 0x14;
+ break;
+ case 24:
+ value = 0x0C;
+ break;
+ case 30:
+ value = 0x08;
+ break;
+ default:
+ printk(KERN_WARNING "viafb_set_primary_color_depth: "
+ "Unsupported depth: %d\n", depth);
+ return;
+ }
+
+ viafb_write_reg_mask(0x15, VIASR, value, 0x1C);
+}
+
+void viafb_set_secondary_color_depth(u8 depth)
+{
+ u8 value;
+
+ DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_color_depth(%d)\n", depth);
+ switch (depth) {
+ case 8:
+ value = 0x00;
+ break;
+ case 16:
+ value = 0x40;
+ break;
+ case 24:
+ value = 0xC0;
+ break;
+ case 30:
+ value = 0x80;
+ break;
+ default:
+ printk(KERN_WARNING "viafb_set_secondary_color_depth: "
+ "Unsupported depth: %d\n", depth);
+ return;
+ }
+
+ viafb_write_reg_mask(0x67, VIACR, value, 0xC0);
+}
+
+static void set_color_register(u8 index, u8 red, u8 green, u8 blue)
+{
+ outb(0xFF, 0x3C6); /* bit mask of palette */
+ outb(index, 0x3C8);
+ outb(red, 0x3C9);
+ outb(green, 0x3C9);
+ outb(blue, 0x3C9);
+}
+
+void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue)
+{
+ viafb_write_reg_mask(0x1A, VIASR, 0x00, 0x01);
+ set_color_register(index, red, green, blue);
+}
+
+void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue)
+{
+ viafb_write_reg_mask(0x1A, VIASR, 0x01, 0x01);
+ set_color_register(index, red, green, blue);
+}
+
void viafb_set_output_path(int device, int set_iga, int output_interface)
{
switch (device) {
@@ -710,11 +787,8 @@ static void set_crt_output_path(int set_iga)
viafb_write_reg_mask(SR16, VIASR, 0x00, BIT6);
break;
case IGA2:
- case IGA1_IGA2:
viafb_write_reg_mask(CR6A, VIACR, 0xC0, BIT6 + BIT7);
viafb_write_reg_mask(SR16, VIASR, 0x40, BIT6);
- if (set_iga == IGA1_IGA2)
- viafb_write_reg_mask(CR6B, VIACR, 0x08, BIT3);
break;
}
}
@@ -904,13 +978,6 @@ static void set_lcd_output_path(int set_iga, int output_interface)
enable_second_display_channel();
break;
-
- case IGA1_IGA2:
- viafb_write_reg_mask(CR6B, VIACR, 0x08, BIT3);
- viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
-
- disable_second_display_channel();
- break;
}
switch (output_interface) {
@@ -987,49 +1054,6 @@ static void set_lcd_output_path(int set_iga, int output_interface)
}
}
-/* Search Mode Index */
-static int search_mode_setting(int ModeInfoIndex)
-{
- int i = 0;
-
- while ((i < NUM_TOTAL_MODETABLE) &&
- (ModeInfoIndex != CLE266Modes[i].ModeIndex))
- i++;
- if (i >= NUM_TOTAL_MODETABLE)
- i = 0;
- return i;
-
-}
-
-struct VideoModeTable *viafb_get_modetbl_pointer(int Index)
-{
- struct VideoModeTable *TmpTbl = NULL;
- TmpTbl = &CLE266Modes[search_mode_setting(Index)];
- return TmpTbl;
-}
-
-struct VideoModeTable *viafb_get_cea_mode_tbl_pointer(int Index)
-{
- struct VideoModeTable *TmpTbl = NULL;
- int i = 0;
- while ((i < NUM_TOTAL_CEA_MODES) &&
- (Index != CEA_HDMI_Modes[i].ModeIndex))
- i++;
- if ((i < NUM_TOTAL_CEA_MODES))
- TmpTbl = &CEA_HDMI_Modes[i];
- else {
- /*Still use general timing if don't find CEA timing */
- i = 0;
- while ((i < NUM_TOTAL_MODETABLE) &&
- (Index != CLE266Modes[i].ModeIndex))
- i++;
- if (i >= NUM_TOTAL_MODETABLE)
- i = 0;
- TmpTbl = &CLE266Modes[i];
- }
- return TmpTbl;
-}
-
static void load_fix_bit_crtc_reg(void)
{
/* always set to 1 */
@@ -1121,15 +1145,13 @@ void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga)
struct io_register *reg = NULL;
switch (set_iga) {
- case IGA1_IGA2:
case IGA1:
reg_value = IGA1_FETCH_COUNT_FORMULA(h_addr, bpp_byte);
viafb_load_reg_num = fetch_count_reg.
iga1_fetch_count_reg.reg_num;
reg = fetch_count_reg.iga1_fetch_count_reg.reg;
viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR);
- if (set_iga == IGA1)
- break;
+ break;
case IGA2:
reg_value = IGA2_FETCH_COUNT_FORMULA(h_addr, bpp_byte);
viafb_load_reg_num = fetch_count_reg.
@@ -1499,7 +1521,7 @@ void viafb_set_vclock(u32 CLK, int set_iga)
/* H.W. Reset : ON */
viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
- if ((set_iga == IGA1) || (set_iga == IGA1_IGA2)) {
+ if (set_iga == IGA1) {
/* Change D,N FOR VCLK */
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
@@ -1528,7 +1550,7 @@ void viafb_set_vclock(u32 CLK, int set_iga)
}
}
- if ((set_iga == IGA2) || (set_iga == IGA1_IGA2)) {
+ if (set_iga == IGA2) {
/* Change D,N FOR LCK */
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
@@ -1557,12 +1579,12 @@ void viafb_set_vclock(u32 CLK, int set_iga)
viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
/* Reset PLL */
- if ((set_iga == IGA1) || (set_iga == IGA1_IGA2)) {
+ if (set_iga == IGA1) {
viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1);
viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1);
}
- if ((set_iga == IGA2) || (set_iga == IGA1_IGA2)) {
+ if (set_iga == IGA2) {
viafb_write_reg_mask(SR40, VIASR, 0x01, BIT0);
viafb_write_reg_mask(SR40, VIASR, 0x00, BIT0);
}
@@ -1805,47 +1827,15 @@ void viafb_load_crtc_timing(struct display_timing device_timing,
viafb_lock_crt();
}
-void viafb_set_color_depth(int bpp_byte, int set_iga)
-{
- if (set_iga == IGA1) {
- switch (bpp_byte) {
- case MODE_8BPP:
- viafb_write_reg_mask(SR15, VIASR, 0x22, 0x7E);
- break;
- case MODE_16BPP:
- viafb_write_reg_mask(SR15, VIASR, 0xB6, 0xFE);
- break;
- case MODE_32BPP:
- viafb_write_reg_mask(SR15, VIASR, 0xAE, 0xFE);
- break;
- }
- } else {
- switch (bpp_byte) {
- case MODE_8BPP:
- viafb_write_reg_mask(CR67, VIACR, 0x00, BIT6 + BIT7);
- break;
- case MODE_16BPP:
- viafb_write_reg_mask(CR67, VIACR, 0x40, BIT6 + BIT7);
- break;
- case MODE_32BPP:
- viafb_write_reg_mask(CR67, VIACR, 0xC0, BIT6 + BIT7);
- break;
- }
- }
-}
-
void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
- int mode_index, int bpp_byte, int set_iga)
+ struct VideoModeTable *video_mode, int bpp_byte, int set_iga)
{
- struct VideoModeTable *video_mode;
struct display_timing crt_reg;
int i;
int index = 0;
int h_addr, v_addr;
u32 pll_D_N;
- video_mode = &CLE266Modes[search_mode_setting(mode_index)];
-
for (i = 0; i < video_mode->mode_array; i++) {
index = i;
@@ -1858,8 +1848,10 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
/* Mode 640x480 has border, but LCD/DFP didn't have border. */
/* So we would delete border. */
- if ((viafb_LCD_ON | viafb_DVI_ON) && (mode_index == VIA_RES_640X480)
- && (viaparinfo->crt_setting_info->refresh_rate == 60)) {
+ if ((viafb_LCD_ON | viafb_DVI_ON)
+ && video_mode->crtc[0].crtc.hor_addr == 640
+ && video_mode->crtc[0].crtc.ver_addr == 480
+ && viaparinfo->crt_setting_info->refresh_rate == 60) {
/* The border is 8 pixels. */
crt_reg.hor_blank_start = crt_reg.hor_blank_start - 8;
@@ -1912,9 +1904,6 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
&& (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400))
viafb_load_FIFO_reg(set_iga, h_addr, v_addr);
- /* load SR Register About Memory and Color part */
- viafb_set_color_depth(bpp_byte, set_iga);
-
pll_D_N = viafb_get_clk_value(crt_table[index].clk);
DEBUG_MSG(KERN_INFO "PLL=%x", pll_D_N);
viafb_set_vclock(pll_D_N, set_iga);
@@ -1956,9 +1945,6 @@ void viafb_update_device_setting(int hres, int vres,
viaparinfo->tmds_setting_info->h_active = hres;
viaparinfo->tmds_setting_info->v_active = vres;
- viaparinfo->tmds_setting_info->bpp = bpp;
- viaparinfo->tmds_setting_info->refresh_rate =
- vmode_refresh;
viaparinfo->lvds_setting_info->h_active = hres;
viaparinfo->lvds_setting_info->v_active = vres;
@@ -1975,9 +1961,6 @@ void viafb_update_device_setting(int hres, int vres,
if (viaparinfo->tmds_setting_info->iga_path == IGA2) {
viaparinfo->tmds_setting_info->h_active = hres;
viaparinfo->tmds_setting_info->v_active = vres;
- viaparinfo->tmds_setting_info->bpp = bpp;
- viaparinfo->tmds_setting_info->refresh_rate =
- vmode_refresh;
}
if (viaparinfo->lvds_setting_info->iga_path == IGA2) {
@@ -2076,9 +2059,8 @@ static void init_tmds_chip_info(void)
DEBUG_MSG(KERN_INFO "TMDS Chip = %d\n",
viaparinfo->chip_info->tmds_chip_info.tmds_chip_name);
- viaparinfo->tmds_setting_info->get_dvi_size_method =
- GET_DVI_SIZE_BY_VGA_BIOS;
- viafb_init_dvi_size();
+ viafb_init_dvi_size(&viaparinfo->shared->chip_info.tmds_chip_info,
+ &viaparinfo->shared->tmds_setting_info);
}
static void init_lvds_chip_info(void)
@@ -2195,28 +2177,19 @@ static void set_display_channel(void)
}
}
-int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
- int vmode_index1, int hor_res1, int ver_res1, int video_bpp1)
+int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
+ struct VideoModeTable *vmode_tbl1, int video_bpp1)
{
int i, j;
int port;
u8 value, index, mask;
- struct VideoModeTable *vmode_tbl;
struct crt_mode_table *crt_timing;
- struct VideoModeTable *vmode_tbl1 = NULL;
struct crt_mode_table *crt_timing1 = NULL;
- DEBUG_MSG(KERN_INFO "Set Mode!!\n");
- DEBUG_MSG(KERN_INFO
- "vmode_index=%d hor_res=%d ver_res=%d video_bpp=%d\n",
- vmode_index, hor_res, ver_res, video_bpp);
-
device_screen_off();
- vmode_tbl = &CLE266Modes[search_mode_setting(vmode_index)];
crt_timing = vmode_tbl->crtc;
if (viafb_SAMM_ON == 1) {
- vmode_tbl1 = &CLE266Modes[search_mode_setting(vmode_index1)];
crt_timing1 = vmode_tbl1->crtc;
}
@@ -2267,12 +2240,11 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
outb(VPIT.SR[i - 1], VIASR + 1);
}
- viafb_set_primary_address(0);
- viafb_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0);
+ viafb_write_reg_mask(0x15, VIASR, 0xA2, 0xA2);
viafb_set_iga_path();
/* Write CRTC */
- viafb_fill_crtc_timing(crt_timing, vmode_index, video_bpp / 8, IGA1);
+ viafb_fill_crtc_timing(crt_timing, vmode_tbl, video_bpp / 8, IGA1);
/* Write Graphic Controller */
for (i = 0; i < StdGR; i++) {
@@ -2292,65 +2264,25 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
/* Update Patch Register */
- if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
- || (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K400)) {
- for (i = 0; i < NUM_TOTAL_PATCH_MODE; i++) {
- if (res_patch_table[i].mode_index == vmode_index) {
- for (j = 0;
- j < res_patch_table[i].table_length; j++) {
- index =
- res_patch_table[i].
- io_reg_table[j].index;
- port =
- res_patch_table[i].
- io_reg_table[j].port;
- value =
- res_patch_table[i].
- io_reg_table[j].value;
- mask =
- res_patch_table[i].
- io_reg_table[j].mask;
- viafb_write_reg_mask(index, port, value,
- mask);
- }
- }
- }
- }
-
- if (viafb_SAMM_ON == 1) {
- if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
- || (viaparinfo->chip_info->gfx_chip_name ==
- UNICHROME_K400)) {
- for (i = 0; i < NUM_TOTAL_PATCH_MODE; i++) {
- if (res_patch_table[i].mode_index ==
- vmode_index1) {
- for (j = 0;
- j <
- res_patch_table[i].
- table_length; j++) {
- index =
- res_patch_table[i].
- io_reg_table[j].index;
- port =
- res_patch_table[i].
- io_reg_table[j].port;
- value =
- res_patch_table[i].
- io_reg_table[j].value;
- mask =
- res_patch_table[i].
- io_reg_table[j].mask;
- viafb_write_reg_mask(index,
- port, value, mask);
- }
- }
- }
+ if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266
+ || viaparinfo->chip_info->gfx_chip_name == UNICHROME_K400)
+ && vmode_tbl->crtc[0].crtc.hor_addr == 1024
+ && vmode_tbl->crtc[0].crtc.ver_addr == 768) {
+ for (j = 0; j < res_patch_table[0].table_length; j++) {
+ index = res_patch_table[0].io_reg_table[j].index;
+ port = res_patch_table[0].io_reg_table[j].port;
+ value = res_patch_table[0].io_reg_table[j].value;
+ mask = res_patch_table[0].io_reg_table[j].mask;
+ viafb_write_reg_mask(index, port, value, mask);
}
}
viafb_set_primary_pitch(viafbinfo->fix.line_length);
viafb_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length
: viafbinfo->fix.line_length);
+ viafb_set_primary_color_depth(viaparinfo->depth);
+ viafb_set_secondary_color_depth(viafb_dual_fb ? viaparinfo1->depth
+ : viaparinfo->depth);
/* Update Refresh Rate Setting */
/* Clear On Screen */
@@ -2359,11 +2291,11 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
if (viafb_CRT_ON) {
if (viafb_SAMM_ON && (viaparinfo->crt_setting_info->iga_path ==
IGA2)) {
- viafb_fill_crtc_timing(crt_timing1, vmode_index1,
+ viafb_fill_crtc_timing(crt_timing1, vmode_tbl1,
video_bpp1 / 8,
viaparinfo->crt_setting_info->iga_path);
} else {
- viafb_fill_crtc_timing(crt_timing, vmode_index,
+ viafb_fill_crtc_timing(crt_timing, vmode_tbl,
video_bpp / 8,
viaparinfo->crt_setting_info->iga_path);
}
@@ -2373,7 +2305,7 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
/* Patch if set_hres is not 8 alignment (1366) to viafb_setmode
to 8 alignment (1368),there is several pixels (2 pixels)
on right side of screen. */
- if (hor_res % 8) {
+ if (vmode_tbl->crtc[0].crtc.hor_addr % 8) {
viafb_unlock_crt();
viafb_write_reg(CR02, VIACR,
viafb_read_reg(VIACR, CR02) - 1);
@@ -2384,14 +2316,14 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
if (viafb_DVI_ON) {
if (viafb_SAMM_ON &&
(viaparinfo->tmds_setting_info->iga_path == IGA2)) {
- viafb_dvi_set_mode(viafb_get_mode_index
+ viafb_dvi_set_mode(viafb_get_mode
(viaparinfo->tmds_setting_info->h_active,
viaparinfo->tmds_setting_info->
v_active),
video_bpp1, viaparinfo->
tmds_setting_info->iga_path);
} else {
- viafb_dvi_set_mode(viafb_get_mode_index
+ viafb_dvi_set_mode(viafb_get_mode
(viaparinfo->tmds_setting_info->h_active,
viaparinfo->
tmds_setting_info->v_active),
@@ -2445,8 +2377,8 @@ int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
/* If set mode normally, save resolution information for hot-plug . */
if (!viafb_hotplug) {
- viafb_hotplug_Xres = hor_res;
- viafb_hotplug_Yres = ver_res;
+ viafb_hotplug_Xres = vmode_tbl->crtc[0].crtc.hor_addr;
+ viafb_hotplug_Yres = vmode_tbl->crtc[0].crtc.ver_addr;
viafb_hotplug_bpp = video_bpp;
viafb_hotplug_refresh = viafb_refresh;
@@ -2706,13 +2638,11 @@ void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
/*According var's xres, yres fill var's other timing information*/
void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
- int mode_index)
+ struct VideoModeTable *vmode_tbl)
{
- struct VideoModeTable *vmode_tbl = NULL;
struct crt_mode_table *crt_timing = NULL;
struct display_timing crt_reg;
int i = 0, index = 0;
- vmode_tbl = &CLE266Modes[search_mode_setting(mode_index)];
crt_timing = vmode_tbl->crtc;
for (i = 0; i < vmode_tbl->mode_array; i++) {
index = i;
@@ -2721,36 +2651,6 @@ void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
}
crt_reg = crt_timing[index].crtc;
- switch (var->bits_per_pixel) {
- case 8:
- var->red.offset = 0;
- var->green.offset = 0;
- var->blue.offset = 0;
- var->red.length = 6;
- var->green.length = 6;
- var->blue.length = 6;
- break;
- case 16:
- var->red.offset = 11;
- var->green.offset = 5;
- var->blue.offset = 0;
- var->red.length = 5;
- var->green.length = 6;
- var->blue.length = 5;
- break;
- case 32:
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- break;
- default:
- /* never happed, put here to keep consistent */
- break;
- }
-
var->pixclock = viafb_get_pixclock(var->xres, var->yres, refresh);
var->left_margin =
crt_reg.hor_total - (crt_reg.hor_sync_start + crt_reg.hor_sync_end);
diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h
index b874d952b446..12ef32d334cb 100644
--- a/drivers/video/via/hw.h
+++ b/drivers/video/via/hw.h
@@ -22,6 +22,7 @@
#ifndef __HW_H__
#define __HW_H__
+#include "viamode.h"
#include "global.h"
/***************************************************
@@ -862,8 +863,6 @@ struct pci_device_id_info {
};
extern unsigned int viafb_second_virtual_xres;
-extern unsigned int viafb_second_offset;
-extern int viafb_second_size;
extern int viafb_SAMM_ON;
extern int viafb_dual_fb;
extern int viafb_LCD2_ON;
@@ -874,8 +873,9 @@ extern int viafb_hotplug;
void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask);
void viafb_set_output_path(int device, int set_iga,
int output_interface);
+
void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
- int mode_index, int bpp_byte, int set_iga);
+ struct VideoModeTable *video_mode, int bpp_byte, int set_iga);
void viafb_set_vclock(u32 CLK, int set_iga);
void viafb_load_reg(int timing_value, int viafb_load_reg_num,
@@ -891,16 +891,15 @@ void viafb_lock_crt(void);
void viafb_unlock_crt(void);
void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga);
void viafb_write_regx(struct io_reg RegTable[], int ItemNum);
-struct VideoModeTable *viafb_get_modetbl_pointer(int Index);
u32 viafb_get_clk_value(int clk);
void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active);
-void viafb_set_color_depth(int bpp_byte, int set_iga);
void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
*p_gfx_dpa_setting);
-int viafb_setmode(int vmode_index, int hor_res, int ver_res,
- int video_bpp, int vmode_index1, int hor_res1,
- int ver_res1, int video_bpp1);
+int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
+ struct VideoModeTable *vmode_tbl1, int video_bpp1);
+void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
+ struct VideoModeTable *vmode_tbl);
void viafb_init_chip_info(struct pci_dev *pdev,
const struct pci_device_id *pdi);
void viafb_init_dac(int set_iga);
@@ -915,6 +914,8 @@ void viafb_set_primary_address(u32 addr);
void viafb_set_secondary_address(u32 addr);
void viafb_set_primary_pitch(u32 pitch);
void viafb_set_secondary_pitch(u32 pitch);
+void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue);
+void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue);
void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len);
#endif /* __HW_H__ */
diff --git a/drivers/video/via/iface.c b/drivers/video/via/iface.c
deleted file mode 100644
index 1570636c8d51..000000000000
--- a/drivers/video/via/iface.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2008 S3 Graphics, Inc. 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, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.See the GNU General Public License
- * for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include "global.h"
-
-/* Get frame buffer size from VGA BIOS */
-
-unsigned int viafb_get_memsize(void)
-{
- unsigned int m;
-
- /* If memory size provided by user */
- if (viafb_memsize)
- m = viafb_memsize * Mb;
- else {
- m = (unsigned int)viafb_read_reg(VIASR, SR39);
- m = m * (4 * Mb);
-
- if ((m < (16 * Mb)) || (m > (64 * Mb)))
- m = 16 * Mb;
- }
- DEBUG_MSG(KERN_INFO "framebuffer size = %d Mb\n", m / Mb);
- return m;
-}
-
-/* Get Video Buffer Starting Physical Address(back door)*/
-
-unsigned long viafb_get_videobuf_addr(void)
-{
- struct pci_dev *pdev = NULL;
- unsigned char sys_mem;
- unsigned char video_mem;
- unsigned long sys_mem_size;
- unsigned long video_mem_size;
- /*system memory = 256 MB, video memory 64 MB */
- unsigned long vmem_starting_adr = 0x0C000000;
-
- pdev =
- (struct pci_dev *)pci_get_device(VIA_K800_BRIDGE_VID,
- VIA_K800_BRIDGE_DID, NULL);
- if (pdev != NULL) {
- pci_read_config_byte(pdev, VIA_K800_SYSTEM_MEMORY_REG,
- &sys_mem);
- pci_read_config_byte(pdev, VIA_K800_VIDEO_MEMORY_REG,
- &video_mem);
- video_mem = (video_mem & 0x70) >> 4;
- sys_mem_size = ((unsigned long)sys_mem) << 24;
- if (video_mem != 0)
- video_mem_size = (1 << (video_mem)) * 1024 * 1024;
- else
- video_mem_size = 0;
-
- vmem_starting_adr = sys_mem_size - video_mem_size;
- pci_dev_put(pdev);
- }
-
- DEBUG_MSG(KERN_INFO "Video Memory Starting Address = %lx \n",
- vmem_starting_adr);
- return vmem_starting_adr;
-}
diff --git a/drivers/video/via/iface.h b/drivers/video/via/iface.h
deleted file mode 100644
index 790ec3e3aea2..000000000000
--- a/drivers/video/via/iface.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2008 S3 Graphics, Inc. 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, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
- * the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.See the GNU General Public License
- * for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __IFACE_H__
-#define __IFACE_H__
-
-#define Kb (1024)
-#define Mb (Kb*Kb)
-
-#define VIA_K800_BRIDGE_VID 0x1106
-#define VIA_K800_BRIDGE_DID 0x3204
-
-#define VIA_K800_SYSTEM_MEMORY_REG 0x47
-#define VIA_K800_VIDEO_MEMORY_REG 0xA1
-
-extern int viafb_memsize;
-unsigned int viafb_get_memsize(void);
-unsigned long viafb_get_videobuf_addr(void);
-
-#endif /* __IFACE_H__ */
diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c
index 09353e2b92f6..1b1ccdc2d83d 100644
--- a/drivers/video/via/lcd.c
+++ b/drivers/video/via/lcd.c
@@ -22,25 +22,7 @@
#include "global.h"
#include "lcdtbl.h"
-static struct iga2_shadow_crtc_timing iga2_shadow_crtc_reg = {
- /* IGA2 Shadow Horizontal Total */
- {IGA2_SHADOW_HOR_TOTAL_REG_NUM, {{CR6D, 0, 7}, {CR71, 3, 3} } },
- /* IGA2 Shadow Horizontal Blank End */
- {IGA2_SHADOW_HOR_BLANK_END_REG_NUM, {{CR6E, 0, 7} } },
- /* IGA2 Shadow Vertical Total */
- {IGA2_SHADOW_VER_TOTAL_REG_NUM, {{CR6F, 0, 7}, {CR71, 0, 2} } },
- /* IGA2 Shadow Vertical Addressable Video */
- {IGA2_SHADOW_VER_ADDR_REG_NUM, {{CR70, 0, 7}, {CR71, 4, 6} } },
- /* IGA2 Shadow Vertical Blank Start */
- {IGA2_SHADOW_VER_BLANK_START_REG_NUM,
- {{CR72, 0, 7}, {CR74, 4, 6} } },
- /* IGA2 Shadow Vertical Blank End */
- {IGA2_SHADOW_VER_BLANK_END_REG_NUM, {{CR73, 0, 7}, {CR74, 0, 2} } },
- /* IGA2 Shadow Vertical Sync Start */
- {IGA2_SHADOW_VER_SYNC_START_REG_NUM, {{CR75, 0, 7}, {CR76, 4, 6} } },
- /* IGA2 Shadow Vertical Sync End */
- {IGA2_SHADOW_VER_SYNC_END_REG_NUM, {{CR76, 0, 3} } }
-};
+#define viafb_compact_res(x, y) (((x)<<16)|(y))
static struct _lcd_scaling_factor lcd_scaling_factor = {
/* LCD Horizontal Scaling Factor Register */
@@ -59,16 +41,10 @@ static struct _lcd_scaling_factor lcd_scaling_factor_CLE = {
static int check_lvds_chip(int device_id_subaddr, int device_id);
static bool lvds_identify_integratedlvds(void);
-static int fp_id_to_vindex(int panel_id);
+static void fp_id_to_vindex(int panel_id);
static int lvds_register_read(int index);
static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
int panel_vres);
-static void load_lcd_k400_patch_tbl(int set_hres, int set_vres,
- int panel_id);
-static void load_lcd_p880_patch_tbl(int set_hres, int set_vres,
- int panel_id);
-static void load_lcd_patch_regs(int set_hres, int set_vres,
- int panel_id, int set_iga);
static void via_pitch_alignment_patch_lcd(
struct lvds_setting_information *plvds_setting_info,
struct lvds_chip_information
@@ -98,8 +74,6 @@ static void check_diport_of_integrated_lvds(
static struct display_timing lcd_centering_timging(struct display_timing
mode_crt_reg,
struct display_timing panel_crt_reg);
-static void load_crtc_shadow_timing(struct display_timing mode_timing,
- struct display_timing panel_timing);
static void viafb_load_scaling_factor_for_p4m900(int set_hres,
int set_vres, int panel_hres, int panel_vres);
@@ -125,33 +99,24 @@ void viafb_init_lcd_size(void)
break;
case GET_LCD_SIZE_BY_VGA_BIOS:
DEBUG_MSG(KERN_INFO "Get LCD Size method by VGA BIOS !!\n");
- viaparinfo->lvds_setting_info->lcd_panel_size =
- fp_id_to_vindex(viafb_lcd_panel_id);
+ fp_id_to_vindex(viafb_lcd_panel_id);
DEBUG_MSG(KERN_INFO "LCD Panel_ID = %d\n",
viaparinfo->lvds_setting_info->lcd_panel_id);
- DEBUG_MSG(KERN_INFO "LCD Panel Size = %d\n",
- viaparinfo->lvds_setting_info->lcd_panel_size);
break;
case GET_LCD_SIZE_BY_USER_SETTING:
DEBUG_MSG(KERN_INFO "Get LCD Size method by user setting !!\n");
- viaparinfo->lvds_setting_info->lcd_panel_size =
- fp_id_to_vindex(viafb_lcd_panel_id);
+ fp_id_to_vindex(viafb_lcd_panel_id);
DEBUG_MSG(KERN_INFO "LCD Panel_ID = %d\n",
viaparinfo->lvds_setting_info->lcd_panel_id);
- DEBUG_MSG(KERN_INFO "LCD Panel Size = %d\n",
- viaparinfo->lvds_setting_info->lcd_panel_size);
break;
default:
DEBUG_MSG(KERN_INFO "viafb_init_lcd_size fail\n");
viaparinfo->lvds_setting_info->lcd_panel_id =
LCD_PANEL_ID1_800X600;
- viaparinfo->lvds_setting_info->lcd_panel_size =
- fp_id_to_vindex(LCD_PANEL_ID1_800X600);
+ fp_id_to_vindex(LCD_PANEL_ID1_800X600);
}
viaparinfo->lvds_setting_info2->lcd_panel_id =
viaparinfo->lvds_setting_info->lcd_panel_id;
- viaparinfo->lvds_setting_info2->lcd_panel_size =
- viaparinfo->lvds_setting_info->lcd_panel_size;
viaparinfo->lvds_setting_info2->lcd_panel_hres =
viaparinfo->lvds_setting_info->lcd_panel_hres;
viaparinfo->lvds_setting_info2->lcd_panel_vres =
@@ -171,13 +136,13 @@ static bool lvds_identify_integratedlvds(void)
if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name =
INTEGRATED_LVDS;
- DEBUG_MSG(KERN_INFO "Support two dual channel LVDS!\
- (Internal LVDS + External LVDS)\n");
+ DEBUG_MSG(KERN_INFO "Support two dual channel LVDS! "
+ "(Internal LVDS + External LVDS)\n");
} else {
viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
INTEGRATED_LVDS;
- DEBUG_MSG(KERN_INFO "Not found external LVDS,\
- so can't support two dual channel LVDS!\n");
+ DEBUG_MSG(KERN_INFO "Not found external LVDS, "
+ "so can't support two dual channel LVDS!\n");
}
} else if (viafb_display_hardware_layout == HW_LAYOUT_LCD1_LCD2) {
/* Two single channel LCD (Internal LVDS + Internal LVDS): */
@@ -185,8 +150,8 @@ static bool lvds_identify_integratedlvds(void)
INTEGRATED_LVDS;
viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name =
INTEGRATED_LVDS;
- DEBUG_MSG(KERN_INFO "Support two single channel LVDS!\
- (Internal LVDS + Internal LVDS)\n");
+ DEBUG_MSG(KERN_INFO "Support two single channel LVDS! "
+ "(Internal LVDS + Internal LVDS)\n");
} else if (viafb_display_hardware_layout != HW_LAYOUT_DVI_ONLY) {
/* If we have found external LVDS, just use it,
otherwise, we will use internal LVDS as default. */
@@ -248,7 +213,7 @@ int viafb_lvds_trasmitter_identify(void)
return FAIL;
}
-static int fp_id_to_vindex(int panel_id)
+static void fp_id_to_vindex(int panel_id)
{
DEBUG_MSG(KERN_INFO "fp_get_panel_id()\n");
@@ -264,7 +229,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID0_640X480;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_640X480;
break;
case 0x1:
viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
@@ -273,7 +237,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID1_800X600;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_800X600;
break;
case 0x2:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
@@ -282,7 +245,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID2_1024X768;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_1024X768;
break;
case 0x3:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
@@ -291,7 +253,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID3_1280X768;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_1280X768;
break;
case 0x4:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
@@ -300,7 +261,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID4_1280X1024;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_1280X1024;
break;
case 0x5:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1400;
@@ -309,7 +269,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID5_1400X1050;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_1400X1050;
break;
case 0x6:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1600;
@@ -318,7 +277,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID6_1600X1200;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_1600X1200;
break;
case 0x8:
viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
@@ -327,7 +285,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_IDA_800X480;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_800X480;
break;
case 0x9:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
@@ -336,7 +293,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID2_1024X768;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_1024X768;
break;
case 0xA:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
@@ -345,7 +301,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID2_1024X768;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 0;
- return VIA_RES_1024X768;
break;
case 0xB:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
@@ -354,7 +309,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID2_1024X768;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
viaparinfo->lvds_setting_info->LCDDithering = 0;
- return VIA_RES_1024X768;
break;
case 0xC:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
@@ -363,7 +317,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID3_1280X768;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 0;
- return VIA_RES_1280X768;
break;
case 0xD:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
@@ -372,7 +325,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID4_1280X1024;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
viaparinfo->lvds_setting_info->LCDDithering = 0;
- return VIA_RES_1280X1024;
break;
case 0xE:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1400;
@@ -381,7 +333,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID5_1400X1050;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
viaparinfo->lvds_setting_info->LCDDithering = 0;
- return VIA_RES_1400X1050;
break;
case 0xF:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1600;
@@ -390,7 +341,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID6_1600X1200;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
viaparinfo->lvds_setting_info->LCDDithering = 0;
- return VIA_RES_1600X1200;
break;
case 0x10:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1366;
@@ -399,7 +349,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID7_1366X768;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 0;
- return VIA_RES_1368X768;
break;
case 0x11:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
@@ -408,7 +357,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID8_1024X600;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_1024X600;
break;
case 0x12:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
@@ -417,7 +365,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID3_1280X768;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_1280X768;
break;
case 0x13:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
@@ -426,7 +373,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID9_1280X800;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_1280X800;
break;
case 0x14:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1360;
@@ -435,7 +381,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_IDB_1360X768;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 0;
- return VIA_RES_1360X768;
break;
case 0x15:
viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
@@ -444,7 +389,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID3_1280X768;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
viaparinfo->lvds_setting_info->LCDDithering = 0;
- return VIA_RES_1280X768;
break;
case 0x16:
viaparinfo->lvds_setting_info->lcd_panel_hres = 480;
@@ -453,7 +397,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_IDC_480X640;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_480X640;
break;
default:
viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
@@ -462,7 +405,6 @@ static int fp_id_to_vindex(int panel_id)
LCD_PANEL_ID1_800X600;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 1;
- return VIA_RES_800X600;
}
}
@@ -573,284 +515,6 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
}
}
-static void load_lcd_k400_patch_tbl(int set_hres, int set_vres,
- int panel_id)
-{
- int vmode_index;
- int reg_num = 0;
- struct io_reg *lcd_patch_reg = NULL;
-
- vmode_index = viafb_get_mode_index(set_hres, set_vres);
- switch (panel_id) {
- /* LCD 800x600 */
- case LCD_PANEL_ID1_800X600:
- switch (vmode_index) {
- case VIA_RES_640X400:
- case VIA_RES_640X480:
- reg_num = NUM_TOTAL_K400_LCD_RES_6X4_8X6;
- lcd_patch_reg = K400_LCD_RES_6X4_8X6;
- break;
- case VIA_RES_720X480:
- case VIA_RES_720X576:
- reg_num = NUM_TOTAL_K400_LCD_RES_7X4_8X6;
- lcd_patch_reg = K400_LCD_RES_7X4_8X6;
- break;
- }
- break;
-
- /* LCD 1024x768 */
- case LCD_PANEL_ID2_1024X768:
- switch (vmode_index) {
- case VIA_RES_640X400:
- case VIA_RES_640X480:
- reg_num = NUM_TOTAL_K400_LCD_RES_6X4_10X7;
- lcd_patch_reg = K400_LCD_RES_6X4_10X7;
- break;
- case VIA_RES_720X480:
- case VIA_RES_720X576:
- reg_num = NUM_TOTAL_K400_LCD_RES_7X4_10X7;
- lcd_patch_reg = K400_LCD_RES_7X4_10X7;
- break;
- case VIA_RES_800X600:
- reg_num = NUM_TOTAL_K400_LCD_RES_8X6_10X7;
- lcd_patch_reg = K400_LCD_RES_8X6_10X7;
- break;
- }
- break;
-
- /* LCD 1280x1024 */
- case LCD_PANEL_ID4_1280X1024:
- switch (vmode_index) {
- case VIA_RES_640X400:
- case VIA_RES_640X480:
- reg_num = NUM_TOTAL_K400_LCD_RES_6X4_12X10;
- lcd_patch_reg = K400_LCD_RES_6X4_12X10;
- break;
- case VIA_RES_720X480:
- case VIA_RES_720X576:
- reg_num = NUM_TOTAL_K400_LCD_RES_7X4_12X10;
- lcd_patch_reg = K400_LCD_RES_7X4_12X10;
- break;
- case VIA_RES_800X600:
- reg_num = NUM_TOTAL_K400_LCD_RES_8X6_12X10;
- lcd_patch_reg = K400_LCD_RES_8X6_12X10;
- break;
- case VIA_RES_1024X768:
- reg_num = NUM_TOTAL_K400_LCD_RES_10X7_12X10;
- lcd_patch_reg = K400_LCD_RES_10X7_12X10;
- break;
-
- }
- break;
-
- /* LCD 1400x1050 */
- case LCD_PANEL_ID5_1400X1050:
- switch (vmode_index) {
- case VIA_RES_640X480:
- reg_num = NUM_TOTAL_K400_LCD_RES_6X4_14X10;
- lcd_patch_reg = K400_LCD_RES_6X4_14X10;
- break;
- case VIA_RES_800X600:
- reg_num = NUM_TOTAL_K400_LCD_RES_8X6_14X10;
- lcd_patch_reg = K400_LCD_RES_8X6_14X10;
- break;
- case VIA_RES_1024X768:
- reg_num = NUM_TOTAL_K400_LCD_RES_10X7_14X10;
- lcd_patch_reg = K400_LCD_RES_10X7_14X10;
- break;
- case VIA_RES_1280X768:
- case VIA_RES_1280X800:
- case VIA_RES_1280X960:
- case VIA_RES_1280X1024:
- reg_num = NUM_TOTAL_K400_LCD_RES_12X10_14X10;
- lcd_patch_reg = K400_LCD_RES_12X10_14X10;
- break;
- }
- break;
-
- /* LCD 1600x1200 */
- case LCD_PANEL_ID6_1600X1200:
- switch (vmode_index) {
- case VIA_RES_640X400:
- case VIA_RES_640X480:
- reg_num = NUM_TOTAL_K400_LCD_RES_6X4_16X12;
- lcd_patch_reg = K400_LCD_RES_6X4_16X12;
- break;
- case VIA_RES_720X480:
- case VIA_RES_720X576:
- reg_num = NUM_TOTAL_K400_LCD_RES_7X4_16X12;
- lcd_patch_reg = K400_LCD_RES_7X4_16X12;
- break;
- case VIA_RES_800X600:
- reg_num = NUM_TOTAL_K400_LCD_RES_8X6_16X12;
- lcd_patch_reg = K400_LCD_RES_8X6_16X12;
- break;
- case VIA_RES_1024X768:
- reg_num = NUM_TOTAL_K400_LCD_RES_10X7_16X12;
- lcd_patch_reg = K400_LCD_RES_10X7_16X12;
- break;
- case VIA_RES_1280X768:
- case VIA_RES_1280X800:
- case VIA_RES_1280X960:
- case VIA_RES_1280X1024:
- reg_num = NUM_TOTAL_K400_LCD_RES_12X10_16X12;
- lcd_patch_reg = K400_LCD_RES_12X10_16X12;
- break;
- }
- break;
-
- /* LCD 1366x768 */
- case LCD_PANEL_ID7_1366X768:
- switch (vmode_index) {
- case VIA_RES_640X480:
- reg_num = NUM_TOTAL_K400_LCD_RES_6X4_1366X7;
- lcd_patch_reg = K400_LCD_RES_6X4_1366X7;
- break;
- case VIA_RES_720X480:
- case VIA_RES_720X576:
- reg_num = NUM_TOTAL_K400_LCD_RES_7X4_1366X7;
- lcd_patch_reg = K400_LCD_RES_7X4_1366X7;
- break;
- case VIA_RES_800X600:
- reg_num = NUM_TOTAL_K400_LCD_RES_8X6_1366X7;
- lcd_patch_reg = K400_LCD_RES_8X6_1366X7;
- break;
- case VIA_RES_1024X768:
- reg_num = NUM_TOTAL_K400_LCD_RES_10X7_1366X7;
- lcd_patch_reg = K400_LCD_RES_10X7_1366X7;
- break;
- case VIA_RES_1280X768:
- case VIA_RES_1280X800:
- case VIA_RES_1280X960:
- case VIA_RES_1280X1024:
- reg_num = NUM_TOTAL_K400_LCD_RES_12X10_1366X7;
- lcd_patch_reg = K400_LCD_RES_12X10_1366X7;
- break;
- }
- break;
-
- /* LCD 1360x768 */
- case LCD_PANEL_IDB_1360X768:
- break;
- }
- if (reg_num != 0) {
- /* H.W. Reset : ON */
- viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
-
- viafb_write_regx(lcd_patch_reg, reg_num);
-
- /* H.W. Reset : OFF */
- viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
-
- /* Reset PLL */
- viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1);
- viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1);
-
- /* Fire! */
- outb(inb(VIARMisc) | (BIT2 + BIT3), VIAWMisc);
- }
-}
-
-static void load_lcd_p880_patch_tbl(int set_hres, int set_vres,
- int panel_id)
-{
- int vmode_index;
- int reg_num = 0;
- struct io_reg *lcd_patch_reg = NULL;
-
- vmode_index = viafb_get_mode_index(set_hres, set_vres);
-
- switch (panel_id) {
- case LCD_PANEL_ID5_1400X1050:
- switch (vmode_index) {
- case VIA_RES_640X480:
- reg_num = NUM_TOTAL_P880_LCD_RES_6X4_14X10;
- lcd_patch_reg = P880_LCD_RES_6X4_14X10;
- break;
- case VIA_RES_800X600:
- reg_num = NUM_TOTAL_P880_LCD_RES_8X6_14X10;
- lcd_patch_reg = P880_LCD_RES_8X6_14X10;
- break;
- }
- break;
- case LCD_PANEL_ID6_1600X1200:
- switch (vmode_index) {
- case VIA_RES_640X400:
- case VIA_RES_640X480:
- reg_num = NUM_TOTAL_P880_LCD_RES_6X4_16X12;
- lcd_patch_reg = P880_LCD_RES_6X4_16X12;
- break;
- case VIA_RES_720X480:
- case VIA_RES_720X576:
- reg_num = NUM_TOTAL_P880_LCD_RES_7X4_16X12;
- lcd_patch_reg = P880_LCD_RES_7X4_16X12;
- break;
- case VIA_RES_800X600:
- reg_num = NUM_TOTAL_P880_LCD_RES_8X6_16X12;
- lcd_patch_reg = P880_LCD_RES_8X6_16X12;
- break;
- case VIA_RES_1024X768:
- reg_num = NUM_TOTAL_P880_LCD_RES_10X7_16X12;
- lcd_patch_reg = P880_LCD_RES_10X7_16X12;
- break;
- case VIA_RES_1280X768:
- case VIA_RES_1280X960:
- case VIA_RES_1280X1024:
- reg_num = NUM_TOTAL_P880_LCD_RES_12X10_16X12;
- lcd_patch_reg = P880_LCD_RES_12X10_16X12;
- break;
- }
- break;
-
- }
- if (reg_num != 0) {
- /* H.W. Reset : ON */
- viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
-
- viafb_write_regx(lcd_patch_reg, reg_num);
-
- /* H.W. Reset : OFF */
- viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
-
- /* Reset PLL */
- viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1);
- viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1);
-
- /* Fire! */
- outb(inb(VIARMisc) | (BIT2 + BIT3), VIAWMisc);
- }
-}
-
-static void load_lcd_patch_regs(int set_hres, int set_vres,
- int panel_id, int set_iga)
-{
- int vmode_index;
-
- vmode_index = viafb_get_mode_index(set_hres, set_vres);
-
- viafb_unlock_crt();
-
- /* Patch for simultaneous & Expansion */
- if ((set_iga == IGA1_IGA2) &&
- (viaparinfo->lvds_setting_info->display_method ==
- LCD_EXPANDSION)) {
- switch (viaparinfo->chip_info->gfx_chip_name) {
- case UNICHROME_CLE266:
- case UNICHROME_K400:
- load_lcd_k400_patch_tbl(set_hres, set_vres, panel_id);
- break;
- case UNICHROME_K800:
- break;
- case UNICHROME_PM800:
- case UNICHROME_CN700:
- case UNICHROME_CX700:
- load_lcd_p880_patch_tbl(set_hres, set_vres, panel_id);
- }
- }
-
- viafb_lock_crt();
-}
-
static void via_pitch_alignment_patch_lcd(
struct lvds_setting_information *plvds_setting_info,
struct lvds_chip_information
@@ -949,29 +613,25 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
struct lvds_setting_information *plvds_setting_info,
struct lvds_chip_information *plvds_chip_info)
{
- int video_index = plvds_setting_info->lcd_panel_size;
int set_iga = plvds_setting_info->iga_path;
int mode_bpp = plvds_setting_info->bpp;
- int set_hres, set_vres;
- int panel_hres, panel_vres;
+ int set_hres = plvds_setting_info->h_active;
+ int set_vres = plvds_setting_info->v_active;
+ int panel_hres = plvds_setting_info->lcd_panel_hres;
+ int panel_vres = plvds_setting_info->lcd_panel_vres;
u32 pll_D_N;
- int offset;
struct display_timing mode_crt_reg, panel_crt_reg;
struct crt_mode_table *panel_crt_table = NULL;
- struct VideoModeTable *vmode_tbl = NULL;
+ struct VideoModeTable *vmode_tbl = viafb_get_mode(panel_hres,
+ panel_vres);
DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n");
/* Get mode table */
mode_crt_reg = mode_crt_table->crtc;
/* Get panel table Pointer */
- vmode_tbl = viafb_get_modetbl_pointer(video_index);
panel_crt_table = vmode_tbl->crtc;
panel_crt_reg = panel_crt_table->crtc;
DEBUG_MSG(KERN_INFO "bellow viafb_lcd_set_mode!!\n");
- set_hres = plvds_setting_info->h_active;
- set_vres = plvds_setting_info->v_active;
- panel_hres = plvds_setting_info->lcd_panel_hres;
- panel_vres = plvds_setting_info->lcd_panel_vres;
if (VT1636_LVDS == plvds_chip_info->lvds_chip_name)
viafb_init_lvds_vt1636(plvds_setting_info, plvds_chip_info);
plvds_setting_info->vclk = panel_crt_table->clk;
@@ -1001,54 +661,12 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
}
}
- if (set_iga == IGA1_IGA2) {
- load_crtc_shadow_timing(mode_crt_reg, panel_crt_reg);
- /* Fill shadow registers */
-
- switch (plvds_setting_info->lcd_panel_id) {
- case LCD_PANEL_ID0_640X480:
- offset = 80;
- break;
- case LCD_PANEL_ID1_800X600:
- case LCD_PANEL_IDA_800X480:
- offset = 110;
- break;
- case LCD_PANEL_ID2_1024X768:
- offset = 150;
- break;
- case LCD_PANEL_ID3_1280X768:
- case LCD_PANEL_ID4_1280X1024:
- case LCD_PANEL_ID5_1400X1050:
- case LCD_PANEL_ID9_1280X800:
- offset = 190;
- break;
- case LCD_PANEL_ID6_1600X1200:
- offset = 250;
- break;
- case LCD_PANEL_ID7_1366X768:
- case LCD_PANEL_IDB_1360X768:
- offset = 212;
- break;
- default:
- offset = 140;
- break;
- }
-
- /* Offset for simultaneous */
- viafb_set_secondary_pitch(offset << 3);
- DEBUG_MSG(KERN_INFO "viafb_load_reg!!\n");
- viafb_load_fetch_count_reg(set_hres, 4, IGA2);
- /* Fetch count for simultaneous */
- } else { /* SAMM */
- /* Fetch count for IGA2 only */
- viafb_load_fetch_count_reg(set_hres, mode_bpp / 8, set_iga);
-
- if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266)
- && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400))
- viafb_load_FIFO_reg(set_iga, set_hres, set_vres);
+ /* Fetch count for IGA2 only */
+ viafb_load_fetch_count_reg(set_hres, mode_bpp / 8, set_iga);
- viafb_set_color_depth(mode_bpp / 8, set_iga);
- }
+ if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266)
+ && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400))
+ viafb_load_FIFO_reg(set_iga, set_hres, set_vres);
fill_lcd_format();
@@ -1065,11 +683,6 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
|| (UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name))
viafb_write_reg_mask(CR6A, VIACR, 0x01, BIT0);
- load_lcd_patch_regs(set_hres, set_vres,
- plvds_setting_info->lcd_panel_id, set_iga);
-
- DEBUG_MSG(KERN_INFO "load_lcd_patch_regs!!\n");
-
/* Patch for non 32bit alignment mode */
via_pitch_alignment_patch_lcd(plvds_setting_info, plvds_chip_info);
}
@@ -1283,8 +896,7 @@ void viafb_lcd_enable(void)
viafb_write_reg_mask(CR6A, VIACR, 0x48, 0x48);
}
- if ((viaparinfo->lvds_setting_info->iga_path == IGA1)
- || (viaparinfo->lvds_setting_info->iga_path == IGA1_IGA2)) {
+ if (viaparinfo->lvds_setting_info->iga_path == IGA1) {
/* CRT path set to IGA2 */
viafb_write_reg_mask(SR16, VIASR, 0x40, 0x40);
/* IGA2 path disabled */
@@ -1476,210 +1088,6 @@ static struct display_timing lcd_centering_timging(struct display_timing
return crt_reg;
}
-static void load_crtc_shadow_timing(struct display_timing mode_timing,
- struct display_timing panel_timing)
-{
- struct io_register *reg = NULL;
- int i;
- int viafb_load_reg_Num = 0;
- int reg_value = 0;
-
- if (viaparinfo->lvds_setting_info->display_method == LCD_EXPANDSION) {
- /* Expansion */
- for (i = 12; i < 20; i++) {
- switch (i) {
- case H_TOTAL_SHADOW_INDEX:
- reg_value =
- IGA2_HOR_TOTAL_SHADOW_FORMULA
- (panel_timing.hor_total);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.hor_total_shadow.
- reg_num;
- reg = iga2_shadow_crtc_reg.hor_total_shadow.reg;
- break;
- case H_BLANK_END_SHADOW_INDEX:
- reg_value =
- IGA2_HOR_BLANK_END_SHADOW_FORMULA
- (panel_timing.hor_blank_start,
- panel_timing.hor_blank_end);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.
- hor_blank_end_shadow.reg_num;
- reg =
- iga2_shadow_crtc_reg.
- hor_blank_end_shadow.reg;
- break;
- case V_TOTAL_SHADOW_INDEX:
- reg_value =
- IGA2_VER_TOTAL_SHADOW_FORMULA
- (panel_timing.ver_total);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.ver_total_shadow.
- reg_num;
- reg = iga2_shadow_crtc_reg.ver_total_shadow.reg;
- break;
- case V_ADDR_SHADOW_INDEX:
- reg_value =
- IGA2_VER_ADDR_SHADOW_FORMULA
- (panel_timing.ver_addr);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.ver_addr_shadow.
- reg_num;
- reg = iga2_shadow_crtc_reg.ver_addr_shadow.reg;
- break;
- case V_BLANK_SATRT_SHADOW_INDEX:
- reg_value =
- IGA2_VER_BLANK_START_SHADOW_FORMULA
- (panel_timing.ver_blank_start);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.
- ver_blank_start_shadow.reg_num;
- reg =
- iga2_shadow_crtc_reg.
- ver_blank_start_shadow.reg;
- break;
- case V_BLANK_END_SHADOW_INDEX:
- reg_value =
- IGA2_VER_BLANK_END_SHADOW_FORMULA
- (panel_timing.ver_blank_start,
- panel_timing.ver_blank_end);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.
- ver_blank_end_shadow.reg_num;
- reg =
- iga2_shadow_crtc_reg.
- ver_blank_end_shadow.reg;
- break;
- case V_SYNC_SATRT_SHADOW_INDEX:
- reg_value =
- IGA2_VER_SYNC_START_SHADOW_FORMULA
- (panel_timing.ver_sync_start);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.
- ver_sync_start_shadow.reg_num;
- reg =
- iga2_shadow_crtc_reg.
- ver_sync_start_shadow.reg;
- break;
- case V_SYNC_END_SHADOW_INDEX:
- reg_value =
- IGA2_VER_SYNC_END_SHADOW_FORMULA
- (panel_timing.ver_sync_start,
- panel_timing.ver_sync_end);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.
- ver_sync_end_shadow.reg_num;
- reg =
- iga2_shadow_crtc_reg.
- ver_sync_end_shadow.reg;
- break;
- }
- viafb_load_reg(reg_value,
- viafb_load_reg_Num, reg, VIACR);
- }
- } else { /* Centering */
- for (i = 12; i < 20; i++) {
- switch (i) {
- case H_TOTAL_SHADOW_INDEX:
- reg_value =
- IGA2_HOR_TOTAL_SHADOW_FORMULA
- (panel_timing.hor_total);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.hor_total_shadow.
- reg_num;
- reg = iga2_shadow_crtc_reg.hor_total_shadow.reg;
- break;
- case H_BLANK_END_SHADOW_INDEX:
- reg_value =
- IGA2_HOR_BLANK_END_SHADOW_FORMULA
- (panel_timing.hor_blank_start,
- panel_timing.hor_blank_end);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.
- hor_blank_end_shadow.reg_num;
- reg =
- iga2_shadow_crtc_reg.
- hor_blank_end_shadow.reg;
- break;
- case V_TOTAL_SHADOW_INDEX:
- reg_value =
- IGA2_VER_TOTAL_SHADOW_FORMULA
- (panel_timing.ver_total);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.ver_total_shadow.
- reg_num;
- reg = iga2_shadow_crtc_reg.ver_total_shadow.reg;
- break;
- case V_ADDR_SHADOW_INDEX:
- reg_value =
- IGA2_VER_ADDR_SHADOW_FORMULA
- (mode_timing.ver_addr);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.ver_addr_shadow.
- reg_num;
- reg = iga2_shadow_crtc_reg.ver_addr_shadow.reg;
- break;
- case V_BLANK_SATRT_SHADOW_INDEX:
- reg_value =
- IGA2_VER_BLANK_START_SHADOW_FORMULA
- (mode_timing.ver_blank_start);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.
- ver_blank_start_shadow.reg_num;
- reg =
- iga2_shadow_crtc_reg.
- ver_blank_start_shadow.reg;
- break;
- case V_BLANK_END_SHADOW_INDEX:
- reg_value =
- IGA2_VER_BLANK_END_SHADOW_FORMULA
- (panel_timing.ver_blank_start,
- panel_timing.ver_blank_end);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.
- ver_blank_end_shadow.reg_num;
- reg =
- iga2_shadow_crtc_reg.
- ver_blank_end_shadow.reg;
- break;
- case V_SYNC_SATRT_SHADOW_INDEX:
- reg_value =
- IGA2_VER_SYNC_START_SHADOW_FORMULA(
- (panel_timing.ver_sync_start -
- panel_timing.ver_blank_start) +
- (panel_timing.ver_addr -
- mode_timing.ver_addr) / 2 +
- mode_timing.ver_addr);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.ver_sync_start_shadow.
- reg_num;
- reg =
- iga2_shadow_crtc_reg.ver_sync_start_shadow.
- reg;
- break;
- case V_SYNC_END_SHADOW_INDEX:
- reg_value =
- IGA2_VER_SYNC_END_SHADOW_FORMULA(
- (panel_timing.ver_sync_start -
- panel_timing.ver_blank_start) +
- (panel_timing.ver_addr -
- mode_timing.ver_addr) / 2 +
- mode_timing.ver_addr,
- panel_timing.ver_sync_end);
- viafb_load_reg_Num =
- iga2_shadow_crtc_reg.ver_sync_end_shadow.
- reg_num;
- reg =
- iga2_shadow_crtc_reg.ver_sync_end_shadow.
- reg;
- break;
- }
- viafb_load_reg(reg_value,
- viafb_load_reg_Num, reg, VIACR);
- }
- }
-}
-
bool viafb_lcd_get_mobile_state(bool *mobile)
{
unsigned char *romptr, *tableptr;
diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h
index 7cd03e2a1275..d55aaa7b912c 100644
--- a/drivers/video/via/share.h
+++ b/drivers/video/via/share.h
@@ -43,61 +43,6 @@
/* Video Memory Size */
#define VIDEO_MEMORY_SIZE_16M 0x1000000
-/* Definition Mode Index
-*/
-#define VIA_RES_640X480 0
-#define VIA_RES_800X600 1
-#define VIA_RES_1024X768 2
-#define VIA_RES_1152X864 3
-#define VIA_RES_1280X1024 4
-#define VIA_RES_1600X1200 5
-#define VIA_RES_1440X1050 6
-#define VIA_RES_1280X768 7
-#define VIA_RES_1280X960 8
-#define VIA_RES_1920X1440 9
-#define VIA_RES_848X480 10
-#define VIA_RES_1400X1050 11
-#define VIA_RES_720X480 12
-#define VIA_RES_720X576 13
-#define VIA_RES_1024X512 14
-#define VIA_RES_856X480 15
-#define VIA_RES_1024X576 16
-#define VIA_RES_640X400 17
-#define VIA_RES_1280X720 18
-#define VIA_RES_1920X1080 19
-#define VIA_RES_800X480 20
-#define VIA_RES_1368X768 21
-#define VIA_RES_1024X600 22
-#define VIA_RES_1280X800 23
-#define VIA_RES_1680X1050 24
-#define VIA_RES_960X600 25
-#define VIA_RES_1000X600 26
-#define VIA_RES_1088X612 27
-#define VIA_RES_1152X720 28
-#define VIA_RES_1200X720 29
-#define VIA_RES_1280X600 30
-#define VIA_RES_1360X768 31
-#define VIA_RES_1366X768 32
-#define VIA_RES_1440X900 33
-#define VIA_RES_1600X900 34
-#define VIA_RES_1600X1024 35
-#define VIA_RES_1792X1344 36
-#define VIA_RES_1856X1392 37
-#define VIA_RES_1920X1200 38
-#define VIA_RES_2048X1536 39
-#define VIA_RES_480X640 40
-
-/*Reduce Blanking*/
-#define VIA_RES_1360X768_RB 131
-#define VIA_RES_1440X900_RB 133
-#define VIA_RES_1400X1050_RB 111
-#define VIA_RES_1600X900_RB 134
-#define VIA_RES_1680X1050_RB 124
-#define VIA_RES_1920X1080_RB 119
-#define VIA_RES_1920X1200_RB 138
-
-#define VIA_RES_INVALID 255
-
/* standard VGA IO port
*/
#define VIARMisc 0x3CC
@@ -118,7 +63,6 @@
/* Display path */
#define IGA1 1
#define IGA2 2
-#define IGA1_IGA2 3
/* Define Color Depth */
#define MODE_8BPP 1
diff --git a/drivers/video/via/via_utility.c b/drivers/video/via/via_utility.c
index d53c3d54ed8e..aefdeeec89b1 100644
--- a/drivers/video/via/via_utility.c
+++ b/drivers/video/via/via_utility.c
@@ -239,15 +239,3 @@ void viafb_get_gamma_support_state(int bpp, unsigned int *support_state)
else
*support_state = CRT_Device | DVI_Device | LCD_Device;
}
-
-int viafb_input_parameter_converter(int parameter_value)
-{
- int result;
-
- if (parameter_value >= 1 && parameter_value <= 9)
- result = 1 << (parameter_value - 1);
- else
- result = 1;
-
- return result;
-}
diff --git a/drivers/video/via/via_utility.h b/drivers/video/via/via_utility.h
index 2fd455202ebd..1670ba82143f 100644
--- a/drivers/video/via/via_utility.h
+++ b/drivers/video/via/via_utility.h
@@ -30,6 +30,5 @@ bool viafb_lcd_get_support_expand_state(u32 xres, u32 yres);
void viafb_set_gamma_table(int bpp, unsigned int *gamma_table);
void viafb_get_gamma_table(unsigned int *gamma_table);
void viafb_get_gamma_support_state(int bpp, unsigned int *support_state);
-int viafb_input_parameter_converter(int parameter_value);
#endif /* __VIAUTILITY_H__ */
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index d8df17a7d5fc..ce7783b63f6a 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -26,18 +26,22 @@
#include "global.h"
-static struct fb_var_screeninfo default_var;
static char *viafb_name = "Via";
static u32 pseudo_pal[17];
/* video mode */
-static char *viafb_mode = "640x480";
-static char *viafb_mode1 = "640x480";
+static char *viafb_mode;
+static char *viafb_mode1;
+static int viafb_bpp = 32;
+static int viafb_bpp1 = 32;
+
+static unsigned int viafb_second_offset;
+static int viafb_second_size;
static int viafb_accel = 1;
/* Added for specifying active devices.*/
-char *viafb_active_dev = "";
+char *viafb_active_dev;
/*Added for specify lcd output port*/
char *viafb_lcd_port = "";
@@ -50,18 +54,78 @@ static void apply_second_mode_setting(struct fb_var_screeninfo
*sec_var);
static void retrieve_device_setting(struct viafb_ioctl_setting
*setting_info);
+static int viafb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info);
static struct fb_ops viafb_ops;
+static void viafb_fill_var_color_info(struct fb_var_screeninfo *var, u8 depth)
+{
+ var->grayscale = 0;
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
+ var->nonstd = 0;
+ switch (depth) {
+ case 8:
+ var->bits_per_pixel = 8;
+ var->red.offset = 0;
+ var->green.offset = 0;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ break;
+ case 15:
+ var->bits_per_pixel = 16;
+ var->red.offset = 10;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 5;
+ var->blue.length = 5;
+ break;
+ case 16:
+ var->bits_per_pixel = 16;
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ break;
+ case 24:
+ var->bits_per_pixel = 32;
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ break;
+ case 30:
+ var->bits_per_pixel = 32;
+ var->red.offset = 20;
+ var->green.offset = 10;
+ var->blue.offset = 0;
+ var->red.length = 10;
+ var->green.length = 10;
+ var->blue.length = 10;
+ break;
+ }
+}
+
static void viafb_update_fix(struct fb_info *info)
{
u32 bpp = info->var.bits_per_pixel;
info->fix.visual =
bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
- info->fix.line_length =
- ((info->var.xres_virtual + 7) & ~7) * bpp / 8;
+ info->fix.line_length = (info->var.xres_virtual * bpp / 8 + 7) & ~7;
}
static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
@@ -75,6 +139,7 @@ static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
fix->type = FB_TYPE_PACKED_PIXELS;
fix->type_aux = 0;
+ fix->visual = FB_VISUAL_TRUECOLOR;
fix->xpanstep = fix->ywrapstep = 0;
fix->ypanstep = 1;
@@ -97,9 +162,10 @@ static int viafb_release(struct fb_info *info, int user)
static int viafb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
- int vmode_index, htotal, vtotal;
+ int htotal, vtotal, depth;
+ struct VideoModeTable *vmode_entry;
struct viafb_par *ppar = info->par;
- u32 long_refresh;
+ u32 long_refresh, line;
DEBUG_MSG(KERN_INFO "viafb_check_var!\n");
/* Sanity check */
@@ -107,26 +173,36 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
if (var->vmode & FB_VMODE_INTERLACED || var->vmode & FB_VMODE_DOUBLE)
return -EINVAL;
- vmode_index = viafb_get_mode_index(var->xres, var->yres);
- if (vmode_index == VIA_RES_INVALID) {
+ vmode_entry = viafb_get_mode(var->xres, var->yres);
+ if (!vmode_entry) {
DEBUG_MSG(KERN_INFO
"viafb: Mode %dx%dx%d not supported!!\n",
var->xres, var->yres, var->bits_per_pixel);
return -EINVAL;
}
- if (24 == var->bits_per_pixel)
- var->bits_per_pixel = 32;
+ depth = fb_get_color_depth(var, &info->fix);
+ if (!depth)
+ depth = var->bits_per_pixel;
- if (var->bits_per_pixel != 8 && var->bits_per_pixel != 16 &&
- var->bits_per_pixel != 32)
+ if (depth < 0 || depth > 32)
return -EINVAL;
+ else if (!depth)
+ depth = 24;
+ else if (depth == 15 && viafb_dual_fb && ppar->iga_path == IGA1)
+ depth = 15;
+ else if (depth == 30)
+ depth = 30;
+ else if (depth <= 8)
+ depth = 8;
+ else if (depth <= 16)
+ depth = 16;
+ else
+ depth = 24;
- if ((var->xres_virtual * (var->bits_per_pixel >> 3)) & 0x1F)
- /*32 pixel alignment */
- var->xres_virtual = (var->xres_virtual + 31) & ~31;
- if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
- ppar->memsize)
+ viafb_fill_var_color_info(var, depth);
+ line = (var->xres_virtual * var->bits_per_pixel / 8 + 7) & ~7;
+ if (line * var->yres_virtual > ppar->memsize)
return -EINVAL;
/* Based on var passed in to calculate the refresh,
@@ -142,7 +218,7 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
viafb_refresh = viafb_get_refresh(var->xres, var->yres, long_refresh);
/* Adjust var according to our driver's own table */
- viafb_fill_var_timing_info(var, viafb_refresh, vmode_index);
+ viafb_fill_var_timing_info(var, viafb_refresh, vmode_entry);
if (info->var.accel_flags & FB_ACCELF_TEXT &&
!ppar->shared->engine_mmio)
info->var.accel_flags = 0;
@@ -153,40 +229,45 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
static int viafb_set_par(struct fb_info *info)
{
struct viafb_par *viapar = info->par;
- int vmode_index;
- int vmode_index1 = 0;
+ struct VideoModeTable *vmode_entry, *vmode_entry1 = NULL;
DEBUG_MSG(KERN_INFO "viafb_set_par!\n");
viapar->depth = fb_get_color_depth(&info->var, &info->fix);
- viafb_update_device_setting(info->var.xres, info->var.yres,
- info->var.bits_per_pixel, viafb_refresh, 0);
+ viafb_update_device_setting(viafbinfo->var.xres, viafbinfo->var.yres,
+ viafbinfo->var.bits_per_pixel, viafb_refresh, 0);
- vmode_index = viafb_get_mode_index(info->var.xres, info->var.yres);
-
- if (viafb_SAMM_ON == 1) {
+ vmode_entry = viafb_get_mode(viafbinfo->var.xres, viafbinfo->var.yres);
+ if (viafb_dual_fb) {
+ vmode_entry1 = viafb_get_mode(viafbinfo1->var.xres,
+ viafbinfo1->var.yres);
+ viafb_update_device_setting(viafbinfo1->var.xres,
+ viafbinfo1->var.yres, viafbinfo1->var.bits_per_pixel,
+ viafb_refresh1, 1);
+ } else if (viafb_SAMM_ON == 1) {
DEBUG_MSG(KERN_INFO
"viafb_second_xres = %d, viafb_second_yres = %d, bpp = %d\n",
viafb_second_xres, viafb_second_yres, viafb_bpp1);
- vmode_index1 = viafb_get_mode_index(viafb_second_xres,
+ vmode_entry1 = viafb_get_mode(viafb_second_xres,
viafb_second_yres);
- DEBUG_MSG(KERN_INFO "->viafb_SAMM_ON: index=%d\n",
- vmode_index1);
viafb_update_device_setting(viafb_second_xres,
viafb_second_yres, viafb_bpp1, viafb_refresh1, 1);
}
- if (vmode_index != VIA_RES_INVALID) {
- viafb_setmode(vmode_index, info->var.xres, info->var.yres,
- info->var.bits_per_pixel, vmode_index1,
- viafb_second_xres, viafb_second_yres, viafb_bpp1);
-
+ if (vmode_entry) {
viafb_update_fix(info);
- viafb_bpp = info->var.bits_per_pixel;
+ if (viafb_dual_fb && viapar->iga_path == IGA2)
+ viafb_bpp1 = info->var.bits_per_pixel;
+ else
+ viafb_bpp = info->var.bits_per_pixel;
+
if (info->var.accel_flags & FB_ACCELF_TEXT)
info->flags &= ~FBINFO_HWACCEL_DISABLED;
else
info->flags |= FBINFO_HWACCEL_DISABLED;
+ viafb_setmode(vmode_entry, info->var.bits_per_pixel,
+ vmode_entry1, viafb_bpp1);
+ viafb_pan_display(&info->var, info);
}
return 0;
@@ -196,234 +277,52 @@ static int viafb_set_par(struct fb_info *info)
static int viafb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info)
{
- u8 sr1a, sr1b, cr67, cr6a, rev = 0, shift = 10;
- unsigned cmap_entries = (info->var.bits_per_pixel == 8) ? 256 : 16;
- DEBUG_MSG(KERN_INFO "viafb_setcolreg!\n");
- if (regno >= cmap_entries)
- return 1;
- if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name) {
- /*
- * Read PCI bus 0,dev 0,function 0,index 0xF6 to get chip rev.
- */
- outl(0x80000000 | (0xf6 & ~3), (unsigned long)0xCF8);
- rev = (inl((unsigned long)0xCFC) >> ((0xf6 & 3) * 8)) & 0xff;
- }
- switch (info->var.bits_per_pixel) {
- case 8:
- outb(0x1A, 0x3C4);
- sr1a = inb(0x3C5);
- outb(0x1B, 0x3C4);
- sr1b = inb(0x3C5);
- outb(0x67, 0x3D4);
- cr67 = inb(0x3D5);
- outb(0x6A, 0x3D4);
- cr6a = inb(0x3D5);
-
- /* Map the 3C6/7/8/9 to the IGA2 */
- outb(0x1A, 0x3C4);
- outb(sr1a | 0x01, 0x3C5);
- /* Second Display Engine colck always on */
- outb(0x1B, 0x3C4);
- outb(sr1b | 0x80, 0x3C5);
- /* Second Display Color Depth 8 */
- outb(0x67, 0x3D4);
- outb(cr67 & 0x3F, 0x3D5);
- outb(0x6A, 0x3D4);
- /* Second Display Channel Reset CR6A[6]) */
- outb(cr6a & 0xBF, 0x3D5);
- /* Second Display Channel Enable CR6A[7] */
- outb(cr6a | 0x80, 0x3D5);
- /* Second Display Channel stop reset) */
- outb(cr6a | 0x40, 0x3D5);
-
- /* Bit mask of palette */
- outb(0xFF, 0x3c6);
- /* Write one register of IGA2 */
- outb(regno, 0x3C8);
- if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name &&
- rev >= 15) {
- shift = 8;
- viafb_write_reg_mask(CR6A, VIACR, BIT5, BIT5);
- viafb_write_reg_mask(SR15, VIASR, BIT7, BIT7);
- } else {
- shift = 10;
- viafb_write_reg_mask(CR6A, VIACR, 0, BIT5);
- viafb_write_reg_mask(SR15, VIASR, 0, BIT7);
- }
- outb(red >> shift, 0x3C9);
- outb(green >> shift, 0x3C9);
- outb(blue >> shift, 0x3C9);
-
- /* Map the 3C6/7/8/9 to the IGA1 */
- outb(0x1A, 0x3C4);
- outb(sr1a & 0xFE, 0x3C5);
- /* Bit mask of palette */
- outb(0xFF, 0x3c6);
- /* Write one register of IGA1 */
- outb(regno, 0x3C8);
- outb(red >> shift, 0x3C9);
- outb(green >> shift, 0x3C9);
- outb(blue >> shift, 0x3C9);
-
- outb(0x1A, 0x3C4);
- outb(sr1a, 0x3C5);
- outb(0x1B, 0x3C4);
- outb(sr1b, 0x3C5);
- outb(0x67, 0x3D4);
- outb(cr67, 0x3D5);
- outb(0x6A, 0x3D4);
- outb(cr6a, 0x3D5);
- break;
- case 16:
- ((u32 *) info->pseudo_palette)[regno] = (red & 0xF800) |
- ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
- break;
- case 32:
- ((u32 *) info->pseudo_palette)[regno] =
- ((transp & 0xFF00) << 16) |
- ((red & 0xFF00) << 8) |
- ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
- break;
- }
-
- return 0;
+ struct viafb_par *viapar = info->par;
+ u32 r, g, b;
-}
+ if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
+ if (regno > 255)
+ return -EINVAL;
-/*CALLED BY: fb_set_cmap */
-/* fb_set_var, pass 256 colors */
-/*CALLED BY: fb_set_cmap */
-/* fbcon_set_palette, pass 16 colors */
-static int viafb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
-{
- u32 len = cmap->len;
- u32 i;
- u16 *pred = cmap->red;
- u16 *pgreen = cmap->green;
- u16 *pblue = cmap->blue;
- u16 *ptransp = cmap->transp;
- u8 sr1a, sr1b, cr67, cr6a, rev = 0, shift = 10;
- if (len > 256)
- return 1;
- if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name) {
- /*
- * Read PCI bus 0, dev 0, function 0, index 0xF6 to get chip
- * rev.
- */
- outl(0x80000000 | (0xf6 & ~3), (unsigned long)0xCF8);
- rev = (inl((unsigned long)0xCFC) >> ((0xf6 & 3) * 8)) & 0xff;
- }
- switch (info->var.bits_per_pixel) {
- case 8:
- outb(0x1A, 0x3C4);
- sr1a = inb(0x3C5);
- outb(0x1B, 0x3C4);
- sr1b = inb(0x3C5);
- outb(0x67, 0x3D4);
- cr67 = inb(0x3D5);
- outb(0x6A, 0x3D4);
- cr6a = inb(0x3D5);
- /* Map the 3C6/7/8/9 to the IGA2 */
- outb(0x1A, 0x3C4);
- outb(sr1a | 0x01, 0x3C5);
- outb(0x1B, 0x3C4);
- /* Second Display Engine colck always on */
- outb(sr1b | 0x80, 0x3C5);
- outb(0x67, 0x3D4);
- /* Second Display Color Depth 8 */
- outb(cr67 & 0x3F, 0x3D5);
- outb(0x6A, 0x3D4);
- /* Second Display Channel Reset CR6A[6]) */
- outb(cr6a & 0xBF, 0x3D5);
- /* Second Display Channel Enable CR6A[7] */
- outb(cr6a | 0x80, 0x3D5);
- /* Second Display Channel stop reset) */
- outb(cr6a | 0xC0, 0x3D5);
-
- /* Bit mask of palette */
- outb(0xFF, 0x3c6);
- outb(0x00, 0x3C8);
- if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name &&
- rev >= 15) {
- shift = 8;
- viafb_write_reg_mask(CR6A, VIACR, BIT5, BIT5);
- viafb_write_reg_mask(SR15, VIASR, BIT7, BIT7);
- } else {
- shift = 10;
- viafb_write_reg_mask(CR6A, VIACR, 0, BIT5);
- viafb_write_reg_mask(SR15, VIASR, 0, BIT7);
- }
- for (i = 0; i < len; i++) {
- outb((*(pred + i)) >> shift, 0x3C9);
- outb((*(pgreen + i)) >> shift, 0x3C9);
- outb((*(pblue + i)) >> shift, 0x3C9);
- }
+ if (!viafb_dual_fb || viapar->iga_path == IGA1)
+ viafb_set_primary_color_register(regno, red >> 8,
+ green >> 8, blue >> 8);
- outb(0x1A, 0x3C4);
- /* Map the 3C6/7/8/9 to the IGA1 */
- outb(sr1a & 0xFE, 0x3C5);
- /* Bit mask of palette */
- outb(0xFF, 0x3c6);
- outb(0x00, 0x3C8);
- for (i = 0; i < len; i++) {
- outb((*(pred + i)) >> shift, 0x3C9);
- outb((*(pgreen + i)) >> shift, 0x3C9);
- outb((*(pblue + i)) >> shift, 0x3C9);
- }
+ if (!viafb_dual_fb || viapar->iga_path == IGA2)
+ viafb_set_secondary_color_register(regno, red >> 8,
+ green >> 8, blue >> 8);
+ } else {
+ if (regno > 15)
+ return -EINVAL;
- outb(0x1A, 0x3C4);
- outb(sr1a, 0x3C5);
- outb(0x1B, 0x3C4);
- outb(sr1b, 0x3C5);
- outb(0x67, 0x3D4);
- outb(cr67, 0x3D5);
- outb(0x6A, 0x3D4);
- outb(cr6a, 0x3D5);
- break;
- case 16:
- if (len > 17)
- return 0; /* Because static u32 pseudo_pal[17]; */
- for (i = 0; i < len; i++)
- ((u32 *) info->pseudo_palette)[i] =
- (*(pred + i) & 0xF800) |
- ((*(pgreen + i) & 0xFC00) >> 5) |
- ((*(pblue + i) & 0xF800) >> 11);
- break;
- case 32:
- if (len > 17)
- return 0;
- if (ptransp) {
- for (i = 0; i < len; i++)
- ((u32 *) info->pseudo_palette)[i] =
- ((*(ptransp + i) & 0xFF00) << 16) |
- ((*(pred + i) & 0xFF00) << 8) |
- ((*(pgreen + i) & 0xFF00)) |
- ((*(pblue + i) & 0xFF00) >> 8);
- } else {
- for (i = 0; i < len; i++)
- ((u32 *) info->pseudo_palette)[i] =
- 0x00000000 |
- ((*(pred + i) & 0xFF00) << 8) |
- ((*(pgreen + i) & 0xFF00)) |
- ((*(pblue + i) & 0xFF00) >> 8);
- }
- break;
+ r = (red >> (16 - info->var.red.length))
+ << info->var.red.offset;
+ b = (blue >> (16 - info->var.blue.length))
+ << info->var.blue.offset;
+ g = (green >> (16 - info->var.green.length))
+ << info->var.green.offset;
+ ((u32 *) info->pseudo_palette)[regno] = r | g | b;
}
+
return 0;
}
static int viafb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
- unsigned int offset;
-
- DEBUG_MSG(KERN_INFO "viafb_pan_display!\n");
-
- offset = (var->xoffset + (var->yoffset * var->xres_virtual)) *
- var->bits_per_pixel / 16;
+ struct viafb_par *viapar = info->par;
+ u32 vram_addr = (var->yoffset * var->xres_virtual + var->xoffset)
+ * (var->bits_per_pixel / 8) + viapar->vram_addr;
+
+ DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr);
+ if (!viafb_dual_fb) {
+ viafb_set_primary_address(vram_addr);
+ viafb_set_secondary_address(vram_addr);
+ } else if (viapar->iga_path == IGA1)
+ viafb_set_primary_address(vram_addr);
+ else
+ viafb_set_secondary_address(vram_addr);
- DEBUG_MSG(KERN_INFO "\nviafb_pan_display,offset =%d ", offset);
- viafb_set_primary_address(offset);
return 0;
}
@@ -477,6 +376,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
u32 gpu32;
DEBUG_MSG(KERN_INFO "viafb_ioctl: 0x%X !!\n", cmd);
+ printk(KERN_WARNING "viafb_ioctl: Please avoid this interface as it is unstable and might change or vanish at any time!\n");
memset(&u, 0, sizeof(u));
switch (cmd) {
@@ -872,7 +772,9 @@ static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
if (info->flags & FBINFO_HWACCEL_DISABLED || info != viafbinfo)
return -ENODEV;
- if (chip_name == UNICHROME_CLE266 && viapar->iga_path == IGA2)
+ /* LCD ouput does not support hw cursors (at least on VN896) */
+ if ((chip_name == UNICHROME_CLE266 && viapar->iga_path == IGA2) ||
+ viafb_LCD_ON)
return -ENODEV;
viafb_show_hw_cursor(info, HW_Cursor_OFF);
@@ -1014,23 +916,6 @@ static int viafb_sync(struct fb_info *info)
return 0;
}
-int viafb_get_mode_index(int hres, int vres)
-{
- u32 i;
- DEBUG_MSG(KERN_INFO "viafb_get_mode_index!\n");
-
- for (i = 0; i < NUM_TOTAL_MODETABLE; i++)
- if (CLE266Modes[i].mode_array &&
- CLE266Modes[i].crtc[0].crtc.hor_addr == hres &&
- CLE266Modes[i].crtc[0].crtc.ver_addr == vres)
- break;
-
- if (i == NUM_TOTAL_MODETABLE)
- return VIA_RES_INVALID;
-
- return CLE266Modes[i].ModeIndex;
-}
-
static void check_available_device_to_enable(int device_id)
{
int device_num = 0;
@@ -1329,7 +1214,7 @@ static void retrieve_device_setting(struct viafb_ioctl_setting
setting_info->lcd_attributes.lcd_mode = viafb_lcd_mode;
}
-static void parse_active_dev(void)
+static int parse_active_dev(void)
{
viafb_CRT_ON = STATE_OFF;
viafb_DVI_ON = STATE_OFF;
@@ -1340,60 +1225,63 @@ static void parse_active_dev(void)
IGA path to devices in SAMM case. */
/* Note: The previous of active_dev is primary device,
and the following is secondary device. */
- if (!strncmp(viafb_active_dev, "CRT+DVI", 7)) {
+ if (!viafb_active_dev) {
+ viafb_CRT_ON = STATE_ON;
+ viafb_SAMM_ON = STATE_OFF;
+ } else if (!strcmp(viafb_active_dev, "CRT+DVI")) {
/* CRT+DVI */
viafb_CRT_ON = STATE_ON;
viafb_DVI_ON = STATE_ON;
viafb_primary_dev = CRT_Device;
- } else if (!strncmp(viafb_active_dev, "DVI+CRT", 7)) {
+ } else if (!strcmp(viafb_active_dev, "DVI+CRT")) {
/* DVI+CRT */
viafb_CRT_ON = STATE_ON;
viafb_DVI_ON = STATE_ON;
viafb_primary_dev = DVI_Device;
- } else if (!strncmp(viafb_active_dev, "CRT+LCD", 7)) {
+ } else if (!strcmp(viafb_active_dev, "CRT+LCD")) {
/* CRT+LCD */
viafb_CRT_ON = STATE_ON;
viafb_LCD_ON = STATE_ON;
viafb_primary_dev = CRT_Device;
- } else if (!strncmp(viafb_active_dev, "LCD+CRT", 7)) {
+ } else if (!strcmp(viafb_active_dev, "LCD+CRT")) {
/* LCD+CRT */
viafb_CRT_ON = STATE_ON;
viafb_LCD_ON = STATE_ON;
viafb_primary_dev = LCD_Device;
- } else if (!strncmp(viafb_active_dev, "DVI+LCD", 7)) {
+ } else if (!strcmp(viafb_active_dev, "DVI+LCD")) {
/* DVI+LCD */
viafb_DVI_ON = STATE_ON;
viafb_LCD_ON = STATE_ON;
viafb_primary_dev = DVI_Device;
- } else if (!strncmp(viafb_active_dev, "LCD+DVI", 7)) {
+ } else if (!strcmp(viafb_active_dev, "LCD+DVI")) {
/* LCD+DVI */
viafb_DVI_ON = STATE_ON;
viafb_LCD_ON = STATE_ON;
viafb_primary_dev = LCD_Device;
- } else if (!strncmp(viafb_active_dev, "LCD+LCD2", 8)) {
+ } else if (!strcmp(viafb_active_dev, "LCD+LCD2")) {
viafb_LCD_ON = STATE_ON;
viafb_LCD2_ON = STATE_ON;
viafb_primary_dev = LCD_Device;
- } else if (!strncmp(viafb_active_dev, "LCD2+LCD", 8)) {
+ } else if (!strcmp(viafb_active_dev, "LCD2+LCD")) {
viafb_LCD_ON = STATE_ON;
viafb_LCD2_ON = STATE_ON;
viafb_primary_dev = LCD2_Device;
- } else if (!strncmp(viafb_active_dev, "CRT", 3)) {
+ } else if (!strcmp(viafb_active_dev, "CRT")) {
/* CRT only */
viafb_CRT_ON = STATE_ON;
viafb_SAMM_ON = STATE_OFF;
- } else if (!strncmp(viafb_active_dev, "DVI", 3)) {
+ } else if (!strcmp(viafb_active_dev, "DVI")) {
/* DVI only */
viafb_DVI_ON = STATE_ON;
viafb_SAMM_ON = STATE_OFF;
- } else if (!strncmp(viafb_active_dev, "LCD", 3)) {
+ } else if (!strcmp(viafb_active_dev, "LCD")) {
/* LCD only */
viafb_LCD_ON = STATE_ON;
viafb_SAMM_ON = STATE_OFF;
- } else {
- viafb_CRT_ON = STATE_ON;
- viafb_SAMM_ON = STATE_OFF;
- }
+ } else
+ return -EINVAL;
+
+ return 0;
}
static int parse_port(char *opt_str, int *output_interface)
@@ -1822,35 +1710,37 @@ static void viafb_remove_proc(struct proc_dir_entry *viafb_entry)
remove_proc_entry("viafb", NULL);
}
-static void parse_mode(const char *str, u32 *xres, u32 *yres)
+static int parse_mode(const char *str, u32 *xres, u32 *yres)
{
char *ptr;
+ if (!str) {
+ *xres = 640;
+ *yres = 480;
+ return 0;
+ }
+
*xres = simple_strtoul(str, &ptr, 10);
if (ptr[0] != 'x')
- goto out_default;
+ return -EINVAL;
*yres = simple_strtoul(&ptr[1], &ptr, 10);
if (ptr[0])
- goto out_default;
-
- return;
+ return -EINVAL;
-out_default:
- printk(KERN_WARNING "viafb received invalid mode string: %s\n", str);
- *xres = 640;
- *yres = 480;
+ return 0;
}
static int __devinit via_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
u32 default_xres, default_yres;
- int vmode_index;
+ struct VideoModeTable *vmode_entry;
+ struct fb_var_screeninfo default_var;
u32 viafb_par_length;
DEBUG_MSG(KERN_INFO "VIAFB PCI Probe!!\n");
-
+ memset(&default_var, 0, sizeof(default_var));
viafb_par_length = ALIGN(sizeof(struct viafb_par), BITS_PER_LONG/8);
/* Allocate fb_info and ***_par here, also including some other needed
@@ -1876,7 +1766,6 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
if (viafb_dual_fb)
viafb_SAMM_ON = 1;
- parse_active_dev();
parse_lcd_port();
parse_dvi_port();
@@ -1925,9 +1814,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
}
parse_mode(viafb_mode, &default_xres, &default_yres);
- vmode_index = viafb_get_mode_index(default_xres, default_yres);
- DEBUG_MSG(KERN_INFO "0->index=%d\n", vmode_index);
-
+ vmode_entry = viafb_get_mode(default_xres, default_yres);
if (viafb_SAMM_ON == 1) {
parse_mode(viafb_mode1, &viafb_second_xres,
&viafb_second_yres);
@@ -1946,19 +1833,6 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
viafb_second_virtual_yres = viafb_second_yres;
}
- switch (viafb_bpp) {
- case 0 ... 8:
- viafb_bpp = 8;
- break;
- case 9 ... 16:
- viafb_bpp = 16;
- break;
- case 17 ... 32:
- viafb_bpp = 32;
- break;
- default:
- viafb_bpp = 8;
- }
default_var.xres = default_xres;
default_var.yres = default_yres;
switch (default_xres) {
@@ -1971,8 +1845,6 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
}
default_var.yres_virtual = default_yres;
default_var.bits_per_pixel = viafb_bpp;
- if (default_var.bits_per_pixel == 15)
- default_var.bits_per_pixel = 16;
default_var.pixclock =
viafb_get_pixclock(default_xres, default_yres, viafb_refresh);
default_var.left_margin = (default_xres >> 3) & 0xf8;
@@ -1981,6 +1853,8 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
default_var.lower_margin = 4;
default_var.hsync_len = default_var.left_margin;
default_var.vsync_len = 4;
+ viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo);
+ viafbinfo->var = default_var;
if (viafb_dual_fb) {
viafbinfo1 = framebuffer_alloc(viafb_par_length, &pdev->dev);
@@ -2015,8 +1889,6 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
default_var.yres = viafb_second_yres;
default_var.xres_virtual = viafb_second_virtual_xres;
default_var.yres_virtual = viafb_second_virtual_yres;
- if (viafb_bpp1 != viafb_bpp)
- viafb_bpp1 = viafb_bpp;
default_var.bits_per_pixel = viafb_bpp1;
default_var.pixclock =
viafb_get_pixclock(viafb_second_xres, viafb_second_yres,
@@ -2036,9 +1908,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
&viafbinfo1->fix);
}
- viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo);
- viafb_check_var(&default_var, viafbinfo);
- viafbinfo->var = default_var;
+ viafb_check_var(&viafbinfo->var, viafbinfo);
viafb_update_fix(viafbinfo);
viaparinfo->depth = fb_get_color_depth(&viafbinfo->var,
&viafbinfo->fix);
@@ -2196,12 +2066,20 @@ static struct pci_driver viafb_driver = {
static int __init viafb_init(void)
{
+ u32 dummy;
#ifndef MODULE
char *option = NULL;
if (fb_get_options("viafb", &option))
return -ENODEV;
viafb_setup(option);
#endif
+ if (parse_mode(viafb_mode, &dummy, &dummy)
+ || parse_mode(viafb_mode1, &dummy, &dummy)
+ || viafb_bpp < 0 || viafb_bpp > 32
+ || viafb_bpp1 < 0 || viafb_bpp1 > 32
+ || parse_active_dev())
+ return -EINVAL;
+
printk(KERN_INFO
"VIA Graphics Intergration Chipset framebuffer %d.%d initializing\n",
VERSION_MAJOR, VERSION_MINOR);
@@ -2229,15 +2107,12 @@ static struct fb_ops viafb_ops = {
.fb_cursor = viafb_cursor,
.fb_ioctl = viafb_ioctl,
.fb_sync = viafb_sync,
- .fb_setcmap = viafb_setcmap,
};
module_init(viafb_init);
module_exit(viafb_exit);
#ifdef MODULE
-module_param(viafb_memsize, int, S_IRUSR);
-
module_param(viafb_mode, charp, S_IRUSR);
MODULE_PARM_DESC(viafb_mode, "Set resolution (default=640x480)");
diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h
index 0c94d2441922..61b5953cd159 100644
--- a/drivers/video/via/viafbdev.h
+++ b/drivers/video/via/viafbdev.h
@@ -83,22 +83,16 @@ struct viafb_par {
extern unsigned int viafb_second_virtual_yres;
extern unsigned int viafb_second_virtual_xres;
-extern unsigned int viafb_second_offset;
-extern int viafb_second_size;
extern int viafb_SAMM_ON;
extern int viafb_dual_fb;
extern int viafb_LCD2_ON;
extern int viafb_LCD_ON;
extern int viafb_DVI_ON;
extern int viafb_hotplug;
-extern int viafb_memsize;
extern int strict_strtoul(const char *cp, unsigned int base,
unsigned long *res);
-void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
- int mode_index);
-int viafb_get_mode_index(int hres, int vres);
u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
*plvds_setting_info, struct lvds_chip_information
*plvds_chip_info, u8 index);
diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c
index b74f8a67923c..af50e244016c 100644
--- a/drivers/video/via/viamode.c
+++ b/drivers/video/via/viamode.c
@@ -412,7 +412,7 @@ struct io_reg PM1024x768[] = { {VIASR, 0x16, 0xBF, 0x0C},
};
struct patch_table res_patch_table[] = {
- {VIA_RES_1024X768, ARRAY_SIZE(PM1024x768), PM1024x768}
+ {ARRAY_SIZE(PM1024x768), PM1024x768}
};
/* struct VPITTable {
@@ -879,169 +879,151 @@ struct crt_mode_table CRTM2048x1536[] = {
{2800, 2048, 2048, 752, 2200, 224, 1592, 1536, 1536, 56, 1539, 4} }
};
-/* Video Mode Table */
-/* struct VideoModeTable {*/
-/* int ModeIndex;*/
-/* struct crt_mode_table *crtc;*/
-/* int mode_array;*/
-/* };*/
-struct VideoModeTable CLE266Modes[] = {
+struct VideoModeTable viafb_modes[] = {
/* Display : 480x640 (GTF) */
- {VIA_RES_480X640, CRTM480x640, ARRAY_SIZE(CRTM480x640)},
+ {CRTM480x640, ARRAY_SIZE(CRTM480x640)},
/* Display : 640x480 */
- {VIA_RES_640X480, CRTM640x480, ARRAY_SIZE(CRTM640x480)},
+ {CRTM640x480, ARRAY_SIZE(CRTM640x480)},
/* Display : 720x480 (GTF) */
- {VIA_RES_720X480, CRTM720x480, ARRAY_SIZE(CRTM720x480)},
+ {CRTM720x480, ARRAY_SIZE(CRTM720x480)},
/* Display : 720x576 (GTF) */
- {VIA_RES_720X576, CRTM720x576, ARRAY_SIZE(CRTM720x576)},
+ {CRTM720x576, ARRAY_SIZE(CRTM720x576)},
/* Display : 800x600 */
- {VIA_RES_800X600, CRTM800x600, ARRAY_SIZE(CRTM800x600)},
+ {CRTM800x600, ARRAY_SIZE(CRTM800x600)},
/* Display : 800x480 (CVT) */
- {VIA_RES_800X480, CRTM800x480, ARRAY_SIZE(CRTM800x480)},
+ {CRTM800x480, ARRAY_SIZE(CRTM800x480)},
/* Display : 848x480 (CVT) */
- {VIA_RES_848X480, CRTM848x480, ARRAY_SIZE(CRTM848x480)},
+ {CRTM848x480, ARRAY_SIZE(CRTM848x480)},
/* Display : 852x480 (GTF) */
- {VIA_RES_856X480, CRTM852x480, ARRAY_SIZE(CRTM852x480)},
+ {CRTM852x480, ARRAY_SIZE(CRTM852x480)},
/* Display : 1024x512 (GTF) */
- {VIA_RES_1024X512, CRTM1024x512, ARRAY_SIZE(CRTM1024x512)},
+ {CRTM1024x512, ARRAY_SIZE(CRTM1024x512)},
/* Display : 1024x600 */
- {VIA_RES_1024X600, CRTM1024x600, ARRAY_SIZE(CRTM1024x600)},
-
- /* Display : 1024x576 (GTF) */
- /*{ VIA_RES_1024X576, CRTM1024x576, ARRAY_SIZE(CRTM1024x576)}, */
+ {CRTM1024x600, ARRAY_SIZE(CRTM1024x600)},
/* Display : 1024x768 */
- {VIA_RES_1024X768, CRTM1024x768, ARRAY_SIZE(CRTM1024x768)},
+ {CRTM1024x768, ARRAY_SIZE(CRTM1024x768)},
/* Display : 1152x864 */
- {VIA_RES_1152X864, CRTM1152x864, ARRAY_SIZE(CRTM1152x864)},
+ {CRTM1152x864, ARRAY_SIZE(CRTM1152x864)},
/* Display : 1280x768 (GTF) */
- {VIA_RES_1280X768, CRTM1280x768, ARRAY_SIZE(CRTM1280x768)},
+ {CRTM1280x768, ARRAY_SIZE(CRTM1280x768)},
/* Display : 960x600 (CVT) */
- {VIA_RES_960X600, CRTM960x600, ARRAY_SIZE(CRTM960x600)},
+ {CRTM960x600, ARRAY_SIZE(CRTM960x600)},
/* Display : 1000x600 (GTF) */
- {VIA_RES_1000X600, CRTM1000x600, ARRAY_SIZE(CRTM1000x600)},
+ {CRTM1000x600, ARRAY_SIZE(CRTM1000x600)},
/* Display : 1024x576 (GTF) */
- {VIA_RES_1024X576, CRTM1024x576, ARRAY_SIZE(CRTM1024x576)},
+ {CRTM1024x576, ARRAY_SIZE(CRTM1024x576)},
/* Display : 1088x612 (GTF) */
- {VIA_RES_1088X612, CRTM1088x612, ARRAY_SIZE(CRTM1088x612)},
+ {CRTM1088x612, ARRAY_SIZE(CRTM1088x612)},
/* Display : 1152x720 (CVT) */
- {VIA_RES_1152X720, CRTM1152x720, ARRAY_SIZE(CRTM1152x720)},
+ {CRTM1152x720, ARRAY_SIZE(CRTM1152x720)},
/* Display : 1200x720 (GTF) */
- {VIA_RES_1200X720, CRTM1200x720, ARRAY_SIZE(CRTM1200x720)},
+ {CRTM1200x720, ARRAY_SIZE(CRTM1200x720)},
/* Display : 1280x600 (GTF) */
- {VIA_RES_1280X600, CRTM1280x600, ARRAY_SIZE(CRTM1280x600)},
+ {CRTM1280x600, ARRAY_SIZE(CRTM1280x600)},
/* Display : 1280x800 (CVT) */
- {VIA_RES_1280X800, CRTM1280x800, ARRAY_SIZE(CRTM1280x800)},
-
- /* Display : 1280x800 (GTF) */
- /*{ M1280x800, CRTM1280x800, ARRAY_SIZE(CRTM1280x800)}, */
+ {CRTM1280x800, ARRAY_SIZE(CRTM1280x800)},
/* Display : 1280x960 */
- {VIA_RES_1280X960, CRTM1280x960, ARRAY_SIZE(CRTM1280x960)},
+ {CRTM1280x960, ARRAY_SIZE(CRTM1280x960)},
/* Display : 1280x1024 */
- {VIA_RES_1280X1024, CRTM1280x1024, ARRAY_SIZE(CRTM1280x1024)},
+ {CRTM1280x1024, ARRAY_SIZE(CRTM1280x1024)},
/* Display : 1360x768 (CVT) */
- {VIA_RES_1360X768, CRTM1360x768, ARRAY_SIZE(CRTM1360x768)},
-
- /* Display : 1360x768 (CVT Reduce Blanking) */
- {VIA_RES_1360X768_RB, CRTM1360x768_RB,
- ARRAY_SIZE(CRTM1360x768_RB)},
+ {CRTM1360x768, ARRAY_SIZE(CRTM1360x768)},
/* Display : 1366x768 */
- {VIA_RES_1366X768, CRTM1366x768, ARRAY_SIZE(CRTM1366x768)},
+ {CRTM1366x768, ARRAY_SIZE(CRTM1366x768)},
/* Display : 1368x768 (GTF) */
- /*{ M1368x768,CRTM1368x768,ARRAY_SIZE(CRTM1368x768)}, */
- /* Display : 1368x768 (GTF) */
- {VIA_RES_1368X768, CRTM1368x768, ARRAY_SIZE(CRTM1368x768)},
+ {CRTM1368x768, ARRAY_SIZE(CRTM1368x768)},
/* Display : 1440x900 (CVT) */
- {VIA_RES_1440X900, CRTM1440x900, ARRAY_SIZE(CRTM1440x900)},
-
- /* Display : 1440x900 (CVT Reduce Blanking) */
- {VIA_RES_1440X900_RB, CRTM1440x900_RB,
- ARRAY_SIZE(CRTM1440x900_RB)},
+ {CRTM1440x900, ARRAY_SIZE(CRTM1440x900)},
/* Display : 1440x1050 (GTF) */
- {VIA_RES_1440X1050, CRTM1440x1050, ARRAY_SIZE(CRTM1440x1050)},
-
- /* Display : 1400x1050 (CVT Reduce Blanking) */
- {VIA_RES_1400X1050_RB, CRTM1400x1050_RB,
- ARRAY_SIZE(CRTM1400x1050_RB)},
+ {CRTM1440x1050, ARRAY_SIZE(CRTM1440x1050)},
/* Display : 1600x900 (CVT) */
- {VIA_RES_1600X900, CRTM1600x900, ARRAY_SIZE(CRTM1600x900)},
-
- /* Display : 1600x900 (CVT Reduce Blanking) */
- {VIA_RES_1600X900_RB, CRTM1600x900_RB,
- ARRAY_SIZE(CRTM1600x900_RB)},
+ {CRTM1600x900, ARRAY_SIZE(CRTM1600x900)},
/* Display : 1600x1024 (GTF) */
- {VIA_RES_1600X1024, CRTM1600x1024, ARRAY_SIZE(CRTM1600x1024)},
+ {CRTM1600x1024, ARRAY_SIZE(CRTM1600x1024)},
/* Display : 1600x1200 */
- {VIA_RES_1600X1200, CRTM1600x1200, ARRAY_SIZE(CRTM1600x1200)},
+ {CRTM1600x1200, ARRAY_SIZE(CRTM1600x1200)},
/* Display : 1680x1050 (CVT) */
- {VIA_RES_1680X1050, CRTM1680x1050, ARRAY_SIZE(CRTM1680x1050)},
-
- /* Display : 1680x1050 (CVT Reduce Blanking) */
- {VIA_RES_1680X1050_RB, CRTM1680x1050_RB,
- ARRAY_SIZE(CRTM1680x1050_RB)},
+ {CRTM1680x1050, ARRAY_SIZE(CRTM1680x1050)},
/* Display : 1792x1344 (DMT) */
- {VIA_RES_1792X1344, CRTM1792x1344, ARRAY_SIZE(CRTM1792x1344)},
+ {CRTM1792x1344, ARRAY_SIZE(CRTM1792x1344)},
/* Display : 1856x1392 (DMT) */
- {VIA_RES_1856X1392, CRTM1856x1392, ARRAY_SIZE(CRTM1856x1392)},
+ {CRTM1856x1392, ARRAY_SIZE(CRTM1856x1392)},
/* Display : 1920x1440 */
- {VIA_RES_1920X1440, CRTM1920x1440, ARRAY_SIZE(CRTM1920x1440)},
+ {CRTM1920x1440, ARRAY_SIZE(CRTM1920x1440)},
/* Display : 2048x1536 */
- {VIA_RES_2048X1536, CRTM2048x1536, ARRAY_SIZE(CRTM2048x1536)},
+ {CRTM2048x1536, ARRAY_SIZE(CRTM2048x1536)},
/* Display : 1280x720 */
- {VIA_RES_1280X720, CRTM1280x720, ARRAY_SIZE(CRTM1280x720)},
+ {CRTM1280x720, ARRAY_SIZE(CRTM1280x720)},
/* Display : 1920x1080 (CVT) */
- {VIA_RES_1920X1080, CRTM1920x1080, ARRAY_SIZE(CRTM1920x1080)},
-
- /* Display : 1920x1080 (CVT Reduce Blanking) */
- {VIA_RES_1920X1080_RB, CRTM1920x1080_RB,
- ARRAY_SIZE(CRTM1920x1080_RB)},
+ {CRTM1920x1080, ARRAY_SIZE(CRTM1920x1080)},
/* Display : 1920x1200 (CVT) */
- {VIA_RES_1920X1200, CRTM1920x1200, ARRAY_SIZE(CRTM1920x1200)},
-
- /* Display : 1920x1200 (CVT Reduce Blanking) */
- {VIA_RES_1920X1200_RB, CRTM1920x1200_RB,
- ARRAY_SIZE(CRTM1920x1200_RB)},
+ {CRTM1920x1200, ARRAY_SIZE(CRTM1920x1200)},
/* Display : 1400x1050 (CVT) */
- {VIA_RES_1400X1050, CRTM1400x1050, ARRAY_SIZE(CRTM1400x1050)}
+ {CRTM1400x1050, ARRAY_SIZE(CRTM1400x1050)}
};
+
+struct VideoModeTable viafb_rb_modes[] = {
+ /* Display : 1360x768 (CVT Reduce Blanking) */
+ {CRTM1360x768_RB, ARRAY_SIZE(CRTM1360x768_RB)},
+
+ /* Display : 1440x900 (CVT Reduce Blanking) */
+ {CRTM1440x900_RB, ARRAY_SIZE(CRTM1440x900_RB)},
+
+ /* Display : 1400x1050 (CVT Reduce Blanking) */
+ {CRTM1400x1050_RB, ARRAY_SIZE(CRTM1400x1050_RB)},
+
+ /* Display : 1600x900 (CVT Reduce Blanking) */
+ {CRTM1600x900_RB, ARRAY_SIZE(CRTM1600x900_RB)},
+
+ /* Display : 1680x1050 (CVT Reduce Blanking) */
+ {CRTM1680x1050_RB, ARRAY_SIZE(CRTM1680x1050_RB)},
+
+ /* Display : 1920x1080 (CVT Reduce Blanking) */
+ {CRTM1920x1080_RB, ARRAY_SIZE(CRTM1920x1080_RB)},
+
+ /* Display : 1920x1200 (CVT Reduce Blanking) */
+ {CRTM1920x1200_RB, ARRAY_SIZE(CRTM1920x1200_RB)}
+};
+
struct crt_mode_table CEAM1280x720[] = {
{REFRESH_60, CLK_74_270M, M1280X720_CEA_R60_HSP,
M1280X720_CEA_R60_VSP,
@@ -1056,8 +1038,8 @@ struct crt_mode_table CEAM1920x1080[] = {
};
struct VideoModeTable CEA_HDMI_Modes[] = {
/* Display : 1280x720 */
- {VIA_RES_1280X720, CEAM1280x720, ARRAY_SIZE(CEAM1280x720)},
- {VIA_RES_1920X1080, CEAM1920x1080, ARRAY_SIZE(CEAM1920x1080)}
+ {CEAM1280x720, ARRAY_SIZE(CEAM1280x720)},
+ {CEAM1920x1080, ARRAY_SIZE(CEAM1920x1080)}
};
int NUM_TOTAL_RES_MAP_REFRESH = ARRAY_SIZE(res_map_refresh_tbl);
@@ -1069,4 +1051,28 @@ int NUM_TOTAL_CX700_ModeXregs = ARRAY_SIZE(CX700_ModeXregs);
int NUM_TOTAL_VX855_ModeXregs = ARRAY_SIZE(VX855_ModeXregs);
int NUM_TOTAL_CLE266_ModeXregs = ARRAY_SIZE(CLE266_ModeXregs);
int NUM_TOTAL_PATCH_MODE = ARRAY_SIZE(res_patch_table);
-int NUM_TOTAL_MODETABLE = ARRAY_SIZE(CLE266Modes);
+
+
+struct VideoModeTable *viafb_get_mode(int hres, int vres)
+{
+ u32 i;
+ for (i = 0; i < ARRAY_SIZE(viafb_modes); i++)
+ if (viafb_modes[i].mode_array &&
+ viafb_modes[i].crtc[0].crtc.hor_addr == hres &&
+ viafb_modes[i].crtc[0].crtc.ver_addr == vres)
+ return &viafb_modes[i];
+
+ return NULL;
+}
+
+struct VideoModeTable *viafb_get_rb_mode(int hres, int vres)
+{
+ u32 i;
+ for (i = 0; i < ARRAY_SIZE(viafb_rb_modes); i++)
+ if (viafb_rb_modes[i].mode_array &&
+ viafb_rb_modes[i].crtc[0].crtc.hor_addr == hres &&
+ viafb_rb_modes[i].crtc[0].crtc.ver_addr == vres)
+ return &viafb_rb_modes[i];
+
+ return NULL;
+}
diff --git a/drivers/video/via/viamode.h b/drivers/video/via/viamode.h
index a9d6554fabdf..5b1ced86514b 100644
--- a/drivers/video/via/viamode.h
+++ b/drivers/video/via/viamode.h
@@ -32,13 +32,11 @@ struct VPITTable {
};
struct VideoModeTable {
- int ModeIndex;
struct crt_mode_table *crtc;
int mode_array;
};
struct patch_table {
- int mode_index;
int table_length;
struct io_reg *io_reg_table;
};
@@ -59,13 +57,11 @@ extern int NUM_TOTAL_CX700_ModeXregs;
extern int NUM_TOTAL_VX855_ModeXregs;
extern int NUM_TOTAL_CLE266_ModeXregs;
extern int NUM_TOTAL_PATCH_MODE;
-extern int NUM_TOTAL_MODETABLE;
/********************/
/* Mode Table */
/********************/
-extern struct VideoModeTable CLE266Modes[];
extern struct crt_mode_table CEAM1280x720[];
extern struct crt_mode_table CEAM1920x1080[];
extern struct VideoModeTable CEA_HDMI_Modes[];
@@ -81,4 +77,8 @@ extern struct io_reg CLE266_ModeXregs[];
extern struct io_reg PM1024x768[];
extern struct patch_table res_patch_table[];
extern struct VPITTable VPIT;
+
+struct VideoModeTable *viafb_get_mode(int hres, int vres);
+struct VideoModeTable *viafb_get_rb_mode(int hres, int vres);
+
#endif /* __VIAMODE_H__ */
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
index 2376f688ec8b..5d223959778a 100644
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -628,7 +628,7 @@ static int w100fb_resume(struct platform_device *dev)
#endif
-int __init w100fb_probe(struct platform_device *pdev)
+int __devinit w100fb_probe(struct platform_device *pdev)
{
int err = -EIO;
struct w100fb_mach_info *inf;
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 9dd588042880..369f2eebbad1 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -28,7 +28,7 @@
struct virtio_balloon
{
struct virtio_device *vdev;
- struct virtqueue *inflate_vq, *deflate_vq;
+ struct virtqueue *inflate_vq, *deflate_vq, *stats_vq;
/* Where the ballooning thread waits for config to change. */
wait_queue_head_t config_change;
@@ -49,6 +49,10 @@ struct virtio_balloon
/* The array of pfns we tell the Host about. */
unsigned int num_pfns;
u32 pfns[256];
+
+ /* Memory statistics */
+ int need_stats_update;
+ struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
};
static struct virtio_device_id id_table[] = {
@@ -154,6 +158,72 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
}
}
+static inline void update_stat(struct virtio_balloon *vb, int idx,
+ u16 tag, u64 val)
+{
+ BUG_ON(idx >= VIRTIO_BALLOON_S_NR);
+ vb->stats[idx].tag = tag;
+ vb->stats[idx].val = val;
+}
+
+#define pages_to_bytes(x) ((u64)(x) << PAGE_SHIFT)
+
+static void update_balloon_stats(struct virtio_balloon *vb)
+{
+ unsigned long events[NR_VM_EVENT_ITEMS];
+ struct sysinfo i;
+ int idx = 0;
+
+ all_vm_events(events);
+ si_meminfo(&i);
+
+ update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_IN,
+ pages_to_bytes(events[PSWPIN]));
+ update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_OUT,
+ pages_to_bytes(events[PSWPOUT]));
+ update_stat(vb, idx++, VIRTIO_BALLOON_S_MAJFLT, events[PGMAJFAULT]);
+ update_stat(vb, idx++, VIRTIO_BALLOON_S_MINFLT, events[PGFAULT]);
+ update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMFREE,
+ pages_to_bytes(i.freeram));
+ update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMTOT,
+ pages_to_bytes(i.totalram));
+}
+
+/*
+ * While most virtqueues communicate guest-initiated requests to the hypervisor,
+ * the stats queue operates in reverse. The driver initializes the virtqueue
+ * with a single buffer. From that point forward, all conversations consist of
+ * a hypervisor request (a call to this function) which directs us to refill
+ * the virtqueue with a fresh stats buffer. Since stats collection can sleep,
+ * we notify our kthread which does the actual work via stats_handle_request().
+ */
+static void stats_request(struct virtqueue *vq)
+{
+ struct virtio_balloon *vb;
+ unsigned int len;
+
+ vb = vq->vq_ops->get_buf(vq, &len);
+ if (!vb)
+ return;
+ vb->need_stats_update = 1;
+ wake_up(&vb->config_change);
+}
+
+static void stats_handle_request(struct virtio_balloon *vb)
+{
+ struct virtqueue *vq;
+ struct scatterlist sg;
+
+ vb->need_stats_update = 0;
+ update_balloon_stats(vb);
+
+ vq = vb->stats_vq;
+ sg_init_one(&sg, vb->stats, sizeof(vb->stats));
+ if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) < 0)
+ BUG();
+ vq->vq_ops->kick(vq);
+}
+
static void virtballoon_changed(struct virtio_device *vdev)
{
struct virtio_balloon *vb = vdev->priv;
@@ -190,8 +260,11 @@ static int balloon(void *_vballoon)
try_to_freeze();
wait_event_interruptible(vb->config_change,
(diff = towards_target(vb)) != 0
+ || vb->need_stats_update
|| kthread_should_stop()
|| freezing(current));
+ if (vb->need_stats_update)
+ stats_handle_request(vb);
if (diff > 0)
fill_balloon(vb, diff);
else if (diff < 0)
@@ -204,10 +277,10 @@ static int balloon(void *_vballoon)
static int virtballoon_probe(struct virtio_device *vdev)
{
struct virtio_balloon *vb;
- struct virtqueue *vqs[2];
- vq_callback_t *callbacks[] = { balloon_ack, balloon_ack };
- const char *names[] = { "inflate", "deflate" };
- int err;
+ struct virtqueue *vqs[3];
+ vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request };
+ const char *names[] = { "inflate", "deflate", "stats" };
+ int err, nvqs;
vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
if (!vb) {
@@ -219,14 +292,31 @@ static int virtballoon_probe(struct virtio_device *vdev)
vb->num_pages = 0;
init_waitqueue_head(&vb->config_change);
vb->vdev = vdev;
+ vb->need_stats_update = 0;
- /* We expect two virtqueues. */
- err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names);
+ /* We expect two virtqueues: inflate and deflate,
+ * and optionally stat. */
+ nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2;
+ err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
if (err)
goto out_free_vb;
vb->inflate_vq = vqs[0];
vb->deflate_vq = vqs[1];
+ if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) {
+ struct scatterlist sg;
+ vb->stats_vq = vqs[2];
+
+ /*
+ * Prime this virtqueue with one buffer so the hypervisor can
+ * use it to signal us later.
+ */
+ sg_init_one(&sg, vb->stats, sizeof vb->stats);
+ if (vb->stats_vq->vq_ops->add_buf(vb->stats_vq,
+ &sg, 1, 0, vb) < 0)
+ BUG();
+ vb->stats_vq->vq_ops->kick(vb->stats_vq);
+ }
vb->thread = kthread_run(balloon, vb, "vballoon");
if (IS_ERR(vb->thread)) {
@@ -264,9 +354,12 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev)
kfree(vb);
}
-static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST };
+static unsigned int features[] = {
+ VIRTIO_BALLOON_F_MUST_TELL_HOST,
+ VIRTIO_BALLOON_F_STATS_VQ,
+};
-static struct virtio_driver virtio_balloon = {
+static struct virtio_driver virtio_balloon_driver = {
.feature_table = features,
.feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
@@ -279,12 +372,12 @@ static struct virtio_driver virtio_balloon = {
static int __init init(void)
{
- return register_virtio_driver(&virtio_balloon);
+ return register_virtio_driver(&virtio_balloon_driver);
}
static void __exit fini(void)
{
- unregister_virtio_driver(&virtio_balloon);
+ unregister_virtio_driver(&virtio_balloon_driver);
}
module_init(init);
module_exit(fini);
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index 28d9cf7cf72f..625447f645d9 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -473,7 +473,8 @@ static void vp_del_vqs(struct virtio_device *vdev)
list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
info = vq->priv;
- if (vp_dev->per_vq_vectors)
+ if (vp_dev->per_vq_vectors &&
+ info->msix_vector != VIRTIO_MSI_NO_VECTOR)
free_irq(vp_dev->msix_entries[info->msix_vector].vector,
vq);
vp_del_vq(vq);
@@ -648,6 +649,7 @@ static int __devinit virtio_pci_probe(struct pci_dev *pci_dev,
goto out_req_regions;
pci_set_drvdata(pci_dev, vp_dev);
+ pci_set_master(pci_dev);
/* we use the subsystem vendor/device id as the virtio vendor/device
* id. this allows us to use the same PCI vendor/device id for all
@@ -702,7 +704,7 @@ static struct pci_driver virtio_pci_driver = {
.name = "virtio-pci",
.id_table = virtio_pci_id_table,
.probe = virtio_pci_probe,
- .remove = virtio_pci_remove,
+ .remove = __devexit_p(virtio_pci_remove),
#ifdef CONFIG_PM
.suspend = virtio_pci_suspend,
.resume = virtio_pci_resume,
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index fbd2ecde93e4..0db906b3c95d 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -21,6 +21,24 @@
#include <linux/virtio_config.h>
#include <linux/device.h>
+/* virtio guest is communicating with a virtual "device" that actually runs on
+ * a host processor. Memory barriers are used to control SMP effects. */
+#ifdef CONFIG_SMP
+/* Where possible, use SMP barriers which are more lightweight than mandatory
+ * barriers, because mandatory barriers control MMIO effects on accesses
+ * through relaxed memory I/O windows (which virtio does not use). */
+#define virtio_mb() smp_mb()
+#define virtio_rmb() smp_rmb()
+#define virtio_wmb() smp_wmb()
+#else
+/* We must force memory ordering even if guest is UP since host could be
+ * running on another CPU, but SMP barriers are defined to barrier() in that
+ * configuration. So fall back to mandatory barriers instead. */
+#define virtio_mb() mb()
+#define virtio_rmb() rmb()
+#define virtio_wmb() wmb()
+#endif
+
#ifdef DEBUG
/* For development, we want to crash whenever the ring is screwed. */
#define BAD_RING(_vq, fmt, args...) \
@@ -36,10 +54,9 @@
panic("%s:in_use = %i\n", \
(_vq)->vq.name, (_vq)->in_use); \
(_vq)->in_use = __LINE__; \
- mb(); \
} while (0)
#define END_USE(_vq) \
- do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; mb(); } while(0)
+ do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; } while(0)
#else
#define BAD_RING(_vq, fmt, args...) \
do { \
@@ -221,13 +238,13 @@ static void vring_kick(struct virtqueue *_vq)
START_USE(vq);
/* Descriptors and available array need to be set before we expose the
* new available array entries. */
- wmb();
+ virtio_wmb();
vq->vring.avail->idx += vq->num_added;
vq->num_added = 0;
/* Need to update avail index before checking if we should notify */
- mb();
+ virtio_mb();
if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
/* Prod other side to tell it about changes. */
@@ -286,7 +303,7 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
}
/* Only get used array entries after they have been exposed by host. */
- rmb();
+ virtio_rmb();
i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id;
*len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len;
@@ -324,7 +341,7 @@ static bool vring_enable_cb(struct virtqueue *_vq)
/* We optimistically turn back on interrupts, then check if there was
* more to do. */
vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
- mb();
+ virtio_mb();
if (unlikely(more_used(vq))) {
END_USE(vq);
return false;
@@ -334,6 +351,30 @@ static bool vring_enable_cb(struct virtqueue *_vq)
return true;
}
+static void *vring_detach_unused_buf(struct virtqueue *_vq)
+{
+ struct vring_virtqueue *vq = to_vvq(_vq);
+ unsigned int i;
+ void *buf;
+
+ START_USE(vq);
+
+ for (i = 0; i < vq->vring.num; i++) {
+ if (!vq->data[i])
+ continue;
+ /* detach_buf clears data, so grab it now. */
+ buf = vq->data[i];
+ detach_buf(vq, i);
+ END_USE(vq);
+ return buf;
+ }
+ /* That should have freed everything. */
+ BUG_ON(vq->num_free != vq->vring.num);
+
+ END_USE(vq);
+ return NULL;
+}
+
irqreturn_t vring_interrupt(int irq, void *_vq)
{
struct vring_virtqueue *vq = to_vvq(_vq);
@@ -360,6 +401,7 @@ static struct virtqueue_ops vring_vq_ops = {
.kick = vring_kick,
.disable_cb = vring_disable_cb,
.enable_cb = vring_enable_cb,
+ .detach_unused_buf = vring_detach_unused_buf,
};
struct virtqueue *vring_new_virtqueue(unsigned int num,
@@ -406,8 +448,11 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
/* Put everything in free lists. */
vq->num_free = num;
vq->free_head = 0;
- for (i = 0; i < num-1; i++)
+ for (i = 0; i < num-1; i++) {
vq->vring.desc[i].next = i+1;
+ vq->data[i] = NULL;
+ }
+ vq->data[i] = NULL;
return &vq->vq;
}
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
index 3195fb8b7d9a..80b3b123dd7f 100644
--- a/drivers/w1/masters/Kconfig
+++ b/drivers/w1/masters/Kconfig
@@ -60,7 +60,7 @@ config W1_MASTER_GPIO
config HDQ_MASTER_OMAP
tristate "OMAP HDQ driver"
- depends on ARCH_OMAP2430 || ARCH_OMAP34XX
+ depends on ARCH_OMAP2430 || ARCH_OMAP3
help
Say Y here if you want support for the 1-wire or HDQ Interface
on an OMAP processor.
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index 406caa6a71cb..e5f74416d4b7 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -214,7 +214,7 @@ static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
(++retries < DS2482_WAIT_IDLE_TIMEOUT));
}
- if (retries > DS2482_WAIT_IDLE_TIMEOUT)
+ if (retries >= DS2482_WAIT_IDLE_TIMEOUT)
printk(KERN_ERR "%s: timeout on channel %d\n",
__func__, pdev->channel);
diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c
index 65244c02551b..492670358cbf 100644
--- a/drivers/w1/masters/mxc_w1.c
+++ b/drivers/w1/masters/mxc_w1.c
@@ -102,7 +102,7 @@ static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
return ((__raw_readb(ctrl_addr)) >> 3) & 0x1;
}
-static int __init mxc_w1_probe(struct platform_device *pdev)
+static int __devinit mxc_w1_probe(struct platform_device *pdev)
{
struct mxc_w1_device *mdev;
struct resource *res;
@@ -166,7 +166,7 @@ failed_clk:
/*
* disassociate the w1 device from the driver
*/
-static int mxc_w1_remove(struct platform_device *pdev)
+static int __devexit mxc_w1_remove(struct platform_device *pdev)
{
struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
struct resource *res;
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index 0d92969404c3..22977d30f89e 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -72,7 +72,7 @@ struct hdq_data {
int init_trans;
};
-static int __init omap_hdq_probe(struct platform_device *pdev);
+static int __devinit omap_hdq_probe(struct platform_device *pdev);
static int omap_hdq_remove(struct platform_device *pdev);
static struct platform_driver omap_hdq_driver = {
@@ -558,7 +558,7 @@ static void omap_w1_write_byte(void *_hdq, u8 byte)
return;
}
-static int __init omap_hdq_probe(struct platform_device *pdev)
+static int __devinit omap_hdq_probe(struct platform_device *pdev)
{
struct hdq_data *hdq_data;
struct resource *res;
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index acc7e3b7fe17..ad5897dc4495 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -986,7 +986,7 @@ int w1_process(void *data)
return 0;
}
-static int w1_init(void)
+static int __init w1_init(void)
{
int retval;
@@ -1034,7 +1034,7 @@ err_out_exit_init:
return retval;
}
-static void w1_fini(void)
+static void __exit w1_fini(void)
{
struct w1_master *dev;
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 088f32f29a6e..bdcdbd53da89 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -55,6 +55,11 @@ config SOFT_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called softdog.
+config MAX63XX_WATCHDOG
+ tristate "Max63xx watchdog"
+ help
+ Support for memory mapped max63{69,70,71,72,73,74} watchdog timer.
+
config WM831X_WATCHDOG
tristate "WM831x watchdog"
depends on MFD_WM831X
@@ -194,7 +199,7 @@ config EP93XX_WATCHDOG
config OMAP_WATCHDOG
tristate "OMAP Watchdog"
- depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
+ depends on ARCH_OMAP16XX || ARCH_OMAP2 || ARCH_OMAP3
help
Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog. Say 'Y'
here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog timer.
@@ -289,6 +294,17 @@ config ADX_WATCHDOG
Say Y here if you want support for the watchdog timer on Avionic
Design Xanthos boards.
+config TS72XX_WATCHDOG
+ tristate "TS-72XX SBC Watchdog"
+ depends on MACH_TS72XX
+ help
+ Technologic Systems TS-7200, TS-7250 and TS-7260 boards have
+ watchdog timer implemented in a external CPLD chip. Say Y here
+ if you want to support for the watchdog timer on TS-72XX boards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ts72xx_wdt.
+
# AVR32 Architecture
config AT32AP700X_WDT
@@ -396,8 +412,8 @@ config SBC_FITPC2_WATCHDOG
tristate "Compulab SBC-FITPC2 watchdog"
depends on X86
---help---
- This is the driver for the built-in watchdog timer on the fit-PC2
- Single-board computer made by Compulab.
+ This is the driver for the built-in watchdog timer on the fit-PC2,
+ fit-PC2i, CM-iAM single-board computers made by Compulab.
It`s possible to enable watchdog timer either from BIOS (F2) or from booted Linux.
When "Watchdog Timer Value" enabled one can set 31-255 s operational range.
@@ -845,10 +861,10 @@ config TXX9_WDT
# POWERPC Architecture
config GEF_WDT
- tristate "GE Fanuc Watchdog Timer"
+ tristate "GE Watchdog Timer"
depends on GEF_SBC610 || GEF_SBC310 || GEF_PPC9A
---help---
- Watchdog timer found in a number of GE Fanuc single board computers.
+ Watchdog timer found in a number of GE single board computers.
config MPC5200_WDT
bool "MPC52xx Watchdog Timer"
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 475c61100069..5e3cb95bb0e9 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o
obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
obj-$(CONFIG_ADX_WATCHDOG) += adx_wdt.o
+obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
@@ -142,4 +143,5 @@ obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o
# Architecture Independant
obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
+obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o
obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
diff --git a/drivers/watchdog/acquirewdt.c b/drivers/watchdog/acquirewdt.c
index 4d18c874d963..2ffce4d75443 100644
--- a/drivers/watchdog/acquirewdt.c
+++ b/drivers/watchdog/acquirewdt.c
@@ -150,7 +150,7 @@ static long acq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int options, retval = -EINVAL;
void __user *argp = (void __user *)arg;
int __user *p = argp;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = WATCHDOG_NAME,
diff --git a/drivers/watchdog/advantechwdt.c b/drivers/watchdog/advantechwdt.c
index 824d076a5cd6..4d40965d2c9f 100644
--- a/drivers/watchdog/advantechwdt.c
+++ b/drivers/watchdog/advantechwdt.c
@@ -137,7 +137,7 @@ static long advwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int new_timeout;
void __user *argp = (void __user *)arg;
int __user *p = argp;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
diff --git a/drivers/watchdog/adx_wdt.c b/drivers/watchdog/adx_wdt.c
index 9d7d155364f8..a5ca7a6ee133 100644
--- a/drivers/watchdog/adx_wdt.c
+++ b/drivers/watchdog/adx_wdt.c
@@ -37,7 +37,7 @@ struct adx_wdt {
spinlock_t lock;
};
-static struct watchdog_info adx_wdt_info = {
+static const struct watchdog_info adx_wdt_info = {
.identity = "Avionic Design Xanthos Watchdog",
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
};
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
index 937a80fb61e1..1e9caea8ff8a 100644
--- a/drivers/watchdog/alim1535_wdt.c
+++ b/drivers/watchdog/alim1535_wdt.c
@@ -180,7 +180,7 @@ static long ali_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
index f90afdb1b255..d8d4da9a483d 100644
--- a/drivers/watchdog/alim7101_wdt.c
+++ b/drivers/watchdog/alim7101_wdt.c
@@ -238,7 +238,7 @@ static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1,
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
index 2e94b71b20d9..c764c52412e4 100644
--- a/drivers/watchdog/ar7_wdt.c
+++ b/drivers/watchdog/ar7_wdt.c
@@ -34,6 +34,7 @@
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/uaccess.h>
+#include <linux/clk.h>
#include <asm/addrspace.h>
#include <asm/mach-ar7/ar7.h>
@@ -80,6 +81,8 @@ static struct resource *ar7_regs_wdt;
/* Pointer to the remapped WDT IO space */
static struct ar7_wdt *ar7_wdt;
+static struct clk *vbus_clk;
+
static void ar7_wdt_kick(u32 value)
{
WRITE_REG(ar7_wdt->kick_lock, 0x5555);
@@ -138,17 +141,19 @@ static void ar7_wdt_disable(u32 value)
static void ar7_wdt_update_margin(int new_margin)
{
u32 change;
+ u32 vbus_rate;
- change = new_margin * (ar7_vbus_freq() / prescale_value);
+ vbus_rate = clk_get_rate(vbus_clk);
+ change = new_margin * (vbus_rate / prescale_value);
if (change < 1)
change = 1;
if (change > 0xffff)
change = 0xffff;
ar7_wdt_change(change);
- margin = change * prescale_value / ar7_vbus_freq();
+ margin = change * prescale_value / vbus_rate;
printk(KERN_INFO DRVNAME
": timer margin %d seconds (prescale %d, change %d, freq %d)\n",
- margin, prescale_value, change, ar7_vbus_freq());
+ margin, prescale_value, change, vbus_rate);
}
static void ar7_wdt_enable_wdt(void)
@@ -214,7 +219,7 @@ static ssize_t ar7_wdt_write(struct file *file, const char *data,
static long ar7_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.identity = LONGNAME,
.firmware_version = 1,
.options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
@@ -298,6 +303,13 @@ static int __devinit ar7_wdt_probe(struct platform_device *pdev)
goto out_mem_region;
}
+ vbus_clk = clk_get(NULL, "vbus");
+ if (IS_ERR(vbus_clk)) {
+ printk(KERN_ERR DRVNAME ": could not get vbus clock\n");
+ rc = PTR_ERR(vbus_clk);
+ goto out_mem_region;
+ }
+
ar7_wdt_disable_wdt();
ar7_wdt_prescale(prescale_value);
ar7_wdt_update_margin(margin);
diff --git a/drivers/watchdog/at32ap700x_wdt.c b/drivers/watchdog/at32ap700x_wdt.c
index 037847923dcb..6873376f986c 100644
--- a/drivers/watchdog/at32ap700x_wdt.c
+++ b/drivers/watchdog/at32ap700x_wdt.c
@@ -202,7 +202,7 @@ static int at32_wdt_get_status(void)
return status;
}
-static struct watchdog_info at32_wdt_info = {
+static const struct watchdog_info at32_wdt_info = {
.identity = "at32ap700x watchdog",
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c
index b185dafe1494..b3046dc4b56c 100644
--- a/drivers/watchdog/at91rm9200_wdt.c
+++ b/drivers/watchdog/at91rm9200_wdt.c
@@ -121,7 +121,7 @@ static int at91_wdt_settimeout(int new_time)
return 0;
}
-static struct watchdog_info at91_wdt_info = {
+static const struct watchdog_info at91_wdt_info = {
.identity = "at91 watchdog",
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
};
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index 751c003864ad..5f245522397b 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -149,7 +149,7 @@ static ssize_t bcm47xx_wdt_write(struct file *file, const char __user *data,
return len;
}
-static struct watchdog_info bcm47xx_wdt_info = {
+static const struct watchdog_info bcm47xx_wdt_info = {
.identity = DRV_NAME,
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
index c7b3f9df2317..9c7ccd1e9088 100644
--- a/drivers/watchdog/bfin_wdt.c
+++ b/drivers/watchdog/bfin_wdt.c
@@ -1,9 +1,8 @@
/*
* Blackfin On-Chip Watchdog Driver
- * Supports BF53[123]/BF53[467]/BF54[2489]/BF561
*
* Originally based on softdog.c
- * Copyright 2006-2007 Analog Devices Inc.
+ * Copyright 2006-2010 Analog Devices Inc.
* Copyright 2006-2007 Michele d'Amico
* Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>
*
@@ -20,8 +19,6 @@
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/fs.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
@@ -75,7 +72,7 @@
static unsigned int timeout = WATCHDOG_TIMEOUT;
static int nowayout = WATCHDOG_NOWAYOUT;
-static struct watchdog_info bfin_wdt_info;
+static const struct watchdog_info bfin_wdt_info;
static unsigned long open_check;
static char expect_close;
static DEFINE_SPINLOCK(bfin_wdt_spinlock);
@@ -137,13 +134,15 @@ static int bfin_wdt_running(void)
*/
static int bfin_wdt_set_timeout(unsigned long t)
{
- u32 cnt;
+ u32 cnt, max_t, sclk;
unsigned long flags;
- stampit();
+ sclk = get_sclk();
+ max_t = -1 / sclk;
+ cnt = t * sclk;
+ stamp("maxtimeout=%us newtimeout=%lus (cnt=%#x)", max_t, t, cnt);
- cnt = t * get_sclk();
- if (cnt < get_sclk()) {
+ if (t > max_t) {
printk(KERN_WARNING PFX "timeout value is too large\n");
return -EINVAL;
}
@@ -308,26 +307,6 @@ static long bfin_wdt_ioctl(struct file *file,
}
}
-/**
- * bfin_wdt_notify_sys - Notifier Handler
- * @this: notifier block
- * @code: notifier event
- * @unused: unused
- *
- * Handles specific events, such as turning off the watchdog during a
- * shutdown event.
- */
-static int bfin_wdt_notify_sys(struct notifier_block *this,
- unsigned long code, void *unused)
-{
- stampit();
-
- if (code == SYS_DOWN || code == SYS_HALT)
- bfin_wdt_stop();
-
- return NOTIFY_DONE;
-}
-
#ifdef CONFIG_PM
static int state_before_suspend;
@@ -387,40 +366,28 @@ static struct miscdevice bfin_wdt_miscdev = {
.fops = &bfin_wdt_fops,
};
-static struct watchdog_info bfin_wdt_info = {
+static const struct watchdog_info bfin_wdt_info = {
.identity = "Blackfin Watchdog",
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
};
-static struct notifier_block bfin_wdt_notifier = {
- .notifier_call = bfin_wdt_notify_sys,
-};
-
/**
* bfin_wdt_probe - Initialize module
*
- * Registers the misc device and notifier handler. Actual device
+ * Registers the misc device. Actual device
* initialization is handled by bfin_wdt_open().
*/
static int __devinit bfin_wdt_probe(struct platform_device *pdev)
{
int ret;
- ret = register_reboot_notifier(&bfin_wdt_notifier);
- if (ret) {
- pr_devinit(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", ret);
- return ret;
- }
-
ret = misc_register(&bfin_wdt_miscdev);
if (ret) {
pr_devinit(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
- unregister_reboot_notifier(&bfin_wdt_notifier);
return ret;
}
@@ -433,21 +400,33 @@ static int __devinit bfin_wdt_probe(struct platform_device *pdev)
/**
* bfin_wdt_remove - Initialize module
*
- * Unregisters the misc device and notifier handler. Actual device
+ * Unregisters the misc device. Actual device
* deinitialization is handled by bfin_wdt_close().
*/
static int __devexit bfin_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&bfin_wdt_miscdev);
- unregister_reboot_notifier(&bfin_wdt_notifier);
return 0;
}
+/**
+ * bfin_wdt_shutdown - Soft Shutdown Handler
+ *
+ * Handles the soft shutdown event.
+ */
+static void bfin_wdt_shutdown(struct platform_device *pdev)
+{
+ stampit();
+
+ bfin_wdt_stop();
+}
+
static struct platform_device *bfin_wdt_device;
static struct platform_driver bfin_wdt_driver = {
.probe = bfin_wdt_probe,
.remove = __devexit_p(bfin_wdt_remove),
+ .shutdown = bfin_wdt_shutdown,
.suspend = bfin_wdt_suspend,
.resume = bfin_wdt_resume,
.driver = {
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index e8380ef65c1c..8b724aad6825 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -121,7 +121,7 @@ static ssize_t booke_wdt_write(struct file *file, const char __user *buf,
return count;
}
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "PowerPC Book-E Watchdog",
};
diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c
index 923cc68dba26..9291506b8b23 100644
--- a/drivers/watchdog/coh901327_wdt.c
+++ b/drivers/watchdog/coh901327_wdt.c
@@ -257,7 +257,7 @@ static long coh901327_ioctl(struct file *file, unsigned int cmd,
struct watchdog_info __user *ident;
int __user *i;
} uarg;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET |
WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING,
diff --git a/drivers/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c
index 71f6d7eec9a8..edd3475f41db 100644
--- a/drivers/watchdog/cpu5wdt.c
+++ b/drivers/watchdog/cpu5wdt.c
@@ -154,7 +154,7 @@ static long cpu5wdt_ioctl(struct file *file, unsigned int cmd,
void __user *argp = (void __user *)arg;
int __user *p = argp;
unsigned int value;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET,
.identity = "CPU5 WDT",
};
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
index 081f2955419e..37ea052d4dee 100644
--- a/drivers/watchdog/cpwd.c
+++ b/drivers/watchdog/cpwd.c
@@ -403,7 +403,7 @@ static int cpwd_release(struct inode *inode, struct file *file)
static long cpwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- static struct watchdog_info info = {
+ static const struct watchdog_info info = {
.options = WDIOF_SETTIMEOUT,
.firmware_version = 1,
.identity = DRIVER_NAME,
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c
index 887136de1857..56162c87f5d8 100644
--- a/drivers/watchdog/davinci_wdt.c
+++ b/drivers/watchdog/davinci_wdt.c
@@ -142,7 +142,7 @@ davinci_wdt_write(struct file *file, const char *data, size_t len,
return len;
}
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING,
.identity = "DaVinci Watchdog",
};
diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c
index cdd55e0d09f8..88ed54e50f74 100644
--- a/drivers/watchdog/ep93xx_wdt.c
+++ b/drivers/watchdog/ep93xx_wdt.c
@@ -131,7 +131,7 @@ ep93xx_wdt_write(struct file *file, const char __user *data, size_t len,
return len;
}
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE,
.identity = "EP93xx Watchdog",
};
diff --git a/drivers/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c
index 9add3541fb42..d1c4e55b1db0 100644
--- a/drivers/watchdog/eurotechwdt.c
+++ b/drivers/watchdog/eurotechwdt.c
@@ -238,7 +238,7 @@ static long eurwdt_ioctl(struct file *file,
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1,
diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c
index 734d9806a872..abdbad034a6c 100644
--- a/drivers/watchdog/gef_wdt.c
+++ b/drivers/watchdog/gef_wdt.c
@@ -1,9 +1,9 @@
/*
- * GE Fanuc watchdog userspace interface
+ * GE watchdog userspace interface
*
- * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ * Author: Martyn Welch <martyn.welch@ge.com>
*
- * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ * Copyright 2008 GE Intelligent Platforms Embedded Systems, 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
@@ -161,11 +161,11 @@ static long gef_wdt_ioctl(struct file *file, unsigned int cmd,
int timeout;
int options;
void __user *argp = (void __user *)arg;
- static struct watchdog_info info = {
+ static const struct watchdog_info info = {
.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
WDIOF_KEEPALIVEPING,
.firmware_version = 0,
- .identity = "GE Fanuc watchdog",
+ .identity = "GE watchdog",
};
switch (cmd) {
@@ -311,7 +311,7 @@ static struct of_platform_driver gef_wdt_driver = {
static int __init gef_wdt_init(void)
{
- printk(KERN_INFO "GE Fanuc watchdog driver\n");
+ printk(KERN_INFO "GE watchdog driver\n");
return of_register_platform_driver(&gef_wdt_driver);
}
@@ -323,8 +323,8 @@ static void __exit gef_wdt_exit(void)
module_init(gef_wdt_init);
module_exit(gef_wdt_exit);
-MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com>");
-MODULE_DESCRIPTION("GE Fanuc watchdog driver");
+MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com>");
+MODULE_DESCRIPTION("GE watchdog driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
MODULE_ALIAS("platform: gef_wdt");
diff --git a/drivers/watchdog/geodewdt.c b/drivers/watchdog/geodewdt.c
index 38252ff828ca..9b49b125ad5a 100644
--- a/drivers/watchdog/geodewdt.c
+++ b/drivers/watchdog/geodewdt.c
@@ -142,7 +142,7 @@ static long geodewdt_ioctl(struct file *file, unsigned int cmd,
int __user *p = argp;
int interval;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING
| WDIOF_MAGICCLOSE,
.firmware_version = 1,
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index a6c5674c78e6..70c2c24660d0 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -554,7 +554,7 @@ static ssize_t hpwdt_write(struct file *file, const char __user *data,
return len;
}
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c
index 7ba0b11ec525..bb9750a03942 100644
--- a/drivers/watchdog/i6300esb.c
+++ b/drivers/watchdog/i6300esb.c
@@ -34,7 +34,6 @@
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
-#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/ioport.h>
@@ -42,7 +41,7 @@
#include <linux/io.h>
/* Module and version information */
-#define ESB_VERSION "0.04"
+#define ESB_VERSION "0.05"
#define ESB_MODULE_NAME "i6300ESB timer"
#define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION
#define PFX ESB_MODULE_NAME ": "
@@ -65,7 +64,7 @@
/* Config register bits */
#define ESB_WDT_REBOOT (0x01 << 5) /* Enable reboot on timeout */
#define ESB_WDT_FREQ (0x01 << 2) /* Decrement frequency */
-#define ESB_WDT_INTTYPE (0x11 << 0) /* Interrupt type on timer1 timeout */
+#define ESB_WDT_INTTYPE (0x03 << 0) /* Interrupt type on timer1 timeout */
/* Reload register bits */
#define ESB_WDT_TIMEOUT (0x01 << 9) /* Watchdog timed out */
@@ -82,7 +81,9 @@ static unsigned long timer_alive;
static struct pci_dev *esb_pci;
static unsigned short triggered; /* The status of the watchdog upon boot */
static char esb_expect_close;
-static struct platform_device *esb_platform_device;
+
+/* We can only use 1 card due to the /dev/watchdog restriction */
+static int cards_found;
/* module parameters */
/* 30 sec default heartbeat (1 < heartbeat < 2*1023) */
@@ -111,8 +112,8 @@ MODULE_PARM_DESC(nowayout,
*/
static inline void esb_unlock_registers(void)
{
- writeb(ESB_UNLOCK1, ESB_RELOAD_REG);
- writeb(ESB_UNLOCK2, ESB_RELOAD_REG);
+ writew(ESB_UNLOCK1, ESB_RELOAD_REG);
+ writew(ESB_UNLOCK2, ESB_RELOAD_REG);
}
static int esb_timer_start(void)
@@ -256,7 +257,7 @@ static long esb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int new_heartbeat;
void __user *argp = (void __user *)arg;
int __user *p = argp;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
@@ -332,11 +333,6 @@ static struct miscdevice esb_miscdev = {
/*
* Data for PCI driver interface
- *
- * This data only exists for exporting the supported
- * PCI ids via MODULE_DEVICE_TABLE. We do not actually
- * register a pci_driver, because someone else might one day
- * want to register another driver on the same PCI id.
*/
static struct pci_device_id esb_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
@@ -348,29 +344,19 @@ MODULE_DEVICE_TABLE(pci, esb_pci_tbl);
* Init & exit routines
*/
-static unsigned char __devinit esb_getdevice(void)
+static unsigned char __devinit esb_getdevice(struct pci_dev *pdev)
{
- /*
- * Find the PCI device
- */
-
- esb_pci = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_ESB_9, NULL);
-
- if (!esb_pci)
- return 0;
-
- if (pci_enable_device(esb_pci)) {
+ if (pci_enable_device(pdev)) {
printk(KERN_ERR PFX "failed to enable device\n");
goto err_devput;
}
- if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) {
+ if (pci_request_region(pdev, 0, ESB_MODULE_NAME)) {
printk(KERN_ERR PFX "failed to request region\n");
goto err_disable;
}
- BASEADDR = pci_ioremap_bar(esb_pci, 0);
+ BASEADDR = pci_ioremap_bar(pdev, 0);
if (BASEADDR == NULL) {
/* Something's wrong here, BASEADDR has to be set */
printk(KERN_ERR PFX "failed to get BASEADDR\n");
@@ -378,14 +364,14 @@ static unsigned char __devinit esb_getdevice(void)
}
/* Done */
+ esb_pci = pdev;
return 1;
err_release:
- pci_release_region(esb_pci, 0);
+ pci_release_region(pdev, 0);
err_disable:
- pci_disable_device(esb_pci);
+ pci_disable_device(pdev);
err_devput:
- pci_dev_put(esb_pci);
return 0;
}
@@ -430,12 +416,23 @@ static void __devinit esb_initdevice(void)
esb_timer_set_heartbeat(heartbeat);
}
-static int __devinit esb_probe(struct platform_device *dev)
+static int __devinit esb_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
int ret;
+ cards_found++;
+ if (cards_found == 1)
+ printk(KERN_INFO PFX "Intel 6300ESB WatchDog Timer Driver v%s\n",
+ ESB_VERSION);
+
+ if (cards_found > 1) {
+ printk(KERN_ERR PFX "This driver only supports 1 device\n");
+ return -ENODEV;
+ }
+
/* Check whether or not the hardware watchdog is there */
- if (!esb_getdevice() || esb_pci == NULL)
+ if (!esb_getdevice(pdev) || esb_pci == NULL)
return -ENODEV;
/* Check that the heartbeat value is within it's range;
@@ -467,11 +464,11 @@ err_unmap:
iounmap(BASEADDR);
pci_release_region(esb_pci, 0);
pci_disable_device(esb_pci);
- pci_dev_put(esb_pci);
+ esb_pci = NULL;
return ret;
}
-static int __devexit esb_remove(struct platform_device *dev)
+static void __devexit esb_remove(struct pci_dev *pdev)
{
/* Stop the timer before we leave */
if (!nowayout)
@@ -482,54 +479,30 @@ static int __devexit esb_remove(struct platform_device *dev)
iounmap(BASEADDR);
pci_release_region(esb_pci, 0);
pci_disable_device(esb_pci);
- pci_dev_put(esb_pci);
- return 0;
+ esb_pci = NULL;
}
-static void esb_shutdown(struct platform_device *dev)
+static void esb_shutdown(struct pci_dev *pdev)
{
esb_timer_stop();
}
-static struct platform_driver esb_platform_driver = {
+static struct pci_driver esb_driver = {
+ .name = ESB_MODULE_NAME,
+ .id_table = esb_pci_tbl,
.probe = esb_probe,
.remove = __devexit_p(esb_remove),
.shutdown = esb_shutdown,
- .driver = {
- .owner = THIS_MODULE,
- .name = ESB_MODULE_NAME,
- },
};
static int __init watchdog_init(void)
{
- int err;
-
- printk(KERN_INFO PFX "Intel 6300ESB WatchDog Timer Driver v%s\n",
- ESB_VERSION);
-
- err = platform_driver_register(&esb_platform_driver);
- if (err)
- return err;
-
- esb_platform_device = platform_device_register_simple(ESB_MODULE_NAME,
- -1, NULL, 0);
- if (IS_ERR(esb_platform_device)) {
- err = PTR_ERR(esb_platform_device);
- goto unreg_platform_driver;
- }
-
- return 0;
-
-unreg_platform_driver:
- platform_driver_unregister(&esb_platform_driver);
- return err;
+ return pci_register_driver(&esb_driver);
}
static void __exit watchdog_cleanup(void)
{
- platform_device_unregister(esb_platform_device);
- platform_driver_unregister(&esb_platform_driver);
+ pci_unregister_driver(&esb_driver);
printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
}
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index c8a3bec26830..44bc6aa46edf 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -29,8 +29,9 @@
* document number 313056-003, 313057-017: 82801H (ICH8)
* document number 316972-004, 316973-012: 82801I (ICH9)
* document number 319973-002, 319974-002: 82801J (ICH10)
- * document number 322169-001, 322170-001: 5 Series, 3400 Series (PCH)
+ * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
* document number 320066-003, 320257-008: EP80597 (IICH)
+ * document number TBD : Cougar Point (CPT)
*/
/*
@@ -100,8 +101,22 @@ enum iTCO_chipsets {
TCO_ICH10DO, /* ICH10DO */
TCO_PCH, /* PCH Desktop Full Featured */
TCO_PCHM, /* PCH Mobile Full Featured */
+ TCO_P55, /* P55 */
+ TCO_PM55, /* PM55 */
+ TCO_H55, /* H55 */
+ TCO_QM57, /* QM57 */
+ TCO_H57, /* H57 */
+ TCO_HM55, /* HM55 */
+ TCO_Q57, /* Q57 */
+ TCO_HM57, /* HM57 */
TCO_PCHMSFF, /* PCH Mobile SFF Full Featured */
+ TCO_QS57, /* QS57 */
+ TCO_3400, /* 3400 */
+ TCO_3420, /* 3420 */
+ TCO_3450, /* 3450 */
TCO_EP80579, /* EP80579 */
+ TCO_CPTD, /* CPT Desktop */
+ TCO_CPTM, /* CPT Mobile */
};
static struct {
@@ -144,8 +159,22 @@ static struct {
{"ICH10DO", 2},
{"PCH Desktop Full Featured", 2},
{"PCH Mobile Full Featured", 2},
+ {"P55", 2},
+ {"PM55", 2},
+ {"H55", 2},
+ {"QM57", 2},
+ {"H57", 2},
+ {"HM55", 2},
+ {"Q57", 2},
+ {"HM57", 2},
{"PCH Mobile SFF Full Featured", 2},
+ {"QS57", 2},
+ {"3400", 2},
+ {"3420", 2},
+ {"3450", 2},
{"EP80579", 2},
+ {"CPT Desktop", 2},
+ {"CPT Mobile", 2},
{NULL, 0}
};
@@ -216,8 +245,22 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ ITCO_PCI_DEVICE(0x3a14, TCO_ICH10DO)},
{ ITCO_PCI_DEVICE(0x3b00, TCO_PCH)},
{ ITCO_PCI_DEVICE(0x3b01, TCO_PCHM)},
+ { ITCO_PCI_DEVICE(0x3b02, TCO_P55)},
+ { ITCO_PCI_DEVICE(0x3b03, TCO_PM55)},
+ { ITCO_PCI_DEVICE(0x3b06, TCO_H55)},
+ { ITCO_PCI_DEVICE(0x3b07, TCO_QM57)},
+ { ITCO_PCI_DEVICE(0x3b08, TCO_H57)},
+ { ITCO_PCI_DEVICE(0x3b09, TCO_HM55)},
+ { ITCO_PCI_DEVICE(0x3b0a, TCO_Q57)},
+ { ITCO_PCI_DEVICE(0x3b0b, TCO_HM57)},
{ ITCO_PCI_DEVICE(0x3b0d, TCO_PCHMSFF)},
+ { ITCO_PCI_DEVICE(0x3b0f, TCO_QS57)},
+ { ITCO_PCI_DEVICE(0x3b12, TCO_3400)},
+ { ITCO_PCI_DEVICE(0x3b14, TCO_3420)},
+ { ITCO_PCI_DEVICE(0x3b16, TCO_3450)},
{ ITCO_PCI_DEVICE(0x5031, TCO_EP80579)},
+ { ITCO_PCI_DEVICE(0x1c42, TCO_CPTD)},
+ { ITCO_PCI_DEVICE(0x1c43, TCO_CPTM)},
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
@@ -541,7 +584,7 @@ static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd,
int new_heartbeat;
void __user *argp = (void __user *)arg;
int __user *p = argp;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
@@ -655,7 +698,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
if (iTCO_wdt_private.iTCO_version == 2) {
pci_read_config_dword(pdev, 0xf0, &base_address);
if ((base_address & 1) == 0) {
- printk(KERN_ERR PFX "RCBA is disabled by harddware\n");
+ printk(KERN_ERR PFX "RCBA is disabled by hardware\n");
ret = -ENODEV;
goto out;
}
@@ -665,8 +708,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
/* Check chipset's NO_REBOOT bit */
if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
- printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, "
- "reboot disabled by hardware\n");
+ printk(KERN_INFO PFX "unable to reset NO_REBOOT flag, "
+ "platform may have disabled it\n");
ret = -ENODEV; /* Cannot reset NO_REBOOT bit */
goto out_unmap;
}
@@ -762,6 +805,7 @@ static void __devexit iTCO_wdt_cleanup(void)
static int __devinit iTCO_wdt_probe(struct platform_device *dev)
{
+ int ret = -ENODEV;
int found = 0;
struct pci_dev *pdev = NULL;
const struct pci_device_id *ent;
@@ -771,19 +815,17 @@ static int __devinit iTCO_wdt_probe(struct platform_device *dev)
for_each_pci_dev(pdev) {
ent = pci_match_id(iTCO_wdt_pci_tbl, pdev);
if (ent) {
- if (!(iTCO_wdt_init(pdev, ent, dev))) {
- found++;
+ found++;
+ ret = iTCO_wdt_init(pdev, ent, dev);
+ if (!ret)
break;
- }
}
}
- if (!found) {
+ if (!found)
printk(KERN_INFO PFX "No card detected\n");
- return -ENODEV;
- }
- return 0;
+ return ret;
}
static int __devexit iTCO_wdt_remove(struct platform_device *dev)
diff --git a/drivers/watchdog/ib700wdt.c b/drivers/watchdog/ib700wdt.c
index 4bef3ddff4a5..0149d8dfc81d 100644
--- a/drivers/watchdog/ib700wdt.c
+++ b/drivers/watchdog/ib700wdt.c
@@ -174,7 +174,7 @@ static long ibwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
void __user *argp = (void __user *)arg;
int __user *p = argp;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1,
diff --git a/drivers/watchdog/indydog.c b/drivers/watchdog/indydog.c
index bea8a124a559..1cc5609666d1 100644
--- a/drivers/watchdog/indydog.c
+++ b/drivers/watchdog/indydog.c
@@ -111,7 +111,7 @@ static long indydog_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int options, retval = -EINVAL;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING,
.firmware_version = 0,
.identity = "Hardware Watchdog for SGI IP22",
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c
index daed48ded7fe..f52c162b1bea 100644
--- a/drivers/watchdog/it8712f_wdt.c
+++ b/drivers/watchdog/it8712f_wdt.c
@@ -236,7 +236,7 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.identity = "IT8712F Watchdog",
.firmware_version = 1,
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index cc133c531d08..b709b3b2d1ef 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -421,7 +421,7 @@ static ssize_t wdt_write(struct file *file, const char __user *buf,
return count;
}
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
.firmware_version = 1,
.identity = WATCHDOG_NAME,
diff --git a/drivers/watchdog/ixp2000_wdt.c b/drivers/watchdog/ixp2000_wdt.c
index 4f4b35a20d84..e86952a7168c 100644
--- a/drivers/watchdog/ixp2000_wdt.c
+++ b/drivers/watchdog/ixp2000_wdt.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
+#include <linux/timer.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
@@ -99,7 +100,7 @@ static ssize_t ixp2000_wdt_write(struct file *file, const char *data,
}
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING,
.identity = "IXP2000 Watchdog",
diff --git a/drivers/watchdog/ixp4xx_wdt.c b/drivers/watchdog/ixp4xx_wdt.c
index 147b4d5c63b3..e02c0ecda26b 100644
--- a/drivers/watchdog/ixp4xx_wdt.c
+++ b/drivers/watchdog/ixp4xx_wdt.c
@@ -89,7 +89,7 @@ ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
return len;
}
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "IXP4xx Watchdog",
diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c
index e1c82769b08e..2852bb2e3fd9 100644
--- a/drivers/watchdog/ks8695_wdt.c
+++ b/drivers/watchdog/ks8695_wdt.c
@@ -145,7 +145,7 @@ static int ks8695_wdt_close(struct inode *inode, struct file *file)
return 0;
}
-static struct watchdog_info ks8695_wdt_info = {
+static const struct watchdog_info ks8695_wdt_info = {
.identity = "ks8695 watchdog",
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
};
diff --git a/drivers/watchdog/machzwd.c b/drivers/watchdog/machzwd.c
index 47d719717a3b..2d118cf022fc 100644
--- a/drivers/watchdog/machzwd.c
+++ b/drivers/watchdog/machzwd.c
@@ -101,7 +101,7 @@ MODULE_PARM_DESC(nowayout,
#define PFX "machzwd"
-static struct watchdog_info zf_info = {
+static const struct watchdog_info zf_info = {
.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "ZF-Logic watchdog",
diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c
new file mode 100644
index 000000000000..6eb91d757604
--- /dev/null
+++ b/drivers/watchdog/max63xx_wdt.c
@@ -0,0 +1,397 @@
+/*
+ * drivers/char/watchdog/max63xx_wdt.c
+ *
+ * Driver for max63{69,70,71,72,73,74} watchdog timers
+ *
+ * Copyright (C) 2009 Marc Zyngier <maz@misterjones.org>
+ *
+ * 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.
+ *
+ * This driver assumes the watchdog pins are memory mapped (as it is
+ * the case for the Arcom Zeus). Should it be connected over GPIOs or
+ * another interface, some abstraction will have to be introduced.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/device.h>
+
+#define DEFAULT_HEARTBEAT 60
+#define MAX_HEARTBEAT 60
+
+static int heartbeat = DEFAULT_HEARTBEAT;
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+/*
+ * Memory mapping: a single byte, 3 first lower bits to select bit 3
+ * to ping the watchdog.
+ */
+#define MAX6369_WDSET (7 << 0)
+#define MAX6369_WDI (1 << 3)
+
+static DEFINE_SPINLOCK(io_lock);
+
+static unsigned long wdt_status;
+#define WDT_IN_USE 0
+#define WDT_RUNNING 1
+#define WDT_OK_TO_CLOSE 2
+
+static int nodelay;
+static struct resource *wdt_mem;
+static void __iomem *wdt_base;
+static struct platform_device *max63xx_pdev;
+
+/*
+ * The timeout values used are actually the absolute minimum the chip
+ * offers. Typical values on my board are slightly over twice as long
+ * (10s setting ends up with a 25s timeout), and can be up to 3 times
+ * the nominal setting (according to the datasheet). So please take
+ * these values with a grain of salt. Same goes for the initial delay
+ * "feature". Only max6373/74 have a few settings without this initial
+ * delay (selected with the "nodelay" parameter).
+ *
+ * I also decided to remove from the tables any timeout smaller than a
+ * second, as it looked completly overkill...
+ */
+
+/* Timeouts in second */
+struct max63xx_timeout {
+ u8 wdset;
+ u8 tdelay;
+ u8 twd;
+};
+
+static struct max63xx_timeout max6369_table[] = {
+ { 5, 1, 1 },
+ { 6, 10, 10 },
+ { 7, 60, 60 },
+ { },
+};
+
+static struct max63xx_timeout max6371_table[] = {
+ { 6, 60, 3 },
+ { 7, 60, 60 },
+ { },
+};
+
+static struct max63xx_timeout max6373_table[] = {
+ { 2, 60, 1 },
+ { 5, 0, 1 },
+ { 1, 3, 3 },
+ { 7, 60, 10 },
+ { 6, 0, 10 },
+ { },
+};
+
+static struct max63xx_timeout *current_timeout;
+
+static struct max63xx_timeout *
+max63xx_select_timeout(struct max63xx_timeout *table, int value)
+{
+ while (table->twd) {
+ if (value <= table->twd) {
+ if (nodelay && table->tdelay == 0)
+ return table;
+
+ if (!nodelay)
+ return table;
+ }
+
+ table++;
+ }
+
+ return NULL;
+}
+
+static void max63xx_wdt_ping(void)
+{
+ u8 val;
+
+ spin_lock(&io_lock);
+
+ val = __raw_readb(wdt_base);
+
+ __raw_writeb(val | MAX6369_WDI, wdt_base);
+ __raw_writeb(val & ~MAX6369_WDI, wdt_base);
+
+ spin_unlock(&io_lock);
+}
+
+static void max63xx_wdt_enable(struct max63xx_timeout *entry)
+{
+ u8 val;
+
+ if (test_and_set_bit(WDT_RUNNING, &wdt_status))
+ return;
+
+ spin_lock(&io_lock);
+
+ val = __raw_readb(wdt_base);
+ val &= ~MAX6369_WDSET;
+ val |= entry->wdset;
+ __raw_writeb(val, wdt_base);
+
+ spin_unlock(&io_lock);
+
+ /* check for a edge triggered startup */
+ if (entry->tdelay == 0)
+ max63xx_wdt_ping();
+}
+
+static void max63xx_wdt_disable(void)
+{
+ spin_lock(&io_lock);
+
+ __raw_writeb(3, wdt_base);
+
+ spin_unlock(&io_lock);
+
+ clear_bit(WDT_RUNNING, &wdt_status);
+}
+
+static int max63xx_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+ return -EBUSY;
+
+ max63xx_wdt_enable(current_timeout);
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t max63xx_wdt_write(struct file *file, const char *data,
+ size_t len, loff_t *ppos)
+{
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+
+ if (c == 'V')
+ set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ }
+ }
+
+ max63xx_wdt_ping();
+ }
+
+ return len;
+}
+
+static const struct watchdog_info ident = {
+ .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+ .identity = "max63xx Watchdog",
+};
+
+static long max63xx_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = -ENOTTY;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ max63xx_wdt_ping();
+ ret = 0;
+ break;
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(heartbeat, (int *)arg);
+ break;
+ }
+ return ret;
+}
+
+static int max63xx_wdt_release(struct inode *inode, struct file *file)
+{
+ if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+ max63xx_wdt_disable();
+ else
+ dev_crit(&max63xx_pdev->dev,
+ "device closed unexpectedly - timer will not stop\n");
+
+ clear_bit(WDT_IN_USE, &wdt_status);
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ return 0;
+}
+
+static const struct file_operations max63xx_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = max63xx_wdt_write,
+ .unlocked_ioctl = max63xx_wdt_ioctl,
+ .open = max63xx_wdt_open,
+ .release = max63xx_wdt_release,
+};
+
+static struct miscdevice max63xx_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &max63xx_wdt_fops,
+};
+
+static int __devinit max63xx_wdt_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ int size;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct max63xx_timeout *table;
+
+ table = (struct max63xx_timeout *)pdev->id_entry->driver_data;
+
+ if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
+ heartbeat = DEFAULT_HEARTBEAT;
+
+ dev_info(dev, "requesting %ds heartbeat\n", heartbeat);
+ current_timeout = max63xx_select_timeout(table, heartbeat);
+
+ if (!current_timeout) {
+ dev_err(dev, "unable to satisfy heartbeat request\n");
+ return -EINVAL;
+ }
+
+ dev_info(dev, "using %ds heartbeat with %ds initial delay\n",
+ current_timeout->twd, current_timeout->tdelay);
+
+ heartbeat = current_timeout->twd;
+
+ max63xx_pdev = pdev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "failed to get memory region resource\n");
+ return -ENOENT;
+ }
+
+ size = resource_size(res);
+ wdt_mem = request_mem_region(res->start, size, pdev->name);
+
+ if (wdt_mem == NULL) {
+ dev_err(dev, "failed to get memory region\n");
+ return -ENOENT;
+ }
+
+ wdt_base = ioremap(res->start, size);
+ if (!wdt_base) {
+ dev_err(dev, "failed to map memory region\n");
+ ret = -ENOMEM;
+ goto out_request;
+ }
+
+ ret = misc_register(&max63xx_wdt_miscdev);
+ if (ret < 0) {
+ dev_err(dev, "cannot register misc device\n");
+ goto out_unmap;
+ }
+
+ return 0;
+
+out_unmap:
+ iounmap(wdt_base);
+out_request:
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+
+ return ret;
+}
+
+static int __devexit max63xx_wdt_remove(struct platform_device *pdev)
+{
+ misc_deregister(&max63xx_wdt_miscdev);
+ if (wdt_mem) {
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ wdt_mem = NULL;
+ }
+
+ if (wdt_base)
+ iounmap(wdt_base);
+
+ return 0;
+}
+
+static struct platform_device_id max63xx_id_table[] = {
+ { "max6369_wdt", (kernel_ulong_t)max6369_table, },
+ { "max6370_wdt", (kernel_ulong_t)max6369_table, },
+ { "max6371_wdt", (kernel_ulong_t)max6371_table, },
+ { "max6372_wdt", (kernel_ulong_t)max6371_table, },
+ { "max6373_wdt", (kernel_ulong_t)max6373_table, },
+ { "max6374_wdt", (kernel_ulong_t)max6373_table, },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, max63xx_id_table);
+
+static struct platform_driver max63xx_wdt_driver = {
+ .probe = max63xx_wdt_probe,
+ .remove = __devexit_p(max63xx_wdt_remove),
+ .id_table = max63xx_id_table,
+ .driver = {
+ .name = "max63xx_wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init max63xx_wdt_init(void)
+{
+ return platform_driver_register(&max63xx_wdt_driver);
+}
+
+static void __exit max63xx_wdt_exit(void)
+{
+ platform_driver_unregister(&max63xx_wdt_driver);
+}
+
+module_init(max63xx_wdt_init);
+module_exit(max63xx_wdt_exit);
+
+MODULE_AUTHOR("Marc Zyngier <maz@misterjones.org>");
+MODULE_DESCRIPTION("max63xx Watchdog Driver");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+ "Watchdog heartbeat period in seconds from 1 to "
+ __MODULE_STRING(MAX_HEARTBEAT) ", default "
+ __MODULE_STRING(DEFAULT_HEARTBEAT));
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+module_param(nodelay, int, 0);
+MODULE_PARM_DESC(nodelay,
+ "Force selection of a timeout setting without initial delay "
+ "(max6373/74 only, default=0)");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/mixcomwd.c b/drivers/watchdog/mixcomwd.c
index 407b025cb104..bc820d16699a 100644
--- a/drivers/watchdog/mixcomwd.c
+++ b/drivers/watchdog/mixcomwd.c
@@ -201,7 +201,7 @@ static long mixcomwd_ioctl(struct file *file,
void __user *argp = (void __user *)arg;
int __user *p = argp;
int status;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "MixCOM watchdog",
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
index 38c588ee694f..4e3941c5e293 100644
--- a/drivers/watchdog/mpc8xxx_wdt.c
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -148,7 +148,7 @@ static long mpc8xxx_wdt_ioctl(struct file *file, unsigned int cmd,
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING,
.firmware_version = 1,
.identity = "MPC8xxx",
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c
index a2dc07c2ed49..b0646dac924e 100644
--- a/drivers/watchdog/mpcore_wdt.c
+++ b/drivers/watchdog/mpcore_wdt.c
@@ -213,7 +213,7 @@ static ssize_t mpcore_wdt_write(struct file *file, const char *data,
return len;
}
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
diff --git a/drivers/watchdog/mv64x60_wdt.c b/drivers/watchdog/mv64x60_wdt.c
index a51dbe4c43da..97f8a48d8b78 100644
--- a/drivers/watchdog/mv64x60_wdt.c
+++ b/drivers/watchdog/mv64x60_wdt.c
@@ -179,7 +179,7 @@ static long mv64x60_wdt_ioctl(struct file *file,
int timeout;
int options;
void __user *argp = (void __user *)arg;
- static struct watchdog_info info = {
+ static const struct watchdog_info info = {
.options = WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE |
WDIOF_KEEPALIVEPING,
diff --git a/drivers/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c
index 1a2b916e3f8d..d3aa2f1fe61d 100644
--- a/drivers/watchdog/pc87413_wdt.c
+++ b/drivers/watchdog/pc87413_wdt.c
@@ -407,7 +407,7 @@ static long pc87413_ioctl(struct file *file, unsigned int cmd,
int __user *i;
} uarg;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
diff --git a/drivers/watchdog/pcwd.c b/drivers/watchdog/pcwd.c
index aa9512321f3a..06f7922606c0 100644
--- a/drivers/watchdog/pcwd.c
+++ b/drivers/watchdog/pcwd.c
@@ -606,7 +606,7 @@ static long pcwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int temperature;
int new_heartbeat;
int __user *argp = (int __user *)arg;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_OVERHEAT |
WDIOF_CARDRESET |
WDIOF_KEEPALIVEPING |
diff --git a/drivers/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c
index 698f51bff1bc..64374d636f09 100644
--- a/drivers/watchdog/pcwd_pci.c
+++ b/drivers/watchdog/pcwd_pci.c
@@ -481,7 +481,7 @@ static long pcipcwd_ioctl(struct file *file, unsigned int cmd,
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_OVERHEAT |
WDIOF_CARDRESET |
WDIOF_KEEPALIVEPING |
diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c
index 052fe451851f..8e4eacc5bb52 100644
--- a/drivers/watchdog/pcwd_usb.c
+++ b/drivers/watchdog/pcwd_usb.c
@@ -404,7 +404,7 @@ static long usb_pcwd_ioctl(struct file *file, unsigned int cmd,
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
diff --git a/drivers/watchdog/pika_wdt.c b/drivers/watchdog/pika_wdt.c
index 2d22e996e996..435ec2aed4fe 100644
--- a/drivers/watchdog/pika_wdt.c
+++ b/drivers/watchdog/pika_wdt.c
@@ -52,7 +52,7 @@ static struct {
struct timer_list timer; /* The timer that pings the watchdog */
} pikawdt_private;
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.identity = DRV_NAME,
.options = WDIOF_CARDRESET |
WDIOF_SETTIMEOUT |
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index 430a5848a9a5..c7a9479934af 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -96,9 +96,6 @@ static void wdt_enable(void)
{
spin_lock(&io_lock);
- if (wdt_clk)
- clk_set_rate(wdt_clk, 1);
-
/* stop counter, initiate counter reset */
__raw_writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
/*wait for reset to complete. 100% guarantee event */
@@ -125,19 +122,25 @@ static void wdt_disable(void)
spin_lock(&io_lock);
__raw_writel(0, WDTIM_CTRL(wdt_base)); /*stop counter */
- if (wdt_clk)
- clk_set_rate(wdt_clk, 0);
spin_unlock(&io_lock);
}
static int pnx4008_wdt_open(struct inode *inode, struct file *file)
{
+ int ret;
+
if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY;
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ ret = clk_enable(wdt_clk);
+ if (ret) {
+ clear_bit(WDT_IN_USE, &wdt_status);
+ return ret;
+ }
+
wdt_enable();
return nonseekable_open(inode, file);
@@ -225,6 +228,7 @@ static int pnx4008_wdt_release(struct inode *inode, struct file *file)
printk(KERN_WARNING "WATCHDOG: Device closed unexpectdly\n");
wdt_disable();
+ clk_disable(wdt_clk);
clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
@@ -273,25 +277,33 @@ static int __devinit pnx4008_wdt_probe(struct platform_device *pdev)
}
wdt_base = (void __iomem *)IO_ADDRESS(res->start);
- wdt_clk = clk_get(&pdev->dev, "wdt_ck");
+ wdt_clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(wdt_clk)) {
ret = PTR_ERR(wdt_clk);
release_resource(wdt_mem);
kfree(wdt_mem);
goto out;
- } else
- clk_set_rate(wdt_clk, 1);
+ }
+
+ ret = clk_enable(wdt_clk);
+ if (ret) {
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ goto out;
+ }
ret = misc_register(&pnx4008_wdt_miscdev);
if (ret < 0) {
printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
release_resource(wdt_mem);
kfree(wdt_mem);
- clk_set_rate(wdt_clk, 0);
+ clk_disable(wdt_clk);
+ clk_put(wdt_clk);
} else {
boot_status = (__raw_readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
WDIOF_CARDRESET : 0;
wdt_disable(); /*disable for now */
+ clk_disable(wdt_clk);
set_bit(WDT_DEVICE_INITED, &wdt_status);
}
@@ -302,11 +314,10 @@ out:
static int __devexit pnx4008_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&pnx4008_wdt_miscdev);
- if (wdt_clk) {
- clk_set_rate(wdt_clk, 0);
- clk_put(wdt_clk);
- wdt_clk = NULL;
- }
+
+ clk_disable(wdt_clk);
+ clk_put(wdt_clk);
+
if (wdt_mem) {
release_resource(wdt_mem);
kfree(wdt_mem);
diff --git a/drivers/watchdog/pnx833x_wdt.c b/drivers/watchdog/pnx833x_wdt.c
index 538ec2c05197..09102f09e681 100644
--- a/drivers/watchdog/pnx833x_wdt.c
+++ b/drivers/watchdog/pnx833x_wdt.c
@@ -141,7 +141,7 @@ static long pnx833x_wdt_ioctl(struct file *file, unsigned int cmd,
int options, new_timeout = 0;
uint32_t timeout, timeout_left = 0;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
.firmware_version = 0,
.identity = "Hardware Watchdog for PNX833x",
diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c
index bf12d06b5877..d4c29b5311a4 100644
--- a/drivers/watchdog/rc32434_wdt.c
+++ b/drivers/watchdog/rc32434_wdt.c
@@ -198,7 +198,7 @@ static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd,
void __user *argp = (void __user *)arg;
int new_timeout;
unsigned int value;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
diff --git a/drivers/watchdog/rdc321x_wdt.c b/drivers/watchdog/rdc321x_wdt.c
index 4976bfd1fce6..69c6adbd8205 100644
--- a/drivers/watchdog/rdc321x_wdt.c
+++ b/drivers/watchdog/rdc321x_wdt.c
@@ -149,7 +149,7 @@ static long rdc321x_wdt_ioctl(struct file *file, unsigned int cmd,
{
void __user *argp = (void __user *)arg;
unsigned int value;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET,
.identity = "RDC321x WDT",
};
diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c
index c14ae8676903..ae57bf9e1b03 100644
--- a/drivers/watchdog/riowd.c
+++ b/drivers/watchdog/riowd.c
@@ -85,7 +85,7 @@ static int riowd_release(struct inode *inode, struct file *filp)
static long riowd_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
- static struct watchdog_info info = {
+ static const struct watchdog_info info = {
.options = WDIOF_SETTIMEOUT,
.firmware_version = 1,
.identity = DRIVER_NAME,
diff --git a/drivers/watchdog/sbc_fitpc2_wdt.c b/drivers/watchdog/sbc_fitpc2_wdt.c
index 91430a89107c..8d44c9b6fb5b 100644
--- a/drivers/watchdog/sbc_fitpc2_wdt.c
+++ b/drivers/watchdog/sbc_fitpc2_wdt.c
@@ -46,9 +46,9 @@ static DEFINE_SPINLOCK(wdt_lock);
static void wdt_send_data(unsigned char command, unsigned char data)
{
outb(command, COMMAND_PORT);
- mdelay(100);
+ msleep(100);
outb(data, DATA_PORT);
- mdelay(200);
+ msleep(200);
}
static void wdt_enable(void)
@@ -111,7 +111,7 @@ out:
}
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING,
.identity = WATCHDOG_NAME,
@@ -202,11 +202,10 @@ static int __init fitpc2_wdt_init(void)
{
int err;
- if (strcmp("SBC-FITPC2", dmi_get_system_info(DMI_BOARD_NAME))) {
- pr_info("board name is: %s. Should be SBC-FITPC2\n",
- dmi_get_system_info(DMI_BOARD_NAME));
+ if (!strstr(dmi_get_system_info(DMI_BOARD_NAME), "SBC-FITPC2"))
return -ENODEV;
- }
+
+ pr_info("%s found\n", dmi_get_system_info(DMI_BOARD_NAME));
if (!request_region(COMMAND_PORT, 1, WATCHDOG_NAME)) {
pr_err("I/O address 0x%04x already in use\n", COMMAND_PORT);
diff --git a/drivers/watchdog/sch311x_wdt.c b/drivers/watchdog/sch311x_wdt.c
index 569eb295a7a8..9c40f48804f5 100644
--- a/drivers/watchdog/sch311x_wdt.c
+++ b/drivers/watchdog/sch311x_wdt.c
@@ -250,7 +250,7 @@ static long sch311x_wdt_ioctl(struct file *file, unsigned int cmd,
int new_timeout;
void __user *argp = (void __user *)arg;
int __user *p = argp;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
diff --git a/drivers/watchdog/stmp3xxx_wdt.c b/drivers/watchdog/stmp3xxx_wdt.c
index 5dd952681f32..b3421fd2cda8 100644
--- a/drivers/watchdog/stmp3xxx_wdt.c
+++ b/drivers/watchdog/stmp3xxx_wdt.c
@@ -94,7 +94,7 @@ static ssize_t stmp3xxx_wdt_write(struct file *file, const char __user *data,
return len;
}
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET |
WDIOF_MAGICCLOSE |
WDIOF_SETTIMEOUT |
diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c
new file mode 100644
index 000000000000..565a2c3321e5
--- /dev/null
+++ b/drivers/watchdog/ts72xx_wdt.c
@@ -0,0 +1,520 @@
+/*
+ * Watchdog driver for Technologic Systems TS-72xx based SBCs
+ * (TS-7200, TS-7250 and TS-7260). These boards have external
+ * glue logic CPLD chip, which includes programmable watchdog
+ * timer.
+ *
+ * Copyright (c) 2009 Mika Westerberg <mika.westerberg@iki.fi>
+ *
+ * This driver is based on ep93xx_wdt and wm831x_wdt drivers.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/uaccess.h>
+
+#define TS72XX_WDT_FEED_VAL 0x05
+#define TS72XX_WDT_DEFAULT_TIMEOUT 8
+
+static int timeout = TS72XX_WDT_DEFAULT_TIMEOUT;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. "
+ "(1 <= timeout <= 8, default="
+ __MODULE_STRING(TS72XX_WDT_DEFAULT_TIMEOUT)
+ ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
+
+/**
+ * struct ts72xx_wdt - watchdog control structure
+ * @lock: lock that protects this structure
+ * @regval: watchdog timeout value suitable for control register
+ * @flags: flags controlling watchdog device state
+ * @control_reg: watchdog control register
+ * @feed_reg: watchdog feed register
+ * @pdev: back pointer to platform dev
+ */
+struct ts72xx_wdt {
+ struct mutex lock;
+ int regval;
+
+#define TS72XX_WDT_BUSY_FLAG 1
+#define TS72XX_WDT_EXPECT_CLOSE_FLAG 2
+ int flags;
+
+ void __iomem *control_reg;
+ void __iomem *feed_reg;
+
+ struct platform_device *pdev;
+};
+
+struct platform_device *ts72xx_wdt_pdev;
+
+/*
+ * TS-72xx Watchdog supports following timeouts (value written
+ * to control register):
+ * value description
+ * -------------------------
+ * 0x00 watchdog disabled
+ * 0x01 250ms
+ * 0x02 500ms
+ * 0x03 1s
+ * 0x04 reserved
+ * 0x05 2s
+ * 0x06 4s
+ * 0x07 8s
+ *
+ * Timeouts below 1s are not very usable so we don't
+ * allow them at all.
+ *
+ * We provide two functions that convert between these:
+ * timeout_to_regval() and regval_to_timeout().
+ */
+static const struct {
+ int timeout;
+ int regval;
+} ts72xx_wdt_map[] = {
+ { 1, 3 },
+ { 2, 5 },
+ { 4, 6 },
+ { 8, 7 },
+};
+
+/**
+ * timeout_to_regval() - converts given timeout to control register value
+ * @new_timeout: timeout in seconds to be converted
+ *
+ * Function converts given @new_timeout into valid value that can
+ * be programmed into watchdog control register. When conversion is
+ * not possible, function returns %-EINVAL.
+ */
+static int timeout_to_regval(int new_timeout)
+{
+ int i;
+
+ /* first limit it to 1 - 8 seconds */
+ new_timeout = clamp_val(new_timeout, 1, 8);
+
+ for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) {
+ if (ts72xx_wdt_map[i].timeout >= new_timeout)
+ return ts72xx_wdt_map[i].regval;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * regval_to_timeout() - converts control register value to timeout
+ * @regval: control register value to be converted
+ *
+ * Function converts given @regval to timeout in seconds (1, 2, 4 or 8).
+ * If @regval cannot be converted, function returns %-EINVAL.
+ */
+static int regval_to_timeout(int regval)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) {
+ if (ts72xx_wdt_map[i].regval == regval)
+ return ts72xx_wdt_map[i].timeout;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * ts72xx_wdt_kick() - kick the watchdog
+ * @wdt: watchdog to be kicked
+ *
+ * Called with @wdt->lock held.
+ */
+static inline void ts72xx_wdt_kick(struct ts72xx_wdt *wdt)
+{
+ __raw_writeb(TS72XX_WDT_FEED_VAL, wdt->feed_reg);
+}
+
+/**
+ * ts72xx_wdt_start() - starts the watchdog timer
+ * @wdt: watchdog to be started
+ *
+ * This function programs timeout to watchdog timer
+ * and starts it.
+ *
+ * Called with @wdt->lock held.
+ */
+static void ts72xx_wdt_start(struct ts72xx_wdt *wdt)
+{
+ /*
+ * To program the wdt, it first must be "fed" and
+ * only after that (within 30 usecs) the configuration
+ * can be changed.
+ */
+ ts72xx_wdt_kick(wdt);
+ __raw_writeb((u8)wdt->regval, wdt->control_reg);
+}
+
+/**
+ * ts72xx_wdt_stop() - stops the watchdog timer
+ * @wdt: watchdog to be stopped
+ *
+ * Called with @wdt->lock held.
+ */
+static void ts72xx_wdt_stop(struct ts72xx_wdt *wdt)
+{
+ ts72xx_wdt_kick(wdt);
+ __raw_writeb(0, wdt->control_reg);
+}
+
+static int ts72xx_wdt_open(struct inode *inode, struct file *file)
+{
+ struct ts72xx_wdt *wdt = platform_get_drvdata(ts72xx_wdt_pdev);
+ int regval;
+
+ /*
+ * Try to convert default timeout to valid register
+ * value first.
+ */
+ regval = timeout_to_regval(timeout);
+ if (regval < 0) {
+ dev_err(&wdt->pdev->dev,
+ "failed to convert timeout (%d) to register value\n",
+ timeout);
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&wdt->lock))
+ return -ERESTARTSYS;
+
+ if ((wdt->flags & TS72XX_WDT_BUSY_FLAG) != 0) {
+ mutex_unlock(&wdt->lock);
+ return -EBUSY;
+ }
+
+ wdt->flags = TS72XX_WDT_BUSY_FLAG;
+ wdt->regval = regval;
+ file->private_data = wdt;
+
+ ts72xx_wdt_start(wdt);
+
+ mutex_unlock(&wdt->lock);
+ return nonseekable_open(inode, file);
+}
+
+static int ts72xx_wdt_release(struct inode *inode, struct file *file)
+{
+ struct ts72xx_wdt *wdt = file->private_data;
+
+ if (mutex_lock_interruptible(&wdt->lock))
+ return -ERESTARTSYS;
+
+ if ((wdt->flags & TS72XX_WDT_EXPECT_CLOSE_FLAG) != 0) {
+ ts72xx_wdt_stop(wdt);
+ } else {
+ dev_warn(&wdt->pdev->dev,
+ "TS-72XX WDT device closed unexpectly. "
+ "Watchdog timer will not stop!\n");
+ /*
+ * Kick it one more time, to give userland some time
+ * to recover (for example, respawning the kicker
+ * daemon).
+ */
+ ts72xx_wdt_kick(wdt);
+ }
+
+ wdt->flags = 0;
+
+ mutex_unlock(&wdt->lock);
+ return 0;
+}
+
+static ssize_t ts72xx_wdt_write(struct file *file,
+ const char __user *data,
+ size_t len,
+ loff_t *ppos)
+{
+ struct ts72xx_wdt *wdt = file->private_data;
+
+ if (!len)
+ return 0;
+
+ if (mutex_lock_interruptible(&wdt->lock))
+ return -ERESTARTSYS;
+
+ ts72xx_wdt_kick(wdt);
+
+ /*
+ * Support for magic character closing. User process
+ * writes 'V' into the device, just before it is closed.
+ * This means that we know that the wdt timer can be
+ * stopped after user closes the device.
+ */
+ if (!nowayout) {
+ int i;
+
+ for (i = 0; i < len; i++) {
+ char c;
+
+ /* In case it was set long ago */
+ wdt->flags &= ~TS72XX_WDT_EXPECT_CLOSE_FLAG;
+
+ if (get_user(c, data + i)) {
+ mutex_unlock(&wdt->lock);
+ return -EFAULT;
+ }
+ if (c == 'V') {
+ wdt->flags |= TS72XX_WDT_EXPECT_CLOSE_FLAG;
+ break;
+ }
+ }
+ }
+
+ mutex_unlock(&wdt->lock);
+ return len;
+}
+
+static const struct watchdog_info winfo = {
+ .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
+ WDIOF_MAGICCLOSE,
+ .firmware_version = 1,
+ .identity = "TS-72XX WDT",
+};
+
+static long ts72xx_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct ts72xx_wdt *wdt = file->private_data;
+ void __user *argp = (void __user *)arg;
+ int __user *p = (int __user *)argp;
+ int error = 0;
+
+ if (mutex_lock_interruptible(&wdt->lock))
+ return -ERESTARTSYS;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ error = copy_to_user(argp, &winfo, sizeof(winfo));
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+
+ case WDIOC_KEEPALIVE:
+ ts72xx_wdt_kick(wdt);
+ break;
+
+ case WDIOC_SETOPTIONS: {
+ int options;
+
+ if (get_user(options, p)) {
+ error = -EFAULT;
+ break;
+ }
+
+ error = -EINVAL;
+
+ if ((options & WDIOS_DISABLECARD) != 0) {
+ ts72xx_wdt_stop(wdt);
+ error = 0;
+ }
+ if ((options & WDIOS_ENABLECARD) != 0) {
+ ts72xx_wdt_start(wdt);
+ error = 0;
+ }
+
+ break;
+ }
+
+ case WDIOC_SETTIMEOUT: {
+ int new_timeout;
+
+ if (get_user(new_timeout, p)) {
+ error = -EFAULT;
+ } else {
+ int regval;
+
+ regval = timeout_to_regval(new_timeout);
+ if (regval < 0) {
+ error = -EINVAL;
+ } else {
+ ts72xx_wdt_stop(wdt);
+ wdt->regval = regval;
+ ts72xx_wdt_start(wdt);
+ }
+ }
+ if (error)
+ break;
+
+ /*FALLTHROUGH*/
+ }
+
+ case WDIOC_GETTIMEOUT:
+ if (put_user(regval_to_timeout(wdt->regval), p))
+ error = -EFAULT;
+ break;
+
+ default:
+ error = -ENOTTY;
+ break;
+ }
+
+ mutex_unlock(&wdt->lock);
+ return error;
+}
+
+static const struct file_operations ts72xx_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .open = ts72xx_wdt_open,
+ .release = ts72xx_wdt_release,
+ .write = ts72xx_wdt_write,
+ .unlocked_ioctl = ts72xx_wdt_ioctl,
+};
+
+static struct miscdevice ts72xx_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &ts72xx_wdt_fops,
+};
+
+static __devinit int ts72xx_wdt_probe(struct platform_device *pdev)
+{
+ struct ts72xx_wdt *wdt;
+ struct resource *r1, *r2;
+ int error = 0;
+
+ wdt = kzalloc(sizeof(struct ts72xx_wdt), GFP_KERNEL);
+ if (!wdt) {
+ dev_err(&pdev->dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r1) {
+ dev_err(&pdev->dev, "failed to get memory resource\n");
+ error = -ENODEV;
+ goto fail;
+ }
+
+ r1 = request_mem_region(r1->start, resource_size(r1), pdev->name);
+ if (!r1) {
+ dev_err(&pdev->dev, "cannot request memory region\n");
+ error = -EBUSY;
+ goto fail;
+ }
+
+ wdt->control_reg = ioremap(r1->start, resource_size(r1));
+ if (!wdt->control_reg) {
+ dev_err(&pdev->dev, "failed to map memory\n");
+ error = -ENODEV;
+ goto fail_free_control;
+ }
+
+ r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!r2) {
+ dev_err(&pdev->dev, "failed to get memory resource\n");
+ error = -ENODEV;
+ goto fail_unmap_control;
+ }
+
+ r2 = request_mem_region(r2->start, resource_size(r2), pdev->name);
+ if (!r2) {
+ dev_err(&pdev->dev, "cannot request memory region\n");
+ error = -EBUSY;
+ goto fail_unmap_control;
+ }
+
+ wdt->feed_reg = ioremap(r2->start, resource_size(r2));
+ if (!wdt->feed_reg) {
+ dev_err(&pdev->dev, "failed to map memory\n");
+ error = -ENODEV;
+ goto fail_free_feed;
+ }
+
+ platform_set_drvdata(pdev, wdt);
+ ts72xx_wdt_pdev = pdev;
+ wdt->pdev = pdev;
+ mutex_init(&wdt->lock);
+
+ error = misc_register(&ts72xx_wdt_miscdev);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register miscdev\n");
+ goto fail_unmap_feed;
+ }
+
+ dev_info(&pdev->dev, "TS-72xx Watchdog driver\n");
+
+ return 0;
+
+fail_unmap_feed:
+ platform_set_drvdata(pdev, NULL);
+ iounmap(wdt->feed_reg);
+fail_free_feed:
+ release_mem_region(r2->start, resource_size(r2));
+fail_unmap_control:
+ iounmap(wdt->control_reg);
+fail_free_control:
+ release_mem_region(r1->start, resource_size(r1));
+fail:
+ kfree(wdt);
+ return error;
+}
+
+static __devexit int ts72xx_wdt_remove(struct platform_device *pdev)
+{
+ struct ts72xx_wdt *wdt = platform_get_drvdata(pdev);
+ struct resource *res;
+ int error;
+
+ error = misc_deregister(&ts72xx_wdt_miscdev);
+ platform_set_drvdata(pdev, NULL);
+
+ iounmap(wdt->feed_reg);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ release_mem_region(res->start, resource_size(res));
+
+ iounmap(wdt->control_reg);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(wdt);
+ return error;
+}
+
+static struct platform_driver ts72xx_wdt_driver = {
+ .probe = ts72xx_wdt_probe,
+ .remove = __devexit_p(ts72xx_wdt_remove),
+ .driver = {
+ .name = "ts72xx-wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static __init int ts72xx_wdt_init(void)
+{
+ return platform_driver_register(&ts72xx_wdt_driver);
+}
+module_init(ts72xx_wdt_init);
+
+static __exit void ts72xx_wdt_exit(void)
+{
+ platform_driver_unregister(&ts72xx_wdt_driver);
+}
+module_exit(ts72xx_wdt_exit);
+
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
+MODULE_DESCRIPTION("TS-72xx SBC Watchdog");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ts72xx-wdt");
diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c
index d635566e9307..9e9ed7bfabcb 100644
--- a/drivers/watchdog/txx9wdt.c
+++ b/drivers/watchdog/txx9wdt.c
@@ -13,7 +13,6 @@
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/fs.h>
-#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
@@ -166,14 +165,6 @@ static long txx9wdt_ioctl(struct file *file, unsigned int cmd,
}
}
-static int txx9wdt_notify_sys(struct notifier_block *this, unsigned long code,
- void *unused)
-{
- if (code == SYS_DOWN || code == SYS_HALT)
- txx9wdt_stop();
- return NOTIFY_DONE;
-}
-
static const struct file_operations txx9wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -189,10 +180,6 @@ static struct miscdevice txx9wdt_miscdev = {
.fops = &txx9wdt_fops,
};
-static struct notifier_block txx9wdt_notifier = {
- .notifier_call = txx9wdt_notify_sys,
-};
-
static int __init txx9wdt_probe(struct platform_device *dev)
{
struct resource *res;
@@ -221,13 +208,8 @@ static int __init txx9wdt_probe(struct platform_device *dev)
if (!txx9wdt_reg)
goto exit_busy;
- ret = register_reboot_notifier(&txx9wdt_notifier);
- if (ret)
- goto exit;
-
ret = misc_register(&txx9wdt_miscdev);
if (ret) {
- unregister_reboot_notifier(&txx9wdt_notifier);
goto exit;
}
@@ -249,14 +231,19 @@ exit:
static int __exit txx9wdt_remove(struct platform_device *dev)
{
misc_deregister(&txx9wdt_miscdev);
- unregister_reboot_notifier(&txx9wdt_notifier);
clk_disable(txx9_imclk);
clk_put(txx9_imclk);
return 0;
}
+static void txx9wdt_shutdown(struct platform_device *dev)
+{
+ txx9wdt_stop();
+}
+
static struct platform_driver txx9wdt_driver = {
.remove = __exit_p(txx9wdt_remove),
+ .shutdown = txx9wdt_shutdown,
.driver = {
.name = "txx9wdt",
.owner = THIS_MODULE,
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index f201accc4e3d..0f5288df0091 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -201,7 +201,7 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_timeout;
- static struct watchdog_info ident = {
+ static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
.firmware_version = 1,
diff --git a/drivers/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c
index 0560182a1d09..6e6743d1066f 100644
--- a/drivers/watchdog/w83977f_wdt.c
+++ b/drivers/watchdog/w83977f_wdt.c
@@ -371,7 +371,7 @@ static ssize_t wdt_write(struct file *file, const char __user *buf,
* according to their available features.
*/
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
.firmware_version = 1,
.identity = WATCHDOG_NAME,
diff --git a/drivers/watchdog/wdrtas.c b/drivers/watchdog/wdrtas.c
index 5bfb1f2c5319..94ec22b9e66b 100644
--- a/drivers/watchdog/wdrtas.c
+++ b/drivers/watchdog/wdrtas.c
@@ -312,7 +312,7 @@ static long wdrtas_ioctl(struct file *file, unsigned int cmd,
{
int __user *argp = (void __user *)arg;
int i;
- static struct watchdog_info wdinfo = {
+ static const struct watchdog_info wdinfo = {
.options = WDRTAS_SUPPORTED_MASK,
.firmware_version = 0,
.identity = "wdrtas",
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
index 3bbefe9a2634..bfda2e99dd89 100644
--- a/drivers/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -358,7 +358,7 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int new_heartbeat;
int status;
- static struct watchdog_info ident = {
+ struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT|
WDIOF_MAGICCLOSE|
WDIOF_KEEPALIVEPING,
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index f368dd87083a..7b22e3cdbc81 100644
--- a/drivers/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -412,7 +412,7 @@ static long wdtpci_ioctl(struct file *file, unsigned int cmd,
int new_heartbeat;
int status;
- static struct watchdog_info ident = {
+ struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT|
WDIOF_MAGICCLOSE|
WDIOF_KEEPALIVEPING,
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c
index 775bcd807f31..8c4b2d5bb7da 100644
--- a/drivers/watchdog/wm831x_wdt.c
+++ b/drivers/watchdog/wm831x_wdt.c
@@ -213,7 +213,7 @@ static ssize_t wm831x_wdt_write(struct file *file,
return count;
}
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
.identity = "WM831x Watchdog",
};
diff --git a/drivers/watchdog/wm8350_wdt.c b/drivers/watchdog/wm8350_wdt.c
index a2d2e8eb2282..89dd7b035295 100644
--- a/drivers/watchdog/wm8350_wdt.c
+++ b/drivers/watchdog/wm8350_wdt.c
@@ -177,7 +177,7 @@ static ssize_t wm8350_wdt_write(struct file *file,
return count;
}
-static struct watchdog_info ident = {
+static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
.identity = "WM8350 Watchdog",
};
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index cab100acf983..fad3df2c1276 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -1,6 +1,8 @@
+menu "Xen driver support"
+ depends on XEN
+
config XEN_BALLOON
bool "Xen memory balloon driver"
- depends on XEN
default y
help
The balloon driver allows the Xen domain to request more memory from
@@ -20,7 +22,6 @@ config XEN_SCRUB_PAGES
config XEN_DEV_EVTCHN
tristate "Xen /dev/xen/evtchn device"
- depends on XEN
default y
help
The evtchn driver allows a userspace process to triger event
@@ -30,7 +31,6 @@ config XEN_DEV_EVTCHN
config XENFS
tristate "Xen filesystem"
- depends on XEN
default y
help
The xen filesystem provides a way for domains to share
@@ -53,11 +53,13 @@ config XEN_COMPAT_XENFS
config XEN_SYS_HYPERVISOR
bool "Create xen entries under /sys/hypervisor"
- depends on XEN && SYSFS
+ depends on SYSFS
select SYS_HYPERVISOR
default y
help
Create entries under /sys/hypervisor describing the Xen
hypervisor environment. When running native or in another
virtual environment, /sys/hypervisor will still be present,
- but will have no xen contents. \ No newline at end of file
+ but will have no xen contents.
+
+endmenu
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index ce602dd09bc1..2f8413794d05 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -649,9 +649,13 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
int bit_idx = __ffs(pending_bits);
int port = (word_idx * BITS_PER_LONG) + bit_idx;
int irq = evtchn_to_irq[port];
+ struct irq_desc *desc;
- if (irq != -1)
- handle_irq(irq, regs);
+ if (irq != -1) {
+ desc = irq_to_desc(irq);
+ if (desc)
+ generic_handle_irq_desc(irq, desc);
+ }
}
}
diff --git a/drivers/xen/sys-hypervisor.c b/drivers/xen/sys-hypervisor.c
index ae5cb05a1a1c..bb71ab2336c8 100644
--- a/drivers/xen/sys-hypervisor.c
+++ b/drivers/xen/sys-hypervisor.c
@@ -426,7 +426,7 @@ static ssize_t hyp_sysfs_store(struct kobject *kobj,
return 0;
}
-static struct sysfs_ops hyp_sysfs_ops = {
+static const struct sysfs_ops hyp_sysfs_ops = {
.show = hyp_sysfs_show,
.store = hyp_sysfs_store,
};
diff --git a/drivers/zorro/zorro.ids b/drivers/zorro/zorro.ids
index 0c0f99e2dd62..de24e3decedd 100644
--- a/drivers/zorro/zorro.ids
+++ b/drivers/zorro/zorro.ids
@@ -108,7 +108,7 @@
0c00 500XP/SupraDrive WordSync [SCSI Host Adapter]
0d00 SupraDrive WordSync II [SCSI Host Adapter]
1000 2400zi+ [Modem]
-0422 Computer Systems Assosiates
+0422 Computer Systems Associates
1100 Magnum 40 [Accelerator and SCSI Host Adapter]
1500 12 Gauge [SCSI Host Adapter]
0439 Marc Michael Groth